From 7a6610139a1e1d9297dd1c5d178022eac36839cb Mon Sep 17 00:00:00 2001 From: Jan Kiszka Date: Tue, 2 Nov 2010 08:05:51 +0100 Subject: intel-iommu: Fix use after release during device attach Obtain the new pgd pointer before releasing the page containing this value. Cc: stable@kernel.org Signed-off-by: Jan Kiszka Reviewed-by: Sheng Yang Signed-off-by: David Woodhouse diff --git a/drivers/pci/intel-iommu.c b/drivers/pci/intel-iommu.c index 4789f8e..35463dd 100644 --- a/drivers/pci/intel-iommu.c +++ b/drivers/pci/intel-iommu.c @@ -3627,9 +3627,9 @@ static int intel_iommu_attach_device(struct iommu_domain *domain, pte = dmar_domain->pgd; if (dma_pte_present(pte)) { - free_pgtable_page(dmar_domain->pgd); dmar_domain->pgd = (struct dma_pte *) phys_to_virt(dma_pte_addr(pte)); + free_pgtable_page(pte); } dmar_domain->agaw--; } -- cgit v0.10.2 From 36d8593ec74dc04d3bd7c1c897a7b7cfbd0b0dc6 Mon Sep 17 00:00:00 2001 From: Russell King - ARM Linux Date: Sat, 19 Feb 2011 15:34:50 +0000 Subject: Make clocksource name const As nothing should be writing to the clocksource name string, make the clocksource name pointer const. Build-tested on ARM Versatile Express. Signed-off-by: Russell King Signed-off-by: John Stultz diff --git a/include/linux/clocksource.h b/include/linux/clocksource.h index c37b21a..94c1f38 100644 --- a/include/linux/clocksource.h +++ b/include/linux/clocksource.h @@ -161,7 +161,7 @@ struct clocksource { /* * First part of structure is read mostly */ - char *name; + const char *name; struct list_head list; int rating; cycle_t (*read)(struct clocksource *cs); -- cgit v0.10.2 From b01cc1b0eae0dea19257b29347116505fbedf679 Mon Sep 17 00:00:00 2001 From: John Stultz Date: Mon, 26 Apr 2010 19:03:05 -0700 Subject: x86: Convert remaining x86 clocksources to clocksource_register_hz/khz This converts the remaining x86 clocksources to use clocksource_register_hz/khz. CC: jacob.jun.pan@intel.com CC: Glauber Costa CC: Dimitri Sivanich CC: Rusty Russell CC: Jeremy Fitzhardinge CC: Chris McDermott CC: Thomas Gleixner Tested-by: Konrad Rzeszutek Wilk [xen] Signed-off-by: John Stultz diff --git a/arch/x86/kernel/apb_timer.c b/arch/x86/kernel/apb_timer.c index 51ef31a..29ebf5a 100644 --- a/arch/x86/kernel/apb_timer.c +++ b/arch/x86/kernel/apb_timer.c @@ -177,7 +177,6 @@ static struct clocksource clocksource_apbt = { .rating = APBT_CLOCKSOURCE_RATING, .read = apbt_read_clocksource, .mask = APBT_MASK, - .shift = APBT_SHIFT, .flags = CLOCK_SOURCE_IS_CONTINUOUS, .resume = apbt_restart_clocksource, }; @@ -595,14 +594,7 @@ static int apbt_clocksource_register(void) if (t1 == apbt_read_clocksource(&clocksource_apbt)) panic("APBT counter not counting. APBT disabled\n"); - /* - * initialize and register APBT clocksource - * convert that to ns/clock cycle - * mult = (ns/c) * 2^APBT_SHIFT - */ - clocksource_apbt.mult = div_sc(MSEC_PER_SEC, - (unsigned long) apbt_freq, APBT_SHIFT); - clocksource_register(&clocksource_apbt); + clocksource_register_khz(&clocksource_apbt, (u32)apbt_freq*1000); return 0; } diff --git a/arch/x86/kernel/i8253.c b/arch/x86/kernel/i8253.c index 2dfd315..212fe65 100644 --- a/arch/x86/kernel/i8253.c +++ b/arch/x86/kernel/i8253.c @@ -188,8 +188,6 @@ static struct clocksource pit_cs = { .rating = 110, .read = pit_read, .mask = CLOCKSOURCE_MASK(32), - .mult = 0, - .shift = 20, }; static int __init init_pit_clocksource(void) @@ -205,9 +203,7 @@ static int __init init_pit_clocksource(void) pit_ce.mode != CLOCK_EVT_MODE_PERIODIC) return 0; - pit_cs.mult = clocksource_hz2mult(CLOCK_TICK_RATE, pit_cs.shift); - - return clocksource_register(&pit_cs); + return clocksource_register_hz(&pit_cs, CLOCK_TICK_RATE); } arch_initcall(init_pit_clocksource); diff --git a/arch/x86/kernel/kvmclock.c b/arch/x86/kernel/kvmclock.c index f98d3ea..6389a6b 100644 --- a/arch/x86/kernel/kvmclock.c +++ b/arch/x86/kernel/kvmclock.c @@ -26,8 +26,6 @@ #include #include -#define KVM_SCALE 22 - static int kvmclock = 1; static int msr_kvm_system_time = MSR_KVM_SYSTEM_TIME; static int msr_kvm_wall_clock = MSR_KVM_WALL_CLOCK; @@ -120,8 +118,6 @@ static struct clocksource kvm_clock = { .read = kvm_clock_get_cycles, .rating = 400, .mask = CLOCKSOURCE_MASK(64), - .mult = 1 << KVM_SCALE, - .shift = KVM_SCALE, .flags = CLOCK_SOURCE_IS_CONTINUOUS, }; @@ -203,7 +199,7 @@ void __init kvmclock_init(void) machine_ops.crash_shutdown = kvm_crash_shutdown; #endif kvm_get_preset_lpj(); - clocksource_register(&kvm_clock); + clocksource_register_hz(&kvm_clock, NSEC_PER_SEC); pv_info.paravirt_enabled = 1; pv_info.name = "KVM"; diff --git a/arch/x86/lguest/boot.c b/arch/x86/lguest/boot.c index eba687f0..5b96fd9 100644 --- a/arch/x86/lguest/boot.c +++ b/arch/x86/lguest/boot.c @@ -913,8 +913,6 @@ static struct clocksource lguest_clock = { .rating = 200, .read = lguest_clock_read, .mask = CLOCKSOURCE_MASK(64), - .mult = 1 << 22, - .shift = 22, .flags = CLOCK_SOURCE_IS_CONTINUOUS, }; @@ -997,7 +995,7 @@ static void lguest_time_init(void) /* Set up the timer interrupt (0) to go to our simple timer routine */ set_irq_handler(0, lguest_time_irq); - clocksource_register(&lguest_clock); + clocksource_register_hz(&lguest_clock, NSEC_PER_SEC); /* We can't set cpumask in the initializer: damn C limitations! Set it * here and register our timer device. */ diff --git a/arch/x86/platform/uv/uv_time.c b/arch/x86/platform/uv/uv_time.c index 9daf5d1..0eb9018 100644 --- a/arch/x86/platform/uv/uv_time.c +++ b/arch/x86/platform/uv/uv_time.c @@ -40,7 +40,6 @@ static struct clocksource clocksource_uv = { .rating = 400, .read = uv_read_rtc, .mask = (cycle_t)UVH_RTC_REAL_TIME_CLOCK_MASK, - .shift = 10, .flags = CLOCK_SOURCE_IS_CONTINUOUS, }; @@ -372,14 +371,11 @@ static __init int uv_rtc_setup_clock(void) if (!is_uv_system()) return -ENODEV; - clocksource_uv.mult = clocksource_hz2mult(sn_rtc_cycles_per_second, - clocksource_uv.shift); - /* If single blade, prefer tsc */ if (uv_num_possible_blades() == 1) clocksource_uv.rating = 250; - rc = clocksource_register(&clocksource_uv); + rc = clocksource_register_hz(&clocksource_uv, sn_rtc_cycles_per_second); if (rc) printk(KERN_INFO "UV RTC clocksource failed rc %d\n", rc); else diff --git a/arch/x86/xen/time.c b/arch/x86/xen/time.c index 067759e..04e1159 100644 --- a/arch/x86/xen/time.c +++ b/arch/x86/xen/time.c @@ -26,8 +26,6 @@ #include "xen-ops.h" -#define XEN_SHIFT 22 - /* Xen may fire a timer up to this many ns early */ #define TIMER_SLOP 100000 #define NS_PER_TICK (1000000000LL / HZ) @@ -211,8 +209,6 @@ static struct clocksource xen_clocksource __read_mostly = { .rating = 400, .read = xen_clocksource_get_cycles, .mask = ~0, - .mult = 1< Date: Mon, 26 Apr 2010 20:20:47 -0700 Subject: ia64: convert to clocksource_register_hz/khz This converts the ia64 clocksources to use clocksource_register_hz/khz CC: Tony Luck CC: Thomas Gleixner Tested-by: Tony Luck [clocksource_itc path] Signed-off-by: John Stultz diff --git a/arch/ia64/kernel/cyclone.c b/arch/ia64/kernel/cyclone.c index d52f1f7..f64097b 100644 --- a/arch/ia64/kernel/cyclone.c +++ b/arch/ia64/kernel/cyclone.c @@ -31,8 +31,6 @@ static struct clocksource clocksource_cyclone = { .rating = 300, .read = read_cyclone, .mask = (1LL << 40) - 1, - .mult = 0, /*to be caluclated*/ - .shift = 16, .flags = CLOCK_SOURCE_IS_CONTINUOUS, }; @@ -118,9 +116,7 @@ int __init init_cyclone_clock(void) /* initialize last tick */ cyclone_mc = cyclone_timer; clocksource_cyclone.fsys_mmio = cyclone_timer; - clocksource_cyclone.mult = clocksource_hz2mult(CYCLONE_TIMER_FREQ, - clocksource_cyclone.shift); - clocksource_register(&clocksource_cyclone); + clocksource_register_hz(&clocksource_cyclone, CYCLONE_TIMER_FREQ); return 0; } diff --git a/arch/ia64/kernel/time.c b/arch/ia64/kernel/time.c index 9702fa9..41c40f0 100644 --- a/arch/ia64/kernel/time.c +++ b/arch/ia64/kernel/time.c @@ -73,8 +73,6 @@ static struct clocksource clocksource_itc = { .rating = 350, .read = itc_get_cycles, .mask = CLOCKSOURCE_MASK(64), - .mult = 0, /*to be calculated*/ - .shift = 16, .flags = CLOCK_SOURCE_IS_CONTINUOUS, #ifdef CONFIG_PARAVIRT .resume = paravirt_clocksource_resume, @@ -374,11 +372,8 @@ ia64_init_itm (void) ia64_cpu_local_tick(); if (!itc_clocksource) { - /* Sort out mult/shift values: */ - clocksource_itc.mult = - clocksource_hz2mult(local_cpu_data->itc_freq, - clocksource_itc.shift); - clocksource_register(&clocksource_itc); + clocksource_register_hz(&clocksource_itc, + local_cpu_data->itc_freq); itc_clocksource = &clocksource_itc; } } diff --git a/arch/ia64/sn/kernel/sn2/timer.c b/arch/ia64/sn/kernel/sn2/timer.c index 21d6f09..c34efda 100644 --- a/arch/ia64/sn/kernel/sn2/timer.c +++ b/arch/ia64/sn/kernel/sn2/timer.c @@ -33,8 +33,6 @@ static struct clocksource clocksource_sn2 = { .rating = 450, .read = read_sn2, .mask = (1LL << 55) - 1, - .mult = 0, - .shift = 10, .flags = CLOCK_SOURCE_IS_CONTINUOUS, }; @@ -57,9 +55,7 @@ ia64_sn_udelay (unsigned long usecs) void __init sn_timer_init(void) { clocksource_sn2.fsys_mmio = RTC_COUNTER_ADDR; - clocksource_sn2.mult = clocksource_hz2mult(sn_rtc_cycles_per_second, - clocksource_sn2.shift); - clocksource_register(&clocksource_sn2); + clocksource_register_hz(&clocksource_sn2, sn_rtc_cycles_per_second); ia64_udelay = &ia64_sn_udelay; } diff --git a/drivers/char/hpet.c b/drivers/char/hpet.c index 7066e80..051474c 100644 --- a/drivers/char/hpet.c +++ b/drivers/char/hpet.c @@ -84,8 +84,6 @@ static struct clocksource clocksource_hpet = { .rating = 250, .read = read_hpet, .mask = CLOCKSOURCE_MASK(64), - .mult = 0, /* to be calculated */ - .shift = 10, .flags = CLOCK_SOURCE_IS_CONTINUOUS, }; static struct clocksource *hpet_clocksource; @@ -934,9 +932,7 @@ int hpet_alloc(struct hpet_data *hdp) if (!hpet_clocksource) { hpet_mctr = (void __iomem *)&hpetp->hp_hpet->hpet_mc; CLKSRC_FSYS_MMIO_SET(clocksource_hpet.fsys_mmio, hpet_mctr); - clocksource_hpet.mult = clocksource_hz2mult(hpetp->hp_tick_freq, - clocksource_hpet.shift); - clocksource_register(&clocksource_hpet); + clocksource_register_hz(&clocksource_hpet, hpetp->hp_tick_freq); hpetp->hp_clocksource = &clocksource_hpet; hpet_clocksource = &clocksource_hpet; } -- cgit v0.10.2 From b8f39f7dfe12d4c8402c493a24fbf1e21d086771 Mon Sep 17 00:00:00 2001 From: John Stultz Date: Mon, 26 Apr 2010 20:22:23 -0700 Subject: microblaze: convert to clocksource_register_hz/khz This converts the microblaze clocksources to use clocksource_register_hz/khz CC: Michal Simek CC: Thomas Gleixner Tested-by: Michal Simek Signed-off-by: John Stultz diff --git a/arch/microblaze/kernel/timer.c b/arch/microblaze/kernel/timer.c index a5aa33d..68ec7d1 100644 --- a/arch/microblaze/kernel/timer.c +++ b/arch/microblaze/kernel/timer.c @@ -217,16 +217,12 @@ static struct clocksource clocksource_microblaze = { .rating = 300, .read = microblaze_read, .mask = CLOCKSOURCE_MASK(32), - .shift = 8, /* I can shift it */ .flags = CLOCK_SOURCE_IS_CONTINUOUS, }; static int __init microblaze_clocksource_init(void) { - clocksource_microblaze.mult = - clocksource_hz2mult(timer_clock_freq, - clocksource_microblaze.shift); - if (clocksource_register(&clocksource_microblaze)) + if (clocksource_register_hz(&clocksource_microblaze, timer_clock_freq)) panic("failed to register clocksource"); /* stop timer1 */ -- cgit v0.10.2 From 7861434fe9b5c9dad1bbb1f674cded95950e778e Mon Sep 17 00:00:00 2001 From: John Stultz Date: Tue, 19 Oct 2010 17:49:07 -0700 Subject: alpha: convert to clocksource_register_hz Converts alpha to use clocksource_register_hz. CC: Richard Henderson CC: Ivan Kokshaysky CC: Matt Turner CC: Thomas Gleixner Signed-off-by: John Stultz diff --git a/arch/alpha/kernel/time.c b/arch/alpha/kernel/time.c index c1f3e7c..33b8110 100644 --- a/arch/alpha/kernel/time.c +++ b/arch/alpha/kernel/time.c @@ -378,8 +378,7 @@ static struct clocksource clocksource_rpcc = { static inline void register_rpcc_clocksource(long cycle_freq) { - clocksource_calc_mult_shift(&clocksource_rpcc, cycle_freq, 4); - clocksource_register(&clocksource_rpcc); + clocksource_register_hz(&clocksource_rpcc, cycle_freq); } #else /* !CONFIG_SMP */ static inline void register_rpcc_clocksource(long cycle_freq) -- cgit v0.10.2 From 39280742efb00ab61ad62486c737fdd3e980c30f Mon Sep 17 00:00:00 2001 From: John Stultz Date: Mon, 26 Apr 2010 20:24:37 -0700 Subject: sparc: convert to clocksource_register_hz/khz This converts the sparc clocksources to use clocksource_register_hz/khz CC: "David S. Miller" CC: Thomas Gleixner Signed-off-by: John Stultz diff --git a/arch/sparc/kernel/time_64.c b/arch/sparc/kernel/time_64.c index 3bc9c99..58aa27b 100644 --- a/arch/sparc/kernel/time_64.c +++ b/arch/sparc/kernel/time_64.c @@ -816,14 +816,12 @@ void __init time_init(void) clocksource_hz2mult(freq, SPARC64_NSEC_PER_CYC_SHIFT); clocksource_tick.name = tick_ops->name; - clocksource_calc_mult_shift(&clocksource_tick, freq, 4); clocksource_tick.read = clocksource_tick_read; + clocksource_register_hz(&clocksource_tick, freq); printk("clocksource: mult[%x] shift[%d]\n", clocksource_tick.mult, clocksource_tick.shift); - clocksource_register(&clocksource_tick); - sparc64_clockevent.name = tick_ops->name; clockevents_calc_mult_shift(&sparc64_clockevent, freq, 4); -- cgit v0.10.2 From 75c4fd8c7862f37eeae5c80f33bbe4dce97571d4 Mon Sep 17 00:00:00 2001 From: John Stultz Date: Mon, 26 Apr 2010 20:23:11 -0700 Subject: mips: convert to clocksource_register_hz/khz This converts the mips clocksources to use clocksource_register_hz/khz CC: Ralf Baechle CC: Thomas Gleixner Signed-off-by: John Stultz diff --git a/arch/mips/alchemy/common/time.c b/arch/mips/alchemy/common/time.c index 2aecb2f..d5da6ad 100644 --- a/arch/mips/alchemy/common/time.c +++ b/arch/mips/alchemy/common/time.c @@ -141,8 +141,7 @@ static int __init alchemy_time_init(unsigned int m2int) goto cntr_err; /* register counter1 clocksource and event device */ - clocksource_set_clock(&au1x_counter1_clocksource, 32768); - clocksource_register(&au1x_counter1_clocksource); + clocksource_register_hz(&au1x_counter1_clocksource, 32768); cd->shift = 32; cd->mult = div_sc(32768, NSEC_PER_SEC, cd->shift); diff --git a/arch/mips/cavium-octeon/csrc-octeon.c b/arch/mips/cavium-octeon/csrc-octeon.c index 26bf711..29d56af 100644 --- a/arch/mips/cavium-octeon/csrc-octeon.c +++ b/arch/mips/cavium-octeon/csrc-octeon.c @@ -105,8 +105,7 @@ unsigned long long notrace sched_clock(void) void __init plat_time_init(void) { clocksource_mips.rating = 300; - clocksource_set_clock(&clocksource_mips, octeon_get_clock_rate()); - clocksource_register(&clocksource_mips); + clocksource_register_hz(&clocksource_mips, octeon_get_clock_rate()); } static u64 octeon_udelay_factor; diff --git a/arch/mips/include/asm/time.h b/arch/mips/include/asm/time.h index c7f1bfe..bc14447 100644 --- a/arch/mips/include/asm/time.h +++ b/arch/mips/include/asm/time.h @@ -84,12 +84,6 @@ static inline int init_mips_clocksource(void) #endif } -static inline void clocksource_set_clock(struct clocksource *cs, - unsigned int clock) -{ - clocksource_calc_mult_shift(cs, clock, 4); -} - static inline void clockevent_set_clock(struct clock_event_device *cd, unsigned int clock) { diff --git a/arch/mips/jz4740/time.c b/arch/mips/jz4740/time.c index fe01678..03dfd4e 100644 --- a/arch/mips/jz4740/time.c +++ b/arch/mips/jz4740/time.c @@ -121,8 +121,7 @@ void __init plat_time_init(void) clockevents_register_device(&jz4740_clockevent); - clocksource_set_clock(&jz4740_clocksource, clk_rate); - ret = clocksource_register(&jz4740_clocksource); + ret = clocksource_register_hz(&jz4740_clocksource, clk_rate); if (ret) printk(KERN_ERR "Failed to register clocksource: %d\n", ret); diff --git a/arch/mips/kernel/cevt-txx9.c b/arch/mips/kernel/cevt-txx9.c index 0b73773..f0ab92a 100644 --- a/arch/mips/kernel/cevt-txx9.c +++ b/arch/mips/kernel/cevt-txx9.c @@ -51,8 +51,7 @@ void __init txx9_clocksource_init(unsigned long baseaddr, { struct txx9_tmr_reg __iomem *tmrptr; - clocksource_set_clock(&txx9_clocksource.cs, TIMER_CLK(imbusclk)); - clocksource_register(&txx9_clocksource.cs); + clocksource_register_hz(&txx9_clocksource.cs, TIMER_CLK(imbusclk)); tmrptr = ioremap(baseaddr, sizeof(struct txx9_tmr_reg)); __raw_writel(TCR_BASE, &tmrptr->tcr); diff --git a/arch/mips/kernel/csrc-bcm1480.c b/arch/mips/kernel/csrc-bcm1480.c index 51489f8..f96f99c 100644 --- a/arch/mips/kernel/csrc-bcm1480.c +++ b/arch/mips/kernel/csrc-bcm1480.c @@ -49,6 +49,5 @@ void __init sb1480_clocksource_init(void) plldiv = G_BCM1480_SYS_PLL_DIV(__raw_readq(IOADDR(A_SCD_SYSTEM_CFG))); zbbus = ((plldiv >> 1) * 50000000) + ((plldiv & 1) * 25000000); - clocksource_set_clock(cs, zbbus); - clocksource_register(cs); + clocksource_register_hz(cs, zbbus); } diff --git a/arch/mips/kernel/csrc-ioasic.c b/arch/mips/kernel/csrc-ioasic.c index 23da108..46bd7fa 100644 --- a/arch/mips/kernel/csrc-ioasic.c +++ b/arch/mips/kernel/csrc-ioasic.c @@ -59,7 +59,5 @@ void __init dec_ioasic_clocksource_init(void) printk(KERN_INFO "I/O ASIC clock frequency %dHz\n", freq); clocksource_dec.rating = 200 + freq / 10000000; - clocksource_set_clock(&clocksource_dec, freq); - - clocksource_register(&clocksource_dec); + clocksource_register_hz(&clocksource_dec, freq); } diff --git a/arch/mips/kernel/csrc-powertv.c b/arch/mips/kernel/csrc-powertv.c index a27c16c..2e7c523 100644 --- a/arch/mips/kernel/csrc-powertv.c +++ b/arch/mips/kernel/csrc-powertv.c @@ -78,9 +78,7 @@ static void __init powertv_c0_hpt_clocksource_init(void) clocksource_mips.rating = 200 + mips_hpt_frequency / 10000000; - clocksource_set_clock(&clocksource_mips, mips_hpt_frequency); - - clocksource_register(&clocksource_mips); + clocksource_register_hz(&clocksource_mips, mips_hpt_frequency); } /** @@ -130,43 +128,16 @@ static struct clocksource clocksource_tim_c = { /** * powertv_tim_c_clocksource_init - set up a clock source for the TIM_C clock * - * The hard part here is coming up with a constant k and shift s such that - * the 48-bit TIM_C value multiplied by k doesn't overflow and that value, - * when shifted right by s, yields the corresponding number of nanoseconds. * We know that TIM_C counts at 27 MHz/8, so each cycle corresponds to - * 1 / (27,000,000/8) seconds. Multiply that by a billion and you get the - * number of nanoseconds. Since the TIM_C value has 48 bits and the math is - * done in 64 bits, avoiding an overflow means that k must be less than - * 64 - 48 = 16 bits. + * 1 / (27,000,000/8) seconds. */ static void __init powertv_tim_c_clocksource_init(void) { - int prescale; - unsigned long dividend; - unsigned long k; - int s; - const int max_k_bits = (64 - 48) - 1; - const unsigned long billion = 1000000000; const unsigned long counts_per_second = 27000000 / 8; - prescale = BITS_PER_LONG - ilog2(billion) - 1; - dividend = billion << prescale; - k = dividend / counts_per_second; - s = ilog2(k) - max_k_bits; - - if (s < 0) - s = prescale; - - else { - k >>= s; - s += prescale; - } - - clocksource_tim_c.mult = k; - clocksource_tim_c.shift = s; clocksource_tim_c.rating = 200; - clocksource_register(&clocksource_tim_c); + clocksource_register_hz(&clocksource_tim_c, counts_per_second); tim_c = (struct tim_c *) asic_reg_addr(tim_ch); } diff --git a/arch/mips/kernel/csrc-r4k.c b/arch/mips/kernel/csrc-r4k.c index e95a3cd..decd1fa 100644 --- a/arch/mips/kernel/csrc-r4k.c +++ b/arch/mips/kernel/csrc-r4k.c @@ -30,9 +30,7 @@ int __init init_r4k_clocksource(void) /* Calculate a somewhat reasonable rating value */ clocksource_mips.rating = 200 + mips_hpt_frequency / 10000000; - clocksource_set_clock(&clocksource_mips, mips_hpt_frequency); - - clocksource_register(&clocksource_mips); + clocksource_register_hz(&clocksource_mips, mips_hpt_frequency); return 0; } diff --git a/arch/mips/kernel/csrc-sb1250.c b/arch/mips/kernel/csrc-sb1250.c index d14d3d1..e9606d9 100644 --- a/arch/mips/kernel/csrc-sb1250.c +++ b/arch/mips/kernel/csrc-sb1250.c @@ -65,6 +65,5 @@ void __init sb1250_clocksource_init(void) IOADDR(A_SCD_TIMER_REGISTER(SB1250_HPT_NUM, R_SCD_TIMER_CFG))); - clocksource_set_clock(cs, V_SCD_TIMER_FREQ); - clocksource_register(cs); + clocksource_register_hz(cs, V_SCD_TIMER_FREQ); } diff --git a/arch/mips/kernel/i8253.c b/arch/mips/kernel/i8253.c index 2392a7a2..9fadd17 100644 --- a/arch/mips/kernel/i8253.c +++ b/arch/mips/kernel/i8253.c @@ -196,8 +196,6 @@ static struct clocksource clocksource_pit = { .rating = 110, .read = pit_read, .mask = CLOCKSOURCE_MASK(32), - .mult = 0, - .shift = 20, }; static int __init init_pit_clocksource(void) @@ -205,7 +203,6 @@ static int __init init_pit_clocksource(void) if (num_possible_cpus() > 1) /* PIT does not scale! */ return 0; - clocksource_pit.mult = clocksource_hz2mult(CLOCK_TICK_RATE, 20); - return clocksource_register(&clocksource_pit); + return clocksource_register_hz(&clocksource_pit, CLOCK_TICK_RATE); } arch_initcall(init_pit_clocksource); diff --git a/arch/mips/loongson/common/cs5536/cs5536_mfgpt.c b/arch/mips/loongson/common/cs5536/cs5536_mfgpt.c index 8c807c9..0cb1b97 100644 --- a/arch/mips/loongson/common/cs5536/cs5536_mfgpt.c +++ b/arch/mips/loongson/common/cs5536/cs5536_mfgpt.c @@ -201,8 +201,6 @@ static struct clocksource clocksource_mfgpt = { .rating = 120, /* Functional for real use, but not desired */ .read = mfgpt_read, .mask = CLOCKSOURCE_MASK(32), - .mult = 0, - .shift = 22, }; int __init init_mfgpt_clocksource(void) @@ -210,8 +208,7 @@ int __init init_mfgpt_clocksource(void) if (num_possible_cpus() > 1) /* MFGPT does not scale! */ return 0; - clocksource_mfgpt.mult = clocksource_hz2mult(MFGPT_TICK_RATE, 22); - return clocksource_register(&clocksource_mfgpt); + return clocksource_register_hz(&clocksource_mfgpt, MFGPT_TICK_RATE); } arch_initcall(init_mfgpt_clocksource); diff --git a/arch/mips/sgi-ip27/ip27-timer.c b/arch/mips/sgi-ip27/ip27-timer.c index d6802d6..3cac883 100644 --- a/arch/mips/sgi-ip27/ip27-timer.c +++ b/arch/mips/sgi-ip27/ip27-timer.c @@ -177,8 +177,7 @@ static void __init hub_rt_clocksource_init(void) { struct clocksource *cs = &hub_rt_clocksource; - clocksource_set_clock(cs, CYCLES_PER_SEC); - clocksource_register(cs); + clocksource_register_hz(cs, CYCLES_PER_SEC); } void __init plat_time_init(void) -- cgit v0.10.2 From a1c57e0fec53defe745e64417eacdbd3618c3e66 Mon Sep 17 00:00:00 2001 From: John Stultz Date: Mon, 26 Apr 2010 20:20:07 -0700 Subject: blackfin: convert to clocksource_register_hz This converts the blackfin clocksource to use clocksource_register_hz. CC: Mike Frysinger CC: Thomas Gleixner Signed-off-by: John Stultz diff --git a/arch/blackfin/kernel/time-ts.c b/arch/blackfin/kernel/time-ts.c index 8c9a43d..4a01371 100644 --- a/arch/blackfin/kernel/time-ts.c +++ b/arch/blackfin/kernel/time-ts.c @@ -23,29 +23,6 @@ #include #include -/* Accelerators for sched_clock() - * convert from cycles(64bits) => nanoseconds (64bits) - * basic equation: - * ns = cycles / (freq / ns_per_sec) - * ns = cycles * (ns_per_sec / freq) - * ns = cycles * (10^9 / (cpu_khz * 10^3)) - * ns = cycles * (10^6 / cpu_khz) - * - * Then we use scaling math (suggested by george@mvista.com) to get: - * ns = cycles * (10^6 * SC / cpu_khz) / SC - * ns = cycles * cyc2ns_scale / SC - * - * And since SC is a constant power of two, we can convert the div - * into a shift. - * - * We can use khz divisor instead of mhz to keep a better precision, since - * cyc2ns_scale is limited to 10^6 * 2^10, which fits in 32 bits. - * (mathieu.desnoyers@polymtl.ca) - * - * -johnstul@us.ibm.com "math is hard, lets go shopping!" - */ - -#define CYC2NS_SCALE_FACTOR 10 /* 2^10, carefully chosen */ #if defined(CONFIG_CYCLES_CLOCKSOURCE) @@ -63,7 +40,6 @@ static struct clocksource bfin_cs_cycles = { .rating = 400, .read = bfin_read_cycles, .mask = CLOCKSOURCE_MASK(64), - .shift = CYC2NS_SCALE_FACTOR, .flags = CLOCK_SOURCE_IS_CONTINUOUS, }; @@ -75,10 +51,7 @@ static inline unsigned long long bfin_cs_cycles_sched_clock(void) static int __init bfin_cs_cycles_init(void) { - bfin_cs_cycles.mult = \ - clocksource_hz2mult(get_cclk(), bfin_cs_cycles.shift); - - if (clocksource_register(&bfin_cs_cycles)) + if (clocksource_register_hz(&bfin_cs_cycles, get_cclk())) panic("failed to register clocksource"); return 0; @@ -111,7 +84,6 @@ static struct clocksource bfin_cs_gptimer0 = { .rating = 350, .read = bfin_read_gptimer0, .mask = CLOCKSOURCE_MASK(32), - .shift = CYC2NS_SCALE_FACTOR, .flags = CLOCK_SOURCE_IS_CONTINUOUS, }; @@ -125,10 +97,7 @@ static int __init bfin_cs_gptimer0_init(void) { setup_gptimer0(); - bfin_cs_gptimer0.mult = \ - clocksource_hz2mult(get_sclk(), bfin_cs_gptimer0.shift); - - if (clocksource_register(&bfin_cs_gptimer0)) + if (clocksource_register_hz(&bfin_cs_gptimer0, get_sclk())) panic("failed to register clocksource"); return 0; -- cgit v0.10.2 From d79647aea22732f39c81bbdc80931f96b46023f0 Mon Sep 17 00:00:00 2001 From: Daniel De Graaf Date: Mon, 7 Mar 2011 15:18:57 -0500 Subject: xen/gntdev,gntalloc: Remove unneeded VM flags The only time when granted pages need to be treated specially is when using Xen's PTE modification for grant mappings owned by another domain (that is, only gntdev on PV guests). Otherwise, the area does not require VM_DONTCOPY and VM_PFNMAP, since it can be accessed just like any other page of RAM. Since the vm_operations_struct close operations decrement reference counts, a corresponding open function that increments them is required now that it is possible to have multiple references to a single area. We are careful in the gntdev to check if we can remove those flags. The reason that we need to be careful in gntdev on PV guests is because we are not changing the PFN/MFN mapping on PV; instead, we change the application's page tables to point to the other domain's memory. This means that the vma cannot be copied without using another grant mapping hypercall; it also requires special handling on unmap, which is the reason for gntdev's dependency on the MMU notifier. For gntalloc, this is not a concern - the pages are owned by the domain using the gntalloc device, and can be mapped and unmapped in the same manner as any other page of memory. Acked-by: Ian Campbell Signed-off-by: Daniel De Graaf Signed-off-by: Konrad Rzeszutek Wilk [v2: Added in git commit "We are.." from email correspondence] diff --git a/drivers/xen/gntalloc.c b/drivers/xen/gntalloc.c index a7ffdfe..f6832f4 100644 --- a/drivers/xen/gntalloc.c +++ b/drivers/xen/gntalloc.c @@ -427,6 +427,17 @@ static long gntalloc_ioctl(struct file *filp, unsigned int cmd, return 0; } +static void gntalloc_vma_open(struct vm_area_struct *vma) +{ + struct gntalloc_gref *gref = vma->vm_private_data; + if (!gref) + return; + + spin_lock(&gref_lock); + gref->users++; + spin_unlock(&gref_lock); +} + static void gntalloc_vma_close(struct vm_area_struct *vma) { struct gntalloc_gref *gref = vma->vm_private_data; @@ -441,6 +452,7 @@ static void gntalloc_vma_close(struct vm_area_struct *vma) } static struct vm_operations_struct gntalloc_vmops = { + .open = gntalloc_vma_open, .close = gntalloc_vma_close, }; @@ -471,8 +483,6 @@ static int gntalloc_mmap(struct file *filp, struct vm_area_struct *vma) vma->vm_private_data = gref; vma->vm_flags |= VM_RESERVED; - vma->vm_flags |= VM_DONTCOPY; - vma->vm_flags |= VM_PFNMAP | VM_PFN_AT_MMAP; vma->vm_ops = &gntalloc_vmops; diff --git a/drivers/xen/gntdev.c b/drivers/xen/gntdev.c index d96d311..687761f 100644 --- a/drivers/xen/gntdev.c +++ b/drivers/xen/gntdev.c @@ -358,17 +358,26 @@ static int unmap_grant_pages(struct grant_map *map, int offset, int pages) /* ------------------------------------------------------------------ */ +static void gntdev_vma_open(struct vm_area_struct *vma) +{ + struct grant_map *map = vma->vm_private_data; + + pr_debug("gntdev_vma_open %p\n", vma); + atomic_inc(&map->users); +} + static void gntdev_vma_close(struct vm_area_struct *vma) { struct grant_map *map = vma->vm_private_data; - pr_debug("close %p\n", vma); + pr_debug("gntdev_vma_close %p\n", vma); map->vma = NULL; vma->vm_private_data = NULL; gntdev_put_map(map); } static struct vm_operations_struct gntdev_vmops = { + .open = gntdev_vma_open, .close = gntdev_vma_close, }; @@ -680,7 +689,10 @@ static int gntdev_mmap(struct file *flip, struct vm_area_struct *vma) vma->vm_ops = &gntdev_vmops; - vma->vm_flags |= VM_RESERVED|VM_DONTCOPY|VM_DONTEXPAND|VM_PFNMAP; + vma->vm_flags |= VM_RESERVED|VM_DONTEXPAND; + + if (use_ptemod) + vma->vm_flags |= VM_DONTCOPY|VM_PFNMAP; vma->vm_private_data = map; -- cgit v0.10.2 From a97590e56d0d58e1dd262353f7cbd84e81d8e600 Mon Sep 17 00:00:00 2001 From: Alex Williamson Date: Fri, 4 Mar 2011 14:52:16 -0700 Subject: intel-iommu: Unlink domain from iommu When we remove a device, we unlink the iommu from the domain, but we never do the reverse unlinking of the domain from the iommu. This means that we never clear iommu->domain_ids, eventually leading to resource exhaustion if we repeatedly bind and unbind a device to a driver. Also free empty domains to avoid a resource leak. Signed-off-by: Alex Williamson Acked-by: Donald Dutile Signed-off-by: David Woodhouse Cc: stable@kernel.org diff --git a/drivers/pci/intel-iommu.c b/drivers/pci/intel-iommu.c index 35463dd..292f223 100644 --- a/drivers/pci/intel-iommu.c +++ b/drivers/pci/intel-iommu.c @@ -3260,9 +3260,15 @@ static int device_notifier(struct notifier_block *nb, if (!domain) return 0; - if (action == BUS_NOTIFY_UNBOUND_DRIVER && !iommu_pass_through) + if (action == BUS_NOTIFY_UNBOUND_DRIVER && !iommu_pass_through) { domain_remove_one_dev_info(domain, pdev); + if (!(domain->flags & DOMAIN_FLAG_VIRTUAL_MACHINE) && + !(domain->flags & DOMAIN_FLAG_STATIC_IDENTITY) && + list_empty(&domain->devices)) + domain_exit(domain); + } + return 0; } @@ -3411,6 +3417,11 @@ static void domain_remove_one_dev_info(struct dmar_domain *domain, domain->iommu_count--; domain_update_iommu_cap(domain); spin_unlock_irqrestore(&domain->iommu_lock, tmp_flags); + + spin_lock_irqsave(&iommu->lock, tmp_flags); + clear_bit(domain->id, iommu->domain_ids); + iommu->domains[domain->id] = NULL; + spin_unlock_irqrestore(&iommu->lock, tmp_flags); } spin_unlock_irqrestore(&device_domain_lock, flags); -- cgit v0.10.2 From 2fe9723df8e45fd247782adea244a5e653c30bf4 Mon Sep 17 00:00:00 2001 From: Alex Williamson Date: Fri, 4 Mar 2011 14:52:30 -0700 Subject: intel-iommu: Fix get_domain_for_dev() error path If we run out of domain_ids and fail iommu_attach_domain(), we fall into domain_exit() without having setup enough of the domain structure for this to do anything useful. In fact, it typically runs off into the weeds walking the bogus domain->devices list. Just free the domain. Signed-off-by: Alex Williamson Acked-by: Donald Dutile Signed-off-by: David Woodhouse Cc: stable@kernel.org diff --git a/drivers/pci/intel-iommu.c b/drivers/pci/intel-iommu.c index 292f223..5dc5d3e 100644 --- a/drivers/pci/intel-iommu.c +++ b/drivers/pci/intel-iommu.c @@ -1835,7 +1835,7 @@ static struct dmar_domain *get_domain_for_dev(struct pci_dev *pdev, int gaw) ret = iommu_attach_domain(domain, iommu); if (ret) { - domain_exit(domain); + free_domain_mem(domain); goto error; } -- cgit v0.10.2 From 45bb1674b976ef81429c1e42de05844b49d45dea Mon Sep 17 00:00:00 2001 From: Daniel Drake Date: Sun, 13 Mar 2011 15:10:17 +0000 Subject: x86, olpc: Use device tree for platform identification Make OLPC fully depend on device tree, and use it to identify the OLPC platform details. Some nodes are exposed as platform devices where we plan to use device tree for device probing. Signed-off-by: Daniel Drake Acked-by: Grant Likely LKML-Reference: <20110313151017.C255F9D401E@zog.reactivated.net> Signed-off-by: H. Peter Anvin diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig index b4c2e9c..471221b 100644 --- a/arch/x86/Kconfig +++ b/arch/x86/Kconfig @@ -2071,7 +2071,7 @@ config OLPC depends on !X86_PAE select GPIOLIB select OF - select OF_PROMTREE if PROC_DEVICETREE + select OF_PROMTREE ---help--- Add support for detecting the unique features of the OLPC XO hardware. diff --git a/arch/x86/include/asm/olpc_ofw.h b/arch/x86/include/asm/olpc_ofw.h index c5d3a5a..2448771 100644 --- a/arch/x86/include/asm/olpc_ofw.h +++ b/arch/x86/include/asm/olpc_ofw.h @@ -26,15 +26,12 @@ extern void setup_olpc_ofw_pgd(void); /* check if OFW was detected during boot */ extern bool olpc_ofw_present(void); +extern void olpc_dt_build_devicetree(void); + #else /* !CONFIG_OLPC */ static inline void olpc_ofw_detect(void) { } static inline void setup_olpc_ofw_pgd(void) { } -#endif /* !CONFIG_OLPC */ - -#ifdef CONFIG_OF_PROMTREE -extern void olpc_dt_build_devicetree(void); -#else static inline void olpc_dt_build_devicetree(void) { } -#endif +#endif /* !CONFIG_OLPC */ #endif /* _ASM_X86_OLPC_OFW_H */ diff --git a/arch/x86/platform/olpc/Makefile b/arch/x86/platform/olpc/Makefile index c2a8cab..81c5e21 100644 --- a/arch/x86/platform/olpc/Makefile +++ b/arch/x86/platform/olpc/Makefile @@ -1,4 +1,2 @@ -obj-$(CONFIG_OLPC) += olpc.o +obj-$(CONFIG_OLPC) += olpc.o olpc_ofw.o olpc_dt.o obj-$(CONFIG_OLPC_XO1) += olpc-xo1.o -obj-$(CONFIG_OLPC) += olpc_ofw.o -obj-$(CONFIG_OF_PROMTREE) += olpc_dt.o diff --git a/arch/x86/platform/olpc/olpc.c b/arch/x86/platform/olpc/olpc.c index edaf3fe..0060fd5 100644 --- a/arch/x86/platform/olpc/olpc.c +++ b/arch/x86/platform/olpc/olpc.c @@ -18,6 +18,7 @@ #include #include #include +#include #include #include @@ -187,41 +188,43 @@ err: } EXPORT_SYMBOL_GPL(olpc_ec_cmd); -static bool __init check_ofw_architecture(void) +static bool __init check_ofw_architecture(struct device_node *root) { - size_t propsize; - char olpc_arch[5]; - const void *args[] = { NULL, "architecture", olpc_arch, (void *)5 }; - void *res[] = { &propsize }; + const char *olpc_arch; + int propsize; - if (olpc_ofw("getprop", args, res)) { - printk(KERN_ERR "ofw: getprop call failed!\n"); - return false; - } + olpc_arch = of_get_property(root, "architecture", &propsize); return propsize == 5 && strncmp("OLPC", olpc_arch, 5) == 0; } -static u32 __init get_board_revision(void) +static u32 __init get_board_revision(struct device_node *root) { - size_t propsize; - __be32 rev; - const void *args[] = { NULL, "board-revision-int", &rev, (void *)4 }; - void *res[] = { &propsize }; - - if (olpc_ofw("getprop", args, res) || propsize != 4) { - printk(KERN_ERR "ofw: getprop call failed!\n"); - return cpu_to_be32(0); - } - return be32_to_cpu(rev); + int propsize; + const __be32 *rev; + + rev = of_get_property(root, "board-revision-int", &propsize); + if (propsize != 4) + return 0; + + return be32_to_cpu(*rev); } static bool __init platform_detect(void) { - if (!check_ofw_architecture()) + struct device_node *root = of_find_node_by_path("/"); + bool success; + + if (!root) return false; - olpc_platform_info.flags |= OLPC_F_PRESENT; - olpc_platform_info.boardrev = get_board_revision(); - return true; + + success = check_ofw_architecture(root); + if (success) { + olpc_platform_info.boardrev = get_board_revision(root); + olpc_platform_info.flags |= OLPC_F_PRESENT; + } + + of_node_put(root); + return success; } static int __init add_xo1_platform_devices(void) diff --git a/arch/x86/platform/olpc/olpc_dt.c b/arch/x86/platform/olpc/olpc_dt.c index dab8746..4ce208f 100644 --- a/arch/x86/platform/olpc/olpc_dt.c +++ b/arch/x86/platform/olpc/olpc_dt.c @@ -19,7 +19,9 @@ #include #include #include +#include #include +#include #include static phandle __init olpc_dt_getsibling(phandle node) @@ -181,3 +183,20 @@ void __init olpc_dt_build_devicetree(void) pr_info("PROM DT: Built device tree with %u bytes of memory.\n", prom_early_allocated); } + +/* A list of DT node/bus matches that we want to expose as platform devices */ +static struct of_device_id __initdata of_ids[] = { + { .compatible = "olpc,xo1-battery" }, + { .compatible = "olpc,xo1-dcon" }, + { .compatible = "olpc,xo1-rtc" }, + {}, +}; + +static int __init olpc_create_platform_devices(void) +{ + if (machine_is_olpc()) + return of_platform_bus_probe(NULL, of_ids, NULL); + else + return 0; +} +device_initcall(olpc_create_platform_devices); -- cgit v0.10.2 From 5d94e81f69d4b1d1102d3ab557ce0a817c11fbbb Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Tue, 8 Mar 2011 10:36:19 -0800 Subject: x86: Introduce pci_map_biosrom() The isci driver needs to retrieve its preboot OROM image which contains necessary runtime parameters like platform specific sas addresses and phy configuration. There is no ROM BAR associated with this area, instead we will need to scan legacy expansion ROM space. 1/ Promote the probe_roms_32 implementation to x86-64 2/ Add a facility to find and map an adapter rom by pci device (according to PCI Firmware Specification Revision 3.0) Signed-off-by: Dave Jiang LKML-Reference: <20110308183226.6246.90354.stgit@localhost6.localdomain6> Signed-off-by: Dan Williams Signed-off-by: H. Peter Anvin diff --git a/arch/x86/include/asm/probe_roms.h b/arch/x86/include/asm/probe_roms.h new file mode 100644 index 0000000..4950a0b --- /dev/null +++ b/arch/x86/include/asm/probe_roms.h @@ -0,0 +1,8 @@ +#ifndef _PROBE_ROMS_H_ +#define _PROBE_ROMS_H_ +struct pci_dev; + +extern void __iomem *pci_map_biosrom(struct pci_dev *pdev); +extern void pci_unmap_biosrom(void __iomem *rom); +extern size_t pci_biosrom_size(struct pci_dev *pdev); +#endif diff --git a/arch/x86/include/asm/setup.h b/arch/x86/include/asm/setup.h index db8aa19..03d3a32 100644 --- a/arch/x86/include/asm/setup.h +++ b/arch/x86/include/asm/setup.h @@ -104,10 +104,10 @@ void *extend_brk(size_t size, size_t align); type *name; \ RESERVE_BRK(name, sizeof(type) * entries) +extern void probe_roms(void); #ifdef __i386__ void __init i386_start_kernel(void); -extern void probe_roms(void); #else void __init x86_64_start_kernel(char *real_mode); diff --git a/arch/x86/kernel/Makefile b/arch/x86/kernel/Makefile index 62445ba..f33d738 100644 --- a/arch/x86/kernel/Makefile +++ b/arch/x86/kernel/Makefile @@ -36,7 +36,7 @@ obj-y += traps.o irq.o irq_$(BITS).o dumpstack_$(BITS).o obj-y += time.o ioport.o ldt.o dumpstack.o obj-y += setup.o x86_init.o i8259.o irqinit.o jump_label.o obj-$(CONFIG_IRQ_WORK) += irq_work.o -obj-$(CONFIG_X86_32) += probe_roms_32.o +obj-y += probe_roms.o obj-$(CONFIG_X86_32) += sys_i386_32.o i386_ksyms_32.o obj-$(CONFIG_X86_64) += sys_x86_64.o x8664_ksyms_64.o obj-$(CONFIG_X86_64) += syscall_64.o vsyscall_64.o diff --git a/arch/x86/kernel/head32.c b/arch/x86/kernel/head32.c index 7f138b3..eab4940 100644 --- a/arch/x86/kernel/head32.c +++ b/arch/x86/kernel/head32.c @@ -23,7 +23,6 @@ static void __init i386_default_early_setup(void) { /* Initialize 32bit specific setup functions */ - x86_init.resources.probe_roms = probe_roms; x86_init.resources.reserve_resources = i386_reserve_resources; x86_init.mpparse.setup_ioapic_ids = setup_ioapic_ids_from_mpc; diff --git a/arch/x86/kernel/probe_roms.c b/arch/x86/kernel/probe_roms.c new file mode 100644 index 0000000..ba0a4cc --- /dev/null +++ b/arch/x86/kernel/probe_roms.c @@ -0,0 +1,267 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +#include +#include +#include +#include +#include +#include + +static struct resource system_rom_resource = { + .name = "System ROM", + .start = 0xf0000, + .end = 0xfffff, + .flags = IORESOURCE_BUSY | IORESOURCE_READONLY | IORESOURCE_MEM +}; + +static struct resource extension_rom_resource = { + .name = "Extension ROM", + .start = 0xe0000, + .end = 0xeffff, + .flags = IORESOURCE_BUSY | IORESOURCE_READONLY | IORESOURCE_MEM +}; + +static struct resource adapter_rom_resources[] = { { + .name = "Adapter ROM", + .start = 0xc8000, + .end = 0, + .flags = IORESOURCE_BUSY | IORESOURCE_READONLY | IORESOURCE_MEM +}, { + .name = "Adapter ROM", + .start = 0, + .end = 0, + .flags = IORESOURCE_BUSY | IORESOURCE_READONLY | IORESOURCE_MEM +}, { + .name = "Adapter ROM", + .start = 0, + .end = 0, + .flags = IORESOURCE_BUSY | IORESOURCE_READONLY | IORESOURCE_MEM +}, { + .name = "Adapter ROM", + .start = 0, + .end = 0, + .flags = IORESOURCE_BUSY | IORESOURCE_READONLY | IORESOURCE_MEM +}, { + .name = "Adapter ROM", + .start = 0, + .end = 0, + .flags = IORESOURCE_BUSY | IORESOURCE_READONLY | IORESOURCE_MEM +}, { + .name = "Adapter ROM", + .start = 0, + .end = 0, + .flags = IORESOURCE_BUSY | IORESOURCE_READONLY | IORESOURCE_MEM +} }; + +static struct resource video_rom_resource = { + .name = "Video ROM", + .start = 0xc0000, + .end = 0xc7fff, + .flags = IORESOURCE_BUSY | IORESOURCE_READONLY | IORESOURCE_MEM +}; + +/* does this oprom support the given pci device, or any of the devices + * that the driver supports? + */ +static bool match_id(struct pci_dev *pdev, unsigned short vendor, unsigned short device) +{ + struct pci_driver *drv = pdev->driver; + const struct pci_device_id *id; + + if (pdev->vendor == vendor && pdev->device == device) + return true; + + for (id = drv ? drv->id_table : NULL; id && id->vendor; id++) + if (id->vendor == vendor && id->device == device) + break; + + return id && id->vendor; +} + +static bool probe_list(struct pci_dev *pdev, unsigned short vendor, + const unsigned char *rom_list) +{ + unsigned short device; + + do { + if (probe_kernel_address(rom_list, device) != 0) + device = 0; + + if (device && match_id(pdev, vendor, device)) + break; + + rom_list += 2; + } while (device); + + return !!device; +} + +static struct resource *find_oprom(struct pci_dev *pdev) +{ + struct resource *oprom = NULL; + int i; + + for (i = 0; i < ARRAY_SIZE(adapter_rom_resources); i++) { + struct resource *res = &adapter_rom_resources[i]; + unsigned short offset, vendor, device, list, rev; + const unsigned char *rom; + + if (res->end == 0) + break; + + rom = isa_bus_to_virt(res->start); + if (probe_kernel_address(rom + 0x18, offset) != 0) + continue; + + if (probe_kernel_address(rom + offset + 0x4, vendor) != 0) + continue; + + if (probe_kernel_address(rom + offset + 0x6, device) != 0) + continue; + + if (match_id(pdev, vendor, device)) { + oprom = res; + break; + } + + if (probe_kernel_address(rom + offset + 0x8, list) == 0 && + probe_kernel_address(rom + offset + 0xc, rev) == 0 && + rev >= 3 && list && + probe_list(pdev, vendor, rom + offset + list)) { + oprom = res; + break; + } + } + + return oprom; +} + +void *pci_map_biosrom(struct pci_dev *pdev) +{ + struct resource *oprom = find_oprom(pdev); + + if (!oprom) + return NULL; + + return ioremap(oprom->start, resource_size(oprom)); +} +EXPORT_SYMBOL(pci_map_biosrom); + +void pci_unmap_biosrom(void __iomem *image) +{ + iounmap(image); +} +EXPORT_SYMBOL(pci_unmap_biosrom); + +size_t pci_biosrom_size(struct pci_dev *pdev) +{ + struct resource *oprom = find_oprom(pdev); + + return oprom ? resource_size(oprom) : 0; +} +EXPORT_SYMBOL(pci_biosrom_size); + +#define ROMSIGNATURE 0xaa55 + +static int __init romsignature(const unsigned char *rom) +{ + const unsigned short * const ptr = (const unsigned short *)rom; + unsigned short sig; + + return probe_kernel_address(ptr, sig) == 0 && sig == ROMSIGNATURE; +} + +static int __init romchecksum(const unsigned char *rom, unsigned long length) +{ + unsigned char sum, c; + + for (sum = 0; length && probe_kernel_address(rom++, c) == 0; length--) + sum += c; + return !length && !sum; +} + +void __init probe_roms(void) +{ + const unsigned char *rom; + unsigned long start, length, upper; + unsigned char c; + int i; + + /* video rom */ + upper = adapter_rom_resources[0].start; + for (start = video_rom_resource.start; start < upper; start += 2048) { + rom = isa_bus_to_virt(start); + if (!romsignature(rom)) + continue; + + video_rom_resource.start = start; + + if (probe_kernel_address(rom + 2, c) != 0) + continue; + + /* 0 < length <= 0x7f * 512, historically */ + length = c * 512; + + /* if checksum okay, trust length byte */ + if (length && romchecksum(rom, length)) + video_rom_resource.end = start + length - 1; + + request_resource(&iomem_resource, &video_rom_resource); + break; + } + + start = (video_rom_resource.end + 1 + 2047) & ~2047UL; + if (start < upper) + start = upper; + + /* system rom */ + request_resource(&iomem_resource, &system_rom_resource); + upper = system_rom_resource.start; + + /* check for extension rom (ignore length byte!) */ + rom = isa_bus_to_virt(extension_rom_resource.start); + if (romsignature(rom)) { + length = extension_rom_resource.end - extension_rom_resource.start + 1; + if (romchecksum(rom, length)) { + request_resource(&iomem_resource, &extension_rom_resource); + upper = extension_rom_resource.start; + } + } + + /* check for adapter roms on 2k boundaries */ + for (i = 0; i < ARRAY_SIZE(adapter_rom_resources) && start < upper; start += 2048) { + rom = isa_bus_to_virt(start); + if (!romsignature(rom)) + continue; + + if (probe_kernel_address(rom + 2, c) != 0) + continue; + + /* 0 < length <= 0x7f * 512, historically */ + length = c * 512; + + /* but accept any length that fits if checksum okay */ + if (!length || start + length > upper || !romchecksum(rom, length)) + continue; + + adapter_rom_resources[i].start = start; + adapter_rom_resources[i].end = start + length - 1; + request_resource(&iomem_resource, &adapter_rom_resources[i]); + + start = adapter_rom_resources[i++].end & ~2047UL; + } +} + diff --git a/arch/x86/kernel/probe_roms_32.c b/arch/x86/kernel/probe_roms_32.c deleted file mode 100644 index 071e7fe..0000000 --- a/arch/x86/kernel/probe_roms_32.c +++ /dev/null @@ -1,166 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - - -#include -#include -#include -#include -#include -#include - -static struct resource system_rom_resource = { - .name = "System ROM", - .start = 0xf0000, - .end = 0xfffff, - .flags = IORESOURCE_BUSY | IORESOURCE_READONLY | IORESOURCE_MEM -}; - -static struct resource extension_rom_resource = { - .name = "Extension ROM", - .start = 0xe0000, - .end = 0xeffff, - .flags = IORESOURCE_BUSY | IORESOURCE_READONLY | IORESOURCE_MEM -}; - -static struct resource adapter_rom_resources[] = { { - .name = "Adapter ROM", - .start = 0xc8000, - .end = 0, - .flags = IORESOURCE_BUSY | IORESOURCE_READONLY | IORESOURCE_MEM -}, { - .name = "Adapter ROM", - .start = 0, - .end = 0, - .flags = IORESOURCE_BUSY | IORESOURCE_READONLY | IORESOURCE_MEM -}, { - .name = "Adapter ROM", - .start = 0, - .end = 0, - .flags = IORESOURCE_BUSY | IORESOURCE_READONLY | IORESOURCE_MEM -}, { - .name = "Adapter ROM", - .start = 0, - .end = 0, - .flags = IORESOURCE_BUSY | IORESOURCE_READONLY | IORESOURCE_MEM -}, { - .name = "Adapter ROM", - .start = 0, - .end = 0, - .flags = IORESOURCE_BUSY | IORESOURCE_READONLY | IORESOURCE_MEM -}, { - .name = "Adapter ROM", - .start = 0, - .end = 0, - .flags = IORESOURCE_BUSY | IORESOURCE_READONLY | IORESOURCE_MEM -} }; - -static struct resource video_rom_resource = { - .name = "Video ROM", - .start = 0xc0000, - .end = 0xc7fff, - .flags = IORESOURCE_BUSY | IORESOURCE_READONLY | IORESOURCE_MEM -}; - -#define ROMSIGNATURE 0xaa55 - -static int __init romsignature(const unsigned char *rom) -{ - const unsigned short * const ptr = (const unsigned short *)rom; - unsigned short sig; - - return probe_kernel_address(ptr, sig) == 0 && sig == ROMSIGNATURE; -} - -static int __init romchecksum(const unsigned char *rom, unsigned long length) -{ - unsigned char sum, c; - - for (sum = 0; length && probe_kernel_address(rom++, c) == 0; length--) - sum += c; - return !length && !sum; -} - -void __init probe_roms(void) -{ - const unsigned char *rom; - unsigned long start, length, upper; - unsigned char c; - int i; - - /* video rom */ - upper = adapter_rom_resources[0].start; - for (start = video_rom_resource.start; start < upper; start += 2048) { - rom = isa_bus_to_virt(start); - if (!romsignature(rom)) - continue; - - video_rom_resource.start = start; - - if (probe_kernel_address(rom + 2, c) != 0) - continue; - - /* 0 < length <= 0x7f * 512, historically */ - length = c * 512; - - /* if checksum okay, trust length byte */ - if (length && romchecksum(rom, length)) - video_rom_resource.end = start + length - 1; - - request_resource(&iomem_resource, &video_rom_resource); - break; - } - - start = (video_rom_resource.end + 1 + 2047) & ~2047UL; - if (start < upper) - start = upper; - - /* system rom */ - request_resource(&iomem_resource, &system_rom_resource); - upper = system_rom_resource.start; - - /* check for extension rom (ignore length byte!) */ - rom = isa_bus_to_virt(extension_rom_resource.start); - if (romsignature(rom)) { - length = extension_rom_resource.end - extension_rom_resource.start + 1; - if (romchecksum(rom, length)) { - request_resource(&iomem_resource, &extension_rom_resource); - upper = extension_rom_resource.start; - } - } - - /* check for adapter roms on 2k boundaries */ - for (i = 0; i < ARRAY_SIZE(adapter_rom_resources) && start < upper; start += 2048) { - rom = isa_bus_to_virt(start); - if (!romsignature(rom)) - continue; - - if (probe_kernel_address(rom + 2, c) != 0) - continue; - - /* 0 < length <= 0x7f * 512, historically */ - length = c * 512; - - /* but accept any length that fits if checksum okay */ - if (!length || start + length > upper || !romchecksum(rom, length)) - continue; - - adapter_rom_resources[i].start = start; - adapter_rom_resources[i].end = start + length - 1; - request_resource(&iomem_resource, &adapter_rom_resources[i]); - - start = adapter_rom_resources[i++].end & ~2047UL; - } -} - diff --git a/arch/x86/kernel/x86_init.c b/arch/x86/kernel/x86_init.c index c11514e9..6eee082 100644 --- a/arch/x86/kernel/x86_init.c +++ b/arch/x86/kernel/x86_init.c @@ -35,7 +35,7 @@ void iommu_shutdown_noop(void) { } struct x86_init_ops x86_init __initdata = { .resources = { - .probe_roms = x86_init_noop, + .probe_roms = probe_roms, .reserve_resources = reserve_standard_io_resources, .memory_setup = default_machine_specific_memory_setup, }, -- cgit v0.10.2 From 0f8132b7431e241c29e61ac14f22549a6fca9632 Mon Sep 17 00:00:00 2001 From: Florian Tobias Schandinat Date: Wed, 16 Mar 2011 13:11:17 +0000 Subject: viafb: move initialization code This moves some mode independend initialization code to the function where the other parts of the initialization are. Signed-off-by: Florian Tobias Schandinat diff --git a/drivers/video/via/hw.c b/drivers/video/via/hw.c index dc4c778..a982718 100644 --- a/drivers/video/via/hw.c +++ b/drivers/video/via/hw.c @@ -1162,6 +1162,8 @@ void via_odev_to_seq(struct seq_file *m, u32 odev) static void load_fix_bit_crtc_reg(void) { + viafb_unlock_crt(); + /* always set to 1 */ viafb_write_reg_mask(CR03, VIACR, 0x80, BIT7); /* line compare should set all bits = 1 (extend modes) */ @@ -1169,8 +1171,6 @@ static void load_fix_bit_crtc_reg(void) /* line compare should set all bits = 1 (extend modes) */ viafb_write_reg_mask(CR07, VIACR, 0x10, BIT4); /* line compare should set all bits = 1 (extend modes) */ - viafb_write_reg_mask(CR09, VIACR, 0x40, BIT6); - /* line compare should set all bits = 1 (extend modes) */ viafb_write_reg_mask(CR35, VIACR, 0x10, BIT4); /* line compare should set all bits = 1 (extend modes) */ viafb_write_reg_mask(CR33, VIACR, 0x06, BIT0 + BIT1 + BIT2); @@ -1181,6 +1181,10 @@ static void load_fix_bit_crtc_reg(void) viafb_write_reg(CR08, VIACR, 0x00); /* extend mode always set to 0h */ viafb_write_reg(CR14, VIACR, 0x00); + viafb_write_reg_mask(CR09, VIACR, 0x40, 0xDF); + viafb_write_reg_mask(CR11, VIACR, 0x00, BIT4 + BIT5 + BIT6); + + viafb_lock_crt(); /* If K8M800, enable Prefetch Mode. */ if ((viaparinfo->chip_info->gfx_chip_name == UNICHROME_K800) @@ -2033,8 +2037,6 @@ void viafb_fill_crtc_timing(struct crt_mode_table *crt_table, v_addr = crt_reg.ver_addr; if (set_iga == IGA1) { viafb_unlock_crt(); - viafb_write_reg(CR09, VIACR, 0x00); /*initial CR09=0 */ - viafb_write_reg_mask(CR11, VIACR, 0x00, BIT4 + BIT5 + BIT6); viafb_write_reg_mask(CR17, VIACR, 0x00, BIT7); } @@ -2047,7 +2049,6 @@ void viafb_fill_crtc_timing(struct crt_mode_table *crt_table, break; } - load_fix_bit_crtc_reg(); viafb_lock_crt(); viafb_write_reg_mask(CR17, VIACR, 0x80, BIT7); viafb_load_fetch_count_reg(h_addr, bpp_byte, set_iga); @@ -2432,6 +2433,7 @@ int viafb_setmode(struct VideoModeTable *vmode_tbl, int video_bpp, } } + load_fix_bit_crtc_reg(); via_set_primary_pitch(viafbinfo->fix.line_length); via_set_secondary_pitch(viafb_dual_fb ? viafbinfo1->fix.line_length : viafbinfo->fix.line_length); -- cgit v0.10.2 From 486d4c08dd2eb29b26b4a27f8056155a7a639861 Mon Sep 17 00:00:00 2001 From: Florian Tobias Schandinat Date: Wed, 16 Mar 2011 13:46:36 +0000 Subject: viafb: no need to write CRTC values twice Later the correct values will be written so there is no need to write early some values which might be wrong. Signed-off-by: Florian Tobias Schandinat diff --git a/drivers/video/via/hw.c b/drivers/video/via/hw.c index a982718..c4d2136 100644 --- a/drivers/video/via/hw.c +++ b/drivers/video/via/hw.c @@ -2401,9 +2401,6 @@ int viafb_setmode(struct VideoModeTable *vmode_tbl, int video_bpp, viafb_write_reg_mask(0x15, VIASR, 0xA2, 0xA2); - /* Write CRTC */ - viafb_fill_crtc_timing(crt_timing, vmode_tbl, video_bpp / 8, IGA1); - /* Write Graphic Controller */ for (i = 0; i < StdGR; i++) via_write_reg(VIAGR, i, VPIT.GR[i]); -- cgit v0.10.2 From 0523656eed6941a1a0e6b8de36ca73f44d2142c0 Mon Sep 17 00:00:00 2001 From: Florian Tobias Schandinat Date: Mon, 21 Mar 2011 01:46:24 +0000 Subject: viafb: kill crt_setting_information As the iga path is the only remaining information which is also handled by the active devices there is no reason to keep it. Signed-off-by: Florian Tobias Schandinat diff --git a/drivers/video/via/chip.h b/drivers/video/via/chip.h index 29d7024..1aa0fb3 100644 --- a/drivers/video/via/chip.h +++ b/drivers/video/via/chip.h @@ -137,10 +137,6 @@ struct chip_information { struct lvds_chip_information lvds_chip_info2; }; -struct crt_setting_information { - int iga_path; -}; - struct tmds_setting_information { int iga_path; int h_active; diff --git a/drivers/video/via/hw.c b/drivers/video/via/hw.c index c4d2136..0098270 100644 --- a/drivers/video/via/hw.c +++ b/drivers/video/via/hw.c @@ -770,13 +770,14 @@ static u32 get_lcd_devices(int output_interface) /*Set IGA path for each device*/ void viafb_set_iga_path(void) { + int crt_iga_path = 0; if (viafb_SAMM_ON == 1) { if (viafb_CRT_ON) { if (viafb_primary_dev == CRT_Device) - viaparinfo->crt_setting_info->iga_path = IGA1; + crt_iga_path = IGA1; else - viaparinfo->crt_setting_info->iga_path = IGA2; + crt_iga_path = IGA2; } if (viafb_DVI_ON) { @@ -793,8 +794,7 @@ void viafb_set_iga_path(void) UNICHROME_CLE266)) { viaparinfo-> lvds_setting_info->iga_path = IGA2; - viaparinfo-> - crt_setting_info->iga_path = IGA1; + crt_iga_path = IGA1; viaparinfo-> tmds_setting_info->iga_path = IGA1; } else @@ -814,10 +814,10 @@ void viafb_set_iga_path(void) viafb_SAMM_ON = 0; if (viafb_CRT_ON && viafb_LCD_ON) { - viaparinfo->crt_setting_info->iga_path = IGA1; + crt_iga_path = IGA1; viaparinfo->lvds_setting_info->iga_path = IGA2; } else if (viafb_CRT_ON && viafb_DVI_ON) { - viaparinfo->crt_setting_info->iga_path = IGA1; + crt_iga_path = IGA1; viaparinfo->tmds_setting_info->iga_path = IGA2; } else if (viafb_LCD_ON && viafb_DVI_ON) { viaparinfo->tmds_setting_info->iga_path = IGA1; @@ -826,7 +826,7 @@ void viafb_set_iga_path(void) viaparinfo->lvds_setting_info->iga_path = IGA2; viaparinfo->lvds_setting_info2->iga_path = IGA2; } else if (viafb_CRT_ON) { - viaparinfo->crt_setting_info->iga_path = IGA1; + crt_iga_path = IGA1; } else if (viafb_LCD_ON) { viaparinfo->lvds_setting_info->iga_path = IGA2; } else if (viafb_DVI_ON) { @@ -837,7 +837,7 @@ void viafb_set_iga_path(void) viaparinfo->shared->iga1_devices = 0; viaparinfo->shared->iga2_devices = 0; if (viafb_CRT_ON) { - if (viaparinfo->crt_setting_info->iga_path == IGA1) + if (crt_iga_path == IGA1) viaparinfo->shared->iga1_devices |= VIA_CRT; else viaparinfo->shared->iga2_devices |= VIA_CRT; @@ -2072,8 +2072,6 @@ void __devinit viafb_init_chip_info(int chip_type) init_tmds_chip_info(); init_lvds_chip_info(); - viaparinfo->crt_setting_info->iga_path = IGA1; - /*Set IGA path for each device */ viafb_set_iga_path(); @@ -2450,15 +2448,15 @@ int viafb_setmode(struct VideoModeTable *vmode_tbl, int video_bpp, /* CRT set mode */ if (viafb_CRT_ON) { - if (viafb_SAMM_ON && (viaparinfo->crt_setting_info->iga_path == - IGA2)) { + if (viafb_SAMM_ON && + viaparinfo->shared->iga2_devices & VIA_CRT) { viafb_fill_crtc_timing(crt_timing1, vmode_tbl1, - video_bpp1 / 8, - viaparinfo->crt_setting_info->iga_path); + video_bpp1 / 8, IGA2); } else { viafb_fill_crtc_timing(crt_timing, vmode_tbl, video_bpp / 8, - viaparinfo->crt_setting_info->iga_path); + (viaparinfo->shared->iga1_devices & VIA_CRT) + ? IGA1 : IGA2); } /* Patch if set_hres is not 8 alignment (1366) to viafb_setmode diff --git a/drivers/video/via/viafbdev.c b/drivers/video/via/viafbdev.c index 9d9bb9b4..ed9bd79 100644 --- a/drivers/video/via/viafbdev.c +++ b/drivers/video/via/viafbdev.c @@ -930,10 +930,8 @@ static int get_primary_device(void) /* Rule: device on iga1 path are the primary device. */ if (viafb_SAMM_ON) { if (viafb_CRT_ON) { - if (viaparinfo->crt_setting_info->iga_path == IGA1) { - DEBUG_MSG(KERN_INFO "CRT IGA Path:%d\n", - viaparinfo-> - crt_setting_info->iga_path); + if (viaparinfo->shared->iga1_devices & VIA_CRT) { + DEBUG_MSG(KERN_INFO "CRT IGA Path:%d\n", IGA1); primary_device = CRT_Device; } } @@ -1746,7 +1744,6 @@ int __devinit via_fb_pci_probe(struct viafb_dev *vdev) viaparinfo->lvds_setting_info = &viaparinfo->shared->lvds_setting_info; viaparinfo->lvds_setting_info2 = &viaparinfo->shared->lvds_setting_info2; - viaparinfo->crt_setting_info = &viaparinfo->shared->crt_setting_info; viaparinfo->chip_info = &viaparinfo->shared->chip_info; if (viafb_dual_fb) diff --git a/drivers/video/via/viafbdev.h b/drivers/video/via/viafbdev.h index d66f963..ff60e1d 100644 --- a/drivers/video/via/viafbdev.h +++ b/drivers/video/via/viafbdev.h @@ -50,7 +50,6 @@ struct viafb_shared { /* All the information will be needed to set engine */ struct tmds_setting_information tmds_setting_info; - struct crt_setting_information crt_setting_info; struct lvds_setting_information lvds_setting_info; struct lvds_setting_information lvds_setting_info2; struct chip_information chip_info; @@ -79,7 +78,6 @@ struct viafb_par { /* All the information will be needed to set engine */ /* depreciated, use the ones in shared directly */ struct tmds_setting_information *tmds_setting_info; - struct crt_setting_information *crt_setting_info; struct lvds_setting_information *lvds_setting_info; struct lvds_setting_information *lvds_setting_info2; struct chip_information *chip_info; -- cgit v0.10.2 From c672af35d54992b88d3c48133bd62cc3386fb2f9 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Wed, 23 Mar 2011 10:36:59 +0100 Subject: signal: Fix SIGCONT notification code After a task receives SIGCONT, its parent is notified via SIGCHLD with its siginfo describing what the notified event is. If SIGCONT is received while the child process is stopped, the code should be CLD_CONTINUED. If SIGCONT is recieved while the child process is in the process of being stopped, it should be CLD_STOPPED. Which code to use is determined in prepare_signal() and recorded in signal->flags using SIGNAL_CLD_CONTINUED|STOP flags. get_signal_deliver() should test these flags and then notify accoringly; however, it incorrectly tested SIGNAL_STOP_CONTINUED instead of SIGNAL_CLD_CONTINUED, thus incorrectly notifying CLD_CONTINUED if the signal is delivered before the task is wait(2)ed and CLD_STOPPED if the state was fetched already. Fix it by testing SIGNAL_CLD_CONTINUED. While at it, uncompress the ?: test into if/else clause for better readability. Signed-off-by: Tejun Heo Reviewed-by: Oleg Nesterov Acked-by: Roland McGrath diff --git a/kernel/signal.c b/kernel/signal.c index 3175186..e26274a 100644 --- a/kernel/signal.c +++ b/kernel/signal.c @@ -1853,8 +1853,13 @@ relock: * the CLD_ si_code into SIGNAL_CLD_MASK bits. */ if (unlikely(signal->flags & SIGNAL_CLD_MASK)) { - int why = (signal->flags & SIGNAL_STOP_CONTINUED) - ? CLD_CONTINUED : CLD_STOPPED; + int why; + + if (signal->flags & SIGNAL_CLD_CONTINUED) + why = CLD_CONTINUED; + else + why = CLD_STOPPED; + signal->flags &= ~SIGNAL_CLD_MASK; why = tracehook_notify_jctl(why, CLD_CONTINUED); -- cgit v0.10.2 From 9f2bf6513a6cca0b00cbbf67ba6197017cfba548 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Wed, 23 Mar 2011 10:37:00 +0100 Subject: ptrace: Remove the extra wake_up_state() from ptrace_detach() This wake_up_state() has a turbulent history. This is a remnant from ancient ptrace implementation and patently wrong. Commit 95a3540d (ptrace_detach: the wrong wakeup breaks the ERESTARTxxx logic) removed it but the change was reverted later by commit edaba2c5 (ptrace: revert "ptrace_detach: the wrong wakeup breaks the ERESTARTxxx logic") citing compatibility breakage and general brokeness of the whole group stop / ptrace interaction. Then, recently, it got converted from wake_up_process() to wake_up_state() to make it less dangerous. Digging through the mailing archives, the compatibility breakage doesn't seem to be critical in the sense that the behavior isn't well defined or reliable to begin with and it seems to have been agreed to remove the wakeup with proper cleanup of the whole thing. Now that the group stop and its interaction with ptrace are being cleaned up, it's high time to finally kill this silliness. Signed-off-by: Tejun Heo Acked-by: Oleg Nesterov Cc: Roland McGrath diff --git a/kernel/ptrace.c b/kernel/ptrace.c index e2302e4..6acf895 100644 --- a/kernel/ptrace.c +++ b/kernel/ptrace.c @@ -312,8 +312,6 @@ static int ptrace_detach(struct task_struct *child, unsigned int data) if (child->ptrace) { child->exit_code = data; dead = __ptrace_detach(current, child); - if (!child->exit_state) - wake_up_state(child, TASK_TRACED | TASK_STOPPED); } write_unlock_irq(&tasklist_lock); -- cgit v0.10.2 From 71db5eb99c960e9c30e4b3ed04103c513b6251b5 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Wed, 23 Mar 2011 10:37:00 +0100 Subject: signal: Remove superflous try_to_freeze() loop in do_signal_stop() do_signal_stop() is used only by get_signal_to_deliver() and after a successful signal stop, it always calls try_to_freeze(), so the try_to_freeze() loop around schedule() in do_signal_stop() is superflous and confusing. Remove it. Signed-off-by: Tejun Heo Acked-by: Rafael J. Wysocki Acked-by: Oleg Nesterov Acked-by: Roland McGrath diff --git a/kernel/signal.c b/kernel/signal.c index e26274a..f4db769 100644 --- a/kernel/signal.c +++ b/kernel/signal.c @@ -1781,9 +1781,7 @@ static int do_signal_stop(int signr) } /* Now we don't run again until woken by SIGCONT or SIGKILL */ - do { - schedule(); - } while (try_to_freeze()); + schedule(); tracehook_finish_jctl(); current->exit_code = 0; -- cgit v0.10.2 From edf2ed153bcae52de70db00a98b0e81a5668e563 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Wed, 23 Mar 2011 10:37:00 +0100 Subject: ptrace: Kill tracehook_notify_jctl() tracehook_notify_jctl() aids in determining whether and what to report to the parent when a task is stopped or continued. The function also adds an extra requirement that siglock may be released across it, which is currently unused and quite difficult to satisfy in well-defined manner. As job control and the notifications are about to receive major overhaul, remove the tracehook and open code it. If ever necessary, let's factor it out after the overhaul. * Oleg spotted incorrect CLD_CONTINUED/STOPPED selection when ptraced. Fixed. Signed-off-by: Tejun Heo Cc: Oleg Nesterov Cc: Roland McGrath diff --git a/include/linux/tracehook.h b/include/linux/tracehook.h index 3a2e66d..b073f3c 100644 --- a/include/linux/tracehook.h +++ b/include/linux/tracehook.h @@ -469,33 +469,6 @@ static inline int tracehook_get_signal(struct task_struct *task, } /** - * tracehook_notify_jctl - report about job control stop/continue - * @notify: zero, %CLD_STOPPED or %CLD_CONTINUED - * @why: %CLD_STOPPED or %CLD_CONTINUED - * - * This is called when we might call do_notify_parent_cldstop(). - * - * @notify is zero if we would not ordinarily send a %SIGCHLD, - * or is the %CLD_STOPPED or %CLD_CONTINUED .si_code for %SIGCHLD. - * - * @why is %CLD_STOPPED when about to stop for job control; - * we are already in %TASK_STOPPED state, about to call schedule(). - * It might also be that we have just exited (check %PF_EXITING), - * but need to report that a group-wide stop is complete. - * - * @why is %CLD_CONTINUED when waking up after job control stop and - * ready to make a delayed @notify report. - * - * Return the %CLD_* value for %SIGCHLD, or zero to generate no signal. - * - * Called with the siglock held. - */ -static inline int tracehook_notify_jctl(int notify, int why) -{ - return notify ?: (current->ptrace & PT_PTRACED) ? why : 0; -} - -/** * tracehook_finish_jctl - report about return from job control stop * * This is called by do_signal_stop() after wakeup. diff --git a/kernel/signal.c b/kernel/signal.c index f4db769..03d874e 100644 --- a/kernel/signal.c +++ b/kernel/signal.c @@ -1727,7 +1727,7 @@ void ptrace_notify(int exit_code) static int do_signal_stop(int signr) { struct signal_struct *sig = current->signal; - int notify; + int notify = 0; if (!sig->group_stop_count) { struct task_struct *t; @@ -1759,19 +1759,16 @@ static int do_signal_stop(int signr) * a group stop in progress and we are the last to stop, report * to the parent. When ptraced, every thread reports itself. */ - notify = sig->group_stop_count == 1 ? CLD_STOPPED : 0; - notify = tracehook_notify_jctl(notify, CLD_STOPPED); - /* - * tracehook_notify_jctl() can drop and reacquire siglock, so - * we keep ->group_stop_count != 0 before the call. If SIGCONT - * or SIGKILL comes in between ->group_stop_count == 0. - */ - if (sig->group_stop_count) { - if (!--sig->group_stop_count) - sig->flags = SIGNAL_STOP_STOPPED; - current->exit_code = sig->group_exit_code; - __set_current_state(TASK_STOPPED); + if (!--sig->group_stop_count) { + sig->flags = SIGNAL_STOP_STOPPED; + notify = CLD_STOPPED; } + if (task_ptrace(current)) + notify = CLD_STOPPED; + + current->exit_code = sig->group_exit_code; + __set_current_state(TASK_STOPPED); + spin_unlock_irq(¤t->sighand->siglock); if (notify) { @@ -1860,14 +1857,11 @@ relock: signal->flags &= ~SIGNAL_CLD_MASK; - why = tracehook_notify_jctl(why, CLD_CONTINUED); spin_unlock_irq(&sighand->siglock); - if (why) { - read_lock(&tasklist_lock); - do_notify_parent_cldstop(current->group_leader, why); - read_unlock(&tasklist_lock); - } + read_lock(&tasklist_lock); + do_notify_parent_cldstop(current->group_leader, why); + read_unlock(&tasklist_lock); goto relock; } @@ -2034,7 +2028,7 @@ void exit_signals(struct task_struct *tsk) if (unlikely(tsk->signal->group_stop_count) && !--tsk->signal->group_stop_count) { tsk->signal->flags = SIGNAL_STOP_STOPPED; - group_stop = tracehook_notify_jctl(CLD_STOPPED, CLD_STOPPED); + group_stop = CLD_STOPPED; } out: spin_unlock_irq(&tsk->sighand->siglock); -- cgit v0.10.2 From fe1bc6a0954611b806f9e158eb0817cf8ba21660 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Wed, 23 Mar 2011 10:37:00 +0100 Subject: ptrace: Add @why to ptrace_stop() To prepare for cleanup of the interaction between group stop and ptrace, add @why to ptrace_stop(). Existing users are updated such that there is no behavior change. Signed-off-by: Tejun Heo Acked-by: Roland McGrath diff --git a/kernel/signal.c b/kernel/signal.c index 03d874e..95ac42d 100644 --- a/kernel/signal.c +++ b/kernel/signal.c @@ -1617,7 +1617,7 @@ static int sigkill_pending(struct task_struct *tsk) * If we actually decide not to stop at all because the tracer * is gone, we keep current->exit_code unless clear_code. */ -static void ptrace_stop(int exit_code, int clear_code, siginfo_t *info) +static void ptrace_stop(int exit_code, int why, int clear_code, siginfo_t *info) __releases(¤t->sighand->siglock) __acquires(¤t->sighand->siglock) { @@ -1655,7 +1655,7 @@ static void ptrace_stop(int exit_code, int clear_code, siginfo_t *info) spin_unlock_irq(¤t->sighand->siglock); read_lock(&tasklist_lock); if (may_ptrace_stop()) { - do_notify_parent_cldstop(current, CLD_TRAPPED); + do_notify_parent_cldstop(current, why); /* * Don't want to allow preemption here, because * sys_ptrace() needs this task to be inactive. @@ -1714,7 +1714,7 @@ void ptrace_notify(int exit_code) /* Let the debugger run. */ spin_lock_irq(¤t->sighand->siglock); - ptrace_stop(exit_code, 1, &info); + ptrace_stop(exit_code, CLD_TRAPPED, 1, &info); spin_unlock_irq(¤t->sighand->siglock); } @@ -1795,7 +1795,7 @@ static int ptrace_signal(int signr, siginfo_t *info, ptrace_signal_deliver(regs, cookie); /* Let the debugger run. */ - ptrace_stop(signr, 0, info); + ptrace_stop(signr, CLD_TRAPPED, 0, info); /* We're back. Did the debugger cancel the sig? */ signr = current->exit_code; -- cgit v0.10.2 From e5c1902e9260a0075ea52cb5ef627a8d9aaede89 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Wed, 23 Mar 2011 10:37:00 +0100 Subject: signal: Fix premature completion of group stop when interfered by ptrace task->signal->group_stop_count is used to track the progress of group stop. It's initialized to the number of tasks which need to stop for group stop to finish and each stopping or trapping task decrements. However, each task doesn't keep track of whether it decremented the counter or not and if woken up before the group stop is complete and stops again, it can decrement the counter multiple times. Please consider the following example code. static void *worker(void *arg) { while (1) ; return NULL; } int main(void) { pthread_t thread; pid_t pid; int i; pid = fork(); if (!pid) { for (i = 0; i < 5; i++) pthread_create(&thread, NULL, worker, NULL); while (1) ; return 0; } ptrace(PTRACE_ATTACH, pid, NULL, NULL); while (1) { waitid(P_PID, pid, NULL, WSTOPPED); ptrace(PTRACE_SINGLESTEP, pid, NULL, (void *)(long)SIGSTOP); } return 0; } The child creates five threads and the parent continuously traps the first thread and whenever the child gets a signal, SIGSTOP is delivered. If an external process sends SIGSTOP to the child, all other threads in the process should reliably stop. However, due to the above bug, the first thread will often end up consuming group_stop_count multiple times and SIGSTOP often ends up stopping none or part of the other four threads. This patch adds a new field task->group_stop which is protected by siglock and uses GROUP_STOP_CONSUME flag to track which task is still to consume group_stop_count to fix this bug. task_clear_group_stop_pending() and task_participate_group_stop() are added to help manipulating group stop states. As ptrace_stop() now also uses task_participate_group_stop(), it will set SIGNAL_STOP_STOPPED if it completes a group stop. There still are many issues regarding the interaction between group stop and ptrace. Patches to address them will follow. - Oleg spotted duplicate GROUP_STOP_CONSUME. Dropped. Signed-off-by: Tejun Heo Acked-by: Oleg Nesterov Cc: Roland McGrath diff --git a/include/linux/sched.h b/include/linux/sched.h index 4b601be..85f5104 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h @@ -1260,6 +1260,7 @@ struct task_struct { int exit_state; int exit_code, exit_signal; int pdeath_signal; /* The signal sent when the parent dies */ + unsigned int group_stop; /* GROUP_STOP_*, siglock protected */ /* ??? */ unsigned int personality; unsigned did_exec:1; @@ -1771,6 +1772,11 @@ extern void thread_group_times(struct task_struct *p, cputime_t *ut, cputime_t * #define tsk_used_math(p) ((p)->flags & PF_USED_MATH) #define used_math() tsk_used_math(current) +/* + * task->group_stop flags + */ +#define GROUP_STOP_CONSUME (1 << 17) /* consume group stop count */ + #ifdef CONFIG_PREEMPT_RCU #define RCU_READ_UNLOCK_BLOCKED (1 << 0) /* blocked while in RCU read-side. */ diff --git a/kernel/signal.c b/kernel/signal.c index 95ac42d..ecb2008 100644 --- a/kernel/signal.c +++ b/kernel/signal.c @@ -223,6 +223,52 @@ static inline void print_dropped_signal(int sig) current->comm, current->pid, sig); } +/** + * task_clear_group_stop_pending - clear pending group stop + * @task: target task + * + * Clear group stop states for @task. + * + * CONTEXT: + * Must be called with @task->sighand->siglock held. + */ +static void task_clear_group_stop_pending(struct task_struct *task) +{ + task->group_stop &= ~GROUP_STOP_CONSUME; +} + +/** + * task_participate_group_stop - participate in a group stop + * @task: task participating in a group stop + * + * @task is participating in a group stop. Group stop states are cleared + * and the group stop count is consumed if %GROUP_STOP_CONSUME was set. If + * the consumption completes the group stop, the appropriate %SIGNAL_* + * flags are set. + * + * CONTEXT: + * Must be called with @task->sighand->siglock held. + */ +static bool task_participate_group_stop(struct task_struct *task) +{ + struct signal_struct *sig = task->signal; + bool consume = task->group_stop & GROUP_STOP_CONSUME; + + task_clear_group_stop_pending(task); + + if (!consume) + return false; + + if (!WARN_ON_ONCE(sig->group_stop_count == 0)) + sig->group_stop_count--; + + if (!sig->group_stop_count) { + sig->flags = SIGNAL_STOP_STOPPED; + return true; + } + return false; +} + /* * allocate a new signal queue record * - this may be called without locks if and only if t == current, otherwise an @@ -1645,7 +1691,7 @@ static void ptrace_stop(int exit_code, int why, int clear_code, siginfo_t *info) * we must participate in the bookkeeping. */ if (current->signal->group_stop_count > 0) - --current->signal->group_stop_count; + task_participate_group_stop(current); current->last_siginfo = info; current->exit_code = exit_code; @@ -1730,6 +1776,7 @@ static int do_signal_stop(int signr) int notify = 0; if (!sig->group_stop_count) { + unsigned int gstop = GROUP_STOP_CONSUME; struct task_struct *t; if (!likely(sig->flags & SIGNAL_STOP_DEQUEUED) || @@ -1741,6 +1788,7 @@ static int do_signal_stop(int signr) */ sig->group_exit_code = signr; + current->group_stop = gstop; sig->group_stop_count = 1; for (t = next_thread(current); t != current; t = next_thread(t)) /* @@ -1750,19 +1798,19 @@ static int do_signal_stop(int signr) */ if (!(t->flags & PF_EXITING) && !task_is_stopped_or_traced(t)) { + t->group_stop = gstop; sig->group_stop_count++; signal_wake_up(t, 0); - } + } else + task_clear_group_stop_pending(t); } /* * If there are no other threads in the group, or if there is * a group stop in progress and we are the last to stop, report * to the parent. When ptraced, every thread reports itself. */ - if (!--sig->group_stop_count) { - sig->flags = SIGNAL_STOP_STOPPED; + if (task_participate_group_stop(current)) notify = CLD_STOPPED; - } if (task_ptrace(current)) notify = CLD_STOPPED; @@ -2026,10 +2074,8 @@ void exit_signals(struct task_struct *tsk) recalc_sigpending_and_wake(t); if (unlikely(tsk->signal->group_stop_count) && - !--tsk->signal->group_stop_count) { - tsk->signal->flags = SIGNAL_STOP_STOPPED; + task_participate_group_stop(tsk)) group_stop = CLD_STOPPED; - } out: spin_unlock_irq(&tsk->sighand->siglock); -- cgit v0.10.2 From 39efa3ef3a376a4e53de2f82fc91182459d34200 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Wed, 23 Mar 2011 10:37:00 +0100 Subject: signal: Use GROUP_STOP_PENDING to stop once for a single group stop Currently task->signal->group_stop_count is used to decide whether to stop for group stop. However, if there is a task in the group which is taking a long time to stop, other tasks which are continued by ptrace would repeatedly stop for the same group stop until the group stop is complete. Conversely, if a ptraced task is in TASK_TRACED state, the debugger won't get notified of group stops which is inconsistent compared to the ptraced task in any other state. This patch introduces GROUP_STOP_PENDING which tracks whether a task is yet to stop for the group stop in progress. The flag is set when a group stop starts and cleared when the task stops the first time for the group stop, and consulted whenever whether the task should participate in a group stop needs to be determined. Note that now tasks in TASK_TRACED also participate in group stop. This results in the following behavior changes. * For a single group stop, a ptracer would see at most one stop reported. * A ptracee in TASK_TRACED now also participates in group stop and the tracer would get the notification. However, as a ptraced task could be in TASK_STOPPED state or any ptrace trap could consume group stop, the notification may still be missing. These will be addressed with further patches. * A ptracee may start a group stop while one is still in progress if the tracer let it continue with stop signal delivery. Group stop code handles this correctly. Oleg: * Spotted that a task might skip signal check even when its GROUP_STOP_PENDING is set. Fixed by updating recalc_sigpending_tsk() to check GROUP_STOP_PENDING instead of group_stop_count. * Pointed out that task->group_stop should be cleared whenever task->signal->group_stop_count is cleared. Fixed accordingly. * Pointed out the behavior inconsistency between TASK_TRACED and RUNNING and the last behavior change. Signed-off-by: Tejun Heo Acked-by: Oleg Nesterov Cc: Roland McGrath diff --git a/fs/exec.c b/fs/exec.c index 5e62d26..8328beb 100644 --- a/fs/exec.c +++ b/fs/exec.c @@ -1659,6 +1659,7 @@ static int zap_process(struct task_struct *start, int exit_code) t = start; do { + task_clear_group_stop_pending(t); if (t != current && t->mm) { sigaddset(&t->pending.signal, SIGKILL); signal_wake_up(t, 1); diff --git a/include/linux/sched.h b/include/linux/sched.h index 85f5104..b2a17df 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h @@ -1775,8 +1775,11 @@ extern void thread_group_times(struct task_struct *p, cputime_t *ut, cputime_t * /* * task->group_stop flags */ +#define GROUP_STOP_PENDING (1 << 16) /* task should stop for group stop */ #define GROUP_STOP_CONSUME (1 << 17) /* consume group stop count */ +extern void task_clear_group_stop_pending(struct task_struct *task); + #ifdef CONFIG_PREEMPT_RCU #define RCU_READ_UNLOCK_BLOCKED (1 << 0) /* blocked while in RCU read-side. */ diff --git a/kernel/signal.c b/kernel/signal.c index ecb2008..a2e7a65 100644 --- a/kernel/signal.c +++ b/kernel/signal.c @@ -124,7 +124,7 @@ static inline int has_pending_signals(sigset_t *signal, sigset_t *blocked) static int recalc_sigpending_tsk(struct task_struct *t) { - if (t->signal->group_stop_count > 0 || + if ((t->group_stop & GROUP_STOP_PENDING) || PENDING(&t->pending, &t->blocked) || PENDING(&t->signal->shared_pending, &t->blocked)) { set_tsk_thread_flag(t, TIF_SIGPENDING); @@ -232,19 +232,19 @@ static inline void print_dropped_signal(int sig) * CONTEXT: * Must be called with @task->sighand->siglock held. */ -static void task_clear_group_stop_pending(struct task_struct *task) +void task_clear_group_stop_pending(struct task_struct *task) { - task->group_stop &= ~GROUP_STOP_CONSUME; + task->group_stop &= ~(GROUP_STOP_PENDING | GROUP_STOP_CONSUME); } /** * task_participate_group_stop - participate in a group stop * @task: task participating in a group stop * - * @task is participating in a group stop. Group stop states are cleared - * and the group stop count is consumed if %GROUP_STOP_CONSUME was set. If - * the consumption completes the group stop, the appropriate %SIGNAL_* - * flags are set. + * @task has GROUP_STOP_PENDING set and is participating in a group stop. + * Group stop states are cleared and the group stop count is consumed if + * %GROUP_STOP_CONSUME was set. If the consumption completes the group + * stop, the appropriate %SIGNAL_* flags are set. * * CONTEXT: * Must be called with @task->sighand->siglock held. @@ -254,6 +254,8 @@ static bool task_participate_group_stop(struct task_struct *task) struct signal_struct *sig = task->signal; bool consume = task->group_stop & GROUP_STOP_CONSUME; + WARN_ON_ONCE(!(task->group_stop & GROUP_STOP_PENDING)); + task_clear_group_stop_pending(task); if (!consume) @@ -765,6 +767,9 @@ static int prepare_signal(int sig, struct task_struct *p, int from_ancestor_ns) t = p; do { unsigned int state; + + task_clear_group_stop_pending(t); + rm_from_queue(SIG_KERNEL_STOP_MASK, &t->pending); /* * If there is a handler for SIGCONT, we must make @@ -906,6 +911,7 @@ static void complete_signal(int sig, struct task_struct *p, int group) signal->group_stop_count = 0; t = p; do { + task_clear_group_stop_pending(t); sigaddset(&t->pending.signal, SIGKILL); signal_wake_up(t, 1); } while_each_thread(p, t); @@ -1139,6 +1145,7 @@ int zap_other_threads(struct task_struct *p) p->signal->group_stop_count = 0; while_each_thread(p, t) { + task_clear_group_stop_pending(t); count++; /* Don't bother with already dead threads */ @@ -1690,7 +1697,7 @@ static void ptrace_stop(int exit_code, int why, int clear_code, siginfo_t *info) * If there is a group stop in progress, * we must participate in the bookkeeping. */ - if (current->signal->group_stop_count > 0) + if (current->group_stop & GROUP_STOP_PENDING) task_participate_group_stop(current); current->last_siginfo = info; @@ -1775,8 +1782,8 @@ static int do_signal_stop(int signr) struct signal_struct *sig = current->signal; int notify = 0; - if (!sig->group_stop_count) { - unsigned int gstop = GROUP_STOP_CONSUME; + if (!(current->group_stop & GROUP_STOP_PENDING)) { + unsigned int gstop = GROUP_STOP_PENDING | GROUP_STOP_CONSUME; struct task_struct *t; if (!likely(sig->flags & SIGNAL_STOP_DEQUEUED) || @@ -1796,8 +1803,7 @@ static int do_signal_stop(int signr) * stop is always done with the siglock held, * so this check has no races. */ - if (!(t->flags & PF_EXITING) && - !task_is_stopped_or_traced(t)) { + if (!(t->flags & PF_EXITING) && !task_is_stopped(t)) { t->group_stop = gstop; sig->group_stop_count++; signal_wake_up(t, 0); @@ -1926,8 +1932,8 @@ relock: if (unlikely(signr != 0)) ka = return_ka; else { - if (unlikely(signal->group_stop_count > 0) && - do_signal_stop(0)) + if (unlikely(current->group_stop & + GROUP_STOP_PENDING) && do_signal_stop(0)) goto relock; signr = dequeue_signal(current, ¤t->blocked, @@ -2073,7 +2079,7 @@ void exit_signals(struct task_struct *tsk) if (!signal_pending(t) && !(t->flags & PF_EXITING)) recalc_sigpending_and_wake(t); - if (unlikely(tsk->signal->group_stop_count) && + if (unlikely(tsk->group_stop & GROUP_STOP_PENDING) && task_participate_group_stop(tsk)) group_stop = CLD_STOPPED; out: -- cgit v0.10.2 From 0ae8ce1c8c5b9007ce6bfc83ec2aa0dfce5bbed3 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Wed, 23 Mar 2011 10:37:00 +0100 Subject: ptrace: Participate in group stop from ptrace_stop() iff the task is trapping for group stop Currently, ptrace_stop() unconditionally participates in group stop bookkeeping. This is unnecessary and inaccurate. Make it only participate if the task is trapping for group stop - ie. if @why is CLD_STOPPED. As ptrace_stop() currently is not used when trapping for group stop, this equals to disabling group stop participation from ptrace_stop(). A visible behavior change is increased likelihood of delayed group stop completion if the thread group contains one or more ptraced tasks. This is to preapre for further cleanup of the interaction between group stop and ptrace. Signed-off-by: Tejun Heo Acked-by: Oleg Nesterov Cc: Roland McGrath diff --git a/kernel/signal.c b/kernel/signal.c index a2e7a65..9f36dd2 100644 --- a/kernel/signal.c +++ b/kernel/signal.c @@ -1694,10 +1694,13 @@ static void ptrace_stop(int exit_code, int why, int clear_code, siginfo_t *info) } /* - * If there is a group stop in progress, - * we must participate in the bookkeeping. + * If @why is CLD_STOPPED, we're trapping to participate in a group + * stop. Do the bookkeeping. Note that if SIGCONT was delievered + * while siglock was released for the arch hook, PENDING could be + * clear now. We act as if SIGCONT is received after TASK_TRACED + * is entered - ignore it. */ - if (current->group_stop & GROUP_STOP_PENDING) + if (why == CLD_STOPPED && (current->group_stop & GROUP_STOP_PENDING)) task_participate_group_stop(current); current->last_siginfo = info; -- cgit v0.10.2 From 5224fa3660ad3881d2f2ad726d22614117963f10 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Wed, 23 Mar 2011 10:37:00 +0100 Subject: ptrace: Make do_signal_stop() use ptrace_stop() if the task is being ptraced A ptraced task would still stop at do_signal_stop() when it's stopping for stop signals and do_signal_stop() behaves the same whether the task is ptraced or not. However, in addition to stopping, ptrace_stop() also does ptrace specific stuff like calling architecture specific callbacks, so this behavior makes the code more fragile and difficult to understand. This patch makes do_signal_stop() test whether the task is ptraced and use ptrace_stop() if so. This renders tracehook_notify_jctl() rather pointless as the ptrace notification is now handled by ptrace_stop() regardless of the return value from the tracehook. It probably is a good idea to update it. This doesn't solve the whole problem as tasks already in stopped state would stay in the regular stop when ptrace attached. That part will be handled by the next patch. Oleg pointed out that this makes a userland-visible change. Before, SIGCONT would be able to wake up a task in group stop even if the task is ptraced if the tracer hasn't issued another ptrace command afterwards (as the next ptrace commands transitions the state into TASK_TRACED which ignores SIGCONT wakeups). With this and the next patch, SIGCONT may race with the transition into TASK_TRACED and is ignored if the tracee already entered TASK_TRACED. Another userland visible change of this and the next patch is that the ptracee's state would now be TASK_TRACED where it used to be TASK_STOPPED, which is visible via fs/proc. Signed-off-by: Tejun Heo Acked-by: Oleg Nesterov Cc: Roland McGrath Cc: Jan Kratochvil diff --git a/kernel/signal.c b/kernel/signal.c index 9f36dd2..418776c 100644 --- a/kernel/signal.c +++ b/kernel/signal.c @@ -1783,7 +1783,6 @@ void ptrace_notify(int exit_code) static int do_signal_stop(int signr) { struct signal_struct *sig = current->signal; - int notify = 0; if (!(current->group_stop & GROUP_STOP_PENDING)) { unsigned int gstop = GROUP_STOP_PENDING | GROUP_STOP_CONSUME; @@ -1813,29 +1812,37 @@ static int do_signal_stop(int signr) } else task_clear_group_stop_pending(t); } - /* - * If there are no other threads in the group, or if there is - * a group stop in progress and we are the last to stop, report - * to the parent. When ptraced, every thread reports itself. - */ - if (task_participate_group_stop(current)) - notify = CLD_STOPPED; - if (task_ptrace(current)) - notify = CLD_STOPPED; current->exit_code = sig->group_exit_code; __set_current_state(TASK_STOPPED); - spin_unlock_irq(¤t->sighand->siglock); + if (likely(!task_ptrace(current))) { + int notify = 0; - if (notify) { - read_lock(&tasklist_lock); - do_notify_parent_cldstop(current, notify); - read_unlock(&tasklist_lock); - } + /* + * If there are no other threads in the group, or if there + * is a group stop in progress and we are the last to stop, + * report to the parent. + */ + if (task_participate_group_stop(current)) + notify = CLD_STOPPED; - /* Now we don't run again until woken by SIGCONT or SIGKILL */ - schedule(); + spin_unlock_irq(¤t->sighand->siglock); + + if (notify) { + read_lock(&tasklist_lock); + do_notify_parent_cldstop(current, notify); + read_unlock(&tasklist_lock); + } + + /* Now we don't run again until woken by SIGCONT or SIGKILL */ + schedule(); + + spin_lock_irq(¤t->sighand->siglock); + } else + ptrace_stop(current->exit_code, CLD_STOPPED, 0, NULL); + + spin_unlock_irq(¤t->sighand->siglock); tracehook_finish_jctl(); current->exit_code = 0; -- cgit v0.10.2 From d79fdd6d96f46fabb779d86332e3677c6f5c2a4f Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Wed, 23 Mar 2011 10:37:00 +0100 Subject: ptrace: Clean transitions between TASK_STOPPED and TRACED Currently, if the task is STOPPED on ptrace attach, it's left alone and the state is silently changed to TRACED on the next ptrace call. The behavior breaks the assumption that arch_ptrace_stop() is called before any task is poked by ptrace and is ugly in that a task manipulates the state of another task directly. With GROUP_STOP_PENDING, the transitions between TASK_STOPPED and TRACED can be made clean. The tracer can use the flag to tell the tracee to retry stop on attach and detach. On retry, the tracee will enter the desired state in the correct way. The lower 16bits of task->group_stop is used to remember the signal number which caused the last group stop. This is used while retrying for ptrace attach as the original group_exit_code could have been consumed with wait(2) by then. As the real parent may wait(2) and consume the group_exit_code anytime, the group_exit_code needs to be saved separately so that it can be used when switching from regular sleep to ptrace_stop(). This is recorded in the lower 16bits of task->group_stop. If a task is already stopped and there's no intervening SIGCONT, a ptrace request immediately following a successful PTRACE_ATTACH should always succeed even if the tracer doesn't wait(2) for attach completion; however, with this change, the tracee might still be TASK_RUNNING trying to enter TASK_TRACED which would cause the following request to fail with -ESRCH. This intermediate state is hidden from the ptracer by setting GROUP_STOP_TRAPPING on attach and making ptrace_check_attach() wait for it to clear on its signal->wait_chldexit. Completing the transition or getting killed clears TRAPPING and wakes up the tracer. Note that the STOPPED -> RUNNING -> TRACED transition is still visible to other threads which are in the same group as the ptracer and the reverse transition is visible to all. Please read the comments for details. Oleg: * Spotted a race condition where a task may retry group stop without proper bookkeeping. Fixed by redoing bookkeeping on retry. * Spotted that the transition is visible to userland in several different ways. Most are fixed with GROUP_STOP_TRAPPING. Unhandled corner case is documented. * Pointed out not setting GROUP_STOP_SIGMASK on an already stopped task would result in more consistent behavior. * Pointed out that calling ptrace_stop() from do_signal_stop() in TASK_STOPPED can race with group stop start logic and then confuse the TRAPPING wait in ptrace_check_attach(). ptrace_stop() is now called with TASK_RUNNING. * Suggested using signal->wait_chldexit instead of bit wait. * Spotted a race condition between TRACED transition and clearing of TRAPPING. Signed-off-by: Tejun Heo Acked-by: Oleg Nesterov Cc: Roland McGrath Cc: Jan Kratochvil diff --git a/include/linux/sched.h b/include/linux/sched.h index b2a17df..456d80e 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h @@ -1775,8 +1775,10 @@ extern void thread_group_times(struct task_struct *p, cputime_t *ut, cputime_t * /* * task->group_stop flags */ +#define GROUP_STOP_SIGMASK 0xffff /* signr of the last group stop */ #define GROUP_STOP_PENDING (1 << 16) /* task should stop for group stop */ #define GROUP_STOP_CONSUME (1 << 17) /* consume group stop count */ +#define GROUP_STOP_TRAPPING (1 << 18) /* switching from STOPPED to TRACED */ extern void task_clear_group_stop_pending(struct task_struct *task); diff --git a/kernel/ptrace.c b/kernel/ptrace.c index 6acf895..745fc2d 100644 --- a/kernel/ptrace.c +++ b/kernel/ptrace.c @@ -49,14 +49,22 @@ static void ptrace_untrace(struct task_struct *child) spin_lock(&child->sighand->siglock); if (task_is_traced(child)) { /* - * If the group stop is completed or in progress, - * this thread was already counted as stopped. + * If group stop is completed or in progress, it should + * participate in the group stop. Set GROUP_STOP_PENDING + * before kicking it. + * + * This involves TRACED -> RUNNING -> STOPPED transition + * which is similar to but in the opposite direction of + * what happens while attaching to a stopped task. + * However, in this direction, the intermediate RUNNING + * state is not hidden even from the current ptracer and if + * it immediately re-attaches and performs a WNOHANG + * wait(2), it may fail. */ if (child->signal->flags & SIGNAL_STOP_STOPPED || child->signal->group_stop_count) - __set_task_state(child, TASK_STOPPED); - else - signal_wake_up(child, 1); + child->group_stop |= GROUP_STOP_PENDING; + signal_wake_up(child, 1); } spin_unlock(&child->sighand->siglock); } @@ -165,6 +173,7 @@ bool ptrace_may_access(struct task_struct *task, unsigned int mode) static int ptrace_attach(struct task_struct *task) { + bool wait_trap = false; int retval; audit_ptrace(task); @@ -204,12 +213,42 @@ static int ptrace_attach(struct task_struct *task) __ptrace_link(task, current); send_sig_info(SIGSTOP, SEND_SIG_FORCED, task); + spin_lock(&task->sighand->siglock); + + /* + * If the task is already STOPPED, set GROUP_STOP_PENDING and + * TRAPPING, and kick it so that it transits to TRACED. TRAPPING + * will be cleared if the child completes the transition or any + * event which clears the group stop states happens. We'll wait + * for the transition to complete before returning from this + * function. + * + * This hides STOPPED -> RUNNING -> TRACED transition from the + * attaching thread but a different thread in the same group can + * still observe the transient RUNNING state. IOW, if another + * thread's WNOHANG wait(2) on the stopped tracee races against + * ATTACH, the wait(2) may fail due to the transient RUNNING. + * + * The following task_is_stopped() test is safe as both transitions + * in and out of STOPPED are protected by siglock. + */ + if (task_is_stopped(task)) { + task->group_stop |= GROUP_STOP_PENDING | GROUP_STOP_TRAPPING; + signal_wake_up(task, 1); + wait_trap = true; + } + + spin_unlock(&task->sighand->siglock); + retval = 0; unlock_tasklist: write_unlock_irq(&tasklist_lock); unlock_creds: mutex_unlock(&task->signal->cred_guard_mutex); out: + if (wait_trap) + wait_event(current->signal->wait_chldexit, + !(task->group_stop & GROUP_STOP_TRAPPING)); return retval; } diff --git a/kernel/signal.c b/kernel/signal.c index 418776c..1e19991 100644 --- a/kernel/signal.c +++ b/kernel/signal.c @@ -224,6 +224,26 @@ static inline void print_dropped_signal(int sig) } /** + * task_clear_group_stop_trapping - clear group stop trapping bit + * @task: target task + * + * If GROUP_STOP_TRAPPING is set, a ptracer is waiting for us. Clear it + * and wake up the ptracer. Note that we don't need any further locking. + * @task->siglock guarantees that @task->parent points to the ptracer. + * + * CONTEXT: + * Must be called with @task->sighand->siglock held. + */ +static void task_clear_group_stop_trapping(struct task_struct *task) +{ + if (unlikely(task->group_stop & GROUP_STOP_TRAPPING)) { + task->group_stop &= ~GROUP_STOP_TRAPPING; + __wake_up_sync(&task->parent->signal->wait_chldexit, + TASK_UNINTERRUPTIBLE, 1); + } +} + +/** * task_clear_group_stop_pending - clear pending group stop * @task: target task * @@ -1706,8 +1726,20 @@ static void ptrace_stop(int exit_code, int why, int clear_code, siginfo_t *info) current->last_siginfo = info; current->exit_code = exit_code; - /* Let the debugger run. */ - __set_current_state(TASK_TRACED); + /* + * TRACED should be visible before TRAPPING is cleared; otherwise, + * the tracer might fail do_wait(). + */ + set_current_state(TASK_TRACED); + + /* + * We're committing to trapping. Clearing GROUP_STOP_TRAPPING and + * transition to TASK_TRACED should be atomic with respect to + * siglock. This hsould be done after the arch hook as siglock is + * released and regrabbed across it. + */ + task_clear_group_stop_trapping(current); + spin_unlock_irq(¤t->sighand->siglock); read_lock(&tasklist_lock); if (may_ptrace_stop()) { @@ -1788,6 +1820,9 @@ static int do_signal_stop(int signr) unsigned int gstop = GROUP_STOP_PENDING | GROUP_STOP_CONSUME; struct task_struct *t; + /* signr will be recorded in task->group_stop for retries */ + WARN_ON_ONCE(signr & ~GROUP_STOP_SIGMASK); + if (!likely(sig->flags & SIGNAL_STOP_DEQUEUED) || unlikely(signal_group_exit(sig))) return 0; @@ -1797,25 +1832,27 @@ static int do_signal_stop(int signr) */ sig->group_exit_code = signr; - current->group_stop = gstop; + current->group_stop &= ~GROUP_STOP_SIGMASK; + current->group_stop |= signr | gstop; sig->group_stop_count = 1; - for (t = next_thread(current); t != current; t = next_thread(t)) + for (t = next_thread(current); t != current; + t = next_thread(t)) { + t->group_stop &= ~GROUP_STOP_SIGMASK; /* * Setting state to TASK_STOPPED for a group * stop is always done with the siglock held, * so this check has no races. */ if (!(t->flags & PF_EXITING) && !task_is_stopped(t)) { - t->group_stop = gstop; + t->group_stop |= signr | gstop; sig->group_stop_count++; signal_wake_up(t, 0); - } else + } else { task_clear_group_stop_pending(t); + } + } } - - current->exit_code = sig->group_exit_code; - __set_current_state(TASK_STOPPED); - +retry: if (likely(!task_ptrace(current))) { int notify = 0; @@ -1827,6 +1864,7 @@ static int do_signal_stop(int signr) if (task_participate_group_stop(current)) notify = CLD_STOPPED; + __set_current_state(TASK_STOPPED); spin_unlock_irq(¤t->sighand->siglock); if (notify) { @@ -1839,13 +1877,28 @@ static int do_signal_stop(int signr) schedule(); spin_lock_irq(¤t->sighand->siglock); - } else - ptrace_stop(current->exit_code, CLD_STOPPED, 0, NULL); + } else { + ptrace_stop(current->group_stop & GROUP_STOP_SIGMASK, + CLD_STOPPED, 0, NULL); + current->exit_code = 0; + } + + /* + * GROUP_STOP_PENDING could be set if another group stop has + * started since being woken up or ptrace wants us to transit + * between TASK_STOPPED and TRACED. Retry group stop. + */ + if (current->group_stop & GROUP_STOP_PENDING) { + WARN_ON_ONCE(!(current->group_stop & GROUP_STOP_SIGMASK)); + goto retry; + } + + /* PTRACE_ATTACH might have raced with task killing, clear trapping */ + task_clear_group_stop_trapping(current); spin_unlock_irq(¤t->sighand->siglock); tracehook_finish_jctl(); - current->exit_code = 0; return 1; } -- cgit v0.10.2 From e3bd058f62896ec7a2c605ed62a0a811e9147947 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Wed, 23 Mar 2011 10:37:01 +0100 Subject: ptrace: Collapse ptrace_untrace() into __ptrace_unlink() Remove the extra task_is_traced() check in __ptrace_unlink() and collapse ptrace_untrace() into __ptrace_unlink(). This is to prepare for further changes. While at it, drop the comment on top of ptrace_untrace() and convert __ptrace_unlink() comment to docbook format. Detailed comment will be added by the next patch. This patch doesn't cause any visible behavior changes. Signed-off-by: Tejun Heo Acked-by: Oleg Nesterov diff --git a/kernel/ptrace.c b/kernel/ptrace.c index 745fc2d..e609843 100644 --- a/kernel/ptrace.c +++ b/kernel/ptrace.c @@ -37,15 +37,23 @@ void __ptrace_link(struct task_struct *child, struct task_struct *new_parent) child->parent = new_parent; } -/* - * Turn a tracing stop into a normal stop now, since with no tracer there - * would be no way to wake it up with SIGCONT or SIGKILL. If there was a - * signal sent that would resume the child, but didn't because it was in - * TASK_TRACED, resume it now. - * Requires that irqs be disabled. +/** + * __ptrace_unlink - unlink ptracee and restore its execution state + * @child: ptracee to be unlinked + * + * Remove @child from the ptrace list, move it back to the original parent. + * + * CONTEXT: + * write_lock_irq(tasklist_lock) */ -static void ptrace_untrace(struct task_struct *child) +void __ptrace_unlink(struct task_struct *child) { + BUG_ON(!child->ptrace); + + child->ptrace = 0; + child->parent = child->real_parent; + list_del_init(&child->ptrace_entry); + spin_lock(&child->sighand->siglock); if (task_is_traced(child)) { /* @@ -70,24 +78,6 @@ static void ptrace_untrace(struct task_struct *child) } /* - * unptrace a task: move it back to its original parent and - * remove it from the ptrace list. - * - * Must be called with the tasklist lock write-held. - */ -void __ptrace_unlink(struct task_struct *child) -{ - BUG_ON(!child->ptrace); - - child->ptrace = 0; - child->parent = child->real_parent; - list_del_init(&child->ptrace_entry); - - if (task_is_traced(child)) - ptrace_untrace(child); -} - -/* * Check that we have indeed attached to the thing.. */ int ptrace_check_attach(struct task_struct *child, int kill) -- cgit v0.10.2 From 0e9f0a4abfd80f8adca624538d479d95159b16d8 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Wed, 23 Mar 2011 10:37:01 +0100 Subject: ptrace: Always put ptracee into appropriate execution state Currently, __ptrace_unlink() wakes up the tracee iff it's in TASK_TRACED. For unlinking from PTRACE_DETACH, this is correct as the tracee is guaranteed to be in TASK_TRACED or dead; however, unlinking also happens when the ptracer exits and in this case the ptracee can be in any state and ptrace might be left running even if the group it belongs to is stopped. This patch updates __ptrace_unlink() such that GROUP_STOP_PENDING is reinstated regardless of the ptracee's current state as long as it's alive and makes sure that signal_wake_up() is called if execution state transition is necessary. Test case follows. #include #include #include #include #include static const struct timespec ts1s = { .tv_sec = 1 }; int main(void) { pid_t tracee; siginfo_t si; tracee = fork(); if (tracee == 0) { while (1) { nanosleep(&ts1s, NULL); write(1, ".", 1); } } ptrace(PTRACE_ATTACH, tracee, NULL, NULL); waitid(P_PID, tracee, &si, WSTOPPED); ptrace(PTRACE_CONT, tracee, NULL, (void *)(long)si.si_status); waitid(P_PID, tracee, &si, WSTOPPED); ptrace(PTRACE_CONT, tracee, NULL, (void *)(long)si.si_status); write(1, "exiting", 7); return 0; } Before the patch, after the parent process exits, the child is left running and prints out "." every second. exiting..... (continues) After the patch, the group stop initiated by the implied SIGSTOP from PTRACE_ATTACH is re-established when the parent exits. exiting Signed-off-by: Tejun Heo Reported-by: Oleg Nesterov Acked-by: Oleg Nesterov diff --git a/kernel/ptrace.c b/kernel/ptrace.c index e609843..4348586 100644 --- a/kernel/ptrace.c +++ b/kernel/ptrace.c @@ -41,7 +41,26 @@ void __ptrace_link(struct task_struct *child, struct task_struct *new_parent) * __ptrace_unlink - unlink ptracee and restore its execution state * @child: ptracee to be unlinked * - * Remove @child from the ptrace list, move it back to the original parent. + * Remove @child from the ptrace list, move it back to the original parent, + * and restore the execution state so that it conforms to the group stop + * state. + * + * Unlinking can happen via two paths - explicit PTRACE_DETACH or ptracer + * exiting. For PTRACE_DETACH, unless the ptracee has been killed between + * ptrace_check_attach() and here, it's guaranteed to be in TASK_TRACED. + * If the ptracer is exiting, the ptracee can be in any state. + * + * After detach, the ptracee should be in a state which conforms to the + * group stop. If the group is stopped or in the process of stopping, the + * ptracee should be put into TASK_STOPPED; otherwise, it should be woken + * up from TASK_TRACED. + * + * If the ptracee is in TASK_TRACED and needs to be moved to TASK_STOPPED, + * it goes through TRACED -> RUNNING -> STOPPED transition which is similar + * to but in the opposite direction of what happens while attaching to a + * stopped task. However, in this direction, the intermediate RUNNING + * state is not hidden even from the current ptracer and if it immediately + * re-attaches and performs a WNOHANG wait(2), it may fail. * * CONTEXT: * write_lock_irq(tasklist_lock) @@ -55,25 +74,25 @@ void __ptrace_unlink(struct task_struct *child) list_del_init(&child->ptrace_entry); spin_lock(&child->sighand->siglock); - if (task_is_traced(child)) { - /* - * If group stop is completed or in progress, it should - * participate in the group stop. Set GROUP_STOP_PENDING - * before kicking it. - * - * This involves TRACED -> RUNNING -> STOPPED transition - * which is similar to but in the opposite direction of - * what happens while attaching to a stopped task. - * However, in this direction, the intermediate RUNNING - * state is not hidden even from the current ptracer and if - * it immediately re-attaches and performs a WNOHANG - * wait(2), it may fail. - */ - if (child->signal->flags & SIGNAL_STOP_STOPPED || - child->signal->group_stop_count) - child->group_stop |= GROUP_STOP_PENDING; - signal_wake_up(child, 1); - } + + /* + * Reinstate GROUP_STOP_PENDING if group stop is in effect and + * @child isn't dead. + */ + if (!(child->flags & PF_EXITING) && + (child->signal->flags & SIGNAL_STOP_STOPPED || + child->signal->group_stop_count)) + child->group_stop |= GROUP_STOP_PENDING; + + /* + * If transition to TASK_STOPPED is pending or in TASK_TRACED, kick + * @child in the butt. Note that @resume should be used iff @child + * is in TASK_TRACED; otherwise, we might unduly disrupt + * TASK_KILLABLE sleeps. + */ + if (child->group_stop & GROUP_STOP_PENDING || task_is_traced(child)) + signal_wake_up(child, task_is_traced(child)); + spin_unlock(&child->sighand->siglock); } -- cgit v0.10.2 From 408a37de6c95832a4880a88a742f89f0cc554d06 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Wed, 23 Mar 2011 10:37:01 +0100 Subject: job control: Don't set group_stop exit_code if re-entering job control stop While ptraced, a task may be resumed while the containing process is still job control stopped. If the task receives another stop signal in this state, it will still initiate group stop, which generates group_exit_code, which the real parent would be able to see once the ptracer detaches. In this scenario, the real parent may see two consecutive CLD_STOPPED events from two stop signals without intervening SIGCONT, which normally is impossible. Test case follows. #include #include #include #include int main(void) { pid_t tracee; siginfo_t si; tracee = fork(); if (!tracee) while (1) pause(); kill(tracee, SIGSTOP); waitid(P_PID, tracee, &si, WSTOPPED); if (!fork()) { ptrace(PTRACE_ATTACH, tracee, NULL, NULL); waitid(P_PID, tracee, &si, WSTOPPED); ptrace(PTRACE_CONT, tracee, NULL, (void *)(long)si.si_status); waitid(P_PID, tracee, &si, WSTOPPED); ptrace(PTRACE_CONT, tracee, NULL, (void *)(long)si.si_status); waitid(P_PID, tracee, &si, WSTOPPED); ptrace(PTRACE_DETACH, tracee, NULL, NULL); return 0; } while (1) { si.si_pid = 0; waitid(P_PID, tracee, &si, WSTOPPED | WNOHANG); if (si.si_pid) printf("st=%02d c=%02d\n", si.si_status, si.si_code); } return 0; } Before the patch, the latter waitid() in polling mode reports the second stopped event generated by the implied SIGSTOP of PTRACE_ATTACH. st=19 c=05 ^C After the patch, the second event is not reported. Signed-off-by: Tejun Heo Acked-by: Oleg Nesterov diff --git a/kernel/signal.c b/kernel/signal.c index 1e19991..2f2c8f6 100644 --- a/kernel/signal.c +++ b/kernel/signal.c @@ -1827,10 +1827,27 @@ static int do_signal_stop(int signr) unlikely(signal_group_exit(sig))) return 0; /* - * There is no group stop already in progress. - * We must initiate one now. + * There is no group stop already in progress. We must + * initiate one now. + * + * While ptraced, a task may be resumed while group stop is + * still in effect and then receive a stop signal and + * initiate another group stop. This deviates from the + * usual behavior as two consecutive stop signals can't + * cause two group stops when !ptraced. + * + * The condition can be distinguished by testing whether + * SIGNAL_STOP_STOPPED is already set. Don't generate + * group_exit_code in such case. + * + * This is not necessary for SIGNAL_STOP_CONTINUED because + * an intervening stop signal is required to cause two + * continued events regardless of ptrace. */ - sig->group_exit_code = signr; + if (!(sig->flags & SIGNAL_STOP_STOPPED)) + sig->group_exit_code = signr; + else + WARN_ON_ONCE(!task_ptrace(current)); current->group_stop &= ~GROUP_STOP_SIGMASK; current->group_stop |= signr | gstop; -- cgit v0.10.2 From 823b018e5b1196d810790559357447948f644548 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Wed, 23 Mar 2011 10:37:01 +0100 Subject: job control: Small reorganization of wait_consider_task() Move EXIT_DEAD test in wait_consider_task() above ptrace check. As ptraced tasks can't be EXIT_DEAD, this change doesn't cause any behavior change. This is to prepare for further changes. Signed-off-by: Tejun Heo Acked-by: Oleg Nesterov diff --git a/kernel/exit.c b/kernel/exit.c index f9a45eb..b4a935c 100644 --- a/kernel/exit.c +++ b/kernel/exit.c @@ -1537,6 +1537,10 @@ static int wait_consider_task(struct wait_opts *wo, int ptrace, return 0; } + /* dead body doesn't have much to contribute */ + if (p->exit_state == EXIT_DEAD) + return 0; + if (likely(!ptrace) && unlikely(task_ptrace(p))) { /* * This child is hidden by ptrace. @@ -1546,9 +1550,6 @@ static int wait_consider_task(struct wait_opts *wo, int ptrace, return 0; } - if (p->exit_state == EXIT_DEAD) - return 0; - /* * We don't reap group leaders with subthreads. */ -- cgit v0.10.2 From 9b84cca2564b9a5b2d064fb44d2a55a5b44473a0 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Wed, 23 Mar 2011 10:37:01 +0100 Subject: job control: Fix ptracer wait(2) hang and explain notask_error clearing wait(2) and friends allow access to stopped/continued states through zombies, which is required as the states are process-wide and should be accessible whether the leader task is alive or undead. wait_consider_task() implements this by always clearing notask_error and going through wait_task_stopped/continued() for unreaped zombies. However, while ptraced, the stopped state is per-task and as such if the ptracee became a zombie, there's no further stopped event to listen to and wait(2) and friends should return -ECHILD on the tracee. Fix it by clearing notask_error only if WCONTINUED | WEXITED is set for ptraced zombies. While at it, document why clearing notask_error is safe for each case. Test case follows. #include #include #include #include #include #include #include static void *nooper(void *arg) { pause(); return NULL; } int main(void) { const struct timespec ts1s = { .tv_sec = 1 }; pid_t tracee, tracer; siginfo_t si; tracee = fork(); if (tracee == 0) { pthread_t thr; pthread_create(&thr, NULL, nooper, NULL); nanosleep(&ts1s, NULL); printf("tracee exiting\n"); pthread_exit(NULL); /* let subthread run */ } tracer = fork(); if (tracer == 0) { ptrace(PTRACE_ATTACH, tracee, NULL, NULL); while (1) { if (waitid(P_PID, tracee, &si, WSTOPPED) < 0) { perror("waitid"); break; } ptrace(PTRACE_CONT, tracee, NULL, (void *)(long)si.si_status); } return 0; } waitid(P_PID, tracer, &si, WEXITED); kill(tracee, SIGKILL); return 0; } Before the patch, after the tracee becomes a zombie, the tracer's waitid(WSTOPPED) never returns and the program doesn't terminate. tracee exiting ^C After the patch, tracee exiting triggers waitid() to fail. tracee exiting waitid: No child processes -v2: Oleg pointed out that exited in addition to continued can happen for ptraced dead group leader. Clear notask_error for ptraced child on WEXITED too. Signed-off-by: Tejun Heo Acked-by: Oleg Nesterov diff --git a/kernel/exit.c b/kernel/exit.c index b4a935c..84d13d6 100644 --- a/kernel/exit.c +++ b/kernel/exit.c @@ -1550,17 +1550,41 @@ static int wait_consider_task(struct wait_opts *wo, int ptrace, return 0; } - /* - * We don't reap group leaders with subthreads. - */ - if (p->exit_state == EXIT_ZOMBIE && !delay_group_leader(p)) - return wait_task_zombie(wo, p); + /* slay zombie? */ + if (p->exit_state == EXIT_ZOMBIE) { + /* we don't reap group leaders with subthreads */ + if (!delay_group_leader(p)) + return wait_task_zombie(wo, p); - /* - * It's stopped or running now, so it might - * later continue, exit, or stop again. - */ - wo->notask_error = 0; + /* + * Allow access to stopped/continued state via zombie by + * falling through. Clearing of notask_error is complex. + * + * When !@ptrace: + * + * If WEXITED is set, notask_error should naturally be + * cleared. If not, subset of WSTOPPED|WCONTINUED is set, + * so, if there are live subthreads, there are events to + * wait for. If all subthreads are dead, it's still safe + * to clear - this function will be called again in finite + * amount time once all the subthreads are released and + * will then return without clearing. + * + * When @ptrace: + * + * Stopped state is per-task and thus can't change once the + * target task dies. Only continued and exited can happen. + * Clear notask_error if WCONTINUED | WEXITED. + */ + if (likely(!ptrace) || (wo->wo_flags & (WCONTINUED | WEXITED))) + wo->notask_error = 0; + } else { + /* + * @p is alive and it's gonna stop, continue or exit, so + * there always is something to wait for. + */ + wo->notask_error = 0; + } if (task_stopped_code(p, ptrace)) return wait_task_stopped(wo, ptrace, p); -- cgit v0.10.2 From 45cb24a1da53beb70f09efccc0373f6a47a9efe0 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Wed, 23 Mar 2011 10:37:01 +0100 Subject: job control: Allow access to job control events through ptracees Currently a real parent can't access job control stopped/continued events through a ptraced child. This utterly breaks job control when the children are ptraced. For example, if a program is run from an interactive shell and then strace(1) attaches to it, pressing ^Z would send SIGTSTP and strace(1) would notice it but the shell has no way to tell whether the child entered job control stop and thus can't tell when to take over the terminal - leading to awkward lone ^Z on the terminal. Because the job control and ptrace stopped states are independent, there is no reason to prevent real parents from accessing the stopped state regardless of ptrace. The continued state isn't separate but ptracers don't have any use for them as ptracees can never resume without explicit command from their ptracers, so as long as ptracers don't consume it, it should be fine. Although this is a behavior change, because the previous behavior is utterly broken when viewed from real parents and the change is only visible to real parents, I don't think it's necessary to make this behavior optional. One situation to be careful about is when a task from the real parent's group is ptracing. The parent group is the recipient of both ptrace and job control stop events and one stop can be reported as both job control and ptrace stops. As this can break the current ptrace users, suppress job control stopped events for these cases. If a real parent ptracer wants to know about both job control and ptrace stops, it can create a separate process to serve the role of real parent. Note that this only updates wait(2) side of things. The real parent can access the states via wait(2) but still is not properly notified (woken up and delivered signal). Test case polls wait(2) with WNOHANG to work around. Notification will be updated by future patches. Test case follows. #include #include #include #include #include #include #include int main(void) { const struct timespec ts100ms = { .tv_nsec = 100000000 }; pid_t tracee, tracer; siginfo_t si; int i; tracee = fork(); if (tracee == 0) { while (1) { printf("tracee: SIGSTOP\n"); raise(SIGSTOP); nanosleep(&ts100ms, NULL); printf("tracee: SIGCONT\n"); raise(SIGCONT); nanosleep(&ts100ms, NULL); } } waitid(P_PID, tracee, &si, WSTOPPED | WNOHANG | WNOWAIT); tracer = fork(); if (tracer == 0) { nanosleep(&ts100ms, NULL); ptrace(PTRACE_ATTACH, tracee, NULL, NULL); for (i = 0; i < 11; i++) { si.si_pid = 0; waitid(P_PID, tracee, &si, WSTOPPED); if (si.si_pid && si.si_code == CLD_TRAPPED) ptrace(PTRACE_CONT, tracee, NULL, (void *)(long)si.si_status); } printf("tracer: EXITING\n"); return 0; } while (1) { si.si_pid = 0; waitid(P_PID, tracee, &si, WSTOPPED | WCONTINUED | WEXITED | WNOHANG); if (si.si_pid) printf("mommy : WAIT status=%02d code=%02d\n", si.si_status, si.si_code); nanosleep(&ts100ms, NULL); } return 0; } Before the patch, while ptraced, the parent can't see any job control events. tracee: SIGSTOP mommy : WAIT status=19 code=05 tracee: SIGCONT tracee: SIGSTOP tracee: SIGCONT tracee: SIGSTOP tracee: SIGCONT tracee: SIGSTOP tracer: EXITING mommy : WAIT status=19 code=05 ^C After the patch, tracee: SIGSTOP mommy : WAIT status=19 code=05 tracee: SIGCONT mommy : WAIT status=18 code=06 tracee: SIGSTOP mommy : WAIT status=19 code=05 tracee: SIGCONT mommy : WAIT status=18 code=06 tracee: SIGSTOP mommy : WAIT status=19 code=05 tracee: SIGCONT mommy : WAIT status=18 code=06 tracee: SIGSTOP tracer: EXITING mommy : WAIT status=19 code=05 ^C -v2: Oleg pointed out that wait(2) should be suppressed for the real parent's group instead of only the real parent task itself. Updated accordingly. Signed-off-by: Tejun Heo Acked-by: Oleg Nesterov diff --git a/kernel/exit.c b/kernel/exit.c index 84d13d6..1a0f10f 100644 --- a/kernel/exit.c +++ b/kernel/exit.c @@ -1541,17 +1541,19 @@ static int wait_consider_task(struct wait_opts *wo, int ptrace, if (p->exit_state == EXIT_DEAD) return 0; - if (likely(!ptrace) && unlikely(task_ptrace(p))) { + /* slay zombie? */ + if (p->exit_state == EXIT_ZOMBIE) { /* - * This child is hidden by ptrace. - * We aren't allowed to see it now, but eventually we will. + * A zombie ptracee is only visible to its ptracer. + * Notification and reaping will be cascaded to the real + * parent when the ptracer detaches. */ - wo->notask_error = 0; - return 0; - } + if (likely(!ptrace) && unlikely(task_ptrace(p))) { + /* it will become visible, clear notask_error */ + wo->notask_error = 0; + return 0; + } - /* slay zombie? */ - if (p->exit_state == EXIT_ZOMBIE) { /* we don't reap group leaders with subthreads */ if (!delay_group_leader(p)) return wait_task_zombie(wo, p); @@ -1580,15 +1582,38 @@ static int wait_consider_task(struct wait_opts *wo, int ptrace, wo->notask_error = 0; } else { /* + * If @p is ptraced by a task in its real parent's group, + * hide group stop/continued state when looking at @p as + * the real parent; otherwise, a single stop can be + * reported twice as group and ptrace stops. + * + * If a ptracer wants to distinguish the two events for its + * own children, it should create a separate process which + * takes the role of real parent. + */ + if (likely(!ptrace) && task_ptrace(p) && + same_thread_group(p->parent, p->real_parent)) + return 0; + + /* * @p is alive and it's gonna stop, continue or exit, so * there always is something to wait for. */ wo->notask_error = 0; } + /* + * Wait for stopped. Depending on @ptrace, different stopped state + * is used and the two don't interact with each other. + */ if (task_stopped_code(p, ptrace)) return wait_task_stopped(wo, ptrace, p); + /* + * Wait for continued. There's only one continued state and the + * ptracer can consume it which can confuse the real parent. Don't + * use WCONTINUED from ptracer. You don't need or want it. + */ return wait_task_continued(wo, p); } -- cgit v0.10.2 From 75b95953a56969a990e6ce154b260be83818fe71 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Wed, 23 Mar 2011 10:37:01 +0100 Subject: job control: Add @for_ptrace to do_notify_parent_cldstop() Currently, do_notify_parent_cldstop() determines whether the notification is for the real parent or ptracer. Move the decision to the caller by adding @for_ptrace parameter to do_notify_parent_cldstop(). All the callers are updated to pass task_ptrace(target_task), so this patch doesn't cause any behavior difference. While at it, add function comment to do_notify_parent_cldstop(). Signed-off-by: Tejun Heo Acked-by: Oleg Nesterov diff --git a/kernel/signal.c b/kernel/signal.c index 2f2c8f6..69d6054 100644 --- a/kernel/signal.c +++ b/kernel/signal.c @@ -1595,16 +1595,30 @@ int do_notify_parent(struct task_struct *tsk, int sig) return ret; } -static void do_notify_parent_cldstop(struct task_struct *tsk, int why) +/** + * do_notify_parent_cldstop - notify parent of stopped/continued state change + * @tsk: task reporting the state change + * @for_ptracer: the notification is for ptracer + * @why: CLD_{CONTINUED|STOPPED|TRAPPED} to report + * + * Notify @tsk's parent that the stopped/continued state has changed. If + * @for_ptracer is %false, @tsk's group leader notifies to its real parent. + * If %true, @tsk reports to @tsk->parent which should be the ptracer. + * + * CONTEXT: + * Must be called with tasklist_lock at least read locked. + */ +static void do_notify_parent_cldstop(struct task_struct *tsk, + bool for_ptracer, int why) { struct siginfo info; unsigned long flags; struct task_struct *parent; struct sighand_struct *sighand; - if (task_ptrace(tsk)) + if (for_ptracer) { parent = tsk->parent; - else { + } else { tsk = tsk->group_leader; parent = tsk->real_parent; } @@ -1743,7 +1757,7 @@ static void ptrace_stop(int exit_code, int why, int clear_code, siginfo_t *info) spin_unlock_irq(¤t->sighand->siglock); read_lock(&tasklist_lock); if (may_ptrace_stop()) { - do_notify_parent_cldstop(current, why); + do_notify_parent_cldstop(current, task_ptrace(current), why); /* * Don't want to allow preemption here, because * sys_ptrace() needs this task to be inactive. @@ -1886,7 +1900,8 @@ retry: if (notify) { read_lock(&tasklist_lock); - do_notify_parent_cldstop(current, notify); + do_notify_parent_cldstop(current, task_ptrace(current), + notify); read_unlock(&tasklist_lock); } @@ -1982,6 +1997,7 @@ relock: * the CLD_ si_code into SIGNAL_CLD_MASK bits. */ if (unlikely(signal->flags & SIGNAL_CLD_MASK)) { + struct task_struct *leader; int why; if (signal->flags & SIGNAL_CLD_CONTINUED) @@ -1994,7 +2010,8 @@ relock: spin_unlock_irq(&sighand->siglock); read_lock(&tasklist_lock); - do_notify_parent_cldstop(current->group_leader, why); + leader = current->group_leader; + do_notify_parent_cldstop(leader, task_ptrace(leader), why); read_unlock(&tasklist_lock); goto relock; } @@ -2167,7 +2184,7 @@ out: if (unlikely(group_stop)) { read_lock(&tasklist_lock); - do_notify_parent_cldstop(tsk, group_stop); + do_notify_parent_cldstop(tsk, task_ptrace(tsk), group_stop); read_unlock(&tasklist_lock); } } -- cgit v0.10.2 From 62bcf9d992ecc19ea4f37ff57ee0b3333e3e843e Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Wed, 23 Mar 2011 10:37:01 +0100 Subject: job control: Job control stop notifications should always go to the real parent The stopped notifications in do_signal_stop() and exit_signals() are always for the completion of job control. The one in do_signal_stop() may be delivered to the ptracer if PTRACE_ATTACH races with notification and the one in exit_signals() if task exits while ptraced. In both cases, the notifications are meaningless and confusing to the ptracer as it never accesses the group stop state while the real parent would miss notifications for the events it is watching. Make sure these notifications always go to the real parent by calling do_notify_parent_cld_stop() with %false @for_ptrace. Signed-off-by: Tejun Heo Acked-by: Oleg Nesterov diff --git a/kernel/signal.c b/kernel/signal.c index 69d6054..9f10b24 100644 --- a/kernel/signal.c +++ b/kernel/signal.c @@ -1898,10 +1898,18 @@ retry: __set_current_state(TASK_STOPPED); spin_unlock_irq(¤t->sighand->siglock); + /* + * Notify the parent of the group stop completion. Because + * we're not holding either the siglock or tasklist_lock + * here, ptracer may attach inbetween; however, this is for + * group stop and should always be delivered to the real + * parent of the group leader. The new ptracer will get + * its notification when this task transitions into + * TASK_TRACED. + */ if (notify) { read_lock(&tasklist_lock); - do_notify_parent_cldstop(current, task_ptrace(current), - notify); + do_notify_parent_cldstop(current, false, notify); read_unlock(&tasklist_lock); } @@ -2182,9 +2190,13 @@ void exit_signals(struct task_struct *tsk) out: spin_unlock_irq(&tsk->sighand->siglock); + /* + * If group stop has completed, deliver the notification. This + * should always go to the real parent of the group leader. + */ if (unlikely(group_stop)) { read_lock(&tasklist_lock); - do_notify_parent_cldstop(tsk, task_ptrace(tsk), group_stop); + do_notify_parent_cldstop(tsk, false, group_stop); read_unlock(&tasklist_lock); } } -- cgit v0.10.2 From ceb6bd67f9b9db765e1c29405f26e8460391badd Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Wed, 23 Mar 2011 10:37:01 +0100 Subject: job control: Notify the real parent of job control events regardless of ptrace With recent changes, job control and ptrace stopped states are properly separated and accessible to the real parent and the ptracer respectively; however, notifications of job control stopped/continued events to the real parent while ptraced are still missing. A ptracee participates in group stop in ptrace_stop() but the completion isn't notified. If participation results in completion of group stop, notify the real parent of the event. The ptrace and group stops are separate and can be handled as such. However, when the real parent and the ptracer are in the same thread group, only the ptrace stop event is visible through wait(2) and the duplicate notifications are different from the current behavior and are confusing. Suppress group stop notification in such cases. The continued state is shared between the real parent and the ptracer but is only meaningful to the real parent. Always notify the real parent and notify the ptracer too for backward compatibility. Similar to stop notification, if the real parent is the ptracer, suppress a duplicate notification. Test case follows. #include #include #include #include #include #include #include int main(void) { const struct timespec ts100ms = { .tv_nsec = 100000000 }; pid_t tracee, tracer; siginfo_t si; int i; tracee = fork(); if (tracee == 0) { while (1) { printf("tracee: SIGSTOP\n"); raise(SIGSTOP); nanosleep(&ts100ms, NULL); printf("tracee: SIGCONT\n"); raise(SIGCONT); nanosleep(&ts100ms, NULL); } } waitid(P_PID, tracee, &si, WSTOPPED | WNOHANG | WNOWAIT); tracer = fork(); if (tracer == 0) { nanosleep(&ts100ms, NULL); ptrace(PTRACE_ATTACH, tracee, NULL, NULL); for (i = 0; i < 11; i++) { si.si_pid = 0; waitid(P_PID, tracee, &si, WSTOPPED); if (si.si_pid && si.si_code == CLD_TRAPPED) ptrace(PTRACE_CONT, tracee, NULL, (void *)(long)si.si_status); } printf("tracer: EXITING\n"); return 0; } while (1) { si.si_pid = 0; waitid(P_PID, tracee, &si, WSTOPPED | WCONTINUED | WEXITED); if (si.si_pid) printf("mommy : WAIT status=%02d code=%02d\n", si.si_status, si.si_code); } return 0; } Before this patch, while ptraced, the real parent doesn't get notifications for job control events, so although it can access those events, the later waitid(2) call never wakes up. tracee: SIGSTOP mommy : WAIT status=19 code=05 tracee: SIGCONT tracee: SIGSTOP tracee: SIGCONT tracee: SIGSTOP tracee: SIGCONT tracee: SIGSTOP tracer: EXITING mommy : WAIT status=19 code=05 ^C After this patch, it works as expected. tracee: SIGSTOP mommy : WAIT status=19 code=05 tracee: SIGCONT mommy : WAIT status=18 code=06 tracee: SIGSTOP mommy : WAIT status=19 code=05 tracee: SIGCONT mommy : WAIT status=18 code=06 tracee: SIGSTOP mommy : WAIT status=19 code=05 tracee: SIGCONT mommy : WAIT status=18 code=06 tracee: SIGSTOP tracer: EXITING mommy : WAIT status=19 code=05 ^C -v2: Oleg pointed out that * Group stop notification to the real parent should also happen when ptracer detach races with ptrace_stop(). * real_parent_is_ptracer() should be testing thread group equality not the task itself as wait(2) and stop/cont notifications are normally thread-group wide. Both issues are fixed accordingly. -v3: real_parent_is_ptracer() updated to test child->real_parent instead of child->group_leader->real_parent per Oleg's suggestion. Signed-off-by: Tejun Heo Acked-by: Oleg Nesterov diff --git a/kernel/signal.c b/kernel/signal.c index 9f10b24..f65403d 100644 --- a/kernel/signal.c +++ b/kernel/signal.c @@ -1694,6 +1694,15 @@ static int sigkill_pending(struct task_struct *tsk) } /* + * Test whether the target task of the usual cldstop notification - the + * real_parent of @child - is in the same group as the ptracer. + */ +static bool real_parent_is_ptracer(struct task_struct *child) +{ + return same_thread_group(child->parent, child->real_parent); +} + +/* * This must be called with current->sighand->siglock held. * * This should be the path for all ptrace stops. @@ -1708,6 +1717,8 @@ static void ptrace_stop(int exit_code, int why, int clear_code, siginfo_t *info) __releases(¤t->sighand->siglock) __acquires(¤t->sighand->siglock) { + bool gstop_done = false; + if (arch_ptrace_stop_needed(exit_code, info)) { /* * The arch code has something special to do before a @@ -1735,7 +1746,7 @@ static void ptrace_stop(int exit_code, int why, int clear_code, siginfo_t *info) * is entered - ignore it. */ if (why == CLD_STOPPED && (current->group_stop & GROUP_STOP_PENDING)) - task_participate_group_stop(current); + gstop_done = task_participate_group_stop(current); current->last_siginfo = info; current->exit_code = exit_code; @@ -1757,7 +1768,20 @@ static void ptrace_stop(int exit_code, int why, int clear_code, siginfo_t *info) spin_unlock_irq(¤t->sighand->siglock); read_lock(&tasklist_lock); if (may_ptrace_stop()) { - do_notify_parent_cldstop(current, task_ptrace(current), why); + /* + * Notify parents of the stop. + * + * While ptraced, there are two parents - the ptracer and + * the real_parent of the group_leader. The ptracer should + * know about every stop while the real parent is only + * interested in the completion of group stop. The states + * for the two don't interact with each other. Notify + * separately unless they're gonna be duplicates. + */ + do_notify_parent_cldstop(current, true, why); + if (gstop_done && !real_parent_is_ptracer(current)) + do_notify_parent_cldstop(current, false, why); + /* * Don't want to allow preemption here, because * sys_ptrace() needs this task to be inactive. @@ -1772,7 +1796,16 @@ static void ptrace_stop(int exit_code, int why, int clear_code, siginfo_t *info) /* * By the time we got the lock, our tracer went away. * Don't drop the lock yet, another tracer may come. + * + * If @gstop_done, the ptracer went away between group stop + * completion and here. During detach, it would have set + * GROUP_STOP_PENDING on us and we'll re-enter TASK_STOPPED + * in do_signal_stop() on return, so notifying the real + * parent of the group stop completion is enough. */ + if (gstop_done) + do_notify_parent_cldstop(current, false, why); + __set_current_state(TASK_RUNNING); if (clear_code) current->exit_code = 0; @@ -2017,10 +2050,24 @@ relock: spin_unlock_irq(&sighand->siglock); + /* + * Notify the parent that we're continuing. This event is + * always per-process and doesn't make whole lot of sense + * for ptracers, who shouldn't consume the state via + * wait(2) either, but, for backward compatibility, notify + * the ptracer of the group leader too unless it's gonna be + * a duplicate. + */ read_lock(&tasklist_lock); + + do_notify_parent_cldstop(current, false, why); + leader = current->group_leader; - do_notify_parent_cldstop(leader, task_ptrace(leader), why); + if (task_ptrace(leader) && !real_parent_is_ptracer(leader)) + do_notify_parent_cldstop(leader, true, why); + read_unlock(&tasklist_lock); + goto relock; } -- cgit v0.10.2 From 244056f9dbbc6dc4126a301c745fa3dd67d8af3c Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Wed, 23 Mar 2011 10:37:01 +0100 Subject: job control: Don't send duplicate job control stop notification while ptraced Just as group_exit_code shouldn't be generated when a PTRACE_CONT'd task re-enters job control stop, notifiction for the event should be suppressed too. The logic is the same as the group_exit_code generation suppression in do_signal_stop(), if SIGNAL_STOP_STOPPED is already set, the task is re-entering job control stop without intervening SIGCONT and the notifications should be suppressed. Test case follows. #include #include #include #include #include #include static const struct timespec ts100ms = { .tv_nsec = 100000000 }; static pid_t tracee, tracer; static const char *pid_who(pid_t pid) { return pid == tracee ? "tracee" : (pid == tracer ? "tracer" : "mommy "); } static void sigchld_sigaction(int signo, siginfo_t *si, void *ucxt) { printf("%s: SIG status=%02d code=%02d (%s)\n", pid_who(getpid()), si->si_status, si->si_code, pid_who(si->si_pid)); } int main(void) { const struct sigaction chld_sa = { .sa_sigaction = sigchld_sigaction, .sa_flags = SA_SIGINFO|SA_RESTART }; siginfo_t si; sigaction(SIGCHLD, &chld_sa, NULL); tracee = fork(); if (!tracee) { tracee = getpid(); while (1) pause(); } kill(tracee, SIGSTOP); waitid(P_PID, tracee, &si, WSTOPPED); tracer = fork(); if (!tracer) { tracer = getpid(); ptrace(PTRACE_ATTACH, tracee, NULL, NULL); waitid(P_PID, tracee, &si, WSTOPPED); ptrace(PTRACE_CONT, tracee, NULL, (void *)(long)si.si_status); waitid(P_PID, tracee, &si, WSTOPPED); ptrace(PTRACE_CONT, tracee, NULL, (void *)(long)si.si_status); waitid(P_PID, tracee, &si, WSTOPPED); printf("tracer: detaching\n"); ptrace(PTRACE_DETACH, tracee, NULL, NULL); return 0; } while (1) pause(); return 0; } Before the patch, the parent gets the second notification for the tracee after the tracer detaches. si_status is zero because group_exit_code is not set by the group stop completion which triggered this notification. mommy : SIG status=19 code=05 (tracee) tracer: SIG status=00 code=05 (tracee) tracer: SIG status=19 code=04 (tracee) tracer: SIG status=00 code=05 (tracee) tracer: detaching mommy : SIG status=00 code=05 (tracee) mommy : SIG status=00 code=01 (tracer) ^C After the patch, the duplicate notification is gone. mommy : SIG status=19 code=05 (tracee) tracer: SIG status=00 code=05 (tracee) tracer: SIG status=19 code=04 (tracee) tracer: SIG status=00 code=05 (tracee) tracer: detaching mommy : SIG status=00 code=01 (tracer) ^C Signed-off-by: Tejun Heo Acked-by: Oleg Nesterov diff --git a/kernel/signal.c b/kernel/signal.c index f65403d..f799a05 100644 --- a/kernel/signal.c +++ b/kernel/signal.c @@ -268,6 +268,10 @@ void task_clear_group_stop_pending(struct task_struct *task) * * CONTEXT: * Must be called with @task->sighand->siglock held. + * + * RETURNS: + * %true if group stop completion should be notified to the parent, %false + * otherwise. */ static bool task_participate_group_stop(struct task_struct *task) { @@ -284,7 +288,11 @@ static bool task_participate_group_stop(struct task_struct *task) if (!WARN_ON_ONCE(sig->group_stop_count == 0)) sig->group_stop_count--; - if (!sig->group_stop_count) { + /* + * Tell the caller to notify completion iff we are entering into a + * fresh group stop. Read comment in do_signal_stop() for details. + */ + if (!sig->group_stop_count && !(sig->flags & SIGNAL_STOP_STOPPED)) { sig->flags = SIGNAL_STOP_STOPPED; return true; } -- cgit v0.10.2 From eb0536c5e2815e3e38ed2b2f31401e114faec016 Mon Sep 17 00:00:00 2001 From: Florian Tobias Schandinat Date: Mon, 21 Mar 2011 13:28:26 +0000 Subject: viafb: allow some pll calculations This patch allows calculating the pll multiplier within limits based on the previous table. All available information supports that it should be possible/sane to choose the multiplier free within some ranges. Storing the multiplier ranges instead of lots of pll configurations reduces the memory needed and may as well improve the performance. It is also expected to provide better pll values resulting in better frequencies for the connected devices. Signed-off-by: Florian Tobias Schandinat diff --git a/drivers/video/via/hw.c b/drivers/video/via/hw.c index dc4c778..063ff65 100644 --- a/drivers/video/via/hw.c +++ b/drivers/video/via/hw.c @@ -22,272 +22,80 @@ #include #include "global.h" -static struct pll_config cle266_pll_config[] = { - {19, 4, 0}, - {26, 5, 0}, - {28, 5, 0}, - {31, 5, 0}, - {33, 5, 0}, - {55, 5, 0}, - {102, 5, 0}, - {53, 6, 0}, - {92, 6, 0}, - {98, 6, 0}, - {112, 6, 0}, - {41, 7, 0}, - {60, 7, 0}, - {99, 7, 0}, - {100, 7, 0}, - {83, 8, 0}, - {86, 8, 0}, - {108, 8, 0}, - {87, 9, 0}, - {118, 9, 0}, - {95, 12, 0}, - {115, 12, 0}, - {108, 13, 0}, - {83, 17, 0}, - {67, 20, 0}, - {86, 20, 0}, - {98, 20, 0}, - {121, 24, 0}, - {99, 29, 0}, - {33, 3, 1}, - {15, 4, 1}, - {23, 4, 1}, - {37, 5, 1}, - {83, 5, 1}, - {85, 5, 1}, - {94, 5, 1}, - {103, 5, 1}, - {109, 5, 1}, - {113, 5, 1}, - {121, 5, 1}, - {82, 6, 1}, - {31, 7, 1}, - {55, 7, 1}, - {84, 7, 1}, - {83, 8, 1}, - {76, 9, 1}, - {127, 9, 1}, - {33, 4, 2}, - {75, 4, 2}, - {119, 4, 2}, - {121, 4, 2}, - {91, 5, 2}, - {118, 5, 2}, - {83, 6, 2}, - {109, 6, 2}, - {90, 7, 2}, - {93, 2, 3}, - {53, 3, 3}, - {73, 4, 3}, - {89, 4, 3}, - {105, 4, 3}, - {117, 4, 3}, - {101, 5, 3}, - {121, 5, 3}, - {127, 5, 3}, - {99, 7, 3} +static struct pll_limit cle266_pll_limits[] = { + {19, 19, 4, 0}, + {26, 102, 5, 0}, + {53, 112, 6, 0}, + {41, 100, 7, 0}, + {83, 108, 8, 0}, + {87, 118, 9, 0}, + {95, 115, 12, 0}, + {108, 108, 13, 0}, + {83, 83, 17, 0}, + {67, 98, 20, 0}, + {121, 121, 24, 0}, + {99, 99, 29, 0}, + {33, 33, 3, 1}, + {15, 23, 4, 1}, + {37, 121, 5, 1}, + {82, 82, 6, 1}, + {31, 84, 7, 1}, + {83, 83, 8, 1}, + {76, 127, 9, 1}, + {33, 121, 4, 2}, + {91, 118, 5, 2}, + {83, 109, 6, 2}, + {90, 90, 7, 2}, + {93, 93, 2, 3}, + {53, 53, 3, 3}, + {73, 117, 4, 3}, + {101, 127, 5, 3}, + {99, 99, 7, 3} }; -static struct pll_config k800_pll_config[] = { - {22, 2, 0}, - {28, 3, 0}, - {81, 3, 1}, - {85, 3, 1}, - {98, 3, 1}, - {112, 3, 1}, - {86, 4, 1}, - {166, 4, 1}, - {109, 5, 1}, - {113, 5, 1}, - {121, 5, 1}, - {131, 5, 1}, - {143, 5, 1}, - {153, 5, 1}, - {66, 3, 2}, - {68, 3, 2}, - {95, 3, 2}, - {106, 3, 2}, - {116, 3, 2}, - {93, 4, 2}, - {119, 4, 2}, - {121, 4, 2}, - {133, 4, 2}, - {137, 4, 2}, - {117, 5, 2}, - {118, 5, 2}, - {120, 5, 2}, - {124, 5, 2}, - {132, 5, 2}, - {137, 5, 2}, - {141, 5, 2}, - {166, 5, 2}, - {170, 5, 2}, - {191, 5, 2}, - {206, 5, 2}, - {208, 5, 2}, - {30, 2, 3}, - {69, 3, 3}, - {82, 3, 3}, - {83, 3, 3}, - {109, 3, 3}, - {114, 3, 3}, - {125, 3, 3}, - {89, 4, 3}, - {103, 4, 3}, - {117, 4, 3}, - {126, 4, 3}, - {150, 4, 3}, - {161, 4, 3}, - {121, 5, 3}, - {127, 5, 3}, - {131, 5, 3}, - {134, 5, 3}, - {148, 5, 3}, - {169, 5, 3}, - {172, 5, 3}, - {182, 5, 3}, - {195, 5, 3}, - {196, 5, 3}, - {208, 5, 3}, - {66, 2, 4}, - {85, 3, 4}, - {141, 4, 4}, - {146, 4, 4}, - {161, 4, 4}, - {177, 5, 4} +static struct pll_limit k800_pll_limits[] = { + {22, 22, 2, 0}, + {28, 28, 3, 0}, + {81, 112, 3, 1}, + {86, 166, 4, 1}, + {109, 153, 5, 1}, + {66, 116, 3, 2}, + {93, 137, 4, 2}, + {117, 208, 5, 2}, + {30, 30, 2, 3}, + {69, 125, 3, 3}, + {89, 161, 4, 3}, + {121, 208, 5, 3}, + {66, 66, 2, 4}, + {85, 85, 3, 4}, + {141, 161, 4, 4}, + {177, 177, 5, 4} }; -static struct pll_config cx700_pll_config[] = { - {98, 3, 1}, - {86, 4, 1}, - {109, 5, 1}, - {110, 5, 1}, - {113, 5, 1}, - {121, 5, 1}, - {131, 5, 1}, - {135, 5, 1}, - {142, 5, 1}, - {143, 5, 1}, - {153, 5, 1}, - {187, 5, 1}, - {208, 5, 1}, - {68, 2, 2}, - {95, 3, 2}, - {116, 3, 2}, - {93, 4, 2}, - {119, 4, 2}, - {133, 4, 2}, - {137, 4, 2}, - {151, 4, 2}, - {166, 4, 2}, - {110, 5, 2}, - {112, 5, 2}, - {117, 5, 2}, - {118, 5, 2}, - {120, 5, 2}, - {132, 5, 2}, - {137, 5, 2}, - {141, 5, 2}, - {151, 5, 2}, - {166, 5, 2}, - {175, 5, 2}, - {191, 5, 2}, - {206, 5, 2}, - {174, 7, 2}, - {82, 3, 3}, - {109, 3, 3}, - {117, 4, 3}, - {150, 4, 3}, - {161, 4, 3}, - {112, 5, 3}, - {115, 5, 3}, - {121, 5, 3}, - {127, 5, 3}, - {129, 5, 3}, - {131, 5, 3}, - {134, 5, 3}, - {138, 5, 3}, - {148, 5, 3}, - {157, 5, 3}, - {169, 5, 3}, - {172, 5, 3}, - {190, 5, 3}, - {195, 5, 3}, - {196, 5, 3}, - {208, 5, 3}, - {141, 5, 4}, - {150, 5, 4}, - {166, 5, 4}, - {176, 5, 4}, - {177, 5, 4}, - {183, 5, 4}, - {202, 5, 4} +static struct pll_limit cx700_pll_limits[] = { + {98, 98, 3, 1}, + {86, 86, 4, 1}, + {109, 208, 5, 1}, + {68, 68, 2, 2}, + {95, 116, 3, 2}, + {93, 166, 4, 2}, + {110, 206, 5, 2}, + {174, 174, 7, 2}, + {82, 109, 3, 3}, + {117, 161, 4, 3}, + {112, 208, 5, 3}, + {141, 202, 5, 4} }; -static struct pll_config vx855_pll_config[] = { - {86, 4, 1}, - {108, 5, 1}, - {110, 5, 1}, - {113, 5, 1}, - {121, 5, 1}, - {131, 5, 1}, - {135, 5, 1}, - {142, 5, 1}, - {143, 5, 1}, - {153, 5, 1}, - {164, 5, 1}, - {187, 5, 1}, - {208, 5, 1}, - {110, 5, 2}, - {112, 5, 2}, - {117, 5, 2}, - {118, 5, 2}, - {124, 5, 2}, - {132, 5, 2}, - {137, 5, 2}, - {141, 5, 2}, - {149, 5, 2}, - {151, 5, 2}, - {159, 5, 2}, - {166, 5, 2}, - {167, 5, 2}, - {172, 5, 2}, - {189, 5, 2}, - {191, 5, 2}, - {194, 5, 2}, - {206, 5, 2}, - {208, 5, 2}, - {83, 3, 3}, - {88, 3, 3}, - {109, 3, 3}, - {112, 3, 3}, - {103, 4, 3}, - {105, 4, 3}, - {161, 4, 3}, - {112, 5, 3}, - {115, 5, 3}, - {121, 5, 3}, - {127, 5, 3}, - {134, 5, 3}, - {137, 5, 3}, - {148, 5, 3}, - {157, 5, 3}, - {169, 5, 3}, - {172, 5, 3}, - {182, 5, 3}, - {191, 5, 3}, - {195, 5, 3}, - {209, 5, 3}, - {142, 4, 4}, - {146, 4, 4}, - {161, 4, 4}, - {141, 5, 4}, - {150, 5, 4}, - {165, 5, 4}, - {176, 5, 4} +static struct pll_limit vx855_pll_limits[] = { + {86, 86, 4, 1}, + {108, 208, 5, 1}, + {110, 208, 5, 2}, + {83, 112, 3, 3}, + {103, 161, 4, 3}, + {112, 209, 5, 3}, + {142, 161, 4, 4}, + {141, 176, 5, 4} }; /* according to VIA Technologies these values are based on experiment */ @@ -1633,17 +1441,34 @@ static inline u32 get_pll_output_frequency(u32 ref_freq, struct pll_config pll) return get_pll_internal_frequency(ref_freq, pll)>>pll.rshift; } -static struct pll_config get_pll_config(struct pll_config *config, int size, +static struct pll_config get_pll_config(struct pll_limit *limits, int size, int clk) { - struct pll_config best = config[0]; + struct pll_config cur, up, down, best = {0, 1, 0}; const u32 f0 = 14318180; /* X1 frequency */ - int i; - - for (i = 1; i < size; i++) { - if (abs(get_pll_output_frequency(f0, config[i]) - clk) - < abs(get_pll_output_frequency(f0, best) - clk)) - best = config[i]; + int i, f; + + for (i = 0; i < size; i++) { + cur.rshift = limits[i].rshift; + cur.divisor = limits[i].divisor; + cur.multiplier = clk / ((f0 / cur.divisor)>>cur.rshift); + f = abs(get_pll_output_frequency(f0, cur) - clk); + up = down = cur; + up.multiplier++; + down.multiplier--; + if (abs(get_pll_output_frequency(f0, up) - clk) < f) + cur = up; + else if (abs(get_pll_output_frequency(f0, down) - clk) < f) + cur = down; + + if (cur.multiplier < limits[i].multiplier_min) + cur.multiplier = limits[i].multiplier_min; + else if (cur.multiplier > limits[i].multiplier_max) + cur.multiplier = limits[i].multiplier_max; + + f = abs(get_pll_output_frequency(f0, cur) - clk); + if (f < abs(get_pll_output_frequency(f0, best) - clk)) + best = cur; } return best; @@ -1656,14 +1481,14 @@ u32 viafb_get_clk_value(int clk) switch (viaparinfo->chip_info->gfx_chip_name) { case UNICHROME_CLE266: case UNICHROME_K400: - value = cle266_encode_pll(get_pll_config(cle266_pll_config, - ARRAY_SIZE(cle266_pll_config), clk)); + value = cle266_encode_pll(get_pll_config(cle266_pll_limits, + ARRAY_SIZE(cle266_pll_limits), clk)); break; case UNICHROME_K800: case UNICHROME_PM800: case UNICHROME_CN700: - value = k800_encode_pll(get_pll_config(k800_pll_config, - ARRAY_SIZE(k800_pll_config), clk)); + value = k800_encode_pll(get_pll_config(k800_pll_limits, + ARRAY_SIZE(k800_pll_limits), clk)); break; case UNICHROME_CX700: case UNICHROME_CN750: @@ -1671,13 +1496,13 @@ u32 viafb_get_clk_value(int clk) case UNICHROME_P4M890: case UNICHROME_P4M900: case UNICHROME_VX800: - value = k800_encode_pll(get_pll_config(cx700_pll_config, - ARRAY_SIZE(cx700_pll_config), clk)); + value = k800_encode_pll(get_pll_config(cx700_pll_limits, + ARRAY_SIZE(cx700_pll_limits), clk)); break; case UNICHROME_VX855: case UNICHROME_VX900: - value = vx855_encode_pll(get_pll_config(vx855_pll_config, - ARRAY_SIZE(vx855_pll_config), clk)); + value = vx855_encode_pll(get_pll_config(vx855_pll_limits, + ARRAY_SIZE(vx855_pll_limits), clk)); break; } diff --git a/drivers/video/via/hw.h b/drivers/video/via/hw.h index 8858593..63d8d37 100644 --- a/drivers/video/via/hw.h +++ b/drivers/video/via/hw.h @@ -738,12 +738,11 @@ struct pll_config { u8 rshift; }; -struct pll_map { - u32 clk; - struct pll_config cle266_pll; - struct pll_config k800_pll; - struct pll_config cx700_pll; - struct pll_config vx855_pll; +struct pll_limit { + u16 multiplier_min; + u16 multiplier_max; + u8 divisor; + u8 rshift; }; struct rgbLUT { -- cgit v0.10.2 From c91faa61697a60ee5cc653db9b6fd3c7049890a6 Mon Sep 17 00:00:00 2001 From: Florian Tobias Schandinat Date: Tue, 22 Mar 2011 20:33:20 +0000 Subject: viafb: remove unused max_hres/vres This patch removes the max_hres and max_vres which are not used at the moment. In general they could be useful but it would be better to get them via any standard EDID implementation and not the buggy incomplete one currently used which is also removed as far as possible. Signed-off-by: Florian Tobias Schandinat diff --git a/drivers/video/via/chip.h b/drivers/video/via/chip.h index 1aa0fb3..3ebf20c 100644 --- a/drivers/video/via/chip.h +++ b/drivers/video/via/chip.h @@ -142,8 +142,6 @@ struct tmds_setting_information { int h_active; int v_active; int max_pixel_clock; - int max_hres; - int max_vres; }; struct lvds_setting_information { diff --git a/drivers/video/via/dvi.c b/drivers/video/via/dvi.c index 41ca198..3dbcd77 100644 --- a/drivers/video/via/dvi.c +++ b/drivers/video/via/dvi.c @@ -28,9 +28,6 @@ static int tmds_register_read_bytes(int index, u8 *buff, int buff_len); static void __devinit dvi_get_panel_size_from_DDCv1( struct tmds_chip_information *tmds_chip, struct tmds_setting_information *tmds_setting); -static void __devinit dvi_get_panel_size_from_DDCv2( - struct tmds_chip_information *tmds_chip, - struct tmds_setting_information *tmds_setting); static int viafb_dvi_query_EDID(void); static int check_tmds_chip(int device_id_subaddr, int device_id) @@ -47,17 +44,8 @@ void __devinit viafb_init_dvi_size(struct tmds_chip_information *tmds_chip, DEBUG_MSG(KERN_INFO "viafb_init_dvi_size()\n"); viafb_dvi_sense(); - switch (viafb_dvi_query_EDID()) { - case 1: + if (viafb_dvi_query_EDID() == 1) dvi_get_panel_size_from_DDCv1(tmds_chip, tmds_setting); - break; - case 2: - dvi_get_panel_size_from_DDCv2(tmds_chip, tmds_setting); - break; - default: - printk(KERN_WARNING "viafb_init_dvi_size: DVI panel size undetected!\n"); - break; - } return; } @@ -306,12 +294,7 @@ static int viafb_dvi_query_EDID(void) return EDID_VERSION_1; /* Found EDID1 Table */ } - data0 = (u8) tmds_register_read(0x00); - viaparinfo->chip_info->tmds_chip_info.tmds_chip_slave_addr = restore; - if (data0 == 0x20) - return EDID_VERSION_2; /* Found EDID2 Table */ - else - return false; + return false; } /* Get Panel Size Using EDID1 Table */ @@ -319,50 +302,15 @@ static void __devinit dvi_get_panel_size_from_DDCv1( struct tmds_chip_information *tmds_chip, struct tmds_setting_information *tmds_setting) { - int i, max_h = 0, tmp, restore; - unsigned char rData; + int i, restore; unsigned char EDID_DATA[18]; DEBUG_MSG(KERN_INFO "\n dvi_get_panel_size_from_DDCv1 \n"); restore = tmds_chip->tmds_chip_slave_addr; tmds_chip->tmds_chip_slave_addr = 0xA0; - - rData = tmds_register_read(0x23); - if (rData & 0x3C) - max_h = 640; - if (rData & 0xC0) - max_h = 720; - if (rData & 0x03) - max_h = 800; - - rData = tmds_register_read(0x24); - if (rData & 0xC0) - max_h = 800; - if (rData & 0x1E) - max_h = 1024; - if (rData & 0x01) - max_h = 1280; - for (i = 0x25; i < 0x6D; i++) { switch (i) { - case 0x26: - case 0x28: - case 0x2A: - case 0x2C: - case 0x2E: - case 0x30: - case 0x32: - case 0x34: - rData = tmds_register_read(i); - if (rData == 1) - break; - /* data = (data + 31) * 8 */ - tmp = (rData + 31) << 3; - if (tmp > max_h) - max_h = tmp; - break; - case 0x36: case 0x48: case 0x5A: @@ -383,91 +331,11 @@ static void __devinit dvi_get_panel_size_from_DDCv1( } } - tmds_setting->max_hres = max_h; - switch (max_h) { - case 640: - tmds_setting->max_vres = 480; - break; - case 800: - tmds_setting->max_vres = 600; - break; - case 1024: - tmds_setting->max_vres = 768; - break; - case 1280: - tmds_setting->max_vres = 1024; - break; - case 1400: - tmds_setting->max_vres = 1050; - break; - case 1440: - tmds_setting->max_vres = 1050; - break; - case 1600: - tmds_setting->max_vres = 1200; - break; - case 1920: - tmds_setting->max_vres = 1080; - break; - default: - DEBUG_MSG(KERN_INFO "Unknown panel size max resolution = %d ! " - "set default panel size.\n", max_h); - break; - } - DEBUG_MSG(KERN_INFO "DVI max pixelclock = %d\n", tmds_setting->max_pixel_clock); tmds_chip->tmds_chip_slave_addr = restore; } -/* Get Panel Size Using EDID2 Table */ -static void __devinit dvi_get_panel_size_from_DDCv2( - struct tmds_chip_information *tmds_chip, - struct tmds_setting_information *tmds_setting) -{ - int restore; - unsigned char R_Buffer[2]; - - DEBUG_MSG(KERN_INFO "\n dvi_get_panel_size_from_DDCv2 \n"); - - restore = tmds_chip->tmds_chip_slave_addr; - tmds_chip->tmds_chip_slave_addr = 0xA2; - - /* Horizontal: 0x76, 0x77 */ - tmds_register_read_bytes(0x76, R_Buffer, 2); - tmds_setting->max_hres = R_Buffer[0] + (R_Buffer[1] << 8); - - switch (tmds_setting->max_hres) { - case 640: - tmds_setting->max_vres = 480; - break; - case 800: - tmds_setting->max_vres = 600; - break; - case 1024: - tmds_setting->max_vres = 768; - break; - case 1280: - tmds_setting->max_vres = 1024; - break; - case 1400: - tmds_setting->max_vres = 1050; - break; - case 1440: - tmds_setting->max_vres = 1050; - break; - case 1600: - tmds_setting->max_vres = 1200; - break; - default: - DEBUG_MSG(KERN_INFO "Unknown panel size max resolution = %d! " - "set default panel size.\n", tmds_setting->max_hres); - break; - } - - tmds_chip->tmds_chip_slave_addr = restore; -} - /* If Disable DVI, turn off pad */ void viafb_dvi_disable(void) { -- cgit v0.10.2 From 1606f87e98f83512762da6dbc992103ae690ff11 Mon Sep 17 00:00:00 2001 From: Florian Tobias Schandinat Date: Wed, 23 Mar 2011 13:49:32 +0000 Subject: viafb: call viafb_get_clk_value only in viafb_set_vclock As no caller is interested in the result call viafb_get_clk_value directly from viafb_set_vclock to encapsulate the hardware dependend stuff there. Signed-off-by: Florian Tobias Schandinat diff --git a/drivers/video/via/hw.c b/drivers/video/via/hw.c index 063ff65..c28ae2e 100644 --- a/drivers/video/via/hw.c +++ b/drivers/video/via/hw.c @@ -1474,7 +1474,7 @@ static struct pll_config get_pll_config(struct pll_limit *limits, int size, return best; } -u32 viafb_get_clk_value(int clk) +static u32 viafb_get_clk_value(int clk) { u32 value = 0; @@ -1512,6 +1512,10 @@ u32 viafb_get_clk_value(int clk) /* Set VCLK*/ void viafb_set_vclock(u32 clk, int set_iga) { + u32 value = viafb_get_clk_value(clk); + + DEBUG_MSG(KERN_INFO "PLL=0x%x", value); + /* H.W. Reset : ON */ viafb_write_reg_mask(CR17, VIACR, 0x00, BIT7); @@ -1520,8 +1524,8 @@ void viafb_set_vclock(u32 clk, int set_iga) switch (viaparinfo->chip_info->gfx_chip_name) { case UNICHROME_CLE266: case UNICHROME_K400: - via_write_reg(VIASR, SR46, (clk & 0x00FF)); - via_write_reg(VIASR, SR47, (clk & 0xFF00) >> 8); + via_write_reg(VIASR, SR46, (value & 0x00FF)); + via_write_reg(VIASR, SR47, (value & 0xFF00) >> 8); break; case UNICHROME_K800: @@ -1535,9 +1539,9 @@ void viafb_set_vclock(u32 clk, int set_iga) case UNICHROME_VX800: case UNICHROME_VX855: case UNICHROME_VX900: - via_write_reg(VIASR, SR44, (clk & 0x0000FF)); - via_write_reg(VIASR, SR45, (clk & 0x00FF00) >> 8); - via_write_reg(VIASR, SR46, (clk & 0xFF0000) >> 16); + via_write_reg(VIASR, SR44, (value & 0x0000FF)); + via_write_reg(VIASR, SR45, (value & 0x00FF00) >> 8); + via_write_reg(VIASR, SR46, (value & 0xFF0000) >> 16); break; } } @@ -1547,8 +1551,8 @@ void viafb_set_vclock(u32 clk, int set_iga) switch (viaparinfo->chip_info->gfx_chip_name) { case UNICHROME_CLE266: case UNICHROME_K400: - via_write_reg(VIASR, SR44, (clk & 0x00FF)); - via_write_reg(VIASR, SR45, (clk & 0xFF00) >> 8); + via_write_reg(VIASR, SR44, (value & 0x00FF)); + via_write_reg(VIASR, SR45, (value & 0xFF00) >> 8); break; case UNICHROME_K800: @@ -1562,9 +1566,9 @@ void viafb_set_vclock(u32 clk, int set_iga) case UNICHROME_VX800: case UNICHROME_VX855: case UNICHROME_VX900: - via_write_reg(VIASR, SR4A, (clk & 0x0000FF)); - via_write_reg(VIASR, SR4B, (clk & 0x00FF00) >> 8); - via_write_reg(VIASR, SR4C, (clk & 0xFF0000) >> 16); + via_write_reg(VIASR, SR4A, (value & 0x0000FF)); + via_write_reg(VIASR, SR4B, (value & 0x00FF00) >> 8); + via_write_reg(VIASR, SR4C, (value & 0xFF0000) >> 16); break; } } @@ -1827,7 +1831,7 @@ void viafb_fill_crtc_timing(struct crt_mode_table *crt_table, int i; int index = 0; int h_addr, v_addr; - u32 pll_D_N, clock, refresh = viafb_refresh; + u32 clock, refresh = viafb_refresh; if (viafb_SAMM_ON && set_iga == IGA2) refresh = viafb_refresh1; @@ -1884,9 +1888,7 @@ void viafb_fill_crtc_timing(struct crt_mode_table *crt_table, clock = crt_reg.hor_total * crt_reg.ver_total * crt_table[index].refresh_rate; - pll_D_N = viafb_get_clk_value(clock); - DEBUG_MSG(KERN_INFO "PLL=%x", pll_D_N); - viafb_set_vclock(pll_D_N, set_iga); + viafb_set_vclock(clock, set_iga); } diff --git a/drivers/video/via/hw.h b/drivers/video/via/hw.h index 63d8d37..2cdce9b 100644 --- a/drivers/video/via/hw.h +++ b/drivers/video/via/hw.h @@ -935,7 +935,6 @@ void viafb_lock_crt(void); void viafb_unlock_crt(void); void viafb_load_fetch_count_reg(int h_addr, int bpp_byte, int set_iga); void viafb_write_regx(struct io_reg RegTable[], int ItemNum); -u32 viafb_get_clk_value(int clk); void viafb_load_FIFO_reg(int set_iga, int hor_active, int ver_active); void viafb_set_dpa_gfx(int output_interface, struct GFX_DPA_SETTING\ *p_gfx_dpa_setting); diff --git a/drivers/video/via/lcd.c b/drivers/video/via/lcd.c index 64bc7e7..284e681 100644 --- a/drivers/video/via/lcd.c +++ b/drivers/video/via/lcd.c @@ -562,7 +562,7 @@ void viafb_lcd_set_mode(struct crt_mode_table *mode_crt_table, int set_vres = plvds_setting_info->v_active; int panel_hres = plvds_setting_info->lcd_panel_hres; int panel_vres = plvds_setting_info->lcd_panel_vres; - u32 pll_D_N, clock; + u32 clock; struct display_timing mode_crt_reg, panel_crt_reg; struct crt_mode_table *panel_crt_table = NULL; struct VideoModeTable *vmode_tbl = viafb_get_mode(panel_hres, @@ -613,10 +613,7 @@ void viafb_lcd_set_mode(struct crt_mode_table *mode_crt_table, viafb_load_FIFO_reg(set_iga, set_hres, set_vres); fill_lcd_format(); - - pll_D_N = viafb_get_clk_value(clock); - DEBUG_MSG(KERN_INFO "PLL=0x%x", pll_D_N); - viafb_set_vclock(pll_D_N, set_iga); + viafb_set_vclock(clock, set_iga); lcd_patch_skew(plvds_setting_info, plvds_chip_info); /* If K8M800, enable LCD Prefetch Mode. */ -- cgit v0.10.2 From 0f77d4a052aec7392dbfd3d8942a519d013d66d9 Mon Sep 17 00:00:00 2001 From: Florian Tobias Schandinat Date: Wed, 23 Mar 2011 17:14:26 +0000 Subject: viafb: prepare for PLL separation This patch splits some functionality to extra functions. Signed-off-by: Florian Tobias Schandinat diff --git a/drivers/video/via/hw.c b/drivers/video/via/hw.c index c28ae2e..bd28e13 100644 --- a/drivers/video/via/hw.c +++ b/drivers/video/via/hw.c @@ -1430,6 +1430,70 @@ static u32 vx855_encode_pll(struct pll_config pll) | pll.multiplier; } +static inline void cle266_set_primary_pll_encoded(u32 data) +{ + via_write_reg_mask(VIASR, 0x40, 0x02, 0x02); /* enable reset */ + via_write_reg(VIASR, 0x46, data & 0xFF); + via_write_reg(VIASR, 0x47, (data >> 8) & 0xFF); + via_write_reg_mask(VIASR, 0x40, 0x00, 0x02); /* disable reset */ +} + +static inline void k800_set_primary_pll_encoded(u32 data) +{ + via_write_reg_mask(VIASR, 0x40, 0x02, 0x02); /* enable reset */ + via_write_reg(VIASR, 0x44, data & 0xFF); + via_write_reg(VIASR, 0x45, (data >> 8) & 0xFF); + via_write_reg(VIASR, 0x46, (data >> 16) & 0xFF); + via_write_reg_mask(VIASR, 0x40, 0x00, 0x02); /* disable reset */ +} + +static inline void cle266_set_secondary_pll_encoded(u32 data) +{ + via_write_reg_mask(VIASR, 0x40, 0x04, 0x04); /* enable reset */ + via_write_reg(VIASR, 0x44, data & 0xFF); + via_write_reg(VIASR, 0x45, (data >> 8) & 0xFF); + via_write_reg_mask(VIASR, 0x40, 0x00, 0x04); /* disable reset */ +} + +static inline void k800_set_secondary_pll_encoded(u32 data) +{ + via_write_reg_mask(VIASR, 0x40, 0x04, 0x04); /* enable reset */ + via_write_reg(VIASR, 0x4A, data & 0xFF); + via_write_reg(VIASR, 0x4B, (data >> 8) & 0xFF); + via_write_reg(VIASR, 0x4C, (data >> 16) & 0xFF); + via_write_reg_mask(VIASR, 0x40, 0x00, 0x04); /* disable reset */ +} + +static void cle266_set_primary_pll(struct pll_config config) +{ + cle266_set_primary_pll_encoded(cle266_encode_pll(config)); +} + +static void k800_set_primary_pll(struct pll_config config) +{ + k800_set_primary_pll_encoded(k800_encode_pll(config)); +} + +static void vx855_set_primary_pll(struct pll_config config) +{ + k800_set_primary_pll_encoded(vx855_encode_pll(config)); +} + +static void cle266_set_secondary_pll(struct pll_config config) +{ + cle266_set_secondary_pll_encoded(cle266_encode_pll(config)); +} + +static void k800_set_secondary_pll(struct pll_config config) +{ + k800_set_secondary_pll_encoded(k800_encode_pll(config)); +} + +static void vx855_set_secondary_pll(struct pll_config config) +{ + k800_set_secondary_pll_encoded(vx855_encode_pll(config)); +} + static inline u32 get_pll_internal_frequency(u32 ref_freq, struct pll_config pll) { @@ -1474,21 +1538,21 @@ static struct pll_config get_pll_config(struct pll_limit *limits, int size, return best; } -static u32 viafb_get_clk_value(int clk) +static struct pll_config get_best_pll_config(int clk) { - u32 value = 0; + struct pll_config config; switch (viaparinfo->chip_info->gfx_chip_name) { case UNICHROME_CLE266: case UNICHROME_K400: - value = cle266_encode_pll(get_pll_config(cle266_pll_limits, - ARRAY_SIZE(cle266_pll_limits), clk)); + config = get_pll_config(cle266_pll_limits, + ARRAY_SIZE(cle266_pll_limits), clk); break; case UNICHROME_K800: case UNICHROME_PM800: case UNICHROME_CN700: - value = k800_encode_pll(get_pll_config(k800_pll_limits, - ARRAY_SIZE(k800_pll_limits), clk)); + config = get_pll_config(k800_pll_limits, + ARRAY_SIZE(k800_pll_limits), clk); break; case UNICHROME_CX700: case UNICHROME_CN750: @@ -1496,38 +1560,31 @@ static u32 viafb_get_clk_value(int clk) case UNICHROME_P4M890: case UNICHROME_P4M900: case UNICHROME_VX800: - value = k800_encode_pll(get_pll_config(cx700_pll_limits, - ARRAY_SIZE(cx700_pll_limits), clk)); + config = get_pll_config(cx700_pll_limits, + ARRAY_SIZE(cx700_pll_limits), clk); break; case UNICHROME_VX855: case UNICHROME_VX900: - value = vx855_encode_pll(get_pll_config(vx855_pll_limits, - ARRAY_SIZE(vx855_pll_limits), clk)); + config = get_pll_config(vx855_pll_limits, + ARRAY_SIZE(vx855_pll_limits), clk); break; } - return value; + return config; } /* Set VCLK*/ void viafb_set_vclock(u32 clk, int set_iga) { - u32 value = viafb_get_clk_value(clk); - - DEBUG_MSG(KERN_INFO "PLL=0x%x", value); - - /* H.W. Reset : ON */ - viafb_write_reg_mask(CR17, VIACR, 0x00, BIT7); + struct pll_config config = get_best_pll_config(clk); if (set_iga == IGA1) { /* Change D,N FOR VCLK */ switch (viaparinfo->chip_info->gfx_chip_name) { case UNICHROME_CLE266: case UNICHROME_K400: - via_write_reg(VIASR, SR46, (value & 0x00FF)); - via_write_reg(VIASR, SR47, (value & 0xFF00) >> 8); + cle266_set_primary_pll(config); break; - case UNICHROME_K800: case UNICHROME_PM800: case UNICHROME_CN700: @@ -1537,11 +1594,11 @@ void viafb_set_vclock(u32 clk, int set_iga) case UNICHROME_P4M890: case UNICHROME_P4M900: case UNICHROME_VX800: + k800_set_primary_pll(config); + break; case UNICHROME_VX855: case UNICHROME_VX900: - via_write_reg(VIASR, SR44, (value & 0x0000FF)); - via_write_reg(VIASR, SR45, (value & 0x00FF00) >> 8); - via_write_reg(VIASR, SR46, (value & 0xFF0000) >> 16); + vx855_set_primary_pll(config); break; } } @@ -1551,10 +1608,8 @@ void viafb_set_vclock(u32 clk, int set_iga) switch (viaparinfo->chip_info->gfx_chip_name) { case UNICHROME_CLE266: case UNICHROME_K400: - via_write_reg(VIASR, SR44, (value & 0x00FF)); - via_write_reg(VIASR, SR45, (value & 0xFF00) >> 8); + cle266_set_secondary_pll(config); break; - case UNICHROME_K800: case UNICHROME_PM800: case UNICHROME_CN700: @@ -1564,29 +1619,15 @@ void viafb_set_vclock(u32 clk, int set_iga) case UNICHROME_P4M890: case UNICHROME_P4M900: case UNICHROME_VX800: + k800_set_secondary_pll(config); + break; case UNICHROME_VX855: case UNICHROME_VX900: - via_write_reg(VIASR, SR4A, (value & 0x0000FF)); - via_write_reg(VIASR, SR4B, (value & 0x00FF00) >> 8); - via_write_reg(VIASR, SR4C, (value & 0xFF0000) >> 16); + vx855_set_secondary_pll(config); break; } } - /* H.W. Reset : OFF */ - viafb_write_reg_mask(CR17, VIACR, 0x80, BIT7); - - /* Reset PLL */ - if (set_iga == IGA1) { - viafb_write_reg_mask(SR40, VIASR, 0x02, BIT1); - viafb_write_reg_mask(SR40, VIASR, 0x00, BIT1); - } - - if (set_iga == IGA2) { - viafb_write_reg_mask(SR40, VIASR, 0x04, BIT2); - viafb_write_reg_mask(SR40, VIASR, 0x00, BIT2); - } - /* Fire! */ via_write_misc_reg_mask(0x0C, 0x0C); /* select external clock */ } -- cgit v0.10.2 From 6c1093af5833d4c69634711d9453287ab9e0cb77 Mon Sep 17 00:00:00 2001 From: Florian Tobias Schandinat Date: Wed, 23 Mar 2011 21:04:01 +0000 Subject: viafb: add clock source selection and PLL power management support This patch adds some support for clock source selection as well as PLL power management. The code is unused at the moment but was successfully tested as far as possible. The implementation is according to the documentation for VX700, VX800, VX855, VX900. Probably the source selection works like this starting with K800 and the power managemennt at least since VX700. (guessed based on the initialization in viamode.c) Signed-off-by: Florian Tobias Schandinat diff --git a/drivers/video/via/hw.c b/drivers/video/via/hw.c index bd28e13..b38d3b4 100644 --- a/drivers/video/via/hw.c +++ b/drivers/video/via/hw.c @@ -1409,6 +1409,42 @@ void viafb_load_FIFO_reg(int set_iga, int hor_active, int ver_active) } +static void set_primary_pll_state(u8 state) +{ + u8 value; + + switch (state) { + case VIA_STATE_ON: + value = 0x20; + break; + case VIA_STATE_OFF: + value = 0x00; + break; + default: + return; + } + + via_write_reg_mask(VIASR, 0x2D, value, 0x30); +} + +static void set_secondary_pll_state(u8 state) +{ + u8 value; + + switch (state) { + case VIA_STATE_ON: + value = 0x08; + break; + case VIA_STATE_OFF: + value = 0x00; + break; + default: + return; + } + + via_write_reg_mask(VIASR, 0x2D, value, 0x08); +} + static u32 cle266_encode_pll(struct pll_config pll) { return (pll.multiplier << 8) @@ -1494,6 +1530,58 @@ static void vx855_set_secondary_pll(struct pll_config config) k800_set_secondary_pll_encoded(vx855_encode_pll(config)); } +enum via_clksrc { + VIA_CLKSRC_X1 = 0, + VIA_CLKSRC_TVX1, + VIA_CLKSRC_TVPLL, + VIA_CLKSRC_DVP1TVCLKR, + VIA_CLKSRC_CAP0, + VIA_CLKSRC_CAP1, +}; + +static inline u8 set_clock_source_common(enum via_clksrc source, bool use_pll) +{ + u8 data = 0; + + switch (source) { + case VIA_CLKSRC_X1: + data = 0x00; + break; + case VIA_CLKSRC_TVX1: + data = 0x02; + break; + case VIA_CLKSRC_TVPLL: + data = 0x04; /* 0x06 should be the same */ + break; + case VIA_CLKSRC_DVP1TVCLKR: + data = 0x0A; + break; + case VIA_CLKSRC_CAP0: + data = 0xC; + break; + case VIA_CLKSRC_CAP1: + data = 0x0E; + break; + } + + if (!use_pll) + data |= 1; + + return data; +} + +static void set_primary_clock_source(enum via_clksrc source, bool use_pll) +{ + u8 data = set_clock_source_common(source, use_pll) << 4; + via_write_reg_mask(VIACR, 0x6C, data, 0xF0); +} + +static void set_secondary_clock_source(enum via_clksrc source, bool use_pll) +{ + u8 data = set_clock_source_common(source, use_pll); + via_write_reg_mask(VIACR, 0x6C, data, 0x0F); +} + static inline u32 get_pll_internal_frequency(u32 ref_freq, struct pll_config pll) { -- cgit v0.10.2 From c5593d26aea3aba2a7703a0b5d74b4ea8b726889 Mon Sep 17 00:00:00 2001 From: Florian Tobias Schandinat Date: Thu, 24 Mar 2011 02:03:42 +0000 Subject: viafb: add primary/secondary clock on/off switches This patch adds functions to enable/disable the display clocks. It also fixes a tiny bug that slipped in with a previous commit but could not yet have caused any problems. Signed-off-by: Florian Tobias Schandinat diff --git a/drivers/video/via/hw.c b/drivers/video/via/hw.c index b38d3b4..712348d 100644 --- a/drivers/video/via/hw.c +++ b/drivers/video/via/hw.c @@ -1409,6 +1409,42 @@ void viafb_load_FIFO_reg(int set_iga, int hor_active, int ver_active) } +static void set_primary_clock_state(u8 state) +{ + u8 value; + + switch (state) { + case VIA_STATE_ON: + value = 0x20; + break; + case VIA_STATE_OFF: + value = 0x00; + break; + default: + return; + } + + via_write_reg_mask(VIASR, 0x1B, value, 0x30); +} + +static void set_secondary_clock_state(u8 state) +{ + u8 value; + + switch (state) { + case VIA_STATE_ON: + value = 0x80; + break; + case VIA_STATE_OFF: + value = 0x00; + break; + default: + return; + } + + via_write_reg_mask(VIASR, 0x1B, value, 0xC0); +} + static void set_primary_pll_state(u8 state) { u8 value; @@ -1442,7 +1478,7 @@ static void set_secondary_pll_state(u8 state) return; } - via_write_reg_mask(VIASR, 0x2D, value, 0x08); + via_write_reg_mask(VIASR, 0x2D, value, 0x0C); } static u32 cle266_encode_pll(struct pll_config pll) -- cgit v0.10.2 From 9f1f1bfd8d7e579f07dbe56d6f93bd594da43b3d Mon Sep 17 00:00:00 2001 From: Rakib Mullick Date: Wed, 23 Mar 2011 21:31:40 +0600 Subject: x86, mpparse: Remove unnecessary variable 'ret' isn't used by check_slot(), gets initialized but has no real use, so remove it. Signed-off-by: Rakib Mullick LKML-Reference: Signed-off-by: Ingo Molnar diff --git a/arch/x86/kernel/mpparse.c b/arch/x86/kernel/mpparse.c index 6f789a8..ef32d4c 100644 --- a/arch/x86/kernel/mpparse.c +++ b/arch/x86/kernel/mpparse.c @@ -722,14 +722,12 @@ inline void __init check_irq_src(struct mpc_intsrc *m, int *nr_m_spare) {} static int check_slot(unsigned long mpc_new_phys, unsigned long mpc_new_length, int count) { - int ret = 0; - if (!mpc_new_phys || count <= mpc_new_length) { WARN(1, "update_mptable: No spare slots (length: %x)\n", count); return -1; } - return ret; + return 0; } static int __init replace_intsrc_all(struct mpc_table *mpc, -- cgit v0.10.2 From 2c536f84c19c73ab1e3411bf1596ff85c4a23783 Mon Sep 17 00:00:00 2001 From: Florian Tobias Schandinat Date: Thu, 24 Mar 2011 13:30:09 +0000 Subject: viafb: split clock and PLL code to an extra file This patch is a huge move operation with some rename and introduces an interface to still use the functions. This should be a step in the right direction to reuse the code whenever possible but cleanly separate code that differs on different platform and keeping the complexity as low as possible. pll_config was renamed to via_pll_config to keep the naming scheme. Signed-off-by: Florian Tobias Schandinat diff --git a/drivers/video/via/Makefile b/drivers/video/via/Makefile index 96f01ee..5108136 100644 --- a/drivers/video/via/Makefile +++ b/drivers/video/via/Makefile @@ -6,4 +6,4 @@ obj-$(CONFIG_FB_VIA) += viafb.o viafb-y :=viafbdev.o hw.o via_i2c.o dvi.o lcd.o ioctl.o accel.o \ via_utility.o vt1636.o global.o tblDPASetting.o viamode.o \ - via-core.o via-gpio.o via_modesetting.o + via-core.o via-gpio.o via_modesetting.o via_clock.o diff --git a/drivers/video/via/hw.c b/drivers/video/via/hw.c index 712348d..f1eff0b 100644 --- a/drivers/video/via/hw.c +++ b/drivers/video/via/hw.c @@ -21,6 +21,7 @@ #include #include "global.h" +#include "via_clock.h" static struct pll_limit cle266_pll_limits[] = { {19, 19, 4, 0}, @@ -484,6 +485,9 @@ static struct via_device_mapping device_mapping[] = { {VIA_LVDS2, "LVDS2"} }; +/* structure with function pointers to support clock control */ +static struct via_clock clock; + static void load_fix_bit_crtc_reg(void); static void __devinit init_gfx_chip_info(int chip_type); static void __devinit init_tmds_chip_info(void); @@ -1409,230 +1413,10 @@ void viafb_load_FIFO_reg(int set_iga, int hor_active, int ver_active) } -static void set_primary_clock_state(u8 state) -{ - u8 value; - - switch (state) { - case VIA_STATE_ON: - value = 0x20; - break; - case VIA_STATE_OFF: - value = 0x00; - break; - default: - return; - } - - via_write_reg_mask(VIASR, 0x1B, value, 0x30); -} - -static void set_secondary_clock_state(u8 state) -{ - u8 value; - - switch (state) { - case VIA_STATE_ON: - value = 0x80; - break; - case VIA_STATE_OFF: - value = 0x00; - break; - default: - return; - } - - via_write_reg_mask(VIASR, 0x1B, value, 0xC0); -} - -static void set_primary_pll_state(u8 state) -{ - u8 value; - - switch (state) { - case VIA_STATE_ON: - value = 0x20; - break; - case VIA_STATE_OFF: - value = 0x00; - break; - default: - return; - } - - via_write_reg_mask(VIASR, 0x2D, value, 0x30); -} - -static void set_secondary_pll_state(u8 state) -{ - u8 value; - - switch (state) { - case VIA_STATE_ON: - value = 0x08; - break; - case VIA_STATE_OFF: - value = 0x00; - break; - default: - return; - } - - via_write_reg_mask(VIASR, 0x2D, value, 0x0C); -} - -static u32 cle266_encode_pll(struct pll_config pll) -{ - return (pll.multiplier << 8) - | (pll.rshift << 6) - | pll.divisor; -} - -static u32 k800_encode_pll(struct pll_config pll) -{ - return ((pll.divisor - 2) << 16) - | (pll.rshift << 10) - | (pll.multiplier - 2); -} - -static u32 vx855_encode_pll(struct pll_config pll) -{ - return (pll.divisor << 16) - | (pll.rshift << 10) - | pll.multiplier; -} - -static inline void cle266_set_primary_pll_encoded(u32 data) -{ - via_write_reg_mask(VIASR, 0x40, 0x02, 0x02); /* enable reset */ - via_write_reg(VIASR, 0x46, data & 0xFF); - via_write_reg(VIASR, 0x47, (data >> 8) & 0xFF); - via_write_reg_mask(VIASR, 0x40, 0x00, 0x02); /* disable reset */ -} - -static inline void k800_set_primary_pll_encoded(u32 data) -{ - via_write_reg_mask(VIASR, 0x40, 0x02, 0x02); /* enable reset */ - via_write_reg(VIASR, 0x44, data & 0xFF); - via_write_reg(VIASR, 0x45, (data >> 8) & 0xFF); - via_write_reg(VIASR, 0x46, (data >> 16) & 0xFF); - via_write_reg_mask(VIASR, 0x40, 0x00, 0x02); /* disable reset */ -} - -static inline void cle266_set_secondary_pll_encoded(u32 data) -{ - via_write_reg_mask(VIASR, 0x40, 0x04, 0x04); /* enable reset */ - via_write_reg(VIASR, 0x44, data & 0xFF); - via_write_reg(VIASR, 0x45, (data >> 8) & 0xFF); - via_write_reg_mask(VIASR, 0x40, 0x00, 0x04); /* disable reset */ -} - -static inline void k800_set_secondary_pll_encoded(u32 data) -{ - via_write_reg_mask(VIASR, 0x40, 0x04, 0x04); /* enable reset */ - via_write_reg(VIASR, 0x4A, data & 0xFF); - via_write_reg(VIASR, 0x4B, (data >> 8) & 0xFF); - via_write_reg(VIASR, 0x4C, (data >> 16) & 0xFF); - via_write_reg_mask(VIASR, 0x40, 0x00, 0x04); /* disable reset */ -} - -static void cle266_set_primary_pll(struct pll_config config) -{ - cle266_set_primary_pll_encoded(cle266_encode_pll(config)); -} - -static void k800_set_primary_pll(struct pll_config config) -{ - k800_set_primary_pll_encoded(k800_encode_pll(config)); -} - -static void vx855_set_primary_pll(struct pll_config config) -{ - k800_set_primary_pll_encoded(vx855_encode_pll(config)); -} - -static void cle266_set_secondary_pll(struct pll_config config) -{ - cle266_set_secondary_pll_encoded(cle266_encode_pll(config)); -} - -static void k800_set_secondary_pll(struct pll_config config) -{ - k800_set_secondary_pll_encoded(k800_encode_pll(config)); -} - -static void vx855_set_secondary_pll(struct pll_config config) -{ - k800_set_secondary_pll_encoded(vx855_encode_pll(config)); -} - -enum via_clksrc { - VIA_CLKSRC_X1 = 0, - VIA_CLKSRC_TVX1, - VIA_CLKSRC_TVPLL, - VIA_CLKSRC_DVP1TVCLKR, - VIA_CLKSRC_CAP0, - VIA_CLKSRC_CAP1, -}; - -static inline u8 set_clock_source_common(enum via_clksrc source, bool use_pll) -{ - u8 data = 0; - - switch (source) { - case VIA_CLKSRC_X1: - data = 0x00; - break; - case VIA_CLKSRC_TVX1: - data = 0x02; - break; - case VIA_CLKSRC_TVPLL: - data = 0x04; /* 0x06 should be the same */ - break; - case VIA_CLKSRC_DVP1TVCLKR: - data = 0x0A; - break; - case VIA_CLKSRC_CAP0: - data = 0xC; - break; - case VIA_CLKSRC_CAP1: - data = 0x0E; - break; - } - - if (!use_pll) - data |= 1; - - return data; -} - -static void set_primary_clock_source(enum via_clksrc source, bool use_pll) -{ - u8 data = set_clock_source_common(source, use_pll) << 4; - via_write_reg_mask(VIACR, 0x6C, data, 0xF0); -} - -static void set_secondary_clock_source(enum via_clksrc source, bool use_pll) -{ - u8 data = set_clock_source_common(source, use_pll); - via_write_reg_mask(VIACR, 0x6C, data, 0x0F); -} - -static inline u32 get_pll_internal_frequency(u32 ref_freq, - struct pll_config pll) -{ - return ref_freq / pll.divisor * pll.multiplier; -} - -static inline u32 get_pll_output_frequency(u32 ref_freq, struct pll_config pll) -{ - return get_pll_internal_frequency(ref_freq, pll)>>pll.rshift; -} - -static struct pll_config get_pll_config(struct pll_limit *limits, int size, +static struct via_pll_config get_pll_config(struct pll_limit *limits, int size, int clk) { - struct pll_config cur, up, down, best = {0, 1, 0}; + struct via_pll_config cur, up, down, best = {0, 1, 0}; const u32 f0 = 14318180; /* X1 frequency */ int i, f; @@ -1662,9 +1446,9 @@ static struct pll_config get_pll_config(struct pll_limit *limits, int size, return best; } -static struct pll_config get_best_pll_config(int clk) +static struct via_pll_config get_best_pll_config(int clk) { - struct pll_config config; + struct via_pll_config config; switch (viaparinfo->chip_info->gfx_chip_name) { case UNICHROME_CLE266: @@ -1700,57 +1484,12 @@ static struct pll_config get_best_pll_config(int clk) /* Set VCLK*/ void viafb_set_vclock(u32 clk, int set_iga) { - struct pll_config config = get_best_pll_config(clk); + struct via_pll_config config = get_best_pll_config(clk); - if (set_iga == IGA1) { - /* Change D,N FOR VCLK */ - switch (viaparinfo->chip_info->gfx_chip_name) { - case UNICHROME_CLE266: - case UNICHROME_K400: - cle266_set_primary_pll(config); - break; - case UNICHROME_K800: - case UNICHROME_PM800: - case UNICHROME_CN700: - case UNICHROME_CX700: - case UNICHROME_CN750: - case UNICHROME_K8M890: - case UNICHROME_P4M890: - case UNICHROME_P4M900: - case UNICHROME_VX800: - k800_set_primary_pll(config); - break; - case UNICHROME_VX855: - case UNICHROME_VX900: - vx855_set_primary_pll(config); - break; - } - } - - if (set_iga == IGA2) { - /* Change D,N FOR LCK */ - switch (viaparinfo->chip_info->gfx_chip_name) { - case UNICHROME_CLE266: - case UNICHROME_K400: - cle266_set_secondary_pll(config); - break; - case UNICHROME_K800: - case UNICHROME_PM800: - case UNICHROME_CN700: - case UNICHROME_CX700: - case UNICHROME_CN750: - case UNICHROME_K8M890: - case UNICHROME_P4M890: - case UNICHROME_P4M900: - case UNICHROME_VX800: - k800_set_secondary_pll(config); - break; - case UNICHROME_VX855: - case UNICHROME_VX900: - vx855_set_secondary_pll(config); - break; - } - } + if (set_iga == IGA1) + clock.set_primary_pll(config); + if (set_iga == IGA2) + clock.set_secondary_pll(config); /* Fire! */ via_write_misc_reg_mask(0x0C, 0x0C); /* select external clock */ @@ -2059,6 +1798,7 @@ void viafb_fill_crtc_timing(struct crt_mode_table *crt_table, void __devinit viafb_init_chip_info(int chip_type) { + via_clock_init(&clock, chip_type); init_gfx_chip_info(chip_type); init_tmds_chip_info(); init_lvds_chip_info(); diff --git a/drivers/video/via/hw.h b/drivers/video/via/hw.h index 2cdce9b..7e9f51a 100644 --- a/drivers/video/via/hw.h +++ b/drivers/video/via/hw.h @@ -732,12 +732,6 @@ struct _lcd_scaling_factor { struct _lcd_ver_scaling_factor lcd_ver_scaling_factor; }; -struct pll_config { - u16 multiplier; - u8 divisor; - u8 rshift; -}; - struct pll_limit { u16 multiplier_min; u16 multiplier_max; diff --git a/drivers/video/via/via_clock.c b/drivers/video/via/via_clock.c new file mode 100644 index 0000000..29afe4c --- /dev/null +++ b/drivers/video/via/via_clock.c @@ -0,0 +1,280 @@ +/* + * Copyright 1998-2008 VIA Technologies, Inc. All Rights Reserved. + * Copyright 2001-2008 S3 Graphics, Inc. All Rights Reserved. + * Copyright 2011 Florian Tobias Schandinat + * + * 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, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTIES OR REPRESENTATIONS; without even + * the implied warranty of MERCHANTABILITY or FITNESS FOR + * A PARTICULAR PURPOSE.See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ +/* + * clock and PLL management functions + */ + +#include +#include +#include "via_clock.h" +#include "global.h" +#include "debug.h" + +static inline u32 cle266_encode_pll(struct via_pll_config pll) +{ + return (pll.multiplier << 8) + | (pll.rshift << 6) + | pll.divisor; +} + +static inline u32 k800_encode_pll(struct via_pll_config pll) +{ + return ((pll.divisor - 2) << 16) + | (pll.rshift << 10) + | (pll.multiplier - 2); +} + +static inline u32 vx855_encode_pll(struct via_pll_config pll) +{ + return (pll.divisor << 16) + | (pll.rshift << 10) + | pll.multiplier; +} + +static inline void cle266_set_primary_pll_encoded(u32 data) +{ + via_write_reg_mask(VIASR, 0x40, 0x02, 0x02); /* enable reset */ + via_write_reg(VIASR, 0x46, data & 0xFF); + via_write_reg(VIASR, 0x47, (data >> 8) & 0xFF); + via_write_reg_mask(VIASR, 0x40, 0x00, 0x02); /* disable reset */ +} + +static inline void k800_set_primary_pll_encoded(u32 data) +{ + via_write_reg_mask(VIASR, 0x40, 0x02, 0x02); /* enable reset */ + via_write_reg(VIASR, 0x44, data & 0xFF); + via_write_reg(VIASR, 0x45, (data >> 8) & 0xFF); + via_write_reg(VIASR, 0x46, (data >> 16) & 0xFF); + via_write_reg_mask(VIASR, 0x40, 0x00, 0x02); /* disable reset */ +} + +static inline void cle266_set_secondary_pll_encoded(u32 data) +{ + via_write_reg_mask(VIASR, 0x40, 0x04, 0x04); /* enable reset */ + via_write_reg(VIASR, 0x44, data & 0xFF); + via_write_reg(VIASR, 0x45, (data >> 8) & 0xFF); + via_write_reg_mask(VIASR, 0x40, 0x00, 0x04); /* disable reset */ +} + +static inline void k800_set_secondary_pll_encoded(u32 data) +{ + via_write_reg_mask(VIASR, 0x40, 0x04, 0x04); /* enable reset */ + via_write_reg(VIASR, 0x4A, data & 0xFF); + via_write_reg(VIASR, 0x4B, (data >> 8) & 0xFF); + via_write_reg(VIASR, 0x4C, (data >> 16) & 0xFF); + via_write_reg_mask(VIASR, 0x40, 0x00, 0x04); /* disable reset */ +} + +static void cle266_set_primary_pll(struct via_pll_config config) +{ + cle266_set_primary_pll_encoded(cle266_encode_pll(config)); +} + +static void k800_set_primary_pll(struct via_pll_config config) +{ + k800_set_primary_pll_encoded(k800_encode_pll(config)); +} + +static void vx855_set_primary_pll(struct via_pll_config config) +{ + k800_set_primary_pll_encoded(vx855_encode_pll(config)); +} + +static void cle266_set_secondary_pll(struct via_pll_config config) +{ + cle266_set_secondary_pll_encoded(cle266_encode_pll(config)); +} + +static void k800_set_secondary_pll(struct via_pll_config config) +{ + k800_set_secondary_pll_encoded(k800_encode_pll(config)); +} + +static void vx855_set_secondary_pll(struct via_pll_config config) +{ + k800_set_secondary_pll_encoded(vx855_encode_pll(config)); +} + +static void set_primary_pll_state(u8 state) +{ + u8 value; + + switch (state) { + case VIA_STATE_ON: + value = 0x20; + break; + case VIA_STATE_OFF: + value = 0x00; + break; + default: + return; + } + + via_write_reg_mask(VIASR, 0x2D, value, 0x30); +} + +static void set_secondary_pll_state(u8 state) +{ + u8 value; + + switch (state) { + case VIA_STATE_ON: + value = 0x08; + break; + case VIA_STATE_OFF: + value = 0x00; + break; + default: + return; + } + + via_write_reg_mask(VIASR, 0x2D, value, 0x0C); +} + +static void set_primary_clock_state(u8 state) +{ + u8 value; + + switch (state) { + case VIA_STATE_ON: + value = 0x20; + break; + case VIA_STATE_OFF: + value = 0x00; + break; + default: + return; + } + + via_write_reg_mask(VIASR, 0x1B, value, 0x30); +} + +static void set_secondary_clock_state(u8 state) +{ + u8 value; + + switch (state) { + case VIA_STATE_ON: + value = 0x80; + break; + case VIA_STATE_OFF: + value = 0x00; + break; + default: + return; + } + + via_write_reg_mask(VIASR, 0x1B, value, 0xC0); +} + +static inline u8 set_clock_source_common(enum via_clksrc source, bool use_pll) +{ + u8 data = 0; + + switch (source) { + case VIA_CLKSRC_X1: + data = 0x00; + break; + case VIA_CLKSRC_TVX1: + data = 0x02; + break; + case VIA_CLKSRC_TVPLL: + data = 0x04; /* 0x06 should be the same */ + break; + case VIA_CLKSRC_DVP1TVCLKR: + data = 0x0A; + break; + case VIA_CLKSRC_CAP0: + data = 0xC; + break; + case VIA_CLKSRC_CAP1: + data = 0x0E; + break; + } + + if (!use_pll) + data |= 1; + + return data; +} + +static void set_primary_clock_source(enum via_clksrc source, bool use_pll) +{ + u8 data = set_clock_source_common(source, use_pll) << 4; + via_write_reg_mask(VIACR, 0x6C, data, 0xF0); +} + +static void set_secondary_clock_source(enum via_clksrc source, bool use_pll) +{ + u8 data = set_clock_source_common(source, use_pll); + via_write_reg_mask(VIACR, 0x6C, data, 0x0F); +} + +void via_clock_init(struct via_clock *clock, int gfx_chip) +{ + switch (gfx_chip) { + case UNICHROME_CLE266: + case UNICHROME_K400: + clock->set_primary_clock_state = NULL; + clock->set_primary_clock_source = NULL; + clock->set_primary_pll_state = NULL; + clock->set_primary_pll = cle266_set_primary_pll; + + clock->set_secondary_clock_state = NULL; + clock->set_secondary_clock_source = NULL; + clock->set_secondary_pll_state = NULL; + clock->set_secondary_pll = cle266_set_secondary_pll; + break; + case UNICHROME_K800: + case UNICHROME_PM800: + case UNICHROME_CN700: + case UNICHROME_CX700: + case UNICHROME_CN750: + case UNICHROME_K8M890: + case UNICHROME_P4M890: + case UNICHROME_P4M900: + case UNICHROME_VX800: + clock->set_primary_clock_state = set_primary_clock_state; + clock->set_primary_clock_source = set_primary_clock_source; + clock->set_primary_pll_state = set_primary_pll_state; + clock->set_primary_pll = k800_set_primary_pll; + + clock->set_secondary_clock_state = set_secondary_clock_state; + clock->set_secondary_clock_source = set_secondary_clock_source; + clock->set_secondary_pll_state = set_secondary_pll_state; + clock->set_secondary_pll = k800_set_secondary_pll; + break; + case UNICHROME_VX855: + case UNICHROME_VX900: + clock->set_primary_clock_state = set_primary_clock_state; + clock->set_primary_clock_source = set_primary_clock_source; + clock->set_primary_pll_state = set_primary_pll_state; + clock->set_primary_pll = vx855_set_primary_pll; + + clock->set_secondary_clock_state = set_secondary_clock_state; + clock->set_secondary_clock_source = set_secondary_clock_source; + clock->set_secondary_pll_state = set_secondary_pll_state; + clock->set_secondary_pll = vx855_set_secondary_pll; + break; + + } +} diff --git a/drivers/video/via/via_clock.h b/drivers/video/via/via_clock.h new file mode 100644 index 0000000..f213a7a --- /dev/null +++ b/drivers/video/via/via_clock.h @@ -0,0 +1,73 @@ +/* + * Copyright 1998-2008 VIA Technologies, Inc. All Rights Reserved. + * Copyright 2001-2008 S3 Graphics, Inc. All Rights Reserved. + * Copyright 2011 Florian Tobias Schandinat + * + * 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, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTIES OR REPRESENTATIONS; without even + * the implied warranty of MERCHANTABILITY or FITNESS FOR + * A PARTICULAR PURPOSE.See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ +/* + * clock and PLL management functions + */ + +#ifndef __VIA_CLOCK_H__ +#define __VIA_CLOCK_H__ + +#include + +enum via_clksrc { + VIA_CLKSRC_X1 = 0, + VIA_CLKSRC_TVX1, + VIA_CLKSRC_TVPLL, + VIA_CLKSRC_DVP1TVCLKR, + VIA_CLKSRC_CAP0, + VIA_CLKSRC_CAP1, +}; + +struct via_pll_config { + u16 multiplier; + u8 divisor; + u8 rshift; +}; + +struct via_clock { + void (*set_primary_clock_state)(u8 state); + void (*set_primary_clock_source)(enum via_clksrc src, bool use_pll); + void (*set_primary_pll_state)(u8 state); + void (*set_primary_pll)(struct via_pll_config config); + + void (*set_secondary_clock_state)(u8 state); + void (*set_secondary_clock_source)(enum via_clksrc src, bool use_pll); + void (*set_secondary_pll_state)(u8 state); + void (*set_secondary_pll)(struct via_pll_config config); +}; + + +static inline u32 get_pll_internal_frequency(u32 ref_freq, + struct via_pll_config pll) +{ + return ref_freq / pll.divisor * pll.multiplier; +} + +static inline u32 get_pll_output_frequency(u32 ref_freq, + struct via_pll_config pll) +{ + return get_pll_internal_frequency(ref_freq, pll) >> pll.rshift; +} + +void via_clock_init(struct via_clock *clock, int gfx_chip); + +#endif /* __VIA_CLOCK_H__ */ -- cgit v0.10.2 From b692a63af8b63a7a7e84702a713d0072e336b326 Mon Sep 17 00:00:00 2001 From: Florian Tobias Schandinat Date: Thu, 24 Mar 2011 14:25:51 +0000 Subject: viafb: add VIA slapping capability This patch introduces dummy functions to execute when we don't know what we should do (due to missing documentation). They do nothing but print a nice message in the log explaining the situation. To trigger this message initial power management support is activated which might save a bit energy by disabling PLL and clock if no device is configured to use them. Note: The message is only shown for the oldest IGPs CLE266 and K400 as for the other platforms there are reasonable assumptions how it does (hopefully) work. Signed-off-by: Florian Tobias Schandinat diff --git a/drivers/video/via/hw.c b/drivers/video/via/hw.c index f1eff0b..df84251 100644 --- a/drivers/video/via/hw.c +++ b/drivers/video/via/hw.c @@ -2289,6 +2289,25 @@ int viafb_setmode(struct VideoModeTable *vmode_tbl, int video_bpp, get_sync(viafbinfo1)); } + clock.set_primary_clock_source(VIA_CLKSRC_X1, true); + clock.set_secondary_clock_source(VIA_CLKSRC_X1, true); + + if (viaparinfo->shared->iga1_devices) { + clock.set_primary_pll_state(VIA_STATE_ON); + clock.set_primary_clock_state(VIA_STATE_ON); + } else { + clock.set_primary_pll_state(VIA_STATE_OFF); + clock.set_primary_clock_state(VIA_STATE_OFF); + } + + if (viaparinfo->shared->iga2_devices) { + clock.set_secondary_pll_state(VIA_STATE_ON); + clock.set_secondary_clock_state(VIA_STATE_ON); + } else { + clock.set_secondary_pll_state(VIA_STATE_OFF); + clock.set_secondary_clock_state(VIA_STATE_OFF); + } + via_set_state(devices, VIA_STATE_ON); device_screen_on(); return 1; diff --git a/drivers/video/via/via_clock.c b/drivers/video/via/via_clock.c index 29afe4c..a829a24 100644 --- a/drivers/video/via/via_clock.c +++ b/drivers/video/via/via_clock.c @@ -29,6 +29,9 @@ #include "global.h" #include "debug.h" +const char *via_slap = "Please slap VIA Technologies to motivate them " + "releasing full documentation for your platform!\n"; + static inline u32 cle266_encode_pll(struct via_pll_config pll) { return (pll.multiplier << 8) @@ -229,19 +232,34 @@ static void set_secondary_clock_source(enum via_clksrc source, bool use_pll) via_write_reg_mask(VIACR, 0x6C, data, 0x0F); } +static void dummy_set_clock_state(u8 state) +{ + printk(KERN_INFO "Using undocumented set clock state.\n%s", via_slap); +} + +static void dummy_set_clock_source(enum via_clksrc source, bool use_pll) +{ + printk(KERN_INFO "Using undocumented set clock source.\n%s", via_slap); +} + +static void dummy_set_pll_state(u8 state) +{ + printk(KERN_INFO "Using undocumented set PLL state.\n%s", via_slap); +} + void via_clock_init(struct via_clock *clock, int gfx_chip) { switch (gfx_chip) { case UNICHROME_CLE266: case UNICHROME_K400: - clock->set_primary_clock_state = NULL; - clock->set_primary_clock_source = NULL; - clock->set_primary_pll_state = NULL; + clock->set_primary_clock_state = dummy_set_clock_state; + clock->set_primary_clock_source = dummy_set_clock_source; + clock->set_primary_pll_state = dummy_set_pll_state; clock->set_primary_pll = cle266_set_primary_pll; - clock->set_secondary_clock_state = NULL; - clock->set_secondary_clock_source = NULL; - clock->set_secondary_pll_state = NULL; + clock->set_secondary_clock_state = dummy_set_clock_state; + clock->set_secondary_clock_source = dummy_set_clock_source; + clock->set_secondary_pll_state = dummy_set_pll_state; clock->set_secondary_pll = cle266_set_secondary_pll; break; case UNICHROME_K800: -- cgit v0.10.2 From efa3144e7cb2a7a58961e5b881b1b9ef73f39cd5 Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Tue, 22 Feb 2011 16:43:05 -0800 Subject: iwlegacy: MAINTAINERS Add iwlegacy driver to MAINTAINERS file and mark as 'Orphan' Signed-off-by: Wey-Yi Guy diff --git a/MAINTAINERS b/MAINTAINERS index 95482e9..12698b3 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -3322,6 +3322,16 @@ F: Documentation/wimax/README.i2400m F: drivers/net/wimax/i2400m/ F: include/linux/wimax/i2400m.h +INTEL PRO/WIRELESS 3945ABG/BG NETWORK CONNECTION SUPPORT +L: linux-wireless@vger.kernel.org +S: Orphan +F: drivers/net/wireless/iwlegacy/ + +INTEL WIRELESS WIFI 4965AGN NETWORK CONNECTION SUPPORT +L: linux-wireless@vger.kernel.org +S: Orphan +F: drivers/net/wireless/iwlegacy/ + INTEL WIRELESS WIFI LINK (iwlwifi) M: Wey-Yi Guy M: Intel Linux Wireless -- cgit v0.10.2 From d103e3448a3ecb9f81babd1f6d7f5a678e213c82 Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Thu, 10 Mar 2011 03:17:16 -0800 Subject: iwlagn: use 6030 configuration for 6035 series 6035 series of devices should use the same uCode as 6030 series, change it. Signed-off-by: Wey-Yi Guy diff --git a/drivers/net/wireless/iwlwifi/iwl-2000.c b/drivers/net/wireless/iwlwifi/iwl-2000.c index d7b6126..b1dbe93 100644 --- a/drivers/net/wireless/iwlwifi/iwl-2000.c +++ b/drivers/net/wireless/iwlwifi/iwl-2000.c @@ -471,37 +471,6 @@ struct iwl_cfg iwl2030_2bg_cfg = { IWL_DEVICE_2030, }; -#define IWL_DEVICE_6035 \ - .fw_name_pre = IWL2030_FW_PRE, \ - .ucode_api_max = IWL2030_UCODE_API_MAX, \ - .ucode_api_min = IWL2030_UCODE_API_MIN, \ - .eeprom_ver = EEPROM_6035_EEPROM_VERSION, \ - .eeprom_calib_ver = EEPROM_6035_TX_POWER_VERSION, \ - .ops = &iwl2030_ops, \ - .mod_params = &iwlagn_mod_params, \ - .base_params = &iwl2030_base_params, \ - .bt_params = &iwl2030_bt_params, \ - .need_dc_calib = true, \ - .need_temp_offset_calib = true, \ - .led_mode = IWL_LED_RF_STATE, \ - .adv_pm = true \ - -struct iwl_cfg iwl6035_2agn_cfg = { - .name = "2000 Series 2x2 AGN/BT", - IWL_DEVICE_6035, - .ht_params = &iwl2000_ht_params, -}; - -struct iwl_cfg iwl6035_2abg_cfg = { - .name = "2000 Series 2x2 ABG/BT", - IWL_DEVICE_6035, -}; - -struct iwl_cfg iwl6035_2bg_cfg = { - .name = "2000 Series 2x2 BG/BT", - IWL_DEVICE_6035, -}; - #define IWL_DEVICE_200 \ .fw_name_pre = IWL200_FW_PRE, \ .ucode_api_max = IWL200_UCODE_API_MAX, \ diff --git a/drivers/net/wireless/iwlwifi/iwl-6000.c b/drivers/net/wireless/iwlwifi/iwl-6000.c index a745b01..40e0226 100644 --- a/drivers/net/wireless/iwlwifi/iwl-6000.c +++ b/drivers/net/wireless/iwlwifi/iwl-6000.c @@ -613,6 +613,22 @@ struct iwl_cfg iwl6030_2bg_cfg = { IWL_DEVICE_6030, }; +struct iwl_cfg iwl6035_2agn_cfg = { + .name = "6035 Series 2x2 AGN/BT", + IWL_DEVICE_6030, + .ht_params = &iwl6000_ht_params, +}; + +struct iwl_cfg iwl6035_2abg_cfg = { + .name = "6035 Series 2x2 ABG/BT", + IWL_DEVICE_6030, +}; + +struct iwl_cfg iwl6035_2bg_cfg = { + .name = "6035 Series 2x2 BG/BT", + IWL_DEVICE_6030, +}; + struct iwl_cfg iwl1030_bgn_cfg = { .name = "Intel(R) Centrino(R) Wireless-N 1030 BGN", IWL_DEVICE_6030, -- cgit v0.10.2 From 7ffef13d7a24654292c4641450f2794224b9eb5d Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 15 Mar 2011 04:59:10 -0700 Subject: iwlagn: clean up TX aggregation code Since the driver split, there's no need for function pointers any more for aggregation queue setup and teardown as all devices now share the same code. Simplify this. Signed-off-by: Johannes Berg Signed-off-by: Wey-Yi Guy diff --git a/drivers/net/wireless/iwlwifi/iwl-1000.c b/drivers/net/wireless/iwlwifi/iwl-1000.c index e8e1c2d..9631d8f 100644 --- a/drivers/net/wireless/iwlwifi/iwl-1000.c +++ b/drivers/net/wireless/iwlwifi/iwl-1000.c @@ -179,8 +179,6 @@ static struct iwl_lib_ops iwl1000_lib = { .txq_update_byte_cnt_tbl = iwlagn_txq_update_byte_cnt_tbl, .txq_inval_byte_cnt_tbl = iwlagn_txq_inval_byte_cnt_tbl, .txq_set_sched = iwlagn_txq_set_sched, - .txq_agg_enable = iwlagn_txq_agg_enable, - .txq_agg_disable = iwlagn_txq_agg_disable, .txq_attach_buf_to_tfd = iwl_hw_txq_attach_buf_to_tfd, .txq_free_tfd = iwl_hw_txq_free_tfd, .txq_init = iwl_hw_tx_queue_init, diff --git a/drivers/net/wireless/iwlwifi/iwl-2000.c b/drivers/net/wireless/iwlwifi/iwl-2000.c index b1dbe93..55274a1 100644 --- a/drivers/net/wireless/iwlwifi/iwl-2000.c +++ b/drivers/net/wireless/iwlwifi/iwl-2000.c @@ -259,8 +259,6 @@ static struct iwl_lib_ops iwl2000_lib = { .txq_update_byte_cnt_tbl = iwlagn_txq_update_byte_cnt_tbl, .txq_inval_byte_cnt_tbl = iwlagn_txq_inval_byte_cnt_tbl, .txq_set_sched = iwlagn_txq_set_sched, - .txq_agg_enable = iwlagn_txq_agg_enable, - .txq_agg_disable = iwlagn_txq_agg_disable, .txq_attach_buf_to_tfd = iwl_hw_txq_attach_buf_to_tfd, .txq_free_tfd = iwl_hw_txq_free_tfd, .txq_init = iwl_hw_tx_queue_init, diff --git a/drivers/net/wireless/iwlwifi/iwl-5000.c b/drivers/net/wireless/iwlwifi/iwl-5000.c index 90e727b..4064490 100644 --- a/drivers/net/wireless/iwlwifi/iwl-5000.c +++ b/drivers/net/wireless/iwlwifi/iwl-5000.c @@ -348,8 +348,6 @@ static struct iwl_lib_ops iwl5000_lib = { .txq_update_byte_cnt_tbl = iwlagn_txq_update_byte_cnt_tbl, .txq_inval_byte_cnt_tbl = iwlagn_txq_inval_byte_cnt_tbl, .txq_set_sched = iwlagn_txq_set_sched, - .txq_agg_enable = iwlagn_txq_agg_enable, - .txq_agg_disable = iwlagn_txq_agg_disable, .txq_attach_buf_to_tfd = iwl_hw_txq_attach_buf_to_tfd, .txq_free_tfd = iwl_hw_txq_free_tfd, .txq_init = iwl_hw_tx_queue_init, @@ -416,8 +414,6 @@ static struct iwl_lib_ops iwl5150_lib = { .txq_update_byte_cnt_tbl = iwlagn_txq_update_byte_cnt_tbl, .txq_inval_byte_cnt_tbl = iwlagn_txq_inval_byte_cnt_tbl, .txq_set_sched = iwlagn_txq_set_sched, - .txq_agg_enable = iwlagn_txq_agg_enable, - .txq_agg_disable = iwlagn_txq_agg_disable, .txq_attach_buf_to_tfd = iwl_hw_txq_attach_buf_to_tfd, .txq_free_tfd = iwl_hw_txq_free_tfd, .txq_init = iwl_hw_tx_queue_init, diff --git a/drivers/net/wireless/iwlwifi/iwl-6000.c b/drivers/net/wireless/iwlwifi/iwl-6000.c index 40e0226..7ecfbbc 100644 --- a/drivers/net/wireless/iwlwifi/iwl-6000.c +++ b/drivers/net/wireless/iwlwifi/iwl-6000.c @@ -288,8 +288,6 @@ static struct iwl_lib_ops iwl6000_lib = { .txq_update_byte_cnt_tbl = iwlagn_txq_update_byte_cnt_tbl, .txq_inval_byte_cnt_tbl = iwlagn_txq_inval_byte_cnt_tbl, .txq_set_sched = iwlagn_txq_set_sched, - .txq_agg_enable = iwlagn_txq_agg_enable, - .txq_agg_disable = iwlagn_txq_agg_disable, .txq_attach_buf_to_tfd = iwl_hw_txq_attach_buf_to_tfd, .txq_free_tfd = iwl_hw_txq_free_tfd, .txq_init = iwl_hw_tx_queue_init, @@ -357,8 +355,6 @@ static struct iwl_lib_ops iwl6030_lib = { .txq_update_byte_cnt_tbl = iwlagn_txq_update_byte_cnt_tbl, .txq_inval_byte_cnt_tbl = iwlagn_txq_inval_byte_cnt_tbl, .txq_set_sched = iwlagn_txq_set_sched, - .txq_agg_enable = iwlagn_txq_agg_enable, - .txq_agg_disable = iwlagn_txq_agg_disable, .txq_attach_buf_to_tfd = iwl_hw_txq_attach_buf_to_tfd, .txq_free_tfd = iwl_hw_txq_free_tfd, .txq_init = iwl_hw_tx_queue_init, diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-tx.c b/drivers/net/wireless/iwlwifi/iwl-agn-tx.c index a709d05..23e5667 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-tx.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-tx.c @@ -222,8 +222,8 @@ void iwlagn_tx_queue_set_status(struct iwl_priv *priv, scd_retry ? "BA" : "AC/CMD", txq_id, tx_fifo_id); } -int iwlagn_txq_agg_enable(struct iwl_priv *priv, int txq_id, - int tx_fifo, int sta_id, int tid, u16 ssn_idx) +static int iwlagn_txq_agg_enable(struct iwl_priv *priv, int txq_id, + int tx_fifo, int sta_id, int tid, u16 ssn_idx) { unsigned long flags; u16 ra_tid; @@ -288,8 +288,8 @@ int iwlagn_txq_agg_enable(struct iwl_priv *priv, int txq_id, return 0; } -int iwlagn_txq_agg_disable(struct iwl_priv *priv, u16 txq_id, - u16 ssn_idx, u8 tx_fifo) +static int iwlagn_txq_agg_disable(struct iwl_priv *priv, u16 txq_id, + u16 ssn_idx, u8 tx_fifo) { if ((IWLAGN_FIRST_AMPDU_QUEUE > txq_id) || (IWLAGN_FIRST_AMPDU_QUEUE + @@ -1037,8 +1037,7 @@ int iwlagn_tx_agg_start(struct iwl_priv *priv, struct ieee80211_vif *vif, iwl_set_swq_id(&priv->txq[txq_id], get_ac_from_tid(tid), txq_id); spin_unlock_irqrestore(&priv->sta_lock, flags); - ret = priv->cfg->ops->lib->txq_agg_enable(priv, txq_id, tx_fifo, - sta_id, tid, *ssn); + ret = iwlagn_txq_agg_enable(priv, txq_id, tx_fifo, sta_id, tid, *ssn); if (ret) return ret; @@ -1125,8 +1124,7 @@ int iwlagn_tx_agg_stop(struct iwl_priv *priv, struct ieee80211_vif *vif, * to deactivate the uCode queue, just return "success" to allow * mac80211 to clean up it own data. */ - priv->cfg->ops->lib->txq_agg_disable(priv, txq_id, ssn, - tx_fifo_id); + iwlagn_txq_agg_disable(priv, txq_id, ssn, tx_fifo_id); spin_unlock_irqrestore(&priv->lock, flags); ieee80211_stop_tx_ba_cb_irqsafe(vif, sta->addr, tid); @@ -1155,8 +1153,7 @@ int iwlagn_txq_check_empty(struct iwl_priv *priv, u16 ssn = SEQ_TO_SN(tid_data->seq_number); int tx_fifo = get_fifo_from_tid(ctx, tid); IWL_DEBUG_HT(priv, "HW queue empty: continue DELBA flow\n"); - priv->cfg->ops->lib->txq_agg_disable(priv, txq_id, - ssn, tx_fifo); + iwlagn_txq_agg_disable(priv, txq_id, ssn, tx_fifo); tid_data->agg.state = IWL_AGG_OFF; ieee80211_stop_tx_ba_cb_irqsafe(ctx->vif, addr, tid); } diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.h b/drivers/net/wireless/iwlwifi/iwl-agn.h index 20f8e41..8d918ea 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.h +++ b/drivers/net/wireless/iwlwifi/iwl-agn.h @@ -133,10 +133,6 @@ void iwlagn_txq_update_byte_cnt_tbl(struct iwl_priv *priv, u16 byte_cnt); void iwlagn_txq_inval_byte_cnt_tbl(struct iwl_priv *priv, struct iwl_tx_queue *txq); -int iwlagn_txq_agg_enable(struct iwl_priv *priv, int txq_id, - int tx_fifo, int sta_id, int tid, u16 ssn_idx); -int iwlagn_txq_agg_disable(struct iwl_priv *priv, u16 txq_id, - u16 ssn_idx, u8 tx_fifo); void iwlagn_txq_set_sched(struct iwl_priv *priv, u32 mask); void iwl_free_tfds_in_queue(struct iwl_priv *priv, int sta_id, int tid, int freed); diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h index b316d83..1f4f6dd 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.h +++ b/drivers/net/wireless/iwlwifi/iwl-core.h @@ -171,11 +171,6 @@ struct iwl_lib_ops { struct iwl_tx_queue *txq); int (*txq_init)(struct iwl_priv *priv, struct iwl_tx_queue *txq); - /* aggregations */ - int (*txq_agg_enable)(struct iwl_priv *priv, int txq_id, int tx_fifo, - int sta_id, int tid, u16 ssn_idx); - int (*txq_agg_disable)(struct iwl_priv *priv, u16 txq_id, u16 ssn_idx, - u8 tx_fifo); /* setup Rx handler */ void (*rx_handler_setup)(struct iwl_priv *priv); /* setup deferred work */ -- cgit v0.10.2 From c8823ec1337017e23b99fb0814e2f3d62537f811 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 15 Mar 2011 11:33:03 -0700 Subject: iwlagn: fix aggregation queue scheduler setup iwlagn's hardware scheduler needs to be set up with the right aggregation frame limit and buffer sizes. To achieve this, we need to move the hardware queue setup to when the session becomes operational. Tested-by: Daniel Halperin Signed-off-by: Johannes Berg Signed-off-by: Wey-Yi Guy diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-tx.c b/drivers/net/wireless/iwlwifi/iwl-agn-tx.c index 23e5667..fb63a03 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-tx.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-tx.c @@ -222,13 +222,8 @@ void iwlagn_tx_queue_set_status(struct iwl_priv *priv, scd_retry ? "BA" : "AC/CMD", txq_id, tx_fifo_id); } -static int iwlagn_txq_agg_enable(struct iwl_priv *priv, int txq_id, - int tx_fifo, int sta_id, int tid, u16 ssn_idx) +static int iwlagn_txq_agg_enable(struct iwl_priv *priv, int txq_id, int sta_id, int tid) { - unsigned long flags; - u16 ra_tid; - int ret; - if ((IWLAGN_FIRST_AMPDU_QUEUE > txq_id) || (IWLAGN_FIRST_AMPDU_QUEUE + priv->cfg->base_params->num_of_ampdu_queues <= txq_id)) { @@ -240,12 +235,33 @@ static int iwlagn_txq_agg_enable(struct iwl_priv *priv, int txq_id, return -EINVAL; } - ra_tid = BUILD_RAxTID(sta_id, tid); - /* Modify device's station table to Tx this TID */ - ret = iwl_sta_tx_modify_enable_tid(priv, sta_id, tid); - if (ret) - return ret; + return iwl_sta_tx_modify_enable_tid(priv, sta_id, tid); +} + +void iwlagn_txq_agg_queue_setup(struct iwl_priv *priv, + struct ieee80211_sta *sta, + int tid, int frame_limit) +{ + int sta_id, tx_fifo, txq_id, ssn_idx; + u16 ra_tid; + unsigned long flags; + struct iwl_tid_data *tid_data; + + sta_id = iwl_sta_id(sta); + if (WARN_ON(sta_id == IWL_INVALID_STATION)) + return; + if (WARN_ON(tid >= MAX_TID_COUNT)) + return; + + spin_lock_irqsave(&priv->sta_lock, flags); + tid_data = &priv->stations[sta_id].tid[tid]; + ssn_idx = SEQ_TO_SN(tid_data->seq_number); + txq_id = tid_data->agg.txq_id; + tx_fifo = tid_data->agg.tx_fifo; + spin_unlock_irqrestore(&priv->sta_lock, flags); + + ra_tid = BUILD_RAxTID(sta_id, tid); spin_lock_irqsave(&priv->lock, flags); @@ -271,10 +287,10 @@ static int iwlagn_txq_agg_enable(struct iwl_priv *priv, int txq_id, iwl_write_targ_mem(priv, priv->scd_base_addr + IWLAGN_SCD_CONTEXT_QUEUE_OFFSET(txq_id) + sizeof(u32), - ((SCD_WIN_SIZE << + ((frame_limit << IWLAGN_SCD_QUEUE_CTX_REG2_WIN_SIZE_POS) & IWLAGN_SCD_QUEUE_CTX_REG2_WIN_SIZE_MSK) | - ((SCD_FRAME_LIMIT << + ((frame_limit << IWLAGN_SCD_QUEUE_CTX_REG2_FRAME_LIMIT_POS) & IWLAGN_SCD_QUEUE_CTX_REG2_FRAME_LIMIT_MSK)); @@ -284,8 +300,6 @@ static int iwlagn_txq_agg_enable(struct iwl_priv *priv, int txq_id, iwlagn_tx_queue_set_status(priv, &priv->txq[txq_id], tx_fifo, 1); spin_unlock_irqrestore(&priv->lock, flags); - - return 0; } static int iwlagn_txq_agg_disable(struct iwl_priv *priv, u16 txq_id, @@ -1034,10 +1048,11 @@ int iwlagn_tx_agg_start(struct iwl_priv *priv, struct ieee80211_vif *vif, tid_data = &priv->stations[sta_id].tid[tid]; *ssn = SEQ_TO_SN(tid_data->seq_number); tid_data->agg.txq_id = txq_id; + tid_data->agg.tx_fifo = tx_fifo; iwl_set_swq_id(&priv->txq[txq_id], get_ac_from_tid(tid), txq_id); spin_unlock_irqrestore(&priv->sta_lock, flags); - ret = iwlagn_txq_agg_enable(priv, txq_id, tx_fifo, sta_id, tid, *ssn); + ret = iwlagn_txq_agg_enable(priv, txq_id, sta_id, tid); if (ret) return ret; diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index b57fbbf..8fdd174 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -3345,6 +3345,10 @@ int iwlagn_mac_ampdu_action(struct ieee80211_hw *hw, } break; case IEEE80211_AMPDU_TX_OPERATIONAL: + buf_size = min_t(int, buf_size, LINK_QUAL_AGG_FRAME_LIMIT_DEF); + + iwlagn_txq_agg_queue_setup(priv, sta, tid, buf_size); + /* * If the limit is 0, then it wasn't initialised yet, * use the default. We can do that since we take the diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.h b/drivers/net/wireless/iwlwifi/iwl-agn.h index 8d918ea..4f7c9ce 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.h +++ b/drivers/net/wireless/iwlwifi/iwl-agn.h @@ -202,6 +202,9 @@ int iwlagn_tx_agg_start(struct iwl_priv *priv, struct ieee80211_vif *vif, struct ieee80211_sta *sta, u16 tid, u16 *ssn); int iwlagn_tx_agg_stop(struct iwl_priv *priv, struct ieee80211_vif *vif, struct ieee80211_sta *sta, u16 tid); +void iwlagn_txq_agg_queue_setup(struct iwl_priv *priv, + struct ieee80211_sta *sta, + int tid, int frame_limit); int iwlagn_txq_check_empty(struct iwl_priv *priv, int sta_id, u8 tid, int txq_id); void iwlagn_rx_reply_compressed_ba(struct iwl_priv *priv, diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index 68b953f..a5d438d 100644 --- a/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h @@ -416,6 +416,7 @@ struct iwl_ht_agg { #define IWL_EMPTYING_HW_QUEUE_ADDBA 2 #define IWL_EMPTYING_HW_QUEUE_DELBA 3 u8 state; + u8 tx_fifo; }; -- cgit v0.10.2 From 374920cb0512f5938fdf1f5af4f9afa7502dd0f9 Mon Sep 17 00:00:00 2001 From: Daniel Halperin Date: Wed, 16 Mar 2011 19:16:36 -0700 Subject: iwlwifi: limit number of attempts for highest HT rate When filling out its rate scale table, iwlwifi repeats the first HT rate IWL_HT_NUMBER_TRY times. The hardware scheduler will stop using aggregation for any frame that fails LINK_QUAL_AGG_DISABLE_START_DEF times. Currently, both these constants equal 3. If iwlwifi probes a faster rate than the link supports, all frames in a (potentially tens of frames large) batch will fail IWL_HT_NUMBER_TRY times. Because this happens to be as large as LINK_QUAL_AGG_DISABLE_START_DEF, all frames will then be sent individually. This leads to a short, but performance-degrading window where the legacy stop-and-wait MAC takes over. Bounding the initial rate by (LINK_QUAL_AGG_DISABLE_START_DEF-1) attempts makes the third try use a lower rate and hence more be likely to succeed. This somewhat mitigates the above described behavior. Signed-off-by: Daniel Halperin Signed-off-by: Wey-Yi Guy diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c index d03b473..63b58ec 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c @@ -2912,7 +2912,8 @@ static void rs_fill_link_cmd(struct iwl_priv *priv, ant_toggle_cnt = 1; repeat_rate = IWL_NUMBER_TRY; } else { - repeat_rate = IWL_HT_NUMBER_TRY; + repeat_rate = min(IWL_HT_NUMBER_TRY, + LINK_QUAL_AGG_DISABLE_START_DEF - 1); } lq_cmd->general_params.mimo_delimiter = -- cgit v0.10.2 From d0eb633431ec922f8f9b2040f46d9b42a4cec193 Mon Sep 17 00:00:00 2001 From: Daniel Halperin Date: Wed, 16 Mar 2011 17:17:36 -0700 Subject: iwlwifi: cleanup and bugfix tx aggregation code Since the driver split, there's no need for no_agg_framecnt_info since all devices have this set to false. Secondly, the compressed block ack handling code was broken. Fix this. (1) A shift less than zero simply implies that the buffer wrapped, this is expected. Remove the incorrect comment. (2) The (agg->frame_count > (64-sh)) condition can happen if the last frame is dropped. E.g., if I send 7 frames and the 6th is received but the 7th is lost, the other side may only shift the window 6, not 7 frames since the last bit is a 0. This is perfectly fine behavior and doesn't invalidate the feedback. (3) Store the feedback from a Compressed BA in the first newly received frame, rather than the start of the window. This way it will get processed by the rate selection code. Feedback stored in a non-received frame is likely to get overwritten by the retransmission. This is based on the approach taken by minstrel_ht. Signed-off-by: Daniel Halperin Signed-off-by: Wey-Yi Guy diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-tx.c b/drivers/net/wireless/iwlwifi/iwl-agn-tx.c index fb63a03..cb8eacd 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-tx.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-tx.c @@ -1263,11 +1263,11 @@ static int iwlagn_tx_status_reply_compressed_ba(struct iwl_priv *priv, struct iwl_compressed_ba_resp *ba_resp) { - int i, sh, ack; + int sh; u16 seq_ctl = le16_to_cpu(ba_resp->seq_ctl); u16 scd_flow = le16_to_cpu(ba_resp->scd_flow); - int successes = 0; struct ieee80211_tx_info *info; + u64 bitmap, sent_bitmap; if (unlikely(!agg->wait_for_ba)) { if (unlikely(ba_resp->bitmap)) @@ -1281,70 +1281,42 @@ static int iwlagn_tx_status_reply_compressed_ba(struct iwl_priv *priv, /* Calculate shift to align block-ack bits with our Tx window bits */ sh = agg->start_idx - SEQ_TO_INDEX(seq_ctl >> 4); - if (sh < 0) /* tbw something is wrong with indices */ + if (sh < 0) sh += 0x100; - if (agg->frame_count > (64 - sh)) { - IWL_DEBUG_TX_REPLY(priv, "more frames than bitmap size"); - return -1; - } - if (!priv->cfg->base_params->no_agg_framecnt_info && ba_resp->txed) { + /* + * Check for success or failure according to the + * transmitted bitmap and block-ack bitmap + */ + bitmap = le64_to_cpu(ba_resp->bitmap) >> sh; + sent_bitmap = bitmap & agg->bitmap; + + /* Sanity check values reported by uCode */ + if (ba_resp->txed_2_done > ba_resp->txed) { + IWL_DEBUG_TX_REPLY(priv, + "bogus sent(%d) and ack(%d) count\n", + ba_resp->txed, ba_resp->txed_2_done); /* - * sent and ack information provided by uCode - * use it instead of figure out ourself + * set txed_2_done = txed, + * so it won't impact rate scale */ - if (ba_resp->txed_2_done > ba_resp->txed) { - IWL_DEBUG_TX_REPLY(priv, - "bogus sent(%d) and ack(%d) count\n", - ba_resp->txed, ba_resp->txed_2_done); - /* - * set txed_2_done = txed, - * so it won't impact rate scale - */ - ba_resp->txed = ba_resp->txed_2_done; - } - IWL_DEBUG_HT(priv, "agg frames sent:%d, acked:%d\n", - ba_resp->txed, ba_resp->txed_2_done); - } else { - u64 bitmap, sent_bitmap; - - /* don't use 64-bit values for now */ - bitmap = le64_to_cpu(ba_resp->bitmap) >> sh; - - /* check for success or failure according to the - * transmitted bitmap and block-ack bitmap */ - sent_bitmap = bitmap & agg->bitmap; - - /* For each frame attempted in aggregation, - * update driver's record of tx frame's status. */ - i = 0; - while (sent_bitmap) { - ack = sent_bitmap & 1ULL; - successes += ack; - IWL_DEBUG_TX_REPLY(priv, "%s ON i=%d idx=%d raw=%d\n", - ack ? "ACK" : "NACK", i, - (agg->start_idx + i) & 0xff, - agg->start_idx + i); - sent_bitmap >>= 1; - ++i; - } + ba_resp->txed = ba_resp->txed_2_done; + } + IWL_DEBUG_HT(priv, "agg frames sent:%d, acked:%d\n", + ba_resp->txed, ba_resp->txed_2_done); - IWL_DEBUG_TX_REPLY(priv, "Bitmap %llx\n", - (unsigned long long)bitmap); + /* Find the first ACKed frame to store the TX status */ + while (sent_bitmap && !(sent_bitmap & 1)) { + agg->start_idx = (agg->start_idx + 1) & 0xff; + sent_bitmap >>= 1; } info = IEEE80211_SKB_CB(priv->txq[scd_flow].txb[agg->start_idx].skb); memset(&info->status, 0, sizeof(info->status)); info->flags |= IEEE80211_TX_STAT_ACK; info->flags |= IEEE80211_TX_STAT_AMPDU; - if (!priv->cfg->base_params->no_agg_framecnt_info && ba_resp->txed) { - info->status.ampdu_ack_len = ba_resp->txed_2_done; - info->status.ampdu_len = ba_resp->txed; - - } else { - info->status.ampdu_ack_len = successes; - info->status.ampdu_len = agg->frame_count; - } + info->status.ampdu_ack_len = ba_resp->txed_2_done; + info->status.ampdu_len = ba_resp->txed; iwlagn_hwrate_to_tx_control(priv, agg->rate_n_flags, info); return 0; diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h index 1f4f6dd..3e680af 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.h +++ b/drivers/net/wireless/iwlwifi/iwl-core.h @@ -281,8 +281,6 @@ struct iwl_mod_params { * @chain_noise_calib_by_driver: driver has the capability to perform * chain noise calibration operation * @shadow_reg_enable: HW shadhow register bit - * @no_agg_framecnt_info: uCode do not provide aggregation frame count - * information */ struct iwl_base_params { int eeprom_size; @@ -312,7 +310,6 @@ struct iwl_base_params { const bool sensitivity_calib_by_driver; const bool chain_noise_calib_by_driver; const bool shadow_reg_enable; - const bool no_agg_framecnt_info; }; /* * @advanced_bt_coexist: support advanced bt coexist -- cgit v0.10.2 From 2520546aecc969372080448a2422b39eedb2a528 Mon Sep 17 00:00:00 2001 From: Daniel Halperin Date: Fri, 18 Mar 2011 18:48:55 -0700 Subject: iwlwifi: add RATE_MCS_RATE_MSK Throughout the code we use rate_n_flags & 0xff to extract the lower byte of the rate_n_flags u32 that contains the information about the rate. Add a #define and remove the use of the magic number. Signed-off-by: Daniel Halperin Signed-off-by: Wey-Yi Guy diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c index 63b58ec..e394e49 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c @@ -115,13 +115,18 @@ const struct iwl_rate_info iwl_rates[IWL_RATE_COUNT] = { /* FIXME:RS: ^^ should be INV (legacy) */ }; +static inline u8 rs_extract_rate(u32 rate_n_flags) +{ + return (u8)(rate_n_flags & RATE_MCS_RATE_MSK); +} + static int iwl_hwrate_to_plcp_idx(u32 rate_n_flags) { int idx = 0; /* HT rate format */ if (rate_n_flags & RATE_MCS_HT_MSK) { - idx = (rate_n_flags & 0xff); + idx = rs_extract_rate(rate_n_flags); if (idx >= IWL_RATE_MIMO3_6M_PLCP) idx = idx - IWL_RATE_MIMO3_6M_PLCP; @@ -138,7 +143,8 @@ static int iwl_hwrate_to_plcp_idx(u32 rate_n_flags) /* legacy rate format, search for match in table */ } else { for (idx = 0; idx < ARRAY_SIZE(iwl_rates); idx++) - if (iwl_rates[idx].plcp == (rate_n_flags & 0xFF)) + if (iwl_rates[idx].plcp == + rs_extract_rate(rate_n_flags)) return idx; } @@ -239,11 +245,6 @@ static const struct iwl_rate_mcs_info iwl_rate_mcs[IWL_RATE_COUNT] = { #define MCS_INDEX_PER_STREAM (8) -static inline u8 rs_extract_rate(u32 rate_n_flags) -{ - return (u8)(rate_n_flags & 0xFF); -} - static void rs_rate_scale_clear_window(struct iwl_rate_scale_data *window) { window->data = 0; diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.h b/drivers/net/wireless/iwlwifi/iwl-agn.h index 4f7c9ce..39313ac 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.h +++ b/drivers/net/wireless/iwlwifi/iwl-agn.h @@ -310,7 +310,7 @@ static inline u32 iwl_ant_idx_to_flags(u8 ant_idx) static inline u8 iwl_hw_get_rate(__le32 rate_n_flags) { - return le32_to_cpu(rate_n_flags) & 0xFF; + return le32_to_cpu(rate_n_flags) & RATE_MCS_RATE_MSK; } static inline __le32 iwl_hw_set_rate_n_flags(u8 rate, u32 flags) diff --git a/drivers/net/wireless/iwlwifi/iwl-commands.h b/drivers/net/wireless/iwlwifi/iwl-commands.h index ca42ffa..2883915 100644 --- a/drivers/net/wireless/iwlwifi/iwl-commands.h +++ b/drivers/net/wireless/iwlwifi/iwl-commands.h @@ -324,6 +324,8 @@ struct iwl3945_power_per_rate { #define RATE_MCS_SPATIAL_MSK 0x18 #define RATE_MCS_HT_DUP_POS 5 #define RATE_MCS_HT_DUP_MSK 0x20 +/* Both legacy and HT use bits 7:0 as the CCK/OFDM rate or HT MCS */ +#define RATE_MCS_RATE_MSK 0xff /* Bit 8: (1) HT format, (0) legacy format in bits 7:0 */ #define RATE_MCS_FLAGS_POS 8 -- cgit v0.10.2 From 4263108c2a9028544cf4037fa4e72000ee456c33 Mon Sep 17 00:00:00 2001 From: Daniel Halperin Date: Mon, 21 Mar 2011 15:27:34 -0700 Subject: iwlwifi: set default aggregation frame limit to 63 This gives much better performance at fast 3x3 rates (up to ~160 Mbps). The scheduler will still make most decisions about batch size based on available packets and RX parameters. Signed-off-by: Daniel Halperin Signed-off-by: Wey-Yi Guy diff --git a/drivers/net/wireless/iwlwifi/iwl-commands.h b/drivers/net/wireless/iwlwifi/iwl-commands.h index 2883915..cc21514 100644 --- a/drivers/net/wireless/iwlwifi/iwl-commands.h +++ b/drivers/net/wireless/iwlwifi/iwl-commands.h @@ -2132,7 +2132,7 @@ struct iwl_link_qual_general_params { #define LINK_QUAL_AGG_DISABLE_START_MAX (255) #define LINK_QUAL_AGG_DISABLE_START_MIN (0) -#define LINK_QUAL_AGG_FRAME_LIMIT_DEF (31) +#define LINK_QUAL_AGG_FRAME_LIMIT_DEF (63) #define LINK_QUAL_AGG_FRAME_LIMIT_MAX (63) #define LINK_QUAL_AGG_FRAME_LIMIT_MIN (0) -- cgit v0.10.2 From d6b8061824a03fbe915c6cf5be2b290ae44c4ec4 Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Mon, 21 Mar 2011 16:53:38 -0700 Subject: iwlwifi: remove legacy isr tasklet After driver split, no need for support legacy isr, remove it. Signed-off-by: Wey-Yi Guy diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-ict.c b/drivers/net/wireless/iwlwifi/iwl-agn-ict.c index b5cb3be..47e1fa4 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-ict.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-ict.c @@ -59,8 +59,6 @@ void iwl_free_isr_ict(struct iwl_priv *priv) int iwl_alloc_isr_ict(struct iwl_priv *priv) { - if (priv->cfg->base_params->use_isr_legacy) - return 0; /* allocate shrared data table */ priv->_agn.ict_tbl_vir = dma_alloc_coherent(&priv->pci_dev->dev, diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-lib.c b/drivers/net/wireless/iwlwifi/iwl-agn-lib.c index 2003c1d..8163a0e 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-lib.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-lib.c @@ -652,8 +652,7 @@ int iwlagn_rx_init(struct iwl_priv *priv, struct iwl_rx_queue *rxq) const u32 rfdnlog = RX_QUEUE_SIZE_LOG; /* 256 RBDs */ u32 rb_timeout = 0; /* FIXME: RX_RB_TIMEOUT for all devices? */ - if (!priv->cfg->base_params->use_isr_legacy) - rb_timeout = RX_RB_TIMEOUT; + rb_timeout = RX_RB_TIMEOUT; if (priv->cfg->mod_params->amsdu_size_8K) rb_size = FH_RCSR_RX_CONFIG_REG_VAL_RB_SIZE_8K; diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index 8fdd174..bd980a2 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -845,191 +845,6 @@ static inline void iwl_synchronize_irq(struct iwl_priv *priv) tasklet_kill(&priv->irq_tasklet); } -static void iwl_irq_tasklet_legacy(struct iwl_priv *priv) -{ - u32 inta, handled = 0; - u32 inta_fh; - unsigned long flags; - u32 i; -#ifdef CONFIG_IWLWIFI_DEBUG - u32 inta_mask; -#endif - - spin_lock_irqsave(&priv->lock, flags); - - /* Ack/clear/reset pending uCode interrupts. - * Note: Some bits in CSR_INT are "OR" of bits in CSR_FH_INT_STATUS, - * and will clear only when CSR_FH_INT_STATUS gets cleared. */ - inta = iwl_read32(priv, CSR_INT); - iwl_write32(priv, CSR_INT, inta); - - /* Ack/clear/reset pending flow-handler (DMA) interrupts. - * Any new interrupts that happen after this, either while we're - * in this tasklet, or later, will show up in next ISR/tasklet. */ - inta_fh = iwl_read32(priv, CSR_FH_INT_STATUS); - iwl_write32(priv, CSR_FH_INT_STATUS, inta_fh); - -#ifdef CONFIG_IWLWIFI_DEBUG - if (iwl_get_debug_level(priv) & IWL_DL_ISR) { - /* just for debug */ - inta_mask = iwl_read32(priv, CSR_INT_MASK); - IWL_DEBUG_ISR(priv, "inta 0x%08x, enabled 0x%08x, fh 0x%08x\n", - inta, inta_mask, inta_fh); - } -#endif - - spin_unlock_irqrestore(&priv->lock, flags); - - /* Since CSR_INT and CSR_FH_INT_STATUS reads and clears are not - * atomic, make sure that inta covers all the interrupts that - * we've discovered, even if FH interrupt came in just after - * reading CSR_INT. */ - if (inta_fh & CSR49_FH_INT_RX_MASK) - inta |= CSR_INT_BIT_FH_RX; - if (inta_fh & CSR49_FH_INT_TX_MASK) - inta |= CSR_INT_BIT_FH_TX; - - /* Now service all interrupt bits discovered above. */ - if (inta & CSR_INT_BIT_HW_ERR) { - IWL_ERR(priv, "Hardware error detected. Restarting.\n"); - - /* Tell the device to stop sending interrupts */ - iwl_disable_interrupts(priv); - - priv->isr_stats.hw++; - iwl_irq_handle_error(priv); - - handled |= CSR_INT_BIT_HW_ERR; - - return; - } - -#ifdef CONFIG_IWLWIFI_DEBUG - if (iwl_get_debug_level(priv) & (IWL_DL_ISR)) { - /* NIC fires this, but we don't use it, redundant with WAKEUP */ - if (inta & CSR_INT_BIT_SCD) { - IWL_DEBUG_ISR(priv, "Scheduler finished to transmit " - "the frame/frames.\n"); - priv->isr_stats.sch++; - } - - /* Alive notification via Rx interrupt will do the real work */ - if (inta & CSR_INT_BIT_ALIVE) { - IWL_DEBUG_ISR(priv, "Alive interrupt\n"); - priv->isr_stats.alive++; - } - } -#endif - /* Safely ignore these bits for debug checks below */ - inta &= ~(CSR_INT_BIT_SCD | CSR_INT_BIT_ALIVE); - - /* HW RF KILL switch toggled */ - if (inta & CSR_INT_BIT_RF_KILL) { - int hw_rf_kill = 0; - if (!(iwl_read32(priv, CSR_GP_CNTRL) & - CSR_GP_CNTRL_REG_FLAG_HW_RF_KILL_SW)) - hw_rf_kill = 1; - - IWL_WARN(priv, "RF_KILL bit toggled to %s.\n", - hw_rf_kill ? "disable radio" : "enable radio"); - - priv->isr_stats.rfkill++; - - /* driver only loads ucode once setting the interface up. - * the driver allows loading the ucode even if the radio - * is killed. Hence update the killswitch state here. The - * rfkill handler will care about restarting if needed. - */ - if (!test_bit(STATUS_ALIVE, &priv->status)) { - if (hw_rf_kill) - set_bit(STATUS_RF_KILL_HW, &priv->status); - else - clear_bit(STATUS_RF_KILL_HW, &priv->status); - wiphy_rfkill_set_hw_state(priv->hw->wiphy, hw_rf_kill); - } - - handled |= CSR_INT_BIT_RF_KILL; - } - - /* Chip got too hot and stopped itself */ - if (inta & CSR_INT_BIT_CT_KILL) { - IWL_ERR(priv, "Microcode CT kill error detected.\n"); - priv->isr_stats.ctkill++; - handled |= CSR_INT_BIT_CT_KILL; - } - - /* Error detected by uCode */ - if (inta & CSR_INT_BIT_SW_ERR) { - IWL_ERR(priv, "Microcode SW error detected. " - " Restarting 0x%X.\n", inta); - priv->isr_stats.sw++; - iwl_irq_handle_error(priv); - handled |= CSR_INT_BIT_SW_ERR; - } - - /* - * uCode wakes up after power-down sleep. - * Tell device about any new tx or host commands enqueued, - * and about any Rx buffers made available while asleep. - */ - if (inta & CSR_INT_BIT_WAKEUP) { - IWL_DEBUG_ISR(priv, "Wakeup interrupt\n"); - iwl_rx_queue_update_write_ptr(priv, &priv->rxq); - for (i = 0; i < priv->hw_params.max_txq_num; i++) - iwl_txq_update_write_ptr(priv, &priv->txq[i]); - priv->isr_stats.wakeup++; - handled |= CSR_INT_BIT_WAKEUP; - } - - /* All uCode command responses, including Tx command responses, - * Rx "responses" (frame-received notification), and other - * notifications from uCode come through here*/ - if (inta & (CSR_INT_BIT_FH_RX | CSR_INT_BIT_SW_RX)) { - iwl_rx_handle(priv); - priv->isr_stats.rx++; - handled |= (CSR_INT_BIT_FH_RX | CSR_INT_BIT_SW_RX); - } - - /* This "Tx" DMA channel is used only for loading uCode */ - if (inta & CSR_INT_BIT_FH_TX) { - IWL_DEBUG_ISR(priv, "uCode load interrupt\n"); - priv->isr_stats.tx++; - handled |= CSR_INT_BIT_FH_TX; - /* Wake up uCode load routine, now that load is complete */ - priv->ucode_write_complete = 1; - wake_up_interruptible(&priv->wait_command_queue); - } - - if (inta & ~handled) { - IWL_ERR(priv, "Unhandled INTA bits 0x%08x\n", inta & ~handled); - priv->isr_stats.unhandled++; - } - - if (inta & ~(priv->inta_mask)) { - IWL_WARN(priv, "Disabled INTA bits 0x%08x were pending\n", - inta & ~priv->inta_mask); - IWL_WARN(priv, " with FH_INT = 0x%08x\n", inta_fh); - } - - /* Re-enable all interrupts */ - /* only Re-enable if disabled by irq */ - if (test_bit(STATUS_INT_ENABLED, &priv->status)) - iwl_enable_interrupts(priv); - /* Re-enable RF_KILL if it occurred */ - else if (handled & CSR_INT_BIT_RF_KILL) - iwl_enable_rfkill_int(priv); - -#ifdef CONFIG_IWLWIFI_DEBUG - if (iwl_get_debug_level(priv) & (IWL_DL_ISR)) { - inta = iwl_read32(priv, CSR_INT); - inta_mask = iwl_read32(priv, CSR_INT_MASK); - inta_fh = iwl_read32(priv, CSR_FH_INT_STATUS); - IWL_DEBUG_ISR(priv, "End inta 0x%08x, enabled 0x%08x, fh 0x%08x, " - "flags 0x%08lx\n", inta, inta_mask, inta_fh, flags); - } -#endif -} - /* tasklet for iwlagn interrupt */ static void iwl_irq_tasklet(struct iwl_priv *priv) { @@ -3751,12 +3566,8 @@ static void iwl_setup_deferred_work(struct iwl_priv *priv) priv->watchdog.data = (unsigned long)priv; priv->watchdog.function = iwl_bg_watchdog; - if (!priv->cfg->base_params->use_isr_legacy) - tasklet_init(&priv->irq_tasklet, (void (*)(unsigned long)) - iwl_irq_tasklet, (unsigned long)priv); - else - tasklet_init(&priv->irq_tasklet, (void (*)(unsigned long)) - iwl_irq_tasklet_legacy, (unsigned long)priv); + tasklet_init(&priv->irq_tasklet, (void (*)(unsigned long)) + iwl_irq_tasklet, (unsigned long)priv); } static void iwl_cancel_deferred_work(struct iwl_priv *priv) diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h index 3e680af..3a4e9b4 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.h +++ b/drivers/net/wireless/iwlwifi/iwl-core.h @@ -291,7 +291,6 @@ struct iwl_base_params { bool set_l0s; bool use_bsm; - bool use_isr_legacy; const u16 max_ll_items; const bool shadow_ram_support; u16 led_compensation; -- cgit v0.10.2 From 2a226ab67f2f9c46e534f37f867d3bf3af335d02 Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Tue, 22 Mar 2011 08:05:36 -0700 Subject: iwlagn: remove 3945 only station code After driver split, no more 3945 only station support needed. Signed-off-by: Wey-Yi Guy diff --git a/drivers/net/wireless/iwlwifi/iwl-sta.c b/drivers/net/wireless/iwlwifi/iwl-sta.c index bc90a12..b0dcca0 100644 --- a/drivers/net/wireless/iwlwifi/iwl-sta.c +++ b/drivers/net/wireless/iwlwifi/iwl-sta.c @@ -306,12 +306,6 @@ u8 iwl_prep_station(struct iwl_priv *priv, struct iwl_rxon_context *ctx, */ iwl_set_ht_add_station(priv, sta_id, sta, ctx); - /* 3945 only */ - rate = (priv->band == IEEE80211_BAND_5GHZ) ? - IWL_RATE_6M_PLCP : IWL_RATE_1M_PLCP; - /* Turn on both antennas for the station... */ - station->sta.rate_n_flags = cpu_to_le16(rate | RATE_MCS_ANT_AB_MSK); - return sta_id; } -- cgit v0.10.2 From f7d046f91bd165e747b9a95d089a4168b6f9796a Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Tue, 22 Mar 2011 08:05:37 -0700 Subject: iwlagn: remove reference to 3945 and 4965 After driver split, remove the unused reference to 3945 and 4965 Signed-off-by: Wey-Yi Guy diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index bd980a2..9251c68 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -409,7 +409,7 @@ int iwl_hw_txq_attach_buf_to_tfd(struct iwl_priv *priv, * Tell nic where to find circular buffer of Tx Frame Descriptors for * given Tx queue, and enable the DMA channel used for that queue. * - * 4965 supports up to 16 Tx queues in DRAM, mapped to up to 8 Tx DMA + * supports up to 16 Tx queues in DRAM, mapped to up to 8 Tx DMA * channels supported in hardware. */ int iwl_hw_tx_queue_init(struct iwl_priv *priv, @@ -986,7 +986,7 @@ static void iwl_irq_tasklet(struct iwl_priv *priv) if (inta & (CSR_INT_BIT_FH_RX | CSR_INT_BIT_SW_RX)) { handled |= (CSR_INT_BIT_FH_RX | CSR_INT_BIT_SW_RX); iwl_write32(priv, CSR_FH_INT_STATUS, - CSR49_FH_INT_RX_MASK); + CSR_FH_INT_RX_MASK); } if (inta & CSR_INT_BIT_RX_PERIODIC) { handled |= CSR_INT_BIT_RX_PERIODIC; @@ -1024,7 +1024,7 @@ static void iwl_irq_tasklet(struct iwl_priv *priv) /* This "Tx" DMA channel is used only for loading uCode */ if (inta & CSR_INT_BIT_FH_TX) { - iwl_write32(priv, CSR_FH_INT_STATUS, CSR49_FH_INT_TX_MASK); + iwl_write32(priv, CSR_FH_INT_STATUS, CSR_FH_INT_TX_MASK); IWL_DEBUG_ISR(priv, "uCode load interrupt\n"); priv->isr_stats.tx++; handled |= CSR_INT_BIT_FH_TX; @@ -1259,28 +1259,19 @@ static int iwlagn_load_legacy_firmware(struct iwl_priv *priv, switch (api_ver) { default: - /* - * 4965 doesn't revision the firmware file format - * along with the API version, it always uses v1 - * file format. - */ - if ((priv->hw_rev & CSR_HW_REV_TYPE_MSK) != - CSR_HW_REV_TYPE_4965) { - hdr_size = 28; - if (ucode_raw->size < hdr_size) { - IWL_ERR(priv, "File size too small!\n"); - return -EINVAL; - } - pieces->build = le32_to_cpu(ucode->u.v2.build); - pieces->inst_size = le32_to_cpu(ucode->u.v2.inst_size); - pieces->data_size = le32_to_cpu(ucode->u.v2.data_size); - pieces->init_size = le32_to_cpu(ucode->u.v2.init_size); - pieces->init_data_size = le32_to_cpu(ucode->u.v2.init_data_size); - pieces->boot_size = le32_to_cpu(ucode->u.v2.boot_size); - src = ucode->u.v2.data; - break; + hdr_size = 28; + if (ucode_raw->size < hdr_size) { + IWL_ERR(priv, "File size too small!\n"); + return -EINVAL; } - /* fall through for 4965 */ + pieces->build = le32_to_cpu(ucode->u.v2.build); + pieces->inst_size = le32_to_cpu(ucode->u.v2.inst_size); + pieces->data_size = le32_to_cpu(ucode->u.v2.data_size); + pieces->init_size = le32_to_cpu(ucode->u.v2.init_size); + pieces->init_data_size = le32_to_cpu(ucode->u.v2.init_data_size); + pieces->boot_size = le32_to_cpu(ucode->u.v2.boot_size); + src = ucode->u.v2.data; + break; case 0: case 1: case 2: diff --git a/drivers/net/wireless/iwlwifi/iwl-csr.h b/drivers/net/wireless/iwlwifi/iwl-csr.h index f52bc04..1123319 100644 --- a/drivers/net/wireless/iwlwifi/iwl-csr.h +++ b/drivers/net/wireless/iwlwifi/iwl-csr.h @@ -155,18 +155,10 @@ #define CSR_DBG_LINK_PWR_MGMT_REG (CSR_BASE+0x250) /* Bits for CSR_HW_IF_CONFIG_REG */ -#define CSR49_HW_IF_CONFIG_REG_BIT_4965_R (0x00000010) #define CSR_HW_IF_CONFIG_REG_MSK_BOARD_VER (0x00000C00) #define CSR_HW_IF_CONFIG_REG_BIT_MAC_SI (0x00000100) #define CSR_HW_IF_CONFIG_REG_BIT_RADIO_SI (0x00000200) -#define CSR39_HW_IF_CONFIG_REG_BIT_3945_MB (0x00000100) -#define CSR39_HW_IF_CONFIG_REG_BIT_3945_MM (0x00000200) -#define CSR39_HW_IF_CONFIG_REG_BIT_SKU_MRC (0x00000400) -#define CSR39_HW_IF_CONFIG_REG_BIT_BOARD_TYPE (0x00000800) -#define CSR39_HW_IF_CONFIG_REG_BITS_SILICON_TYPE_A (0x00000000) -#define CSR39_HW_IF_CONFIG_REG_BITS_SILICON_TYPE_B (0x00001000) - #define CSR_HW_IF_CONFIG_REG_BIT_HAP_WAKE_L1A (0x00080000) #define CSR_HW_IF_CONFIG_REG_BIT_EEPROM_OWN_SEM (0x00200000) #define CSR_HW_IF_CONFIG_REG_BIT_NIC_READY (0x00400000) /* PCI_OWN_SEM */ @@ -186,7 +178,7 @@ #define CSR_INT_BIT_SW_ERR (1 << 25) /* uCode error */ #define CSR_INT_BIT_RF_KILL (1 << 7) /* HW RFKILL switch GP_CNTRL[27] toggled */ #define CSR_INT_BIT_CT_KILL (1 << 6) /* Critical temp (chip too hot) rfkill */ -#define CSR_INT_BIT_SW_RX (1 << 3) /* Rx, command responses, 3945 */ +#define CSR_INT_BIT_SW_RX (1 << 3) /* Rx, command responses */ #define CSR_INT_BIT_WAKEUP (1 << 1) /* NIC controller waking up (pwr mgmt) */ #define CSR_INT_BIT_ALIVE (1 << 0) /* uCode interrupts once it initializes */ @@ -202,29 +194,17 @@ /* interrupt flags in FH (flow handler) (PCI busmaster DMA) */ #define CSR_FH_INT_BIT_ERR (1 << 31) /* Error */ #define CSR_FH_INT_BIT_HI_PRIOR (1 << 30) /* High priority Rx, bypass coalescing */ -#define CSR39_FH_INT_BIT_RX_CHNL2 (1 << 18) /* Rx channel 2 (3945 only) */ #define CSR_FH_INT_BIT_RX_CHNL1 (1 << 17) /* Rx channel 1 */ #define CSR_FH_INT_BIT_RX_CHNL0 (1 << 16) /* Rx channel 0 */ -#define CSR39_FH_INT_BIT_TX_CHNL6 (1 << 6) /* Tx channel 6 (3945 only) */ #define CSR_FH_INT_BIT_TX_CHNL1 (1 << 1) /* Tx channel 1 */ #define CSR_FH_INT_BIT_TX_CHNL0 (1 << 0) /* Tx channel 0 */ -#define CSR39_FH_INT_RX_MASK (CSR_FH_INT_BIT_HI_PRIOR | \ - CSR39_FH_INT_BIT_RX_CHNL2 | \ - CSR_FH_INT_BIT_RX_CHNL1 | \ - CSR_FH_INT_BIT_RX_CHNL0) - - -#define CSR39_FH_INT_TX_MASK (CSR39_FH_INT_BIT_TX_CHNL6 | \ - CSR_FH_INT_BIT_TX_CHNL1 | \ - CSR_FH_INT_BIT_TX_CHNL0) - -#define CSR49_FH_INT_RX_MASK (CSR_FH_INT_BIT_HI_PRIOR | \ - CSR_FH_INT_BIT_RX_CHNL1 | \ - CSR_FH_INT_BIT_RX_CHNL0) +#define CSR_FH_INT_RX_MASK (CSR_FH_INT_BIT_HI_PRIOR | \ + CSR_FH_INT_BIT_RX_CHNL1 | \ + CSR_FH_INT_BIT_RX_CHNL0) -#define CSR49_FH_INT_TX_MASK (CSR_FH_INT_BIT_TX_CHNL1 | \ - CSR_FH_INT_BIT_TX_CHNL0) +#define CSR_FH_INT_TX_MASK (CSR_FH_INT_BIT_TX_CHNL1 | \ + CSR_FH_INT_BIT_TX_CHNL0) /* GPIO */ #define CSR_GPIO_IN_BIT_AUX_POWER (0x00000200) @@ -268,7 +248,7 @@ * Indicates MAC (ucode processor, etc.) is powered up and can run. * Internal resources are accessible. * NOTE: This does not indicate that the processor is actually running. - * NOTE: This does not indicate that 4965 or 3945 has completed + * NOTE: This does not indicate that device has completed * init or post-power-down restore of internal SRAM memory. * Use CSR_UCODE_DRV_GP1_BIT_MAC_SLEEP as indication that * SRAM is restored and uCode is in normal operation mode. @@ -291,8 +271,6 @@ /* HW REV */ #define CSR_HW_REV_TYPE_MSK (0x00001F0) -#define CSR_HW_REV_TYPE_3945 (0x00000D0) -#define CSR_HW_REV_TYPE_4965 (0x0000000) #define CSR_HW_REV_TYPE_5300 (0x0000020) #define CSR_HW_REV_TYPE_5350 (0x0000030) #define CSR_HW_REV_TYPE_5100 (0x0000050) @@ -363,7 +341,7 @@ * 0: MAC_SLEEP * uCode sets this when preparing a power-saving power-down. * uCode resets this when power-up is complete and SRAM is sane. - * NOTE: 3945/4965 saves internal SRAM data to host when powering down, + * NOTE: device saves internal SRAM data to host when powering down, * and must restore this data after powering back up. * MAC_SLEEP is the best indication that restore is complete. * Later devices (5xxx/6xxx/1xxx) use non-volatile SRAM, and @@ -394,7 +372,6 @@ #define CSR_LED_REG_TRUN_OFF (0x38) /* ANA_PLL */ -#define CSR39_ANA_PLL_CFG_VAL (0x01000000) #define CSR50_ANA_PLL_CFG_VAL (0x00880300) /* HPET MEM debug */ diff --git a/drivers/net/wireless/iwlwifi/iwl-eeprom.c b/drivers/net/wireless/iwlwifi/iwl-eeprom.c index 833194a..c831a0f 100644 --- a/drivers/net/wireless/iwlwifi/iwl-eeprom.c +++ b/drivers/net/wireless/iwlwifi/iwl-eeprom.c @@ -198,8 +198,6 @@ static int iwlcore_get_nvm_type(struct iwl_priv *priv) case CSR_HW_REV_TYPE_NONE: IWL_ERR(priv, "Unknown hardware type\n"); return -ENOENT; - case CSR_HW_REV_TYPE_3945: - case CSR_HW_REV_TYPE_4965: case CSR_HW_REV_TYPE_5300: case CSR_HW_REV_TYPE_5350: case CSR_HW_REV_TYPE_5100: -- cgit v0.10.2 From 7eaa6a5e964f1ab02d849bda36950c0d30be8ce2 Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Tue, 22 Mar 2011 08:05:38 -0700 Subject: iwlagn: remove deprecated module parameters Number of deprecated module parameters need to be remove for 2.6.40 kernel Signed-off-by: Wey-Yi Guy diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index 9251c68..39a05e3 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -3771,14 +3771,6 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) * 1. Allocating HW data ************************/ - /* Disabling hardware scan means that mac80211 will perform scans - * "the hard way", rather than using device's scan. */ - if (cfg->mod_params->disable_hw_scan) { - dev_printk(KERN_DEBUG, &(pdev->dev), - "sw scan support is deprecated\n"); - iwlagn_hw_ops.hw_scan = NULL; - } - hw = iwl_alloc_all(cfg); if (!hw) { err = -ENOMEM; @@ -4388,43 +4380,21 @@ module_exit(iwl_exit); module_init(iwl_init); #ifdef CONFIG_IWLWIFI_DEBUG -module_param_named(debug50, iwl_debug_level, uint, S_IRUGO); -MODULE_PARM_DESC(debug50, "50XX debug output mask (deprecated)"); module_param_named(debug, iwl_debug_level, uint, S_IRUGO | S_IWUSR); MODULE_PARM_DESC(debug, "debug output mask"); #endif -module_param_named(swcrypto50, iwlagn_mod_params.sw_crypto, bool, S_IRUGO); -MODULE_PARM_DESC(swcrypto50, - "using crypto in software (default 0 [hardware]) (deprecated)"); module_param_named(swcrypto, iwlagn_mod_params.sw_crypto, int, S_IRUGO); MODULE_PARM_DESC(swcrypto, "using crypto in software (default 0 [hardware])"); -module_param_named(queues_num50, - iwlagn_mod_params.num_of_queues, int, S_IRUGO); -MODULE_PARM_DESC(queues_num50, - "number of hw queues in 50xx series (deprecated)"); module_param_named(queues_num, iwlagn_mod_params.num_of_queues, int, S_IRUGO); MODULE_PARM_DESC(queues_num, "number of hw queues."); -module_param_named(11n_disable50, iwlagn_mod_params.disable_11n, int, S_IRUGO); -MODULE_PARM_DESC(11n_disable50, "disable 50XX 11n functionality (deprecated)"); module_param_named(11n_disable, iwlagn_mod_params.disable_11n, int, S_IRUGO); MODULE_PARM_DESC(11n_disable, "disable 11n functionality"); -module_param_named(amsdu_size_8K50, iwlagn_mod_params.amsdu_size_8K, - int, S_IRUGO); -MODULE_PARM_DESC(amsdu_size_8K50, - "enable 8K amsdu size in 50XX series (deprecated)"); module_param_named(amsdu_size_8K, iwlagn_mod_params.amsdu_size_8K, int, S_IRUGO); MODULE_PARM_DESC(amsdu_size_8K, "enable 8K amsdu size"); -module_param_named(fw_restart50, iwlagn_mod_params.restart_fw, int, S_IRUGO); -MODULE_PARM_DESC(fw_restart50, - "restart firmware in case of error (deprecated)"); module_param_named(fw_restart, iwlagn_mod_params.restart_fw, int, S_IRUGO); MODULE_PARM_DESC(fw_restart, "restart firmware in case of error"); -module_param_named( - disable_hw_scan, iwlagn_mod_params.disable_hw_scan, int, S_IRUGO); -MODULE_PARM_DESC(disable_hw_scan, - "disable hardware scanning (default 0) (deprecated)"); module_param_named(ucode_alternative, iwlagn_wanted_ucode_alternative, int, S_IRUGO); diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h index 3a4e9b4..967b4c0 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.h +++ b/drivers/net/wireless/iwlwifi/iwl-core.h @@ -247,7 +247,6 @@ struct iwl_ops { struct iwl_mod_params { int sw_crypto; /* def: 0 = using hardware encryption */ - int disable_hw_scan; /* def: 0 = use h/w scan */ int num_of_queues; /* def: HW dependent */ int disable_11n; /* def: 0 = 11n capabilities enabled */ int amsdu_size_8K; /* def: 1 = enable 8K amsdu size */ -- cgit v0.10.2 From bea02e45874a5d18127b0779740c4fd5b3e7e44a Mon Sep 17 00:00:00 2001 From: Florian Tobias Schandinat Date: Sat, 26 Mar 2011 02:29:18 +0000 Subject: viafb: add engine clock support This patch adds support for enabling and configuring the engine on VIAs IGPs. This is the main clock used for everything but pixel output. Signed-off-by: Florian Tobias Schandinat diff --git a/drivers/video/via/hw.c b/drivers/video/via/hw.c index df84251..e531147 100644 --- a/drivers/video/via/hw.c +++ b/drivers/video/via/hw.c @@ -2289,6 +2289,7 @@ int viafb_setmode(struct VideoModeTable *vmode_tbl, int video_bpp, get_sync(viafbinfo1)); } + clock.set_engine_pll_state(VIA_STATE_ON); clock.set_primary_clock_source(VIA_CLKSRC_X1, true); clock.set_secondary_clock_source(VIA_CLKSRC_X1, true); diff --git a/drivers/video/via/via_clock.c b/drivers/video/via/via_clock.c index a829a24..af8f26b 100644 --- a/drivers/video/via/via_clock.c +++ b/drivers/video/via/via_clock.c @@ -87,6 +87,15 @@ static inline void k800_set_secondary_pll_encoded(u32 data) via_write_reg_mask(VIASR, 0x40, 0x00, 0x04); /* disable reset */ } +static inline void set_engine_pll_encoded(u32 data) +{ + via_write_reg_mask(VIASR, 0x40, 0x01, 0x01); /* enable reset */ + via_write_reg(VIASR, 0x47, data & 0xFF); + via_write_reg(VIASR, 0x48, (data >> 8) & 0xFF); + via_write_reg(VIASR, 0x49, (data >> 16) & 0xFF); + via_write_reg_mask(VIASR, 0x40, 0x00, 0x01); /* disable reset */ +} + static void cle266_set_primary_pll(struct via_pll_config config) { cle266_set_primary_pll_encoded(cle266_encode_pll(config)); @@ -117,6 +126,16 @@ static void vx855_set_secondary_pll(struct via_pll_config config) k800_set_secondary_pll_encoded(vx855_encode_pll(config)); } +static void k800_set_engine_pll(struct via_pll_config config) +{ + set_engine_pll_encoded(k800_encode_pll(config)); +} + +static void vx855_set_engine_pll(struct via_pll_config config) +{ + set_engine_pll_encoded(vx855_encode_pll(config)); +} + static void set_primary_pll_state(u8 state) { u8 value; @@ -153,6 +172,24 @@ static void set_secondary_pll_state(u8 state) via_write_reg_mask(VIASR, 0x2D, value, 0x0C); } +static void set_engine_pll_state(u8 state) +{ + u8 value; + + switch (state) { + case VIA_STATE_ON: + value = 0x02; + break; + case VIA_STATE_OFF: + value = 0x00; + break; + default: + return; + } + + via_write_reg_mask(VIASR, 0x2D, value, 0x03); +} + static void set_primary_clock_state(u8 state) { u8 value; @@ -247,6 +284,11 @@ static void dummy_set_pll_state(u8 state) printk(KERN_INFO "Using undocumented set PLL state.\n%s", via_slap); } +static void dummy_set_pll(struct via_pll_config config) +{ + printk(KERN_INFO "Using undocumented set PLL.\n%s", via_slap); +} + void via_clock_init(struct via_clock *clock, int gfx_chip) { switch (gfx_chip) { @@ -261,6 +303,9 @@ void via_clock_init(struct via_clock *clock, int gfx_chip) clock->set_secondary_clock_source = dummy_set_clock_source; clock->set_secondary_pll_state = dummy_set_pll_state; clock->set_secondary_pll = cle266_set_secondary_pll; + + clock->set_engine_pll_state = dummy_set_pll_state; + clock->set_engine_pll = dummy_set_pll; break; case UNICHROME_K800: case UNICHROME_PM800: @@ -280,6 +325,9 @@ void via_clock_init(struct via_clock *clock, int gfx_chip) clock->set_secondary_clock_source = set_secondary_clock_source; clock->set_secondary_pll_state = set_secondary_pll_state; clock->set_secondary_pll = k800_set_secondary_pll; + + clock->set_engine_pll_state = set_engine_pll_state; + clock->set_engine_pll = k800_set_engine_pll; break; case UNICHROME_VX855: case UNICHROME_VX900: @@ -292,6 +340,9 @@ void via_clock_init(struct via_clock *clock, int gfx_chip) clock->set_secondary_clock_source = set_secondary_clock_source; clock->set_secondary_pll_state = set_secondary_pll_state; clock->set_secondary_pll = vx855_set_secondary_pll; + + clock->set_engine_pll_state = set_engine_pll_state; + clock->set_engine_pll = vx855_set_engine_pll; break; } diff --git a/drivers/video/via/via_clock.h b/drivers/video/via/via_clock.h index f213a7a..88714ae 100644 --- a/drivers/video/via/via_clock.h +++ b/drivers/video/via/via_clock.h @@ -53,6 +53,9 @@ struct via_clock { void (*set_secondary_clock_source)(enum via_clksrc src, bool use_pll); void (*set_secondary_pll_state)(u8 state); void (*set_secondary_pll)(struct via_pll_config config); + + void (*set_engine_pll_state)(u8 state); + void (*set_engine_pll)(struct via_pll_config config); }; -- cgit v0.10.2 From 95d517cfce023eb24c5363ab82377146bd659816 Mon Sep 17 00:00:00 2001 From: Florian Tobias Schandinat Date: Sat, 26 Mar 2011 23:39:07 +0000 Subject: viafb: gather common good, old VGA initialization in one place This patch moves all unprotected VGA initialization in one table and provides some documentation for those values. Signed-off-by: Florian Tobias Schandinat diff --git a/drivers/video/via/hw.c b/drivers/video/via/hw.c index 0098270..5b9c096 100644 --- a/drivers/video/via/hw.c +++ b/drivers/video/via/hw.c @@ -308,6 +308,42 @@ static struct io_reg scaling_parameters[] = { {VIACR, CR87, 0xFF, 0x1F}, /* LCD Scaling Parameter 14 */ }; +static struct io_reg common_vga[] = { + {VIACR, CR07, 0x10, 0x10}, /* [0] vertical total (bit 8) + [1] vertical display end (bit 8) + [2] vertical retrace start (bit 8) + [3] start vertical blanking (bit 8) + [4] line compare (bit 8) + [5] vertical total (bit 9) + [6] vertical display end (bit 9) + [7] vertical retrace start (bit 9) */ + {VIACR, CR08, 0xFF, 0x00}, /* [0-4] preset row scan + [5-6] byte panning */ + {VIACR, CR09, 0xDF, 0x40}, /* [0-4] max scan line + [5] start vertical blanking (bit 9) + [6] line compare (bit 9) + [7] scan doubling */ + {VIACR, CR0A, 0xFF, 0x1E}, /* [0-4] cursor start + [5] cursor disable */ + {VIACR, CR0B, 0xFF, 0x00}, /* [0-4] cursor end + [5-6] cursor skew */ + {VIACR, CR0E, 0xFF, 0x00}, /* [0-7] cursor location (high) */ + {VIACR, CR0F, 0xFF, 0x00}, /* [0-7] cursor location (low) */ + {VIACR, CR11, 0xF0, 0x80}, /* [0-3] vertical retrace end + [6] memory refresh bandwidth + [7] CRTC register protect enable */ + {VIACR, CR14, 0xFF, 0x00}, /* [0-4] underline location + [5] divide memory address clock by 4 + [6] double word addressing */ + {VIACR, CR17, 0xFF, 0x63}, /* [0-1] mapping of display address 13-14 + [2] divide scan line clock by 2 + [3] divide memory address clock by 2 + [5] address wrap + [6] byte mode select + [7] sync enable */ + {VIACR, CR18, 0xFF, 0xFF}, /* [0-7] line compare */ +}; + static struct fifo_depth_select display_fifo_depth_reg = { /* IGA1 FIFO Depth_Select */ {IGA1_FIFO_DEPTH_SELECT_REG_NUM, {{SR17, 0, 7} } }, @@ -1167,22 +1203,10 @@ static void load_fix_bit_crtc_reg(void) /* always set to 1 */ viafb_write_reg_mask(CR03, VIACR, 0x80, BIT7); /* line compare should set all bits = 1 (extend modes) */ - viafb_write_reg(CR18, VIACR, 0xff); - /* line compare should set all bits = 1 (extend modes) */ - viafb_write_reg_mask(CR07, VIACR, 0x10, BIT4); - /* line compare should set all bits = 1 (extend modes) */ viafb_write_reg_mask(CR35, VIACR, 0x10, BIT4); /* line compare should set all bits = 1 (extend modes) */ viafb_write_reg_mask(CR33, VIACR, 0x06, BIT0 + BIT1 + BIT2); /*viafb_write_reg_mask(CR32, VIACR, 0x01, BIT0); */ - /* extend mode always set to e3h */ - viafb_write_reg(CR17, VIACR, 0xe3); - /* extend mode always set to 0h */ - viafb_write_reg(CR08, VIACR, 0x00); - /* extend mode always set to 0h */ - viafb_write_reg(CR14, VIACR, 0x00); - viafb_write_reg_mask(CR09, VIACR, 0x40, 0xDF); - viafb_write_reg_mask(CR11, VIACR, 0x00, BIT4 + BIT5 + BIT6); viafb_lock_crt(); @@ -2353,6 +2377,7 @@ int viafb_setmode(struct VideoModeTable *vmode_tbl, int video_bpp, outb(0x00, VIAAR); /* Write Common Setting for Video Mode */ + viafb_write_regx(common_vga, ARRAY_SIZE(common_vga)); switch (viaparinfo->chip_info->gfx_chip_name) { case UNICHROME_CLE266: viafb_write_regx(CLE266_ModeXregs, NUM_TOTAL_CLE266_ModeXregs); diff --git a/drivers/video/via/viamode.c b/drivers/video/via/viamode.c index 8c5bc41..036ad3a 100644 --- a/drivers/video/via/viamode.c +++ b/drivers/video/via/viamode.c @@ -30,10 +30,6 @@ struct io_reg CN400_ModeXregs[] = { {VIASR, SR10, 0xFF, 0x01}, {VIASR, SR1A, 0xFB, 0x08}, {VIASR, SR1E, 0x0F, 0x01}, {VIASR, SR2A, 0xFF, 0x00}, -{VIACR, CR0A, 0xFF, 0x1E}, /* Cursor Start */ -{VIACR, CR0B, 0xFF, 0x00}, /* Cursor End */ -{VIACR, CR0E, 0xFF, 0x00}, /* Cursor Location High */ -{VIACR, CR0F, 0xFF, 0x00}, /* Cursor Localtion Low */ {VIACR, CR32, 0xFF, 0x00}, {VIACR, CR33, 0xFF, 0x00}, {VIACR, CR35, 0xFF, 0x00}, @@ -125,10 +121,6 @@ struct io_reg KM400_ModeXregs[] = { {VIASR, SR2A, 0xFF, 0x00}, /* Power Management Control 5 */ {VIASR, SR2D, 0xFF, 0xFF}, /* Power Management Control 1 */ {VIASR, SR2E, 0xFF, 0xFF}, /* Power Management Control 2 */ - {VIACR, CR0A, 0xFF, 0x1E}, /* Cursor Start */ - {VIACR, CR0B, 0xFF, 0x00}, /* Cursor End */ - {VIACR, CR0E, 0xFF, 0x00}, /* Cursor Location High */ - {VIACR, CR0F, 0xFF, 0x00}, /* Cursor Localtion Low */ {VIACR, CR33, 0xFF, 0x00}, {VIACR, CR55, 0x80, 0x00}, {VIACR, CR5D, 0x80, 0x00}, @@ -162,10 +154,6 @@ struct io_reg CX700_ModeXregs[] = { {VIASR, SR10, 0xFF, 0x01}, {VIASR, SR1E, 0xFF, 0x01}, {VIASR, SR2A, 0xFF, 0x00}, {VIASR, SR2D, 0xFF, 0xFF}, /* VCK and LCK PLL power on. */ -{VIACR, CR0A, 0xFF, 0x1E}, /* Cursor Start */ -{VIACR, CR0B, 0xFF, 0x00}, /* Cursor End */ -{VIACR, CR0E, 0xFF, 0x00}, /* Cursor Location High */ -{VIACR, CR0F, 0xFF, 0x00}, /* Cursor Localtion Low */ {VIACR, CR32, 0xFF, 0x00}, {VIACR, CR33, 0xFF, 0x00}, {VIACR, CR35, 0xFF, 0x00}, @@ -205,13 +193,6 @@ struct io_reg VX855_ModeXregs[] = { {VIASR, SR58, 0xFF, 0x00}, {VIASR, SR59, 0xFF, 0x00}, {VIASR, SR2D, 0xFF, 0xFF}, /* VCK and LCK PLL power on. */ -{VIACR, CR09, 0xFF, 0x00}, /* Initial CR09=0*/ -{VIACR, CR11, 0x8F, 0x00}, /* IGA1 initial Vertical end */ -{VIACR, CR17, 0x7F, 0x00}, /* IGA1 CRT Mode control init */ -{VIACR, CR0A, 0xFF, 0x1E}, /* Cursor Start */ -{VIACR, CR0B, 0xFF, 0x00}, /* Cursor End */ -{VIACR, CR0E, 0xFF, 0x00}, /* Cursor Location High */ -{VIACR, CR0F, 0xFF, 0x00}, /* Cursor Localtion Low */ {VIACR, CR32, 0xFF, 0x00}, {VIACR, CR33, 0x7F, 0x00}, {VIACR, CR35, 0xFF, 0x00}, -- cgit v0.10.2 From 8e8ec596e6c0144e2dd500a57ee23dde9684df46 Mon Sep 17 00:00:00 2001 From: Kim Phillips Date: Sun, 13 Mar 2011 16:54:26 +0800 Subject: crypto: caam - Add support for the Freescale SEC4/CAAM The SEC4 supercedes the SEC2.x/3.x as Freescale's Integrated Security Engine. Its programming model is incompatible with all prior versions of the SEC (talitos). The SEC4 is also known as the Cryptographic Accelerator and Assurance Module (CAAM); this driver is named caam. This initial submission does not include support for Data Path mode operation - AEAD descriptors are submitted via the job ring interface, while the Queue Interface (QI) is enabled for use by others. Only AEAD algorithms are implemented at this time, for use with IPsec. Many thanks to the Freescale STC team for their contributions to this driver. Signed-off-by: Steve Cornelius Signed-off-by: Kim Phillips Signed-off-by: Herbert Xu diff --git a/Documentation/devicetree/bindings/crypto/fsl-sec4.txt b/Documentation/devicetree/bindings/crypto/fsl-sec4.txt new file mode 100644 index 0000000..fce16a8 --- /dev/null +++ b/Documentation/devicetree/bindings/crypto/fsl-sec4.txt @@ -0,0 +1,409 @@ +===================================================================== +SEC 4 Device Tree Binding +Copyright (C) 2008-2011 Freescale Semiconductor Inc. + + CONTENTS + -Overview + -SEC 4 Node + -Job Ring Node + -Run Time Integrity Check (RTIC) Node + -Run Time Integrity Check (RTIC) Memory Node + -Secure Non-Volatile Storage (SNVS) Node + -Full Example + +NOTE: the SEC 4 is also known as Freescale's Cryptographic Accelerator +Accelerator and Assurance Module (CAAM). + +===================================================================== +Overview + +DESCRIPTION + +SEC 4 h/w can process requests from 2 types of sources. +1. DPAA Queue Interface (HW interface between Queue Manager & SEC 4). +2. Job Rings (HW interface between cores & SEC 4 registers). + +High Speed Data Path Configuration: + +HW interface between QM & SEC 4 and also BM & SEC 4, on DPAA-enabled parts +such as the P4080. The number of simultaneous dequeues the QI can make is +equal to the number of Descriptor Controller (DECO) engines in a particular +SEC version. E.g., the SEC 4.0 in the P4080 has 5 DECOs and can thus +dequeue from 5 subportals simultaneously. + +Job Ring Data Path Configuration: + +Each JR is located on a separate 4k page, they may (or may not) be made visible +in the memory partition devoted to a particular core. The P4080 has 4 JRs, so +up to 4 JRs can be configured; and all 4 JRs process requests in parallel. + +===================================================================== +P4080 SEC 4 Node + +Description + + Node defines the base address of the SEC 4 block. + This block specifies the address range of all global + configuration registers for the SEC 4 block. It + also receives interrupts from the Run Time Integrity Check + (RTIC) function within the SEC 4 block. + +PROPERTIES + + - compatible + Usage: required + Value type: + Definition: Must include "fsl,p4080-sec4.0","fsl,sec-4.0" + + - #address-cells + Usage: required + Value type: + Definition: A standard property. Defines the number of cells + for representing physical addresses in child nodes. + + - #size-cells + Usage: required + Value type: + Definition: A standard property. Defines the number of cells + for representing the size of physical addresses in + child nodes. + + - reg + Usage: required + Value type: + Definition: A standard property. Specifies the physical + address and length of the SEC4.0 configuration registers. + registers + + - ranges + Usage: required + Value type: + Definition: A standard property. Specifies the physical address + range of the SEC 4.0 register space (-SNVS not included). A + triplet that includes the child address, parent address, & + length. + + - interrupts + Usage: required + Value type: + Definition: Specifies the interrupts generated by this + device. The value of the interrupts property + consists of one interrupt specifier. The format + of the specifier is defined by the binding document + describing the node's interrupt parent. + + - interrupt-parent + Usage: (required if interrupt property is defined) + Value type: + Definition: A single value that points + to the interrupt parent to which the child domain + is being mapped. + + Note: All other standard properties (see the ePAPR) are allowed + but are optional. + + +EXAMPLE + crypto@300000 { + compatible = "fsl,p4080-sec4.0", "fsl,sec4.0"; + #address-cells = <1>; + #size-cells = <1>; + reg = <0x300000 0x10000>; + ranges = <0 0x300000 0x10000>; + interrupt-parent = <&mpic>; + interrupts = <92 2>; + }; + +===================================================================== +P4080 Job Ring (JR) Node + + Child of the crypto node defines data processing interface to SEC 4 + across the peripheral bus for purposes of processing + cryptographic descriptors. The specified address + range can be made visible to one (or more) cores. + The interrupt defined for this node is controlled within + the address range of this node. + + - compatible + Usage: required + Value type: + Definition: Must include "fsl,p4080-sec4.0-job-ring","fsl,sec4.0-job-ring" + + - reg + Usage: required + Value type: + Definition: Specifies a two JR parameters: an offset from + the parent physical address and the length the JR registers. + + - fsl,liodn + Usage: optional-but-recommended + Value type: + Definition: + Specifies the LIODN to be used in conjunction with + the ppid-to-liodn table that specifies the PPID to LIODN mapping. + Needed if the PAMU is used. Value is a 12 bit value + where value is a LIODN ID for this JR. This property is + normally set by boot firmware. + + - interrupts + Usage: required + Value type: + Definition: Specifies the interrupts generated by this + device. The value of the interrupts property + consists of one interrupt specifier. The format + of the specifier is defined by the binding document + describing the node's interrupt parent. + + - interrupt-parent + Usage: (required if interrupt property is defined) + Value type: + Definition: A single value that points + to the interrupt parent to which the child domain + is being mapped. + +EXAMPLE + jr@1000 { + compatible = "fsl,p4080-sec4.0-job-ring", + "fsl,sec4.0-job-ring"; + reg = <0x1000 0x1000>; + fsl,liodn = <0x081>; + interrupt-parent = <&mpic>; + interrupts = <88 2>; + }; + + +===================================================================== +P4080 Run Time Integrity Check (RTIC) Node + + Child node of the crypto node. Defines a register space that + contains up to 5 sets of addresses and their lengths (sizes) that + will be checked at run time. After an initial hash result is + calculated, these addresses are checked by HW to monitor any + change. If any memory is modified, a Security Violation is + triggered (see SNVS definition). + + + - compatible + Usage: required + Value type: + Definition: Must include "fsl,p4080-sec4.0-rtic","fsl,sec4.0-rtic". + + - #address-cells + Usage: required + Value type: + Definition: A standard property. Defines the number of cells + for representing physical addresses in child nodes. Must + have a value of 1. + + - #size-cells + Usage: required + Value type: + Definition: A standard property. Defines the number of cells + for representing the size of physical addresses in + child nodes. Must have a value of 1. + + - reg + Usage: required + Value type: + Definition: A standard property. Specifies a two parameters: + an offset from the parent physical address and the length + the SEC4 registers. + + - ranges + Usage: required + Value type: + Definition: A standard property. Specifies the physical address + range of the SEC 4 register space (-SNVS not included). A + triplet that includes the child address, parent address, & + length. + +EXAMPLE + rtic@6000 { + compatible = "fsl,p4080-sec4.0-rtic", + "fsl,sec4.0-rtic"; + #address-cells = <1>; + #size-cells = <1>; + reg = <0x6000 0x100>; + ranges = <0x0 0x6100 0xe00>; + }; + +===================================================================== +P4080 Run Time Integrity Check (RTIC) Memory Node + A child node that defines individual RTIC memory regions that are used to + perform run-time integrity check of memory areas that should not modified. + The node defines a register that contains the memory address & + length (combined) and a second register that contains the hash result + in big endian format. + + - compatible + Usage: required + Value type: + Definition: Must include "fsl,p4080-sec4.0-rtic-memory","fsl,sec4.0-rtic-memory". + + - reg + Usage: required + Value type: + Definition: A standard property. Specifies two parameters: + an offset from the parent physical address and the length: + + 1. The location of the RTIC memory address & length registers. + 2. The location RTIC hash result. + + - fsl,rtic-region + Usage: optional-but-recommended + Value type: + Definition: + Specifies the HW address (36 bit address) for this region + followed by the length of the HW partition to be checked; + the address is represented as a 64 bit quantity followed + by a 32 bit length. + + - fsl,liodn + Usage: optional-but-recommended + Value type: + Definition: + Specifies the LIODN to be used in conjunction with + the ppid-to-liodn table that specifies the PPID to LIODN + mapping. Needed if the PAMU is used. Value is a 12 bit value + where value is a LIODN ID for this RTIC memory region. This + property is normally set by boot firmware. + +EXAMPLE + rtic-a@0 { + compatible = "fsl,p4080-sec4.0-rtic-memory", + "fsl,sec4.0-rtic-memory"; + reg = <0x00 0x20 0x100 0x80>; + fsl,liodn = <0x03c>; + fsl,rtic-region = <0x12345678 0x12345678 0x12345678>; + }; + +===================================================================== +P4080 Secure Non-Volatile Storage (SNVS) Node + + Node defines address range and the associated + interrupt for the SNVS function. This function + monitors security state information & reports + security violations. + + - compatible + Usage: required + Value type: + Definition: Must include "fsl,p4080-sec4.0-mon", "fsl,sec4.0-mon". + + - reg + Usage: required + Value type: + Definition: A standard property. Specifies the physical + address and length of the SEC4 configuration + registers. + + - interrupts + Usage: required + Value type: + Definition: Specifies the interrupts generated by this + device. The value of the interrupts property + consists of one interrupt specifier. The format + of the specifier is defined by the binding document + describing the node's interrupt parent. + + - interrupt-parent + Usage: (required if interrupt property is defined) + Value type: + Definition: A single value that points + to the interrupt parent to which the child domain + is being mapped. + +EXAMPLE + sec_mon@314000 { + compatible = "fsl,p4080-sec4.0-mon", "fsl,sec4.0-mon"; + reg = <0x314000 0x1000>; + interrupt-parent = <&mpic>; + interrupts = <93 2>; + }; + +===================================================================== +FULL EXAMPLE + + crypto: crypto@300000 { + compatible = "fsl,p4080-sec4.0", "fsl,sec4.0"; + #address-cells = <1>; + #size-cells = <1>; + reg = <0x300000 0x10000>; + ranges = <0 0x300000 0x10000>; + interrupt-parent = <&mpic>; + interrupts = <92 2>; + + sec_jr0: jr@1000 { + compatible = "fsl,p4080-sec4.0-job-ring", + "fsl,sec4.0-job-ring"; + reg = <0x1000 0x1000>; + interrupt-parent = <&mpic>; + interrupts = <88 2>; + }; + + sec_jr1: jr@2000 { + compatible = "fsl,p4080-sec4.0-job-ring", + "fsl,sec4.0-job-ring"; + reg = <0x2000 0x1000>; + interrupt-parent = <&mpic>; + interrupts = <89 2>; + }; + + sec_jr2: jr@3000 { + compatible = "fsl,p4080-sec4.0-job-ring", + "fsl,sec4.0-job-ring"; + reg = <0x3000 0x1000>; + interrupt-parent = <&mpic>; + interrupts = <90 2>; + }; + + sec_jr3: jr@4000 { + compatible = "fsl,p4080-sec4.0-job-ring", + "fsl,sec4.0-job-ring"; + reg = <0x4000 0x1000>; + interrupt-parent = <&mpic>; + interrupts = <91 2>; + }; + + rtic@6000 { + compatible = "fsl,p4080-sec4.0-rtic", + "fsl,sec4.0-rtic"; + #address-cells = <1>; + #size-cells = <1>; + reg = <0x6000 0x100>; + ranges = <0x0 0x6100 0xe00>; + + rtic_a: rtic-a@0 { + compatible = "fsl,p4080-sec4.0-rtic-memory", + "fsl,sec4.0-rtic-memory"; + reg = <0x00 0x20 0x100 0x80>; + }; + + rtic_b: rtic-b@20 { + compatible = "fsl,p4080-sec4.0-rtic-memory", + "fsl,sec4.0-rtic-memory"; + reg = <0x20 0x20 0x200 0x80>; + }; + + rtic_c: rtic-c@40 { + compatible = "fsl,p4080-sec4.0-rtic-memory", + "fsl,sec4.0-rtic-memory"; + reg = <0x40 0x20 0x300 0x80>; + }; + + rtic_d: rtic-d@60 { + compatible = "fsl,p4080-sec4.0-rtic-memory", + "fsl,sec4.0-rtic-memory"; + reg = <0x60 0x20 0x500 0x80>; + }; + }; + }; + + sec_mon: sec_mon@314000 { + compatible = "fsl,p4080-sec4.0-mon", "fsl,sec4.0-mon"; + reg = <0x314000 0x1000>; + interrupt-parent = <&mpic>; + interrupts = <93 2>; + }; + +===================================================================== diff --git a/arch/powerpc/boot/dts/p4080ds.dts b/arch/powerpc/boot/dts/p4080ds.dts index 5b7fc29..c78e801 100644 --- a/arch/powerpc/boot/dts/p4080ds.dts +++ b/arch/powerpc/boot/dts/p4080ds.dts @@ -1,7 +1,7 @@ /* * P4080DS Device Tree Source * - * Copyright 2009 Freescale Semiconductor Inc. + * Copyright 2009-2011 Freescale Semiconductor Inc. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the @@ -33,6 +33,17 @@ dma1 = &dma1; sdhc = &sdhc; + crypto = &crypto; + sec_jr0 = &sec_jr0; + sec_jr1 = &sec_jr1; + sec_jr2 = &sec_jr2; + sec_jr3 = &sec_jr3; + rtic_a = &rtic_a; + rtic_b = &rtic_b; + rtic_c = &rtic_c; + rtic_d = &rtic_d; + sec_mon = &sec_mon; + rio0 = &rapidio0; }; @@ -410,6 +421,88 @@ dr_mode = "host"; phy_type = "ulpi"; }; + + crypto: crypto@300000 { + compatible = "fsl,p4080-sec4.0", "fsl,sec4.0"; + #address-cells = <1>; + #size-cells = <1>; + reg = <0x300000 0x10000>; + ranges = <0 0x300000 0x10000>; + interrupt-parent = <&mpic>; + interrupts = <92 2>; + + sec_jr0: jr@1000 { + compatible = "fsl,p4080-sec4.0-job-ring", + "fsl,sec4.0-job-ring"; + reg = <0x1000 0x1000>; + interrupt-parent = <&mpic>; + interrupts = <88 2>; + }; + + sec_jr1: jr@2000 { + compatible = "fsl,p4080-sec4.0-job-ring", + "fsl,sec4.0-job-ring"; + reg = <0x2000 0x1000>; + interrupt-parent = <&mpic>; + interrupts = <89 2>; + }; + + sec_jr2: jr@3000 { + compatible = "fsl,p4080-sec4.0-job-ring", + "fsl,sec4.0-job-ring"; + reg = <0x3000 0x1000>; + interrupt-parent = <&mpic>; + interrupts = <90 2>; + }; + + sec_jr3: jr@4000 { + compatible = "fsl,p4080-sec4.0-job-ring", + "fsl,sec4.0-job-ring"; + reg = <0x4000 0x1000>; + interrupt-parent = <&mpic>; + interrupts = <91 2>; + }; + + rtic@6000 { + compatible = "fsl,p4080-sec4.0-rtic", + "fsl,sec4.0-rtic"; + #address-cells = <1>; + #size-cells = <1>; + reg = <0x6000 0x100>; + ranges = <0x0 0x6100 0xe00>; + + rtic_a: rtic-a@0 { + compatible = "fsl,p4080-sec4.0-rtic-memory", + "fsl,sec4.0-rtic-memory"; + reg = <0x00 0x20 0x100 0x80>; + }; + + rtic_b: rtic-b@20 { + compatible = "fsl,p4080-sec4.0-rtic-memory", + "fsl,sec4.0-rtic-memory"; + reg = <0x20 0x20 0x200 0x80>; + }; + + rtic_c: rtic-c@40 { + compatible = "fsl,p4080-sec4.0-rtic-memory", + "fsl,sec4.0-rtic-memory"; + reg = <0x40 0x20 0x300 0x80>; + }; + + rtic_d: rtic-d@60 { + compatible = "fsl,p4080-sec4.0-rtic-memory", + "fsl,sec4.0-rtic-memory"; + reg = <0x60 0x20 0x500 0x80>; + }; + }; + }; + + sec_mon: sec_mon@314000 { + compatible = "fsl,p4080-sec4.0-mon", "fsl,sec4.0-mon"; + reg = <0x314000 0x1000>; + interrupt-parent = <&mpic>; + interrupts = <93 2>; + }; }; rapidio0: rapidio@ffe0c0000 { diff --git a/drivers/crypto/Kconfig b/drivers/crypto/Kconfig index e541852..a27224a 100644 --- a/drivers/crypto/Kconfig +++ b/drivers/crypto/Kconfig @@ -200,6 +200,8 @@ config CRYPTO_DEV_HIFN_795X_RNG Select this option if you want to enable the random number generator on the HIFN 795x crypto adapters. +source drivers/crypto/caam/Kconfig + config CRYPTO_DEV_TALITOS tristate "Talitos Freescale Security Engine (SEC)" select CRYPTO_ALGAPI diff --git a/drivers/crypto/Makefile b/drivers/crypto/Makefile index 5203e34..663c5ef 100644 --- a/drivers/crypto/Makefile +++ b/drivers/crypto/Makefile @@ -6,6 +6,7 @@ n2_crypto-y := n2_core.o n2_asm.o obj-$(CONFIG_CRYPTO_DEV_HIFN_795X) += hifn_795x.o obj-$(CONFIG_CRYPTO_DEV_MV_CESA) += mv_cesa.o obj-$(CONFIG_CRYPTO_DEV_TALITOS) += talitos.o +obj-$(CONFIG_CRYPTO_DEV_FSL_CAAM) += caam/ obj-$(CONFIG_CRYPTO_DEV_IXP4XX) += ixp4xx_crypto.o obj-$(CONFIG_CRYPTO_DEV_PPC4XX) += amcc/ obj-$(CONFIG_CRYPTO_DEV_OMAP_SHAM) += omap-sham.o diff --git a/drivers/crypto/caam/Kconfig b/drivers/crypto/caam/Kconfig new file mode 100644 index 0000000..2d876bb --- /dev/null +++ b/drivers/crypto/caam/Kconfig @@ -0,0 +1,72 @@ +config CRYPTO_DEV_FSL_CAAM + tristate "Freescale CAAM-Multicore driver backend" + depends on FSL_SOC + help + Enables the driver module for Freescale's Cryptographic Accelerator + and Assurance Module (CAAM), also known as the SEC version 4 (SEC4). + This module adds a job ring operation interface, and configures h/w + to operate as a DPAA component automatically, depending + on h/w feature availability. + + To compile this driver as a module, choose M here: the module + will be called caam. + +config CRYPTO_DEV_FSL_CAAM_RINGSIZE + int "Job Ring size" + depends on CRYPTO_DEV_FSL_CAAM + range 2 9 + default "9" + help + Select size of Job Rings as a power of 2, within the + range 2-9 (ring size 4-512). + Examples: + 2 => 4 + 3 => 8 + 4 => 16 + 5 => 32 + 6 => 64 + 7 => 128 + 8 => 256 + 9 => 512 + +config CRYPTO_DEV_FSL_CAAM_INTC + bool "Job Ring interrupt coalescing" + depends on CRYPTO_DEV_FSL_CAAM + default y + help + Enable the Job Ring's interrupt coalescing feature. + +config CRYPTO_DEV_FSL_CAAM_INTC_COUNT_THLD + int "Job Ring interrupt coalescing count threshold" + depends on CRYPTO_DEV_FSL_CAAM_INTC + range 1 255 + default 255 + help + Select number of descriptor completions to queue before + raising an interrupt, in the range 1-255. Note that a selection + of 1 functionally defeats the coalescing feature, and a selection + equal or greater than the job ring size will force timeouts. + +config CRYPTO_DEV_FSL_CAAM_INTC_TIME_THLD + int "Job Ring interrupt coalescing timer threshold" + depends on CRYPTO_DEV_FSL_CAAM_INTC + range 1 65535 + default 2048 + help + Select number of bus clocks/64 to timeout in the case that one or + more descriptor completions are queued without reaching the count + threshold. Range is 1-65535. + +config CRYPTO_DEV_FSL_CAAM_CRYPTO_API + tristate "Register algorithm implementations with the Crypto API" + depends on CRYPTO_DEV_FSL_CAAM + default y + select CRYPTO_ALGAPI + select CRYPTO_AUTHENC + help + Selecting this will offload crypto for users of the + scatterlist crypto API (such as the linux native IPSec + stack) to the SEC4 via job ring. + + To compile this as a module, choose M here: the module + will be called caamalg. diff --git a/drivers/crypto/caam/Makefile b/drivers/crypto/caam/Makefile new file mode 100644 index 0000000..ef39011 --- /dev/null +++ b/drivers/crypto/caam/Makefile @@ -0,0 +1,8 @@ +# +# Makefile for the CAAM backend and dependent components +# + +obj-$(CONFIG_CRYPTO_DEV_FSL_CAAM) += caam.o +obj-$(CONFIG_CRYPTO_DEV_FSL_CAAM_CRYPTO_API) += caamalg.o + +caam-objs := ctrl.o jr.o error.o diff --git a/drivers/crypto/caam/caamalg.c b/drivers/crypto/caam/caamalg.c new file mode 100644 index 0000000..d7fe3d3 --- /dev/null +++ b/drivers/crypto/caam/caamalg.c @@ -0,0 +1,1163 @@ +/* + * caam - Freescale FSL CAAM support for crypto API + * + * Copyright 2008-2011 Freescale Semiconductor, Inc. + * + * Based on talitos crypto API driver. + * + * relationship of job descriptors to shared descriptors (SteveC Dec 10 2008): + * + * --------------- --------------- + * | JobDesc #1 |-------------------->| ShareDesc | + * | *(packet 1) | | (PDB) | + * --------------- |------------->| (hashKey) | + * . | | (cipherKey) | + * . | |-------->| (operation) | + * --------------- | | --------------- + * | JobDesc #2 |------| | + * | *(packet 2) | | + * --------------- | + * . | + * . | + * --------------- | + * | JobDesc #3 |------------ + * | *(packet 3) | + * --------------- + * + * The SharedDesc never changes for a connection unless rekeyed, but + * each packet will likely be in a different place. So all we need + * to know to process the packet is where the input is, where the + * output goes, and what context we want to process with. Context is + * in the SharedDesc, packet references in the JobDesc. + * + * So, a job desc looks like: + * + * --------------------- + * | Header | + * | ShareDesc Pointer | + * | SEQ_OUT_PTR | + * | (output buffer) | + * | SEQ_IN_PTR | + * | (input buffer) | + * | LOAD (to DECO) | + * --------------------- + */ + +#include "compat.h" + +#include "regs.h" +#include "intern.h" +#include "desc_constr.h" +#include "jr.h" +#include "error.h" + +/* + * crypto alg + */ +#define CAAM_CRA_PRIORITY 3000 +/* max key is sum of AES_MAX_KEY_SIZE, max split key size */ +#define CAAM_MAX_KEY_SIZE (AES_MAX_KEY_SIZE + \ + SHA512_DIGEST_SIZE * 2) +/* max IV is max of AES_BLOCK_SIZE, DES3_EDE_BLOCK_SIZE */ +#define CAAM_MAX_IV_LENGTH 16 + +#ifdef DEBUG +/* for print_hex_dumps with line references */ +#define xstr(s) str(s) +#define str(s) #s +#define debug(format, arg...) printk(format, arg) +#else +#define debug(format, arg...) +#endif + +/* + * per-session context + */ +struct caam_ctx { + struct device *jrdev; + u32 *sh_desc; + dma_addr_t shared_desc_phys; + u32 class1_alg_type; + u32 class2_alg_type; + u32 alg_op; + u8 *key; + dma_addr_t key_phys; + unsigned int keylen; + unsigned int enckeylen; + unsigned int authkeylen; + unsigned int split_key_len; + unsigned int split_key_pad_len; + unsigned int authsize; +}; + +static int aead_authenc_setauthsize(struct crypto_aead *authenc, + unsigned int authsize) +{ + struct caam_ctx *ctx = crypto_aead_ctx(authenc); + + ctx->authsize = authsize; + + return 0; +} + +struct split_key_result { + struct completion completion; + int err; +}; + +static void split_key_done(struct device *dev, u32 *desc, u32 err, + void *context) +{ + struct split_key_result *res = context; + +#ifdef DEBUG + dev_err(dev, "%s %d: err 0x%x\n", __func__, __LINE__, err); +#endif + if (err) { + char tmp[256]; + + dev_err(dev, "%08x: %s\n", err, caam_jr_strstatus(tmp, err)); + } + + res->err = err; + + complete(&res->completion); +} + +/* +get a split ipad/opad key + +Split key generation----------------------------------------------- + +[00] 0xb0810008 jobdesc: stidx=1 share=never len=8 +[01] 0x04000014 key: class2->keyreg len=20 + @0xffe01000 +[03] 0x84410014 operation: cls2-op sha1 hmac init dec +[04] 0x24940000 fifold: class2 msgdata-last2 len=0 imm +[05] 0xa4000001 jump: class2 local all ->1 [06] +[06] 0x64260028 fifostr: class2 mdsplit-jdk len=40 + @0xffe04000 +*/ +static u32 gen_split_key(struct caam_ctx *ctx, const u8 *key_in, u32 authkeylen) +{ + struct device *jrdev = ctx->jrdev; + u32 *desc; + struct split_key_result result; + dma_addr_t dma_addr_in, dma_addr_out; + int ret = 0; + + desc = kmalloc(CAAM_CMD_SZ * 6 + CAAM_PTR_SZ * 2, GFP_KERNEL | GFP_DMA); + + init_job_desc(desc, 0); + + dma_addr_in = dma_map_single(jrdev, (void *)key_in, authkeylen, + DMA_TO_DEVICE); + if (dma_mapping_error(jrdev, dma_addr_in)) { + dev_err(jrdev, "unable to map key input memory\n"); + kfree(desc); + return -ENOMEM; + } + append_key(desc, dma_addr_in, authkeylen, CLASS_2 | + KEY_DEST_CLASS_REG); + + /* Sets MDHA up into an HMAC-INIT */ + append_operation(desc, ctx->alg_op | OP_ALG_DECRYPT | + OP_ALG_AS_INIT); + + /* + * do a FIFO_LOAD of zero, this will trigger the internal key expansion + into both pads inside MDHA + */ + append_fifo_load_as_imm(desc, NULL, 0, LDST_CLASS_2_CCB | + FIFOLD_TYPE_MSG | FIFOLD_TYPE_LAST2); + + /* + * FIFO_STORE with the explicit split-key content store + * (0x26 output type) + */ + dma_addr_out = dma_map_single(jrdev, ctx->key, ctx->split_key_pad_len, + DMA_FROM_DEVICE); + if (dma_mapping_error(jrdev, dma_addr_out)) { + dev_err(jrdev, "unable to map key output memory\n"); + kfree(desc); + return -ENOMEM; + } + append_fifo_store(desc, dma_addr_out, ctx->split_key_len, + LDST_CLASS_2_CCB | FIFOST_TYPE_SPLIT_KEK); + +#ifdef DEBUG + print_hex_dump(KERN_ERR, "ctx.key@"xstr(__LINE__)": ", + DUMP_PREFIX_ADDRESS, 16, 4, key_in, authkeylen, 1); + print_hex_dump(KERN_ERR, "jobdesc@"xstr(__LINE__)": ", + DUMP_PREFIX_ADDRESS, 16, 4, desc, desc_bytes(desc), 1); +#endif + + result.err = 0; + init_completion(&result.completion); + + ret = caam_jr_enqueue(jrdev, desc, split_key_done, &result); + if (!ret) { + /* in progress */ + wait_for_completion_interruptible(&result.completion); + ret = result.err; +#ifdef DEBUG + print_hex_dump(KERN_ERR, "ctx.key@"xstr(__LINE__)": ", + DUMP_PREFIX_ADDRESS, 16, 4, ctx->key, + ctx->split_key_pad_len, 1); +#endif + } + + dma_unmap_single(jrdev, dma_addr_out, ctx->split_key_pad_len, + DMA_FROM_DEVICE); + dma_unmap_single(jrdev, dma_addr_in, authkeylen, DMA_TO_DEVICE); + + kfree(desc); + + return ret; +} + +static int build_sh_desc_ipsec(struct caam_ctx *ctx) +{ + struct device *jrdev = ctx->jrdev; + u32 *sh_desc; + u32 *jump_cmd; + + /* build shared descriptor for this session */ + sh_desc = kmalloc(CAAM_CMD_SZ * 4 + ctx->split_key_pad_len + + ctx->enckeylen, GFP_DMA | GFP_KERNEL); + if (!sh_desc) { + dev_err(jrdev, "could not allocate shared descriptor\n"); + return -ENOMEM; + } + + init_sh_desc(sh_desc, HDR_SAVECTX | HDR_SHARE_SERIAL); + + jump_cmd = append_jump(sh_desc, CLASS_BOTH | JUMP_TEST_ALL | + JUMP_COND_SHRD | JUMP_COND_SELF); + + /* process keys, starting with class 2/authentication */ + append_key_as_imm(sh_desc, ctx->key, ctx->split_key_pad_len, + ctx->split_key_len, + CLASS_2 | KEY_DEST_MDHA_SPLIT | KEY_ENC); + + append_key_as_imm(sh_desc, (void *)ctx->key + ctx->split_key_pad_len, + ctx->enckeylen, ctx->enckeylen, + CLASS_1 | KEY_DEST_CLASS_REG); + + /* update jump cmd now that we are at the jump target */ + set_jump_tgt_here(sh_desc, jump_cmd); + + ctx->shared_desc_phys = dma_map_single(jrdev, sh_desc, + desc_bytes(sh_desc), + DMA_TO_DEVICE); + if (dma_mapping_error(jrdev, ctx->shared_desc_phys)) { + dev_err(jrdev, "unable to map shared descriptor\n"); + kfree(sh_desc); + return -ENOMEM; + } + + ctx->sh_desc = sh_desc; + + return 0; +} + +static int aead_authenc_setkey(struct crypto_aead *aead, + const u8 *key, unsigned int keylen) +{ + /* Sizes for MDHA pads (*not* keys): MD5, SHA1, 224, 256, 384, 512 */ + static const u8 mdpadlen[] = { 16, 20, 32, 32, 64, 64 }; + struct caam_ctx *ctx = crypto_aead_ctx(aead); + struct device *jrdev = ctx->jrdev; + struct rtattr *rta = (void *)key; + struct crypto_authenc_key_param *param; + unsigned int authkeylen; + unsigned int enckeylen; + int ret = 0; + + param = RTA_DATA(rta); + enckeylen = be32_to_cpu(param->enckeylen); + + key += RTA_ALIGN(rta->rta_len); + keylen -= RTA_ALIGN(rta->rta_len); + + if (keylen < enckeylen) + goto badkey; + + authkeylen = keylen - enckeylen; + + if (keylen > CAAM_MAX_KEY_SIZE) + goto badkey; + + /* Pick class 2 key length from algorithm submask */ + ctx->split_key_len = mdpadlen[(ctx->alg_op & OP_ALG_ALGSEL_SUBMASK) >> + OP_ALG_ALGSEL_SHIFT] * 2; + ctx->split_key_pad_len = ALIGN(ctx->split_key_len, 16); + +#ifdef DEBUG + printk(KERN_ERR "keylen %d enckeylen %d authkeylen %d\n", + keylen, enckeylen, authkeylen); + printk(KERN_ERR "split_key_len %d split_key_pad_len %d\n", + ctx->split_key_len, ctx->split_key_pad_len); + print_hex_dump(KERN_ERR, "key in @"xstr(__LINE__)": ", + DUMP_PREFIX_ADDRESS, 16, 4, key, keylen, 1); +#endif + ctx->key = kmalloc(ctx->split_key_pad_len + enckeylen, + GFP_KERNEL | GFP_DMA); + if (!ctx->key) { + dev_err(jrdev, "could not allocate key output memory\n"); + return -ENOMEM; + } + + ret = gen_split_key(ctx, key, authkeylen); + if (ret) { + kfree(ctx->key); + goto badkey; + } + + /* postpend encryption key to auth split key */ + memcpy(ctx->key + ctx->split_key_pad_len, key + authkeylen, enckeylen); + + ctx->key_phys = dma_map_single(jrdev, ctx->key, ctx->split_key_pad_len + + enckeylen, DMA_TO_DEVICE); + if (dma_mapping_error(jrdev, ctx->key_phys)) { + dev_err(jrdev, "unable to map key i/o memory\n"); + kfree(ctx->key); + return -ENOMEM; + } +#ifdef DEBUG + print_hex_dump(KERN_ERR, "ctx.key@"xstr(__LINE__)": ", + DUMP_PREFIX_ADDRESS, 16, 4, ctx->key, + ctx->split_key_pad_len + enckeylen, 1); +#endif + + ctx->keylen = keylen; + ctx->enckeylen = enckeylen; + ctx->authkeylen = authkeylen; + + ret = build_sh_desc_ipsec(ctx); + if (ret) { + dma_unmap_single(jrdev, ctx->key_phys, ctx->split_key_pad_len + + enckeylen, DMA_TO_DEVICE); + kfree(ctx->key); + } + + return ret; +badkey: + crypto_aead_set_flags(aead, CRYPTO_TFM_RES_BAD_KEY_LEN); + return -EINVAL; +} + +struct link_tbl_entry { + u64 ptr; + u32 len; + u8 reserved; + u8 buf_pool_id; + u16 offset; +}; + +/* + * ipsec_esp_edesc - s/w-extended ipsec_esp descriptor + * @src_nents: number of segments in input scatterlist + * @dst_nents: number of segments in output scatterlist + * @assoc_nents: number of segments in associated data (SPI+Seq) scatterlist + * @desc: h/w descriptor (variable length; must not exceed MAX_CAAM_DESCSIZE) + * @link_tbl_bytes: length of dma mapped link_tbl space + * @link_tbl_dma: bus physical mapped address of h/w link table + * @hw_desc: the h/w job descriptor followed by any referenced link tables + */ +struct ipsec_esp_edesc { + int assoc_nents; + int src_nents; + int dst_nents; + int link_tbl_bytes; + dma_addr_t link_tbl_dma; + struct link_tbl_entry *link_tbl; + u32 hw_desc[0]; +}; + +static void ipsec_esp_unmap(struct device *dev, + struct ipsec_esp_edesc *edesc, + struct aead_request *areq) +{ + dma_unmap_sg(dev, areq->assoc, edesc->assoc_nents, DMA_TO_DEVICE); + + if (unlikely(areq->dst != areq->src)) { + dma_unmap_sg(dev, areq->src, edesc->src_nents, + DMA_TO_DEVICE); + dma_unmap_sg(dev, areq->dst, edesc->dst_nents, + DMA_FROM_DEVICE); + } else { + dma_unmap_sg(dev, areq->src, edesc->src_nents, + DMA_BIDIRECTIONAL); + } + + if (edesc->link_tbl_bytes) + dma_unmap_single(dev, edesc->link_tbl_dma, + edesc->link_tbl_bytes, + DMA_TO_DEVICE); +} + +/* + * ipsec_esp descriptor callbacks + */ +static void ipsec_esp_encrypt_done(struct device *jrdev, u32 *desc, u32 err, + void *context) +{ + struct aead_request *areq = context; + struct ipsec_esp_edesc *edesc; +#ifdef DEBUG + struct crypto_aead *aead = crypto_aead_reqtfm(areq); + int ivsize = crypto_aead_ivsize(aead); + struct caam_ctx *ctx = crypto_aead_ctx(aead); + + dev_err(jrdev, "%s %d: err 0x%x\n", __func__, __LINE__, err); +#endif + edesc = (struct ipsec_esp_edesc *)((char *)desc - + offsetof(struct ipsec_esp_edesc, hw_desc)); + + if (err) { + char tmp[256]; + + dev_err(jrdev, "%s\n", caam_jr_strstatus(tmp, err)); + dev_err(jrdev, "%08x: %s\n", err, caam_jr_strstatus(tmp, err)); + } + + ipsec_esp_unmap(jrdev, edesc, areq); + +#ifdef DEBUG + print_hex_dump(KERN_ERR, "assoc @"xstr(__LINE__)": ", + DUMP_PREFIX_ADDRESS, 16, 4, sg_virt(areq->assoc), + areq->assoclen , 1); + print_hex_dump(KERN_ERR, "dstiv @"xstr(__LINE__)": ", + DUMP_PREFIX_ADDRESS, 16, 4, sg_virt(areq->src) - ivsize, + edesc->src_nents ? 100 : ivsize, 1); + print_hex_dump(KERN_ERR, "dst @"xstr(__LINE__)": ", + DUMP_PREFIX_ADDRESS, 16, 4, sg_virt(areq->src), + edesc->src_nents ? 100 : areq->cryptlen + + ctx->authsize + 4, 1); +#endif + + kfree(edesc); + + aead_request_complete(areq, err); +} + +static void ipsec_esp_decrypt_done(struct device *jrdev, u32 *desc, u32 err, + void *context) +{ + struct aead_request *areq = context; + struct ipsec_esp_edesc *edesc; +#ifdef DEBUG + struct crypto_aead *aead = crypto_aead_reqtfm(areq); + struct caam_ctx *ctx = crypto_aead_ctx(aead); + + dev_err(jrdev, "%s %d: err 0x%x\n", __func__, __LINE__, err); +#endif + edesc = (struct ipsec_esp_edesc *)((char *)desc - + offsetof(struct ipsec_esp_edesc, hw_desc)); + + if (err) { + char tmp[256]; + + dev_err(jrdev, "%08x: %s\n", err, caam_jr_strstatus(tmp, err)); + } + + ipsec_esp_unmap(jrdev, edesc, areq); + + /* + * verify hw auth check passed else return -EBADMSG + */ + if ((err & JRSTA_CCBERR_ERRID_MASK) == JRSTA_CCBERR_ERRID_ICVCHK) + err = -EBADMSG; + +#ifdef DEBUG + print_hex_dump(KERN_ERR, "iphdrout@"xstr(__LINE__)": ", + DUMP_PREFIX_ADDRESS, 16, 4, + ((char *)sg_virt(areq->assoc) - sizeof(struct iphdr)), + sizeof(struct iphdr) + areq->assoclen + + ((areq->cryptlen > 1500) ? 1500 : areq->cryptlen) + + ctx->authsize + 36, 1); + if (!err && edesc->link_tbl_bytes) { + struct scatterlist *sg = sg_last(areq->src, edesc->src_nents); + print_hex_dump(KERN_ERR, "sglastout@"xstr(__LINE__)": ", + DUMP_PREFIX_ADDRESS, 16, 4, sg_virt(sg), + sg->length + ctx->authsize + 16, 1); + } +#endif + kfree(edesc); + + aead_request_complete(areq, err); +} + +/* + * convert scatterlist to h/w link table format + * scatterlist must have been previously dma mapped + */ +static void sg_to_link_tbl(struct scatterlist *sg, int sg_count, + struct link_tbl_entry *link_tbl_ptr, u32 offset) +{ + while (sg_count) { + link_tbl_ptr->ptr = sg_dma_address(sg); + link_tbl_ptr->len = sg_dma_len(sg); + link_tbl_ptr->reserved = 0; + link_tbl_ptr->buf_pool_id = 0; + link_tbl_ptr->offset = offset; + link_tbl_ptr++; + sg = sg_next(sg); + sg_count--; + } + + /* set Final bit (marks end of link table) */ + link_tbl_ptr--; + link_tbl_ptr->len |= 0x40000000; +} + +/* + * fill in and submit ipsec_esp job descriptor + */ +static int ipsec_esp(struct ipsec_esp_edesc *edesc, struct aead_request *areq, + u32 encrypt, + void (*callback) (struct device *dev, u32 *desc, + u32 err, void *context)) +{ + struct crypto_aead *aead = crypto_aead_reqtfm(areq); + struct caam_ctx *ctx = crypto_aead_ctx(aead); + struct device *jrdev = ctx->jrdev; + u32 *desc = edesc->hw_desc, options; + int ret, sg_count, assoc_sg_count; + int ivsize = crypto_aead_ivsize(aead); + int authsize = ctx->authsize; + dma_addr_t ptr, dst_dma, src_dma; +#ifdef DEBUG + u32 *sh_desc = ctx->sh_desc; + + debug("assoclen %d cryptlen %d authsize %d\n", + areq->assoclen, areq->cryptlen, authsize); + print_hex_dump(KERN_ERR, "assoc @"xstr(__LINE__)": ", + DUMP_PREFIX_ADDRESS, 16, 4, sg_virt(areq->assoc), + areq->assoclen , 1); + print_hex_dump(KERN_ERR, "presciv@"xstr(__LINE__)": ", + DUMP_PREFIX_ADDRESS, 16, 4, sg_virt(areq->src) - ivsize, + edesc->src_nents ? 100 : ivsize, 1); + print_hex_dump(KERN_ERR, "src @"xstr(__LINE__)": ", + DUMP_PREFIX_ADDRESS, 16, 4, sg_virt(areq->src), + edesc->src_nents ? 100 : areq->cryptlen + authsize, 1); + print_hex_dump(KERN_ERR, "shrdesc@"xstr(__LINE__)": ", + DUMP_PREFIX_ADDRESS, 16, 4, sh_desc, + desc_bytes(sh_desc), 1); +#endif + assoc_sg_count = dma_map_sg(jrdev, areq->assoc, edesc->assoc_nents ?: 1, + DMA_TO_DEVICE); + if (areq->src == areq->dst) + sg_count = dma_map_sg(jrdev, areq->src, edesc->src_nents ? : 1, + DMA_BIDIRECTIONAL); + else + sg_count = dma_map_sg(jrdev, areq->src, edesc->src_nents ? : 1, + DMA_TO_DEVICE); + + /* start auth operation */ + append_operation(desc, ctx->class2_alg_type | OP_ALG_AS_INITFINAL | + (encrypt ? : OP_ALG_ICV_ON)); + + /* Load FIFO with data for Class 2 CHA */ + options = FIFOLD_CLASS_CLASS2 | FIFOLD_TYPE_MSG; + if (!edesc->assoc_nents) { + ptr = sg_dma_address(areq->assoc); + } else { + sg_to_link_tbl(areq->assoc, edesc->assoc_nents, + edesc->link_tbl, 0); + ptr = edesc->link_tbl_dma; + options |= LDST_SGF; + } + append_fifo_load(desc, ptr, areq->assoclen, options); + + /* copy iv from cipher/class1 input context to class2 infifo */ + append_move(desc, MOVE_SRC_CLASS1CTX | MOVE_DEST_CLASS2INFIFO | ivsize); + + /* start class 1 (cipher) operation */ + append_operation(desc, ctx->class1_alg_type | OP_ALG_AS_INITFINAL | + encrypt); + + /* load payload & instruct to class2 to snoop class 1 if encrypting */ + options = 0; + if (!edesc->src_nents) { + src_dma = sg_dma_address(areq->src); + } else { + sg_to_link_tbl(areq->src, edesc->src_nents, edesc->link_tbl + + edesc->assoc_nents, 0); + src_dma = edesc->link_tbl_dma + edesc->assoc_nents * + sizeof(struct link_tbl_entry); + options |= LDST_SGF; + } + append_seq_in_ptr(desc, src_dma, areq->cryptlen + authsize, options); + append_seq_fifo_load(desc, areq->cryptlen, FIFOLD_CLASS_BOTH | + FIFOLD_TYPE_LASTBOTH | + (encrypt ? FIFOLD_TYPE_MSG1OUT2 + : FIFOLD_TYPE_MSG)); + + /* specify destination */ + if (areq->src == areq->dst) { + dst_dma = src_dma; + } else { + sg_count = dma_map_sg(jrdev, areq->dst, edesc->dst_nents ? : 1, + DMA_FROM_DEVICE); + if (!edesc->dst_nents) { + dst_dma = sg_dma_address(areq->dst); + options = 0; + } else { + sg_to_link_tbl(areq->dst, edesc->dst_nents, + edesc->link_tbl + edesc->assoc_nents + + edesc->src_nents, 0); + dst_dma = edesc->link_tbl_dma + (edesc->assoc_nents + + edesc->src_nents) * + sizeof(struct link_tbl_entry); + options = LDST_SGF; + } + } + append_seq_out_ptr(desc, dst_dma, areq->cryptlen + authsize, options); + append_seq_fifo_store(desc, areq->cryptlen, FIFOST_TYPE_MESSAGE_DATA); + + /* ICV */ + if (encrypt) + append_seq_store(desc, authsize, LDST_CLASS_2_CCB | + LDST_SRCDST_BYTE_CONTEXT); + else + append_seq_fifo_load(desc, authsize, FIFOLD_CLASS_CLASS2 | + FIFOLD_TYPE_LAST2 | FIFOLD_TYPE_ICV); + +#ifdef DEBUG + debug("job_desc_len %d\n", desc_len(desc)); + print_hex_dump(KERN_ERR, "jobdesc@"xstr(__LINE__)": ", + DUMP_PREFIX_ADDRESS, 16, 4, desc, desc_bytes(desc) , 1); + print_hex_dump(KERN_ERR, "jdlinkt@"xstr(__LINE__)": ", + DUMP_PREFIX_ADDRESS, 16, 4, edesc->link_tbl, + edesc->link_tbl_bytes, 1); +#endif + + ret = caam_jr_enqueue(jrdev, desc, callback, areq); + if (!ret) + ret = -EINPROGRESS; + else { + ipsec_esp_unmap(jrdev, edesc, areq); + kfree(edesc); + } + + return ret; +} + +/* + * derive number of elements in scatterlist + */ +static int sg_count(struct scatterlist *sg_list, int nbytes, int *chained) +{ + struct scatterlist *sg = sg_list; + int sg_nents = 0; + + *chained = 0; + while (nbytes > 0) { + sg_nents++; + nbytes -= sg->length; + if (!sg_is_last(sg) && (sg + 1)->length == 0) + *chained = 1; + sg = scatterwalk_sg_next(sg); + } + + return sg_nents; +} + +/* + * allocate and map the ipsec_esp extended descriptor + */ +static struct ipsec_esp_edesc *ipsec_esp_edesc_alloc(struct aead_request *areq, + int desc_bytes) +{ + struct crypto_aead *aead = crypto_aead_reqtfm(areq); + struct caam_ctx *ctx = crypto_aead_ctx(aead); + struct device *jrdev = ctx->jrdev; + gfp_t flags = areq->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP ? GFP_KERNEL : + GFP_ATOMIC; + int assoc_nents, src_nents, dst_nents = 0, chained, link_tbl_bytes; + struct ipsec_esp_edesc *edesc; + + assoc_nents = sg_count(areq->assoc, areq->assoclen, &chained); + BUG_ON(chained); + if (likely(assoc_nents == 1)) + assoc_nents = 0; + + src_nents = sg_count(areq->src, areq->cryptlen + ctx->authsize, + &chained); + BUG_ON(chained); + if (src_nents == 1) + src_nents = 0; + + if (unlikely(areq->dst != areq->src)) { + dst_nents = sg_count(areq->dst, areq->cryptlen + ctx->authsize, + &chained); + BUG_ON(chained); + if (dst_nents == 1) + dst_nents = 0; + } + + link_tbl_bytes = (assoc_nents + src_nents + dst_nents) * + sizeof(struct link_tbl_entry); + debug("link_tbl_bytes %d\n", link_tbl_bytes); + + /* allocate space for base edesc and hw desc commands, link tables */ + edesc = kmalloc(sizeof(struct ipsec_esp_edesc) + desc_bytes + + link_tbl_bytes, GFP_DMA | flags); + if (!edesc) { + dev_err(jrdev, "could not allocate extended descriptor\n"); + return ERR_PTR(-ENOMEM); + } + + edesc->assoc_nents = assoc_nents; + edesc->src_nents = src_nents; + edesc->dst_nents = dst_nents; + edesc->link_tbl = (void *)edesc + sizeof(struct ipsec_esp_edesc) + + desc_bytes; + edesc->link_tbl_dma = dma_map_single(jrdev, edesc->link_tbl, + link_tbl_bytes, DMA_TO_DEVICE); + edesc->link_tbl_bytes = link_tbl_bytes; + + return edesc; +} + +static int aead_authenc_encrypt(struct aead_request *areq) +{ + struct ipsec_esp_edesc *edesc; + struct crypto_aead *aead = crypto_aead_reqtfm(areq); + struct caam_ctx *ctx = crypto_aead_ctx(aead); + struct device *jrdev = ctx->jrdev; + int ivsize = crypto_aead_ivsize(aead); + u32 *desc; + dma_addr_t iv_dma; + + /* allocate extended descriptor */ + edesc = ipsec_esp_edesc_alloc(areq, 21 * sizeof(u32)); + if (IS_ERR(edesc)) + return PTR_ERR(edesc); + + desc = edesc->hw_desc; + + /* insert shared descriptor pointer */ + init_job_desc_shared(desc, ctx->shared_desc_phys, + desc_len(ctx->sh_desc), HDR_SHARE_DEFER); + + iv_dma = dma_map_single(jrdev, areq->iv, ivsize, DMA_TO_DEVICE); + /* check dma error */ + + append_load(desc, iv_dma, ivsize, + LDST_CLASS_1_CCB | LDST_SRCDST_BYTE_CONTEXT); + + return ipsec_esp(edesc, areq, OP_ALG_ENCRYPT, ipsec_esp_encrypt_done); +} + +static int aead_authenc_decrypt(struct aead_request *req) +{ + struct crypto_aead *aead = crypto_aead_reqtfm(req); + int ivsize = crypto_aead_ivsize(aead); + struct caam_ctx *ctx = crypto_aead_ctx(aead); + struct device *jrdev = ctx->jrdev; + struct ipsec_esp_edesc *edesc; + u32 *desc; + dma_addr_t iv_dma; + + req->cryptlen -= ctx->authsize; + + /* allocate extended descriptor */ + edesc = ipsec_esp_edesc_alloc(req, 21 * sizeof(u32)); + if (IS_ERR(edesc)) + return PTR_ERR(edesc); + + desc = edesc->hw_desc; + + /* insert shared descriptor pointer */ + init_job_desc_shared(desc, ctx->shared_desc_phys, + desc_len(ctx->sh_desc), HDR_SHARE_DEFER); + + iv_dma = dma_map_single(jrdev, req->iv, ivsize, DMA_TO_DEVICE); + /* check dma error */ + + append_load(desc, iv_dma, ivsize, + LDST_CLASS_1_CCB | LDST_SRCDST_BYTE_CONTEXT); + + return ipsec_esp(edesc, req, !OP_ALG_ENCRYPT, ipsec_esp_decrypt_done); +} + +static int aead_authenc_givencrypt(struct aead_givcrypt_request *req) +{ + struct aead_request *areq = &req->areq; + struct ipsec_esp_edesc *edesc; + struct crypto_aead *aead = crypto_aead_reqtfm(areq); + struct caam_ctx *ctx = crypto_aead_ctx(aead); + struct device *jrdev = ctx->jrdev; + int ivsize = crypto_aead_ivsize(aead); + dma_addr_t iv_dma; + u32 *desc; + + iv_dma = dma_map_single(jrdev, req->giv, ivsize, DMA_FROM_DEVICE); + + debug("%s: giv %p\n", __func__, req->giv); + + /* allocate extended descriptor */ + edesc = ipsec_esp_edesc_alloc(areq, 27 * sizeof(u32)); + if (IS_ERR(edesc)) + return PTR_ERR(edesc); + + desc = edesc->hw_desc; + + /* insert shared descriptor pointer */ + init_job_desc_shared(desc, ctx->shared_desc_phys, + desc_len(ctx->sh_desc), HDR_SHARE_DEFER); + + /* + * LOAD IMM Info FIFO + * to DECO, Last, Padding, Random, Message, 16 bytes + */ + append_load_imm_u32(desc, NFIFOENTRY_DEST_DECO | NFIFOENTRY_LC1 | + NFIFOENTRY_STYPE_PAD | NFIFOENTRY_DTYPE_MSG | + NFIFOENTRY_PTYPE_RND | ivsize, + LDST_SRCDST_WORD_INFO_FIFO); + + /* + * disable info fifo entries since the above serves as the entry + * this way, the MOVE command won't generate an entry. + * Note that this isn't required in more recent versions of + * SEC as a MOVE that doesn't do info FIFO entries is available. + */ + append_cmd(desc, CMD_LOAD | DISABLE_AUTO_INFO_FIFO); + + /* MOVE DECO Alignment -> C1 Context 16 bytes */ + append_move(desc, MOVE_WAITCOMP | MOVE_SRC_INFIFO | + MOVE_DEST_CLASS1CTX | ivsize); + + /* re-enable info fifo entries */ + append_cmd(desc, CMD_LOAD | ENABLE_AUTO_INFO_FIFO); + + /* MOVE C1 Context -> OFIFO 16 bytes */ + append_move(desc, MOVE_WAITCOMP | MOVE_SRC_CLASS1CTX | + MOVE_DEST_OUTFIFO | ivsize); + + append_fifo_store(desc, iv_dma, ivsize, FIFOST_TYPE_MESSAGE_DATA); + + return ipsec_esp(edesc, areq, OP_ALG_ENCRYPT, ipsec_esp_encrypt_done); +} + +struct caam_alg_template { + char name[CRYPTO_MAX_ALG_NAME]; + char driver_name[CRYPTO_MAX_ALG_NAME]; + unsigned int blocksize; + struct aead_alg aead; + u32 class1_alg_type; + u32 class2_alg_type; + u32 alg_op; +}; + +static struct caam_alg_template driver_algs[] = { + /* single-pass ipsec_esp descriptor */ + { + .name = "authenc(hmac(sha1),cbc(aes))", + .driver_name = "authenc-hmac-sha1-cbc-aes-caam", + .blocksize = AES_BLOCK_SIZE, + .aead = { + .setkey = aead_authenc_setkey, + .setauthsize = aead_authenc_setauthsize, + .encrypt = aead_authenc_encrypt, + .decrypt = aead_authenc_decrypt, + .givencrypt = aead_authenc_givencrypt, + .geniv = "", + .ivsize = AES_BLOCK_SIZE, + .maxauthsize = SHA1_DIGEST_SIZE, + }, + .class1_alg_type = OP_ALG_ALGSEL_AES | OP_ALG_AAI_CBC, + .class2_alg_type = OP_ALG_ALGSEL_SHA1 | OP_ALG_AAI_HMAC_PRECOMP, + .alg_op = OP_ALG_ALGSEL_SHA1 | OP_ALG_AAI_HMAC, + }, + { + .name = "authenc(hmac(sha256),cbc(aes))", + .driver_name = "authenc-hmac-sha256-cbc-aes-caam", + .blocksize = AES_BLOCK_SIZE, + .aead = { + .setkey = aead_authenc_setkey, + .setauthsize = aead_authenc_setauthsize, + .encrypt = aead_authenc_encrypt, + .decrypt = aead_authenc_decrypt, + .givencrypt = aead_authenc_givencrypt, + .geniv = "", + .ivsize = AES_BLOCK_SIZE, + .maxauthsize = SHA256_DIGEST_SIZE, + }, + .class1_alg_type = OP_ALG_ALGSEL_AES | OP_ALG_AAI_CBC, + .class2_alg_type = OP_ALG_ALGSEL_SHA256 | + OP_ALG_AAI_HMAC_PRECOMP, + .alg_op = OP_ALG_ALGSEL_SHA256 | OP_ALG_AAI_HMAC, + }, + { + .name = "authenc(hmac(sha1),cbc(des3_ede))", + .driver_name = "authenc-hmac-sha1-cbc-des3_ede-caam", + .blocksize = DES3_EDE_BLOCK_SIZE, + .aead = { + .setkey = aead_authenc_setkey, + .setauthsize = aead_authenc_setauthsize, + .encrypt = aead_authenc_encrypt, + .decrypt = aead_authenc_decrypt, + .givencrypt = aead_authenc_givencrypt, + .geniv = "", + .ivsize = DES3_EDE_BLOCK_SIZE, + .maxauthsize = SHA1_DIGEST_SIZE, + }, + .class1_alg_type = OP_ALG_ALGSEL_3DES | OP_ALG_AAI_CBC, + .class2_alg_type = OP_ALG_ALGSEL_SHA1 | OP_ALG_AAI_HMAC_PRECOMP, + .alg_op = OP_ALG_ALGSEL_SHA1 | OP_ALG_AAI_HMAC, + }, + { + .name = "authenc(hmac(sha256),cbc(des3_ede))", + .driver_name = "authenc-hmac-sha256-cbc-des3_ede-caam", + .blocksize = DES3_EDE_BLOCK_SIZE, + .aead = { + .setkey = aead_authenc_setkey, + .setauthsize = aead_authenc_setauthsize, + .encrypt = aead_authenc_encrypt, + .decrypt = aead_authenc_decrypt, + .givencrypt = aead_authenc_givencrypt, + .geniv = "", + .ivsize = DES3_EDE_BLOCK_SIZE, + .maxauthsize = SHA256_DIGEST_SIZE, + }, + .class1_alg_type = OP_ALG_ALGSEL_3DES | OP_ALG_AAI_CBC, + .class2_alg_type = OP_ALG_ALGSEL_SHA256 | + OP_ALG_AAI_HMAC_PRECOMP, + .alg_op = OP_ALG_ALGSEL_SHA256 | OP_ALG_AAI_HMAC, + }, + { + .name = "authenc(hmac(sha1),cbc(des))", + .driver_name = "authenc-hmac-sha1-cbc-des-caam", + .blocksize = DES_BLOCK_SIZE, + .aead = { + .setkey = aead_authenc_setkey, + .setauthsize = aead_authenc_setauthsize, + .encrypt = aead_authenc_encrypt, + .decrypt = aead_authenc_decrypt, + .givencrypt = aead_authenc_givencrypt, + .geniv = "", + .ivsize = DES_BLOCK_SIZE, + .maxauthsize = SHA1_DIGEST_SIZE, + }, + .class1_alg_type = OP_ALG_ALGSEL_DES | OP_ALG_AAI_CBC, + .class2_alg_type = OP_ALG_ALGSEL_SHA1 | OP_ALG_AAI_HMAC_PRECOMP, + .alg_op = OP_ALG_ALGSEL_SHA1 | OP_ALG_AAI_HMAC, + }, + { + .name = "authenc(hmac(sha256),cbc(des))", + .driver_name = "authenc-hmac-sha256-cbc-des-caam", + .blocksize = DES_BLOCK_SIZE, + .aead = { + .setkey = aead_authenc_setkey, + .setauthsize = aead_authenc_setauthsize, + .encrypt = aead_authenc_encrypt, + .decrypt = aead_authenc_decrypt, + .givencrypt = aead_authenc_givencrypt, + .geniv = "", + .ivsize = DES_BLOCK_SIZE, + .maxauthsize = SHA256_DIGEST_SIZE, + }, + .class1_alg_type = OP_ALG_ALGSEL_DES | OP_ALG_AAI_CBC, + .class2_alg_type = OP_ALG_ALGSEL_SHA256 | + OP_ALG_AAI_HMAC_PRECOMP, + .alg_op = OP_ALG_ALGSEL_SHA256 | OP_ALG_AAI_HMAC, + }, +}; + +struct caam_crypto_alg { + struct list_head entry; + struct device *ctrldev; + int class1_alg_type; + int class2_alg_type; + int alg_op; + struct crypto_alg crypto_alg; +}; + +static int caam_cra_init(struct crypto_tfm *tfm) +{ + struct crypto_alg *alg = tfm->__crt_alg; + struct caam_crypto_alg *caam_alg = + container_of(alg, struct caam_crypto_alg, crypto_alg); + struct caam_ctx *ctx = crypto_tfm_ctx(tfm); + struct caam_drv_private *priv = dev_get_drvdata(caam_alg->ctrldev); + int tgt_jr = atomic_inc_return(&priv->tfm_count); + + /* + * distribute tfms across job rings to ensure in-order + * crypto request processing per tfm + */ + ctx->jrdev = priv->algapi_jr[(tgt_jr / 2) % priv->num_jrs_for_algapi]; + + /* copy descriptor header template value */ + ctx->class1_alg_type = OP_TYPE_CLASS1_ALG | caam_alg->class1_alg_type; + ctx->class2_alg_type = OP_TYPE_CLASS2_ALG | caam_alg->class2_alg_type; + ctx->alg_op = OP_TYPE_CLASS2_ALG | caam_alg->alg_op; + + return 0; +} + +static void caam_cra_exit(struct crypto_tfm *tfm) +{ + struct caam_ctx *ctx = crypto_tfm_ctx(tfm); + + if (!dma_mapping_error(ctx->jrdev, ctx->shared_desc_phys)) + dma_unmap_single(ctx->jrdev, ctx->shared_desc_phys, + desc_bytes(ctx->sh_desc), DMA_TO_DEVICE); + kfree(ctx->sh_desc); +} + +static void __exit caam_algapi_exit(void) +{ + + struct device_node *dev_node; + struct platform_device *pdev; + struct device *ctrldev; + struct caam_drv_private *priv; + struct caam_crypto_alg *t_alg, *n; + int i, err; + + dev_node = of_find_compatible_node(NULL, NULL, "fsl,sec4.0"); + if (!dev_node) + return; + + pdev = of_find_device_by_node(dev_node); + if (!pdev) + return; + + ctrldev = &pdev->dev; + of_node_put(dev_node); + priv = dev_get_drvdata(ctrldev); + + if (!priv->alg_list.next) + return; + + list_for_each_entry_safe(t_alg, n, &priv->alg_list, entry) { + crypto_unregister_alg(&t_alg->crypto_alg); + list_del(&t_alg->entry); + kfree(t_alg); + } + + for (i = 0; i < priv->total_jobrs; i++) { + err = caam_jr_deregister(priv->algapi_jr[i]); + if (err < 0) + break; + } + kfree(priv->algapi_jr); +} + +static struct caam_crypto_alg *caam_alg_alloc(struct device *ctrldev, + struct caam_alg_template + *template) +{ + struct caam_crypto_alg *t_alg; + struct crypto_alg *alg; + + t_alg = kzalloc(sizeof(struct caam_crypto_alg), GFP_KERNEL); + if (!t_alg) { + dev_err(ctrldev, "failed to allocate t_alg\n"); + return ERR_PTR(-ENOMEM); + } + + alg = &t_alg->crypto_alg; + + snprintf(alg->cra_name, CRYPTO_MAX_ALG_NAME, "%s", template->name); + snprintf(alg->cra_driver_name, CRYPTO_MAX_ALG_NAME, "%s", + template->driver_name); + alg->cra_module = THIS_MODULE; + alg->cra_init = caam_cra_init; + alg->cra_exit = caam_cra_exit; + alg->cra_priority = CAAM_CRA_PRIORITY; + alg->cra_flags = CRYPTO_ALG_TYPE_AEAD | CRYPTO_ALG_ASYNC; + alg->cra_blocksize = template->blocksize; + alg->cra_alignmask = 0; + alg->cra_type = &crypto_aead_type; + alg->cra_ctxsize = sizeof(struct caam_ctx); + alg->cra_u.aead = template->aead; + + t_alg->class1_alg_type = template->class1_alg_type; + t_alg->class2_alg_type = template->class2_alg_type; + t_alg->alg_op = template->alg_op; + t_alg->ctrldev = ctrldev; + + return t_alg; +} + +static int __init caam_algapi_init(void) +{ + struct device_node *dev_node; + struct platform_device *pdev; + struct device *ctrldev, **jrdev; + struct caam_drv_private *priv; + int i = 0, err = 0; + + dev_node = of_find_compatible_node(NULL, NULL, "fsl,sec4.0"); + if (!dev_node) + return -ENODEV; + + pdev = of_find_device_by_node(dev_node); + if (!pdev) + return -ENODEV; + + ctrldev = &pdev->dev; + priv = dev_get_drvdata(ctrldev); + of_node_put(dev_node); + + INIT_LIST_HEAD(&priv->alg_list); + + jrdev = kmalloc(sizeof(*jrdev) * priv->total_jobrs, GFP_KERNEL); + if (!jrdev) + return -ENOMEM; + + for (i = 0; i < priv->total_jobrs; i++) { + err = caam_jr_register(ctrldev, &jrdev[i]); + if (err < 0) + break; + } + if (err < 0 && i == 0) { + dev_err(ctrldev, "algapi error in job ring registration: %d\n", + err); + return err; + } + + priv->num_jrs_for_algapi = i; + priv->algapi_jr = jrdev; + atomic_set(&priv->tfm_count, -1); + + /* register crypto algorithms the device supports */ + for (i = 0; i < ARRAY_SIZE(driver_algs); i++) { + /* TODO: check if h/w supports alg */ + struct caam_crypto_alg *t_alg; + + t_alg = caam_alg_alloc(ctrldev, &driver_algs[i]); + if (IS_ERR(t_alg)) { + err = PTR_ERR(t_alg); + dev_warn(ctrldev, "%s alg allocation failed\n", + t_alg->crypto_alg.cra_driver_name); + continue; + } + + err = crypto_register_alg(&t_alg->crypto_alg); + if (err) { + dev_warn(ctrldev, "%s alg registration failed\n", + t_alg->crypto_alg.cra_driver_name); + kfree(t_alg); + } else { + list_add_tail(&t_alg->entry, &priv->alg_list); + dev_info(ctrldev, "%s\n", + t_alg->crypto_alg.cra_driver_name); + } + } + + return err; +} + +module_init(caam_algapi_init); +module_exit(caam_algapi_exit); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("FSL CAAM support for crypto API"); +MODULE_AUTHOR("Freescale Semiconductor - NMG/STC"); diff --git a/drivers/crypto/caam/compat.h b/drivers/crypto/caam/compat.h new file mode 100644 index 0000000..9504503 --- /dev/null +++ b/drivers/crypto/caam/compat.h @@ -0,0 +1,35 @@ +/* + * Copyright 2008-2011 Freescale Semiconductor, Inc. + */ + +#ifndef CAAM_COMPAT_H +#define CAAM_COMPAT_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#endif /* !defined(CAAM_COMPAT_H) */ diff --git a/drivers/crypto/caam/ctrl.c b/drivers/crypto/caam/ctrl.c new file mode 100644 index 0000000..aa221616 --- /dev/null +++ b/drivers/crypto/caam/ctrl.c @@ -0,0 +1,270 @@ +/* + * CAAM control-plane driver backend + * Controller-level driver, kernel property detection, initialization + * + * Copyright 2008-2011 Freescale Semiconductor, Inc. + */ + +#include "compat.h" +#include "regs.h" +#include "intern.h" +#include "jr.h" + +static int caam_remove(struct platform_device *pdev) +{ + struct device *ctrldev; + struct caam_drv_private *ctrlpriv; + struct caam_drv_private_jr *jrpriv; + struct caam_full __iomem *topregs; + int ring, ret = 0; + + ctrldev = &pdev->dev; + ctrlpriv = dev_get_drvdata(ctrldev); + topregs = (struct caam_full __iomem *)ctrlpriv->ctrl; + + /* shut down JobRs */ + for (ring = 0; ring < ctrlpriv->total_jobrs; ring++) { + ret |= caam_jr_shutdown(ctrlpriv->jrdev[ring]); + jrpriv = dev_get_drvdata(ctrlpriv->jrdev[ring]); + irq_dispose_mapping(jrpriv->irq); + } + + /* Shut down debug views */ +#ifdef CONFIG_DEBUG_FS + debugfs_remove_recursive(ctrlpriv->dfs_root); +#endif + + /* Unmap controller region */ + iounmap(&topregs->ctrl); + + kfree(ctrlpriv->jrdev); + kfree(ctrlpriv); + + return ret; +} + +/* Probe routine for CAAM top (controller) level */ +static int caam_probe(struct platform_device *pdev, + const struct of_device_id *devmatch) +{ + int d, ring, rspec; + struct device *dev; + struct device_node *nprop, *np; + struct caam_ctrl __iomem *ctrl; + struct caam_full __iomem *topregs; + struct caam_drv_private *ctrlpriv; + struct caam_perfmon *perfmon; + struct caam_deco **deco; + u32 deconum; + + ctrlpriv = kzalloc(sizeof(struct caam_drv_private), GFP_KERNEL); + if (!ctrlpriv) + return -ENOMEM; + + dev = &pdev->dev; + dev_set_drvdata(dev, ctrlpriv); + ctrlpriv->pdev = pdev; + nprop = pdev->dev.of_node; + + /* Get configuration properties from device tree */ + /* First, get register page */ + ctrl = of_iomap(nprop, 0); + if (ctrl == NULL) { + dev_err(dev, "caam: of_iomap() failed\n"); + return -ENOMEM; + } + ctrlpriv->ctrl = (struct caam_ctrl __force *)ctrl; + + /* topregs used to derive pointers to CAAM sub-blocks only */ + topregs = (struct caam_full __iomem *)ctrl; + + /* Get the IRQ of the controller (for security violations only) */ + ctrlpriv->secvio_irq = of_irq_to_resource(nprop, 0, NULL); + + /* + * Enable DECO watchdogs and, if this is a PHYS_ADDR_T_64BIT kernel, + * 36-bit pointers in master configuration register + */ + setbits32(&topregs->ctrl.mcr, MCFGR_WDENABLE | + (sizeof(dma_addr_t) == sizeof(u64) ? MCFGR_LONG_PTR : 0)); + + if (sizeof(dma_addr_t) == sizeof(u64)) + dma_set_mask(dev, DMA_BIT_MASK(36)); + + /* Find out how many DECOs are present */ + deconum = (rd_reg64(&topregs->ctrl.perfmon.cha_num) & + CHA_NUM_DECONUM_MASK) >> CHA_NUM_DECONUM_SHIFT; + + ctrlpriv->deco = kmalloc(deconum * sizeof(struct caam_deco *), + GFP_KERNEL); + + deco = (struct caam_deco __force **)&topregs->deco; + for (d = 0; d < deconum; d++) + ctrlpriv->deco[d] = deco[d]; + + /* + * Detect and enable JobRs + * First, find out how many ring spec'ed, allocate references + * for all, then go probe each one. + */ + rspec = 0; + for_each_compatible_node(np, NULL, "fsl,sec4.0-job-ring") + rspec++; + ctrlpriv->jrdev = kzalloc(sizeof(struct device *) * rspec, GFP_KERNEL); + if (ctrlpriv->jrdev == NULL) { + iounmap(&topregs->ctrl); + return -ENOMEM; + } + + ring = 0; + ctrlpriv->total_jobrs = 0; + for_each_compatible_node(np, NULL, "fsl,sec4.0-job-ring") { + caam_jr_probe(pdev, np, ring); + ctrlpriv->total_jobrs++; + ring++; + } + + /* Check to see if QI present. If so, enable */ + ctrlpriv->qi_present = !!(rd_reg64(&topregs->ctrl.perfmon.comp_parms) & + CTPR_QI_MASK); + if (ctrlpriv->qi_present) { + ctrlpriv->qi = (struct caam_queue_if __force *)&topregs->qi; + /* This is all that's required to physically enable QI */ + wr_reg32(&topregs->qi.qi_control_lo, QICTL_DQEN); + } + + /* If no QI and no rings specified, quit and go home */ + if ((!ctrlpriv->qi_present) && (!ctrlpriv->total_jobrs)) { + dev_err(dev, "no queues configured, terminating\n"); + caam_remove(pdev); + return -ENOMEM; + } + + /* NOTE: RTIC detection ought to go here, around Si time */ + + /* Initialize queue allocator lock */ + spin_lock_init(&ctrlpriv->jr_alloc_lock); + + /* Report "alive" for developer to see */ + dev_info(dev, "device ID = 0x%016llx\n", + rd_reg64(&topregs->ctrl.perfmon.caam_id)); + dev_info(dev, "job rings = %d, qi = %d\n", + ctrlpriv->total_jobrs, ctrlpriv->qi_present); + +#ifdef CONFIG_DEBUG_FS + /* + * FIXME: needs better naming distinction, as some amalgamation of + * "caam" and nprop->full_name. The OF name isn't distinctive, + * but does separate instances + */ + perfmon = (struct caam_perfmon __force *)&ctrl->perfmon; + + ctrlpriv->dfs_root = debugfs_create_dir("caam", NULL); + ctrlpriv->ctl = debugfs_create_dir("ctl", ctrlpriv->dfs_root); + + /* Controller-level - performance monitor counters */ + ctrlpriv->ctl_rq_dequeued = + debugfs_create_u64("rq_dequeued", + S_IFCHR | S_IRUSR | S_IRGRP | S_IROTH, + ctrlpriv->ctl, &perfmon->req_dequeued); + ctrlpriv->ctl_ob_enc_req = + debugfs_create_u64("ob_rq_encrypted", + S_IFCHR | S_IRUSR | S_IRGRP | S_IROTH, + ctrlpriv->ctl, &perfmon->ob_enc_req); + ctrlpriv->ctl_ib_dec_req = + debugfs_create_u64("ib_rq_decrypted", + S_IFCHR | S_IRUSR | S_IRGRP | S_IROTH, + ctrlpriv->ctl, &perfmon->ib_dec_req); + ctrlpriv->ctl_ob_enc_bytes = + debugfs_create_u64("ob_bytes_encrypted", + S_IFCHR | S_IRUSR | S_IRGRP | S_IROTH, + ctrlpriv->ctl, &perfmon->ob_enc_bytes); + ctrlpriv->ctl_ob_prot_bytes = + debugfs_create_u64("ob_bytes_protected", + S_IFCHR | S_IRUSR | S_IRGRP | S_IROTH, + ctrlpriv->ctl, &perfmon->ob_prot_bytes); + ctrlpriv->ctl_ib_dec_bytes = + debugfs_create_u64("ib_bytes_decrypted", + S_IFCHR | S_IRUSR | S_IRGRP | S_IROTH, + ctrlpriv->ctl, &perfmon->ib_dec_bytes); + ctrlpriv->ctl_ib_valid_bytes = + debugfs_create_u64("ib_bytes_validated", + S_IFCHR | S_IRUSR | S_IRGRP | S_IROTH, + ctrlpriv->ctl, &perfmon->ib_valid_bytes); + + /* Controller level - global status values */ + ctrlpriv->ctl_faultaddr = + debugfs_create_u64("fault_addr", + S_IFCHR | S_IRUSR | S_IRGRP | S_IROTH, + ctrlpriv->ctl, &perfmon->faultaddr); + ctrlpriv->ctl_faultdetail = + debugfs_create_u32("fault_detail", + S_IFCHR | S_IRUSR | S_IRGRP | S_IROTH, + ctrlpriv->ctl, &perfmon->faultdetail); + ctrlpriv->ctl_faultstatus = + debugfs_create_u32("fault_status", + S_IFCHR | S_IRUSR | S_IRGRP | S_IROTH, + ctrlpriv->ctl, &perfmon->status); + + /* Internal covering keys (useful in non-secure mode only) */ + ctrlpriv->ctl_kek_wrap.data = &ctrlpriv->ctrl->kek[0]; + ctrlpriv->ctl_kek_wrap.size = KEK_KEY_SIZE * sizeof(u32); + ctrlpriv->ctl_kek = debugfs_create_blob("kek", + S_IFCHR | S_IRUSR | + S_IRGRP | S_IROTH, + ctrlpriv->ctl, + &ctrlpriv->ctl_kek_wrap); + + ctrlpriv->ctl_tkek_wrap.data = &ctrlpriv->ctrl->tkek[0]; + ctrlpriv->ctl_tkek_wrap.size = KEK_KEY_SIZE * sizeof(u32); + ctrlpriv->ctl_tkek = debugfs_create_blob("tkek", + S_IFCHR | S_IRUSR | + S_IRGRP | S_IROTH, + ctrlpriv->ctl, + &ctrlpriv->ctl_tkek_wrap); + + ctrlpriv->ctl_tdsk_wrap.data = &ctrlpriv->ctrl->tdsk[0]; + ctrlpriv->ctl_tdsk_wrap.size = KEK_KEY_SIZE * sizeof(u32); + ctrlpriv->ctl_tdsk = debugfs_create_blob("tdsk", + S_IFCHR | S_IRUSR | + S_IRGRP | S_IROTH, + ctrlpriv->ctl, + &ctrlpriv->ctl_tdsk_wrap); +#endif + return 0; +} + +static struct of_device_id caam_match[] = { + { + .compatible = "fsl,sec4.0", + }, + {}, +}; +MODULE_DEVICE_TABLE(of, caam_match); + +static struct of_platform_driver caam_driver = { + .driver = { + .name = "caam", + .owner = THIS_MODULE, + .of_match_table = caam_match, + }, + .probe = caam_probe, + .remove = __devexit_p(caam_remove), +}; + +static int __init caam_base_init(void) +{ + return of_register_platform_driver(&caam_driver); +} + +static void __exit caam_base_exit(void) +{ + return of_unregister_platform_driver(&caam_driver); +} + +module_init(caam_base_init); +module_exit(caam_base_exit); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("FSL CAAM request backend"); +MODULE_AUTHOR("Freescale Semiconductor - NMG/STC"); diff --git a/drivers/crypto/caam/desc.h b/drivers/crypto/caam/desc.h new file mode 100644 index 0000000..974a758 --- /dev/null +++ b/drivers/crypto/caam/desc.h @@ -0,0 +1,1605 @@ +/* + * CAAM descriptor composition header + * Definitions to support CAAM descriptor instruction generation + * + * Copyright 2008-2011 Freescale Semiconductor, Inc. + */ + +#ifndef DESC_H +#define DESC_H + +/* Max size of any CAAM descriptor in 32-bit words, inclusive of header */ +#define MAX_CAAM_DESCSIZE 64 + +/* Block size of any entity covered/uncovered with a KEK/TKEK */ +#define KEK_BLOCKSIZE 16 + +/* + * Supported descriptor command types as they show up + * inside a descriptor command word. + */ +#define CMD_SHIFT 27 +#define CMD_MASK 0xf8000000 + +#define CMD_KEY (0x00 << CMD_SHIFT) +#define CMD_SEQ_KEY (0x01 << CMD_SHIFT) +#define CMD_LOAD (0x02 << CMD_SHIFT) +#define CMD_SEQ_LOAD (0x03 << CMD_SHIFT) +#define CMD_FIFO_LOAD (0x04 << CMD_SHIFT) +#define CMD_SEQ_FIFO_LOAD (0x05 << CMD_SHIFT) +#define CMD_STORE (0x0a << CMD_SHIFT) +#define CMD_SEQ_STORE (0x0b << CMD_SHIFT) +#define CMD_FIFO_STORE (0x0c << CMD_SHIFT) +#define CMD_SEQ_FIFO_STORE (0x0d << CMD_SHIFT) +#define CMD_MOVE_LEN (0x0e << CMD_SHIFT) +#define CMD_MOVE (0x0f << CMD_SHIFT) +#define CMD_OPERATION (0x10 << CMD_SHIFT) +#define CMD_SIGNATURE (0x12 << CMD_SHIFT) +#define CMD_JUMP (0x14 << CMD_SHIFT) +#define CMD_MATH (0x15 << CMD_SHIFT) +#define CMD_DESC_HDR (0x16 << CMD_SHIFT) +#define CMD_SHARED_DESC_HDR (0x17 << CMD_SHIFT) +#define CMD_SEQ_IN_PTR (0x1e << CMD_SHIFT) +#define CMD_SEQ_OUT_PTR (0x1f << CMD_SHIFT) + +/* General-purpose class selector for all commands */ +#define CLASS_SHIFT 25 +#define CLASS_MASK (0x03 << CLASS_SHIFT) + +#define CLASS_NONE (0x00 << CLASS_SHIFT) +#define CLASS_1 (0x01 << CLASS_SHIFT) +#define CLASS_2 (0x02 << CLASS_SHIFT) +#define CLASS_BOTH (0x03 << CLASS_SHIFT) + +/* + * Descriptor header command constructs + * Covers shared, job, and trusted descriptor headers + */ + +/* + * Do Not Run - marks a descriptor inexecutable if there was + * a preceding error somewhere + */ +#define HDR_DNR 0x01000000 + +/* + * ONE - should always be set. Combination of ONE (always + * set) and ZRO (always clear) forms an endianness sanity check + */ +#define HDR_ONE 0x00800000 +#define HDR_ZRO 0x00008000 + +/* Start Index or SharedDesc Length */ +#define HDR_START_IDX_MASK 0x3f +#define HDR_START_IDX_SHIFT 16 + +/* If shared descriptor header, 6-bit length */ +#define HDR_DESCLEN_SHR_MASK 0x3f + +/* If non-shared header, 7-bit length */ +#define HDR_DESCLEN_MASK 0x7f + +/* This is a TrustedDesc (if not SharedDesc) */ +#define HDR_TRUSTED 0x00004000 + +/* Make into TrustedDesc (if not SharedDesc) */ +#define HDR_MAKE_TRUSTED 0x00002000 + +/* Save context if self-shared (if SharedDesc) */ +#define HDR_SAVECTX 0x00001000 + +/* Next item points to SharedDesc */ +#define HDR_SHARED 0x00001000 + +/* + * Reverse Execution Order - execute JobDesc first, then + * execute SharedDesc (normally SharedDesc goes first). + */ +#define HDR_REVERSE 0x00000800 + +/* Propogate DNR property to SharedDesc */ +#define HDR_PROP_DNR 0x00000800 + +/* JobDesc/SharedDesc share property */ +#define HDR_SD_SHARE_MASK 0x03 +#define HDR_SD_SHARE_SHIFT 8 +#define HDR_JD_SHARE_MASK 0x07 +#define HDR_JD_SHARE_SHIFT 8 + +#define HDR_SHARE_NEVER (0x00 << HDR_SD_SHARE_SHIFT) +#define HDR_SHARE_WAIT (0x01 << HDR_SD_SHARE_SHIFT) +#define HDR_SHARE_SERIAL (0x02 << HDR_SD_SHARE_SHIFT) +#define HDR_SHARE_ALWAYS (0x03 << HDR_SD_SHARE_SHIFT) +#define HDR_SHARE_DEFER (0x04 << HDR_SD_SHARE_SHIFT) + +/* JobDesc/SharedDesc descriptor length */ +#define HDR_JD_LENGTH_MASK 0x7f +#define HDR_SD_LENGTH_MASK 0x3f + +/* + * KEY/SEQ_KEY Command Constructs + */ + +/* Key Destination Class: 01 = Class 1, 02 - Class 2 */ +#define KEY_DEST_CLASS_SHIFT 25 /* use CLASS_1 or CLASS_2 */ +#define KEY_DEST_CLASS_MASK (0x03 << KEY_DEST_CLASS_SHIFT) + +/* Scatter-Gather Table/Variable Length Field */ +#define KEY_SGF 0x01000000 +#define KEY_VLF 0x01000000 + +/* Immediate - Key follows command in the descriptor */ +#define KEY_IMM 0x00800000 + +/* + * Encrypted - Key is encrypted either with the KEK, or + * with the TDKEK if TK is set + */ +#define KEY_ENC 0x00400000 + +/* + * No Write Back - Do not allow key to be FIFO STOREd + */ +#define KEY_NWB 0x00200000 + +/* + * Enhanced Encryption of Key + */ +#define KEY_EKT 0x00100000 + +/* + * Encrypted with Trusted Key + */ +#define KEY_TK 0x00008000 + +/* + * KDEST - Key Destination: 0 - class key register, + * 1 - PKHA 'e', 2 - AFHA Sbox, 3 - MDHA split-key + */ +#define KEY_DEST_SHIFT 16 +#define KEY_DEST_MASK (0x03 << KEY_DEST_SHIFT) + +#define KEY_DEST_CLASS_REG (0x00 << KEY_DEST_SHIFT) +#define KEY_DEST_PKHA_E (0x01 << KEY_DEST_SHIFT) +#define KEY_DEST_AFHA_SBOX (0x02 << KEY_DEST_SHIFT) +#define KEY_DEST_MDHA_SPLIT (0x03 << KEY_DEST_SHIFT) + +/* Length in bytes */ +#define KEY_LENGTH_MASK 0x000003ff + +/* + * LOAD/SEQ_LOAD/STORE/SEQ_STORE Command Constructs + */ + +/* + * Load/Store Destination: 0 = class independent CCB, + * 1 = class 1 CCB, 2 = class 2 CCB, 3 = DECO + */ +#define LDST_CLASS_SHIFT 25 +#define LDST_CLASS_MASK (0x03 << LDST_CLASS_SHIFT) +#define LDST_CLASS_IND_CCB (0x00 << LDST_CLASS_SHIFT) +#define LDST_CLASS_1_CCB (0x01 << LDST_CLASS_SHIFT) +#define LDST_CLASS_2_CCB (0x02 << LDST_CLASS_SHIFT) +#define LDST_CLASS_DECO (0x03 << LDST_CLASS_SHIFT) + +/* Scatter-Gather Table/Variable Length Field */ +#define LDST_SGF 0x01000000 +#define LDST_VLF LDST_SGF + +/* Immediate - Key follows this command in descriptor */ +#define LDST_IMM_MASK 1 +#define LDST_IMM_SHIFT 23 +#define LDST_IMM (LDST_IMM_MASK << LDST_IMM_SHIFT) + +/* SRC/DST - Destination for LOAD, Source for STORE */ +#define LDST_SRCDST_SHIFT 16 +#define LDST_SRCDST_MASK (0x7f << LDST_SRCDST_SHIFT) + +#define LDST_SRCDST_BYTE_CONTEXT (0x20 << LDST_SRCDST_SHIFT) +#define LDST_SRCDST_BYTE_KEY (0x40 << LDST_SRCDST_SHIFT) +#define LDST_SRCDST_BYTE_INFIFO (0x7c << LDST_SRCDST_SHIFT) +#define LDST_SRCDST_BYTE_OUTFIFO (0x7e << LDST_SRCDST_SHIFT) + +#define LDST_SRCDST_WORD_MODE_REG (0x00 << LDST_SRCDST_SHIFT) +#define LDST_SRCDST_WORD_KEYSZ_REG (0x01 << LDST_SRCDST_SHIFT) +#define LDST_SRCDST_WORD_DATASZ_REG (0x02 << LDST_SRCDST_SHIFT) +#define LDST_SRCDST_WORD_ICVSZ_REG (0x03 << LDST_SRCDST_SHIFT) +#define LDST_SRCDST_WORD_CHACTRL (0x06 << LDST_SRCDST_SHIFT) +#define LDST_SRCDST_WORD_DECOCTRL (0x06 << LDST_SRCDST_SHIFT) +#define LDST_SRCDST_WORD_IRQCTRL (0x07 << LDST_SRCDST_SHIFT) +#define LDST_SRCDST_WORD_DECO_PCLOVRD (0x07 << LDST_SRCDST_SHIFT) +#define LDST_SRCDST_WORD_CLRW (0x08 << LDST_SRCDST_SHIFT) +#define LDST_SRCDST_WORD_DECO_MATH0 (0x08 << LDST_SRCDST_SHIFT) +#define LDST_SRCDST_WORD_STAT (0x09 << LDST_SRCDST_SHIFT) +#define LDST_SRCDST_WORD_DECO_MATH1 (0x09 << LDST_SRCDST_SHIFT) +#define LDST_SRCDST_WORD_DECO_MATH2 (0x0a << LDST_SRCDST_SHIFT) +#define LDST_SRCDST_WORD_DECO_AAD_SZ (0x0b << LDST_SRCDST_SHIFT) +#define LDST_SRCDST_WORD_DECO_MATH3 (0x0b << LDST_SRCDST_SHIFT) +#define LDST_SRCDST_WORD_CLASS1_ICV_SZ (0x0c << LDST_SRCDST_SHIFT) +#define LDST_SRCDST_WORD_ALTDS_CLASS1 (0x0f << LDST_SRCDST_SHIFT) +#define LDST_SRCDST_WORD_PKHA_A_SZ (0x10 << LDST_SRCDST_SHIFT) +#define LDST_SRCDST_WORD_PKHA_B_SZ (0x11 << LDST_SRCDST_SHIFT) +#define LDST_SRCDST_WORD_PKHA_N_SZ (0x12 << LDST_SRCDST_SHIFT) +#define LDST_SRCDST_WORD_PKHA_E_SZ (0x13 << LDST_SRCDST_SHIFT) +#define LDST_SRCDST_WORD_DESCBUF (0x40 << LDST_SRCDST_SHIFT) +#define LDST_SRCDST_WORD_INFO_FIFO (0x7a << LDST_SRCDST_SHIFT) + +/* Offset in source/destination */ +#define LDST_OFFSET_SHIFT 8 +#define LDST_OFFSET_MASK (0xff << LDST_OFFSET_SHIFT) + +/* LDOFF definitions used when DST = LDST_SRCDST_WORD_DECOCTRL */ +/* These could also be shifted by LDST_OFFSET_SHIFT - this reads better */ +#define LDOFF_CHG_SHARE_SHIFT 0 +#define LDOFF_CHG_SHARE_MASK (0x3 << LDOFF_CHG_SHARE_SHIFT) +#define LDOFF_CHG_SHARE_NEVER (0x1 << LDOFF_CHG_SHARE_SHIFT) +#define LDOFF_CHG_SHARE_OK_NO_PROP (0x2 << LDOFF_CHG_SHARE_SHIFT) +#define LDOFF_CHG_SHARE_OK_PROP (0x3 << LDOFF_CHG_SHARE_SHIFT) + +#define LDOFF_ENABLE_AUTO_NFIFO (1 << 2) +#define LDOFF_DISABLE_AUTO_NFIFO (1 << 3) + +#define LDOFF_CHG_NONSEQLIODN_SHIFT 4 +#define LDOFF_CHG_NONSEQLIODN_MASK (0x3 << LDOFF_CHG_NONSEQLIODN_SHIFT) +#define LDOFF_CHG_NONSEQLIODN_SEQ (0x1 << LDOFF_CHG_NONSEQLIODN_SHIFT) +#define LDOFF_CHG_NONSEQLIODN_NON_SEQ (0x2 << LDOFF_CHG_NONSEQLIODN_SHIFT) +#define LDOFF_CHG_NONSEQLIODN_TRUSTED (0x3 << LDOFF_CHG_NONSEQLIODN_SHIFT) + +#define LDOFF_CHG_SEQLIODN_SHIFT 6 +#define LDOFF_CHG_SEQLIODN_MASK (0x3 << LDOFF_CHG_SEQLIODN_SHIFT) +#define LDOFF_CHG_SEQLIODN_SEQ (0x1 << LDOFF_CHG_SEQLIODN_SHIFT) +#define LDOFF_CHG_SEQLIODN_NON_SEQ (0x2 << LDOFF_CHG_SEQLIODN_SHIFT) +#define LDOFF_CHG_SEQLIODN_TRUSTED (0x3 << LDOFF_CHG_SEQLIODN_SHIFT) + +/* Data length in bytes */ +#define LDST_LEN_SHIFT 0 +#define LDST_LEN_MASK (0xff << LDST_LEN_SHIFT) + +/* Special Length definitions when dst=deco-ctrl */ +#define LDLEN_ENABLE_OSL_COUNT (1 << 7) +#define LDLEN_RST_CHA_OFIFO_PTR (1 << 6) +#define LDLEN_RST_OFIFO (1 << 5) +#define LDLEN_SET_OFIFO_OFF_VALID (1 << 4) +#define LDLEN_SET_OFIFO_OFF_RSVD (1 << 3) +#define LDLEN_SET_OFIFO_OFFSET_SHIFT 0 +#define LDLEN_SET_OFIFO_OFFSET_MASK (3 << LDLEN_SET_OFIFO_OFFSET_SHIFT) + +/* + * FIFO_LOAD/FIFO_STORE/SEQ_FIFO_LOAD/SEQ_FIFO_STORE + * Command Constructs + */ + +/* + * Load Destination: 0 = skip (SEQ_FIFO_LOAD only), + * 1 = Load for Class1, 2 = Load for Class2, 3 = Load both + * Store Source: 0 = normal, 1 = Class1key, 2 = Class2key + */ +#define FIFOLD_CLASS_SHIFT 25 +#define FIFOLD_CLASS_MASK (0x03 << FIFOLD_CLASS_SHIFT) +#define FIFOLD_CLASS_SKIP (0x00 << FIFOLD_CLASS_SHIFT) +#define FIFOLD_CLASS_CLASS1 (0x01 << FIFOLD_CLASS_SHIFT) +#define FIFOLD_CLASS_CLASS2 (0x02 << FIFOLD_CLASS_SHIFT) +#define FIFOLD_CLASS_BOTH (0x03 << FIFOLD_CLASS_SHIFT) + +#define FIFOST_CLASS_SHIFT 25 +#define FIFOST_CLASS_MASK (0x03 << FIFOST_CLASS_SHIFT) +#define FIFOST_CLASS_NORMAL (0x00 << FIFOST_CLASS_SHIFT) +#define FIFOST_CLASS_CLASS1KEY (0x01 << FIFOST_CLASS_SHIFT) +#define FIFOST_CLASS_CLASS2KEY (0x02 << FIFOST_CLASS_SHIFT) + +/* + * Scatter-Gather Table/Variable Length Field + * If set for FIFO_LOAD, refers to a SG table. Within + * SEQ_FIFO_LOAD, is variable input sequence + */ +#define FIFOLDST_SGF_SHIFT 24 +#define FIFOLDST_SGF_MASK (1 << FIFOLDST_SGF_SHIFT) +#define FIFOLDST_VLF_MASK (1 << FIFOLDST_SGF_SHIFT) +#define FIFOLDST_SGF (1 << FIFOLDST_SGF_SHIFT) +#define FIFOLDST_VLF (1 << FIFOLDST_SGF_SHIFT) + +/* Immediate - Data follows command in descriptor */ +#define FIFOLD_IMM_SHIFT 23 +#define FIFOLD_IMM_MASK (1 << FIFOLD_IMM_SHIFT) +#define FIFOLD_IMM (1 << FIFOLD_IMM_SHIFT) + +/* Continue - Not the last FIFO store to come */ +#define FIFOST_CONT_SHIFT 23 +#define FIFOST_CONT_MASK (1 << FIFOST_CONT_SHIFT) +#define FIFOST_CONT_MASK (1 << FIFOST_CONT_SHIFT) + +/* + * Extended Length - use 32-bit extended length that + * follows the pointer field. Illegal with IMM set + */ +#define FIFOLDST_EXT_SHIFT 22 +#define FIFOLDST_EXT_MASK (1 << FIFOLDST_EXT_SHIFT) +#define FIFOLDST_EXT (1 << FIFOLDST_EXT_SHIFT) + +/* Input data type.*/ +#define FIFOLD_TYPE_SHIFT 16 +#define FIFOLD_CONT_TYPE_SHIFT 19 /* shift past last-flush bits */ +#define FIFOLD_TYPE_MASK (0x3f << FIFOLD_TYPE_SHIFT) + +/* PK types */ +#define FIFOLD_TYPE_PK (0x00 << FIFOLD_TYPE_SHIFT) +#define FIFOLD_TYPE_PK_MASK (0x30 << FIFOLD_TYPE_SHIFT) +#define FIFOLD_TYPE_PK_TYPEMASK (0x0f << FIFOLD_TYPE_SHIFT) +#define FIFOLD_TYPE_PK_A0 (0x00 << FIFOLD_TYPE_SHIFT) +#define FIFOLD_TYPE_PK_A1 (0x01 << FIFOLD_TYPE_SHIFT) +#define FIFOLD_TYPE_PK_A2 (0x02 << FIFOLD_TYPE_SHIFT) +#define FIFOLD_TYPE_PK_A3 (0x03 << FIFOLD_TYPE_SHIFT) +#define FIFOLD_TYPE_PK_B0 (0x04 << FIFOLD_TYPE_SHIFT) +#define FIFOLD_TYPE_PK_B1 (0x05 << FIFOLD_TYPE_SHIFT) +#define FIFOLD_TYPE_PK_B2 (0x06 << FIFOLD_TYPE_SHIFT) +#define FIFOLD_TYPE_PK_B3 (0x07 << FIFOLD_TYPE_SHIFT) +#define FIFOLD_TYPE_PK_N (0x08 << FIFOLD_TYPE_SHIFT) +#define FIFOLD_TYPE_PK_A (0x0c << FIFOLD_TYPE_SHIFT) +#define FIFOLD_TYPE_PK_B (0x0d << FIFOLD_TYPE_SHIFT) + +/* Other types. Need to OR in last/flush bits as desired */ +#define FIFOLD_TYPE_MSG_MASK (0x38 << FIFOLD_TYPE_SHIFT) +#define FIFOLD_TYPE_MSG (0x10 << FIFOLD_TYPE_SHIFT) +#define FIFOLD_TYPE_MSG1OUT2 (0x18 << FIFOLD_TYPE_SHIFT) +#define FIFOLD_TYPE_IV (0x20 << FIFOLD_TYPE_SHIFT) +#define FIFOLD_TYPE_BITDATA (0x28 << FIFOLD_TYPE_SHIFT) +#define FIFOLD_TYPE_AAD (0x30 << FIFOLD_TYPE_SHIFT) +#define FIFOLD_TYPE_ICV (0x38 << FIFOLD_TYPE_SHIFT) + +/* Last/Flush bits for use with "other" types above */ +#define FIFOLD_TYPE_ACT_MASK (0x07 << FIFOLD_TYPE_SHIFT) +#define FIFOLD_TYPE_NOACTION (0x00 << FIFOLD_TYPE_SHIFT) +#define FIFOLD_TYPE_FLUSH1 (0x01 << FIFOLD_TYPE_SHIFT) +#define FIFOLD_TYPE_LAST1 (0x02 << FIFOLD_TYPE_SHIFT) +#define FIFOLD_TYPE_LAST2FLUSH (0x03 << FIFOLD_TYPE_SHIFT) +#define FIFOLD_TYPE_LAST2 (0x04 << FIFOLD_TYPE_SHIFT) +#define FIFOLD_TYPE_LAST2FLUSH1 (0x05 << FIFOLD_TYPE_SHIFT) +#define FIFOLD_TYPE_LASTBOTH (0x06 << FIFOLD_TYPE_SHIFT) +#define FIFOLD_TYPE_LASTBOTHFL (0x07 << FIFOLD_TYPE_SHIFT) + +#define FIFOLDST_LEN_MASK 0xffff +#define FIFOLDST_EXT_LEN_MASK 0xffffffff + +/* Output data types */ +#define FIFOST_TYPE_SHIFT 16 +#define FIFOST_TYPE_MASK (0x3f << FIFOST_TYPE_SHIFT) + +#define FIFOST_TYPE_PKHA_A0 (0x00 << FIFOST_TYPE_SHIFT) +#define FIFOST_TYPE_PKHA_A1 (0x01 << FIFOST_TYPE_SHIFT) +#define FIFOST_TYPE_PKHA_A2 (0x02 << FIFOST_TYPE_SHIFT) +#define FIFOST_TYPE_PKHA_A3 (0x03 << FIFOST_TYPE_SHIFT) +#define FIFOST_TYPE_PKHA_B0 (0x04 << FIFOST_TYPE_SHIFT) +#define FIFOST_TYPE_PKHA_B1 (0x05 << FIFOST_TYPE_SHIFT) +#define FIFOST_TYPE_PKHA_B2 (0x06 << FIFOST_TYPE_SHIFT) +#define FIFOST_TYPE_PKHA_B3 (0x07 << FIFOST_TYPE_SHIFT) +#define FIFOST_TYPE_PKHA_N (0x08 << FIFOST_TYPE_SHIFT) +#define FIFOST_TYPE_PKHA_A (0x0c << FIFOST_TYPE_SHIFT) +#define FIFOST_TYPE_PKHA_B (0x0d << FIFOST_TYPE_SHIFT) +#define FIFOST_TYPE_AF_SBOX_JKEK (0x10 << FIFOST_TYPE_SHIFT) +#define FIFOST_TYPE_AF_SBOX_TKEK (0x21 << FIFOST_TYPE_SHIFT) +#define FIFOST_TYPE_PKHA_E_JKEK (0x22 << FIFOST_TYPE_SHIFT) +#define FIFOST_TYPE_PKHA_E_TKEK (0x23 << FIFOST_TYPE_SHIFT) +#define FIFOST_TYPE_KEY_KEK (0x24 << FIFOST_TYPE_SHIFT) +#define FIFOST_TYPE_KEY_TKEK (0x25 << FIFOST_TYPE_SHIFT) +#define FIFOST_TYPE_SPLIT_KEK (0x26 << FIFOST_TYPE_SHIFT) +#define FIFOST_TYPE_SPLIT_TKEK (0x27 << FIFOST_TYPE_SHIFT) +#define FIFOST_TYPE_OUTFIFO_KEK (0x28 << FIFOST_TYPE_SHIFT) +#define FIFOST_TYPE_OUTFIFO_TKEK (0x29 << FIFOST_TYPE_SHIFT) +#define FIFOST_TYPE_MESSAGE_DATA (0x30 << FIFOST_TYPE_SHIFT) +#define FIFOST_TYPE_RNGSTORE (0x34 << FIFOST_TYPE_SHIFT) +#define FIFOST_TYPE_RNGFIFO (0x35 << FIFOST_TYPE_SHIFT) +#define FIFOST_TYPE_SKIP (0x3f << FIFOST_TYPE_SHIFT) + +/* + * OPERATION Command Constructs + */ + +/* Operation type selectors - OP TYPE */ +#define OP_TYPE_SHIFT 24 +#define OP_TYPE_MASK (0x07 << OP_TYPE_SHIFT) + +#define OP_TYPE_UNI_PROTOCOL (0x00 << OP_TYPE_SHIFT) +#define OP_TYPE_PK (0x01 << OP_TYPE_SHIFT) +#define OP_TYPE_CLASS1_ALG (0x02 << OP_TYPE_SHIFT) +#define OP_TYPE_CLASS2_ALG (0x04 << OP_TYPE_SHIFT) +#define OP_TYPE_DECAP_PROTOCOL (0x06 << OP_TYPE_SHIFT) +#define OP_TYPE_ENCAP_PROTOCOL (0x07 << OP_TYPE_SHIFT) + +/* ProtocolID selectors - PROTID */ +#define OP_PCLID_SHIFT 16 +#define OP_PCLID_MASK (0xff << 16) + +/* Assuming OP_TYPE = OP_TYPE_UNI_PROTOCOL */ +#define OP_PCLID_IKEV1_PRF (0x01 << OP_PCLID_SHIFT) +#define OP_PCLID_IKEV2_PRF (0x02 << OP_PCLID_SHIFT) +#define OP_PCLID_SSL30_PRF (0x08 << OP_PCLID_SHIFT) +#define OP_PCLID_TLS10_PRF (0x09 << OP_PCLID_SHIFT) +#define OP_PCLID_TLS11_PRF (0x0a << OP_PCLID_SHIFT) +#define OP_PCLID_DTLS10_PRF (0x0c << OP_PCLID_SHIFT) +#define OP_PCLID_PRF (0x06 << OP_PCLID_SHIFT) +#define OP_PCLID_BLOB (0x0d << OP_PCLID_SHIFT) +#define OP_PCLID_SECRETKEY (0x11 << OP_PCLID_SHIFT) +#define OP_PCLID_PUBLICKEYPAIR (0x14 << OP_PCLID_SHIFT) +#define OP_PCLID_DSASIGN (0x15 << OP_PCLID_SHIFT) +#define OP_PCLID_DSAVERIFY (0x16 << OP_PCLID_SHIFT) + +/* Assuming OP_TYPE = OP_TYPE_DECAP_PROTOCOL/ENCAP_PROTOCOL */ +#define OP_PCLID_IPSEC (0x01 << OP_PCLID_SHIFT) +#define OP_PCLID_SRTP (0x02 << OP_PCLID_SHIFT) +#define OP_PCLID_MACSEC (0x03 << OP_PCLID_SHIFT) +#define OP_PCLID_WIFI (0x04 << OP_PCLID_SHIFT) +#define OP_PCLID_WIMAX (0x05 << OP_PCLID_SHIFT) +#define OP_PCLID_SSL30 (0x08 << OP_PCLID_SHIFT) +#define OP_PCLID_TLS10 (0x09 << OP_PCLID_SHIFT) +#define OP_PCLID_TLS11 (0x0a << OP_PCLID_SHIFT) +#define OP_PCLID_TLS12 (0x0b << OP_PCLID_SHIFT) +#define OP_PCLID_DTLS (0x0c << OP_PCLID_SHIFT) + +/* + * ProtocolInfo selectors + */ +#define OP_PCLINFO_MASK 0xffff + +/* for OP_PCLID_IPSEC */ +#define OP_PCL_IPSEC_CIPHER_MASK 0xff00 +#define OP_PCL_IPSEC_AUTH_MASK 0x00ff + +#define OP_PCL_IPSEC_DES_IV64 0x0100 +#define OP_PCL_IPSEC_DES 0x0200 +#define OP_PCL_IPSEC_3DES 0x0300 +#define OP_PCL_IPSEC_AES_CBC 0x0c00 +#define OP_PCL_IPSEC_AES_CTR 0x0d00 +#define OP_PCL_IPSEC_AES_XTS 0x1600 +#define OP_PCL_IPSEC_AES_CCM8 0x0e00 +#define OP_PCL_IPSEC_AES_CCM12 0x0f00 +#define OP_PCL_IPSEC_AES_CCM16 0x1000 +#define OP_PCL_IPSEC_AES_GCM8 0x1200 +#define OP_PCL_IPSEC_AES_GCM12 0x1300 +#define OP_PCL_IPSEC_AES_GCM16 0x1400 + +#define OP_PCL_IPSEC_HMAC_NULL 0x0000 +#define OP_PCL_IPSEC_HMAC_MD5_96 0x0001 +#define OP_PCL_IPSEC_HMAC_SHA1_96 0x0002 +#define OP_PCL_IPSEC_AES_XCBC_MAC_96 0x0005 +#define OP_PCL_IPSEC_HMAC_MD5_128 0x0006 +#define OP_PCL_IPSEC_HMAC_SHA1_160 0x0007 +#define OP_PCL_IPSEC_HMAC_SHA2_256_128 0x000c +#define OP_PCL_IPSEC_HMAC_SHA2_384_192 0x000d +#define OP_PCL_IPSEC_HMAC_SHA2_512_256 0x000e + +/* For SRTP - OP_PCLID_SRTP */ +#define OP_PCL_SRTP_CIPHER_MASK 0xff00 +#define OP_PCL_SRTP_AUTH_MASK 0x00ff + +#define OP_PCL_SRTP_AES_CTR 0x0d00 + +#define OP_PCL_SRTP_HMAC_SHA1_160 0x0007 + +/* For SSL 3.0 - OP_PCLID_SSL30 */ +#define OP_PCL_SSL30_AES_128_CBC_SHA 0x002f +#define OP_PCL_SSL30_AES_128_CBC_SHA_2 0x0030 +#define OP_PCL_SSL30_AES_128_CBC_SHA_3 0x0031 +#define OP_PCL_SSL30_AES_128_CBC_SHA_4 0x0032 +#define OP_PCL_SSL30_AES_128_CBC_SHA_5 0x0033 +#define OP_PCL_SSL30_AES_128_CBC_SHA_6 0x0034 +#define OP_PCL_SSL30_AES_128_CBC_SHA_7 0x008c +#define OP_PCL_SSL30_AES_128_CBC_SHA_8 0x0090 +#define OP_PCL_SSL30_AES_128_CBC_SHA_9 0x0094 +#define OP_PCL_SSL30_AES_128_CBC_SHA_10 0xc004 +#define OP_PCL_SSL30_AES_128_CBC_SHA_11 0xc009 +#define OP_PCL_SSL30_AES_128_CBC_SHA_12 0xc00e +#define OP_PCL_SSL30_AES_128_CBC_SHA_13 0xc013 +#define OP_PCL_SSL30_AES_128_CBC_SHA_14 0xc018 +#define OP_PCL_SSL30_AES_128_CBC_SHA_15 0xc01d +#define OP_PCL_SSL30_AES_128_CBC_SHA_16 0xc01e +#define OP_PCL_SSL30_AES_128_CBC_SHA_17 0xc01f + +#define OP_PCL_SSL30_AES_256_CBC_SHA 0x0035 +#define OP_PCL_SSL30_AES_256_CBC_SHA_2 0x0036 +#define OP_PCL_SSL30_AES_256_CBC_SHA_3 0x0037 +#define OP_PCL_SSL30_AES_256_CBC_SHA_4 0x0038 +#define OP_PCL_SSL30_AES_256_CBC_SHA_5 0x0039 +#define OP_PCL_SSL30_AES_256_CBC_SHA_6 0x003a +#define OP_PCL_SSL30_AES_256_CBC_SHA_7 0x008d +#define OP_PCL_SSL30_AES_256_CBC_SHA_8 0x0091 +#define OP_PCL_SSL30_AES_256_CBC_SHA_9 0x0095 +#define OP_PCL_SSL30_AES_256_CBC_SHA_10 0xc005 +#define OP_PCL_SSL30_AES_256_CBC_SHA_11 0xc00a +#define OP_PCL_SSL30_AES_256_CBC_SHA_12 0xc00f +#define OP_PCL_SSL30_AES_256_CBC_SHA_13 0xc014 +#define OP_PCL_SSL30_AES_256_CBC_SHA_14 0xc019 +#define OP_PCL_SSL30_AES_256_CBC_SHA_15 0xc020 +#define OP_PCL_SSL30_AES_256_CBC_SHA_16 0xc021 +#define OP_PCL_SSL30_AES_256_CBC_SHA_17 0xc022 + +#define OP_PCL_SSL30_3DES_EDE_CBC_MD5 0x0023 + +#define OP_PCL_SSL30_3DES_EDE_CBC_SHA 0x001f +#define OP_PCL_SSL30_3DES_EDE_CBC_SHA_2 0x008b +#define OP_PCL_SSL30_3DES_EDE_CBC_SHA_3 0x008f +#define OP_PCL_SSL30_3DES_EDE_CBC_SHA_4 0x0093 +#define OP_PCL_SSL30_3DES_EDE_CBC_SHA_5 0x000a +#define OP_PCL_SSL30_3DES_EDE_CBC_SHA_6 0x000d +#define OP_PCL_SSL30_3DES_EDE_CBC_SHA_7 0x0010 +#define OP_PCL_SSL30_3DES_EDE_CBC_SHA_8 0x0013 +#define OP_PCL_SSL30_3DES_EDE_CBC_SHA_9 0x0016 +#define OP_PCL_SSL30_3DES_EDE_CBC_SHA_10 0x001b +#define OP_PCL_SSL30_3DES_EDE_CBC_SHA_11 0xc003 +#define OP_PCL_SSL30_3DES_EDE_CBC_SHA_12 0xc008 +#define OP_PCL_SSL30_3DES_EDE_CBC_SHA_13 0xc00d +#define OP_PCL_SSL30_3DES_EDE_CBC_SHA_14 0xc012 +#define OP_PCL_SSL30_3DES_EDE_CBC_SHA_15 0xc017 +#define OP_PCL_SSL30_3DES_EDE_CBC_SHA_16 0xc01a +#define OP_PCL_SSL30_3DES_EDE_CBC_SHA_17 0xc01b +#define OP_PCL_SSL30_3DES_EDE_CBC_SHA_18 0xc01c + +#define OP_PCL_SSL30_DES40_CBC_MD5 0x0029 + +#define OP_PCL_SSL30_DES_CBC_MD5 0x0022 + +#define OP_PCL_SSL30_DES40_CBC_SHA 0x0008 +#define OP_PCL_SSL30_DES40_CBC_SHA_2 0x000b +#define OP_PCL_SSL30_DES40_CBC_SHA_3 0x000e +#define OP_PCL_SSL30_DES40_CBC_SHA_4 0x0011 +#define OP_PCL_SSL30_DES40_CBC_SHA_5 0x0014 +#define OP_PCL_SSL30_DES40_CBC_SHA_6 0x0019 +#define OP_PCL_SSL30_DES40_CBC_SHA_7 0x0026 + +#define OP_PCL_SSL30_DES_CBC_SHA 0x001e +#define OP_PCL_SSL30_DES_CBC_SHA_2 0x0009 +#define OP_PCL_SSL30_DES_CBC_SHA_3 0x000c +#define OP_PCL_SSL30_DES_CBC_SHA_4 0x000f +#define OP_PCL_SSL30_DES_CBC_SHA_5 0x0012 +#define OP_PCL_SSL30_DES_CBC_SHA_6 0x0015 +#define OP_PCL_SSL30_DES_CBC_SHA_7 0x001a + +#define OP_PCL_SSL30_RC4_128_MD5 0x0024 +#define OP_PCL_SSL30_RC4_128_MD5_2 0x0004 +#define OP_PCL_SSL30_RC4_128_MD5_3 0x0018 + +#define OP_PCL_SSL30_RC4_40_MD5 0x002b +#define OP_PCL_SSL30_RC4_40_MD5_2 0x0003 +#define OP_PCL_SSL30_RC4_40_MD5_3 0x0017 + +#define OP_PCL_SSL30_RC4_128_SHA 0x0020 +#define OP_PCL_SSL30_RC4_128_SHA_2 0x008a +#define OP_PCL_SSL30_RC4_128_SHA_3 0x008e +#define OP_PCL_SSL30_RC4_128_SHA_4 0x0092 +#define OP_PCL_SSL30_RC4_128_SHA_5 0x0005 +#define OP_PCL_SSL30_RC4_128_SHA_6 0xc002 +#define OP_PCL_SSL30_RC4_128_SHA_7 0xc007 +#define OP_PCL_SSL30_RC4_128_SHA_8 0xc00c +#define OP_PCL_SSL30_RC4_128_SHA_9 0xc011 +#define OP_PCL_SSL30_RC4_128_SHA_10 0xc016 + +#define OP_PCL_SSL30_RC4_40_SHA 0x0028 + + +/* For TLS 1.0 - OP_PCLID_TLS10 */ +#define OP_PCL_TLS10_AES_128_CBC_SHA 0x002f +#define OP_PCL_TLS10_AES_128_CBC_SHA_2 0x0030 +#define OP_PCL_TLS10_AES_128_CBC_SHA_3 0x0031 +#define OP_PCL_TLS10_AES_128_CBC_SHA_4 0x0032 +#define OP_PCL_TLS10_AES_128_CBC_SHA_5 0x0033 +#define OP_PCL_TLS10_AES_128_CBC_SHA_6 0x0034 +#define OP_PCL_TLS10_AES_128_CBC_SHA_7 0x008c +#define OP_PCL_TLS10_AES_128_CBC_SHA_8 0x0090 +#define OP_PCL_TLS10_AES_128_CBC_SHA_9 0x0094 +#define OP_PCL_TLS10_AES_128_CBC_SHA_10 0xc004 +#define OP_PCL_TLS10_AES_128_CBC_SHA_11 0xc009 +#define OP_PCL_TLS10_AES_128_CBC_SHA_12 0xc00e +#define OP_PCL_TLS10_AES_128_CBC_SHA_13 0xc013 +#define OP_PCL_TLS10_AES_128_CBC_SHA_14 0xc018 +#define OP_PCL_TLS10_AES_128_CBC_SHA_15 0xc01d +#define OP_PCL_TLS10_AES_128_CBC_SHA_16 0xc01e +#define OP_PCL_TLS10_AES_128_CBC_SHA_17 0xc01f + +#define OP_PCL_TLS10_AES_256_CBC_SHA 0x0035 +#define OP_PCL_TLS10_AES_256_CBC_SHA_2 0x0036 +#define OP_PCL_TLS10_AES_256_CBC_SHA_3 0x0037 +#define OP_PCL_TLS10_AES_256_CBC_SHA_4 0x0038 +#define OP_PCL_TLS10_AES_256_CBC_SHA_5 0x0039 +#define OP_PCL_TLS10_AES_256_CBC_SHA_6 0x003a +#define OP_PCL_TLS10_AES_256_CBC_SHA_7 0x008d +#define OP_PCL_TLS10_AES_256_CBC_SHA_8 0x0091 +#define OP_PCL_TLS10_AES_256_CBC_SHA_9 0x0095 +#define OP_PCL_TLS10_AES_256_CBC_SHA_10 0xc005 +#define OP_PCL_TLS10_AES_256_CBC_SHA_11 0xc00a +#define OP_PCL_TLS10_AES_256_CBC_SHA_12 0xc00f +#define OP_PCL_TLS10_AES_256_CBC_SHA_13 0xc014 +#define OP_PCL_TLS10_AES_256_CBC_SHA_14 0xc019 +#define OP_PCL_TLS10_AES_256_CBC_SHA_15 0xc020 +#define OP_PCL_TLS10_AES_256_CBC_SHA_16 0xc021 +#define OP_PCL_TLS10_AES_256_CBC_SHA_17 0xc022 + +/* #define OP_PCL_TLS10_3DES_EDE_CBC_MD5 0x0023 */ + +#define OP_PCL_TLS10_3DES_EDE_CBC_SHA 0x001f +#define OP_PCL_TLS10_3DES_EDE_CBC_SHA_2 0x008b +#define OP_PCL_TLS10_3DES_EDE_CBC_SHA_3 0x008f +#define OP_PCL_TLS10_3DES_EDE_CBC_SHA_4 0x0093 +#define OP_PCL_TLS10_3DES_EDE_CBC_SHA_5 0x000a +#define OP_PCL_TLS10_3DES_EDE_CBC_SHA_6 0x000d +#define OP_PCL_TLS10_3DES_EDE_CBC_SHA_7 0x0010 +#define OP_PCL_TLS10_3DES_EDE_CBC_SHA_8 0x0013 +#define OP_PCL_TLS10_3DES_EDE_CBC_SHA_9 0x0016 +#define OP_PCL_TLS10_3DES_EDE_CBC_SHA_10 0x001b +#define OP_PCL_TLS10_3DES_EDE_CBC_SHA_11 0xc003 +#define OP_PCL_TLS10_3DES_EDE_CBC_SHA_12 0xc008 +#define OP_PCL_TLS10_3DES_EDE_CBC_SHA_13 0xc00d +#define OP_PCL_TLS10_3DES_EDE_CBC_SHA_14 0xc012 +#define OP_PCL_TLS10_3DES_EDE_CBC_SHA_15 0xc017 +#define OP_PCL_TLS10_3DES_EDE_CBC_SHA_16 0xc01a +#define OP_PCL_TLS10_3DES_EDE_CBC_SHA_17 0xc01b +#define OP_PCL_TLS10_3DES_EDE_CBC_SHA_18 0xc01c + +#define OP_PCL_TLS10_DES40_CBC_MD5 0x0029 + +#define OP_PCL_TLS10_DES_CBC_MD5 0x0022 + +#define OP_PCL_TLS10_DES40_CBC_SHA 0x0008 +#define OP_PCL_TLS10_DES40_CBC_SHA_2 0x000b +#define OP_PCL_TLS10_DES40_CBC_SHA_3 0x000e +#define OP_PCL_TLS10_DES40_CBC_SHA_4 0x0011 +#define OP_PCL_TLS10_DES40_CBC_SHA_5 0x0014 +#define OP_PCL_TLS10_DES40_CBC_SHA_6 0x0019 +#define OP_PCL_TLS10_DES40_CBC_SHA_7 0x0026 + + +#define OP_PCL_TLS10_DES_CBC_SHA 0x001e +#define OP_PCL_TLS10_DES_CBC_SHA_2 0x0009 +#define OP_PCL_TLS10_DES_CBC_SHA_3 0x000c +#define OP_PCL_TLS10_DES_CBC_SHA_4 0x000f +#define OP_PCL_TLS10_DES_CBC_SHA_5 0x0012 +#define OP_PCL_TLS10_DES_CBC_SHA_6 0x0015 +#define OP_PCL_TLS10_DES_CBC_SHA_7 0x001a + +#define OP_PCL_TLS10_RC4_128_MD5 0x0024 +#define OP_PCL_TLS10_RC4_128_MD5_2 0x0004 +#define OP_PCL_TLS10_RC4_128_MD5_3 0x0018 + +#define OP_PCL_TLS10_RC4_40_MD5 0x002b +#define OP_PCL_TLS10_RC4_40_MD5_2 0x0003 +#define OP_PCL_TLS10_RC4_40_MD5_3 0x0017 + +#define OP_PCL_TLS10_RC4_128_SHA 0x0020 +#define OP_PCL_TLS10_RC4_128_SHA_2 0x008a +#define OP_PCL_TLS10_RC4_128_SHA_3 0x008e +#define OP_PCL_TLS10_RC4_128_SHA_4 0x0092 +#define OP_PCL_TLS10_RC4_128_SHA_5 0x0005 +#define OP_PCL_TLS10_RC4_128_SHA_6 0xc002 +#define OP_PCL_TLS10_RC4_128_SHA_7 0xc007 +#define OP_PCL_TLS10_RC4_128_SHA_8 0xc00c +#define OP_PCL_TLS10_RC4_128_SHA_9 0xc011 +#define OP_PCL_TLS10_RC4_128_SHA_10 0xc016 + +#define OP_PCL_TLS10_RC4_40_SHA 0x0028 + +#define OP_PCL_TLS10_3DES_EDE_CBC_MD5 0xff23 +#define OP_PCL_TLS10_3DES_EDE_CBC_SHA160 0xff30 +#define OP_PCL_TLS10_3DES_EDE_CBC_SHA224 0xff34 +#define OP_PCL_TLS10_3DES_EDE_CBC_SHA256 0xff36 +#define OP_PCL_TLS10_3DES_EDE_CBC_SHA384 0xff33 +#define OP_PCL_TLS10_3DES_EDE_CBC_SHA512 0xff35 +#define OP_PCL_TLS10_AES_128_CBC_SHA160 0xff80 +#define OP_PCL_TLS10_AES_128_CBC_SHA224 0xff84 +#define OP_PCL_TLS10_AES_128_CBC_SHA256 0xff86 +#define OP_PCL_TLS10_AES_128_CBC_SHA384 0xff83 +#define OP_PCL_TLS10_AES_128_CBC_SHA512 0xff85 +#define OP_PCL_TLS10_AES_192_CBC_SHA160 0xff20 +#define OP_PCL_TLS10_AES_192_CBC_SHA224 0xff24 +#define OP_PCL_TLS10_AES_192_CBC_SHA256 0xff26 +#define OP_PCL_TLS10_AES_192_CBC_SHA384 0xff23 +#define OP_PCL_TLS10_AES_192_CBC_SHA512 0xff25 +#define OP_PCL_TLS10_AES_256_CBC_SHA160 0xff60 +#define OP_PCL_TLS10_AES_256_CBC_SHA224 0xff64 +#define OP_PCL_TLS10_AES_256_CBC_SHA256 0xff66 +#define OP_PCL_TLS10_AES_256_CBC_SHA384 0xff63 +#define OP_PCL_TLS10_AES_256_CBC_SHA512 0xff65 + + + +/* For TLS 1.1 - OP_PCLID_TLS11 */ +#define OP_PCL_TLS11_AES_128_CBC_SHA 0x002f +#define OP_PCL_TLS11_AES_128_CBC_SHA_2 0x0030 +#define OP_PCL_TLS11_AES_128_CBC_SHA_3 0x0031 +#define OP_PCL_TLS11_AES_128_CBC_SHA_4 0x0032 +#define OP_PCL_TLS11_AES_128_CBC_SHA_5 0x0033 +#define OP_PCL_TLS11_AES_128_CBC_SHA_6 0x0034 +#define OP_PCL_TLS11_AES_128_CBC_SHA_7 0x008c +#define OP_PCL_TLS11_AES_128_CBC_SHA_8 0x0090 +#define OP_PCL_TLS11_AES_128_CBC_SHA_9 0x0094 +#define OP_PCL_TLS11_AES_128_CBC_SHA_10 0xc004 +#define OP_PCL_TLS11_AES_128_CBC_SHA_11 0xc009 +#define OP_PCL_TLS11_AES_128_CBC_SHA_12 0xc00e +#define OP_PCL_TLS11_AES_128_CBC_SHA_13 0xc013 +#define OP_PCL_TLS11_AES_128_CBC_SHA_14 0xc018 +#define OP_PCL_TLS11_AES_128_CBC_SHA_15 0xc01d +#define OP_PCL_TLS11_AES_128_CBC_SHA_16 0xc01e +#define OP_PCL_TLS11_AES_128_CBC_SHA_17 0xc01f + +#define OP_PCL_TLS11_AES_256_CBC_SHA 0x0035 +#define OP_PCL_TLS11_AES_256_CBC_SHA_2 0x0036 +#define OP_PCL_TLS11_AES_256_CBC_SHA_3 0x0037 +#define OP_PCL_TLS11_AES_256_CBC_SHA_4 0x0038 +#define OP_PCL_TLS11_AES_256_CBC_SHA_5 0x0039 +#define OP_PCL_TLS11_AES_256_CBC_SHA_6 0x003a +#define OP_PCL_TLS11_AES_256_CBC_SHA_7 0x008d +#define OP_PCL_TLS11_AES_256_CBC_SHA_8 0x0091 +#define OP_PCL_TLS11_AES_256_CBC_SHA_9 0x0095 +#define OP_PCL_TLS11_AES_256_CBC_SHA_10 0xc005 +#define OP_PCL_TLS11_AES_256_CBC_SHA_11 0xc00a +#define OP_PCL_TLS11_AES_256_CBC_SHA_12 0xc00f +#define OP_PCL_TLS11_AES_256_CBC_SHA_13 0xc014 +#define OP_PCL_TLS11_AES_256_CBC_SHA_14 0xc019 +#define OP_PCL_TLS11_AES_256_CBC_SHA_15 0xc020 +#define OP_PCL_TLS11_AES_256_CBC_SHA_16 0xc021 +#define OP_PCL_TLS11_AES_256_CBC_SHA_17 0xc022 + +/* #define OP_PCL_TLS11_3DES_EDE_CBC_MD5 0x0023 */ + +#define OP_PCL_TLS11_3DES_EDE_CBC_SHA 0x001f +#define OP_PCL_TLS11_3DES_EDE_CBC_SHA_2 0x008b +#define OP_PCL_TLS11_3DES_EDE_CBC_SHA_3 0x008f +#define OP_PCL_TLS11_3DES_EDE_CBC_SHA_4 0x0093 +#define OP_PCL_TLS11_3DES_EDE_CBC_SHA_5 0x000a +#define OP_PCL_TLS11_3DES_EDE_CBC_SHA_6 0x000d +#define OP_PCL_TLS11_3DES_EDE_CBC_SHA_7 0x0010 +#define OP_PCL_TLS11_3DES_EDE_CBC_SHA_8 0x0013 +#define OP_PCL_TLS11_3DES_EDE_CBC_SHA_9 0x0016 +#define OP_PCL_TLS11_3DES_EDE_CBC_SHA_10 0x001b +#define OP_PCL_TLS11_3DES_EDE_CBC_SHA_11 0xc003 +#define OP_PCL_TLS11_3DES_EDE_CBC_SHA_12 0xc008 +#define OP_PCL_TLS11_3DES_EDE_CBC_SHA_13 0xc00d +#define OP_PCL_TLS11_3DES_EDE_CBC_SHA_14 0xc012 +#define OP_PCL_TLS11_3DES_EDE_CBC_SHA_15 0xc017 +#define OP_PCL_TLS11_3DES_EDE_CBC_SHA_16 0xc01a +#define OP_PCL_TLS11_3DES_EDE_CBC_SHA_17 0xc01b +#define OP_PCL_TLS11_3DES_EDE_CBC_SHA_18 0xc01c + +#define OP_PCL_TLS11_DES40_CBC_MD5 0x0029 + +#define OP_PCL_TLS11_DES_CBC_MD5 0x0022 + +#define OP_PCL_TLS11_DES40_CBC_SHA 0x0008 +#define OP_PCL_TLS11_DES40_CBC_SHA_2 0x000b +#define OP_PCL_TLS11_DES40_CBC_SHA_3 0x000e +#define OP_PCL_TLS11_DES40_CBC_SHA_4 0x0011 +#define OP_PCL_TLS11_DES40_CBC_SHA_5 0x0014 +#define OP_PCL_TLS11_DES40_CBC_SHA_6 0x0019 +#define OP_PCL_TLS11_DES40_CBC_SHA_7 0x0026 + +#define OP_PCL_TLS11_DES_CBC_SHA 0x001e +#define OP_PCL_TLS11_DES_CBC_SHA_2 0x0009 +#define OP_PCL_TLS11_DES_CBC_SHA_3 0x000c +#define OP_PCL_TLS11_DES_CBC_SHA_4 0x000f +#define OP_PCL_TLS11_DES_CBC_SHA_5 0x0012 +#define OP_PCL_TLS11_DES_CBC_SHA_6 0x0015 +#define OP_PCL_TLS11_DES_CBC_SHA_7 0x001a + +#define OP_PCL_TLS11_RC4_128_MD5 0x0024 +#define OP_PCL_TLS11_RC4_128_MD5_2 0x0004 +#define OP_PCL_TLS11_RC4_128_MD5_3 0x0018 + +#define OP_PCL_TLS11_RC4_40_MD5 0x002b +#define OP_PCL_TLS11_RC4_40_MD5_2 0x0003 +#define OP_PCL_TLS11_RC4_40_MD5_3 0x0017 + +#define OP_PCL_TLS11_RC4_128_SHA 0x0020 +#define OP_PCL_TLS11_RC4_128_SHA_2 0x008a +#define OP_PCL_TLS11_RC4_128_SHA_3 0x008e +#define OP_PCL_TLS11_RC4_128_SHA_4 0x0092 +#define OP_PCL_TLS11_RC4_128_SHA_5 0x0005 +#define OP_PCL_TLS11_RC4_128_SHA_6 0xc002 +#define OP_PCL_TLS11_RC4_128_SHA_7 0xc007 +#define OP_PCL_TLS11_RC4_128_SHA_8 0xc00c +#define OP_PCL_TLS11_RC4_128_SHA_9 0xc011 +#define OP_PCL_TLS11_RC4_128_SHA_10 0xc016 + +#define OP_PCL_TLS11_RC4_40_SHA 0x0028 + +#define OP_PCL_TLS11_3DES_EDE_CBC_MD5 0xff23 +#define OP_PCL_TLS11_3DES_EDE_CBC_SHA160 0xff30 +#define OP_PCL_TLS11_3DES_EDE_CBC_SHA224 0xff34 +#define OP_PCL_TLS11_3DES_EDE_CBC_SHA256 0xff36 +#define OP_PCL_TLS11_3DES_EDE_CBC_SHA384 0xff33 +#define OP_PCL_TLS11_3DES_EDE_CBC_SHA512 0xff35 +#define OP_PCL_TLS11_AES_128_CBC_SHA160 0xff80 +#define OP_PCL_TLS11_AES_128_CBC_SHA224 0xff84 +#define OP_PCL_TLS11_AES_128_CBC_SHA256 0xff86 +#define OP_PCL_TLS11_AES_128_CBC_SHA384 0xff83 +#define OP_PCL_TLS11_AES_128_CBC_SHA512 0xff85 +#define OP_PCL_TLS11_AES_192_CBC_SHA160 0xff20 +#define OP_PCL_TLS11_AES_192_CBC_SHA224 0xff24 +#define OP_PCL_TLS11_AES_192_CBC_SHA256 0xff26 +#define OP_PCL_TLS11_AES_192_CBC_SHA384 0xff23 +#define OP_PCL_TLS11_AES_192_CBC_SHA512 0xff25 +#define OP_PCL_TLS11_AES_256_CBC_SHA160 0xff60 +#define OP_PCL_TLS11_AES_256_CBC_SHA224 0xff64 +#define OP_PCL_TLS11_AES_256_CBC_SHA256 0xff66 +#define OP_PCL_TLS11_AES_256_CBC_SHA384 0xff63 +#define OP_PCL_TLS11_AES_256_CBC_SHA512 0xff65 + + +/* For TLS 1.2 - OP_PCLID_TLS12 */ +#define OP_PCL_TLS12_AES_128_CBC_SHA 0x002f +#define OP_PCL_TLS12_AES_128_CBC_SHA_2 0x0030 +#define OP_PCL_TLS12_AES_128_CBC_SHA_3 0x0031 +#define OP_PCL_TLS12_AES_128_CBC_SHA_4 0x0032 +#define OP_PCL_TLS12_AES_128_CBC_SHA_5 0x0033 +#define OP_PCL_TLS12_AES_128_CBC_SHA_6 0x0034 +#define OP_PCL_TLS12_AES_128_CBC_SHA_7 0x008c +#define OP_PCL_TLS12_AES_128_CBC_SHA_8 0x0090 +#define OP_PCL_TLS12_AES_128_CBC_SHA_9 0x0094 +#define OP_PCL_TLS12_AES_128_CBC_SHA_10 0xc004 +#define OP_PCL_TLS12_AES_128_CBC_SHA_11 0xc009 +#define OP_PCL_TLS12_AES_128_CBC_SHA_12 0xc00e +#define OP_PCL_TLS12_AES_128_CBC_SHA_13 0xc013 +#define OP_PCL_TLS12_AES_128_CBC_SHA_14 0xc018 +#define OP_PCL_TLS12_AES_128_CBC_SHA_15 0xc01d +#define OP_PCL_TLS12_AES_128_CBC_SHA_16 0xc01e +#define OP_PCL_TLS12_AES_128_CBC_SHA_17 0xc01f + +#define OP_PCL_TLS12_AES_256_CBC_SHA 0x0035 +#define OP_PCL_TLS12_AES_256_CBC_SHA_2 0x0036 +#define OP_PCL_TLS12_AES_256_CBC_SHA_3 0x0037 +#define OP_PCL_TLS12_AES_256_CBC_SHA_4 0x0038 +#define OP_PCL_TLS12_AES_256_CBC_SHA_5 0x0039 +#define OP_PCL_TLS12_AES_256_CBC_SHA_6 0x003a +#define OP_PCL_TLS12_AES_256_CBC_SHA_7 0x008d +#define OP_PCL_TLS12_AES_256_CBC_SHA_8 0x0091 +#define OP_PCL_TLS12_AES_256_CBC_SHA_9 0x0095 +#define OP_PCL_TLS12_AES_256_CBC_SHA_10 0xc005 +#define OP_PCL_TLS12_AES_256_CBC_SHA_11 0xc00a +#define OP_PCL_TLS12_AES_256_CBC_SHA_12 0xc00f +#define OP_PCL_TLS12_AES_256_CBC_SHA_13 0xc014 +#define OP_PCL_TLS12_AES_256_CBC_SHA_14 0xc019 +#define OP_PCL_TLS12_AES_256_CBC_SHA_15 0xc020 +#define OP_PCL_TLS12_AES_256_CBC_SHA_16 0xc021 +#define OP_PCL_TLS12_AES_256_CBC_SHA_17 0xc022 + +/* #define OP_PCL_TLS12_3DES_EDE_CBC_MD5 0x0023 */ + +#define OP_PCL_TLS12_3DES_EDE_CBC_SHA 0x001f +#define OP_PCL_TLS12_3DES_EDE_CBC_SHA_2 0x008b +#define OP_PCL_TLS12_3DES_EDE_CBC_SHA_3 0x008f +#define OP_PCL_TLS12_3DES_EDE_CBC_SHA_4 0x0093 +#define OP_PCL_TLS12_3DES_EDE_CBC_SHA_5 0x000a +#define OP_PCL_TLS12_3DES_EDE_CBC_SHA_6 0x000d +#define OP_PCL_TLS12_3DES_EDE_CBC_SHA_7 0x0010 +#define OP_PCL_TLS12_3DES_EDE_CBC_SHA_8 0x0013 +#define OP_PCL_TLS12_3DES_EDE_CBC_SHA_9 0x0016 +#define OP_PCL_TLS12_3DES_EDE_CBC_SHA_10 0x001b +#define OP_PCL_TLS12_3DES_EDE_CBC_SHA_11 0xc003 +#define OP_PCL_TLS12_3DES_EDE_CBC_SHA_12 0xc008 +#define OP_PCL_TLS12_3DES_EDE_CBC_SHA_13 0xc00d +#define OP_PCL_TLS12_3DES_EDE_CBC_SHA_14 0xc012 +#define OP_PCL_TLS12_3DES_EDE_CBC_SHA_15 0xc017 +#define OP_PCL_TLS12_3DES_EDE_CBC_SHA_16 0xc01a +#define OP_PCL_TLS12_3DES_EDE_CBC_SHA_17 0xc01b +#define OP_PCL_TLS12_3DES_EDE_CBC_SHA_18 0xc01c + +#define OP_PCL_TLS12_DES40_CBC_MD5 0x0029 + +#define OP_PCL_TLS12_DES_CBC_MD5 0x0022 + +#define OP_PCL_TLS12_DES40_CBC_SHA 0x0008 +#define OP_PCL_TLS12_DES40_CBC_SHA_2 0x000b +#define OP_PCL_TLS12_DES40_CBC_SHA_3 0x000e +#define OP_PCL_TLS12_DES40_CBC_SHA_4 0x0011 +#define OP_PCL_TLS12_DES40_CBC_SHA_5 0x0014 +#define OP_PCL_TLS12_DES40_CBC_SHA_6 0x0019 +#define OP_PCL_TLS12_DES40_CBC_SHA_7 0x0026 + +#define OP_PCL_TLS12_DES_CBC_SHA 0x001e +#define OP_PCL_TLS12_DES_CBC_SHA_2 0x0009 +#define OP_PCL_TLS12_DES_CBC_SHA_3 0x000c +#define OP_PCL_TLS12_DES_CBC_SHA_4 0x000f +#define OP_PCL_TLS12_DES_CBC_SHA_5 0x0012 +#define OP_PCL_TLS12_DES_CBC_SHA_6 0x0015 +#define OP_PCL_TLS12_DES_CBC_SHA_7 0x001a + +#define OP_PCL_TLS12_RC4_128_MD5 0x0024 +#define OP_PCL_TLS12_RC4_128_MD5_2 0x0004 +#define OP_PCL_TLS12_RC4_128_MD5_3 0x0018 + +#define OP_PCL_TLS12_RC4_40_MD5 0x002b +#define OP_PCL_TLS12_RC4_40_MD5_2 0x0003 +#define OP_PCL_TLS12_RC4_40_MD5_3 0x0017 + +#define OP_PCL_TLS12_RC4_128_SHA 0x0020 +#define OP_PCL_TLS12_RC4_128_SHA_2 0x008a +#define OP_PCL_TLS12_RC4_128_SHA_3 0x008e +#define OP_PCL_TLS12_RC4_128_SHA_4 0x0092 +#define OP_PCL_TLS12_RC4_128_SHA_5 0x0005 +#define OP_PCL_TLS12_RC4_128_SHA_6 0xc002 +#define OP_PCL_TLS12_RC4_128_SHA_7 0xc007 +#define OP_PCL_TLS12_RC4_128_SHA_8 0xc00c +#define OP_PCL_TLS12_RC4_128_SHA_9 0xc011 +#define OP_PCL_TLS12_RC4_128_SHA_10 0xc016 + +#define OP_PCL_TLS12_RC4_40_SHA 0x0028 + +/* #define OP_PCL_TLS12_AES_128_CBC_SHA256 0x003c */ +#define OP_PCL_TLS12_AES_128_CBC_SHA256_2 0x003e +#define OP_PCL_TLS12_AES_128_CBC_SHA256_3 0x003f +#define OP_PCL_TLS12_AES_128_CBC_SHA256_4 0x0040 +#define OP_PCL_TLS12_AES_128_CBC_SHA256_5 0x0067 +#define OP_PCL_TLS12_AES_128_CBC_SHA256_6 0x006c + +/* #define OP_PCL_TLS12_AES_256_CBC_SHA256 0x003d */ +#define OP_PCL_TLS12_AES_256_CBC_SHA256_2 0x0068 +#define OP_PCL_TLS12_AES_256_CBC_SHA256_3 0x0069 +#define OP_PCL_TLS12_AES_256_CBC_SHA256_4 0x006a +#define OP_PCL_TLS12_AES_256_CBC_SHA256_5 0x006b +#define OP_PCL_TLS12_AES_256_CBC_SHA256_6 0x006d + +/* AEAD_AES_xxx_CCM/GCM remain to be defined... */ + +#define OP_PCL_TLS12_3DES_EDE_CBC_MD5 0xff23 +#define OP_PCL_TLS12_3DES_EDE_CBC_SHA160 0xff30 +#define OP_PCL_TLS12_3DES_EDE_CBC_SHA224 0xff34 +#define OP_PCL_TLS12_3DES_EDE_CBC_SHA256 0xff36 +#define OP_PCL_TLS12_3DES_EDE_CBC_SHA384 0xff33 +#define OP_PCL_TLS12_3DES_EDE_CBC_SHA512 0xff35 +#define OP_PCL_TLS12_AES_128_CBC_SHA160 0xff80 +#define OP_PCL_TLS12_AES_128_CBC_SHA224 0xff84 +#define OP_PCL_TLS12_AES_128_CBC_SHA256 0xff86 +#define OP_PCL_TLS12_AES_128_CBC_SHA384 0xff83 +#define OP_PCL_TLS12_AES_128_CBC_SHA512 0xff85 +#define OP_PCL_TLS12_AES_192_CBC_SHA160 0xff20 +#define OP_PCL_TLS12_AES_192_CBC_SHA224 0xff24 +#define OP_PCL_TLS12_AES_192_CBC_SHA256 0xff26 +#define OP_PCL_TLS12_AES_192_CBC_SHA384 0xff23 +#define OP_PCL_TLS12_AES_192_CBC_SHA512 0xff25 +#define OP_PCL_TLS12_AES_256_CBC_SHA160 0xff60 +#define OP_PCL_TLS12_AES_256_CBC_SHA224 0xff64 +#define OP_PCL_TLS12_AES_256_CBC_SHA256 0xff66 +#define OP_PCL_TLS12_AES_256_CBC_SHA384 0xff63 +#define OP_PCL_TLS12_AES_256_CBC_SHA512 0xff65 + +/* For DTLS - OP_PCLID_DTLS */ + +#define OP_PCL_DTLS_AES_128_CBC_SHA 0x002f +#define OP_PCL_DTLS_AES_128_CBC_SHA_2 0x0030 +#define OP_PCL_DTLS_AES_128_CBC_SHA_3 0x0031 +#define OP_PCL_DTLS_AES_128_CBC_SHA_4 0x0032 +#define OP_PCL_DTLS_AES_128_CBC_SHA_5 0x0033 +#define OP_PCL_DTLS_AES_128_CBC_SHA_6 0x0034 +#define OP_PCL_DTLS_AES_128_CBC_SHA_7 0x008c +#define OP_PCL_DTLS_AES_128_CBC_SHA_8 0x0090 +#define OP_PCL_DTLS_AES_128_CBC_SHA_9 0x0094 +#define OP_PCL_DTLS_AES_128_CBC_SHA_10 0xc004 +#define OP_PCL_DTLS_AES_128_CBC_SHA_11 0xc009 +#define OP_PCL_DTLS_AES_128_CBC_SHA_12 0xc00e +#define OP_PCL_DTLS_AES_128_CBC_SHA_13 0xc013 +#define OP_PCL_DTLS_AES_128_CBC_SHA_14 0xc018 +#define OP_PCL_DTLS_AES_128_CBC_SHA_15 0xc01d +#define OP_PCL_DTLS_AES_128_CBC_SHA_16 0xc01e +#define OP_PCL_DTLS_AES_128_CBC_SHA_17 0xc01f + +#define OP_PCL_DTLS_AES_256_CBC_SHA 0x0035 +#define OP_PCL_DTLS_AES_256_CBC_SHA_2 0x0036 +#define OP_PCL_DTLS_AES_256_CBC_SHA_3 0x0037 +#define OP_PCL_DTLS_AES_256_CBC_SHA_4 0x0038 +#define OP_PCL_DTLS_AES_256_CBC_SHA_5 0x0039 +#define OP_PCL_DTLS_AES_256_CBC_SHA_6 0x003a +#define OP_PCL_DTLS_AES_256_CBC_SHA_7 0x008d +#define OP_PCL_DTLS_AES_256_CBC_SHA_8 0x0091 +#define OP_PCL_DTLS_AES_256_CBC_SHA_9 0x0095 +#define OP_PCL_DTLS_AES_256_CBC_SHA_10 0xc005 +#define OP_PCL_DTLS_AES_256_CBC_SHA_11 0xc00a +#define OP_PCL_DTLS_AES_256_CBC_SHA_12 0xc00f +#define OP_PCL_DTLS_AES_256_CBC_SHA_13 0xc014 +#define OP_PCL_DTLS_AES_256_CBC_SHA_14 0xc019 +#define OP_PCL_DTLS_AES_256_CBC_SHA_15 0xc020 +#define OP_PCL_DTLS_AES_256_CBC_SHA_16 0xc021 +#define OP_PCL_DTLS_AES_256_CBC_SHA_17 0xc022 + +/* #define OP_PCL_DTLS_3DES_EDE_CBC_MD5 0x0023 */ + +#define OP_PCL_DTLS_3DES_EDE_CBC_SHA 0x001f +#define OP_PCL_DTLS_3DES_EDE_CBC_SHA_2 0x008b +#define OP_PCL_DTLS_3DES_EDE_CBC_SHA_3 0x008f +#define OP_PCL_DTLS_3DES_EDE_CBC_SHA_4 0x0093 +#define OP_PCL_DTLS_3DES_EDE_CBC_SHA_5 0x000a +#define OP_PCL_DTLS_3DES_EDE_CBC_SHA_6 0x000d +#define OP_PCL_DTLS_3DES_EDE_CBC_SHA_7 0x0010 +#define OP_PCL_DTLS_3DES_EDE_CBC_SHA_8 0x0013 +#define OP_PCL_DTLS_3DES_EDE_CBC_SHA_9 0x0016 +#define OP_PCL_DTLS_3DES_EDE_CBC_SHA_10 0x001b +#define OP_PCL_DTLS_3DES_EDE_CBC_SHA_11 0xc003 +#define OP_PCL_DTLS_3DES_EDE_CBC_SHA_12 0xc008 +#define OP_PCL_DTLS_3DES_EDE_CBC_SHA_13 0xc00d +#define OP_PCL_DTLS_3DES_EDE_CBC_SHA_14 0xc012 +#define OP_PCL_DTLS_3DES_EDE_CBC_SHA_15 0xc017 +#define OP_PCL_DTLS_3DES_EDE_CBC_SHA_16 0xc01a +#define OP_PCL_DTLS_3DES_EDE_CBC_SHA_17 0xc01b +#define OP_PCL_DTLS_3DES_EDE_CBC_SHA_18 0xc01c + +#define OP_PCL_DTLS_DES40_CBC_MD5 0x0029 + +#define OP_PCL_DTLS_DES_CBC_MD5 0x0022 + +#define OP_PCL_DTLS_DES40_CBC_SHA 0x0008 +#define OP_PCL_DTLS_DES40_CBC_SHA_2 0x000b +#define OP_PCL_DTLS_DES40_CBC_SHA_3 0x000e +#define OP_PCL_DTLS_DES40_CBC_SHA_4 0x0011 +#define OP_PCL_DTLS_DES40_CBC_SHA_5 0x0014 +#define OP_PCL_DTLS_DES40_CBC_SHA_6 0x0019 +#define OP_PCL_DTLS_DES40_CBC_SHA_7 0x0026 + + +#define OP_PCL_DTLS_DES_CBC_SHA 0x001e +#define OP_PCL_DTLS_DES_CBC_SHA_2 0x0009 +#define OP_PCL_DTLS_DES_CBC_SHA_3 0x000c +#define OP_PCL_DTLS_DES_CBC_SHA_4 0x000f +#define OP_PCL_DTLS_DES_CBC_SHA_5 0x0012 +#define OP_PCL_DTLS_DES_CBC_SHA_6 0x0015 +#define OP_PCL_DTLS_DES_CBC_SHA_7 0x001a + + +#define OP_PCL_DTLS_3DES_EDE_CBC_MD5 0xff23 +#define OP_PCL_DTLS_3DES_EDE_CBC_SHA160 0xff30 +#define OP_PCL_DTLS_3DES_EDE_CBC_SHA224 0xff34 +#define OP_PCL_DTLS_3DES_EDE_CBC_SHA256 0xff36 +#define OP_PCL_DTLS_3DES_EDE_CBC_SHA384 0xff33 +#define OP_PCL_DTLS_3DES_EDE_CBC_SHA512 0xff35 +#define OP_PCL_DTLS_AES_128_CBC_SHA160 0xff80 +#define OP_PCL_DTLS_AES_128_CBC_SHA224 0xff84 +#define OP_PCL_DTLS_AES_128_CBC_SHA256 0xff86 +#define OP_PCL_DTLS_AES_128_CBC_SHA384 0xff83 +#define OP_PCL_DTLS_AES_128_CBC_SHA512 0xff85 +#define OP_PCL_DTLS_AES_192_CBC_SHA160 0xff20 +#define OP_PCL_DTLS_AES_192_CBC_SHA224 0xff24 +#define OP_PCL_DTLS_AES_192_CBC_SHA256 0xff26 +#define OP_PCL_DTLS_AES_192_CBC_SHA384 0xff23 +#define OP_PCL_DTLS_AES_192_CBC_SHA512 0xff25 +#define OP_PCL_DTLS_AES_256_CBC_SHA160 0xff60 +#define OP_PCL_DTLS_AES_256_CBC_SHA224 0xff64 +#define OP_PCL_DTLS_AES_256_CBC_SHA256 0xff66 +#define OP_PCL_DTLS_AES_256_CBC_SHA384 0xff63 +#define OP_PCL_DTLS_AES_256_CBC_SHA512 0xff65 + +/* 802.16 WiMAX protinfos */ +#define OP_PCL_WIMAX_OFDM 0x0201 +#define OP_PCL_WIMAX_OFDMA 0x0231 + +/* 802.11 WiFi protinfos */ +#define OP_PCL_WIFI 0xac04 + +/* MacSec protinfos */ +#define OP_PCL_MACSEC 0x0001 + +/* PKI unidirectional protocol protinfo bits */ +#define OP_PCL_PKPROT_TEST 0x0008 +#define OP_PCL_PKPROT_DECRYPT 0x0004 +#define OP_PCL_PKPROT_ECC 0x0002 +#define OP_PCL_PKPROT_F2M 0x0001 + +/* For non-protocol/alg-only op commands */ +#define OP_ALG_TYPE_SHIFT 24 +#define OP_ALG_TYPE_MASK (0x7 << OP_ALG_TYPE_SHIFT) +#define OP_ALG_TYPE_CLASS1 2 +#define OP_ALG_TYPE_CLASS2 4 + +#define OP_ALG_ALGSEL_SHIFT 16 +#define OP_ALG_ALGSEL_MASK (0xff << OP_ALG_ALGSEL_SHIFT) +#define OP_ALG_ALGSEL_SUBMASK (0x0f << OP_ALG_ALGSEL_SHIFT) +#define OP_ALG_ALGSEL_AES (0x10 << OP_ALG_ALGSEL_SHIFT) +#define OP_ALG_ALGSEL_DES (0x20 << OP_ALG_ALGSEL_SHIFT) +#define OP_ALG_ALGSEL_3DES (0x21 << OP_ALG_ALGSEL_SHIFT) +#define OP_ALG_ALGSEL_ARC4 (0x30 << OP_ALG_ALGSEL_SHIFT) +#define OP_ALG_ALGSEL_MD5 (0x40 << OP_ALG_ALGSEL_SHIFT) +#define OP_ALG_ALGSEL_SHA1 (0x41 << OP_ALG_ALGSEL_SHIFT) +#define OP_ALG_ALGSEL_SHA224 (0x42 << OP_ALG_ALGSEL_SHIFT) +#define OP_ALG_ALGSEL_SHA256 (0x43 << OP_ALG_ALGSEL_SHIFT) +#define OP_ALG_ALGSEL_SHA384 (0x44 << OP_ALG_ALGSEL_SHIFT) +#define OP_ALG_ALGSEL_SHA512 (0x45 << OP_ALG_ALGSEL_SHIFT) +#define OP_ALG_ALGSEL_RNG (0x50 << OP_ALG_ALGSEL_SHIFT) +#define OP_ALG_ALGSEL_SNOW (0x60 << OP_ALG_ALGSEL_SHIFT) +#define OP_ALG_ALGSEL_SNOW_F8 (0x60 << OP_ALG_ALGSEL_SHIFT) +#define OP_ALG_ALGSEL_KASUMI (0x70 << OP_ALG_ALGSEL_SHIFT) +#define OP_ALG_ALGSEL_CRC (0x90 << OP_ALG_ALGSEL_SHIFT) +#define OP_ALG_ALGSEL_SNOW_F9 (0xA0 << OP_ALG_ALGSEL_SHIFT) + +#define OP_ALG_AAI_SHIFT 4 +#define OP_ALG_AAI_MASK (0x1ff << OP_ALG_AAI_SHIFT) + +/* blockcipher AAI set */ +#define OP_ALG_AAI_CTR_MOD128 (0x00 << OP_ALG_AAI_SHIFT) +#define OP_ALG_AAI_CTR_MOD8 (0x01 << OP_ALG_AAI_SHIFT) +#define OP_ALG_AAI_CTR_MOD16 (0x02 << OP_ALG_AAI_SHIFT) +#define OP_ALG_AAI_CTR_MOD24 (0x03 << OP_ALG_AAI_SHIFT) +#define OP_ALG_AAI_CTR_MOD32 (0x04 << OP_ALG_AAI_SHIFT) +#define OP_ALG_AAI_CTR_MOD40 (0x05 << OP_ALG_AAI_SHIFT) +#define OP_ALG_AAI_CTR_MOD48 (0x06 << OP_ALG_AAI_SHIFT) +#define OP_ALG_AAI_CTR_MOD56 (0x07 << OP_ALG_AAI_SHIFT) +#define OP_ALG_AAI_CTR_MOD64 (0x08 << OP_ALG_AAI_SHIFT) +#define OP_ALG_AAI_CTR_MOD72 (0x09 << OP_ALG_AAI_SHIFT) +#define OP_ALG_AAI_CTR_MOD80 (0x0a << OP_ALG_AAI_SHIFT) +#define OP_ALG_AAI_CTR_MOD88 (0x0b << OP_ALG_AAI_SHIFT) +#define OP_ALG_AAI_CTR_MOD96 (0x0c << OP_ALG_AAI_SHIFT) +#define OP_ALG_AAI_CTR_MOD104 (0x0d << OP_ALG_AAI_SHIFT) +#define OP_ALG_AAI_CTR_MOD112 (0x0e << OP_ALG_AAI_SHIFT) +#define OP_ALG_AAI_CTR_MOD120 (0x0f << OP_ALG_AAI_SHIFT) +#define OP_ALG_AAI_CBC (0x10 << OP_ALG_AAI_SHIFT) +#define OP_ALG_AAI_ECB (0x20 << OP_ALG_AAI_SHIFT) +#define OP_ALG_AAI_CFB (0x30 << OP_ALG_AAI_SHIFT) +#define OP_ALG_AAI_OFB (0x40 << OP_ALG_AAI_SHIFT) +#define OP_ALG_AAI_XTS (0x50 << OP_ALG_AAI_SHIFT) +#define OP_ALG_AAI_CMAC (0x60 << OP_ALG_AAI_SHIFT) +#define OP_ALG_AAI_XCBC_MAC (0x70 << OP_ALG_AAI_SHIFT) +#define OP_ALG_AAI_CCM (0x80 << OP_ALG_AAI_SHIFT) +#define OP_ALG_AAI_GCM (0x90 << OP_ALG_AAI_SHIFT) +#define OP_ALG_AAI_CBC_XCBCMAC (0xa0 << OP_ALG_AAI_SHIFT) +#define OP_ALG_AAI_CTR_XCBCMAC (0xb0 << OP_ALG_AAI_SHIFT) +#define OP_ALG_AAI_CHECKODD (0x80 << OP_ALG_AAI_SHIFT) +#define OP_ALG_AAI_DK (0x100 << OP_ALG_AAI_SHIFT) + +/* randomizer AAI set */ +#define OP_ALG_AAI_RNG (0x00 << OP_ALG_AAI_SHIFT) +#define OP_ALG_AAI_RNG_NOZERO (0x10 << OP_ALG_AAI_SHIFT) +#define OP_ALG_AAI_RNG_ODD (0x20 << OP_ALG_AAI_SHIFT) + +/* hmac/smac AAI set */ +#define OP_ALG_AAI_HASH (0x00 << OP_ALG_AAI_SHIFT) +#define OP_ALG_AAI_HMAC (0x01 << OP_ALG_AAI_SHIFT) +#define OP_ALG_AAI_SMAC (0x02 << OP_ALG_AAI_SHIFT) +#define OP_ALG_AAI_HMAC_PRECOMP (0x04 << OP_ALG_AAI_SHIFT) + +/* CRC AAI set*/ +#define OP_ALG_AAI_802 (0x01 << OP_ALG_AAI_SHIFT) +#define OP_ALG_AAI_3385 (0x02 << OP_ALG_AAI_SHIFT) +#define OP_ALG_AAI_CUST_POLY (0x04 << OP_ALG_AAI_SHIFT) +#define OP_ALG_AAI_DIS (0x10 << OP_ALG_AAI_SHIFT) +#define OP_ALG_AAI_DOS (0x20 << OP_ALG_AAI_SHIFT) +#define OP_ALG_AAI_DOC (0x40 << OP_ALG_AAI_SHIFT) + +/* Kasumi/SNOW AAI set */ +#define OP_ALG_AAI_F8 (0xc0 << OP_ALG_AAI_SHIFT) +#define OP_ALG_AAI_F9 (0xc8 << OP_ALG_AAI_SHIFT) +#define OP_ALG_AAI_GSM (0x10 << OP_ALG_AAI_SHIFT) +#define OP_ALG_AAI_EDGE (0x20 << OP_ALG_AAI_SHIFT) + + +#define OP_ALG_AS_SHIFT 2 +#define OP_ALG_AS_MASK (0x3 << OP_ALG_AS_SHIFT) +#define OP_ALG_AS_UPDATE (0 << OP_ALG_AS_SHIFT) +#define OP_ALG_AS_INIT (1 << OP_ALG_AS_SHIFT) +#define OP_ALG_AS_FINALIZE (2 << OP_ALG_AS_SHIFT) +#define OP_ALG_AS_INITFINAL (3 << OP_ALG_AS_SHIFT) + +#define OP_ALG_ICV_SHIFT 1 +#define OP_ALG_ICV_MASK (1 << OP_ALG_ICV_SHIFT) +#define OP_ALG_ICV_OFF (0 << OP_ALG_ICV_SHIFT) +#define OP_ALG_ICV_ON (1 << OP_ALG_ICV_SHIFT) + +#define OP_ALG_DIR_SHIFT 0 +#define OP_ALG_DIR_MASK 1 +#define OP_ALG_DECRYPT 0 +#define OP_ALG_ENCRYPT 1 + +/* PKHA algorithm type set */ +#define OP_ALG_PK 0x00800000 +#define OP_ALG_PK_FUN_MASK 0x3f /* clrmem, modmath, or cpymem */ + +/* PKHA mode clear memory functions */ +#define OP_ALG_PKMODE_A_RAM 0x80000 +#define OP_ALG_PKMODE_B_RAM 0x40000 +#define OP_ALG_PKMODE_E_RAM 0x20000 +#define OP_ALG_PKMODE_N_RAM 0x10000 +#define OP_ALG_PKMODE_CLEARMEM 0x00001 + +/* PKHA mode modular-arithmetic functions */ +#define OP_ALG_PKMODE_MOD_IN_MONTY 0x80000 +#define OP_ALG_PKMODE_MOD_OUT_MONTY 0x40000 +#define OP_ALG_PKMODE_MOD_F2M 0x20000 +#define OP_ALG_PKMODE_MOD_R2_IN 0x10000 +#define OP_ALG_PKMODE_PRJECTV 0x00800 +#define OP_ALG_PKMODE_TIME_EQ 0x400 +#define OP_ALG_PKMODE_OUT_B 0x000 +#define OP_ALG_PKMODE_OUT_A 0x100 +#define OP_ALG_PKMODE_MOD_ADD 0x002 +#define OP_ALG_PKMODE_MOD_SUB_AB 0x003 +#define OP_ALG_PKMODE_MOD_SUB_BA 0x004 +#define OP_ALG_PKMODE_MOD_MULT 0x005 +#define OP_ALG_PKMODE_MOD_EXPO 0x006 +#define OP_ALG_PKMODE_MOD_REDUCT 0x007 +#define OP_ALG_PKMODE_MOD_INV 0x008 +#define OP_ALG_PKMODE_MOD_ECC_ADD 0x009 +#define OP_ALG_PKMODE_MOD_ECC_DBL 0x00a +#define OP_ALG_PKMODE_MOD_ECC_MULT 0x00b +#define OP_ALG_PKMODE_MOD_MONT_CNST 0x00c +#define OP_ALG_PKMODE_MOD_CRT_CNST 0x00d +#define OP_ALG_PKMODE_MOD_GCD 0x00e +#define OP_ALG_PKMODE_MOD_PRIMALITY 0x00f + +/* PKHA mode copy-memory functions */ +#define OP_ALG_PKMODE_SRC_REG_SHIFT 13 +#define OP_ALG_PKMODE_SRC_REG_MASK (7 << OP_ALG_PKMODE_SRC_REG_SHIFT) +#define OP_ALG_PKMODE_DST_REG_SHIFT 10 +#define OP_ALG_PKMODE_DST_REG_MASK (7 << OP_ALG_PKMODE_DST_REG_SHIFT) +#define OP_ALG_PKMODE_SRC_SEG_SHIFT 8 +#define OP_ALG_PKMODE_SRC_SEG_MASK (3 << OP_ALG_PKMODE_SRC_SEG_SHIFT) +#define OP_ALG_PKMODE_DST_SEG_SHIFT 6 +#define OP_ALG_PKMODE_DST_SEG_MASK (3 << OP_ALG_PKMODE_DST_SEG_SHIFT) + +#define OP_ALG_PKMODE_SRC_REG_A (0 << OP_ALG_PKMODE_SRC_REG_SHIFT) +#define OP_ALG_PKMODE_SRC_REG_B (1 << OP_ALG_PKMODE_SRC_REG_SHIFT) +#define OP_ALG_PKMODE_SRC_REG_N (3 << OP_ALG_PKMODE_SRC_REG_SHIFT) +#define OP_ALG_PKMODE_DST_REG_A (0 << OP_ALG_PKMODE_DST_REG_SHIFT) +#define OP_ALG_PKMODE_DST_REG_B (1 << OP_ALG_PKMODE_DST_REG_SHIFT) +#define OP_ALG_PKMODE_DST_REG_E (2 << OP_ALG_PKMODE_DST_REG_SHIFT) +#define OP_ALG_PKMODE_DST_REG_N (3 << OP_ALG_PKMODE_DST_REG_SHIFT) +#define OP_ALG_PKMODE_SRC_SEG_0 (0 << OP_ALG_PKMODE_SRC_SEG_SHIFT) +#define OP_ALG_PKMODE_SRC_SEG_1 (1 << OP_ALG_PKMODE_SRC_SEG_SHIFT) +#define OP_ALG_PKMODE_SRC_SEG_2 (2 << OP_ALG_PKMODE_SRC_SEG_SHIFT) +#define OP_ALG_PKMODE_SRC_SEG_3 (3 << OP_ALG_PKMODE_SRC_SEG_SHIFT) +#define OP_ALG_PKMODE_DST_SEG_0 (0 << OP_ALG_PKMODE_DST_SEG_SHIFT) +#define OP_ALG_PKMODE_DST_SEG_1 (1 << OP_ALG_PKMODE_DST_SEG_SHIFT) +#define OP_ALG_PKMODE_DST_SEG_2 (2 << OP_ALG_PKMODE_DST_SEG_SHIFT) +#define OP_ALG_PKMODE_DST_SEG_3 (3 << OP_ALG_PKMODE_DST_SEG_SHIFT) +#define OP_ALG_PKMODE_CPYMEM_N_SZ 0x80 +#define OP_ALG_PKMODE_CPYMEM_SRC_SZ 0x81 + +/* + * SEQ_IN_PTR Command Constructs + */ + +/* Release Buffers */ +#define SQIN_RBS 0x04000000 + +/* Sequence pointer is really a descriptor */ +#define SQIN_INL 0x02000000 + +/* Sequence pointer is a scatter-gather table */ +#define SQIN_SGF 0x01000000 + +/* Appends to a previous pointer */ +#define SQIN_PRE 0x00800000 + +/* Use extended length following pointer */ +#define SQIN_EXT 0x00400000 + +/* Restore sequence with pointer/length */ +#define SQIN_RTO 0x00200000 + +/* Replace job descriptor */ +#define SQIN_RJD 0x00100000 + +#define SQIN_LEN_SHIFT 0 +#define SQIN_LEN_MASK (0xffff << SQIN_LEN_SHIFT) + +/* + * SEQ_OUT_PTR Command Constructs + */ + +/* Sequence pointer is a scatter-gather table */ +#define SQOUT_SGF 0x01000000 + +/* Appends to a previous pointer */ +#define SQOUT_PRE 0x00800000 + +/* Restore sequence with pointer/length */ +#define SQOUT_RTO 0x00200000 + +/* Use extended length following pointer */ +#define SQOUT_EXT 0x00400000 + +#define SQOUT_LEN_SHIFT 0 +#define SQOUT_LEN_MASK (0xffff << SQOUT_LEN_SHIFT) + + +/* + * SIGNATURE Command Constructs + */ + +/* TYPE field is all that's relevant */ +#define SIGN_TYPE_SHIFT 16 +#define SIGN_TYPE_MASK (0x0f << SIGN_TYPE_SHIFT) + +#define SIGN_TYPE_FINAL (0x00 << SIGN_TYPE_SHIFT) +#define SIGN_TYPE_FINAL_RESTORE (0x01 << SIGN_TYPE_SHIFT) +#define SIGN_TYPE_FINAL_NONZERO (0x02 << SIGN_TYPE_SHIFT) +#define SIGN_TYPE_IMM_2 (0x0a << SIGN_TYPE_SHIFT) +#define SIGN_TYPE_IMM_3 (0x0b << SIGN_TYPE_SHIFT) +#define SIGN_TYPE_IMM_4 (0x0c << SIGN_TYPE_SHIFT) + +/* + * MOVE Command Constructs + */ + +#define MOVE_AUX_SHIFT 25 +#define MOVE_AUX_MASK (3 << MOVE_AUX_SHIFT) +#define MOVE_AUX_MS (2 << MOVE_AUX_SHIFT) +#define MOVE_AUX_LS (1 << MOVE_AUX_SHIFT) + +#define MOVE_WAITCOMP_SHIFT 24 +#define MOVE_WAITCOMP_MASK (1 << MOVE_WAITCOMP_SHIFT) +#define MOVE_WAITCOMP (1 << MOVE_WAITCOMP_SHIFT) + +#define MOVE_SRC_SHIFT 20 +#define MOVE_SRC_MASK (0x0f << MOVE_SRC_SHIFT) +#define MOVE_SRC_CLASS1CTX (0x00 << MOVE_SRC_SHIFT) +#define MOVE_SRC_CLASS2CTX (0x01 << MOVE_SRC_SHIFT) +#define MOVE_SRC_OUTFIFO (0x02 << MOVE_SRC_SHIFT) +#define MOVE_SRC_DESCBUF (0x03 << MOVE_SRC_SHIFT) +#define MOVE_SRC_MATH0 (0x04 << MOVE_SRC_SHIFT) +#define MOVE_SRC_MATH1 (0x05 << MOVE_SRC_SHIFT) +#define MOVE_SRC_MATH2 (0x06 << MOVE_SRC_SHIFT) +#define MOVE_SRC_MATH3 (0x07 << MOVE_SRC_SHIFT) +#define MOVE_SRC_INFIFO (0x08 << MOVE_SRC_SHIFT) +#define MOVE_SRC_INFIFO_CL (0x09 << MOVE_SRC_SHIFT) + +#define MOVE_DEST_SHIFT 16 +#define MOVE_DEST_MASK (0x0f << MOVE_DEST_SHIFT) +#define MOVE_DEST_CLASS1CTX (0x00 << MOVE_DEST_SHIFT) +#define MOVE_DEST_CLASS2CTX (0x01 << MOVE_DEST_SHIFT) +#define MOVE_DEST_OUTFIFO (0x02 << MOVE_DEST_SHIFT) +#define MOVE_DEST_DESCBUF (0x03 << MOVE_DEST_SHIFT) +#define MOVE_DEST_MATH0 (0x04 << MOVE_DEST_SHIFT) +#define MOVE_DEST_MATH1 (0x05 << MOVE_DEST_SHIFT) +#define MOVE_DEST_MATH2 (0x06 << MOVE_DEST_SHIFT) +#define MOVE_DEST_MATH3 (0x07 << MOVE_DEST_SHIFT) +#define MOVE_DEST_CLASS1INFIFO (0x08 << MOVE_DEST_SHIFT) +#define MOVE_DEST_CLASS2INFIFO (0x09 << MOVE_DEST_SHIFT) +#define MOVE_DEST_PK_A (0x0c << MOVE_DEST_SHIFT) +#define MOVE_DEST_CLASS1KEY (0x0d << MOVE_DEST_SHIFT) +#define MOVE_DEST_CLASS2KEY (0x0e << MOVE_DEST_SHIFT) + +#define MOVE_OFFSET_SHIFT 8 +#define MOVE_OFFSET_MASK (0xff << MOVE_OFFSET_SHIFT) + +#define MOVE_LEN_SHIFT 0 +#define MOVE_LEN_MASK (0xff << MOVE_LEN_SHIFT) + +#define MOVELEN_MRSEL_SHIFT 0 +#define MOVELEN_MRSEL_MASK (0x3 << MOVE_LEN_SHIFT) + +/* + * MATH Command Constructs + */ + +#define MATH_IFB_SHIFT 26 +#define MATH_IFB_MASK (1 << MATH_IFB_SHIFT) +#define MATH_IFB (1 << MATH_IFB_SHIFT) + +#define MATH_NFU_SHIFT 25 +#define MATH_NFU_MASK (1 << MATH_NFU_SHIFT) +#define MATH_NFU (1 << MATH_NFU_SHIFT) + +#define MATH_STL_SHIFT 24 +#define MATH_STL_MASK (1 << MATH_STL_SHIFT) +#define MATH_STL (1 << MATH_STL_SHIFT) + +/* Function selectors */ +#define MATH_FUN_SHIFT 20 +#define MATH_FUN_MASK (0x0f << MATH_FUN_SHIFT) +#define MATH_FUN_ADD (0x00 << MATH_FUN_SHIFT) +#define MATH_FUN_ADDC (0x01 << MATH_FUN_SHIFT) +#define MATH_FUN_SUB (0x02 << MATH_FUN_SHIFT) +#define MATH_FUN_SUBB (0x03 << MATH_FUN_SHIFT) +#define MATH_FUN_OR (0x04 << MATH_FUN_SHIFT) +#define MATH_FUN_AND (0x05 << MATH_FUN_SHIFT) +#define MATH_FUN_XOR (0x06 << MATH_FUN_SHIFT) +#define MATH_FUN_LSHIFT (0x07 << MATH_FUN_SHIFT) +#define MATH_FUN_RSHIFT (0x08 << MATH_FUN_SHIFT) +#define MATH_FUN_SHLD (0x09 << MATH_FUN_SHIFT) +#define MATH_FUN_ZBYT (0x0a << MATH_FUN_SHIFT) + +/* Source 0 selectors */ +#define MATH_SRC0_SHIFT 16 +#define MATH_SRC0_MASK (0x0f << MATH_SRC0_SHIFT) +#define MATH_SRC0_REG0 (0x00 << MATH_SRC0_SHIFT) +#define MATH_SRC0_REG1 (0x01 << MATH_SRC0_SHIFT) +#define MATH_SRC0_REG2 (0x02 << MATH_SRC0_SHIFT) +#define MATH_SRC0_REG3 (0x03 << MATH_SRC0_SHIFT) +#define MATH_SRC0_IMM (0x04 << MATH_SRC0_SHIFT) +#define MATH_SRC0_SEQINLEN (0x08 << MATH_SRC0_SHIFT) +#define MATH_SRC0_SEQOUTLEN (0x09 << MATH_SRC0_SHIFT) +#define MATH_SRC0_VARSEQINLEN (0x0a << MATH_SRC0_SHIFT) +#define MATH_SRC0_VARSEQOUTLEN (0x0b << MATH_SRC0_SHIFT) +#define MATH_SRC0_ZERO (0x0c << MATH_SRC0_SHIFT) + +/* Source 1 selectors */ +#define MATH_SRC1_SHIFT 12 +#define MATH_SRC1_MASK (0x0f << MATH_SRC1_SHIFT) +#define MATH_SRC1_REG0 (0x00 << MATH_SRC1_SHIFT) +#define MATH_SRC1_REG1 (0x01 << MATH_SRC1_SHIFT) +#define MATH_SRC1_REG2 (0x02 << MATH_SRC1_SHIFT) +#define MATH_SRC1_REG3 (0x03 << MATH_SRC1_SHIFT) +#define MATH_SRC1_IMM (0x04 << MATH_SRC1_SHIFT) +#define MATH_SRC1_INFIFO (0x0a << MATH_SRC1_SHIFT) +#define MATH_SRC1_OUTFIFO (0x0b << MATH_SRC1_SHIFT) +#define MATH_SRC1_ONE (0x0c << MATH_SRC1_SHIFT) + +/* Destination selectors */ +#define MATH_DEST_SHIFT 8 +#define MATH_DEST_MASK (0x0f << MATH_DEST_SHIFT) +#define MATH_DEST_REG0 (0x00 << MATH_DEST_SHIFT) +#define MATH_DEST_REG1 (0x01 << MATH_DEST_SHIFT) +#define MATH_DEST_REG2 (0x02 << MATH_DEST_SHIFT) +#define MATH_DEST_REG3 (0x03 << MATH_DEST_SHIFT) +#define MATH_DEST_SEQINLEN (0x08 << MATH_DEST_SHIFT) +#define MATH_DEST_SEQOUTLEN (0x09 << MATH_DEST_SHIFT) +#define MATH_DEST_VARSEQINLEN (0x0a << MATH_DEST_SHIFT) +#define MATH_DEST_VARSEQOUTLEN (0x0b << MATH_DEST_SHIFT) +#define MATH_DEST_NONE (0x0f << MATH_DEST_SHIFT) + +/* Length selectors */ +#define MATH_LEN_SHIFT 0 +#define MATH_LEN_MASK (0x0f << MATH_LEN_SHIFT) +#define MATH_LEN_1BYTE 0x01 +#define MATH_LEN_2BYTE 0x02 +#define MATH_LEN_4BYTE 0x04 +#define MATH_LEN_8BYTE 0x08 + +/* + * JUMP Command Constructs + */ + +#define JUMP_CLASS_SHIFT 25 +#define JUMP_CLASS_MASK (3 << JUMP_CLASS_SHIFT) +#define JUMP_CLASS_NONE 0 +#define JUMP_CLASS_CLASS1 (1 << JUMP_CLASS_SHIFT) +#define JUMP_CLASS_CLASS2 (2 << JUMP_CLASS_SHIFT) +#define JUMP_CLASS_BOTH (3 << JUMP_CLASS_SHIFT) + +#define JUMP_JSL_SHIFT 24 +#define JUMP_JSL_MASK (1 << JUMP_JSL_SHIFT) +#define JUMP_JSL (1 << JUMP_JSL_SHIFT) + +#define JUMP_TYPE_SHIFT 22 +#define JUMP_TYPE_MASK (0x03 << JUMP_TYPE_SHIFT) +#define JUMP_TYPE_LOCAL (0x00 << JUMP_TYPE_SHIFT) +#define JUMP_TYPE_NONLOCAL (0x01 << JUMP_TYPE_SHIFT) +#define JUMP_TYPE_HALT (0x02 << JUMP_TYPE_SHIFT) +#define JUMP_TYPE_HALT_USER (0x03 << JUMP_TYPE_SHIFT) + +#define JUMP_TEST_SHIFT 16 +#define JUMP_TEST_MASK (0x03 << JUMP_TEST_SHIFT) +#define JUMP_TEST_ALL (0x00 << JUMP_TEST_SHIFT) +#define JUMP_TEST_INVALL (0x01 << JUMP_TEST_SHIFT) +#define JUMP_TEST_ANY (0x02 << JUMP_TEST_SHIFT) +#define JUMP_TEST_INVANY (0x03 << JUMP_TEST_SHIFT) + +/* Condition codes. JSL bit is factored in */ +#define JUMP_COND_SHIFT 8 +#define JUMP_COND_MASK (0x100ff << JUMP_COND_SHIFT) +#define JUMP_COND_PK_0 (0x80 << JUMP_COND_SHIFT) +#define JUMP_COND_PK_GCD_1 (0x40 << JUMP_COND_SHIFT) +#define JUMP_COND_PK_PRIME (0x20 << JUMP_COND_SHIFT) +#define JUMP_COND_MATH_N (0x08 << JUMP_COND_SHIFT) +#define JUMP_COND_MATH_Z (0x04 << JUMP_COND_SHIFT) +#define JUMP_COND_MATH_C (0x02 << JUMP_COND_SHIFT) +#define JUMP_COND_MATH_NV (0x01 << JUMP_COND_SHIFT) + +#define JUMP_COND_JRP ((0x80 << JUMP_COND_SHIFT) | JUMP_JSL) +#define JUMP_COND_SHRD ((0x40 << JUMP_COND_SHIFT) | JUMP_JSL) +#define JUMP_COND_SELF ((0x20 << JUMP_COND_SHIFT) | JUMP_JSL) +#define JUMP_COND_CALM ((0x10 << JUMP_COND_SHIFT) | JUMP_JSL) +#define JUMP_COND_NIP ((0x08 << JUMP_COND_SHIFT) | JUMP_JSL) +#define JUMP_COND_NIFP ((0x04 << JUMP_COND_SHIFT) | JUMP_JSL) +#define JUMP_COND_NOP ((0x02 << JUMP_COND_SHIFT) | JUMP_JSL) +#define JUMP_COND_NCP ((0x01 << JUMP_COND_SHIFT) | JUMP_JSL) + +#define JUMP_OFFSET_SHIFT 0 +#define JUMP_OFFSET_MASK (0xff << JUMP_OFFSET_SHIFT) + +/* + * NFIFO ENTRY + * Data Constructs + * + */ +#define NFIFOENTRY_DEST_SHIFT 30 +#define NFIFOENTRY_DEST_MASK (3 << NFIFOENTRY_DEST_SHIFT) +#define NFIFOENTRY_DEST_DECO (0 << NFIFOENTRY_DEST_SHIFT) +#define NFIFOENTRY_DEST_CLASS1 (1 << NFIFOENTRY_DEST_SHIFT) +#define NFIFOENTRY_DEST_CLASS2 (2 << NFIFOENTRY_DEST_SHIFT) +#define NFIFOENTRY_DEST_BOTH (3 << NFIFOENTRY_DEST_SHIFT) + +#define NFIFOENTRY_LC2_SHIFT 29 +#define NFIFOENTRY_LC2_MASK (1 << NFIFOENTRY_LC2_SHIFT) +#define NFIFOENTRY_LC2 (1 << NFIFOENTRY_LC2_SHIFT) + +#define NFIFOENTRY_LC1_SHIFT 28 +#define NFIFOENTRY_LC1_MASK (1 << NFIFOENTRY_LC1_SHIFT) +#define NFIFOENTRY_LC1 (1 << NFIFOENTRY_LC1_SHIFT) + +#define NFIFOENTRY_FC2_SHIFT 27 +#define NFIFOENTRY_FC2_MASK (1 << NFIFOENTRY_FC2_SHIFT) +#define NFIFOENTRY_FC2 (1 << NFIFOENTRY_FC2_SHIFT) + +#define NFIFOENTRY_FC1_SHIFT 26 +#define NFIFOENTRY_FC1_MASK (1 << NFIFOENTRY_FC1_SHIFT) +#define NFIFOENTRY_FC1 (1 << NFIFOENTRY_FC1_SHIFT) + +#define NFIFOENTRY_STYPE_SHIFT 24 +#define NFIFOENTRY_STYPE_MASK (3 << NFIFOENTRY_STYPE_SHIFT) +#define NFIFOENTRY_STYPE_DFIFO (0 << NFIFOENTRY_STYPE_SHIFT) +#define NFIFOENTRY_STYPE_OFIFO (1 << NFIFOENTRY_STYPE_SHIFT) +#define NFIFOENTRY_STYPE_PAD (2 << NFIFOENTRY_STYPE_SHIFT) +#define NFIFOENTRY_STYPE_SNOOP (3 << NFIFOENTRY_STYPE_SHIFT) + +#define NFIFOENTRY_DTYPE_SHIFT 20 +#define NFIFOENTRY_DTYPE_MASK (0xF << NFIFOENTRY_DTYPE_SHIFT) + +#define NFIFOENTRY_DTYPE_SBOX (0x0 << NFIFOENTRY_DTYPE_SHIFT) +#define NFIFOENTRY_DTYPE_AAD (0x1 << NFIFOENTRY_DTYPE_SHIFT) +#define NFIFOENTRY_DTYPE_IV (0x2 << NFIFOENTRY_DTYPE_SHIFT) +#define NFIFOENTRY_DTYPE_SAD (0x3 << NFIFOENTRY_DTYPE_SHIFT) +#define NFIFOENTRY_DTYPE_ICV (0xA << NFIFOENTRY_DTYPE_SHIFT) +#define NFIFOENTRY_DTYPE_SKIP (0xE << NFIFOENTRY_DTYPE_SHIFT) +#define NFIFOENTRY_DTYPE_MSG (0xF << NFIFOENTRY_DTYPE_SHIFT) + +#define NFIFOENTRY_DTYPE_PK_A0 (0x0 << NFIFOENTRY_DTYPE_SHIFT) +#define NFIFOENTRY_DTYPE_PK_A1 (0x1 << NFIFOENTRY_DTYPE_SHIFT) +#define NFIFOENTRY_DTYPE_PK_A2 (0x2 << NFIFOENTRY_DTYPE_SHIFT) +#define NFIFOENTRY_DTYPE_PK_A3 (0x3 << NFIFOENTRY_DTYPE_SHIFT) +#define NFIFOENTRY_DTYPE_PK_B0 (0x4 << NFIFOENTRY_DTYPE_SHIFT) +#define NFIFOENTRY_DTYPE_PK_B1 (0x5 << NFIFOENTRY_DTYPE_SHIFT) +#define NFIFOENTRY_DTYPE_PK_B2 (0x6 << NFIFOENTRY_DTYPE_SHIFT) +#define NFIFOENTRY_DTYPE_PK_B3 (0x7 << NFIFOENTRY_DTYPE_SHIFT) +#define NFIFOENTRY_DTYPE_PK_N (0x8 << NFIFOENTRY_DTYPE_SHIFT) +#define NFIFOENTRY_DTYPE_PK_E (0x9 << NFIFOENTRY_DTYPE_SHIFT) +#define NFIFOENTRY_DTYPE_PK_A (0xC << NFIFOENTRY_DTYPE_SHIFT) +#define NFIFOENTRY_DTYPE_PK_B (0xD << NFIFOENTRY_DTYPE_SHIFT) + + +#define NFIFOENTRY_BND_SHIFT 19 +#define NFIFOENTRY_BND_MASK (1 << NFIFOENTRY_BND_SHIFT) +#define NFIFOENTRY_BND (1 << NFIFOENTRY_BND_SHIFT) + +#define NFIFOENTRY_PTYPE_SHIFT 16 +#define NFIFOENTRY_PTYPE_MASK (0x7 << NFIFOENTRY_PTYPE_SHIFT) + +#define NFIFOENTRY_PTYPE_ZEROS (0x0 << NFIFOENTRY_PTYPE_SHIFT) +#define NFIFOENTRY_PTYPE_RND_NOZEROS (0x1 << NFIFOENTRY_PTYPE_SHIFT) +#define NFIFOENTRY_PTYPE_INCREMENT (0x2 << NFIFOENTRY_PTYPE_SHIFT) +#define NFIFOENTRY_PTYPE_RND (0x3 << NFIFOENTRY_PTYPE_SHIFT) +#define NFIFOENTRY_PTYPE_ZEROS_NZ (0x4 << NFIFOENTRY_PTYPE_SHIFT) +#define NFIFOENTRY_PTYPE_RND_NZ_LZ (0x5 << NFIFOENTRY_PTYPE_SHIFT) +#define NFIFOENTRY_PTYPE_N (0x6 << NFIFOENTRY_PTYPE_SHIFT) +#define NFIFOENTRY_PTYPE_RND_NZ_N (0x7 << NFIFOENTRY_PTYPE_SHIFT) + +#define NFIFOENTRY_OC_SHIFT 15 +#define NFIFOENTRY_OC_MASK (1 << NFIFOENTRY_OC_SHIFT) +#define NFIFOENTRY_OC (1 << NFIFOENTRY_OC_SHIFT) + +#define NFIFOENTRY_AST_SHIFT 14 +#define NFIFOENTRY_AST_MASK (1 << NFIFOENTRY_OC_SHIFT) +#define NFIFOENTRY_AST (1 << NFIFOENTRY_OC_SHIFT) + +#define NFIFOENTRY_BM_SHIFT 11 +#define NFIFOENTRY_BM_MASK (1 << NFIFOENTRY_BM_SHIFT) +#define NFIFOENTRY_BM (1 << NFIFOENTRY_BM_SHIFT) + +#define NFIFOENTRY_PS_SHIFT 10 +#define NFIFOENTRY_PS_MASK (1 << NFIFOENTRY_PS_SHIFT) +#define NFIFOENTRY_PS (1 << NFIFOENTRY_PS_SHIFT) + + +#define NFIFOENTRY_DLEN_SHIFT 0 +#define NFIFOENTRY_DLEN_MASK (0xFFF << NFIFOENTRY_DLEN_SHIFT) + +#define NFIFOENTRY_PLEN_SHIFT 0 +#define NFIFOENTRY_PLEN_MASK (0xFF << NFIFOENTRY_PLEN_SHIFT) + +/* + * PDB internal definitions + */ + +/* IPSec ESP CBC Encap/Decap Options */ +#define PDBOPTS_ESPCBC_ARSNONE 0x00 /* no antireplay window */ +#define PDBOPTS_ESPCBC_ARS32 0x40 /* 32-entry antireplay window */ +#define PDBOPTS_ESPCBC_ARS64 0xc0 /* 64-entry antireplay window */ +#define PDBOPTS_ESPCBC_IVSRC 0x20 /* IV comes from internal random gen */ +#define PDBOPTS_ESPCBC_ESN 0x10 /* extended sequence included */ +#define PDBOPTS_ESPCBC_OUTFMT 0x08 /* output only decapsulation (decap) */ +#define PDBOPTS_ESPCBC_IPHDRSRC 0x08 /* IP header comes from PDB (encap) */ +#define PDBOPTS_ESPCBC_INCIPHDR 0x04 /* Prepend IP header to output frame */ +#define PDBOPTS_ESPCBC_IPVSN 0x02 /* process IPv6 header */ +#define PDBOPTS_ESPCBC_TUNNEL 0x01 /* tunnel mode next-header byte */ + +#endif /* DESC_H */ diff --git a/drivers/crypto/caam/desc_constr.h b/drivers/crypto/caam/desc_constr.h new file mode 100644 index 0000000..c224f39 --- /dev/null +++ b/drivers/crypto/caam/desc_constr.h @@ -0,0 +1,204 @@ +/* + * caam descriptor construction helper functions + * + * Copyright 2008-2011 Freescale Semiconductor, Inc. + */ + +#include "desc.h" + +#define IMMEDIATE (1 << 23) +#define CAAM_CMD_SZ sizeof(u32) +#define CAAM_PTR_SZ sizeof(dma_addr_t) + +#ifdef DEBUG +#define PRINT_POS do { printk(KERN_DEBUG "%02d: %s\n", desc_len(desc),\ + &__func__[sizeof("append")]); } while (0) +#else +#define PRINT_POS +#endif + +#define DISABLE_AUTO_INFO_FIFO (IMMEDIATE | LDST_CLASS_DECO | \ + LDST_SRCDST_WORD_DECOCTRL | \ + (LDOFF_DISABLE_AUTO_NFIFO << LDST_OFFSET_SHIFT)) +#define ENABLE_AUTO_INFO_FIFO (IMMEDIATE | LDST_CLASS_DECO | \ + LDST_SRCDST_WORD_DECOCTRL | \ + (LDOFF_ENABLE_AUTO_NFIFO << LDST_OFFSET_SHIFT)) + +static inline int desc_len(u32 *desc) +{ + return *desc & HDR_DESCLEN_MASK; +} + +static inline int desc_bytes(void *desc) +{ + return desc_len(desc) * CAAM_CMD_SZ; +} + +static inline u32 *desc_end(u32 *desc) +{ + return desc + desc_len(desc); +} + +static inline void *sh_desc_pdb(u32 *desc) +{ + return desc + 1; +} + +static inline void init_desc(u32 *desc, u32 options) +{ + *desc = options | HDR_ONE | 1; +} + +static inline void init_sh_desc(u32 *desc, u32 options) +{ + PRINT_POS; + init_desc(desc, CMD_SHARED_DESC_HDR | options); +} + +static inline void init_sh_desc_pdb(u32 *desc, u32 options, size_t pdb_bytes) +{ + u32 pdb_len = pdb_bytes / CAAM_CMD_SZ + 1; + + init_sh_desc(desc, ((pdb_len << HDR_START_IDX_SHIFT) + pdb_len) | + options); +} + +static inline void init_job_desc(u32 *desc, u32 options) +{ + init_desc(desc, CMD_DESC_HDR | options); +} + +static inline void append_ptr(u32 *desc, dma_addr_t ptr) +{ + dma_addr_t *offset = (dma_addr_t *)desc_end(desc); + + *offset = ptr; + + (*desc) += CAAM_PTR_SZ / CAAM_CMD_SZ; +} + +static inline void init_job_desc_shared(u32 *desc, dma_addr_t ptr, int len, + u32 options) +{ + PRINT_POS; + init_job_desc(desc, HDR_SHARED | options | + (len << HDR_START_IDX_SHIFT)); + append_ptr(desc, ptr); +} + +static inline void append_data(u32 *desc, void *data, int len) +{ + u32 *offset = desc_end(desc); + + if (len) /* avoid sparse warning: memcpy with byte count of 0 */ + memcpy(offset, data, len); + + (*desc) += (len + CAAM_CMD_SZ - 1) / CAAM_CMD_SZ; +} + +static inline void append_cmd(u32 *desc, u32 command) +{ + u32 *cmd = desc_end(desc); + + *cmd = command; + + (*desc)++; +} + +static inline void append_cmd_ptr(u32 *desc, dma_addr_t ptr, int len, + u32 command) +{ + append_cmd(desc, command | len); + append_ptr(desc, ptr); +} + +static inline void append_cmd_data(u32 *desc, void *data, int len, + u32 command) +{ + append_cmd(desc, command | IMMEDIATE | len); + append_data(desc, data, len); +} + +static inline u32 *append_jump(u32 *desc, u32 options) +{ + u32 *cmd = desc_end(desc); + + PRINT_POS; + append_cmd(desc, CMD_JUMP | options); + + return cmd; +} + +static inline void set_jump_tgt_here(u32 *desc, u32 *jump_cmd) +{ + *jump_cmd = *jump_cmd | (desc_len(desc) - (jump_cmd - desc)); +} + +#define APPEND_CMD(cmd, op) \ +static inline void append_##cmd(u32 *desc, u32 options) \ +{ \ + PRINT_POS; \ + append_cmd(desc, CMD_##op | options); \ +} +APPEND_CMD(operation, OPERATION) +APPEND_CMD(move, MOVE) + +#define APPEND_CMD_LEN(cmd, op) \ +static inline void append_##cmd(u32 *desc, unsigned int len, u32 options) \ +{ \ + PRINT_POS; \ + append_cmd(desc, CMD_##op | len | options); \ +} +APPEND_CMD_LEN(seq_store, SEQ_STORE) +APPEND_CMD_LEN(seq_fifo_load, SEQ_FIFO_LOAD) +APPEND_CMD_LEN(seq_fifo_store, SEQ_FIFO_STORE) + +#define APPEND_CMD_PTR(cmd, op) \ +static inline void append_##cmd(u32 *desc, dma_addr_t ptr, unsigned int len, \ + u32 options) \ +{ \ + PRINT_POS; \ + append_cmd_ptr(desc, ptr, len, CMD_##op | options); \ +} +APPEND_CMD_PTR(key, KEY) +APPEND_CMD_PTR(seq_in_ptr, SEQ_IN_PTR) +APPEND_CMD_PTR(seq_out_ptr, SEQ_OUT_PTR) +APPEND_CMD_PTR(load, LOAD) +APPEND_CMD_PTR(store, STORE) +APPEND_CMD_PTR(fifo_load, FIFO_LOAD) +APPEND_CMD_PTR(fifo_store, FIFO_STORE) + +#define APPEND_CMD_PTR_TO_IMM(cmd, op) \ +static inline void append_##cmd##_as_imm(u32 *desc, void *data, \ + unsigned int len, u32 options) \ +{ \ + PRINT_POS; \ + append_cmd_data(desc, data, len, CMD_##op | options); \ +} +APPEND_CMD_PTR_TO_IMM(load, LOAD); +APPEND_CMD_PTR_TO_IMM(fifo_load, FIFO_LOAD); + +/* + * 2nd variant for commands whose specified immediate length differs + * from length of immediate data provided, e.g., split keys + */ +#define APPEND_CMD_PTR_TO_IMM2(cmd, op) \ +static inline void append_##cmd##_as_imm(u32 *desc, void *data, \ + unsigned int data_len, \ + unsigned int len, u32 options) \ +{ \ + PRINT_POS; \ + append_cmd(desc, CMD_##op | IMMEDIATE | len | options); \ + append_data(desc, data, data_len); \ +} +APPEND_CMD_PTR_TO_IMM2(key, KEY); + +#define APPEND_CMD_RAW_IMM(cmd, op, type) \ +static inline void append_##cmd##_imm_##type(u32 *desc, type immediate, \ + u32 options) \ +{ \ + PRINT_POS; \ + append_cmd(desc, CMD_##op | IMMEDIATE | options | sizeof(type)); \ + append_cmd(desc, immediate); \ +} +APPEND_CMD_RAW_IMM(load, LOAD, u32); diff --git a/drivers/crypto/caam/error.c b/drivers/crypto/caam/error.c new file mode 100644 index 0000000..bd57a68 --- /dev/null +++ b/drivers/crypto/caam/error.c @@ -0,0 +1,248 @@ +/* + * CAAM Error Reporting + * + * Copyright 2009-2011 Freescale Semiconductor, Inc. + */ + +#include "compat.h" +#include "regs.h" +#include "intern.h" +#include "desc.h" +#include "jr.h" +#include "error.h" + +#define SPRINTFCAT(str, format, param, max_alloc) \ +{ \ + char *tmp; \ + \ + tmp = kmalloc(sizeof(format) + max_alloc, GFP_ATOMIC); \ + sprintf(tmp, format, param); \ + strcat(str, tmp); \ + kfree(tmp); \ +} + +static void report_jump_idx(u32 status, char *outstr) +{ + u8 idx = (status & JRSTA_DECOERR_INDEX_MASK) >> + JRSTA_DECOERR_INDEX_SHIFT; + + if (status & JRSTA_DECOERR_JUMP) + strcat(outstr, "jump tgt desc idx "); + else + strcat(outstr, "desc idx "); + + SPRINTFCAT(outstr, "%d: ", idx, sizeof("255")); +} + +static void report_ccb_status(u32 status, char *outstr) +{ + char *cha_id_list[] = { + "", + "AES", + "DES, 3DES", + "ARC4", + "MD5, SHA-1, SH-224, SHA-256, SHA-384, SHA-512", + "RNG", + "SNOW f8", + "Kasumi f8, f9", + "All Public Key Algorithms", + "CRC", + "SNOW f9", + }; + char *err_id_list[] = { + "None. No error.", + "Mode error.", + "Data size error.", + "Key size error.", + "PKHA A memory size error.", + "PKHA B memory size error.", + "Data arrived out of sequence error.", + "PKHA divide-by-zero error.", + "PKHA modulus even error.", + "DES key parity error.", + "ICV check failed.", + "Hardware error.", + "Unsupported CCM AAD size.", + "Class 1 CHA is not reset", + "Invalid CHA combination was selected", + "Invalid CHA selected.", + }; + u8 cha_id = (status & JRSTA_CCBERR_CHAID_MASK) >> + JRSTA_CCBERR_CHAID_SHIFT; + u8 err_id = status & JRSTA_CCBERR_ERRID_MASK; + + report_jump_idx(status, outstr); + + if (cha_id < sizeof(cha_id_list)) { + SPRINTFCAT(outstr, "%s: ", cha_id_list[cha_id], + strlen(cha_id_list[cha_id])); + } else { + SPRINTFCAT(outstr, "unidentified cha_id value 0x%02x: ", + cha_id, sizeof("ff")); + } + + if (err_id < sizeof(err_id_list)) { + SPRINTFCAT(outstr, "%s", err_id_list[err_id], + strlen(err_id_list[err_id])); + } else { + SPRINTFCAT(outstr, "unidentified err_id value 0x%02x", + err_id, sizeof("ff")); + } +} + +static void report_jump_status(u32 status, char *outstr) +{ + SPRINTFCAT(outstr, "%s() not implemented", __func__, sizeof(__func__)); +} + +static void report_deco_status(u32 status, char *outstr) +{ + const struct { + u8 value; + char *error_text; + } desc_error_list[] = { + { 0x00, "None. No error." }, + { 0x01, "SGT Length Error. The descriptor is trying to read " + "more data than is contained in the SGT table." }, + { 0x02, "Reserved." }, + { 0x03, "Job Ring Control Error. There is a bad value in the " + "Job Ring Control register." }, + { 0x04, "Invalid Descriptor Command. The Descriptor Command " + "field is invalid." }, + { 0x05, "Reserved." }, + { 0x06, "Invalid KEY Command" }, + { 0x07, "Invalid LOAD Command" }, + { 0x08, "Invalid STORE Command" }, + { 0x09, "Invalid OPERATION Command" }, + { 0x0A, "Invalid FIFO LOAD Command" }, + { 0x0B, "Invalid FIFO STORE Command" }, + { 0x0C, "Invalid MOVE Command" }, + { 0x0D, "Invalid JUMP Command. A nonlocal JUMP Command is " + "invalid because the target is not a Job Header " + "Command, or the jump is from a Trusted Descriptor to " + "a Job Descriptor, or because the target Descriptor " + "contains a Shared Descriptor." }, + { 0x0E, "Invalid MATH Command" }, + { 0x0F, "Invalid SIGNATURE Command" }, + { 0x10, "Invalid Sequence Command. A SEQ IN PTR OR SEQ OUT PTR " + "Command is invalid or a SEQ KEY, SEQ LOAD, SEQ FIFO " + "LOAD, or SEQ FIFO STORE decremented the input or " + "output sequence length below 0. This error may result " + "if a built-in PROTOCOL Command has encountered a " + "malformed PDU." }, + { 0x11, "Skip data type invalid. The type must be 0xE or 0xF."}, + { 0x12, "Shared Descriptor Header Error" }, + { 0x13, "Header Error. Invalid length or parity, or certain " + "other problems." }, + { 0x14, "Burster Error. Burster has gotten to an illegal " + "state" }, + { 0x15, "Context Register Length Error. The descriptor is " + "trying to read or write past the end of the Context " + "Register. A SEQ LOAD or SEQ STORE with the VLF bit " + "set was executed with too large a length in the " + "variable length register (VSOL for SEQ STORE or VSIL " + "for SEQ LOAD)." }, + { 0x16, "DMA Error" }, + { 0x17, "Reserved." }, + { 0x1A, "Job failed due to JR reset" }, + { 0x1B, "Job failed due to Fail Mode" }, + { 0x1C, "DECO Watchdog timer timeout error" }, + { 0x1D, "DECO tried to copy a key from another DECO but the " + "other DECO's Key Registers were locked" }, + { 0x1E, "DECO attempted to copy data from a DECO that had an " + "unmasked Descriptor error" }, + { 0x1F, "LIODN error. DECO was trying to share from itself or " + "from another DECO but the two Non-SEQ LIODN values " + "didn't match or the 'shared from' DECO's Descriptor " + "required that the SEQ LIODNs be the same and they " + "aren't." }, + { 0x20, "DECO has completed a reset initiated via the DRR " + "register" }, + { 0x21, "Nonce error. When using EKT (CCM) key encryption " + "option in the FIFO STORE Command, the Nonce counter " + "reached its maximum value and this encryption mode " + "can no longer be used." }, + { 0x22, "Meta data is too large (> 511 bytes) for TLS decap " + "(input frame; block ciphers) and IPsec decap (output " + "frame, when doing the next header byte update) and " + "DCRC (output frame)." }, + { 0x80, "DNR (do not run) error" }, + { 0x81, "undefined protocol command" }, + { 0x82, "invalid setting in PDB" }, + { 0x83, "Anti-replay LATE error" }, + { 0x84, "Anti-replay REPLAY error" }, + { 0x85, "Sequence number overflow" }, + { 0x86, "Sigver invalid signature" }, + { 0x87, "DSA Sign Illegal test descriptor" }, + { 0x88, "Protocol Format Error - A protocol has seen an error " + "in the format of data received. When running RSA, " + "this means that formatting with random padding was " + "used, and did not follow the form: 0x00, 0x02, 8-to-N " + "bytes of non-zero pad, 0x00, F data." }, + { 0x89, "Protocol Size Error - A protocol has seen an error in " + "size. When running RSA, pdb size N < (size of F) when " + "no formatting is used; or pdb size N < (F + 11) when " + "formatting is used." }, + { 0xC1, "Blob Command error: Undefined mode" }, + { 0xC2, "Blob Command error: Secure Memory Blob mode error" }, + { 0xC4, "Blob Command error: Black Blob key or input size " + "error" }, + { 0xC5, "Blob Command error: Invalid key destination" }, + { 0xC8, "Blob Command error: Trusted/Secure mode error" }, + { 0xF0, "IPsec TTL or hop limit field either came in as 0, " + "or was decremented to 0" }, + { 0xF1, "3GPP HFN matches or exceeds the Threshold" }, + }; + u8 desc_error = status & JRSTA_DECOERR_ERROR_MASK; + int i; + + report_jump_idx(status, outstr); + + for (i = 0; i < sizeof(desc_error_list); i++) + if (desc_error_list[i].value == desc_error) + break; + + if (i != sizeof(desc_error_list) && desc_error_list[i].error_text) { + SPRINTFCAT(outstr, "%s", desc_error_list[i].error_text, + strlen(desc_error_list[i].error_text)); + } else { + SPRINTFCAT(outstr, "unidentified error value 0x%02x", + desc_error, sizeof("ff")); + } +} + +static void report_jr_status(u32 status, char *outstr) +{ + SPRINTFCAT(outstr, "%s() not implemented", __func__, sizeof(__func__)); +} + +static void report_cond_code_status(u32 status, char *outstr) +{ + SPRINTFCAT(outstr, "%s() not implemented", __func__, sizeof(__func__)); +} + +char *caam_jr_strstatus(char *outstr, u32 status) +{ + struct stat_src { + void (*report_ssed)(u32 status, char *outstr); + char *error; + } status_src[] = { + { NULL, "No error" }, + { NULL, NULL }, + { report_ccb_status, "CCB" }, + { report_jump_status, "Jump" }, + { report_deco_status, "DECO" }, + { NULL, NULL }, + { report_jr_status, "Job Ring" }, + { report_cond_code_status, "Condition Code" }, + }; + u32 ssrc = status >> JRSTA_SSRC_SHIFT; + + sprintf(outstr, "%s: ", status_src[ssrc].error); + + if (status_src[ssrc].report_ssed) + status_src[ssrc].report_ssed(status, outstr); + + return outstr; +} +EXPORT_SYMBOL(caam_jr_strstatus); diff --git a/drivers/crypto/caam/error.h b/drivers/crypto/caam/error.h new file mode 100644 index 0000000..067afc1 --- /dev/null +++ b/drivers/crypto/caam/error.h @@ -0,0 +1,10 @@ +/* + * CAAM Error Reporting code header + * + * Copyright 2009-2011 Freescale Semiconductor, Inc. + */ + +#ifndef CAAM_ERROR_H +#define CAAM_ERROR_H +extern char *caam_jr_strstatus(char *outstr, u32 status); +#endif /* CAAM_ERROR_H */ diff --git a/drivers/crypto/caam/intern.h b/drivers/crypto/caam/intern.h new file mode 100644 index 0000000..a34be01 --- /dev/null +++ b/drivers/crypto/caam/intern.h @@ -0,0 +1,113 @@ +/* + * CAAM/SEC 4.x driver backend + * Private/internal definitions between modules + * + * Copyright 2008-2011 Freescale Semiconductor, Inc. + * + */ + +#ifndef INTERN_H +#define INTERN_H + +#define JOBR_UNASSIGNED 0 +#define JOBR_ASSIGNED 1 + +/* Currently comes from Kconfig param as a ^2 (driver-required) */ +#define JOBR_DEPTH (1 << CONFIG_CRYPTO_DEV_FSL_CAAM_RINGSIZE) + +/* Kconfig params for interrupt coalescing if selected (else zero) */ +#ifdef CONFIG_CRYPTO_DEV_FSL_CAAM_INTC +#define JOBR_INTC JRCFG_ICEN +#define JOBR_INTC_TIME_THLD CONFIG_CRYPTO_DEV_FSL_CAAM_INTC_TIME_THLD +#define JOBR_INTC_COUNT_THLD CONFIG_CRYPTO_DEV_FSL_CAAM_INTC_COUNT_THLD +#else +#define JOBR_INTC 0 +#define JOBR_INTC_TIME_THLD 0 +#define JOBR_INTC_COUNT_THLD 0 +#endif + +/* + * Storage for tracking each in-process entry moving across a ring + * Each entry on an output ring needs one of these + */ +struct caam_jrentry_info { + void (*callbk)(struct device *dev, u32 *desc, u32 status, void *arg); + void *cbkarg; /* Argument per ring entry */ + u32 *desc_addr_virt; /* Stored virt addr for postprocessing */ + dma_addr_t desc_addr_dma; /* Stored bus addr for done matching */ + u32 desc_size; /* Stored size for postprocessing, header derived */ +}; + +/* Private sub-storage for a single JobR */ +struct caam_drv_private_jr { + struct device *parentdev; /* points back to controller dev */ + int ridx; + struct caam_job_ring __iomem *rregs; /* JobR's register space */ + struct tasklet_struct irqtask[NR_CPUS]; + int irq; /* One per queue */ + int assign; /* busy/free */ + + /* Job ring info */ + int ringsize; /* Size of rings (assume input = output) */ + struct caam_jrentry_info *entinfo; /* Alloc'ed 1 per ring entry */ + spinlock_t inplock ____cacheline_aligned; /* Input ring index lock */ + int inp_ring_write_index; /* Input index "tail" */ + int head; /* entinfo (s/w ring) head index */ + dma_addr_t *inpring; /* Base of input ring, alloc DMA-safe */ + spinlock_t outlock ____cacheline_aligned; /* Output ring index lock */ + int out_ring_read_index; /* Output index "tail" */ + int tail; /* entinfo (s/w ring) tail index */ + struct jr_outentry *outring; /* Base of output ring, DMA-safe */ +}; + +/* + * Driver-private storage for a single CAAM block instance + */ +struct caam_drv_private { + + struct device *dev; + struct device **jrdev; /* Alloc'ed array per sub-device */ + spinlock_t jr_alloc_lock; + struct platform_device *pdev; + + /* Physical-presence section */ + struct caam_ctrl *ctrl; /* controller region */ + struct caam_deco **deco; /* DECO/CCB views */ + struct caam_assurance *ac; + struct caam_queue_if *qi; /* QI control region */ + + /* + * Detected geometry block. Filled in from device tree if powerpc, + * or from register-based version detection code + */ + u8 total_jobrs; /* Total Job Rings in device */ + u8 qi_present; /* Nonzero if QI present in device */ + int secvio_irq; /* Security violation interrupt number */ + + /* which jr allocated to scatterlist crypto */ + atomic_t tfm_count ____cacheline_aligned; + int num_jrs_for_algapi; + struct device **algapi_jr; + /* list of registered crypto algorithms (mk generic context handle?) */ + struct list_head alg_list; + + /* + * debugfs entries for developer view into driver/device + * variables at runtime. + */ +#ifdef CONFIG_DEBUG_FS + struct dentry *dfs_root; + struct dentry *ctl; /* controller dir */ + struct dentry *ctl_rq_dequeued, *ctl_ob_enc_req, *ctl_ib_dec_req; + struct dentry *ctl_ob_enc_bytes, *ctl_ob_prot_bytes; + struct dentry *ctl_ib_dec_bytes, *ctl_ib_valid_bytes; + struct dentry *ctl_faultaddr, *ctl_faultdetail, *ctl_faultstatus; + + struct debugfs_blob_wrapper ctl_kek_wrap, ctl_tkek_wrap, ctl_tdsk_wrap; + struct dentry *ctl_kek, *ctl_tkek, *ctl_tdsk; +#endif +}; + +void caam_jr_algapi_init(struct device *dev); +void caam_jr_algapi_remove(struct device *dev); +#endif /* INTERN_H */ diff --git a/drivers/crypto/caam/jr.c b/drivers/crypto/caam/jr.c new file mode 100644 index 0000000..68cb9af --- /dev/null +++ b/drivers/crypto/caam/jr.c @@ -0,0 +1,523 @@ +/* + * CAAM/SEC 4.x transport/backend driver + * JobR backend functionality + * + * Copyright 2008-2011 Freescale Semiconductor, Inc. + */ + +#include "compat.h" +#include "regs.h" +#include "jr.h" +#include "desc.h" +#include "intern.h" + +/* Main per-ring interrupt handler */ +static irqreturn_t caam_jr_interrupt(int irq, void *st_dev) +{ + struct device *dev = st_dev; + struct caam_drv_private_jr *jrp = dev_get_drvdata(dev); + u32 irqstate; + + /* + * Check the output ring for ready responses, kick + * tasklet if jobs done. + */ + irqstate = rd_reg32(&jrp->rregs->jrintstatus); + if (!irqstate) + return IRQ_NONE; + + /* + * If JobR error, we got more development work to do + * Flag a bug now, but we really need to shut down and + * restart the queue (and fix code). + */ + if (irqstate & JRINT_JR_ERROR) { + dev_err(dev, "job ring error: irqstate: %08x\n", irqstate); + BUG(); + } + + /* mask valid interrupts */ + setbits32(&jrp->rregs->rconfig_lo, JRCFG_IMSK); + + /* Have valid interrupt at this point, just ACK and trigger */ + wr_reg32(&jrp->rregs->jrintstatus, irqstate); + + preempt_disable(); + tasklet_schedule(&jrp->irqtask[smp_processor_id()]); + preempt_enable(); + + return IRQ_HANDLED; +} + +/* Deferred service handler, run as interrupt-fired tasklet */ +static void caam_jr_dequeue(unsigned long devarg) +{ + int hw_idx, sw_idx, i, head, tail; + struct device *dev = (struct device *)devarg; + struct caam_drv_private_jr *jrp = dev_get_drvdata(dev); + void (*usercall)(struct device *dev, u32 *desc, u32 status, void *arg); + u32 *userdesc, userstatus; + void *userarg; + unsigned long flags; + + spin_lock_irqsave(&jrp->outlock, flags); + + head = ACCESS_ONCE(jrp->head); + sw_idx = tail = jrp->tail; + + while (CIRC_CNT(head, tail, JOBR_DEPTH) >= 1 && + rd_reg32(&jrp->rregs->outring_used)) { + + hw_idx = jrp->out_ring_read_index; + for (i = 0; CIRC_CNT(head, tail + i, JOBR_DEPTH) >= 1; i++) { + sw_idx = (tail + i) & (JOBR_DEPTH - 1); + + smp_read_barrier_depends(); + + if (jrp->outring[hw_idx].desc == + jrp->entinfo[sw_idx].desc_addr_dma) + break; /* found */ + } + /* we should never fail to find a matching descriptor */ + BUG_ON(CIRC_CNT(head, tail + i, JOBR_DEPTH) <= 0); + + /* Unmap just-run descriptor so we can post-process */ + dma_unmap_single(dev, jrp->outring[hw_idx].desc, + jrp->entinfo[sw_idx].desc_size, + DMA_TO_DEVICE); + + /* mark completed, avoid matching on a recycled desc addr */ + jrp->entinfo[sw_idx].desc_addr_dma = 0; + + /* Stash callback params for use outside of lock */ + usercall = jrp->entinfo[sw_idx].callbk; + userarg = jrp->entinfo[sw_idx].cbkarg; + userdesc = jrp->entinfo[sw_idx].desc_addr_virt; + userstatus = jrp->outring[hw_idx].jrstatus; + + smp_mb(); + + jrp->out_ring_read_index = (jrp->out_ring_read_index + 1) & + (JOBR_DEPTH - 1); + + /* + * if this job completed out-of-order, do not increment + * the tail. Otherwise, increment tail by 1 plus the + * number of subsequent jobs already completed out-of-order + */ + if (sw_idx == tail) { + do { + tail = (tail + 1) & (JOBR_DEPTH - 1); + smp_read_barrier_depends(); + } while (CIRC_CNT(head, tail, JOBR_DEPTH) >= 1 && + jrp->entinfo[tail].desc_addr_dma == 0); + + jrp->tail = tail; + } + + /* set done */ + wr_reg32(&jrp->rregs->outring_rmvd, 1); + + spin_unlock_irqrestore(&jrp->outlock, flags); + + /* Finally, execute user's callback */ + usercall(dev, userdesc, userstatus, userarg); + + spin_lock_irqsave(&jrp->outlock, flags); + + head = ACCESS_ONCE(jrp->head); + sw_idx = tail = jrp->tail; + } + + spin_unlock_irqrestore(&jrp->outlock, flags); + + /* reenable / unmask IRQs */ + clrbits32(&jrp->rregs->rconfig_lo, JRCFG_IMSK); +} + +/** + * caam_jr_register() - Alloc a ring for someone to use as needed. Returns + * an ordinal of the rings allocated, else returns -ENODEV if no rings + * are available. + * @ctrldev: points to the controller level dev (parent) that + * owns rings available for use. + * @dev: points to where a pointer to the newly allocated queue's + * dev can be written to if successful. + **/ +int caam_jr_register(struct device *ctrldev, struct device **rdev) +{ + struct caam_drv_private *ctrlpriv = dev_get_drvdata(ctrldev); + struct caam_drv_private_jr *jrpriv = NULL; + unsigned long flags; + int ring; + + /* Lock, if free ring - assign, unlock */ + spin_lock_irqsave(&ctrlpriv->jr_alloc_lock, flags); + for (ring = 0; ring < ctrlpriv->total_jobrs; ring++) { + jrpriv = dev_get_drvdata(ctrlpriv->jrdev[ring]); + if (jrpriv->assign == JOBR_UNASSIGNED) { + jrpriv->assign = JOBR_ASSIGNED; + *rdev = ctrlpriv->jrdev[ring]; + spin_unlock_irqrestore(&ctrlpriv->jr_alloc_lock, flags); + return ring; + } + } + + /* If assigned, write dev where caller needs it */ + spin_unlock_irqrestore(&ctrlpriv->jr_alloc_lock, flags); + *rdev = NULL; + + return -ENODEV; +} +EXPORT_SYMBOL(caam_jr_register); + +/** + * caam_jr_deregister() - Deregister an API and release the queue. + * Returns 0 if OK, -EBUSY if queue still contains pending entries + * or unprocessed results at the time of the call + * @dev - points to the dev that identifies the queue to + * be released. + **/ +int caam_jr_deregister(struct device *rdev) +{ + struct caam_drv_private_jr *jrpriv = dev_get_drvdata(rdev); + struct caam_drv_private *ctrlpriv; + unsigned long flags; + + /* Get the owning controller's private space */ + ctrlpriv = dev_get_drvdata(jrpriv->parentdev); + + /* + * Make sure ring empty before release + */ + if (rd_reg32(&jrpriv->rregs->outring_used) || + (rd_reg32(&jrpriv->rregs->inpring_avail) != JOBR_DEPTH)) + return -EBUSY; + + /* Release ring */ + spin_lock_irqsave(&ctrlpriv->jr_alloc_lock, flags); + jrpriv->assign = JOBR_UNASSIGNED; + spin_unlock_irqrestore(&ctrlpriv->jr_alloc_lock, flags); + + return 0; +} +EXPORT_SYMBOL(caam_jr_deregister); + +/** + * caam_jr_enqueue() - Enqueue a job descriptor head. Returns 0 if OK, + * -EBUSY if the queue is full, -EIO if it cannot map the caller's + * descriptor. + * @dev: device of the job ring to be used. This device should have + * been assigned prior by caam_jr_register(). + * @desc: points to a job descriptor that execute our request. All + * descriptors (and all referenced data) must be in a DMAable + * region, and all data references must be physical addresses + * accessible to CAAM (i.e. within a PAMU window granted + * to it). + * @cbk: pointer to a callback function to be invoked upon completion + * of this request. This has the form: + * callback(struct device *dev, u32 *desc, u32 stat, void *arg) + * where: + * @dev: contains the job ring device that processed this + * response. + * @desc: descriptor that initiated the request, same as + * "desc" being argued to caam_jr_enqueue(). + * @status: untranslated status received from CAAM. See the + * reference manual for a detailed description of + * error meaning, or see the JRSTA definitions in the + * register header file + * @areq: optional pointer to an argument passed with the + * original request + * @areq: optional pointer to a user argument for use at callback + * time. + **/ +int caam_jr_enqueue(struct device *dev, u32 *desc, + void (*cbk)(struct device *dev, u32 *desc, + u32 status, void *areq), + void *areq) +{ + struct caam_drv_private_jr *jrp = dev_get_drvdata(dev); + struct caam_jrentry_info *head_entry; + unsigned long flags; + int head, tail, desc_size; + dma_addr_t desc_dma; + + desc_size = (*desc & HDR_JD_LENGTH_MASK) * sizeof(u32); + desc_dma = dma_map_single(dev, desc, desc_size, DMA_TO_DEVICE); + if (dma_mapping_error(dev, desc_dma)) { + dev_err(dev, "caam_jr_enqueue(): can't map jobdesc\n"); + return -EIO; + } + + spin_lock_irqsave(&jrp->inplock, flags); + + head = jrp->head; + tail = ACCESS_ONCE(jrp->tail); + + if (!rd_reg32(&jrp->rregs->inpring_avail) || + CIRC_SPACE(head, tail, JOBR_DEPTH) <= 0) { + spin_unlock_irqrestore(&jrp->inplock, flags); + dma_unmap_single(dev, desc_dma, desc_size, DMA_TO_DEVICE); + return -EBUSY; + } + + head_entry = &jrp->entinfo[head]; + head_entry->desc_addr_virt = desc; + head_entry->desc_size = desc_size; + head_entry->callbk = (void *)cbk; + head_entry->cbkarg = areq; + head_entry->desc_addr_dma = desc_dma; + + jrp->inpring[jrp->inp_ring_write_index] = desc_dma; + + smp_wmb(); + + jrp->inp_ring_write_index = (jrp->inp_ring_write_index + 1) & + (JOBR_DEPTH - 1); + jrp->head = (head + 1) & (JOBR_DEPTH - 1); + + wmb(); + + wr_reg32(&jrp->rregs->inpring_jobadd, 1); + + spin_unlock_irqrestore(&jrp->inplock, flags); + + return 0; +} +EXPORT_SYMBOL(caam_jr_enqueue); + +static int caam_reset_hw_jr(struct device *dev) +{ + struct caam_drv_private_jr *jrp = dev_get_drvdata(dev); + unsigned int timeout = 100000; + + /* + * FIXME: disabling IRQs here inhibits proper job completion + * and error propagation + */ + disable_irq(jrp->irq); + + /* initiate flush (required prior to reset) */ + wr_reg32(&jrp->rregs->jrcommand, JRCR_RESET); + while (((rd_reg32(&jrp->rregs->jrintstatus) & JRINT_ERR_HALT_MASK) == + JRINT_ERR_HALT_INPROGRESS) && --timeout) + cpu_relax(); + + if ((rd_reg32(&jrp->rregs->jrintstatus) & JRINT_ERR_HALT_MASK) != + JRINT_ERR_HALT_COMPLETE || timeout == 0) { + dev_err(dev, "failed to flush job ring %d\n", jrp->ridx); + return -EIO; + } + + /* initiate reset */ + timeout = 100000; + wr_reg32(&jrp->rregs->jrcommand, JRCR_RESET); + while ((rd_reg32(&jrp->rregs->jrcommand) & JRCR_RESET) && --timeout) + cpu_relax(); + + if (timeout == 0) { + dev_err(dev, "failed to reset job ring %d\n", jrp->ridx); + return -EIO; + } + + enable_irq(jrp->irq); + + return 0; +} + +/* + * Init JobR independent of platform property detection + */ +static int caam_jr_init(struct device *dev) +{ + struct caam_drv_private_jr *jrp; + dma_addr_t inpbusaddr, outbusaddr; + int i, error; + + jrp = dev_get_drvdata(dev); + + error = caam_reset_hw_jr(dev); + if (error) + return error; + + jrp->inpring = kzalloc(sizeof(dma_addr_t) * JOBR_DEPTH, + GFP_KERNEL | GFP_DMA); + jrp->outring = kzalloc(sizeof(struct jr_outentry) * + JOBR_DEPTH, GFP_KERNEL | GFP_DMA); + + jrp->entinfo = kzalloc(sizeof(struct caam_jrentry_info) * JOBR_DEPTH, + GFP_KERNEL); + + if ((jrp->inpring == NULL) || (jrp->outring == NULL) || + (jrp->entinfo == NULL)) { + dev_err(dev, "can't allocate job rings for %d\n", + jrp->ridx); + return -ENOMEM; + } + + for (i = 0; i < JOBR_DEPTH; i++) + jrp->entinfo[i].desc_addr_dma = !0; + + /* Setup rings */ + inpbusaddr = dma_map_single(dev, jrp->inpring, + sizeof(u32 *) * JOBR_DEPTH, + DMA_BIDIRECTIONAL); + if (dma_mapping_error(dev, inpbusaddr)) { + dev_err(dev, "caam_jr_init(): can't map input ring\n"); + kfree(jrp->inpring); + kfree(jrp->outring); + kfree(jrp->entinfo); + return -EIO; + } + + outbusaddr = dma_map_single(dev, jrp->outring, + sizeof(struct jr_outentry) * JOBR_DEPTH, + DMA_BIDIRECTIONAL); + if (dma_mapping_error(dev, outbusaddr)) { + dev_err(dev, "caam_jr_init(): can't map output ring\n"); + dma_unmap_single(dev, inpbusaddr, + sizeof(u32 *) * JOBR_DEPTH, + DMA_BIDIRECTIONAL); + kfree(jrp->inpring); + kfree(jrp->outring); + kfree(jrp->entinfo); + return -EIO; + } + + jrp->inp_ring_write_index = 0; + jrp->out_ring_read_index = 0; + jrp->head = 0; + jrp->tail = 0; + + wr_reg64(&jrp->rregs->inpring_base, inpbusaddr); + wr_reg64(&jrp->rregs->outring_base, outbusaddr); + wr_reg32(&jrp->rregs->inpring_size, JOBR_DEPTH); + wr_reg32(&jrp->rregs->outring_size, JOBR_DEPTH); + + jrp->ringsize = JOBR_DEPTH; + + spin_lock_init(&jrp->inplock); + spin_lock_init(&jrp->outlock); + + /* Select interrupt coalescing parameters */ + setbits32(&jrp->rregs->rconfig_lo, JOBR_INTC | + (JOBR_INTC_COUNT_THLD << JRCFG_ICDCT_SHIFT) | + (JOBR_INTC_TIME_THLD << JRCFG_ICTT_SHIFT)); + + /* Connect job ring interrupt handler. */ + for_each_possible_cpu(i) + tasklet_init(&jrp->irqtask[i], caam_jr_dequeue, + (unsigned long)dev); + + error = request_irq(jrp->irq, caam_jr_interrupt, 0, + "caam-jobr", dev); + if (error) { + dev_err(dev, "can't connect JobR %d interrupt (%d)\n", + jrp->ridx, jrp->irq); + irq_dispose_mapping(jrp->irq); + jrp->irq = 0; + dma_unmap_single(dev, inpbusaddr, sizeof(u32 *) * JOBR_DEPTH, + DMA_BIDIRECTIONAL); + dma_unmap_single(dev, outbusaddr, sizeof(u32 *) * JOBR_DEPTH, + DMA_BIDIRECTIONAL); + kfree(jrp->inpring); + kfree(jrp->outring); + kfree(jrp->entinfo); + return -EINVAL; + } + + jrp->assign = JOBR_UNASSIGNED; + return 0; +} + +/* + * Shutdown JobR independent of platform property code + */ +int caam_jr_shutdown(struct device *dev) +{ + struct caam_drv_private_jr *jrp = dev_get_drvdata(dev); + dma_addr_t inpbusaddr, outbusaddr; + int ret, i; + + ret = caam_reset_hw_jr(dev); + + for_each_possible_cpu(i) + tasklet_kill(&jrp->irqtask[i]); + + /* Release interrupt */ + free_irq(jrp->irq, dev); + + /* Free rings */ + inpbusaddr = rd_reg64(&jrp->rregs->inpring_base); + outbusaddr = rd_reg64(&jrp->rregs->outring_base); + dma_unmap_single(dev, outbusaddr, + sizeof(struct jr_outentry) * JOBR_DEPTH, + DMA_BIDIRECTIONAL); + dma_unmap_single(dev, inpbusaddr, sizeof(u32 *) * JOBR_DEPTH, + DMA_BIDIRECTIONAL); + kfree(jrp->outring); + kfree(jrp->inpring); + kfree(jrp->entinfo); + + return ret; +} + +/* + * Probe routine for each detected JobR subsystem. It assumes that + * property detection was picked up externally. + */ +int caam_jr_probe(struct platform_device *pdev, struct device_node *np, + int ring) +{ + struct device *ctrldev, *jrdev; + struct platform_device *jr_pdev; + struct caam_drv_private *ctrlpriv; + struct caam_drv_private_jr *jrpriv; + u32 *jroffset; + int error; + + ctrldev = &pdev->dev; + ctrlpriv = dev_get_drvdata(ctrldev); + + jrpriv = kmalloc(sizeof(struct caam_drv_private_jr), + GFP_KERNEL); + if (jrpriv == NULL) { + dev_err(ctrldev, "can't alloc private mem for job ring %d\n", + ring); + return -ENOMEM; + } + jrpriv->parentdev = ctrldev; /* point back to parent */ + jrpriv->ridx = ring; /* save ring identity relative to detection */ + + /* + * Derive a pointer to the detected JobRs regs + * Driver has already iomapped the entire space, we just + * need to add in the offset to this JobR. Don't know if I + * like this long-term, but it'll run + */ + jroffset = (u32 *)of_get_property(np, "reg", NULL); + jrpriv->rregs = (struct caam_job_ring __iomem *)((void *)ctrlpriv->ctrl + + *jroffset); + + /* Build a local dev for each detected queue */ + jr_pdev = of_platform_device_create(np, NULL, ctrldev); + if (jr_pdev == NULL) { + kfree(jrpriv); + return -EINVAL; + } + jrdev = &jr_pdev->dev; + dev_set_drvdata(jrdev, jrpriv); + ctrlpriv->jrdev[ring] = jrdev; + + /* Identify the interrupt */ + jrpriv->irq = of_irq_to_resource(np, 0, NULL); + + /* Now do the platform independent part */ + error = caam_jr_init(jrdev); /* now turn on hardware */ + if (error) { + kfree(jrpriv); + return error; + } + + return error; +} diff --git a/drivers/crypto/caam/jr.h b/drivers/crypto/caam/jr.h new file mode 100644 index 0000000..c23df39 --- /dev/null +++ b/drivers/crypto/caam/jr.h @@ -0,0 +1,21 @@ +/* + * CAAM public-level include definitions for the JobR backend + * + * Copyright 2008-2011 Freescale Semiconductor, Inc. + */ + +#ifndef JR_H +#define JR_H + +/* Prototypes for backend-level services exposed to APIs */ +int caam_jr_register(struct device *ctrldev, struct device **rdev); +int caam_jr_deregister(struct device *rdev); +int caam_jr_enqueue(struct device *dev, u32 *desc, + void (*cbk)(struct device *dev, u32 *desc, u32 status, + void *areq), + void *areq); + +extern int caam_jr_probe(struct platform_device *pdev, struct device_node *np, + int ring); +extern int caam_jr_shutdown(struct device *dev); +#endif /* JR_H */ diff --git a/drivers/crypto/caam/regs.h b/drivers/crypto/caam/regs.h new file mode 100644 index 0000000..d063a26 --- /dev/null +++ b/drivers/crypto/caam/regs.h @@ -0,0 +1,663 @@ +/* + * CAAM hardware register-level view + * + * Copyright 2008-2011 Freescale Semiconductor, Inc. + */ + +#ifndef REGS_H +#define REGS_H + +#include +#include + +/* + * Architecture-specific register access methods + * + * CAAM's bus-addressable registers are 64 bits internally. + * They have been wired to be safely accessible on 32-bit + * architectures, however. Registers were organized such + * that (a) they can be contained in 32 bits, (b) if not, then they + * can be treated as two 32-bit entities, or finally (c) if they + * must be treated as a single 64-bit value, then this can safely + * be done with two 32-bit cycles. + * + * For 32-bit operations on 64-bit values, CAAM follows the same + * 64-bit register access conventions as it's predecessors, in that + * writes are "triggered" by a write to the register at the numerically + * higher address, thus, a full 64-bit write cycle requires a write + * to the lower address, followed by a write to the higher address, + * which will latch/execute the write cycle. + * + * For example, let's assume a SW reset of CAAM through the master + * configuration register. + * - SWRST is in bit 31 of MCFG. + * - MCFG begins at base+0x0000. + * - Bits 63-32 are a 32-bit word at base+0x0000 (numerically-lower) + * - Bits 31-0 are a 32-bit word at base+0x0004 (numerically-higher) + * + * (and on Power, the convention is 0-31, 32-63, I know...) + * + * Assuming a 64-bit write to this MCFG to perform a software reset + * would then require a write of 0 to base+0x0000, followed by a + * write of 0x80000000 to base+0x0004, which would "execute" the + * reset. + * + * Of course, since MCFG 63-32 is all zero, we could cheat and simply + * write 0x8000000 to base+0x0004, and the reset would work fine. + * However, since CAAM does contain some write-and-read-intended + * 64-bit registers, this code defines 64-bit access methods for + * the sake of internal consistency and simplicity, and so that a + * clean transition to 64-bit is possible when it becomes necessary. + * + * There are limitations to this that the developer must recognize. + * 32-bit architectures cannot enforce an atomic-64 operation, + * Therefore: + * + * - On writes, since the HW is assumed to latch the cycle on the + * write of the higher-numeric-address word, then ordered + * writes work OK. + * + * - For reads, where a register contains a relevant value of more + * that 32 bits, the hardware employs logic to latch the other + * "half" of the data until read, ensuring an accurate value. + * This is of particular relevance when dealing with CAAM's + * performance counters. + * + */ + +#ifdef __BIG_ENDIAN +#define wr_reg32(reg, data) out_be32(reg, data) +#define rd_reg32(reg) in_be32(reg) +#ifdef CONFIG_64BIT +#define wr_reg64(reg, data) out_be64(reg, data) +#define rd_reg64(reg) in_be64(reg) +#endif +#else +#ifdef __LITTLE_ENDIAN +#define wr_reg32(reg, data) __raw_writel(reg, data) +#define rd_reg32(reg) __raw_readl(reg) +#ifdef CONFIG_64BIT +#define wr_reg64(reg, data) __raw_writeq(reg, data) +#define rd_reg64(reg) __raw_readq(reg) +#endif +#endif +#endif + +#ifndef CONFIG_64BIT +static inline void wr_reg64(u64 __iomem *reg, u64 data) +{ + wr_reg32((u32 __iomem *)reg, (data & 0xffffffff00000000ull) >> 32); + wr_reg32((u32 __iomem *)reg + 1, data & 0x00000000ffffffffull); +} + +static inline u64 rd_reg64(u64 __iomem *reg) +{ + return (((u64)rd_reg32((u32 __iomem *)reg)) << 32) | + ((u64)rd_reg32((u32 __iomem *)reg + 1)); +} +#endif + +/* + * jr_outentry + * Represents each entry in a JobR output ring + */ +struct jr_outentry { + dma_addr_t desc;/* Pointer to completed descriptor */ + u32 jrstatus; /* Status for completed descriptor */ +} __packed; + +/* + * caam_perfmon - Performance Monitor/Secure Memory Status/ + * CAAM Global Status/Component Version IDs + * + * Spans f00-fff wherever instantiated + */ + +/* Number of DECOs */ +#define CHA_NUM_DECONUM_SHIFT 56 +#define CHA_NUM_DECONUM_MASK (0xfull << CHA_NUM_DECONUM_SHIFT) + +struct caam_perfmon { + /* Performance Monitor Registers f00-f9f */ + u64 req_dequeued; /* PC_REQ_DEQ - Dequeued Requests */ + u64 ob_enc_req; /* PC_OB_ENC_REQ - Outbound Encrypt Requests */ + u64 ib_dec_req; /* PC_IB_DEC_REQ - Inbound Decrypt Requests */ + u64 ob_enc_bytes; /* PC_OB_ENCRYPT - Outbound Bytes Encrypted */ + u64 ob_prot_bytes; /* PC_OB_PROTECT - Outbound Bytes Protected */ + u64 ib_dec_bytes; /* PC_IB_DECRYPT - Inbound Bytes Decrypted */ + u64 ib_valid_bytes; /* PC_IB_VALIDATED Inbound Bytes Validated */ + u64 rsvd[13]; + + /* CAAM Hardware Instantiation Parameters fa0-fbf */ + u64 cha_rev; /* CRNR - CHA Revision Number */ +#define CTPR_QI_SHIFT 57 +#define CTPR_QI_MASK (0x1ull << CHA_NUM_DECONUM_SHIFT) + u64 comp_parms; /* CTPR - Compile Parameters Register */ + u64 rsvd1[2]; + + /* CAAM Global Status fc0-fdf */ + u64 faultaddr; /* FAR - Fault Address */ + u32 faultliodn; /* FALR - Fault Address LIODN */ + u32 faultdetail; /* FADR - Fault Addr Detail */ + u32 rsvd2; + u32 status; /* CSTA - CAAM Status */ + u64 rsvd3; + + /* Component Instantiation Parameters fe0-fff */ + u32 rtic_id; /* RVID - RTIC Version ID */ + u32 ccb_id; /* CCBVID - CCB Version ID */ + u64 cha_id; /* CHAVID - CHA Version ID */ + u64 cha_num; /* CHANUM - CHA Number */ + u64 caam_id; /* CAAMVID - CAAM Version ID */ +}; + +/* LIODN programming for DMA configuration */ +#define MSTRID_LOCK_LIODN 0x80000000 +#define MSTRID_LOCK_MAKETRUSTED 0x00010000 /* only for JR masterid */ + +#define MSTRID_LIODN_MASK 0x0fff +struct masterid { + u32 liodn_ms; /* lock and make-trusted control bits */ + u32 liodn_ls; /* LIODN for non-sequence and seq access */ +}; + +/* Partition ID for DMA configuration */ +struct partid { + u32 rsvd1; + u32 pidr; /* partition ID, DECO */ +}; + +/* RNG test mode (replicated twice in some configurations) */ +/* Padded out to 0x100 */ +struct rngtst { + u32 mode; /* RTSTMODEx - Test mode */ + u32 rsvd1[3]; + u32 reset; /* RTSTRESETx - Test reset control */ + u32 rsvd2[3]; + u32 status; /* RTSTSSTATUSx - Test status */ + u32 rsvd3; + u32 errstat; /* RTSTERRSTATx - Test error status */ + u32 rsvd4; + u32 errctl; /* RTSTERRCTLx - Test error control */ + u32 rsvd5; + u32 entropy; /* RTSTENTROPYx - Test entropy */ + u32 rsvd6[15]; + u32 verifctl; /* RTSTVERIFCTLx - Test verification control */ + u32 rsvd7; + u32 verifstat; /* RTSTVERIFSTATx - Test verification status */ + u32 rsvd8; + u32 verifdata; /* RTSTVERIFDx - Test verification data */ + u32 rsvd9; + u32 xkey; /* RTSTXKEYx - Test XKEY */ + u32 rsvd10; + u32 oscctctl; /* RTSTOSCCTCTLx - Test osc. counter control */ + u32 rsvd11; + u32 oscct; /* RTSTOSCCTx - Test oscillator counter */ + u32 rsvd12; + u32 oscctstat; /* RTSTODCCTSTATx - Test osc counter status */ + u32 rsvd13[2]; + u32 ofifo[4]; /* RTSTOFIFOx - Test output FIFO */ + u32 rsvd14[15]; +}; + +/* + * caam_ctrl - basic core configuration + * starts base + 0x0000 padded out to 0x1000 + */ + +#define KEK_KEY_SIZE 8 +#define TKEK_KEY_SIZE 8 +#define TDSK_KEY_SIZE 8 + +#define DECO_RESET 1 /* Use with DECO reset/availability regs */ +#define DECO_RESET_0 (DECO_RESET << 0) +#define DECO_RESET_1 (DECO_RESET << 1) +#define DECO_RESET_2 (DECO_RESET << 2) +#define DECO_RESET_3 (DECO_RESET << 3) +#define DECO_RESET_4 (DECO_RESET << 4) + +struct caam_ctrl { + /* Basic Configuration Section 000-01f */ + /* Read/Writable */ + u32 rsvd1; + u32 mcr; /* MCFG Master Config Register */ + u32 rsvd2[2]; + + /* Bus Access Configuration Section 010-11f */ + /* Read/Writable */ + struct masterid jr_mid[4]; /* JRxLIODNR - JobR LIODN setup */ + u32 rsvd3[12]; + struct masterid rtic_mid[4]; /* RTICxLIODNR - RTIC LIODN setup */ + u32 rsvd4[7]; + u32 deco_rq; /* DECORR - DECO Request */ + struct partid deco_mid[5]; /* DECOxLIODNR - 1 per DECO */ + u32 rsvd5[22]; + + /* DECO Availability/Reset Section 120-3ff */ + u32 deco_avail; /* DAR - DECO availability */ + u32 deco_reset; /* DRR - DECO reset */ + u32 rsvd6[182]; + + /* Key Encryption/Decryption Configuration 400-5ff */ + /* Read/Writable only while in Non-secure mode */ + u32 kek[KEK_KEY_SIZE]; /* JDKEKR - Key Encryption Key */ + u32 tkek[TKEK_KEY_SIZE]; /* TDKEKR - Trusted Desc KEK */ + u32 tdsk[TDSK_KEY_SIZE]; /* TDSKR - Trusted Desc Signing Key */ + u32 rsvd7[32]; + u64 sknonce; /* SKNR - Secure Key Nonce */ + u32 rsvd8[70]; + + /* RNG Test/Verification/Debug Access 600-7ff */ + /* (Useful in Test/Debug modes only...) */ + struct rngtst rtst[2]; + + u32 rsvd9[448]; + + /* Performance Monitor f00-fff */ + struct caam_perfmon perfmon; +}; + +/* + * Controller master config register defs + */ +#define MCFGR_SWRESET 0x80000000 /* software reset */ +#define MCFGR_WDENABLE 0x40000000 /* DECO watchdog enable */ +#define MCFGR_WDFAIL 0x20000000 /* DECO watchdog force-fail */ +#define MCFGR_DMA_RESET 0x10000000 +#define MCFGR_LONG_PTR 0x00010000 /* Use >32-bit desc addressing */ + +/* AXI read cache control */ +#define MCFGR_ARCACHE_SHIFT 12 +#define MCFGR_ARCACHE_MASK (0xf << MCFGR_ARCACHE_SHIFT) + +/* AXI write cache control */ +#define MCFGR_AWCACHE_SHIFT 8 +#define MCFGR_AWCACHE_MASK (0xf << MCFGR_AWCACHE_SHIFT) + +/* AXI pipeline depth */ +#define MCFGR_AXIPIPE_SHIFT 4 +#define MCFGR_AXIPIPE_MASK (0xf << MCFGR_AXIPIPE_SHIFT) + +#define MCFGR_AXIPRI 0x00000008 /* Assert AXI priority sideband */ +#define MCFGR_BURST_64 0x00000001 /* Max burst size */ + +/* + * caam_job_ring - direct job ring setup + * 1-4 possible per instantiation, base + 1000/2000/3000/4000 + * Padded out to 0x1000 + */ +struct caam_job_ring { + /* Input ring */ + u64 inpring_base; /* IRBAx - Input desc ring baseaddr */ + u32 rsvd1; + u32 inpring_size; /* IRSx - Input ring size */ + u32 rsvd2; + u32 inpring_avail; /* IRSAx - Input ring room remaining */ + u32 rsvd3; + u32 inpring_jobadd; /* IRJAx - Input ring jobs added */ + + /* Output Ring */ + u64 outring_base; /* ORBAx - Output status ring base addr */ + u32 rsvd4; + u32 outring_size; /* ORSx - Output ring size */ + u32 rsvd5; + u32 outring_rmvd; /* ORJRx - Output ring jobs removed */ + u32 rsvd6; + u32 outring_used; /* ORSFx - Output ring slots full */ + + /* Status/Configuration */ + u32 rsvd7; + u32 jroutstatus; /* JRSTAx - JobR output status */ + u32 rsvd8; + u32 jrintstatus; /* JRINTx - JobR interrupt status */ + u32 rconfig_hi; /* JRxCFG - Ring configuration */ + u32 rconfig_lo; + + /* Indices. CAAM maintains as "heads" of each queue */ + u32 rsvd9; + u32 inp_rdidx; /* IRRIx - Input ring read index */ + u32 rsvd10; + u32 out_wtidx; /* ORWIx - Output ring write index */ + + /* Command/control */ + u32 rsvd11; + u32 jrcommand; /* JRCRx - JobR command */ + + u32 rsvd12[932]; + + /* Performance Monitor f00-fff */ + struct caam_perfmon perfmon; +}; + +#define JR_RINGSIZE_MASK 0x03ff +/* + * jrstatus - Job Ring Output Status + * All values in lo word + * Also note, same values written out as status through QI + * in the command/status field of a frame descriptor + */ +#define JRSTA_SSRC_SHIFT 28 +#define JRSTA_SSRC_MASK 0xf0000000 + +#define JRSTA_SSRC_NONE 0x00000000 +#define JRSTA_SSRC_CCB_ERROR 0x20000000 +#define JRSTA_SSRC_JUMP_HALT_USER 0x30000000 +#define JRSTA_SSRC_DECO 0x40000000 +#define JRSTA_SSRC_JRERROR 0x60000000 +#define JRSTA_SSRC_JUMP_HALT_CC 0x70000000 + +#define JRSTA_DECOERR_JUMP 0x08000000 +#define JRSTA_DECOERR_INDEX_SHIFT 8 +#define JRSTA_DECOERR_INDEX_MASK 0xff00 +#define JRSTA_DECOERR_ERROR_MASK 0x00ff + +#define JRSTA_DECOERR_NONE 0x00 +#define JRSTA_DECOERR_LINKLEN 0x01 +#define JRSTA_DECOERR_LINKPTR 0x02 +#define JRSTA_DECOERR_JRCTRL 0x03 +#define JRSTA_DECOERR_DESCCMD 0x04 +#define JRSTA_DECOERR_ORDER 0x05 +#define JRSTA_DECOERR_KEYCMD 0x06 +#define JRSTA_DECOERR_LOADCMD 0x07 +#define JRSTA_DECOERR_STORECMD 0x08 +#define JRSTA_DECOERR_OPCMD 0x09 +#define JRSTA_DECOERR_FIFOLDCMD 0x0a +#define JRSTA_DECOERR_FIFOSTCMD 0x0b +#define JRSTA_DECOERR_MOVECMD 0x0c +#define JRSTA_DECOERR_JUMPCMD 0x0d +#define JRSTA_DECOERR_MATHCMD 0x0e +#define JRSTA_DECOERR_SHASHCMD 0x0f +#define JRSTA_DECOERR_SEQCMD 0x10 +#define JRSTA_DECOERR_DECOINTERNAL 0x11 +#define JRSTA_DECOERR_SHDESCHDR 0x12 +#define JRSTA_DECOERR_HDRLEN 0x13 +#define JRSTA_DECOERR_BURSTER 0x14 +#define JRSTA_DECOERR_DESCSIGNATURE 0x15 +#define JRSTA_DECOERR_DMA 0x16 +#define JRSTA_DECOERR_BURSTFIFO 0x17 +#define JRSTA_DECOERR_JRRESET 0x1a +#define JRSTA_DECOERR_JOBFAIL 0x1b +#define JRSTA_DECOERR_DNRERR 0x80 +#define JRSTA_DECOERR_UNDEFPCL 0x81 +#define JRSTA_DECOERR_PDBERR 0x82 +#define JRSTA_DECOERR_ANRPLY_LATE 0x83 +#define JRSTA_DECOERR_ANRPLY_REPLAY 0x84 +#define JRSTA_DECOERR_SEQOVF 0x85 +#define JRSTA_DECOERR_INVSIGN 0x86 +#define JRSTA_DECOERR_DSASIGN 0x87 + +#define JRSTA_CCBERR_JUMP 0x08000000 +#define JRSTA_CCBERR_INDEX_MASK 0xff00 +#define JRSTA_CCBERR_INDEX_SHIFT 8 +#define JRSTA_CCBERR_CHAID_MASK 0x00f0 +#define JRSTA_CCBERR_CHAID_SHIFT 4 +#define JRSTA_CCBERR_ERRID_MASK 0x000f + +#define JRSTA_CCBERR_CHAID_AES (0x01 << JRSTA_CCBERR_CHAID_SHIFT) +#define JRSTA_CCBERR_CHAID_DES (0x02 << JRSTA_CCBERR_CHAID_SHIFT) +#define JRSTA_CCBERR_CHAID_ARC4 (0x03 << JRSTA_CCBERR_CHAID_SHIFT) +#define JRSTA_CCBERR_CHAID_MD (0x04 << JRSTA_CCBERR_CHAID_SHIFT) +#define JRSTA_CCBERR_CHAID_RNG (0x05 << JRSTA_CCBERR_CHAID_SHIFT) +#define JRSTA_CCBERR_CHAID_SNOW (0x06 << JRSTA_CCBERR_CHAID_SHIFT) +#define JRSTA_CCBERR_CHAID_KASUMI (0x07 << JRSTA_CCBERR_CHAID_SHIFT) +#define JRSTA_CCBERR_CHAID_PK (0x08 << JRSTA_CCBERR_CHAID_SHIFT) +#define JRSTA_CCBERR_CHAID_CRC (0x09 << JRSTA_CCBERR_CHAID_SHIFT) + +#define JRSTA_CCBERR_ERRID_NONE 0x00 +#define JRSTA_CCBERR_ERRID_MODE 0x01 +#define JRSTA_CCBERR_ERRID_DATASIZ 0x02 +#define JRSTA_CCBERR_ERRID_KEYSIZ 0x03 +#define JRSTA_CCBERR_ERRID_PKAMEMSZ 0x04 +#define JRSTA_CCBERR_ERRID_PKBMEMSZ 0x05 +#define JRSTA_CCBERR_ERRID_SEQUENCE 0x06 +#define JRSTA_CCBERR_ERRID_PKDIVZRO 0x07 +#define JRSTA_CCBERR_ERRID_PKMODEVN 0x08 +#define JRSTA_CCBERR_ERRID_KEYPARIT 0x09 +#define JRSTA_CCBERR_ERRID_ICVCHK 0x0a +#define JRSTA_CCBERR_ERRID_HARDWARE 0x0b +#define JRSTA_CCBERR_ERRID_CCMAAD 0x0c +#define JRSTA_CCBERR_ERRID_INVCHA 0x0f + +#define JRINT_ERR_INDEX_MASK 0x3fff0000 +#define JRINT_ERR_INDEX_SHIFT 16 +#define JRINT_ERR_TYPE_MASK 0xf00 +#define JRINT_ERR_TYPE_SHIFT 8 +#define JRINT_ERR_HALT_MASK 0xc +#define JRINT_ERR_HALT_SHIFT 2 +#define JRINT_ERR_HALT_INPROGRESS 0x4 +#define JRINT_ERR_HALT_COMPLETE 0x8 +#define JRINT_JR_ERROR 0x02 +#define JRINT_JR_INT 0x01 + +#define JRINT_ERR_TYPE_WRITE 1 +#define JRINT_ERR_TYPE_BAD_INPADDR 3 +#define JRINT_ERR_TYPE_BAD_OUTADDR 4 +#define JRINT_ERR_TYPE_INV_INPWRT 5 +#define JRINT_ERR_TYPE_INV_OUTWRT 6 +#define JRINT_ERR_TYPE_RESET 7 +#define JRINT_ERR_TYPE_REMOVE_OFL 8 +#define JRINT_ERR_TYPE_ADD_OFL 9 + +#define JRCFG_SOE 0x04 +#define JRCFG_ICEN 0x02 +#define JRCFG_IMSK 0x01 +#define JRCFG_ICDCT_SHIFT 8 +#define JRCFG_ICTT_SHIFT 16 + +#define JRCR_RESET 0x01 + +/* + * caam_assurance - Assurance Controller View + * base + 0x6000 padded out to 0x1000 + */ + +struct rtic_element { + u64 address; + u32 rsvd; + u32 length; +}; + +struct rtic_block { + struct rtic_element element[2]; +}; + +struct rtic_memhash { + u32 memhash_be[32]; + u32 memhash_le[32]; +}; + +struct caam_assurance { + /* Status/Command/Watchdog */ + u32 rsvd1; + u32 status; /* RSTA - Status */ + u32 rsvd2; + u32 cmd; /* RCMD - Command */ + u32 rsvd3; + u32 ctrl; /* RCTL - Control */ + u32 rsvd4; + u32 throttle; /* RTHR - Throttle */ + u32 rsvd5[2]; + u64 watchdog; /* RWDOG - Watchdog Timer */ + u32 rsvd6; + u32 rend; /* REND - Endian corrections */ + u32 rsvd7[50]; + + /* Block access/configuration @ 100/110/120/130 */ + struct rtic_block memblk[4]; /* Memory Blocks A-D */ + u32 rsvd8[32]; + + /* Block hashes @ 200/300/400/500 */ + struct rtic_memhash hash[4]; /* Block hash values A-D */ + u32 rsvd_3[640]; +}; + +/* + * caam_queue_if - QI configuration and control + * starts base + 0x7000, padded out to 0x1000 long + */ + +struct caam_queue_if { + u32 qi_control_hi; /* QICTL - QI Control */ + u32 qi_control_lo; + u32 rsvd1; + u32 qi_status; /* QISTA - QI Status */ + u32 qi_deq_cfg_hi; /* QIDQC - QI Dequeue Configuration */ + u32 qi_deq_cfg_lo; + u32 qi_enq_cfg_hi; /* QISEQC - QI Enqueue Command */ + u32 qi_enq_cfg_lo; + u32 rsvd2[1016]; +}; + +/* QI control bits - low word */ +#define QICTL_DQEN 0x01 /* Enable frame pop */ +#define QICTL_STOP 0x02 /* Stop dequeue/enqueue */ +#define QICTL_SOE 0x04 /* Stop on error */ + +/* QI control bits - high word */ +#define QICTL_MBSI 0x01 +#define QICTL_MHWSI 0x02 +#define QICTL_MWSI 0x04 +#define QICTL_MDWSI 0x08 +#define QICTL_CBSI 0x10 /* CtrlDataByteSwapInput */ +#define QICTL_CHWSI 0x20 /* CtrlDataHalfSwapInput */ +#define QICTL_CWSI 0x40 /* CtrlDataWordSwapInput */ +#define QICTL_CDWSI 0x80 /* CtrlDataDWordSwapInput */ +#define QICTL_MBSO 0x0100 +#define QICTL_MHWSO 0x0200 +#define QICTL_MWSO 0x0400 +#define QICTL_MDWSO 0x0800 +#define QICTL_CBSO 0x1000 /* CtrlDataByteSwapOutput */ +#define QICTL_CHWSO 0x2000 /* CtrlDataHalfSwapOutput */ +#define QICTL_CWSO 0x4000 /* CtrlDataWordSwapOutput */ +#define QICTL_CDWSO 0x8000 /* CtrlDataDWordSwapOutput */ +#define QICTL_DMBS 0x010000 +#define QICTL_EPO 0x020000 + +/* QI status bits */ +#define QISTA_PHRDERR 0x01 /* PreHeader Read Error */ +#define QISTA_CFRDERR 0x02 /* Compound Frame Read Error */ +#define QISTA_OFWRERR 0x04 /* Output Frame Read Error */ +#define QISTA_BPDERR 0x08 /* Buffer Pool Depleted */ +#define QISTA_BTSERR 0x10 /* Buffer Undersize */ +#define QISTA_CFWRERR 0x20 /* Compound Frame Write Err */ +#define QISTA_STOPD 0x80000000 /* QI Stopped (see QICTL) */ + +/* deco_sg_table - DECO view of scatter/gather table */ +struct deco_sg_table { + u64 addr; /* Segment Address */ + u32 elen; /* E, F bits + 30-bit length */ + u32 bpid_offset; /* Buffer Pool ID + 16-bit length */ +}; + +/* + * caam_deco - descriptor controller - CHA cluster block + * + * Only accessible when direct DECO access is turned on + * (done in DECORR, via MID programmed in DECOxMID + * + * 5 typical, base + 0x8000/9000/a000/b000 + * Padded out to 0x1000 long + */ +struct caam_deco { + u32 rsvd1; + u32 cls1_mode; /* CxC1MR - Class 1 Mode */ + u32 rsvd2; + u32 cls1_keysize; /* CxC1KSR - Class 1 Key Size */ + u32 cls1_datasize_hi; /* CxC1DSR - Class 1 Data Size */ + u32 cls1_datasize_lo; + u32 rsvd3; + u32 cls1_icvsize; /* CxC1ICVSR - Class 1 ICV size */ + u32 rsvd4[5]; + u32 cha_ctrl; /* CCTLR - CHA control */ + u32 rsvd5; + u32 irq_crtl; /* CxCIRQ - CCB interrupt done/error/clear */ + u32 rsvd6; + u32 clr_written; /* CxCWR - Clear-Written */ + u32 ccb_status_hi; /* CxCSTA - CCB Status/Error */ + u32 ccb_status_lo; + u32 rsvd7[3]; + u32 aad_size; /* CxAADSZR - Current AAD Size */ + u32 rsvd8; + u32 cls1_iv_size; /* CxC1IVSZR - Current Class 1 IV Size */ + u32 rsvd9[7]; + u32 pkha_a_size; /* PKASZRx - Size of PKHA A */ + u32 rsvd10; + u32 pkha_b_size; /* PKBSZRx - Size of PKHA B */ + u32 rsvd11; + u32 pkha_n_size; /* PKNSZRx - Size of PKHA N */ + u32 rsvd12; + u32 pkha_e_size; /* PKESZRx - Size of PKHA E */ + u32 rsvd13[24]; + u32 cls1_ctx[16]; /* CxC1CTXR - Class 1 Context @100 */ + u32 rsvd14[48]; + u32 cls1_key[8]; /* CxC1KEYR - Class 1 Key @200 */ + u32 rsvd15[121]; + u32 cls2_mode; /* CxC2MR - Class 2 Mode */ + u32 rsvd16; + u32 cls2_keysize; /* CxX2KSR - Class 2 Key Size */ + u32 cls2_datasize_hi; /* CxC2DSR - Class 2 Data Size */ + u32 cls2_datasize_lo; + u32 rsvd17; + u32 cls2_icvsize; /* CxC2ICVSZR - Class 2 ICV Size */ + u32 rsvd18[56]; + u32 cls2_ctx[18]; /* CxC2CTXR - Class 2 Context @500 */ + u32 rsvd19[46]; + u32 cls2_key[32]; /* CxC2KEYR - Class2 Key @600 */ + u32 rsvd20[84]; + u32 inp_infofifo_hi; /* CxIFIFO - Input Info FIFO @7d0 */ + u32 inp_infofifo_lo; + u32 rsvd21[2]; + u64 inp_datafifo; /* CxDFIFO - Input Data FIFO */ + u32 rsvd22[2]; + u64 out_datafifo; /* CxOFIFO - Output Data FIFO */ + u32 rsvd23[2]; + u32 jr_ctl_hi; /* CxJRR - JobR Control Register @800 */ + u32 jr_ctl_lo; + u64 jr_descaddr; /* CxDADR - JobR Descriptor Address */ + u32 op_status_hi; /* DxOPSTA - DECO Operation Status */ + u32 op_status_lo; + u32 rsvd24[2]; + u32 liodn; /* DxLSR - DECO LIODN Status - non-seq */ + u32 td_liodn; /* DxLSR - DECO LIODN Status - trustdesc */ + u32 rsvd26[6]; + u64 math[4]; /* DxMTH - Math register */ + u32 rsvd27[8]; + struct deco_sg_table gthr_tbl[4]; /* DxGTR - Gather Tables */ + u32 rsvd28[16]; + struct deco_sg_table sctr_tbl[4]; /* DxSTR - Scatter Tables */ + u32 rsvd29[48]; + u32 descbuf[64]; /* DxDESB - Descriptor buffer */ + u32 rsvd30[320]; +}; + +/* + * Current top-level view of memory map is: + * + * 0x0000 - 0x0fff - CAAM Top-Level Control + * 0x1000 - 0x1fff - Job Ring 0 + * 0x2000 - 0x2fff - Job Ring 1 + * 0x3000 - 0x3fff - Job Ring 2 + * 0x4000 - 0x4fff - Job Ring 3 + * 0x5000 - 0x5fff - (unused) + * 0x6000 - 0x6fff - Assurance Controller + * 0x7000 - 0x7fff - Queue Interface + * 0x8000 - 0x8fff - DECO-CCB 0 + * 0x9000 - 0x9fff - DECO-CCB 1 + * 0xa000 - 0xafff - DECO-CCB 2 + * 0xb000 - 0xbfff - DECO-CCB 3 + * 0xc000 - 0xcfff - DECO-CCB 4 + * + * caam_full describes the full register view of CAAM if useful, + * although many configurations may choose to implement parts of + * the register map separately, in differing privilege regions + */ +struct caam_full { + struct caam_ctrl __iomem ctrl; + struct caam_job_ring jr[4]; + u64 rsvd[512]; + struct caam_assurance assure; + struct caam_queue_if qi; + struct caam_deco *deco; +}; + +#endif /* REGS_H */ -- cgit v0.10.2 From 54e198d4c162b36ba864ecc658c829454074523f Mon Sep 17 00:00:00 2001 From: Kim Phillips Date: Wed, 23 Mar 2011 21:15:44 +0800 Subject: crypto: caam - standardize device tree naming convention to utilize '-vX.Y' Help clarify that the number trailing in compatible nomenclature is the version number of the device, i.e., change: "fsl,p4080-sec4.0", "fsl,sec4.0"; to: "fsl,p4080-sec-v4.0", "fsl,sec-v4.0"; Signed-off-by: Kim Phillips Cc: Kumar Gala Cc: Steve Cornelius Signed-off-by: Herbert Xu diff --git a/Documentation/devicetree/bindings/crypto/fsl-sec4.txt b/Documentation/devicetree/bindings/crypto/fsl-sec4.txt index fce16a8..568aa3c 100644 --- a/Documentation/devicetree/bindings/crypto/fsl-sec4.txt +++ b/Documentation/devicetree/bindings/crypto/fsl-sec4.txt @@ -53,7 +53,7 @@ PROPERTIES - compatible Usage: required Value type: - Definition: Must include "fsl,p4080-sec4.0","fsl,sec-4.0" + Definition: Must include "fsl,p4080-sec-v4.0","fsl,sec-v4.0" - #address-cells Usage: required @@ -72,7 +72,7 @@ PROPERTIES Usage: required Value type: Definition: A standard property. Specifies the physical - address and length of the SEC4.0 configuration registers. + address and length of the SEC4 configuration registers. registers - ranges @@ -105,7 +105,7 @@ PROPERTIES EXAMPLE crypto@300000 { - compatible = "fsl,p4080-sec4.0", "fsl,sec4.0"; + compatible = "fsl,p4080-sec-v4.0", "fsl,sec-v4.0"; #address-cells = <1>; #size-cells = <1>; reg = <0x300000 0x10000>; @@ -127,7 +127,7 @@ P4080 Job Ring (JR) Node - compatible Usage: required Value type: - Definition: Must include "fsl,p4080-sec4.0-job-ring","fsl,sec4.0-job-ring" + Definition: Must include "fsl,p4080-sec-v4.0-job-ring","fsl,sec-v4.0-job-ring" - reg Usage: required @@ -163,8 +163,8 @@ P4080 Job Ring (JR) Node EXAMPLE jr@1000 { - compatible = "fsl,p4080-sec4.0-job-ring", - "fsl,sec4.0-job-ring"; + compatible = "fsl,p4080-sec-v4.0-job-ring", + "fsl,sec-v4.0-job-ring"; reg = <0x1000 0x1000>; fsl,liodn = <0x081>; interrupt-parent = <&mpic>; @@ -186,7 +186,7 @@ P4080 Run Time Integrity Check (RTIC) Node - compatible Usage: required Value type: - Definition: Must include "fsl,p4080-sec4.0-rtic","fsl,sec4.0-rtic". + Definition: Must include "fsl,p4080-sec-v4.0-rtic","fsl,sec-v4.0-rtic". - #address-cells Usage: required @@ -219,8 +219,8 @@ P4080 Run Time Integrity Check (RTIC) Node EXAMPLE rtic@6000 { - compatible = "fsl,p4080-sec4.0-rtic", - "fsl,sec4.0-rtic"; + compatible = "fsl,p4080-sec-v4.0-rtic", + "fsl,sec-v4.0-rtic"; #address-cells = <1>; #size-cells = <1>; reg = <0x6000 0x100>; @@ -238,7 +238,7 @@ P4080 Run Time Integrity Check (RTIC) Memory Node - compatible Usage: required Value type: - Definition: Must include "fsl,p4080-sec4.0-rtic-memory","fsl,sec4.0-rtic-memory". + Definition: Must include "fsl,p4080-sec-v4.0-rtic-memory","fsl,sec-v4.0-rtic-memory". - reg Usage: required @@ -270,8 +270,8 @@ P4080 Run Time Integrity Check (RTIC) Memory Node EXAMPLE rtic-a@0 { - compatible = "fsl,p4080-sec4.0-rtic-memory", - "fsl,sec4.0-rtic-memory"; + compatible = "fsl,p4080-sec-v4.0-rtic-memory", + "fsl,sec-v4.0-rtic-memory"; reg = <0x00 0x20 0x100 0x80>; fsl,liodn = <0x03c>; fsl,rtic-region = <0x12345678 0x12345678 0x12345678>; @@ -288,7 +288,7 @@ P4080 Secure Non-Volatile Storage (SNVS) Node - compatible Usage: required Value type: - Definition: Must include "fsl,p4080-sec4.0-mon", "fsl,sec4.0-mon". + Definition: Must include "fsl,p4080-sec-v4.0-mon", "fsl,sec-v4.0-mon". - reg Usage: required @@ -315,7 +315,7 @@ P4080 Secure Non-Volatile Storage (SNVS) Node EXAMPLE sec_mon@314000 { - compatible = "fsl,p4080-sec4.0-mon", "fsl,sec4.0-mon"; + compatible = "fsl,p4080-sec-v4.0-mon", "fsl,sec-v4.0-mon"; reg = <0x314000 0x1000>; interrupt-parent = <&mpic>; interrupts = <93 2>; @@ -325,7 +325,7 @@ EXAMPLE FULL EXAMPLE crypto: crypto@300000 { - compatible = "fsl,p4080-sec4.0", "fsl,sec4.0"; + compatible = "fsl,p4080-sec-v4.0", "fsl,sec-v4.0"; #address-cells = <1>; #size-cells = <1>; reg = <0x300000 0x10000>; @@ -334,73 +334,73 @@ FULL EXAMPLE interrupts = <92 2>; sec_jr0: jr@1000 { - compatible = "fsl,p4080-sec4.0-job-ring", - "fsl,sec4.0-job-ring"; + compatible = "fsl,p4080-sec-v4.0-job-ring", + "fsl,sec-v4.0-job-ring"; reg = <0x1000 0x1000>; interrupt-parent = <&mpic>; interrupts = <88 2>; }; sec_jr1: jr@2000 { - compatible = "fsl,p4080-sec4.0-job-ring", - "fsl,sec4.0-job-ring"; + compatible = "fsl,p4080-sec-v4.0-job-ring", + "fsl,sec-v4.0-job-ring"; reg = <0x2000 0x1000>; interrupt-parent = <&mpic>; interrupts = <89 2>; }; sec_jr2: jr@3000 { - compatible = "fsl,p4080-sec4.0-job-ring", - "fsl,sec4.0-job-ring"; + compatible = "fsl,p4080-sec-v4.0-job-ring", + "fsl,sec-v4.0-job-ring"; reg = <0x3000 0x1000>; interrupt-parent = <&mpic>; interrupts = <90 2>; }; sec_jr3: jr@4000 { - compatible = "fsl,p4080-sec4.0-job-ring", - "fsl,sec4.0-job-ring"; + compatible = "fsl,p4080-sec-v4.0-job-ring", + "fsl,sec-v4.0-job-ring"; reg = <0x4000 0x1000>; interrupt-parent = <&mpic>; interrupts = <91 2>; }; rtic@6000 { - compatible = "fsl,p4080-sec4.0-rtic", - "fsl,sec4.0-rtic"; + compatible = "fsl,p4080-sec-v4.0-rtic", + "fsl,sec-v4.0-rtic"; #address-cells = <1>; #size-cells = <1>; reg = <0x6000 0x100>; ranges = <0x0 0x6100 0xe00>; rtic_a: rtic-a@0 { - compatible = "fsl,p4080-sec4.0-rtic-memory", - "fsl,sec4.0-rtic-memory"; + compatible = "fsl,p4080-sec-v4.0-rtic-memory", + "fsl,sec-v4.0-rtic-memory"; reg = <0x00 0x20 0x100 0x80>; }; rtic_b: rtic-b@20 { - compatible = "fsl,p4080-sec4.0-rtic-memory", - "fsl,sec4.0-rtic-memory"; + compatible = "fsl,p4080-sec-v4.0-rtic-memory", + "fsl,sec-v4.0-rtic-memory"; reg = <0x20 0x20 0x200 0x80>; }; rtic_c: rtic-c@40 { - compatible = "fsl,p4080-sec4.0-rtic-memory", - "fsl,sec4.0-rtic-memory"; + compatible = "fsl,p4080-sec-v4.0-rtic-memory", + "fsl,sec-v4.0-rtic-memory"; reg = <0x40 0x20 0x300 0x80>; }; rtic_d: rtic-d@60 { - compatible = "fsl,p4080-sec4.0-rtic-memory", - "fsl,sec4.0-rtic-memory"; + compatible = "fsl,p4080-sec-v4.0-rtic-memory", + "fsl,sec-v4.0-rtic-memory"; reg = <0x60 0x20 0x500 0x80>; }; }; }; sec_mon: sec_mon@314000 { - compatible = "fsl,p4080-sec4.0-mon", "fsl,sec4.0-mon"; + compatible = "fsl,p4080-sec-v4.0-mon", "fsl,sec-v4.0-mon"; reg = <0x314000 0x1000>; interrupt-parent = <&mpic>; interrupts = <93 2>; diff --git a/arch/powerpc/boot/dts/p4080ds.dts b/arch/powerpc/boot/dts/p4080ds.dts index c78e801..0430d24 100644 --- a/arch/powerpc/boot/dts/p4080ds.dts +++ b/arch/powerpc/boot/dts/p4080ds.dts @@ -423,7 +423,7 @@ }; crypto: crypto@300000 { - compatible = "fsl,p4080-sec4.0", "fsl,sec4.0"; + compatible = "fsl,p4080-sec-v4.0", "fsl,sec-v4.0"; #address-cells = <1>; #size-cells = <1>; reg = <0x300000 0x10000>; @@ -432,73 +432,74 @@ interrupts = <92 2>; sec_jr0: jr@1000 { - compatible = "fsl,p4080-sec4.0-job-ring", - "fsl,sec4.0-job-ring"; + compatible = "fsl,p4080-sec-v4.0-job-ring", + "fsl,sec-v4.0-job-ring"; reg = <0x1000 0x1000>; interrupt-parent = <&mpic>; interrupts = <88 2>; }; sec_jr1: jr@2000 { - compatible = "fsl,p4080-sec4.0-job-ring", - "fsl,sec4.0-job-ring"; + compatible = "fsl,p4080-sec-v4.0-job-ring", + "fsl,sec-v4.0-job-ring"; reg = <0x2000 0x1000>; interrupt-parent = <&mpic>; interrupts = <89 2>; }; sec_jr2: jr@3000 { - compatible = "fsl,p4080-sec4.0-job-ring", - "fsl,sec4.0-job-ring"; + compatible = "fsl,p4080-sec-v4.0-job-ring", + "fsl,sec-v4.0-job-ring"; reg = <0x3000 0x1000>; interrupt-parent = <&mpic>; interrupts = <90 2>; }; sec_jr3: jr@4000 { - compatible = "fsl,p4080-sec4.0-job-ring", - "fsl,sec4.0-job-ring"; + compatible = "fsl,p4080-sec-v4.0-job-ring", + "fsl,sec-v4.0-job-ring"; reg = <0x4000 0x1000>; interrupt-parent = <&mpic>; interrupts = <91 2>; }; rtic@6000 { - compatible = "fsl,p4080-sec4.0-rtic", - "fsl,sec4.0-rtic"; + compatible = "fsl,p4080-sec-v4.0-rtic", + "fsl,sec-v4.0-rtic"; #address-cells = <1>; #size-cells = <1>; reg = <0x6000 0x100>; ranges = <0x0 0x6100 0xe00>; rtic_a: rtic-a@0 { - compatible = "fsl,p4080-sec4.0-rtic-memory", - "fsl,sec4.0-rtic-memory"; + compatible = "fsl,p4080-sec-v4.0-rtic-memory", + "fsl,sec-v4.0-rtic-memory"; reg = <0x00 0x20 0x100 0x80>; }; rtic_b: rtic-b@20 { - compatible = "fsl,p4080-sec4.0-rtic-memory", - "fsl,sec4.0-rtic-memory"; + compatible = "fsl,p4080-sec-v4.0-rtic-memory", + "fsl,sec-v4.0-rtic-memory"; reg = <0x20 0x20 0x200 0x80>; }; rtic_c: rtic-c@40 { - compatible = "fsl,p4080-sec4.0-rtic-memory", - "fsl,sec4.0-rtic-memory"; + compatible = "fsl,p4080-sec-v4.0-rtic-memory", + "fsl,sec-v4.0-rtic-memory"; reg = <0x40 0x20 0x300 0x80>; }; rtic_d: rtic-d@60 { - compatible = "fsl,p4080-sec4.0-rtic-memory", - "fsl,sec4.0-rtic-memory"; + compatible = "fsl,p4080-sec-v4.0-rtic-memory", + "fsl,sec-v4.0-rtic-memory"; reg = <0x60 0x20 0x500 0x80>; }; }; }; sec_mon: sec_mon@314000 { - compatible = "fsl,p4080-sec4.0-mon", "fsl,sec4.0-mon"; + compatible = "fsl,p4080-sec-v4.0-mon", + "fsl,sec-v4.0-mon"; reg = <0x314000 0x1000>; interrupt-parent = <&mpic>; interrupts = <93 2>; diff --git a/drivers/crypto/caam/caamalg.c b/drivers/crypto/caam/caamalg.c index d7fe3d3..1403434 100644 --- a/drivers/crypto/caam/caamalg.c +++ b/drivers/crypto/caam/caamalg.c @@ -1020,7 +1020,7 @@ static void __exit caam_algapi_exit(void) struct caam_crypto_alg *t_alg, *n; int i, err; - dev_node = of_find_compatible_node(NULL, NULL, "fsl,sec4.0"); + dev_node = of_find_compatible_node(NULL, NULL, "fsl,sec-v4.0"); if (!dev_node) return; @@ -1094,7 +1094,7 @@ static int __init caam_algapi_init(void) struct caam_drv_private *priv; int i = 0, err = 0; - dev_node = of_find_compatible_node(NULL, NULL, "fsl,sec4.0"); + dev_node = of_find_compatible_node(NULL, NULL, "fsl,sec-v4.0"); if (!dev_node) return -ENODEV; diff --git a/drivers/crypto/caam/ctrl.c b/drivers/crypto/caam/ctrl.c index aa221616..59aae4e 100644 --- a/drivers/crypto/caam/ctrl.c +++ b/drivers/crypto/caam/ctrl.c @@ -108,7 +108,7 @@ static int caam_probe(struct platform_device *pdev, * for all, then go probe each one. */ rspec = 0; - for_each_compatible_node(np, NULL, "fsl,sec4.0-job-ring") + for_each_compatible_node(np, NULL, "fsl,sec-v4.0-job-ring") rspec++; ctrlpriv->jrdev = kzalloc(sizeof(struct device *) * rspec, GFP_KERNEL); if (ctrlpriv->jrdev == NULL) { @@ -118,7 +118,7 @@ static int caam_probe(struct platform_device *pdev, ring = 0; ctrlpriv->total_jobrs = 0; - for_each_compatible_node(np, NULL, "fsl,sec4.0-job-ring") { + for_each_compatible_node(np, NULL, "fsl,sec-v4.0-job-ring") { caam_jr_probe(pdev, np, ring); ctrlpriv->total_jobrs++; ring++; @@ -236,7 +236,7 @@ static int caam_probe(struct platform_device *pdev, static struct of_device_id caam_match[] = { { - .compatible = "fsl,sec4.0", + .compatible = "fsl,sec-v4.0", }, {}, }; -- cgit v0.10.2 From cdc712d884cec0354d6899e7a329eee542ca2f7d Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Wed, 23 Mar 2011 21:20:27 +0800 Subject: crypto: caam - dereferencing ERR_PTR on allocation failure t_alg is an ERR_PTR here so we can't dereference it. Signed-off-by: Dan Carpenter Acked-by: Kim Phillips Signed-off-by: Herbert Xu diff --git a/drivers/crypto/caam/caamalg.c b/drivers/crypto/caam/caamalg.c index 1403434..dce44b2 100644 --- a/drivers/crypto/caam/caamalg.c +++ b/drivers/crypto/caam/caamalg.c @@ -1136,7 +1136,7 @@ static int __init caam_algapi_init(void) if (IS_ERR(t_alg)) { err = PTR_ERR(t_alg); dev_warn(ctrldev, "%s alg allocation failed\n", - t_alg->crypto_alg.cra_driver_name); + driver_algs[i].driver_name); continue; } -- cgit v0.10.2 From 6d00376ad15a931d4b148e52d80abc54173e9bf5 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Wed, 23 Mar 2011 21:21:53 +0800 Subject: crypto: caam - ARRAY_SIZE() vs sizeof() ARRAY_SIZE() was intended here instead of sizeof(). sizeof() is four times larger than ARRAY_SIZE(). outstr is normally 256 chars so printing garbage to it could overfill the buffer and corrupt memory. Signed-off-by: Dan Carpenter Acked-by: Kim Phillips Signed-off-by: Herbert Xu diff --git a/drivers/crypto/caam/error.c b/drivers/crypto/caam/error.c index bd57a68..7e2d54b 100644 --- a/drivers/crypto/caam/error.c +++ b/drivers/crypto/caam/error.c @@ -73,7 +73,7 @@ static void report_ccb_status(u32 status, char *outstr) report_jump_idx(status, outstr); - if (cha_id < sizeof(cha_id_list)) { + if (cha_id < ARRAY_SIZE(cha_id_list)) { SPRINTFCAT(outstr, "%s: ", cha_id_list[cha_id], strlen(cha_id_list[cha_id])); } else { @@ -81,7 +81,7 @@ static void report_ccb_status(u32 status, char *outstr) cha_id, sizeof("ff")); } - if (err_id < sizeof(err_id_list)) { + if (err_id < ARRAY_SIZE(err_id_list)) { SPRINTFCAT(outstr, "%s", err_id_list[err_id], strlen(err_id_list[err_id])); } else { @@ -198,11 +198,11 @@ static void report_deco_status(u32 status, char *outstr) report_jump_idx(status, outstr); - for (i = 0; i < sizeof(desc_error_list); i++) + for (i = 0; i < ARRAY_SIZE(desc_error_list); i++) if (desc_error_list[i].value == desc_error) break; - if (i != sizeof(desc_error_list) && desc_error_list[i].error_text) { + if (i != ARRAY_SIZE(desc_error_list) && desc_error_list[i].error_text) { SPRINTFCAT(outstr, "%s", desc_error_list[i].error_text, strlen(desc_error_list[i].error_text)); } else { -- cgit v0.10.2 From 7dfc2179ec7339a180e822a5af7eb1294da245cf Mon Sep 17 00:00:00 2001 From: Kim Phillips Date: Wed, 23 Mar 2011 21:23:36 +0800 Subject: crypto: caam - de-CHIP-ify device tree compatibles - all the integration parameters have been captured by the binding. - the block name really uniquely identifies this hardware. Some advocate putting SoC names everywhere in case software needs to work around some chip-specific bug, but more precise SoC information already exists in SVR, and board information already exists in the top-level device tree node. Note that sometimes the SoC name is a worse identifier than the block version, as the block version can change between revisions of the same SoC. As a matter of historical reference, neither SEC versions 2.x nor 3.x (driven by talitos) ever needed CHIP references. Signed-off-by: Kim Phillips Cc: Kumar Gala Cc: Scott Wood Acked-off-by: Grant Likely Signed-off-by: Herbert Xu diff --git a/Documentation/devicetree/bindings/crypto/fsl-sec4.txt b/Documentation/devicetree/bindings/crypto/fsl-sec4.txt index 568aa3c..bf57ecd 100644 --- a/Documentation/devicetree/bindings/crypto/fsl-sec4.txt +++ b/Documentation/devicetree/bindings/crypto/fsl-sec4.txt @@ -38,7 +38,7 @@ in the memory partition devoted to a particular core. The P4080 has 4 JRs, so up to 4 JRs can be configured; and all 4 JRs process requests in parallel. ===================================================================== -P4080 SEC 4 Node +SEC 4 Node Description @@ -53,7 +53,7 @@ PROPERTIES - compatible Usage: required Value type: - Definition: Must include "fsl,p4080-sec-v4.0","fsl,sec-v4.0" + Definition: Must include "fsl,sec-v4.0" - #address-cells Usage: required @@ -105,7 +105,7 @@ PROPERTIES EXAMPLE crypto@300000 { - compatible = "fsl,p4080-sec-v4.0", "fsl,sec-v4.0"; + compatible = "fsl,sec-v4.0"; #address-cells = <1>; #size-cells = <1>; reg = <0x300000 0x10000>; @@ -115,7 +115,7 @@ EXAMPLE }; ===================================================================== -P4080 Job Ring (JR) Node +Job Ring (JR) Node Child of the crypto node defines data processing interface to SEC 4 across the peripheral bus for purposes of processing @@ -127,7 +127,7 @@ P4080 Job Ring (JR) Node - compatible Usage: required Value type: - Definition: Must include "fsl,p4080-sec-v4.0-job-ring","fsl,sec-v4.0-job-ring" + Definition: Must include "fsl,sec-v4.0-job-ring" - reg Usage: required @@ -163,8 +163,7 @@ P4080 Job Ring (JR) Node EXAMPLE jr@1000 { - compatible = "fsl,p4080-sec-v4.0-job-ring", - "fsl,sec-v4.0-job-ring"; + compatible = "fsl,sec-v4.0-job-ring"; reg = <0x1000 0x1000>; fsl,liodn = <0x081>; interrupt-parent = <&mpic>; @@ -173,7 +172,7 @@ EXAMPLE ===================================================================== -P4080 Run Time Integrity Check (RTIC) Node +Run Time Integrity Check (RTIC) Node Child node of the crypto node. Defines a register space that contains up to 5 sets of addresses and their lengths (sizes) that @@ -186,7 +185,7 @@ P4080 Run Time Integrity Check (RTIC) Node - compatible Usage: required Value type: - Definition: Must include "fsl,p4080-sec-v4.0-rtic","fsl,sec-v4.0-rtic". + Definition: Must include "fsl,sec-v4.0-rtic". - #address-cells Usage: required @@ -219,8 +218,7 @@ P4080 Run Time Integrity Check (RTIC) Node EXAMPLE rtic@6000 { - compatible = "fsl,p4080-sec-v4.0-rtic", - "fsl,sec-v4.0-rtic"; + compatible = "fsl,sec-v4.0-rtic"; #address-cells = <1>; #size-cells = <1>; reg = <0x6000 0x100>; @@ -228,7 +226,7 @@ EXAMPLE }; ===================================================================== -P4080 Run Time Integrity Check (RTIC) Memory Node +Run Time Integrity Check (RTIC) Memory Node A child node that defines individual RTIC memory regions that are used to perform run-time integrity check of memory areas that should not modified. The node defines a register that contains the memory address & @@ -238,7 +236,7 @@ P4080 Run Time Integrity Check (RTIC) Memory Node - compatible Usage: required Value type: - Definition: Must include "fsl,p4080-sec-v4.0-rtic-memory","fsl,sec-v4.0-rtic-memory". + Definition: Must include "fsl,sec-v4.0-rtic-memory". - reg Usage: required @@ -270,15 +268,14 @@ P4080 Run Time Integrity Check (RTIC) Memory Node EXAMPLE rtic-a@0 { - compatible = "fsl,p4080-sec-v4.0-rtic-memory", - "fsl,sec-v4.0-rtic-memory"; + compatible = "fsl,sec-v4.0-rtic-memory"; reg = <0x00 0x20 0x100 0x80>; fsl,liodn = <0x03c>; fsl,rtic-region = <0x12345678 0x12345678 0x12345678>; }; ===================================================================== -P4080 Secure Non-Volatile Storage (SNVS) Node +Secure Non-Volatile Storage (SNVS) Node Node defines address range and the associated interrupt for the SNVS function. This function @@ -288,7 +285,7 @@ P4080 Secure Non-Volatile Storage (SNVS) Node - compatible Usage: required Value type: - Definition: Must include "fsl,p4080-sec-v4.0-mon", "fsl,sec-v4.0-mon". + Definition: Must include "fsl,sec-v4.0-mon". - reg Usage: required @@ -315,7 +312,7 @@ P4080 Secure Non-Volatile Storage (SNVS) Node EXAMPLE sec_mon@314000 { - compatible = "fsl,p4080-sec-v4.0-mon", "fsl,sec-v4.0-mon"; + compatible = "fsl,sec-v4.0-mon"; reg = <0x314000 0x1000>; interrupt-parent = <&mpic>; interrupts = <93 2>; @@ -325,7 +322,7 @@ EXAMPLE FULL EXAMPLE crypto: crypto@300000 { - compatible = "fsl,p4080-sec-v4.0", "fsl,sec-v4.0"; + compatible = "fsl,sec-v4.0"; #address-cells = <1>; #size-cells = <1>; reg = <0x300000 0x10000>; @@ -334,73 +331,64 @@ FULL EXAMPLE interrupts = <92 2>; sec_jr0: jr@1000 { - compatible = "fsl,p4080-sec-v4.0-job-ring", - "fsl,sec-v4.0-job-ring"; + compatible = "fsl,sec-v4.0-job-ring"; reg = <0x1000 0x1000>; interrupt-parent = <&mpic>; interrupts = <88 2>; }; sec_jr1: jr@2000 { - compatible = "fsl,p4080-sec-v4.0-job-ring", - "fsl,sec-v4.0-job-ring"; + compatible = "fsl,sec-v4.0-job-ring"; reg = <0x2000 0x1000>; interrupt-parent = <&mpic>; interrupts = <89 2>; }; sec_jr2: jr@3000 { - compatible = "fsl,p4080-sec-v4.0-job-ring", - "fsl,sec-v4.0-job-ring"; + compatible = "fsl,sec-v4.0-job-ring"; reg = <0x3000 0x1000>; interrupt-parent = <&mpic>; interrupts = <90 2>; }; sec_jr3: jr@4000 { - compatible = "fsl,p4080-sec-v4.0-job-ring", - "fsl,sec-v4.0-job-ring"; + compatible = "fsl,sec-v4.0-job-ring"; reg = <0x4000 0x1000>; interrupt-parent = <&mpic>; interrupts = <91 2>; }; rtic@6000 { - compatible = "fsl,p4080-sec-v4.0-rtic", - "fsl,sec-v4.0-rtic"; + compatible = "fsl,sec-v4.0-rtic"; #address-cells = <1>; #size-cells = <1>; reg = <0x6000 0x100>; ranges = <0x0 0x6100 0xe00>; rtic_a: rtic-a@0 { - compatible = "fsl,p4080-sec-v4.0-rtic-memory", - "fsl,sec-v4.0-rtic-memory"; + compatible = "fsl,sec-v4.0-rtic-memory"; reg = <0x00 0x20 0x100 0x80>; }; rtic_b: rtic-b@20 { - compatible = "fsl,p4080-sec-v4.0-rtic-memory", - "fsl,sec-v4.0-rtic-memory"; + compatible = "fsl,sec-v4.0-rtic-memory"; reg = <0x20 0x20 0x200 0x80>; }; rtic_c: rtic-c@40 { - compatible = "fsl,p4080-sec-v4.0-rtic-memory", - "fsl,sec-v4.0-rtic-memory"; + compatible = "fsl,sec-v4.0-rtic-memory"; reg = <0x40 0x20 0x300 0x80>; }; rtic_d: rtic-d@60 { - compatible = "fsl,p4080-sec-v4.0-rtic-memory", - "fsl,sec-v4.0-rtic-memory"; + compatible = "fsl,sec-v4.0-rtic-memory"; reg = <0x60 0x20 0x500 0x80>; }; }; }; sec_mon: sec_mon@314000 { - compatible = "fsl,p4080-sec-v4.0-mon", "fsl,sec-v4.0-mon"; + compatible = "fsl,sec-v4.0-mon"; reg = <0x314000 0x1000>; interrupt-parent = <&mpic>; interrupts = <93 2>; diff --git a/arch/powerpc/boot/dts/p4080ds.dts b/arch/powerpc/boot/dts/p4080ds.dts index 0430d24..927f94d 100644 --- a/arch/powerpc/boot/dts/p4080ds.dts +++ b/arch/powerpc/boot/dts/p4080ds.dts @@ -423,7 +423,7 @@ }; crypto: crypto@300000 { - compatible = "fsl,p4080-sec-v4.0", "fsl,sec-v4.0"; + compatible = "fsl,sec-v4.0"; #address-cells = <1>; #size-cells = <1>; reg = <0x300000 0x10000>; @@ -432,74 +432,64 @@ interrupts = <92 2>; sec_jr0: jr@1000 { - compatible = "fsl,p4080-sec-v4.0-job-ring", - "fsl,sec-v4.0-job-ring"; + compatible = "fsl,sec-v4.0-job-ring"; reg = <0x1000 0x1000>; interrupt-parent = <&mpic>; interrupts = <88 2>; }; sec_jr1: jr@2000 { - compatible = "fsl,p4080-sec-v4.0-job-ring", - "fsl,sec-v4.0-job-ring"; + compatible = "fsl,sec-v4.0-job-ring"; reg = <0x2000 0x1000>; interrupt-parent = <&mpic>; interrupts = <89 2>; }; sec_jr2: jr@3000 { - compatible = "fsl,p4080-sec-v4.0-job-ring", - "fsl,sec-v4.0-job-ring"; + compatible = "fsl,sec-v4.0-job-ring"; reg = <0x3000 0x1000>; interrupt-parent = <&mpic>; interrupts = <90 2>; }; sec_jr3: jr@4000 { - compatible = "fsl,p4080-sec-v4.0-job-ring", - "fsl,sec-v4.0-job-ring"; + compatible = "fsl,sec-v4.0-job-ring"; reg = <0x4000 0x1000>; interrupt-parent = <&mpic>; interrupts = <91 2>; }; rtic@6000 { - compatible = "fsl,p4080-sec-v4.0-rtic", - "fsl,sec-v4.0-rtic"; + compatible = "fsl,sec-v4.0-rtic"; #address-cells = <1>; #size-cells = <1>; reg = <0x6000 0x100>; ranges = <0x0 0x6100 0xe00>; rtic_a: rtic-a@0 { - compatible = "fsl,p4080-sec-v4.0-rtic-memory", - "fsl,sec-v4.0-rtic-memory"; + compatible = "fsl,sec-v4.0-rtic-memory"; reg = <0x00 0x20 0x100 0x80>; }; rtic_b: rtic-b@20 { - compatible = "fsl,p4080-sec-v4.0-rtic-memory", - "fsl,sec-v4.0-rtic-memory"; + compatible = "fsl,sec-v4.0-rtic-memory"; reg = <0x20 0x20 0x200 0x80>; }; rtic_c: rtic-c@40 { - compatible = "fsl,p4080-sec-v4.0-rtic-memory", - "fsl,sec-v4.0-rtic-memory"; + compatible = "fsl,sec-v4.0-rtic-memory"; reg = <0x40 0x20 0x300 0x80>; }; rtic_d: rtic-d@60 { - compatible = "fsl,p4080-sec-v4.0-rtic-memory", - "fsl,sec-v4.0-rtic-memory"; + compatible = "fsl,sec-v4.0-rtic-memory"; reg = <0x60 0x20 0x500 0x80>; }; }; }; sec_mon: sec_mon@314000 { - compatible = "fsl,p4080-sec-v4.0-mon", - "fsl,sec-v4.0-mon"; + compatible = "fsl,sec-v4.0-mon"; reg = <0x314000 0x1000>; interrupt-parent = <&mpic>; interrupts = <93 2>; -- cgit v0.10.2 From 0475add3c27a43a6599fe6338f8fffe919a13547 Mon Sep 17 00:00:00 2001 From: Brilly Wu Date: Sun, 27 Mar 2011 10:45:00 +0800 Subject: crypto: padlock - Add SHA-1/256 module for VIA Nano Add new SHA-1/256 module that never needs any fallback and just calls the PadLock hardware instruction supported from VIA Nano processors to implement the "update" and "final" function. They are respectively named "sha1_alg_nano" and "sha256_alg_nano", and will be used on any VIA Nano processor or the later ones. On VIA C7 CPU, the "sha1_alg" and "sha256_alg" modules will still be used as before. Signed-off-by: Brilly Wu Signed-off-by: Kary Jin Signed-off-by: Herbert Xu diff --git a/drivers/crypto/padlock-sha.c b/drivers/crypto/padlock-sha.c index adf075b..06bdb4b 100644 --- a/drivers/crypto/padlock-sha.c +++ b/drivers/crypto/padlock-sha.c @@ -288,9 +288,250 @@ static struct shash_alg sha256_alg = { } }; +/* Add two shash_alg instance for hardware-implemented * +* multiple-parts hash supported by VIA Nano Processor.*/ +static int padlock_sha1_init_nano(struct shash_desc *desc) +{ + struct sha1_state *sctx = shash_desc_ctx(desc); + + *sctx = (struct sha1_state){ + .state = { SHA1_H0, SHA1_H1, SHA1_H2, SHA1_H3, SHA1_H4 }, + }; + + return 0; +} + +static int padlock_sha1_update_nano(struct shash_desc *desc, + const u8 *data, unsigned int len) +{ + struct sha1_state *sctx = shash_desc_ctx(desc); + unsigned int partial, done; + const u8 *src; + /*The PHE require the out buffer must 128 bytes and 16-bytes aligned*/ + u8 buf[128 + PADLOCK_ALIGNMENT - STACK_ALIGN] __attribute__ + ((aligned(STACK_ALIGN))); + u8 *dst = PTR_ALIGN(&buf[0], PADLOCK_ALIGNMENT); + int ts_state; + + partial = sctx->count & 0x3f; + sctx->count += len; + done = 0; + src = data; + memcpy(dst, (u8 *)(sctx->state), SHA1_DIGEST_SIZE); + + if ((partial + len) >= SHA1_BLOCK_SIZE) { + + /* Append the bytes in state's buffer to a block to handle */ + if (partial) { + done = -partial; + memcpy(sctx->buffer + partial, data, + done + SHA1_BLOCK_SIZE); + src = sctx->buffer; + ts_state = irq_ts_save(); + asm volatile (".byte 0xf3,0x0f,0xa6,0xc8" + : "+S"(src), "+D"(dst) \ + : "a"((long)-1), "c"((unsigned long)1)); + irq_ts_restore(ts_state); + done += SHA1_BLOCK_SIZE; + src = data + done; + } + + /* Process the left bytes from the input data */ + if (len - done >= SHA1_BLOCK_SIZE) { + ts_state = irq_ts_save(); + asm volatile (".byte 0xf3,0x0f,0xa6,0xc8" + : "+S"(src), "+D"(dst) + : "a"((long)-1), + "c"((unsigned long)((len - done) / SHA1_BLOCK_SIZE))); + irq_ts_restore(ts_state); + done += ((len - done) - (len - done) % SHA1_BLOCK_SIZE); + src = data + done; + } + partial = 0; + } + memcpy((u8 *)(sctx->state), dst, SHA1_DIGEST_SIZE); + memcpy(sctx->buffer + partial, src, len - done); + + return 0; +} + +static int padlock_sha1_final_nano(struct shash_desc *desc, u8 *out) +{ + struct sha1_state *state = (struct sha1_state *)shash_desc_ctx(desc); + unsigned int partial, padlen; + __be64 bits; + static const u8 padding[64] = { 0x80, }; + + bits = cpu_to_be64(state->count << 3); + + /* Pad out to 56 mod 64 */ + partial = state->count & 0x3f; + padlen = (partial < 56) ? (56 - partial) : ((64+56) - partial); + padlock_sha1_update_nano(desc, padding, padlen); + + /* Append length field bytes */ + padlock_sha1_update_nano(desc, (const u8 *)&bits, sizeof(bits)); + + /* Swap to output */ + padlock_output_block((uint32_t *)(state->state), (uint32_t *)out, 5); + + return 0; +} + +static int padlock_sha256_init_nano(struct shash_desc *desc) +{ + struct sha256_state *sctx = shash_desc_ctx(desc); + + *sctx = (struct sha256_state){ + .state = { SHA256_H0, SHA256_H1, SHA256_H2, SHA256_H3, \ + SHA256_H4, SHA256_H5, SHA256_H6, SHA256_H7}, + }; + + return 0; +} + +static int padlock_sha256_update_nano(struct shash_desc *desc, const u8 *data, + unsigned int len) +{ + struct sha256_state *sctx = shash_desc_ctx(desc); + unsigned int partial, done; + const u8 *src; + /*The PHE require the out buffer must 128 bytes and 16-bytes aligned*/ + u8 buf[128 + PADLOCK_ALIGNMENT - STACK_ALIGN] __attribute__ + ((aligned(STACK_ALIGN))); + u8 *dst = PTR_ALIGN(&buf[0], PADLOCK_ALIGNMENT); + int ts_state; + + partial = sctx->count & 0x3f; + sctx->count += len; + done = 0; + src = data; + memcpy(dst, (u8 *)(sctx->state), SHA256_DIGEST_SIZE); + + if ((partial + len) >= SHA256_BLOCK_SIZE) { + + /* Append the bytes in state's buffer to a block to handle */ + if (partial) { + done = -partial; + memcpy(sctx->buf + partial, data, + done + SHA256_BLOCK_SIZE); + src = sctx->buf; + ts_state = irq_ts_save(); + asm volatile (".byte 0xf3,0x0f,0xa6,0xd0" + : "+S"(src), "+D"(dst) + : "a"((long)-1), "c"((unsigned long)1)); + irq_ts_restore(ts_state); + done += SHA256_BLOCK_SIZE; + src = data + done; + } + + /* Process the left bytes from input data*/ + if (len - done >= SHA256_BLOCK_SIZE) { + ts_state = irq_ts_save(); + asm volatile (".byte 0xf3,0x0f,0xa6,0xd0" + : "+S"(src), "+D"(dst) + : "a"((long)-1), + "c"((unsigned long)((len - done) / 64))); + irq_ts_restore(ts_state); + done += ((len - done) - (len - done) % 64); + src = data + done; + } + partial = 0; + } + memcpy((u8 *)(sctx->state), dst, SHA256_DIGEST_SIZE); + memcpy(sctx->buf + partial, src, len - done); + + return 0; +} + +static int padlock_sha256_final_nano(struct shash_desc *desc, u8 *out) +{ + struct sha256_state *state = + (struct sha256_state *)shash_desc_ctx(desc); + unsigned int partial, padlen; + __be64 bits; + static const u8 padding[64] = { 0x80, }; + + bits = cpu_to_be64(state->count << 3); + + /* Pad out to 56 mod 64 */ + partial = state->count & 0x3f; + padlen = (partial < 56) ? (56 - partial) : ((64+56) - partial); + padlock_sha256_update_nano(desc, padding, padlen); + + /* Append length field bytes */ + padlock_sha256_update_nano(desc, (const u8 *)&bits, sizeof(bits)); + + /* Swap to output */ + padlock_output_block((uint32_t *)(state->state), (uint32_t *)out, 8); + + return 0; +} + +static int padlock_sha_export_nano(struct shash_desc *desc, + void *out) +{ + int statesize = crypto_shash_statesize(desc->tfm); + void *sctx = shash_desc_ctx(desc); + + memcpy(out, sctx, statesize); + return 0; +} + +static int padlock_sha_import_nano(struct shash_desc *desc, + const void *in) +{ + int statesize = crypto_shash_statesize(desc->tfm); + void *sctx = shash_desc_ctx(desc); + + memcpy(sctx, in, statesize); + return 0; +} + +static struct shash_alg sha1_alg_nano = { + .digestsize = SHA1_DIGEST_SIZE, + .init = padlock_sha1_init_nano, + .update = padlock_sha1_update_nano, + .final = padlock_sha1_final_nano, + .export = padlock_sha_export_nano, + .import = padlock_sha_import_nano, + .descsize = sizeof(struct sha1_state), + .statesize = sizeof(struct sha1_state), + .base = { + .cra_name = "sha1", + .cra_driver_name = "sha1-padlock-nano", + .cra_priority = PADLOCK_CRA_PRIORITY, + .cra_flags = CRYPTO_ALG_TYPE_SHASH, + .cra_blocksize = SHA1_BLOCK_SIZE, + .cra_module = THIS_MODULE, + } +}; + +static struct shash_alg sha256_alg_nano = { + .digestsize = SHA256_DIGEST_SIZE, + .init = padlock_sha256_init_nano, + .update = padlock_sha256_update_nano, + .final = padlock_sha256_final_nano, + .export = padlock_sha_export_nano, + .import = padlock_sha_import_nano, + .descsize = sizeof(struct sha256_state), + .statesize = sizeof(struct sha256_state), + .base = { + .cra_name = "sha256", + .cra_driver_name = "sha256-padlock-nano", + .cra_priority = PADLOCK_CRA_PRIORITY, + .cra_flags = CRYPTO_ALG_TYPE_SHASH, + .cra_blocksize = SHA256_BLOCK_SIZE, + .cra_module = THIS_MODULE, + } +}; + static int __init padlock_init(void) { int rc = -ENODEV; + struct cpuinfo_x86 *c = &cpu_data(0); + struct shash_alg *sha1; + struct shash_alg *sha256; if (!cpu_has_phe) { printk(KERN_NOTICE PFX "VIA PadLock Hash Engine not detected.\n"); @@ -302,11 +543,21 @@ static int __init padlock_init(void) return -ENODEV; } - rc = crypto_register_shash(&sha1_alg); + /* Register the newly added algorithm module if on * + * VIA Nano processor, or else just do as before */ + if (c->x86_model < 0x0f) { + sha1 = &sha1_alg; + sha256 = &sha256_alg; + } else { + sha1 = &sha1_alg_nano; + sha256 = &sha256_alg_nano; + } + + rc = crypto_register_shash(sha1); if (rc) goto out; - rc = crypto_register_shash(&sha256_alg); + rc = crypto_register_shash(sha256); if (rc) goto out_unreg1; @@ -315,7 +566,8 @@ static int __init padlock_init(void) return 0; out_unreg1: - crypto_unregister_shash(&sha1_alg); + crypto_unregister_shash(sha1); + out: printk(KERN_ERR PFX "VIA PadLock SHA1/SHA256 initialization failed.\n"); return rc; @@ -323,8 +575,15 @@ out: static void __exit padlock_fini(void) { - crypto_unregister_shash(&sha1_alg); - crypto_unregister_shash(&sha256_alg); + struct cpuinfo_x86 *c = &cpu_data(0); + + if (c->x86_model >= 0x0f) { + crypto_unregister_shash(&sha1_alg_nano); + crypto_unregister_shash(&sha256_alg_nano); + } else { + crypto_unregister_shash(&sha1_alg); + crypto_unregister_shash(&sha256_alg); + } } module_init(padlock_init); -- cgit v0.10.2 From 40bfc14f3250691dca6fcb00f791727e180a7f79 Mon Sep 17 00:00:00 2001 From: Jamie Iles Date: Sun, 27 Mar 2011 10:48:29 +0800 Subject: crypto: picoxcell - fix possible status FIFO overflow The SPAcc's have 2 equally sized FIFO's - a command FIFO and a status FIFO. The command FIFO takes the requests that are to be performed and the status FIFO reports the results. It is possible to get into the situation where there are more free spaces in the command FIFO than the status FIFO if we don't empty the status FIFO quickly enough resulting in a possible overflow of the status FIFO. This can result in incorrect status being reported in the status FIFO. Make sure that when we are submitting requests the number of requests that have been dispatched but not yet popped from the status FIFO does not exceed the size of a single FIFO. Signed-off-by: Jamie Iles Signed-off-by: Herbert Xu diff --git a/drivers/crypto/picoxcell_crypto.c b/drivers/crypto/picoxcell_crypto.c index b092d0a..230b5b8 100644 --- a/drivers/crypto/picoxcell_crypto.c +++ b/drivers/crypto/picoxcell_crypto.c @@ -176,6 +176,8 @@ struct spacc_aead_ctx { u8 salt[AES_BLOCK_SIZE]; }; +static int spacc_ablk_submit(struct spacc_req *req); + static inline struct spacc_alg *to_spacc_alg(struct crypto_alg *alg) { return alg ? container_of(alg, struct spacc_alg, alg) : NULL; @@ -666,6 +668,24 @@ static int spacc_aead_submit(struct spacc_req *req) return -EINPROGRESS; } +static int spacc_req_submit(struct spacc_req *req); + +static void spacc_push(struct spacc_engine *engine) +{ + struct spacc_req *req; + + while (!list_empty(&engine->pending) && + engine->in_flight + 1 <= engine->fifo_sz) { + + ++engine->in_flight; + req = list_first_entry(&engine->pending, struct spacc_req, + list); + list_move_tail(&req->list, &engine->in_progress); + + req->result = spacc_req_submit(req); + } +} + /* * Setup an AEAD request for processing. This will configure the engine, load * the context and then start the packet processing. @@ -698,7 +718,8 @@ static int spacc_aead_setup(struct aead_request *req, u8 *giv, err = -EINPROGRESS; spin_lock_irqsave(&engine->hw_lock, flags); - if (unlikely(spacc_fifo_cmd_full(engine))) { + if (unlikely(spacc_fifo_cmd_full(engine)) || + engine->in_flight + 1 > engine->fifo_sz) { if (!(req->base.flags & CRYPTO_TFM_REQ_MAY_BACKLOG)) { err = -EBUSY; spin_unlock_irqrestore(&engine->hw_lock, flags); @@ -706,9 +727,8 @@ static int spacc_aead_setup(struct aead_request *req, u8 *giv, } list_add_tail(&dev_req->list, &engine->pending); } else { - ++engine->in_flight; - list_add_tail(&dev_req->list, &engine->in_progress); - spacc_aead_submit(dev_req); + list_add_tail(&dev_req->list, &engine->pending); + spacc_push(engine); } spin_unlock_irqrestore(&engine->hw_lock, flags); @@ -1041,7 +1061,8 @@ static int spacc_ablk_setup(struct ablkcipher_request *req, unsigned alg_type, * we either stick it on the end of a pending list if we can backlog, * or bailout with an error if not. */ - if (unlikely(spacc_fifo_cmd_full(engine))) { + if (unlikely(spacc_fifo_cmd_full(engine)) || + engine->in_flight + 1 > engine->fifo_sz) { if (!(req->base.flags & CRYPTO_TFM_REQ_MAY_BACKLOG)) { err = -EBUSY; spin_unlock_irqrestore(&engine->hw_lock, flags); @@ -1049,9 +1070,8 @@ static int spacc_ablk_setup(struct ablkcipher_request *req, unsigned alg_type, } list_add_tail(&dev_req->list, &engine->pending); } else { - ++engine->in_flight; - list_add_tail(&dev_req->list, &engine->in_progress); - spacc_ablk_submit(dev_req); + list_add_tail(&dev_req->list, &engine->pending); + spacc_push(engine); } spin_unlock_irqrestore(&engine->hw_lock, flags); @@ -1139,6 +1159,7 @@ static void spacc_process_done(struct spacc_engine *engine) req = list_first_entry(&engine->in_progress, struct spacc_req, list); list_move_tail(&req->list, &engine->completed); + --engine->in_flight; /* POP the status register. */ writel(~0, engine->regs + SPA_STAT_POP_REG_OFFSET); @@ -1208,36 +1229,21 @@ static void spacc_spacc_complete(unsigned long data) struct spacc_engine *engine = (struct spacc_engine *)data; struct spacc_req *req, *tmp; unsigned long flags; - int num_removed = 0; LIST_HEAD(completed); spin_lock_irqsave(&engine->hw_lock, flags); + list_splice_init(&engine->completed, &completed); + spacc_push(engine); + if (engine->in_flight) + mod_timer(&engine->packet_timeout, jiffies + PACKET_TIMEOUT); + spin_unlock_irqrestore(&engine->hw_lock, flags); list_for_each_entry_safe(req, tmp, &completed, list) { - ++num_removed; req->complete(req); + list_del(&req->list); } - - /* Try and fill the engine back up again. */ - spin_lock_irqsave(&engine->hw_lock, flags); - - engine->in_flight -= num_removed; - - list_for_each_entry_safe(req, tmp, &engine->pending, list) { - if (spacc_fifo_cmd_full(engine)) - break; - - list_move_tail(&req->list, &engine->in_progress); - ++engine->in_flight; - req->result = spacc_req_submit(req); - } - - if (engine->in_flight) - mod_timer(&engine->packet_timeout, jiffies + PACKET_TIMEOUT); - - spin_unlock_irqrestore(&engine->hw_lock, flags); } #ifdef CONFIG_PM -- cgit v0.10.2 From 7f980a06e4a9e3bb26db91da8f0e980b0786023a Mon Sep 17 00:00:00 2001 From: Florian Tobias Schandinat Date: Sun, 27 Mar 2011 02:54:32 +0000 Subject: viafb: some small cleanup for global variables We do not need viafb_second{,_virtual}_{xres,yres} outside of viafbdev.c so move them there and eliminate the virtual ones where the only sane usage is done during initalization. Signed-off-by: Florian Tobias Schandinat diff --git a/drivers/video/via/global.c b/drivers/video/via/global.c index 1ee511b..e10d824 100644 --- a/drivers/video/via/global.c +++ b/drivers/video/via/global.c @@ -40,10 +40,6 @@ int viafb_hotplug_Yres = 480; int viafb_hotplug_bpp = 32; int viafb_hotplug_refresh = 60; int viafb_primary_dev = None_Device; -unsigned int viafb_second_xres = 640; -unsigned int viafb_second_yres = 480; -unsigned int viafb_second_virtual_xres; -unsigned int viafb_second_virtual_yres; int viafb_lcd_panel_id = LCD_PANEL_ID_MAXIMUM + 1; struct fb_info *viafbinfo; struct fb_info *viafbinfo1; diff --git a/drivers/video/via/global.h b/drivers/video/via/global.h index 38ef5ac..ff969dc 100644 --- a/drivers/video/via/global.h +++ b/drivers/video/via/global.h @@ -73,8 +73,6 @@ extern int viafb_hotplug_bpp; extern int viafb_hotplug_refresh; extern int viafb_primary_dev; -extern unsigned int viafb_second_xres; -extern unsigned int viafb_second_yres; extern int viafb_lcd_panel_id; #endif /* __GLOBAL_H__ */ diff --git a/drivers/video/via/hw.h b/drivers/video/via/hw.h index 8858593..090d167 100644 --- a/drivers/video/via/hw.h +++ b/drivers/video/via/hw.h @@ -910,7 +910,6 @@ struct via_device_mapping { const char *name; }; -extern unsigned int viafb_second_virtual_xres; extern int viafb_SAMM_ON; extern int viafb_dual_fb; extern int viafb_LCD2_ON; diff --git a/drivers/video/via/viafbdev.c b/drivers/video/via/viafbdev.c index ed9bd79..eace9a4 100644 --- a/drivers/video/via/viafbdev.c +++ b/drivers/video/via/viafbdev.c @@ -37,6 +37,8 @@ static char *viafb_mode1; static int viafb_bpp = 32; static int viafb_bpp1 = 32; +static unsigned int viafb_second_xres = 640; +static unsigned int viafb_second_yres = 480; static unsigned int viafb_second_offset; static int viafb_second_size; @@ -440,8 +442,8 @@ static int viafb_ioctl(struct fb_info *info, u_int cmd, u_long arg) if (viafb_SAMM_ON == 1) { u.viamode.xres_sec = viafb_second_xres; u.viamode.yres_sec = viafb_second_yres; - u.viamode.virtual_xres_sec = viafb_second_virtual_xres; - u.viamode.virtual_yres_sec = viafb_second_virtual_yres; + u.viamode.virtual_xres_sec = viafb_dual_fb ? viafbinfo1->var.xres_virtual : viafbinfo->var.xres_virtual; + u.viamode.virtual_yres_sec = viafb_dual_fb ? viafbinfo1->var.yres_virtual : viafbinfo->var.yres_virtual; u.viamode.refresh_sec = viafb_refresh1; u.viamode.bpp_sec = viafb_bpp1; } else { @@ -1790,14 +1792,10 @@ int __devinit via_fb_pci_probe(struct viafb_dev *vdev) parse_mode(viafb_mode, &default_xres, &default_yres); vmode_entry = viafb_get_mode(default_xres, default_yres); - if (viafb_SAMM_ON == 1) { + if (viafb_SAMM_ON == 1) parse_mode(viafb_mode1, &viafb_second_xres, &viafb_second_yres); - viafb_second_virtual_xres = viafb_second_xres; - viafb_second_virtual_yres = viafb_second_yres; - } - default_var.xres = default_xres; default_var.yres = default_yres; default_var.xres_virtual = default_xres; @@ -1841,8 +1839,8 @@ int __devinit via_fb_pci_probe(struct viafb_dev *vdev) default_var.xres = viafb_second_xres; default_var.yres = viafb_second_yres; - default_var.xres_virtual = viafb_second_virtual_xres; - default_var.yres_virtual = viafb_second_virtual_yres; + default_var.xres_virtual = viafb_second_xres; + default_var.yres_virtual = viafb_second_yres; default_var.bits_per_pixel = viafb_bpp1; viafb_fill_var_timing_info(&default_var, viafb_get_refresh( default_var.xres, default_var.yres, viafb_refresh1), diff --git a/drivers/video/via/viafbdev.h b/drivers/video/via/viafbdev.h index ff60e1d..59e40d1 100644 --- a/drivers/video/via/viafbdev.h +++ b/drivers/video/via/viafbdev.h @@ -83,8 +83,6 @@ struct viafb_par { struct chip_information *chip_info; }; -extern unsigned int viafb_second_virtual_yres; -extern unsigned int viafb_second_virtual_xres; extern int viafb_SAMM_ON; extern int viafb_dual_fb; extern int viafb_LCD2_ON; -- cgit v0.10.2 From cd00b1154d3c7d711e83c3c17b831aafe6377532 Mon Sep 17 00:00:00 2001 From: Florian Tobias Schandinat Date: Sun, 27 Mar 2011 03:36:00 +0000 Subject: viafb: replace custom return values This patch replaces OK/FAIL by true/false which is simpler and saner. Signed-off-by: Florian Tobias Schandinat diff --git a/drivers/video/via/dvi.c b/drivers/video/via/dvi.c index 3dbcd77..b1f3647 100644 --- a/drivers/video/via/dvi.c +++ b/drivers/video/via/dvi.c @@ -30,12 +30,9 @@ static void __devinit dvi_get_panel_size_from_DDCv1( struct tmds_setting_information *tmds_setting); static int viafb_dvi_query_EDID(void); -static int check_tmds_chip(int device_id_subaddr, int device_id) +static inline bool check_tmds_chip(int device_id_subaddr, int device_id) { - if (tmds_register_read(device_id_subaddr) == device_id) - return OK; - else - return FAIL; + return tmds_register_read(device_id_subaddr) == device_id; } void __devinit viafb_init_dvi_size(struct tmds_chip_information *tmds_chip, @@ -50,7 +47,7 @@ void __devinit viafb_init_dvi_size(struct tmds_chip_information *tmds_chip, return; } -int __devinit viafb_tmds_trasmitter_identify(void) +bool __devinit viafb_tmds_trasmitter_identify(void) { unsigned char sr2a = 0, sr1e = 0, sr3e = 0; @@ -89,7 +86,7 @@ int __devinit viafb_tmds_trasmitter_identify(void) viaparinfo->chip_info-> tmds_chip_info.tmds_chip_slave_addr = VT1632_TMDS_I2C_ADDR; viaparinfo->chip_info->tmds_chip_info.i2c_port = VIA_PORT_31; - if (check_tmds_chip(VT1632_DEVICE_ID_REG, VT1632_DEVICE_ID) != FAIL) { + if (check_tmds_chip(VT1632_DEVICE_ID_REG, VT1632_DEVICE_ID)) { /* * Currently only support 12bits,dual edge,add 24bits mode later */ @@ -100,11 +97,10 @@ int __devinit viafb_tmds_trasmitter_identify(void) viaparinfo->chip_info->tmds_chip_info.tmds_chip_name); DEBUG_MSG(KERN_INFO "\n %2d", viaparinfo->chip_info->tmds_chip_info.i2c_port); - return OK; + return true; } else { viaparinfo->chip_info->tmds_chip_info.i2c_port = VIA_PORT_2C; - if (check_tmds_chip(VT1632_DEVICE_ID_REG, VT1632_DEVICE_ID) - != FAIL) { + if (check_tmds_chip(VT1632_DEVICE_ID_REG, VT1632_DEVICE_ID)) { tmds_register_write(0x08, 0x3b); DEBUG_MSG(KERN_INFO "\n VT1632 TMDS ! \n"); DEBUG_MSG(KERN_INFO "\n %2d", @@ -113,7 +109,7 @@ int __devinit viafb_tmds_trasmitter_identify(void) DEBUG_MSG(KERN_INFO "\n %2d", viaparinfo->chip_info-> tmds_chip_info.i2c_port); - return OK; + return true; } } @@ -123,7 +119,7 @@ int __devinit viafb_tmds_trasmitter_identify(void) ((viafb_display_hardware_layout == HW_LAYOUT_DVI_ONLY) || (viafb_display_hardware_layout == HW_LAYOUT_LCD_DVI))) { DEBUG_MSG(KERN_INFO "\n Integrated TMDS ! \n"); - return OK; + return true; } switch (viaparinfo->chip_info->gfx_chip_name) { @@ -147,7 +143,7 @@ int __devinit viafb_tmds_trasmitter_identify(void) tmds_chip_info.tmds_chip_name = NON_TMDS_TRANSMITTER; viaparinfo->chip_info->tmds_chip_info. tmds_chip_slave_addr = VT1632_TMDS_I2C_ADDR; - return FAIL; + return false; } static void tmds_register_write(int index, u8 data) diff --git a/drivers/video/via/dvi.h b/drivers/video/via/dvi.h index 2c525c0..f473dd0 100644 --- a/drivers/video/via/dvi.h +++ b/drivers/video/via/dvi.h @@ -56,7 +56,7 @@ int viafb_dvi_sense(void); void viafb_dvi_disable(void); void viafb_dvi_enable(void); -int __devinit viafb_tmds_trasmitter_identify(void); +bool __devinit viafb_tmds_trasmitter_identify(void); void __devinit viafb_init_dvi_size(struct tmds_chip_information *tmds_chip, struct tmds_setting_information *tmds_setting); void viafb_dvi_set_mode(struct VideoModeTable *videoMode, int mode_bpp, diff --git a/drivers/video/via/lcd.c b/drivers/video/via/lcd.c index 64bc7e7..6984046 100644 --- a/drivers/video/via/lcd.c +++ b/drivers/video/via/lcd.c @@ -48,7 +48,6 @@ static struct _lcd_scaling_factor lcd_scaling_factor_CLE = { {LCD_VER_SCALING_FACTOR_REG_NUM_CLE, {{CR78, 0, 7}, {CR79, 6, 7} } } }; -static int check_lvds_chip(int device_id_subaddr, int device_id); static bool lvds_identify_integratedlvds(void); static void __devinit fp_id_to_vindex(int panel_id); static int lvds_register_read(int index); @@ -84,12 +83,9 @@ static struct display_timing lcd_centering_timging(struct display_timing mode_crt_reg, struct display_timing panel_crt_reg); -static int check_lvds_chip(int device_id_subaddr, int device_id) +static inline bool check_lvds_chip(int device_id_subaddr, int device_id) { - if (lvds_register_read(device_id_subaddr) == device_id) - return OK; - else - return FAIL; + return lvds_register_read(device_id_subaddr) == device_id; } void __devinit viafb_init_lcd_size(void) @@ -150,7 +146,7 @@ static bool lvds_identify_integratedlvds(void) return true; } -int __devinit viafb_lvds_trasmitter_identify(void) +bool __devinit viafb_lvds_trasmitter_identify(void) { if (viafb_lvds_identify_vt1636(VIA_PORT_31)) { viaparinfo->chip_info->lvds_chip_info.i2c_port = VIA_PORT_31; @@ -175,20 +171,20 @@ int __devinit viafb_lvds_trasmitter_identify(void) viaparinfo->chip_info->lvds_chip_info.lvds_chip_slave_addr = VT1631_LVDS_I2C_ADDR; - if (check_lvds_chip(VT1631_DEVICE_ID_REG, VT1631_DEVICE_ID) != FAIL) { + if (check_lvds_chip(VT1631_DEVICE_ID_REG, VT1631_DEVICE_ID)) { DEBUG_MSG(KERN_INFO "\n VT1631 LVDS ! \n"); DEBUG_MSG(KERN_INFO "\n %2d", viaparinfo->chip_info->lvds_chip_info.lvds_chip_name); DEBUG_MSG(KERN_INFO "\n %2d", viaparinfo->chip_info->lvds_chip_info.lvds_chip_name); - return OK; + return true; } viaparinfo->chip_info->lvds_chip_info.lvds_chip_name = NON_LVDS_TRANSMITTER; viaparinfo->chip_info->lvds_chip_info.lvds_chip_slave_addr = VT1631_LVDS_I2C_ADDR; - return FAIL; + return false; } static void __devinit fp_id_to_vindex(int panel_id) diff --git a/drivers/video/via/lcd.h b/drivers/video/via/lcd.h index c7909fe..75f60a6 100644 --- a/drivers/video/via/lcd.h +++ b/drivers/video/via/lcd.h @@ -79,7 +79,7 @@ void __devinit viafb_init_lvds_output_interface(struct lvds_chip_information void viafb_lcd_set_mode(struct crt_mode_table *mode_crt_table, struct lvds_setting_information *plvds_setting_info, struct lvds_chip_information *plvds_chip_info); -int __devinit viafb_lvds_trasmitter_identify(void); +bool __devinit viafb_lvds_trasmitter_identify(void); void viafb_init_lvds_output_interface(struct lvds_chip_information *plvds_chip_info, struct lvds_setting_information diff --git a/drivers/video/via/share.h b/drivers/video/via/share.h index 4b7831f..beb59bc 100644 --- a/drivers/video/via/share.h +++ b/drivers/video/via/share.h @@ -22,14 +22,6 @@ #ifndef __SHARE_H__ #define __SHARE_H__ -/* Define Return Value */ -#define FAIL -1 -#define OK 1 - -#ifndef NULL -#define NULL 0 -#endif - /* Define Bit Field */ #define BIT0 0x01 #define BIT1 0x02 -- cgit v0.10.2 From 49a341f2bb0e8eb2f2877956a758ea40cbd47b26 Mon Sep 17 00:00:00 2001 From: Jozsef Kadlecsik Date: Mon, 28 Mar 2011 14:24:57 +0200 Subject: netfilter: ipset: list:set timeout variant fixes - the timeout value was actually not set - the garbage collector was broken The variant is fixed, the tests to the ipset testsuite are added. Signed-off-by: Jozsef Kadlecsik Signed-off-by: Patrick McHardy diff --git a/net/netfilter/ipset/ip_set_list_set.c b/net/netfilter/ipset/ip_set_list_set.c index a47c329..f4a46c0 100644 --- a/net/netfilter/ipset/ip_set_list_set.c +++ b/net/netfilter/ipset/ip_set_list_set.c @@ -43,14 +43,19 @@ struct list_set { static inline struct set_elem * list_set_elem(const struct list_set *map, u32 id) { - return (struct set_elem *)((char *)map->members + id * map->dsize); + return (struct set_elem *)((void *)map->members + id * map->dsize); +} + +static inline struct set_telem * +list_set_telem(const struct list_set *map, u32 id) +{ + return (struct set_telem *)((void *)map->members + id * map->dsize); } static inline bool list_set_timeout(const struct list_set *map, u32 id) { - const struct set_telem *elem = - (const struct set_telem *) list_set_elem(map, id); + const struct set_telem *elem = list_set_telem(map, id); return ip_set_timeout_test(elem->timeout); } @@ -58,19 +63,11 @@ list_set_timeout(const struct list_set *map, u32 id) static inline bool list_set_expired(const struct list_set *map, u32 id) { - const struct set_telem *elem = - (const struct set_telem *) list_set_elem(map, id); + const struct set_telem *elem = list_set_telem(map, id); return ip_set_timeout_expired(elem->timeout); } -static inline int -list_set_exist(const struct set_telem *elem) -{ - return elem->id != IPSET_INVALID_ID && - !ip_set_timeout_expired(elem->timeout); -} - /* Set list without and with timeout */ static int @@ -146,11 +143,11 @@ list_elem_tadd(struct list_set *map, u32 i, ip_set_id_t id, struct set_telem *e; for (; i < map->size; i++) { - e = (struct set_telem *)list_set_elem(map, i); + e = list_set_telem(map, i); swap(e->id, id); + swap(e->timeout, timeout); if (e->id == IPSET_INVALID_ID) break; - swap(e->timeout, timeout); } } @@ -164,7 +161,7 @@ list_set_add(struct list_set *map, u32 i, ip_set_id_t id, /* Last element replaced: e.g. add new,before,last */ ip_set_put_byindex(e->id); if (with_timeout(map->timeout)) - list_elem_tadd(map, i, id, timeout); + list_elem_tadd(map, i, id, ip_set_timeout_set(timeout)); else list_elem_add(map, i, id); @@ -172,11 +169,11 @@ list_set_add(struct list_set *map, u32 i, ip_set_id_t id, } static int -list_set_del(struct list_set *map, ip_set_id_t id, u32 i) +list_set_del(struct list_set *map, u32 i) { struct set_elem *a = list_set_elem(map, i), *b; - ip_set_put_byindex(id); + ip_set_put_byindex(a->id); for (; i < map->size - 1; i++) { b = list_set_elem(map, i + 1); @@ -308,11 +305,11 @@ list_set_uadt(struct ip_set *set, struct nlattr *tb[], (before == 0 || (before > 0 && next_id_eq(map, i, refid)))) - ret = list_set_del(map, id, i); + ret = list_set_del(map, i); else if (before < 0 && elem->id == refid && next_id_eq(map, i, id)) - ret = list_set_del(map, id, i + 1); + ret = list_set_del(map, i + 1); } break; default: @@ -460,17 +457,15 @@ list_set_gc(unsigned long ul_set) struct list_set *map = set->data; struct set_telem *e; u32 i; - - /* We run parallel with other readers (test element) - * but adding/deleting new entries is locked out */ - read_lock_bh(&set->lock); - for (i = map->size - 1; i >= 0; i--) { - e = (struct set_telem *) list_set_elem(map, i); - if (e->id != IPSET_INVALID_ID && - list_set_expired(map, i)) - list_set_del(map, e->id, i); + + /* nfnl_lock should be called */ + write_lock_bh(&set->lock); + for (i = 0; i < map->size; i++) { + e = list_set_telem(map, i); + if (e->id != IPSET_INVALID_ID && list_set_expired(map, i)) + list_set_del(map, i); } - read_unlock_bh(&set->lock); + write_unlock_bh(&set->lock); map->gc.expires = jiffies + IPSET_GC_PERIOD(map->timeout) * HZ; add_timer(&map->gc); -- cgit v0.10.2 From 1d321881afb955bba1e0a8f50d3a04e111fcb581 Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Mon, 28 Mar 2011 00:46:11 +0400 Subject: perf, x86: P4 PMU - clean up the code a bit No change on the functional level, just align the table properly. Signed-off-by: Cyrill Gorcunov Cc: Lin Ming LKML-Reference: <4D8FA213.5050108@openvz.org> Signed-off-by: Ingo Molnar diff --git a/arch/x86/kernel/cpu/perf_event_p4.c b/arch/x86/kernel/cpu/perf_event_p4.c index c2520e1..8ff882f 100644 --- a/arch/x86/kernel/cpu/perf_event_p4.c +++ b/arch/x86/kernel/cpu/perf_event_p4.c @@ -468,7 +468,7 @@ static struct p4_event_bind p4_event_bind_map[] = { .opcode = P4_OPCODE(P4_EVENT_MISPRED_BRANCH_RETIRED), .escr_msr = { MSR_P4_CRU_ESCR0, MSR_P4_CRU_ESCR1 }, .escr_emask = - P4_ESCR_EMASK_BIT(P4_EVENT_MISPRED_BRANCH_RETIRED, NBOGUS), + P4_ESCR_EMASK_BIT(P4_EVENT_MISPRED_BRANCH_RETIRED, NBOGUS), .cntr = { {12, 13, 16}, {14, 15, 17} }, }, [P4_EVENT_X87_ASSIST] = { -- cgit v0.10.2 From 349c004e3d31fda23ad225b61861be38047fff16 Mon Sep 17 00:00:00 2001 From: Christoph Lameter Date: Sat, 12 Mar 2011 12:50:10 +0100 Subject: x86: A fast way to check capabilities of the current cpu Add this_cpu_has() which determines if the current cpu has a certain ability using a segment prefix and a bit test operation. For that we need to add bit operations to x86s percpu.h. Many uses of cpu_has use a pointer passed to a function to determine the current flags. That is no longer necessary after this patch. However, this patch only converts the straightforward cases where cpu_has is used with this_cpu_ptr. The rest is work for later. -tj: Rolled up patch to add x86_ prefix and use percpu_read() instead of percpu_read_stable(). Signed-off-by: Christoph Lameter Acked-by: Tejun Heo Signed-off-by: Tejun Heo diff --git a/arch/x86/include/asm/cpufeature.h b/arch/x86/include/asm/cpufeature.h index 91f3e087..50c0d30 100644 --- a/arch/x86/include/asm/cpufeature.h +++ b/arch/x86/include/asm/cpufeature.h @@ -207,8 +207,7 @@ extern const char * const x86_power_flags[32]; #define test_cpu_cap(c, bit) \ test_bit(bit, (unsigned long *)((c)->x86_capability)) -#define cpu_has(c, bit) \ - (__builtin_constant_p(bit) && \ +#define REQUIRED_MASK_BIT_SET(bit) \ ( (((bit)>>5)==0 && (1UL<<((bit)&31) & REQUIRED_MASK0)) || \ (((bit)>>5)==1 && (1UL<<((bit)&31) & REQUIRED_MASK1)) || \ (((bit)>>5)==2 && (1UL<<((bit)&31) & REQUIRED_MASK2)) || \ @@ -218,10 +217,16 @@ extern const char * const x86_power_flags[32]; (((bit)>>5)==6 && (1UL<<((bit)&31) & REQUIRED_MASK6)) || \ (((bit)>>5)==7 && (1UL<<((bit)&31) & REQUIRED_MASK7)) || \ (((bit)>>5)==8 && (1UL<<((bit)&31) & REQUIRED_MASK8)) || \ - (((bit)>>5)==9 && (1UL<<((bit)&31) & REQUIRED_MASK9)) ) \ - ? 1 : \ + (((bit)>>5)==9 && (1UL<<((bit)&31) & REQUIRED_MASK9)) ) + +#define cpu_has(c, bit) \ + (__builtin_constant_p(bit) && REQUIRED_MASK_BIT_SET(bit) ? 1 : \ test_cpu_cap(c, bit)) +#define this_cpu_has(bit) \ + (__builtin_constant_p(bit) && REQUIRED_MASK_BIT_SET(bit) ? 1 : \ + x86_this_cpu_test_bit(bit, (unsigned long *)&cpu_info.x86_capability)) + #define boot_cpu_has(bit) cpu_has(&boot_cpu_data, bit) #define set_cpu_cap(c, bit) set_bit(bit, (unsigned long *)((c)->x86_capability)) diff --git a/arch/x86/include/asm/percpu.h b/arch/x86/include/asm/percpu.h index d475b43..76042d9 100644 --- a/arch/x86/include/asm/percpu.h +++ b/arch/x86/include/asm/percpu.h @@ -542,6 +542,33 @@ do { \ old__; \ }) +static __always_inline int x86_this_cpu_constant_test_bit(unsigned int nr, + const unsigned long __percpu *addr) +{ + unsigned long __percpu *a = (unsigned long *)addr + nr / BITS_PER_LONG; + + return ((1UL << (nr % BITS_PER_LONG)) & percpu_read(*a)) != 0; +} + +static inline int x86_this_cpu_variable_test_bit(int nr, + const unsigned long __percpu *addr) +{ + int oldbit; + + asm volatile("bt "__percpu_arg(2)",%1\n\t" + "sbb %0,%0" + : "=r" (oldbit) + : "m" (*(unsigned long *)addr), "Ir" (nr)); + + return oldbit; +} + +#define x86_this_cpu_test_bit(nr, addr) \ + (__builtin_constant_p((nr)) \ + ? x86_this_cpu_constant_test_bit((nr), (addr)) \ + : x86_this_cpu_variable_test_bit((nr), (addr))) + + #include /* We can use this directly for local CPU (faster). */ diff --git a/arch/x86/kernel/apic/apic.c b/arch/x86/kernel/apic/apic.c index fabf01e..2bc503b 100644 --- a/arch/x86/kernel/apic/apic.c +++ b/arch/x86/kernel/apic/apic.c @@ -505,7 +505,7 @@ static void __cpuinit setup_APIC_timer(void) { struct clock_event_device *levt = &__get_cpu_var(lapic_events); - if (cpu_has(__this_cpu_ptr(&cpu_info), X86_FEATURE_ARAT)) { + if (this_cpu_has(X86_FEATURE_ARAT)) { lapic_clockevent.features &= ~CLOCK_EVT_FEAT_C3STOP; /* Make LAPIC timer preferrable over percpu HPET */ lapic_clockevent.rating = 150; diff --git a/arch/x86/kernel/process.c b/arch/x86/kernel/process.c index d46cbe4..88a90a9 100644 --- a/arch/x86/kernel/process.c +++ b/arch/x86/kernel/process.c @@ -449,7 +449,7 @@ EXPORT_SYMBOL_GPL(cpu_idle_wait); void mwait_idle_with_hints(unsigned long ax, unsigned long cx) { if (!need_resched()) { - if (cpu_has(__this_cpu_ptr(&cpu_info), X86_FEATURE_CLFLUSH_MONITOR)) + if (this_cpu_has(X86_FEATURE_CLFLUSH_MONITOR)) clflush((void *)¤t_thread_info()->flags); __monitor((void *)¤t_thread_info()->flags, 0, 0); @@ -465,7 +465,7 @@ static void mwait_idle(void) if (!need_resched()) { trace_power_start(POWER_CSTATE, 1, smp_processor_id()); trace_cpu_idle(1, smp_processor_id()); - if (cpu_has(__this_cpu_ptr(&cpu_info), X86_FEATURE_CLFLUSH_MONITOR)) + if (this_cpu_has(X86_FEATURE_CLFLUSH_MONITOR)) clflush((void *)¤t_thread_info()->flags); __monitor((void *)¤t_thread_info()->flags, 0, 0); diff --git a/arch/x86/kernel/smpboot.c b/arch/x86/kernel/smpboot.c index c2871d3..a3c430b 100644 --- a/arch/x86/kernel/smpboot.c +++ b/arch/x86/kernel/smpboot.c @@ -1332,9 +1332,9 @@ static inline void mwait_play_dead(void) void *mwait_ptr; struct cpuinfo_x86 *c = __this_cpu_ptr(&cpu_info); - if (!(cpu_has(c, X86_FEATURE_MWAIT) && mwait_usable(c))) + if (!this_cpu_has(X86_FEATURE_MWAIT) && mwait_usable(c)) return; - if (!cpu_has(__this_cpu_ptr(&cpu_info), X86_FEATURE_CLFLSH)) + if (!this_cpu_has(X86_FEATURE_CLFLSH)) return; if (__this_cpu_read(cpu_info.cpuid_level) < CPUID_MWAIT_LEAF) return; -- cgit v0.10.2 From fe5042138b6fc60edde3b60025078884c2eb71ac Mon Sep 17 00:00:00 2001 From: Christoph Lameter Date: Sat, 12 Mar 2011 12:50:46 +0100 Subject: x86: Use this_cpu_has for thermal_interrupt current cpu It is more effective to use a segment prefix instead of calculating the address of the current cpu area amd then testing flags. Signed-off-by: Christoph Lameter Acked-by: Tejun Heo Signed-off-by: Tejun Heo diff --git a/arch/x86/kernel/cpu/mcheck/therm_throt.c b/arch/x86/kernel/cpu/mcheck/therm_throt.c index 6f8c5e9..6b0f4cd 100644 --- a/arch/x86/kernel/cpu/mcheck/therm_throt.c +++ b/arch/x86/kernel/cpu/mcheck/therm_throt.c @@ -355,7 +355,6 @@ static void notify_thresholds(__u64 msr_val) static void intel_thermal_interrupt(void) { __u64 msr_val; - struct cpuinfo_x86 *c = &cpu_data(smp_processor_id()); rdmsrl(MSR_IA32_THERM_STATUS, msr_val); @@ -367,19 +366,19 @@ static void intel_thermal_interrupt(void) CORE_LEVEL) != 0) mce_log_therm_throt_event(CORE_THROTTLED | msr_val); - if (cpu_has(c, X86_FEATURE_PLN)) + if (this_cpu_has(X86_FEATURE_PLN)) if (therm_throt_process(msr_val & THERM_STATUS_POWER_LIMIT, POWER_LIMIT_EVENT, CORE_LEVEL) != 0) mce_log_therm_throt_event(CORE_POWER_LIMIT | msr_val); - if (cpu_has(c, X86_FEATURE_PTS)) { + if (this_cpu_has(X86_FEATURE_PTS)) { rdmsrl(MSR_IA32_PACKAGE_THERM_STATUS, msr_val); if (therm_throt_process(msr_val & PACKAGE_THERM_STATUS_PROCHOT, THERMAL_THROTTLING_EVENT, PACKAGE_LEVEL) != 0) mce_log_therm_throt_event(PACKAGE_THROTTLED | msr_val); - if (cpu_has(c, X86_FEATURE_PLN)) + if (this_cpu_has(X86_FEATURE_PLN)) if (therm_throt_process(msr_val & PACKAGE_THERM_STATUS_POWER_LIMIT, POWER_LIMIT_EVENT, -- cgit v0.10.2 From 9d42a53e0f46505b39494041d514372235817e15 Mon Sep 17 00:00:00 2001 From: Christoph Lameter Date: Sat, 12 Mar 2011 12:51:12 +0100 Subject: acpi throttling: Use this_cpu_has and simplify code current cpu With the this_cpu_xx we no longer need to pass an acpi structure to the msr management code. Simplifies code and improves performance. NOTE: This code is x86 specific (see #ifdef CONFIG_X86) but not under arch/x86. Signed-off-by: Christoph Lameter Acked-by: Tejun Heo Signed-off-by: Tejun Heo diff --git a/drivers/acpi/processor_throttling.c b/drivers/acpi/processor_throttling.c index fa84e97..6f2c6d9 100644 --- a/drivers/acpi/processor_throttling.c +++ b/drivers/acpi/processor_throttling.c @@ -710,20 +710,14 @@ static int acpi_processor_get_throttling_fadt(struct acpi_processor *pr) } #ifdef CONFIG_X86 -static int acpi_throttling_rdmsr(struct acpi_processor *pr, - u64 *value) +static int acpi_throttling_rdmsr(u64 *value) { - struct cpuinfo_x86 *c; u64 msr_high, msr_low; - unsigned int cpu; u64 msr = 0; int ret = -1; - cpu = pr->id; - c = &cpu_data(cpu); - - if ((c->x86_vendor != X86_VENDOR_INTEL) || - !cpu_has(c, X86_FEATURE_ACPI)) { + if ((this_cpu_read(cpu_info.x86_vendor) != X86_VENDOR_INTEL) || + !this_cpu_has(X86_FEATURE_ACPI)) { printk(KERN_ERR PREFIX "HARDWARE addr space,NOT supported yet\n"); } else { @@ -738,18 +732,13 @@ static int acpi_throttling_rdmsr(struct acpi_processor *pr, return ret; } -static int acpi_throttling_wrmsr(struct acpi_processor *pr, u64 value) +static int acpi_throttling_wrmsr(u64 value) { - struct cpuinfo_x86 *c; - unsigned int cpu; int ret = -1; u64 msr; - cpu = pr->id; - c = &cpu_data(cpu); - - if ((c->x86_vendor != X86_VENDOR_INTEL) || - !cpu_has(c, X86_FEATURE_ACPI)) { + if ((this_cpu_read(cpu_info.x86_vendor) != X86_VENDOR_INTEL) || + !this_cpu_has(X86_FEATURE_ACPI)) { printk(KERN_ERR PREFIX "HARDWARE addr space,NOT supported yet\n"); } else { @@ -761,15 +750,14 @@ static int acpi_throttling_wrmsr(struct acpi_processor *pr, u64 value) return ret; } #else -static int acpi_throttling_rdmsr(struct acpi_processor *pr, - u64 *value) +static int acpi_throttling_rdmsr(u64 *value) { printk(KERN_ERR PREFIX "HARDWARE addr space,NOT supported yet\n"); return -1; } -static int acpi_throttling_wrmsr(struct acpi_processor *pr, u64 value) +static int acpi_throttling_wrmsr(u64 value) { printk(KERN_ERR PREFIX "HARDWARE addr space,NOT supported yet\n"); @@ -801,7 +789,7 @@ static int acpi_read_throttling_status(struct acpi_processor *pr, ret = 0; break; case ACPI_ADR_SPACE_FIXED_HARDWARE: - ret = acpi_throttling_rdmsr(pr, value); + ret = acpi_throttling_rdmsr(value); break; default: printk(KERN_ERR PREFIX "Unknown addr space %d\n", @@ -834,7 +822,7 @@ static int acpi_write_throttling_state(struct acpi_processor *pr, ret = 0; break; case ACPI_ADR_SPACE_FIXED_HARDWARE: - ret = acpi_throttling_wrmsr(pr, value); + ret = acpi_throttling_wrmsr(value); break; default: printk(KERN_ERR PREFIX "Unknown addr space %d\n", -- cgit v0.10.2 From 6604271c5bc658a6067ed0c3deba4d89e0e50382 Mon Sep 17 00:00:00 2001 From: Jozsef Kadlecsik Date: Tue, 29 Mar 2011 15:00:43 +0200 Subject: netfilter: ipset: References are protected by rwlock instead of mutex The timeout variant of the list:set type must reference the member sets. However, its garbage collector runs at timer interrupt so the mutex protection of the references is a no go. Therefore the reference protection is converted to rwlock. Signed-off-by: Jozsef Kadlecsik Signed-off-by: Patrick McHardy diff --git a/include/linux/netfilter/ipset/ip_set.h b/include/linux/netfilter/ipset/ip_set.h index ec333d8..5a262e3 100644 --- a/include/linux/netfilter/ipset/ip_set.h +++ b/include/linux/netfilter/ipset/ip_set.h @@ -293,7 +293,7 @@ struct ip_set { /* Lock protecting the set data */ rwlock_t lock; /* References to the set */ - atomic_t ref; + u32 ref; /* The core set type */ struct ip_set_type *type; /* The type variant doing the real job */ diff --git a/include/linux/netfilter/ipset/ip_set_ahash.h b/include/linux/netfilter/ipset/ip_set_ahash.h index ec9d9be..a0196ac 100644 --- a/include/linux/netfilter/ipset/ip_set_ahash.h +++ b/include/linux/netfilter/ipset/ip_set_ahash.h @@ -515,8 +515,7 @@ type_pf_head(struct ip_set *set, struct sk_buff *skb) if (h->netmask != HOST_MASK) NLA_PUT_U8(skb, IPSET_ATTR_NETMASK, h->netmask); #endif - NLA_PUT_NET32(skb, IPSET_ATTR_REFERENCES, - htonl(atomic_read(&set->ref) - 1)); + NLA_PUT_NET32(skb, IPSET_ATTR_REFERENCES, htonl(set->ref - 1)); NLA_PUT_NET32(skb, IPSET_ATTR_MEMSIZE, htonl(memsize)); if (with_timeout(h->timeout)) NLA_PUT_NET32(skb, IPSET_ATTR_TIMEOUT, htonl(h->timeout)); diff --git a/net/netfilter/ipset/ip_set_bitmap_ip.c b/net/netfilter/ipset/ip_set_bitmap_ip.c index bca9699..a113ff0 100644 --- a/net/netfilter/ipset/ip_set_bitmap_ip.c +++ b/net/netfilter/ipset/ip_set_bitmap_ip.c @@ -338,8 +338,7 @@ bitmap_ip_head(struct ip_set *set, struct sk_buff *skb) NLA_PUT_IPADDR4(skb, IPSET_ATTR_IP_TO, htonl(map->last_ip)); if (map->netmask != 32) NLA_PUT_U8(skb, IPSET_ATTR_NETMASK, map->netmask); - NLA_PUT_NET32(skb, IPSET_ATTR_REFERENCES, - htonl(atomic_read(&set->ref) - 1)); + NLA_PUT_NET32(skb, IPSET_ATTR_REFERENCES, htonl(set->ref - 1)); NLA_PUT_NET32(skb, IPSET_ATTR_MEMSIZE, htonl(sizeof(*map) + map->memsize)); if (with_timeout(map->timeout)) diff --git a/net/netfilter/ipset/ip_set_bitmap_ipmac.c b/net/netfilter/ipset/ip_set_bitmap_ipmac.c index 5e79017..00a3324 100644 --- a/net/netfilter/ipset/ip_set_bitmap_ipmac.c +++ b/net/netfilter/ipset/ip_set_bitmap_ipmac.c @@ -434,8 +434,7 @@ bitmap_ipmac_head(struct ip_set *set, struct sk_buff *skb) goto nla_put_failure; NLA_PUT_IPADDR4(skb, IPSET_ATTR_IP, htonl(map->first_ip)); NLA_PUT_IPADDR4(skb, IPSET_ATTR_IP_TO, htonl(map->last_ip)); - NLA_PUT_NET32(skb, IPSET_ATTR_REFERENCES, - htonl(atomic_read(&set->ref) - 1)); + NLA_PUT_NET32(skb, IPSET_ATTR_REFERENCES, htonl(set->ref - 1)); NLA_PUT_NET32(skb, IPSET_ATTR_MEMSIZE, htonl(sizeof(*map) + (map->last_ip - map->first_ip + 1) * map->dsize)); diff --git a/net/netfilter/ipset/ip_set_bitmap_port.c b/net/netfilter/ipset/ip_set_bitmap_port.c index 165f09b..6b38eb8 100644 --- a/net/netfilter/ipset/ip_set_bitmap_port.c +++ b/net/netfilter/ipset/ip_set_bitmap_port.c @@ -320,8 +320,7 @@ bitmap_port_head(struct ip_set *set, struct sk_buff *skb) goto nla_put_failure; NLA_PUT_NET16(skb, IPSET_ATTR_PORT, htons(map->first_port)); NLA_PUT_NET16(skb, IPSET_ATTR_PORT_TO, htons(map->last_port)); - NLA_PUT_NET32(skb, IPSET_ATTR_REFERENCES, - htonl(atomic_read(&set->ref) - 1)); + NLA_PUT_NET32(skb, IPSET_ATTR_REFERENCES, htonl(set->ref - 1)); NLA_PUT_NET32(skb, IPSET_ATTR_MEMSIZE, htonl(sizeof(*map) + map->memsize)); if (with_timeout(map->timeout)) diff --git a/net/netfilter/ipset/ip_set_core.c b/net/netfilter/ipset/ip_set_core.c index d6b4823..e88ac3c 100644 --- a/net/netfilter/ipset/ip_set_core.c +++ b/net/netfilter/ipset/ip_set_core.c @@ -26,6 +26,7 @@ static LIST_HEAD(ip_set_type_list); /* all registered set types */ static DEFINE_MUTEX(ip_set_type_mutex); /* protects ip_set_type_list */ +static DEFINE_RWLOCK(ip_set_ref_lock); /* protects the set refs */ static struct ip_set **ip_set_list; /* all individual sets */ static ip_set_id_t ip_set_max = CONFIG_IP_SET_MAX; /* max number of sets */ @@ -301,13 +302,18 @@ EXPORT_SYMBOL_GPL(ip_set_get_ipaddr6); static inline void __ip_set_get(ip_set_id_t index) { - atomic_inc(&ip_set_list[index]->ref); + write_lock_bh(&ip_set_ref_lock); + ip_set_list[index]->ref++; + write_unlock_bh(&ip_set_ref_lock); } static inline void __ip_set_put(ip_set_id_t index) { - atomic_dec(&ip_set_list[index]->ref); + write_lock_bh(&ip_set_ref_lock); + BUG_ON(ip_set_list[index]->ref == 0); + ip_set_list[index]->ref--; + write_unlock_bh(&ip_set_ref_lock); } /* @@ -324,7 +330,7 @@ ip_set_test(ip_set_id_t index, const struct sk_buff *skb, struct ip_set *set = ip_set_list[index]; int ret = 0; - BUG_ON(set == NULL || atomic_read(&set->ref) == 0); + BUG_ON(set == NULL); pr_debug("set %s, index %u\n", set->name, index); if (dim < set->type->dimension || @@ -356,7 +362,7 @@ ip_set_add(ip_set_id_t index, const struct sk_buff *skb, struct ip_set *set = ip_set_list[index]; int ret; - BUG_ON(set == NULL || atomic_read(&set->ref) == 0); + BUG_ON(set == NULL); pr_debug("set %s, index %u\n", set->name, index); if (dim < set->type->dimension || @@ -378,7 +384,7 @@ ip_set_del(ip_set_id_t index, const struct sk_buff *skb, struct ip_set *set = ip_set_list[index]; int ret = 0; - BUG_ON(set == NULL || atomic_read(&set->ref) == 0); + BUG_ON(set == NULL); pr_debug("set %s, index %u\n", set->name, index); if (dim < set->type->dimension || @@ -397,7 +403,6 @@ EXPORT_SYMBOL_GPL(ip_set_del); * Find set by name, reference it once. The reference makes sure the * thing pointed to, does not go away under our feet. * - * The nfnl mutex must already be activated. */ ip_set_id_t ip_set_get_byname(const char *name, struct ip_set **set) @@ -423,15 +428,12 @@ EXPORT_SYMBOL_GPL(ip_set_get_byname); * reference count by 1. The caller shall not assume the index * to be valid, after calling this function. * - * The nfnl mutex must already be activated. */ void ip_set_put_byindex(ip_set_id_t index) { - if (ip_set_list[index] != NULL) { - BUG_ON(atomic_read(&ip_set_list[index]->ref) == 0); + if (ip_set_list[index] != NULL) __ip_set_put(index); - } } EXPORT_SYMBOL_GPL(ip_set_put_byindex); @@ -441,7 +443,6 @@ EXPORT_SYMBOL_GPL(ip_set_put_byindex); * can't be destroyed. The set cannot be renamed due to * the referencing either. * - * The nfnl mutex must already be activated. */ const char * ip_set_name_byindex(ip_set_id_t index) @@ -449,7 +450,7 @@ ip_set_name_byindex(ip_set_id_t index) const struct ip_set *set = ip_set_list[index]; BUG_ON(set == NULL); - BUG_ON(atomic_read(&set->ref) == 0); + BUG_ON(set->ref == 0); /* Referenced, so it's safe */ return set->name; @@ -515,10 +516,7 @@ void ip_set_nfnl_put(ip_set_id_t index) { nfnl_lock(); - if (ip_set_list[index] != NULL) { - BUG_ON(atomic_read(&ip_set_list[index]->ref) == 0); - __ip_set_put(index); - } + ip_set_put_byindex(index); nfnl_unlock(); } EXPORT_SYMBOL_GPL(ip_set_nfnl_put); @@ -526,7 +524,7 @@ EXPORT_SYMBOL_GPL(ip_set_nfnl_put); /* * Communication protocol with userspace over netlink. * - * We already locked by nfnl_lock. + * The commands are serialized by the nfnl mutex. */ static inline bool @@ -657,7 +655,6 @@ ip_set_create(struct sock *ctnl, struct sk_buff *skb, return -ENOMEM; rwlock_init(&set->lock); strlcpy(set->name, name, IPSET_MAXNAMELEN); - atomic_set(&set->ref, 0); set->family = family; /* @@ -690,8 +687,8 @@ ip_set_create(struct sock *ctnl, struct sk_buff *skb, /* * Here, we have a valid, constructed set and we are protected - * by nfnl_lock. Find the first free index in ip_set_list and - * check clashing. + * by the nfnl mutex. Find the first free index in ip_set_list + * and check clashing. */ if ((ret = find_free_id(set->name, &index, &clash)) != 0) { /* If this is the same set and requested, ignore error */ @@ -751,31 +748,51 @@ ip_set_destroy(struct sock *ctnl, struct sk_buff *skb, const struct nlattr * const attr[]) { ip_set_id_t i; + int ret = 0; if (unlikely(protocol_failed(attr))) return -IPSET_ERR_PROTOCOL; - /* References are protected by the nfnl mutex */ + /* Commands are serialized and references are + * protected by the ip_set_ref_lock. + * External systems (i.e. xt_set) must call + * ip_set_put|get_nfnl_* functions, that way we + * can safely check references here. + * + * list:set timer can only decrement the reference + * counter, so if it's already zero, we can proceed + * without holding the lock. + */ + read_lock_bh(&ip_set_ref_lock); if (!attr[IPSET_ATTR_SETNAME]) { for (i = 0; i < ip_set_max; i++) { - if (ip_set_list[i] != NULL && - (atomic_read(&ip_set_list[i]->ref))) - return -IPSET_ERR_BUSY; + if (ip_set_list[i] != NULL && ip_set_list[i]->ref) { + ret = IPSET_ERR_BUSY; + goto out; + } } + read_unlock_bh(&ip_set_ref_lock); for (i = 0; i < ip_set_max; i++) { if (ip_set_list[i] != NULL) ip_set_destroy_set(i); } } else { i = find_set_id(nla_data(attr[IPSET_ATTR_SETNAME])); - if (i == IPSET_INVALID_ID) - return -ENOENT; - else if (atomic_read(&ip_set_list[i]->ref)) - return -IPSET_ERR_BUSY; + if (i == IPSET_INVALID_ID) { + ret = -ENOENT; + goto out; + } else if (ip_set_list[i]->ref) { + ret = -IPSET_ERR_BUSY; + goto out; + } + read_unlock_bh(&ip_set_ref_lock); ip_set_destroy_set(i); } return 0; +out: + read_unlock_bh(&ip_set_ref_lock); + return ret; } /* Flush sets */ @@ -834,6 +851,7 @@ ip_set_rename(struct sock *ctnl, struct sk_buff *skb, struct ip_set *set; const char *name2; ip_set_id_t i; + int ret = 0; if (unlikely(protocol_failed(attr) || attr[IPSET_ATTR_SETNAME] == NULL || @@ -843,25 +861,33 @@ ip_set_rename(struct sock *ctnl, struct sk_buff *skb, set = find_set(nla_data(attr[IPSET_ATTR_SETNAME])); if (set == NULL) return -ENOENT; - if (atomic_read(&set->ref) != 0) - return -IPSET_ERR_REFERENCED; + + read_lock_bh(&ip_set_ref_lock); + if (set->ref != 0) { + ret = -IPSET_ERR_REFERENCED; + goto out; + } name2 = nla_data(attr[IPSET_ATTR_SETNAME2]); for (i = 0; i < ip_set_max; i++) { if (ip_set_list[i] != NULL && - STREQ(ip_set_list[i]->name, name2)) - return -IPSET_ERR_EXIST_SETNAME2; + STREQ(ip_set_list[i]->name, name2)) { + ret = -IPSET_ERR_EXIST_SETNAME2; + goto out; + } } strncpy(set->name, name2, IPSET_MAXNAMELEN); - return 0; +out: + read_unlock_bh(&ip_set_ref_lock); + return ret; } /* Swap two sets so that name/index points to the other. * References and set names are also swapped. * - * We are protected by the nfnl mutex and references are - * manipulated only by holding the mutex. The kernel interfaces + * The commands are serialized by the nfnl mutex and references are + * protected by the ip_set_ref_lock. The kernel interfaces * do not hold the mutex but the pointer settings are atomic * so the ip_set_list always contains valid pointers to the sets. */ @@ -874,7 +900,6 @@ ip_set_swap(struct sock *ctnl, struct sk_buff *skb, struct ip_set *from, *to; ip_set_id_t from_id, to_id; char from_name[IPSET_MAXNAMELEN]; - u32 from_ref; if (unlikely(protocol_failed(attr) || attr[IPSET_ATTR_SETNAME] == NULL || @@ -899,17 +924,15 @@ ip_set_swap(struct sock *ctnl, struct sk_buff *skb, from->type->family == to->type->family)) return -IPSET_ERR_TYPE_MISMATCH; - /* No magic here: ref munging protected by the nfnl_lock */ strncpy(from_name, from->name, IPSET_MAXNAMELEN); - from_ref = atomic_read(&from->ref); - strncpy(from->name, to->name, IPSET_MAXNAMELEN); - atomic_set(&from->ref, atomic_read(&to->ref)); strncpy(to->name, from_name, IPSET_MAXNAMELEN); - atomic_set(&to->ref, from_ref); + write_lock_bh(&ip_set_ref_lock); + swap(from->ref, to->ref); ip_set_list[from_id] = to; ip_set_list[to_id] = from; + write_unlock_bh(&ip_set_ref_lock); return 0; } @@ -926,7 +949,7 @@ ip_set_dump_done(struct netlink_callback *cb) { if (cb->args[2]) { pr_debug("release set %s\n", ip_set_list[cb->args[1]]->name); - __ip_set_put((ip_set_id_t) cb->args[1]); + ip_set_put_byindex((ip_set_id_t) cb->args[1]); } return 0; } @@ -1068,7 +1091,7 @@ release_refcount: /* If there was an error or set is done, release set */ if (ret || !cb->args[2]) { pr_debug("release set %s\n", ip_set_list[index]->name); - __ip_set_put(index); + ip_set_put_byindex(index); } /* If we dump all sets, continue with dumping last ones */ diff --git a/net/netfilter/ipset/ip_set_list_set.c b/net/netfilter/ipset/ip_set_list_set.c index f4a46c0..e9159e9 100644 --- a/net/netfilter/ipset/ip_set_list_set.c +++ b/net/netfilter/ipset/ip_set_list_set.c @@ -366,8 +366,7 @@ list_set_head(struct ip_set *set, struct sk_buff *skb) NLA_PUT_NET32(skb, IPSET_ATTR_SIZE, htonl(map->size)); if (with_timeout(map->timeout)) NLA_PUT_NET32(skb, IPSET_ATTR_TIMEOUT, htonl(map->timeout)); - NLA_PUT_NET32(skb, IPSET_ATTR_REFERENCES, - htonl(atomic_read(&set->ref) - 1)); + NLA_PUT_NET32(skb, IPSET_ATTR_REFERENCES, htonl(set->ref - 1)); NLA_PUT_NET32(skb, IPSET_ATTR_MEMSIZE, htonl(sizeof(*map) + map->size * map->dsize)); ipset_nest_end(skb, nested); @@ -457,8 +456,7 @@ list_set_gc(unsigned long ul_set) struct list_set *map = set->data; struct set_telem *e; u32 i; - - /* nfnl_lock should be called */ + write_lock_bh(&set->lock); for (i = 0; i < map->size; i++) { e = list_set_telem(map, i); -- cgit v0.10.2 From cd25f8bc2696664877b21d33b7994e12fa570919 Mon Sep 17 00:00:00 2001 From: Lin Ming Date: Fri, 25 Mar 2011 16:27:48 +0800 Subject: perf probe: Add fastpath to do lookup by function name v3 -> v2: - Make pubname_search_cb more generic - Add fastpath to find_probes also v2 -> v1: - Don't compare file names with cu_find_realpath(...), instead, compare them with the name returned by dwarf_decl_file(sp_die) The vmlinux file may have thousands of CUs. We can lookup function name from .debug_pubnames section to avoid the slow loop on CUs. 1. Improvement data for find_line_range ./perf stat -e cycles -r 10 -- ./perf probe -k /home/mlin/vmlinux \ -s /home/mlin/linux-2.6 \ --line csum_partial_copy_to_user > tmp.log before patch applied ===================== 847,988,276 cycles 0.355075856 seconds time elapsed after patch applied ===================== 206,102,622 cycles 0.086883555 seconds time elapsed 2. Improvement data for find_probes ./perf stat -e cycles -r 10 -- ./perf probe -k /home/mlin/vmlinux \ -s /home/mlin/linux-2.6 \ --vars csum_partial_copy_to_user > tmp.log before patch applied ===================== 848,490,844 cycles 0.355307901 seconds time elapsed after patch applied ===================== 205,684,469 cycles 0.086694010 seconds time elapsed Acked-by: Masami Hiramatsu Cc: Ingo Molnar Cc: Masami Hiramatsu Cc: Peter Zijlstra Cc: linux-kernel LKML-Reference: <1301041668.14111.52.camel@minggr.sh.intel.com> Signed-off-by: Lin Ming Signed-off-by: Arnaldo Carvalho de Melo diff --git a/tools/perf/util/probe-finder.c b/tools/perf/util/probe-finder.c index 194f9e2..ff416b8 100644 --- a/tools/perf/util/probe-finder.c +++ b/tools/perf/util/probe-finder.c @@ -1435,6 +1435,38 @@ static int find_probe_point_by_func(struct probe_finder *pf) return _param.retval; } +struct pubname_callback_param { + char *function; + char *file; + Dwarf_Die *cu_die; + Dwarf_Die *sp_die; + int found; +}; + +static int pubname_search_cb(Dwarf *dbg, Dwarf_Global *gl, void *data) +{ + struct pubname_callback_param *param = data; + + if (dwarf_offdie(dbg, gl->die_offset, param->sp_die)) { + if (dwarf_tag(param->sp_die) != DW_TAG_subprogram) + return DWARF_CB_OK; + + if (die_compare_name(param->sp_die, param->function)) { + if (!dwarf_offdie(dbg, gl->cu_offset, param->cu_die)) + return DWARF_CB_OK; + + if (param->file && + strtailcmp(param->file, dwarf_decl_file(param->sp_die))) + return DWARF_CB_OK; + + param->found = 1; + return DWARF_CB_ABORT; + } + } + + return DWARF_CB_OK; +} + /* Find probe points from debuginfo */ static int find_probes(int fd, struct probe_finder *pf) { @@ -1461,6 +1493,27 @@ static int find_probes(int fd, struct probe_finder *pf) off = 0; line_list__init(&pf->lcache); + + /* Fastpath: lookup by function name from .debug_pubnames section */ + if (pp->function) { + struct pubname_callback_param pubname_param = { + .function = pp->function, + .file = pp->file, + .cu_die = &pf->cu_die, + .sp_die = &pf->sp_die, + }; + struct dwarf_callback_param probe_param = { + .data = pf, + }; + + dwarf_getpubnames(dbg, pubname_search_cb, &pubname_param, 0); + if (pubname_param.found) { + ret = probe_point_search_cb(&pf->sp_die, &probe_param); + if (ret) + goto found; + } + } + /* Loop on CUs (Compilation Unit) */ while (!dwarf_nextcu(dbg, off, &noff, &cuhl, NULL, NULL, NULL)) { /* Get the DIE(Debugging Information Entry) of this CU */ @@ -1488,6 +1541,8 @@ static int find_probes(int fd, struct probe_finder *pf) } off = noff; } + +found: line_list__free(&pf->lcache); if (dwfl) dwfl_end(dwfl); @@ -1895,6 +1950,22 @@ int find_line_range(int fd, struct line_range *lr) return -EBADF; } + /* Fastpath: lookup by function name from .debug_pubnames section */ + if (lr->function) { + struct pubname_callback_param pubname_param = { + .function = lr->function, .file = lr->file, + .cu_die = &lf.cu_die, .sp_die = &lf.sp_die, .found = 0}; + struct dwarf_callback_param line_range_param = { + .data = (void *)&lf, .retval = 0}; + + dwarf_getpubnames(dbg, pubname_search_cb, &pubname_param, 0); + if (pubname_param.found) { + line_range_search_cb(&lf.sp_die, &line_range_param); + if (lf.found) + goto found; + } + } + /* Loop on CUs (Compilation Unit) */ while (!lf.found && ret >= 0) { if (dwarf_nextcu(dbg, off, &noff, &cuhl, NULL, NULL, NULL) != 0) @@ -1923,6 +1994,7 @@ int find_line_range(int fd, struct line_range *lr) off = noff; } +found: /* Store comp_dir */ if (lf.found) { comp_dir = cu_get_comp_dir(&lf.cu_die); diff --git a/tools/perf/util/probe-finder.h b/tools/perf/util/probe-finder.h index beaefc3..605730a 100644 --- a/tools/perf/util/probe-finder.h +++ b/tools/perf/util/probe-finder.h @@ -49,6 +49,7 @@ struct probe_finder { Dwarf_Addr addr; /* Address */ const char *fname; /* Real file name */ Dwarf_Die cu_die; /* Current CU */ + Dwarf_Die sp_die; struct list_head lcache; /* Line cache for lazy match */ /* For variable searching */ @@ -83,6 +84,7 @@ struct line_finder { int lno_s; /* Start line number */ int lno_e; /* End line number */ Dwarf_Die cu_die; /* Current CU */ + Dwarf_Die sp_die; int found; }; -- cgit v0.10.2 From a7f3c8f1da1050ad778c3a3930f07c63a5ec570b Mon Sep 17 00:00:00 2001 From: Daniel Kiper Date: Mon, 28 Mar 2011 11:32:31 +0200 Subject: xen/balloon: Use PageHighMem() for high memory page detection Replace pfn < max_low_pfn by !PageHighMem() in increase_reservation(). It makes more clearer what is going on. Acked-by: Ian Campbell Acked-by: Daniel De Graaf Signed-off-by: Daniel Kiper Signed-off-by: Konrad Rzeszutek Wilk diff --git a/drivers/xen/balloon.c b/drivers/xen/balloon.c index 043af8a..61665b2 100644 --- a/drivers/xen/balloon.c +++ b/drivers/xen/balloon.c @@ -246,7 +246,7 @@ static enum bp_state increase_reservation(unsigned long nr_pages) set_phys_to_machine(pfn, frame_list[i]); /* Link back into the page tables if not highmem. */ - if (!xen_hvm_domain() && pfn < max_low_pfn) { + if (!xen_hvm_domain() && !PageHighMem(page)) { int ret; ret = HYPERVISOR_update_va_mapping( (unsigned long)__va(pfn << PAGE_SHIFT), -- cgit v0.10.2 From 4dfe22f5f24345511c378272189b7504d67767fb Mon Sep 17 00:00:00 2001 From: Daniel Kiper Date: Mon, 28 Mar 2011 11:33:18 +0200 Subject: xen/balloon: Simplify HVM integration Simplify HVM integration proposed by Stefano Stabellini in 53d5522cad291a0e93a385e0594b6aea6b54a071. Acked-by: Ian Campbell Acked-by: Daniel De Graaf Signed-off-by: Daniel Kiper Signed-off-by: Konrad Rzeszutek Wilk diff --git a/drivers/xen/balloon.c b/drivers/xen/balloon.c index 61665b2..42a0ba0 100644 --- a/drivers/xen/balloon.c +++ b/drivers/xen/balloon.c @@ -246,7 +246,7 @@ static enum bp_state increase_reservation(unsigned long nr_pages) set_phys_to_machine(pfn, frame_list[i]); /* Link back into the page tables if not highmem. */ - if (!xen_hvm_domain() && !PageHighMem(page)) { + if (xen_pv_domain() && !PageHighMem(page)) { int ret; ret = HYPERVISOR_update_va_mapping( (unsigned long)__va(pfn << PAGE_SHIFT), @@ -293,7 +293,7 @@ static enum bp_state decrease_reservation(unsigned long nr_pages, gfp_t gfp) scrub_page(page); - if (!xen_hvm_domain() && !PageHighMem(page)) { + if (xen_pv_domain() && !PageHighMem(page)) { ret = HYPERVISOR_update_va_mapping( (unsigned long)__va(pfn << PAGE_SHIFT), __pte_ma(0), 0); @@ -429,7 +429,7 @@ EXPORT_SYMBOL(free_xenballooned_pages); static int __init balloon_init(void) { - unsigned long pfn, nr_pages, extra_pfn_end; + unsigned long pfn, extra_pfn_end; struct page *page; if (!xen_domain()) @@ -437,11 +437,7 @@ static int __init balloon_init(void) pr_info("xen/balloon: Initialising balloon driver.\n"); - if (xen_pv_domain()) - nr_pages = xen_start_info->nr_pages; - else - nr_pages = max_pfn; - balloon_stats.current_pages = min(nr_pages, max_pfn); + balloon_stats.current_pages = xen_pv_domain() ? min(xen_start_info->nr_pages, max_pfn) : max_pfn; balloon_stats.target_pages = balloon_stats.current_pages; balloon_stats.balloon_low = 0; balloon_stats.balloon_high = 0; -- cgit v0.10.2 From 83be7e52d46a5b3a9955a38a9597bf1de1851ea7 Mon Sep 17 00:00:00 2001 From: Daniel Kiper Date: Mon, 28 Mar 2011 11:34:10 +0200 Subject: xen/balloon: Clarify credit calculation Move credit calculation to current_target() and rename it to current_credit(). Acked-by: Ian Campbell Acked-by: Daniel De Graaf Signed-off-by: Daniel Kiper Signed-off-by: Konrad Rzeszutek Wilk diff --git a/drivers/xen/balloon.c b/drivers/xen/balloon.c index 42a0ba0..a6d8e59 100644 --- a/drivers/xen/balloon.c +++ b/drivers/xen/balloon.c @@ -193,7 +193,7 @@ static enum bp_state update_schedule(enum bp_state state) return BP_EAGAIN; } -static unsigned long current_target(void) +static long current_credit(void) { unsigned long target = balloon_stats.target_pages; @@ -202,7 +202,7 @@ static unsigned long current_target(void) balloon_stats.balloon_low + balloon_stats.balloon_high); - return target; + return target - balloon_stats.current_pages; } static enum bp_state increase_reservation(unsigned long nr_pages) @@ -337,7 +337,7 @@ static void balloon_process(struct work_struct *work) mutex_lock(&balloon_mutex); do { - credit = current_target() - balloon_stats.current_pages; + credit = current_credit(); if (credit > 0) state = increase_reservation(credit); @@ -420,7 +420,7 @@ void free_xenballooned_pages(int nr_pages, struct page** pages) } /* The balloon may be too large now. Shrink it if needed. */ - if (current_target() != balloon_stats.current_pages) + if (current_credit()) schedule_delayed_work(&balloon_worker, 0); mutex_unlock(&balloon_mutex); -- cgit v0.10.2 From 09ca132a8e469f87504899b4016c7517511887d0 Mon Sep 17 00:00:00 2001 From: Daniel Kiper Date: Mon, 28 Mar 2011 11:35:59 +0200 Subject: xen/balloon: Move dec_totalhigh_pages() from __balloon_append() to balloon_append() git commit 9be4d4575906af9698de660e477f949a076c87e1 (xen: add extra pages to balloon) splited balloon_append() into two functions (balloon_append() and __balloon_append()) and left decrementation of totalram_pages counter in __balloon_append(). In this situation if __balloon_append() is called on i386 with highmem page referenced then totalhigh_pages is decremented, however, it should not. This patch corrects that issue and moves dec_totalhigh_pages() from __balloon_append() to balloon_append(). Now totalram_pages and totalhigh_pages are decremented simultaneously only when balloon_append() is called. Acked-by: Ian Campbell Acked-by: Daniel De Graaf Signed-off-by: Daniel Kiper Signed-off-by: Konrad Rzeszutek Wilk diff --git a/drivers/xen/balloon.c b/drivers/xen/balloon.c index a6d8e59..f54290b 100644 --- a/drivers/xen/balloon.c +++ b/drivers/xen/balloon.c @@ -114,7 +114,6 @@ static void __balloon_append(struct page *page) if (PageHighMem(page)) { list_add_tail(&page->lru, &ballooned_pages); balloon_stats.balloon_high++; - dec_totalhigh_pages(); } else { list_add(&page->lru, &ballooned_pages); balloon_stats.balloon_low++; @@ -124,6 +123,8 @@ static void __balloon_append(struct page *page) static void balloon_append(struct page *page) { __balloon_append(page); + if (PageHighMem(page)) + dec_totalhigh_pages(); totalram_pages--; } @@ -462,7 +463,7 @@ static int __init balloon_init(void) pfn < extra_pfn_end; pfn++) { page = pfn_to_page(pfn); - /* totalram_pages doesn't include the boot-time + /* totalram_pages and totalhigh_pages do not include the boot-time balloon extension, so don't subtract from it. */ __balloon_append(page); } -- cgit v0.10.2 From 2c9e45f7a287384e1382932597e41a9a567811ba Mon Sep 17 00:00:00 2001 From: David Ahern Date: Thu, 17 Mar 2011 10:03:21 -0600 Subject: perf script: If type not given fields apply to all event types Allow: perf script -f to be equivalent to: perf script -f trace: -f sw: -f hw: i.e., the specified fields apply to all event types if the type string is not given. The field (-f) arguments are processed in the order received. A later usage can reset a prior request. e.g., -f trace: -f comm,tid,time,sym The first -f suppresses trace events (field list is ""), but then the second invocation sets the fields to comm,tid,time,sym. In this case a warning is given to the user: "Overriding previous field request for all events." Alternativey, consider the order: -f comm,tid,time,sym -f trace: The first -f sets the fields for all events and the second -f suppresses trace events. The user is given a warning message about the override, and the result of the above is that only S/W and H/W events are displayed with the given fields. For the 'wildcard' option if a user selected field is invalid for an event type, a message is displayed to the user that the option is ignored for that type. For example: perf script -f comm,tid,trace 2>&1 | less 'trace' not valid for hardware events. Ignoring. 'trace' not valid for software events. Ignoring. Alternatively, if the type is given an invalid field is specified it is an error. For example: perf script -v -f sw:comm,tid,trace 2>&1 | less 'trace' not valid for software events. At this point usage is displayed, and perf-script exits. Finally, a user may not set fields to none for all event types. i.e., -f "" is not allowed. Cc: Frederic Weisbecker Cc: Ingo Molnar Cc: Paul Mackerras Cc: Peter Zijlstra Cc: linux-kernel@vger.kernel.org LPU-Reference: <1300377801-27246-1-git-send-email-daahern@cisco.com> Signed-off-by: David Ahern Signed-off-by: Arnaldo Carvalho de Melo diff --git a/tools/perf/builtin-script.c b/tools/perf/builtin-script.c index ac574ea..6cf811a 100644 --- a/tools/perf/builtin-script.c +++ b/tools/perf/builtin-script.c @@ -49,23 +49,52 @@ struct output_option { }; /* default set to maintain compatibility with current format */ -static u64 output_fields[PERF_TYPE_MAX] = { - [PERF_TYPE_HARDWARE] = PERF_OUTPUT_COMM | PERF_OUTPUT_TID | \ - PERF_OUTPUT_CPU | PERF_OUTPUT_TIME | \ - PERF_OUTPUT_EVNAME | PERF_OUTPUT_SYM, - - [PERF_TYPE_SOFTWARE] = PERF_OUTPUT_COMM | PERF_OUTPUT_TID | \ - PERF_OUTPUT_CPU | PERF_OUTPUT_TIME | \ - PERF_OUTPUT_EVNAME | PERF_OUTPUT_SYM, - - [PERF_TYPE_TRACEPOINT] = PERF_OUTPUT_COMM | PERF_OUTPUT_TID | \ - PERF_OUTPUT_CPU | PERF_OUTPUT_TIME | \ - PERF_OUTPUT_EVNAME | PERF_OUTPUT_TRACE, +static struct { + bool user_set; + u64 fields; + u64 invalid_fields; +} output[PERF_TYPE_MAX] = { + + [PERF_TYPE_HARDWARE] = { + .user_set = false, + + .fields = PERF_OUTPUT_COMM | PERF_OUTPUT_TID | + PERF_OUTPUT_CPU | PERF_OUTPUT_TIME | + PERF_OUTPUT_EVNAME | PERF_OUTPUT_SYM, + + .invalid_fields = PERF_OUTPUT_TRACE, + }, + + [PERF_TYPE_SOFTWARE] = { + .user_set = false, + + .fields = PERF_OUTPUT_COMM | PERF_OUTPUT_TID | + PERF_OUTPUT_CPU | PERF_OUTPUT_TIME | + PERF_OUTPUT_EVNAME | PERF_OUTPUT_SYM, + + .invalid_fields = PERF_OUTPUT_TRACE, + }, + + [PERF_TYPE_TRACEPOINT] = { + .user_set = false, + + .fields = PERF_OUTPUT_COMM | PERF_OUTPUT_TID | + PERF_OUTPUT_CPU | PERF_OUTPUT_TIME | + PERF_OUTPUT_EVNAME | PERF_OUTPUT_TRACE, + }, }; -static bool output_set_by_user; +static bool output_set_by_user(void) +{ + int j; + for (j = 0; j < PERF_TYPE_MAX; ++j) { + if (output[j].user_set) + return true; + } + return false; +} -#define PRINT_FIELD(x) (output_fields[attr->type] & PERF_OUTPUT_##x) +#define PRINT_FIELD(x) (output[attr->type].fields & PERF_OUTPUT_##x) static int perf_session__check_attr(struct perf_session *session, struct perf_event_attr *attr) @@ -168,7 +197,7 @@ static void process_event(union perf_event *event __unused, { struct perf_event_attr *attr = &evsel->attr; - if (output_fields[attr->type] == 0) + if (output[attr->type].fields == 0) return; if (perf_session__check_attr(session, attr) < 0) @@ -451,6 +480,7 @@ static int parse_output_fields(const struct option *opt __used, { char *tok; int i, imax = sizeof(all_output_options) / sizeof(struct output_option); + int j; int rc = 0; char *str = strdup(arg); int type = -1; @@ -458,52 +488,95 @@ static int parse_output_fields(const struct option *opt __used, if (!str) return -ENOMEM; - tok = strtok(str, ":"); - if (!tok) { - fprintf(stderr, - "Invalid field string - not prepended with type."); - return -EINVAL; - } - - /* first word should state which event type user - * is specifying the fields + /* first word can state for which event type the user is specifying + * the fields. If no type exists, the specified fields apply to all + * event types found in the file minus the invalid fields for a type. */ - if (!strcmp(tok, "hw")) - type = PERF_TYPE_HARDWARE; - else if (!strcmp(tok, "sw")) - type = PERF_TYPE_SOFTWARE; - else if (!strcmp(tok, "trace")) - type = PERF_TYPE_TRACEPOINT; - else { - fprintf(stderr, "Invalid event type in field string."); - return -EINVAL; + tok = strchr(str, ':'); + if (tok) { + *tok = '\0'; + tok++; + if (!strcmp(str, "hw")) + type = PERF_TYPE_HARDWARE; + else if (!strcmp(str, "sw")) + type = PERF_TYPE_SOFTWARE; + else if (!strcmp(str, "trace")) + type = PERF_TYPE_TRACEPOINT; + else { + fprintf(stderr, "Invalid event type in field string.\n"); + return -EINVAL; + } + + if (output[type].user_set) + pr_warning("Overriding previous field request for %s events.\n", + event_type(type)); + + output[type].fields = 0; + output[type].user_set = true; + + } else { + tok = str; + if (strlen(str) == 0) { + fprintf(stderr, + "Cannot set fields to 'none' for all event types.\n"); + rc = -EINVAL; + goto out; + } + + if (output_set_by_user()) + pr_warning("Overriding previous field request for all events.\n"); + + for (j = 0; j < PERF_TYPE_MAX; ++j) { + output[j].fields = 0; + output[j].user_set = true; + } } - output_fields[type] = 0; - while (1) { - tok = strtok(NULL, ","); - if (!tok) - break; + tok = strtok(tok, ","); + while (tok) { for (i = 0; i < imax; ++i) { - if (strcmp(tok, all_output_options[i].str) == 0) { - output_fields[type] |= all_output_options[i].field; + if (strcmp(tok, all_output_options[i].str) == 0) break; - } } if (i == imax) { - fprintf(stderr, "Invalid field requested."); + fprintf(stderr, "Invalid field requested.\n"); rc = -EINVAL; - break; + goto out; } - } - if (output_fields[type] == 0) { - pr_debug("No fields requested for %s type. " - "Events will not be displayed\n", event_type(type)); + if (type == -1) { + /* add user option to all events types for + * which it is valid + */ + for (j = 0; j < PERF_TYPE_MAX; ++j) { + if (output[j].invalid_fields & all_output_options[i].field) { + pr_warning("\'%s\' not valid for %s events. Ignoring.\n", + all_output_options[i].str, event_type(j)); + } else + output[j].fields |= all_output_options[i].field; + } + } else { + if (output[type].invalid_fields & all_output_options[i].field) { + fprintf(stderr, "\'%s\' not valid for %s events.\n", + all_output_options[i].str, event_type(type)); + + rc = -EINVAL; + goto out; + } + output[type].fields |= all_output_options[i].field; + } + + tok = strtok(NULL, ","); } - output_set_by_user = true; + if (type >= 0) { + if (output[type].fields == 0) { + pr_debug("No fields requested for %s type. " + "Events will not be displayed.\n", event_type(type)); + } + } +out: free(str); return rc; } @@ -1020,7 +1093,7 @@ int cmd_script(int argc, const char **argv, const char *prefix __used) struct stat perf_stat; int input; - if (output_set_by_user) { + if (output_set_by_user()) { fprintf(stderr, "custom fields not supported for generated scripts"); return -1; -- cgit v0.10.2 From 22dd2fd283ea96b4d45185d3e861ef46005082f4 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Tue, 15 Mar 2011 10:03:24 +0300 Subject: iwlwifi: remove duplicate initialization in __iwl_down() We initialize exit_pending twice. It's the second initialization which is correct. That was added in d745d472af "iwlwifi: cancel scan when down the device". Signed-off-by: Dan Carpenter Acked-by: Wey-Yi Guy Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index 321b18b..7adc60e 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -2537,7 +2537,7 @@ static void iwl_cancel_deferred_work(struct iwl_priv *priv); static void __iwl_down(struct iwl_priv *priv) { unsigned long flags; - int exit_pending = test_bit(STATUS_EXIT_PENDING, &priv->status); + int exit_pending; IWL_DEBUG_INFO(priv, DRV_NAME " is going down\n"); -- cgit v0.10.2 From 6d64ab7f9240e3201fde3fd16ce4227bd795d2ab Mon Sep 17 00:00:00 2001 From: Rajkumar Manoharan Date: Tue, 15 Mar 2011 19:55:35 +0530 Subject: ath9k_htc: Fix LED pin for AR9287 HTC device Signed-off-by: Rajkumar Manoharan Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/htc.h b/drivers/net/wireless/ath/ath9k/htc.h index 753a245..ec47be9 100644 --- a/drivers/net/wireless/ath/ath9k/htc.h +++ b/drivers/net/wireless/ath/ath9k/htc.h @@ -328,7 +328,7 @@ struct ath9k_debug { #endif /* CONFIG_ATH9K_HTC_DEBUGFS */ #define ATH_LED_PIN_DEF 1 -#define ATH_LED_PIN_9287 8 +#define ATH_LED_PIN_9287 10 #define ATH_LED_PIN_9271 15 #define ATH_LED_PIN_7010 12 #define ATH_LED_ON_DURATION_IDLE 350 /* in msecs */ -- cgit v0.10.2 From 81544026e4cecb85a8b727d5f64cb3c8a8cb64a3 Mon Sep 17 00:00:00 2001 From: Rajkumar Manoharan Date: Tue, 15 Mar 2011 19:55:36 +0530 Subject: ath9k_hw: Fix throughput drops in HT40 mode for AR9287 chips Doing adc gain calibration for AR9287 chips is causing throughput drops in HT40 mode. Remove ADC Gain from supported calibration list. Signed-off-by: Rajkumar Manoharan Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/ar9002_calib.c b/drivers/net/wireless/ath/ath9k/ar9002_calib.c index 76388c6..cb611b2 100644 --- a/drivers/net/wireless/ath/ath9k/ar9002_calib.c +++ b/drivers/net/wireless/ath/ath9k/ar9002_calib.c @@ -26,6 +26,27 @@ enum ar9002_cal_types { IQ_MISMATCH_CAL = BIT(2), }; +static bool ar9002_hw_is_cal_supported(struct ath_hw *ah, + struct ath9k_channel *chan, + enum ar9002_cal_types cal_type) +{ + bool supported = false; + switch (ah->supp_cals & cal_type) { + case IQ_MISMATCH_CAL: + /* Run IQ Mismatch for non-CCK only */ + if (!IS_CHAN_B(chan)) + supported = true; + break; + case ADC_GAIN_CAL: + case ADC_DC_CAL: + /* Run ADC Gain Cal for non-CCK & non 2GHz-HT20 only */ + if (!IS_CHAN_B(chan) && + !(IS_CHAN_2GHZ(chan) && IS_CHAN_HT20(chan))) + supported = true; + break; + } + return supported; +} static void ar9002_hw_setup_calibration(struct ath_hw *ah, struct ath9k_cal_list *currCal) @@ -858,26 +879,32 @@ static bool ar9002_hw_init_cal(struct ath_hw *ah, struct ath9k_channel *chan) if (AR_SREV_9100(ah) || AR_SREV_9160_10_OR_LATER(ah)) { ah->supp_cals = IQ_MISMATCH_CAL; - if (AR_SREV_9160_10_OR_LATER(ah) && - !(IS_CHAN_2GHZ(chan) && IS_CHAN_HT20(chan))) { + if (AR_SREV_9160_10_OR_LATER(ah)) ah->supp_cals |= ADC_GAIN_CAL | ADC_DC_CAL; + if (AR_SREV_9287(ah)) + ah->supp_cals &= ~ADC_GAIN_CAL; + if (ar9002_hw_is_cal_supported(ah, chan, ADC_GAIN_CAL)) { INIT_CAL(&ah->adcgain_caldata); INSERT_CAL(ah, &ah->adcgain_caldata); ath_dbg(common, ATH_DBG_CALIBRATE, - "enabling ADC Gain Calibration.\n"); + "enabling ADC Gain Calibration.\n"); + } + if (ar9002_hw_is_cal_supported(ah, chan, ADC_DC_CAL)) { INIT_CAL(&ah->adcdc_caldata); INSERT_CAL(ah, &ah->adcdc_caldata); ath_dbg(common, ATH_DBG_CALIBRATE, - "enabling ADC DC Calibration.\n"); + "enabling ADC DC Calibration.\n"); } - INIT_CAL(&ah->iq_caldata); - INSERT_CAL(ah, &ah->iq_caldata); - ath_dbg(common, ATH_DBG_CALIBRATE, - "enabling IQ Calibration.\n"); + if (ar9002_hw_is_cal_supported(ah, chan, IQ_MISMATCH_CAL)) { + INIT_CAL(&ah->iq_caldata); + INSERT_CAL(ah, &ah->iq_caldata); + ath_dbg(common, ATH_DBG_CALIBRATE, + "enabling IQ Calibration.\n"); + } ah->cal_list_curr = ah->cal_list; -- cgit v0.10.2 From b0a9ede228175c25f76314a028d305fd5b2de427 Mon Sep 17 00:00:00 2001 From: Rajkumar Manoharan Date: Tue, 15 Mar 2011 19:55:38 +0530 Subject: ath: Speedup key set/reset ops for HTC driver By enabling buffered register write for ath9k_htc driver avoids unnecessary dissociation while rekeying phase under heavy traffic exchange. Signed-off-by: Rajkumar Manoharan Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/key.c b/drivers/net/wireless/ath/key.c index 37b8e11..0d4f39c 100644 --- a/drivers/net/wireless/ath/key.c +++ b/drivers/net/wireless/ath/key.c @@ -23,6 +23,14 @@ #define REG_READ (common->ops->read) #define REG_WRITE(_ah, _reg, _val) (common->ops->write)(_ah, _val, _reg) +#define ENABLE_REGWRITE_BUFFER(_ah) \ + if (common->ops->enable_write_buffer) \ + common->ops->enable_write_buffer((_ah)); + +#define REGWRITE_BUFFER_FLUSH(_ah) \ + if (common->ops->write_flush) \ + common->ops->write_flush((_ah)); + #define IEEE80211_WEP_NKID 4 /* number of key ids */ @@ -42,6 +50,8 @@ bool ath_hw_keyreset(struct ath_common *common, u16 entry) keyType = REG_READ(ah, AR_KEYTABLE_TYPE(entry)); + ENABLE_REGWRITE_BUFFER(ah); + REG_WRITE(ah, AR_KEYTABLE_KEY0(entry), 0); REG_WRITE(ah, AR_KEYTABLE_KEY1(entry), 0); REG_WRITE(ah, AR_KEYTABLE_KEY2(entry), 0); @@ -66,6 +76,8 @@ bool ath_hw_keyreset(struct ath_common *common, u16 entry) } + REGWRITE_BUFFER_FLUSH(ah); + return true; } EXPORT_SYMBOL(ath_hw_keyreset); @@ -104,9 +116,13 @@ static bool ath_hw_keysetmac(struct ath_common *common, } else { macLo = macHi = 0; } + ENABLE_REGWRITE_BUFFER(ah); + REG_WRITE(ah, AR_KEYTABLE_MAC0(entry), macLo); REG_WRITE(ah, AR_KEYTABLE_MAC1(entry), macHi | unicast_flag); + REGWRITE_BUFFER_FLUSH(ah); + return true; } @@ -223,6 +239,8 @@ static bool ath_hw_set_keycache_entry(struct ath_common *common, u16 entry, mic3 = get_unaligned_le16(k->kv_txmic + 0) & 0xffff; mic4 = get_unaligned_le32(k->kv_txmic + 4); + ENABLE_REGWRITE_BUFFER(ah); + /* Write RX[31:0] and TX[31:16] */ REG_WRITE(ah, AR_KEYTABLE_KEY0(micentry), mic0); REG_WRITE(ah, AR_KEYTABLE_KEY1(micentry), mic1); @@ -236,6 +254,8 @@ static bool ath_hw_set_keycache_entry(struct ath_common *common, u16 entry, REG_WRITE(ah, AR_KEYTABLE_TYPE(micentry), AR_KEYTABLE_TYPE_CLR); + REGWRITE_BUFFER_FLUSH(ah); + } else { /* * TKIP uses four key cache entries (two for group @@ -258,6 +278,8 @@ static bool ath_hw_set_keycache_entry(struct ath_common *common, u16 entry, mic0 = get_unaligned_le32(k->kv_mic + 0); mic2 = get_unaligned_le32(k->kv_mic + 4); + ENABLE_REGWRITE_BUFFER(ah); + /* Write MIC key[31:0] */ REG_WRITE(ah, AR_KEYTABLE_KEY0(micentry), mic0); REG_WRITE(ah, AR_KEYTABLE_KEY1(micentry), 0); @@ -270,8 +292,12 @@ static bool ath_hw_set_keycache_entry(struct ath_common *common, u16 entry, REG_WRITE(ah, AR_KEYTABLE_KEY4(micentry), 0); REG_WRITE(ah, AR_KEYTABLE_TYPE(micentry), AR_KEYTABLE_TYPE_CLR); + + REGWRITE_BUFFER_FLUSH(ah); } + ENABLE_REGWRITE_BUFFER(ah); + /* MAC address registers are reserved for the MIC entry */ REG_WRITE(ah, AR_KEYTABLE_MAC0(micentry), 0); REG_WRITE(ah, AR_KEYTABLE_MAC1(micentry), 0); @@ -283,7 +309,11 @@ static bool ath_hw_set_keycache_entry(struct ath_common *common, u16 entry, */ REG_WRITE(ah, AR_KEYTABLE_KEY0(entry), key0); REG_WRITE(ah, AR_KEYTABLE_KEY1(entry), key1); + + REGWRITE_BUFFER_FLUSH(ah); } else { + ENABLE_REGWRITE_BUFFER(ah); + /* Write key[47:0] */ REG_WRITE(ah, AR_KEYTABLE_KEY0(entry), key0); REG_WRITE(ah, AR_KEYTABLE_KEY1(entry), key1); @@ -296,6 +326,8 @@ static bool ath_hw_set_keycache_entry(struct ath_common *common, u16 entry, REG_WRITE(ah, AR_KEYTABLE_KEY4(entry), key4); REG_WRITE(ah, AR_KEYTABLE_TYPE(entry), keyType); + REGWRITE_BUFFER_FLUSH(ah); + /* Write MAC address for the entry */ (void) ath_hw_keysetmac(common, entry, mac); } -- cgit v0.10.2 From e7fc63388def06d2d1bdb6916748c92c037a42c6 Mon Sep 17 00:00:00 2001 From: Rajkumar Manoharan Date: Tue, 15 Mar 2011 23:11:35 +0530 Subject: ath9k_hw: Speedup register ops for HTC driver Fine-tuning register write operation and avoid unnecessay delays for ath9k_htc driver, saves hw reset time which improves scanning time and also solves one of the following scenario. Sometimes the ACK is sent by STA for assoc response is not seen at AP side. So the AP continues to send retry assoc responses. At the STA side, since the assoc response was already forwarded to mac80211, it proceeded to channel change which in turns does chip reset. In most of the cases the chip reset was completed before max retries are reached at AP side. Hence STA can able to ACK the retried frames again. But in clear environment these retries are completed within shortspan of time. Since ath9k_htc consumes more time for hw reset, this latency is causing dissociation by AP due to max reties are reached. This issue was originally reported with Cisco Aironet 1250 AP in HT40 mode in noise free environment. Signed-off-by: Rajkumar Manoharan Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/ar5008_phy.c b/drivers/net/wireless/ath/ath9k/ar5008_phy.c index ffcf44a..94acce5 100644 --- a/drivers/net/wireless/ath/ath9k/ar5008_phy.c +++ b/drivers/net/wireless/ath/ath9k/ar5008_phy.c @@ -729,6 +729,7 @@ static int ar5008_hw_process_ini(struct ath_hw *ah, struct ath9k_channel *chan) { struct ath_regulatory *regulatory = ath9k_hw_regulatory(ah); + struct ath_common *common = ath9k_hw_common(ah); int i, regWrites = 0; struct ieee80211_channel *channel = chan->chan; u32 modesIndex, freqIndex; @@ -805,7 +806,8 @@ static int ar5008_hw_process_ini(struct ath_hw *ah, REG_WRITE(ah, reg, val); if (reg >= 0x7800 && reg < 0x78a0 - && ah->config.analog_shiftreg) { + && ah->config.analog_shiftreg + && (common->bus_ops->ath_bus_type != ATH_USB)) { udelay(100); } @@ -835,7 +837,8 @@ static int ar5008_hw_process_ini(struct ath_hw *ah, REG_WRITE(ah, reg, val); if (reg >= 0x7800 && reg < 0x78a0 - && ah->config.analog_shiftreg) { + && ah->config.analog_shiftreg + && (common->bus_ops->ath_bus_type != ATH_USB)) { udelay(100); } diff --git a/drivers/net/wireless/ath/ath9k/eeprom_9287.c b/drivers/net/wireless/ath/ath9k/eeprom_9287.c index 8cd8333..2f0712e 100644 --- a/drivers/net/wireless/ath/ath9k/eeprom_9287.c +++ b/drivers/net/wireless/ath/ath9k/eeprom_9287.c @@ -392,6 +392,8 @@ static void ath9k_hw_set_ar9287_power_cal_table(struct ath_hw *ah, numXpdGain); } + ENABLE_REGWRITE_BUFFER(ah); + if (i == 0) { if (!ath9k_hw_ar9287_get_eeprom(ah, EEP_OL_PWRCTRL)) { @@ -442,6 +444,7 @@ static void ath9k_hw_set_ar9287_power_cal_table(struct ath_hw *ah, regOffset += 4; } } + REGWRITE_BUFFER_FLUSH(ah); } } @@ -757,6 +760,8 @@ static void ath9k_hw_ar9287_set_txpower(struct ath_hw *ah, ratesArray[i] -= AR9287_PWR_TABLE_OFFSET_DB * 2; } + ENABLE_REGWRITE_BUFFER(ah); + /* OFDM power per rate */ REG_WRITE(ah, AR_PHY_POWER_TX_RATE1, ATH9K_POW_SM(ratesArray[rate18mb], 24) @@ -840,6 +845,7 @@ static void ath9k_hw_ar9287_set_txpower(struct ath_hw *ah, | ATH9K_POW_SM(ratesArray[rateDupOfdm], 8) | ATH9K_POW_SM(ratesArray[rateDupCck], 0)); } + REGWRITE_BUFFER_FLUSH(ah); } static void ath9k_hw_ar9287_set_addac(struct ath_hw *ah, diff --git a/drivers/net/wireless/ath/ath9k/eeprom_def.c b/drivers/net/wireless/ath/ath9k/eeprom_def.c index fccd87d..995949d 100644 --- a/drivers/net/wireless/ath/ath9k/eeprom_def.c +++ b/drivers/net/wireless/ath/ath9k/eeprom_def.c @@ -799,6 +799,8 @@ static void ath9k_hw_set_def_power_cal_table(struct ath_hw *ah, pwr_table_offset, &diff); + ENABLE_REGWRITE_BUFFER(ah); + if ((i == 0) || AR_SREV_5416_20_OR_LATER(ah)) { if (OLC_FOR_AR9280_20_LATER) { REG_WRITE(ah, @@ -847,6 +849,7 @@ static void ath9k_hw_set_def_power_cal_table(struct ath_hw *ah, regOffset += 4; } + REGWRITE_BUFFER_FLUSH(ah); } } @@ -1205,6 +1208,8 @@ static void ath9k_hw_def_set_txpower(struct ath_hw *ah, } } + ENABLE_REGWRITE_BUFFER(ah); + REG_WRITE(ah, AR_PHY_POWER_TX_RATE1, ATH9K_POW_SM(ratesArray[rate18mb], 24) | ATH9K_POW_SM(ratesArray[rate12mb], 16) @@ -1291,6 +1296,8 @@ static void ath9k_hw_def_set_txpower(struct ath_hw *ah, REG_WRITE(ah, AR_PHY_POWER_TX_SUB, ATH9K_POW_SM(pModal->pwrDecreaseFor3Chain, 6) | ATH9K_POW_SM(pModal->pwrDecreaseFor2Chain, 0)); + + REGWRITE_BUFFER_FLUSH(ah); } static u16 ath9k_hw_def_get_spur_channel(struct ath_hw *ah, u16 i, bool is2GHz) diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h index 6650fd4..c86eea2 100644 --- a/drivers/net/wireless/ath/ath9k/hw.h +++ b/drivers/net/wireless/ath/ath9k/hw.h @@ -99,18 +99,22 @@ #define REG_CLR_BIT(_a, _r, _f) \ REG_WRITE(_a, _r, REG_READ(_a, _r) & ~(_f)) -#define DO_DELAY(x) do { \ - if ((++(x) % 64) == 0) \ - udelay(1); \ +#define DO_DELAY(x) do { \ + if (((++(x) % 64) == 0) && \ + (ath9k_hw_common(ah)->bus_ops->ath_bus_type \ + != ATH_USB)) \ + udelay(1); \ } while (0) #define REG_WRITE_ARRAY(iniarray, column, regWr) do { \ int r; \ + ENABLE_REGWRITE_BUFFER(ah); \ for (r = 0; r < ((iniarray)->ia_rows); r++) { \ REG_WRITE(ah, INI_RA((iniarray), (r), 0), \ INI_RA((iniarray), r, (column))); \ DO_DELAY(regWr); \ } \ + REGWRITE_BUFFER_FLUSH(ah); \ } while (0) #define AR_GPIO_OUTPUT_MUX_AS_OUTPUT 0 diff --git a/drivers/net/wireless/ath/ath9k/phy.h b/drivers/net/wireless/ath/ath9k/phy.h index 5e3d749..e4029325 100644 --- a/drivers/net/wireless/ath/ath9k/phy.h +++ b/drivers/net/wireless/ath/ath9k/phy.h @@ -40,10 +40,12 @@ #define REG_WRITE_RF_ARRAY(iniarray, regData, regWr) do { \ int r; \ + ENABLE_REGWRITE_BUFFER(ah); \ for (r = 0; r < ((iniarray)->ia_rows); r++) { \ REG_WRITE(ah, INI_RA((iniarray), r, 0), (regData)[r]); \ DO_DELAY(regWr); \ } \ + REGWRITE_BUFFER_FLUSH(ah); \ } while (0) #define ANTSWAP_AB 0x0001 -- cgit v0.10.2 From c835b21405fa551cd5af2c7bfe1c3ae129c5f8ef Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 15 Mar 2011 23:17:01 +0100 Subject: mac80211: add comment about reordering Took me a minute to figure this out, maybe it's better documented... Signed-off-by: Johannes Berg Signed-off-by: John W. Linville diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index 5c1930ba..82414a6 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -706,6 +706,8 @@ static bool ieee80211_sta_manage_reorder_buf(struct ieee80211_hw *hw, /* * If the current MPDU is in the right order and nothing else * is stored we can process it directly, no need to buffer it. + * If it is first but there's something stored, we may be able + * to release frames after this one. */ if (mpdu_seq_num == tid_agg_rx->head_seq_num && tid_agg_rx->stored_mpdu_num == 0) { -- cgit v0.10.2 From 73b46320209e9fe0d65aba1b8c21489278047574 Mon Sep 17 00:00:00 2001 From: Brian Cavagnolo Date: Thu, 17 Mar 2011 11:58:41 -0700 Subject: mwl8k: refactor in preparation for APIv2 update Specifically, APIv2 will specify a variable number of AMPDU queues in the MWL8K_CMD_GET_HW_SPEC. So init the tx queues after MWL8K_CMD_GET_HW_SPEC for ap fw. Also, we make it safe to deinit queues that have not been init'd. This happens if the mwl8k_get_hw_spec_ap routine fails, for example. Signed-off-by: Nishant Sarmukadam Signed-off-by: Brian Cavagnolo Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c index 3695227..8fefed2 100644 --- a/drivers/net/wireless/mwl8k.c +++ b/drivers/net/wireless/mwl8k.c @@ -191,6 +191,7 @@ struct mwl8k_priv { struct mwl8k_rx_queue rxq[MWL8K_RX_QUEUES]; struct mwl8k_tx_queue txq[MWL8K_TX_QUEUES]; + u32 txq_offset[MWL8K_TX_QUEUES]; bool radio_on; bool radio_short_preamble; @@ -1126,6 +1127,9 @@ static void mwl8k_rxq_deinit(struct ieee80211_hw *hw, int index) struct mwl8k_rx_queue *rxq = priv->rxq + index; int i; + if (rxq->rxd == NULL) + return; + for (i = 0; i < MWL8K_RX_DESCS; i++) { if (rxq->buf[i].skb != NULL) { pci_unmap_single(priv->pdev, @@ -1560,6 +1564,9 @@ static void mwl8k_txq_deinit(struct ieee80211_hw *hw, int index) struct mwl8k_priv *priv = hw->priv; struct mwl8k_tx_queue *txq = priv->txq + index; + if (txq->txd == NULL) + return; + mwl8k_txq_reclaim(hw, index, INT_MAX, 1); kfree(txq->skb); @@ -2058,23 +2065,16 @@ static int mwl8k_cmd_get_hw_spec_ap(struct ieee80211_hw *hw) priv->ap_macids_supported = 0x000000ff; priv->sta_macids_supported = 0x00000000; - off = le32_to_cpu(cmd->wcbbase0) & 0xffff; - iowrite32(priv->txq[0].txd_dma, priv->sram + off); - off = le32_to_cpu(cmd->rxwrptr) & 0xffff; iowrite32(priv->rxq[0].rxd_dma, priv->sram + off); off = le32_to_cpu(cmd->rxrdptr) & 0xffff; iowrite32(priv->rxq[0].rxd_dma, priv->sram + off); - off = le32_to_cpu(cmd->wcbbase1) & 0xffff; - iowrite32(priv->txq[1].txd_dma, priv->sram + off); - - off = le32_to_cpu(cmd->wcbbase2) & 0xffff; - iowrite32(priv->txq[2].txd_dma, priv->sram + off); - - off = le32_to_cpu(cmd->wcbbase3) & 0xffff; - iowrite32(priv->txq[3].txd_dma, priv->sram + off); + priv->txq_offset[0] = le32_to_cpu(cmd->wcbbase0) & 0xffff; + priv->txq_offset[1] = le32_to_cpu(cmd->wcbbase1) & 0xffff; + priv->txq_offset[2] = le32_to_cpu(cmd->wcbbase2) & 0xffff; + priv->txq_offset[3] = le32_to_cpu(cmd->wcbbase3) & 0xffff; } done: @@ -4600,6 +4600,23 @@ static int mwl8k_init_firmware(struct ieee80211_hw *hw, char *fw_image, return rc; } +static int mwl8k_init_txqs(struct ieee80211_hw *hw) +{ + struct mwl8k_priv *priv = hw->priv; + int rc = 0; + int i; + + for (i = 0; i < MWL8K_TX_QUEUES; i++) { + rc = mwl8k_txq_init(hw, i); + if (rc) + break; + if (priv->ap_fw) + iowrite32(priv->txq[i].txd_dma, + priv->sram + priv->txq_offset[i]); + } + return rc; +} + /* initialize hw after successfully loading a firmware image */ static int mwl8k_probe_hw(struct ieee80211_hw *hw) { @@ -4627,8 +4644,14 @@ static int mwl8k_probe_hw(struct ieee80211_hw *hw) goto err_stop_firmware; rxq_refill(hw, 0, INT_MAX); - for (i = 0; i < MWL8K_TX_QUEUES; i++) { - rc = mwl8k_txq_init(hw, i); + /* For the sta firmware, we need to know the dma addresses of tx queues + * before sending MWL8K_CMD_GET_HW_SPEC. So we must initialize them + * prior to issuing this command. But for the AP case, we learn the + * total number of queues from the result CMD_GET_HW_SPEC, so for this + * case we must initialize the tx queues after. + */ + if (!priv->ap_fw) { + rc = mwl8k_init_txqs(hw); if (rc) goto err_free_queues; } @@ -4657,6 +4680,8 @@ static int mwl8k_probe_hw(struct ieee80211_hw *hw) if (priv->ap_fw) { rc = mwl8k_cmd_get_hw_spec_ap(hw); if (!rc) + rc = mwl8k_init_txqs(hw); + if (!rc) rc = mwl8k_cmd_set_hw_spec(hw); } else { rc = mwl8k_cmd_get_hw_spec_sta(hw); -- cgit v0.10.2 From 8a7a578c2e3ac463a17fe30b11ada0509658a952 Mon Sep 17 00:00:00 2001 From: Brian Cavagnolo Date: Thu, 17 Mar 2011 11:58:42 -0700 Subject: mwl8k: update to ap firmware API version 2 Firmware APIv2 adds the following enhancements: -- capabilities are reported by the firmware -- API supports up to 8 dedicated AMPDU streams -- optional packet timestamping and expiration can be enabled. Specifically, packets that are queued in firmware for longer than 500ms will be dropped if this option is used. Based on work by "Nishant Sarmukadam" Signed-off-by: Brian Cavagnolo Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c index 8fefed2..9db66d5 100644 --- a/drivers/net/wireless/mwl8k.c +++ b/drivers/net/wireless/mwl8k.c @@ -86,6 +86,7 @@ MODULE_PARM_DESC(ap_mode_default, #define MWL8K_RX_QUEUES 1 #define MWL8K_TX_QUEUES 4 +#define MWL8K_MAX_AMPDU_QUEUES 8 struct rxd_ops { int rxd_size; @@ -159,6 +160,9 @@ struct mwl8k_priv { u32 ap_macids_supported; u32 sta_macids_supported; + /* Ampdu stream information */ + u8 num_ampdu_queues; + /* firmware access */ struct mutex fw_mutex; struct task_struct *fw_mutex_owner; @@ -190,8 +194,8 @@ struct mwl8k_priv { int pending_tx_pkts; struct mwl8k_rx_queue rxq[MWL8K_RX_QUEUES]; - struct mwl8k_tx_queue txq[MWL8K_TX_QUEUES]; - u32 txq_offset[MWL8K_TX_QUEUES]; + struct mwl8k_tx_queue txq[MWL8K_TX_QUEUES + MWL8K_MAX_AMPDU_QUEUES]; + u32 txq_offset[MWL8K_TX_QUEUES + MWL8K_MAX_AMPDU_QUEUES]; bool radio_on; bool radio_short_preamble; @@ -1322,7 +1326,7 @@ struct mwl8k_tx_desc { __le16 pkt_len; __u8 dest_MAC_addr[ETH_ALEN]; __le32 next_txd_phys_addr; - __le32 reserved; + __le32 timestamp; __le16 rate_info; __u8 peer_id; __u8 tx_frag_cnt; @@ -2023,13 +2027,16 @@ struct mwl8k_cmd_get_hw_spec_ap { __le32 wcbbase2; __le32 wcbbase3; __le32 fw_api_version; + __le32 caps; + __le32 num_of_ampdu_queues; + __le32 wcbbase_ampdu[MWL8K_MAX_AMPDU_QUEUES]; } __packed; static int mwl8k_cmd_get_hw_spec_ap(struct ieee80211_hw *hw) { struct mwl8k_priv *priv = hw->priv; struct mwl8k_cmd_get_hw_spec_ap *cmd; - int rc; + int rc, i; u32 api_version; cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); @@ -2061,10 +2068,17 @@ static int mwl8k_cmd_get_hw_spec_ap(struct ieee80211_hw *hw) priv->num_mcaddrs = le16_to_cpu(cmd->num_mcaddrs); priv->fw_rev = le32_to_cpu(cmd->fw_rev); priv->hw_rev = cmd->hw_rev; - mwl8k_setup_2ghz_band(hw); + mwl8k_set_caps(hw, le32_to_cpu(cmd->caps)); priv->ap_macids_supported = 0x000000ff; priv->sta_macids_supported = 0x00000000; - + priv->num_ampdu_queues = le32_to_cpu(cmd->num_of_ampdu_queues); + if (priv->num_ampdu_queues > MWL8K_MAX_AMPDU_QUEUES) { + wiphy_warn(hw->wiphy, "fw reported %d ampdu queues" + " but we only support %d.\n", + priv->num_ampdu_queues, + MWL8K_MAX_AMPDU_QUEUES); + priv->num_ampdu_queues = MWL8K_MAX_AMPDU_QUEUES; + } off = le32_to_cpu(cmd->rxwrptr) & 0xffff; iowrite32(priv->rxq[0].rxd_dma, priv->sram + off); @@ -2075,6 +2089,10 @@ static int mwl8k_cmd_get_hw_spec_ap(struct ieee80211_hw *hw) priv->txq_offset[1] = le32_to_cpu(cmd->wcbbase1) & 0xffff; priv->txq_offset[2] = le32_to_cpu(cmd->wcbbase2) & 0xffff; priv->txq_offset[3] = le32_to_cpu(cmd->wcbbase3) & 0xffff; + + for (i = 0; i < priv->num_ampdu_queues; i++) + priv->txq_offset[i + MWL8K_TX_QUEUES] = + le32_to_cpu(cmd->wcbbase_ampdu[i]) & 0xffff; } done: @@ -2103,6 +2121,14 @@ struct mwl8k_cmd_set_hw_spec { __le32 total_rxd; } __packed; +/* If enabled, MWL8K_SET_HW_SPEC_FLAG_ENABLE_LIFE_TIME_EXPIRY will cause + * packets to expire 500 ms after the timestamp in the tx descriptor. That is, + * the packets that are queued for more than 500ms, will be dropped in the + * hardware. This helps minimizing the issues caused due to head-of-line + * blocking where a slow client can hog the bandwidth and affect traffic to a + * faster client. + */ +#define MWL8K_SET_HW_SPEC_FLAG_ENABLE_LIFE_TIME_EXPIRY 0x00000400 #define MWL8K_SET_HW_SPEC_FLAG_HOST_DECR_MGMT 0x00000080 #define MWL8K_SET_HW_SPEC_FLAG_HOSTFORM_PROBERESP 0x00000020 #define MWL8K_SET_HW_SPEC_FLAG_HOSTFORM_BEACON 0x00000010 @@ -4434,7 +4460,7 @@ enum { MWL8366, }; -#define MWL8K_8366_AP_FW_API 1 +#define MWL8K_8366_AP_FW_API 2 #define _MWL8K_8366_AP_FW(api) "mwl8k/fmimage_8366_ap-" #api ".fw" #define MWL8K_8366_AP_FW(api) _MWL8K_8366_AP_FW(api) @@ -4650,6 +4676,7 @@ static int mwl8k_probe_hw(struct ieee80211_hw *hw) * total number of queues from the result CMD_GET_HW_SPEC, so for this * case we must initialize the tx queues after. */ + priv->num_ampdu_queues = 0; if (!priv->ap_fw) { rc = mwl8k_init_txqs(hw); if (rc) -- cgit v0.10.2 From 5faa1aff08ef8d82b98ac2dfd7beb62ae6eda5e5 Mon Sep 17 00:00:00 2001 From: Nishant Sarmukadam Date: Thu, 17 Mar 2011 11:58:43 -0700 Subject: mwl8k: add support for block ack commands Signed-off-by: Pradeep Nemavat Signed-off-by: Brian Cavagnolo Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c index 9db66d5..944ad03 100644 --- a/drivers/net/wireless/mwl8k.c +++ b/drivers/net/wireless/mwl8k.c @@ -135,6 +135,14 @@ struct mwl8k_tx_queue { struct sk_buff **skb; }; +struct mwl8k_ampdu_stream { + struct ieee80211_sta *sta; + u8 tid; + u8 state; + u8 idx; + u8 txq_idx; /* index of this stream in priv->txq */ +}; + struct mwl8k_priv { struct ieee80211_hw *hw; struct pci_dev *pdev; @@ -360,6 +368,7 @@ static const struct ieee80211_rate mwl8k_rates_50[] = { #define MWL8K_CMD_SET_NEW_STN 0x1111 /* per-vif */ #define MWL8K_CMD_UPDATE_ENCRYPTION 0x1122 /* per-vif */ #define MWL8K_CMD_UPDATE_STADB 0x1123 +#define MWL8K_CMD_BASTREAM 0x1125 static const char *mwl8k_cmd_name(__le16 cmd, char *buf, int bufsize) { @@ -399,6 +408,7 @@ static const char *mwl8k_cmd_name(__le16 cmd, char *buf, int bufsize) MWL8K_CMDNAME(SET_NEW_STN); MWL8K_CMDNAME(UPDATE_ENCRYPTION); MWL8K_CMDNAME(UPDATE_STADB); + MWL8K_CMDNAME(BASTREAM); default: snprintf(buf, bufsize, "0x%x", cmd); } @@ -3176,6 +3186,152 @@ static int mwl8k_cmd_bss_start(struct ieee80211_hw *hw, } /* + * CMD_BASTREAM. + */ + +/* + * UPSTREAM is tx direction + */ +#define BASTREAM_FLAG_DIRECTION_UPSTREAM 0x00 +#define BASTREAM_FLAG_IMMEDIATE_TYPE 0x01 + +enum { + MWL8K_BA_CREATE, + MWL8K_BA_UPDATE, + MWL8K_BA_DESTROY, + MWL8K_BA_FLUSH, + MWL8K_BA_CHECK, +} ba_stream_action_type; + + +struct mwl8k_create_ba_stream { + __le32 flags; + __le32 idle_thrs; + __le32 bar_thrs; + __le32 window_size; + u8 peer_mac_addr[6]; + u8 dialog_token; + u8 tid; + u8 queue_id; + u8 param_info; + __le32 ba_context; + u8 reset_seq_no_flag; + __le16 curr_seq_no; + u8 sta_src_mac_addr[6]; +} __packed; + +struct mwl8k_destroy_ba_stream { + __le32 flags; + __le32 ba_context; +} __packed; + +struct mwl8k_cmd_bastream { + struct mwl8k_cmd_pkt header; + __le32 action; + union { + struct mwl8k_create_ba_stream create_params; + struct mwl8k_destroy_ba_stream destroy_params; + }; +} __packed; + +static int +mwl8k_check_ba(struct ieee80211_hw *hw, struct mwl8k_ampdu_stream *stream) +{ + struct mwl8k_cmd_bastream *cmd; + int rc; + + cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); + if (cmd == NULL) + return -ENOMEM; + + cmd->header.code = cpu_to_le16(MWL8K_CMD_BASTREAM); + cmd->header.length = cpu_to_le16(sizeof(*cmd)); + + cmd->action = cpu_to_le32(MWL8K_BA_CHECK); + + cmd->create_params.queue_id = stream->idx; + memcpy(&cmd->create_params.peer_mac_addr[0], stream->sta->addr, + ETH_ALEN); + cmd->create_params.tid = stream->tid; + + cmd->create_params.flags = + cpu_to_le32(BASTREAM_FLAG_IMMEDIATE_TYPE) | + cpu_to_le32(BASTREAM_FLAG_DIRECTION_UPSTREAM); + + rc = mwl8k_post_cmd(hw, &cmd->header); + + kfree(cmd); + + return rc; +} + +static int +mwl8k_create_ba(struct ieee80211_hw *hw, struct mwl8k_ampdu_stream *stream, + u8 buf_size) +{ + struct mwl8k_cmd_bastream *cmd; + int rc; + + cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); + if (cmd == NULL) + return -ENOMEM; + + + cmd->header.code = cpu_to_le16(MWL8K_CMD_BASTREAM); + cmd->header.length = cpu_to_le16(sizeof(*cmd)); + + cmd->action = cpu_to_le32(MWL8K_BA_CREATE); + + cmd->create_params.bar_thrs = cpu_to_le32((u32)buf_size); + cmd->create_params.window_size = cpu_to_le32((u32)buf_size); + cmd->create_params.queue_id = stream->idx; + + memcpy(cmd->create_params.peer_mac_addr, stream->sta->addr, ETH_ALEN); + cmd->create_params.tid = stream->tid; + cmd->create_params.curr_seq_no = cpu_to_le16(0); + cmd->create_params.reset_seq_no_flag = 1; + + cmd->create_params.param_info = + (stream->sta->ht_cap.ampdu_factor & + IEEE80211_HT_AMPDU_PARM_FACTOR) | + ((stream->sta->ht_cap.ampdu_density << 2) & + IEEE80211_HT_AMPDU_PARM_DENSITY); + + cmd->create_params.flags = + cpu_to_le32(BASTREAM_FLAG_IMMEDIATE_TYPE | + BASTREAM_FLAG_DIRECTION_UPSTREAM); + + rc = mwl8k_post_cmd(hw, &cmd->header); + + wiphy_debug(hw->wiphy, "Created a BA stream for %pM : tid %d\n", + stream->sta->addr, stream->tid); + kfree(cmd); + + return rc; +} + +static void mwl8k_destroy_ba(struct ieee80211_hw *hw, + struct mwl8k_ampdu_stream *stream) +{ + struct mwl8k_cmd_bastream *cmd; + + cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); + if (cmd == NULL) + return; + + cmd->header.code = cpu_to_le16(MWL8K_CMD_BASTREAM); + cmd->header.length = cpu_to_le16(sizeof(*cmd)); + cmd->action = cpu_to_le32(MWL8K_BA_DESTROY); + + cmd->destroy_params.ba_context = cpu_to_le32(stream->idx); + mwl8k_post_cmd(hw, &cmd->header); + + wiphy_debug(hw->wiphy, "Deleted BA stream index %d\n", stream->idx); + + kfree(cmd); +} + +/* * CMD_SET_NEW_STN. */ struct mwl8k_cmd_set_new_stn { -- cgit v0.10.2 From e600707b021efdc109e7becd467798da339ec26d Mon Sep 17 00:00:00 2001 From: Brian Cavagnolo Date: Thu, 17 Mar 2011 11:58:44 -0700 Subject: mwl8k: differentiate between WMM queues and AMPDU queues We now have two different kinds of queues. And the number of AMPDU queues may vary. So we must be clear about which queues we are dealing with. Note that when we report the number of queues to mac80211, we only report the WMM queues. Based on work by Yogesh Powar . Signed-off-by: Brian Cavagnolo Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c index 944ad03..53581ee 100644 --- a/drivers/net/wireless/mwl8k.c +++ b/drivers/net/wireless/mwl8k.c @@ -85,8 +85,10 @@ MODULE_PARM_DESC(ap_mode_default, MWL8K_A2H_INT_TX_DONE) #define MWL8K_RX_QUEUES 1 -#define MWL8K_TX_QUEUES 4 +#define MWL8K_TX_WMM_QUEUES 4 #define MWL8K_MAX_AMPDU_QUEUES 8 +#define MWL8K_MAX_TX_QUEUES (MWL8K_TX_WMM_QUEUES + MWL8K_MAX_AMPDU_QUEUES) +#define mwl8k_tx_queues(priv) (MWL8K_TX_WMM_QUEUES + (priv)->num_ampdu_queues) struct rxd_ops { int rxd_size; @@ -202,8 +204,8 @@ struct mwl8k_priv { int pending_tx_pkts; struct mwl8k_rx_queue rxq[MWL8K_RX_QUEUES]; - struct mwl8k_tx_queue txq[MWL8K_TX_QUEUES + MWL8K_MAX_AMPDU_QUEUES]; - u32 txq_offset[MWL8K_TX_QUEUES + MWL8K_MAX_AMPDU_QUEUES]; + struct mwl8k_tx_queue txq[MWL8K_MAX_TX_QUEUES]; + u32 txq_offset[MWL8K_MAX_TX_QUEUES]; bool radio_on; bool radio_short_preamble; @@ -236,7 +238,7 @@ struct mwl8k_priv { * preserve the queue configurations so they can be restored if/when * the firmware image is swapped. */ - struct ieee80211_tx_queue_params wmm_params[MWL8K_TX_QUEUES]; + struct ieee80211_tx_queue_params wmm_params[MWL8K_TX_WMM_QUEUES]; /* async firmware loading state */ unsigned fw_state; @@ -1400,7 +1402,7 @@ static void mwl8k_dump_tx_rings(struct ieee80211_hw *hw) struct mwl8k_priv *priv = hw->priv; int i; - for (i = 0; i < MWL8K_TX_QUEUES; i++) { + for (i = 0; i < mwl8k_tx_queues(priv); i++) { struct mwl8k_tx_queue *txq = priv->txq + i; int fw_owned = 0; int drv_owned = 0; @@ -1888,7 +1890,7 @@ struct mwl8k_cmd_get_hw_spec_sta { __u8 mcs_bitmap[16]; __le32 rx_queue_ptr; __le32 num_tx_queues; - __le32 tx_queue_ptrs[MWL8K_TX_QUEUES]; + __le32 tx_queue_ptrs[MWL8K_TX_WMM_QUEUES]; __le32 caps2; __le32 num_tx_desc_per_queue; __le32 total_rxd; @@ -1994,8 +1996,8 @@ static int mwl8k_cmd_get_hw_spec_sta(struct ieee80211_hw *hw) memset(cmd->perm_addr, 0xff, sizeof(cmd->perm_addr)); cmd->ps_cookie = cpu_to_le32(priv->cookie_dma); cmd->rx_queue_ptr = cpu_to_le32(priv->rxq[0].rxd_dma); - cmd->num_tx_queues = cpu_to_le32(MWL8K_TX_QUEUES); - for (i = 0; i < MWL8K_TX_QUEUES; i++) + cmd->num_tx_queues = cpu_to_le32(mwl8k_tx_queues(priv)); + for (i = 0; i < mwl8k_tx_queues(priv); i++) cmd->tx_queue_ptrs[i] = cpu_to_le32(priv->txq[i].txd_dma); cmd->num_tx_desc_per_queue = cpu_to_le32(MWL8K_TX_DESCS); cmd->total_rxd = cpu_to_le32(MWL8K_RX_DESCS); @@ -2101,7 +2103,7 @@ static int mwl8k_cmd_get_hw_spec_ap(struct ieee80211_hw *hw) priv->txq_offset[3] = le32_to_cpu(cmd->wcbbase3) & 0xffff; for (i = 0; i < priv->num_ampdu_queues; i++) - priv->txq_offset[i + MWL8K_TX_QUEUES] = + priv->txq_offset[i + MWL8K_TX_WMM_QUEUES] = le32_to_cpu(cmd->wcbbase_ampdu[i]) & 0xffff; } @@ -2125,7 +2127,7 @@ struct mwl8k_cmd_set_hw_spec { __le32 caps; __le32 rx_queue_ptr; __le32 num_tx_queues; - __le32 tx_queue_ptrs[MWL8K_TX_QUEUES]; + __le32 tx_queue_ptrs[MWL8K_MAX_TX_QUEUES]; __le32 flags; __le32 num_tx_desc_per_queue; __le32 total_rxd; @@ -2159,7 +2161,7 @@ static int mwl8k_cmd_set_hw_spec(struct ieee80211_hw *hw) cmd->ps_cookie = cpu_to_le32(priv->cookie_dma); cmd->rx_queue_ptr = cpu_to_le32(priv->rxq[0].rxd_dma); - cmd->num_tx_queues = cpu_to_le32(MWL8K_TX_QUEUES); + cmd->num_tx_queues = cpu_to_le32(mwl8k_tx_queues(priv)); /* * Mac80211 stack has Q0 as highest priority and Q3 as lowest in @@ -2167,8 +2169,8 @@ static int mwl8k_cmd_set_hw_spec(struct ieee80211_hw *hw) * in that order. Map Q3 of mac80211 to Q0 of firmware so that the * priority is interpreted the right way in firmware. */ - for (i = 0; i < MWL8K_TX_QUEUES; i++) { - int j = MWL8K_TX_QUEUES - 1 - i; + for (i = 0; i < mwl8k_tx_queues(priv); i++) { + int j = mwl8k_tx_queues(priv) - 1 - i; cmd->tx_queue_ptrs[i] = cpu_to_le32(priv->txq[j].txd_dma); } @@ -3880,7 +3882,7 @@ static void mwl8k_tx_poll(unsigned long data) spin_lock_bh(&priv->tx_lock); - for (i = 0; i < MWL8K_TX_QUEUES; i++) + for (i = 0; i < mwl8k_tx_queues(priv); i++) limit -= mwl8k_txq_reclaim(hw, i, limit, 0); if (!priv->pending_tx_pkts && priv->tx_wait != NULL) { @@ -4012,7 +4014,7 @@ static void mwl8k_stop(struct ieee80211_hw *hw) tasklet_disable(&priv->poll_rx_task); /* Return all skbs to mac80211 */ - for (i = 0; i < MWL8K_TX_QUEUES; i++) + for (i = 0; i < mwl8k_tx_queues(priv); i++) mwl8k_txq_reclaim(hw, i, INT_MAX, 1); } @@ -4510,14 +4512,14 @@ static int mwl8k_conf_tx(struct ieee80211_hw *hw, u16 queue, rc = mwl8k_fw_lock(hw); if (!rc) { - BUG_ON(queue > MWL8K_TX_QUEUES - 1); + BUG_ON(queue > MWL8K_TX_WMM_QUEUES - 1); memcpy(&priv->wmm_params[queue], params, sizeof(*params)); if (!priv->wmm_enabled) rc = mwl8k_cmd_set_wmm_mode(hw, 1); if (!rc) { - int q = MWL8K_TX_QUEUES - 1 - queue; + int q = MWL8K_TX_WMM_QUEUES - 1 - queue; rc = mwl8k_cmd_set_edca_params(hw, q, params->cw_min, params->cw_max, @@ -4788,7 +4790,7 @@ static int mwl8k_init_txqs(struct ieee80211_hw *hw) int rc = 0; int i; - for (i = 0; i < MWL8K_TX_QUEUES; i++) { + for (i = 0; i < mwl8k_tx_queues(priv); i++) { rc = mwl8k_txq_init(hw, i); if (rc) break; @@ -4906,7 +4908,7 @@ err_free_irq: free_irq(priv->pdev->irq, hw); err_free_queues: - for (i = 0; i < MWL8K_TX_QUEUES; i++) + for (i = 0; i < mwl8k_tx_queues(priv); i++) mwl8k_txq_deinit(hw, i); mwl8k_rxq_deinit(hw, 0); @@ -4928,7 +4930,7 @@ static int mwl8k_reload_firmware(struct ieee80211_hw *hw, char *fw_image) mwl8k_stop(hw); mwl8k_rxq_deinit(hw, 0); - for (i = 0; i < MWL8K_TX_QUEUES; i++) + for (i = 0; i < mwl8k_tx_queues(priv); i++) mwl8k_txq_deinit(hw, i); rc = mwl8k_init_firmware(hw, fw_image, false); @@ -4947,7 +4949,7 @@ static int mwl8k_reload_firmware(struct ieee80211_hw *hw, char *fw_image) if (rc) goto fail; - for (i = 0; i < MWL8K_TX_QUEUES; i++) { + for (i = 0; i < MWL8K_TX_WMM_QUEUES; i++) { rc = mwl8k_conf_tx(hw, i, &priv->wmm_params[i]); if (rc) goto fail; @@ -4981,7 +4983,7 @@ static int mwl8k_firmware_load_success(struct mwl8k_priv *priv) hw->channel_change_time = 10; - hw->queues = MWL8K_TX_QUEUES; + hw->queues = MWL8K_TX_WMM_QUEUES; /* Set rssi values to dBm */ hw->flags |= IEEE80211_HW_SIGNAL_DBM | IEEE80211_HW_HAS_RATE_CONTROL; @@ -5037,7 +5039,7 @@ static int mwl8k_firmware_load_success(struct mwl8k_priv *priv) return 0; err_unprobe_hw: - for (i = 0; i < MWL8K_TX_QUEUES; i++) + for (i = 0; i < mwl8k_tx_queues(priv); i++) mwl8k_txq_deinit(hw, i); mwl8k_rxq_deinit(hw, 0); @@ -5196,10 +5198,10 @@ static void __devexit mwl8k_remove(struct pci_dev *pdev) mwl8k_hw_reset(priv); /* Return all skbs to mac80211 */ - for (i = 0; i < MWL8K_TX_QUEUES; i++) + for (i = 0; i < mwl8k_tx_queues(priv); i++) mwl8k_txq_reclaim(hw, i, INT_MAX, 1); - for (i = 0; i < MWL8K_TX_QUEUES; i++) + for (i = 0; i < mwl8k_tx_queues(priv); i++) mwl8k_txq_deinit(hw, i); mwl8k_rxq_deinit(hw, 0); -- cgit v0.10.2 From ac109fd0427008e5b55e0e52e59c364de6d686fe Mon Sep 17 00:00:00 2001 From: Brian Cavagnolo Date: Thu, 17 Mar 2011 11:58:45 -0700 Subject: mwl8k: add internal API for managing AMPDU streams In particular, we can now add, start, lookup, and remove streams. Based on work by Nishant Sarmukadam and Pradeep Nemavat . Signed-off-by: Pradeep Nemavat Signed-off-by: Nishant Sarmukadam Signed-off-by: Brian Cavagnolo Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c index 53581ee..dcd4508 100644 --- a/drivers/net/wireless/mwl8k.c +++ b/drivers/net/wireless/mwl8k.c @@ -137,6 +137,13 @@ struct mwl8k_tx_queue { struct sk_buff **skb; }; +enum { + AMPDU_NO_STREAM, + AMPDU_STREAM_NEW, + AMPDU_STREAM_IN_PROGRESS, + AMPDU_STREAM_ACTIVE, +}; + struct mwl8k_ampdu_stream { struct ieee80211_sta *sta; u8 tid; @@ -172,6 +179,8 @@ struct mwl8k_priv { /* Ampdu stream information */ u8 num_ampdu_queues; + spinlock_t stream_lock; + struct mwl8k_ampdu_stream ampdu[MWL8K_MAX_AMPDU_QUEUES]; /* firmware access */ struct mutex fw_mutex; @@ -1594,6 +1603,74 @@ static void mwl8k_txq_deinit(struct ieee80211_hw *hw, int index) txq->txd = NULL; } +/* caller must hold priv->stream_lock when calling the stream functions */ +struct mwl8k_ampdu_stream * +mwl8k_add_stream(struct ieee80211_hw *hw, struct ieee80211_sta *sta, u8 tid) +{ + struct mwl8k_ampdu_stream *stream; + struct mwl8k_priv *priv = hw->priv; + int i; + + for (i = 0; i < priv->num_ampdu_queues; i++) { + stream = &priv->ampdu[i]; + if (stream->state == AMPDU_NO_STREAM) { + stream->sta = sta; + stream->state = AMPDU_STREAM_NEW; + stream->tid = tid; + stream->idx = i; + stream->txq_idx = MWL8K_TX_WMM_QUEUES + i; + wiphy_debug(hw->wiphy, "Added a new stream for %pM %d", + sta->addr, tid); + return stream; + } + } + return NULL; +} + +static int +mwl8k_start_stream(struct ieee80211_hw *hw, struct mwl8k_ampdu_stream *stream) +{ + int ret; + + /* if the stream has already been started, don't start it again */ + if (stream->state != AMPDU_STREAM_NEW) + return 0; + ret = ieee80211_start_tx_ba_session(stream->sta, stream->tid, 0); + if (ret) + wiphy_debug(hw->wiphy, "Failed to start stream for %pM %d: " + "%d\n", stream->sta->addr, stream->tid, ret); + else + wiphy_debug(hw->wiphy, "Started stream for %pM %d\n", + stream->sta->addr, stream->tid); + return ret; +} + +static void +mwl8k_remove_stream(struct ieee80211_hw *hw, struct mwl8k_ampdu_stream *stream) +{ + wiphy_debug(hw->wiphy, "Remove stream for %pM %d\n", stream->sta->addr, + stream->tid); + memset(stream, 0, sizeof(*stream)); +} + +static struct mwl8k_ampdu_stream * +mwl8k_lookup_stream(struct ieee80211_hw *hw, u8 *addr, u8 tid) +{ + struct mwl8k_priv *priv = hw->priv; + int i; + + for (i = 0 ; i < priv->num_ampdu_queues; i++) { + struct mwl8k_ampdu_stream *stream; + stream = &priv->ampdu[i]; + if (stream->state == AMPDU_NO_STREAM) + continue; + if (!memcmp(stream->sta->addr, addr, ETH_ALEN) && + stream->tid == tid) + return stream; + } + return NULL; +} + static void mwl8k_txq_xmit(struct ieee80211_hw *hw, int index, struct sk_buff *skb) { @@ -4854,6 +4931,8 @@ static int mwl8k_probe_hw(struct ieee80211_hw *hw) goto err_free_queues; } + memset(priv->ampdu, 0, sizeof(priv->ampdu)); + /* * Temporarily enable interrupts. Initial firmware host * commands use interrupts and avoid polling. Disable @@ -5018,6 +5097,8 @@ static int mwl8k_firmware_load_success(struct mwl8k_priv *priv) spin_lock_init(&priv->tx_lock); + spin_lock_init(&priv->stream_lock); + priv->tx_wait = NULL; rc = mwl8k_probe_hw(hw); -- cgit v0.10.2 From 65f3ddcd08fe24490359274a8c9bf526e81357a5 Mon Sep 17 00:00:00 2001 From: Nishant Sarmukadam Date: Thu, 17 Mar 2011 11:58:46 -0700 Subject: mwl8k: Initiate BA sessions Specifically, handle ampdu_action and attempt to start a BA session on receiving the first qos packet from mac80211 for transmission to a HT sta. While the BA session is being created, all the packets belonging to that stream will be dropped to prevent sequence number mismatch at the recipient. Contains contributions from: Yogesh Powar Pradeep Nemavat Brian Cavagnolo Signed-off-by: Brian Cavagnolo Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c index dcd4508..ec1190a 100644 --- a/drivers/net/wireless/mwl8k.c +++ b/drivers/net/wireless/mwl8k.c @@ -1577,7 +1577,8 @@ mwl8k_txq_reclaim(struct ieee80211_hw *hw, int index, int limit, int force) processed++; } - if (processed && priv->radio_on && !mutex_is_locked(&priv->fw_mutex)) + if (index < MWL8K_TX_WMM_QUEUES && processed && priv->radio_on && + !mutex_is_locked(&priv->fw_mutex)) ieee80211_wake_queue(hw, index); return processed; @@ -1677,6 +1678,7 @@ mwl8k_txq_xmit(struct ieee80211_hw *hw, int index, struct sk_buff *skb) struct mwl8k_priv *priv = hw->priv; struct ieee80211_tx_info *tx_info; struct mwl8k_vif *mwl8k_vif; + struct ieee80211_sta *sta; struct ieee80211_hdr *wh; struct mwl8k_tx_queue *txq; struct mwl8k_tx_desc *tx; @@ -1684,6 +1686,10 @@ mwl8k_txq_xmit(struct ieee80211_hw *hw, int index, struct sk_buff *skb) u32 txstatus; u8 txdatarate; u16 qos; + int txpriority; + u8 tid = 0; + struct mwl8k_ampdu_stream *stream = NULL; + bool start_ba_session = false; wh = (struct ieee80211_hdr *)skb->data; if (ieee80211_is_data_qos(wh->frame_control)) @@ -1699,6 +1705,7 @@ mwl8k_txq_xmit(struct ieee80211_hw *hw, int index, struct sk_buff *skb) wh = &((struct mwl8k_dma_data *)skb->data)->wh; tx_info = IEEE80211_SKB_CB(skb); + sta = tx_info->control.sta; mwl8k_vif = MWL8K_VIF(tx_info->control.vif); if (tx_info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ) { @@ -1726,12 +1733,70 @@ mwl8k_txq_xmit(struct ieee80211_hw *hw, int index, struct sk_buff *skb) qos |= MWL8K_QOS_ACK_POLICY_NORMAL; } + txpriority = index; + + if (ieee80211_is_data_qos(wh->frame_control) && + skb->protocol != cpu_to_be16(ETH_P_PAE) && + sta->ht_cap.ht_supported && priv->ap_fw) { + tid = qos & 0xf; + spin_lock(&priv->stream_lock); + stream = mwl8k_lookup_stream(hw, sta->addr, tid); + if (stream != NULL) { + if (stream->state == AMPDU_STREAM_ACTIVE) { + txpriority = stream->txq_idx; + index = stream->txq_idx; + } else if (stream->state == AMPDU_STREAM_NEW) { + /* We get here if the driver sends us packets + * after we've initiated a stream, but before + * our ampdu_action routine has been called + * with IEEE80211_AMPDU_TX_START to get the SSN + * for the ADDBA request. So this packet can + * go out with no risk of sequence number + * mismatch. No special handling is required. + */ + } else { + /* Drop packets that would go out after the + * ADDBA request was sent but before the ADDBA + * response is received. If we don't do this, + * the recipient would probably receive it + * after the ADDBA request with SSN 0. This + * will cause the recipient's BA receive window + * to shift, which would cause the subsequent + * packets in the BA stream to be discarded. + * mac80211 queues our packets for us in this + * case, so this is really just a safety check. + */ + wiphy_warn(hw->wiphy, + "Cannot send packet while ADDBA " + "dialog is underway.\n"); + spin_unlock(&priv->stream_lock); + dev_kfree_skb(skb); + return; + } + } else { + /* Defer calling mwl8k_start_stream so that the current + * skb can go out before the ADDBA request. This + * prevents sequence number mismatch at the recepient + * as described above. + */ + stream = mwl8k_add_stream(hw, sta, tid); + if (stream != NULL) + start_ba_session = true; + } + spin_unlock(&priv->stream_lock); + } + dma = pci_map_single(priv->pdev, skb->data, skb->len, PCI_DMA_TODEVICE); if (pci_dma_mapping_error(priv->pdev, dma)) { wiphy_debug(hw->wiphy, "failed to dma map skb, dropping TX frame.\n"); + if (start_ba_session) { + spin_lock(&priv->stream_lock); + mwl8k_remove_stream(hw, stream); + spin_unlock(&priv->stream_lock); + } dev_kfree_skb(skb); return; } @@ -1740,12 +1805,22 @@ mwl8k_txq_xmit(struct ieee80211_hw *hw, int index, struct sk_buff *skb) txq = priv->txq + index; + if (index >= MWL8K_TX_WMM_QUEUES && txq->len >= MWL8K_TX_DESCS) { + /* This is the case in which the tx packet is destined for an + * AMPDU queue and that AMPDU queue is full. Because we don't + * start and stop the AMPDU queues, we must drop these packets. + */ + dev_kfree_skb(skb); + spin_unlock_bh(&priv->tx_lock); + return; + } + BUG_ON(txq->skb[txq->tail] != NULL); txq->skb[txq->tail] = skb; tx = txq->txd + txq->tail; tx->data_rate = txdatarate; - tx->tx_priority = index; + tx->tx_priority = txpriority; tx->qos_control = cpu_to_le16(qos); tx->pkt_phys_addr = cpu_to_le32(dma); tx->pkt_len = cpu_to_le16(skb->len); @@ -1764,12 +1839,20 @@ mwl8k_txq_xmit(struct ieee80211_hw *hw, int index, struct sk_buff *skb) if (txq->tail == MWL8K_TX_DESCS) txq->tail = 0; - if (txq->head == txq->tail) + if (txq->head == txq->tail && index < MWL8K_TX_WMM_QUEUES) ieee80211_stop_queue(hw, index); mwl8k_tx_start(priv); spin_unlock_bh(&priv->tx_lock); + + /* Initiate the ampdu session here */ + if (start_ba_session) { + spin_lock(&priv->stream_lock); + if (mwl8k_start_stream(hw, stream)) + mwl8k_remove_stream(hw, stream); + spin_unlock(&priv->stream_lock); + } } @@ -4632,21 +4715,118 @@ static int mwl8k_get_survey(struct ieee80211_hw *hw, int idx, return 0; } +#define MAX_AMPDU_ATTEMPTS 5 + static int mwl8k_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif, enum ieee80211_ampdu_mlme_action action, struct ieee80211_sta *sta, u16 tid, u16 *ssn, u8 buf_size) { + + int i, rc = 0; + struct mwl8k_priv *priv = hw->priv; + struct mwl8k_ampdu_stream *stream; + u8 *addr = sta->addr; + + if (!(hw->flags & IEEE80211_HW_AMPDU_AGGREGATION)) + return -ENOTSUPP; + + spin_lock(&priv->stream_lock); + stream = mwl8k_lookup_stream(hw, addr, tid); + switch (action) { case IEEE80211_AMPDU_RX_START: case IEEE80211_AMPDU_RX_STOP: - if (!(hw->flags & IEEE80211_HW_AMPDU_AGGREGATION)) - return -ENOTSUPP; - return 0; + break; + case IEEE80211_AMPDU_TX_START: + /* By the time we get here the hw queues may contain outgoing + * packets for this RA/TID that are not part of this BA + * session. The hw will assign sequence numbers to these + * packets as they go out. So if we query the hw for its next + * sequence number and use that for the SSN here, it may end up + * being wrong, which will lead to sequence number mismatch at + * the recipient. To avoid this, we reset the sequence number + * to O for the first MPDU in this BA stream. + */ + *ssn = 0; + if (stream == NULL) { + /* This means that somebody outside this driver called + * ieee80211_start_tx_ba_session. This is unexpected + * because we do our own rate control. Just warn and + * move on. + */ + wiphy_warn(hw->wiphy, "Unexpected call to %s. " + "Proceeding anyway.\n", __func__); + stream = mwl8k_add_stream(hw, sta, tid); + } + if (stream == NULL) { + wiphy_debug(hw->wiphy, "no free AMPDU streams\n"); + rc = -EBUSY; + break; + } + stream->state = AMPDU_STREAM_IN_PROGRESS; + + /* Release the lock before we do the time consuming stuff */ + spin_unlock(&priv->stream_lock); + for (i = 0; i < MAX_AMPDU_ATTEMPTS; i++) { + rc = mwl8k_check_ba(hw, stream); + + if (!rc) + break; + /* + * HW queues take time to be flushed, give them + * sufficient time + */ + + msleep(1000); + } + spin_lock(&priv->stream_lock); + if (rc) { + wiphy_err(hw->wiphy, "Stream for tid %d busy after %d" + " attempts\n", tid, MAX_AMPDU_ATTEMPTS); + mwl8k_remove_stream(hw, stream); + rc = -EBUSY; + break; + } + ieee80211_start_tx_ba_cb_irqsafe(vif, addr, tid); + break; + case IEEE80211_AMPDU_TX_STOP: + if (stream == NULL) + break; + if (stream->state == AMPDU_STREAM_ACTIVE) { + spin_unlock(&priv->stream_lock); + mwl8k_destroy_ba(hw, stream); + spin_lock(&priv->stream_lock); + } + mwl8k_remove_stream(hw, stream); + ieee80211_stop_tx_ba_cb_irqsafe(vif, addr, tid); + break; + case IEEE80211_AMPDU_TX_OPERATIONAL: + BUG_ON(stream == NULL); + BUG_ON(stream->state != AMPDU_STREAM_IN_PROGRESS); + spin_unlock(&priv->stream_lock); + rc = mwl8k_create_ba(hw, stream, buf_size); + spin_lock(&priv->stream_lock); + if (!rc) + stream->state = AMPDU_STREAM_ACTIVE; + else { + spin_unlock(&priv->stream_lock); + mwl8k_destroy_ba(hw, stream); + spin_lock(&priv->stream_lock); + wiphy_debug(hw->wiphy, + "Failed adding stream for sta %pM tid %d\n", + addr, tid); + mwl8k_remove_stream(hw, stream); + } + break; + default: - return -ENOTSUPP; + rc = -ENOTSUPP; } + + spin_unlock(&priv->stream_lock); + return rc; } static const struct ieee80211_ops mwl8k_ops = { -- cgit v0.10.2 From 3aefc37ee789188f0d4488cae04ff618f4c4ddf6 Mon Sep 17 00:00:00 2001 From: Nishant Sarmukadam Date: Thu, 17 Mar 2011 11:58:47 -0700 Subject: mwl8k: Handle the watchdog event from the firmware When an ampdu stream is on, if the firmware rate adaptation logic decides that the outgoing packet rate to the station needs to go below 6.5Mbps (non HT rate), it sends an event indicating that the ampdu stream needs to be destroyed. Handle this event in the driver and destroy the ampdu stream so that the rate can go below 6.5Mbps Signed-off-by: Nishant Sarmukadam Signed-off-by: Brian Cavagnolo Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c index ec1190a..b90178d 100644 --- a/drivers/net/wireless/mwl8k.c +++ b/drivers/net/wireless/mwl8k.c @@ -63,6 +63,7 @@ MODULE_PARM_DESC(ap_mode_default, #define MWL8K_HIU_A2H_INTERRUPT_CLEAR_SEL 0x00000c38 #define MWL8K_HIU_A2H_INTERRUPT_STATUS_MASK 0x00000c3c #define MWL8K_A2H_INT_DUMMY (1 << 20) +#define MWL8K_A2H_INT_BA_WATCHDOG (1 << 14) #define MWL8K_A2H_INT_CHNL_SWITCHED (1 << 11) #define MWL8K_A2H_INT_QUEUE_EMPTY (1 << 10) #define MWL8K_A2H_INT_RADAR_DETECT (1 << 7) @@ -82,7 +83,8 @@ MODULE_PARM_DESC(ap_mode_default, MWL8K_A2H_INT_MAC_EVENT | \ MWL8K_A2H_INT_OPC_DONE | \ MWL8K_A2H_INT_RX_READY | \ - MWL8K_A2H_INT_TX_DONE) + MWL8K_A2H_INT_TX_DONE | \ + MWL8K_A2H_INT_BA_WATCHDOG) #define MWL8K_RX_QUEUES 1 #define MWL8K_TX_WMM_QUEUES 4 @@ -181,6 +183,7 @@ struct mwl8k_priv { u8 num_ampdu_queues; spinlock_t stream_lock; struct mwl8k_ampdu_stream ampdu[MWL8K_MAX_AMPDU_QUEUES]; + struct work_struct watchdog_ba_handle; /* firmware access */ struct mutex fw_mutex; @@ -375,6 +378,7 @@ static const struct ieee80211_rate mwl8k_rates_50[] = { #define MWL8K_CMD_ENABLE_SNIFFER 0x0150 #define MWL8K_CMD_SET_MAC_ADDR 0x0202 /* per-vif */ #define MWL8K_CMD_SET_RATEADAPT_MODE 0x0203 +#define MWL8K_CMD_GET_WATCHDOG_BITMAP 0x0205 #define MWL8K_CMD_BSS_START 0x1100 /* per-vif */ #define MWL8K_CMD_SET_NEW_STN 0x1111 /* per-vif */ #define MWL8K_CMD_UPDATE_ENCRYPTION 0x1122 /* per-vif */ @@ -420,6 +424,7 @@ static const char *mwl8k_cmd_name(__le16 cmd, char *buf, int bufsize) MWL8K_CMDNAME(UPDATE_ENCRYPTION); MWL8K_CMDNAME(UPDATE_STADB); MWL8K_CMDNAME(BASTREAM); + MWL8K_CMDNAME(GET_WATCHDOG_BITMAP); default: snprintf(buf, bufsize, "0x%x", cmd); } @@ -3320,6 +3325,65 @@ static int mwl8k_cmd_set_rateadapt_mode(struct ieee80211_hw *hw, __u16 mode) } /* + * CMD_GET_WATCHDOG_BITMAP. + */ +struct mwl8k_cmd_get_watchdog_bitmap { + struct mwl8k_cmd_pkt header; + u8 bitmap; +} __packed; + +static int mwl8k_cmd_get_watchdog_bitmap(struct ieee80211_hw *hw, u8 *bitmap) +{ + struct mwl8k_cmd_get_watchdog_bitmap *cmd; + int rc; + + cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); + if (cmd == NULL) + return -ENOMEM; + + cmd->header.code = cpu_to_le16(MWL8K_CMD_GET_WATCHDOG_BITMAP); + cmd->header.length = cpu_to_le16(sizeof(*cmd)); + + rc = mwl8k_post_cmd(hw, &cmd->header); + if (!rc) + *bitmap = cmd->bitmap; + + kfree(cmd); + + return rc; +} + +#define INVALID_BA 0xAA +static void mwl8k_watchdog_ba_events(struct work_struct *work) +{ + int rc; + u8 bitmap = 0, stream_index; + struct mwl8k_ampdu_stream *streams; + struct mwl8k_priv *priv = + container_of(work, struct mwl8k_priv, watchdog_ba_handle); + + rc = mwl8k_cmd_get_watchdog_bitmap(priv->hw, &bitmap); + if (rc) + return; + + if (bitmap == INVALID_BA) + return; + + /* the bitmap is the hw queue number. Map it to the ampdu queue. */ + stream_index = bitmap - MWL8K_TX_WMM_QUEUES; + + BUG_ON(stream_index >= priv->num_ampdu_queues); + + streams = &priv->ampdu[stream_index]; + + if (streams->state == AMPDU_STREAM_ACTIVE) + ieee80211_stop_tx_ba_session(streams->sta, streams->tid); + + return; +} + + +/* * CMD_BSS_START. */ struct mwl8k_cmd_bss_start { @@ -4014,6 +4078,11 @@ static irqreturn_t mwl8k_interrupt(int irq, void *dev_id) tasklet_schedule(&priv->poll_rx_task); } + if (status & MWL8K_A2H_INT_BA_WATCHDOG) { + status &= ~MWL8K_A2H_INT_BA_WATCHDOG; + ieee80211_queue_work(hw, &priv->watchdog_ba_handle); + } + if (status) iowrite32(~status, priv->regs + MWL8K_HIU_A2H_INTERRUPT_STATUS); @@ -4166,6 +4235,7 @@ static void mwl8k_stop(struct ieee80211_hw *hw) /* Stop finalize join worker */ cancel_work_sync(&priv->finalize_join_worker); + cancel_work_sync(&priv->watchdog_ba_handle); if (priv->beacon_skb != NULL) dev_kfree_skb(priv->beacon_skb); @@ -5100,7 +5170,8 @@ static int mwl8k_probe_hw(struct ieee80211_hw *hw) iowrite32(0, priv->regs + MWL8K_HIU_A2H_INTERRUPT_STATUS); iowrite32(0, priv->regs + MWL8K_HIU_A2H_INTERRUPT_MASK); - iowrite32(MWL8K_A2H_INT_TX_DONE | MWL8K_A2H_INT_RX_READY, + iowrite32(MWL8K_A2H_INT_TX_DONE|MWL8K_A2H_INT_RX_READY| + MWL8K_A2H_INT_BA_WATCHDOG, priv->regs + MWL8K_HIU_A2H_INTERRUPT_CLEAR_SEL); iowrite32(0xffffffff, priv->regs + MWL8K_HIU_A2H_INTERRUPT_STATUS_MASK); @@ -5258,6 +5329,8 @@ static int mwl8k_firmware_load_success(struct mwl8k_priv *priv) /* Finalize join worker */ INIT_WORK(&priv->finalize_join_worker, mwl8k_finalize_join_worker); + /* Handle watchdog ba events */ + INIT_WORK(&priv->watchdog_ba_handle, mwl8k_watchdog_ba_events); /* TX reclaim and RX tasklets. */ tasklet_init(&priv->poll_tx_task, mwl8k_tx_poll, (unsigned long)hw); -- cgit v0.10.2 From 170335432ad36584a6d24fc1fd903024d221ef55 Mon Sep 17 00:00:00 2001 From: Nishant Sarmukadam Date: Thu, 17 Mar 2011 11:58:48 -0700 Subject: mwl8k: Check outgoing rate for a station to decide if ampdu can be created If the outgoing packet rate to a particular HT station is <=6.5 Mbps, do not attempt to create an ampdu. Also, if the outgoing rate is legacy rate, do not create an ampdu. Signed-off-by: Nishant Sarmukadam Signed-off-by: Brian Cavagnolo Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c index b90178d..5473f4c 100644 --- a/drivers/net/wireless/mwl8k.c +++ b/drivers/net/wireless/mwl8k.c @@ -291,6 +291,7 @@ struct mwl8k_vif { struct mwl8k_sta { /* Index into station database. Returned by UPDATE_STADB. */ u8 peer_id; + u8 is_ampdu_allowed; }; #define MWL8K_STA(_sta) ((struct mwl8k_sta *)&((_sta)->drv_priv)) @@ -1517,6 +1518,27 @@ static int mwl8k_tx_wait_empty(struct ieee80211_hw *hw) MWL8K_TXD_STATUS_OK_RETRY | \ MWL8K_TXD_STATUS_OK_MORE_RETRY)) +/* The firmware will fill in the rate information + * for each packet that gets queued in the hardware + * in this structure + */ + +struct rateinfo { + __le16 format:1; + __le16 short_gi:1; + __le16 band_width:1; + __le16 rate_id_mcs:6; + __le16 adv_coding:2; + __le16 antenna:2; + __le16 act_sub_chan:2; + __le16 preamble_type:1; + __le16 power_id:4; + __le16 antenna2:1; + __le16 reserved:1; + __le16 tx_bf_frame:1; + __le16 green_field:1; +} __packed; + static int mwl8k_txq_reclaim(struct ieee80211_hw *hw, int index, int limit, int force) { @@ -1533,6 +1555,11 @@ mwl8k_txq_reclaim(struct ieee80211_hw *hw, int index, int limit, int force) struct sk_buff *skb; struct ieee80211_tx_info *info; u32 status; + struct ieee80211_sta *sta; + struct mwl8k_sta *sta_info = NULL; + u16 rate_info; + struct rateinfo *rate; + struct ieee80211_hdr *wh; tx = txq->head; tx_desc = txq->txd + tx; @@ -1561,11 +1588,34 @@ mwl8k_txq_reclaim(struct ieee80211_hw *hw, int index, int limit, int force) mwl8k_remove_dma_header(skb, tx_desc->qos_control); + wh = (struct ieee80211_hdr *) skb->data; + /* Mark descriptor as unused */ tx_desc->pkt_phys_addr = 0; tx_desc->pkt_len = 0; info = IEEE80211_SKB_CB(skb); + if (ieee80211_is_data(wh->frame_control)) { + sta = info->control.sta; + if (sta) { + sta_info = MWL8K_STA(sta); + BUG_ON(sta_info == NULL); + rate_info = le16_to_cpu(tx_desc->rate_info); + rate = (struct rateinfo *)&rate_info; + /* If rate is < 6.5 Mpbs for an ht station + * do not form an ampdu. If the station is a + * legacy station (format = 0), do not form an + * ampdu + */ + if (rate->rate_id_mcs < 1 || + rate->format == 0) { + sta_info->is_ampdu_allowed = false; + } else { + sta_info->is_ampdu_allowed = true; + } + } + } + ieee80211_tx_info_clear_status(info); /* Rate control is happening in the firmware. @@ -1784,9 +1834,11 @@ mwl8k_txq_xmit(struct ieee80211_hw *hw, int index, struct sk_buff *skb) * prevents sequence number mismatch at the recepient * as described above. */ - stream = mwl8k_add_stream(hw, sta, tid); - if (stream != NULL) - start_ba_session = true; + if (MWL8K_STA(sta)->is_ampdu_allowed) { + stream = mwl8k_add_stream(hw, sta, tid); + if (stream != NULL) + start_ba_session = true; + } } spin_unlock(&priv->stream_lock); } @@ -4719,6 +4771,8 @@ static int mwl8k_sta_add(struct ieee80211_hw *hw, ret = mwl8k_cmd_update_stadb_add(hw, vif, sta); if (ret >= 0) { MWL8K_STA(sta)->peer_id = ret; + if (sta->ht_cap.ht_supported) + MWL8K_STA(sta)->is_ampdu_allowed = true; ret = 0; } -- cgit v0.10.2 From a0e7c6cfe2a04af450274638845802b5c384e8df Mon Sep 17 00:00:00 2001 From: Nishant Sarmukadam Date: Thu, 17 Mar 2011 11:58:49 -0700 Subject: mwl8k: Queue ADDBA requests in respective data queues Queue ADDBA requests in respective data queues to avoid ADDBA requests and the the related data packets (to the same ra/tid) queued in the hardware to be sent out asynchronously. Signed-off-by: Nishant Sarmukadam Signed-off-by: Brian Cavagnolo Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c index 5473f4c..ae56d2f3 100644 --- a/drivers/net/wireless/mwl8k.c +++ b/drivers/net/wireless/mwl8k.c @@ -1518,6 +1518,33 @@ static int mwl8k_tx_wait_empty(struct ieee80211_hw *hw) MWL8K_TXD_STATUS_OK_RETRY | \ MWL8K_TXD_STATUS_OK_MORE_RETRY)) +static int mwl8k_tid_queue_mapping(u8 tid) +{ + BUG_ON(tid > 7); + + switch (tid) { + case 0: + case 3: + return IEEE80211_AC_BE; + break; + case 1: + case 2: + return IEEE80211_AC_BK; + break; + case 4: + case 5: + return IEEE80211_AC_VI; + break; + case 6: + case 7: + return IEEE80211_AC_VO; + break; + default: + return -1; + break; + } +} + /* The firmware will fill in the rate information * for each packet that gets queued in the hardware * in this structure @@ -1745,6 +1772,7 @@ mwl8k_txq_xmit(struct ieee80211_hw *hw, int index, struct sk_buff *skb) u8 tid = 0; struct mwl8k_ampdu_stream *stream = NULL; bool start_ba_session = false; + struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)skb->data; wh = (struct ieee80211_hdr *)skb->data; if (ieee80211_is_data_qos(wh->frame_control)) @@ -1788,6 +1816,24 @@ mwl8k_txq_xmit(struct ieee80211_hw *hw, int index, struct sk_buff *skb) qos |= MWL8K_QOS_ACK_POLICY_NORMAL; } + /* Queue ADDBA request in the respective data queue. While setting up + * the ampdu stream, mac80211 queues further packets for that + * particular ra/tid pair. However, packets piled up in the hardware + * for that ra/tid pair will still go out. ADDBA request and the + * related data packets going out from different queues asynchronously + * will cause a shift in the receiver window which might result in + * ampdu packets getting dropped at the receiver after the stream has + * been setup. + */ + if (unlikely(ieee80211_is_action(wh->frame_control) && + mgmt->u.action.category == WLAN_CATEGORY_BACK && + mgmt->u.action.u.addba_req.action_code == WLAN_ACTION_ADDBA_REQ && + priv->ap_fw)) { + u16 capab = le16_to_cpu(mgmt->u.action.u.addba_req.capab); + tid = (capab & IEEE80211_ADDBA_PARAM_TID_MASK) >> 2; + index = mwl8k_tid_queue_mapping(tid); + } + txpriority = index; if (ieee80211_is_data_qos(wh->frame_control) && -- cgit v0.10.2 From 716b1bf3c5040f2303d6d1d0dfee6d8851cedc9d Mon Sep 17 00:00:00 2001 From: Larry Finger Date: Thu, 17 Mar 2011 21:53:01 -0500 Subject: rtlwifi: rtl8192c{e,u}: Remove some extraneous casts on memcpy commands Signed-off-by: Larry Finger Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/rtlwifi/rtl8192ce/trx.h b/drivers/net/wireless/rtlwifi/rtl8192ce/trx.h index 803adcc..b0b0b13 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192ce/trx.h +++ b/drivers/net/wireless/rtlwifi/rtl8192ce/trx.h @@ -532,9 +532,9 @@ #define CLEAR_PCI_TX_DESC_CONTENT(__pdesc, _size) \ do { \ if (_size > TX_DESC_NEXT_DESC_OFFSET) \ - memset((void *)__pdesc, 0, TX_DESC_NEXT_DESC_OFFSET); \ + memset(__pdesc, 0, TX_DESC_NEXT_DESC_OFFSET); \ else \ - memset((void *)__pdesc, 0, _size); \ + memset(__pdesc, 0, _size); \ } while (0); #define RX_HAL_IS_CCK_RATE(_pdesc)\ diff --git a/drivers/net/wireless/rtlwifi/rtl8192cu/trx.c b/drivers/net/wireless/rtlwifi/rtl8192cu/trx.c index d0b0d43..3f0cb81 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192cu/trx.c +++ b/drivers/net/wireless/rtlwifi/rtl8192cu/trx.c @@ -656,7 +656,7 @@ void rtl92cu_tx_fill_cmddesc(struct ieee80211_hw *hw, struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)(skb->data); __le16 fc = hdr->frame_control; - memset((void *)pdesc, 0, RTL_TX_HEADER_SIZE); + memset(pdesc, 0, RTL_TX_HEADER_SIZE); if (firstseg) SET_TX_DESC_OFFSET(pdesc, RTL_TX_HEADER_SIZE); SET_TX_DESC_TX_RATE(pdesc, DESC92C_RATE1M); -- cgit v0.10.2 From c70cab1a45d56395db03957f6504c6b613bece5b Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Sat, 19 Mar 2011 13:55:37 +0100 Subject: ath9k: remove unnecessary debugfs return code checks Since the ath9k debugfs directory is cleaned up by debugfs_remove_recursive, there's no point in checking the return code of every single debugfs create line. Signed-off-by: Felix Fietkau Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/debug.c b/drivers/net/wireless/ath/ath9k/debug.c index 8df5a92..9fe8693 100644 --- a/drivers/net/wireless/ath/ath9k/debug.c +++ b/drivers/net/wireless/ath/ath9k/debug.c @@ -1088,67 +1088,37 @@ int ath9k_init_debug(struct ath_hw *ah) return -ENOMEM; #ifdef CONFIG_ATH_DEBUG - if (!debugfs_create_file("debug", S_IRUSR | S_IWUSR, - sc->debug.debugfs_phy, sc, &fops_debug)) - goto err; + debugfs_create_file("debug", S_IRUSR | S_IWUSR, sc->debug.debugfs_phy, + sc, &fops_debug); #endif - - if (!debugfs_create_file("dma", S_IRUSR, sc->debug.debugfs_phy, - sc, &fops_dma)) - goto err; - - if (!debugfs_create_file("interrupt", S_IRUSR, sc->debug.debugfs_phy, - sc, &fops_interrupt)) - goto err; - - if (!debugfs_create_file("wiphy", S_IRUSR | S_IWUSR, - sc->debug.debugfs_phy, sc, &fops_wiphy)) - goto err; - - if (!debugfs_create_file("xmit", S_IRUSR, sc->debug.debugfs_phy, - sc, &fops_xmit)) - goto err; - - if (!debugfs_create_file("stations", S_IRUSR, sc->debug.debugfs_phy, - sc, &fops_stations)) - goto err; - - if (!debugfs_create_file("misc", S_IRUSR, sc->debug.debugfs_phy, - sc, &fops_misc)) - goto err; - - if (!debugfs_create_file("recv", S_IRUSR, sc->debug.debugfs_phy, - sc, &fops_recv)) - goto err; - - if (!debugfs_create_file("rx_chainmask", S_IRUSR | S_IWUSR, - sc->debug.debugfs_phy, sc, &fops_rx_chainmask)) - goto err; - - if (!debugfs_create_file("tx_chainmask", S_IRUSR | S_IWUSR, - sc->debug.debugfs_phy, sc, &fops_tx_chainmask)) - goto err; - - if (!debugfs_create_file("regidx", S_IRUSR | S_IWUSR, - sc->debug.debugfs_phy, sc, &fops_regidx)) - goto err; - - if (!debugfs_create_file("regval", S_IRUSR | S_IWUSR, - sc->debug.debugfs_phy, sc, &fops_regval)) - goto err; - - if (!debugfs_create_bool("ignore_extcca", S_IRUSR | S_IWUSR, - sc->debug.debugfs_phy, &ah->config.cwm_ignore_extcca)) - goto err; - - if (!debugfs_create_file("regdump", S_IRUSR, sc->debug.debugfs_phy, - sc, &fops_regdump)) - goto err; + debugfs_create_file("dma", S_IRUSR, sc->debug.debugfs_phy, sc, + &fops_dma); + debugfs_create_file("interrupt", S_IRUSR, sc->debug.debugfs_phy, sc, + &fops_interrupt); + debugfs_create_file("wiphy", S_IRUSR | S_IWUSR, sc->debug.debugfs_phy, + sc, &fops_wiphy); + debugfs_create_file("xmit", S_IRUSR, sc->debug.debugfs_phy, sc, + &fops_xmit); + debugfs_create_file("stations", S_IRUSR, sc->debug.debugfs_phy, sc, + &fops_stations); + debugfs_create_file("misc", S_IRUSR, sc->debug.debugfs_phy, sc, + &fops_misc); + debugfs_create_file("recv", S_IRUSR, sc->debug.debugfs_phy, sc, + &fops_recv); + debugfs_create_file("rx_chainmask", S_IRUSR | S_IWUSR, + sc->debug.debugfs_phy, sc, &fops_rx_chainmask); + debugfs_create_file("tx_chainmask", S_IRUSR | S_IWUSR, + sc->debug.debugfs_phy, sc, &fops_tx_chainmask); + debugfs_create_file("regidx", S_IRUSR | S_IWUSR, sc->debug.debugfs_phy, + sc, &fops_regidx); + debugfs_create_file("regval", S_IRUSR | S_IWUSR, sc->debug.debugfs_phy, + sc, &fops_regval); + debugfs_create_bool("ignore_extcca", S_IRUSR | S_IWUSR, + sc->debug.debugfs_phy, + &ah->config.cwm_ignore_extcca); + debugfs_create_file("regdump", S_IRUSR, sc->debug.debugfs_phy, sc, + &fops_regdump); sc->debug.regidx = 0; return 0; -err: - debugfs_remove_recursive(sc->debug.debugfs_phy); - sc->debug.debugfs_phy = NULL; - return -ENOMEM; } -- cgit v0.10.2 From 691680b8335fa8995b190676f53e3bcef6477b4a Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Sat, 19 Mar 2011 13:55:38 +0100 Subject: ath9k: add an interface for overriding the value of specific GPIO pins Some devices control antenna settings or other things through GPIO pins of the wireless interface. Add a debugfs interface for changing those and keeping them set across card resets. Signed-off-by: Felix Fietkau Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/debug.c b/drivers/net/wireless/ath/ath9k/debug.c index 9fe8693..a762cad 100644 --- a/drivers/net/wireless/ath/ath9k/debug.c +++ b/drivers/net/wireless/ath/ath9k/debug.c @@ -1119,6 +1119,12 @@ int ath9k_init_debug(struct ath_hw *ah) debugfs_create_file("regdump", S_IRUSR, sc->debug.debugfs_phy, sc, &fops_regdump); + debugfs_create_u32("gpio_mask", S_IRUSR | S_IWUSR, + sc->debug.debugfs_phy, &sc->sc_ah->gpio_mask); + + debugfs_create_u32("gpio_val", S_IRUSR | S_IWUSR, + sc->debug.debugfs_phy, &sc->sc_ah->gpio_val); + sc->debug.regidx = 0; return 0; } diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index 338b075..b170c45 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c @@ -1212,6 +1212,20 @@ static bool ath9k_hw_channel_change(struct ath_hw *ah, return true; } +static void ath9k_hw_apply_gpio_override(struct ath_hw *ah) +{ + u32 gpio_mask = ah->gpio_mask; + int i; + + for (i = 0; gpio_mask; i++, gpio_mask >>= 1) { + if (!(gpio_mask & 1)) + continue; + + ath9k_hw_cfg_output(ah, i, AR_GPIO_OUTPUT_MUX_AS_OUTPUT); + ath9k_hw_set_gpio(ah, i, !!(ah->gpio_val & BIT(i))); + } +} + bool ath9k_hw_check_alive(struct ath_hw *ah) { int count = 50; @@ -1500,6 +1514,8 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan, if (AR_SREV_9300_20_OR_LATER(ah)) ar9003_hw_bb_watchdog_config(ah); + ath9k_hw_apply_gpio_override(ah); + return 0; } EXPORT_SYMBOL(ath9k_hw_reset); diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h index c86eea2..775c0eb 100644 --- a/drivers/net/wireless/ath/ath9k/hw.h +++ b/drivers/net/wireless/ath/ath9k/hw.h @@ -799,6 +799,8 @@ struct ath_hw { int initPDADC; int PDADCdelta; u8 led_pin; + u32 gpio_mask; + u32 gpio_val; struct ar5416IniArray iniModes; struct ar5416IniArray iniCommon; -- cgit v0.10.2 From 6fb1b1e18fe3d141c54182c5d5b3af823bed455f Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Sat, 19 Mar 2011 13:55:39 +0100 Subject: ath9k: add support for overriding the MAC address through platform data On some devices the correct MAC address is not in the EEPROM data, but stored somewhere else. Signed-off-by: Felix Fietkau Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/init.c b/drivers/net/wireless/ath/ath9k/init.c index 79aec983..e22e821 100644 --- a/drivers/net/wireless/ath/ath9k/init.c +++ b/drivers/net/wireless/ath/ath9k/init.c @@ -15,6 +15,7 @@ */ #include +#include #include "ath9k.h" @@ -537,6 +538,7 @@ static void ath9k_init_misc(struct ath_softc *sc) static int ath9k_init_softc(u16 devid, struct ath_softc *sc, u16 subsysid, const struct ath_bus_ops *bus_ops) { + struct ath9k_platform_data *pdata = sc->dev->platform_data; struct ath_hw *ah = NULL; struct ath_common *common; int ret = 0, i; @@ -551,7 +553,7 @@ static int ath9k_init_softc(u16 devid, struct ath_softc *sc, u16 subsysid, ah->hw_version.subsysid = subsysid; sc->sc_ah = ah; - if (!sc->dev->platform_data) + if (!pdata) ah->ah_flags |= AH_USE_EEPROM; common = ath9k_hw_common(ah); @@ -587,6 +589,9 @@ static int ath9k_init_softc(u16 devid, struct ath_softc *sc, u16 subsysid, if (ret) goto err_hw; + if (pdata && pdata->macaddr) + memcpy(common->macaddr, pdata->macaddr, ETH_ALEN); + ret = ath9k_init_queues(sc); if (ret) goto err_queues; diff --git a/include/linux/ath9k_platform.h b/include/linux/ath9k_platform.h index b847fc7..b5f0658 100644 --- a/include/linux/ath9k_platform.h +++ b/include/linux/ath9k_platform.h @@ -23,6 +23,7 @@ struct ath9k_platform_data { u16 eeprom_data[ATH9K_PLAT_EEP_MAX_WORDS]; + u8 *macaddr; }; #endif /* _LINUX_ATH9K_PLATFORM_H */ -- cgit v0.10.2 From 6de66dd963ddd669667a81a2401f2fd6472ff55c Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Sat, 19 Mar 2011 13:55:40 +0100 Subject: ath9k: add support for overriding LED pin and GPIO settings from platform data Signed-off-by: Felix Fietkau Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/gpio.c b/drivers/net/wireless/ath/ath9k/gpio.c index 0fb8f8a..44a0a88 100644 --- a/drivers/net/wireless/ath/ath9k/gpio.c +++ b/drivers/net/wireless/ath/ath9k/gpio.c @@ -41,12 +41,14 @@ void ath_init_leds(struct ath_softc *sc) { int ret; - if (AR_SREV_9287(sc->sc_ah)) - sc->sc_ah->led_pin = ATH_LED_PIN_9287; - else if (AR_SREV_9485(sc->sc_ah)) - sc->sc_ah->led_pin = ATH_LED_PIN_9485; - else - sc->sc_ah->led_pin = ATH_LED_PIN_DEF; + if (sc->sc_ah->led_pin < 0) { + if (AR_SREV_9287(sc->sc_ah)) + sc->sc_ah->led_pin = ATH_LED_PIN_9287; + else if (AR_SREV_9485(sc->sc_ah)) + sc->sc_ah->led_pin = ATH_LED_PIN_9485; + else + sc->sc_ah->led_pin = ATH_LED_PIN_DEF; + } /* Configure gpio 1 for output */ ath9k_hw_cfg_output(sc->sc_ah, sc->sc_ah->led_pin, diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h index 775c0eb..3d9fc6e 100644 --- a/drivers/net/wireless/ath/ath9k/hw.h +++ b/drivers/net/wireless/ath/ath9k/hw.h @@ -798,7 +798,7 @@ struct ath_hw { u32 originalGain[22]; int initPDADC; int PDADCdelta; - u8 led_pin; + int led_pin; u32 gpio_mask; u32 gpio_val; diff --git a/drivers/net/wireless/ath/ath9k/init.c b/drivers/net/wireless/ath/ath9k/init.c index e22e821..cdb0f1c 100644 --- a/drivers/net/wireless/ath/ath9k/init.c +++ b/drivers/net/wireless/ath/ath9k/init.c @@ -553,8 +553,14 @@ static int ath9k_init_softc(u16 devid, struct ath_softc *sc, u16 subsysid, ah->hw_version.subsysid = subsysid; sc->sc_ah = ah; - if (!pdata) + if (!pdata) { ah->ah_flags |= AH_USE_EEPROM; + sc->sc_ah->led_pin = -1; + } else { + sc->sc_ah->gpio_mask = pdata->gpio_mask; + sc->sc_ah->gpio_val = pdata->gpio_val; + sc->sc_ah->led_pin = pdata->led_pin; + } common = ath9k_hw_common(ah); common->ops = &ath9k_common_ops; diff --git a/include/linux/ath9k_platform.h b/include/linux/ath9k_platform.h index b5f0658..020387a 100644 --- a/include/linux/ath9k_platform.h +++ b/include/linux/ath9k_platform.h @@ -24,6 +24,10 @@ struct ath9k_platform_data { u16 eeprom_data[ATH9K_PLAT_EEP_MAX_WORDS]; u8 *macaddr; + + int led_pin; + u32 gpio_mask; + u32 gpio_val; }; #endif /* _LINUX_ATH9K_PLATFORM_H */ -- cgit v0.10.2 From f171760c558946c7a2e0ee310dfb968f9d4853c6 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Sat, 19 Mar 2011 13:55:41 +0100 Subject: ath9k_hw: enable a BlockAck related fixup specific to AR9100 Fixes interop issues with aggregation in combination with multi-BSSID Signed-off-by: Felix Fietkau Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index b170c45..175c36f 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c @@ -410,6 +410,8 @@ static void ath9k_hw_init_defaults(struct ath_hw *ah) ah->sta_id1_defaults = AR_STA_ID1_CRPT_MIC_ENABLE | AR_STA_ID1_MCAST_KSRCH; + if (AR_SREV_9100(ah)) + ah->sta_id1_defaults |= AR_STA_ID1_AR9100_BA_FIX; ah->enable_32kHz_clock = DONT_USE_32KHZ; ah->slottime = 20; ah->globaltxtimeout = (u32) -1; diff --git a/drivers/net/wireless/ath/ath9k/reg.h b/drivers/net/wireless/ath/ath9k/reg.h index 8fa8acf..693d543 100644 --- a/drivers/net/wireless/ath/ath9k/reg.h +++ b/drivers/net/wireless/ath/ath9k/reg.h @@ -1396,6 +1396,7 @@ enum { #define AR_STA_ID1_PCF 0x00100000 #define AR_STA_ID1_USE_DEFANT 0x00200000 #define AR_STA_ID1_DEFANT_UPDATE 0x00400000 +#define AR_STA_ID1_AR9100_BA_FIX 0x00400000 #define AR_STA_ID1_RTS_USE_DEF 0x00800000 #define AR_STA_ID1_ACKCTS_6MB 0x01000000 #define AR_STA_ID1_BASE_RATE_11B 0x02000000 -- cgit v0.10.2 From 598cdd5246ea158310942699e5008ac7f687ad62 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Sat, 19 Mar 2011 13:55:42 +0100 Subject: ath9k_hw: force rx chainmask to 7 on AR9100 Most AR9100 devices already have a chainmask of 7 (three antennas), however on the ones that don't (rx and tx chainmask set to 5), problems with IQ mismatch calibration have been observed. This shows up as tx queue hangs (and subsequent hardware resets) if traffic is sent during this type of calibration. Forcing the rx chainmask to 7 fixes the calibration issues with no apparent negative side effects on throughput and stability. Signed-off-by: Felix Fietkau Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index 175c36f..8b86568 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c @@ -1869,6 +1869,8 @@ int ath9k_hw_fill_cap_info(struct ath_hw *ah) !(AR_SREV_9271(ah))) /* CB71: GPIO 0 is pulled down to indicate 3 rx chains */ pCap->rx_chainmask = ath9k_hw_gpio_get(ah, 0) ? 0x5 : 0x7; + else if (AR_SREV_9100(ah)) + pCap->rx_chainmask = 0x7; else /* Use rx_chainmask from EEPROM. */ pCap->rx_chainmask = ah->eep_ops->get_eeprom(ah, EEP_RX_MASK); -- cgit v0.10.2 From a9cbe96d19861755680a712b709cccac5dc6aca8 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Sat, 19 Mar 2011 13:55:43 +0100 Subject: ath9k: remove the pending frames ath_txq_schedule workaround This workaround called ath_txq_schedule whenever there were still pending frames for a queue, but the queue depth was zero. Because of its its high false positive probability (e.g. with paused TIDs) and because it is in the way of other pending work (AP powersave fixes), it is better to remove this code entirely. Signed-off-by: Felix Fietkau Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c index 26734e5..f916f08 100644 --- a/drivers/net/wireless/ath/ath9k/xmit.c +++ b/drivers/net/wireless/ath/ath9k/xmit.c @@ -2144,33 +2144,6 @@ static void ath_tx_complete_poll_work(struct work_struct *work) } else { txq->axq_tx_inprogress = true; } - } else { - /* If the queue has pending buffers, then it - * should be doing tx work (and have axq_depth). - * Shouldn't get to this state I think..but - * we do. - */ - if (!(sc->sc_flags & (SC_OP_OFFCHANNEL)) && - (txq->pending_frames > 0 || - !list_empty(&txq->axq_acq) || - txq->stopped)) { - ath_err(ath9k_hw_common(sc->sc_ah), - "txq: %p axq_qnum: %u," - " mac80211_qnum: %i" - " axq_link: %p" - " pending frames: %i" - " axq_acq empty: %i" - " stopped: %i" - " axq_depth: 0 Attempting to" - " restart tx logic.\n", - txq, txq->axq_qnum, - txq->mac80211_qnum, - txq->axq_link, - txq->pending_frames, - list_empty(&txq->axq_acq), - txq->stopped); - ath_txq_schedule(sc, txq); - } } spin_unlock_bh(&txq->axq_lock); } -- cgit v0.10.2 From be7974aa105dc47bb25013016d1fcad17da17783 Mon Sep 17 00:00:00 2001 From: Helmut Schaa Date: Mon, 21 Mar 2011 15:07:55 +0100 Subject: mac80211: Minor optimization in tx status handling ieee80211_tx_status iterates over all tx rates the driver reports back in order to 1) mark tx rates as invalid if the driver cannot have tried that rate 2) find the actually used tx rate for the final retransmission By leaving the for loop when the first invalid rate index is found we can move the rates_idx assignment after the loop and therefore save a few assignments and conditionals. Signed-off-by: Helmut Schaa Signed-off-by: John W. Linville diff --git a/net/mac80211/status.c b/net/mac80211/status.c index b936dd2..3ed3c83 100644 --- a/net/mac80211/status.c +++ b/net/mac80211/status.c @@ -189,16 +189,19 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb) bool acked; for (i = 0; i < IEEE80211_TX_MAX_RATES; i++) { - /* the HW cannot have attempted that rate */ - if (i >= hw->max_report_rates) { + if (info->status.rates[i].idx < 0) { + break; + } else if (i >= hw->max_report_rates) { + /* the HW cannot have attempted that rate */ info->status.rates[i].idx = -1; info->status.rates[i].count = 0; - } else if (info->status.rates[i].idx >= 0) { - rates_idx = i; + break; } retry_count += info->status.rates[i].count; } + rates_idx = i - 1; + if (retry_count < 0) retry_count = 0; -- cgit v0.10.2 From 903946e6e21ef4dd678acafb8881cabde9182caf Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Mon, 21 Mar 2011 17:27:35 -0700 Subject: ath9k_hw: remove AR9485 1.0 support Only AR9485 1.1 was sold. This debloats the driver by ~14 KiB. text data bss dec hex filename 300413 624 1056 302093 49c0d drivers/net/wireless/ath/ath9k/ath9k_hw.ko text data bss dec hex filename 310285 624 1056 311965 4c29d drivers/net/wireless/ath/ath9k/ath9k_hw-old.ko $ du -b ath9k_hw* 6210541 ath9k_hw.ko 6225089 ath9k_hw-old.ko Cc: Bill Wu Cc: Paul Shaw Cc: Forbes Tsai Cc: Jesmine Chen Cc: Marvian Chen Cc: Vivek Natarajan Cc: Bernadette Yetso Cc: Sarvesh Shrivastava Acked-by: Yi-Chen Su Acked-by: Jeffrey Chung Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/ar9003_hw.c b/drivers/net/wireless/ath/ath9k/ar9003_hw.c index 7f5de6e..3daf3df 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_hw.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_hw.c @@ -88,66 +88,6 @@ static void ar9003_hw_init_mode_regs(struct ath_hw *ah) ar9485_1_1_pcie_phy_clkreq_disable_L1, ARRAY_SIZE(ar9485_1_1_pcie_phy_clkreq_disable_L1), 2); - } else if (AR_SREV_9485(ah)) { - /* mac */ - INIT_INI_ARRAY(&ah->iniMac[ATH_INI_PRE], NULL, 0, 0); - INIT_INI_ARRAY(&ah->iniMac[ATH_INI_CORE], - ar9485_1_0_mac_core, - ARRAY_SIZE(ar9485_1_0_mac_core), 2); - INIT_INI_ARRAY(&ah->iniMac[ATH_INI_POST], - ar9485_1_0_mac_postamble, - ARRAY_SIZE(ar9485_1_0_mac_postamble), 5); - - /* bb */ - INIT_INI_ARRAY(&ah->iniBB[ATH_INI_PRE], ar9485_1_0, - ARRAY_SIZE(ar9485_1_0), 2); - INIT_INI_ARRAY(&ah->iniBB[ATH_INI_CORE], - ar9485_1_0_baseband_core, - ARRAY_SIZE(ar9485_1_0_baseband_core), 2); - INIT_INI_ARRAY(&ah->iniBB[ATH_INI_POST], - ar9485_1_0_baseband_postamble, - ARRAY_SIZE(ar9485_1_0_baseband_postamble), 5); - - /* radio */ - INIT_INI_ARRAY(&ah->iniRadio[ATH_INI_PRE], NULL, 0, 0); - INIT_INI_ARRAY(&ah->iniRadio[ATH_INI_CORE], - ar9485_1_0_radio_core, - ARRAY_SIZE(ar9485_1_0_radio_core), 2); - INIT_INI_ARRAY(&ah->iniRadio[ATH_INI_POST], - ar9485_1_0_radio_postamble, - ARRAY_SIZE(ar9485_1_0_radio_postamble), 2); - - /* soc */ - INIT_INI_ARRAY(&ah->iniSOC[ATH_INI_PRE], - ar9485_1_0_soc_preamble, - ARRAY_SIZE(ar9485_1_0_soc_preamble), 2); - INIT_INI_ARRAY(&ah->iniSOC[ATH_INI_CORE], NULL, 0, 0); - INIT_INI_ARRAY(&ah->iniSOC[ATH_INI_POST], NULL, 0, 0); - - /* rx/tx gain */ - INIT_INI_ARRAY(&ah->iniModesRxGain, - ar9485Common_rx_gain_1_0, - ARRAY_SIZE(ar9485Common_rx_gain_1_0), 2); - INIT_INI_ARRAY(&ah->iniModesTxGain, - ar9485Modes_lowest_ob_db_tx_gain_1_0, - ARRAY_SIZE(ar9485Modes_lowest_ob_db_tx_gain_1_0), - 5); - - /* Load PCIE SERDES settings from INI */ - - /* Awake Setting */ - - INIT_INI_ARRAY(&ah->iniPcieSerdes, - ar9485_1_0_pcie_phy_pll_on_clkreq_disable_L1, - ARRAY_SIZE(ar9485_1_0_pcie_phy_pll_on_clkreq_disable_L1), - 2); - - /* Sleep Setting */ - - INIT_INI_ARRAY(&ah->iniPcieSerdesLowPower, - ar9485_1_0_pcie_phy_pll_on_clkreq_disable_L1, - ARRAY_SIZE(ar9485_1_0_pcie_phy_pll_on_clkreq_disable_L1), - 2); } else { /* mac */ INIT_INI_ARRAY(&ah->iniMac[ATH_INI_PRE], NULL, 0, 0); @@ -228,11 +168,6 @@ static void ar9003_tx_gain_table_apply(struct ath_hw *ah) ar9485_modes_lowest_ob_db_tx_gain_1_1, ARRAY_SIZE(ar9485_modes_lowest_ob_db_tx_gain_1_1), 5); - else if (AR_SREV_9485(ah)) - INIT_INI_ARRAY(&ah->iniModesTxGain, - ar9485Modes_lowest_ob_db_tx_gain_1_0, - ARRAY_SIZE(ar9485Modes_lowest_ob_db_tx_gain_1_0), - 5); else INIT_INI_ARRAY(&ah->iniModesTxGain, ar9300Modes_lowest_ob_db_tx_gain_table_2p2, @@ -245,11 +180,6 @@ static void ar9003_tx_gain_table_apply(struct ath_hw *ah) ar9485Modes_high_ob_db_tx_gain_1_1, ARRAY_SIZE(ar9485Modes_high_ob_db_tx_gain_1_1), 5); - else if (AR_SREV_9485(ah)) - INIT_INI_ARRAY(&ah->iniModesTxGain, - ar9485Modes_high_ob_db_tx_gain_1_0, - ARRAY_SIZE(ar9485Modes_high_ob_db_tx_gain_1_0), - 5); else INIT_INI_ARRAY(&ah->iniModesTxGain, ar9300Modes_high_ob_db_tx_gain_table_2p2, @@ -262,11 +192,6 @@ static void ar9003_tx_gain_table_apply(struct ath_hw *ah) ar9485Modes_low_ob_db_tx_gain_1_1, ARRAY_SIZE(ar9485Modes_low_ob_db_tx_gain_1_1), 5); - else if (AR_SREV_9485(ah)) - INIT_INI_ARRAY(&ah->iniModesTxGain, - ar9485Modes_low_ob_db_tx_gain_1_0, - ARRAY_SIZE(ar9485Modes_low_ob_db_tx_gain_1_0), - 5); else INIT_INI_ARRAY(&ah->iniModesTxGain, ar9300Modes_low_ob_db_tx_gain_table_2p2, @@ -279,11 +204,6 @@ static void ar9003_tx_gain_table_apply(struct ath_hw *ah) ar9485Modes_high_power_tx_gain_1_1, ARRAY_SIZE(ar9485Modes_high_power_tx_gain_1_1), 5); - else if (AR_SREV_9485(ah)) - INIT_INI_ARRAY(&ah->iniModesTxGain, - ar9485Modes_high_power_tx_gain_1_0, - ARRAY_SIZE(ar9485Modes_high_power_tx_gain_1_0), - 5); else INIT_INI_ARRAY(&ah->iniModesTxGain, ar9300Modes_high_power_tx_gain_table_2p2, @@ -303,11 +223,6 @@ static void ar9003_rx_gain_table_apply(struct ath_hw *ah) ar9485_common_rx_gain_1_1, ARRAY_SIZE(ar9485_common_rx_gain_1_1), 2); - else if (AR_SREV_9485(ah)) - INIT_INI_ARRAY(&ah->iniModesRxGain, - ar9485Common_rx_gain_1_0, - ARRAY_SIZE(ar9485Common_rx_gain_1_0), - 2); else INIT_INI_ARRAY(&ah->iniModesRxGain, ar9300Common_rx_gain_table_2p2, @@ -320,11 +235,6 @@ static void ar9003_rx_gain_table_apply(struct ath_hw *ah) ar9485Common_wo_xlna_rx_gain_1_1, ARRAY_SIZE(ar9485Common_wo_xlna_rx_gain_1_1), 2); - else if (AR_SREV_9485(ah)) - INIT_INI_ARRAY(&ah->iniModesRxGain, - ar9485Common_wo_xlna_rx_gain_1_0, - ARRAY_SIZE(ar9485Common_wo_xlna_rx_gain_1_0), - 2); else INIT_INI_ARRAY(&ah->iniModesRxGain, ar9300Common_wo_xlna_rx_gain_table_2p2, diff --git a/drivers/net/wireless/ath/ath9k/ar9485_initvals.h b/drivers/net/wireless/ath/ath9k/ar9485_initvals.h index 71cc0a3..f91f73e 100644 --- a/drivers/net/wireless/ath/ath9k/ar9485_initvals.h +++ b/drivers/net/wireless/ath/ath9k/ar9485_initvals.h @@ -17,931 +17,6 @@ #ifndef INITVALS_9485_H #define INITVALS_9485_H -static const u32 ar9485Common_1_0[][2] = { - /* Addr allmodes */ - {0x00007010, 0x00000022}, - {0x00007020, 0x00000000}, - {0x00007034, 0x00000002}, - {0x00007038, 0x000004c2}, -}; - -static const u32 ar9485_1_0_mac_postamble[][5] = { - /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ - {0x00001030, 0x00000230, 0x00000460, 0x000002c0, 0x00000160}, - {0x00001070, 0x00000168, 0x000002d0, 0x00000318, 0x0000018c}, - {0x000010b0, 0x00000e60, 0x00001cc0, 0x00007c70, 0x00003e38}, - {0x00008014, 0x03e803e8, 0x07d007d0, 0x10801600, 0x08400b00}, - {0x0000801c, 0x128d8027, 0x128d804f, 0x12e00057, 0x12e0002b}, - {0x00008120, 0x08f04800, 0x08f04800, 0x08f04810, 0x08f04810}, - {0x000081d0, 0x00003210, 0x00003210, 0x0000320a, 0x0000320a}, - {0x00008318, 0x00003e80, 0x00007d00, 0x00006880, 0x00003440}, -}; - -static const u32 ar9485_1_0_pcie_phy_pll_on_clkreq_disable_L1[][2] = { - /* Addr allmodes */ - {0x00018c00, 0x10212e5e}, - {0x00018c04, 0x000801d8}, - {0x00018c08, 0x0000580c}, -}; - -static const u32 ar9485Common_wo_xlna_rx_gain_1_0[][2] = { - /* Addr allmodes */ - {0x0000a000, 0x00010000}, - {0x0000a004, 0x00030002}, - {0x0000a008, 0x00050004}, - {0x0000a00c, 0x00810080}, - {0x0000a010, 0x01800082}, - {0x0000a014, 0x01820181}, - {0x0000a018, 0x01840183}, - {0x0000a01c, 0x01880185}, - {0x0000a020, 0x018a0189}, - {0x0000a024, 0x02850284}, - {0x0000a028, 0x02890288}, - {0x0000a02c, 0x03850384}, - {0x0000a030, 0x03890388}, - {0x0000a034, 0x038b038a}, - {0x0000a038, 0x038d038c}, - {0x0000a03c, 0x03910390}, - {0x0000a040, 0x03930392}, - {0x0000a044, 0x03950394}, - {0x0000a048, 0x00000396}, - {0x0000a04c, 0x00000000}, - {0x0000a050, 0x00000000}, - {0x0000a054, 0x00000000}, - {0x0000a058, 0x00000000}, - {0x0000a05c, 0x00000000}, - {0x0000a060, 0x00000000}, - {0x0000a064, 0x00000000}, - {0x0000a068, 0x00000000}, - {0x0000a06c, 0x00000000}, - {0x0000a070, 0x00000000}, - {0x0000a074, 0x00000000}, - {0x0000a078, 0x00000000}, - {0x0000a07c, 0x00000000}, - {0x0000a080, 0x28282828}, - {0x0000a084, 0x28282828}, - {0x0000a088, 0x28282828}, - {0x0000a08c, 0x28282828}, - {0x0000a090, 0x28282828}, - {0x0000a094, 0x21212128}, - {0x0000a098, 0x171c1c1c}, - {0x0000a09c, 0x02020212}, - {0x0000a0a0, 0x00000202}, - {0x0000a0a4, 0x00000000}, - {0x0000a0a8, 0x00000000}, - {0x0000a0ac, 0x00000000}, - {0x0000a0b0, 0x00000000}, - {0x0000a0b4, 0x00000000}, - {0x0000a0b8, 0x00000000}, - {0x0000a0bc, 0x00000000}, - {0x0000a0c0, 0x001f0000}, - {0x0000a0c4, 0x111f1100}, - {0x0000a0c8, 0x111d111e}, - {0x0000a0cc, 0x111b111c}, - {0x0000a0d0, 0x22032204}, - {0x0000a0d4, 0x22012202}, - {0x0000a0d8, 0x221f2200}, - {0x0000a0dc, 0x221d221e}, - {0x0000a0e0, 0x33013302}, - {0x0000a0e4, 0x331f3300}, - {0x0000a0e8, 0x4402331e}, - {0x0000a0ec, 0x44004401}, - {0x0000a0f0, 0x441e441f}, - {0x0000a0f4, 0x55015502}, - {0x0000a0f8, 0x551f5500}, - {0x0000a0fc, 0x6602551e}, - {0x0000a100, 0x66006601}, - {0x0000a104, 0x661e661f}, - {0x0000a108, 0x7703661d}, - {0x0000a10c, 0x77017702}, - {0x0000a110, 0x00007700}, - {0x0000a114, 0x00000000}, - {0x0000a118, 0x00000000}, - {0x0000a11c, 0x00000000}, - {0x0000a120, 0x00000000}, - {0x0000a124, 0x00000000}, - {0x0000a128, 0x00000000}, - {0x0000a12c, 0x00000000}, - {0x0000a130, 0x00000000}, - {0x0000a134, 0x00000000}, - {0x0000a138, 0x00000000}, - {0x0000a13c, 0x00000000}, - {0x0000a140, 0x001f0000}, - {0x0000a144, 0x111f1100}, - {0x0000a148, 0x111d111e}, - {0x0000a14c, 0x111b111c}, - {0x0000a150, 0x22032204}, - {0x0000a154, 0x22012202}, - {0x0000a158, 0x221f2200}, - {0x0000a15c, 0x221d221e}, - {0x0000a160, 0x33013302}, - {0x0000a164, 0x331f3300}, - {0x0000a168, 0x4402331e}, - {0x0000a16c, 0x44004401}, - {0x0000a170, 0x441e441f}, - {0x0000a174, 0x55015502}, - {0x0000a178, 0x551f5500}, - {0x0000a17c, 0x6602551e}, - {0x0000a180, 0x66006601}, - {0x0000a184, 0x661e661f}, - {0x0000a188, 0x7703661d}, - {0x0000a18c, 0x77017702}, - {0x0000a190, 0x00007700}, - {0x0000a194, 0x00000000}, - {0x0000a198, 0x00000000}, - {0x0000a19c, 0x00000000}, - {0x0000a1a0, 0x00000000}, - {0x0000a1a4, 0x00000000}, - {0x0000a1a8, 0x00000000}, - {0x0000a1ac, 0x00000000}, - {0x0000a1b0, 0x00000000}, - {0x0000a1b4, 0x00000000}, - {0x0000a1b8, 0x00000000}, - {0x0000a1bc, 0x00000000}, - {0x0000a1c0, 0x00000000}, - {0x0000a1c4, 0x00000000}, - {0x0000a1c8, 0x00000000}, - {0x0000a1cc, 0x00000000}, - {0x0000a1d0, 0x00000000}, - {0x0000a1d4, 0x00000000}, - {0x0000a1d8, 0x00000000}, - {0x0000a1dc, 0x00000000}, - {0x0000a1e0, 0x00000000}, - {0x0000a1e4, 0x00000000}, - {0x0000a1e8, 0x00000000}, - {0x0000a1ec, 0x00000000}, - {0x0000a1f0, 0x00000396}, - {0x0000a1f4, 0x00000396}, - {0x0000a1f8, 0x00000396}, - {0x0000a1fc, 0x00000296}, -}; - -static const u32 ar9485Modes_high_power_tx_gain_1_0[][5] = { - /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ - {0x0000a410, 0x000050d9, 0x000050d9, 0x000050d8, 0x000050d8}, - {0x0000a500, 0x00022200, 0x00022200, 0x00000000, 0x00000000}, - {0x0000a504, 0x05062002, 0x05062002, 0x04000002, 0x04000002}, - {0x0000a508, 0x0c002e00, 0x0c002e00, 0x08000004, 0x08000004}, - {0x0000a50c, 0x11062202, 0x11062202, 0x0d000200, 0x0d000200}, - {0x0000a510, 0x17022e00, 0x17022e00, 0x11000202, 0x11000202}, - {0x0000a514, 0x1d000ec2, 0x1d000ec2, 0x15000400, 0x15000400}, - {0x0000a518, 0x25020ec0, 0x25020ec0, 0x19000402, 0x19000402}, - {0x0000a51c, 0x2b020ec3, 0x2b020ec3, 0x1d000404, 0x1d000404}, - {0x0000a520, 0x2f001f04, 0x2f001f04, 0x21000603, 0x21000603}, - {0x0000a524, 0x35001fc4, 0x35001fc4, 0x25000605, 0x25000605}, - {0x0000a528, 0x3c022f04, 0x3c022f04, 0x2a000a03, 0x2a000a03}, - {0x0000a52c, 0x41023e85, 0x41023e85, 0x2c000a04, 0x2c000a04}, - {0x0000a530, 0x48023ec6, 0x48023ec6, 0x2e000a20, 0x2e000a20}, - {0x0000a534, 0x4d023f01, 0x4d023f01, 0x34000e20, 0x34000e20}, - {0x0000a538, 0x53023f4b, 0x53023f4b, 0x38000e22, 0x38000e22}, - {0x0000a53c, 0x5a027f09, 0x5a027f09, 0x3c000e24, 0x3c000e24}, - {0x0000a540, 0x5f027fc9, 0x5f027fc9, 0x40000e26, 0x40000e26}, - {0x0000a544, 0x6502feca, 0x6502feca, 0x43001640, 0x43001640}, - {0x0000a548, 0x6b02ff4a, 0x6b02ff4a, 0x46001660, 0x46001660}, - {0x0000a54c, 0x7203feca, 0x7203feca, 0x49001861, 0x49001861}, - {0x0000a550, 0x7703ff0b, 0x7703ff0b, 0x4c001a81, 0x4c001a81}, - {0x0000a554, 0x7d06ffcb, 0x7d06ffcb, 0x4f001a83, 0x4f001a83}, - {0x0000a558, 0x8407ff0b, 0x8407ff0b, 0x54001c85, 0x54001c85}, - {0x0000a55c, 0x8907ffcb, 0x8907ffcb, 0x58001ce5, 0x58001ce5}, - {0x0000a560, 0x900fff0b, 0x900fff0b, 0x5b001ce9, 0x5b001ce9}, - {0x0000a564, 0x960fffcb, 0x960fffcb, 0x60001eeb, 0x60001eeb}, - {0x0000a568, 0x9c1fff0b, 0x9c1fff0b, 0x60001eeb, 0x60001eeb}, - {0x0000a56c, 0x9c1fff0b, 0x9c1fff0b, 0x60001eeb, 0x60001eeb}, - {0x0000a570, 0x9c1fff0b, 0x9c1fff0b, 0x60001eeb, 0x60001eeb}, - {0x0000a574, 0x9c1fff0b, 0x9c1fff0b, 0x60001eeb, 0x60001eeb}, - {0x0000a578, 0x9c1fff0b, 0x9c1fff0b, 0x60001eeb, 0x60001eeb}, - {0x0000a57c, 0x9c1fff0b, 0x9c1fff0b, 0x60001eeb, 0x60001eeb}, - {0x00016044, 0x05b6b2db, 0x05b6b2db, 0x05b6b2db, 0x05b6b2db}, -}; - -static const u32 ar9485_1_0[][2] = { - /* Addr allmodes */ - {0x0000a580, 0x00000000}, - {0x0000a584, 0x00000000}, - {0x0000a588, 0x00000000}, - {0x0000a58c, 0x00000000}, - {0x0000a590, 0x00000000}, - {0x0000a594, 0x00000000}, - {0x0000a598, 0x00000000}, - {0x0000a59c, 0x00000000}, - {0x0000a5a0, 0x00000000}, - {0x0000a5a4, 0x00000000}, - {0x0000a5a8, 0x00000000}, - {0x0000a5ac, 0x00000000}, - {0x0000a5b0, 0x00000000}, - {0x0000a5b4, 0x00000000}, - {0x0000a5b8, 0x00000000}, - {0x0000a5bc, 0x00000000}, -}; - -static const u32 ar9485_1_0_radio_core[][2] = { - /* Addr allmodes */ - {0x00016000, 0x36db6db6}, - {0x00016004, 0x6db6db40}, - {0x00016008, 0x73800000}, - {0x0001600c, 0x00000000}, - {0x00016040, 0x7f80fff8}, - {0x00016048, 0x6c92426e}, - {0x0001604c, 0x000f0278}, - {0x00016050, 0x6db6db6c}, - {0x00016054, 0x6db60000}, - {0x00016080, 0x00080000}, - {0x00016084, 0x0e48048c}, - {0x00016088, 0x14214514}, - {0x0001608c, 0x119f081e}, - {0x00016090, 0x24926490}, - {0x00016098, 0xd28b3330}, - {0x000160a0, 0xc2108ffe}, - {0x000160a4, 0x812fc370}, - {0x000160a8, 0x423c8000}, - {0x000160b4, 0x92480040}, - {0x000160c0, 0x006db6db}, - {0x000160c4, 0x0186db60}, - {0x000160c8, 0x6db6db6c}, - {0x000160cc, 0x6de6fbe0}, - {0x000160d0, 0xf7dfcf3c}, - {0x00016100, 0x04cb0001}, - {0x00016104, 0xfff80015}, - {0x00016108, 0x00080010}, - {0x00016144, 0x01884080}, - {0x00016148, 0x00008040}, - {0x00016180, 0x08453333}, - {0x00016184, 0x18e82f01}, - {0x00016188, 0x00000000}, - {0x0001618c, 0x00000000}, - {0x00016240, 0x08400000}, - {0x00016244, 0x1bf90f00}, - {0x00016248, 0x00000000}, - {0x0001624c, 0x00000000}, - {0x00016280, 0x01000015}, - {0x00016284, 0x00d30000}, - {0x00016288, 0x00318000}, - {0x0001628c, 0x50000000}, - {0x00016290, 0x4b96210f}, - {0x00016380, 0x00000000}, - {0x00016384, 0x00000000}, - {0x00016388, 0x00800700}, - {0x0001638c, 0x00800700}, - {0x00016390, 0x00800700}, - {0x00016394, 0x00000000}, - {0x00016398, 0x00000000}, - {0x0001639c, 0x00000000}, - {0x000163a0, 0x00000001}, - {0x000163a4, 0x00000001}, - {0x000163a8, 0x00000000}, - {0x000163ac, 0x00000000}, - {0x000163b0, 0x00000000}, - {0x000163b4, 0x00000000}, - {0x000163b8, 0x00000000}, - {0x000163bc, 0x00000000}, - {0x000163c0, 0x000000a0}, - {0x000163c4, 0x000c0000}, - {0x000163c8, 0x14021402}, - {0x000163cc, 0x00001402}, - {0x000163d0, 0x00000000}, - {0x000163d4, 0x00000000}, - {0x00016c40, 0x1319c178}, - {0x00016c44, 0x10000000}, -}; - -static const u32 ar9485Modes_lowest_ob_db_tx_gain_1_0[][5] = { - /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ - {0x0000a410, 0x000050d9, 0x000050d9, 0x000050d8, 0x000050d8}, - {0x0000a500, 0x00022200, 0x00022200, 0x00000000, 0x00000000}, - {0x0000a504, 0x05062002, 0x05062002, 0x04000002, 0x04000002}, - {0x0000a508, 0x0c002e00, 0x0c002e00, 0x08000004, 0x08000004}, - {0x0000a50c, 0x11062202, 0x11062202, 0x0d000200, 0x0d000200}, - {0x0000a510, 0x17022e00, 0x17022e00, 0x11000202, 0x11000202}, - {0x0000a514, 0x1d000ec2, 0x1d000ec2, 0x15000400, 0x15000400}, - {0x0000a518, 0x25020ec0, 0x25020ec0, 0x19000402, 0x19000402}, - {0x0000a51c, 0x2b020ec3, 0x2b020ec3, 0x1d000404, 0x1d000404}, - {0x0000a520, 0x2f001f04, 0x2f001f04, 0x21000603, 0x21000603}, - {0x0000a524, 0x35001fc4, 0x35001fc4, 0x25000605, 0x25000605}, - {0x0000a528, 0x3c022f04, 0x3c022f04, 0x2a000a03, 0x2a000a03}, - {0x0000a52c, 0x41023e85, 0x41023e85, 0x2c000a04, 0x2c000a04}, - {0x0000a530, 0x48023ec6, 0x48023ec6, 0x2e000a20, 0x2e000a20}, - {0x0000a534, 0x4d023f01, 0x4d023f01, 0x34000e20, 0x34000e20}, - {0x0000a538, 0x53023f4b, 0x53023f4b, 0x38000e22, 0x38000e22}, - {0x0000a53c, 0x5a027f09, 0x5a027f09, 0x3c000e24, 0x3c000e24}, - {0x0000a540, 0x5f027fc9, 0x5f027fc9, 0x40000e26, 0x40000e26}, - {0x0000a544, 0x6502feca, 0x6502feca, 0x43001640, 0x43001640}, - {0x0000a548, 0x6b02ff4a, 0x6b02ff4a, 0x46001660, 0x46001660}, - {0x0000a54c, 0x7203feca, 0x7203feca, 0x49001861, 0x49001861}, - {0x0000a550, 0x7703ff0b, 0x7703ff0b, 0x4c001a81, 0x4c001a81}, - {0x0000a554, 0x7d06ffcb, 0x7d06ffcb, 0x4f001a83, 0x4f001a83}, - {0x0000a558, 0x8407ff0b, 0x8407ff0b, 0x54001c85, 0x54001c85}, - {0x0000a55c, 0x8907ffcb, 0x8907ffcb, 0x58001ce5, 0x58001ce5}, - {0x0000a560, 0x900fff0b, 0x900fff0b, 0x5b001ce9, 0x5b001ce9}, - {0x0000a564, 0x960fffcb, 0x960fffcb, 0x60001eeb, 0x60001eeb}, - {0x0000a568, 0x9c1fff0b, 0x9c1fff0b, 0x60001eeb, 0x60001eeb}, - {0x0000a56c, 0x9c1fff0b, 0x9c1fff0b, 0x60001eeb, 0x60001eeb}, - {0x0000a570, 0x9c1fff0b, 0x9c1fff0b, 0x60001eeb, 0x60001eeb}, - {0x0000a574, 0x9c1fff0b, 0x9c1fff0b, 0x60001eeb, 0x60001eeb}, - {0x0000a578, 0x9c1fff0b, 0x9c1fff0b, 0x60001eeb, 0x60001eeb}, - {0x0000a57c, 0x9c1fff0b, 0x9c1fff0b, 0x60001eeb, 0x60001eeb}, - {0x00016044, 0x05b6b2db, 0x05b6b2db, 0x05b6b2db, 0x05b6b2db}, -}; - -static const u32 ar9485_1_0_baseband_core[][2] = { - /* Addr allmodes */ - {0x00009800, 0xafe68e30}, - {0x00009804, 0xfd14e000}, - {0x00009808, 0x9c0a8f6b}, - {0x0000980c, 0x04800000}, - {0x00009814, 0x9280c00a}, - {0x00009818, 0x00000000}, - {0x0000981c, 0x00020028}, - {0x00009834, 0x5f3ca3de}, - {0x00009838, 0x0108ecff}, - {0x0000983c, 0x14750600}, - {0x00009880, 0x201fff00}, - {0x00009884, 0x00001042}, - {0x000098a4, 0x00200400}, - {0x000098b0, 0x52440bbe}, - {0x000098bc, 0x00000002}, - {0x000098d0, 0x004b6a8e}, - {0x000098d4, 0x00000820}, - {0x000098dc, 0x00000000}, - {0x000098f0, 0x00000000}, - {0x000098f4, 0x00000000}, - {0x00009c04, 0x00000000}, - {0x00009c08, 0x03200000}, - {0x00009c0c, 0x00000000}, - {0x00009c10, 0x00000000}, - {0x00009c14, 0x00046384}, - {0x00009c18, 0x05b6b440}, - {0x00009c1c, 0x00b6b440}, - {0x00009d00, 0xc080a333}, - {0x00009d04, 0x40206c10}, - {0x00009d08, 0x009c4060}, - {0x00009d0c, 0x1883800a}, - {0x00009d10, 0x01834061}, - {0x00009d14, 0x00c00400}, - {0x00009d18, 0x00000000}, - {0x00009d1c, 0x00000000}, - {0x00009e08, 0x0038233c}, - {0x00009e24, 0x990bb515}, - {0x00009e28, 0x0a6f0000}, - {0x00009e30, 0x06336f77}, - {0x00009e34, 0x6af6532f}, - {0x00009e38, 0x0cc80c00}, - {0x00009e40, 0x0d261820}, - {0x00009e4c, 0x00001004}, - {0x00009e50, 0x00ff03f1}, - {0x00009fc0, 0x80be4788}, - {0x00009fc4, 0x0001efb5}, - {0x00009fcc, 0x40000014}, - {0x0000a20c, 0x00000000}, - {0x0000a210, 0x00000000}, - {0x0000a220, 0x00000000}, - {0x0000a224, 0x00000000}, - {0x0000a228, 0x10002310}, - {0x0000a23c, 0x00000000}, - {0x0000a244, 0x0c000000}, - {0x0000a2a0, 0x00000001}, - {0x0000a2c0, 0x00000001}, - {0x0000a2c8, 0x00000000}, - {0x0000a2cc, 0x18c43433}, - {0x0000a2d4, 0x00000000}, - {0x0000a2dc, 0x00000000}, - {0x0000a2e0, 0x00000000}, - {0x0000a2e4, 0x00000000}, - {0x0000a2e8, 0x00000000}, - {0x0000a2ec, 0x00000000}, - {0x0000a2f0, 0x00000000}, - {0x0000a2f4, 0x00000000}, - {0x0000a2f8, 0x00000000}, - {0x0000a344, 0x00000000}, - {0x0000a34c, 0x00000000}, - {0x0000a350, 0x0000a000}, - {0x0000a364, 0x00000000}, - {0x0000a370, 0x00000000}, - {0x0000a390, 0x00000001}, - {0x0000a394, 0x00000444}, - {0x0000a398, 0x001f0e0f}, - {0x0000a39c, 0x0075393f}, - {0x0000a3a0, 0xb79f6427}, - {0x0000a3a4, 0x00000000}, - {0x0000a3a8, 0xaaaaaaaa}, - {0x0000a3ac, 0x3c466478}, - {0x0000a3c0, 0x20202020}, - {0x0000a3c4, 0x22222220}, - {0x0000a3c8, 0x20200020}, - {0x0000a3cc, 0x20202020}, - {0x0000a3d0, 0x20202020}, - {0x0000a3d4, 0x20202020}, - {0x0000a3d8, 0x20202020}, - {0x0000a3dc, 0x20202020}, - {0x0000a3e0, 0x20202020}, - {0x0000a3e4, 0x20202020}, - {0x0000a3e8, 0x20202020}, - {0x0000a3ec, 0x20202020}, - {0x0000a3f0, 0x00000000}, - {0x0000a3f4, 0x00000006}, - {0x0000a3f8, 0x0cdbd380}, - {0x0000a3fc, 0x000f0f01}, - {0x0000a400, 0x8fa91f01}, - {0x0000a404, 0x00000000}, - {0x0000a408, 0x0e79e5c6}, - {0x0000a40c, 0x00820820}, - {0x0000a414, 0x1ce739ce}, - {0x0000a418, 0x2d0011ce}, - {0x0000a41c, 0x1ce739ce}, - {0x0000a420, 0x000001ce}, - {0x0000a424, 0x1ce739ce}, - {0x0000a428, 0x000001ce}, - {0x0000a42c, 0x1ce739ce}, - {0x0000a430, 0x1ce739ce}, - {0x0000a434, 0x00000000}, - {0x0000a438, 0x00001801}, - {0x0000a43c, 0x00000000}, - {0x0000a440, 0x00000000}, - {0x0000a444, 0x00000000}, - {0x0000a448, 0x04000000}, - {0x0000a44c, 0x00000001}, - {0x0000a450, 0x00010000}, - {0x0000a458, 0x00000000}, - {0x0000a5c4, 0x3fad9d74}, - {0x0000a5c8, 0x0048060a}, - {0x0000a5cc, 0x00000637}, - {0x0000a760, 0x03020100}, - {0x0000a764, 0x09080504}, - {0x0000a768, 0x0d0c0b0a}, - {0x0000a76c, 0x13121110}, - {0x0000a770, 0x31301514}, - {0x0000a774, 0x35343332}, - {0x0000a778, 0x00000036}, - {0x0000a780, 0x00000838}, - {0x0000a7c0, 0x00000000}, - {0x0000a7c4, 0xfffffffc}, - {0x0000a7c8, 0x00000000}, - {0x0000a7cc, 0x00000000}, - {0x0000a7d0, 0x00000000}, - {0x0000a7d4, 0x00000004}, - {0x0000a7dc, 0x00000001}, -}; - -static const u32 ar9485Modes_high_ob_db_tx_gain_1_0[][5] = { - /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ - {0x0000a410, 0x000050d9, 0x000050d9, 0x000050d8, 0x000050d8}, - {0x0000a500, 0x00022200, 0x00022200, 0x00000000, 0x00000000}, - {0x0000a504, 0x05062002, 0x05062002, 0x04000002, 0x04000002}, - {0x0000a508, 0x0c002e00, 0x0c002e00, 0x08000004, 0x08000004}, - {0x0000a50c, 0x11062202, 0x11062202, 0x0d000200, 0x0d000200}, - {0x0000a510, 0x17022e00, 0x17022e00, 0x11000202, 0x11000202}, - {0x0000a514, 0x1d000ec2, 0x1d000ec2, 0x15000400, 0x15000400}, - {0x0000a518, 0x25020ec0, 0x25020ec0, 0x19000402, 0x19000402}, - {0x0000a51c, 0x2b020ec3, 0x2b020ec3, 0x1d000404, 0x1d000404}, - {0x0000a520, 0x2f001f04, 0x2f001f04, 0x21000603, 0x21000603}, - {0x0000a524, 0x35001fc4, 0x35001fc4, 0x25000605, 0x25000605}, - {0x0000a528, 0x3c022f04, 0x3c022f04, 0x2a000a03, 0x2a000a03}, - {0x0000a52c, 0x41023e85, 0x41023e85, 0x2c000a04, 0x2c000a04}, - {0x0000a530, 0x48023ec6, 0x48023ec6, 0x2e000a20, 0x2e000a20}, - {0x0000a534, 0x4d023f01, 0x4d023f01, 0x34000e20, 0x34000e20}, - {0x0000a538, 0x53023f4b, 0x53023f4b, 0x38000e22, 0x38000e22}, - {0x0000a53c, 0x5a027f09, 0x5a027f09, 0x3c000e24, 0x3c000e24}, - {0x0000a540, 0x5f027fc9, 0x5f027fc9, 0x40000e26, 0x40000e26}, - {0x0000a544, 0x6502feca, 0x6502feca, 0x43001640, 0x43001640}, - {0x0000a548, 0x6b02ff4a, 0x6b02ff4a, 0x46001660, 0x46001660}, - {0x0000a54c, 0x7203feca, 0x7203feca, 0x49001861, 0x49001861}, - {0x0000a550, 0x7703ff0b, 0x7703ff0b, 0x4c001a81, 0x4c001a81}, - {0x0000a554, 0x7d06ffcb, 0x7d06ffcb, 0x4f001a83, 0x4f001a83}, - {0x0000a558, 0x8407ff0b, 0x8407ff0b, 0x54001c85, 0x54001c85}, - {0x0000a55c, 0x8907ffcb, 0x8907ffcb, 0x58001ce5, 0x58001ce5}, - {0x0000a560, 0x900fff0b, 0x900fff0b, 0x5b001ce9, 0x5b001ce9}, - {0x0000a564, 0x960fffcb, 0x960fffcb, 0x60001eeb, 0x60001eeb}, - {0x0000a568, 0x9c1fff0b, 0x9c1fff0b, 0x60001eeb, 0x60001eeb}, - {0x0000a56c, 0x9c1fff0b, 0x9c1fff0b, 0x60001eeb, 0x60001eeb}, - {0x0000a570, 0x9c1fff0b, 0x9c1fff0b, 0x60001eeb, 0x60001eeb}, - {0x0000a574, 0x9c1fff0b, 0x9c1fff0b, 0x60001eeb, 0x60001eeb}, - {0x0000a578, 0x9c1fff0b, 0x9c1fff0b, 0x60001eeb, 0x60001eeb}, - {0x0000a57c, 0x9c1fff0b, 0x9c1fff0b, 0x60001eeb, 0x60001eeb}, - {0x00016044, 0x05b6b2db, 0x05b6b2db, 0x05b6b2db, 0x05b6b2db}, -}; - -static const u32 ar9485Common_rx_gain_1_0[][2] = { - /* Addr allmodes */ - {0x0000a000, 0x00010000}, - {0x0000a004, 0x00030002}, - {0x0000a008, 0x00050004}, - {0x0000a00c, 0x00810080}, - {0x0000a010, 0x01800082}, - {0x0000a014, 0x01820181}, - {0x0000a018, 0x01840183}, - {0x0000a01c, 0x01880185}, - {0x0000a020, 0x018a0189}, - {0x0000a024, 0x02850284}, - {0x0000a028, 0x02890288}, - {0x0000a02c, 0x03850384}, - {0x0000a030, 0x03890388}, - {0x0000a034, 0x038b038a}, - {0x0000a038, 0x038d038c}, - {0x0000a03c, 0x03910390}, - {0x0000a040, 0x03930392}, - {0x0000a044, 0x03950394}, - {0x0000a048, 0x00000396}, - {0x0000a04c, 0x00000000}, - {0x0000a050, 0x00000000}, - {0x0000a054, 0x00000000}, - {0x0000a058, 0x00000000}, - {0x0000a05c, 0x00000000}, - {0x0000a060, 0x00000000}, - {0x0000a064, 0x00000000}, - {0x0000a068, 0x00000000}, - {0x0000a06c, 0x00000000}, - {0x0000a070, 0x00000000}, - {0x0000a074, 0x00000000}, - {0x0000a078, 0x00000000}, - {0x0000a07c, 0x00000000}, - {0x0000a080, 0x28282828}, - {0x0000a084, 0x28282828}, - {0x0000a088, 0x28282828}, - {0x0000a08c, 0x28282828}, - {0x0000a090, 0x28282828}, - {0x0000a094, 0x21212128}, - {0x0000a098, 0x171c1c1c}, - {0x0000a09c, 0x02020212}, - {0x0000a0a0, 0x00000202}, - {0x0000a0a4, 0x00000000}, - {0x0000a0a8, 0x00000000}, - {0x0000a0ac, 0x00000000}, - {0x0000a0b0, 0x00000000}, - {0x0000a0b4, 0x00000000}, - {0x0000a0b8, 0x00000000}, - {0x0000a0bc, 0x00000000}, - {0x0000a0c0, 0x001f0000}, - {0x0000a0c4, 0x111f1100}, - {0x0000a0c8, 0x111d111e}, - {0x0000a0cc, 0x111b111c}, - {0x0000a0d0, 0x22032204}, - {0x0000a0d4, 0x22012202}, - {0x0000a0d8, 0x221f2200}, - {0x0000a0dc, 0x221d221e}, - {0x0000a0e0, 0x33013302}, - {0x0000a0e4, 0x331f3300}, - {0x0000a0e8, 0x4402331e}, - {0x0000a0ec, 0x44004401}, - {0x0000a0f0, 0x441e441f}, - {0x0000a0f4, 0x55015502}, - {0x0000a0f8, 0x551f5500}, - {0x0000a0fc, 0x6602551e}, - {0x0000a100, 0x66006601}, - {0x0000a104, 0x661e661f}, - {0x0000a108, 0x7703661d}, - {0x0000a10c, 0x77017702}, - {0x0000a110, 0x00007700}, - {0x0000a114, 0x00000000}, - {0x0000a118, 0x00000000}, - {0x0000a11c, 0x00000000}, - {0x0000a120, 0x00000000}, - {0x0000a124, 0x00000000}, - {0x0000a128, 0x00000000}, - {0x0000a12c, 0x00000000}, - {0x0000a130, 0x00000000}, - {0x0000a134, 0x00000000}, - {0x0000a138, 0x00000000}, - {0x0000a13c, 0x00000000}, - {0x0000a140, 0x001f0000}, - {0x0000a144, 0x111f1100}, - {0x0000a148, 0x111d111e}, - {0x0000a14c, 0x111b111c}, - {0x0000a150, 0x22032204}, - {0x0000a154, 0x22012202}, - {0x0000a158, 0x221f2200}, - {0x0000a15c, 0x221d221e}, - {0x0000a160, 0x33013302}, - {0x0000a164, 0x331f3300}, - {0x0000a168, 0x4402331e}, - {0x0000a16c, 0x44004401}, - {0x0000a170, 0x441e441f}, - {0x0000a174, 0x55015502}, - {0x0000a178, 0x551f5500}, - {0x0000a17c, 0x6602551e}, - {0x0000a180, 0x66006601}, - {0x0000a184, 0x661e661f}, - {0x0000a188, 0x7703661d}, - {0x0000a18c, 0x77017702}, - {0x0000a190, 0x00007700}, - {0x0000a194, 0x00000000}, - {0x0000a198, 0x00000000}, - {0x0000a19c, 0x00000000}, - {0x0000a1a0, 0x00000000}, - {0x0000a1a4, 0x00000000}, - {0x0000a1a8, 0x00000000}, - {0x0000a1ac, 0x00000000}, - {0x0000a1b0, 0x00000000}, - {0x0000a1b4, 0x00000000}, - {0x0000a1b8, 0x00000000}, - {0x0000a1bc, 0x00000000}, - {0x0000a1c0, 0x00000000}, - {0x0000a1c4, 0x00000000}, - {0x0000a1c8, 0x00000000}, - {0x0000a1cc, 0x00000000}, - {0x0000a1d0, 0x00000000}, - {0x0000a1d4, 0x00000000}, - {0x0000a1d8, 0x00000000}, - {0x0000a1dc, 0x00000000}, - {0x0000a1e0, 0x00000000}, - {0x0000a1e4, 0x00000000}, - {0x0000a1e8, 0x00000000}, - {0x0000a1ec, 0x00000000}, - {0x0000a1f0, 0x00000396}, - {0x0000a1f4, 0x00000396}, - {0x0000a1f8, 0x00000396}, - {0x0000a1fc, 0x00000296}, -}; - -static const u32 ar9485_1_0_pcie_phy_pll_on_clkreq_enable_L1[][2] = { - /* Addr allmodes */ - {0x00018c00, 0x10252e5e}, - {0x00018c04, 0x000801d8}, - {0x00018c08, 0x0000580c}, -}; - -static const u32 ar9485_1_0_pcie_phy_clkreq_enable_L1[][2] = { - /* Addr allmodes */ - {0x00018c00, 0x10253e5e}, - {0x00018c04, 0x000801d8}, - {0x00018c08, 0x0000580c}, -}; - -static const u32 ar9485_1_0_soc_preamble[][2] = { - /* Addr allmodes */ - {0x00004090, 0x00aa10aa}, - {0x000040a4, 0x00a0c9c9}, - {0x00007048, 0x00000004}, -}; - -static const u32 ar9485_fast_clock_1_0_baseband_postamble[][3] = { - /* Addr 5G_HT20 5G_HT40 */ - {0x00009e00, 0x03721821, 0x03721821}, - {0x0000a230, 0x0000400b, 0x00004016}, - {0x0000a254, 0x00000898, 0x00001130}, -}; - -static const u32 ar9485_1_0_baseband_postamble[][5] = { - /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ - {0x00009810, 0xd00a8005, 0xd00a8005, 0xd00a8005, 0xd00a8005}, - {0x00009820, 0x206a002e, 0x206a002e, 0x206a002e, 0x206a002e}, - {0x00009824, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0}, - {0x00009828, 0x06903081, 0x06903081, 0x06903881, 0x06903881}, - {0x0000982c, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4}, - {0x00009830, 0x0000059c, 0x0000059c, 0x0000059c, 0x0000059c}, - {0x00009c00, 0x00000044, 0x00000044, 0x00000044, 0x00000044}, - {0x00009e00, 0x0372161e, 0x0372161e, 0x037216a0, 0x037216a0}, - {0x00009e04, 0x00182020, 0x00182020, 0x00182020, 0x00182020}, - {0x00009e0c, 0x6c4000e2, 0x6d4000e2, 0x6d4000e2, 0x6c4000e2}, - {0x00009e10, 0x7ec88d2e, 0x7ec88d2e, 0x7ec80d2e, 0x7ec80d2e}, - {0x00009e14, 0x31395d5e, 0x3139605e, 0x3139605e, 0x31395d5e}, - {0x00009e18, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x00009e1c, 0x0001cf9c, 0x0001cf9c, 0x00021f9c, 0x00021f9c}, - {0x00009e20, 0x000003b5, 0x000003b5, 0x000003ce, 0x000003ce}, - {0x00009e2c, 0x0000001c, 0x0000001c, 0x00000021, 0x00000021}, - {0x00009e3c, 0xcf946220, 0xcf946220, 0xcf946222, 0xcf946222}, - {0x00009e44, 0x02321e27, 0x02321e27, 0x02282324, 0x02282324}, - {0x00009e48, 0x5030201a, 0x5030201a, 0x50302010, 0x50302010}, - {0x00009fc8, 0x0003f000, 0x0003f000, 0x0001a000, 0x0001a000}, - {0x0000a204, 0x01303fc0, 0x01303fc4, 0x01303fc4, 0x01303fc0}, - {0x0000a208, 0x00000104, 0x00000104, 0x00000004, 0x00000004}, - {0x0000a230, 0x0000400a, 0x00004014, 0x00004016, 0x0000400b}, - {0x0000a234, 0x10000fff, 0x10000fff, 0x10000fff, 0x10000fff}, - {0x0000a238, 0xffb81018, 0xffb81018, 0xffb81018, 0xffb81018}, - {0x0000a250, 0x00000000, 0x00000000, 0x00000210, 0x00000108}, - {0x0000a254, 0x000007d0, 0x00000fa0, 0x00001130, 0x00000898}, - {0x0000a258, 0x02020002, 0x02020002, 0x02020002, 0x02020002}, - {0x0000a25c, 0x01000e0e, 0x01000e0e, 0x01000e0e, 0x01000e0e}, - {0x0000a260, 0x3a021501, 0x3a021501, 0x3a021501, 0x3a021501}, - {0x0000a264, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e}, - {0x0000a280, 0x00000007, 0x00000007, 0x0000000b, 0x0000000b}, - {0x0000a284, 0x00000000, 0x00000000, 0x000002a0, 0x000002a0}, - {0x0000a288, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x0000a28c, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x0000a2c4, 0x00158d18, 0x00158d18, 0x00158d18, 0x00158d18}, - {0x0000a2d0, 0x00071981, 0x00071981, 0x00071981, 0x00071982}, - {0x0000a2d8, 0xf999a83a, 0xf999a83a, 0xf999a83a, 0xf999a83a}, - {0x0000a358, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x0000be04, 0x00802020, 0x00802020, 0x00802020, 0x00802020}, - {0x0000be18, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, -}; - -static const u32 ar9485Modes_low_ob_db_tx_gain_1_0[][5] = { - /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ - {0x0000a410, 0x000050d9, 0x000050d9, 0x000050d8, 0x000050d8}, - {0x0000a500, 0x00022200, 0x00022200, 0x00000000, 0x00000000}, - {0x0000a504, 0x05062002, 0x05062002, 0x04000002, 0x04000002}, - {0x0000a508, 0x0c002e00, 0x0c002e00, 0x08000004, 0x08000004}, - {0x0000a50c, 0x11062202, 0x11062202, 0x0d000200, 0x0d000200}, - {0x0000a510, 0x17022e00, 0x17022e00, 0x11000202, 0x11000202}, - {0x0000a514, 0x1d000ec2, 0x1d000ec2, 0x15000400, 0x15000400}, - {0x0000a518, 0x25020ec0, 0x25020ec0, 0x19000402, 0x19000402}, - {0x0000a51c, 0x2b020ec3, 0x2b020ec3, 0x1d000404, 0x1d000404}, - {0x0000a520, 0x2f001f04, 0x2f001f04, 0x21000603, 0x21000603}, - {0x0000a524, 0x35001fc4, 0x35001fc4, 0x25000605, 0x25000605}, - {0x0000a528, 0x3c022f04, 0x3c022f04, 0x2a000a03, 0x2a000a03}, - {0x0000a52c, 0x41023e85, 0x41023e85, 0x2c000a04, 0x2c000a04}, - {0x0000a530, 0x48023ec6, 0x48023ec6, 0x2e000a20, 0x2e000a20}, - {0x0000a534, 0x4d023f01, 0x4d023f01, 0x34000e20, 0x34000e20}, - {0x0000a538, 0x53023f4b, 0x53023f4b, 0x38000e22, 0x38000e22}, - {0x0000a53c, 0x5a027f09, 0x5a027f09, 0x3c000e24, 0x3c000e24}, - {0x0000a540, 0x5f027fc9, 0x5f027fc9, 0x40000e26, 0x40000e26}, - {0x0000a544, 0x6502feca, 0x6502feca, 0x43001640, 0x43001640}, - {0x0000a548, 0x6b02ff4a, 0x6b02ff4a, 0x46001660, 0x46001660}, - {0x0000a54c, 0x7203feca, 0x7203feca, 0x49001861, 0x49001861}, - {0x0000a550, 0x7703ff0b, 0x7703ff0b, 0x4c001a81, 0x4c001a81}, - {0x0000a554, 0x7d06ffcb, 0x7d06ffcb, 0x4f001a83, 0x4f001a83}, - {0x0000a558, 0x8407ff0b, 0x8407ff0b, 0x54001c85, 0x54001c85}, - {0x0000a55c, 0x8907ffcb, 0x8907ffcb, 0x58001ce5, 0x58001ce5}, - {0x0000a560, 0x900fff0b, 0x900fff0b, 0x5b001ce9, 0x5b001ce9}, - {0x0000a564, 0x960fffcb, 0x960fffcb, 0x60001eeb, 0x60001eeb}, - {0x0000a568, 0x9c1fff0b, 0x9c1fff0b, 0x60001eeb, 0x60001eeb}, - {0x0000a56c, 0x9c1fff0b, 0x9c1fff0b, 0x60001eeb, 0x60001eeb}, - {0x0000a570, 0x9c1fff0b, 0x9c1fff0b, 0x60001eeb, 0x60001eeb}, - {0x0000a574, 0x9c1fff0b, 0x9c1fff0b, 0x60001eeb, 0x60001eeb}, - {0x0000a578, 0x9c1fff0b, 0x9c1fff0b, 0x60001eeb, 0x60001eeb}, - {0x0000a57c, 0x9c1fff0b, 0x9c1fff0b, 0x60001eeb, 0x60001eeb}, - {0x00016044, 0x05b6b2db, 0x05b6b2db, 0x05b6b2db, 0x05b6b2db}, -}; - -static const u32 ar9485_1_0_pcie_phy_clkreq_disable_L1[][2] = { - /* Addr allmodes */ - {0x00018c00, 0x10213e5e}, - {0x00018c04, 0x000801d8}, - {0x00018c08, 0x0000580c}, -}; - -static const u32 ar9485_1_0_radio_postamble[][2] = { - /* Addr allmodes */ - {0x0001609c, 0x0b283f31}, - {0x000160ac, 0x24611800}, - {0x000160b0, 0x03284f3e}, - {0x0001610c, 0x00170000}, - {0x00016140, 0x10804008}, -}; - -static const u32 ar9485_1_0_mac_core[][2] = { - /* Addr allmodes */ - {0x00000008, 0x00000000}, - {0x00000030, 0x00020085}, - {0x00000034, 0x00000005}, - {0x00000040, 0x00000000}, - {0x00000044, 0x00000000}, - {0x00000048, 0x00000008}, - {0x0000004c, 0x00000010}, - {0x00000050, 0x00000000}, - {0x00001040, 0x002ffc0f}, - {0x00001044, 0x002ffc0f}, - {0x00001048, 0x002ffc0f}, - {0x0000104c, 0x002ffc0f}, - {0x00001050, 0x002ffc0f}, - {0x00001054, 0x002ffc0f}, - {0x00001058, 0x002ffc0f}, - {0x0000105c, 0x002ffc0f}, - {0x00001060, 0x002ffc0f}, - {0x00001064, 0x002ffc0f}, - {0x000010f0, 0x00000100}, - {0x00001270, 0x00000000}, - {0x000012b0, 0x00000000}, - {0x000012f0, 0x00000000}, - {0x0000143c, 0x00000000}, - {0x0000147c, 0x00000000}, - {0x00008000, 0x00000000}, - {0x00008004, 0x00000000}, - {0x00008008, 0x00000000}, - {0x0000800c, 0x00000000}, - {0x00008018, 0x00000000}, - {0x00008020, 0x00000000}, - {0x00008038, 0x00000000}, - {0x0000803c, 0x00000000}, - {0x00008040, 0x00000000}, - {0x00008044, 0x00000000}, - {0x00008048, 0x00000000}, - {0x0000804c, 0xffffffff}, - {0x00008054, 0x00000000}, - {0x00008058, 0x00000000}, - {0x0000805c, 0x000fc78f}, - {0x00008060, 0x0000000f}, - {0x00008064, 0x00000000}, - {0x00008070, 0x00000310}, - {0x00008074, 0x00000020}, - {0x00008078, 0x00000000}, - {0x0000809c, 0x0000000f}, - {0x000080a0, 0x00000000}, - {0x000080a4, 0x02ff0000}, - {0x000080a8, 0x0e070605}, - {0x000080ac, 0x0000000d}, - {0x000080b0, 0x00000000}, - {0x000080b4, 0x00000000}, - {0x000080b8, 0x00000000}, - {0x000080bc, 0x00000000}, - {0x000080c0, 0x2a800000}, - {0x000080c4, 0x06900168}, - {0x000080c8, 0x13881c20}, - {0x000080cc, 0x01f40000}, - {0x000080d0, 0x00252500}, - {0x000080d4, 0x00a00000}, - {0x000080d8, 0x00400000}, - {0x000080dc, 0x00000000}, - {0x000080e0, 0xffffffff}, - {0x000080e4, 0x0000ffff}, - {0x000080e8, 0x3f3f3f3f}, - {0x000080ec, 0x00000000}, - {0x000080f0, 0x00000000}, - {0x000080f4, 0x00000000}, - {0x000080fc, 0x00020000}, - {0x00008100, 0x00000000}, - {0x00008108, 0x00000052}, - {0x0000810c, 0x00000000}, - {0x00008110, 0x00000000}, - {0x00008114, 0x000007ff}, - {0x00008118, 0x000000aa}, - {0x0000811c, 0x00003210}, - {0x00008124, 0x00000000}, - {0x00008128, 0x00000000}, - {0x0000812c, 0x00000000}, - {0x00008130, 0x00000000}, - {0x00008134, 0x00000000}, - {0x00008138, 0x00000000}, - {0x0000813c, 0x0000ffff}, - {0x00008144, 0xffffffff}, - {0x00008168, 0x00000000}, - {0x0000816c, 0x00000000}, - {0x00008170, 0x18486200}, - {0x00008174, 0x33332210}, - {0x00008178, 0x00000000}, - {0x0000817c, 0x00020000}, - {0x000081c0, 0x00000000}, - {0x000081c4, 0x33332210}, - {0x000081c8, 0x00000000}, - {0x000081cc, 0x00000000}, - {0x000081d4, 0x00000000}, - {0x000081ec, 0x00000000}, - {0x000081f0, 0x00000000}, - {0x000081f4, 0x00000000}, - {0x000081f8, 0x00000000}, - {0x000081fc, 0x00000000}, - {0x00008240, 0x00100000}, - {0x00008244, 0x0010f400}, - {0x00008248, 0x00000800}, - {0x0000824c, 0x0001e800}, - {0x00008250, 0x00000000}, - {0x00008254, 0x00000000}, - {0x00008258, 0x00000000}, - {0x0000825c, 0x40000000}, - {0x00008260, 0x00080922}, - {0x00008264, 0x9ca00010}, - {0x00008268, 0xffffffff}, - {0x0000826c, 0x0000ffff}, - {0x00008270, 0x00000000}, - {0x00008274, 0x40000000}, - {0x00008278, 0x003e4180}, - {0x0000827c, 0x00000004}, - {0x00008284, 0x0000002c}, - {0x00008288, 0x0000002c}, - {0x0000828c, 0x000000ff}, - {0x00008294, 0x00000000}, - {0x00008298, 0x00000000}, - {0x0000829c, 0x00000000}, - {0x00008300, 0x00000140}, - {0x00008314, 0x00000000}, - {0x0000831c, 0x0000010d}, - {0x00008328, 0x00000000}, - {0x0000832c, 0x00000007}, - {0x00008330, 0x00000302}, - {0x00008334, 0x00000700}, - {0x00008338, 0x00ff0000}, - {0x0000833c, 0x02400000}, - {0x00008340, 0x000107ff}, - {0x00008344, 0xa248105b}, - {0x00008348, 0x008f0000}, - {0x0000835c, 0x00000000}, - {0x00008360, 0xffffffff}, - {0x00008364, 0xffffffff}, - {0x00008368, 0x00000000}, - {0x00008370, 0x00000000}, - {0x00008374, 0x000000ff}, - {0x00008378, 0x00000000}, - {0x0000837c, 0x00000000}, - {0x00008380, 0xffffffff}, - {0x00008384, 0xffffffff}, - {0x00008390, 0xffffffff}, - {0x00008394, 0xffffffff}, - {0x00008398, 0x00000000}, - {0x0000839c, 0x00000000}, - {0x000083a0, 0x00000000}, - {0x000083a4, 0x0000fa14}, - {0x000083a8, 0x000f0c00}, - {0x000083ac, 0x33332210}, - {0x000083b0, 0x33332210}, - {0x000083b4, 0x33332210}, - {0x000083b8, 0x33332210}, - {0x000083bc, 0x00000000}, - {0x000083c0, 0x00000000}, - {0x000083c4, 0x00000000}, - {0x000083c8, 0x00000000}, - {0x000083cc, 0x00000200}, - {0x000083d0, 0x000301ff}, -}; - static const u32 ar9485_1_1_mac_core[][2] = { /* Addr allmodes */ {0x00000008, 0x00000000}, -- cgit v0.10.2 From 5e6e3a92b9a4c9416b17f468fa5c7fa2233b8b4e Mon Sep 17 00:00:00 2001 From: Bing Zhao Date: Mon, 21 Mar 2011 18:00:50 -0700 Subject: wireless: mwifiex: initial commit for Marvell mwifiex driver This driver adds WiFi support for Marvell 802.11n based chipsets with SDIO interface. Currently only SD8787 is supported. More chipsets will be supported later. drivers/net/wireless/mwifiex/ Signed-off-by: Nishant Sarmukadam Signed-off-by: Amitkumar Karwar Signed-off-by: Kiran Divekar Signed-off-by: Bing Zhao Signed-off-by: Yogesh Ashok Powar Signed-off-by: Marc Yang Signed-off-by: Ramesh Radhakrishnan Signed-off-by: Frank Huang Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/Kconfig b/drivers/net/wireless/Kconfig index 7aeb113..f354bd4 100644 --- a/drivers/net/wireless/Kconfig +++ b/drivers/net/wireless/Kconfig @@ -284,5 +284,6 @@ source "drivers/net/wireless/rtlwifi/Kconfig" source "drivers/net/wireless/wl1251/Kconfig" source "drivers/net/wireless/wl12xx/Kconfig" source "drivers/net/wireless/zd1211rw/Kconfig" +source "drivers/net/wireless/mwifiex/Kconfig" endif # WLAN diff --git a/drivers/net/wireless/Makefile b/drivers/net/wireless/Makefile index ddd3fb6..7bba6a8 100644 --- a/drivers/net/wireless/Makefile +++ b/drivers/net/wireless/Makefile @@ -56,3 +56,5 @@ obj-$(CONFIG_WL12XX) += wl12xx/ obj-$(CONFIG_WL12XX_PLATFORM_DATA) += wl12xx/ obj-$(CONFIG_IWM) += iwmc3200wifi/ + +obj-$(CONFIG_MWIFIEX) += mwifiex/ diff --git a/drivers/net/wireless/mwifiex/11n.c b/drivers/net/wireless/mwifiex/11n.c new file mode 100644 index 0000000..0e04a21 --- /dev/null +++ b/drivers/net/wireless/mwifiex/11n.c @@ -0,0 +1,922 @@ +/* + * Marvell Wireless LAN device driver: 802.11n + * + * Copyright (C) 2011, Marvell International Ltd. + * + * This software file (the "File") is distributed by Marvell International + * Ltd. under the terms of the GNU General Public License Version 2, June 1991 + * (the "License"). You may use, redistribute and/or modify this File in + * accordance with the terms and conditions of the License, a copy of which + * is available by writing to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the + * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. + * + * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE + * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE + * ARE EXPRESSLY DISCLAIMED. The License provides additional details about + * this warranty disclaimer. + */ + +#include "decl.h" +#include "ioctl.h" +#include "util.h" +#include "fw.h" +#include "main.h" +#include "wmm.h" +#include "11n.h" + +/* + * Fills HT capability information field, AMPDU Parameters field, HT extended + * capability field, and supported MCS set fields. + * + * Only the following HT capability information fields are used, all other + * fields are always turned off. + * + * Bit 1 : Supported channel width (0: 20MHz, 1: Both 20 and 40 MHz) + * Bit 4 : Greenfield support (0: Not supported, 1: Supported) + * Bit 5 : Short GI for 20 MHz support (0: Not supported, 1: Supported) + * Bit 6 : Short GI for 40 MHz support (0: Not supported, 1: Supported) + * Bit 7 : Tx STBC (0: Not supported, 1: Supported) + * Bit 8-9 : Rx STBC (0: Not supported, X: Support for up to X spatial streams) + * Bit 10 : Delayed BA support (0: Not supported, 1: Supported) + * Bit 11 : Maximum AMSDU length (0: 3839 octets, 1: 7935 octets) + * Bit 14 : 40-Mhz intolerant support (0: Not supported, 1: Supported) + * + * In addition, the following AMPDU Parameters are set - + * - Maximum AMPDU length exponent (set to 3) + * - Minimum AMPDU start spacing (set to 0 - No restrictions) + * + * MCS is set for 1x1, with MSC32 for infra mode or ad-hoc mode with 40 MHz + * support. + * + * RD responder bit to set to clear in the extended capability header. + */ +void +mwifiex_fill_cap_info(struct mwifiex_private *priv, + struct mwifiex_ie_types_htcap *ht_cap) +{ + struct mwifiex_adapter *adapter = priv->adapter; + u8 *mcs; + int rx_mcs_supp; + uint16_t ht_cap_info = le16_to_cpu(ht_cap->ht_cap.cap_info); + uint16_t ht_ext_cap = le16_to_cpu(ht_cap->ht_cap.extended_ht_cap_info); + + if (ISSUPP_CHANWIDTH40(adapter->hw_dot_11n_dev_cap) && + ISSUPP_CHANWIDTH40(adapter->usr_dot_11n_dev_cap)) + SETHT_SUPPCHANWIDTH(ht_cap_info); + else + RESETHT_SUPPCHANWIDTH(ht_cap_info); + + if (ISSUPP_GREENFIELD(adapter->hw_dot_11n_dev_cap) && + ISSUPP_GREENFIELD(adapter->usr_dot_11n_dev_cap)) + SETHT_GREENFIELD(ht_cap_info); + else + RESETHT_GREENFIELD(ht_cap_info); + + if (ISSUPP_SHORTGI20(adapter->hw_dot_11n_dev_cap) && + ISSUPP_SHORTGI20(adapter->usr_dot_11n_dev_cap)) + SETHT_SHORTGI20(ht_cap_info); + else + RESETHT_SHORTGI20(ht_cap_info); + + if (ISSUPP_SHORTGI40(adapter->hw_dot_11n_dev_cap) && + ISSUPP_SHORTGI40(adapter->usr_dot_11n_dev_cap)) + SETHT_SHORTGI40(ht_cap_info); + else + RESETHT_SHORTGI40(ht_cap_info); + + /* No user config for RX STBC yet */ + if (ISSUPP_RXSTBC(adapter->hw_dot_11n_dev_cap) + && ISSUPP_RXSTBC(adapter->usr_dot_11n_dev_cap)) + SETHT_RXSTBC(ht_cap_info, 1); + else + RESETHT_RXSTBC(ht_cap_info); + + /* No user config for TX STBC yet */ + if (ISSUPP_TXSTBC(adapter->hw_dot_11n_dev_cap)) + SETHT_TXSTBC(ht_cap_info); + else + RESETHT_TXSTBC(ht_cap_info); + + /* No user config for Delayed BACK yet */ + if (GET_DELAYEDBACK(adapter->hw_dot_11n_dev_cap)) + SETHT_DELAYEDBACK(ht_cap_info); + else + RESETHT_DELAYEDBACK(ht_cap_info); + + if (ISENABLED_40MHZ_INTOLARENT(adapter->usr_dot_11n_dev_cap)) + SETHT_40MHZ_INTOLARANT(ht_cap_info); + else + RESETHT_40MHZ_INTOLARANT(ht_cap_info); + + SETAMPDU_SIZE(ht_cap->ht_cap.ampdu_params_info, AMPDU_FACTOR_64K); + SETAMPDU_SPACING(ht_cap->ht_cap.ampdu_params_info, 0); + + /* Need change to support 8k AMSDU receive */ + RESETHT_MAXAMSDU(ht_cap_info); + + rx_mcs_supp = GET_RXMCSSUPP(adapter->hw_dev_mcs_support); + + mcs = (u8 *)&ht_cap->ht_cap.mcs; + + /* Set MCS for 1x1 */ + memset(mcs, 0xff, rx_mcs_supp); + + /* Clear all the other values */ + memset(&mcs[rx_mcs_supp], 0, + sizeof(struct ieee80211_mcs_info) - rx_mcs_supp); + + if (priv->bss_mode == MWIFIEX_BSS_MODE_INFRA || + (ISSUPP_CHANWIDTH40(adapter->hw_dot_11n_dev_cap) && + ISSUPP_CHANWIDTH40(adapter->usr_dot_11n_dev_cap))) + /* Set MCS32 for infra mode or ad-hoc mode with 40MHz support */ + SETHT_MCS32(ht_cap->ht_cap.mcs.rx_mask); + + /* Clear RD responder bit */ + RESETHT_EXTCAP_RDG(ht_ext_cap); + + ht_cap->ht_cap.cap_info = cpu_to_le16(ht_cap_info); + ht_cap->ht_cap.extended_ht_cap_info = cpu_to_le16(ht_ext_cap); +} + +/* + * Shows HT capability information fields. + * + * The following HT capability information fields are supported. + * - Maximum AMSDU length (3839 bytes or 7935 bytes) + * - Beam forming support + * - Greenfield preamble support + * - AMPDU support + * - MIMO Power Save support + * - Rx STBC support + * - Tx STBC support + * - Short GI for 20 MHz support + * - Short GI for 40 MHz support + * - LDPC coded packets receive support + * - Number of delayed BA streams + * - Number of immediate BA streams + * - 10 MHz channel width support + * - 20 MHz channel width support + * - 40 MHz channel width support + * - Presence of Tx antenna A/B/C/D + * - Presence of Rx antenna A/B/C/D + */ +void +mwifiex_show_dot_11n_dev_cap(struct mwifiex_adapter *adapter, u32 cap) +{ + dev_dbg(adapter->dev, "info: GET_HW_SPEC: Max MSDU len = %s octets\n", + (ISSUPP_MAXAMSDU(cap) ? "7935" : "3839")); + dev_dbg(adapter->dev, "info: GET_HW_SPEC: Beam forming %s\n", + (ISSUPP_BEAMFORMING(cap) ? "supported" : "not supported")); + dev_dbg(adapter->dev, "info: GET_HW_SPEC: Greenfield preamble %s\n", + (ISSUPP_GREENFIELD(cap) ? "supported" : "not supported")); + dev_dbg(adapter->dev, "info: GET_HW_SPEC: AMPDU %s\n", + (ISSUPP_AMPDU(cap) ? "supported" : "not supported")); + dev_dbg(adapter->dev, "info: GET_HW_SPEC: MIMO Power Save %s\n", + (ISSUPP_MIMOPS(cap) ? "supported" : "not supported")); + dev_dbg(adapter->dev, "info: GET_HW_SPEC: Rx STBC %s\n", + (ISSUPP_RXSTBC(cap) ? "supported" : "not supported")); + dev_dbg(adapter->dev, "info: GET_HW_SPEC: Tx STBC %s\n", + (ISSUPP_TXSTBC(cap) ? "supported" : "not supported")); + dev_dbg(adapter->dev, "info: GET_HW_SPEC: Short GI for 40 Mhz %s\n", + (ISSUPP_SHORTGI40(cap) ? "supported" : "not supported")); + dev_dbg(adapter->dev, "info: GET_HW_SPEC: Short GI for 20 Mhz %s\n", + (ISSUPP_SHORTGI20(cap) ? "supported" : "not supported")); + dev_dbg(adapter->dev, "info: GET_HW_SPEC: LDPC coded packet receive %s\n", + (ISSUPP_RXLDPC(cap) ? "supported" : "not supported")); + dev_dbg(adapter->dev, + "info: GET_HW_SPEC: Number of Delayed Block Ack streams = %d\n", + GET_DELAYEDBACK(cap)); + dev_dbg(adapter->dev, + "info: GET_HW_SPEC: Number of Immediate Block Ack streams = %d\n", + GET_IMMEDIATEBACK(cap)); + dev_dbg(adapter->dev, "info: GET_HW_SPEC: 40 Mhz channel width %s\n", + (ISSUPP_CHANWIDTH40(cap) ? "supported" : "not supported")); + dev_dbg(adapter->dev, "info: GET_HW_SPEC: 20 Mhz channel width %s\n", + (ISSUPP_CHANWIDTH20(cap) ? "supported" : "not supported")); + dev_dbg(adapter->dev, "info: GET_HW_SPEC: 10 Mhz channel width %s\n", + (ISSUPP_CHANWIDTH10(cap) ? "supported" : "not supported")); + + if (ISSUPP_RXANTENNAA(cap)) + dev_dbg(adapter->dev, "info: GET_HW_SPEC: Prescence of Rx antennea A\n"); + + if (ISSUPP_RXANTENNAB(cap)) + dev_dbg(adapter->dev, "info: GET_HW_SPEC: Prescence of Rx antennea B\n"); + + if (ISSUPP_RXANTENNAC(cap)) + dev_dbg(adapter->dev, "info: GET_HW_SPEC: Prescence of Rx antennea C\n"); + + if (ISSUPP_RXANTENNAD(cap)) + dev_dbg(adapter->dev, "info: GET_HW_SPEC: Prescence of Rx antennea D\n"); + + if (ISSUPP_TXANTENNAA(cap)) + dev_dbg(adapter->dev, "info: GET_HW_SPEC: Prescence of Tx antennea A\n"); + + if (ISSUPP_TXANTENNAB(cap)) + dev_dbg(adapter->dev, "info: GET_HW_SPEC: Prescence of Tx antennea B\n"); + + if (ISSUPP_TXANTENNAC(cap)) + dev_dbg(adapter->dev, "info: GET_HW_SPEC: Prescence of Tx antennea C\n"); + + if (ISSUPP_TXANTENNAD(cap)) + dev_dbg(adapter->dev, "info: GET_HW_SPEC: Prescence of Tx antennea D\n"); + + return; +} + +/* + * Shows HT MCS support field. + */ +void +mwifiex_show_dev_mcs_support(struct mwifiex_adapter *adapter, u8 support) +{ + dev_dbg(adapter->dev, "info: GET_HW_SPEC: MCSs for %dx%d MIMO\n", + GET_RXMCSSUPP(support), GET_TXMCSSUPP(support)); + return; +} + +/* + * This function returns the pointer to an entry in BA Stream + * table which matches the requested BA status. + */ +static struct mwifiex_tx_ba_stream_tbl * +mwifiex_11n_get_tx_ba_stream_status(struct mwifiex_private *priv, + enum mwifiex_ba_status ba_status) +{ + struct mwifiex_tx_ba_stream_tbl *tx_ba_tsr_tbl; + unsigned long flags; + + spin_lock_irqsave(&priv->tx_ba_stream_tbl_lock, flags); + list_for_each_entry(tx_ba_tsr_tbl, &priv->tx_ba_stream_tbl_ptr, list) { + if (tx_ba_tsr_tbl->ba_status == ba_status) { + spin_unlock_irqrestore(&priv->tx_ba_stream_tbl_lock, + flags); + return tx_ba_tsr_tbl; + } + } + spin_unlock_irqrestore(&priv->tx_ba_stream_tbl_lock, flags); + return NULL; +} + +/* + * This function handles the command response of delete a block + * ack request. + * + * The function checks the response success status and takes action + * accordingly (send an add BA request in case of success, or recreate + * the deleted stream in case of failure, if the add BA was also + * initiated by us). + */ +int mwifiex_ret_11n_delba(struct mwifiex_private *priv, + struct host_cmd_ds_command *resp) +{ + int tid; + struct mwifiex_tx_ba_stream_tbl *tx_ba_tbl; + struct host_cmd_ds_11n_delba *del_ba = + (struct host_cmd_ds_11n_delba *) &resp->params.del_ba; + uint16_t del_ba_param_set = le16_to_cpu(del_ba->del_ba_param_set); + + tid = del_ba_param_set >> DELBA_TID_POS; + if (del_ba->del_result == BA_RESULT_SUCCESS) { + mwifiex_11n_delete_ba_stream_tbl(priv, tid, + del_ba->peer_mac_addr, TYPE_DELBA_SENT, + INITIATOR_BIT(del_ba_param_set)); + + tx_ba_tbl = mwifiex_11n_get_tx_ba_stream_status(priv, + BA_STREAM_SETUP_INPROGRESS); + if (tx_ba_tbl) + mwifiex_send_addba(priv, tx_ba_tbl->tid, + tx_ba_tbl->ra); + } else { /* + * In case of failure, recreate the deleted stream in case + * we initiated the ADDBA + */ + if (INITIATOR_BIT(del_ba_param_set)) { + mwifiex_11n_create_tx_ba_stream_tbl(priv, + del_ba->peer_mac_addr, tid, + BA_STREAM_SETUP_INPROGRESS); + + tx_ba_tbl = mwifiex_11n_get_tx_ba_stream_status(priv, + BA_STREAM_SETUP_INPROGRESS); + if (tx_ba_tbl) + mwifiex_11n_delete_ba_stream_tbl(priv, + tx_ba_tbl->tid, tx_ba_tbl->ra, + TYPE_DELBA_SENT, true); + } + } + + return 0; +} + +/* + * This function handles the command response of add a block + * ack request. + * + * Handling includes changing the header fields to CPU formats, checking + * the response success status and taking actions accordingly (delete the + * BA stream table in case of failure). + */ +int mwifiex_ret_11n_addba_req(struct mwifiex_private *priv, + struct host_cmd_ds_command *resp) +{ + int tid; + struct host_cmd_ds_11n_addba_rsp *add_ba_rsp = + (struct host_cmd_ds_11n_addba_rsp *) &resp->params.add_ba_rsp; + struct mwifiex_tx_ba_stream_tbl *tx_ba_tbl; + + add_ba_rsp->ssn = cpu_to_le16((le16_to_cpu(add_ba_rsp->ssn)) + & SSN_MASK); + + tid = (le16_to_cpu(add_ba_rsp->block_ack_param_set) + & IEEE80211_ADDBA_PARAM_TID_MASK) + >> BLOCKACKPARAM_TID_POS; + if (le16_to_cpu(add_ba_rsp->status_code) == BA_RESULT_SUCCESS) { + tx_ba_tbl = mwifiex_11n_get_tx_ba_stream_tbl(priv, tid, + add_ba_rsp->peer_mac_addr); + if (tx_ba_tbl) { + dev_dbg(priv->adapter->dev, "info: BA stream complete\n"); + tx_ba_tbl->ba_status = BA_STREAM_SETUP_COMPLETE; + } else { + dev_err(priv->adapter->dev, "BA stream not created\n"); + } + } else { + mwifiex_11n_delete_ba_stream_tbl(priv, tid, + add_ba_rsp->peer_mac_addr, + TYPE_DELBA_SENT, true); + if (add_ba_rsp->add_rsp_result != BA_RESULT_TIMEOUT) + priv->aggr_prio_tbl[tid].ampdu_ap = + BA_STREAM_NOT_ALLOWED; + } + + return 0; +} + +/* + * This function handles the command response of 11n configuration request. + * + * Handling includes changing the header fields into CPU format. + */ +int mwifiex_ret_11n_cfg(struct mwifiex_private *priv, + struct host_cmd_ds_command *resp, + void *data_buf) +{ + struct mwifiex_ds_11n_tx_cfg *tx_cfg = NULL; + struct host_cmd_ds_11n_cfg *htcfg = &resp->params.htcfg; + + if (data_buf) { + tx_cfg = (struct mwifiex_ds_11n_tx_cfg *) data_buf; + tx_cfg->tx_htcap = le16_to_cpu(htcfg->ht_tx_cap); + tx_cfg->tx_htinfo = le16_to_cpu(htcfg->ht_tx_info); + } + return 0; +} + +/* + * This function prepares command of reconfigure Tx buffer. + * + * Preparation includes - + * - Setting command ID, action and proper size + * - Setting Tx buffer size (for SET only) + * - Ensuring correct endian-ness + */ +int mwifiex_cmd_recfg_tx_buf(struct mwifiex_private *priv, + struct host_cmd_ds_command *cmd, int cmd_action, + void *data_buf) +{ + struct host_cmd_ds_txbuf_cfg *tx_buf = &cmd->params.tx_buf; + u16 action = (u16) cmd_action; + u16 buf_size = *((u16 *) data_buf); + + cmd->command = cpu_to_le16(HostCmd_CMD_RECONFIGURE_TX_BUFF); + cmd->size = + cpu_to_le16(sizeof(struct host_cmd_ds_txbuf_cfg) + S_DS_GEN); + tx_buf->action = cpu_to_le16(action); + switch (action) { + case HostCmd_ACT_GEN_SET: + dev_dbg(priv->adapter->dev, "cmd: set tx_buf=%d\n", buf_size); + tx_buf->buff_size = cpu_to_le16(buf_size); + break; + case HostCmd_ACT_GEN_GET: + default: + tx_buf->buff_size = 0; + break; + } + return 0; +} + +/* + * This function prepares command of AMSDU aggregation control. + * + * Preparation includes - + * - Setting command ID, action and proper size + * - Setting AMSDU control parameters (for SET only) + * - Ensuring correct endian-ness + */ +int mwifiex_cmd_amsdu_aggr_ctrl(struct mwifiex_private *priv, + struct host_cmd_ds_command *cmd, + int cmd_action, void *data_buf) +{ + struct host_cmd_ds_amsdu_aggr_ctrl *amsdu_ctrl = + &cmd->params.amsdu_aggr_ctrl; + u16 action = (u16) cmd_action; + struct mwifiex_ds_11n_amsdu_aggr_ctrl *aa_ctrl = + (struct mwifiex_ds_11n_amsdu_aggr_ctrl *) data_buf; + + cmd->command = cpu_to_le16(HostCmd_CMD_AMSDU_AGGR_CTRL); + cmd->size = cpu_to_le16(sizeof(struct host_cmd_ds_amsdu_aggr_ctrl) + + S_DS_GEN); + amsdu_ctrl->action = cpu_to_le16(action); + switch (action) { + case HostCmd_ACT_GEN_SET: + amsdu_ctrl->enable = cpu_to_le16(aa_ctrl->enable); + amsdu_ctrl->curr_buf_size = 0; + break; + case HostCmd_ACT_GEN_GET: + default: + amsdu_ctrl->curr_buf_size = 0; + break; + } + return 0; +} + +/* + * This function handles the command response of AMSDU aggregation + * control request. + * + * Handling includes changing the header fields into CPU format. + */ +int mwifiex_ret_amsdu_aggr_ctrl(struct mwifiex_private *priv, + struct host_cmd_ds_command *resp, + void *data_buf) +{ + struct mwifiex_ds_11n_amsdu_aggr_ctrl *amsdu_aggr_ctrl = NULL; + struct host_cmd_ds_amsdu_aggr_ctrl *amsdu_ctrl = + &resp->params.amsdu_aggr_ctrl; + + if (data_buf) { + amsdu_aggr_ctrl = + (struct mwifiex_ds_11n_amsdu_aggr_ctrl *) data_buf; + amsdu_aggr_ctrl->enable = le16_to_cpu(amsdu_ctrl->enable); + amsdu_aggr_ctrl->curr_buf_size = + le16_to_cpu(amsdu_ctrl->curr_buf_size); + } + return 0; +} + +/* + * This function prepares 11n configuration command. + * + * Preparation includes - + * - Setting command ID, action and proper size + * - Setting HT Tx capability and HT Tx information fields + * - Ensuring correct endian-ness + */ +int mwifiex_cmd_11n_cfg(struct mwifiex_private *priv, + struct host_cmd_ds_command *cmd, + u16 cmd_action, void *data_buf) +{ + struct host_cmd_ds_11n_cfg *htcfg = &cmd->params.htcfg; + struct mwifiex_ds_11n_tx_cfg *txcfg = + (struct mwifiex_ds_11n_tx_cfg *) data_buf; + + cmd->command = cpu_to_le16(HostCmd_CMD_11N_CFG); + cmd->size = cpu_to_le16(sizeof(struct host_cmd_ds_11n_cfg) + S_DS_GEN); + htcfg->action = cpu_to_le16(cmd_action); + htcfg->ht_tx_cap = cpu_to_le16(txcfg->tx_htcap); + htcfg->ht_tx_info = cpu_to_le16(txcfg->tx_htinfo); + return 0; +} + +/* + * This function appends an 11n TLV to a buffer. + * + * Buffer allocation is responsibility of the calling + * function. No size validation is made here. + * + * The function fills up the following sections, if applicable - + * - HT capability IE + * - HT information IE (with channel list) + * - 20/40 BSS Coexistence IE + * - HT Extended Capabilities IE + */ +int +mwifiex_cmd_append_11n_tlv(struct mwifiex_private *priv, + struct mwifiex_bssdescriptor *bss_desc, + u8 **buffer) +{ + struct mwifiex_ie_types_htcap *ht_cap; + struct mwifiex_ie_types_htinfo *ht_info; + struct mwifiex_ie_types_chan_list_param_set *chan_list; + struct mwifiex_ie_types_2040bssco *bss_co_2040; + struct mwifiex_ie_types_extcap *ext_cap; + int ret_len = 0; + + if (!buffer || !*buffer) + return ret_len; + + if (bss_desc->bcn_ht_cap) { + ht_cap = (struct mwifiex_ie_types_htcap *) *buffer; + memset(ht_cap, 0, sizeof(struct mwifiex_ie_types_htcap)); + ht_cap->header.type = cpu_to_le16(WLAN_EID_HT_CAPABILITY); + ht_cap->header.len = + cpu_to_le16(sizeof(struct ieee80211_ht_cap)); + memcpy((u8 *) ht_cap + sizeof(struct mwifiex_ie_types_header), + (u8 *) bss_desc->bcn_ht_cap + + sizeof(struct ieee_types_header), + le16_to_cpu(ht_cap->header.len)); + + mwifiex_fill_cap_info(priv, ht_cap); + + *buffer += sizeof(struct mwifiex_ie_types_htcap); + ret_len += sizeof(struct mwifiex_ie_types_htcap); + } + + if (bss_desc->bcn_ht_info) { + if (priv->bss_mode == MWIFIEX_BSS_MODE_IBSS) { + ht_info = (struct mwifiex_ie_types_htinfo *) *buffer; + memset(ht_info, 0, + sizeof(struct mwifiex_ie_types_htinfo)); + ht_info->header.type = + cpu_to_le16(WLAN_EID_HT_INFORMATION); + ht_info->header.len = + cpu_to_le16(sizeof(struct ieee80211_ht_info)); + + memcpy((u8 *) ht_info + + sizeof(struct mwifiex_ie_types_header), + (u8 *) bss_desc->bcn_ht_info + + sizeof(struct ieee_types_header), + le16_to_cpu(ht_info->header.len)); + + if (!ISSUPP_CHANWIDTH40 + (priv->adapter->hw_dot_11n_dev_cap) + || !ISSUPP_CHANWIDTH40(priv->adapter-> + usr_dot_11n_dev_cap)) + RESET_CHANWIDTH40(ht_info->ht_info.ht_param); + + *buffer += sizeof(struct mwifiex_ie_types_htinfo); + ret_len += sizeof(struct mwifiex_ie_types_htinfo); + } + + chan_list = + (struct mwifiex_ie_types_chan_list_param_set *) *buffer; + memset(chan_list, 0, + sizeof(struct mwifiex_ie_types_chan_list_param_set)); + chan_list->header.type = cpu_to_le16(TLV_TYPE_CHANLIST); + chan_list->header.len = cpu_to_le16( + sizeof(struct mwifiex_ie_types_chan_list_param_set) - + sizeof(struct mwifiex_ie_types_header)); + chan_list->chan_scan_param[0].chan_number = + bss_desc->bcn_ht_info->control_chan; + chan_list->chan_scan_param[0].radio_type = + mwifiex_band_to_radio_type((u8) bss_desc->bss_band); + + if ((ISSUPP_CHANWIDTH40(priv->adapter->hw_dot_11n_dev_cap) && + ISSUPP_CHANWIDTH40(priv->adapter->usr_dot_11n_dev_cap)) + && ISALLOWED_CHANWIDTH40(bss_desc->bcn_ht_info->ht_param)) + SET_SECONDARYCHAN(chan_list->chan_scan_param[0]. + radio_type, + GET_SECONDARYCHAN(bss_desc-> + bcn_ht_info->ht_param)); + + *buffer += sizeof(struct mwifiex_ie_types_chan_list_param_set); + ret_len += sizeof(struct mwifiex_ie_types_chan_list_param_set); + } + + if (bss_desc->bcn_bss_co_2040) { + bss_co_2040 = (struct mwifiex_ie_types_2040bssco *) *buffer; + memset(bss_co_2040, 0, + sizeof(struct mwifiex_ie_types_2040bssco)); + bss_co_2040->header.type = cpu_to_le16(WLAN_EID_BSS_COEX_2040); + bss_co_2040->header.len = + cpu_to_le16(sizeof(bss_co_2040->bss_co_2040)); + + memcpy((u8 *) bss_co_2040 + + sizeof(struct mwifiex_ie_types_header), + (u8 *) bss_desc->bcn_bss_co_2040 + + sizeof(struct ieee_types_header), + le16_to_cpu(bss_co_2040->header.len)); + + *buffer += sizeof(struct mwifiex_ie_types_2040bssco); + ret_len += sizeof(struct mwifiex_ie_types_2040bssco); + } + + if (bss_desc->bcn_ext_cap) { + ext_cap = (struct mwifiex_ie_types_extcap *) *buffer; + memset(ext_cap, 0, sizeof(struct mwifiex_ie_types_extcap)); + ext_cap->header.type = cpu_to_le16(WLAN_EID_EXT_CAPABILITY); + ext_cap->header.len = cpu_to_le16(sizeof(ext_cap->ext_cap)); + + memcpy((u8 *) ext_cap + + sizeof(struct mwifiex_ie_types_header), + (u8 *) bss_desc->bcn_ext_cap + + sizeof(struct ieee_types_header), + le16_to_cpu(ext_cap->header.len)); + + *buffer += sizeof(struct mwifiex_ie_types_extcap); + ret_len += sizeof(struct mwifiex_ie_types_extcap); + } + + return ret_len; +} + +/* + * This function reconfigures the Tx buffer size in firmware. + * + * This function prepares a firmware command and issues it, if + * the current Tx buffer size is different from the one requested. + * Maximum configurable Tx buffer size is limited by the HT capability + * field value. + */ +void +mwifiex_cfg_tx_buf(struct mwifiex_private *priv, + struct mwifiex_bssdescriptor *bss_desc) +{ + u16 max_amsdu = MWIFIEX_TX_DATA_BUF_SIZE_2K; + u16 tx_buf = 0; + u16 curr_tx_buf_size = 0; + + if (bss_desc->bcn_ht_cap) { + if (GETHT_MAXAMSDU(le16_to_cpu(bss_desc->bcn_ht_cap->cap_info))) + max_amsdu = MWIFIEX_TX_DATA_BUF_SIZE_8K; + else + max_amsdu = MWIFIEX_TX_DATA_BUF_SIZE_4K; + } + + tx_buf = min(priv->adapter->max_tx_buf_size, max_amsdu); + + dev_dbg(priv->adapter->dev, "info: max_amsdu=%d, max_tx_buf=%d\n", + max_amsdu, priv->adapter->max_tx_buf_size); + + if (priv->adapter->curr_tx_buf_size <= MWIFIEX_TX_DATA_BUF_SIZE_2K) + curr_tx_buf_size = MWIFIEX_TX_DATA_BUF_SIZE_2K; + else if (priv->adapter->curr_tx_buf_size <= MWIFIEX_TX_DATA_BUF_SIZE_4K) + curr_tx_buf_size = MWIFIEX_TX_DATA_BUF_SIZE_4K; + else if (priv->adapter->curr_tx_buf_size <= MWIFIEX_TX_DATA_BUF_SIZE_8K) + curr_tx_buf_size = MWIFIEX_TX_DATA_BUF_SIZE_8K; + if (curr_tx_buf_size != tx_buf) + mwifiex_prepare_cmd(priv, HostCmd_CMD_RECONFIGURE_TX_BUFF, + HostCmd_ACT_GEN_SET, 0, + NULL, &tx_buf); + + return; +} + +/* + * This function checks if the given pointer is valid entry of + * Tx BA Stream table. + */ +static int mwifiex_is_tx_ba_stream_ptr_valid(struct mwifiex_private *priv, + struct mwifiex_tx_ba_stream_tbl *tx_tbl_ptr) +{ + struct mwifiex_tx_ba_stream_tbl *tx_ba_tsr_tbl; + + list_for_each_entry(tx_ba_tsr_tbl, &priv->tx_ba_stream_tbl_ptr, list) { + if (tx_ba_tsr_tbl == tx_tbl_ptr) + return true; + } + + return false; +} + +/* + * This function deletes the given entry in Tx BA Stream table. + * + * The function also performs a validity check on the supplied + * pointer before trying to delete. + */ +void mwifiex_11n_delete_tx_ba_stream_tbl_entry(struct mwifiex_private *priv, + struct mwifiex_tx_ba_stream_tbl *tx_ba_tsr_tbl) +{ + if (!tx_ba_tsr_tbl && + mwifiex_is_tx_ba_stream_ptr_valid(priv, tx_ba_tsr_tbl)) + return; + + dev_dbg(priv->adapter->dev, "info: tx_ba_tsr_tbl %p\n", tx_ba_tsr_tbl); + + list_del(&tx_ba_tsr_tbl->list); + + kfree(tx_ba_tsr_tbl); + + return; +} + +/* + * This function deletes all the entries in Tx BA Stream table. + */ +void mwifiex_11n_delete_all_tx_ba_stream_tbl(struct mwifiex_private *priv) +{ + int i; + struct mwifiex_tx_ba_stream_tbl *del_tbl_ptr, *tmp_node; + unsigned long flags; + + spin_lock_irqsave(&priv->tx_ba_stream_tbl_lock, flags); + list_for_each_entry_safe(del_tbl_ptr, tmp_node, + &priv->tx_ba_stream_tbl_ptr, list) + mwifiex_11n_delete_tx_ba_stream_tbl_entry(priv, del_tbl_ptr); + spin_unlock_irqrestore(&priv->tx_ba_stream_tbl_lock, flags); + + INIT_LIST_HEAD(&priv->tx_ba_stream_tbl_ptr); + + for (i = 0; i < MAX_NUM_TID; ++i) + priv->aggr_prio_tbl[i].ampdu_ap = + priv->aggr_prio_tbl[i].ampdu_user; +} + +/* + * This function returns the pointer to an entry in BA Stream + * table which matches the given RA/TID pair. + */ +struct mwifiex_tx_ba_stream_tbl * +mwifiex_11n_get_tx_ba_stream_tbl(struct mwifiex_private *priv, + int tid, u8 *ra) +{ + struct mwifiex_tx_ba_stream_tbl *tx_ba_tsr_tbl; + unsigned long flags; + + spin_lock_irqsave(&priv->tx_ba_stream_tbl_lock, flags); + list_for_each_entry(tx_ba_tsr_tbl, &priv->tx_ba_stream_tbl_ptr, list) { + if ((!memcmp(tx_ba_tsr_tbl->ra, ra, ETH_ALEN)) + && (tx_ba_tsr_tbl->tid == tid)) { + spin_unlock_irqrestore(&priv->tx_ba_stream_tbl_lock, + flags); + return tx_ba_tsr_tbl; + } + } + spin_unlock_irqrestore(&priv->tx_ba_stream_tbl_lock, flags); + return NULL; +} + +/* + * This function creates an entry in Tx BA stream table for the + * given RA/TID pair. + */ +void mwifiex_11n_create_tx_ba_stream_tbl(struct mwifiex_private *priv, + u8 *ra, int tid, + enum mwifiex_ba_status ba_status) +{ + struct mwifiex_tx_ba_stream_tbl *new_node; + unsigned long flags; + + if (!mwifiex_11n_get_tx_ba_stream_tbl(priv, tid, ra)) { + new_node = kzalloc(sizeof(struct mwifiex_tx_ba_stream_tbl), + GFP_ATOMIC); + if (!new_node) { + dev_err(priv->adapter->dev, + "%s: failed to alloc new_node\n", __func__); + return; + } + + INIT_LIST_HEAD(&new_node->list); + + new_node->tid = tid; + new_node->ba_status = ba_status; + memcpy(new_node->ra, ra, ETH_ALEN); + + spin_lock_irqsave(&priv->tx_ba_stream_tbl_lock, flags); + list_add_tail(&new_node->list, &priv->tx_ba_stream_tbl_ptr); + spin_unlock_irqrestore(&priv->tx_ba_stream_tbl_lock, flags); + } + + return; +} + +/* + * This function sends an add BA request to the given TID/RA pair. + */ +int mwifiex_send_addba(struct mwifiex_private *priv, int tid, u8 *peer_mac) +{ + struct host_cmd_ds_11n_addba_req add_ba_req; + static u8 dialog_tok; + int ret; + + dev_dbg(priv->adapter->dev, "cmd: %s: tid %d\n", __func__, tid); + + add_ba_req.block_ack_param_set = cpu_to_le16( + (u16) ((tid << BLOCKACKPARAM_TID_POS) | + (priv->add_ba_param. + tx_win_size << BLOCKACKPARAM_WINSIZE_POS) | + IMMEDIATE_BLOCK_ACK)); + add_ba_req.block_ack_tmo = cpu_to_le16((u16)priv->add_ba_param.timeout); + + ++dialog_tok; + + if (dialog_tok == 0) + dialog_tok = 1; + + add_ba_req.dialog_token = dialog_tok; + memcpy(&add_ba_req.peer_mac_addr, peer_mac, ETH_ALEN); + + /* We don't wait for the response of this command */ + ret = mwifiex_prepare_cmd(priv, HostCmd_CMD_11N_ADDBA_REQ, + 0, 0, NULL, &add_ba_req); + + return ret; +} + +/* + * This function sends a delete BA request to the given TID/RA pair. + */ +int mwifiex_send_delba(struct mwifiex_private *priv, int tid, u8 *peer_mac, + int initiator) +{ + struct host_cmd_ds_11n_delba delba; + int ret; + uint16_t del_ba_param_set; + + memset(&delba, 0, sizeof(delba)); + delba.del_ba_param_set = cpu_to_le16(tid << DELBA_TID_POS); + + del_ba_param_set = le16_to_cpu(delba.del_ba_param_set); + if (initiator) + del_ba_param_set |= IEEE80211_DELBA_PARAM_INITIATOR_MASK; + else + del_ba_param_set &= ~IEEE80211_DELBA_PARAM_INITIATOR_MASK; + + memcpy(&delba.peer_mac_addr, peer_mac, ETH_ALEN); + + /* We don't wait for the response of this command */ + ret = mwifiex_prepare_cmd(priv, HostCmd_CMD_11N_DELBA, + HostCmd_ACT_GEN_SET, 0, NULL, &delba); + + return ret; +} + +/* + * This function handles the command response of a delete BA request. + */ +void mwifiex_11n_delete_ba_stream(struct mwifiex_private *priv, u8 *del_ba) +{ + struct host_cmd_ds_11n_delba *cmd_del_ba = + (struct host_cmd_ds_11n_delba *) del_ba; + uint16_t del_ba_param_set = le16_to_cpu(cmd_del_ba->del_ba_param_set); + int tid; + + tid = del_ba_param_set >> DELBA_TID_POS; + + mwifiex_11n_delete_ba_stream_tbl(priv, tid, cmd_del_ba->peer_mac_addr, + TYPE_DELBA_RECEIVE, + INITIATOR_BIT(del_ba_param_set)); +} + +/* + * This function retrieves the Rx reordering table. + */ +int mwifiex_get_rx_reorder_tbl(struct mwifiex_private *priv, + struct mwifiex_ds_rx_reorder_tbl *buf) +{ + int i; + struct mwifiex_ds_rx_reorder_tbl *rx_reo_tbl = buf; + struct mwifiex_rx_reorder_tbl *rx_reorder_tbl_ptr; + int count = 0; + unsigned long flags; + + spin_lock_irqsave(&priv->rx_reorder_tbl_lock, flags); + list_for_each_entry(rx_reorder_tbl_ptr, &priv->rx_reorder_tbl_ptr, + list) { + rx_reo_tbl->tid = (u16) rx_reorder_tbl_ptr->tid; + memcpy(rx_reo_tbl->ta, rx_reorder_tbl_ptr->ta, ETH_ALEN); + rx_reo_tbl->start_win = rx_reorder_tbl_ptr->start_win; + rx_reo_tbl->win_size = rx_reorder_tbl_ptr->win_size; + for (i = 0; i < rx_reorder_tbl_ptr->win_size; ++i) { + if (rx_reorder_tbl_ptr->rx_reorder_ptr[i]) + rx_reo_tbl->buffer[i] = true; + else + rx_reo_tbl->buffer[i] = false; + } + rx_reo_tbl++; + count++; + + if (count >= MWIFIEX_MAX_RX_BASTREAM_SUPPORTED) + break; + } + spin_unlock_irqrestore(&priv->rx_reorder_tbl_lock, flags); + + return count; +} + +/* + * This function retrieves the Tx BA stream table. + */ +int mwifiex_get_tx_ba_stream_tbl(struct mwifiex_private *priv, + struct mwifiex_ds_tx_ba_stream_tbl *buf) +{ + struct mwifiex_tx_ba_stream_tbl *tx_ba_tsr_tbl; + struct mwifiex_ds_tx_ba_stream_tbl *rx_reo_tbl = buf; + int count = 0; + unsigned long flags; + + spin_lock_irqsave(&priv->tx_ba_stream_tbl_lock, flags); + list_for_each_entry(tx_ba_tsr_tbl, &priv->tx_ba_stream_tbl_ptr, list) { + rx_reo_tbl->tid = (u16) tx_ba_tsr_tbl->tid; + dev_dbg(priv->adapter->dev, "data: %s tid=%d\n", + __func__, rx_reo_tbl->tid); + memcpy(rx_reo_tbl->ra, tx_ba_tsr_tbl->ra, ETH_ALEN); + rx_reo_tbl++; + count++; + if (count >= MWIFIEX_MAX_TX_BASTREAM_SUPPORTED) + break; + } + spin_unlock_irqrestore(&priv->tx_ba_stream_tbl_lock, flags); + + return count; +} diff --git a/drivers/net/wireless/mwifiex/11n.h b/drivers/net/wireless/mwifiex/11n.h new file mode 100644 index 0000000..769a27f --- /dev/null +++ b/drivers/net/wireless/mwifiex/11n.h @@ -0,0 +1,178 @@ +/* + * Marvell Wireless LAN device driver: 802.11n + * + * Copyright (C) 2011, Marvell International Ltd. + * + * This software file (the "File") is distributed by Marvell International + * Ltd. under the terms of the GNU General Public License Version 2, June 1991 + * (the "License"). You may use, redistribute and/or modify this File in + * accordance with the terms and conditions of the License, a copy of which + * is available by writing to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the + * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. + * + * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE + * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE + * ARE EXPRESSLY DISCLAIMED. The License provides additional details about + * this warranty disclaimer. + */ + +#ifndef _MWIFIEX_11N_H_ +#define _MWIFIEX_11N_H_ + +#include "11n_aggr.h" +#include "11n_rxreorder.h" +#include "wmm.h" + +void mwifiex_show_dot_11n_dev_cap(struct mwifiex_adapter *adapter, u32 cap); +void mwifiex_show_dev_mcs_support(struct mwifiex_adapter *adapter, u8 support); +int mwifiex_ret_11n_delba(struct mwifiex_private *priv, + struct host_cmd_ds_command *resp); +int mwifiex_ret_11n_addba_req(struct mwifiex_private *priv, + struct host_cmd_ds_command *resp); +int mwifiex_ret_11n_cfg(struct mwifiex_private *priv, + struct host_cmd_ds_command *resp, + void *data_buf); +int mwifiex_cmd_11n_cfg(struct mwifiex_private *priv, + struct host_cmd_ds_command *cmd, + u16 cmd_action, void *data_buf); + +int mwifiex_cmd_11n_cfg(struct mwifiex_private *priv, + struct host_cmd_ds_command *cmd, + u16 cmd_action, void *data_buf); + +int mwifiex_cmd_append_11n_tlv(struct mwifiex_private *priv, + struct mwifiex_bssdescriptor *bss_desc, + u8 **buffer); +void mwifiex_cfg_tx_buf(struct mwifiex_private *priv, + struct mwifiex_bssdescriptor *bss_desc); +void mwifiex_fill_cap_info(struct mwifiex_private *, + struct mwifiex_ie_types_htcap *); +int mwifiex_set_get_11n_htcap_cfg(struct mwifiex_private *priv, + u16 action, int *htcap_cfg); +void mwifiex_11n_delete_tx_ba_stream_tbl_entry(struct mwifiex_private *priv, + struct mwifiex_tx_ba_stream_tbl + *tx_tbl); +void mwifiex_11n_delete_all_tx_ba_stream_tbl(struct mwifiex_private *priv); +struct mwifiex_tx_ba_stream_tbl *mwifiex_11n_get_tx_ba_stream_tbl(struct + mwifiex_private + *priv, int tid, + u8 *ra); +void mwifiex_11n_create_tx_ba_stream_tbl(struct mwifiex_private *priv, u8 *ra, + int tid, + enum mwifiex_ba_status ba_status); +int mwifiex_send_addba(struct mwifiex_private *priv, int tid, u8 *peer_mac); +int mwifiex_send_delba(struct mwifiex_private *priv, int tid, u8 *peer_mac, + int initiator); +void mwifiex_11n_delete_ba_stream(struct mwifiex_private *priv, u8 *del_ba); +int mwifiex_get_rx_reorder_tbl(struct mwifiex_private *priv, + struct mwifiex_ds_rx_reorder_tbl *buf); +int mwifiex_get_tx_ba_stream_tbl(struct mwifiex_private *priv, + struct mwifiex_ds_tx_ba_stream_tbl *buf); +int mwifiex_ret_amsdu_aggr_ctrl(struct mwifiex_private *priv, + struct host_cmd_ds_command + *resp, + void *data_buf); +int mwifiex_cmd_recfg_tx_buf(struct mwifiex_private *priv, + struct host_cmd_ds_command *cmd, + int cmd_action, void *data_buf); +int mwifiex_cmd_amsdu_aggr_ctrl(struct mwifiex_private *priv, + struct host_cmd_ds_command *cmd, + int cmd_action, + void *data_buf); + +/* + * This function checks whether AMPDU is allowed or not for a particular TID. + */ +static inline u8 +mwifiex_is_ampdu_allowed(struct mwifiex_private *priv, + struct mwifiex_ra_list_tbl *ptr, int tid) +{ + return ((priv->aggr_prio_tbl[tid].ampdu_ap != BA_STREAM_NOT_ALLOWED) + ? true : false); +} + +/* + * This function checks whether AMSDU is allowed or not for a particular TID. + */ +static inline u8 +mwifiex_is_amsdu_allowed(struct mwifiex_private *priv, + struct mwifiex_ra_list_tbl *ptr, int tid) +{ + return (((priv->aggr_prio_tbl[tid].amsdu != BA_STREAM_NOT_ALLOWED) + && ((priv->is_data_rate_auto) + || !((priv->bitmap_rates[2]) & 0x03))) + ? true : false); +} + +/* + * This function checks whether a BA stream is available or not. + */ +static inline u8 +mwifiex_is_ba_stream_avail(struct mwifiex_private *priv) +{ + struct mwifiex_private *pmpriv = NULL; + u8 i = 0; + u32 ba_stream_num = 0; + + for (i = 0; i < priv->adapter->priv_num; i++) { + pmpriv = priv->adapter->priv[i]; + if (pmpriv) + ba_stream_num += + mwifiex_wmm_list_len(priv->adapter, + (struct list_head + *) &pmpriv-> + tx_ba_stream_tbl_ptr); + } + + return ((ba_stream_num < + MWIFIEX_MAX_TX_BASTREAM_SUPPORTED) ? true : false); +} + +/* + * This function finds the correct Tx BA stream to delete. + * + * Upon successfully locating, both the TID and the RA are returned. + */ +static inline u8 +mwifiex_find_stream_to_delete(struct mwifiex_private *priv, + struct mwifiex_ra_list_tbl *ptr, int ptr_tid, + int *ptid, u8 *ra) +{ + int tid; + u8 ret = false; + struct mwifiex_tx_ba_stream_tbl *tx_tbl; + unsigned long flags; + + tid = priv->aggr_prio_tbl[ptr_tid].ampdu_user; + + spin_lock_irqsave(&priv->tx_ba_stream_tbl_lock, flags); + list_for_each_entry(tx_tbl, &priv->tx_ba_stream_tbl_ptr, list) { + if (tid > priv->aggr_prio_tbl[tx_tbl->tid].ampdu_user) { + tid = priv->aggr_prio_tbl[tx_tbl->tid].ampdu_user; + *ptid = tx_tbl->tid; + memcpy(ra, tx_tbl->ra, ETH_ALEN); + ret = true; + } + } + spin_unlock_irqrestore(&priv->tx_ba_stream_tbl_lock, flags); + + return ret; +} + +/* + * This function checks whether BA stream is set up or not. + */ +static inline int +mwifiex_is_ba_stream_setup(struct mwifiex_private *priv, + struct mwifiex_ra_list_tbl *ptr, int tid) +{ + struct mwifiex_tx_ba_stream_tbl *tx_tbl; + + tx_tbl = mwifiex_11n_get_tx_ba_stream_tbl(priv, tid, ptr->ra); + if (tx_tbl && IS_BASTREAM_SETUP(tx_tbl)) + return true; + + return false; +} +#endif /* !_MWIFIEX_11N_H_ */ diff --git a/drivers/net/wireless/mwifiex/11n_aggr.c b/drivers/net/wireless/mwifiex/11n_aggr.c new file mode 100644 index 0000000..c2abced --- /dev/null +++ b/drivers/net/wireless/mwifiex/11n_aggr.c @@ -0,0 +1,423 @@ +/* + * Marvell Wireless LAN device driver: 802.11n Aggregation + * + * Copyright (C) 2011, Marvell International Ltd. + * + * This software file (the "File") is distributed by Marvell International + * Ltd. under the terms of the GNU General Public License Version 2, June 1991 + * (the "License"). You may use, redistribute and/or modify this File in + * accordance with the terms and conditions of the License, a copy of which + * is available by writing to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the + * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. + * + * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE + * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE + * ARE EXPRESSLY DISCLAIMED. The License provides additional details about + * this warranty disclaimer. + */ + +#include "decl.h" +#include "ioctl.h" +#include "util.h" +#include "fw.h" +#include "main.h" +#include "wmm.h" +#include "11n.h" +#include "11n_aggr.h" + +/* + * Creates an AMSDU subframe for aggregation into one AMSDU packet. + * + * The resultant AMSDU subframe format is - + * + * +---- ~ -----+---- ~ ------+---- ~ -----+----- ~ -----+---- ~ -----+ + * | DA | SA | Length | SNAP header | MSDU | + * | data[0..5] | data[6..11] | | | data[14..] | + * +---- ~ -----+---- ~ ------+---- ~ -----+----- ~ -----+---- ~ -----+ + * <--6-bytes--> <--6-bytes--> <--2-bytes--><--8-bytes--> <--n-bytes--> + * + * This function also computes the amount of padding required to make the + * buffer length multiple of 4 bytes. + * + * Data => |DA|SA|SNAP-TYPE|........ .| + * MSDU => |DA|SA|Length|SNAP|...... ..| + */ +static int +mwifiex_11n_form_amsdu_pkt(struct mwifiex_adapter *adapter, + struct sk_buff *skb_aggr, + struct sk_buff *skb_src, int *pad) + +{ + int dt_offset; + struct rfc_1042_hdr snap = { + 0xaa, /* LLC DSAP */ + 0xaa, /* LLC SSAP */ + 0x03, /* LLC CTRL */ + {0x00, 0x00, 0x00}, /* SNAP OUI */ + 0x0000 /* SNAP type */ + /* + * This field will be overwritten + * later with ethertype + */ + }; + struct tx_packet_hdr *tx_header = NULL; + + skb_put(skb_aggr, sizeof(*tx_header)); + + tx_header = (struct tx_packet_hdr *) skb_aggr->data; + + /* Copy DA and SA */ + dt_offset = 2 * ETH_ALEN; + memcpy(&tx_header->eth803_hdr, skb_src->data, dt_offset); + + /* Copy SNAP header */ + snap.snap_type = *(u16 *) ((u8 *)skb_src->data + dt_offset); + dt_offset += sizeof(u16); + + memcpy(&tx_header->rfc1042_hdr, &snap, sizeof(struct rfc_1042_hdr)); + + skb_pull(skb_src, dt_offset); + + /* Update Length field */ + tx_header->eth803_hdr.h_proto = htons(skb_src->len + LLC_SNAP_LEN); + + /* Add payload */ + skb_put(skb_aggr, skb_src->len); + memcpy(skb_aggr->data + sizeof(*tx_header), skb_src->data, + skb_src->len); + *pad = (((skb_src->len + LLC_SNAP_LEN) & 3)) ? (4 - (((skb_src->len + + LLC_SNAP_LEN)) & 3)) : 0; + skb_put(skb_aggr, *pad); + + return skb_aggr->len + *pad; +} + +/* + * Adds TxPD to AMSDU header. + * + * Each AMSDU packet will contain one TxPD at the beginning, + * followed by multiple AMSDU subframes. + */ +static void +mwifiex_11n_form_amsdu_txpd(struct mwifiex_private *priv, + struct sk_buff *skb) +{ + struct txpd *local_tx_pd; + + skb_push(skb, sizeof(*local_tx_pd)); + + local_tx_pd = (struct txpd *) skb->data; + memset(local_tx_pd, 0, sizeof(struct txpd)); + + /* Original priority has been overwritten */ + local_tx_pd->priority = (u8) skb->priority; + local_tx_pd->pkt_delay_2ms = + mwifiex_wmm_compute_drv_pkt_delay(priv, skb); + local_tx_pd->bss_num = priv->bss_num; + local_tx_pd->bss_type = priv->bss_type; + /* Always zero as the data is followed by struct txpd */ + local_tx_pd->tx_pkt_offset = cpu_to_le16(sizeof(struct txpd)); + local_tx_pd->tx_pkt_type = cpu_to_le16(PKT_TYPE_AMSDU); + local_tx_pd->tx_pkt_length = cpu_to_le16(skb->len - + sizeof(*local_tx_pd)); + + if (local_tx_pd->tx_control == 0) + /* TxCtrl set by user or default */ + local_tx_pd->tx_control = cpu_to_le32(priv->pkt_tx_ctrl); + + if ((GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_STA) && + (priv->adapter->pps_uapsd_mode)) { + if (true == mwifiex_check_last_packet_indication(priv)) { + priv->adapter->tx_lock_flag = true; + local_tx_pd->flags = + MWIFIEX_TxPD_POWER_MGMT_LAST_PACKET; + } + } +} + +/* + * Counts the number of subframes in an aggregate packet. + * + * This function parses an aggregate packet buffer, looking for + * subframes and counting the number of such subframe found. The + * function automatically skips the DA/SA fields at the beginning + * of each subframe and padding at the end. + */ +static int +mwifiex_11n_get_num_aggr_pkts(u8 *data, int total_pkt_len) +{ + int pkt_count = 0, pkt_len, pad; + + while (total_pkt_len > 0) { + /* Length will be in network format, change it to host */ + pkt_len = ntohs((*(__be16 *)(data + 2 * ETH_ALEN))); + pad = (((pkt_len + sizeof(struct ethhdr)) & 3)) ? + (4 - ((pkt_len + sizeof(struct ethhdr)) & 3)) : 0; + data += pkt_len + pad + sizeof(struct ethhdr); + total_pkt_len -= pkt_len + pad + sizeof(struct ethhdr); + ++pkt_count; + } + + return pkt_count; +} + +/* + * De-aggregate received packets. + * + * This function parses the received aggregate buffer, extracts each subframe, + * strips off the SNAP header from them and sends the data portion for further + * processing. + * + * Each subframe body is copied onto a separate buffer, which are freed by + * upper layer after processing. The function also performs sanity tests on + * the received buffer. + */ +int mwifiex_11n_deaggregate_pkt(struct mwifiex_private *priv, + struct sk_buff *skb) +{ + u16 pkt_len; + int total_pkt_len; + u8 *data; + int pad; + struct mwifiex_rxinfo *rx_info = MWIFIEX_SKB_RXCB(skb); + struct rxpd *local_rx_pd = (struct rxpd *) skb->data; + struct sk_buff *skb_daggr; + struct mwifiex_rxinfo *rx_info_daggr = NULL; + int ret = -1; + struct rx_packet_hdr *rx_pkt_hdr; + struct mwifiex_adapter *adapter = priv->adapter; + u8 rfc1042_eth_hdr[ETH_ALEN] = { 0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00}; + + data = (u8 *) (local_rx_pd + local_rx_pd->rx_pkt_offset); + total_pkt_len = local_rx_pd->rx_pkt_length; + + /* Sanity test */ + if (total_pkt_len > MWIFIEX_RX_DATA_BUF_SIZE) { + dev_err(adapter->dev, "total pkt len greater than buffer" + " size %d\n", total_pkt_len); + return -1; + } + + rx_info->use_count = mwifiex_11n_get_num_aggr_pkts(data, total_pkt_len); + + while (total_pkt_len > 0) { + rx_pkt_hdr = (struct rx_packet_hdr *) data; + /* Length will be in network format, change it to host */ + pkt_len = ntohs((*(__be16 *) (data + 2 * ETH_ALEN))); + if (pkt_len > total_pkt_len) { + dev_err(adapter->dev, "pkt_len %d > total_pkt_len %d\n", + total_pkt_len, pkt_len); + break; + } + + pad = (((pkt_len + sizeof(struct ethhdr)) & 3)) ? + (4 - ((pkt_len + sizeof(struct ethhdr)) & 3)) : 0; + + total_pkt_len -= pkt_len + pad + sizeof(struct ethhdr); + + if (memcmp(&rx_pkt_hdr->rfc1042_hdr, + rfc1042_eth_hdr, sizeof(rfc1042_eth_hdr)) == 0) { + memmove(data + LLC_SNAP_LEN, data, 2 * ETH_ALEN); + data += LLC_SNAP_LEN; + pkt_len += sizeof(struct ethhdr) - LLC_SNAP_LEN; + } else { + *(u16 *) (data + 2 * ETH_ALEN) = (u16) 0; + pkt_len += sizeof(struct ethhdr); + } + + skb_daggr = dev_alloc_skb(pkt_len); + if (!skb_daggr) { + dev_err(adapter->dev, "%s: failed to alloc skb_daggr\n", + __func__); + return -1; + } + rx_info_daggr = MWIFIEX_SKB_RXCB(skb_daggr); + + rx_info_daggr->bss_index = rx_info->bss_index; + skb_daggr->tstamp = skb->tstamp; + rx_info_daggr->parent = skb; + skb_daggr->priority = skb->priority; + skb_put(skb_daggr, pkt_len); + memcpy(skb_daggr->data, data, pkt_len); + + ret = mwifiex_recv_packet(adapter, skb_daggr); + + switch (ret) { + case -EINPROGRESS: + break; + case -1: + dev_err(adapter->dev, "deaggr: host_to_card failed\n"); + case 0: + mwifiex_recv_packet_complete(adapter, skb_daggr, ret); + break; + default: + break; + } + + data += pkt_len + pad; + } + + return ret; +} + +/* + * Create aggregated packet. + * + * This function creates an aggregated MSDU packet, by combining buffers + * from the RA list. Each individual buffer is encapsulated as an AMSDU + * subframe and all such subframes are concatenated together to form the + * AMSDU packet. + * + * A TxPD is also added to the front of the resultant AMSDU packets for + * transmission. The resultant packets format is - + * + * +---- ~ ----+------ ~ ------+------ ~ ------+-..-+------ ~ ------+ + * | TxPD |AMSDU sub-frame|AMSDU sub-frame| .. |AMSDU sub-frame| + * | | 1 | 2 | .. | n | + * +---- ~ ----+------ ~ ------+------ ~ ------+ .. +------ ~ ------+ + */ +int +mwifiex_11n_aggregate_pkt(struct mwifiex_private *priv, + struct mwifiex_ra_list_tbl *pra_list, int headroom, + int ptrindex, unsigned long ra_list_flags) + __releases(&priv->wmm.ra_list_spinlock) +{ + struct mwifiex_adapter *adapter = priv->adapter; + struct sk_buff *skb_aggr, *skb_src; + struct mwifiex_txinfo *tx_info_aggr, *tx_info_src; + int pad = 0; + int ret = 0; + struct mwifiex_tx_param tx_param; + struct txpd *ptx_pd = NULL; + + if (skb_queue_empty(&pra_list->skb_head)) { + spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock, + ra_list_flags); + return 0; + } + skb_src = skb_peek(&pra_list->skb_head); + tx_info_src = MWIFIEX_SKB_TXCB(skb_src); + skb_aggr = dev_alloc_skb(adapter->tx_buf_size); + if (!skb_aggr) { + dev_err(adapter->dev, "%s: alloc skb_aggr\n", __func__); + spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock, + ra_list_flags); + return -1; + } + skb_reserve(skb_aggr, headroom + sizeof(struct txpd)); + tx_info_aggr = MWIFIEX_SKB_TXCB(skb_aggr); + + tx_info_aggr->bss_index = tx_info_src->bss_index; + skb_aggr->priority = skb_src->priority; + + while (skb_src && ((skb_headroom(skb_aggr) + skb_src->len + + LLC_SNAP_LEN) + <= adapter->tx_buf_size)) { + + if (!skb_queue_empty(&pra_list->skb_head)) + skb_src = skb_dequeue(&pra_list->skb_head); + else + skb_src = NULL; + + pra_list->total_pkts_size -= skb_src->len; + + spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock, + ra_list_flags); + mwifiex_11n_form_amsdu_pkt(adapter, skb_aggr, skb_src, &pad); + + mwifiex_write_data_complete(adapter, skb_src, 0); + + spin_lock_irqsave(&priv->wmm.ra_list_spinlock, ra_list_flags); + + if (!mwifiex_is_ralist_valid(priv, pra_list, ptrindex)) { + spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock, + ra_list_flags); + return -1; + } + + if (!skb_queue_empty(&pra_list->skb_head)) + skb_src = skb_peek(&pra_list->skb_head); + else + skb_src = NULL; + } + + spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock, ra_list_flags); + + /* Last AMSDU packet does not need padding */ + skb_trim(skb_aggr, skb_aggr->len - pad); + + /* Form AMSDU */ + mwifiex_11n_form_amsdu_txpd(priv, skb_aggr); + if (GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_STA) + ptx_pd = (struct txpd *)skb_aggr->data; + + skb_push(skb_aggr, headroom); + + tx_param.next_pkt_len = ((pra_list->total_pkts_size) ? + (((pra_list->total_pkts_size) > + adapter->tx_buf_size) ? adapter-> + tx_buf_size : pra_list->total_pkts_size + + LLC_SNAP_LEN + sizeof(struct txpd)) : 0); + ret = adapter->if_ops.host_to_card(adapter, MWIFIEX_TYPE_DATA, + skb_aggr->data, + skb_aggr->len, &tx_param); + switch (ret) { + case -EBUSY: + spin_lock_irqsave(&priv->wmm.ra_list_spinlock, ra_list_flags); + if (!mwifiex_is_ralist_valid(priv, pra_list, ptrindex)) { + spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock, + ra_list_flags); + mwifiex_write_data_complete(adapter, skb_aggr, -1); + return -1; + } + if ((GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_STA) && + (adapter->pps_uapsd_mode) && + (adapter->tx_lock_flag)) { + priv->adapter->tx_lock_flag = false; + ptx_pd->flags = 0; + } + + skb_queue_tail(&pra_list->skb_head, skb_aggr); + + pra_list->total_pkts_size += skb_aggr->len; + + tx_info_aggr->flags |= MWIFIEX_BUF_FLAG_REQUEUED_PKT; + spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock, + ra_list_flags); + dev_dbg(adapter->dev, "data: -EBUSY is returned\n"); + break; + case -1: + adapter->data_sent = false; + dev_err(adapter->dev, "%s: host_to_card failed: %#x\n", + __func__, ret); + adapter->dbg.num_tx_host_to_card_failure++; + mwifiex_write_data_complete(adapter, skb_aggr, ret); + return 0; + case -EINPROGRESS: + adapter->data_sent = false; + break; + case 0: + mwifiex_write_data_complete(adapter, skb_aggr, ret); + break; + default: + break; + } + if (ret != -EBUSY) { + spin_lock_irqsave(&priv->wmm.ra_list_spinlock, ra_list_flags); + if (mwifiex_is_ralist_valid(priv, pra_list, ptrindex)) { + priv->wmm.packets_out[ptrindex]++; + priv->wmm.tid_tbl_ptr[ptrindex].ra_list_curr = pra_list; + } + /* Now bss_prio_cur pointer points to next node */ + adapter->bss_prio_tbl[priv->bss_priority].bss_prio_cur = + list_first_entry( + &adapter->bss_prio_tbl[priv->bss_priority] + .bss_prio_cur->list, + struct mwifiex_bss_prio_node, list); + spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock, + ra_list_flags); + } + + return 0; +} diff --git a/drivers/net/wireless/mwifiex/11n_aggr.h b/drivers/net/wireless/mwifiex/11n_aggr.h new file mode 100644 index 0000000..9c6dca7 --- /dev/null +++ b/drivers/net/wireless/mwifiex/11n_aggr.h @@ -0,0 +1,32 @@ +/* + * Marvell Wireless LAN device driver: 802.11n Aggregation + * + * Copyright (C) 2011, Marvell International Ltd. + * + * This software file (the "File") is distributed by Marvell International + * Ltd. under the terms of the GNU General Public License Version 2, June 1991 + * (the "License"). You may use, redistribute and/or modify this File in + * accordance with the terms and conditions of the License, a copy of which + * is available by writing to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the + * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. + * + * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE + * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE + * ARE EXPRESSLY DISCLAIMED. The License provides additional details about + * this warranty disclaimer. + */ + +#ifndef _MWIFIEX_11N_AGGR_H_ +#define _MWIFIEX_11N_AGGR_H_ + +#define PKT_TYPE_AMSDU 0xE6 + +int mwifiex_11n_deaggregate_pkt(struct mwifiex_private *priv, + struct sk_buff *skb); +int mwifiex_11n_aggregate_pkt(struct mwifiex_private *priv, + struct mwifiex_ra_list_tbl *ptr, int headroom, + int ptr_index, unsigned long flags) + __releases(&priv->wmm.ra_list_spinlock); + +#endif /* !_MWIFIEX_11N_AGGR_H_ */ diff --git a/drivers/net/wireless/mwifiex/11n_rxreorder.c b/drivers/net/wireless/mwifiex/11n_rxreorder.c new file mode 100644 index 0000000..8e94e62 --- /dev/null +++ b/drivers/net/wireless/mwifiex/11n_rxreorder.c @@ -0,0 +1,637 @@ +/* + * Marvell Wireless LAN device driver: 802.11n RX Re-ordering + * + * Copyright (C) 2011, Marvell International Ltd. + * + * This software file (the "File") is distributed by Marvell International + * Ltd. under the terms of the GNU General Public License Version 2, June 1991 + * (the "License"). You may use, redistribute and/or modify this File in + * accordance with the terms and conditions of the License, a copy of which + * is available by writing to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the + * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. + * + * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE + * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE + * ARE EXPRESSLY DISCLAIMED. The License provides additional details about + * this warranty disclaimer. + */ + +#include "decl.h" +#include "ioctl.h" +#include "util.h" +#include "fw.h" +#include "main.h" +#include "wmm.h" +#include "11n.h" +#include "11n_rxreorder.h" + +/* + * This function processes a received packet and forwards + * it to the kernel/upper layer. + */ +static int mwifiex_11n_dispatch_pkt(struct mwifiex_private *priv, void *payload) +{ + int ret = 0; + struct mwifiex_adapter *adapter = priv->adapter; + + ret = mwifiex_process_rx_packet(adapter, (struct sk_buff *) payload); + return ret; +} + +/* + * This function dispatches all packets in the Rx reorder table. + * + * There could be holes in the buffer, which are skipped by the function. + * Since the buffer is linear, the function uses rotation to simulate + * circular buffer. + */ +static int +mwifiex_11n_dispatch_pkt_until_start_win(struct mwifiex_private *priv, + struct mwifiex_rx_reorder_tbl + *rx_reor_tbl_ptr, int start_win) +{ + int no_pkt_to_send, i, xchg; + void *rx_tmp_ptr = NULL; + unsigned long flags; + + no_pkt_to_send = (start_win > rx_reor_tbl_ptr->start_win) ? + min((start_win - rx_reor_tbl_ptr->start_win), + rx_reor_tbl_ptr->win_size) : rx_reor_tbl_ptr->win_size; + + for (i = 0; i < no_pkt_to_send; ++i) { + spin_lock_irqsave(&priv->rx_pkt_lock, flags); + rx_tmp_ptr = NULL; + if (rx_reor_tbl_ptr->rx_reorder_ptr[i]) { + rx_tmp_ptr = rx_reor_tbl_ptr->rx_reorder_ptr[i]; + rx_reor_tbl_ptr->rx_reorder_ptr[i] = NULL; + } + spin_unlock_irqrestore(&priv->rx_pkt_lock, flags); + if (rx_tmp_ptr) + mwifiex_11n_dispatch_pkt(priv, rx_tmp_ptr); + } + + spin_lock_irqsave(&priv->rx_pkt_lock, flags); + /* + * We don't have a circular buffer, hence use rotation to simulate + * circular buffer + */ + xchg = rx_reor_tbl_ptr->win_size - no_pkt_to_send; + for (i = 0; i < xchg; ++i) { + rx_reor_tbl_ptr->rx_reorder_ptr[i] = + rx_reor_tbl_ptr->rx_reorder_ptr[no_pkt_to_send + i]; + rx_reor_tbl_ptr->rx_reorder_ptr[no_pkt_to_send + i] = NULL; + } + + rx_reor_tbl_ptr->start_win = start_win; + spin_unlock_irqrestore(&priv->rx_pkt_lock, flags); + + return 0; +} + +/* + * This function dispatches all packets in the Rx reorder table until + * a hole is found. + * + * The start window is adjusted automatically when a hole is located. + * Since the buffer is linear, the function uses rotation to simulate + * circular buffer. + */ +static int +mwifiex_11n_scan_and_dispatch(struct mwifiex_private *priv, + struct mwifiex_rx_reorder_tbl *rx_reor_tbl_ptr) +{ + int i, j, xchg; + void *rx_tmp_ptr = NULL; + unsigned long flags; + + for (i = 0; i < rx_reor_tbl_ptr->win_size; ++i) { + spin_lock_irqsave(&priv->rx_pkt_lock, flags); + if (!rx_reor_tbl_ptr->rx_reorder_ptr[i]) { + spin_unlock_irqrestore(&priv->rx_pkt_lock, flags); + break; + } + rx_tmp_ptr = rx_reor_tbl_ptr->rx_reorder_ptr[i]; + rx_reor_tbl_ptr->rx_reorder_ptr[i] = NULL; + spin_unlock_irqrestore(&priv->rx_pkt_lock, flags); + mwifiex_11n_dispatch_pkt(priv, rx_tmp_ptr); + } + + spin_lock_irqsave(&priv->rx_pkt_lock, flags); + /* + * We don't have a circular buffer, hence use rotation to simulate + * circular buffer + */ + if (i > 0) { + xchg = rx_reor_tbl_ptr->win_size - i; + for (j = 0; j < xchg; ++j) { + rx_reor_tbl_ptr->rx_reorder_ptr[j] = + rx_reor_tbl_ptr->rx_reorder_ptr[i + j]; + rx_reor_tbl_ptr->rx_reorder_ptr[i + j] = NULL; + } + } + rx_reor_tbl_ptr->start_win = (rx_reor_tbl_ptr->start_win + i) + &(MAX_TID_VALUE - 1); + spin_unlock_irqrestore(&priv->rx_pkt_lock, flags); + return 0; +} + +/* + * This function deletes the Rx reorder table and frees the memory. + * + * The function stops the associated timer and dispatches all the + * pending packets in the Rx reorder table before deletion. + */ +static void +mwifiex_11n_delete_rx_reorder_tbl_entry(struct mwifiex_private *priv, + struct mwifiex_rx_reorder_tbl + *rx_reor_tbl_ptr) +{ + unsigned long flags; + + if (!rx_reor_tbl_ptr) + return; + + mwifiex_11n_dispatch_pkt_until_start_win(priv, rx_reor_tbl_ptr, + (rx_reor_tbl_ptr->start_win + + rx_reor_tbl_ptr->win_size) + &(MAX_TID_VALUE - 1)); + + del_timer(&rx_reor_tbl_ptr->timer_context.timer); + + spin_lock_irqsave(&priv->rx_reorder_tbl_lock, flags); + list_del(&rx_reor_tbl_ptr->list); + spin_unlock_irqrestore(&priv->rx_reorder_tbl_lock, flags); + + kfree(rx_reor_tbl_ptr->rx_reorder_ptr); + kfree(rx_reor_tbl_ptr); +} + +/* + * This function returns the pointer to an entry in Rx reordering + * table which matches the given TA/TID pair. + */ +static struct mwifiex_rx_reorder_tbl * +mwifiex_11n_get_rx_reorder_tbl(struct mwifiex_private *priv, int tid, u8 *ta) +{ + struct mwifiex_rx_reorder_tbl *rx_reor_tbl_ptr; + unsigned long flags; + + spin_lock_irqsave(&priv->rx_reorder_tbl_lock, flags); + list_for_each_entry(rx_reor_tbl_ptr, &priv->rx_reorder_tbl_ptr, list) { + if ((!memcmp(rx_reor_tbl_ptr->ta, ta, ETH_ALEN)) + && (rx_reor_tbl_ptr->tid == tid)) { + spin_unlock_irqrestore(&priv->rx_reorder_tbl_lock, + flags); + return rx_reor_tbl_ptr; + } + } + spin_unlock_irqrestore(&priv->rx_reorder_tbl_lock, flags); + + return NULL; +} + +/* + * This function finds the last sequence number used in the packets + * buffered in Rx reordering table. + */ +static int +mwifiex_11n_find_last_seq_num(struct mwifiex_rx_reorder_tbl *rx_reorder_tbl_ptr) +{ + int i; + + for (i = (rx_reorder_tbl_ptr->win_size - 1); i >= 0; --i) + if (rx_reorder_tbl_ptr->rx_reorder_ptr[i]) + return i; + + return -1; +} + +/* + * This function flushes all the packets in Rx reordering table. + * + * The function checks if any packets are currently buffered in the + * table or not. In case there are packets available, it dispatches + * them and then dumps the Rx reordering table. + */ +static void +mwifiex_flush_data(unsigned long context) +{ + struct reorder_tmr_cnxt *reorder_cnxt = + (struct reorder_tmr_cnxt *) context; + int start_win; + + start_win = mwifiex_11n_find_last_seq_num(reorder_cnxt->ptr); + if (start_win >= 0) { + dev_dbg(reorder_cnxt->priv->adapter->dev, + "info: flush data %d\n", start_win); + mwifiex_11n_dispatch_pkt_until_start_win(reorder_cnxt->priv, + reorder_cnxt->ptr, + ((reorder_cnxt->ptr->start_win + + start_win + 1) & (MAX_TID_VALUE - 1))); + } +} + +/* + * This function creates an entry in Rx reordering table for the + * given TA/TID. + * + * The function also initializes the entry with sequence number, window + * size as well as initializes the timer. + * + * If the received TA/TID pair is already present, all the packets are + * dispatched and the window size is moved until the SSN. + */ +static void +mwifiex_11n_create_rx_reorder_tbl(struct mwifiex_private *priv, u8 *ta, + int tid, int win_size, int seq_num) +{ + int i; + struct mwifiex_rx_reorder_tbl *rx_reor_tbl_ptr, *new_node; + u16 last_seq = 0; + unsigned long flags; + + /* + * If we get a TID, ta pair which is already present dispatch all the + * the packets and move the window size until the ssn + */ + rx_reor_tbl_ptr = mwifiex_11n_get_rx_reorder_tbl(priv, tid, ta); + if (rx_reor_tbl_ptr) { + mwifiex_11n_dispatch_pkt_until_start_win(priv, rx_reor_tbl_ptr, + seq_num); + return; + } + /* if !rx_reor_tbl_ptr then create one */ + new_node = kzalloc(sizeof(struct mwifiex_rx_reorder_tbl), GFP_KERNEL); + if (!new_node) { + dev_err(priv->adapter->dev, "%s: failed to alloc new_node\n", + __func__); + return; + } + + INIT_LIST_HEAD(&new_node->list); + new_node->tid = tid; + memcpy(new_node->ta, ta, ETH_ALEN); + new_node->start_win = seq_num; + if (mwifiex_queuing_ra_based(priv)) + /* TODO for adhoc */ + dev_dbg(priv->adapter->dev, + "info: ADHOC:last_seq=%d start_win=%d\n", + last_seq, new_node->start_win); + else + last_seq = priv->rx_seq[tid]; + + if (last_seq >= new_node->start_win) + new_node->start_win = last_seq + 1; + + new_node->win_size = win_size; + + new_node->rx_reorder_ptr = kzalloc(sizeof(void *) * win_size, + GFP_KERNEL); + if (!new_node->rx_reorder_ptr) { + kfree((u8 *) new_node); + dev_err(priv->adapter->dev, + "%s: failed to alloc reorder_ptr\n", __func__); + return; + } + + new_node->timer_context.ptr = new_node; + new_node->timer_context.priv = priv; + + init_timer(&new_node->timer_context.timer); + new_node->timer_context.timer.function = mwifiex_flush_data; + new_node->timer_context.timer.data = + (unsigned long) &new_node->timer_context; + + for (i = 0; i < win_size; ++i) + new_node->rx_reorder_ptr[i] = NULL; + + spin_lock_irqsave(&priv->rx_reorder_tbl_lock, flags); + list_add_tail(&new_node->list, &priv->rx_reorder_tbl_ptr); + spin_unlock_irqrestore(&priv->rx_reorder_tbl_lock, flags); + + return; +} + +/* + * This function prepares command for adding a BA request. + * + * Preparation includes - + * - Setting command ID and proper size + * - Setting add BA request buffer + * - Ensuring correct endian-ness + */ +int mwifiex_cmd_11n_addba_req(struct mwifiex_private *priv, + struct host_cmd_ds_command *cmd, void *data_buf) +{ + struct host_cmd_ds_11n_addba_req *add_ba_req = + (struct host_cmd_ds_11n_addba_req *) + &cmd->params.add_ba_req; + + cmd->command = cpu_to_le16(HostCmd_CMD_11N_ADDBA_REQ); + cmd->size = cpu_to_le16(sizeof(*add_ba_req) + S_DS_GEN); + memcpy(add_ba_req, data_buf, sizeof(*add_ba_req)); + + return 0; +} + +/* + * This function prepares command for adding a BA response. + * + * Preparation includes - + * - Setting command ID and proper size + * - Setting add BA response buffer + * - Ensuring correct endian-ness + */ +int mwifiex_cmd_11n_addba_rsp_gen(struct mwifiex_private *priv, + struct host_cmd_ds_command *cmd, + void *data_buf) +{ + struct host_cmd_ds_11n_addba_rsp *add_ba_rsp = + (struct host_cmd_ds_11n_addba_rsp *) + &cmd->params.add_ba_rsp; + struct host_cmd_ds_11n_addba_req *cmd_addba_req = + (struct host_cmd_ds_11n_addba_req *) data_buf; + u8 tid = 0; + int win_size = 0; + uint16_t block_ack_param_set; + + cmd->command = cpu_to_le16(HostCmd_CMD_11N_ADDBA_RSP); + cmd->size = cpu_to_le16(sizeof(*add_ba_rsp) + S_DS_GEN); + + memcpy(add_ba_rsp->peer_mac_addr, cmd_addba_req->peer_mac_addr, + ETH_ALEN); + add_ba_rsp->dialog_token = cmd_addba_req->dialog_token; + add_ba_rsp->block_ack_tmo = cmd_addba_req->block_ack_tmo; + add_ba_rsp->ssn = cmd_addba_req->ssn; + + block_ack_param_set = le16_to_cpu(cmd_addba_req->block_ack_param_set); + tid = (block_ack_param_set & IEEE80211_ADDBA_PARAM_TID_MASK) + >> BLOCKACKPARAM_TID_POS; + add_ba_rsp->status_code = cpu_to_le16(ADDBA_RSP_STATUS_ACCEPT); + block_ack_param_set &= ~IEEE80211_ADDBA_PARAM_BUF_SIZE_MASK; + /* We donot support AMSDU inside AMPDU, hence reset the bit */ + block_ack_param_set &= ~BLOCKACKPARAM_AMSDU_SUPP_MASK; + block_ack_param_set |= (priv->add_ba_param.rx_win_size << + BLOCKACKPARAM_WINSIZE_POS); + add_ba_rsp->block_ack_param_set = cpu_to_le16(block_ack_param_set); + win_size = (le16_to_cpu(add_ba_rsp->block_ack_param_set) + & IEEE80211_ADDBA_PARAM_BUF_SIZE_MASK) + >> BLOCKACKPARAM_WINSIZE_POS; + cmd_addba_req->block_ack_param_set = cpu_to_le16(block_ack_param_set); + + mwifiex_11n_create_rx_reorder_tbl(priv, cmd_addba_req->peer_mac_addr, + tid, win_size, le16_to_cpu(cmd_addba_req->ssn)); + return 0; +} + +/* + * This function prepares command for deleting a BA request. + * + * Preparation includes - + * - Setting command ID and proper size + * - Setting del BA request buffer + * - Ensuring correct endian-ness + */ +int mwifiex_cmd_11n_delba(struct mwifiex_private *priv, + struct host_cmd_ds_command *cmd, void *data_buf) +{ + struct host_cmd_ds_11n_delba *del_ba = (struct host_cmd_ds_11n_delba *) + &cmd->params.del_ba; + + cmd->command = cpu_to_le16(HostCmd_CMD_11N_DELBA); + cmd->size = cpu_to_le16(sizeof(*del_ba) + S_DS_GEN); + memcpy(del_ba, data_buf, sizeof(*del_ba)); + + return 0; +} + +/* + * This function identifies if Rx reordering is needed for a received packet. + * + * In case reordering is required, the function will do the reordering + * before sending it to kernel. + * + * The Rx reorder table is checked first with the received TID/TA pair. If + * not found, the received packet is dispatched immediately. But if found, + * the packet is reordered and all the packets in the updated Rx reordering + * table is dispatched until a hole is found. + * + * For sequence number less than the starting window, the packet is dropped. + */ +int mwifiex_11n_rx_reorder_pkt(struct mwifiex_private *priv, + u16 seq_num, u16 tid, + u8 *ta, u8 pkt_type, void *payload) +{ + struct mwifiex_rx_reorder_tbl *rx_reor_tbl_ptr; + int start_win, end_win, win_size; + int ret = 0; + u16 pkt_index = 0; + + rx_reor_tbl_ptr = + mwifiex_11n_get_rx_reorder_tbl((struct mwifiex_private *) priv, + tid, ta); + if (!rx_reor_tbl_ptr) { + if (pkt_type != PKT_TYPE_BAR) + mwifiex_11n_dispatch_pkt(priv, payload); + return 0; + } + start_win = rx_reor_tbl_ptr->start_win; + win_size = rx_reor_tbl_ptr->win_size; + end_win = ((start_win + win_size) - 1) & (MAX_TID_VALUE - 1); + del_timer(&rx_reor_tbl_ptr->timer_context.timer); + mod_timer(&rx_reor_tbl_ptr->timer_context.timer, jiffies + + (MIN_FLUSH_TIMER_MS * win_size * HZ) / 1000); + + /* + * If seq_num is less then starting win then ignore and drop the + * packet + */ + if ((start_win + TWOPOW11) > (MAX_TID_VALUE - 1)) {/* Wrap */ + if (seq_num >= ((start_win + (TWOPOW11)) & (MAX_TID_VALUE - 1)) + && (seq_num < start_win)) + return -1; + } else if ((seq_num < start_win) + || (seq_num > (start_win + (TWOPOW11)))) { + return -1; + } + + /* + * If this packet is a BAR we adjust seq_num as + * WinStart = seq_num + */ + if (pkt_type == PKT_TYPE_BAR) + seq_num = ((seq_num + win_size) - 1) & (MAX_TID_VALUE - 1); + + if (((end_win < start_win) + && (seq_num < (TWOPOW11 - (MAX_TID_VALUE - start_win))) + && (seq_num > end_win)) || ((end_win > start_win) + && ((seq_num > end_win) || (seq_num < start_win)))) { + end_win = seq_num; + if (((seq_num - win_size) + 1) >= 0) + start_win = (end_win - win_size) + 1; + else + start_win = (MAX_TID_VALUE - (win_size - seq_num)) + 1; + ret = mwifiex_11n_dispatch_pkt_until_start_win(priv, + rx_reor_tbl_ptr, start_win); + + if (ret) + return ret; + } + + if (pkt_type != PKT_TYPE_BAR) { + if (seq_num >= start_win) + pkt_index = seq_num - start_win; + else + pkt_index = (seq_num+MAX_TID_VALUE) - start_win; + + if (rx_reor_tbl_ptr->rx_reorder_ptr[pkt_index]) + return -1; + + rx_reor_tbl_ptr->rx_reorder_ptr[pkt_index] = payload; + } + + /* + * Dispatch all packets sequentially from start_win until a + * hole is found and adjust the start_win appropriately + */ + ret = mwifiex_11n_scan_and_dispatch(priv, rx_reor_tbl_ptr); + + return ret; +} + +/* + * This function deletes an entry for a given TID/TA pair. + * + * The TID/TA are taken from del BA event body. + */ +void +mwifiex_11n_delete_ba_stream_tbl(struct mwifiex_private *priv, int tid, + u8 *peer_mac, u8 type, int initiator) +{ + struct mwifiex_rx_reorder_tbl *rx_reor_tbl_ptr; + struct mwifiex_tx_ba_stream_tbl *ptx_tbl; + u8 cleanup_rx_reorder_tbl; + unsigned long flags; + + if (type == TYPE_DELBA_RECEIVE) + cleanup_rx_reorder_tbl = (initiator) ? true : false; + else + cleanup_rx_reorder_tbl = (initiator) ? false : true; + + dev_dbg(priv->adapter->dev, "event: DELBA: %pM tid=%d, " + "initiator=%d\n", peer_mac, tid, initiator); + + if (cleanup_rx_reorder_tbl) { + rx_reor_tbl_ptr = mwifiex_11n_get_rx_reorder_tbl(priv, tid, + peer_mac); + if (!rx_reor_tbl_ptr) { + dev_dbg(priv->adapter->dev, + "event: TID, TA not found in table\n"); + return; + } + mwifiex_11n_delete_rx_reorder_tbl_entry(priv, rx_reor_tbl_ptr); + } else { + ptx_tbl = mwifiex_11n_get_tx_ba_stream_tbl(priv, tid, peer_mac); + if (!ptx_tbl) { + dev_dbg(priv->adapter->dev, + "event: TID, RA not found in table\n"); + return; + } + + spin_lock_irqsave(&priv->tx_ba_stream_tbl_lock, flags); + mwifiex_11n_delete_tx_ba_stream_tbl_entry(priv, ptx_tbl); + spin_unlock_irqrestore(&priv->tx_ba_stream_tbl_lock, flags); + } +} + +/* + * This function handles the command response of an add BA response. + * + * Handling includes changing the header fields into CPU format and + * creating the stream, provided the add BA is accepted. + */ +int mwifiex_ret_11n_addba_resp(struct mwifiex_private *priv, + struct host_cmd_ds_command *resp) +{ + struct host_cmd_ds_11n_addba_rsp *add_ba_rsp = + (struct host_cmd_ds_11n_addba_rsp *) + &resp->params.add_ba_rsp; + int tid, win_size; + struct mwifiex_rx_reorder_tbl *rx_reor_tbl_ptr = NULL; + uint16_t block_ack_param_set; + + block_ack_param_set = le16_to_cpu(add_ba_rsp->block_ack_param_set); + + tid = (block_ack_param_set & IEEE80211_ADDBA_PARAM_TID_MASK) + >> BLOCKACKPARAM_TID_POS; + /* + * Check if we had rejected the ADDBA, if yes then do not create + * the stream + */ + if (le16_to_cpu(add_ba_rsp->status_code) == BA_RESULT_SUCCESS) { + win_size = (block_ack_param_set & + IEEE80211_ADDBA_PARAM_BUF_SIZE_MASK) + >> BLOCKACKPARAM_WINSIZE_POS; + + dev_dbg(priv->adapter->dev, "cmd: ADDBA RSP: %pM" + " tid=%d ssn=%d win_size=%d\n", + add_ba_rsp->peer_mac_addr, + tid, add_ba_rsp->ssn, win_size); + } else { + dev_err(priv->adapter->dev, "ADDBA RSP: failed %pM tid=%d)\n", + add_ba_rsp->peer_mac_addr, tid); + + rx_reor_tbl_ptr = mwifiex_11n_get_rx_reorder_tbl(priv, + tid, add_ba_rsp->peer_mac_addr); + if (rx_reor_tbl_ptr) + mwifiex_11n_delete_rx_reorder_tbl_entry(priv, + rx_reor_tbl_ptr); + } + + return 0; +} + +/* + * This function handles BA stream timeout event by preparing and sending + * a command to the firmware. + */ +void mwifiex_11n_ba_stream_timeout(struct mwifiex_private *priv, + struct host_cmd_ds_11n_batimeout *event) +{ + struct host_cmd_ds_11n_delba delba; + + memset(&delba, 0, sizeof(struct host_cmd_ds_11n_delba)); + memcpy(delba.peer_mac_addr, event->peer_mac_addr, ETH_ALEN); + + delba.del_ba_param_set |= + cpu_to_le16((u16) event->tid << DELBA_TID_POS); + delba.del_ba_param_set |= cpu_to_le16( + (u16) event->origninator << DELBA_INITIATOR_POS); + delba.reason_code = cpu_to_le16(WLAN_REASON_QSTA_TIMEOUT); + mwifiex_prepare_cmd(priv, HostCmd_CMD_11N_DELBA, 0, 0, NULL, &delba); + + return; +} + +/* + * This function cleans up the Rx reorder table by deleting all the entries + * and re-initializing. + */ +void mwifiex_11n_cleanup_reorder_tbl(struct mwifiex_private *priv) +{ + struct mwifiex_rx_reorder_tbl *del_tbl_ptr, *tmp_node; + unsigned long flags; + + spin_lock_irqsave(&priv->rx_reorder_tbl_lock, flags); + list_for_each_entry_safe(del_tbl_ptr, tmp_node, + &priv->rx_reorder_tbl_ptr, list) { + spin_unlock_irqrestore(&priv->rx_reorder_tbl_lock, flags); + mwifiex_11n_delete_rx_reorder_tbl_entry(priv, del_tbl_ptr); + spin_lock_irqsave(&priv->rx_reorder_tbl_lock, flags); + } + spin_unlock_irqrestore(&priv->rx_reorder_tbl_lock, flags); + + INIT_LIST_HEAD(&priv->rx_reorder_tbl_ptr); + memset(priv->rx_seq, 0, sizeof(priv->rx_seq)); +} diff --git a/drivers/net/wireless/mwifiex/11n_rxreorder.h b/drivers/net/wireless/mwifiex/11n_rxreorder.h new file mode 100644 index 0000000..42f5690 --- /dev/null +++ b/drivers/net/wireless/mwifiex/11n_rxreorder.h @@ -0,0 +1,67 @@ +/* + * Marvell Wireless LAN device driver: 802.11n RX Re-ordering + * + * Copyright (C) 2011, Marvell International Ltd. + * + * This software file (the "File") is distributed by Marvell International + * Ltd. under the terms of the GNU General Public License Version 2, June 1991 + * (the "License"). You may use, redistribute and/or modify this File in + * accordance with the terms and conditions of the License, a copy of which + * is available by writing to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the + * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. + * + * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE + * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE + * ARE EXPRESSLY DISCLAIMED. The License provides additional details about + * this warranty disclaimer. + */ + +#ifndef _MWIFIEX_11N_RXREORDER_H_ +#define _MWIFIEX_11N_RXREORDER_H_ + +#define MIN_FLUSH_TIMER_MS 50 + +#define PKT_TYPE_BAR 0xE7 +#define MAX_TID_VALUE (2 << 11) +#define TWOPOW11 (2 << 10) + +#define BLOCKACKPARAM_TID_POS 2 +#define BLOCKACKPARAM_AMSDU_SUPP_MASK 0x1 +#define BLOCKACKPARAM_WINSIZE_POS 6 +#define DELBA_TID_POS 12 +#define DELBA_INITIATOR_POS 11 +#define TYPE_DELBA_SENT 1 +#define TYPE_DELBA_RECEIVE 2 +#define IMMEDIATE_BLOCK_ACK 0x2 + +#define ADDBA_RSP_STATUS_ACCEPT 0 + +int mwifiex_11n_rx_reorder_pkt(struct mwifiex_private *, + u16 seqNum, + u16 tid, u8 *ta, + u8 pkttype, void *payload); +void mwifiex_11n_delete_ba_stream_tbl(struct mwifiex_private *priv, int Tid, + u8 *PeerMACAddr, u8 type, + int initiator); +void mwifiex_11n_ba_stream_timeout(struct mwifiex_private *priv, + struct host_cmd_ds_11n_batimeout *event); +int mwifiex_ret_11n_addba_resp(struct mwifiex_private *priv, + struct host_cmd_ds_command + *resp); +int mwifiex_cmd_11n_delba(struct mwifiex_private *priv, + struct host_cmd_ds_command *cmd, + void *data_buf); +int mwifiex_cmd_11n_addba_rsp_gen(struct mwifiex_private *priv, + struct host_cmd_ds_command + *cmd, void *data_buf); +int mwifiex_cmd_11n_addba_req(struct mwifiex_private *priv, + struct host_cmd_ds_command *cmd, + void *data_buf); +void mwifiex_11n_cleanup_reorder_tbl(struct mwifiex_private *priv); +struct mwifiex_rx_reorder_tbl *mwifiex_11n_get_rxreorder_tbl(struct + mwifiex_private + *priv, int tid, + u8 *ta); + +#endif /* _MWIFIEX_11N_RXREORDER_H_ */ diff --git a/drivers/net/wireless/mwifiex/Kconfig b/drivers/net/wireless/mwifiex/Kconfig new file mode 100644 index 0000000..8696292 --- /dev/null +++ b/drivers/net/wireless/mwifiex/Kconfig @@ -0,0 +1,21 @@ +config MWIFIEX + tristate "Marvell WiFi-Ex Driver" + depends on CFG80211 + select LIB80211 + ---help--- + This adds support for wireless adapters based on Marvell + 802.11n chipsets. + + If you choose to build it as a module, it will be called + mwifiex. + +config MWIFIEX_SDIO + tristate "Marvell WiFi-Ex Driver for SD8787" + depends on MWIFIEX && MMC + select FW_LOADER + ---help--- + This adds support for wireless adapters based on Marvell + 8787 chipset with SDIO interface. + + If you choose to build it as a module, it will be called + mwifiex_sdio. diff --git a/drivers/net/wireless/mwifiex/Makefile b/drivers/net/wireless/mwifiex/Makefile new file mode 100644 index 0000000..42cb733 --- /dev/null +++ b/drivers/net/wireless/mwifiex/Makefile @@ -0,0 +1,41 @@ +# +# Copyright (C) 2011, Marvell International Ltd. +# +# This software file (the "File") is distributed by Marvell International +# Ltd. under the terms of the GNU General Public License Version 2, June 1991 +# (the "License"). You may use, redistribute and/or modify this File in +# accordance with the terms and conditions of the License, a copy of which +# is available by writing to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the +# worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. +# +# THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE +# IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE +# ARE EXPRESSLY DISCLAIMED. The License provides additional details about +# this warranty disclaimer. + + +mwifiex-y += main.o +mwifiex-y += init.o +mwifiex-y += cfp.o +mwifiex-y += cmdevt.o +mwifiex-y += util.o +mwifiex-y += txrx.o +mwifiex-y += wmm.o +mwifiex-y += 11n.o +mwifiex-y += 11n_aggr.o +mwifiex-y += 11n_rxreorder.o +mwifiex-y += scan.o +mwifiex-y += join.o +mwifiex-y += sta_ioctl.o +mwifiex-y += sta_cmd.o +mwifiex-y += sta_cmdresp.o +mwifiex-y += sta_event.o +mwifiex-y += sta_tx.o +mwifiex-y += sta_rx.o +mwifiex-y += cfg80211.o +mwifiex-$(CONFIG_DEBUG_FS) += debugfs.o +obj-$(CONFIG_MWIFIEX) += mwifiex.o + +mwifiex_sdio-y += sdio.o +obj-$(CONFIG_MWIFIEX_SDIO) += mwifiex_sdio.o diff --git a/drivers/net/wireless/mwifiex/README b/drivers/net/wireless/mwifiex/README new file mode 100644 index 0000000..338377f --- /dev/null +++ b/drivers/net/wireless/mwifiex/README @@ -0,0 +1,204 @@ +# Copyright (C) 2011, Marvell International Ltd. +# +# This software file (the "File") is distributed by Marvell International +# Ltd. under the terms of the GNU General Public License Version 2, June 1991 +# (the "License"). You may use, redistribute and/or modify this File in +# accordance with the terms and conditions of the License, a copy of which +# is available by writing to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the +# worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. +# +# THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE +# IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE +# ARE EXPRESSLY DISCLAIMED. The License provides additional details about +# this warranty disclaimer. + + +=============================================================================== + U S E R M A N U A L + +1) FOR DRIVER INSTALL + + a) Copy sd8787.bin to /lib/firmware/mrvl/ directory, + create the directory if it doesn't exist. + b) Install WLAN driver, + insmod mwifiex.ko + c) Uninstall WLAN driver, + ifconfig mlanX down + rmmod mwifiex + + +2) FOR DRIVER CONFIGURATION AND INFO + The configurations can be done either using the 'iw' user space + utility or debugfs. + + a) 'iw' utility commands + + Following are some useful iw commands:- + +iw dev mlan0 scan + + This command will trigger a scan. + The command will then display the scan table entries + +iw dev mlan0 connect -w [] [] [key 0:abcde d:1123456789a] + The above command can be used to connect to an AP with a particular SSID. + Ap's operating frequency can be specified or even the bssid. If the AP is using + WEP encryption, wep keys can be specified in the command. + Note: Every time before connecting to an AP scan command (iw dev mlan0 scan) should be used by user. + +iw dev mlan0 disconnect + This command will be used to disconnect from an AP. + + +iw dev mlan0 ibss join [fixed-freq] [fixed-bssid] [key 0:abcde] + The command will be used to join or create an ibss. Optionally, operating frequency, + bssid and the security related parameters can be specified while joining/creating + and ibss. + +iw dev mlan0 ibss leave + The command will be used to leave an ibss network. + +iw dev mlan0 link + The command will be used to get the connection status. The command will return parameters + such as SSID, operating frequency, rx/tx packets, signal strength, tx bitrate. + + Apart from the iw utility all standard configurations using the 'iwconfig' utility are also supported. + + b) Debugfs interface + + The debugfs interface can be used for configurations and for getting + some useful information from the driver. + The section below explains the configurations that can be + done. + + Mount debugfs to /debugfs mount point: + + mkdir /debugfs + mount -t debugfs debugfs /debugfs + + The information is provided in /debugfs/mwifiex/mlanX/: + +iw reg set + The command will be used to change the regulatory domain. + +iw reg get + The command will be used to get current regulatory domain. + +info + This command is used to get driver info. + + Usage: + cat info + + driver_name = "mwifiex" + driver_version = + interface_name = "mlanX" + bss_mode = "Ad-hoc" | "Managed" | "Auto" | "Unknown" + media_state = "Disconnected" | "Connected" + mac_address = <6-byte adapter MAC address> + multicase_count = + essid = + bssid = + channel = + region_code = + multicasr_address[n] = + num_tx_bytes = + num_rx_bytes = + num_tx_pkts = + num_rx_pkts = + num_tx_pkts_dropped = + num_rx_pkts_dropped = + num_tx_pkts_err = + num_rx_pkts_err = + carrier "on" | "off" + tx queue "stopped" | "started" + + The following debug info are provided in /debugfs/mwifiex/mlanX/debug: + + int_counter = + wmm_ac_vo = + wmm_ac_vi = + wmm_ac_be = + wmm_ac_bk = + max_tx_buf_size = + tx_buf_size = + curr_tx_buf_size = + ps_mode = <0/1, CAM mode/PS mode> + ps_state = <0/1/2/3, full power state/awake state/pre-sleep state/sleep state> + is_deep_sleep = <0/1, not deep sleep state/deep sleep state> + wakeup_dev_req = <0/1, wakeup device not required/required> + wakeup_tries = + hs_configured = <0/1, host sleep not configured/configured> + hs_activated = <0/1, extended host sleep not activated/activated> + num_tx_timeout = + num_cmd_timeout = + timeout_cmd_id = + timeout_cmd_act = + last_cmd_id = + last_cmd_act = + last_cmd_index = <0 based last command index> + last_cmd_resp_id = + last_cmd_resp_index = <0 based last command response index> + last_event = + last_event_index = <0 based last event index> + num_cmd_h2c_fail = + num_cmd_sleep_cfm_fail = + num_tx_h2c_fail = + num_evt_deauth = + num_evt_disassoc = + num_evt_link_lost = + num_cmd_deauth = + num_cmd_assoc_ok = + num_cmd_assoc_fail = + cmd_sent = <0/1, send command resources available/sending command to device> + data_sent = <0/1, send data resources available/sending data to device> + mp_rd_bitmap = + mp_wr_bitmap = + cmd_resp_received = <0/1, no cmd response to process/response received and yet to process> + event_received = <0/1, no event to process/event received and yet to process> + ioctl_pending = + tx_pending = + rx_pending = + + +3) FOR DRIVER CONFIGURATION + +regrdwr + This command is used to read/write the adapter register. + + Usage: + echo " [value]" > regrdwr + cat regrdwr + + where the parameters are, + : 1:MAC/SOC, 2:BBP, 3:RF, 4:PMIC, 5:CAU + : offset of register + [value]: value to be written + + Examples: + echo "1 0xa060" > regrdwr : Read the MAC register + echo "1 0xa060 0x12" > regrdwr : Write the MAC register + echo "1 0xa794 0x80000000" > regrdwr + : Write 0x80000000 to MAC register +rdeeprom + This command is used to read the EEPROM contents of the card. + + Usage: + echo " " > rdeeprom + cat rdeeprom + + where the parameters are, + : multiples of 4 + : 4-20, multiples of 4 + + Example: + echo "0 20" > rdeeprom : Read 20 bytes of EEPROM data from offset 0 + +getlog + This command is used to get the statistics available in the station. + Usage: + + cat getlog + +=============================================================================== diff --git a/drivers/net/wireless/mwifiex/cfg80211.c b/drivers/net/wireless/mwifiex/cfg80211.c new file mode 100644 index 0000000..80f367f --- /dev/null +++ b/drivers/net/wireless/mwifiex/cfg80211.c @@ -0,0 +1,1517 @@ +/* + * Marvell Wireless LAN device driver: CFG80211 + * + * Copyright (C) 2011, Marvell International Ltd. + * + * This software file (the "File") is distributed by Marvell International + * Ltd. under the terms of the GNU General Public License Version 2, June 1991 + * (the "License"). You may use, redistribute and/or modify this File in + * accordance with the terms and conditions of the License, a copy of which + * is available by writing to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the + * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. + * + * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE + * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE + * ARE EXPRESSLY DISCLAIMED. The License provides additional details about + * this warranty disclaimer. + */ + +#include "cfg80211.h" +#include "main.h" + +/* + * This function maps the nl802.11 channel type into driver channel type. + * + * The mapping is as follows - + * NL80211_CHAN_NO_HT -> NO_SEC_CHANNEL + * NL80211_CHAN_HT20 -> NO_SEC_CHANNEL + * NL80211_CHAN_HT40PLUS -> SEC_CHANNEL_ABOVE + * NL80211_CHAN_HT40MINUS -> SEC_CHANNEL_BELOW + * Others -> NO_SEC_CHANNEL + */ +static int +mwifiex_cfg80211_channel_type_to_mwifiex_channels(enum nl80211_channel_type + channel_type) +{ + int channel; + switch (channel_type) { + case NL80211_CHAN_NO_HT: + case NL80211_CHAN_HT20: + channel = NO_SEC_CHANNEL; + break; + case NL80211_CHAN_HT40PLUS: + channel = SEC_CHANNEL_ABOVE; + break; + case NL80211_CHAN_HT40MINUS: + channel = SEC_CHANNEL_BELOW; + break; + default: + channel = NO_SEC_CHANNEL; + } + return channel; +} + +/* + * This function maps the driver channel type into nl802.11 channel type. + * + * The mapping is as follows - + * NO_SEC_CHANNEL -> NL80211_CHAN_HT20 + * SEC_CHANNEL_ABOVE -> NL80211_CHAN_HT40PLUS + * SEC_CHANNEL_BELOW -> NL80211_CHAN_HT40MINUS + * Others -> NL80211_CHAN_HT20 + */ +static enum nl80211_channel_type +mwifiex_channels_to_cfg80211_channel_type(int channel_type) +{ + int channel; + switch (channel_type) { + case NO_SEC_CHANNEL: + channel = NL80211_CHAN_HT20; + break; + case SEC_CHANNEL_ABOVE: + channel = NL80211_CHAN_HT40PLUS; + break; + case SEC_CHANNEL_BELOW: + channel = NL80211_CHAN_HT40MINUS; + break; + default: + channel = NL80211_CHAN_HT20; + } + return channel; +} + +/* + * This function checks whether WEP is set. + */ +static int +mwifiex_is_alg_wep(u32 cipher) +{ + int alg = 0; + + switch (cipher) { + case MWIFIEX_ENCRYPTION_MODE_WEP40: + case MWIFIEX_ENCRYPTION_MODE_WEP104: + alg = 1; + break; + default: + alg = 0; + break; + } + return alg; +} + +/* + * This function maps the given cipher type into driver specific type. + * + * It also sets a flag to indicate whether WPA is enabled or not. + * + * The mapping table is - + * Input cipher Driver cipher type WPA enabled? + * ------------ ------------------ ------------ + * IW_AUTH_CIPHER_NONE MWIFIEX_ENCRYPTION_MODE_NONE No + * WLAN_CIPHER_SUITE_WEP40 MWIFIEX_ENCRYPTION_MODE_WEP40 No + * WLAN_CIPHER_SUITE_WEP104 MWIFIEX_ENCRYPTION_MODE_WEP104 No + * WLAN_CIPHER_SUITE_TKIP MWIFIEX_ENCRYPTION_MODE_TKIP Yes + * WLAN_CIPHER_SUITE_CCMP MWIFIEX_ENCRYPTION_MODE_CCMP Yes + * Others -1 No + */ +static int +mwifiex_get_mwifiex_cipher(u32 cipher, int *wpa_enabled) +{ + int encrypt_mode; + + if (wpa_enabled) + *wpa_enabled = 0; + switch (cipher) { + case IW_AUTH_CIPHER_NONE: + encrypt_mode = MWIFIEX_ENCRYPTION_MODE_NONE; + break; + case WLAN_CIPHER_SUITE_WEP40: + encrypt_mode = MWIFIEX_ENCRYPTION_MODE_WEP40; + break; + case WLAN_CIPHER_SUITE_WEP104: + encrypt_mode = MWIFIEX_ENCRYPTION_MODE_WEP104; + break; + case WLAN_CIPHER_SUITE_TKIP: + encrypt_mode = MWIFIEX_ENCRYPTION_MODE_TKIP; + if (wpa_enabled) + *wpa_enabled = 1; + break; + case WLAN_CIPHER_SUITE_CCMP: + encrypt_mode = MWIFIEX_ENCRYPTION_MODE_CCMP; + if (wpa_enabled) + *wpa_enabled = 1; + break; + default: + encrypt_mode = -1; + } + + return encrypt_mode; +} + +/* + * This function retrieves the private structure from kernel wiphy structure. + */ +static void *mwifiex_cfg80211_get_priv(struct wiphy *wiphy) +{ + return (void *) (*(unsigned long *) wiphy_priv(wiphy)); +} + +/* + * CFG802.11 operation handler to delete a network key. + */ +static int +mwifiex_cfg80211_del_key(struct wiphy *wiphy, struct net_device *netdev, + u8 key_index, bool pairwise, const u8 *mac_addr) +{ + struct mwifiex_private *priv = mwifiex_cfg80211_get_priv(wiphy); + int ret = 0; + + ret = mwifiex_set_encode(priv, NULL, 0, key_index, 1); + if (ret) { + wiphy_err(wiphy, "deleting the crypto keys\n"); + return -EFAULT; + } + + wiphy_dbg(wiphy, "info: crypto keys deleted\n"); + return 0; +} + +/* + * CFG802.11 operation handler to set Tx power. + */ +static int +mwifiex_cfg80211_set_tx_power(struct wiphy *wiphy, + enum nl80211_tx_power_setting type, + int dbm) +{ + int ret = 0; + struct mwifiex_private *priv = mwifiex_cfg80211_get_priv(wiphy); + + ret = mwifiex_set_tx_power(priv, type, dbm); + + return ret; +} + +/* + * CFG802.11 operation handler to set Power Save option. + * + * The timeout value, if provided, is currently ignored. + */ +static int +mwifiex_cfg80211_set_power_mgmt(struct wiphy *wiphy, + struct net_device *dev, + bool enabled, int timeout) +{ + int ret = 0; + struct mwifiex_private *priv = mwifiex_cfg80211_get_priv(wiphy); + + if (timeout) + wiphy_dbg(wiphy, + "info: ignoring the timeout value" + " for IEEE power save\n"); + + ret = mwifiex_drv_set_power(priv, enabled); + + return ret; +} + +/* + * CFG802.11 operation handler to set the default network key. + */ +static int +mwifiex_cfg80211_set_default_key(struct wiphy *wiphy, struct net_device *netdev, + u8 key_index, bool unicast, + bool multicast) +{ + struct mwifiex_private *priv = mwifiex_cfg80211_get_priv(wiphy); + int ret; + + ret = mwifiex_set_encode(priv, NULL, 0, key_index, 0); + + wiphy_dbg(wiphy, "info: set default Tx key index\n"); + + if (ret) + return -EFAULT; + + return 0; +} + +/* + * CFG802.11 operation handler to add a network key. + */ +static int +mwifiex_cfg80211_add_key(struct wiphy *wiphy, struct net_device *netdev, + u8 key_index, bool pairwise, const u8 *mac_addr, + struct key_params *params) +{ + struct mwifiex_private *priv = mwifiex_cfg80211_get_priv(wiphy); + int ret = 0; + int encrypt_mode; + + encrypt_mode = mwifiex_get_mwifiex_cipher(params->cipher, NULL); + + if (encrypt_mode != -1) + ret = mwifiex_set_encode(priv, params->key, params->key_len, + key_index, 0); + + wiphy_dbg(wiphy, "info: crypto keys added\n"); + + if (ret) + return -EFAULT; + + return 0; +} + +/* + * This function sends domain information to the firmware. + * + * The following information are passed to the firmware - + * - Country codes + * - Sub bands (first channel, number of channels, maximum Tx power) + */ +static int mwifiex_send_domain_info_cmd_fw(struct wiphy *wiphy) +{ + u8 no_of_triplet = 0; + struct ieee80211_country_ie_triplet *t; + u8 no_of_parsed_chan = 0; + u8 first_chan = 0, next_chan = 0, max_pwr = 0; + u8 i, flag = 0; + enum ieee80211_band band; + struct ieee80211_supported_band *sband; + struct ieee80211_channel *ch; + struct mwifiex_private *priv = mwifiex_cfg80211_get_priv(wiphy); + struct mwifiex_adapter *adapter = priv->adapter; + struct mwifiex_802_11d_domain_reg *domain_info = &adapter->domain_reg; + int ret = 0; + + /* Set country code */ + domain_info->country_code[0] = priv->country_code[0]; + domain_info->country_code[1] = priv->country_code[1]; + domain_info->country_code[2] = ' '; + + band = mwifiex_band_to_radio_type(adapter->config_bands); + if (!wiphy->bands[band]) { + wiphy_err(wiphy, "11D: setting domain info in FW\n"); + return -1; + } + + sband = wiphy->bands[band]; + + for (i = 0; i < sband->n_channels ; i++) { + ch = &sband->channels[i]; + if (ch->flags & IEEE80211_CHAN_DISABLED) + continue; + + if (!flag) { + flag = 1; + first_chan = (u32) ch->hw_value; + next_chan = first_chan; + max_pwr = ch->max_power; + no_of_parsed_chan = 1; + continue; + } + + if (ch->hw_value == next_chan + 1 && + ch->max_power == max_pwr) { + next_chan++; + no_of_parsed_chan++; + } else { + t = &domain_info->triplet[no_of_triplet]; + t->chans.first_channel = first_chan; + t->chans.num_channels = no_of_parsed_chan; + t->chans.max_power = max_pwr; + no_of_triplet++; + first_chan = (u32) ch->hw_value; + next_chan = first_chan; + max_pwr = ch->max_power; + no_of_parsed_chan = 1; + } + } + + if (flag) { + t = &domain_info->triplet[no_of_triplet]; + t->chans.first_channel = first_chan; + t->chans.num_channels = no_of_parsed_chan; + t->chans.max_power = max_pwr; + no_of_triplet++; + } + + domain_info->no_of_triplet = no_of_triplet; + /* Send cmd to FW to set domain info */ + ret = mwifiex_prepare_cmd(priv, HostCmd_CMD_802_11D_DOMAIN_INFO, + HostCmd_ACT_GEN_SET, 0, NULL, NULL); + if (ret) + wiphy_err(wiphy, "11D: setting domain info in FW\n"); + + return ret; +} + +/* + * CFG802.11 regulatory domain callback function. + * + * This function is called when the regulatory domain is changed due to the + * following reasons - + * - Set by driver + * - Set by system core + * - Set by user + * - Set bt Country IE + */ +static int mwifiex_reg_notifier(struct wiphy *wiphy, + struct regulatory_request *request) +{ + struct mwifiex_private *priv = mwifiex_cfg80211_get_priv(wiphy); + + wiphy_dbg(wiphy, "info: cfg80211 regulatory domain callback for domain" + " %c%c\n", request->alpha2[0], request->alpha2[1]); + + memcpy(priv->country_code, request->alpha2, sizeof(request->alpha2)); + + switch (request->initiator) { + case NL80211_REGDOM_SET_BY_DRIVER: + case NL80211_REGDOM_SET_BY_CORE: + case NL80211_REGDOM_SET_BY_USER: + break; + /* Todo: apply driver specific changes in channel flags based + on the request initiator if necessary. */ + case NL80211_REGDOM_SET_BY_COUNTRY_IE: + break; + } + mwifiex_send_domain_info_cmd_fw(wiphy); + + return 0; +} + +/* + * This function sets the RF channel. + * + * This function creates multiple IOCTL requests, populates them accordingly + * and issues them to set the band/channel and frequency. + */ +static int +mwifiex_set_rf_channel(struct mwifiex_private *priv, + struct ieee80211_channel *chan, + enum nl80211_channel_type channel_type) +{ + struct mwifiex_chan_freq_power cfp; + int ret = 0; + int status = 0; + struct mwifiex_ds_band_cfg band_cfg; + int mode; + u8 wait_option = MWIFIEX_IOCTL_WAIT; + u32 config_bands = 0; + struct wiphy *wiphy = priv->wdev->wiphy; + + mode = mwifiex_drv_get_mode(priv, wait_option); + + if (chan) { + memset(&band_cfg, 0, sizeof(band_cfg)); + /* Set appropriate bands */ + if (chan->band == IEEE80211_BAND_2GHZ) + config_bands = BAND_B | BAND_G | BAND_GN; + else + config_bands = BAND_AN | BAND_A; + if (mode == MWIFIEX_BSS_MODE_INFRA + || mode == MWIFIEX_BSS_MODE_AUTO) { + band_cfg.config_bands = config_bands; + } else if (mode == MWIFIEX_BSS_MODE_IBSS) { + band_cfg.config_bands = config_bands; + band_cfg.adhoc_start_band = config_bands; + } + /* Set channel offset */ + band_cfg.sec_chan_offset = + mwifiex_cfg80211_channel_type_to_mwifiex_channels + (channel_type); + status = mwifiex_radio_ioctl_band_cfg(priv, HostCmd_ACT_GEN_SET, + &band_cfg); + + if (status) + return -EFAULT; + mwifiex_send_domain_info_cmd_fw(wiphy); + } + + wiphy_dbg(wiphy, "info: setting band %d, channel offset %d and " + "mode %d\n", config_bands, band_cfg.sec_chan_offset, mode); + if (!chan) + return ret; + + memset(&cfp, 0, sizeof(cfp)); + cfp.freq = chan->center_freq; + /* Convert frequency to channel */ + cfp.channel = ieee80211_frequency_to_channel(chan->center_freq); + + status = mwifiex_bss_ioctl_channel(priv, HostCmd_ACT_GEN_SET, &cfp); + if (status) + return -EFAULT; + + ret = mwifiex_drv_change_adhoc_chan(priv, cfp.channel); + + return ret; +} + +/* + * CFG802.11 operation handler to set channel. + * + * This function can only be used when station is not connected. + */ +static int +mwifiex_cfg80211_set_channel(struct wiphy *wiphy, struct net_device *dev, + struct ieee80211_channel *chan, + enum nl80211_channel_type channel_type) +{ + struct mwifiex_private *priv = mwifiex_cfg80211_get_priv(wiphy); + + if (priv->media_connected) { + wiphy_err(wiphy, "This setting is valid only when station " + "is not connected\n"); + return -EINVAL; + } + + return mwifiex_set_rf_channel(priv, chan, channel_type); +} + +/* + * This function sets the fragmentation threshold. + * + * This function creates an IOCTL request, populates it accordingly + * and issues an IOCTL. + * + * The fragmentation threshold value must lies between MWIFIEX_FRAG_MIN_VALUE + * and MWIFIEX_FRAG_MAX_VALUE. + */ +static int +mwifiex_set_frag(struct mwifiex_private *priv, u32 frag_thr) +{ + int ret = 0; + int status = 0; + struct mwifiex_wait_queue *wait = NULL; + u8 wait_option = MWIFIEX_IOCTL_WAIT; + + if (frag_thr < MWIFIEX_FRAG_MIN_VALUE + || frag_thr > MWIFIEX_FRAG_MAX_VALUE) + return -EINVAL; + + wait = mwifiex_alloc_fill_wait_queue(priv, wait_option); + if (!wait) + return -ENOMEM; + + status = mwifiex_snmp_mib_ioctl(priv, wait, FRAG_THRESH_I, + HostCmd_ACT_GEN_SET, &frag_thr); + + if (mwifiex_request_ioctl(priv, wait, status, wait_option)) + ret = -EFAULT; + + kfree(wait); + return ret; +} + +/* + * This function sets the RTS threshold. + * + * This function creates an IOCTL request, populates it accordingly + * and issues an IOCTL. + */ +static int +mwifiex_set_rts(struct mwifiex_private *priv, u32 rts_thr) +{ + int ret = 0; + struct mwifiex_wait_queue *wait = NULL; + int status = 0; + u8 wait_option = MWIFIEX_IOCTL_WAIT; + + if (rts_thr < MWIFIEX_RTS_MIN_VALUE || rts_thr > MWIFIEX_RTS_MAX_VALUE) + rts_thr = MWIFIEX_RTS_MAX_VALUE; + + wait = mwifiex_alloc_fill_wait_queue(priv, wait_option); + if (!wait) + return -ENOMEM; + + status = mwifiex_snmp_mib_ioctl(priv, wait, RTS_THRESH_I, + HostCmd_ACT_GEN_SET, &rts_thr); + + if (mwifiex_request_ioctl(priv, wait, status, wait_option)) + ret = -EFAULT; + + kfree(wait); + return ret; +} + +/* + * CFG802.11 operation handler to set wiphy parameters. + * + * This function can be used to set the RTS threshold and the + * Fragmentation threshold of the driver. + */ +static int +mwifiex_cfg80211_set_wiphy_params(struct wiphy *wiphy, u32 changed) +{ + struct mwifiex_private *priv = mwifiex_cfg80211_get_priv(wiphy); + + int ret = 0; + + if (changed & WIPHY_PARAM_RTS_THRESHOLD) + ret = mwifiex_set_rts(priv, wiphy->rts_threshold); + + if (changed & WIPHY_PARAM_FRAG_THRESHOLD) + ret = mwifiex_set_frag(priv, wiphy->frag_threshold); + + return ret; +} + +/* + * CFG802.11 operation handler to change interface type. + * + * This function creates an IOCTL request, populates it accordingly + * and issues an IOCTL. + * + * The function also maps the CFG802.11 mode type into driver mode type. + * NL80211_IFTYPE_ADHOC -> MWIFIEX_BSS_MODE_IBSS + * NL80211_IFTYPE_STATION -> MWIFIEX_BSS_MODE_INFRA + * NL80211_IFTYPE_UNSPECIFIED -> MWIFIEX_BSS_MODE_AUTO + */ +static int +mwifiex_cfg80211_change_virtual_intf(struct wiphy *wiphy, + struct net_device *dev, + enum nl80211_iftype type, u32 *flags, + struct vif_params *params) +{ + int ret = 0; + struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev); + int mode = -1; + struct mwifiex_wait_queue *wait = NULL; + int status = 0; + + wait = mwifiex_alloc_fill_wait_queue(priv, MWIFIEX_IOCTL_WAIT); + if (!wait) + return -ENOMEM; + + switch (type) { + case NL80211_IFTYPE_ADHOC: + mode = MWIFIEX_BSS_MODE_IBSS; + dev->ieee80211_ptr->iftype = NL80211_IFTYPE_ADHOC; + wiphy_dbg(wiphy, "info: setting interface type to adhoc\n"); + break; + case NL80211_IFTYPE_STATION: + mode = MWIFIEX_BSS_MODE_INFRA; + dev->ieee80211_ptr->iftype = NL80211_IFTYPE_STATION; + wiphy_dbg(wiphy, "info: Setting interface type to managed\n"); + break; + case NL80211_IFTYPE_UNSPECIFIED: + mode = MWIFIEX_BSS_MODE_AUTO; + dev->ieee80211_ptr->iftype = NL80211_IFTYPE_STATION; + wiphy_dbg(wiphy, "info: setting interface type to auto\n"); + break; + default: + ret = -EINVAL; + } + if (ret) + goto done; + status = mwifiex_bss_ioctl_mode(priv, wait, HostCmd_ACT_GEN_SET, &mode); + + if (mwifiex_request_ioctl(priv, wait, status, MWIFIEX_IOCTL_WAIT)) + ret = -EFAULT; + +done: + kfree(wait); + return ret; +} + +/* + * This function dumps the station information on a buffer. + * + * The following information are shown - + * - Total bytes transmitted + * - Total bytes received + * - Total packets transmitted + * - Total packets received + * - Signal quality level + * - Transmission rate + */ +static int +mwifiex_dump_station_info(struct mwifiex_private *priv, + struct station_info *sinfo) +{ + struct mwifiex_ds_get_signal signal; + struct mwifiex_rate_cfg rate; + int ret = 0; + + sinfo->filled = STATION_INFO_RX_BYTES | STATION_INFO_TX_BYTES | + STATION_INFO_RX_PACKETS | + STATION_INFO_TX_PACKETS + | STATION_INFO_SIGNAL | STATION_INFO_TX_BITRATE; + + /* Get signal information from the firmware */ + memset(&signal, 0, sizeof(struct mwifiex_ds_get_signal)); + if (mwifiex_get_signal_info(priv, MWIFIEX_IOCTL_WAIT, &signal)) { + dev_err(priv->adapter->dev, "getting signal information\n"); + ret = -EFAULT; + } + + if (mwifiex_drv_get_data_rate(priv, &rate)) { + dev_err(priv->adapter->dev, "getting data rate\n"); + ret = -EFAULT; + } + + sinfo->rx_bytes = priv->stats.rx_bytes; + sinfo->tx_bytes = priv->stats.tx_bytes; + sinfo->rx_packets = priv->stats.rx_packets; + sinfo->tx_packets = priv->stats.tx_packets; + sinfo->signal = priv->w_stats.qual.level; + sinfo->txrate.legacy = rate.rate; + + return ret; +} + +/* + * CFG802.11 operation handler to get station information. + * + * This function only works in connected mode, and dumps the + * requested station information, if available. + */ +static int +mwifiex_cfg80211_get_station(struct wiphy *wiphy, struct net_device *dev, + u8 *mac, struct station_info *sinfo) +{ + struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev); + int ret = 0; + + mwifiex_dump_station_info(priv, sinfo); + + if (!priv->media_connected) + return -ENOENT; + if (memcmp(mac, priv->cfg_bssid, ETH_ALEN)) + return -ENOENT; + + + ret = mwifiex_dump_station_info(priv, sinfo); + + return ret; +} + +/* Supported rates to be advertised to the cfg80211 */ + +static struct ieee80211_rate mwifiex_rates[] = { + {.bitrate = 10, .hw_value = 2, }, + {.bitrate = 20, .hw_value = 4, }, + {.bitrate = 55, .hw_value = 11, }, + {.bitrate = 110, .hw_value = 22, }, + {.bitrate = 220, .hw_value = 44, }, + {.bitrate = 60, .hw_value = 12, }, + {.bitrate = 90, .hw_value = 18, }, + {.bitrate = 120, .hw_value = 24, }, + {.bitrate = 180, .hw_value = 36, }, + {.bitrate = 240, .hw_value = 48, }, + {.bitrate = 360, .hw_value = 72, }, + {.bitrate = 480, .hw_value = 96, }, + {.bitrate = 540, .hw_value = 108, }, + {.bitrate = 720, .hw_value = 144, }, +}; + +/* Channel definitions to be advertised to cfg80211 */ + +static struct ieee80211_channel mwifiex_channels_2ghz[] = { + {.center_freq = 2412, .hw_value = 1, }, + {.center_freq = 2417, .hw_value = 2, }, + {.center_freq = 2422, .hw_value = 3, }, + {.center_freq = 2427, .hw_value = 4, }, + {.center_freq = 2432, .hw_value = 5, }, + {.center_freq = 2437, .hw_value = 6, }, + {.center_freq = 2442, .hw_value = 7, }, + {.center_freq = 2447, .hw_value = 8, }, + {.center_freq = 2452, .hw_value = 9, }, + {.center_freq = 2457, .hw_value = 10, }, + {.center_freq = 2462, .hw_value = 11, }, + {.center_freq = 2467, .hw_value = 12, }, + {.center_freq = 2472, .hw_value = 13, }, + {.center_freq = 2484, .hw_value = 14, }, +}; + +static struct ieee80211_supported_band mwifiex_band_2ghz = { + .channels = mwifiex_channels_2ghz, + .n_channels = ARRAY_SIZE(mwifiex_channels_2ghz), + .bitrates = mwifiex_rates, + .n_bitrates = 14, +}; + +static struct ieee80211_channel mwifiex_channels_5ghz[] = { + {.center_freq = 5040, .hw_value = 8, }, + {.center_freq = 5060, .hw_value = 12, }, + {.center_freq = 5080, .hw_value = 16, }, + {.center_freq = 5170, .hw_value = 34, }, + {.center_freq = 5190, .hw_value = 38, }, + {.center_freq = 5210, .hw_value = 42, }, + {.center_freq = 5230, .hw_value = 46, }, + {.center_freq = 5180, .hw_value = 36, }, + {.center_freq = 5200, .hw_value = 40, }, + {.center_freq = 5220, .hw_value = 44, }, + {.center_freq = 5240, .hw_value = 48, }, + {.center_freq = 5260, .hw_value = 52, }, + {.center_freq = 5280, .hw_value = 56, }, + {.center_freq = 5300, .hw_value = 60, }, + {.center_freq = 5320, .hw_value = 64, }, + {.center_freq = 5500, .hw_value = 100, }, + {.center_freq = 5520, .hw_value = 104, }, + {.center_freq = 5540, .hw_value = 108, }, + {.center_freq = 5560, .hw_value = 112, }, + {.center_freq = 5580, .hw_value = 116, }, + {.center_freq = 5600, .hw_value = 120, }, + {.center_freq = 5620, .hw_value = 124, }, + {.center_freq = 5640, .hw_value = 128, }, + {.center_freq = 5660, .hw_value = 132, }, + {.center_freq = 5680, .hw_value = 136, }, + {.center_freq = 5700, .hw_value = 140, }, + {.center_freq = 5745, .hw_value = 149, }, + {.center_freq = 5765, .hw_value = 153, }, + {.center_freq = 5785, .hw_value = 157, }, + {.center_freq = 5805, .hw_value = 161, }, + {.center_freq = 5825, .hw_value = 165, }, +}; + +static struct ieee80211_supported_band mwifiex_band_5ghz = { + .channels = mwifiex_channels_5ghz, + .n_channels = ARRAY_SIZE(mwifiex_channels_5ghz), + .bitrates = mwifiex_rates - 4, + .n_bitrates = ARRAY_SIZE(mwifiex_rates) + 4, +}; + + +/* Supported crypto cipher suits to be advertised to cfg80211 */ + +static const u32 mwifiex_cipher_suites[] = { + WLAN_CIPHER_SUITE_WEP40, + WLAN_CIPHER_SUITE_WEP104, + WLAN_CIPHER_SUITE_TKIP, + WLAN_CIPHER_SUITE_CCMP, +}; + +/* + * CFG802.11 operation handler for disconnection request. + * + * This function does not work when there is already a disconnection + * procedure going on. + */ +static int +mwifiex_cfg80211_disconnect(struct wiphy *wiphy, struct net_device *dev, + u16 reason_code) +{ + struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev); + + if (priv->disconnect) + return -EBUSY; + + priv->disconnect = 1; + if (mwifiex_disconnect(priv, MWIFIEX_IOCTL_WAIT, NULL)) + return -EFAULT; + + wiphy_dbg(wiphy, "info: successfully disconnected from %pM:" + " reason code %d\n", priv->cfg_bssid, reason_code); + + queue_work(priv->workqueue, &priv->cfg_workqueue); + + return 0; +} + +/* + * This function informs the CFG802.11 subsystem of a new IBSS. + * + * The following information are sent to the CFG802.11 subsystem + * to register the new IBSS. If we do not register the new IBSS, + * a kernel panic will result. + * - SSID + * - SSID length + * - BSSID + * - Channel + */ +static int mwifiex_cfg80211_inform_ibss_bss(struct mwifiex_private *priv) +{ + int ret = 0; + struct ieee80211_channel *chan; + struct mwifiex_bss_info bss_info; + int ie_len = 0; + u8 ie_buf[IEEE80211_MAX_SSID_LEN + sizeof(struct ieee_types_header)]; + + ret = mwifiex_get_bss_info(priv, &bss_info); + if (ret) + return ret; + + ie_buf[0] = WLAN_EID_SSID; + ie_buf[1] = bss_info.ssid.ssid_len; + + memcpy(&ie_buf[sizeof(struct ieee_types_header)], + &bss_info.ssid.ssid, + bss_info.ssid.ssid_len); + ie_len = ie_buf[1] + sizeof(struct ieee_types_header); + + chan = __ieee80211_get_channel(priv->wdev->wiphy, + ieee80211_channel_to_frequency(bss_info.bss_chan, + priv->curr_bss_params.band)); + + cfg80211_inform_bss(priv->wdev->wiphy, chan, + bss_info.bssid, 0, WLAN_CAPABILITY_IBSS, + 0, ie_buf, ie_len, 0, GFP_KERNEL); + memcpy(priv->cfg_bssid, bss_info.bssid, ETH_ALEN); + + return ret; +} + +/* + * This function informs the CFG802.11 subsystem of a new BSS connection. + * + * The following information are sent to the CFG802.11 subsystem + * to register the new BSS connection. If we do not register the new BSS, + * a kernel panic will result. + * - MAC address + * - Capabilities + * - Beacon period + * - RSSI value + * - Channel + * - Supported rates IE + * - Extended capabilities IE + * - DS parameter set IE + * - HT Capability IE + * - Vendor Specific IE (221) + * - WPA IE + * - RSN IE + */ +static int mwifiex_inform_bss_from_scan_result(struct mwifiex_private *priv, + struct mwifiex_802_11_ssid *ssid) +{ + struct mwifiex_scan_resp scan_resp; + struct mwifiex_bssdescriptor *scan_table; + int i, j; + struct ieee80211_channel *chan; + u8 *ie, *tmp, *ie_buf; + u32 ie_len; + u64 ts = 0; + u8 *beacon; + int beacon_size; + u8 element_id, element_len; + + memset(&scan_resp, 0, sizeof(scan_resp)); + if (mwifiex_get_scan_table(priv, MWIFIEX_IOCTL_WAIT, &scan_resp)) + return -EFAULT; + +#define MAX_IE_BUF 2048 + ie_buf = kzalloc(MAX_IE_BUF, GFP_KERNEL); + if (!ie_buf) { + dev_err(priv->adapter->dev, "%s: failed to alloc ie_buf\n", + __func__); + return -ENOMEM; + } + + scan_table = (struct mwifiex_bssdescriptor *) scan_resp.scan_table; + for (i = 0; i < scan_resp.num_in_scan_table; i++) { + if (ssid) { + /* Inform specific BSS only */ + if (memcmp(ssid->ssid, scan_table[i].ssid.ssid, + ssid->ssid_len)) + continue; + } + memset(ie_buf, 0, MAX_IE_BUF); + ie_buf[0] = WLAN_EID_SSID; + ie_buf[1] = scan_table[i].ssid.ssid_len; + memcpy(&ie_buf[sizeof(struct ieee_types_header)], + scan_table[i].ssid.ssid, ie_buf[1]); + + ie = ie_buf + ie_buf[1] + sizeof(struct ieee_types_header); + ie_len = ie_buf[1] + sizeof(struct ieee_types_header); + + ie[0] = WLAN_EID_SUPP_RATES; + + for (j = 0; j < sizeof(scan_table[i].supported_rates); j++) { + if (!scan_table[i].supported_rates[j]) + break; + else + ie[j + sizeof(struct ieee_types_header)] = + scan_table[i].supported_rates[j]; + } + + ie[1] = j; + ie_len += ie[1] + sizeof(struct ieee_types_header); + + beacon = scan_table[i].beacon_buf; + beacon_size = scan_table[i].beacon_buf_size; + + /* Skip time stamp, beacon interval and capability */ + + if (beacon) { + beacon += sizeof(scan_table[i].beacon_period) + + sizeof(scan_table[i].time_stamp) + + +sizeof(scan_table[i].cap_info_bitmap); + + beacon_size -= sizeof(scan_table[i].beacon_period) + + sizeof(scan_table[i].time_stamp) + + sizeof(scan_table[i].cap_info_bitmap); + } + + while (beacon_size >= sizeof(struct ieee_types_header)) { + ie = ie_buf + ie_len; + element_id = *beacon; + element_len = *(beacon + 1); + if (beacon_size < (int) element_len + + sizeof(struct ieee_types_header)) { + dev_err(priv->adapter->dev, "%s: in processing" + " IE, bytes left < IE length\n", + __func__); + break; + } + switch (element_id) { + case WLAN_EID_EXT_CAPABILITY: + case WLAN_EID_DS_PARAMS: + case WLAN_EID_HT_CAPABILITY: + case WLAN_EID_VENDOR_SPECIFIC: + case WLAN_EID_RSN: + case WLAN_EID_BSS_AC_ACCESS_DELAY: + ie[0] = element_id; + ie[1] = element_len; + tmp = (u8 *) beacon; + memcpy(&ie[sizeof(struct ieee_types_header)], + tmp + sizeof(struct ieee_types_header), + element_len); + ie_len += ie[1] + + sizeof(struct ieee_types_header); + break; + default: + break; + } + beacon += element_len + + sizeof(struct ieee_types_header); + beacon_size -= element_len + + sizeof(struct ieee_types_header); + } + chan = ieee80211_get_channel(priv->wdev->wiphy, + scan_table[i].freq); + cfg80211_inform_bss(priv->wdev->wiphy, chan, + scan_table[i].mac_address, + ts, scan_table[i].cap_info_bitmap, + scan_table[i].beacon_period, + ie_buf, ie_len, + scan_table[i].rssi, GFP_KERNEL); + } + + kfree(ie_buf); + return 0; +} + +/* + * This function connects with a BSS. + * + * This function handles both Infra and Ad-Hoc modes. It also performs + * validity checking on the provided parameters, disconnects from the + * current BSS (if any), sets up the association/scan parameters, + * including security settings, and performs specific SSID scan before + * trying to connect. + * + * For Infra mode, the function returns failure if the specified SSID + * is not found in scan table. However, for Ad-Hoc mode, it can create + * the IBSS if it does not exist. On successful completion in either case, + * the function notifies the CFG802.11 subsystem of the new BSS connection, + * otherwise the kernel will panic. + */ +static int +mwifiex_cfg80211_assoc(struct mwifiex_private *priv, size_t ssid_len, u8 *ssid, + u8 *bssid, int mode, struct ieee80211_channel *channel, + struct cfg80211_connect_params *sme, bool privacy) +{ + struct mwifiex_802_11_ssid req_ssid; + struct mwifiex_ssid_bssid ssid_bssid; + int ret = 0; + int auth_type = 0, pairwise_encrypt_mode = 0, wpa_enabled = 0; + int group_encrypt_mode = 0; + int alg_is_wep = 0; + + memset(&req_ssid, 0, sizeof(struct mwifiex_802_11_ssid)); + memset(&ssid_bssid, 0, sizeof(struct mwifiex_ssid_bssid)); + + req_ssid.ssid_len = ssid_len; + if (ssid_len > IEEE80211_MAX_SSID_LEN) { + dev_err(priv->adapter->dev, "invalid SSID - aborting\n"); + return -EINVAL; + } + + memcpy(req_ssid.ssid, ssid, ssid_len); + if (!req_ssid.ssid_len || req_ssid.ssid[0] < 0x20) { + dev_err(priv->adapter->dev, "invalid SSID - aborting\n"); + return -EINVAL; + } + + /* disconnect before try to associate */ + mwifiex_disconnect(priv, MWIFIEX_IOCTL_WAIT, NULL); + + if (channel) + ret = mwifiex_set_rf_channel(priv, channel, + mwifiex_channels_to_cfg80211_channel_type + (priv->adapter->chan_offset)); + + ret = mwifiex_set_encode(priv, NULL, 0, 0, 1); /* Disable keys */ + + if (mode == MWIFIEX_BSS_MODE_IBSS) { + /* "privacy" is set only for ad-hoc mode */ + if (privacy) { + /* + * Keep MWIFIEX_ENCRYPTION_MODE_WEP104 for now so that + * the firmware can find a matching network from the + * scan. The cfg80211 does not give us the encryption + * mode at this stage so just setting it to WEP here. + */ + wpa_enabled = 0; + auth_type = MWIFIEX_AUTH_MODE_OPEN; + ret = mwifiex_set_auth(priv, + MWIFIEX_ENCRYPTION_MODE_WEP104, + auth_type, wpa_enabled); + } + + goto done; + } + + /* Now handle infra mode. "sme" is valid for infra mode only */ + if (sme->auth_type == NL80211_AUTHTYPE_AUTOMATIC + || sme->auth_type == NL80211_AUTHTYPE_OPEN_SYSTEM) + auth_type = MWIFIEX_AUTH_MODE_OPEN; + else if (sme->auth_type == NL80211_AUTHTYPE_SHARED_KEY) + auth_type = MWIFIEX_AUTH_MODE_SHARED; + + if (sme->crypto.n_ciphers_pairwise) { + pairwise_encrypt_mode = mwifiex_get_mwifiex_cipher(sme->crypto. + ciphers_pairwise[0], &wpa_enabled); + ret = mwifiex_set_auth(priv, pairwise_encrypt_mode, auth_type, + wpa_enabled); + } + + if (sme->crypto.cipher_group) { + group_encrypt_mode = mwifiex_get_mwifiex_cipher(sme->crypto. + cipher_group, &wpa_enabled); + ret = mwifiex_set_auth(priv, group_encrypt_mode, auth_type, + wpa_enabled); + } + if (sme->ie) + ret = mwifiex_set_gen_ie(priv, sme->ie, sme->ie_len); + + if (sme->key) { + alg_is_wep = mwifiex_is_alg_wep(pairwise_encrypt_mode) + | mwifiex_is_alg_wep(group_encrypt_mode); + if (alg_is_wep) { + dev_dbg(priv->adapter->dev, + "info: setting wep encryption" + " with key len %d\n", sme->key_len); + ret = mwifiex_set_encode(priv, sme->key, sme->key_len, + sme->key_idx, 0); + } + } +done: + /* Do specific SSID scanning */ + if (mwifiex_request_scan(priv, MWIFIEX_IOCTL_WAIT, &req_ssid)) { + dev_err(priv->adapter->dev, "scan error\n"); + return -EFAULT; + } + + + memcpy(&ssid_bssid.ssid, &req_ssid, sizeof(struct mwifiex_802_11_ssid)); + + if (mode != MWIFIEX_BSS_MODE_IBSS) { + if (mwifiex_find_best_bss(priv, MWIFIEX_IOCTL_WAIT, + &ssid_bssid)) + return -EFAULT; + /* Inform the BSS information to kernel, otherwise + * kernel will give a panic after successful assoc */ + if (mwifiex_inform_bss_from_scan_result(priv, &req_ssid)) + return -EFAULT; + } + + dev_dbg(priv->adapter->dev, "info: trying to associate to %s and bssid %pM\n", + (char *) req_ssid.ssid, ssid_bssid.bssid); + + memcpy(&priv->cfg_bssid, ssid_bssid.bssid, 6); + + /* Connect to BSS by ESSID */ + memset(&ssid_bssid.bssid, 0, ETH_ALEN); + + if (mwifiex_bss_start(priv, MWIFIEX_IOCTL_WAIT, &ssid_bssid)) + return -EFAULT; + + if (mode == MWIFIEX_BSS_MODE_IBSS) { + /* Inform the BSS information to kernel, otherwise + * kernel will give a panic after successful assoc */ + if (mwifiex_cfg80211_inform_ibss_bss(priv)) + return -EFAULT; + } + + return ret; +} + +/* + * CFG802.11 operation handler for association request. + * + * This function does not work when the current mode is set to Ad-Hoc, or + * when there is already an association procedure going on. The given BSS + * information is used to associate. + */ +static int +mwifiex_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev, + struct cfg80211_connect_params *sme) +{ + struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev); + int ret = 0; + int mode = 0; + + if (priv->assoc_request) + return -EBUSY; + + mode = mwifiex_drv_get_mode(priv, MWIFIEX_IOCTL_WAIT); + + if (mode == MWIFIEX_BSS_MODE_IBSS) { + wiphy_err(wiphy, "received infra assoc request " + "when station is in ibss mode\n"); + goto done; + } + + priv->assoc_request = 1; + + wiphy_dbg(wiphy, "info: Trying to associate to %s and bssid %pM\n", + (char *) sme->ssid, sme->bssid); + + ret = mwifiex_cfg80211_assoc(priv, sme->ssid_len, sme->ssid, sme->bssid, + mode, sme->channel, sme, 0); + +done: + priv->assoc_result = ret; + queue_work(priv->workqueue, &priv->cfg_workqueue); + return ret; +} + +/* + * CFG802.11 operation handler to join an IBSS. + * + * This function does not work in any mode other than Ad-Hoc, or if + * a join operation is already in progress. + */ +static int +mwifiex_cfg80211_join_ibss(struct wiphy *wiphy, struct net_device *dev, + struct cfg80211_ibss_params *params) +{ + struct mwifiex_private *priv = mwifiex_cfg80211_get_priv(wiphy); + int ret = 0; + int mode = 0; + + if (priv->ibss_join_request) + return -EBUSY; + + mode = mwifiex_drv_get_mode(priv, MWIFIEX_IOCTL_WAIT); + if (mode != MWIFIEX_BSS_MODE_IBSS) { + wiphy_err(wiphy, "request to join ibss received " + "when station is not in ibss mode\n"); + goto done; + } + + priv->ibss_join_request = 1; + + wiphy_dbg(wiphy, "info: trying to join to %s and bssid %pM\n", + (char *) params->ssid, params->bssid); + + ret = mwifiex_cfg80211_assoc(priv, params->ssid_len, params->ssid, + params->bssid, mode, params->channel, NULL, + params->privacy); +done: + priv->ibss_join_result = ret; + queue_work(priv->workqueue, &priv->cfg_workqueue); + return ret; +} + +/* + * CFG802.11 operation handler to leave an IBSS. + * + * This function does not work if a leave operation is + * already in progress. + */ +static int +mwifiex_cfg80211_leave_ibss(struct wiphy *wiphy, struct net_device *dev) +{ + struct mwifiex_private *priv = mwifiex_cfg80211_get_priv(wiphy); + + if (priv->disconnect) + return -EBUSY; + + priv->disconnect = 1; + + wiphy_dbg(wiphy, "info: disconnecting from essid %pM\n", + priv->cfg_bssid); + if (mwifiex_disconnect(priv, MWIFIEX_IOCTL_WAIT, NULL)) + return -EFAULT; + + queue_work(priv->workqueue, &priv->cfg_workqueue); + + return 0; +} + +/* + * CFG802.11 operation handler for scan request. + * + * This function issues a scan request to the firmware based upon + * the user specified scan configuration. On successfull completion, + * it also informs the results. + */ +static int +mwifiex_cfg80211_scan(struct wiphy *wiphy, struct net_device *dev, + struct cfg80211_scan_request *request) +{ + struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev); + + wiphy_dbg(wiphy, "info: received scan request on %s\n", dev->name); + + if (priv->scan_request && priv->scan_request != request) + return -EBUSY; + + priv->scan_request = request; + + queue_work(priv->workqueue, &priv->cfg_workqueue); + return 0; +} + +/* + * This function sets up the CFG802.11 specific HT capability fields + * with default values. + * + * The following default values are set - + * - HT Supported = True + * - Maximum AMPDU length factor = 0x3 + * - Minimum AMPDU spacing = 0x6 + * - HT Capabilities map = IEEE80211_HT_CAP_SUP_WIDTH_20_40 (0x0002) + * - MCS information, Rx mask = 0xff + * - MCD information, Tx parameters = IEEE80211_HT_MCS_TX_DEFINED (0x01) + */ +static void +mwifiex_setup_ht_caps(struct ieee80211_sta_ht_cap *ht_info, + struct mwifiex_private *priv) +{ + int rx_mcs_supp; + struct ieee80211_mcs_info mcs_set; + u8 *mcs = (u8 *)&mcs_set; + struct mwifiex_adapter *adapter = priv->adapter; + + ht_info->ht_supported = true; + ht_info->ampdu_factor = 0x3; + ht_info->ampdu_density = 0x6; + + memset(&ht_info->mcs, 0, sizeof(ht_info->mcs)); + ht_info->cap = IEEE80211_HT_CAP_SUP_WIDTH_20_40; + + rx_mcs_supp = GET_RXMCSSUPP(priv->adapter->hw_dev_mcs_support); + /* Set MCS for 1x1 */ + memset(mcs, 0xff, rx_mcs_supp); + /* Clear all the other values */ + memset(&mcs[rx_mcs_supp], 0, + sizeof(struct ieee80211_mcs_info) - rx_mcs_supp); + if (priv->bss_mode == MWIFIEX_BSS_MODE_INFRA || + (ISSUPP_CHANWIDTH40(adapter->hw_dot_11n_dev_cap) && + ISSUPP_CHANWIDTH40(adapter->usr_dot_11n_dev_cap))) + /* Set MCS32 for infra mode or ad-hoc mode with 40MHz support */ + SETHT_MCS32(mcs_set.rx_mask); + + memcpy((u8 *) &ht_info->mcs, mcs, sizeof(struct ieee80211_mcs_info)); + + ht_info->mcs.tx_params = IEEE80211_HT_MCS_TX_DEFINED; +} + +/* station cfg80211 operations */ +static struct cfg80211_ops mwifiex_cfg80211_ops = { + .change_virtual_intf = mwifiex_cfg80211_change_virtual_intf, + .scan = mwifiex_cfg80211_scan, + .connect = mwifiex_cfg80211_connect, + .disconnect = mwifiex_cfg80211_disconnect, + .get_station = mwifiex_cfg80211_get_station, + .set_wiphy_params = mwifiex_cfg80211_set_wiphy_params, + .set_channel = mwifiex_cfg80211_set_channel, + .join_ibss = mwifiex_cfg80211_join_ibss, + .leave_ibss = mwifiex_cfg80211_leave_ibss, + .add_key = mwifiex_cfg80211_add_key, + .del_key = mwifiex_cfg80211_del_key, + .set_default_key = mwifiex_cfg80211_set_default_key, + .set_power_mgmt = mwifiex_cfg80211_set_power_mgmt, + .set_tx_power = mwifiex_cfg80211_set_tx_power, +}; + +/* + * This function registers the device with CFG802.11 subsystem. + * + * The function creates the wireless device/wiphy, populates it with + * default parameters and handler function pointers, and finally + * registers the device. + */ +int mwifiex_register_cfg80211(struct net_device *dev, u8 *mac, + struct mwifiex_private *priv) +{ + int ret = 0; + void *wdev_priv = NULL; + struct wireless_dev *wdev; + + wdev = kzalloc(sizeof(struct wireless_dev), GFP_KERNEL); + if (!wdev) { + dev_err(priv->adapter->dev, "%s: allocating wireless device\n", + __func__); + return -ENOMEM; + } + wdev->wiphy = + wiphy_new(&mwifiex_cfg80211_ops, + sizeof(struct mwifiex_private *)); + if (!wdev->wiphy) + return -ENOMEM; + wdev->iftype = NL80211_IFTYPE_STATION; + wdev->wiphy->max_scan_ssids = 10; + wdev->wiphy->interface_modes = + BIT(NL80211_IFTYPE_STATION) | BIT(NL80211_IFTYPE_ADHOC); + wdev->wiphy->bands[IEEE80211_BAND_2GHZ] = &mwifiex_band_2ghz; + wdev->wiphy->bands[IEEE80211_BAND_5GHZ] = &mwifiex_band_5ghz; + + /* Initialize cipher suits */ + wdev->wiphy->cipher_suites = mwifiex_cipher_suites; + wdev->wiphy->n_cipher_suites = ARRAY_SIZE(mwifiex_cipher_suites); + + /* Initialize parameters for 2GHz band */ + + mwifiex_setup_ht_caps(&wdev->wiphy->bands[IEEE80211_BAND_2GHZ]->ht_cap, + priv); + mwifiex_setup_ht_caps(&wdev->wiphy->bands[IEEE80211_BAND_5GHZ]->ht_cap, + priv); + + memcpy(wdev->wiphy->perm_addr, mac, 6); + wdev->wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM; + + /* We are using custom domains */ + wdev->wiphy->flags |= WIPHY_FLAG_CUSTOM_REGULATORY; + + wdev->wiphy->reg_notifier = mwifiex_reg_notifier; + + /* Set struct mwifiex_private pointer in wiphy_priv */ + wdev_priv = wiphy_priv(wdev->wiphy); + + *(unsigned long *) wdev_priv = (unsigned long) priv; + + ret = wiphy_register(wdev->wiphy); + if (ret < 0) { + dev_err(priv->adapter->dev, "%s: registering cfg80211 device\n", + __func__); + wiphy_free(wdev->wiphy); + return ret; + } else { + dev_dbg(priv->adapter->dev, + "info: successfully registered wiphy device\n"); + } + + dev_net_set(dev, wiphy_net(wdev->wiphy)); + dev->ieee80211_ptr = wdev; + memcpy(dev->dev_addr, wdev->wiphy->perm_addr, 6); + memcpy(dev->perm_addr, wdev->wiphy->perm_addr, 6); + SET_NETDEV_DEV(dev, wiphy_dev(wdev->wiphy)); + priv->wdev = wdev; + + dev->flags |= IFF_BROADCAST | IFF_MULTICAST; + dev->watchdog_timeo = MWIFIEX_DEFAULT_WATCHDOG_TIMEOUT; + dev->hard_header_len += MWIFIEX_MIN_DATA_HEADER_LEN; + + return ret; +} + +/* + * This function handles the result of different pending network operations. + * + * The following operations are handled and CFG802.11 subsystem is + * notified accordingly - + * - Scan request completion + * - Association request completion + * - IBSS join request completion + * - Disconnect request completion + */ +void +mwifiex_cfg80211_results(struct work_struct *work) +{ + struct mwifiex_private *priv = + container_of(work, struct mwifiex_private, cfg_workqueue); + struct mwifiex_user_scan_cfg *scan_req; + int ret = 0, i; + struct ieee80211_channel *chan; + + if (priv->scan_request) { + scan_req = kzalloc(sizeof(struct mwifiex_user_scan_cfg), + GFP_KERNEL); + if (!scan_req) { + dev_err(priv->adapter->dev, "failed to alloc " + "scan_req\n"); + return; + } + for (i = 0; i < priv->scan_request->n_ssids; i++) { + memcpy(scan_req->ssid_list[i].ssid, + priv->scan_request->ssids[i].ssid, + priv->scan_request->ssids[i].ssid_len); + scan_req->ssid_list[i].max_len = + priv->scan_request->ssids[i].ssid_len; + } + for (i = 0; i < priv->scan_request->n_channels; i++) { + chan = priv->scan_request->channels[i]; + scan_req->chan_list[i].chan_number = chan->hw_value; + scan_req->chan_list[i].radio_type = chan->band; + if (chan->flags & IEEE80211_CHAN_DISABLED) + scan_req->chan_list[i].scan_type = + MWIFIEX_SCAN_TYPE_PASSIVE; + else + scan_req->chan_list[i].scan_type = + MWIFIEX_SCAN_TYPE_ACTIVE; + scan_req->chan_list[i].scan_time = 0; + } + if (mwifiex_set_user_scan_ioctl(priv, scan_req)) { + ret = -EFAULT; + goto done; + } + if (mwifiex_inform_bss_from_scan_result(priv, NULL)) + ret = -EFAULT; +done: + priv->scan_result_status = ret; + dev_dbg(priv->adapter->dev, "info: %s: sending scan results\n", + __func__); + cfg80211_scan_done(priv->scan_request, + (priv->scan_result_status < 0)); + priv->scan_request = NULL; + kfree(scan_req); + } + + if (priv->assoc_request) { + if (!priv->assoc_result) { + cfg80211_connect_result(priv->netdev, priv->cfg_bssid, + NULL, 0, NULL, 0, + WLAN_STATUS_SUCCESS, + GFP_KERNEL); + dev_dbg(priv->adapter->dev, + "info: associated to bssid %pM successfully\n", + priv->cfg_bssid); + } else { + dev_dbg(priv->adapter->dev, + "info: association to bssid %pM failed\n", + priv->cfg_bssid); + memset(priv->cfg_bssid, 0, ETH_ALEN); + } + priv->assoc_request = 0; + priv->assoc_result = 0; + } + + if (priv->ibss_join_request) { + if (!priv->ibss_join_result) { + cfg80211_ibss_joined(priv->netdev, priv->cfg_bssid, + GFP_KERNEL); + dev_dbg(priv->adapter->dev, + "info: joined/created adhoc network with bssid" + " %pM successfully\n", priv->cfg_bssid); + } else { + dev_dbg(priv->adapter->dev, + "info: failed creating/joining adhoc network\n"); + } + priv->ibss_join_request = 0; + priv->ibss_join_result = 0; + } + + if (priv->disconnect) { + memset(priv->cfg_bssid, 0, ETH_ALEN); + priv->disconnect = 0; + } + + return; +} diff --git a/drivers/net/wireless/mwifiex/cfg80211.h b/drivers/net/wireless/mwifiex/cfg80211.h new file mode 100644 index 0000000..c4db8f3 --- /dev/null +++ b/drivers/net/wireless/mwifiex/cfg80211.h @@ -0,0 +1,31 @@ +/* + * Marvell Wireless LAN device driver: CFG80211 + * + * Copyright (C) 2011, Marvell International Ltd. + * + * This software file (the "File") is distributed by Marvell International + * Ltd. under the terms of the GNU General Public License Version 2, June 1991 + * (the "License"). You may use, redistribute and/or modify this File in + * accordance with the terms and conditions of the License, a copy of which + * is available by writing to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the + * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. + * + * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE + * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE + * ARE EXPRESSLY DISCLAIMED. The License provides additional details about + * this warranty disclaimer. + */ + +#ifndef __MWIFIEX_CFG80211__ +#define __MWIFIEX_CFG80211__ + +#include + +#include "main.h" + +int mwifiex_register_cfg80211(struct net_device *, u8 *, + struct mwifiex_private *); + +void mwifiex_cfg80211_results(struct work_struct *work); +#endif diff --git a/drivers/net/wireless/mwifiex/cfp.c b/drivers/net/wireless/mwifiex/cfp.c new file mode 100644 index 0000000..999ed81 --- /dev/null +++ b/drivers/net/wireless/mwifiex/cfp.c @@ -0,0 +1,368 @@ +/* + * Marvell Wireless LAN device driver: Channel, Frequence and Power + * + * Copyright (C) 2011, Marvell International Ltd. + * + * This software file (the "File") is distributed by Marvell International + * Ltd. under the terms of the GNU General Public License Version 2, June 1991 + * (the "License"). You may use, redistribute and/or modify this File in + * accordance with the terms and conditions of the License, a copy of which + * is available by writing to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the + * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. + * + * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE + * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE + * ARE EXPRESSLY DISCLAIMED. The License provides additional details about + * this warranty disclaimer. + */ + +#include "decl.h" +#include "ioctl.h" +#include "util.h" +#include "fw.h" +#include "main.h" +#include "cfg80211.h" + +/* 100mW */ +#define MWIFIEX_TX_PWR_DEFAULT 20 +/* 100mW */ +#define MWIFIEX_TX_PWR_US_DEFAULT 20 +/* 50mW */ +#define MWIFIEX_TX_PWR_JP_DEFAULT 16 +/* 100mW */ +#define MWIFIEX_TX_PWR_FR_100MW 20 +/* 10mW */ +#define MWIFIEX_TX_PWR_FR_10MW 10 +/* 100mW */ +#define MWIFIEX_TX_PWR_EMEA_DEFAULT 20 + +static u8 adhoc_rates_b[B_SUPPORTED_RATES] = { 0x82, 0x84, 0x8b, 0x96, 0 }; + +static u8 adhoc_rates_g[G_SUPPORTED_RATES] = { 0x8c, 0x12, 0x98, 0x24, + 0xb0, 0x48, 0x60, 0x6c, 0 }; + +static u8 adhoc_rates_bg[BG_SUPPORTED_RATES] = { 0x82, 0x84, 0x8b, 0x96, + 0x0c, 0x12, 0x18, 0x24, + 0x30, 0x48, 0x60, 0x6c, 0 }; + +static u8 adhoc_rates_a[A_SUPPORTED_RATES] = { 0x8c, 0x12, 0x98, 0x24, + 0xb0, 0x48, 0x60, 0x6c, 0 }; +u8 supported_rates_a[A_SUPPORTED_RATES] = { 0x0c, 0x12, 0x18, 0x24, + 0xb0, 0x48, 0x60, 0x6c, 0 }; +static u16 mwifiex_data_rates[MWIFIEX_SUPPORTED_RATES_EXT] = { 0x02, 0x04, + 0x0B, 0x16, 0x00, 0x0C, 0x12, 0x18, + 0x24, 0x30, 0x48, 0x60, 0x6C, 0x90, + 0x0D, 0x1A, 0x27, 0x34, 0x4E, 0x68, + 0x75, 0x82, 0x0C, 0x1B, 0x36, 0x51, + 0x6C, 0xA2, 0xD8, 0xF3, 0x10E, 0x00 }; + +u8 supported_rates_b[B_SUPPORTED_RATES] = { 0x02, 0x04, 0x0b, 0x16, 0 }; + +u8 supported_rates_g[G_SUPPORTED_RATES] = { 0x0c, 0x12, 0x18, 0x24, + 0x30, 0x48, 0x60, 0x6c, 0 }; + +u8 supported_rates_bg[BG_SUPPORTED_RATES] = { 0x02, 0x04, 0x0b, 0x0c, + 0x12, 0x16, 0x18, 0x24, 0x30, 0x48, + 0x60, 0x6c, 0 }; + +u16 region_code_index[MWIFIEX_MAX_REGION_CODE] = { 0x10, 0x20, 0x30, + 0x32, 0x40, 0x41, 0xff }; + +u8 supported_rates_n[N_SUPPORTED_RATES] = { 0x02, 0x04, 0 }; + +/* + * This function maps an index in supported rates table into + * the corresponding data rate. + */ +u32 mwifiex_index_to_data_rate(struct mwifiex_adapter *adapter, u8 index, + u8 ht_info) +{ + u16 mcs_rate[4][8] = { + {0x1b, 0x36, 0x51, 0x6c, 0xa2, 0xd8, 0xf3, 0x10e} + , /* LG 40M */ + {0x1e, 0x3c, 0x5a, 0x78, 0xb4, 0xf0, 0x10e, 0x12c} + , /* SG 40M */ + {0x0d, 0x1a, 0x27, 0x34, 0x4e, 0x68, 0x75, 0x82} + , /* LG 20M */ + {0x0e, 0x1c, 0x2b, 0x39, 0x56, 0x73, 0x82, 0x90} + }; /* SG 20M */ + + u32 rate; + + if (ht_info & BIT(0)) { + if (index == MWIFIEX_RATE_BITMAP_MCS0) { + if (ht_info & BIT(2)) + rate = 0x0D; /* MCS 32 SGI rate */ + else + rate = 0x0C; /* MCS 32 LGI rate */ + } else if (index < 8) { + if (ht_info & BIT(1)) { + if (ht_info & BIT(2)) + /* SGI, 40M */ + rate = mcs_rate[1][index]; + else + /* LGI, 40M */ + rate = mcs_rate[0][index]; + } else { + if (ht_info & BIT(2)) + /* SGI, 20M */ + rate = mcs_rate[3][index]; + else + /* LGI, 20M */ + rate = mcs_rate[2][index]; + } + } else + rate = mwifiex_data_rates[0]; + } else { + if (index >= MWIFIEX_SUPPORTED_RATES_EXT) + index = 0; + rate = mwifiex_data_rates[index]; + } + return rate; +} + +/* + * This function maps a data rate value into corresponding index in supported + * rates table. + */ +u8 mwifiex_data_rate_to_index(struct mwifiex_adapter *adapter, u32 rate) +{ + u16 *ptr; + + if (rate) { + ptr = memchr(mwifiex_data_rates, rate, + sizeof(mwifiex_data_rates)); + if (ptr) + return (u8) (ptr - mwifiex_data_rates); + } + return 0; +} + +/* + * This function returns the current active data rates. + * + * The result may vary depending upon connection status. + */ +u32 mwifiex_get_active_data_rates(struct mwifiex_private *priv, u8 *rates) +{ + u32 k; + + if (!priv->media_connected) + k = mwifiex_get_supported_rates(priv, rates); + else + k = mwifiex_copy_rates(rates, 0, + priv->curr_bss_params.data_rates, + priv->curr_bss_params.num_of_rates); + + return k; +} + +/* + * This function locates the Channel-Frequency-Power triplet based upon + * band and channel parameters. + */ +struct mwifiex_chan_freq_power * +mwifiex_get_cfp_by_band_and_channel_from_cfg80211(struct mwifiex_private + *priv, u8 band, u16 channel) +{ + struct mwifiex_chan_freq_power *cfp = NULL; + struct ieee80211_supported_band *sband; + struct ieee80211_channel *ch; + int i; + + if (mwifiex_band_to_radio_type(band) == HostCmd_SCAN_RADIO_TYPE_BG) + sband = priv->wdev->wiphy->bands[IEEE80211_BAND_2GHZ]; + else + sband = priv->wdev->wiphy->bands[IEEE80211_BAND_5GHZ]; + + if (!sband) { + dev_err(priv->adapter->dev, "%s: cannot find cfp by band %d" + " & channel %d\n", __func__, band, channel); + return cfp; + } + + for (i = 0; i < sband->n_channels; i++) { + ch = &sband->channels[i]; + if (((ch->hw_value == channel) || + (channel == FIRST_VALID_CHANNEL)) + && !(ch->flags & IEEE80211_CHAN_DISABLED)) { + priv->cfp.channel = channel; + priv->cfp.freq = ch->center_freq; + priv->cfp.max_tx_power = ch->max_power; + cfp = &priv->cfp; + break; + } + } + if (i == sband->n_channels) + dev_err(priv->adapter->dev, "%s: cannot find cfp by band %d" + " & channel %d\n", __func__, band, channel); + + return cfp; +} + +/* + * This function locates the Channel-Frequency-Power triplet based upon + * band and frequency parameters. + */ +struct mwifiex_chan_freq_power * +mwifiex_get_cfp_by_band_and_freq_from_cfg80211(struct mwifiex_private *priv, + u8 band, u32 freq) +{ + struct mwifiex_chan_freq_power *cfp = NULL; + struct ieee80211_supported_band *sband; + struct ieee80211_channel *ch; + int i; + + if (mwifiex_band_to_radio_type(band) == HostCmd_SCAN_RADIO_TYPE_BG) + sband = priv->wdev->wiphy->bands[IEEE80211_BAND_2GHZ]; + else + sband = priv->wdev->wiphy->bands[IEEE80211_BAND_5GHZ]; + + if (!sband) { + dev_err(priv->adapter->dev, "%s: cannot find cfp by band %d" + " & freq %d\n", __func__, band, freq); + return cfp; + } + + for (i = 0; i < sband->n_channels; i++) { + ch = &sband->channels[i]; + if ((ch->center_freq == freq) && + !(ch->flags & IEEE80211_CHAN_DISABLED)) { + priv->cfp.channel = ch->hw_value; + priv->cfp.freq = freq; + priv->cfp.max_tx_power = ch->max_power; + cfp = &priv->cfp; + break; + } + } + if (i == sband->n_channels) + dev_err(priv->adapter->dev, "%s: cannot find cfp by band %d" + " & freq %d\n", __func__, band, freq); + + return cfp; +} + +/* + * This function checks if the data rate is set to auto. + */ +u8 +mwifiex_is_rate_auto(struct mwifiex_private *priv) +{ + u32 i; + int rate_num = 0; + + for (i = 0; i < ARRAY_SIZE(priv->bitmap_rates); i++) + if (priv->bitmap_rates[i]) + rate_num++; + + if (rate_num > 1) + return true; + else + return false; +} + +/* + * This function converts rate bitmap into rate index. + */ +int +mwifiex_get_rate_index(struct mwifiex_adapter *adapter, u16 *rate_bitmap, + int size) +{ + int i; + + for (i = 0; i < size * 8; i++) + if (rate_bitmap[i / 16] & (1 << (i % 16))) + return i; + + return 0; +} + +/* + * This function gets the supported data rates. + * + * The function works in both Ad-Hoc and infra mode by printing the + * band and returning the data rates. + */ +u32 mwifiex_get_supported_rates(struct mwifiex_private *priv, u8 *rates) +{ + u32 k = 0; + struct mwifiex_adapter *adapter = priv->adapter; + if (priv->bss_mode == MWIFIEX_BSS_MODE_INFRA) { + /* Infra. mode */ + switch (adapter->config_bands) { + case BAND_B: + dev_dbg(adapter->dev, "info: infra band=%d " + "supported_rates_b\n", adapter->config_bands); + k = mwifiex_copy_rates(rates, k, supported_rates_b, + sizeof(supported_rates_b)); + break; + case BAND_G: + case BAND_G | BAND_GN: + dev_dbg(adapter->dev, "info: infra band=%d " + "supported_rates_g\n", adapter->config_bands); + k = mwifiex_copy_rates(rates, k, supported_rates_g, + sizeof(supported_rates_g)); + break; + case BAND_B | BAND_G: + case BAND_A | BAND_B | BAND_G: + case BAND_A | BAND_B: + case BAND_A | BAND_B | BAND_G | BAND_GN | BAND_AN: + case BAND_B | BAND_G | BAND_GN: + dev_dbg(adapter->dev, "info: infra band=%d " + "supported_rates_bg\n", adapter->config_bands); + k = mwifiex_copy_rates(rates, k, supported_rates_bg, + sizeof(supported_rates_bg)); + break; + case BAND_A: + case BAND_A | BAND_G: + dev_dbg(adapter->dev, "info: infra band=%d " + "supported_rates_a\n", adapter->config_bands); + k = mwifiex_copy_rates(rates, k, supported_rates_a, + sizeof(supported_rates_a)); + break; + case BAND_A | BAND_AN: + case BAND_A | BAND_G | BAND_AN | BAND_GN: + dev_dbg(adapter->dev, "info: infra band=%d " + "supported_rates_a\n", adapter->config_bands); + k = mwifiex_copy_rates(rates, k, supported_rates_a, + sizeof(supported_rates_a)); + break; + case BAND_GN: + dev_dbg(adapter->dev, "info: infra band=%d " + "supported_rates_n\n", adapter->config_bands); + k = mwifiex_copy_rates(rates, k, supported_rates_n, + sizeof(supported_rates_n)); + break; + } + } else { + /* Ad-hoc mode */ + switch (adapter->adhoc_start_band) { + case BAND_B: + dev_dbg(adapter->dev, "info: adhoc B\n"); + k = mwifiex_copy_rates(rates, k, adhoc_rates_b, + sizeof(adhoc_rates_b)); + break; + case BAND_G: + case BAND_G | BAND_GN: + dev_dbg(adapter->dev, "info: adhoc G only\n"); + k = mwifiex_copy_rates(rates, k, adhoc_rates_g, + sizeof(adhoc_rates_g)); + break; + case BAND_B | BAND_G: + case BAND_B | BAND_G | BAND_GN: + dev_dbg(adapter->dev, "info: adhoc BG\n"); + k = mwifiex_copy_rates(rates, k, adhoc_rates_bg, + sizeof(adhoc_rates_bg)); + break; + case BAND_A: + case BAND_A | BAND_AN: + dev_dbg(adapter->dev, "info: adhoc A\n"); + k = mwifiex_copy_rates(rates, k, adhoc_rates_a, + sizeof(adhoc_rates_a)); + break; + } + } + + return k; +} diff --git a/drivers/net/wireless/mwifiex/cmdevt.c b/drivers/net/wireless/mwifiex/cmdevt.c new file mode 100644 index 0000000..3a8fe1e --- /dev/null +++ b/drivers/net/wireless/mwifiex/cmdevt.c @@ -0,0 +1,1463 @@ +/* + * Marvell Wireless LAN device driver: commands and events + * + * Copyright (C) 2011, Marvell International Ltd. + * + * This software file (the "File") is distributed by Marvell International + * Ltd. under the terms of the GNU General Public License Version 2, June 1991 + * (the "License"). You may use, redistribute and/or modify this File in + * accordance with the terms and conditions of the License, a copy of which + * is available by writing to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the + * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. + * + * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE + * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE + * ARE EXPRESSLY DISCLAIMED. The License provides additional details about + * this warranty disclaimer. + */ + +#include "decl.h" +#include "ioctl.h" +#include "util.h" +#include "fw.h" +#include "main.h" +#include "wmm.h" +#include "11n.h" + +/* + * This function initializes a command node. + * + * The actual allocation of the node is not done by this function. It only + * initiates a node by filling it with default parameters. Similarly, + * allocation of the different buffers used (IOCTL buffer, data buffer) are + * not done by this function either. + */ +static void +mwifiex_init_cmd_node(struct mwifiex_private *priv, + struct cmd_ctrl_node *cmd_node, + u32 cmd_oid, void *wait_queue, void *data_buf) +{ + cmd_node->priv = priv; + cmd_node->cmd_oid = cmd_oid; + cmd_node->wq_buf = wait_queue; + cmd_node->data_buf = data_buf; + cmd_node->cmd_skb = cmd_node->skb; +} + +/* + * This function returns a command node from the free queue depending upon + * availability. + */ +static struct cmd_ctrl_node * +mwifiex_get_cmd_node(struct mwifiex_adapter *adapter) +{ + struct cmd_ctrl_node *cmd_node; + unsigned long flags; + + spin_lock_irqsave(&adapter->cmd_free_q_lock, flags); + if (list_empty(&adapter->cmd_free_q)) { + dev_err(adapter->dev, "GET_CMD_NODE: cmd node not available\n"); + spin_unlock_irqrestore(&adapter->cmd_free_q_lock, flags); + return NULL; + } + cmd_node = list_first_entry(&adapter->cmd_free_q, + struct cmd_ctrl_node, list); + list_del(&cmd_node->list); + spin_unlock_irqrestore(&adapter->cmd_free_q_lock, flags); + + return cmd_node; +} + +/* + * This function cleans up a command node. + * + * The function resets the fields including the buffer pointers. + * This function does not try to free the buffers. They must be + * freed before calling this function. + * + * This function will however call the receive completion callback + * in case a response buffer is still available before resetting + * the pointer. + */ +static void +mwifiex_clean_cmd_node(struct mwifiex_adapter *adapter, + struct cmd_ctrl_node *cmd_node) +{ + cmd_node->cmd_oid = 0; + cmd_node->cmd_flag = 0; + cmd_node->wq_buf = NULL; + cmd_node->data_buf = NULL; + + if (cmd_node->resp_skb) { + mwifiex_recv_complete(adapter, cmd_node->resp_skb, 0); + cmd_node->resp_skb = NULL; + } + + return; +} + +/* + * This function returns a command node from the pending queue which + * matches the given IOCTL request. + */ +static struct cmd_ctrl_node * +mwifiex_get_pending_ioctl_cmd(struct mwifiex_adapter *adapter, + struct mwifiex_wait_queue *wait_queue) +{ + unsigned long flags; + struct cmd_ctrl_node *cmd_node; + + spin_lock_irqsave(&adapter->cmd_pending_q_lock, flags); + list_for_each_entry(cmd_node, &adapter->cmd_pending_q, list) { + if (cmd_node->wq_buf == wait_queue) { + spin_unlock_irqrestore(&adapter->cmd_pending_q_lock, + flags); + return cmd_node; + } + } + spin_unlock_irqrestore(&adapter->cmd_pending_q_lock, flags); + + return NULL; +} + +/* + * This function sends a host command to the firmware. + * + * The function copies the host command into the driver command + * buffer, which will be transferred to the firmware later by the + * main thread. + */ +static int mwifiex_cmd_host_cmd(struct mwifiex_private *priv, + struct host_cmd_ds_command *cmd, void *data_buf) +{ + struct mwifiex_ds_misc_cmd *pcmd_ptr = + (struct mwifiex_ds_misc_cmd *) data_buf; + + /* Copy the HOST command to command buffer */ + memcpy((void *) cmd, pcmd_ptr->cmd, pcmd_ptr->len); + dev_dbg(priv->adapter->dev, "cmd: host cmd size = %d\n", pcmd_ptr->len); + return 0; +} + +/* + * This function downloads a command to the firmware. + * + * The function performs sanity tests, sets the command sequence + * number and size, converts the header fields to CPU format before + * sending. Afterwards, it logs the command ID and action for debugging + * and sets up the command timeout timer. + */ +static int mwifiex_dnld_cmd_to_fw(struct mwifiex_private *priv, + struct cmd_ctrl_node *cmd_node) +{ + + struct mwifiex_adapter *adapter = priv->adapter; + int ret = 0; + struct host_cmd_ds_command *host_cmd; + struct mwifiex_wait_queue *wait_queue = NULL; + uint16_t cmd_code; + uint16_t cmd_size; + struct timeval tstamp; + unsigned long flags; + + if (!adapter || !cmd_node) + return -1; + + host_cmd = (struct host_cmd_ds_command *) (cmd_node->cmd_skb->data); + if (cmd_node->wq_buf) + wait_queue = (struct mwifiex_wait_queue *) cmd_node->wq_buf; + + /* Sanity test */ + if (host_cmd == NULL || host_cmd->size == 0) { + dev_err(adapter->dev, "DNLD_CMD: host_cmd is null" + " or cmd size is 0, not sending\n"); + if (wait_queue) + wait_queue->status = MWIFIEX_ERROR_CMD_DNLD_FAIL; + mwifiex_insert_cmd_to_free_q(adapter, cmd_node); + return -1; + } + + /* Set command sequence number */ + adapter->seq_num++; + host_cmd->seq_num = cpu_to_le16(HostCmd_SET_SEQ_NO_BSS_INFO + (adapter->seq_num, cmd_node->priv->bss_num, + cmd_node->priv->bss_type)); + + spin_lock_irqsave(&adapter->mwifiex_cmd_lock, flags); + adapter->curr_cmd = cmd_node; + spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock, flags); + + cmd_code = le16_to_cpu(host_cmd->command); + cmd_size = le16_to_cpu(host_cmd->size); + + skb_trim(cmd_node->cmd_skb, cmd_size); + + do_gettimeofday(&tstamp); + dev_dbg(adapter->dev, "cmd: DNLD_CMD: (%lu.%lu): %#x, act %#x, len %d," + " seqno %#x\n", + tstamp.tv_sec, tstamp.tv_usec, cmd_code, + le16_to_cpu(*(__le16 *) ((u8 *) host_cmd + S_DS_GEN)), cmd_size, + le16_to_cpu(host_cmd->seq_num)); + + skb_push(cmd_node->cmd_skb, INTF_HEADER_LEN); + + ret = adapter->if_ops.host_to_card(adapter, MWIFIEX_TYPE_CMD, + cmd_node->cmd_skb->data, + cmd_node->cmd_skb->len, NULL); + + if (ret == -1) { + dev_err(adapter->dev, "DNLD_CMD: host to card failed\n"); + if (wait_queue) + wait_queue->status = MWIFIEX_ERROR_CMD_DNLD_FAIL; + mwifiex_insert_cmd_to_free_q(adapter, adapter->curr_cmd); + + spin_lock_irqsave(&adapter->mwifiex_cmd_lock, flags); + adapter->curr_cmd = NULL; + spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock, flags); + + adapter->dbg.num_cmd_host_to_card_failure++; + return -1; + } + + /* Save the last command id and action to debug log */ + adapter->dbg.last_cmd_index = + (adapter->dbg.last_cmd_index + 1) % DBG_CMD_NUM; + adapter->dbg.last_cmd_id[adapter->dbg.last_cmd_index] = cmd_code; + adapter->dbg.last_cmd_act[adapter->dbg.last_cmd_index] = + le16_to_cpu(*(__le16 *) ((u8 *) host_cmd + S_DS_GEN)); + + /* Clear BSS_NO_BITS from HostCmd */ + cmd_code &= HostCmd_CMD_ID_MASK; + + /* Setup the timer after transmit command */ + mod_timer(&adapter->cmd_timer, + jiffies + (MWIFIEX_TIMER_10S * HZ) / 1000); + + return 0; +} + +/* + * This function downloads a sleep confirm command to the firmware. + * + * The function performs sanity tests, sets the command sequence + * number and size, converts the header fields to CPU format before + * sending. + * + * No responses are needed for sleep confirm command. + */ +static int mwifiex_dnld_sleep_confirm_cmd(struct mwifiex_adapter *adapter) +{ + int ret = 0; + u16 cmd_len = 0; + struct mwifiex_private *priv; + struct mwifiex_opt_sleep_confirm_buffer *sleep_cfm_buf = + (struct mwifiex_opt_sleep_confirm_buffer *) + adapter->sleep_cfm->data; + cmd_len = sizeof(struct mwifiex_opt_sleep_confirm); + priv = mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_ANY); + + sleep_cfm_buf->ps_cfm_sleep.seq_num = + cpu_to_le16((HostCmd_SET_SEQ_NO_BSS_INFO + (adapter->seq_num, priv->bss_num, + priv->bss_type))); + adapter->seq_num++; + + ret = adapter->if_ops.host_to_card(adapter, MWIFIEX_TYPE_CMD, + adapter->sleep_cfm->data, + adapter->sleep_cfm->len + + INTF_HEADER_LEN, NULL); + + if (ret == -1) { + dev_err(adapter->dev, "SLEEP_CFM: failed\n"); + adapter->dbg.num_cmd_sleep_cfm_host_to_card_failure++; + return -1; + } + if (GET_BSS_ROLE(mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_ANY)) + == MWIFIEX_BSS_ROLE_STA) { + if (!sleep_cfm_buf->ps_cfm_sleep.sleep_cfm.resp_ctrl) + /* Response is not needed for sleep + confirm command */ + adapter->ps_state = PS_STATE_SLEEP; + else + adapter->ps_state = PS_STATE_SLEEP_CFM; + + if (!sleep_cfm_buf->ps_cfm_sleep.sleep_cfm.resp_ctrl + && (adapter->is_hs_configured + && !adapter->sleep_period.period)) { + adapter->pm_wakeup_card_req = true; + mwifiex_hs_activated_event(mwifiex_get_priv(adapter, + MWIFIEX_BSS_ROLE_STA), true); + } + } + + return ret; +} + +/* + * This function allocates the command buffers and links them to + * the command free queue. + * + * The driver uses a pre allocated number of command buffers, which + * are created at driver initializations and freed at driver cleanup. + * Every command needs to obtain a command buffer from this pool before + * it can be issued. The command free queue lists the command buffers + * currently free to use, while the command pending queue lists the + * command buffers already in use and awaiting handling. Command buffers + * are returned to the free queue after use. + */ +int mwifiex_alloc_cmd_buffer(struct mwifiex_adapter *adapter) +{ + struct cmd_ctrl_node *cmd_array; + u32 buf_size; + u32 i; + + /* Allocate and initialize struct cmd_ctrl_node */ + buf_size = sizeof(struct cmd_ctrl_node) * MWIFIEX_NUM_OF_CMD_BUFFER; + cmd_array = kzalloc(buf_size, GFP_KERNEL); + if (!cmd_array) { + dev_err(adapter->dev, "%s: failed to alloc cmd_array\n", + __func__); + return -1; + } + + adapter->cmd_pool = cmd_array; + memset(adapter->cmd_pool, 0, buf_size); + + /* Allocate and initialize command buffers */ + for (i = 0; i < MWIFIEX_NUM_OF_CMD_BUFFER; i++) { + cmd_array[i].skb = dev_alloc_skb(MWIFIEX_SIZE_OF_CMD_BUFFER); + if (!cmd_array[i].skb) { + dev_err(adapter->dev, "ALLOC_CMD_BUF: out of memory\n"); + return -1; + } + } + + for (i = 0; i < MWIFIEX_NUM_OF_CMD_BUFFER; i++) + mwifiex_insert_cmd_to_free_q(adapter, &cmd_array[i]); + + return 0; +} + +/* + * This function frees the command buffers. + * + * The function calls the completion callback for all the command + * buffers that still have response buffers associated with them. + */ +int mwifiex_free_cmd_buffer(struct mwifiex_adapter *adapter) +{ + struct cmd_ctrl_node *cmd_array; + u32 i; + + /* Need to check if cmd pool is allocated or not */ + if (!adapter->cmd_pool) { + dev_dbg(adapter->dev, "info: FREE_CMD_BUF: cmd_pool is null\n"); + return 0; + } + + cmd_array = adapter->cmd_pool; + + /* Release shared memory buffers */ + for (i = 0; i < MWIFIEX_NUM_OF_CMD_BUFFER; i++) { + if (cmd_array[i].skb) { + dev_dbg(adapter->dev, "cmd: free cmd buffer %d\n", i); + dev_kfree_skb_any(cmd_array[i].skb); + } + if (!cmd_array[i].resp_skb) + continue; + mwifiex_recv_complete(adapter, cmd_array[i].resp_skb, 0); + } + /* Release struct cmd_ctrl_node */ + if (adapter->cmd_pool) { + dev_dbg(adapter->dev, "cmd: free cmd pool\n"); + kfree(adapter->cmd_pool); + adapter->cmd_pool = NULL; + } + + return 0; +} + +/* + * This function handles events generated by firmware. + * + * Event body of events received from firmware are not used (though they are + * saved), only the event ID is used. Some events are re-invoked by + * the driver, with a new event body. + * + * After processing, the function calls the completion callback + * for cleanup. + */ +int mwifiex_process_event(struct mwifiex_adapter *adapter) +{ + int ret = 0; + struct mwifiex_private *priv = + mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_ANY); + struct sk_buff *skb = adapter->event_skb; + u32 eventcause = adapter->event_cause; + struct timeval tstamp; + struct mwifiex_rxinfo *rx_info = NULL; + + /* Save the last event to debug log */ + adapter->dbg.last_event_index = + (adapter->dbg.last_event_index + 1) % DBG_CMD_NUM; + adapter->dbg.last_event[adapter->dbg.last_event_index] = + (u16) eventcause; + + /* Get BSS number and corresponding priv */ + priv = mwifiex_get_priv_by_id(adapter, EVENT_GET_BSS_NUM(eventcause), + EVENT_GET_BSS_TYPE(eventcause)); + if (!priv) + priv = mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_ANY); + /* Clear BSS_NO_BITS from event */ + eventcause &= EVENT_ID_MASK; + adapter->event_cause = eventcause; + + if (skb) { + rx_info = MWIFIEX_SKB_RXCB(skb); + rx_info->bss_index = priv->bss_index; + } + + if (eventcause != EVENT_PS_SLEEP && eventcause != EVENT_PS_AWAKE) { + do_gettimeofday(&tstamp); + dev_dbg(adapter->dev, "event: %lu.%lu: cause: %#x\n", + tstamp.tv_sec, tstamp.tv_usec, eventcause); + } + + ret = mwifiex_process_sta_event(priv); + + adapter->event_cause = 0; + adapter->event_skb = NULL; + + mwifiex_recv_complete(adapter, skb, 0); + + return ret; +} + +/* + * This function prepares a command before sending it to the firmware. + * + * Preparation includes - + * - Sanity tests to make sure the card is still present or the FW + * is not reset + * - Getting a new command node from the command free queue + * - Initializing the command node for default parameters + * - Fill up the non-default parameters and buffer pointers + * - Add the command to pending queue + */ +int mwifiex_prepare_cmd(struct mwifiex_private *priv, uint16_t cmd_no, + u16 cmd_action, u32 cmd_oid, + void *wait_queue, void *data_buf) +{ + int ret = 0; + struct mwifiex_adapter *adapter = priv->adapter; + struct cmd_ctrl_node *cmd_node = NULL; + struct host_cmd_ds_command *cmd_ptr = NULL; + + if (!adapter) { + pr_err("PREP_CMD: adapter is NULL\n"); + return -1; + } + + if (adapter->is_suspended) { + dev_err(adapter->dev, "PREP_CMD: device in suspended state\n"); + return -1; + } + + if (adapter->surprise_removed) { + dev_err(adapter->dev, "PREP_CMD: card is removed\n"); + return -1; + } + + if (adapter->hw_status == MWIFIEX_HW_STATUS_RESET) { + if (cmd_no != HostCmd_CMD_FUNC_INIT) { + dev_err(adapter->dev, "PREP_CMD: FW in reset state\n"); + return -1; + } + } + + /* Get a new command node */ + cmd_node = mwifiex_get_cmd_node(adapter); + + if (!cmd_node) { + dev_err(adapter->dev, "PREP_CMD: no free cmd node\n"); + return -1; + } + + /* Initialize the command node */ + mwifiex_init_cmd_node(priv, cmd_node, cmd_oid, wait_queue, data_buf); + + if (!cmd_node->cmd_skb) { + dev_err(adapter->dev, "PREP_CMD: no free cmd buf\n"); + return -1; + } + + memset(skb_put(cmd_node->cmd_skb, sizeof(struct host_cmd_ds_command)), + 0, sizeof(struct host_cmd_ds_command)); + + cmd_ptr = (struct host_cmd_ds_command *) (cmd_node->cmd_skb->data); + cmd_ptr->command = cpu_to_le16(cmd_no); + cmd_ptr->result = 0; + + /* Prepare command */ + if (cmd_no) { + ret = mwifiex_sta_prepare_cmd(priv, cmd_no, cmd_action, + cmd_oid, data_buf, cmd_ptr); + } else { + ret = mwifiex_cmd_host_cmd(priv, cmd_ptr, data_buf); + cmd_node->cmd_flag |= CMD_F_HOSTCMD; + } + + /* Return error, since the command preparation failed */ + if (ret) { + dev_err(adapter->dev, "PREP_CMD: cmd %#x preparation failed\n", + cmd_no); + mwifiex_insert_cmd_to_free_q(adapter, cmd_node); + return -1; + } + + /* Send command */ + if (cmd_no == HostCmd_CMD_802_11_SCAN) + mwifiex_queue_scan_cmd(priv, cmd_node); + else + mwifiex_insert_cmd_to_pending_q(adapter, cmd_node, true); + + return ret; +} + +/* + * This function returns a command to the command free queue. + * + * The function also calls the completion callback if required, before + * cleaning the command node and re-inserting it into the free queue. + */ +void +mwifiex_insert_cmd_to_free_q(struct mwifiex_adapter *adapter, + struct cmd_ctrl_node *cmd_node) +{ + struct mwifiex_wait_queue *wait_queue = NULL; + unsigned long flags; + + if (cmd_node == NULL) + return; + if (cmd_node->wq_buf) { + wait_queue = (struct mwifiex_wait_queue *) cmd_node->wq_buf; + if (wait_queue->status != MWIFIEX_ERROR_NO_ERROR) + mwifiex_ioctl_complete(adapter, wait_queue, -1); + else + mwifiex_ioctl_complete(adapter, wait_queue, 0); + } + /* Clean the node */ + mwifiex_clean_cmd_node(adapter, cmd_node); + + /* Insert node into cmd_free_q */ + spin_lock_irqsave(&adapter->cmd_free_q_lock, flags); + list_add_tail(&cmd_node->list, &adapter->cmd_free_q); + spin_unlock_irqrestore(&adapter->cmd_free_q_lock, flags); + + return; +} + +/* + * This function queues a command to the command pending queue. + * + * This in effect adds the command to the command list to be executed. + * Exit PS command is handled specially, by placing it always to the + * front of the command queue. + */ +void +mwifiex_insert_cmd_to_pending_q(struct mwifiex_adapter *adapter, + struct cmd_ctrl_node *cmd_node, u32 add_tail) +{ + struct host_cmd_ds_command *host_cmd = NULL; + u16 command; + unsigned long flags; + + host_cmd = (struct host_cmd_ds_command *) (cmd_node->cmd_skb->data); + if (!host_cmd) { + dev_err(adapter->dev, "QUEUE_CMD: host_cmd is NULL\n"); + return; + } + + command = le16_to_cpu(host_cmd->command); + + /* Exit_PS command needs to be queued in the header always. */ + if (command == HostCmd_CMD_802_11_PS_MODE_ENH) { + struct host_cmd_ds_802_11_ps_mode_enh *pm = + &host_cmd->params.psmode_enh; + if ((le16_to_cpu(pm->action) == DIS_PS) + || (le16_to_cpu(pm->action) == DIS_AUTO_PS)) { + if (adapter->ps_state != PS_STATE_AWAKE) + add_tail = false; + } + } + + spin_lock_irqsave(&adapter->cmd_pending_q_lock, flags); + if (add_tail) + list_add_tail(&cmd_node->list, &adapter->cmd_pending_q); + else + list_add(&cmd_node->list, &adapter->cmd_pending_q); + spin_unlock_irqrestore(&adapter->cmd_pending_q_lock, flags); + + dev_dbg(adapter->dev, "cmd: QUEUE_CMD: cmd=%#x is queued\n", command); + + return; +} + +/* + * This function executes the next command in command pending queue. + * + * This function will fail if a command is already in processing stage, + * otherwise it will dequeue the first command from the command pending + * queue and send to the firmware. + * + * If the device is currently in host sleep mode, any commands, except the + * host sleep configuration command will de-activate the host sleep. For PS + * mode, the function will put the firmware back to sleep if applicable. + */ +int mwifiex_exec_next_cmd(struct mwifiex_adapter *adapter) +{ + struct mwifiex_private *priv = NULL; + struct cmd_ctrl_node *cmd_node = NULL; + int ret = 0; + struct host_cmd_ds_command *host_cmd; + unsigned long cmd_flags; + unsigned long cmd_pending_q_flags; + + /* Check if already in processing */ + if (adapter->curr_cmd) { + dev_err(adapter->dev, "EXEC_NEXT_CMD: cmd in processing\n"); + return -1; + } + + spin_lock_irqsave(&adapter->mwifiex_cmd_lock, cmd_flags); + /* Check if any command is pending */ + spin_lock_irqsave(&adapter->cmd_pending_q_lock, cmd_pending_q_flags); + if (list_empty(&adapter->cmd_pending_q)) { + spin_unlock_irqrestore(&adapter->cmd_pending_q_lock, + cmd_pending_q_flags); + spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock, cmd_flags); + return 0; + } + cmd_node = list_first_entry(&adapter->cmd_pending_q, + struct cmd_ctrl_node, list); + spin_unlock_irqrestore(&adapter->cmd_pending_q_lock, + cmd_pending_q_flags); + + host_cmd = (struct host_cmd_ds_command *) (cmd_node->cmd_skb->data); + priv = cmd_node->priv; + + if (adapter->ps_state != PS_STATE_AWAKE) { + dev_err(adapter->dev, "%s: cannot send cmd in sleep state," + " this should not happen\n", __func__); + spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock, cmd_flags); + return ret; + } + + spin_lock_irqsave(&adapter->cmd_pending_q_lock, cmd_pending_q_flags); + list_del(&cmd_node->list); + spin_unlock_irqrestore(&adapter->cmd_pending_q_lock, + cmd_pending_q_flags); + + spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock, cmd_flags); + ret = mwifiex_dnld_cmd_to_fw(priv, cmd_node); + priv = mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_ANY); + /* Any command sent to the firmware when host is in sleep + * mode should de-configure host sleep. We should skip the + * host sleep configuration command itself though + */ + if (priv && (host_cmd->command != + cpu_to_le16(HostCmd_CMD_802_11_HS_CFG_ENH))) { + if (adapter->hs_activated) { + adapter->is_hs_configured = false; + mwifiex_hs_activated_event(priv, false); + } + } + + return ret; +} + +/* + * This function handles the command response. + * + * After processing, the function cleans the command node and puts + * it back to the command free queue. + */ +int mwifiex_process_cmdresp(struct mwifiex_adapter *adapter) +{ + struct host_cmd_ds_command *resp = NULL; + struct mwifiex_private *priv = + mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_ANY); + int ret = 0; + uint16_t orig_cmdresp_no; + uint16_t cmdresp_no; + uint16_t cmdresp_result; + struct mwifiex_wait_queue *wait_queue = NULL; + struct timeval tstamp; + unsigned long flags; + + /* Now we got response from FW, cancel the command timer */ + del_timer(&adapter->cmd_timer); + + if (!adapter->curr_cmd || !adapter->curr_cmd->resp_skb) { + resp = (struct host_cmd_ds_command *) adapter->upld_buf; + dev_err(adapter->dev, "CMD_RESP: NULL curr_cmd, %#x\n", + le16_to_cpu(resp->command)); + return -1; + } + + if (adapter->curr_cmd->wq_buf) + wait_queue = (struct mwifiex_wait_queue *) + adapter->curr_cmd->wq_buf; + + adapter->num_cmd_timeout = 0; + + resp = (struct host_cmd_ds_command *) adapter->curr_cmd->resp_skb->data; + if (adapter->curr_cmd->cmd_flag & CMD_F_CANCELED) { + dev_err(adapter->dev, "CMD_RESP: %#x been canceled\n", + le16_to_cpu(resp->command)); + mwifiex_insert_cmd_to_free_q(adapter, adapter->curr_cmd); + spin_lock_irqsave(&adapter->mwifiex_cmd_lock, flags); + adapter->curr_cmd = NULL; + spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock, flags); + return -1; + } + + if (adapter->curr_cmd->cmd_flag & CMD_F_HOSTCMD) { + /* Copy original response back to response buffer */ + struct mwifiex_ds_misc_cmd *hostcmd = NULL; + uint16_t size = le16_to_cpu(resp->size); + dev_dbg(adapter->dev, "info: host cmd resp size = %d\n", size); + size = min_t(u16, size, MWIFIEX_SIZE_OF_CMD_BUFFER); + if (adapter->curr_cmd->data_buf) { + hostcmd = (struct mwifiex_ds_misc_cmd *) + adapter->curr_cmd->data_buf; + hostcmd->len = size; + memcpy(hostcmd->cmd, (void *) resp, size); + } + } + orig_cmdresp_no = le16_to_cpu(resp->command); + + /* Get BSS number and corresponding priv */ + priv = mwifiex_get_priv_by_id(adapter, + HostCmd_GET_BSS_NO(le16_to_cpu(resp->seq_num)), + HostCmd_GET_BSS_TYPE(le16_to_cpu(resp->seq_num))); + if (!priv) + priv = mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_ANY); + /* Clear RET_BIT from HostCmd */ + resp->command = cpu_to_le16(orig_cmdresp_no & HostCmd_CMD_ID_MASK); + + cmdresp_no = le16_to_cpu(resp->command); + cmdresp_result = le16_to_cpu(resp->result); + + /* Save the last command response to debug log */ + adapter->dbg.last_cmd_resp_index = + (adapter->dbg.last_cmd_resp_index + 1) % DBG_CMD_NUM; + adapter->dbg.last_cmd_resp_id[adapter->dbg.last_cmd_resp_index] = + orig_cmdresp_no; + + do_gettimeofday(&tstamp); + dev_dbg(adapter->dev, "cmd: CMD_RESP: (%lu.%lu): 0x%x, result %d," + " len %d, seqno 0x%x\n", + tstamp.tv_sec, tstamp.tv_usec, orig_cmdresp_no, cmdresp_result, + le16_to_cpu(resp->size), le16_to_cpu(resp->seq_num)); + + if (!(orig_cmdresp_no & HostCmd_RET_BIT)) { + dev_err(adapter->dev, "CMD_RESP: invalid cmd resp\n"); + if (wait_queue) + wait_queue->status = MWIFIEX_ERROR_FW_CMDRESP; + + mwifiex_insert_cmd_to_free_q(adapter, adapter->curr_cmd); + spin_lock_irqsave(&adapter->mwifiex_cmd_lock, flags); + adapter->curr_cmd = NULL; + spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock, flags); + return -1; + } + + if (adapter->curr_cmd->cmd_flag & CMD_F_HOSTCMD) { + adapter->curr_cmd->cmd_flag &= ~CMD_F_HOSTCMD; + if ((cmdresp_result == HostCmd_RESULT_OK) + && (cmdresp_no == HostCmd_CMD_802_11_HS_CFG_ENH)) + ret = mwifiex_ret_802_11_hs_cfg(priv, resp); + } else { + /* handle response */ + ret = mwifiex_process_sta_cmdresp(priv, cmdresp_no, resp, + wait_queue); + } + + /* Check init command response */ + if (adapter->hw_status == MWIFIEX_HW_STATUS_INITIALIZING) { + if (ret == -1) { + dev_err(adapter->dev, "%s: cmd %#x failed during " + "initialization\n", __func__, cmdresp_no); + mwifiex_init_fw_complete(adapter); + return -1; + } else if (adapter->last_init_cmd == cmdresp_no) + adapter->hw_status = MWIFIEX_HW_STATUS_INIT_DONE; + } + + if (adapter->curr_cmd) { + if (wait_queue && (!ret)) + wait_queue->status = MWIFIEX_ERROR_NO_ERROR; + else if (wait_queue && (ret == -1)) + wait_queue->status = MWIFIEX_ERROR_CMD_RESP_FAIL; + + /* Clean up and put current command back to cmd_free_q */ + mwifiex_insert_cmd_to_free_q(adapter, adapter->curr_cmd); + + spin_lock_irqsave(&adapter->mwifiex_cmd_lock, flags); + adapter->curr_cmd = NULL; + spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock, flags); + } + + return ret; +} + +/* + * This function handles the timeout of command sending. + * + * It will re-send the same command again. + */ +void +mwifiex_cmd_timeout_func(unsigned long function_context) +{ + struct mwifiex_adapter *adapter = + (struct mwifiex_adapter *) function_context; + struct cmd_ctrl_node *cmd_node = NULL; + struct mwifiex_wait_queue *wait_queue = NULL; + struct timeval tstamp; + + adapter->num_cmd_timeout++; + adapter->dbg.num_cmd_timeout++; + if (!adapter->curr_cmd) { + dev_dbg(adapter->dev, "cmd: empty curr_cmd\n"); + return; + } + cmd_node = adapter->curr_cmd; + if (cmd_node->wq_buf) { + wait_queue = (struct mwifiex_wait_queue *) cmd_node->wq_buf; + wait_queue->status = MWIFIEX_ERROR_CMD_TIMEOUT; + } + + if (cmd_node) { + adapter->dbg.timeout_cmd_id = + adapter->dbg.last_cmd_id[adapter->dbg.last_cmd_index]; + adapter->dbg.timeout_cmd_act = + adapter->dbg.last_cmd_act[adapter->dbg.last_cmd_index]; + do_gettimeofday(&tstamp); + dev_err(adapter->dev, "%s: Timeout cmd id (%lu.%lu) = %#x," + " act = %#x\n", __func__, + tstamp.tv_sec, tstamp.tv_usec, + adapter->dbg.timeout_cmd_id, + adapter->dbg.timeout_cmd_act); + + dev_err(adapter->dev, "num_data_h2c_failure = %d\n", + adapter->dbg.num_tx_host_to_card_failure); + dev_err(adapter->dev, "num_cmd_h2c_failure = %d\n", + adapter->dbg.num_cmd_host_to_card_failure); + + dev_err(adapter->dev, "num_cmd_timeout = %d\n", + adapter->dbg.num_cmd_timeout); + dev_err(adapter->dev, "num_tx_timeout = %d\n", + adapter->dbg.num_tx_timeout); + + dev_err(adapter->dev, "last_cmd_index = %d\n", + adapter->dbg.last_cmd_index); + print_hex_dump_bytes("last_cmd_id: ", DUMP_PREFIX_OFFSET, + adapter->dbg.last_cmd_id, DBG_CMD_NUM); + print_hex_dump_bytes("last_cmd_act: ", DUMP_PREFIX_OFFSET, + adapter->dbg.last_cmd_act, DBG_CMD_NUM); + + dev_err(adapter->dev, "last_cmd_resp_index = %d\n", + adapter->dbg.last_cmd_resp_index); + print_hex_dump_bytes("last_cmd_resp_id: ", DUMP_PREFIX_OFFSET, + adapter->dbg.last_cmd_resp_id, DBG_CMD_NUM); + + dev_err(adapter->dev, "last_event_index = %d\n", + adapter->dbg.last_event_index); + print_hex_dump_bytes("last_event: ", DUMP_PREFIX_OFFSET, + adapter->dbg.last_event, DBG_CMD_NUM); + + dev_err(adapter->dev, "data_sent=%d cmd_sent=%d\n", + adapter->data_sent, adapter->cmd_sent); + + dev_err(adapter->dev, "ps_mode=%d ps_state=%d\n", + adapter->ps_mode, adapter->ps_state); + } + if (adapter->hw_status == MWIFIEX_HW_STATUS_INITIALIZING) + mwifiex_init_fw_complete(adapter); + + return; +} + +/* + * This function cancels all the pending commands. + * + * The current command, all commands in command pending queue and all scan + * commands in scan pending queue are cancelled. All the completion callbacks + * are called with failure status to ensure cleanup. + */ +void +mwifiex_cancel_all_pending_cmd(struct mwifiex_adapter *adapter) +{ + struct cmd_ctrl_node *cmd_node = NULL, *tmp_node = NULL; + struct mwifiex_wait_queue *wait_queue = NULL; + unsigned long flags; + + /* Cancel current cmd */ + if ((adapter->curr_cmd) && (adapter->curr_cmd->wq_buf)) { + wait_queue = + (struct mwifiex_wait_queue *) adapter->curr_cmd->wq_buf; + spin_lock_irqsave(&adapter->mwifiex_cmd_lock, flags); + adapter->curr_cmd->wq_buf = NULL; + spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock, flags); + wait_queue->status = MWIFIEX_ERROR_CMD_CANCEL; + mwifiex_ioctl_complete(adapter, wait_queue, -1); + } + /* Cancel all pending command */ + spin_lock_irqsave(&adapter->cmd_pending_q_lock, flags); + list_for_each_entry_safe(cmd_node, tmp_node, + &adapter->cmd_pending_q, list) { + list_del(&cmd_node->list); + spin_unlock_irqrestore(&adapter->cmd_pending_q_lock, flags); + + if (cmd_node->wq_buf) { + wait_queue = + (struct mwifiex_wait_queue *) cmd_node->wq_buf; + wait_queue->status = MWIFIEX_ERROR_CMD_CANCEL; + mwifiex_ioctl_complete(adapter, wait_queue, -1); + cmd_node->wq_buf = NULL; + } + mwifiex_insert_cmd_to_free_q(adapter, cmd_node); + spin_lock_irqsave(&adapter->cmd_pending_q_lock, flags); + } + spin_unlock_irqrestore(&adapter->cmd_pending_q_lock, flags); + + /* Cancel all pending scan command */ + spin_lock_irqsave(&adapter->scan_pending_q_lock, flags); + list_for_each_entry_safe(cmd_node, tmp_node, + &adapter->scan_pending_q, list) { + list_del(&cmd_node->list); + spin_unlock_irqrestore(&adapter->scan_pending_q_lock, flags); + + cmd_node->wq_buf = NULL; + mwifiex_insert_cmd_to_free_q(adapter, cmd_node); + spin_lock_irqsave(&adapter->scan_pending_q_lock, flags); + } + spin_unlock_irqrestore(&adapter->scan_pending_q_lock, flags); + + spin_lock_irqsave(&adapter->mwifiex_cmd_lock, flags); + adapter->scan_processing = false; + spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock, flags); +} + +/* + * This function cancels all pending commands that matches with + * the given IOCTL request. + * + * Both the current command buffer and the pending command queue are + * searched for matching IOCTL request. The completion callback of + * the matched command is called with failure status to ensure cleanup. + * In case of scan commands, all pending commands in scan pending queue + * are cancelled. + */ +void +mwifiex_cancel_pending_ioctl(struct mwifiex_adapter *adapter, + struct mwifiex_wait_queue *wait_queue) +{ + struct cmd_ctrl_node *cmd_node = NULL, *tmp_node = NULL; + unsigned long cmd_flags; + unsigned long cmd_pending_q_flags; + unsigned long scan_pending_q_flags; + uint16_t cancel_scan_cmd = false; + + if ((adapter->curr_cmd) && + (adapter->curr_cmd->wq_buf == wait_queue)) { + spin_lock_irqsave(&adapter->mwifiex_cmd_lock, cmd_flags); + cmd_node = adapter->curr_cmd; + cmd_node->wq_buf = NULL; + cmd_node->cmd_flag |= CMD_F_CANCELED; + spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock, cmd_flags); + } + + spin_lock_irqsave(&adapter->mwifiex_cmd_lock, cmd_flags); + while (1) { + cmd_node = mwifiex_get_pending_ioctl_cmd(adapter, wait_queue); + if (!cmd_node) + break; + + spin_lock_irqsave(&adapter->cmd_pending_q_lock, + cmd_pending_q_flags); + list_del(&cmd_node->list); + spin_unlock_irqrestore(&adapter->cmd_pending_q_lock, + cmd_pending_q_flags); + + cmd_node->wq_buf = NULL; + mwifiex_insert_cmd_to_free_q(adapter, cmd_node); + } + spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock, cmd_flags); + /* Cancel all pending scan command */ + spin_lock_irqsave(&adapter->scan_pending_q_lock, + scan_pending_q_flags); + list_for_each_entry_safe(cmd_node, tmp_node, + &adapter->scan_pending_q, list) { + if (cmd_node->wq_buf == wait_queue) { + list_del(&cmd_node->list); + spin_unlock_irqrestore(&adapter->scan_pending_q_lock, + scan_pending_q_flags); + cmd_node->wq_buf = NULL; + mwifiex_insert_cmd_to_free_q(adapter, cmd_node); + spin_lock_irqsave(&adapter->scan_pending_q_lock, + scan_pending_q_flags); + cancel_scan_cmd = true; + } + } + spin_unlock_irqrestore(&adapter->scan_pending_q_lock, + scan_pending_q_flags); + + if (cancel_scan_cmd) { + spin_lock_irqsave(&adapter->mwifiex_cmd_lock, cmd_flags); + adapter->scan_processing = false; + spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock, cmd_flags); + } + wait_queue->status = MWIFIEX_ERROR_CMD_CANCEL; + mwifiex_ioctl_complete(adapter, wait_queue, -1); + + return; +} + +/* + * This function sends the sleep confirm command to firmware, if + * possible. + * + * The sleep confirm command cannot be issued if command response, + * data response or event response is awaiting handling, or if we + * are in the middle of sending a command, or expecting a command + * response. + */ +void +mwifiex_check_ps_cond(struct mwifiex_adapter *adapter) +{ + if (!adapter->cmd_sent && + !adapter->curr_cmd && !IS_CARD_RX_RCVD(adapter)) + mwifiex_dnld_sleep_confirm_cmd(adapter); + else + dev_dbg(adapter->dev, + "cmd: Delay Sleep Confirm (%s%s%s)\n", + (adapter->cmd_sent) ? "D" : "", + (adapter->curr_cmd) ? "C" : "", + (IS_CARD_RX_RCVD(adapter)) ? "R" : ""); +} + +/* + * This function sends a Host Sleep activated event to applications. + * + * This event is generated by the driver, with a blank event body. + */ +void +mwifiex_hs_activated_event(struct mwifiex_private *priv, u8 activated) +{ + if (activated) { + if (priv->adapter->is_hs_configured) { + priv->adapter->hs_activated = true; + dev_dbg(priv->adapter->dev, "event: hs_activated\n"); + priv->adapter->hs_activate_wait_q_woken = true; + wake_up_interruptible( + &priv->adapter->hs_activate_wait_q); + } else { + dev_dbg(priv->adapter->dev, "event: HS not configured\n"); + } + } else { + dev_dbg(priv->adapter->dev, "event: hs_deactivated\n"); + priv->adapter->hs_activated = false; + } +} + +/* + * This function handles the command response of a Host Sleep configuration + * command. + * + * Handling includes changing the header fields into CPU format + * and setting the current host sleep activation status in driver. + * + * In case host sleep status change, the function generates an event to + * notify the applications. + */ +int mwifiex_ret_802_11_hs_cfg(struct mwifiex_private *priv, + struct host_cmd_ds_command *resp) +{ + struct mwifiex_adapter *adapter = priv->adapter; + struct host_cmd_ds_802_11_hs_cfg_enh *phs_cfg = + &resp->params.opt_hs_cfg; + uint32_t conditions = le32_to_cpu(phs_cfg->params.hs_config.conditions); + + if (phs_cfg->action == cpu_to_le16(HS_ACTIVATE)) { + mwifiex_hs_activated_event(priv, true); + return 0; + } else { + dev_dbg(adapter->dev, "cmd: CMD_RESP: HS_CFG cmd reply" + " result=%#x, conditions=0x%x gpio=0x%x gap=0x%x\n", + resp->result, conditions, + phs_cfg->params.hs_config.gpio, + phs_cfg->params.hs_config.gap); + } + if (conditions != HOST_SLEEP_CFG_CANCEL) { + adapter->is_hs_configured = true; + } else { + adapter->is_hs_configured = false; + if (adapter->hs_activated) + mwifiex_hs_activated_event(priv, false); + } + + return 0; +} + +/* + * This function wakes up the adapter and generates a Host Sleep + * cancel event on receiving the power up interrupt. + */ +void +mwifiex_process_hs_config(struct mwifiex_adapter *adapter) +{ + dev_dbg(adapter->dev, "info: %s: auto cancelling host sleep" + " since there is interrupt from the firmware\n", __func__); + + adapter->if_ops.wakeup(adapter); + adapter->hs_activated = false; + adapter->is_hs_configured = false; + mwifiex_hs_activated_event(mwifiex_get_priv(adapter, + MWIFIEX_BSS_ROLE_ANY), false); + return; +} + +/* + * This function handles the command response of a sleep confirm command. + * + * The function sets the card state to SLEEP if the response indicates success. + */ +void +mwifiex_process_sleep_confirm_resp(struct mwifiex_adapter *adapter, + u8 *pbuf, u32 upld_len) +{ + struct host_cmd_ds_command *cmd = (struct host_cmd_ds_command *) pbuf; + struct mwifiex_private *priv = + mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_ANY); + uint16_t result = le16_to_cpu(cmd->result); + uint16_t command = le16_to_cpu(cmd->command); + uint16_t seq_num = le16_to_cpu(cmd->seq_num); + + if (!upld_len) { + dev_err(adapter->dev, "%s: cmd size is 0\n", __func__); + return; + } + + /* Get BSS number and corresponding priv */ + priv = mwifiex_get_priv_by_id(adapter, HostCmd_GET_BSS_NO(seq_num), + HostCmd_GET_BSS_TYPE(seq_num)); + if (!priv) + priv = mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_ANY); + + /* Update sequence number */ + seq_num = HostCmd_GET_SEQ_NO(seq_num); + /* Clear RET_BIT from HostCmd */ + command &= HostCmd_CMD_ID_MASK; + + if (command != HostCmd_CMD_802_11_PS_MODE_ENH) { + dev_err(adapter->dev, "%s: received unexpected response for" + " cmd %x, result = %x\n", __func__, command, result); + return; + } + + if (result) { + dev_err(adapter->dev, "%s: sleep confirm cmd failed\n", + __func__); + adapter->pm_wakeup_card_req = false; + adapter->ps_state = PS_STATE_AWAKE; + return; + } + adapter->pm_wakeup_card_req = true; + if (adapter->is_hs_configured) + mwifiex_hs_activated_event(mwifiex_get_priv(adapter, + MWIFIEX_BSS_ROLE_ANY), true); + adapter->ps_state = PS_STATE_SLEEP; + cmd->command = cpu_to_le16(command); + cmd->seq_num = cpu_to_le16(seq_num); +} +EXPORT_SYMBOL_GPL(mwifiex_process_sleep_confirm_resp); + +/* + * This function prepares an enhanced power mode command. + * + * This function can be used to disable power save or to configure + * power save with auto PS or STA PS or auto deep sleep. + * + * Preparation includes - + * - Setting command ID, action and proper size + * - Setting Power Save bitmap, PS parameters TLV, PS mode TLV, + * auto deep sleep TLV (as required) + * - Ensuring correct endian-ness + */ +int mwifiex_cmd_enh_power_mode(struct mwifiex_private *priv, + struct host_cmd_ds_command *cmd, + u16 cmd_action, uint16_t ps_bitmap, + void *data_buf) +{ + struct host_cmd_ds_802_11_ps_mode_enh *psmode_enh = + &cmd->params.psmode_enh; + u8 *tlv = NULL; + u16 cmd_size = 0; + + cmd->command = cpu_to_le16(HostCmd_CMD_802_11_PS_MODE_ENH); + if (cmd_action == DIS_AUTO_PS) { + psmode_enh->action = cpu_to_le16(DIS_AUTO_PS); + psmode_enh->params.ps_bitmap = cpu_to_le16(ps_bitmap); + cmd->size = cpu_to_le16(S_DS_GEN + AUTO_PS_FIX_SIZE); + } else if (cmd_action == GET_PS) { + psmode_enh->action = cpu_to_le16(GET_PS); + psmode_enh->params.ps_bitmap = cpu_to_le16(ps_bitmap); + cmd->size = cpu_to_le16(S_DS_GEN + AUTO_PS_FIX_SIZE); + } else if (cmd_action == EN_AUTO_PS) { + psmode_enh->action = cpu_to_le16(EN_AUTO_PS); + psmode_enh->params.auto_ps.ps_bitmap = cpu_to_le16(ps_bitmap); + cmd_size = S_DS_GEN + AUTO_PS_FIX_SIZE; + tlv = (u8 *) cmd + cmd_size; + if (ps_bitmap & BITMAP_STA_PS) { + struct mwifiex_adapter *adapter = priv->adapter; + struct mwifiex_ie_types_ps_param *ps_tlv = + (struct mwifiex_ie_types_ps_param *) tlv; + struct mwifiex_ps_param *ps_mode = &ps_tlv->param; + ps_tlv->header.type = cpu_to_le16(TLV_TYPE_PS_PARAM); + ps_tlv->header.len = cpu_to_le16(sizeof(*ps_tlv) - + sizeof(struct mwifiex_ie_types_header)); + cmd_size += sizeof(*ps_tlv); + tlv += sizeof(*ps_tlv); + dev_dbg(adapter->dev, "cmd: PS Command: Enter PS\n"); + ps_mode->null_pkt_interval = + cpu_to_le16(adapter->null_pkt_interval); + ps_mode->multiple_dtims = + cpu_to_le16(adapter->multiple_dtim); + ps_mode->bcn_miss_timeout = + cpu_to_le16(adapter->bcn_miss_time_out); + ps_mode->local_listen_interval = + cpu_to_le16(adapter->local_listen_interval); + ps_mode->adhoc_wake_period = + cpu_to_le16(adapter->adhoc_awake_period); + ps_mode->delay_to_ps = + cpu_to_le16(adapter->delay_to_ps); + ps_mode->mode = + cpu_to_le16(adapter->enhanced_ps_mode); + + } + if (ps_bitmap & BITMAP_AUTO_DS) { + struct mwifiex_ie_types_auto_ds_param *auto_ps_tlv = + (struct mwifiex_ie_types_auto_ds_param *) tlv; + struct mwifiex_auto_ds_param *auto_ds = + &auto_ps_tlv->param; + u16 idletime = 0; + auto_ps_tlv->header.type = + cpu_to_le16(TLV_TYPE_AUTO_DS_PARAM); + auto_ps_tlv->header.len = + cpu_to_le16(sizeof(*auto_ps_tlv) - + sizeof(struct mwifiex_ie_types_header)); + cmd_size += sizeof(*auto_ps_tlv); + tlv += sizeof(*auto_ps_tlv); + if (data_buf) + idletime = ((struct mwifiex_ds_auto_ds *) + data_buf)->idle_time; + dev_dbg(priv->adapter->dev, + "cmd: PS Command: Enter Auto Deep Sleep\n"); + auto_ds->deep_sleep_timeout = cpu_to_le16(idletime); + } + cmd->size = cpu_to_le16(cmd_size); + } + return 0; +} + +/* + * This function handles the command response of an enhanced power mode + * command. + * + * Handling includes changing the header fields into CPU format + * and setting the current enhanced power mode in driver. + */ +int mwifiex_ret_enh_power_mode(struct mwifiex_private *priv, + struct host_cmd_ds_command *resp, + void *data_buf) +{ + struct mwifiex_adapter *adapter = priv->adapter; + struct host_cmd_ds_802_11_ps_mode_enh *ps_mode = + &resp->params.psmode_enh; + uint16_t action = le16_to_cpu(ps_mode->action); + uint16_t ps_bitmap = le16_to_cpu(ps_mode->params.ps_bitmap); + uint16_t auto_ps_bitmap = + le16_to_cpu(ps_mode->params.auto_ps.ps_bitmap); + + dev_dbg(adapter->dev, "info: %s: PS_MODE cmd reply result=%#x action=%#X\n", + __func__, resp->result, action); + if (action == EN_AUTO_PS) { + if (auto_ps_bitmap & BITMAP_AUTO_DS) { + dev_dbg(adapter->dev, "cmd: Enabled auto deep sleep\n"); + priv->adapter->is_deep_sleep = true; + } + if (auto_ps_bitmap & BITMAP_STA_PS) { + dev_dbg(adapter->dev, "cmd: Enabled STA power save\n"); + if (adapter->sleep_period.period) + dev_dbg(adapter->dev, "cmd: set to uapsd/pps mode\n"); + } + } else if (action == DIS_AUTO_PS) { + if (ps_bitmap & BITMAP_AUTO_DS) { + priv->adapter->is_deep_sleep = false; + dev_dbg(adapter->dev, "cmd: Disabled auto deep sleep\n"); + } + if (ps_bitmap & BITMAP_STA_PS) { + dev_dbg(adapter->dev, "cmd: Disabled STA power save\n"); + if (adapter->sleep_period.period) { + adapter->delay_null_pkt = false; + adapter->tx_lock_flag = false; + adapter->pps_uapsd_mode = false; + } + } + } else if (action == GET_PS) { + if (ps_bitmap & (BITMAP_STA_PS | BITMAP_UAP_INACT_PS + | BITMAP_UAP_DTIM_PS)) + adapter->ps_mode = MWIFIEX_802_11_POWER_MODE_PSP; + else + adapter->ps_mode = MWIFIEX_802_11_POWER_MODE_CAM; + + dev_dbg(adapter->dev, "cmd: ps_bitmap=%#x\n", ps_bitmap); + + if (data_buf) { + /* This section is for get power save mode */ + struct mwifiex_ds_pm_cfg *pm_cfg = + (struct mwifiex_ds_pm_cfg *)data_buf; + if (ps_bitmap & BITMAP_STA_PS) + pm_cfg->param.ps_mode = 1; + else + pm_cfg->param.ps_mode = 0; + } + } + return 0; +} + +/* + * This function prepares command to get hardware specifications. + * + * Preparation includes - + * - Setting command ID, action and proper size + * - Setting permanent address parameter + * - Ensuring correct endian-ness + */ +int mwifiex_cmd_get_hw_spec(struct mwifiex_private *priv, + struct host_cmd_ds_command *cmd) +{ + struct host_cmd_ds_get_hw_spec *hw_spec = &cmd->params.hw_spec; + + cmd->command = cpu_to_le16(HostCmd_CMD_GET_HW_SPEC); + cmd->size = + cpu_to_le16(sizeof(struct host_cmd_ds_get_hw_spec) + S_DS_GEN); + memcpy(hw_spec->permanent_addr, priv->curr_addr, ETH_ALEN); + + return 0; +} + +/* + * This function handles the command response of get hardware + * specifications. + * + * Handling includes changing the header fields into CPU format + * and saving/updating the following parameters in driver - + * - Firmware capability information + * - Firmware band settings + * - Ad-hoc start band and channel + * - Ad-hoc 11n activation status + * - Firmware release number + * - Number of antennas + * - Hardware address + * - Hardware interface version + * - Firmware version + * - Region code + * - 11n capabilities + * - MCS support fields + * - MP end port + */ +int mwifiex_ret_get_hw_spec(struct mwifiex_private *priv, + struct host_cmd_ds_command *resp) +{ + struct host_cmd_ds_get_hw_spec *hw_spec = &resp->params.hw_spec; + struct mwifiex_adapter *adapter = priv->adapter; + int i; + + adapter->fw_cap_info = le32_to_cpu(hw_spec->fw_cap_info); + + if (IS_SUPPORT_MULTI_BANDS(adapter)) + adapter->fw_bands = (u8) GET_FW_DEFAULT_BANDS(adapter); + else + adapter->fw_bands = BAND_B; + + adapter->config_bands = adapter->fw_bands; + + if (adapter->fw_bands & BAND_A) { + if (adapter->fw_bands & BAND_GN) { + adapter->config_bands |= BAND_AN; + adapter->fw_bands |= BAND_AN; + } + if (adapter->fw_bands & BAND_AN) { + adapter->adhoc_start_band = BAND_A | BAND_AN; + adapter->adhoc_11n_enabled = true; + } else { + adapter->adhoc_start_band = BAND_A; + } + priv->adhoc_channel = DEFAULT_AD_HOC_CHANNEL_A; + } else if (adapter->fw_bands & BAND_GN) { + adapter->adhoc_start_band = BAND_G | BAND_B | BAND_GN; + priv->adhoc_channel = DEFAULT_AD_HOC_CHANNEL; + adapter->adhoc_11n_enabled = true; + } else if (adapter->fw_bands & BAND_G) { + adapter->adhoc_start_band = BAND_G | BAND_B; + priv->adhoc_channel = DEFAULT_AD_HOC_CHANNEL; + } else if (adapter->fw_bands & BAND_B) { + adapter->adhoc_start_band = BAND_B; + priv->adhoc_channel = DEFAULT_AD_HOC_CHANNEL; + } + + adapter->fw_release_number = le32_to_cpu(hw_spec->fw_release_number); + adapter->number_of_antenna = le16_to_cpu(hw_spec->number_of_antenna); + + dev_dbg(adapter->dev, "info: GET_HW_SPEC: fw_release_number- %#x\n", + adapter->fw_release_number); + dev_dbg(adapter->dev, "info: GET_HW_SPEC: permanent addr: %pM\n", + hw_spec->permanent_addr); + dev_dbg(adapter->dev, "info: GET_HW_SPEC: hw_if_version=%#x version=%#x\n", + le16_to_cpu(hw_spec->hw_if_version), + le16_to_cpu(hw_spec->version)); + + if (priv->curr_addr[0] == 0xff) + memmove(priv->curr_addr, hw_spec->permanent_addr, ETH_ALEN); + + adapter->region_code = le16_to_cpu(hw_spec->region_code); + + for (i = 0; i < MWIFIEX_MAX_REGION_CODE; i++) + /* Use the region code to search for the index */ + if (adapter->region_code == region_code_index[i]) + break; + + /* If it's unidentified region code, use the default (USA) */ + if (i >= MWIFIEX_MAX_REGION_CODE) { + adapter->region_code = 0x10; + dev_dbg(adapter->dev, "cmd: unknown region code, use default (USA)\n"); + } + + adapter->hw_dot_11n_dev_cap = le32_to_cpu(hw_spec->dot_11n_dev_cap); + adapter->usr_dot_11n_dev_cap = adapter->hw_dot_11n_dev_cap & + DEFAULT_11N_CAP_MASK; + adapter->hw_dev_mcs_support = hw_spec->dev_mcs_support; + adapter->usr_dev_mcs_support = adapter->hw_dev_mcs_support; + mwifiex_show_dot_11n_dev_cap(adapter, adapter->hw_dot_11n_dev_cap); + mwifiex_show_dev_mcs_support(adapter, adapter->hw_dev_mcs_support); + + if (adapter->if_ops.update_mp_end_port) + adapter->if_ops.update_mp_end_port(adapter, + le16_to_cpu(hw_spec->mp_end_port)); + + return 0; +} diff --git a/drivers/net/wireless/mwifiex/debugfs.c b/drivers/net/wireless/mwifiex/debugfs.c new file mode 100644 index 0000000..63b0969 --- /dev/null +++ b/drivers/net/wireless/mwifiex/debugfs.c @@ -0,0 +1,773 @@ +/* + * Marvell Wireless LAN device driver: debugfs + * + * Copyright (C) 2011, Marvell International Ltd. + * + * This software file (the "File") is distributed by Marvell International + * Ltd. under the terms of the GNU General Public License Version 2, June 1991 + * (the "License"). You may use, redistribute and/or modify this File in + * accordance with the terms and conditions of the License, a copy of which + * is available by writing to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the + * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. + * + * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE + * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE + * ARE EXPRESSLY DISCLAIMED. The License provides additional details about + * this warranty disclaimer. + */ + +#include + +#include "main.h" +#include "11n.h" + + +static struct dentry *mwifiex_dfs_dir; + +static char *bss_modes[] = { + "Unknown", + "Managed", + "Ad-hoc", + "Auto" +}; + +/* size/addr for mwifiex_debug_info */ +#define item_size(n) (FIELD_SIZEOF(struct mwifiex_debug_info, n)) +#define item_addr(n) (offsetof(struct mwifiex_debug_info, n)) + +/* size/addr for struct mwifiex_adapter */ +#define adapter_item_size(n) (FIELD_SIZEOF(struct mwifiex_adapter, n)) +#define adapter_item_addr(n) (offsetof(struct mwifiex_adapter, n)) + +struct mwifiex_debug_data { + char name[32]; /* variable/array name */ + u32 size; /* size of the variable/array */ + size_t addr; /* address of the variable/array */ + int num; /* number of variables in an array */ +}; + +static struct mwifiex_debug_data items[] = { + {"int_counter", item_size(int_counter), + item_addr(int_counter), 1}, + {"wmm_ac_vo", item_size(packets_out[WMM_AC_VO]), + item_addr(packets_out[WMM_AC_VO]), 1}, + {"wmm_ac_vi", item_size(packets_out[WMM_AC_VI]), + item_addr(packets_out[WMM_AC_VI]), 1}, + {"wmm_ac_be", item_size(packets_out[WMM_AC_BE]), + item_addr(packets_out[WMM_AC_BE]), 1}, + {"wmm_ac_bk", item_size(packets_out[WMM_AC_BK]), + item_addr(packets_out[WMM_AC_BK]), 1}, + {"max_tx_buf_size", item_size(max_tx_buf_size), + item_addr(max_tx_buf_size), 1}, + {"tx_buf_size", item_size(tx_buf_size), + item_addr(tx_buf_size), 1}, + {"curr_tx_buf_size", item_size(curr_tx_buf_size), + item_addr(curr_tx_buf_size), 1}, + {"ps_mode", item_size(ps_mode), + item_addr(ps_mode), 1}, + {"ps_state", item_size(ps_state), + item_addr(ps_state), 1}, + {"is_deep_sleep", item_size(is_deep_sleep), + item_addr(is_deep_sleep), 1}, + {"wakeup_dev_req", item_size(pm_wakeup_card_req), + item_addr(pm_wakeup_card_req), 1}, + {"wakeup_tries", item_size(pm_wakeup_fw_try), + item_addr(pm_wakeup_fw_try), 1}, + {"hs_configured", item_size(is_hs_configured), + item_addr(is_hs_configured), 1}, + {"hs_activated", item_size(hs_activated), + item_addr(hs_activated), 1}, + {"num_tx_timeout", item_size(num_tx_timeout), + item_addr(num_tx_timeout), 1}, + {"num_cmd_timeout", item_size(num_cmd_timeout), + item_addr(num_cmd_timeout), 1}, + {"timeout_cmd_id", item_size(timeout_cmd_id), + item_addr(timeout_cmd_id), 1}, + {"timeout_cmd_act", item_size(timeout_cmd_act), + item_addr(timeout_cmd_act), 1}, + {"last_cmd_id", item_size(last_cmd_id), + item_addr(last_cmd_id), DBG_CMD_NUM}, + {"last_cmd_act", item_size(last_cmd_act), + item_addr(last_cmd_act), DBG_CMD_NUM}, + {"last_cmd_index", item_size(last_cmd_index), + item_addr(last_cmd_index), 1}, + {"last_cmd_resp_id", item_size(last_cmd_resp_id), + item_addr(last_cmd_resp_id), DBG_CMD_NUM}, + {"last_cmd_resp_index", item_size(last_cmd_resp_index), + item_addr(last_cmd_resp_index), 1}, + {"last_event", item_size(last_event), + item_addr(last_event), DBG_CMD_NUM}, + {"last_event_index", item_size(last_event_index), + item_addr(last_event_index), 1}, + {"num_cmd_h2c_fail", item_size(num_cmd_host_to_card_failure), + item_addr(num_cmd_host_to_card_failure), 1}, + {"num_cmd_sleep_cfm_fail", + item_size(num_cmd_sleep_cfm_host_to_card_failure), + item_addr(num_cmd_sleep_cfm_host_to_card_failure), 1}, + {"num_tx_h2c_fail", item_size(num_tx_host_to_card_failure), + item_addr(num_tx_host_to_card_failure), 1}, + {"num_evt_deauth", item_size(num_event_deauth), + item_addr(num_event_deauth), 1}, + {"num_evt_disassoc", item_size(num_event_disassoc), + item_addr(num_event_disassoc), 1}, + {"num_evt_link_lost", item_size(num_event_link_lost), + item_addr(num_event_link_lost), 1}, + {"num_cmd_deauth", item_size(num_cmd_deauth), + item_addr(num_cmd_deauth), 1}, + {"num_cmd_assoc_ok", item_size(num_cmd_assoc_success), + item_addr(num_cmd_assoc_success), 1}, + {"num_cmd_assoc_fail", item_size(num_cmd_assoc_failure), + item_addr(num_cmd_assoc_failure), 1}, + {"cmd_sent", item_size(cmd_sent), + item_addr(cmd_sent), 1}, + {"data_sent", item_size(data_sent), + item_addr(data_sent), 1}, + {"cmd_resp_received", item_size(cmd_resp_received), + item_addr(cmd_resp_received), 1}, + {"event_received", item_size(event_received), + item_addr(event_received), 1}, + + /* variables defined in struct mwifiex_adapter */ + {"ioctl_pending", adapter_item_size(ioctl_pending), + adapter_item_addr(ioctl_pending), 1}, + {"tx_pending", adapter_item_size(tx_pending), + adapter_item_addr(tx_pending), 1}, + {"rx_pending", adapter_item_size(rx_pending), + adapter_item_addr(rx_pending), 1}, +}; + +static int num_of_items = ARRAY_SIZE(items); + +/* + * Generic proc file open handler. + * + * This function is called every time a file is accessed for read or write. + */ +static int +mwifiex_open_generic(struct inode *inode, struct file *file) +{ + file->private_data = inode->i_private; + return 0; +} + +/* + * Proc info file read handler. + * + * This function is called when the 'info' file is opened for reading. + * It prints the following driver related information - + * - Driver name + * - Driver version + * - Driver extended version + * - Interface name + * - BSS mode + * - Media state (connected or disconnected) + * - MAC address + * - Total number of Tx bytes + * - Total number of Rx bytes + * - Total number of Tx packets + * - Total number of Rx packets + * - Total number of dropped Tx packets + * - Total number of dropped Rx packets + * - Total number of corrupted Tx packets + * - Total number of corrupted Rx packets + * - Carrier status (on or off) + * - Tx queue status (started or stopped) + * + * For STA mode drivers, it also prints the following extra - + * - ESSID + * - BSSID + * - Channel + * - Region code + * - Multicast count + * - Multicast addresses + */ +static ssize_t +mwifiex_info_read(struct file *file, char __user *ubuf, + size_t count, loff_t *ppos) +{ + struct mwifiex_private *priv = + (struct mwifiex_private *) file->private_data; + struct net_device *netdev = priv->netdev; + struct netdev_hw_addr *ha; + unsigned long page = get_zeroed_page(GFP_KERNEL); + char *p = (char *) page, fmt[64]; + struct mwifiex_bss_info info; + ssize_t ret = 0; + int i = 0; + + if (!p) + return -ENOMEM; + + memset(&info, 0, sizeof(info)); + ret = mwifiex_get_bss_info(priv, &info); + if (ret) + goto free_and_exit; + + mwifiex_drv_get_driver_version(priv->adapter, fmt, sizeof(fmt) - 1); + + if (!priv->version_str[0]) + mwifiex_get_ver_ext(priv); + + p += sprintf(p, "driver_name = " "\"mwifiex\"\n"); + p += sprintf(p, "driver_version = %s", fmt); + p += sprintf(p, "\nverext = %s", priv->version_str); + p += sprintf(p, "\ninterface_name=\"%s\"\n", netdev->name); + p += sprintf(p, "bss_mode=\"%s\"\n", bss_modes[info.bss_mode]); + p += sprintf(p, "media_state=\"%s\"\n", + (!priv->media_connected ? "Disconnected" : "Connected")); + p += sprintf(p, "mac_address=\"%02x:%02x:%02x:%02x:%02x:%02x\"\n", + netdev->dev_addr[0], netdev->dev_addr[1], + netdev->dev_addr[2], netdev->dev_addr[3], + netdev->dev_addr[4], netdev->dev_addr[5]); + + if (GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_STA) { + p += sprintf(p, "multicast_count=\"%d\"\n", + netdev_mc_count(netdev)); + p += sprintf(p, "essid=\"%s\"\n", info.ssid.ssid); + p += sprintf(p, "bssid=\"%02x:%02x:%02x:%02x:%02x:%02x\"\n", + info.bssid[0], info.bssid[1], + info.bssid[2], info.bssid[3], + info.bssid[4], info.bssid[5]); + p += sprintf(p, "channel=\"%d\"\n", (int) info.bss_chan); + p += sprintf(p, "region_code = \"%02x\"\n", info.region_code); + + netdev_for_each_mc_addr(ha, netdev) + p += sprintf(p, "multicast_address[%d]=" + "\"%02x:%02x:%02x:%02x:%02x:%02x\"\n", i++, + ha->addr[0], ha->addr[1], + ha->addr[2], ha->addr[3], + ha->addr[4], ha->addr[5]); + } + + p += sprintf(p, "num_tx_bytes = %lu\n", priv->stats.tx_bytes); + p += sprintf(p, "num_rx_bytes = %lu\n", priv->stats.rx_bytes); + p += sprintf(p, "num_tx_pkts = %lu\n", priv->stats.tx_packets); + p += sprintf(p, "num_rx_pkts = %lu\n", priv->stats.rx_packets); + p += sprintf(p, "num_tx_pkts_dropped = %lu\n", priv->stats.tx_dropped); + p += sprintf(p, "num_rx_pkts_dropped = %lu\n", priv->stats.rx_dropped); + p += sprintf(p, "num_tx_pkts_err = %lu\n", priv->stats.tx_errors); + p += sprintf(p, "num_rx_pkts_err = %lu\n", priv->stats.rx_errors); + p += sprintf(p, "carrier %s\n", ((netif_carrier_ok(priv->netdev)) + ? "on" : "off")); + p += sprintf(p, "tx queue %s\n", ((netif_queue_stopped(priv->netdev)) + ? "stopped" : "started")); + + ret = simple_read_from_buffer(ubuf, count, ppos, (char *) page, + (unsigned long) p - page); + +free_and_exit: + free_page(page); + return ret; +} + +/* + * Proc getlog file read handler. + * + * This function is called when the 'getlog' file is opened for reading + * It prints the following log information - + * - Number of multicast Tx frames + * - Number of failed packets + * - Number of Tx retries + * - Number of multicast Tx retries + * - Number of duplicate frames + * - Number of RTS successes + * - Number of RTS failures + * - Number of ACK failures + * - Number of fragmented Rx frames + * - Number of multicast Rx frames + * - Number of FCS errors + * - Number of Tx frames + * - WEP ICV error counts + */ +static ssize_t +mwifiex_getlog_read(struct file *file, char __user *ubuf, + size_t count, loff_t *ppos) +{ + struct mwifiex_private *priv = + (struct mwifiex_private *) file->private_data; + unsigned long page = get_zeroed_page(GFP_KERNEL); + char *p = (char *) page; + ssize_t ret = 0; + struct mwifiex_ds_get_stats stats; + + if (!p) + return -ENOMEM; + + memset(&stats, 0, sizeof(stats)); + ret = mwifiex_get_stats_info(priv, &stats); + if (ret) + goto free_and_exit; + + p += sprintf(p, "\n" + "mcasttxframe %u\n" + "failed %u\n" + "retry %u\n" + "multiretry %u\n" + "framedup %u\n" + "rtssuccess %u\n" + "rtsfailure %u\n" + "ackfailure %u\n" + "rxfrag %u\n" + "mcastrxframe %u\n" + "fcserror %u\n" + "txframe %u\n" + "wepicverrcnt-1 %u\n" + "wepicverrcnt-2 %u\n" + "wepicverrcnt-3 %u\n" + "wepicverrcnt-4 %u\n", + stats.mcast_tx_frame, + stats.failed, + stats.retry, + stats.multi_retry, + stats.frame_dup, + stats.rts_success, + stats.rts_failure, + stats.ack_failure, + stats.rx_frag, + stats.mcast_rx_frame, + stats.fcs_error, + stats.tx_frame, + stats.wep_icv_error[0], + stats.wep_icv_error[1], + stats.wep_icv_error[2], + stats.wep_icv_error[3]); + + + ret = simple_read_from_buffer(ubuf, count, ppos, (char *) page, + (unsigned long) p - page); + +free_and_exit: + free_page(page); + return ret; +} + +static struct mwifiex_debug_info info; + +/* + * Proc debug file read handler. + * + * This function is called when the 'debug' file is opened for reading + * It prints the following log information - + * - Interrupt count + * - WMM AC VO packets count + * - WMM AC VI packets count + * - WMM AC BE packets count + * - WMM AC BK packets count + * - Maximum Tx buffer size + * - Tx buffer size + * - Current Tx buffer size + * - Power Save mode + * - Power Save state + * - Deep Sleep status + * - Device wakeup required status + * - Number of wakeup tries + * - Host Sleep configured status + * - Host Sleep activated status + * - Number of Tx timeouts + * - Number of command timeouts + * - Last timed out command ID + * - Last timed out command action + * - Last command ID + * - Last command action + * - Last command index + * - Last command response ID + * - Last command response index + * - Last event + * - Last event index + * - Number of host to card command failures + * - Number of sleep confirm command failures + * - Number of host to card data failure + * - Number of deauthentication events + * - Number of disassociation events + * - Number of link lost events + * - Number of deauthentication commands + * - Number of association success commands + * - Number of association failure commands + * - Number of commands sent + * - Number of data packets sent + * - Number of command responses received + * - Number of events received + * - Tx BA stream table (TID, RA) + * - Rx reorder table (TID, TA, Start window, Window size, Buffer) + */ +static ssize_t +mwifiex_debug_read(struct file *file, char __user *ubuf, + size_t count, loff_t *ppos) +{ + struct mwifiex_private *priv = + (struct mwifiex_private *) file->private_data; + struct mwifiex_debug_data *d = &items[0]; + unsigned long page = get_zeroed_page(GFP_KERNEL); + char *p = (char *) page; + ssize_t ret = 0; + size_t size, addr; + long val; + int i, j; + + if (!p) + return -ENOMEM; + + ret = mwifiex_get_debug_info(priv, &info); + if (ret) + goto free_and_exit; + + for (i = 0; i < num_of_items; i++) { + p += sprintf(p, "%s=", d[i].name); + + size = d[i].size / d[i].num; + + if (i < (num_of_items - 3)) + addr = d[i].addr + (size_t) &info; + else /* The last 3 items are struct mwifiex_adapter variables */ + addr = d[i].addr + (size_t) priv->adapter; + + for (j = 0; j < d[i].num; j++) { + switch (size) { + case 1: + val = *((u8 *) addr); + break; + case 2: + val = *((u16 *) addr); + break; + case 4: + val = *((u32 *) addr); + break; + case 8: + val = *((long long *) addr); + break; + default: + val = -1; + break; + } + + p += sprintf(p, "%#lx ", val); + addr += size; + } + + p += sprintf(p, "\n"); + } + + if (info.tx_tbl_num) { + p += sprintf(p, "Tx BA stream table:\n"); + for (i = 0; i < info.tx_tbl_num; i++) + p += sprintf(p, "tid = %d, " + "ra = %02x:%02x:%02x:%02x:%02x:%02x\n", + info.tx_tbl[i].tid, info.tx_tbl[i].ra[0], + info.tx_tbl[i].ra[1], info.tx_tbl[i].ra[2], + info.tx_tbl[i].ra[3], info.tx_tbl[i].ra[4], + info.tx_tbl[i].ra[5]); + } + + if (info.rx_tbl_num) { + p += sprintf(p, "Rx reorder table:\n"); + for (i = 0; i < info.rx_tbl_num; i++) { + + p += sprintf(p, "tid = %d, " + "ta = %02x:%02x:%02x:%02x:%02x:%02x, " + "start_win = %d, " + "win_size = %d, buffer: ", + info.rx_tbl[i].tid, + info.rx_tbl[i].ta[0], info.rx_tbl[i].ta[1], + info.rx_tbl[i].ta[2], info.rx_tbl[i].ta[3], + info.rx_tbl[i].ta[4], info.rx_tbl[i].ta[5], + info.rx_tbl[i].start_win, + info.rx_tbl[i].win_size); + + for (j = 0; j < info.rx_tbl[i].win_size; j++) + p += sprintf(p, "%c ", + info.rx_tbl[i].buffer[j] ? + '1' : '0'); + + p += sprintf(p, "\n"); + } + } + + ret = simple_read_from_buffer(ubuf, count, ppos, (char *) page, + (unsigned long) p - page); + +free_and_exit: + free_page(page); + return ret; +} + +static u32 saved_reg_type, saved_reg_offset, saved_reg_value; + +/* + * Proc regrdwr file write handler. + * + * This function is called when the 'regrdwr' file is opened for writing + * + * This function can be used to write to a register. + */ +static ssize_t +mwifiex_regrdwr_write(struct file *file, + const char __user *ubuf, size_t count, loff_t *ppos) +{ + unsigned long addr = get_zeroed_page(GFP_KERNEL); + char *buf = (char *) addr; + size_t buf_size = min(count, (size_t) (PAGE_SIZE - 1)); + int ret = 0; + u32 reg_type = 0, reg_offset = 0, reg_value = UINT_MAX; + + if (!buf) + return -ENOMEM; + + + if (copy_from_user(buf, ubuf, buf_size)) { + ret = -EFAULT; + goto done; + } + + sscanf(buf, "%u %x %x", ®_type, ®_offset, ®_value); + + if (reg_type == 0 || reg_offset == 0) { + ret = -EINVAL; + goto done; + } else { + saved_reg_type = reg_type; + saved_reg_offset = reg_offset; + saved_reg_value = reg_value; + ret = count; + } +done: + free_page(addr); + return ret; +} + +/* + * Proc regrdwr file read handler. + * + * This function is called when the 'regrdwr' file is opened for reading + * + * This function can be used to read from a register. + */ +static ssize_t +mwifiex_regrdwr_read(struct file *file, char __user *ubuf, + size_t count, loff_t *ppos) +{ + struct mwifiex_private *priv = + (struct mwifiex_private *) file->private_data; + unsigned long addr = get_zeroed_page(GFP_KERNEL); + char *buf = (char *) addr; + int pos = 0, ret = 0; + u32 reg_value; + + if (!buf) + return -ENOMEM; + + if (!saved_reg_type) { + /* No command has been given */ + pos += snprintf(buf, PAGE_SIZE, "0"); + goto done; + } + /* Set command has been given */ + if (saved_reg_value != UINT_MAX) { + ret = mwifiex_reg_write(priv, saved_reg_type, saved_reg_offset, + saved_reg_value); + + pos += snprintf(buf, PAGE_SIZE, "%u 0x%x 0x%x\n", + saved_reg_type, saved_reg_offset, + saved_reg_value); + + ret = simple_read_from_buffer(ubuf, count, ppos, buf, pos); + + goto done; + } + /* Get command has been given */ + ret = mwifiex_reg_read(priv, saved_reg_type, + saved_reg_offset, ®_value); + if (ret) { + ret = -EINVAL; + goto done; + } + + pos += snprintf(buf, PAGE_SIZE, "%u 0x%x 0x%x\n", saved_reg_type, + saved_reg_offset, reg_value); + + ret = simple_read_from_buffer(ubuf, count, ppos, buf, pos); + +done: + free_page(addr); + return ret; +} + +static u32 saved_offset = -1, saved_bytes = -1; + +/* + * Proc rdeeprom file write handler. + * + * This function is called when the 'rdeeprom' file is opened for writing + * + * This function can be used to write to a RDEEPROM location. + */ +static ssize_t +mwifiex_rdeeprom_write(struct file *file, + const char __user *ubuf, size_t count, loff_t *ppos) +{ + unsigned long addr = get_zeroed_page(GFP_KERNEL); + char *buf = (char *) addr; + size_t buf_size = min(count, (size_t) (PAGE_SIZE - 1)); + int ret = 0; + int offset = -1, bytes = -1; + + if (!buf) + return -ENOMEM; + + + if (copy_from_user(buf, ubuf, buf_size)) { + ret = -EFAULT; + goto done; + } + + sscanf(buf, "%d %d", &offset, &bytes); + + if (offset == -1 || bytes == -1) { + ret = -EINVAL; + goto done; + } else { + saved_offset = offset; + saved_bytes = bytes; + ret = count; + } +done: + free_page(addr); + return ret; +} + +/* + * Proc rdeeprom read write handler. + * + * This function is called when the 'rdeeprom' file is opened for reading + * + * This function can be used to read from a RDEEPROM location. + */ +static ssize_t +mwifiex_rdeeprom_read(struct file *file, char __user *ubuf, + size_t count, loff_t *ppos) +{ + struct mwifiex_private *priv = + (struct mwifiex_private *) file->private_data; + unsigned long addr = get_zeroed_page(GFP_KERNEL); + char *buf = (char *) addr; + int pos = 0, ret = 0, i = 0; + u8 value[MAX_EEPROM_DATA]; + + if (!buf) + return -ENOMEM; + + if (saved_offset == -1) { + /* No command has been given */ + pos += snprintf(buf, PAGE_SIZE, "0"); + goto done; + } + + /* Get command has been given */ + ret = mwifiex_eeprom_read(priv, (u16) saved_offset, + (u16) saved_bytes, value); + if (ret) { + ret = -EINVAL; + goto done; + } + + pos += snprintf(buf, PAGE_SIZE, "%d %d ", saved_offset, saved_bytes); + + for (i = 0; i < saved_bytes; i++) + pos += snprintf(buf + strlen(buf), PAGE_SIZE, "%d ", value[i]); + + ret = simple_read_from_buffer(ubuf, count, ppos, buf, pos); + +done: + free_page(addr); + return ret; +} + + +#define MWIFIEX_DFS_ADD_FILE(name) do { \ + if (!debugfs_create_file(#name, 0644, priv->dfs_dev_dir, \ + priv, &mwifiex_dfs_##name##_fops)) \ + return; \ +} while (0); + +#define MWIFIEX_DFS_FILE_OPS(name) \ +static const struct file_operations mwifiex_dfs_##name##_fops = { \ + .read = mwifiex_##name##_read, \ + .write = mwifiex_##name##_write, \ + .open = mwifiex_open_generic, \ +}; + +#define MWIFIEX_DFS_FILE_READ_OPS(name) \ +static const struct file_operations mwifiex_dfs_##name##_fops = { \ + .read = mwifiex_##name##_read, \ + .open = mwifiex_open_generic, \ +}; + +#define MWIFIEX_DFS_FILE_WRITE_OPS(name) \ +static const struct file_operations mwifiex_dfs_##name##_fops = { \ + .write = mwifiex_##name##_write, \ + .open = mwifiex_open_generic, \ +}; + + +MWIFIEX_DFS_FILE_READ_OPS(info); +MWIFIEX_DFS_FILE_READ_OPS(debug); +MWIFIEX_DFS_FILE_READ_OPS(getlog); +MWIFIEX_DFS_FILE_OPS(regrdwr); +MWIFIEX_DFS_FILE_OPS(rdeeprom); + +/* + * This function creates the debug FS directory structure and the files. + */ +void +mwifiex_dev_debugfs_init(struct mwifiex_private *priv) +{ + if (!mwifiex_dfs_dir || !priv) + return; + + priv->dfs_dev_dir = debugfs_create_dir(priv->netdev->name, + mwifiex_dfs_dir); + + if (!priv->dfs_dev_dir) + return; + + MWIFIEX_DFS_ADD_FILE(info); + MWIFIEX_DFS_ADD_FILE(debug); + MWIFIEX_DFS_ADD_FILE(getlog); + MWIFIEX_DFS_ADD_FILE(regrdwr); + MWIFIEX_DFS_ADD_FILE(rdeeprom); + + return; +} + +/* + * This function removes the debug FS directory structure and the files. + */ +void +mwifiex_dev_debugfs_remove(struct mwifiex_private *priv) +{ + if (!priv) + return; + + debugfs_remove_recursive(priv->dfs_dev_dir); + return; +} + +/* + * This function creates the top level proc directory. + */ +void +mwifiex_debugfs_init(void) +{ + if (!mwifiex_dfs_dir) + mwifiex_dfs_dir = debugfs_create_dir("mwifiex", NULL); +} + +/* + * This function removes the top level proc directory. + */ +void +mwifiex_debugfs_remove(void) +{ + if (mwifiex_dfs_dir) + debugfs_remove(mwifiex_dfs_dir); +} diff --git a/drivers/net/wireless/mwifiex/decl.h b/drivers/net/wireless/mwifiex/decl.h new file mode 100644 index 0000000..4e1f115 --- /dev/null +++ b/drivers/net/wireless/mwifiex/decl.h @@ -0,0 +1,177 @@ +/* + * Marvell Wireless LAN device driver: generic data structures and APIs + * + * Copyright (C) 2011, Marvell International Ltd. + * + * This software file (the "File") is distributed by Marvell International + * Ltd. under the terms of the GNU General Public License Version 2, June 1991 + * (the "License"). You may use, redistribute and/or modify this File in + * accordance with the terms and conditions of the License, a copy of which + * is available by writing to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the + * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. + * + * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE + * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE + * ARE EXPRESSLY DISCLAIMED. The License provides additional details about + * this warranty disclaimer. + */ + +#ifndef _MWIFIEX_DECL_H_ +#define _MWIFIEX_DECL_H_ + +#undef pr_fmt +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#include +#include +#include + + +#define MWIFIEX_MAX_BSS_NUM (1) + +#define MWIFIEX_MIN_DATA_HEADER_LEN 32 /* (sizeof(mwifiex_txpd)) */ + +#define MWIFIEX_MAX_TX_BASTREAM_SUPPORTED 2 +#define MWIFIEX_MAX_RX_BASTREAM_SUPPORTED 16 + +#define MWIFIEX_AMPDU_DEF_TXWINSIZE 32 +#define MWIFIEX_AMPDU_DEF_RXWINSIZE 16 +#define MWIFIEX_DEFAULT_BLOCK_ACK_TIMEOUT 0xffff + +#define MWIFIEX_RATE_INDEX_HRDSSS0 0 +#define MWIFIEX_RATE_INDEX_HRDSSS3 3 +#define MWIFIEX_RATE_INDEX_OFDM0 4 +#define MWIFIEX_RATE_INDEX_OFDM7 11 +#define MWIFIEX_RATE_INDEX_MCS0 12 + +#define MWIFIEX_RATE_BITMAP_OFDM0 16 +#define MWIFIEX_RATE_BITMAP_OFDM7 23 +#define MWIFIEX_RATE_BITMAP_MCS0 32 +#define MWIFIEX_RATE_BITMAP_MCS127 159 + +#define MWIFIEX_RX_DATA_BUF_SIZE (4 * 1024) +#define MWIFIEX_RX_CMD_BUF_SIZE (2 * 1024) + +#define MWIFIEX_RTS_MIN_VALUE (0) +#define MWIFIEX_RTS_MAX_VALUE (2347) +#define MWIFIEX_FRAG_MIN_VALUE (256) +#define MWIFIEX_FRAG_MAX_VALUE (2346) + +#define MWIFIEX_SDIO_BLOCK_SIZE 256 + +#define MWIFIEX_BUF_FLAG_REQUEUED_PKT BIT(0) + +enum mwifiex_error_code { + MWIFIEX_ERROR_NO_ERROR = 0, + MWIFIEX_ERROR_FW_NOT_READY = 0x00000001, + MWIFIEX_ERROR_FW_BUSY, + MWIFIEX_ERROR_FW_CMDRESP, + MWIFIEX_ERROR_PKT_SIZE_INVALID = 0x80000001, + MWIFIEX_ERROR_PKT_TIMEOUT, + MWIFIEX_ERROR_CMD_INVALID, + MWIFIEX_ERROR_CMD_TIMEOUT, + MWIFIEX_ERROR_CMD_DNLD_FAIL, + MWIFIEX_ERROR_CMD_CANCEL, + MWIFIEX_ERROR_CMD_RESP_FAIL, + MWIFIEX_ERROR_ASSOC_FAIL, + MWIFIEX_ERROR_EVENT_UNKNOWN, + MWIFIEX_ERROR_INVALID_PARAMETER, +}; + +enum mwifiex_bss_type { + MWIFIEX_BSS_TYPE_STA = 0, + MWIFIEX_BSS_TYPE_UAP = 1, + MWIFIEX_BSS_TYPE_ANY = 0xff, +}; + +enum mwifiex_bss_role { + MWIFIEX_BSS_ROLE_STA = 0, + MWIFIEX_BSS_ROLE_UAP = 1, + MWIFIEX_BSS_ROLE_ANY = 0xff, +}; + +#define BSS_ROLE_BIT_MASK BIT(0) + +#define GET_BSS_ROLE(priv) ((priv)->bss_role & BSS_ROLE_BIT_MASK) + +enum mwifiex_data_frame_type { + MWIFIEX_DATA_FRAME_TYPE_ETH_II = 0, + MWIFIEX_DATA_FRAME_TYPE_802_11, +}; + +struct mwifiex_fw_image { + u8 *helper_buf; + u32 helper_len; + u8 *fw_buf; + u32 fw_len; +}; + +struct mwifiex_802_11_ssid { + u32 ssid_len; + u8 ssid[IEEE80211_MAX_SSID_LEN]; +}; + +struct mwifiex_wait_queue { + u32 bss_index; + wait_queue_head_t *wait; + u16 *condition; + u32 start_time; + int status; + u32 enabled; +}; + +struct mwifiex_rxinfo { + u8 bss_index; + struct sk_buff *parent; + u8 use_count; +}; + +struct mwifiex_txinfo { + u32 status_code; + u8 flags; + u8 bss_index; +}; + +struct mwifiex_bss_attr { + u32 bss_type; + u32 frame_type; + u32 active; + u32 bss_priority; + u32 bss_num; +}; + +enum mwifiex_cmd_result_e { + MWIFIEX_CMD_RESULT_SUCCESS = 0, + MWIFIEX_CMD_RESULT_FAILURE = 1, + MWIFIEX_CMD_RESULT_TIMEOUT = 2, + MWIFIEX_CMD_RESULT_INVALID_DATA = 3 +} __packed; + +enum mwifiex_wmm_ac_e { + WMM_AC_BK, + WMM_AC_BE, + WMM_AC_VI, + WMM_AC_VO +} __packed; + +enum mwifiex_wmm_queue_config_action_e { + MWIFIEX_WMM_QUEUE_CONFIG_ACTION_GET = 0, + MWIFIEX_WMM_QUEUE_CONFIG_ACTION_SET = 1, + MWIFIEX_WMM_QUEUE_CONFIG_ACTION_DEFAULT = 2, + MWIFIEX_WMM_QUEUE_CONFIG_ACTION_MAX +} __packed; + +enum mwifiex_wmm_queue_stats_action_e { + MWIFIEX_WMM_STATS_ACTION_START = 0, + MWIFIEX_WMM_STATS_ACTION_STOP = 1, + MWIFIEX_WMM_STATS_ACTION_GET_CLR = 2, + MWIFIEX_WMM_STATS_ACTION_SET_CFG = 3, /* Not currently used */ + MWIFIEX_WMM_STATS_ACTION_GET_CFG = 4, /* Not currently used */ + MWIFIEX_WMM_STATS_ACTION_MAX +} __packed; + +struct mwifiex_device { + struct mwifiex_bss_attr bss_attr[MWIFIEX_MAX_BSS_NUM]; +}; +#endif /* !_MWIFIEX_DECL_H_ */ diff --git a/drivers/net/wireless/mwifiex/fw.h b/drivers/net/wireless/mwifiex/fw.h new file mode 100644 index 0000000..e5dae45 --- /dev/null +++ b/drivers/net/wireless/mwifiex/fw.h @@ -0,0 +1,1376 @@ +/* + * Marvell Wireless LAN device driver: Firmware specific macros & structures + * + * Copyright (C) 2011, Marvell International Ltd. + * + * This software file (the "File") is distributed by Marvell International + * Ltd. under the terms of the GNU General Public License Version 2, June 1991 + * (the "License"). You may use, redistribute and/or modify this File in + * accordance with the terms and conditions of the License, a copy of which + * is available by writing to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the + * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. + * + * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE + * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE + * ARE EXPRESSLY DISCLAIMED. The License provides additional details about + * this warranty disclaimer. + */ + +#ifndef _MWIFIEX_FW_H_ +#define _MWIFIEX_FW_H_ + +#include + + +#define INTF_HEADER_LEN 4 + +struct rfc_1042_hdr { + u8 llc_dsap; + u8 llc_ssap; + u8 llc_ctrl; + u8 snap_oui[3]; + u16 snap_type; +}; + +struct rx_packet_hdr { + struct ethhdr eth803_hdr; + struct rfc_1042_hdr rfc1042_hdr; +}; + +struct tx_packet_hdr { + struct ethhdr eth803_hdr; + struct rfc_1042_hdr rfc1042_hdr; +}; + +#define B_SUPPORTED_RATES 5 +#define G_SUPPORTED_RATES 9 +#define BG_SUPPORTED_RATES 13 +#define A_SUPPORTED_RATES 9 +#define HOSTCMD_SUPPORTED_RATES 14 +#define N_SUPPORTED_RATES 3 +#define ALL_802_11_BANDS (BAND_A | BAND_B | BAND_G | BAND_GN) + +#define FW_MULTI_BANDS_SUPPORT (BIT(8) | BIT(9) | BIT(10) | BIT(11)) +#define IS_SUPPORT_MULTI_BANDS(adapter) \ + (adapter->fw_cap_info & FW_MULTI_BANDS_SUPPORT) +#define GET_FW_DEFAULT_BANDS(adapter) \ + ((adapter->fw_cap_info >> 8) & ALL_802_11_BANDS) + +#define SHORT_SLOT_TIME_DISABLED(CapInfo) (CapInfo &= ~BIT(10)) +#define SHORT_SLOT_TIME_ENABLED(CapInfo) (CapInfo |= BIT(10)) + +extern u8 supported_rates_b[B_SUPPORTED_RATES]; +extern u8 supported_rates_g[G_SUPPORTED_RATES]; +extern u8 supported_rates_bg[BG_SUPPORTED_RATES]; +extern u8 supported_rates_a[A_SUPPORTED_RATES]; +extern u8 supported_rates_n[N_SUPPORTED_RATES]; + +#define HostCmd_WEP_KEY_INDEX_MASK 0x3fff + +#define KEY_INFO_ENABLED 0x01 +enum KEY_TYPE_ID { + KEY_TYPE_ID_WEP = 0, + KEY_TYPE_ID_TKIP, + KEY_TYPE_ID_AES, + KEY_TYPE_ID_WAPI, +}; + +enum KEY_INFO_WEP { + KEY_INFO_WEP_MCAST = 0x01, + KEY_INFO_WEP_UNICAST = 0x02, + KEY_INFO_WEP_ENABLED = 0x04 +}; + +enum KEY_INFO_TKIP { + KEY_INFO_TKIP_MCAST = 0x01, + KEY_INFO_TKIP_UNICAST = 0x02, + KEY_INFO_TKIP_ENABLED = 0x04 +}; + +enum KEY_INFO_AES { + KEY_INFO_AES_MCAST = 0x01, + KEY_INFO_AES_UNICAST = 0x02, + KEY_INFO_AES_ENABLED = 0x04 +}; + +#define WAPI_KEY_LEN 50 + +enum KEY_INFO_WAPI { + KEY_INFO_WAPI_MCAST = 0x01, + KEY_INFO_WAPI_UNICAST = 0x02, + KEY_INFO_WAPI_ENABLED = 0x04 +}; + +#define MAX_POLL_TRIES 100 + +#define MAX_MULTI_INTERFACE_POLL_TRIES 1000 + +#define MAX_FIRMWARE_POLL_TRIES 100 + +#define FIRMWARE_READY 0xfedc + +#define FIRMWARE_TRANSFER_NBLOCK 2 + +enum MWIFIEX_802_11_PRIVACY_FILTER { + MWIFIEX_802_11_PRIV_FILTER_ACCEPT_ALL, + MWIFIEX_802_11_PRIV_FILTER_8021X_WEP +}; + +enum MWIFIEX_802_11_WEP_STATUS { + MWIFIEX_802_11_WEP_ENABLED, + MWIFIEX_802_11_WEP_DISABLED, +}; + +#define CAL_SNR(RSSI, NF) ((s16)((s16)(RSSI)-(s16)(NF))) + +#define PROPRIETARY_TLV_BASE_ID 0x0100 +#define TLV_TYPE_KEY_MATERIAL (PROPRIETARY_TLV_BASE_ID + 0) +#define TLV_TYPE_CHANLIST (PROPRIETARY_TLV_BASE_ID + 1) +#define TLV_TYPE_NUMPROBES (PROPRIETARY_TLV_BASE_ID + 2) +#define TLV_TYPE_RSSI_LOW (PROPRIETARY_TLV_BASE_ID + 4) +#define TLV_TYPE_SNR_LOW (PROPRIETARY_TLV_BASE_ID + 5) +#define TLV_TYPE_FAILCOUNT (PROPRIETARY_TLV_BASE_ID + 6) +#define TLV_TYPE_BCNMISS (PROPRIETARY_TLV_BASE_ID + 7) +#define TLV_TYPE_LEDBEHAVIOR (PROPRIETARY_TLV_BASE_ID + 9) +#define TLV_TYPE_PASSTHROUGH (PROPRIETARY_TLV_BASE_ID + 10) +#define TLV_TYPE_POWER_TBL_2_4GHZ (PROPRIETARY_TLV_BASE_ID + 12) +#define TLV_TYPE_POWER_TBL_5GHZ (PROPRIETARY_TLV_BASE_ID + 13) +#define TLV_TYPE_WMMQSTATUS (PROPRIETARY_TLV_BASE_ID + 16) +#define TLV_TYPE_WILDCARDSSID (PROPRIETARY_TLV_BASE_ID + 18) +#define TLV_TYPE_TSFTIMESTAMP (PROPRIETARY_TLV_BASE_ID + 19) +#define TLV_TYPE_RSSI_HIGH (PROPRIETARY_TLV_BASE_ID + 22) +#define TLV_TYPE_SNR_HIGH (PROPRIETARY_TLV_BASE_ID + 23) + +#define TLV_TYPE_STARTBGSCANLATER (PROPRIETARY_TLV_BASE_ID + 30) +#define TLV_TYPE_AUTH_TYPE (PROPRIETARY_TLV_BASE_ID + 31) +#define TLV_TYPE_LINK_QUALITY (PROPRIETARY_TLV_BASE_ID + 36) +#define TLV_TYPE_RSSI_LOW_DATA (PROPRIETARY_TLV_BASE_ID + 38) +#define TLV_TYPE_SNR_LOW_DATA (PROPRIETARY_TLV_BASE_ID + 39) +#define TLV_TYPE_RSSI_HIGH_DATA (PROPRIETARY_TLV_BASE_ID + 40) +#define TLV_TYPE_SNR_HIGH_DATA (PROPRIETARY_TLV_BASE_ID + 41) + +#define TLV_TYPE_CHANNELBANDLIST (PROPRIETARY_TLV_BASE_ID + 42) +#define TLV_TYPE_WAPI_IE (PROPRIETARY_TLV_BASE_ID + 94) +#define TLV_TYPE_BSSID (PROPRIETARY_TLV_BASE_ID + 35) + +#define MWIFIEX_TX_DATA_BUF_SIZE_2K 2048 + +#define TLV_TYPE_HT_CAP (PROPRIETARY_TLV_BASE_ID + 74) +#define TLV_TYPE_HT_INFO (PROPRIETARY_TLV_BASE_ID + 75) +#define TLV_SECONDARY_CHANNEL_OFFSET (PROPRIETARY_TLV_BASE_ID + 76) +#define TLV_TYPE_2040BSS_COEXISTENCE (PROPRIETARY_TLV_BASE_ID + 77) +#define TLV_TYPE_OVERLAP_BSS_SCAN_PARAM (PROPRIETARY_TLV_BASE_ID + 78) +#define TLV_TYPE_EXTCAP (PROPRIETARY_TLV_BASE_ID + 79) +#define TLV_TYPE_HT_OPERATIONAL_MCS_SET (PROPRIETARY_TLV_BASE_ID + 80) + +#define ADDBA_TID_MASK (BIT(2) | BIT(3) | BIT(4) | BIT(5)) +#define DELBA_TID_MASK (BIT(12) | BIT(13) | BIT(14) | BIT(15)) +#define SSN_MASK 0xfff0 + +#define BA_RESULT_SUCCESS 0x0 +#define BA_RESULT_FAILURE 0x1 +#define BA_RESULT_TIMEOUT 0x2 +#define BA_RESULT_DATA_INVALID 0x3 + +#define IS_BASTREAM_SETUP(ptr) (ptr->ba_status) + +#define BA_STREAM_NOT_ALLOWED 0xff + +#define IS_11N_ENABLED(priv) ((priv->adapter->config_bands & BAND_GN || \ + priv->adapter->config_bands & BAND_AN) \ + && priv->curr_bss_params.bss_descriptor.bcn_ht_cap) +#define INITIATOR_BIT(DelBAParamSet) (((DelBAParamSet) &\ + BIT(DELBA_INITIATOR_POS)) >> DELBA_INITIATOR_POS) + +#define MWIFIEX_TX_DATA_BUF_SIZE_4K 4096 +#define MWIFIEX_TX_DATA_BUF_SIZE_8K 8192 +#define MAX_RX_AMPDU_SIZE_64K 0x03 +#define NON_GREENFIELD_STAS 0x04 + +#define HWSPEC_GREENFIELD_SUPP BIT(29) +#define HWSPEC_RXSTBC_SUPP BIT(26) +#define HWSPEC_SHORTGI40_SUPP BIT(24) +#define HWSPEC_SHORTGI20_SUPP BIT(23) +#define HWSPEC_CHANBW40_SUPP BIT(17) + +#define DEFAULT_11N_CAP_MASK (HWSPEC_SHORTGI20_SUPP | HWSPEC_RXSTBC_SUPP) +#define ISSUPP_11NENABLED(FwCapInfo) (FwCapInfo & BIT(11)) +#define ISSUPP_MAXAMSDU(Dot11nDevCap) (Dot11nDevCap & BIT(31)) +#define ISSUPP_BEAMFORMING(Dot11nDevCap) (Dot11nDevCap & BIT(30)) +#define ISSUPP_GREENFIELD(Dot11nDevCap) (Dot11nDevCap & BIT(29)) +#define ISSUPP_AMPDU(Dot11nDevCap) (Dot11nDevCap & BIT(28)) +#define ISSUPP_MIMOPS(Dot11nDevCap) (Dot11nDevCap & BIT(27)) +#define ISSUPP_RXSTBC(Dot11nDevCap) (Dot11nDevCap & BIT(26)) +#define ISSUPP_TXSTBC(Dot11nDevCap) (Dot11nDevCap & BIT(25)) +#define ISSUPP_SHORTGI40(Dot11nDevCap) (Dot11nDevCap & BIT(24)) +#define ISSUPP_SHORTGI20(Dot11nDevCap) (Dot11nDevCap & BIT(23)) +#define ISSUPP_RXLDPC(Dot11nDevCap) (Dot11nDevCap & BIT(22)) +#define GET_DELAYEDBACK(Dot11nDevCap) (((Dot11nDevCap >> 20) & 0x03)) +#define GET_IMMEDIATEBACK(Dot11nDevCap) (((Dot11nDevCap >> 18) & 0x03)) +#define ISSUPP_CHANWIDTH40(Dot11nDevCap) (Dot11nDevCap & BIT(17)) +#define ISSUPP_CHANWIDTH20(Dot11nDevCap) (Dot11nDevCap & BIT(16)) +#define ISSUPP_CHANWIDTH10(Dot11nDevCap) (Dot11nDevCap & BIT(15)) +#define ISENABLED_40MHZ_INTOLARENT(Dot11nDevCap) (Dot11nDevCap & BIT(8)) +#define ISSUPP_RXANTENNAD(Dot11nDevCap) (Dot11nDevCap & BIT(7)) +#define ISSUPP_RXANTENNAC(Dot11nDevCap) (Dot11nDevCap & BIT(6)) +#define ISSUPP_RXANTENNAB(Dot11nDevCap) (Dot11nDevCap & BIT(5)) +#define ISSUPP_RXANTENNAA(Dot11nDevCap) (Dot11nDevCap & BIT(4)) +#define ISSUPP_TXANTENNAD(Dot11nDevCap) (Dot11nDevCap & BIT(3)) +#define ISSUPP_TXANTENNAC(Dot11nDevCap) (Dot11nDevCap & BIT(2)) +#define ISSUPP_TXANTENNAB(Dot11nDevCap) (Dot11nDevCap & BIT(1)) +#define ISSUPP_TXANTENNAA(Dot11nDevCap) (Dot11nDevCap & BIT(0)) +#define SETSUPP_CHANWIDTH40(Dot11nDevCap) (Dot11nDevCap |= BIT(17)) +#define RESETSUPP_CHANWIDTH40(Dot11nDevCap) (Dot11nDevCap &= ~BIT(17)) +#define GET_TXMCSSUPP(DevMCSSupported) (DevMCSSupported >> 4) +#define GET_RXMCSSUPP(DevMCSSupported) (DevMCSSupported & 0x0f) +#define GETHT_SUPPCHANWIDTH(HTCapInfo) (HTCapInfo & BIT(1)) +#define GETHT_GREENFIELD(HTCapInfo) (HTCapInfo & BIT(4)) +#define GETHT_SHORTGI20(HTCapInfo) (HTCapInfo & BIT(5)) +#define GETHT_SHORTGI40(HTCapInfo) (HTCapInfo & BIT(6)) +#define GETHT_TXSTBC(HTCapInfo) (HTCapInfo & BIT(7)) +#define GETHT_RXSTBC(HTCapInfo) ((HTCapInfo >> 8) & 0x03) +#define GETHT_DELAYEDBACK(HTCapInfo) (HTCapInfo & BIT(10)) +#define GETHT_MAXAMSDU(HTCapInfo) (HTCapInfo & BIT(11)) +#define SETHT_SUPPCHANWIDTH(HTCapInfo) (HTCapInfo |= BIT(1)) +#define SETHT_GREENFIELD(HTCapInfo) (HTCapInfo |= BIT(4)) +#define SETHT_SHORTGI20(HTCapInfo) (HTCapInfo |= BIT(5)) +#define SETHT_SHORTGI40(HTCapInfo) (HTCapInfo |= BIT(6)) +#define SETHT_TXSTBC(HTCapInfo) (HTCapInfo |= BIT(7)) +#define SETHT_RXSTBC(HTCapInfo, value) (HTCapInfo |= (value << 8)) +#define SETHT_DELAYEDBACK(HTCapInfo) (HTCapInfo |= BIT(10)) +#define SETHT_MAXAMSDU(HTCapInfo) (HTCapInfo |= BIT(11)) +#define SETHT_DSSSCCK40(HTCapInfo) (HTCapInfo |= BIT(12)) +#define SETHT_40MHZ_INTOLARANT(HTCapInfo) (HTCapInfo |= BIT(14)) +#define RESETHT_SUPPCHANWIDTH(HTCapInfo) (HTCapInfo &= ~BIT(1)) +#define RESETHT_GREENFIELD(HTCapInfo) (HTCapInfo &= ~BIT(4)) +#define RESETHT_SHORTGI20(HTCapInfo) (HTCapInfo &= ~BIT(5)) +#define RESETHT_SHORTGI40(HTCapInfo) (HTCapInfo &= ~BIT(6)) +#define RESETHT_TXSTBC(HTCapInfo) (HTCapInfo &= ~BIT(7)) +#define RESETHT_RXSTBC(HTCapInfo) (HTCapInfo &= ~(0x03 << 8)) +#define RESETHT_DELAYEDBACK(HTCapInfo) (HTCapInfo &= ~BIT(10)) +#define RESETHT_MAXAMSDU(HTCapInfo) (HTCapInfo &= ~BIT(11)) +#define RESETHT_40MHZ_INTOLARANT(HTCapInfo) (HTCapInfo &= ~BIT(14)) +#define RESETHT_EXTCAP_RDG(HTExtCap) (HTExtCap &= ~BIT(11)) +#define SETHT_MCS32(x) (x[4] |= 1) +#define SETHT_MCS_SET_DEFINED(x) (x[12] |= 1) +#define SETHT_RX_HIGHEST_DT_SUPP(x, y) ((*(u16 *) (x + 10)) = y) +#define AMPDU_FACTOR_64K 0x03 +#define SETAMPDU_SIZE(x, y) do { \ + x = x & ~0x03; \ + x |= y & 0x03; \ +} while (0) \ + +#define SETAMPDU_SPACING(x, y) do { \ + x = x & ~0x1c; \ + x |= (y & 0x07) << 2; \ +} while (0) \ + +#define ISSUPP_BANDA(FwCapInfo) (FwCapInfo & BIT(10)) +#define ISALLOWED_CHANWIDTH40(Field2) (Field2 & BIT(2)) +#define SET_CHANWIDTH40(Field2) (Field2 |= BIT(2)) +#define RESET_CHANWIDTH40(Field2) (Field2 &= ~(BIT(0) | BIT(1) | BIT(2))) +#define GET_SECONDARYCHAN(Field2) (Field2 & (BIT(0) | BIT(1))) +#define SET_SECONDARYCHAN(RadioType, SECCHAN) (RadioType |= (SECCHAN << 4)) + +#define LLC_SNAP_LEN 8 + +#define TLV_TYPE_RATE_DROP_PATTERN (PROPRIETARY_TLV_BASE_ID + 81) +#define TLV_TYPE_RATE_DROP_CONTROL (PROPRIETARY_TLV_BASE_ID + 82) +#define TLV_TYPE_RATE_SCOPE (PROPRIETARY_TLV_BASE_ID + 83) + +#define TLV_TYPE_POWER_GROUP (PROPRIETARY_TLV_BASE_ID + 84) + +#define MOD_CLASS_HR_DSSS 0x03 +#define MOD_CLASS_OFDM 0x07 +#define MOD_CLASS_HT 0x08 +#define HT_BW_20 0 +#define HT_BW_40 1 + +#define HostCmd_CMD_GET_HW_SPEC 0x0003 +#define HostCmd_CMD_802_11_SCAN 0x0006 +#define HostCmd_CMD_802_11_GET_LOG 0x000b +#define HostCmd_CMD_MAC_MULTICAST_ADR 0x0010 +#define HostCmd_CMD_802_11_EEPROM_ACCESS 0x0059 +#define HostCmd_CMD_802_11_ASSOCIATE 0x0012 +#define HostCmd_CMD_802_11_SNMP_MIB 0x0016 +#define HostCmd_CMD_MAC_REG_ACCESS 0x0019 +#define HostCmd_CMD_BBP_REG_ACCESS 0x001a +#define HostCmd_CMD_RF_REG_ACCESS 0x001b +#define HostCmd_CMD_PMIC_REG_ACCESS 0x00ad +#define HostCmd_CMD_802_11_RF_CHANNEL 0x001d +#define HostCmd_CMD_802_11_DEAUTHENTICATE 0x0024 +#define HostCmd_CMD_MAC_CONTROL 0x0028 +#define HostCmd_CMD_802_11_AD_HOC_START 0x002b +#define HostCmd_CMD_802_11_AD_HOC_JOIN 0x002c +#define HostCmd_CMD_802_11_AD_HOC_STOP 0x0040 +#define HostCmd_CMD_802_11_MAC_ADDRESS 0x004D +#define HostCmd_CMD_802_11D_DOMAIN_INFO 0x005b +#define HostCmd_CMD_802_11_KEY_MATERIAL 0x005e +#define HostCmd_CMD_802_11_BG_SCAN_QUERY 0x006c +#define HostCmd_CMD_WMM_GET_STATUS 0x0071 +#define HostCmd_CMD_802_11_TX_RATE_QUERY 0x007f +#define HostCmd_CMD_802_11_IBSS_COALESCING_STATUS 0x0083 +#define HostCmd_CMD_VERSION_EXT 0x0097 +#define HostCmd_CMD_RSSI_INFO 0x00a4 +#define HostCmd_CMD_FUNC_INIT 0x00a9 +#define HostCmd_CMD_FUNC_SHUTDOWN 0x00aa +#define HostCmd_CMD_11N_CFG 0x00cd +#define HostCmd_CMD_11N_ADDBA_REQ 0x00ce +#define HostCmd_CMD_11N_ADDBA_RSP 0x00cf +#define HostCmd_CMD_11N_DELBA 0x00d0 +#define HostCmd_CMD_RECONFIGURE_TX_BUFF 0x00d9 +#define HostCmd_CMD_AMSDU_AGGR_CTRL 0x00df +#define HostCmd_CMD_TXPWR_CFG 0x00d1 +#define HostCmd_CMD_TX_RATE_CFG 0x00d6 +#define HostCmd_CMD_802_11_PS_MODE_ENH 0x00e4 +#define HostCmd_CMD_802_11_HS_CFG_ENH 0x00e5 +#define HostCmd_CMD_CAU_REG_ACCESS 0x00ed +#define HostCmd_CMD_SET_BSS_MODE 0x00f7 + + +enum ENH_PS_MODES { + EN_PS = 1, + DIS_PS = 2, + EN_AUTO_DS = 3, + DIS_AUTO_DS = 4, + SLEEP_CONFIRM = 5, + GET_PS = 0, + EN_AUTO_PS = 0xff, + DIS_AUTO_PS = 0xfe, +}; + +#define HostCmd_RET_BIT 0x8000 +#define HostCmd_ACT_GEN_GET 0x0000 +#define HostCmd_ACT_GEN_SET 0x0001 +#define HostCmd_ACT_GEN_REMOVE 0x0004 +#define HostCmd_ACT_SET_BOTH 0x0003 +#define HostCmd_ACT_GET_BOTH 0x000c +#define HostCmd_RESULT_OK 0x0000 +#define HostCmd_RESULT_ERROR 0x0001 +#define HostCmd_RESULT_NOT_SUPPORT 0x0002 +#define HostCmd_RESULT_PENDING 0x0003 +#define HostCmd_RESULT_BUSY 0x0004 +#define HostCmd_RESULT_PARTIAL_DATA 0x0005 + +#define HostCmd_ACT_MAC_RX_ON 0x0001 +#define HostCmd_ACT_MAC_TX_ON 0x0002 +#define HostCmd_ACT_MAC_WEP_ENABLE 0x0008 +#define HostCmd_ACT_MAC_ETHERNETII_ENABLE 0x0010 +#define HostCmd_ACT_MAC_PROMISCUOUS_ENABLE 0x0080 +#define HostCmd_ACT_MAC_ALL_MULTICAST_ENABLE 0x0100 +#define HostCmd_ACT_MAC_RTS_CTS_ENABLE 0x0200 +#define HostCmd_ACT_MAC_STRICT_PROTECTION_ENABLE 0x0400 +#define HostCmd_ACT_MAC_ADHOC_G_PROTECTION_ON 0x2000 + +#define HostCmd_BSS_MODE_BSS 0x0001 +#define HostCmd_BSS_MODE_IBSS 0x0002 +#define HostCmd_BSS_MODE_ANY 0x0003 + +#define HostCmd_SCAN_RADIO_TYPE_BG 0 +#define HostCmd_SCAN_RADIO_TYPE_A 1 + +#define HOST_SLEEP_CFG_CANCEL 0xffffffff +#define HOST_SLEEP_CFG_COND_DEF 0x0000000f +#define HOST_SLEEP_CFG_GPIO_DEF 0xff +#define HOST_SLEEP_CFG_GAP_DEF 0 + +#define CMD_F_HOSTCMD (1 << 0) +#define CMD_F_CANCELED (1 << 1) + +#define HostCmd_CMD_ID_MASK 0x0fff + +#define HostCmd_SEQ_NUM_MASK 0x00ff + +#define HostCmd_BSS_NUM_MASK 0x0f00 + +#define HostCmd_BSS_TYPE_MASK 0xf000 + +#define HostCmd_SET_SEQ_NO_BSS_INFO(seq, num, type) { \ + (((seq) & 0x00ff) | \ + (((num) & 0x000f) << 8)) | \ + (((type) & 0x000f) << 12); } + +#define HostCmd_GET_SEQ_NO(seq) \ + ((seq) & HostCmd_SEQ_NUM_MASK) + +#define HostCmd_GET_BSS_NO(seq) \ + (((seq) & HostCmd_BSS_NUM_MASK) >> 8) + +#define HostCmd_GET_BSS_TYPE(seq) \ + (((seq) & HostCmd_BSS_TYPE_MASK) >> 12) + +#define EVENT_DUMMY_HOST_WAKEUP_SIGNAL 0x00000001 +#define EVENT_LINK_LOST 0x00000003 +#define EVENT_LINK_SENSED 0x00000004 +#define EVENT_MIB_CHANGED 0x00000006 +#define EVENT_INIT_DONE 0x00000007 +#define EVENT_DEAUTHENTICATED 0x00000008 +#define EVENT_DISASSOCIATED 0x00000009 +#define EVENT_PS_AWAKE 0x0000000a +#define EVENT_PS_SLEEP 0x0000000b +#define EVENT_MIC_ERR_MULTICAST 0x0000000d +#define EVENT_MIC_ERR_UNICAST 0x0000000e +#define EVENT_DEEP_SLEEP_AWAKE 0x00000010 +#define EVENT_ADHOC_BCN_LOST 0x00000011 + +#define EVENT_WMM_STATUS_CHANGE 0x00000017 +#define EVENT_BG_SCAN_REPORT 0x00000018 +#define EVENT_RSSI_LOW 0x00000019 +#define EVENT_SNR_LOW 0x0000001a +#define EVENT_MAX_FAIL 0x0000001b +#define EVENT_RSSI_HIGH 0x0000001c +#define EVENT_SNR_HIGH 0x0000001d +#define EVENT_IBSS_COALESCED 0x0000001e +#define EVENT_DATA_RSSI_LOW 0x00000024 +#define EVENT_DATA_SNR_LOW 0x00000025 +#define EVENT_DATA_RSSI_HIGH 0x00000026 +#define EVENT_DATA_SNR_HIGH 0x00000027 +#define EVENT_LINK_QUALITY 0x00000028 +#define EVENT_PORT_RELEASE 0x0000002b +#define EVENT_PRE_BEACON_LOST 0x00000031 +#define EVENT_ADDBA 0x00000033 +#define EVENT_DELBA 0x00000034 +#define EVENT_BA_STREAM_TIEMOUT 0x00000037 +#define EVENT_AMSDU_AGGR_CTRL 0x00000042 +#define EVENT_WEP_ICV_ERR 0x00000046 +#define EVENT_HS_ACT_REQ 0x00000047 +#define EVENT_BW_CHANGE 0x00000048 + +#define EVENT_HOSTWAKE_STAIE 0x0000004d + +#define EVENT_ID_MASK 0xffff +#define BSS_NUM_MASK 0xf + +#define EVENT_GET_BSS_NUM(event_cause) \ + (((event_cause) >> 16) & BSS_NUM_MASK) + +#define EVENT_GET_BSS_TYPE(event_cause) \ + (((event_cause) >> 24) & 0x00ff) + +struct mwifiex_event_wep_icv_err { + u16 reason_code; + u8 src_mac_addr[ETH_ALEN]; + u8 wep_key_index; + u8 wep_key_length; + u8 key[WLAN_KEY_LEN_WEP104]; +}; + +struct mwifiex_802_11_fixed_ies { + u8 time_stamp[8]; + __le16 beacon_interval; + __le16 capabilities; +}; + +struct mwifiex_ie_types_header { + __le16 type; + __le16 len; +} __packed; + +struct mwifiex_ie_types_data { + struct mwifiex_ie_types_header header; + u8 data[1]; +} __packed; + +#define MWIFIEX_TxPD_POWER_MGMT_NULL_PACKET 0x01 +#define MWIFIEX_TxPD_POWER_MGMT_LAST_PACKET 0x08 + +struct txpd { + u8 bss_type; + u8 bss_num; + __le16 tx_pkt_length; + __le16 tx_pkt_offset; + __le16 tx_pkt_type; + __le32 tx_control; + u8 priority; + u8 flags; + u8 pkt_delay_2ms; + u8 reserved1; +} __packed; + +struct rxpd { + u8 bss_type; + u8 bss_num; + u16 rx_pkt_length; + u16 rx_pkt_offset; + u16 rx_pkt_type; + u16 seq_num; + u8 priority; + u8 rx_rate; + s8 snr; + s8 nf; + /* Ht Info [Bit 0] RxRate format: LG=0, HT=1 + * [Bit 1] HT Bandwidth: BW20 = 0, BW40 = 1 + * [Bit 2] HT Guard Interval: LGI = 0, SGI = 1 */ + u8 ht_info; + u8 reserved; +} __packed; + +enum mwifiex_chan_scan_mode_bitmasks { + MWIFIEX_PASSIVE_SCAN = BIT(0), + MWIFIEX_DISABLE_CHAN_FILT = BIT(1), +}; + +#define SECOND_CHANNEL_BELOW 0x30 +#define SECOND_CHANNEL_ABOVE 0x10 +struct mwifiex_chan_scan_param_set { + u8 radio_type; + u8 chan_number; + u8 chan_scan_mode_bitmap; + __le16 min_scan_time; + __le16 max_scan_time; +} __packed; + +struct mwifiex_ie_types_chan_list_param_set { + struct mwifiex_ie_types_header header; + struct mwifiex_chan_scan_param_set chan_scan_param[1]; +} __packed; + +struct chan_band_param_set { + u8 radio_type; + u8 chan_number; +}; + +struct mwifiex_ie_types_chan_band_list_param_set { + struct mwifiex_ie_types_header header; + struct chan_band_param_set chan_band_param[1]; +} __packed; + +struct mwifiex_ie_types_rates_param_set { + struct mwifiex_ie_types_header header; + u8 rates[1]; +} __packed; + +struct mwifiex_ie_types_ssid_param_set { + struct mwifiex_ie_types_header header; + u8 ssid[1]; +} __packed; + +struct mwifiex_ie_types_num_probes { + struct mwifiex_ie_types_header header; + __le16 num_probes; +} __packed; + +struct mwifiex_ie_types_wildcard_ssid_params { + struct mwifiex_ie_types_header header; + u8 max_ssid_length; + u8 ssid[1]; +} __packed; + +#define TSF_DATA_SIZE 8 +struct mwifiex_ie_types_tsf_timestamp { + struct mwifiex_ie_types_header header; + u8 tsf_data[1]; +} __packed; + +struct mwifiex_cf_param_set { + u8 cfp_cnt; + u8 cfp_period; + u16 cfp_max_duration; + u16 cfp_duration_remaining; +} __packed; + +struct mwifiex_ibss_param_set { + u16 atim_window; +} __packed; + +struct mwifiex_ie_types_ss_param_set { + struct mwifiex_ie_types_header header; + union { + struct mwifiex_cf_param_set cf_param_set[1]; + struct mwifiex_ibss_param_set ibss_param_set[1]; + } cf_ibss; +} __packed; + +struct mwifiex_fh_param_set { + u16 dwell_time; + u8 hop_set; + u8 hop_pattern; + u8 hop_index; +} __packed; + +struct mwifiex_ds_param_set { + u8 current_chan; +} __packed; + +struct mwifiex_ie_types_phy_param_set { + struct mwifiex_ie_types_header header; + union { + struct mwifiex_fh_param_set fh_param_set[1]; + struct mwifiex_ds_param_set ds_param_set[1]; + } fh_ds; +} __packed; + +struct mwifiex_ie_types_auth_type { + struct mwifiex_ie_types_header header; + __le16 auth_type; +} __packed; + +struct mwifiex_ie_types_vendor_param_set { + struct mwifiex_ie_types_header header; + u8 ie[MWIFIEX_MAX_VSIE_LEN]; +}; + +struct mwifiex_ie_types_rsn_param_set { + struct mwifiex_ie_types_header header; + u8 rsn_ie[1]; +} __packed; + +#define KEYPARAMSET_FIXED_LEN 6 + +struct mwifiex_ie_type_key_param_set { + __le16 type; + __le16 length; + __le16 key_type_id; + __le16 key_info; + __le16 key_len; + u8 key[50]; +} __packed; + +struct host_cmd_ds_802_11_key_material { + __le16 action; + struct mwifiex_ie_type_key_param_set key_param_set; +} __packed; + +struct host_cmd_ds_gen { + u16 command; + u16 size; + u16 seq_num; + u16 result; +}; + +#define S_DS_GEN sizeof(struct host_cmd_ds_gen) + +enum sleep_resp_ctrl { + RESP_NOT_NEEDED = 0, + RESP_NEEDED, +}; + +struct mwifiex_ps_param { + __le16 null_pkt_interval; + __le16 multiple_dtims; + __le16 bcn_miss_timeout; + __le16 local_listen_interval; + __le16 adhoc_wake_period; + __le16 mode; + __le16 delay_to_ps; +}; + +struct mwifiex_auto_ds_param { + __le16 deep_sleep_timeout; +}; + +struct sleep_confirm_param { + __le16 resp_ctrl; +}; + +#define BITMAP_AUTO_DS 0x01 +#define BITMAP_STA_PS 0x10 +#define BITMAP_UAP_INACT_PS 0x100 +#define BITMAP_UAP_DTIM_PS 0x200 +struct auto_ps_param { + __le16 ps_bitmap; + /* auto deep sleep parameter, + * sta power save parameter + * uap inactivity parameter + * uap DTIM parameter */ +}; + +#define AUTO_PS_FIX_SIZE 4 + +#define TLV_TYPE_AUTO_DS_PARAM (PROPRIETARY_TLV_BASE_ID + 113) +#define TLV_TYPE_PS_PARAM (PROPRIETARY_TLV_BASE_ID + 114) + +struct mwifiex_ie_types_auto_ds_param { + struct mwifiex_ie_types_header header; + struct mwifiex_auto_ds_param param; +} __packed; + +struct mwifiex_ie_types_ps_param { + struct mwifiex_ie_types_header header; + struct mwifiex_ps_param param; +} __packed; + +struct host_cmd_ds_802_11_ps_mode_enh { + __le16 action; + + union { + struct mwifiex_ps_param opt_ps; + struct mwifiex_auto_ds_param auto_ds; + struct sleep_confirm_param sleep_cfm; + __le16 ps_bitmap; + struct auto_ps_param auto_ps; + } params; +} __packed; + +struct host_cmd_ds_get_hw_spec { + __le16 hw_if_version; + __le16 version; + __le16 reserved; + __le16 num_of_mcast_adr; + u8 permanent_addr[ETH_ALEN]; + __le16 region_code; + __le16 number_of_antenna; + __le32 fw_release_number; + __le32 reserved_1; + __le32 reserved_2; + __le32 reserved_3; + __le32 fw_cap_info; + __le32 dot_11n_dev_cap; + u8 dev_mcs_support; + __le16 mp_end_port; /* SDIO only, reserved for other interfacces */ + __le16 reserved_4; +} __packed; + +struct host_cmd_ds_802_11_rssi_info { + __le16 action; + __le16 ndata; + __le16 nbcn; + __le16 reserved[9]; + long long reserved_1; +}; + +struct host_cmd_ds_802_11_rssi_info_rsp { + __le16 action; + __le16 ndata; + __le16 nbcn; + __le16 data_rssi_last; + __le16 data_nf_last; + __le16 data_rssi_avg; + __le16 data_nf_avg; + __le16 bcn_rssi_last; + __le16 bcn_nf_last; + __le16 bcn_rssi_avg; + __le16 bcn_nf_avg; + long long tsf_bcn; +}; + +struct host_cmd_ds_802_11_mac_address { + __le16 action; + u8 mac_addr[ETH_ALEN]; +}; + +struct host_cmd_ds_mac_control { + __le16 action; + __le16 reserved; +}; + +struct host_cmd_ds_mac_multicast_adr { + __le16 action; + __le16 num_of_adrs; + u8 mac_list[MWIFIEX_MAX_MULTICAST_LIST_SIZE][ETH_ALEN]; +} __packed; + +struct host_cmd_ds_802_11_deauthenticate { + u8 mac_addr[ETH_ALEN]; + __le16 reason_code; +} __packed; + +struct host_cmd_ds_802_11_associate { + u8 peer_sta_addr[ETH_ALEN]; + __le16 cap_info_bitmap; + __le16 listen_interval; + __le16 beacon_period; + u8 dtim_period; +} __packed; + +struct ieee_types_assoc_rsp { + __le16 cap_info_bitmap; + __le16 status_code; + __le16 a_id; + u8 ie_buffer[1]; +} __packed; + +struct host_cmd_ds_802_11_associate_rsp { + struct ieee_types_assoc_rsp assoc_rsp; +} __packed; + +struct ieee_types_cf_param_set { + u8 element_id; + u8 len; + u8 cfp_cnt; + u8 cfp_period; + u16 cfp_max_duration; + u16 cfp_duration_remaining; +} __packed; + +struct ieee_types_ibss_param_set { + u8 element_id; + u8 len; + __le16 atim_window; +} __packed; + +union ieee_types_ss_param_set { + struct ieee_types_cf_param_set cf_param_set; + struct ieee_types_ibss_param_set ibss_param_set; +} __packed; + +struct ieee_types_fh_param_set { + u8 element_id; + u8 len; + __le16 dwell_time; + u8 hop_set; + u8 hop_pattern; + u8 hop_index; +} __packed; + +struct ieee_types_ds_param_set { + u8 element_id; + u8 len; + u8 current_chan; +} __packed; + +union ieee_types_phy_param_set { + struct ieee_types_fh_param_set fh_param_set; + struct ieee_types_ds_param_set ds_param_set; +} __packed; + +struct host_cmd_ds_802_11_ad_hoc_start { + u8 ssid[IEEE80211_MAX_SSID_LEN]; + u8 bss_mode; + __le16 beacon_period; + u8 dtim_period; + union ieee_types_ss_param_set ss_param_set; + union ieee_types_phy_param_set phy_param_set; + u16 reserved1; + __le16 cap_info_bitmap; + u8 DataRate[HOSTCMD_SUPPORTED_RATES]; +} __packed; + +struct host_cmd_ds_802_11_ad_hoc_result { + u8 pad[3]; + u8 bssid[ETH_ALEN]; +} __packed; + +struct adhoc_bss_desc { + u8 bssid[ETH_ALEN]; + u8 ssid[IEEE80211_MAX_SSID_LEN]; + u8 bss_mode; + __le16 beacon_period; + u8 dtim_period; + u8 time_stamp[8]; + u8 local_time[8]; + union ieee_types_phy_param_set phy_param_set; + union ieee_types_ss_param_set ss_param_set; + __le16 cap_info_bitmap; + u8 data_rates[HOSTCMD_SUPPORTED_RATES]; + + /* + * DO NOT ADD ANY FIELDS TO THIS STRUCTURE. + * It is used in the Adhoc join command and will cause a + * binary layout mismatch with the firmware + */ +} __packed; + +struct host_cmd_ds_802_11_ad_hoc_join { + struct adhoc_bss_desc bss_descriptor; + u16 reserved1; + u16 reserved2; +} __packed; + +struct host_cmd_ds_802_11_get_log { + __le32 mcast_tx_frame; + __le32 failed; + __le32 retry; + __le32 multi_retry; + __le32 frame_dup; + __le32 rts_success; + __le32 rts_failure; + __le32 ack_failure; + __le32 rx_frag; + __le32 mcast_rx_frame; + __le32 fcs_error; + __le32 tx_frame; + __le32 reserved; + __le32 wep_icv_err_cnt[4]; +}; + +struct host_cmd_ds_tx_rate_query { + u8 tx_rate; + /* Ht Info [Bit 0] RxRate format: LG=0, HT=1 + * [Bit 1] HT Bandwidth: BW20 = 0, BW40 = 1 + * [Bit 2] HT Guard Interval: LGI = 0, SGI = 1 */ + u8 ht_info; +} __packed; + +enum Host_Sleep_Action { + HS_CONFIGURE = 0x0001, + HS_ACTIVATE = 0x0002, +}; + +struct mwifiex_hs_config_param { + __le32 conditions; + u8 gpio; + u8 gap; +} __packed; + +struct hs_activate_param { + u16 resp_ctrl; +} __packed; + +struct host_cmd_ds_802_11_hs_cfg_enh { + __le16 action; + + union { + struct mwifiex_hs_config_param hs_config; + struct hs_activate_param hs_activate; + } params; +} __packed; + +enum SNMP_MIB_INDEX { + OP_RATE_SET_I = 1, + DTIM_PERIOD_I = 3, + RTS_THRESH_I = 5, + SHORT_RETRY_LIM_I = 6, + LONG_RETRY_LIM_I = 7, + FRAG_THRESH_I = 8, + DOT11D_I = 9, +}; + +#define MAX_SNMP_BUF_SIZE 128 + +struct host_cmd_ds_802_11_snmp_mib { + __le16 query_type; + __le16 oid; + __le16 buf_size; + u8 value[1]; +} __packed; + +#define RADIO_ON 0x01 +#define RADIO_OFF 0x00 + +struct mwifiex_rate_scope { + __le16 type; + __le16 length; + __le16 hr_dsss_rate_bitmap; + __le16 ofdm_rate_bitmap; + __le16 ht_mcs_rate_bitmap[8]; +} __packed; + +struct mwifiex_rate_drop_pattern { + __le16 type; + __le16 length; + __le32 rate_drop_mode; +} __packed; + +struct host_cmd_ds_tx_rate_cfg { + __le16 action; + __le16 cfg_index; +} __packed; + +struct mwifiex_power_group { + u8 modulation_class; + u8 first_rate_code; + u8 last_rate_code; + s8 power_step; + s8 power_min; + s8 power_max; + u8 ht_bandwidth; + u8 reserved; +} __packed; + +struct mwifiex_types_power_group { + u16 type; + u16 length; +} __packed; + +struct host_cmd_ds_txpwr_cfg { + __le16 action; + __le16 cfg_index; + __le32 mode; +} __packed; + +#define MWIFIEX_USER_SCAN_CHAN_MAX 50 + +#define MWIFIEX_MAX_SSID_LIST_LENGTH 10 + +struct mwifiex_scan_cmd_config { + /* + * BSS Type to be sent in the firmware command + * + * Field can be used to restrict the types of networks returned in the + * scan. Valid settings are: + * + * - MWIFIEX_SCAN_MODE_BSS (infrastructure) + * - MWIFIEX_SCAN_MODE_IBSS (adhoc) + * - MWIFIEX_SCAN_MODE_ANY (unrestricted, adhoc and infrastructure) + */ + u8 bss_mode; + + /* Specific BSSID used to filter scan results in the firmware */ + u8 specific_bssid[ETH_ALEN]; + + /* Length of TLVs sent in command starting at tlvBuffer */ + u32 tlv_buf_len; + + /* + * SSID TLV(s) and ChanList TLVs to be sent in the firmware command + * + * TLV_TYPE_CHANLIST, mwifiex_ie_types_chan_list_param_set + * WLAN_EID_SSID, mwifiex_ie_types_ssid_param_set + */ + u8 tlv_buf[1]; /* SSID TLV(s) and ChanList TLVs are stored + here */ +} __packed; + +struct mwifiex_user_scan_chan { + u8 chan_number; + u8 radio_type; + u8 scan_type; + u8 reserved; + u32 scan_time; +} __packed; + +struct mwifiex_user_scan_ssid { + u8 ssid[IEEE80211_MAX_SSID_LEN + 1]; + u8 max_len; +} __packed; + +struct mwifiex_user_scan_cfg { + /* + * Flag set to keep the previous scan table intact + * + * If set, the scan results will accumulate, replacing any previous + * matched entries for a BSS with the new scan data + */ + u8 keep_previous_scan; + /* + * BSS mode to be sent in the firmware command + * + * Field can be used to restrict the types of networks returned in the + * scan. Valid settings are: + * + * - MWIFIEX_SCAN_MODE_BSS (infrastructure) + * - MWIFIEX_SCAN_MODE_IBSS (adhoc) + * - MWIFIEX_SCAN_MODE_ANY (unrestricted, adhoc and infrastructure) + */ + u8 bss_mode; + /* Configure the number of probe requests for active chan scans */ + u8 num_probes; + u8 reserved; + /* BSSID filter sent in the firmware command to limit the results */ + u8 specific_bssid[ETH_ALEN]; + /* SSID filter list used in the to limit the scan results */ + struct mwifiex_user_scan_ssid ssid_list[MWIFIEX_MAX_SSID_LIST_LENGTH]; + /* Variable number (fixed maximum) of channels to scan up */ + struct mwifiex_user_scan_chan chan_list[MWIFIEX_USER_SCAN_CHAN_MAX]; +} __packed; + +struct ie_body { + u8 grp_key_oui[4]; + u8 ptk_cnt[2]; + u8 ptk_body[4]; +} __packed; + +struct host_cmd_ds_802_11_scan { + u8 bss_mode; + u8 bssid[ETH_ALEN]; + u8 tlv_buffer[1]; +} __packed; + +struct host_cmd_ds_802_11_scan_rsp { + __le16 bss_descript_size; + u8 number_of_sets; + u8 bss_desc_and_tlv_buffer[1]; +} __packed; + +struct host_cmd_ds_802_11_bg_scan_query { + u8 flush; +} __packed; + +struct host_cmd_ds_802_11_bg_scan_query_rsp { + u32 report_condition; + struct host_cmd_ds_802_11_scan_rsp scan_resp; +} __packed; + +struct mwifiex_ietypes_domain_param_set { + struct mwifiex_ie_types_header header; + u8 country_code[IEEE80211_COUNTRY_STRING_LEN]; + struct ieee80211_country_ie_triplet triplet[1]; +} __packed; + +struct host_cmd_ds_802_11d_domain_info { + __le16 action; + struct mwifiex_ietypes_domain_param_set domain; +} __packed; + +struct host_cmd_ds_802_11d_domain_info_rsp { + __le16 action; + struct mwifiex_ietypes_domain_param_set domain; +} __packed; + +struct host_cmd_ds_11n_addba_req { + u8 add_req_result; + u8 peer_mac_addr[ETH_ALEN]; + u8 dialog_token; + __le16 block_ack_param_set; + __le16 block_ack_tmo; + __le16 ssn; +} __packed; + +struct host_cmd_ds_11n_addba_rsp { + u8 add_rsp_result; + u8 peer_mac_addr[ETH_ALEN]; + u8 dialog_token; + __le16 status_code; + __le16 block_ack_param_set; + __le16 block_ack_tmo; + __le16 ssn; +} __packed; + +struct host_cmd_ds_11n_delba { + u8 del_result; + u8 peer_mac_addr[ETH_ALEN]; + __le16 del_ba_param_set; + __le16 reason_code; + u8 reserved; +} __packed; + +struct host_cmd_ds_11n_batimeout { + u8 tid; + u8 peer_mac_addr[ETH_ALEN]; + u8 origninator; +} __packed; + +struct host_cmd_ds_11n_cfg { + __le16 action; + __le16 ht_tx_cap; + __le16 ht_tx_info; +} __packed; + +struct host_cmd_ds_txbuf_cfg { + __le16 action; + __le16 buff_size; + __le16 mp_end_port; /* SDIO only, reserved for other interfacces */ + __le16 reserved3; +} __packed; + +struct host_cmd_ds_amsdu_aggr_ctrl { + __le16 action; + __le16 enable; + __le16 curr_buf_size; +} __packed; + +struct mwifiex_ie_types_wmm_param_set { + struct mwifiex_ie_types_header header; + u8 wmm_ie[1]; +}; + +struct mwifiex_ie_types_wmm_queue_status { + struct mwifiex_ie_types_header header; + u8 queue_index; + u8 disabled; + u16 medium_time; + u8 flow_required; + u8 flow_created; + u32 reserved; +}; + +struct ieee_types_vendor_header { + u8 element_id; + u8 len; + u8 oui[3]; + u8 oui_type; + u8 oui_subtype; + u8 version; +} __packed; + +struct ieee_types_wmm_ac_parameters { + u8 aci_aifsn_bitmap; + u8 ecw_bitmap; + __le16 tx_op_limit; +} __packed; + +struct ieee_types_wmm_parameter { + /* + * WMM Parameter IE - Vendor Specific Header: + * element_id [221/0xdd] + * Len [24] + * Oui [00:50:f2] + * OuiType [2] + * OuiSubType [1] + * Version [1] + */ + struct ieee_types_vendor_header vend_hdr; + u8 qos_info_bitmap; + u8 reserved; + struct ieee_types_wmm_ac_parameters ac_params[IEEE80211_MAX_QUEUES]; +} __packed; + +struct ieee_types_wmm_info { + + /* + * WMM Info IE - Vendor Specific Header: + * element_id [221/0xdd] + * Len [7] + * Oui [00:50:f2] + * OuiType [2] + * OuiSubType [0] + * Version [1] + */ + struct ieee_types_vendor_header vend_hdr; + + u8 qos_info_bitmap; +} __packed; + +struct host_cmd_ds_wmm_get_status { + u8 queue_status_tlv[sizeof(struct mwifiex_ie_types_wmm_queue_status) * + IEEE80211_MAX_QUEUES]; + u8 wmm_param_tlv[sizeof(struct ieee_types_wmm_parameter) + 2]; +} __packed; + +struct mwifiex_wmm_ac_status { + u8 disabled; + u8 flow_required; + u8 flow_created; +}; + +struct mwifiex_ie_types_htcap { + struct mwifiex_ie_types_header header; + struct ieee80211_ht_cap ht_cap; +} __packed; + +struct mwifiex_ie_types_htinfo { + struct mwifiex_ie_types_header header; + struct ieee80211_ht_info ht_info; +} __packed; + +struct mwifiex_ie_types_2040bssco { + struct mwifiex_ie_types_header header; + u8 bss_co_2040; +} __packed; + +struct mwifiex_ie_types_extcap { + struct mwifiex_ie_types_header header; + u8 ext_cap; +} __packed; + +struct host_cmd_ds_mac_reg_access { + __le16 action; + __le16 offset; + __le32 value; +} __packed; + +struct host_cmd_ds_bbp_reg_access { + __le16 action; + __le16 offset; + u8 value; + u8 reserved[3]; +} __packed; + +struct host_cmd_ds_rf_reg_access { + __le16 action; + __le16 offset; + u8 value; + u8 reserved[3]; +} __packed; + +struct host_cmd_ds_pmic_reg_access { + __le16 action; + __le16 offset; + u8 value; + u8 reserved[3]; +} __packed; + +struct host_cmd_ds_802_11_eeprom_access { + __le16 action; + + __le16 offset; + __le16 byte_count; + u8 value; +} __packed; + +struct host_cmd_ds_802_11_rf_channel { + __le16 action; + __le16 current_channel; + __le16 rf_type; + __le16 reserved; + u8 reserved_1[32]; +} __packed; + +struct host_cmd_ds_version_ext { + u8 version_str_sel; + char version_str[128]; +} __packed; + +struct host_cmd_ds_802_11_ibss_status { + __le16 action; + __le16 enable; + u8 bssid[ETH_ALEN]; + __le16 beacon_interval; + __le16 atim_window; + __le16 use_g_rate_protect; +} __packed; + +#define CONNECTION_TYPE_INFRA 0 +#define CONNECTION_TYPE_ADHOC 1 + +struct host_cmd_ds_set_bss_mode { + u8 con_type; +} __packed; + +struct host_cmd_ds_command { + __le16 command; + __le16 size; + __le16 seq_num; + __le16 result; + union { + struct host_cmd_ds_get_hw_spec hw_spec; + struct host_cmd_ds_mac_control mac_ctrl; + struct host_cmd_ds_802_11_mac_address mac_addr; + struct host_cmd_ds_mac_multicast_adr mc_addr; + struct host_cmd_ds_802_11_get_log get_log; + struct host_cmd_ds_802_11_rssi_info rssi_info; + struct host_cmd_ds_802_11_rssi_info_rsp rssi_info_rsp; + struct host_cmd_ds_802_11_snmp_mib smib; + struct host_cmd_ds_802_11_rf_channel rf_channel; + struct host_cmd_ds_tx_rate_query tx_rate; + struct host_cmd_ds_tx_rate_cfg tx_rate_cfg; + struct host_cmd_ds_txpwr_cfg txp_cfg; + struct host_cmd_ds_802_11_ps_mode_enh psmode_enh; + struct host_cmd_ds_802_11_hs_cfg_enh opt_hs_cfg; + struct host_cmd_ds_802_11_scan scan; + struct host_cmd_ds_802_11_scan_rsp scan_resp; + struct host_cmd_ds_802_11_bg_scan_query bg_scan_query; + struct host_cmd_ds_802_11_bg_scan_query_rsp bg_scan_query_resp; + struct host_cmd_ds_802_11_associate associate; + struct host_cmd_ds_802_11_associate_rsp associate_rsp; + struct host_cmd_ds_802_11_deauthenticate deauth; + struct host_cmd_ds_802_11_ad_hoc_start adhoc_start; + struct host_cmd_ds_802_11_ad_hoc_result adhoc_result; + struct host_cmd_ds_802_11_ad_hoc_join adhoc_join; + struct host_cmd_ds_802_11d_domain_info domain_info; + struct host_cmd_ds_802_11d_domain_info_rsp domain_info_resp; + struct host_cmd_ds_11n_addba_req add_ba_req; + struct host_cmd_ds_11n_addba_rsp add_ba_rsp; + struct host_cmd_ds_11n_delba del_ba; + struct host_cmd_ds_txbuf_cfg tx_buf; + struct host_cmd_ds_amsdu_aggr_ctrl amsdu_aggr_ctrl; + struct host_cmd_ds_11n_cfg htcfg; + struct host_cmd_ds_wmm_get_status get_wmm_status; + struct host_cmd_ds_802_11_key_material key_material; + struct host_cmd_ds_version_ext verext; + struct host_cmd_ds_802_11_ibss_status ibss_coalescing; + struct host_cmd_ds_mac_reg_access mac_reg; + struct host_cmd_ds_bbp_reg_access bbp_reg; + struct host_cmd_ds_rf_reg_access rf_reg; + struct host_cmd_ds_pmic_reg_access pmic_reg; + struct host_cmd_ds_set_bss_mode bss_mode; + struct host_cmd_ds_802_11_eeprom_access eeprom; + } params; +} __packed; + +struct mwifiex_opt_sleep_confirm { + __le16 command; + __le16 size; + __le16 seq_num; + __le16 result; + __le16 action; + struct sleep_confirm_param sleep_cfm; +} __packed; + +struct mwifiex_opt_sleep_confirm_buffer { + u8 hdr[4]; + struct mwifiex_opt_sleep_confirm ps_cfm_sleep; +} __packed; +#endif /* !_MWIFIEX_FW_H_ */ diff --git a/drivers/net/wireless/mwifiex/init.c b/drivers/net/wireless/mwifiex/init.c new file mode 100644 index 0000000..07ebc97 --- /dev/null +++ b/drivers/net/wireless/mwifiex/init.c @@ -0,0 +1,665 @@ +/* + * Marvell Wireless LAN device driver: HW/FW Initialization + * + * Copyright (C) 2011, Marvell International Ltd. + * + * This software file (the "File") is distributed by Marvell International + * Ltd. under the terms of the GNU General Public License Version 2, June 1991 + * (the "License"). You may use, redistribute and/or modify this File in + * accordance with the terms and conditions of the License, a copy of which + * is available by writing to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the + * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. + * + * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE + * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE + * ARE EXPRESSLY DISCLAIMED. The License provides additional details about + * this warranty disclaimer. + */ + +#include "decl.h" +#include "ioctl.h" +#include "util.h" +#include "fw.h" +#include "main.h" +#include "wmm.h" +#include "11n.h" + +/* + * This function adds a BSS priority table to the table list. + * + * The function allocates a new BSS priority table node and adds it to + * the end of BSS priority table list, kept in driver memory. + */ +static int mwifiex_add_bss_prio_tbl(struct mwifiex_private *priv) +{ + struct mwifiex_adapter *adapter = priv->adapter; + struct mwifiex_bss_prio_node *bss_prio; + int status = 0; + unsigned long flags; + + bss_prio = kzalloc(sizeof(struct mwifiex_bss_prio_node), GFP_KERNEL); + if (!bss_prio) { + dev_err(adapter->dev, "%s: failed to alloc bss_prio\n", + __func__); + return -1; + } + + bss_prio->priv = priv; + INIT_LIST_HEAD(&bss_prio->list); + if (!adapter->bss_prio_tbl[priv->bss_priority].bss_prio_cur) + adapter->bss_prio_tbl[priv->bss_priority].bss_prio_cur = + bss_prio; + + spin_lock_irqsave(&adapter->bss_prio_tbl[priv->bss_priority] + .bss_prio_lock, flags); + list_add_tail(&bss_prio->list, + &adapter->bss_prio_tbl[priv->bss_priority] + .bss_prio_head); + spin_unlock_irqrestore(&adapter->bss_prio_tbl[priv->bss_priority] + .bss_prio_lock, flags); + + return status; +} + +/* + * This function initializes the private structure and sets default + * values to the members. + * + * Additionally, it also initializes all the locks and sets up all the + * lists. + */ +static int mwifiex_init_priv(struct mwifiex_private *priv) +{ + u32 i; + int ret = 0; + + priv->media_connected = false; + memset(priv->curr_addr, 0xff, ETH_ALEN); + + priv->pkt_tx_ctrl = 0; + priv->bss_mode = MWIFIEX_BSS_MODE_INFRA; + priv->data_rate = 0; /* Initially indicate the rate as auto */ + priv->is_data_rate_auto = true; + priv->bcn_avg_factor = DEFAULT_BCN_AVG_FACTOR; + priv->data_avg_factor = DEFAULT_DATA_AVG_FACTOR; + + priv->sec_info.wep_status = MWIFIEX_802_11_WEP_DISABLED; + priv->sec_info.authentication_mode = MWIFIEX_AUTH_MODE_OPEN; + priv->sec_info.encryption_mode = MWIFIEX_ENCRYPTION_MODE_NONE; + for (i = 0; i < ARRAY_SIZE(priv->wep_key); i++) + memset(&priv->wep_key[i], 0, sizeof(struct mwifiex_wep_key)); + priv->wep_key_curr_index = 0; + priv->curr_pkt_filter = HostCmd_ACT_MAC_RX_ON | HostCmd_ACT_MAC_TX_ON | + HostCmd_ACT_MAC_ETHERNETII_ENABLE; + + priv->beacon_period = 100; /* beacon interval */ ; + priv->attempted_bss_desc = NULL; + memset(&priv->curr_bss_params, 0, sizeof(priv->curr_bss_params)); + priv->listen_interval = MWIFIEX_DEFAULT_LISTEN_INTERVAL; + + memset(&priv->prev_ssid, 0, sizeof(priv->prev_ssid)); + memset(&priv->prev_bssid, 0, sizeof(priv->prev_bssid)); + memset(&priv->assoc_rsp_buf, 0, sizeof(priv->assoc_rsp_buf)); + priv->assoc_rsp_size = 0; + priv->adhoc_channel = DEFAULT_AD_HOC_CHANNEL; + priv->atim_window = 0; + priv->adhoc_state = ADHOC_IDLE; + priv->tx_power_level = 0; + priv->max_tx_power_level = 0; + priv->min_tx_power_level = 0; + priv->tx_rate = 0; + priv->rxpd_htinfo = 0; + priv->rxpd_rate = 0; + priv->rate_bitmap = 0; + priv->data_rssi_last = 0; + priv->data_rssi_avg = 0; + priv->data_nf_avg = 0; + priv->data_nf_last = 0; + priv->bcn_rssi_last = 0; + priv->bcn_rssi_avg = 0; + priv->bcn_nf_avg = 0; + priv->bcn_nf_last = 0; + memset(&priv->wpa_ie, 0, sizeof(priv->wpa_ie)); + memset(&priv->aes_key, 0, sizeof(priv->aes_key)); + priv->wpa_ie_len = 0; + priv->wpa_is_gtk_set = false; + + memset(&priv->assoc_tlv_buf, 0, sizeof(priv->assoc_tlv_buf)); + priv->assoc_tlv_buf_len = 0; + memset(&priv->wps, 0, sizeof(priv->wps)); + memset(&priv->gen_ie_buf, 0, sizeof(priv->gen_ie_buf)); + priv->gen_ie_buf_len = 0; + memset(priv->vs_ie, 0, sizeof(priv->vs_ie)); + + priv->wmm_required = true; + priv->wmm_enabled = false; + priv->wmm_qosinfo = 0; + priv->curr_bcn_buf = NULL; + priv->curr_bcn_size = 0; + + priv->scan_block = false; + + ret = mwifiex_add_bss_prio_tbl(priv); + + return ret; +} + +/* + * This function allocates buffers for members of the adapter + * structure. + * + * The memory allocated includes scan table, command buffers, and + * sleep confirm command buffer. In addition, the queues are + * also initialized. + */ +static int mwifiex_allocate_adapter(struct mwifiex_adapter *adapter) +{ + int ret = 0; + u32 buf_size; + struct mwifiex_bssdescriptor *temp_scan_table; + + /* Allocate buffer to store the BSSID list */ + buf_size = sizeof(struct mwifiex_bssdescriptor) * IW_MAX_AP; + temp_scan_table = kzalloc(buf_size, GFP_KERNEL); + if (!temp_scan_table) { + dev_err(adapter->dev, "%s: failed to alloc temp_scan_table\n", + __func__); + return -1; + } + + adapter->scan_table = temp_scan_table; + + /* Allocate command buffer */ + ret = mwifiex_alloc_cmd_buffer(adapter); + if (ret) { + dev_err(adapter->dev, "%s: failed to alloc cmd buffer\n", + __func__); + return -1; + } + + adapter->sleep_cfm = + dev_alloc_skb(sizeof(struct mwifiex_opt_sleep_confirm_buffer) + + INTF_HEADER_LEN); + + if (!adapter->sleep_cfm) { + dev_err(adapter->dev, "%s: failed to alloc sleep cfm" + " cmd buffer\n", __func__); + return -1; + } + skb_reserve(adapter->sleep_cfm, INTF_HEADER_LEN); + + return 0; +} + +/* + * This function initializes the adapter structure and sets default + * values to the members of adapter. + * + * This also initializes the WMM related parameters in the driver private + * structures. + */ +static void mwifiex_init_adapter(struct mwifiex_adapter *adapter) +{ + struct mwifiex_opt_sleep_confirm_buffer *sleep_cfm_buf = NULL; + + skb_put(adapter->sleep_cfm, sizeof(sleep_cfm_buf->ps_cfm_sleep)); + sleep_cfm_buf = (struct mwifiex_opt_sleep_confirm_buffer *) + (adapter->sleep_cfm->data); + + adapter->cmd_sent = false; + adapter->data_sent = true; + adapter->cmd_resp_received = false; + adapter->event_received = false; + adapter->data_received = false; + + adapter->surprise_removed = false; + + adapter->hw_status = MWIFIEX_HW_STATUS_INITIALIZING; + + adapter->ps_mode = MWIFIEX_802_11_POWER_MODE_CAM; + adapter->ps_state = PS_STATE_AWAKE; + adapter->need_to_wakeup = false; + + adapter->scan_mode = HostCmd_BSS_MODE_ANY; + adapter->specific_scan_time = MWIFIEX_SPECIFIC_SCAN_CHAN_TIME; + adapter->active_scan_time = MWIFIEX_ACTIVE_SCAN_CHAN_TIME; + adapter->passive_scan_time = MWIFIEX_PASSIVE_SCAN_CHAN_TIME; + + adapter->num_in_scan_table = 0; + memset(adapter->scan_table, 0, + (sizeof(struct mwifiex_bssdescriptor) * IW_MAX_AP)); + adapter->scan_probes = 1; + + memset(adapter->bcn_buf, 0, sizeof(adapter->bcn_buf)); + adapter->bcn_buf_end = adapter->bcn_buf; + + adapter->radio_on = RADIO_ON; + adapter->multiple_dtim = 1; + + adapter->local_listen_interval = 0; /* default value in firmware + will be used */ + + adapter->is_deep_sleep = false; + + adapter->delay_null_pkt = false; + adapter->delay_to_ps = 1000; + adapter->enhanced_ps_mode = PS_MODE_AUTO; + + adapter->gen_null_pkt = false; /* Disable NULL Pkg generation by + default */ + adapter->pps_uapsd_mode = false; /* Disable pps/uapsd mode by + default */ + adapter->pm_wakeup_card_req = false; + + adapter->pm_wakeup_fw_try = false; + + adapter->max_tx_buf_size = MWIFIEX_TX_DATA_BUF_SIZE_2K; + adapter->tx_buf_size = MWIFIEX_TX_DATA_BUF_SIZE_2K; + adapter->curr_tx_buf_size = MWIFIEX_TX_DATA_BUF_SIZE_2K; + + adapter->is_hs_configured = false; + adapter->hs_cfg.conditions = cpu_to_le32(HOST_SLEEP_CFG_COND_DEF); + adapter->hs_cfg.gpio = HOST_SLEEP_CFG_GPIO_DEF; + adapter->hs_cfg.gap = HOST_SLEEP_CFG_GAP_DEF; + adapter->hs_activated = false; + + memset(adapter->event_body, 0, sizeof(adapter->event_body)); + adapter->hw_dot_11n_dev_cap = 0; + adapter->hw_dev_mcs_support = 0; + adapter->usr_dot_11n_dev_cap = 0; + adapter->usr_dev_mcs_support = 0; + adapter->chan_offset = 0; + adapter->adhoc_11n_enabled = false; + + mwifiex_wmm_init(adapter); + + if (adapter->sleep_cfm) { + memset(&sleep_cfm_buf->ps_cfm_sleep, 0, + adapter->sleep_cfm->len); + sleep_cfm_buf->ps_cfm_sleep.command = + cpu_to_le16(HostCmd_CMD_802_11_PS_MODE_ENH); + sleep_cfm_buf->ps_cfm_sleep.size = + cpu_to_le16(adapter->sleep_cfm->len); + sleep_cfm_buf->ps_cfm_sleep.result = 0; + sleep_cfm_buf->ps_cfm_sleep.action = cpu_to_le16(SLEEP_CONFIRM); + sleep_cfm_buf->ps_cfm_sleep.sleep_cfm.resp_ctrl = + cpu_to_le16(RESP_NEEDED); + } + memset(&adapter->sleep_params, 0, sizeof(adapter->sleep_params)); + memset(&adapter->sleep_period, 0, sizeof(adapter->sleep_period)); + adapter->tx_lock_flag = false; + adapter->null_pkt_interval = 0; + adapter->fw_bands = 0; + adapter->config_bands = 0; + adapter->adhoc_start_band = 0; + adapter->scan_channels = NULL; + adapter->fw_release_number = 0; + adapter->fw_cap_info = 0; + memset(&adapter->upld_buf, 0, sizeof(adapter->upld_buf)); + adapter->event_cause = 0; + adapter->region_code = 0; + adapter->bcn_miss_time_out = DEFAULT_BCN_MISS_TIMEOUT; + adapter->adhoc_awake_period = 0; + memset(&adapter->arp_filter, 0, sizeof(adapter->arp_filter)); + adapter->arp_filter_size = 0; + + return; +} + +/* + * This function frees the adapter structure. + * + * The freeing operation is done recursively, by canceling all + * pending commands, freeing the member buffers previously + * allocated (command buffers, scan table buffer, sleep confirm + * command buffer), stopping the timers and calling the cleanup + * routines for every interface, before the actual adapter + * structure is freed. + */ +static void +mwifiex_free_adapter(struct mwifiex_adapter *adapter) +{ + if (!adapter) { + pr_err("%s: adapter is NULL\n", __func__); + return; + } + + mwifiex_cancel_all_pending_cmd(adapter); + + /* Free lock variables */ + mwifiex_free_lock_list(adapter); + + /* Free command buffer */ + dev_dbg(adapter->dev, "info: free cmd buffer\n"); + mwifiex_free_cmd_buffer(adapter); + + del_timer(&adapter->cmd_timer); + + dev_dbg(adapter->dev, "info: free scan table\n"); + kfree(adapter->scan_table); + adapter->scan_table = NULL; + + adapter->if_ops.cleanup_if(adapter); + + dev_kfree_skb_any(adapter->sleep_cfm); + + return; +} + +/* + * This function intializes the lock variables and + * the list heads. + */ +int mwifiex_init_lock_list(struct mwifiex_adapter *adapter) +{ + struct mwifiex_private *priv = NULL; + s32 i = 0; + u32 j = 0; + + spin_lock_init(&adapter->mwifiex_lock); + spin_lock_init(&adapter->int_lock); + spin_lock_init(&adapter->main_proc_lock); + spin_lock_init(&adapter->mwifiex_cmd_lock); + for (i = 0; i < adapter->priv_num; i++) { + if (adapter->priv[i]) { + priv = adapter->priv[i]; + spin_lock_init(&priv->rx_pkt_lock); + spin_lock_init(&priv->wmm.ra_list_spinlock); + spin_lock_init(&priv->curr_bcn_buf_lock); + } + } + + /* Initialize cmd_free_q */ + INIT_LIST_HEAD(&adapter->cmd_free_q); + /* Initialize cmd_pending_q */ + INIT_LIST_HEAD(&adapter->cmd_pending_q); + /* Initialize scan_pending_q */ + INIT_LIST_HEAD(&adapter->scan_pending_q); + + spin_lock_init(&adapter->cmd_free_q_lock); + spin_lock_init(&adapter->cmd_pending_q_lock); + spin_lock_init(&adapter->scan_pending_q_lock); + + for (i = 0; i < adapter->priv_num; ++i) { + INIT_LIST_HEAD(&adapter->bss_prio_tbl[i].bss_prio_head); + adapter->bss_prio_tbl[i].bss_prio_cur = NULL; + spin_lock_init(&adapter->bss_prio_tbl[i].bss_prio_lock); + } + + for (i = 0; i < adapter->priv_num; i++) { + if (!adapter->priv[i]) + continue; + priv = adapter->priv[i]; + for (j = 0; j < MAX_NUM_TID; ++j) { + INIT_LIST_HEAD(&priv->wmm.tid_tbl_ptr[j].ra_list); + spin_lock_init(&priv->wmm.tid_tbl_ptr[j].tid_tbl_lock); + } + INIT_LIST_HEAD(&priv->tx_ba_stream_tbl_ptr); + INIT_LIST_HEAD(&priv->rx_reorder_tbl_ptr); + + spin_lock_init(&priv->tx_ba_stream_tbl_lock); + spin_lock_init(&priv->rx_reorder_tbl_lock); + } + + return 0; +} + +/* + * This function releases the lock variables and frees the locks and + * associated locks. + */ +void mwifiex_free_lock_list(struct mwifiex_adapter *adapter) +{ + struct mwifiex_private *priv = NULL; + s32 i = 0; + s32 j = 0; + + /* Free lists */ + list_del(&adapter->cmd_free_q); + list_del(&adapter->cmd_pending_q); + list_del(&adapter->scan_pending_q); + + for (i = 0; i < adapter->priv_num; i++) + list_del(&adapter->bss_prio_tbl[i].bss_prio_head); + + for (i = 0; i < adapter->priv_num; i++) { + if (adapter->priv[i]) { + priv = adapter->priv[i]; + for (j = 0; j < MAX_NUM_TID; ++j) + list_del(&priv->wmm.tid_tbl_ptr[j].ra_list); + list_del(&priv->tx_ba_stream_tbl_ptr); + list_del(&priv->rx_reorder_tbl_ptr); + } + } + + return; +} + +/* + * This function initializes the firmware. + * + * The following operations are performed sequentially - + * - Allocate adapter structure + * - Initialize the adapter structure + * - Initialize the private structure + * - Add BSS priority tables to the adapter structure + * - For each interface, send the init commands to firmware + * - Send the first command in command pending queue, if available + */ +int mwifiex_init_fw(struct mwifiex_adapter *adapter) +{ + int ret = 0; + struct mwifiex_private *priv = NULL; + u8 i = 0; + u8 first_sta = true; + int is_cmd_pend_q_empty; + unsigned long flags; + + adapter->hw_status = MWIFIEX_HW_STATUS_INITIALIZING; + + /* Allocate memory for member of adapter structure */ + ret = mwifiex_allocate_adapter(adapter); + if (ret) + return -1; + + /* Initialize adapter structure */ + mwifiex_init_adapter(adapter); + + for (i = 0; i < adapter->priv_num; i++) { + if (adapter->priv[i]) { + priv = adapter->priv[i]; + + /* Initialize private structure */ + ret = mwifiex_init_priv(priv); + if (ret) + return -1; + } + } + for (i = 0; i < adapter->priv_num; i++) { + if (adapter->priv[i]) { + ret = mwifiex_sta_init_cmd(adapter->priv[i], first_sta); + if (ret == -1) + return -1; + + first_sta = false; + } + } + + spin_lock_irqsave(&adapter->cmd_pending_q_lock, flags); + is_cmd_pend_q_empty = list_empty(&adapter->cmd_pending_q); + spin_unlock_irqrestore(&adapter->cmd_pending_q_lock, flags); + if (!is_cmd_pend_q_empty) { + /* Send the first command in queue and return */ + if (mwifiex_main_process(adapter) != -1) + ret = -EINPROGRESS; + } else { + adapter->hw_status = MWIFIEX_HW_STATUS_READY; + } + + return ret; +} + +/* + * This function deletes the BSS priority tables. + * + * The function traverses through all the allocated BSS priority nodes + * in every BSS priority table and frees them. + */ +static void mwifiex_delete_bss_prio_tbl(struct mwifiex_private *priv) +{ + int i; + struct mwifiex_adapter *adapter = priv->adapter; + struct mwifiex_bss_prio_node *bssprio_node = NULL, *tmp_node = NULL, + **cur = NULL; + struct list_head *head; + spinlock_t *lock; + unsigned long flags; + + for (i = 0; i < adapter->priv_num; ++i) { + head = &adapter->bss_prio_tbl[i].bss_prio_head; + cur = &adapter->bss_prio_tbl[i].bss_prio_cur; + lock = &adapter->bss_prio_tbl[i].bss_prio_lock; + dev_dbg(adapter->dev, "info: delete BSS priority table," + " index = %d, i = %d, head = %p, cur = %p\n", + priv->bss_index, i, head, *cur); + if (*cur) { + spin_lock_irqsave(lock, flags); + if (list_empty(head)) { + spin_unlock_irqrestore(lock, flags); + continue; + } + bssprio_node = list_first_entry(head, + struct mwifiex_bss_prio_node, list); + spin_unlock_irqrestore(lock, flags); + + list_for_each_entry_safe(bssprio_node, tmp_node, head, + list) { + if (bssprio_node->priv == priv) { + dev_dbg(adapter->dev, "info: Delete " + "node %p, next = %p\n", + bssprio_node, tmp_node); + spin_lock_irqsave(lock, flags); + list_del(&bssprio_node->list); + spin_unlock_irqrestore(lock, flags); + kfree(bssprio_node); + } + } + *cur = (struct mwifiex_bss_prio_node *)head; + } + } +} + +/* + * This function is used to shutdown the driver. + * + * The following operations are performed sequentially - + * - Check if already shut down + * - Make sure the main process has stopped + * - Clean up the Tx and Rx queues + * - Delete BSS priority tables + * - Free the adapter + * - Notify completion + */ +int +mwifiex_shutdown_drv(struct mwifiex_adapter *adapter) +{ + int ret = -EINPROGRESS; + struct mwifiex_private *priv = NULL; + s32 i = 0; + unsigned long flags; + + /* mwifiex already shutdown */ + if (adapter->hw_status == MWIFIEX_HW_STATUS_NOT_READY) + return 0; + + adapter->hw_status = MWIFIEX_HW_STATUS_CLOSING; + /* wait for mwifiex_process to complete */ + if (adapter->mwifiex_processing) { + dev_warn(adapter->dev, "main process is still running\n"); + return ret; + } + + /* shut down mwifiex */ + dev_dbg(adapter->dev, "info: shutdown mwifiex...\n"); + + /* Clean up Tx/Rx queues and delete BSS priority table */ + for (i = 0; i < adapter->priv_num; i++) { + if (adapter->priv[i]) { + priv = adapter->priv[i]; + + mwifiex_clean_txrx(priv); + mwifiex_delete_bss_prio_tbl(priv); + } + } + + spin_lock_irqsave(&adapter->mwifiex_lock, flags); + + /* Free adapter structure */ + mwifiex_free_adapter(adapter); + + spin_unlock_irqrestore(&adapter->mwifiex_lock, flags); + + /* Notify completion */ + ret = mwifiex_shutdown_fw_complete(adapter); + + return ret; +} + +/* + * This function downloads the firmware to the card. + * + * The actual download is preceded by two sanity checks - + * - Check if firmware is already running + * - Check if the interface is the winner to download the firmware + * + * ...and followed by another - + * - Check if the firmware is downloaded successfully + * + * After download is successfully completed, the host interrupts are enabled. + */ +int mwifiex_dnld_fw(struct mwifiex_adapter *adapter, + struct mwifiex_fw_image *pmfw) +{ + int ret = 0; + u32 poll_num = 1; + int winner; + + /* Check if firmware is already running */ + ret = adapter->if_ops.check_fw_status(adapter, poll_num, &winner); + if (!ret) { + dev_notice(adapter->dev, + "WLAN FW already running! Skip FW download\n"); + goto done; + } + poll_num = MAX_FIRMWARE_POLL_TRIES; + + /* Check if we are the winner for downloading FW */ + if (!winner) { + dev_notice(adapter->dev, + "Other interface already running!" + " Skip FW download\n"); + poll_num = MAX_MULTI_INTERFACE_POLL_TRIES; + goto poll_fw; + } + if (pmfw) { + /* Download firmware with helper */ + ret = adapter->if_ops.prog_fw(adapter, pmfw); + if (ret) { + dev_err(adapter->dev, "prog_fw failed ret=%#x\n", ret); + return ret; + } + } + +poll_fw: + /* Check if the firmware is downloaded successfully or not */ + ret = adapter->if_ops.check_fw_status(adapter, poll_num, NULL); + if (ret) { + dev_err(adapter->dev, "FW failed to be active in time\n"); + return -1; + } +done: + /* re-enable host interrupt for mwifiex after fw dnld is successful */ + adapter->if_ops.enable_int(adapter); + return ret; +} diff --git a/drivers/net/wireless/mwifiex/ioctl.h b/drivers/net/wireless/mwifiex/ioctl.h new file mode 100644 index 0000000..d6babfb --- /dev/null +++ b/drivers/net/wireless/mwifiex/ioctl.h @@ -0,0 +1,433 @@ +/* + * Marvell Wireless LAN device driver: ioctl data structures & APIs + * + * Copyright (C) 2011, Marvell International Ltd. + * + * This software file (the "File") is distributed by Marvell International + * Ltd. under the terms of the GNU General Public License Version 2, June 1991 + * (the "License"). You may use, redistribute and/or modify this File in + * accordance with the terms and conditions of the License, a copy of which + * is available by writing to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the + * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. + * + * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE + * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE + * ARE EXPRESSLY DISCLAIMED. The License provides additional details about + * this warranty disclaimer. + */ + +#ifndef _MWIFIEX_IOCTL_H_ +#define _MWIFIEX_IOCTL_H_ + +#include + +enum { + MWIFIEX_SCAN_MODE_UNCHANGED = 0, + MWIFIEX_SCAN_MODE_BSS, + MWIFIEX_SCAN_MODE_IBSS, + MWIFIEX_SCAN_MODE_ANY +}; + +enum { + MWIFIEX_SCAN_TYPE_UNCHANGED = 0, + MWIFIEX_SCAN_TYPE_ACTIVE, + MWIFIEX_SCAN_TYPE_PASSIVE +}; + +struct mwifiex_get_scan_table_fixed { + u8 bssid[ETH_ALEN]; + u8 channel; + u8 rssi; + long long network_tsf; +}; + +struct mwifiex_scan_time_params { + u32 specific_scan_time; + u32 active_scan_time; + u32 passive_scan_time; +}; + +struct mwifiex_user_scan { + u32 scan_cfg_len; + u8 scan_cfg_buf[1]; +}; + +struct mwifiex_scan_req { + u32 scan_mode; + u32 scan_type; + struct mwifiex_802_11_ssid scan_ssid; + struct mwifiex_scan_time_params scan_time; + struct mwifiex_user_scan user_scan; +}; + +struct mwifiex_scan_resp { + u32 num_in_scan_table; + u8 *scan_table; +}; + +enum { + MWIFIEX_BSS_MODE_INFRA = 1, + MWIFIEX_BSS_MODE_IBSS, + MWIFIEX_BSS_MODE_AUTO +}; + +#define MWIFIEX_PROMISC_MODE 1 +#define MWIFIEX_MULTICAST_MODE 2 +#define MWIFIEX_ALL_MULTI_MODE 4 +#define MWIFIEX_MAX_MULTICAST_LIST_SIZE 32 + +struct mwifiex_multicast_list { + u32 mode; + u32 num_multicast_addr; + u8 mac_list[MWIFIEX_MAX_MULTICAST_LIST_SIZE][ETH_ALEN]; +}; + +#define MWIFIEX_MAX_CHANNEL_NUM 128 + +struct mwifiex_chan_freq { + u32 channel; + u32 freq; +}; + +struct mwifiex_chan_list { + u32 num_of_chan; + struct mwifiex_chan_freq cf[MWIFIEX_MAX_CHANNEL_NUM]; +}; + +struct mwifiex_ssid_bssid { + struct mwifiex_802_11_ssid ssid; + u8 bssid[ETH_ALEN]; +}; + +enum { + BAND_B = 1, + BAND_G = 2, + BAND_A = 4, + BAND_GN = 8, + BAND_AN = 16, +}; + +#define NO_SEC_CHANNEL 0 +#define SEC_CHANNEL_ABOVE 1 +#define SEC_CHANNEL_BELOW 3 + +struct mwifiex_ds_band_cfg { + u32 config_bands; + u32 adhoc_start_band; + u32 adhoc_channel; + u32 sec_chan_offset; +}; + +enum { + ADHOC_IDLE, + ADHOC_STARTED, + ADHOC_JOINED, + ADHOC_COALESCED +}; + +struct mwifiex_ds_get_stats { + u32 mcast_tx_frame; + u32 failed; + u32 retry; + u32 multi_retry; + u32 frame_dup; + u32 rts_success; + u32 rts_failure; + u32 ack_failure; + u32 rx_frag; + u32 mcast_rx_frame; + u32 fcs_error; + u32 tx_frame; + u32 wep_icv_error[4]; +}; + +#define BCN_RSSI_LAST_MASK 0x00000001 +#define BCN_RSSI_AVG_MASK 0x00000002 +#define DATA_RSSI_LAST_MASK 0x00000004 +#define DATA_RSSI_AVG_MASK 0x00000008 +#define BCN_SNR_LAST_MASK 0x00000010 +#define BCN_SNR_AVG_MASK 0x00000020 +#define DATA_SNR_LAST_MASK 0x00000040 +#define DATA_SNR_AVG_MASK 0x00000080 +#define BCN_NF_LAST_MASK 0x00000100 +#define BCN_NF_AVG_MASK 0x00000200 +#define DATA_NF_LAST_MASK 0x00000400 +#define DATA_NF_AVG_MASK 0x00000800 +#define ALL_RSSI_INFO_MASK 0x00000fff + +struct mwifiex_ds_get_signal { + /* + * Bit0: Last Beacon RSSI, Bit1: Average Beacon RSSI, + * Bit2: Last Data RSSI, Bit3: Average Data RSSI, + * Bit4: Last Beacon SNR, Bit5: Average Beacon SNR, + * Bit6: Last Data SNR, Bit7: Average Data SNR, + * Bit8: Last Beacon NF, Bit9: Average Beacon NF, + * Bit10: Last Data NF, Bit11: Average Data NF + */ + u16 selector; + s16 bcn_rssi_last; + s16 bcn_rssi_avg; + s16 data_rssi_last; + s16 data_rssi_avg; + s16 bcn_snr_last; + s16 bcn_snr_avg; + s16 data_snr_last; + s16 data_snr_avg; + s16 bcn_nf_last; + s16 bcn_nf_avg; + s16 data_nf_last; + s16 data_nf_avg; +}; + +struct mwifiex_fw_info { + u32 fw_ver; + u8 mac_addr[ETH_ALEN]; +}; + +#define MWIFIEX_MAX_VER_STR_LEN 128 + +struct mwifiex_ver_ext { + u32 version_str_sel; + char version_str[MWIFIEX_MAX_VER_STR_LEN]; +}; + +struct mwifiex_bss_info { + u32 bss_mode; + struct mwifiex_802_11_ssid ssid; + u32 scan_table_idx; + u32 bss_chan; + u32 region_code; + u32 media_connected; + u32 radio_on; + u32 max_power_level; + u32 min_power_level; + u32 adhoc_state; + signed int bcn_nf_last; + u32 wep_status; + u32 is_hs_configured; + u32 is_deep_sleep; + u8 bssid[ETH_ALEN]; +}; + +#define MAX_NUM_TID 8 + +#define MAX_RX_WINSIZE 64 + +struct mwifiex_ds_rx_reorder_tbl { + u16 tid; + u8 ta[ETH_ALEN]; + u32 start_win; + u32 win_size; + u32 buffer[MAX_RX_WINSIZE]; +}; + +struct mwifiex_ds_tx_ba_stream_tbl { + u16 tid; + u8 ra[ETH_ALEN]; +}; + +#define DBG_CMD_NUM 5 + +struct mwifiex_debug_info { + u32 int_counter; + u32 packets_out[MAX_NUM_TID]; + u32 max_tx_buf_size; + u32 tx_buf_size; + u32 curr_tx_buf_size; + u32 tx_tbl_num; + struct mwifiex_ds_tx_ba_stream_tbl + tx_tbl[MWIFIEX_MAX_TX_BASTREAM_SUPPORTED]; + u32 rx_tbl_num; + struct mwifiex_ds_rx_reorder_tbl rx_tbl + [MWIFIEX_MAX_RX_BASTREAM_SUPPORTED]; + u16 ps_mode; + u32 ps_state; + u8 is_deep_sleep; + u8 pm_wakeup_card_req; + u32 pm_wakeup_fw_try; + u8 is_hs_configured; + u8 hs_activated; + u32 num_cmd_host_to_card_failure; + u32 num_cmd_sleep_cfm_host_to_card_failure; + u32 num_tx_host_to_card_failure; + u32 num_event_deauth; + u32 num_event_disassoc; + u32 num_event_link_lost; + u32 num_cmd_deauth; + u32 num_cmd_assoc_success; + u32 num_cmd_assoc_failure; + u32 num_tx_timeout; + u32 num_cmd_timeout; + u16 timeout_cmd_id; + u16 timeout_cmd_act; + u16 last_cmd_id[DBG_CMD_NUM]; + u16 last_cmd_act[DBG_CMD_NUM]; + u16 last_cmd_index; + u16 last_cmd_resp_id[DBG_CMD_NUM]; + u16 last_cmd_resp_index; + u16 last_event[DBG_CMD_NUM]; + u16 last_event_index; + u8 data_sent; + u8 cmd_sent; + u8 cmd_resp_received; + u8 event_received; +}; + +enum { + MWIFIEX_AUTH_MODE_OPEN = 0x00, + MWIFIEX_AUTH_MODE_SHARED = 0x01, + MWIFIEX_AUTH_MODE_NETWORKEAP = 0x80, + MWIFIEX_AUTH_MODE_AUTO = 0xFF, +}; + +enum { + MWIFIEX_ENCRYPTION_MODE_NONE = 0, + MWIFIEX_ENCRYPTION_MODE_WEP40 = 1, + MWIFIEX_ENCRYPTION_MODE_TKIP = 2, + MWIFIEX_ENCRYPTION_MODE_CCMP = 3, + MWIFIEX_ENCRYPTION_MODE_WEP104 = 4, +}; + +#define MWIFIEX_KEY_INDEX_UNICAST 0x40000000 +#define MWIFIEX_MAX_KEY_LENGTH 32 +#define WAPI_RXPN_LEN 16 + +struct mwifiex_ds_encrypt_key { + u32 key_disable; + u32 key_index; + u32 key_len; + u8 key_material[MWIFIEX_MAX_KEY_LENGTH]; + u8 mac_addr[ETH_ALEN]; + u32 is_wapi_key; + u8 wapi_rxpn[WAPI_RXPN_LEN]; +}; + +struct mwifiex_rate_cfg { + u32 action; + u32 is_rate_auto; + u32 rate; +}; + +struct mwifiex_data_rate { + u32 tx_data_rate; + u32 rx_data_rate; +}; + +struct mwifiex_power_cfg { + u32 is_power_auto; + u32 power_level; +}; + +struct mwifiex_ds_hs_cfg { + u32 is_invoke_hostcmd; + /* Bit0: non-unicast data + * Bit1: unicast data + * Bit2: mac events + * Bit3: magic packet + */ + u32 conditions; + u32 gpio; + u32 gap; +}; + +#define DEEP_SLEEP_ON 1 +#define DEEP_SLEEP_OFF 0 + +#define DEEP_SLEEP_IDLE_TIME 100 + +struct mwifiex_ds_auto_ds { + u16 auto_ds; + u16 idle_time; +}; + +#define PS_MODE_UNCHANGED 0 +#define PS_MODE_AUTO 1 +#define PS_MODE_POLL 2 +#define PS_MODE_NULL 3 + + +struct mwifiex_ds_pm_cfg { + union { + u32 ps_mode; + struct mwifiex_ds_hs_cfg hs_cfg; + struct mwifiex_ds_auto_ds auto_deep_sleep; + u32 sleep_period; + } param; +}; + +struct mwifiex_ioctl_wmm_queue_status_ac { + u8 wmm_acm; + u8 flow_required; + u8 flow_created; + u8 disabled; +}; + +struct mwifiex_ds_wmm_queue_status { + struct mwifiex_ioctl_wmm_queue_status_ac + ac_status[IEEE80211_MAX_QUEUES]; +}; + +struct mwifiex_ds_11n_tx_cfg { + u16 tx_htcap; + u16 tx_htinfo; +}; + +struct mwifiex_ds_11n_amsdu_aggr_ctrl { + u16 enable; + u16 curr_buf_size; +}; + +#define MWIFIEX_NUM_OF_CMD_BUFFER 20 +#define MWIFIEX_SIZE_OF_CMD_BUFFER 2048 + +enum { + MWIFIEX_IE_TYPE_GEN_IE = 0, + MWIFIEX_IE_TYPE_ARP_FILTER, +}; + +enum { + MWIFIEX_REG_MAC = 1, + MWIFIEX_REG_BBP, + MWIFIEX_REG_RF, + MWIFIEX_REG_PMIC, + MWIFIEX_REG_CAU, +}; + +struct mwifiex_ds_reg_rw { + __le32 type; + __le32 offset; + __le32 value; +}; + +#define MAX_EEPROM_DATA 256 + +struct mwifiex_ds_read_eeprom { + __le16 offset; + __le16 byte_count; + u8 value[MAX_EEPROM_DATA]; +}; + +struct mwifiex_ds_misc_gen_ie { + u32 type; + u32 len; + u8 ie_data[IW_CUSTOM_MAX]; +}; + +struct mwifiex_ds_misc_cmd { + u32 len; + u8 cmd[MWIFIEX_SIZE_OF_CMD_BUFFER]; +}; + +#define MWIFIEX_MAX_VSIE_LEN (256) +#define MWIFIEX_MAX_VSIE_NUM (8) +#define MWIFIEX_VSIE_MASK_SCAN 0x01 +#define MWIFIEX_VSIE_MASK_ASSOC 0x02 +#define MWIFIEX_VSIE_MASK_ADHOC 0x04 + +enum { + MWIFIEX_FUNC_INIT = 1, + MWIFIEX_FUNC_SHUTDOWN, +}; + +#endif /* !_MWIFIEX_IOCTL_H_ */ diff --git a/drivers/net/wireless/mwifiex/join.c b/drivers/net/wireless/mwifiex/join.c new file mode 100644 index 0000000..d06f4c2 --- /dev/null +++ b/drivers/net/wireless/mwifiex/join.c @@ -0,0 +1,1464 @@ +/* + * Marvell Wireless LAN device driver: association and ad-hoc start/join + * + * Copyright (C) 2011, Marvell International Ltd. + * + * This software file (the "File") is distributed by Marvell International + * Ltd. under the terms of the GNU General Public License Version 2, June 1991 + * (the "License"). You may use, redistribute and/or modify this File in + * accordance with the terms and conditions of the License, a copy of which + * is available by writing to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the + * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. + * + * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE + * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE + * ARE EXPRESSLY DISCLAIMED. The License provides additional details about + * this warranty disclaimer. + */ + +#include "decl.h" +#include "ioctl.h" +#include "util.h" +#include "fw.h" +#include "main.h" +#include "wmm.h" +#include "11n.h" + +#define CAPINFO_MASK (~(BIT(15) | BIT(14) | BIT(12) | BIT(11) | BIT(9))) + +/* + * Append a generic IE as a pass through TLV to a TLV buffer. + * + * This function is called from the network join command preparation routine. + * + * If the IE buffer has been setup by the application, this routine appends + * the buffer as a pass through TLV type to the request. + */ +static int +mwifiex_cmd_append_generic_ie(struct mwifiex_private *priv, u8 **buffer) +{ + int ret_len = 0; + struct mwifiex_ie_types_header ie_header; + + /* Null Checks */ + if (!buffer) + return 0; + if (!(*buffer)) + return 0; + + /* + * If there is a generic ie buffer setup, append it to the return + * parameter buffer pointer. + */ + if (priv->gen_ie_buf_len) { + dev_dbg(priv->adapter->dev, "info: %s: append generic %d to %p\n", + __func__, priv->gen_ie_buf_len, *buffer); + + /* Wrap the generic IE buffer with a pass through TLV type */ + ie_header.type = cpu_to_le16(TLV_TYPE_PASSTHROUGH); + ie_header.len = cpu_to_le16(priv->gen_ie_buf_len); + memcpy(*buffer, &ie_header, sizeof(ie_header)); + + /* Increment the return size and the return buffer pointer + param */ + *buffer += sizeof(ie_header); + ret_len += sizeof(ie_header); + + /* Copy the generic IE buffer to the output buffer, advance + pointer */ + memcpy(*buffer, priv->gen_ie_buf, priv->gen_ie_buf_len); + + /* Increment the return size and the return buffer pointer + param */ + *buffer += priv->gen_ie_buf_len; + ret_len += priv->gen_ie_buf_len; + + /* Reset the generic IE buffer */ + priv->gen_ie_buf_len = 0; + } + + /* return the length appended to the buffer */ + return ret_len; +} + +/* + * Append TSF tracking info from the scan table for the target AP. + * + * This function is called from the network join command preparation routine. + * + * The TSF table TSF sent to the firmware contains two TSF values: + * - The TSF of the target AP from its previous beacon/probe response + * - The TSF timestamp of our local MAC at the time we observed the + * beacon/probe response. + * + * The firmware uses the timestamp values to set an initial TSF value + * in the MAC for the new association after a reassociation attempt. + */ +static int +mwifiex_cmd_append_tsf_tlv(struct mwifiex_private *priv, u8 **buffer, + struct mwifiex_bssdescriptor *bss_desc) +{ + struct mwifiex_ie_types_tsf_timestamp tsf_tlv; + long long tsf_val; + + /* Null Checks */ + if (buffer == NULL) + return 0; + if (*buffer == NULL) + return 0; + + memset(&tsf_tlv, 0x00, sizeof(struct mwifiex_ie_types_tsf_timestamp)); + + tsf_tlv.header.type = cpu_to_le16(TLV_TYPE_TSFTIMESTAMP); + tsf_tlv.header.len = cpu_to_le16(2 * sizeof(tsf_val)); + + memcpy(*buffer, &tsf_tlv, sizeof(tsf_tlv.header)); + *buffer += sizeof(tsf_tlv.header); + + memcpy(*buffer, &tsf_val, sizeof(tsf_val)); + *buffer += sizeof(tsf_val); + + memcpy(&tsf_val, bss_desc->time_stamp, sizeof(tsf_val)); + + dev_dbg(priv->adapter->dev, "info: %s: TSF offset calc: %016llx - " + "%016llx\n", __func__, tsf_val, bss_desc->network_tsf); + + memcpy(*buffer, &tsf_val, sizeof(tsf_val)); + *buffer += sizeof(tsf_val); + + return sizeof(tsf_tlv.header) + (2 * sizeof(tsf_val)); +} + +/* + * This function finds out the common rates between rate1 and rate2. + * + * It will fill common rates in rate1 as output if found. + * + * NOTE: Setting the MSB of the basic rates needs to be taken + * care of, either before or after calling this function. + */ +static int mwifiex_get_common_rates(struct mwifiex_private *priv, u8 *rate1, + u32 rate1_size, u8 *rate2, u32 rate2_size) +{ + int ret = 0; + u8 *ptr = rate1; + u8 *tmp = NULL; + u32 i, j; + + tmp = kmalloc(rate1_size, GFP_KERNEL); + if (!tmp) { + dev_err(priv->adapter->dev, "failed to alloc tmp buf\n"); + return -ENOMEM; + } + + memcpy(tmp, rate1, rate1_size); + memset(rate1, 0, rate1_size); + + for (i = 0; rate2[i] && i < rate2_size; i++) { + for (j = 0; tmp[j] && j < rate1_size; j++) { + /* Check common rate, excluding the bit for + basic rate */ + if ((rate2[i] & 0x7F) == (tmp[j] & 0x7F)) { + *rate1++ = tmp[j]; + break; + } + } + } + + dev_dbg(priv->adapter->dev, "info: Tx data rate set to %#x\n", + priv->data_rate); + + if (!priv->is_data_rate_auto) { + while (*ptr) { + if ((*ptr & 0x7f) == priv->data_rate) { + ret = 0; + goto done; + } + ptr++; + } + dev_err(priv->adapter->dev, "previously set fixed data rate %#x" + " is not compatible with the network\n", + priv->data_rate); + + ret = -1; + goto done; + } + + ret = 0; +done: + kfree(tmp); + return ret; +} + +/* + * This function creates the intersection of the rates supported by a + * target BSS and our adapter settings for use in an assoc/join command. + */ +static int +mwifiex_setup_rates_from_bssdesc(struct mwifiex_private *priv, + struct mwifiex_bssdescriptor *bss_desc, + u8 *out_rates, u32 *out_rates_size) +{ + u8 card_rates[MWIFIEX_SUPPORTED_RATES]; + u32 card_rates_size = 0; + + /* Copy AP supported rates */ + memcpy(out_rates, bss_desc->supported_rates, MWIFIEX_SUPPORTED_RATES); + /* Get the STA supported rates */ + card_rates_size = mwifiex_get_active_data_rates(priv, card_rates); + /* Get the common rates between AP and STA supported rates */ + if (mwifiex_get_common_rates(priv, out_rates, MWIFIEX_SUPPORTED_RATES, + card_rates, card_rates_size)) { + *out_rates_size = 0; + dev_err(priv->adapter->dev, "%s: cannot get common rates\n", + __func__); + return -1; + } + + *out_rates_size = + min_t(size_t, strlen(out_rates), MWIFIEX_SUPPORTED_RATES); + + return 0; +} + +/* + * This function updates the scan entry TSF timestamps to reflect + * a new association. + */ +static void +mwifiex_update_tsf_timestamps(struct mwifiex_private *priv, + struct mwifiex_bssdescriptor *new_bss_desc) +{ + struct mwifiex_adapter *adapter = priv->adapter; + u32 table_idx; + long long new_tsf_base; + signed long long tsf_delta; + + memcpy(&new_tsf_base, new_bss_desc->time_stamp, sizeof(new_tsf_base)); + + tsf_delta = new_tsf_base - new_bss_desc->network_tsf; + + dev_dbg(adapter->dev, "info: TSF: update TSF timestamps, " + "0x%016llx -> 0x%016llx\n", + new_bss_desc->network_tsf, new_tsf_base); + + for (table_idx = 0; table_idx < adapter->num_in_scan_table; + table_idx++) + adapter->scan_table[table_idx].network_tsf += tsf_delta; +} + +/* + * This function appends a WAPI IE. + * + * This function is called from the network join command preparation routine. + * + * If the IE buffer has been setup by the application, this routine appends + * the buffer as a WAPI TLV type to the request. + */ +static int +mwifiex_cmd_append_wapi_ie(struct mwifiex_private *priv, u8 **buffer) +{ + int retLen = 0; + struct mwifiex_ie_types_header ie_header; + + /* Null Checks */ + if (buffer == NULL) + return 0; + if (*buffer == NULL) + return 0; + + /* + * If there is a wapi ie buffer setup, append it to the return + * parameter buffer pointer. + */ + if (priv->wapi_ie_len) { + dev_dbg(priv->adapter->dev, "cmd: append wapi ie %d to %p\n", + priv->wapi_ie_len, *buffer); + + /* Wrap the generic IE buffer with a pass through TLV type */ + ie_header.type = cpu_to_le16(TLV_TYPE_WAPI_IE); + ie_header.len = cpu_to_le16(priv->wapi_ie_len); + memcpy(*buffer, &ie_header, sizeof(ie_header)); + + /* Increment the return size and the return buffer pointer + param */ + *buffer += sizeof(ie_header); + retLen += sizeof(ie_header); + + /* Copy the wapi IE buffer to the output buffer, advance + pointer */ + memcpy(*buffer, priv->wapi_ie, priv->wapi_ie_len); + + /* Increment the return size and the return buffer pointer + param */ + *buffer += priv->wapi_ie_len; + retLen += priv->wapi_ie_len; + + } + /* return the length appended to the buffer */ + return retLen; +} + +/* + * This function appends rsn ie tlv for wpa/wpa2 security modes. + * It is called from the network join command preparation routine. + */ +static int mwifiex_append_rsn_ie_wpa_wpa2(struct mwifiex_private *priv, + u8 **buffer) +{ + struct mwifiex_ie_types_rsn_param_set *rsn_ie_tlv; + int rsn_ie_len; + + if (!buffer || !(*buffer)) + return 0; + + rsn_ie_tlv = (struct mwifiex_ie_types_rsn_param_set *) (*buffer); + rsn_ie_tlv->header.type = cpu_to_le16((u16) priv->wpa_ie[0]); + rsn_ie_tlv->header.type = cpu_to_le16( + le16_to_cpu(rsn_ie_tlv->header.type) & 0x00FF); + rsn_ie_tlv->header.len = cpu_to_le16((u16) priv->wpa_ie[1]); + rsn_ie_tlv->header.len = cpu_to_le16(le16_to_cpu(rsn_ie_tlv->header.len) + & 0x00FF); + if (le16_to_cpu(rsn_ie_tlv->header.len) <= (sizeof(priv->wpa_ie) - 2)) + memcpy(rsn_ie_tlv->rsn_ie, &priv->wpa_ie[2], + le16_to_cpu(rsn_ie_tlv->header.len)); + else + return -1; + + rsn_ie_len = sizeof(rsn_ie_tlv->header) + + le16_to_cpu(rsn_ie_tlv->header.len); + *buffer += rsn_ie_len; + + return rsn_ie_len; +} + +/* + * This function prepares command for association. + * + * This sets the following parameters - + * - Peer MAC address + * - Listen interval + * - Beacon interval + * - Capability information + * + * ...and the following TLVs, as required - + * - SSID TLV + * - PHY TLV + * - SS TLV + * - Rates TLV + * - Authentication TLV + * - Channel TLV + * - WPA/WPA2 IE + * - 11n TLV + * - Vendor specific TLV + * - WMM TLV + * - WAPI IE + * - Generic IE + * - TSF TLV + * + * Preparation also includes - + * - Setting command ID and proper size + * - Ensuring correct endian-ness + */ +int mwifiex_cmd_802_11_associate(struct mwifiex_private *priv, + struct host_cmd_ds_command *cmd, + void *data_buf) +{ + struct host_cmd_ds_802_11_associate *assoc = &cmd->params.associate; + struct mwifiex_bssdescriptor *bss_desc; + struct mwifiex_ie_types_ssid_param_set *ssid_tlv; + struct mwifiex_ie_types_phy_param_set *phy_tlv; + struct mwifiex_ie_types_ss_param_set *ss_tlv; + struct mwifiex_ie_types_rates_param_set *rates_tlv; + struct mwifiex_ie_types_auth_type *auth_tlv; + struct mwifiex_ie_types_chan_list_param_set *chan_tlv; + u8 rates[MWIFIEX_SUPPORTED_RATES]; + u32 rates_size; + u16 tmp_cap; + u8 *pos; + int rsn_ie_len = 0; + + bss_desc = (struct mwifiex_bssdescriptor *) data_buf; + pos = (u8 *) assoc; + + mwifiex_cfg_tx_buf(priv, bss_desc); + + cmd->command = cpu_to_le16(HostCmd_CMD_802_11_ASSOCIATE); + + /* Save so we know which BSS Desc to use in the response handler */ + priv->attempted_bss_desc = bss_desc; + + memcpy(assoc->peer_sta_addr, + bss_desc->mac_address, sizeof(assoc->peer_sta_addr)); + pos += sizeof(assoc->peer_sta_addr); + + /* Set the listen interval */ + assoc->listen_interval = cpu_to_le16(priv->listen_interval); + /* Set the beacon period */ + assoc->beacon_period = cpu_to_le16(bss_desc->beacon_period); + + pos += sizeof(assoc->cap_info_bitmap); + pos += sizeof(assoc->listen_interval); + pos += sizeof(assoc->beacon_period); + pos += sizeof(assoc->dtim_period); + + ssid_tlv = (struct mwifiex_ie_types_ssid_param_set *) pos; + ssid_tlv->header.type = cpu_to_le16(WLAN_EID_SSID); + ssid_tlv->header.len = cpu_to_le16((u16) bss_desc->ssid.ssid_len); + memcpy(ssid_tlv->ssid, bss_desc->ssid.ssid, + le16_to_cpu(ssid_tlv->header.len)); + pos += sizeof(ssid_tlv->header) + le16_to_cpu(ssid_tlv->header.len); + + phy_tlv = (struct mwifiex_ie_types_phy_param_set *) pos; + phy_tlv->header.type = cpu_to_le16(WLAN_EID_DS_PARAMS); + phy_tlv->header.len = cpu_to_le16(sizeof(phy_tlv->fh_ds.ds_param_set)); + memcpy(&phy_tlv->fh_ds.ds_param_set, + &bss_desc->phy_param_set.ds_param_set.current_chan, + sizeof(phy_tlv->fh_ds.ds_param_set)); + pos += sizeof(phy_tlv->header) + le16_to_cpu(phy_tlv->header.len); + + ss_tlv = (struct mwifiex_ie_types_ss_param_set *) pos; + ss_tlv->header.type = cpu_to_le16(WLAN_EID_CF_PARAMS); + ss_tlv->header.len = cpu_to_le16(sizeof(ss_tlv->cf_ibss.cf_param_set)); + pos += sizeof(ss_tlv->header) + le16_to_cpu(ss_tlv->header.len); + + /* Get the common rates supported between the driver and the BSS Desc */ + if (mwifiex_setup_rates_from_bssdesc + (priv, bss_desc, rates, &rates_size)) + return -1; + + /* Save the data rates into Current BSS state structure */ + priv->curr_bss_params.num_of_rates = rates_size; + memcpy(&priv->curr_bss_params.data_rates, rates, rates_size); + + /* Setup the Rates TLV in the association command */ + rates_tlv = (struct mwifiex_ie_types_rates_param_set *) pos; + rates_tlv->header.type = cpu_to_le16(WLAN_EID_SUPP_RATES); + rates_tlv->header.len = cpu_to_le16((u16) rates_size); + memcpy(rates_tlv->rates, rates, rates_size); + pos += sizeof(rates_tlv->header) + rates_size; + dev_dbg(priv->adapter->dev, "info: ASSOC_CMD: rates size = %d\n", + rates_size); + + /* Add the Authentication type to be used for Auth frames if needed */ + if (priv->sec_info.authentication_mode != MWIFIEX_AUTH_MODE_AUTO) { + auth_tlv = (struct mwifiex_ie_types_auth_type *) pos; + auth_tlv->header.type = cpu_to_le16(TLV_TYPE_AUTH_TYPE); + auth_tlv->header.len = cpu_to_le16(sizeof(auth_tlv->auth_type)); + if (priv->sec_info.wep_status == MWIFIEX_802_11_WEP_ENABLED) + auth_tlv->auth_type = cpu_to_le16((u16) priv->sec_info. + authentication_mode); + else + auth_tlv->auth_type = + cpu_to_le16(MWIFIEX_AUTH_MODE_OPEN); + pos += sizeof(auth_tlv->header) + + le16_to_cpu(auth_tlv->header.len); + } + + if (IS_SUPPORT_MULTI_BANDS(priv->adapter) + && !(ISSUPP_11NENABLED(priv->adapter->fw_cap_info) + && (!bss_desc->disable_11n) + && (priv->adapter->config_bands & BAND_GN + || priv->adapter->config_bands & BAND_AN) + && (bss_desc->bcn_ht_cap) + ) + ) { + /* Append a channel TLV for the channel the attempted AP was + found on */ + chan_tlv = (struct mwifiex_ie_types_chan_list_param_set *) pos; + chan_tlv->header.type = cpu_to_le16(TLV_TYPE_CHANLIST); + chan_tlv->header.len = + cpu_to_le16(sizeof(struct mwifiex_chan_scan_param_set)); + + memset(chan_tlv->chan_scan_param, 0x00, + sizeof(struct mwifiex_chan_scan_param_set)); + chan_tlv->chan_scan_param[0].chan_number = + (bss_desc->phy_param_set.ds_param_set.current_chan); + dev_dbg(priv->adapter->dev, "info: Assoc: TLV Chan = %d\n", + chan_tlv->chan_scan_param[0].chan_number); + + chan_tlv->chan_scan_param[0].radio_type = + mwifiex_band_to_radio_type((u8) bss_desc->bss_band); + + dev_dbg(priv->adapter->dev, "info: Assoc: TLV Band = %d\n", + chan_tlv->chan_scan_param[0].radio_type); + pos += sizeof(chan_tlv->header) + + sizeof(struct mwifiex_chan_scan_param_set); + } + + if (!priv->wps.session_enable) { + if (priv->sec_info.wpa_enabled || priv->sec_info.wpa2_enabled) + rsn_ie_len = mwifiex_append_rsn_ie_wpa_wpa2(priv, &pos); + + if (rsn_ie_len == -1) + return -1; + } + + if (ISSUPP_11NENABLED(priv->adapter->fw_cap_info) + && (!bss_desc->disable_11n) + && (priv->adapter->config_bands & BAND_GN + || priv->adapter->config_bands & BAND_AN)) + mwifiex_cmd_append_11n_tlv(priv, bss_desc, &pos); + + /* Append vendor specific IE TLV */ + mwifiex_cmd_append_vsie_tlv(priv, MWIFIEX_VSIE_MASK_ASSOC, &pos); + + mwifiex_wmm_process_association_req(priv, &pos, &bss_desc->wmm_ie, + bss_desc->bcn_ht_cap); + if (priv->sec_info.wapi_enabled && priv->wapi_ie_len) + mwifiex_cmd_append_wapi_ie(priv, &pos); + + + mwifiex_cmd_append_generic_ie(priv, &pos); + + mwifiex_cmd_append_tsf_tlv(priv, &pos, bss_desc); + + cmd->size = cpu_to_le16((u16) (pos - (u8 *) assoc) + S_DS_GEN); + + /* Set the Capability info at last */ + tmp_cap = bss_desc->cap_info_bitmap; + + if (priv->adapter->config_bands == BAND_B) + SHORT_SLOT_TIME_DISABLED(tmp_cap); + + tmp_cap &= CAPINFO_MASK; + dev_dbg(priv->adapter->dev, "info: ASSOC_CMD: tmp_cap=%4X CAPINFO_MASK=%4lX\n", + tmp_cap, CAPINFO_MASK); + assoc->cap_info_bitmap = cpu_to_le16(tmp_cap); + + return 0; +} + +/* + * Association firmware command response handler + * + * The response buffer for the association command has the following + * memory layout. + * + * For cases where an association response was not received (indicated + * by the CapInfo and AId field): + * + * .------------------------------------------------------------. + * | Header(4 * sizeof(t_u16)): Standard command response hdr | + * .------------------------------------------------------------. + * | cap_info/Error Return(t_u16): | + * | 0xFFFF(-1): Internal error | + * | 0xFFFE(-2): Authentication unhandled message | + * | 0xFFFD(-3): Authentication refused | + * | 0xFFFC(-4): Timeout waiting for AP response | + * .------------------------------------------------------------. + * | status_code(t_u16): | + * | If cap_info is -1: | + * | An internal firmware failure prevented the | + * | command from being processed. The status_code | + * | will be set to 1. | + * | | + * | If cap_info is -2: | + * | An authentication frame was received but was | + * | not handled by the firmware. IEEE Status | + * | code for the failure is returned. | + * | | + * | If cap_info is -3: | + * | An authentication frame was received and the | + * | status_code is the IEEE Status reported in the | + * | response. | + * | | + * | If cap_info is -4: | + * | (1) Association response timeout | + * | (2) Authentication response timeout | + * .------------------------------------------------------------. + * | a_id(t_u16): 0xFFFF | + * .------------------------------------------------------------. + * + * + * For cases where an association response was received, the IEEE + * standard association response frame is returned: + * + * .------------------------------------------------------------. + * | Header(4 * sizeof(t_u16)): Standard command response hdr | + * .------------------------------------------------------------. + * | cap_info(t_u16): IEEE Capability | + * .------------------------------------------------------------. + * | status_code(t_u16): IEEE Status Code | + * .------------------------------------------------------------. + * | a_id(t_u16): IEEE Association ID | + * .------------------------------------------------------------. + * | IEEE IEs(variable): Any received IEs comprising the | + * | remaining portion of a received | + * | association response frame. | + * .------------------------------------------------------------. + * + * For simplistic handling, the status_code field can be used to determine + * an association success (0) or failure (non-zero). + */ +int mwifiex_ret_802_11_associate(struct mwifiex_private *priv, + struct host_cmd_ds_command *resp, void *wq_buf) +{ + int ret = 0; + struct mwifiex_wait_queue *wait_queue = + (struct mwifiex_wait_queue *) wq_buf; + struct ieee_types_assoc_rsp *assoc_rsp; + struct mwifiex_bssdescriptor *bss_desc; + u8 enable_data = true; + + assoc_rsp = (struct ieee_types_assoc_rsp *) &resp->params; + + priv->assoc_rsp_size = min(le16_to_cpu(resp->size) - S_DS_GEN, + sizeof(priv->assoc_rsp_buf)); + + memcpy(priv->assoc_rsp_buf, &resp->params, priv->assoc_rsp_size); + + if (le16_to_cpu(assoc_rsp->status_code)) { + priv->adapter->dbg.num_cmd_assoc_failure++; + dev_err(priv->adapter->dev, "ASSOC_RESP: association failed, " + "status code = %d, error = 0x%x, a_id = 0x%x\n", + le16_to_cpu(assoc_rsp->status_code), + le16_to_cpu(assoc_rsp->cap_info_bitmap), + le16_to_cpu(assoc_rsp->a_id)); + + ret = -1; + goto done; + } + + /* Send a Media Connected event, according to the Spec */ + priv->media_connected = true; + + priv->adapter->ps_state = PS_STATE_AWAKE; + priv->adapter->pps_uapsd_mode = false; + priv->adapter->tx_lock_flag = false; + + /* Set the attempted BSSID Index to current */ + bss_desc = priv->attempted_bss_desc; + + dev_dbg(priv->adapter->dev, "info: ASSOC_RESP: %s\n", + bss_desc->ssid.ssid); + + /* Make a copy of current BSSID descriptor */ + memcpy(&priv->curr_bss_params.bss_descriptor, + bss_desc, sizeof(struct mwifiex_bssdescriptor)); + + /* Update curr_bss_params */ + priv->curr_bss_params.bss_descriptor.channel + = bss_desc->phy_param_set.ds_param_set.current_chan; + + priv->curr_bss_params.band = (u8) bss_desc->bss_band; + + /* + * Adjust the timestamps in the scan table to be relative to the newly + * associated AP's TSF + */ + mwifiex_update_tsf_timestamps(priv, bss_desc); + + if (bss_desc->wmm_ie.vend_hdr.element_id == WLAN_EID_VENDOR_SPECIFIC) + priv->curr_bss_params.wmm_enabled = true; + else + priv->curr_bss_params.wmm_enabled = false; + + if ((priv->wmm_required || bss_desc->bcn_ht_cap) + && priv->curr_bss_params.wmm_enabled) + priv->wmm_enabled = true; + else + priv->wmm_enabled = false; + + priv->curr_bss_params.wmm_uapsd_enabled = false; + + if (priv->wmm_enabled) + priv->curr_bss_params.wmm_uapsd_enabled + = ((bss_desc->wmm_ie.qos_info_bitmap & + IEEE80211_WMM_IE_AP_QOSINFO_UAPSD) ? 1 : 0); + + dev_dbg(priv->adapter->dev, "info: ASSOC_RESP: curr_pkt_filter is %#x\n", + priv->curr_pkt_filter); + if (priv->sec_info.wpa_enabled || priv->sec_info.wpa2_enabled) + priv->wpa_is_gtk_set = false; + + if (priv->wmm_enabled) { + /* Don't re-enable carrier until we get the WMM_GET_STATUS + event */ + enable_data = false; + } else { + /* Since WMM is not enabled, setup the queues with the + defaults */ + mwifiex_wmm_setup_queue_priorities(priv, NULL); + mwifiex_wmm_setup_ac_downgrade(priv); + } + + if (enable_data) + dev_dbg(priv->adapter->dev, + "info: post association, re-enabling data flow\n"); + + /* Reset SNR/NF/RSSI values */ + priv->data_rssi_last = 0; + priv->data_nf_last = 0; + priv->data_rssi_avg = 0; + priv->data_nf_avg = 0; + priv->bcn_rssi_last = 0; + priv->bcn_nf_last = 0; + priv->bcn_rssi_avg = 0; + priv->bcn_nf_avg = 0; + priv->rxpd_rate = 0; + priv->rxpd_htinfo = 0; + + mwifiex_save_curr_bcn(priv); + + priv->adapter->dbg.num_cmd_assoc_success++; + + dev_dbg(priv->adapter->dev, "info: ASSOC_RESP: associated\n"); + + /* Add the ra_list here for infra mode as there will be only 1 ra + always */ + mwifiex_ralist_add(priv, + priv->curr_bss_params.bss_descriptor.mac_address); + + if (!netif_carrier_ok(priv->netdev)) + netif_carrier_on(priv->netdev); + if (netif_queue_stopped(priv->netdev)) + netif_wake_queue(priv->netdev); + + if (priv->sec_info.wpa_enabled || priv->sec_info.wpa2_enabled) + priv->scan_block = true; + +done: + /* Need to indicate IOCTL complete */ + if (wait_queue) { + if (ret) { + if (assoc_rsp->status_code) + wait_queue->status = + le16_to_cpu(assoc_rsp->status_code); + else + wait_queue->status = MWIFIEX_ERROR_ASSOC_FAIL; + } else { + wait_queue->status = MWIFIEX_ERROR_NO_ERROR; + } + } + + return ret; +} + +/* + * This function prepares command for ad-hoc start. + * + * Driver will fill up SSID, BSS mode, IBSS parameters, physical + * parameters, probe delay, and capability information. Firmware + * will fill up beacon period, basic rates and operational rates. + * + * In addition, the following TLVs are added - + * - Channel TLV + * - Vendor specific IE + * - WPA/WPA2 IE + * - HT Capabilities IE + * - HT Information IE + * + * Preparation also includes - + * - Setting command ID and proper size + * - Ensuring correct endian-ness + */ +int +mwifiex_cmd_802_11_ad_hoc_start(struct mwifiex_private *priv, + struct host_cmd_ds_command *cmd, void *data_buf) +{ + int ret = 0, rsn_ie_len = 0; + struct mwifiex_adapter *adapter = priv->adapter; + struct host_cmd_ds_802_11_ad_hoc_start *adhoc_start = + &cmd->params.adhoc_start; + struct mwifiex_bssdescriptor *bss_desc; + u32 cmd_append_size = 0; + u32 i; + u16 tmp_cap; + uint16_t ht_cap_info; + struct mwifiex_ie_types_chan_list_param_set *chan_tlv; + + struct mwifiex_ie_types_htcap *ht_cap; + struct mwifiex_ie_types_htinfo *ht_info; + u8 *pos = (u8 *) adhoc_start + + sizeof(struct host_cmd_ds_802_11_ad_hoc_start); + + if (!adapter) + return -1; + + cmd->command = cpu_to_le16(HostCmd_CMD_802_11_AD_HOC_START); + + bss_desc = &priv->curr_bss_params.bss_descriptor; + priv->attempted_bss_desc = bss_desc; + + /* + * Fill in the parameters for 2 data structures: + * 1. struct host_cmd_ds_802_11_ad_hoc_start command + * 2. bss_desc + * Driver will fill up SSID, bss_mode,IBSS param, Physical Param, + * probe delay, and Cap info. + * Firmware will fill up beacon period, Basic rates + * and operational rates. + */ + + memset(adhoc_start->ssid, 0, IEEE80211_MAX_SSID_LEN); + + memcpy(adhoc_start->ssid, + ((struct mwifiex_802_11_ssid *) data_buf)->ssid, + ((struct mwifiex_802_11_ssid *) data_buf)->ssid_len); + + dev_dbg(adapter->dev, "info: ADHOC_S_CMD: SSID = %s\n", + adhoc_start->ssid); + + memset(bss_desc->ssid.ssid, 0, IEEE80211_MAX_SSID_LEN); + memcpy(bss_desc->ssid.ssid, + ((struct mwifiex_802_11_ssid *) data_buf)->ssid, + ((struct mwifiex_802_11_ssid *) data_buf)->ssid_len); + + bss_desc->ssid.ssid_len = + ((struct mwifiex_802_11_ssid *) data_buf)->ssid_len; + + /* Set the BSS mode */ + adhoc_start->bss_mode = HostCmd_BSS_MODE_IBSS; + bss_desc->bss_mode = MWIFIEX_BSS_MODE_IBSS; + adhoc_start->beacon_period = cpu_to_le16(priv->beacon_period); + bss_desc->beacon_period = priv->beacon_period; + + /* Set Physical param set */ +/* Parameter IE Id */ +#define DS_PARA_IE_ID 3 +/* Parameter IE length */ +#define DS_PARA_IE_LEN 1 + + adhoc_start->phy_param_set.ds_param_set.element_id = DS_PARA_IE_ID; + adhoc_start->phy_param_set.ds_param_set.len = DS_PARA_IE_LEN; + + if (!mwifiex_get_cfp_by_band_and_channel_from_cfg80211 + (priv, adapter->adhoc_start_band, (u16) + priv->adhoc_channel)) { + struct mwifiex_chan_freq_power *cfp; + cfp = mwifiex_get_cfp_by_band_and_channel_from_cfg80211(priv, + adapter->adhoc_start_band, FIRST_VALID_CHANNEL); + if (cfp) + priv->adhoc_channel = (u8) cfp->channel; + } + + if (!priv->adhoc_channel) { + dev_err(adapter->dev, "ADHOC_S_CMD: adhoc_channel cannot be 0\n"); + return -1; + } + + dev_dbg(adapter->dev, "info: ADHOC_S_CMD: creating ADHOC on channel %d\n", + priv->adhoc_channel); + + priv->curr_bss_params.bss_descriptor.channel = priv->adhoc_channel; + priv->curr_bss_params.band = adapter->adhoc_start_band; + + bss_desc->channel = priv->adhoc_channel; + adhoc_start->phy_param_set.ds_param_set.current_chan = + priv->adhoc_channel; + + memcpy(&bss_desc->phy_param_set, &adhoc_start->phy_param_set, + sizeof(union ieee_types_phy_param_set)); + + /* Set IBSS param set */ +/* IBSS parameter IE Id */ +#define IBSS_PARA_IE_ID 6 +/* IBSS parameter IE length */ +#define IBSS_PARA_IE_LEN 2 + + adhoc_start->ss_param_set.ibss_param_set.element_id = IBSS_PARA_IE_ID; + adhoc_start->ss_param_set.ibss_param_set.len = IBSS_PARA_IE_LEN; + adhoc_start->ss_param_set.ibss_param_set.atim_window + = cpu_to_le16(priv->atim_window); + memcpy(&bss_desc->ss_param_set, &adhoc_start->ss_param_set, + sizeof(union ieee_types_ss_param_set)); + + /* Set Capability info */ + bss_desc->cap_info_bitmap |= WLAN_CAPABILITY_IBSS; + tmp_cap = le16_to_cpu(adhoc_start->cap_info_bitmap); + tmp_cap &= ~WLAN_CAPABILITY_ESS; + tmp_cap |= WLAN_CAPABILITY_IBSS; + + /* Set up privacy in bss_desc */ + if (priv->sec_info.encryption_mode != MWIFIEX_ENCRYPTION_MODE_NONE) { + /* Ad-Hoc capability privacy on */ + dev_dbg(adapter->dev, + "info: ADHOC_S_CMD: wep_status set privacy to WEP\n"); + bss_desc->privacy = MWIFIEX_802_11_PRIV_FILTER_8021X_WEP; + tmp_cap |= WLAN_CAPABILITY_PRIVACY; + } else { + dev_dbg(adapter->dev, "info: ADHOC_S_CMD: wep_status NOT set," + " setting privacy to ACCEPT ALL\n"); + bss_desc->privacy = MWIFIEX_802_11_PRIV_FILTER_ACCEPT_ALL; + } + + memset(adhoc_start->DataRate, 0, sizeof(adhoc_start->DataRate)); + mwifiex_get_active_data_rates(priv, adhoc_start->DataRate); + if ((adapter->adhoc_start_band & BAND_G) && + (priv->curr_pkt_filter & HostCmd_ACT_MAC_ADHOC_G_PROTECTION_ON)) { + ret = mwifiex_prepare_cmd(priv, HostCmd_CMD_MAC_CONTROL, + HostCmd_ACT_GEN_SET, + 0, NULL, &priv->curr_pkt_filter); + + if (ret) { + dev_err(adapter->dev, + "ADHOC_S_CMD: G Protection config failed\n"); + return -1; + } + } + /* Find the last non zero */ + for (i = 0; i < sizeof(adhoc_start->DataRate) && + adhoc_start->DataRate[i]; + i++) + ; + + priv->curr_bss_params.num_of_rates = i; + + /* Copy the ad-hoc creating rates into Current BSS rate structure */ + memcpy(&priv->curr_bss_params.data_rates, + &adhoc_start->DataRate, priv->curr_bss_params.num_of_rates); + + dev_dbg(adapter->dev, "info: ADHOC_S_CMD: rates=%02x %02x %02x %02x\n", + adhoc_start->DataRate[0], adhoc_start->DataRate[1], + adhoc_start->DataRate[2], adhoc_start->DataRate[3]); + + dev_dbg(adapter->dev, "info: ADHOC_S_CMD: AD-HOC Start command is ready\n"); + + if (IS_SUPPORT_MULTI_BANDS(adapter)) { + /* Append a channel TLV */ + chan_tlv = (struct mwifiex_ie_types_chan_list_param_set *) pos; + chan_tlv->header.type = cpu_to_le16(TLV_TYPE_CHANLIST); + chan_tlv->header.len = + cpu_to_le16(sizeof(struct mwifiex_chan_scan_param_set)); + + memset(chan_tlv->chan_scan_param, 0x00, + sizeof(struct mwifiex_chan_scan_param_set)); + chan_tlv->chan_scan_param[0].chan_number = + (u8) priv->curr_bss_params.bss_descriptor.channel; + + dev_dbg(adapter->dev, "info: ADHOC_S_CMD: TLV Chan = %d\n", + chan_tlv->chan_scan_param[0].chan_number); + + chan_tlv->chan_scan_param[0].radio_type + = mwifiex_band_to_radio_type(priv->curr_bss_params.band); + if (adapter->adhoc_start_band & BAND_GN + || adapter->adhoc_start_band & BAND_AN) { + if (adapter->chan_offset == SEC_CHANNEL_ABOVE) + chan_tlv->chan_scan_param[0].radio_type |= + SECOND_CHANNEL_ABOVE; + else if (adapter->chan_offset == SEC_CHANNEL_BELOW) + chan_tlv->chan_scan_param[0].radio_type |= + SECOND_CHANNEL_BELOW; + } + dev_dbg(adapter->dev, "info: ADHOC_S_CMD: TLV Band = %d\n", + chan_tlv->chan_scan_param[0].radio_type); + pos += sizeof(chan_tlv->header) + + sizeof(struct mwifiex_chan_scan_param_set); + cmd_append_size += + sizeof(chan_tlv->header) + + sizeof(struct mwifiex_chan_scan_param_set); + } + + /* Append vendor specific IE TLV */ + cmd_append_size += mwifiex_cmd_append_vsie_tlv(priv, + MWIFIEX_VSIE_MASK_ADHOC, &pos); + + if (priv->sec_info.wpa_enabled) { + rsn_ie_len = mwifiex_append_rsn_ie_wpa_wpa2(priv, &pos); + if (rsn_ie_len == -1) + return -1; + cmd_append_size += rsn_ie_len; + } + + if (adapter->adhoc_11n_enabled) { + { + ht_cap = (struct mwifiex_ie_types_htcap *) pos; + memset(ht_cap, 0, + sizeof(struct mwifiex_ie_types_htcap)); + ht_cap->header.type = + cpu_to_le16(WLAN_EID_HT_CAPABILITY); + ht_cap->header.len = + cpu_to_le16(sizeof(struct ieee80211_ht_cap)); + ht_cap_info = le16_to_cpu(ht_cap->ht_cap.cap_info); + + SETHT_SHORTGI20(ht_cap_info); + if (adapter->chan_offset) { + SETHT_SHORTGI40(ht_cap_info); + SETHT_DSSSCCK40(ht_cap_info); + SETHT_SUPPCHANWIDTH(ht_cap_info); + SETHT_MCS32(ht_cap->ht_cap.mcs.rx_mask); + } + + ht_cap->ht_cap.ampdu_params_info + = MAX_RX_AMPDU_SIZE_64K; + ht_cap->ht_cap.mcs.rx_mask[0] = 0xff; + pos += sizeof(struct mwifiex_ie_types_htcap); + cmd_append_size += + sizeof(struct mwifiex_ie_types_htcap); + } + { + ht_info = (struct mwifiex_ie_types_htinfo *) pos; + memset(ht_info, 0, + sizeof(struct mwifiex_ie_types_htinfo)); + ht_info->header.type = + cpu_to_le16(WLAN_EID_HT_INFORMATION); + ht_info->header.len = + cpu_to_le16(sizeof(struct ieee80211_ht_info)); + ht_info->ht_info.control_chan = + (u8) priv->curr_bss_params.bss_descriptor. + channel; + if (adapter->chan_offset) { + ht_info->ht_info.ht_param = + adapter->chan_offset; + SET_CHANWIDTH40(ht_info->ht_info.ht_param); + } + ht_info->ht_info.operation_mode = + cpu_to_le16(NON_GREENFIELD_STAS); + ht_info->ht_info.basic_set[0] = 0xff; + pos += sizeof(struct mwifiex_ie_types_htinfo); + cmd_append_size += + sizeof(struct mwifiex_ie_types_htinfo); + } + } + + cmd->size = cpu_to_le16((u16) + (sizeof(struct host_cmd_ds_802_11_ad_hoc_start) + + S_DS_GEN + cmd_append_size)); + + if (adapter->adhoc_start_band == BAND_B) + SHORT_SLOT_TIME_DISABLED(tmp_cap); + else + SHORT_SLOT_TIME_ENABLED(tmp_cap); + + adhoc_start->cap_info_bitmap = cpu_to_le16(tmp_cap); + + return 0; +} + +/* + * This function prepares command for ad-hoc join. + * + * Most of the parameters are set up by copying from the target BSS descriptor + * from the scan response. + * + * In addition, the following TLVs are added - + * - Channel TLV + * - Vendor specific IE + * - WPA/WPA2 IE + * - 11n IE + * + * Preparation also includes - + * - Setting command ID and proper size + * - Ensuring correct endian-ness + */ +int +mwifiex_cmd_802_11_ad_hoc_join(struct mwifiex_private *priv, + struct host_cmd_ds_command *cmd, void *data_buf) +{ + int ret = 0, rsn_ie_len = 0; + struct host_cmd_ds_802_11_ad_hoc_join *adhoc_join = + &cmd->params.adhoc_join; + struct mwifiex_bssdescriptor *bss_desc = + (struct mwifiex_bssdescriptor *) data_buf; + struct mwifiex_ie_types_chan_list_param_set *chan_tlv; + u32 cmd_append_size = 0; + u16 tmp_cap; + u32 i, rates_size = 0; + u16 curr_pkt_filter; + u8 *pos = + (u8 *) adhoc_join + + sizeof(struct host_cmd_ds_802_11_ad_hoc_join); + +/* Use G protection */ +#define USE_G_PROTECTION 0x02 + if (bss_desc->erp_flags & USE_G_PROTECTION) { + curr_pkt_filter = + priv-> + curr_pkt_filter | HostCmd_ACT_MAC_ADHOC_G_PROTECTION_ON; + + ret = mwifiex_prepare_cmd(priv, HostCmd_CMD_MAC_CONTROL, + HostCmd_ACT_GEN_SET, 0, NULL, + &curr_pkt_filter); + if (ret) { + dev_err(priv->adapter->dev, + "ADHOC_J_CMD: G Protection config failed\n"); + return -1; + } + } + + priv->attempted_bss_desc = bss_desc; + + cmd->command = cpu_to_le16(HostCmd_CMD_802_11_AD_HOC_JOIN); + + adhoc_join->bss_descriptor.bss_mode = HostCmd_BSS_MODE_IBSS; + + adhoc_join->bss_descriptor.beacon_period + = cpu_to_le16(bss_desc->beacon_period); + + memcpy(&adhoc_join->bss_descriptor.bssid, + &bss_desc->mac_address, ETH_ALEN); + + memcpy(&adhoc_join->bss_descriptor.ssid, + &bss_desc->ssid.ssid, bss_desc->ssid.ssid_len); + + memcpy(&adhoc_join->bss_descriptor.phy_param_set, + &bss_desc->phy_param_set, + sizeof(union ieee_types_phy_param_set)); + + memcpy(&adhoc_join->bss_descriptor.ss_param_set, + &bss_desc->ss_param_set, sizeof(union ieee_types_ss_param_set)); + + tmp_cap = bss_desc->cap_info_bitmap; + + tmp_cap &= CAPINFO_MASK; + + dev_dbg(priv->adapter->dev, "info: ADHOC_J_CMD: tmp_cap=%4X" + " CAPINFO_MASK=%4lX\n", tmp_cap, CAPINFO_MASK); + + /* Information on BSSID descriptor passed to FW */ + dev_dbg(priv->adapter->dev, "info: ADHOC_J_CMD: BSSID = %pM, SSID = %s\n", + adhoc_join->bss_descriptor.bssid, + adhoc_join->bss_descriptor.ssid); + + for (i = 0; bss_desc->supported_rates[i] && + i < MWIFIEX_SUPPORTED_RATES; + i++) + ; + rates_size = i; + + /* Copy Data Rates from the Rates recorded in scan response */ + memset(adhoc_join->bss_descriptor.data_rates, 0, + sizeof(adhoc_join->bss_descriptor.data_rates)); + memcpy(adhoc_join->bss_descriptor.data_rates, + bss_desc->supported_rates, rates_size); + + /* Copy the adhoc join rates into Current BSS state structure */ + priv->curr_bss_params.num_of_rates = rates_size; + memcpy(&priv->curr_bss_params.data_rates, bss_desc->supported_rates, + rates_size); + + /* Copy the channel information */ + priv->curr_bss_params.bss_descriptor.channel = bss_desc->channel; + priv->curr_bss_params.band = (u8) bss_desc->bss_band; + + if (priv->sec_info.wep_status == MWIFIEX_802_11_WEP_ENABLED + || priv->sec_info.wpa_enabled) + tmp_cap |= WLAN_CAPABILITY_PRIVACY; + + if (IS_SUPPORT_MULTI_BANDS(priv->adapter)) { + /* Append a channel TLV */ + chan_tlv = (struct mwifiex_ie_types_chan_list_param_set *) pos; + chan_tlv->header.type = cpu_to_le16(TLV_TYPE_CHANLIST); + chan_tlv->header.len = + cpu_to_le16(sizeof(struct mwifiex_chan_scan_param_set)); + + memset(chan_tlv->chan_scan_param, 0x00, + sizeof(struct mwifiex_chan_scan_param_set)); + chan_tlv->chan_scan_param[0].chan_number = + (bss_desc->phy_param_set.ds_param_set.current_chan); + dev_dbg(priv->adapter->dev, "info: ADHOC_J_CMD: TLV Chan = %d\n", + chan_tlv->chan_scan_param[0].chan_number); + + chan_tlv->chan_scan_param[0].radio_type = + mwifiex_band_to_radio_type((u8) bss_desc->bss_band); + + dev_dbg(priv->adapter->dev, "info: ADHOC_J_CMD: TLV Band = %d\n", + chan_tlv->chan_scan_param[0].radio_type); + pos += sizeof(chan_tlv->header) + + sizeof(struct mwifiex_chan_scan_param_set); + cmd_append_size += sizeof(chan_tlv->header) + + sizeof(struct mwifiex_chan_scan_param_set); + } + + if (priv->sec_info.wpa_enabled) + rsn_ie_len = mwifiex_append_rsn_ie_wpa_wpa2(priv, &pos); + if (rsn_ie_len == -1) + return -1; + cmd_append_size += rsn_ie_len; + + if (ISSUPP_11NENABLED(priv->adapter->fw_cap_info)) + cmd_append_size += mwifiex_cmd_append_11n_tlv(priv, + bss_desc, &pos); + + /* Append vendor specific IE TLV */ + cmd_append_size += mwifiex_cmd_append_vsie_tlv(priv, + MWIFIEX_VSIE_MASK_ADHOC, &pos); + + cmd->size = cpu_to_le16((u16) + (sizeof(struct host_cmd_ds_802_11_ad_hoc_join) + + S_DS_GEN + cmd_append_size)); + + adhoc_join->bss_descriptor.cap_info_bitmap = cpu_to_le16(tmp_cap); + + return ret; +} + +/* + * This function handles the command response of ad-hoc start and + * ad-hoc join. + * + * The function generates a device-connected event to notify + * the applications, in case of successful ad-hoc start/join, and + * saves the beacon buffer. + */ +int mwifiex_ret_802_11_ad_hoc(struct mwifiex_private *priv, + struct host_cmd_ds_command *resp, void *wq_buf) +{ + int ret = 0; + struct mwifiex_wait_queue *wait_queue = + (struct mwifiex_wait_queue *) wq_buf; + struct host_cmd_ds_802_11_ad_hoc_result *adhoc_result; + struct mwifiex_bssdescriptor *bss_desc; + u16 command = le16_to_cpu(resp->command); + u16 result = le16_to_cpu(resp->result); + + adhoc_result = &resp->params.adhoc_result; + + bss_desc = priv->attempted_bss_desc; + + /* Join result code 0 --> SUCCESS */ + if (result) { + dev_err(priv->adapter->dev, "ADHOC_RESP: failed\n"); + if (priv->media_connected) + mwifiex_reset_connect_state(priv); + + memset(&priv->curr_bss_params.bss_descriptor, + 0x00, sizeof(struct mwifiex_bssdescriptor)); + + ret = -1; + goto done; + } + + /* Send a Media Connected event, according to the Spec */ + priv->media_connected = true; + + if (command == HostCmd_CMD_802_11_AD_HOC_START) { + dev_dbg(priv->adapter->dev, "info: ADHOC_S_RESP %s\n", + bss_desc->ssid.ssid); + + /* Update the created network descriptor with the new BSSID */ + memcpy(bss_desc->mac_address, + adhoc_result->bssid, ETH_ALEN); + + priv->adhoc_state = ADHOC_STARTED; + } else { + /* + * Now the join cmd should be successful. + * If BSSID has changed use SSID to compare instead of BSSID + */ + dev_dbg(priv->adapter->dev, "info: ADHOC_J_RESP %s\n", + bss_desc->ssid.ssid); + + /* + * Make a copy of current BSSID descriptor, only needed for + * join since the current descriptor is already being used + * for adhoc start + */ + memcpy(&priv->curr_bss_params.bss_descriptor, + bss_desc, sizeof(struct mwifiex_bssdescriptor)); + + priv->adhoc_state = ADHOC_JOINED; + } + + dev_dbg(priv->adapter->dev, "info: ADHOC_RESP: channel = %d\n", + priv->adhoc_channel); + dev_dbg(priv->adapter->dev, "info: ADHOC_RESP: BSSID = %pM\n", + priv->curr_bss_params.bss_descriptor.mac_address); + + if (!netif_carrier_ok(priv->netdev)) + netif_carrier_on(priv->netdev); + if (netif_queue_stopped(priv->netdev)) + netif_wake_queue(priv->netdev); + + mwifiex_save_curr_bcn(priv); + +done: + /* Need to indicate IOCTL complete */ + if (wait_queue) { + if (ret) + wait_queue->status = MWIFIEX_ERROR_ASSOC_FAIL; + else + wait_queue->status = MWIFIEX_ERROR_NO_ERROR; + + } + + return ret; +} + +/* + * This function associates to a specific BSS discovered in a scan. + * + * It clears any past association response stored for application + * retrieval and calls the command preparation routine to send the + * command to firmware. + */ +int mwifiex_associate(struct mwifiex_private *priv, + void *wait_queue, struct mwifiex_bssdescriptor *bss_desc) +{ + int ret = 0; + u8 current_bssid[ETH_ALEN]; + + /* Return error if the adapter or table entry is not marked as infra */ + if ((priv->bss_mode != MWIFIEX_BSS_MODE_INFRA) || + (bss_desc->bss_mode != MWIFIEX_BSS_MODE_INFRA)) + return -1; + + memcpy(¤t_bssid, + &priv->curr_bss_params.bss_descriptor.mac_address, + sizeof(current_bssid)); + + /* Clear any past association response stored for application + retrieval */ + priv->assoc_rsp_size = 0; + + ret = mwifiex_prepare_cmd(priv, HostCmd_CMD_802_11_ASSOCIATE, + HostCmd_ACT_GEN_SET, 0, wait_queue, + bss_desc); + + return ret; +} + +/* + * This function starts an ad-hoc network. + * + * It calls the command preparation routine to send the command to firmware. + */ +int +mwifiex_adhoc_start(struct mwifiex_private *priv, + void *wait_queue, struct mwifiex_802_11_ssid *adhoc_ssid) +{ + int ret = 0; + + dev_dbg(priv->adapter->dev, "info: Adhoc Channel = %d\n", + priv->adhoc_channel); + dev_dbg(priv->adapter->dev, "info: curr_bss_params.channel = %d\n", + priv->curr_bss_params.bss_descriptor.channel); + dev_dbg(priv->adapter->dev, "info: curr_bss_params.band = %d\n", + priv->curr_bss_params.band); + + ret = mwifiex_prepare_cmd(priv, HostCmd_CMD_802_11_AD_HOC_START, + HostCmd_ACT_GEN_SET, 0, wait_queue, + adhoc_ssid); + + return ret; +} + +/* + * This function joins an ad-hoc network found in a previous scan. + * + * It calls the command preparation routine to send the command to firmware, + * if already not connected to the requested SSID. + */ +int mwifiex_adhoc_join(struct mwifiex_private *priv, + void *wait_queue, struct mwifiex_bssdescriptor *bss_desc) +{ + int ret = 0; + + dev_dbg(priv->adapter->dev, "info: adhoc join: curr_bss ssid =%s\n", + priv->curr_bss_params.bss_descriptor.ssid.ssid); + dev_dbg(priv->adapter->dev, "info: adhoc join: curr_bss ssid_len =%u\n", + priv->curr_bss_params.bss_descriptor.ssid.ssid_len); + dev_dbg(priv->adapter->dev, "info: adhoc join: ssid =%s\n", + bss_desc->ssid.ssid); + dev_dbg(priv->adapter->dev, "info: adhoc join: ssid_len =%u\n", + bss_desc->ssid.ssid_len); + + /* Check if the requested SSID is already joined */ + if (priv->curr_bss_params.bss_descriptor.ssid.ssid_len && + !mwifiex_ssid_cmp(&bss_desc->ssid, + &priv->curr_bss_params.bss_descriptor.ssid) && + (priv->curr_bss_params.bss_descriptor.bss_mode == + MWIFIEX_BSS_MODE_IBSS)) { + dev_dbg(priv->adapter->dev, "info: ADHOC_J_CMD: new ad-hoc SSID" + " is the same as current; not attempting to re-join\n"); + return -1; + } + + dev_dbg(priv->adapter->dev, "info: curr_bss_params.channel = %d\n", + priv->curr_bss_params.bss_descriptor.channel); + dev_dbg(priv->adapter->dev, "info: curr_bss_params.band = %c\n", + priv->curr_bss_params.band); + + ret = mwifiex_prepare_cmd(priv, HostCmd_CMD_802_11_AD_HOC_JOIN, + HostCmd_ACT_GEN_SET, 0, wait_queue, + bss_desc); + + return ret; +} + +/* + * This function deauthenticates/disconnects from infra network by sending + * deauthentication request. + */ +static int mwifiex_deauthenticate_infra(struct mwifiex_private *priv, + struct mwifiex_wait_queue *wait, + u8 *mac) +{ + u8 mac_address[ETH_ALEN]; + int ret = 0; + u8 zero_mac[ETH_ALEN] = { 0, 0, 0, 0, 0, 0 }; + + if (mac) { + if (!memcmp(mac, zero_mac, sizeof(zero_mac))) + memcpy((u8 *) &mac_address, + (u8 *) &priv->curr_bss_params.bss_descriptor. + mac_address, ETH_ALEN); + else + memcpy((u8 *) &mac_address, (u8 *) mac, ETH_ALEN); + } else { + memcpy((u8 *) &mac_address, (u8 *) &priv->curr_bss_params. + bss_descriptor.mac_address, ETH_ALEN); + } + + ret = mwifiex_prepare_cmd(priv, HostCmd_CMD_802_11_DEAUTHENTICATE, + HostCmd_ACT_GEN_SET, 0, wait, &mac_address); + + if (!ret && wait) + ret = -EINPROGRESS; + + return ret; +} + +/* + * This function deauthenticates/disconnects from a BSS. + * + * In case of infra made, it sends deauthentication request, and + * in case of ad-hoc mode, a stop network request is sent to the firmware. + */ +int mwifiex_deauthenticate(struct mwifiex_private *priv, + struct mwifiex_wait_queue *wait, u8 *mac) +{ + int ret = 0; + + if (priv->media_connected) { + if (priv->bss_mode == MWIFIEX_BSS_MODE_INFRA) { + ret = mwifiex_deauthenticate_infra(priv, wait, mac); + } else if (priv->bss_mode == MWIFIEX_BSS_MODE_IBSS) { + ret = mwifiex_prepare_cmd(priv, + HostCmd_CMD_802_11_AD_HOC_STOP, + HostCmd_ACT_GEN_SET, 0, wait, NULL); + + if (!ret && wait) + ret = -EINPROGRESS; + } + } + + return ret; +} + +/* + * This function converts band to radio type used in channel TLV. + */ +u8 +mwifiex_band_to_radio_type(u8 band) +{ + u8 ret_radio_type; + + switch (band) { + case BAND_A: + case BAND_AN: + case BAND_A | BAND_AN: + ret_radio_type = HostCmd_SCAN_RADIO_TYPE_A; + break; + case BAND_B: + case BAND_G: + case BAND_B | BAND_G: + default: + ret_radio_type = HostCmd_SCAN_RADIO_TYPE_BG; + break; + } + + return ret_radio_type; +} diff --git a/drivers/net/wireless/mwifiex/main.c b/drivers/net/wireless/mwifiex/main.c new file mode 100644 index 0000000..ed89ca4 --- /dev/null +++ b/drivers/net/wireless/mwifiex/main.c @@ -0,0 +1,1102 @@ +/* + * Marvell Wireless LAN device driver: major functions + * + * Copyright (C) 2011, Marvell International Ltd. + * + * This software file (the "File") is distributed by Marvell International + * Ltd. under the terms of the GNU General Public License Version 2, June 1991 + * (the "License"). You may use, redistribute and/or modify this File in + * accordance with the terms and conditions of the License, a copy of which + * is available by writing to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the + * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. + * + * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE + * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE + * ARE EXPRESSLY DISCLAIMED. The License provides additional details about + * this warranty disclaimer. + */ + +#include "main.h" +#include "wmm.h" +#include "cfg80211.h" +#include "11n.h" + +#define VERSION "1.0" + +const char driver_version[] = "mwifiex " VERSION " (%s) "; + +struct mwifiex_adapter *g_adapter; +EXPORT_SYMBOL_GPL(g_adapter); + +static struct mwifiex_bss_attr mwifiex_bss_sta[] = { + {MWIFIEX_BSS_TYPE_STA, MWIFIEX_DATA_FRAME_TYPE_ETH_II, true, 0, 0}, +}; + +static int drv_mode = DRV_MODE_STA; + +static char fw_name[32] = DEFAULT_FW_NAME; + +/* Supported drv_mode table */ +static struct mwifiex_drv_mode mwifiex_drv_mode_tbl[] = { + { + /* drv_mode */ + .drv_mode = DRV_MODE_STA, + /* intf number */ + .intf_num = ARRAY_SIZE(mwifiex_bss_sta), + /* bss_attr */ + .bss_attr = mwifiex_bss_sta, + } + , +}; + +/* + * This function registers the device and performs all the necessary + * initializations. + * + * The following initialization operations are performed - + * - Allocate adapter structure + * - Save interface specific operations table in adapter + * - Call interface specific initialization routine + * - Allocate private structures + * - Set default adapter structure parameters + * - Initialize locks + * + * In case of any errors during inittialization, this function also ensures + * proper cleanup before exiting. + */ +static int mwifiex_register(void *card, struct mwifiex_if_ops *if_ops, + struct mwifiex_device *mdevice, void **padapter) +{ + int ret = 0; + struct mwifiex_adapter *adapter = NULL; + u8 i = 0; + + adapter = kzalloc(sizeof(struct mwifiex_adapter), GFP_KERNEL); + /* Allocate memory for adapter structure */ + if (!adapter) + return -1; + + g_adapter = adapter; + adapter->card = card; + + /* Save interface specific operations in adapter */ + memmove(&adapter->if_ops, if_ops, sizeof(struct mwifiex_if_ops)); + + /* card specific initialization has been deferred until now .. */ + ret = adapter->if_ops.init_if(adapter); + if (ret) + goto error; + + adapter->priv_num = 0; + for (i = 0; i < MWIFIEX_MAX_BSS_NUM; i++) { + adapter->priv[i] = NULL; + + if (!mdevice->bss_attr[i].active) + continue; + + /* For valid bss_attr, + allocate memory for private structure */ + adapter->priv[i] = kzalloc(sizeof(struct mwifiex_private), + GFP_KERNEL); + if (!adapter->priv[i]) { + dev_err(adapter->dev, "%s: failed to alloc priv[%d]\n", + __func__, i); + goto error; + } + + adapter->priv_num++; + memset(adapter->priv[i], 0, + sizeof(struct mwifiex_private)); + adapter->priv[i]->adapter = adapter; + /* Save bss_type, frame_type & bss_priority */ + adapter->priv[i]->bss_type = (u8) mdevice->bss_attr[i].bss_type; + adapter->priv[i]->frame_type = + (u8) mdevice->bss_attr[i].frame_type; + adapter->priv[i]->bss_priority = + (u8) mdevice->bss_attr[i].bss_priority; + if (mdevice->bss_attr[i].bss_type == MWIFIEX_BSS_TYPE_STA) + adapter->priv[i]->bss_role = MWIFIEX_BSS_ROLE_STA; + else if (mdevice->bss_attr[i].bss_type == MWIFIEX_BSS_TYPE_UAP) + adapter->priv[i]->bss_role = MWIFIEX_BSS_ROLE_UAP; + + /* Save bss_index & bss_num */ + adapter->priv[i]->bss_index = i; + adapter->priv[i]->bss_num = mdevice->bss_attr[i].bss_num; + } + + /* Initialize lock variables */ + if (mwifiex_init_lock_list(adapter)) + goto error; + + init_timer(&adapter->cmd_timer); + adapter->cmd_timer.function = mwifiex_cmd_timeout_func; + adapter->cmd_timer.data = (unsigned long) adapter; + + /* Return pointer of struct mwifiex_adapter */ + *padapter = adapter; + return 0; + +error: + dev_dbg(adapter->dev, "info: leave mwifiex_register with error\n"); + + /* Free lock variables */ + mwifiex_free_lock_list(adapter); + for (i = 0; i < MWIFIEX_MAX_BSS_NUM; i++) + kfree(adapter->priv[i]); + kfree(adapter); + + return -1; +} + +/* + * This function unregisters the device and performs all the necessary + * cleanups. + * + * The following cleanup operations are performed - + * - Free the timers + * - Free beacon buffers + * - Free private structures + * - Free adapter structure + */ +static int mwifiex_unregister(struct mwifiex_adapter *adapter) +{ + s32 i = 0; + + del_timer(&adapter->cmd_timer); + + /* Free private structures */ + for (i = 0; i < adapter->priv_num; i++) { + if (adapter->priv[i]) { + mwifiex_free_curr_bcn(adapter->priv[i]); + kfree(adapter->priv[i]); + } + } + + kfree(adapter); + return 0; +} + +/* + * The main process. + * + * This function is the main procedure of the driver and handles various driver + * operations. It runs in a loop and provides the core functionalities. + * + * The main responsibilities of this function are - + * - Ensure concurrency control + * - Handle pending interrupts and call interrupt handlers + * - Wake up the card if required + * - Handle command responses and call response handlers + * - Handle events and call event handlers + * - Execute pending commands + * - Transmit pending data packets + */ +int mwifiex_main_process(struct mwifiex_adapter *adapter) +{ + int ret = 0; + unsigned long flags; + + spin_lock_irqsave(&adapter->main_proc_lock, flags); + + /* Check if already processing */ + if (adapter->mwifiex_processing) { + spin_unlock_irqrestore(&adapter->main_proc_lock, flags); + goto exit_main_proc; + } else { + adapter->mwifiex_processing = true; + spin_unlock_irqrestore(&adapter->main_proc_lock, flags); + } +process_start: + do { + if ((adapter->hw_status == MWIFIEX_HW_STATUS_CLOSING) || + (adapter->hw_status == MWIFIEX_HW_STATUS_NOT_READY)) + break; + + /* Handle pending interrupt if any */ + if (adapter->int_status) { + if (adapter->hs_activated) + mwifiex_process_hs_config(adapter); + adapter->if_ops.process_int_status(adapter); + } + + /* Need to wake up the card ? */ + if ((adapter->ps_state == PS_STATE_SLEEP) && + (adapter->pm_wakeup_card_req && + !adapter->pm_wakeup_fw_try) && + (is_command_pending(adapter) + || !mwifiex_wmm_lists_empty(adapter))) { + adapter->pm_wakeup_fw_try = true; + adapter->if_ops.wakeup(adapter); + continue; + } + if (IS_CARD_RX_RCVD(adapter)) { + adapter->pm_wakeup_fw_try = false; + if (adapter->ps_state == PS_STATE_SLEEP) + adapter->ps_state = PS_STATE_AWAKE; + } else { + /* We have tried to wakeup the card already */ + if (adapter->pm_wakeup_fw_try) + break; + if (adapter->ps_state != PS_STATE_AWAKE || + adapter->tx_lock_flag) + break; + + if (adapter->scan_processing || adapter->data_sent + || mwifiex_wmm_lists_empty(adapter)) { + if (adapter->cmd_sent || adapter->curr_cmd + || (!is_command_pending(adapter))) + break; + } + } + + /* Check for Cmd Resp */ + if (adapter->cmd_resp_received) { + adapter->cmd_resp_received = false; + mwifiex_process_cmdresp(adapter); + + /* call mwifiex back when init_fw is done */ + if (adapter->hw_status == MWIFIEX_HW_STATUS_INIT_DONE) { + adapter->hw_status = MWIFIEX_HW_STATUS_READY; + mwifiex_init_fw_complete(adapter); + } + } + + /* Check for event */ + if (adapter->event_received) { + adapter->event_received = false; + mwifiex_process_event(adapter); + } + + /* Check if we need to confirm Sleep Request + received previously */ + if (adapter->ps_state == PS_STATE_PRE_SLEEP) { + if (!adapter->cmd_sent && !adapter->curr_cmd) + mwifiex_check_ps_cond(adapter); + } + + /* * The ps_state may have been changed during processing of + * Sleep Request event. + */ + if ((adapter->ps_state == PS_STATE_SLEEP) + || (adapter->ps_state == PS_STATE_PRE_SLEEP) + || (adapter->ps_state == PS_STATE_SLEEP_CFM) + || adapter->tx_lock_flag) + continue; + + if (!adapter->cmd_sent && !adapter->curr_cmd) { + if (mwifiex_exec_next_cmd(adapter) == -1) { + ret = -1; + break; + } + } + + if (!adapter->scan_processing && !adapter->data_sent && + !mwifiex_wmm_lists_empty(adapter)) { + mwifiex_wmm_process_tx(adapter); + if (adapter->hs_activated) { + adapter->is_hs_configured = false; + mwifiex_hs_activated_event + (mwifiex_get_priv + (adapter, MWIFIEX_BSS_ROLE_ANY), + false); + } + } + + if (adapter->delay_null_pkt && !adapter->cmd_sent && + !adapter->curr_cmd && !is_command_pending(adapter) + && mwifiex_wmm_lists_empty(adapter)) { + if (!mwifiex_send_null_packet + (mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_STA), + MWIFIEX_TxPD_POWER_MGMT_NULL_PACKET | + MWIFIEX_TxPD_POWER_MGMT_LAST_PACKET)) { + adapter->delay_null_pkt = false; + adapter->ps_state = PS_STATE_SLEEP; + } + break; + } + } while (true); + + if ((adapter->int_status) || IS_CARD_RX_RCVD(adapter)) + goto process_start; + + spin_lock_irqsave(&adapter->main_proc_lock, flags); + adapter->mwifiex_processing = false; + spin_unlock_irqrestore(&adapter->main_proc_lock, flags); + +exit_main_proc: + if (adapter->hw_status == MWIFIEX_HW_STATUS_CLOSING) + mwifiex_shutdown_drv(adapter); + return ret; +} + +/* + * This function initializes the software. + * + * The main work includes allocating and initializing the adapter structure + * and initializing the private structures. + */ +static int +mwifiex_init_sw(void *card, struct mwifiex_if_ops *if_ops, void **pmwifiex) +{ + int i; + struct mwifiex_device device; + struct mwifiex_drv_mode *drv_mode_ptr; + + /* find mwifiex_drv_mode entry from mwifiex_drv_mode_tbl */ + drv_mode_ptr = NULL; + for (i = 0; i < ARRAY_SIZE(mwifiex_drv_mode_tbl); i++) { + if (mwifiex_drv_mode_tbl[i].drv_mode == drv_mode) { + drv_mode_ptr = &mwifiex_drv_mode_tbl[i]; + break; + } + } + + if (!drv_mode_ptr) { + pr_err("invalid drv_mode=%d\n", drv_mode); + return -1; + } + + memset(&device, 0, sizeof(struct mwifiex_device)); + + for (i = 0; i < drv_mode_ptr->intf_num; i++) { + device.bss_attr[i].bss_type = + drv_mode_ptr->bss_attr[i].bss_type; + device.bss_attr[i].frame_type = + drv_mode_ptr->bss_attr[i].frame_type; + device.bss_attr[i].active = drv_mode_ptr->bss_attr[i].active; + device.bss_attr[i].bss_priority = + drv_mode_ptr->bss_attr[i].bss_priority; + device.bss_attr[i].bss_num = drv_mode_ptr->bss_attr[i].bss_num; + } + + if (mwifiex_register(card, if_ops, &device, pmwifiex)) + return -1; + + return 0; +} + +/* + * This function frees the adapter structure. + * + * Additionally, this closes the netlink socket, frees the timers + * and private structures. + */ +static void mwifiex_free_adapter(struct mwifiex_adapter *adapter) +{ + if (!adapter) { + pr_err("%s: adapter is NULL\n", __func__); + return; + } + + mwifiex_unregister(adapter); + pr_debug("info: %s: free adapter\n", __func__); +} + +/* + * This function initializes the hardware and firmware. + * + * The main initialization steps followed are - + * - Download the correct firmware to card + * - Allocate and initialize the adapter structure + * - Initialize the private structures + * - Issue the init commands to firmware + */ +static int mwifiex_init_hw_fw(struct mwifiex_adapter *adapter) +{ + int ret = 0; + int err; + struct mwifiex_fw_image fw; + + memset(&fw, 0, sizeof(struct mwifiex_fw_image)); + + switch (adapter->revision_id) { + case SD8787_W0: + case SD8787_W1: + strcpy(fw_name, SD8787_W1_FW_NAME); + break; + case SD8787_A0: + case SD8787_A1: + strcpy(fw_name, SD8787_AX_FW_NAME); + break; + default: + break; + } + + err = request_firmware(&adapter->firmware, fw_name, adapter->dev); + if (err < 0) { + dev_err(adapter->dev, "request_firmware() returned" + " error code %#x\n", err); + ret = -1; + goto done; + } + fw.fw_buf = (u8 *) adapter->firmware->data; + fw.fw_len = adapter->firmware->size; + + ret = mwifiex_dnld_fw(adapter, &fw); + if (ret == -1) + goto done; + + dev_notice(adapter->dev, "WLAN FW is active\n"); + + adapter->init_wait_q_woken = false; + ret = mwifiex_init_fw(adapter); + if (ret == -1) { + goto done; + } else if (!ret) { + adapter->hw_status = MWIFIEX_HW_STATUS_READY; + goto done; + } + /* Wait for mwifiex_init to complete */ + wait_event_interruptible(adapter->init_wait_q, + adapter->init_wait_q_woken); + if (adapter->hw_status != MWIFIEX_HW_STATUS_READY) { + ret = -1; + goto done; + } + ret = 0; + +done: + if (adapter->firmware) + release_firmware(adapter->firmware); + if (ret) + ret = -1; + return ret; +} + +/* + * This function fills a driver buffer. + * + * The function associates a given SKB with the provided driver buffer + * and also updates some of the SKB parameters, including IP header, + * priority and timestamp. + */ +static void +mwifiex_fill_buffer(struct sk_buff *skb) +{ + struct ethhdr *eth = NULL; + struct iphdr *iph; + struct timeval tv; + u8 tid = 0; + + eth = (struct ethhdr *) skb->data; + switch (eth->h_proto) { + case __constant_htons(ETH_P_IP): + iph = ip_hdr(skb); + tid = IPTOS_PREC(iph->tos); + pr_debug("data: packet type ETH_P_IP: %04x, tid=%#x prio=%#x\n", + eth->h_proto, tid, skb->priority); + break; + case __constant_htons(ETH_P_ARP): + pr_debug("data: ARP packet: %04x\n", eth->h_proto); + default: + break; + } +/* Offset for TOS field in the IP header */ +#define IPTOS_OFFSET 5 + tid = (tid >> IPTOS_OFFSET); + skb->priority = tid; + /* Record the current time the packet was queued; used to + determine the amount of time the packet was queued in + the driver before it was sent to the firmware. + The delay is then sent along with the packet to the + firmware for aggregate delay calculation for stats and + MSDU lifetime expiry. + */ + do_gettimeofday(&tv); + skb->tstamp = timeval_to_ktime(tv); + return; +} + +/* + * CFG802.11 network device handler for open. + * + * Starts the data queue. + */ +static int +mwifiex_open(struct net_device *dev) +{ + netif_start_queue(dev); + return 0; +} + +/* + * CFG802.11 network device handler for close. + */ +static int +mwifiex_close(struct net_device *dev) +{ + return 0; +} + +/* + * CFG802.11 network device handler for data transmission. + */ +static int +mwifiex_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) +{ + struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev); + struct sk_buff *new_skb = NULL; + struct mwifiex_txinfo *tx_info; + + dev_dbg(priv->adapter->dev, "data: %lu BSS(%d): Data <= kernel\n", + jiffies, priv->bss_index); + + if (priv->adapter->surprise_removed) { + kfree(skb); + priv->stats.tx_dropped++; + return 0; + } + if (!skb->len || (skb->len > ETH_FRAME_LEN)) { + dev_err(priv->adapter->dev, "Tx: bad skb len %d\n", skb->len); + kfree(skb); + priv->stats.tx_dropped++; + return 0; + } + if (skb_headroom(skb) < MWIFIEX_MIN_DATA_HEADER_LEN) { + dev_dbg(priv->adapter->dev, + "data: Tx: insufficient skb headroom %d\n", + skb_headroom(skb)); + /* Insufficient skb headroom - allocate a new skb */ + new_skb = + skb_realloc_headroom(skb, MWIFIEX_MIN_DATA_HEADER_LEN); + if (unlikely(!new_skb)) { + dev_err(priv->adapter->dev, "Tx: cannot alloca new_skb\n"); + kfree(skb); + priv->stats.tx_dropped++; + return 0; + } + kfree_skb(skb); + skb = new_skb; + dev_dbg(priv->adapter->dev, "info: new skb headroomd %d\n", + skb_headroom(skb)); + } + + tx_info = MWIFIEX_SKB_TXCB(skb); + tx_info->bss_index = priv->bss_index; + mwifiex_fill_buffer(skb); + + mwifiex_wmm_add_buf_txqueue(priv->adapter, skb); + atomic_inc(&priv->adapter->tx_pending); + + if (atomic_read(&priv->adapter->tx_pending) >= MAX_TX_PENDING) { + netif_stop_queue(priv->netdev); + dev->trans_start = jiffies; + } + + queue_work(priv->adapter->workqueue, &priv->adapter->main_work); + + return 0; +} + +/* + * CFG802.11 network device handler for setting MAC address. + */ +static int +mwifiex_set_mac_address(struct net_device *dev, void *addr) +{ + struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev); + struct sockaddr *hw_addr = (struct sockaddr *) addr; + + memcpy(priv->curr_addr, hw_addr->sa_data, ETH_ALEN); + + if (mwifiex_request_set_mac_address(priv)) { + dev_err(priv->adapter->dev, "set MAC address failed\n"); + return -EFAULT; + } + memcpy(dev->dev_addr, priv->curr_addr, ETH_ALEN); + + return 0; +} + +/* + * CFG802.11 network device handler for setting multicast list. + */ +static void mwifiex_set_multicast_list(struct net_device *dev) +{ + struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev); + mwifiex_request_set_multicast_list(priv, dev); +} + +/* + * CFG802.11 network device handler for transmission timeout. + */ +static void +mwifiex_tx_timeout(struct net_device *dev) +{ + struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev); + + dev_err(priv->adapter->dev, "%lu : Tx timeout, bss_index=%d\n", + jiffies, priv->bss_index); + dev->trans_start = jiffies; + priv->num_tx_timeout++; +} + +/* + * CFG802.11 network device handler for statistics retrieval. + */ +static struct net_device_stats *mwifiex_get_stats(struct net_device *dev) +{ + struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev); + + return &priv->stats; +} + +/* Network device handlers */ +static const struct net_device_ops mwifiex_netdev_ops = { + .ndo_open = mwifiex_open, + .ndo_stop = mwifiex_close, + .ndo_start_xmit = mwifiex_hard_start_xmit, + .ndo_set_mac_address = mwifiex_set_mac_address, + .ndo_tx_timeout = mwifiex_tx_timeout, + .ndo_get_stats = mwifiex_get_stats, + .ndo_set_multicast_list = mwifiex_set_multicast_list, +}; + +/* + * This function initializes the private structure parameters. + * + * The following wait queues are initialized - + * - IOCTL wait queue + * - Command wait queue + * - Statistics wait queue + * + * ...and the following default parameters are set - + * - Current key index : Set to 0 + * - Rate index : Set to auto + * - Media connected : Set to disconnected + * - Adhoc link sensed : Set to false + * - Nick name : Set to null + * - Number of Tx timeout : Set to 0 + * - Device address : Set to current address + * + * In addition, the CFG80211 work queue is also created. + */ +static void +mwifiex_init_priv_params(struct mwifiex_private *priv, struct net_device *dev) +{ + dev->netdev_ops = &mwifiex_netdev_ops; + /* Initialize private structure */ + init_waitqueue_head(&priv->ioctl_wait_q); + init_waitqueue_head(&priv->cmd_wait_q); + init_waitqueue_head(&priv->w_stats_wait_q); + priv->current_key_index = 0; + priv->media_connected = false; + memset(&priv->nick_name, 0, sizeof(priv->nick_name)); + priv->num_tx_timeout = 0; + priv->workqueue = create_singlethread_workqueue("cfg80211_wq"); + INIT_WORK(&priv->cfg_workqueue, mwifiex_cfg80211_results); + memcpy(dev->dev_addr, priv->curr_addr, ETH_ALEN); +} + +/* + * This function adds a new logical interface. + * + * It allocates, initializes and registers the interface by performing + * the following opearations - + * - Allocate a new net device structure + * - Assign device name + * - Register the new device with CFG80211 subsystem + * - Initialize semaphore and private structure + * - Register the new device with kernel + * - Create the complete debug FS structure if configured + */ +static struct mwifiex_private *mwifiex_add_interface( + struct mwifiex_adapter *adapter, + u8 bss_index, u8 bss_type) +{ + struct net_device *dev = NULL; + struct mwifiex_private *priv = NULL; + void *mdev_priv = NULL; + + dev = alloc_netdev_mq(sizeof(struct mwifiex_private *), "mlan%d", + ether_setup, 1); + if (!dev) { + dev_err(adapter->dev, "no memory available for netdevice\n"); + goto error; + } + if (dev_alloc_name(dev, dev->name)) { + dev_err(adapter->dev, "unable to alloc name for netdevice\n"); + goto error; + } + + if (mwifiex_register_cfg80211(dev, adapter->priv[bss_index]->curr_addr, + adapter->priv[bss_index]) != 0) { + dev_err(adapter->dev, "cannot register netdevice with cfg80211\n"); + goto error; + } + /* Save the priv pointer in netdev */ + priv = adapter->priv[bss_index]; + mdev_priv = netdev_priv(dev); + *((unsigned long *) mdev_priv) = (unsigned long) priv; + + priv->netdev = dev; + + sema_init(&priv->async_sem, 1); + priv->scan_pending_on_block = false; + + mwifiex_init_priv_params(priv, dev); + + SET_NETDEV_DEV(dev, adapter->dev); + + /* Register network device */ + if (register_netdev(dev)) { + dev_err(adapter->dev, "cannot register virtual network device\n"); + goto error; + } + + dev_dbg(adapter->dev, "info: %s: Marvell 802.11 Adapter\n", dev->name); +#ifdef CONFIG_DEBUG_FS + mwifiex_dev_debugfs_init(priv); +#endif + return priv; +error: + if (dev) + free_netdev(dev); + return NULL; +} + +/* + * This function removes a logical interface. + * + * It deregisters, resets and frees the interface by performing + * the following operations - + * - Disconnect the device if connected, send wireless event to + * notify applications. + * - Remove the debug FS structure if configured + * - Unregister the device from kernel + * - Free the net device structure + * - Cancel all works and destroy work queue + * - Unregister and free the wireless device from CFG80211 subsystem + */ +static void +mwifiex_remove_interface(struct mwifiex_adapter *adapter, u8 bss_index) +{ + struct net_device *dev = NULL; + struct mwifiex_private *priv = adapter->priv[bss_index]; + + if (!priv) + return; + dev = priv->netdev; + + if (priv->media_connected) + priv->media_connected = false; + +#ifdef CONFIG_DEBUG_FS + mwifiex_dev_debugfs_remove(priv); +#endif + /* Last reference is our one */ + dev_dbg(adapter->dev, "info: %s: refcnt = %d\n", + dev->name, netdev_refcnt_read(dev)); + + if (dev->reg_state == NETREG_REGISTERED) + unregister_netdev(dev); + + /* Clear the priv in adapter */ + priv->netdev = NULL; + if (dev) + free_netdev(dev); + + cancel_work_sync(&priv->cfg_workqueue); + flush_workqueue(priv->workqueue); + destroy_workqueue(priv->workqueue); + wiphy_unregister(priv->wdev->wiphy); + wiphy_free(priv->wdev->wiphy); + kfree(priv->wdev); + + return; +} + +/* + * Sends IOCTL request to shutdown firmware. + * + * This function allocates the IOCTL request buffer, fills it + * with requisite parameters and calls the IOCTL handler. + */ +int mwifiex_shutdown_fw(struct mwifiex_private *priv, u8 wait_option) +{ + struct mwifiex_wait_queue *wait = NULL; + int status = 0; + + /* Allocate an IOCTL request buffer */ + wait = mwifiex_alloc_fill_wait_queue(priv, wait_option); + if (!wait) + return -ENOMEM; + + status = mwifiex_misc_ioctl_init_shutdown(priv->adapter, wait, + MWIFIEX_FUNC_SHUTDOWN); + + status = mwifiex_request_ioctl(priv, wait, status, wait_option); + + kfree(wait); + return status; +} +EXPORT_SYMBOL_GPL(mwifiex_shutdown_fw); + +/* + * This function check if command is pending. + */ +int is_command_pending(struct mwifiex_adapter *adapter) +{ + unsigned long flags; + int is_cmd_pend_q_empty; + + spin_lock_irqsave(&adapter->cmd_pending_q_lock, flags); + is_cmd_pend_q_empty = list_empty(&adapter->cmd_pending_q); + spin_unlock_irqrestore(&adapter->cmd_pending_q_lock, flags); + + return !is_cmd_pend_q_empty; +} + +/* + * This function returns the correct private structure pointer based + * upon the BSS number. + */ +struct mwifiex_private * +mwifiex_bss_index_to_priv(struct mwifiex_adapter *adapter, u8 bss_index) +{ + if (!adapter || (bss_index >= adapter->priv_num)) + return NULL; + return adapter->priv[bss_index]; +} + +/* + * This is the main work queue function. + * + * It handles the main process, which in turn handles the complete + * driver operations. + */ +static void mwifiex_main_work_queue(struct work_struct *work) +{ + struct mwifiex_adapter *adapter = + container_of(work, struct mwifiex_adapter, main_work); + + if (adapter->surprise_removed) + return; + mwifiex_main_process(adapter); +} + +/* + * This function cancels all works in the queue and destroys + * the main workqueue. + */ +static void +mwifiex_terminate_workqueue(struct mwifiex_adapter *adapter) +{ + flush_workqueue(adapter->workqueue); + destroy_workqueue(adapter->workqueue); + adapter->workqueue = NULL; +} + +/* + * This function adds the card. + * + * This function follows the following major steps to set up the device - + * - Initialize software. This includes probing the card, registering + * the interface operations table, and allocating/initializing the + * adapter structure + * - Set up the netlink socket + * - Create and start the main work queue + * - Register the device + * - Initialize firmware and hardware + * - Add logical interfaces + */ +int +mwifiex_add_card(void *card, struct semaphore *sem, + struct mwifiex_if_ops *if_ops) +{ + int status = 0; + int i; + struct mwifiex_adapter *adapter = NULL; + struct mwifiex_drv_mode *drv_mode_info = &mwifiex_drv_mode_tbl[0]; + + if (down_interruptible(sem)) + goto exit_sem_err; + + if (mwifiex_init_sw(card, if_ops, (void **) &adapter)) { + pr_err("%s: software init failed\n", __func__); + goto err_init_sw; + } + + adapter->drv_mode = drv_mode_info; + + adapter->hw_status = MWIFIEX_HW_STATUS_INITIALIZING; + /* PnP and power profile */ + adapter->surprise_removed = false; + init_waitqueue_head(&adapter->init_wait_q); + adapter->is_suspended = false; + adapter->hs_activated = false; + init_waitqueue_head(&adapter->hs_activate_wait_q); + + /* Create workqueue */ + adapter->workqueue = create_workqueue("MWIFIEX_WORK_QUEUE"); + if (!adapter->workqueue) + goto err_kmalloc; + + INIT_WORK(&adapter->main_work, mwifiex_main_work_queue); + + /* Register the device. Fill up the private data structure with relevant + information from the card and request for the required IRQ. */ + if (adapter->if_ops.register_dev(adapter)) { + pr_err("%s: failed to register mwifiex device\n", __func__); + goto err_registerdev; + } + + /* Init FW and HW */ + if (mwifiex_init_hw_fw(adapter)) { + pr_err("%s: firmware init failed\n", __func__); + goto err_init_fw; + } + /* Add interfaces */ + for (i = 0; i < drv_mode_info->intf_num; i++) { + if (!mwifiex_add_interface(adapter, i, + adapter->drv_mode->bss_attr[i].bss_type)) { + status = -1; + break; + } + } + if (status) + goto err_add_intf; + + up(sem); + + return 0; + +err_add_intf: + for (i = 0; i < adapter->priv_num; i++) + mwifiex_remove_interface(adapter, i); +err_init_fw: + /* Unregister device */ + pr_debug("info: %s: unregister device\n", __func__); + adapter->if_ops.unregister_dev(adapter); +err_registerdev: + adapter->surprise_removed = true; + mwifiex_terminate_workqueue(adapter); +err_kmalloc: + if ((adapter->hw_status == MWIFIEX_HW_STATUS_FW_READY) || + (adapter->hw_status == MWIFIEX_HW_STATUS_READY)) { + pr_debug("info: %s: shutdown mwifiex\n", __func__); + adapter->init_wait_q_woken = false; + status = mwifiex_shutdown_drv(adapter); + if (status == -EINPROGRESS) + wait_event_interruptible(adapter->init_wait_q, + adapter->init_wait_q_woken); + } + + mwifiex_free_adapter(adapter); + +err_init_sw: + up(sem); + +exit_sem_err: + return -1; +} +EXPORT_SYMBOL_GPL(mwifiex_add_card); + +/* + * This function removes the card. + * + * This function follows the following major steps to remove the device - + * - Stop data traffic + * - Shutdown firmware + * - Remove the logical interfaces + * - Terminate the work queue + * - Unregister the device + * - Free the adapter structure + */ +int mwifiex_remove_card(struct mwifiex_adapter *adapter, struct semaphore *sem) +{ + struct mwifiex_private *priv = NULL; + int status; + int i; + + if (down_interruptible(sem)) + goto exit_sem_err; + + if (!adapter) + goto exit_remove; + + adapter->surprise_removed = true; + + /* Stop data */ + for (i = 0; i < adapter->priv_num; i++) { + priv = adapter->priv[i]; + if (priv) { + if (!netif_queue_stopped(priv->netdev)) + netif_stop_queue(priv->netdev); + if (netif_carrier_ok(priv->netdev)) + netif_carrier_off(priv->netdev); + } + } + + dev_dbg(adapter->dev, "cmd: calling mwifiex_shutdown_drv...\n"); + adapter->init_wait_q_woken = false; + status = mwifiex_shutdown_drv(adapter); + if (status == -EINPROGRESS) + wait_event_interruptible(adapter->init_wait_q, + adapter->init_wait_q_woken); + dev_dbg(adapter->dev, "cmd: mwifiex_shutdown_drv done\n"); + if (atomic_read(&adapter->rx_pending) || + atomic_read(&adapter->tx_pending) || + atomic_read(&adapter->ioctl_pending)) { + dev_err(adapter->dev, "rx_pending=%d, tx_pending=%d, " + "ioctl_pending=%d\n", + atomic_read(&adapter->rx_pending), + atomic_read(&adapter->tx_pending), + atomic_read(&adapter->ioctl_pending)); + } + + /* Remove interface */ + for (i = 0; i < adapter->priv_num; i++) + mwifiex_remove_interface(adapter, i); + + mwifiex_terminate_workqueue(adapter); + + /* Unregister device */ + dev_dbg(adapter->dev, "info: unregister device\n"); + adapter->if_ops.unregister_dev(adapter); + /* Free adapter structure */ + dev_dbg(adapter->dev, "info: free adapter\n"); + mwifiex_free_adapter(adapter); + +exit_remove: + up(sem); +exit_sem_err: + return 0; +} +EXPORT_SYMBOL_GPL(mwifiex_remove_card); + +/* + * This function initializes the module. + * + * The debug FS is also initialized if configured. + */ +static int +mwifiex_init_module(void) +{ +#ifdef CONFIG_DEBUG_FS + mwifiex_debugfs_init(); +#endif + return 0; +} + +/* + * This function cleans up the module. + * + * The debug FS is removed if available. + */ +static void +mwifiex_cleanup_module(void) +{ +#ifdef CONFIG_DEBUG_FS + mwifiex_debugfs_remove(); +#endif +} + +module_init(mwifiex_init_module); +module_exit(mwifiex_cleanup_module); + +MODULE_AUTHOR("Marvell International Ltd."); +MODULE_DESCRIPTION("Marvell WiFi-Ex Driver version " VERSION); +MODULE_VERSION(VERSION); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/net/wireless/mwifiex/main.h b/drivers/net/wireless/mwifiex/main.h new file mode 100644 index 0000000..2b0ad8e --- /dev/null +++ b/drivers/net/wireless/mwifiex/main.h @@ -0,0 +1,1081 @@ +/* + * Marvell Wireless LAN device driver: major data structures and prototypes + * + * Copyright (C) 2011, Marvell International Ltd. + * + * This software file (the "File") is distributed by Marvell International + * Ltd. under the terms of the GNU General Public License Version 2, June 1991 + * (the "License"). You may use, redistribute and/or modify this File in + * accordance with the terms and conditions of the License, a copy of which + * is available by writing to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the + * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. + * + * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE + * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE + * ARE EXPRESSLY DISCLAIMED. The License provides additional details about + * this warranty disclaimer. + */ + +#ifndef _MWIFIEX_MAIN_H_ +#define _MWIFIEX_MAIN_H_ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "decl.h" +#include "ioctl.h" +#include "util.h" +#include "fw.h" + +extern const char driver_version[]; +extern struct mwifiex_adapter *g_adapter; + +enum { + MWIFIEX_NO_WAIT, + MWIFIEX_IOCTL_WAIT, + MWIFIEX_CMD_WAIT, + MWIFIEX_PROC_WAIT, + MWIFIEX_WSTATS_WAIT +}; + +#define DRV_MODE_STA 0x1 +#define DRV_MODE_UAP 0x2 +#define DRV_MODE_UAP_STA 0x3 + +#define SD8787_W0 0x30 +#define SD8787_W1 0x31 +#define SD8787_A0 0x40 +#define SD8787_A1 0x41 + +#define DEFAULT_FW_NAME "mrvl/sd8787_uapsta.bin" +#define SD8787_W1_FW_NAME "mrvl/sd8787_uapsta_w1.bin" +#define SD8787_AX_FW_NAME "mrvl/sd8787_uapsta.bin" + +struct mwifiex_drv_mode { + u16 drv_mode; + u16 intf_num; + struct mwifiex_bss_attr *bss_attr; +}; + + +#define MWIFIEX_DEFAULT_WATCHDOG_TIMEOUT (5 * HZ) + +#define MWIFIEX_TIMER_10S 10000 +#define MWIFIEX_TIMER_1S 1000 + +#define NL_MAX_PAYLOAD 1024 +#define NL_MULTICAST_GROUP 1 + +#define MAX_TX_PENDING 60 + +#define HEADER_ALIGNMENT 8 + +#define MWIFIEX_UPLD_SIZE (2312) + +#define MAX_EVENT_SIZE 1024 + +#define ARP_FILTER_MAX_BUF_SIZE 68 + +#define MWIFIEX_KEY_BUFFER_SIZE 16 +#define MWIFIEX_DEFAULT_LISTEN_INTERVAL 10 +#define MWIFIEX_MAX_REGION_CODE 7 + +#define DEFAULT_BCN_AVG_FACTOR 8 +#define DEFAULT_DATA_AVG_FACTOR 8 + +#define FIRST_VALID_CHANNEL 0xff +#define DEFAULT_AD_HOC_CHANNEL 6 +#define DEFAULT_AD_HOC_CHANNEL_A 36 + +#define DEFAULT_BCN_MISS_TIMEOUT 5 + +#define MAX_SCAN_BEACON_BUFFER 8000 + +#define SCAN_BEACON_ENTRY_PAD 6 + +#define MWIFIEX_PASSIVE_SCAN_CHAN_TIME 200 +#define MWIFIEX_ACTIVE_SCAN_CHAN_TIME 200 +#define MWIFIEX_SPECIFIC_SCAN_CHAN_TIME 110 + +#define SCAN_RSSI(RSSI) (0x100 - ((u8)(RSSI))) + +#define MWIFIEX_MAX_TOTAL_SCAN_TIME (MWIFIEX_TIMER_10S - MWIFIEX_TIMER_1S) + +#define RSN_GTK_OUI_OFFSET 2 + +#define MWIFIEX_OUI_NOT_PRESENT 0 +#define MWIFIEX_OUI_PRESENT 1 + +#define IS_CARD_RX_RCVD(adapter) (adapter->cmd_resp_received || \ + adapter->event_received || \ + adapter->data_received) + +#define MWIFIEX_TYPE_CMD 1 +#define MWIFIEX_TYPE_DATA 0 +#define MWIFIEX_TYPE_EVENT 3 + +#define DBG_CMD_NUM 5 + +#define MAX_BITMAP_RATES_SIZE 10 + +#define MAX_CHANNEL_BAND_BG 14 + +#define MAX_FREQUENCY_BAND_BG 2484 + +struct mwifiex_dbg { + u32 num_cmd_host_to_card_failure; + u32 num_cmd_sleep_cfm_host_to_card_failure; + u32 num_tx_host_to_card_failure; + u32 num_event_deauth; + u32 num_event_disassoc; + u32 num_event_link_lost; + u32 num_cmd_deauth; + u32 num_cmd_assoc_success; + u32 num_cmd_assoc_failure; + u32 num_tx_timeout; + u32 num_cmd_timeout; + u16 timeout_cmd_id; + u16 timeout_cmd_act; + u16 last_cmd_id[DBG_CMD_NUM]; + u16 last_cmd_act[DBG_CMD_NUM]; + u16 last_cmd_index; + u16 last_cmd_resp_id[DBG_CMD_NUM]; + u16 last_cmd_resp_index; + u16 last_event[DBG_CMD_NUM]; + u16 last_event_index; +}; + +enum MWIFIEX_HARDWARE_STATUS { + MWIFIEX_HW_STATUS_READY, + MWIFIEX_HW_STATUS_INITIALIZING, + MWIFIEX_HW_STATUS_FW_READY, + MWIFIEX_HW_STATUS_INIT_DONE, + MWIFIEX_HW_STATUS_RESET, + MWIFIEX_HW_STATUS_CLOSING, + MWIFIEX_HW_STATUS_NOT_READY +}; + +enum MWIFIEX_802_11_POWER_MODE { + MWIFIEX_802_11_POWER_MODE_CAM, + MWIFIEX_802_11_POWER_MODE_PSP +}; + +struct mwifiex_tx_param { + u32 next_pkt_len; +}; + +enum MWIFIEX_PS_STATE { + PS_STATE_AWAKE, + PS_STATE_PRE_SLEEP, + PS_STATE_SLEEP_CFM, + PS_STATE_SLEEP +}; + +struct mwifiex_add_ba_param { + u32 tx_win_size; + u32 rx_win_size; + u32 timeout; +}; + +struct mwifiex_tx_aggr { + u8 ampdu_user; + u8 ampdu_ap; + u8 amsdu; +}; + +struct mwifiex_ra_list_tbl { + struct list_head list; + struct sk_buff_head skb_head; + u8 ra[ETH_ALEN]; + u32 total_pkts_size; + u32 is_11n_enabled; +}; + +struct mwifiex_tid_tbl { + struct list_head ra_list; + /* spin lock for tid table */ + spinlock_t tid_tbl_lock; + struct mwifiex_ra_list_tbl *ra_list_curr; +}; + +#define WMM_HIGHEST_PRIORITY 7 +#define HIGH_PRIO_TID 7 +#define LOW_PRIO_TID 0 + +struct mwifiex_wmm_desc { + struct mwifiex_tid_tbl tid_tbl_ptr[MAX_NUM_TID]; + u32 packets_out[MAX_NUM_TID]; + /* spin lock to protect ra_list */ + spinlock_t ra_list_spinlock; + struct mwifiex_wmm_ac_status ac_status[IEEE80211_MAX_QUEUES]; + enum mwifiex_wmm_ac_e ac_down_graded_vals[IEEE80211_MAX_QUEUES]; + u32 drv_pkt_delay_max; + u8 queue_priority[IEEE80211_MAX_QUEUES]; + u32 user_pri_pkt_tx_ctrl[WMM_HIGHEST_PRIORITY + 1]; /* UP: 0 to 7 */ + +}; + +struct mwifiex_802_11_security { + u8 wpa_enabled; + u8 wpa2_enabled; + u8 wapi_enabled; + u8 wapi_key_on; + enum MWIFIEX_802_11_WEP_STATUS wep_status; + u32 authentication_mode; + u32 encryption_mode; +}; + +struct ieee_types_header { + u8 element_id; + u8 len; +} __packed; + +struct ieee_obss_scan_param { + u16 obss_scan_passive_dwell; + u16 obss_scan_active_dwell; + u16 bss_chan_width_trigger_scan_int; + u16 obss_scan_passive_total; + u16 obss_scan_active_total; + u16 bss_width_chan_trans_delay; + u16 obss_scan_active_threshold; +} __packed; + +struct ieee_types_obss_scan_param { + struct ieee_types_header ieee_hdr; + struct ieee_obss_scan_param obss_scan; +} __packed; + +#define MWIFIEX_SUPPORTED_RATES 14 + +#define MWIFIEX_SUPPORTED_RATES_EXT 32 + +#define IEEE_MAX_IE_SIZE 256 + +struct ieee_types_vendor_specific { + struct ieee_types_vendor_header vend_hdr; + u8 data[IEEE_MAX_IE_SIZE - sizeof(struct ieee_types_vendor_header)]; +} __packed; + +struct ieee_types_generic { + struct ieee_types_header ieee_hdr; + u8 data[IEEE_MAX_IE_SIZE - sizeof(struct ieee_types_header)]; +} __packed; + +struct mwifiex_bssdescriptor { + u8 mac_address[ETH_ALEN]; + struct mwifiex_802_11_ssid ssid; + u32 privacy; + s32 rssi; + u32 channel; + u32 freq; + u16 beacon_period; + u8 erp_flags; + u32 bss_mode; + u8 supported_rates[MWIFIEX_SUPPORTED_RATES]; + u8 data_rates[MWIFIEX_SUPPORTED_RATES]; + /* Network band. + * BAND_B(0x01): 'b' band + * BAND_G(0x02): 'g' band + * BAND_A(0X04): 'a' band + */ + u16 bss_band; + long long network_tsf; + u8 time_stamp[8]; + union ieee_types_phy_param_set phy_param_set; + union ieee_types_ss_param_set ss_param_set; + u16 cap_info_bitmap; + struct ieee_types_wmm_parameter wmm_ie; + u8 disable_11n; + struct ieee80211_ht_cap *bcn_ht_cap; + u16 ht_cap_offset; + struct ieee80211_ht_info *bcn_ht_info; + u16 ht_info_offset; + u8 *bcn_bss_co_2040; + u16 bss_co_2040_offset; + u8 *bcn_ext_cap; + u16 ext_cap_offset; + struct ieee_types_obss_scan_param *bcn_obss_scan; + u16 overlap_bss_offset; + struct ieee_types_vendor_specific *bcn_wpa_ie; + u16 wpa_offset; + struct ieee_types_generic *bcn_rsn_ie; + u16 rsn_offset; + struct ieee_types_generic *bcn_wapi_ie; + u16 wapi_offset; + u8 *beacon_buf; + u32 beacon_buf_size; + u32 beacon_buf_size_max; + +}; + +struct mwifiex_current_bss_params { + struct mwifiex_bssdescriptor bss_descriptor; + u8 wmm_enabled; + u8 wmm_uapsd_enabled; + u8 band; + u32 num_of_rates; + u8 data_rates[MWIFIEX_SUPPORTED_RATES]; +}; + +struct mwifiex_sleep_params { + u16 sp_error; + u16 sp_offset; + u16 sp_stable_time; + u8 sp_cal_control; + u8 sp_ext_sleep_clk; + u16 sp_reserved; +}; + +struct mwifiex_sleep_period { + u16 period; + u16 reserved; +}; + +struct mwifiex_wep_key { + u32 length; + u32 key_index; + u32 key_length; + u8 key_material[MWIFIEX_KEY_BUFFER_SIZE]; +}; + +#define MAX_REGION_CHANNEL_NUM 2 + +struct mwifiex_chan_freq_power { + u16 channel; + u32 freq; + u16 max_tx_power; + u8 unsupported; +}; + +enum state_11d_t { + DISABLE_11D = 0, + ENABLE_11D = 1, +}; + +#define MWIFIEX_MAX_TRIPLET_802_11D 83 + +struct mwifiex_802_11d_domain_reg { + u8 country_code[IEEE80211_COUNTRY_STRING_LEN]; + u8 no_of_triplet; + struct ieee80211_country_ie_triplet + triplet[MWIFIEX_MAX_TRIPLET_802_11D]; +}; + +struct mwifiex_vendor_spec_cfg_ie { + u16 mask; + u16 flag; + u8 ie[MWIFIEX_MAX_VSIE_LEN]; +}; + +struct wps { + u8 session_enable; +}; + +struct mwifiex_adapter; +struct mwifiex_private; + +struct mwifiex_private { + struct mwifiex_adapter *adapter; + u8 bss_index; + u8 bss_type; + u8 bss_role; + u8 bss_priority; + u8 bss_num; + u8 frame_type; + u8 curr_addr[ETH_ALEN]; + u8 media_connected; + u32 num_tx_timeout; + struct net_device *netdev; + struct net_device_stats stats; + u16 curr_pkt_filter; + u32 bss_mode; + u32 pkt_tx_ctrl; + u16 tx_power_level; + u8 max_tx_power_level; + u8 min_tx_power_level; + u8 tx_rate; + u8 tx_htinfo; + u8 rxpd_htinfo; + u8 rxpd_rate; + u16 rate_bitmap; + u16 bitmap_rates[MAX_BITMAP_RATES_SIZE]; + u32 data_rate; + u8 is_data_rate_auto; + u16 bcn_avg_factor; + u16 data_avg_factor; + s16 data_rssi_last; + s16 data_nf_last; + s16 data_rssi_avg; + s16 data_nf_avg; + s16 bcn_rssi_last; + s16 bcn_nf_last; + s16 bcn_rssi_avg; + s16 bcn_nf_avg; + struct mwifiex_bssdescriptor *attempted_bss_desc; + struct mwifiex_802_11_ssid prev_ssid; + u8 prev_bssid[ETH_ALEN]; + struct mwifiex_current_bss_params curr_bss_params; + u16 beacon_period; + u16 listen_interval; + u16 atim_window; + u8 adhoc_channel; + u8 adhoc_is_link_sensed; + u8 adhoc_state; + struct mwifiex_802_11_security sec_info; + struct mwifiex_wep_key wep_key[NUM_WEP_KEYS]; + u16 wep_key_curr_index; + u8 wpa_ie[256]; + u8 wpa_ie_len; + u8 wpa_is_gtk_set; + struct host_cmd_ds_802_11_key_material aes_key; + u8 wapi_ie[256]; + u8 wapi_ie_len; + u8 wmm_required; + u8 wmm_enabled; + u8 wmm_qosinfo; + struct mwifiex_wmm_desc wmm; + struct list_head tx_ba_stream_tbl_ptr; + /* spin lock for tx_ba_stream_tbl_ptr queue */ + spinlock_t tx_ba_stream_tbl_lock; + struct mwifiex_tx_aggr aggr_prio_tbl[MAX_NUM_TID]; + struct mwifiex_add_ba_param add_ba_param; + u16 rx_seq[MAX_NUM_TID]; + struct list_head rx_reorder_tbl_ptr; + /* spin lock for rx_reorder_tbl_ptr queue */ + spinlock_t rx_reorder_tbl_lock; + /* spin lock for Rx packets */ + spinlock_t rx_pkt_lock; + +#define MWIFIEX_ASSOC_RSP_BUF_SIZE 500 + u8 assoc_rsp_buf[MWIFIEX_ASSOC_RSP_BUF_SIZE]; + u32 assoc_rsp_size; + +#define MWIFIEX_GENIE_BUF_SIZE 256 + u8 gen_ie_buf[MWIFIEX_GENIE_BUF_SIZE]; + u8 gen_ie_buf_len; + + struct mwifiex_vendor_spec_cfg_ie vs_ie[MWIFIEX_MAX_VSIE_NUM]; + +#define MWIFIEX_ASSOC_TLV_BUF_SIZE 256 + u8 assoc_tlv_buf[MWIFIEX_ASSOC_TLV_BUF_SIZE]; + u8 assoc_tlv_buf_len; + + u8 *curr_bcn_buf; + u32 curr_bcn_size; + /* spin lock for beacon buffer */ + spinlock_t curr_bcn_buf_lock; + u16 ioctl_wait_q_woken; + wait_queue_head_t ioctl_wait_q; + u16 cmd_wait_q_woken; + wait_queue_head_t cmd_wait_q; + struct wireless_dev *wdev; + struct mwifiex_chan_freq_power cfp; + char version_str[128]; +#ifdef CONFIG_DEBUG_FS + struct dentry *dfs_dev_dir; +#endif + u8 nick_name[16]; + struct iw_statistics w_stats; + u16 w_stats_wait_q_woken; + wait_queue_head_t w_stats_wait_q; + u16 current_key_index; + struct semaphore async_sem; + u8 scan_pending_on_block; + u8 report_scan_result; + struct cfg80211_scan_request *scan_request; + int scan_result_status; + bool assoc_request; + u16 assoc_result; + bool ibss_join_request; + u16 ibss_join_result; + bool disconnect; + u8 cfg_bssid[6]; + struct workqueue_struct *workqueue; + struct work_struct cfg_workqueue; + u8 country_code[IEEE80211_COUNTRY_STRING_LEN]; + struct wps wps; + u8 scan_block; +}; + +enum mwifiex_ba_status { + BA_STREAM_NOT_SETUP = 0, + BA_STREAM_SETUP_INPROGRESS, + BA_STREAM_SETUP_COMPLETE +}; + +struct mwifiex_tx_ba_stream_tbl { + struct list_head list; + int tid; + u8 ra[ETH_ALEN]; + enum mwifiex_ba_status ba_status; +}; + +struct mwifiex_rx_reorder_tbl; + +struct reorder_tmr_cnxt { + struct timer_list timer; + struct mwifiex_rx_reorder_tbl *ptr; + struct mwifiex_private *priv; +}; + +struct mwifiex_rx_reorder_tbl { + struct list_head list; + int tid; + u8 ta[ETH_ALEN]; + int start_win; + int win_size; + void **rx_reorder_ptr; + struct reorder_tmr_cnxt timer_context; +}; + +struct mwifiex_bss_prio_node { + struct list_head list; + struct mwifiex_private *priv; +}; + +struct mwifiex_bss_prio_tbl { + struct list_head bss_prio_head; + /* spin lock for bss priority */ + spinlock_t bss_prio_lock; + struct mwifiex_bss_prio_node *bss_prio_cur; +}; + +struct cmd_ctrl_node { + struct list_head list; + struct mwifiex_private *priv; + u32 cmd_oid; + u32 cmd_flag; + struct sk_buff *cmd_skb; + struct sk_buff *resp_skb; + void *data_buf; + void *wq_buf; + struct sk_buff *skb; +}; + +struct mwifiex_if_ops { + int (*init_if) (struct mwifiex_adapter *); + void (*cleanup_if) (struct mwifiex_adapter *); + int (*check_fw_status) (struct mwifiex_adapter *, u32, int *); + int (*prog_fw) (struct mwifiex_adapter *, struct mwifiex_fw_image *); + int (*register_dev) (struct mwifiex_adapter *); + void (*unregister_dev) (struct mwifiex_adapter *); + int (*enable_int) (struct mwifiex_adapter *); + int (*process_int_status) (struct mwifiex_adapter *); + int (*host_to_card) (struct mwifiex_adapter *, u8, + u8 *payload, u32 pkt_len, + struct mwifiex_tx_param *); + int (*wakeup) (struct mwifiex_adapter *); + int (*wakeup_complete) (struct mwifiex_adapter *); + + void (*update_mp_end_port) (struct mwifiex_adapter *, u16); + void (*cleanup_mpa_buf) (struct mwifiex_adapter *); +}; + +struct mwifiex_adapter { + struct mwifiex_private *priv[MWIFIEX_MAX_BSS_NUM]; + u8 priv_num; + struct mwifiex_drv_mode *drv_mode; + const struct firmware *firmware; + struct device *dev; + bool surprise_removed; + u32 fw_release_number; + u32 revision_id; + u16 init_wait_q_woken; + wait_queue_head_t init_wait_q; + void *card; + struct mwifiex_if_ops if_ops; + atomic_t rx_pending; + atomic_t tx_pending; + atomic_t ioctl_pending; + struct workqueue_struct *workqueue; + struct work_struct main_work; + struct mwifiex_bss_prio_tbl bss_prio_tbl[MWIFIEX_MAX_BSS_NUM]; + /* spin lock for init/shutdown */ + spinlock_t mwifiex_lock; + /* spin lock for main process */ + spinlock_t main_proc_lock; + u32 mwifiex_processing; + u16 max_tx_buf_size; + u16 tx_buf_size; + u16 curr_tx_buf_size; + u32 ioport; + enum MWIFIEX_HARDWARE_STATUS hw_status; + u16 radio_on; + u16 number_of_antenna; + u32 fw_cap_info; + /* spin lock for interrupt handling */ + spinlock_t int_lock; + u8 int_status; + u32 event_cause; + struct sk_buff *event_skb; + u8 upld_buf[MWIFIEX_UPLD_SIZE]; + u8 data_sent; + u8 cmd_sent; + u8 cmd_resp_received; + u8 event_received; + u8 data_received; + u16 seq_num; + struct cmd_ctrl_node *cmd_pool; + struct cmd_ctrl_node *curr_cmd; + /* spin lock for command */ + spinlock_t mwifiex_cmd_lock; + u32 num_cmd_timeout; + u16 last_init_cmd; + struct timer_list cmd_timer; + struct list_head cmd_free_q; + /* spin lock for cmd_free_q */ + spinlock_t cmd_free_q_lock; + struct list_head cmd_pending_q; + /* spin lock for cmd_pending_q */ + spinlock_t cmd_pending_q_lock; + struct list_head scan_pending_q; + /* spin lock for scan_pending_q */ + spinlock_t scan_pending_q_lock; + u32 scan_processing; + u16 region_code; + struct mwifiex_802_11d_domain_reg domain_reg; + struct mwifiex_bssdescriptor *scan_table; + u32 num_in_scan_table; + u16 scan_probes; + u32 scan_mode; + u16 specific_scan_time; + u16 active_scan_time; + u16 passive_scan_time; + u8 bcn_buf[MAX_SCAN_BEACON_BUFFER]; + u8 *bcn_buf_end; + u8 fw_bands; + u8 adhoc_start_band; + u8 config_bands; + struct mwifiex_chan_scan_param_set *scan_channels; + u8 tx_lock_flag; + struct mwifiex_sleep_params sleep_params; + struct mwifiex_sleep_period sleep_period; + u16 ps_mode; + u32 ps_state; + u8 need_to_wakeup; + u16 multiple_dtim; + u16 local_listen_interval; + u16 null_pkt_interval; + struct sk_buff *sleep_cfm; + u16 bcn_miss_time_out; + u16 adhoc_awake_period; + u8 is_deep_sleep; + u8 delay_null_pkt; + u16 delay_to_ps; + u16 enhanced_ps_mode; + u8 pm_wakeup_card_req; + u16 gen_null_pkt; + u16 pps_uapsd_mode; + u32 pm_wakeup_fw_try; + u8 is_hs_configured; + struct mwifiex_hs_config_param hs_cfg; + u8 hs_activated; + u16 hs_activate_wait_q_woken; + wait_queue_head_t hs_activate_wait_q; + bool is_suspended; + u8 event_body[MAX_EVENT_SIZE]; + u32 hw_dot_11n_dev_cap; + u8 hw_dev_mcs_support; + u32 usr_dot_11n_dev_cap; + u8 usr_dev_mcs_support; + u8 adhoc_11n_enabled; + u8 chan_offset; + struct mwifiex_dbg dbg; + u8 arp_filter[ARP_FILTER_MAX_BUF_SIZE]; + u32 arp_filter_size; +}; + +int mwifiex_init_lock_list(struct mwifiex_adapter *adapter); +void mwifiex_free_lock_list(struct mwifiex_adapter *adapter); + +int mwifiex_init_fw(struct mwifiex_adapter *adapter); + +int mwifiex_init_fw_complete(struct mwifiex_adapter *adapter); + +int mwifiex_shutdown_drv(struct mwifiex_adapter *adapter); + +int mwifiex_shutdown_fw_complete(struct mwifiex_adapter *adapter); + +int mwifiex_dnld_fw(struct mwifiex_adapter *, struct mwifiex_fw_image *); + +int mwifiex_recv_complete(struct mwifiex_adapter *, + struct sk_buff *skb, + int status); + +int mwifiex_recv_packet(struct mwifiex_adapter *, struct sk_buff *skb); + +int mwifiex_process_event(struct mwifiex_adapter *adapter); + +int mwifiex_ioctl_complete(struct mwifiex_adapter *adapter, + struct mwifiex_wait_queue *ioctl_wq, + int status); + +int mwifiex_prepare_cmd(struct mwifiex_private *priv, + uint16_t cmd_no, + u16 cmd_action, + u32 cmd_oid, + void *wait_queue, void *data_buf); + +void mwifiex_cmd_timeout_func(unsigned long function_context); + +int mwifiex_misc_ioctl_init_shutdown(struct mwifiex_adapter *adapter, + struct mwifiex_wait_queue *wait_queue, + u32 func_init_shutdown); +int mwifiex_get_debug_info(struct mwifiex_private *, + struct mwifiex_debug_info *); + +int mwifiex_alloc_cmd_buffer(struct mwifiex_adapter *adapter); +int mwifiex_free_cmd_buffer(struct mwifiex_adapter *adapter); +void mwifiex_cancel_all_pending_cmd(struct mwifiex_adapter *adapter); +void mwifiex_cancel_pending_ioctl(struct mwifiex_adapter *adapter, + struct mwifiex_wait_queue *ioctl_wq); + +void mwifiex_insert_cmd_to_free_q(struct mwifiex_adapter *adapter, + struct cmd_ctrl_node *cmd_node); + +void mwifiex_insert_cmd_to_pending_q(struct mwifiex_adapter *adapter, + struct cmd_ctrl_node *cmd_node, + u32 addtail); + +int mwifiex_exec_next_cmd(struct mwifiex_adapter *adapter); +int mwifiex_process_cmdresp(struct mwifiex_adapter *adapter); +int mwifiex_handle_rx_packet(struct mwifiex_adapter *adapter, + struct sk_buff *skb); +int mwifiex_process_tx(struct mwifiex_private *priv, struct sk_buff *skb, + struct mwifiex_tx_param *tx_param); +int mwifiex_send_null_packet(struct mwifiex_private *priv, u8 flags); +int mwifiex_write_data_complete(struct mwifiex_adapter *adapter, + struct sk_buff *skb, int status); +int mwifiex_recv_packet_complete(struct mwifiex_adapter *, + struct sk_buff *skb, int status); +void mwifiex_clean_txrx(struct mwifiex_private *priv); +u8 mwifiex_check_last_packet_indication(struct mwifiex_private *priv); +void mwifiex_check_ps_cond(struct mwifiex_adapter *adapter); +void mwifiex_process_sleep_confirm_resp(struct mwifiex_adapter *, u8 *, + u32); +int mwifiex_cmd_enh_power_mode(struct mwifiex_private *priv, + struct host_cmd_ds_command *cmd, + u16 cmd_action, uint16_t ps_bitmap, + void *data_buf); +int mwifiex_ret_enh_power_mode(struct mwifiex_private *priv, + struct host_cmd_ds_command *resp, + void *data_buf); +void mwifiex_process_hs_config(struct mwifiex_adapter *adapter); +void mwifiex_hs_activated_event(struct mwifiex_private *priv, + u8 activated); +int mwifiex_ret_802_11_hs_cfg(struct mwifiex_private *priv, + struct host_cmd_ds_command *resp); +int mwifiex_process_rx_packet(struct mwifiex_adapter *adapter, + struct sk_buff *skb); +int mwifiex_sta_prepare_cmd(struct mwifiex_private *, uint16_t cmd_no, + u16 cmd_action, u32 cmd_oid, + void *data_buf, void *cmd_buf); +int mwifiex_process_sta_cmdresp(struct mwifiex_private *, u16 cmdresp_no, + void *cmd_buf, void *ioctl); +int mwifiex_process_sta_rx_packet(struct mwifiex_adapter *, + struct sk_buff *skb); +int mwifiex_process_sta_event(struct mwifiex_private *); +void *mwifiex_process_sta_txpd(struct mwifiex_private *, struct sk_buff *skb); +int mwifiex_sta_init_cmd(struct mwifiex_private *, u8 first_sta); +int mwifiex_scan_networks(struct mwifiex_private *priv, void *wait_queue, + u16 action, + const struct mwifiex_user_scan_cfg + *user_scan_in, struct mwifiex_scan_resp *); +int mwifiex_cmd_802_11_scan(struct mwifiex_private *priv, + struct host_cmd_ds_command *cmd, + void *data_buf); +void mwifiex_queue_scan_cmd(struct mwifiex_private *priv, + struct cmd_ctrl_node *cmd_node); +int mwifiex_ret_802_11_scan(struct mwifiex_private *priv, + struct host_cmd_ds_command *resp, + void *wait_queue); +s32 mwifiex_find_ssid_in_list(struct mwifiex_private *priv, + struct mwifiex_802_11_ssid *ssid, u8 *bssid, + u32 mode); +s32 mwifiex_find_bssid_in_list(struct mwifiex_private *priv, u8 *bssid, + u32 mode); +int mwifiex_find_best_network(struct mwifiex_private *priv, + struct mwifiex_ssid_bssid *req_ssid_bssid); +s32 mwifiex_ssid_cmp(struct mwifiex_802_11_ssid *ssid1, + struct mwifiex_802_11_ssid *ssid2); +int mwifiex_associate(struct mwifiex_private *priv, void *wait_queue, + struct mwifiex_bssdescriptor *bss_desc); +int mwifiex_cmd_802_11_associate(struct mwifiex_private *priv, + struct host_cmd_ds_command + *cmd, void *data_buf); +int mwifiex_ret_802_11_associate(struct mwifiex_private *priv, + struct host_cmd_ds_command *resp, + void *wait_queue); +void mwifiex_reset_connect_state(struct mwifiex_private *priv); +void mwifiex_2040_coex_event(struct mwifiex_private *priv); +u8 mwifiex_band_to_radio_type(u8 band); +int mwifiex_deauthenticate(struct mwifiex_private *priv, + struct mwifiex_wait_queue *wait_queue, + u8 *mac); +int mwifiex_adhoc_start(struct mwifiex_private *priv, void *wait_queue, + struct mwifiex_802_11_ssid *adhoc_ssid); +int mwifiex_adhoc_join(struct mwifiex_private *priv, void *wait_queue, + struct mwifiex_bssdescriptor *bss_desc); +int mwifiex_cmd_802_11_ad_hoc_start(struct mwifiex_private *priv, + struct host_cmd_ds_command *cmd, + void *data_buf); +int mwifiex_cmd_802_11_ad_hoc_join(struct mwifiex_private *priv, + struct host_cmd_ds_command *cmd, + void *data_buf); +int mwifiex_ret_802_11_ad_hoc(struct mwifiex_private *priv, + struct host_cmd_ds_command *resp, + void *wait_queue); +int mwifiex_cmd_802_11_bg_scan_query(struct mwifiex_private *priv, + struct host_cmd_ds_command *cmd, + void *data_buf); +struct mwifiex_chan_freq_power * + mwifiex_get_cfp_by_band_and_channel_from_cfg80211( + struct mwifiex_private *priv, + u8 band, u16 channel); +struct mwifiex_chan_freq_power *mwifiex_get_cfp_by_band_and_freq_from_cfg80211( + struct mwifiex_private *priv, + u8 band, u32 freq); +u32 mwifiex_index_to_data_rate(struct mwifiex_adapter *adapter, u8 index, + u8 ht_info); +u32 mwifiex_find_freq_from_band_chan(u8, u8); +int mwifiex_cmd_append_vsie_tlv(struct mwifiex_private *priv, u16 vsie_mask, + u8 **buffer); +u32 mwifiex_index_to_data_rate(struct mwifiex_adapter *adapter, u8 index, + u8 ht_info); +u32 mwifiex_get_active_data_rates(struct mwifiex_private *priv, + u8 *rates); +u32 mwifiex_get_supported_rates(struct mwifiex_private *priv, u8 *rates); +u8 mwifiex_data_rate_to_index(struct mwifiex_adapter *adapter, u32 rate); +u8 mwifiex_is_rate_auto(struct mwifiex_private *priv); +int mwifiex_get_rate_index(struct mwifiex_adapter *adapter, + u16 *rateBitmap, int size); +extern u16 region_code_index[MWIFIEX_MAX_REGION_CODE]; +void mwifiex_save_curr_bcn(struct mwifiex_private *priv); +void mwifiex_free_curr_bcn(struct mwifiex_private *priv); +int mwifiex_cmd_get_hw_spec(struct mwifiex_private *priv, + struct host_cmd_ds_command *cmd); +int mwifiex_ret_get_hw_spec(struct mwifiex_private *priv, + struct host_cmd_ds_command *resp); +int is_command_pending(struct mwifiex_adapter *adapter); + +/* + * This function checks if the queuing is RA based or not. + */ +static inline u8 +mwifiex_queuing_ra_based(struct mwifiex_private *priv) +{ + /* + * Currently we assume if we are in Infra, then DA=RA. This might not be + * true in the future + */ + if ((priv->bss_mode == MWIFIEX_BSS_MODE_INFRA) && + (GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_STA)) + return false; + + return true; +} + +/* + * This function copies rates. + */ +static inline u32 +mwifiex_copy_rates(u8 *dest, u32 pos, u8 *src, int len) +{ + int i; + + for (i = 0; i < len && src[i]; i++, pos++) { + if (pos >= MWIFIEX_SUPPORTED_RATES) + break; + dest[pos] = src[i]; + } + + return pos; +} + +/* + * This function returns the correct private structure pointer based + * upon the BSS type and BSS number. + */ +static inline struct mwifiex_private * +mwifiex_get_priv_by_id(struct mwifiex_adapter *adapter, + u32 bss_num, u32 bss_type) +{ + int i; + + for (i = 0; i < adapter->priv_num; i++) { + if (adapter->priv[i]) { + if ((adapter->priv[i]->bss_num == bss_num) + && (adapter->priv[i]->bss_type == bss_type)) + break; + } + } + return ((i < adapter->priv_num) ? adapter->priv[i] : NULL); +} + +/* + * This function returns the first available private structure pointer + * based upon the BSS role. + */ +static inline struct mwifiex_private * +mwifiex_get_priv(struct mwifiex_adapter *adapter, + enum mwifiex_bss_role bss_role) +{ + int i; + + for (i = 0; i < adapter->priv_num; i++) { + if (adapter->priv[i]) { + if (bss_role == MWIFIEX_BSS_ROLE_ANY || + GET_BSS_ROLE(adapter->priv[i]) == bss_role) + break; + } + } + + return ((i < adapter->priv_num) ? adapter->priv[i] : NULL); +} + +/* + * This function returns the driver private structure of a network device. + */ +static inline struct mwifiex_private * +mwifiex_netdev_get_priv(struct net_device *dev) +{ + return (struct mwifiex_private *) (*(unsigned long *) netdev_priv(dev)); +} + +struct mwifiex_wait_queue *mwifiex_alloc_fill_wait_queue( + struct mwifiex_private *, + u8 wait_option); +struct mwifiex_private *mwifiex_bss_index_to_priv(struct mwifiex_adapter + *adapter, u8 bss_index); +int mwifiex_shutdown_fw(struct mwifiex_private *, u8); + +int mwifiex_add_card(void *, struct semaphore *, struct mwifiex_if_ops *); +int mwifiex_remove_card(struct mwifiex_adapter *, struct semaphore *); + +void mwifiex_get_version(struct mwifiex_adapter *adapter, char *version, + int maxlen); +int mwifiex_request_set_mac_address(struct mwifiex_private *priv); +void mwifiex_request_set_multicast_list(struct mwifiex_private *priv, + struct net_device *dev); +int mwifiex_request_ioctl(struct mwifiex_private *priv, + struct mwifiex_wait_queue *req, + int, u8 wait_option); +int mwifiex_disconnect(struct mwifiex_private *, u8, u8 *); +int mwifiex_bss_start(struct mwifiex_private *priv, + u8 wait_option, + struct mwifiex_ssid_bssid *ssid_bssid); +int mwifiex_set_hs_params(struct mwifiex_private *priv, + u16 action, u8 wait_option, + struct mwifiex_ds_hs_cfg *hscfg); +int mwifiex_cancel_hs(struct mwifiex_private *priv, u8 wait_option); +int mwifiex_enable_hs(struct mwifiex_adapter *adapter); +void mwifiex_process_ioctl_resp(struct mwifiex_private *priv, + struct mwifiex_wait_queue *req); +u32 mwifiex_get_mode(struct mwifiex_private *priv, u8 wait_option); +int mwifiex_get_signal_info(struct mwifiex_private *priv, + u8 wait_option, + struct mwifiex_ds_get_signal *signal); +int mwifiex_drv_get_data_rate(struct mwifiex_private *priv, + struct mwifiex_rate_cfg *rate); +int mwifiex_get_channel_list(struct mwifiex_private *priv, + u8 wait_option, + struct mwifiex_chan_list *chanlist); +int mwifiex_get_scan_table(struct mwifiex_private *priv, + u8 wait_option, + struct mwifiex_scan_resp *scanresp); +int mwifiex_get_auth_mode(struct mwifiex_private *priv, + u8 wait_option, u32 *auth_mode); +int mwifiex_get_encrypt_mode(struct mwifiex_private *priv, + u8 wait_option, + u32 *encrypt_mode); +int mwifiex_enable_wep_key(struct mwifiex_private *priv, u8 wait_option); +int mwifiex_find_best_bss(struct mwifiex_private *priv, u8 wait_option, + struct mwifiex_ssid_bssid *ssid_bssid); +int mwifiex_request_scan(struct mwifiex_private *priv, + u8 wait_option, + struct mwifiex_802_11_ssid *req_ssid); +int mwifiex_set_user_scan_ioctl(struct mwifiex_private *priv, + struct mwifiex_user_scan_cfg *scan_req); +int mwifiex_change_adhoc_chan(struct mwifiex_private *priv, int channel); +int mwifiex_set_radio(struct mwifiex_private *priv, u8 option); + +int mwifiex_drv_get_mode(struct mwifiex_private *priv, u8 wait_option); + +int mwifiex_drv_change_adhoc_chan(struct mwifiex_private *priv, int channel); + +int mwifiex_set_auth(struct mwifiex_private *priv, int encrypt_mode, + int auth_mode, int wpa_enabled); + +int mwifiex_set_encode(struct mwifiex_private *priv, const u8 *key, + int key_len, u8 key_index, int disable); + +int mwifiex_set_gen_ie(struct mwifiex_private *priv, u8 *ie, int ie_len); + +int mwifiex_get_ver_ext(struct mwifiex_private *priv); + +int mwifiex_get_stats_info(struct mwifiex_private *priv, + struct mwifiex_ds_get_stats *log); + +int mwifiex_reg_write(struct mwifiex_private *priv, u32 reg_type, + u32 reg_offset, u32 reg_value); + +int mwifiex_reg_read(struct mwifiex_private *priv, u32 reg_type, + u32 reg_offset, u32 *value); + +int mwifiex_eeprom_read(struct mwifiex_private *priv, u16 offset, u16 bytes, + u8 *value); + +int mwifiex_set_11n_httx_cfg(struct mwifiex_private *priv, int data); + +int mwifiex_get_11n_httx_cfg(struct mwifiex_private *priv, int *data); + +int mwifiex_set_tx_rate_cfg(struct mwifiex_private *priv, int tx_rate_index); + +int mwifiex_get_tx_rate_cfg(struct mwifiex_private *priv, int *tx_rate_index); + +int mwifiex_drv_set_power(struct mwifiex_private *priv, bool power_on); + +int mwifiex_drv_get_driver_version(struct mwifiex_adapter *adapter, + char *version, int max_len); + +int mwifiex_set_tx_power(struct mwifiex_private *priv, int type, int dbm); + +int mwifiex_main_process(struct mwifiex_adapter *); + +int mwifiex_bss_ioctl_mode(struct mwifiex_private *, + struct mwifiex_wait_queue *, + u16 action, int *mode); +int mwifiex_bss_ioctl_channel(struct mwifiex_private *, + u16 action, + struct mwifiex_chan_freq_power *cfp); +int mwifiex_bss_ioctl_find_bss(struct mwifiex_private *, + struct mwifiex_wait_queue *, + struct mwifiex_ssid_bssid *); +int mwifiex_radio_ioctl_band_cfg(struct mwifiex_private *, + u16 action, + struct mwifiex_ds_band_cfg *); +int mwifiex_snmp_mib_ioctl(struct mwifiex_private *, + struct mwifiex_wait_queue *, + u32 cmd_oid, u16 action, u32 *value); +int mwifiex_get_bss_info(struct mwifiex_private *, + struct mwifiex_bss_info *); + +#ifdef CONFIG_DEBUG_FS +void mwifiex_debugfs_init(void); +void mwifiex_debugfs_remove(void); + +void mwifiex_dev_debugfs_init(struct mwifiex_private *priv); +void mwifiex_dev_debugfs_remove(struct mwifiex_private *priv); +#endif +#endif /* !_MWIFIEX_MAIN_H_ */ diff --git a/drivers/net/wireless/mwifiex/scan.c b/drivers/net/wireless/mwifiex/scan.c new file mode 100644 index 0000000..1152beb --- /dev/null +++ b/drivers/net/wireless/mwifiex/scan.c @@ -0,0 +1,3098 @@ +/* + * Marvell Wireless LAN device driver: scan ioctl and command handling + * + * Copyright (C) 2011, Marvell International Ltd. + * + * This software file (the "File") is distributed by Marvell International + * Ltd. under the terms of the GNU General Public License Version 2, June 1991 + * (the "License"). You may use, redistribute and/or modify this File in + * accordance with the terms and conditions of the License, a copy of which + * is available by writing to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the + * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. + * + * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE + * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE + * ARE EXPRESSLY DISCLAIMED. The License provides additional details about + * this warranty disclaimer. + */ + +#include "decl.h" +#include "ioctl.h" +#include "util.h" +#include "fw.h" +#include "main.h" +#include "11n.h" +#include "cfg80211.h" + +/* The maximum number of channels the firmware can scan per command */ +#define MWIFIEX_MAX_CHANNELS_PER_SPECIFIC_SCAN 14 + +#define MWIFIEX_CHANNELS_PER_SCAN_CMD 4 + +/* Memory needed to store a max sized Channel List TLV for a firmware scan */ +#define CHAN_TLV_MAX_SIZE (sizeof(struct mwifiex_ie_types_header) \ + + (MWIFIEX_MAX_CHANNELS_PER_SPECIFIC_SCAN \ + *sizeof(struct mwifiex_chan_scan_param_set))) + +/* Memory needed to store supported rate */ +#define RATE_TLV_MAX_SIZE (sizeof(struct mwifiex_ie_types_rates_param_set) \ + + HOSTCMD_SUPPORTED_RATES) + +/* Memory needed to store a max number/size WildCard SSID TLV for a firmware + scan */ +#define WILDCARD_SSID_TLV_MAX_SIZE \ + (MWIFIEX_MAX_SSID_LIST_LENGTH * \ + (sizeof(struct mwifiex_ie_types_wildcard_ssid_params) \ + + IEEE80211_MAX_SSID_LEN)) + +/* Maximum memory needed for a mwifiex_scan_cmd_config with all TLVs at max */ +#define MAX_SCAN_CFG_ALLOC (sizeof(struct mwifiex_scan_cmd_config) \ + + sizeof(struct mwifiex_ie_types_num_probes) \ + + sizeof(struct mwifiex_ie_types_htcap) \ + + CHAN_TLV_MAX_SIZE \ + + RATE_TLV_MAX_SIZE \ + + WILDCARD_SSID_TLV_MAX_SIZE) + + +union mwifiex_scan_cmd_config_tlv { + /* Scan configuration (variable length) */ + struct mwifiex_scan_cmd_config config; + /* Max allocated block */ + u8 config_alloc_buf[MAX_SCAN_CFG_ALLOC]; +}; + +enum cipher_suite { + CIPHER_SUITE_TKIP, + CIPHER_SUITE_CCMP, + CIPHER_SUITE_MAX +}; +static u8 mwifiex_wpa_oui[CIPHER_SUITE_MAX][4] = { + { 0x00, 0x50, 0xf2, 0x02 }, /* TKIP */ + { 0x00, 0x50, 0xf2, 0x04 }, /* AES */ +}; +static u8 mwifiex_rsn_oui[CIPHER_SUITE_MAX][4] = { + { 0x00, 0x0f, 0xac, 0x02 }, /* TKIP */ + { 0x00, 0x0f, 0xac, 0x04 }, /* AES */ +}; + +/* + * This function parses a given IE for a given OUI. + * + * This is used to parse a WPA/RSN IE to find if it has + * a given oui in PTK. + */ +static u8 +mwifiex_search_oui_in_ie(struct ie_body *iebody, u8 *oui) +{ + u8 count; + + count = iebody->ptk_cnt[0]; + + /* There could be multiple OUIs for PTK hence + 1) Take the length. + 2) Check all the OUIs for AES. + 3) If one of them is AES then pass success. */ + while (count) { + if (!memcmp(iebody->ptk_body, oui, sizeof(iebody->ptk_body))) + return MWIFIEX_OUI_PRESENT; + + --count; + if (count) + iebody = (struct ie_body *) ((u8 *) iebody + + sizeof(iebody->ptk_body)); + } + + pr_debug("info: %s: OUI is not found in PTK\n", __func__); + return MWIFIEX_OUI_NOT_PRESENT; +} + +/* + * This function checks if a given OUI is present in a RSN IE. + * + * The function first checks if a RSN IE is present or not in the + * BSS descriptor. It tries to locate the OUI only if such an IE is + * present. + */ +static u8 +mwifiex_is_rsn_oui_present(struct mwifiex_bssdescriptor *bss_desc, u32 cipher) +{ + u8 *oui = NULL; + struct ie_body *iebody = NULL; + u8 ret = MWIFIEX_OUI_NOT_PRESENT; + + if (((bss_desc->bcn_rsn_ie) && ((*(bss_desc->bcn_rsn_ie)). + ieee_hdr.element_id == WLAN_EID_RSN))) { + iebody = (struct ie_body *) + (((u8 *) bss_desc->bcn_rsn_ie->data) + + RSN_GTK_OUI_OFFSET); + oui = &mwifiex_rsn_oui[cipher][0]; + ret = mwifiex_search_oui_in_ie(iebody, oui); + if (ret) + return ret; + } + return ret; +} + +/* + * This function checks if a given OUI is present in a WPA IE. + * + * The function first checks if a WPA IE is present or not in the + * BSS descriptor. It tries to locate the OUI only if such an IE is + * present. + */ +static u8 +mwifiex_is_wpa_oui_present(struct mwifiex_bssdescriptor *bss_desc, u32 cipher) +{ + u8 *oui = NULL; + struct ie_body *iebody = NULL; + u8 ret = MWIFIEX_OUI_NOT_PRESENT; + + if (((bss_desc->bcn_wpa_ie) && ((*(bss_desc->bcn_wpa_ie)). + vend_hdr.element_id == WLAN_EID_WPA))) { + iebody = (struct ie_body *) bss_desc->bcn_wpa_ie->data; + oui = &mwifiex_wpa_oui[cipher][0]; + ret = mwifiex_search_oui_in_ie(iebody, oui); + if (ret) + return ret; + } + return ret; +} + +/* + * This function compares two SSIDs and checks if they match. + */ +s32 +mwifiex_ssid_cmp(struct mwifiex_802_11_ssid *ssid1, + struct mwifiex_802_11_ssid *ssid2) +{ + if (!ssid1 || !ssid2 || (ssid1->ssid_len != ssid2->ssid_len)) + return -1; + return memcmp(ssid1->ssid, ssid2->ssid, ssid1->ssid_len); +} + +/* + * Sends IOCTL request to get the best BSS. + * + * This function allocates the IOCTL request buffer, fills it + * with requisite parameters and calls the IOCTL handler. + */ +int mwifiex_find_best_bss(struct mwifiex_private *priv, + u8 wait_option, struct mwifiex_ssid_bssid *ssid_bssid) +{ + struct mwifiex_wait_queue *wait = NULL; + struct mwifiex_ssid_bssid tmp_ssid_bssid; + int ret = 0; + u8 *mac = NULL; + + if (!ssid_bssid) + return -1; + + /* Allocate wait request buffer */ + wait = mwifiex_alloc_fill_wait_queue(priv, wait_option); + if (!wait) + return -ENOMEM; + + memcpy(&tmp_ssid_bssid, ssid_bssid, + sizeof(struct mwifiex_ssid_bssid)); + ret = mwifiex_bss_ioctl_find_bss(priv, wait, &tmp_ssid_bssid); + + if (!ret) { + memcpy(ssid_bssid, &tmp_ssid_bssid, + sizeof(struct mwifiex_ssid_bssid)); + mac = (u8 *) &ssid_bssid->bssid; + dev_dbg(priv->adapter->dev, "cmd: found network: ssid=%s," + " %pM\n", ssid_bssid->ssid.ssid, mac); + } + + kfree(wait); + return ret; +} + +/* + * Sends IOCTL request to start a scan with user configurations. + * + * This function allocates the IOCTL request buffer, fills it + * with requisite parameters and calls the IOCTL handler. + * + * Upon completion, it also generates a wireless event to notify + * applications. + */ +int mwifiex_set_user_scan_ioctl(struct mwifiex_private *priv, + struct mwifiex_user_scan_cfg *scan_req) +{ + struct mwifiex_wait_queue *wait = NULL; + int status = 0; + u8 wait_option = MWIFIEX_IOCTL_WAIT; + + /* Allocate an IOCTL request buffer */ + wait = mwifiex_alloc_fill_wait_queue(priv, wait_option); + if (!wait) + return -ENOMEM; + + status = mwifiex_scan_networks(priv, wait, HostCmd_ACT_GEN_SET, + scan_req, NULL); + + status = mwifiex_request_ioctl(priv, wait, status, wait_option); + + if (wait && (status != -EINPROGRESS)) + kfree(wait); + return status; +} + +/* + * This function checks if wapi is enabled in driver and scanned network is + * compatible with it. + */ +static bool +mwifiex_is_network_compatible_for_wapi(struct mwifiex_private *priv, + struct mwifiex_bssdescriptor *bss_desc) +{ + if (priv->sec_info.wapi_enabled && + (bss_desc->bcn_wapi_ie && + ((*(bss_desc->bcn_wapi_ie)).ieee_hdr.element_id == + WLAN_EID_BSS_AC_ACCESS_DELAY))) { + return true; + } + return false; +} + +/* + * This function checks if driver is configured with no security mode and + * scanned network is compatible with it. + */ +static bool +mwifiex_is_network_compatible_for_no_sec(struct mwifiex_private *priv, + struct mwifiex_bssdescriptor *bss_desc) +{ + if (priv->sec_info.wep_status == MWIFIEX_802_11_WEP_DISABLED + && !priv->sec_info.wpa_enabled && !priv->sec_info.wpa2_enabled + && ((!bss_desc->bcn_wpa_ie) || + ((*(bss_desc->bcn_wpa_ie)).vend_hdr.element_id != + WLAN_EID_WPA)) + && ((!bss_desc->bcn_rsn_ie) || + ((*(bss_desc->bcn_rsn_ie)).ieee_hdr.element_id != + WLAN_EID_RSN)) + && priv->sec_info.encryption_mode == + MWIFIEX_ENCRYPTION_MODE_NONE && !bss_desc->privacy) { + return true; + } + return false; +} + +/* + * This function checks if static WEP is enabled in driver and scanned network + * is compatible with it. + */ +static bool +mwifiex_is_network_compatible_for_static_wep(struct mwifiex_private *priv, + struct mwifiex_bssdescriptor *bss_desc) +{ + if (priv->sec_info.wep_status == MWIFIEX_802_11_WEP_ENABLED + && !priv->sec_info.wpa_enabled && !priv->sec_info.wpa2_enabled + && bss_desc->privacy) { + return true; + } + return false; +} + +/* + * This function checks if wpa is enabled in driver and scanned network is + * compatible with it. + */ +static bool +mwifiex_is_network_compatible_for_wpa(struct mwifiex_private *priv, + struct mwifiex_bssdescriptor *bss_desc, + int index) +{ + if (priv->sec_info.wep_status == MWIFIEX_802_11_WEP_DISABLED + && priv->sec_info.wpa_enabled && !priv->sec_info.wpa2_enabled + && ((bss_desc->bcn_wpa_ie) && ((*(bss_desc->bcn_wpa_ie)).vend_hdr. + element_id == WLAN_EID_WPA)) + /* + * Privacy bit may NOT be set in some APs like + * LinkSys WRT54G && bss_desc->privacy + */ + ) { + dev_dbg(priv->adapter->dev, "info: %s: WPA: index=%d" + " wpa_ie=%#x wpa2_ie=%#x WEP=%s WPA=%s WPA2=%s " + "EncMode=%#x privacy=%#x\n", __func__, index, + (bss_desc->bcn_wpa_ie) ? + (*(bss_desc->bcn_wpa_ie)). + vend_hdr.element_id : 0, + (bss_desc->bcn_rsn_ie) ? + (*(bss_desc->bcn_rsn_ie)). + ieee_hdr.element_id : 0, + (priv->sec_info.wep_status == + MWIFIEX_802_11_WEP_ENABLED) ? "e" : "d", + (priv->sec_info.wpa_enabled) ? "e" : "d", + (priv->sec_info.wpa2_enabled) ? "e" : "d", + priv->sec_info.encryption_mode, + bss_desc->privacy); + return true; + } + return false; +} + +/* + * This function checks if wpa2 is enabled in driver and scanned network is + * compatible with it. + */ +static bool +mwifiex_is_network_compatible_for_wpa2(struct mwifiex_private *priv, + struct mwifiex_bssdescriptor *bss_desc, + int index) +{ + if (priv->sec_info.wep_status == MWIFIEX_802_11_WEP_DISABLED + && !priv->sec_info.wpa_enabled && priv->sec_info.wpa2_enabled + && ((bss_desc->bcn_rsn_ie) && ((*(bss_desc->bcn_rsn_ie)).ieee_hdr. + element_id == WLAN_EID_RSN)) + /* + * Privacy bit may NOT be set in some APs like + * LinkSys WRT54G && bss_desc->privacy + */ + ) { + dev_dbg(priv->adapter->dev, "info: %s: WPA2: index=%d" + " wpa_ie=%#x wpa2_ie=%#x WEP=%s WPA=%s WPA2=%s " + "EncMode=%#x privacy=%#x\n", __func__, index, + (bss_desc->bcn_wpa_ie) ? + (*(bss_desc->bcn_wpa_ie)). + vend_hdr.element_id : 0, + (bss_desc->bcn_rsn_ie) ? + (*(bss_desc->bcn_rsn_ie)). + ieee_hdr.element_id : 0, + (priv->sec_info.wep_status == + MWIFIEX_802_11_WEP_ENABLED) ? "e" : "d", + (priv->sec_info.wpa_enabled) ? "e" : "d", + (priv->sec_info.wpa2_enabled) ? "e" : "d", + priv->sec_info.encryption_mode, + bss_desc->privacy); + return true; + } + return false; +} + +/* + * This function checks if adhoc AES is enabled in driver and scanned network is + * compatible with it. + */ +static bool +mwifiex_is_network_compatible_for_adhoc_aes(struct mwifiex_private *priv, + struct mwifiex_bssdescriptor *bss_desc) +{ + if (priv->sec_info.wep_status == MWIFIEX_802_11_WEP_DISABLED + && !priv->sec_info.wpa_enabled && !priv->sec_info.wpa2_enabled + && ((!bss_desc->bcn_wpa_ie) || ((*(bss_desc->bcn_wpa_ie)).vend_hdr. + element_id != WLAN_EID_WPA)) + && ((!bss_desc->bcn_rsn_ie) || ((*(bss_desc->bcn_rsn_ie)).ieee_hdr. + element_id != WLAN_EID_RSN)) + && priv->sec_info.encryption_mode == + MWIFIEX_ENCRYPTION_MODE_NONE && bss_desc->privacy) { + return true; + } + return false; +} + +/* + * This function checks if dynamic WEP is enabled in driver and scanned network + * is compatible with it. + */ +static bool +mwifiex_is_network_compatible_for_dynamic_wep(struct mwifiex_private *priv, + struct mwifiex_bssdescriptor *bss_desc, + int index) +{ + if (priv->sec_info.wep_status == MWIFIEX_802_11_WEP_DISABLED + && !priv->sec_info.wpa_enabled && !priv->sec_info.wpa2_enabled + && ((!bss_desc->bcn_wpa_ie) || ((*(bss_desc->bcn_wpa_ie)).vend_hdr. + element_id != WLAN_EID_WPA)) + && ((!bss_desc->bcn_rsn_ie) || ((*(bss_desc->bcn_rsn_ie)).ieee_hdr. + element_id != WLAN_EID_RSN)) + && priv->sec_info.encryption_mode != + MWIFIEX_ENCRYPTION_MODE_NONE && bss_desc->privacy) { + dev_dbg(priv->adapter->dev, "info: %s: dynamic " + "WEP: index=%d wpa_ie=%#x wpa2_ie=%#x " + "EncMode=%#x privacy=%#x\n", + __func__, index, + (bss_desc->bcn_wpa_ie) ? + (*(bss_desc->bcn_wpa_ie)). + vend_hdr.element_id : 0, + (bss_desc->bcn_rsn_ie) ? + (*(bss_desc->bcn_rsn_ie)). + ieee_hdr.element_id : 0, + priv->sec_info.encryption_mode, + bss_desc->privacy); + return true; + } + return false; +} + +/* + * This function checks if a scanned network is compatible with the driver + * settings. + * + * WEP WPA WPA2 ad-hoc encrypt Network + * enabled enabled enabled AES mode Privacy WPA WPA2 Compatible + * 0 0 0 0 NONE 0 0 0 yes No security + * 0 1 0 0 x 1x 1 x yes WPA (disable + * HT if no AES) + * 0 0 1 0 x 1x x 1 yes WPA2 (disable + * HT if no AES) + * 0 0 0 1 NONE 1 0 0 yes Ad-hoc AES + * 1 0 0 0 NONE 1 0 0 yes Static WEP + * (disable HT) + * 0 0 0 0 !=NONE 1 0 0 yes Dynamic WEP + * + * Compatibility is not matched while roaming, except for mode. + */ +static s32 +mwifiex_is_network_compatible(struct mwifiex_private *priv, u32 index, u32 mode) +{ + struct mwifiex_adapter *adapter = priv->adapter; + struct mwifiex_bssdescriptor *bss_desc; + + bss_desc = &adapter->scan_table[index]; + bss_desc->disable_11n = false; + + /* Don't check for compatibility if roaming */ + if (priv->media_connected && (priv->bss_mode == MWIFIEX_BSS_MODE_INFRA) + && (bss_desc->bss_mode == MWIFIEX_BSS_MODE_INFRA)) + return index; + + if (priv->wps.session_enable) { + dev_dbg(adapter->dev, + "info: return success directly in WPS period\n"); + return index; + } + + if (mwifiex_is_network_compatible_for_wapi(priv, bss_desc)) { + dev_dbg(adapter->dev, "info: return success for WAPI AP\n"); + return index; + } + + if (bss_desc->bss_mode == mode) { + if (mwifiex_is_network_compatible_for_no_sec(priv, bss_desc)) { + /* No security */ + return index; + } else if (mwifiex_is_network_compatible_for_static_wep(priv, + bss_desc)) { + /* Static WEP enabled */ + dev_dbg(adapter->dev, "info: Disable 11n in WEP mode.\n"); + bss_desc->disable_11n = true; + return index; + } else if (mwifiex_is_network_compatible_for_wpa(priv, bss_desc, + index)) { + /* WPA enabled */ + if (((priv->adapter->config_bands & BAND_GN + || priv->adapter->config_bands & BAND_AN) + && bss_desc->bcn_ht_cap) + && !mwifiex_is_wpa_oui_present(bss_desc, + CIPHER_SUITE_CCMP)) { + + if (mwifiex_is_wpa_oui_present(bss_desc, + CIPHER_SUITE_TKIP)) { + dev_dbg(adapter->dev, + "info: Disable 11n if AES " + "is not supported by AP\n"); + bss_desc->disable_11n = true; + } else { + return -1; + } + } + return index; + } else if (mwifiex_is_network_compatible_for_wpa2(priv, + bss_desc, index)) { + /* WPA2 enabled */ + if (((priv->adapter->config_bands & BAND_GN + || priv->adapter->config_bands & BAND_AN) + && bss_desc->bcn_ht_cap) + && !mwifiex_is_rsn_oui_present(bss_desc, + CIPHER_SUITE_CCMP)) { + + if (mwifiex_is_rsn_oui_present(bss_desc, + CIPHER_SUITE_TKIP)) { + dev_dbg(adapter->dev, + "info: Disable 11n if AES " + "is not supported by AP\n"); + bss_desc->disable_11n = true; + } else { + return -1; + } + } + return index; + } else if (mwifiex_is_network_compatible_for_adhoc_aes(priv, + bss_desc)) { + /* Ad-hoc AES enabled */ + return index; + } else if (mwifiex_is_network_compatible_for_dynamic_wep(priv, + bss_desc, index)) { + /* Dynamic WEP enabled */ + return index; + } + + /* Security doesn't match */ + dev_dbg(adapter->dev, "info: %s: failed: index=%d " + "wpa_ie=%#x wpa2_ie=%#x WEP=%s WPA=%s WPA2=%s EncMode" + "=%#x privacy=%#x\n", + __func__, index, + (bss_desc->bcn_wpa_ie) ? + (*(bss_desc->bcn_wpa_ie)).vend_hdr. + element_id : 0, + (bss_desc->bcn_rsn_ie) ? + (*(bss_desc->bcn_rsn_ie)).ieee_hdr. + element_id : 0, + (priv->sec_info.wep_status == + MWIFIEX_802_11_WEP_ENABLED) ? "e" : "d", + (priv->sec_info.wpa_enabled) ? "e" : "d", + (priv->sec_info.wpa2_enabled) ? "e" : "d", + priv->sec_info.encryption_mode, bss_desc->privacy); + return -1; + } + + /* Mode doesn't match */ + return -1; +} + +/* + * This function finds the best SSID in the scan list. + * + * It searches the scan table for the best SSID that also matches the current + * adapter network preference (mode, security etc.). + */ +static s32 +mwifiex_find_best_network_in_list(struct mwifiex_private *priv) +{ + struct mwifiex_adapter *adapter = priv->adapter; + u32 mode = priv->bss_mode; + s32 best_net = -1; + s32 best_rssi = 0; + u32 i; + + dev_dbg(adapter->dev, "info: num of BSSIDs = %d\n", + adapter->num_in_scan_table); + + for (i = 0; i < adapter->num_in_scan_table; i++) { + switch (mode) { + case MWIFIEX_BSS_MODE_INFRA: + case MWIFIEX_BSS_MODE_IBSS: + if (mwifiex_is_network_compatible(priv, i, mode) >= 0) { + if (SCAN_RSSI(adapter->scan_table[i].rssi) > + best_rssi) { + best_rssi = SCAN_RSSI(adapter-> + scan_table[i].rssi); + best_net = i; + } + } + break; + case MWIFIEX_BSS_MODE_AUTO: + default: + if (SCAN_RSSI(adapter->scan_table[i].rssi) > + best_rssi) { + best_rssi = SCAN_RSSI(adapter->scan_table[i]. + rssi); + best_net = i; + } + break; + } + } + + return best_net; +} + +/* + * This function creates a channel list for the driver to scan, based + * on region/band information. + * + * This routine is used for any scan that is not provided with a + * specific channel list to scan. + */ +static void +mwifiex_scan_create_channel_list(struct mwifiex_private *priv, + const struct mwifiex_user_scan_cfg + *user_scan_in, + struct mwifiex_chan_scan_param_set + *scan_chan_list, + u8 filtered_scan) +{ + enum ieee80211_band band; + struct ieee80211_supported_band *sband; + struct ieee80211_channel *ch; + struct mwifiex_adapter *adapter = priv->adapter; + int chan_idx = 0, i; + u8 scan_type; + + for (band = 0; (band < IEEE80211_NUM_BANDS) ; band++) { + + if (!priv->wdev->wiphy->bands[band]) + continue; + + sband = priv->wdev->wiphy->bands[band]; + + for (i = 0; (i < sband->n_channels) ; i++, chan_idx++) { + ch = &sband->channels[i]; + if (ch->flags & IEEE80211_CHAN_DISABLED) + continue; + scan_chan_list[chan_idx].radio_type = band; + scan_type = ch->flags & IEEE80211_CHAN_PASSIVE_SCAN; + if (user_scan_in && + user_scan_in->chan_list[0].scan_time) + scan_chan_list[chan_idx].max_scan_time = + cpu_to_le16((u16) user_scan_in-> + chan_list[0].scan_time); + else if (scan_type == MWIFIEX_SCAN_TYPE_PASSIVE) + scan_chan_list[chan_idx].max_scan_time = + cpu_to_le16(adapter->passive_scan_time); + else + scan_chan_list[chan_idx].max_scan_time = + cpu_to_le16(adapter->active_scan_time); + if (scan_type == MWIFIEX_SCAN_TYPE_PASSIVE) + scan_chan_list[chan_idx].chan_scan_mode_bitmap + |= MWIFIEX_PASSIVE_SCAN; + else + scan_chan_list[chan_idx].chan_scan_mode_bitmap + &= ~MWIFIEX_PASSIVE_SCAN; + scan_chan_list[chan_idx].chan_number = + (u32) ch->hw_value; + if (filtered_scan) { + scan_chan_list[chan_idx].max_scan_time = + cpu_to_le16(adapter->specific_scan_time); + scan_chan_list[chan_idx].chan_scan_mode_bitmap + |= MWIFIEX_DISABLE_CHAN_FILT; + } + } + + } +} + +/* + * This function constructs and sends multiple scan config commands to + * the firmware. + * + * Previous routines in the code flow have created a scan command configuration + * with any requested TLVs. This function splits the channel TLV into maximum + * channels supported per scan lists and sends the portion of the channel TLV, + * along with the other TLVs, to the firmware. + */ +static int +mwifiex_scan_channel_list(struct mwifiex_private *priv, void *wait_buf, + u32 max_chan_per_scan, u8 filtered_scan, + struct mwifiex_scan_cmd_config *scan_cfg_out, + struct mwifiex_ie_types_chan_list_param_set + *chan_tlv_out, + struct mwifiex_chan_scan_param_set *scan_chan_list) +{ + int ret = 0; + struct mwifiex_chan_scan_param_set *tmp_chan_list; + struct mwifiex_chan_scan_param_set *start_chan; + + u32 tlv_idx; + u32 total_scan_time; + u32 done_early; + + if (!scan_cfg_out || !chan_tlv_out || !scan_chan_list) { + dev_dbg(priv->adapter->dev, + "info: Scan: Null detect: %p, %p, %p\n", + scan_cfg_out, chan_tlv_out, scan_chan_list); + return -1; + } + + chan_tlv_out->header.type = cpu_to_le16(TLV_TYPE_CHANLIST); + + /* Set the temp channel struct pointer to the start of the desired + list */ + tmp_chan_list = scan_chan_list; + + /* Loop through the desired channel list, sending a new firmware scan + commands for each max_chan_per_scan channels (or for 1,6,11 + individually if configured accordingly) */ + while (tmp_chan_list->chan_number) { + + tlv_idx = 0; + total_scan_time = 0; + chan_tlv_out->header.len = 0; + start_chan = tmp_chan_list; + done_early = false; + + /* + * Construct the Channel TLV for the scan command. Continue to + * insert channel TLVs until: + * - the tlv_idx hits the maximum configured per scan command + * - the next channel to insert is 0 (end of desired channel + * list) + * - done_early is set (controlling individual scanning of + * 1,6,11) + */ + while (tlv_idx < max_chan_per_scan + && tmp_chan_list->chan_number && !done_early) { + + dev_dbg(priv->adapter->dev, + "info: Scan: Chan(%3d), Radio(%d)," + " Mode(%d, %d), Dur(%d)\n", + tmp_chan_list->chan_number, + tmp_chan_list->radio_type, + tmp_chan_list->chan_scan_mode_bitmap + & MWIFIEX_PASSIVE_SCAN, + (tmp_chan_list->chan_scan_mode_bitmap + & MWIFIEX_DISABLE_CHAN_FILT) >> 1, + le16_to_cpu(tmp_chan_list->max_scan_time)); + + /* Copy the current channel TLV to the command being + prepared */ + memcpy(chan_tlv_out->chan_scan_param + tlv_idx, + tmp_chan_list, + sizeof(chan_tlv_out->chan_scan_param)); + + /* Increment the TLV header length by the size + appended */ + chan_tlv_out->header.len = + cpu_to_le16(le16_to_cpu(chan_tlv_out->header.len) + + (sizeof(chan_tlv_out->chan_scan_param))); + + /* + * The tlv buffer length is set to the number of bytes + * of the between the channel tlv pointer and the start + * of the tlv buffer. This compensates for any TLVs + * that were appended before the channel list. + */ + scan_cfg_out->tlv_buf_len = (u32) ((u8 *) chan_tlv_out - + scan_cfg_out->tlv_buf); + + /* Add the size of the channel tlv header and the data + length */ + scan_cfg_out->tlv_buf_len += + (sizeof(chan_tlv_out->header) + + le16_to_cpu(chan_tlv_out->header.len)); + + /* Increment the index to the channel tlv we are + constructing */ + tlv_idx++; + + /* Count the total scan time per command */ + total_scan_time += + le16_to_cpu(tmp_chan_list->max_scan_time); + + done_early = false; + + /* Stop the loop if the *current* channel is in the + 1,6,11 set and we are not filtering on a BSSID + or SSID. */ + if (!filtered_scan && (tmp_chan_list->chan_number == 1 + || tmp_chan_list->chan_number == 6 + || tmp_chan_list->chan_number == 11)) + done_early = true; + + /* Increment the tmp pointer to the next channel to + be scanned */ + tmp_chan_list++; + + /* Stop the loop if the *next* channel is in the 1,6,11 + set. This will cause it to be the only channel + scanned on the next interation */ + if (!filtered_scan && (tmp_chan_list->chan_number == 1 + || tmp_chan_list->chan_number == 6 + || tmp_chan_list->chan_number == 11)) + done_early = true; + } + + /* The total scan time should be less than scan command timeout + value */ + if (total_scan_time > MWIFIEX_MAX_TOTAL_SCAN_TIME) { + dev_err(priv->adapter->dev, "total scan time %dms" + " is over limit (%dms), scan skipped\n", + total_scan_time, MWIFIEX_MAX_TOTAL_SCAN_TIME); + ret = -1; + break; + } + + priv->adapter->scan_channels = start_chan; + + /* Send the scan command to the firmware with the specified + cfg */ + ret = mwifiex_prepare_cmd(priv, HostCmd_CMD_802_11_SCAN, + HostCmd_ACT_GEN_SET, + 0, wait_buf, scan_cfg_out); + if (ret) + break; + } + + if (ret) + return -1; + + return 0; +} + +/* + * This function constructs a scan command configuration structure to use + * in scan commands. + * + * Application layer or other functions can invoke network scanning + * with a scan configuration supplied in a user scan configuration structure. + * This structure is used as the basis of one or many scan command configuration + * commands that are sent to the command processing module and eventually to the + * firmware. + * + * This function creates a scan command configuration structure based on the + * following user supplied parameters (if present): + * - SSID filter + * - BSSID filter + * - Number of Probes to be sent + * - Channel list + * + * If the SSID or BSSID filter is not present, the filter is disabled/cleared. + * If the number of probes is not set, adapter default setting is used. + */ +static void +mwifiex_scan_setup_scan_config(struct mwifiex_private *priv, + const struct mwifiex_user_scan_cfg *user_scan_in, + struct mwifiex_scan_cmd_config *scan_cfg_out, + struct mwifiex_ie_types_chan_list_param_set + **chan_list_out, + struct mwifiex_chan_scan_param_set + *scan_chan_list, + u8 *max_chan_per_scan, u8 *filtered_scan, + u8 *scan_current_only) +{ + struct mwifiex_adapter *adapter = priv->adapter; + struct mwifiex_ie_types_num_probes *num_probes_tlv; + struct mwifiex_ie_types_wildcard_ssid_params *wildcard_ssid_tlv; + struct mwifiex_ie_types_rates_param_set *rates_tlv; + const u8 zero_mac[ETH_ALEN] = { 0, 0, 0, 0, 0, 0 }; + u8 *tlv_pos; + u32 num_probes; + u32 ssid_len; + u32 chan_idx; + u32 scan_type; + u16 scan_dur; + u8 channel; + u8 radio_type; + u32 ssid_idx; + u8 ssid_filter; + u8 rates[MWIFIEX_SUPPORTED_RATES]; + u32 rates_size; + struct mwifiex_ie_types_htcap *ht_cap; + + /* The tlv_buf_len is calculated for each scan command. The TLVs added + in this routine will be preserved since the routine that sends the + command will append channelTLVs at *chan_list_out. The difference + between the *chan_list_out and the tlv_buf start will be used to + calculate the size of anything we add in this routine. */ + scan_cfg_out->tlv_buf_len = 0; + + /* Running tlv pointer. Assigned to chan_list_out at end of function + so later routines know where channels can be added to the command + buf */ + tlv_pos = scan_cfg_out->tlv_buf; + + /* Initialize the scan as un-filtered; the flag is later set to TRUE + below if a SSID or BSSID filter is sent in the command */ + *filtered_scan = false; + + /* Initialize the scan as not being only on the current channel. If + the channel list is customized, only contains one channel, and is + the active channel, this is set true and data flow is not halted. */ + *scan_current_only = false; + + if (user_scan_in) { + + /* Default the ssid_filter flag to TRUE, set false under + certain wildcard conditions and qualified by the existence + of an SSID list before marking the scan as filtered */ + ssid_filter = true; + + /* Set the BSS type scan filter, use Adapter setting if + unset */ + scan_cfg_out->bss_mode = + (user_scan_in->bss_mode ? (u8) user_scan_in-> + bss_mode : (u8) adapter->scan_mode); + + /* Set the number of probes to send, use Adapter setting + if unset */ + num_probes = + (user_scan_in->num_probes ? user_scan_in-> + num_probes : adapter->scan_probes); + + /* + * Set the BSSID filter to the incoming configuration, + * if non-zero. If not set, it will remain disabled + * (all zeros). + */ + memcpy(scan_cfg_out->specific_bssid, + user_scan_in->specific_bssid, + sizeof(scan_cfg_out->specific_bssid)); + + for (ssid_idx = 0; + ((ssid_idx < ARRAY_SIZE(user_scan_in->ssid_list)) + && (*user_scan_in->ssid_list[ssid_idx].ssid + || user_scan_in->ssid_list[ssid_idx].max_len)); + ssid_idx++) { + + ssid_len = strlen(user_scan_in->ssid_list[ssid_idx]. + ssid) + 1; + + wildcard_ssid_tlv = + (struct mwifiex_ie_types_wildcard_ssid_params *) + tlv_pos; + wildcard_ssid_tlv->header.type = + cpu_to_le16(TLV_TYPE_WILDCARDSSID); + wildcard_ssid_tlv->header.len = cpu_to_le16( + (u16) (ssid_len + sizeof(wildcard_ssid_tlv-> + max_ssid_length))); + wildcard_ssid_tlv->max_ssid_length = + user_scan_in->ssid_list[ssid_idx].max_len; + + memcpy(wildcard_ssid_tlv->ssid, + user_scan_in->ssid_list[ssid_idx].ssid, + ssid_len); + + tlv_pos += (sizeof(wildcard_ssid_tlv->header) + + le16_to_cpu(wildcard_ssid_tlv->header.len)); + + dev_dbg(adapter->dev, "info: scan: ssid_list[%d]: %s, %d\n", + ssid_idx, wildcard_ssid_tlv->ssid, + wildcard_ssid_tlv->max_ssid_length); + + /* Empty wildcard ssid with a maxlen will match many or + potentially all SSIDs (maxlen == 32), therefore do + not treat the scan as + filtered. */ + if (!ssid_len && wildcard_ssid_tlv->max_ssid_length) + ssid_filter = false; + + } + + /* + * The default number of channels sent in the command is low to + * ensure the response buffer from the firmware does not + * truncate scan results. That is not an issue with an SSID + * or BSSID filter applied to the scan results in the firmware. + */ + if ((ssid_idx && ssid_filter) + || memcmp(scan_cfg_out->specific_bssid, &zero_mac, + sizeof(zero_mac))) + *filtered_scan = true; + } else { + scan_cfg_out->bss_mode = (u8) adapter->scan_mode; + num_probes = adapter->scan_probes; + } + + /* + * If a specific BSSID or SSID is used, the number of channels in the + * scan command will be increased to the absolute maximum. + */ + if (*filtered_scan) + *max_chan_per_scan = MWIFIEX_MAX_CHANNELS_PER_SPECIFIC_SCAN; + else + *max_chan_per_scan = MWIFIEX_CHANNELS_PER_SCAN_CMD; + + /* If the input config or adapter has the number of Probes set, + add tlv */ + if (num_probes) { + + dev_dbg(adapter->dev, "info: scan: num_probes = %d\n", + num_probes); + + num_probes_tlv = (struct mwifiex_ie_types_num_probes *) tlv_pos; + num_probes_tlv->header.type = cpu_to_le16(TLV_TYPE_NUMPROBES); + num_probes_tlv->header.len = + cpu_to_le16(sizeof(num_probes_tlv->num_probes)); + num_probes_tlv->num_probes = cpu_to_le16((u16) num_probes); + + tlv_pos += sizeof(num_probes_tlv->header) + + le16_to_cpu(num_probes_tlv->header.len); + + } + + /* Append rates tlv */ + memset(rates, 0, sizeof(rates)); + + rates_size = mwifiex_get_supported_rates(priv, rates); + + rates_tlv = (struct mwifiex_ie_types_rates_param_set *) tlv_pos; + rates_tlv->header.type = cpu_to_le16(WLAN_EID_SUPP_RATES); + rates_tlv->header.len = cpu_to_le16((u16) rates_size); + memcpy(rates_tlv->rates, rates, rates_size); + tlv_pos += sizeof(rates_tlv->header) + rates_size; + + dev_dbg(adapter->dev, "info: SCAN_CMD: Rates size = %d\n", rates_size); + + if (ISSUPP_11NENABLED(priv->adapter->fw_cap_info) + && (priv->adapter->config_bands & BAND_GN + || priv->adapter->config_bands & BAND_AN)) { + ht_cap = (struct mwifiex_ie_types_htcap *) tlv_pos; + memset(ht_cap, 0, sizeof(struct mwifiex_ie_types_htcap)); + ht_cap->header.type = cpu_to_le16(WLAN_EID_HT_CAPABILITY); + ht_cap->header.len = + cpu_to_le16(sizeof(struct ieee80211_ht_cap)); + mwifiex_fill_cap_info(priv, ht_cap); + tlv_pos += sizeof(struct mwifiex_ie_types_htcap); + } + + /* Append vendor specific IE TLV */ + mwifiex_cmd_append_vsie_tlv(priv, MWIFIEX_VSIE_MASK_SCAN, &tlv_pos); + + /* + * Set the output for the channel TLV to the address in the tlv buffer + * past any TLVs that were added in this function (SSID, num_probes). + * Channel TLVs will be added past this for each scan command, + * preserving the TLVs that were previously added. + */ + *chan_list_out = + (struct mwifiex_ie_types_chan_list_param_set *) tlv_pos; + + if (user_scan_in && user_scan_in->chan_list[0].chan_number) { + + dev_dbg(adapter->dev, "info: Scan: Using supplied channel list\n"); + + for (chan_idx = 0; + chan_idx < MWIFIEX_USER_SCAN_CHAN_MAX + && user_scan_in->chan_list[chan_idx].chan_number; + chan_idx++) { + + channel = user_scan_in->chan_list[chan_idx].chan_number; + (scan_chan_list + chan_idx)->chan_number = channel; + + radio_type = + user_scan_in->chan_list[chan_idx].radio_type; + (scan_chan_list + chan_idx)->radio_type = radio_type; + + scan_type = user_scan_in->chan_list[chan_idx].scan_type; + + if (scan_type == MWIFIEX_SCAN_TYPE_PASSIVE) + (scan_chan_list + + chan_idx)->chan_scan_mode_bitmap + |= MWIFIEX_PASSIVE_SCAN; + else + (scan_chan_list + + chan_idx)->chan_scan_mode_bitmap + &= ~MWIFIEX_PASSIVE_SCAN; + + if (user_scan_in->chan_list[chan_idx].scan_time) { + scan_dur = (u16) user_scan_in-> + chan_list[chan_idx].scan_time; + } else { + if (scan_type == MWIFIEX_SCAN_TYPE_PASSIVE) + scan_dur = adapter->passive_scan_time; + else if (*filtered_scan) + scan_dur = adapter->specific_scan_time; + else + scan_dur = adapter->active_scan_time; + } + + (scan_chan_list + chan_idx)->min_scan_time = + cpu_to_le16(scan_dur); + (scan_chan_list + chan_idx)->max_scan_time = + cpu_to_le16(scan_dur); + } + + /* Check if we are only scanning the current channel */ + if ((chan_idx == 1) + && (user_scan_in->chan_list[0].chan_number + == priv->curr_bss_params.bss_descriptor.channel)) { + *scan_current_only = true; + dev_dbg(adapter->dev, + "info: Scan: Scanning current channel only\n"); + } + + } else { + dev_dbg(adapter->dev, + "info: Scan: Creating full region channel list\n"); + mwifiex_scan_create_channel_list(priv, user_scan_in, + scan_chan_list, + *filtered_scan); + } +} + +/* + * This function inspects the scan response buffer for pointers to + * expected TLVs. + * + * TLVs can be included at the end of the scan response BSS information. + * + * Data in the buffer is parsed pointers to TLVs that can potentially + * be passed back in the response. + */ +static void +mwifiex_ret_802_11_scan_get_tlv_ptrs(struct mwifiex_adapter *adapter, + struct mwifiex_ie_types_data *tlv, + u32 tlv_buf_size, u32 req_tlv_type, + struct mwifiex_ie_types_data **tlv_data) +{ + struct mwifiex_ie_types_data *current_tlv; + u32 tlv_buf_left; + u32 tlv_type; + u32 tlv_len; + + current_tlv = tlv; + tlv_buf_left = tlv_buf_size; + *tlv_data = NULL; + + dev_dbg(adapter->dev, "info: SCAN_RESP: tlv_buf_size = %d\n", + tlv_buf_size); + + while (tlv_buf_left >= sizeof(struct mwifiex_ie_types_header)) { + + tlv_type = le16_to_cpu(current_tlv->header.type); + tlv_len = le16_to_cpu(current_tlv->header.len); + + if (sizeof(tlv->header) + tlv_len > tlv_buf_left) { + dev_err(adapter->dev, "SCAN_RESP: TLV buffer corrupt\n"); + break; + } + + if (req_tlv_type == tlv_type) { + switch (tlv_type) { + case TLV_TYPE_TSFTIMESTAMP: + dev_dbg(adapter->dev, "info: SCAN_RESP: TSF " + "timestamp TLV, len = %d\n", tlv_len); + *tlv_data = (struct mwifiex_ie_types_data *) + current_tlv; + break; + case TLV_TYPE_CHANNELBANDLIST: + dev_dbg(adapter->dev, "info: SCAN_RESP: channel" + " band list TLV, len = %d\n", tlv_len); + *tlv_data = (struct mwifiex_ie_types_data *) + current_tlv; + break; + default: + dev_err(adapter->dev, + "SCAN_RESP: unhandled TLV = %d\n", + tlv_type); + /* Give up, this seems corrupted */ + return; + } + } + + if (*tlv_data) + break; + + + tlv_buf_left -= (sizeof(tlv->header) + tlv_len); + current_tlv = + (struct mwifiex_ie_types_data *) (current_tlv->data + + tlv_len); + + } /* while */ +} + +/* + * This function interprets a BSS scan response returned from the firmware. + * + * The various fixed fields and IEs are parsed and passed back for a BSS + * probe response or beacon from scan command. Information is recorded as + * needed in the scan table for that entry. + * + * The following IE types are recognized and parsed - + * - SSID + * - Supported rates + * - FH parameters set + * - DS parameters set + * - CF parameters set + * - IBSS parameters set + * - ERP information + * - Extended supported rates + * - Vendor specific (221) + * - RSN IE + * - WAPI IE + * - HT capability + * - HT operation + * - BSS Coexistence 20/40 + * - Extended capability + * - Overlapping BSS scan parameters + */ +static int +mwifiex_interpret_bss_desc_with_ie(struct mwifiex_adapter *adapter, + struct mwifiex_bssdescriptor *bss_entry, + u8 **beacon_info, u32 *bytes_left) +{ + int ret = 0; + u8 element_id; + struct ieee_types_fh_param_set *fh_param_set; + struct ieee_types_ds_param_set *ds_param_set; + struct ieee_types_cf_param_set *cf_param_set; + struct ieee_types_ibss_param_set *ibss_param_set; + struct mwifiex_802_11_fixed_ies fixed_ie; + u8 *current_ptr; + u8 *rate; + u8 element_len; + u16 total_ie_len; + u8 bytes_to_copy; + u8 rate_size; + u16 beacon_size; + u8 found_data_rate_ie; + u32 bytes_left_for_current_beacon; + struct ieee_types_vendor_specific *vendor_ie; + const u8 wpa_oui[4] = { 0x00, 0x50, 0xf2, 0x01 }; + const u8 wmm_oui[4] = { 0x00, 0x50, 0xf2, 0x02 }; + + found_data_rate_ie = false; + rate_size = 0; + beacon_size = 0; + + if (*bytes_left >= sizeof(beacon_size)) { + /* Extract & convert beacon size from the command buffer */ + memcpy(&beacon_size, *beacon_info, sizeof(beacon_size)); + *bytes_left -= sizeof(beacon_size); + *beacon_info += sizeof(beacon_size); + } + + if (!beacon_size || beacon_size > *bytes_left) { + *beacon_info += *bytes_left; + *bytes_left = 0; + return -1; + } + + /* Initialize the current working beacon pointer for this BSS + iteration */ + current_ptr = *beacon_info; + + /* Advance the return beacon pointer past the current beacon */ + *beacon_info += beacon_size; + *bytes_left -= beacon_size; + + bytes_left_for_current_beacon = beacon_size; + + memcpy(bss_entry->mac_address, current_ptr, ETH_ALEN); + dev_dbg(adapter->dev, "info: InterpretIE: AP MAC Addr: %pM\n", + bss_entry->mac_address); + + current_ptr += ETH_ALEN; + bytes_left_for_current_beacon -= ETH_ALEN; + + if (bytes_left_for_current_beacon < 12) { + dev_err(adapter->dev, "InterpretIE: not enough bytes left\n"); + return -1; + } + + /* + * Next 4 fields are RSSI, time stamp, beacon interval, + * and capability information + */ + + /* RSSI is 1 byte long */ + bss_entry->rssi = (s32) (*current_ptr); + dev_dbg(adapter->dev, "info: InterpretIE: RSSI=%02X\n", *current_ptr); + current_ptr += 1; + bytes_left_for_current_beacon -= 1; + + /* + * The RSSI is not part of the beacon/probe response. After we have + * advanced current_ptr past the RSSI field, save the remaining + * data for use at the application layer + */ + bss_entry->beacon_buf = current_ptr; + bss_entry->beacon_buf_size = bytes_left_for_current_beacon; + + /* Time stamp is 8 bytes long */ + memcpy(fixed_ie.time_stamp, current_ptr, 8); + memcpy(bss_entry->time_stamp, current_ptr, 8); + current_ptr += 8; + bytes_left_for_current_beacon -= 8; + + /* Beacon interval is 2 bytes long */ + memcpy(&fixed_ie.beacon_interval, current_ptr, 2); + bss_entry->beacon_period = le16_to_cpu(fixed_ie.beacon_interval); + current_ptr += 2; + bytes_left_for_current_beacon -= 2; + + /* Capability information is 2 bytes long */ + memcpy(&fixed_ie.capabilities, current_ptr, 2); + dev_dbg(adapter->dev, "info: InterpretIE: fixed_ie.capabilities=0x%X\n", + fixed_ie.capabilities); + bss_entry->cap_info_bitmap = le16_to_cpu(fixed_ie.capabilities); + current_ptr += 2; + bytes_left_for_current_beacon -= 2; + + /* Rest of the current buffer are IE's */ + dev_dbg(adapter->dev, "info: InterpretIE: IELength for this AP = %d\n", + bytes_left_for_current_beacon); + + if (bss_entry->cap_info_bitmap & WLAN_CAPABILITY_PRIVACY) { + dev_dbg(adapter->dev, "info: InterpretIE: AP WEP enabled\n"); + bss_entry->privacy = MWIFIEX_802_11_PRIV_FILTER_8021X_WEP; + } else { + bss_entry->privacy = MWIFIEX_802_11_PRIV_FILTER_ACCEPT_ALL; + } + + if (bss_entry->cap_info_bitmap & WLAN_CAPABILITY_IBSS) + bss_entry->bss_mode = MWIFIEX_BSS_MODE_IBSS; + else + bss_entry->bss_mode = MWIFIEX_BSS_MODE_INFRA; + + + /* Process variable IE */ + while (bytes_left_for_current_beacon >= 2) { + element_id = *current_ptr; + element_len = *(current_ptr + 1); + total_ie_len = element_len + sizeof(struct ieee_types_header); + + if (bytes_left_for_current_beacon < total_ie_len) { + dev_err(adapter->dev, "err: InterpretIE: in processing" + " IE, bytes left < IE length\n"); + bytes_left_for_current_beacon = 0; + ret = -1; + continue; + } + switch (element_id) { + case WLAN_EID_SSID: + bss_entry->ssid.ssid_len = element_len; + memcpy(bss_entry->ssid.ssid, (current_ptr + 2), + element_len); + dev_dbg(adapter->dev, "info: InterpretIE: ssid: %-32s\n", + bss_entry->ssid.ssid); + break; + + case WLAN_EID_SUPP_RATES: + memcpy(bss_entry->data_rates, current_ptr + 2, + element_len); + memcpy(bss_entry->supported_rates, current_ptr + 2, + element_len); + rate_size = element_len; + found_data_rate_ie = true; + break; + + case WLAN_EID_FH_PARAMS: + fh_param_set = + (struct ieee_types_fh_param_set *) current_ptr; + memcpy(&bss_entry->phy_param_set.fh_param_set, + fh_param_set, + sizeof(struct ieee_types_fh_param_set)); + break; + + case WLAN_EID_DS_PARAMS: + ds_param_set = + (struct ieee_types_ds_param_set *) current_ptr; + + bss_entry->channel = ds_param_set->current_chan; + + memcpy(&bss_entry->phy_param_set.ds_param_set, + ds_param_set, + sizeof(struct ieee_types_ds_param_set)); + break; + + case WLAN_EID_CF_PARAMS: + cf_param_set = + (struct ieee_types_cf_param_set *) current_ptr; + memcpy(&bss_entry->ss_param_set.cf_param_set, + cf_param_set, + sizeof(struct ieee_types_cf_param_set)); + break; + + case WLAN_EID_IBSS_PARAMS: + ibss_param_set = + (struct ieee_types_ibss_param_set *) + current_ptr; + memcpy(&bss_entry->ss_param_set.ibss_param_set, + ibss_param_set, + sizeof(struct ieee_types_ibss_param_set)); + break; + + case WLAN_EID_ERP_INFO: + bss_entry->erp_flags = *(current_ptr + 2); + break; + + case WLAN_EID_EXT_SUPP_RATES: + /* + * Only process extended supported rate + * if data rate is already found. + * Data rate IE should come before + * extended supported rate IE + */ + if (found_data_rate_ie) { + if ((element_len + rate_size) > + MWIFIEX_SUPPORTED_RATES) + bytes_to_copy = + (MWIFIEX_SUPPORTED_RATES - + rate_size); + else + bytes_to_copy = element_len; + + rate = (u8 *) bss_entry->data_rates; + rate += rate_size; + memcpy(rate, current_ptr + 2, bytes_to_copy); + + rate = (u8 *) bss_entry->supported_rates; + rate += rate_size; + memcpy(rate, current_ptr + 2, bytes_to_copy); + } + break; + + case WLAN_EID_VENDOR_SPECIFIC: + vendor_ie = (struct ieee_types_vendor_specific *) + current_ptr; + + if (!memcmp + (vendor_ie->vend_hdr.oui, wpa_oui, + sizeof(wpa_oui))) { + bss_entry->bcn_wpa_ie = + (struct ieee_types_vendor_specific *) + current_ptr; + bss_entry->wpa_offset = (u16) (current_ptr - + bss_entry->beacon_buf); + } else if (!memcmp(vendor_ie->vend_hdr.oui, wmm_oui, + sizeof(wmm_oui))) { + if (total_ie_len == + sizeof(struct ieee_types_wmm_parameter) + || total_ie_len == + sizeof(struct ieee_types_wmm_info)) + /* + * Only accept and copy the WMM IE if + * it matches the size expected for the + * WMM Info IE or the WMM Parameter IE. + */ + memcpy((u8 *) &bss_entry->wmm_ie, + current_ptr, total_ie_len); + } + break; + case WLAN_EID_RSN: + bss_entry->bcn_rsn_ie = + (struct ieee_types_generic *) current_ptr; + bss_entry->rsn_offset = (u16) (current_ptr - + bss_entry->beacon_buf); + break; + case WLAN_EID_BSS_AC_ACCESS_DELAY: + bss_entry->bcn_wapi_ie = + (struct ieee_types_generic *) current_ptr; + bss_entry->wapi_offset = (u16) (current_ptr - + bss_entry->beacon_buf); + break; + case WLAN_EID_HT_CAPABILITY: + bss_entry->bcn_ht_cap = (struct ieee80211_ht_cap *) + (current_ptr + + sizeof(struct ieee_types_header)); + bss_entry->ht_cap_offset = (u16) (current_ptr + + sizeof(struct ieee_types_header) - + bss_entry->beacon_buf); + break; + case WLAN_EID_HT_INFORMATION: + bss_entry->bcn_ht_info = (struct ieee80211_ht_info *) + (current_ptr + + sizeof(struct ieee_types_header)); + bss_entry->ht_info_offset = (u16) (current_ptr + + sizeof(struct ieee_types_header) - + bss_entry->beacon_buf); + break; + case WLAN_EID_BSS_COEX_2040: + bss_entry->bcn_bss_co_2040 = (u8 *) (current_ptr + + sizeof(struct ieee_types_header)); + bss_entry->bss_co_2040_offset = (u16) (current_ptr + + sizeof(struct ieee_types_header) - + bss_entry->beacon_buf); + break; + case WLAN_EID_EXT_CAPABILITY: + bss_entry->bcn_ext_cap = (u8 *) (current_ptr + + sizeof(struct ieee_types_header)); + bss_entry->ext_cap_offset = (u16) (current_ptr + + sizeof(struct ieee_types_header) - + bss_entry->beacon_buf); + break; + case WLAN_EID_OVERLAP_BSS_SCAN_PARAM: + bss_entry->bcn_obss_scan = + (struct ieee_types_obss_scan_param *) + current_ptr; + bss_entry->overlap_bss_offset = (u16) (current_ptr - + bss_entry->beacon_buf); + break; + default: + break; + } + + current_ptr += element_len + 2; + + /* Need to account for IE ID and IE Len */ + bytes_left_for_current_beacon -= (element_len + 2); + + } /* while (bytes_left_for_current_beacon > 2) */ + return ret; +} + +/* + * This function adjusts the pointers used in beacon buffers to reflect + * shifts. + * + * The memory allocated for beacon buffers is of fixed sizes where all the + * saved beacons must be stored. New beacons are added in the free portion + * of this memory, space permitting; while duplicate beacon buffers are + * placed at the same start location. However, since duplicate beacon + * buffers may not match the size of the old one, all the following buffers + * in the memory must be shifted to either make space, or to fill up freed + * up space. + * + * This function is used to update the beacon buffer pointers that are past + * an existing beacon buffer that is updated with a new one of different + * size. The pointers are shifted by a fixed amount, either forward or + * backward. + * + * the following pointers in every affected beacon buffers are changed, if + * present - + * - WPA IE pointer + * - RSN IE pointer + * - WAPI IE pointer + * - HT capability IE pointer + * - HT information IE pointer + * - BSS coexistence 20/40 IE pointer + * - Extended capability IE pointer + * - Overlapping BSS scan parameter IE pointer + */ +static void +mwifiex_adjust_beacon_buffer_ptrs(struct mwifiex_private *priv, u8 advance, + u8 *bcn_store, u32 rem_bcn_size, + u32 num_of_ent) +{ + struct mwifiex_adapter *adapter = priv->adapter; + u32 adj_idx; + for (adj_idx = 0; adj_idx < num_of_ent; adj_idx++) { + if (adapter->scan_table[adj_idx].beacon_buf > bcn_store) { + + if (advance) + adapter->scan_table[adj_idx].beacon_buf += + rem_bcn_size; + else + adapter->scan_table[adj_idx].beacon_buf -= + rem_bcn_size; + + if (adapter->scan_table[adj_idx].bcn_wpa_ie) + adapter->scan_table[adj_idx].bcn_wpa_ie = + (struct ieee_types_vendor_specific *) + (adapter->scan_table[adj_idx].beacon_buf + + adapter->scan_table[adj_idx].wpa_offset); + if (adapter->scan_table[adj_idx].bcn_rsn_ie) + adapter->scan_table[adj_idx].bcn_rsn_ie = + (struct ieee_types_generic *) + (adapter->scan_table[adj_idx].beacon_buf + + adapter->scan_table[adj_idx].rsn_offset); + if (adapter->scan_table[adj_idx].bcn_wapi_ie) + adapter->scan_table[adj_idx].bcn_wapi_ie = + (struct ieee_types_generic *) + (adapter->scan_table[adj_idx].beacon_buf + + adapter->scan_table[adj_idx].wapi_offset); + if (adapter->scan_table[adj_idx].bcn_ht_cap) + adapter->scan_table[adj_idx].bcn_ht_cap = + (struct ieee80211_ht_cap *) + (adapter->scan_table[adj_idx].beacon_buf + + adapter->scan_table[adj_idx].ht_cap_offset); + + if (adapter->scan_table[adj_idx].bcn_ht_info) + adapter->scan_table[adj_idx].bcn_ht_info = + (struct ieee80211_ht_info *) + (adapter->scan_table[adj_idx].beacon_buf + + adapter->scan_table[adj_idx].ht_info_offset); + if (adapter->scan_table[adj_idx].bcn_bss_co_2040) + adapter->scan_table[adj_idx].bcn_bss_co_2040 = + (u8 *) + (adapter->scan_table[adj_idx].beacon_buf + + adapter->scan_table[adj_idx].bss_co_2040_offset); + if (adapter->scan_table[adj_idx].bcn_ext_cap) + adapter->scan_table[adj_idx].bcn_ext_cap = + (u8 *) + (adapter->scan_table[adj_idx].beacon_buf + + adapter->scan_table[adj_idx].ext_cap_offset); + if (adapter->scan_table[adj_idx].bcn_obss_scan) + adapter->scan_table[adj_idx].bcn_obss_scan = + (struct ieee_types_obss_scan_param *) + (adapter->scan_table[adj_idx].beacon_buf + + adapter->scan_table[adj_idx].overlap_bss_offset); + } + } +} + +/* + * This function updates the pointers used in beacon buffer for given bss + * descriptor to reflect shifts + * + * Following pointers are updated + * - WPA IE pointer + * - RSN IE pointer + * - WAPI IE pointer + * - HT capability IE pointer + * - HT information IE pointer + * - BSS coexistence 20/40 IE pointer + * - Extended capability IE pointer + * - Overlapping BSS scan parameter IE pointer + */ +static void +mwifiex_update_beacon_buffer_ptrs(struct mwifiex_bssdescriptor *beacon) +{ + if (beacon->bcn_wpa_ie) + beacon->bcn_wpa_ie = (struct ieee_types_vendor_specific *) + (beacon->beacon_buf + beacon->wpa_offset); + if (beacon->bcn_rsn_ie) + beacon->bcn_rsn_ie = (struct ieee_types_generic *) + (beacon->beacon_buf + beacon->rsn_offset); + if (beacon->bcn_wapi_ie) + beacon->bcn_wapi_ie = (struct ieee_types_generic *) + (beacon->beacon_buf + beacon->wapi_offset); + if (beacon->bcn_ht_cap) + beacon->bcn_ht_cap = (struct ieee80211_ht_cap *) + (beacon->beacon_buf + beacon->ht_cap_offset); + if (beacon->bcn_ht_info) + beacon->bcn_ht_info = (struct ieee80211_ht_info *) + (beacon->beacon_buf + beacon->ht_info_offset); + if (beacon->bcn_bss_co_2040) + beacon->bcn_bss_co_2040 = (u8 *) (beacon->beacon_buf + + beacon->bss_co_2040_offset); + if (beacon->bcn_ext_cap) + beacon->bcn_ext_cap = (u8 *) (beacon->beacon_buf + + beacon->ext_cap_offset); + if (beacon->bcn_obss_scan) + beacon->bcn_obss_scan = (struct ieee_types_obss_scan_param *) + (beacon->beacon_buf + beacon->overlap_bss_offset); +} + +/* + * This function stores a beacon or probe response for a BSS returned + * in the scan. + * + * This stores a new scan response or an update for a previous scan response. + * New entries need to verify that they do not exceed the total amount of + * memory allocated for the table. + * + * Replacement entries need to take into consideration the amount of space + * currently allocated for the beacon/probe response and adjust the entry + * as needed. + * + * A small amount of extra pad (SCAN_BEACON_ENTRY_PAD) is generally reserved + * for an entry in case it is a beacon since a probe response for the + * network will by larger per the standard. This helps to reduce the + * amount of memory copying to fit a new probe response into an entry + * already occupied by a network's previously stored beacon. + */ +static void +mwifiex_ret_802_11_scan_store_beacon(struct mwifiex_private *priv, + u32 beacon_idx, u32 num_of_ent, + struct mwifiex_bssdescriptor *new_beacon) +{ + struct mwifiex_adapter *adapter = priv->adapter; + u8 *bcn_store; + u32 new_bcn_size; + u32 old_bcn_size; + u32 bcn_space; + + if (adapter->scan_table[beacon_idx].beacon_buf) { + + new_bcn_size = new_beacon->beacon_buf_size; + old_bcn_size = adapter->scan_table[beacon_idx].beacon_buf_size; + bcn_space = adapter->scan_table[beacon_idx].beacon_buf_size_max; + bcn_store = adapter->scan_table[beacon_idx].beacon_buf; + + /* Set the max to be the same as current entry unless changed + below */ + new_beacon->beacon_buf_size_max = bcn_space; + if (new_bcn_size == old_bcn_size) { + /* + * Beacon is the same size as the previous entry. + * Replace the previous contents with the scan result + */ + memcpy(bcn_store, new_beacon->beacon_buf, + new_beacon->beacon_buf_size); + + } else if (new_bcn_size <= bcn_space) { + /* + * New beacon size will fit in the amount of space + * we have previously allocated for it + */ + + /* Copy the new beacon buffer entry over the old one */ + memcpy(bcn_store, new_beacon->beacon_buf, new_bcn_size); + + /* + * If the old beacon size was less than the maximum + * we had alloted for the entry, and the new entry + * is even smaller, reset the max size to the old + * beacon entry and compress the storage space + * (leaving a new pad space of (old_bcn_size - + * new_bcn_size). + */ + if (old_bcn_size < bcn_space + && new_bcn_size <= old_bcn_size) { + /* + * Old Beacon size is smaller than the alloted + * storage size. Shrink the alloted storage + * space. + */ + dev_dbg(adapter->dev, "info: AppControl:" + " smaller duplicate beacon " + "(%d), old = %d, new = %d, space = %d," + "left = %d\n", + beacon_idx, old_bcn_size, new_bcn_size, + bcn_space, + (int)(sizeof(adapter->bcn_buf) - + (adapter->bcn_buf_end - + adapter->bcn_buf))); + + /* + * memmove (since the memory overlaps) the + * data after the beacon we just stored to the + * end of the current beacon. This cleans up + * any unused space the old larger beacon was + * using in the buffer + */ + memmove(bcn_store + old_bcn_size, + bcn_store + bcn_space, + adapter->bcn_buf_end - (bcn_store + + bcn_space)); + + /* + * Decrement the end pointer by the difference + * between the old larger size and the new + * smaller size since we are using less space + * due to the new beacon being smaller + */ + adapter->bcn_buf_end -= + (bcn_space - old_bcn_size); + + /* Set the maximum storage size to the old + beacon size */ + new_beacon->beacon_buf_size_max = old_bcn_size; + + /* Adjust beacon buffer pointers that are past + the current */ + mwifiex_adjust_beacon_buffer_ptrs(priv, 0, + bcn_store, (bcn_space - old_bcn_size), + num_of_ent); + } + } else if (adapter->bcn_buf_end + (new_bcn_size - bcn_space) + < (adapter->bcn_buf + sizeof(adapter->bcn_buf))) { + /* + * Beacon is larger than space previously allocated + * (bcn_space) and there is enough space left in the + * beaconBuffer to store the additional data + */ + dev_dbg(adapter->dev, "info: AppControl:" + " larger duplicate beacon (%d), " + "old = %d, new = %d, space = %d, left = %d\n", + beacon_idx, old_bcn_size, new_bcn_size, + bcn_space, + (int)(sizeof(adapter->bcn_buf) - + (adapter->bcn_buf_end - + adapter->bcn_buf))); + + /* + * memmove (since the memory overlaps) the data + * after the beacon we just stored to the end of + * the current beacon. This moves the data for + * the beacons after this further in memory to + * make space for the new larger beacon we are + * about to copy in. + */ + memmove(bcn_store + new_bcn_size, + bcn_store + bcn_space, + adapter->bcn_buf_end - (bcn_store + bcn_space)); + + /* Copy the new beacon buffer entry over the old one */ + memcpy(bcn_store, new_beacon->beacon_buf, new_bcn_size); + + /* Move the beacon end pointer by the amount of new + beacon data we are adding */ + adapter->bcn_buf_end += (new_bcn_size - bcn_space); + + /* + * This entry is bigger than the alloted max space + * previously reserved. Increase the max space to + * be equal to the new beacon size + */ + new_beacon->beacon_buf_size_max = new_bcn_size; + + /* Adjust beacon buffer pointers that are past the + current */ + mwifiex_adjust_beacon_buffer_ptrs(priv, 1, bcn_store, + (new_bcn_size - bcn_space), + num_of_ent); + } else { + /* + * Beacon is larger than the previously allocated space, + * but there is not enough free space to store the + * additional data. + */ + dev_err(adapter->dev, "AppControl: larger duplicate " + " beacon (%d), old = %d new = %d, space = %d," + " left = %d\n", beacon_idx, old_bcn_size, + new_bcn_size, bcn_space, + (int)(sizeof(adapter->bcn_buf) - + (adapter->bcn_buf_end - adapter->bcn_buf))); + + /* Storage failure, keep old beacon intact */ + new_beacon->beacon_buf_size = old_bcn_size; + if (new_beacon->bcn_wpa_ie) + new_beacon->wpa_offset = + adapter->scan_table[beacon_idx]. + wpa_offset; + if (new_beacon->bcn_rsn_ie) + new_beacon->rsn_offset = + adapter->scan_table[beacon_idx]. + rsn_offset; + if (new_beacon->bcn_wapi_ie) + new_beacon->wapi_offset = + adapter->scan_table[beacon_idx]. + wapi_offset; + if (new_beacon->bcn_ht_cap) + new_beacon->ht_cap_offset = + adapter->scan_table[beacon_idx]. + ht_cap_offset; + if (new_beacon->bcn_ht_info) + new_beacon->ht_info_offset = + adapter->scan_table[beacon_idx]. + ht_info_offset; + if (new_beacon->bcn_bss_co_2040) + new_beacon->bss_co_2040_offset = + adapter->scan_table[beacon_idx]. + bss_co_2040_offset; + if (new_beacon->bcn_ext_cap) + new_beacon->ext_cap_offset = + adapter->scan_table[beacon_idx]. + ext_cap_offset; + if (new_beacon->bcn_obss_scan) + new_beacon->overlap_bss_offset = + adapter->scan_table[beacon_idx]. + overlap_bss_offset; + } + /* Point the new entry to its permanent storage space */ + new_beacon->beacon_buf = bcn_store; + mwifiex_update_beacon_buffer_ptrs(new_beacon); + } else { + /* + * No existing beacon data exists for this entry, check to see + * if we can fit it in the remaining space + */ + if (adapter->bcn_buf_end + new_beacon->beacon_buf_size + + SCAN_BEACON_ENTRY_PAD < (adapter->bcn_buf + + sizeof(adapter->bcn_buf))) { + + /* + * Copy the beacon buffer data from the local entry to + * the adapter dev struct buffer space used to store + * the raw beacon data for each entry in the scan table + */ + memcpy(adapter->bcn_buf_end, new_beacon->beacon_buf, + new_beacon->beacon_buf_size); + + /* Update the beacon ptr to point to the table save + area */ + new_beacon->beacon_buf = adapter->bcn_buf_end; + new_beacon->beacon_buf_size_max = + (new_beacon->beacon_buf_size + + SCAN_BEACON_ENTRY_PAD); + + mwifiex_update_beacon_buffer_ptrs(new_beacon); + + /* Increment the end pointer by the size reserved */ + adapter->bcn_buf_end += new_beacon->beacon_buf_size_max; + + dev_dbg(adapter->dev, "info: AppControl: beacon[%02d]" + " sz=%03d, used = %04d, left = %04d\n", + beacon_idx, + new_beacon->beacon_buf_size, + (int)(adapter->bcn_buf_end - adapter->bcn_buf), + (int)(sizeof(adapter->bcn_buf) - + (adapter->bcn_buf_end - + adapter->bcn_buf))); + } else { + /* No space for new beacon */ + dev_dbg(adapter->dev, "info: AppControl: no space for" + " beacon (%d): %pM sz=%03d, left=%03d\n", + beacon_idx, new_beacon->mac_address, + new_beacon->beacon_buf_size, + (int)(sizeof(adapter->bcn_buf) - + (adapter->bcn_buf_end - + adapter->bcn_buf))); + + /* Storage failure; clear storage records for this + bcn */ + new_beacon->beacon_buf = NULL; + new_beacon->beacon_buf_size = 0; + new_beacon->beacon_buf_size_max = 0; + new_beacon->bcn_wpa_ie = NULL; + new_beacon->wpa_offset = 0; + new_beacon->bcn_rsn_ie = NULL; + new_beacon->rsn_offset = 0; + new_beacon->bcn_wapi_ie = NULL; + new_beacon->wapi_offset = 0; + new_beacon->bcn_ht_cap = NULL; + new_beacon->ht_cap_offset = 0; + new_beacon->bcn_ht_info = NULL; + new_beacon->ht_info_offset = 0; + new_beacon->bcn_bss_co_2040 = NULL; + new_beacon->bss_co_2040_offset = 0; + new_beacon->bcn_ext_cap = NULL; + new_beacon->ext_cap_offset = 0; + new_beacon->bcn_obss_scan = NULL; + new_beacon->overlap_bss_offset = 0; + } + } +} + +/* + * This function restores a beacon buffer of the current BSS descriptor. + */ +static void mwifiex_restore_curr_bcn(struct mwifiex_private *priv) +{ + struct mwifiex_adapter *adapter = priv->adapter; + struct mwifiex_bssdescriptor *curr_bss = + &priv->curr_bss_params.bss_descriptor; + unsigned long flags; + + if (priv->curr_bcn_buf && + ((adapter->bcn_buf_end + priv->curr_bcn_size) < + (adapter->bcn_buf + sizeof(adapter->bcn_buf)))) { + spin_lock_irqsave(&priv->curr_bcn_buf_lock, flags); + + /* restore the current beacon buffer */ + memcpy(adapter->bcn_buf_end, priv->curr_bcn_buf, + priv->curr_bcn_size); + curr_bss->beacon_buf = adapter->bcn_buf_end; + curr_bss->beacon_buf_size = priv->curr_bcn_size; + adapter->bcn_buf_end += priv->curr_bcn_size; + + /* adjust the pointers in the current BSS descriptor */ + if (curr_bss->bcn_wpa_ie) + curr_bss->bcn_wpa_ie = + (struct ieee_types_vendor_specific *) + (curr_bss->beacon_buf + + curr_bss->wpa_offset); + + if (curr_bss->bcn_rsn_ie) + curr_bss->bcn_rsn_ie = (struct ieee_types_generic *) + (curr_bss->beacon_buf + + curr_bss->rsn_offset); + + if (curr_bss->bcn_ht_cap) + curr_bss->bcn_ht_cap = (struct ieee80211_ht_cap *) + (curr_bss->beacon_buf + + curr_bss->ht_cap_offset); + + if (curr_bss->bcn_ht_info) + curr_bss->bcn_ht_info = (struct ieee80211_ht_info *) + (curr_bss->beacon_buf + + curr_bss->ht_info_offset); + + if (curr_bss->bcn_bss_co_2040) + curr_bss->bcn_bss_co_2040 = + (u8 *) (curr_bss->beacon_buf + + curr_bss->bss_co_2040_offset); + + if (curr_bss->bcn_ext_cap) + curr_bss->bcn_ext_cap = (u8 *) (curr_bss->beacon_buf + + curr_bss->ext_cap_offset); + + if (curr_bss->bcn_obss_scan) + curr_bss->bcn_obss_scan = + (struct ieee_types_obss_scan_param *) + (curr_bss->beacon_buf + + curr_bss->overlap_bss_offset); + + spin_unlock_irqrestore(&priv->curr_bcn_buf_lock, flags); + + dev_dbg(adapter->dev, "info: current beacon restored %d\n", + priv->curr_bcn_size); + } else { + dev_warn(adapter->dev, + "curr_bcn_buf not saved or bcn_buf has no space\n"); + } +} + +/* + * This function post processes the scan table after a new scan command has + * completed. + * + * It inspects each entry of the scan table and tries to find an entry that + * matches with our current associated/joined network from the scan. If + * one is found, the stored copy of the BSS descriptor of our current network + * is updated. + * + * It also debug dumps the current scan table contents after processing is over. + */ +static void +mwifiex_process_scan_results(struct mwifiex_private *priv) +{ + struct mwifiex_adapter *adapter = priv->adapter; + s32 j; + u32 i; + unsigned long flags; + + if (priv->media_connected) { + + j = mwifiex_find_ssid_in_list(priv, &priv->curr_bss_params. + bss_descriptor.ssid, + priv->curr_bss_params. + bss_descriptor.mac_address, + priv->bss_mode); + + if (j >= 0) { + spin_lock_irqsave(&priv->curr_bcn_buf_lock, flags); + priv->curr_bss_params.bss_descriptor.bcn_wpa_ie = NULL; + priv->curr_bss_params.bss_descriptor.wpa_offset = 0; + priv->curr_bss_params.bss_descriptor.bcn_rsn_ie = NULL; + priv->curr_bss_params.bss_descriptor.rsn_offset = 0; + priv->curr_bss_params.bss_descriptor.bcn_wapi_ie = NULL; + priv->curr_bss_params.bss_descriptor.wapi_offset = 0; + priv->curr_bss_params.bss_descriptor.bcn_ht_cap = NULL; + priv->curr_bss_params.bss_descriptor.ht_cap_offset = + 0; + priv->curr_bss_params.bss_descriptor.bcn_ht_info = NULL; + priv->curr_bss_params.bss_descriptor.ht_info_offset = + 0; + priv->curr_bss_params.bss_descriptor.bcn_bss_co_2040 = + NULL; + priv->curr_bss_params.bss_descriptor. + bss_co_2040_offset = 0; + priv->curr_bss_params.bss_descriptor.bcn_ext_cap = NULL; + priv->curr_bss_params.bss_descriptor.ext_cap_offset = 0; + priv->curr_bss_params.bss_descriptor. + bcn_obss_scan = NULL; + priv->curr_bss_params.bss_descriptor. + overlap_bss_offset = 0; + priv->curr_bss_params.bss_descriptor.beacon_buf = NULL; + priv->curr_bss_params.bss_descriptor.beacon_buf_size = + 0; + priv->curr_bss_params.bss_descriptor. + beacon_buf_size_max = 0; + + dev_dbg(adapter->dev, "info: Found current ssid/bssid" + " in list @ index #%d\n", j); + /* Make a copy of current BSSID descriptor */ + memcpy(&priv->curr_bss_params.bss_descriptor, + &adapter->scan_table[j], + sizeof(priv->curr_bss_params.bss_descriptor)); + + mwifiex_save_curr_bcn(priv); + spin_unlock_irqrestore(&priv->curr_bcn_buf_lock, flags); + + } else { + mwifiex_restore_curr_bcn(priv); + } + } + + for (i = 0; i < adapter->num_in_scan_table; i++) + dev_dbg(adapter->dev, "info: scan:(%02d) %pM " + "RSSI[%03d], SSID[%s]\n", + i, adapter->scan_table[i].mac_address, + (s32) adapter->scan_table[i].rssi, + adapter->scan_table[i].ssid.ssid); +} + +/* + * This function converts radio type scan parameter to a band configuration + * to be used in join command. + */ +static u8 +mwifiex_radio_type_to_band(u8 radio_type) +{ + u8 ret_band; + + switch (radio_type) { + case HostCmd_SCAN_RADIO_TYPE_A: + ret_band = BAND_A; + break; + case HostCmd_SCAN_RADIO_TYPE_BG: + default: + ret_band = BAND_G; + break; + } + + return ret_band; +} + +/* + * This function deletes a specific indexed entry from the scan table. + * + * This also compacts the remaining entries and adjusts any buffering + * of beacon/probe response data if needed. + */ +static void +mwifiex_scan_delete_table_entry(struct mwifiex_private *priv, s32 table_idx) +{ + struct mwifiex_adapter *adapter = priv->adapter; + u32 del_idx; + u32 beacon_buf_adj; + u8 *beacon_buf; + + /* + * Shift the saved beacon buffer data for the scan table back over the + * entry being removed. Update the end of buffer pointer. Save the + * deleted buffer allocation size for pointer adjustments for entries + * compacted after the deleted index. + */ + beacon_buf_adj = adapter->scan_table[table_idx].beacon_buf_size_max; + + dev_dbg(adapter->dev, "info: Scan: Delete Entry %d, beacon buffer " + "removal = %d bytes\n", table_idx, beacon_buf_adj); + + /* Check if the table entry had storage allocated for its beacon */ + if (beacon_buf_adj) { + beacon_buf = adapter->scan_table[table_idx].beacon_buf; + + /* + * Remove the entry's buffer space, decrement the table end + * pointer by the amount we are removing + */ + adapter->bcn_buf_end -= beacon_buf_adj; + + dev_dbg(adapter->dev, "info: scan: delete entry %d," + " compact data: %p <- %p (sz = %d)\n", + table_idx, beacon_buf, + beacon_buf + beacon_buf_adj, + (int)(adapter->bcn_buf_end - beacon_buf)); + + /* + * Compact data storage. Copy all data after the deleted + * entry's end address (beacon_buf + beacon_buf_adj) back + * to the original start address (beacon_buf). + * + * Scan table entries affected by the move will have their + * entry pointer adjusted below. + * + * Use memmove since the dest/src memory regions overlap. + */ + memmove(beacon_buf, beacon_buf + beacon_buf_adj, + adapter->bcn_buf_end - beacon_buf); + } + + dev_dbg(adapter->dev, + "info: Scan: Delete Entry %d, num_in_scan_table = %d\n", + table_idx, adapter->num_in_scan_table); + + /* Shift all of the entries after the table_idx back by one, compacting + the table and removing the requested entry */ + for (del_idx = table_idx; (del_idx + 1) < adapter->num_in_scan_table; + del_idx++) { + /* Copy the next entry over this one */ + memcpy(adapter->scan_table + del_idx, + adapter->scan_table + del_idx + 1, + sizeof(struct mwifiex_bssdescriptor)); + + /* + * Adjust this entry's pointer to its beacon buffer based on + * the removed/compacted entry from the deleted index. Don't + * decrement if the buffer pointer is NULL (no data stored for + * this entry). + */ + if (adapter->scan_table[del_idx].beacon_buf) { + adapter->scan_table[del_idx].beacon_buf -= + beacon_buf_adj; + if (adapter->scan_table[del_idx].bcn_wpa_ie) + adapter->scan_table[del_idx].bcn_wpa_ie = + (struct ieee_types_vendor_specific *) + (adapter->scan_table[del_idx]. + beacon_buf + + adapter->scan_table[del_idx]. + wpa_offset); + if (adapter->scan_table[del_idx].bcn_rsn_ie) + adapter->scan_table[del_idx].bcn_rsn_ie = + (struct ieee_types_generic *) + (adapter->scan_table[del_idx]. + beacon_buf + + adapter->scan_table[del_idx]. + rsn_offset); + if (adapter->scan_table[del_idx].bcn_wapi_ie) + adapter->scan_table[del_idx].bcn_wapi_ie = + (struct ieee_types_generic *) + (adapter->scan_table[del_idx].beacon_buf + + adapter->scan_table[del_idx]. + wapi_offset); + if (adapter->scan_table[del_idx].bcn_ht_cap) + adapter->scan_table[del_idx].bcn_ht_cap = + (struct ieee80211_ht_cap *) + (adapter->scan_table[del_idx].beacon_buf + + adapter->scan_table[del_idx]. + ht_cap_offset); + + if (adapter->scan_table[del_idx].bcn_ht_info) + adapter->scan_table[del_idx].bcn_ht_info = + (struct ieee80211_ht_info *) + (adapter->scan_table[del_idx].beacon_buf + + adapter->scan_table[del_idx]. + ht_info_offset); + if (adapter->scan_table[del_idx].bcn_bss_co_2040) + adapter->scan_table[del_idx].bcn_bss_co_2040 = + (u8 *) + (adapter->scan_table[del_idx].beacon_buf + + adapter->scan_table[del_idx]. + bss_co_2040_offset); + if (adapter->scan_table[del_idx].bcn_ext_cap) + adapter->scan_table[del_idx].bcn_ext_cap = + (u8 *) + (adapter->scan_table[del_idx].beacon_buf + + adapter->scan_table[del_idx]. + ext_cap_offset); + if (adapter->scan_table[del_idx].bcn_obss_scan) + adapter->scan_table[del_idx]. + bcn_obss_scan = + (struct ieee_types_obss_scan_param *) + (adapter->scan_table[del_idx].beacon_buf + + adapter->scan_table[del_idx]. + overlap_bss_offset); + } + } + + /* The last entry is invalid now that it has been deleted or moved + back */ + memset(adapter->scan_table + adapter->num_in_scan_table - 1, + 0x00, sizeof(struct mwifiex_bssdescriptor)); + + adapter->num_in_scan_table--; +} + +/* + * This function deletes all occurrences of a given SSID from the scan table. + * + * This iterates through the scan table and deletes all entries that match + * the given SSID. It also compacts the remaining scan table entries. + */ +static int +mwifiex_scan_delete_ssid_table_entry(struct mwifiex_private *priv, + struct mwifiex_802_11_ssid *del_ssid) +{ + int ret = -1; + s32 table_idx; + + dev_dbg(priv->adapter->dev, "info: scan: delete ssid entry: %-32s\n", + del_ssid->ssid); + + /* If the requested SSID is found in the table, delete it. Then keep + searching the table for multiple entires for the SSID until no + more are found */ + while ((table_idx = mwifiex_find_ssid_in_list(priv, del_ssid, NULL, + MWIFIEX_BSS_MODE_AUTO)) >= + 0) { + dev_dbg(priv->adapter->dev, + "info: Scan: Delete SSID Entry: Found Idx = %d\n", + table_idx); + ret = 0; + mwifiex_scan_delete_table_entry(priv, table_idx); + } + + return ret; +} + +/* + * This is an internal function used to start a scan based on an input + * configuration. + * + * This uses the input user scan configuration information when provided in + * order to send the appropriate scan commands to firmware to populate or + * update the internal driver scan table. + */ +int mwifiex_scan_networks(struct mwifiex_private *priv, + void *wait_buf, u16 action, + const struct mwifiex_user_scan_cfg *user_scan_in, + struct mwifiex_scan_resp *scan_resp) +{ + int ret = 0; + struct mwifiex_adapter *adapter = priv->adapter; + struct cmd_ctrl_node *cmd_node = NULL; + union mwifiex_scan_cmd_config_tlv *scan_cfg_out = NULL; + struct mwifiex_ie_types_chan_list_param_set *chan_list_out; + u32 buf_size; + struct mwifiex_chan_scan_param_set *scan_chan_list; + u8 keep_previous_scan; + u8 filtered_scan; + u8 scan_current_chan_only; + u8 max_chan_per_scan; + unsigned long flags; + + if (action == HostCmd_ACT_GEN_GET) { + if (scan_resp) { + scan_resp->scan_table = (u8 *) adapter->scan_table; + scan_resp->num_in_scan_table = + adapter->num_in_scan_table; + } else { + ret = -1; + } + return ret; + } + + if (adapter->scan_processing && action == HostCmd_ACT_GEN_SET) { + dev_dbg(adapter->dev, "cmd: Scan already in process...\n"); + return ret; + } + + spin_lock_irqsave(&adapter->mwifiex_cmd_lock, flags); + adapter->scan_processing = true; + spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock, flags); + + if (priv->scan_block && action == HostCmd_ACT_GEN_SET) { + dev_dbg(adapter->dev, + "cmd: Scan is blocked during association...\n"); + return ret; + } + + scan_cfg_out = kzalloc(sizeof(union mwifiex_scan_cmd_config_tlv), + GFP_KERNEL); + if (!scan_cfg_out) { + dev_err(adapter->dev, "failed to alloc scan_cfg_out\n"); + return -1; + } + + buf_size = sizeof(struct mwifiex_chan_scan_param_set) * + MWIFIEX_USER_SCAN_CHAN_MAX; + scan_chan_list = kzalloc(buf_size, GFP_KERNEL); + if (!scan_chan_list) { + dev_err(adapter->dev, "failed to alloc scan_chan_list\n"); + kfree(scan_cfg_out); + return -1; + } + + keep_previous_scan = false; + + mwifiex_scan_setup_scan_config(priv, user_scan_in, + &scan_cfg_out->config, &chan_list_out, + scan_chan_list, &max_chan_per_scan, + &filtered_scan, &scan_current_chan_only); + + if (user_scan_in) + keep_previous_scan = user_scan_in->keep_previous_scan; + + + if (!keep_previous_scan) { + memset(adapter->scan_table, 0x00, + sizeof(struct mwifiex_bssdescriptor) * IW_MAX_AP); + adapter->num_in_scan_table = 0; + adapter->bcn_buf_end = adapter->bcn_buf; + } + + ret = mwifiex_scan_channel_list(priv, wait_buf, max_chan_per_scan, + filtered_scan, &scan_cfg_out->config, + chan_list_out, scan_chan_list); + + /* Get scan command from scan_pending_q and put to cmd_pending_q */ + if (!ret) { + spin_lock_irqsave(&adapter->scan_pending_q_lock, flags); + if (!list_empty(&adapter->scan_pending_q)) { + cmd_node = list_first_entry(&adapter->scan_pending_q, + struct cmd_ctrl_node, list); + list_del(&cmd_node->list); + spin_unlock_irqrestore(&adapter->scan_pending_q_lock, + flags); + mwifiex_insert_cmd_to_pending_q(adapter, cmd_node, + true); + } else { + spin_unlock_irqrestore(&adapter->scan_pending_q_lock, + flags); + } + ret = -EINPROGRESS; + } else { + spin_lock_irqsave(&adapter->mwifiex_cmd_lock, flags); + adapter->scan_processing = true; + spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock, flags); + } + + kfree(scan_cfg_out); + kfree(scan_chan_list); + return ret; +} + +/* + * This function prepares a scan command to be sent to the firmware. + * + * This uses the scan command configuration sent to the command processing + * module in command preparation stage to configure a scan command structure + * to send to firmware. + * + * The fixed fields specifying the BSS type and BSSID filters as well as a + * variable number/length of TLVs are sent in the command to firmware. + * + * Preparation also includes - + * - Setting command ID, and proper size + * - Ensuring correct endian-ness + */ +int mwifiex_cmd_802_11_scan(struct mwifiex_private *priv, + struct host_cmd_ds_command *cmd, void *data_buf) +{ + struct host_cmd_ds_802_11_scan *scan_cmd = &cmd->params.scan; + struct mwifiex_scan_cmd_config *scan_cfg; + + scan_cfg = (struct mwifiex_scan_cmd_config *) data_buf; + + /* Set fixed field variables in scan command */ + scan_cmd->bss_mode = scan_cfg->bss_mode; + memcpy(scan_cmd->bssid, scan_cfg->specific_bssid, + sizeof(scan_cmd->bssid)); + memcpy(scan_cmd->tlv_buffer, scan_cfg->tlv_buf, scan_cfg->tlv_buf_len); + + cmd->command = cpu_to_le16(HostCmd_CMD_802_11_SCAN); + + /* Size is equal to the sizeof(fixed portions) + the TLV len + header */ + cmd->size = cpu_to_le16((u16) (sizeof(scan_cmd->bss_mode) + + sizeof(scan_cmd->bssid) + + scan_cfg->tlv_buf_len + S_DS_GEN)); + + return 0; +} + +/* + * This function handles the command response of scan. + * + * The response buffer for the scan command has the following + * memory layout: + * + * .-------------------------------------------------------------. + * | Header (4 * sizeof(t_u16)): Standard command response hdr | + * .-------------------------------------------------------------. + * | BufSize (t_u16) : sizeof the BSS Description data | + * .-------------------------------------------------------------. + * | NumOfSet (t_u8) : Number of BSS Descs returned | + * .-------------------------------------------------------------. + * | BSSDescription data (variable, size given in BufSize) | + * .-------------------------------------------------------------. + * | TLV data (variable, size calculated using Header->Size, | + * | BufSize and sizeof the fixed fields above) | + * .-------------------------------------------------------------. + */ +int mwifiex_ret_802_11_scan(struct mwifiex_private *priv, + struct host_cmd_ds_command *resp, void *wq_buf) +{ + int ret = 0; + struct mwifiex_adapter *adapter = priv->adapter; + struct mwifiex_wait_queue *wait_queue = NULL; + struct cmd_ctrl_node *cmd_node = NULL; + struct host_cmd_ds_802_11_scan_rsp *scan_rsp = NULL; + struct mwifiex_bssdescriptor *bss_new_entry = NULL; + struct mwifiex_ie_types_data *tlv_data; + struct mwifiex_ie_types_tsf_timestamp *tsf_tlv; + u8 *bss_info; + u32 scan_resp_size; + u32 bytes_left; + u32 num_in_table; + u32 bss_idx; + u32 idx; + u32 tlv_buf_size; + long long tsf_val; + struct mwifiex_chan_freq_power *cfp; + struct mwifiex_ie_types_chan_band_list_param_set *chan_band_tlv; + struct chan_band_param_set *chan_band; + u8 band; + u8 is_bgscan_resp; + unsigned long flags; + + is_bgscan_resp = (le16_to_cpu(resp->command) + == HostCmd_CMD_802_11_BG_SCAN_QUERY); + if (is_bgscan_resp) + scan_rsp = &resp->params.bg_scan_query_resp.scan_resp; + else + scan_rsp = &resp->params.scan_resp; + + + if (scan_rsp->number_of_sets > IW_MAX_AP) { + dev_err(adapter->dev, "SCAN_RESP: too many AP returned (%d)\n", + scan_rsp->number_of_sets); + ret = -1; + goto done; + } + + bytes_left = le16_to_cpu(scan_rsp->bss_descript_size); + dev_dbg(adapter->dev, "info: SCAN_RESP: bss_descript_size %d\n", + bytes_left); + + scan_resp_size = le16_to_cpu(resp->size); + + dev_dbg(adapter->dev, + "info: SCAN_RESP: returned %d APs before parsing\n", + scan_rsp->number_of_sets); + + num_in_table = adapter->num_in_scan_table; + bss_info = scan_rsp->bss_desc_and_tlv_buffer; + + /* + * The size of the TLV buffer is equal to the entire command response + * size (scan_resp_size) minus the fixed fields (sizeof()'s), the + * BSS Descriptions (bss_descript_size as bytesLef) and the command + * response header (S_DS_GEN) + */ + tlv_buf_size = scan_resp_size - (bytes_left + + sizeof(scan_rsp->bss_descript_size) + + sizeof(scan_rsp->number_of_sets) + + S_DS_GEN); + + tlv_data = (struct mwifiex_ie_types_data *) (scan_rsp-> + bss_desc_and_tlv_buffer + + bytes_left); + + /* Search the TLV buffer space in the scan response for any valid + TLVs */ + mwifiex_ret_802_11_scan_get_tlv_ptrs(adapter, tlv_data, tlv_buf_size, + TLV_TYPE_TSFTIMESTAMP, + (struct mwifiex_ie_types_data **) + &tsf_tlv); + + /* Search the TLV buffer space in the scan response for any valid + TLVs */ + mwifiex_ret_802_11_scan_get_tlv_ptrs(adapter, tlv_data, tlv_buf_size, + TLV_TYPE_CHANNELBANDLIST, + (struct mwifiex_ie_types_data **) + &chan_band_tlv); + + /* + * Process each scan response returned (scan_rsp->number_of_sets). + * Save the information in the bss_new_entry and then insert into the + * driver scan table either as an update to an existing entry + * or as an addition at the end of the table + */ + bss_new_entry = kzalloc(sizeof(struct mwifiex_bssdescriptor), + GFP_KERNEL); + if (!bss_new_entry) { + dev_err(adapter->dev, " failed to alloc bss_new_entry\n"); + return -1; + } + + for (idx = 0; idx < scan_rsp->number_of_sets && bytes_left; idx++) { + /* Zero out the bss_new_entry we are about to store info in */ + memset(bss_new_entry, 0x00, + sizeof(struct mwifiex_bssdescriptor)); + + if (mwifiex_interpret_bss_desc_with_ie(adapter, bss_new_entry, + &bss_info, + &bytes_left)) { + /* Error parsing/interpreting scan response, skipped */ + dev_err(adapter->dev, "SCAN_RESP: " + "mwifiex_interpret_bss_desc_with_ie " + "returned ERROR\n"); + continue; + } + + /* Process the data fields and IEs returned for this BSS */ + dev_dbg(adapter->dev, "info: SCAN_RESP: BSSID = %pM\n", + bss_new_entry->mac_address); + + /* Search the scan table for the same bssid */ + for (bss_idx = 0; bss_idx < num_in_table; bss_idx++) { + if (memcmp(bss_new_entry->mac_address, + adapter->scan_table[bss_idx].mac_address, + sizeof(bss_new_entry->mac_address))) { + continue; + } + /* + * If the SSID matches as well, it is a + * duplicate of this entry. Keep the bss_idx + * set to this entry so we replace the old + * contents in the table + */ + if ((bss_new_entry->ssid.ssid_len + == adapter->scan_table[bss_idx]. ssid.ssid_len) + && (!memcmp(bss_new_entry->ssid.ssid, + adapter->scan_table[bss_idx].ssid.ssid, + bss_new_entry->ssid.ssid_len))) { + dev_dbg(adapter->dev, "info: SCAN_RESP:" + " duplicate of index: %d\n", bss_idx); + break; + } + } + /* + * If the bss_idx is equal to the number of entries in + * the table, the new entry was not a duplicate; append + * it to the scan table + */ + if (bss_idx == num_in_table) { + /* Range check the bss_idx, keep it limited to + the last entry */ + if (bss_idx == IW_MAX_AP) + bss_idx--; + else + num_in_table++; + } + + /* + * Save the beacon/probe response returned for later application + * retrieval. Duplicate beacon/probe responses are updated if + * possible + */ + mwifiex_ret_802_11_scan_store_beacon(priv, bss_idx, + num_in_table, bss_new_entry); + /* + * If the TSF TLV was appended to the scan results, save this + * entry's TSF value in the networkTSF field.The networkTSF is + * the firmware's TSF value at the time the beacon or probe + * response was received. + */ + if (tsf_tlv) { + memcpy(&tsf_val, &tsf_tlv->tsf_data[idx * TSF_DATA_SIZE] + , sizeof(tsf_val)); + memcpy(&bss_new_entry->network_tsf, &tsf_val, + sizeof(bss_new_entry->network_tsf)); + } + band = BAND_G; + if (chan_band_tlv) { + chan_band = &chan_band_tlv->chan_band_param[idx]; + band = mwifiex_radio_type_to_band(chan_band->radio_type + & (BIT(0) | BIT(1))); + } + + /* Save the band designation for this entry for use in join */ + bss_new_entry->bss_band = band; + cfp = mwifiex_get_cfp_by_band_and_channel_from_cfg80211(priv, + (u8) bss_new_entry->bss_band, + (u16)bss_new_entry->channel); + + if (cfp) + bss_new_entry->freq = cfp->freq; + else + bss_new_entry->freq = 0; + + /* Copy the locally created bss_new_entry to the scan table */ + memcpy(&adapter->scan_table[bss_idx], bss_new_entry, + sizeof(adapter->scan_table[bss_idx])); + + } + + dev_dbg(adapter->dev, + "info: SCAN_RESP: Scanned %2d APs, %d valid, %d total\n", + scan_rsp->number_of_sets, + num_in_table - adapter->num_in_scan_table, num_in_table); + + /* Update the total number of BSSIDs in the scan table */ + adapter->num_in_scan_table = num_in_table; + + 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); + spin_lock_irqsave(&adapter->mwifiex_cmd_lock, flags); + adapter->scan_processing = false; + spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock, flags); + /* + * Process the resulting scan table: + * - Remove any bad ssids + * - Update our current BSS information from scan data + */ + mwifiex_process_scan_results(priv); + + /* Need to indicate IOCTL complete */ + wait_queue = (struct mwifiex_wait_queue *) wq_buf; + if (wait_queue) { + wait_queue->status = MWIFIEX_ERROR_NO_ERROR; + + /* Indicate ioctl complete */ + mwifiex_ioctl_complete(adapter, + (struct mwifiex_wait_queue *) wait_queue, 0); + } + if (priv->report_scan_result) + priv->report_scan_result = false; + if (priv->scan_pending_on_block) { + priv->scan_pending_on_block = false; + up(&priv->async_sem); + } + + } else { + /* Get scan command from scan_pending_q and put to + cmd_pending_q */ + cmd_node = list_first_entry(&adapter->scan_pending_q, + struct cmd_ctrl_node, list); + list_del(&cmd_node->list); + spin_unlock_irqrestore(&adapter->scan_pending_q_lock, flags); + + mwifiex_insert_cmd_to_pending_q(adapter, cmd_node, true); + } + +done: + kfree((u8 *) bss_new_entry); + return ret; +} + +/* + * This function prepares command for background scan query. + * + * Preparation includes - + * - Setting command ID and proper size + * - Setting background scan flush parameter + * - Ensuring correct endian-ness + */ +int mwifiex_cmd_802_11_bg_scan_query(struct mwifiex_private *priv, + struct host_cmd_ds_command *cmd, + void *data_buf) +{ + struct host_cmd_ds_802_11_bg_scan_query *bg_query = + &cmd->params.bg_scan_query; + + cmd->command = cpu_to_le16(HostCmd_CMD_802_11_BG_SCAN_QUERY); + cmd->size = cpu_to_le16(sizeof(struct host_cmd_ds_802_11_bg_scan_query) + + S_DS_GEN); + + bg_query->flush = 1; + + return 0; +} + +/* + * This function finds a SSID in the scan table. + * + * A BSSID may optionally be provided to qualify the SSID. + * For non-Auto mode, further check is made to make sure the + * BSS found in the scan table is compatible with the current + * settings of the driver. + */ +s32 +mwifiex_find_ssid_in_list(struct mwifiex_private *priv, + struct mwifiex_802_11_ssid *ssid, u8 *bssid, + u32 mode) +{ + struct mwifiex_adapter *adapter = priv->adapter; + s32 net = -1, j; + u8 best_rssi = 0; + u32 i; + + dev_dbg(adapter->dev, "info: num of entries in table = %d\n", + adapter->num_in_scan_table); + + /* + * Loop through the table until the maximum is reached or until a match + * is found based on the bssid field comparison + */ + for (i = 0; + i < adapter->num_in_scan_table && (!bssid || (bssid && net < 0)); + i++) { + if (!mwifiex_ssid_cmp(&adapter->scan_table[i].ssid, ssid) && + (!bssid + || !memcmp(adapter->scan_table[i].mac_address, bssid, + ETH_ALEN)) + && + (mwifiex_get_cfp_by_band_and_channel_from_cfg80211 + (priv, (u8) adapter->scan_table[i].bss_band, + (u16) adapter->scan_table[i].channel))) { + switch (mode) { + case MWIFIEX_BSS_MODE_INFRA: + case MWIFIEX_BSS_MODE_IBSS: + j = mwifiex_is_network_compatible(priv, i, + mode); + + if (j >= 0) { + if (SCAN_RSSI + (adapter->scan_table[i].rssi) > + best_rssi) { + best_rssi = SCAN_RSSI(adapter-> + scan_table + [i].rssi); + net = i; + } + } else { + if (net == -1) + net = j; + } + break; + case MWIFIEX_BSS_MODE_AUTO: + default: + /* + * Do not check compatibility if the mode + * requested is Auto/Unknown. Allows generic + * find to work without verifying against the + * Adapter security settings + */ + if (SCAN_RSSI(adapter->scan_table[i].rssi) > + best_rssi) { + best_rssi = SCAN_RSSI(adapter-> + scan_table[i].rssi); + net = i; + } + break; + } + } + } + + return net; +} + +/* + * This function finds a specific compatible BSSID in the scan list. + * + * This function loops through the scan table looking for a compatible + * match. If a BSSID matches, but the BSS is found to be not compatible + * the function ignores it and continues to search through the rest of + * the entries in case there is an AP with multiple SSIDs assigned to + * the same BSSID. + */ +s32 +mwifiex_find_bssid_in_list(struct mwifiex_private *priv, u8 *bssid, + u32 mode) +{ + struct mwifiex_adapter *adapter = priv->adapter; + s32 net = -1; + u32 i; + + if (!bssid) + return -1; + + dev_dbg(adapter->dev, "info: FindBSSID: Num of BSSIDs = %d\n", + adapter->num_in_scan_table); + + /* + * Look through the scan table for a compatible match. The ret return + * variable will be equal to the index in the scan table (greater + * than zero) if the network is compatible. The loop will continue + * past a matched bssid that is not compatible in case there is an + * AP with multiple SSIDs assigned to the same BSSID + */ + for (i = 0; net < 0 && i < adapter->num_in_scan_table; i++) { + if (!memcmp + (adapter->scan_table[i].mac_address, bssid, ETH_ALEN) + && mwifiex_get_cfp_by_band_and_channel_from_cfg80211 + (priv, + (u8) adapter-> + scan_table[i]. + bss_band, + (u16) adapter-> + scan_table[i]. + channel)) { + switch (mode) { + case MWIFIEX_BSS_MODE_INFRA: + case MWIFIEX_BSS_MODE_IBSS: + net = mwifiex_is_network_compatible(priv, i, + mode); + break; + default: + net = i; + break; + } + } + } + + return net; +} + +/* + * This function inserts scan command node to the scan pending queue. + */ +void +mwifiex_queue_scan_cmd(struct mwifiex_private *priv, + struct cmd_ctrl_node *cmd_node) +{ + struct mwifiex_adapter *adapter = priv->adapter; + unsigned long flags; + + spin_lock_irqsave(&adapter->scan_pending_q_lock, flags); + list_add_tail(&cmd_node->list, &adapter->scan_pending_q); + spin_unlock_irqrestore(&adapter->scan_pending_q_lock, flags); +} + +/* + * This function finds an AP with specific ssid in the scan list. + */ +int mwifiex_find_best_network(struct mwifiex_private *priv, + struct mwifiex_ssid_bssid *req_ssid_bssid) +{ + struct mwifiex_adapter *adapter = priv->adapter; + struct mwifiex_bssdescriptor *req_bss; + s32 i; + + memset(req_ssid_bssid, 0, sizeof(struct mwifiex_ssid_bssid)); + + i = mwifiex_find_best_network_in_list(priv); + + if (i >= 0) { + req_bss = &adapter->scan_table[i]; + memcpy(&req_ssid_bssid->ssid, &req_bss->ssid, + sizeof(struct mwifiex_802_11_ssid)); + memcpy((u8 *) &req_ssid_bssid->bssid, + (u8 *) &req_bss->mac_address, ETH_ALEN); + + /* Make sure we are in the right mode */ + if (priv->bss_mode == MWIFIEX_BSS_MODE_AUTO) + priv->bss_mode = req_bss->bss_mode; + } + + if (!req_ssid_bssid->ssid.ssid_len) + return -1; + + dev_dbg(adapter->dev, "info: Best network found = [%s], " + "[%pM]\n", req_ssid_bssid->ssid.ssid, + req_ssid_bssid->bssid); + + return 0; +} + +/* + * This function sends a scan command for all available channels to the + * firmware, filtered on a specific SSID. + */ +static int mwifiex_scan_specific_ssid(struct mwifiex_private *priv, + void *wait_buf, u16 action, + struct mwifiex_802_11_ssid *req_ssid, + struct mwifiex_scan_resp *scan_resp) +{ + struct mwifiex_adapter *adapter = priv->adapter; + int ret = 0; + struct mwifiex_user_scan_cfg *scan_cfg; + + if (!req_ssid) + return -1; + + if (action == HostCmd_ACT_GEN_GET) { + if (scan_resp) { + scan_resp->scan_table = + (u8 *) &priv->curr_bss_params.bss_descriptor; + scan_resp->num_in_scan_table = + adapter->num_in_scan_table; + } else { + ret = -1; + } + return ret; + } + + if (adapter->scan_processing && action == HostCmd_ACT_GEN_SET) { + dev_dbg(adapter->dev, "cmd: Scan already in process...\n"); + return ret; + } + + if (priv->scan_block && action == HostCmd_ACT_GEN_SET) { + dev_dbg(adapter->dev, + "cmd: Scan is blocked during association...\n"); + return ret; + } + + mwifiex_scan_delete_ssid_table_entry(priv, req_ssid); + + scan_cfg = kzalloc(sizeof(struct mwifiex_user_scan_cfg), GFP_KERNEL); + if (!scan_cfg) { + dev_err(adapter->dev, "failed to alloc scan_cfg\n"); + return -1; + } + + memcpy(scan_cfg->ssid_list[0].ssid, req_ssid->ssid, + req_ssid->ssid_len); + scan_cfg->keep_previous_scan = true; + + ret = mwifiex_scan_networks(priv, wait_buf, action, scan_cfg, NULL); + + kfree(scan_cfg); + return ret; +} + +/* + * Sends IOCTL request to start a scan. + * + * This function allocates the IOCTL request buffer, fills it + * with requisite parameters and calls the IOCTL handler. + * + * Scan command can be issued for both normal scan and specific SSID + * scan, depending upon whether an SSID is provided or not. + */ +int mwifiex_request_scan(struct mwifiex_private *priv, u8 wait_option, + struct mwifiex_802_11_ssid *req_ssid) +{ + int ret = 0; + struct mwifiex_wait_queue *wait = NULL; + int status = 0; + + if (down_interruptible(&priv->async_sem)) { + dev_err(priv->adapter->dev, "%s: acquire semaphore\n", + __func__); + return -1; + } + priv->scan_pending_on_block = true; + + /* Allocate wait request buffer */ + wait = mwifiex_alloc_fill_wait_queue(priv, wait_option); + if (!wait) { + ret = -1; + goto done; + } + + if (req_ssid && req_ssid->ssid_len != 0) + /* Specific SSID scan */ + status = mwifiex_scan_specific_ssid(priv, wait, + HostCmd_ACT_GEN_SET, + req_ssid, NULL); + else + /* Normal scan */ + status = mwifiex_scan_networks(priv, wait, HostCmd_ACT_GEN_SET, + NULL, NULL); + status = mwifiex_request_ioctl(priv, wait, status, wait_option); + if (status == -1) + ret = -1; +done: + if ((wait) && (status != -EINPROGRESS)) + kfree(wait); + if (ret == -1) { + priv->scan_pending_on_block = false; + up(&priv->async_sem); + } + return ret; +} + +/* + * This function appends the vendor specific IE TLV to a buffer. + */ +int +mwifiex_cmd_append_vsie_tlv(struct mwifiex_private *priv, + u16 vsie_mask, u8 **buffer) +{ + int id, ret_len = 0; + struct mwifiex_ie_types_vendor_param_set *vs_param_set; + + if (!buffer) + return 0; + if (!(*buffer)) + return 0; + + /* + * Traverse through the saved vendor specific IE array and append + * the selected(scan/assoc/adhoc) IE as TLV to the command + */ + for (id = 0; id < MWIFIEX_MAX_VSIE_NUM; id++) { + if (priv->vs_ie[id].mask & vsie_mask) { + vs_param_set = + (struct mwifiex_ie_types_vendor_param_set *) + *buffer; + vs_param_set->header.type = + cpu_to_le16(TLV_TYPE_PASSTHROUGH); + vs_param_set->header.len = + cpu_to_le16((((u16) priv->vs_ie[id].ie[1]) + & 0x00FF) + 2); + memcpy(vs_param_set->ie, priv->vs_ie[id].ie, + le16_to_cpu(vs_param_set->header.len)); + *buffer += le16_to_cpu(vs_param_set->header.len) + + sizeof(struct mwifiex_ie_types_header); + ret_len += le16_to_cpu(vs_param_set->header.len) + + sizeof(struct mwifiex_ie_types_header); + } + } + return ret_len; +} + +/* + * This function saves a beacon buffer of the current BSS descriptor. + * + * The current beacon buffer is saved so that it can be restored in the + * following cases that makes the beacon buffer not to contain the current + * ssid's beacon buffer. + * - The current ssid was not found somehow in the last scan. + * - The current ssid was the last entry of the scan table and overloaded. + */ +void +mwifiex_save_curr_bcn(struct mwifiex_private *priv) +{ + struct mwifiex_bssdescriptor *curr_bss = + &priv->curr_bss_params.bss_descriptor; + + /* save the beacon buffer if it is not saved or updated */ + if ((priv->curr_bcn_buf == NULL) || + (priv->curr_bcn_size != curr_bss->beacon_buf_size) || + (memcmp(priv->curr_bcn_buf, curr_bss->beacon_buf, + curr_bss->beacon_buf_size))) { + + kfree(priv->curr_bcn_buf); + priv->curr_bcn_buf = NULL; + + priv->curr_bcn_size = curr_bss->beacon_buf_size; + if (!priv->curr_bcn_size) + return; + + priv->curr_bcn_buf = kzalloc(curr_bss->beacon_buf_size, + GFP_KERNEL); + if (!priv->curr_bcn_buf) { + dev_err(priv->adapter->dev, + "failed to alloc curr_bcn_buf\n"); + } else { + memcpy(priv->curr_bcn_buf, curr_bss->beacon_buf, + curr_bss->beacon_buf_size); + dev_dbg(priv->adapter->dev, + "info: current beacon saved %d\n", + priv->curr_bcn_size); + } + } +} + +/* + * This function frees the current BSS descriptor beacon buffer. + */ +void +mwifiex_free_curr_bcn(struct mwifiex_private *priv) +{ + kfree(priv->curr_bcn_buf); + priv->curr_bcn_buf = NULL; +} diff --git a/drivers/net/wireless/mwifiex/sdio.c b/drivers/net/wireless/mwifiex/sdio.c new file mode 100644 index 0000000..f21e5cd --- /dev/null +++ b/drivers/net/wireless/mwifiex/sdio.c @@ -0,0 +1,1770 @@ +/* + * Marvell Wireless LAN device driver: SDIO specific handling + * + * Copyright (C) 2011, Marvell International Ltd. + * + * This software file (the "File") is distributed by Marvell International + * Ltd. under the terms of the GNU General Public License Version 2, June 1991 + * (the "License"). You may use, redistribute and/or modify this File in + * accordance with the terms and conditions of the License, a copy of which + * is available by writing to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the + * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. + * + * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE + * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE + * ARE EXPRESSLY DISCLAIMED. The License provides additional details about + * this warranty disclaimer. + */ + +#include + +#include "decl.h" +#include "ioctl.h" +#include "util.h" +#include "fw.h" +#include "main.h" +#include "wmm.h" +#include "11n.h" +#include "sdio.h" + + +#define SDIO_VERSION "1.0" + +static struct mwifiex_if_ops sdio_ops; + +static struct semaphore add_remove_card_sem; + +/* + * SDIO probe. + * + * This function probes an mwifiex device and registers it. It allocates + * the card structure, enables SDIO function number and initiates the + * device registration and initialization procedure by adding a logical + * interface. + */ +static int +mwifiex_sdio_probe(struct sdio_func *func, const struct sdio_device_id *id) +{ + int ret = 0; + struct sdio_mmc_card *card = NULL; + + pr_debug("info: vendor=0x%4.04X device=0x%4.04X class=%d function=%d\n", + func->vendor, func->device, func->class, func->num); + + card = kzalloc(sizeof(struct sdio_mmc_card), GFP_KERNEL); + if (!card) { + pr_err("%s: failed to alloc memory\n", __func__); + return -ENOMEM; + } + + card->func = func; + + func->card->quirks |= MMC_QUIRK_BLKSZ_FOR_BYTE_MODE; + + sdio_claim_host(func); + ret = sdio_enable_func(func); + sdio_release_host(func); + + if (ret) { + pr_err("%s: failed to enable function\n", __func__); + return -EIO; + } + + if (mwifiex_add_card(card, &add_remove_card_sem, &sdio_ops)) { + pr_err("%s: add card failed\n", __func__); + kfree(card); + sdio_claim_host(func); + ret = sdio_disable_func(func); + sdio_release_host(func); + ret = -1; + } + + return ret; +} + +/* + * SDIO remove. + * + * This function removes the interface and frees up the card structure. + */ +static void +mwifiex_sdio_remove(struct sdio_func *func) +{ + struct sdio_mmc_card *card; + + pr_debug("info: SDIO func num=%d\n", func->num); + + if (func) { + card = sdio_get_drvdata(func); + if (card) { + mwifiex_remove_card(card->adapter, + &add_remove_card_sem); + kfree(card); + } + } +} + +/* + * SDIO suspend. + * + * Kernel needs to suspend all functions separately. Therefore all + * registered functions must have drivers with suspend and resume + * methods. Failing that the kernel simply removes the whole card. + * + * If already not suspended, this function allocates and sends a host + * sleep activate request to the firmware and turns off the traffic. + */ +static int mwifiex_sdio_suspend(struct device *dev) +{ + struct sdio_func *func = dev_to_sdio_func(dev); + struct sdio_mmc_card *card; + struct mwifiex_adapter *adapter = NULL; + mmc_pm_flag_t pm_flag = 0; + int hs_actived = 0; + int i; + int ret = 0; + + if (func) { + pm_flag = sdio_get_host_pm_caps(func); + pr_debug("cmd: %s: suspend: PM flag = 0x%x\n", + sdio_func_id(func), pm_flag); + if (!(pm_flag & MMC_PM_KEEP_POWER)) { + pr_err("%s: cannot remain alive while host is" + " suspended\n", sdio_func_id(func)); + return -ENOSYS; + } + + card = sdio_get_drvdata(func); + if (!card || !card->adapter) { + pr_err("suspend: invalid card or adapter\n"); + return 0; + } + } else { + pr_err("suspend: sdio_func is not specified\n"); + return 0; + } + + adapter = card->adapter; + + /* Enable the Host Sleep */ + hs_actived = mwifiex_enable_hs(adapter); + if (hs_actived) { + pr_debug("cmd: suspend with MMC_PM_KEEP_POWER\n"); + ret = sdio_set_host_pm_flags(func, MMC_PM_KEEP_POWER); + } + + /* Indicate device suspended */ + adapter->is_suspended = true; + + for (i = 0; i < adapter->priv_num; i++) + netif_carrier_off(adapter->priv[i]->netdev); + + return ret; +} + +/* + * SDIO resume. + * + * Kernel needs to suspend all functions separately. Therefore all + * registered functions must have drivers with suspend and resume + * methods. Failing that the kernel simply removes the whole card. + * + * If already not resumed, this function turns on the traffic and + * sends a host sleep cancel request to the firmware. + */ +static int mwifiex_sdio_resume(struct device *dev) +{ + struct sdio_func *func = dev_to_sdio_func(dev); + struct sdio_mmc_card *card; + struct mwifiex_adapter *adapter = NULL; + mmc_pm_flag_t pm_flag = 0; + int i; + + if (func) { + pm_flag = sdio_get_host_pm_caps(func); + card = sdio_get_drvdata(func); + if (!card || !card->adapter) { + pr_err("resume: invalid card or adapter\n"); + return 0; + } + } else { + pr_err("resume: sdio_func is not specified\n"); + return 0; + } + + adapter = card->adapter; + + if (!adapter->is_suspended) { + dev_warn(adapter->dev, "device already resumed\n"); + return 0; + } + + adapter->is_suspended = false; + + for (i = 0; i < adapter->priv_num; i++) + if (adapter->priv[i]->media_connected) + netif_carrier_on(adapter->priv[i]->netdev); + + /* Disable Host Sleep */ + mwifiex_cancel_hs(mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_STA), + MWIFIEX_NO_WAIT); + + return 0; +} + +/* Device ID for SD8787 */ +#define SDIO_DEVICE_ID_MARVELL_8787 (0x9119) + +/* WLAN IDs */ +static const struct sdio_device_id mwifiex_ids[] = { + {SDIO_DEVICE(SDIO_VENDOR_ID_MARVELL, SDIO_DEVICE_ID_MARVELL_8787)}, + {}, +}; + +MODULE_DEVICE_TABLE(sdio, mwifiex_ids); + +static const struct dev_pm_ops mwifiex_sdio_pm_ops = { + .suspend = mwifiex_sdio_suspend, + .resume = mwifiex_sdio_resume, +}; + +static struct sdio_driver mwifiex_sdio = { + .name = "mwifiex_sdio", + .id_table = mwifiex_ids, + .probe = mwifiex_sdio_probe, + .remove = mwifiex_sdio_remove, + .drv = { + .owner = THIS_MODULE, + .pm = &mwifiex_sdio_pm_ops, + } +}; + +/* + * This function writes data into SDIO card register. + */ +static int +mwifiex_write_reg(struct mwifiex_adapter *adapter, u32 reg, u32 data) +{ + struct sdio_mmc_card *card = adapter->card; + int ret = -1; + + sdio_claim_host(card->func); + sdio_writeb(card->func, (u8) data, reg, &ret); + sdio_release_host(card->func); + + return ret; +} + +/* + * This function reads data from SDIO card register. + */ +static int +mwifiex_read_reg(struct mwifiex_adapter *adapter, u32 reg, u32 *data) +{ + struct sdio_mmc_card *card = adapter->card; + int ret = -1; + u8 val; + + sdio_claim_host(card->func); + val = sdio_readb(card->func, reg, &ret); + sdio_release_host(card->func); + + *data = val; + + return ret; +} + +/* + * This function writes multiple data into SDIO card memory. + * + * This does not work in suspended mode. + */ +static int +mwifiex_write_data_sync(struct mwifiex_adapter *adapter, + u8 *buffer, u32 pkt_len, u32 port, u32 timeout) +{ + struct sdio_mmc_card *card = adapter->card; + int ret = -1; + u8 blk_mode = + (port & MWIFIEX_SDIO_BYTE_MODE_MASK) ? BYTE_MODE : BLOCK_MODE; + u32 blk_size = (blk_mode == BLOCK_MODE) ? MWIFIEX_SDIO_BLOCK_SIZE : 1; + u32 blk_cnt = + (blk_mode == + BLOCK_MODE) ? (pkt_len / + MWIFIEX_SDIO_BLOCK_SIZE) : pkt_len; + u32 ioport = (port & MWIFIEX_SDIO_IO_PORT_MASK); + + if (adapter->is_suspended) { + dev_err(adapter->dev, + "%s: not allowed while suspended\n", __func__); + return -1; + } + + sdio_claim_host(card->func); + + if (!sdio_writesb(card->func, ioport, buffer, blk_cnt * blk_size)) + ret = 0; + + sdio_release_host(card->func); + + return ret; +} + +/* + * This function reads multiple data from SDIO card memory. + */ +static int mwifiex_read_data_sync(struct mwifiex_adapter *adapter, + u8 *buffer, u32 len, + u32 port, u32 timeout, u8 claim) +{ + struct sdio_mmc_card *card = adapter->card; + int ret = -1; + u8 blk_mode = + (port & MWIFIEX_SDIO_BYTE_MODE_MASK) ? BYTE_MODE : BLOCK_MODE; + u32 blk_size = (blk_mode == BLOCK_MODE) ? MWIFIEX_SDIO_BLOCK_SIZE : 1; + u32 blk_cnt = + (blk_mode == + BLOCK_MODE) ? (len / MWIFIEX_SDIO_BLOCK_SIZE) : len; + u32 ioport = (port & MWIFIEX_SDIO_IO_PORT_MASK); + + if (claim) + sdio_claim_host(card->func); + + if (!sdio_readsb(card->func, buffer, ioport, blk_cnt * blk_size)) + ret = 0; + + if (claim) + sdio_release_host(card->func); + + return ret; +} + +/* + * This function wakes up the card. + * + * A host power up command is written to the card configuration + * register to wake up the card. + */ +static int mwifiex_pm_wakeup_card(struct mwifiex_adapter *adapter) +{ + int ret; + + dev_dbg(adapter->dev, "event: wakeup device...\n"); + ret = mwifiex_write_reg(adapter, CONFIGURATION_REG, HOST_POWER_UP); + + return ret; +} + +/* + * This function is called after the card has woken up. + * + * The card configuration register is reset. + */ +static int mwifiex_pm_wakeup_card_complete(struct mwifiex_adapter *adapter) +{ + int ret; + + dev_dbg(adapter->dev, "cmd: wakeup device completed\n"); + ret = mwifiex_write_reg(adapter, CONFIGURATION_REG, 0); + + return ret; +} + +/* + * This function initializes the IO ports. + * + * The following operations are performed - + * - Read the IO ports (0, 1 and 2) + * - Set host interrupt Reset-To-Read to clear + * - Set auto re-enable interrupt + */ +static int mwifiex_init_sdio_ioport(struct mwifiex_adapter *adapter) +{ + u32 reg; + + adapter->ioport = 0; + + /* Read the IO port */ + if (!mwifiex_read_reg(adapter, IO_PORT_0_REG, ®)) + adapter->ioport |= (reg & 0xff); + else + return -1; + + if (!mwifiex_read_reg(adapter, IO_PORT_1_REG, ®)) + adapter->ioport |= ((reg & 0xff) << 8); + else + return -1; + + if (!mwifiex_read_reg(adapter, IO_PORT_2_REG, ®)) + adapter->ioport |= ((reg & 0xff) << 16); + else + return -1; + + pr_debug("info: SDIO FUNC1 IO port: %#x\n", adapter->ioport); + + /* Set Host interrupt reset to read to clear */ + if (!mwifiex_read_reg(adapter, HOST_INT_RSR_REG, ®)) + mwifiex_write_reg(adapter, HOST_INT_RSR_REG, + reg | SDIO_INT_MASK); + else + return -1; + + /* Dnld/Upld ready set to auto reset */ + if (!mwifiex_read_reg(adapter, CARD_MISC_CFG_REG, ®)) + mwifiex_write_reg(adapter, CARD_MISC_CFG_REG, + reg | AUTO_RE_ENABLE_INT); + else + return -1; + + return 0; +} + +/* + * This function sends data to the card. + */ +static int mwifiex_write_data_to_card(struct mwifiex_adapter *adapter, + u8 *payload, u32 pkt_len, u32 port) +{ + u32 i = 0; + int ret = 0; + + do { + ret = mwifiex_write_data_sync(adapter, payload, pkt_len, + port, 0); + if (ret) { + i++; + dev_err(adapter->dev, "host_to_card, write iomem" + " (%d) failed: %d\n", i, ret); + if (mwifiex_write_reg(adapter, + CONFIGURATION_REG, 0x04)) + dev_err(adapter->dev, "write CFG reg failed\n"); + + ret = -1; + if (i > MAX_WRITE_IOMEM_RETRY) + return ret; + } + } while (ret == -1); + + return ret; +} + +/* + * This function gets the read port. + * + * If control port bit is set in MP read bitmap, the control port + * is returned, otherwise the current read port is returned and + * the value is increased (provided it does not reach the maximum + * limit, in which case it is reset to 1) + */ +static int mwifiex_get_rd_port(struct mwifiex_adapter *adapter, u8 *port) +{ + struct sdio_mmc_card *card = adapter->card; + u16 rd_bitmap = card->mp_rd_bitmap; + + dev_dbg(adapter->dev, "data: mp_rd_bitmap=0x%04x\n", rd_bitmap); + + if (!(rd_bitmap & (CTRL_PORT_MASK | DATA_PORT_MASK))) + return -1; + + if (card->mp_rd_bitmap & CTRL_PORT_MASK) { + card->mp_rd_bitmap &= (u16) (~CTRL_PORT_MASK); + *port = CTRL_PORT; + dev_dbg(adapter->dev, "data: port=%d mp_rd_bitmap=0x%04x\n", + *port, card->mp_rd_bitmap); + } else { + if (card->mp_rd_bitmap & (1 << card->curr_rd_port)) { + card->mp_rd_bitmap &= + (u16) (~(1 << card->curr_rd_port)); + *port = card->curr_rd_port; + + if (++card->curr_rd_port == MAX_PORT) + card->curr_rd_port = 1; + } else { + return -1; + } + + dev_dbg(adapter->dev, + "data: port=%d mp_rd_bitmap=0x%04x -> 0x%04x\n", + *port, rd_bitmap, card->mp_rd_bitmap); + } + return 0; +} + +/* + * This function gets the write port for data. + * + * The current write port is returned if available and the value is + * increased (provided it does not reach the maximum limit, in which + * case it is reset to 1) + */ +static int mwifiex_get_wr_port_data(struct mwifiex_adapter *adapter, u8 *port) +{ + struct sdio_mmc_card *card = adapter->card; + u16 wr_bitmap = card->mp_wr_bitmap; + + dev_dbg(adapter->dev, "data: mp_wr_bitmap=0x%04x\n", wr_bitmap); + + if (!(wr_bitmap & card->mp_data_port_mask)) + return -1; + + if (card->mp_wr_bitmap & (1 << card->curr_wr_port)) { + card->mp_wr_bitmap &= (u16) (~(1 << card->curr_wr_port)); + *port = card->curr_wr_port; + if (++card->curr_wr_port == card->mp_end_port) + card->curr_wr_port = 1; + } else { + adapter->data_sent = true; + return -EBUSY; + } + + if (*port == CTRL_PORT) { + dev_err(adapter->dev, "invalid data port=%d cur port=%d" + " mp_wr_bitmap=0x%04x -> 0x%04x\n", + *port, card->curr_wr_port, wr_bitmap, + card->mp_wr_bitmap); + return -1; + } + + dev_dbg(adapter->dev, "data: port=%d mp_wr_bitmap=0x%04x -> 0x%04x\n", + *port, wr_bitmap, card->mp_wr_bitmap); + + return 0; +} + +/* + * This function polls the card status. + */ +static int +mwifiex_sdio_poll_card_status(struct mwifiex_adapter *adapter, u8 bits) +{ + u32 tries; + u32 cs = 0; + + for (tries = 0; tries < MAX_POLL_TRIES; tries++) { + if (mwifiex_read_reg(adapter, CARD_STATUS_REG, &cs)) + break; + else if ((cs & bits) == bits) + return 0; + + udelay(10); + } + + dev_err(adapter->dev, "poll card status failed, tries = %d\n", + tries); + return -1; +} + +/* + * This function reads the firmware status. + */ +static int +mwifiex_sdio_read_fw_status(struct mwifiex_adapter *adapter, u16 *dat) +{ + u32 fws0 = 0, fws1 = 0; + + if (mwifiex_read_reg(adapter, CARD_FW_STATUS0_REG, &fws0)) + return -1; + + if (mwifiex_read_reg(adapter, CARD_FW_STATUS1_REG, &fws1)) + return -1; + + *dat = (u16) ((fws1 << 8) | fws0); + + return 0; +} + +/* + * This function disables the host interrupt. + * + * The host interrupt mask is read, the disable bit is reset and + * written back to the card host interrupt mask register. + */ +static int mwifiex_sdio_disable_host_int(struct mwifiex_adapter *adapter) +{ + u32 host_int_mask = 0; + + /* Read back the host_int_mask register */ + if (mwifiex_read_reg(adapter, HOST_INT_MASK_REG, &host_int_mask)) + return -1; + + /* Update with the mask and write back to the register */ + host_int_mask &= ~HOST_INT_DISABLE; + + if (mwifiex_write_reg(adapter, HOST_INT_MASK_REG, host_int_mask)) { + dev_err(adapter->dev, "disable host interrupt failed\n"); + return -1; + } + + return 0; +} + +/* + * This function enables the host interrupt. + * + * The host interrupt enable mask is written to the card + * host interrupt mask register. + */ +static int mwifiex_sdio_enable_host_int(struct mwifiex_adapter *adapter) +{ + /* Simply write the mask to the register */ + if (mwifiex_write_reg(adapter, HOST_INT_MASK_REG, HOST_INT_ENABLE)) { + dev_err(adapter->dev, "enable host interrupt failed\n"); + return -1; + } + return 0; +} + +/* + * This function sends a data buffer to the card. + */ +static int mwifiex_sdio_card_to_host(struct mwifiex_adapter *adapter, + u32 *type, u8 *buffer, + u32 npayload, u32 ioport) +{ + int ret = 0; + u32 nb; + + if (!buffer) { + dev_err(adapter->dev, "%s: buffer is NULL\n", __func__); + return -1; + } + + ret = mwifiex_read_data_sync(adapter, buffer, npayload, ioport, 0, 1); + + if (ret) { + dev_err(adapter->dev, "%s: read iomem failed: %d\n", __func__, + ret); + return -1; + } + + nb = le16_to_cpu(*(__le16 *) (buffer)); + if (nb > npayload) { + dev_err(adapter->dev, "%s: invalid packet, nb=%d, npayload=%d\n", + __func__, nb, npayload); + return -1; + } + + *type = le16_to_cpu(*(__le16 *) (buffer + 2)); + + return ret; +} + +/* + * This function downloads the firmware to the card. + * + * Firmware is downloaded to the card in blocks. Every block download + * is tested for CRC errors, and retried a number of times before + * returning failure. + */ +static int mwifiex_prog_fw_w_helper(struct mwifiex_adapter *adapter, + struct mwifiex_fw_image *fw) +{ + int ret = 0; + u8 *firmware = fw->fw_buf; + u32 firmware_len = fw->fw_len; + u32 offset = 0; + u32 base0, base1; + u8 *fwbuf; + u16 len = 0; + u32 txlen = 0, tx_blocks = 0, tries = 0; + u32 i = 0; + + if (!firmware_len) { + dev_err(adapter->dev, "firmware image not found!" + " Terminating download\n"); + return -1; + } + + dev_dbg(adapter->dev, "info: downloading FW image (%d bytes)\n", + firmware_len); + + /* Assume that the allocated buffer is 8-byte aligned */ + fwbuf = kzalloc(MWIFIEX_UPLD_SIZE, GFP_KERNEL); + if (!fwbuf) { + dev_err(adapter->dev, "unable to alloc buffer for firmware." + " Terminating download\n"); + return -1; + } + + /* Perform firmware data transfer */ + do { + /* The host polls for the DN_LD_CARD_RDY and CARD_IO_READY + bits */ + ret = mwifiex_sdio_poll_card_status(adapter, CARD_IO_READY | + DN_LD_CARD_RDY); + if (ret) { + dev_err(adapter->dev, "FW download with helper:" + " poll status timeout @ %d\n", offset); + goto done; + } + + /* More data? */ + if (offset >= firmware_len) + break; + + for (tries = 0; tries < MAX_POLL_TRIES; tries++) { + ret = mwifiex_read_reg(adapter, HOST_F1_RD_BASE_0, + &base0); + if (ret) { + dev_err(adapter->dev, "dev BASE0 register read" + " failed: base0=0x%04X(%d). Terminating " + "download\n", base0, base0); + goto done; + } + ret = mwifiex_read_reg(adapter, HOST_F1_RD_BASE_1, + &base1); + if (ret) { + dev_err(adapter->dev, "dev BASE1 register read" + " failed: base1=0x%04X(%d). Terminating " + "download\n", base1, base1); + goto done; + } + len = (u16) (((base1 & 0xff) << 8) | (base0 & 0xff)); + + if (len) + break; + + udelay(10); + } + + if (!len) { + break; + } else if (len > MWIFIEX_UPLD_SIZE) { + dev_err(adapter->dev, "FW download failed @ %d," + " invalid length %d\n", offset, len); + ret = -1; + goto done; + } + + txlen = len; + + if (len & BIT(0)) { + i++; + if (i > MAX_WRITE_IOMEM_RETRY) { + dev_err(adapter->dev, "FW download failed @" + " %d, over max retry count\n", offset); + ret = -1; + goto done; + } + dev_err(adapter->dev, "CRC indicated by the helper:" + " len = 0x%04X, txlen = %d\n", len, txlen); + len &= ~BIT(0); + /* Setting this to 0 to resend from same offset */ + txlen = 0; + } else { + i = 0; + + /* Set blocksize to transfer - checking for last + block */ + if (firmware_len - offset < txlen) + txlen = firmware_len - offset; + + tx_blocks = (txlen + MWIFIEX_SDIO_BLOCK_SIZE - + 1) / MWIFIEX_SDIO_BLOCK_SIZE; + + /* Copy payload to buffer */ + memmove(fwbuf, &firmware[offset], txlen); + } + + ret = mwifiex_write_data_sync(adapter, fwbuf, tx_blocks * + MWIFIEX_SDIO_BLOCK_SIZE, + adapter->ioport, 0); + if (ret) { + dev_err(adapter->dev, "FW download, write iomem (%d)" + " failed @ %d\n", i, offset); + if (mwifiex_write_reg(adapter, CONFIGURATION_REG, 0x04)) + dev_err(adapter->dev, "write CFG reg failed\n"); + + ret = -1; + goto done; + } + + offset += txlen; + } while (true); + + dev_dbg(adapter->dev, "info: FW download over, size %d bytes\n", + offset); + + ret = 0; +done: + kfree(fwbuf); + return ret; +} + +/* + * This function checks the firmware status in card. + * + * The winner interface is also determined by this function. + */ +static int mwifiex_check_fw_status(struct mwifiex_adapter *adapter, + u32 poll_num, int *winner) +{ + int ret = 0; + u16 firmware_stat; + u32 tries; + u32 winner_status; + + /* Wait for firmware initialization event */ + for (tries = 0; tries < poll_num; tries++) { + ret = mwifiex_sdio_read_fw_status(adapter, &firmware_stat); + if (ret) + continue; + if (firmware_stat == FIRMWARE_READY) { + ret = 0; + break; + } else { + mdelay(100); + ret = -1; + } + } + + if (winner && ret) { + if (mwifiex_read_reg + (adapter, CARD_FW_STATUS0_REG, &winner_status)) + winner_status = 0; + + if (winner_status) + *winner = 0; + else + *winner = 1; + } + return ret; +} + +/* + * This function reads the interrupt status from card. + */ +static void mwifiex_interrupt_status(struct mwifiex_adapter *adapter) +{ + struct sdio_mmc_card *card = adapter->card; + u32 sdio_ireg = 0; + unsigned long flags; + + if (mwifiex_read_data_sync(adapter, card->mp_regs, MAX_MP_REGS, + REG_PORT | MWIFIEX_SDIO_BYTE_MODE_MASK, 0, + 0)) { + dev_err(adapter->dev, "read mp_regs failed\n"); + return; + } + + sdio_ireg = card->mp_regs[HOST_INTSTATUS_REG]; + if (sdio_ireg) { + /* + * DN_LD_HOST_INT_STATUS and/or UP_LD_HOST_INT_STATUS + * Clear the interrupt status register + */ + dev_dbg(adapter->dev, "int: sdio_ireg = %#x\n", sdio_ireg); + spin_lock_irqsave(&adapter->int_lock, flags); + adapter->int_status |= sdio_ireg; + spin_unlock_irqrestore(&adapter->int_lock, flags); + } + + return; +} + +/* + * SDIO interrupt handler. + * + * This function reads the interrupt status from firmware and assigns + * the main process in workqueue which will handle the interrupt. + */ +static void +mwifiex_sdio_interrupt(struct sdio_func *func) +{ + struct mwifiex_adapter *adapter; + struct sdio_mmc_card *card; + + card = sdio_get_drvdata(func); + if (!card || !card->adapter) { + pr_debug("int: func=%p card=%p adapter=%p\n", + func, card, card ? card->adapter : NULL); + return; + } + adapter = card->adapter; + + if (adapter->surprise_removed) + return; + + if (!adapter->pps_uapsd_mode && adapter->ps_state == PS_STATE_SLEEP) + adapter->ps_state = PS_STATE_AWAKE; + + mwifiex_interrupt_status(adapter); + queue_work(adapter->workqueue, &adapter->main_work); + + return; +} + +/* + * This function decodes a received packet. + * + * Based on the type, the packet is treated as either a data, or + * a command response, or an event, and the correct handler + * function is invoked. + */ +static int mwifiex_decode_rx_packet(struct mwifiex_adapter *adapter, + struct sk_buff *skb, u32 upld_typ) +{ + u8 *cmd_buf; + + skb_pull(skb, INTF_HEADER_LEN); + + switch (upld_typ) { + case MWIFIEX_TYPE_DATA: + dev_dbg(adapter->dev, "info: --- Rx: Data packet ---\n"); + mwifiex_handle_rx_packet(adapter, skb); + break; + + case MWIFIEX_TYPE_CMD: + dev_dbg(adapter->dev, "info: --- Rx: Cmd Response ---\n"); + /* take care of curr_cmd = NULL case */ + if (!adapter->curr_cmd) { + cmd_buf = adapter->upld_buf; + + if (adapter->ps_state == PS_STATE_SLEEP_CFM) + mwifiex_process_sleep_confirm_resp(adapter, + skb->data, skb->len); + + memcpy(cmd_buf, skb->data, min_t(u32, + MWIFIEX_SIZE_OF_CMD_BUFFER, skb->len)); + + dev_kfree_skb_any(skb); + } else { + adapter->cmd_resp_received = true; + adapter->curr_cmd->resp_skb = skb; + } + break; + + case MWIFIEX_TYPE_EVENT: + dev_dbg(adapter->dev, "info: --- Rx: Event ---\n"); + adapter->event_cause = *(u32 *) skb->data; + + skb_pull(skb, MWIFIEX_EVENT_HEADER_LEN); + + if ((skb->len > 0) && (skb->len < MAX_EVENT_SIZE)) + memcpy(adapter->event_body, skb->data, skb->len); + + /* event cause has been saved to adapter->event_cause */ + adapter->event_received = true; + adapter->event_skb = skb; + + break; + + default: + dev_err(adapter->dev, "unknown upload type %#x\n", upld_typ); + dev_kfree_skb_any(skb); + break; + } + + return 0; +} + +/* + * This function transfers received packets from card to driver, performing + * aggregation if required. + * + * For data received on control port, or if aggregation is disabled, the + * received buffers are uploaded as separate packets. However, if aggregation + * is enabled and required, the buffers are copied onto an aggregation buffer, + * provided there is space left, processed and finally uploaded. + */ +static int mwifiex_sdio_card_to_host_mp_aggr(struct mwifiex_adapter *adapter, + struct sk_buff *skb, u8 port) +{ + struct sdio_mmc_card *card = adapter->card; + s32 f_do_rx_aggr = 0; + s32 f_do_rx_cur = 0; + s32 f_aggr_cur = 0; + struct sk_buff *skb_deaggr; + u32 pind = 0; + u32 pkt_len, pkt_type = 0; + u8 *curr_ptr; + u32 rx_len = skb->len; + + if (port == CTRL_PORT) { + /* Read the command Resp without aggr */ + dev_dbg(adapter->dev, "info: %s: no aggregation for cmd " + "response\n", __func__); + + f_do_rx_cur = 1; + goto rx_curr_single; + } + + if (!card->mpa_rx.enabled) { + dev_dbg(adapter->dev, "info: %s: rx aggregation disabled\n", + __func__); + + f_do_rx_cur = 1; + goto rx_curr_single; + } + + if (card->mp_rd_bitmap & (~((u16) CTRL_PORT_MASK))) { + /* Some more data RX pending */ + dev_dbg(adapter->dev, "info: %s: not last packet\n", __func__); + + if (MP_RX_AGGR_IN_PROGRESS(card)) { + if (MP_RX_AGGR_BUF_HAS_ROOM(card, skb->len)) { + f_aggr_cur = 1; + } else { + /* No room in Aggr buf, do rx aggr now */ + f_do_rx_aggr = 1; + f_do_rx_cur = 1; + } + } else { + /* Rx aggr not in progress */ + f_aggr_cur = 1; + } + + } else { + /* No more data RX pending */ + dev_dbg(adapter->dev, "info: %s: last packet\n", __func__); + + if (MP_RX_AGGR_IN_PROGRESS(card)) { + f_do_rx_aggr = 1; + if (MP_RX_AGGR_BUF_HAS_ROOM(card, skb->len)) + f_aggr_cur = 1; + else + /* No room in Aggr buf, do rx aggr now */ + f_do_rx_cur = 1; + } else { + f_do_rx_cur = 1; + } + } + + if (f_aggr_cur) { + dev_dbg(adapter->dev, "info: current packet aggregation\n"); + /* Curr pkt can be aggregated */ + MP_RX_AGGR_SETUP(card, skb, port); + + if (MP_RX_AGGR_PKT_LIMIT_REACHED(card) || + MP_RX_AGGR_PORT_LIMIT_REACHED(card)) { + dev_dbg(adapter->dev, "info: %s: aggregated packet " + "limit reached\n", __func__); + /* No more pkts allowed in Aggr buf, rx it */ + f_do_rx_aggr = 1; + } + } + + if (f_do_rx_aggr) { + /* do aggr RX now */ + dev_dbg(adapter->dev, "info: do_rx_aggr: num of packets: %d\n", + card->mpa_rx.pkt_cnt); + + if (mwifiex_read_data_sync(adapter, card->mpa_rx.buf, + card->mpa_rx.buf_len, + (adapter->ioport | 0x1000 | + (card->mpa_rx.ports << 4)) + + card->mpa_rx.start_port, 0, 1)) + return -1; + + curr_ptr = card->mpa_rx.buf; + + for (pind = 0; pind < card->mpa_rx.pkt_cnt; pind++) { + + /* get curr PKT len & type */ + pkt_len = *(u16 *) &curr_ptr[0]; + pkt_type = *(u16 *) &curr_ptr[2]; + + /* copy pkt to deaggr buf */ + skb_deaggr = card->mpa_rx.skb_arr[pind]; + + if ((pkt_type == MWIFIEX_TYPE_DATA) && (pkt_len <= + card->mpa_rx.len_arr[pind])) { + + memcpy(skb_deaggr->data, curr_ptr, pkt_len); + + skb_trim(skb_deaggr, pkt_len); + + /* Process de-aggr packet */ + mwifiex_decode_rx_packet(adapter, skb_deaggr, + pkt_type); + } else { + dev_err(adapter->dev, "wrong aggr pkt:" + " type=%d len=%d max_len=%d\n", + pkt_type, pkt_len, + card->mpa_rx.len_arr[pind]); + dev_kfree_skb_any(skb_deaggr); + } + curr_ptr += card->mpa_rx.len_arr[pind]; + } + MP_RX_AGGR_BUF_RESET(card); + } + +rx_curr_single: + if (f_do_rx_cur) { + dev_dbg(adapter->dev, "info: RX: port: %d, rx_len: %d\n", + port, rx_len); + + if (mwifiex_sdio_card_to_host(adapter, &pkt_type, + skb->data, skb->len, + adapter->ioport + port)) + return -1; + + mwifiex_decode_rx_packet(adapter, skb, pkt_type); + } + + return 0; +} + +/* + * This function checks the current interrupt status. + * + * The following interrupts are checked and handled by this function - + * - Data sent + * - Command sent + * - Packets received + * + * Since the firmware does not generate download ready interrupt if the + * port updated is command port only, command sent interrupt checking + * should be done manually, and for every SDIO interrupt. + * + * In case of Rx packets received, the packets are uploaded from card to + * host and processed accordingly. + */ +static int mwifiex_process_int_status(struct mwifiex_adapter *adapter) +{ + struct sdio_mmc_card *card = adapter->card; + int ret = 0; + u8 sdio_ireg; + struct sk_buff *skb = NULL; + u8 port = CTRL_PORT; + u32 len_reg_l, len_reg_u; + u32 rx_blocks; + u16 rx_len; + unsigned long flags; + + spin_lock_irqsave(&adapter->int_lock, flags); + sdio_ireg = adapter->int_status; + adapter->int_status = 0; + spin_unlock_irqrestore(&adapter->int_lock, flags); + + if (!sdio_ireg) + return ret; + + if (sdio_ireg & DN_LD_HOST_INT_STATUS) { + card->mp_wr_bitmap = ((u16) card->mp_regs[WR_BITMAP_U]) << 8; + card->mp_wr_bitmap |= (u16) card->mp_regs[WR_BITMAP_L]; + dev_dbg(adapter->dev, "int: DNLD: wr_bitmap=0x%04x\n", + card->mp_wr_bitmap); + if (adapter->data_sent && + (card->mp_wr_bitmap & card->mp_data_port_mask)) { + dev_dbg(adapter->dev, + "info: <--- Tx DONE Interrupt --->\n"); + adapter->data_sent = false; + } + } + + /* As firmware will not generate download ready interrupt if the port + updated is command port only, cmd_sent should be done for any SDIO + interrupt. */ + if (adapter->cmd_sent) { + /* Check if firmware has attach buffer at command port and + update just that in wr_bit_map. */ + card->mp_wr_bitmap |= + (u16) card->mp_regs[WR_BITMAP_L] & CTRL_PORT_MASK; + if (card->mp_wr_bitmap & CTRL_PORT_MASK) + adapter->cmd_sent = false; + } + + dev_dbg(adapter->dev, "info: cmd_sent=%d data_sent=%d\n", + adapter->cmd_sent, adapter->data_sent); + if (sdio_ireg & UP_LD_HOST_INT_STATUS) { + card->mp_rd_bitmap = ((u16) card->mp_regs[RD_BITMAP_U]) << 8; + card->mp_rd_bitmap |= (u16) card->mp_regs[RD_BITMAP_L]; + dev_dbg(adapter->dev, "int: UPLD: rd_bitmap=0x%04x\n", + card->mp_rd_bitmap); + + while (true) { + ret = mwifiex_get_rd_port(adapter, &port); + if (ret) { + dev_dbg(adapter->dev, + "info: no more rd_port available\n"); + break; + } + len_reg_l = RD_LEN_P0_L + (port << 1); + len_reg_u = RD_LEN_P0_U + (port << 1); + rx_len = ((u16) card->mp_regs[len_reg_u]) << 8; + rx_len |= (u16) card->mp_regs[len_reg_l]; + dev_dbg(adapter->dev, "info: RX: port=%d rx_len=%u\n", + port, rx_len); + rx_blocks = + (rx_len + MWIFIEX_SDIO_BLOCK_SIZE - + 1) / MWIFIEX_SDIO_BLOCK_SIZE; + if (rx_len <= INTF_HEADER_LEN + || (rx_blocks * MWIFIEX_SDIO_BLOCK_SIZE) > + MWIFIEX_RX_DATA_BUF_SIZE) { + dev_err(adapter->dev, "invalid rx_len=%d\n", + rx_len); + return -1; + } + rx_len = (u16) (rx_blocks * MWIFIEX_SDIO_BLOCK_SIZE); + + skb = dev_alloc_skb(rx_len); + + if (!skb) { + dev_err(adapter->dev, "%s: failed to alloc skb", + __func__); + return -1; + } + + skb_put(skb, rx_len); + + dev_dbg(adapter->dev, "info: rx_len = %d skb->len = %d\n", + rx_len, skb->len); + + if (mwifiex_sdio_card_to_host_mp_aggr(adapter, skb, + port)) { + u32 cr = 0; + + dev_err(adapter->dev, "card_to_host_mpa failed:" + " int status=%#x\n", sdio_ireg); + if (mwifiex_read_reg(adapter, + CONFIGURATION_REG, &cr)) + dev_err(adapter->dev, + "read CFG reg failed\n"); + + dev_dbg(adapter->dev, + "info: CFG reg val = %d\n", cr); + if (mwifiex_write_reg(adapter, + CONFIGURATION_REG, + (cr | 0x04))) + dev_err(adapter->dev, + "write CFG reg failed\n"); + + dev_dbg(adapter->dev, "info: write success\n"); + if (mwifiex_read_reg(adapter, + CONFIGURATION_REG, &cr)) + dev_err(adapter->dev, + "read CFG reg failed\n"); + + dev_dbg(adapter->dev, + "info: CFG reg val =%x\n", cr); + dev_kfree_skb_any(skb); + return -1; + } + } + } + + return 0; +} + +/* + * This function aggregates transmission buffers in driver and downloads + * the aggregated packet to card. + * + * The individual packets are aggregated by copying into an aggregation + * buffer and then downloaded to the card. Previous unsent packets in the + * aggregation buffer are pre-copied first before new packets are added. + * Aggregation is done till there is space left in the aggregation buffer, + * or till new packets are available. + * + * The function will only download the packet to the card when aggregation + * stops, otherwise it will just aggregate the packet in aggregation buffer + * and return. + */ +static int mwifiex_host_to_card_mp_aggr(struct mwifiex_adapter *adapter, + u8 *payload, u32 pkt_len, u8 port, + u32 next_pkt_len) +{ + struct sdio_mmc_card *card = adapter->card; + int ret = 0; + s32 f_send_aggr_buf = 0; + s32 f_send_cur_buf = 0; + s32 f_precopy_cur_buf = 0; + s32 f_postcopy_cur_buf = 0; + + if ((!card->mpa_tx.enabled) || (port == CTRL_PORT)) { + dev_dbg(adapter->dev, "info: %s: tx aggregation disabled\n", + __func__); + + f_send_cur_buf = 1; + goto tx_curr_single; + } + + if (next_pkt_len) { + /* More pkt in TX queue */ + dev_dbg(adapter->dev, "info: %s: more packets in queue.\n", + __func__); + + if (MP_TX_AGGR_IN_PROGRESS(card)) { + if (!MP_TX_AGGR_PORT_LIMIT_REACHED(card) && + MP_TX_AGGR_BUF_HAS_ROOM(card, pkt_len)) { + f_precopy_cur_buf = 1; + + if (!(card->mp_wr_bitmap & + (1 << card->curr_wr_port)) + || !MP_TX_AGGR_BUF_HAS_ROOM( + card, next_pkt_len)) + f_send_aggr_buf = 1; + } else { + /* No room in Aggr buf, send it */ + f_send_aggr_buf = 1; + + if (MP_TX_AGGR_PORT_LIMIT_REACHED(card) || + !(card->mp_wr_bitmap & + (1 << card->curr_wr_port))) + f_send_cur_buf = 1; + else + f_postcopy_cur_buf = 1; + } + } else { + if (MP_TX_AGGR_BUF_HAS_ROOM(card, pkt_len) + && (card->mp_wr_bitmap & (1 << card->curr_wr_port))) + f_precopy_cur_buf = 1; + else + f_send_cur_buf = 1; + } + } else { + /* Last pkt in TX queue */ + dev_dbg(adapter->dev, "info: %s: Last packet in Tx Queue.\n", + __func__); + + if (MP_TX_AGGR_IN_PROGRESS(card)) { + /* some packs in Aggr buf already */ + f_send_aggr_buf = 1; + + if (MP_TX_AGGR_BUF_HAS_ROOM(card, pkt_len)) + f_precopy_cur_buf = 1; + else + /* No room in Aggr buf, send it */ + f_send_cur_buf = 1; + } else { + f_send_cur_buf = 1; + } + } + + if (f_precopy_cur_buf) { + dev_dbg(adapter->dev, "data: %s: precopy current buffer\n", + __func__); + MP_TX_AGGR_BUF_PUT(card, payload, pkt_len, port); + + if (MP_TX_AGGR_PKT_LIMIT_REACHED(card) || + MP_TX_AGGR_PORT_LIMIT_REACHED(card)) + /* No more pkts allowed in Aggr buf, send it */ + f_send_aggr_buf = 1; + } + + if (f_send_aggr_buf) { + dev_dbg(adapter->dev, "data: %s: send aggr buffer: %d %d\n", + __func__, + card->mpa_tx.start_port, card->mpa_tx.ports); + ret = mwifiex_write_data_to_card(adapter, card->mpa_tx.buf, + card->mpa_tx.buf_len, + (adapter->ioport | 0x1000 | + (card->mpa_tx.ports << 4)) + + card->mpa_tx.start_port); + + MP_TX_AGGR_BUF_RESET(card); + } + +tx_curr_single: + if (f_send_cur_buf) { + dev_dbg(adapter->dev, "data: %s: send current buffer %d\n", + __func__, port); + ret = mwifiex_write_data_to_card(adapter, payload, pkt_len, + adapter->ioport + port); + } + + if (f_postcopy_cur_buf) { + dev_dbg(adapter->dev, "data: %s: postcopy current buffer\n", + __func__); + MP_TX_AGGR_BUF_PUT(card, payload, pkt_len, port); + } + + return ret; +} + +/* + * This function downloads data from driver to card. + * + * Both commands and data packets are transferred to the card by this + * function. + * + * This function adds the SDIO specific header to the front of the buffer + * before transferring. The header contains the length of the packet and + * the type. The firmware handles the packets based upon this set type. + */ +static int mwifiex_sdio_host_to_card(struct mwifiex_adapter *adapter, + u8 type, u8 *payload, u32 pkt_len, + struct mwifiex_tx_param *tx_param) +{ + struct sdio_mmc_card *card = adapter->card; + int ret = 0; + u32 buf_block_len; + u32 blk_size; + u8 port = CTRL_PORT; + + /* Allocate buffer and copy payload */ + blk_size = MWIFIEX_SDIO_BLOCK_SIZE; + buf_block_len = (pkt_len + blk_size - 1) / blk_size; + *(u16 *) &payload[0] = (u16) pkt_len; + *(u16 *) &payload[2] = type; + + /* + * This is SDIO specific header + * u16 length, + * u16 type (MWIFIEX_TYPE_DATA = 0, MWIFIEX_TYPE_CMD = 1, + * MWIFIEX_TYPE_EVENT = 3) + */ + if (type == MWIFIEX_TYPE_DATA) { + ret = mwifiex_get_wr_port_data(adapter, &port); + if (ret) { + dev_err(adapter->dev, "%s: no wr_port available\n", + __func__); + return ret; + } + } else { + adapter->cmd_sent = true; + /* Type must be MWIFIEX_TYPE_CMD */ + + if (pkt_len <= INTF_HEADER_LEN || + pkt_len > MWIFIEX_UPLD_SIZE) + dev_err(adapter->dev, "%s: payload=%p, nb=%d\n", + __func__, payload, pkt_len); + } + + /* Transfer data to card */ + pkt_len = buf_block_len * blk_size; + + if (tx_param) + ret = mwifiex_host_to_card_mp_aggr(adapter, payload, pkt_len, + port, tx_param->next_pkt_len); + else + ret = mwifiex_host_to_card_mp_aggr(adapter, payload, pkt_len, + port, 0); + + if (ret) { + if (type == MWIFIEX_TYPE_CMD) + adapter->cmd_sent = false; + if (type == MWIFIEX_TYPE_DATA) + adapter->data_sent = false; + } else { + if (type == MWIFIEX_TYPE_DATA) { + if (!(card->mp_wr_bitmap & (1 << card->curr_wr_port))) + adapter->data_sent = true; + else + adapter->data_sent = false; + } + } + + return ret; +} + +/* + * This function allocates the MPA Tx and Rx buffers. + */ +static int mwifiex_alloc_sdio_mpa_buffers(struct mwifiex_adapter *adapter, + u32 mpa_tx_buf_size, u32 mpa_rx_buf_size) +{ + struct sdio_mmc_card *card = adapter->card; + int ret = 0; + + card->mpa_tx.buf = kzalloc(mpa_tx_buf_size, GFP_KERNEL); + if (!card->mpa_tx.buf) { + dev_err(adapter->dev, "could not alloc buffer for MP-A TX\n"); + ret = -1; + goto error; + } + + card->mpa_tx.buf_size = mpa_tx_buf_size; + + card->mpa_rx.buf = kzalloc(mpa_rx_buf_size, GFP_KERNEL); + if (!card->mpa_rx.buf) { + dev_err(adapter->dev, "could not alloc buffer for MP-A RX\n"); + ret = -1; + goto error; + } + + card->mpa_rx.buf_size = mpa_rx_buf_size; + +error: + if (ret) { + kfree(card->mpa_tx.buf); + kfree(card->mpa_rx.buf); + } + + return ret; +} + +/* + * This function unregisters the SDIO device. + * + * The SDIO IRQ is released, the function is disabled and driver + * data is set to null. + */ +static void +mwifiex_unregister_dev(struct mwifiex_adapter *adapter) +{ + struct sdio_mmc_card *card = adapter->card; + + if (adapter->card) { + /* Release the SDIO IRQ */ + sdio_claim_host(card->func); + sdio_release_irq(card->func); + sdio_disable_func(card->func); + sdio_release_host(card->func); + sdio_set_drvdata(card->func, NULL); + } +} + +/* + * This function registers the SDIO device. + * + * SDIO IRQ is claimed, block size is set and driver data is initialized. + */ +static int mwifiex_register_dev(struct mwifiex_adapter *adapter) +{ + int ret = 0; + struct sdio_mmc_card *card = adapter->card; + struct sdio_func *func = card->func; + + /* save adapter pointer in card */ + card->adapter = adapter; + + sdio_claim_host(func); + + /* Request the SDIO IRQ */ + ret = sdio_claim_irq(func, mwifiex_sdio_interrupt); + if (ret) { + pr_err("claim irq failed: ret=%d\n", ret); + goto disable_func; + } + + /* Set block size */ + ret = sdio_set_block_size(card->func, MWIFIEX_SDIO_BLOCK_SIZE); + if (ret) { + pr_err("cannot set SDIO block size\n"); + ret = -1; + goto release_irq; + } + + sdio_release_host(func); + sdio_set_drvdata(func, card); + + adapter->dev = &func->dev; + + return 0; + +release_irq: + sdio_release_irq(func); +disable_func: + sdio_disable_func(func); + sdio_release_host(func); + adapter->card = NULL; + + return -1; +} + +/* + * This function initializes the SDIO driver. + * + * The following initializations steps are followed - + * - Read the Host interrupt status register to acknowledge + * the first interrupt got from bootloader + * - Disable host interrupt mask register + * - Get SDIO port + * - Get revision ID + * - Initialize SDIO variables in card + * - Allocate MP registers + * - Allocate MPA Tx and Rx buffers + */ +static int mwifiex_init_sdio(struct mwifiex_adapter *adapter) +{ + struct sdio_mmc_card *card = adapter->card; + int ret; + u32 sdio_ireg = 0; + + /* + * Read the HOST_INT_STATUS_REG for ACK the first interrupt got + * from the bootloader. If we don't do this we get a interrupt + * as soon as we register the irq. + */ + mwifiex_read_reg(adapter, HOST_INTSTATUS_REG, &sdio_ireg); + + /* Disable host interrupt mask register for SDIO */ + mwifiex_sdio_disable_host_int(adapter); + + /* Get SDIO ioport */ + mwifiex_init_sdio_ioport(adapter); + + /* Get revision ID */ +#define REV_ID_REG 0x5c + mwifiex_read_reg(adapter, REV_ID_REG, &adapter->revision_id); + + /* Initialize SDIO variables in card */ + card->mp_rd_bitmap = 0; + card->mp_wr_bitmap = 0; + card->curr_rd_port = 1; + card->curr_wr_port = 1; + + card->mp_data_port_mask = DATA_PORT_MASK; + + card->mpa_tx.buf_len = 0; + card->mpa_tx.pkt_cnt = 0; + card->mpa_tx.start_port = 0; + + card->mpa_tx.enabled = 0; + card->mpa_tx.pkt_aggr_limit = SDIO_MP_AGGR_DEF_PKT_LIMIT; + + card->mpa_rx.buf_len = 0; + card->mpa_rx.pkt_cnt = 0; + card->mpa_rx.start_port = 0; + + card->mpa_rx.enabled = 0; + card->mpa_rx.pkt_aggr_limit = SDIO_MP_AGGR_DEF_PKT_LIMIT; + + /* Allocate buffers for SDIO MP-A */ + card->mp_regs = kzalloc(MAX_MP_REGS, GFP_KERNEL); + if (!card->mp_regs) { + dev_err(adapter->dev, "failed to alloc mp_regs\n"); + return -1; + } + + ret = mwifiex_alloc_sdio_mpa_buffers(adapter, + SDIO_MP_TX_AGGR_DEF_BUF_SIZE, + SDIO_MP_RX_AGGR_DEF_BUF_SIZE); + if (ret) { + dev_err(adapter->dev, "failed to alloc sdio mp-a buffers\n"); + kfree(card->mp_regs); + return -1; + } + + return ret; +} + +/* + * This function resets the MPA Tx and Rx buffers. + */ +static void mwifiex_cleanup_mpa_buf(struct mwifiex_adapter *adapter) +{ + struct sdio_mmc_card *card = adapter->card; + + MP_TX_AGGR_BUF_RESET(card); + MP_RX_AGGR_BUF_RESET(card); +} + +/* + * This function cleans up the allocated card buffers. + * + * The following are freed by this function - + * - MP registers + * - MPA Tx buffer + * - MPA Rx buffer + */ +static void mwifiex_cleanup_sdio(struct mwifiex_adapter *adapter) +{ + struct sdio_mmc_card *card = adapter->card; + + kfree(card->mp_regs); + kfree(card->mpa_tx.buf); + kfree(card->mpa_rx.buf); +} + +/* + * This function updates the MP end port in card. + */ +static void +mwifiex_update_mp_end_port(struct mwifiex_adapter *adapter, u16 port) +{ + struct sdio_mmc_card *card = adapter->card; + int i; + + card->mp_end_port = port; + + card->mp_data_port_mask = DATA_PORT_MASK; + + for (i = 1; i <= MAX_PORT - card->mp_end_port; i++) + card->mp_data_port_mask &= ~(1 << (MAX_PORT - i)); + + card->curr_wr_port = 1; + + dev_dbg(adapter->dev, "cmd: mp_end_port %d, data port mask 0x%x\n", + port, card->mp_data_port_mask); +} + +static struct mwifiex_if_ops sdio_ops = { + .init_if = mwifiex_init_sdio, + .cleanup_if = mwifiex_cleanup_sdio, + .check_fw_status = mwifiex_check_fw_status, + .prog_fw = mwifiex_prog_fw_w_helper, + .register_dev = mwifiex_register_dev, + .unregister_dev = mwifiex_unregister_dev, + .enable_int = mwifiex_sdio_enable_host_int, + .process_int_status = mwifiex_process_int_status, + .host_to_card = mwifiex_sdio_host_to_card, + .wakeup = mwifiex_pm_wakeup_card, + .wakeup_complete = mwifiex_pm_wakeup_card_complete, + + /* SDIO specific */ + .update_mp_end_port = mwifiex_update_mp_end_port, + .cleanup_mpa_buf = mwifiex_cleanup_mpa_buf, +}; + +/* + * This function initializes the SDIO driver. + * + * This initiates the semaphore and registers the device with + * SDIO bus. + */ +static int +mwifiex_sdio_init_module(void) +{ + int ret; + + sema_init(&add_remove_card_sem, 1); + + ret = sdio_register_driver(&mwifiex_sdio); + + return ret; +} + +/* + * This function cleans up the SDIO driver. + * + * The following major steps are followed for cleanup - + * - Resume the device if its suspended + * - Disconnect the device if connected + * - Shutdown the firmware + * - Unregister the device from SDIO bus. + */ +static void +mwifiex_sdio_cleanup_module(void) +{ + struct mwifiex_adapter *adapter = g_adapter; + int i; + + if (down_interruptible(&add_remove_card_sem)) + goto exit_sem_err; + + if (!adapter || !adapter->priv_num) + goto exit; + + if (adapter->is_suspended) + mwifiex_sdio_resume(adapter->dev); + + for (i = 0; i < adapter->priv_num; i++) + if ((GET_BSS_ROLE(adapter->priv[i]) == MWIFIEX_BSS_ROLE_STA) && + adapter->priv[i]->media_connected) + mwifiex_disconnect(adapter->priv[i], MWIFIEX_CMD_WAIT, + NULL); + + if (!adapter->surprise_removed) + mwifiex_shutdown_fw(mwifiex_get_priv + (adapter, MWIFIEX_BSS_ROLE_ANY), + MWIFIEX_CMD_WAIT); + +exit: + up(&add_remove_card_sem); + +exit_sem_err: + sdio_unregister_driver(&mwifiex_sdio); +} + +module_init(mwifiex_sdio_init_module); +module_exit(mwifiex_sdio_cleanup_module); + +MODULE_AUTHOR("Marvell International Ltd."); +MODULE_DESCRIPTION("Marvell WiFi-Ex SDIO Driver version " SDIO_VERSION); +MODULE_VERSION(SDIO_VERSION); +MODULE_LICENSE("GPL v2"); +MODULE_FIRMWARE("sd8787.bin"); diff --git a/drivers/net/wireless/mwifiex/sdio.h b/drivers/net/wireless/mwifiex/sdio.h new file mode 100644 index 0000000..a0e9bc5 --- /dev/null +++ b/drivers/net/wireless/mwifiex/sdio.h @@ -0,0 +1,305 @@ +/* + * Marvell Wireless LAN device driver: SDIO specific definitions + * + * Copyright (C) 2011, Marvell International Ltd. + * + * This software file (the "File") is distributed by Marvell International + * Ltd. under the terms of the GNU General Public License Version 2, June 1991 + * (the "License"). You may use, redistribute and/or modify this File in + * accordance with the terms and conditions of the License, a copy of which + * is available by writing to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the + * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. + * + * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE + * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE + * ARE EXPRESSLY DISCLAIMED. The License provides additional details about + * this warranty disclaimer. + */ + +#ifndef _MWIFIEX_SDIO_H +#define _MWIFIEX_SDIO_H + + +#include +#include +#include +#include + +#include "main.h" + +#define BLOCK_MODE 1 +#define BYTE_MODE 0 + +#define REG_PORT 0 +#define RD_BITMAP_L 0x04 +#define RD_BITMAP_U 0x05 +#define WR_BITMAP_L 0x06 +#define WR_BITMAP_U 0x07 +#define RD_LEN_P0_L 0x08 +#define RD_LEN_P0_U 0x09 + +#define MWIFIEX_SDIO_IO_PORT_MASK 0xfffff + +#define MWIFIEX_SDIO_BYTE_MODE_MASK 0x80000000 + +#define CTRL_PORT 0 +#define CTRL_PORT_MASK 0x0001 +#define DATA_PORT_MASK 0xfffe + +#define MAX_MP_REGS 64 +#define MAX_PORT 16 + +#define SDIO_MP_AGGR_DEF_PKT_LIMIT 8 + +#define SDIO_MP_TX_AGGR_DEF_BUF_SIZE (4096) /* 4K */ + +/* Multi port RX aggregation buffer size */ +#define SDIO_MP_RX_AGGR_DEF_BUF_SIZE (4096) /* 4K */ + +/* Misc. Config Register : Auto Re-enable interrupts */ +#define AUTO_RE_ENABLE_INT BIT(4) + +/* Host Control Registers */ +/* Host Control Registers : I/O port 0 */ +#define IO_PORT_0_REG 0x78 +/* Host Control Registers : I/O port 1 */ +#define IO_PORT_1_REG 0x79 +/* Host Control Registers : I/O port 2 */ +#define IO_PORT_2_REG 0x7A + +/* Host Control Registers : Configuration */ +#define CONFIGURATION_REG 0x00 +/* Host Control Registers : Host without Command 53 finish host*/ +#define HOST_TO_CARD_EVENT (0x1U << 3) +/* Host Control Registers : Host without Command 53 finish host */ +#define HOST_WO_CMD53_FINISH_HOST (0x1U << 2) +/* Host Control Registers : Host power up */ +#define HOST_POWER_UP (0x1U << 1) +/* Host Control Registers : Host power down */ +#define HOST_POWER_DOWN (0x1U << 0) + +/* Host Control Registers : Host interrupt mask */ +#define HOST_INT_MASK_REG 0x02 +/* Host Control Registers : Upload host interrupt mask */ +#define UP_LD_HOST_INT_MASK (0x1U) +/* Host Control Registers : Download host interrupt mask */ +#define DN_LD_HOST_INT_MASK (0x2U) +/* Enable Host interrupt mask */ +#define HOST_INT_ENABLE (UP_LD_HOST_INT_MASK | DN_LD_HOST_INT_MASK) +/* Disable Host interrupt mask */ +#define HOST_INT_DISABLE 0xff + +/* Host Control Registers : Host interrupt status */ +#define HOST_INTSTATUS_REG 0x03 +/* Host Control Registers : Upload host interrupt status */ +#define UP_LD_HOST_INT_STATUS (0x1U) +/* Host Control Registers : Download host interrupt status */ +#define DN_LD_HOST_INT_STATUS (0x2U) + +/* Host Control Registers : Host interrupt RSR */ +#define HOST_INT_RSR_REG 0x01 +/* Host Control Registers : Upload host interrupt RSR */ +#define UP_LD_HOST_INT_RSR (0x1U) +#define SDIO_INT_MASK 0x3F + +/* Host Control Registers : Host interrupt status */ +#define HOST_INT_STATUS_REG 0x28 +/* Host Control Registers : Upload CRC error */ +#define UP_LD_CRC_ERR (0x1U << 2) +/* Host Control Registers : Upload restart */ +#define UP_LD_RESTART (0x1U << 1) +/* Host Control Registers : Download restart */ +#define DN_LD_RESTART (0x1U << 0) + +/* Card Control Registers : Card status register */ +#define CARD_STATUS_REG 0x30 +/* Card Control Registers : Card I/O ready */ +#define CARD_IO_READY (0x1U << 3) +/* Card Control Registers : CIS card ready */ +#define CIS_CARD_RDY (0x1U << 2) +/* Card Control Registers : Upload card ready */ +#define UP_LD_CARD_RDY (0x1U << 1) +/* Card Control Registers : Download card ready */ +#define DN_LD_CARD_RDY (0x1U << 0) + +/* Card Control Registers : Host interrupt mask register */ +#define HOST_INTERRUPT_MASK_REG 0x34 +/* Card Control Registers : Host power interrupt mask */ +#define HOST_POWER_INT_MASK (0x1U << 3) +/* Card Control Registers : Abort card interrupt mask */ +#define ABORT_CARD_INT_MASK (0x1U << 2) +/* Card Control Registers : Upload card interrupt mask */ +#define UP_LD_CARD_INT_MASK (0x1U << 1) +/* Card Control Registers : Download card interrupt mask */ +#define DN_LD_CARD_INT_MASK (0x1U << 0) + +/* Card Control Registers : Card interrupt status register */ +#define CARD_INTERRUPT_STATUS_REG 0x38 +/* Card Control Registers : Power up interrupt */ +#define POWER_UP_INT (0x1U << 4) +/* Card Control Registers : Power down interrupt */ +#define POWER_DOWN_INT (0x1U << 3) + +/* Card Control Registers : Card interrupt RSR register */ +#define CARD_INTERRUPT_RSR_REG 0x3c +/* Card Control Registers : Power up RSR */ +#define POWER_UP_RSR (0x1U << 4) +/* Card Control Registers : Power down RSR */ +#define POWER_DOWN_RSR (0x1U << 3) + +/* Card Control Registers : Miscellaneous Configuration Register */ +#define CARD_MISC_CFG_REG 0x6C + +/* Host F1 read base 0 */ +#define HOST_F1_RD_BASE_0 0x0040 +/* Host F1 read base 1 */ +#define HOST_F1_RD_BASE_1 0x0041 +/* Host F1 card ready */ +#define HOST_F1_CARD_RDY 0x0020 + +/* Firmware status 0 register */ +#define CARD_FW_STATUS0_REG 0x60 +/* Firmware status 1 register */ +#define CARD_FW_STATUS1_REG 0x61 +/* Rx length register */ +#define CARD_RX_LEN_REG 0x62 +/* Rx unit register */ +#define CARD_RX_UNIT_REG 0x63 + +/* Event header Len*/ +#define MWIFIEX_EVENT_HEADER_LEN 8 + +/* Max retry number of CMD53 write */ +#define MAX_WRITE_IOMEM_RETRY 2 + +/* SDIO Tx aggregation in progress ? */ +#define MP_TX_AGGR_IN_PROGRESS(a) (a->mpa_tx.pkt_cnt > 0) + +/* SDIO Tx aggregation buffer room for next packet ? */ +#define MP_TX_AGGR_BUF_HAS_ROOM(a, len) ((a->mpa_tx.buf_len+len) \ + <= a->mpa_tx.buf_size) + +/* Copy current packet (SDIO Tx aggregation buffer) to SDIO buffer */ +#define MP_TX_AGGR_BUF_PUT(a, payload, pkt_len, port) do { \ + memmove(&a->mpa_tx.buf[a->mpa_tx.buf_len], \ + payload, pkt_len); \ + a->mpa_tx.buf_len += pkt_len; \ + if (!a->mpa_tx.pkt_cnt) \ + a->mpa_tx.start_port = port; \ + if (a->mpa_tx.start_port <= port) \ + a->mpa_tx.ports |= (1<<(a->mpa_tx.pkt_cnt)); \ + else \ + a->mpa_tx.ports |= (1<<(a->mpa_tx.pkt_cnt+1+(MAX_PORT - \ + a->mp_end_port))); \ + a->mpa_tx.pkt_cnt++; \ +} while (0); + +/* SDIO Tx aggregation limit ? */ +#define MP_TX_AGGR_PKT_LIMIT_REACHED(a) \ + (a->mpa_tx.pkt_cnt == a->mpa_tx.pkt_aggr_limit) + +/* SDIO Tx aggregation port limit ? */ +#define MP_TX_AGGR_PORT_LIMIT_REACHED(a) ((a->curr_wr_port < \ + a->mpa_tx.start_port) && (((MAX_PORT - \ + a->mpa_tx.start_port) + a->curr_wr_port) >= \ + SDIO_MP_AGGR_DEF_PKT_LIMIT)) + +/* Reset SDIO Tx aggregation buffer parameters */ +#define MP_TX_AGGR_BUF_RESET(a) do { \ + a->mpa_tx.pkt_cnt = 0; \ + a->mpa_tx.buf_len = 0; \ + a->mpa_tx.ports = 0; \ + a->mpa_tx.start_port = 0; \ +} while (0); + +/* SDIO Rx aggregation limit ? */ +#define MP_RX_AGGR_PKT_LIMIT_REACHED(a) \ + (a->mpa_rx.pkt_cnt == a->mpa_rx.pkt_aggr_limit) + +/* SDIO Tx aggregation port limit ? */ +#define MP_RX_AGGR_PORT_LIMIT_REACHED(a) ((a->curr_rd_port < \ + a->mpa_rx.start_port) && (((MAX_PORT - \ + a->mpa_rx.start_port) + a->curr_rd_port) >= \ + SDIO_MP_AGGR_DEF_PKT_LIMIT)) + +/* SDIO Rx aggregation in progress ? */ +#define MP_RX_AGGR_IN_PROGRESS(a) (a->mpa_rx.pkt_cnt > 0) + +/* SDIO Rx aggregation buffer room for next packet ? */ +#define MP_RX_AGGR_BUF_HAS_ROOM(a, rx_len) \ + ((a->mpa_rx.buf_len+rx_len) <= a->mpa_rx.buf_size) + +/* Prepare to copy current packet from card to SDIO Rx aggregation buffer */ +#define MP_RX_AGGR_SETUP(a, skb, port) do { \ + a->mpa_rx.buf_len += skb->len; \ + if (!a->mpa_rx.pkt_cnt) \ + a->mpa_rx.start_port = port; \ + if (a->mpa_rx.start_port <= port) \ + a->mpa_rx.ports |= (1<<(a->mpa_rx.pkt_cnt)); \ + else \ + a->mpa_rx.ports |= (1<<(a->mpa_rx.pkt_cnt+1)); \ + a->mpa_rx.skb_arr[a->mpa_rx.pkt_cnt] = skb; \ + a->mpa_rx.len_arr[a->mpa_rx.pkt_cnt] = skb->len; \ + a->mpa_rx.pkt_cnt++; \ +} while (0); + +/* Reset SDIO Rx aggregation buffer parameters */ +#define MP_RX_AGGR_BUF_RESET(a) do { \ + a->mpa_rx.pkt_cnt = 0; \ + a->mpa_rx.buf_len = 0; \ + a->mpa_rx.ports = 0; \ + a->mpa_rx.start_port = 0; \ +} while (0); + + +/* data structure for SDIO MPA TX */ +struct mwifiex_sdio_mpa_tx { + /* multiport tx aggregation buffer pointer */ + u8 *buf; + u32 buf_len; + u32 pkt_cnt; + u16 ports; + u16 start_port; + u8 enabled; + u32 buf_size; + u32 pkt_aggr_limit; +}; + +struct mwifiex_sdio_mpa_rx { + u8 *buf; + u32 buf_len; + u32 pkt_cnt; + u16 ports; + u16 start_port; + + struct sk_buff *skb_arr[SDIO_MP_AGGR_DEF_PKT_LIMIT]; + u32 len_arr[SDIO_MP_AGGR_DEF_PKT_LIMIT]; + + u8 enabled; + u32 buf_size; + u32 pkt_aggr_limit; +}; + +int mwifiex_bus_register(void); +void mwifiex_bus_unregister(void); + +struct sdio_mmc_card { + struct sdio_func *func; + struct mwifiex_adapter *adapter; + + u16 mp_rd_bitmap; + u16 mp_wr_bitmap; + + u16 mp_end_port; + u16 mp_data_port_mask; + + u8 curr_rd_port; + u8 curr_wr_port; + + u8 *mp_regs; + + struct mwifiex_sdio_mpa_tx mpa_tx; + struct mwifiex_sdio_mpa_rx mpa_rx; +}; +#endif /* _MWIFIEX_SDIO_H */ diff --git a/drivers/net/wireless/mwifiex/sta_cmd.c b/drivers/net/wireless/mwifiex/sta_cmd.c new file mode 100644 index 0000000..795b1ea --- /dev/null +++ b/drivers/net/wireless/mwifiex/sta_cmd.c @@ -0,0 +1,1226 @@ +/* + * Marvell Wireless LAN device driver: station command handling + * + * Copyright (C) 2011, Marvell International Ltd. + * + * This software file (the "File") is distributed by Marvell International + * Ltd. under the terms of the GNU General Public License Version 2, June 1991 + * (the "License"). You may use, redistribute and/or modify this File in + * accordance with the terms and conditions of the License, a copy of which + * is available by writing to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the + * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. + * + * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE + * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE + * ARE EXPRESSLY DISCLAIMED. The License provides additional details about + * this warranty disclaimer. + */ + +#include "decl.h" +#include "ioctl.h" +#include "util.h" +#include "fw.h" +#include "main.h" +#include "wmm.h" +#include "11n.h" + +/* + * This function prepares command to set/get RSSI information. + * + * Preparation includes - + * - Setting command ID, action and proper size + * - Setting data/beacon average factors + * - Resetting SNR/NF/RSSI values in private structure + * - Ensuring correct endian-ness + */ +static int +mwifiex_cmd_802_11_rssi_info(struct mwifiex_private *priv, + struct host_cmd_ds_command *cmd, u16 cmd_action) +{ + cmd->command = cpu_to_le16(HostCmd_CMD_RSSI_INFO); + cmd->size = cpu_to_le16(sizeof(struct host_cmd_ds_802_11_rssi_info) + + S_DS_GEN); + cmd->params.rssi_info.action = cpu_to_le16(cmd_action); + cmd->params.rssi_info.ndata = cpu_to_le16(priv->data_avg_factor); + cmd->params.rssi_info.nbcn = cpu_to_le16(priv->bcn_avg_factor); + + /* Reset SNR/NF/RSSI values in private structure */ + priv->data_rssi_last = 0; + priv->data_nf_last = 0; + priv->data_rssi_avg = 0; + priv->data_nf_avg = 0; + priv->bcn_rssi_last = 0; + priv->bcn_nf_last = 0; + priv->bcn_rssi_avg = 0; + priv->bcn_nf_avg = 0; + + return 0; +} + +/* + * This function prepares command to set MAC control. + * + * Preparation includes - + * - Setting command ID, action and proper size + * - Ensuring correct endian-ness + */ +static int mwifiex_cmd_mac_control(struct mwifiex_private *priv, + struct host_cmd_ds_command *cmd, + u16 cmd_action, void *data_buf) +{ + struct host_cmd_ds_mac_control *mac_ctrl = &cmd->params.mac_ctrl; + u16 action = *((u16 *) data_buf); + + if (cmd_action != HostCmd_ACT_GEN_SET) { + dev_err(priv->adapter->dev, + "mac_control: only support set cmd\n"); + return -1; + } + + cmd->command = cpu_to_le16(HostCmd_CMD_MAC_CONTROL); + cmd->size = + cpu_to_le16(sizeof(struct host_cmd_ds_mac_control) + S_DS_GEN); + mac_ctrl->action = cpu_to_le16(action); + + return 0; +} + +/* + * This function prepares command to set/get SNMP MIB. + * + * Preparation includes - + * - Setting command ID, action and proper size + * - Setting SNMP MIB OID number and value + * (as required) + * - Ensuring correct endian-ness + * + * The following SNMP MIB OIDs are supported - + * - FRAG_THRESH_I : Fragmentation threshold + * - RTS_THRESH_I : RTS threshold + * - SHORT_RETRY_LIM_I : Short retry limit + * - DOT11D_I : 11d support + */ +static int mwifiex_cmd_802_11_snmp_mib(struct mwifiex_private *priv, + struct host_cmd_ds_command *cmd, + u16 cmd_action, u32 cmd_oid, + void *data_buf) +{ + struct host_cmd_ds_802_11_snmp_mib *snmp_mib = &cmd->params.smib; + u32 ul_temp; + + dev_dbg(priv->adapter->dev, "cmd: SNMP_CMD: cmd_oid = 0x%x\n", cmd_oid); + cmd->command = cpu_to_le16(HostCmd_CMD_802_11_SNMP_MIB); + cmd->size = cpu_to_le16(sizeof(struct host_cmd_ds_802_11_snmp_mib) + - 1 + S_DS_GEN); + + if (cmd_action == HostCmd_ACT_GEN_GET) { + snmp_mib->query_type = cpu_to_le16(HostCmd_ACT_GEN_GET); + snmp_mib->buf_size = cpu_to_le16(MAX_SNMP_BUF_SIZE); + cmd->size = cpu_to_le16(le16_to_cpu(cmd->size) + + MAX_SNMP_BUF_SIZE); + } + + switch (cmd_oid) { + case FRAG_THRESH_I: + snmp_mib->oid = cpu_to_le16((u16) FRAG_THRESH_I); + if (cmd_action == HostCmd_ACT_GEN_SET) { + snmp_mib->query_type = cpu_to_le16(HostCmd_ACT_GEN_SET); + snmp_mib->buf_size = cpu_to_le16(sizeof(u16)); + ul_temp = *((u32 *) data_buf); + *((__le16 *) (snmp_mib->value)) = + cpu_to_le16((u16) ul_temp); + cmd->size = cpu_to_le16(le16_to_cpu(cmd->size) + + sizeof(u16)); + } + break; + case RTS_THRESH_I: + snmp_mib->oid = cpu_to_le16((u16) RTS_THRESH_I); + if (cmd_action == HostCmd_ACT_GEN_SET) { + snmp_mib->query_type = cpu_to_le16(HostCmd_ACT_GEN_SET); + snmp_mib->buf_size = cpu_to_le16(sizeof(u16)); + ul_temp = *((u32 *) data_buf); + *(__le16 *) (snmp_mib->value) = + cpu_to_le16((u16) ul_temp); + cmd->size = cpu_to_le16(le16_to_cpu(cmd->size) + + sizeof(u16)); + } + break; + + case SHORT_RETRY_LIM_I: + snmp_mib->oid = cpu_to_le16((u16) SHORT_RETRY_LIM_I); + if (cmd_action == HostCmd_ACT_GEN_SET) { + snmp_mib->query_type = cpu_to_le16(HostCmd_ACT_GEN_SET); + snmp_mib->buf_size = cpu_to_le16(sizeof(u16)); + ul_temp = (*(u32 *) data_buf); + *((__le16 *) (snmp_mib->value)) = + cpu_to_le16((u16) ul_temp); + cmd->size = cpu_to_le16(le16_to_cpu(cmd->size) + + sizeof(u16)); + } + break; + case DOT11D_I: + snmp_mib->oid = cpu_to_le16((u16) DOT11D_I); + if (cmd_action == HostCmd_ACT_GEN_SET) { + snmp_mib->query_type = cpu_to_le16(HostCmd_ACT_GEN_SET); + snmp_mib->buf_size = cpu_to_le16(sizeof(u16)); + ul_temp = *(u32 *) data_buf; + *((__le16 *) (snmp_mib->value)) = + cpu_to_le16((u16) ul_temp); + cmd->size = cpu_to_le16(le16_to_cpu(cmd->size) + + sizeof(u16)); + } + break; + default: + break; + } + dev_dbg(priv->adapter->dev, + "cmd: SNMP_CMD: Action=0x%x, OID=0x%x, OIDSize=0x%x," + " Value=0x%x\n", + cmd_action, cmd_oid, le16_to_cpu(snmp_mib->buf_size), + le16_to_cpu(*(__le16 *) snmp_mib->value)); + return 0; +} + +/* + * This function prepares command to get log. + * + * Preparation includes - + * - Setting command ID and proper size + * - Ensuring correct endian-ness + */ +static int +mwifiex_cmd_802_11_get_log(struct mwifiex_private *priv, + struct host_cmd_ds_command *cmd) +{ + cmd->command = cpu_to_le16(HostCmd_CMD_802_11_GET_LOG); + cmd->size = cpu_to_le16(sizeof(struct host_cmd_ds_802_11_get_log) + + S_DS_GEN); + return 0; +} + +/* + * This function prepares command to set/get Tx data rate configuration. + * + * Preparation includes - + * - Setting command ID, action and proper size + * - Setting configuration index, rate scope and rate drop pattern + * parameters (as required) + * - Ensuring correct endian-ness + */ +static int mwifiex_cmd_tx_rate_cfg(struct mwifiex_private *priv, + struct host_cmd_ds_command *cmd, + u16 cmd_action, void *data_buf) +{ + struct host_cmd_ds_tx_rate_cfg *rate_cfg = &cmd->params.tx_rate_cfg; + struct mwifiex_rate_scope *rate_scope; + struct mwifiex_rate_drop_pattern *rate_drop; + u16 *pbitmap_rates = (u16 *) data_buf; + + u32 i; + + cmd->command = cpu_to_le16(HostCmd_CMD_TX_RATE_CFG); + + rate_cfg->action = cpu_to_le16(cmd_action); + rate_cfg->cfg_index = 0; + + rate_scope = (struct mwifiex_rate_scope *) ((u8 *) rate_cfg + + sizeof(struct host_cmd_ds_tx_rate_cfg)); + rate_scope->type = cpu_to_le16(TLV_TYPE_RATE_SCOPE); + rate_scope->length = cpu_to_le16(sizeof(struct mwifiex_rate_scope) - + sizeof(struct mwifiex_ie_types_header)); + if (pbitmap_rates != NULL) { + rate_scope->hr_dsss_rate_bitmap = cpu_to_le16(pbitmap_rates[0]); + rate_scope->ofdm_rate_bitmap = cpu_to_le16(pbitmap_rates[1]); + for (i = 0; + i < sizeof(rate_scope->ht_mcs_rate_bitmap) / sizeof(u16); + i++) + rate_scope->ht_mcs_rate_bitmap[i] = + cpu_to_le16(pbitmap_rates[2 + i]); + } else { + rate_scope->hr_dsss_rate_bitmap = + cpu_to_le16(priv->bitmap_rates[0]); + rate_scope->ofdm_rate_bitmap = + cpu_to_le16(priv->bitmap_rates[1]); + for (i = 0; + i < sizeof(rate_scope->ht_mcs_rate_bitmap) / sizeof(u16); + i++) + rate_scope->ht_mcs_rate_bitmap[i] = + cpu_to_le16(priv->bitmap_rates[2 + i]); + } + + rate_drop = (struct mwifiex_rate_drop_pattern *) ((u8 *) rate_scope + + sizeof(struct mwifiex_rate_scope)); + rate_drop->type = cpu_to_le16(TLV_TYPE_RATE_DROP_CONTROL); + rate_drop->length = cpu_to_le16(sizeof(rate_drop->rate_drop_mode)); + rate_drop->rate_drop_mode = 0; + + cmd->size = + cpu_to_le16(S_DS_GEN + sizeof(struct host_cmd_ds_tx_rate_cfg) + + sizeof(struct mwifiex_rate_scope) + + sizeof(struct mwifiex_rate_drop_pattern)); + + return 0; +} + +/* + * This function prepares command to set/get Tx power configuration. + * + * Preparation includes - + * - Setting command ID, action and proper size + * - Setting Tx power mode, power group TLV + * (as required) + * - Ensuring correct endian-ness + */ +static int mwifiex_cmd_tx_power_cfg(struct mwifiex_private *priv, + struct host_cmd_ds_command *cmd, + u16 cmd_action, void *data_buf) +{ + struct mwifiex_types_power_group *pg_tlv = NULL; + struct host_cmd_ds_txpwr_cfg *txp = NULL; + struct host_cmd_ds_txpwr_cfg *cmd_txp_cfg = &cmd->params.txp_cfg; + + cmd->command = cpu_to_le16(HostCmd_CMD_TXPWR_CFG); + cmd->size = + cpu_to_le16(S_DS_GEN + sizeof(struct host_cmd_ds_txpwr_cfg)); + switch (cmd_action) { + case HostCmd_ACT_GEN_SET: + txp = (struct host_cmd_ds_txpwr_cfg *) data_buf; + if (txp->mode) { + pg_tlv = (struct mwifiex_types_power_group + *) ((unsigned long) data_buf + + sizeof(struct host_cmd_ds_txpwr_cfg)); + memmove(cmd_txp_cfg, data_buf, + sizeof(struct host_cmd_ds_txpwr_cfg) + + sizeof(struct mwifiex_types_power_group) + + pg_tlv->length); + + pg_tlv = (struct mwifiex_types_power_group *) ((u8 *) + cmd_txp_cfg + + sizeof(struct host_cmd_ds_txpwr_cfg)); + cmd->size = cpu_to_le16(le16_to_cpu(cmd->size) + + sizeof(struct mwifiex_types_power_group) + + pg_tlv->length); + } else { + memmove(cmd_txp_cfg, data_buf, + sizeof(struct host_cmd_ds_txpwr_cfg)); + } + cmd_txp_cfg->action = cpu_to_le16(cmd_action); + break; + case HostCmd_ACT_GEN_GET: + cmd_txp_cfg->action = cpu_to_le16(cmd_action); + break; + } + + return 0; +} + +/* + * This function prepares command to set Host Sleep configuration. + * + * Preparation includes - + * - Setting command ID and proper size + * - Setting Host Sleep action, conditions, ARP filters + * (as required) + * - Ensuring correct endian-ness + */ +static int mwifiex_cmd_802_11_hs_cfg(struct mwifiex_private *priv, + struct host_cmd_ds_command *cmd, + u16 cmd_action, + struct mwifiex_hs_config_param *data_buf) +{ + struct mwifiex_adapter *adapter = priv->adapter; + struct host_cmd_ds_802_11_hs_cfg_enh *hs_cfg = &cmd->params.opt_hs_cfg; + u16 hs_activate = false; + + if (data_buf == NULL) + /* New Activate command */ + hs_activate = true; + cmd->command = cpu_to_le16(HostCmd_CMD_802_11_HS_CFG_ENH); + + if (!hs_activate && + (data_buf->conditions + != cpu_to_le32(HOST_SLEEP_CFG_CANCEL)) + && ((adapter->arp_filter_size > 0) + && (adapter->arp_filter_size <= ARP_FILTER_MAX_BUF_SIZE))) { + dev_dbg(adapter->dev, + "cmd: Attach %d bytes ArpFilter to HSCfg cmd\n", + adapter->arp_filter_size); + memcpy(((u8 *) hs_cfg) + + sizeof(struct host_cmd_ds_802_11_hs_cfg_enh), + adapter->arp_filter, adapter->arp_filter_size); + cmd->size = cpu_to_le16(adapter->arp_filter_size + + sizeof(struct host_cmd_ds_802_11_hs_cfg_enh) + + S_DS_GEN); + } else { + cmd->size = cpu_to_le16(S_DS_GEN + sizeof(struct + host_cmd_ds_802_11_hs_cfg_enh)); + } + if (hs_activate) { + hs_cfg->action = cpu_to_le16(HS_ACTIVATE); + hs_cfg->params.hs_activate.resp_ctrl = RESP_NEEDED; + } else { + hs_cfg->action = cpu_to_le16(HS_CONFIGURE); + hs_cfg->params.hs_config.conditions = data_buf->conditions; + hs_cfg->params.hs_config.gpio = data_buf->gpio; + hs_cfg->params.hs_config.gap = data_buf->gap; + dev_dbg(adapter->dev, + "cmd: HS_CFG_CMD: condition:0x%x gpio:0x%x gap:0x%x\n", + hs_cfg->params.hs_config.conditions, + hs_cfg->params.hs_config.gpio, + hs_cfg->params.hs_config.gap); + } + + return 0; +} + +/* + * This function prepares command to set/get MAC address. + * + * Preparation includes - + * - Setting command ID, action and proper size + * - Setting MAC address (for SET only) + * - Ensuring correct endian-ness + */ +static int mwifiex_cmd_802_11_mac_address(struct mwifiex_private *priv, + struct host_cmd_ds_command *cmd, + u16 cmd_action) +{ + cmd->command = cpu_to_le16(HostCmd_CMD_802_11_MAC_ADDRESS); + cmd->size = cpu_to_le16(sizeof(struct host_cmd_ds_802_11_mac_address) + + S_DS_GEN); + cmd->result = 0; + + cmd->params.mac_addr.action = cpu_to_le16(cmd_action); + + if (cmd_action == HostCmd_ACT_GEN_SET) + memcpy(cmd->params.mac_addr.mac_addr, priv->curr_addr, + ETH_ALEN); + return 0; +} + +/* + * This function prepares command to set MAC multicast address. + * + * Preparation includes - + * - Setting command ID, action and proper size + * - Setting MAC multicast address + * - Ensuring correct endian-ness + */ +static int mwifiex_cmd_mac_multicast_adr(struct mwifiex_private *priv, + struct host_cmd_ds_command *cmd, + u16 cmd_action, void *data_buf) +{ + struct mwifiex_multicast_list *mcast_list = + (struct mwifiex_multicast_list *) data_buf; + struct host_cmd_ds_mac_multicast_adr *mcast_addr = &cmd->params.mc_addr; + + cmd->size = cpu_to_le16(sizeof(struct host_cmd_ds_mac_multicast_adr) + + S_DS_GEN); + cmd->command = cpu_to_le16(HostCmd_CMD_MAC_MULTICAST_ADR); + + mcast_addr->action = cpu_to_le16(cmd_action); + mcast_addr->num_of_adrs = + cpu_to_le16((u16) mcast_list->num_multicast_addr); + memcpy(mcast_addr->mac_list, mcast_list->mac_list, + mcast_list->num_multicast_addr * ETH_ALEN); + + return 0; +} + +/* + * This function prepares command to deauthenticate. + * + * Preparation includes - + * - Setting command ID and proper size + * - Setting AP MAC address and reason code + * - Ensuring correct endian-ness + */ +static int mwifiex_cmd_802_11_deauthenticate(struct mwifiex_private *priv, + struct host_cmd_ds_command *cmd, + void *data_buf) +{ + struct host_cmd_ds_802_11_deauthenticate *deauth = &cmd->params.deauth; + + cmd->command = cpu_to_le16(HostCmd_CMD_802_11_DEAUTHENTICATE); + cmd->size = cpu_to_le16(sizeof(struct host_cmd_ds_802_11_deauthenticate) + + S_DS_GEN); + + /* Set AP MAC address */ + memcpy(deauth->mac_addr, (u8 *) data_buf, ETH_ALEN); + + dev_dbg(priv->adapter->dev, "cmd: Deauth: %pM\n", deauth->mac_addr); + + deauth->reason_code = cpu_to_le16(WLAN_REASON_DEAUTH_LEAVING); + + return 0; +} + +/* + * This function prepares command to stop Ad-Hoc network. + * + * Preparation includes - + * - Setting command ID and proper size + * - Ensuring correct endian-ness + */ +static int mwifiex_cmd_802_11_ad_hoc_stop(struct mwifiex_private *priv, + struct host_cmd_ds_command *cmd) +{ + cmd->command = cpu_to_le16(HostCmd_CMD_802_11_AD_HOC_STOP); + cmd->size = cpu_to_le16(S_DS_GEN); + return 0; +} + +/* + * This function sets WEP key(s) to key parameter TLV(s). + * + * Multi-key parameter TLVs are supported, so we can send multiple + * WEP keys in a single buffer. + */ +static int +mwifiex_set_keyparamset_wep(struct mwifiex_private *priv, + struct mwifiex_ie_type_key_param_set *key_param_set, + u16 *key_param_len) +{ + int cur_key_param_len = 0; + u8 i; + + /* Multi-key_param_set TLV is supported */ + for (i = 0; i < NUM_WEP_KEYS; i++) { + if ((priv->wep_key[i].key_length == WLAN_KEY_LEN_WEP40) || + (priv->wep_key[i].key_length == WLAN_KEY_LEN_WEP104)) { + key_param_set->type = + cpu_to_le16(TLV_TYPE_KEY_MATERIAL); +/* Key_param_set WEP fixed length */ +#define KEYPARAMSET_WEP_FIXED_LEN 8 + key_param_set->length = cpu_to_le16((u16) + (priv->wep_key[i]. + key_length + + KEYPARAMSET_WEP_FIXED_LEN)); + key_param_set->key_type_id = + cpu_to_le16(KEY_TYPE_ID_WEP); + key_param_set->key_info = + cpu_to_le16(KEY_INFO_WEP_ENABLED | + KEY_INFO_WEP_UNICAST | + KEY_INFO_WEP_MCAST); + key_param_set->key_len = + cpu_to_le16(priv->wep_key[i].key_length); + /* Set WEP key index */ + key_param_set->key[0] = i; + /* Set default Tx key flag */ + if (i == + (priv-> + wep_key_curr_index & HostCmd_WEP_KEY_INDEX_MASK)) + key_param_set->key[1] = 1; + else + key_param_set->key[1] = 0; + memmove(&key_param_set->key[2], + priv->wep_key[i].key_material, + priv->wep_key[i].key_length); + + cur_key_param_len = priv->wep_key[i].key_length + + KEYPARAMSET_WEP_FIXED_LEN + + sizeof(struct mwifiex_ie_types_header); + *key_param_len += (u16) cur_key_param_len; + key_param_set = + (struct mwifiex_ie_type_key_param_set *) + ((u8 *)key_param_set + + cur_key_param_len); + } else if (!priv->wep_key[i].key_length) { + continue; + } else { + dev_err(priv->adapter->dev, + "key%d Length = %d is incorrect\n", + (i + 1), priv->wep_key[i].key_length); + return -1; + } + } + + return 0; +} + +/* + * This function prepares command to set/get/reset network key(s). + * + * Preparation includes - + * - Setting command ID, action and proper size + * - Setting WEP keys, WAPI keys or WPA keys along with required + * encryption (TKIP, AES) (as required) + * - Ensuring correct endian-ness + */ +static int mwifiex_cmd_802_11_key_material(struct mwifiex_private *priv, + struct host_cmd_ds_command *cmd, + u16 cmd_action, + u32 cmd_oid, void *data_buf) +{ + struct host_cmd_ds_802_11_key_material *key_material = + &cmd->params.key_material; + struct mwifiex_ds_encrypt_key *enc_key = + (struct mwifiex_ds_encrypt_key *) data_buf; + u16 key_param_len = 0; + int ret = 0; + const u8 bc_mac[] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; + + cmd->command = cpu_to_le16(HostCmd_CMD_802_11_KEY_MATERIAL); + key_material->action = cpu_to_le16(cmd_action); + + if (cmd_action == HostCmd_ACT_GEN_GET) { + cmd->size = + cpu_to_le16(sizeof(key_material->action) + S_DS_GEN); + return ret; + } + + if (!enc_key) { + memset(&key_material->key_param_set, 0, + (NUM_WEP_KEYS * + sizeof(struct mwifiex_ie_type_key_param_set))); + ret = mwifiex_set_keyparamset_wep(priv, + &key_material->key_param_set, + &key_param_len); + cmd->size = cpu_to_le16(key_param_len + + sizeof(key_material->action) + S_DS_GEN); + return ret; + } else + memset(&key_material->key_param_set, 0, + sizeof(struct mwifiex_ie_type_key_param_set)); + if (enc_key->is_wapi_key) { + dev_dbg(priv->adapter->dev, "info: Set WAPI Key\n"); + key_material->key_param_set.key_type_id = + cpu_to_le16(KEY_TYPE_ID_WAPI); + if (cmd_oid == KEY_INFO_ENABLED) + key_material->key_param_set.key_info = + cpu_to_le16(KEY_INFO_WAPI_ENABLED); + else + key_material->key_param_set.key_info = + cpu_to_le16(!KEY_INFO_WAPI_ENABLED); + + key_material->key_param_set.key[0] = enc_key->key_index; + if (!priv->sec_info.wapi_key_on) + key_material->key_param_set.key[1] = 1; + else + /* set 0 when re-key */ + key_material->key_param_set.key[1] = 0; + + if (0 != memcmp(enc_key->mac_addr, bc_mac, sizeof(bc_mac))) { + /* WAPI pairwise key: unicast */ + key_material->key_param_set.key_info |= + cpu_to_le16(KEY_INFO_WAPI_UNICAST); + } else { /* WAPI group key: multicast */ + key_material->key_param_set.key_info |= + cpu_to_le16(KEY_INFO_WAPI_MCAST); + priv->sec_info.wapi_key_on = true; + } + + key_material->key_param_set.type = + cpu_to_le16(TLV_TYPE_KEY_MATERIAL); + key_material->key_param_set.key_len = + cpu_to_le16(WAPI_KEY_LEN); + memcpy(&key_material->key_param_set.key[2], + enc_key->key_material, enc_key->key_len); + memcpy(&key_material->key_param_set.key[2 + enc_key->key_len], + enc_key->wapi_rxpn, WAPI_RXPN_LEN); + key_material->key_param_set.length = + cpu_to_le16(WAPI_KEY_LEN + KEYPARAMSET_FIXED_LEN); + + key_param_len = (WAPI_KEY_LEN + KEYPARAMSET_FIXED_LEN) + + sizeof(struct mwifiex_ie_types_header); + cmd->size = cpu_to_le16(key_param_len + + sizeof(key_material->action) + S_DS_GEN); + return ret; + } + if (enc_key->key_len == WLAN_KEY_LEN_CCMP) { + dev_dbg(priv->adapter->dev, "cmd: WPA_AES\n"); + key_material->key_param_set.key_type_id = + cpu_to_le16(KEY_TYPE_ID_AES); + if (cmd_oid == KEY_INFO_ENABLED) + key_material->key_param_set.key_info = + cpu_to_le16(KEY_INFO_AES_ENABLED); + else + key_material->key_param_set.key_info = + cpu_to_le16(!KEY_INFO_AES_ENABLED); + + if (enc_key->key_index & MWIFIEX_KEY_INDEX_UNICAST) + /* AES pairwise key: unicast */ + key_material->key_param_set.key_info |= + cpu_to_le16(KEY_INFO_AES_UNICAST); + else /* AES group key: multicast */ + key_material->key_param_set.key_info |= + cpu_to_le16(KEY_INFO_AES_MCAST); + } else if (enc_key->key_len == WLAN_KEY_LEN_TKIP) { + dev_dbg(priv->adapter->dev, "cmd: WPA_TKIP\n"); + key_material->key_param_set.key_type_id = + cpu_to_le16(KEY_TYPE_ID_TKIP); + key_material->key_param_set.key_info = + cpu_to_le16(KEY_INFO_TKIP_ENABLED); + + if (enc_key->key_index & MWIFIEX_KEY_INDEX_UNICAST) + /* TKIP pairwise key: unicast */ + key_material->key_param_set.key_info |= + cpu_to_le16(KEY_INFO_TKIP_UNICAST); + else /* TKIP group key: multicast */ + key_material->key_param_set.key_info |= + cpu_to_le16(KEY_INFO_TKIP_MCAST); + } + + if (key_material->key_param_set.key_type_id) { + key_material->key_param_set.type = + cpu_to_le16(TLV_TYPE_KEY_MATERIAL); + key_material->key_param_set.key_len = + cpu_to_le16((u16) enc_key->key_len); + memcpy(key_material->key_param_set.key, enc_key->key_material, + enc_key->key_len); + key_material->key_param_set.length = + cpu_to_le16((u16) enc_key->key_len + + KEYPARAMSET_FIXED_LEN); + + key_param_len = (u16) (enc_key->key_len + KEYPARAMSET_FIXED_LEN) + + sizeof(struct mwifiex_ie_types_header); + + cmd->size = cpu_to_le16(key_param_len + + sizeof(key_material->action) + S_DS_GEN); + } + + return ret; +} + +/* + * This function prepares command to set/get 11d domain information. + * + * Preparation includes - + * - Setting command ID, action and proper size + * - Setting domain information fields (for SET only) + * - Ensuring correct endian-ness + */ +static int mwifiex_cmd_802_11d_domain_info(struct mwifiex_private *priv, + struct host_cmd_ds_command *cmd, + u16 cmd_action) +{ + struct mwifiex_adapter *adapter = priv->adapter; + struct host_cmd_ds_802_11d_domain_info *domain_info = + &cmd->params.domain_info; + struct mwifiex_ietypes_domain_param_set *domain = + &domain_info->domain; + u8 no_of_triplet = adapter->domain_reg.no_of_triplet; + + dev_dbg(adapter->dev, "info: 11D: no_of_triplet=0x%x\n", no_of_triplet); + + cmd->command = cpu_to_le16(HostCmd_CMD_802_11D_DOMAIN_INFO); + domain_info->action = cpu_to_le16(cmd_action); + if (cmd_action == HostCmd_ACT_GEN_GET) { + cmd->size = cpu_to_le16(sizeof(domain_info->action) + S_DS_GEN); + return 0; + } + + /* Set domain info fields */ + domain->header.type = cpu_to_le16(WLAN_EID_COUNTRY); + memcpy(domain->country_code, adapter->domain_reg.country_code, + sizeof(domain->country_code)); + + domain->header.len = cpu_to_le16((no_of_triplet * + sizeof(struct ieee80211_country_ie_triplet)) + + sizeof(domain->country_code)); + + if (no_of_triplet) { + memcpy(domain->triplet, adapter->domain_reg.triplet, + no_of_triplet * + sizeof(struct ieee80211_country_ie_triplet)); + + cmd->size = cpu_to_le16(sizeof(domain_info->action) + + le16_to_cpu(domain->header.len) + + sizeof(struct mwifiex_ie_types_header) + + S_DS_GEN); + } else { + cmd->size = cpu_to_le16(sizeof(domain_info->action) + S_DS_GEN); + } + + return 0; +} + +/* + * This function prepares command to set/get RF channel. + * + * Preparation includes - + * - Setting command ID, action and proper size + * - Setting RF type and current RF channel (for SET only) + * - Ensuring correct endian-ness + */ +static int mwifiex_cmd_802_11_rf_channel(struct mwifiex_private *priv, + struct host_cmd_ds_command *cmd, + u16 cmd_action, void *data_buf) +{ + struct host_cmd_ds_802_11_rf_channel *rf_chan = + &cmd->params.rf_channel; + uint16_t rf_type = le16_to_cpu(rf_chan->rf_type); + + cmd->command = cpu_to_le16(HostCmd_CMD_802_11_RF_CHANNEL); + cmd->size = cpu_to_le16(sizeof(struct host_cmd_ds_802_11_rf_channel) + + S_DS_GEN); + + if (cmd_action == HostCmd_ACT_GEN_SET) { + if ((priv->adapter->adhoc_start_band & BAND_A) + || (priv->adapter->adhoc_start_band & BAND_AN)) + rf_chan->rf_type = + cpu_to_le16(HostCmd_SCAN_RADIO_TYPE_A); + + rf_type = le16_to_cpu(rf_chan->rf_type); + SET_SECONDARYCHAN(rf_type, priv->adapter->chan_offset); + rf_chan->current_channel = cpu_to_le16(*((u16 *) data_buf)); + } + rf_chan->action = cpu_to_le16(cmd_action); + return 0; +} + +/* + * This function prepares command to set/get IBSS coalescing status. + * + * Preparation includes - + * - Setting command ID, action and proper size + * - Setting status to enable or disable (for SET only) + * - Ensuring correct endian-ness + */ +static int mwifiex_cmd_ibss_coalescing_status(struct mwifiex_private *priv, + struct host_cmd_ds_command *cmd, + u16 cmd_action, void *data_buf) +{ + struct host_cmd_ds_802_11_ibss_status *ibss_coal = + &(cmd->params.ibss_coalescing); + u16 enable = 0; + + cmd->command = cpu_to_le16(HostCmd_CMD_802_11_IBSS_COALESCING_STATUS); + cmd->size = cpu_to_le16(sizeof(struct host_cmd_ds_802_11_ibss_status) + + S_DS_GEN); + cmd->result = 0; + ibss_coal->action = cpu_to_le16(cmd_action); + + switch (cmd_action) { + case HostCmd_ACT_GEN_SET: + if (data_buf != NULL) + enable = *(u16 *) data_buf; + ibss_coal->enable = cpu_to_le16(enable); + break; + + /* In other case.. Nothing to do */ + case HostCmd_ACT_GEN_GET: + default: + break; + } + + return 0; +} + +/* + * This function prepares command to set/get register value. + * + * Preparation includes - + * - Setting command ID, action and proper size + * - Setting register offset (for both GET and SET) and + * register value (for SET only) + * - Ensuring correct endian-ness + * + * The following type of registers can be accessed with this function - + * - MAC register + * - BBP register + * - RF register + * - PMIC register + * - CAU register + * - EEPROM + */ +static int mwifiex_cmd_reg_access(struct host_cmd_ds_command *cmd, + u16 cmd_action, void *data_buf) +{ + struct mwifiex_ds_reg_rw *reg_rw; + + reg_rw = (struct mwifiex_ds_reg_rw *) data_buf; + switch (le16_to_cpu(cmd->command)) { + case HostCmd_CMD_MAC_REG_ACCESS: + { + struct host_cmd_ds_mac_reg_access *mac_reg; + + cmd->size = cpu_to_le16(sizeof(*mac_reg) + S_DS_GEN); + mac_reg = (struct host_cmd_ds_mac_reg_access *) &cmd-> + params.mac_reg; + mac_reg->action = cpu_to_le16(cmd_action); + mac_reg->offset = + cpu_to_le16((u16) le32_to_cpu(reg_rw->offset)); + mac_reg->value = reg_rw->value; + break; + } + case HostCmd_CMD_BBP_REG_ACCESS: + { + struct host_cmd_ds_bbp_reg_access *bbp_reg; + + cmd->size = cpu_to_le16(sizeof(*bbp_reg) + S_DS_GEN); + bbp_reg = (struct host_cmd_ds_bbp_reg_access *) &cmd-> + params.bbp_reg; + bbp_reg->action = cpu_to_le16(cmd_action); + bbp_reg->offset = + cpu_to_le16((u16) le32_to_cpu(reg_rw->offset)); + bbp_reg->value = (u8) le32_to_cpu(reg_rw->value); + break; + } + case HostCmd_CMD_RF_REG_ACCESS: + { + struct host_cmd_ds_rf_reg_access *rf_reg; + + cmd->size = cpu_to_le16(sizeof(*rf_reg) + S_DS_GEN); + rf_reg = (struct host_cmd_ds_rf_reg_access *) &cmd-> + params.rf_reg; + rf_reg->action = cpu_to_le16(cmd_action); + rf_reg->offset = + cpu_to_le16((u16) le32_to_cpu(reg_rw->offset)); + rf_reg->value = (u8) le32_to_cpu(reg_rw->value); + break; + } + case HostCmd_CMD_PMIC_REG_ACCESS: + { + struct host_cmd_ds_pmic_reg_access *pmic_reg; + + cmd->size = cpu_to_le16(sizeof(*pmic_reg) + S_DS_GEN); + pmic_reg = (struct host_cmd_ds_pmic_reg_access *) &cmd-> + params.pmic_reg; + pmic_reg->action = cpu_to_le16(cmd_action); + pmic_reg->offset = + cpu_to_le16((u16) le32_to_cpu(reg_rw->offset)); + pmic_reg->value = (u8) le32_to_cpu(reg_rw->value); + break; + } + case HostCmd_CMD_CAU_REG_ACCESS: + { + struct host_cmd_ds_rf_reg_access *cau_reg; + + cmd->size = cpu_to_le16(sizeof(*cau_reg) + S_DS_GEN); + cau_reg = (struct host_cmd_ds_rf_reg_access *) &cmd-> + params.rf_reg; + cau_reg->action = cpu_to_le16(cmd_action); + cau_reg->offset = + cpu_to_le16((u16) le32_to_cpu(reg_rw->offset)); + cau_reg->value = (u8) le32_to_cpu(reg_rw->value); + break; + } + case HostCmd_CMD_802_11_EEPROM_ACCESS: + { + struct mwifiex_ds_read_eeprom *rd_eeprom = + (struct mwifiex_ds_read_eeprom *) data_buf; + struct host_cmd_ds_802_11_eeprom_access *cmd_eeprom = + (struct host_cmd_ds_802_11_eeprom_access *) + &cmd->params.eeprom; + + cmd->size = cpu_to_le16(sizeof(*cmd_eeprom) + S_DS_GEN); + cmd_eeprom->action = cpu_to_le16(cmd_action); + cmd_eeprom->offset = rd_eeprom->offset; + cmd_eeprom->byte_count = rd_eeprom->byte_count; + cmd_eeprom->value = 0; + break; + } + default: + return -1; + } + + return 0; +} + +/* + * This function prepares the commands before sending them to the firmware. + * + * This is a generic function which calls specific command preparation + * routines based upon the command number. + */ +int mwifiex_sta_prepare_cmd(struct mwifiex_private *priv, uint16_t cmd_no, + u16 cmd_action, u32 cmd_oid, + void *data_buf, void *cmd_buf) +{ + struct host_cmd_ds_command *cmd_ptr = + (struct host_cmd_ds_command *) cmd_buf; + int ret = 0; + + /* Prepare command */ + switch (cmd_no) { + case HostCmd_CMD_GET_HW_SPEC: + ret = mwifiex_cmd_get_hw_spec(priv, cmd_ptr); + break; + case HostCmd_CMD_MAC_CONTROL: + ret = mwifiex_cmd_mac_control(priv, cmd_ptr, cmd_action, + data_buf); + break; + case HostCmd_CMD_802_11_MAC_ADDRESS: + ret = mwifiex_cmd_802_11_mac_address(priv, cmd_ptr, + cmd_action); + break; + case HostCmd_CMD_MAC_MULTICAST_ADR: + ret = mwifiex_cmd_mac_multicast_adr(priv, cmd_ptr, cmd_action, + data_buf); + break; + case HostCmd_CMD_TX_RATE_CFG: + ret = mwifiex_cmd_tx_rate_cfg(priv, cmd_ptr, cmd_action, + data_buf); + break; + case HostCmd_CMD_TXPWR_CFG: + ret = mwifiex_cmd_tx_power_cfg(priv, cmd_ptr, cmd_action, + data_buf); + break; + case HostCmd_CMD_802_11_PS_MODE_ENH: + ret = mwifiex_cmd_enh_power_mode(priv, cmd_ptr, cmd_action, + (uint16_t)cmd_oid, data_buf); + break; + case HostCmd_CMD_802_11_HS_CFG_ENH: + ret = mwifiex_cmd_802_11_hs_cfg(priv, cmd_ptr, cmd_action, + (struct mwifiex_hs_config_param *) data_buf); + break; + case HostCmd_CMD_802_11_SCAN: + ret = mwifiex_cmd_802_11_scan(priv, cmd_ptr, data_buf); + break; + case HostCmd_CMD_802_11_BG_SCAN_QUERY: + ret = mwifiex_cmd_802_11_bg_scan_query(priv, cmd_ptr, + data_buf); + break; + case HostCmd_CMD_802_11_ASSOCIATE: + ret = mwifiex_cmd_802_11_associate(priv, cmd_ptr, data_buf); + break; + case HostCmd_CMD_802_11_DEAUTHENTICATE: + ret = mwifiex_cmd_802_11_deauthenticate(priv, cmd_ptr, + data_buf); + break; + case HostCmd_CMD_802_11_AD_HOC_START: + ret = mwifiex_cmd_802_11_ad_hoc_start(priv, cmd_ptr, + data_buf); + break; + case HostCmd_CMD_802_11_GET_LOG: + ret = mwifiex_cmd_802_11_get_log(priv, cmd_ptr); + break; + case HostCmd_CMD_802_11_AD_HOC_JOIN: + ret = mwifiex_cmd_802_11_ad_hoc_join(priv, cmd_ptr, + data_buf); + break; + case HostCmd_CMD_802_11_AD_HOC_STOP: + ret = mwifiex_cmd_802_11_ad_hoc_stop(priv, cmd_ptr); + break; + case HostCmd_CMD_RSSI_INFO: + ret = mwifiex_cmd_802_11_rssi_info(priv, cmd_ptr, cmd_action); + break; + case HostCmd_CMD_802_11_SNMP_MIB: + ret = mwifiex_cmd_802_11_snmp_mib(priv, cmd_ptr, cmd_action, + cmd_oid, data_buf); + break; + case HostCmd_CMD_802_11_TX_RATE_QUERY: + cmd_ptr->command = + cpu_to_le16(HostCmd_CMD_802_11_TX_RATE_QUERY); + cmd_ptr->size = + cpu_to_le16(sizeof(struct host_cmd_ds_tx_rate_query) + + S_DS_GEN); + priv->tx_rate = 0; + ret = 0; + break; + case HostCmd_CMD_VERSION_EXT: + cmd_ptr->command = cpu_to_le16(cmd_no); + cmd_ptr->params.verext.version_str_sel = + (u8) (*((u32 *) data_buf)); + memcpy(&cmd_ptr->params, data_buf, + sizeof(struct host_cmd_ds_version_ext)); + cmd_ptr->size = + cpu_to_le16(sizeof(struct host_cmd_ds_version_ext) + + S_DS_GEN); + ret = 0; + break; + case HostCmd_CMD_802_11_RF_CHANNEL: + ret = mwifiex_cmd_802_11_rf_channel(priv, cmd_ptr, cmd_action, + data_buf); + break; + case HostCmd_CMD_FUNC_INIT: + if (priv->adapter->hw_status == MWIFIEX_HW_STATUS_RESET) + priv->adapter->hw_status = MWIFIEX_HW_STATUS_READY; + cmd_ptr->command = cpu_to_le16(cmd_no); + cmd_ptr->size = cpu_to_le16(S_DS_GEN); + break; + case HostCmd_CMD_FUNC_SHUTDOWN: + priv->adapter->hw_status = MWIFIEX_HW_STATUS_RESET; + cmd_ptr->command = cpu_to_le16(cmd_no); + cmd_ptr->size = cpu_to_le16(S_DS_GEN); + break; + case HostCmd_CMD_11N_ADDBA_REQ: + ret = mwifiex_cmd_11n_addba_req(priv, cmd_ptr, data_buf); + break; + case HostCmd_CMD_11N_DELBA: + ret = mwifiex_cmd_11n_delba(priv, cmd_ptr, data_buf); + break; + case HostCmd_CMD_11N_ADDBA_RSP: + ret = mwifiex_cmd_11n_addba_rsp_gen(priv, cmd_ptr, data_buf); + break; + case HostCmd_CMD_802_11_KEY_MATERIAL: + ret = mwifiex_cmd_802_11_key_material(priv, cmd_ptr, + cmd_action, cmd_oid, + data_buf); + break; + case HostCmd_CMD_802_11D_DOMAIN_INFO: + ret = mwifiex_cmd_802_11d_domain_info(priv, cmd_ptr, + cmd_action); + break; + case HostCmd_CMD_RECONFIGURE_TX_BUFF: + ret = mwifiex_cmd_recfg_tx_buf(priv, cmd_ptr, cmd_action, + data_buf); + break; + case HostCmd_CMD_AMSDU_AGGR_CTRL: + ret = mwifiex_cmd_amsdu_aggr_ctrl(priv, cmd_ptr, cmd_action, + data_buf); + break; + case HostCmd_CMD_11N_CFG: + ret = mwifiex_cmd_11n_cfg(priv, cmd_ptr, cmd_action, + data_buf); + break; + case HostCmd_CMD_WMM_GET_STATUS: + dev_dbg(priv->adapter->dev, + "cmd: WMM: WMM_GET_STATUS cmd sent\n"); + cmd_ptr->command = cpu_to_le16(HostCmd_CMD_WMM_GET_STATUS); + cmd_ptr->size = + cpu_to_le16(sizeof(struct host_cmd_ds_wmm_get_status) + + S_DS_GEN); + ret = 0; + break; + case HostCmd_CMD_802_11_IBSS_COALESCING_STATUS: + ret = mwifiex_cmd_ibss_coalescing_status(priv, cmd_ptr, + cmd_action, data_buf); + break; + case HostCmd_CMD_MAC_REG_ACCESS: + case HostCmd_CMD_BBP_REG_ACCESS: + case HostCmd_CMD_RF_REG_ACCESS: + case HostCmd_CMD_PMIC_REG_ACCESS: + case HostCmd_CMD_CAU_REG_ACCESS: + case HostCmd_CMD_802_11_EEPROM_ACCESS: + ret = mwifiex_cmd_reg_access(cmd_ptr, cmd_action, data_buf); + break; + case HostCmd_CMD_SET_BSS_MODE: + cmd_ptr->command = cpu_to_le16(cmd_no); + if (priv->bss_mode == MWIFIEX_BSS_MODE_IBSS) + cmd_ptr->params.bss_mode.con_type = + CONNECTION_TYPE_ADHOC; + else if (priv->bss_mode == MWIFIEX_BSS_MODE_INFRA) + cmd_ptr->params.bss_mode.con_type = + CONNECTION_TYPE_INFRA; + cmd_ptr->size = cpu_to_le16(sizeof(struct + host_cmd_ds_set_bss_mode) + S_DS_GEN); + ret = 0; + break; + default: + dev_err(priv->adapter->dev, + "PREP_CMD: unknown cmd- %#x\n", cmd_no); + ret = -1; + break; + } + return ret; +} + +/* + * This function issues commands to initialize firmware. + * + * This is called after firmware download to bring the card to + * working state. + * + * The following commands are issued sequentially - + * - Function init (for first interface only) + * - Read MAC address (for first interface only) + * - Reconfigure Tx buffer size (for first interface only) + * - Enable auto deep sleep (for first interface only) + * - Get Tx rate + * - Get Tx power + * - Set IBSS coalescing status + * - Set AMSDU aggregation control + * - Set 11d control + * - Set MAC control (this must be the last command to initialize firmware) + */ +int mwifiex_sta_init_cmd(struct mwifiex_private *priv, u8 first_sta) +{ + int ret = 0; + u16 enable = true; + struct mwifiex_ds_11n_amsdu_aggr_ctrl amsdu_aggr_ctrl; + struct mwifiex_ds_auto_ds auto_ds; + enum state_11d_t state_11d; + + if (first_sta) { + + ret = mwifiex_prepare_cmd(priv, HostCmd_CMD_FUNC_INIT, + HostCmd_ACT_GEN_SET, 0, NULL, NULL); + if (ret) + return -1; + /* Read MAC address from HW */ + ret = mwifiex_prepare_cmd(priv, HostCmd_CMD_GET_HW_SPEC, + HostCmd_ACT_GEN_GET, 0, NULL, NULL); + if (ret) + return -1; + + /* Reconfigure tx buf size */ + ret = mwifiex_prepare_cmd(priv, HostCmd_CMD_RECONFIGURE_TX_BUFF, + HostCmd_ACT_GEN_SET, 0, NULL, + &priv->adapter->tx_buf_size); + if (ret) + return -1; + + /* Enable IEEE PS by default */ + priv->adapter->ps_mode = MWIFIEX_802_11_POWER_MODE_PSP; + ret = mwifiex_prepare_cmd(priv, HostCmd_CMD_802_11_PS_MODE_ENH, + EN_AUTO_PS, BITMAP_STA_PS, NULL, + NULL); + if (ret) + return -1; + } + + /* get tx rate */ + ret = mwifiex_prepare_cmd(priv, HostCmd_CMD_TX_RATE_CFG, + HostCmd_ACT_GEN_GET, 0, NULL, NULL); + if (ret) + return -1; + priv->data_rate = 0; + + /* get tx power */ + ret = mwifiex_prepare_cmd(priv, HostCmd_CMD_TXPWR_CFG, + HostCmd_ACT_GEN_GET, 0, NULL, NULL); + if (ret) + return -1; + + /* set ibss coalescing_status */ + ret = mwifiex_prepare_cmd(priv, + HostCmd_CMD_802_11_IBSS_COALESCING_STATUS, + HostCmd_ACT_GEN_SET, 0, NULL, &enable); + if (ret) + return -1; + + memset(&amsdu_aggr_ctrl, 0, sizeof(amsdu_aggr_ctrl)); + amsdu_aggr_ctrl.enable = true; + /* Send request to firmware */ + ret = mwifiex_prepare_cmd(priv, HostCmd_CMD_AMSDU_AGGR_CTRL, + HostCmd_ACT_GEN_SET, 0, NULL, + (void *) &amsdu_aggr_ctrl); + if (ret) + return -1; + /* MAC Control must be the last command in init_fw */ + /* set MAC Control */ + ret = mwifiex_prepare_cmd(priv, HostCmd_CMD_MAC_CONTROL, + HostCmd_ACT_GEN_SET, 0, NULL, + &priv->curr_pkt_filter); + if (ret) + return -1; + + if (first_sta) { + /* Enable auto deep sleep */ + auto_ds.auto_ds = DEEP_SLEEP_ON; + auto_ds.idle_time = DEEP_SLEEP_IDLE_TIME; + ret = mwifiex_prepare_cmd(priv, + HostCmd_CMD_802_11_PS_MODE_ENH, + EN_AUTO_PS, BITMAP_AUTO_DS, NULL, + &auto_ds); + if (ret) + return -1; + } + + /* Send cmd to FW to enable/disable 11D function */ + state_11d = ENABLE_11D; + ret = mwifiex_prepare_cmd(priv, HostCmd_CMD_802_11_SNMP_MIB, + HostCmd_ACT_GEN_SET, DOT11D_I, + NULL, &state_11d); + if (ret) + dev_err(priv->adapter->dev, "11D: failed to enable 11D\n"); + + /* set last_init_cmd */ + priv->adapter->last_init_cmd = HostCmd_CMD_802_11_SNMP_MIB; + ret = -EINPROGRESS; + + return ret; +} diff --git a/drivers/net/wireless/mwifiex/sta_cmdresp.c b/drivers/net/wireless/mwifiex/sta_cmdresp.c new file mode 100644 index 0000000..ae960dd --- /dev/null +++ b/drivers/net/wireless/mwifiex/sta_cmdresp.c @@ -0,0 +1,986 @@ +/* + * Marvell Wireless LAN device driver: station command response handling + * + * Copyright (C) 2011, Marvell International Ltd. + * + * This software file (the "File") is distributed by Marvell International + * Ltd. under the terms of the GNU General Public License Version 2, June 1991 + * (the "License"). You may use, redistribute and/or modify this File in + * accordance with the terms and conditions of the License, a copy of which + * is available by writing to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the + * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. + * + * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE + * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE + * ARE EXPRESSLY DISCLAIMED. The License provides additional details about + * this warranty disclaimer. + */ + +#include "decl.h" +#include "ioctl.h" +#include "util.h" +#include "fw.h" +#include "main.h" +#include "wmm.h" +#include "11n.h" + + +/* + * This function handles the command response error case. + * + * For scan response error, the function cancels all the pending + * scan commands and generates an event to inform the applications + * of the scan completion. + * + * For Power Save command failure, we do not retry enter PS + * command in case of Ad-hoc mode. + * + * For all other response errors, the current command buffer is freed + * and returned to the free command queue. + */ +static void +mwifiex_process_cmdresp_error(struct mwifiex_private *priv, + struct host_cmd_ds_command *resp, + struct mwifiex_wait_queue *wq_buf) +{ + struct cmd_ctrl_node *cmd_node = NULL, *tmp_node = NULL; + struct mwifiex_adapter *adapter = priv->adapter; + unsigned long flags; + + dev_err(adapter->dev, "CMD_RESP: cmd %#x error, result=%#x\n", + resp->command, resp->result); + if (wq_buf) + wq_buf->status = MWIFIEX_ERROR_FW_CMDRESP; + + switch (le16_to_cpu(resp->command)) { + case HostCmd_CMD_802_11_PS_MODE_ENH: + { + struct host_cmd_ds_802_11_ps_mode_enh *pm = + &resp->params.psmode_enh; + dev_err(adapter->dev, "PS_MODE_ENH cmd failed: " + "result=0x%x action=0x%X\n", + resp->result, le16_to_cpu(pm->action)); + /* We do not re-try enter-ps command in ad-hoc mode. */ + if (le16_to_cpu(pm->action) == EN_AUTO_PS && + (le16_to_cpu(pm->params.auto_ps.ps_bitmap) & + BITMAP_STA_PS) + && priv->bss_mode == MWIFIEX_BSS_MODE_IBSS) + adapter->ps_mode = + MWIFIEX_802_11_POWER_MODE_CAM; + } + break; + case HostCmd_CMD_802_11_SCAN: + /* Cancel all pending scan command */ + spin_lock_irqsave(&adapter->scan_pending_q_lock, flags); + list_for_each_entry_safe(cmd_node, tmp_node, + &adapter->scan_pending_q, list) { + list_del(&cmd_node->list); + spin_unlock_irqrestore(&adapter->scan_pending_q_lock, + flags); + mwifiex_insert_cmd_to_free_q(adapter, cmd_node); + spin_lock_irqsave(&adapter->scan_pending_q_lock, flags); + } + spin_unlock_irqrestore(&adapter->scan_pending_q_lock, flags); + + spin_lock_irqsave(&adapter->mwifiex_cmd_lock, flags); + adapter->scan_processing = false; + spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock, flags); + if (priv->report_scan_result) + priv->report_scan_result = false; + if (priv->scan_pending_on_block) { + priv->scan_pending_on_block = false; + up(&priv->async_sem); + } + break; + + case HostCmd_CMD_MAC_CONTROL: + break; + + default: + break; + } + /* Handling errors here */ + mwifiex_insert_cmd_to_free_q(adapter, adapter->curr_cmd); + + spin_lock_irqsave(&adapter->mwifiex_cmd_lock, flags); + adapter->curr_cmd = NULL; + spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock, flags); + + return; +} + +/* + * This function handles the command response of get RSSI info. + * + * Handling includes changing the header fields into CPU format + * and saving the following parameters in driver - + * - Last data and beacon RSSI value + * - Average data and beacon RSSI value + * - Last data and beacon NF value + * - Average data and beacon NF value + * + * The parameters are send to the application as well, along with + * calculated SNR values. + */ +static int mwifiex_ret_802_11_rssi_info(struct mwifiex_private *priv, + struct host_cmd_ds_command *resp, + void *data_buf) +{ + struct host_cmd_ds_802_11_rssi_info_rsp *rssi_info_rsp = + &resp->params.rssi_info_rsp; + struct mwifiex_ds_get_signal *signal = NULL; + + priv->data_rssi_last = le16_to_cpu(rssi_info_rsp->data_rssi_last); + priv->data_nf_last = le16_to_cpu(rssi_info_rsp->data_nf_last); + + priv->data_rssi_avg = le16_to_cpu(rssi_info_rsp->data_rssi_avg); + priv->data_nf_avg = le16_to_cpu(rssi_info_rsp->data_nf_avg); + + priv->bcn_rssi_last = le16_to_cpu(rssi_info_rsp->bcn_rssi_last); + priv->bcn_nf_last = le16_to_cpu(rssi_info_rsp->bcn_nf_last); + + priv->bcn_rssi_avg = le16_to_cpu(rssi_info_rsp->bcn_rssi_avg); + priv->bcn_nf_avg = le16_to_cpu(rssi_info_rsp->bcn_nf_avg); + + /* Need to indicate IOCTL complete */ + if (data_buf) { + signal = (struct mwifiex_ds_get_signal *) data_buf; + memset(signal, 0, sizeof(struct mwifiex_ds_get_signal)); + + signal->selector = ALL_RSSI_INFO_MASK; + + /* RSSI */ + signal->bcn_rssi_last = priv->bcn_rssi_last; + signal->bcn_rssi_avg = priv->bcn_rssi_avg; + signal->data_rssi_last = priv->data_rssi_last; + signal->data_rssi_avg = priv->data_rssi_avg; + + /* SNR */ + signal->bcn_snr_last = + CAL_SNR(priv->bcn_rssi_last, priv->bcn_nf_last); + signal->bcn_snr_avg = + CAL_SNR(priv->bcn_rssi_avg, priv->bcn_nf_avg); + signal->data_snr_last = + CAL_SNR(priv->data_rssi_last, priv->data_nf_last); + signal->data_snr_avg = + CAL_SNR(priv->data_rssi_avg, priv->data_nf_avg); + + /* NF */ + signal->bcn_nf_last = priv->bcn_nf_last; + signal->bcn_nf_avg = priv->bcn_nf_avg; + signal->data_nf_last = priv->data_nf_last; + signal->data_nf_avg = priv->data_nf_avg; + } + + return 0; +} + +/* + * This function handles the command response of set/get SNMP + * MIB parameters. + * + * Handling includes changing the header fields into CPU format + * and saving the parameter in driver. + * + * The following parameters are supported - + * - Fragmentation threshold + * - RTS threshold + * - Short retry limit + */ +static int mwifiex_ret_802_11_snmp_mib(struct mwifiex_private *priv, + struct host_cmd_ds_command *resp, + void *data_buf) +{ + struct host_cmd_ds_802_11_snmp_mib *smib = &resp->params.smib; + u16 oid = le16_to_cpu(smib->oid); + u16 query_type = le16_to_cpu(smib->query_type); + u32 ul_temp; + + dev_dbg(priv->adapter->dev, "info: SNMP_RESP: oid value = %#x," + " query_type = %#x, buf size = %#x\n", + oid, query_type, le16_to_cpu(smib->buf_size)); + if (query_type == HostCmd_ACT_GEN_GET) { + ul_temp = le16_to_cpu(*((__le16 *) (smib->value))); + if (data_buf) + *(u32 *)data_buf = ul_temp; + switch (oid) { + case FRAG_THRESH_I: + dev_dbg(priv->adapter->dev, + "info: SNMP_RESP: FragThsd =%u\n", ul_temp); + break; + case RTS_THRESH_I: + dev_dbg(priv->adapter->dev, + "info: SNMP_RESP: RTSThsd =%u\n", ul_temp); + break; + case SHORT_RETRY_LIM_I: + dev_dbg(priv->adapter->dev, + "info: SNMP_RESP: TxRetryCount=%u\n", ul_temp); + break; + default: + break; + } + } + + return 0; +} + +/* + * This function handles the command response of get log request + * + * Handling includes changing the header fields into CPU format + * and sending the received parameters to application. + */ +static int mwifiex_ret_get_log(struct mwifiex_private *priv, + struct host_cmd_ds_command *resp, + void *data_buf) +{ + struct host_cmd_ds_802_11_get_log *get_log = + (struct host_cmd_ds_802_11_get_log *) &resp->params.get_log; + struct mwifiex_ds_get_stats *stats = NULL; + + if (data_buf) { + stats = (struct mwifiex_ds_get_stats *) data_buf; + stats->mcast_tx_frame = le32_to_cpu(get_log->mcast_tx_frame); + stats->failed = le32_to_cpu(get_log->failed); + stats->retry = le32_to_cpu(get_log->retry); + stats->multi_retry = le32_to_cpu(get_log->multi_retry); + stats->frame_dup = le32_to_cpu(get_log->frame_dup); + stats->rts_success = le32_to_cpu(get_log->rts_success); + stats->rts_failure = le32_to_cpu(get_log->rts_failure); + stats->ack_failure = le32_to_cpu(get_log->ack_failure); + stats->rx_frag = le32_to_cpu(get_log->rx_frag); + stats->mcast_rx_frame = le32_to_cpu(get_log->mcast_rx_frame); + stats->fcs_error = le32_to_cpu(get_log->fcs_error); + stats->tx_frame = le32_to_cpu(get_log->tx_frame); + stats->wep_icv_error[0] = + le32_to_cpu(get_log->wep_icv_err_cnt[0]); + stats->wep_icv_error[1] = + le32_to_cpu(get_log->wep_icv_err_cnt[1]); + stats->wep_icv_error[2] = + le32_to_cpu(get_log->wep_icv_err_cnt[2]); + stats->wep_icv_error[3] = + le32_to_cpu(get_log->wep_icv_err_cnt[3]); + } + + return 0; +} + +/* + * This function handles the command response of set/get Tx rate + * configurations. + * + * Handling includes changing the header fields into CPU format + * and saving the following parameters in driver - + * - DSSS rate bitmap + * - OFDM rate bitmap + * - HT MCS rate bitmaps + * + * Based on the new rate bitmaps, the function re-evaluates if + * auto data rate has been activated. If not, it sends another + * query to the firmware to get the current Tx data rate and updates + * the driver value. + */ +static int mwifiex_ret_tx_rate_cfg(struct mwifiex_private *priv, + struct host_cmd_ds_command *resp, + void *data_buf) +{ + struct mwifiex_adapter *adapter = priv->adapter; + struct mwifiex_rate_cfg *ds_rate = NULL; + struct host_cmd_ds_tx_rate_cfg *rate_cfg = &resp->params.tx_rate_cfg; + struct mwifiex_rate_scope *rate_scope; + struct mwifiex_ie_types_header *head = NULL; + u16 tlv, tlv_buf_len; + u8 *tlv_buf; + u32 i; + int ret = 0; + + tlv_buf = (u8 *) ((u8 *) rate_cfg) + + sizeof(struct host_cmd_ds_tx_rate_cfg); + tlv_buf_len = *(u16 *) (tlv_buf + sizeof(u16)); + + while (tlv_buf && tlv_buf_len > 0) { + tlv = (*tlv_buf); + tlv = tlv | (*(tlv_buf + 1) << 8); + + switch (tlv) { + case TLV_TYPE_RATE_SCOPE: + rate_scope = (struct mwifiex_rate_scope *) tlv_buf; + priv->bitmap_rates[0] = + le16_to_cpu(rate_scope->hr_dsss_rate_bitmap); + priv->bitmap_rates[1] = + le16_to_cpu(rate_scope->ofdm_rate_bitmap); + for (i = 0; + i < + sizeof(rate_scope->ht_mcs_rate_bitmap) / + sizeof(u16); i++) + priv->bitmap_rates[2 + i] = + le16_to_cpu(rate_scope-> + ht_mcs_rate_bitmap[i]); + break; + /* Add RATE_DROP tlv here */ + } + + head = (struct mwifiex_ie_types_header *) tlv_buf; + tlv_buf += le16_to_cpu(head->len) + sizeof(*head); + tlv_buf_len -= le16_to_cpu(head->len); + } + + priv->is_data_rate_auto = mwifiex_is_rate_auto(priv); + + if (priv->is_data_rate_auto) + priv->data_rate = 0; + else + ret = mwifiex_prepare_cmd(priv, + HostCmd_CMD_802_11_TX_RATE_QUERY, + HostCmd_ACT_GEN_GET, 0, NULL, NULL); + + if (data_buf) { + ds_rate = (struct mwifiex_rate_cfg *) data_buf; + if (le16_to_cpu(rate_cfg->action) == HostCmd_ACT_GEN_GET) { + if (priv->is_data_rate_auto) { + ds_rate->is_rate_auto = 1; + } else { + ds_rate->rate = + mwifiex_get_rate_index(adapter, + priv-> + bitmap_rates, + sizeof(priv-> + bitmap_rates)); + if (ds_rate->rate >= + MWIFIEX_RATE_BITMAP_OFDM0 + && ds_rate->rate <= + MWIFIEX_RATE_BITMAP_OFDM7) + ds_rate->rate -= + (MWIFIEX_RATE_BITMAP_OFDM0 - + MWIFIEX_RATE_INDEX_OFDM0); + if (ds_rate->rate >= + MWIFIEX_RATE_BITMAP_MCS0 + && ds_rate->rate <= + MWIFIEX_RATE_BITMAP_MCS127) + ds_rate->rate -= + (MWIFIEX_RATE_BITMAP_MCS0 - + MWIFIEX_RATE_INDEX_MCS0); + } + } + } + + return ret; +} + +/* + * This function handles the command response of get Tx power level. + * + * Handling includes saving the maximum and minimum Tx power levels + * in driver, as well as sending the values to user. + */ +static int mwifiex_get_power_level(struct mwifiex_private *priv, void *data_buf) +{ + int length = -1, max_power = -1, min_power = -1; + struct mwifiex_types_power_group *pg_tlv_hdr = NULL; + struct mwifiex_power_group *pg = NULL; + + if (data_buf) { + pg_tlv_hdr = + (struct mwifiex_types_power_group *) ((u8 *) data_buf + + sizeof(struct host_cmd_ds_txpwr_cfg)); + pg = (struct mwifiex_power_group *) ((u8 *) pg_tlv_hdr + + sizeof(struct mwifiex_types_power_group)); + length = pg_tlv_hdr->length; + if (length > 0) { + max_power = pg->power_max; + min_power = pg->power_min; + length -= sizeof(struct mwifiex_power_group); + } + while (length) { + pg++; + if (max_power < pg->power_max) + max_power = pg->power_max; + + if (min_power > pg->power_min) + min_power = pg->power_min; + + length -= sizeof(struct mwifiex_power_group); + } + if (pg_tlv_hdr->length > 0) { + priv->min_tx_power_level = (u8) min_power; + priv->max_tx_power_level = (u8) max_power; + } + } else { + return -1; + } + + return 0; +} + +/* + * This function handles the command response of set/get Tx power + * configurations. + * + * Handling includes changing the header fields into CPU format + * and saving the current Tx power level in driver. + */ +static int mwifiex_ret_tx_power_cfg(struct mwifiex_private *priv, + struct host_cmd_ds_command *resp, + void *data_buf) +{ + struct mwifiex_adapter *adapter = priv->adapter; + struct host_cmd_ds_txpwr_cfg *txp_cfg = &resp->params.txp_cfg; + struct mwifiex_types_power_group *pg_tlv_hdr = NULL; + struct mwifiex_power_group *pg = NULL; + u16 action = le16_to_cpu(txp_cfg->action); + + switch (action) { + case HostCmd_ACT_GEN_GET: + { + pg_tlv_hdr = + (struct mwifiex_types_power_group *) ((u8 *) + txp_cfg + + sizeof + (struct + host_cmd_ds_txpwr_cfg)); + pg = (struct mwifiex_power_group *) ((u8 *) + pg_tlv_hdr + + sizeof(struct + mwifiex_types_power_group)); + if (adapter->hw_status == + MWIFIEX_HW_STATUS_INITIALIZING) + mwifiex_get_power_level(priv, txp_cfg); + priv->tx_power_level = (u16) pg->power_min; + break; + } + case HostCmd_ACT_GEN_SET: + if (le32_to_cpu(txp_cfg->mode)) { + pg_tlv_hdr = + (struct mwifiex_types_power_group *) ((u8 *) + txp_cfg + + sizeof + (struct + host_cmd_ds_txpwr_cfg)); + pg = (struct mwifiex_power_group *) ((u8 *) pg_tlv_hdr + + + sizeof(struct + mwifiex_types_power_group)); + if (pg->power_max == pg->power_min) + priv->tx_power_level = (u16) pg->power_min; + } + break; + default: + dev_err(adapter->dev, "CMD_RESP: unknown cmd action %d\n", + action); + return 0; + } + dev_dbg(adapter->dev, + "info: Current TxPower Level = %d, Max Power=%d, Min Power=%d\n", + priv->tx_power_level, priv->max_tx_power_level, + priv->min_tx_power_level); + + return 0; +} + +/* + * This function handles the command response of set/get MAC address. + * + * Handling includes saving the MAC address in driver. + */ +static int mwifiex_ret_802_11_mac_address(struct mwifiex_private *priv, + struct host_cmd_ds_command *resp) +{ + struct host_cmd_ds_802_11_mac_address *cmd_mac_addr = + &resp->params.mac_addr; + + memcpy(priv->curr_addr, cmd_mac_addr->mac_addr, ETH_ALEN); + + dev_dbg(priv->adapter->dev, + "info: set mac address: %pM\n", priv->curr_addr); + + return 0; +} + +/* + * This function handles the command response of set/get MAC multicast + * address. + */ +static int mwifiex_ret_mac_multicast_adr(struct mwifiex_private *priv, + struct host_cmd_ds_command *resp) +{ + return 0; +} + +/* + * This function handles the command response of get Tx rate query. + * + * Handling includes changing the header fields into CPU format + * and saving the Tx rate and HT information parameters in driver. + * + * Both rate configuration and current data rate can be retrieved + * with this request. + */ +static int mwifiex_ret_802_11_tx_rate_query(struct mwifiex_private *priv, + struct host_cmd_ds_command *resp) +{ + struct mwifiex_adapter *adapter = priv->adapter; + + priv->tx_rate = resp->params.tx_rate.tx_rate; + priv->tx_htinfo = resp->params.tx_rate.ht_info; + if (!priv->is_data_rate_auto) + priv->data_rate = + mwifiex_index_to_data_rate(adapter, priv->tx_rate, + priv->tx_htinfo); + + return 0; +} + +/* + * This function handles the command response of a deauthenticate + * command. + * + * If the deauthenticated MAC matches the current BSS MAC, the connection + * state is reset. + */ +static int mwifiex_ret_802_11_deauthenticate(struct mwifiex_private *priv, + struct host_cmd_ds_command *resp) +{ + struct mwifiex_adapter *adapter = priv->adapter; + + adapter->dbg.num_cmd_deauth++; + if (!memcmp(resp->params.deauth.mac_addr, + &priv->curr_bss_params.bss_descriptor.mac_address, + sizeof(resp->params.deauth.mac_addr))) + mwifiex_reset_connect_state(priv); + + return 0; +} + +/* + * This function handles the command response of ad-hoc stop. + * + * The function resets the connection state in driver. + */ +static int mwifiex_ret_802_11_ad_hoc_stop(struct mwifiex_private *priv, + struct host_cmd_ds_command *resp) +{ + mwifiex_reset_connect_state(priv); + return 0; +} + +/* + * This function handles the command response of set/get key material. + * + * Handling includes updating the driver parameters to reflect the + * changes. + */ +static int mwifiex_ret_802_11_key_material(struct mwifiex_private *priv, + struct host_cmd_ds_command *resp) +{ + struct host_cmd_ds_802_11_key_material *key = + &resp->params.key_material; + + if (le16_to_cpu(key->action) == HostCmd_ACT_GEN_SET) { + if ((le16_to_cpu(key->key_param_set.key_info) & + KEY_INFO_TKIP_MCAST)) { + dev_dbg(priv->adapter->dev, "info: key: GTK is set\n"); + priv->wpa_is_gtk_set = true; + priv->scan_block = false; + } + } + + memset(priv->aes_key.key_param_set.key, 0, + sizeof(key->key_param_set.key)); + priv->aes_key.key_param_set.key_len = key->key_param_set.key_len; + memcpy(priv->aes_key.key_param_set.key, key->key_param_set.key, + le16_to_cpu(priv->aes_key.key_param_set.key_len)); + + return 0; +} + +/* + * This function handles the command response of get 11d domain information. + */ +static int mwifiex_ret_802_11d_domain_info(struct mwifiex_private *priv, + struct host_cmd_ds_command *resp) +{ + struct host_cmd_ds_802_11d_domain_info_rsp *domain_info = + &resp->params.domain_info_resp; + struct mwifiex_ietypes_domain_param_set *domain = &domain_info->domain; + u16 action = le16_to_cpu(domain_info->action); + u8 no_of_triplet = 0; + + no_of_triplet = (u8) ((le16_to_cpu(domain->header.len) - + IEEE80211_COUNTRY_STRING_LEN) / + sizeof(struct ieee80211_country_ie_triplet)); + + dev_dbg(priv->adapter->dev, "info: 11D Domain Info Resp:" + " no_of_triplet=%d\n", no_of_triplet); + + if (no_of_triplet > MWIFIEX_MAX_TRIPLET_802_11D) { + dev_warn(priv->adapter->dev, + "11D: invalid number of triplets %d " + "returned!!\n", no_of_triplet); + return -1; + } + + switch (action) { + case HostCmd_ACT_GEN_SET: /* Proc Set Action */ + break; + case HostCmd_ACT_GEN_GET: + break; + default: + dev_err(priv->adapter->dev, + "11D: invalid action:%d\n", domain_info->action); + return -1; + } + + return 0; +} + +/* + * This function handles the command response of get RF channel. + * + * Handling includes changing the header fields into CPU format + * and saving the new channel in driver. + */ +static int mwifiex_ret_802_11_rf_channel(struct mwifiex_private *priv, + struct host_cmd_ds_command *resp, + void *data_buf) +{ + struct host_cmd_ds_802_11_rf_channel *rf_channel = + &resp->params.rf_channel; + u16 new_channel = le16_to_cpu(rf_channel->current_channel); + + if (priv->curr_bss_params.bss_descriptor.channel != new_channel) { + dev_dbg(priv->adapter->dev, "cmd: Channel Switch: %d to %d\n", + priv->curr_bss_params.bss_descriptor.channel, + new_channel); + /* Update the channel again */ + priv->curr_bss_params.bss_descriptor.channel = new_channel; + } + if (data_buf) + *((u16 *)data_buf) = new_channel; + + return 0; +} + +/* + * This function handles the command response of get extended version. + * + * Handling includes forming the extended version string and sending it + * to application. + */ +static int mwifiex_ret_ver_ext(struct mwifiex_private *priv, + struct host_cmd_ds_command *resp, + void *data_buf) +{ + struct host_cmd_ds_version_ext *ver_ext = &resp->params.verext; + struct host_cmd_ds_version_ext *version_ext = NULL; + + if (data_buf) { + version_ext = (struct host_cmd_ds_version_ext *)data_buf; + version_ext->version_str_sel = ver_ext->version_str_sel; + memcpy(version_ext->version_str, ver_ext->version_str, + sizeof(char) * 128); + memcpy(priv->version_str, ver_ext->version_str, 128); + } + return 0; +} + +/* + * This function handles the command response of register access. + * + * The register value and offset are returned to the user. For EEPROM + * access, the byte count is also returned. + */ +static int mwifiex_ret_reg_access(u16 type, struct host_cmd_ds_command *resp, + void *data_buf) +{ + struct mwifiex_ds_reg_rw *reg_rw = NULL; + struct mwifiex_ds_read_eeprom *eeprom = NULL; + + if (data_buf) { + reg_rw = (struct mwifiex_ds_reg_rw *) data_buf; + eeprom = (struct mwifiex_ds_read_eeprom *) data_buf; + switch (type) { + case HostCmd_CMD_MAC_REG_ACCESS: + { + struct host_cmd_ds_mac_reg_access *reg; + reg = (struct host_cmd_ds_mac_reg_access *) + &resp->params.mac_reg; + reg_rw->offset = cpu_to_le32( + (u32) le16_to_cpu(reg->offset)); + reg_rw->value = reg->value; + break; + } + case HostCmd_CMD_BBP_REG_ACCESS: + { + struct host_cmd_ds_bbp_reg_access *reg; + reg = (struct host_cmd_ds_bbp_reg_access *) + &resp->params.bbp_reg; + reg_rw->offset = cpu_to_le32( + (u32) le16_to_cpu(reg->offset)); + reg_rw->value = cpu_to_le32((u32) reg->value); + break; + } + + case HostCmd_CMD_RF_REG_ACCESS: + { + struct host_cmd_ds_rf_reg_access *reg; + reg = (struct host_cmd_ds_rf_reg_access *) + &resp->params.rf_reg; + reg_rw->offset = cpu_to_le32( + (u32) le16_to_cpu(reg->offset)); + reg_rw->value = cpu_to_le32((u32) reg->value); + break; + } + case HostCmd_CMD_PMIC_REG_ACCESS: + { + struct host_cmd_ds_pmic_reg_access *reg; + reg = (struct host_cmd_ds_pmic_reg_access *) + &resp->params.pmic_reg; + reg_rw->offset = cpu_to_le32( + (u32) le16_to_cpu(reg->offset)); + reg_rw->value = cpu_to_le32((u32) reg->value); + break; + } + case HostCmd_CMD_CAU_REG_ACCESS: + { + struct host_cmd_ds_rf_reg_access *reg; + reg = (struct host_cmd_ds_rf_reg_access *) + &resp->params.rf_reg; + reg_rw->offset = cpu_to_le32( + (u32) le16_to_cpu(reg->offset)); + reg_rw->value = cpu_to_le32((u32) reg->value); + break; + } + case HostCmd_CMD_802_11_EEPROM_ACCESS: + { + struct host_cmd_ds_802_11_eeprom_access + *cmd_eeprom = + (struct host_cmd_ds_802_11_eeprom_access + *) &resp->params.eeprom; + pr_debug("info: EEPROM read len=%x\n", + cmd_eeprom->byte_count); + if (le16_to_cpu(eeprom->byte_count) < + le16_to_cpu( + cmd_eeprom->byte_count)) { + eeprom->byte_count = cpu_to_le16(0); + pr_debug("info: EEPROM read " + "length is too big\n"); + return -1; + } + eeprom->offset = cmd_eeprom->offset; + eeprom->byte_count = cmd_eeprom->byte_count; + if (le16_to_cpu(eeprom->byte_count) > 0) + memcpy(&eeprom->value, + &cmd_eeprom->value, + le16_to_cpu(eeprom->byte_count)); + + break; + } + default: + return -1; + } + } + return 0; +} + +/* + * This function handles the command response of get IBSS coalescing status. + * + * If the received BSSID is different than the current one, the current BSSID, + * beacon interval, ATIM window and ERP information are updated, along with + * changing the ad-hoc state accordingly. + */ +static int mwifiex_ret_ibss_coalescing_status(struct mwifiex_private *priv, + struct host_cmd_ds_command *resp) +{ + struct host_cmd_ds_802_11_ibss_status *ibss_coal_resp = + &(resp->params.ibss_coalescing); + u8 zero_mac[ETH_ALEN] = { 0, 0, 0, 0, 0, 0 }; + + if (le16_to_cpu(ibss_coal_resp->action) == HostCmd_ACT_GEN_SET) + return 0; + + dev_dbg(priv->adapter->dev, + "info: new BSSID %pM\n", ibss_coal_resp->bssid); + + /* If rsp has NULL BSSID, Just return..... No Action */ + if (!memcmp(ibss_coal_resp->bssid, zero_mac, ETH_ALEN)) { + dev_warn(priv->adapter->dev, "new BSSID is NULL\n"); + return 0; + } + + /* If BSSID is diff, modify current BSS parameters */ + if (memcmp(priv->curr_bss_params.bss_descriptor.mac_address, + ibss_coal_resp->bssid, ETH_ALEN)) { + /* BSSID */ + memcpy(priv->curr_bss_params.bss_descriptor.mac_address, + ibss_coal_resp->bssid, ETH_ALEN); + + /* Beacon Interval */ + priv->curr_bss_params.bss_descriptor.beacon_period + = le16_to_cpu(ibss_coal_resp->beacon_interval); + + /* ERP Information */ + priv->curr_bss_params.bss_descriptor.erp_flags = + (u8) le16_to_cpu(ibss_coal_resp->use_g_rate_protect); + + priv->adhoc_state = ADHOC_COALESCED; + } + + return 0; +} + +/* + * This function handles the command responses. + * + * This is a generic function, which calls command specific + * response handlers based on the command ID. + */ +int mwifiex_process_sta_cmdresp(struct mwifiex_private *priv, + u16 cmdresp_no, void *cmd_buf, void *wq_buf) +{ + int ret = 0; + struct mwifiex_adapter *adapter = priv->adapter; + struct host_cmd_ds_command *resp = + (struct host_cmd_ds_command *) cmd_buf; + struct mwifiex_wait_queue *wait_queue = + (struct mwifiex_wait_queue *) wq_buf; + void *data_buf = adapter->curr_cmd->data_buf; + + /* If the command is not successful, cleanup and return failure */ + if (resp->result != HostCmd_RESULT_OK) { + mwifiex_process_cmdresp_error(priv, resp, wait_queue); + return -1; + } + /* Command successful, handle response */ + switch (cmdresp_no) { + case HostCmd_CMD_GET_HW_SPEC: + ret = mwifiex_ret_get_hw_spec(priv, resp); + break; + case HostCmd_CMD_MAC_CONTROL: + break; + case HostCmd_CMD_802_11_MAC_ADDRESS: + ret = mwifiex_ret_802_11_mac_address(priv, resp); + break; + case HostCmd_CMD_MAC_MULTICAST_ADR: + ret = mwifiex_ret_mac_multicast_adr(priv, resp); + break; + case HostCmd_CMD_TX_RATE_CFG: + ret = mwifiex_ret_tx_rate_cfg(priv, resp, data_buf); + break; + case HostCmd_CMD_802_11_SCAN: + ret = mwifiex_ret_802_11_scan(priv, resp, wait_queue); + wait_queue = NULL; + adapter->curr_cmd->wq_buf = NULL; + break; + case HostCmd_CMD_802_11_BG_SCAN_QUERY: + ret = mwifiex_ret_802_11_scan(priv, resp, wait_queue); + dev_dbg(adapter->dev, + "info: CMD_RESP: BG_SCAN result is ready!\n"); + break; + case HostCmd_CMD_TXPWR_CFG: + ret = mwifiex_ret_tx_power_cfg(priv, resp, data_buf); + break; + case HostCmd_CMD_802_11_PS_MODE_ENH: + ret = mwifiex_ret_enh_power_mode(priv, resp, data_buf); + break; + case HostCmd_CMD_802_11_HS_CFG_ENH: + ret = mwifiex_ret_802_11_hs_cfg(priv, resp); + break; + case HostCmd_CMD_802_11_ASSOCIATE: + ret = mwifiex_ret_802_11_associate(priv, resp, wait_queue); + break; + case HostCmd_CMD_802_11_DEAUTHENTICATE: + ret = mwifiex_ret_802_11_deauthenticate(priv, resp); + break; + case HostCmd_CMD_802_11_AD_HOC_START: + case HostCmd_CMD_802_11_AD_HOC_JOIN: + ret = mwifiex_ret_802_11_ad_hoc(priv, resp, wait_queue); + break; + case HostCmd_CMD_802_11_AD_HOC_STOP: + ret = mwifiex_ret_802_11_ad_hoc_stop(priv, resp); + break; + case HostCmd_CMD_802_11_GET_LOG: + ret = mwifiex_ret_get_log(priv, resp, data_buf); + break; + case HostCmd_CMD_RSSI_INFO: + ret = mwifiex_ret_802_11_rssi_info(priv, resp, data_buf); + break; + case HostCmd_CMD_802_11_SNMP_MIB: + ret = mwifiex_ret_802_11_snmp_mib(priv, resp, data_buf); + break; + case HostCmd_CMD_802_11_TX_RATE_QUERY: + ret = mwifiex_ret_802_11_tx_rate_query(priv, resp); + break; + case HostCmd_CMD_802_11_RF_CHANNEL: + ret = mwifiex_ret_802_11_rf_channel(priv, resp, data_buf); + break; + case HostCmd_CMD_VERSION_EXT: + ret = mwifiex_ret_ver_ext(priv, resp, data_buf); + break; + case HostCmd_CMD_FUNC_INIT: + case HostCmd_CMD_FUNC_SHUTDOWN: + break; + case HostCmd_CMD_802_11_KEY_MATERIAL: + ret = mwifiex_ret_802_11_key_material(priv, resp); + break; + case HostCmd_CMD_802_11D_DOMAIN_INFO: + ret = mwifiex_ret_802_11d_domain_info(priv, resp); + break; + case HostCmd_CMD_11N_ADDBA_REQ: + ret = mwifiex_ret_11n_addba_req(priv, resp); + break; + case HostCmd_CMD_11N_DELBA: + ret = mwifiex_ret_11n_delba(priv, resp); + break; + case HostCmd_CMD_11N_ADDBA_RSP: + ret = mwifiex_ret_11n_addba_resp(priv, resp); + break; + case HostCmd_CMD_RECONFIGURE_TX_BUFF: + adapter->tx_buf_size = (u16) le16_to_cpu(resp->params. + tx_buf.buff_size); + adapter->tx_buf_size = (adapter->tx_buf_size / + MWIFIEX_SDIO_BLOCK_SIZE) * + MWIFIEX_SDIO_BLOCK_SIZE; + adapter->curr_tx_buf_size = adapter->tx_buf_size; + dev_dbg(adapter->dev, + "cmd: max_tx_buf_size=%d, tx_buf_size=%d\n", + adapter->max_tx_buf_size, adapter->tx_buf_size); + + if (adapter->if_ops.update_mp_end_port) + adapter->if_ops.update_mp_end_port(adapter, + le16_to_cpu(resp-> + params. + tx_buf. + mp_end_port)); + break; + case HostCmd_CMD_AMSDU_AGGR_CTRL: + ret = mwifiex_ret_amsdu_aggr_ctrl(priv, resp, data_buf); + break; + case HostCmd_CMD_WMM_GET_STATUS: + ret = mwifiex_ret_wmm_get_status(priv, resp); + break; + case HostCmd_CMD_802_11_IBSS_COALESCING_STATUS: + ret = mwifiex_ret_ibss_coalescing_status(priv, resp); + break; + case HostCmd_CMD_MAC_REG_ACCESS: + case HostCmd_CMD_BBP_REG_ACCESS: + case HostCmd_CMD_RF_REG_ACCESS: + case HostCmd_CMD_PMIC_REG_ACCESS: + case HostCmd_CMD_CAU_REG_ACCESS: + case HostCmd_CMD_802_11_EEPROM_ACCESS: + ret = mwifiex_ret_reg_access(cmdresp_no, resp, data_buf); + break; + case HostCmd_CMD_SET_BSS_MODE: + break; + case HostCmd_CMD_11N_CFG: + ret = mwifiex_ret_11n_cfg(priv, resp, data_buf); + break; + default: + dev_err(adapter->dev, "CMD_RESP: unknown cmd response %#x\n", + resp->command); + break; + } + + return ret; +} diff --git a/drivers/net/wireless/mwifiex/sta_event.c b/drivers/net/wireless/mwifiex/sta_event.c new file mode 100644 index 0000000..d4a5c1f --- /dev/null +++ b/drivers/net/wireless/mwifiex/sta_event.c @@ -0,0 +1,405 @@ +/* + * Marvell Wireless LAN device driver: station event handling + * + * Copyright (C) 2011, Marvell International Ltd. + * + * This software file (the "File") is distributed by Marvell International + * Ltd. under the terms of the GNU General Public License Version 2, June 1991 + * (the "License"). You may use, redistribute and/or modify this File in + * accordance with the terms and conditions of the License, a copy of which + * is available by writing to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the + * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. + * + * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE + * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE + * ARE EXPRESSLY DISCLAIMED. The License provides additional details about + * this warranty disclaimer. + */ + +#include "decl.h" +#include "ioctl.h" +#include "util.h" +#include "fw.h" +#include "main.h" +#include "wmm.h" +#include "11n.h" + +/* + * This function resets the connection state. + * + * The function is invoked after receiving a disconnect event from firmware, + * and performs the following actions - + * - Set media status to disconnected + * - Clean up Tx and Rx packets + * - Resets SNR/NF/RSSI value in driver + * - Resets security configurations in driver + * - Enables auto data rate + * - Saves the previous SSID and BSSID so that they can + * be used for re-association, if required + * - Erases current SSID and BSSID information + * - Sends a disconnect event to upper layers/applications. + */ +void +mwifiex_reset_connect_state(struct mwifiex_private *priv) +{ + struct mwifiex_adapter *adapter = priv->adapter; + + if (!priv->media_connected) + return; + + dev_dbg(adapter->dev, "info: handles disconnect event\n"); + + priv->media_connected = false; + + priv->scan_block = false; + + /* Free Tx and Rx packets, report disconnect to upper layer */ + mwifiex_clean_txrx(priv); + + /* Reset SNR/NF/RSSI values */ + priv->data_rssi_last = 0; + priv->data_nf_last = 0; + priv->data_rssi_avg = 0; + priv->data_nf_avg = 0; + priv->bcn_rssi_last = 0; + priv->bcn_nf_last = 0; + priv->bcn_rssi_avg = 0; + priv->bcn_nf_avg = 0; + priv->rxpd_rate = 0; + priv->rxpd_htinfo = 0; + priv->sec_info.wpa_enabled = false; + priv->sec_info.wpa2_enabled = false; + priv->wpa_ie_len = 0; + + priv->sec_info.wapi_enabled = false; + priv->wapi_ie_len = 0; + priv->sec_info.wapi_key_on = false; + + priv->sec_info.encryption_mode = MWIFIEX_ENCRYPTION_MODE_NONE; + + /* Enable auto data rate */ + priv->is_data_rate_auto = true; + priv->data_rate = 0; + + if (priv->bss_mode == MWIFIEX_BSS_MODE_IBSS) { + priv->adhoc_state = ADHOC_IDLE; + priv->adhoc_is_link_sensed = false; + } + + /* + * Memorize the previous SSID and BSSID so + * it could be used for re-assoc + */ + + dev_dbg(adapter->dev, "info: previous SSID=%s, SSID len=%u\n", + priv->prev_ssid.ssid, priv->prev_ssid.ssid_len); + + dev_dbg(adapter->dev, "info: current SSID=%s, SSID len=%u\n", + priv->curr_bss_params.bss_descriptor.ssid.ssid, + priv->curr_bss_params.bss_descriptor.ssid.ssid_len); + + memcpy(&priv->prev_ssid, + &priv->curr_bss_params.bss_descriptor.ssid, + sizeof(struct mwifiex_802_11_ssid)); + + memcpy(priv->prev_bssid, + priv->curr_bss_params.bss_descriptor.mac_address, ETH_ALEN); + + /* Need to erase the current SSID and BSSID info */ + memset(&priv->curr_bss_params, 0x00, sizeof(priv->curr_bss_params)); + + adapter->tx_lock_flag = false; + adapter->pps_uapsd_mode = false; + + if (adapter->num_cmd_timeout && adapter->curr_cmd) + return; + priv->media_connected = false; + if (!priv->disconnect) { + priv->disconnect = 1; + dev_dbg(adapter->dev, "info: successfully disconnected from" + " %pM: reason code %d\n", priv->cfg_bssid, + WLAN_REASON_DEAUTH_LEAVING); + cfg80211_disconnected(priv->netdev, + WLAN_REASON_DEAUTH_LEAVING, NULL, 0, + GFP_KERNEL); + queue_work(priv->workqueue, &priv->cfg_workqueue); + } + if (!netif_queue_stopped(priv->netdev)) + netif_stop_queue(priv->netdev); + if (netif_carrier_ok(priv->netdev)) + netif_carrier_off(priv->netdev); + /* Reset wireless stats signal info */ + priv->w_stats.qual.level = 0; + priv->w_stats.qual.noise = 0; +} + +/* + * This function handles events generated by firmware. + * + * This is a generic function and handles all events. + * + * Event specific routines are called by this function based + * upon the generated event cause. + * + * For the following events, the function just forwards them to upper + * layers, optionally recording the change - + * - EVENT_LINK_SENSED + * - EVENT_MIC_ERR_UNICAST + * - EVENT_MIC_ERR_MULTICAST + * - EVENT_PORT_RELEASE + * - EVENT_RSSI_LOW + * - EVENT_SNR_LOW + * - EVENT_MAX_FAIL + * - EVENT_RSSI_HIGH + * - EVENT_SNR_HIGH + * - EVENT_DATA_RSSI_LOW + * - EVENT_DATA_SNR_LOW + * - EVENT_DATA_RSSI_HIGH + * - EVENT_DATA_SNR_HIGH + * - EVENT_LINK_QUALITY + * - EVENT_PRE_BEACON_LOST + * - EVENT_IBSS_COALESCED + * - EVENT_WEP_ICV_ERR + * - EVENT_BW_CHANGE + * - EVENT_HOSTWAKE_STAIE + * + * For the following events, no action is taken - + * - EVENT_MIB_CHANGED + * - EVENT_INIT_DONE + * - EVENT_DUMMY_HOST_WAKEUP_SIGNAL + * + * Rest of the supported events requires driver handling - + * - EVENT_DEAUTHENTICATED + * - EVENT_DISASSOCIATED + * - EVENT_LINK_LOST + * - EVENT_PS_SLEEP + * - EVENT_PS_AWAKE + * - EVENT_DEEP_SLEEP_AWAKE + * - EVENT_HS_ACT_REQ + * - EVENT_ADHOC_BCN_LOST + * - EVENT_BG_SCAN_REPORT + * - EVENT_WMM_STATUS_CHANGE + * - EVENT_ADDBA + * - EVENT_DELBA + * - EVENT_BA_STREAM_TIEMOUT + * - EVENT_AMSDU_AGGR_CTRL + */ +int mwifiex_process_sta_event(struct mwifiex_private *priv) +{ + struct mwifiex_adapter *adapter = priv->adapter; + int ret = 0; + u32 eventcause = adapter->event_cause; + + switch (eventcause) { + case EVENT_DUMMY_HOST_WAKEUP_SIGNAL: + dev_err(adapter->dev, "invalid EVENT: DUMMY_HOST_WAKEUP_SIGNAL," + " ignoring it\n"); + break; + case EVENT_LINK_SENSED: + dev_dbg(adapter->dev, "event: LINK_SENSED\n"); + if (!netif_carrier_ok(priv->netdev)) + netif_carrier_on(priv->netdev); + if (netif_queue_stopped(priv->netdev)) + netif_wake_queue(priv->netdev); + break; + + case EVENT_DEAUTHENTICATED: + dev_dbg(adapter->dev, "event: Deauthenticated\n"); + adapter->dbg.num_event_deauth++; + if (priv->media_connected) + mwifiex_reset_connect_state(priv); + break; + + case EVENT_DISASSOCIATED: + dev_dbg(adapter->dev, "event: Disassociated\n"); + adapter->dbg.num_event_disassoc++; + if (priv->media_connected) + mwifiex_reset_connect_state(priv); + break; + + case EVENT_LINK_LOST: + dev_dbg(adapter->dev, "event: Link lost\n"); + adapter->dbg.num_event_link_lost++; + if (priv->media_connected) + mwifiex_reset_connect_state(priv); + break; + + case EVENT_PS_SLEEP: + dev_dbg(adapter->dev, "info: EVENT: SLEEP\n"); + + adapter->ps_state = PS_STATE_PRE_SLEEP; + + mwifiex_check_ps_cond(adapter); + break; + + case EVENT_PS_AWAKE: + dev_dbg(adapter->dev, "info: EVENT: AWAKE\n"); + if (!adapter->pps_uapsd_mode && + priv->media_connected && + adapter->sleep_period.period) { + adapter->pps_uapsd_mode = true; + dev_dbg(adapter->dev, + "event: PPS/UAPSD mode activated\n"); + } + adapter->tx_lock_flag = false; + if (adapter->pps_uapsd_mode && adapter->gen_null_pkt) { + if (mwifiex_check_last_packet_indication(priv)) { + if (!adapter->data_sent) { + if (!mwifiex_send_null_packet(priv, + MWIFIEX_TxPD_POWER_MGMT_NULL_PACKET + | + MWIFIEX_TxPD_POWER_MGMT_LAST_PACKET)) + adapter->ps_state = + PS_STATE_SLEEP; + return 0; + } + } + } + adapter->ps_state = PS_STATE_AWAKE; + adapter->pm_wakeup_card_req = false; + adapter->pm_wakeup_fw_try = false; + + break; + + case EVENT_DEEP_SLEEP_AWAKE: + adapter->if_ops.wakeup_complete(adapter); + dev_dbg(adapter->dev, "event: DS_AWAKE\n"); + if (adapter->is_deep_sleep) + adapter->is_deep_sleep = false; + break; + + case EVENT_HS_ACT_REQ: + dev_dbg(adapter->dev, "event: HS_ACT_REQ\n"); + ret = mwifiex_prepare_cmd(priv, HostCmd_CMD_802_11_HS_CFG_ENH, + 0, 0, NULL, NULL); + break; + + case EVENT_MIC_ERR_UNICAST: + dev_dbg(adapter->dev, "event: UNICAST MIC ERROR\n"); + break; + + case EVENT_MIC_ERR_MULTICAST: + dev_dbg(adapter->dev, "event: MULTICAST MIC ERROR\n"); + break; + case EVENT_MIB_CHANGED: + case EVENT_INIT_DONE: + break; + + case EVENT_ADHOC_BCN_LOST: + dev_dbg(adapter->dev, "event: ADHOC_BCN_LOST\n"); + priv->adhoc_is_link_sensed = false; + mwifiex_clean_txrx(priv); + if (!netif_queue_stopped(priv->netdev)) + netif_stop_queue(priv->netdev); + if (netif_carrier_ok(priv->netdev)) + netif_carrier_off(priv->netdev); + break; + + case EVENT_BG_SCAN_REPORT: + dev_dbg(adapter->dev, "event: BGS_REPORT\n"); + /* Clear the previous scan result */ + memset(adapter->scan_table, 0x00, + sizeof(struct mwifiex_bssdescriptor) * IW_MAX_AP); + adapter->num_in_scan_table = 0; + adapter->bcn_buf_end = adapter->bcn_buf; + ret = mwifiex_prepare_cmd(priv, + HostCmd_CMD_802_11_BG_SCAN_QUERY, + HostCmd_ACT_GEN_GET, 0, NULL, NULL); + break; + + case EVENT_PORT_RELEASE: + dev_dbg(adapter->dev, "event: PORT RELEASE\n"); + break; + + case EVENT_WMM_STATUS_CHANGE: + dev_dbg(adapter->dev, "event: WMM status changed\n"); + ret = mwifiex_prepare_cmd(priv, HostCmd_CMD_WMM_GET_STATUS, + 0, 0, NULL, NULL); + break; + + case EVENT_RSSI_LOW: + dev_dbg(adapter->dev, "event: Beacon RSSI_LOW\n"); + break; + case EVENT_SNR_LOW: + dev_dbg(adapter->dev, "event: Beacon SNR_LOW\n"); + break; + case EVENT_MAX_FAIL: + dev_dbg(adapter->dev, "event: MAX_FAIL\n"); + break; + case EVENT_RSSI_HIGH: + dev_dbg(adapter->dev, "event: Beacon RSSI_HIGH\n"); + break; + case EVENT_SNR_HIGH: + dev_dbg(adapter->dev, "event: Beacon SNR_HIGH\n"); + break; + case EVENT_DATA_RSSI_LOW: + dev_dbg(adapter->dev, "event: Data RSSI_LOW\n"); + break; + case EVENT_DATA_SNR_LOW: + dev_dbg(adapter->dev, "event: Data SNR_LOW\n"); + break; + case EVENT_DATA_RSSI_HIGH: + dev_dbg(adapter->dev, "event: Data RSSI_HIGH\n"); + break; + case EVENT_DATA_SNR_HIGH: + dev_dbg(adapter->dev, "event: Data SNR_HIGH\n"); + break; + case EVENT_LINK_QUALITY: + dev_dbg(adapter->dev, "event: Link Quality\n"); + break; + case EVENT_PRE_BEACON_LOST: + dev_dbg(adapter->dev, "event: Pre-Beacon Lost\n"); + break; + case EVENT_IBSS_COALESCED: + dev_dbg(adapter->dev, "event: IBSS_COALESCED\n"); + ret = mwifiex_prepare_cmd(priv, + HostCmd_CMD_802_11_IBSS_COALESCING_STATUS, + HostCmd_ACT_GEN_GET, 0, NULL, NULL); + break; + case EVENT_ADDBA: + dev_dbg(adapter->dev, "event: ADDBA Request\n"); + mwifiex_prepare_cmd(priv, HostCmd_CMD_11N_ADDBA_RSP, + HostCmd_ACT_GEN_SET, 0, NULL, + adapter->event_body); + break; + case EVENT_DELBA: + dev_dbg(adapter->dev, "event: DELBA Request\n"); + mwifiex_11n_delete_ba_stream(priv, adapter->event_body); + break; + case EVENT_BA_STREAM_TIEMOUT: + dev_dbg(adapter->dev, "event: BA Stream timeout\n"); + mwifiex_11n_ba_stream_timeout(priv, + (struct host_cmd_ds_11n_batimeout + *) + adapter->event_body); + break; + case EVENT_AMSDU_AGGR_CTRL: + dev_dbg(adapter->dev, "event: AMSDU_AGGR_CTRL %d\n", + *(u16 *) adapter->event_body); + adapter->tx_buf_size = + min(adapter->curr_tx_buf_size, + le16_to_cpu(*(__le16 *) adapter->event_body)); + dev_dbg(adapter->dev, "event: tx_buf_size %d\n", + adapter->tx_buf_size); + break; + + case EVENT_WEP_ICV_ERR: + dev_dbg(adapter->dev, "event: WEP ICV error\n"); + break; + + case EVENT_BW_CHANGE: + dev_dbg(adapter->dev, "event: BW Change\n"); + break; + + case EVENT_HOSTWAKE_STAIE: + dev_dbg(adapter->dev, "event: HOSTWAKE_STAIE %d\n", eventcause); + break; + default: + dev_dbg(adapter->dev, "event: unknown event id: %#x\n", + eventcause); + break; + } + + return ret; +} diff --git a/drivers/net/wireless/mwifiex/sta_ioctl.c b/drivers/net/wireless/mwifiex/sta_ioctl.c new file mode 100644 index 0000000..665a519 --- /dev/null +++ b/drivers/net/wireless/mwifiex/sta_ioctl.c @@ -0,0 +1,2478 @@ +/* + * Marvell Wireless LAN device driver: functions for station ioctl + * + * Copyright (C) 2011, Marvell International Ltd. + * + * This software file (the "File") is distributed by Marvell International + * Ltd. under the terms of the GNU General Public License Version 2, June 1991 + * (the "License"). You may use, redistribute and/or modify this File in + * accordance with the terms and conditions of the License, a copy of which + * is available by writing to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the + * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. + * + * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE + * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE + * ARE EXPRESSLY DISCLAIMED. The License provides additional details about + * this warranty disclaimer. + */ + +#include "decl.h" +#include "ioctl.h" +#include "util.h" +#include "fw.h" +#include "main.h" +#include "wmm.h" +#include "11n.h" +#include "cfg80211.h" + +/* + * Copies the multicast address list from device to driver. + * + * This function does not validate the destination memory for + * size, and the calling function must ensure enough memory is + * available. + */ +static int +mwifiex_copy_mcast_addr(struct mwifiex_multicast_list *mlist, + struct net_device *dev) +{ + int i = 0; + struct netdev_hw_addr *ha; + + netdev_for_each_mc_addr(ha, dev) + memcpy(&mlist->mac_list[i++], ha->addr, ETH_ALEN); + + return i; +} + +/* + * Allocate and fills a wait queue with proper parameters. + * + * This function needs to be called before an IOCTL request can be made. + * It can handle the following wait options: + * MWIFIEX_NO_WAIT - Waiting is disabled + * MWIFIEX_IOCTL_WAIT - Waiting is done on IOCTL wait queue + * MWIFIEX_CMD_WAIT - Waiting is done on command wait queue + * MWIFIEX_WSTATS_WAIT - Waiting is done on stats wait queue + */ +struct mwifiex_wait_queue * +mwifiex_alloc_fill_wait_queue(struct mwifiex_private *priv, + u8 wait_option) +{ + struct mwifiex_wait_queue *wait = NULL; + + wait = (struct mwifiex_wait_queue *) + kzalloc(sizeof(struct mwifiex_wait_queue), GFP_ATOMIC); + if (!wait) { + dev_err(priv->adapter->dev, "%s: fail to alloc buffer\n", + __func__); + return wait; + } + + wait->bss_index = priv->bss_index; + + switch (wait_option) { + case MWIFIEX_NO_WAIT: + wait->enabled = 0; + break; + case MWIFIEX_IOCTL_WAIT: + priv->ioctl_wait_q_woken = false; + wait->start_time = jiffies; + wait->wait = &priv->ioctl_wait_q; + wait->condition = &priv->ioctl_wait_q_woken; + wait->enabled = 1; + break; + case MWIFIEX_CMD_WAIT: + priv->cmd_wait_q_woken = false; + wait->start_time = jiffies; + wait->wait = &priv->cmd_wait_q; + wait->condition = &priv->cmd_wait_q_woken; + wait->enabled = 1; + break; + case MWIFIEX_WSTATS_WAIT: + priv->w_stats_wait_q_woken = false; + wait->start_time = jiffies; + wait->wait = &priv->w_stats_wait_q; + wait->condition = &priv->w_stats_wait_q_woken; + wait->enabled = 1; + break; + } + + return wait; +} + +/* + * Wait queue completion handler. + * + * This function waits on a particular wait queue. + * For NO_WAIT option, it returns immediately. It also cancels the + * pending IOCTL request after waking up, in case of errors. + */ +static void +mwifiex_wait_ioctl_complete(struct mwifiex_private *priv, + struct mwifiex_wait_queue *wait, + u8 wait_option) +{ + bool cancel_flag = false; + + switch (wait_option) { + case MWIFIEX_NO_WAIT: + break; + case MWIFIEX_IOCTL_WAIT: + wait_event_interruptible(priv->ioctl_wait_q, + priv->ioctl_wait_q_woken); + if (!priv->ioctl_wait_q_woken) + cancel_flag = true; + break; + case MWIFIEX_CMD_WAIT: + wait_event_interruptible(priv->cmd_wait_q, + priv->cmd_wait_q_woken); + if (!priv->cmd_wait_q_woken) + cancel_flag = true; + break; + case MWIFIEX_WSTATS_WAIT: + wait_event_interruptible(priv->w_stats_wait_q, + priv->w_stats_wait_q_woken); + if (!priv->w_stats_wait_q_woken) + cancel_flag = true; + break; + } + if (cancel_flag) { + mwifiex_cancel_pending_ioctl(priv->adapter, wait); + dev_dbg(priv->adapter->dev, "cmd: IOCTL cancel: wait=%p, wait_option=%d\n", + wait, wait_option); + } + + return; +} + +/* + * The function waits for the request to complete and issues the + * completion handler, if required. + */ +int mwifiex_request_ioctl(struct mwifiex_private *priv, + struct mwifiex_wait_queue *wait, + int status, u8 wait_option) +{ + switch (status) { + case -EINPROGRESS: + dev_dbg(priv->adapter->dev, "cmd: IOCTL pending: wait=%p, wait_option=%d\n", + wait, wait_option); + atomic_inc(&priv->adapter->ioctl_pending); + /* Status pending, wake up main process */ + queue_work(priv->adapter->workqueue, &priv->adapter->main_work); + + /* Wait for completion */ + if (wait_option) { + mwifiex_wait_ioctl_complete(priv, wait, wait_option); + status = wait->status; + } + break; + case 0: + case -1: + case -EBUSY: + default: + break; + } + return status; +} +EXPORT_SYMBOL_GPL(mwifiex_request_ioctl); + +/* + * IOCTL request handler to set/get MAC address. + * + * This function prepares the correct firmware command and + * issues it to get the extended version information. + */ +static int mwifiex_bss_ioctl_mac_address(struct mwifiex_private *priv, + struct mwifiex_wait_queue *wait, + u8 action, u8 *mac) +{ + int ret = 0; + + if ((action == HostCmd_ACT_GEN_GET) && mac) { + memcpy(mac, priv->curr_addr, ETH_ALEN); + return 0; + } + + /* Send request to firmware */ + ret = mwifiex_prepare_cmd(priv, HostCmd_CMD_802_11_MAC_ADDRESS, + action, 0, wait, mac); + if (!ret) + ret = -EINPROGRESS; + + return ret; +} + +/* + * Sends IOCTL request to set MAC address. + * + * This function allocates the IOCTL request buffer, fills it + * with requisite parameters and calls the IOCTL handler. + */ +int mwifiex_request_set_mac_address(struct mwifiex_private *priv) +{ + struct mwifiex_wait_queue *wait = NULL; + int status = 0; + u8 wait_option = MWIFIEX_CMD_WAIT; + + /* Allocate wait buffer */ + wait = mwifiex_alloc_fill_wait_queue(priv, wait_option); + if (!wait) + return -ENOMEM; + + status = mwifiex_bss_ioctl_mac_address(priv, wait, HostCmd_ACT_GEN_SET, + NULL); + + status = mwifiex_request_ioctl(priv, wait, status, wait_option); + if (!status) + memcpy(priv->netdev->dev_addr, priv->curr_addr, ETH_ALEN); + else + dev_err(priv->adapter->dev, "set mac address failed: status=%d" + " error_code=%#x\n", status, wait->status); + + kfree(wait); + return status; +} + +/* + * IOCTL request handler to set multicast list. + * + * This function prepares the correct firmware command and + * issues it to set the multicast list. + * + * This function can be used to enable promiscuous mode, or enable all + * multicast packets, or to enable selective multicast. + */ +static int +mwifiex_bss_ioctl_multicast_list(struct mwifiex_private *priv, + struct mwifiex_wait_queue *wait, + u16 action, + struct mwifiex_multicast_list *mcast_list) +{ + int ret = 0; + u16 old_pkt_filter; + + old_pkt_filter = priv->curr_pkt_filter; + if (action == HostCmd_ACT_GEN_GET) + return -1; + + if (mcast_list->mode == MWIFIEX_PROMISC_MODE) { + dev_dbg(priv->adapter->dev, "info: Enable Promiscuous mode\n"); + priv->curr_pkt_filter |= HostCmd_ACT_MAC_PROMISCUOUS_ENABLE; + priv->curr_pkt_filter &= + ~HostCmd_ACT_MAC_ALL_MULTICAST_ENABLE; + } else { + /* Multicast */ + priv->curr_pkt_filter &= ~HostCmd_ACT_MAC_PROMISCUOUS_ENABLE; + if (mcast_list->mode == MWIFIEX_MULTICAST_MODE) { + dev_dbg(priv->adapter->dev, + "info: Enabling All Multicast!\n"); + priv->curr_pkt_filter |= + HostCmd_ACT_MAC_ALL_MULTICAST_ENABLE; + } else { + priv->curr_pkt_filter &= + ~HostCmd_ACT_MAC_ALL_MULTICAST_ENABLE; + if (mcast_list->num_multicast_addr) { + dev_dbg(priv->adapter->dev, + "info: Set multicast list=%d\n", + mcast_list->num_multicast_addr); + /* Set multicast addresses to firmware */ + if (old_pkt_filter == priv->curr_pkt_filter) { + /* Send request to firmware */ + ret = mwifiex_prepare_cmd(priv, + HostCmd_CMD_MAC_MULTICAST_ADR, + action, 0, wait, mcast_list); + if (!ret) + ret = -EINPROGRESS; + } else { + /* Send request to firmware */ + ret = mwifiex_prepare_cmd(priv, + HostCmd_CMD_MAC_MULTICAST_ADR, + action, 0, NULL, + mcast_list); + } + } + } + } + dev_dbg(priv->adapter->dev, + "info: old_pkt_filter=%#x, curr_pkt_filter=%#x\n", + old_pkt_filter, priv->curr_pkt_filter); + if (old_pkt_filter != priv->curr_pkt_filter) { + ret = mwifiex_prepare_cmd(priv, HostCmd_CMD_MAC_CONTROL, action, + 0, wait, &priv->curr_pkt_filter); + if (!ret) + ret = -EINPROGRESS; + } + + return ret; +} + +/* + * Sends IOCTL request to set multicast list. + * + * This function allocates the IOCTL request buffer, fills it + * with requisite parameters and calls the IOCTL handler. + */ +void +mwifiex_request_set_multicast_list(struct mwifiex_private *priv, + struct net_device *dev) +{ + struct mwifiex_wait_queue *wait = NULL; + struct mwifiex_multicast_list mcast_list; + u8 wait_option = MWIFIEX_NO_WAIT; + int status = 0; + + /* Allocate wait buffer */ + wait = mwifiex_alloc_fill_wait_queue(priv, wait_option); + if (!wait) + return; + + if (dev->flags & IFF_PROMISC) { + mcast_list.mode = MWIFIEX_PROMISC_MODE; + } else if (dev->flags & IFF_ALLMULTI || + netdev_mc_count(dev) > MWIFIEX_MAX_MULTICAST_LIST_SIZE) { + mcast_list.mode = MWIFIEX_ALL_MULTI_MODE; + } else { + mcast_list.mode = MWIFIEX_MULTICAST_MODE; + if (netdev_mc_count(dev)) + mcast_list.num_multicast_addr = + mwifiex_copy_mcast_addr(&mcast_list, dev); + } + status = mwifiex_bss_ioctl_multicast_list(priv, wait, + HostCmd_ACT_GEN_SET, + &mcast_list); + + status = mwifiex_request_ioctl(priv, wait, status, wait_option); + if (wait && status != -EINPROGRESS) + kfree(wait); + + return; +} + +/* + * IOCTL request handler to disconnect from a BSS/IBSS. + */ +static int mwifiex_bss_ioctl_stop(struct mwifiex_private *priv, + struct mwifiex_wait_queue *wait, u8 *mac) +{ + return mwifiex_deauthenticate(priv, wait, mac); +} + +/* + * Sends IOCTL request to disconnect from a BSS. + * + * This function allocates the IOCTL request buffer, fills it + * with requisite parameters and calls the IOCTL handler. + */ +int mwifiex_disconnect(struct mwifiex_private *priv, u8 wait_option, u8 *mac) +{ + struct mwifiex_wait_queue *wait = NULL; + int status = 0; + + /* Allocate wait buffer */ + wait = mwifiex_alloc_fill_wait_queue(priv, wait_option); + if (!wait) + return -ENOMEM; + + status = mwifiex_bss_ioctl_stop(priv, wait, mac); + + status = mwifiex_request_ioctl(priv, wait, status, wait_option); + + kfree(wait); + return status; +} +EXPORT_SYMBOL_GPL(mwifiex_disconnect); + +/* + * IOCTL request handler to join a BSS/IBSS. + * + * In Ad-Hoc mode, the IBSS is created if not found in scan list. + * In both Ad-Hoc and infra mode, an deauthentication is performed + * first. + */ +static int mwifiex_bss_ioctl_start(struct mwifiex_private *priv, + struct mwifiex_wait_queue *wait, + struct mwifiex_ssid_bssid *ssid_bssid) +{ + int ret = 0; + struct mwifiex_adapter *adapter = priv->adapter; + s32 i = -1; + + priv->scan_block = false; + if (!ssid_bssid) + return -1; + + if (priv->bss_mode == MWIFIEX_BSS_MODE_INFRA) { + /* Infra mode */ + ret = mwifiex_deauthenticate(priv, NULL, NULL); + if (ret) + return ret; + + /* Search for the requested SSID in the scan table */ + if (ssid_bssid->ssid.ssid_len) + i = mwifiex_find_ssid_in_list(priv, &ssid_bssid->ssid, + NULL, MWIFIEX_BSS_MODE_INFRA); + else + i = mwifiex_find_bssid_in_list(priv, + (u8 *) &ssid_bssid->bssid, + MWIFIEX_BSS_MODE_INFRA); + if (i < 0) + return -1; + + dev_dbg(adapter->dev, + "info: SSID found in scan list ... associating...\n"); + + /* Clear any past association response stored for + * application retrieval */ + priv->assoc_rsp_size = 0; + ret = mwifiex_associate(priv, wait, &adapter->scan_table[i]); + if (ret) + return ret; + } else { + /* Adhoc mode */ + /* If the requested SSID matches current SSID, return */ + if (ssid_bssid->ssid.ssid_len && + (!mwifiex_ssid_cmp + (&priv->curr_bss_params.bss_descriptor.ssid, + &ssid_bssid->ssid))) + return 0; + + /* Exit Adhoc mode first */ + dev_dbg(adapter->dev, "info: Sending Adhoc Stop\n"); + ret = mwifiex_deauthenticate(priv, NULL, NULL); + if (ret) + return ret; + + priv->adhoc_is_link_sensed = false; + + /* Search for the requested network in the scan table */ + if (ssid_bssid->ssid.ssid_len) + i = mwifiex_find_ssid_in_list(priv, + &ssid_bssid->ssid, NULL, + MWIFIEX_BSS_MODE_IBSS); + else + i = mwifiex_find_bssid_in_list(priv, + (u8 *)&ssid_bssid->bssid, + MWIFIEX_BSS_MODE_IBSS); + + if (i >= 0) { + dev_dbg(adapter->dev, "info: network found in scan" + " list. Joining...\n"); + ret = mwifiex_adhoc_join(priv, wait, + &adapter->scan_table[i]); + if (ret) + return ret; + } else { /* i >= 0 */ + dev_dbg(adapter->dev, "info: Network not found in " + "the list, creating adhoc with ssid = %s\n", + ssid_bssid->ssid.ssid); + ret = mwifiex_adhoc_start(priv, wait, + &ssid_bssid->ssid); + if (ret) + return ret; + } + } + + if (!ret) + ret = -EINPROGRESS; + + return ret; +} + +/* + * Sends IOCTL request to connect with a BSS. + * + * This function allocates the IOCTL request buffer, fills it + * with requisite parameters and calls the IOCTL handler. + */ +int mwifiex_bss_start(struct mwifiex_private *priv, u8 wait_option, + struct mwifiex_ssid_bssid *ssid_bssid) +{ + struct mwifiex_wait_queue *wait = NULL; + struct mwifiex_ssid_bssid tmp_ssid_bssid; + int status = 0; + + /* Stop the O.S. TX queue if needed */ + if (!netif_queue_stopped(priv->netdev)) + netif_stop_queue(priv->netdev); + + /* Allocate wait buffer */ + wait = mwifiex_alloc_fill_wait_queue(priv, wait_option); + if (!wait) + return -ENOMEM; + + if (ssid_bssid) + memcpy(&tmp_ssid_bssid, ssid_bssid, + sizeof(struct mwifiex_ssid_bssid)); + status = mwifiex_bss_ioctl_start(priv, wait, &tmp_ssid_bssid); + + status = mwifiex_request_ioctl(priv, wait, status, wait_option); + + kfree(wait); + return status; +} + +/* + * IOCTL request handler to set host sleep configuration. + * + * This function prepares the correct firmware command and + * issues it. + */ +static int +mwifiex_pm_ioctl_hs_cfg(struct mwifiex_private *priv, + struct mwifiex_wait_queue *wait, + u16 action, struct mwifiex_ds_hs_cfg *hs_cfg) +{ + struct mwifiex_adapter *adapter = priv->adapter; + int status = 0; + u32 prev_cond = 0; + + switch (action) { + case HostCmd_ACT_GEN_SET: + if (adapter->pps_uapsd_mode) { + dev_dbg(adapter->dev, "info: Host Sleep IOCTL" + " is blocked in UAPSD/PPS mode\n"); + status = -1; + break; + } + if (hs_cfg->is_invoke_hostcmd) { + if (hs_cfg->conditions == HOST_SLEEP_CFG_CANCEL) { + if (!adapter->is_hs_configured) + /* Already cancelled */ + break; + /* Save previous condition */ + prev_cond = le32_to_cpu(adapter->hs_cfg + .conditions); + adapter->hs_cfg.conditions = + cpu_to_le32(hs_cfg->conditions); + } else if (hs_cfg->conditions) { + adapter->hs_cfg.conditions = + cpu_to_le32(hs_cfg->conditions); + adapter->hs_cfg.gpio = (u8)hs_cfg->gpio; + if (hs_cfg->gap) + adapter->hs_cfg.gap = (u8)hs_cfg->gap; + } else if (adapter->hs_cfg.conditions == + cpu_to_le32( + HOST_SLEEP_CFG_CANCEL)) { + /* Return failure if no parameters for HS + enable */ + status = -1; + break; + } + status = mwifiex_prepare_cmd(priv, + HostCmd_CMD_802_11_HS_CFG_ENH, + HostCmd_ACT_GEN_SET, + 0, wait, &adapter->hs_cfg); + if (!status) + status = -EINPROGRESS; + if (hs_cfg->conditions == HOST_SLEEP_CFG_CANCEL) + /* Restore previous condition */ + adapter->hs_cfg.conditions = + cpu_to_le32(prev_cond); + } else { + adapter->hs_cfg.conditions = + cpu_to_le32(hs_cfg->conditions); + adapter->hs_cfg.gpio = (u8)hs_cfg->gpio; + adapter->hs_cfg.gap = (u8)hs_cfg->gap; + } + break; + case HostCmd_ACT_GEN_GET: + hs_cfg->conditions = le32_to_cpu(adapter->hs_cfg.conditions); + hs_cfg->gpio = adapter->hs_cfg.gpio; + hs_cfg->gap = adapter->hs_cfg.gap; + break; + default: + status = -1; + break; + } + + return status; +} + +/* + * Sends IOCTL request to set Host Sleep parameters. + * + * This function allocates the IOCTL request buffer, fills it + * with requisite parameters and calls the IOCTL handler. + */ +int mwifiex_set_hs_params(struct mwifiex_private *priv, u16 action, + u8 wait_option, + struct mwifiex_ds_hs_cfg *hscfg) +{ + int ret = 0; + struct mwifiex_wait_queue *wait = NULL; + + if (!hscfg) + return -ENOMEM; + + /* Allocate wait buffer */ + wait = mwifiex_alloc_fill_wait_queue(priv, wait_option); + if (!wait) + return -ENOMEM; + + ret = mwifiex_pm_ioctl_hs_cfg(priv, wait, action, hscfg); + + ret = mwifiex_request_ioctl(priv, wait, ret, wait_option); + + if (wait && (ret != -EINPROGRESS)) + kfree(wait); + return ret; +} + +/* + * Sends IOCTL request to cancel the existing Host Sleep configuration. + * + * This function allocates the IOCTL request buffer, fills it + * with requisite parameters and calls the IOCTL handler. + */ +int mwifiex_cancel_hs(struct mwifiex_private *priv, u8 wait_option) +{ + int ret = 0; + struct mwifiex_ds_hs_cfg hscfg; + + /* Cancel Host Sleep */ + hscfg.conditions = HOST_SLEEP_CFG_CANCEL; + hscfg.is_invoke_hostcmd = true; + ret = mwifiex_set_hs_params(priv, HostCmd_ACT_GEN_SET, + wait_option, &hscfg); + + return ret; +} +EXPORT_SYMBOL_GPL(mwifiex_cancel_hs); + +/* + * Sends IOCTL request to cancel the existing Host Sleep configuration. + * + * This function allocates the IOCTL request buffer, fills it + * with requisite parameters and calls the IOCTL handler. + */ +int mwifiex_enable_hs(struct mwifiex_adapter *adapter) +{ + struct mwifiex_ds_hs_cfg hscfg; + + if (adapter->hs_activated) { + dev_dbg(adapter->dev, "cmd: HS Already actived\n"); + return true; + } + + /* Enable Host Sleep */ + adapter->hs_activate_wait_q_woken = false; + + memset(&hscfg, 0, sizeof(struct mwifiex_hs_config_param)); + hscfg.is_invoke_hostcmd = true; + + if (mwifiex_set_hs_params(mwifiex_get_priv(adapter, + MWIFIEX_BSS_ROLE_STA), + HostCmd_ACT_GEN_SET, + MWIFIEX_IOCTL_WAIT, &hscfg)) { + dev_err(adapter->dev, "IOCTL request HS enable failed\n"); + return false; + } + + wait_event_interruptible(adapter->hs_activate_wait_q, + adapter->hs_activate_wait_q_woken); + + return true; +} +EXPORT_SYMBOL_GPL(mwifiex_enable_hs); + +/* + * IOCTL request handler to get signal information. + * + * This function prepares the correct firmware command and + * issues it to get the signal (RSSI) information. + * + * This only works in the connected mode. + */ +static int mwifiex_get_info_signal(struct mwifiex_private *priv, + struct mwifiex_wait_queue *wait, + struct mwifiex_ds_get_signal *signal) +{ + int ret = 0; + + if (!wait) { + dev_err(priv->adapter->dev, "WAIT information is not present\n"); + return -1; + } + + /* Signal info can be obtained only if connected */ + if (!priv->media_connected) { + dev_dbg(priv->adapter->dev, + "info: Can not get signal in disconnected state\n"); + return -1; + } + + /* Send request to firmware */ + ret = mwifiex_prepare_cmd(priv, HostCmd_CMD_RSSI_INFO, + HostCmd_ACT_GEN_GET, 0, wait, signal); + + if (!ret) + ret = -EINPROGRESS; + + return ret; +} + +/* + * IOCTL request handler to get statistics. + * + * This function prepares the correct firmware command and + * issues it to get the statistics (RSSI) information. + */ +static int mwifiex_get_info_stats(struct mwifiex_private *priv, + struct mwifiex_wait_queue *wait, + struct mwifiex_ds_get_stats *log) +{ + int ret = 0; + + if (!wait) { + dev_err(priv->adapter->dev, "MWIFIEX IOCTL information is not present\n"); + return -1; + } + + /* Send request to firmware */ + ret = mwifiex_prepare_cmd(priv, HostCmd_CMD_802_11_GET_LOG, + HostCmd_ACT_GEN_GET, 0, wait, log); + + if (!ret) + ret = -EINPROGRESS; + + return ret; +} + +/* + * IOCTL request handler to get BSS information. + * + * This function collates the information from different driver structures + * to send to the user. + */ +int mwifiex_get_bss_info(struct mwifiex_private *priv, + struct mwifiex_bss_info *info) +{ + struct mwifiex_adapter *adapter = priv->adapter; + struct mwifiex_bssdescriptor *bss_desc; + s32 tbl_idx = 0; + + if (!info) + return -1; + + /* Get current BSS info */ + bss_desc = &priv->curr_bss_params.bss_descriptor; + + /* BSS mode */ + info->bss_mode = priv->bss_mode; + + /* SSID */ + memcpy(&info->ssid, &bss_desc->ssid, + sizeof(struct mwifiex_802_11_ssid)); + + /* BSSID */ + memcpy(&info->bssid, &bss_desc->mac_address, ETH_ALEN); + + /* Channel */ + info->bss_chan = bss_desc->channel; + + /* Region code */ + info->region_code = adapter->region_code; + + /* Scan table index if connected */ + info->scan_table_idx = 0; + if (priv->media_connected) { + tbl_idx = + mwifiex_find_ssid_in_list(priv, &bss_desc->ssid, + bss_desc->mac_address, + priv->bss_mode); + if (tbl_idx >= 0) + info->scan_table_idx = tbl_idx; + } + + /* Connection status */ + info->media_connected = priv->media_connected; + + /* Radio status */ + info->radio_on = adapter->radio_on; + + /* Tx power information */ + info->max_power_level = priv->max_tx_power_level; + info->min_power_level = priv->min_tx_power_level; + + /* AdHoc state */ + info->adhoc_state = priv->adhoc_state; + + /* Last beacon NF */ + info->bcn_nf_last = priv->bcn_nf_last; + + /* wep status */ + if (priv->sec_info.wep_status == MWIFIEX_802_11_WEP_ENABLED) + info->wep_status = true; + else + info->wep_status = false; + + info->is_hs_configured = adapter->is_hs_configured; + info->is_deep_sleep = adapter->is_deep_sleep; + + return 0; +} + +/* + * IOCTL request handler to get extended version information. + * + * This function prepares the correct firmware command and + * issues it to get the extended version information. + */ +static int mwifiex_get_info_ver_ext(struct mwifiex_private *priv, + struct mwifiex_wait_queue *wait, + struct mwifiex_ver_ext *ver_ext) +{ + int ret = 0; + + /* Send request to firmware */ + ret = mwifiex_prepare_cmd(priv, HostCmd_CMD_VERSION_EXT, + HostCmd_ACT_GEN_GET, 0, wait, ver_ext); + if (!ret) + ret = -EINPROGRESS; + + return ret; +} + +/* + * IOCTL request handler to set/get SNMP MIB parameters. + * + * This function prepares the correct firmware command and + * issues it. + * + * Currently the following parameters are supported - + * Set/get RTS Threshold + * Set/get fragmentation threshold + * Set/get retry count + */ +int mwifiex_snmp_mib_ioctl(struct mwifiex_private *priv, + struct mwifiex_wait_queue *wait, + u32 cmd_oid, u16 action, u32 *value) +{ + int ret = 0; + + if (!value) + return -1; + + /* Send request to firmware */ + ret = mwifiex_prepare_cmd(priv, HostCmd_CMD_802_11_SNMP_MIB, + action, cmd_oid, wait, value); + + if (!ret) + ret = -EINPROGRESS; + + return ret; +} + +/* + * IOCTL request handler to set/get band configurations. + * + * For SET operation, it performs extra checks to make sure the Ad-Hoc + * band and channel are compatible. Otherwise it returns an error. + * + * For GET operation, this function retrieves the following information - + * - Infra bands + * - Ad-hoc band + * - Ad-hoc channel + * - Secondary channel offset + */ +int mwifiex_radio_ioctl_band_cfg(struct mwifiex_private *priv, + u16 action, + struct mwifiex_ds_band_cfg *radio_cfg) +{ + struct mwifiex_adapter *adapter = priv->adapter; + u8 infra_band = 0; + u8 adhoc_band = 0; + u32 adhoc_channel = 0; + + if (action == HostCmd_ACT_GEN_GET) { + /* Infra Bands */ + radio_cfg->config_bands = adapter->config_bands; + /* Adhoc Band */ + radio_cfg->adhoc_start_band = adapter->adhoc_start_band; + /* Adhoc channel */ + radio_cfg->adhoc_channel = priv->adhoc_channel; + /* Secondary channel offset */ + radio_cfg->sec_chan_offset = adapter->chan_offset; + return 0; + } + + /* For action = SET */ + infra_band = (u8) radio_cfg->config_bands; + adhoc_band = (u8) radio_cfg->adhoc_start_band; + adhoc_channel = radio_cfg->adhoc_channel; + + /* SET Infra band */ + if ((infra_band | adapter->fw_bands) & ~adapter->fw_bands) + return -1; + + adapter->config_bands = infra_band; + + /* SET Ad-hoc Band */ + if ((adhoc_band | adapter->fw_bands) & ~adapter->fw_bands) + return -1; + + if (adhoc_band) + adapter->adhoc_start_band = adhoc_band; + adapter->chan_offset = (u8) radio_cfg->sec_chan_offset; + /* + * If no adhoc_channel is supplied verify if the existing adhoc + * channel compiles with new adhoc_band + */ + if (!adhoc_channel) { + if (!mwifiex_get_cfp_by_band_and_channel_from_cfg80211 + (priv, adapter->adhoc_start_band, + priv->adhoc_channel)) { + /* Pass back the default channel */ + radio_cfg->adhoc_channel = DEFAULT_AD_HOC_CHANNEL; + if ((adapter->adhoc_start_band & BAND_A) + || (adapter->adhoc_start_band & BAND_AN)) + radio_cfg->adhoc_channel = + DEFAULT_AD_HOC_CHANNEL_A; + } + } else { /* Retrurn error if adhoc_band and + adhoc_channel combination is invalid */ + if (!mwifiex_get_cfp_by_band_and_channel_from_cfg80211 + (priv, adapter->adhoc_start_band, (u16) adhoc_channel)) + return -1; + priv->adhoc_channel = (u8) adhoc_channel; + } + if ((adhoc_band & BAND_GN) || (adhoc_band & BAND_AN)) + adapter->adhoc_11n_enabled = true; + else + adapter->adhoc_11n_enabled = false; + + return 0; +} + +/* + * IOCTL request handler to set/get active channel. + * + * This function performs validity checking on channel/frequency + * compatibility and returns failure if not valid. + */ +int mwifiex_bss_ioctl_channel(struct mwifiex_private *priv, u16 action, + struct mwifiex_chan_freq_power *chan) +{ + struct mwifiex_adapter *adapter = priv->adapter; + struct mwifiex_chan_freq_power *cfp = NULL; + + if (!chan) + return -1; + + if (action == HostCmd_ACT_GEN_GET) { + cfp = mwifiex_get_cfp_by_band_and_channel_from_cfg80211(priv, + priv->curr_bss_params.band, + (u16) priv->curr_bss_params.bss_descriptor. + channel); + chan->channel = cfp->channel; + chan->freq = cfp->freq; + + return 0; + } + if (!chan->channel && !chan->freq) + return -1; + if (adapter->adhoc_start_band & BAND_AN) + adapter->adhoc_start_band = BAND_G | BAND_B | BAND_GN; + else if (adapter->adhoc_start_band & BAND_A) + adapter->adhoc_start_band = BAND_G | BAND_B; + if (chan->channel) { + if (chan->channel <= MAX_CHANNEL_BAND_BG) + cfp = mwifiex_get_cfp_by_band_and_channel_from_cfg80211 + (priv, 0, (u16) chan->channel); + if (!cfp) { + cfp = mwifiex_get_cfp_by_band_and_channel_from_cfg80211 + (priv, BAND_A, (u16) chan->channel); + if (cfp) { + if (adapter->adhoc_11n_enabled) + adapter->adhoc_start_band = BAND_A + | BAND_AN; + else + adapter->adhoc_start_band = BAND_A; + } + } + } else { + if (chan->freq <= MAX_FREQUENCY_BAND_BG) + cfp = mwifiex_get_cfp_by_band_and_freq_from_cfg80211( + priv, 0, chan->freq); + if (!cfp) { + cfp = mwifiex_get_cfp_by_band_and_freq_from_cfg80211 + (priv, BAND_A, chan->freq); + if (cfp) { + if (adapter->adhoc_11n_enabled) + adapter->adhoc_start_band = BAND_A + | BAND_AN; + else + adapter->adhoc_start_band = BAND_A; + } + } + } + if (!cfp || !cfp->channel) { + dev_err(adapter->dev, "invalid channel/freq\n"); + return -1; + } + priv->adhoc_channel = (u8) cfp->channel; + chan->channel = cfp->channel; + chan->freq = cfp->freq; + + return 0; +} + +/* + * IOCTL request handler to set/get BSS mode. + * + * This function prepares the correct firmware command and + * issues it to set or get the BSS mode. + * + * In case the mode is changed, a deauthentication is performed + * first by the function automatically. + */ +int mwifiex_bss_ioctl_mode(struct mwifiex_private *priv, + struct mwifiex_wait_queue *wait, + u16 action, int *mode) +{ + int ret = 0; + + if (!mode) + return -1; + + if (action == HostCmd_ACT_GEN_GET) { + *mode = priv->bss_mode; + return 0; + } + + if ((priv->bss_mode == *mode) || (*mode == MWIFIEX_BSS_MODE_AUTO)) { + dev_dbg(priv->adapter->dev, + "info: Already set to required mode! No change!\n"); + priv->bss_mode = *mode; + return 0; + } + + ret = mwifiex_deauthenticate(priv, wait, NULL); + + priv->sec_info.authentication_mode = MWIFIEX_AUTH_MODE_OPEN; + priv->bss_mode = *mode; + if (priv->bss_mode != MWIFIEX_BSS_MODE_AUTO) { + ret = mwifiex_prepare_cmd(priv, HostCmd_CMD_SET_BSS_MODE, + HostCmd_ACT_GEN_SET, 0, wait, NULL); + if (!ret) + ret = -EINPROGRESS; + } + + return ret; +} + +/* + * IOCTL request handler to set/get Ad-Hoc channel. + * + * This function prepares the correct firmware command and + * issues it to set or get the ad-hoc channel. + */ +static int mwifiex_bss_ioctl_ibss_channel(struct mwifiex_private *priv, + struct mwifiex_wait_queue *wait, + u16 action, u16 *channel) +{ + int ret = 0; + + if (action == HostCmd_ACT_GEN_GET) { + if (!priv->media_connected) { + *channel = priv->adhoc_channel; + return ret; + } + } else { + priv->adhoc_channel = (u8) *channel; + } + + /* Send request to firmware */ + ret = mwifiex_prepare_cmd(priv, HostCmd_CMD_802_11_RF_CHANNEL, + action, 0, wait, channel); + if (!ret) + ret = -EINPROGRESS; + + return ret; +} + +/* + * IOCTL request handler to find a particular BSS. + * + * The BSS can be searched with either a BSSID or a SSID. If none of + * these are provided, just the best BSS (best RSSI) is returned. + */ +int mwifiex_bss_ioctl_find_bss(struct mwifiex_private *priv, + struct mwifiex_wait_queue *wait, + struct mwifiex_ssid_bssid *ssid_bssid) +{ + struct mwifiex_adapter *adapter = priv->adapter; + int ret = 0; + struct mwifiex_bssdescriptor *bss_desc; + u8 zero_mac[ETH_ALEN] = { 0, 0, 0, 0, 0, 0 }; + u8 mac[ETH_ALEN]; + int i = 0; + + if (memcmp(ssid_bssid->bssid, zero_mac, sizeof(zero_mac))) { + i = mwifiex_find_bssid_in_list(priv, + (u8 *) ssid_bssid->bssid, + priv->bss_mode); + if (i < 0) { + memcpy(mac, ssid_bssid->bssid, sizeof(mac)); + dev_err(adapter->dev, "cannot find bssid %pM\n", mac); + return -1; + } + bss_desc = &adapter->scan_table[i]; + memcpy(&ssid_bssid->ssid, &bss_desc->ssid, + sizeof(struct mwifiex_802_11_ssid)); + } else if (ssid_bssid->ssid.ssid_len) { + i = mwifiex_find_ssid_in_list(priv, &ssid_bssid->ssid, NULL, + priv->bss_mode); + if (i < 0) { + dev_err(adapter->dev, "cannot find ssid %s\n", + ssid_bssid->ssid.ssid); + return -1; + } + bss_desc = &adapter->scan_table[i]; + memcpy(ssid_bssid->bssid, bss_desc->mac_address, ETH_ALEN); + } else { + ret = mwifiex_find_best_network(priv, ssid_bssid); + } + + return ret; +} + +/* + * IOCTL request handler to change Ad-Hoc channel. + * + * This function allocates the IOCTL request buffer, fills it + * with requisite parameters and calls the IOCTL handler. + * + * The function follows the following steps to perform the change - + * - Get current IBSS information + * - Get current channel + * - If no change is required, return + * - If not connected, change channel and return + * - If connected, + * - Disconnect + * - Change channel + * - Perform specific SSID scan with same SSID + * - Start/Join the IBSS + */ +int +mwifiex_drv_change_adhoc_chan(struct mwifiex_private *priv, int channel) +{ + int ret = 0; + int status = 0; + struct mwifiex_bss_info bss_info; + struct mwifiex_wait_queue *wait = NULL; + u8 wait_option = MWIFIEX_IOCTL_WAIT; + struct mwifiex_ssid_bssid ssid_bssid; + u16 curr_chan = 0; + + memset(&bss_info, 0, sizeof(bss_info)); + + /* Get BSS information */ + if (mwifiex_get_bss_info(priv, &bss_info)) + return -1; + + /* Allocate wait buffer */ + wait = mwifiex_alloc_fill_wait_queue(priv, wait_option); + if (!wait) + return -ENOMEM; + + /* Get current channel */ + status = mwifiex_bss_ioctl_ibss_channel(priv, wait, HostCmd_ACT_GEN_GET, + &curr_chan); + + if (mwifiex_request_ioctl(priv, wait, status, wait_option)) { + ret = -1; + goto done; + } + if (curr_chan == channel) { + ret = 0; + goto done; + } + dev_dbg(priv->adapter->dev, "cmd: updating channel from %d to %d\n", + curr_chan, channel); + + if (!bss_info.media_connected) { + ret = 0; + goto done; + } + + /* Do disonnect */ + memset(&ssid_bssid, 0, ETH_ALEN); + status = mwifiex_bss_ioctl_stop(priv, wait, ssid_bssid.bssid); + + if (mwifiex_request_ioctl(priv, wait, status, wait_option)) { + ret = -1; + goto done; + } + + status = mwifiex_bss_ioctl_ibss_channel(priv, wait, HostCmd_ACT_GEN_SET, + (u16 *) &channel); + + if (mwifiex_request_ioctl(priv, wait, status, wait_option)) { + ret = -1; + goto done; + } + + /* Do specific SSID scanning */ + if (mwifiex_request_scan(priv, wait_option, &bss_info.ssid)) { + ret = -1; + goto done; + } + /* Start/Join Adhoc network */ + memset(&ssid_bssid, 0, sizeof(struct mwifiex_ssid_bssid)); + memcpy(&ssid_bssid.ssid, &bss_info.ssid, + sizeof(struct mwifiex_802_11_ssid)); + + status = mwifiex_bss_ioctl_start(priv, wait, &ssid_bssid); + + if (mwifiex_request_ioctl(priv, wait, status, wait_option)) + ret = -1; + +done: + kfree(wait); + return ret; +} + +/* + * IOCTL request handler to get current driver mode. + * + * This function allocates the IOCTL request buffer, fills it + * with requisite parameters and calls the IOCTL handler. + */ +int +mwifiex_drv_get_mode(struct mwifiex_private *priv, u8 wait_option) +{ + struct mwifiex_wait_queue *wait = NULL; + int status = 0; + int mode = -1; + + /* Allocate wait buffer */ + wait = mwifiex_alloc_fill_wait_queue(priv, wait_option); + if (!wait) + return -1; + + status = mwifiex_bss_ioctl_mode(priv, wait, HostCmd_ACT_GEN_GET, &mode); + + status = mwifiex_request_ioctl(priv, wait, status, wait_option); + + if (wait && (status != -EINPROGRESS)) + kfree(wait); + return mode; +} + +/* + * IOCTL request handler to get rate. + * + * This function prepares the correct firmware command and + * issues it to get the current rate if it is connected, + * otherwise, the function returns the lowest supported rate + * for the band. + */ +static int mwifiex_rate_ioctl_get_rate_value(struct mwifiex_private *priv, + struct mwifiex_wait_queue *wait, + struct mwifiex_rate_cfg *rate_cfg) +{ + struct mwifiex_adapter *adapter = priv->adapter; + int ret = 0; + + rate_cfg->is_rate_auto = priv->is_data_rate_auto; + if (!priv->media_connected) { + switch (adapter->config_bands) { + case BAND_B: + /* Return the lowest supported rate for B band */ + rate_cfg->rate = supported_rates_b[0] & 0x7f; + break; + case BAND_G: + case BAND_G | BAND_GN: + /* Return the lowest supported rate for G band */ + rate_cfg->rate = supported_rates_g[0] & 0x7f; + break; + case BAND_B | BAND_G: + case BAND_A | BAND_B | BAND_G: + case BAND_A | BAND_B: + case BAND_A | BAND_B | BAND_G | BAND_AN | BAND_GN: + case BAND_B | BAND_G | BAND_GN: + /* Return the lowest supported rate for BG band */ + rate_cfg->rate = supported_rates_bg[0] & 0x7f; + break; + case BAND_A: + case BAND_A | BAND_G: + case BAND_A | BAND_G | BAND_AN | BAND_GN: + case BAND_A | BAND_AN: + /* Return the lowest supported rate for A band */ + rate_cfg->rate = supported_rates_a[0] & 0x7f; + break; + case BAND_GN: + /* Return the lowest supported rate for N band */ + rate_cfg->rate = supported_rates_n[0] & 0x7f; + break; + default: + dev_warn(adapter->dev, "invalid band %#x\n", + adapter->config_bands); + break; + } + } else { + /* Send request to firmware */ + ret = mwifiex_prepare_cmd(priv, + HostCmd_CMD_802_11_TX_RATE_QUERY, + HostCmd_ACT_GEN_GET, 0, wait, NULL); + if (!ret) + ret = -EINPROGRESS; + } + + return ret; +} + +/* + * IOCTL request handler to set rate. + * + * This function prepares the correct firmware command and + * issues it to set the current rate. + * + * The function also performs validation checking on the supplied value. + */ +static int mwifiex_rate_ioctl_set_rate_value(struct mwifiex_private *priv, + struct mwifiex_wait_queue *wait, + struct mwifiex_rate_cfg *rate_cfg) +{ + u8 rates[MWIFIEX_SUPPORTED_RATES]; + u8 *rate = NULL; + int rate_index = 0; + u16 bitmap_rates[MAX_BITMAP_RATES_SIZE]; + u32 i = 0; + int ret = 0; + struct mwifiex_adapter *adapter = priv->adapter; + + if (rate_cfg->is_rate_auto) { + memset(bitmap_rates, 0, sizeof(bitmap_rates)); + /* Support all HR/DSSS rates */ + bitmap_rates[0] = 0x000F; + /* Support all OFDM rates */ + bitmap_rates[1] = 0x00FF; + /* Support all HT-MCSs rate */ + for (i = 0; i < ARRAY_SIZE(priv->bitmap_rates) - 3; i++) + bitmap_rates[i + 2] = 0xFFFF; + bitmap_rates[9] = 0x3FFF; + } else { + memset(rates, 0, sizeof(rates)); + mwifiex_get_active_data_rates(priv, rates); + rate = rates; + for (i = 0; (rate[i] && i < MWIFIEX_SUPPORTED_RATES); i++) { + dev_dbg(adapter->dev, "info: rate=%#x wanted=%#x\n", + rate[i], rate_cfg->rate); + if ((rate[i] & 0x7f) == (rate_cfg->rate & 0x7f)) + break; + } + if (!rate[i] || (i == MWIFIEX_SUPPORTED_RATES)) { + dev_err(adapter->dev, "fixed data rate %#x is out " + "of range\n", rate_cfg->rate); + return -1; + } + memset(bitmap_rates, 0, sizeof(bitmap_rates)); + + rate_index = + mwifiex_data_rate_to_index(adapter, rate_cfg->rate); + + /* Only allow b/g rates to be set */ + if (rate_index >= MWIFIEX_RATE_INDEX_HRDSSS0 && + rate_index <= MWIFIEX_RATE_INDEX_HRDSSS3) { + bitmap_rates[0] = 1 << rate_index; + } else { + rate_index -= 1; /* There is a 0x00 in the table */ + if (rate_index >= MWIFIEX_RATE_INDEX_OFDM0 && + rate_index <= MWIFIEX_RATE_INDEX_OFDM7) + bitmap_rates[1] = 1 << (rate_index - + MWIFIEX_RATE_INDEX_OFDM0); + } + } + + /* Send request to firmware */ + ret = mwifiex_prepare_cmd(priv, HostCmd_CMD_TX_RATE_CFG, + HostCmd_ACT_GEN_SET, 0, wait, bitmap_rates); + if (!ret) + ret = -EINPROGRESS; + + return ret; +} + +/* + * IOCTL request handler to set/get rate. + * + * This function can be used to set/get either the rate value or the + * rate index. + */ +static int mwifiex_rate_ioctl_cfg(struct mwifiex_private *priv, + struct mwifiex_wait_queue *wait, + struct mwifiex_rate_cfg *rate_cfg) +{ + int status = 0; + + if (!rate_cfg) + return -1; + + if (rate_cfg->action == HostCmd_ACT_GEN_GET) + status = mwifiex_rate_ioctl_get_rate_value( + priv, wait, rate_cfg); + else + status = mwifiex_rate_ioctl_set_rate_value( + priv, wait, rate_cfg); + + return status; +} + +/* + * Sends IOCTL request to get the data rate. + * + * This function allocates the IOCTL request buffer, fills it + * with requisite parameters and calls the IOCTL handler. + */ +int mwifiex_drv_get_data_rate(struct mwifiex_private *priv, + struct mwifiex_rate_cfg *rate) +{ + int ret = 0; + struct mwifiex_wait_queue *wait = NULL; + u8 wait_option = MWIFIEX_IOCTL_WAIT; + + /* Allocate wait buffer */ + wait = mwifiex_alloc_fill_wait_queue(priv, wait_option); + if (!wait) + return -ENOMEM; + + memset(rate, 0, sizeof(struct mwifiex_rate_cfg)); + rate->action = HostCmd_ACT_GEN_GET; + ret = mwifiex_rate_ioctl_cfg(priv, wait, rate); + + ret = mwifiex_request_ioctl(priv, wait, ret, wait_option); + if (!ret) { + if (rate && rate->is_rate_auto) + rate->rate = mwifiex_index_to_data_rate(priv->adapter, + priv->tx_rate, priv->tx_htinfo); + else if (rate) + rate->rate = priv->data_rate; + } else { + ret = -1; + } + + kfree(wait); + return ret; +} + +/* + * IOCTL request handler to set tx power configuration. + * + * This function prepares the correct firmware command and + * issues it. + * + * For non-auto power mode, all the following power groups are set - + * - Modulation class HR/DSSS + * - Modulation class OFDM + * - Modulation class HTBW20 + * - Modulation class HTBW40 + */ +static int mwifiex_power_ioctl_set_power(struct mwifiex_private *priv, + struct mwifiex_wait_queue *wait, + struct mwifiex_power_cfg *power_cfg) +{ + int ret = 0; + struct host_cmd_ds_txpwr_cfg *txp_cfg = NULL; + struct mwifiex_types_power_group *pg_tlv = NULL; + struct mwifiex_power_group *pg = NULL; + u8 *buf = NULL; + u16 dbm = 0; + + if (!power_cfg->is_power_auto) { + dbm = (u16) power_cfg->power_level; + if ((dbm < priv->min_tx_power_level) || + (dbm > priv->max_tx_power_level)) { + dev_err(priv->adapter->dev, "txpower value %d dBm" + " is out of range (%d dBm-%d dBm)\n", + dbm, priv->min_tx_power_level, + priv->max_tx_power_level); + return -1; + } + } + buf = kzalloc(MWIFIEX_SIZE_OF_CMD_BUFFER, GFP_KERNEL); + if (!buf) { + dev_err(priv->adapter->dev, "%s: failed to alloc cmd buffer\n", + __func__); + return -1; + } + + txp_cfg = (struct host_cmd_ds_txpwr_cfg *) buf; + txp_cfg->action = cpu_to_le16(HostCmd_ACT_GEN_SET); + if (!power_cfg->is_power_auto) { + txp_cfg->mode = cpu_to_le32(1); + pg_tlv = (struct mwifiex_types_power_group *) (buf + + sizeof(struct host_cmd_ds_txpwr_cfg)); + pg_tlv->type = TLV_TYPE_POWER_GROUP; + pg_tlv->length = 4 * sizeof(struct mwifiex_power_group); + pg = (struct mwifiex_power_group *) (buf + + sizeof(struct host_cmd_ds_txpwr_cfg) + + sizeof(struct mwifiex_types_power_group)); + /* Power group for modulation class HR/DSSS */ + pg->first_rate_code = 0x00; + pg->last_rate_code = 0x03; + pg->modulation_class = MOD_CLASS_HR_DSSS; + pg->power_step = 0; + pg->power_min = (s8) dbm; + pg->power_max = (s8) dbm; + pg++; + /* Power group for modulation class OFDM */ + pg->first_rate_code = 0x00; + pg->last_rate_code = 0x07; + pg->modulation_class = MOD_CLASS_OFDM; + pg->power_step = 0; + pg->power_min = (s8) dbm; + pg->power_max = (s8) dbm; + pg++; + /* Power group for modulation class HTBW20 */ + pg->first_rate_code = 0x00; + pg->last_rate_code = 0x20; + pg->modulation_class = MOD_CLASS_HT; + pg->power_step = 0; + pg->power_min = (s8) dbm; + pg->power_max = (s8) dbm; + pg->ht_bandwidth = HT_BW_20; + pg++; + /* Power group for modulation class HTBW40 */ + pg->first_rate_code = 0x00; + pg->last_rate_code = 0x20; + pg->modulation_class = MOD_CLASS_HT; + pg->power_step = 0; + pg->power_min = (s8) dbm; + pg->power_max = (s8) dbm; + pg->ht_bandwidth = HT_BW_40; + } + /* Send request to firmware */ + ret = mwifiex_prepare_cmd(priv, HostCmd_CMD_TXPWR_CFG, + HostCmd_ACT_GEN_SET, 0, wait, buf); + if (!ret) + ret = -EINPROGRESS; + kfree(buf); + + return ret; +} + +/* + * IOCTL request handler to get power save mode. + * + * This function prepares the correct firmware command and + * issues it. + */ +static int mwifiex_pm_ioctl_ps_mode(struct mwifiex_private *priv, + struct mwifiex_wait_queue *wait, + u32 *ps_mode, u16 action) +{ + int ret = 0; + struct mwifiex_adapter *adapter = priv->adapter; + u16 sub_cmd; + + if (action == HostCmd_ACT_GEN_SET) { + if (*ps_mode) + adapter->ps_mode = MWIFIEX_802_11_POWER_MODE_PSP; + else + adapter->ps_mode = MWIFIEX_802_11_POWER_MODE_CAM; + sub_cmd = (*ps_mode) ? EN_AUTO_PS : DIS_AUTO_PS; + ret = mwifiex_prepare_cmd(priv, HostCmd_CMD_802_11_PS_MODE_ENH, + sub_cmd, BITMAP_STA_PS, wait, NULL); + if ((!ret) && (sub_cmd == DIS_AUTO_PS)) + ret = mwifiex_prepare_cmd(priv, + HostCmd_CMD_802_11_PS_MODE_ENH, GET_PS, + 0, NULL, NULL); + } else { + ret = mwifiex_prepare_cmd(priv, HostCmd_CMD_802_11_PS_MODE_ENH, + GET_PS, 0, wait, NULL); + } + + if (!ret) + ret = -EINPROGRESS; + + return ret; +} + +/* + * IOCTL request handler to set/reset WPA IE. + * + * The supplied WPA IE is treated as a opaque buffer. Only the first field + * is checked to determine WPA version. If buffer length is zero, the existing + * WPA IE is reset. + */ +static int mwifiex_set_wpa_ie_helper(struct mwifiex_private *priv, + u8 *ie_data_ptr, u16 ie_len) +{ + if (ie_len) { + if (ie_len > sizeof(priv->wpa_ie)) { + dev_err(priv->adapter->dev, + "failed to copy WPA IE, too big\n"); + return -1; + } + memcpy(priv->wpa_ie, ie_data_ptr, ie_len); + priv->wpa_ie_len = (u8) ie_len; + dev_dbg(priv->adapter->dev, "cmd: Set Wpa_ie_len=%d IE=%#x\n", + priv->wpa_ie_len, priv->wpa_ie[0]); + + if (priv->wpa_ie[0] == WLAN_EID_WPA) { + priv->sec_info.wpa_enabled = true; + } else if (priv->wpa_ie[0] == WLAN_EID_RSN) { + priv->sec_info.wpa2_enabled = true; + } else { + priv->sec_info.wpa_enabled = false; + priv->sec_info.wpa2_enabled = false; + } + } else { + memset(priv->wpa_ie, 0, sizeof(priv->wpa_ie)); + priv->wpa_ie_len = 0; + dev_dbg(priv->adapter->dev, "info: reset wpa_ie_len=%d IE=%#x\n", + priv->wpa_ie_len, priv->wpa_ie[0]); + priv->sec_info.wpa_enabled = false; + priv->sec_info.wpa2_enabled = false; + } + + return 0; +} + +/* + * IOCTL request handler to set/reset WAPI IE. + * + * The supplied WAPI IE is treated as a opaque buffer. Only the first field + * is checked to internally enable WAPI. If buffer length is zero, the existing + * WAPI IE is reset. + */ +static int mwifiex_set_wapi_ie(struct mwifiex_private *priv, + u8 *ie_data_ptr, u16 ie_len) +{ + if (ie_len) { + if (ie_len > sizeof(priv->wapi_ie)) { + dev_dbg(priv->adapter->dev, + "info: failed to copy WAPI IE, too big\n"); + return -1; + } + memcpy(priv->wapi_ie, ie_data_ptr, ie_len); + priv->wapi_ie_len = ie_len; + dev_dbg(priv->adapter->dev, "cmd: Set wapi_ie_len=%d IE=%#x\n", + priv->wapi_ie_len, priv->wapi_ie[0]); + + if (priv->wapi_ie[0] == WLAN_EID_BSS_AC_ACCESS_DELAY) + priv->sec_info.wapi_enabled = true; + } else { + memset(priv->wapi_ie, 0, sizeof(priv->wapi_ie)); + priv->wapi_ie_len = ie_len; + dev_dbg(priv->adapter->dev, + "info: Reset wapi_ie_len=%d IE=%#x\n", + priv->wapi_ie_len, priv->wapi_ie[0]); + priv->sec_info.wapi_enabled = false; + } + return 0; +} + +/* + * IOCTL request handler to set WAPI key. + * + * This function prepares the correct firmware command and + * issues it. + */ +static int mwifiex_sec_ioctl_set_wapi_key(struct mwifiex_adapter *adapter, + struct mwifiex_wait_queue *wait, + struct mwifiex_ds_encrypt_key *encrypt_key) +{ + int ret = 0; + struct mwifiex_private *priv = adapter->priv[wait->bss_index]; + + ret = mwifiex_prepare_cmd(priv, HostCmd_CMD_802_11_KEY_MATERIAL, + HostCmd_ACT_GEN_SET, KEY_INFO_ENABLED, + wait, encrypt_key); + if (!ret) + ret = -EINPROGRESS; + + return ret; +} + +/* + * IOCTL request handler to set/get authentication mode. + */ +static int mwifiex_set_auth_mode(struct mwifiex_private *priv, u32 auth_mode) +{ + int ret = 0; + + priv->sec_info.authentication_mode = auth_mode; + if (priv->sec_info.authentication_mode == MWIFIEX_AUTH_MODE_NETWORKEAP) + ret = mwifiex_set_wpa_ie_helper(priv, NULL, 0); + + return ret; +} + +/* + * IOCTL request handler to set WEP network key. + * + * This function prepares the correct firmware command and + * issues it, after validation checks. + */ +static int mwifiex_sec_ioctl_set_wep_key(struct mwifiex_adapter *adapter, + struct mwifiex_wait_queue *wait, + struct mwifiex_ds_encrypt_key *encrypt_key) +{ + int ret = 0; + struct mwifiex_private *priv = adapter->priv[wait->bss_index]; + struct mwifiex_wep_key *wep_key = NULL; + int index; + + if (priv->wep_key_curr_index >= NUM_WEP_KEYS) + priv->wep_key_curr_index = 0; + wep_key = &priv->wep_key[priv->wep_key_curr_index]; + index = encrypt_key->key_index; + if (encrypt_key->key_disable) { + priv->sec_info.wep_status = MWIFIEX_802_11_WEP_DISABLED; + } else if (!encrypt_key->key_len) { + /* Copy the required key as the current key */ + wep_key = &priv->wep_key[index]; + if (!wep_key->key_length) { + dev_err(adapter->dev, + "key not set, so cannot enable it\n"); + return -1; + } + priv->wep_key_curr_index = (u16) index; + priv->sec_info.wep_status = MWIFIEX_802_11_WEP_ENABLED; + } else { + wep_key = &priv->wep_key[index]; + /* Cleanup */ + memset(wep_key, 0, sizeof(struct mwifiex_wep_key)); + /* Copy the key in the driver */ + memcpy(wep_key->key_material, + encrypt_key->key_material, + encrypt_key->key_len); + wep_key->key_index = index; + wep_key->key_length = encrypt_key->key_len; + priv->sec_info.wep_status = MWIFIEX_802_11_WEP_ENABLED; + } + if (wep_key->key_length) { + /* Send request to firmware */ + ret = mwifiex_prepare_cmd(priv, HostCmd_CMD_802_11_KEY_MATERIAL, + HostCmd_ACT_GEN_SET, 0, NULL, NULL); + if (ret) + return ret; + } + if (priv->sec_info.wep_status == MWIFIEX_802_11_WEP_ENABLED) + priv->curr_pkt_filter |= HostCmd_ACT_MAC_WEP_ENABLE; + else + priv->curr_pkt_filter &= ~HostCmd_ACT_MAC_WEP_ENABLE; + + /* Send request to firmware */ + ret = mwifiex_prepare_cmd(priv, HostCmd_CMD_MAC_CONTROL, + HostCmd_ACT_GEN_SET, 0, wait, + &priv->curr_pkt_filter); + if (!ret) + ret = -EINPROGRESS; + + return ret; +} + +/* + * IOCTL request handler to set WPA key. + * + * This function prepares the correct firmware command and + * issues it, after validation checks. + * + * Current driver only supports key length of up to 32 bytes. + * + * This function can also be used to disable a currently set key. + */ +static int mwifiex_sec_ioctl_set_wpa_key(struct mwifiex_adapter *adapter, + struct mwifiex_wait_queue *wait, + struct mwifiex_ds_encrypt_key *encrypt_key) +{ + int ret = 0; + struct mwifiex_private *priv = adapter->priv[wait->bss_index]; + u8 remove_key = false; + struct host_cmd_ds_802_11_key_material *ibss_key; + + /* Current driver only supports key length of up to 32 bytes */ + if (encrypt_key->key_len > MWIFIEX_MAX_KEY_LENGTH) { + dev_err(adapter->dev, "key length too long\n"); + return -1; + } + + if (priv->bss_mode == MWIFIEX_BSS_MODE_IBSS) { + /* + * IBSS/WPA-None uses only one key (Group) for both receiving + * and sending unicast and multicast packets. + */ + /* Send the key as PTK to firmware */ + encrypt_key->key_index = MWIFIEX_KEY_INDEX_UNICAST; + ret = mwifiex_prepare_cmd(priv, HostCmd_CMD_802_11_KEY_MATERIAL, + HostCmd_ACT_GEN_SET, KEY_INFO_ENABLED, + NULL, encrypt_key); + if (ret) + return ret; + + ibss_key = &priv->aes_key; + memset(ibss_key, 0, + sizeof(struct host_cmd_ds_802_11_key_material)); + /* Copy the key in the driver */ + memcpy(ibss_key->key_param_set.key, encrypt_key->key_material, + encrypt_key->key_len); + memcpy(&ibss_key->key_param_set.key_len, &encrypt_key->key_len, + sizeof(ibss_key->key_param_set.key_len)); + ibss_key->key_param_set.key_type_id + = cpu_to_le16(KEY_TYPE_ID_TKIP); + ibss_key->key_param_set.key_info + = cpu_to_le16(KEY_INFO_TKIP_ENABLED); + + /* Send the key as GTK to firmware */ + encrypt_key->key_index = ~MWIFIEX_KEY_INDEX_UNICAST; + } + + if (!encrypt_key->key_index) + encrypt_key->key_index = MWIFIEX_KEY_INDEX_UNICAST; + + if (remove_key) + /* Send request to firmware */ + ret = mwifiex_prepare_cmd(priv, HostCmd_CMD_802_11_KEY_MATERIAL, + HostCmd_ACT_GEN_SET, + !(KEY_INFO_ENABLED), + wait, encrypt_key); + else + /* Send request to firmware */ + ret = mwifiex_prepare_cmd(priv, HostCmd_CMD_802_11_KEY_MATERIAL, + HostCmd_ACT_GEN_SET, KEY_INFO_ENABLED, + wait, encrypt_key); + + if (!ret) + ret = -EINPROGRESS; + + return ret; +} + +/* + * IOCTL request handler to set/get network keys. + * + * This is a generic key handling function which supports WEP, WPA + * and WAPI. + */ +static int +mwifiex_sec_ioctl_encrypt_key(struct mwifiex_private *priv, + struct mwifiex_wait_queue *wait, + struct mwifiex_ds_encrypt_key *encrypt_key) +{ + int status = 0; + struct mwifiex_adapter *adapter = priv->adapter; + + if (encrypt_key->is_wapi_key) + status = mwifiex_sec_ioctl_set_wapi_key(adapter, wait, + encrypt_key); + else if (encrypt_key->key_len > WLAN_KEY_LEN_WEP104) + status = mwifiex_sec_ioctl_set_wpa_key(adapter, wait, + encrypt_key); + else + status = mwifiex_sec_ioctl_set_wep_key(adapter, wait, + encrypt_key); + return status; +} + +/* + * This function returns the driver version. + */ +int +mwifiex_drv_get_driver_version(struct mwifiex_adapter *adapter, char *version, + int max_len) +{ + union { + u32 l; + u8 c[4]; + } ver; + char fw_ver[32]; + + ver.l = adapter->fw_release_number; + sprintf(fw_ver, "%u.%u.%u.p%u", ver.c[2], ver.c[1], ver.c[0], ver.c[3]); + + snprintf(version, max_len, driver_version, fw_ver); + + dev_dbg(adapter->dev, "info: MWIFIEX VERSION: %s\n", version); + + return 0; +} + +/* + * Sends IOCTL request to set Tx power. It can be set to either auto + * or a fixed value. + * + * This function allocates the IOCTL request buffer, fills it + * with requisite parameters and calls the IOCTL handler. + */ +int +mwifiex_set_tx_power(struct mwifiex_private *priv, int type, int dbm) +{ + struct mwifiex_power_cfg power_cfg; + struct mwifiex_wait_queue *wait = NULL; + int status = 0; + int ret = 0; + + wait = mwifiex_alloc_fill_wait_queue(priv, MWIFIEX_IOCTL_WAIT); + if (!wait) + return -ENOMEM; + + if (type == NL80211_TX_POWER_FIXED) { + power_cfg.is_power_auto = 0; + power_cfg.power_level = dbm; + } else { + power_cfg.is_power_auto = 1; + } + status = mwifiex_power_ioctl_set_power(priv, wait, &power_cfg); + + ret = mwifiex_request_ioctl(priv, wait, status, MWIFIEX_IOCTL_WAIT); + + kfree(wait); + return ret; +} + +/* + * Sends IOCTL request to get scan table. + * + * This function allocates the IOCTL request buffer, fills it + * with requisite parameters and calls the IOCTL handler. + */ +int mwifiex_get_scan_table(struct mwifiex_private *priv, u8 wait_option, + struct mwifiex_scan_resp *scan_resp) +{ + struct mwifiex_wait_queue *wait = NULL; + struct mwifiex_scan_resp scan; + int status = 0; + + /* Allocate wait buffer */ + wait = mwifiex_alloc_fill_wait_queue(priv, wait_option); + if (!wait) + return -ENOMEM; + + status = mwifiex_scan_networks(priv, wait, HostCmd_ACT_GEN_GET, + NULL, &scan); + + status = mwifiex_request_ioctl(priv, wait, status, wait_option); + if (!status) { + if (scan_resp) + memcpy(scan_resp, &scan, + sizeof(struct mwifiex_scan_resp)); + } + + if (wait && (status != -EINPROGRESS)) + kfree(wait); + return status; +} + +/* + * Sends IOCTL request to get signal information. + * + * This function allocates the IOCTL request buffer, fills it + * with requisite parameters and calls the IOCTL handler. + */ +int mwifiex_get_signal_info(struct mwifiex_private *priv, u8 wait_option, + struct mwifiex_ds_get_signal *signal) +{ + struct mwifiex_ds_get_signal info; + struct mwifiex_wait_queue *wait = NULL; + int status = 0; + + /* Allocate wait buffer */ + wait = mwifiex_alloc_fill_wait_queue(priv, wait_option); + if (!wait) + return -ENOMEM; + + info.selector = ALL_RSSI_INFO_MASK; + + status = mwifiex_get_info_signal(priv, wait, &info); + + status = mwifiex_request_ioctl(priv, wait, status, wait_option); + if (!status) { + if (signal) + memcpy(signal, &info, + sizeof(struct mwifiex_ds_get_signal)); + if (info.selector & BCN_RSSI_AVG_MASK) + priv->w_stats.qual.level = info.bcn_rssi_avg; + if (info.selector & BCN_NF_AVG_MASK) + priv->w_stats.qual.noise = info.bcn_nf_avg; + } + + if (wait && (status != -EINPROGRESS)) + kfree(wait); + return status; +} + +/* + * Sends IOCTL request to set encryption mode. + * + * This function allocates the IOCTL request buffer, fills it + * with requisite parameters and calls the IOCTL handler. + */ +static int mwifiex_set_encrypt_mode(struct mwifiex_private *priv, + u8 wait_option, u32 encrypt_mode) +{ + priv->sec_info.encryption_mode = encrypt_mode; + return 0; +} + +/* + * This function set the authentication parameters. It sets both encryption + * mode and authentication mode, and also enables WPA if required. + */ +int +mwifiex_set_auth(struct mwifiex_private *priv, int encrypt_mode, + int auth_mode, int wpa_enabled) +{ + if (mwifiex_set_encrypt_mode(priv, MWIFIEX_IOCTL_WAIT, encrypt_mode)) + return -EFAULT; + + if (mwifiex_set_auth_mode(priv, auth_mode)) + return -EFAULT; + + return 0; +} + +/* + * Sends IOCTL request to set encoding parameters. + * + * This function allocates the IOCTL request buffer, fills it + * with requisite parameters and calls the IOCTL handler. + */ +int mwifiex_set_encode(struct mwifiex_private *priv, const u8 *key, + int key_len, u8 key_index, int disable) +{ + struct mwifiex_wait_queue *wait = NULL; + struct mwifiex_ds_encrypt_key encrypt_key; + int status = 0; + int ret = 0; + + wait = mwifiex_alloc_fill_wait_queue(priv, MWIFIEX_IOCTL_WAIT); + if (!wait) + return -ENOMEM; + + memset(&encrypt_key, 0, sizeof(struct mwifiex_ds_encrypt_key)); + encrypt_key.key_len = key_len; + if (!disable) { + encrypt_key.key_index = key_index; + if (key_len) + memcpy(encrypt_key.key_material, key, key_len); + } else { + encrypt_key.key_disable = true; + } + + status = mwifiex_sec_ioctl_encrypt_key(priv, wait, &encrypt_key); + + if (mwifiex_request_ioctl(priv, wait, status, MWIFIEX_IOCTL_WAIT)) + ret = -EFAULT; + + kfree(wait); + return ret; +} + +/* + * Sends IOCTL request to set power management parameters. + * + * This function allocates the IOCTL request buffer, fills it + * with requisite parameters and calls the IOCTL handler. + */ +int +mwifiex_drv_set_power(struct mwifiex_private *priv, bool power_on) +{ + int ret = 0; + int status = 0; + struct mwifiex_wait_queue *wait = NULL; + u32 ps_mode; + + wait = mwifiex_alloc_fill_wait_queue(priv, MWIFIEX_IOCTL_WAIT); + if (!wait) + return -ENOMEM; + + ps_mode = power_on; + status = mwifiex_pm_ioctl_ps_mode(priv, wait, &ps_mode, + HostCmd_ACT_GEN_SET); + + ret = mwifiex_request_ioctl(priv, wait, status, MWIFIEX_IOCTL_WAIT); + + kfree(wait); + return ret; +} + +/* + * Sends IOCTL request to get extended version. + * + * This function allocates the IOCTL request buffer, fills it + * with requisite parameters and calls the IOCTL handler. + */ +int +mwifiex_get_ver_ext(struct mwifiex_private *priv) +{ + struct mwifiex_ver_ext ver_ext; + struct mwifiex_wait_queue *wait = NULL; + int status = 0; + int ret = 0; + u8 wait_option = MWIFIEX_IOCTL_WAIT; + + /* Allocate wait buffer */ + wait = mwifiex_alloc_fill_wait_queue(priv, wait_option); + if (!wait) + return -ENOMEM; + + /* get fw version */ + memset(&ver_ext, 0, sizeof(struct host_cmd_ds_version_ext)); + status = mwifiex_get_info_ver_ext(priv, wait, &ver_ext); + + ret = mwifiex_request_ioctl(priv, wait, status, wait_option); + + if (ret) + ret = -1; + + kfree(wait); + return ret; +} + +/* + * Sends IOCTL request to get statistics information. + * + * This function allocates the IOCTL request buffer, fills it + * with requisite parameters and calls the IOCTL handler. + */ +int +mwifiex_get_stats_info(struct mwifiex_private *priv, + struct mwifiex_ds_get_stats *log) +{ + int ret = 0; + int status = 0; + struct mwifiex_wait_queue *wait = NULL; + struct mwifiex_ds_get_stats get_log; + u8 wait_option = MWIFIEX_IOCTL_WAIT; + + /* Allocate wait buffer */ + wait = mwifiex_alloc_fill_wait_queue(priv, wait_option); + if (!wait) + return -ENOMEM; + + memset(&get_log, 0, sizeof(struct mwifiex_ds_get_stats)); + status = mwifiex_get_info_stats(priv, wait, &get_log); + + /* Send IOCTL request to MWIFIEX */ + ret = mwifiex_request_ioctl(priv, wait, status, wait_option); + if (!ret) { + if (log) + memcpy(log, &get_log, sizeof(struct + mwifiex_ds_get_stats)); + priv->w_stats.discard.fragment = get_log.fcs_error; + priv->w_stats.discard.retries = get_log.retry; + priv->w_stats.discard.misc = get_log.ack_failure; + } + + kfree(wait); + return ret; +} + +/* + * IOCTL request handler to read/write register. + * + * This function prepares the correct firmware command and + * issues it. + * + * Access to the following registers are supported - + * - MAC + * - BBP + * - RF + * - PMIC + * - CAU + */ +static int mwifiex_reg_mem_ioctl_reg_rw(struct mwifiex_private *priv, + struct mwifiex_wait_queue *wait, + struct mwifiex_ds_reg_rw *reg_rw, + u16 action) +{ + int ret = 0; + u16 cmd_no; + + switch (le32_to_cpu(reg_rw->type)) { + case MWIFIEX_REG_MAC: + cmd_no = HostCmd_CMD_MAC_REG_ACCESS; + break; + case MWIFIEX_REG_BBP: + cmd_no = HostCmd_CMD_BBP_REG_ACCESS; + break; + case MWIFIEX_REG_RF: + cmd_no = HostCmd_CMD_RF_REG_ACCESS; + break; + case MWIFIEX_REG_PMIC: + cmd_no = HostCmd_CMD_PMIC_REG_ACCESS; + break; + case MWIFIEX_REG_CAU: + cmd_no = HostCmd_CMD_CAU_REG_ACCESS; + break; + default: + return -1; + } + + /* Send request to firmware */ + ret = mwifiex_prepare_cmd(priv, cmd_no, action, 0, wait, reg_rw); + + if (!ret) + ret = -EINPROGRESS; + + return ret; +} + +/* + * Sends IOCTL request to write to a register. + * + * This function allocates the IOCTL request buffer, fills it + * with requisite parameters and calls the IOCTL handler. + */ +int +mwifiex_reg_write(struct mwifiex_private *priv, u32 reg_type, + u32 reg_offset, u32 reg_value) +{ + int ret = 0; + int status = 0; + struct mwifiex_wait_queue *wait = NULL; + struct mwifiex_ds_reg_rw reg_rw; + + wait = mwifiex_alloc_fill_wait_queue(priv, MWIFIEX_IOCTL_WAIT); + if (!wait) + return -ENOMEM; + + reg_rw.type = cpu_to_le32(reg_type); + reg_rw.offset = cpu_to_le32(reg_offset); + reg_rw.value = cpu_to_le32(reg_value); + status = mwifiex_reg_mem_ioctl_reg_rw(priv, wait, ®_rw, + HostCmd_ACT_GEN_SET); + + ret = mwifiex_request_ioctl(priv, wait, status, MWIFIEX_IOCTL_WAIT); + + kfree(wait); + return ret; +} + +/* + * Sends IOCTL request to read from a register. + * + * This function allocates the IOCTL request buffer, fills it + * with requisite parameters and calls the IOCTL handler. + */ +int +mwifiex_reg_read(struct mwifiex_private *priv, u32 reg_type, + u32 reg_offset, u32 *value) +{ + int ret = 0; + int status = 0; + struct mwifiex_wait_queue *wait = NULL; + struct mwifiex_ds_reg_rw reg_rw; + + wait = mwifiex_alloc_fill_wait_queue(priv, MWIFIEX_IOCTL_WAIT); + if (!wait) + return -ENOMEM; + + reg_rw.type = cpu_to_le32(reg_type); + reg_rw.offset = cpu_to_le32(reg_offset); + status = mwifiex_reg_mem_ioctl_reg_rw(priv, wait, ®_rw, + HostCmd_ACT_GEN_GET); + + ret = mwifiex_request_ioctl(priv, wait, status, MWIFIEX_IOCTL_WAIT); + if (ret) + goto done; + + *value = le32_to_cpu(reg_rw.value); + +done: + kfree(wait); + return ret; +} + +/* + * IOCTL request handler to read EEPROM. + * + * This function prepares the correct firmware command and + * issues it. + */ +static int +mwifiex_reg_mem_ioctl_read_eeprom(struct mwifiex_private *priv, + struct mwifiex_wait_queue *wait, + struct mwifiex_ds_read_eeprom *rd_eeprom) +{ + int ret = 0; + + /* Send request to firmware */ + ret = mwifiex_prepare_cmd(priv, HostCmd_CMD_802_11_EEPROM_ACCESS, + HostCmd_ACT_GEN_GET, 0, wait, rd_eeprom); + + if (!ret) + ret = -EINPROGRESS; + + return ret; +} + +/* + * Sends IOCTL request to read from EEPROM. + * + * This function allocates the IOCTL request buffer, fills it + * with requisite parameters and calls the IOCTL handler. + */ +int +mwifiex_eeprom_read(struct mwifiex_private *priv, u16 offset, u16 bytes, + u8 *value) +{ + int ret = 0; + int status = 0; + struct mwifiex_wait_queue *wait = NULL; + struct mwifiex_ds_read_eeprom rd_eeprom; + + wait = mwifiex_alloc_fill_wait_queue(priv, MWIFIEX_IOCTL_WAIT); + if (!wait) + return -ENOMEM; + + rd_eeprom.offset = cpu_to_le16((u16) offset); + rd_eeprom.byte_count = cpu_to_le16((u16) bytes); + status = mwifiex_reg_mem_ioctl_read_eeprom(priv, wait, &rd_eeprom); + + ret = mwifiex_request_ioctl(priv, wait, status, MWIFIEX_IOCTL_WAIT); + if (ret) + goto done; + + memcpy(value, rd_eeprom.value, MAX_EEPROM_DATA); +done: + kfree(wait); + return ret; +} + +/* + * This function sets a generic IE. In addition to generic IE, it can + * also handle WPA, WPA2 and WAPI IEs. + */ +static int +mwifiex_set_gen_ie_helper(struct mwifiex_private *priv, u8 *ie_data_ptr, + u16 ie_len) +{ + int ret = 0; + struct ieee_types_vendor_header *pvendor_ie; + const u8 wpa_oui[] = { 0x00, 0x50, 0xf2, 0x01 }; + const u8 wps_oui[] = { 0x00, 0x50, 0xf2, 0x04 }; + + /* If the passed length is zero, reset the buffer */ + if (!ie_len) { + priv->gen_ie_buf_len = 0; + priv->wps.session_enable = false; + + return 0; + } else if (!ie_data_ptr) { + return -1; + } + pvendor_ie = (struct ieee_types_vendor_header *) ie_data_ptr; + /* Test to see if it is a WPA IE, if not, then it is a gen IE */ + if (((pvendor_ie->element_id == WLAN_EID_WPA) + && (!memcmp(pvendor_ie->oui, wpa_oui, sizeof(wpa_oui)))) + || (pvendor_ie->element_id == WLAN_EID_RSN)) { + + /* IE is a WPA/WPA2 IE so call set_wpa function */ + ret = mwifiex_set_wpa_ie_helper(priv, ie_data_ptr, ie_len); + priv->wps.session_enable = false; + + return ret; + } else if (pvendor_ie->element_id == WLAN_EID_BSS_AC_ACCESS_DELAY) { + /* IE is a WAPI IE so call set_wapi function */ + ret = mwifiex_set_wapi_ie(priv, ie_data_ptr, ie_len); + + return ret; + } + /* + * Verify that the passed length is not larger than the + * available space remaining in the buffer + */ + if (ie_len < (sizeof(priv->gen_ie_buf) - priv->gen_ie_buf_len)) { + + /* Test to see if it is a WPS IE, if so, enable + * wps session flag + */ + pvendor_ie = (struct ieee_types_vendor_header *) ie_data_ptr; + if ((pvendor_ie->element_id == WLAN_EID_VENDOR_SPECIFIC) + && (!memcmp(pvendor_ie->oui, wps_oui, + sizeof(wps_oui)))) { + priv->wps.session_enable = true; + dev_dbg(priv->adapter->dev, + "info: WPS Session Enabled.\n"); + } + + /* Append the passed data to the end of the + genIeBuffer */ + memcpy(priv->gen_ie_buf + priv->gen_ie_buf_len, ie_data_ptr, + ie_len); + /* Increment the stored buffer length by the + size passed */ + priv->gen_ie_buf_len += ie_len; + } else { + /* Passed data does not fit in the remaining + buffer space */ + ret = -1; + } + + /* Return 0, or -1 for error case */ + return ret; +} + +/* + * IOCTL request handler to set/get generic IE. + * + * In addition to various generic IEs, this function can also be + * used to set the ARP filter. + */ +static int mwifiex_misc_ioctl_gen_ie(struct mwifiex_private *priv, + struct mwifiex_ds_misc_gen_ie *gen_ie, + u16 action) +{ + struct mwifiex_adapter *adapter = priv->adapter; + + switch (gen_ie->type) { + case MWIFIEX_IE_TYPE_GEN_IE: + if (action == HostCmd_ACT_GEN_GET) { + gen_ie->len = priv->wpa_ie_len; + memcpy(gen_ie->ie_data, priv->wpa_ie, gen_ie->len); + } else { + mwifiex_set_gen_ie_helper(priv, gen_ie->ie_data, + (u16) gen_ie->len); + } + break; + case MWIFIEX_IE_TYPE_ARP_FILTER: + memset(adapter->arp_filter, 0, sizeof(adapter->arp_filter)); + if (gen_ie->len > ARP_FILTER_MAX_BUF_SIZE) { + adapter->arp_filter_size = 0; + dev_err(adapter->dev, "invalid ARP filter size\n"); + return -1; + } else { + memcpy(adapter->arp_filter, gen_ie->ie_data, + gen_ie->len); + adapter->arp_filter_size = gen_ie->len; + } + break; + default: + dev_err(adapter->dev, "invalid IE type\n"); + return -1; + } + return 0; +} + +/* + * Sends IOCTL request to set a generic IE. + * + * This function allocates the IOCTL request buffer, fills it + * with requisite parameters and calls the IOCTL handler. + */ +int +mwifiex_set_gen_ie(struct mwifiex_private *priv, u8 *ie, int ie_len) +{ + struct mwifiex_ds_misc_gen_ie gen_ie; + int status = 0; + + if (ie_len > IW_CUSTOM_MAX) + return -EFAULT; + + gen_ie.type = MWIFIEX_IE_TYPE_GEN_IE; + gen_ie.len = ie_len; + memcpy(gen_ie.ie_data, ie, ie_len); + status = mwifiex_misc_ioctl_gen_ie(priv, &gen_ie, HostCmd_ACT_GEN_SET); + if (status) + return -EFAULT; + + return 0; +} diff --git a/drivers/net/wireless/mwifiex/sta_rx.c b/drivers/net/wireless/mwifiex/sta_rx.c new file mode 100644 index 0000000..8282679 --- /dev/null +++ b/drivers/net/wireless/mwifiex/sta_rx.c @@ -0,0 +1,182 @@ +/* + * Marvell Wireless LAN device driver: station RX data handling + * + * Copyright (C) 2011, Marvell International Ltd. + * + * This software file (the "File") is distributed by Marvell International + * Ltd. under the terms of the GNU General Public License Version 2, June 1991 + * (the "License"). You may use, redistribute and/or modify this File in + * accordance with the terms and conditions of the License, a copy of which + * is available by writing to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the + * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. + * + * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE + * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE + * ARE EXPRESSLY DISCLAIMED. The License provides additional details about + * this warranty disclaimer. + */ + +#include "decl.h" +#include "ioctl.h" +#include "util.h" +#include "fw.h" +#include "main.h" +#include "11n_aggr.h" +#include "11n_rxreorder.h" + +/* + * This function processes the received packet and forwards it + * to kernel/upper layer. + * + * This function parses through the received packet and determines + * if it is a debug packet or normal packet. + * + * For non-debug packets, the function chops off unnecessary leading + * header bytes, reconstructs the packet as an ethernet frame or + * 802.2/llc/snap frame as required, and sends it to kernel/upper layer. + * + * The completion callback is called after processing in complete. + */ +int mwifiex_process_rx_packet(struct mwifiex_adapter *adapter, + struct sk_buff *skb) +{ + int ret = 0; + struct mwifiex_rxinfo *rx_info = MWIFIEX_SKB_RXCB(skb); + struct mwifiex_private *priv = adapter->priv[rx_info->bss_index]; + struct rx_packet_hdr *rx_pkt_hdr; + struct rxpd *local_rx_pd; + int hdr_chop; + struct ethhdr *eth_hdr; + u8 rfc1042_eth_hdr[ETH_ALEN] = { 0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00 }; + + local_rx_pd = (struct rxpd *) (skb->data); + + rx_pkt_hdr = (struct rx_packet_hdr *) ((u8 *) local_rx_pd + + local_rx_pd->rx_pkt_offset); + + if (!memcmp(&rx_pkt_hdr->rfc1042_hdr, + rfc1042_eth_hdr, sizeof(rfc1042_eth_hdr))) { + /* + * Replace the 803 header and rfc1042 header (llc/snap) with an + * EthernetII header, keep the src/dst and snap_type + * (ethertype). + * The firmware only passes up SNAP frames converting + * all RX Data from 802.11 to 802.2/LLC/SNAP frames. + * To create the Ethernet II, just move the src, dst address + * right before the snap_type. + */ + eth_hdr = (struct ethhdr *) + ((u8 *) &rx_pkt_hdr->eth803_hdr + + sizeof(rx_pkt_hdr->eth803_hdr) + + sizeof(rx_pkt_hdr->rfc1042_hdr) + - sizeof(rx_pkt_hdr->eth803_hdr.h_dest) + - sizeof(rx_pkt_hdr->eth803_hdr.h_source) + - sizeof(rx_pkt_hdr->rfc1042_hdr.snap_type)); + + memcpy(eth_hdr->h_source, rx_pkt_hdr->eth803_hdr.h_source, + sizeof(eth_hdr->h_source)); + memcpy(eth_hdr->h_dest, rx_pkt_hdr->eth803_hdr.h_dest, + sizeof(eth_hdr->h_dest)); + + /* Chop off the rxpd + the excess memory from the 802.2/llc/snap + header that was removed. */ + hdr_chop = (u8 *) eth_hdr - (u8 *) local_rx_pd; + } else { + /* Chop off the rxpd */ + hdr_chop = (u8 *) &rx_pkt_hdr->eth803_hdr - + (u8 *) local_rx_pd; + } + + /* Chop off the leading header bytes so the it points to the start of + either the reconstructed EthII frame or the 802.2/llc/snap frame */ + skb_pull(skb, hdr_chop); + + priv->rxpd_rate = local_rx_pd->rx_rate; + + priv->rxpd_htinfo = local_rx_pd->ht_info; + + ret = mwifiex_recv_packet(adapter, skb); + if (ret == -1) + dev_err(adapter->dev, "recv packet failed\n"); + + return ret; +} + +/* + * This function processes the received buffer. + * + * The function looks into the RxPD and performs sanity tests on the + * received buffer to ensure its a valid packet, before processing it + * further. If the packet is determined to be aggregated, it is + * de-aggregated accordingly. Non-unicast packets are sent directly to + * the kernel/upper layers. Unicast packets are handed over to the + * Rx reordering routine if 11n is enabled. + * + * The completion callback is called after processing in complete. + */ +int mwifiex_process_sta_rx_packet(struct mwifiex_adapter *adapter, + struct sk_buff *skb) +{ + int ret = 0; + struct rxpd *local_rx_pd; + struct mwifiex_rxinfo *rx_info = MWIFIEX_SKB_RXCB(skb); + struct rx_packet_hdr *rx_pkt_hdr; + u8 ta[ETH_ALEN]; + u16 rx_pkt_type = 0; + struct mwifiex_private *priv = adapter->priv[rx_info->bss_index]; + + local_rx_pd = (struct rxpd *) (skb->data); + rx_pkt_type = local_rx_pd->rx_pkt_type; + + rx_pkt_hdr = (struct rx_packet_hdr *) ((u8 *) local_rx_pd + + local_rx_pd->rx_pkt_offset); + + if ((local_rx_pd->rx_pkt_offset + local_rx_pd->rx_pkt_length) > + (u16) skb->len) { + dev_err(adapter->dev, "wrong rx packet: len=%d," + " rx_pkt_offset=%d, rx_pkt_length=%d\n", skb->len, + local_rx_pd->rx_pkt_offset, local_rx_pd->rx_pkt_length); + priv->stats.rx_dropped++; + dev_kfree_skb_any(skb); + return ret; + } + if (local_rx_pd->rx_pkt_type == PKT_TYPE_AMSDU) { + mwifiex_11n_deaggregate_pkt(priv, skb); + return ret; + } + /* + * If the packet is not an unicast packet then send the packet + * directly to os. Don't pass thru rx reordering + */ + if (!IS_11N_ENABLED(priv) || + memcmp(priv->curr_addr, rx_pkt_hdr->eth803_hdr.h_dest, ETH_ALEN)) { + mwifiex_process_rx_packet(adapter, skb); + return ret; + } + + if (mwifiex_queuing_ra_based(priv)) { + memcpy(ta, rx_pkt_hdr->eth803_hdr.h_source, ETH_ALEN); + } else { + if (rx_pkt_type != PKT_TYPE_BAR) + priv->rx_seq[local_rx_pd->priority] = + local_rx_pd->seq_num; + memcpy(ta, priv->curr_bss_params.bss_descriptor.mac_address, + ETH_ALEN); + } + + /* Reorder and send to OS */ + ret = mwifiex_11n_rx_reorder_pkt(priv, local_rx_pd->seq_num, + local_rx_pd->priority, ta, + (u8) local_rx_pd->rx_pkt_type, + (void *) skb); + + if (ret || (rx_pkt_type == PKT_TYPE_BAR)) { + if (priv && (ret == -1)) + priv->stats.rx_dropped++; + + dev_kfree_skb_any(skb); + } + + return ret; +} diff --git a/drivers/net/wireless/mwifiex/sta_tx.c b/drivers/net/wireless/mwifiex/sta_tx.c new file mode 100644 index 0000000..e8db6bd --- /dev/null +++ b/drivers/net/wireless/mwifiex/sta_tx.c @@ -0,0 +1,202 @@ +/* + * Marvell Wireless LAN device driver: station TX data handling + * + * Copyright (C) 2011, Marvell International Ltd. + * + * This software file (the "File") is distributed by Marvell International + * Ltd. under the terms of the GNU General Public License Version 2, June 1991 + * (the "License"). You may use, redistribute and/or modify this File in + * accordance with the terms and conditions of the License, a copy of which + * is available by writing to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the + * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. + * + * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE + * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE + * ARE EXPRESSLY DISCLAIMED. The License provides additional details about + * this warranty disclaimer. + */ + +#include "decl.h" +#include "ioctl.h" +#include "util.h" +#include "fw.h" +#include "main.h" +#include "wmm.h" + +/* + * This function fills the TxPD for tx packets. + * + * The Tx buffer received by this function should already have the + * header space allocated for TxPD. + * + * This function inserts the TxPD in between interface header and actual + * data and adjusts the buffer pointers accordingly. + * + * The following TxPD fields are set by this function, as required - + * - BSS number + * - Tx packet length and offset + * - Priority + * - Packet delay + * - Priority specific Tx control + * - Flags + */ +void *mwifiex_process_sta_txpd(struct mwifiex_private *priv, + struct sk_buff *skb) +{ + struct mwifiex_adapter *adapter = priv->adapter; + struct txpd *local_tx_pd; + struct mwifiex_txinfo *tx_info = MWIFIEX_SKB_TXCB(skb); + + if (!skb->len) { + dev_err(adapter->dev, "Tx: bad packet length: %d\n", + skb->len); + tx_info->status_code = MWIFIEX_ERROR_PKT_SIZE_INVALID; + return skb->data; + } + + BUG_ON(skb_headroom(skb) < (sizeof(*local_tx_pd) + INTF_HEADER_LEN)); + skb_push(skb, sizeof(*local_tx_pd)); + + local_tx_pd = (struct txpd *) skb->data; + memset(local_tx_pd, 0, sizeof(struct txpd)); + local_tx_pd->bss_num = priv->bss_num; + local_tx_pd->bss_type = priv->bss_type; + local_tx_pd->tx_pkt_length = cpu_to_le16((u16) (skb->len - + sizeof(struct txpd))); + + local_tx_pd->priority = (u8) skb->priority; + local_tx_pd->pkt_delay_2ms = + mwifiex_wmm_compute_drv_pkt_delay(priv, skb); + + if (local_tx_pd->priority < + ARRAY_SIZE(priv->wmm.user_pri_pkt_tx_ctrl)) + /* + * Set the priority specific tx_control field, setting of 0 will + * cause the default value to be used later in this function + */ + local_tx_pd->tx_control = + cpu_to_le32(priv->wmm.user_pri_pkt_tx_ctrl[local_tx_pd-> + priority]); + + if (adapter->pps_uapsd_mode) { + if (mwifiex_check_last_packet_indication(priv)) { + adapter->tx_lock_flag = true; + local_tx_pd->flags = + MWIFIEX_TxPD_POWER_MGMT_LAST_PACKET; + } + } + + /* Offset of actual data */ + local_tx_pd->tx_pkt_offset = cpu_to_le16(sizeof(struct txpd)); + + /* make space for INTF_HEADER_LEN */ + skb_push(skb, INTF_HEADER_LEN); + + if (!local_tx_pd->tx_control) + /* TxCtrl set by user or default */ + local_tx_pd->tx_control = cpu_to_le32(priv->pkt_tx_ctrl); + + return skb->data; +} + +/* + * This function tells firmware to send a NULL data packet. + * + * The function creates a NULL data packet with TxPD and sends to the + * firmware for transmission, with highest priority setting. + */ +int mwifiex_send_null_packet(struct mwifiex_private *priv, u8 flags) +{ + struct mwifiex_adapter *adapter = priv->adapter; + struct txpd *local_tx_pd; +/* sizeof(struct txpd) + Interface specific header */ +#define NULL_PACKET_HDR 64 + u32 data_len = NULL_PACKET_HDR; + struct sk_buff *skb = NULL; + int ret = 0; + struct mwifiex_txinfo *tx_info = NULL; + + if (adapter->surprise_removed) + return -1; + + if (!priv->media_connected) + return -1; + + if (adapter->data_sent) + return -1; + + skb = dev_alloc_skb(data_len); + if (!skb) + return -1; + + tx_info = MWIFIEX_SKB_TXCB(skb); + tx_info->bss_index = priv->bss_index; + skb_reserve(skb, sizeof(struct txpd) + INTF_HEADER_LEN); + skb_push(skb, sizeof(struct txpd)); + + local_tx_pd = (struct txpd *) skb->data; + local_tx_pd->tx_control = cpu_to_le32(priv->pkt_tx_ctrl); + local_tx_pd->flags = flags; + local_tx_pd->priority = WMM_HIGHEST_PRIORITY; + local_tx_pd->tx_pkt_offset = cpu_to_le16(sizeof(struct txpd)); + local_tx_pd->bss_num = priv->bss_num; + local_tx_pd->bss_type = priv->bss_type; + + skb_push(skb, INTF_HEADER_LEN); + + ret = adapter->if_ops.host_to_card(adapter, MWIFIEX_TYPE_DATA, + skb->data, skb->len, NULL); + switch (ret) { + case -EBUSY: + adapter->data_sent = true; + /* Fall through FAILURE handling */ + case -1: + dev_kfree_skb_any(skb); + dev_err(adapter->dev, "%s: host_to_card failed: ret=%d\n", + __func__, ret); + adapter->dbg.num_tx_host_to_card_failure++; + break; + case 0: + dev_kfree_skb_any(skb); + dev_dbg(adapter->dev, "data: %s: host_to_card succeeded\n", + __func__); + adapter->tx_lock_flag = true; + break; + case -EINPROGRESS: + break; + default: + break; + } + + return ret; +} + +/* + * This function checks if we need to send last packet indication. + */ +u8 +mwifiex_check_last_packet_indication(struct mwifiex_private *priv) +{ + struct mwifiex_adapter *adapter = priv->adapter; + u8 ret = false; + u8 prop_ps = true; + + if (!adapter->sleep_period.period) + return ret; + if (mwifiex_wmm_lists_empty(adapter)) { + if ((priv->curr_bss_params.wmm_uapsd_enabled && + priv->wmm_qosinfo) || prop_ps) + ret = true; + } + + if (ret && !adapter->cmd_sent && !adapter->curr_cmd + && !is_command_pending(adapter)) { + adapter->delay_null_pkt = false; + ret = true; + } else { + ret = false; + adapter->delay_null_pkt = true; + } + return ret; +} diff --git a/drivers/net/wireless/mwifiex/txrx.c b/drivers/net/wireless/mwifiex/txrx.c new file mode 100644 index 0000000..f06923c --- /dev/null +++ b/drivers/net/wireless/mwifiex/txrx.c @@ -0,0 +1,202 @@ +/* + * Marvell Wireless LAN device driver: generic TX/RX data handling + * + * Copyright (C) 2011, Marvell International Ltd. + * + * This software file (the "File") is distributed by Marvell International + * Ltd. under the terms of the GNU General Public License Version 2, June 1991 + * (the "License"). You may use, redistribute and/or modify this File in + * accordance with the terms and conditions of the License, a copy of which + * is available by writing to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the + * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. + * + * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE + * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE + * ARE EXPRESSLY DISCLAIMED. The License provides additional details about + * this warranty disclaimer. + */ + +#include "decl.h" +#include "ioctl.h" +#include "util.h" +#include "fw.h" +#include "main.h" +#include "wmm.h" + +/* + * This function processes the received buffer. + * + * Main responsibility of this function is to parse the RxPD to + * identify the correct interface this packet is headed for and + * forwarding it to the associated handling function, where the + * packet will be further processed and sent to kernel/upper layer + * if required. + */ +int mwifiex_handle_rx_packet(struct mwifiex_adapter *adapter, + struct sk_buff *skb) +{ + int ret = 0; + struct mwifiex_private *priv = + mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_ANY); + struct rxpd *local_rx_pd; + struct mwifiex_rxinfo *rx_info = MWIFIEX_SKB_RXCB(skb); + + local_rx_pd = (struct rxpd *) (skb->data); + /* Get the BSS number from rxpd, get corresponding priv */ + priv = mwifiex_get_priv_by_id(adapter, local_rx_pd->bss_num & + BSS_NUM_MASK, local_rx_pd->bss_type); + if (!priv) + priv = mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_ANY); + + rx_info->bss_index = priv->bss_index; + ret = mwifiex_process_sta_rx_packet(adapter, skb); + + return ret; +} +EXPORT_SYMBOL_GPL(mwifiex_handle_rx_packet); + +/* + * This function sends a packet to device. + * + * It processes the packet to add the TxPD, checks condition and + * sends the processed packet to firmware for transmission. + * + * On successful completion, the function calls the completion callback + * and logs the time. + */ +int mwifiex_process_tx(struct mwifiex_private *priv, struct sk_buff *skb, + struct mwifiex_tx_param *tx_param) +{ + int ret = -1; + struct mwifiex_adapter *adapter = priv->adapter; + u8 *head_ptr = NULL; + struct txpd *local_tx_pd = NULL; + + head_ptr = (u8 *) mwifiex_process_sta_txpd(priv, skb); + if (head_ptr) { + if (GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_STA) + local_tx_pd = + (struct txpd *) (head_ptr + INTF_HEADER_LEN); + + ret = adapter->if_ops.host_to_card(adapter, MWIFIEX_TYPE_DATA, + skb->data, skb->len, tx_param); + } + + switch (ret) { + case -EBUSY: + if ((GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_STA) && + (adapter->pps_uapsd_mode) && + (adapter->tx_lock_flag)) { + priv->adapter->tx_lock_flag = false; + local_tx_pd->flags = 0; + } + dev_dbg(adapter->dev, "data: -EBUSY is returned\n"); + break; + case -1: + adapter->data_sent = false; + dev_err(adapter->dev, "mwifiex_write_data_async failed: 0x%X\n", + ret); + adapter->dbg.num_tx_host_to_card_failure++; + mwifiex_write_data_complete(adapter, skb, ret); + break; + case -EINPROGRESS: + adapter->data_sent = false; + break; + case 0: + mwifiex_write_data_complete(adapter, skb, ret); + break; + default: + break; + } + + return ret; +} + +/* + * Packet send completion callback handler. + * + * It either frees the buffer directly or forwards it to another + * completion callback which checks conditions, updates statistics, + * wakes up stalled traffic queue if required, and then frees the buffer. + */ +int mwifiex_write_data_complete(struct mwifiex_adapter *adapter, + struct sk_buff *skb, int status) +{ + struct mwifiex_private *priv = NULL, *tpriv = NULL; + struct mwifiex_txinfo *tx_info = NULL; + int i; + + if (!skb) + return 0; + + tx_info = MWIFIEX_SKB_TXCB(skb); + priv = mwifiex_bss_index_to_priv(adapter, tx_info->bss_index); + if (!priv) + goto done; + + priv->netdev->trans_start = jiffies; + if (!status) { + priv->stats.tx_packets++; + priv->stats.tx_bytes += skb->len; + } else { + priv->stats.tx_errors++; + } + atomic_dec(&adapter->tx_pending); + + for (i = 0; i < adapter->priv_num; i++) { + + tpriv = adapter->priv[i]; + + if ((GET_BSS_ROLE(tpriv) == MWIFIEX_BSS_ROLE_STA) + && (tpriv->media_connected)) { + if (netif_queue_stopped(tpriv->netdev)) + netif_wake_queue(tpriv->netdev); + } + } +done: + dev_kfree_skb_any(skb); + + return 0; +} + +/* + * Packet receive completion callback handler. + * + * This function calls another completion callback handler which + * updates the statistics, and optionally updates the parent buffer + * use count before freeing the received packet. + */ +int mwifiex_recv_packet_complete(struct mwifiex_adapter *adapter, + struct sk_buff *skb, int status) +{ + struct mwifiex_rxinfo *rx_info = MWIFIEX_SKB_RXCB(skb); + struct mwifiex_rxinfo *rx_info_parent = NULL; + struct mwifiex_private *priv; + struct sk_buff *skb_parent = NULL; + unsigned long flags; + + priv = adapter->priv[rx_info->bss_index]; + + if (priv && (status == -1)) + priv->stats.rx_dropped++; + + if (rx_info->parent) { + skb_parent = rx_info->parent; + rx_info_parent = MWIFIEX_SKB_RXCB(skb_parent); + + spin_lock_irqsave(&priv->rx_pkt_lock, flags); + --rx_info_parent->use_count; + + if (!rx_info_parent->use_count) { + spin_unlock_irqrestore(&priv->rx_pkt_lock, flags); + dev_kfree_skb_any(skb_parent); + } else { + spin_unlock_irqrestore(&priv->rx_pkt_lock, flags); + } + } else { + dev_kfree_skb_any(skb); + } + + return 0; +} diff --git a/drivers/net/wireless/mwifiex/util.c b/drivers/net/wireless/mwifiex/util.c new file mode 100644 index 0000000..205022a --- /dev/null +++ b/drivers/net/wireless/mwifiex/util.c @@ -0,0 +1,252 @@ +/* + * Marvell Wireless LAN device driver: utility functions + * + * Copyright (C) 2011, Marvell International Ltd. + * + * This software file (the "File") is distributed by Marvell International + * Ltd. under the terms of the GNU General Public License Version 2, June 1991 + * (the "License"). You may use, redistribute and/or modify this File in + * accordance with the terms and conditions of the License, a copy of which + * is available by writing to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the + * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. + * + * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE + * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE + * ARE EXPRESSLY DISCLAIMED. The License provides additional details about + * this warranty disclaimer. + */ + +#include "decl.h" +#include "ioctl.h" +#include "util.h" +#include "fw.h" +#include "main.h" +#include "wmm.h" +#include "11n.h" + +/* + * Firmware initialization complete callback handler. + * + * This function wakes up the function waiting on the init + * wait queue for the firmware initialization to complete. + */ +int mwifiex_init_fw_complete(struct mwifiex_adapter *adapter) +{ + + adapter->init_wait_q_woken = true; + wake_up_interruptible(&adapter->init_wait_q); + return 0; +} + +/* + * Firmware shutdown complete callback handler. + * + * This function sets the hardware status to not ready and wakes up + * the function waiting on the init wait queue for the firmware + * shutdown to complete. + */ +int mwifiex_shutdown_fw_complete(struct mwifiex_adapter *adapter) +{ + adapter->hw_status = MWIFIEX_HW_STATUS_NOT_READY; + adapter->init_wait_q_woken = true; + wake_up_interruptible(&adapter->init_wait_q); + return 0; +} + +/* + * IOCTL request handler to send function init/shutdown command + * to firmware. + * + * This function prepares the correct firmware command and + * issues it. + */ +int mwifiex_misc_ioctl_init_shutdown(struct mwifiex_adapter *adapter, + struct mwifiex_wait_queue *wait, + u32 func_init_shutdown) +{ + struct mwifiex_private *priv = adapter->priv[wait->bss_index]; + int ret; + u16 cmd; + + if (func_init_shutdown == MWIFIEX_FUNC_INIT) { + cmd = HostCmd_CMD_FUNC_INIT; + } else if (func_init_shutdown == MWIFIEX_FUNC_SHUTDOWN) { + cmd = HostCmd_CMD_FUNC_SHUTDOWN; + } else { + dev_err(adapter->dev, "unsupported parameter\n"); + return -1; + } + + /* Send command to firmware */ + ret = mwifiex_prepare_cmd(priv, cmd, HostCmd_ACT_GEN_SET, + 0, wait, NULL); + + if (!ret) + ret = -EINPROGRESS; + + return ret; +} + +/* + * IOCTL request handler to set/get debug information. + * + * This function collates/sets the information from/to different driver + * structures. + */ +int mwifiex_get_debug_info(struct mwifiex_private *priv, + struct mwifiex_debug_info *info) +{ + struct mwifiex_adapter *adapter = priv->adapter; + + if (info) { + memcpy(info->packets_out, + priv->wmm.packets_out, + sizeof(priv->wmm.packets_out)); + info->max_tx_buf_size = (u32) adapter->max_tx_buf_size; + info->tx_buf_size = (u32) adapter->tx_buf_size; + info->rx_tbl_num = mwifiex_get_rx_reorder_tbl( + priv, info->rx_tbl); + info->tx_tbl_num = mwifiex_get_tx_ba_stream_tbl( + priv, info->tx_tbl); + info->ps_mode = adapter->ps_mode; + info->ps_state = adapter->ps_state; + info->is_deep_sleep = adapter->is_deep_sleep; + info->pm_wakeup_card_req = adapter->pm_wakeup_card_req; + info->pm_wakeup_fw_try = adapter->pm_wakeup_fw_try; + info->is_hs_configured = adapter->is_hs_configured; + info->hs_activated = adapter->hs_activated; + info->num_cmd_host_to_card_failure + = adapter->dbg.num_cmd_host_to_card_failure; + info->num_cmd_sleep_cfm_host_to_card_failure + = adapter->dbg.num_cmd_sleep_cfm_host_to_card_failure; + info->num_tx_host_to_card_failure + = adapter->dbg.num_tx_host_to_card_failure; + info->num_event_deauth = adapter->dbg.num_event_deauth; + info->num_event_disassoc = adapter->dbg.num_event_disassoc; + info->num_event_link_lost = adapter->dbg.num_event_link_lost; + info->num_cmd_deauth = adapter->dbg.num_cmd_deauth; + info->num_cmd_assoc_success = + adapter->dbg.num_cmd_assoc_success; + info->num_cmd_assoc_failure = + adapter->dbg.num_cmd_assoc_failure; + info->num_tx_timeout = adapter->dbg.num_tx_timeout; + info->num_cmd_timeout = adapter->dbg.num_cmd_timeout; + info->timeout_cmd_id = adapter->dbg.timeout_cmd_id; + info->timeout_cmd_act = adapter->dbg.timeout_cmd_act; + memcpy(info->last_cmd_id, adapter->dbg.last_cmd_id, + sizeof(adapter->dbg.last_cmd_id)); + memcpy(info->last_cmd_act, adapter->dbg.last_cmd_act, + sizeof(adapter->dbg.last_cmd_act)); + info->last_cmd_index = adapter->dbg.last_cmd_index; + memcpy(info->last_cmd_resp_id, adapter->dbg.last_cmd_resp_id, + sizeof(adapter->dbg.last_cmd_resp_id)); + info->last_cmd_resp_index = adapter->dbg.last_cmd_resp_index; + memcpy(info->last_event, adapter->dbg.last_event, + sizeof(adapter->dbg.last_event)); + info->last_event_index = adapter->dbg.last_event_index; + info->data_sent = adapter->data_sent; + info->cmd_sent = adapter->cmd_sent; + info->cmd_resp_received = adapter->cmd_resp_received; + } + + return 0; +} + +/* + * This function processes the received packet before sending it to the + * kernel. + * + * It extracts the SKB from the received buffer and sends it to kernel. + * In case the received buffer does not contain the data in SKB format, + * the function creates a blank SKB, fills it with the data from the + * received buffer and then sends this new SKB to the kernel. + */ +int mwifiex_recv_packet(struct mwifiex_adapter *adapter, struct sk_buff *skb) +{ + struct mwifiex_rxinfo *rx_info = NULL; + struct mwifiex_private *priv = NULL; + + if (!skb) + return -1; + + rx_info = MWIFIEX_SKB_RXCB(skb); + priv = mwifiex_bss_index_to_priv(adapter, rx_info->bss_index); + if (!priv) + return -1; + + skb->dev = priv->netdev; + skb->protocol = eth_type_trans(skb, priv->netdev); + skb->ip_summed = CHECKSUM_NONE; + priv->stats.rx_bytes += skb->len; + priv->stats.rx_packets++; + if (in_interrupt()) + netif_rx(skb); + else + netif_rx_ni(skb); + + return 0; +} + +/* + * Receive packet completion callback handler. + * + * This function updates the statistics and frees the buffer SKB. + */ +int mwifiex_recv_complete(struct mwifiex_adapter *adapter, + struct sk_buff *skb, int status) +{ + struct mwifiex_private *priv = NULL; + struct mwifiex_rxinfo *rx_info = NULL; + + if (!skb) + return 0; + + rx_info = MWIFIEX_SKB_RXCB(skb); + priv = mwifiex_bss_index_to_priv(adapter, rx_info->bss_index); + + if (priv && (status == -1)) + priv->stats.rx_dropped++; + + dev_kfree_skb_any(skb); + + return 0; +} + +/* + * IOCTL completion callback handler. + * + * This function is called when a pending IOCTL is completed. + * + * If work queue support is enabled, the function wakes up the + * corresponding waiting function. Otherwise, it processes the + * IOCTL response and frees the response buffer. + */ +int mwifiex_ioctl_complete(struct mwifiex_adapter *adapter, + struct mwifiex_wait_queue *wait_queue, + int status) +{ + enum mwifiex_error_code status_code = + (enum mwifiex_error_code) wait_queue->status; + + atomic_dec(&adapter->ioctl_pending); + + dev_dbg(adapter->dev, "cmd: IOCTL completed: status=%d," + " status_code=%#x\n", status, status_code); + + if (wait_queue->enabled) { + *wait_queue->condition = true; + wait_queue->status = status; + if (status && (status_code == MWIFIEX_ERROR_CMD_TIMEOUT)) + dev_err(adapter->dev, "cmd timeout\n"); + else + wake_up_interruptible(wait_queue->wait); + } else { + if (status) + dev_err(adapter->dev, "cmd failed: status_code=%#x\n", + status_code); + kfree(wait_queue); + } + + return 0; +} diff --git a/drivers/net/wireless/mwifiex/util.h b/drivers/net/wireless/mwifiex/util.h new file mode 100644 index 0000000..9506afc --- /dev/null +++ b/drivers/net/wireless/mwifiex/util.h @@ -0,0 +1,32 @@ +/* + * Marvell Wireless LAN device driver: utility functions + * + * Copyright (C) 2011, Marvell International Ltd. + * + * This software file (the "File") is distributed by Marvell International + * Ltd. under the terms of the GNU General Public License Version 2, June 1991 + * (the "License"). You may use, redistribute and/or modify this File in + * accordance with the terms and conditions of the License, a copy of which + * is available by writing to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the + * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. + * + * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE + * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE + * ARE EXPRESSLY DISCLAIMED. The License provides additional details about + * this warranty disclaimer. + */ + +#ifndef _MWIFIEX_UTIL_H_ +#define _MWIFIEX_UTIL_H_ + +static inline struct mwifiex_rxinfo *MWIFIEX_SKB_RXCB(struct sk_buff *skb) +{ + return (struct mwifiex_rxinfo *)skb->cb; +} + +static inline struct mwifiex_txinfo *MWIFIEX_SKB_TXCB(struct sk_buff *skb) +{ + return (struct mwifiex_txinfo *)skb->cb; +} +#endif /* !_MWIFIEX_UTIL_H_ */ diff --git a/drivers/net/wireless/mwifiex/wmm.c b/drivers/net/wireless/mwifiex/wmm.c new file mode 100644 index 0000000..1cfbc6b --- /dev/null +++ b/drivers/net/wireless/mwifiex/wmm.c @@ -0,0 +1,1237 @@ +/* + * Marvell Wireless LAN device driver: WMM + * + * Copyright (C) 2011, Marvell International Ltd. + * + * This software file (the "File") is distributed by Marvell International + * Ltd. under the terms of the GNU General Public License Version 2, June 1991 + * (the "License"). You may use, redistribute and/or modify this File in + * accordance with the terms and conditions of the License, a copy of which + * is available by writing to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the + * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. + * + * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE + * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE + * ARE EXPRESSLY DISCLAIMED. The License provides additional details about + * this warranty disclaimer. + */ + +#include "decl.h" +#include "ioctl.h" +#include "util.h" +#include "fw.h" +#include "main.h" +#include "wmm.h" +#include "11n.h" + + +/* Maximum value FW can accept for driver delay in packet transmission */ +#define DRV_PKT_DELAY_TO_FW_MAX 512 + + +#define WMM_QUEUED_PACKET_LOWER_LIMIT 180 + +#define WMM_QUEUED_PACKET_UPPER_LIMIT 200 + +/* Offset for TOS field in the IP header */ +#define IPTOS_OFFSET 5 + +/* WMM information IE */ +static const u8 wmm_info_ie[] = { WLAN_EID_VENDOR_SPECIFIC, 0x07, + 0x00, 0x50, 0xf2, 0x02, + 0x00, 0x01, 0x00 +}; + +static const u8 wmm_aci_to_qidx_map[] = { WMM_AC_BE, + WMM_AC_BK, + WMM_AC_VI, + WMM_AC_VO +}; + +static u8 tos_to_tid[] = { + /* TID DSCP_P2 DSCP_P1 DSCP_P0 WMM_AC */ + 0x01, /* 0 1 0 AC_BK */ + 0x02, /* 0 0 0 AC_BK */ + 0x00, /* 0 0 1 AC_BE */ + 0x03, /* 0 1 1 AC_BE */ + 0x04, /* 1 0 0 AC_VI */ + 0x05, /* 1 0 1 AC_VI */ + 0x06, /* 1 1 0 AC_VO */ + 0x07 /* 1 1 1 AC_VO */ +}; + +/* + * This table inverses the tos_to_tid operation to get a priority + * which is in sequential order, and can be compared. + * Use this to compare the priority of two different TIDs. + */ +static u8 tos_to_tid_inv[] = { + 0x02, /* from tos_to_tid[2] = 0 */ + 0x00, /* from tos_to_tid[0] = 1 */ + 0x01, /* from tos_to_tid[1] = 2 */ + 0x03, + 0x04, + 0x05, + 0x06, + 0x07}; + +static u8 ac_to_tid[4][2] = { {1, 2}, {0, 3}, {4, 5}, {6, 7} }; + +/* + * This function debug prints the priority parameters for a WMM AC. + */ +static void +mwifiex_wmm_ac_debug_print(const struct ieee_types_wmm_ac_parameters *ac_param) +{ + const char *ac_str[] = { "BK", "BE", "VI", "VO" }; + + pr_debug("info: WMM AC_%s: ACI=%d, ACM=%d, Aifsn=%d, " + "EcwMin=%d, EcwMax=%d, TxopLimit=%d\n", + ac_str[wmm_aci_to_qidx_map[(ac_param->aci_aifsn_bitmap + & MWIFIEX_ACI) >> 5]], + (ac_param->aci_aifsn_bitmap & MWIFIEX_ACI) >> 5, + (ac_param->aci_aifsn_bitmap & MWIFIEX_ACM) >> 4, + ac_param->aci_aifsn_bitmap & MWIFIEX_AIFSN, + ac_param->ecw_bitmap & MWIFIEX_ECW_MIN, + (ac_param->ecw_bitmap & MWIFIEX_ECW_MAX) >> 4, + le16_to_cpu(ac_param->tx_op_limit)); +} + +/* + * This function allocates a route address list. + * + * The function also initializes the list with the provided RA. + */ +static struct mwifiex_ra_list_tbl * +mwifiex_wmm_allocate_ralist_node(struct mwifiex_adapter *adapter, u8 *ra) +{ + struct mwifiex_ra_list_tbl *ra_list; + + ra_list = kzalloc(sizeof(struct mwifiex_ra_list_tbl), GFP_ATOMIC); + + if (!ra_list) { + dev_err(adapter->dev, "%s: failed to alloc ra_list\n", + __func__); + return NULL; + } + INIT_LIST_HEAD(&ra_list->list); + skb_queue_head_init(&ra_list->skb_head); + + memcpy(ra_list->ra, ra, ETH_ALEN); + + ra_list->total_pkts_size = 0; + + dev_dbg(adapter->dev, "info: allocated ra_list %p\n", ra_list); + + return ra_list; +} + +/* + * This function allocates and adds a RA list for all TIDs + * with the given RA. + */ +void +mwifiex_ralist_add(struct mwifiex_private *priv, u8 *ra) +{ + int i; + struct mwifiex_ra_list_tbl *ra_list; + struct mwifiex_adapter *adapter = priv->adapter; + + for (i = 0; i < MAX_NUM_TID; ++i) { + ra_list = mwifiex_wmm_allocate_ralist_node(adapter, ra); + dev_dbg(adapter->dev, "info: created ra_list %p\n", ra_list); + + if (!ra_list) + break; + + if (!mwifiex_queuing_ra_based(priv)) + ra_list->is_11n_enabled = IS_11N_ENABLED(priv); + else + ra_list->is_11n_enabled = false; + + dev_dbg(adapter->dev, "data: ralist %p: is_11n_enabled=%d\n", + ra_list, ra_list->is_11n_enabled); + + list_add_tail(&ra_list->list, + &priv->wmm.tid_tbl_ptr[i].ra_list); + + if (!priv->wmm.tid_tbl_ptr[i].ra_list_curr) + priv->wmm.tid_tbl_ptr[i].ra_list_curr = ra_list; + } +} + +/* + * This function sets the WMM queue priorities to their default values. + */ +static void mwifiex_wmm_default_queue_priorities(struct mwifiex_private *priv) +{ + /* Default queue priorities: VO->VI->BE->BK */ + priv->wmm.queue_priority[0] = WMM_AC_VO; + priv->wmm.queue_priority[1] = WMM_AC_VI; + priv->wmm.queue_priority[2] = WMM_AC_BE; + priv->wmm.queue_priority[3] = WMM_AC_BK; +} + +/* + * This function map ACs to TIDs. + */ +static void +mwifiex_wmm_queue_priorities_tid(struct mwifiex_private *priv, + u8 queue_priority[]) +{ + int i; + + for (i = 0; i < 4; ++i) { + tos_to_tid[7 - (i * 2)] = ac_to_tid[queue_priority[i]][1]; + tos_to_tid[6 - (i * 2)] = ac_to_tid[queue_priority[i]][0]; + } +} + +/* + * This function initializes WMM priority queues. + */ +void +mwifiex_wmm_setup_queue_priorities(struct mwifiex_private *priv, + struct ieee_types_wmm_parameter *wmm_ie) +{ + u16 cw_min, avg_back_off, tmp[4]; + u32 i, j, num_ac; + u8 ac_idx; + + if (!wmm_ie || !priv->wmm_enabled) { + /* WMM is not enabled, just set the defaults and return */ + mwifiex_wmm_default_queue_priorities(priv); + return; + } + + dev_dbg(priv->adapter->dev, "info: WMM Parameter IE: version=%d, " + "qos_info Parameter Set Count=%d, Reserved=%#x\n", + wmm_ie->vend_hdr.version, wmm_ie->qos_info_bitmap & + IEEE80211_WMM_IE_AP_QOSINFO_PARAM_SET_CNT_MASK, + wmm_ie->reserved); + + for (num_ac = 0; num_ac < ARRAY_SIZE(wmm_ie->ac_params); num_ac++) { + cw_min = (1 << (wmm_ie->ac_params[num_ac].ecw_bitmap & + MWIFIEX_ECW_MIN)) - 1; + avg_back_off = (cw_min >> 1) + + (wmm_ie->ac_params[num_ac].aci_aifsn_bitmap & + MWIFIEX_AIFSN); + + ac_idx = wmm_aci_to_qidx_map[(wmm_ie->ac_params[num_ac]. + aci_aifsn_bitmap & + MWIFIEX_ACI) >> 5]; + priv->wmm.queue_priority[ac_idx] = ac_idx; + tmp[ac_idx] = avg_back_off; + + dev_dbg(priv->adapter->dev, "info: WMM: CWmax=%d CWmin=%d Avg Back-off=%d\n", + (1 << ((wmm_ie->ac_params[num_ac].ecw_bitmap & + MWIFIEX_ECW_MAX) >> 4)) - 1, + cw_min, avg_back_off); + mwifiex_wmm_ac_debug_print(&wmm_ie->ac_params[num_ac]); + } + + /* Bubble sort */ + for (i = 0; i < num_ac; i++) { + for (j = 1; j < num_ac - i; j++) { + if (tmp[j - 1] > tmp[j]) { + swap(tmp[j - 1], tmp[j]); + swap(priv->wmm.queue_priority[j - 1], + priv->wmm.queue_priority[j]); + } else if (tmp[j - 1] == tmp[j]) { + if (priv->wmm.queue_priority[j - 1] + < priv->wmm.queue_priority[j]) + swap(priv->wmm.queue_priority[j - 1], + priv->wmm.queue_priority[j]); + } + } + } + + mwifiex_wmm_queue_priorities_tid(priv, priv->wmm.queue_priority); +} + +/* + * This function evaluates whether or not an AC is to be downgraded. + * + * In case the AC is not enabled, the highest AC is returned that is + * enabled and does not require admission control. + */ +static enum mwifiex_wmm_ac_e +mwifiex_wmm_eval_downgrade_ac(struct mwifiex_private *priv, + enum mwifiex_wmm_ac_e eval_ac) +{ + int down_ac; + enum mwifiex_wmm_ac_e ret_ac; + struct mwifiex_wmm_ac_status *ac_status; + + ac_status = &priv->wmm.ac_status[eval_ac]; + + if (!ac_status->disabled) + /* Okay to use this AC, its enabled */ + return eval_ac; + + /* Setup a default return value of the lowest priority */ + ret_ac = WMM_AC_BK; + + /* + * Find the highest AC that is enabled and does not require + * admission control. The spec disallows downgrading to an AC, + * which is enabled due to a completed admission control. + * Unadmitted traffic is not to be sent on an AC with admitted + * traffic. + */ + for (down_ac = WMM_AC_BK; down_ac < eval_ac; down_ac++) { + ac_status = &priv->wmm.ac_status[down_ac]; + + if (!ac_status->disabled && !ac_status->flow_required) + /* AC is enabled and does not require admission + control */ + ret_ac = (enum mwifiex_wmm_ac_e) down_ac; + } + + return ret_ac; +} + +/* + * This function downgrades WMM priority queue. + */ +void +mwifiex_wmm_setup_ac_downgrade(struct mwifiex_private *priv) +{ + int ac_val; + + dev_dbg(priv->adapter->dev, "info: WMM: AC Priorities:" + "BK(0), BE(1), VI(2), VO(3)\n"); + + if (!priv->wmm_enabled) { + /* WMM is not enabled, default priorities */ + for (ac_val = WMM_AC_BK; ac_val <= WMM_AC_VO; ac_val++) + priv->wmm.ac_down_graded_vals[ac_val] = + (enum mwifiex_wmm_ac_e) ac_val; + } else { + for (ac_val = WMM_AC_BK; ac_val <= WMM_AC_VO; ac_val++) { + priv->wmm.ac_down_graded_vals[ac_val] + = mwifiex_wmm_eval_downgrade_ac(priv, + (enum mwifiex_wmm_ac_e) ac_val); + dev_dbg(priv->adapter->dev, "info: WMM: AC PRIO %d maps to %d\n", + ac_val, priv->wmm.ac_down_graded_vals[ac_val]); + } + } +} + +/* + * This function converts the IP TOS field to an WMM AC + * Queue assignment. + */ +static enum mwifiex_wmm_ac_e +mwifiex_wmm_convert_tos_to_ac(struct mwifiex_adapter *adapter, u32 tos) +{ + /* Map of TOS UP values to WMM AC */ + const enum mwifiex_wmm_ac_e tos_to_ac[] = { WMM_AC_BE, + WMM_AC_BK, + WMM_AC_BK, + WMM_AC_BE, + WMM_AC_VI, + WMM_AC_VI, + WMM_AC_VO, + WMM_AC_VO + }; + + if (tos >= ARRAY_SIZE(tos_to_ac)) + return WMM_AC_BE; + + return tos_to_ac[tos]; +} + +/* + * This function evaluates a given TID and downgrades it to a lower + * TID if the WMM Parameter IE received from the AP indicates that the + * AP is disabled (due to call admission control (ACM bit). Mapping + * of TID to AC is taken care of internally. + */ +static u8 +mwifiex_wmm_downgrade_tid(struct mwifiex_private *priv, u32 tid) +{ + enum mwifiex_wmm_ac_e ac, ac_down; + u8 new_tid; + + ac = mwifiex_wmm_convert_tos_to_ac(priv->adapter, tid); + ac_down = priv->wmm.ac_down_graded_vals[ac]; + + /* Send the index to tid array, picking from the array will be + * taken care by dequeuing function + */ + new_tid = ac_to_tid[ac_down][tid % 2]; + + return new_tid; +} + +/* + * This function initializes the WMM state information and the + * WMM data path queues. + */ +void +mwifiex_wmm_init(struct mwifiex_adapter *adapter) +{ + int i, j; + struct mwifiex_private *priv; + + for (j = 0; j < adapter->priv_num; ++j) { + priv = adapter->priv[j]; + if (!priv) + continue; + + for (i = 0; i < MAX_NUM_TID; ++i) { + priv->aggr_prio_tbl[i].amsdu = tos_to_tid_inv[i]; + priv->aggr_prio_tbl[i].ampdu_ap = tos_to_tid_inv[i]; + priv->aggr_prio_tbl[i].ampdu_user = tos_to_tid_inv[i]; + priv->wmm.tid_tbl_ptr[i].ra_list_curr = NULL; + } + + priv->aggr_prio_tbl[6].amsdu + = priv->aggr_prio_tbl[6].ampdu_ap + = priv->aggr_prio_tbl[6].ampdu_user + = BA_STREAM_NOT_ALLOWED; + + priv->aggr_prio_tbl[7].amsdu = priv->aggr_prio_tbl[7].ampdu_ap + = priv->aggr_prio_tbl[7].ampdu_user + = BA_STREAM_NOT_ALLOWED; + + priv->add_ba_param.timeout = MWIFIEX_DEFAULT_BLOCK_ACK_TIMEOUT; + priv->add_ba_param.tx_win_size = MWIFIEX_AMPDU_DEF_TXWINSIZE; + priv->add_ba_param.rx_win_size = MWIFIEX_AMPDU_DEF_RXWINSIZE; + } +} + +/* + * This function checks if WMM Tx queue is empty. + */ +int +mwifiex_wmm_lists_empty(struct mwifiex_adapter *adapter) +{ + int i, j; + struct mwifiex_private *priv; + + for (j = 0; j < adapter->priv_num; ++j) { + priv = adapter->priv[j]; + if (priv) { + for (i = 0; i < MAX_NUM_TID; i++) + if (!mwifiex_wmm_is_ra_list_empty(adapter, + &priv->wmm.tid_tbl_ptr[i].ra_list)) + return false; + } + } + + return true; +} + +/* + * This function deletes all packets in an RA list node. + * + * The packet sent completion callback handler are called with + * status failure, after they are dequeued to ensure proper + * cleanup. The RA list node itself is freed at the end. + */ +static void +mwifiex_wmm_del_pkts_in_ralist_node(struct mwifiex_private *priv, + struct mwifiex_ra_list_tbl *ra_list) +{ + struct mwifiex_adapter *adapter = priv->adapter; + struct sk_buff *skb, *tmp; + + skb_queue_walk_safe(&ra_list->skb_head, skb, tmp) + mwifiex_write_data_complete(adapter, skb, -1); +} + +/* + * This function deletes all packets in an RA list. + * + * Each nodes in the RA list are freed individually first, and then + * the RA list itself is freed. + */ +static void +mwifiex_wmm_del_pkts_in_ralist(struct mwifiex_private *priv, + struct list_head *ra_list_head) +{ + struct mwifiex_ra_list_tbl *ra_list; + + list_for_each_entry(ra_list, ra_list_head, list) + mwifiex_wmm_del_pkts_in_ralist_node(priv, ra_list); +} + +/* + * This function deletes all packets in all RA lists. + */ +static void mwifiex_wmm_cleanup_queues(struct mwifiex_private *priv) +{ + int i; + + for (i = 0; i < MAX_NUM_TID; i++) + mwifiex_wmm_del_pkts_in_ralist(priv, &priv->wmm.tid_tbl_ptr[i]. + ra_list); +} + +/* + * This function deletes all route addresses from all RA lists. + */ +static void mwifiex_wmm_delete_all_ralist(struct mwifiex_private *priv) +{ + struct mwifiex_ra_list_tbl *ra_list, *tmp_node; + int i; + + for (i = 0; i < MAX_NUM_TID; ++i) { + dev_dbg(priv->adapter->dev, + "info: ra_list: freeing buf for tid %d\n", i); + list_for_each_entry_safe(ra_list, tmp_node, + &priv->wmm.tid_tbl_ptr[i].ra_list, list) { + list_del(&ra_list->list); + kfree(ra_list); + } + + INIT_LIST_HEAD(&priv->wmm.tid_tbl_ptr[i].ra_list); + + priv->wmm.tid_tbl_ptr[i].ra_list_curr = NULL; + } +} + +/* + * This function cleans up the Tx and Rx queues. + * + * Cleanup includes - + * - All packets in RA lists + * - All entries in Rx reorder table + * - All entries in Tx BA stream table + * - MPA buffer (if required) + * - All RA lists + */ +void +mwifiex_clean_txrx(struct mwifiex_private *priv) +{ + unsigned long flags; + + mwifiex_11n_cleanup_reorder_tbl(priv); + spin_lock_irqsave(&priv->wmm.ra_list_spinlock, flags); + + mwifiex_wmm_cleanup_queues(priv); + mwifiex_11n_delete_all_tx_ba_stream_tbl(priv); + + if (priv->adapter->if_ops.cleanup_mpa_buf) + priv->adapter->if_ops.cleanup_mpa_buf(priv->adapter); + + mwifiex_wmm_delete_all_ralist(priv); + memcpy(tos_to_tid, ac_to_tid, sizeof(tos_to_tid)); + + spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock, flags); +} + +/* + * This function retrieves a particular RA list node, matching with the + * given TID and RA address. + */ +static struct mwifiex_ra_list_tbl * +mwifiex_wmm_get_ralist_node(struct mwifiex_private *priv, u8 tid, + u8 *ra_addr) +{ + struct mwifiex_ra_list_tbl *ra_list; + + list_for_each_entry(ra_list, &priv->wmm.tid_tbl_ptr[tid].ra_list, + list) { + if (!memcmp(ra_list->ra, ra_addr, ETH_ALEN)) + return ra_list; + } + + return NULL; +} + +/* + * This function retrieves an RA list node for a given TID and + * RA address pair. + * + * If no such node is found, a new node is added first and then + * retrieved. + */ +static struct mwifiex_ra_list_tbl * +mwifiex_wmm_get_queue_raptr(struct mwifiex_private *priv, u8 tid, u8 *ra_addr) +{ + struct mwifiex_ra_list_tbl *ra_list; + + ra_list = mwifiex_wmm_get_ralist_node(priv, tid, ra_addr); + if (ra_list) + return ra_list; + mwifiex_ralist_add(priv, ra_addr); + + return mwifiex_wmm_get_ralist_node(priv, tid, ra_addr); +} + +/* + * This function checks if a particular RA list node exists in a given TID + * table index. + */ +int +mwifiex_is_ralist_valid(struct mwifiex_private *priv, + struct mwifiex_ra_list_tbl *ra_list, int ptr_index) +{ + struct mwifiex_ra_list_tbl *rlist; + + list_for_each_entry(rlist, &priv->wmm.tid_tbl_ptr[ptr_index].ra_list, + list) { + if (rlist == ra_list) + return true; + } + + return false; +} + +/* + * This function adds a packet to WMM queue. + * + * In disconnected state the packet is immediately dropped and the + * packet send completion callback is called with status failure. + * + * Otherwise, the correct RA list node is located and the packet + * is queued at the list tail. + */ +void +mwifiex_wmm_add_buf_txqueue(struct mwifiex_adapter *adapter, + struct sk_buff *skb) +{ + struct mwifiex_txinfo *tx_info = MWIFIEX_SKB_TXCB(skb); + struct mwifiex_private *priv = adapter->priv[tx_info->bss_index]; + u32 tid; + struct mwifiex_ra_list_tbl *ra_list; + u8 ra[ETH_ALEN], tid_down; + unsigned long flags; + + if (!priv->media_connected) { + dev_dbg(adapter->dev, "data: drop packet in disconnect\n"); + mwifiex_write_data_complete(adapter, skb, -1); + return; + } + + tid = skb->priority; + + spin_lock_irqsave(&priv->wmm.ra_list_spinlock, flags); + + tid_down = mwifiex_wmm_downgrade_tid(priv, tid); + + /* In case of infra as we have already created the list during + association we just don't have to call get_queue_raptr, we will + have only 1 raptr for a tid in case of infra */ + if (!mwifiex_queuing_ra_based(priv)) { + if (!list_empty(&priv->wmm.tid_tbl_ptr[tid_down].ra_list)) + ra_list = list_first_entry( + &priv->wmm.tid_tbl_ptr[tid_down].ra_list, + struct mwifiex_ra_list_tbl, list); + else + ra_list = NULL; + } else { + memcpy(ra, skb->data, ETH_ALEN); + ra_list = mwifiex_wmm_get_queue_raptr(priv, tid_down, ra); + } + + if (!ra_list) { + spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock, flags); + mwifiex_write_data_complete(adapter, skb, -1); + return; + } + + skb_queue_tail(&ra_list->skb_head, skb); + + ra_list->total_pkts_size += skb->len; + + spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock, flags); +} + +/* + * This function processes the get WMM status command response from firmware. + * + * The response may contain multiple TLVs - + * - AC Queue status TLVs + * - Current WMM Parameter IE TLV + * - Admission Control action frame TLVs + * + * This function parses the TLVs and then calls further specific functions + * to process any changes in the queue prioritize or state. + */ +int mwifiex_ret_wmm_get_status(struct mwifiex_private *priv, + const struct host_cmd_ds_command *resp) +{ + u8 *curr = (u8 *) &resp->params.get_wmm_status; + uint16_t resp_len = le16_to_cpu(resp->size), tlv_len; + int valid = true; + + struct mwifiex_ie_types_data *tlv_hdr; + struct mwifiex_ie_types_wmm_queue_status *tlv_wmm_qstatus; + struct ieee_types_wmm_parameter *wmm_param_ie = NULL; + struct mwifiex_wmm_ac_status *ac_status; + + dev_dbg(priv->adapter->dev, "info: WMM: WMM_GET_STATUS cmdresp received: %d\n", + resp_len); + + while ((resp_len >= sizeof(tlv_hdr->header)) && valid) { + tlv_hdr = (struct mwifiex_ie_types_data *) curr; + tlv_len = le16_to_cpu(tlv_hdr->header.len); + + switch (le16_to_cpu(tlv_hdr->header.type)) { + case TLV_TYPE_WMMQSTATUS: + tlv_wmm_qstatus = + (struct mwifiex_ie_types_wmm_queue_status *) + tlv_hdr; + dev_dbg(priv->adapter->dev, + "info: CMD_RESP: WMM_GET_STATUS:" + " QSTATUS TLV: %d, %d, %d\n", + tlv_wmm_qstatus->queue_index, + tlv_wmm_qstatus->flow_required, + tlv_wmm_qstatus->disabled); + + ac_status = &priv->wmm.ac_status[tlv_wmm_qstatus-> + queue_index]; + ac_status->disabled = tlv_wmm_qstatus->disabled; + ac_status->flow_required = + tlv_wmm_qstatus->flow_required; + ac_status->flow_created = tlv_wmm_qstatus->flow_created; + break; + + case WLAN_EID_VENDOR_SPECIFIC: + /* + * Point the regular IEEE IE 2 bytes into the Marvell IE + * and setup the IEEE IE type and length byte fields + */ + + wmm_param_ie = + (struct ieee_types_wmm_parameter *) (curr + + 2); + wmm_param_ie->vend_hdr.len = (u8) tlv_len; + wmm_param_ie->vend_hdr.element_id = + WLAN_EID_VENDOR_SPECIFIC; + + dev_dbg(priv->adapter->dev, + "info: CMD_RESP: WMM_GET_STATUS:" + " WMM Parameter Set Count: %d\n", + wmm_param_ie->qos_info_bitmap & + IEEE80211_WMM_IE_AP_QOSINFO_PARAM_SET_CNT_MASK); + + memcpy((u8 *) &priv->curr_bss_params.bss_descriptor. + wmm_ie, wmm_param_ie, + wmm_param_ie->vend_hdr.len + 2); + + break; + + default: + valid = false; + break; + } + + curr += (tlv_len + sizeof(tlv_hdr->header)); + resp_len -= (tlv_len + sizeof(tlv_hdr->header)); + } + + mwifiex_wmm_setup_queue_priorities(priv, wmm_param_ie); + mwifiex_wmm_setup_ac_downgrade(priv); + + return 0; +} + +/* + * Callback handler from the command module to allow insertion of a WMM TLV. + * + * If the BSS we are associating to supports WMM, this function adds the + * required WMM Information IE to the association request command buffer in + * the form of a Marvell extended IEEE IE. + */ +u32 +mwifiex_wmm_process_association_req(struct mwifiex_private *priv, + u8 **assoc_buf, + struct ieee_types_wmm_parameter *wmm_ie, + struct ieee80211_ht_cap *ht_cap) +{ + struct mwifiex_ie_types_wmm_param_set *wmm_tlv; + u32 ret_len = 0; + + /* Null checks */ + if (!assoc_buf) + return 0; + if (!(*assoc_buf)) + return 0; + + if (!wmm_ie) + return 0; + + dev_dbg(priv->adapter->dev, "info: WMM: process assoc req:" + "bss->wmmIe=0x%x\n", + wmm_ie->vend_hdr.element_id); + + if ((priv->wmm_required + || (ht_cap && (priv->adapter->config_bands & BAND_GN + || priv->adapter->config_bands & BAND_AN)) + ) + && wmm_ie->vend_hdr.element_id == WLAN_EID_VENDOR_SPECIFIC) { + wmm_tlv = (struct mwifiex_ie_types_wmm_param_set *) *assoc_buf; + wmm_tlv->header.type = cpu_to_le16((u16) wmm_info_ie[0]); + wmm_tlv->header.len = cpu_to_le16((u16) wmm_info_ie[1]); + memcpy(wmm_tlv->wmm_ie, &wmm_info_ie[2], + le16_to_cpu(wmm_tlv->header.len)); + if (wmm_ie->qos_info_bitmap & IEEE80211_WMM_IE_AP_QOSINFO_UAPSD) + memcpy((u8 *) (wmm_tlv->wmm_ie + + le16_to_cpu(wmm_tlv->header.len) + - sizeof(priv->wmm_qosinfo)), + &priv->wmm_qosinfo, + sizeof(priv->wmm_qosinfo)); + + ret_len = sizeof(wmm_tlv->header) + + le16_to_cpu(wmm_tlv->header.len); + + *assoc_buf += ret_len; + } + + return ret_len; +} + +/* + * This function computes the time delay in the driver queues for a + * given packet. + * + * When the packet is received at the OS/Driver interface, the current + * time is set in the packet structure. The difference between the present + * time and that received time is computed in this function and limited + * based on pre-compiled limits in the driver. + */ +u8 +mwifiex_wmm_compute_drv_pkt_delay(struct mwifiex_private *priv, + const struct sk_buff *skb) +{ + u8 ret_val = 0; + struct timeval out_tstamp, in_tstamp; + u32 queue_delay; + + do_gettimeofday(&out_tstamp); + in_tstamp = ktime_to_timeval(skb->tstamp); + + queue_delay = (out_tstamp.tv_sec - in_tstamp.tv_sec) * 1000; + queue_delay += (out_tstamp.tv_usec - in_tstamp.tv_usec) / 1000; + + /* + * Queue delay is passed as a uint8 in units of 2ms (ms shifted + * by 1). Min value (other than 0) is therefore 2ms, max is 510ms. + * + * Pass max value if queue_delay is beyond the uint8 range + */ + ret_val = (u8) (min(queue_delay, priv->wmm.drv_pkt_delay_max) >> 1); + + dev_dbg(priv->adapter->dev, "data: WMM: Pkt Delay: %d ms," + " %d ms sent to FW\n", queue_delay, ret_val); + + return ret_val; +} + +/* + * This function retrieves the highest priority RA list table pointer. + */ +static struct mwifiex_ra_list_tbl * +mwifiex_wmm_get_highest_priolist_ptr(struct mwifiex_adapter *adapter, + struct mwifiex_private **priv, int *tid) +{ + struct mwifiex_private *priv_tmp; + struct mwifiex_ra_list_tbl *ptr, *head; + struct mwifiex_bss_prio_node *bssprio_node, *bssprio_head; + struct mwifiex_tid_tbl *tid_ptr; + int is_list_empty; + unsigned long flags; + int i, j; + + for (j = adapter->priv_num - 1; j >= 0; --j) { + spin_lock_irqsave(&adapter->bss_prio_tbl[j].bss_prio_lock, + flags); + is_list_empty = list_empty(&adapter->bss_prio_tbl[j] + .bss_prio_head); + spin_unlock_irqrestore(&adapter->bss_prio_tbl[j].bss_prio_lock, + flags); + if (is_list_empty) + continue; + + if (adapter->bss_prio_tbl[j].bss_prio_cur == + (struct mwifiex_bss_prio_node *) + &adapter->bss_prio_tbl[j].bss_prio_head) { + bssprio_node = + list_first_entry(&adapter->bss_prio_tbl[j] + .bss_prio_head, + struct mwifiex_bss_prio_node, + list); + bssprio_head = bssprio_node; + } else { + bssprio_node = adapter->bss_prio_tbl[j].bss_prio_cur; + bssprio_head = bssprio_node; + } + + do { + priv_tmp = bssprio_node->priv; + + for (i = HIGH_PRIO_TID; i >= LOW_PRIO_TID; --i) { + + tid_ptr = &(priv_tmp)->wmm. + tid_tbl_ptr[tos_to_tid[i]]; + + spin_lock_irqsave(&tid_ptr->tid_tbl_lock, + flags); + is_list_empty = + list_empty(&adapter->bss_prio_tbl[j] + .bss_prio_head); + spin_unlock_irqrestore(&tid_ptr->tid_tbl_lock, + flags); + if (is_list_empty) + continue; + + /* + * Always choose the next ra we transmitted + * last time, this way we pick the ra's in + * round robin fashion. + */ + ptr = list_first_entry( + &tid_ptr->ra_list_curr->list, + struct mwifiex_ra_list_tbl, + list); + + head = ptr; + if (ptr == (struct mwifiex_ra_list_tbl *) + &tid_ptr->ra_list) { + /* Get next ra */ + ptr = list_first_entry(&ptr->list, + struct mwifiex_ra_list_tbl, list); + head = ptr; + } + + do { + is_list_empty = + skb_queue_empty(&ptr->skb_head); + if (!is_list_empty) { + *priv = priv_tmp; + *tid = tos_to_tid[i]; + return ptr; + } + /* Get next ra */ + ptr = list_first_entry(&ptr->list, + struct mwifiex_ra_list_tbl, + list); + if (ptr == + (struct mwifiex_ra_list_tbl *) + &tid_ptr->ra_list) + ptr = list_first_entry( + &ptr->list, + struct mwifiex_ra_list_tbl, + list); + } while (ptr != head); + } + + /* Get next bss priority node */ + bssprio_node = list_first_entry(&bssprio_node->list, + struct mwifiex_bss_prio_node, + list); + + if (bssprio_node == + (struct mwifiex_bss_prio_node *) + &adapter->bss_prio_tbl[j].bss_prio_head) + /* Get next bss priority node */ + bssprio_node = list_first_entry( + &bssprio_node->list, + struct mwifiex_bss_prio_node, + list); + } while (bssprio_node != bssprio_head); + } + return NULL; +} + +/* + * This function gets the number of packets in the Tx queue of a + * particular RA list. + */ +static int +mwifiex_num_pkts_in_txq(struct mwifiex_private *priv, + struct mwifiex_ra_list_tbl *ptr, int max_buf_size) +{ + int count = 0, total_size = 0; + struct sk_buff *skb, *tmp; + + skb_queue_walk_safe(&ptr->skb_head, skb, tmp) { + total_size += skb->len; + if (total_size < max_buf_size) + ++count; + else + break; + } + + return count; +} + +/* + * This function sends a single packet to firmware for transmission. + */ +static void +mwifiex_send_single_packet(struct mwifiex_private *priv, + struct mwifiex_ra_list_tbl *ptr, int ptr_index, + unsigned long ra_list_flags) + __releases(&priv->wmm.ra_list_spinlock) +{ + struct sk_buff *skb, *skb_next; + struct mwifiex_tx_param tx_param; + struct mwifiex_adapter *adapter = priv->adapter; + int status = 0; + struct mwifiex_txinfo *tx_info; + + if (skb_queue_empty(&ptr->skb_head)) { + spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock, + ra_list_flags); + dev_dbg(adapter->dev, "data: nothing to send\n"); + return; + } + + skb = skb_dequeue(&ptr->skb_head); + + tx_info = MWIFIEX_SKB_TXCB(skb); + dev_dbg(adapter->dev, "data: dequeuing the packet %p %p\n", ptr, skb); + + ptr->total_pkts_size -= skb->len; + + if (!skb_queue_empty(&ptr->skb_head)) + skb_next = skb_peek(&ptr->skb_head); + else + skb_next = NULL; + + spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock, ra_list_flags); + + tx_param.next_pkt_len = ((skb_next) ? skb_next->len + + sizeof(struct txpd) : 0); + + status = mwifiex_process_tx(priv, skb, &tx_param); + + if (status == -EBUSY) { + /* Queue the packet back at the head */ + spin_lock_irqsave(&priv->wmm.ra_list_spinlock, ra_list_flags); + + if (!mwifiex_is_ralist_valid(priv, ptr, ptr_index)) { + spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock, + ra_list_flags); + mwifiex_write_data_complete(adapter, skb, -1); + return; + } + + skb_queue_tail(&ptr->skb_head, skb); + + ptr->total_pkts_size += skb->len; + tx_info->flags |= MWIFIEX_BUF_FLAG_REQUEUED_PKT; + spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock, + ra_list_flags); + } else { + spin_lock_irqsave(&priv->wmm.ra_list_spinlock, ra_list_flags); + if (mwifiex_is_ralist_valid(priv, ptr, ptr_index)) { + priv->wmm.packets_out[ptr_index]++; + priv->wmm.tid_tbl_ptr[ptr_index].ra_list_curr = ptr; + } + adapter->bss_prio_tbl[priv->bss_priority].bss_prio_cur = + list_first_entry( + &adapter->bss_prio_tbl[priv->bss_priority] + .bss_prio_cur->list, + struct mwifiex_bss_prio_node, + list); + spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock, + ra_list_flags); + } +} + +/* + * This function checks if the first packet in the given RA list + * is already processed or not. + */ +static int +mwifiex_is_ptr_processed(struct mwifiex_private *priv, + struct mwifiex_ra_list_tbl *ptr) +{ + struct sk_buff *skb; + struct mwifiex_txinfo *tx_info; + + if (skb_queue_empty(&ptr->skb_head)) + return false; + + skb = skb_peek(&ptr->skb_head); + + tx_info = MWIFIEX_SKB_TXCB(skb); + if (tx_info->flags & MWIFIEX_BUF_FLAG_REQUEUED_PKT) + return true; + + return false; +} + +/* + * This function sends a single processed packet to firmware for + * transmission. + */ +static void +mwifiex_send_processed_packet(struct mwifiex_private *priv, + struct mwifiex_ra_list_tbl *ptr, int ptr_index, + unsigned long ra_list_flags) + __releases(&priv->wmm.ra_list_spinlock) +{ + struct mwifiex_tx_param tx_param; + struct mwifiex_adapter *adapter = priv->adapter; + int ret = -1; + struct sk_buff *skb, *skb_next; + struct mwifiex_txinfo *tx_info; + + if (skb_queue_empty(&ptr->skb_head)) { + spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock, + ra_list_flags); + return; + } + + skb = skb_dequeue(&ptr->skb_head); + + if (!skb_queue_empty(&ptr->skb_head)) + skb_next = skb_peek(&ptr->skb_head); + else + skb_next = NULL; + + tx_info = MWIFIEX_SKB_TXCB(skb); + + spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock, ra_list_flags); + tx_param.next_pkt_len = + ((skb_next) ? skb_next->len + + sizeof(struct txpd) : 0); + ret = adapter->if_ops.host_to_card(adapter, MWIFIEX_TYPE_DATA, + skb->data, skb->len, &tx_param); + switch (ret) { + case -EBUSY: + dev_dbg(adapter->dev, "data: -EBUSY is returned\n"); + spin_lock_irqsave(&priv->wmm.ra_list_spinlock, ra_list_flags); + + if (!mwifiex_is_ralist_valid(priv, ptr, ptr_index)) { + spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock, + ra_list_flags); + mwifiex_write_data_complete(adapter, skb, -1); + return; + } + + skb_queue_tail(&ptr->skb_head, skb); + + tx_info->flags |= MWIFIEX_BUF_FLAG_REQUEUED_PKT; + spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock, + ra_list_flags); + break; + case -1: + adapter->data_sent = false; + dev_err(adapter->dev, "host_to_card failed: %#x\n", ret); + adapter->dbg.num_tx_host_to_card_failure++; + mwifiex_write_data_complete(adapter, skb, ret); + break; + case -EINPROGRESS: + adapter->data_sent = false; + default: + break; + } + if (ret != -EBUSY) { + spin_lock_irqsave(&priv->wmm.ra_list_spinlock, ra_list_flags); + if (mwifiex_is_ralist_valid(priv, ptr, ptr_index)) { + priv->wmm.packets_out[ptr_index]++; + priv->wmm.tid_tbl_ptr[ptr_index].ra_list_curr = ptr; + } + adapter->bss_prio_tbl[priv->bss_priority].bss_prio_cur = + list_first_entry( + &adapter->bss_prio_tbl[priv->bss_priority] + .bss_prio_cur->list, + struct mwifiex_bss_prio_node, + list); + spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock, + ra_list_flags); + } +} + +/* + * This function dequeues a packet from the highest priority list + * and transmits it. + */ +static int +mwifiex_dequeue_tx_packet(struct mwifiex_adapter *adapter) +{ + struct mwifiex_ra_list_tbl *ptr; + struct mwifiex_private *priv = NULL; + int ptr_index = 0; + u8 ra[ETH_ALEN]; + int tid_del = 0, tid = 0; + unsigned long flags; + + ptr = mwifiex_wmm_get_highest_priolist_ptr(adapter, &priv, &ptr_index); + if (!ptr) + return -1; + + tid = mwifiex_get_tid(priv->adapter, ptr); + + dev_dbg(adapter->dev, "data: tid=%d\n", tid); + + spin_lock_irqsave(&priv->wmm.ra_list_spinlock, flags); + if (!mwifiex_is_ralist_valid(priv, ptr, ptr_index)) { + spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock, flags); + return -1; + } + + if (mwifiex_is_ptr_processed(priv, ptr)) { + mwifiex_send_processed_packet(priv, ptr, ptr_index, flags); + /* ra_list_spinlock has been freed in + mwifiex_send_processed_packet() */ + return 0; + } + + if (!ptr->is_11n_enabled || mwifiex_is_ba_stream_setup(priv, ptr, tid) + || ((priv->sec_info.wpa_enabled + || priv->sec_info.wpa2_enabled) && !priv->wpa_is_gtk_set) + ) { + mwifiex_send_single_packet(priv, ptr, ptr_index, flags); + /* ra_list_spinlock has been freed in + mwifiex_send_single_packet() */ + } else { + if (mwifiex_is_ampdu_allowed(priv, ptr, tid)) { + if (mwifiex_is_ba_stream_avail(priv)) { + mwifiex_11n_create_tx_ba_stream_tbl(priv, + ptr->ra, tid, + BA_STREAM_SETUP_INPROGRESS); + mwifiex_send_addba(priv, tid, ptr->ra); + } else if (mwifiex_find_stream_to_delete + (priv, ptr, tid, &tid_del, ra)) { + mwifiex_11n_create_tx_ba_stream_tbl(priv, + ptr->ra, tid, + BA_STREAM_SETUP_INPROGRESS); + mwifiex_send_delba(priv, tid_del, ra, 1); + } + } +/* Minimum number of AMSDU */ +#define MIN_NUM_AMSDU 2 + if (mwifiex_is_amsdu_allowed(priv, ptr, tid) && + (mwifiex_num_pkts_in_txq(priv, ptr, adapter->tx_buf_size) >= + MIN_NUM_AMSDU)) + mwifiex_11n_aggregate_pkt(priv, ptr, INTF_HEADER_LEN, + ptr_index, flags); + /* ra_list_spinlock has been freed in + mwifiex_11n_aggregate_pkt() */ + else + mwifiex_send_single_packet(priv, ptr, ptr_index, flags); + /* ra_list_spinlock has been freed in + mwifiex_send_single_packet() */ + } + return 0; +} + +/* + * This function transmits the highest priority packet awaiting in the + * WMM Queues. + */ +void +mwifiex_wmm_process_tx(struct mwifiex_adapter *adapter) +{ + do { + /* Check if busy */ + if (adapter->data_sent || adapter->tx_lock_flag) + break; + + if (mwifiex_dequeue_tx_packet(adapter)) + break; + } while (true); + + return; +} diff --git a/drivers/net/wireless/mwifiex/wmm.h b/drivers/net/wireless/mwifiex/wmm.h new file mode 100644 index 0000000..241f1b0 --- /dev/null +++ b/drivers/net/wireless/mwifiex/wmm.h @@ -0,0 +1,112 @@ +/* + * Marvell Wireless LAN device driver: WMM + * + * Copyright (C) 2011, Marvell International Ltd. + * + * This software file (the "File") is distributed by Marvell International + * Ltd. under the terms of the GNU General Public License Version 2, June 1991 + * (the "License"). You may use, redistribute and/or modify this File in + * accordance with the terms and conditions of the License, a copy of which + * is available by writing to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the + * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. + * + * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE + * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE + * ARE EXPRESSLY DISCLAIMED. The License provides additional details about + * this warranty disclaimer. + */ + +#ifndef _MWIFIEX_WMM_H_ +#define _MWIFIEX_WMM_H_ + +enum ieee_types_wmm_aciaifsn_bitmasks { + MWIFIEX_AIFSN = (BIT(0) | BIT(1) | BIT(2) | BIT(3)), + MWIFIEX_ACM = BIT(4), + MWIFIEX_ACI = (BIT(5) | BIT(6)), +}; + +enum ieee_types_wmm_ecw_bitmasks { + MWIFIEX_ECW_MIN = (BIT(0) | BIT(1) | BIT(2) | BIT(3)), + MWIFIEX_ECW_MAX = (BIT(4) | BIT(5) | BIT(6) | BIT(7)), +}; + +/* + * This function retrieves the TID of the given RA list. + */ +static inline int +mwifiex_get_tid(struct mwifiex_adapter *adapter, + struct mwifiex_ra_list_tbl *ptr) +{ + struct sk_buff *skb; + + if (skb_queue_empty(&ptr->skb_head)) + return 0; + + skb = skb_peek(&ptr->skb_head); + + return skb->priority; +} + +/* + * This function gets the length of a list. + */ +static inline int +mwifiex_wmm_list_len(struct mwifiex_adapter *adapter, struct list_head *head) +{ + struct list_head *pos; + int count = 0; + + list_for_each(pos, head) + ++count; + + return count; +} + +/* + * This function checks if a RA list is empty or not. + */ +static inline u8 +mwifiex_wmm_is_ra_list_empty(struct mwifiex_adapter *adapter, + struct list_head *ra_list_hhead) +{ + struct mwifiex_ra_list_tbl *ra_list; + int is_list_empty; + + list_for_each_entry(ra_list, ra_list_hhead, list) { + is_list_empty = skb_queue_empty(&ra_list->skb_head); + if (!is_list_empty) + return false; + } + + return true; +} + +void mwifiex_wmm_add_buf_txqueue(struct mwifiex_adapter *adapter, + struct sk_buff *skb); +void mwifiex_ralist_add(struct mwifiex_private *priv, u8 *ra); + +int mwifiex_wmm_lists_empty(struct mwifiex_adapter *adapter); +void mwifiex_wmm_process_tx(struct mwifiex_adapter *adapter); +int mwifiex_is_ralist_valid(struct mwifiex_private *priv, + struct mwifiex_ra_list_tbl *ra_list, int tid); + +u8 mwifiex_wmm_compute_drv_pkt_delay(struct mwifiex_private *priv, + const struct sk_buff *skb); +void mwifiex_wmm_init(struct mwifiex_adapter *adapter); + +extern u32 mwifiex_wmm_process_association_req(struct mwifiex_private *priv, + u8 **assoc_buf, + struct ieee_types_wmm_parameter + *wmmie, + struct ieee80211_ht_cap + *htcap); + +void mwifiex_wmm_setup_queue_priorities(struct mwifiex_private *priv, + struct ieee_types_wmm_parameter + *wmm_ie); +void mwifiex_wmm_setup_ac_downgrade(struct mwifiex_private *priv); +extern int mwifiex_ret_wmm_get_status(struct mwifiex_private *priv, + const struct host_cmd_ds_command *resp); + +#endif /* !_MWIFIEX_WMM_H_ */ -- cgit v0.10.2 From f39de992540cf68cc865498242f963f70f7e97b3 Mon Sep 17 00:00:00 2001 From: Vasily Khoruzhick Date: Wed, 16 Mar 2011 16:41:46 +0200 Subject: libertas_spi: Add support for suspend/resume Add support for suspend/resume in if_spi. Signed-off-by: Vasily Khoruzhick Acked-by: Dan Williams Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/libertas/if_spi.c b/drivers/net/wireless/libertas/if_spi.c index f6c2cd66..078ef43d9 100644 --- a/drivers/net/wireless/libertas/if_spi.c +++ b/drivers/net/wireless/libertas/if_spi.c @@ -57,6 +57,7 @@ struct if_spi_card { /* Handles all SPI communication (except for FW load) */ struct workqueue_struct *workqueue; struct work_struct packet_work; + struct work_struct resume_work; u8 cmd_buffer[IF_SPI_CMD_BUF_SIZE]; @@ -68,6 +69,9 @@ struct if_spi_card { /* Protects cmd_packet_list and data_packet_list */ spinlock_t buffer_lock; + + /* True is card suspended */ + u8 suspended; }; static void free_if_spi_card(struct if_spi_card *card) @@ -1057,6 +1061,28 @@ out: return err; } +static void if_spi_resume_worker(struct work_struct *work) +{ + struct if_spi_card *card; + + card = container_of(work, struct if_spi_card, resume_work); + + if (card->suspended) { + if (card->pdata->setup) + card->pdata->setup(card->spi); + + /* Init card ... */ + if_spi_init_card(card); + + enable_irq(card->spi->irq); + + /* And resume it ... */ + lbs_resume(card->priv); + + card->suspended = 0; + } +} + static int __devinit if_spi_probe(struct spi_device *spi) { struct if_spi_card *card; @@ -1107,6 +1133,7 @@ static int __devinit if_spi_probe(struct spi_device *spi) goto free_card; } card->priv = priv; + priv->setup_fw_on_resume = 1; priv->card = card; priv->hw_host_to_card = if_spi_host_to_card; priv->enter_deep_sleep = NULL; @@ -1117,6 +1144,7 @@ static int __devinit if_spi_probe(struct spi_device *spi) /* Initialize interrupt handling stuff. */ card->workqueue = create_workqueue("libertas_spi"); INIT_WORK(&card->packet_work, if_spi_host_to_card_worker); + INIT_WORK(&card->resume_work, if_spi_resume_worker); err = request_irq(spi->irq, if_spi_host_interrupt, IRQF_TRIGGER_FALLING, "libertas_spi", card); @@ -1161,6 +1189,8 @@ static int __devexit libertas_spi_remove(struct spi_device *spi) lbs_deb_spi("libertas_spi_remove\n"); lbs_deb_enter(LBS_DEB_SPI); + cancel_work_sync(&card->resume_work); + lbs_stop_card(priv); lbs_remove_card(priv); /* will call free_netdev */ @@ -1174,6 +1204,40 @@ static int __devexit libertas_spi_remove(struct spi_device *spi) return 0; } +static int if_spi_suspend(struct device *dev) +{ + struct spi_device *spi = to_spi_device(dev); + struct if_spi_card *card = spi_get_drvdata(spi); + + if (!card->suspended) { + lbs_suspend(card->priv); + flush_workqueue(card->workqueue); + disable_irq(spi->irq); + + if (card->pdata->teardown) + card->pdata->teardown(spi); + card->suspended = 1; + } + + return 0; +} + +static int if_spi_resume(struct device *dev) +{ + struct spi_device *spi = to_spi_device(dev); + struct if_spi_card *card = spi_get_drvdata(spi); + + /* Schedule delayed work */ + schedule_work(&card->resume_work); + + return 0; +} + +static const struct dev_pm_ops if_spi_pm_ops = { + .suspend = if_spi_suspend, + .resume = if_spi_resume, +}; + static struct spi_driver libertas_spi_driver = { .probe = if_spi_probe, .remove = __devexit_p(libertas_spi_remove), @@ -1181,6 +1245,7 @@ static struct spi_driver libertas_spi_driver = { .name = "libertas_spi", .bus = &spi_bus_type, .owner = THIS_MODULE, + .pm = &if_spi_pm_ops, }, }; -- cgit v0.10.2 From dd347f2fb2ddb20a80e9a8285252bf208ab91398 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Tue, 22 Mar 2011 21:54:17 +0100 Subject: ath9k: fix beacon timer handling issues AP mode beacon timers in ath9k are configured in milliseconds, which breaks when increasing ATH_BCBUF to 8 instead of 4 (due to rounding errors). Since the hardware timers are actually configured in microseconds, it's better to let the driver use that unit directly. To be able to do that, the beacon interval parameter abuse for passing certain flags needs to be removed. This is easy to do, because those flags are completely unnecessary anyway. ATH9K_BEACON_ENA is ignored, ATH9K_BEACON_RESET_TSF can be replaced with calling ath9k_hw_reset_tsf from the driver directly. Signed-off-by: Felix Fietkau Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h index 099bd41..07dfb31 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h @@ -386,7 +386,7 @@ struct ath_beacon { u32 beaconq; u32 bmisscnt; u32 ast_be_xmit; - u64 bc_tstamp; + u32 bc_tstamp; struct ieee80211_vif *bslot[ATH_BCBUF]; int slottime; int slotupdate; diff --git a/drivers/net/wireless/ath/ath9k/beacon.c b/drivers/net/wireless/ath/ath9k/beacon.c index 6d2a545f..b5eab2f 100644 --- a/drivers/net/wireless/ath/ath9k/beacon.c +++ b/drivers/net/wireless/ath/ath9k/beacon.c @@ -57,8 +57,8 @@ int ath_beaconq_config(struct ath_softc *sc) /* * Associates the beacon frame buffer with a transmit descriptor. Will set - * up all required antenna switch parameters, rate codes, and channel flags. - * Beacons are always sent out at the lowest rate, and are not retried. + * up rate codes, and channel flags. Beacons are always sent out at the + * lowest rate, and are not retried. */ static void ath_beacon_setup(struct ath_softc *sc, struct ath_vif *avp, struct ath_buf *bf, int rateidx) @@ -68,7 +68,7 @@ static void ath_beacon_setup(struct ath_softc *sc, struct ath_vif *avp, struct ath_common *common = ath9k_hw_common(ah); struct ath_desc *ds; struct ath9k_11n_rate_series series[4]; - int flags, antenna, ctsrate = 0, ctsduration = 0; + int flags, ctsrate = 0, ctsduration = 0; struct ieee80211_supported_band *sband; u8 rate = 0; @@ -76,12 +76,6 @@ static void ath_beacon_setup(struct ath_softc *sc, struct ath_vif *avp, flags = ATH9K_TXDESC_NOACK; ds->ds_link = 0; - /* - * Switch antenna every beacon. - * Should only switch every beacon period, not for every SWBA - * XXX assumes two antennae - */ - antenna = ((sc->beacon.ast_be_xmit / sc->nbcnvifs) & 1 ? 2 : 1); sband = &sc->sbands[common->hw->conf.channel->band]; rate = sband->bitrates[rateidx].hw_value; @@ -278,7 +272,7 @@ int ath_beacon_alloc(struct ath_softc *sc, struct ieee80211_vif *vif) return -ENOMEM; tstamp = ((struct ieee80211_mgmt *)skb->data)->u.beacon.timestamp; - sc->beacon.bc_tstamp = le64_to_cpu(tstamp); + sc->beacon.bc_tstamp = (u32) le64_to_cpu(tstamp); /* Calculate a TSF adjustment factor required for staggered beacons. */ if (avp->av_bslot > 0) { u64 tsfadjust; @@ -294,8 +288,8 @@ int ath_beacon_alloc(struct ath_softc *sc, struct ieee80211_vif *vif) * adjustment. Other slots are adjusted to get the timestamp * close to the TBTT for the BSS. */ - tsfadjust = intval * avp->av_bslot / ATH_BCBUF; - avp->tsf_adjust = cpu_to_le64(TU_TO_USEC(tsfadjust)); + tsfadjust = TU_TO_USEC(intval * avp->av_bslot) / ATH_BCBUF; + avp->tsf_adjust = cpu_to_le64(tsfadjust); ath_dbg(common, ATH_DBG_BEACON, "stagger beacons, bslot %d intval %u tsfadjust %llu\n", @@ -401,8 +395,9 @@ void ath_beacon_tasklet(unsigned long data) intval = cur_conf->beacon_interval ? : ATH_DEFAULT_BINTVAL; tsf = ath9k_hw_gettsf64(ah); - tsftu = TSF_TO_TU(tsf>>32, tsf); - slot = ((tsftu % intval) * ATH_BCBUF) / intval; + tsf += TU_TO_USEC(ah->config.sw_beacon_response_time); + tsftu = TSF_TO_TU((tsf * ATH_BCBUF) >>32, tsf * ATH_BCBUF); + slot = (tsftu % (intval * ATH_BCBUF)) / intval; /* * Reverse the slot order to get slot 0 on the TBTT offset that does * not require TSF adjustment and other slots adding @@ -415,7 +410,7 @@ void ath_beacon_tasklet(unsigned long data) ath_dbg(common, ATH_DBG_BEACON, "slot %d [tsf %llu tsftu %u intval %u] vif %p\n", - slot, tsf, tsftu, intval, vif); + slot, tsf, tsftu / ATH_BCBUF, intval, vif); bfaddr = 0; if (vif) { @@ -463,13 +458,17 @@ static void ath9k_beacon_init(struct ath_softc *sc, u32 next_beacon, u32 beacon_period) { - if (beacon_period & ATH9K_BEACON_RESET_TSF) + if (sc->sc_flags & SC_OP_TSF_RESET) { ath9k_ps_wakeup(sc); + ath9k_hw_reset_tsf(sc->sc_ah); + } ath9k_hw_beaconinit(sc->sc_ah, next_beacon, beacon_period); - if (beacon_period & ATH9K_BEACON_RESET_TSF) + if (sc->sc_flags & SC_OP_TSF_RESET) { ath9k_ps_restore(sc); + sc->sc_flags &= ~SC_OP_TSF_RESET; + } } /* @@ -484,18 +483,14 @@ static void ath_beacon_config_ap(struct ath_softc *sc, u32 nexttbtt, intval; /* NB: the beacon interval is kept internally in TU's */ - intval = conf->beacon_interval & ATH9K_BEACON_PERIOD; + intval = TU_TO_USEC(conf->beacon_interval & ATH9K_BEACON_PERIOD); intval /= ATH_BCBUF; /* for staggered beacons */ nexttbtt = intval; - if (sc->sc_flags & SC_OP_TSF_RESET) - intval |= ATH9K_BEACON_RESET_TSF; - /* * In AP mode we enable the beacon timers and SWBA interrupts to * prepare beacon frames. */ - intval |= ATH9K_BEACON_ENA; ah->imask |= ATH9K_INT_SWBA; ath_beaconq_config(sc); @@ -505,11 +500,6 @@ static void ath_beacon_config_ap(struct ath_softc *sc, ath9k_beacon_init(sc, nexttbtt, intval); sc->beacon.bmisscnt = 0; ath9k_hw_set_interrupts(ah, ah->imask); - - /* Clear the reset TSF flag, so that subsequent beacon updation - will not reset the HW TSF. */ - - sc->sc_flags &= ~SC_OP_TSF_RESET; } /* @@ -643,25 +633,20 @@ static void ath_beacon_config_adhoc(struct ath_softc *sc, { struct ath_hw *ah = sc->sc_ah; struct ath_common *common = ath9k_hw_common(ah); - u64 tsf; - u32 tsftu, intval, nexttbtt; - - intval = conf->beacon_interval & ATH9K_BEACON_PERIOD; - - - /* Pull nexttbtt forward to reflect the current TSF */ - - nexttbtt = TSF_TO_TU(sc->beacon.bc_tstamp >> 32, sc->beacon.bc_tstamp); - if (nexttbtt == 0) - nexttbtt = intval; - else if (intval) - nexttbtt = roundup(nexttbtt, intval); - - tsf = ath9k_hw_gettsf64(ah); - tsftu = TSF_TO_TU((u32)(tsf>>32), (u32)tsf) + FUDGE; - do { - nexttbtt += intval; - } while (nexttbtt < tsftu); + u32 tsf, delta, intval, nexttbtt; + + tsf = ath9k_hw_gettsf32(ah) + TU_TO_USEC(FUDGE); + intval = TU_TO_USEC(conf->beacon_interval & ATH9K_BEACON_PERIOD); + + if (!sc->beacon.bc_tstamp) + nexttbtt = tsf + intval; + else { + if (tsf > sc->beacon.bc_tstamp) + delta = (tsf - sc->beacon.bc_tstamp); + else + delta = (tsf + 1 + (~0U - sc->beacon.bc_tstamp)); + nexttbtt = tsf + roundup(delta, intval); + } ath_dbg(common, ATH_DBG_BEACON, "IBSS nexttbtt %u intval %u (%u)\n", @@ -672,7 +657,6 @@ static void ath_beacon_config_adhoc(struct ath_softc *sc, * if we need to manually prepare beacon frames. Otherwise we use a * self-linked tx descriptor and let the hardware deal with things. */ - intval |= ATH9K_BEACON_ENA; ah->imask |= ATH9K_INT_SWBA; ath_beaconq_config(sc); diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c b/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c index 8d1d879..8f56158 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c @@ -155,7 +155,7 @@ static void ath9k_htc_beacon_config_ap(struct ath9k_htc_priv *priv, nexttbtt = intval; if (priv->op_flags & OP_TSF_RESET) { - intval |= ATH9K_BEACON_RESET_TSF; + ath9k_hw_reset_tsf(priv->ah); priv->op_flags &= ~OP_TSF_RESET; } else { /* @@ -168,8 +168,6 @@ static void ath9k_htc_beacon_config_ap(struct ath9k_htc_priv *priv, } while (nexttbtt < tsftu); } - intval |= ATH9K_BEACON_ENA; - if (priv->op_flags & OP_ENABLE_BEACON) imask |= ATH9K_INT_SWBA; @@ -178,7 +176,7 @@ static void ath9k_htc_beacon_config_ap(struct ath9k_htc_priv *priv, bss_conf->beacon_interval, nexttbtt, imask); WMI_CMD(WMI_DISABLE_INTR_CMDID); - ath9k_hw_beaconinit(priv->ah, nexttbtt, intval); + ath9k_hw_beaconinit(priv->ah, TU_TO_USEC(nexttbtt), TU_TO_USEC(intval)); priv->bmiss_cnt = 0; htc_imask = cpu_to_be32(imask); WMI_CMD_BUF(WMI_ENABLE_INTR_CMDID, &htc_imask); @@ -207,7 +205,6 @@ static void ath9k_htc_beacon_config_adhoc(struct ath9k_htc_priv *priv, nexttbtt += intval; } while (nexttbtt < tsftu); - intval |= ATH9K_BEACON_ENA; if (priv->op_flags & OP_ENABLE_BEACON) imask |= ATH9K_INT_SWBA; @@ -216,7 +213,7 @@ static void ath9k_htc_beacon_config_adhoc(struct ath9k_htc_priv *priv, bss_conf->beacon_interval, nexttbtt, imask); WMI_CMD(WMI_DISABLE_INTR_CMDID); - ath9k_hw_beaconinit(priv->ah, nexttbtt, intval); + ath9k_hw_beaconinit(priv->ah, TU_TO_USEC(nexttbtt), TU_TO_USEC(intval)); priv->bmiss_cnt = 0; htc_imask = cpu_to_be32(imask); WMI_CMD_BUF(WMI_ENABLE_INTR_CMDID, &htc_imask); diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index 8b86568..9513ec7 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c @@ -1697,21 +1697,15 @@ void ath9k_hw_beaconinit(struct ath_hw *ah, u32 next_beacon, u32 beacon_period) case NL80211_IFTYPE_MESH_POINT: REG_SET_BIT(ah, AR_TXCFG, AR_TXCFG_ADHOC_BEACON_ATIM_TX_POLICY); - REG_WRITE(ah, AR_NEXT_NDP_TIMER, - TU_TO_USEC(next_beacon + - (ah->atim_window ? ah-> - atim_window : 1))); + REG_WRITE(ah, AR_NEXT_NDP_TIMER, next_beacon + + TU_TO_USEC(ah->atim_window ? ah->atim_window : 1)); flags |= AR_NDP_TIMER_EN; case NL80211_IFTYPE_AP: - REG_WRITE(ah, AR_NEXT_TBTT_TIMER, TU_TO_USEC(next_beacon)); - REG_WRITE(ah, AR_NEXT_DMA_BEACON_ALERT, - TU_TO_USEC(next_beacon - - ah->config. - dma_beacon_response_time)); - REG_WRITE(ah, AR_NEXT_SWBA, - TU_TO_USEC(next_beacon - - ah->config. - sw_beacon_response_time)); + REG_WRITE(ah, AR_NEXT_TBTT_TIMER, next_beacon); + REG_WRITE(ah, AR_NEXT_DMA_BEACON_ALERT, next_beacon - + TU_TO_USEC(ah->config.dma_beacon_response_time)); + REG_WRITE(ah, AR_NEXT_SWBA, next_beacon - + TU_TO_USEC(ah->config.sw_beacon_response_time)); flags |= AR_TBTT_TIMER_EN | AR_DBA_TIMER_EN | AR_SWBA_TIMER_EN; break; @@ -1723,18 +1717,13 @@ void ath9k_hw_beaconinit(struct ath_hw *ah, u32 next_beacon, u32 beacon_period) break; } - REG_WRITE(ah, AR_BEACON_PERIOD, TU_TO_USEC(beacon_period)); - REG_WRITE(ah, AR_DMA_BEACON_PERIOD, TU_TO_USEC(beacon_period)); - REG_WRITE(ah, AR_SWBA_PERIOD, TU_TO_USEC(beacon_period)); - REG_WRITE(ah, AR_NDP_PERIOD, TU_TO_USEC(beacon_period)); + REG_WRITE(ah, AR_BEACON_PERIOD, beacon_period); + REG_WRITE(ah, AR_DMA_BEACON_PERIOD, beacon_period); + REG_WRITE(ah, AR_SWBA_PERIOD, beacon_period); + REG_WRITE(ah, AR_NDP_PERIOD, beacon_period); REGWRITE_BUFFER_FLUSH(ah); - beacon_period &= ~ATH9K_BEACON_ENA; - if (beacon_period & ATH9K_BEACON_RESET_TSF) { - ath9k_hw_reset_tsf(ah); - } - REG_SET_BIT(ah, AR_TIMER_MODE, flags); } EXPORT_SYMBOL(ath9k_hw_beaconinit); @@ -2395,10 +2384,11 @@ static u32 rightmost_index(struct ath_gen_timer_table *timer_table, u32 *mask) return timer_table->gen_timer_index[b]; } -static u32 ath9k_hw_gettsf32(struct ath_hw *ah) +u32 ath9k_hw_gettsf32(struct ath_hw *ah) { return REG_READ(ah, AR_TSF_L32); } +EXPORT_SYMBOL(ath9k_hw_gettsf32); struct ath_gen_timer *ath_gen_timer_alloc(struct ath_hw *ah, void (*trigger)(void *), diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h index 3d9fc6e..c819973 100644 --- a/drivers/net/wireless/ath/ath9k/hw.h +++ b/drivers/net/wireless/ath/ath9k/hw.h @@ -416,8 +416,6 @@ struct ath9k_beacon_state { u32 bs_nextdtim; u32 bs_intval; #define ATH9K_BEACON_PERIOD 0x0000ffff -#define ATH9K_BEACON_ENA 0x00800000 -#define ATH9K_BEACON_RESET_TSF 0x01000000 #define ATH9K_TSFOOR_THRESHOLD 0x00004240 /* 16k us */ u32 bs_dtimperiod; u16 bs_cfpperiod; @@ -930,6 +928,7 @@ void ath9k_hw_setopmode(struct ath_hw *ah); void ath9k_hw_setmcastfilter(struct ath_hw *ah, u32 filter0, u32 filter1); void ath9k_hw_setbssidmask(struct ath_hw *ah); void ath9k_hw_write_associd(struct ath_hw *ah); +u32 ath9k_hw_gettsf32(struct ath_hw *ah); u64 ath9k_hw_gettsf64(struct ath_hw *ah); void ath9k_hw_settsf64(struct ath_hw *ah, u64 tsf64); void ath9k_hw_reset_tsf(struct ath_hw *ah); -- cgit v0.10.2 From 87c510fe2d4f193cd4eb518364a2dfa5059b1218 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Tue, 22 Mar 2011 21:54:18 +0100 Subject: ath9k: trigger nfcal only after multiple missed beacons in AP mode Single missed (i.e. not transmitted) beacons in AP mode are not very rare and not necessarily an indicator of strong interference, so only trigger noise floor recalibration when multiple consecutive beacons could not be transmitted. Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/beacon.c b/drivers/net/wireless/ath/ath9k/beacon.c index b5eab2f..6ebeafe 100644 --- a/drivers/net/wireless/ath/ath9k/beacon.c +++ b/drivers/net/wireless/ath/ath9k/beacon.c @@ -368,7 +368,8 @@ void ath_beacon_tasklet(unsigned long data) "missed %u consecutive beacons\n", sc->beacon.bmisscnt); ath9k_hw_stop_dma_queue(ah, sc->beacon.beaconq); - ath9k_hw_bstuck_nfcal(ah); + if (sc->beacon.bmisscnt > 3) + ath9k_hw_bstuck_nfcal(ah); } else if (sc->beacon.bmisscnt >= BSTUCK_THRESH) { ath_dbg(common, ATH_DBG_BSTUCK, "beacon is officially stuck\n"); -- cgit v0.10.2 From c944daf46a8cfa50d6c1f54d4842180d0384c594 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Tue, 22 Mar 2011 21:54:19 +0100 Subject: ath9k: fix stuck beacon detection Stuck beacon detection is supposed to trigger when 9 consecutive beacons could not be sent by the hardware. When the driver runs only one active AP mode interface, it still configures the hardware beacon timer for 4 (ATH_BCBUF) beacon slots slots, which causes stuck beacon detection to be reset if ath9k_hw_stoptxdma clears the stuck frames between SWBA intervals. Fix this by not resetting the missed beacon count for empty slots and multiplying the threshold not by the maximum number of beacon slots but by the configured number of beacon interfaces. Signed-off-by: Felix Fietkau Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h index 07dfb31..7c91ba4 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h @@ -362,7 +362,7 @@ struct ath_vif { * number of BSSIDs) if a given beacon does not go out even after waiting this * number of beacon intervals, the game's up. */ -#define BSTUCK_THRESH (9 * ATH_BCBUF) +#define BSTUCK_THRESH 9 #define ATH_BCBUF 4 #define ATH_DEFAULT_BINTVAL 100 /* TU */ #define ATH_DEFAULT_BMISS_LIMIT 10 diff --git a/drivers/net/wireless/ath/ath9k/beacon.c b/drivers/net/wireless/ath/ath9k/beacon.c index 6ebeafe..74f33bc 100644 --- a/drivers/net/wireless/ath/ath9k/beacon.c +++ b/drivers/net/wireless/ath/ath9k/beacon.c @@ -363,7 +363,7 @@ void ath_beacon_tasklet(unsigned long data) if (ath9k_hw_numtxpending(ah, sc->beacon.beaconq) != 0) { sc->beacon.bmisscnt++; - if (sc->beacon.bmisscnt < BSTUCK_THRESH) { + if (sc->beacon.bmisscnt < BSTUCK_THRESH * sc->nbcnvifs) { ath_dbg(common, ATH_DBG_BSTUCK, "missed %u consecutive beacons\n", sc->beacon.bmisscnt); @@ -380,13 +380,6 @@ void ath_beacon_tasklet(unsigned long data) return; } - if (sc->beacon.bmisscnt != 0) { - ath_dbg(common, ATH_DBG_BSTUCK, - "resume beacon xmit after %u misses\n", - sc->beacon.bmisscnt); - sc->beacon.bmisscnt = 0; - } - /* * Generate beacon frames. we are sending frames * staggered so calculate the slot for this frame based @@ -420,6 +413,13 @@ void ath_beacon_tasklet(unsigned long data) bfaddr = bf->bf_daddr; bc = 1; } + + if (sc->beacon.bmisscnt != 0) { + ath_dbg(common, ATH_DBG_BSTUCK, + "resume beacon xmit after %u misses\n", + sc->beacon.bmisscnt); + sc->beacon.bmisscnt = 0; + } } /* -- cgit v0.10.2 From cfdc9a8bb8d90c6aa212a5a881862599673c443d Mon Sep 17 00:00:00 2001 From: Jouni Malinen Date: Wed, 23 Mar 2011 14:52:19 +0200 Subject: ath9k: Support RSN IBSS Add support for using RSN IBSS with ath9k. For now, this uses software crypto for group addressed frames in RSN IBSS, but that may be optimized in the future by extending the key cache design to support per-STA RX GTK. Signed-off-by: Jouni Malinen Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/init.c b/drivers/net/wireless/ath/ath9k/init.c index cdb0f1c..b590a9e 100644 --- a/drivers/net/wireless/ath/ath9k/init.c +++ b/drivers/net/wireless/ath/ath9k/init.c @@ -690,6 +690,8 @@ void ath9k_set_hw_capab(struct ath_softc *sc, struct ieee80211_hw *hw) if (AR_SREV_5416(sc->sc_ah)) hw->wiphy->flags &= ~WIPHY_FLAG_PS_ON_BY_DEFAULT; + hw->wiphy->flags |= WIPHY_FLAG_IBSS_RSN; + hw->queues = 4; hw->max_rates = 4; hw->channel_change_time = 5000; diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index 5248257..3c5de73 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -1845,6 +1845,20 @@ static int ath9k_set_key(struct ieee80211_hw *hw, if (ath9k_modparam_nohwcrypt) return -ENOSPC; + if (vif->type == NL80211_IFTYPE_ADHOC && + (key->cipher == WLAN_CIPHER_SUITE_TKIP || + key->cipher == WLAN_CIPHER_SUITE_CCMP) && + !(key->flags & IEEE80211_KEY_FLAG_PAIRWISE)) { + /* + * For now, disable hw crypto for the RSN IBSS group keys. This + * could be optimized in the future to use a modified key cache + * design to support per-STA RX GTK, but until that gets + * implemented, use of software crypto for group addressed + * frames is a acceptable to allow RSN IBSS to be used. + */ + return -EOPNOTSUPP; + } + mutex_lock(&sc->mutex); ath9k_ps_wakeup(sc); ath_dbg(common, ATH_DBG_CONFIG, "Set HW Key\n"); -- cgit v0.10.2 From ec15e68ba6a505631016f230899bafbb7b8cd0d6 Mon Sep 17 00:00:00 2001 From: Jouni Malinen Date: Wed, 23 Mar 2011 15:29:52 +0200 Subject: cfg80211: Add nl80211 event for deletion of a station entry Indicate an NL80211_CMD_DEL_STATION event when a station entry in mac80211 is deleted to match with the NL80211_CMD_NEW_STATION event that is used when the entry was added. This is needed, e.g., to allow user space to remove a peer from RSN IBSS Authenticator state machine to avoid re-authentication and re-keying delays when the peer is not reachable anymore. Signed-off-by: Jouni Malinen Reviewed-by: Johannes Berg Signed-off-by: John W. Linville diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index b2b9d28..2c45304 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -2667,6 +2667,15 @@ void cfg80211_new_sta(struct net_device *dev, const u8 *mac_addr, struct station_info *sinfo, gfp_t gfp); /** + * cfg80211_del_sta - notify userspace about deletion of a station + * + * @dev: the netdev + * @mac_addr: the station's address + * @gfp: allocation flags + */ +void cfg80211_del_sta(struct net_device *dev, const u8 *mac_addr, gfp_t gfp); + +/** * cfg80211_rx_mgmt - notification of received, unprocessed management frame * @dev: network device * @freq: Frequency on which the frame was received in MHz diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c index d0311a3..5ec0a7c 100644 --- a/net/mac80211/sta_info.c +++ b/net/mac80211/sta_info.c @@ -698,6 +698,8 @@ static int __must_check __sta_info_destroy(struct sta_info *sta) #endif /* CONFIG_MAC80211_VERBOSE_DEBUG */ cancel_work_sync(&sta->drv_unblock_wk); + cfg80211_del_sta(sdata->dev, sta->sta.addr, GFP_KERNEL); + rate_control_remove_sta_debugfs(sta); ieee80211_sta_debugfs_remove(sta); diff --git a/net/wireless/mlme.c b/net/wireless/mlme.c index aa5df88..16881fe 100644 --- a/net/wireless/mlme.c +++ b/net/wireless/mlme.c @@ -770,6 +770,15 @@ void cfg80211_new_sta(struct net_device *dev, const u8 *mac_addr, } EXPORT_SYMBOL(cfg80211_new_sta); +void cfg80211_del_sta(struct net_device *dev, const u8 *mac_addr, gfp_t gfp) +{ + struct wiphy *wiphy = dev->ieee80211_ptr->wiphy; + struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); + + nl80211_send_sta_del_event(rdev, dev, mac_addr, gfp); +} +EXPORT_SYMBOL(cfg80211_del_sta); + struct cfg80211_mgmt_registration { struct list_head list; diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 4ebce42..40c90fb 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -5966,6 +5966,40 @@ void nl80211_send_sta_event(struct cfg80211_registered_device *rdev, nl80211_mlme_mcgrp.id, gfp); } +void nl80211_send_sta_del_event(struct cfg80211_registered_device *rdev, + struct net_device *dev, const u8 *mac_addr, + gfp_t gfp) +{ + struct sk_buff *msg; + void *hdr; + + msg = nlmsg_new(NLMSG_GOODSIZE, gfp); + if (!msg) + return; + + hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_DEL_STATION); + if (!hdr) { + nlmsg_free(msg); + return; + } + + NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, dev->ifindex); + NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, mac_addr); + + if (genlmsg_end(msg, hdr) < 0) { + nlmsg_free(msg); + return; + } + + genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0, + nl80211_mlme_mcgrp.id, gfp); + return; + + nla_put_failure: + genlmsg_cancel(msg, hdr); + nlmsg_free(msg); +} + int nl80211_send_mgmt(struct cfg80211_registered_device *rdev, struct net_device *netdev, u32 nlpid, int freq, const u8 *buf, size_t len, gfp_t gfp) diff --git a/net/wireless/nl80211.h b/net/wireless/nl80211.h index e3f7fa8..dcac5cd 100644 --- a/net/wireless/nl80211.h +++ b/net/wireless/nl80211.h @@ -79,6 +79,9 @@ void nl80211_send_remain_on_channel_cancel( void nl80211_send_sta_event(struct cfg80211_registered_device *rdev, struct net_device *dev, const u8 *mac_addr, struct station_info *sinfo, gfp_t gfp); +void nl80211_send_sta_del_event(struct cfg80211_registered_device *rdev, + struct net_device *dev, const u8 *mac_addr, + gfp_t gfp); int nl80211_send_mgmt(struct cfg80211_registered_device *rdev, struct net_device *netdev, u32 nlpid, int freq, -- cgit v0.10.2 From f9f84e96f6d642aa7b337c22cbb7d6f936039fda Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Wed, 23 Mar 2011 20:57:24 +0100 Subject: ath9k_hw: embed the ath_ops callbacks in the ath_hw struct With this change, loading the address to a register read/write function costs only one pointer dereference instead of two. On MIPS this reduces ath9k_hw binary size from 326k down to 321k. Signed-off-by: Felix Fietkau Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_init.c b/drivers/net/wireless/ath/ath9k/htc_drv_init.c index fc67c93..4e26946 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_init.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_init.c @@ -430,14 +430,6 @@ static void ath9k_regwrite_flush(void *hw_priv) mutex_unlock(&priv->wmi->multi_write_mutex); } -static const struct ath_ops ath9k_common_ops = { - .read = ath9k_regread, - .multi_read = ath9k_multi_regread, - .write = ath9k_regwrite, - .enable_write_buffer = ath9k_enable_regwrite_buffer, - .write_flush = ath9k_regwrite_flush, -}; - static void ath_usb_read_cachesize(struct ath_common *common, int *csz) { *csz = L1_CACHE_BYTES >> 2; @@ -658,10 +650,15 @@ static int ath9k_init_priv(struct ath9k_htc_priv *priv, ah->hw_version.subsysid = 0; /* FIXME */ ah->hw_version.usbdev = drv_info; ah->ah_flags |= AH_USE_EEPROM; + ah->reg_ops.read = ath9k_regread; + ah->reg_ops.multi_read = ath9k_multi_regread; + ah->reg_ops.write = ath9k_regwrite; + ah->reg_ops.enable_write_buffer = ath9k_enable_regwrite_buffer; + ah->reg_ops.write_flush = ath9k_regwrite_flush; priv->ah = ah; common = ath9k_hw_common(ah); - common->ops = &ath9k_common_ops; + common->ops = &ah->reg_ops; common->bus_ops = &ath9k_usb_bus_ops; common->ah = ah; common->hw = priv->hw; diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h index c819973..ef387a2 100644 --- a/drivers/net/wireless/ath/ath9k/hw.h +++ b/drivers/net/wireless/ath/ath9k/hw.h @@ -65,24 +65,24 @@ /* Register read/write primitives */ #define REG_WRITE(_ah, _reg, _val) \ - ath9k_hw_common(_ah)->ops->write((_ah), (_val), (_reg)) + (_ah)->reg_ops.write((_ah), (_val), (_reg)) #define REG_READ(_ah, _reg) \ - ath9k_hw_common(_ah)->ops->read((_ah), (_reg)) + (_ah)->reg_ops.read((_ah), (_reg)) #define REG_READ_MULTI(_ah, _addr, _val, _cnt) \ - ath9k_hw_common(_ah)->ops->multi_read((_ah), (_addr), (_val), (_cnt)) + (_ah)->reg_ops.multi_read((_ah), (_addr), (_val), (_cnt)) #define ENABLE_REGWRITE_BUFFER(_ah) \ do { \ - if (ath9k_hw_common(_ah)->ops->enable_write_buffer) \ - ath9k_hw_common(_ah)->ops->enable_write_buffer((_ah)); \ + if ((_ah)->reg_ops.enable_write_buffer) \ + (_ah)->reg_ops.enable_write_buffer((_ah)); \ } while (0) #define REGWRITE_BUFFER_FLUSH(_ah) \ do { \ - if (ath9k_hw_common(_ah)->ops->write_flush) \ - ath9k_hw_common(_ah)->ops->write_flush((_ah)); \ + if ((_ah)->reg_ops.write_flush) \ + (_ah)->reg_ops.write_flush((_ah)); \ } while (0) #define SM(_v, _f) (((_v) << _f##_S) & _f) @@ -657,6 +657,8 @@ struct ath_nf_limits { #define AH_UNPLUGGED 0x2 /* The card has been physically removed. */ struct ath_hw { + struct ath_ops reg_ops; + struct ieee80211_hw *hw; struct ath_common common; struct ath9k_hw_version hw_version; diff --git a/drivers/net/wireless/ath/ath9k/init.c b/drivers/net/wireless/ath/ath9k/init.c index b590a9e..da114c2 100644 --- a/drivers/net/wireless/ath/ath9k/init.c +++ b/drivers/net/wireless/ath/ath9k/init.c @@ -196,11 +196,6 @@ static unsigned int ath9k_ioread32(void *hw_priv, u32 reg_offset) return val; } -static const struct ath_ops ath9k_common_ops = { - .read = ath9k_ioread32, - .write = ath9k_iowrite32, -}; - /**************************/ /* Initialization */ /**************************/ @@ -551,6 +546,8 @@ static int ath9k_init_softc(u16 devid, struct ath_softc *sc, u16 subsysid, ah->hw = sc->hw; ah->hw_version.devid = devid; ah->hw_version.subsysid = subsysid; + ah->reg_ops.read = ath9k_ioread32; + ah->reg_ops.write = ath9k_iowrite32; sc->sc_ah = ah; if (!pdata) { @@ -563,7 +560,7 @@ static int ath9k_init_softc(u16 devid, struct ath_softc *sc, u16 subsysid, } common = ath9k_hw_common(ah); - common->ops = &ath9k_common_ops; + common->ops = &ah->reg_ops; common->bus_ops = bus_ops; common->ah = ah; common->hw = sc->hw; -- cgit v0.10.2 From 845e03c93dda2c00ffb5c68a1f7c8efc412d7c1a Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Wed, 23 Mar 2011 20:57:25 +0100 Subject: ath9k_hw: add a new register op for read-mask-write Reduces the number of calls to register ops. On MIPS this reduces the ath9k_hw binary size from 321k down to 310k Signed-off-by: Felix Fietkau Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath.h b/drivers/net/wireless/ath/ath.h index a6c6a46..6d7105b 100644 --- a/drivers/net/wireless/ath/ath.h +++ b/drivers/net/wireless/ath/ath.h @@ -119,6 +119,7 @@ struct ath_ops { void (*write)(void *, u32 val, u32 reg_offset); void (*enable_write_buffer)(void *); void (*write_flush) (void *); + u32 (*rmw)(void *, u32 reg_offset, u32 set, u32 clr); }; struct ath_common; diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_init.c b/drivers/net/wireless/ath/ath9k/htc_drv_init.c index 4e26946..ca69e7c 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_init.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_init.c @@ -430,6 +430,17 @@ static void ath9k_regwrite_flush(void *hw_priv) mutex_unlock(&priv->wmi->multi_write_mutex); } +static u32 ath9k_reg_rmw(void *hw_priv, u32 reg_offset, u32 set, u32 clr) +{ + u32 val; + + val = ath9k_regread(hw_priv, reg_offset); + val &= ~clr; + val |= set; + ath9k_regwrite(hw_priv, val, reg_offset); + return val; +} + static void ath_usb_read_cachesize(struct ath_common *common, int *csz) { *csz = L1_CACHE_BYTES >> 2; @@ -655,6 +666,7 @@ static int ath9k_init_priv(struct ath9k_htc_priv *priv, ah->reg_ops.write = ath9k_regwrite; ah->reg_ops.enable_write_buffer = ath9k_enable_regwrite_buffer; ah->reg_ops.write_flush = ath9k_regwrite_flush; + ah->reg_ops.rmw = ath9k_reg_rmw; priv->ah = ah; common = ath9k_hw_common(ah); diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h index ef387a2..e256658 100644 --- a/drivers/net/wireless/ath/ath9k/hw.h +++ b/drivers/net/wireless/ath/ath9k/hw.h @@ -73,6 +73,9 @@ #define REG_READ_MULTI(_ah, _addr, _val, _cnt) \ (_ah)->reg_ops.multi_read((_ah), (_addr), (_val), (_cnt)) +#define REG_RMW(_ah, _reg, _set, _clr) \ + (_ah)->reg_ops.rmw((_ah), (_reg), (_set), (_clr)) + #define ENABLE_REGWRITE_BUFFER(_ah) \ do { \ if ((_ah)->reg_ops.enable_write_buffer) \ @@ -87,17 +90,14 @@ #define SM(_v, _f) (((_v) << _f##_S) & _f) #define MS(_v, _f) (((_v) & _f) >> _f##_S) -#define REG_RMW(_a, _r, _set, _clr) \ - REG_WRITE(_a, _r, (REG_READ(_a, _r) & ~(_clr)) | (_set)) #define REG_RMW_FIELD(_a, _r, _f, _v) \ - REG_WRITE(_a, _r, \ - (REG_READ(_a, _r) & ~_f) | (((_v) << _f##_S) & _f)) + REG_RMW(_a, _r, (((_v) << _f##_S) & _f), (_f)) #define REG_READ_FIELD(_a, _r, _f) \ (((REG_READ(_a, _r) & _f) >> _f##_S)) #define REG_SET_BIT(_a, _r, _f) \ - REG_WRITE(_a, _r, REG_READ(_a, _r) | (_f)) + REG_RMW(_a, _r, (_f), 0) #define REG_CLR_BIT(_a, _r, _f) \ - REG_WRITE(_a, _r, REG_READ(_a, _r) & ~(_f)) + REG_RMW(_a, _r, 0, (_f)) #define DO_DELAY(x) do { \ if (((++(x) % 64) == 0) && \ diff --git a/drivers/net/wireless/ath/ath9k/init.c b/drivers/net/wireless/ath/ath9k/init.c index da114c2..db1b755 100644 --- a/drivers/net/wireless/ath/ath9k/init.c +++ b/drivers/net/wireless/ath/ath9k/init.c @@ -196,6 +196,28 @@ static unsigned int ath9k_ioread32(void *hw_priv, u32 reg_offset) return val; } +static unsigned int ath9k_reg_rmw(void *hw_priv, u32 reg_offset, u32 set, u32 clr) +{ + struct ath_hw *ah = (struct ath_hw *) hw_priv; + struct ath_common *common = ath9k_hw_common(ah); + struct ath_softc *sc = (struct ath_softc *) common->priv; + unsigned long uninitialized_var(flags); + u32 val; + + if (ah->config.serialize_regmode == SER_REG_MODE_ON) + spin_lock_irqsave(&sc->sc_serial_rw, flags); + + val = ioread32(sc->mem + reg_offset); + val &= ~clr; + val |= set; + iowrite32(val, sc->mem + reg_offset); + + if (ah->config.serialize_regmode == SER_REG_MODE_ON) + spin_unlock_irqrestore(&sc->sc_serial_rw, flags); + + return val; +} + /**************************/ /* Initialization */ /**************************/ @@ -548,6 +570,7 @@ static int ath9k_init_softc(u16 devid, struct ath_softc *sc, u16 subsysid, ah->hw_version.subsysid = subsysid; ah->reg_ops.read = ath9k_ioread32; ah->reg_ops.write = ath9k_iowrite32; + ah->reg_ops.rmw = ath9k_reg_rmw; sc->sc_ah = ah; if (!pdata) { -- cgit v0.10.2 From ca7a4deb4a1a87dbdc6e7cab0d1022a535204226 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Wed, 23 Mar 2011 20:57:26 +0100 Subject: ath9k_hw: replace REG_READ+REG_WRITE with REG_RMW It's easier to read and it slightly decreases code size Signed-off-by: Felix Fietkau Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index 9513ec7..807d410 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c @@ -675,14 +675,14 @@ static void ath9k_hw_init_qos(struct ath_hw *ah) unsigned long ar9003_get_pll_sqsum_dvc(struct ath_hw *ah) { - REG_WRITE(ah, PLL3, (REG_READ(ah, PLL3) & ~(PLL3_DO_MEAS_MASK))); - udelay(100); - REG_WRITE(ah, PLL3, (REG_READ(ah, PLL3) | PLL3_DO_MEAS_MASK)); + REG_CLR_BIT(ah, PLL3, PLL3_DO_MEAS_MASK); + udelay(100); + REG_SET_BIT(ah, PLL3, PLL3_DO_MEAS_MASK); - while ((REG_READ(ah, PLL4) & PLL4_MEAS_DONE) == 0) - udelay(100); + while ((REG_READ(ah, PLL4) & PLL4_MEAS_DONE) == 0) + udelay(100); - return (REG_READ(ah, PLL3) & SQSUM_DVC_MASK) >> 3; + return (REG_READ(ah, PLL3) & SQSUM_DVC_MASK) >> 3; } EXPORT_SYMBOL(ar9003_get_pll_sqsum_dvc); @@ -832,8 +832,7 @@ void ath9k_hw_init_global_settings(struct ath_hw *ah) ah->misc_mode); if (ah->misc_mode != 0) - REG_WRITE(ah, AR_PCU_MISC, - REG_READ(ah, AR_PCU_MISC) | ah->misc_mode); + REG_SET_BIT(ah, AR_PCU_MISC, ah->misc_mode); if (conf->channel && conf->channel->band == IEEE80211_BAND_5GHZ) sifstime = 16; @@ -901,23 +900,19 @@ u32 ath9k_regd_get_ctl(struct ath_regulatory *reg, struct ath9k_channel *chan) static inline void ath9k_hw_set_dma(struct ath_hw *ah) { struct ath_common *common = ath9k_hw_common(ah); - u32 regval; ENABLE_REGWRITE_BUFFER(ah); /* * set AHB_MODE not to do cacheline prefetches */ - if (!AR_SREV_9300_20_OR_LATER(ah)) { - regval = REG_READ(ah, AR_AHB_MODE); - REG_WRITE(ah, AR_AHB_MODE, regval | AR_AHB_PREFETCH_RD_EN); - } + if (!AR_SREV_9300_20_OR_LATER(ah)) + REG_SET_BIT(ah, AR_AHB_MODE, AR_AHB_PREFETCH_RD_EN); /* * let mac dma reads be in 128 byte chunks */ - regval = REG_READ(ah, AR_TXCFG) & ~AR_TXCFG_DMASZ_MASK; - REG_WRITE(ah, AR_TXCFG, regval | AR_TXCFG_DMASZ_128B); + REG_RMW(ah, AR_TXCFG, AR_TXCFG_DMASZ_128B, AR_TXCFG_DMASZ_MASK); REGWRITE_BUFFER_FLUSH(ah); @@ -934,8 +929,7 @@ static inline void ath9k_hw_set_dma(struct ath_hw *ah) /* * let mac dma writes be in 128 byte chunks */ - regval = REG_READ(ah, AR_RXCFG) & ~AR_RXCFG_DMASZ_MASK; - REG_WRITE(ah, AR_RXCFG, regval | AR_RXCFG_DMASZ_128B); + REG_RMW(ah, AR_RXCFG, AR_RXCFG_DMASZ_128B, AR_RXCFG_DMASZ_MASK); /* * Setup receive FIFO threshold to hold off TX activities @@ -974,30 +968,27 @@ static inline void ath9k_hw_set_dma(struct ath_hw *ah) static void ath9k_hw_set_operating_mode(struct ath_hw *ah, int opmode) { - u32 val; + u32 mask = AR_STA_ID1_STA_AP | AR_STA_ID1_ADHOC; + u32 set = AR_STA_ID1_KSRCH_MODE; - val = REG_READ(ah, AR_STA_ID1); - val &= ~(AR_STA_ID1_STA_AP | AR_STA_ID1_ADHOC); switch (opmode) { - case NL80211_IFTYPE_AP: - REG_WRITE(ah, AR_STA_ID1, val | AR_STA_ID1_STA_AP - | AR_STA_ID1_KSRCH_MODE); - REG_CLR_BIT(ah, AR_CFG, AR_CFG_AP_ADHOC_INDICATION); - break; case NL80211_IFTYPE_ADHOC: case NL80211_IFTYPE_MESH_POINT: - REG_WRITE(ah, AR_STA_ID1, val | AR_STA_ID1_ADHOC - | AR_STA_ID1_KSRCH_MODE); + set |= AR_STA_ID1_ADHOC; REG_SET_BIT(ah, AR_CFG, AR_CFG_AP_ADHOC_INDICATION); break; + case NL80211_IFTYPE_AP: + set |= AR_STA_ID1_STA_AP; + /* fall through */ case NL80211_IFTYPE_STATION: - REG_WRITE(ah, AR_STA_ID1, val | AR_STA_ID1_KSRCH_MODE); + REG_CLR_BIT(ah, AR_CFG, AR_CFG_AP_ADHOC_INDICATION); break; default: - if (ah->is_monitoring) - REG_WRITE(ah, AR_STA_ID1, val | AR_STA_ID1_KSRCH_MODE); + if (!ah->is_monitoring) + set = 0; break; } + REG_RMW(ah, AR_STA_ID1, set, mask); } void ath9k_hw_get_delta_slope_vals(struct ath_hw *ah, u32 coef_scaled, @@ -1023,10 +1014,8 @@ static bool ath9k_hw_set_reset(struct ath_hw *ah, int type) u32 tmpReg; if (AR_SREV_9100(ah)) { - u32 val = REG_READ(ah, AR_RTC_DERIVED_CLK); - val &= ~AR_RTC_DERIVED_CLK_PERIOD; - val |= SM(1, AR_RTC_DERIVED_CLK_PERIOD); - REG_WRITE(ah, AR_RTC_DERIVED_CLK, val); + REG_RMW_FIELD(ah, AR_RTC_DERIVED_CLK, + AR_RTC_DERIVED_CLK_PERIOD, 1); (void)REG_READ(ah, AR_RTC_DERIVED_CLK); } @@ -1451,8 +1440,7 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan, ar9002_hw_enable_wep_aggregation(ah); } - REG_WRITE(ah, AR_STA_ID1, - REG_READ(ah, AR_STA_ID1) | AR_STA_ID1_PRESERVE_SEQNUM); + REG_SET_BIT(ah, AR_STA_ID1, AR_STA_ID1_PRESERVE_SEQNUM); ath9k_hw_set_dma(ah); @@ -2204,11 +2192,9 @@ void ath9k_hw_setrxfilter(struct ath_hw *ah, u32 bits) REG_WRITE(ah, AR_PHY_ERR, phybits); if (phybits) - REG_WRITE(ah, AR_RXCFG, - REG_READ(ah, AR_RXCFG) | AR_RXCFG_ZLFDMA); + REG_SET_BIT(ah, AR_RXCFG, AR_RXCFG_ZLFDMA); else - REG_WRITE(ah, AR_RXCFG, - REG_READ(ah, AR_RXCFG) & ~AR_RXCFG_ZLFDMA); + REG_CLR_BIT(ah, AR_RXCFG, AR_RXCFG_ZLFDMA); REGWRITE_BUFFER_FLUSH(ah); } diff --git a/drivers/net/wireless/ath/ath9k/mac.c b/drivers/net/wireless/ath/ath9k/mac.c index 562257a..db496f2 100644 --- a/drivers/net/wireless/ath/ath9k/mac.c +++ b/drivers/net/wireless/ath/ath9k/mac.c @@ -465,10 +465,9 @@ bool ath9k_hw_resettxqueue(struct ath_hw *ah, u32 q) REG_WRITE(ah, AR_QCBRCFG(q), SM(qi->tqi_cbrPeriod, AR_Q_CBRCFG_INTERVAL) | SM(qi->tqi_cbrOverflowLimit, AR_Q_CBRCFG_OVF_THRESH)); - REG_WRITE(ah, AR_QMISC(q), - REG_READ(ah, AR_QMISC(q)) | AR_Q_MISC_FSP_CBR | - (qi->tqi_cbrOverflowLimit ? - AR_Q_MISC_CBR_EXP_CNTR_LIMIT_EN : 0)); + REG_SET_BIT(ah, AR_QMISC(q), AR_Q_MISC_FSP_CBR | + (qi->tqi_cbrOverflowLimit ? + AR_Q_MISC_CBR_EXP_CNTR_LIMIT_EN : 0)); } if (qi->tqi_readyTime && (qi->tqi_type != ATH9K_TX_QUEUE_CAB)) { REG_WRITE(ah, AR_QRDYTIMECFG(q), @@ -481,40 +480,31 @@ bool ath9k_hw_resettxqueue(struct ath_hw *ah, u32 q) (qi->tqi_burstTime ? AR_D_CHNTIME_EN : 0)); if (qi->tqi_burstTime - && (qi->tqi_qflags & TXQ_FLAG_RDYTIME_EXP_POLICY_ENABLE)) { - REG_WRITE(ah, AR_QMISC(q), - REG_READ(ah, AR_QMISC(q)) | - AR_Q_MISC_RDYTIME_EXP_POLICY); + && (qi->tqi_qflags & TXQ_FLAG_RDYTIME_EXP_POLICY_ENABLE)) + REG_SET_BIT(ah, AR_QMISC(q), AR_Q_MISC_RDYTIME_EXP_POLICY); - } - - if (qi->tqi_qflags & TXQ_FLAG_BACKOFF_DISABLE) { - REG_WRITE(ah, AR_DMISC(q), - REG_READ(ah, AR_DMISC(q)) | - AR_D_MISC_POST_FR_BKOFF_DIS); - } + if (qi->tqi_qflags & TXQ_FLAG_BACKOFF_DISABLE) + REG_SET_BIT(ah, AR_DMISC(q), AR_D_MISC_POST_FR_BKOFF_DIS); REGWRITE_BUFFER_FLUSH(ah); - if (qi->tqi_qflags & TXQ_FLAG_FRAG_BURST_BACKOFF_ENABLE) { - REG_WRITE(ah, AR_DMISC(q), - REG_READ(ah, AR_DMISC(q)) | - AR_D_MISC_FRAG_BKOFF_EN); - } + if (qi->tqi_qflags & TXQ_FLAG_FRAG_BURST_BACKOFF_ENABLE) + REG_SET_BIT(ah, AR_DMISC(q), AR_D_MISC_FRAG_BKOFF_EN); + switch (qi->tqi_type) { case ATH9K_TX_QUEUE_BEACON: ENABLE_REGWRITE_BUFFER(ah); - REG_WRITE(ah, AR_QMISC(q), REG_READ(ah, AR_QMISC(q)) - | AR_Q_MISC_FSP_DBA_GATED - | AR_Q_MISC_BEACON_USE - | AR_Q_MISC_CBR_INCR_DIS1); + REG_SET_BIT(ah, AR_QMISC(q), + AR_Q_MISC_FSP_DBA_GATED + | AR_Q_MISC_BEACON_USE + | AR_Q_MISC_CBR_INCR_DIS1); - REG_WRITE(ah, AR_DMISC(q), REG_READ(ah, AR_DMISC(q)) - | (AR_D_MISC_ARB_LOCKOUT_CNTRL_GLOBAL << + REG_SET_BIT(ah, AR_DMISC(q), + (AR_D_MISC_ARB_LOCKOUT_CNTRL_GLOBAL << AR_D_MISC_ARB_LOCKOUT_CNTRL_S) - | AR_D_MISC_BEACON_USE - | AR_D_MISC_POST_FR_BKOFF_DIS); + | AR_D_MISC_BEACON_USE + | AR_D_MISC_POST_FR_BKOFF_DIS); REGWRITE_BUFFER_FLUSH(ah); @@ -533,41 +523,38 @@ bool ath9k_hw_resettxqueue(struct ath_hw *ah, u32 q) case ATH9K_TX_QUEUE_CAB: ENABLE_REGWRITE_BUFFER(ah); - REG_WRITE(ah, AR_QMISC(q), REG_READ(ah, AR_QMISC(q)) - | AR_Q_MISC_FSP_DBA_GATED - | AR_Q_MISC_CBR_INCR_DIS1 - | AR_Q_MISC_CBR_INCR_DIS0); + REG_SET_BIT(ah, AR_QMISC(q), + AR_Q_MISC_FSP_DBA_GATED + | AR_Q_MISC_CBR_INCR_DIS1 + | AR_Q_MISC_CBR_INCR_DIS0); value = (qi->tqi_readyTime - (ah->config.sw_beacon_response_time - ah->config.dma_beacon_response_time) - ah->config.additional_swba_backoff) * 1024; REG_WRITE(ah, AR_QRDYTIMECFG(q), value | AR_Q_RDYTIMECFG_EN); - REG_WRITE(ah, AR_DMISC(q), REG_READ(ah, AR_DMISC(q)) - | (AR_D_MISC_ARB_LOCKOUT_CNTRL_GLOBAL << + REG_SET_BIT(ah, AR_DMISC(q), + (AR_D_MISC_ARB_LOCKOUT_CNTRL_GLOBAL << AR_D_MISC_ARB_LOCKOUT_CNTRL_S)); REGWRITE_BUFFER_FLUSH(ah); break; case ATH9K_TX_QUEUE_PSPOLL: - REG_WRITE(ah, AR_QMISC(q), - REG_READ(ah, AR_QMISC(q)) | AR_Q_MISC_CBR_INCR_DIS1); + REG_SET_BIT(ah, AR_QMISC(q), AR_Q_MISC_CBR_INCR_DIS1); break; case ATH9K_TX_QUEUE_UAPSD: - REG_WRITE(ah, AR_DMISC(q), REG_READ(ah, AR_DMISC(q)) | - AR_D_MISC_POST_FR_BKOFF_DIS); + REG_SET_BIT(ah, AR_DMISC(q), AR_D_MISC_POST_FR_BKOFF_DIS); break; default: break; } if (qi->tqi_intFlags & ATH9K_TXQ_USE_LOCKOUT_BKOFF_DIS) { - REG_WRITE(ah, AR_DMISC(q), - REG_READ(ah, AR_DMISC(q)) | - SM(AR_D_MISC_ARB_LOCKOUT_CNTRL_GLOBAL, - AR_D_MISC_ARB_LOCKOUT_CNTRL) | - AR_D_MISC_POST_FR_BKOFF_DIS); + REG_SET_BIT(ah, AR_DMISC(q), + SM(AR_D_MISC_ARB_LOCKOUT_CNTRL_GLOBAL, + AR_D_MISC_ARB_LOCKOUT_CNTRL) | + AR_D_MISC_POST_FR_BKOFF_DIS); } if (AR_SREV_9300_20_OR_LATER(ah)) -- cgit v0.10.2 From a9b6b2569cf107fe541381e82faa0a3c47a9a7fd Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Wed, 23 Mar 2011 20:57:27 +0100 Subject: ath9k_hw: turn a few big macros into functions RF_BANK_SETUP, REG_WRITE_RF_ARRAY and REG_WRITE_ARRAY are way too big, so they shouldn't be inlined at every single callsite, especially since they can easily be turned into real functions. Signed-off-by: Felix Fietkau Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/ar5008_phy.c b/drivers/net/wireless/ath/ath9k/ar5008_phy.c index 94acce5..4361704 100644 --- a/drivers/net/wireless/ath/ath9k/ar5008_phy.c +++ b/drivers/net/wireless/ath/ath9k/ar5008_phy.c @@ -44,6 +44,34 @@ static const int m1ThreshExt_off = 127; static const int m2ThreshExt_off = 127; +static void ar5008_rf_bank_setup(u32 *bank, struct ar5416IniArray *array, + int col) +{ + int i; + + for (i = 0; i < array->ia_rows; i++) + bank[i] = INI_RA(array, i, col); +} + + +#define REG_WRITE_RF_ARRAY(iniarray, regData, regWr) \ + ar5008_write_rf_array(ah, iniarray, regData, &(regWr)) + +static void ar5008_write_rf_array(struct ath_hw *ah, struct ar5416IniArray *array, + u32 *data, unsigned int *writecnt) +{ + int r; + + ENABLE_REGWRITE_BUFFER(ah); + + for (r = 0; r < array->ia_rows; r++) { + REG_WRITE(ah, INI_RA(array, r, 0), data[r]); + DO_DELAY(*writecnt); + } + + REGWRITE_BUFFER_FLUSH(ah); +} + /** * ar5008_hw_phy_modify_rx_buffer() - perform analog swizzling of parameters * @rfbuf: @@ -530,16 +558,16 @@ static bool ar5008_hw_set_rf_regs(struct ath_hw *ah, eepMinorRev = ah->eep_ops->get_eeprom(ah, EEP_MINOR_REV); /* Setup Bank 0 Write */ - RF_BANK_SETUP(ah->analogBank0Data, &ah->iniBank0, 1); + ar5008_rf_bank_setup(ah->analogBank0Data, &ah->iniBank0, 1); /* Setup Bank 1 Write */ - RF_BANK_SETUP(ah->analogBank1Data, &ah->iniBank1, 1); + ar5008_rf_bank_setup(ah->analogBank1Data, &ah->iniBank1, 1); /* Setup Bank 2 Write */ - RF_BANK_SETUP(ah->analogBank2Data, &ah->iniBank2, 1); + ar5008_rf_bank_setup(ah->analogBank2Data, &ah->iniBank2, 1); /* Setup Bank 6 Write */ - RF_BANK_SETUP(ah->analogBank3Data, &ah->iniBank3, + ar5008_rf_bank_setup(ah->analogBank3Data, &ah->iniBank3, modesIndex); { int i; @@ -569,7 +597,7 @@ static bool ar5008_hw_set_rf_regs(struct ath_hw *ah, } /* Setup Bank 7 Setup */ - RF_BANK_SETUP(ah->analogBank7Data, &ah->iniBank7, 1); + ar5008_rf_bank_setup(ah->analogBank7Data, &ah->iniBank7, 1); /* Write Analog registers */ REG_WRITE_RF_ARRAY(&ah->iniBank0, ah->analogBank0Data, diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index 807d410..bb9a3f3 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c @@ -130,6 +130,20 @@ bool ath9k_hw_wait(struct ath_hw *ah, u32 reg, u32 mask, u32 val, u32 timeout) } EXPORT_SYMBOL(ath9k_hw_wait); +void ath9k_hw_write_array(struct ath_hw *ah, struct ar5416IniArray *array, + int column, unsigned int *writecnt) +{ + int r; + + ENABLE_REGWRITE_BUFFER(ah); + for (r = 0; r < array->ia_rows; r++) { + REG_WRITE(ah, INI_RA(array, r, 0), + INI_RA(array, r, column)); + DO_DELAY(*writecnt); + } + REGWRITE_BUFFER_FLUSH(ah); +} + u32 ath9k_hw_reverse_bits(u32 val, u32 n) { u32 retval; diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h index e256658..dafbe97 100644 --- a/drivers/net/wireless/ath/ath9k/hw.h +++ b/drivers/net/wireless/ath/ath9k/hw.h @@ -106,16 +106,8 @@ udelay(1); \ } while (0) -#define REG_WRITE_ARRAY(iniarray, column, regWr) do { \ - int r; \ - ENABLE_REGWRITE_BUFFER(ah); \ - for (r = 0; r < ((iniarray)->ia_rows); r++) { \ - REG_WRITE(ah, INI_RA((iniarray), (r), 0), \ - INI_RA((iniarray), r, (column))); \ - DO_DELAY(regWr); \ - } \ - REGWRITE_BUFFER_FLUSH(ah); \ - } while (0) +#define REG_WRITE_ARRAY(iniarray, column, regWr) \ + ath9k_hw_write_array(ah, iniarray, column, &(regWr)) #define AR_GPIO_OUTPUT_MUX_AS_OUTPUT 0 #define AR_GPIO_OUTPUT_MUX_AS_PCIE_ATTENTION_LED 1 @@ -913,6 +905,8 @@ void ath9k_hw_antdiv_comb_conf_set(struct ath_hw *ah, /* General Operation */ bool ath9k_hw_wait(struct ath_hw *ah, u32 reg, u32 mask, u32 val, u32 timeout); +void ath9k_hw_write_array(struct ath_hw *ah, struct ar5416IniArray *array, + int column, unsigned int *writecnt); u32 ath9k_hw_reverse_bits(u32 val, u32 n); bool ath9k_get_channel_edges(struct ath_hw *ah, u16 flags, u16 *low, u16 *high); u16 ath9k_hw_computetxtime(struct ath_hw *ah, diff --git a/drivers/net/wireless/ath/ath9k/phy.h b/drivers/net/wireless/ath/ath9k/phy.h index e4029325..f50e2c2 100644 --- a/drivers/net/wireless/ath/ath9k/phy.h +++ b/drivers/net/wireless/ath/ath9k/phy.h @@ -38,27 +38,11 @@ #define AR_PHY_CLC_Q0 0x0000ffd0 #define AR_PHY_CLC_Q0_S 5 -#define REG_WRITE_RF_ARRAY(iniarray, regData, regWr) do { \ - int r; \ - ENABLE_REGWRITE_BUFFER(ah); \ - for (r = 0; r < ((iniarray)->ia_rows); r++) { \ - REG_WRITE(ah, INI_RA((iniarray), r, 0), (regData)[r]); \ - DO_DELAY(regWr); \ - } \ - REGWRITE_BUFFER_FLUSH(ah); \ - } while (0) - #define ANTSWAP_AB 0x0001 #define REDUCE_CHAIN_0 0x00000050 #define REDUCE_CHAIN_1 0x00000051 #define AR_PHY_CHIP_ID 0x9818 -#define RF_BANK_SETUP(_bank, _iniarray, _col) do { \ - int i; \ - for (i = 0; i < (_iniarray)->ia_rows; i++) \ - (_bank)[i] = INI_RA((_iniarray), i, _col);; \ - } while (0) - #define AR_PHY_TIMING11_SPUR_FREQ_SD 0x3FF00000 #define AR_PHY_TIMING11_SPUR_FREQ_SD_S 20 -- cgit v0.10.2 From f4c607dc53ece4ac15afed163292425efa060775 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Wed, 23 Mar 2011 20:57:28 +0100 Subject: ath9k_hw: remove pCap->total_queues The EEPROM contains a field that can restrict the number of hardware queues, however this is not only useless (all the known chips contain the same number of hardware queues), but also potentially dangerous in case of a misprogrammed EEPROM (could trigger driver crashes), so let's just ignore it completely. Signed-off-by: Felix Fietkau Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index bb9a3f3..de0d218 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c @@ -1437,7 +1437,7 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan, REGWRITE_BUFFER_FLUSH(ah); ah->intr_txqs = 0; - for (i = 0; i < ah->caps.total_queues; i++) + for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) ath9k_hw_resettxqueue(ah, i); ath9k_hw_init_interrupt_masks(ah, ah->opmode); @@ -1885,12 +1885,6 @@ int ath9k_hw_fill_cap_info(struct ath_hw *ah) else pCap->hw_caps &= ~ATH9K_HW_CAP_HT; - if (capField & AR_EEPROM_EEPCAP_MAXQCU) - pCap->total_queues = - MS(capField, AR_EEPROM_EEPCAP_MAXQCU); - else - pCap->total_queues = ATH9K_NUM_TX_QUEUES; - if (capField & AR_EEPROM_EEPCAP_KC_ENTRIES) pCap->keycache_size = 1 << MS(capField, AR_EEPROM_EEPCAP_KC_ENTRIES); diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h index dafbe97..4e62ad8 100644 --- a/drivers/net/wireless/ath/ath9k/hw.h +++ b/drivers/net/wireless/ath/ath9k/hw.h @@ -191,7 +191,6 @@ enum ath9k_hw_caps { struct ath9k_hw_capabilities { u32 hw_caps; /* ATH9K_HW_CAP_* from ath9k_hw_caps */ - u16 total_queues; u16 keycache_size; u16 low_5ghz_chan, high_5ghz_chan; u16 low_2ghz_chan, high_2ghz_chan; diff --git a/drivers/net/wireless/ath/ath9k/mac.c b/drivers/net/wireless/ath/ath9k/mac.c index db496f2..05efcfb 100644 --- a/drivers/net/wireless/ath/ath9k/mac.c +++ b/drivers/net/wireless/ath/ath9k/mac.c @@ -209,15 +209,8 @@ bool ath9k_hw_set_txq_props(struct ath_hw *ah, int q, { u32 cw; struct ath_common *common = ath9k_hw_common(ah); - struct ath9k_hw_capabilities *pCap = &ah->caps; struct ath9k_tx_queue_info *qi; - if (q >= pCap->total_queues) { - ath_dbg(common, ATH_DBG_QUEUE, - "Set TXQ properties, invalid queue: %u\n", q); - return false; - } - qi = &ah->txq[q]; if (qi->tqi_type == ATH9K_TX_QUEUE_INACTIVE) { ath_dbg(common, ATH_DBG_QUEUE, @@ -280,15 +273,8 @@ bool ath9k_hw_get_txq_props(struct ath_hw *ah, int q, struct ath9k_tx_queue_info *qinfo) { struct ath_common *common = ath9k_hw_common(ah); - struct ath9k_hw_capabilities *pCap = &ah->caps; struct ath9k_tx_queue_info *qi; - if (q >= pCap->total_queues) { - ath_dbg(common, ATH_DBG_QUEUE, - "Get TXQ properties, invalid queue: %u\n", q); - return false; - } - qi = &ah->txq[q]; if (qi->tqi_type == ATH9K_TX_QUEUE_INACTIVE) { ath_dbg(common, ATH_DBG_QUEUE, @@ -320,28 +306,27 @@ int ath9k_hw_setuptxqueue(struct ath_hw *ah, enum ath9k_tx_queue type, { struct ath_common *common = ath9k_hw_common(ah); struct ath9k_tx_queue_info *qi; - struct ath9k_hw_capabilities *pCap = &ah->caps; int q; switch (type) { case ATH9K_TX_QUEUE_BEACON: - q = pCap->total_queues - 1; + q = ATH9K_NUM_TX_QUEUES - 1; break; case ATH9K_TX_QUEUE_CAB: - q = pCap->total_queues - 2; + q = ATH9K_NUM_TX_QUEUES - 2; break; case ATH9K_TX_QUEUE_PSPOLL: q = 1; break; case ATH9K_TX_QUEUE_UAPSD: - q = pCap->total_queues - 3; + q = ATH9K_NUM_TX_QUEUES - 3; break; case ATH9K_TX_QUEUE_DATA: - for (q = 0; q < pCap->total_queues; q++) + for (q = 0; q < ATH9K_NUM_TX_QUEUES; q++) if (ah->txq[q].tqi_type == ATH9K_TX_QUEUE_INACTIVE) break; - if (q == pCap->total_queues) { + if (q == ATH9K_NUM_TX_QUEUES) { ath_err(common, "No available TX queue\n"); return -1; } @@ -382,15 +367,9 @@ EXPORT_SYMBOL(ath9k_hw_setuptxqueue); bool ath9k_hw_releasetxqueue(struct ath_hw *ah, u32 q) { - struct ath9k_hw_capabilities *pCap = &ah->caps; struct ath_common *common = ath9k_hw_common(ah); struct ath9k_tx_queue_info *qi; - if (q >= pCap->total_queues) { - ath_dbg(common, ATH_DBG_QUEUE, - "Release TXQ, invalid queue: %u\n", q); - return false; - } qi = &ah->txq[q]; if (qi->tqi_type == ATH9K_TX_QUEUE_INACTIVE) { ath_dbg(common, ATH_DBG_QUEUE, @@ -414,18 +393,11 @@ EXPORT_SYMBOL(ath9k_hw_releasetxqueue); bool ath9k_hw_resettxqueue(struct ath_hw *ah, u32 q) { - struct ath9k_hw_capabilities *pCap = &ah->caps; struct ath_common *common = ath9k_hw_common(ah); struct ath9k_channel *chan = ah->curchan; struct ath9k_tx_queue_info *qi; u32 cwMin, chanCwMin, value; - if (q >= pCap->total_queues) { - ath_dbg(common, ATH_DBG_QUEUE, - "Reset TXQ, invalid queue: %u\n", q); - return false; - } - qi = &ah->txq[q]; if (qi->tqi_type == ATH9K_TX_QUEUE_INACTIVE) { ath_dbg(common, ATH_DBG_QUEUE, -- cgit v0.10.2 From 0db156e9648e69c34e8e88328358a26611fd71e3 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Wed, 23 Mar 2011 20:57:29 +0100 Subject: ath9k_hw: remove ah->config.ht_enable It is only used in one place, and the device id check that it's based on can be moved there as well. Signed-off-by: Felix Fietkau Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index de0d218..625ad0b 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c @@ -378,11 +378,6 @@ static void ath9k_hw_init_config(struct ath_hw *ah) ah->config.spurchans[i][1] = AR_NO_SPUR; } - if (ah->hw_version.devid != AR2427_DEVID_PCIE) - ah->config.ht_enable = 1; - else - ah->config.ht_enable = 0; - /* PAPRD needs some more work to be enabled */ ah->config.paprd_disable = 1; @@ -1880,7 +1875,7 @@ int ath9k_hw_fill_cap_info(struct ath_hw *ah) common->crypt_caps |= ATH_CRYPT_CAP_CIPHER_AESCCM; - if (ah->config.ht_enable) + if (ah->hw_version.devid != AR2427_DEVID_PCIE) pCap->hw_caps |= ATH9K_HW_CAP_HT; else pCap->hw_caps &= ~ATH9K_HW_CAP_HT; diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h index 4e62ad8..7bbf701 100644 --- a/drivers/net/wireless/ath/ath9k/hw.h +++ b/drivers/net/wireless/ath/ath9k/hw.h @@ -222,7 +222,6 @@ struct ath9k_ops_config { u8 pcie_clock_req; u32 pcie_waen; u8 analog_shiftreg; - u8 ht_enable; u8 paprd_disable; u32 ofdm_trig_low; u32 ofdm_trig_high; -- cgit v0.10.2 From c429bdcf8fe033f04830a960e07c13a01f631499 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Wed, 23 Mar 2011 20:57:30 +0100 Subject: ath9k_hw: remove pCap->reg_cap It is not used anywhere and seems pointless Signed-off-by: Felix Fietkau Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index 625ad0b..be22574 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c @@ -1932,23 +1932,6 @@ int ath9k_hw_fill_cap_info(struct ath_hw *ah) else pCap->hw_caps |= ATH9K_HW_CAP_4KB_SPLITTRANS; - if (regulatory->current_rd_ext & (1 << REG_EXT_JAPAN_MIDBAND)) { - pCap->reg_cap = - AR_EEPROM_EEREGCAP_EN_KK_NEW_11A | - AR_EEPROM_EEREGCAP_EN_KK_U1_EVEN | - AR_EEPROM_EEREGCAP_EN_KK_U2 | - AR_EEPROM_EEREGCAP_EN_KK_MIDBAND; - } else { - pCap->reg_cap = - AR_EEPROM_EEREGCAP_EN_KK_NEW_11A | - AR_EEPROM_EEREGCAP_EN_KK_U1_EVEN; - } - - /* Advertise midband for AR5416 with FCC midband set in eeprom */ - if (regulatory->current_rd_ext & (1 << REG_EXT_FCC_MIDBAND) && - AR_SREV_5416(ah)) - pCap->reg_cap |= AR_EEPROM_EEREGCAP_EN_FCC_MIDBAND; - if (AR_SREV_9280_20_OR_LATER(ah) && common->btcoex_enabled) { btcoex_hw->btactive_gpio = ATH_BTACTIVE_GPIO; btcoex_hw->wlanactive_gpio = ATH_WLANACTIVE_GPIO; diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h index 7bbf701..a255f9a 100644 --- a/drivers/net/wireless/ath/ath9k/hw.h +++ b/drivers/net/wireless/ath/ath9k/hw.h @@ -200,7 +200,6 @@ struct ath9k_hw_capabilities { u8 max_txchains; u8 max_rxchains; u16 tx_triglevel_max; - u16 reg_cap; u8 num_gpio_pins; u8 rx_hp_qdepth; u8 rx_lp_qdepth; -- cgit v0.10.2 From 6de12a1bcef0145436e815d30a3d48b9fadb199d Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Wed, 23 Mar 2011 20:57:31 +0100 Subject: ath9k_hw: remove pCap->keycache_size Similar to the number of tx queue, the number of keycache entries depends on the chip and shouldn't be messed with based on EEPROM data. Remove this field and stick to using AR_KEYTABLE_SIZE Signed-off-by: Felix Fietkau Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_init.c b/drivers/net/wireless/ath/ath9k/htc_drv_init.c index ca69e7c..8303b34 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_init.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_init.c @@ -564,13 +564,7 @@ static void ath9k_init_crypto(struct ath9k_htc_priv *priv) int i = 0; /* Get the hardware key cache size. */ - common->keymax = priv->ah->caps.keycache_size; - if (common->keymax > ATH_KEYMAX) { - ath_dbg(common, ATH_DBG_ANY, - "Warning, using only %u entries in %u key cache\n", - ATH_KEYMAX, common->keymax); - common->keymax = ATH_KEYMAX; - } + common->keymax = AR_KEYTABLE_SIZE; if (priv->ah->misc_mode & AR_PCU_MIC_NEW_LOC_ENA) common->crypt_caps |= ATH_CRYPT_CAP_MIC_COMBINED; diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index be22574..5c676da 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c @@ -1880,12 +1880,6 @@ int ath9k_hw_fill_cap_info(struct ath_hw *ah) else pCap->hw_caps &= ~ATH9K_HW_CAP_HT; - if (capField & AR_EEPROM_EEPCAP_KC_ENTRIES) - pCap->keycache_size = - 1 << MS(capField, AR_EEPROM_EEPCAP_KC_ENTRIES); - else - pCap->keycache_size = AR_KEYTABLE_SIZE; - if (AR_SREV_9285(ah) || AR_SREV_9271(ah)) pCap->tx_triglevel_max = MAX_TX_FIFO_THRESHOLD >> 1; else diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h index a255f9a..296e51b 100644 --- a/drivers/net/wireless/ath/ath9k/hw.h +++ b/drivers/net/wireless/ath/ath9k/hw.h @@ -191,7 +191,6 @@ enum ath9k_hw_caps { struct ath9k_hw_capabilities { u32 hw_caps; /* ATH9K_HW_CAP_* from ath9k_hw_caps */ - u16 keycache_size; u16 low_5ghz_chan, high_5ghz_chan; u16 low_2ghz_chan, high_2ghz_chan; u16 rts_aggr_limit; diff --git a/drivers/net/wireless/ath/ath9k/init.c b/drivers/net/wireless/ath/ath9k/init.c index db1b755..1ac8318 100644 --- a/drivers/net/wireless/ath/ath9k/init.c +++ b/drivers/net/wireless/ath/ath9k/init.c @@ -407,13 +407,7 @@ void ath9k_init_crypto(struct ath_softc *sc) int i = 0; /* Get the hardware key cache size. */ - common->keymax = sc->sc_ah->caps.keycache_size; - if (common->keymax > ATH_KEYMAX) { - ath_dbg(common, ATH_DBG_ANY, - "Warning, using only %u entries in %u key cache\n", - ATH_KEYMAX, common->keymax); - common->keymax = ATH_KEYMAX; - } + common->keymax = AR_KEYTABLE_SIZE; /* * Reset the key cache since some parts do not -- cgit v0.10.2 From 340d0ea774d4ff0038a068e14340b59c5a1fce2c Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Wed, 23 Mar 2011 20:57:32 +0100 Subject: ath9k_hw: remove ATH9K_HW_CAP_ENHANCEDPM It is not used anywhere Signed-off-by: Felix Fietkau Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index 5c676da..a2509dc 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c @@ -1903,8 +1903,6 @@ int ath9k_hw_fill_cap_info(struct ath_hw *ah) pCap->rts_aggr_limit = (8 * 1024); } - pCap->hw_caps |= ATH9K_HW_CAP_ENHANCEDPM; - #if defined(CONFIG_RFKILL) || defined(CONFIG_RFKILL_MODULE) ah->rfsilent = ah->eep_ops->get_eeprom(ah, EEP_RF_SILENT); if (ah->rfsilent & EEP_RFSILENT_ENABLED) { diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h index 296e51b..a0243b8 100644 --- a/drivers/net/wireless/ath/ath9k/hw.h +++ b/drivers/net/wireless/ath/ath9k/hw.h @@ -174,7 +174,6 @@ enum ath9k_hw_caps { ATH9K_HW_CAP_HT = BIT(0), ATH9K_HW_CAP_RFSILENT = BIT(1), ATH9K_HW_CAP_CST = BIT(2), - ATH9K_HW_CAP_ENHANCEDPM = BIT(3), ATH9K_HW_CAP_AUTOSLEEP = BIT(4), ATH9K_HW_CAP_4KB_SPLITTRANS = BIT(5), ATH9K_HW_CAP_EDMA = BIT(6), -- cgit v0.10.2 From 83860c594f65945b1a2c99e84338e1145cd34890 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Wed, 23 Mar 2011 20:57:33 +0100 Subject: ath9k_hw: remove pCap->tx_triglevel_max It has the same purpose (and value) as ah->config.max_txtrig_level Signed-off-by: Felix Fietkau Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index a2509dc..298f4d6 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c @@ -1880,11 +1880,6 @@ int ath9k_hw_fill_cap_info(struct ath_hw *ah) else pCap->hw_caps &= ~ATH9K_HW_CAP_HT; - if (AR_SREV_9285(ah) || AR_SREV_9271(ah)) - pCap->tx_triglevel_max = MAX_TX_FIFO_THRESHOLD >> 1; - else - pCap->tx_triglevel_max = MAX_TX_FIFO_THRESHOLD; - if (AR_SREV_9271(ah)) pCap->num_gpio_pins = AR9271_NUM_GPIO; else if (AR_DEVID_7010(ah)) diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h index a0243b8..4cc320b 100644 --- a/drivers/net/wireless/ath/ath9k/hw.h +++ b/drivers/net/wireless/ath/ath9k/hw.h @@ -197,7 +197,6 @@ struct ath9k_hw_capabilities { u8 rx_chainmask; u8 max_txchains; u8 max_rxchains; - u16 tx_triglevel_max; u8 num_gpio_pins; u8 rx_hp_qdepth; u8 rx_lp_qdepth; diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c index f916f08..5943bdc 100644 --- a/drivers/net/wireless/ath/ath9k/xmit.c +++ b/drivers/net/wireless/ath/ath9k/xmit.c @@ -1980,7 +1980,7 @@ static void ath_tx_rc_status(struct ath_softc *sc, struct ath_buf *bf, if (ieee80211_is_data(hdr->frame_control) && (ts->ts_flags & (ATH9K_TX_DATA_UNDERRUN | ATH9K_TX_DELIM_UNDERRUN)) && - ah->tx_trig_level >= sc->sc_ah->caps.tx_triglevel_max) + ah->tx_trig_level >= sc->sc_ah->config.max_txtrig_level) tx_info->status.rates[tx_rateindex].count = hw->max_rate_tries; } -- cgit v0.10.2 From 176fcc5c5f0131504a55e1e1d35389c49a9177c2 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Wed, 30 Mar 2011 15:30:43 -0300 Subject: perf script: Add more documentation about the -f/--fields parameters Using the commit log for 2c9e45f. Cc: David Ahern Cc: Frederic Weisbecker Cc: Ingo Molnar Cc: Mike Galbraith Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Stephane Eranian Cc: Tom Zanussi LKML-Reference: Signed-off-by: Arnaldo Carvalho de Melo diff --git a/tools/perf/Documentation/perf-script.txt b/tools/perf/Documentation/perf-script.txt index 66f040b..86c87e2 100644 --- a/tools/perf/Documentation/perf-script.txt +++ b/tools/perf/Documentation/perf-script.txt @@ -113,13 +113,61 @@ OPTIONS Do various checks like samples ordering and lost events. -f:: ---fields +--fields:: Comma separated list of fields to print. Options are: comm, tid, pid, time, cpu, event, trace, sym. Field - list must be prepended with the type, trace, sw or hw, + list can be prepended with the type, trace, sw or hw, to indicate to which event type the field list applies. e.g., -f sw:comm,tid,time,sym and -f trace:time,cpu,trace + perf script -f + + is equivalent to: + + perf script -f trace: -f sw: -f hw: + + i.e., the specified fields apply to all event types if the type string + is not given. + + The arguments are processed in the order received. A later usage can + reset a prior request. e.g.: + + -f trace: -f comm,tid,time,sym + + The first -f suppresses trace events (field list is ""), but then the + second invocation sets the fields to comm,tid,time,sym. In this case a + warning is given to the user: + + "Overriding previous field request for all events." + + Alternativey, consider the order: + + -f comm,tid,time,sym -f trace: + + The first -f sets the fields for all events and the second -f + suppresses trace events. The user is given a warning message about + the override, and the result of the above is that only S/W and H/W + events are displayed with the given fields. + + For the 'wildcard' option if a user selected field is invalid for an + event type, a message is displayed to the user that the option is + ignored for that type. For example: + + $ perf script -f comm,tid,trace + 'trace' not valid for hardware events. Ignoring. + 'trace' not valid for software events. Ignoring. + + Alternatively, if the type is given an invalid field is specified it + is an error. For example: + + perf script -v -f sw:comm,tid,trace + 'trace' not valid for software events. + + At this point usage is displayed, and perf-script exits. + + Finally, a user may not set fields to none for all event types. + i.e., -f "" is not allowed. + -k:: --vmlinux=:: vmlinux pathname -- cgit v0.10.2 From 36a0e6c2d6f3eb59b7a5ddfda63d252a42dba189 Mon Sep 17 00:00:00 2001 From: hayeswang Date: Mon, 21 Mar 2011 01:50:30 +0000 Subject: net/r8169: add a new chip for RTL8105 Add a new chip for RTL8105 whose settings are the same with RTL_GIGA_MAC_VER_30. Signed-off-by: Hayes Wang Signed-off-by: David S. Miller diff --git a/drivers/net/r8169.c b/drivers/net/r8169.c index 493b0de..0111a14 100644 --- a/drivers/net/r8169.c +++ b/drivers/net/r8169.c @@ -1574,6 +1574,7 @@ static void rtl8169_get_mac_version(struct rtl8169_private *tp, { 0x7c800000, 0x30000000, RTL_GIGA_MAC_VER_11 }, /* 8101 family. */ + { 0x7cf00000, 0x40b00000, RTL_GIGA_MAC_VER_30 }, { 0x7cf00000, 0x40a00000, RTL_GIGA_MAC_VER_30 }, { 0x7cf00000, 0x40900000, RTL_GIGA_MAC_VER_29 }, { 0x7c800000, 0x40800000, RTL_GIGA_MAC_VER_30 }, -- cgit v0.10.2 From 4804b3b3aec163b59328140d6c858c3ed1c85992 Mon Sep 17 00:00:00 2001 From: hayeswang Date: Mon, 21 Mar 2011 01:50:29 +0000 Subject: net/r8169: add a new chip for RTL8168DP Add a new chip for RTL8168DP. Signed-off-by: Hayes Wang Signed-off-by: David S. Miller diff --git a/drivers/net/r8169.c b/drivers/net/r8169.c index 0111a14..5c48075 100644 --- a/drivers/net/r8169.c +++ b/drivers/net/r8169.c @@ -127,6 +127,7 @@ enum mac_version { RTL_GIGA_MAC_VER_28 = 0x1c, // 8168DP RTL_GIGA_MAC_VER_29 = 0x1d, // 8105E RTL_GIGA_MAC_VER_30 = 0x1e, // 8105E + RTL_GIGA_MAC_VER_31 = 0x1f, // 8168DP }; #define _R(NAME,MAC,MASK) \ @@ -166,7 +167,8 @@ static const struct { _R("RTL8168dp/8111dp", RTL_GIGA_MAC_VER_27, 0xff7e1880), // PCI-E _R("RTL8168dp/8111dp", RTL_GIGA_MAC_VER_28, 0xff7e1880), // PCI-E _R("RTL8105e", RTL_GIGA_MAC_VER_29, 0xff7e1880), // PCI-E - _R("RTL8105e", RTL_GIGA_MAC_VER_30, 0xff7e1880) // PCI-E + _R("RTL8105e", RTL_GIGA_MAC_VER_30, 0xff7e1880), // PCI-E + _R("RTL8168dp/8111dp", RTL_GIGA_MAC_VER_31, 0xff7e1880) // PCI-E }; #undef _R @@ -651,12 +653,18 @@ static void rtl8168_oob_notify(struct rtl8169_private *tp, u8 cmd) static void rtl8168_driver_start(struct rtl8169_private *tp) { int i; + u32 reg; rtl8168_oob_notify(tp, OOB_CMD_DRIVER_START); + if (tp->mac_version == RTL_GIGA_MAC_VER_31) + reg = 0xb8; + else + reg = 0x10; + for (i = 0; i < 10; i++) { msleep(10); - if (ocp_read(tp, 0x0f, 0x0010) & 0x00000800) + if (ocp_read(tp, 0x0f, reg) & 0x00000800) break; } } @@ -664,16 +672,36 @@ static void rtl8168_driver_start(struct rtl8169_private *tp) static void rtl8168_driver_stop(struct rtl8169_private *tp) { int i; + u32 reg; rtl8168_oob_notify(tp, OOB_CMD_DRIVER_STOP); + if (tp->mac_version == RTL_GIGA_MAC_VER_31) + reg = 0xb8; + else + reg = 0x10; + for (i = 0; i < 10; i++) { msleep(10); - if ((ocp_read(tp, 0x0f, 0x0010) & 0x00000800) == 0) + if ((ocp_read(tp, 0x0f, reg) & 0x00000800) == 0) break; } } +static int r8168dp_check_dash(struct rtl8169_private *tp) +{ + u32 reg; + + if (tp->mac_version == RTL_GIGA_MAC_VER_31) + reg = 0xb8; + else + reg = 0x10; + + if (ocp_read(tp, 0xF, reg) & 0x00008000) + return 1; + else + return 0; +} static void r8169_mdio_write(void __iomem *ioaddr, int reg_addr, int value) { @@ -1555,6 +1583,7 @@ static void rtl8169_get_mac_version(struct rtl8169_private *tp, /* 8168DP family. */ { 0x7cf00000, 0x28800000, RTL_GIGA_MAC_VER_27 }, { 0x7cf00000, 0x28a00000, RTL_GIGA_MAC_VER_28 }, + { 0x7cf00000, 0x28b00000, RTL_GIGA_MAC_VER_31 }, /* 8168C family. */ { 0x7cf00000, 0x3cb00000, RTL_GIGA_MAC_VER_24 }, @@ -2860,6 +2889,7 @@ static void __devinit rtl_init_mdio_ops(struct rtl8169_private *tp) ops->read = r8168dp_1_mdio_read; break; case RTL_GIGA_MAC_VER_28: + case RTL_GIGA_MAC_VER_31: ops->write = r8168dp_2_mdio_write; ops->read = r8168dp_2_mdio_read; break; @@ -2917,8 +2947,9 @@ static void r8168_pll_power_down(struct rtl8169_private *tp) void __iomem *ioaddr = tp->mmio_addr; if (((tp->mac_version == RTL_GIGA_MAC_VER_27) || - (tp->mac_version == RTL_GIGA_MAC_VER_28)) && - (ocp_read(tp, 0x0f, 0x0010) & 0x00008000)) { + (tp->mac_version == RTL_GIGA_MAC_VER_28) || + (tp->mac_version == RTL_GIGA_MAC_VER_31)) && + r8168dp_check_dash(tp)) { return; } @@ -2944,6 +2975,7 @@ static void r8168_pll_power_down(struct rtl8169_private *tp) case RTL_GIGA_MAC_VER_26: case RTL_GIGA_MAC_VER_27: case RTL_GIGA_MAC_VER_28: + case RTL_GIGA_MAC_VER_31: RTL_W8(PMCH, RTL_R8(PMCH) & ~0x80); break; } @@ -2954,8 +2986,9 @@ static void r8168_pll_power_up(struct rtl8169_private *tp) void __iomem *ioaddr = tp->mmio_addr; if (((tp->mac_version == RTL_GIGA_MAC_VER_27) || - (tp->mac_version == RTL_GIGA_MAC_VER_28)) && - (ocp_read(tp, 0x0f, 0x0010) & 0x00008000)) { + (tp->mac_version == RTL_GIGA_MAC_VER_28) || + (tp->mac_version == RTL_GIGA_MAC_VER_31)) && + r8168dp_check_dash(tp)) { return; } @@ -2964,6 +2997,7 @@ static void r8168_pll_power_up(struct rtl8169_private *tp) case RTL_GIGA_MAC_VER_26: case RTL_GIGA_MAC_VER_27: case RTL_GIGA_MAC_VER_28: + case RTL_GIGA_MAC_VER_31: RTL_W8(PMCH, RTL_R8(PMCH) | 0x80); break; } @@ -3018,6 +3052,7 @@ static void __devinit rtl_init_pll_power_ops(struct rtl8169_private *tp) case RTL_GIGA_MAC_VER_26: case RTL_GIGA_MAC_VER_27: case RTL_GIGA_MAC_VER_28: + case RTL_GIGA_MAC_VER_31: ops->down = r8168_pll_power_down; ops->up = r8168_pll_power_up; break; @@ -3250,7 +3285,8 @@ rtl8169_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) (u32)(RTL_R32(TxConfig) & 0x9cf0f8ff), dev->irq); if ((tp->mac_version == RTL_GIGA_MAC_VER_27) || - (tp->mac_version == RTL_GIGA_MAC_VER_28)) { + (tp->mac_version == RTL_GIGA_MAC_VER_28) || + (tp->mac_version == RTL_GIGA_MAC_VER_31)) { rtl8168_driver_start(tp); } @@ -3283,7 +3319,8 @@ static void __devexit rtl8169_remove_one(struct pci_dev *pdev) struct rtl8169_private *tp = netdev_priv(dev); if ((tp->mac_version == RTL_GIGA_MAC_VER_27) || - (tp->mac_version == RTL_GIGA_MAC_VER_28)) { + (tp->mac_version == RTL_GIGA_MAC_VER_28) || + (tp->mac_version == RTL_GIGA_MAC_VER_31)) { rtl8168_driver_stop(tp); } @@ -3383,7 +3420,8 @@ static void rtl8169_hw_reset(struct rtl8169_private *tp) rtl8169_irq_mask_and_ack(ioaddr); if (tp->mac_version == RTL_GIGA_MAC_VER_27 || - tp->mac_version == RTL_GIGA_MAC_VER_28) { + tp->mac_version == RTL_GIGA_MAC_VER_28 || + tp->mac_version == RTL_GIGA_MAC_VER_31) { while (RTL_R8(TxPoll) & NPQ) udelay(20); @@ -3780,6 +3818,17 @@ static void rtl_hw_start_8168d(void __iomem *ioaddr, struct pci_dev *pdev) RTL_W16(CPlusCmd, RTL_R16(CPlusCmd) & ~R8168_CPCMD_QUIRK_MASK); } +static void rtl_hw_start_8168dp(void __iomem *ioaddr, struct pci_dev *pdev) +{ + rtl_csi_access_enable_1(ioaddr); + + rtl_tx_performance_tweak(pdev, 0x5 << MAX_READ_REQUEST_SHIFT); + + RTL_W8(MaxTxPacketSize, TxPacketMax); + + rtl_disable_clock_request(pdev); +} + static void rtl_hw_start_8168d_4(void __iomem *ioaddr, struct pci_dev *pdev) { static const struct ephy_info e_info_8168d_4[] = { @@ -3843,55 +3892,59 @@ static void rtl_hw_start_8168(struct net_device *dev) switch (tp->mac_version) { case RTL_GIGA_MAC_VER_11: rtl_hw_start_8168bb(ioaddr, pdev); - break; + break; case RTL_GIGA_MAC_VER_12: case RTL_GIGA_MAC_VER_17: rtl_hw_start_8168bef(ioaddr, pdev); - break; + break; case RTL_GIGA_MAC_VER_18: rtl_hw_start_8168cp_1(ioaddr, pdev); - break; + break; case RTL_GIGA_MAC_VER_19: rtl_hw_start_8168c_1(ioaddr, pdev); - break; + break; case RTL_GIGA_MAC_VER_20: rtl_hw_start_8168c_2(ioaddr, pdev); - break; + break; case RTL_GIGA_MAC_VER_21: rtl_hw_start_8168c_3(ioaddr, pdev); - break; + break; case RTL_GIGA_MAC_VER_22: rtl_hw_start_8168c_4(ioaddr, pdev); - break; + break; case RTL_GIGA_MAC_VER_23: rtl_hw_start_8168cp_2(ioaddr, pdev); - break; + break; case RTL_GIGA_MAC_VER_24: rtl_hw_start_8168cp_3(ioaddr, pdev); - break; + break; case RTL_GIGA_MAC_VER_25: case RTL_GIGA_MAC_VER_26: case RTL_GIGA_MAC_VER_27: rtl_hw_start_8168d(ioaddr, pdev); - break; + break; case RTL_GIGA_MAC_VER_28: rtl_hw_start_8168d_4(ioaddr, pdev); - break; + break; + case RTL_GIGA_MAC_VER_31: + rtl_hw_start_8168dp(ioaddr, pdev); + break; + default: printk(KERN_ERR PFX "%s: unknown chipset (mac_version = %d).\n", dev->name, tp->mac_version); - break; + break; } RTL_W8(ChipCmd, CmdTxEnb | CmdRxEnb); @@ -4756,6 +4809,7 @@ static irqreturn_t rtl8169_interrupt(int irq, void *dev_instance) case RTL_GIGA_MAC_VER_24: case RTL_GIGA_MAC_VER_27: case RTL_GIGA_MAC_VER_28: + case RTL_GIGA_MAC_VER_31: /* Experimental science. Pktgen proof. */ case RTL_GIGA_MAC_VER_12: case RTL_GIGA_MAC_VER_25: -- cgit v0.10.2 From 01dc7fec4025f6bb72b6b98ec88b375346b6dbbb Mon Sep 17 00:00:00 2001 From: hayeswang Date: Mon, 21 Mar 2011 01:50:28 +0000 Subject: net/r8169: support RTL8168E Support RTL8168E/RTL8111E. Signed-off-by: Hayes Wang Signed-off-by: David S. Miller diff --git a/drivers/net/r8169.c b/drivers/net/r8169.c index 5c48075..caa99cd 100644 --- a/drivers/net/r8169.c +++ b/drivers/net/r8169.c @@ -37,6 +37,8 @@ #define FIRMWARE_8168D_1 "rtl_nic/rtl8168d-1.fw" #define FIRMWARE_8168D_2 "rtl_nic/rtl8168d-2.fw" +#define FIRMWARE_8168E_1 "rtl_nic/rtl8168e-1.fw" +#define FIRMWARE_8168E_2 "rtl_nic/rtl8168e-2.fw" #define FIRMWARE_8105E_1 "rtl_nic/rtl8105e-1.fw" #ifdef RTL8169_DEBUG @@ -128,6 +130,8 @@ enum mac_version { RTL_GIGA_MAC_VER_29 = 0x1d, // 8105E RTL_GIGA_MAC_VER_30 = 0x1e, // 8105E RTL_GIGA_MAC_VER_31 = 0x1f, // 8168DP + RTL_GIGA_MAC_VER_32 = 0x20, // 8168E + RTL_GIGA_MAC_VER_33 = 0x21, // 8168E }; #define _R(NAME,MAC,MASK) \ @@ -168,7 +172,9 @@ static const struct { _R("RTL8168dp/8111dp", RTL_GIGA_MAC_VER_28, 0xff7e1880), // PCI-E _R("RTL8105e", RTL_GIGA_MAC_VER_29, 0xff7e1880), // PCI-E _R("RTL8105e", RTL_GIGA_MAC_VER_30, 0xff7e1880), // PCI-E - _R("RTL8168dp/8111dp", RTL_GIGA_MAC_VER_31, 0xff7e1880) // PCI-E + _R("RTL8168dp/8111dp", RTL_GIGA_MAC_VER_31, 0xff7e1880), // PCI-E + _R("RTL8168e/8111e", RTL_GIGA_MAC_VER_32, 0xff7e1880), // PCI-E + _R("RTL8168e/8111e", RTL_GIGA_MAC_VER_33, 0xff7e1880) // PCI-E }; #undef _R @@ -317,7 +323,9 @@ enum rtl8168_registers { #define OCPAR_FLAG 0x80000000 #define OCPAR_GPHY_WRITE_CMD 0x8000f060 #define OCPAR_GPHY_READ_CMD 0x0000f060 - RDSAR1 = 0xd0 /* 8168c only. Undocumented on 8168dp */ + RDSAR1 = 0xd0, /* 8168c only. Undocumented on 8168dp */ + MISC = 0xf0, /* 8168e only. */ + txpla_rst = (1 << 29) }; enum rtl_register_content { @@ -395,6 +403,7 @@ enum rtl_register_content { BWF = (1 << 6), /* Accept Broadcast wakeup frame */ MWF = (1 << 5), /* Accept Multicast wakeup frame */ UWF = (1 << 4), /* Accept Unicast wakeup frame */ + spi_en = (1 << 3), LanWake = (1 << 1), /* LanWake enable/disable */ PMEStatus = (1 << 0), /* PME status can be reset by PCI RST# */ @@ -579,6 +588,8 @@ MODULE_LICENSE("GPL"); MODULE_VERSION(RTL8169_VERSION); MODULE_FIRMWARE(FIRMWARE_8168D_1); MODULE_FIRMWARE(FIRMWARE_8168D_2); +MODULE_FIRMWARE(FIRMWARE_8168E_1); +MODULE_FIRMWARE(FIRMWARE_8168E_2); MODULE_FIRMWARE(FIRMWARE_8105E_1); static int rtl8169_open(struct net_device *dev); @@ -1575,6 +1586,11 @@ static void rtl8169_get_mac_version(struct rtl8169_private *tp, u32 val; int mac_version; } mac_info[] = { + /* 8168E family. */ + { 0x7cf00000, 0x2c200000, RTL_GIGA_MAC_VER_33 }, + { 0x7cf00000, 0x2c100000, RTL_GIGA_MAC_VER_32 }, + { 0x7c800000, 0x2c000000, RTL_GIGA_MAC_VER_33 }, + /* 8168D family. */ { 0x7cf00000, 0x28300000, RTL_GIGA_MAC_VER_26 }, { 0x7cf00000, 0x28100000, RTL_GIGA_MAC_VER_25 }, @@ -2466,6 +2482,93 @@ static void rtl8168d_4_hw_phy_config(struct rtl8169_private *tp) rtl_patchphy(tp, 0x0d, 1 << 5); } +static void rtl8168e_hw_phy_config(struct rtl8169_private *tp) +{ + static const struct phy_reg phy_reg_init[] = { + /* Enable Delay cap */ + { 0x1f, 0x0005 }, + { 0x05, 0x8b80 }, + { 0x06, 0xc896 }, + { 0x1f, 0x0000 }, + + /* Channel estimation fine tune */ + { 0x1f, 0x0001 }, + { 0x0b, 0x6c20 }, + { 0x07, 0x2872 }, + { 0x1c, 0xefff }, + { 0x1f, 0x0003 }, + { 0x14, 0x6420 }, + { 0x1f, 0x0000 }, + + /* Update PFM & 10M TX idle timer */ + { 0x1f, 0x0007 }, + { 0x1e, 0x002f }, + { 0x15, 0x1919 }, + { 0x1f, 0x0000 }, + + { 0x1f, 0x0007 }, + { 0x1e, 0x00ac }, + { 0x18, 0x0006 }, + { 0x1f, 0x0000 } + }; + + rtl_writephy_batch(tp, phy_reg_init, ARRAY_SIZE(phy_reg_init)); + + /* DCO enable for 10M IDLE Power */ + rtl_writephy(tp, 0x1f, 0x0007); + rtl_writephy(tp, 0x1e, 0x0023); + rtl_w1w0_phy(tp, 0x17, 0x0006, 0x0000); + rtl_writephy(tp, 0x1f, 0x0000); + + /* For impedance matching */ + rtl_writephy(tp, 0x1f, 0x0002); + rtl_w1w0_phy(tp, 0x08, 0x8000, 0x7f00); + rtl_writephy(tp, 0x1F, 0x0000); + + /* PHY auto speed down */ + rtl_writephy(tp, 0x1f, 0x0007); + rtl_writephy(tp, 0x1e, 0x002d); + rtl_w1w0_phy(tp, 0x18, 0x0050, 0x0000); + rtl_writephy(tp, 0x1f, 0x0000); + rtl_w1w0_phy(tp, 0x14, 0x8000, 0x0000); + + rtl_writephy(tp, 0x1f, 0x0005); + rtl_writephy(tp, 0x05, 0x8b86); + rtl_w1w0_phy(tp, 0x06, 0x0001, 0x0000); + rtl_writephy(tp, 0x1f, 0x0000); + + rtl_writephy(tp, 0x1f, 0x0005); + rtl_writephy(tp, 0x05, 0x8b85); + rtl_w1w0_phy(tp, 0x06, 0x0000, 0x2000); + rtl_writephy(tp, 0x1f, 0x0007); + rtl_writephy(tp, 0x1e, 0x0020); + rtl_w1w0_phy(tp, 0x15, 0x0000, 0x1100); + rtl_writephy(tp, 0x1f, 0x0006); + rtl_writephy(tp, 0x00, 0x5a00); + rtl_writephy(tp, 0x1f, 0x0000); + rtl_writephy(tp, 0x0d, 0x0007); + rtl_writephy(tp, 0x0e, 0x003c); + rtl_writephy(tp, 0x0d, 0x4007); + rtl_writephy(tp, 0x0e, 0x0000); + rtl_writephy(tp, 0x0d, 0x0000); +} + +static void rtl8168e_1_hw_phy_config(struct rtl8169_private *tp) +{ + if (rtl_apply_firmware(tp, FIRMWARE_8168E_1) < 0) + netif_warn(tp, probe, tp->dev, "unable to apply firmware patch\n"); + + rtl8168e_hw_phy_config(tp); +} + +static void rtl8168e_2_hw_phy_config(struct rtl8169_private *tp) +{ + if (rtl_apply_firmware(tp, FIRMWARE_8168E_2) < 0) + netif_warn(tp, probe, tp->dev, "unable to apply firmware patch\n"); + + rtl8168e_hw_phy_config(tp); +} + static void rtl8102e_hw_phy_config(struct rtl8169_private *tp) { static const struct phy_reg phy_reg_init[] = { @@ -2581,6 +2684,12 @@ static void rtl_hw_phy_config(struct net_device *dev) case RTL_GIGA_MAC_VER_30: rtl8105e_hw_phy_config(tp); break; + case RTL_GIGA_MAC_VER_32: + rtl8168e_1_hw_phy_config(tp); + break; + case RTL_GIGA_MAC_VER_33: + rtl8168e_2_hw_phy_config(tp); + break; default: break; @@ -2931,15 +3040,59 @@ static void r810x_pll_power_up(struct rtl8169_private *tp) static void r8168_phy_power_up(struct rtl8169_private *tp) { rtl_writephy(tp, 0x1f, 0x0000); - rtl_writephy(tp, 0x0e, 0x0000); + switch (tp->mac_version) { + case RTL_GIGA_MAC_VER_11: + case RTL_GIGA_MAC_VER_12: + case RTL_GIGA_MAC_VER_17: + case RTL_GIGA_MAC_VER_18: + case RTL_GIGA_MAC_VER_19: + case RTL_GIGA_MAC_VER_20: + case RTL_GIGA_MAC_VER_21: + case RTL_GIGA_MAC_VER_22: + case RTL_GIGA_MAC_VER_23: + case RTL_GIGA_MAC_VER_24: + case RTL_GIGA_MAC_VER_25: + case RTL_GIGA_MAC_VER_26: + case RTL_GIGA_MAC_VER_27: + case RTL_GIGA_MAC_VER_28: + case RTL_GIGA_MAC_VER_31: + rtl_writephy(tp, 0x0e, 0x0000); + break; + default: + break; + } rtl_writephy(tp, MII_BMCR, BMCR_ANENABLE); } static void r8168_phy_power_down(struct rtl8169_private *tp) { rtl_writephy(tp, 0x1f, 0x0000); - rtl_writephy(tp, 0x0e, 0x0200); - rtl_writephy(tp, MII_BMCR, BMCR_PDOWN); + switch (tp->mac_version) { + case RTL_GIGA_MAC_VER_32: + case RTL_GIGA_MAC_VER_33: + rtl_writephy(tp, MII_BMCR, BMCR_ANENABLE | BMCR_PDOWN); + break; + + case RTL_GIGA_MAC_VER_11: + case RTL_GIGA_MAC_VER_12: + case RTL_GIGA_MAC_VER_17: + case RTL_GIGA_MAC_VER_18: + case RTL_GIGA_MAC_VER_19: + case RTL_GIGA_MAC_VER_20: + case RTL_GIGA_MAC_VER_21: + case RTL_GIGA_MAC_VER_22: + case RTL_GIGA_MAC_VER_23: + case RTL_GIGA_MAC_VER_24: + case RTL_GIGA_MAC_VER_25: + case RTL_GIGA_MAC_VER_26: + case RTL_GIGA_MAC_VER_27: + case RTL_GIGA_MAC_VER_28: + case RTL_GIGA_MAC_VER_31: + rtl_writephy(tp, 0x0e, 0x0200); + default: + rtl_writephy(tp, MII_BMCR, BMCR_PDOWN); + break; + } } static void r8168_pll_power_down(struct rtl8169_private *tp) @@ -2959,6 +3112,10 @@ static void r8168_pll_power_down(struct rtl8169_private *tp) return; } + if (tp->mac_version == RTL_GIGA_MAC_VER_32 || + tp->mac_version == RTL_GIGA_MAC_VER_33) + rtl_ephy_write(ioaddr, 0x19, 0xff64); + if (__rtl8169_get_wol(tp) & WAKE_ANY) { rtl_writephy(tp, 0x1f, 0x0000); rtl_writephy(tp, MII_BMCR, 0x0000); @@ -2976,6 +3133,8 @@ static void r8168_pll_power_down(struct rtl8169_private *tp) case RTL_GIGA_MAC_VER_27: case RTL_GIGA_MAC_VER_28: case RTL_GIGA_MAC_VER_31: + case RTL_GIGA_MAC_VER_32: + case RTL_GIGA_MAC_VER_33: RTL_W8(PMCH, RTL_R8(PMCH) & ~0x80); break; } @@ -2998,6 +3157,8 @@ static void r8168_pll_power_up(struct rtl8169_private *tp) case RTL_GIGA_MAC_VER_27: case RTL_GIGA_MAC_VER_28: case RTL_GIGA_MAC_VER_31: + case RTL_GIGA_MAC_VER_32: + case RTL_GIGA_MAC_VER_33: RTL_W8(PMCH, RTL_R8(PMCH) | 0x80); break; } @@ -3053,6 +3214,8 @@ static void __devinit rtl_init_pll_power_ops(struct rtl8169_private *tp) case RTL_GIGA_MAC_VER_27: case RTL_GIGA_MAC_VER_28: case RTL_GIGA_MAC_VER_31: + case RTL_GIGA_MAC_VER_32: + case RTL_GIGA_MAC_VER_33: ops->down = r8168_pll_power_down; ops->up = r8168_pll_power_up; break; @@ -3855,6 +4018,41 @@ static void rtl_hw_start_8168d_4(void __iomem *ioaddr, struct pci_dev *pdev) rtl_enable_clock_request(pdev); } +static void rtl_hw_start_8168e(void __iomem *ioaddr, struct pci_dev *pdev) +{ + static const struct ephy_info e_info_8168e[] = { + { 0x00, 0x0200, 0x0100 }, + { 0x00, 0x0000, 0x0004 }, + { 0x06, 0x0002, 0x0001 }, + { 0x06, 0x0000, 0x0030 }, + { 0x07, 0x0000, 0x2000 }, + { 0x00, 0x0000, 0x0020 }, + { 0x03, 0x5800, 0x2000 }, + { 0x03, 0x0000, 0x0001 }, + { 0x01, 0x0800, 0x1000 }, + { 0x07, 0x0000, 0x4000 }, + { 0x1e, 0x0000, 0x2000 }, + { 0x19, 0xffff, 0xfe6c }, + { 0x0a, 0x0000, 0x0040 } + }; + + rtl_csi_access_enable_2(ioaddr); + + rtl_ephy_init(ioaddr, e_info_8168e, ARRAY_SIZE(e_info_8168e)); + + rtl_tx_performance_tweak(pdev, 0x5 << MAX_READ_REQUEST_SHIFT); + + RTL_W8(MaxTxPacketSize, TxPacketMax); + + rtl_disable_clock_request(pdev); + + /* Reset tx FIFO pointer */ + RTL_W32(MISC, RTL_R32(MISC) | txpla_rst); + RTL_W32(MISC, RTL_R32(MISC) & ~txpla_rst); + + RTL_W8(Config5, RTL_R8(Config5) & ~spi_en); +} + static void rtl_hw_start_8168(struct net_device *dev) { struct rtl8169_private *tp = netdev_priv(dev); @@ -3940,6 +4138,10 @@ static void rtl_hw_start_8168(struct net_device *dev) rtl_hw_start_8168dp(ioaddr, pdev); break; + case RTL_GIGA_MAC_VER_32: + case RTL_GIGA_MAC_VER_33: + rtl_hw_start_8168e(ioaddr, pdev); + break; default: printk(KERN_ERR PFX "%s: unknown chipset (mac_version = %d).\n", -- cgit v0.10.2 From 311fddc7569d7a3340d61de262cff11685060f74 Mon Sep 17 00:00:00 2001 From: Somnath Kotur Date: Wed, 16 Mar 2011 21:22:43 +0000 Subject: be2net: Support for FAT dump retrieval using ethtool --register-dump option Signed-off-by: Somnath Kotur Signed-off-by: David S. Miller diff --git a/drivers/net/benet/be_cmds.c b/drivers/net/benet/be_cmds.c index 5a4a87e7..2aadf88 100644 --- a/drivers/net/benet/be_cmds.c +++ b/drivers/net/benet/be_cmds.c @@ -1186,6 +1186,113 @@ err: return status; } +/* Uses synchronous mcc */ +int be_cmd_get_reg_len(struct be_adapter *adapter, u32 *log_size) +{ + struct be_mcc_wrb *wrb; + struct be_cmd_req_get_fat *req; + int status; + + spin_lock_bh(&adapter->mcc_lock); + + wrb = wrb_from_mccq(adapter); + if (!wrb) { + status = -EBUSY; + goto err; + } + req = embedded_payload(wrb); + + be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0, + OPCODE_COMMON_MANAGE_FAT); + + be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON, + OPCODE_COMMON_MANAGE_FAT, sizeof(*req)); + req->fat_operation = cpu_to_le32(QUERY_FAT); + status = be_mcc_notify_wait(adapter); + if (!status) { + struct be_cmd_resp_get_fat *resp = embedded_payload(wrb); + if (log_size && resp->log_size) + *log_size = le32_to_cpu(resp->log_size - + sizeof(u32)); + } +err: + spin_unlock_bh(&adapter->mcc_lock); + return status; +} + +void be_cmd_get_regs(struct be_adapter *adapter, u32 buf_len, void *buf) +{ + struct be_dma_mem get_fat_cmd; + struct be_mcc_wrb *wrb; + struct be_cmd_req_get_fat *req; + struct be_sge *sge; + u32 offset = 0, total_size, buf_size, log_offset = sizeof(u32); + int status; + + if (buf_len == 0) + return; + + total_size = buf_len; + + spin_lock_bh(&adapter->mcc_lock); + + wrb = wrb_from_mccq(adapter); + if (!wrb) { + status = -EBUSY; + goto err; + } + while (total_size) { + buf_size = min(total_size, (u32)60*1024); + total_size -= buf_size; + + get_fat_cmd.size = sizeof(struct be_cmd_req_get_fat) + buf_size; + get_fat_cmd.va = pci_alloc_consistent(adapter->pdev, + get_fat_cmd.size, + &get_fat_cmd.dma); + if (!get_fat_cmd.va) { + status = -ENOMEM; + dev_err(&adapter->pdev->dev, + "Memory allocation failure while retrieving FAT data\n"); + goto err; + } + req = get_fat_cmd.va; + sge = nonembedded_sgl(wrb); + + be_wrb_hdr_prepare(wrb, get_fat_cmd.size, false, 1, + OPCODE_COMMON_MANAGE_FAT); + + be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON, + OPCODE_COMMON_MANAGE_FAT, get_fat_cmd.size); + + sge->pa_hi = cpu_to_le32(upper_32_bits(get_fat_cmd.size)); + sge->pa_lo = cpu_to_le32(get_fat_cmd.dma & 0xFFFFFFFF); + sge->len = cpu_to_le32(get_fat_cmd.size); + + req->fat_operation = cpu_to_le32(RETRIEVE_FAT); + req->read_log_offset = cpu_to_le32(log_offset); + req->read_log_length = cpu_to_le32(buf_size); + req->data_buffer_size = cpu_to_le32(buf_size); + + status = be_mcc_notify_wait(adapter); + if (!status) { + struct be_cmd_resp_get_fat *resp = get_fat_cmd.va; + memcpy(buf + offset, + resp->data_buffer, + resp->read_log_length); + } + pci_free_consistent(adapter->pdev, get_fat_cmd.size, + get_fat_cmd.va, + get_fat_cmd.dma); + if (status) + dev_err(&adapter->pdev->dev, "FAT Table Retrieve error\n"); + + offset += buf_size; + log_offset += buf_size; + } +err: + spin_unlock_bh(&adapter->mcc_lock); +} + /* Uses Mbox */ int be_cmd_get_fw_ver(struct be_adapter *adapter, char *fw_ver) { diff --git a/drivers/net/benet/be_cmds.h b/drivers/net/benet/be_cmds.h index 4f254cf..3fb6e0a 100644 --- a/drivers/net/benet/be_cmds.h +++ b/drivers/net/benet/be_cmds.h @@ -186,6 +186,7 @@ struct be_mcc_mailbox { #define OPCODE_COMMON_NTWK_PMAC_ADD 59 #define OPCODE_COMMON_NTWK_PMAC_DEL 60 #define OPCODE_COMMON_FUNCTION_RESET 61 +#define OPCODE_COMMON_MANAGE_FAT 68 #define OPCODE_COMMON_ENABLE_DISABLE_BEACON 69 #define OPCODE_COMMON_GET_BEACON_STATE 70 #define OPCODE_COMMON_READ_TRANSRECV_DATA 73 @@ -380,6 +381,24 @@ struct be_cmd_resp_cq_create { u16 rsvd0; } __packed; +struct be_cmd_req_get_fat { + struct be_cmd_req_hdr hdr; + u32 fat_operation; + u32 read_log_offset; + u32 read_log_length; + u32 data_buffer_size; + u32 data_buffer[1]; +} __packed; + +struct be_cmd_resp_get_fat { + struct be_cmd_resp_hdr hdr; + u32 log_size; + u32 read_log_length; + u32 rsvd[2]; + u32 data_buffer[1]; +} __packed; + + /******************** Create MCCQ ***************************/ /* Pseudo amap definition in which each bit of the actual structure is defined * as a byte: used to calculate offset/shift/mask of each field */ @@ -1148,4 +1167,6 @@ extern void be_detect_dump_ue(struct be_adapter *adapter); extern int be_cmd_get_die_temperature(struct be_adapter *adapter); extern int be_cmd_get_cntl_attributes(struct be_adapter *adapter); extern int be_cmd_check_native_mode(struct be_adapter *adapter); +extern int be_cmd_get_reg_len(struct be_adapter *adapter, u32 *log_size); +extern void be_cmd_get_regs(struct be_adapter *adapter, u32 buf_len, void *buf); diff --git a/drivers/net/benet/be_ethtool.c b/drivers/net/benet/be_ethtool.c index aac248f..575ac659 100644 --- a/drivers/net/benet/be_ethtool.c +++ b/drivers/net/benet/be_ethtool.c @@ -156,6 +156,25 @@ be_get_drvinfo(struct net_device *netdev, struct ethtool_drvinfo *drvinfo) } static int +be_get_reg_len(struct net_device *netdev) +{ + struct be_adapter *adapter = netdev_priv(netdev); + u32 log_size = 0; + + be_cmd_get_reg_len(adapter, &log_size); + return log_size; +} + +static void +be_get_regs(struct net_device *netdev, struct ethtool_regs *regs, void *buf) +{ + struct be_adapter *adapter = netdev_priv(netdev); + + memset(buf, 0, regs->len); + be_cmd_get_regs(adapter, regs->len, buf); +} + +static int be_get_coalesce(struct net_device *netdev, struct ethtool_coalesce *coalesce) { struct be_adapter *adapter = netdev_priv(netdev); @@ -737,6 +756,8 @@ const struct ethtool_ops be_ethtool_ops = { .phys_id = be_phys_id, .get_sset_count = be_get_sset_count, .get_ethtool_stats = be_get_ethtool_stats, + .get_regs_len = be_get_reg_len, + .get_regs = be_get_regs, .flash_device = be_do_flash, .self_test = be_self_test, }; diff --git a/drivers/net/benet/be_hw.h b/drivers/net/benet/be_hw.h index d4344a0..53d658a 100644 --- a/drivers/net/benet/be_hw.h +++ b/drivers/net/benet/be_hw.h @@ -155,6 +155,10 @@ /********** SRIOV VF PCICFG OFFSET ********/ #define SRIOV_VF_PCICFG_OFFSET (4096) +/********** FAT TABLE ********/ +#define RETRIEVE_FAT 0 +#define QUERY_FAT 1 + /* Flashrom related descriptors */ #define IMAGE_TYPE_FIRMWARE 160 #define IMAGE_TYPE_BOOTCODE 224 -- cgit v0.10.2 From ac6a0c4aab16070d7d55f49a52de33f716ae1d3d Mon Sep 17 00:00:00 2001 From: Sathya Perla Date: Mon, 21 Mar 2011 20:49:25 +0000 Subject: be2net: refactor code that decides adapter->num_rx_queues The code has been refactored to not set num_rx_qs inside be_enable_msix(). num_rx_qs is now set at the time of queue creation based on the number of available msix vectors. Signed-off-by: Sathya Perla Signed-off-by: David S. Miller diff --git a/drivers/net/benet/be.h b/drivers/net/benet/be.h index f803c58..3937bca 100644 --- a/drivers/net/benet/be.h +++ b/drivers/net/benet/be.h @@ -84,7 +84,8 @@ static inline char *nic_name(struct pci_dev *pdev) #define MCC_CQ_LEN 256 #define MAX_RSS_QS 4 /* BE limit is 4 queues/port */ -#define BE_MAX_MSIX_VECTORS (MAX_RSS_QS + 1 + 1)/* RSS qs + 1 def Rx + Tx */ +#define MAX_RX_QS (MAX_RSS_QS + 1) /* RSS qs + 1 def Rx */ +#define BE_MAX_MSIX_VECTORS (MAX_RX_QS + 1)/* RX + TX */ #define BE_NAPI_WEIGHT 64 #define MAX_RX_POST BE_NAPI_WEIGHT /* Frags posted at a time */ #define RX_FRAGS_REFILL_WM (RX_Q_LEN - MAX_RX_POST) @@ -276,7 +277,7 @@ struct be_adapter { spinlock_t mcc_cq_lock; struct msix_entry msix_entries[BE_MAX_MSIX_VECTORS]; - bool msix_enabled; + u32 num_msix_vec; bool isr_registered; /* TX Rings */ @@ -287,7 +288,7 @@ struct be_adapter { u32 cache_line_break[8]; /* Rx rings */ - struct be_rx_obj rx_obj[MAX_RSS_QS + 1]; /* one default non-rss Q */ + struct be_rx_obj rx_obj[MAX_RX_QS]; u32 num_rx_qs; u32 big_page_size; /* Compounded page size shared by rx wrbs */ @@ -351,6 +352,7 @@ struct be_adapter { extern const struct ethtool_ops be_ethtool_ops; +#define msix_enabled(adapter) (adapter->num_msix_vec > 0) #define tx_stats(adapter) (&adapter->tx_stats) #define rx_stats(rxo) (&rxo->stats) diff --git a/drivers/net/benet/be_main.c b/drivers/net/benet/be_main.c index a71163f..7a5d6a3 100644 --- a/drivers/net/benet/be_main.c +++ b/drivers/net/benet/be_main.c @@ -1567,12 +1567,31 @@ static void be_rx_queues_destroy(struct be_adapter *adapter) } } +static u32 be_num_rxqs_want(struct be_adapter *adapter) +{ + if (multi_rxq && (adapter->function_caps & BE_FUNCTION_CAPS_RSS) && + !adapter->sriov_enabled && !(adapter->function_mode & 0x400)) { + return 1 + MAX_RSS_QS; /* one default non-RSS queue */ + } else { + dev_warn(&adapter->pdev->dev, + "No support for multiple RX queues\n"); + return 1; + } +} + static int be_rx_queues_create(struct be_adapter *adapter) { struct be_queue_info *eq, *q, *cq; struct be_rx_obj *rxo; int rc, i; + adapter->num_rx_qs = min(be_num_rxqs_want(adapter), + msix_enabled(adapter) ? + adapter->num_msix_vec - 1 : 1); + if (adapter->num_rx_qs != MAX_RX_QS) + dev_warn(&adapter->pdev->dev, + "Can create only %d RX queues", adapter->num_rx_qs); + adapter->big_page_size = (1 << get_order(rx_frag_size)) * PAGE_SIZE; for_all_rx_queues(adapter, rxo, i) { rxo->adapter = adapter; @@ -1878,51 +1897,35 @@ reschedule: static void be_msix_disable(struct be_adapter *adapter) { - if (adapter->msix_enabled) { + if (msix_enabled(adapter)) { pci_disable_msix(adapter->pdev); - adapter->msix_enabled = false; - } -} - -static int be_num_rxqs_get(struct be_adapter *adapter) -{ - if (multi_rxq && (adapter->function_caps & BE_FUNCTION_CAPS_RSS) && - !adapter->sriov_enabled && !(adapter->function_mode & 0x400)) { - return 1 + MAX_RSS_QS; /* one default non-RSS queue */ - } else { - dev_warn(&adapter->pdev->dev, - "No support for multiple RX queues\n"); - return 1; + adapter->num_msix_vec = 0; } } static void be_msix_enable(struct be_adapter *adapter) { #define BE_MIN_MSIX_VECTORS (1 + 1) /* Rx + Tx */ - int i, status; + int i, status, num_vec; - adapter->num_rx_qs = be_num_rxqs_get(adapter); + num_vec = be_num_rxqs_want(adapter) + 1; - for (i = 0; i < (adapter->num_rx_qs + 1); i++) + for (i = 0; i < num_vec; i++) adapter->msix_entries[i].entry = i; - status = pci_enable_msix(adapter->pdev, adapter->msix_entries, - adapter->num_rx_qs + 1); + status = pci_enable_msix(adapter->pdev, adapter->msix_entries, num_vec); if (status == 0) { goto done; } else if (status >= BE_MIN_MSIX_VECTORS) { + num_vec = status; if (pci_enable_msix(adapter->pdev, adapter->msix_entries, - status) == 0) { - adapter->num_rx_qs = status - 1; - dev_warn(&adapter->pdev->dev, - "Could alloc only %d MSIx vectors. " - "Using %d RX Qs\n", status, adapter->num_rx_qs); + num_vec) == 0) goto done; - } } return; done: - adapter->msix_enabled = true; + adapter->num_msix_vec = num_vec; + return; } static void be_sriov_enable(struct be_adapter *adapter) @@ -2003,8 +2006,7 @@ err_msix: err: dev_warn(&adapter->pdev->dev, "MSIX Request IRQ failed - err %d\n", status); - pci_disable_msix(adapter->pdev); - adapter->msix_enabled = false; + be_msix_disable(adapter); return status; } @@ -2013,7 +2015,7 @@ static int be_irq_register(struct be_adapter *adapter) struct net_device *netdev = adapter->netdev; int status; - if (adapter->msix_enabled) { + if (msix_enabled(adapter)) { status = be_msix_register(adapter); if (status == 0) goto done; @@ -2046,7 +2048,7 @@ static void be_irq_unregister(struct be_adapter *adapter) return; /* INTx */ - if (!adapter->msix_enabled) { + if (!msix_enabled(adapter)) { free_irq(netdev->irq, adapter); goto done; } @@ -2088,7 +2090,7 @@ static int be_close(struct net_device *netdev) be_cq_notify(adapter, rxo->cq.id, false, 0); } - if (adapter->msix_enabled) { + if (msix_enabled(adapter)) { vec = be_msix_vec_get(adapter, tx_eq); synchronize_irq(vec); @@ -2261,7 +2263,7 @@ static int be_setup(struct be_adapter *adapter) BE_IF_FLAGS_PASS_L3L4_ERRORS; en_flags |= BE_IF_FLAGS_PASS_L3L4_ERRORS; - if (be_multi_rxq(adapter)) { + if (adapter->function_caps & BE_FUNCTION_CAPS_RSS) { cap_flags |= BE_IF_FLAGS_RSS; en_flags |= BE_IF_FLAGS_RSS; } -- cgit v0.10.2 From 15d721847f56f32fe9fd43d34db1b32b13de78dc Mon Sep 17 00:00:00 2001 From: Sathya Perla Date: Mon, 21 Mar 2011 20:49:26 +0000 Subject: be2net: parse vid and vtm fields of rx-compl only if vlanf bit is set Signed-off-by: Sathya Perla Signed-off-by: David S. Miller diff --git a/drivers/net/benet/be_main.c b/drivers/net/benet/be_main.c index 7a5d6a3..6616300 100644 --- a/drivers/net/benet/be_main.c +++ b/drivers/net/benet/be_main.c @@ -1101,8 +1101,12 @@ static void be_parse_rx_compl_v1(struct be_adapter *adapter, AMAP_GET_BITS(struct amap_eth_rx_compl_v1, numfrags, compl); rxcp->pkt_type = AMAP_GET_BITS(struct amap_eth_rx_compl_v1, cast_enc, compl); - rxcp->vtm = AMAP_GET_BITS(struct amap_eth_rx_compl_v1, vtm, compl); - rxcp->vid = AMAP_GET_BITS(struct amap_eth_rx_compl_v1, vlan_tag, compl); + if (rxcp->vlanf) { + rxcp->vtm = AMAP_GET_BITS(struct amap_eth_rx_compl_v1, vtm, + compl); + rxcp->vid = AMAP_GET_BITS(struct amap_eth_rx_compl_v1, vlan_tag, + compl); + } } static void be_parse_rx_compl_v0(struct be_adapter *adapter, @@ -1127,8 +1131,12 @@ static void be_parse_rx_compl_v0(struct be_adapter *adapter, AMAP_GET_BITS(struct amap_eth_rx_compl_v0, numfrags, compl); rxcp->pkt_type = AMAP_GET_BITS(struct amap_eth_rx_compl_v0, cast_enc, compl); - rxcp->vtm = AMAP_GET_BITS(struct amap_eth_rx_compl_v0, vtm, compl); - rxcp->vid = AMAP_GET_BITS(struct amap_eth_rx_compl_v0, vlan_tag, compl); + if (rxcp->vlanf) { + rxcp->vtm = AMAP_GET_BITS(struct amap_eth_rx_compl_v0, vtm, + compl); + rxcp->vid = AMAP_GET_BITS(struct amap_eth_rx_compl_v0, vlan_tag, + compl); + } } static struct be_rx_compl_info *be_rx_compl_get(struct be_rx_obj *rxo) @@ -1150,15 +1158,19 @@ static struct be_rx_compl_info *be_rx_compl_get(struct be_rx_obj *rxo) else be_parse_rx_compl_v0(adapter, compl, rxcp); - /* vlanf could be wrongly set in some cards. ignore if vtm is not set */ - if ((adapter->function_mode & 0x400) && !rxcp->vtm) - rxcp->vlanf = 0; + if (rxcp->vlanf) { + /* vlanf could be wrongly set in some cards. + * ignore if vtm is not set */ + if ((adapter->function_mode & 0x400) && !rxcp->vtm) + rxcp->vlanf = 0; - if (!lancer_chip(adapter)) - rxcp->vid = swab16(rxcp->vid); + if (!lancer_chip(adapter)) + rxcp->vid = swab16(rxcp->vid); - if ((adapter->pvid == rxcp->vid) && !adapter->vlan_tag[rxcp->vid]) - rxcp->vlanf = 0; + if ((adapter->pvid == rxcp->vid) && + !adapter->vlan_tag[rxcp->vid]) + rxcp->vlanf = 0; + } /* As the compl has been parsed, reset it; we wont touch it again */ compl->dw[offsetof(struct amap_eth_rx_compl_v1, valid) / 32] = 0; -- cgit v0.10.2 From 16da8250df36547269d20a3d53daa11c79f59637 Mon Sep 17 00:00:00 2001 From: Sathya Perla Date: Mon, 21 Mar 2011 20:49:27 +0000 Subject: be2net: remove redundant code in be_worker() Signed-off-by: Sathya Perla Signed-off-by: David S. Miller diff --git a/drivers/net/benet/be_main.c b/drivers/net/benet/be_main.c index 6616300..3bf79d1 100644 --- a/drivers/net/benet/be_main.c +++ b/drivers/net/benet/be_main.c @@ -1868,6 +1868,9 @@ static void be_worker(struct work_struct *work) struct be_rx_obj *rxo; int i; + if (!adapter->ue_detected && !lancer_chip(adapter)) + be_detect_dump_ue(adapter); + /* when interrupts are not yet enabled, just reap any pending * mcc completions */ if (!netif_running(adapter->netdev)) { @@ -1880,9 +1883,6 @@ static void be_worker(struct work_struct *work) be_cq_notify(adapter, mcc_obj->cq.id, false, mcc_compl); } - if (!adapter->ue_detected && !lancer_chip(adapter)) - be_detect_dump_ue(adapter); - goto reschedule; } @@ -1900,8 +1900,6 @@ static void be_worker(struct work_struct *work) be_post_rx_frags(rxo, GFP_KERNEL); } } - if (!adapter->ue_detected && !lancer_chip(adapter)) - be_detect_dump_ue(adapter); reschedule: schedule_delayed_work(&adapter->work, msecs_to_jiffies(1000)); -- cgit v0.10.2 From 0f4a682882171d81c9e3c33c1094b87a197c09fa Mon Sep 17 00:00:00 2001 From: Sathya Perla Date: Mon, 21 Mar 2011 20:49:28 +0000 Subject: be2net: cancel be_worker in be_shutdown() even when i/f is down As the be_worker() workqueue is scheduled in be_probe() it must be canceled unconditionally in be_shutdown(). Signed-off-by: Sathya Perla Signed-off-by: David S. Miller diff --git a/drivers/net/benet/be_main.c b/drivers/net/benet/be_main.c index 3bf79d1..8638913 100644 --- a/drivers/net/benet/be_main.c +++ b/drivers/net/benet/be_main.c @@ -3155,8 +3155,7 @@ static void be_shutdown(struct pci_dev *pdev) struct be_adapter *adapter = pci_get_drvdata(pdev); struct net_device *netdev = adapter->netdev; - if (netif_running(netdev)) - cancel_delayed_work_sync(&adapter->work); + cancel_delayed_work_sync(&adapter->work); netif_device_detach(netdev); -- cgit v0.10.2 From e8c37c80006c99a00aa70a783023d616c166a04b Mon Sep 17 00:00:00 2001 From: Sathya Perla Date: Mon, 21 Mar 2011 20:49:29 +0000 Subject: be2net: remove one useless line Signed-off-by: Sathya Perla Signed-off-by: David S. Miller diff --git a/drivers/net/benet/be_main.c b/drivers/net/benet/be_main.c index 8638913..a24fb45 100644 --- a/drivers/net/benet/be_main.c +++ b/drivers/net/benet/be_main.c @@ -2330,7 +2330,6 @@ static int be_setup(struct be_adapter *adapter) return 0; - be_mcc_queues_destroy(adapter); rx_qs_destroy: be_rx_queues_destroy(adapter); tx_qs_destroy: -- cgit v0.10.2 From dffc6b2432ea89af24a36e8100b3eeea09db67e5 Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Fri, 25 Mar 2011 14:21:22 +0000 Subject: smsc911x: Use pr_fmt, netdev_, and netif_ Use the more common/verbose logging styles. Add #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt Remove smsc911x prefixes from format strings. Rename SMSC_WARNING to SMSC_WARN. Remove DPRINTK macro. Use netif_ in SMSC_ macros. Convert NETIF_MSG_ uses to lower case. Add no_printk verification in non-debug uses. Add pdata to SMSC_ uses to avoid hidden variable uses. Convert printks to netdev_ as appropriate. Signed-off-by: Joe Perches Signed-off-by: David S. Miller diff --git a/drivers/net/smsc911x.c b/drivers/net/smsc911x.c index 1566259..8b501d5 100644 --- a/drivers/net/smsc911x.c +++ b/drivers/net/smsc911x.c @@ -29,6 +29,8 @@ * */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include #include #include @@ -248,8 +250,8 @@ static int smsc911x_mac_complete(struct smsc911x_data *pdata) if (!(val & MAC_CSR_CMD_CSR_BUSY_)) return 0; } - SMSC_WARNING(HW, "Timed out waiting for MAC not BUSY. " - "MAC_CSR_CMD: 0x%08X", val); + SMSC_WARN(pdata, hw, "Timed out waiting for MAC not BUSY. " + "MAC_CSR_CMD: 0x%08X", val); return -EIO; } @@ -262,7 +264,7 @@ static u32 smsc911x_mac_read(struct smsc911x_data *pdata, unsigned int offset) temp = smsc911x_reg_read(pdata, MAC_CSR_CMD); if (unlikely(temp & MAC_CSR_CMD_CSR_BUSY_)) { - SMSC_WARNING(HW, "MAC busy at entry"); + SMSC_WARN(pdata, hw, "MAC busy at entry"); return 0xFFFFFFFF; } @@ -277,7 +279,7 @@ static u32 smsc911x_mac_read(struct smsc911x_data *pdata, unsigned int offset) if (likely(smsc911x_mac_complete(pdata) == 0)) return smsc911x_reg_read(pdata, MAC_CSR_DATA); - SMSC_WARNING(HW, "MAC busy after read"); + SMSC_WARN(pdata, hw, "MAC busy after read"); return 0xFFFFFFFF; } @@ -291,8 +293,8 @@ static void smsc911x_mac_write(struct smsc911x_data *pdata, temp = smsc911x_reg_read(pdata, MAC_CSR_CMD); if (unlikely(temp & MAC_CSR_CMD_CSR_BUSY_)) { - SMSC_WARNING(HW, - "smsc911x_mac_write failed, MAC busy at entry"); + SMSC_WARN(pdata, hw, + "smsc911x_mac_write failed, MAC busy at entry"); return; } @@ -310,8 +312,7 @@ static void smsc911x_mac_write(struct smsc911x_data *pdata, if (likely(smsc911x_mac_complete(pdata) == 0)) return; - SMSC_WARNING(HW, - "smsc911x_mac_write failed, MAC busy after write"); + SMSC_WARN(pdata, hw, "smsc911x_mac_write failed, MAC busy after write"); } /* Get a phy register */ @@ -326,8 +327,7 @@ static int smsc911x_mii_read(struct mii_bus *bus, int phyaddr, int regidx) /* Confirm MII not busy */ if (unlikely(smsc911x_mac_read(pdata, MII_ACC) & MII_ACC_MII_BUSY_)) { - SMSC_WARNING(HW, - "MII is busy in smsc911x_mii_read???"); + SMSC_WARN(pdata, hw, "MII is busy in smsc911x_mii_read???"); reg = -EIO; goto out; } @@ -343,7 +343,7 @@ static int smsc911x_mii_read(struct mii_bus *bus, int phyaddr, int regidx) goto out; } - SMSC_WARNING(HW, "Timed out waiting for MII read to finish"); + SMSC_WARN(pdata, hw, "Timed out waiting for MII read to finish"); reg = -EIO; out: @@ -364,8 +364,7 @@ static int smsc911x_mii_write(struct mii_bus *bus, int phyaddr, int regidx, /* Confirm MII not busy */ if (unlikely(smsc911x_mac_read(pdata, MII_ACC) & MII_ACC_MII_BUSY_)) { - SMSC_WARNING(HW, - "MII is busy in smsc911x_mii_write???"); + SMSC_WARN(pdata, hw, "MII is busy in smsc911x_mii_write???"); reg = -EIO; goto out; } @@ -385,7 +384,7 @@ static int smsc911x_mii_write(struct mii_bus *bus, int phyaddr, int regidx, goto out; } - SMSC_WARNING(HW, "Timed out waiting for MII write to finish"); + SMSC_WARN(pdata, hw, "Timed out waiting for MII write to finish"); reg = -EIO; out: @@ -426,18 +425,20 @@ static void smsc911x_phy_initialise_external(struct smsc911x_data *pdata) unsigned int hwcfg = smsc911x_reg_read(pdata, HW_CFG); if (pdata->config.flags & SMSC911X_FORCE_INTERNAL_PHY) { - SMSC_TRACE(HW, "Forcing internal PHY"); + SMSC_TRACE(pdata, hw, "Forcing internal PHY"); pdata->using_extphy = 0; } else if (pdata->config.flags & SMSC911X_FORCE_EXTERNAL_PHY) { - SMSC_TRACE(HW, "Forcing external PHY"); + SMSC_TRACE(pdata, hw, "Forcing external PHY"); smsc911x_phy_enable_external(pdata); pdata->using_extphy = 1; } else if (hwcfg & HW_CFG_EXT_PHY_DET_) { - SMSC_TRACE(HW, "HW_CFG EXT_PHY_DET set, using external PHY"); + SMSC_TRACE(pdata, hw, + "HW_CFG EXT_PHY_DET set, using external PHY"); smsc911x_phy_enable_external(pdata); pdata->using_extphy = 1; } else { - SMSC_TRACE(HW, "HW_CFG EXT_PHY_DET clear, using internal PHY"); + SMSC_TRACE(pdata, hw, + "HW_CFG EXT_PHY_DET clear, using internal PHY"); pdata->using_extphy = 0; } } @@ -509,13 +510,13 @@ static int smsc911x_phy_check_loopbackpkt(struct smsc911x_data *pdata) } while ((i--) && (!status)); if (!status) { - SMSC_WARNING(HW, "Failed to transmit " - "during loopback test"); + SMSC_WARN(pdata, hw, + "Failed to transmit during loopback test"); continue; } if (status & TX_STS_ES_) { - SMSC_WARNING(HW, "Transmit encountered " - "errors during loopback test"); + SMSC_WARN(pdata, hw, + "Transmit encountered errors during loopback test"); continue; } @@ -527,13 +528,13 @@ static int smsc911x_phy_check_loopbackpkt(struct smsc911x_data *pdata) } while ((i--) && (!status)); if (!status) { - SMSC_WARNING(HW, - "Failed to receive during loopback test"); + SMSC_WARN(pdata, hw, + "Failed to receive during loopback test"); continue; } if (status & RX_STS_ES_) { - SMSC_WARNING(HW, "Receive encountered " - "errors during loopback test"); + SMSC_WARN(pdata, hw, + "Receive encountered errors during loopback test"); continue; } @@ -546,9 +547,9 @@ static int smsc911x_phy_check_loopbackpkt(struct smsc911x_data *pdata) smsc911x_rx_readfifo(pdata, (unsigned int *)bufp, rdsz); if (pktlength != (MIN_PACKET_SIZE + 4)) { - SMSC_WARNING(HW, "Unexpected packet size " - "during loop back test, size=%d, will retry", - pktlength); + SMSC_WARN(pdata, hw, "Unexpected packet size " + "during loop back test, size=%d, will retry", + pktlength); } else { unsigned int j; int mismatch = 0; @@ -560,12 +561,12 @@ static int smsc911x_phy_check_loopbackpkt(struct smsc911x_data *pdata) } } if (!mismatch) { - SMSC_TRACE(HW, "Successfully verified " + SMSC_TRACE(pdata, hw, "Successfully verified " "loopback packet"); return 0; } else { - SMSC_WARNING(HW, "Data mismatch " - "during loop back test, will retry"); + SMSC_WARN(pdata, hw, "Data mismatch " + "during loop back test, will retry"); } } } @@ -582,7 +583,7 @@ static int smsc911x_phy_reset(struct smsc911x_data *pdata) BUG_ON(!phy_dev); BUG_ON(!phy_dev->bus); - SMSC_TRACE(HW, "Performing PHY BCR Reset"); + SMSC_TRACE(pdata, hw, "Performing PHY BCR Reset"); smsc911x_mii_write(phy_dev->bus, phy_dev->addr, MII_BMCR, BMCR_RESET); do { msleep(1); @@ -591,7 +592,7 @@ static int smsc911x_phy_reset(struct smsc911x_data *pdata) } while ((i--) && (temp & BMCR_RESET)); if (temp & BMCR_RESET) { - SMSC_WARNING(HW, "PHY reset failed to complete."); + SMSC_WARN(pdata, hw, "PHY reset failed to complete"); return -EIO; } /* Extra delay required because the phy may not be completed with @@ -695,11 +696,11 @@ static void smsc911x_phy_update_flowcontrol(struct smsc911x_data *pdata) else afc &= ~0xF; - SMSC_TRACE(HW, "rx pause %s, tx pause %s", - (cap & FLOW_CTRL_RX ? "enabled" : "disabled"), - (cap & FLOW_CTRL_TX ? "enabled" : "disabled")); + SMSC_TRACE(pdata, hw, "rx pause %s, tx pause %s", + (cap & FLOW_CTRL_RX ? "enabled" : "disabled"), + (cap & FLOW_CTRL_TX ? "enabled" : "disabled")); } else { - SMSC_TRACE(HW, "half duplex"); + SMSC_TRACE(pdata, hw, "half duplex"); flow = 0; afc |= 0xF; } @@ -722,17 +723,17 @@ static void smsc911x_phy_adjust_link(struct net_device *dev) if (phy_dev->duplex != pdata->last_duplex) { unsigned int mac_cr; - SMSC_TRACE(HW, "duplex state has changed"); + SMSC_TRACE(pdata, hw, "duplex state has changed"); spin_lock_irqsave(&pdata->mac_lock, flags); mac_cr = smsc911x_mac_read(pdata, MAC_CR); if (phy_dev->duplex) { - SMSC_TRACE(HW, - "configuring for full duplex mode"); + SMSC_TRACE(pdata, hw, + "configuring for full duplex mode"); mac_cr |= MAC_CR_FDPX_; } else { - SMSC_TRACE(HW, - "configuring for half duplex mode"); + SMSC_TRACE(pdata, hw, + "configuring for half duplex mode"); mac_cr &= ~MAC_CR_FDPX_; } smsc911x_mac_write(pdata, MAC_CR, mac_cr); @@ -744,9 +745,9 @@ static void smsc911x_phy_adjust_link(struct net_device *dev) carrier = netif_carrier_ok(dev); if (carrier != pdata->last_carrier) { - SMSC_TRACE(HW, "carrier state has changed"); + SMSC_TRACE(pdata, hw, "carrier state has changed"); if (carrier) { - SMSC_TRACE(HW, "configuring for carrier OK"); + SMSC_TRACE(pdata, hw, "configuring for carrier OK"); if ((pdata->gpio_orig_setting & GPIO_CFG_LED1_EN_) && (!pdata->using_extphy)) { /* Restore original GPIO configuration */ @@ -755,7 +756,7 @@ static void smsc911x_phy_adjust_link(struct net_device *dev) pdata->gpio_setting); } } else { - SMSC_TRACE(HW, "configuring for no carrier"); + SMSC_TRACE(pdata, hw, "configuring for no carrier"); /* Check global setting that LED1 * usage is 10/100 indicator */ pdata->gpio_setting = smsc911x_reg_read(pdata, @@ -787,25 +788,25 @@ static int smsc911x_mii_probe(struct net_device *dev) /* find the first phy */ phydev = phy_find_first(pdata->mii_bus); if (!phydev) { - pr_err("%s: no PHY found\n", dev->name); + netdev_err(dev, "no PHY found\n"); return -ENODEV; } - SMSC_TRACE(PROBE, "PHY: addr %d, phy_id 0x%08X", - phydev->addr, phydev->phy_id); + SMSC_TRACE(pdata, probe, "PHY: addr %d, phy_id 0x%08X", + phydev->addr, phydev->phy_id); ret = phy_connect_direct(dev, phydev, &smsc911x_phy_adjust_link, 0, pdata->config.phy_interface); if (ret) { - pr_err("%s: Could not attach to PHY\n", dev->name); + netdev_err(dev, "Could not attach to PHY\n"); return ret; } - pr_info("%s: attached PHY driver [%s] (mii_bus:phy_addr=%s, irq=%d)\n", - dev->name, phydev->drv->name, - dev_name(&phydev->dev), phydev->irq); + netdev_info(dev, + "attached PHY driver [%s] (mii_bus:phy_addr=%s, irq=%d)\n", + phydev->drv->name, dev_name(&phydev->dev), phydev->irq); /* mask with MAC supported features */ phydev->supported &= (PHY_BASIC_FEATURES | SUPPORTED_Pause | @@ -818,13 +819,13 @@ static int smsc911x_mii_probe(struct net_device *dev) #ifdef USE_PHY_WORK_AROUND if (smsc911x_phy_loopbacktest(dev) < 0) { - SMSC_WARNING(HW, "Failed Loop Back Test"); + SMSC_WARN(pdata, hw, "Failed Loop Back Test"); return -ENODEV; } - SMSC_TRACE(HW, "Passed Loop Back Test"); + SMSC_TRACE(pdata, hw, "Passed Loop Back Test"); #endif /* USE_PHY_WORK_AROUND */ - SMSC_TRACE(HW, "phy initialised successfully"); + SMSC_TRACE(pdata, hw, "phy initialised successfully"); return 0; } @@ -860,8 +861,8 @@ static int __devinit smsc911x_mii_init(struct platform_device *pdev, smsc911x_phy_initialise_external(pdata); break; default: - SMSC_TRACE(HW, "External PHY is not supported, " - "using internal PHY"); + SMSC_TRACE(pdata, hw, "External PHY is not supported, " + "using internal PHY"); pdata->using_extphy = 0; break; } @@ -872,12 +873,12 @@ static int __devinit smsc911x_mii_init(struct platform_device *pdev, } if (mdiobus_register(pdata->mii_bus)) { - SMSC_WARNING(PROBE, "Error registering mii bus"); + SMSC_WARN(pdata, probe, "Error registering mii bus"); goto err_out_free_bus_2; } if (smsc911x_mii_probe(dev) < 0) { - SMSC_WARNING(PROBE, "Error registering mii bus"); + SMSC_WARN(pdata, probe, "Error registering mii bus"); goto err_out_unregister_bus_3; } @@ -913,8 +914,7 @@ static void smsc911x_tx_update_txcounters(struct net_device *dev) * does not reference a hardware defined reserved bit * but rather a driver defined one. */ - SMSC_WARNING(HW, - "Packet tag reserved bit is high"); + SMSC_WARN(pdata, hw, "Packet tag reserved bit is high"); } else { if (unlikely(tx_stat & TX_STS_ES_)) { dev->stats.tx_errors++; @@ -977,8 +977,8 @@ smsc911x_rx_fastforward(struct smsc911x_data *pdata, unsigned int pktbytes) } while ((val & RX_DP_CTRL_RX_FFWD_) && --timeout); if (unlikely(timeout == 0)) - SMSC_WARNING(HW, "Timed out waiting for " - "RX FFWD to finish, RX_DP_CTRL: 0x%08X", val); + SMSC_WARN(pdata, hw, "Timed out waiting for " + "RX FFWD to finish, RX_DP_CTRL: 0x%08X", val); } else { unsigned int temp; while (pktwords--) @@ -1021,8 +1021,8 @@ static int smsc911x_poll(struct napi_struct *napi, int budget) smsc911x_rx_counterrors(dev, rxstat); if (unlikely(rxstat & RX_STS_ES_)) { - SMSC_WARNING(RX_ERR, - "Discarding packet with error bit set"); + SMSC_WARN(pdata, rx_err, + "Discarding packet with error bit set"); /* Packet has an error, discard it and continue with * the next */ smsc911x_rx_fastforward(pdata, pktwords); @@ -1032,8 +1032,8 @@ static int smsc911x_poll(struct napi_struct *napi, int budget) skb = netdev_alloc_skb(dev, pktlength + NET_IP_ALIGN); if (unlikely(!skb)) { - SMSC_WARNING(RX_ERR, - "Unable to allocate skb for rx packet"); + SMSC_WARN(pdata, rx_err, + "Unable to allocate skb for rx packet"); /* Drop the packet and stop this polling iteration */ smsc911x_rx_fastforward(pdata, pktwords); dev->stats.rx_dropped++; @@ -1083,8 +1083,8 @@ static void smsc911x_rx_multicast_update(struct smsc911x_data *pdata) smsc911x_mac_write(pdata, MAC_CR, mac_cr); smsc911x_mac_write(pdata, HASHH, pdata->hashhi); smsc911x_mac_write(pdata, HASHL, pdata->hashlo); - SMSC_TRACE(HW, "maccr 0x%08X, HASHH 0x%08X, HASHL 0x%08X", - mac_cr, pdata->hashhi, pdata->hashlo); + SMSC_TRACE(pdata, hw, "maccr 0x%08X, HASHH 0x%08X, HASHL 0x%08X", + mac_cr, pdata->hashhi, pdata->hashlo); } static void smsc911x_rx_multicast_update_workaround(struct smsc911x_data *pdata) @@ -1102,7 +1102,7 @@ static void smsc911x_rx_multicast_update_workaround(struct smsc911x_data *pdata) /* Check Rx has stopped */ if (smsc911x_mac_read(pdata, MAC_CR) & MAC_CR_RXEN_) - SMSC_WARNING(DRV, "Rx not stopped"); + SMSC_WARN(pdata, drv, "Rx not stopped"); /* Perform the update - safe to do now Rx has stopped */ smsc911x_rx_multicast_update(pdata); @@ -1131,7 +1131,7 @@ static int smsc911x_soft_reset(struct smsc911x_data *pdata) } while ((--timeout) && (temp & HW_CFG_SRST_)); if (unlikely(temp & HW_CFG_SRST_)) { - SMSC_WARNING(DRV, "Failed to complete reset"); + SMSC_WARN(pdata, drv, "Failed to complete reset"); return -EIO; } return 0; @@ -1160,18 +1160,18 @@ static int smsc911x_open(struct net_device *dev) /* if the phy is not yet registered, retry later*/ if (!pdata->phy_dev) { - SMSC_WARNING(HW, "phy_dev is NULL"); + SMSC_WARN(pdata, hw, "phy_dev is NULL"); return -EAGAIN; } if (!is_valid_ether_addr(dev->dev_addr)) { - SMSC_WARNING(HW, "dev_addr is not a valid MAC address"); + SMSC_WARN(pdata, hw, "dev_addr is not a valid MAC address"); return -EADDRNOTAVAIL; } /* Reset the LAN911x */ if (smsc911x_soft_reset(pdata)) { - SMSC_WARNING(HW, "soft reset failed"); + SMSC_WARN(pdata, hw, "soft reset failed"); return -EIO; } @@ -1191,8 +1191,8 @@ static int smsc911x_open(struct net_device *dev) } if (unlikely(timeout == 0)) - SMSC_WARNING(IFUP, - "Timed out waiting for EEPROM busy bit to clear"); + SMSC_WARN(pdata, ifup, + "Timed out waiting for EEPROM busy bit to clear"); smsc911x_reg_write(pdata, GPIO_CFG, 0x70070000); @@ -1210,22 +1210,22 @@ static int smsc911x_open(struct net_device *dev) intcfg = ((10 << 24) | INT_CFG_IRQ_EN_); if (pdata->config.irq_polarity) { - SMSC_TRACE(IFUP, "irq polarity: active high"); + SMSC_TRACE(pdata, ifup, "irq polarity: active high"); intcfg |= INT_CFG_IRQ_POL_; } else { - SMSC_TRACE(IFUP, "irq polarity: active low"); + SMSC_TRACE(pdata, ifup, "irq polarity: active low"); } if (pdata->config.irq_type) { - SMSC_TRACE(IFUP, "irq type: push-pull"); + SMSC_TRACE(pdata, ifup, "irq type: push-pull"); intcfg |= INT_CFG_IRQ_TYPE_; } else { - SMSC_TRACE(IFUP, "irq type: open drain"); + SMSC_TRACE(pdata, ifup, "irq type: open drain"); } smsc911x_reg_write(pdata, INT_CFG, intcfg); - SMSC_TRACE(IFUP, "Testing irq handler using IRQ %d", dev->irq); + SMSC_TRACE(pdata, ifup, "Testing irq handler using IRQ %d", dev->irq); pdata->software_irq_signal = 0; smp_wmb(); @@ -1241,14 +1241,15 @@ static int smsc911x_open(struct net_device *dev) } if (!pdata->software_irq_signal) { - dev_warn(&dev->dev, "ISR failed signaling test (IRQ %d)\n", - dev->irq); + netdev_warn(dev, "ISR failed signaling test (IRQ %d)\n", + dev->irq); return -ENODEV; } - SMSC_TRACE(IFUP, "IRQ handler passed test using IRQ %d", dev->irq); + SMSC_TRACE(pdata, ifup, "IRQ handler passed test using IRQ %d", + dev->irq); - dev_info(&dev->dev, "SMSC911x/921x identified at %#08lx, IRQ: %d\n", - (unsigned long)pdata->ioaddr, dev->irq); + netdev_info(dev, "SMSC911x/921x identified at %#08lx, IRQ: %d\n", + (unsigned long)pdata->ioaddr, dev->irq); /* Reset the last known duplex and carrier */ pdata->last_duplex = -1; @@ -1313,7 +1314,7 @@ static int smsc911x_stop(struct net_device *dev) if (pdata->phy_dev) phy_stop(pdata->phy_dev); - SMSC_TRACE(IFDOWN, "Interface stopped"); + SMSC_TRACE(pdata, ifdown, "Interface stopped"); return 0; } @@ -1331,8 +1332,8 @@ static int smsc911x_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) freespace = smsc911x_reg_read(pdata, TX_FIFO_INF) & TX_FIFO_INF_TDFREE_; if (unlikely(freespace < TX_FIFO_LOW_THRESHOLD)) - SMSC_WARNING(TX_ERR, - "Tx data fifo low, space available: %d", freespace); + SMSC_WARN(pdata, tx_err, + "Tx data fifo low, space available: %d", freespace); /* Word alignment adjustment */ tx_cmd_a = (u32)((ulong)skb->data & 0x03) << 16; @@ -1432,7 +1433,7 @@ static void smsc911x_set_multicast_list(struct net_device *dev) * receiving data */ if (!pdata->multicast_update_pending) { unsigned int temp; - SMSC_TRACE(HW, "scheduling mcast update"); + SMSC_TRACE(pdata, hw, "scheduling mcast update"); pdata->multicast_update_pending = 1; /* Request the hardware to stop, then perform the @@ -1474,7 +1475,7 @@ static irqreturn_t smsc911x_irqhandler(int irq, void *dev_id) if (unlikely(intsts & inten & INT_STS_RXSTOP_INT_)) { /* Called when there is a multicast update scheduled and * it is now safe to complete the update */ - SMSC_TRACE(INTR, "RX Stop interrupt"); + SMSC_TRACE(pdata, intr, "RX Stop interrupt"); smsc911x_reg_write(pdata, INT_STS, INT_STS_RXSTOP_INT_); if (pdata->multicast_update_pending) smsc911x_rx_multicast_update_workaround(pdata); @@ -1491,7 +1492,7 @@ static irqreturn_t smsc911x_irqhandler(int irq, void *dev_id) } if (unlikely(intsts & inten & INT_STS_RXE_)) { - SMSC_TRACE(INTR, "RX Error interrupt"); + SMSC_TRACE(pdata, intr, "RX Error interrupt"); smsc911x_reg_write(pdata, INT_STS, INT_STS_RXE_); serviced = IRQ_HANDLED; } @@ -1505,8 +1506,7 @@ static irqreturn_t smsc911x_irqhandler(int irq, void *dev_id) /* Schedule a NAPI poll */ __napi_schedule(&pdata->napi); } else { - SMSC_WARNING(RX_ERR, - "napi_schedule_prep failed"); + SMSC_WARN(pdata, rx_err, "napi_schedule_prep failed"); } serviced = IRQ_HANDLED; } @@ -1543,7 +1543,7 @@ static int smsc911x_set_mac_address(struct net_device *dev, void *p) smsc911x_set_hw_mac_address(pdata, dev->dev_addr); spin_unlock_irq(&pdata->mac_lock); - dev_info(&dev->dev, "MAC Address: %pM\n", dev->dev_addr); + netdev_info(dev, "MAC Address: %pM\n", dev->dev_addr); return 0; } @@ -1649,9 +1649,9 @@ static int smsc911x_eeprom_send_cmd(struct smsc911x_data *pdata, u32 op) int timeout = 100; u32 e2cmd; - SMSC_TRACE(DRV, "op 0x%08x", op); + SMSC_TRACE(pdata, drv, "op 0x%08x", op); if (smsc911x_reg_read(pdata, E2P_CMD) & E2P_CMD_EPC_BUSY_) { - SMSC_WARNING(DRV, "Busy at start"); + SMSC_WARN(pdata, drv, "Busy at start"); return -EBUSY; } @@ -1664,12 +1664,12 @@ static int smsc911x_eeprom_send_cmd(struct smsc911x_data *pdata, u32 op) } while ((e2cmd & E2P_CMD_EPC_BUSY_) && (--timeout)); if (!timeout) { - SMSC_TRACE(DRV, "TIMED OUT"); + SMSC_TRACE(pdata, drv, "TIMED OUT"); return -EAGAIN; } if (e2cmd & E2P_CMD_EPC_TIMEOUT_) { - SMSC_TRACE(DRV, "Error occured during eeprom operation"); + SMSC_TRACE(pdata, drv, "Error occured during eeprom operation"); return -EINVAL; } @@ -1682,7 +1682,7 @@ static int smsc911x_eeprom_read_location(struct smsc911x_data *pdata, u32 op = E2P_CMD_EPC_CMD_READ_ | address; int ret; - SMSC_TRACE(DRV, "address 0x%x", address); + SMSC_TRACE(pdata, drv, "address 0x%x", address); ret = smsc911x_eeprom_send_cmd(pdata, op); if (!ret) @@ -1698,7 +1698,7 @@ static int smsc911x_eeprom_write_location(struct smsc911x_data *pdata, u32 temp; int ret; - SMSC_TRACE(DRV, "address 0x%x, data 0x%x", address, data); + SMSC_TRACE(pdata, drv, "address 0x%x, data 0x%x", address, data); ret = smsc911x_eeprom_send_cmd(pdata, op); if (!ret) { @@ -1811,25 +1811,25 @@ static int __devinit smsc911x_init(struct net_device *dev) struct smsc911x_data *pdata = netdev_priv(dev); unsigned int byte_test; - SMSC_TRACE(PROBE, "Driver Parameters:"); - SMSC_TRACE(PROBE, "LAN base: 0x%08lX", - (unsigned long)pdata->ioaddr); - SMSC_TRACE(PROBE, "IRQ: %d", dev->irq); - SMSC_TRACE(PROBE, "PHY will be autodetected."); + SMSC_TRACE(pdata, probe, "Driver Parameters:"); + SMSC_TRACE(pdata, probe, "LAN base: 0x%08lX", + (unsigned long)pdata->ioaddr); + SMSC_TRACE(pdata, probe, "IRQ: %d", dev->irq); + SMSC_TRACE(pdata, probe, "PHY will be autodetected."); spin_lock_init(&pdata->dev_lock); if (pdata->ioaddr == 0) { - SMSC_WARNING(PROBE, "pdata->ioaddr: 0x00000000"); + SMSC_WARN(pdata, probe, "pdata->ioaddr: 0x00000000"); return -ENODEV; } /* Check byte ordering */ byte_test = smsc911x_reg_read(pdata, BYTE_TEST); - SMSC_TRACE(PROBE, "BYTE_TEST: 0x%08X", byte_test); + SMSC_TRACE(pdata, probe, "BYTE_TEST: 0x%08X", byte_test); if (byte_test == 0x43218765) { - SMSC_TRACE(PROBE, "BYTE_TEST looks swapped, " - "applying WORD_SWAP"); + SMSC_TRACE(pdata, probe, "BYTE_TEST looks swapped, " + "applying WORD_SWAP"); smsc911x_reg_write(pdata, WORD_SWAP, 0xffffffff); /* 1 dummy read of BYTE_TEST is needed after a write to @@ -1840,12 +1840,13 @@ static int __devinit smsc911x_init(struct net_device *dev) } if (byte_test != 0x87654321) { - SMSC_WARNING(DRV, "BYTE_TEST: 0x%08X", byte_test); + SMSC_WARN(pdata, drv, "BYTE_TEST: 0x%08X", byte_test); if (((byte_test >> 16) & 0xFFFF) == (byte_test & 0xFFFF)) { - SMSC_WARNING(PROBE, - "top 16 bits equal to bottom 16 bits"); - SMSC_TRACE(PROBE, "This may mean the chip is set " - "for 32 bit while the bus is reading 16 bit"); + SMSC_WARN(pdata, probe, + "top 16 bits equal to bottom 16 bits"); + SMSC_TRACE(pdata, probe, + "This may mean the chip is set " + "for 32 bit while the bus is reading 16 bit"); } return -ENODEV; } @@ -1880,17 +1881,18 @@ static int __devinit smsc911x_init(struct net_device *dev) break; default: - SMSC_WARNING(PROBE, "LAN911x not identified, idrev: 0x%08X", - pdata->idrev); + SMSC_WARN(pdata, probe, "LAN911x not identified, idrev: 0x%08X", + pdata->idrev); return -ENODEV; } - SMSC_TRACE(PROBE, "LAN911x identified, idrev: 0x%08X, generation: %d", - pdata->idrev, pdata->generation); + SMSC_TRACE(pdata, probe, + "LAN911x identified, idrev: 0x%08X, generation: %d", + pdata->idrev, pdata->generation); if (pdata->generation == 0) - SMSC_WARNING(PROBE, - "This driver is not intended for this chip revision"); + SMSC_WARN(pdata, probe, + "This driver is not intended for this chip revision"); /* workaround for platforms without an eeprom, where the mac address * is stored elsewhere and set by the bootloader. This saves the @@ -1927,7 +1929,7 @@ static int __devexit smsc911x_drv_remove(struct platform_device *pdev) BUG_ON(!pdata->ioaddr); BUG_ON(!pdata->phy_dev); - SMSC_TRACE(IFDOWN, "Stopping driver."); + SMSC_TRACE(pdata, ifdown, "Stopping driver"); phy_disconnect(pdata->phy_dev); pdata->phy_dev = NULL; @@ -1961,11 +1963,11 @@ static int __devinit smsc911x_drv_probe(struct platform_device *pdev) int res_size, irq_flags; int retval; - pr_info("%s: Driver version %s.\n", SMSC_CHIPNAME, SMSC_DRV_VERSION); + pr_info("Driver version %s\n", SMSC_DRV_VERSION); /* platform data specifies irq & dynamic bus configuration */ if (!pdev->dev.platform_data) { - pr_warning("%s: platform_data not provided\n", SMSC_CHIPNAME); + pr_warn("platform_data not provided\n"); retval = -ENODEV; goto out_0; } @@ -1975,8 +1977,7 @@ static int __devinit smsc911x_drv_probe(struct platform_device *pdev) if (!res) res = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!res) { - pr_warning("%s: Could not allocate resource.\n", - SMSC_CHIPNAME); + pr_warn("Could not allocate resource\n"); retval = -ENODEV; goto out_0; } @@ -1984,8 +1985,7 @@ static int __devinit smsc911x_drv_probe(struct platform_device *pdev) irq_res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); if (!irq_res) { - pr_warning("%s: Could not allocate irq resource.\n", - SMSC_CHIPNAME); + pr_warn("Could not allocate irq resource\n"); retval = -ENODEV; goto out_0; } @@ -1997,7 +1997,7 @@ static int __devinit smsc911x_drv_probe(struct platform_device *pdev) dev = alloc_etherdev(sizeof(struct smsc911x_data)); if (!dev) { - pr_warning("%s: Could not allocate device.\n", SMSC_CHIPNAME); + pr_warn("Could not allocate device\n"); retval = -ENOMEM; goto out_release_io_1; } @@ -2017,8 +2017,7 @@ static int __devinit smsc911x_drv_probe(struct platform_device *pdev) pdata->msg_enable = ((1 << debug) - 1); if (pdata->ioaddr == NULL) { - SMSC_WARNING(PROBE, - "Error smsc911x base address invalid"); + SMSC_WARN(pdata, probe, "Error smsc911x base address invalid"); retval = -ENOMEM; goto out_free_netdev_2; } @@ -2043,8 +2042,8 @@ static int __devinit smsc911x_drv_probe(struct platform_device *pdev) retval = request_irq(dev->irq, smsc911x_irqhandler, irq_flags | IRQF_SHARED, dev->name, dev); if (retval) { - SMSC_WARNING(PROBE, - "Unable to claim requested irq: %d", dev->irq); + SMSC_WARN(pdata, probe, + "Unable to claim requested irq: %d", dev->irq); goto out_unmap_io_3; } @@ -2052,19 +2051,18 @@ static int __devinit smsc911x_drv_probe(struct platform_device *pdev) retval = register_netdev(dev); if (retval) { - SMSC_WARNING(PROBE, - "Error %i registering device", retval); + SMSC_WARN(pdata, probe, "Error %i registering device", retval); goto out_unset_drvdata_4; } else { - SMSC_TRACE(PROBE, "Network interface: \"%s\"", dev->name); + SMSC_TRACE(pdata, probe, + "Network interface: \"%s\"", dev->name); } spin_lock_init(&pdata->mac_lock); retval = smsc911x_mii_init(pdev, dev); if (retval) { - SMSC_WARNING(PROBE, - "Error %i initialising mii", retval); + SMSC_WARN(pdata, probe, "Error %i initialising mii", retval); goto out_unregister_netdev_5; } @@ -2073,10 +2071,12 @@ static int __devinit smsc911x_drv_probe(struct platform_device *pdev) /* Check if mac address has been specified when bringing interface up */ if (is_valid_ether_addr(dev->dev_addr)) { smsc911x_set_hw_mac_address(pdata, dev->dev_addr); - SMSC_TRACE(PROBE, "MAC Address is specified by configuration"); + SMSC_TRACE(pdata, probe, + "MAC Address is specified by configuration"); } else if (is_valid_ether_addr(pdata->config.mac)) { memcpy(dev->dev_addr, pdata->config.mac, 6); - SMSC_TRACE(PROBE, "MAC Address specified by platform data"); + SMSC_TRACE(pdata, probe, + "MAC Address specified by platform data"); } else { /* Try reading mac address from device. if EEPROM is present * it will already have been set */ @@ -2084,20 +2084,20 @@ static int __devinit smsc911x_drv_probe(struct platform_device *pdev) if (is_valid_ether_addr(dev->dev_addr)) { /* eeprom values are valid so use them */ - SMSC_TRACE(PROBE, - "Mac Address is read from LAN911x EEPROM"); + SMSC_TRACE(pdata, probe, + "Mac Address is read from LAN911x EEPROM"); } else { /* eeprom values are invalid, generate random MAC */ random_ether_addr(dev->dev_addr); smsc911x_set_hw_mac_address(pdata, dev->dev_addr); - SMSC_TRACE(PROBE, - "MAC Address is set to random_ether_addr"); + SMSC_TRACE(pdata, probe, + "MAC Address is set to random_ether_addr"); } } spin_unlock_irq(&pdata->mac_lock); - dev_info(&dev->dev, "MAC Address: %pM\n", dev->dev_addr); + netdev_info(dev, "MAC Address: %pM\n", dev->dev_addr); return 0; diff --git a/drivers/net/smsc911x.h b/drivers/net/smsc911x.h index 50f712e..8d67aac 100644 --- a/drivers/net/smsc911x.h +++ b/drivers/net/smsc911x.h @@ -33,25 +33,21 @@ * can be successfully looped back */ #define USE_PHY_WORK_AROUND -#define DPRINTK(nlevel, klevel, fmt, args...) \ - ((void)((NETIF_MSG_##nlevel & pdata->msg_enable) && \ - printk(KERN_##klevel "%s: %s: " fmt "\n", \ - pdata->dev->name, __func__, ## args))) - #if USE_DEBUG >= 1 -#define SMSC_WARNING(nlevel, fmt, args...) \ - DPRINTK(nlevel, WARNING, fmt, ## args) +#define SMSC_WARN(pdata, nlevel, fmt, args...) \ + netif_warn(pdata, nlevel, (pdata)->dev, \ + "%s: " fmt "\n", __func__, ##args) #else -#define SMSC_WARNING(nlevel, fmt, args...) \ - ({ do {} while (0); 0; }) +#define SMSC_WARN(pdata, nlevel, fmt, args...) \ + no_printk(fmt "\n", ##args) #endif #if USE_DEBUG >= 2 -#define SMSC_TRACE(nlevel, fmt, args...) \ - DPRINTK(nlevel, INFO, fmt, ## args) +#define SMSC_TRACE(pdata, nlevel, fmt, args...) \ + netif_info(pdata, nlevel, pdata->dev, fmt "\n", ##args) #else -#define SMSC_TRACE(nlevel, fmt, args...) \ - ({ do {} while (0); 0; }) +#define SMSC_TRACE(pdata, nlevel, fmt, args...) \ + no_printk(fmt "\n", ##args) #endif #ifdef CONFIG_DEBUG_SPINLOCK -- cgit v0.10.2 From 19eccc2bc6ad3b1c81d0826a77955500be972504 Mon Sep 17 00:00:00 2001 From: Alexey Dobriyan Date: Sun, 27 Mar 2011 02:58:35 +0000 Subject: kstrtox: convert drivers/isdn/ Signed-off-by: Alexey Dobriyan Signed-off-by: David S. Miller diff --git a/drivers/isdn/gigaset/ev-layer.c b/drivers/isdn/gigaset/ev-layer.c index a141876..ba74646 100644 --- a/drivers/isdn/gigaset/ev-layer.c +++ b/drivers/isdn/gigaset/ev-layer.c @@ -390,12 +390,12 @@ static const struct zsau_resp_t { */ static int cid_of_response(char *s) { - unsigned long cid; + int cid; int rc; if (s[-1] != ';') return 0; /* no CID separator */ - rc = strict_strtoul(s, 10, &cid); + rc = kstrtoint(s, 10, &cid); if (rc) return 0; /* CID not numeric */ if (cid < 1 || cid > 65535) @@ -566,27 +566,19 @@ void gigaset_handle_modem_response(struct cardstate *cs) case RT_ZCAU: event->parameter = -1; if (curarg + 1 < params) { - unsigned long type, value; - - i = strict_strtoul(argv[curarg++], 16, &type); - j = strict_strtoul(argv[curarg++], 16, &value); + u8 type, value; - if (i == 0 && type < 256 && - j == 0 && value < 256) + i = kstrtou8(argv[curarg++], 16, &type); + j = kstrtou8(argv[curarg++], 16, &value); + if (i == 0 && j == 0) event->parameter = (type << 8) | value; } else curarg = params - 1; break; case RT_NUMBER: - event->parameter = -1; - if (curarg < params) { - unsigned long res; - int rc; - - rc = strict_strtoul(argv[curarg++], 10, &res); - if (rc == 0) - event->parameter = res; - } + if (curarg >= params || + kstrtoint(argv[curarg++], 10, &event->parameter)) + event->parameter = -1; gig_dbg(DEBUG_EVENT, "parameter==%d", event->parameter); break; } diff --git a/drivers/isdn/hysdn/hysdn_proclog.c b/drivers/isdn/hysdn/hysdn_proclog.c index 2ee93d0..236cc7d 100644 --- a/drivers/isdn/hysdn/hysdn_proclog.c +++ b/drivers/isdn/hysdn/hysdn_proclog.c @@ -155,7 +155,6 @@ put_log_buffer(hysdn_card * card, char *cp) static ssize_t hysdn_log_write(struct file *file, const char __user *buf, size_t count, loff_t * off) { - unsigned long u = 0; int rc; unsigned char valbuf[128]; hysdn_card *card = file->private_data; @@ -167,12 +166,10 @@ hysdn_log_write(struct file *file, const char __user *buf, size_t count, loff_t valbuf[count] = 0; /* terminating 0 */ - rc = strict_strtoul(valbuf, 0, &u); - - if (rc == 0) { - card->debug_flags = u; /* remember debug flags */ - hysdn_addlog(card, "debug set to 0x%lx", card->debug_flags); - } + rc = kstrtoul(valbuf, 0, &card->debug_flags); + if (rc < 0) + return rc; + hysdn_addlog(card, "debug set to 0x%lx", card->debug_flags); return (count); } /* hysdn_log_write */ -- cgit v0.10.2 From 4562b2fe1ebc7c547746660f735ff9af964f28ad Mon Sep 17 00:00:00 2001 From: Harvey Harrison Date: Mon, 28 Mar 2011 17:08:59 +0000 Subject: via-rhine: trivial sparse annotation in vlan_tci helper Noticed by sparse: drivers/net/via-rhine.c:1706:16: warning: cast to restricted __be16 Signed-off-by: Harvey Harrison Signed-off-by: David S. Miller diff --git a/drivers/net/via-rhine.c b/drivers/net/via-rhine.c index 5e7f069..707f7f8 100644 --- a/drivers/net/via-rhine.c +++ b/drivers/net/via-rhine.c @@ -1703,7 +1703,7 @@ static void rhine_tx(struct net_device *dev) static inline u16 rhine_get_vlan_tci(struct sk_buff *skb, int data_size) { u8 *trailer = (u8 *)skb->data + ((data_size + 3) & ~3) + 2; - return ntohs(*(u16 *)trailer); + return be16_to_cpup((__be16 *)trailer); } /* Process up to limit frames from receive ring */ -- cgit v0.10.2 From 9085fd09859fafbde17380b93d317a13c23c39af Mon Sep 17 00:00:00 2001 From: Roopa Prabhu Date: Tue, 29 Mar 2011 20:35:51 +0000 Subject: enic: Add support for new fw devcmds for port profile handling This patch introduces new fw devcmds for port profile handling. These new commands are similar to the current fw commands for port profile handling. The only difference being that the new commands split the existing port profile handling devcmds into multiple fw commands, giving the driver finer control over port profile operations. Signed-off-by: Roopa Prabhu Signed-off-by: David Wang Signed-off-by: Christian Benvenuti Signed-off-by: David S. Miller diff --git a/drivers/net/enic/vnic_dev.c b/drivers/net/enic/vnic_dev.c index c089b36..68f24ae 100644 --- a/drivers/net/enic/vnic_dev.c +++ b/drivers/net/enic/vnic_dev.c @@ -786,48 +786,6 @@ int vnic_dev_init(struct vnic_dev *vdev, int arg) return r; } -int vnic_dev_init_done(struct vnic_dev *vdev, int *done, int *err) -{ - u64 a0 = 0, a1 = 0; - int wait = 1000; - int ret; - - *done = 0; - - ret = vnic_dev_cmd(vdev, CMD_INIT_STATUS, &a0, &a1, wait); - if (ret) - return ret; - - *done = (a0 == 0); - - *err = (a0 == 0) ? (int)a1:0; - - return 0; -} - -int vnic_dev_init_prov(struct vnic_dev *vdev, u8 *buf, u32 len) -{ - u64 a0, a1 = len; - int wait = 1000; - dma_addr_t prov_pa; - void *prov_buf; - int ret; - - prov_buf = pci_alloc_consistent(vdev->pdev, len, &prov_pa); - if (!prov_buf) - return -ENOMEM; - - memcpy(prov_buf, buf, len); - - a0 = prov_pa; - - ret = vnic_dev_cmd(vdev, CMD_INIT_PROV_INFO, &a0, &a1, wait); - - pci_free_consistent(vdev->pdev, len, prov_buf, prov_pa); - - return ret; -} - int vnic_dev_deinit(struct vnic_dev *vdev) { u64 a0 = 0, a1 = 0; @@ -927,4 +885,59 @@ err_out: return NULL; } +int vnic_dev_init_prov2(struct vnic_dev *vdev, u8 *buf, u32 len) +{ + u64 a0, a1 = len; + int wait = 1000; + dma_addr_t prov_pa; + void *prov_buf; + int ret; + + prov_buf = pci_alloc_consistent(vdev->pdev, len, &prov_pa); + if (!prov_buf) + return -ENOMEM; + memcpy(prov_buf, buf, len); + + a0 = prov_pa; + + ret = vnic_dev_cmd(vdev, CMD_INIT_PROV_INFO2, &a0, &a1, wait); + + pci_free_consistent(vdev->pdev, len, prov_buf, prov_pa); + + return ret; +} + +int vnic_dev_enable2(struct vnic_dev *vdev, int active) +{ + u64 a0, a1 = 0; + int wait = 1000; + + a0 = (active ? CMD_ENABLE2_ACTIVE : 0); + + return vnic_dev_cmd(vdev, CMD_ENABLE2, &a0, &a1, wait); +} + +static int vnic_dev_cmd_status(struct vnic_dev *vdev, enum vnic_devcmd_cmd cmd, + int *status) +{ + u64 a0 = cmd, a1 = 0; + int wait = 1000; + int ret; + + ret = vnic_dev_cmd(vdev, CMD_STATUS, &a0, &a1, wait); + if (!ret) + *status = (int)a0; + + return ret; +} + +int vnic_dev_enable2_done(struct vnic_dev *vdev, int *status) +{ + return vnic_dev_cmd_status(vdev, CMD_ENABLE2, status); +} + +int vnic_dev_deinit_done(struct vnic_dev *vdev, int *status) +{ + return vnic_dev_cmd_status(vdev, CMD_DEINIT, status); +} diff --git a/drivers/net/enic/vnic_dev.h b/drivers/net/enic/vnic_dev.h index e837546..cf482a2 100644 --- a/drivers/net/enic/vnic_dev.h +++ b/drivers/net/enic/vnic_dev.h @@ -108,8 +108,6 @@ int vnic_dev_disable(struct vnic_dev *vdev); int vnic_dev_open(struct vnic_dev *vdev, int arg); int vnic_dev_open_done(struct vnic_dev *vdev, int *done); int vnic_dev_init(struct vnic_dev *vdev, int arg); -int vnic_dev_init_done(struct vnic_dev *vdev, int *done, int *err); -int vnic_dev_init_prov(struct vnic_dev *vdev, u8 *buf, u32 len); int vnic_dev_deinit(struct vnic_dev *vdev); int vnic_dev_hang_reset(struct vnic_dev *vdev, int arg); int vnic_dev_hang_reset_done(struct vnic_dev *vdev, int *done); @@ -122,5 +120,9 @@ int vnic_dev_set_ig_vlan_rewrite_mode(struct vnic_dev *vdev, struct vnic_dev *vnic_dev_register(struct vnic_dev *vdev, void *priv, struct pci_dev *pdev, struct vnic_dev_bar *bar, unsigned int num_bars); +int vnic_dev_init_prov2(struct vnic_dev *vdev, u8 *buf, u32 len); +int vnic_dev_enable2(struct vnic_dev *vdev, int active); +int vnic_dev_enable2_done(struct vnic_dev *vdev, int *status); +int vnic_dev_deinit_done(struct vnic_dev *vdev, int *status); #endif /* _VNIC_DEV_H_ */ diff --git a/drivers/net/enic/vnic_devcmd.h b/drivers/net/enic/vnic_devcmd.h index d833a07..c5569bf 100644 --- a/drivers/net/enic/vnic_devcmd.h +++ b/drivers/net/enic/vnic_devcmd.h @@ -267,17 +267,62 @@ enum vnic_devcmd_cmd { /* * As for BY_BDF except a0 is index of hvnlink subordinate vnic - * or SR-IOV virtual vnic */ + * or SR-IOV virtual vnic + */ CMD_PROXY_BY_INDEX = _CMDC(_CMD_DIR_RW, _CMD_VTYPE_ALL, 43), /* - * in: (u64)a0=paddr of buffer to put latest VIC VIF-CONFIG-INFO TLV in - * (u32)a1=length of buffer in a0 - * out: (u64)a0=paddr of buffer with latest VIC VIF-CONFIG-INFO TLV - * (u32)a1=actual length of latest VIC VIF-CONFIG-INFO TLV */ + * For HPP toggle: + * adapter-info-get + * in: (u64)a0=phsical address of buffer passed in from caller. + * (u16)a1=size of buffer specified in a0. + * out: (u64)a0=phsical address of buffer passed in from caller. + * (u16)a1=actual bytes from VIF-CONFIG-INFO TLV, or + * 0 if no VIF-CONFIG-INFO TLV was ever received. */ CMD_CONFIG_INFO_GET = _CMDC(_CMD_DIR_RW, _CMD_VTYPE_ALL, 44), + + /* init_prov_info2: + * Variant of CMD_INIT_PROV_INFO, where it will not try to enable + * the vnic until CMD_ENABLE2 is issued. + * (u64)a0=paddr of vnic_devcmd_provinfo + * (u32)a1=sizeof provision info */ + CMD_INIT_PROV_INFO2 = _CMDC(_CMD_DIR_WRITE, _CMD_VTYPE_ENET, 47), + + /* enable2: + * (u32)a0=0 ==> standby + * =CMD_ENABLE2_ACTIVE ==> active + */ + CMD_ENABLE2 = _CMDC(_CMD_DIR_WRITE, _CMD_VTYPE_ENET, 48), + + /* + * cmd_status: + * Returns the status of the specified command + * Input: + * a0 = command for which status is being queried. + * Possible values are: + * CMD_SOFT_RESET + * CMD_HANG_RESET + * CMD_OPEN + * CMD_INIT + * CMD_INIT_PROV_INFO + * CMD_DEINIT + * CMD_INIT_PROV_INFO2 + * CMD_ENABLE2 + * Output: + * if status == STAT_ERROR + * a0 = ERR_ENOTSUPPORTED - status for command in a0 is + * not supported + * if status == STAT_NONE + * a0 = status of the devcmd specified in a0 as follows. + * ERR_SUCCESS - command in a0 completed successfully + * ERR_EINPROGRESS - command in a0 is still in progress + */ + CMD_STATUS = _CMDC(_CMD_DIR_RW, _CMD_VTYPE_ALL, 49), }; +/* CMD_ENABLE2 flags */ +#define CMD_ENABLE2_ACTIVE 0x1 + /* flags for CMD_OPEN */ #define CMD_OPENF_OPROM 0x1 /* open coming from option rom */ @@ -315,6 +360,8 @@ enum vnic_devcmd_error { ERR_ETIMEDOUT = 8, ERR_ELINKDOWN = 9, ERR_EMAXRES = 10, + ERR_ENOTSUPPORTED = 11, + ERR_EINPROGRESS = 12, }; /* -- cgit v0.10.2 From 18714ff8de7a000e7642561cabaf8ace8d082e9f Mon Sep 17 00:00:00 2001 From: Roopa Prabhu Date: Tue, 29 Mar 2011 20:35:56 +0000 Subject: enic: Add wrapper routines for new fw devcmds for port profile handling This patch adds wrapper routines to new port profile related fw devcmds and removes the old ones Signed-off-by: Roopa Prabhu Signed-off-by: David Wang Signed-off-by: Christian Benvenuti Signed-off-by: David S. Miller diff --git a/drivers/net/enic/enic_dev.c b/drivers/net/enic/enic_dev.c index 37ad3a1..90687b1 100644 --- a/drivers/net/enic/enic_dev.c +++ b/drivers/net/enic/enic_dev.c @@ -177,24 +177,24 @@ int enic_vnic_dev_deinit(struct enic *enic) return err; } -int enic_dev_init_prov(struct enic *enic, struct vic_provinfo *vp) +int enic_dev_init_prov2(struct enic *enic, struct vic_provinfo *vp) { int err; spin_lock(&enic->devcmd_lock); - err = vnic_dev_init_prov(enic->vdev, + err = vnic_dev_init_prov2(enic->vdev, (u8 *)vp, vic_provinfo_size(vp)); spin_unlock(&enic->devcmd_lock); return err; } -int enic_dev_init_done(struct enic *enic, int *done, int *error) +int enic_dev_deinit_done(struct enic *enic, int *status) { int err; spin_lock(&enic->devcmd_lock); - err = vnic_dev_init_done(enic->vdev, done, error); + err = vnic_dev_deinit_done(enic->vdev, status); spin_unlock(&enic->devcmd_lock); return err; @@ -219,3 +219,57 @@ void enic_vlan_rx_kill_vid(struct net_device *netdev, u16 vid) enic_del_vlan(enic, vid); spin_unlock(&enic->devcmd_lock); } + +int enic_dev_enable2(struct enic *enic, int active) +{ + int err; + + spin_lock(&enic->devcmd_lock); + err = vnic_dev_enable2(enic->vdev, active); + spin_unlock(&enic->devcmd_lock); + + return err; +} + +int enic_dev_enable2_done(struct enic *enic, int *status) +{ + int err; + + spin_lock(&enic->devcmd_lock); + err = vnic_dev_enable2_done(enic->vdev, status); + spin_unlock(&enic->devcmd_lock); + + return err; +} + +int enic_dev_status_to_errno(int devcmd_status) +{ + switch (devcmd_status) { + case ERR_SUCCESS: + return 0; + case ERR_EINVAL: + return -EINVAL; + case ERR_EFAULT: + return -EFAULT; + case ERR_EPERM: + return -EPERM; + case ERR_EBUSY: + return -EBUSY; + case ERR_ECMDUNKNOWN: + case ERR_ENOTSUPPORTED: + return -EOPNOTSUPP; + case ERR_EBADSTATE: + return -EINVAL; + case ERR_ENOMEM: + return -ENOMEM; + case ERR_ETIMEDOUT: + return -ETIMEDOUT; + case ERR_ELINKDOWN: + return -ENETDOWN; + case ERR_EINPROGRESS: + return -EINPROGRESS; + case ERR_EMAXRES: + default: + return (devcmd_status < 0) ? devcmd_status : -1; + } +} diff --git a/drivers/net/enic/enic_dev.h b/drivers/net/enic/enic_dev.h index 495f57f..d5f6813 100644 --- a/drivers/net/enic/enic_dev.h +++ b/drivers/net/enic/enic_dev.h @@ -35,7 +35,10 @@ int enic_dev_set_ig_vlan_rewrite_mode(struct enic *enic); int enic_dev_enable(struct enic *enic); int enic_dev_disable(struct enic *enic); int enic_vnic_dev_deinit(struct enic *enic); -int enic_dev_init_prov(struct enic *enic, struct vic_provinfo *vp); -int enic_dev_init_done(struct enic *enic, int *done, int *error); +int enic_dev_init_prov2(struct enic *enic, struct vic_provinfo *vp); +int enic_dev_deinit_done(struct enic *enic, int *status); +int enic_dev_enable2(struct enic *enic, int arg); +int enic_dev_enable2_done(struct enic *enic, int *status); +int enic_dev_status_to_errno(int devcmd_status); #endif /* _ENIC_DEV_H_ */ -- cgit v0.10.2 From 756462f3434ec4807a61f884d59358092a03fc15 Mon Sep 17 00:00:00 2001 From: Roopa Prabhu Date: Tue, 29 Mar 2011 20:36:02 +0000 Subject: enic: Cleanups in port profile helper code This patch does the following: - Introduces a new macro VIC_PROVINFO_ADD_TLV - Adds a new OS type in vic_generic_prov_os_type - Changes some vic_provinfo* helper routine args to constants Signed-off-by: Roopa Prabhu Signed-off-by: David Wang Signed-off-by: Christian Benvenuti Signed-off-by: David S. Miller diff --git a/drivers/net/enic/vnic_vic.c b/drivers/net/enic/vnic_vic.c index 4725b79..24ef8cd 100644 --- a/drivers/net/enic/vnic_vic.c +++ b/drivers/net/enic/vnic_vic.c @@ -23,7 +23,8 @@ #include "vnic_vic.h" -struct vic_provinfo *vic_provinfo_alloc(gfp_t flags, u8 *oui, u8 type) +struct vic_provinfo *vic_provinfo_alloc(gfp_t flags, const u8 *oui, + const u8 type) { struct vic_provinfo *vp; @@ -47,7 +48,7 @@ void vic_provinfo_free(struct vic_provinfo *vp) } int vic_provinfo_add_tlv(struct vic_provinfo *vp, u16 type, u16 length, - void *value) + const void *value) { struct vic_provinfo_tlv *tlv; diff --git a/drivers/net/enic/vnic_vic.h b/drivers/net/enic/vnic_vic.h index f700f5d..9ef81f1 100644 --- a/drivers/net/enic/vnic_vic.h +++ b/drivers/net/enic/vnic_vic.h @@ -47,6 +47,7 @@ enum vic_generic_prov_os_type { VIC_GENERIC_PROV_OS_TYPE_ESX = 1, VIC_GENERIC_PROV_OS_TYPE_LINUX = 2, VIC_GENERIC_PROV_OS_TYPE_WINDOWS = 3, + VIC_GENERIC_PROV_OS_TYPE_SOLARIS = 4, }; struct vic_provinfo { @@ -61,14 +62,22 @@ struct vic_provinfo { } tlv[0]; } __packed; +#define VIC_PROVINFO_ADD_TLV(vp, tlvtype, tlvlen, data) \ + do { \ + err = vic_provinfo_add_tlv(vp, tlvtype, tlvlen, data); \ + if (err) \ + goto add_tlv_failure; \ + } while (0) + #define VIC_PROVINFO_MAX_DATA 1385 #define VIC_PROVINFO_MAX_TLV_DATA (VIC_PROVINFO_MAX_DATA - \ sizeof(struct vic_provinfo)) -struct vic_provinfo *vic_provinfo_alloc(gfp_t flags, u8 *oui, u8 type); +struct vic_provinfo *vic_provinfo_alloc(gfp_t flags, const u8 *oui, + const u8 type); void vic_provinfo_free(struct vic_provinfo *vp); int vic_provinfo_add_tlv(struct vic_provinfo *vp, u16 type, u16 length, - void *value); + const void *value); size_t vic_provinfo_size(struct vic_provinfo *vp); #endif /* _VNIC_VIC_H_ */ -- cgit v0.10.2 From b3abfbd2951102f5f5b8fe251a672e5223ac972b Mon Sep 17 00:00:00 2001 From: Roopa Prabhu Date: Tue, 29 Mar 2011 20:36:07 +0000 Subject: enic: Add support for PORT_REQUEST_PREASSOCIATE_RR Current enic code only supports ASSOCIATE and DISASSOCIATE port profile operations. This patch adds enic support for port profile PORT_REQUEST_PREASSOCIATE_RR operation. The VIC adapter (8021qbh) is capable of handling port profile requests done in two steps namely PREASSOCIATE_RR and ASSOCIATE today. The motivation to support PREASSOCIATE_RR comes mainly from its use as an optimization during VM migration ie, to do resource reservation on destination host before resources on source host are released. PREASSOCIATE_RR is a VDP operation and according to the latest at IEEE, 8021qbh will also need to support VDP commands. In addition to handling the new PORT_REQUEST_PREASSOCIATE_RR operation this patch also does the below: - Introduces handlers for PORT_REQUEST operations - Moves most of the port profile handling code to new files enic_pp.[ch] - Uses new fw devcmds for port profile operations Signed-off-by: Roopa Prabhu Signed-off-by: David Wang Signed-off-by: Christian Benvenuti Signed-off-by: David S. Miller diff --git a/drivers/net/enic/Makefile b/drivers/net/enic/Makefile index 2e573be..9d4974b 100644 --- a/drivers/net/enic/Makefile +++ b/drivers/net/enic/Makefile @@ -1,5 +1,5 @@ obj-$(CONFIG_ENIC) := enic.o enic-y := enic_main.o vnic_cq.o vnic_intr.o vnic_wq.o \ - enic_res.o enic_dev.o vnic_dev.o vnic_rq.o vnic_vic.o + enic_res.o enic_dev.o enic_pp.o vnic_dev.o vnic_rq.o vnic_vic.o diff --git a/drivers/net/enic/enic.h b/drivers/net/enic/enic.h index 3a3c3c8..178b94d 100644 --- a/drivers/net/enic/enic.h +++ b/drivers/net/enic/enic.h @@ -32,7 +32,7 @@ #define DRV_NAME "enic" #define DRV_DESCRIPTION "Cisco VIC Ethernet NIC Driver" -#define DRV_VERSION "2.1.1.12" +#define DRV_VERSION "2.1.1.13" #define DRV_COPYRIGHT "Copyright 2008-2011 Cisco Systems, Inc" #define ENIC_BARS_MAX 6 @@ -120,4 +120,6 @@ static inline struct device *enic_get_dev(struct enic *enic) return &(enic->pdev->dev); } +void enic_reset_addr_lists(struct enic *enic); + #endif /* _ENIC_H_ */ diff --git a/drivers/net/enic/enic_main.c b/drivers/net/enic/enic_main.c index 8b9cad5..9a3a027 100644 --- a/drivers/net/enic/enic_main.c +++ b/drivers/net/enic/enic_main.c @@ -45,6 +45,7 @@ #include "enic_res.h" #include "enic.h" #include "enic_dev.h" +#include "enic_pp.h" #define ENIC_NOTIFY_TIMER_PERIOD (2 * HZ) #define WQ_ENET_MAX_DESC_LEN (1 << WQ_ENET_LEN_BITS) @@ -874,7 +875,7 @@ static struct net_device_stats *enic_get_stats(struct net_device *netdev) return net_stats; } -static void enic_reset_addr_lists(struct enic *enic) +void enic_reset_addr_lists(struct enic *enic) { enic->mc_count = 0; enic->uc_count = 0; @@ -1112,157 +1113,77 @@ static int enic_set_vf_mac(struct net_device *netdev, int vf, u8 *mac) return -EINVAL; } -static int enic_set_port_profile(struct enic *enic, u8 *mac) -{ - struct vic_provinfo *vp; - u8 oui[3] = VIC_PROVINFO_CISCO_OUI; - u16 os_type = VIC_GENERIC_PROV_OS_TYPE_LINUX; - char uuid_str[38]; - char client_mac_str[18]; - u8 *client_mac; - int err; - - err = enic_vnic_dev_deinit(enic); - if (err) - return err; - - enic_reset_addr_lists(enic); - - switch (enic->pp.request) { - - case PORT_REQUEST_ASSOCIATE: - - if (!(enic->pp.set & ENIC_SET_NAME) || !strlen(enic->pp.name)) - return -EINVAL; - - if (!is_valid_ether_addr(mac)) - return -EADDRNOTAVAIL; - - vp = vic_provinfo_alloc(GFP_KERNEL, oui, - VIC_PROVINFO_GENERIC_TYPE); - if (!vp) - return -ENOMEM; - - vic_provinfo_add_tlv(vp, - VIC_GENERIC_PROV_TLV_PORT_PROFILE_NAME_STR, - strlen(enic->pp.name) + 1, enic->pp.name); - - if (!is_zero_ether_addr(enic->pp.mac_addr)) - client_mac = enic->pp.mac_addr; - else - client_mac = mac; - - vic_provinfo_add_tlv(vp, - VIC_GENERIC_PROV_TLV_CLIENT_MAC_ADDR, - ETH_ALEN, client_mac); - - sprintf(client_mac_str, "%pM", client_mac); - vic_provinfo_add_tlv(vp, - VIC_GENERIC_PROV_TLV_CLUSTER_PORT_UUID_STR, - sizeof(client_mac_str), client_mac_str); - - if (enic->pp.set & ENIC_SET_INSTANCE) { - sprintf(uuid_str, "%pUB", enic->pp.instance_uuid); - vic_provinfo_add_tlv(vp, - VIC_GENERIC_PROV_TLV_CLIENT_UUID_STR, - sizeof(uuid_str), uuid_str); - } - - if (enic->pp.set & ENIC_SET_HOST) { - sprintf(uuid_str, "%pUB", enic->pp.host_uuid); - vic_provinfo_add_tlv(vp, - VIC_GENERIC_PROV_TLV_HOST_UUID_STR, - sizeof(uuid_str), uuid_str); - } - - os_type = htons(os_type); - vic_provinfo_add_tlv(vp, - VIC_GENERIC_PROV_TLV_OS_TYPE, - sizeof(os_type), &os_type); - - err = enic_dev_init_prov(enic, vp); - vic_provinfo_free(vp); - if (err) - return err; - break; - - case PORT_REQUEST_DISASSOCIATE: - break; - - default: - return -EINVAL; - } - - /* Set flag to indicate that the port assoc/disassoc - * request has been sent out to fw - */ - enic->pp.set |= ENIC_PORT_REQUEST_APPLIED; - - return 0; -} - static int enic_set_vf_port(struct net_device *netdev, int vf, struct nlattr *port[]) { struct enic *enic = netdev_priv(netdev); - struct enic_port_profile new_pp; - int err = 0; + struct enic_port_profile prev_pp; + int err = 0, restore_pp = 1; - memset(&new_pp, 0, sizeof(new_pp)); + /* don't support VFs, yet */ + if (vf != PORT_SELF_VF) + return -EOPNOTSUPP; - if (port[IFLA_PORT_REQUEST]) { - new_pp.set |= ENIC_SET_REQUEST; - new_pp.request = nla_get_u8(port[IFLA_PORT_REQUEST]); - } + if (!port[IFLA_PORT_REQUEST]) + return -EOPNOTSUPP; + + memcpy(&prev_pp, &enic->pp, sizeof(enic->pp)); + memset(&enic->pp, 0, sizeof(enic->pp)); + + enic->pp.set |= ENIC_SET_REQUEST; + enic->pp.request = nla_get_u8(port[IFLA_PORT_REQUEST]); if (port[IFLA_PORT_PROFILE]) { - new_pp.set |= ENIC_SET_NAME; - memcpy(new_pp.name, nla_data(port[IFLA_PORT_PROFILE]), + enic->pp.set |= ENIC_SET_NAME; + memcpy(enic->pp.name, nla_data(port[IFLA_PORT_PROFILE]), PORT_PROFILE_MAX); } if (port[IFLA_PORT_INSTANCE_UUID]) { - new_pp.set |= ENIC_SET_INSTANCE; - memcpy(new_pp.instance_uuid, + enic->pp.set |= ENIC_SET_INSTANCE; + memcpy(enic->pp.instance_uuid, nla_data(port[IFLA_PORT_INSTANCE_UUID]), PORT_UUID_MAX); } if (port[IFLA_PORT_HOST_UUID]) { - new_pp.set |= ENIC_SET_HOST; - memcpy(new_pp.host_uuid, + enic->pp.set |= ENIC_SET_HOST; + memcpy(enic->pp.host_uuid, nla_data(port[IFLA_PORT_HOST_UUID]), PORT_UUID_MAX); } - /* don't support VFs, yet */ - if (vf != PORT_SELF_VF) - return -EOPNOTSUPP; - - if (!(new_pp.set & ENIC_SET_REQUEST)) - return -EOPNOTSUPP; - - if (new_pp.request == PORT_REQUEST_ASSOCIATE) { - /* Special case handling */ - if (!is_zero_ether_addr(enic->pp.vf_mac)) - memcpy(new_pp.mac_addr, enic->pp.vf_mac, ETH_ALEN); + /* Special case handling: mac came from IFLA_VF_MAC */ + if (!is_zero_ether_addr(prev_pp.vf_mac)) + memcpy(enic->pp.mac_addr, prev_pp.vf_mac, ETH_ALEN); if (is_zero_ether_addr(netdev->dev_addr)) random_ether_addr(netdev->dev_addr); - } - memcpy(&enic->pp, &new_pp, sizeof(struct enic_port_profile)); + err = enic_process_set_pp_request(enic, &prev_pp, &restore_pp); + if (err) { + if (restore_pp) { + /* Things are still the way they were: Implicit + * DISASSOCIATE failed + */ + memcpy(&enic->pp, &prev_pp, sizeof(enic->pp)); + } else { + memset(&enic->pp, 0, sizeof(enic->pp)); + memset(netdev->dev_addr, 0, ETH_ALEN); + } + } else { + /* Set flag to indicate that the port assoc/disassoc + * request has been sent out to fw + */ + enic->pp.set |= ENIC_PORT_REQUEST_APPLIED; - err = enic_set_port_profile(enic, netdev->dev_addr); - if (err) - goto set_port_profile_cleanup; + /* If DISASSOCIATE, clean up all assigned/saved macaddresses */ + if (enic->pp.request == PORT_REQUEST_DISASSOCIATE) { + memset(enic->pp.mac_addr, 0, ETH_ALEN); + memset(netdev->dev_addr, 0, ETH_ALEN); + } + } -set_port_profile_cleanup: memset(enic->pp.vf_mac, 0, ETH_ALEN); - if (err || enic->pp.request == PORT_REQUEST_DISASSOCIATE) { - memset(netdev->dev_addr, 0, ETH_ALEN); - memset(enic->pp.mac_addr, 0, ETH_ALEN); - } - return err; } @@ -1270,34 +1191,15 @@ static int enic_get_vf_port(struct net_device *netdev, int vf, struct sk_buff *skb) { struct enic *enic = netdev_priv(netdev); - int err, error, done; u16 response = PORT_PROFILE_RESPONSE_SUCCESS; + int err; if (!(enic->pp.set & ENIC_PORT_REQUEST_APPLIED)) return -ENODATA; - err = enic_dev_init_done(enic, &done, &error); + err = enic_process_get_pp_request(enic, enic->pp.request, &response); if (err) - error = err; - - switch (error) { - case ERR_SUCCESS: - if (!done) - response = PORT_PROFILE_RESPONSE_INPROGRESS; - break; - case ERR_EINVAL: - response = PORT_PROFILE_RESPONSE_INVALID; - break; - case ERR_EBADSTATE: - response = PORT_PROFILE_RESPONSE_BADSTATE; - break; - case ERR_ENOMEM: - response = PORT_PROFILE_RESPONSE_INSUFFICIENT_RESOURCES; - break; - default: - response = PORT_PROFILE_RESPONSE_ERROR; - break; - } + return err; NLA_PUT_U16(skb, IFLA_PORT_REQUEST, enic->pp.request); NLA_PUT_U16(skb, IFLA_PORT_RESPONSE, response); diff --git a/drivers/net/enic/enic_pp.c b/drivers/net/enic/enic_pp.c new file mode 100644 index 0000000..ffaa75d --- /dev/null +++ b/drivers/net/enic/enic_pp.c @@ -0,0 +1,264 @@ +/* + * Copyright 2011 Cisco Systems, Inc. All rights reserved. + * + * This program is free software; you may redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "vnic_vic.h" +#include "enic_res.h" +#include "enic.h" +#include "enic_dev.h" + +static int enic_set_port_profile(struct enic *enic) +{ + struct net_device *netdev = enic->netdev; + struct vic_provinfo *vp; + const u8 oui[3] = VIC_PROVINFO_CISCO_OUI; + const u16 os_type = htons(VIC_GENERIC_PROV_OS_TYPE_LINUX); + char uuid_str[38]; + char client_mac_str[18]; + u8 *client_mac; + int err; + + if (!(enic->pp.set & ENIC_SET_NAME) || !strlen(enic->pp.name)) + return -EINVAL; + + vp = vic_provinfo_alloc(GFP_KERNEL, oui, + VIC_PROVINFO_GENERIC_TYPE); + if (!vp) + return -ENOMEM; + + VIC_PROVINFO_ADD_TLV(vp, + VIC_GENERIC_PROV_TLV_PORT_PROFILE_NAME_STR, + strlen(enic->pp.name) + 1, enic->pp.name); + + if (!is_zero_ether_addr(enic->pp.mac_addr)) + client_mac = enic->pp.mac_addr; + else + client_mac = netdev->dev_addr; + + VIC_PROVINFO_ADD_TLV(vp, + VIC_GENERIC_PROV_TLV_CLIENT_MAC_ADDR, + ETH_ALEN, client_mac); + + snprintf(client_mac_str, sizeof(client_mac_str), "%pM", client_mac); + VIC_PROVINFO_ADD_TLV(vp, + VIC_GENERIC_PROV_TLV_CLUSTER_PORT_UUID_STR, + sizeof(client_mac_str), client_mac_str); + + if (enic->pp.set & ENIC_SET_INSTANCE) { + sprintf(uuid_str, "%pUB", enic->pp.instance_uuid); + VIC_PROVINFO_ADD_TLV(vp, + VIC_GENERIC_PROV_TLV_CLIENT_UUID_STR, + sizeof(uuid_str), uuid_str); + } + + if (enic->pp.set & ENIC_SET_HOST) { + sprintf(uuid_str, "%pUB", enic->pp.host_uuid); + VIC_PROVINFO_ADD_TLV(vp, + VIC_GENERIC_PROV_TLV_HOST_UUID_STR, + sizeof(uuid_str), uuid_str); + } + + VIC_PROVINFO_ADD_TLV(vp, + VIC_GENERIC_PROV_TLV_OS_TYPE, + sizeof(os_type), &os_type); + + err = enic_dev_status_to_errno(enic_dev_init_prov2(enic, vp)); + +add_tlv_failure: + vic_provinfo_free(vp); + + return err; +} + +static int enic_unset_port_profile(struct enic *enic) +{ + int err; + + err = enic_vnic_dev_deinit(enic); + if (err) + return enic_dev_status_to_errno(err); + + enic_reset_addr_lists(enic); + + return 0; +} + +static int enic_are_pp_different(struct enic_port_profile *pp1, + struct enic_port_profile *pp2) +{ + return strcmp(pp1->name, pp2->name) | !!memcmp(pp1->instance_uuid, + pp2->instance_uuid, PORT_UUID_MAX) | + !!memcmp(pp1->host_uuid, pp2->host_uuid, PORT_UUID_MAX) | + !!memcmp(pp1->mac_addr, pp2->mac_addr, ETH_ALEN); +} + +static int enic_pp_preassociate(struct enic *enic, + struct enic_port_profile *prev_pp, int *restore_pp); +static int enic_pp_disassociate(struct enic *enic, + struct enic_port_profile *prev_pp, int *restore_pp); +static int enic_pp_preassociate_rr(struct enic *enic, + struct enic_port_profile *prev_pp, int *restore_pp); +static int enic_pp_associate(struct enic *enic, + struct enic_port_profile *prev_pp, int *restore_pp); + +static int (*enic_pp_handlers[])(struct enic *enic, + struct enic_port_profile *prev_state, int *restore_pp) = { + [PORT_REQUEST_PREASSOCIATE] = enic_pp_preassociate, + [PORT_REQUEST_PREASSOCIATE_RR] = enic_pp_preassociate_rr, + [PORT_REQUEST_ASSOCIATE] = enic_pp_associate, + [PORT_REQUEST_DISASSOCIATE] = enic_pp_disassociate, +}; + +static const int enic_pp_handlers_count = + sizeof(enic_pp_handlers)/sizeof(*enic_pp_handlers); + +static int enic_pp_preassociate(struct enic *enic, + struct enic_port_profile *prev_pp, int *restore_pp) +{ + return -EOPNOTSUPP; +} + +static int enic_pp_disassociate(struct enic *enic, + struct enic_port_profile *prev_pp, int *restore_pp) +{ + return enic_unset_port_profile(enic); +} + +static int enic_pp_preassociate_rr(struct enic *enic, + struct enic_port_profile *prev_pp, int *restore_pp) +{ + int err; + int active = 0; + + if (enic->pp.request != PORT_REQUEST_ASSOCIATE) { + /* If pre-associate is not part of an associate. + We always disassociate first */ + err = enic_pp_handlers[PORT_REQUEST_DISASSOCIATE](enic, + prev_pp, restore_pp); + if (err) + return err; + + *restore_pp = 0; + } + + *restore_pp = 0; + + err = enic_set_port_profile(enic); + if (err) + return err; + + /* If pre-associate is not part of an associate. */ + if (enic->pp.request != PORT_REQUEST_ASSOCIATE) + err = enic_dev_status_to_errno(enic_dev_enable2(enic, active)); + + return err; +} + +static int enic_pp_associate(struct enic *enic, + struct enic_port_profile *prev_pp, int *restore_pp) +{ + int err; + int active = 1; + + /* Check if a pre-associate was called before */ + if (prev_pp->request != PORT_REQUEST_PREASSOCIATE_RR || + (prev_pp->request == PORT_REQUEST_PREASSOCIATE_RR && + enic_are_pp_different(prev_pp, &enic->pp))) { + err = enic_pp_handlers[PORT_REQUEST_DISASSOCIATE]( + enic, prev_pp, restore_pp); + if (err) + return err; + + *restore_pp = 0; + } + + err = enic_pp_handlers[PORT_REQUEST_PREASSOCIATE_RR]( + enic, prev_pp, restore_pp); + if (err) + return err; + + *restore_pp = 0; + + return enic_dev_status_to_errno(enic_dev_enable2(enic, active)); +} + +int enic_process_set_pp_request(struct enic *enic, + struct enic_port_profile *prev_pp, int *restore_pp) +{ + if (enic->pp.request < enic_pp_handlers_count + && enic_pp_handlers[enic->pp.request]) + return enic_pp_handlers[enic->pp.request](enic, + prev_pp, restore_pp); + else + return -EOPNOTSUPP; +} + +int enic_process_get_pp_request(struct enic *enic, int request, + u16 *response) +{ + int err, status = ERR_SUCCESS; + + switch (request) { + + case PORT_REQUEST_PREASSOCIATE_RR: + case PORT_REQUEST_ASSOCIATE: + err = enic_dev_enable2_done(enic, &status); + break; + + case PORT_REQUEST_DISASSOCIATE: + err = enic_dev_deinit_done(enic, &status); + break; + + default: + return -EINVAL; + } + + if (err) + status = err; + + switch (status) { + case ERR_SUCCESS: + *response = PORT_PROFILE_RESPONSE_SUCCESS; + break; + case ERR_EINVAL: + *response = PORT_PROFILE_RESPONSE_INVALID; + break; + case ERR_EBADSTATE: + *response = PORT_PROFILE_RESPONSE_BADSTATE; + break; + case ERR_ENOMEM: + *response = PORT_PROFILE_RESPONSE_INSUFFICIENT_RESOURCES; + break; + case ERR_EINPROGRESS: + *response = PORT_PROFILE_RESPONSE_INPROGRESS; + break; + default: + *response = PORT_PROFILE_RESPONSE_ERROR; + break; + } + + return 0; +} diff --git a/drivers/net/enic/enic_pp.h b/drivers/net/enic/enic_pp.h new file mode 100644 index 0000000..699e365 --- /dev/null +++ b/drivers/net/enic/enic_pp.h @@ -0,0 +1,27 @@ +/* + * Copyright 2011 Cisco Systems, Inc. All rights reserved. + * + * This program is free software; you may redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +#ifndef _ENIC_PP_H_ +#define _ENIC_PP_H_ + +int enic_process_set_pp_request(struct enic *enic, + struct enic_port_profile *prev_pp, int *restore_pp); +int enic_process_get_pp_request(struct enic *enic, int request, + u16 *response); + +#endif /* _ENIC_PP_H_ */ -- cgit v0.10.2 From ab392d2d6d4e2e50502985eead545b44ee58802c Mon Sep 17 00:00:00 2001 From: Javier Martinez Canillas Date: Mon, 28 Mar 2011 16:27:31 +0000 Subject: drivers/net: Remove IRQF_SAMPLE_RANDOM flag from network drivers The IRQF_SAMPLE_RANDOM flag is marked as deprecated and will be removed. Every input point to the kernel's entropy pool have to better document the type of entropy source it is. drivers/char/random.c now implements a set of interfaces that can be used for devices to collect enviromental noise. IRQF_SAMPLE_RANDOM will be replaced with these add_*_randomness exported functions. Network drivers are not a good source of entropy. They use as a source of entropy essentially a remote host. Which means that the source of entropy can be potentially controlled by an attacker. Also, with heavy workloads the entropy decreases due to less hardware interrupts happening thanks to irq mitigation and NAPI. If a system relies in its network interface as a entropy source it has a false sense of security. Systems that don't have devices whose drivers are good sources of entropy, should either use a hardware random number generator or feed the kernel's entropy pool from userspace using other sources of entropy such as EGD, video_entropyd, timer_entropyd and audio-entropyd. Signed-off-by: Javier Martinez Canillas Signed-off-by: David S. Miller diff --git a/drivers/net/atlx/atl1.c b/drivers/net/atlx/atl1.c index 67f40b9..e973d05 100644 --- a/drivers/net/atlx/atl1.c +++ b/drivers/net/atlx/atl1.c @@ -2572,7 +2572,7 @@ static s32 atl1_up(struct atl1_adapter *adapter) { struct net_device *netdev = adapter->netdev; int err; - int irq_flags = IRQF_SAMPLE_RANDOM; + int irq_flags = 0; /* hardware has been reset, we need to reload some things */ atlx_set_multi(netdev); diff --git a/drivers/net/bcm63xx_enet.c b/drivers/net/bcm63xx_enet.c index e94a966a..2af413f 100644 --- a/drivers/net/bcm63xx_enet.c +++ b/drivers/net/bcm63xx_enet.c @@ -839,8 +839,8 @@ static int bcm_enet_open(struct net_device *dev) if (ret) goto out_phy_disconnect; - ret = request_irq(priv->irq_rx, bcm_enet_isr_dma, - IRQF_SAMPLE_RANDOM | IRQF_DISABLED, dev->name, dev); + ret = request_irq(priv->irq_rx, bcm_enet_isr_dma, IRQF_DISABLED, + dev->name, dev); if (ret) goto out_freeirq; diff --git a/drivers/net/cris/eth_v10.c b/drivers/net/cris/eth_v10.c index 80c2fee..e759d74 100644 --- a/drivers/net/cris/eth_v10.c +++ b/drivers/net/cris/eth_v10.c @@ -491,8 +491,8 @@ e100_open(struct net_device *dev) /* allocate the irq corresponding to the receiving DMA */ - if (request_irq(NETWORK_DMA_RX_IRQ_NBR, e100rxtx_interrupt, - IRQF_SAMPLE_RANDOM, cardname, (void *)dev)) { + if (request_irq(NETWORK_DMA_RX_IRQ_NBR, e100rxtx_interrupt, 0, cardname, + (void *)dev)) { goto grace_exit0; } diff --git a/drivers/net/ibmlana.c b/drivers/net/ibmlana.c index 94d9969..f872f96 100644 --- a/drivers/net/ibmlana.c +++ b/drivers/net/ibmlana.c @@ -782,7 +782,8 @@ static int ibmlana_open(struct net_device *dev) /* register resources - only necessary for IRQ */ - result = request_irq(priv->realirq, irq_handler, IRQF_SHARED | IRQF_SAMPLE_RANDOM, dev->name, dev); + result = request_irq(priv->realirq, irq_handler, IRQF_SHARED, + dev->name, dev); if (result != 0) { printk(KERN_ERR "%s: failed to register irq %d\n", dev->name, dev->irq); return result; diff --git a/drivers/net/macb.c b/drivers/net/macb.c index 79ccb54..2cb4e79 100644 --- a/drivers/net/macb.c +++ b/drivers/net/macb.c @@ -1171,8 +1171,7 @@ static int __init macb_probe(struct platform_device *pdev) } dev->irq = platform_get_irq(pdev, 0); - err = request_irq(dev->irq, macb_interrupt, IRQF_SAMPLE_RANDOM, - dev->name, dev); + err = request_irq(dev->irq, macb_interrupt, 0, dev->name, dev); if (err) { printk(KERN_ERR "%s: Unable to request IRQ %d (error %d)\n", diff --git a/drivers/net/netxen/netxen_nic_main.c b/drivers/net/netxen/netxen_nic_main.c index 83348dc..9336715 100644 --- a/drivers/net/netxen/netxen_nic_main.c +++ b/drivers/net/netxen/netxen_nic_main.c @@ -905,7 +905,7 @@ netxen_nic_request_irq(struct netxen_adapter *adapter) struct nx_host_sds_ring *sds_ring; int err, ring; - unsigned long flags = IRQF_SAMPLE_RANDOM; + unsigned long flags = 0; struct net_device *netdev = adapter->netdev; struct netxen_recv_context *recv_ctx = &adapter->recv_ctx; diff --git a/drivers/net/niu.c b/drivers/net/niu.c index 32678b6..681a42c 100644 --- a/drivers/net/niu.c +++ b/drivers/net/niu.c @@ -6071,8 +6071,7 @@ static int niu_request_irq(struct niu *np) for (i = 0; i < np->num_ldg; i++) { struct niu_ldg *lp = &np->ldg[i]; - err = request_irq(lp->irq, niu_interrupt, - IRQF_SHARED | IRQF_SAMPLE_RANDOM, + err = request_irq(lp->irq, niu_interrupt, IRQF_SHARED, np->irq_name[i], lp); if (err) goto out_free_irqs; diff --git a/drivers/net/qla3xxx.c b/drivers/net/qla3xxx.c index 348b4f1..f3f737b 100644 --- a/drivers/net/qla3xxx.c +++ b/drivers/net/qla3xxx.c @@ -3468,7 +3468,7 @@ static int ql_adapter_up(struct ql3_adapter *qdev) { struct net_device *ndev = qdev->ndev; int err; - unsigned long irq_flags = IRQF_SAMPLE_RANDOM | IRQF_SHARED; + unsigned long irq_flags = IRQF_SHARED; unsigned long hw_flags; if (ql_alloc_mem_resources(qdev)) { diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index 73c942d..b7e03a6 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -8839,12 +8839,12 @@ static int tg3_request_irq(struct tg3 *tp, int irq_num) fn = tg3_msi; if (tp->tg3_flags2 & TG3_FLG2_1SHOT_MSI) fn = tg3_msi_1shot; - flags = IRQF_SAMPLE_RANDOM; + flags = 0; } else { fn = tg3_interrupt; if (tp->tg3_flags & TG3_FLAG_TAGGED_STATUS) fn = tg3_interrupt_tagged; - flags = IRQF_SHARED | IRQF_SAMPLE_RANDOM; + flags = IRQF_SHARED; } return request_irq(tnapi->irq_vec, fn, flags, name, tnapi); diff --git a/drivers/net/xen-netfront.c b/drivers/net/xen-netfront.c index 5c8d9c3..c06f5a0 100644 --- a/drivers/net/xen-netfront.c +++ b/drivers/net/xen-netfront.c @@ -1416,8 +1416,7 @@ static int setup_netfront(struct xenbus_device *dev, struct netfront_info *info) goto fail; err = bind_evtchn_to_irqhandler(info->evtchn, xennet_interrupt, - IRQF_SAMPLE_RANDOM, netdev->name, - netdev); + 0, netdev->name, netdev); if (err < 0) goto fail; netdev->irq = err; -- cgit v0.10.2 From 0a5c047507aaaf00519921336d19c0f8f5f9f363 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Thu, 31 Mar 2011 01:51:35 -0700 Subject: fib: add __rcu annotations Add __rcu annotations and lockdep checks. Add const qualifiers node_parent() and node_parent_rcu() can use rcu_dereference_index_check() Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller diff --git a/net/ipv4/fib_trie.c b/net/ipv4/fib_trie.c index b92c86f..b9d1f33 100644 --- a/net/ipv4/fib_trie.c +++ b/net/ipv4/fib_trie.c @@ -126,7 +126,7 @@ struct tnode { struct work_struct work; struct tnode *tnode_free; }; - struct rt_trie_node *child[0]; + struct rt_trie_node __rcu *child[0]; }; #ifdef CONFIG_IP_FIB_TRIE_STATS @@ -151,7 +151,7 @@ struct trie_stat { }; struct trie { - struct rt_trie_node *trie; + struct rt_trie_node __rcu *trie; #ifdef CONFIG_IP_FIB_TRIE_STATS struct trie_use_stats stats; #endif @@ -177,16 +177,29 @@ static const int sync_pages = 128; static struct kmem_cache *fn_alias_kmem __read_mostly; static struct kmem_cache *trie_leaf_kmem __read_mostly; -static inline struct tnode *node_parent(struct rt_trie_node *node) +/* + * caller must hold RTNL + */ +static inline struct tnode *node_parent(const struct rt_trie_node *node) { - return (struct tnode *)(node->parent & ~NODE_TYPE_MASK); + unsigned long parent; + + parent = rcu_dereference_index_check(node->parent, lockdep_rtnl_is_held()); + + return (struct tnode *)(parent & ~NODE_TYPE_MASK); } -static inline struct tnode *node_parent_rcu(struct rt_trie_node *node) +/* + * caller must hold RCU read lock or RTNL + */ +static inline struct tnode *node_parent_rcu(const struct rt_trie_node *node) { - struct tnode *ret = node_parent(node); + unsigned long parent; + + parent = rcu_dereference_index_check(node->parent, rcu_read_lock_held() || + lockdep_rtnl_is_held()); - return rcu_dereference_rtnl(ret); + return (struct tnode *)(parent & ~NODE_TYPE_MASK); } /* Same as rcu_assign_pointer @@ -198,18 +211,24 @@ static inline void node_set_parent(struct rt_trie_node *node, struct tnode *ptr) node->parent = (unsigned long)ptr | NODE_TYPE(node); } -static inline struct rt_trie_node *tnode_get_child(struct tnode *tn, unsigned int i) +/* + * caller must hold RTNL + */ +static inline struct rt_trie_node *tnode_get_child(const struct tnode *tn, unsigned int i) { BUG_ON(i >= 1U << tn->bits); - return tn->child[i]; + return rtnl_dereference(tn->child[i]); } -static inline struct rt_trie_node *tnode_get_child_rcu(struct tnode *tn, unsigned int i) +/* + * caller must hold RCU read lock or RTNL + */ +static inline struct rt_trie_node *tnode_get_child_rcu(const struct tnode *tn, unsigned int i) { - struct rt_trie_node *ret = tnode_get_child(tn, i); + BUG_ON(i >= 1U << tn->bits); - return rcu_dereference_rtnl(ret); + return rcu_dereference_rtnl(tn->child[i]); } static inline int tnode_child_length(const struct tnode *tn) @@ -487,7 +506,7 @@ static inline void put_child(struct trie *t, struct tnode *tn, int i, static void tnode_put_child_reorg(struct tnode *tn, int i, struct rt_trie_node *n, int wasfull) { - struct rt_trie_node *chi = tn->child[i]; + struct rt_trie_node *chi = rtnl_dereference(tn->child[i]); int isfull; BUG_ON(i >= 1<bits); @@ -665,7 +684,7 @@ one_child: for (i = 0; i < tnode_child_length(tn); i++) { struct rt_trie_node *n; - n = tn->child[i]; + n = rtnl_dereference(tn->child[i]); if (!n) continue; @@ -679,6 +698,20 @@ one_child: return (struct rt_trie_node *) tn; } + +static void tnode_clean_free(struct tnode *tn) +{ + int i; + struct tnode *tofree; + + for (i = 0; i < tnode_child_length(tn); i++) { + tofree = (struct tnode *)rtnl_dereference(tn->child[i]); + if (tofree) + tnode_free(tofree); + } + tnode_free(tn); +} + static struct tnode *inflate(struct trie *t, struct tnode *tn) { struct tnode *oldtnode = tn; @@ -755,8 +788,8 @@ static struct tnode *inflate(struct trie *t, struct tnode *tn) inode = (struct tnode *) node; if (inode->bits == 1) { - put_child(t, tn, 2*i, inode->child[0]); - put_child(t, tn, 2*i+1, inode->child[1]); + put_child(t, tn, 2*i, rtnl_dereference(inode->child[0])); + put_child(t, tn, 2*i+1, rtnl_dereference(inode->child[1])); tnode_free_safe(inode); continue; @@ -797,8 +830,8 @@ static struct tnode *inflate(struct trie *t, struct tnode *tn) size = tnode_child_length(left); for (j = 0; j < size; j++) { - put_child(t, left, j, inode->child[j]); - put_child(t, right, j, inode->child[j + size]); + put_child(t, left, j, rtnl_dereference(inode->child[j])); + put_child(t, right, j, rtnl_dereference(inode->child[j + size])); } put_child(t, tn, 2*i, resize(t, left)); put_child(t, tn, 2*i+1, resize(t, right)); @@ -808,18 +841,8 @@ static struct tnode *inflate(struct trie *t, struct tnode *tn) tnode_free_safe(oldtnode); return tn; nomem: - { - int size = tnode_child_length(tn); - int j; - - for (j = 0; j < size; j++) - if (tn->child[j]) - tnode_free((struct tnode *)tn->child[j]); - - tnode_free(tn); - - return ERR_PTR(-ENOMEM); - } + tnode_clean_free(tn); + return ERR_PTR(-ENOMEM); } static struct tnode *halve(struct trie *t, struct tnode *tn) @@ -890,18 +913,8 @@ static struct tnode *halve(struct trie *t, struct tnode *tn) tnode_free_safe(oldtnode); return tn; nomem: - { - int size = tnode_child_length(tn); - int j; - - for (j = 0; j < size; j++) - if (tn->child[j]) - tnode_free((struct tnode *)tn->child[j]); - - tnode_free(tn); - - return ERR_PTR(-ENOMEM); - } + tnode_clean_free(tn); + return ERR_PTR(-ENOMEM); } /* readside must use rcu_read_lock currently dump routines @@ -1033,7 +1046,7 @@ static struct list_head *fib_insert_node(struct trie *t, u32 key, int plen) t_key cindex; pos = 0; - n = t->trie; + n = rtnl_dereference(t->trie); /* If we point to NULL, stop. Either the tree is empty and we should * just put a new leaf in if, or we have reached an empty child slot, @@ -1756,7 +1769,7 @@ static struct leaf *leaf_walk_rcu(struct tnode *p, struct rt_trie_node *c) continue; if (IS_LEAF(c)) { - prefetch(p->child[idx]); + prefetch(rcu_dereference_rtnl(p->child[idx])); return (struct leaf *) c; } @@ -2272,7 +2285,7 @@ static void *fib_trie_seq_next(struct seq_file *seq, void *v, loff_t *pos) /* walk rest of this hash chain */ h = tb->tb_id & (FIB_TABLE_HASHSZ - 1); - while ( (tb_node = rcu_dereference(tb->tb_hlist.next)) ) { + while ((tb_node = rcu_dereference(hlist_next_rcu(&tb->tb_hlist)))) { tb = hlist_entry(tb_node, struct fib_table, tb_hlist); n = fib_trie_get_first(iter, (struct trie *) tb->tb_data); if (n) -- cgit v0.10.2 From e2de9e0862778f4aba103027ce575efbddb8117f Mon Sep 17 00:00:00 2001 From: Florian Mickler Date: Thu, 31 Mar 2011 13:40:42 +0200 Subject: workqueue: Document debugging tricks It is not obvious how to debug run-away workers. These are some tips given by Tejun on lkml. Signed-off-by: Florian Mickler Signed-off-by: Tejun Heo diff --git a/Documentation/workqueue.txt b/Documentation/workqueue.txt index 01c513f..a0b577d 100644 --- a/Documentation/workqueue.txt +++ b/Documentation/workqueue.txt @@ -12,6 +12,7 @@ CONTENTS 4. Application Programming Interface (API) 5. Example Execution Scenarios 6. Guidelines +7. Debugging 1. Introduction @@ -379,3 +380,42 @@ If q1 has WQ_CPU_INTENSIVE set, * Unless work items are expected to consume a huge amount of CPU cycles, using a bound wq is usually beneficial due to the increased level of locality in wq operations and work item execution. + + +7. Debugging + +Because the work functions are executed by generic worker threads +there are a few tricks needed to shed some light on misbehaving +workqueue users. + +Worker threads show up in the process list as: + +root 5671 0.0 0.0 0 0 ? S 12:07 0:00 [kworker/0:1] +root 5672 0.0 0.0 0 0 ? S 12:07 0:00 [kworker/1:2] +root 5673 0.0 0.0 0 0 ? S 12:12 0:00 [kworker/0:0] +root 5674 0.0 0.0 0 0 ? S 12:13 0:00 [kworker/1:0] + +If kworkers are going crazy (using too much cpu), there are two types +of possible problems: + + 1. Something beeing scheduled in rapid succession + 2. A single work item that consumes lots of cpu cycles + +The first one can be tracked using tracing: + + $ echo workqueue:workqueue_queue_work > /sys/kernel/debug/tracing/set_event + $ cat /sys/kernel/debug/tracing/trace_pipe > out.txt + (wait a few secs) + ^C + +If something is busy looping on work queueing, it would be dominating +the output and the offender can be determined with the work item +function. + +For the second type of problems it should be possible to just check +the stack trace of the offending worker thread. + + $ cat /proc/THE_OFFENDING_KWORKER/stack + +The work item's function should be trivially visible in the stack +trace. -- cgit v0.10.2 From 83229aa5e2c242163599266a686483e3b91ec07e Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Thu, 31 Mar 2011 04:52:14 -0700 Subject: net: Add helper flowi4_init_output(). On-stack initialization via assignment of flow structures are expensive because GCC emits a memset() to clear the entire structure out no matter what. Add a helper for ipv4 output flow key setup which we can use to avoid the memset. Signed-off-by: David S. Miller diff --git a/include/net/flow.h b/include/net/flow.h index 7fe5a0f..37e77d6 100644 --- a/include/net/flow.h +++ b/include/net/flow.h @@ -70,6 +70,27 @@ struct flowi4 { #define fl4_gre_key uli.gre_key }; +static inline void flowi4_init_output(struct flowi4 *fl4, int oif, + __u32 mark, __u8 tos, __u8 scope, + __u8 proto, __u8 flags, + __be32 daddr, __be32 saddr, + __be16 dport, __be32 sport) +{ + fl4->flowi4_oif = oif; + fl4->flowi4_iif = 0; + fl4->flowi4_mark = mark; + fl4->flowi4_tos = tos; + fl4->flowi4_scope = scope; + fl4->flowi4_proto = proto; + fl4->flowi4_flags = flags; + fl4->flowi4_secid = 0; + fl4->daddr = daddr; + fl4->saddr = saddr; + fl4->fl4_sport = sport; + fl4->fl4_dport = dport; +} + + struct flowi6 { struct flowi_common __fl_common; #define flowi6_oif __fl_common.flowic_oif -- cgit v0.10.2 From 94b92b88344641dbeadd2ef371549b7663a48fb1 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Thu, 31 Mar 2011 04:52:59 -0700 Subject: ipv4: Use flowi4_init_output() in net/route.h Signed-off-by: David S. Miller diff --git a/include/net/route.h b/include/net/route.h index f88429c..b242885 100644 --- a/include/net/route.h +++ b/include/net/route.h @@ -149,17 +149,12 @@ static inline struct rtable *ip_route_output_ports(struct net *net, struct sock __be16 dport, __be16 sport, __u8 proto, __u8 tos, int oif) { - struct flowi4 fl4 = { - .flowi4_oif = oif, - .flowi4_flags = sk ? inet_sk_flowi_flags(sk) : 0, - .flowi4_mark = sk ? sk->sk_mark : 0, - .daddr = daddr, - .saddr = saddr, - .flowi4_tos = tos, - .flowi4_proto = proto, - .fl4_dport = dport, - .fl4_sport = sport, - }; + struct flowi4 fl4; + + flowi4_init_output(&fl4, oif, sk ? sk->sk_mark : 0, tos, + RT_SCOPE_UNIVERSE, proto, + sk ? inet_sk_flowi_flags(sk) : 0, + daddr, saddr, dport, sport); if (sk) security_sk_classify_flow(sk, flowi4_to_flowi(&fl4)); return ip_route_output_flow(net, &fl4, sk); @@ -229,25 +224,21 @@ static inline struct rtable *ip_route_connect(__be32 dst, __be32 src, u32 tos, __be16 sport, __be16 dport, struct sock *sk, bool can_sleep) { - struct flowi4 fl4 = { - .flowi4_oif = oif, - .flowi4_mark = sk->sk_mark, - .daddr = dst, - .saddr = src, - .flowi4_tos = tos, - .flowi4_proto = protocol, - .fl4_sport = sport, - .fl4_dport = dport, - }; struct net *net = sock_net(sk); struct rtable *rt; + struct flowi4 fl4; + __u8 flow_flags; + flow_flags = 0; if (inet_sk(sk)->transparent) - fl4.flowi4_flags |= FLOWI_FLAG_ANYSRC; + flow_flags |= FLOWI_FLAG_ANYSRC; if (protocol == IPPROTO_TCP) - fl4.flowi4_flags |= FLOWI_FLAG_PRECOW_METRICS; + flow_flags |= FLOWI_FLAG_PRECOW_METRICS; if (can_sleep) - fl4.flowi4_flags |= FLOWI_FLAG_CAN_SLEEP; + flow_flags |= FLOWI_FLAG_CAN_SLEEP; + + flowi4_init_output(&fl4, oif, sk->sk_mark, tos, RT_SCOPE_UNIVERSE, + protocol, flow_flags, dst, src, dport, sport); if (!dst || !src) { rt = __ip_route_output_key(net, &fl4); @@ -267,20 +258,17 @@ static inline struct rtable *ip_route_newports(struct rtable *rt, __be16 dport, struct sock *sk) { if (sport != orig_sport || dport != orig_dport) { - struct flowi4 fl4 = { - .flowi4_oif = rt->rt_oif, - .flowi4_mark = rt->rt_mark, - .daddr = rt->rt_dst, - .saddr = rt->rt_src, - .flowi4_tos = rt->rt_tos, - .flowi4_proto = protocol, - .fl4_sport = sport, - .fl4_dport = dport - }; + struct flowi4 fl4; + __u8 flow_flags; + + flow_flags = 0; if (inet_sk(sk)->transparent) - fl4.flowi4_flags |= FLOWI_FLAG_ANYSRC; + flow_flags |= FLOWI_FLAG_ANYSRC; if (protocol == IPPROTO_TCP) - fl4.flowi4_flags |= FLOWI_FLAG_PRECOW_METRICS; + flow_flags |= FLOWI_FLAG_PRECOW_METRICS; + flowi4_init_output(&fl4, rt->rt_oif, rt->rt_mark, rt->rt_tos, + RT_SCOPE_UNIVERSE, protocol, flow_flags, + rt->rt_dst, rt->rt_src, dport, sport); ip_rt_put(rt); security_sk_classify_flow(sk, flowi4_to_flowi(&fl4)); return ip_route_output_flow(sock_net(sk), &fl4, sk); -- cgit v0.10.2 From e79d9bc7ea76e08fc24d7adaad8b6a821d1624c3 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Thu, 31 Mar 2011 04:53:20 -0700 Subject: ipv4: Use flowi4_init_output() in inet_connection_sock.c Signed-off-by: David S. Miller diff --git a/net/ipv4/inet_connection_sock.c b/net/ipv4/inet_connection_sock.c index 6c0b7f4..f784608 100644 --- a/net/ipv4/inet_connection_sock.c +++ b/net/ipv4/inet_connection_sock.c @@ -356,20 +356,14 @@ struct dst_entry *inet_csk_route_req(struct sock *sk, struct rtable *rt; const struct inet_request_sock *ireq = inet_rsk(req); struct ip_options *opt = inet_rsk(req)->opt; - struct flowi4 fl4 = { - .flowi4_oif = sk->sk_bound_dev_if, - .flowi4_mark = sk->sk_mark, - .daddr = ((opt && opt->srr) ? - opt->faddr : ireq->rmt_addr), - .saddr = ireq->loc_addr, - .flowi4_tos = RT_CONN_FLAGS(sk), - .flowi4_proto = sk->sk_protocol, - .flowi4_flags = inet_sk_flowi_flags(sk), - .fl4_sport = inet_sk(sk)->inet_sport, - .fl4_dport = ireq->rmt_port, - }; struct net *net = sock_net(sk); + struct flowi4 fl4; + flowi4_init_output(&fl4, sk->sk_bound_dev_if, sk->sk_mark, + RT_CONN_FLAGS(sk), RT_SCOPE_UNIVERSE, + sk->sk_protocol, inet_sk_flowi_flags(sk), + (opt && opt->srr) ? opt->faddr : ireq->rmt_addr, + ireq->loc_addr, ireq->rmt_port, inet_sk(sk)->inet_sport); security_req_classify_flow(req, flowi4_to_flowi(&fl4)); rt = ip_route_output_flow(net, &fl4, sk); if (IS_ERR(rt)) -- cgit v0.10.2 From 538de0e01f1ca3568ad03877ff297c646dd8ad23 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Thu, 31 Mar 2011 04:53:37 -0700 Subject: ipv4: Use flowi4_init_output() in ip_send_reply() Signed-off-by: David S. Miller diff --git a/net/ipv4/ip_output.c b/net/ipv4/ip_output.c index 67f241b..86a2843 100644 --- a/net/ipv4/ip_output.c +++ b/net/ipv4/ip_output.c @@ -1474,16 +1474,14 @@ void ip_send_reply(struct sock *sk, struct sk_buff *skb, struct ip_reply_arg *ar } { - struct flowi4 fl4 = { - .flowi4_oif = arg->bound_dev_if, - .daddr = daddr, - .saddr = rt->rt_spec_dst, - .flowi4_tos = RT_TOS(ip_hdr(skb)->tos), - .fl4_sport = tcp_hdr(skb)->dest, - .fl4_dport = tcp_hdr(skb)->source, - .flowi4_proto = sk->sk_protocol, - .flowi4_flags = ip_reply_arg_flowi_flags(arg), - }; + struct flowi4 fl4; + + flowi4_init_output(&fl4, arg->bound_dev_if, 0, + RT_TOS(ip_hdr(skb)->tos), + RT_SCOPE_UNIVERSE, sk->sk_protocol, + ip_reply_arg_flowi_flags(arg), + daddr, rt->rt_spec_dst, + tcp_hdr(skb)->source, tcp_hdr(skb)->dest); security_skb_classify_flow(skb, flowi4_to_flowi(&fl4)); rt = ip_route_output_key(sock_net(sk), &fl4); if (IS_ERR(rt)) -- cgit v0.10.2 From ef164ae3563bf4d291b6f75ca2e120b17d606963 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Thu, 31 Mar 2011 04:53:51 -0700 Subject: ipv4: Use flowi4_init_output() in raw_sendmsg() Signed-off-by: David S. Miller diff --git a/net/ipv4/raw.c b/net/ipv4/raw.c index 2d3c72e..7d32d9d 100644 --- a/net/ipv4/raw.c +++ b/net/ipv4/raw.c @@ -548,17 +548,13 @@ static int raw_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, } { - struct flowi4 fl4 = { - .flowi4_oif = ipc.oif, - .flowi4_mark = sk->sk_mark, - .daddr = daddr, - .saddr = saddr, - .flowi4_tos = tos, - .flowi4_proto = (inet->hdrincl ? - IPPROTO_RAW : - sk->sk_protocol), - .flowi4_flags = FLOWI_FLAG_CAN_SLEEP, - }; + struct flowi4 fl4; + + flowi4_init_output(&fl4, ipc.oif, sk->sk_mark, tos, + RT_SCOPE_UNIVERSE, + inet->hdrincl ? IPPROTO_RAW : sk->sk_protocol, + FLOWI_FLAG_CAN_SLEEP, daddr, saddr, 0, 0); + if (!inet->hdrincl) { err = raw_probe_proto_opt(&fl4, msg); if (err) -- cgit v0.10.2 From 1bba6ffeeb44480ddbdda912cc85ad2cfd4725ae Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Thu, 31 Mar 2011 04:54:08 -0700 Subject: ipv4: Use flowi4_init_output() in cookie_v4_check() Signed-off-by: David S. Miller diff --git a/net/ipv4/syncookies.c b/net/ipv4/syncookies.c index 8b44c6d..71e0296 100644 --- a/net/ipv4/syncookies.c +++ b/net/ipv4/syncookies.c @@ -345,17 +345,13 @@ struct sock *cookie_v4_check(struct sock *sk, struct sk_buff *skb, * no easy way to do this. */ { - struct flowi4 fl4 = { - .flowi4_mark = sk->sk_mark, - .daddr = ((opt && opt->srr) ? - opt->faddr : ireq->rmt_addr), - .saddr = ireq->loc_addr, - .flowi4_tos = RT_CONN_FLAGS(sk), - .flowi4_proto = IPPROTO_TCP, - .flowi4_flags = inet_sk_flowi_flags(sk), - .fl4_sport = th->dest, - .fl4_dport = th->source, - }; + struct flowi4 fl4; + + flowi4_init_output(&fl4, 0, sk->sk_mark, RT_CONN_FLAGS(sk), + RT_SCOPE_UNIVERSE, IPPROTO_TCP, + inet_sk_flowi_flags(sk), + (opt && opt->srr) ? opt->faddr : ireq->rmt_addr, + ireq->loc_addr, th->source, th->dest); security_req_classify_flow(req, flowi4_to_flowi(&fl4)); rt = ip_route_output_key(sock_net(sk), &fl4); if (IS_ERR(rt)) { -- cgit v0.10.2 From c0951cbcfd7142003bc683046ef78a53c66d3265 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Thu, 31 Mar 2011 04:54:27 -0700 Subject: ipv4: Use flowi4_init_output() in udp_sendmsg() Signed-off-by: David S. Miller diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c index 588f47a..ac66132 100644 --- a/net/ipv4/udp.c +++ b/net/ipv4/udp.c @@ -909,20 +909,14 @@ int udp_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, rt = (struct rtable *)sk_dst_check(sk, 0); if (rt == NULL) { - struct flowi4 fl4 = { - .flowi4_oif = ipc.oif, - .flowi4_mark = sk->sk_mark, - .daddr = faddr, - .saddr = saddr, - .flowi4_tos = tos, - .flowi4_proto = sk->sk_protocol, - .flowi4_flags = (inet_sk_flowi_flags(sk) | - FLOWI_FLAG_CAN_SLEEP), - .fl4_sport = inet->inet_sport, - .fl4_dport = dport, - }; + struct flowi4 fl4; struct net *net = sock_net(sk); + flowi4_init_output(&fl4, ipc.oif, sk->sk_mark, tos, + RT_SCOPE_UNIVERSE, sk->sk_protocol, + inet_sk_flowi_flags(sk)|FLOWI_FLAG_CAN_SLEEP, + faddr, saddr, dport, inet->inet_sport); + security_sk_classify_flow(sk, flowi4_to_flowi(&fl4)); rt = ip_route_output_flow(net, &fl4, sk); if (IS_ERR(rt)) { -- cgit v0.10.2 From f0681a68dd3a32699891cd1de93459aee5af7728 Mon Sep 17 00:00:00 2001 From: "Gustavo F. Padovan" Date: Wed, 16 Mar 2011 21:06:52 -0300 Subject: Bluetooth: remove unnecessary function declaration hci_notify() doesn't need declaration first. Signed-off-by: Gustavo F. Padovan diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index b372fb8..c20cbe5 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -56,7 +56,6 @@ static void hci_cmd_task(unsigned long arg); static void hci_rx_task(unsigned long arg); static void hci_tx_task(unsigned long arg); -static void hci_notify(struct hci_dev *hdev, int event); static DEFINE_RWLOCK(hci_task_lock); -- cgit v0.10.2 From 1f6c6378c59f3ddac9ed89a68ccefe2611300c09 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Wed, 16 Mar 2011 14:29:35 +0200 Subject: Bluetooth: Add define for the maximum name length on HCI level This patch adds a clear define for the maximum device name length in HCI messages and thereby avoids magic numbers in the code. Signed-off-by: Johan Hedberg Signed-off-by: Gustavo F. Padovan diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h index ec6acf2..1cd031c 100644 --- a/include/net/bluetooth/hci.h +++ b/include/net/bluetooth/hci.h @@ -535,15 +535,17 @@ struct hci_cp_delete_stored_link_key { __u8 delete_all; } __packed; +#define HCI_MAX_NAME_LENGTH 248 + #define HCI_OP_WRITE_LOCAL_NAME 0x0c13 struct hci_cp_write_local_name { - __u8 name[248]; + __u8 name[HCI_MAX_NAME_LENGTH]; } __packed; #define HCI_OP_READ_LOCAL_NAME 0x0c14 struct hci_rp_read_local_name { __u8 status; - __u8 name[248]; + __u8 name[HCI_MAX_NAME_LENGTH]; } __packed; #define HCI_OP_WRITE_CA_TIMEOUT 0x0c16 @@ -745,7 +747,7 @@ struct hci_ev_auth_complete { struct hci_ev_remote_name { __u8 status; bdaddr_t bdaddr; - __u8 name[248]; + __u8 name[HCI_MAX_NAME_LENGTH]; } __packed; #define HCI_EV_ENCRYPT_CHANGE 0x08 diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index 441dadb..9aabb14 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -94,7 +94,7 @@ struct hci_dev { __u8 bus; __u8 dev_type; bdaddr_t bdaddr; - __u8 dev_name[248]; + __u8 dev_name[HCI_MAX_NAME_LENGTH]; __u8 dev_class[3]; __u8 major_class; __u8 minor_class; diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index 3fbfa50..91ef526 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -200,7 +200,7 @@ static void hci_cc_write_local_name(struct hci_dev *hdev, struct sk_buff *skb) if (!sent) return; - memcpy(hdev->dev_name, sent, 248); + memcpy(hdev->dev_name, sent, HCI_MAX_NAME_LENGTH); } static void hci_cc_read_local_name(struct hci_dev *hdev, struct sk_buff *skb) @@ -212,7 +212,7 @@ static void hci_cc_read_local_name(struct hci_dev *hdev, struct sk_buff *skb) if (rp->status) return; - memcpy(hdev->dev_name, rp->name, 248); + memcpy(hdev->dev_name, rp->name, HCI_MAX_NAME_LENGTH); } static void hci_cc_write_auth_enable(struct hci_dev *hdev, struct sk_buff *skb) diff --git a/net/bluetooth/hci_sysfs.c b/net/bluetooth/hci_sysfs.c index 3c838a6..e544216 100644 --- a/net/bluetooth/hci_sysfs.c +++ b/net/bluetooth/hci_sysfs.c @@ -216,13 +216,13 @@ static ssize_t show_type(struct device *dev, struct device_attribute *attr, char static ssize_t show_name(struct device *dev, struct device_attribute *attr, char *buf) { struct hci_dev *hdev = dev_get_drvdata(dev); - char name[249]; + char name[HCI_MAX_NAME_LENGTH + 1]; int i; - for (i = 0; i < 248; i++) + for (i = 0; i < HCI_MAX_NAME_LENGTH; i++) name[i] = hdev->dev_name[i]; - name[248] = '\0'; + name[HCI_MAX_NAME_LENGTH] = '\0'; return sprintf(buf, "%s\n", name); } -- cgit v0.10.2 From dc4fe30b8675033e538e2dea50be8af9c75f1b6a Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Wed, 16 Mar 2011 14:29:36 +0200 Subject: Bluetooth: mgmt: Add local name information to read_info reply This patch adds the name of the adapter to the reply of the read_info management command. The management messages reserve 249 bytes for the name instead of 248 (like in the HCI spec) so that there is always a guarantee that it is nul-terminated. That way it can safely be passed onto string manipulation functions. Signed-off-by: Johan Hedberg Signed-off-by: Gustavo F. Padovan diff --git a/include/net/bluetooth/mgmt.h b/include/net/bluetooth/mgmt.h index 5fabfa8..7d0749b 100644 --- a/include/net/bluetooth/mgmt.h +++ b/include/net/bluetooth/mgmt.h @@ -41,6 +41,10 @@ struct mgmt_rp_read_index_list { __le16 index[0]; } __packed; +/* Reserve one extra byte for names in management messages so that they + * are always guaranteed to be nul-terminated */ +#define MGMT_MAX_NAME_LENGTH (HCI_MAX_NAME_LENGTH + 1) + #define MGMT_OP_READ_INFO 0x0004 struct mgmt_rp_read_info { __u8 type; @@ -55,6 +59,7 @@ struct mgmt_rp_read_info { __u16 manufacturer; __u8 hci_ver; __u16 hci_rev; + __u8 name[MGMT_MAX_NAME_LENGTH]; } __packed; struct mgmt_mode { diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 0054c74..ffdb2f4 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -183,6 +183,8 @@ static int read_controller_info(struct sock *sk, u16 index) set_bit(HCI_MGMT, &hdev->flags); + memset(&rp, 0, sizeof(rp)); + rp.type = hdev->dev_type; rp.powered = test_bit(HCI_UP, &hdev->flags); @@ -204,6 +206,8 @@ static int read_controller_info(struct sock *sk, u16 index) rp.hci_ver = hdev->hci_ver; put_unaligned_le16(hdev->hci_rev, &rp.hci_rev); + memcpy(rp.name, hdev->dev_name, sizeof(hdev->dev_name)); + hci_dev_unlock_bh(hdev); hci_dev_put(hdev); -- cgit v0.10.2 From b312b161ecb833b1bce5c4a97853f4a4f40c7901 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Wed, 16 Mar 2011 14:29:37 +0200 Subject: Bluetooth: mgmt: Add support for setting the local name This patch adds a new set_local_name management command as well as a local_name_changed management event. With these user space can both change the local name as well as monitor changes to it by others. Signed-off-by: Johan Hedberg Signed-off-by: Gustavo F. Padovan diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index 9aabb14..3912c7a 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -767,6 +767,7 @@ int mgmt_user_confirm_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status); int mgmt_user_confirm_neg_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status); int mgmt_auth_failed(u16 index, bdaddr_t *bdaddr, u8 status); +int mgmt_set_local_name_complete(u16 index, u8 *name, u8 status); /* HCI info for socket */ #define hci_pi(sk) ((struct hci_pinfo *) sk) diff --git a/include/net/bluetooth/mgmt.h b/include/net/bluetooth/mgmt.h index 7d0749b..89e7c82 100644 --- a/include/net/bluetooth/mgmt.h +++ b/include/net/bluetooth/mgmt.h @@ -172,6 +172,11 @@ struct mgmt_rp_user_confirm_reply { #define MGMT_OP_USER_CONFIRM_NEG_REPLY 0x0016 +#define MGMT_OP_SET_LOCAL_NAME 0x0017 +struct mgmt_cp_set_local_name { + __u8 name[MGMT_MAX_NAME_LENGTH]; +} __packed; + #define MGMT_EV_CMD_COMPLETE 0x0001 struct mgmt_ev_cmd_complete { __le16 opcode; @@ -239,3 +244,8 @@ struct mgmt_ev_auth_failed { bdaddr_t bdaddr; __u8 status; } __packed; + +#define MGMT_EV_LOCAL_NAME_CHANGED 0x0011 +struct mgmt_ev_local_name_changed { + __u8 name[MGMT_MAX_NAME_LENGTH]; +} __packed; diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index 91ef526..0def3e1 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -193,13 +193,16 @@ static void hci_cc_write_local_name(struct hci_dev *hdev, struct sk_buff *skb) BT_DBG("%s status 0x%x", hdev->name, status); - if (status) - return; - sent = hci_sent_cmd_data(hdev, HCI_OP_WRITE_LOCAL_NAME); if (!sent) return; + if (test_bit(HCI_MGMT, &hdev->flags)) + mgmt_set_local_name_complete(hdev->id, sent, status); + + if (status) + return; + memcpy(hdev->dev_name, sent, HCI_MAX_NAME_LENGTH); } diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index ffdb2f4..f7ce782 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -1256,6 +1256,45 @@ failed: return err; } +static int set_local_name(struct sock *sk, u16 index, unsigned char *data, + u16 len) +{ + struct mgmt_cp_set_local_name *mgmt_cp = (void *) data; + struct hci_cp_write_local_name hci_cp; + struct hci_dev *hdev; + struct pending_cmd *cmd; + int err; + + BT_DBG(""); + + if (len != sizeof(*mgmt_cp)) + return cmd_status(sk, index, MGMT_OP_SET_LOCAL_NAME, EINVAL); + + hdev = hci_dev_get(index); + if (!hdev) + return cmd_status(sk, index, MGMT_OP_SET_LOCAL_NAME, ENODEV); + + hci_dev_lock_bh(hdev); + + cmd = mgmt_pending_add(sk, MGMT_OP_SET_LOCAL_NAME, index, data, len); + if (!cmd) { + err = -ENOMEM; + goto failed; + } + + memcpy(hci_cp.name, mgmt_cp->name, sizeof(hci_cp.name)); + err = hci_send_cmd(hdev, HCI_OP_WRITE_LOCAL_NAME, sizeof(hci_cp), + &hci_cp); + if (err < 0) + mgmt_pending_remove(cmd); + +failed: + hci_dev_unlock_bh(hdev); + hci_dev_put(hdev); + + return err; +} + int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen) { unsigned char *buf; @@ -1351,6 +1390,9 @@ int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen) case MGMT_OP_USER_CONFIRM_NEG_REPLY: err = user_confirm_reply(sk, index, buf + sizeof(*hdr), len, 0); break; + case MGMT_OP_SET_LOCAL_NAME: + err = set_local_name(sk, index, buf + sizeof(*hdr), len); + break; default: BT_DBG("Unknown op %u", opcode); err = cmd_status(sk, index, opcode, 0x01); @@ -1647,3 +1689,36 @@ int mgmt_auth_failed(u16 index, bdaddr_t *bdaddr, u8 status) return mgmt_event(MGMT_EV_AUTH_FAILED, index, &ev, sizeof(ev), NULL); } + +int mgmt_set_local_name_complete(u16 index, u8 *name, u8 status) +{ + struct pending_cmd *cmd; + struct mgmt_cp_set_local_name ev; + int err; + + memset(&ev, 0, sizeof(ev)); + memcpy(ev.name, name, HCI_MAX_NAME_LENGTH); + + cmd = mgmt_pending_find(MGMT_OP_SET_LOCAL_NAME, index); + if (!cmd) + goto send_event; + + if (status) { + err = cmd_status(cmd->sk, index, MGMT_OP_SET_LOCAL_NAME, EIO); + goto failed; + } + + err = cmd_complete(cmd->sk, index, MGMT_OP_SET_LOCAL_NAME, &ev, + sizeof(ev)); + if (err < 0) + goto failed; + +send_event: + err = mgmt_event(MGMT_EV_LOCAL_NAME_CHANGED, index, &ev, sizeof(ev), + cmd ? cmd->sk : NULL); + +failed: + if (cmd) + mgmt_pending_remove(cmd); + return err; +} -- cgit v0.10.2 From b0d2199d6ff9f788b324fe54b1f783aff83502c4 Mon Sep 17 00:00:00 2001 From: "Gustavo F. Padovan" Date: Tue, 22 Mar 2011 18:06:49 -0300 Subject: Bluetooth: Remove unused struct item num in struct l2cap_chan_list isn't used anywhere. Signed-off-by: Gustavo F. Padovan diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h index 4f4bff1..7a02625 100644 --- a/include/net/bluetooth/l2cap.h +++ b/include/net/bluetooth/l2cap.h @@ -280,7 +280,6 @@ struct l2cap_conn_param_update_rsp { struct l2cap_chan_list { struct sock *head; rwlock_t lock; - long num; }; struct l2cap_conn { -- cgit v0.10.2 From 2c6d1a2eec5c49793c6760546d05515ce1b76881 Mon Sep 17 00:00:00 2001 From: "Gustavo F. Padovan" Date: Wed, 23 Mar 2011 14:38:32 -0300 Subject: Bluetooth: Improve error message on wrong link type Signed-off-by: Gustavo F. Padovan diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index c9f9cec..b5a1ce0 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -2670,7 +2670,8 @@ static inline void l2cap_sig_channel(struct l2cap_conn *conn, if (err) { struct l2cap_cmd_rej rej; - BT_DBG("error %d", err); + + BT_ERR("Wrong link type (%d)", err); /* FIXME: Map err to a valid reason */ rej.reason = cpu_to_le16(0); -- cgit v0.10.2 From a3d9bd4c00f13defd4c0fdcf8b47f8764a69e54d Mon Sep 17 00:00:00 2001 From: Szymon Janc Date: Mon, 21 Mar 2011 14:19:57 +0100 Subject: Bluetooth: Opencode macros in bnep/core.c BNEP_RX_TYPES and INCA macros have only one user each and don't provide any benefits compared to opencoding them. Signed-off-by: Szymon Janc Signed-off-by: Gustavo F. Padovan diff --git a/net/bluetooth/bnep/core.c b/net/bluetooth/bnep/core.c index 03d4d12..940b4e1 100644 --- a/net/bluetooth/bnep/core.c +++ b/net/bluetooth/bnep/core.c @@ -187,6 +187,8 @@ static int bnep_ctrl_set_mcfilter(struct bnep_session *s, u8 *data, int len) n /= (ETH_ALEN * 2); if (n > 0) { + int i; + s->mc_filter = 0; /* Always send broadcast */ @@ -202,12 +204,14 @@ static int bnep_ctrl_set_mcfilter(struct bnep_session *s, u8 *data, int len) BT_DBG("mc filter %s -> %s", batostr((void *) a1), batostr((void *) a2)); - #define INCA(a) { int i = 5; while (i >=0 && ++a[i--] == 0); } - /* Iterate from a1 to a2 */ set_bit(bnep_mc_hash(a1), (ulong *) &s->mc_filter); while (memcmp(a1, a2, 6) < 0 && s->mc_filter != ~0LL) { - INCA(a1); + /* Increment a1 */ + i = 5; + while (i >= 0 && ++a1[i--] == 0) + ; + set_bit(bnep_mc_hash(a1), (ulong *) &s->mc_filter); } } @@ -302,7 +306,6 @@ static u8 __bnep_rx_hlen[] = { ETH_ALEN + 2, /* BNEP_COMPRESSED_SRC_ONLY */ ETH_ALEN + 2 /* BNEP_COMPRESSED_DST_ONLY */ }; -#define BNEP_RX_TYPES (sizeof(__bnep_rx_hlen) - 1) static inline int bnep_rx_frame(struct bnep_session *s, struct sk_buff *skb) { @@ -314,7 +317,7 @@ static inline int bnep_rx_frame(struct bnep_session *s, struct sk_buff *skb) type = *(u8 *) skb->data; skb_pull(skb, 1); - if ((type & BNEP_TYPE_MASK) > BNEP_RX_TYPES) + if ((type & BNEP_TYPE_MASK) >= sizeof(__bnep_rx_hlen)) goto badframe; if ((type & BNEP_TYPE_MASK) == BNEP_CONTROL) { -- cgit v0.10.2 From 3aad75a128e2f2b8da31de1df4b9b9b4a8f65c66 Mon Sep 17 00:00:00 2001 From: Szymon Janc Date: Mon, 21 Mar 2011 14:19:58 +0100 Subject: Bluetooth: Fix checkpatch errors and some code style issues in bnep Signed-off-by: Szymon Janc Signed-off-by: Gustavo F. Padovan diff --git a/net/bluetooth/bnep/bnep.h b/net/bluetooth/bnep/bnep.h index 70672544..d768e04 100644 --- a/net/bluetooth/bnep/bnep.h +++ b/net/bluetooth/bnep/bnep.h @@ -23,88 +23,88 @@ #include #include -// Limits -#define BNEP_MAX_PROTO_FILTERS 5 -#define BNEP_MAX_MULTICAST_FILTERS 20 - -// UUIDs -#define BNEP_BASE_UUID 0x0000000000001000800000805F9B34FB -#define BNEP_UUID16 0x02 -#define BNEP_UUID32 0x04 -#define BNEP_UUID128 0x16 - -#define BNEP_SVC_PANU 0x1115 -#define BNEP_SVC_NAP 0x1116 -#define BNEP_SVC_GN 0x1117 - -// Packet types -#define BNEP_GENERAL 0x00 -#define BNEP_CONTROL 0x01 -#define BNEP_COMPRESSED 0x02 -#define BNEP_COMPRESSED_SRC_ONLY 0x03 -#define BNEP_COMPRESSED_DST_ONLY 0x04 - -// Control types -#define BNEP_CMD_NOT_UNDERSTOOD 0x00 -#define BNEP_SETUP_CONN_REQ 0x01 -#define BNEP_SETUP_CONN_RSP 0x02 -#define BNEP_FILTER_NET_TYPE_SET 0x03 -#define BNEP_FILTER_NET_TYPE_RSP 0x04 -#define BNEP_FILTER_MULTI_ADDR_SET 0x05 -#define BNEP_FILTER_MULTI_ADDR_RSP 0x06 - -// Extension types -#define BNEP_EXT_CONTROL 0x00 - -// Response messages -#define BNEP_SUCCESS 0x00 - -#define BNEP_CONN_INVALID_DST 0x01 -#define BNEP_CONN_INVALID_SRC 0x02 -#define BNEP_CONN_INVALID_SVC 0x03 -#define BNEP_CONN_NOT_ALLOWED 0x04 - -#define BNEP_FILTER_UNSUPPORTED_REQ 0x01 -#define BNEP_FILTER_INVALID_RANGE 0x02 -#define BNEP_FILTER_INVALID_MCADDR 0x02 -#define BNEP_FILTER_LIMIT_REACHED 0x03 -#define BNEP_FILTER_DENIED_SECURITY 0x04 - -// L2CAP settings -#define BNEP_MTU 1691 -#define BNEP_PSM 0x0f -#define BNEP_FLUSH_TO 0xffff -#define BNEP_CONNECT_TO 15 -#define BNEP_FILTER_TO 15 - -// Headers -#define BNEP_TYPE_MASK 0x7f -#define BNEP_EXT_HEADER 0x80 +/* Limits */ +#define BNEP_MAX_PROTO_FILTERS 5 +#define BNEP_MAX_MULTICAST_FILTERS 20 + +/* UUIDs */ +#define BNEP_BASE_UUID 0x0000000000001000800000805F9B34FB +#define BNEP_UUID16 0x02 +#define BNEP_UUID32 0x04 +#define BNEP_UUID128 0x16 + +#define BNEP_SVC_PANU 0x1115 +#define BNEP_SVC_NAP 0x1116 +#define BNEP_SVC_GN 0x1117 + +/* Packet types */ +#define BNEP_GENERAL 0x00 +#define BNEP_CONTROL 0x01 +#define BNEP_COMPRESSED 0x02 +#define BNEP_COMPRESSED_SRC_ONLY 0x03 +#define BNEP_COMPRESSED_DST_ONLY 0x04 + +/* Control types */ +#define BNEP_CMD_NOT_UNDERSTOOD 0x00 +#define BNEP_SETUP_CONN_REQ 0x01 +#define BNEP_SETUP_CONN_RSP 0x02 +#define BNEP_FILTER_NET_TYPE_SET 0x03 +#define BNEP_FILTER_NET_TYPE_RSP 0x04 +#define BNEP_FILTER_MULTI_ADDR_SET 0x05 +#define BNEP_FILTER_MULTI_ADDR_RSP 0x06 + +/* Extension types */ +#define BNEP_EXT_CONTROL 0x00 + +/* Response messages */ +#define BNEP_SUCCESS 0x00 + +#define BNEP_CONN_INVALID_DST 0x01 +#define BNEP_CONN_INVALID_SRC 0x02 +#define BNEP_CONN_INVALID_SVC 0x03 +#define BNEP_CONN_NOT_ALLOWED 0x04 + +#define BNEP_FILTER_UNSUPPORTED_REQ 0x01 +#define BNEP_FILTER_INVALID_RANGE 0x02 +#define BNEP_FILTER_INVALID_MCADDR 0x02 +#define BNEP_FILTER_LIMIT_REACHED 0x03 +#define BNEP_FILTER_DENIED_SECURITY 0x04 + +/* L2CAP settings */ +#define BNEP_MTU 1691 +#define BNEP_PSM 0x0f +#define BNEP_FLUSH_TO 0xffff +#define BNEP_CONNECT_TO 15 +#define BNEP_FILTER_TO 15 + +/* Headers */ +#define BNEP_TYPE_MASK 0x7f +#define BNEP_EXT_HEADER 0x80 struct bnep_setup_conn_req { - __u8 type; - __u8 ctrl; - __u8 uuid_size; - __u8 service[0]; + __u8 type; + __u8 ctrl; + __u8 uuid_size; + __u8 service[0]; } __packed; struct bnep_set_filter_req { - __u8 type; - __u8 ctrl; + __u8 type; + __u8 ctrl; __be16 len; - __u8 list[0]; + __u8 list[0]; } __packed; struct bnep_control_rsp { - __u8 type; - __u8 ctrl; + __u8 type; + __u8 ctrl; __be16 resp; } __packed; struct bnep_ext_hdr { - __u8 type; - __u8 len; - __u8 data[0]; + __u8 type; + __u8 len; + __u8 data[0]; } __packed; /* BNEP ioctl defines */ @@ -114,10 +114,10 @@ struct bnep_ext_hdr { #define BNEPGETCONNINFO _IOR('B', 211, int) struct bnep_connadd_req { - int sock; // Connected socket + int sock; /* Connected socket */ __u32 flags; __u16 role; - char device[16]; // Name of the Ethernet device + char device[16]; /* Name of the Ethernet device */ }; struct bnep_conndel_req { @@ -148,7 +148,7 @@ int bnep_del_connection(struct bnep_conndel_req *req); int bnep_get_connlist(struct bnep_connlist_req *req); int bnep_get_conninfo(struct bnep_conninfo *ci); -// BNEP sessions +/* BNEP sessions */ struct bnep_session { struct list_head list; @@ -173,7 +173,7 @@ void bnep_sock_cleanup(void); static inline int bnep_mc_hash(__u8 *addr) { - return (crc32_be(~0, addr, ETH_ALEN) >> 26); + return crc32_be(~0, addr, ETH_ALEN) >> 26; } #endif diff --git a/net/bluetooth/bnep/core.c b/net/bluetooth/bnep/core.c index 940b4e1..0a2e76b 100644 --- a/net/bluetooth/bnep/core.c +++ b/net/bluetooth/bnep/core.c @@ -131,7 +131,8 @@ static int bnep_ctrl_set_netfilter(struct bnep_session *s, __be16 *data, int len return -EILSEQ; n = get_unaligned_be16(data); - data++; len -= 2; + data++; + len -= 2; if (len < n) return -EILSEQ; @@ -176,7 +177,8 @@ static int bnep_ctrl_set_mcfilter(struct bnep_session *s, u8 *data, int len) return -EILSEQ; n = get_unaligned_be16(data); - data += 2; len -= 2; + data += 2; + len -= 2; if (len < n) return -EILSEQ; @@ -198,8 +200,10 @@ static int bnep_ctrl_set_mcfilter(struct bnep_session *s, u8 *data, int len) for (; n > 0; n--) { u8 a1[6], *a2; - memcpy(a1, data, ETH_ALEN); data += ETH_ALEN; - a2 = data; data += ETH_ALEN; + memcpy(a1, data, ETH_ALEN); + data += ETH_ALEN; + a2 = data; + data += ETH_ALEN; BT_DBG("mc filter %s -> %s", batostr((void *) a1), batostr((void *) a2)); @@ -231,7 +235,8 @@ static int bnep_rx_control(struct bnep_session *s, void *data, int len) u8 cmd = *(u8 *)data; int err = 0; - data++; len--; + data++; + len--; switch (cmd) { case BNEP_CMD_NOT_UNDERSTOOD: @@ -315,7 +320,8 @@ static inline int bnep_rx_frame(struct bnep_session *s, struct sk_buff *skb) dev->stats.rx_bytes += skb->len; - type = *(u8 *) skb->data; skb_pull(skb, 1); + type = *(u8 *) skb->data; + skb_pull(skb, 1); if ((type & BNEP_TYPE_MASK) >= sizeof(__bnep_rx_hlen)) goto badframe; @@ -370,14 +376,14 @@ static inline int bnep_rx_frame(struct bnep_session *s, struct sk_buff *skb) case BNEP_COMPRESSED_DST_ONLY: memcpy(__skb_put(nskb, ETH_ALEN), skb_mac_header(skb), - ETH_ALEN); + ETH_ALEN); memcpy(__skb_put(nskb, ETH_ALEN + 2), s->eh.h_source, - ETH_ALEN + 2); + ETH_ALEN + 2); break; case BNEP_GENERAL: memcpy(__skb_put(nskb, ETH_ALEN * 2), skb_mac_header(skb), - ETH_ALEN * 2); + ETH_ALEN * 2); put_unaligned(s->eh.h_proto, (__be16 *) __skb_put(nskb, 2)); break; } @@ -481,7 +487,7 @@ static int bnep_session(void *arg) while (!atomic_read(&s->killed)) { set_current_state(TASK_INTERRUPTIBLE); - // RX + /* RX */ while ((skb = skb_dequeue(&sk->sk_receive_queue))) { skb_orphan(skb); bnep_rx_frame(s, skb); @@ -490,7 +496,7 @@ static int bnep_session(void *arg) if (sk->sk_state != BT_CONNECTED) break; - // TX + /* TX */ while ((skb = skb_dequeue(&sk->sk_write_queue))) if (bnep_tx_frame(s, skb)) break; @@ -558,8 +564,8 @@ int bnep_add_connection(struct bnep_connadd_req *req, struct socket *sock) /* session struct allocated as private part of net_device */ dev = alloc_netdev(sizeof(struct bnep_session), - (*req->device) ? req->device : "bnep%d", - bnep_net_setup); + (*req->device) ? req->device : "bnep%d", + bnep_net_setup); if (!dev) return -ENOMEM; @@ -574,7 +580,7 @@ int bnep_add_connection(struct bnep_connadd_req *req, struct socket *sock) s = netdev_priv(dev); /* This is rx header therefore addresses are swapped. - * ie eh.h_dest is our local address. */ + * ie. eh.h_dest is our local address. */ memcpy(s->eh.h_dest, &src, ETH_ALEN); memcpy(s->eh.h_source, &dst, ETH_ALEN); memcpy(dev->dev_addr, s->eh.h_dest, ETH_ALEN); @@ -600,9 +606,8 @@ int bnep_add_connection(struct bnep_connadd_req *req, struct socket *sock) SET_NETDEV_DEVTYPE(dev, &bnep_type); err = register_netdev(dev); - if (err) { + if (err) goto failed; - } __bnep_link_session(s); -- cgit v0.10.2 From 8c20aa9ffc5a5ef52b6148e905671a8d12b40c87 Mon Sep 17 00:00:00 2001 From: Szymon Janc Date: Mon, 21 Mar 2011 14:19:59 +0100 Subject: Bluetooth: Use #include instead of As warned by checkpatch.pl, use #include instead of Signed-off-by: Szymon Janc Signed-off-by: Gustavo F. Padovan diff --git a/net/bluetooth/bnep/sock.c b/net/bluetooth/bnep/sock.c index d935da7..17800b1 100644 --- a/net/bluetooth/bnep/sock.c +++ b/net/bluetooth/bnep/sock.c @@ -39,10 +39,10 @@ #include #include #include +#include #include #include -#include #include "bnep.h" -- cgit v0.10.2 From 17f09a7e4ec5dd6a0d96498da6bf78762fba4468 Mon Sep 17 00:00:00 2001 From: Szymon Janc Date: Mon, 21 Mar 2011 14:20:01 +0100 Subject: Bluetooth: Fix checkpatch errors, code style issues and typos in hidp Signed-off-by: Szymon Janc Signed-off-by: Gustavo F. Padovan diff --git a/net/bluetooth/hidp/core.c b/net/bluetooth/hidp/core.c index 5ec1297..a1472b7 100644 --- a/net/bluetooth/hidp/core.c +++ b/net/bluetooth/hidp/core.c @@ -55,22 +55,24 @@ static DECLARE_RWSEM(hidp_session_sem); static LIST_HEAD(hidp_session_list); static unsigned char hidp_keycode[256] = { - 0, 0, 0, 0, 30, 48, 46, 32, 18, 33, 34, 35, 23, 36, 37, 38, - 50, 49, 24, 25, 16, 19, 31, 20, 22, 47, 17, 45, 21, 44, 2, 3, - 4, 5, 6, 7, 8, 9, 10, 11, 28, 1, 14, 15, 57, 12, 13, 26, - 27, 43, 43, 39, 40, 41, 51, 52, 53, 58, 59, 60, 61, 62, 63, 64, - 65, 66, 67, 68, 87, 88, 99, 70,119,110,102,104,111,107,109,106, - 105,108,103, 69, 98, 55, 74, 78, 96, 79, 80, 81, 75, 76, 77, 71, - 72, 73, 82, 83, 86,127,116,117,183,184,185,186,187,188,189,190, - 191,192,193,194,134,138,130,132,128,129,131,137,133,135,136,113, - 115,114, 0, 0, 0,121, 0, 89, 93,124, 92, 94, 95, 0, 0, 0, - 122,123, 90, 91, 85, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 29, 42, 56,125, 97, 54,100,126,164,166,165,163,161,115,114,113, - 150,158,159,128,136,177,178,176,142,152,173,140 + 0, 0, 0, 0, 30, 48, 46, 32, 18, 33, 34, 35, 23, 36, + 37, 38, 50, 49, 24, 25, 16, 19, 31, 20, 22, 47, 17, 45, + 21, 44, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 28, 1, + 14, 15, 57, 12, 13, 26, 27, 43, 43, 39, 40, 41, 51, 52, + 53, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 87, 88, + 99, 70, 119, 110, 102, 104, 111, 107, 109, 106, 105, 108, 103, 69, + 98, 55, 74, 78, 96, 79, 80, 81, 75, 76, 77, 71, 72, 73, + 82, 83, 86, 127, 116, 117, 183, 184, 185, 186, 187, 188, 189, 190, + 191, 192, 193, 194, 134, 138, 130, 132, 128, 129, 131, 137, 133, 135, + 136, 113, 115, 114, 0, 0, 0, 121, 0, 89, 93, 124, 92, 94, + 95, 0, 0, 0, 122, 123, 90, 91, 85, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 29, 42, 56, 125, 97, 54, 100, 126, 164, 166, 165, 163, 161, 115, + 114, 113, 150, 158, 159, 128, 136, 177, 178, 176, 142, 152, 173, 140 }; static unsigned char hidp_mkeyspat[] = { 0x01, 0x01, 0x01, 0x01, 0x01, 0x01 }; @@ -721,7 +723,8 @@ static int hidp_session(void *arg) while (!atomic_read(&session->terminate)) { set_current_state(TASK_INTERRUPTIBLE); - if (ctrl_sk->sk_state != BT_CONNECTED || intr_sk->sk_state != BT_CONNECTED) + if (ctrl_sk->sk_state != BT_CONNECTED || + intr_sk->sk_state != BT_CONNECTED) break; while ((skb = skb_dequeue(&ctrl_sk->sk_receive_queue))) { diff --git a/net/bluetooth/hidp/hidp.h b/net/bluetooth/hidp/hidp.h index 13de5fa..b412e71 100644 --- a/net/bluetooth/hidp/hidp.h +++ b/net/bluetooth/hidp/hidp.h @@ -84,8 +84,8 @@ #define HIDP_WAITING_FOR_SEND_ACK 11 struct hidp_connadd_req { - int ctrl_sock; // Connected control socket - int intr_sock; // Connteted interrupt socket + int ctrl_sock; /* Connected control socket */ + int intr_sock; /* Connected interrupt socket */ __u16 parser; __u16 rd_size; __u8 __user *rd_data; diff --git a/net/bluetooth/hidp/sock.c b/net/bluetooth/hidp/sock.c index 250dfd4..178ac7f 100644 --- a/net/bluetooth/hidp/sock.c +++ b/net/bluetooth/hidp/sock.c @@ -85,7 +85,8 @@ static int hidp_sock_ioctl(struct socket *sock, unsigned int cmd, unsigned long return err; } - if (csock->sk->sk_state != BT_CONNECTED || isock->sk->sk_state != BT_CONNECTED) { + if (csock->sk->sk_state != BT_CONNECTED || + isock->sk->sk_state != BT_CONNECTED) { sockfd_put(csock); sockfd_put(isock); return -EBADFD; @@ -140,8 +141,8 @@ static int hidp_sock_ioctl(struct socket *sock, unsigned int cmd, unsigned long #ifdef CONFIG_COMPAT struct compat_hidp_connadd_req { - int ctrl_sock; // Connected control socket - int intr_sock; // Connteted interrupt socket + int ctrl_sock; /* Connected control socket */ + int intr_sock; /* Connected interrupt socket */ __u16 parser; __u16 rd_size; compat_uptr_t rd_data; -- cgit v0.10.2 From 58aac468be411f2a9b4a28f2ed8e6e2a0db04267 Mon Sep 17 00:00:00 2001 From: Szymon Janc Date: Mon, 21 Mar 2011 14:20:03 +0100 Subject: Bluetooth: Do not use assignments in IF conditions Fix checkpatch warnings concerning assignments in if conditions. Signed-off-by: Szymon Janc Signed-off-by: Gustavo F. Padovan diff --git a/net/bluetooth/cmtp/core.c b/net/bluetooth/cmtp/core.c index 964ea91..16aa6bd 100644 --- a/net/bluetooth/cmtp/core.c +++ b/net/bluetooth/cmtp/core.c @@ -235,9 +235,12 @@ static void cmtp_process_transmit(struct cmtp_session *session) size = min_t(uint, ((tail < 258) ? (tail - 2) : (tail - 3)), skb->len); - if ((scb->id < 0) && ((scb->id = cmtp_alloc_block_id(session)) < 0)) { - skb_queue_head(&session->transmit, skb); - break; + if (scb->id < 0) { + scb->id = cmtp_alloc_block_id(session); + if (scb->id < 0) { + skb_queue_head(&session->transmit, skb); + break; + } } if (size < 256) { -- cgit v0.10.2 From ffd13320aa96e07f3048ebdcc603aaf38bed0c47 Mon Sep 17 00:00:00 2001 From: Szymon Janc Date: Mon, 21 Mar 2011 14:20:04 +0100 Subject: Bluetooth: Use #include instead of As warned by checkpatch.pl, use #include instead of Signed-off-by: Szymon Janc Signed-off-by: Gustavo F. Padovan diff --git a/net/bluetooth/cmtp/sock.c b/net/bluetooth/cmtp/sock.c index 7ea1979..3f2dd5c 100644 --- a/net/bluetooth/cmtp/sock.c +++ b/net/bluetooth/cmtp/sock.c @@ -34,12 +34,12 @@ #include #include #include +#include #include #include #include -#include #include "cmtp.h" -- cgit v0.10.2 From e0e185efbad442a659657c152a9cd9b3fdcb43f2 Mon Sep 17 00:00:00 2001 From: Szymon Janc Date: Mon, 21 Mar 2011 14:20:05 +0100 Subject: Bluetooth: Fix checkpatch error in cmtp.h Do not use C99 // comments. Signed-off-by: Szymon Janc Signed-off-by: Gustavo F. Padovan diff --git a/net/bluetooth/cmtp/cmtp.h b/net/bluetooth/cmtp/cmtp.h index 785e79e..c6f78f8 100644 --- a/net/bluetooth/cmtp/cmtp.h +++ b/net/bluetooth/cmtp/cmtp.h @@ -37,7 +37,7 @@ #define CMTP_LOOPBACK 0 struct cmtp_connadd_req { - int sock; // Connected socket + int sock; /* Connected socket */ __u32 flags; }; -- cgit v0.10.2 From c68fb7ff29622a7db8264f939f94e37330c27080 Mon Sep 17 00:00:00 2001 From: Szymon Janc Date: Tue, 22 Mar 2011 13:12:19 +0100 Subject: Bluetooth: Rename cmd to param in pending_cmd This field holds not whole command but only command specific parameters. Signed-off-by: Szymon Janc Signed-off-by: Gustavo F. Padovan diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index f7ce782..d0c0123 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -36,7 +36,7 @@ struct pending_cmd { struct list_head list; __u16 opcode; int index; - void *cmd; + void *param; struct sock *sk; void *user_data; }; @@ -217,7 +217,7 @@ static int read_controller_info(struct sock *sk, u16 index) static void mgmt_pending_free(struct pending_cmd *cmd) { sock_put(cmd->sk); - kfree(cmd->cmd); + kfree(cmd->param); kfree(cmd); } @@ -233,13 +233,13 @@ static struct pending_cmd *mgmt_pending_add(struct sock *sk, u16 opcode, cmd->opcode = opcode; cmd->index = index; - cmd->cmd = kmalloc(len, GFP_ATOMIC); - if (!cmd->cmd) { + cmd->param = kmalloc(len, GFP_ATOMIC); + if (!cmd->param) { kfree(cmd); return NULL; } - memcpy(cmd->cmd, data, len); + memcpy(cmd->param, data, len); cmd->sk = sk; sock_hold(sk); @@ -1426,7 +1426,7 @@ struct cmd_lookup { static void mode_rsp(struct pending_cmd *cmd, void *data) { - struct mgmt_mode *cp = cmd->cmd; + struct mgmt_mode *cp = cmd->param; struct cmd_lookup *match = data; if (cp->val != match->val) @@ -1525,7 +1525,7 @@ int mgmt_connected(u16 index, bdaddr_t *bdaddr) static void disconnect_rsp(struct pending_cmd *cmd, void *data) { - struct mgmt_cp_disconnect *cp = cmd->cmd; + struct mgmt_cp_disconnect *cp = cmd->param; struct sock **sk = data; struct mgmt_rp_disconnect rp; -- cgit v0.10.2 From 8fce6357a9e72c4c9c846f9951895954bfb34ad1 Mon Sep 17 00:00:00 2001 From: Szymon Janc Date: Tue, 22 Mar 2011 13:12:20 +0100 Subject: Bluetooth: Allow for NULL data in mgmt_pending_add Since index is in mgmt_hdr it is possible to have mgmt command with no parameters that still needs to add itself to pending list. Signed-off-by: Szymon Janc Signed-off-by: Gustavo F. Padovan diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index d0c0123..93f0f04 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -239,7 +239,8 @@ static struct pending_cmd *mgmt_pending_add(struct sock *sk, u16 opcode, return NULL; } - memcpy(cmd->param, data, len); + if (data) + memcpy(cmd->param, data, len); cmd->sk = sk; sock_hold(sk); -- cgit v0.10.2 From c35938b2f56547ee77b5a038fe0db394aeac59bb Mon Sep 17 00:00:00 2001 From: Szymon Janc Date: Tue, 22 Mar 2011 13:12:21 +0100 Subject: Bluetooth: Add read_local_oob_data management command This patch adds a command to read local OOB data to the managment interface. The command maps directly to the Read Local OOB Data HCI command. Signed-off-by: Szymon Janc Signed-off-by: Gustavo F. Padovan diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h index 1cd031c..ac4de1a 100644 --- a/include/net/bluetooth/hci.h +++ b/include/net/bluetooth/hci.h @@ -613,6 +613,13 @@ struct hci_cp_write_ssp_mode { __u8 mode; } __packed; +#define HCI_OP_READ_LOCAL_OOB_DATA 0x0c57 +struct hci_rp_read_local_oob_data { + __u8 status; + __u8 hash[16]; + __u8 randomizer[16]; +} __packed; + #define HCI_OP_READ_INQ_RSP_TX_POWER 0x0c58 #define HCI_OP_READ_LOCAL_VERSION 0x1001 diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index 3912c7a..fd9b8a3 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -768,6 +768,8 @@ int mgmt_user_confirm_neg_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status); int mgmt_auth_failed(u16 index, bdaddr_t *bdaddr, u8 status); int mgmt_set_local_name_complete(u16 index, u8 *name, u8 status); +int mgmt_read_local_oob_data_reply_complete(u16 index, u8 *hash, u8 *randomizer, + u8 status); /* HCI info for socket */ #define hci_pi(sk) ((struct hci_pinfo *) sk) diff --git a/include/net/bluetooth/mgmt.h b/include/net/bluetooth/mgmt.h index 89e7c82..6ebb126 100644 --- a/include/net/bluetooth/mgmt.h +++ b/include/net/bluetooth/mgmt.h @@ -177,6 +177,12 @@ struct mgmt_cp_set_local_name { __u8 name[MGMT_MAX_NAME_LENGTH]; } __packed; +#define MGMT_OP_READ_LOCAL_OOB_DATA 0x0018 +struct mgmt_rp_read_local_oob_data { + __u8 hash[16]; + __u8 randomizer[16]; +} __packed; + #define MGMT_EV_CMD_COMPLETE 0x0001 struct mgmt_ev_cmd_complete { __le16 opcode; diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index 0def3e1..582ef60 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -822,6 +822,17 @@ static void hci_cc_user_confirm_neg_reply(struct hci_dev *hdev, rp->status); } +static void hci_cc_read_local_oob_data_reply(struct hci_dev *hdev, + struct sk_buff *skb) +{ + struct hci_rp_read_local_oob_data *rp = (void *) skb->data; + + BT_DBG("%s status 0x%x", hdev->name, rp->status); + + mgmt_read_local_oob_data_reply_complete(hdev->id, rp->hash, + rp->randomizer, rp->status); +} + static inline void hci_cs_inquiry(struct hci_dev *hdev, __u8 status) { BT_DBG("%s status 0x%x", hdev->name, status); @@ -1752,6 +1763,10 @@ static inline void hci_cmd_complete_evt(struct hci_dev *hdev, struct sk_buff *sk hci_cc_pin_code_neg_reply(hdev, skb); break; + case HCI_OP_READ_LOCAL_OOB_DATA: + hci_cc_read_local_oob_data_reply(hdev, skb); + break; + case HCI_OP_LE_READ_BUFFER_SIZE: hci_cc_le_read_buffer_size(hdev, skb); break; diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 93f0f04..33b1f74 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -1296,6 +1296,55 @@ failed: return err; } +static int read_local_oob_data(struct sock *sk, u16 index) +{ + struct hci_dev *hdev; + struct pending_cmd *cmd; + int err; + + BT_DBG("hci%u", index); + + hdev = hci_dev_get(index); + if (!hdev) + return cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA, + ENODEV); + + hci_dev_lock_bh(hdev); + + if (!test_bit(HCI_UP, &hdev->flags)) { + err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA, + ENETDOWN); + goto unlock; + } + + if (!(hdev->features[6] & LMP_SIMPLE_PAIR)) { + err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA, + EOPNOTSUPP); + goto unlock; + } + + if (mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, index)) { + err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA, EBUSY); + goto unlock; + } + + cmd = mgmt_pending_add(sk, MGMT_OP_READ_LOCAL_OOB_DATA, index, NULL, 0); + if (!cmd) { + err = -ENOMEM; + goto unlock; + } + + err = hci_send_cmd(hdev, HCI_OP_READ_LOCAL_OOB_DATA, 0, NULL); + if (err < 0) + mgmt_pending_remove(cmd); + +unlock: + hci_dev_unlock_bh(hdev); + hci_dev_put(hdev); + + return err; +} + int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen) { unsigned char *buf; @@ -1394,6 +1443,10 @@ int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen) case MGMT_OP_SET_LOCAL_NAME: err = set_local_name(sk, index, buf + sizeof(*hdr), len); break; + case MGMT_OP_READ_LOCAL_OOB_DATA: + err = read_local_oob_data(sk, index); + break; + default: BT_DBG("Unknown op %u", opcode); err = cmd_status(sk, index, opcode, 0x01); @@ -1723,3 +1776,33 @@ failed: mgmt_pending_remove(cmd); return err; } + +int mgmt_read_local_oob_data_reply_complete(u16 index, u8 *hash, u8 *randomizer, + u8 status) +{ + struct pending_cmd *cmd; + int err; + + BT_DBG("hci%u status %u", index, status); + + cmd = mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, index); + if (!cmd) + return -ENOENT; + + if (status) { + err = cmd_status(cmd->sk, index, MGMT_OP_READ_LOCAL_OOB_DATA, + EIO); + } else { + struct mgmt_rp_read_local_oob_data rp; + + memcpy(rp.hash, hash, sizeof(rp.hash)); + memcpy(rp.randomizer, randomizer, sizeof(rp.randomizer)); + + err = cmd_complete(cmd->sk, index, MGMT_OP_READ_LOCAL_OOB_DATA, + &rp, sizeof(rp)); + } + + mgmt_pending_remove(cmd); + + return err; +} -- cgit v0.10.2 From 2763eda6ccaf126633bb3180f440c8f3589f0679 Mon Sep 17 00:00:00 2001 From: Szymon Janc Date: Tue, 22 Mar 2011 13:12:22 +0100 Subject: Bluetooth: Add add/remove_remote_oob_data management commands This patch adds commands to add and remove remote OOB data to the managment interface. Remote data is stored in kernel and can be used by corresponding HCI commands and events when needed. Signed-off-by: Szymon Janc Signed-off-by: Gustavo F. Padovan diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h index ac4de1a..b989a8c 100644 --- a/include/net/bluetooth/hci.h +++ b/include/net/bluetooth/hci.h @@ -426,6 +426,18 @@ struct hci_rp_user_confirm_reply { #define HCI_OP_USER_CONFIRM_NEG_REPLY 0x042d +#define HCI_OP_REMOTE_OOB_DATA_REPLY 0x0430 +struct hci_cp_remote_oob_data_reply { + bdaddr_t bdaddr; + __u8 hash[16]; + __u8 randomizer[16]; +} __packed; + +#define HCI_OP_REMOTE_OOB_DATA_NEG_REPLY 0x0433 +struct hci_cp_remote_oob_data_neg_reply { + bdaddr_t bdaddr; +} __packed; + #define HCI_OP_IO_CAPABILITY_NEG_REPLY 0x0434 struct hci_cp_io_capability_neg_reply { bdaddr_t bdaddr; @@ -962,6 +974,11 @@ struct hci_ev_user_confirm_req { __le32 passkey; } __packed; +#define HCI_EV_REMOTE_OOB_DATA_REQUEST 0x35 +struct hci_ev_remote_oob_data_request { + bdaddr_t bdaddr; +} __packed; + #define HCI_EV_SIMPLE_PAIR_COMPLETE 0x36 struct hci_ev_simple_pair_complete { __u8 status; diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index fd9b8a3..87bff51 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -82,6 +82,13 @@ struct link_key { u8 pin_len; }; +struct oob_data { + struct list_head list; + bdaddr_t bdaddr; + u8 hash[16]; + u8 randomizer[16]; +}; + #define NUM_REASSEMBLY 4 struct hci_dev { struct list_head list; @@ -169,6 +176,8 @@ struct hci_dev { struct list_head link_keys; + struct list_head remote_oob_data; + struct hci_dev_stats stat; struct sk_buff_head driver_init; @@ -505,6 +514,13 @@ int hci_add_link_key(struct hci_dev *hdev, int new_key, bdaddr_t *bdaddr, u8 *key, u8 type, u8 pin_len); int hci_remove_link_key(struct hci_dev *hdev, bdaddr_t *bdaddr); +int hci_remote_oob_data_clear(struct hci_dev *hdev); +struct oob_data *hci_find_remote_oob_data(struct hci_dev *hdev, + bdaddr_t *bdaddr); +int hci_add_remote_oob_data(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 *hash, + u8 *randomizer); +int hci_remove_remote_oob_data(struct hci_dev *hdev, bdaddr_t *bdaddr); + void hci_del_off_timer(struct hci_dev *hdev); void hci_event_packet(struct hci_dev *hdev, struct sk_buff *skb); diff --git a/include/net/bluetooth/mgmt.h b/include/net/bluetooth/mgmt.h index 6ebb126..1a6283f 100644 --- a/include/net/bluetooth/mgmt.h +++ b/include/net/bluetooth/mgmt.h @@ -183,6 +183,18 @@ struct mgmt_rp_read_local_oob_data { __u8 randomizer[16]; } __packed; +#define MGMT_OP_ADD_REMOTE_OOB_DATA 0x0019 +struct mgmt_cp_add_remote_oob_data { + bdaddr_t bdaddr; + __u8 hash[16]; + __u8 randomizer[16]; +} __packed; + +#define MGMT_OP_REMOVE_REMOTE_OOB_DATA 0x001A +struct mgmt_cp_remove_remote_oob_data { + bdaddr_t bdaddr; +} __packed; + #define MGMT_EV_CMD_COMPLETE 0x0001 struct mgmt_ev_cmd_complete { __le16 opcode; diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index c20cbe5..675f0a1 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -1076,6 +1076,70 @@ static void hci_cmd_timer(unsigned long arg) tasklet_schedule(&hdev->cmd_task); } +struct oob_data *hci_find_remote_oob_data(struct hci_dev *hdev, + bdaddr_t *bdaddr) +{ + struct oob_data *data; + + list_for_each_entry(data, &hdev->remote_oob_data, list) + if (bacmp(bdaddr, &data->bdaddr) == 0) + return data; + + return NULL; +} + +int hci_remove_remote_oob_data(struct hci_dev *hdev, bdaddr_t *bdaddr) +{ + struct oob_data *data; + + data = hci_find_remote_oob_data(hdev, bdaddr); + if (!data) + return -ENOENT; + + BT_DBG("%s removing %s", hdev->name, batostr(bdaddr)); + + list_del(&data->list); + kfree(data); + + return 0; +} + +int hci_remote_oob_data_clear(struct hci_dev *hdev) +{ + struct oob_data *data, *n; + + list_for_each_entry_safe(data, n, &hdev->remote_oob_data, list) { + list_del(&data->list); + kfree(data); + } + + return 0; +} + +int hci_add_remote_oob_data(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 *hash, + u8 *randomizer) +{ + struct oob_data *data; + + data = hci_find_remote_oob_data(hdev, bdaddr); + + if (!data) { + data = kmalloc(sizeof(*data), GFP_ATOMIC); + if (!data) + return -ENOMEM; + + bacpy(&data->bdaddr, bdaddr); + list_add(&data->list, &hdev->remote_oob_data); + } + + memcpy(data->hash, hash, sizeof(data->hash)); + memcpy(data->randomizer, randomizer, sizeof(data->randomizer)); + + BT_DBG("%s for %s", hdev->name, batostr(bdaddr)); + + return 0; +} + /* Register HCI device */ int hci_register_dev(struct hci_dev *hdev) { @@ -1140,6 +1204,8 @@ int hci_register_dev(struct hci_dev *hdev) INIT_LIST_HEAD(&hdev->link_keys); + INIT_LIST_HEAD(&hdev->remote_oob_data); + INIT_WORK(&hdev->power_on, hci_power_on); INIT_WORK(&hdev->power_off, hci_power_off); setup_timer(&hdev->off_timer, hci_auto_off, (unsigned long) hdev); @@ -1219,6 +1285,7 @@ int hci_unregister_dev(struct hci_dev *hdev) hci_blacklist_clear(hdev); hci_uuids_clear(hdev); hci_link_keys_clear(hdev); + hci_remote_oob_data_clear(hdev); hci_dev_unlock_bh(hdev); __hci_dev_put(hdev); diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index 582ef60..e0aaf30 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -2471,6 +2471,37 @@ static inline void hci_remote_host_features_evt(struct hci_dev *hdev, struct sk_ hci_dev_unlock(hdev); } +static inline void hci_remote_oob_data_request_evt(struct hci_dev *hdev, + struct sk_buff *skb) +{ + struct hci_ev_remote_oob_data_request *ev = (void *) skb->data; + struct oob_data *data; + + BT_DBG("%s", hdev->name); + + hci_dev_lock(hdev); + + data = hci_find_remote_oob_data(hdev, &ev->bdaddr); + if (data) { + struct hci_cp_remote_oob_data_reply cp; + + bacpy(&cp.bdaddr, &ev->bdaddr); + memcpy(cp.hash, data->hash, sizeof(cp.hash)); + memcpy(cp.randomizer, data->randomizer, sizeof(cp.randomizer)); + + hci_send_cmd(hdev, HCI_OP_REMOTE_OOB_DATA_REPLY, sizeof(cp), + &cp); + } else { + struct hci_cp_remote_oob_data_neg_reply cp; + + bacpy(&cp.bdaddr, &ev->bdaddr); + hci_send_cmd(hdev, HCI_OP_REMOTE_OOB_DATA_NEG_REPLY, sizeof(cp), + &cp); + } + + hci_dev_unlock(hdev); +} + static inline void hci_le_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb) { struct hci_ev_le_conn_complete *ev = (void *) skb->data; @@ -2673,6 +2704,10 @@ void hci_event_packet(struct hci_dev *hdev, struct sk_buff *skb) hci_le_meta_evt(hdev, skb); break; + case HCI_EV_REMOTE_OOB_DATA_REQUEST: + hci_remote_oob_data_request_evt(hdev, skb); + break; + default: BT_DBG("%s event 0x%x", hdev->name, event); break; diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 33b1f74..a42dc8c 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -1345,6 +1345,74 @@ unlock: return err; } +static int add_remote_oob_data(struct sock *sk, u16 index, unsigned char *data, + u16 len) +{ + struct hci_dev *hdev; + struct mgmt_cp_add_remote_oob_data *cp = (void *) data; + int err; + + BT_DBG("hci%u ", index); + + if (len != sizeof(*cp)) + return cmd_status(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA, + EINVAL); + + hdev = hci_dev_get(index); + if (!hdev) + return cmd_status(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA, + ENODEV); + + hci_dev_lock_bh(hdev); + + err = hci_add_remote_oob_data(hdev, &cp->bdaddr, cp->hash, + cp->randomizer); + if (err < 0) + err = cmd_status(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA, -err); + else + err = cmd_complete(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA, NULL, + 0); + + hci_dev_unlock_bh(hdev); + hci_dev_put(hdev); + + return err; +} + +static int remove_remote_oob_data(struct sock *sk, u16 index, + unsigned char *data, u16 len) +{ + struct hci_dev *hdev; + struct mgmt_cp_remove_remote_oob_data *cp = (void *) data; + int err; + + BT_DBG("hci%u ", index); + + if (len != sizeof(*cp)) + return cmd_status(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA, + EINVAL); + + hdev = hci_dev_get(index); + if (!hdev) + return cmd_status(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA, + ENODEV); + + hci_dev_lock_bh(hdev); + + err = hci_remove_remote_oob_data(hdev, &cp->bdaddr); + if (err < 0) + err = cmd_status(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA, + -err); + else + err = cmd_complete(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA, + NULL, 0); + + hci_dev_unlock_bh(hdev); + hci_dev_put(hdev); + + return err; +} + int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen) { unsigned char *buf; @@ -1446,6 +1514,13 @@ int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen) case MGMT_OP_READ_LOCAL_OOB_DATA: err = read_local_oob_data(sk, index); break; + case MGMT_OP_ADD_REMOTE_OOB_DATA: + err = add_remote_oob_data(sk, index, buf + sizeof(*hdr), len); + break; + case MGMT_OP_REMOVE_REMOTE_OOB_DATA: + err = remove_remote_oob_data(sk, index, buf + sizeof(*hdr), + len); + break; default: BT_DBG("Unknown op %u", opcode); -- cgit v0.10.2 From ce85ee13e6b5d078f4a6c3b02ba7cd0fa140c552 Mon Sep 17 00:00:00 2001 From: Szymon Janc Date: Tue, 22 Mar 2011 13:12:23 +0100 Subject: Bluetooth: Enable support for out of band association model If remote side reports oob availability or we are pairing initiator use oob data for pairing if available. Signed-off-by: Szymon Janc Signed-off-by: Gustavo F. Padovan diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index e0aaf30..da4c662 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -2371,9 +2371,14 @@ static inline void hci_io_capa_request_evt(struct hci_dev *hdev, struct sk_buff bacpy(&cp.bdaddr, &ev->bdaddr); cp.capability = conn->io_capability; - cp.oob_data = 0; cp.authentication = hci_get_auth_req(conn); + if ((conn->out == 0x01 || conn->remote_oob == 0x01) && + hci_find_remote_oob_data(hdev, &conn->dst)) + cp.oob_data = 0x01; + else + cp.oob_data = 0x00; + hci_send_cmd(hdev, HCI_OP_IO_CAPABILITY_REPLY, sizeof(cp), &cp); } else { -- cgit v0.10.2 From f3dd4f0f586b3a70734820b68c69985363e2d798 Mon Sep 17 00:00:00 2001 From: "Gustavo F. Padovan" Date: Thu, 24 Mar 2011 20:14:16 -0300 Subject: Bluetooth: Remove unused struct l2cap_conn item Signed-off-by: Gustavo F. Padovan diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h index 7a02625..2b9ca0d 100644 --- a/include/net/bluetooth/l2cap.h +++ b/include/net/bluetooth/l2cap.h @@ -301,7 +301,6 @@ struct l2cap_conn { struct sk_buff *rx_skb; __u32 rx_len; - __u8 rx_ident; __u8 tx_ident; __u8 disc_reason; -- cgit v0.10.2 From d1010240fa9aac93da56a683c1295e759ee69d10 Mon Sep 17 00:00:00 2001 From: "Gustavo F. Padovan" Date: Fri, 25 Mar 2011 00:39:48 -0300 Subject: Bluetooth: Move bt_accept_enqueue() to outside __l2cap_chan_add bt_accept_enqueue() is not really a channel action, so do it outside. This patch is part of a set of patches to create an struct l2cap_chan to have a clear separation between the struct sock and the L2CAP channel stuff. Signed-off-by: Gustavo F. Padovan diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index b5a1ce0..bf09f60 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -169,7 +169,7 @@ static inline void l2cap_chan_unlink(struct l2cap_chan_list *l, struct sock *sk) __sock_put(sk); } -static void __l2cap_chan_add(struct l2cap_conn *conn, struct sock *sk, struct sock *parent) +static void __l2cap_chan_add(struct l2cap_conn *conn, struct sock *sk) { struct l2cap_chan_list *l = &conn->chan_list; @@ -204,9 +204,6 @@ static void __l2cap_chan_add(struct l2cap_conn *conn, struct sock *sk, struct so } __l2cap_chan_link(l, sk); - - if (parent) - bt_accept_enqueue(parent, sk); } /* Delete channel. @@ -652,7 +649,9 @@ static void l2cap_le_conn_ready(struct l2cap_conn *conn) bacpy(&bt_sk(sk)->src, conn->src); bacpy(&bt_sk(sk)->dst, conn->dst); - __l2cap_chan_add(conn, sk, parent); + bt_accept_enqueue(parent, sk); + + __l2cap_chan_add(conn, sk); l2cap_sock_set_timer(sk, sk->sk_sndtimeo); @@ -793,11 +792,11 @@ static void l2cap_conn_del(struct hci_conn *hcon, int err) kfree(conn); } -static inline void l2cap_chan_add(struct l2cap_conn *conn, struct sock *sk, struct sock *parent) +static inline void l2cap_chan_add(struct l2cap_conn *conn, struct sock *sk) { struct l2cap_chan_list *l = &conn->chan_list; write_lock_bh(&l->lock); - __l2cap_chan_add(conn, sk, parent); + __l2cap_chan_add(conn, sk); write_unlock_bh(&l->lock); } @@ -876,7 +875,7 @@ int l2cap_do_connect(struct sock *sk) /* Update source addr of the socket */ bacpy(src, conn->src); - l2cap_chan_add(conn, sk, NULL); + l2cap_chan_add(conn, sk); sk->sk_state = BT_CONNECT; l2cap_sock_set_timer(sk, sk->sk_sndtimeo); @@ -2030,7 +2029,9 @@ static inline int l2cap_connect_req(struct l2cap_conn *conn, struct l2cap_cmd_hd l2cap_pi(sk)->psm = psm; l2cap_pi(sk)->dcid = scid; - __l2cap_chan_add(conn, sk, parent); + bt_accept_enqueue(parent, sk); + + __l2cap_chan_add(conn, sk); dcid = l2cap_pi(sk)->scid; l2cap_sock_set_timer(sk, sk->sk_sndtimeo); -- cgit v0.10.2 From e90165be9a4d6a1e8fa632fcae00a5294abd3981 Mon Sep 17 00:00:00 2001 From: Andrei Emeltchenko Date: Fri, 25 Mar 2011 11:31:41 +0200 Subject: Bluetooth: check L2CAP info_rsp ident and state Information requests/responses are unbound to L2CAP channel. Patch fixes issue arising when two devices connects at the same time to each other. This way we do not process out of the context messages. We are safe dropping info_rsp since info_timer is left running. Signed-off-by: Andrei Emeltchenko Signed-off-by: Gustavo F. Padovan diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index bf09f60..033c83b 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -2461,6 +2461,11 @@ static inline int l2cap_information_rsp(struct l2cap_conn *conn, struct l2cap_cm BT_DBG("type 0x%4.4x result 0x%2.2x", type, result); + /* L2CAP Info req/rsp are unbound to channels, add extra checks */ + if (cmd->ident != conn->info_ident || + conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_DONE) + return 0; + del_timer(&conn->info_timer); if (result != L2CAP_IR_SUCCESS) { -- cgit v0.10.2 From 80a1e1dbf62a08984d4c1bfb5a4bca38c3e1664f Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Mon, 28 Mar 2011 14:07:23 +0300 Subject: Bluetooth: Add local Extended Inquiry Response (EIR) support This patch adds automated creation of the local EIR data based on what 16-bit UUIDs are registered and what the device name is. This should cover the majority use cases, however things like 32/128-bit UUIDs, TX power and Device ID will need to be added later to be on par with what bluetoothd is capable of doing (without the Management interface). Signed-off-by: Johan Hedberg Signed-off-by: Gustavo F. Padovan diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h index b989a8c..6846ec0 100644 --- a/include/net/bluetooth/hci.h +++ b/include/net/bluetooth/hci.h @@ -614,6 +614,14 @@ struct hci_cp_host_buffer_size { #define HCI_OP_WRITE_INQUIRY_MODE 0x0c45 +#define HCI_MAX_EIR_LENGTH 240 + +#define HCI_OP_WRITE_EIR 0x0c52 +struct hci_cp_write_eir { + uint8_t fec; + uint8_t data[HCI_MAX_EIR_LENGTH]; +} __packed; + #define HCI_OP_READ_SSP_MODE 0x0c55 struct hci_rp_read_ssp_mode { __u8 status; diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index 87bff51..3b2f09d 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -102,6 +102,7 @@ struct hci_dev { __u8 dev_type; bdaddr_t bdaddr; __u8 dev_name[HCI_MAX_NAME_LENGTH]; + __u8 eir[HCI_MAX_EIR_LENGTH]; __u8 dev_class[3]; __u8 major_class; __u8 minor_class; diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index a42dc8c..62055c9 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -544,6 +544,150 @@ failed: return err; } +#define EIR_FLAGS 0x01 /* flags */ +#define EIR_UUID16_SOME 0x02 /* 16-bit UUID, more available */ +#define EIR_UUID16_ALL 0x03 /* 16-bit UUID, all listed */ +#define EIR_UUID32_SOME 0x04 /* 32-bit UUID, more available */ +#define EIR_UUID32_ALL 0x05 /* 32-bit UUID, all listed */ +#define EIR_UUID128_SOME 0x06 /* 128-bit UUID, more available */ +#define EIR_UUID128_ALL 0x07 /* 128-bit UUID, all listed */ +#define EIR_NAME_SHORT 0x08 /* shortened local name */ +#define EIR_NAME_COMPLETE 0x09 /* complete local name */ +#define EIR_TX_POWER 0x0A /* transmit power level */ +#define EIR_DEVICE_ID 0x10 /* device ID */ + +#define PNP_INFO_SVCLASS_ID 0x1200 + +static u8 bluetooth_base_uuid[] = { + 0xFB, 0x34, 0x9B, 0x5F, 0x80, 0x00, 0x00, 0x80, + 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +}; + +static u16 get_uuid16(u8 *uuid128) +{ + u32 val; + int i; + + for (i = 0; i < 12; i++) { + if (bluetooth_base_uuid[i] != uuid128[i]) + return 0; + } + + memcpy(&val, &uuid128[12], 4); + + val = le32_to_cpu(val); + if (val > 0xffff) + return 0; + + return (u16) val; +} + +static void create_eir(struct hci_dev *hdev, u8 *data) +{ + u8 *ptr = data; + u16 eir_len = 0; + u16 uuid16_list[HCI_MAX_EIR_LENGTH / sizeof(u16)]; + int i, truncated = 0; + struct list_head *p; + size_t name_len; + + name_len = strlen(hdev->dev_name); + + if (name_len > 0) { + /* EIR Data type */ + if (name_len > 48) { + name_len = 48; + ptr[1] = EIR_NAME_SHORT; + } else + ptr[1] = EIR_NAME_COMPLETE; + + /* EIR Data length */ + ptr[0] = name_len + 1; + + memcpy(ptr + 2, hdev->dev_name, name_len); + + eir_len += (name_len + 2); + ptr += (name_len + 2); + } + + memset(uuid16_list, 0, sizeof(uuid16_list)); + + /* Group all UUID16 types */ + list_for_each(p, &hdev->uuids) { + struct bt_uuid *uuid = list_entry(p, struct bt_uuid, list); + u16 uuid16; + + uuid16 = get_uuid16(uuid->uuid); + if (uuid16 == 0) + return; + + if (uuid16 < 0x1100) + continue; + + if (uuid16 == PNP_INFO_SVCLASS_ID) + continue; + + /* Stop if not enough space to put next UUID */ + if (eir_len + 2 + sizeof(u16) > HCI_MAX_EIR_LENGTH) { + truncated = 1; + break; + } + + /* Check for duplicates */ + for (i = 0; uuid16_list[i] != 0; i++) + if (uuid16_list[i] == uuid16) + break; + + if (uuid16_list[i] == 0) { + uuid16_list[i] = uuid16; + eir_len += sizeof(u16); + } + } + + if (uuid16_list[0] != 0) { + u8 *length = ptr; + + /* EIR Data type */ + ptr[1] = truncated ? EIR_UUID16_SOME : EIR_UUID16_ALL; + + ptr += 2; + eir_len += 2; + + for (i = 0; uuid16_list[i] != 0; i++) { + *ptr++ = (uuid16_list[i] & 0x00ff); + *ptr++ = (uuid16_list[i] & 0xff00) >> 8; + } + + /* EIR Data length */ + *length = (i * sizeof(u16)) + 1; + } +} + +static int update_eir(struct hci_dev *hdev) +{ + struct hci_cp_write_eir cp; + + if (!(hdev->features[6] & LMP_EXT_INQ)) + return 0; + + if (hdev->ssp_mode == 0) + return 0; + + if (test_bit(HCI_SERVICE_CACHE, &hdev->flags)) + return 0; + + memset(&cp, 0, sizeof(cp)); + + create_eir(hdev, cp.data); + + if (memcmp(cp.data, hdev->eir, sizeof(cp.data)) == 0) + return 0; + + memcpy(hdev->eir, cp.data, sizeof(cp.data)); + + return hci_send_cmd(hdev, HCI_OP_WRITE_EIR, sizeof(cp), &cp); +} + static u8 get_service_classes(struct hci_dev *hdev) { struct list_head *p; @@ -612,6 +756,10 @@ static int add_uuid(struct sock *sk, u16 index, unsigned char *data, u16 len) if (err < 0) goto failed; + err = update_eir(hdev); + if (err < 0) + goto failed; + err = cmd_complete(sk, index, MGMT_OP_ADD_UUID, NULL, 0); failed: @@ -668,6 +816,10 @@ static int remove_uuid(struct sock *sk, u16 index, unsigned char *data, u16 len) if (err < 0) goto unlock; + err = update_eir(hdev); + if (err < 0) + goto unlock; + err = cmd_complete(sk, index, MGMT_OP_REMOVE_UUID, NULL, 0); unlock: @@ -737,6 +889,8 @@ static int set_service_cache(struct sock *sk, u16 index, unsigned char *data, } else { clear_bit(HCI_SERVICE_CACHE, &hdev->flags); err = update_class(hdev); + if (err == 0) + err = update_eir(hdev); } if (err == 0) @@ -1822,6 +1976,7 @@ int mgmt_auth_failed(u16 index, bdaddr_t *bdaddr, u8 status) int mgmt_set_local_name_complete(u16 index, u8 *name, u8 status) { struct pending_cmd *cmd; + struct hci_dev *hdev; struct mgmt_cp_set_local_name ev; int err; @@ -1837,6 +1992,14 @@ int mgmt_set_local_name_complete(u16 index, u8 *name, u8 status) goto failed; } + hdev = hci_dev_get(index); + if (hdev) { + hci_dev_lock_bh(hdev); + update_eir(hdev); + hci_dev_unlock_bh(hdev); + hci_dev_put(hdev); + } + err = cmd_complete(cmd->sk, index, MGMT_OP_SET_LOCAL_NAME, &ev, sizeof(ev)); if (err < 0) -- cgit v0.10.2 From 88d377b6c3c28ee54cd4c76bfe6e60f2d9bf6ae1 Mon Sep 17 00:00:00 2001 From: Marc-Antoine Perennou Date: Thu, 24 Mar 2011 14:51:21 -0300 Subject: Bluetooth: add support for Apple MacBook Pro 8,2 Just adding the vendor details makes it work fine. Signed-off-by: Marc-Antoine Perennou Signed-off-by: Gustavo F. Padovan diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c index 8668114..2af2e77 100644 --- a/drivers/bluetooth/btusb.c +++ b/drivers/bluetooth/btusb.c @@ -71,6 +71,9 @@ static struct usb_device_id btusb_table[] = { /* Apple MacBookAir3,1, MacBookAir3,2 */ { USB_DEVICE(0x05ac, 0x821b) }, + /* Apple MacBookPro8,2 */ + { USB_DEVICE(0x05ac, 0x821a) }, + /* AVM BlueFRITZ! USB v2.0 */ { USB_DEVICE(0x057c, 0x3800) }, -- cgit v0.10.2 From 23e9fde2b344c22c5176c7fd37b52c3776ef5aba Mon Sep 17 00:00:00 2001 From: Suraj Sumangala Date: Wed, 9 Mar 2011 14:44:05 +0530 Subject: Bluetooth: Increment unacked_frames count only the first transmit This patch lets 'l2cap_pinfo.unacked_frames' be incremented only the first time a frame is transmitted. Previously it was being incremented for retransmitted packets too resulting the value to cross the transmit window size. Signed-off-by: Suraj Sumangala Signed-off-by: Gustavo F. Padovan diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index c9f9cec..ca27f3a 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -1116,7 +1116,9 @@ int l2cap_ertm_send(struct sock *sk) bt_cb(skb)->tx_seq = pi->next_tx_seq; pi->next_tx_seq = (pi->next_tx_seq + 1) % 64; - pi->unacked_frames++; + if (bt_cb(skb)->retries == 1) + pi->unacked_frames++; + pi->frames_sent++; if (skb_queue_is_last(TX_QUEUE(sk), skb)) -- cgit v0.10.2 From 105721328f0fa53e772592eaca17ee0023f0cc87 Mon Sep 17 00:00:00 2001 From: "Gustavo F. Padovan" Date: Wed, 16 Mar 2011 15:36:29 -0300 Subject: Bluetooth: Fix HCI_RESET command synchronization We can't send new commands before a cmd_complete for the HCI_RESET command shows up. Reported-by: Mikko Vinni Reported-by: Justin P. Mattock Reported-by: Ed Tomlinson Signed-off-by: Gustavo F. Padovan Tested-by: Justin P. Mattock Tested-by: Mikko Vinni Tested-by: Ed Tomlinson diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h index ec6acf2..2c0d309 100644 --- a/include/net/bluetooth/hci.h +++ b/include/net/bluetooth/hci.h @@ -84,6 +84,8 @@ enum { HCI_SERVICE_CACHE, HCI_LINK_KEYS, HCI_DEBUG_KEYS, + + HCI_RESET, }; /* HCI ioctl defines */ diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index b372fb8..92b48e2 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -186,6 +186,7 @@ static void hci_reset_req(struct hci_dev *hdev, unsigned long opt) BT_DBG("%s %ld", hdev->name, opt); /* Reset device */ + set_bit(HCI_RESET, &hdev->flags); hci_send_cmd(hdev, HCI_OP_RESET, 0, NULL); } @@ -213,8 +214,10 @@ static void hci_init_req(struct hci_dev *hdev, unsigned long opt) /* Mandatory initialization */ /* Reset */ - if (!test_bit(HCI_QUIRK_NO_RESET, &hdev->quirks)) + if (!test_bit(HCI_QUIRK_NO_RESET, &hdev->quirks)) { + set_bit(HCI_RESET, &hdev->flags); hci_send_cmd(hdev, HCI_OP_RESET, 0, NULL); + } /* Read Local Supported Features */ hci_send_cmd(hdev, HCI_OP_READ_LOCAL_FEATURES, 0, NULL); @@ -1074,6 +1077,7 @@ static void hci_cmd_timer(unsigned long arg) BT_ERR("%s command tx timeout", hdev->name); atomic_set(&hdev->cmd_cnt, 1); + clear_bit(HCI_RESET, &hdev->flags); tasklet_schedule(&hdev->cmd_task); } diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index 3fbfa50..cebe7588 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -183,6 +183,8 @@ static void hci_cc_reset(struct hci_dev *hdev, struct sk_buff *skb) BT_DBG("%s status 0x%x", hdev->name, status); + clear_bit(HCI_RESET, &hdev->flags); + hci_req_complete(hdev, HCI_OP_RESET, status); } @@ -1847,7 +1849,7 @@ static inline void hci_cmd_status_evt(struct hci_dev *hdev, struct sk_buff *skb) if (ev->opcode != HCI_OP_NOP) del_timer(&hdev->cmd_timer); - if (ev->ncmd) { + if (ev->ncmd && !test_bit(HCI_RESET, &hdev->flags)) { atomic_set(&hdev->cmd_cnt, 1); if (!skb_queue_empty(&hdev->cmd_q)) tasklet_schedule(&hdev->cmd_task); -- cgit v0.10.2 From 8693ac900e230c85d6fff428984a0f983330844d Mon Sep 17 00:00:00 2001 From: Vinicius Costa Gomes Date: Mon, 14 Mar 2011 18:20:33 -0300 Subject: Bluetooth: Fix sending LE data over USB Now that we have support for LE connections, before discarding a frame we must check if there's a LE connection over that transport. Signed-off-by: Vinicius Costa Gomes Acked-by: Ville Tervo Signed-off-by: Gustavo F. Padovan diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c index 2af2e77..762a510 100644 --- a/drivers/bluetooth/btusb.c +++ b/drivers/bluetooth/btusb.c @@ -693,7 +693,8 @@ static int btusb_send_frame(struct sk_buff *skb) break; case HCI_ACLDATA_PKT: - if (!data->bulk_tx_ep || hdev->conn_hash.acl_num < 1) + if (!data->bulk_tx_ep || (hdev->conn_hash.acl_num < 1 && + hdev->conn_hash.le_num < 1)) return -ENODEV; urb = usb_alloc_urb(0, GFP_ATOMIC); -- cgit v0.10.2 From 08ba53824a7fb224085a0ff73eab213cab0197e9 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Wed, 16 Mar 2011 14:29:34 +0200 Subject: Bluetooth: Fix missing hci_dev_lock_bh in user_confirm_reply The code was correctly calling _unlock at the end of the function but there was no actual _lock call anywhere. Signed-off-by: Johan Hedberg Signed-off-by: Gustavo F. Padovan diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 0054c74..4476d8e 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -1230,6 +1230,8 @@ static int user_confirm_reply(struct sock *sk, u16 index, unsigned char *data, if (!hdev) return cmd_status(sk, index, mgmt_op, ENODEV); + hci_dev_lock_bh(hdev); + if (!test_bit(HCI_UP, &hdev->flags)) { err = cmd_status(sk, index, mgmt_op, ENETDOWN); goto failed; -- cgit v0.10.2 From 34bd0273b631742e8d929c80e90cb7782105d8da Mon Sep 17 00:00:00 2001 From: Andrei Emeltchenko Date: Thu, 24 Mar 2011 17:16:08 +0200 Subject: Bluetooth: delete hanging L2CAP channel Sometimes L2CAP connection remains hanging. Make sure that L2CAP channel is deleted. Signed-off-by: Andrei Emeltchenko Signed-off-by: Gustavo F. Padovan diff --git a/net/bluetooth/l2cap_sock.c b/net/bluetooth/l2cap_sock.c index fc85e7a..f77308e 100644 --- a/net/bluetooth/l2cap_sock.c +++ b/net/bluetooth/l2cap_sock.c @@ -923,8 +923,9 @@ void __l2cap_sock_close(struct sock *sk, int reason) rsp.status = cpu_to_le16(L2CAP_CS_NO_INFO); l2cap_send_cmd(conn, l2cap_pi(sk)->ident, L2CAP_CONN_RSP, sizeof(rsp), &rsp); - } else - l2cap_chan_del(sk, reason); + } + + l2cap_chan_del(sk, reason); break; case BT_CONNECT: -- cgit v0.10.2 From 6f5ef998b7b0b1bf1471654bf6176a5419197128 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 24 Mar 2011 20:16:42 +0100 Subject: Bluetooth: Fix warning with hci_cmd_timer After we made debugobjects working again, we got the following: WARNING: at lib/debugobjects.c:262 debug_print_object+0x8e/0xb0() Hardware name: System Product Name ODEBUG: free active (active state 0) object type: timer_list hint: hci_cmd_timer+0x0/0x60 Pid: 2125, comm: dmsetup Tainted: G W 2.6.38-06707-gc62b389 #110375 Call Trace: [] warn_slowpath_common+0x7a/0xb0 [] warn_slowpath_fmt+0x46/0x50 [] debug_print_object+0x8e/0xb0 [] ? hci_cmd_timer+0x0/0x60 [] debug_check_no_obj_freed+0x125/0x230 [] ? check_object+0xb3/0x2b0 [] kfree+0x150/0x190 [] ? bt_host_release+0x16/0x20 [] bt_host_release+0x16/0x20 [] device_release+0x27/0xa0 [] kobject_release+0x4c/0xa0 [] ? kobject_release+0x0/0xa0 [] kref_put+0x36/0x70 [] kobject_put+0x27/0x60 [] put_device+0x17/0x20 [] hci_free_dev+0x29/0x30 [] vhci_release+0x36/0x70 [] fput+0xd6/0x1f0 [] filp_close+0x66/0x90 [] sys_close+0x99/0xf0 [] system_call_fastpath+0x16/0x1b That timer was introduced with commit 6bd32326cda(Bluetooth: Use proper timer for hci command timout) Timer seems to be running when the thing is closed. Removing the timer unconditionally fixes the problem. And yes, it needs to be fixed before the HCI_UP check. Signed-off-by: Thomas Gleixner Tested-by: Ingo Molnar Signed-off-by: Gustavo F. Padovan diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 92b48e2..2216620 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -587,6 +587,9 @@ static int hci_dev_do_close(struct hci_dev *hdev) hci_req_cancel(hdev, ENODEV); hci_req_lock(hdev); + /* Stop timer, it might be running */ + del_timer_sync(&hdev->cmd_timer); + if (!test_and_clear_bit(HCI_UP, &hdev->flags)) { hci_req_unlock(hdev); return 0; @@ -626,7 +629,6 @@ static int hci_dev_do_close(struct hci_dev *hdev) /* Drop last sent command */ if (hdev->sent_cmd) { - del_timer_sync(&hdev->cmd_timer); kfree_skb(hdev->sent_cmd); hdev->sent_cmd = NULL; } -- cgit v0.10.2 From 62f0988ee5280ac03f787e3abd70bd91366e3778 Mon Sep 17 00:00:00 2001 From: David Brown Date: Tue, 29 Mar 2011 11:48:45 -0700 Subject: msm: Remove extraneous ffa device check The qsd8x50 board file contains a few references to machine_is_... macros that are otherwise unused, and contain no machine definition. The recent purge of unused machine definitions breaks the compilation of this target. Since the machine cannot ever be used, just remove the bogus checks. Signed-off-by: David Brown diff --git a/arch/arm/mach-msm/board-qsd8x50.c b/arch/arm/mach-msm/board-qsd8x50.c index 7f56861..6a96911 100644 --- a/arch/arm/mach-msm/board-qsd8x50.c +++ b/arch/arm/mach-msm/board-qsd8x50.c @@ -160,10 +160,7 @@ static struct msm_mmc_platform_data qsd8x50_sdc1_data = { static void __init qsd8x50_init_mmc(void) { - if (machine_is_qsd8x50_ffa() || machine_is_qsd8x50a_ffa()) - vreg_mmc = vreg_get(NULL, "gp6"); - else - vreg_mmc = vreg_get(NULL, "gp5"); + vreg_mmc = vreg_get(NULL, "gp5"); if (IS_ERR(vreg_mmc)) { pr_err("vreg get for vreg_mmc failed (%ld)\n", -- cgit v0.10.2 From 893b66c39da812e7dd0d7b32aa0633e5d90d950c Mon Sep 17 00:00:00 2001 From: David Brown Date: Wed, 30 Mar 2011 11:26:57 -0700 Subject: msm: timer: fix missing return value Change af90f10d38 "ARM: 6759/1: smp: Select local timers vs broadcast timer support runtime" missed a return statement, causing a compile warning: arch/arm/mach-msm/timer.c:272: warning: 'return' with no value, in function returning non-void Trivially return 0 for success when running on cpu 0 (to match the comment and previous behavior). Signed-off-by: David Brown diff --git a/arch/arm/mach-msm/timer.c b/arch/arm/mach-msm/timer.c index 56f920c..38b95e9 100644 --- a/arch/arm/mach-msm/timer.c +++ b/arch/arm/mach-msm/timer.c @@ -269,7 +269,7 @@ int __cpuinit local_timer_setup(struct clock_event_device *evt) /* Use existing clock_event for cpu 0 */ if (!smp_processor_id()) - return; + return 0; writel(DGT_CLK_CTL_DIV_4, MSM_TMR_BASE + DGT_CLK_CTL); -- cgit v0.10.2 From 96b8e1a0e96bd30ffb07e739b29b8c4c5759b93f Mon Sep 17 00:00:00 2001 From: Dmitry Kravkov Date: Thu, 31 Mar 2011 17:03:36 -0700 Subject: bnx2x: Update firmware to 6.2.9 To fix bugs when running offloaded FCoE/iSCSI traffic in multiple Class of Service environments. In some scenarios, traffic could stop on certain rings and eventually all traffic would stop. Signed-off-by: Dmitry Kravkov Signed-off-by: Michael Chan Signed-off-by: David S. Miller diff --git a/drivers/net/bnx2x/bnx2x_hsi.h b/drivers/net/bnx2x/bnx2x_hsi.h index be503cc..d9d0184 100644 --- a/drivers/net/bnx2x/bnx2x_hsi.h +++ b/drivers/net/bnx2x/bnx2x_hsi.h @@ -1929,7 +1929,7 @@ struct host_func_stats { #define BCM_5710_FW_MAJOR_VERSION 6 #define BCM_5710_FW_MINOR_VERSION 2 -#define BCM_5710_FW_REVISION_VERSION 5 +#define BCM_5710_FW_REVISION_VERSION 9 #define BCM_5710_FW_ENGINEERING_VERSION 0 #define BCM_5710_FW_COMPILE_FLAGS 1 diff --git a/firmware/Makefile b/firmware/Makefile index 0384afa..0d15a3d 100644 --- a/firmware/Makefile +++ b/firmware/Makefile @@ -32,9 +32,9 @@ fw-shipped-$(CONFIG_ADAPTEC_STARFIRE) += adaptec/starfire_rx.bin \ adaptec/starfire_tx.bin fw-shipped-$(CONFIG_ATARI_DSP56K) += dsp56k/bootstrap.bin fw-shipped-$(CONFIG_ATM_AMBASSADOR) += atmsar11.fw -fw-shipped-$(CONFIG_BNX2X) += bnx2x/bnx2x-e1-6.2.5.0.fw \ - bnx2x/bnx2x-e1h-6.2.5.0.fw \ - bnx2x/bnx2x-e2-6.2.5.0.fw +fw-shipped-$(CONFIG_BNX2X) += bnx2x/bnx2x-e1-6.2.9.0.fw \ + bnx2x/bnx2x-e1h-6.2.9.0.fw \ + bnx2x/bnx2x-e2-6.2.9.0.fw fw-shipped-$(CONFIG_BNX2) += bnx2/bnx2-mips-09-6.2.1a.fw \ bnx2/bnx2-rv2p-09-6.0.17.fw \ bnx2/bnx2-rv2p-09ax-6.0.17.fw \ diff --git a/firmware/WHENCE b/firmware/WHENCE index 76404f9..182ecb6 100644 --- a/firmware/WHENCE +++ b/firmware/WHENCE @@ -679,14 +679,15 @@ Found in hex form in kernel source. Driver: bnx2x: Broadcom Everest -File: bnx2x/bnx2x-e1-5.2.13.0.fw -File: bnx2x/bnx2x-e1h-5.2.13.0.fw +File: bnx2x/bnx2x-e1-6.2.9.0.fw +File: bnx2x/bnx2x-e1h-6.2.9.0.fw +File: bnx2x/bnx2x-e2-6.2.9.0.fw License: - Copyright (c) 2007-2010 Broadcom Corporation + Copyright (c) 2007-2011 Broadcom Corporation This file contains firmware data derived from proprietary unpublished - source code, Copyright (c) 2007-2009 Broadcom Corporation. + source code, Copyright (c) 2007-2011 Broadcom Corporation. Permission is hereby granted for the distribution of this firmware data in hexadecimal or equivalent format, provided this copyright notice is diff --git a/firmware/bnx2x/bnx2x-e1-6.2.5.0.fw.ihex b/firmware/bnx2x/bnx2x-e1-6.2.5.0.fw.ihex deleted file mode 100644 index 1b53582..0000000 --- a/firmware/bnx2x/bnx2x-e1-6.2.5.0.fw.ihex +++ /dev/null @@ -1,9483 +0,0 @@ -:1000000000003BB0000000680000070C00003C202E -:1000100000001AF8000043300000007C00005E3051 -:1000200000007A2C00005EB0000000B00000D8E0B4 -:10003000000080200000D99800000088000159C00D -:100040000000398800015A5000000090000193E040 -:100050000000ABFC0001947800000FFC0002407827 -:100060000000000400025078020400480000000F65 -:100070000204005400000045020400580000000083 -:100080000204005C0000000602040070000000048E -:1000900002040078000000000204007C1217000037 -:1000A00002040080221700000204008432170000BE -:1000B00006040088000000050204009C12150000E0 -:1000C000020400A022150000020400A43215000062 -:1000D000060400A800000004020400B8021000009A -:1000E000020400BC00100000020400C01010000058 -:1000F000020400C420100000020400C830100000F8 -:10010000060400CC00000004020400DC0010000023 -:10011000020400E012140000020400E422140000B3 -:10012000020400E832140000060400EC00000004A1 -:100130000104012400000000010401280000000067 -:100140000104012C00000000010401300000000047 -:1001500002040004000000FF02040008000000FF89 -:100160000204000C000000FF02040010000000FF69 -:1001700002040014000000FF02040018000000FF49 -:100180000204001C000000FF02040020000000FF29 -:10019000020400240000003E0204002800000000C9 -:1001A0000204002C0000003F020400300000003F69 -:1001B000020400340000003F020400380000000088 -:1001C0000204003C0000003F020400400000003F29 -:1001D000020400440000003F020420080000021155 -:1001E0000204200C0000020002042010000002049F -:1001F00002042014000002190204201C0000FFFF6A -:10020000020420200000FFFF020420240000FFFF62 -:10021000020420280000FFFF0604203800000080B0 -:100220000204223807FFFFFF0204223C0000003FC7 -:100230000204224007FFFFFF020422440000000FD7 -:1002400001042248000000000104224C00000000CC -:1002500001042250000000000104225400000000AC -:1002600001042258000000000104225C000000008C -:10027000010422600000000001042264000000006C -:1002800001042268000000000104226C000000004C -:10029000010422700000000001042274000000002C -:1002A00001042278000000000104227C000000000C -:1002B000020424BC000000010C042000000003E83C -:1002C0000A042000000000010B0420000000000AC6 -:1002D0000605400000000D0002050044000000205B -:1002E00002050048000000320205009002150020BF -:1002F000020500940215002002050098000000305D -:100300000205009C08100000020500A00000003358 -:10031000020500A400000030020500A80000003122 -:10032000020500AC00000002020500B0000000055C -:10033000020500B400000006020500B8000000023B -:10034000020500BC00000002020500C00000000021 -:10035000020500C400000005020500C800000002FC -:10036000020500CC00000002020500D000000002DF -:10037000020500D400000001020501140000000184 -:100380000205011C0000000102050120000000021E -:1003900002050204000000010205020C00000040FA -:1003A00002050210000000400205021C00000020AF -:1003B00002050220000000130205022400000020B4 -:1003C000060502400000000A04050280002000002B -:1003D000020500500000000702050054000000075D -:1003E00002050058000000000205005C0000000843 -:1003F0000605006000000004020500D800000006A9 -:10040000020500E00000000D020500E40000002DE0 -:10041000020500E800000000020500EC00000020DA -:10042000020500F000000000020500F400000020BA -:10043000020500F800000000020500FC000000209A -:100440000205000400000001020500080000000190 -:100450000205000C00000001020500100000000170 -:100460000205001400000001020500180000000150 -:100470000205001C00000001020500200000000130 -:100480000205002400000001020500280000000110 -:100490000205002C000000010205003000000001F0 -:1004A00002050034000000010205003800000001D0 -:1004B0000205003C000000010205004000000001B0 -:1004C0000406100002000020020600DC000000010B -:1004D000010600D80000000004060200000302200C -:1004E000020600DC0000000002060068000000B800 -:1004F0000206007800000114010600B800000000A8 -:10050000010600C8000000000206006C000000B8F0 -:100510000206007C00000114010600BC000000007F -:10052000010600CC0000000007180400007B00005A -:100530000818076000140223071C00002A040000AA -:10054000071C800032110A82071D00001E0C1707CD -:10055000081D4550575602250118000000000000F4 -:10056000011800040000000001180008000000004D -:100570000118000C0000000001180010000000002D -:100580000118001400000000021800200000000103 -:1005900002180024000000020218002800000003D6 -:1005A0000218002C000000000218003000000004B7 -:1005B000021800340000000102180038000000009A -:1005C0000218003C00000001021800400000000476 -:1005D000021800440000000002180048000000015A -:1005E0000218004C00000003021800500000000038 -:1005F0000218005400000001021800580000000416 -:100600000218005C000000000218006000000001F9 -:1006100002180064000000030218006800000000D7 -:100620000218006C000000010218007000000004B5 -:100630000218007400000000021800780000000496 -:100640000218007C00000003061800800000000271 -:10065000021800A400003FFF021800A8000003FFDA -:1006600002180224000000000218023400000000FA -:100670000218024C00000000021802E4000000FF13 -:100680000618100000000400021B8BC000000001CF -:10069000021B800000000034021B80400000001894 -:1006A000021B80800000000C021B80C000000020A4 -:1006B0000C1B83000007A1200A1B830000000138E7 -:1006C0000B1B8300000013880A1B834000000000FE -:1006D0000C1B8340000001F40B1B8340000000054D -:1006E000021B83800007A120021B83C0000001F4CD -:1006F000061A100000000273041A19CC0001022728 -:10070000061A2008000000C8061A20000000000297 -:10071000041A499800040228061A2E280000000234 -:10072000061A2E2000000002061A0800000000022F -:10073000061A080800000004061A08180000000243 -:10074000041A08B00002022C061A2FD0000000067E -:10075000041A2FE80002022E041A2FC000040230EF -:10076000041A300000010234061A300400000003AD -:10077000041A301000010235061A3014000000037C -:10078000041A302000010236061A3024000000034B -:10079000041A303000010237061A3034000000031A -:1007A000041A304000010238061A304400000003E9 -:1007B000041A305000010239061A305400000003B8 -:1007C000041A30600001023A061A30640000000387 -:1007D000041A30700001023B061A30740000000356 -:1007E000041A30800001023C061A30840000000325 -:1007F000041A30900001023D061A309400000003F4 -:10080000041A30A00001023E061A30A400000003C2 -:10081000041A30B00001023F061A30B40000000391 -:10082000041A30C000010240061A30C40000000360 -:10083000041A30D000010241061A30D4000000032F -:10084000041A30E000010242061A30E400000003FE -:10085000041A30F000010243061A30F400000003CD -:10086000041A310000010244061A3104000000039A -:10087000041A311000010245061A31140000000369 -:10088000041A312000010246061A31240000000338 -:10089000041A313000010247061A31340000000307 -:1008A000041A314000010248061A314400000003D6 -:1008B000041A315000010249061A315400000003A5 -:1008C000041A31600001024A061A31640000000374 -:1008D000041A31700001024B061A31740000000343 -:1008E000041A31800001024C061A31840000000312 -:1008F000041A31900001024D061A319400000003E1 -:10090000041A31A00001024E061A31A400000003AF -:10091000041A31B00001024F061A31B4000000037E -:10092000041A31C000010250061A31C4000000034D -:10093000041A31D000010251061A31D4000000031C -:10094000041A31E000010252061A31E400000003EB -:10095000041A31F000010253061A31F400000003BA -:10096000041A320000010254061A32040000000387 -:10097000041A321000010255061A32140000000356 -:10098000041A322000010256061A32240000000325 -:10099000041A323000010257061A323400000003F4 -:1009A000041A324000010258061A324400000003C3 -:1009B000041A325000010259061A32540000000392 -:1009C000041A32600001025A061A32640000000361 -:1009D000041A32700001025B061A32740000000330 -:1009E000041A32800001025C061A328400000003FF -:1009F000041A32900001025D061A329400000003CE -:100A0000041A32A00001025E061A32A4000000039C -:100A1000041A32B00001025F061A32B4000000036B -:100A2000041A32C000010260061A32C4000000033A -:100A3000041A32D000010261061A32D40000000309 -:100A4000041A32E000010262061A32E400000003D8 -:100A5000041A32F000010263061A32F400000003A7 -:100A6000041A330000010264061A33040000000374 -:100A7000041A331000010265061A33140000000343 -:100A8000041A332000010266061A33240000000312 -:100A9000041A333000010267061A333400000003E1 -:100AA000041A334000010268061A334400000003B0 -:100AB000041A335000010269061A3354000000037F -:100AC000041A33600001026A061A3364000000034E -:100AD000041A33700001026B061A3374000000031D -:100AE000041A33800001026C061A338400000003EC -:100AF000041A33900001026D061A339400000003BB -:100B0000041A33A00001026E061A33A40000000389 -:100B1000041A33B00001026F061A33B40000000358 -:100B2000041A33C000010270061A33C40000000327 -:100B3000041A33D000010271061A33D400000003F6 -:100B4000041A33E000010272061A33E400000003C5 -:100B5000041A33F000010273061A33F40000000394 -:100B6000041A340000010274061A34040000000361 -:100B7000041A341000010275061A34140000000330 -:100B8000041A342000010276061A342400000003FF -:100B9000041A343000010277061A343400000003CE -:100BA000041A344000010278061A3444000000039D -:100BB000041A345000010279061A3454000000036C -:100BC000041A34600001027A061A3464000000033B -:100BD000041A34700001027B061A3474000000030A -:100BE000041A34800001027C061A348400000003D9 -:100BF000041A34900001027D061A349400000003A8 -:100C0000041A34A00001027E061A34A40000000376 -:100C1000041A34B00001027F061A34B40000000345 -:100C2000041A34C000010280061A34C40000000314 -:100C3000041A34D000010281061A34D400000003E3 -:100C4000041A34E000010282061A34E400000003B2 -:100C5000041A34F000010283061A34F40000000381 -:100C6000041A350000010284061A3504000000034E -:100C7000041A351000010285061A3514000000031D -:100C8000041A352000010286061A352400000003EC -:100C9000041A353000010287061A353400000003BB -:100CA000041A354000010288061A3544000000038A -:100CB000041A355000010289061A35540000000359 -:100CC000041A35600001028A061A35640000000328 -:100CD000041A35700001028B061A357400000003F7 -:100CE000041A35800001028C061A358400000003C6 -:100CF000041A35900001028D061A35940000000395 -:100D0000041A35A00001028E061A35A40000000363 -:100D1000041A35B00001028F061A35B40000000332 -:100D2000041A35C000010290061A35C40000000301 -:100D3000041A35D000010291061A35D400000003D0 -:100D4000041A35E000010292061A35E4000000039F -:100D5000041A35F000010293061A35F4000000036E -:100D6000041A360000010294061A3604000000033B -:100D7000041A361000010295061A3614000000030A -:100D8000041A362000010296061A362400000003D9 -:100D9000041A363000010297061A363400000003A8 -:100DA000041A364000010298061A36440000000377 -:100DB000041A365000010299061A36540000000346 -:100DC000041A36600001029A061A36640000000315 -:100DD000041A36700001029B061A367400000003E4 -:100DE000041A36800001029C061A368400000003B3 -:100DF000041A36900001029D061A36940000000382 -:100E0000041A36A00001029E061A36A40000000350 -:100E1000041A36B00001029F061A36B4000000031F -:100E2000041A36C0000102A0061A36C400000003EE -:100E3000041A36D0000102A1061A36D400000003BD -:100E4000041A36E0000102A2061A36E4000000038C -:100E5000041A36F0000102A3061A36F4000000035B -:100E6000041A3700000102A4061A37040000000328 -:100E7000041A3710000102A5061A371400000003F7 -:100E8000041A3720000102A6061A372400000003C6 -:100E9000041A3730000102A7061A37340000000395 -:100EA000041A3740000102A8061A37440000000364 -:100EB000041A3750000102A9061A37540000000333 -:100EC000041A3760000102AA061A37640000000302 -:100ED000041A3770000102AB061A377400000003D1 -:100EE000041A3780000102AC061A378400000003A0 -:100EF000041A3790000102AD061A3794000000036F -:100F0000041A37A0000102AE061A37A4000000033D -:100F1000041A37B0000102AF061A37B4000000030C -:100F2000041A37C0000102B0061A37C400000003DB -:100F3000041A37D0000102B1061A37D400000003AA -:100F4000041A37E0000102B2061A37E40000000379 -:100F5000041A37F0000102B3061A37F40000000348 -:100F6000041A3800000102B4061A38040000000315 -:100F7000041A3810000102B5061A381400000003E4 -:100F8000041A3820000102B6061A382400000003B3 -:100F9000041A3830000102B7061A38340000000382 -:100FA000041A3840000102B8061A38440000000351 -:100FB000041A3850000102B9061A38540000000320 -:100FC000041A3860000102BA061A386400000003EF -:100FD000041A3870000102BB061A387400000003BE -:100FE000041A3880000102BC061A3884000000038D -:100FF000041A3890000102BD061A3894000000035C -:10100000041A38A0000102BE061A38A4000000032A -:10101000041A38B0000102BF061A38B400000003F9 -:10102000041A38C0000102C0061A38C400000003C8 -:10103000041A38D0000102C1061A38D40000000397 -:10104000041A38E0000102C2061A38E40000000366 -:10105000041A38F0000102C3061A38F40000000335 -:10106000041A3900000102C4061A39040000000302 -:10107000041A3910000102C5061A391400000003D1 -:10108000041A3920000102C6061A392400000003A0 -:10109000041A3930000102C7061A3934000000036F -:1010A000041A3940000102C8061A3944000000033E -:1010B000041A3950000102C9061A3954000000030D -:1010C000041A3960000102CA061A396400000003DC -:1010D000041A3970000102CB061A397400000003AB -:1010E000041A3980000102CC061A3984000000037A -:1010F000041A3990000102CD061A39940000000349 -:10110000041A39A0000102CE061A39A40000000317 -:10111000041A39B0000102CF061A39B400000003E6 -:10112000041A39C0000102D0061A39C400000003B5 -:10113000041A39D0000102D1061A39D40000000384 -:10114000041A39E0000102D2061A39E40000000353 -:10115000041A39F0000102D3061A39F40000000322 -:10116000041A3A00000102D4061A3A0400000003EF -:10117000041A3A10000102D5061A3A1400000003BE -:10118000041A3A20000102D6061A3A24000000038D -:10119000041A3A30000102D7061A3A34000000035C -:1011A000041A3A40000102D8061A3A44000000032B -:1011B000041A3A50000102D9061A3A5400000003FA -:1011C000041A3A60000102DA061A3A6400000003C9 -:1011D000041A3A70000102DB061A3A740000000398 -:1011E000041A3A80000102DC061A3A840000000367 -:1011F000041A3A90000102DD061A3A940000000336 -:10120000041A3AA0000102DE061A3AA40000000304 -:10121000041A3AB0000102DF061A3AB400000003D3 -:10122000041A3AC0000102E0061A3AC400000003A2 -:10123000041A3AD0000102E1061A3AD40000000371 -:10124000041A3AE0000102E2061A3AE40000000340 -:10125000041A3AF0000102E3061A3AF4000000030F -:10126000041A3B00000102E4061A3B0400000003DC -:10127000041A3B10000102E5061A3B1400000003AB -:10128000041A3B20000102E6061A3B24000000037A -:10129000041A3B30000102E7061A3B340000000349 -:1012A000041A3B40000102E8061A3B440000000318 -:1012B000041A3B50000102E9061A3B5400000003E7 -:1012C000041A3B60000102EA061A3B6400000003B6 -:1012D000041A3B70000102EB061A3B740000000385 -:1012E000041A3B80000102EC061A3B840000000354 -:1012F000041A3B90000102ED061A3B940000000323 -:10130000041A3BA0000102EE061A3BA400000003F1 -:10131000041A3BB0000102EF061A3BB400000003C0 -:10132000041A3BC0000102F0061A3BC4000000038F -:10133000041A3BD0000102F1061A3BD4000000035E -:10134000041A3BE0000102F2061A3BE4000000032D -:10135000041A3BF0000102F3061A3BF400000003FC -:10136000041A3C00000102F4061A3C0400000003C9 -:10137000041A3C10000102F5061A3C140000000398 -:10138000041A3C20000102F6061A3C240000000367 -:10139000041A3C30000102F7061A3C340000000336 -:1013A000041A3C40000102F8061A3C440000000305 -:1013B000041A3C50000102F9061A3C5400000003D4 -:1013C000041A3C60000102FA061A3C6400000003A3 -:1013D000041A3C70000102FB061A3C740000000372 -:1013E000041A3C80000102FC061A3C840000000341 -:1013F000041A3C90000102FD061A3C940000000310 -:10140000041A3CA0000102FE061A3CA400000003DE -:10141000041A3CB0000102FF061A3CB400000003AD -:10142000041A3CC000010300061A3CC4000000037B -:10143000041A3CD000010301061A3CD4000000034A -:10144000041A3CE000010302061A3CE40000000319 -:10145000041A3CF000010303061A3CF400000003E8 -:10146000041A3D0000010304061A3D0400000003B5 -:10147000041A3D1000010305061A3D140000000384 -:10148000041A3D2000010306061A3D240000000353 -:10149000041A3D3000010307061A3D340000000322 -:1014A000041A3D4000010308061A3D4400000003F1 -:1014B000041A3D5000010309061A3D5400000003C0 -:1014C000041A3D600001030A061A3D64000000038F -:1014D000041A3D700001030B061A3D74000000035E -:1014E000041A3D800001030C061A3D84000000032D -:1014F000041A3D900001030D061A3D9400000003FC -:10150000041A3DA00001030E061A3DA400000003CA -:10151000041A3DB00001030F061A3DB40000000399 -:10152000041A3DC000010310061A3DC40000000368 -:10153000041A3DD000010311061A3DD40000000337 -:10154000041A3DE000010312061A3DE40000000306 -:10155000041A3DF000010313061A3DF400000003D5 -:10156000041A3E0000010314061A3E0400000003A2 -:10157000041A3E1000010315061A3E140000000371 -:10158000041A3E2000010316061A3E240000000340 -:10159000041A3E3000010317061A3E34000000030F -:1015A000041A3E4000010318061A3E4400000003DE -:1015B000041A3E5000010319061A3E5400000003AD -:1015C000041A3E600001031A061A3E64000000037C -:1015D000041A3E700001031B061A3E74000000034B -:1015E000041A3E800001031C061A3E84000000031A -:1015F000041A3E900001031D061A3E9400000003E9 -:10160000041A3EA00001031E061A3EA400000003B7 -:10161000041A3EB00001031F061A3EB40000000386 -:10162000041A3EC000010320061A3EC40000000355 -:10163000041A3ED000010321061A3ED40000000324 -:10164000041A3EE000010322061A3EE400000003F3 -:10165000041A3EF000010323061A3EF400000003C2 -:10166000041A3F0000010324061A3F04000000038F -:10167000041A3F1000010325061A3F14000000035E -:10168000041A3F2000010326061A3F24000000032D -:10169000041A3F3000010327061A3F3400000003FC -:1016A000041A3F4000010328061A3F4400000003CB -:1016B000041A3F5000010329061A3F54000000039A -:1016C000041A3F600001032A061A3F640000000369 -:1016D000041A3F700001032B061A3F740000000338 -:1016E000041A3F800001032C061A3F840000000307 -:1016F000041A3F900001032D061A3F9400000003D6 -:10170000041A3FA00001032E061A3FA400000003A4 -:10171000041A3FB00001032F061A3FB40000000373 -:10172000041A3FC000010330061A3FC40000000342 -:10173000041A3FD000010331061A3FD40000000311 -:10174000041A3FE000010332061A3FE400000007DC -:10175000041A4CB000080333061A400000000124AC -:10176000021A492000000000061A2500000000109F -:10177000061A258000000012061A09C00000004861 -:10178000061A080000000002061A082000000012D5 -:10179000041A2FB00002033B041A4CF00002033D70 -:1017A000061A500000000004061A449000000124AC -:1017B000021A492400000000061A2540000000100B -:1017C000061A25C800000012061A0AE000000048A8 -:1017D000061A081000000002061A0868000000122D -:1017E000041A2FB80002033F041A4CF80002034108 -:1017F000061A5010000000040200A468000AFFDC72 -:101800000200A280000000010200A294071D29111D -:101810000200A298000000000200A29C009C042488 -:101820000200A2A0000000000200A2A40000020921 -:101830000200A4FCFF000000020100B4000000014F -:10184000020100B800000001020100DC00000001FC -:10185000020101000000000102010104000000017A -:101860000201007C0030000002010084000000281A -:101870000201008C000000000201013000000004A1 -:101880000201025C000000010201032800000000C8 -:101890000201055400000030020100C400000001F4 -:1018A000020100CC00000001020100F8000000016C -:1018B000020100F000000001020100800030000081 -:1018C00002010088000000280201009000000000D2 -:1018D0000201013400000004020102DC00000001EA -:1018E0000201032C0000000002010564000000302A -:1018F000020100C800000001020100D00000000148 -:10190000020100FC00000001020100F400000001DF -:10191000020C100000000028020C200800000A1130 -:10192000020C200C00000A00020C201000000A0427 -:10193000020C201C0000FFFF020C20200000FFFF13 -:10194000020C20240000FFFF020C20280000FFFFF3 -:10195000020C203800000020020C203C0000002176 -:10196000020C204000000022020C20440000002352 -:10197000020C204800000024020C204C000000252E -:10198000020C205000000026020C2054000000270A -:10199000020C205800000028020C205C00000029E6 -:1019A000020C20600000002A020C20640000002BC2 -:1019B000020C20680000002C020C206C0000002D9E -:1019C000020C20700000002E020C20740000002F7A -:1019D000020C207800000010060C207C0000004F54 -:1019E000020C21B800000001020C21BC0000000123 -:1019F000020C21C000000001020C21C40000000103 -:101A0000020C21C800000001020C21CC00000001E2 -:101A1000020C21D000000001020C21D400000001C2 -:101A2000020C21D800000001020C21DC00000001A2 -:101A3000020C21E000000001020C21E40000000182 -:101A4000020C21E800000001020C21EC0000000162 -:101A5000020C21F000000001020C21F40000000142 -:101A6000020C21F800000001060C21FC0000000F10 -:101A7000020C223807FFFFFF020C223C0000003F4F -:101A8000020C224007FFFFFF020C22440000000F5F -:101A9000010C224800000000010C224C0000000054 -:101AA000010C225000000000010C22540000000034 -:101AB000010C225800000000010C225C0000000014 -:101AC000010C226000000000010C226400000000F4 -:101AD000010C226800000000010C226C00000000D4 -:101AE000010C227000000000010C227400000000B4 -:101AF000010C227800000000010C227C0000000094 -:101B0000020C24BC000000010C0C2000000003E8C3 -:101B10000A0C2000000000010B0C20000000000A4D -:101B2000020C400800000562020C400C0000055148 -:101B3000020C401000000555020C40140000057214 -:101B4000020C401C0000FFFF020C40200000FFFFC1 -:101B5000020C40240000FFFF020C40280000FFFFA1 -:101B6000020C403800000046020C403C0000000C13 -:101B7000060C40400000005E020C41B8000000016D -:101B8000060C41BC0000001F020C423807FFFFFF9B -:101B9000020C423C0000003F020C424007FFFFFFE6 -:101BA000020C42440000000F010C424800000000FB -:101BB000010C424C00000000010C425000000000EB -:101BC000010C425400000000010C425800000000CB -:101BD000010C425C00000000010C426000000000AB -:101BE000010C426400000000010C4268000000008B -:101BF000010C426C00000000010C4270000000006B -:101C0000010C427400000000010C4278000000004A -:101C1000010C427C00000000010C4280000000002A -:101C2000020C44C0000000010C0C4000000003E85E -:101C30000A0C4000000000010B0C40000000000AEC -:101C4000060D400000000A00020D004400000032B2 -:101C5000020D008C02150020020D009002150020DC -:101C6000020D009408100000020D009800000033DF -:101C7000020D009C00000002020D00A00000000008 -:101C8000020D00A400000005020D00A800000005E0 -:101C9000060D00AC00000002020D00B400000002BE -:101CA000020D00B800000003020D00BC000000029D -:101CB000020D00C000000001020D00C8000000027B -:101CC000020D00CC00000002020D015C00000001CA -:101CD000020D016400000001020D01680000000215 -:101CE000020D020400000001020D020C00000020A1 -:101CF000020D021000000040020D0214000000401E -:101D0000020D022000000003020D02240000001852 -:101D1000060D028000000012040D030000180343AA -:101D2000060D03600000000C020D004C00000001D5 -:101D3000020D005000000002020D005400000000DF -:101D4000020D005800000008060D005C00000004B1 -:101D5000020D00C400000004020D0114000000097F -:101D6000020D011800000029020D011C0000000AEC -:101D7000020D01200000002A020D012400000000D5 -:101D8000020D012800000020020D012C00000000BF -:101D9000020D013000000020020D0134000000009F -:101DA000020D013800000020020D013C000000007F -:101DB000020D014000000020020D0144000000005F -:101DC000020D014800000020020D00040000000187 -:101DD000020D000800000001020D000C00000001CF -:101DE000020D001000000001020D001400000001AF -:101DF000020D001800000001020D001C000000018F -:101E0000020D002000000001020D0024000000016E -:101E1000020D002800000001020D002C000000014E -:101E2000020D003000000001020D0034000000012E -:101E3000020D003800000001020D003C000000010E -:101E4000060E200000000800020E004C00000032C8 -:101E5000020E009402150020020E009802150020C8 -:101E6000020E009C00000030020E00A008100000CE -:101E7000020E00A400000033020E00A80000003093 -:101E8000020E00AC00000031020E00B000000002A3 -:101E9000020E00B400000004020E00B800000000B2 -:101EA000020E00BC00000002020E00C00000000292 -:101EB000020E00C400000000020E00C80000000274 -:101EC000020E00CC00000007020E00D0000000024D -:101ED000020E00D400000002020E00D80000000133 -:101EE000020E014400000001020E014C000000013E -:101EF000020E015000000002020E02040000000168 -:101F0000020E020C00000040020E02100000004011 -:101F1000020E021C00000004020E0220000000203D -:101F2000020E02240000000E020E02280000001B18 -:101F3000060E030000000012040E0280001B035B6B -:101F4000060E02EC00000005020E00540000000C1A -:101F5000020E00580000000C020E005C00000000A1 -:101F6000020E006000000010060E00640000000475 -:101F7000020E00DC00000003020E01100000000F42 -:101F8000020E01140000002F020E011800000000D4 -:101F9000020E011C00000020020E000400000001DF -:101FA000020E000800000001020E000C00000001FB -:101FB000020E001000000001020E001400000001DB -:101FC000020E001800000001020E001C00000001BB -:101FD000020E002000000001020E0024000000019B -:101FE000020E002800000001020E002C000000017B -:101FF000020E003000000001020E0034000000015B -:10200000020E003800000001020E003C000000013A -:10201000020E004000000001020E0044000000011A -:102020000730040000AF0000083007680013037693 -:1020300007340000331C00000734800032780CC8DD -:10204000073500001A801967083539B058CA037877 -:10205000013000000000000001300004000000001A -:1020600001300008000000000130000C00000000FA -:1020700001300010000000000130001400000000DA -:1020800002300020000000010230002400000002A5 -:1020900002300028000000030230002C0000000085 -:1020A0000230003000000004023000340000000163 -:1020B00002300038000000000230003C0000000147 -:1020C0000230004000000004023000440000000024 -:1020D00002300048000000010230004C0000000304 -:1020E00002300050000000000230005400000001E7 -:1020F00002300058000000040230005C00000000C4 -:1021000002300060000000010230006400000003A3 -:1021100002300068000000000230006C0000000186 -:102120000230007000000004023000740000000063 -:1021300002300078000000040230007C0000000340 -:102140000630008000000002023000A400003FFFC3 -:10215000023000A8000003FF02300224000000004B -:1021600002300234000000000230024C0000000087 -:10217000023002E40000FFFF0630200000000800EB -:1021800002338BC000000001023380000000001AFF -:10219000023380400000004E0233808000000010B7 -:1021A000023380C0000000200C3383000007A12010 -:1021B0000A338300000001380B33830000001388CA -:1021C0000A338340000000000C338340000001F418 -:1021D0000B33834000000005023383800007A120F9 -:1021E000023383C0000001F406322A88000000C2D6 -:1021F00006322008000000C806322000000000025D -:10220000063223E80000004004322E580004037A0E -:10221000063250A000000004063250B80000000250 -:102220000632508000000006043250980002037EFF -:10223000063250000000002006323000000004008A -:1022400006321C0000000004043218300002038033 -:10225000063224E8000000B402322DB00000000075 -:1022600006324000000000B40632300000000020BA -:10227000063231000000002006323200000000204B -:102280000632330000000020063234000000002037 -:102290000632350000000020063236000000002023 -:1022A000063237000000002006323800000000200F -:1022B000063239000000002006323A0000000020FB -:1022C00006323B000000002006323C0000000020E7 -:1022D00006323D000000002006323E0000000020D3 -:1022E00006323F000000002006321C1000000002F1 -:1022F000063245A000000024063227B8000000B4D2 -:1023000002322DB400000000063242D0000000B4BA -:1023100006323080000000200632318000000020AC -:102320000632328000000020063233800000002098 -:102330000632348000000020063235800000002084 -:102340000632368000000020063237800000002070 -:10235000063238800000002006323980000000205C -:1023600006323A800000002006323B800000002048 -:1023700006323C800000002006323D800000002034 -:1023800006323E800000002006323F800000002020 -:1023900006321C20000000020632463000000024F5 -:1023A0000720040000870000082007800010038237 -:1023B000072400003165000007248000081D0C5A26 -:1023C00008248EB06C9003840120000000000000FF -:1023D00001200004000000000120000800000000AF -:1023E0000120000C0000000001200010000000008F -:1023F0000120001400000000022000200000000165 -:102400000220002400000002022000280000000337 -:102410000220002C00000000022000300000000418 -:1024200002200034000000010220003800000000FB -:102430000220003C000000010220004000000004D7 -:1024400002200044000000000220004800000001BB -:102450000220004C00000003022000500000000099 -:102460000220005400000001022000580000000477 -:102470000220005C0000000002200060000000015B -:102480000220006400000003022000680000000039 -:102490000220006C00000001022000700000000417 -:1024A00002200074000000000220007800000004F8 -:1024B0000220007C000000030620008000000002D3 -:1024C000022000A400003FFF022000A8000003FF3C -:1024D000022002240000000002200234000000005C -:1024E0000220024C00000000022002E40000FFFF76 -:1024F000062020000000080002238BC0000000011D -:10250000022380000000001002238040000000121F -:102510000223808000000030022380C00000000EF3 -:102520000C2383000007A1200A2383000000013848 -:102530000B238300000013880A238340000000005F -:102540000C238340000001F40B23834000000005AE -:10255000022383800007A120022383C0000001F42E -:10256000062250000000004206222008000000C899 -:10257000062220000000000206224000000000C6E3 -:1025800004224318000503860622432C0000000B9A -:10259000042243580005038B0622436C0000000B05 -:1025A0000422439800050390062243AC0000000B70 -:1025B000042243D800050395062243EC0000000BDB -:1025C000042244180005039A0622442C0000000B44 -:1025D000042244580005039F0622446C0000000BAF -:1025E00004224498000503A4062244AC0000000B1A -:1025F000042244D8000503A9062244EC0000000B85 -:1026000004224518000503AE0622452C0000000BED -:1026100004224558000503B30622456C0000000B58 -:1026200004224598000503B8062245AC0000000BC3 -:10263000042245D8000503BD062245EC0000000B2E -:1026400004224618000503C20622462C0000000B97 -:1026500004224658000503C70622466C0000000B02 -:1026600004224698000503CC062246AC0000000B6D -:10267000042246D8000503D1062246EC0000000BD8 -:1026800004224718000503D60622472C0000000B41 -:1026900004224758000503DB0622476C0000000BAC -:1026A00004224798000503E0062247AC0000000B17 -:1026B000042247D8000503E5062247EC0000000B82 -:1026C00004224818000503EA0622482C0000000BEB -:1026D00004224858000503EF0622486C0000000B56 -:1026E00004224898000503F4062248AC0000000BC1 -:1026F000042248D8000503F9062248EC0000000B2C -:1027000004224918000503FE0622492C0000000B94 -:1027100004224958000504030622496C0000000BFE -:102720000422499800050408062249AC0000000B69 -:10273000042249D80005040D062249EC0000000BD4 -:1027400004224A180005041206224A2C0000000B3D -:1027500004224A580005041706224A6C0000000BA8 -:1027600004224A980005041C06224AAC0000000B13 -:1027700004224AD80005042106224AEC0000000584 -:1027800006224B000000001704224B5C00010426C7 -:1027900006224B600000000304224B6C000104275A -:1027A000062238000000004006223000000002002F -:1027B000042251C00004042806221000000000C0BA -:1027C000062215C00000024004221EC80008042C86 -:1027D0000622390000000008022251180000000003 -:1027E000062251D00000000606221300000000025D -:1027F00006221410000000300622392000000008D4 -:102800000222511C00000000062251E800000006D0 -:102810000622130800000002062214D00000003037 -:102820000216100000000028021700080000000235 -:102830000217002C000000030217003C00000004F7 -:1028400002170044000000000217004800000002C8 -:102850000217004C0000009002170050000000908A -:102860000217005400800090021700580810000062 -:10287000021700600000008A021700640000008058 -:1028800002170068000000810217006C0000008041 -:10289000021700700000000602170078000007D041 -:1028A0000217007C0000076C02170038007C10043F -:1028B000021700040000000F06164024000000026A -:1028C000021640700000001C0216420800000001C1 -:1028D0000216421000000001021642200000000112 -:1028E00002164228000000010216423000000001DA -:1028F000021642380000000102164260000000018A -:102900000C16401C0003D0900A16401C0000009CCE -:102910000B16401C000009C40216403000000008DD -:10292000021640340000000C02164038000000106F -:102930000216404400000020021640000000000182 -:10294000021640D8000000010216400800000001F5 -:102950000216400C000000010216401000000001A9 -:10296000021642400000000002164248000000002B -:1029700006164270000000020216425000000000DD -:1029800002164258000000000616428000000002B5 -:1029900002166008000006140216600C0000060013 -:1029A00002166010000006040216601C0000FFFF03 -:1029B000021660200000FFFF021660240000FFFFE7 -:1029C000021660280000FFFF021660380000002099 -:1029D0000216603C00000020061660400000000265 -:1029E00002166048000000230216604C000000241C -:1029F00002166050000000250216605400000026F8 -:102A000002166058000000270216605C00000029D2 -:102A1000021660600000002A021660640000002BAD -:102A2000021660680000002C0216606C0000002D89 -:102A30000616607000000012021660B80000000167 -:102A4000021660BC00000001061660C00000003ED7 -:102A5000021661B800000001061661BC0000001FEC -:102A60000216623807FFFFFF0216623C0000003FBB -:102A70000216624007FFFFFF021662440000000FCB -:102A800001166248000000000116624C00000000C0 -:102A900001166250000000000116625400000000A0 -:102AA00001166258000000000116625C0000000080 -:102AB0000116626000000000011662640000000060 -:102AC00001166268000000000116626C0000000040 -:102AD0000116627000000000011662740000000020 -:102AE00001166278000000000116627C0000000000 -:102AF000021664BC000000010C166000000003E830 -:102B00000A166000000000010B1660000000000AB9 -:102B100002168040000000060216804400000005F6 -:102B2000021680480000000A0216804C00000005D2 -:102B30000216805400000002021680CC000000043F -:102B4000021680D000000004021680D400000004A9 -:102B5000021680D800000004021680DC0000000489 -:102B6000021680E000000004021680E40000000469 -:102B7000021680E800000004021688040000000429 -:102B8000021680300000007C021680340000003DF8 -:102B9000021680380000003F0216803C0000009CB6 -:102BA000021680F000000007061680F40000000501 -:102BB0000216880C010101010216810800000000C4 -:102BC0000216810C000000040216811000000004AF -:102BD0000216811400000002021688100801200469 -:102BE00002168118000000050216811C0000000575 -:102BF0000216812000000005021681240000000555 -:102C00000216882C200810010216812800000008F6 -:102C10000216812C00000006021681300000000719 -:102C200002168134000000000216883001010120E4 -:102C300006168138000000040216883401010101E3 -:102C400006168148000000040216883801010101BF -:102C500006168158000000040216883C010101019B -:102C6000061681680000000302168174000000014E -:102C7000021688400101010102168178000000015E -:102C80000216817C00000001021681800000000114 -:102C9000021681840000000102168844010101012E -:102CA00002168188000000010216818C00000004D9 -:102CB00002168190000000040216819400000002B8 -:102CC00002168848080120040216819800000005B9 -:102CD0000216819C00000005021681A0000000057C -:102CE000021681A4000000050216881420081001B5 -:102CF000021681A800000008021681AC0000000640 -:102D0000021681B000000007021681B40000000125 -:102D10000216881801010120021681B80000000186 -:102D2000021681BC00000001021681C000000001F3 -:102D3000021681C4000000010216881C0101010175 -:102D4000021681C800000001021681CC00000001BB -:102D5000021681D000000001021681D4000000019B -:102D60000216882001010101021681D8000000012D -:102D7000021681DC00000001021681E00000000163 -:102D8000021681E4000000010216882401010101FD -:102D9000021681E800000001021681EC000000012B -:102DA000021681F0000000010216882801010101CD -:102DB00002168240FFFF003F061682440000000218 -:102DC0000216824CFFFF003F0216825000000100F5 -:102DD000021682540000010006168258000000020C -:102DE00002168260000000C002168264000000C06B -:102DF0000216826800001E000216826C00001E008F -:102E0000021682700000400002168274000040002A -:102E100002168278000080000216827C000080008A -:102E2000021682800000200002168284000020002A -:102E30000616828800000007021682A40000000126 -:102E4000061682A80000000A021681F400000C0891 -:102E5000021681F800000040021681FC000001000B -:102E600002168200000000200216820400000017F3 -:102E700002168208000000800216820C0000020088 -:102E8000021682100000000002168218FFFF01FFE8 -:102E900002168214FFFF01FF0216823C000000139D -:102EA000021680900000013F021680600000014081 -:102EB00002168064000001400616806800000002CF -:102EC00002168070000000C0061680740000000723 -:102ED0000216809C00000048021680A000000048F6 -:102EE000061680A400000002021680AC0000004814 -:102EF000061680B00000000702168238000080002D -:102F000002168234000025E40216809400007FFF40 -:102F100002168220000000070216821C0000000733 -:102F2000021682280000000002168224FFFFFFFF25 -:102F300002168230000000000216822CFFFFFFFF05 -:102F4000021680EC000000FF0214000000000001E7 -:102F50000214000C000000010214004000000001F7 -:102F60000214004400007FFF0214000C0000000067 -:102F700002140000000000000214006C00000000B9 -:102F800002140004000000010214003000000001DF -:102F900002140004000000000214005C00000000A5 -:102FA00002140008000000010214003400000001B7 -:102FB000021400080000000002140060000000007D -:102FC00006028000000020000202005800000032CB -:102FD000020200A003150020020200A40315002035 -:102FE000020200A801000030020200AC081000003C -:102FF000020200B000000033020200B40000003002 -:10300000020200B800000031020200BC0000000310 -:10301000020200C000000006020200C4000000031B -:10302000020200C800000003020200CC00000002FF -:10303000020200D000000000020200D400000002E2 -:10304000020200DC00000000020200E000000006B6 -:10305000020200E400000004020200E80000000296 -:10306000020200EC00000002020200F00000000179 -:10307000020200FC00000006020201200000000025 -:103080000202013400000002020201B0000000014F -:103090000202020C00000001020202140000000102 -:1030A00002020218000000020202040400000001F3 -:1030B0000202040C00000040020204100000004064 -:1030C0000202041C00000004020204200000002090 -:1030D0000202042400000002020204280000001F73 -:1030E00006020500000000120402048000200434DF -:1030F000020200600000000F0202006400000007EE -:1031000002020068000000000202006C0000000ED5 -:103110000602007000000004020200F40000000437 -:103120000202000400000001020200080000000189 -:103130000202000C00000001020200100000000169 -:103140000202001400000001020200180000000149 -:103150000202001C00000001020200200000000129 -:103160000202002400000001020200280000000109 -:103170000202002C000000010202003000000001E9 -:1031800002020034000000010202003800000001C9 -:103190000202003C000000010202004000000001A9 -:1031A0000202004400000001020200480000000189 -:1031B0000202004C00000001020200500000000169 -:1031C00002020108000000C802020118000000020B -:1031D000020201C400000000020201CC0000000055 -:1031E000020201D400000002020201DC0000000221 -:1031F000020201E4000000FF020201EC000000FFF7 -:103200000202010C000000C80202011C00000002C2 -:10321000020201C800000000020201D0000000000C -:10322000020201D800000002020201E000000002D8 -:10323000020201E8000000FF020201F0000000FFAE -:1032400007280400008D00000828076800130454B4 -:10325000072C000034090000072C800038990D036A -:10326000072D0000390C1B2A072D80000641296E0E -:10327000082D8AB04EAA0456012800000000000064 -:1032800001280004000000000128000800000000E0 -:103290000128000C000000000128001000000000C0 -:1032A0000128001400000000022800200000000196 -:1032B0000228002400000002022800280000000369 -:1032C0000228002C0000000002280030000000044A -:1032D000022800340000000102280038000000002D -:1032E0000228003C00000001022800400000000409 -:1032F00002280044000000000228004800000001ED -:103300000228004C000000030228005000000000CA -:1033100002280054000000010228005800000004A8 -:103320000228005C0000000002280060000000018C -:10333000022800640000000302280068000000006A -:103340000228006C00000001022800700000000448 -:103350000228007400000000022800780000000429 -:103360000228007C00000003062800800000000204 -:10337000022800A400003FFF022800A8000003FF6D -:10338000022802240000000002280234000000008D -:103390000228024C00000000022802E40000FFFFA7 -:1033A0000628200000000800022B8BC0000000014E -:1033B000022B800000000000022B8040000000185B -:1033C000022B80800000000C022B80C000000066F1 -:1033D0000C2B83000007A1200A2B8300000001387A -:1033E0000B2B8300000013880A2B83400000000091 -:1033F0000C2B8340000001F40B2B834000000005E0 -:10340000022B83800007A120022B83C0000001F45F -:10341000062A3D4800000004042A3D5800020458D2 -:10342000062A3D6000000006062A30000000004821 -:10343000062A2008000000C8062A2000000000021A -:10344000062A31280000008E062A33680000000397 -:10345000042A33740001045A062A3A780000000254 -:10346000042A3A800002045B042A3A700002045DD8 -:10347000042A3E280002045F042A3EB000040461CE -:10348000042A250000020465062A25080000010020 -:10349000062A297000000004042A29600004046739 -:1034A000042A2F480002046B062A3378000000D853 -:1034B000022A3A3800000000062A3A88000000324A -:1034C000042A3D880010046D062A502000000002E6 -:1034D000062A503000000002062A500000000002B8 -:1034E000062A501000000002022A50B80000000115 -:1034F000062A50480000000E042A3D780002047D90 -:10350000062A3C1800000026022A50400000000055 -:10351000062A36D8000000D8022A3A3C00000000F3 -:10352000062A3B5000000032042A3DC80010047FE8 -:10353000062A502800000002062A50380000000227 -:10354000062A500800000002062A50180000000257 -:10355000022A50BC00000001062A50800000000E24 -:10356000042A3D800002048F062A3CB00000002699 -:10357000022A504400000000021010080000000160 -:103580000210101000000264021010000003D000AE -:10359000021010040000003D091018000200049100 -:1035A00009101100001006910610114000000008DB -:1035B00009101160000806A1061011800000000229 -:1035C00009101188000606A9061011A000000018B5 -:1035D000021010100000000006102400000000E09F -:1035E0000210201C0000000002102020000000013A -:1035F000021020C0000000010210200400000001A1 -:10360000021020080000000109103C00000506AF70 -:1036100009103C20000506B409103800000506B961 -:1036200002104028000000100210404400003FFF3C -:103630000210405800280000021040840084924A82 -:1036400006104C000000010002104058000000006D -:103650000610806800000004021080000000108046 -:1036600006108028000000020210803800000010C0 -:10367000021080400000FFFF021080440000FFFFA6 -:1036800002108050000000000210810000000000C5 -:10369000061081200000000202108008000002B520 -:1036A0000210801000000000061082000000004A96 -:1036B000021081080001FFFF061081400000000297 -:1036C0000210800000001A80061090000000002404 -:1036D000061091200000004A061093700000004A76 -:1036E000061095C00000004A0210800400001080FF -:1036F00006108030000000020210803C0000001024 -:10370000021080480000FFFF0210804C0000FFFF05 -:10371000021080540000000002108104000000002C -:1037200006108128000000020210800C000002B583 -:103730000210801400000000061084000000004AFF -:103740000210810C0001FFFF0610814800000002FA -:103750000210800400001A800610909000000024DF -:10376000061092480000004A061094980000004A93 -:10377000061096E80000004A0212049000E383401D -:103780000212051400003C10021205200000000285 -:1037900002120494FFFFFFFF02120498FFFFFFFFD5 -:1037A0000212049CFFFFFFFF021204A0FFFFFFFFB5 -:1037B000021204A4FFFFFFFF021204A8FFFFFFFF95 -:1037C000021204ACFFFFFFFF021204B0FFFFFFFF75 -:1037D000021204B8FFFFFFFF021204BCFFFFFFFF4D -:1037E000021204C0FFFFFFFF021204C4FFFFFFFF2D -:1037F000021204C8FFFFFFFF021204CCFFFFFFFF0D -:10380000021204D0FFFFFFFF021204DCFFFFFFFFE4 -:10381000021204E0FFFFFFFF021204E4FFFFFFFFBC -:10382000021204E8FFFFFFFF021204ECFFFFFFFF9C -:10383000021204F0FFFFFFFF021204F4FFFFFFFF7C -:10384000021204F8FFFFFFFF021204FCFFFFFFFF5C -:1038500002120500FFFFFFFF02120504FFFFFFFF3A -:1038600002120508FFFFFFFF0212050CFFFFFFFF1A -:1038700002120510FFFFFFFF021204D4FFFF3330D6 -:10388000021204D8FFFF3340021204B4F0003000EB -:1038900002120390000000080212039C00000008BE -:1038A000061203A000000002021203BC0000000484 -:1038B000021203C400000004021203D00000000042 -:1038C000021203DC000000000212036C0000000181 -:1038D000021203680000003F021201BC0000004019 -:1038E000021201C000001808021201C400000803FF -:1038F000021201C800000803021201CC00000040BF -:10390000021201D000000003021201D400000803DB -:10391000021201D800000803021201DC00000803B3 -:10392000021201E000010003021201E4000008039A -:10393000021201E800000803021201EC000000037B -:10394000021201F000000003021201F40000000363 -:10395000021201F800000003021201FC0000000343 -:103960000212020000000003021202040000000321 -:1039700002120208000000030212020C0000000301 -:1039800002120210000000030212021400000003E1 -:1039900002120218000000030212021C00000003C1 -:1039A00002120220000000030212022400000003A1 -:1039B00002120228000024030212022C0000002F31 -:1039C0000212023000000009021202340000001945 -:1039D00002120238000001840212023C000001833E -:1039E0000212024000000306021202440000001905 -:1039F00002120248000000060212024C00000306F8 -:103A000002120250000003060212025400000306D4 -:103A10000212025800000C860212025C000003062B -:103A20000212026000000306021202640000000697 -:103A300002120268000000060212026C000000067A -:103A4000021202700000000602120274000000065A -:103A500002120278000000060212027C000000063A -:103A6000021202800000000602120284000000061A -:103A700002120288000000060212028C00000006FA -:103A800002120290000000060212029400000006DA -:103A900002120298000000060212029C00000006BA -:103AA000021202A000000306021202A4000000138A -:103AB000021202A800000006021202B00000100468 -:103AC000021202B400001004021203240010644029 -:103AD0000212032800106440021201B0000000012D -:103AE0000600A000000000160200A06CBF5C0000F1 -:103AF0000200A070FFF51FEF0200A0740000FFFF9E -:103B00000200A078F00003E00200A07C00000000AA -:103B10000200A0800000A0000600A08400000005B4 -:103B20000200A0980FE000000600A09C0000001416 -:103B30000200A0EC555400000200A0F05555555568 -:103B40000200A0F4000055550200A0F8F0000000AB -:103B50000200A0FC555400000200A1005555555527 -:103B60000200A104000055550200A108F000000069 -:103B70000600A22C000000040200A0600000030761 -:103B80000200A10CBF5C00000200A110FFF51FEFB6 -:103B90000200A1140000FFFF0200A118F00003E0E2 -:103BA0000200A11C000000000200A1200000A000F3 -:103BB0000600A124000000050200A1380FE000006B -:103BC0000600A13C000000140200A18C5554000026 -:103BD0000200A190555555550200A194000055557D -:103BE0000200A198F00000000200A19C55540000C2 -:103BF0000200A1A0555555550200A1A4000055553D -:103C00000200A1A8F00000000600A23C0000000491 -:103C10000200A06400000307000000000000000094 -:103C20000000002E00000000000000000000000066 -:103C30000000000000000000000000000000000084 -:103C40000000000000000000000000000000000074 -:103C50000000000000000000000000000000000064 -:103C60000000000000000000000000000000000054 -:103C70000000000000000000002E004D00000000C9 -:103C80000000000000000000000000000000000034 -:103C90000000000000000000000000000000000024 -:103CA00000000000004D008B00000000000000003C -:103CB0000000000000000000000000000000000004 -:103CC00000000000000000000000000000000000F4 -:103CD000008B009000900094009400980000000079 -:103CE00000000000000000000000000000000000D4 -:103CF000000000000000000000000000009802DE4C -:103D000002DE02E802E802F200000000000000000B -:103D100000000000000000000000000000000000A3 -:103D20000000000000000000000000000000000093 -:103D30000000000000000000000000000000000083 -:103D40000000000000000000000000000000000073 -:103D50000000000000000000000000000000000063 -:103D60000000000000000000000000000000000053 -:103D70000000000000000000000000000000000043 -:103D80000000000000000000000000000000000033 -:103D90000000000000000000000000000000000023 -:103DA0000000000000000000000000000000000013 -:103DB0000000000000000000000000000000000003 -:103DC00000000000000000000000000000000000F3 -:103DD000000000000000000002F202FA00000000F3 -:103DE00000000000000000000000000000000000D3 -:103DF00000000000000000000000000000000000C3 -:103E000000000000000000000000000000000000B2 -:103E100000000000000000000000000000000000A2 -:103E20000000000000000000000000000000000092 -:103E300002FA02FF02FF030A030A03150000000052 -:103E40000000000000000000000000000000000072 -:103E50000000000000000000000000000000000062 -:103E60000000000000000000000000000000000052 -:103E70000000000000000000000000000000000042 -:103E80000000000000000000031503160000000001 -:103E90000000000000000000000000000000000022 -:103EA0000000000000000000000000000000000012 -:103EB000000000000316035700000000000000008F -:103EC00000000000000000000000000000000000F2 -:103ED00000000000000000000000000000000000E2 -:103EE0000357037B000000000000000000000000FA -:103EF00000000000000000000000000000000000C2 -:103F0000000000000000000000000000037B03BB75 -:103F100000000000000000000000000000000000A1 -:103F20000000000000000000000000000000000091 -:103F3000000000000000000003BB03F700000000C9 -:103F40000000000000000000000000000000000071 -:103F50000000000000000000000000000000000061 -:103F60000000000003F7043D043D045204520467BE -:103F70000000000000000000000000000000000041 -:103F80000000000000000000000000000000000031 -:103F9000046704ED04ED04F204F204F700000000ED -:103FA0000000000000000000000000000000000011 -:103FB00000000000000000000000000004F704F80A -:103FC00000000000000000000000000000000000F1 -:103FD00000000000000000000000000000000000E1 -:103FE000000000000000000004F8050A00000000C6 -:103FF00000000000000000000000000000000000C1 -:1040000000000000000000000000000000000000B0 -:1040100000000000050A051F051F052205220525D1 -:104020000000000000000000000000000000000090 -:104030000000000000000000000000000000000080 -:1040400005250555000000000000000000000000EC -:104050000000000000000000000000000000000060 -:10406000000000000000000000000000055505DC15 -:104070000000000000000000000000000000000040 -:104080000000000000000000000000000000000030 -:10409000000000000000000005DC05E305E305E783 -:1040A00005E705EB00000000000000000000000034 -:1040B0000000000000000000000000000000000000 -:1040C0000000000005EB062B062B06330633063BEB -:1040D00000000000000000000000000000000000E0 -:1040E00000000000000000000000000000000000D0 -:1040F000063B068806880695069506A20000000085 -:1041000000000000000000000000000000000000AF -:1041100000000000000000000000000006A206AE43 -:10412000000000000000000000000000000000008F -:10413000000000000000000000000000000000007F -:10414000000000000000000006AE06B40000000001 -:10415000000000000000000000000000000000005F -:10416000000000000000000000000000000000004F -:104170000000000006B406B70000000000000000C8 -:10418000000000000000000000000000000000002F -:10419000000000000000000000000000000000001F -:1041A00006B706BD0000000000000000000000008F -:1041B00000000000000000000000000000000000FF -:1041C00000000000000000000000000006BD06BE68 -:1041D00006BE06D006D006E2000000000000000087 -:1041E00000000000000000000000000000000000CF -:1041F000000000000000000006E2074F0000000081 -:1042000000000000000000000000000000000000AE -:10421000000000000000000000000000000000009E -:1042200000000000074F0750075007630763077639 -:10423000000000000000000000000000000000007E -:10424000000000000000000000000000000000006E -:10425000000000000000000000000000000000005E -:10426000000000000000000000000000000000004E -:10427000000000000000000000000000000000003E -:10428000000000000000000000000000000000002E -:10429000000000000000000000000000000000001E -:1042A000000000000000000000000000000000000E -:1042B00000000000000000000000000000000000FE -:1042C00000000000000000000000000000000000EE -:1042D00000000000000000000000000000000000DE -:1042E00000000000000000000000000000000000CE -:1042F00000000000000000000000000000000000BE -:1043000000000000000000000000000000000000AD -:10431000000000000000000000000000000000009D -:10432000000000000000000000000000000000008D -:1043300000010000000204C00003098000040E40D8 -:1043400000051300000617C000071C80000821406C -:1043500000092600000A2AC0000B2F80000C344000 -:10436000000D3900000E3DC0000F42800010474094 -:1043700000114C00001250C00013558000145A4028 -:1043800000155F00001663C00017688000186D40BC -:1043900000197200001A76C0001B7B80001C804050 -:1043A000001D8500001E89C0001F8E800000934004 -:1043B00000002000000040000000600000008000BD -:1043C0000000A0000000C0000000E00000010000AC -:1043D0000001200000014000000160000001800099 -:1043E0000001A0000001C0000001E0000002000088 -:1043F0000002200000024000000260000002800075 -:104400000002A0000002C0000002E0000003000063 -:104410000003200000034000000360000003800050 -:104420000003A0000003C0000003E000000400003F -:10443000000420000004400000046000000480002C -:104440000004A0000004C0000004E000000500001B -:104450000005200000054000000560000005800008 -:104460000005A0000005C0000005E00000060000F7 -:1044700000062000000640000006600000068000E4 -:104480000006A0000006C0000006E00000070000D3 -:1044900000072000000740000007600000078000C0 -:1044A0000007A0000007C0000007E00000080000AF -:1044B000000820000008400000086000000880009C -:1044C0000008A0000008C0000008E000000900008B -:1044D0000009200000094000000960000009800078 -:1044E0000009A0000009C0000009E000000A000067 -:1044F000000A2000000A4000000A6000000A800054 -:10450000000AA000000AC000000AE000000B000042 -:10451000000B2000000B4000000B6000000B80002F -:10452000000BA000000BC000000BE000000C00001E -:10453000000C2000000C4000000C6000000C80000B -:10454000000CA000000CC000000CE000000D0000FA -:10455000000D2000000D4000000D6000000D8000E7 -:10456000000DA000000DC000000DE000000E0000D6 -:10457000000E2000000E4000000E6000000E8000C3 -:10458000000EA000000EC000000EE000000F0000B2 -:10459000000F2000000F4000000F6000000F80009F -:1045A000000FA000000FC000000FE000001000008E -:1045B000001020000010400000106000001080007B -:1045C0000010A0000010C0000010E000001100006A -:1045D0000011200000114000001160000011800057 -:1045E0000011A0000011C0000011E0000012000046 -:1045F0000012200000124000001260000012800033 -:104600000012A0000012C0000012E0000013000021 -:10461000001320000013400000136000001380000E -:104620000013A0000013C0000013E00000140000FD -:1046300000142000001440000014600000148000EA -:104640000014A0000014C0000014E00000150000D9 -:1046500000152000001540000015600000158000C6 -:104660000015A0000015C0000015E00000160000B5 -:1046700000162000001640000016600000168000A2 -:104680000016A0000016C0000016E0000017000091 -:10469000001720000017400000176000001780007E -:1046A0000017A0000017C0000017E000001800006D -:1046B000001820000018400000186000001880005A -:1046C0000018A0000018C0000018E0000019000049 -:1046D0000019200000194000001960000019800036 -:1046E0000019A0000019C0000019E000001A000025 -:1046F000001A2000001A4000001A6000001A800012 -:10470000001AA000001AC000001AE000001B000000 -:10471000001B2000001B4000001B6000001B8000ED -:10472000001BA000001BC000001BE000001C0000DC -:10473000001C2000001C4000001C6000001C8000C9 -:10474000001CA000001CC000001CE000001D0000B8 -:10475000001D2000001D4000001D6000001D8000A5 -:10476000001DA000001DC000001DE000001E000094 -:10477000001E2000001E4000001E6000001E800081 -:10478000001EA000001EC000001EE000001F000070 -:10479000001F2000001F4000001F6000001F80005D -:1047A000001FA000001FC000001FE000002000004C -:1047B0000020200000204000002060000020800039 -:1047C0000020A0000020C0000020E0000021000028 -:1047D0000021200000214000002160000021800015 -:1047E0000021A0000021C0000021E0000022000004 -:1047F00000222000002240000022600000228000F1 -:104800000022A0000022C0000022E00000230000DF -:1048100000232000002340000023600000238000CC -:104820000023A0000023C0000023E00000240000BB -:1048300000242000002440000024600000248000A8 -:104840000024A0000024C0000024E0000025000097 -:104850000025200000254000002560000025800084 -:104860000025A0000025C0000025E0000026000073 -:104870000026200000264000002660000026800060 -:104880000026A0000026C0000026E000002700004F -:10489000002720000027400000276000002780003C -:1048A0000027A0000027C0000027E000002800002B -:1048B0000028200000284000002860000028800018 -:1048C0000028A0000028C0000028E0000029000007 -:1048D00000292000002940000029600000298000F4 -:1048E0000029A0000029C0000029E000002A0000E3 -:1048F000002A2000002A4000002A6000002A8000D0 -:10490000002AA000002AC000002AE000002B0000BE -:10491000002B2000002B4000002B6000002B8000AB -:10492000002BA000002BC000002BE000002C00009A -:10493000002C2000002C4000002C6000002C800087 -:10494000002CA000002CC000002CE000002D000076 -:10495000002D2000002D4000002D6000002D800063 -:10496000002DA000002DC000002DE000002E000052 -:10497000002E2000002E4000002E6000002E80003F -:10498000002EA000002EC000002EE000002F00002E -:10499000002F2000002F4000002F6000002F80001B -:1049A000002FA000002FC000002FE000003000000A -:1049B00000302000003040000030600000308000F7 -:1049C0000030A0000030C0000030E00000310000E6 -:1049D00000312000003140000031600000318000D3 -:1049E0000031A0000031C0000031E00000320000C2 -:1049F00000322000003240000032600000328000AF -:104A00000032A0000032C0000032E000003300009D -:104A1000003320000033400000336000003380008A -:104A20000033A0000033C0000033E0000034000079 -:104A30000034200000344000003460000034800066 -:104A40000034A0000034C0000034E0000035000055 -:104A50000035200000354000003560000035800042 -:104A60000035A0000035C0000035E0000036000031 -:104A7000003620000036400000366000003680001E -:104A80000036A0000036C0000036E000003700000D -:104A900000372000003740000037600000378000FA -:104AA0000037A0000037C0000037E00000380000E9 -:104AB00000382000003840000038600000388000D6 -:104AC0000038A0000038C0000038E00000390000C5 -:104AD00000392000003940000039600000398000B2 -:104AE0000039A0000039C0000039E000003A0000A1 -:104AF000003A2000003A4000003A6000003A80008E -:104B0000003AA000003AC000003AE000003B00007C -:104B1000003B2000003B4000003B6000003B800069 -:104B2000003BA000003BC000003BE000003C000058 -:104B3000003C2000003C4000003C6000003C800045 -:104B4000003CA000003CC000003CE000003D000034 -:104B5000003D2000003D4000003D6000003D800021 -:104B6000003DA000003DC000003DE000003E000010 -:104B7000003E2000003E4000003E6000003E8000FD -:104B8000003EA000003EC000003EE000003F0000EC -:104B9000003F2000003F4000003F6000003F8000D9 -:104BA000003FA000003FC000003FE000003FE001E8 -:104BB00000000000000001FF0000020000007FF87C -:104BC00000007FF80000016A0000150000000001ED -:104BD0000000FF00000000000000FF0000000000D7 -:104BE00000000000140AFF000000000100000000A7 -:104BF00000201001000000000100860000000100FC -:104C00000000860200008604000086060000860878 -:104C10000000860A0000860C0000860E0000861048 -:104C20000000861200008614000086160000861818 -:104C30000000861A0000861C0000861E00008620E8 -:104C400000008622000086240000862600008628B8 -:104C50000000862A0000862C0000862E0000863088 -:104C60000000863200008634000086360000863858 -:104C70000000863A0000863C0000863E0000864028 -:104C800000008642000086440000864600008648F8 -:104C90000000864A0000864C0000864E00008650C8 -:104CA0000000865200008654000086560000865898 -:104CB0000000865A0000865C0000865E0000866068 -:104CC0000000866200008664000086660000866838 -:104CD0000000866A0000866C0000866E0000867008 -:104CE00000008672000086740000867600008678D8 -:104CF0000000867A0000867C0000867E00008680A8 -:104D00000000868200008684000086860000868877 -:104D10000000868A0000868C0000868E0000869047 -:104D20000000869200008694000086960000869817 -:104D30000000869A0000869C0000869E000086A0E7 -:104D4000000086A2000086A4000086A6000086A8B7 -:104D5000000086AA000086AC000086AE000086B087 -:104D6000000086B2000086B4000086B6000086B857 -:104D7000000086BA000086BC000086BE000086C027 -:104D8000000086C2000086C4000086C6000086C8F7 -:104D9000000086CA000086CC000086CE000086D0C7 -:104DA000000086D2000086D4000086D6000086D897 -:104DB000000086DA000086DC000086DE000086E067 -:104DC000000086E2000086E4000086E6000086E837 -:104DD000000086EA000086EC000086EE000086F007 -:104DE000000086F2000086F4000086F6000086F8D7 -:104DF000000086FA000086FC000086FE00008700A6 -:104E00000000870200008704000087060000870872 -:104E10000000870A0000870C0000870E0000871042 -:104E20000000871200008714000087160000871812 -:104E30000000871A0000871C0000871E00008720E2 -:104E400000008722000087240000872600008728B2 -:104E50000000872A0000872C0000872E0000873082 -:104E60000000873200008734000087360000873852 -:104E70000000873A0000873C0000873E0000874022 -:104E800000008742000087440000874600008748F2 -:104E90000000874A0000874C0000874E00008750C2 -:104EA0000000875200008754000087560000875892 -:104EB0000000875A0000875C0000875E0000876062 -:104EC0000000876200008764000087660000876832 -:104ED0000000876A0000876C0000876E0000877002 -:104EE00000008772000087740000877600008778D2 -:104EF0000000877A0000877C0000877E00008780A2 -:104F00000000878200008784000087860000878871 -:104F10000000878A0000878C0000878E0000879041 -:104F20000000879200008794000087960000879811 -:104F30000000879A0000879C0000879E000087A0E1 -:104F4000000087A2000087A4000087A6000087A8B1 -:104F5000000087AA000087AC000087AE000087B081 -:104F6000000087B2000087B4000087B6000087B851 -:104F7000000087BA000087BC000087BE000087C021 -:104F8000000087C2000087C4000087C6000087C8F1 -:104F9000000087CA000087CC000087CE000087D0C1 -:104FA000000087D2000087D4000087D6000087D891 -:104FB000000087DA000087DC000087DE000087E061 -:104FC000000087E2000087E4000087E6000087E831 -:104FD000000087EA000087EC000087EE000087F001 -:104FE000000087F2000087F4000087F6000087F8D1 -:104FF000000087FA000087FC000087FEFFFFFFFF2C -:10500000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFB0 -:10501000FFFFFFFFFFFFFFFFFFFFFFFF0000000399 -:1050200000BEBC20000000000000000500000003DE -:1050300000BEBC20000000000000000500002000B1 -:10504000000040C000006180000082400000A3001A -:105050000000C3C00000E4800001054000012600FC -:10506000000146C000016780000188400001A900DE -:105070000001C9C00001EA8000020B4000022C00C0 -:1050800000024CC000026D8000028E400002AF00A2 -:105090000002CFC00002F08000001140000080003C -:1050A000000103800001870000020A8000028E00D8 -:1050B00000031180000395000004188000049C0088 -:1050C00000051F800005A300000626800006AA0038 -:1050D00000072D800007B100000834800008B800E8 -:1050E00000093B800009BF00000A4280000AC60098 -:1050F000000B4980000BCD00000C5080000CD40048 -:10510000000D578000005B0000007FF800007FF872 -:1051100000000166000015000000FF000000000014 -:105120000000FF0000000000000019000000000067 -:1051300000000000FFFFFFFF00007FF800007FF885 -:1051400000000361000015000000FF000FFFFFFFDB -:105150000000FF000FFFFFFF000000FF0000FF0046 -:105160000FFFFFFF0000FF000FFFFFFF000000FF29 -:105170000000FF000FFFFFFF0000FF000FFFFFFF19 -:10518000000000FF0000FF000FFFFFFF0000FF0016 -:105190000FFFFFFF000000FF0000FF000FFFFFFFF9 -:1051A0000000FF000FFFFFFF000000FF0000FF00F6 -:1051B0000FFFFFFF0000FF000FFFFFFF000000FFD9 -:1051C0000000FF000FFFFFFF0000FF000FFFFFFFC9 -:1051D000000000FF0000FF000FFFFFFF0000FF00C6 -:1051E0000FFFFFFF000000FF0000FF000FFFFFFFA9 -:1051F0000000FF000FFFFFFF000000FF0000FF00A6 -:105200000FFFFFFF0000FF000FFFFFFF000000FF88 -:105210000000FF000FFFFFFF0000FF000FFFFFFF78 -:10522000000000FF0000FF000FFFFFFF0000FF0075 -:105230000FFFFFFF000000FF0000FF000FFFFFFF58 -:105240000000FF000FFFFFFF000000FF0000FF0055 -:105250000FFFFFFF0000FF000FFFFFFF000000FF38 -:105260000000FF000FFFFFFF0000FF000FFFFFFF28 -:10527000000000FF0000FF000FFFFFFF0000FF0025 -:105280000FFFFFFF000000FF0000FF000FFFFFFF08 -:105290000000FF000FFFFFFF000000FF0000FF0005 -:1052A0000FFFFFFF0000FF000FFFFFFF000000FFE8 -:1052B0000000FF000FFFFFFF0000FF000FFFFFFFD8 -:1052C000000000FF0000FF000FFFFFFF0000FF00D5 -:1052D0000FFFFFFF000000FF0000FF000FFFFFFFB8 -:1052E0000000FF000FFFFFFF000000FF0000FF00B5 -:1052F0000FFFFFFF0000FF000FFFFFFF000000FF98 -:105300000000FF000FFFFFFF0000FF000FFFFFFF87 -:10531000000000FF0000FF000FFFFFFF0000FF0084 -:105320000FFFFFFF000000FF0000FF000FFFFFFF67 -:105330000000FF000FFFFFFF000000FF0000FF0064 -:105340000FFFFFFF0000FF000FFFFFFF000000FF47 -:105350000000FF000FFFFFFF0000FF000FFFFFFF37 -:10536000000000FF0000FF000FFFFFFF0000FF0034 -:105370000FFFFFFF000000FF0000FF000FFFFFFF17 -:105380000000FF000FFFFFFF000000FF0000FF0014 -:105390000FFFFFFF0000FF000FFFFFFF000000FFF7 -:1053A0000000FF000FFFFFFF0000FF000FFFFFFFE7 -:1053B000000000FF0000FF000FFFFFFF0000FF00E4 -:1053C0000FFFFFFF000000FF000000FF000000FFD4 -:1053D0000000FF00000000000000FF0000000000CF -:1053E000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFCD -:1053F000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFBD -:1054000000001000000020800000310000004180FA -:1054100000005200000062800000730000008380E2 -:10542000000094000000A4800000B5000000C580CA -:105430000000D6000000E6800000F70000010780B1 -:105440000001180000012880000139000001498096 -:1054500000015A0000016A8000017B0000018B807E -:1054600000019C000001AC800001BD000001CD8066 -:105470000001DE000001EE8000000F0000000000CF -:1054800000007FF800007FF80000021D00001500FA -:1054900010000000000028AD00010001FFFFFFFF29 -:1054A000FFFFFFFF00050206CCCCCCC17058103CBA -:1054B000000000000000FF00000000000000FF00EE -:1054C000000000000000000000000001CCCC020140 -:1054D000CCCCCCCCCCCC0201CCCCCCCC00000000D1 -:1054E000FFFFFFFF0000FFFF000000000000FFFFC4 -:1054F000000000000000FFFF000000000000FFFFB0 -:10550000000000000000FFFF000000000000FFFF9F -:10551000000000000000FFFF000000000000FFFF8F -:1055200000000000000E0000011600D60000FFFF82 -:10553000000000000000FFFF000000000000FFFF6F -:10554000000000000000FFFF000000000000FFFF5F -:10555000000000000000FFFF000000000000FFFF4F -:10556000000000000000FFFF0000000000720000CB -:10557000012300F3FFFFFFF3318FFFFF0C30C30C5B -:10558000C30C30C3CF3CF300F3CF3CF30000CF3C5F -:10559000CDCDCDCDFFFFFFF130EFFFFF0C30C30CC1 -:1055A000C30C30C3CF3CF300F3CF3CF30001CF3C3E -:1055B000CDCDCDCDFFFFFFF6305FFFFF0C30C30C2C -:1055C000C30C30C3CF3CF300F3CF3CF30002CF3C1D -:1055D000CDCDCDCDFFFFF4061CBFFFFF0C30C305C2 -:1055E000C30C30C3CF300014F3CF3CF30004CF3CE6 -:1055F000CDCDCDCDFFFFFFF2304FFFFF0C30C30C00 -:10560000C30C30C3CF3CF300F3CF3CF30008CF3CD6 -:10561000CDCDCDCDFFFFFFFA302FFFFF0C30C30CF7 -:10562000C30C30C3CF3CF300F3CF3CF30010CF3CAE -:10563000CDCDCDCDFFFFFFF731EFFFFF0C30C30C19 -:10564000C30C30C3CF3CF300F3CF3CF30020CF3C7E -:10565000CDCDCDCDFFFFFFF5302FFFFF0C30C30CBC -:10566000C30C30C3CF3CF300F3CF3CF30040CF3C3E -:10567000CDCDCDCDFFFFFFF3318FFFFF0C30C30C3D -:10568000C30C30C3CF3CF300F3CF3CF30000CF3C5E -:10569000CDCDCDCDFFFFFFF1310FFFFF0C30C30C9F -:1056A000C30C30C3CF3CF300F3CF3CF30001CF3C3D -:1056B000CDCDCDCDFFFFFFF6305FFFFF0C30C30C2B -:1056C000C30C30C3CF3CF300F3CF3CF30002CF3C1C -:1056D000CDCDCDCDFFFFF4061CBFFFFF0C30C305C1 -:1056E000C30C30C3CF300014F3CF3CF30004CF3CE5 -:1056F000CDCDCDCDFFFFFFF2304FFFFF0C30C30CFF -:10570000C30C30C3CF3CF300F3CF3CF30008CF3CD5 -:10571000CDCDCDCDFFFFFFFA302FFFFF0C30C30CF6 -:10572000C30C30C3CF3CF300F3CF3CF30010CF3CAD -:10573000CDCDCDCDFFFFFFF730EFFFFF0C30C30C19 -:10574000C30C30C3CF3CF300F3CF3CF30020CF3C7D -:10575000CDCDCDCDFFFFFFF5304FFFFF0C30C30C9B -:10576000C30C30C3CF3CF300F3CF3CF30040CF3C3D -:10577000CDCDCDCDFFFFFFFF30CFFFFF0C30C30CF1 -:10578000C30C30C3CF3CF3CCF3CF3CF30000CF3C91 -:10579000CDCDCDCDFFFFFFFF30CFFFFF0C30C30CD1 -:1057A000C30C30C3CF3CF3CCF3CF3CF30001CF3C70 -:1057B000CDCDCDCDFFFFFFFF30CFFFFF0C30C30CB1 -:1057C000C30C30C3CF3CF3CCF3CF3CF30002CF3C4F -:1057D000CDCDCDCDFFFFFFFF30CFFFFF0C30C30C91 -:1057E000C30C30C3CF3CF3CCF3CF3CF30004CF3C2D -:1057F000CDCDCDCDFFFFFFFF30CFFFFF0C30C30C71 -:10580000C30C30C3CF3CF3CCF3CF3CF30008CF3C08 -:10581000CDCDCDCDFFFFFFFF30CFFFFF0C30C30C50 -:10582000C30C30C3CF3CF3CCF3CF3CF30010CF3CE0 -:10583000CDCDCDCDFFFFFFFF30CFFFFF0C30C30C30 -:10584000C30C30C3CF3CF3CCF3CF3CF30020CF3CB0 -:10585000CDCDCDCDFFFFFFFF30CFFFFF0C30C30C10 -:10586000C30C30C3CF3CF3CCF3CF3CF30040CF3C70 -:10587000CDCDCDCDFFFFFFF3320FFFFF0C30C30CBA -:10588000C30C30C3CF3CF300F3CF3CF30000CF3C5C -:10589000CDCDCDCDFFFFFFF1310FFFFF0C30C30C9D -:1058A000C30C30C3CF3CF300F3CF3CF30001CF3C3B -:1058B000CDCDCDCDFFFFFFF6305FFFFF0C30C30C29 -:1058C000C30C30C3CF3CF300F3CF3CF30002CF3C1A -:1058D000CDCDCDCDFFFFF4061CBFFFFF0C30C305BF -:1058E000C30C30C3CF300014F3CF3CF30004CF3CE3 -:1058F000CDCDCDCDFFFFFFF2304FFFFF0C30C30CFD -:10590000C30C30C3CF3CF300F3CF3CF30008CF3CD3 -:10591000CDCDCDCDFFFFFF8A042FFFFF0C30C30C90 -:10592000C30C30C3CF3CC000F3CF3CF30010CF3CDE -:10593000CDCDCDCDFFFFFF9705CFFFFF0C30C30CC2 -:10594000C30C30C3CF3CC000F3CF3CF30020CF3CAE -:10595000CDCDCDCDFFFFFFF5310FFFFF0C30C30CD8 -:10596000C30C30C3CF3CF300F3CF3CF30040CF3C3B -:10597000CDCDCDCDFFFFFFF3300FFFFF0C30C30CBB -:10598000C30C30C3CF3CF300F3CF3CF30000CF3C5B -:10599000CDCDCDCDFFFFFFF1300FFFFF0C30C30C9D -:1059A000C30C30C3CF3CF300F3CF3CF30001CF3C3A -:1059B000CDCDCDCDFFFFFFF6305FFFFF0C30C30C28 -:1059C000C30C30C3CF3CF300F3CF3CF30002CF3C19 -:1059D000CDCDCDCDFFFFF4061CBFFFFF0C30C305BE -:1059E000C30C30C3CF300014F3CF3CF30004CF3CE2 -:1059F000CDCDCDCDFFFFFFF2304FFFFF0C30C30CFC -:105A0000C30C30C3CF3CF300F3CF3CF30008CF3CD2 -:105A1000CDCDCDCDFFFFFFFA302FFFFF0C30C30CF3 -:105A2000C30C30C3CF3CF300F3CF3CF30010CF3CAA -:105A3000CDCDCDCDFFFFFF97040FFFFF0C30C30C82 -:105A4000C30C30C3CF3CC000F3CF3CF30020CF3CAD -:105A5000CDCDCDCDFFFFFFF5300FFFFF0C30C30CD8 -:105A6000C30C30C3CF3CF300F3CF3CF30040CF3C3A -:105A7000CDCDCDCDFFFFFFFF30CFFFFF0C30C30CEE -:105A8000C30C30C3CF3CF3CCF3CF3CF30000CF3C8E -:105A9000CDCDCDCDFFFFFFFF30CFFFFF0C30C30CCE -:105AA000C30C30C3CF3CF3CCF3CF3CF30001CF3C6D -:105AB000CDCDCDCDFFFFFFFF30CFFFFF0C30C30CAE -:105AC000C30C30C3CF3CF3CCF3CF3CF30002CF3C4C -:105AD000CDCDCDCDFFFFFFFF30CFFFFF0C30C30C8E -:105AE000C30C30C3CF3CF3CCF3CF3CF30004CF3C2A -:105AF000CDCDCDCDFFFFFFFF30CFFFFF0C30C30C6E -:105B0000C30C30C3CF3CF3CCF3CF3CF30008CF3C05 -:105B1000CDCDCDCDFFFFFFFF30CFFFFF0C30C30C4D -:105B2000C30C30C3CF3CF3CCF3CF3CF30010CF3CDD -:105B3000CDCDCDCDFFFFFFFF30CFFFFF0C30C30C2D -:105B4000C30C30C3CF3CF3CCF3CF3CF30020CF3CAD -:105B5000CDCDCDCDFFFFFFFF30CFFFFF0C30C30C0D -:105B6000C30C30C3CF3CF3CCF3CF3CF30040CF3C6D -:105B7000CDCDCDCDFFFFFFFF30CFFFFF0C30C30CED -:105B8000C30C30C3CF3CF3CCF3CF3CF30000CF3C8D -:105B9000CDCDCDCDFFFFFFFF30CFFFFF0C30C30CCD -:105BA000C30C30C3CF3CF3CCF3CF3CF30001CF3C6C -:105BB000CDCDCDCDFFFFFFFF30CFFFFF0C30C30CAD -:105BC000C30C30C3CF3CF3CCF3CF3CF30002CF3C4B -:105BD000CDCDCDCDFFFFFFFF30CFFFFF0C30C30C8D -:105BE000C30C30C3CF3CF3CCF3CF3CF30004CF3C29 -:105BF000CDCDCDCDFFFFFFFF30CFFFFF0C30C30C6D -:105C0000C30C30C3CF3CF3CCF3CF3CF30008CF3C04 -:105C1000CDCDCDCDFFFFFFFF30CFFFFF0C30C30C4C -:105C2000C30C30C3CF3CF3CCF3CF3CF30010CF3CDC -:105C3000CDCDCDCDFFFFFFFF30CFFFFF0C30C30C2C -:105C4000C30C30C3CF3CF3CCF3CF3CF30020CF3CAC -:105C5000CDCDCDCDFFFFFFFF30CFFFFF0C30C30C0C -:105C6000C30C30C3CF3CF3CCF3CF3CF30040CF3C6C -:105C7000CDCDCDCDFFFFFFFF30CFFFFF0C30C30CEC -:105C8000C30C30C3CF3CF3CCF3CF3CF30000CF3C8C -:105C9000CDCDCDCDFFFFFFFF30CFFFFF0C30C30CCC -:105CA000C30C30C3CF3CF3CCF3CF3CF30001CF3C6B -:105CB000CDCDCDCDFFFFFFFF30CFFFFF0C30C30CAC -:105CC000C30C30C3CF3CF3CCF3CF3CF30002CF3C4A -:105CD000CDCDCDCDFFFFFFFF30CFFFFF0C30C30C8C -:105CE000C30C30C3CF3CF3CCF3CF3CF30004CF3C28 -:105CF000CDCDCDCDFFFFFFFF30CFFFFF0C30C30C6C -:105D0000C30C30C3CF3CF3CCF3CF3CF30008CF3C03 -:105D1000CDCDCDCDFFFFFFFF30CFFFFF0C30C30C4B -:105D2000C30C30C3CF3CF3CCF3CF3CF30010CF3CDB -:105D3000CDCDCDCDFFFFFFFF30CFFFFF0C30C30C2B -:105D4000C30C30C3CF3CF3CCF3CF3CF30020CF3CAB -:105D5000CDCDCDCDFFFFFFFF30CFFFFF0C30C30C0B -:105D6000C30C30C3CF3CF3CCF3CF3CF30040CF3C6B -:105D7000CDCDCDCD000C0000000700C00002813069 -:105D8000000B81580002021000010230000F024097 -:105D900000010330000C0000000800C00002814038 -:105DA000000B81680002022000010240000702503F -:105DB000000202C000100000000801000002818003 -:105DC000000B81A80002026000018280000E829810 -:105DD0000008038000028000000B8028000200E021 -:105DE000000101000000811000000118CCCCCCCCD7 -:105DF000CCCCCCCCCCCCCCCCCCCCCCCC00002000F3 -:105E0000CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCD2 -:105E100000002000CCCCCCCCCCCCCCCCCCCCCCCCD2 -:105E2000CCCCCCCC00002000000000000000000022 -:105E30001F8B080000000000000BFB51CFC0F003D7 -:105E40008ABB5819180238107C7AE0A58C94E9DFD7 -:105E5000C8CCC0B00388AF02F17E66D2F5B34A2346 -:105E6000D8F7241818182419184E893130EC9244A8 -:105E700088E702D5084A3130DC858A0500D967A554 -:105E8000E81B4EA39836F8BB3A2AFF912A84CE87A6 -:105E900089A3C93F86CA6F5480D03FD5B19BBB0947 -:105EA0002A0F00FE694F6760030000000000000039 -:105EB0001F8B080000000000000BED7D0B7854D50F -:105EC000B9E8DACFD933994C7642422610700703ED -:105ED000040D30208FA85427E1D1E0E5E8F0462EEC -:105EE000CA80AF0892448D356D39373B6412020287 -:105EF0008ECAA1B4A53A207AA247DBD4464B7BF5E3 -:105F0000DC206A73DAD37B9152A52DB6413D281669 -:105F100068F49403BDD796BBFE7FAD3DD97B672661 -:105F20000F5FDF395F1B3EDD597BAFBDD6BFFEF78C -:105F3000FAFF7FEDA8A242D44B08B9083FD712B2AE -:105F40004E2084E4F55EADFB448B56935C42AA82FE -:105F5000AAB1953E5B2F858DC669F4FE2562E809DE -:105F600002F7C7CD21930851E0BD0242A6C2FFA6A9 -:105F70001322E7B40E8FFAE93D6955165CADF1AC1A -:105F80006B954C883E159E6F1B97EA7972FE84D202 -:105F9000D3AD11FCB9388690FAE337CE7FC56AD30A -:105FA000FF4692CCDC9397D35F6692991725423EC9 -:105FB0002A5C94D569A41FEF83862E5D1E4BC8F919 -:105FC0008615F35F19DBF7F97A89D4B697F6BD7FAA -:105FD00015D1102F4433D5C8C4DE75AF27A4D39391 -:105FE00043C8E6C24D6CBDB9145957D2FB6DFFA230 -:105FF000CB25BD70AE9769BFA97DD7438889E35A89 -:10600000E324DF4F7439DE77BF971C8FBF4F64FAEC -:106010006F0621D885AE7FBA10BD16EE7B0A1799A0 -:1060200023687BFD33E5245A9A1EFE24BD3E21FCE5 -:10603000D67B69E9C8FB7DB4BFA985D0F74EAAF12C -:10604000EBAFA27CF4DEF7A5D026E0A33DE3E7901A -:1060500000BD4F181F59743AB5BF69782AFE4847EA -:10606000A7BF275EE43F8BBFAAC455599DE493F3B5 -:10607000D71DC05F1936FE6A5FDCEF789F94BF6260 -:106080006EFEE2F838DDCED64F760F6374E1F4721F -:10609000D3272D5D3EE97B7DF9690BE0D5D3BED8D2 -:1060A0001C4152F01387D7A2D7A78577203E222420 -:1060B0008E74262422C1FCBDF7D935A3CC1080CF25 -:1060C00068F330AC23C8A622C15B5BEE16299C01A5 -:1060D00092681D5744DBDD6B1600DC81E3F34F81D2 -:1060E0003C34872AB4D974BDFA34E3A179F49A51C7 -:1060F000AA0BB09EAD44042540C7AB36CB4B815EA6 -:1061000004DB4F9BB7844DC0030913329C90FBF80E -:106110009A08110D99B655F8754CAA75A8A493E183 -:1061200043B8E8E9FB7EBAF5ABBDEF918B45F0FFD4 -:106130007B08AC6FA0F74894BD67D27F80EF1CD777 -:1061400038FA1CDAB6F17D80D8DAF4F951F805F1A5 -:106150007DF717325F36D9A719543FA825A29E8034 -:10616000FEC4C896693BA3922A22781E24072945BB -:1061700006A44B332195EDC08FA49D2C9CD80BDF3A -:106180002922E07A0A6EDFB9A685AAAE7365FE10F1 -:10619000F079502764584EDFF56C6BA08C3CDED64E -:1061A0000E3D87FC1FA37C3486BE6F86983DDC5A6B -:1061B000F2B21EB5C977862070BE74F30731E419B8 -:1061C0002066C02AF45A2286BD814FCF1FB20B8FA2 -:1061D00083E50F7FD4461F32747A05B9DF3058FE4D -:1061E000F8B4F35974ED2B578D165D3542E9B0A51F -:1061F00078514AFF233D5DF711E89F5142C289144F -:10620000EF8D12042E07A643DFE095D2474A92F79E -:106210005E07BDA4FC192BF6F6830F29D7890F6BF7 -:106220005C6FBD64BC4B5522917511C653613CCA6D -:10623000A75B820F9B84CAC339E06D8A0F293EA5F4 -:1062400013DAA498201FD29F4E81B6BDC170622B75 -:10625000F24102E962C1E73144077EE55C9FA34D4C -:106260005698821D7E6FBD8A70A8E823D071743A5B -:10627000204585EC279DC0B716BF021B5CBC14DA15 -:106280005F77F041AB3195A4A283C5AF8056C6AF0E -:106290005F1F9C7E71CFB7C409EFA0DFF3CBC64967 -:1062A0009B1D4AFF9E4C4E5AF4A148AC82016C7C67 -:1062B000B059210784C98434152E23517A77333C91 -:1062C000A276AC05AE05E01F4E45BD40DA0419E0EC -:1062D000B4EC2A09E660BFE98281E3895A2DEA1508 -:1062E000C91F66F6953F4F0F179B7FB8110FEB1430 -:1062F000BFF9241E16297DA8AE0C7512D09B610231 -:106300007C40428C2F24EEA75BEFC7383F7BC951FE -:106310007C9F6A5753477BE694E3B9127D48C7D9FF -:106320005242121EA4535C83B65C2213D81750FD50 -:10633000E42FA0FDB32CF697168400FE2C6E5FC9E7 -:106340002CCEDF02D56714CFFE694EF9F6B9E45FB3 -:10635000E6F6B88F3E4BB39FB0AE6EFFED3181FBDA -:106360006F19C48FF4E6EF137F6A7FD5F2DB2CBC84 -:10637000E68904F1497EAA249E28E26BA3ED7BDE28 -:10638000CA4EC0BACD8AC89A668A07F36D21D40472 -:10639000F494C33D59F4F9C92725DC2FE52DABBF93 -:1063A00004E6DBDE608E2DB6F983DBE55A0DF04D99 -:1063B000F942B3DB8B1B48F405C1B6FFF2045BC6A0 -:1063C000160F43FE7BBBBB044C8580FCE7F5C78200 -:1063D000AF825CF2FB49FCD8DB52DF766E3EE1F621 -:1063E000F286F2309DB71574D7087C6C0A149ED6DD -:1063F00002D6FE49E3F072B09FAD99ACFD51E33B8C -:10640000E146E48BA816A1F7EA09C74B17C50BD2E2 -:10641000DFC8B7DB57F7D5BDFE1DB2EE033EDBEBA1 -:10642000CFB9AE04EC67991802B4EF8D1DD1D7D85F -:10643000F0F14D4FC51B808F91242110A05F2C17C8 -:10644000E5C7F2E780F1A05DC0E5A9901CC67EA378 -:10645000233DE50ADC5AA1BF0CD796E073D9284F3B -:10646000648E7E12E55F122E5E3E78794FB7DE8035 -:106470004022A9FCF9FBA51C94ABC034BA6E875E20 -:106480002FD4911FF9B85F031A81FEC8A6304D06BC -:106490003D125F114931DE4F0411FB69600FAEA060 -:1064A00068285C56F66F74BD9A169EF22A85CB93C7 -:1064B000EB0F990836B3130697014FBC5103FC92BA -:1064C000A31201F9D70AC391DB804F49242CD0FBDA -:1064D0005A301CDA6AF45D9F4A987DC8A1D78B4C6C -:1064E000BE09F4BF274FC7FE04EC85B5AE31009757 -:1064F0008A707D06F4CE15A70F4CE711A4BD1C8C45 -:10650000593A7A7FD6744EF7BE9BBE0181C9D7FD3A -:106510004DE7C32695A796E3822881528C17235D09 -:10652000344E97F34A5403BF71CB5745B28FB61F11 -:10653000ADEFDF4F89819FE2B1D94D9DD16FE45D11 -:10654000FA5460A174EFEDBA4BAC4CA4E0A74A91A9 -:10655000E9FD2D773D1C1F0BF47CC5B9DF53568533 -:10656000D12FA5FBBE4AA087F59EB798D927B29F29 -:10657000AE87F657B83F723E6F511649318F75DDC1 -:10658000E382BF90E23995DCDC2771FF6A271BDFCD -:10659000F277CE17F43FBE859F0B9522395C8A6453 -:1065A000F59152BE188AF7C2A4DF9D876D0F7F94C4 -:1065B000A8157D04EC5E6167395C15D2D3087CBAFE -:1065C0004B2455A9E05B2B89085F61986E3DA8DEDE -:1065D0002F3445D04CE45EC9C0FBF9AB6A0F2A9456 -:1065E0002EADA34808CCCC25301EE8D5835EB49FE1 -:1065F0006A2E4978A99E7EADE82B26D865BD908489 -:106600000116BD16F69CF43F6A5F0DFA5CD9183589 -:1066100011AE6004F708878A9621BD5BA87FE76109 -:106620000B71F0538B297602DFC6E9F8E00FC68DB7 -:106630000A94D773416AF9E1E7630ABFB5DFB8147A -:10664000E242949400E70419E1A423317AEA0C2F82 -:106650002377CF229DD4EEB466EF427930AF242861 -:10666000AF32396C0A6067E48429527863554C1F55 -:1066700028B971C16EC7F690E88376BE91F54EF4E5 -:10668000FF5AFF2CAD4885D76A91E9B7FBB83E3C6D -:10669000AFB4CF477FA399CA4751DFFE614E876FE2 -:1066A000C7163D381EF519B34BD6F32EC170C43151 -:1066B000475E50713D6EBF661EF76B5A0AA95F8335 -:1066C000F24E16801F93C1F9A305B0479F7BB249D4 -:1066D000C2A47064803F43FD1252CAFC128DFE03B7 -:1066E000FD97BFC2E9CF785C7E4B3A7FE66B42E410 -:1066F00007A8EFA8AA02F8770BF1F9E300DF057409 -:106700003F69F45D7717DF4FCE95B615B550B81ECB -:10671000CB151DFC309ACBCB63C43C71913E8F17D7 -:106720008A06C01DAF17711DE70CE6B79377BD0E43 -:106730003BD16C2ED2884DFFECE0F2B4AD4173C872 -:10674000ADFBEA57E3D1480ABDA573FA64CC0A63EE -:10675000FCC31F4A20FD619DA9FCF4074A2BB4FE2F -:10676000F49F5CA2AE41FC15569C92E15AE6DE2FE6 -:10677000A51ED77D25763F534ADF6FB0D72D144F26 -:106780006F2B0E7FBC53827D9749D0FFF386A8A95B -:106790000AC0551F0EF07B4354DCE0DA5D5E09F75A -:1067A0008D59110DE4C8B2CFDE50642BDCCFFA92C4 -:1067B000BC05E8E52D174589D24F934D9263939B15 -:1067C000A970D3C6DF99545DDAF1A145BF52097EA5 -:1067D0002A2914C9580AC7E68F1B343B9DBAE836EC -:1067E00084ED5B9D7C13AFEF5FCF7E5ABEF8B96836 -:1067F000C5439CF4C21F7B3C84D33949FF3E718D55 -:10680000FF1CF4D638FD0C4ABF4D06D093E90BBAF5 -:10681000F142FF21AE996168C70D43346D7AEC6394 -:106820003107F1205F90512FED5ED312067AE974A3 -:106830000C202DBD8653D9ED2E4145B9A27AE32A0D -:10684000693A2A6401E29F73A58D48EFC728BD41CC -:106850008F3D466ABB2EE6F6CABF1655D18FEF6A4A -:1068600034CB1B8B87A237297CD4AF237B98FF7254 -:1068700089E5BFFC3DE59341F82BE7A9D1E0F6D8C7 -:106880000B7C25775396A670156E6476137CB51C29 -:10689000DA36A8DDEB147AF9D1C3E7514A1387C77A -:1068A00023BD9DF6E9B1C297050FD8B76266DF54E4 -:1068B000B3330C7A26504CED1341FBB31AF033A2DC -:1068C000245E0EED91BBE7E13ABE0D7EA81FEC0BF6 -:1068D000417C7C534C349A9466BE70A4539460FF00 -:1068E0004C707F67D1CF3D2FB57A484F5FB6B81750 -:1068F000E814A83D0CCBB4DBBD6A29AFD71E8E28A7 -:10690000E94475EBF617D2FA097F96F87E6C666358 -:1069100098B647C1AFD49FDC293EDE08FBB188277B -:106920005C8F7477ED239271281EEF5E5B6609958C -:10693000B1FC37749E3BBB140A00013F40B2C781D3 -:10694000EE04BB44F5CD5A6ED76E2591003C3C4316 -:10695000448CAF9D21470257D8F870A7A4B2795A4A -:1069600095B7217E6FC5776F8BB3B6A57FEED8ED57 -:106970006CDF4E160D87F8EDED3B155CFF9DAE7D8F -:106980006B4CD271DC3B486D0BE0A15921E827AC80 -:10699000D5890CF1D80D3FFCCE0CD8277C9BDB951C -:1069A0000F287F1936FDB3CE9F50613FFB4EC715B0 -:1069B000CBAE26F07EA26504ECCBB3494A3B7A4BC2 -:1069C000AB13BE81E077C34BC8A67EE190DB849415 -:1069D000F1C3A724C11137ACD70293206872DECB74 -:1069E000AE6605D31FE66FBD8926F0132583F7AF8A -:1069F0009DCCF21CB533E13AD07B3FE3FEE850DF9B -:106A00003B9CE6BD0D5AB70AFC5F239B9582D81BC1 -:106A1000AFD294DAF04890E303E59D2389A35FEBBE -:106A200020FB558AFDF473C37B4AD74C71725FB863 -:106A30006F20D1B740EECE8BD16A8C1370B83D80F9 -:106A40006709AE32D213E3274530AFBF55C882384D -:106A50004A07FA275E4376D0BBC6D203542F41DCE7 -:106A600027A3C4F9DC1D57E949D2B513E50B43A2AE -:106A7000744901CDDF2981BF58269F4EF6A7F355F3 -:106A8000C3BA266327D42F755CBF5413E3C159D30F -:106A900050BE305E57377F8C0970D4E51921D30082 -:106AA000351A0AE3182EBEAAB92090846DFF5D2323 -:106AB000F7A8204735547FDBEFDF1364F1E4747AE5 -:106AC0005B219AE12F01BF56443C493A6DDBD6FD6C -:106AD000515CA86C67FBAAAC25FDEC8BEF09B27882 -:106AE000F1DA2D63B358DCC5A9AFCE72FBF0936722 -:106AF0001E57BB41CF3C7DE27A58E7FAFF29118D42 -:106B0000CE7BF6994CD2897623A182DD58D721A578 -:106B1000B4878434B1FCF9F732915EEB9EF324160E -:106B2000D0F7D7BDF0CE2442E13BBBA9E7B591E059 -:106B30004F3F2DB0B8B8D93D6931BDBF4E26AB53DC -:106B4000C55926C86C1F72FA47192B407E85B6833B -:106B500037E3B8EDCB15B0AB563F4356905F693F76 -:106B6000B4DBE6534262AC900A3E968F38FD94C087 -:106B7000E03BA0E0FE6F5DDB5E354AE1A869FB10FB -:106B8000F5C5ECEF3D1B003CD41C901C7E5C4D9B7E -:106B9000D4E99984D713708538AB3003F884F34B6C -:106BA000C7068CAF56B73FF0A11480F79D7A8BE2F1 -:106BB00025D409787D530A2D80F60FFE316050549C -:106BC0007D70F88900E0958EBB46CD8238BE93BFBC -:106BD00061FC0B397DC7A39C8EF9DE9AF62D6C3EC5 -:106BE000975EFC007E29E81B878DC8CE3C3A691B66 -:106BF0005C9E77FDB3E71E35E97CA79FFBFDA326CE -:106C000085FBAEBFFCFBA35F07B9FC67AF0E7ABD87 -:106C1000E6E95F06888D0FD7C92C7E707614DD42B9 -:106C2000D17E677FE549804370F6A5F7461B74BDAA -:106C300067BFFFA7E106ED5FF7D2DC7C587FDDF38D -:106C4000B3F3FBF363804F131E3B5C091CDF38205A -:106C50003067E1457E75D1E550C7A1D100E7996362 -:106C60001EDC9FD5D07BF553814E1BD0CE427B23BB -:106C7000C56FF5339B3F04FDD017CFE64811835F06 -:106C8000540D0681CEEFCC437A911EB48FEEFE35C3 -:106C900047291D27A7A7DB39F2B10A7AAEE6992D5D -:106CA0006C3E17DDCEC02F57F6A5DB6617DDCE9103 -:106CB000BB1E2B80C46BC730471EC1BAF6C6CF239C -:106CC00059917EF48325FF03E115F32C14AEA572D0 -:106CD000F81B32C8D1731949BA2E00BA3E7B6E3404 -:106CE000A17CF1BED27333D8839E973CFA3E7A7F63 -:106CF000DD4B6FA25C9D7DFE75D5403B46FC02F5E9 -:106D00002BCF92E4CF61F033AB99CF496AF6677627 -:106D10007A02BDF4A94E2CAC340278FF04DE4F3069 -:106D20007EAF4E1C5C22A4A0D7EBF218A6FF13790D -:106D300088970DFB7FA312BF938E4219D0F1C43CFC -:106D4000B89F8E8ED6FA7558FF4C1B3DF7333975B8 -:106D5000F7AFA6F208F62E49D784F02649219767A7 -:106D6000F77A64B07767C1AF4A993765FECC50F3C4 -:106D70002B3F939DF557C9FC0AC7437AFE60F23D4D -:106D8000D0FA868ABF1FC9068EEBC6E3E98F53EBA4 -:106D9000FBF7B8BEA82666E5884BFBFA2132899836 -:106DA000238B7AE13D0D1B54CA7FA79F96301ED4DA -:106DB000D27E08F5B65B4F54A7896F5E90999F50BD -:106DC0007DE0E024D067A75FFE11F267F53327541A -:106DD0008817BFD6F603B5BBB4571EC01E246CF689 -:106DE000E0F4770F4E627A808E9F824E8AC2C6AFE1 -:106DF00079D1397ECD331F3AC65F6FB6A37F30D0CD -:106E00003C1FC8E1E5B0DE0F0E2B04F4E807ED529D -:106E1000652ABFF6036E0F2D3CB5BC3EEF379007D9 -:106E20009B76C46780DDECD814CEDF0EFEDA1185C8 -:106E300080DE2672F8F71EDAEE78DD67407EBAE370 -:106E4000C832C9B0ED437FE8C2E7CCA3E6EC4C3AC8 -:106E5000DECCEEC8347051DD7AA3EC38DD57D9F8BA -:106E6000A0EEF5CA7CD0F7B00F35C6C37CA120ECEC -:106E700073A5C0BC4A96BF16756F4A7BCDC653FC3E -:106E8000118C5729BA988C91C1B82349A211E2AB51 -:106E9000C4EF77E727229A3D0FB5E2F041D862E6CA -:106EA0002E7EB100C60990987E12FD4F12BAD88F7F -:106EB000FFE5CE4758F84CCA5F9AFC44867E73F0D3 -:106EC00020E93B5EDF3C4C5483F8768B7F6D6B9101 -:106ED0002D0FD312EC938799AB503CB40A2465BCB8 -:106EE00076BC52315FC9C3DD7134D5F39B1426578C -:106EF000D792EE7BD7009C1196CF99E5C2D79738F1 -:106F0000BEFE79325D3855A1E5E05951FCCE5E12E6 -:106F10008E29F4FEDC553D97BF8CDD793EC71C2FD2 -:106F20005ECC183CFE869AB78B7816DDAE0C226FCD -:106F3000972E7FDC0B87C9F7E3398E3CC6A1B7EEED -:106F4000D7BA31CF50DB5A648BFB0DEFF49230E6A9 -:106F5000F10CF40F8777DEF9CDDB20EE9C5B18F2A5 -:106F600092BEE3C817AEC6B89195CF970BC39D10DC -:106F7000EF9775A35CC279968721BFB0D960F9827B -:106F8000CDC1FEE37A339468B382F1A86B705C5193 -:106F9000E3F507835CE737160710CF018A67907720 -:106FA000DCFFC0FA8E0B3C6FDE6D4A903F3C918D4A -:106FB000F982804C4A201E705EF08536613EC19990 -:106FC000374FC7BFDB6513F3E6AD469FBCF97714B7 -:106FD0005BBE414B9337D7FC4B306FAE119BBF5B11 -:106FE000D4DBAF57EE5C7973180BE332DB67435C9D -:106FF000A6399B38F2E6CD20F85711F29C72F56C59 -:10700000AC3BF3F2E7E6ACD9617B9B1C7F19DB3C20 -:10701000FEF4C7E6739BA07FEE48528B756A7284BC -:107020002CB5E9C1F71416A7DDA0847FA8D8EB8E94 -:10703000383F58F99F436FBD877C05D73114AFCDDA -:1070400094AF3CC857A7885DAF5A578B7F9A8DFE87 -:10705000F942BD3005E366C976D044BE0804A3E119 -:10706000708AF7267998DC5BF306CAA81EA5F2A6FB -:107070001811CC47A93ADDF01A83873F1D5C169F93 -:10708000361B63581D944EB07E2FFD3AA6B13826AC -:1070900044B8285CBB6EBC3DD49F9F63AD73861221 -:1070A0003E69C77BEE25A9EB77AB55B6EEE6C82A5D -:1070B000965FAF72E653217D6D8FB34E17A2FFAE80 -:1070C000609C90E553452DC2F323A6151F0F26E3C0 -:1070D000E106D419DE65823E5456B59B025C7359B5 -:1070E0003E25578B7EACD8EC83AC7733B975E5077A -:1070F000E74AA787845FAB2E6E6B838E7EFA9686F7 -:1071000020B6373718786D6908E37D371D9B8D975A -:1071100083B7605D9A0FE3B2E9C67FB02184E3C410 -:107120001ACAD8783C6F4E486613F0952A5AF23244 -:107130000CDB7E893F370B9A40FEB60BECF9352D00 -:1071400097A2BC59FCB3C3E83F2E2D2566201F0C27 -:1071500075FCBEFCFA135C67F32C3FEAD781E42888 -:10716000AB93CD3BD87994A4BD60F3EC98A5E13CFA -:107170003B72079827CEE619187E86AF6D074F61E0 -:107180001D8242F9015494A28753D7E97179EB3BF0 -:107190008E07F57C7390D585A9C5FE3028FF6683E0 -:1071A000E71B0B59BE512D195E01F7D5D065582745 -:1071B000AE96FA319FA7160FBF05DADB0E6ED12B04 -:1071C000C07E148A21AF0176BB9BC8B9283618BF90 -:1071D000558B4B6E83FE3AC83185639487EDB7D4E7 -:1071E000E2ABEE80F70F4E79CD68A2FD9B0B7D21BF -:1071F0000FC85BB7ECE0FF41EB8942671E8DC854B6 -:107200005F50FDB56DCAED25289F9AAD4E3245BD44 -:10721000A04D6F6C506D7A4325734CC0433ABD430B -:10722000EDEF7D6A5EDF71ACF73728917A15F54294 -:107230008438EBDD53E7B32D7A809B05F948399804 -:10724000ACD35B5030BC37BF6DD5E9B9F3DA71FA16 -:107250002F555EDB5D7FFE59D5E9ED5493757AA31A -:10726000A04EEFC70A0975425EFE9752689FD197FC -:10727000EFDCE3B9CF5B50FF47837D4E3AB9FC9911 -:10728000EACC9F16445D74BFD5EB98EF159097D26A -:1072900081F5CBC82AE738A36A9D75B597D4E7383E -:1072A000DA45E60847FF4B5BC7389E8F8D5FE6786F -:1072B0003E7EF754477B42E22A47FFCBDB2A1CED98 -:1072C00089EDD739FA4F3EB0C8D19ED2B9D2D1FF9D -:1072D0008AAEB58EE7D30FAF733C9F79EC1E47FBA8 -:1072E000CAEEAF39FAD753774805B9CDE575C8B9B5 -:1072F000F9A23D4FDB9A47ED12DDE7EFC8A30C83FF -:10730000F16F56D7A5B2C7C9BCA1FB3DD950C33A4E -:10731000E6FDC7CD812B91EBD09ECAC6F00A03EFE4 -:10732000CF98075732CD595FAB1AAC3E19F671CEE4 -:107330007A01679DB12A6DC33C9DE7F897BB8449EC -:107340007DE9AA163AE560B075CA8AE17A6F88725B -:1073500071DE928B51542E30FEF6B184E75AE6640A -:10736000A27F61DB4F211EADFDD4351A89818B6967 -:10737000C945F9AA9E91AF62376B1FE51187521775 -:1073800067C95FC0A6F761BF62E999E6B2C1E95774 -:10739000297185C39F745F9B02EBD2E9C7028FCD31 -:1073A000BF77EBC7194AA4109E6B72D824B6780D2C -:1073B000A9551C700F16CE4F6A07EEA20C4752E873 -:1073C0007195D462DD55CB8A300601481D71F0E914 -:1073D000CEC5FFA30CC6A57EE10CE73A995FE8F69F -:1073E000A7A97E437F7A07F5A7D1DEB9F423D55349 -:1073F00026AFFF32981FC1F4A17B9D9F971FFD6FA1 -:10740000E0ACF643AF4051A812F787792281FD61C5 -:10741000F3AC4810E27356DDBCF55EABE7521C27B7 -:1074200096AB8A10BF8C75CDC5787D9316D5589EC6 -:10743000388AE334658B7AAA3AB13A0FCB176BF5E9 -:107440000F8CDDDF4FDC45534934553C6DA787E594 -:107450008362FADA2EB0A39979AA017BEED683A7CC -:1074600022104792CB641DF6EB8402F38E2DBF47AA -:107470004814E34C5A5044BBABD5EFC0F90782F730 -:10748000668FC0CF7D6CE9175EAF9A3AEE920EDE42 -:107490002D00EFB481E1F502BC4530FF369CBFC63C -:1074A00063A4C4BF42C295B3816E27BE1CC1742BB6 -:1074B000651B908F1D656C5F4E0D8183BFAD7D0E8A -:1074C000E5EF873D7958BF8A7C6D9D73B8D1A3E302 -:1074D0003C165D49610EC63502D1D8D862CA6F9993 -:1074E00051B69FEFD54F8C8F329530817896EC173F -:1074F000313FA8F27888D5EF0F1C9F4DB3BA915E4B -:107500009BAF94C926A1B7CE3A5648D735B9775D17 -:10751000FFC793CDF893CFEB234BB2B02E457A261D -:10752000D89FDEF6717CB9F5F7F73C5C7F179002C7 -:10753000A6BF4B9743BE3BDD386E3FA69EC77987FB -:107540005E5FCFCF17F8EFE982389315E723C16963 -:1075500029E3F2BD7865F9CA5EFA2E373A29FDE4CF -:10756000E953314F6E9D57A0EACC592FCCE96BD12E -:10757000D58AA393208B1F5974F626F1B9A75F7C97 -:107580007A415EAEE88BCF5F7978BEE1BF183E5F8F -:10759000019F865E3333D9F97472E8AB04F35285E8 -:1075A0004E39B4DEB3F8DDBDFE3FFD17E5276BFDB8 -:1075B000163FA4EF6FA6DCD758F9D54CCE6F1A9CB6 -:1075C000B2A28AE7D5B2B75B2F85FD6BD08FFBBE29 -:1075D000CCB2189EEF5588A9835EC8B4F635FCBCC2 -:1075E0009155AFE42B75FA659A6BFFA2F2BAA83EEB -:1075F000E76DB9FFE63E4795C4AF8B5E93B534F9AE -:10760000B1419E3FDAC5F3750575F146D80F17DC19 -:10761000CAEAFDF7286435D4578EA832455F2EE4B8 -:107620006F8ABE9F41D75FF0E2438D238124B71A52 -:1076300045E0663CA3190E3B5C7057BCDCC79E4F0F -:1076400081719ED298DE2DA88CE339E7A6E7C76743 -:10765000819FF0CA5BCB75880F7C945B8CFBA73352 -:107660002F78C2A0FFCFE4902AAC0B7B61E66BE0E1 -:10767000C7FFBEA12B47B6F1C999EFBE3E43A14457 -:107680003AF3DCEB33642456C231FF868BBF98019A -:10769000709B15A4A416F277BA4A60DC1A8DE5CB6C -:1076A000AC7A9F5DC3D516B8FED49BCDE289F9E2D2 -:1076B0000E68D743400CFC061ECFBFFAB4B11CEADB -:1076C0002FB3BB1401EAF11E124CD34FAFE74F3C6E -:1076D00024809FA576D6429885DE0F1D02949B6379 -:1076E000D9BEE47C112929A27ADF77B8763CFAD397 -:1076F000AE7A278BFFE5D904F37D3D376A09B0D711 -:10770000DB65E31BABC07EAF92B11E67BB7C18E5A7 -:10771000C24DC7E3DE31CEFA5C1E8F3EF4D61DF1BA -:1077200072FAFE3D5344E457FF8929592485FC6EC3 -:107730006F28C3F903056F579603581FD3BB337ADD -:10774000F7497E999859D4442A45A2A950BCF8CB50 -:107750000879DBC6772D2209EBF4F90B0D04C7E994 -:1077600068D0F0DAD6A08F2DA61B836F3504F1BA4E -:10777000B3C1C0EBC30D25F8FCC1869043EE61BEDA -:10778000B74B783B85BFF2795D1F68A0F3DAE0D88C -:1077900035914A3DA5D72E9E8F7AA0746AD6DA7E9F -:1077A000E2607B1ABA86CD19CB9105F5A675FADE93 -:1077B000ADFDC0BFA75158BD08FC9ABBE5C83ED47B -:1077C0008FD1824536FD48FDB6024259F1DE961151 -:1077D00073E614A03CA2BC4C3B1C457FBC20181790 -:1077E000208E587094DDB7CE5B20BDA8A0FD307709 -:1077F0008EA080DE2C25ED00965A1A2515B4FFCCFC -:10780000BC25E5709F4C74DE9FA132F986712BE890 -:1078100075B616F991361DBED3B1DB7C96AEE78FF7 -:107820001D1E03F23C0FBEFC2715F605B15FA91A19 -:10783000F831052F9EC0BA8798D0AD4265EC71AD86 -:107840007A8E4CF50C6E0631BE4A150BE59318E89E -:10785000588C7FF6C4E6F8E1BC4BF494BDFF2E5F74 -:10786000F46E7E7224AC05291F25F317EB6361BA11 -:10787000E97C81E72F8E6BEB626621B469FF29AC4E -:107880001DA3EFBF901D1D296643D14555ACEB4BA1 -:10789000D0B6FA57C5A0DEF64DAE77883F5A04F24F -:1078A000966CEBB49D696BCBAC4D3476B5D6BBE131 -:1078B000D09F5E033D57FDA2D00EA051BDC7F07F03 -:1078C000E021ACBB6D6BE8D2630AA7BF45072A92E3 -:1078D000138204EBE9D484901843F5C704FE7D8A33 -:1078E000826961A311F46B420981DE0CF998DF38DB -:1078F0002141C7B1C9D58434DF41C1BC2FD0711B30 -:10790000AB1B76F3D7B35E961FA827E656C88391C4 -:1079100067141DF3913C4E79DAB2737CBF7A979766 -:1079200035954DA6EF32D03F6B648C83AD2F8A978F -:10793000AB749EF53F2A0A51CB0A7925AC6B589F50 -:10794000DD3E7C2ACB4B39DA0FF13ADA60B6990D7D -:10795000E707AA0F3C341AEA02AA49FCE6AF01BCC9 -:10796000FFCAF28FA70E5E9975356D6FA06D88BF47 -:107970006EE8785D8DD27EC338DCD51D53AE83F5BD -:10798000556F138958C4E4333C9EE2391CBF4CA6A2 -:107990007C72CDD69173BD94CE4F8D09EB22E583D9 -:1079A00095BE71CD1AB4557D02C8CD4ADFC466E0DC -:1079B000ABF513F9F71AC8C457C332AF97A27C319D -:1079C0006C4B430CEA13F6AFACBC0ECCEC7091C917 -:1079D0002D6544CC1F4AD931CC5BFCA1999D7781A0 -:1079E00094FE464A87629974C9F4BA4B65F4335BD6 -:1079F000648C17D3FBADCA54A04B3C8CE72B5A992F -:107A0000DE1FFBA207E3CEC5B5E13BD12FD04B7102 -:107A10009F329A247F302F7D09FC46C719AF93729D -:107A20003887F0632F8B1716AF58B61EDE93329748 -:107A3000F8705F2EB17350E4DB2C4EBD4B4CB46B31 -:107A400020E78162A4EFAE00E30BF3E152E48BFD8B -:107A500062C56577435C5258B3F55F80AED9C50403 -:107A6000E80AF7EFA1F7F7737A4AD9211DE8B79F23 -:107A7000D33396104DA88FB1EEBF20ACBD13E46D8B -:107A80009DF7F9391AC5EB704F383E8CD2E14EEFB5 -:107A9000F3B16001D2618C46F17EE7968E98368A0A -:107AA0008ED3181EA1DBDAE3FF4CBD11CC4F76A0BC -:107AB0003CCBD90FAF0379A7CF5FD1E83A9FCAE19A -:107AC000FA823F2F1E93D41F61426D8DD4D8AB4FE5 -:107AD000346A1F8A6DFDE7507DF0E4A3AC8EFD7A19 -:107AE0003A1FC83B5D07E67F7B26C809A8CFF25145 -:107AF00058C06FF14D1C83F57974DD04FC929E89AA -:107B000032DA592B8EED9920627C09FA033FF84650 -:107B1000B1FE545022A037E54219F7ABB2B4273C6E -:107B2000C180F031CBEB0AFA423CB7EA2DB1E571E6 -:107B3000496F1D30B68BF033378EF6584F7781483A -:107B4000FDCADCE30B85D174BC3BBCDCDFCEA5FEFB -:107B500036BDBFDECBF4D2FD11F3CB10E220467769 -:107B600001EA2712990AD7FC9B8AF3A3FDD8A5BE88 -:107B70007E7537FA0F3BFCA9CF694EF7B1FD7C93B8 -:107B8000FF880EFC564FA8FC835CE88CDF2CFD615F -:107B90009D4F70D7135BFA44C9666BAC9B5F910F26 -:107BA0007A40E6F549B21ED2A1BEB23C731AFA7D04 -:107BB0004F7A99DE930E5E79039CD350FF95E5854D -:107BC000F678A3184FEA2920EDC0AF72304CECF9DB -:107BD0005F4B1FB43468787D62EAB80A909327A699 -:107BE0000EAFD0A90C1C9AF4E32EC8339DDBC3E47E -:107BF000F7DCE1DBF0FCE33993C59B80AD302ED997 -:107C0000F9089ED77D5C8E3C8875B5501F4141DADE -:107C100096EDACDF2AE67831B97E6A56D8F3CD0D01 -:107C20002C7EAC5EB81CE35A2AD7E39EE8AD786E92 -:107C3000C3436D199CAFD48869B2EF1D303C688591 -:107C4000CEEF61A81726E1FBA697C58FAC7A117716 -:107C50005D8805CF0C0E4FDF73194E7A58FB2F8BC2 -:107C60000ED6FB7542385FEF876F6A2E4824618B12 -:107C70007FF4D677AB78FF2CD4C567411D4F347E97 -:107C80007511C84102F7475E7F1D21FCFB4AC8A75A -:107C900041B9C75E879EE1AA8BEF232F86B3EDAE75 -:107CA0008B580FCCC1EBF8B09E5526DF1428BDCF02 -:107CB00064FC7606F8B535543D681020924D1DE6FB -:107CC0003FCBFD7DF9C5BBC3230D1B9F0B86639F77 -:107CD000507D6021C6116AF6FBB1DEBF1AF4DF6485 -:107CE00038376076791CE705C29D509FA71C60E37A -:107CF0003D09F0D0FB7FD4AB0A60DDC761FF93077D -:107D0000F6242AB1432F87110F316FF818D1993E0D -:107D100093294FC4B22D7D561D830DC32E9538FC7B -:107D2000A55D3EDEF655C762A5BDF51FC7B5FF8749 -:107D3000FACDAAEF38AEFD07FA43BBD47827E83B6B -:107D4000F3058F01F68BBE8FE777CD952568076227 -:107D5000456404E0E1956C15F55CEC79CF3ED07399 -:107D6000B3B5E89B9A6DDF7026FB8DD1B0FF4A3129 -:107D70009EE9186FD4D0C6A3F377005EADE7AF6479 -:107D8000EFC2738BF43D03F386858747AFA1EDE126 -:107D90002F78F0DC90B5DF74F3653E97AF16D77996 -:107DA0004015E4CD0FFAB616E5CC1374E6C12CB934 -:107DB000532F4C70E4039E043B4BE9A7CA51085172 -:107DC000D2E7A5F8DCE47CD6C2EB11D2CF93936660 -:107DD0009E2B509ED3CF3383CB3BE1722CEBC9EF6C -:107DE000C2F4736ED09D2771EB29EB6AE9A96F711C -:107DF000FE9449F40A1F9D675DA27D9E0FDF8E4EA3 -:107E0000023FF8038D9D832A697BE86530CFDFF45C -:107E100084EFF74EC7735FFFE4CD1BBA3CACF4119F -:107E20005E97D9470F31FFEA56E6AFD6CD9F8AFE5F -:107E30005DDDF631BAFD9CA2FB5A7521C3A1878690 -:107E4000790DFEBD3D13F551D585003EFFECE6F3FF -:107E50003ACEAFF49DCF8FCFADF9EE72E9D943930F -:107E60007EBA0BCEB9D77D5F113DB679EABECFEBB6 -:107E7000FFBD54EF3AE53D0CF22E1791647D17E8F3 -:107E8000876DAAD50E37CF99057EAD4D3F9481FF02 -:107E9000D5FB3E7CE76E9B8FF7372B53F7CF70F502 -:107EA0001F638DBF10FBBBE149EA1FD88FD1FEF2E3 -:107EB0009F3D167CA8BF1E125DE3E558F3DF88E303 -:107EC000597EF7456DEDABA60C7C1A2F87FD53CF7D -:107ED0006DC480EF4F3C2E877C213BDF6A8C5FAB0B -:107EE0002E5CEAA0772FDEC739EEBFD71074D4EB33 -:107EF000DE11ADC33AED8B3CFE54453D737C6FCF34 -:107F000048479DEEDFE0F8A4705C9D068E6BBE6076 -:107F1000388A1CF2D90B47B1E3FE278563A1C6F46A -:107F2000D7727E9DABB373B3730D21D4446FCDA5CF -:107F3000F7BD94D7BF4CAF1ABDCE9589E9C7EFA264 -:107F400026587FDA86FDFD0D7FBEF7DD6B315115BA -:107F500074D41548BCCEDBAD77E09C37AB77D31C2F -:107F6000DF87B3AE3E89D56BBAEF7FE86378F9C699 -:107F7000E5D504FC69EAABA73CB7B6CB2FF0EF7DA3 -:107F80000645479C9BB7AD3ADFCF0A2E3983CDF724 -:107F90008DCBAF2710D79573537FDFEEA09FC1DF46 -:107FA000A285B14E3CA6F7FF5D9A4F0ACFF0243C64 -:107FB000D7209EA43478AAB5E0D1595EB025F8F94F -:107FC000C0539261D1AD7FFC6CE570930B97201F7D -:107FD000499C4E2DB07F4BD1DFCA7FB4689F2FFCE8 -:107FE000E141D2F7B98C2F86BE8B0649DF622E079E -:107FF0002DFAE70BCFAD8384E73A8BDF8261A4D7FC -:10800000E705CF570609CF318B5EC6E78B9FD62495 -:10801000FFF70FCF5F38DCF9192C0ED252C2CE9386 -:10802000F8A4C88345C2C072E12B76EEB3B5429F77 -:10803000B3CEE65D67DD57BA75FE9AAF339D3CADB2 -:1080400054127940BF630D2C1EF006DF9FFCBAAAC4 -:108050002913E3F3AE795A82FB32FB8BDBFCF72A60 -:10806000E7B9DC81E4785206CBFFDC1875BEB77C3B -:108070004586AB8ECCC47E16FED28DF7D782B73044 -:1080800024310781378AAFACA27EF60D9F35BED270 -:10809000C9DD50F115D38786AF81E4FD2B43C4972A -:1080A00025AF7FADF8CA077C4DFF1B7F0D165F8B98 -:1080B000FE268F43C2D7AD439547EED7FEB5E26BA0 -:1080C000B0F2E8DEB7D1FD5DA8BFEF0B7CD6F87348 -:1080D000CFFF69F1688DB732CD3E2F1D3E0782C3B9 -:1080E000BA7EE81B245EDDFBCF2F1AAFAEF93F3519 -:1080F0005EF97843C6EB007058577990F26DF975C8 -:108100006D6AEAEF888ECB64DF711B2FD41E990F46 -:10811000F9E3BF93303F7D64CF9C0DF67AA071994F -:10812000CCDF3E52397B03C44FCF4532B0F6ECA8CA -:1081300018FAF934C82B2F62EFB9C73FC2F1E5C96D -:10814000CCB6E2BF7940D7A391C5FDCA23A9B4AD8F -:108150000BF34636FA4A7DF17D8418DBA7411E6297 -:10816000416A382C3AA79B77A8F43D1A797C48FAE3 -:1081700067A0F5FE877FCC20F54F02FBE592E4DF98 -:10818000DDB90CF0D926B27AB8E370AB00BEEB468D -:10819000B0D3F215F97B814E7767B2FC61876A6CC8 -:1081A00080FC8967F182073229DD8E2ECD16ECE73F -:1081B0002FE764B2FDD78C55A9F75D0B391FF4BECC -:1081C0002F90F129F83BCCFB2D5DC5BE3F46E4F076 -:1081D000A845B673A7EB5DCFFBD0233380701C4D51 -:1081E00073EE7F017F7FF992FEDF27B5ECFB3E94B3 -:1081F000EF46D9CFBD26F98CCBC7197F746926BD50 -:10820000BE2144BF731FF0D1043F3B37249322A803 -:10821000BFB2C6C99549A74AF1FEAE628C82BC6660 -:108220008A716ECE9C9E7E9C7478B5D663CD03A277 -:1082300008DFE999ABB138E2B43021B3207EE80918 -:10824000DDCDF2878C0F72781DE2CCDA8C4423EC02 -:108250007B65BA4E1BBC1DFF77F67F83E71D474445 -:108260001DCFB7BBF030907E68CA64F9E45C29BAD0 -:10827000C90B7993D542CAEFD86DCC647FEF6852B1 -:1082800066B25E0AE719B733AAC0F72F96C92CFF6A -:10829000454874D442DBFC9338BFB9DFCB9558BD59 -:1082A000117993C973DBBE75A352C9CF2FB89C4E09 -:1082B000CA2C71D4392E89DCAD807C2E59B0503156 -:1082C000FCF0DCC0F1977238DAD4E8A829FE5E3CF5 -:1082D000A5D5431C3F1DC7A24DF0DD8FD5F502D6B5 -:1082E00009946E647CB77AE3417103BDEEE5F2B7A1 -:1082F0001068601BEFBB9CAE6DFB7CA301FEB664F7 -:10830000FE860E4CE1B87937C17CC893DB4FB7408D -:108310003EA45B203C7F726325D43574F3FAB69794 -:10832000E9F346C0DF9C3C94EF711B3FAC03FDDCDE -:10833000A1123C2FF3BB2D9E049C27B0F825A92742 -:10834000369E6F80FAE147D4CE89C037794DB5F7B4 -:10835000A5CA9FBEC4E9F0477F242B951F685D2DF9 -:108360007D6EF55B241B4AAAFE8B2B5D768DC33D8B -:10837000CCD37986A4C86326F930D1BF9FF64BAE23 -:10838000C77FE1CAF32E39963ACEF82BCEBF6D895E -:108390008AF568B74C0F9E43B1E0B1F0956B323C63 -:1083A0002D5B2239F4EDEA05192EBF87E1F5068F22 -:1083B000F128ACE3917D3F9D88E7A85CF6C1274595 -:1083C00055787E07E954404FBC2F19787DA3C1F939 -:1083D000775EDE20D1EDD3C17ED64B29E5EA8F9CB6 -:1083E0007FDE5871CB52843F26E900FF8955C3AE2A -:1083F0002F03FDB24209C177D34FC4EECDBCCDB639 -:10840000FEA45FE382EBD755B7F46BB796AF70D29B -:10841000AD4D657E81791D93C33B298FCE42FEEA27 -:10842000DE3E93CE7F249133652BEB4EE0EF4C2D57 -:10843000E6BFBF2F4677CCA4FAE694C8F224E657ED -:1084400098DE58B233D20CA9D353F557BCD44DFBA8 -:1084500079038CEF7E5BDFBF7D74F3D3B89D4E7FD5 -:108460006FC631A2C2FBD1BAD4F6E0DB7A06FF7B3D -:1084700062A1D1A05F6EDA98BADFFF0266A6F09C17 -:10848000FA8B54952A3E7995CEE05D1D49FDFE5547 -:108490007A267B0E7629059ECF0532B89ED3478378 -:1084A0009E5E9D06DE0F030184F79DE6FB6F823A18 -:1084B00090F75DDF817F27C0F8E26080F1F7A97D4A -:1084C0002B953CA0538BA0033FBC9D1D9A00FCB68E -:1084D000267602CFBB1CE0787ED3179912980EF255 -:1084E000B2686E1EA54BC72A12128CF4FAFFCA009E -:1084F000F31B7279BC96DABF77C1FED157DF45FF17 -:10850000430E8FBE71222B81823AF053A2B90EEB3B -:108510000CF7F9585D29094DB7FBF15FE6709CDA5D -:108520003F347A2F8DB8FCA03EFE5FBC1AE7DD9F7A -:10853000A1435DCA914AA9F35A0AE4C9FD19F87D1D -:108540005CB75CA49B7FA87EE0A9FD43F303075AB8 -:10855000F78640D1A0FCC073958FEC980672A4C634 -:1085600027A5D2BF969E3ECAE3EF6EFEB1AE5FE591 -:108570007CF47EA27FB8EED8ED84E7A65A273C961D -:10858000BCBC9F68F2AD013C91CE8976BF94CC997A -:108590003E809D65F9A974706E77E909E03CA0C33F -:1085A0009D5CDFFCB6FE91809D0EEEF59F12F9FEFC -:1085B000E05156973B36B2A622CFE8E5CF6F7D4E0D -:1085C0007C69D919F738FFD9F9D0B27303F1616E1C -:1085D0009A3CCE2438E84CDF5F23EB2AE4EB2705F6 -:1085E0000CD626FA3C38AA45CA78DD283146C3F9AC -:1085F000AF53FB7CF8F7A1CCAD9EC4582A02EFEF35 -:10860000BB7A827D3DBFE27CBA7A49367E7EE27DCE -:1086100031343F1FEBCE24FC8EDB1BC772E641FBDF -:1086200091C32268687253DD1A09D6F74680ED3B84 -:10863000576F7C1DFDC1A1F2F9EA5AA7FDBF8AAFB1 -:1086400023E967C93DD3807FD2E1E1358E87A591CB -:108650008573413FDFB251407DFB1318872EE4162E -:10866000398C7A9BC4987D241AC50735212760115F -:10867000808F7FE0DFAD9223AAFD9CDC6DDBEE9F57 -:108680000BFEA15B5E5664313EAEC86276E14D5F83 -:10869000F40FA0EF2DFDFCB6507B309F76D918D09B -:1086A000ADEF04A39C5AEBD9C8E1A27EDAB3F8FD82 -:1086B00062BE3ED2E3E237315EFD63C07F85867ED7 -:1086C00081CF43F53ED4453FEEC33A2A4BAE2C7FD3 -:1086D000C7FDFE3239EAF01B33B38A1CFEBBDB0F49 -:1086E000F99BBD48DDFF8AAC2FD65E5C9BF5D9D8DF -:1086F0008B619CCFDC762329D72DEC3CC889631F86 -:10870000CD4D25D7914F08875B9EDFDFE763DF4DB7 -:10871000BE2613F54EEF7E2A3F01FB65B75CC07E97 -:108720000ABEFBF1C8BE9F4D84BADE13DBEFBF2942 -:10873000153D67E9CC6F22DDF98E78DEDA00C1FAEB -:108740006F42E77BC236BEF55E525E06885F2E5BE7 -:108750007925EE27DF5879F5E835A57DF7157DFAFF -:108760000BD17F580AF336F2FDF40E4FD5BE54FB01 -:10877000408ED7BE7162A77FBF746379336CA9370F -:10878000655CF3A5688AF993FB9A8DA9E3710F7272 -:108790003D95DCD798745F43F1D1BD4A0A944DEB07 -:1087A000DDD7749B9FCFBEE677A4E7E73351FE5336 -:1087B000C3F73D8BBFD4E88E2B297CA7E8FEC70406 -:1087C000F911E97BC02FDF4ABD5F7B9CBFF7BB8DF2 -:1087D00043D457C79CFB9974F2F7BDCF48FEDAD457 -:1087E0009E51A0077EB7F7E3B7EE87F5ECF521BE03 -:1087F000DDE3447489EF2F7CC8B7967DEE5099FE77 -:10880000FFDDDF8DC0BF9BED960F42E2D75F459F36 -:108810001FDF274E81EF2CB6EDCBA84AB5CF59AF5D -:108820000B3CBEE48CF710EEDF2DE5FCA6EF7BBA27 -:10883000D61E8F7E93EB2B2B0EF0BFB3989D5DB2AF -:1088400060A10AF19EDB92F126829B15FDB2C2BDAA -:10885000F0FD8B5FF2F35CE6DACC94E7E37EC3F1E4 -:108860003B501C62C52A679C60C982FEEDCDC9449D -:10887000EABA2C8B9FD3CD3754FBD296185A5E6C34 -:10888000A0758ED007675F9692DA2F41BC631909F5 -:1088900029705D426A27FE98A2F2E4EEC508CF2F48 -:1088A000ADBF7FFCF1BD13ED7ECCFF0710F667274F -:1088B00000800000000000001F8B08000000000086 -:1088C000000BDD7D0B7854459670DDBEFD4AD24924 -:1088D0003A9DEEBC091D020818620742001FD02114 -:1088E0004482B2DA810041519A87184948A2E2CA0B -:1088F000FEBA438720467466C2AA8CBFE3B80D82D5 -:10890000EB286AA2D1418CD8A0F8D8D59DA0AE8B17 -:10891000B3E846C7415E4322A32BB3CB0CFF39A774 -:10892000AAD2F7DE744370C7FDF6FBE338D7BAB7B7 -:108930009EE77D4E9DAAB63915C63C8C7D5B73FBC8 -:108940005F4D628CFDABB579BCD3C1D859FC9B1E81 -:108950007DFECB3AC6221731F6E13A3B8BD8A01CFC -:1089600036558563D4FB53AA8931E8E85FE1C14AF3 -:10897000190B2D50C33B94C1F5B2705CACB7785E57 -:108980006A30463FF2B9A04665113BA3BFB3F06F12 -:10899000CD9C245DF922A753F4D39A182C62EC885D -:1089A0001CF7513EEE91307F2FFBBB488C7B247C23 -:1089B000EE716F7E04C61D131DE78666FDB8BD2CE3 -:1089C000B48AB9619C70A2734701C3FF8CD8264456 -:1089D000DBEF759A08AEEC48A689653076876C1B8C -:1089E00067BC0F057C8DF56BCC7E8B161FB7A77A05 -:1089F00069FEB25C33473F4F6F8A938FCB9CF981FE -:108A000064C68E6E4BF4133CA6258747C13C2BED04 -:108A10002CE480793EF8E4C59FB1118C2D13F8AF9A -:108A2000097C6D41781C35F5DF938CEBFAC0E4DCF2 -:108A30000143951DF45BB4F0BB2B85C3EFE8F673DF -:108A4000C3EFAE143ECF7955FAF9CD3F98A82B1B52 -:108A5000D7FBEF7F7BEF04ECF7DFFFF63B8BB6FF36 -:108A600005A77359243D5A5E52ABF8C34583C77DB1 -:108A700029D53A24B8BF6480E392D3F9D4BF5B65AB -:108A8000CD1D31D655EEB453FDF981728B07E0B997 -:108A9000FC6EC5A74017339CBC9FE566E6EF80F9E6 -:108AA00030B337BF1AE0EE696DBE2310A39FFF23DA -:108AB000E0FD8D23901A8BCFE4F363410FB2DE0209 -:108AC00073D012ABFEC25A3D7C7B19AB8A35FF1FB7 -:108AD0003B395F0E951EE5F8C6FA439DC7DD820E51 -:108AE000D36D91DF33155E9C807ECA2E605C437D22 -:108AF000E3B8F73BF5F8338E7FF4CF6A5D2C38BCD2 -:108B000026F83F1800FA89F93D99BE7FC0DA1B7735 -:108B1000137F27F9762018B62FFF09A09DAD9C7D05 -:108B2000C75BF09A25A614D0FA16070E5412BB9D07 -:108B300079B018F1FE6DD5833F2985A91DB5065B77 -:108B400093A1C1D1F58A2FE41D3CCE07B84E90A366 -:108B50001FA13CBD08FB639C6E67C2FF65333646B0 -:108B6000F5D7A3506177D9BC3B347CEB5EFBDD3A93 -:108B700056CCD853D6C0FA64783FFAEEAFD73094CB -:108B8000792C4CF3FEC2E2BB85E0CD18F1FDA16D5E -:108B90008EAD9BA05E6A0A97938CF9F203E335725F -:108BA000C2ECA4F250F1F3611CFC5CA89C92EB8C2B -:108BB000370E409EE6377786A34D4965ACCBEABDBC -:108BC00009D7D33F3BC1B90D5038D7EABF1AE1F3FB -:108BD000C10193A9A580BA35239DCEE343B0826B32 -:108BE0000AEE1F578AF2C7E24F80A954431B36157D -:108BF000E868862384FD957E38E719C4CF83B536AF -:108C0000AF8AFD4DF37EAA4279EE5536EF7AE8AF92 -:108C1000AC67C45E37F43F7F8EE264D07EE6EC51F1 -:108C20009E5E585FD25AE8270747B8B7AAC2CCD889 -:108C3000D3F89F97323E6180C55C45965F6C9B0977 -:108C4000F2609CA7CBE40050AF4C7BB1CD0EFDDEB3 -:108C5000D312C872A6C1D236DFD7661FC658468661 -:108C6000BF67BA8FB1D99BEFAFB25F01EB7C54B451 -:108C70000F3DD0E6CF63EC5553B04081EFCD9B77ED -:108C80005499015EEE4239FE2B6DFECB613D57DDFE -:108C9000B2630DF4BF25ED9FAACC38EFC572FC9EE0 -:108CA000AA8A9130FFCB65F95FEC385F77926C0F41 -:108CB000F39DC298654474FEE62C18DF25CB9F54C3 -:108CC000CD84F13F2E6FAE30C3F8C7D2FEBDAD6884 -:108CD0002C6393E7943BFD50EEDBFC1F5549809FCE -:108CE0002E06740AE53F6C3E4DF377AB26DE7FE837 -:108CF0008F34BFB2C5A171F85D617F6AAB8275AF79 -:108D0000B6F7BE85E4DAB43664CF4091A4703AB1C8 -:108D10005B9AFDB9003BCBAEF2482E4DA79DD36BBD -:108D20005E643CEAB181F218288FD794B378B96BAE -:108D30003D5B124BDE76BAB81EEE4A8CFDBD228D2D -:108D4000CB03801BE993D483CCBF33865E1997E6AF -:108D5000A07EF627B290DD15E5B76B8187A7005F8F -:108D6000323B9FA7EC6790FE48E3729F85AE75216A -:108D7000DFCCC12E60E9853E258474CD9A93C2A3D1 -:108D8000907658C43C0FF5876AA2F97A5465493544 -:108D9000F49791C8829DF0F4A4332A437B7FA723E4 -:108DA000DADF7B82EE2B0B03DBB1BFCACCEC92D6B1 -:108DB00082683F30EF0DF609BA799BA7B8F0FBDC6B -:108DC000925B8B34F02CE2EB003AA07630CC33D3BC -:108DD000810FBA7AC68DD804F3FB06E5AE27BAAE8A -:108DE000B29EB91606F5B6B8843CF1F2F69E0A2E8C -:108DF0007FFA6F4D0A6F43FEB4FB4A104FB2DD0D90 -:108E000002EE15F7CEF919D66BE8B1301BD45BD35F -:108E1000599EC9CEA1171B4E5FC6C213356573C4D8 -:108E20008A72A7E1F4347A5F71EF7B56E453ECC7A2 -:108E30000BEB5A93E0CFF421DC5A63E39FB1169A0F -:108E400047C3E934169AA87DCFE114EDDF4DDFCF9B -:108E5000B7AE687F2A0BA79FAB3F2B7D1F80BB5906 -:108E6000C0DD1A7B9E1B04FD20BC4D1AFA9A2FE828 -:108E70000DA49F1FE5E1A16B8AB6A1BC8F8EBB9E9E -:108E8000FAEF32031ED10EEC49F4A25D5C66E6F205 -:108E9000B3ACC7E50C2951FA907421F1DAE56A2EDA -:108EA000A7F5562BCE6D0583E775BF9C97D0A79984 -:108EB0008B83EA52CDFC243F40FF5DA2FFD229C440 -:108EC0003FBFE0F4027C7303F22FDA2DB80E5F642B -:108ED000FCDCE4C1F33F0DE4854FC02387FF5F391D -:108EE000C2A80724DC06C33FF73CF8CCA7EF653DDA -:108EF000FBACB8CE86387CFB802B85DA651E8CA453 -:108F000078A1DE19617774754C4CB80CF9628E89C2 -:108F1000A108C375A3BD5A36206FAF7C7706C8DBA6 -:108F2000CC8132C85B2FE26140FE46ECF668FD1F43 -:108F3000B9AE9CBD01E4B5DB06F82F223BD4CE349C -:108F4000FEC4EE346EBF4D09B29876CBDFB9927590 -:108F500072ECFFAEAD60BF85F599D3B8DE9FD21B32 -:108F600052102F92AF8D72EA13C18F1F8BE7FFBC97 -:108F70009C52CE23A7AA859CE2EFF783998FF53206 -:108F80003222E315D089CBDE9D380AFD99DBB2543D -:108F9000EF97C057F314DFB067A1DF1ABBF79E64E9 -:108FA0006F944E6A98DDEB40B883D17416F5FE9C41 -:108FB000042AE31FDA25A7DA154E87CC9B5A333EE5 -:108FC000BE1C92F3B82DCB4AE32DBB6F546A503BC5 -:108FD0003FA127AEB5459E658583F95C9661FEABE2 -:108FE0004DAAE6BB83EBB3B1C9FE6FD2D00E555884 -:108FF0002DCDC7602F3904DF19EDA587B16F0FFDA7 -:109000002F62233E3691739AD9660B33DE24847E19 -:109010006A660713FC1A313568E8C0EECAA3792CDA -:109020005E081F2F01A6B4BF71C9971A3E7A07E7E1 -:10903000437A213209F934C1C57476DE623590A7CE -:10904000A0DD9A69F3A19C013C111CF62730730244 -:109050008CFB363C116F95EAAD7B2D6EA403C5D712 -:109060004AD0DF2AFC5616417D73EDF424B25BD959 -:1090700099DB4756033C3C499C6EA11FBBE8C74E99 -:109080007422E4DEAFF3C76E43FD24E5A7C4033BBF -:10909000A3527FF2FB7EA53ACF09E5FD9E8B4A5A8B -:1090A00015BDFD83F650D47E4ABF6F16F0E3E4AAE7 -:1090B0008E880958A825E4997D27D4AF4CE26B1E11 -:1090C000E9E27A707F41484DC1FE46C13AE0D55B86 -:1090D00089C1A26647141F60E304117F1956783ACC -:1090E000387FE0739F8BF3D99C748E942DE9BC9CE0 -:1090F00091C2EB1BE9ED49F17D95C2F1BBA99CCB77 -:109100000963BDE92EDEDF6A7BA82A6384D6BE0A26 -:1091100030A44333E37696DF25E8A482C3ABE2DED6 -:10912000C5A9A837BFED999FCA8AA272F41E25E887 -:10913000F441FD7B2C819F52BCE35F5486FE883551 -:109140002DE87441BDF4A4D8FEF24D621EE9E84F4B -:1091500043BD9F087FC772FA62F2B317BAB83C4B9F -:10916000C9AA21798E30F4A29FC2FA434E0DFE5255 -:10917000A798747E83E57431B5BF70BBA1248EDDE2 -:1091800050AAB31BE4B846FBE1D37559347FD9FE2E -:1091900086AC8F2A99A6FE8DACF71EECEFC635B9CA -:1091A000BA38513CBBE32E011FB4134231E765D5F9 -:1091B000BDFF14FCC49076FC237CFCE8B849C06871 -:1091C000D171FD2EFFDD2EE2A7CB9D872F864702B2 -:1091D000BC5749DF90DC07BDE4DFEA207D5485F20F -:1091E0005AFA47C8F7CE54A4F1F20DAE491AFD2839 -:1091F000DA19E5D09F453CE3CF4E6EFFA51E94F6ED -:1092000062A25751A2FA66B0BE127AC62017CF6783 -:109210005F03BD86B4FADFD8EF53AEEF6B5716C6C7 -:10922000A18FD1FF237665D9E541753CCACD2A854A -:109230008D82C7E4997A3DDFEDE2FE47B72B49A75F -:10924000E7E72ED6D78B60BD49F84C1A92BFA2D55E -:10925000438A8AF28EF7D728E8A1E0D807562FC8AC -:10926000DFFF1276D017E9FEB791AE3624A614A31D -:109270007ED8FAA78A315B61DEFDEF5B7CDBB0BB99 -:109280005D9C3ECA17AD6935C37B4B87E2B4318D17 -:10929000DE5ADB79C90A58EF0792FEDD7C1D0DEE20 -:1092A0008875248C9BD3C0C7CFEBD8AB9835F22DF3 -:1092B000AF8ED73BE4B2E8F45EAF287F26FD0F16F1 -:1092C0006EA92CC5FA7EF326107D391D0AC583735D -:1092D0009A01004007393EDEBFC31756961745D79F -:1092E000D966AA2E42BDD09691E443BD30D61D3C2E -:1092F0008CF4DF70281241304D3ED46346FBAEC281 -:10930000EDFF0ADFCB757A55670ECAD5A4437C7E84 -:10931000ED067A070B59D0F9362E6F55F60E437CC1 -:10932000A0EC80F132D68F21BD24EB67B8849EC8B3 -:1093300060C117C8AE626D8CF0C5681D19EB47930C -:109340007D2FF119B5A3C64E403BAAF0818879194B -:10935000B4DBFD58ECF8BC45E81158074BF744D78F -:10936000118F2FA41E93F52C71FC6849EF4955B15C -:10937000ED53D000F4BD7C91FB3A5C77C3062BB370 -:109380002951F857B803E9389F9C8EAD0AC246D2DE -:10939000D706D7D34A2EACEFF65B985365F1E7DBDF -:1093A000B0F6C54B5668FC2DE89FF0B1D5CAEAB4BB -:1093B000FA54FA1317A773FD73A73B3002C76DDC8D -:1093C000B5D98AF8BD65FBE7566DBC7BD03A8608F7 -:1093D0002FA58EFB290DB5F630AEB37C9199F057D1 -:1093E000BFC11A4679D4B0B33362427BFA6EE6430A -:1093F0007E6FE8E87C2B07E092DBE09FA47AA3FD78 -:10940000E53684159C4F0610610FF979112BEA6738 -:10941000235DA33D8C76C95B099CDF4F943B420AD8 -:10942000C0EF8425D880F54E6427F942055178BFF6 -:10943000DD39EB1D05583AF9055B049F6DA66D59A2 -:1094400076A8D736CEEA433AAA700767A5037C5CB4 -:10945000E64017B64F7327FB5AA0ADD7C626907EBD -:109460001E221C261BE861F2DD9C4FFE263D45DADC -:109470007B13500E2D4D4F96F612C9A7B72C7C1DAD -:109480001B189FEF3E977F01D1ABD345E3E63444F1 -:1094900014B4F78DE346E9C9BFF842E81BEC3C2B56 -:1094A000CAF57A2167CA176D577EABA1837A3064FB -:1094B000905E72766E55D00F84EF2D956EAACF6CAC -:1094C000286776F2FD887AF87E9346AEC875C49018 -:1094D0002FB7217C1D877ADEE4F22542F427E76B63 -:1094E000C4E78FD2B91D77259805F4DE1A1AE385F3 -:1094F000FEDE1A9148FD497E37F2E78F049DE7D4DE -:109500006E57306EE04EE276A39C9FACF745FA8C26 -:10951000F5389FC9553D0487D5B566C29B9C4FA5BC -:10952000353012FDAF76D1DFBE859F597BA1FCD0CF -:10953000AF0E103DAE6E57FCE417B41FB0CEC7F8A7 -:109540005CE8972AC663AFE62609DBF2D201D22394 -:109550005777F138C1EAAE4EF37247944E0B8EED59 -:10956000BB11E96C75878D2528883FBE5E239D82DF -:109570007C21BA67212BED67817C0C913C65C1028F -:10958000F447A4FCDD27EC4BE6E0EF9F10F396FDDB -:1095900046E56602D17BC1B109FBEC00CFD53EC5E3 -:1095A00007A612D8DBBC1EF41F21F9CBD808F4CBD8 -:1095B00064FF46F8FD5AC8D518787E3E3D861E9158 -:1095C0007AB5E0F1190C9F127F660177D9EF9E748E -:1095D000BE9FB527DD4CFD6F28E7F1EB0D16AE3FC2 -:1095E00036B4D8C3C8D76FA75DF98E520C707259C4 -:1095F00023F8DC6F5AD680DFF7E7F079B499D68F7D -:1096000069E6FAEBF574C25F0AE3F289CBA3875EE1 -:10961000E4F2A421E4203FB12158B382F61FDC0913 -:109620003EB4F759F04DEBFCE4283D18F1EB7D61B9 -:10963000AFD50BDFAFEEE07C10855B5847B720E776 -:1096400008EFFB5C723F2258807005FFBD05E30CFC -:10965000D27F4F591C08257B07F36BBAF0DF27092F -:10966000FFDD32C5FE17F5DFEBD7FE5336965765A3 -:10967000BD4B4FC92FE027EAF8EA84F0DB0E08BCA7 -:10968000FF41D04B7D6907F143FD97CDC4478E2A3A -:109690002E4F1C87F47290B11F8BF53F40FD54266E -:1096A000755CA9A23FFCF78AB395C59FF7CD4AF335 -:1096B0003F4F45BC74AAB42FC5CE80555F06704D90 -:1096C000103010F52C6E1EF73EF1142002F9D2DC9A -:1096D0006C3D97FD7BBE7E59E42305F15D2F607DD7 -:1096E0006267C5D4DF613CF1A954DF2858FAF19DC7 -:1096F000F3FEE677D0FEC4F6E93ED4D3EED600D131 -:109700004FBF27C1877143B70A962DD0434BC71B64 -:109710002997E1BED833974C40B999E7E67C79ECBC -:1097200045752DC267FD3F3C3F0DBFD7879574B48B -:109730001B4F3CF5F77F46BD58B7BD093D0DD6FA26 -:10974000CCEB64879BC25BF9FBA752C9BE3CFAC451 -:10975000E66908F7D68E56FA7EEC89AD54DEF70F2F -:10976000CFEFF94FB43702293EAC77ECC5CD3FFAC5 -:109770004FA4F39A141FAEA32168E6FBB692BE8DE8 -:1097800072AB732FF1A9A497AB51EF229C6AB9FC7D -:1097900091F4FC85D8575A56E1684379F6C5A6E49A -:1097A000BA58F144BF582FC65C488ED52A144F6B67 -:1097B00003AAC1B8465B229B82CFA4A2883517C6F4 -:1097C00059B8B8731AD93DA1CF5762FD79BB12D8E9 -:1097D000268ABF61F016EC7F2275C6C683183C0C42 -:1097E0007E32F4BEFD2CD8D71F5B309643FDE9ECEA -:1097F000FF796DEFFE11E5688DBD77AFC71B7DDF8B -:1098000026E234509FF44ED99AD8F1D02AB743D0EB -:109810002DD79B395DD5795E921336DF288D5D3A61 -:10982000EC60F32610432CA7AEE74A5CC75563965D -:109830004E24BAC0381FEA9F9083FA5F8D714AE0C8 -:10984000B3456ECE4F194EE6BE14C6AF3433B703E0 -:109850009F8C7D642139B283FA05FB83EC2AEFEB00 -:109860000B77A03DB2C512CC9E84FDB409BDB59D59 -:10987000CF1BDA3B71BF14FA735E3A81FAE9B1B8D3 -:10988000A87D88B79FB5BD4589CE1728351FF51629 -:10989000F657EA403D13AA25FC78ADB4AE635825CF -:1098A0009BD65D7CC3F828FF1AE33B28CF701FF8D6 -:1098B0004E77F96DEE49D1A78CFB18E1F9327E871E -:1098C000757FEBF6D3933D95AED32BF1EC957D0BE5 -:1098D0004F72FDFBEAE7246F1A918E71FCE0973A14 -:1098E000FDBB5CD2F12B9F131D2FDFC5F56FE3AEDF -:1098F000122BD2EDF1757EF65B30401BC53EEB16A8 -:10990000A57725C5795E497062FCEEA4D037F50FC6 -:109910007C7E18F74747ECCA26BFFEE42B09B5D872 -:10992000CF7E9389E0B97FDBC55B5B15ED3CB93F2A -:10993000007630916A23D8A9DC0E5EB119FDB3D54B -:1099400075CC87FCDF68A09FC65D07885EA41D5CA0 -:10995000F0F8DC15DCFE4CF025A0FF3693DBA30C01 -:10996000EC51AC9F3633DC6225FA2A2943FADAB788 -:1099700070CF46D4E38D339913FBDF32CCFF4A2EF0 -:10998000AD476198CFB2C5D23EC30CEDB7547A9DB6 -:10999000004980DB76B27BD918ABD0732BC85E6EE2 -:1099A000CCBADE477C669407AFB490DDD5E84DA411 -:1099B000F95CBD4BB98DDB230EC6E7AF107D5E1D94 -:1099C000BE2C8CFBCABF17F093703C69E9B911E15A -:1099D00071F2252044F87EF54C4EAF69333B488E3A -:1099E000BCFDCA2CD2E3922E935FB6913E77999D2F -:1099F0008A8FF4DA3C9B16AFED16AE97D2849E297F -:109A00007C80E33722F82922F440C46DD5C75B9CE3 -:109A1000A162D4BBBF17F8273182F25DC893D52B62 -:109A200022C44F0D3B797F6E9BBFE4760DFDBA2BB0 -:109A3000B85E94717FDC07A88E212F7EE7E6FAB12D -:109A4000E0F1659BD15EBE0AF08E2A25678C90A35B -:109A5000401708B79CBA00D1C155EE9B7D6A01ED55 -:109A60001F909FD8DF6265B1E23C47851CF5A407D3 -:109A70004A31DEECC94C263BC7A3969B12B05D89E8 -:109A8000E2DBE6A5FD4DB2F3FA3DD9BE6D3A7E0F9D -:109A9000949AA0DE918C648EE7F0AFCD73C7231F3C -:109AA0007AA59FAEB3FB06FBDBDC6E9CD31E2A4679 -:109AB0003F44EE5F4838845B126BB5F2B34FC02170 -:109AC0003C96C7F3C1BE7750FCDA09E3A05FBFED57 -:109AD000B227B85FDF4AE31F74F3784625AC0FED79 -:109AE000364F61600DD7A7C9BE58F0B853E079DF93 -:109AF000C21B4BD0AF6CAC71F890DF1E7A55594643 -:109B0000F48CC141F4B7832B080F0CF080FCC082A9 -:109B1000DC2F6D6C0E8463D37B35F15F23F29F42A3 -:109B2000F44EF176A0F730A777AEFFA4DF8FF2B145 -:109B30003AC67EA8942F8DD6DED148C7921F1AA7A9 -:109B4000F58E46B80D559E9CB400FF23FF001C9077 -:109B50007F24BF24EFE67CB2A9C55B8EDF37553288 -:109B600067AB461F19FD259C27FA9D52AE8F7507DE -:109B70000A3D1807304536621E8594C38DBBEF1B26 -:109B80001D2BCF4DCA61BB99CB377B3829DCAAA1ED -:109B90002FDCDB4B9E404FCADB495A1B3B2E52E663 -:109BA000718878FDD0F222325097A3BCD996144622 -:109BB0007925E344C67EC778145D3C46FA2DB8BFCC -:109BC00080F5E77A38BD547AB89CB85E3CE5FC2550 -:109BD000FD7B4DC1CF319F289EFE92EDFE52712B31 -:109BE000398ED4A346FCCBFD115C4F7551FC7AED48 -:109BF0007BB97C32D2E372C1275E5C2BD47B4EEC06 -:109C0000670DC62FEF87D59A75F96F6DA6CEBA5836 -:109C1000F12FB9BFC11E320F29BF6EEF3A9E47F533 -:109C20009CC8A7658BCDBA7C2A87CFDB82F1D3197C -:109C3000F6821295C6E571ACE469EC6BD4C3C5BB82 -:109C4000DAC7609E9227A0DF1FC9AC4DD4ED3F64F8 -:109C5000075DBA726E5D8EAEFEB0E611BAEFC3D785 -:109C60008ED37D2F084DD0950BDB2ED5D51FD53E3D -:109C7000439F8FFBC855BAFA63C37375E54D2D1D1D -:109C8000B588978B9FBA4ED76E86D9692E01B88E4C -:109C9000EF58A6CF1333C033F5CF6A4C3A7CD2537A -:109CA00040789D61D6E70B5FB24B0F0F4C8BC3FE24 -:109CB0008A99E86FDA9109E7CA632D66E66F7A65DB -:109CC000FB82C1F4C0ECBDBE400C3F53D2B92C1B8B -:109CD000F7B1A4FCB850FA8B374F497FF1BEC78368 -:109CE000DBBB1EB90FC3E16219804BADEF5C70B1F5 -:109CF0009C0F2E0CE092FCFDE162EC6F7D5223E59F -:109D0000037F84058D7DDC2BF84896178452B91E9D -:109D10000ACC3B8F1DCDE3C0411BDF9F347EB7676C -:109D200070B9361AE640F019225F7F26F070281EBF -:109D30005FAFFD7A7F26CAEF2A467EB3B3B9E56BE3 -:109D4000D45B4BCC1186F4FF9058CF169117FAC80C -:109D50003A27F5F3A8D87F7C6C9D97DE3FBE6E0C4A -:109D60003DC3EB7CF47EDBBA29F4DC0EF61C3E9F8F -:109D70005C5745CFA7D605A8DED3EB6AE9B9735D7A -:109D800090CF6B10BE5819D93981F498F1D2A52122 -:109D9000754878626A5E4C7D19B71F75F139F3C852 -:109DA000D71E5A34FB4D0DFF666524BB0F630EE3CF -:109DB000643619F733CFD7FEBB75B5B3DF1C3574E6 -:109DC0003E92F4C4CEA48F8EC5D741913FF9BB8794 -:109DD000CF6E0A15C5875794CE62C3A9C67E3207D7 -:109DE0009DF562B41934ED0F1AF8B826981AD36E9F -:109DF000A811F4596BE3FBEF8B0CFCFD92F8FE52BB -:109E000006D7779FC49133576798A43F6FA1FDC0D1 -:109E1000417CF7932B62C1777F8657C7C78B820639 -:109E2000BC1AFAF9C4D23ECC1783CFCED78F5C9F31 -:109E3000B1DDC3195C6EBDF8FF297F7E725332F924 -:109E40000F08378F66FD9FDC94541B2B2EF35A06A8 -:109E5000DF0705EB9C15B8C8D40F59D1561CC3BCFD -:109E60007C9F77A413E343320F203EBD9A298E4492 -:109E7000305407C315F0E1B51642FFE68171226642 -:109E80001CC7678AEA59CCA9619A731EEA607A8076 -:109E9000F6212BE5EFF4E6D0BEFF05D213531F1BCE -:109EA00075AE7DBA41ED2F50CEECF881E58CE473B0 -:109EB00076E6C151B1F4642D8E7D29AC63CBD4FB21 -:109EC00049CE9CA7DF0B855FADDA4BFBD64386DF1F -:109ED0002EF790E2526BED29C50CFCBAEF12F83365 -:109EE0003483F1F3589F2584D1CE3F20E6098EFFBD -:109EF00025DCAF6E9E8CCF7FCE0A7C9801ED975902 -:109F0000B99F383EC3FF119613C53EB035D3BA1181 -:109F10009FCCC9D7718958C74693371FD7F1A5E29F -:109F20001B8B7E8AD314F6E1338545C6F3BCBB7028 -:109F300010FDB3F48B13BDE8DF268E66AC87E2E13B -:109F4000BE048C9B5993FAFF7124F2FBEB268C30F4 -:109F5000B2E79D7CBECF3F924BFB2AE801A17C2853 -:109F6000C6F730F54D688743FB6B59F018CEEFA864 -:109F7000D31E32C1BC8A677FE1C27CA8E7BB67D031 -:109F80003E42E4293564C5730B3D27FEEE6AE8EFD7 -:109F9000921E0BC59B2F612AC9F37A337B00F926E9 -:109FA0001E3C8FFF75ECFCAE2B32B9DC93795BC69F -:109FB000EF79E2FBF13879C48E4CAE17647E8C45A4 -:109FC000E6C778FCE7CC8FB118F2632CE600C37DBE -:109FD00060CB407ECC6246F931D08F363FE6F88CBC -:109FE000D8F3708B79584E27C5E93785DE1F1F716E -:109FF000EE755A4E27E8F2ACA3ED1DF43E5E7ECE20 -:10A000007831FEF138F9496307FACF66A1746D3BE8 -:10A010002F9FF7C03879F4DD62C8F3897EE7F93DF8 -:10A020001BD2389DECCD72BA9742D74B59AF05E998 -:10A030007489C36DC1F85180F93AE9DC8ED9D2DF59 -:10A040002BF96E04D6337F8176B609242DDAD94BED -:10A05000D65ABEE8D5C8A96ABFBECCB0BE46EE6E21 -:10A06000CA6234DFC4716328AFEF14F3A63ACF217C -:10A070003717DB55BB59B3DE4371EC865B05FC0E2D -:10A0800065C786DF7599DCEE88771EE2D6CC14DDD5 -:10A0900039BDDB9DE7969708DF60BAB67F231EDCEB -:10A0A000F4FD7C70F6E0E61AC6D1CA159EBFFF1714 -:10A0B00087779A3857C5CF05580C79E89BB2B8FC1A -:10A0C0008BCE9BE7A17FE40CDC9E8972D1EC1DADA9 -:10A0D0003D07D065F6274D80E72121778C70D99D0B -:10A0E000C9ED37E3BABB443E7DA2CA9A3B35F0378F -:10A0F000AEF73941E7B2FE060BDFBF82BF801DF02D -:10A100007203E372EFE1CC11222F3CCD8CF270315F -:10A11000EF82DDE07C8BF693249C07C14FC0DD0805 -:10A12000C700F3DE8879DBE783674796FF6184CB5E -:10A13000D203895694FF37DAFBF7A38FDADB63FA91 -:10A1400078243C3F778C3CBC9DE1FEDB9897F7C1BF -:10A1500033658A8FE751B09964EF28A15CF5ECC5AF -:10A1600043B77736A604C7207F7C29F2AEA53EDA36 -:10A1700098736C34E6CF7B5DE5ABB23C1477F7A700 -:10A18000231DBD66E374F408F404E5A63D63B7A29D -:10A190009E79302B5887F5641E1FF3F78FC63C84D9 -:10A1A0000B8513FC59908ECE07A7273219E1E75093 -:10A1B0004A6C3AF94D1C3A31F2079D2F2BFDE1F81C -:10A1C00043C253EE5BC8F9D565713A944F093763C2 -:10A1D000FE505D9649D4E3F9880F660508CE7DC32D -:10A1E000BE3E9C00733F64C8F792CF93421E9D6FA2 -:10A1F000FD12DE3F941C3E94187B7EA6ACA1E1E7E5 -:10A20000879A5FBD9C5F71ECF965660D0D7E01D686 -:10A21000FF59DA0FA0C700CFF58867B6A19FE4E326 -:10A220002157EC79960D799E41CB0FA16F257DB317 -:10A23000D0D23ADAAFCF4A8CB95FBF00FC27F47FA7 -:10A240008CFBF6727F1EE407ADB7C6DE7F633AE291 -:10A250007DA65877068BA4E17EE61E1BC5FF8DEB1D -:10A26000BF42D011C0AB82E035A79FE2188746C736 -:10A27000960B15C6FA6D7C9C78E70BAECE528674B1 -:10A28000BE80950629FE576E774454C0C36D021FE9 -:10A29000D6DC553EB40FCBB3DE3B88EB04F89F18F9 -:10A2A00080A7269FEFD8BA779C232DF1E576BDFADB -:10A2B0004259738CF5043DC11BB3347E50FD53EFFE -:10A2C0003A476AF0359EF59AF8F9E87E93CE2FCE9C -:10A2D0006417E41757639F988FE00A903E40FD8013 -:10A2E0007A67E3EEA925884CB433309FA73F3991B4 -:10A2F000E4686BCEA563BC1A7886B2A47DA9C6B10A -:10A300001BFF7BF9FF51BB49D1D9AFD1FECDF45E24 -:10A31000E2A7DCF18F31F111F4F8EF213DE6F26FA5 -:10A32000C4A7117EA17B2F4FA3F30508BFE9D1FE7F -:10A3300006F01F07CF1D1E7F3BF6D720CED1283257 -:10A340008F6F205E61761EB647E13D54BC248A784B -:10A350001AD80D8F211D586D821F9983CE874BBB54 -:10A360008519EC1B3686FBB73764BDF7478CF76C55 -:10A370004CE12CBBF14709E4072E519C565C37D8C1 -:10A380001F9FFE1CEA0759E4D3BBC83F9476469250 -:10A390007A3669E8F394FEF2F9F2A9F7A13D06F3E3 -:10A3A000996172D0FEE63E585F36C88D1956FE2C74 -:10A3B0009F055405FDCD50F3BA7B615EDFB2338952 -:10A3C00057C0F3A78CC361CD81DFB9D01F9D61B6A3 -:10A3D0001CD3CA2D63BCE38DAC6437E151C43BBED2 -:10A3E00065737E7D31C2E57217C1A5F8959999DA3A -:10A3F00078CB40BC43AC635E682997A7063927E554 -:10A4000099C9CEEF11617EE6756650DC88C33DA424 -:10A41000303394AF90657452A07CB9409282ED6164 -:10A42000DD5788275B16CC423983693C381E787F1C -:10A4300059F86C9DEAF3E273BA1230F3798479DE4D -:10A44000216BCEC3FA267BAFCACFE7C10C32B0BDB9 -:10A450001C8F9793457943CDA91B6FF20E8E633005 -:10A460004732D9BD5631AFA34E47C804EF6D8EC8F1 -:10A4700051CA4F154F63BCE33B532884F9D977AADF -:10A48000619A6F128B447A303E61071098288EF0E3 -:10A4900007E403F06E1A719E09CE5391BB18E6399A -:10A4A000FA152CA71BF491C7B186F29E3D01B3416A -:10A4B0000F0515E49BCC5AE37BBD7EB2B343741EFB -:10A4C000488904B2CEA69F3F5E638CD35866701451 -:10A4D000F7DFC2EDDE8F13793B4917E9D95CFF3610 -:10A4E000BAAC8CF25D32EC76B4DB4F261FC12397F9 -:10A4F000A837DA506FD82D7E8287D41FABBB6E652C -:10A50000889FC65DD50CE5E86F14BEFF19BA41A15E -:10A510003C05796F436D117B1F5AB2A6EC1134CE06 -:10A52000FC7782373440B9E63D363E02F54AA6074D -:10A530002AF17E96D6F1CCB71ECAAD09C1675FC2BB -:10A54000F51C50A99F26712E963167FD4EE87FEBD2 -:10A5500075C37C9B704915FD1B310FA8FF3EE6C4F7 -:10A56000BC9141747A06D607F87F02CB30EFA6156E -:10A57000C15FDC01F5B3DF633EAA23BEA32F82785F -:10A5800053043DE0FBE9F0BE49D04D61B7C2F7EF9F -:10A59000DD36CA9F600733895FE6DBF9384DDDE5BC -:10A5A000D74E827915F64C24321E09F531BF093396 -:10A5B0000C787E1D237FD9587F24D6F752B48AE7C2 -:10A5C000D5E458E9FE2326E4DC6403BF5D16A57FCD -:10A5D000FA5E22CA4D421FE9F804FB01FFDC5FC6A8 -:10A5E000B7F3A99D9BF3838FC93FCEB797B2E81FFE -:10A5F000F65B111D87E4EF4CF16DFFA2D994D73DB6 -:10A60000D91CD98B7C7D9978968827F2B51DE0B846 -:10A61000D0DCBCDF03EB495BCB7C2D38CA626F2BEF -:10A62000F657CA022AC2B9CC795F2BCE6FEAE20391 -:10A63000E9485F4F6617123D5D6EF715260089B435 -:10A640004EF1F99CF0AA76B14270995F6B0F63FEF0 -:10A65000DAFC81FB7A82050B806F160615718E3E3F -:10A6600058B058138F95797D0B6CE047C7DA77CED9 -:10A67000E67A5CB66F12E74EE4F76DD90E9E5F99ED -:10A680007D655336E557F07C67E0FBDBB22745E597 -:10A69000088C4BF928F398DF82EB9A27F856F2FDE5 -:10A6A0007CFFED64B7CE0FE8EDCFDF281CDFA145BE -:10A6B0000AD9830B6BCF6D9FB664CBFDDE3C27C5FB -:10A6C000B799D4479CAEA4DC9E8B7A1CE56D15E847 -:10A6D0006D8D7DBCF8CE3369D42EF3C9D56787471D -:10A6E000CFB93419CEB9348A732E4DBB5A2C1948C0 -:10A6F000EFE29C4B53F7E71BB5F97D124E83CFB9C0 -:10A70000F4535EE3026B782F9EFF59B00AD608F52A -:10A71000DF10E722DEC4731113A274947C5D4284BF -:10A72000E7CDF9297F2FCF99E4C37C9336D304CAB0 -:10A73000176A4B49F669F37336B53457623D99276A -:10A7400024CFB52C88B31FFC9C906B5B149EAF1577 -:10A750005A6427787B5476507B4EDF5318A03CB95F -:10A76000A66C2F8DB345C41130AF74223CC3608EEC -:10A77000717CF1F646F900FD6DC0FE2A0A7D941F3A -:10A780005391CAF3CC3CE98192DB8AA2FDD674F3E3 -:10A79000BCBC9AC0D76FF1FCDAEA5284A7519E4B39 -:10A7A000FA32CA75A0BF7D488FDF99B8DE89CAF733 -:10A7B000C0A29BA0BFBEF7AD943FC7EEF62B1668B4 -:10A7C000F7E2BB4E1F9EA7DB501EA8AEA4EF663A71 -:10A7D000EF9751CB2236F85EFA9E751BE6EDD5B1A8 -:10A7E000762BF65767D05BAB1C6F5A913F576DB70E -:10A7F00044E99161BEA1AF10055DC3CE41710F92D6 -:10A800003F522E19E9988DD4CB9F12296F412E709B -:10A810007DB598EB39F6A482F19FBEE423AAF09FA0 -:10A8200049DE4D9242CA20E72775BF4DF6CA3490E3 -:10A830000FE89F29582EA6FA5406F93906F3472F38 -:10A840006389445F83EC0431AFD28179737B48CA5A -:10A85000C5F2298CE17D06122F300ED1B3DCAF9BFF -:10A8600084F7F0C0F33231EE9D267F5144413CB174 -:10A87000B0A910ED8820D93B46FBA7CCDE9C6487AD -:10A88000F54D61ED241727EF7F93E424E0F92CCAFE -:10A8900099D798C4B3CF8E72A61213FF547CEAF1F5 -:10A8A00034CBF19019E1342BCB888F9019E13ADB4E -:10A8B0003B084F744EC01F074F7E2947985E8E1489 -:10A8C000B033FC5CF27D6FDD817EEFF9EC900F3DE3 -:10A8D000C1AC1C929F7A7B245E5E5D418EE382F266 -:10A8E000EAFA2CDC4FB894F5AEDCA90CA68B93FBEE -:10A8F000D7AA591AFA9174B95BE4D92BAF8BBCDD96 -:10A90000D264D27351BDC8F15F264A97225D69F0C7 -:10A910007FC5AE84880AF45622DA5F8AF43021AA11 -:10A9200017232687D70AE36E547C6D6A0CBC67B880 -:10A93000BCA4FF269AFC2AD953CC978E7806BC4F2C -:10A9400043784DB177B49A619E87ADBE9FA3BF5245 -:10A95000CEBC84F772837EA970D498913F2BEC46CD -:10A96000FCFA09EF95CE41EF4DDF07EFC311EF522F -:10A970007F0CC1FE04BC2FCC89B15F180FEFC1EF73 -:10A98000897723BE25DF7726382B1C18D7ADE3F94E -:10A99000C413DF1FD98AE58CD50574CEA533CDF756 -:10A9A000067D6FE6DF4B7BFC2ADE9F58B806BE4370 -:10A9B000B9B3205081E5A6B50AC9CB491F055BB1E3 -:10A9C0003CF26EFEBD647DF31B780F595388B7DFF0 -:10A9D0007D7423DD2711DE28DA97B75760B9A98D7A -:10A9E000B7FF2AD91E42FFBAEC60B815DF8F7D8011 -:10A9F000CF43DA75D3059D752A2FBC41EDDA79BBBB -:10AA00009BDFB227927C1276DA34B1CEE98FF175F2 -:10AA1000BA7F7B559517E8F0A6FE9005E9E0B0A94E -:10AA2000A18CE4651C7FAB5C69CFC3E72C900B8CD9 -:10AA3000F00DF43982E79B6E83211ECBE17686CC44 -:10AA4000D3C47CF16A0DBE1ECBE17127592FC3C55B -:10AA5000785EF1A3C964B7CA3CD2C8CF98827100AE -:10AA60005C23E9D73879A5B30A9B495FCE1A2EF348 -:10AA7000497BCDCB60DC92B37FB832967FFD8418E2 -:10AA8000F788C87F97EFEBC20526F43F3A9178E844 -:10AA90001EB3DAF7D12EE94C63BA7B423A0B78B990 -:10AAA000F3D19A1FB7E5017C4DCDE6100AFD7C85F8 -:10AAB000EE3DB9A68745525306CF7F96994578DE7D -:10AAC000039FFFCA56EBB64D1A3B7DBE141B978FF2 -:10AAD000223D5223F024E5C57C812FE0EFDDC8DF65 -:10AAE0000BECCD64172E12F2FD1616A638C52D06F6 -:10AAF000FEAE777CF399C984F1303D1FAF86E970D3 -:10AB0000BDD0FFF82700FFBA47929DA8E75777E826 -:10AB1000EBD53DF2FE416E5FE9F9BC4EF27958CFBC -:10AB2000E76038703EFFD938DA7F91E7FA12ECFD22 -:10AB30009F855874BD03FADDC07F0978CE6F0CFA8B -:10AB40002D269E5F28CA72DC53ED5C0F87400F0BE9 -:10AB50003F8744EDA943B3C3480F25827F251F9744 -:10AB6000087D3E485F5719FD9887883F268A928462 -:10AB7000BBD4CFD00FE967796E10F4F2FB7EF2EF11 -:10AB8000C1FFC4798ED3F3CB2605E47341D45F01B2 -:10AB9000BC7D8D7803796CE7718A7686F22CAEDD08 -:10ABA000EF5813D3EE074947FB0083EDFD88CE8EA7 -:10ABB00037E22B9E5D3F80AF04B09792D08F67C481 -:10ABC0001FFF88CF21E475809C76E4C690D3D67DA4 -:10ABD000BC5EFFD6048A17C8F8B8E437258FDBD5EA -:10ABE000EF66F95DB9B8FF20FA3F74EB2CDAAFFEDF -:10ABF00086F969BF1AF38D7263E44BE07EF5064D6A -:10AC00009CF4505AECB8F5F05CCEEF4B72F9BAC632 -:10AC10007BFC5E1CEF8895C7C58F248A670ADF57C7 -:10AC2000B83897C7B9978867B9781E1179D8475C43 -:10AC3000FA78BAAC5721C6F9729DDDBE412357BCE4 -:10AC40003FB335A3BEF2148ABCF5359C5EFB5E496A -:10AC5000DBAABDAFED9ADCF22508474FA1DF9A8D44 -:10AC6000719657B85E6834F75A31BFE41A77702A84 -:10AC70007E6FF432FF0BD88FB7D73A0FE0DC27F6A0 -:10AC8000E9FB2CDCDFE84BE04F39AF6B72AB97E0B0 -:10AC90007AFB6EED25F93050AEEE25FEBF2637402B -:10ACA000E3F6CD97DF45F9C7BCCC847F582EF882F8 -:10ACB000E2BC31E2BA83E3B8FAFB679AACB1F7972A -:10ACC000595EB22E3E7B43378F1BDE68671B73E1F4 -:10ACD000FB92EE4CF21FEA5242A39D14C7FBEFC554 -:10ACE0005DFB86F5D0BA3695F7E73F5A4AFBB814B4 -:10ACF000F759DDFD36C9B9D5924FBAF47C522FF021 -:10AD00007BBEFD0F635C7C08FCB32616FFBC8CFA8F -:10AD1000C91285FF6D220FA9526DA8C0B8D0A91520 -:10AD20008CCEBFDEF6AE4AF474DBB30ADD0721ED4C -:10AD3000B3D502BEF1D683E707BC1AF981E707BC99 -:10AD40001AFF0CCF0F68CB787E405B1FCF0F68BF18 -:10AD5000E3F901ED773C3FA02D97B0E5AD18676BA7 -:10AD60006A63CEB0979F27D0B6C7F304DA329E2726 -:10AD7000D0B6C7F304DAF229C6E178EA3195E2F4F5 -:10AD800078AE40DBFEE677276621DD7425F03C32A5 -:10AD900016F2F714015C5608B8E079036D7FC753CB -:10ADA000AE7C8701DDADE85939079F97EC5AA5EBDA -:10ADB000AF5E6D203A64ED5CEE36C33F243FD52292 -:10ADC00015E7F1ED2E85A517E0FDE106FDD9BD796A -:10ADD000238A9E5BC2FAF7F54C13AF2D181C977FA0 -:10ADE0003957E421E6B01C6D9C264A070E5F04D754 -:10ADF000FF91EA8B450725ECA2548ACFBCA362ECF5 -:10AE0000817DC59AB75CAE68E2F70678D8B2F4F4F3 -:10AE100090E0D5D343D2183D3D24FBF4F4903A455D -:10AE20004F0F69FE71E7846F7A959E3E8CF09D020C -:10AE3000FF207C27E0CD9018578275629CF72F0584 -:10AE4000DF2F72C5BE8780EFB7ECF20A87973ED737 -:10AE5000D8CBA2F649E93BCDB4496B8C7B4A384A42 -:10AE60003B41C62F2731EEA7DBF1BC6521DA01DCBF -:10AE70007F43FD8F7C7ED8CAFD36A420949337B1E2 -:10AE800020C9A39B0CFAFF66C74356D4FF83D60B99 -:10AE90001617DE1B685C2FDA514C134F32EA7FA580 -:10AEA0005B892417E372BBA55C0E9E2563C7AF0CBC -:10AEB000455EFCDEE1B7E579681C662FD3C57B6390 -:10AEC000DA73721E122E727C1B6B56B3909EC718DB -:10AED000ED2FBDBF2CFD6BEA54138F96FEB1F44FDE -:10AEE0008C7056871790DD35D129FDE29EEBF1BDC0 -:10AEF000F4878D7EE8F9F6A5E68594DE9F1744ED8C -:10AF0000C92BC4739E8817C1B27EFB6FD0F872C57F -:10AF10003B0CC79BBBFB220FD2CB46A59919E6770A -:10AF2000F055E84735F5A7F3F84B50B75FF5B6D2C3 -:10AF30004BF35EC0FCF7E0B351C4D31ABBDEA67D71 -:10AF4000D4C62E1E2F60BBF47831DAFBAB5887B520 -:10AF500040196CEF37B01EEACF68DF0FA293F3E819 -:10AF6000F18E3C79DF16CF1760422ED50978C5F3F4 -:10AF70000BCC08E0A9D1FB3B811FE6E54D8AE6D169 -:10AF800066B8C08F51310FC36B8D9527C5F0721510 -:10AF9000B049973B6A484E2C6F1B1497B0123FB5CF -:10AFA0009F7B7DD20EB81F7C377C96E67979DC20BA -:10AFB00071CE3B7EFC5CDA93AF3DFFD164E5E70EDA -:10AFC00059B3FE7CFEDA3C933C3FA50E65FD83E160 -:10AFD000FAFDF2F265FE01C0EF2E2DFCE43E825C2C -:10AFE000CFEF27F53C89F1433579A61DFD5AAF2BEC -:10AFF000D882F5871DEC3DACA03C7378293FE4E492 -:10B00000AEA31FA3FF2ED7C758EF16BCDFB66E97AF -:10B010004AFE60DDAE37C82E8AEFEFB50FDCA32005 -:10B02000F6377E126B5E32AFB9522D4AEDD5D8E9B4 -:10B030004B851F307978E0216C57FA615E0ACED7D4 -:10B0400032A283EEC5EABF83DBC16E95CD44F881A1 -:10B05000DEE37ADF61A67D077752484D413B6E29DA -:10B06000E3F7D0F99A7D482AEAB0228AD366DCA1B8 -:10B0700006D0FEFE74CDF2343CAF9C91BC22AD10E4 -:10B080009ED36DFC5E9A0CC514E0E74E97A5E13D9A -:10B090002037D8F8BE7CC15F27450A81DF5EB7F252 -:10B0A000FB46DD4941BABFA03F4DA5F91C5B074BEC -:10B0B0001B85FB1EDF4CC47B0772CE3826E07CB2BA -:10B0C000C5BD163FCAE3F7DC1C7FF6BB89E8AFAA13 -:10B0D000671D74BE5DD29FBB30B6BFB242C0A3D164 -:10B0E000C3F3DE4F0AFBF190D86F9579F06BC43E45 -:10B0F000E0A1D103F78379302FA431C19FBA10E3C7 -:10B10000110754CA6BFFC6E94F4D23BB99E7B3AF94 -:10B1100011F6C34991F7B966F68C4CF42FE2E54B72 -:10B120001FC8E376EF0F755FA5CC3F8D0B873433D7 -:10B13000335F42F72E05CE55EFD53FAB31E1795A5B -:10B140007C8F9737DF97A7E8F2E21B312F1E5EADA9 -:10B1500079A53C939D235FBA11EF23D7E4D7A09F35 -:10B1600086EB6BC4FBC8E99ED213744F07F683F7D6 -:10B17000869DEFDEC815621E8D984F9EAE7DCFF97D -:10B1800039DABF9BBE3F2DE0F6F43BA6AA6D31E64F -:10B1900099378CCBA7711E7300F7252F8EF07B3F5C -:10B1A000E3D593E7B8E3CDAB6B46EF8D386FCCCFEB -:10B1B0008C355ECA304E2772BE5DAEDE9501BE9FF5 -:10B1C00037BA3A595376F6E7CFD5C8D7D9023F5D9B -:10B1D00057F5E6D37D00B3B9FF1A0FCF65E66605D4 -:10B1E000E190E00A06D11E91F715E37DC63CCF231E -:10B1F000744E7C47E1ACEACE1F0C86B395BECBFE05 -:10B20000A4DC39FA884A72E7E807821F99DFA19423 -:10B21000A1BEE27C7594F1B8EED176FEFB1FCB8225 -:10B22000A02B407E2CDD5E3F070F1FAFDC3171236A -:10B230008A7F7C7F37C89FA5598C4D83E7B20DFA72 -:10B24000FDB16FD903A4E7563C60D467012BCAD97E -:10B25000950FE9EBD7B107BE46FBA0CE60F76608B5 -:10B26000BD6BB47F670C13F66F192BBB90734E8FB9 -:10B2700030FFEC61A4FFF97EDB24B19F6EACFFBC14 -:10B2800097D3C36D3BFE60C59F048AD7EF319017FB -:10B2900023A1DF13EB9CF45C32CC5F330CDA350D69 -:10B2A0000B2EC471FA0E70389F6A38B592E2D2B58F -:10B2B000DC0EB0E1252BF09FB6EBEDE447DF8BF71A -:10B2C0008C019C6D366E5F48BB4A556F57F1275B0A -:10B2D000A6FE6E451AAECFFDCCAC2AF43F3CCF247F -:10B2E000F9111F9BCAFD2528BF37553B689F78ABD6 -:10B2F00089DF4368B7F1FDB9F0D353F7613878645B -:10B30000C7E619E86738BBF746302ED166E2FBAFD7 -:10B310006DD398B8C79A8FD7D45DDD89F3CAAF01D2 -:10B32000790FFD6D2AF0973835FD33612F350A5CB2 -:10B33000F4BD76D14FF1DEAB9FBF43E62AAC730478 -:10B34000C5BFC6314E3732BF847E1B43132F3A012F -:10B35000FA8769CE3F8FEB50229614BA5F8FE2D8FE -:10B360000DEB2319D7A3FEFC25DFAF95F373BF9E2A -:10B370003D03E3FD529F5E8FF96D18071676EF22AD -:10B3800026FFF87E41ADA0EB45C2DEBD3E89C37904 -:10B3900019F3D1F9ABEBEC2C05E3CBD757744CA2E6 -:10B3A000FBAFEB2D6968AFC8B8773CBCC78BCF3417 -:10B3B0003E99CCEFCB51FA476327C73006521ACDDE -:10B3C000B737F6B36398E0E7D1C24E1BC9FCB8CFDC -:10B3D000D2B8E722CAC7B725F27D35906F76C4EBA5 -:10B3E0007ED4E7B0EE5B5E4D88F07DE3B0B81787A2 -:10B3F00085683F664F26ED2BB80BFDB4EF7ED2D2A9 -:10B400009B4FF200E49702BA73CFB04FAE31E3FD29 -:10B410002039604741F9F82F0E5F83BFCFD238A2A1 -:10B420007725DE179EFEF8595E1ED77B18CBC31E0C -:10B430004FBC96CA137A57AA509EF278D6B5D41E3E -:10B440001D2820ACCAC7875F8BE7FC8E89F825F3DF -:10B45000F5D23D418DBB2F3269E38325F95C4E1F48 -:10B460004BE0F58E15B0257311DE637A476B7F379D -:10B47000C1932FED526E97C975CA762C2B76FFEFCC -:10B480000B3D708BB8DF677A126B4BE0FB1521B474 -:10B49000AFDEECBE88E0F2C2309780572FDDDB28AC -:10B4A000FB319EEF97E3AE42BD8D72DDA23F4FF4BC -:10B4B0001BA12F609C0D344E91BF04EFE5699C9B4E -:10B4C000578278037C9905BECCDC0FDC4A78C67EB7 -:10B4D000D38A498F4CC43CB137CF40FD82E8BC8D44 -:10B4E000F471588C734B2BDF67EA4F2B243A9A9EEA -:10B4F000C4ED3F560AF003393645C0AD245F9CE3E6 -:10B5000019C043A642FDB70AF8E5F1FA17BADED32F -:10B510003FD07A3578F263DEF19BBBC6129EA60C53 -:10B52000D0C1665D3FC75A0CEDA6F0BC94465721CA -:10B53000B5BB57DCB32FEF2DC67605D06E7A45FF2D -:10B5400044E407796F1B0B4D2367BD41488B817B1A -:10B55000D83A787E0A1BE9E7F711CD9D532AD6E742 -:10B5600014EB736AEFA51BE0C38FFAF36B34F75249 -:10B57000CBF703701FE8AF6882E84FC7CFB1FA433B -:10B58000BE88878F71F97F617CC8791AE0390067BE -:10B59000C3FC243C918FA95D919E9FE43C87E59B71 -:10B5A00084BF6DE0E782EF399EC8EF5FFD37221F51 -:10B5B000D2ABA7E7D55D0526DC3F95EDDA3A5A0216 -:10B5C00028E765BCDBD6551D42FDD7D45D4E799B7F -:10B5D000AB7FF5ECCB2168BFEAF987533099F6A829 -:10B5E000B93D03EDDC861DF7A4F871BFC41C4A41C8 -:10B5F000F97934AC56C53A0F181278907654A3D026 -:10B6000037C79EBEFF1A84C77FECB038518F363DD6 -:10B61000658BD8280E720BD95150FE9C97EFFD1AFE -:10B62000FDD2A65D7A3B69D53F3C9CE1257A0AE5CF -:10B630009AF08C0B8BE43278366EB7F8226E1E4F80 -:10B6400084615813EBDF88F333B6C7799C06BC37A7 -:10B6500075A84BF13CAFF13B4812B2C39ABAEE2742 -:10B66000BBAB491B67003CD4C5B1BB6ECDD7E75B14 -:10B670004BB8B0B087EC9AD65FFEACF87307DEA784 -:10B68000F94F294A91565FAE27389DEA58FEF7BB1D -:10B69000BDF1F5EA49B40B6CDA761CAFDE5D0AED5C -:10B6A00049B06EFE6CB04452D0CF6FD86AF181E6DB -:10B6B000650DCF3EF124EE87B04F6C74FF41FDB3B2 -:10B6C000FB3FBE14CAF59D16F71C3E7D879211C53F -:10B6D0004F9397DB27121FAB5EDC4FF70CE27BB476 -:10B6E0006B255EEA3BF75AD9F8C1F0ABE8D82B7E60 -:10B6F00077C1809F8ECFAFA4FB3C7FF99D15E9FAFF -:10B70000E81E8565160C6E5FB7757F0AD21FC209E9 -:10B71000FD4B89A701BC0DC257E49ADDA5548FE209 -:10B720001AF1F036379FF178D0AF9E7D0E7F07B0CB -:10B73000EE37361FAEBFEEB9DB53701D5F999B39F4 -:10B740007DFFE29E0C3F8C5B67096538E9C9DFD756 -:10B750003D7E07D1DDCD07EEC8E0BFA7E1CF364D76 -:10B76000A17566E3FA6E7A6C3EAD6F250B12DDD5DE -:10B77000FD82C727BE15BFC760C4E769C11F5F6DE3 -:10B78000B3E18F64B0AF30111DF3083F50459EEF19 -:10B79000AD4C7B8F0558DC54FE56C407DE1FD0032A -:10B7A000CCCE3471D9A6EDF7F6207E8E0DF367E28C -:10B7B000BE1AC02124E0A5E0FDBAEA81CA4C8E1F62 -:10B7C000E635CBB832D8DF15F81EEBF758FC09C5C3 -:10B7D000BA7662BF9E8F2FE31330EF44DCF7FB2A6B -:10B7E00023F6B9ADD1C31521DF580FD3D2573C7E14 -:10B7F000DF7E1FD1D5371F71BE690C5757D1F71E99 -:10B800004B048F163786F7D628240F6CBAFB9F0699 -:10B81000E862BB45F0B3FE3BCCD3AC68E1BB87E745 -:10B82000D5AE7CC8A6BB0F214A37D6E8FB82287F5D -:10B830004A3FEA66C1FFC6F51AE5C11F0CF2803D1A -:10B84000E619D2BD320D96F0938F22FF02BFA29F60 -:10B85000D9F0AC85FCFCE33BDFF8F83AA0F3E31D3C -:10B86000926FF572D5C8B7752F4C62B1F8F6B8C3B0 -:10B87000C762F22DBC8FC9B78EE83E8D97FD7072FE -:10B88000F5E63872356FB8F11C4B512AE6BA1F7BCA -:10B89000BA7E38C5050C7095FEAC515EBE9CEF8D2E -:10B8A000292F195E41A581A3849FA4C755CFACA6BB -:10B8B0007106E856D2A5A4DB01BA1C945FA983A344 -:10B8C000F1FB17288F2645F16E590F7E0ADAB1AFCA -:10B8D000A9F43B287D30978D00F7BE9D05B40F7A03 -:10B8E0008FB0F3FB9CFD2918D7BB47F815FD184F07 -:10B8F0004C8DBEEF4F10790381FE94348D5DF47949 -:10B90000B79A82765C6F38F6EFC9CA7B2A7BE3FC74 -:10B91000DEAC3CBF54A93AF2D7629CB69DEF4FAE65 -:10B9200068599882F18CBEEE42FA3DA19BDE057FFC -:10B9300017E6DB27E39A21BF39BB2C7ABFE9111642 -:10B94000A2FDCAE5DDF5B45F688C83AC74D4A4E2D3 -:10B950007EA0310E7233E641611EF263FAF7AB301E -:10B960003E827832D05310E9297B303DAD1C2EF653 -:10B970005F4B58896EFF55C8B54AB5E8A7689FF474 -:10B9800081DF8EF120A616FD1AF5E9B7E8C723037B -:10B99000843C44A7F5C12332CF8AE85AD29DD17F97 -:10B9A000373E4FBCF469199E076A78F9DF8A7F0E2B -:10B9B000CF132F7F32FA552CFFEA5FF3FF8D0DAEC8 -:10B9C0005FB1E78FE4AFF4EDB1D17CFAF6BC9D7FB7 -:10B9D000179677DB7C38DFBEF536FE7BD07B92E9AD -:10B9E000DEE9BE613CCED6FADA77C5BDA4A7361033 -:10B9F000DEFE6E38BF2FF654F77F7D86F7AB9EEAEA -:10BA0000B67931EED0B42789FCF0A6DD09744F7CFD -:10BA1000DF6BDF9569E345FFDDF5348AF3167DC9F9 -:10BA2000AC16F35BFAD2B8BFD6F4EAD4275A0AD0E0 -:10BA30002EDD4BF71657BCFEA762943F7D2F70BBDF -:10BA400002FCF3C77113F117C3BB7F6A998AE78DB4 -:10BA500018F9D553BD7FBA36E48805170E873E80A6 -:10BA600003AE0BE042F775C78347D7707E0FFFFF29 -:10BA70003E787C4DFE4243F764E2A3285C14FEFB53 -:10BA800023DDC961BB42EBE7EFF77C578C76D2F13F -:10BA90008E16D2FBE75BF787FF6BE9E0FBAE5B89B5 -:10BAA0000C65DDA7FED7AE9BD3FFDAE15C3F19F949 -:10BAB00060309DFFEAAFA9FC5CB28FE66BE0FFFF50 -:10BAC00007ABA359F3008000000000001F8B0800A3 -:10BAD00000000000000BCD3C0B7814D5B9FFECCC76 -:10BAE0003E926CC22604084260F2244A1E0B791072 -:10BAF0001EA99B842008E206A4A2222EF8E015923B -:10BB000008B6C66ACD622202F5B6516CAF6DD16F30 -:10BB10004141DADA6B8A41B1025D10115AAAAB8257 -:10BB2000A246BA52AB50031B41052ABDDEFFFFCF30 -:10BB30004CB233243CFCAEDFD7E423C733E7CC3927 -:10BB4000FFFB75CE18498599ADB9004DDB4EE587F1 -:10BB5000B1056806280648526D00FD004E6CFDFADE -:10BB600090944CAD5D853480BAED710045D8FE31BE -:10BB70002600124064DBA9129F13E01BFAB912A041 -:10BB8000A3119718D6DD37B71D9B3F2CB917A7D443 -:10BB9000BCF041FEAFB1ED78E1BDEC97A9FFE2BB8F -:10BBA000433EC0B6D606BE565C2F120F3337213C3B -:10BBB0009144F000EE5FF7F2E8A796E1FE8BDB3EE2 -:10BBC0009F4DFBD76C1D0532F62BFFF4EFFC30CDFB -:10BBD000DF2479C4F3F88003E1AADC7E463CDF7EF3 -:10BBE0002A1FB0FD6C93149413B0FF807D7E80D625 -:10BBF000ED05EF118477F17F22DE3B6CB7E278C36D -:10BC00005095E1EBC67B870DF208DFBDB3697E641A -:10BC10007BBCCB9E46F0FD7B0844E17F21BCBDFF91 -:10BC2000B1FC3E3FDE007E86DB2A7B1DE908DFC3D8 -:10BC3000100CA9D83E0830B1D5792E3C3FA6C16280 -:10BC40007A0F42D01F4006F123272F9C0209D4AE61 -:10BC5000FA5CCEA7F7A74D4C4338FCAAC5BD5EA53C -:10BC60001916A6C38AC1EEC02A840B14EFFCB5D8FE -:10BC7000B70EAD71AFE215EE042801F881435BAF5A -:10BC8000FF948912AED7B40CE1C2759AFA595C4D93 -:10BC9000B88EA25A82F67C6E3FA2F6A1FE57EFA1A3 -:10BCA0007D15A70D82DABBDFE03F27603F47EBE35E -:10BCB0007EB199517DFC17033B5D0AEE1FE35620D0 -:10BCC0008028D921EA7D9C7F93EA62BAC442C0EF02 -:10BCD000725E3A9D7E4F83FD7AA793993E3ADDCE00 -:10BCE000A1138083DE57E8BF08FFE45521D2430546 -:10BCF000147F58E0237D23113DDD290E5CCFDAE768 -:10BD00000EF72A899FAB4A89F69E85FE2C31D01703 -:10BD1000E9E789C9EFA673D47A8CBF99CE974A5FB9 -:10BD20009D2F31308DF91C33D8E90E20FC0FAA82EB -:10BD3000EE0F22DD25A99BBE3ADDCC7CF093EC14FE -:10BD400077D3BFBB1DE7FA64383312BE41E2FA2B4A -:10BD500020A71ED7A992C785FDB8FE89D238B79D06 -:10BD6000F44582A03412DBF2FE15807874A4DA1454 -:10BD70006ACB3A11A72878AF3CED00250ABF72487C -:10BD800034F43B52B3F9FD4AC740C37B1D034B1D3E -:10BD9000F4BCCA956698FF464C423E14D07B1326ED -:10BDA000D2F85529971BDE9B7AB863CD1C6CAF95F2 -:10BDB000C245241C1D7B675510BD26A9230CF3B674 -:10BDC000A059217DEEAC9203EB901ED552B07F3E80 -:10BDD000D26D72CE68237C128C273C6B2C285A388B -:10BDE000EF1A77B961FCDAD2498675AB3DD5867E0C -:10BDF0004DC357A0F40518DB70169442B4E3C15646 -:10BE0000C3FB857BB618E627EC03391EDB11FBD597 -:10BE1000266A0BDB434924BEB6BE0EBFA50F8A704F -:10BE2000D85B89E840C991FA57A86D70203DF0F9B8 -:10BE3000A918D122BF58CEFD8762024D08EF294BC9 -:10BE4000C04774B85B0EE4501B3BE88E7C48073853 -:10BE50009AF2B0DC87E0075FA78A7230FA8B401352 -:10BE6000F5AF3CDB2AFBC80E6F94FDB602E2FB94F3 -:10BE7000B8BF92DD6D9580F85EE3B47802E4B792C6 -:10BE80005AF39746C9D7673F845BBCB9E7EAEB8BA7 -:10BE900059E596345CBF39C5D3B283EC66C587B328 -:10BEA000E5F473E7814BE90CEB7449A7F7BC4583D4 -:10BEB000511EE5F8F10EB2EBB19532E30557590387 -:10BEC000EB719DE516778CA6FCEC5F5D13AC6B49BE -:10BED000AFD7A409FB10FB175025843FB6AF4FCE58 -:10BEE000A3F77E26C17AE8DEEFD652603CB2D22CB0 -:10BEF000420F1457BF9BF3E8FD787EBFA454D011C6 -:10BF0000A6580259B864C241F76E2BF657E7EC7792 -:10BF10009119689B72D82F235DDA0E86CA24D4A5A6 -:10BF2000010F979FCC14F3210BFB6D39E3E3F2D89B -:10BF30008FE558C8CE2C41B347766647D93339E4EC -:10BF400027965C7EC500E8C1BEE96DC26909D4C20E -:10BF5000EEFE9A3495E14A50C2407A9D705AE171E2 -:10BF600068C8B690FDD1D74F98A5BEBB94E0D86302 -:10BF7000852CDA5EF12C223C565DD1AEAE623C04DB -:10BF8000DE00E1142FA2FA4FF4932A315609A7DC00 -:10BF90001C7F2E1CFFDC589CA8221E7DCBDD896EE9 -:10BFA0006A7F8F441FC374F7131D7E4A7F2EA3DE62 -:10BFB000DAD0781CDF4836518C0701E57A954D1BA5 -:10BFC000279382FDBE9236EE5FEB1D4F7C958DF37D -:10BFD0000BD2BBE67B1C29DDEB7BD7AE0D35F748DA -:10BFE0004F3BFBE55513AC01BB7431748DBB005D59 -:10BFF00013045DCFA2F5C77DEE72887D3E96D421F5 -:10C00000246FAB2D68053200F6BB7CD7935CC7CAA2 -:10C01000C13C7A3E37C133A00CE5AFCDE619720FB3 -:10C02000D9956D31EE75F85EF59D9F3DDE407A3D08 -:10C03000F59F39CD24378A276E24EE53E7FA8AED2F -:10C0400041959CDB87E29D2E3A923CE39E3FB5747E -:10C05000F7C93E2474D3D59389E3ABA2E8EC709082 -:10C06000FD12FD47D3DABC4CA7DB1C4CA7A59A4EAA -:10C070003527428B05F5E1A46BC3F7491E4E6EB41C -:10C0800002C54D6D3448FE32C7C17A05C9E1946AD4 -:10C09000D483BC372D5E8ACBDA513E3C241FF5D9C0 -:10C0A00086F54E8E7B37290FDF3B99AC24117D1628 -:10C0B000866D4CB79B1508DAD15EB625DF5659CE92 -:10C0C000FAA1F278ABB6CE6B599EFBD2D8EF8C7743 -:10C0D0007D8278499E31F237C37BE71779D04F7460 -:10C0E000FB8874AE2334937A9783E6724780E2CC60 -:10C0F000BAD265B9E41F9624660F00C4A36EBCC40F -:10C10000FEB6AEE10BA6BBBEBE725A06B56F777F18 -:10C110007C86CAF640513C2C0FCA691B8FD7349CD1 -:10C12000643B8EE0A491DE742C13F6AEC50AB754BE -:10C13000635BF3BFF22DD538BF06430CF617B0D3BF -:10C14000B624CA1E42EBE75D76BF0079B77ACA5BB8 -:10C15000B16467AB25D70C401C8EA6BBAA95D1D87D -:10C160008F71CD90B0DFB6EE8C97FBA9AE1916ECAF -:10C17000EF4ABB498C0F74FDDCE206F87CDD5DA262 -:10C180009FE63A40FD0FD31EA95606623F5EC8C126 -:10C190006FD26AABFDB9245F4EA6CB891571AC1F77 -:10C1A000BDD1795EC3CB06BA9C332E4BB778C96E2E -:10C1B000CC1476F1D8CA416B391ECA0C65D39E5B8C -:10C1C000D344FCDA1F79538AFF5E45BD77201D9268 -:10C1D00033C063C1F9C92FA23FA2F91F878610FDA2 -:10C1E000E6BD181394901F8B9F78C546FE68AEACD1 -:10C1F00066935EBD3FCCB793E4E3787C88FBF31A8B -:10C20000B6335C29592E61A75D9DB95E94CFF9D0F4 -:10C2100062A3F1F9A01C26BF614161A6B866A173B3 -:10C22000978DE2B2854F5B0F87A3FCEA22081F229D -:10C230003DAD79D67A381CE57F81DE8F92AFC3168B -:10C240000187A2D163AE1C9A6D13701D20B816270A -:10C25000617C2F93BB08F5F7715C5493C379494A0D -:10C260002C90DC2DBFECFD7C5F0F7EB0B511FD3E48 -:10C27000AADCA6C62DDCAEC135C9EE0C50C23637DD -:10C28000AE53ABD9E592D0611B44BD7F42A36B9FF7 -:10C290002D128FEBF6A27B3C5ED025D733C2827085 -:10C2A0002C9EB66F1CF145E7E79571D01A93C47CBC -:10C2B000716B7C71135F74FA233D0B157C6FD7593A -:10C2C0007C2FAD27B9D0E92FE06D8B15F6A27373E3 -:10C2D0000CC74D66F8E3D205BC3A1E43D3CF0FFF1F -:10C2E000D0F4EF06FEA1E9428FCD78E87AAC3FD7D3 -:10C2F000F5D88CB70EF7A5CB59C8763172A6DB9965 -:10C300005AF0E5D0FABA5DD1E9ACC3A9D3AB8DF24E -:10C31000A11EE0541A5E32E0A3842A28898071E9C4 -:10C32000E9C28EB54E02E283D2B095E75D2A3EBAED -:10C33000BDED0D2FDDCE9AF1D3EDAD8EA76E7775E5 -:10C340007CCBD090B03DC4349EF2AC2B4FFB0C7133 -:10C3500070392C30C4C9958E3B0DFD2AD73D86F926 -:10C3600057A52C338C4F52571AC627E73C62E85F1B -:10C37000E3FEA5298E5F6B8AE37F63181F170E719A -:10C38000DCFD7AE344509047DF3BD2C9F177B0D16E -:10C39000C5FD9D8D29DCEE6A5459BF7737E670BB29 -:10C3A000A7D1CDCFFFDC58CAEDBE460FB7A1462FAF -:10C3B000B766BB30F5F9EB15CA574A432D9564CAE9 -:10C3C0007764F87E928EF47BC312688A473A8D6A4E -:10C3D00017F139CC37FBE35387EE25BFEEB2B9C96D -:10C3E0001F36EF182DA93DC47309E8EF3C51F292B6 -:10C3F00030250C1E8A7BD03DF7245F2DE916964729 -:10C4000032FB807A37D301D664D4B79933257713BA -:10C41000F0733F24711BF4E1F85405FCE4FFAB9D7D -:10C420004AD09EC0A0791D08E70C0126D8699CFC63 -:10C4300077725F85E2D6EBE821C22B7B64F81E3E63 -:10C440009F51FA97339437DFE86CB5929CDCB0E7E4 -:10C450008163F7E23834FB8B493FBAE206FFFB9673 -:10C460004B891B5A28AE443A462477C843F14EA262 -:10C47000E28ECE07F4F6B674910F4C6DF2CB0948FC -:10C48000CFCE3781E3385D1F11BF1504BFAE17D57E -:10C490002E25382C81FCFD239534BF66BFCA74D18C -:10C4A000F542D7033D0FD4F5A04A7EB689E69F3802 -:10C4B000089C4F8FEAF01D799EF034C59DA59D2DF7 -:10C4C0009594975D286F1C73BAF5159AB7BDD1C7BF -:10C4D00072B4B57126B7C1C6F99A7CD6737F57631B -:10C4E00003F77737FAB9DDD3B84293CF161EDFD7FB -:10C4F000F838F75F6F0C6872BA919F8FCF10FEF714 -:10C500008B50E50092BF17D3451D071CE59C478063 -:10C5100022DA8B95939A9497453C65920FB35CE829 -:10C52000F200683724A4D78DE867C93FDC04FEBC5D -:10C5300039D8CE9CD7621D2B7D7BB958E86CE6F8C4 -:10C54000C36C0F174090EDDDB9F65DC4FF17B2EF75 -:10C5500032E6ABE4AF74FBB718C2BC9E5DBED34DF0 -:10C56000F594EFCEAFB834BF0273687E57DE1DDBA3 -:10C570003E5BB65C38EF2E1A2CF8AAE7DD183F02B6 -:10C58000F9E54840E6B87A7E5A4B02E7DDA59D09F9 -:10C5900014072CD826333F30CF540622DFE6697CBF -:10C5A000EB80E03BC49779E3E6715D6EFE1A233EB3 -:10C5B0000B9DD7F509AA3DC6693DE2590B0F7F4E89 -:10C5C000F5B95A8D5EFC1CE16968BF61D2AEA879ED -:10C5D0003119F1C99FC49142C128A207C2EF0E923E -:10C5E0009EED9759CF7A938BE3989F909C9F6A9C7E -:10C5F000396917CAFDF1B38D9C7F25653CF2887FB0 -:10C60000DC77C7AFB559DEA1199C0F856DA43F3A01 -:10C61000FF96938D44B8975738029468478A5D0A0D -:10C62000ED1F913C723CF1E323702F43FA956F7D2F -:10C63000ED20E947B9C3C9E708884447343F47EFCD -:10C64000F7353971DEA87D1E99C2F7E25DE1269AC1 -:10C65000A6FB1BDDFF8CEDE8947D5C17C8643D02F2 -:10C66000CC25BEC9B8783D32E79B4D946FA2413AC4 -:10C67000E99CC0F09E0C829B9E77D7B544BD69ECC7 -:10C68000598F9C80F02DD7F2C3D11F7B198E6A87FA -:10C69000CA7268D7F2497B8A053C517474D97C1BF5 -:10C6A000A9FE097F8CE13AAF19BEC919C28EAB4908 -:10C6B000DEC94C5FA79A4D794395DCB1E1D7240FD1 -:10C6C0006D716E3BBE67B6B7BA7DEB2D6EAF739DD5 -:10C6D000EC318ED4DB3A8B38371859A91652FE4705 -:10C6E000F125E5857A9E689EEFCBAA989DD18FEBC8 -:10C6F000AB210FC1E5B29C574EEB1A3E3F6F9EA691 -:10C70000EF5FB7ADD83537AA0EB226433F5F505C16 -:10C710009F38BAF976B1FC2DEB9C69F03FFFE9F147 -:10C72000DA540C7324D4A13C2920E20810F1C42C63 -:10C7300008713B1B3AB9F5A124513B17DCDCDE063E -:10C740005E6EBFCEF4AD26B989583BFB931E1F7BAE -:10C75000E1EB5C928B63DF1BEB4A53BBFDABEE6FEF -:10C760002FD5AFC6D2F9520FF2B041935BDD6EF711 -:10C77000CA1F93DD8E8C40FB807046368B73B148A8 -:10C780007C6C80CE0174FB007E63BCA8DB8BC2593D -:10C79000EE37B85EB84FE6BAA5D97E5429228F0786 -:10C7A000C59D43F5517DFF260BCC2739DB88ED1F56 -:10C7B000108F3EB3C28A1A85CF760D8FF21BC60347 -:10C7C000E52F535D223F9CEA80E4D364DBCE9ECC10 -:10C7D0009D8186602AC5A328CFA3923C7F227AFB45 -:10C7E0001F1A97C8E70F647F8622FF3E12E736B014 -:10C7F000400A64213DB6B4897EDEED898CDF4D10A0 -:10C80000643EDE0C612BE17F0B00DBDD39A0727B27 -:10C810002B78989FB8725C3EDAA1DBDB9491AB1069 -:10C82000CF82A4CE74D2CFBCD1EF254908573EC5E4 -:10C83000BF4EAECDACA03845C7C39229F0B82CD3BB -:10C84000F336C15790145AB59AE2C2CD16A0B8F08B -:10C85000D3D1F7DC01517EB524ABE220CD7B4E1263 -:10C86000E785FE6D76515783CEFEDEA878FCEBCCD3 -:10C87000CA43A4F7FF20D838FF5DC5E748D52E414D -:10C880007B18DF8F6980EF0DF1E6F5A49F7EB68FF0 -:10C8900005444B5127F44329EFCBFDAF9EFAA2BAD2 -:10C8A00059E0E3A778AC24CB17A1FD0A6C680A090C -:10C8B000FE27EC81751C37D50FA1FAC5BC27ED16F4 -:10C8C000F2E3EFA11DA673D30F1A1DDC7E88F90DCC -:10C8D000B57FC3FC86DA8F30BFA1F6EF98DF507BBF -:10C8E000FBE9112844003FCCF4FC6FC679F0E8DD89 -:10C8F000CE083C2212CCECE9BCEF5486C83FF2DBF8 -:10C900003E7E208EE4608BEC2639CDDBAC701DE2E0 -:10C91000F8D65101392D9AAEBEB84C84237FCBDBBB -:10C920008F8E2DA2F7149784F38F6F39D99FF3263A -:10C93000137C5DF4D86613F4D0E07D2E31B48ADE2A -:10C940007F6E733A41887604841C123F7BA8A30152 -:10C950002C633EBE9E21E2A76BED9D45D1E79B4037 -:10C960002103D52B353F53259F4D08E76A75DBD151 -:10C9700024D7996FD07EFE3D420F91AF86BA44A571 -:10C9800026877A9BB7CDE6257D7A6EDB3BD32623BF -:10C990001DA68E99542CABDDF30B33FBF1BE79A3AE -:10C9A000CFFC6A7532CFE7738B1B606D950BE7DDAB -:10C9B000E4D8F12A91E066D7475589D8BF2545DAF2 -:10C9C0004DED1C356D4212D90108F03EB7E694EFEB -:10C9D00026119BE2AEB6915F2E27A58AB2BB958E3B -:10C9E000383A49EDEA57B9FA1AFA57A50C32CC9FF2 -:10C9F000A46618C627E70C378CEBFB4E71171AE6B6 -:10CA000091BE52DC8C7830DF61BDCCE732799BBFC0 -:10CA1000787F11E37F4311E11F41FAD930B03852DA -:10CA2000BAF217ABC96C6CDE99C0E7B4A6F8B4666D -:10CA3000DB53BB3D6AEFF1E997B0B5C7B8AEB69727 -:10CA4000B8EE62E353B41F8F92FD2878E13A3E7747 -:10CA50007F6EF499CB54C4CB9789712BD93D53DCAD -:10CA60001AD1E256B3FC74C9A9A40AB9D92B03C5DB -:10CA7000417AFC6A961F800734FF2FDA4BD5F3A961 -:10CA80006F097FF50FD2F7BED172ADB5A67A44819A -:10CA90000DFD0AD509FF2AC33A7A7016E1D0E99F45 -:10CAA000D12DF770DBDA570716F1737F3C6E59AB67 -:10CAB000D5277E95A99DF3D7EC78756072F738DCA1 -:10CAC000F591613EDC27ED36F49BD38CFD87CB7767 -:10CAD00047BFDF9B1D9AB7E64E9B8FEAD28F893AFC -:10CAE000A5795C87A76A678C87ECA5B2D5CEF9508B -:10CAF000ADCBC3F513A597FA896E176E90A1BE272B -:10CB0000FBB65E5B77CACE1890BFC5BAEFA1AC107A -:10CB10003CFE17859F79AF8F07BC51FBB4668AB87E -:10CB2000EF5862CB8FBFC279C75E023791FE58A221 -:10CB3000B0B7F96D9F5A2CE4276285BCE4BBC2965E -:10CB400024BAEF323FCE4FE7C9750BE2FD746E5445 -:10CB500090DEF98E0359BFE569DFA30E94BBF72D74 -:10CB60001683DF8990ADC3FE8E4CDF34F23B9377A2 -:10CB7000C6042DDF029F1D9920FC5A85D0F7D924C9 -:10CB800037FAB9189A9ABA07C1704E46F853FFCCD3 -:10CB9000D3B7BEF518C5BD7B85FEE3B0D39C8FDE51 -:10CBA00014958FC21AA1BF0EFCA53867E1AE161B03 -:10CBB000E549DF95DEB7673ABBF57BD8B9FAACEB50 -:10CBC0007BDD01A1EF27B67EF916D9F513E8EFA2B8 -:10CBD000F5BDCB2F6A7A5EF7B8CCFAA83F3FBE55B9 -:10CBE0009E18E881BEAF697200AE6CC3B9D992B22B -:10CBF00053D3C8AF2DD9A6F079606FFEBA6E85F118 -:10CC00009CECB9EDF6F9E21C59E011D1FDE9B62F23 -:10CC100093CA7345BB8CCF6B5B34BB23E218F4A380 -:10CC2000D664F2A3D512D7DF0E6C1BC0F7330E48C3 -:10CC3000105447F212D739906FD3C572F4DC49F122 -:10CC400018A4E428B4CF348D9FD3B5BAD08C6D33FB -:10CC5000B2885FEFB4CD3DE021F4B232587EAE072A -:10CC60003FC7830712BDA9744F616A9390EF038990 -:10CC70009D1D54473A501627D17914AEDF1C1DEF85 -:10CC80001DB07A53EB192FFD7CF20AF99BB84BC803 -:10CC900083357B88FCF44B229F63F957063ECC72A8 -:10CCA000B50002BB3DB86FAD3BC871E9221079BD3C -:10CCB000399EAF1DF7998DFC8239FF2CDFB2E3203E -:10CCC0009D7B9C538730C9EB85EA0EE6BCB7B7FA6B -:10CCD000C1A8246F615654DDCF1C9F77C5A17A1C73 -:10CCE000B53E8ECF855E29FBEFE38BB07FD7FA3858 -:10CCF00017E5D9479FB4FBC92E1F5D670F48387EE3 -:10CD000034A9B39DF28EA39BF2DCB802CCB3A8BFCA -:10CD10007B96FCFA6FAD2C1700C67B0D4BCAEEE676 -:10CD2000FB7F4BD6C74B740F0752C4B89EF3C9CFD5 -:10CD3000C4735CB0E0F9817CCEA9FB17D20F3A979F -:10CD40003EF2448C8782FCA37BA6F7A17A5F87E53D -:10CD50000F7C9E0FF27D87E8BC7ED186F891143F50 -:10CD6000402E30DFE6AFBB9CCF377FAEF86610FEBB -:10CD700095CF5C3380EE952D78BB1F103E91ADCFE3 -:10CD8000F3F95F779CDE737C77626B461FC8EDA674 -:10CD9000935E075CF1F4322FF1BD5852C5390DD4C2 -:10CDA0007B06915C6CA9065A77A42CEE8D76AE8C2E -:10CDB000E3B8D42C773559220EACD1EB0D7DC1915F -:10CDC00042FAE303A64364E5F075741ED69C95A46D -:10CDD000F9E9CEEC6951F712ABE4F6DA97493ED7A0 -:10CDE000D8B90ED211D3F33958435622CF9FE7302A -:10CDF0009E9BD7369C31F67331BFC3F74736A98562 -:10CE00007762BB54A3FFEA54EFBD59F8FEC2D64780 -:10CE10005ED8C77459F3C3F769DF3D4E517FD927F8 -:10CE2000E8678EFFE739449D03602DEFAF3FFFF4C5 -:10CE30008977F97CF5D3CDC3B3C5B971E8935FA702 -:10CE4000F179F1A17BB1DDB4E72DE68B19DE73CE6C -:10CE5000FD2489F1AD213CFAD2F9AEF71182131904 -:10CE6000C179DBDC55794C3FFDFC2D72B4E7FC4405 -:10CE700087535F5F874F5F5F9FF76496C863666BFA -:10CE8000F9C1315BE8389FA3BF305CA2FA5ED7F3EB -:10CE9000A4507E6294BC7C57F5F41BB57AC841CB94 -:10CEA000B21FD8E89E5CEB6AAB2FDAEE5D621DBD67 -:10CEB0002B0EF480EAEA2F5C09FB2D444EE94FE784 -:10CEC0007D5A9F9401FBE334F0248287EE0D6A2D96 -:10CED0002CF4A5709D9CD693E91A6280FB4DE56EFB -:10CEE00095DA2B25AF22EE7D0558FE2740FD60C266 -:10CEF000C3E208F3B9987ECF6546E2F26BD270BF09 -:10CF0000E67EB09CE29866ABD00BFF9C38CEDF7417 -:10CF10003AE97E065CB906FFD2EC0255C175662A75 -:10CF2000B0C29A24E60D453A1FD833F7558A13DE6E -:10CF300055EAFBD1BEEF391FCB932C14DF05E22954 -:10CF4000477CFFADDF16FF15E77E009E3227CACF74 -:10CF500075AF39D8EE9BEB11B7838FFBF3206CFDD7 -:10CF600002DFFBDBE87FADDF09DD78FD6DCC579B91 -:10CF7000293FB829F181627A5FBF8769BEEF77D414 -:10CF8000E5E47B81E67B7FD782EF33B25BA72CBEE3 -:10CF90005A51FFA81F45FE3792680309E747FA690F -:10CFA000F438064C8F88557BFF7395FB459523B964 -:10CFB0001E09A754B6C7634DFEA668B845E461DFF5 -:10CFC00088F9659D8AC1DF141568759BAF558E4B36 -:10CFD000AF3CAD9CD71F3D942DEC59515F4B7D4F1D -:10CFE000F1A19A2DF4A70982B2C047C40963BBE43A -:10CFF000CA2313FF6AB57E2DF93394A74882C34F25 -:10D00000171DC76E15F2355609EEA016AD2B34501C -:10D010005CB105FD9D0E079D11A60C673918A3CBC9 -:10D0200027AE350BE72D97EA396F71503C83ED2A17 -:10D0300029C4707C0F3AB9F5687EBC02DCDC8E072F -:10D040002FB7289FDC4E84166EAF86566EA74048D9 -:10D05000F8FD2B824DECCFE03E179F5B4C9A67A109 -:10D0600078A3E8FA9EF3850A8D4EBDD30115AEE490 -:10D07000D2E9300150EF327AA0C7E01CB61F667AC1 -:10D0800098F5B30CC232EB2719860CAA13A8ACA7EB -:10D0900095E0E17ED545D2A134EC53B84E63A64766 -:10D0A00065CF723159A3C7BFB281E543E7D3FDD93C -:10D0B0002A3FD7F9857A9542F26FE6A3FEBC28AEE7 -:10D0C000E2245D4DBF237BF874BA57555458B19490 -:10D0D0004CF2DD1BC64CA77B5545632B9EA723CF87 -:10D0E0007BB2C7897E4145A1D58D598B54367D3C95 -:10D0F000CEF769F79261A688AFEFD2E216DFB21FD2 -:10D10000B85DA827BE54A79BF07360704FF759E431 -:10D110000C713E38646270A715E71D527C73B2290A -:10D120003E70041354A4FB5DCBAAF8DEDA4336311B -:10D13000DF6E1775581D2F7CEE8FC1FEA64DC3976D -:10D140004AE9BDEF8FEBD6D2BABE65597ED257DF22 -:10D1500066C92D3859316026EA6747C80A540FD589 -:10D16000F7C94EF52DCDE673DD6CAE930DD2E29985 -:10D170008E4DC387135FEECFD6EE6125A71512DD66 -:10D1800096A57AEFA7F99178215FF76B7CE8ADDD82 -:10D1900090EDB92FBBF8DCE7917F2000F8FECFB20D -:10D1A0007D0FD07A757167D9BF1F1FF1F6F2705AE3 -:10D1B000B79C4AC8A459887793070236F603DA7DEC -:10D1C00075EDBC2A723BAE837428F2FA9AC8A48D1E -:10D1D0009AD55942F613D7FD2F5ED7161E3202DFBD -:10D1E0007B6CFA219B90B3C142CE343BB46DFBDE25 -:10D1F0007B0789AE17A2F4AA6EFB99AF3E40FAD521 -:10D200009D70BA697AB73EFD7229E793E034D80D74 -:10D210005DCFC66CB1735C3D76EBE5B7D3BCB2B7FE -:10D22000DB3308AF2BDBC37C0E16D9F6EE2001876B -:10D230009E6F9C92BE8DDFA5735ACEE3368B73DA58 -:10D240002552FD2BF1D4FFBDE4F623FC9F6A7E43FB -:10D25000CF8BE76B782DDEBB7E39D545E6AFB97550 -:10D260000ADFE30988BC41C55FD2FF2F611F9F8F92 -:10D270002FDA68CE273A6DC4FFC5ADA6FB40940FE8 -:10D28000D3BD8768FBDE433EBC3D5B3BA74D855469 -:10D29000C6439ED5C7D783BD33E7BB8F83E755967B -:10D2A0004FF0CAB47FB1D2733DE1B9EEEF69581FB8 -:10D2B000E6697B139D9C9CEFDAC47DE12796BA5DFD -:10D2C000D4D7F4732DCA4A29C5D19DBF64F9D7DFDD -:10D2D000D3F575C10A712F1BD6F465992BD860F769 -:10D2E000105F0B360CE0FC02F3208EFBD66EB0AF65 -:10D2F000A07ED383B17EB980EAC99D97515DA529EF -:10D30000467CE744EE91EE8916A48B3AC719DDAE50 -:10D310006B7E5DBF6FDB95FFC467F3BDE6AEF1B01A -:10D3200062C8379AB4F8B988E0A338B0DE2AF2A709 -:10D330001801FF8E37BF1F4771EC66C51B4775E9A3 -:10D3400013FBD3FB400F74D3DB62742F709E73C644 -:10D35000E277A7649C8F5F458F6BF7D335F9FC6349 -:10D36000A307FE6EEDE6878E5795FC6CA58DEA1C33 -:10D37000B7818BEA1E4BF63ED544DFDB2C59095CA6 -:10D380005138417F285F3862E173F0317B0B53489D -:10D390001EDB347B47E7C26A945C95505108E7175F -:10D3A0000F86007D7F14A3C6821A9517C7E524193E -:10D3B000FAF1EECB0CEFF7294D378C83DF13CA2D32 -:10D3C000E98E5F133D5718E63F943081BFC7290BA4 -:10D3D000DDC175A5BE13471AC6ED28D774CF01BEAF -:10D3E00010F14F29FEB25F857A99E01C1B06F815F3 -:10D3F000CADD980E637C541A6EE13C3066BF62C889 -:10D40000EBED17A8335D3E4CD3ABC13058D8073392 -:10D41000BD8DF72196EC95398E5B928A81675AEF24 -:10D42000F4D6F54FA77B3FAF91EE03661AE93CD0E7 -:10D4300067A4F3A0F9463AA7D61BE93CB4C148D784 -:10D4400034BF918E192BC618E667B55418FAC31E5F -:10D45000BFDA30FFF2C034437FF8C61B0DF3F35A36 -:10D46000E71AC60BB62C3C2FDF47049718C6CD7CB5 -:10D470002FDCF323931C2A4CE762EDFB2C9DFF7EEF -:10D48000FC25FE8F056F9FA044E5407F13E9E3FF75 -:10D4900017FF170CD3CE1174FE5FA45DBD4AF3C312 -:10D4A000E6EFBCA6C6097BF3FA9E13FB3DD87F438B -:10D4B0002DB4A650DCA4C5075EFD3CC294F7E97903 -:10D4C000CAB5A592E99C3EC6704E7FA17B6DC5A1F1 -:10D4D000A0A13F62BFF83E6AE441F72BD4167FEC6F -:10D4E00091A3BF871AFD05BBE573F24EFD7E9C9E9E -:10D4F0003741F3939C87CED2E127252839B7BEA8C0 -:10D50000E7A7E6BC55CF57CFFDDE4AC42577CBBD94 -:10D51000E5B1227FD5F3D6EF8387BF2BBB6AB06F0F -:10D52000ED30B4FFB2A5B32F8DEBF92C1196CE8D53 -:10D53000234458FE6EE69DE99E5CFE1E95EBDE0BD5 -:10D54000A5B7A7D33D7F04DF152E11E51FFA796932 -:10D5500098EF77B4DE61C9B5BC10DF7D7DCC674341 -:10D5600068BDFF1926E237BB8C1442FF3360960773 -:10D57000E8F9A824CF7334DF7C3FDBDC9AEF0DB5EC -:10D580003506B9555C6EBEB763AE0F862D2AC79DB2 -:10D59000FE1F497C4FE733026E7477BC726285953B -:10D5A000E315D0F2F19B35FAEB758B591A3E877172 -:10D5B00089F9E87F6FDEF21AF365514A8756EFA8C2 -:10D5C000E7F8FAD6C1CE917C0FCD53E816752EBD83 -:10D5D0008E31E892BE2FB910FE8B528E1AEA48F0B7 -:10D5E0006CDF8B3ADFEEC65BAC7F78A5A8471E5E8A -:10D5F00099CAF5EFEEF58F733DE9E6FA370D7A71CA -:10D600004BC37B063D98E3FFC8301E4EEEB452FD7F -:10D6100030FCC2C0093721FD8E6DB6F3F7D0280764 -:10D620001DC4577DFDF0CAE1E3F9BBCA0BE2F9194D -:10D63000C3D1DE1862FEEA781E6A3CC8FD706398AA -:10D640005B339E7A9D426F6D3B2187EEE7774AB14F -:10D650006EAA0B9BEB17775BD44F480F1ECA49D7B6 -:10D66000E2B5FA022FF34FD42BDAB5EF4BDBB5EF6F -:10D670004BDBB5EF45DBB5EF43DBB5EF402356E7BA -:10D680000AAA6BB44BE2DECF2CC9F3E41CDC2F6D8D -:10D69000B0CF994371FFC2CE7C05F7A92B08CF9676 -:10D6A00090CF79FD7C7DE8B984E9C240FE9EC8CF69 -:10D6B000F7C38E58FCF9F4FDCDE48D59D7511E788F -:10D6C00024D67F9C2291CA9CB4EB28EF3B62137A4C -:10D6D000387D63EC75A4771FE362849FFF2549D4EE -:10D6E000959C611B7D3F3535D93728A758DCFBE277 -:10D6F000EF66F039C9A55EE78C58451C18D1E2C128 -:10D70000F41C710E989123E256BD2D239EE3F3E99C -:10D71000D4B27E3E9CCDDF9BACB103C5AFB83F7F9A -:10D720005FA3DF33317F7F33F24F76FE4E42AF8708 -:10D7300096E4A4F13AF45D0EE965F24FE2D86E4149 -:10D74000383484BEE3E98277BFF8AEF218D591A3EE -:10D75000EACF2539A20E03B781E13BA0C57B0F1F9D -:10D76000A23CEBFD61BE3144D7B916B584F8BA3896 -:10D770006107D7BBA6E4A8BC2FC2CBF8A2FD6926DF -:10D780003E2D7684B93E76A17A786FF81FBB3DF4C2 -:10D790008B5CAEFFAAF9FC1D9EB62FC23185E8AFA7 -:10D7A000E3ADC3D1BDCEF9E55FAFEBEAFD4F9F78A6 -:10D7B000285BABCBDFE2EDC19FDEAAD1A5DDDA733A -:10D7C0001DFD7E8DBFE7F0671800D5EDEDB1E823B4 -:10D7D000B0ADD7E874EC06C487EB139E11C4DFC567 -:10D7E000D39CFCFDB9BE3EAEE3FBC379F6599DEA7E -:10D7F0005D48F82FAC1775777D3C2209BEFA578A31 -:10D800003AE8E2EDEF1DA2FF0FC28267F20A39BFCC -:10D81000D7DE37D319E9CBDF45CD95C5B915D2F79A -:10D820006EE2B3B9DEFE6DE91A4915E7AB91B56753 -:10D8300086D03DB2C5746F8DBE0FD3EA57D066ACAB -:10D840004B21BDFC54AF38F73C0AF85CCBAEF91164 -:10D85000BBFEFE60C5F0FE31A7F7A7449F1734BB9F -:10D8600081F30316DCBF4DCF934D7594B690A87726 -:10D87000B6A5D8384EA67887FC931EEFDCF5A6A88F -:10D8800077DE9526E268828FF82B1DDCCD714297FA -:10D89000FF97DC2AD1CF69F505687FF02D65FF255C -:10D8A0000F45FED2F9C59FAFD6EA01C21F166BFE27 -:10D8B000AF98D6A10027B70FFBC5226D5F8C1FB9AB -:10D8C000EE361A7C4D0218AD6EB672B7A18EF07F9F -:10D8D000947817F25045000000000000000000009E -:10D8E0001F8B080000000000000BFB51CFC0F003AD -:10D8F0000917B1A1F26FA0F1533951F9BF5951F98C -:10D9000097D0F884B02E1303C30A46D2F420E39DC7 -:10D9100040FD0780F838109F6322DF1C103E2CCC9E -:10D92000C0F04D8C81610E906E03D2E781F83B1000 -:10D93000DF05F2C5441818548178A12803430C90E0 -:10D940005E0EC44522107D4780749D2879766AF268 -:10D9500050E6E6514C195E2D8DCA2F5701A647554A -:10D960000686B76A10FE622479267506860A1508AF -:10D97000DB408E81A10BA866B63476730D81F2DD93 -:10D9800040792175081F00B5882CEC680300000061 -:10D9900000000000000000001F8B080000000000D5 -:10D9A000000BCD7D097855D5B5F03EC39D879C24ED -:10D9B000377033C9490C1835C04D0C838878120371 -:10D9C000064DF106D1C6FEB45ED0DA481922F26ADD -:10D9D000B4B6B94012C2A441B4A568E98D554B79DB -:10D9E000B646C53EDAA7F482F8446B6BB4D4E1695D -:10D9F000FF469EB5D65FF9E280536DF9D75A7B9FFB -:10DA0000E49C939B04B5EF7D0F87C33E670F6BAF1C -:10DA1000BDE6BDF6BE6ED9C5D804C64EE09FF3186C -:10DA2000BB5A628CE50D3D9937D6C4228C356B6E9E -:10DA30007D530963DF546287F56A783F5E8EDDA30C -:10DA4000E3FB49752CCC9882F5F3198BE1FFA0DD3F -:10DA5000FAE0BA718920BC531667E1D3ECDF7C365B -:10DA6000AB8C6955F87DCBA44CDFCD274BB906FABA -:10DA7000BD8CFE9C2865ACF59597261F32CBF05FD8 -:10DA8000010B455E0FC05F66B0192714C6DE0D2E70 -:10DA9000CC4AB391FB7BB3ADFB4C7522631FB6BD83 -:10DAA00038F9D0C4E1DFBFA9B096DE8AE1EF673074 -:10DAB00018741AE223E98E4F1E9AF7E03C8380A483 -:10DAC000B3A13D63694F0E3C776F3B532D1F82D34B -:10DAD000390FC6921CBF9FB39D27529B2E8052A523 -:10DAE00094984D70A9F0CF74C6A82AACCBB2DD8D46 -:10DAF0008CE072C0DB11F9E7C03BE27A897AEF066D -:10DB0000D7753268B7DEC5E9A53D4F8EAD63C3E971 -:10DB1000C55C0F138F27BB1E37301F8D63D251B3E7 -:10DB2000BC78D4751F8B8EAE443A3AF3BF9F8E9269 -:10DB3000FF7BE9A883FAF95F46478C75737CB17E59 -:10DB400015C71F7ACF9F91C5BD12D21914FB10EED5 -:10DB5000623E142B6EEDBC569E02628AC59E3C0D41 -:10DB6000E45671FF9206847BFC2BF3FF8ACFCE45EF -:10DB7000B5F573617EF94DBDCF5E00CF483C2525DC -:10DB800060BDB63319850AF4B73C5903F36BC7CEB1 -:10DB90006631766F728991C4F93283B1718CFD8BD5 -:10DBA000981363B2AE4239447FCD340F374B737C48 -:10DBB00048273CC3DB8F34FF10B633EB94E0FF57AC -:10DBC000339CDF58EDD81A3E5E12FE417C170E8D55 -:10DBD0004FFDE4375BCA0CF163FFDE877F21FC5EFB -:10DBE000FB3F325E01ABF2A17C0835C85A0AEBB3A9 -:10DBF000DE6C15CA91E52A4B838C28A8EE965CFA58 -:10DC0000D8EBD2C9587D2F5F1FA9313404DF9F990B -:10DC100044F473CA8DAFF56C00923BBE381823FAFA -:10DC2000D018CBCD193E9FDBDB90902DE545B5524A -:10DC300082C68B3D5906ED938BB8DEDBDEB030DB60 -:10DC40002AAF3C9224F0E6A40FA6ABD391AD387D69 -:10DC5000A80DB2E19BF2C5E943FD9CF491B7C6D291 -:10DC60008E7DF6F58A9876C149D2C7171DCF5CD74D -:10DC7000E17CB556AC6B998F01DFDE5ABF30A39DB6 -:10DC800031F2BA5611BF471A9891CAD02E7F703D13 -:10DC900093C39FB03ECAE0F25E675B2F65FCF4A6BB -:10DCA0009E51F0A144ECF335FBF5B52AFA6BB9505F -:10DCB000543519FB73637F40671BA3B72619F0C364 -:10DCC00071A46DC087D25D99C6322B63B17B040409 -:10DCD00032947D5123B589E82045EB62C2E7D165D6 -:10DCE0001BFED588DF56664D49C90ABFAFD54D70BA -:10DCF000B8713CA07745830E01156A90A57D61AC93 -:10DD0000C1E1473238712A96BF6DA3832EBD8A6563 -:10DD10005A07935E11AD9C5EBF7D72F2C539DE225B -:10DD20003BBC27DD2EA8EAAF5BF4D0C8ED54F6BAB1 -:10DD3000B93E80C4ABB0836943EBB4C1C5F6495367 -:10DD4000415F175DC612F076037E3A9BE894EC992A -:10DD50000D45551AD215DB2DA908A7A947593487B7 -:10DD6000EA554A3AF5237B5B18D65382063DCDEF40 -:10DD700023C325E82F691C28837EBF24D6F74B4296 -:10DD8000AFB16AD76BFD26DCA467D5A132CCE3ED39 -:10DD90001BE07F4027C94A29758F34FC7B03EA4585 -:10DDA000904B0DF8DE2257760CF24194D6AB417CB5 -:10DDB0007BECE117269D05F4D11753188AAD750F3A -:10DDC0007B8C3AE8FFD973A5944712F0029C0B04B0 -:10DDD0009C4F1BB9C548A77D751EA2E305177C188B -:10DDE00041323EB6EFF76A267A5930DB350407FC3C -:10DDF000B7CA3A3FF8EF2783EB5244E39870ADA8D7 -:10DE000052088EBED9520AC739F4C7BFDC7C0EC097 -:10DE1000F974B514F3E8046F88C1787DC67B91511D -:10DE2000FD0E737C9D69884FE7F8E67A840B19E153 -:10DE300095FD09F00AE3256B07FAD7239E8F4AB1B7 -:10DE4000F5305ED69CD609384E892C13BC1B677BF7 -:10DE50006505E887BD384E467C06059F67B9BBBDA2 -:10DE6000A7029C9D13657617BCDA5836BA3C6B77CF -:10DE7000C833558B1B12B4D7935A95320A5FA40C42 -:10DE8000B93E93BC7B4AE27AB223B9502BC3E91D59 -:10DE9000B2DB81A897E216BD0AF6E25312CCDF1579 -:10DEA000E1749C5D17E77662DF38925F01B11E591D -:10DEB000531666B10C76F088F3808132D9CDD93211 -:10DEC000878FBDC2FB57CDFE7346EF7F83E8FFA36C -:10DED0006689F5217C6ADC8BEBCF8C4AA267BFA0F8 -:10DEE0004FB62687CAA6DCF594C7BB4A601D3D51D4 -:10DEF00099E93ACE2F49EBBC19D6B80840F1D7C101 -:10DF000077A8BAF9EF0AD925D9F2F16412E0D87CE2 -:10DF1000E01AA6839DEA8FA61895275FED45FC6C55 -:10DF200006A5C0C7EF65387E00C816E56B00E4ABF8 -:10DF30008EF255EF4DCB5056EB59CC804F212D260C -:10DF4000F981640E464BD7AAF0BE7D3123FA65688D -:10DF50004558F0DB1E7DCE5000AECE2646764D678E -:10DF6000A496E6D75E51EB2D417BA741A5F7EC5374 -:10DF7000C0876987803CF4973303C7DB9CCF52414D -:10DF8000E4A5BA3CA247B7C6E7AFEF2863E9B3E020 -:10DF90007BF6F403387EF23B2C36910F49724D35F7 -:10DFA000E9424D2425F4EF5AB5D8A60C74B7832561 -:10DFB000B2E469363A25BDEBC45B969B5D88F8ED0B -:10DFC000AC04FA2F19DE4F11F20FD05B2AB6F0E243 -:10DFD000D20CE394C83AD18759D63F7213FC23D5AB -:10DFE0001FAA0776662E766D4888175617A1F9E5A1 -:10DFF000B0C13F069673C57CC7B116AA179DD97DDF -:10E0000000F9ACC0E8AD415CDC1EBAEC595A377679 -:10E01000A786F10880B6EC44EE909C30825C4EBC42 -:10E020001B93493E86E4B4664007215F5F9494B534 -:10E03000CEC88FC8C22600F0A6B6EEC9E85F8659E2 -:10E040004CC2EFA1989AB4CA9F2C06659BFDC78E5F -:10E05000944D27D2E27CC1B403C8325A79CB69D837 -:10E06000DF7600C8077EF2965082F4C587BEF014B2 -:10E070001CEC43399E95E6EDCBD1EEBE5EF1C73682 -:10E08000213DC4B87EF0C23F28FFB266AA36799C13 -:10E090006DD8CBB90EBD314F09D27CB3BFC4843E1D -:10E0A000301A268E1B820F206B44BAD956A7321C19 -:10E0B0002F18E4709970E62A9FA66546701C4538B3 -:10E0C000003D0447B89C91BF07F01C75C073D40194 -:10E0D000CF512B3CAD5E3E5FA7DFBF54167E3FF8AD -:10E0E000BDA8078FB3B78C7A2418A398F44A58E3D5 -:10E0F0007583DE3E32AA34A6D1FA3BFD7E589F7767 -:10E100006DFA61A628EB60D797127CF6EFAC88E831 -:10E1100084CA0A1BF45F97CE34F1A37FF965E0BB94 -:10E120006B0EBB18F215F0AF82DF5DE2EB35C28FEC -:10E130005D8AFA1FF4F6552C1E46F8DE6632D9CBFE -:10E140006FB3E7C26759E4E276D92DF4382CA8956D -:10E150007F592C8A7EB51AECEC53C2840693CEA468 -:10E1600013B46E31467E7790D35B9279D7927DD18E -:10E17000C5F5A3E9F77DBDDBAEAFBFB1C35EBE9A07 -:10E180002D1C87F475F56D2E96827EAFB1DA1FB027 -:10E190003E37CA1AC1F70DD6D2A905C9CE6AC279CF -:10E1A0002CD5988A7EDA8A7FFBE1F425309F9D4248 -:10E1B0008FBE09725DB7E88D659194DBA8183EBFEC -:10E1C000F5526CC139D2C8F3DBE0EA5B80F64172EC -:10E1D000AB8BFC3AE6F4D7F62AE4AF59DA11BC5718 -:10E1E00076D9E737D6FC9DF3058F85E6BB6CF71231 -:10E1F000D29B23CDC7BD5B325219F4DB03A63E147C -:10E20000F2C5A46F93AF93B58CDB7BFFD7975A0F02 -:10E21000E3FD01E523AD7FCB541E47699981CFB162 -:10E22000DAFDE7E76CF7A7CFD9EE3521C79DED56AC -:10E2300078FBDDB89EABD464BD240FD9D15E578B7B -:10E240005108A870EDAB49A32966A9D77592F50EC0 -:10E250004BA52755AF5E1EA5BF63C2CE78E2BE1F99 -:10E26000BBFB91FFF6BCBA00F5FB37FF5D615E9822 -:10E27000D7B1FB422C8DF4A9A6DC68AF2C03BA4AB7 -:10E2800051393DFD128B5D05144BFD7FF3FE10D916 -:10E2900007CB1EF4A41AA0FDB25FFCD71406783891 -:10E2A000B66EE03F0A915EF748DCFF4BF64FB904CB -:10E2B000DE2F53D915F10C74222B9C5FDEFA65A07A -:10E2C00009ED3E69F781AF51BFBD5F76A15C36EBCA -:10E2D0007D8CFB007954CFC0EFC99F4AA989128772 -:10E2E000AF71F270BFFBAD9F4A1CBE7DAE940FE1D3 -:10E2F000DBDDE34E40BD55BBDF21BA3DFFFE9F8510 -:10E30000110FABF629367F77D56E25ED9942CF57A1 -:10E31000F1899A51027E5B29F875E5DE15A407564E -:10E32000F66E7E07F975D53E974DAE035E6269C401 -:10E33000EB0B4AAC01CB0FFD24AC03AADE8CEE093B -:10E340006B15D4EF1237D0D5C533EDEDB0FF8F721A -:10E3500086F7C7D800C53557F56EE4E331AE6F4C8C -:10E360003E7D13FF923F5C6F9CAED8F71D8EB3A726 -:10E37000A7531C72776E463FCED41726BF7EF36735 -:10E38000C7772561DCB71EFC7FBB9200FFF27FBC24 -:10E39000B7EBDB302FB6DFA7A11C5AB5E70F6166DC -:10E3A000C17B9DC2FDB0633FFDC9BD3B815F8EBD9A -:10E3B000E421BBEED8A37F394587791F7BE0E37169 -:10E3C0006877AE7974EE78A4AF350F9F3F9E8DE2EB -:10E3D0003F20BDA63CD6754DD1BAEAFB240CC23015 -:10E3E000F688783AD6E7B1BD4A1A43B76FBFE84915 -:10E3F00079003FABE05D6B15AED70AD24358BE093A -:10E40000F0BCF2BE0DEF285332E13B592847F10929 -:10E410006C13C5F5BEE4E273ABF1E98AE9481F6C01 -:10E4200080E4BFB3DDAA23B0AE53475EC7E3EC532D -:10E4300037E27FD57D1BF9B88E757C1BFF7276069F -:10E44000FD3F6C1D97FF68277EDC9B4BEB3ED23A6D -:10E45000AE78F8D251FD33531E8C85DF6689C33503 -:10E460005531562BC8570FFEEBBD3B237C7D1B005F -:10E4700021C77E76FC140C2EBFE11AF81ACAC98196 -:10E48000473DDA5DD066D9A32F109F1D7BF859B7A1 -:10E490004E72920525D07BC7D8E09F3ED4832B25B2 -:10E4A0005E58757728ED090FADD3CA5463BD1EA61B -:10E4B000F7AFD2FB14A7FF95A9038BA40CEBB647CB -:10E4C00029E5723995477859A1F7B9B5A07D3DA5E1 -:10E4D00099B88EAFCE43BA1B691DCDF96B38FF19C1 -:10E4E00096F5BC9BF3ED48FC79ACC7A34A5943EBC6 -:10E4F0007B4CD807AB52D20B2C03DF32B68EC33B1A -:10E50000C2FEA3F974D2C3DD0E7A30DB9BF31E8BFF -:10E51000AFC79ECF67C3D76D8A6EA31B136F6F7D86 -:10E520009A59DEA7859C58C992F505A70ED7572A98 -:10E530008B270B4B86E0EDEC55488EBFB55B213B3E -:10E54000DD2917568EE08FFF4EE1F6C7CA7D07A67C -:10E55000A0FC7AEBE02F051D723A5F79DFABEEA4E9 -:10E5600090FF29ABFCC7FE32ACC78B02EE558F641F -:10E57000EE6FD57DEF64ECEF4DD5F832C2FF669FAC -:10E580008B25A18B377B958CF18D838ACB16C7EDBC -:10E590000C4D7F310BE39B61BF8EF35EBFCE7821C4 -:10E5A0008976C8732E4676A01A7BC303DFD787FC13 -:10E5B000B4EFBD3E7C35D32D7ABADD8127351A27DD -:10E5C0003F588DC4AB79EC3565F3475D9A6C839BFE -:10E5D000A9C9228CA7FCAEE42F2AF6FB0CDA7FA790 -:10E5E0000DD57F46651DB9D0DF3386145BCB32C4B1 -:10E5F000A71CFDC7672B4CB7D299512E5BE3ABE14B -:10E600008337505CA295B5A4314EC48A58EF3D962D -:10E610007EEF6CD3581AC667F5E5B235BEEA696974 -:10E62000313C0047D11AAD144DB391C62F6E91ED18 -:10E63000716D31FE6A114F60BBF7ECD903FDD6E373 -:10E64000B752F46378BC0ADC29B263CE1772F0D7F4 -:10E65000C20E3E28C50FA19F65E8DB54947352D9C2 -:10E660003615ED89F99F76AB4B2DF438BF6C6D11E3 -:10E67000D2CBE1BF2B4D99E86A91CAE96A6DC98690 -:10E68000226C7FD8777D117742A334CF0231CF43FC -:10E69000C5DF08F643BF074ABEB16512C0551F5516 -:10E6A00018C65BEA234BB654C2FC0B8E28311F946C -:10E6B0000B9A936A62F2F07176A1BC07FCDD857853 -:10E6C00004F8EF6E8B52F9DE369D9EBBDBCAE9B9CA -:10E6D000A72D46DFEF6B9B49E5DEB67A7A3ED8166A -:10E6E000A7F7E11BFD09A4DFBD6D4DF4FE176D0911 -:10E6F0007AD6AA9CDFE60B7C58E64DFB608BDAC32A -:10E70000EB308E62E2CF89EF3AA0B81CDA37907412 -:10E71000C4F77895CB15275E5B5B836497EE929880 -:10E720000D9FD3556E47C6051CBFF6262E54E1F942 -:10E730006E7D5905D93D2C1E4339BD4B8ADF5209E8 -:10E74000FCF244F18CA855EE66051371356FA87C78 -:10E750004A178FCFCC50B97CAA676B0F65017CC676 -:10E76000A74C473A33E779B0462F42B978702DC0AD -:10E770005381DF65566EA133B3BF59023E16CC2CD0 -:10E78000A787E896F37F7456F9368C1383E3199BB9 -:10E79000A893D56D6BB74D35E3DE3AD1B14927C0AB -:10E7A0003F4F1447A81BEE2F3697F0EF3E4EE7ADD4 -:10E7B000FDEF507C2B3A8ED9E28D1DCD32F9393BDD -:10E7C0005FE171E9E3CDA5DB2641FD1AC01BFAED3F -:10E7D00039F3CBB21216BADE22E869A7379EA58DAF -:10E7E000A2BF3A453DB3FCBC2FF15D5C97EF4FF8FB -:10E7F000793ED2F34E57EA72948FADAF78F475300C -:10E80000A57F04E249FC1E2F82F700D2F1FA351EE3 -:10E810009A5A90EF3FB4DEA46F3BCDC2E7A1989D1A -:10E82000AF77B58E1E9736E1DE85708F129735E192 -:10E8300036D7E378FDA2816FB0E17870F69B337F25 -:10E84000D1A8E3DF897CE7213CECB2D25B518B4657 -:10E85000FB0C667B73BECEF6CEF90EE52B9CDCFE80 -:10E860004CAF8BE5E27A3EF0B7531E7A86E192C751 -:10E8700015946357A8895E84673A6BA1325307F2F7 -:10E88000915F5EF473FADFD9796F3EF1919A2A4174 -:10E89000BD70B2E375B078BC06F5564C8E59E5B93B -:10E8A000F97C5C35E304698A1FD116330C29076EA5 -:10E8B0008A66C2F360FF45EA5BD6FDA42D8C713FEA -:10E8C0003DEDA57D0E0C8868502E39CCAA36417FCF -:10E8D0007B843CA951B95F78D661BD47E1F123A59E -:10E8E0003164C1A388A79A71AC0E7613D3A0A95B3B -:10E8F000AD3C80D54D3E6C74279E477CB9A33AED64 -:10E90000BFBB2209E22B26E2DFC5224E3F57C419C6 -:10E91000EF69E571C65616BFF034E4EB230A23FF16 -:10E920003871AA8D7F9DF33C20E8EADF85FEFBA5C8 -:10E9300090DB65EA01290BFA0FBD913E1886E7BF0F -:10E940000939FEB090E307B7FD4709E6137424DCEC -:10E9500031C469B8DA9F96C00EBD79FA1BFA3550FA -:10E96000BFA37B523BE267C31A1E977F08E53EB404 -:10E970007B40C8FD704BE7B5B46F27E44B91992FEE -:10E9800020E4499190278F6D7B7EC9069C5FC24B26 -:10E99000E3B4B2F49318D7676B64B253C2BDDFBB64 -:10E9A0000EFBB9BFCDE0FD76EFF917B4EF7FE84D70 -:10E9B00057FD06E3FFB3DDB124CAA9D4449B9C0AEA -:10E9C000F7EEBB1EEB857B9FBA81F261041E3C8F84 -:10E9D000C07CA14AD6AD87D321A857D89F46B31B88 -:10E9E000D6B567FEE9D05F59834CE1EAFBA4F8F99C -:10E9F00021A48746BE0F9D55B9682DD6EF5EFE5CFB -:10EA000012DB8F7BBA45C265CFF997BB6A107FF7DF -:10EA100014BDF6640D3C27B94A880E82AFE8F93F71 -:10EA200061D87F3C7A8D3E321D3EB67C354339E657 -:10EA3000B94DA67DFA7B6E5BCDBE61CDBB58AE668F -:10EA40008C8F4D7279F87ED66D0BFB50CE9AFB57AA -:10EA5000852BEABCC4FF4F33DBFEACB98F65B6AF84 -:10EA60009412935C79B45FC1F7B544FB02056D3C29 -:10EA7000285E27733E88A77DD67C93E0B5723C1351 -:10EA80003C335C2AC1D31EABDBFD1F309E3AE33220 -:10EA9000D2CBACDB0E87B31DC03183C3C1E133E100 -:10EAA0002806932008E3DF3AFFF97C84EFA3FA41BC -:10EAB0007DE347FFBFE376393D01D6676BBB4CFB77 -:10EAC000F707AB0F7A118F5BAA6BFDDCFEE1749741 -:10EAD00023F8E8EE7A99F8F67835DFEF679F9EA085 -:10EAE000FD3097F89E9377D04B7B18492358331D00 -:10EAF000D30FCC3F96FC02C04D55D26F939F726BE3 -:10EB00008E2DDFA0981538F2564A87EAA3FF5D7F65 -:10EB10004442BD1412FBD165E6FEB6F24A0CE77F13 -:10EB200087A917DBBCF4EC6939E8D301AEC75B8079 -:10EB30004E685EF6BC144F33A37915B4F07DB62D44 -:10EB40005ADF0137948B6E07D4EB68CFF5927C6166 -:10EB5000DD3C5FC0DCEF98B8DC9EB752E4C8B71963 -:10EB6000969FF519FDCC6B5DF67CC3E36CCBE94455 -:10EB70000F7DA5B675E9391BDC9AA9C3FDCDC17E11 -:10EB8000853FC5A25CCEE5F8F81837DFA834A3BDF1 -:10EB900014BEB02ADBBA3FDAE9E276D2A13F7A1896 -:10EBA000C6E337D479298E63EEA39BEBBD1593AEF4 -:10EBB00030DFA1FD5E1FD2CBCE48293D1F9BF594CF -:10EBC000AF9FE890E70378C49CD6CD7A6A7E33E0A5 -:10EBD000F5877932E9988EA2E7F2717FF1D63A2F64 -:10EBE000EDF78703FDBD8F4139F87D770CF7B7EF5F -:10EBF000A9493759FDD7FB5DDCDEDAE112FA6A8BF1 -:10EC00007DFF19F86007F2812718A7FD4BD92BF279 -:10EC1000261C7E8E898FF0C17CB964327F964E1E91 -:10EC2000B2CFEF1474B353C8FB2D42DE3BFB29690E -:10EC3000D60EBAD1EE5FAE552919F87242ABDD4E51 -:10EC4000286EB1E7D51436DBE93E142B70D8156970 -:10EC5000D263A63EDEE00B9E8A745F05FA92DB0764 -:10EC60009A6CDD6F77EAE33DAAB1CF45F6EEC9D9DC -:10EC700009E140BC05F1EDB4730F097CFF4D310E85 -:10EC8000227E036AFC908BF240E324679C76C330BB -:10EC90003819C0397954387FEBFA0CF6D358FB0396 -:10ECA0001FCAF11DCF00C873B298C8BB08911CEEF3 -:10ECB00008717FA5C3C5FD8477C5BCFECBA550BF39 -:10ECC0000382BEE604584BE67C321E2F7A1F0D13DA -:10ECD000AC373E73FE2E5A2CF4BD30F3F7F75D7C53 -:10ECE0009F6DCE84D1C7F900C781E7EF54E31D972C -:10ECF000651FE75197F19ECB12A7F8C8A5717E302A -:10ED0000D743E4E79AF6D33ED5F8D8DADE7CE6CCF2 -:10ED100057693FF738F3C714C0CFFE7CB697811C04 -:10ED2000D92F097CFED147794026BE07ED6B941F91 -:10ED3000A8075E09A4309E62AE83B90F332847440A -:10ED4000FD33DC5C9E00DD04DC347E9CEF17B234C6 -:10ED5000C9870241373B7D8B6FA983E7CDB3DE7C4A -:10ED600011F315DE7ED8A7235C5BAB8F86AD729363 -:10ED700035DBE9C77CEFFAA890F6E9BF2525F2DD7F -:10ED800016BBDE15197063FBFD924EFE5CF20F0A96 -:10ED9000D923FBA5D4E964A8A88CF633F65F134DFC -:10EDA0006DB2EC7738EDFC1C5FFF1DAB70DECD6003 -:10EDB0002FB10CF12961A70FDA1D517BFBB89B091C -:10EDC0003B1BA60B7C5D29E61D530D05E198C61281 -:10EDD000F49CC1747A823F50E586FA67B1817CE485 -:10EDE000A3758153CEE176C67F1BDE8CFF8D781B29 -:10EDF000A25BBBDE36F71DF2041E42AC85F6DF1FB8 -:10EE00006F5ABA71228CE72E0A923D9CD7D47EAD00 -:10EE10001CC66CBF3E0DFDCD3CB11FCE1671FD6C06 -:10EE2000EE4FE734D8F5B9537F7B84BDE11941AF8C -:10EE30003BE5E6487A7DB9DBAED707E3C723C83F99 -:10EE400067FC786CF9A7DF525782791AC60B756890 -:10EE5000D7CD5629DE193E955D11B7D0C3FF751386 -:10EE6000D1C193E7CD6C027E4D9DC6F99CA19F1048 -:10EE7000000584FB09C5720AF36D362453F5987FAB -:10EE8000B6419DA859D7B1A698DBB35B6BFDCD56B3 -:10EE9000BBF6753F8FA75E1BA8790AE9AA2298AA3C -:10EEA0002577CF0047701CCFBBC4753B5363FDB8BB -:10EEB0000FEB615C6F034778B95EA9D35EA7FCCC0A -:10EEC000043B11184D2FD8F331F7A8A9757EC4471C -:10EED00084C75F423B244ACE517A8D34E6724D0D91 -:10EEE0002CBCD3CDF557398E73603A98BB50FF8355 -:10EEF000036EB2737A43852ADA93FBE5A53F423B62 -:10EF000070E0250FC3FD94DEBF9F41E71A7A43E707 -:10EF1000CC433AE8951878B6307FE01F9EFCC302D8 -:10EF200018B70F9F6F308C5B0E3CCE6277C1F8AE86 -:10EF3000E84371CADB6546409E09ED7CAC0BF35794 -:10EF4000629FF8DF3B0FE8EEC160D5F6A96C280E92 -:10EF500060FAFFE7F9130F219C1DE3FEB319F9AC2A -:10EF60000BE054C80E33A20877559E4CFCC7F282C2 -:10EF7000A989F0BEE670A40EF3D16AD44A94340095 -:10EF8000075FEFE77D8947B19F3AADB12E1BEA5786 -:10EF90001FD1C95E9917BDF61096A7BFC2CB1D6ED3 -:10EFA00046F620F22FB3F05FCD47A7D0FC0E0B3909 -:10EFB000DE1E35FA0C6994F5D054C7790E7B1E8B92 -:10EFC000950EB4E9363A48B8AC743013E860B2959F -:10EFD0000E0CE9B3D0C1F784BC1D9B5F389F5CAFBA -:10EFE00070BE194EF72DDE9C8AE1FC618EBBA93AFA -:10EFF0002782FBAB261F68336ED2B0EC59E28E231A -:10F00000DF997C61F2C33FBC2E820BF8E2421F3CC9 -:10F010001705F5B999F802FD382BFD5F32029F2CD8 -:10F0200060038730E77E81CA925920427E77F61BC3 -:10F0300065A758E8DE89A705B32576D4228F4E9CB4 -:10F04000E0650B1EB5C13C68E5E4F1FD9CAA774480 -:10F050002C7CD709F6331A855D728CE59520DF2D5F -:10F060000D7AA6E1F98607A214DFF7C49B296F6D1C -:10F07000C65B81AB810E3F1827EB38F90E7DE9FDA9 -:10F08000C4BF2F0618DA6D5BA72F9B80FEC907D778 -:10F090002426609C7323E0FF281937A9F132E5424A -:10F0A000F58FE7FB657A943F1351FE9E89EF295156 -:10F0B0003644BD7EAA07EB6C9387DBBD9CBEB77B55 -:10F0C000B95DB8D1DDED45FE1A28F1D27EAA59EF1F -:10F0D0003C85DB6DB33C229EFCE97A1DFDFB591E8D -:10F0E000DE6E7B5B2AFEDA448473373D731B520C61 -:10F0F000F703FCE5491DE3F1DE752C91C9EEBBDD9C -:10F10000CBFD7FEFC11FD03E526E598CFCCE480321 -:10F11000F46759AF05809A2C901F00AE8174DCA172 -:10F12000FBC90E5B10A9FDAB3A65F8FAE29FA39606 -:10F1300075F2FE4349F472FF8CFC8B35C29FAB2BFA -:10F14000F5125F74B4BA7B702A8B3CD9DCDE8DD4A7 -:10F150008E9A3F8B7E5312D639057E133E717F23E4 -:10F16000791ADFDFC032EE6FE013F737F089FB1B4F -:10F17000F81DF737B0FCF33683CAB8CF8165DCE7FA -:10F18000C032EE6F6019F737F0B9AFAD999EBF6A24 -:10F190006BA1EF8FB4B552F93C0FB7B3597932BABE -:10F1A00010F0DC7583DBC07DEBCD627D1E334A73CE -:10F1B00063B08EBE08F73B7D4FDFCA703EBE288F1E -:10F1C0001775466F6557C2B36B5AA80B0359DEFB20 -:10F1D00083F4F4A9DB19C60D7649C9668CD0ADF667 -:10F1E000FCE27C15F47359F4DADA1C28B77A1E595C -:10F1F0008F793B93F4B5B1A5DA50590F552D7BC0EB -:10F20000529E50D1A3FAA1FE7736EC5F8F7C8A70B4 -:10F21000A0F1B6C173E0FCB5B0E4E95246E73706A9 -:10F220004ADC29A4B3AB70BD2622FCDCAEBF88AD9E -:10F230008FA29F3C417757217F40FD34A7CB93ABF2 -:10F24000BF1937A9A60D6F375A3DB9FAA4EA31653F -:10F2500094FEF0BB344A3F1D6CBD8667C936232F30 -:10F26000633E912F407E5A978BF365978F3FDFF473 -:10F2700072BFECD7DEDA8BBCF0BC48F069972F5E2A -:10F280008F71CE81C932C50B7A5DD00526E5B69661 -:10F29000FCBE14C6FDD6532AC3B8F35D1E6EDF4C08 -:10F2A0009C10E2FAF2DB5ED297174CF8597B0E9471 -:10F2B00027FE381643FDB799C5FC4827C92D3C6E7B -:10F2C000FAAFD5A7E63442F533A73D9C43713FC161 -:10F2D000DF293C6F04E5B51D574FC038C707CF7213 -:10F2E000B9F480A0B71E575F0BADE7B420D90D8CE1 -:10F2F00075935DB036AAD2BEBC9CCF9F6E97F615B3 -:10F30000ACE706C59B0478DC7F9FE125FFFB238FDC -:10F3100038A7D647F682DB97D0B2E17D7752267EBA -:10F320005FAFF953988ABF395845E76693152AE5C8 -:10F330005D6FAEE0F1B940E8B214DA09B71CF071C4 -:10F34000F910F452FE55AA62EFE1DA083E650DF9B4 -:10F350003D652CAC27BC6BB246795CF037FADE1CFD -:10F36000A13CEDCD4CAC4BB34C7E60C7B84F7E3367 -:10F3700015F7BBBFAEC5C4D921CA8324D346C67313 -:10F38000BC03070308CF57CD7347FDEB0250BF7D89 -:10F39000A916C37598A2D5D6637CB043ABF5225F9E -:10F3A0000526D77997901C1ACC53A6F36DED15DC82 -:10F3B0005EC5EFC897AC9D1DC2F32C85429605B281 -:10F3C000AB24B4733A1A286C8479BCB6BCCBF69CD7 -:10F3D0000B29AF5D599043707630C38BF5930D2A9E -:10F3E000E9A5C2A0378D765CA11937C494638B1F41 -:10F3F00091BBDC9EB79CDFACDACE758C4FD8CB7955 -:10F40000C22FC873E4377FEA31F755EC7872CE37F4 -:10F4100037725736C29B8B0795F5E1F3D91EA96A5F -:10F42000C479166A7E823BAAADAB41F9359EB5AC74 -:10F4300045BAFBCCF03AE09C52D1DE87EB3E455713 -:10F44000E91CC35436B00EFBDD2CE8BCABC4AE27C0 -:10F45000EFF228627FB7B6DA3B8DC7B99296F14BCF -:10F46000927E96B48C776A578EAD3CB1BBC056FF86 -:10F47000B41DA5B6EFA7A7CEB07D3F737795AD3C81 -:10F48000B97796ADFED47DB5B67265FA425BFDB331 -:10F490000E2FB495A7F57DC5567FC68B4B6DDFCF7C -:10F4A000EE5F66FB7ECE1BAB6DE573076EB4D537A2 -:10F4B000ED66A75E9CE2FD7CF6B207CF79D9E282C9 -:10F4C000767BDC694F7BFFB15E5F87722DEC26FA9D -:10F4D00056518F4379F50DDC9FF1CE89E92857CA43 -:10F4E000845D931534CE41395A13F6923E5083BC55 -:10F4F0009E1A9C4776C7293B401E9D8556201BFCC3 -:10F500001E40B9DC968C97B986E0F669DD7466A179 -:10F51000265C4F7175B3BDAA192C11C2F1746ECF60 -:10F5200080B788F57C3AB4B7CC63BF2CD311EF0118 -:10F53000F0BBEEB2F85D23F9594EBFEA64FDA85363 -:10F5400064E6C7678F146FC16745CBB3B5985E0794 -:10F55000FED5158887ADEE78730FF4BBB5D4CFF721 -:10F56000C1847FD555D24B7C3150A2927E61AA5E78 -:10F57000B1D012DFDAE4E57A25E0BD83FC3BB57457 -:10F58000E6611DF1BE56A5B8C36689C74792B00EA5 -:10F59000A8D776CD7AE39DEFC07B6FA9B7D00BF2E9 -:10F5A00028F698DBC0FDCFED02AFA55A652D585C5B -:10F5B000605F341EC4E7241DEC0C7896976F3B887F -:10F5C000CF9BBC3CBFEE8CD803B5284BBC73B8FDB9 -:10F5D000A74C71A7D6E1FA691C8E91E84CCDD9C130 -:10F5E000F7A9CAD4D791DED0DA3E210FD1810FE935 -:10F5F00040A227D18F2F1224BDE1C38D1C2CAB520A -:10F600002A00DF23658684791735E11DB4EFE64BC8 -:10F61000DBED55F03737215E230DF6F50E787711C7 -:10F620007CED128FBF7665EB4FD702FC5D79A53973 -:10F63000183BC1F844A345DE6C17FAF42B3ED9D42D -:10F64000FF246FE85CD7B4217B07E87F877C2AC260 -:10F65000D7CD506EF96EEA6648EF3E0D5613EDEDCC -:10F66000EF2689FE4D7BF73AC15B75A54DB4DFF5FA -:10F670005EA48AEC5B5FEBCF33E2CFD7AF30E3AC75 -:10F6800091F11A9EB493F43D2B75EB6857B4EA6E72 -:10F69000A327833CA8F2703B6623E67D203C22EF43 -:10F6A000A34BE0C3DC6F7BCFCC8712FBBCD76533A9 -:10F6B000DBBEDF757955E347B3C77DE0F7252CF056 -:10F6C0006E8471102F1D9F36D6C769FF8FF1736A44 -:10F6D0007FAFE8A1F3C0C27FA91276D22C0A9A01AB -:10F6E000DFB819F909E763FCE22CF4362FAA47BE0C -:10F6F00034E31DAF7973A85E2CC99416B2575CA68B -:10F70000DE924F4C259875B719A7249397EB35F8DF -:10F71000F7009EAB38B5CB7E5E6962B7BD7CDA0E72 -:10F720007BF9F494BD0C56F311B40B1A19C7CF9999 -:10F73000BBEDDF1BCD385F1D3F67E185914F70FD4D -:10F740006B3BD7CA84FE37E3A9C5BDE91A14AF45A0 -:10F750006BEC7AB540E8F90287FEAC0A29E4E7D7FA -:10F760001C8E1C42FBD18CBF3CEFD36DF96F661C25 -:10F77000C529CFFDAF6C63F085FCE58487C7171200 -:10F78000E0DFB41689B845317FBA14FD99C564A786 -:10F79000B59C86F2E9D7DEC4075E325AECE720DE7C -:10F7A000AD571F97743E4EC232CEF5E5C90BF8F443 -:10F7B00053945762C6314C3FFD1F01E322E4AFCDA5 -:10F7C000B1E75A1EC338D24B1E86FDCC559E3EDC97 -:10F7D00006E5D5C52AE5416A3396FFC88F7140FC1E -:10F7E0000EE59A127D3CD1FF932EF2D737087A3678 -:10F7F000CFE798718F5C9FD03F3EC9DC87F08B3C90 -:10F80000573FDAB967EE06D96CD3733C9E66C6CD16 -:10F8100026F7DABFF732295783F59BDA9492B95D60 -:10F8200065046B2C71F533C47A4D599CBE753194C7 -:10F83000EF63A92ABC2FA252D045EC90FD3CD838EA -:10F8400026D1B981714794580AEA4F79C4FEBDC2E6 -:10F85000715EEC0CE7F931479C37A4B07796C0781D -:10F860005BF41609E5E796C560C343B9C227F28782 -:10F8700027B149487F7395602C8DF8FD83427AC388 -:10F88000F3EA692F2C417DFE2CCF4FD14ED5B7D551 -:10F890004159FB8D42FA490BB0CACAE0505CF87B73 -:10F8A0002762ACDD351467DA03EB5A3611FD6B2F96 -:10F8B00043BDF273585F2CF7823F8EE507C11FC727 -:10F8C000E75EF0C7F1FD2FC01FC7F23EF0C7F1F9A8 -:10F8D0002BF0C7F1FD23E08F63F9DA404D8D2FCF78 -:10F8E0001EA7B2C6ED86E254FD9219A74251F2BEA0 -:10F8F0009BD3FF60BC2AC1E35563F76398FD503C7E -:10F9000070583F222EF8F60DFF792F9E9F5E316DC5 -:10F910005D179E83F5BACCB818CF7F30F39A4DFEB1 -:10F920005BB1F75ADA0F76E71F69C1F5D85B1DA402 -:10F930003B86DCAE8486F2D1E97F997E97D3FE3593 -:10F940009F4E7DE4473BE02CB493BA29EEB3C9C582 -:10F95000CAE95CACE48F215F38E390261F3FEB2BB4 -:10F96000CD789E69303F56C4673C2CE5C578995BDD -:10F9700012F314F99B24C2A08BCDC8CF967CE36010 -:10F98000459AE21CC1A041F697047619D9695A221A -:10F990008A71A8CE11F26177093E5D9BEFA67B24A8 -:10F9A0003AF3F9FE7F5D512C8AEDD7E74F8F5AF37A -:10F9B00063CDFCDD43A1E9DE7E4B7FAB43A5A3EA2B -:10F9C0002905F4AA3E8A5E553C3C7F7DFDC1B3BD4E -:10F9D0009897BC29B8B40FEDAB4DD1089D5F3F900F -:10F9E0003F9DEC8FC1FAD19994BFAC04B9DDAA4414 -:10F9F000BD64B7AA38FF8AA1FA66BD1B857C06F6EE -:10FA0000A3F85C20D84BF53C6A9CE21F9E08A3FD3E -:10FA10002A8F97E70B04C1BFF6DAE2A6421FFBB8B4 -:10FA20007CDBA427E2D86E5354D5511C6D2AAF223B -:10FA30003CAF17785E9F67EAFD18D91B0F0A39683B -:10FA4000F6B35EF8EBEB9BDD6477C55BB38DBA5C18 -:10FA5000CAC7FC09F2DFA6E05D5ECC6F77E7578F7F -:10FA6000DAEFA363F6FB6A6DDD59D4EF83187F7676 -:10FA700087966AD8AF6B84BCFBA7447F9FD7BE0430 -:10FA8000CC69B4DFC54C7D9B8A5AF7899D4F3FDA1C -:10FA900089670D6FB742EF9F8779BF2A4BD6FB95D9 -:10FAA000E1E71656EEE3F7506D55FBC8DED9FAA92B -:10FAB00094F1FC43B6DFD43F837EB8CD5E2914FCBD -:10FAC0005428BEEB68AF94A05F69B72FCE3A6C2F75 -:10FAD0004FEBB39767BCE8B4578C3FA0BDB248C8A2 -:10FAE000BB3E90CF3C6962404539104FA66A10EE8C -:10FAF00046D6BB16F7295D22CEBC48E8AB8BCDFDC0 -:10FB0000477F36C15FD8ECB7F989E67D1A45A2FF79 -:10FB1000E2BA43D7B6A3708D9BF68F4EFE65F1FC1B -:10FB2000076B484C3AECA046C37E1EF562879DE306 -:10FB3000B4876AD41ECAB72C70C41FCC7D4A9C27D8 -:10FB40009ECB758EFF59C735FBDB097A0BED15F39C -:10FB50009E02BAC70BDA17AB692916A4FC2DCAF3AB -:10FB60002B5CC38C9E0C743CD3CFE5DA30BC25CF24 -:10FB700023BC9D2FDE1504F93D2805754A4A2FE167 -:10FB8000F95F284F162E87F990BD7C82F6A1CDFA39 -:10FB900039D9BD942FB6B341E2FE6392911D62AE96 -:10FBA000F3CE203F3FD378AE9492B17D4B298D4F59 -:10FBB00070950EAD2FE0E928C713CF2FBBA4DE7ED2 -:10FBC000CEA7D1616F98F470B1E3FDCB3E7E4EDAE3 -:10FBD000E483B7CF7E71D22900C70A29591F504E3E -:10FBE0005E4F5AF8C37502F910FF3E8EA642FC71B3 -:10FBF000D0FB9046F901D9FD773020C9063F4BD69E -:10FC0000CD06BDE81F385382F225FEC91D5DE7E22F -:10FC100071C5817F45A3CCE3A99A5B5F3C54F6FB99 -:10FC2000E7503922C601D722C9D7DB726F01C0FB6A -:10FC300003911FB0D960DB14CCAD94B56DB192A126 -:10FC40007639D84E1AA55D9C6D5333B40B9AED00EE -:10FC50005D9DE63D1FA5F8E4DF65018F757C15F11C -:10FC6000A6E9413AC7334FD530EFE18BC2316EACD4 -:10FC70007927D836D7A9C3DB01D86B4DF8E5CCF08E -:10FC8000A7F0BB757CD728F0FFB3F131567F6EF13A -:10FC9000FD33C307D5D78D1B79BE08978BEECBD02C -:10FCA00083B2A59F5B0E7C4CF16BF57246E77454F2 -:10FCB00097A1C580CE2BB4DBC80F57B3EB34B40388 -:10FCC000364219ED808DBDDD14A7AE28BBB50B897A -:10FCD000BE22ED67280F26332DFB3EE877B2A662E1 -:10FCE000260E53CF3D2463DC9B7D89D13991AC0333 -:10FCF0007E7EAF45C9AC1FA37F949DEDA5385020F3 -:10FD00007BFA8FB9B1CBE3C126FC819A23B51827C2 -:10FD1000571B590C59519552AC0699EC7446FB107F -:10FD20007E63EFF578DE12141FE927BAEB01F5AA1E -:10FD3000888B8FE724C3BADC5A23FA09C9A7548AEF -:10FD4000BF8F47D31488B2A222671BC25391800E83 -:10FD500024849FC7B52627E4581AFAAF7A87B76379 -:10FD6000BFE5E703C097687A3838845753AE8C17DD -:10FD7000F1F2E8627B3C990DC09CA17DD56F17DE46 -:10FD800083F18471C3E437F7AFCD7B74B2DE61F1E8 -:10FD900087695FD3AE37FCE2BE0ABFE31E8492A040 -:10FDA000CB768FC130BFE1BB71D2031E16F3BAC947 -:10FDB000BE584C7683E98FECC48A18FF2F66FC5E30 -:10FDC0002B67FBE9BC3D8B72FFC4E30733AF0ABE70 -:10FDD0002FF31BA46F3D50063C4A6EE6CD87F70516 -:10FDE000328F8BAC95988AE5A1F1D2B44FBF418A8E -:10FDF00075C5A421FF77BD16A3FC01B626C7662FE3 -:10FE00009B79A8ABAF29199F03CFACA1F3401AD2BD -:10FE1000E3EABC32B29FC3B9FDFF07E5EBFB9B36BB -:10FE2000CFF5A2FCC4FC8559F05FA0B32309F2D63C -:10FE3000F35121D32D7699476DA13898E7A3536CE0 -:10FE4000EFD36DF6F3834650AEC371C607747E2EB2 -:10FE50008369EDD8AE86D9CF097A3ECAB7D9E943CE -:10FE6000FD17D9DEA7C19EB1DE4F3172FF01A69703 -:10FE70005BFB3F7584FE2739FAD732F63FD46FAE6D -:10FE8000ADDF0E95C74793113FADBBD31E981AA89F -:10FE90002D0A4C1B257E1FE0F1C70DD1168ADFD736 -:10FEA000326078A093F33E3DAAF0F36C8CEC3656AA -:10FEB000648FDFD70AFA958122907ECF53EDF782C7 -:10FEC000CD61CE7BC2ECF6D073C82830AE1CAAEE52 -:10FED000A338FEC7411DFDAF91ECE5BE3646F1E308 -:10FEE0003981FEEB709FFA82CD77BA3A668AFCD7E9 -:10FEF00002C62EDDFCC05CB4EFFBC479BD8E884C1D -:10FF00007889D78EA7F337663F71379B88F2302EFA -:10FF1000F3FC04FA03E3F7E515DCB52903FE9CE7DF -:10FF20003B1B0D295E66A19B3E19F06A1DEFFCC2CA -:10FF30001EC5328FB8874DA3F1849D3B38DEB8CF04 -:10FF400037DEB322EE648ED738CF3EBF46B746F3D6 -:10FF50006B14FC6B8EF72CCE2F037EC71C4FE67400 -:10FF60003338DE05F6F9357A349A5FA3B8E777704F -:10FF7000BC719F6FBC0DAE9604DA6DDB24CEFFDD45 -:10FF8000815F75E0BABED7B03A4AFA40D8C5176368 -:10FF900003A877B1CAC75B50E44DADB58CB713E485 -:10FFA0008021F2DC0D0FE66F68544EB545E97917F4 -:10FFB000D8D906E56F94D3F77BDB6254DEDD369348 -:10FFC0009E663FE533F9BD33A7CF9632DADB870370 -:10FFD000DCCFDA96AF5D7E15EAA51A3F3F0F39F305 -:10FFE0001C6658EC5F30880FFA70FFE5325689BA0C -:10FFF0006DD20E0E77A46E5C0AD7CF5F79A8AF0DD5 -:020000021000EC -:10000000CA1E974B477D0ABC10CFE4A73E16E07E80 -:10001000B8C7CDE53D9BC5EF315C20F40A531A24E7 -:1000200017E2E3E26CDAEF5FB8C8086980B745927F -:10003000F48732A1A7F0DCCAA562A99C767E0435BC -:1000400006F41B319414DE4F7469D1E126D4CBF150 -:10005000D025E41FC4A1610EF473A9D09335AF7A03 -:1000600018E63BB0B96E8263D122BB3DBFCD97D6B7 -:10007000D03ED9561961B83E0B1BECDF3D6ECE87E2 -:1000800071C7BD050BC6B8C780EED2CA9047EA8CCF -:100090004F3E1AB0C7218FB38A5BEAF0635164D434 -:1000A0007B0CD6609BBC21FD369C8E393CAFFB9906 -:1000B000F0DBF6513CCC84AF404D4928AF0B9BF7A9 -:1000C000D9F29A00B1640C9B7178A6DC57897E88BE -:1000D000733E3BA5FBF247BBB7A480A9AFF7978B54 -:1000E0007B3DA5E1F37E2520F26F07E73DFB9932CA -:1000F00096897F78DC75C16125B6561FC28B8987CA -:10010000FF693EEA12787FE6FCF7ABB9FF5664BBA5 -:100110003FD3BC17F892C1B2CA540B3D5FBCCC4D63 -:10012000F60C33062A90EE8E9C1BE0F7B899F64B3E -:10013000FA2519ED972FDEBF516CCBDB14FD8EB481 -:100140005ECE3C42CB39D0A13C77CC2F91F83E56C5 -:1001500001E6B985F9FBA3763BD396E7B6FEC04F1F -:10016000258CF3DD81F978967DEB42F0E7516E1630 -:100170002DB7E7D539E132F3AA06CFD1CE5EA4DDA3 -:10018000A7D3BD89DD78114DD78E649C59F223CD5C -:10019000F381A63FED3C17A804F9FD795171DEC249 -:1001A000190FBE5E4E6A2512E6A3A6BC35F09C92DE -:1001B00093A8C2A3EAD72BC97A7CAF8C9FD58C7841 -:1001C00058DCFAED18C6EFB4DCCC71E9C5427F9F6C -:1001D0001BE4F18E575CE9628C632FCDA93D373863 -:1001E0002D43FDD6EF527F7346B88FFEB220A7BFD6 -:1001F0003B843E777EBF588CF3E51532DD6FE163BB -:10020000A1945482FBC6DD33E93CDECA9DB14CE7C4 -:10021000DE9E0A2716042D71075F193F7FCD58EF28 -:10022000D988AF8D7FBBB3F77E4065CEDF82244790 -:100230007314DEAFA5FD6599DAEFFFF8793AB7BC24 -:100240001FCFA9A09DCCEE9887FEDCD6C1324B4AC9 -:10025000181FCC16E5642BFF3E58AE9A578365A451 -:100260004120B29782733B915EB64A4C10E33C5EEC -:10027000DFC5EBFF427C9F73E15B3FBE05E5FD748C -:1002800037F9815B853D62C2F77290E7CDBC3C06D1 -:100290003E5BC5F720E233F299F0D99A091F2FE7A8 -:1002A0001837E0BAFB30930240F0FDCDBB06F3886F -:1002B0007FD0C66257C11CEE88EDFDE92D8CDA2790 -:1002C000ADF461B6BF28C7581B24788ED2FC4265B6 -:1002D00041746FD8C6198CFAC900C7C64CFD98EB9B -:1002E0007A308BCBB10FD1769E86EBCAED3FC5D36A -:1002F00017C5FD7FADFA7BD76920473A4BBA9B32D1 -:10030000D1F7F7437C9F3A7B8478F5CF053DBEA4B7 -:10031000C57F8070B46BB7D2FDAA6E89DB0D1B67F9 -:10032000F633C9D2EEB7218E6F80BB07EBBBCFE6A9 -:10033000F79E8600EF986016AAE6F06FD48F30CC57 -:10034000EB0E458F505E68A8BA9FF89D8E2A1470F8 -:10035000BA427FCD2BECB39F07BF320FEFDBC85102 -:100360004CBA7BAB13E946192A131DF5E4F0F6BF2E -:100370000FBDD5990491BB0BEC17BC872359C0F373 -:10038000469CF3FBA5807747D8D88BEB320C9F9E19 -:10039000FE1FDF02EDB74EE4E76DE6C87D4D572244 -:1003A0005D5E1824FB0BDE3759EFBF795DE0EBF59E -:1003B00020B79FB67EECA5EFCEF518895E7F27DAD1 -:1003C0007F0E7AFD5D263A017A7D06E765A1D7F7B3 -:1003D00059667A7D7E047A7D21135E9C6585193B82 -:1003E000707F56FD64DE6EEC4FBD68F68EFBE1A9B2 -:1003F0007C725392563326D9CE979AE3544A893F5A -:10040000072DF2DDBC9FFB9B41DEFFB07E674CDF1A -:100410008172EC24FA1DC0F938FBDD1FE4F0CEB97F -:100420003098C8746FD1CE10CF1BBF5BCC6B24BE8D -:10043000792AC4FDD991F8E681D020DFB050DED80A -:100440007CF3AAA80FEBE0C5FA63F3CD6DF4F49545 -:1004500071BEA163C8B386F30D4BBE487CD259C2AE -:10046000F9227FEB9F3B31CE31C847C90FEC7C941A -:10047000FCC0C6477FD9FA01D577B60F8F704F956C -:100480003EC8FFF109380FE34CAD9D9FB3E927BD8E -:10049000DDC3060E7828CF96E7B5FA9349839B0D06 -:1004A0007D0CEF3D2C1778D8853E18FA39D3459C42 -:1004B00049ED630B43C3F939549DAEB6DE23F06BAF -:1004C00031FE47A1F8D4D0341CAFFF74B4BF465AF4 -:1004D000A76A517F5BB6511DCA40D763E9A1CB43E0 -:1004E000FCBCEBE502EE9CBF795BD0FE74F2FB9C9A -:1004F00095BFFAEBBDA3F4739968BF20F4B9F97FF7 -:10050000412833FF5F1CB2F37F35DEBF9981FF2F97 -:10051000CBD41EF8FFCBA10CFCFF05F8FDCA50069A -:100520007E9F1DE2FD8F85EF7B05BEEFFD82F86E9D -:1005300017ED6F0A7D6EFBE0A65066FBE03BA169FC -:100540002785EFF611F0DD1122781E24F8437A900A -:10055000E2D85D33D85EA934231C5BADFD7875DE2F -:100560000FE0FD7D09E87ECE275DB14CF7CE40BBA4 -:10057000DBACF09BEDAA439A99BC7D2DFAE7775C42 -:1005800014A4783FE8C71DFF643AB83B94413ECFBE -:1005900091B91CFA20F820D9815FA0FFDE4CFD2F15 -:1005A000137436965DF098A00F98F7BF85A60D9747 -:1005B0007F3DE27752768413FB4384AFFEF928AF88 -:1005C00076DD9823613CAAC8484BE827EC15FA660B -:1005D0007248E7E71944BB5D6A5AC27C965D2D9A62 -:1005E00084E78D2CFD1D0E4D1BB93F271C00DF6FCE -:1005F0004224EF8CA7B15DF5901DF899ECA44BB2A5 -:100600008D2321D23FF1E7496E9F6697DBE63CE4FC -:100610007837E5BDF86666FE1D97BD41D594FF7F2E -:10062000B2CAFF17429AF9BB52D4DF67D53F00DF49 -:100630001B02BE3733C1E7C4CB58708E177A1EFA3F -:100640007B3F939E72F667FAADE63AB9512759E2BD -:100650003A5278D0EE656194DF1D329D435A20E412 -:10066000C98299D9C26ED7FCD8FF1D224E7EC7F22F -:100670005B6B70BFBBE726AD125150D0CCF59EBE70 -:10068000FC148A7F0644BF4EF807DBBB7B4FC77B59 -:10069000C761DC2C1CF7BCD92C8D7E6316DA0D14D7 -:1006A0008FD0E877BC723CDD518C9F6E94BA9B96DC -:1006B000A25E9D1FE4E74AA28BC6B8BF6D9D8D6EFA -:1006C00059B47A8CFA6BA9BE16E8A6FB2F4EBABEB7 -:1006D000A7BB29537E492C2C9B76D199A3E2351ACE -:1006E000A1B89689DFE1E3F0F5AB89B74888EF5010 -:1006F000B5A4E1D1AB10D009DA4B72591FE5337DB7 -:10070000A99AD30B03BF64F4FB333ACDF59E13CE05 -:10071000FBE27099F5461E4FD4739C57C07D2F8A1B -:10072000CF06B91CA38A507EF7706EC6B8BFF9DC3D -:10073000D0A615A92E6BFF29BE3F33983F1D8BA273 -:10074000BDD5CA383DB2A897EC30BAA7DDB29E4BF2 -:10075000C3DC7FFC4156FCAB61E2EF18DD4BC834D3 -:10076000EDA4E603EDAEA2762AB40B9D7CBB919F6F -:10077000E6EFD7C5F4B8E51E34935FC727920CEFB8 -:1007800099F157304D82F58F84CC7D424E07B705E5 -:10079000CD729236C9E365DD3C2F5F37E984CB1516 -:1007A0002DD06BC8958C6DBF79FE05D1D3A1BFB29A -:1007B0004414AFD487F213788F5A8EC2CBC0684FDF -:1007C0001C227DA19D21C5404FB5CF7DE27031E354 -:1007D00047A5E8F7D5E63E81F9843D66192FA428A0 -:1007E00087B27FB06C78A3502E1D2C27B1BC4BE88C -:1007F000C9ED37CF7DA23D4872EC662B7FD4083A15 -:10080000FC67D35F8FDEAEE13983645425BB6AA3F6 -:10081000831E7E157613FEA76A8914F2C5829B0695 -:10082000543CBAE22D8984901F2644DF4FE2FD79C3 -:1008300013668B34D5327E4F434F740DF1650FAE86 -:100840000BE36909189F1C5A9F54E6F5294FD1FA0A -:10085000F875FE5DC632F9DB3CFE1628E7FCAC7984 -:10086000787CEF2141AF07C33C7E7450C8D7AC6899 -:100870003BF953DE7A99E2C759F5B24D6FD02FE0BC -:10088000517DD5466F2FE724F6872D7A01962F5E8E -:100890000EF3F09F1EC9C1FD979A72750DFADB3FEA -:1008A00012F61FACD30F495E5446FC0992DBF1C728 -:1008B00033AE9BC0CB58EBF67C5B2256E71A79DD52 -:1008C0002EBB9CE7D33BDFBF28E4EAB1A63F7F0FF6 -:1008D000D965857780EEF3EE2A5B4B715833EEEAEB -:1008E000D95B932ED487F201D705C2B3E95C8A6342 -:1008F000DCE73FFDBE46E7443EF664DC4FFA87C0C6 -:10090000F391B6266A070B4CBFBF72054E85E7B15F -:10091000D9CEF199E711BEC638312C8A2FF912CA07 -:10092000A1A54D0ADDDB7005B3E7537CCDCCFB6A96 -:1009300035F3E378DE578265CF43365C9274FC7EF4 -:10094000048BCDC373F4C37E5742EC6F7DDD9137CA -:10095000F1E5A625B13A51EF3DFA7F8AF0B748E7B5 -:10096000F277518CDFDF7369FCF2589D653FFA85A1 -:10097000BF2B19F3262FCA32F1118FD54D1C8E8F44 -:10098000A571C9ADE963E3E564F1B044AD9C97A7F7 -:100990000FC78373FE80B1AD88E7AF039ED1EE1C15 -:1009A000091F508FD6E385CB15FA3D99794A830B01 -:1009B000F741AE6C94688F09F01B1679710D732D99 -:1009C000F03AF1E8C4D7958F323A3770E5ED218AD5 -:1009D000B73D67E2277D1EED5F98FB2796791EE500 -:1009E000F95B1ACD73E1CCCAC7F1DE84443B485BA6 -:1009F0003E5FDB3EE05216CFC2730B30EFA323AC59 -:100A0000BB6D3FD0099F137E9FD02BCE7D31A6A614 -:100A10002B500F1A59625F700A8B89FDB12C4AC79F -:100A20002DCB2C6F9DF7CD997476456BE3E0B8D84C -:100A3000BFC41283650DCF6B3DA96CBD14FEBE3AD9 -:100A4000CA7FD7307E796E077E5BC0CCDF1B3268F1 -:100A5000BFE90A81BF46F0F8F0B7D0CE03E184FBCE -:100A60007A0B0C9F1EB4CCF3DD6EA95E9CA3CA5A10 -:100A70003419DB250F285386C3BB3ACA7FBF10E861 -:100A8000F07D2B1DFA26F27B659D7831F175659618 -:100A9000D8379CC2A67C16BCBC848A731AEDD7904A -:100AA0009D3B2079E93CBCB98F037F4DBA4174B6B8 -:100AB0006695083B80CFDBBCBF8BB116B2EF178BBE -:100AC000F358AFB858D30341BEAF5365915B37E4D9 -:100AD000D4B46659EC6E735FC7BC2FCAA4E7AF7974 -:100AE000836985D3A1ED3EA8A13CA604E53129592F -:100AF000CB75C447177E3A9BEC9EF5D8BF12E0FB3E -:100B000055BE271FEABA541F5ABF4D573DDC3D0D55 -:100B1000CAFEAFFF3E499DEA3984B79058B71AB173 -:100B20006E267CFE0AFEDEB27E3C7E562EE26762B8 -:100B30001D47D213E63A9AEB867614D2AFAF5CFD2E -:100B400024D3EFF0B143D503C8A789A84A39740963 -:100B5000E9B50EBA678BE9BB70FFFD8A5697EDF7D2 -:100B60009712784E1FEB6FF409BF2446ED97E6F31A -:100B7000F6AC9CDB8D83749F84F6963C20E60D8F4B -:100B8000C375EB87B6982706FD8D437DCFBA2CE35E -:100B9000940E1F77C4FE1CED94C17D93582C669172 -:100BA000D70F65713DF96EB4BA57CE107F319F4BA8 -:100BB000BDB945AA253FEC68BEB729D3BDA4667F61 -:100BC00083F7C60DDA896F3F71A868C84EDCEC7AEE -:100BD000C36E27B237BE909DF872D61B4FB4033C4C -:100BE0001FFED143FAEADD7A3FAD436EEBF9ECBF6D -:100BF000F0BCAD8ABFED47F63DDD7BE36D2DA4F97A -:100C0000482A600E7F1F4C8F4988EFD7F0925E8C88 -:100C1000DFE92C1D02E072D59884F8BA55F8A3409C -:100C200067A75BEF677D2D8BDB5BE6381E2F4BE202 -:100C30003963B35FA083B59457DAC0488F98FBB08F -:100C4000263F9BFD0C64D9FDE093E0DF814CFCFB6B -:100C5000B4DCF2A7EFA0FDFA9442F9A05F8DDE406C -:100C6000EF2F6BBD929E97B75E43CF4FC478DF9254 -:100C7000129F64C17AF535FDFEABD703BDAEDAEB4A -:100C8000A173652BBEF5D79B913FBDADB0EED8EEFD -:100C9000EB57DE3E0DBEBB27CA64BF7615F37C0E54 -:100CA000F75A89C7FB75773DC650FE3F378B9AA828 -:100CB00000800000000000001F8B08000000000002 -:100CC000000BE57D097C54D5B9F8B973EF2C496662 -:100CD00026933D210B37842548C049202128D60979 -:100CE0005B632510C40525C0844008109280568798 -:100CF0004A654200A3468D75C3A5BC8162ABADFABF -:100D00008252A56DA4137101A518ABB5B820417826 -:100D10004ADD12411EA3D5FACEF79D73927B6F6612 -:100D200042687DBF7FFFBF177FEDC7B9E7DCB37CAB -:100D3000FBF9CE77EEAC7096E4BA0A09F90EFE2EF6 -:100D4000266485731A9649AAD3448A085963A3FF77 -:100D500056093973F8E6D4C5898444DBED6EFA840C -:100D6000581AB3EF34D132D92F9347289063C8A2D1 -:100D7000F23C0AAD0C0E712984240134218C074801 -:100D8000FBB585244212A09DDBDD60A765C54F5CE5 -:100D900000430A3EB74852795B5EDF7C0414FDD9FC -:100DA000423221E3613CE3FB167C7E8B6A2985F7A6 -:100DB000E504360FF17E0E7F3F87CFC7168A61F3B9 -:100DC0004830F6E364CF65D2D066EF3F8FF5B1537C -:100DD00047B992004F9E5C80847499CB1D842CB4DB -:100DE000BF72481A47A1CD1E9429243EF3A75DB9CE -:100DF00004FFBE1B06FF5FE1FA700C2112E992BEF0 -:100E0000A343CFFA460A0EA5F88B2A91031BB229F9 -:100E1000945C651326D066256637E0B37378A263C9 -:100E20009866FC0B5C12E2EF75C5E58079964F97EA -:100E3000CB0379D87DD2E5D0CFF4AAA25BD97036A6 -:100E4000924CC822F66FF2BABAA37918ADF7FBCD6F -:100E5000EE11948E8B6CFE00CC6F1151FC5D366CE4 -:100E6000227D2721549522FE1E9DEFA269B227CA3A -:100E7000A96B47BEA3F3241BC90BC369FF0B253E17 -:100E8000809F96E97BEFF3E29169A7AE80657411CC -:100E90009765186DBFB0AB722619875576E0A7A588 -:100EA000BCDD229FF9786FBFF47F957E7D797171EB -:100EB000FE4B940C142F81D209C067A34DC867550F -:100EC000CDFA764BDFBBE46FC409FD2AC77BF10D79 -:100ED000F32477313A4F6F72A9144FE7BB542CCFEC -:100EE0009A766C1AA1E5D9845C01FDCE9E26BB8260 -:100EF000B4758BCF443C74E2073D7240A26B3B98C3 -:100F0000DBB5FF62C05BB1597D04D69A4B6E9F9BE7 -:100F100008F5E35D80E772789686ED098176A9B6DB -:100F2000C008FAACD373CC5EA5E1BB83C5C7467BD2 -:100F300029BDB69A484D387E22A411E9FAC24FA2C3 -:100F4000B19F23F748012B9DFF74F99B3F4DA4F3FC -:100F5000A9FAA9D96D55715926A0EB4C3793474290 -:100F60003CF6E9149F0B092B1F23E545413A7E55BA -:100F7000FEE1122BEDA76A9384722AF04FF1FD81F6 -:100F8000166FDE86F2D8A08A78D73DA79D59809F3C -:100F9000299E3F8880E70FB478F6BDF7F6D817345E -:100FA000ED5A5C8E44E07352400ABEA3A8394D2628 -:100FB000C78E27FDD72DE099F587C6BE3082907B7E -:100FC00088E76E2E4F4AF9584A278578C2E9815240 -:100FD000279383E9F2A7489F93C5B20AF83AE8FB42 -:100FE000D84E398C1CFC462E053C130FED6C52DF9D -:100FF0007B8FB92C48FFAD16E2013C6F1D620B34AC -:10100000D2AE3A7E725E4A17D247BD7F32D0F1151A -:101010003379448D3C5F874F26C3296396F9248436 -:10102000827E437D514419DFD76E28093FFFDF835D -:101030001CD37924AD2326958E1BE7279E4018BE2E -:1010400010ED56D97A662804DB07E3E8FCEA54532E -:1010500040A2EBCD97183FDBCC0D9E74DA54699F0C -:10106000E34F27300F19E7A1D2F929747ED9BE18B2 -:101070002C0FF32520CCF1C5211CEE4BC7FA11BE75 -:101080001C84237DD9F87C946F0C96737DE3118EBC -:10109000F6E5233CCF7721C231BEA9D82ECF5782A7 -:1010A00070ACEF527C3ECE3717E1F9BE3908DDBE99 -:1010B000F9589FEFAB4258E0ABC4E7E37D2BB13C5E -:1010C000C1772D960B7DAB1116F96E4438D1D784BC -:1010D000B0D8D788ED26F96EC3F205BEBB115EE825 -:1010E000BB0BE164DF43580F0A08F010CDE5F13681 -:1010F00075898B4A0A70B80A7C1C49EEBEE2F6A8D4 -:10110000D2E5390AF64EB4B3988857DB5EB43BCDCE -:10111000611CD0354C7F3D5C3F7FEEFEE0BE51A4AC -:101120008F6ECDA98DE544EEA397755749309DFE8E -:10113000B36EF71C027A81E426EAF8B4BF7E60EB56 -:10114000EBE2FA6BABD2E991817F1B88DB4F1F95F5 -:101150004D785D827EB6A94A69200CBF8D8E33E33F -:101160007BE7BBBC248ECE2F26FBF80BA04F66FB83 -:101170005D7F9A02FC9297F8CA14DADFD08D2618A8 -:1011800081AA1257C714AA77D46904F5E2362A72E5 -:10119000B0DE6DD17A7B9A1DC7EC28216DFB86A14C -:1011A0003C0D2F60F6A7EB12902FCB4F86915BB3CF -:1011B00041DE829242FBF3AF21E4116133A0FDE6F0 -:1011C000C5BF84FABEFE2C4C8E9AC9F3363A91EC18 -:1011D00056754A1485395B3CCF47D1574604BC53FA -:1011E000A26979D4A3FEE7018E6E0B4C89A170CC65 -:1011F000EEE0F3D49C92B1C1AE29765A3E7F1FD95E -:101200000B68CDEF54A73A6879FC21CF5ECA06A4DB -:10121000B0CB3BD5A9C27C024D4E3A9FADEF1377C0 -:10122000232D177FDA2AC7120DFD2DC4BB53431798 -:10123000C784CE6909F49F19D7B9F265785FE98A46 -:101240008ACBEB4F9F6DB06E5827B5238FD0756555 -:101250007882924BC327657192A0437E1CD8A175FA -:101260003D0AAC73DBC67807D22FDA550243F64C41 -:1012700027AEED2AF0B18278B26C1A86F22EF88E83 -:10128000E277F41C87166F92D06B356D7991F15B24 -:10129000F66F86DFF7383F47C2AF0D7865D2D9E5E4 -:1012A00078615CAF1C5F03788DD4AE298EC9A7111D -:1012B000CFDB4C641FB555745CCAA74CAE889F3613 -:1012C000BD89F3F7D9F0EAFB37C3EB157103E3955A -:1012D000A889A82729BF8E263991F50DF417CE7E4F -:1012E000DDCEF94DA3E72CE02F36BBA89ECB89AC11 -:1012F000E7AE8E3B8BFEE27AC6C2F5B818EF413EF0 -:10130000DE2BCEF22DA0BFEC9B4C7E90B312E240C0 -:10131000B920A9899C4F5CD1C02733655709E81BC8 -:10132000328AA01F1D9317F0C33E65A85F2D90A1C0 -:10133000192865C0E390DCC0ADB4EB6CEA67289473 -:10134000FEB4AB20409BEA322DA6EB8E15F2E6AA46 -:101350004CD5CA9BB0F77DF228F8227EDBADD98C44 -:101360005FE750FFE56DCE6F7DFD48D86EF3DA2163 -:10137000DB6ED5E8C16DA9A95816ED23F1EF19C1AF -:10138000BF1B37102FC8C7E4F07EC31B7132E7DBE9 -:101390001E0FF0B9FF07C405FE4CDCC60F503FC559 -:1013A00051FD24A17E62E367F8A27FE9A7E53FC76C -:1013B00025737DEE8ABED2F1FF8E9F7F45110BF320 -:1013C000183AD9D521D3FAA1D40EA920A793E9DCE4 -:1013D0002700BE2C487795303AAA934900FC5E8AD4 -:1013E000B7A009F4AFC911003B63B1B47A409E893C -:1013F000250ED7FF8AD37B346E00B970C5A8F9409B -:10140000D493715F95DA29FF6DCE764543B99B96EB -:101410005B52E9B8F15D84979BED283FF46F085269 -:101420003148F706601F45D96383F6C37ACB7E281F -:101430006F059FE402DAFF5D67F66DA488991BE7EC -:10144000E989637C7D12F8DA338A6E5073FAF8F911 -:101450006CFE8090CF3E7972E50B79AACC437DF883 -:101460000DF42FFA8BE4DF3CC3F5A7237E60FF4623 -:10147000F0FD39FB377CBE7F07F92F8C2CFF51FB29 -:10148000DFD8B28396D7A4CAEA71EADF3986BCD521 -:10149000A9D0B28DFA9BC768D964EB54A05D1995A9 -:1014A000503BC5B7873A79B0FFB04D6065F883FD12 -:1014B000C7C956A994E96B35F6F2B103E13180F35F -:1014C00059936AC1F1A2460C8F05B97272BE228A85 -:1014D00014003BEE2C76298BB1BF2E7219EDEF3C38 -:1014E0008E2721D7A0B79ECA03BD14AFC07EDD6A88 -:1014F000237E477C5FFF508E2DE8D34F84EFE3AE11 -:10150000E57BA6D60DEED8E120A707591CA5F52648 -:101510002697651924B001F48487A82EDA3E8A88BC -:101520003F2AB8B46CE6A5995F4BC443E77FE06BF4 -:1015300019A1349C041D74BF57E69682B00FB4986D -:101540006C01B0A525436CC40265A7296005F9F8B4 -:1015500040C2755A0A6202A0FCA60D298EEDA2EBCC -:10156000387560AFDD1B86FE57792BDDD3C647C6C5 -:10157000636FBB052FBA008F0FA91B5DE047FA53BD -:10158000158C3BDC024D357AFDEA786637A93F348D -:10159000379EC2594B7A365A80DED989E80F91E1DD -:1015A000F1C8B769A9BB6E29019355CBFCD321249F -:1015B000D0A8F5AB047FBD1BEF5D104FE143DC8E7F -:1015C00050B1EC1C09F1AAD189F1E09796D40F69CA -:1015D000077FF781F5C4BDC48CFAA01CDA7B12DA50 -:1015E000F2817F1F72EF7AEC4EC0A795EE8B418F90 -:1015F0008F3F6C5729BD2A0AF726C17AFE6498BF2F -:101600008015BE9B102FC67DF0AA78BA0F068538CC -:101610008E8C837DF029F7DCD820F2564258F9AE43 -:10162000F0DD88FD88FDF07BE660A62BAC1CEAF1BE -:101630002DC6AF90D8BE969825A6FFB81DA5FA6511 -:101640003DE097BE8676D36395B683BD39E51EEF40 -:1016500006BB1D49DF88F9503C8E287784A997483E -:1016600079383DF1403CB3D71566BA5FA0F5D2EAB0 -:10167000C206985785C32E01DF89769BE2993D13F8 -:10168000FC2CE25572EC3785407F880F865BFF2289 -:10169000A27CA98D476D02594B62F87287F15722DF -:1016A000E1EB90B9B50CE67568A94C1A693FA7BC87 -:1016B00013534898F7057C07F886D2A53E818DD74D -:1016C0004BCFE1E1F177687D8D7B9AB98F9EFDEA82 -:1016D0002BA3E681FD9E0778D48CFB0AC7DF3181FE -:1016E0001FAB5775D17ACBE27B5D642CE8A92F0B39 -:1016F000FD0E888BF5FCB611E8FD5307C62BE655A9 -:101700009E2E6C1CABC167314123B968EF032E9547 -:101710003E9F37626392DF1E198FC7381E6F8307A3 -:1017200093301EF322F2CD20E331242F1EF98DECED -:101730008D7207211EF917D90D7E038CEB45FDC96B -:10174000E2C9D7B9D8BCA20C7EDE3C5F9D4EBFC4B7 -:1017500084241248D09495368CCFC684147C6E9421 -:10176000B75F19E44DE03F123D05FE8DCF9FE7784E -:101770003F54B95C85B8A1253ABC1F9C96C0E824AB -:10178000CA6FADF7EAC6FBEBB7B26EBF2CE07F7352 -:10179000FA9EF24E4A8178D53C8B7FC460E45CE0CF -:1017A000E7AD6FEE7741BF515F59C3CA5F37B74F9F -:1017B000D49E365FA16AECE9D5F246C07B8CC2F5B7 -:1017C0009B41EE3C6057293E2F06BB4AA718731673 -:1017D000BBBA88F83B208E6C1C5FD853237F09FB73 -:1017E0006AA49BE08384041E37E4F41371C348F2B7 -:1017F00025E4EA5DE0DBC2FEF837C2AB2C7ABF47D6 -:10180000C013BDF488227EAA1FAF2D91034442FE6F -:1018100040FB78E85E09FDCD60A515ED72556514B5 -:10182000C667ABF265ACAFBA5D46FB19A4FAA196E8 -:10183000CEE74F5C4F18E3B32544724FD3AC7BD651 -:1018400084285DF9EAA577FF693DC4978BCD2A8C82 -:10185000775065F166BF4746FF95F6E10E427CFA88 -:101860009E8BDC60CF043F1CF4C8286FFE376537C1 -:101870000CDBC9E3D1079BF30332D059F2F68EA3F8 -:10188000E640FF552AD0E1EDD42D2ED07751DFDE92 -:101890005F5E8EFB47AF9A8F76933AAB74DE515CF6 -:1018A0004EA70E29BE12ECF891163381B8D191756E -:1018B000A7509EBBD637B8A78DE88B2F8BF8B031D9 -:1018C000CE6C8C2FF78B2B1BE2C9821F8C7C725540 -:1018D00004FE10FA2A127F503DB630E19FD06342D9 -:1018E0007FBCC3D73975C896DB1B291E6296C88892 -:1018F00007C1976F7F73F3CF410F4751FED800FCAC -:10190000FCEDAF5E847D08592E858D23FF07E737F8 -:10191000BA4F744FCBEDA3CBD5DEE5BD6510FFF913 -:1019200035AB7BCBB07EA35D89ACD706D65BD9093E -:101930002C0E6EB43B4679F8BEEDCEBCCA7B73E18B -:10194000FD79954B03006F1962AB01FD6BD4134613 -:101950003B21E6639C674C482681F1DA79ABD8AE2F -:10196000CF4E58B0DE67738E0367FD4C14837E70D4 -:1019700002C12F7D3F2AD084E3359C5F8EF36F98A0 -:1019800008D047DC5D7E585F6A34C60F5A33587BF7 -:10199000F99268E68F4F88C775CAC221FF320ECB15 -:1019A0004D7C0DE3E2BD4F02BF35794C5170AE3036 -:1019B000D5A1EC87904BEB1413B1923E3C09FF9DEF -:1019C000406480AE17EB24D877E6DB2C39E89F3EE5 -:1019D000930074B889EE0B29BF1F3820EFDA4697C1 -:1019E00078C03D3E369C7F2EE082D4B5A817AEF479 -:1019F00055213CFCE3BF6681BC5E2F793B605E9D58 -:101A0000F3AA6E2FA4F3A9DF2DE3B9D282EBDF1E78 -:101A1000C9F669FAF349D969CB85384A9314ED06BA -:101A20003D22F0D8E1B0A07E693ACCF460D3518970 -:101A300097D93EE2055E7FEA3D07EE3304DEE97AA0 -:101A40003A613D9EBBE3703D629FF12FACE75DE8DC -:101A50002FF27A325CE80F005FC97DF3971D0AAE62 -:101A6000AB9B44BB61FE3E1E0F22EF45A1DF2CE87D -:101A70005BCFF94FD0B78ED3B7BBFDF41D17D2F6AD -:101A8000AD9E783C65903309AEB7FBBD18E40FB14D -:101A90005ECA07DD80EFBDEDCC4EB4BEEF60F872DC -:101AA00014E5C2FC847FED4A607EB271DD157C9F37 -:101AB000FE7502D34BE0DF429C6271FC94AF130AC7 -:101AC000C3B4E77E2DC5F3B780971217F93240FAF9 -:101AD000F02CC611E38AF7A212F5F255C1E30AEF22 -:101AE00099C93C8CD3D2710B34F35B1B5F12959870 -:101AF000D47FDC7F818E898903F2A59E8EF58ABD15 -:101B0000598A25BDFB620CA5A9FDE5DC2867527B3F -:101B1000C757703E6F94FF33A60622D17E6F90BDEB -:101B200087E2296CF2922E6B4E7F79389B1EA1F4CE -:101B3000CE4B4CEAAF4F064BE78989FDE83C31714B -:101B4000003A0F8B2F9F04F5B0FEF402DCE75D082E -:101B500065D0139661381EF2654F1C096CA78D1273 -:101B6000781C45CC07E21251F4BD1F256623FD25E4 -:101B700085F8CDB49C90EB9640EF0F820F7EA49D2C -:101B8000DFF7C007570CCC0741F44B56717AAF1200 -:101B90007916BB06CEB31804DDAA60DC3326778F36 -:101BA00037FBDCE956D79F6E7503D3CDBB1AEA9B92 -:101BB0002CE44BF4C38B2B5361BC579C9EE3B1F4D4 -:101BC000F99E46AE4FB229DD68FD8B8932EAAB9FA4 -:101BD00091F3500FFFC064C2F97753FDBB3D3B1C2E -:101BE000DFFB9578FAFE99CB089EC7D1F5F9195F0E -:101BF000FA25787EC3226282E7A96A23319D831E7B -:101C0000BA8DEB09CD3A6F4B0C6397357AE80EA885 -:101C1000A7FC781DF0A34D752903E9A107CF5D0F3F -:101C20003DF83DEBA14706E6BF73E6AB27C3E903EA -:101C3000C1C7625F10295F88CA23498FEF3F2E21F9 -:101C40006E3C0F2B71DA98DDDD29A19D6D3A9AEF7C -:101C5000C5B2C3864A41D8E193BB58BD3C25BC3FC1 -:101C6000F86C623CF2EFAAB6D56E459707E2477A68 -:101C7000DCE939E91A4EF5E20CD98EEB4B2863F119 -:101C800043B17EAA67674E4FE67153BA9E844C8675 -:101C90008704EA0FC0399A93EF0F628B159DDF2FEF -:101CA000F076835C2E41DC3B2E9140DA0DF5EBD7CC -:101CB0008D82F3FB388FBE7D1269F942C64108CA96 -:101CC000433CB5DF10C74A2835B4837DC83868AFB8 -:101CD000799EDD7F3F713491EF272C2415EC0A911A -:101CE0002B06E41BCD7EE244E220F6139F278AF305 -:101CF00071BDFD6A8B2261E302EB92B8DFFD651CCA -:101D0000FABF32B75BD3BAB2313F658D43C5788134 -:101D10002CBB6D33B3FBBF1FE7311155B3BE84D26B -:101D200068A26AF60F49E5F1BA72CABC21BAF6692F -:101D3000DE61BAFAF49AF374F5990D05BAF250DF40 -:101D400005BAF6D95400B4E59CE61FE9DA8F68BD00 -:101D50004C571EB5E51A5DFBD181C5BAFA318FAE7D -:101D6000D0D58F6D5BA32B9FBFFB27BAF64D3CEE02 -:101D70006BC4CBC5494C3F37294CEF34DA0B301ECE -:101D8000D964D7C723D338FE4B6227E7421CBCE98E -:101D900083FC5CC0F70BCE0B302E1E892F8C7A2C67 -:101DA00092FE343E2FE6E37DFEBCC5047250B79729 -:101DB000CAEBF9B46C7F6733ACA9398F9DA72A842D -:101DC000E5F788F315F17EEFF98AE266F155A79DF4 -:101DD000DC1A862FD292F4EF093D29F82812DE048E -:101DE0003F9E0D6F9EEF096FEF49649E761E15FCB6 -:101DF0003CDBF8DEDA24133F0FF65E93C4FC9D094A -:101E0000D1E889BB501ECF55FF8B7950FDBF3409F7 -:101E1000F7136F2CB801F4FF2EAB1BF6649FCF7B3A -:101E2000A3FA7E15DA57B3F626772ED02552FC7B1F -:101E30006D52BFF8770D8B7F47EBF0B64CC8BB21D6 -:101E40000ED7E4FC1AE3DF4D1677EE60E2DFCBA09D -:101E50000F383FE474EEA52F8F9F47DA07F908D9B2 -:101E60002FC1BEC7AEA870CE75B67D2DDDCFE6C240 -:101E7000796A2BEC9B34FB1CBABFE5FB9B28B40BA7 -:101E8000D4EEDD9184EB22FB55FAFC0CDDF7DEAAE3 -:101E90004251D83F8FCE2FB712B7CD22233DEFC18D -:101EA000F76E22D745C9102F0B1E989CFD2FD9F332 -:101EB000FF481A707F68B4AB673D9743BB5346D762 -:101EC000BF218CDF653C87EBF5BFC14F93F03C0E23 -:101ED000F1B489DA45388FEB4862F679D361B64FB1 -:101EE000DE74744E2ACA4D52D180E77083D5371DF7 -:101EF00049FDFCB58EA401FC35B1FE357CDF3B5DB0 -:101F0000CE6B8378E3C99005F12613961F59BFCF96 -:101F10004C02484F96672CE8680E6DEE04FB6C2669 -:101F2000C6BC623516D66DDE27A37E2289ACDE4F95 -:101F30006C8DE0E7C416EBED569C476FB7124AE391 -:101F40000D764C6FB752E6E9ED569A576FB7D26BE4 -:101F50000A0C764C6FB786FAA618EC98DE6EE5345C -:101F60005F66B0637ABB356A8BDE6E8D0EE8EDD6A8 -:101F70009847D718EC98DE6E9DBF7B83AE3E3F78C6 -:101F8000ABAE7EFCBE9FE9CA859D0FEADA2FDBFF70 -:101F900034E6DF4C3CB45DD76E52D7AF75ED28C246 -:101FA0003B214F7B099284900B4F3CA5AB5FC2FD58 -:101FB000B48B7A7EAFEB87B4B27C6B3FFD0FE8F554 -:101FC00011F15AC0395148CF4BE994AE7501C91D82 -:101FD000A4CD96EFDE5904F3F8E4FD4BF6413FCB78 -:101FE000B6E8F3B49707F4E57A322C16F4433DE5EE -:101FF0008B00E5939590BFADD16B2B498313F321F3 -:1020000006C967CBF6CF2598F7E9F774427EBA5830 -:10201000A7E0370FE737313FB1DE95D4EF0BAA7D4C -:10202000EBF4D0FFD83EB2CB027C5BBD5B220F4A03 -:10203000FDD753D37ED7E6F430EB32AEC3E877BAA0 -:1020400093F5E754D3653BC6F54FBE29BB597C5089 -:102050002F876BF6B378FE9A27248CAF19F121FCF9 -:10206000D2487891FD6C9F509F4802018DFCA91CBD -:102070001FD654BDFC9D847FC07C1E960390171410 -:10208000A5461BF9AD2848FAE33926572FA7463C49 -:102090003BDC43C2F2954AFF83795413762E65E404 -:1020A0002B23DEEB76DF6501BD78AE785F64C0BBC5 -:1020B000383F28A1ABB584C9831378A5FBF2A5C925 -:1020C0004991F7ADAB9325FDF9F2D9F7ADAB93BFCD -:1020D000DFB8C9BAE401F6ADDD102FA37EA5315EED -:1020E000D63F3EB6F72BC989716816FFF2BA6D2C40 -:1020F0005FC5602773537576B277DFFB8114680282 -:1021000039767A6E83F9D43A3D2D007FE4F4DCAE63 -:102110005D6F13C50BDECFA1766A6718FFF0E5642B -:10212000E11795635C6453096B6F6CB7335941BC1D -:10213000772415A5A2DF79349FD94F47D1807EE758 -:102140009DFC3CE736382F1CD197C7733B3F57A106 -:1021500062E701BA6D3297A76AF37CEF498EC3F14B -:102160009C939EEA847CE72697C925A9E03F9BF0D3 -:102170005C74A3C75EBA2B8FBD97A87B8FDD3B92A3 -:1021800001DFE0CFDB95AFB57CFB32C525F41B69E1 -:102190009D2F27337FD74C3C36D0BBE23CD7FC4148 -:1021A000BE0DF4AD22B95DE1F238CD3C4F6A0A3F75 -:1021B000CF955DEC7CB757CECF922755E7F4BE9410 -:1021C000ACF117C4B9EE954ECFCB404F9FE2B7822A -:1021D0007FE9B385DFFFFE89D3F156BE3EEA682270 -:1021E0001FE1F8F2A0E2276F25635CCE8FF98A37F2 -:1021F000C8EE13109F1B6CBCEA6872BFB8DC512D8F -:102200001F1AE58FFA9FC763E17C22768882DB097B -:10221000C59D0BFCDF0CFF9E84F1D513F07EBFFC47 -:1022200053359EE7D3AA03E6D38A7EE6C679BA93EE -:1022300059DEDF17003DA35C1B654D3FCEB3F44371 -:10224000F194DB601F14FEFEC1F0E73EC18209E796 -:1022500016D78C4AE9E73F46A50CE03F9E393C2A59 -:1022600016CE9345DCCAD8CEE64BC8D0DE8F698E39 -:10227000D38FBFB9809513F9B8CB6319DFE7F2B2FA -:10228000C80314716BDB4CE281FB0E3FE3F9D9A26A -:102290009FDC1407B68F8B9F929B5208E76912EE62 -:1022A0002B37C749BAFDE5F1E4925C58CF30DE7FA9 -:1022B0006E0AE3D36DC3587CC69807F9196FFF59AE -:1022C000F214849460A3019F16590E8BC7B1296C38 -:1022D000FEC76359BF227E56752FBBDF25E26622FB -:1022E0000E483D83B762A85E39D6622610D75A2AB7 -:1022F000DB37031FF6DE9FE3E7EA2EFA1FD8CBCACF -:10230000BC72CC3FFA57EF6F013E63E2FBDBCBE9D7 -:1023100029BDF6D27D8EF7B86632FC0CEEBCBD2B23 -:102320009AF16D8FC38EF16C63BB6A4E9F161EA728 -:10233000007D0D76235E260DE1EC4735C7FB99C382 -:10234000560FFA31A5D198CF21CE3F14CA9FB1F1D3 -:102350009806EE0768F3A567C07DA2DEF30F95E04F -:102360007B09763BBEA7A824E8802BA18A5B82FC70 -:10237000B22E4BD7A61498EF45921BEE0FA454B87B -:102380003A5212E11EA18A62B6399B388BA13EDF18 -:1023900084F57197BB369B21EF5A2570924DCC7412 -:1023A0001C071DE78E946C5C7F8B7F6E470A6D1750 -:1023B000ABF6906179A0475C3352418EE7B1FC7572 -:1023C000E3FAD6A730BCD937D17D03E0430D9F0790 -:1023D000BE3E85E501513D7313D0A34425BBD8BD56 -:1023E0002896870A69D6982FE866F9D231906F94BB -:1023F000C3F40CD4DF15377523C88F902F99E31BD6 -:10240000F85E9B0F7F07C77782413E053EE9008D4E -:10241000900FA1CC24C8D7B32BC2CFF7314EE77AA7 -:1024200067F93D30EEECC98D98E74EBEF9EE3BB949 -:10243000089C5E2627F47D027188A844A67FA354D9 -:1024400015F531714998676A53DD35508EB25FE0FA -:1024500092C1EE59F979E1121351A8BC4DE5FD780E -:10246000E611E9C35C166765FA55211F0AB9903970 -:10247000728AC07EB23FEA17B5C4D0F54CB51FC012 -:1024800073C4A8E10D2570AFE0C545AC8F9F45C86A -:10249000DB3FCEF558BCEC4D35814F4F8EBDFA4237 -:1024A00006D2F93CB8A179DBA6C3AFEEBB88C7CF93 -:1024B000215FDC7FF8554FDE3F9F5FFED2FD875FD7 -:1024C00085FCF27F9EFFDD12E8F1E394B160DE4609 -:1024D000FE17FAEC90EC3D7423C5FF1594A97C051A -:1024E00000155281F466F94397733CFBBFA678B69A -:1024F000F5E1F98AF6FD88BF43663A6F3ABE790A7C -:1025000043B5F927B13C1F2380FD5F696B9D0EFE2B -:102510004DB7A5671C8CDBFDDC5F33FD549F1CFEB3 -:10252000E92907A1FC7744E971C0F313EBDE707869 -:10253000E87A0FAF93F1FE1BDE4BD6E4039DE07CFF -:10254000353DB5FC08F0D5A2F5DF1669FD6CE24B10 -:1025500042BBBB3C20C31DDF5EFDB7F2D118CE7479 -:10256000ACBCAA2D415716F6789535FC3DF1CC54FC -:1025700046F7E58F6FB3403EFCF454EF1730FE0989 -:102580009E6F70629703F757623E8B1FCFB7C07E76 -:10259000F248BB950481EF954E33C1389567A64448 -:1025A000F9D6CBF9D038CF97F6C4607F4BEF953191 -:1025B0008E5449C7F251BC7ADB97B3FDAD611D4B18 -:1025C0000FAB33405F2DBD45227E95B55F47E9E6F1 -:1025D000F5DD8CE72BC6751AEDCB69B2CE027AC455 -:1025E000685F961077F364B05BADFAE7CBDA6FC340 -:1025F0007E979DE53C262195DB9B2232F1BB1C8812 -:10260000330FC37CC148F6E6C47A26941FAFB721C6 -:10261000FC74BD0BE11150A614CF2B7777BC948EC0 -:1026200062DD590476286AFF54DB35A4CF7F56B6A5 -:10263000CD0D3EA4025FEAF3212B389E85FFBC8CB2 -:10264000DF33389BFF5C01EB1C201FB26290F990D6 -:1026500027F78DB7C1F3C2547E3E3591E203ED6F8B -:10266000DE6B2A39BBFD8D849748EFAD82EF1C8469 -:10267000C1B3909B23DC8E2CD93167F3103A81A62D -:10268000E73ECAEA42BE647108714E25A76EEE8429 -:10269000F5CBC410FFF3933789867F8DFCB98CB8D6 -:1026A00099DDB1B3F76C3C2ED1CB97EDB7235E0526 -:1026B0001FC18D02532AC060AAA9B8FF7703FA7D13 -:1026C0001FA0555FFEDCDC95057A6399215EF0B9A9 -:1026D000147EFFF5C3D4616CFDAA6706E4452C2582 -:1026E000E59B595CBD159F9F505A5FBA11E479076D -:1026F00093A755CF3EF10CE8A915FF79AF13F4D499 -:10270000DF94D66418AFF6914D4ED0EB2714BF136B -:10271000DEFF5B400E7B5F777BAA24F2E2ED901731 -:1027200056872C0602E69F057AF2BF1F31BB208E2A -:102730005AFFA83568A5F8A8DBC5F048CB4759F97A -:1027400066C457FD6EBD1CAEF8D5BDC92AEEE7FDC7 -:10275000E91C7FE9A0AAEB7698317FB4EE4DD90D44 -:10276000C3D4931E5C9FF17D984788D2ADBE4DAE19 -:10277000B4C4F6AFA71E8F05E4AC7E17A353BDC14A -:10278000CFACE17AD9C8EF3F1372CFF99CE205E3F1 -:1027900061229F9504987E6E7AECFE7147E9BC3EFB -:1027A000DDF1AA53CAEBE377025997145F27DBAA3E -:1027B00016419E41243EFF9CCB45AFDEE77646DDC9 -:1027C0004D2706BE7F3B83B5E6A0F3428A8FDA6DC4 -:1027D00066B79F3EAE7D42F6D8C14F7ADB8ADF777F -:1027E00058F9C48B6F5D40E7B772A73971265B86D5 -:1027F0001DF4B3A0533DF077411F5D563CFDA2058B -:10280000F220E1F9BAF83EFAACDCD96181BC4A2386 -:102810001EA7B67558987C19E8D4767406D8E5A634 -:10282000C7CE58800FFEB64722E0421ADFAFD9F676 -:10283000A213F407E009EC87A0572FFDFAD12D3839 -:10284000EBF713B09D0BCE6922D1EF5A984B12F2E1 -:10285000F793BFA7E3D7BC6375C3FA6B9EBCD609D9 -:10286000EBF84869607CFEF34DC9608F6BCCFE6469 -:102870001742F6BC66EB8F91FF96BDFEE364827A49 -:10288000D39306F24BD79906EB5BFAF015B8BE6A04 -:10289000E245FEABF9B95C0E7EE269859486F3F3FE -:1028A000D3D3989C7CB4DD8A9B828F2C847D87E374 -:1028B000CF32CBE323ABD10FF9315F2BD5C4583ED8 -:1028C0006D6374EA4E357139637AAC9EB7AADF71D5 -:1028D00033EAB18F333D2920EF140FFA78EAEBD3B6 -:1028E00053B8FEC3EFA5E07B94EFA6C27368DF691F -:1028F000F6448DD3BDC7F35AD9F8D7F1F1E9BCA39B -:10290000212EF751B27EFF2AE02569220E463A8930 -:1029100096BF22C9FD8E5B90AFBE7C93E995BAC08D -:102920009C52ACEF340753A03ED071B9847A81FA3F -:1029300017E1E47A8799CBB5BE9ECE5391B4F8DD0A -:10294000C3EEC555DF43DB69FC903EBEB1F43DCF1D -:10295000EE934F915FB1CCE09F0968D40B49697A3F -:10296000FB27DE270F2785BD87D5A70FFC88B75A21 -:1029700073E0970F821CBF6DC57B86B54F98F17BC6 -:10298000399F3CBEF7AD6B28BF7FD226E457AF67B7 -:102990008DF25BF3D415249CFC7E92584EC2CA2F54 -:1029A0007D1E567E1359FEFEFFB69E5D1641CF5E1C -:1029B0009CA6D7B3D49F88BD90163FFEF5CAA1B898 -:1029C000CF32E055E0D3A8370FA5AA885FA3DEA4D5 -:1029D0007F6F120D1E05FE045FAEF8CD2A1CA7976F -:1029E0007F057F0AFEEDE54FE37AF57834D62B704C -:1029F000E7A8B08FEEE60D747F0DE7AECFC978EE95 -:102A0000DAADF638E3212ECBF36EBA5DBC1CC7CA33 -:102A10003D4996CDA03FC4F39E289687D05DDEE366 -:102A20008CD3F8F547DB6527E4D57705C2E74B6023 -:102A3000264512DC128D54DFC8BF5B63CFF2C1BEE6 -:102A4000AC959DF72C69BCCA09FE74777BCEEC79F6 -:102A5000E0C7EF97D1A7EA8EE6F9557E8F9246F14F -:102A60005AC5964C4E10FF7DE06757B5AF9C099B49 -:102A7000C6252D7A7C54DB2FC7F3ACEA7BCC7D7C5A -:102A800041C0DF0958C0CFAA7958FF7C05E4550141 -:102A90007D0C7CE4053E0A730FA359F0513EC967D3 -:102AA000FB647E5EC5F5DA74396FF63CC85FDCC73F -:102AB000EE499C6C97C96658EFE3FCFCCA9F84FC06 -:102AC0005947F9581BE7FC14F86C5464FBFDE96F97 -:102AD0000F17DD489BD43EF3EEB88728FCF499B776 -:102AE00047FE01CACFFE35EB5DD2BFFDD43D5F2D61 -:102AF000C43CCA3D5602FBA2EE3D2F67DD08E5DF70 -:102B00005BDDA8FF37B0FDB17F8F03ED7A7726F349 -:102B1000FF9A9E3B33AE0BEDD346A4D7D369EC9E10 -:102B2000EAC9F6BFBF2F413E5D3B5D15D85DBEEFE4 -:102B3000AAFF7D14EEAFBB9F3BA3DB57FEABEBA917 -:102B4000E3F795BA1D641EDC2FEE8E63F73BEBFFB7 -:102B500030E917705F71D5AE0E4B15AD9FFAC76F98 -:102B6000C781BEE97E8AF913D4BFDD0A2EF59E0720 -:102B70000EB49829FD3E079F6F0821573D682F83AB -:102B80007B18FDF1C2F0D04DF100EBA278A9013D18 -:102B900019091F7FF9B7C5C7170B61FCDAF689045D -:102BA000E2E97D78913CECB903F32EE8FAD9F33DE4 -:102BB00067C6817F74B6F59E4A63F765FEAFAC3792 -:102BC0006EC8BFEB7A19BF3F90A6E23C8D7CDF9FB9 -:102BD000AF9FBD1ECB4F3ADC38DF41CA7BFE90FF72 -:102BE0005BFC3DFBDF76BD67A3F77E4E6F870BCEA8 -:102BF00053BA9FFB368B9CC3BAEBFE3F5D77AF9F0A -:102C00006372DB26D0F9BD430257944891F3381F15 -:102C10001AA2DF47CCE27EC4ACC46AF41F667958BE -:102C20007CA58914EC837B6A7E8F8CE70E984C43DD -:102C3000F1D079797E00F3B614FF88FB208FEBCAC0 -:102C4000556EF69D2FFDFE6A56726929F86F071BB7 -:102C5000E9BC68BB830E93AB892E61B647467F8F74 -:102C600042F4F3FE32E552CC0B995DACDF675C6356 -:102C7000D8375C354F5F7F25D99E04F97757D698B2 -:102C8000315FE80A43FBB5435CB8CEAB48C32616B8 -:102C90009F39373CBDCAF1D41F0F03E3AD1F9EF827 -:102CA0007E127379D4FE78B37AD9FED24A2BB8BF9C -:102CB000C5F3E4D60C0A9F84EF3BAD7C68815FAB23 -:102CC000877DAF53D32FE245E0FD5CF12DE864C46E -:102CD000BBC0AFC09B910E5BE14C42E38FF74191CB -:102CE00047E225DA7CCB59BD7EA31DF1F8DA0E76DA -:102CF0005FE1B5E2AA967C283F2EA1BF767AF278F2 -:102D000062A3EB3D6826BBD9FD2F8FEA2AEACB6789 -:102D1000918A5FC67305C827D4EE4B219F50BB2E06 -:102D2000C827D496219F50DB1EF209B5F5904FA815 -:102D3000AD877C426D19F209B5ED219F505B867C11 -:102D4000426D7BC827D496219F50DB1EF209B5F552 -:102D5000904FA8AD877C426D19F209B5ED219F50C7 -:102D60005B0FF984DA7AC827D496219F50DB1EF2D4 -:102D700008B5F59047A8AD87BC416D19F205B5EDD2 -:102D80002F0E3DAF2B97905775EDA7DADED095A7A4 -:102D9000BBDED5B5FF61EA315DFD25EA27BA7A4190 -:102DA000FF4B734FE99EC39985BF08F631ECAFCC5A -:102DB000FD775D3F0A29C738B3853420B441FC96BE -:102DC000C268D286D04EC51CE0F491DE11E9C0AFD6 -:102DD0005BFD9B81B90E4E3A9305FAFFB5C9735955 -:102DE000FC819F13CC867FAA948963BEC9807DAD88 -:102DF00038F7748664121C4FF930242174856248B8 -:102E00003081F261280A617C28019F2784E2102624 -:102E100086D2F17952280D61722807614A281B6118 -:102E20006A680CC2B4D068844342E3F1BDF4503EFA -:102E3000C28CD085F83C3334096156682A3E1F1A8B -:102E40002A41A8862E45981DBA04E1B0D05C6C9743 -:102E5000139A837078683E3E1F11BA1AE1C8501564 -:102E6000C251A14A84B9A19508478796233C2F7483 -:102E70002DBE3726B41A615EE8467C3E36B416E1B4 -:102E8000B85013C2F3438D08DDA1DBB05D7EE816B8 -:102E90008405A1BBF1F9F8D05D0827841EC2E7853F -:102EA000A1071016857E817062681BC2E2D06F1088 -:102EB0004E0A3D86F082D0D3F8DE85A19D08278793 -:102EC000FE80CF2F0AFD0EE10F427BF1F9C5A10E66 -:102ED000849ED0ABF8BC24B41FE194D01BF87C6A6C -:102EE000E87584D342EFE2F3E9A1B711CE081D43A0 -:102EF000F8C3D05184A5A14F105E12FA1BC21F85E2 -:102F00004EE17B9786BE403833F4777C5E16FA0A32 -:102F100061EF7E7F72A47B895ED37710D7B2C70F33 -:102F2000EA3B5F846CD19D4BDD1FE3443D397B1D43 -:102F3000CB23D95C726A1AFAB5ABAD2AFFBEA641A3 -:102F4000AF7E6307FF6113D4A4B13E200F7001E789 -:102F5000DFD78AF72681BFB4B9A0AB16E221B767E5 -:102F6000775500BC339DC5573773787B3A3BCFAC60 -:102F700018E9C272C5EA11787E451207B78ED78666 -:102F8000B0F744FBBA4C5EB6F764E1BD8041F6335E -:102F9000D87667CB8FBA2EDDBB1DE5BCDFFDBC410B -:102FA000BFFFEBF4C27FE9FDA7067AFF08A7972BC6 -:102FB000A3FC199CA7E21907F55336A4C989B49F4D -:102FC000CA16C90576B26A63FE0CA05F01F1603CC7 -:102FD000714184BCAE7739FD16379809C41517AB1B -:102FE00004E3B98B77B13C5F88839651BEA8E17C3E -:102FF000B1EA969D1670416B1A96B1FCA3008B3313 -:10300000D9E87FC0CF2B5AE660FED1CA47F5F1A7B9 -:103010005A88EBC8708EAC7F5ECFE34CC678A53182 -:10302000BEF4663A8FFBBA59DE11913370BDA7E941 -:103030007A219FC37BBDC306FA9FE201CF49C4FA40 -:1030400045BC52E081F4BFCF8079A127F78DC03C09 -:10305000B593AA9A02EDBC549C3AED90FFE09D080E -:10306000CF29FE309FA4A73106F3918E527DAE4248 -:10307000E293CB3B11BE9FD6F54E26E1DF6FD49F86 -:103080001BD85A30FFBAD24C07A6ED2A1F49C0FB05 -:103090008FB4BF71BB211EF98819F381FC644D2ADE -:1030A00029EE7FAE50BEC98CFCB178771CCB0FF3F4 -:1030B0007BDE847C7D418FA31B7366405ED1E2E69C -:1030C000EC7C0CBBED36A39F27CE4B059DFAE74564 -:1030D00097C7C2F7115734BF8EF4A4F4D2D5D7B630 -:1030E0007C81F70728BD8E47A0D7F181E8159DC1E7 -:1030F000E3816E912796177B1554AE4B4039ADD8BE -:10310000101CD1A0E147639C9E64D8F1BEA3C827E0 -:103110002E1DC2E841147732D0F5544B21D2CB4852 -:10312000A7D27F54213DC83B0EFCDEEE821CB2E8E4 -:1031300032FA7C118F5B2E68BA04FDE79C0CE6D74F -:10314000BFB61E722D09797DBD8D78A8F3FCC67AB5 -:103150001796FFB23E15CB7F5DAF227C7B7D2EC2E2 -:10316000E31696CF23E4893200E6D58DCE60723423 -:103170003A43ECABAE4B85B874E93FDE2884FC9E45 -:10318000247FD2ACE999E877EBF234E65DAECFC3A9 -:10319000E832F33CAF5B24377C476571F985BAF6BA -:1031A00024777C5F19EC07CF1B59DC1C87DF6FBBD2 -:1031B0007A6682AEFD95CDE9BA7249868AFA754E75 -:1031C000698EEEF935156374E54AFEBB09C4166DC8 -:1031D000D29E4F51CAB23C6F176BFB65C3C4941BA0 -:1031E000E8F85F1E3063BD911EC72D7EDC8FFBB7F4 -:1031F0005BDD60874EC03D325A3EF11719F5DD099F -:1032000033F1BBA8EA3E21918D0089C2E4E9F421A3 -:10321000264FA5FF9009ECC3C9AFAD787E57B545E1 -:10322000227EB843D543314FC7BDEE312BAE7BC9AB -:10323000169978F1BE92DA06E7D6D73D32CA0DE785 -:10324000960B728299706FAFE7B751EEEDB4B6AAE4 -:103250008BBD7F82EEAFE3202F492AC0F383CFCA14 -:103260005AAB4D906F201F480239FDEC2919E32914 -:10327000CB57FFA5C8057AEDA5B6B78AE938C75B75 -:10328000651CF79347ADDB6494774F0A7CD7B56F25 -:10329000DD018C33BC945ABE2283F2C1C7D5817143 -:1032A000A877D6B1F8767FFCD0F502BD815F357A7C -:1032B000ACCF6EB17332AA7CD2403F5499DD786EA8 -:1032C0007ABCC58CE77954FFE3F9FFF1D60413D338 -:1032D0003F4F21DF2D56548B76DCC52DB287FD2E56 -:1032E000846A81F992BB642F99086596AFE06F9666 -:1032F000BCECBC464FDF6B574FC4FBC5C6FC290175 -:103300003FA732E5D59C03AD788E9DCF92095D8AAB -:10331000367F5CC457482AEB5F7CC7A776D8FD7719 -:103320004CA6F0A4877D72F0F40E07EAC74F4DCF8C -:1033300017DD40E12765FE0F154A9706D97B5F062A -:10334000E4EF985AB64A782E72EC0E388FFFF809DF -:10335000B31BC590E76BADF8F5F2A103E507C10C0F -:10336000D8F97230594A85AFF212CCDF984FDA782B -:103370007C20C0CEFF6112143FAE5A768E75ACD061 -:10338000712BDCC3AD32DCDB3DC6EF2D3C96C1FCBE -:1033900021619F3FE2E52A13934FB2877D7F11F2AF -:1033A0005E866BECA9D0A7BB3386A1DEE8B5ABA4E3 -:1033B0000DF54A35FF3E70EDA356764F47252E900A -:1033C000C7E584CB1FC8337D6F85E589FB809D975A -:1033D000914EB4731F9B03D59DD9F0FEB68DF1F8C5 -:1033E000BED91D00F9E576C0461507E88F6584CD86 -:1033F0006F55AB14086AE214E2F73808D8058DBEA1 -:10340000E96F0FF4766029B7774B8921DFA7556FF5 -:1034100097CA631CB8AE15AD3CEFB9775E32F98E32 -:10342000E2ACDA1B786916CE5B7207C2CC6319E98D -:1034300009C27780573DCEEE0319E7655CC760E7A8 -:1034400059ED9E330DBE27DC3BAE61DE02DF042E5C -:103450002869E820F05EED67F8AC6E97905EFFC5D6 -:10346000FD2A71CF4ED07D19299F057A6DD93D7403 -:103470005F98DDC707BDF67A6700FDA54F48ABD35F -:103480004EF9BF76CBCE2B27C17B0FBF6E01FEAEB0 -:10349000880F8E30C5C14FD2DC7847E94561ECBB5F -:1034A000C19E7F5FF8213CCE84EF517C2CDD2163EF -:1034B0005E83A61D3FDFF7337EF613CC23AA795334 -:1034C0007637D1A735F0733E05E73E5F819FFFED6C -:1034D000791BFD989CCC81FD18A37EE9E7C718EC09 -:1034E00027DC9B007BD993C4F2C0BF543CB1F1A848 -:1034F000970D7A37A900BF3B2AF46E35B77B629CE3 -:10350000A560EF68F9C32D4F3B21FEF05FF73C9DAE -:103510008C7914605FF2FAECCBF5556CBCEB9F8DA7 -:10352000C2BCA5CFCA3AC781DF57F1F3979DDAEF46 -:103530009AAE48F59664827EE6F67095BC2DCB0572 -:10354000F6D0173EAFA2DFFE2BD23A1D6759A74334 -:10355000BFCEC5B04ECD7D902ABECE0F9AD9FA8E81 -:10356000B5B0F52EE9B74E3F9E835CFF0BABDB8F0A -:103570007E4610EDF8899D3281FB67BD7E86C1EEE7 -:103580009F26AD5B011FABD6FCF57D85F2C5F291A0 -:10359000143F940F2AEEB2A29D5FFE5B76FEF9B156 -:1035A00054928207F02F049D6BE9F315D43F00FF7E -:1035B000A26F1EBD767F39E0B1D7EE0F127F753C4A -:1035C0000E55D7FE32FE5E94E461F99075E23B3011 -:1035D000BB0DDF81514107B07BF236A0530651D9B4 -:1035E0003E511F4FFDEF115F2C5C83FCDF3352FB1C -:1035F000BDDEFAE8A019F27D7B764AE817ADBAAED7 -:10360000C4594220BF95C5C1366732FB25793C9825 -:10361000F762A5748DA6E3DD92A9B2E7AA8BE575E2 -:103620003F4CF0BB3362BEC6E7101FB781FDB39BB2 -:10363000D0FE19D7BF3B93F9CBAB6413FAD3B516C1 -:10364000E65777F3EF3EDCC7EBEFCB64FEF5C399AB -:103650002C9EDF0D7E249C4F5F64C5DFEB21641A36 -:10366000C6C915C2F84F117873299FF7CA37FACB2C -:103670003D1980A785A4D30CF49C553C47857B035A -:10368000EF27DBF03B4AF4AF1CFA99CFFB396866B1 -:10369000F704DE8731E8BAE6F378F2FBF019503A26 -:1036A000FEFB6916F463FDCF59D14FB8399AC5FBBB -:1036B0004862AC027C7E0DD7530B265B3D703E30DA -:1036C0007FF2CDE500697F7E42F15561EBD9944FE1 -:1036D000C76934313BDF184FF0BE24D9D85508F8FC -:1036E0003B9FBAC590274F57BFEBBB8481F8487FFB -:1036F0004FA116E20A1710C660C5885F5DB9D6C231 -:10370000EA0F661E99754F06217F866C26B03380BE -:1037100023E08BCA58DCE7CE863CFE78800AF2DBD9 -:10372000650AF19B186CB6E37788585EBF3807B915 -:10373000A2980463E9FA82FBF5F728AE0A9A82A3FD -:10374000E07C47097600FE4C36D5ECA2E394974A1C -:103750000580F7DA0D839BEFD1CC8F67DD33999627 -:10376000E17B5730CFB512E6F3CCA7420F7CBA50BD -:10377000212FC8058C7EC087F5F1AA1FDBAD667CC2 -:103780002EEE6F08BAE4D3EEB5F89DCFE747FB699C -:1037900076C2FB96F07193CF32C53E8FF9692BB993 -:1037A000DCAE147CF7B85E5E63B354F63D35F007CB -:1037B00029DEE6731889EFED59AC7F7B16E3FB1029 -:1037C00097C7C18EB7CA4A82B8EEE7AC484731EE18 -:1037D0006C0EA3B358FEB29887E0DF6AD280F93747 -:1037E000D53C1E63A29A04F3745B7F81F9FDC63C4D -:1037F00021EA2061DED98A1DC6E79A788EACD34BC8 -:1038000018E7942C3D4B607ED20FA2DCC0EFF32D65 -:103810006D180F30B633B74A28E7E666EA4F49FC21 -:103820007C8B96AD2D12FEBEC3FC8C9EB1F8BD7292 -:10383000EE575773BA52ED3D03EE0155833F85E7CE -:103840005FFC3B515B981FA970FF77718BDECF98AF -:10385000BF51E36732A0BB576F35E4879BB9BF7197 -:10386000C4D23316F4BDF19EFD11139BBF3F996086 -:103870007EA4B867AF707F52F0537A9659773E2690 -:10388000EE7356809E62DF3B30E453D9F1BB2B15BB -:1038900012FF5E258F2B9EA4FE267E57E67014DA5B -:1038A0002D1167EC2E71F84DB1F0394B565E107B3F -:1038B000FD2CF0332B9C1605E01953178E7383DC17 -:1038C000E9C8CEEE8BE36E2E19BF05F286E66CCD0D -:1038D0009D6DCBC4530E7E1F69EC6B90CF7BF93787 -:1038E00074FE581E37DB43F747DD2FF62CB4511515 -:1038F000BD2CEBFCD90AB5E7DDF7F66C85F2DAAC46 -:103900006256BEBD270BBE21BC76EB64566E14FD1D -:103910004D9E0D79F0DD0FB0F295B4DE0F7E2EBF17 -:1039200007547181847A762DB73F227E54617A9E46 -:10393000C129EC773ECED66E4356F9DACC24F8DEB8 -:10394000E771FC3D8116D5B316ECF5FA0C6F6516E0 -:10395000ECA3E6487E0BDC8B7F333092DBAFB0BF4D -:103960007BB13693E5096F1C5A8EEF0B7CD17E56E6 -:1039700064159E7B3FF1FDFBB9F69F99CF91A16C39 -:103980007D9A7ED6FD33FD4C51F5F311FE99F8CEAC -:10399000DCBE6CCF16E877E54D6C3F4C8EDB75F7DF -:1039A000FF4F353C3B12ECFEA9C7AD09C0872B9FEA -:1039B000FC5D5635F87FDC1FFAA4E36D0BE47DD780 -:1039C00085D87771EA43EC3B3975BB3A2C33F2204A -:1039D0008FB5C3325533BFDABEDFB9522ED3F831BB -:1039E0003FCF12F9DAEC771D573EF937FC9EE04ADB -:1039F00053DB8790E74B2E607134E33A37F1F7DE03 -:103A00008773FF30F1825F70FDFB558E673BAC73AF -:103A10006316C1F67284EF767DCAFBAB88667ABC0A -:103A2000AAC8615329BE0BDFF43641DE69F5C3D95C -:103A300005329DC7F68C298F037F448E6FF6B0F850 -:103A4000663B8B6F56C4775E478D14F9686BC59DD6 -:103A500036BACFBBF47ED27BDF0FE286A556213F7C -:103A6000D7CE9E96C1E265507E256BD59D203FFB4B -:103A7000F8EFB32D9838361AE4BC2B3BC6E4A2F21B -:103A8000FF747AE547308F05132F9A01CF4BAC8E28 -:103A900091952C3E8EFCF1747AF9F3500FED21EEE6 -:103AA000E1B50493AEA2EBF0BE2263DEB4775C8C8A -:103AB00037DC3D9520B7571F65313F6D9F89CEB3E9 -:103AC000A06F1E627CEA985DD70971AB0D69F9E0C1 -:103AD00047BB324A3ECC4AEA1BDF95E17D03CA620E -:103AE0007CBADC71F07CB0F3E8E4F4F810E846FB53 -:103AF000299F2CC397127AF5FA65D36274E5CB67D8 -:103B000026108F366E7A79BAAE3CAF2247D7FE9A2E -:103B1000256374F565D6CE090DE7E0EFD73B1EC5EA -:103B2000FCDEC3EDA7DF9A0F7EEC0ED92DD1F52C6C -:103B30007FEE91B720FFFA24FC0449018B8BB1EF93 -:103B400035F2F318C5A3E8CE63F63F6D01BF5D13F0 -:103B5000E737DCCB3B80717CE3798CC817FF67CFFC -:103B6000632C43F9BEB8F7F73C3F7D89AE8C4CDD42 -:103B7000DD81F469DACFF2989BA8DF02DF13FBE165 -:103B80002E6B00BEE1FED9EF8E5A54CDB94C7DA804 -:103B9000117F5777EAEEA3786EF3AB2CA6B7EBDA7A -:103BA000BFB0C03DA91FB6AF46799E41F5572CE581 -:103BB0009BCE0E327617C493B31D9887B3B2F91219 -:103BC0008C53C786E623AC6DBD04FB5B159A8BE571 -:103BD0003AFE7BBEFBA23B67801DDEF74C1CEE0766 -:103BE0005F9383231F827EAC0ED40F65E90B368072 -:103BF0009FB02FDA9F772D1DAFEC3F7F8879E87556 -:103C0000BB248C9B96C9649F04F9F7A128ECAF4CA8 -:103C1000FEF384D5F4F9A553995D2D031F87D6CB08 -:103C2000458E5BF17BD2117E27AD6028D32BE62E2B -:103C300036EFE9A139D89FA82F1E3A4CF7DD18734B -:103C4000D20E65B1BD6F3DE62E09E18F426310D6FD -:103C5000EF9AA340FEF92BB9BF48043CD1F6F87D9A -:103C6000B0FEFA78622C09A3B704B4723D3C1FF48D -:103C7000309CD3677B660D4D82DF23EC526CA047EE -:103C8000ED3617F82FB38AF3D56ACDBAE4E7AFC69D -:103C90007B10D6C41E33F803F329D4EAED4511ECAA -:103CA000CCE5434DDC7F6EC4F50A7B448EFF18CF14 -:103CB000B517F2F88090A792A1261D5E3A25261727 -:103CC000FEDFB27381D26C6F35CCB7B384CC7B0A84 -:103CD000F5686716DC47FFBEE64FE96B03FA3B95D4 -:103CE0002E02718C95BDF367F27CB6F95FCDE7FFCC -:103CF0009A4C7CC017AF5D7C71A787CEABE3C6F151 -:103D0000E3C12E88F1D60D65F987C4D5F30DE61B06 -:103D1000EE895121AE5F06671E13FAFC79C847840D -:103D2000F861FD1EEB76F8406ABD93EEEFED90175B -:103D3000181504BEEDF8639402F663EC70EFBAA1B7 -:103D4000982F386A1A7CC7C7D36E5508FA419E9FD0 -:103D5000C2F348F33D9BFE12F268E4336F33933FA6 -:103D60002F97C34ACEB78BB91C562AEE58388F59B5 -:103D70007440C67B918BD7496377417C4075E03DA9 -:103D80007D218742DECCC097E3813F195FD686E272 -:103D9000B87C67F37E991C94C92CDFAE6C4C1CEE8A -:103DA0009FEB4209D84EC8AB90D3CDD9DEC761DDB9 -:103DB000654D54BEE938DE0D6913405EFAF8C4E281 -:103DC000027EA27C925AADE183A68EAF14E013F37B -:103DD0006409F9C44AE1540D1F95F7FA27AE19C9D1 -:103DE000741EB33666E3F79445FDCEA1C24F191C8D -:103DF000BF6FE5FCB5D81E1C017EADB921CA0DDF31 -:103E0000913F99A8A21E5B738B843F4EB8C65C3E5F -:103E100015FC8B350F4818DF03BF03F44FD1A10603 -:103E20008BF61CE4EAD0383CAF9E1B1A8E707B8662 -:103E3000F78F8087CAD0951C8FE3C29EF77DD9701B -:103E400033C6D5BE0C58DDEC3B63FAF85DA1C78DD7 -:103E5000E77FE60366B24D85B89B57C6F3BD4CE2DB -:103E6000BA5B62F13B88E789F89B38A71371382B5E -:103E70007C0F5763474F2BAD59B00FE9178F2B615C -:103E800076FFD31D66766FABE3CF45265AFF71B63A -:103E900007E3722FA57ADF86F5ACB82CF0A49996CB -:103EA00057DEFEB413E2E5029F6D4A7004EC97DA28 -:103EB000281E213ED8D622970698BF133347935F1A -:103EC0001189AF578472103FC2DE08FDFDECFA5431 -:103ED000DC940A3D7E363B24F87B159783552007FA -:103EE000446B6FE694C3EF9A915C09EFB9F6D91B66 -:103EF000260F424F537E47B929CBC9C4B8BAD0DB8D -:103F0000467BB4576EBBFB02B0BBAA3746A5EB9B02 -:103F1000F29BBF3FFD0EADAA7DEAB16940A7923189 -:103F20001281734CA39EFC1F2B97089D00800000FC -:103F3000000000001F8B080000000000000BB55BB4 -:103F40000B7854D5B55E67CE9C9949322F9210C23A -:103F500023F1CCE441A8018747243CFC3C10082015 -:103F60000627F8155153994404C4BC40B9A642BF72 -:103F700039210902A53654ABD4A29D50B0D4AA8DE4 -:103F80008035AD3C06411A8AD569B5B7F416E828E4 -:103F90005CDE60C05AF116E5AEB5F7399939930485 -:103FA000B5FD3A7E7E9B75F6DA7BAFBDD6BFD65E99 -:103FB0006B9F9359C523E5058500D7E8772B80F8DB -:103FC000E667923C1CC0BAA21C143BC0BDD896D870 -:103FD00063FD1280D28E3440D43CDB117BEE964DD3 -:103FE00000FDE979234011C02C9DEFC432800C8084 -:103FF000FBDCC07F0DC83410E08B1B38FF742BCC6A -:10400000F3E3FA608E64C7CF37DD33D92B63FF50FB -:1040100059E0F3AD889A6DE9C867B7B9B77890FEF3 -:1040200017E52E13C126A40238CD51482DA4F94D11 -:104030006C7E0095C9F36572F7D7F6F9AE080DED01 -:1040400038FEDD5B6F8D2828D7DEE5A3478B726CC9 -:10405000BDF1B285F195A5E1D831005DBBACA14DB4 -:104060002837E07C02F27FB46B58682D6EED18742F -:104070005D05A4D59D2932EDAB6E770AE3AF4B7693 -:104080008504ECAF7376E5FB519E923D4961188142 -:10409000EBEC493203AEFB59CEFDE3E5227A3E74E8 -:1040A0008AE044A1775ACD807C2BB39509A4B7BE92 -:1040B000E4D7E54B6CF5FD97960BAACB0530B3C45E -:1040C000A19AB05D7C25076034C043AB67B0F6F5BC -:1040D00060262A1960EA957200DC5BCD953BD9F326 -:1040E000DA2B298C9EF9DD4829ED075E17600BCA93 -:1040F0005F36F85B2B01E5EB4C86E13B705F9DDEA4 -:104100002C5F137657B7CE60FC65BF9C369DF65585 -:10411000BB0399695C8110CA233D9DB09B48FE8713 -:104120006D5CFC8FEBFF3C46C6F11F8F718C046405 -:10413000DD27B63F395E60F6EC247B4EFEC53FB707 -:10414000FF0FF249574450501EEB1581B57F940381 -:10415000D5A427E40340BEEA6D03C704EC5F054F16 -:10416000BF9664C4A3547D49223C59B12D89EB9F6D -:10417000A7E124518F4BBAF1F4D5FC609EC6FF65D0 -:10418000786AFECFE3A9B90F3CB5FC3B78BA8E1D27 -:104190007DE089E16CE6218E0FC871F8B600C30B93 -:1041A00093BBD392156A42BE7BC9AE84AF6B504FAE -:1041B000FA9C47F64D8BE1F5979EC0CF494EDDCE78 -:1041C0009DC96AE192C2AF62E7BB81E2C6BDE9F573 -:1041D000A0E0F379D8C6C70D2BD9AFB0E7FE5EF9E2 -:1041E0009AF16EE357B4F31EB233E1C78D761CC368 -:1041F000EC27935D13ED4E7625BBD7EDB66EBA9ED8 -:104200005D87E7067E477A49B42BB8934D7073BC3F -:104210005DAC77126E3E0E9B81FCAB2FBB4A1BB888 -:10422000DE75BA256C9E1E62E701A4950F6778398A -:10423000F4EFE0A5ACA4FDEFB67E0067E4257E3385 -:10424000F2CF29C6AE41D4BFB45531537CC17F8E65 -:1042500067332A6063FAD4E8872353508E994F76E8 -:10426000F7ABD43F75A24B1B0F0A6EAB9BFFB45C40 -:104270001F59C7E46EE5FA0E44CDFEE171F418A4AF -:104280001D71747102BD91F3D339E266F384D87362 -:10429000C29F308A687D3ECD0FA0ABB41FDA6FD6C7 -:1042A0000EC1BD16ED7DCFC48F2C649FB292E88104 -:1042B000C1B8DFABF2637E7B123EA73888F2DA3DED -:1042C0002B5B55B3361EF558ADA9D1DA2E2822DA6C -:1042D000A9BA5808793D3DF568F7E8B8D4D7C5A321 -:1042E000D5381E2C63BEDE78C2091BEF65E3C3D64A -:1042F000AFB1FE5D134109F512270779B43879157E -:10430000697D7ED4DD9DB8BF502FFEE6D5E68D9841 -:104310004C3580FAFA86E7E9565B16DA17383E0A1A -:104320003D3FF4AB1C87A024ECF77AF2BA3DC6F30C -:104330009F7EB2717CF87AFACAE8315EC3C7222345 -:104340005E5C66FFFE8F510E57BAE056D1FEB5FE99 -:10435000A475E022FBEBF80EF99521B8BF24E8C65E -:10436000AB11DF6DFE29A8975AD0FB7FDA4AF1CA5C -:104370006FEAE6E778DF29748F2F40FCB8808F2F33 -:10438000F56C6A550B993D583FA3CDD7C17B7B0295 -:104390003D31C13F347C33FFA4B88DFAC9EB256EA3 -:1043A000DCAFD9ED82007329EE4526F37C2FE2E5E0 -:1043B0006D9387E7770F697A7C586B23C9717A18F8 -:1043C00012B333FEC25060D837D3D3DDE9DABED59D -:1043D000BDFEDB715F9154182E204EBED3B6ABB537 -:1043E000F996D8F860DB5E8693EEF9D43D113ADF9A -:1043F000EFD6F4D4D4168E683812C8EF6A1820109D -:10440000073B0455C47DD6100E7AD967594FBF516A -:1044100013C62BD275C6DFD973BC92301EA4F4AF7D -:10442000335EB3D3ED09769C9E60C7290974854E2F -:10443000870CF14C8F73551DEB5B32508E87B60A9B -:10444000744C50BCB608230136780EF9EDE308AF82 -:10445000B2341863FE46CFEF23B66100E514CF18DF -:104460007EDF695572514EF27746BFEB576E22FCE4 -:10447000D4B76422FF264FA4D586ACF734AF972873 -:10448000A779C1F3C75633CE7BF7985F1EA0F9CC4E -:10449000C2FB91DB3DD7C16B6BC23E3626D06A02B0 -:1044A000FF535F12DF9B13C6AF48E85F97406F482A -:1044B000A0571BC757CE17989F54A2FD48715FE6BF -:1044C000373B3DDDF942F77926D8599E64C0FDCCD3 -:1044D000264E1FF07CE85F6D8FA3DB8EFBC9DF7576 -:1044E0001C4BC07FF7A6834AE787D4473CDBD11734 -:1044F0008E0A12CF3BDEFF37FAE740CA3BC1702E6F -:10450000EF138DF45E51F7B74B91470AE9A14E774F -:10451000F90348CF7CC6B82FAC0BB5FE8BFE29E85B -:10452000FF33BFAFF75FF453DCD3F7A9F3977E7E79 -:104530004DA4F58EB45DF06FC6FE8AC9E1BC7A94D5 -:10454000B32295B778CE88748ED5D9B83F95EE1240 -:10455000FD74CE542487F39616C6ED13DAF3699FE3 -:104560007B978BCC3E6A13AF47AAC067012C85F6B8 -:10457000BA5C0D2F20FFBEE562039D6BC71AD232D5 -:10458000A89E18EEE579DB3ED70D190F20BD3765E3 -:104590009E4546BEBD8F4F65ED9BA2B2AA0B71FC36 -:1045A0007F9ECFFDF661D4EF62FAF947DB157F23DA -:1045B000FAC5671E99E93390EACEE8A07C75AD0490 -:1045C0005B6492C7F73CC3CDF7AC23D7A21C958D93 -:1045D000376650FE56F5C3F2D281C857D522F9048A -:1045E000C6072348EEC0DAA916EA9FDFACB5EA3465 -:1045F000D6EEF962FBA111C8DFB546F46D42E6DDE7 -:1046000057BCCE2A94EB78128FC31F9ECF75929C15 -:10461000EBBD01C98B72543A1DC9021D1E6ED939FA -:104620001BE77D2247B1788B62FC7BBE10E751BE51 -:10463000F9C6F9AA0CB29FDBCBF1BAFB4A55465535 -:10464000DC79BFE08299E9798F457E84F2CB3DC960 -:1046500059822A303DA795A3BFCCD7F26BC44BC378 -:10466000F65ECEFDCF3D22D3CB096B031C4710EF86 -:10467000FD6EFF8924A73EAEE8FD409383F03C44E5 -:104680001E159F47F7CB9E3C84F611C359DA1F08CD -:10469000372C8F467AA8D7BD5E455CC13ECCFF491A -:1046A0008E74A594CE0158810C18C720B33D3FFEEF -:1046B0003E2296A7AED4E201E73BAA3A58DD7AF44F -:1046C000A5A410D53347D5BF3AC01ECFCFFD64A1F6 -:1046D000D3A1D2617CCAE130935E8F998327BF8DCD -:1046E000E3163C27B138BAE0B9FE2BBA281EA03D2C -:1046F000F3A0E7BAAA5762F3F4E927E02937F8896B -:104700002A972BF6BEFD6492572EBF9E9F2CD4F2A3 -:10471000F6D2E7243FE17C6191C30C18AF273FF745 -:10472000D616C2E3C22549A3AC28F8C2E7ACCCBE7A -:1047300051874375637FC0E930F7A3B8EEE5712474 -:10474000DA98C4EA1431C3C2E29EB8AA4826FD949E -:104750008860B6E1B9223A7DB29FD3CD6EACDB5A08 -:104760001CC532D9F73B5EEE0FDDFDAEB9B7095877 -:10477000D75CC67DA4E1B8330D4F3E3D16E53B0B3B -:10478000A1396351EF97C9D0B8CEE51D6248A57332 -:10479000C2AC98CB30EE2D02EEEF3507B75B26E1C9 -:1047A0003F17D52FBC9DEAA30743D28751ADF6B979 -:1047B00086FF7F026F5B28BF7D68ABF1397A8C85FD -:1047C000FCAAA6DDF8BC0ED65D1247506BFE305A2F -:1047D000A03DC7751B8EFC65F8FE38BE5AAF23FDA1 -:1047E0002496E0300A46A166719D42D75D04BB065F -:1047F00091C92BAE4C0A911EC56C7E3E4C03219490 -:10480000448070E3BE71DD4F838787EF4740888F18 -:104810008D667A3911443C0D457D386D8C5F7C4C3A -:104820000C5971DD923450FA913E9F2E0770307D05 -:10483000AA6EA4A7A5D79B293E9DD3E24BA500FE57 -:1048400076E6F7BE6CAA8F173C97C4ECB7F0F90771 -:10485000FFFB4763C85E65E9F17EB446C31DCE0722 -:10486000B6D4D83CA71ABF934DF294FC04EB4AAAE5 -:1048700037C5C0D377B37899E26371CB1DFDDE589D -:10488000C24963CAC8B540381998ED2D8C8D5FB800 -:1048900072793E1F8FF5AA93E25512DB4FF50E2B6E -:1048A000C349E51A5161E76396859D8F1F3627310D -:1048B000BA7A4831F3B34A1304681F980B66B2B84A -:1048C000CE550ED57650B6DB29CEAF8B884E661FFF -:1048D00055B39B85ECB3D99BC6FC771EE918CFADC9 -:1048E000FD84B322361FBF7FDA2D84B6B0F8542F73 -:1048F00093FF57980416E712FDF1352FCF5B2BB3CA -:104900007DF7D1B89A27ACBE951E2E83A8CB8378AD -:10491000AA314516FC98E6FD9595DD6BD4E13E92F3 -:104920009CACBE50B6A1FC7566305BE85E4AE6F111 -:104930004C97A74E2E9F4638C5FEC366ECAF71F06C -:10494000785CD38FDFF780C316DA12BF1EC99CC311 -:10495000C7C94EF2B3710C2FE4F726ECFF08787F3D -:1049600089B3588EE2F34E13ACA67B129267D888B7 -:10497000B875911E3882F0B8C4EC75901DD2E6CCA3 -:10498000A5F55E16595C42677AA298F2BF97C5D129 -:1049900054C756AED957BA81E85747BA4984CA575F -:1049A000DE63E7D3431ACEA294F7D37985F4ABD86C -:1049B0001ED5E24240E4F73847498FFD637AD5FBC4 -:1049C0006BD648CC1E352D1C0F358D7F66F3D6383F -:1049D0002219648F9AD7A49B09D72735B9AB1AB38C -:1049E000261E467C54492EB7808FAAD5320BD1D5CE -:1049F000AD02A3F5F56AD6FC29C354C8E7A3D6AA2D -:104A0000E128366FFF6C3ACFCEBD94965D1967F7FB -:104A100073CDAF3B653BF94D38CF4DF7304B927CB2 -:104A20009B989F727B9C6BCEDB44F734F3DD118740 -:104A300080FDF31FC949A573EE983B6CA1FE63EDA1 -:104A40001E13D18ADB3D9168C57C13A3CF61086F2B -:104A50002FD4C08B76AA15386EAA5FDA67F1E27A96 -:104A600029395C3F175E7E2F9FEE0B6AB223F974E3 -:104A7000FE22AEF207935D5E14589E50FB92A8246E -:104A80008D88E1AA967085FEBF58C355ED8ED71F5D -:104A9000253FAD253C8DEA894BAC2BF7B3E7DBDA3C -:104AA0004A818FDF4FB8D3CF7BA49B25BA57B36819 -:104AB00034AE43B43D87EB1FFBA7F07EB5909D233A -:104AC00010B5503E5C27F23C01FD2993F288BA0EE6 -:104AD00049ED8E97B42EF517C6FAFBC2CDF01C93A4 -:104AE00066672B3B8F86E770FF8BAE79CD49B8B8F0 -:104AF000F0F2BE03E3A9BEDA26B829DEF7F0434D93 -:104B00006F75A42727DB27CB8BEA482FCE989EBA58 -:104B1000FD4DC3451D703DE87AA9336B7AD2FBB5D4 -:104B2000F123343D5483A6D71D43B9BF6BFEAD9F1F -:104B300023FAFE02A97CBC8EAF79DAFE266A6D35B7 -:104B4000E2C657C8F0A5586ED6EA7EECBAF06A1BEA -:104B5000BB37D2EDA9CBFDA8B63EC669A55F6ACC2E -:104B6000CE51132CEAED9E7AB6862BC9CEE3CA0746 -:104B70008D83EF6B40FD2D7E49F431E551CD15B7A6 -:104B8000AED51475B0BCF431D14DFB2AF945F96DA1 -:104B9000B46F1D77D256C1DC3186EA8C7E4CFFBAE9 -:104BA0007C2503FCB7F5E3B80B933CBA9C1F086166 -:104BB000662FF555C1CDF3DCA885EE0F753F4D94FA -:104BC000779E666FD1298C176E22797C32F937E097 -:104BD00039C8E4B11F5ECED6538F2EF78C88AD73E3 -:104BE0004C759889EF18F038A0E3F203ED3EE283AC -:104BF00096D7591EACAFB34CD34BDC3A8186F49EAA -:104C0000EBE8FC351ABFEE179DA91CFF25CD7F668A -:104C10007C7A9CA51FDDC3E9FAD4F516E79706FD5B -:104C2000E8FEA5FB936ED77FD5AF60457F96AF3E7C -:104C3000AEED9BF94846EC5C207CD27967B5202E1E -:104C4000ED867393E535D3865CB2047A79AEEB29B1 -:104C5000F179AC9E726793FEA7D9334D94074073E8 -:104C6000E6FEDCB8BCEC38DD77513CED0FFC7D0690 -:104C70008694F8F35CCFD7F4F31A7FEBBA7189E32B -:104C8000EBD29533D4BF68CC927CCA232EE578D979 -:104C9000BA67A1DD3209E7AB3E1D2975CAB17AE5D5 -:104CA00096BF874517DD07EEF018EA85EAF3FB9912 -:104CB0007FD7406415D5B7956BDE2B1B4B76FF393C -:104CC000E6E3C837BFD5C3CEBD339BEF1F4DA56C00 -:104CD000654B1EA31FDCF200A7D7F07CAEB2A5E89F -:104CE00005BA8F3F9EA49412BEBBD60B6EAAB72600 -:104CF0006C295A710FF64F70DCD08FE43EBAF97808 -:104D0000D978AA1B1A44E62FCAE627E750BFD2215A -:104D1000FA68ABF3C1BDE21EC2B7D9C5FCED987607 -:104D20004E34491C676F6B71627F0E3F2FF76B38F3 -:104D30002C696ACA37D1BA6D783EE1FE2B2C727BA2 -:104D400098EABE5D037C9B485F58A666228E4E0B98 -:104D50003CFF5E64011BE1EAA0145946F21F5CE6C9 -:104D600018D9480288576FAEE2753A8B2F5837B181 -:104D700075757DE9EB1FD2D6D5E7D1C775523E4593 -:104D8000E78726EF99E69FCFA13CE1CCD6BC5488BB -:104D9000D3FB19DA17EAFB418C8BDB7AA9FF0EE70C -:104DA000E8F7AB21D62ED2EE0D0F4AAD43E8FD2D2C -:104DB000E6F127E2F3F2536D4936C223E6F1C6E786 -:104DC000123F4F308F373C47BF3961CCF7B5FA4EB1 -:104DD000AC70057A89437A9B98E79FCBB1A79FBCBB -:104DE000117AE4F9BADF258ED7F3FAEE7B9623F633 -:104DF00084F731635D709DF5CF07D13058FBFD948A -:104E00007C17C74F49F97C7B84EAC956ABDB8AFA29 -:104E10003D417E45EF015F13799E68035F18717114 -:104E2000E24FA37DE4870B8E70BF5BD02E84E81524 -:104E3000FBFEF58F8BC4FFC0460106087175D65383 -:104E4000EBE790DB5DF605560D44FECB5B059FCA94 -:104E50002454EC09F5D5818172DFF5D5BF5B57E9A4 -:104E6000F74C897A1F94ABD5573EF019F5CEEBF38A -:104E70003D089FE2513DF57E3E186075D4C5E022A5 -:104E8000D68E6B6F2B198CF27F247CF0C404F21F3A -:104E9000878BDD939C0FD6B39780173B465F9D852C -:104EA000FA79C3EE7253DCB8186C60CFBBF1A2E1A3 -:104EB000F3961D7BC5C1C0F8774E40FEDD7617BD69 -:104EC000D6E8E57D1BB72F40327F3FAAD5DB0F2FF9 -:104ED000193B809EEBFB3DFB6D6E675DFEB35BEFA8 -:104EE00077527EBAF7C7693BC7917D535C6E82D11A -:104EF000C20D220446633EBC81C7A1D336D70B74D2 -:104F00005F7A7AE39D19540F3E2075597C38AF6F54 -:104F100057B993EE41FED71C75BAA945FE30C96159 -:104F20000E8914FFC64F07F61E707CD80CB287BDE1 -:104F3000A267381977DE1C0A237D8EDE0FD2B97D79 -:104F40003599BFA7D7DEFB3DF06B7E9FD67D7FA254 -:104F5000DD234CD0F6FB5FB9A91CE7DAF39262FEC1 -:104F6000FCD4C6EDB368BE339B2537C97B71B3C48F -:104F7000E65F8C75BC0971781AF146F16BF1FBA202 -:104F80008F207D662BAF9317236EE9BEB86689A488 -:104F9000585C3DF158A2F3ED14587DADE372B112A7 -:104FA0002A657AD7F069C3FFAEE191D10FDA579144 -:104FB0003E1271FAAFD6FD35B9BDD7FD8938D0F5AF -:104FC000A5E321864F60B8D4ED9EDA3E72D26036FA -:104FD00040657A54274301E5054D162830130E4CE1 -:104FE000C93EF2F3069B7304DD337D9AC4DB474D63 -:104FF000EEB7A85EFED4244B02B6D15C0F1BFFA80F -:10500000E89B4AB4941E65F70362894931D179D788 -:105010006465F12231DEACC9E571382B8FC79B2D59 -:10502000B96E9E3F423DCB1FF416379845F949793A -:105030004AEA2732B23CBD79C66C33EEAF7C42EA15 -:10504000B21CCC2C9FDF7CC76C7AAF5B3E3AF53547 -:105050002FD2A1DC59BCFFA6D42209E9C646FFEC39 -:1050600029D8BF2B57792AB728B68E3E2F3E7F8688 -:105070009EFF7640E0D9DCFE749ED95753BCFF48B2 -:10508000E8AA358931FE3F0870EC0D21464725C856 -:10509000A67C7A4B2EB07DF4D59EC9557E9ADBCB8B -:1050A000F32A8016D26395FADBC394AFE1CF6F4346 -:1050B000BCDDA1E1ADCA660F132E60B574BE1B172F -:1050C0005E8A4B2E33F9F72CCDDC7798C37B69FCD5 -:1050D0003068769FB4B15470E3B5B4BEE33C3A2671 -:1050E0009CD4E7C3FD7D24E17ED1AE8282B6469793 -:1050F0001250C91518DF849DBFFD8CE66D52219AB0 -:10510000C4EC50E1A6F3488080E91AB63529880737 -:10511000D4D3D2D72EEC27F83FA8E75399FCFB8CC9 -:10512000651A1EEF8828CFB4A150A782909E8BB637 -:10513000BE006F5E34E3BA674C8183A4976AD3DB09 -:10514000D94B65F2DB2627E52F175E117DB7E3B853 -:105150006A2D6F87AB62F8567CDEE919B6696D1C63 -:105160008EFE98CBF394F39E70F6728A1F1E5E77C4 -:10517000C2D57DD9CB917FBA7746119D4B4F81F235 -:105180007E6EDCFBC559E6DEBFBFF8FD209E77C012 -:10519000667EBE5ACDA03A52590B4ED4C70C94A588 -:1051A0001869096991BD8F0F313B129F93F214F971 -:1051B000FE4CFEBE06FCE48FBA1D75FBF4B01B8AE4 -:1051C0004CF9B9C90612F9CB30D8E826FFD6ED372D -:1051D00055B4B378B3F4357E1FB7548836A711FDA4 -:1051E000329E97A42FCD2F7B9E9B5B2C648A451B00 -:1051F000EF67F1498F4B32FE47F8F94FDD4B0A79E3 -:105200000E9EAF8C849184AB2FCB77F4B884F6B12B -:10521000E57D1DFB908A70BF0BB5B5A78A15B299C5 -:10522000F4D2DFE6A3B8BCF4B91C76DEC1BA1FB075 -:10523000FB0F9D0F36A6317CAEF288CC8E651D83A8 -:1052400041C6470F760820E339777B471AA39D575D -:105250000632BAEC67032653FEDFFDDEF267431920 -:105260007DE685436302FC7EC54672F84197A3B094 -:105270009DF2A1CB769403EDE0B7AF66F7857EE8AB -:10528000AE63846B02D18812F2274552B95D6C8DF2 -:10529000CCAFB57D2D75733B2E3DC8CFDDA593F802 -:1052A000FB3DB33ACC4578903A450821FDCD836269 -:1052B0005118599BB4B86CCD34811C678F243919AF -:1052C000E4B8FA0D54254275D25C0D272905A9864C -:1052D000FEC785804472CDB52F60B871F80619E617 -:1052E0008B649776327D04787EABE309C4F36692D3 -:1052F000F3938902A4212EBE3917FBE3E695265EBF -:105300009A22B0D69817A35E4E5C0F4F33F3B4F3D6 -:105310006E180C63784AD00FFA07CB3F2FE3394E53 -:1053200069136617CF4C447A4EA7042199E59BCCAC -:105330007F2E2B29ECFEBE45D3938E3BFF50702869 -:1053400038AFABD8A8B77E8A516F69D38D7AEAEFB0 -:1053500037EA65C05CAFA17F60E01B86FEC18B466B -:1053600019E8ACFAF106FE1B1A261B688F7A9B819E -:105370003F67F56C039DD77A8F817FE8862A43FFCC -:10538000B0D06243FF8D5B971AE8E1ED8F19F86F9B -:10539000EA5869E81F195E6BE81FDDF903035D1425 -:1053A00079D6C03FF6F02643FFB8E88B86FE09A702 -:1053B000B719E85BBA7E63E0BFF5CA9B067A121C98 -:1053C00032F097D8DE33D053DD7F35F04FCB3C6ED3 -:1053D000E89F219F33F4CF2CF8D84097F9FE69E07D -:1053E000DF3828F02CC59FB9A6754755A0F82C7F4B -:1053F0007F22E2F9AE74B32F4C4C5FB36EDBA4C7CF -:10540000410DB79F80FD3E93F7CBE3E0E35A5E305A -:1054100055BC1DE8BEF772BBC070DDD7F9ECC27C8D -:10542000D71CB78F7E8A0D0BF0189D36DD6DA0FB63 -:10543000FB330DFC03E6CA86FE81810243FFE04593 -:105440003E039D555F6CE0BFA14131D01E75BA810E -:105450003F67B5DF40E7B5CE35F00FDD1030F40F14 -:105460000B2D32F4DFB8B5DE400F6F6F30F0DFD4B4 -:10547000A11AFA4786571BFA4777B61AE8A2C80658 -:1054800003FFD8C32143FFB8E85643FF84D3ED069A -:10549000FA96AE0E03FFAD57C2067A121C34F0978F -:1054A000D8FE60A0A7BAFF62E09F96F981A17F862F -:1054B0007CC6D05F7D0EE147F9F31B027BFF35B35D -:1054C000E092A15F4AC73C9DEEA721D9270A3DF390 -:1054D000743D7F2BF37D6658E751533DFB2EEE5311 -:1054E00013CFEB6CF9FC7E0BF3779B8DC5593CA178 -:1054F00086B3AB9646CA4F5DAAC07047A94605BBA6 -:105500002F4C67E72A3B1A65FA0E0DF31B24524D08 -:105510001E0FD50F29B13C74C8B5D15F3D0FCDC862 -:10552000078EFFFC404A7E11D563AF96527DF22074 -:10553000A8AB480E3C5F5DF49EE99D24E3BD91DE7F -:10554000CEB0A1FEE2D63B98D43A64D475FC768600 -:10555000ED3CE3EF9E57BB5712707F4BE3E67F02B3 -:10556000EB26339690AD41F42FF4D31F04DD8C7EEF -:105570002A98C9E8A783326B37040B58FB6CD0C755 -:10558000FA37068B19FD7C50617428389DB59B82D3 -:105590007EF67C73702EA35F080658BB35B888B5BD -:1055A0002F06EB59FF4BC10646BF125459DB1E5C58 -:1055B000CD9E6F0BB6327A477003A37F150CB1B640 -:1055C00023B895B5BF09B6B3FE9DC10E46EF0E8652 -:1055D000191D0E7632FACD6084D1FB8387197D20A8 -:1055E00018656D67F0346B7F17EC62FD6F07AF30A5 -:1055F000FABC76DF5F926F7CAFA6D30053181EF41F -:10560000BC7616D52D048E62E9A2A16E49A81F12A0 -:10561000ED71565B479A8CC736E53983F23735C54D -:10562000E5FB7768EB3D9E0C6A12C6BF462AE61181 -:105630008A8DA9106A62EF5779DEBD50C325A4F3A5 -:105640007C7B8126D742CD1F8A089F050C9F6F7FE8 -:105650009D3A49AF93834302F3F2B15D9C6552D901 -:105660003D813D944F79FFA621812AC2EDE5FA07DD -:105670000EB0F5DCBE7C5AA4CC1AEE7F17DDFF1C01 -:1056800014D97D695FEBD5697FBFD067FFEE3343E7 -:10569000E81C9AFE85C8EED3DF911C73E97EE49185 -:1056A0007CFE1EE3917C93A11D96E57F98E43C95DA -:1056B00057FFC2C3C852B124CF4579EB1D545AA33A -:1056C000DF97832CB1EF6341798B3E99FC262676D8 -:1056D00044DF052A6BB70F0EACA0F177630141746C -:1056E00060BC35BBB7FD24CAB34AB3D3AA7C93A12F -:1056F0002DCDF2B7D07C27F214833CCBB364EDEF11 -:1057000064BA9E27B9FEB1EBD2492127A66FFD5E90 -:1057100062D524EDFBA92582FE9E9AE78336D0F35D -:1057200041D65FB18CDFCF7C0BEB327A5F79448B53 -:105730008797EB25162F2B84641FE5D397EB970DE6 -:10574000A5FD24C6CD0A1C67C27115C0BF87A83845 -:1057500092C2F085F301BD77ABC0CC9DEABFDA2CD5 -:10576000FDDE236AEFCFE551E83DECBC9DD636AABD -:105770005311279B591C1B27AA16AC93DF3185F2C6 -:105780000591E1C322A0BC0BD3111FBDE4053A0E65 -:105790006AB5BF8FD19F23BE5EA1F92EFE7A6C0140 -:1057A0007B6FB27B9C4CFA6B32A13DE8BEE6772260 -:1057B000FF4E82AED8E93B0E57611BFBCE9F92088D -:1057C000B2D738077B1FB2578486577B899FEF6A11 -:1057D000387A27539A1E62F31ADFF3756A76ECD48F -:1057E000EC5BF6E6C1AC4771DEDA4E89D53B30267C -:1057F0005AE8EFE5FBA6BA86430373E3F651D7F107 -:1058000001FF2E0AA285F1DF439DD2D6D7F1245A9B -:105810001C81367BBC7CDDB87E47C3F549CAEB678B -:105820005965D75D38348AAA09631BF8899B7D576F -:10583000A77F5F371FFCAC5D8870201CFBD5F5ACE3 -:10584000FE5D0CEDEC796DF1FDD944D741D7944C58 -:10585000AA5F5637BE9589D2DDD9BA7E2ADD3FCF01 -:105860000E55BE456DF966E124D5DDE8177FA3F539 -:10587000A3427D0B95A4F7BC34A985EE796789DC3A -:105880000E7088DB0171A488A93DF7877E7052F302 -:105890000326BFEE07152B397EF4BFC7E8F68BE26F -:1058A00087FE3698DE7D98BBD8772175BBADA9847D -:1058B000AFC554798AF179A17E3EF3BCE021CC0BCF -:1058C00088EFACC4ED7FF66812FBBB97B302E263CE -:1058D000544FDCEB79E6A7267EEFF6A8885B14A987 -:1058E0005E7E92E969912D3482F484E7330C255C65 -:1058F0001F6F5F3592EEFB2687B2295F955EB4FA83 -:105900009A3C86380FD75262F7784F48FC5E2D518B -:10591000DE1E794BF181CF289FB05A40A5F749E8A8 -:10592000FFDCEF8F71F93F3505326F1679BEC2EAA1 -:10593000E8217E56FF4386CDB756E8B97EB3B66EF2 -:10594000E7E7BC9E56B3807D8F932887E0E6EB2681 -:10595000CA634DE672E8E74E4F79B81D74790A863E -:105960007AF8FD7DB6C2F6DD68EAC7E2D747626025 -:10597000E8503A2FB5FB31BD8EEDF49C62711DAE3F -:10598000360DE1DFF786FB3A4FCF77D7CFDED879F8 -:10599000A7DF33C1C4DEEF05FD36B744769B0D3E6D -:1059A00016F787C1115D3FEC9EE9FF019ECDEE1811 -:1059B000B0390000000000000000000000000000FE -:1059C0001F8B080000000000000B7BC4CEC0F0A3BA -:1059D0001E822538106C62711D0B03C30756D2F569 -:1059E000C17025507F0910E703711610A7027102DC -:1059F000104703711810BF069AFD0C881F02F11D95 -:105A000020BE0EC49780F82C109F40B277191B035C -:105A1000C35A36D2EDFF83E4E78940763910CF24AC -:105A2000231C46F1F0C0F23C0C0CDABC08FE3E5ED2 -:105A30005479051E047BB92065766D03EA0700E9F9 -:105A4000CD424A800300000000000000000000007A -:105A50001F8B080000000000000BD57D0B7854D58B -:105A6000B5F03E8F79253393C9839040C493970452 -:105A700009382421F2AA1E0842A4D406F42A5AAEF8 -:105A80000EC823869044B02DB7729B21092F411B6D -:105A9000152D5AB483458B0A36F268D106EEF028EC -:105AA000C65BB4D1A282D536D45B450B4944116F95 -:105AB000B5BF77ADB5F7C9CC393349406BFF7BC370 -:105AC000C7B7B3CFD967EFB5D75E6BEDF5DA3B76E5 -:105AD000D9C6E42B19FB027FA09CA330C60644CA9A -:105AE00051775EBB687B09FCFE99DDFFB8166967DC -:105AF00094173389B1D1F09E653056CAD8954EF8C7 -:105B000015DA95BD70EA0F97A531B69F29CC018FA4 -:105B1000C26A59EAB7A09FFD9F333FBE975F706787 -:105B200075B8F1BB2063E98C5DC1F877E16C2DCBD2 -:105B300057881526E373DD49BF433FB99BEAE0FB75 -:105B4000B39FBAE97B2B1C46C93E9759587CF34555 -:105B50000EF6AB7EDC5120EAD90C066702DE2C1A69 -:105B6000D780F7D0DBEF11BC075480578B33BE13BF -:105B7000E04F8BC0BF9F5D9BC40A39FC7A6904FE6D -:105B80000B8587E60F786EACD7BE9997CFD8BA7AD7 -:105B900046E5DA7A2795ABEB7DDFCCB331B6B23E82 -:105BA00083CA46153E01381AB7B0501050EF2E8404 -:105BB000F646FFF03F21CF69AA3BB37CA6BA3D0D64 -:105BC000FA2988D455B766AA37BA2739036E1C1F3D -:105BD000E6EEC0F19D5402984733001F978A79BAC8 -:105BE000B4E02C06EB91E7B66B2180E352F782E933 -:105BF0006C24B6CB27BCD9055E9764367420BC1FD5 -:105C0000433B06F31DE69EF23EF332F69FD94FF07A -:105C1000796C606C203C5FFDEF751D12F4B732D3D8 -:105C2000AE35407F4FC0F86B1C5178DCAAFEB9033B -:105C3000FA74C23FC4E3D08DBC1E9937D4A3E631B9 -:105C40008C45BDCF8EF473A1FDE6379BEBD67EF37A -:105C5000347D12D2ABD16F3EAB68F0B9FFF7F67B63 -:105C600029E03C3525D2AF314EBFFD023954C0B7D3 -:105C7000F91B59289C1D3B4E9EE62F0FC2FBBC8D85 -:105C80002A0B65F3E769C01779FC57D6E49B94109B -:105C9000288C8587458F93135997BC34FB1C19E8D2 -:105CA000292FE3FA4512D25573D4FAE63066F0CDC7 -:105CB0008FEA7D4C1FCAD8DDF505546EA9F7E9C8F7 -:105CC0002777FF5D99D55218CB8F7F11F2EA1E1B03 -:105CD00023FA0B3ECE428F4BD85FC5AC39505F3FA5 -:105CE0002ABDE82E8D885C4679E61274BC5ED26EC1 -:105CF000C8C1F6AF280CE5A0951FEEB6E9D3B0BF3A -:105D0000B5A364A901F19CC7F921CF1676E662BF5D -:105D1000CD39A382D88FFF55E287BCFC4B3405C632 -:105D20001D9627F861F4834E94873DF35F96AEE7A6 -:105D300015339664A103DF79D2816F42DF74F07569 -:105D4000F1C3D7475FCD7DD2D77AFF7DEF3BE0FD32 -:105D5000963CBBA664C7C295797138A3C21D4B6F30 -:105D6000797982CEFC7DD399B57CB03EC4DE011A30 -:105D7000BABF3E83E8EEDE7A8DCAB5488730EF07BA -:105D8000B0E958A8231DE2B8D71551BDD77D8BAD1A -:105D900020BA4C9FD5CC50FEDE8FF4390E875BA91C -:105DA000EB1360AE79A20E5BA40C7BC0BDF87E1035 -:105DB000D575DCCAEE928CF6CF0675C0778A683F3F -:105DC00075C5B3C146F8FD7E17AF5FBDA2530F6620 -:105DD000457D1F5CA7EB5991F6500F4F52A3FAC3B4 -:105DE000FE0BA3E13948ED8DFEE6AF38A10701BEF9 -:105DF0007B5DBCBFB52B8EFD53FA5F2B053240B5E2 -:105E000060AB2CFDACEDA9DFAB231E8C7172A45FDF -:105E1000E8C1E8F7C16774DD1D797FB9746F10DFE1 -:105E20006F64157912AC43E6F48A0C06EB6FAF6829 -:105E30000EE296DB039FC077647E0F12BCAE0CFEB1 -:105E40007EC48ADFEB8D51EB3369C5CB4184D7D05B -:105E5000731441AFF20B594B8F00BD2A49763FE9CD -:105E60001BD701D364C278B32A980670C969150C90 -:105E7000E58192A6BE1BCD0706FD019C6309CEC934 -:105E800015B37A8133180DA701477F701B70F44E4C -:105E9000A77C7C2B3D4DBA66CCEF26C0FE6D6FB75C -:105EA000F9515D48453C4157ECF35B8336789E3AA7 -:105EB0001370ADD1BACD62B9B1FDA64D1FC4425128 -:105EC000FBF73F7A5DF3B0CEF116885E5FA8CF9501 -:105ED0000644F03856B4B3D29F313F5BCCFCAE35AC -:105EE000CD8FA9818C0A4FFFF3BBD7E59F55E18E7B -:105EF0006DF75B49A2F1274D19F36DC6C7630E908C -:105F00005FC9385E5164BCE469301E76A636C71D91 -:105F10002F65328CE7FCFAF069E547035E7B0CBC29 -:105F2000B79AE05D6B03BE8DB3FE5F37BCE7CB7FF6 -:105F30002E90BFC47F797DF3DF3FBABF64FC153E6E -:105F4000F94865E12B015F775CE524FDDE9073FF86 -:105F50006C7CA5E2A7B07E77BC547CE24A192B404A -:105F6000D72322E3D74A1AED57BDD1776FF3810DBE -:105F7000D6D4CFFFAFF9F486D7AF5B0E9DAF7C6D63 -:105F8000783D81213FAD2C642107F4B1B2ED2AB2F6 -:105F900037571E291BC8A05FDB9AE14C8749256350 -:105FA000FFD0DF4A43CF985CD24FFF5CCF00FB4E5F -:105FB0006F02A56BB7B782F4A29512A3EFD783DE69 -:105FC00016023DA6E4950DCE3958F7EF70CEC1719B -:105FD0006D8CF4E992570EF9CA80CE5D23524629A2 -:105FE00040022B5DC6F3A3E5A8E7DE55289E7B782B -:105FF0007FF0BC02DB2788F6BDC1959007F044AD69 -:106000007FA2BD395011477FD76599F0F390D0BB7F -:10601000EE46BD0B047262424B00F56A57BA5D7BD7 -:106020004C8AFDEE265912F306BD0DEDEC115332EC -:1060300051CF3A30E389157684AF90915C77E5854E -:106040007419EAEE02CEDB0F59F67D37AE21E95D19 -:106050009952994ADF99EA77F7E831D913516FF3EA -:1060600016F0F7650D574C6C8C7ECFFC1371FF3525 -:10607000DE071A4AE97DA6B3E2D804183F13E468A4 -:1060800023E02B536D96EA685DD3E2EA8F1BE63B73 -:10609000678500860D331ECC9E1F673F81D534F186 -:1060A000E9A079663E7B48E0EF6E81CF4CE4F5D104 -:1060B000820E41BEB978D31EF9E61ACAE55B4241A9 -:1060C000F30AC4F7A079CC8FFAF686194F90DE6AEE -:1060D0008CE32A30CBB94CD53CAFAF6B3E1B99FE5D -:1060E0001D7974EFFD5BF96C230BDC8AED33C57E03 -:1060F0009E5010920285FDCFDF3ADFDEE6FD2DC413 -:10610000271FA74E1E103BCE3F0B2F996E18A7E4FA -:106110001F3F4EC23CB3BC3C5FBCC33E20E88C2951 -:10612000B81F58EDAB84129FC464AAB6A31D4EF2EB -:106130001BE0F6B0E6F24B80DE522B56DD2E83DDFF -:10614000EC79EBEAF7D1CE4EED9843F676536151F8 -:10615000DB246897E4F7CD984274CA08CF6BB1335B -:10616000E2BBAA1513615E8D8CF3DD66F996895C3E -:106170003FD069BDBF2B70062BAEA950477665395D -:10618000F1E66167613E6FE90B47ECF7BDCDDF16C5 -:10619000F94EF8FF9690DFB4BFEFD8743BF9118346 -:1061A000F00FEDD2644B3F49BA3DE2676488A7A87F -:1061B0003ABCFF6D0F5FDFFE4F19CFC7EE736A4029 -:1061C0000AB63CD987F67A12F325AB2867278342B3 -:1061D00000A2D897D61D94B5FED7A589B1F29642F4 -:1061E0004E7733A2F4DC0E99EBC969332767AF848D -:1061F0007ECF9670BF70AA0FFE17C5CE671DEC6BE1 -:10620000E1283FC7BAC2C7887F1B819E72802F8258 -:106210008532F9B7D7E6EDF045F3B5AC18FE6D2B36 -:106220007D304D2D15FA1FE047C99375D7C8AF4E85 -:106230001FCA97A48FC4E951DFB10B5FAF24E5C239 -:10624000E8E3AB8E67AC6B2C5F71FD246DE63C27F9 -:10625000EA3BAB326626C593B3BDAFEB7DB4AEA8C7 -:106260004F84E2F49FA64871FD39567D9EB1A5A6E4 -:10627000F5520696CEDADCD7BAA599F161F4EB5A5D -:10628000A668FF85C24BF5915FDC29FA5BABDD1791 -:10629000C4FDF32CEEED800FA5795418F53D96C79B -:1062A000FC8FF326A487B8343D443A24CADDD208D3 -:1062B0007CF62CD9349E9A9660C2379B05DA761408 -:1062C000FCAE657682C389E3C1388A0F3A94D0FF69 -:1062D000CFC22E2FF548FDE1505FE462FD4E131D45 -:1062E000ACCE2A8ABBDFA9625DD16CE5F47AE7F90E -:1062F000C917EB78D799E13DEFEFDCAAF66E1CFFEA -:1063000071EC772A7BD7C01720F1961E7AE7EBB4A1 -:10631000CAC6F64849200F32AE67010DEAF80A36C0 -:10632000EB35588E453A2CF2915EB05552114E62C3 -:10633000690DFF737DBE10955BE84F7606084F8AA6 -:106340005B67D45E3B3F7DFF9CD0AFD3843E6FBC88 -:10635000FFA162A77E5556C1D06E3EF7F6D40CEA77 -:10636000578747A51138ACFD162A811F2A0390ECE8 -:10637000383CF801FA09584701F9B5F305CECE3D8E -:10638000303389F5C15F0F59F8EB2189C3C92ACE93 -:10639000CFCE380763B6637B359040F1B29305C426 -:1063A00007B962FC27D6CF4DC0F19FD8D8379F1BC5 -:1063B00070FCB4DEC9C2A0A786EA7D541AEF43C2BE -:1063C000DFBF59D831C6F3738A4C70EC137CFF845D -:1063D000B32281FCE7076F9C360CF82BE7A8E24755 -:1063E0001D4F5BCB52FA1A3F3B68E637A6CCEE1343 -:1063F000DE656F4D9C71288A1F7FA178D2DE1D0E4D -:10640000BF5CCE2E47FAEBEFFB73F5FA8C43F95FD6 -:106410001D2F9B85FD79AEF1772B48CF095F49FC95 -:106420009923E448CE3C2E0F72AB594843FEFDFC45 -:106430000B164D1F6099109E32AB558DFC4D4C775D -:10644000CF81F743C5DB4C65BA8C5BF850D4BF50A5 -:106450008E6CE2FE73C3CF0FEB7E17CAB9CDAF29A6 -:10646000640BE7556A0DB8DE39EBCDFEFDC12CCAD1 -:10647000EF8EFE7AA1D7655AFCF85F751D3A701D44 -:1064800012FFF9EB105219D19D51D72456116FFF0D -:10649000FB44D0A9B6E210B743C0F87B272A1E01FF -:1064A000EB99829BC04F83F74D44BB35B886F9F317 -:1064B000E3C84B9B9A48746F637A7828FA0FE65CBE -:1064C000DFB117E5D50466925F71E4864DC5EFD262 -:1064D000B8DC080567F2F27385E265F9EB5908E369 -:1064E0005B9337D4ED47BF5E6635B79B33D7042542 -:1064F0003BD473EA981F87C9AD64BCFD6C16D27992 -:10650000BCE66806D0CD104137430C7A5966A69791 -:10651000C17596B8D01A737D20D2057C37D0422F32 -:10652000D67E723446F1B8BCF5328F17CD32C77DB6 -:10653000F259F7FB3F0778F30FB9FD61161B6FB2F5 -:10654000F6AFB24001E265F70FDDFF590013FCD949 -:10655000FA49A98817902749244F2AE2DB3D31F4F4 -:106560006AE81BBDB48FC84FDEAEB7F7ABF2D39766 -:10657000CE0538D67A7446E307B349AE2B225E794E -:1065800030F37A6707FA6DDC4524DFF7631DFD3CC5 -:1065900019970C8C96F78AF02319F546E147B28ECD -:1065A0003755E57AF07B4C9F8A7818E50864605C83 -:1065B000CF9691BE730E8C67F381BE15E7BBB16AAF -:1065C000029FAFA6FE2D1AFFB071FB481E32BE1F00 -:1065D0003377CA79E1A3440DDCA442199C04660414 -:1065E000D27F0E0B35E2FAD635F3FD2DD2EE16D161 -:1065F0002E8879053DED02D06E84A9DD3C9C0FB458 -:10660000D34DED2A62DADD26FA63A671F598716B37 -:10661000447FA4CFF5B4F3C7F4B754B4233DB0A777 -:106620009D16D3DF3231AE6E6AE78B69F7EF067CD9 -:10663000A6719979DC9EF7A576E33DF9630FE44FE7 -:10664000217A39943FA57C2E8CB3F4451B97115BBE -:10665000793E874157FB45BB26A4AB42CC5B6163C7 -:10666000AA294F85E7AD34BA673A0351CF7BE8CA10 -:106670003DD317FFF95C537B758D8BE9C5F49CDA2C -:1066800037FD5D11F1AA1F4C427FEBEA3459F8DB6C -:10669000AE69D05590630354537D4D86786FBBA689 -:1066A000810262223E02B2F29B8551FCDD33FE3F45 -:1066B0000B7EE13F8EC03FDB02FF6C33FCA2EECCD1 -:1066C000E4EFD595B327E17C0CFFF2D9A6E50D41A7 -:1066D000F7FFE6F95559E65765995F95697EF69596 -:1066E00055938279FF97E6B7CC32BF6596F92D3383 -:1066F000CDCFB972D905AD9FB5DDDDB66692B76B6A -:10670000F35F27FD7FAD88E326ACD41B56E07BE02A -:10671000ED76EA4F23F93E8AE99FA33CE8EFBB47B9 -:10672000548DE482D323935C60F9F6507E36876BF8 -:1067300026C885E7541F97DF02CED72CF50F2D759D -:10674000F8E56FB86FFA9861475AE47C3FFBDACA04 -:106750004CBE9FACF2F8E5E87D4D15B83938A094F1 -:10676000E44FA38FCB9FFD03843C4A837D8DFC4483 -:106770001924AF6C425EDD57CFF3D89A457E506343 -:106780005A11E1A759D80B2C9465DA370F4C9CD2DB -:10679000867EAB334779DEE23A1BD7C756D6339DA8 -:1067A000E8ABDE49F945FBA0DF003468057D0FCB7F -:1067B000E741DFC3724F7D0695BFACD7A8DC01E38C -:1067C00062F94CBD9F0560FC6DF563A8FC31EA8B56 -:1067D000503E20F4C52BD264F2576CAE872D339F08 -:1067E000F4482A1FA9F78D5561BC9FD46750FD233B -:1067F00069E6581BD9AD1D8D4900E7EE57F3285FB8 -:1068000069429A4AFB2F53C34A5249E4B981D78F50 -:10681000A44957E077E33264DECE196AF4C66F57B5 -:1068200086EDC664A8040F7307156F5ADC76E5364B -:10683000C04BA95BF4E70B347AE2F7F72D6C57E411 -:1068400016FDA5698DEEF8FDCDC47147FA381E58C6 -:1068500046474362FC763760BB429F986F56584E5E -:106860008C3FEE6C1C3725A53980F1AD2B6733D2F8 -:10687000476D69DA66292A3E141A50C164A0F39460 -:10688000D4E63A6CF78D809FE5C0F89AD7CF64A024 -:10689000679B1BDE17624E138F478DBF0EDEA33E34 -:1068A0008CEF4744BDC7EFA11C3B4B7C9F647EDF50 -:1068B000A397AF613D793C98BC646B32D79365CEAA -:1068C0009FCB571E98847C9F6CE7EF7F8A75D4B767 -:1068D0009633431EF1F609FCFD8F8CF65EFEFE1723 -:1068E000A27D4A0A9FB76B8A338471B147BE7B4948 -:1068F000E6DCC2C87C2FFA5EC1B0B951F37BE47B01 -:10690000E332E7BA23F3B9E8FB1386CDEDC3EE49D2 -:106910002D977B7264516E25371792FC1CE5A820D9 -:10692000B9336A60A98EFCACACE770FD87EDAE862A -:10693000863C822B88F2C680EB278BCD700DAE3162 -:10694000C3F5931A335C836BFB866B9D8DCBB5DEF1 -:10695000E083F1F5E8F11FFD37F3F8437E601EFF99 -:10696000D11F98C71F72E7571E3F1CBD2E9B6E3765 -:106970008F9FB5C43CFEA625E6F1B3967EB5F1FF28 -:1069800051FA78922D70C426F45D255AEFAC0B981D -:10699000F45368F78A681754A2F5D840C0A49F4200 -:1069A000BBD76D42DF35B5AB8869F707D11F338D93 -:1069B000ABC78CDB21FA0BCBD1FDF963FAFB8B68FB -:1069C0001794A3FBD362FAFBC080CFD4CE17D3AE0B -:1069D0004BB463A67199795CF82950A19FEFB30479 -:1069E0003FFA47964D5E4371AF812C20A1BFCF97F0 -:1069F000CA461D82EF592ECFBF4F9EB2EC62B43B08 -:106A0000D7249BFD5CE9766E9FD9EC0A95BE44566F -:106A100047F900CE60E68CA87C8B6A3BDFCF7ADE3C -:106A2000BB8399D746BD1F28BE5F23E2D469F6D247 -:106A300046942BBEC1D03E8EBF22538C6BBC67697F -:106A4000FE761DE0DDF8AF3347A3BF2832AE8DB729 -:106A5000BB588C9B151FAE35D97CDC45386E213E6A -:106A600037F48B6026E1D7C74BE3F9839EEF49FFEC -:106A70000578593DD9292B49F07E3DF76F1A7EF6EE -:106A8000647B9D13F3761B2F92D963D82EAB6F3F97 -:106A90004E53BDD9DFA9FA2A74B4F70655FA8A1401 -:106AA000D6FB770F97CBE5F1E20DA3C5BC9A2A2759 -:106AB00035E7C1F8EC90D96F0B84CDA2F3610A954C -:106AC000C0687B3CBF6D538129AF3E7950DF7EDBD0 -:106AD00046A15FF4CC033A8AB77E370AF8D8C602DB -:106AE000939E959C3293F4ABE486AB9DBE38DFADAC -:106AF000B5F4EF6233756C9798D6CC64EE5C34E9EC -:106B0000614DBEC7F83E94093209E33F693BC2C8F4 -:106B10003F674BF8790A3523149428CEC1E7896A78 -:106B200025FE24AAE1A00CED076D54593895B1FB60 -:106B3000E5C08D881F575E33F9C7549F2E219ECE26 -:106B4000D94257D379025017E3E57FCCB3733FF0B6 -:106B5000C3DACCDF65C759C7DBEC9A492F1DF4A90E -:106B60009D858B7B6F1F69C7E1EAA1D30CA04FE421 -:106B70006F8DD3E9ED8ABED84EFA5A968FFC8E8679 -:106B80007C35F85FC4B7E78E61E247BBE10F308F19 -:106B9000DBDA6C3CBFEF73681D15F7B94DF8BFE643 -:106BA0008A78F73C56E1C597A7995C8E7C759ABDAB -:106BB000EA2D8E5AAFB5763B1F678D8DFC5B463C48 -:106BC000777EB3CDE4EF5AB8D15C5FC066A6A35C14 -:106BD0005AB0C1C6F07CC76D167FD8BFE17C615E3C -:106BE0000B59DD2AD4D38DFCA0B93EA662FEF7E294 -:106BF0005F3D528A7943CD769EAFF301D08B16C5A7 -:106C00005755EE901DEDF97776155F3F9EE1F7A1A0 -:106C10005583509E26B3B8E78C6E5D6386AF3FF810 -:106C2000ADF032D640F0F60687BA558AEBBF7AD47B -:106C30002E99E244CB9CDE910CE4CC39172F7BFCDF -:106C4000297F74917CDF27E80836C0CBB89CAFBBA6 -:106C50001CCBFEBE3BD8CB778B9D1D76E48F5AB5FF -:106C6000AE5C92237126872DA00F86EF6C7B268663 -:106C7000073353BB35E7D9AE4DCA39AF76E5721F3E -:106C8000FD750A79F9C2B69FD9D1BF78FAA913D791 -:106C9000201F2EFAB5C29CD0AE739B8785715F50C2 -:106CA0004376942755BB94B871598AFCC3FC17FDF1 -:106CB000C24372A26A8723341DBEAFFAE53B231993 -:106CC000E0A1B3A1FBF060DC479F92787C34D8311F -:106CD00012F7AD2A95DD122F4FEC84A0BB53CF25C0 -:106CE000CEC27595B6EEBF99FA6DB9C1E688920F1E -:106CF000C7C4BE04EDB87FED4929941F477E18F143 -:106D0000AC534F4A1CBE3DB6900BE1DBBAD91E0016 -:106D1000386AB77E487454F68BED5EC443ED1EC5E9 -:106D2000E4F7ADDDAA841D23A93C8125C65124E0EA -:106D3000EB1AC6E563CDAEC5E40FAF6959F7A1E222 -:106D4000C5EFCDF40C78F18711AF6F28FEE958DF5D -:106D5000F973AF06A8FAA0FD712FE215FA9D634FF3 -:106D6000C278AED98F8DFD7F9A12DB1F63DD76A4CA -:106D7000AFDA96B57C3C0BBF7C80BF64C6C64F9C27 -:106D80000E4B1C6B6BEA79E9898BB69F7D3408E367 -:106D90009DDAF1D74783B87FFFBF8F1EBD13F59AE9 -:106DA0007D2E1FF27BED53AF7959D43E98E3E07C02 -:106DB000D7F9E4CF9F7818F8A4F3B8838EEE75EE78 -:106DC0007D6F8806F3ED7CF6BFD335687FC7DEABF9 -:106DD000C8EEBF6377D9C0BEF643A4D350F43917C9 -:106DE00091C7A4ED9150D902435E94967539B84B82 -:106DF000612E80F3F4314708F39A6BE1D9B2225C3B -:106E0000A7C5247FB1BE1CF05BB36DF587CAC878F7 -:106E1000780E0E9631C79E01BB64E03A5FFBED6FC2 -:106E2000946069A338492DEB26F969FDAEF628ACCC -:106E3000E765BDAFDF59F6B91D8378B5DBD6F271D2 -:106E40002DEB771A7F191BBB7EBA65FDCEB2EA9F88 -:106E50003E8C2F77A5C68DE71AF1AFC5BBFFA54FB6 -:106E6000BDC99003FDE1B752E270791C7A8503F940 -:106E700069C7D34F3C9CC6D7773A20A473FBD9216E -:106E80000CE8E3A4ADFB66948FDD7B1D3EDCCFAB4D -:106E9000F6BE41FCD5B9FB15BB46F291B925D0131E -:106EA0003A59CF4F3BEA0D3512AFD46EF1841DDE57 -:106EB000C83AD58466946B5E7A7E829E8738DDD729 -:106EC00084F65F27C559B7D58E1C2E8F433C696F5A -:106ED000F1963FD899DBBC9ED2185CC71353F0796A -:106EE0006FEB68CCDF87F3BF3C6A3DB7707EED8DFA -:106EF0002F3B373B54CC4730D6B7D3C6F5FDDA909D -:106F0000F4068BC3AFC6FE76A1F1D00687251E2AF4 -:106F1000E6DB1F3FF73F8F0BC3D3124CAA1C1D8B20 -:106F2000AF539FC797EF8F382401475DF9A0DCD896 -:106F3000FD496515C1C1D911784F8973B3A79E5218 -:106F4000424178BEAAE520C969AB5CA8E9454F7EFD -:106F5000C6186FCFFE9128BF4E1D788EE8B066DB55 -:106F6000093BDA4787B7EEB4771446E81EE57F742D -:106F70005EE4A967F68F24398DFDC7599F5F0B79B1 -:106F800057DB6AEEBF76DB87A6FE17055BECE417DE -:106F9000ED679C0F54FD069CEF07ED368679F71FD1 -:106FA000B428E5F1F49B90C366CA835AE5293D866F -:106FB0007E4525C5AEA1BC6B5AA1BF11A4738F3607 -:106FC0007EEE51D58F39802F1B93ED1ADAAB4D9E93 -:106FD000EB991625B79B2DF8F4A5F926625CCD3701 -:106FE000B9A224DA7E32E04FD66513FC7778CA075F -:106FF000E27909B4C3344C3250FDE45756BC53CA4D -:10700000713E8A4FF6B9E2EECFBC3FF4B721FDDB0B -:107010007C32D3A2E86B54D9F5C3D1D5A632CD9436 -:10702000BF7AEF641EC735E67FEF456C1303B97B6B -:10703000AFD4DD86F9ECC1AB795E201376BA17EDDB -:10704000F4EC587D8EE9BA86F287C40F6FCF7423B3 -:107050007F147EBE0FE0C898BF23FB4999FFBEA2F4 -:10706000533E8F1DC7CD45FB2944CF135998EA8A5B -:1070700093CB1F0FABA3E749ACA319CF30BDEDA84D -:10708000F8D401CFEF2B4F9138DC61CAD74816E313 -:10709000C88959997DF13F9BAC9E8AF6FB38D8266A -:1070A000B24BD0EDF8456A040F463E9CD1EFBDAE21 -:1070B0000912EE3738BFC178AE479C9FF7F5CC5721 -:1070C000A7FA00A36E19075BFA4AC5164BAC1890D5 -:1070D00054056F0D68263FC720D64265166BA73250 -:1070E000C5E9935482EF2DF24BC9ECCFEC8B440BE6 -:1070F0007CE7A18F9F93F5E301281B6DE2F9DB9EEE -:10710000D0E350DF90CC4CE783739D9CBF2F77CAB0 -:10711000865F26106D7735B26A9ABB2B8D1F63315F -:10712000BEBBDE1918EE8CA227C5DDCEF3BE84FDF2 -:107130006BD8EB5729CB29FEBE3A83DBD5BDADCF4B -:10714000CAFA0A935D6D2D9B0738E76C66043FF71A -:1071500053494E7E7E59679A2F9AFE605C67697428 -:107160003EA3AE937D2FDEDB607AF8D28178546245 -:10717000E96F06D2DF68A4BF0ED14937F9296E57EF -:107180000257E37C33F2EA24FE3C2071BF97AEE065 -:107190007CD345FF72627566A08F79B259401F514A -:1071A000792D1B84FDA8AA4C4D284278368975B7E5 -:1071B000D2A5393FD5D0D7DCA2E6107972BF2979A4 -:1071C00095CEA3A8696ECA4F719734DD8EE77C55C2 -:1071D00056E743F9E936F24FFC3C9FD0B08B5D0592 -:1071E000E63C4E87256FD526ECEF983C6EB1EFDE7E -:1071F000830FE2E8C3D67DF77667FC3C2436267E13 -:10720000BEA0A1879D2FDD5BEDC86A67FB611ADC1C -:10721000A7539EA52AFC0D13AFF3911FBC6B9BC413 -:10722000CFAD59E8A86B47D2489487C8BF78CF45FF -:10723000A2782E6DDBBF1FF5A6262FD3935348CE21 -:10724000694A2E9E971AE594A05CBCEBC3977F8D8C -:10725000FEF55685E1D6DCE536E2937A322E5622EB -:107260005B6F5ADF0B9D4F6C5C91F3DB129FC16F1C -:107270006EFAFECC3689CE4F296CF88FF1FC436D47 -:107280009B8D85E0FD19C6FB3FB389EB030B5F8443 -:1072900051F03CA8181FF7A5E8FD23B53C8169D142 -:1072A000793C41BD1DCFFFCF13F8185091627AFF92 -:1072B000D7B9E56DE49F09F07B0006CE1A64EA6F4A -:1072C00091B27C2825E1093F8606FF90FE8CF99F4C -:1072D000930376BE4F542485499F01FB17ED86909A -:1072E00044F94A567F47CD1E89F6A7DB607FC2F37B -:1072F00038B7852CF6A3258FCEC0B7952E0F3985CC -:107300007DE066EE5EF0EA0F97507C94F86AC98BD8 -:107310003C2F6CC976294479CC1D439318E159213F -:10732000BFD17BACEE41D83922F46BC19B23C38C17 -:10733000679766C673628119AF1EBF198F563C27C7 -:107340008DC931B55FA454DB89C8049E0BE01FE2F0 -:1073500019E420CDA306E611D662F159D97AEF2AB5 -:10736000F46FF48B470BFE4E59F07796B5EEE76F4E -:107370005985339D589BE69DA986897FACFC66E0C4 -:1073800029CBD73E919EF93DE42FCE109D48F3F8CE -:1073900077839C2D9C798AFCC46F467E7062CF7E79 -:1073A000F90EFB02CAA5330E9D98CB62F96B1396BA -:1073B000C0D72DF54EDFBC7C8C4F33DF3C1BC6ABFA -:1073C0007D54C6D947A97FA047DA0FEEC1B8641A29 -:1073D000F2B54AF12B5CAAE9504F6CB5F9D06F7940 -:1073E0004F51F735A8B7D7CEE7798E372770FFEB27 -:1073F0009204BEBFDA12785EF35D1532D3D1BE6F50 -:10740000554212FA8B7CFA8B57A2DED56AD3685F9D -:10741000F375BFFC1D7A5FECC3F86EA6DC3C0AE195 -:1074200080F6E46FEF6A7DC77B6B94BED3B9E7FE4D -:1074300061B8EF3C24B3CA787A7CBE8BC3D159F0D3 -:10744000E77424C7C5CE6EB2A35777D455E0BC0C01 -:107450003BC2BE8BFBB76AF6CC207DF2D0027E1E0B -:1074600073F7297E1E738A32FB9B23A03EF6359567 -:10747000CB4DA64F9F93CE5328701D3760BE24F28C -:10748000C17FC9A106C24FF3EF314ED5F81795A1C0 -:10749000FE5852B780F69F5F7BA7B46159AAB71414 -:1074A000235F4F6E4D9E88E7646ADFE27995A3DB28 -:1074B000CDFE1CA6541F443FD8D9637C5BBEFC980C -:1074C0006AB5BB14DC8FC776989F8FEF876ECB5C55 -:1074D000623FF2B2F40BC98BFD91AC4F73917F9474 -:1074E0009FE3F2ABF1EDA74713B87D037891504EBF -:1074F0007575337F03E0A96BDE209A6FD7C7FC6AEE -:10750000A6AECF95F278F6D12D2E4E2F0FD979DC7D -:10751000F6A105EED00A98C781055517A35DF4C9F9 -:10752000BF052E8E17A788D8072C49A63D4F4F625E -:1075300063902F9AF8F932D69C19EFFCBCC10F0664 -:107540007F187C91B9202110CF7FF98E8BCF6FD21D -:107550008202CA83EDDC27518CA7B301E0EA038FD6 -:1075600041D63018E1A9DDF311F9179CADF1FDD03A -:10757000F5784803E9B621B8623CE0EB7BC0D44122 -:10758000E4077B7376BCFE836C03F99B16B834E288 -:10759000B74E27B7A399DA9C39D3837C5276F52A64 -:1075A00080F361E03F24F9876C7E823BB89831F22A -:1075B000AFAA9CFFB3AE619BEF8AB2B7D6BA263EA4 -:1075C000E082FE1E70F178476AC02F21DCFEBF9F6B -:1075D000F362FF5D9F3A68FD06093F8FF15D8BC046 -:1075E0004F5982FE23FC9E55A69130F407BCBE790C -:1075F000B0FF5FB607F01D27BFCBD077520220FB4C -:10760000009E14B74CE756D0DE427BA296193F414C -:10761000523E0DFEC34366783ECB90B752AB14F694 -:1076200080DC2C71BAC3E84F49A98479633C8A395C -:10763000797FED667D14252FCA5D94013C599EDB50 -:107640003B861C36E477533297834DF7AAA146094F -:10765000D3DF3B5CE83FCED6B549985A95A26A94F1 -:10766000E7705125F3075148E63E92DCA3F78C679B -:10767000ECD9BF2B71FD1B275DDC1E294B08FC0AD2 -:10768000F135B2ADFB00AA4F7E174BC5F59E22F433 -:107690009BB1A7B93C32F2FA6B85BD619547CF012A -:1076A0009DA3C018FB0DBEEF8D3DEDF623FDF4C884 -:1076B000A10553681F2D6A2D3E88F939456F717EEB -:1076C0006442FE80F54678296D0B2A880FABDCE911 -:1076D0004FDE18F2C4BACEA05CF7D4B30029C56D52 -:1076E000C06751FBB7554E1D7389FD55C8A9B36CD2 -:1076F000C2C0ABB4083D152DF31F7444D18F21A730 -:1077000022F414223AB48E2331674FDD978BF2E5D1 -:1077100088827E90AE893C3EB942F051F2C7A1AB5F -:1077200071FE1B5AA7BA90EE77B4953991AD966465 -:10773000F0735EEAFEEB824C904F745CD7C69C1AE5 -:107740009E291F0F2B8FF8507C508F9AD79966492E -:107750009C73D492AE8B733F82512EC9E0E7B8760A -:10776000B4E524713B334CEBDE43F7C20F61F08587 -:1077700041EF56FA36F8A19171BF84A13F28528B90 -:10778000B00BCD7E8146C3CF1174519CF80EA10F72 -:1077900036BA2F5937017E6D0A4FF2615CE20E4F07 -:1077A0000EE533DF3180E3CD8A07A3ACFD14F4C3CB -:1077B000A8BCF35AB59BFC5AB59FDA4DCF0DBCF669 -:1077C000860F03AFE310AFD297C7EBA7B8BEA36392 -:1077D000F1FB65E79DB5644CDCF372FF57E63D9E17 -:1077E000057EDD4176173FB761D097212F4A976E0E -:1077F000CC24E26837DFEB65C891317BEA0EA28AC0 -:1078000068951397B5B26B114F63C32AC3A32EFDBE -:10781000C98D8FF1974C3A7F716302F0DFA817662C -:107820002DDA068F466A2C753A0035B25D2539C6C9 -:10783000DACF2F0ED512FE381DFD8B865E1A8357C8 -:10784000A1971AFB8B11075A9710A8C4F1A53DC048 -:10785000375ECC3FE5F6EE5A57605102B44F0498BC -:107860001330D7AE209CCDED53335FF6C687891613 -:107870003E6B01BCD03904D8E7F2A558388CF1F33F -:107880001292399C406DA8BF6495323E580DBFCF0F -:107890002E6B240BE03E8CC736719E6B85FE759770 -:1078A000A55CEBAA68C079D9541674147D79B80D1B -:1078B000BFE0BA043D88F87096EB348FC13EE647CE -:1078C000BD7EB0DA22F9018E946A4DEA71D618FBBA -:1078D000379EFB99AE4D44BA189CC7E83CEC60D487 -:1078E00083E2ACCFA6041EAF5DECEC388C21F3DA5A -:1078F000E975E5DE3EE2D3917B06FCC24F65CEC35F -:10790000E8DAFBC64518977CFBDF3FF260DCE94F05 -:107910006AB707E13CB9FCF71EBCBFE5EDE5DCCE7C -:10792000B8D9A2CFEC14F84B4EAC780AF1774BFDE6 -:10793000DF4BA3F99D2DE37194DB420A1A9D3DF4C0 -:10794000BD686B22F9E68CFAE2965453DDA0D3C5EC -:107950000E9E27659DFFFBC28EBA6DDB66FB600D38 -:10796000C70FB422BE4F0A7DEDE42E0FF9330C7819 -:10797000E66E1B65473CFCA9D521E2F0ED368E7F13 -:107980007D3AC6CF026229AC701EDE9748FDCD7FDE -:107990004021FD620E8CB50CE83BD07A1BD9D9D6BC -:1079A00079CC7F5B9B3210D66FFE5A89F4526CBF44 -:1079B0001CE821B06C35C5D9ACF39C13B4C6339721 -:1079C000939D6ECDF398C7B47513B2E3E47BB4F224 -:1079D00038F9C27EEC9A3F26087DA1945D8EF9E8C5 -:1079E0006759E18F0AB5FEED9A93F58C92B43EA8E3 -:1079F000775279AADE47E553091A8F67EFD97F9846 -:107A0000E84B6D2F457EDFD1F64EE24D5A446E5F56 -:107A1000B1F9A3833F817A31E3FE1BC33F3E5BE0B4 -:107A2000FB4A21BF170A7DA0F8D3BEE5F76C9CEF97 -:107A3000C858780DB93D1BEF958DC28321C7ADF8AD -:107A400038D3969B887421255AE3C05F0D2FBD7DE6 -:107A5000B758899F3768F0CF53C21F306FCB8C5512 -:107A60008360FCC6BDEF0DE1F702B3A3281F0CFA3B -:107A7000B4D21F637576E4E71E3A6BBD9BF063D00A -:107A800005F05186883F66A0DD67A5B7FEF2893A0A -:107A90006D1D43500E58E9AB536271EF154D4DE427 -:107AA000FEF2799A3E05ED50D85E56F1381D973FAB -:107AB00027D5E6C377227F6EE1FCB1F857DB7F89DB -:107AC00072A7EA170F7851EEBCAF36A7E378D58FCF -:107AD000AFF4629CFBA41AF4E2F7EF8794B87985BF -:107AE0000B1325E10F37E72BB035C16B906F3F7952 -:107AF000DCE6433F43ED56078F83EFE278833A8F0E -:107B00007FEF8A9FAF50F5F307D2359EC76ACE5BF1 -:107B1000D862A3FC13F497E130BDC5717BE2C22D9E -:107B20007DC7B76B77AD8B9B7762E40758E9F606A4 -:107B30000BBD025EC88E09023CE4161771EBC62726 -:107B40007F3CF204C0756ACB6FBD5261B4DF9CC745 -:107B5000C7CFB4DCFA530CF1F446AF9D82BE237A52 -:107B600043286E1E43B52DEC453BBC7AB38DECBA71 -:107B7000EAED0A73623ECB7107EDDB8BB6FFE6F5EB -:107B80007100DFA2676D69D3F934285FC158A79EE1 -:107B90003C12B12E553B7FC3E3BD9AC82711EBB30E -:107BA000E8D9FD76CC8BB1E2B1AC65BFBDC3928F95 -:107BB00040EBD472620A9DCB7BF29C1DF7D3F7F7A2 -:107BC0004974BFB2F5FBCACDBFF1A27C403C515C09 -:107BD0005EAC57EFF942E16B9E2FA176E487EB6D27 -:107BE000FDC6E0DE3A9AE8FB99E761FCCA371D94CE -:107BF000AF54F9CC52CAEF794FADE374FEC8CA74E2 -:107C0000DC5F2B6DC1741F95FC79E5A3DF25FA5B62 -:107C1000F8CA77D3F9791E3D93FB6D829938BFF985 -:107C20009BFE85E6B7800588FE2A1F512AD05F7229 -:107C30005665E5CFC6E1933F093E79EF310706511E -:107C4000D97BC26F197C5511F7FE5AE349FCBE95EA -:107C5000B3C28EDE95281BF71439A3EDAADA2DAB3B -:107C6000DB717D3EB8481FE8A3B8BE1A14F89248ED -:107C70001F7FE5AA81428ED13D31869E5386CFB1CA -:107C80007DBB8DEE8B89FACE74DFCB1D627C803B91 -:107C900041BA0CCAF4F8FE4C8F5B32E0E3F92F06D0 -:107CA0007DF5C6F75B783EC9C747B95CC1BC187A99 -:107CB000DF6E0B0F34E5C3384CF78944F23D6C821C -:107CC000AFCDEF014ECA57E9C1EF3E89E2AC0B36AA -:107CD00038CC79703D7463BDE7C69CBFB2D0A26F4B -:107CE00019A5552EBC69910B6CD3F9E5AF54DB4255 -:107CF0009477547DDC41F643F5765B05E2E3AFDB38 -:107D00000EBE7E13D0F95F5B0CBE35CB572BDF5612 -:107D1000EE18CDE2F1ED5FDD7E16976FE1795CBE86 -:107D20007547E2111AFBFAE4EBC25EE4ABE28ED1D6 -:107D30000792302FF783A7165D4C7E060B5E0DB9B8 -:107D40006A95978F246AFCFE8298BC3ABE9F47F2E0 -:107D50001D39FE0C7AAC7A7A318DD343B7065D1AA1 -:107D600074DB4B9E96158FD6F72FA23C1A10EBCFE3 -:107D7000084E620578AF5EA39D15A0FF392827F84D -:107D80001FCF8E93D7C1EA86A29ED1E8CE8E9B9F4D -:107D9000EB77FBD08CC573654ABC78B7BF4C8EAB14 -:107DA000C797B8B95CD98BB40065B59BE3AD49C43E -:107DB00057C012A4BC7FF429123F257B899F6CF029 -:107DC0009CD1B94A3F9DDBF627CA1F69A08255B8EE -:107DD000B5292AFA538BE5A5B9505FE82EE6F5F1EF -:107DE000F2CE1CA8DFE62EE1F5CBE4621B90E61391 -:107DF0006CF494C950AF31E6392FC9E4DF50E51374 -:107E00000F62DC457D9EDF17B70EF8DA591489F74B -:107E1000263A58D05584F7344209F555D9BF5F85C5 -:107E200046E00647E01A37C9A3491AE2F594CF495C -:107E3000F932773C7715E56756BBB9DF78F8CEF1B4 -:107E400074FFEED730FECDEE01BD8FDF64E3FD9C05 -:107E5000DA31BC0CF13AFC62467E0803FF45AA46C3 -:107E6000CF5D2D78F494F83F03CF7F3426DBA99FB4 -:107E7000EA9EF53ABFB251E43528899C0E9424B9A4 -:107E8000EE5928978AF5BF43E0037FD05EEEDA3BD8 -:107E9000F0317EDF53F7105C5F4539F347D41BBBED -:107EA000FF35D18FE757DE4CE0F8BA2169BDED52BE -:107EB000A81739872C45A27E53DAF65D2CBFED0951 -:107EC000FC90E39F85B1BF9B6E56787FEE3A0FDE44 -:107ED0009F26E95C8F96806866031E1A75A6D97383 -:107EE0009145CDF9168A52D41DA6713DA671591639 -:107EF000EC83B04E378CE5EB0438A57DF18D31BCB9 -:107F00003E2B94D3D8A1111CF7201CA31CA18BD00D -:107F1000FEB909D4224ED766FBDB88D3D7FE4526AF -:107F20003BB356D21ADD50DFF91623B9DC99E015C0 -:107F3000F907FCDE19C32F31F6A5B965B864257BB6 -:107F400016F13C0EE18732E2E86759AB829389F182 -:107F5000535BE4E178B69EE4647FF1B19FBB457C5E -:107F60006C101B7481F1B167DCE7111FBBC86DE8B1 -:107F7000F322DE2EF6FF334772285F485531278FF4 -:107F800031BBA6508A88F1DD2E8BFC35E878C451D0 -:107F9000DFAD88971147D92DDC5EEA253FE224A3A7 -:107FA000BCE6511D05941F61B3E6471C9329E1A966 -:107FB000F4C5620DF1D924E2C6171AB737E2FEC53F -:107FC000FC514C1CFF796F39C5418B7DF1E3F8E31F -:107FD00094D914776047F8FA19717CA6142A08E737 -:107FE000D930D86008E751F3DF01B93C2DA8505AC9 -:107FF000CD5BE6E7E32C74605DEFBF58D7FB7CF305 -:1080000020DEE7F7AA8D6223290FC226F2207EC95F -:1080100002F747E7411878EC2FCFC49A5762CD2377 -:10802000C90C98F134B8F252D3FB8BEA8A4CF58B29 -:10803000978D33B5CF868D30BA9EBB669AA97D7E6B -:10804000F34C537DE8C69B4CED8785E69ADE0FDF47 -:108050005AD5E7BA8F6859627AAFC8A162BC0FD20D -:1080600058F7CBF6FC202E5D18EB6EE46961BA116F -:10807000E27734ACFBC3D9E43F2A93B4D8F5F78751 -:1080800083B42F5FE8FAE77B843E7481FC3E0A8963 -:108090000DE3443AD713BB6CEE35A81727036C28C1 -:1080A0006FADFA4572EB0BFF2D79E3E55B682B9022 -:1080B0008EBEAFE86371BF1F20F2239B64719E7474 -:1080C0009293F4817B64F996E87BE4AFF0703972A7 -:1080D0008587FB557E02FB26EE9383135990F64F5E -:1080E00071BE9CA1430AE6EB4D65E2FCF963AB2649 -:1080F0004FC078664781968C2205EADF88C8FD9BD1 -:108100001C5A23C60346295C8E837C9FE6198DFB8F -:10811000CE721BD77F8236C4F360270B7A8B68DF61 -:10812000A3B866324B939614A2E9D5B3BF685F003B -:10813000311CAC1A9E8476D0CB383406699D09B4C4 -:10814000FFDF68C8BDCA6124F7CEB87BEEB5A0F3E7 -:108150008E67E6E5D2F3E33703D701FF1CB79BED4B -:10816000A2FEFC53959BEFF7A0FFFF780133E519C2 -:10817000547BB81D55ED5178BC3CF49774444BD7F3 -:10818000FCCF2E41A06BA5F65528A2576FBCBD822F -:10819000F27677CD08A2FFCFF03B1BFDD4B64E643C -:1081A0003DF707433F37BCC1FD5F377C66F6E7DE2E -:1081B000E9E179D7778AF1AE87C20778BB1EEFF481 -:1081C000C6F2850953901FE0795882FAB7DB40F573 -:1081D00003BA9F11C8B6213CBF67FED7764B98AF54 -:1081E000ADD1F7D7B10A1BC2F5FACD8B3DD8AEA7FA -:1081F0003FA39FC178A613F6E9E4A02D1DE8A7FBD5 -:108200001B12EDEB309E139F57CC1EBC12B70E63B2 -:10821000BCD759E0F46BB0DE33999FFA35FA672C7E -:10822000C1240777542EFA536A0ECA3F99FC1F4B9C -:10823000F63A48FE75559DDBFE20BCBF6570C7450C -:10824000A85FBC59F5D92588971B372A4C83F50FB1 -:108250002504EEF344E1EDF8BC8F3CF81EF484C72E -:108260001FC44DFE69079DF37AB3EAE94BA2F5EA14 -:108270004D9E893FF6E03E39E6FCE23D654F0D2319 -:108280007BDBA0AFDB047D2D797228E9834B3CE6D4 -:108290007B53963C9E4BE7894A2516D78EC47B3F7D -:1082A000302F7D07D0159E23DCF729CF1FDF7924DF -:1082B000A598CEA3B2C07684CF68BFF3E59B865362 -:1082C0005EE7B1B4F3BB1719E00BA27EC5389C2F53 -:1082D00009FE98D59A5A2CF4BBE7106F37FDFAC9FE -:1082E000D37F40FCEC7DFAF13BB14DC9F9E18389C4 -:1082F0007DCC2FF000FB18D93F5D2CC1EF8863FFC8 -:108300003C2BF4AFEFCB3AD925E7E40A91BFCEED91 -:108310001045F667601E774BAB928878F3A2C16276 -:10832000C817D009BD78FFA2B83FDD09F6D9702182 -:108330007FDA3D1F4F69E27108935E5772A8CAA4A5 -:10834000CF55C03F94F7976F0A34E23D8DBDEA7573 -:108350006199ECE12FABDFBDF325E57DA787F37FC6 -:108360004B0197DF2DE18410B71B5831EA7BCFE03A -:108370005CE0FDB464BE2FD8A5CE0227FC7EC6F318 -:10838000C9AA3559B0DC791C1F58C7BFD3C3DA3826 -:108390009DF6E87F872EE57F674E9C032E11E7A2AE -:1083A00063EC49E02BBEC92698F4C7F0E1BFD13990 -:1083B00097ED29DAEFC6A33E0F7A0AF2BD4BEDB076 -:1083C00027C799DF2F517E027D8FF572FBC4B987D5 -:1083D000C7E19C9A4EF79EB97CBE51682F19ED4FAC -:1083E00089FD66F1E13787D8619D4ECB47BC1847C0 -:1083F000A8DEBDC38B66F2658981242FC64B8EBF74 -:108400005AEAA37CABCD43D0AE6D09F3F8C408950E -:1084100005D538F735D76E2CA64BBF6B36A652392B -:108420000CFD09F0A836CCE7D9B9A731259EBD5D72 -:10843000FB1F7B07E1BA3D3D809F971AD15ABC10C4 -:10844000E51FC2620339F7D4A7C3A9BF4BBCD93417 -:108450003F185FC5E7209164BCEFE86961AF757EA6 -:10846000AA503BA3DF117B262A3E58CBC270F301F2 -:10847000B20F5B1D1AAEB36B0BBF0FCED5EA22B99C -:1084800057BB6F2AB7E39279DC737B42F71FC5397C -:1084900036FABB042E5F334B81FEB7DBF9FE380C96 -:1084A0001860873BF2DC18CFD5FA634A6A77E6F1A9 -:1084B0007BF55C6A33FB863B1AEF1EC2FB542FA789 -:1084C000ABED096119F376BA81261F23B822703209 -:1084D0001AD7807318E9F3DBEDDDEFE2F94B3A5F71 -:1084E000A7211C1C4ED63A5443BDC2E5E3F15B976D -:1084F0004FF307A558B86A47829E0BFC764F038B53 -:10850000FC7D04CC634B88D49DC013DB739890072B -:10851000C3564FCE8AAE83401A13F97EF63DC35739 -:10852000374D203B27A8A05D0FA52705E7C9F737E2 -:10853000BCBF604011C703FA89139DFC7D4F7B27A8 -:10854000BFB24475F376FE245FE23489F5DC676AD6 -:10855000F89DEE90C2EF5E89FEADF081911AC05297 -:10856000FDC2F344B78BE4D6074768782E31B000DC -:10857000E9F5576FC90CEF47FAE049179D432E788C -:108580006E33F9ABADFDAD3ED6701FE665773D2786 -:10859000699807DA65EBA6B8514DEB7B745E71EA1A -:1085A0009E13746E4B490AD47947635EC48A32C401 -:1085B000DF58D6DC88FE3D908714A76FC9E0F2E350 -:1085C000CCD14B1E5B1185EF07BDC2BFDB1DB818B8 -:1085D000F9A655F0E73ED46FA0DC2DF4ACDDFB6FBF -:1085E000CC8D3E87156407C81FD6C00E517EA1F101 -:1085F000BC2BA4D239B0E1AF3B6FD1A3E8AD59F0A9 -:108600007BB3182F3F29B08AF876FF9FED5E0DF3FC -:10861000585B86A0DC6D013DACAF7CC65A0BDFF425 -:10862000E4B79CE4F771C3BA3625C13A3DFDFA9E22 -:108630004BF1EF8B00FC8CEEAB3AEE20B9B93B9BD3 -:10864000F3DF8AD73E198972EB93BD8B2E467C2DC2 -:10865000F3DA0C3A9F9480FCF42C233966F0632102 -:10866000F2A384F742713F4A21D239F29FBD7D1AAD -:10867000F1DF6E7E2F04D039D13DD0B90FF58B429A -:108680001FD03D7D3F94F8797BBBCCCF81831CCF3D -:10869000A7FA24CA57D9DE3ED947FC2C036A8B902F -:1086A0002FC307A89F16FADB75ACC4729FEB294C49 -:1086B000D21810918F7FF3703E6D29D092FC309FBD -:1086C000444531F141D43EC9EB621F957F74D3EA32 -:1086D0000DF8F7C3DAC5BE20F4AE7D42CF65C7B84A -:1086E000BC5F2AF6B225BF19F7ED6D30DF252F29C3 -:1086F0005CFE0B3A3920F4E043F51954C7FD428380 -:10870000751A0D25DE0754AAD7E19F2F6163CA9B16 -:108710000F6239AEA2A50C8F4C4D98D57E909F610B -:10872000D38723FDED3A70F570CADF3DEE6098A265 -:10873000B8EB6FDD7F7C0AF351F701FEE3EC4BE809 -:108740009F6514BFA9207AEC8D6EBAA48E6BC6FB10 -:10875000410FBCA77AAA0A1B7D0D1206E0E3F57B48 -:10876000AA56E3BD803725E9C7911E97FB02C79142 -:108770008FBA5EF95B3ACAF4DD47FFEC4579BFCBAF -:10878000AE0F473ADB9503F6401CFA3C2CE8A7A451 -:1087900097BC8ACFBCDC5EBA24C8D621FDD4EC528B -:1087A000E8EF169CDEA5E8780EFB5D3D908E7ACE54 -:1087B0004916BC7E3CEEEFC2AE9DCFD1CEE6A3DE25 -:1087C0003292EECB30D9994C592ED33DEFAD12F900 -:1087D000272A2D7A48356B5E3518F78DD6CD769CD5 -:1087E00047D516F3F7D5A8BF8CC4B26F7BF533AF6E -:1087F000D05F72592EEA2F403FE49FE87E4DF13F53 -:10880000C628BFA70DF37B9E96397E405E121F1AC5 -:108810007ACC569F7E1AF5CAD3824EB70B7BB47BB7 -:10882000BB44F9FDC3B6F2BCEB7127B5CD8CCF9F2D -:10883000F2C22A851C1CA7F2F8C5B8A3B9140F1DF3 -:10884000A333F2872C68954288C74A43AF13E729C0 -:1088500060DB25BD6E2C0B35E2FD720BB74A740E42 -:1088600063D156B3FFBE7AE32B87D13C5CDC62391F -:108870001F2FF0628D6FECC05FE2C4372E4E12FEE8 -:108880009C216C88E9BC55DBF99DB7FAAB387FFDBC -:10889000AAE8DF68372189D34D8D986F754809891B -:1088A000BF4FE9C6FCDB5B057DDC2AE8A39685EDBE -:1088B00098BFBF78039F2F5B6F33DD5BBC60D7ED44 -:1088C000741EC14A4795DB78DC0D1048F19DCA4DF6 -:1088D000E6F755021F55167CD404240B5C5CDF8E32 -:1088E00085ABE57A5CDFC5DB6CF4F739AC709D6570 -:1088F000B3298FE81F0D9F759DAE33D6E95276A937 -:10890000699DCAFBBE9F2062DF98F5DF670F5F4A53 -:10891000F92E67DA72C87F60D087B59F29427F9EA3 -:10892000BA91EB99A7F794258E40BBE888EA97A007 -:108930009FE2973EF6E2798FA2BD0AC3B860576BFB -:10894000F13A3CA7BDB32DEF5ABC8FA2E82595F6AE -:108950008DE2978AE85E90A2978A1273298F424B24 -:10896000457C403FB4EF761DC9FB7D21CACFB6C917 -:108970002588E615478A12513FD8C9B83F427AA9DF -:1089800024B5236A1F599CC4FD03AB32DEB907F539 -:10899000F7A9CFDAE8BCC9545BF7CB987FB0B34DE9 -:1089A000F5AF807AF54B731BF09E8AEA27253FAA24 -:1089B000D987DB97A47D07E9ACD5E67310BCDF3D12 -:1089C00080EF83DB247F3EB4AFDD7BD5F0ED98E70D -:1089D000BDB9D81F7D2EBB2859BB1FF32A5966226B -:1089E000D9DF532FB2D17E7A6A50E2CFE83E167DAE -:1089F000F31494B3A79EDF69A77383DB2596011355 -:108A0000399C71F019BADFE397AF50BE42D9AE5727 -:108A1000283FA137797F3AA4B030D9DDCD742FCC6F -:108A2000E2CD46BD83CE415408BDA966CB09AA5705 -:108A3000A1FE0FE3556D52421AFC7A70EFAF28BFCA -:108A4000A1661BCF6F80F7247FAA307EAA45E87C01 -:108A50002EE3743057C89F458CDF33B4A8999FA389 -:108A600033EE4532E87CFEB639948716936F86F66E -:108A700025C5219A89BE63EF1BE2F46DBD77C84A14 -:108A8000DF2D067D0F63C390BE3F99C8F3C33E79C7 -:108A90002521B110E6F3C98B0AE5DDF741E7B49F64 -:108AA0001E11FBFF99B04CFB93D1AE73CF47B48F2F -:108AB000D41E3963477D754AEB87B40ED35BF74FFD -:108AC000463C7F8B05AA116FDF6A4DF4219F4FEF63 -:108AD000E0726B5AAB23847EEA6FB196265CDFAE00 -:108AE0007D3F6F4A417A7982D38B21CF160A7C2E43 -:108AF00014F85CA8F2FB9EAA0AF73F88F9D0D318B5 -:108B00009737D35A84BCD964C66F97AD4525BA1937 -:108B100021B1E6ECD8FD6E11EBA0738F5D99C3E92E -:108B2000EF4906C15E453DAC7A9B350ECEEDFA1A93 -:108B3000CB7E7A30C9F6A5EEC178C7B22ED3BBF989 -:108B40007E360DE809E3216DE18642947B067EAC1A -:108B5000EBD2A6E526F575DEF965A1B71BF56F8B9F -:108B60007B265A7CCDEE683BBCDCC7F5F0AAB14A47 -:108B700010D7B5C75EC93B38529323F60AD8299F50 -:108B8000250DE076CB28E8FA852C85A5A545EC9542 -:108B9000D519F74F2F4AC3FB23B8BCE81C03FD616E -:108BA000BE80CA484ED56E7384D0CEF81F84BFB83D -:108BB000BB008000000000001F8B080000000000C8 -:108BC000000B8D576D6C53E7153EF7C31F8913FBE0 -:108BD0009A78662C34BB31F9202584DB109A40D773 -:108BE000F626A51D83141C58296AABE2B65BD90A88 -:108BF0004E5085281295B889A9D6956942DA7E54D7 -:108C0000EA56DD226D621BAB4C096A9892C8A1A19D -:108C100025E990A0401BD0D659FC60EB9490C0345D -:108C2000D24D95D873DE7B8D1D12B43A528EDFAFD4 -:108C3000F39EF39CE77DDED75D7DFFF29AF544DF7E -:108C4000EDBFEECDC2C6FBA54709B63A94F069DF89 -:108C500020EA20F2449A60FB242343B0ABAF7B139D -:108C6000254423558B4209CCBBA1EAF335B46FF1FF -:108C7000E7E1BCEDFA52212A23EA84D5CBF2FD9D2F -:108C80006AD6CBF33BFB25D386ED3DF99F8ACA52CA -:108C9000A2C981E98AE760576832FE71FFF796A89A -:108CA000D877EA928F6295D8D8322FD0FD442F9290 -:108CB000F3D9A611ED9987F6F04BEDD4800E697FBC -:108CC00039B5C0AF878C0CD6755E540C4B47FF0985 -:108CD0000F513351F7277F1A9E1721BAF6AE64F869 -:108CE0007467FDAB8D683F6FEF9F87F9377F27195A -:108CF00016A6BFF84DA287D0BFED4DCF95ACDFD9FA -:108D0000EB96F89FBEB217F39247FCFA1B687553B7 -:108D10004F39616E0FED1736493FBBAE04E1AF2FFF -:108D2000E5655CC82E581F23DA7E78A6BF24A9F912 -:108D300036F2DBF397D68EE182F1355A69E46A00A8 -:108D40005FEAA8EE96C2F1171F90B0FFE488A2F97F -:108D50002481DBDBDF2AC4E734C058C0FD4526216F -:108D6000CFC973257611E6FD731FC66A89C6F7C1A0 -:108D7000B90F7E5A148187BCD2B14B06DF8F713D8B -:108D800019FFC452A23F0CBE7F2FF30109883A6C31 -:108D90003F8C798B0BE24E23A88238119791C17ECC -:108DA0005D9F2A06DC735C35DE483EAEE36A3668BA -:108DB00014F0637A9FD9315C8D72492745BD64698F -:108DC00058D8DBBC39A1C4EDFA7C1BF96C35B1FE77 -:108DD000299717A44E45E388F3590D45043FBBFB83 -:108DE0009DFACA038EC5FE9B8971419BF79F35DEB4 -:108DF00066EDE0F19B9501B218B72FAD766EEF8E60 -:108E000029F406DABB3F79A9960AF6278E13F5ED09 -:108E1000F24C4599B75DE764115FD7B91BD12AB40D -:108E2000D7D23BAB35B4D7517A3F8F7F180BFC8834 -:108E3000796DF1BEF3F37EBE0829225EE27CE1CFBC -:108E4000A25F3A7EDD7C7B68A3C0A1C7E5D50B217C -:108E500059CC7F554BBCC2E770F2DC7FA3489B8E98 -:108E60005FB812E47AE5EA7DE7B9BB1D3776E0F535 -:108E7000375BF5F34F83078D23AA15429EC7C68A39 -:108E8000EC76C66560DBDFF672DD2EFB88CFC3EEC5 -:108E9000C16DB5C47E138965719CC39B833F5EC65B -:108EA0003890D423E2B2383EC435D17731AAA33FFB -:108EB000397031CAE3C9E32B7E6161FEF2338DEB79 -:108EC000B8FFD86955F0AFF14C93E0DFB13F37956B -:108ED0002DE2C0C908B0DFE4881A677C92234D1FD9 -:108EE000B7635EF24C5B93C4DB9C692A63FD592E29 -:108EF000513C8D7169A44AB473F9FC5C73F09B1CFE -:108F0000021FD02F51CCE10F55CDE0CF8EDE535E46 -:108F1000CE63479F6216F228B7EE90A60A3FBF6560 -:108F2000FE804FDD69C914FC38EAD81D7DC7447E38 -:108F3000DB3D6951EFEE231E67FC8F8E253A28D664 -:108F40005934CF623C3EE62ED461ADD75E480871FD -:108F5000B492B6A4E7D0C39AB024D68D5E4A7C9B67 -:108F6000F932DA9AA8D5EA67CFB3A84DE443928BD9 -:108F700077AF678D3D87BF2AF6873C8265B4353E63 -:108F8000C77838ECF067AD971273C5F379EE3C11F2 -:108F90001D90C18BF3ED1E8DF94F64962C80CEAEE3 -:108FA000777576D3E31ED3BB0CE3A49D2AC2F8FAEF -:108FB0009CDEB640CFA00B71FCB1BEC5DF8C873202 -:108FC00080B4C39CA9731B29EEA145F0B36666FF6C -:108FD00013AC970D6C55E1E76E3AF829EBE0127C83 -:108FE000A9A11AD641524A021278F3EFD31E4D11AD -:108FF000F1DA55AC0777E697D3990FA17F3AF4EFF2 -:1090000034F48F6D77DD670D59E0313A74E9DDB0E6 -:10901000D0CF228A3101BF8277E49DD4DCBDEFF04E -:10902000D77DFB7C7E7F06DF72F5998064A7EB67B6 -:10903000D7E786E6D421E91FF782ACD4453B5F979A -:109040009147BDE2F0CFE74998E5C8C3D3D79A2945 -:10905000673DAD838A22BF8947259B751E7156F8EF -:109060000A747E628124C6776F966C0B5F87EA3E36 -:1090700013F7763273D6CB7CAAE97DEE35716E2D6F -:10908000BA40D17C1D37F89DFBF276FD72F9F2A053 -:10909000CEF981CF428F23C2F27CBE1FD7BBF7E14E -:1090A000869699F5ABA5B38F95238E274DC9B0E76A -:1090B000AAFB96FB4EB1DC7DDDBA2F09272261E0C9 -:1090C0003179F6C6E6A5F0375AF7F70ABE473BEF07 -:1090D000C2DF0A97DF5D81600385A02EB57A2A0B77 -:1090E0003CDE2B4DDC13669D90BF0ADE4BBC3EFB85 -:1090F000F6CB12D78304DE773B2F55AEBFAAB0E67E -:10910000E874849633AF7EAF69CEB9F5D80B590FAA -:10911000A81E8F9995FF5F77BB4F7CD4C075B93679 -:1091200034D2E02DA8DFF8CB38F77C8F0C7C10D53B -:109130004B0AF925BBFC528595A48DEEFD38936F43 -:10914000E3CC37AEF7D10FD63FCD3CE9DD1491F437 -:1091500082FBF3F8F9607581DF897E45CC27355BAA -:10916000F34469619CAF893827D28E3FA26CCDA6AB -:10917000A585E32997B759C1DB9F2CDE19E7739CBE -:10918000E3AD4A0E6F3BFB3A48DC476EDE692FBE0B -:10919000202E6BD067FF06E3939EA98A70C1B9F8B1 -:1091A000A18B737346127C5C4996C27E9BE1F119D8 -:1091B0006EAB9451611FA08CE8275A48CCE3FB5D4D -:1091C0001E37AB9921A941CCB354F072159D15F30C -:1091D0001EA229614D82C0C3B691216C8B3FB38E14 -:1091E000E5A33E9D56984F99A81ABE0A3EB294CC6C -:1091F00055BF7CFE2A5DCDF11393F1B8D91A9F4378 -:10920000AF0FBAE7DCE0B71AD77982EC43E87A907F -:10921000B20A6FF2804A6B14E4F3A04AFE62C47B88 -:10922000745816E77730ABDBAC5F4699BBEE0BACFE -:1092300043BBD974CE295F35CF34E6F3BD138755D0 -:10924000F017E2792ABDEE113866C47E0F73E0C8CC -:10925000BB957495DBA970A5C3679A7A96F779A434 -:10926000DF27DE39B2DF1278FC34ECD433003C83E4 -:10927000F0B3EAA04463D8D758E4E49BF3BF0AAF45 -:10928000BE5023CF77EE31B4690CFD01BFB38E68B9 -:10929000B5C6784999A87C2BF0F5719D8C92883BD6 -:1092A000F8C2D4B5BDE2DDE6D30E2124A3FFA3317D -:1092B00009EF69C934690FC7E32FC9F0FB1AEC182D -:1092C0002F7C57FF3AFCFC5B7CDE255D13785182D6 -:1092D000747E67CCA75F697C6FC83CAFCC81EF1F01 -:1092E000C0EF4957EF2E173BBA71D8DEA8CBA8C7FD -:1092F0009688DFE07A34FA2B9613FC6E284D08BF6F -:1093000097A523D5C2896AAF60BF399E07C86C6133 -:109310009C25B75E7BFC8EBFE922C7F299643E07AD -:1093200020E77EC47500E7C28FB6D5E6D4DBFABC71 -:10933000C84E61BF69392EC8F88A62F805DF6389B3 -:10934000B16658B5CDD47796F0931D7904F279A41F -:10935000781FDCC7F4033C1041865D9A934FAA4402 -:109360005ECCBF9752546CE07144BB4A1D9EEDFA2F -:109370006B914D95B3E33BE94B9CE4FCA665636CB4 -:1093800054DCA33B9B59EF18A7EFE47092F3386DC0 -:10939000B163A9AC2E7019619DBECF67DF93C1BACE -:1093A000A77C7635C79FC303051224D55C9C73F850 -:1093B000685C3FE6B189FAE5EA1FCBE374A0D8C147 -:1093C000073FDF1C1C74D471E9ECFCFF0753B7A7FF -:1093D000EBB00E00000000000000000000000000E4 -:1093E0001F8B080000000000000B7BCBC7C0F0A360 -:1093F0001E81FDD0F8E8B89D17BF3CA9588601C171 -:10940000CEE7626008E160600805E2FD407C00880C -:10941000E53919182280381288A703F93380B8007B -:1094200088D3816A9B99191876B131301C04E213F4 -:10943000407C9E8D74FB3F88333054C820F8C78031 -:10944000EC2372D4F5E3281EBC38CF0095BF4E1331 -:1094500095BF4D9B81E13D929AF59AA499AF6CC856 -:10946000C0A002C4003A4CE95968030000000000A3 -:1094700000000000000000001F8B0800000000003A -:10948000000BED7D0B7854D5B9E8DA8FD9F39EEC5B -:10949000494218421E3B2140800487102250B0935D -:1094A00014142DB5113D2D7ABC3A8447906740AB1A -:1094B000E9114F3624840001068A3572224E103499 -:1094C0005AA841F1D1536C878716ADED8DD656DB86 -:1094D000FA88A8A0A89C5445A7E7D472D7FFAFB5D7 -:1094E00093BD273301DBDE73EFF7DD9B7E75F1EF74 -:1094F000F5FED7FF5AFFFAD71A45B411F9EB849C51 -:10950000873F9AE68A849021FD2921B2D6E3809490 -:10951000E8E7475860725EBA18F82FA3ADB0CEDB0B -:10952000FD1742B208F91ECFA37F21806770C018D3 -:109530008F9192A04262C5FDEDCC200CD644819C57 -:1095400017E0AB35DFE8A7DEE11B4FD208F9C2C94F -:1095500052BD8A6695D3F44D67B4B1801087101E52 -:10956000C1C65377497529A69742DA2890B95D9EFE -:1095700024E320EB08994493FDC34452D13FFEC439 -:109580007246DAD44048CCDE0FCB3209256BB78265 -:109590008E1FDA7D5F0857E0783C44067C281C1F4C -:1095A00036122484CEEB88FFF2C03C3AFED6694ADC -:1095B000D00E193B874165E233F038371F610787CA -:1095C0002B89C6F11D6B1941EB398322D944A1A621 -:1095D000822A07292164EB94CF03613A1EA71C213C -:1095E0002AA49EE4E3BB9A88BC9DBBC8C5CC3B7152 -:1095F0003D6458A349088A302F63BCDB6C745C99C6 -:10960000743D2689641F85B794CF4983F118F3729E -:10961000A4E8A719F03A9A90CD0D0E4C9B26CF499D -:1096200023508FF4CE85F5DD3A254BDC24F4973FAB -:1096300032E539470F9D6F23AFD7AA1D7540796377 -:109640009D13F1B695E32744041CF7E652D7DC6876 -:10965000C9C07184880FF3B73A692598879744F792 -:1096600015400B3D6DF329EC9BAC966DD206D2CB29 -:109670008C523918A3E3F4783C413BCDF704587D74 -:10968000C7EB4254C3FA21CF305ADE65ACFF64B158 -:109690001F9FF4FF3E524D08E5475F4EEF6BD08FA2 -:1096A000FD757B3044BFBBFFFCE96BF369BBE46D28 -:1096B00021B80FFA25AB2CEB45F632BCDA54FA6F21 -:1096C0009AEF9AB668364CC1FDE5E3D580B78D4573 -:1096D000AB5D6B61AD8AD9FAA9F47FE70B69FB9AA0 -:1096E00062E9DF665EDF02204D2BEC1E39E7DB23EB -:1096F000B4D4F4E1EEF19158062D2CDD88EB9DAA4F -:109700005CFDEB132E3B6EEAB78D78334FB9E93F22 -:109710002E2597229F5FA0FE170DC1CB8EDB70DE3A -:10972000A259DEA42ABF9ED3471F9D1550FA28C117 -:10973000F50C5C53DAFFFD25A00BE007BD12E51820 -:10974000F2229D6FF374D22BD1F5681AA968EB2829 -:109750001EECAA12137CACCF5EA02FF807AD6A2FC7 -:109760006AEE16C603F03D8B1C6C19FAAFC1D82007 -:10977000E34B5C87AF8ABF18E06F5C3FFEECA43A16 -:109780002D06EB5D1D40FC78F938364CBF5D8BD162 -:10979000F96CC8FE61E86D62C2E3A58CCFFAC6938E -:1097A0001325E6FE0DFEBA4408BD08F89194E06B5F -:1097B000618A0F325509EE4B322F596072A51FCFC7 -:1097C0000E99187802FA3DAC07AEF1E290AA1D2678 -:1097D0003CDB03CFFD19F0276792987B3C7E6F92AC -:1097E000D3A9FCCA24BA3B0D5B9101FE332940FE8C -:1097F000A4F9339432900B9707C3B49F661BEF4FC5 -:109800005D6B59D73FF375EDCFD703FF64C9B761DF -:109810007BCD5E2E37D4461CDF80FA7E563F71BE6C -:109820007F02393A09CAA99C7E1A03A06F1CC39A09 -:10983000671D01BC8FAEEB9A0F735409E2C190FF14 -:109840005401122847F5C39FA19E43AB46BCDB736E -:1098500042248C78B3EAD3947239418F0EA02795B5 -:10986000C2461B85F0DF1C15F98D24EA6F9E8672B7 -:109870002F4A0F3626F0156D2AA99E291598BC256A -:109880007A26CE5F36E880DB0736031D3B193FABF7 -:10989000BC5F05C643E5A19344B17137A57480BD93 -:1098A000A40EE173A1B298007423938D20E7EC21FC -:1098B00091E80503FBDFCAF549AA796C9D925C0F1C -:1098C000E40A4C0F489E3ABE1E37AAC067821E2685 -:1098D000E781DF4884EBBF20AEF786867AF20E9DE3 -:1098E0008CEBE89544A3F423E7D48542B49E04BCF2 -:1098F000484534F194B3540E6A66FAEA5B47B216EF -:10990000DBB351B4C03C6D1EC73C321E52F51A4C3D -:109910008BC72E04FEB0A55D5E0FA61CA59B4A0159 -:10992000FA7724A72BE2A14C3A0561AD3A697F7C16 -:10993000BD79B994F4D5471FC67C35A5DA3B906E46 -:109940005CE5AA00AC40C16E18CF503E9AA1E1E69A -:1099500055E27858B7C8AC51747D86F6CC43FDE427 -:109960007DFDCA0F605EEB4BCA4E8009971654AF5F -:10997000B99CAEA7AB980880EF8DD0D85468E1842D -:109980005E097A1DFE994DC8FF109E09E91E463EEC -:10999000567B53D464439E8883DA2FC279FBC0FA86 -:1099A00029E53331F10FEAF1D517672FDDC8FAD376 -:1099B000E9FF80EFFC09FA342D646A97007EACFD64 -:1099C0006C00BA41FCAEFA6FE94F253B1C1AD81D5A -:1099D00045A21AA57DA711D54F653171CD9009E833 -:1099E0001335A75787E5BDD0BAAC276416CA51CA4C -:1099F000B7663A6FE7722050D354D04CDB3D57EE38 -:109A000009821C184AC56646FAC0F96C4EB0B337D5 -:109A100097EC41F9D848E9A810ECFD1211EDA18DA1 -:109A2000458FA9667DF53343DE0CA00FA2C915282A -:109A30003A08A1F8918AC49073FCDF4F1F8976D24F -:109A4000C5D287FB46EB7A7CD5F5FA659FFD7D7123 -:109A5000F4F1F7F667AC6B2AB945D715EDEF166D43 -:109A6000CEA0F6CBC075DD81EBEA2A22A16472B8E4 -:109A70005B10ACFAC99C9AF507B9D5B25EB64BBF7C -:109A800033F78141F0619B6B9DAFD1AEB35ED2DE07 -:109A9000053B5656511F19FB878DDA0E1DECF973E5 -:109AA0003984D97B91553101ECA022827610342083 -:109AB00052D8A985A29B0446FFB02E867D63A3E6FB -:109AC00098B93F497559FB9FAB0BE6F13BEB151C71 -:109AD0008703FA03BEF4D00669BB520E8939D1FE62 -:109AE00064EB075DB17DFC9D17450706BD025A1961 -:109AF000BD5AEB3507CA48B2F51BD0DF75D6F1A6C3 -:109B0000944B89F53CB276CA648FA4AE2793532652 -:109B1000BB66789FFF4237ECB9A7056A173606BEC9 -:109B2000A3E3B8E13F54BFB6404AF59934AC8A8408 -:109B300035D0931AE3132D9DE9DF4EC1B20F37BE26 -:109B4000A71E07EB2FBE90D222C83559B3D8CB89B8 -:109B5000696343E06B32254A77FD0353E589D48876 -:109B60005D1B9A5B4DCB6F6CE89C0ADF8D723345B1 -:109B700063FF4DD5A6C93E96092DE7C0AFE4FC446E -:109B8000F8A812CDA4DF1DA40BF3E957BE7E04D7BD -:109B900001ED2ADA649DA861BB0A791ACB414350D2 -:109BA0008E4AF1A972316B0EE0CDB65008C7254739 -:109BB0001CAB29DF6D767258E3B09FC32A870B3840 -:109BC0004CF504C06E85C23475DA222AC22E0E17F7 -:109BD00070389DC37E0E177258D881F06685B5B770 -:109BE000498EB2F65D1CD6389CCE6195C3851C2685 -:109BF0007B58FF7606BB6C51D6BE9BC3051CCEE0DE -:109C0000B09FC323382CEC4138D5FAB98A3A199E53 -:109C1000FAE442573F8CCA83E3B50F8E25C08C5EB1 -:109C200032044687F16F19741344F9483C79C86FC0 -:109C3000E31C6CBD1BF797A15F82703F8AE9FB09AB -:109C4000D0C7E73AC5E060FCF5432E4F77829D4BC5 -:109C5000D3ED0D2AA6DB1A0268F76E69D0B85FA5AE -:109C600018BF6F6C0822BCA16132A6EB1B42F8BD85 -:109C7000B16116C29D0DD5983ED83017D3BD0D6188 -:109C80004CF7342CC672D1863A8477537B17D2F6C0 -:109C9000061DD35D0D2D98DFD61041F891FD65CFDF -:109CA00017513D7D2E2CA29E4F35FEA173AD7E90A7 -:109CB00021D556B9983E23DD92AF4ECBB6FA4DCAA8 -:109CC0000B2DB0A764AC0576159559DA73E44CB545 -:109CD000E42B99551658F65C6581C744E758E0D1E6 -:109CE0006D3758DA1B19A9B1E48F685962C92FD0B2 -:109CF000575BE0FCFA7FB194CFAD5B67C9DFE60C40 -:109D00003F235279357CF1264BB961E11DD67DDDCB -:109D1000ECCC8B925BE4333DCBECCF4894F7521EF6 -:109D20000985506F31FDD208740B7EAF5C12DD27C0 -:109D300080FFEA8A13B0EFB01731BD33607F99D04E -:109D40009EE279F0359DF653E93B11E831F11909AE -:109D500098EA51B97F5264FBE64D77B17D75EB5DB2 -:109D6000C9F7D728D9E93C5ABF4CEEBFED11256E93 -:109D700007E9967D4AEB5D0296FF7BDB37F213DB4A -:109D8000EDEF8FD25C85D90E891A7E51A267F5EF6F -:109D9000776D3DFEF9B0EF31F6B912E7F3CAB9C1FC -:109DA000B79B289FAC5709FA0DD77BAA08D815E7AF -:109DB00054C6F7646F1EEEC78DF203C767B22B500F -:109DC000FEB8AC7E5ACF1C942FEB3307B7CB94B8B8 -:109DD00084FE3B292E9018D53B8A5C3DAB808E4B90 -:109DE00079450AAE25A87F92EEEF09D981789012C5 -:109DF000EC9BA60509726F462ECEDB66C8B7CC2A4F -:109E0000FCDEA40E3E2E3B8C0BC6C3C7658BBB315C -:109E100095E24E1CEF947806C293E37E4C2F8D0F93 -:109E2000C7B4223E0CD349F1119896C70B309D1848 -:109E30001F87F5CAE263309D109F88DF83F1099880 -:109E40005E12FF1A7E1F1F9F826969FC1BF8BD24EA -:109E50005E89E9B8F837F1FBD8F895988E895F8B61 -:109E6000DF8BE3D7603A3AFECF988E8A5F8FE9C8DE -:109E7000F87C4C8BE2F3301D115F8AF50AE3B76082 -:109E80005A10BF15BF6BF15598E6C7EFC4342FFECB -:109E90007D4C73E38D98E6C4D7623A3CBE19EB65FE -:109EA000C737623A2CFE03FC1E886FC7342B7E2F07 -:109EB000A6FEF80398AFC63B304D8BFF08BFFBE210 -:109EC0000F63EA8D3F8EDF3DF18398BAE33FC5EF24 -:109ED000AEF84F3075C68FE17747FC08A6175A27B2 -:109EE00025C72AC7A54C97059EFC6EBA853E2A5EFB -:109EF000B7CAF1F2570A2DF9652F5AE578F078992B -:109F0000051E7F78AAA57CC9A12A0B3C76BF558E79 -:109F100017EFB5CAF151ED56395EB4D32AC70B5BC2 -:109F2000AD725C6BB2CAF1BC3556399E739B558ECF -:109F3000672FB3CAEFC002ABFCCE22BBACFBEF195C -:109F40007BAC7A6DDA2396F63CE58F25EC57A22898 -:109F5000675C25FF6EA9E7283A9A209F7526A7120D -:109F6000FCE5801299F2F71DC415349FAB18693ACD -:109F7000970719C07734CDE47C3704F88EA6E9DF63 -:109F80005C86E74C5F7CABE5174DB4B1F4E184F936 -:109F900005F44855887E6F1EC661FA45003897A0C3 -:109FA0009F80E8672AC12FD65CC0E07F934E55EAB8 -:109FB000CC7FCBF2C95996EF64F0238DBF5A0BF9D1 -:109FC000E969D1EC204D1FB12597D38F49ECBCED49 -:109FD000AC18EA90E87CFFA3B2E776F0A3FDD51EAB -:109FE000DE27D1EFCB1CE17C704D7F6C0B3F2483CF -:109FF0005C24A107E17B1A093D24A1BCB6FA451BEC -:10A00000C1E0A6ED7C2656EF87FC8CAB17A35FCA98 -:10A010009877B377F0F14425A6979AFD04F78DFA67 -:10A0200011859F2311765E0329D583F7B87D21C85A -:10A03000DF7044D963A7EB60CBC99A4FC6B36216F1 -:10A04000FD116B5E057AD8017A680448F92E4C3D03 -:10A05000A49B9D1B915E4C55A20A901AF3EF9B772F -:10A060002E9B37C5C72F24DC1FD461F975EEAB27B3 -:10A07000C37C283E4EC0778A8FE7A521A9F141E035 -:10A0800064818E3FCFA0A2FD82C5FFF8BE10FE8D79 -:10A0900064F263E6D507713F794052111F06FEE86E -:10A0A000DF6DE9863F86D5FB23F69BD09ECCCFC5DE -:10A0B0007E23F1FEB93E34E8384324E1647ADD388A -:10A0C000F7219D795FC99F2D28CC2E49ECC72657D3 -:10A0D000E379EA00B99799B0AFCF0CC3A250FD491C -:10A0E000F56592714D57B87F4ACEBFA8F32BC35F79 -:10A0F00042F6E77DA5F32EA004286F901C399E87B9 -:10A100007090EBDF02B0EBA83D72EC8DA762CBA99B -:10A110001CD85044752DFA2DACF6DC869888E7EBF8 -:10A12000057E2A706863F5DC0E90B93D68F42B3724 -:10A1300059FD299B6D7C7F7BD88AC7024AD0FF4E90 -:10A14000B7DCC493CFC6C7CF2D8D76F6F48DDF3A3A -:10A150008E074AA83964C2676129251D18478C8D6E -:10A1600023B17FC2CF170CFE913DDC6FA2E663BB2B -:10A1700046BF89FD1069369E27A5C2EF807EBEE2EC -:10A18000795D859CFCBC93AE0FE2696C8AF535CE97 -:10A19000EB0CF8D81BB578FEDDDC59837654738060 -:10A1A0009FB3FF85B60AED1092D45EDCCBF1BB897C -:10A1B000EF17F746AA1C582F33DFB24E45DB67B8BE -:10A1C000000F4D6A553AA4FB76B27223EFBECE154E -:10A1D00066765B3AA49B8AD977D798BD0E567E8F58 -:10A1E0000AE9E612F6DD5D7AC8C1CA333F2DA9A798 -:10A1F0007FA673A022B55A14CA41FF92904C619772 -:10A200001A25E04776AB5D981AE3CE8E88E2185A9D -:10A2100025BB33947E25F8DDEA4870241BAA03D6BB -:10A2200039CA972FC7C8AFA7F9B4BD313B8F564283 -:10A230003DE7CEBD95576AFDE577F3FEC774465BF3 -:10A240000AA17C8EB5BD76DE9EB3B3EB04F89B29E4 -:10A250008EB13D237F17CFB7437E26521BD6974B37 -:10A26000DE8DC1798681E740B1D8087022BF1BED31 -:10A27000B4F171043BA3912AE867AE751C3F34C862 -:10A28000B29384A21E933CE0F9119EBF01F6FDB487 -:10A290003FB993F9518DFCADC63823AC7E23F70B43 -:10A2A00018781DC3E591413FA9E898E8A265FF46EB -:10A2B000EA5D56B8CE64DF01BC38DB9A1F2EB4C20B -:10A2C00073C75AE15099159E3CD5D2DE177D7E9416 -:10A2D000A813FD25DC8F62F85E76A935B8CFE9F7C3 -:10A2E000D3455C588EEF3B7278B987EB98BFA5D108 -:10A2F000C3F985FB5D9C5C2E3617B17D499F5DC11E -:10A30000F1DDC5FD1A8F36B4B1F8940BD8C3EDBC9E -:10A31000DE2E7EFED8C6FD323F04FCDB61BD985FB9 -:10A3200026C2FD325BC12F43D356F0CBD8813F9973 -:10A330005FA605FC32343DC0FD323F02BF0C851FD5 -:10A3400006BF0C4D1FE27E997DDC2FF300F86528D7 -:10A350007C7042F75CF0B775807F86C2F773FF8C24 -:10A360009FCBE58333A3D9E00F7B6466F27DB1DF39 -:10A37000C6FCEEB960A850FAB884048FA1BF9B8ACE -:10A3800061F0774FAC0B362A9960B732BC4D0C07A1 -:10A390001B6DE560B73238DFC6F428E80BD01FE448 -:10A3A00030F327503ECB047C6FE1745976222CCCDD -:10A3B000A3E3F8A3CCF5A2460218B7C0F902F24114 -:10A3C0009EBC21845E972741BB04C795BFB7AE0AE8 -:10A3D000C468F1D3D5475DB4DCA8AEE03A707D1611 -:10A3E00095A8E05920CE224D84F5395819443FDA1A -:10A3F00096DF4AC13DD06626B1D0031D1BCABD31D0 -:10A40000063CCD4A0F97C477A3FDDB5C37270DE9E7 -:10A41000492383EEC7FD21EB3E286DB2D59FD5BC05 -:10A4200097B5938A6E8ADBADF6C4A89DD67D54732A -:10A43000D19C41FDCF45ADD6FE0B9B12EA7B06AF0A -:10A440009F1FBF1AEDFB54F43D4EAC49B34DEA8754 -:10A450003DF1CBB07CA27D2703A150BB4D3EAE6049 -:10A4600048957C5C0D815D2B1FD7781AE4DF431C77 -:10A47000AE66B0CAE220A83D986B1B82EB9370BE1B -:10A480001D2270FE7C109501FDBFBE705D88D2DC80 -:10A49000C17F22B8DF78435E55A55378D76C8728F3 -:10A4A0005D02F4C6E21914BE5E194A746301D0C39A -:10A4B000C322017A78A473703E1E10E7E009A17FE1 -:10A4C000A6A0492D03F59DAADECE2671563449BBC0 -:10A4D00053395F91E324D16E9E0AF35DDF34474523 -:10A4E0003D725D10F7074463E337E45C46FAE0EB46 -:10A4F000B7ABC17ABE964D92DBA16B6C9CDF8A999B -:10A500007C34E83FE3C1C1DBDFC0DB8F770916FF96 -:10A51000CE90EBAA2B6D99B8DF097A408E7E293157 -:10A520003FD961169F66F05363D10E179437FACF67 -:10A53000CE89C1F684341F99C2E226287E713F7805 -:10A5400084CAF11294E368F73917D785989F3C8243 -:10A55000F10DCEBAA00EED481E462FB0DFE4E57136 -:10A560003C1BF78A1872D13897D9AD869C37E8A082 -:10A5700031C0FDEB7365E667FB0B9D9FB11F81FD4D -:10A58000A15A87E77BCD93D87C6C992C0EC4561CBE -:10A590008BC1D959B377D15A98AFBED0D0D73CEE42 -:10A5A00082B0B82B231E0FF003E7E0056DE3518E58 -:10A5B0001878FCB610AE073EB265EA4218E7D185BE -:10A5C000ED1B784BC4FB77B93C1D9EC20F97A6309C -:10A5D000B99EA1A85781BCDD7284D277927DBD93CC -:10A5E00097EB88CDD90636A2C1AF46FE0149C37E9E -:10A5F0000CB820AEB0B8BE9875FFF1FFBA1DFFA829 -:10A60000CD1A77F7FFEDF8FFDBED789A0F7648F873 -:10A6100002763CB7F3F7F6D16F829D5E2C1FC130F6 -:10A62000BA047B3EAB7846AC0AF23BBBBAD18E9FF4 -:10A630003CB81D4F12EC77C3AE37EC77C39E37ECB6 -:10A640007532D09EE7FAEF1BEB4232C48911D47FFA -:10A65000E39ABFB14E87FE13FC1E12157366FF45C9 -:10A660002FF0F910133F78AC76C3C5CB0719F53F2F -:10A6700009E65AE46B46F6E0768E11EFFD45AE61D1 -:10A68000AF87D83968513131DB634D548EFBE87C9C -:10A69000DAE7B2F329C2E578B6E197290EFB47A3C2 -:10A6A0007CB7CADDF6C5353A9EA394133C7FF4E42B -:10A6B0007485E07C3C6B6E04ED492A7F8B1593FC1E -:10A6C0002D68AB4039A773FB32119F20EF0265D094 -:10A6D0004F829C21C19745C8CF85B36BE087A88086 -:10A6E000FA03E234C60F226F2E325EC3889FC8A3DE -:10A6F0007F206736C86C7CE4696BFC3951297D5436 -:10A70000F4DBCDE4FDF98239EECFB06312EB51B941 -:10A71000A026937B6F08E16F2983D047A23F8A244C -:10A72000C8692A8844E8BF60F62CF433F5F9A564BB -:10A73000ABDC9603463CCB7FAFFCAE55FEC6B8F310 -:10A74000AFE8B7DBC8E5F3007E4E68472CE9223D51 -:10A7500049FAF79458F1EE2AB2DAF302085B881F3F -:10A76000CEB19E93CB9EECE4E7003C3EB366B2B123 -:10A770006CDA77FF48F9E4961336BC4762E81DC3EC -:10A780002F7B0BC469D2F5A981B84D4ACF0B48B5D0 -:10A790000F323F2622C6837D4C5EF64D34ADD37D0D -:10A7A0008AC2FA69B19D847B42463CE2C20883FBBF -:10A7B000F0DF668517913959701EB168A70D38888A -:10A7C000DC42E4933DC6F8297F6F51587C752DA972 -:10A7D0006B0639B69EC773D7A84486F8C1E54FDD2E -:10A7E00057318FC27BB9FFF60CC5BF66B28397782D -:10A7F000A20A9C2BBC7368E277BE46A07EB4391BCC -:10A80000E208A9BD0A718489789FDF621DDF85C6D1 -:10A810009F385EE35E51AA71C89D4228D9FEE0319F -:10A82000C51AEF76A1FB4EBF53347EDE6CBDEF74CC -:10A83000A17A7F543492EC9ED485EAF5FC8DFDBD5F -:10A8400097A2DE72478F027260A51C9E2514F6C780 -:10A850006B29B6EAD0708A0AF9E90931385A32957B -:10A860006BB9C8722760637111E5668983B4779606 -:10A87000F3F12FF63FA0007F7EFCC8DB57C379CDF4 -:10A88000D29F4AC441E77576BF97C470DF11554027 -:10A890007F2D392431FF9B1CABB8D6247F315296D3 -:10A8A000E27BE9A35E8CAF58F2983D3A9BD65FF20B -:10A8B000E43BE309C5C3D975BDCF0D87FDC42302B1 -:10A8C0008B27D47BC65F4BBF2F91C9CDD549E4A060 -:10A8D000646774FED14FDC73818E84CE233761BBF5 -:10A8E0005DDFB5D94D76FF7F2A36A31C9E33E90F75 -:10A8F0000BD191021B9FF99E8411C7F9D1C3021B92 -:10A90000DFD3B6A813C6D7D9A18469B9959D7F4274 -:10A91000BAFDC6A3077C8087954F4B16F9B2B25398 -:10A920008AD9C763FAB61DCFAF421E81CA911528D6 -:10A9300062687A6839C67DAFE8DAFC27C907F5ADE9 -:10A94000FC43F1128C015E5F9582B3017EFC211FF6 -:10A95000EC07CF74EFF3015E69BBF3144A57977DA0 -:10A9600066E233C2DA8FA70F6C8F5A380AD0D7CA83 -:10A97000AE8DACBF04FE3C03FF1836502F8CB55B88 -:10A98000EDFA73E4C50ADC877766248D93EFD30B69 -:10A990009C5F971E38B75BA7FD7EF4D887BB753ADE -:10A9A000FE657FFD74F79D6057FECCA9829C59F926 -:10A9B000C86F7DC484F79976C6EF671F7EE8C15DD6 -:10A9C000945FCEFEDE8EFBD1B3CF9CCED3E8BCCF5E -:10A9D0001EFC739646CBDFF6CCCCA18087DB9EF8BD -:10A9E000C6D0C1F6E740AF51BB795DA3B8AEDAD3AC -:10A9F000020BCA3FCCD384F53976E8581E8CF3E3BA -:10AA0000D7EC780F7125FD565F06EBB51CE53EC00F -:10AA10006B289E57ECDFF027697C327CEBC345B88E -:10AA2000F34628DB0460BDAFFDF6F472486D410DBE -:10AA3000DA23BD28B713EBAD7C85AEEB25A9D7F1A2 -:10AA40001CF98B02F85FB97F23EB37611D3F867FCE -:10AA50004C19B88EF3ED56FD7E8E2CBB1F6DFD4359 -:10AA60001949E3A68C755CFEC43F0D6A0718F2E035 -:10AA700042F85DCCE3FF82F6D0AD76E0ABC7DC7A7E -:10AA800080AD6F7436CD3B7BE05C1E186BEFDB7ADC -:10AA90006F0239D9FB8C5D85FDFA92675E453E3BBE -:10AAA000FBC44B8A86729278046A279C257D7FDDE1 -:10AAB0006037AC60B63059B9D71BB3FBFAD76945DC -:10AAC000F49A599A0FBFBF8DDFA38CFE57448F5C59 -:10AAD000272459B703F6422697A343102FCB49B733 -:10AAE000A29658D753980CEBF8F6E54077A9D6D143 -:10AAF00098BF0AF3BFD4B49E7B19DF26965F41F955 -:10AB000013FC837DEB1A155E2549F8F46C875D868E -:10AB100038DFB329CED9FBEEEF7E45FBEF217B8AF0 -:10AB2000FD3BC7C385F8FC42F3FBAAF8BB1B82BF01 -:10AB3000260DC4E3477F492EFF8FD999FF6C050985 -:10AB4000CFCA9606EA2F8984F4E105FDE36DEE9203 -:10AB500050AE7FD42945A16AA29C5891C24FF89269 -:10AB6000D1CFD347C6833CFBE8E84F385D32BA5FAC -:10AB7000B1FF6D45E7FA206AD60729FC547FE4ED62 -:10AB8000AD3C9CBCBD95FBFF94B4BD3372E8BB30BB -:10AB9000FE33DD36A2D326CE744949FDABCFDA6D44 -:10ABA000D638716FC56B69B49EE47369D075E3BA2A -:10ABB000D0ABB09FD35FB611BC4F2B07DFB7D3FC30 -:10ABC00046AF4BDB44F1D5E85B847E48A3BDA604C9 -:10ABD0003CC9816A1DFC1C72667539B391A396FD50 -:10ABE000B04D152DE3A67A3607F4D09B134EDB60EB -:10ABF0009E6F25D8836FC9A479286DEF2D5D08AEAF -:10AC0000D592D1B7B5FDF01A896866FD67EF7D135F -:10AC1000C6437EEE2470BE22FDCCA9833C59B9DB2D -:10AC200019B5D3F91C7BE28B07016F67EFB713BB34 -:10AC3000295EBC56656D9C7EE28BDDFF45F34F437C -:10AC400065DA7FED6E5A1EECF0FD6E0CDAFF8FC7F1 -:10AC5000D2C6132A9F6B7F7EE7D5205F6A41A6D2BA -:10AC6000F2B58F0E45BBEED410069F3A901B85754A -:10AC700059F6F8332B408F2CFDB19B80ABE0D813F5 -:10AC8000AFDE04F0D99F7B31BEF1ECCF4F5F067C85 -:10AC900040ED67CDACC76F31BF3340DB5D0A30CBD1 -:10ACA00017CE735907FB92A59052B9B1F4E934BCA1 -:10ACB000BF632A87F556DA7B6F0FA27F45CF1671E7 -:10ACC0008F13CB063E5CDA69ED4F73303FE84AA53F -:10ACD00077112B1FC966FCDA8DF54A1D9C4E797ED3 -:10ACE000627DA3FC384761423BACFE0A3BA94B4660 -:10ACF000FF931D4CDF2FEDFC72B4B53D9D7F4FECF3 -:10AD0000877DFF9EC0EE9790834E8C235AA6C44643 -:10AD1000A5537E7D52218B816F97F962A3FCB4BF4E -:10AD20009F7239B9CC4561FA3D9B8F03CA034C1C15 -:10AD30003D3F86F55DFE949300BD2FFFB917CF5FB1 -:10AD4000963FF9C5A97FA3DF3F7AC28DFE92E53F0A -:10AD5000BF03D77BB93D7613F8517A0FDAC91E5A73 -:10AD6000FEA383CFE7811DF2912D96973EC8FE7C0E -:10AD700079979D5F6AB0CE83EE0B8AEBE878F4EDAD -:10AD80002CFEAC9EB8826B21AE041C0740C7AF3BC3 -:10AD9000D939213FB75DCDFD499F2CD0D270FC251C -:10ADA000CCAFB59AFB0F567F4B1BEA378D03E243BE -:10ADB000C94442EE50EA46839C95E2DF241A85E5B9 -:10ADC000F8084C8D7292CAFCD05226F3B7D9328360 -:10ADD000A4B604EAB17822E2B9AA8FCFFE275DE2D9 -:10ADE000D5F76A43A1BD790E664F6F7386563870EA -:10ADF0003FE3C17BA1384F2A10F427D8BCBE10D83E -:10AE0000BC12C7FB854DB7833CEF3FCF66E727F504 -:10AE1000B2F6AA06F33FC1E5D280F9333EFB444DBA -:10AE2000473E33E6B1B9414579B2B12180E9868622 -:10AE300062A2615C7F106189E3C35EA21309EEC95F -:10AE40006A6CAC764F7508FC56D026F83B254F1837 -:10AE5000E9CB1EA8C3BDBFC3C3FC94924727B51E50 -:10AE6000F487219EE0BC05F0A470586E9B8D78A5F8 -:10AE7000F5F1FB7267F86EC08B2367AC454E2999DC -:10AE800065167800DE0CBA38F0DF8D3F82F8023F9D -:10AE90008DC6EF4500DEE05E04C0FF07F0F70CC38F -:10AEA000DF542AA3CCF8ABB2C029F1772FC55F6677 -:10AEB0003F5F25E2A19EC7A519FC948A7FE15E0948 -:10AEC0005C1AD8D1D086A9F13D3D855ECF7532B9E7 -:10AED000564FC2782E4654E65721993AC931F99314 -:10AEE0004840C7FB4C782F1AF23DCC8F68ACAFA41A -:10AEF000CAA7ACF24F7B15E673C70B3611E4955425 -:10AF0000FF0079C7748E26CDAE766A88E720FA7581 -:10AF10001BB97E5DDFB79E56FED8DCA061BA85F313 -:10AF2000C936CE27DB61DDC13F1714714D5B671158 -:10AF3000D49F775398EDEF6396732B7FB02B06F178 -:10AF40000E2893344C6328BF5EB34747D27AEE1283 -:10AF500012027AF1BFF6FD28CE957405C01FEAE70C -:10AF6000F823870BFDD7B377106C4C4F1189A511CF -:10AF70001BEC9F12F1DB183CEA807D77AAF1640597 -:10AF8000757B1EED2FEB753BCAEFCC1BBB5EABA1F7 -:10AF9000F3F0B4BA713F991564F4E80986855AD381 -:10AFA000FA65A5B0FBEE735EE976D2F5F4401C2E8F -:10AFB000A5C71D6D239C781E64EB0A801CDCEC6722 -:10AFC0007A469B4B7BBBB4BFDEE70E667FF9CAAD0A -:10AFD000FC6FC863755A99858E0D799B3EC34AEF05 -:10AFE00086BCEDE993B7D5B9309E8C783BF26322ED -:10AFF000FD37DA145DA0764A23D89260DFBD2DB00C -:10B0000078DB817200E3513EE929D803EF05ACE318 -:10B0100071D03AE517D43BDCFF699CB71F20D52DD2 -:10B02000F07E4B0BA52302EFCC50FA2118AF538CC6 -:10B030006984D20FE393C9981AF439139C2726FF29 -:10B04000B954F49CC8EE6188A073884CF7811EF057 -:10B05000331D99E200BB50B6054F80FCEAF58A5DCE -:10B060001097B0DE33C70171D482BF1CD7FD736F58 -:10B070004DFE60E729F01208D08DEA09929325FD74 -:10B08000F77525B58CC07EF280A71BCFFBCA9DA2A9 -:10B09000C59EDCE60C5FE534C1A5D03B5FB7AFE3EE -:10B0A000FC93DFFBFD0EE77792A39322137F1BF146 -:10B0B000A144D349B189CFD78DBC9CC039E740FEAC -:10B0C0004E21C7F6FD63E458637E14D7CD9628372A -:10B0D00032A97CF760AA8B2A8CFF50D33F4F403AAD -:10B0E0005B0AF8209E3D7DF6CBD70B078E33516E61 -:10B0F000F5EB230DFD55541FDD3319E4600A7D7413 -:10B10000E48DD1DF86F8A9779E9704B3BF6E717C7A -:10B1100023EA83DAF814A2D1F1D6B4FD00D3456D49 -:10B120001D48F7EF47D7FB303EA685EDE7DE8FDA07 -:10B13000A25201D2ED7909FCFA84B5FF7E7B2396F9 -:10B1400023E07D31F5FB7E3BAB4FCA35B4A73FE131 -:10B1500073ACD9660FC139CDFB6DB4DE20F8AC817C -:10B16000CD5012FB14DF0180987F52371AE49CC146 -:10B17000EF7728542E011EDEB427F5B32F77CEDCEF -:10B180000E7CBDDC196A839478D22FEA3D8A77441D -:10B190006AF722BEC3BE6B2C7E56E6C77C87DBC532 -:10B1A000C49122DFC7EBABC9F397B77EF8DC5D141F -:10B1B0006A2E095713D3FE5A226C7FBDE2E94AFE7C -:10B1C0002E081B4F12FA64F66CAB1DE5D002EE0F91 -:10B1D00032E8B59F5EC23E7E2FD4424FB7C4B7E37C -:10B1E0007A0B9B4BEF9942F1F729A523F0CB099BF2 -:10B1F000A70F053E5ABBE96BDB6EA4ED7FF6A28478 -:10B20000DF17C79D58FE83BB82F7DC08F6FAAF6CE8 -:10B2100018DFF4D98999780EFB81CDEA47A871B17E -:10B22000FDCD5B4E962E8A6FB6D8C78B5AE62BE0C3 -:10B230007F5C14DF8ADF17C1A10CDECFF8F078A5A0 -:10B240000CE73504CF47DFDA787AC63AD46765E889 -:10B25000C7AADD624F7A9FE42DA766913BB53DAD4D -:10B26000D82EA1F65166166FCF243F6AE370F90419 -:10B27000D6472770DF601197237DE36BB759E4C889 -:10B2800007CEE47E92FFE89BDFD7908F06CEEF32A9 -:10B29000C65F46BF3D8CEFFAE773CF9464F3E99F36 -:10B2A000C7342CFF813F79FF591CCFA71A16931082 -:10B2B000954335765ACE03FDDFDA3C19F6D9EDFE1B -:10B2C00074C134AFDAB6A524643EA76C9FA7D498A6 -:10B2D000DAED5F07DBB39545FDEB90E52233611DA9 -:10B2E000EE73568B2EDA5FCDE6E9E3C3B8CF66F294 -:10B2F000E41D5B300FE4EAE9B65B93F277962B61CD -:10B300007DDAF8FA50BBB7DCB43EC6BA24D63FF5B6 -:10B3100046EDE777811FE05E66D4A4C2D780752B27 -:10B32000488EB7A08BE9975354CF86116FDA93AF4D -:10B33000015D6F71631C676AFC8D23E1C1F097C2E8 -:10B340007EA5F6CE18D710E897201E6ADB181D5C84 -:10B35000086FFDFD723AA84C3E9F9BFAE8A09EE85C -:10B3600094614F2A17A2833B89EE18641E7D7430C6 -:10B37000E659333FDEB449433A781FEC94D103D702 -:10B38000FFA4A2FBA6C239D02609CF994EBAF4ACCD -:10B390001B183C01E4F3495FE4EAA9E5FDF02DFB4D -:10B3A00046FAE699FA3DDD72AB2F999FF5A654F463 -:10B3B00053A493928AFF7DF4F38E2D79FCF2726789 -:10B3C000650DF0018924F7E71AA921BFA5344FDFE5 -:10B3D000BE13F4E9494FE1E7519AFBA833BC1CE8DE -:10B3E000E20E511B3F4FE8DF7F0EB03F1B664D7FE3 -:10B3F0007724F80BABA7BF6B437B08DB23605716A2 -:10B40000F0B808F46F0C437D90785EBAC35590F4A1 -:10B410003C767D43DD4468973874A29AE3E008B334 -:10B42000A3FE9330BF97311FC51656E15E9A229056 -:10B430006AA0739B1C6E817BBCB640E604DD84D79A -:10B44000888BF9BF9CC78FB714D0FACEF75E5461D2 -:10B45000D076DA0FF8D71C39F22766FFB42D93C5E2 -:10B46000279222D3F742884FA0B0659F4FC73BC8B1 -:10B470003EF5A702C383EEB5333F0FD125D07BD76E -:10B480003B89F187F6F7EF8D3810B989E5FB8DEC34 -:10B490002696CFFD972B6B987F32715DAF3FBCA195 -:10B4A0001BEC99EB0F0FC3FB74D77B46BF07E70B71 -:10B4B0003F051F3ED0BB9FE9E5C47A8F733EFDE791 -:10B4C0000E51B7D175396EEB3DEA86F17E8FBDBF67 -:10B4D00078C36F8FDBDC34FDC32B276D104F7433C3 -:10B4E00004E8D079CD239AC28CE028D69F4FBABC0D -:10B4F0000CEE1A32C76B6E8F6E55A1BD55EC9CF7E2 -:10B5000086DFBE3213D4276D6F3DA437BF48146861 -:10B510007FDE21AD995DBFE3ED1DA6ED89FDEDF563 -:10B52000E391DF2B941D88977E3C39106F069EF0C7 -:10B5300002478505CF686F1878EEC35BDADCABC8CD -:10B54000F8D4FC72BD67D47BEC7E221B57229E3F51 -:10B55000832CCA6FCFB8422F03DFEC75857E03E9D9 -:10B5600032476F9E5C88F70F5F05BE5C2185F3B3A1 -:10B5700046E0BDC4D143E05D98EEE4E7AB897CFAD8 -:10B5800026F00BC475F338CB9BF8FC8E7DFFB41707 -:10B59000E3289F78350FD2E552CF96EF02BFFD52D8 -:10B5A00042FBFB9343A3078D477B93FB3BCEBA8CB7 -:10B5B0007759D8FC6EE676DCCD87DC517847F3E628 -:10B5C0007AC962FFDE5CCFE23888DC3DFE3A8B1D33 -:10B5D000D9C4E31D06B603FBCEC4768CF91DCDCBD2 -:10B5E0001E07FBC3FB27291AF81F8EBCF8C9EF6B97 -:10B5F00029ECCA75E0B9EC163FA7DF4A11D7FD7EEA -:10B600007FC85D0A7EA74DE9419DCE73D3B3A44B9D -:10B61000A4F8393AE6F628C4216E9D2EA2CF6A5BC3 -:10B62000FC814815D42B61EF15A9DC1EDDD67DB257 -:10B630000DE8F1F46B76F4F73BBD128E6393AD3AEF -:10B640000FECF7F73A94A4EFE39DF7C82C8E58E877 -:10B65000C178B7F924E200B971A87BCE50188F2FBA -:10B66000485420FFD3ED92C8EC64C3CF1193999F47 -:10B670005D97191CE2A9EA34C7AB6D9C3503E32939 -:10B6800016B4BE84F7297DE5C9DF87BAC4CDEED9EB -:10B690007ABBD3AF04FC7A6788F8B69137D82B40D1 -:10B6A000BDFCEE2A05EB478441EBE7AF51AF04BC8C -:10B6B000427D90FFF917597FB49BC53B6DE7FBE4D2 -:10B6C0000E5BB079066DA7638B5F80F530CA85DCB1 -:10B6D000CC9E393DC3F0DFB0B8F6BC22D509EFA44B -:10B6E000E48590B989B73C82F1B77BA01CF36F2247 -:10B6F0001E3AC63C1983F3E34DA01B609D6D8C9EE2 -:10B70000366D11D09F49F1970DFAE2BDBBEDDF8494 -:10B7100079E4B7082AECBD699A74DCF51E07A3F337 -:10B72000D67B701F08EE516837AFFD37382E6F8A11 -:10B73000F9EEF130FA78EF02F491E1667E9BBCFA03 -:10B740006EBE4F8AE13B8911C013C0A172F63EA1C3 -:10B750001CD2CC7128FDFCC3F661749E2138DFAA8F -:10B7600099AC44C10F20B674E07BC0F32376720518 -:10B770009D5FABD01D027ED12789FC1DAED09B8082 -:10B78000A7ADDB87623CDB06319487FE9D7F55F0D9 -:10B790007CEC68E8937BE13DDDDD9315E48BA32130 -:10B7A00076BFF5FE35851DB00FF7D657E13BBF518B -:10B7B0005541C9D2584E5E180DE7836B4455A0E53C -:10B7C00023D5C63D0315EF314C903EBDB218CECF08 -:10B7D0008689E04B22A705F63EC8FA35552AACEB20 -:10B7E0007A355330EF5BEE7033FDF2B2BFFA0E37AD -:10B7F000C563E0AE1D2A35E3297F668C037FA1DE99 -:10B80000A268C63D7178572483AF4B46B7185BE4F6 -:10B8100043D8B3986E91B74D637ECA1F5C1566FE20 -:10B82000453893AC40FF22FF0BE0BA667268D358EC -:10B8300017023BD72DC2F2D04E166D27A35C8C5554 -:10B84000D076F7F843BB519FCC74209E88DCD3069A -:10B85000788ACECC0E425CEB8E29A35E82FB551912 -:10B86000277AE7801E8DE6BAFED001726ABDA2017A -:10B870009F67AC3975237CF7077F782BA4194DBFE0 -:10B88000BB13F481BFE74F0DF87D9662F1EF65BC05 -:10B89000FEC197909F51AD58FC84BDFEEA5D809734 -:10B8A000DD2591488DC6BE87B2FAE771606DF72C31 -:10B8B00078F7FAF43562700FCFC779ED54A39B186F -:10B8C000DECA41AF1978DB206A5DF02EB37EB50386 -:10B8D000E9A38874A3BC1A06A7C8234CF4FAFAC6D5 -:10B8E00055102791389E1F73BE853F785F12D60A88 -:10B8F000E25194612CAEFE60597700ECF82DFEE425 -:10B90000F109673DACBE3DC53DF5331E460F201223 -:10B91000DBCA300D9542EA217A1AA4398E10C4C7C9 -:10B920001E14B53F229DEF9034581F286FA3EB776C -:10B93000E48533E81F3C12F90DA6CF7B8A8DF662B1 -:10B9400059F03E6EF9493C1FD9AA321AA96D61F22D -:10B95000A236D0E380F38ADA12A2EEE1F4A61B78D5 -:10B96000067F17D75735D731BC6696103C6F059FB9 -:10B9700018BC579605E528FE325BD6AEC27524DDAD -:10B98000FA085A6E2BB40BEBD32412D66E8F03F940 -:10B990003722E17923E5F75FC379624DEB503C6FC5 -:10B9A000876BEAD05E3AEF379DB7D741DB01FFDF07 -:10B9B000E91609EFB140D80BC0DA1A4ACB489FBD4F -:10B9C00095C5B45DAD5C5537197460C831CA1A0BA2 -:10B9D000A8BE00BC2DD0F555407F271DEA0B300EC8 -:10B9E000F74EBB06F35FB0F3A93BC06E71077A5AFE -:10B9F000403ED44E66E34D6FA5DFD1BED17E0DE54E -:10BA00006B5BED1AEB8FE3AF9CD319C7C3423EEEDD -:10BA100085ED6CDCAEDC6804E8B3760DC52BE485FF -:10BA200019DD834BF3BC887C7502E6EFD5B3B0DD3E -:10BA3000217313F82281FE8C79D5F079D5AC61F3AE -:10BA4000229C9FE8B062D06E4D399BE702C2EA8B20 -:10BA5000F09DB6BF90CFA7467F12D3852D764BFBC6 -:10BA6000BB8BF776E37DB612451310CFEC9DCC3C33 -:10BA70003EAFBC26D65F5EC993882F526F1A2FFA4D -:10BA8000454D30E5ABD3CF53C6A276AE90E74062CA -:10BA90003AF97D05CF518A765AE7757AE3E8075A75 -:10BAA000C1FF79B782E71507C5E09BF9B80F553498 -:10BAB000267F82BF990D727A615310E4F8814A861D -:10BAC000FFD3DF2251A0879127AAD301DF234F8420 -:10BAD000795A87E7D81421429FDCA3E3A35BA7161A -:10BAE00001E4657CC48F16831CA0EB0CF660AE7974 -:10BAF000DC747C192D59551087943939BD4AC1A77A -:10BB00007F13F24FEC9A03EFD8661EDF752BF433E8 -:10BB10008C98E643F3477947B0FB57C7692E94AB3F -:10BB20003F7517AC472B7F8F7E248C2C1DD3E39061 -:10BB30006650FEDE9C0EE394C98CB27E79B0EFEEC7 -:10BB40008A092057F0EE4819A6315236506E98CA2D -:10BB50008FE1E5752149B952AF66D997EFBBFBF28A -:10BB600031B07FDF0A76621ABCE7A77E0AF1317A2C -:10BB70005044BC6FB5C51C2599F05EB848C07ED94D -:10BB800056FC3B11F86EEB211204FAC8A8FEABDD9F -:10BB9000BC8EB51E3FCE5B56C866E0FFA3634ECD9C -:10BBA00082758A1E11F13D89AA5F7876B9C11EFAA5 -:10BBB0003D8B3FE978BE0EF5F7ED794AD2F79AC989 -:10BBC00005ECC4C4F2E923E7A01F2F7FE7767C17BA -:10BBD000B676961CBC8296CEDC595909768C564DA9 -:10BBE000A96B281D77FB84B5C084DA6C765EA5CD81 -:10BBF00062DFB5192CDDDCB07822ECDB239DB2B31B -:10BC0000888E77EC46F66EDDE6924F1C616A979659 -:10BC1000573EE6F816FDFE6E39D582F4FBBBD33EE7 -:10BC200071C2F9CCFDE5551980CF432D56BB8EC0AE -:10BC3000A36A741F546A8F84BC745CADBF25884F9F -:10BC4000C91E6BABA1B0F494072C9C01FB9B8DAD7E -:10BC50001D73814E17146378F280F97ECEF5C9FC0E -:10BC6000FADE59705FA94027EC1C35720F0AE58592 -:10BC70005C6414E8DD2874BC3BD9FE2422879E0353 -:10BC8000B91C29092B50C59067AD236B1E0479F6AA -:10BC900025B7EB48DD62BC0789FC2F813DD45B9959 -:10BCA0006CDF749DDB857475BAFDDA57C13FBDA0AA -:10BCB0009ED9FBF9ED9F0AB81ED4EE1B46DBCF2FB1 -:10BCC000C7A72AC98235114729AC4F9148340DC600 -:10BCD000D345609F10A1FAC78C07A3DDBFB5FE76E0 -:10BCE0008F1DEB5F079BE749FDF3F1F0F9E405E9F0 -:10BCF0007C92E8E939BCDFEFDDF7E9912980FF3577 -:10BD00006C8B941F795B7098C691AF5FDC38AE8501 -:10BD1000F6283E1FF1B07B0BDEF21EBC679428DFD5 -:10BD2000C19C07BEDDED3E3B81EDEFADF27400CC72 -:10BD3000E92AF17B5E82BC2AB577E13DD0D603ECDF -:10BD40005D74D87943BE40448DBD171B35DE2FAFDF -:10BD5000837263BD1E15E8A075CCEFCA003F5BB8C7 -:10BD6000BDB0B084E07E75614E37DA0BF39BB8BD91 -:10BD700020079B41C8BADBFD6493C97E405309B6D6 -:10BD8000D04DDC5E30F43FD7DBB581EE16D4AB4D41 -:10BD9000EC7E6A9F9DA133BD9A1F607ABDB685F681 -:10BDA000A37162AE30DB254C8F6B3BB9FDC0F570E3 -:10BDB00006EF37B385E9AB0CB0237C107EA0A35E01 -:10BDC000C6B3BCAC7EBB654809D39719AD0751AF6C -:10BDD0007583D36508C80DA62F735F7A45073405B0 -:10BDE000E8E7362AA77FEA667234A052FB2CBDDF53 -:10BDF0003EDB20F27326C2EC438CADA7E37C9CB7FC -:10BE0000677CDFCBC777F078FA3741BEEE8B144EF4 -:10BE1000904C7C6BDCDBCA2B67E7F479F5EC9CDAA1 -:10BE20001B5CF4A0643A7F68F1B077AE5A0CBAAAF2 -:10BE30008F05A05DBC4788725C41BFDA4678170A5F -:10BE4000E885EFAF6E70F3778D38FDA4D227861C9E -:10BE5000F29290AF84E2F7DDE88328AF75BA5F8293 -:10BE6000B9BD1B69CC5E02FC1EB9A61CC6BF75CA53 -:10BE7000E71877919F62BF78DED8677E45B9EE9D5F -:10BE8000F50ADB87768B49EFC94CF3CA389F2E99A8 -:10BE9000B8019FCE087BA7D03959495AFE122F937B -:10BEA0009B2E2F7BA760EB9407F15E634AFD2C135A -:10BEB0005D4AA24F0D7DDB0AEB3C9590999E1B9A43 -:10BEC0007594FBD16A09E52BC17D6784FF5E8C5EAA -:10BED000ACA0DFB0D51671C07A6C2BE7EBAA3A3A6A -:10BEE000E05EFA575E178A0F58E78D21312A14C099 -:10BEF0003A47D552E6D7C177394ED3FDBBF99CE21C -:10BF00004A2FF36775C99A08F189F92D8CBEB64E90 -:10BF100051701C9B266475480566F9CBF0749D9B97 -:10BF2000D1D7A629CF217D5DECF816D5DF39F55D97 -:10BF3000D339E2A97B1F2A043CF7BFCB121AF4FEC7 -:10BF4000C2A2FA97A6EE4D723ED0970FFB280FECD7 -:10BF500003A33798CF59E6F1F55DE0B5FAEF40BE9F -:10BF6000DA707311CD06FFD281E9511FFAEF97B154 -:10BF7000F3DA5BF879ED99BDD7E2BB07A570973688 -:10BF8000C9BA7FD0607D07E2837D0F6533BF46D499 -:10BF9000625FDDF2E04FC6B2776574FE7B1A44CB78 -:10BFA000AC60EF5FA39E7E2EA8DBA5FE77CD8C77DD -:10BFB000D82EF65DB7746A86E1BE8B54639A45EA63 -:10BFC000300D9008A6D9A40BD31CD8E7C2FB6BA4F4 -:10BFD00017538DA82231C9FD421244B88854632AF0 -:10BFE000C3BA65F49F4BC89D0E8CBF80F30BE07BFA -:10BFF000E39CC238DFAFF6D644BC49CE2B567B4318 -:10C00000DBBDA8576228B7E773117EE2C763BBE0C8 -:10C010007ECFEA2DEC7E8921D7715F43DBFF513A59 -:10C02000D303FA0E01E5D73AF7D597211E5B6D1FB2 -:10C0300099CF1B88C35104BF1B63B43B9FFB17E61A -:10C0400073FD07EE6D76FF2E88F77FE6839FC19420 -:10C050004FFAF2D97D6AA31DD13D6DD460E77BA66E -:10C06000FA188F5C9360FF5F506F27C00B12EBFFD5 -:10C07000850E28ABDF0FF7A3CBB43C76CEC4F436E5 -:10C0800025240DEBB5D8DFC67D586466C88C9713A0 -:10C090009CFE0D7DB220C1AF9F982E90395F24B4D5 -:10C0A00043359F1FEECDE0DB2626BE36DEBF357E54 -:10C0B0005FEB96505819C6AA05601D553EEE0869FB -:10C0C000AF1A46D3F70136F9F35FF4857FE735C53C -:10C0D00043A9A13AD1FCFED222CE8733A5D64A90FD -:10C0E0006FA7C32408FB875B48DD56B0C7C82B1277 -:10C0F000CAB7E174DCF0BB3FB970A0918EB0AED08E -:10C10000F4E306762FE754C2FBD51FF277914ADBA2 -:10C11000EEB81AE8E00C7FB7DAE07FA3DFD22EF7A3 -:10C120003CD0FBA55DD36BA15C69A71D7FE7A9F897 -:10C13000D0C66AF00BC13B2D2EDA4F0EEDCF910E1B -:10C140007284A0BEFDB0D5155D47C7F9619B8472AE -:10C15000F95C8988EF8DC07397121F5F5A3AB4F368 -:10C160005F37811D7286CB11E3DDC70F2B35DC1FD6 -:10C170003F7B608300F7123E9CA7E1BC3F1CD69535 -:10C18000974EF193E363F7738AF6DB6385741C4B78 -:10C190001EF97D610DC8BFC2C89264E7CC437C4CD8 -:10C1A000FE7DF804C178B80F9DFC778D1C5D3EB311 -:10C1B0009F35CD2758E4D6875EFEFB48391728C740 -:10C1C000E3CB89A7CBC7F8BECB07E751F7B87F8C85 -:10C1D000F7D74E3DC1CE299EBDB7360FFC51C37D6A -:10C1E0001A3BF73EF038C68DC33C601F4DC7A7C150 -:10C1F000F8EE71BF7906FC0FB41EDECF30EA9D3A2F -:10C2000050CBCAB7D1F23EC43BF195013D30BC934F -:10C21000FD4C4E18F6E3D26816FEEE427FBE88F95A -:10C22000304427C57FE9FE6BF05CABD497CEE8596C -:10C23000ED1A3B07C71FC983791C981ECE033FDE4A -:10C2400029E377A0E4481EE0A1DA1B2EF599E6FF6A -:10C25000C1DB4FA17C2F16EBDEBA0BE8F231F63BC7 -:10C260002477BCBE5D34CB8F69F0837893607E2BDE -:10C270007C701E75AAEFBD9C088BF739CCDE635D20 -:10C28000CA79EF5407DD3F517C7CB0FF07987FAA45 -:10C29000EF3D9B2E8C27FB60FFB174486B783C3FD1 -:10C2A000895E8BFC45F1D2E248A2AFFAEE4545D952 -:10C2B0007DB7B3027F87F43E036F75CA1CCB791537 -:10C2C000E3EF9CF682E3682F4793DF934BD4F78923 -:10C2D000EFCA5EE81EF049CEA7EFF277D1567BC3D6 -:10C2E000D7FB505F58F548CDE6E57980E71AB8539B -:10C2F00087710ED3AF80FD36DE3761EFCAC6104FAF -:10C300007DEFC64EBC02E21C4FF9195CE79BBD41B4 -:10C31000E77864EFD256B2FA052CBF95E7FFCA5B07 -:10C32000BD98F54F04F6BB46363FFC3E8521FF52D3 -:10C33000CFDFFAFB14F7834C1E82EDADF60DC16C16 -:10C3400081CDE7EF6BCF90377F773B8E7F6C3B865D -:10C350001C06BE84903D120C8EFD47E0EF6FAD4F82 -:10C36000E6E65BE4F917F78E688673A0730182F145 -:10C37000CFF6D6B504F4D2C29DDB93FEBE5D1FCCD2 -:10C38000E349941194CF4CFC1CF3313B3DC6E521AD -:10C39000FCC1F9CC2842F87B1794A6B230E406F72A -:10C3A0007FA3F97BEFC52482F6D558D2856909E9C8 -:10C3B000C6743CE9C5148F494780AB2F28F1777BC1 -:10C3C0002B60F2CB1CE1FB2154F7AFF6F033404F6A -:10C3D000F07EAF20815DB4622A8CFFA84F357E07C6 -:10C3E0009424FCAE5AFFEF816860D7CC0E0C66D760 -:10C3F0001055FEA82F7EA390BDFFCBF821D5EFC42A -:10C4000025FCFE24BF476CE06139E9C2388867DB50 -:10C4100057BF3086E27FC97E2FEA8351ED4DF83B4E -:10C42000604B487716DC2F1DC5DF93206DEC1D0F88 -:10C43000E39D88316D76CBBB1ECB137E876829FFC9 -:10C44000DDB0A509DF8DFB9B9BE143923882C4FBE5 -:10C450009FA77D29DE612D49FE7B3089F73FF77765 -:10C460008918DFB31AE285847EB937666F9DDD4A8D -:10C470005F5D971599DE7B6A14826C3FED7585F6DA -:10C480000903FB19AB323BEE8020248D23BB268DA4 -:10C49000EF174913B98AB6D3B84C5661BFD918758E -:10C4A000E13968A3CAF685C3BD550ED8A713BFA846 -:10C4B000C2FD94CBA569185FAE2C9727C2B9E7F1EE -:10C4C0003D4BBAE1FE426340463FED703F3B0725DE -:10C4D000C3447C1FA0497DCC3F1FD6C9C3CE19736E -:10C4E0005582BF637AA4E37611E046BA6D190AFD5E -:10C4F00008E16EBC77334C26FCFC75F6044A7FF9E4 -:10C500009C1E64D28AF78F672C7FD7097A3D9FAF34 -:10C51000FB94B4029C87CCD77377FD493FD0E9F3F5 -:10C520001DCD2F5F4EDBB345658C6B2DFEB2F10F39 -:10C5300097D3FE7A3B148C6735F090B746B6DC9FF4 -:10C54000CDB9CD0A2B09F7886562CAA7F038DE3F5E -:10C550003CB81A33C755658698B350F5E0FDE04BFB -:10C56000D304661773B814608A924E5BA4CA45C799 -:10C57000D9F986807E87A31D8BF2314EFF27E17C9F -:10C58000A06F831E12D7EF4BB087908F7427BF1F09 -:10C59000EC84C3BA44FA696A2023C11FED881E7770 -:10C5A0008D83753C61C3F7A4D673FB5BF6B0F87757 -:10C5B000835E12D3F50974B7FECB6B91EE7A29DD59 -:10C5C000257B17CEA827AB1ADA09B61C1204F6B0E1 -:10C5D000657667ABB4DEB8A794A087A2ECF2474BB0 -:10C5E000D2C09E1977EC7AF65E1FC517BEF758AF1A -:10C5F0008C847DBFBD3E73A49C01E53C488F9F7831 -:10C60000D8F98F5CEF0E427E6347454033D1757396 -:10C61000833A521E09EFA53A46C2EF2335A7F89D8B -:10C62000E65CBF580DFE2585EFFF97A4B1F12E49BA -:10C6300073637A0B87EF93F53930FEFB28FD40BC1E -:10C64000C091DB18FDAE1EE6C07BCFAB9F1F3174DF -:10C65000B038A0071B0223016FEDB7D5A0DFA3728E -:10C66000D571E715C0E75E870AF428F946DD330D7A -:10C67000E8FD051BDEFB6AF45668F34DED49BEC9C3 -:10C68000E85792443D1B36450D697FB8421E06F4BB -:10C69000A2EF024DB461DB11067BF56C81E66FDB26 -:10C6A000F62C8387E8BB049A7FCFB6E7199CAB676B -:10C6B000C32F80DCBFED570C1EA9EF02F8A16D2F30 -:10C6C00031186C0B6AC73CBAEDB75780EFA7D1168B -:10C6D0009C0BFE9D1FD3F197D8E0BD5A961EE478BF -:10C6E00031F21F83EF14DF87789A98FF24AFF77435 -:10C6F0008AFC7FE7F98753B4FF335E2F96A2FE5181 -:10C700005EEF788AFACFF17A2752E4BFC0F35F4C2C -:10C71000D1FEAF79BDEE14F55FE6F55E4951FF77C6 -:10C72000BCDE6B29F2FFC0F35F4F68FF4D5EBE8732 -:10C730007FCFF1B6FC41A77497D3C15EF82CF6B653 -:10C74000A0FDDE5E578EF4DF3889D91906BDE740BB -:10C75000BC26C85B95C5558D52D93EEE9769CCDE97 -:10C76000A85C55B40DE86EF5AF24D4A7548FE0EF64 -:10C77000F0EAAB58DCCBEAE7D97D90D5AB647C27F7 -:10C78000CDA047A3BE31FEDD7C7C4D7CBCC7D20A68 -:10C79000F9794B60E46C73BCA76A851D949F206493 -:10C7A000A72993E997E255558ED1A03FA87E01B9FC -:10C7B000B9DEA3C4E01EFD7A55C6FCA6CC2A15F24C -:10C7C000755546FDB33EB3CA311FFD39E9E89FC830 -:10C7D000E7717B4DAA8CF7F865FF0CCCBFFCD1D973 -:10C7E0002AC8D126D2EBAF84F9AD91F1BCF6485DF1 -:10C7F000157ECFF77FE607F9FCAC9FE1FDB8F7396E -:10C8000027BCE72A7F4F447D81F8A3FD16AE11A314 -:10C810001A2D725C5D2D02FC4013D357F4CF3BA15F -:10C8200082C771D0BFCEDB2B5E80F89DC62D721003 -:10C83000CE73E04F36E98322FE7BA54355B66F34B5 -:10C84000F4D57DDC8FAB071C188757249380F977CC -:10C850002C87AAFC3C8DBF63362262D54F052DD6AE -:10C86000776CF213F453A2BECAADA3F2D154DE1E0C -:10C87000502DB0A0B2F72CFE17044CD03900800028 -:10C88000000000001F8B080000000000000BDD7D91 -:10C890000B7854D5D5E83E67CE3C3349669299640F -:10C8A00026CF49801020C0044204449D848011B1E9 -:10C8B0000E0F15D4E2846780BCA0A858E9C7840491 -:10C8C0000C1435FE46047EA003A28516ECD0A2020D -:10C8D000063B2022FEC53658DB8B8FDA11B9883C27 -:10C8E000C747953ED4BBD7DA7B27734E12C5B6F740 -:10C8F000FFEF77D3CF1EF6D98FB3F65A6BAFB5F6ED -:10C900005A6BEF215EE2FD5A47C8E23D8B6FB410CF -:10C9100042C6FFA228395A44C85253D210924CC87A -:10C92000D7F07703214DCBC3D7F7D513B269B9A997 -:10C930009F429F4D5F0E9F464A0889255A7CDB2403 -:10C9400042562DB7F553FA75B51F68A32F9D846C19 -:10C9500056829389833E430A69CC23E4D0129940DE -:10C9600079B1DB1432D2268B5FFBFD4DFDA1BC48B3 -:10C97000F6124F577FEDF399E5AE7EF0FDDF50984C -:10C98000605C7D40EA777A38FDB71270F91309E9E7 -:10C99000D3AA9C8A9A08FE7D4DFFCB6BA1E5C2AE5F -:10C9A000B25EEFB7D9AC84E492B876141E4553D684 -:10C9B0003BDFB4078A607C05C7D7C291DD40E71F23 -:10C9C00037AED165539557490D85A40F7D52580157 -:10C9D0003F41A71C7A9ACE336BE983A34FA71292EB -:10C9E00079D4D20C7825AD4F129246880EBE4DE711 -:10C9F000AD483E0FA17468CE2BF64AF479EC590B82 -:10CA0000C353B615F16490BCE937D3A751F6DB6088 -:10CA10007CFAE783F11FCAB66C5D9307C58009F005 -:10CA200090B5830E98418BC19CD53E85D289A29B3F -:10CA30008C86FA375A7C745E3BA4CE722594C3214F -:10CA4000036B4F4804FE6F8F2CF17AE2535C84EC49 -:10CA500096245E5F54599145DB2BB6418A9790B975 -:10CA6000AD435BF4D741BD2CFAFBC8483A3FF81EF2 -:10CA70002F035E7E7E84D707AF6BA9E84BC737884C -:10CA8000EF9320B4DF23CBAC1C2C6D81F17797F3AF -:10CA9000FE41CF6ADF1884E7669D9D9025B6B216E9 -:10CAA000ABBB0BDE95F61B5B1AE9FC2E7AA2497430 -:10CAB0001AA476EBE93442875A352DE0073C12E29E -:10CAC00025FEC1849C9528724774D14FBFB72C981E -:10CAD000495F5D3EFAB7A422FAACD7458F2650FCD9 -:10CAE000D5EE0B98F4F914CF7A5F3033AFAB5FED2E -:10CAF000DE492440F9A6BEBD189F3DF43BA6C8FF01 -:10CB0000543F93E12ABE7731F246DD2E5A55AB0BE6 -:10CB1000B458FB607BC2E8DFF3FC44FF8BBBDEB89C -:10CB20001DBE77C9134D9B007C19A178E9A19F68B0 -:10CB30005FB7AF8C00DF5FB1F89A6CF4FD5D76B63D -:10CB4000CE88D2E085F66153ABCD4BEBCDFA56BF24 -:10CB500097B6A7A40CC923BB9EAB6C7D713CED7B43 -:10CB6000EDFA099B48EA44CAD7C11AC5FB34817261 -:10CB70003061082DAFAD55863752905614FF71586D -:10CB800011949FB312232D37D51C7115C13AF21A97 -:10CB900008152F64EDA8B01BD67173AD61DA76E08D -:10CBA000DFC862D79CA2AEF157DAF508F7EA57E87A -:10CBB0003A1B4A9FFAB05D82FEFD1402EBD06CA7CF -:10CBC00074A665B33B8504F3A09D752DACC7D5FA5B -:10CBD000406539B473CBE469FA5D73BFA995E51478 -:10CBE0000E975396740847C5C9B9B4BEC96600C943 -:10CBF00046DEB0CFDC0578FAB9E26D8075F873AB2C -:10CC0000D516A4155436FA60DD2AFD1C21281B75A3 -:10CC1000A4214CE1CB2C26FEB0B50BCE376094118D -:10CC2000F03420BC6BCDE14965741CCB62D916A4ED -:10CC3000DF5B5DBBAE633CFDCE7FD63E7FA291BE87 -:10CC40005F93A61080C3EA50228624CAC7B7501843 -:10CC500029DCBB1BFD36909F31A742B6D17A4B5FD2 -:10CC600003F1C4C9416B112DC7C9A75487E233D35F -:10CC7000FE317BE0651BFDEEF0D7DF34417FD70846 -:10CC80005986651356189D934AD4E3D8C6A8C74958 -:10CC9000A950D73B26AAEBD3A6AAEB5D77ABCB195D -:10CCA000B3D5E58982DFA8CCB196D279B02A628962 -:10CCB0007EBC9C24217EDE02FC5B0A642FE0C75C04 -:10CCC000BBFDEC5C5A9F09F284C24F8690D0D3948E -:10CCD0009E87737EE889523C1B531A3CF6A2EEF8FD -:10CCE000C8CC36DD0CF4B2F6556C84B6B7BEFBD1B9 -:10CCF0009730BE95C4B5CB03FCF84E037DE1CF451C -:10CD0000E149847F7800DF0D7FFE11E8BD133A2FE3 -:10CD1000E03BB356C1EF3F3CD513D2E5B1E684B654 -:10CD20004FE2ED934C6B3B7443E8F3DDD58B7449D4 -:10CD3000DDF19A461A245897943F505F902A82FA60 -:10CD4000E221995403DFD0E54A603C1B74A072E6EF -:10CD5000C61403F2CDDFB97EA59C26437D9A8D8D46 -:10CD60006970CF36C37A5E7994F1FF4A031BA773CB -:10CD70003C0F7E145510C849A35DC6F1C438EB6C56 -:10CD8000BC0D2F3BEDACBCE748CACDB02ED74D4D06 -:10CD900019067C62944900C64BCE32F906D0F99947 -:10CDA0005F3304253A68B2428EE853687B0BB9C7FB -:10CDB0004FE1D870CC12D4D1F7E639FF61A34826F1 -:10CDC000857606F79E15DEDF831C8855298847B3D4 -:10CDD000B3D536AC88CD2148E14B817F50F958D688 -:10CDE000AFCD06F43497B5A2FE3617B7B6029E361D -:10CDF0004C94D19E48992D233F9BB3C327FAD2F779 -:10CE0000FA39B20DC64BA18ADD4007793CABD5EFAC -:10CE1000877129CEE552C62A302ECE907E2795E323 -:10CE2000D5E1D87BBF44C74985F186B0F680273B62 -:10CE3000C793D7EE41B81D7CDCD4BEB4FD10364E8E -:10CE40007369D738828E1B2A4908E013DF15E37413 -:10CE50008E4F7C12C855FD6F28DE289DA41C13023E -:10CE6000B772010919F3003FFE86ADB8AEAD641B81 -:10CE7000AC17475639F051C6B18D93E521D0CF821A -:10CE8000DFD1CF2121E0E30C8598AE4F01FBC58FA8 -:10CE900078D4AE57F791D629748D74D245BB7EDD18 -:10CEA0000A69D1A5745FC76E87A3BC60480FEB59B0 -:10CEB000B35EDCC762F702D36BD7F596844BC580AF -:10CEC0001712DF5EF7ED659D2E7C623C102B9DEA0C -:10CED000098AFA1CCDF708F9CA086589C89EAFFB14 -:10CEE00080DCB7F3F540F5155DAC7B86D9C65A6199 -:10CEF0009D2E22C85FE52FACBDF33774BCCFFB1964 -:10CF00006CA057B28FB576807E24FB02FD810E9B0C -:10CF100094C04F1268FDA693E904E4F66A339906BB -:10CF2000FCAD703ED7EA97957CDD7840CFB9FEF92D -:10CF3000A7B007C37DD306D9E8DA5BF9D8E1632649 -:10CF4000E77FA39D45FAA39D9575A4A3D10ADF6F42 -:10CF50002D6F3151FC9A5F67ED9B6939A800FE6A1D -:10CF600072611D1ECE9E8B7852DE3612E0D3C13A1E -:10CF70005F08CAE41D3301F9BBE3B9BBAB3D207FB9 -:10CF8000D22678400EADE3EBBDCD2EF5882FC5E05F -:10CF90000B803DA17DFF08E017E9E93F5B45E938DB -:10CFA000F8290359432B0BE5992D79B02E5653F9E7 -:10CFB0004B6B67EA3C753F96BAE8F30B73D9763B47 -:10CFC000EC3B969B48C048E775452201BA38B31D33 -:10CFD0006F9481FCC9211109F46C4E03357881AF3F -:10CFE000965848208EDFB3AE28D8FE1766DF763B12 -:10CFF00097FF262A07F4EC9FE4E7297E52E560328A -:10D000000AEC17FD2ECBFB203788A3C2D7B9DFC8A7 -:10D0100007FEA57A9F7E6F0F9FBF9EE2503F8CFE5A -:10D02000679523C621DDDB3FCFF1A398AC11909724 -:10D030008AF5F849942F36E5427C3B5388E91B5228 -:10D040004342FD2486172CFFC086E54C2A7F8DC302 -:10D05000D0EE0F1A01CE24B6FF203E9FC79106EBFB -:10D06000852092B34CA4C544DB21B7D3F5E6261D39 -:10D0700066B49B8F100FAC078A31FB9904145904D6 -:10D08000F0BA8990CAF875209E0536462765A90E24 -:10D09000F74B835E36233CFA061232833D04B051CF -:10D0A0007C2B4B484881FDD65203B62BB079B09FFC -:10D0B0008134A03DBBFBCBF732404E5B8E527B6C84 -:10D0C00028D059463965B1A8D71F218D88A7D39C90 -:10D0D0003F362FB7219D3BF7678137399DA38DA040 -:10D0E0002F7296A4A8E82BDA655DC92481E1F1E3EB -:10D0F0008670DCACBE47245204F53958BF79B9E7D5 -:10D100005BC6CFEF657C37F251EFE36761FDE6C8A0 -:10D110009BF6EF51546C8A1DB1FB3D5DF6B516CF01 -:10D12000594BD47279E83E7559E0C5ACF7392651B0 -:10D130009C9BEF95BD5BE978D79C54B7ABCCFB03C8 -:10D14000EE6FBBDA471C53A03DDD7F6FA56FAF3D8F -:10D15000AB6EEF2F7BC50EEBB8AB3D83EF862BEAB2 -:10D16000765AFA68E1A570396F8B836BACC9A8AAAF -:10D170009F56D50D2EE71D7170DDE852B70F34F6BE -:10D180000CD7CD85C66F844BB4BB75E4D5B5D3CE73 -:10D19000634AA5B117BCB3F6774CBBBA71EFAAFED0 -:10D1A000E676F72CD57E2788FC7EB3E4BB26853E49 -:10D1B00067C22BB017AD16B47BB5FCB29DEBA7EBE5 -:10D1C000C19EA34F7FA2EF7AE83706D61D2D1B76AE -:10D1D000FEF14E902FC79E1D980E723D13F41CE277 -:10D1E00093F915F6D4B8D0AF3095AF53AA4F9A4102 -:10D1F0005EECD941FB2531B8E2EDA7D41AB6AFB049 -:10D200009118AE67612FA5109BC4F6E3CCDEE9ED63 -:10D210003BDAF11BED0CEE594BC7920FE83A7CDE7E -:10D22000602B53607FB645427B6056854F9748F927 -:10D2300063748B847EA3590FFC6038C89551A73D59 -:10D24000FBA2F4FDAC90DD0B9FADEB20BE10E5AB77 -:10D2500074DDA2E21FD1E71387A9FDC3CB8B80DF6A -:10D26000AC3E0FEC37AA00223ACE057D43B10DE467 -:10D27000E6F7AD3E909B55537D6FE17CFF41AD12CB -:10D28000DA6E0E9B3A79A16D92C143ED8CAABB3D3B -:10D2900023C1EEA90A9B7DF83411C542E75145ED43 -:10D2A0003178A61B886286A78598E059BA82D95F33 -:10D2B0004923FD862AFAFDAAF69FFE05FACD5322E0 -:10D2C00087983D19C27957B5BFF657B0D7E6F8FC35 -:10D2D000069017837618984DCAF96170585D0679E3 -:10D2E000105F2E8EA8CBC38FA9CB7F4A61F83D205B -:10D2F0008506017D0E500507FBE2E06E23EA8BC335 -:10D30000078D489F85E72D5BC1FF3476A115E5FAAF -:10D31000F99F99D11F75400E3F0BE5E0B309B8AFF7 -:10D320003EF4F68152899617FC225186FA17BFD433 -:10D33000219E613A7AFA7EE1B303B6AEA1EF170EF1 -:10D340000F97DAE8FBE70712D201F54A6808CCEF3D -:10D35000F9AF74387E6CA731B48DF2C3F9FD3F7D0F -:10D36000F641FAFDF33B3353244A976B411FD076C5 -:10D37000A39F3259609F31FAFCAE3E202F16EE304B -:10D38000AAE6B53545E2FB194F12F05B6FFEC453B8 -:10D39000AB7F8AFD0BCF9E447E3BA00FCA1698FF41 -:10D3A0006AC65FDAF63B52D87A127040BF3C4A9F99 -:10D3B000CB1F59EE013F5AFFF56AFC0E08A9CB615D -:10D3C0000ED74C12F73E0FC6CB5FE5023B752B41E3 -:10D3D0007BA6F0ECBB77E6811D6D64F683168EFDAF -:10D3E0001C8E9FFD8C8EC3E4838ED9CF74C6743D92 -:10D3F0002EE47CFCA2C4EC57FAB72493F2ED425021 -:10D40000FCF95DEF176AE010E3DFCBC777F07D75BD -:10D41000EC751DD2E3DCF2EAE1A7FB7587E7CCF2FD -:10D42000860115FAAEF2DCF58B8EBA69BF9A3D4ED5 -:10D43000DC278AF7353B5F4EBB8BBEBFB043F18222 -:10D44000E95A33FD99474643BB9DBA30C00BF53EC0 -:10D450003ADF0BE15792A0DDDC4DF661BA383ACCE9 -:10D460005B7FEF808A3879F85DD78358BF357C7F42 -:10D47000FBC2C88EF199C0DFEB252F345B18BE6D5F -:10D48000CA2D60AB6CD279FBD1FA5285F875C370A6 -:10D49000EB3D159E357B9E3B9A41EBEB0F8E28852D -:10D4A00079AD91FD370F06FEDFA2473F96162F9FFD -:10D4B000707AD3FE1199F65F73BBB53A64C5718F6C -:10D4C00040F970E1361DF8D993CE52F9C4DE9F942D -:10D4D000E99A3CDBBE7208F8130FE8AD2DC0E707F0 -:10D4E00012191D82BB7528E74984CD6334F71B2FC1 -:10D4F000FC539B41A1CFB367572495B17584F205C6 -:10D5000084B283CEAFFAA9C1B8EEE6AD57AF13D15E -:10D510004EC03B3FA4AED7F2474AAA5857A4309E0C -:10D52000CFB4ED5227060DB0AE6A9652791C67FF54 -:10D53000D49C6E3580DDA4FD0E588044D05587FC08 -:10D54000493C385F339B2F35594D74BEE7E05FCCC3 -:10D55000EF2DC1BE7C818453240B07920A0FC5E7CF -:10D56000C2C9A4129E07A4C8233A2ECFD0FFBE3B47 -:10D5700001E5D9055BF499FF04FEDB95ED0DD2AA18 -:10D580000CEE97BBE08924A5D0E7655817C07F361D -:10D59000565ED04EE5395DDFE72F1A50AE37865F15 -:10D5A0004E027A5D78D62CCB942EE7F7A496833F73 -:10D5B000E742F8374930AF73E1D472F0CBF5266F0C -:10D5C000B4724AE8F3F7E19FA3A89D96EA1B960A76 -:10D5D000FB9DE65430C6497A6A4371430FEB5FF412 -:10D5E00073181A8A3D2037BE6FF5C2FABC21D5C325 -:10D5F000F486C4C6833F1FADFFE458EA36A0FFB1EE -:10D600004305C9A0E73F219E6490BFB739FDE5A956 -:10D61000B4BDABBCC3A703FFDF04E26DA27D3ED067 -:10D6200079EFB3513CCF2654EFC0B32460407F491B -:10D63000B313E19AA5908842F97416E8C5215846BB -:10D640003CCFDA24859A281CB3D7AAE739B7CDD8BE -:10D65000455FFADF7C4205232CA04D71EDE8F8F31D -:10D6600041FF51FC2D309148021D77C17675BF8571 -:10D670002482F0D4ECFADAD8131EFFC2F1789BD3DF -:10D680007757AA4A7EE9517E2D24FEEBE1BB0BB908 -:10D690009E9D633C8470D43FF0C080D9D46EB8BCEA -:10D6A000F4C101B353C10FC8FA91F512F2DFC20AF7 -:10D6B00012C9A6702D6C972283C10E7893D1478C26 -:10D6C0004FB6B07677723B650EC507E8FDD1BBA4B7 -:10D6D0006022DDC7CC31D12D18C80F3E2FA84FA630 -:10D6E000E56AD28AF3A9255184E37E4E3F8848013A -:10D6F0003EFFF226A3DBE8EAAD3A00EAD8A1528C5D -:10D70000CB7D4ABC483F6A4F10734A77FE007CFBD2 -:10D71000E2F053BD495D26DBE3CAF9804F5A8EC360 -:10D7200073DDDEAF8DBE1EF0FB44A73E090D9834BD -:10D730009874B357DFE3F87FE2B6B96E58FF8F8273 -:10D74000FD96C1071809F292087F44C444C7B70C7C -:10D75000272AFF04B58BB0DCF6F86B37ADCF226417 -:10D760009D3E807EFE593AFF5108497DE60CAC078C -:10D77000BACE927D390ACA015F01EE5397327A3CE4 -:10D7800039AC6140430FFB5301FF3A291C91411E04 -:10D79000EC67FA3DB124A60FC4ADAF5F72F9967C79 -:10D7A000387A3413F8E63909FDE91B24D22C513CB0 -:10D7B000BB2859400F6C90DE3F0A7A63C34D1ED2DE -:10D7C00044EB4BF64E5AF40AEE712D5E884FD4EEC0 -:10D7D0002DD3D55A71FECCCE4C68D82AD3FAF47B1F -:10D7E0000A87C1FAA0F3BE67327DFF02A7B7DBCA82 -:10D7F000F8C1B52298B718FCA987FD8B5E81753DED -:10D80000D8827EAB748AABC4147CB680FDE8228DCE -:10D8100012B45BE594901EABAAC8B45F1621D7285A -:10D82000C929EC79923E258534831F365DA1F628FF -:10D830007BDF0CDF792289C1E59475F74C027B7898 -:10D84000182BA72C937CDB90F91F437CA51B492543 -:10D85000CC1BDE83FD4CC1F0EDC1FA10C29D3EB67B -:10D86000A118E048EFC39E0E43240BC6392EF8A43E -:10D87000DD2D839C5EC2F5ED923D65E929B4FFF193 -:10D880000B2605E4E77197B0FF2256B0FF48DF4250 -:10D89000D69EEBB525C563D381EF1D39EA7697F5A2 -:10D8A000BEE4E1A01F4EE8304EF399D5976CA7ED8A -:10D8B000AE35B07968E97F96D3B5FE8A444271FBF4 -:10D8C000FDFA699FA35D5D7F4551BDBFB0DC444259 -:10D8D00071FBFD9AEAC3E3A15D2DE95805FC581BD5 -:10D8E0004E20A1B8F571ADA5E7EF8A75517F454788 -:10D8F00082C391EDB3C02F795C1F5B3507F8F0A0B0 -:10D9000084FEA37ABA8F0EC6C375259504537B8215 -:10D91000334DFD9ECE4755DEF705B62323A349F0D0 -:10D920009D4BB668929DCF0FDA097D77392407F5B4 -:10D9300043312EC8F41EF875ACCCAE9D04F455628C -:10D94000499313BBC615F5305E4ADC3C2F4D33902E -:10D9500008D22586DF05BC05FB13B2B1FD63830742 -:10D96000F47FFB21C49BE09778FC05E3E3444D1D65 -:10D970001199CA8A7C876D4DD100CA7A87855C4827 -:10D9800059037EC9349DAC921309259D7203C5D4F9 -:10D990001310B5423993BAA6624C7C99B5EFEAEF01 -:10D9A00098007ECF9222D6BFC8E1FCAF157DE17D05 -:10D9B0002B93BB4A2CC79F18573669CA565A1E1C50 -:10D9C00057B669EA1D9A7A97A69CC5DA5F488CE437 -:10D9D000E8BC54DF3BDC13142A2F2FB82333E80EA6 -:10D9E00096AC6DCA9C5041E5586D09D3C775ED9250 -:10D9F000177D751C7F755E66275ABD51C3AC22C06A -:10DA000043C751902B35FB249B44D78135BC2782DB -:10DA100065E8E789EB1796B05F4DF87DECD7EBF83A -:10DA20008532AEF33585A758BBF087A8F757355731 -:10DA3000613C5DC48B75C4EFCB94BAE2C542BE5E57 -:10DA400072FB5E96195FDBE2F74FF5306E9C9F46E6 -:10DA5000B47F6770FB1FC0AC4858F27123D8AF7F0A -:10DA6000AAFD7004D873EF40935120AF4303E0BB8D -:10DA70001B496000E8C9EFD7F63B24D376EFE9A352 -:10DA80009B2126769FA318F1F75E62345BA2326673 -:10DA900069DBB5ACEC8C6E067CFEB66D0C2B674773 -:10DAA000B3655A5EE698C7CAFDA29BA1BCBD6DF2E4 -:10DAB0000485E2FBBDC1D16C1DED9F1F9C32A1828C -:10DAC000D63F6DEB793DD73A981C11F0FD57BEAFAC -:10DAD000DA01F3A961FA6733B5374D545ECE587059 -:10DAE0006EF7D3140F337E988072ECE90B53263017 -:10DAF0007B3CE8574AC1DFCAFE503FA29C57D03E4C -:10DB000071834E4CE9A247624E8707F5C7C0863D38 -:10DB10006067A4CF2842FDE14DF5FD0EBE2B9EF7B8 -:10DB200067B0E7EF1C3626B77532C69FD31F4C444B -:10DB30007BEC51339B0F5D37485F2BA7C70A07F378 -:10DB40004BAF70303FEAF4D47138CEDB926F8389EB -:10DB5000E2FD6D3D099A41CECEB7A0FD7CD7562A95 -:10DB60003792C18FCFE06E7BCC1D82F8F95D12F148 -:10DB7000835C11F2A3CDEE73A7C4ED43DA8A69D9B1 -:10DB8000DAB5EF6C9BE4735B1CF04C9321CE22E47E -:10DB9000525B1EEB27F4517A13FB4EFAA303B6C176 -:10DBA0003C1214E62F9A33AD605B23DA03937FE7D0 -:10DBB000007BD9E77383DFE1F4FC7C19FC48823EEB -:10DBC000E7F37D9BA0FE4EEE87177412F4FC1D9FB9 -:10DBD000F72C1DB527E87C8F3B03381EB52F8670C8 -:10DBE0007F15DA17BF03DD1E875FA24447C0FBFF26 -:10DBF0008FF07408E8FEAFE2A976299517F255C8B0 -:10DC00000B8EBF7552449FCEE405EE9FE13DE89D2B -:10DC1000CDA9813FC0F8E2FB331EAC457B52C095D5 -:10DC200070FF0B957790EEEB4C6BEFFD19E81567E5 -:10DC3000977A85DF917FE7BDB74D186778CF10469B -:10DC4000B9F91EDDFF34827CE171F2D21F2E3C0E49 -:10DC5000FB3F31EE38A70EC75B2DF9DC30BFD59402 -:10DC6000EE26807F9201ED7FA157DBECA10D90A7FE -:10DC7000D0765B16E6295C262C1F24B83401DB5DC8 -:10DC80002B9F22E0C78C8DB2619C9AF209D6B74DCA -:10DC90002FC07C11CA0F4133D4537E82BCBAB66206 -:10DCA0003A21186FFA40AC87FD31EE6BA79B70BC30 -:10DCB0001EF884F985FBB37C88B63CCE87F3F391DC -:10DCC0000FD39A98FF9128BE2193E2F47C9E93F99A -:10DCD0007D124AA2CFFD2FE0F9B566B46741C76255 -:10DCE0000CA7351DC7A3F4B738991F00F96CF623AC -:10DCF000893CFFCC5B0A787D2891F1E526338B2F98 -:10DD00006DA2F633CA45CEBF22EF2DC0EDBC68B57B -:10DD10009C04F682CBD9E95FF0C17E1FFDDBB47EA7 -:10DD200066547A1FF66B3383BA8811F65F2DE37C55 -:10DD3000D1B8FD0BFC417CEE1E2E57C97A827EBF06 -:10DD40007BA05F128C6F498278E43DD01FFCABCB87 -:10DD5000C6A9E26E039D6C7D0BF8B4727FA093C9D7 -:10DD6000490AB72FFE3B627CED7874FF39C8E9445D -:10DD70003C4792611FD1A8433A6AE18CAE677EEAC4 -:10DD8000E8FA5CE43B315E6F70FE5917BB57A27A2C -:10DD900070EE58B62F17FB9E397CDF4C96A9F775AD -:10DDA000E057E92CEBBA97B5FB4488A7ABDB33BB54 -:10DDB00025A12866C0388B4752C12FF0D51B1E26DF -:10DDC0007D47BC09BDF7A499CAD314D87E4BC8B708 -:10DDD000EB1F48403DE6308406005FDDEDF460BB9C -:10DDE0008D90D7827A95ED973F3D2EFC1CEA7D728F -:10DDF000BD25B605F0556F61EBE8D2C1445C07A4C0 -:10DE00006F7406E4855D3E6024C0BF7552B400D6D1 -:10DE1000F525C95785ED1A133CB09E3E903B10DFA7 -:10DE2000F580410A577DF0EF988F54BF4FBD6FBE0C -:10DE300044FFABA6FC7E498E96C238421EC0FA470C -:10DE4000BBA89AC569EA6412847DD5B5F2CCF9A85D -:10DE5000FFA767906DF8FEFD02D84709394FDB1D1B -:10DE6000915218DBC07AA9E1F8AB934F61BB1AC895 -:10DE70002B023CC2FE0AFC615019E7C7AD5B7B1E5A -:10DE8000F39AEAF6AAE95CD3C507D2D712F48BE37A -:10DE90000B5CC741A41BDAD9B0EE2B589C39919783 -:10DEA000132A3B30CFA99EFB3B9C87A3E3419E24D2 -:10DEB0009684C94CFAAC3FCBEC8CD1ED5B5F867D90 -:10DEC000B4BDB2231BD8BF9EFB03059D059CA3DAFE -:10DED0001F43FF86B04FE2F6990326ABFC0C2BB034 -:10DEE0001FEC5BE17B5178E506F233BDB68EEBB5F6 -:10DEF00004D80083FE6BED8FFA0FF413C825B1EF41 -:10DF0000053905F2E13367F94F418EAD4D2BDFC680 -:10DF1000E419E52FB0E761B334AA773F9EC08F685C -:10DF200007FBDF6FF2D3FD92F3ABC3C0E52E617E3A -:10DF3000B9C5AF39855F0EE36F8B254F3AF0EB190A -:10DF40005D00FD6FF34810FD42F3C1EF459F357C46 -:10DF50009DCFE5FEA4B9DC8F047EDDF83821F857AB -:10DF6000E3CB0B08E35FB2C3D8953F037E9F0A1251 -:10DF700049A4E3D5825F0A9E6175BF3A12637CBFF4 -:10DF8000EF6BA32A0ED9C6E67D0FA7BFBD22A4035F -:10DF9000F9B0C1CCFC51426E8C5EC6FC56C9C37C44 -:10DFA000792B81CF5FD3A33FE37F73BA093CDDE6D2 -:10DFB0002CDF05F8B7C03E0DDAAD34A2BC3C4DF500 -:10DFC000F01EEE47990CFBCFE5810190FF4D145BED -:10DFD0004EFCFE543CD71C305703FFFC89EB31F15B -:10DFE000FE31A79EF9E15730FE8D3526A0BD4DC507 -:10DFF000C610E0AFD27CA10FC910F06BBDAF677E39 -:10E00000E0BADBAD01182F2A3339738ECBB3734ED0 -:10E01000967F27CA9DFB3BCE3F22BE077E9E78FFA0 -:10E02000FAC79DED1FE37624C1F9AE9BCFF3B73B52 -:10E03000F95846799450E447B97BAD5C8EF228F6E6 -:10E0400091D50378A93C5F331FE6F1C9340B8138C1 -:10E05000DB6CEEEF95D2EC0887F0EF7E5BFCAB72E9 -:10E06000CD009493A23DC472A1BFD64F7C80CBB1AA -:10E070000384C11B6C3632BF3C87FFC0D98121E0CD -:10E08000636AD70641CEC5F69899BEA37628C8D74D -:10E09000037BFB87603EEFEB99BD10A4F297F50F71 -:10E0A0006C003FC8815F3ABD90D753BFE0DC10B031 -:10E0B0001F0F9CFDD9AF7E0BEF0F1ABDB0DF3BC029 -:10E0C000FDF235864801DACB3C9FB1262952007E0D -:10E0D0009F1739BD6A2CB44CDF579802D96923BA0F -:10E0E000E267D00FDE9F0A31BBFC14617C105CCB71 -:10E0F000E29C14BF6E8023B63A1DE36F302FA0C39D -:10E1000007070723DCEBF4BCFDC3CC7E3BC5CBA7E4 -:10E11000F617637EDF65BF01F371EB1F65F6E22C36 -:10E12000D9B36529C8CA9712D0CF38A7ED04C64322 -:10E13000EA1F993711EAEB172CFB1EF9863801E824 -:10E140009578FFF62512CBC17D70757E3842BF7B76 -:10E15000A97D809785FB5C185CAAE3799FA7297E3F -:10E1600001EED8413DE2FF6AC747876129D36FE8D6 -:10E170000F8F8FC7A03E50C767BEAD7C491F2D785B -:10E18000807E3F9812B835CDC9C41DD0BDFE25375D -:10E19000CABB0F1EFE2207ED8956164F38ADF7CDCC -:10E1A000807562AF881866C6D95FF3D2F8BEC3C85F -:10E1B000ED462A07E3D7BDA82F2D57AF33F19C9B1F -:10E1C000C6ECC9441EFFEF5E2FF25EA718417F32F6 -:10E1D00097128CEBC17173795C6EF4D9D821C8A306 -:10E1E000AA091763DC2F775904D725C57704ECFFFC -:10E1F000D31B12993CA1D38471E68E2468B7CED587 -:10E20000B17C86B9466A07333D8EEDCF6C48473CFA -:10E2100094AE60F65FEC3909E5A2884F5611D6FF3F -:10E2200085E6F7833ADABE6A87544C452BA96A2EF5 -:10E23000C37C87059BF290FEA3B9FC9D65F4156C29 -:10E24000007E7B2111F98D7E0FEDED1AC8E91A864B -:10E2500072C900FAB07A8744D690F878AA860F423D -:10E26000EA78CCE83093DFA037489C9D26F410E88C -:10E270000BA2B11FD57C11E4712A469FC701AF23C1 -:10E28000BAE43F62EC1BF420B5A3DB601D9796B3A4 -:10E29000F516DB23219E6B49038B1F713DD4090FBB -:10E2A000D76367744C6FCE353E86CF9D697908C7BA -:10E2B0000288B360DC206600B9D81B5FECEC852FC8 -:10E2C000043FFC8CCFA3E62C895C47BF57B38C443A -:10E2D0006A87B067E210D4CB4C3F9B987E86A7E557 -:10E2E0002AF4B4563F6BF5B1560FA71B98BE157CA8 -:10E2F00010EF97077B64F4B2908EF95FB36C90C710 -:10E3000027E8323DD57730C3D9656FD59F34993C26 -:10E3100043A1EC27F956F02B95556681DF9ACA6F19 -:10E32000587709144F5BE9FBCDDC2E1F91C5E6EF52 -:10E33000E2F93A7AC54F8AAD40A70EDC47C79C0484 -:10E34000F7B502BF9B1369BF61D08FADC7CEFE2664 -:10E35000D26C89EB5F7EC08CFAE4F3FD89985F4252 -:10E36000F543AE9D8E97F60EB5CF69F9D28144D4B0 -:10E37000EF97B8BC77087F055985F4FD13A7739014 -:10E38000946782DF9748133241440ABBB1D6DE9BC3 -:10E390009F9ED7E775DCCEF8CC887AF6737BF43E87 -:10E3A000285378301FF80F5C2ED4EF1D5BFC20E45F -:10E3B00001F8AD5E86D54031D80D46DD92DBC11F38 -:10E3C000345EB72CF6009D476DB615F38C2B72DFCB -:10E3D000FDE3745AFE68AF9E1881EE4F4F498E40A0 -:10E3E00037C5E7EA493FCF0FE955E7D816EE509712 -:10E3F0006BC3EA723D893BE74651B0F4DDE2EB8F37 -:10E40000C4F1C95769898E338308C8142FE44913AE -:10E41000DDDDC9811EE4A5787EB1DC7BFD113DE622 -:10E4200099E9D3591E8D01EC9A99C00F3DF46B4FB9 -:10E4300063768DD1D87016F2D58D2F1ABD8DB4D7D5 -:10E4400089B44012F4AF936347819EC6DC0B43400E -:10E450000F96E7FE03E3679FFF8878013F9F9BCB02 -:10E46000D0BEF97C83D903FBB2B61C2BF357BC2476 -:10E47000852466BF4F1C510AF1529C03A95F7FD3CC -:10E4800047EC700531C9485FBA7B71819CF1E17E30 -:10E49000EACC248B6D05ED57BD9EE9DB1AD29104C1 -:10E4A00072604A3AA79F6E97C144FF99D7EC1BD080 -:10E4B00048E15DE8B7E0B91AE54BC50FFCF5100C73 -:10E4C0001967FF0F4C67F2A0D6143594C1F7FF31DE -:10E4D000BBD299DFE5DF32E8997F4BD9571CC9A43D -:10E4E0005DE72D9D85FB9CCEF8F30696CF34EF813A -:10E4F0002A7CFFF20623CEEFCC4109F9FCCC66362C -:10E50000FF79EBCD1EC8BBBEC1CEF6B3F368BF9E8C -:10E51000E77FE34730AF0F37DDEF05FFFC87847DF2 -:10E520002768637EA80F6D2C4E0E6D619C0FF7F669 -:10E53000413BA67AFDFC899867B659E7053B821CEA -:10E540004C44FFCEBCCDF7FE7614F88F26DF59027F -:10E5500078B8C1BE240DFC25B49D3FC4EC6296BFC3 -:10E560009B32F2195887377C39B6E306B09736D319 -:10E570007592C7F2E3C14E3FB2F946B44BE74DB2D4 -:10E58000D8615E9E4D4F8F07FDF1E1A40C19E7B3F2 -:10E590005B2236C0837D691ABC9F2729FE9EF8E95D -:10E5A000A334E6672BCBB57A23D0EF0F3AE413BA46 -:10E5B000AE6E07FD59BB598F76EF91C96FFF71BAE7 -:10E5C000A36B5DCDD3B5DE3E3ACEEEA9DF748BE012 -:10E5D00013122985FD14C389767D19739715003CA4 -:10E5E000DA75366F4543018B577DB7F54636B1F581 -:10E5F00056932E91AFE5EFB4DE7E90EEBCFAF54671 -:10E60000B25254FBA8EE722D88ED84BFDFE425BE24 -:10E61000A7AD18D7F549E0974B57B07E533ADBCFFB -:10E62000287F5DBCE3755817E9819500472EF115E9 -:10E63000031F7962B672382B64E5761CD9C4EC6688 -:10E64000B0EF81DEEB9CE49935717E87F5E9EC3C17 -:10E650001B5DFF8FC03897DEFAC751A04F5DCE8596 -:10E66000212CDEF919C607ADED2CAE6CF5C630DEF7 -:10E67000AE77F891FF845CAFF732BDA39DD79FD3EF -:10E68000D9F98B7A470CC739E062EB50F8DB372EAB -:10E69000B5A09F74A32364667E852001BD3471A458 -:10E6A0008EC5C5B89D750BF73F9A4A5E26100F239D -:10E6B0006358DED7EB252F2BA9B4FCDB91E3BC78A4 -:10E6C000DEAEE4A9967C98F7183DAFEF138479FF8E -:10E6D000CE5786F58B5D3A0FACEB89252C7F915494 -:10E6E00027A1BFE4F5920F1CB3E3E0F71393C74AE9 -:10E6F000F96432DDE4C4E7DB7D6F8CD9638DE3AF71 -:10E700004F5AA54A66EF7A92A70E66FE10D4C3252B -:10E710006A7C2C7619F0BB6BD3CAF6039E6FB89E49 -:10E72000D1E3DC6E6308E4DF397E7E458BBF63E9AD -:10E73000DCCF7A77A12A3EEF308473403F9E97D496 -:10E74000FD16B4E8303E3EBF452221FABD733B5F63 -:10E75000C80139FED1D32FE4CC8C8347DB4F3CDF9B -:10E760004857FB01B57EDDDEFCB9A2DDE5F524608E -:10E77000EAD3D5FE72F5DFD09F3BB39DFB837DBE10 -:10E78000BE0ED807F1F6DAF1FECEF943DA27A1BFC3 -:10E7900043F8334F1D7B0A22279DF433B7E7C9F1B5 -:10E7A000F98AE2399AD36D0AD08D4EC5DCC2CABD52 -:10E7B000D1ABB7F5F8643A8343D0ED544B9F64C0B6 -:10E7C000A3A1CEAA10768EAC10ECF4CDC4E285F5F0 -:10E7D00064C87059417E8973F85F98D9D361A14F9D -:10E7E0006AAF65671462BFFB653FE6C57D21B7E28E -:10E7F00039C2FB750D986FFD15FF5E96CDBF672E74 -:10E80000EE4FC2987F4D5AD4F84D6B62FA2356658D -:10E81000403D25F07CEDCCFB709FDA037DD603DF15 -:10E82000648C64EFAE71E571BF4614E304E691C4F5 -:10E8300006FBF9A651418447D0A79E352752BB84D9 -:10E840007632E4B524A4603C34C89FC49A423AE3CB -:10E8500003097C5F4B34F1002AB682D04EC00962B6 -:10E860000CF2631EB5875B0B4A309E8AF6278C0B31 -:10E87000EF671629E84F87768661DFCE6F9D7CC9EA -:10E88000F30C278AF7D5961EE30F13E1BC0E6D9F9C -:10E890004DF520D87FC4AB579DD7D944ED66D88FAE -:10E8A00089F8AE4E0E17BB701FD21105FF88A1D498 -:10E8B000E401BD9AA00B1702DDB4F15EDA2E8FE5FC -:10E8C0001964D941AF88F338754BC7FA21DFBDD33E -:10E8D000CE38C8F647750F94E1FBB1EDCC7F5EDF13 -:10E8E00062C4F384F5FB248C57D5F90D2113FA315A -:10E8F0003C8D40AF20B5C360DFD86667F9516D37F6 -:10E90000D9BC4112EFBF8E6E7910FDD7568CD3FD66 -:10E91000B3F1CBCB89140143E3E253C926A647B830 -:10E920007F3B8DF393A0BF58CF22DE9958E4CF03ED -:10E930008BFBD7EB66FFC6E2FC2E7921D73E0C7924 -:10E940001FBDE7851CBD05F2464C60CDF37A008BF8 -:10E95000EACDCEF375660FC6B53AEBE15E04D33E61 -:10E9600089F7FFC12DE3FA62FE283F5F77DD5AC8C1 -:10E97000637ED44C54DF8B874FD18CAFA7E35B3DD4 -:10E98000A2FD3D378F5330BECBCB2FFDD847E17F63 -:10E9900054AF1E0F59509C0734757DAF3233E1E1FF -:10E9A000B563BAF437D5E7CB5DCE2E3DFED0DB1391 -:10E9B0005B877A607D7D8AF9B8421FD73B589E8875 -:10E9C000566EAD7149C2FE1D0F2A76D5B42ABC47DA -:10E9D000A033BEDB3EC907F72988F86EFD323FE65B -:10E9E000E582FE77A1FEBF70E61001FBF21CDAFFA4 -:10E9F000F55714E60FA2768444F9D0D45E867E4F94 -:10EA0000483705BD29E8BF80EB25B0D581BFEB377E -:10EA1000DDF1B40EEC6597EF491C97EF03B5F08676 -:10EA20005DCC5EAF2F2CDF00F2806C9708E8ED35EF -:10EA3000859FA09D51B77FDC88F8BCF2F9FB9E60F2 -:10EA400079C93BF43DCE3FECD2A17CABDBFF1CFA95 -:10EA500033CF85D871966A25B47A34F855AA65B053 -:10EA6000B44849A86A3AEAFF69741EE03704BD0356 -:10EA700076CA8E2941C873AFA7FF01CA36FAE7A24A -:10EA8000BDBF719AC90AF19AFAC2998B703DD82C10 -:10EA90003E98BF16CECEF8F00316F437AED9A7AF26 -:10EAA00004BBA994DA49BFA2F066A74CA8F452B9F6 -:10EAB00094A9DB53FC032BC4D57BD6C35333981ED8 -:10EAC0006E96FCC15B4B300F92C4E7E9E4EE63F64F -:10EAD000D8AB2E66BF89F7AF42E223C5E79860C77F -:10EAE00058E0B997946802D8C5F5C4F731EC73893A -:10EAF000DFEA8171E02606B0B31CCB3DE8CF3539A3 -:10EB0000A23F1E8A769382FB0CB18FB8B49FF9BFE7 -:10EB100046B9036F021D4B75D1C76F05BCFD989DAB -:10EB2000F3250A93373953ACC3C05F6576441FAFF2 -:10EB3000F4607E0DFA1F92AF6B463ABCE42036C0FB -:10EB4000CFD8609522C5E9192137C6769EA771A056 -:10EB50009FB49C8B977E945A674CC8A2CD5FA776D2 -:10EB6000D905C7FE31558197C25E904D01DCCF5467 -:10EB70004CA3FB43E0CB55B1A332F8E51D1D682F34 -:10EB8000D68625FC4E6DE12F31FF6D21CFB3EACC47 -:10EB90007752A298FF75C995C0F56333E34BD281D4 -:10EBA000FB5FB28BE19FEA4DCC0BEBB2DB1BB19D5F -:10EBB00018CFC0E309B5DC5F431185F57F7589780F -:10EBC000C20AEEAF12796CECBB44F194C6FB17D6C7 -:10EBD0004DA29A04E1F22401BCBF30FB65376D7F82 -:10EBE000AA5A66FEEC9684101C0E5D2775F8C0EFDD -:10EBF000182CEEF91C4CBA5BE279B2B1F1E8EFDF08 -:10EC0000DF5B9E2CCB8BDD306220E69597ECFB78AA -:10EC10003CF007A924B81EA9BCB8AA3CD92C375B84 -:10EC200047FFCFE4C97A25DF36FA1CECB6ABF364B4 -:10EC3000BD8C5E227EA9CD8FBDE48E282C9F2DBA7F -:10EC4000E569D0BBFB8C98273771DFAB27C17F39D3 -:10EC5000D144C218CFD5D80FAFA54E29053A5DBE15 -:10EC60007866CB4A02F9D5CF7B59DE9DDA1EE8CD16 -:10EC7000FEC79846DC3EB1D2FDEFB5FF85BCAEE7DE -:10EC8000FBA9F352EC910298DF419DADA77331B718 -:10EC900089EFF796E7D1DE739E8738775519CD5304 -:10ECA000C5A7EEE91CEFBBC5BB66820FBA87789794 -:10ECB000C2F3B71489890E926D50C5BB147B416FA6 -:10ECC000F1AE08D63FD71FEB1FEA16EF627905CDEC -:10ECD00007D33D60DFD73863CF3CE381F10C384E7A -:10ECE000F3FE8410E4B93773FCD75C7DBCEB41774D -:10ECF0000FF1AEADDC7EFBA0508E18285EB7120679 -:10ED00007FB05DC4BD64DCC7C61ECE16F063FDE5F2 -:10ED10008707A1BF68968867BDC4FC68B378DCEA42 -:10ED200083C90598E7D51B9E67B5A8E3020F039E2C -:10ED30009DE8E7437FFC7DFF3109FD5373C18FDF01 -:10ED4000A7EB1C04E1FE3C4F0B3BDFEED921853CD9 -:10ED50002CAE6292D136B4C9F07E2115A31B41F4CA -:10ED60000629D75C435F4B146BB4DED34CCBD4E89D -:10ED700057562B41176DB7F56402FACF1E72781003 -:10ED8000DE879A597C39B8560AF563E3E2BD61C162 -:10ED900066D907E3EC7633BFD32B6EA6FF3C9AFB14 -:10EDA000089AF53C4ECCBFD748E4083C65893D1F26 -:10EDB000B229953DD90F62BC667D83A90CF09DCD2B -:10EDC000EE27F9DCE09B86FEE59402BC87A839B10A -:10EDD000A1A592D5E39AFDDC1CF363FD750A3348C7 -:10EDE000892705E07DCACDEC1B2D9EE7B4AACBDABE -:10EDF000F88EF6DCD52C12E8EFEED3FD5CD2536E24 -:10EE0000A6FF3E5F93C7E9E2C57849B3DEF3461E2D -:10EE1000F0FB6A76CF506316C39B9CCD9EF9F60A31 -:10EE2000BC0F8ED8B91D4718FCF9D73924580FCD1F -:10EE300076C6B7FF2ADC5A785F771730FCDAD97AC2 -:10EE40006D5E2D8518BE18DC57EB1739FF6F968B5A -:10EE50001F48DE672279D80FE542F0613DAEBB5313 -:10EE60002494C9F2266D283767F27DEE675CCF6D7A -:10EE7000ACCE4F8238E8ACB3ABF0BEA0B153AC0817 -:10EE80007FDD4B66DCC7D52E8BE6003F6BF108D0EB -:10EE90002A429ED2FA990EC2EE996951C7F5B4F191 -:10EEA000DA608A5F8678505D79B400E2464FC81F09 -:10EEB000EC7995C935D4AB75CB62CF809F796A4A1E -:10EEC000C09C41F173E181B7C74B1EEC8EF2EDF2AD -:10EED000C1FE78BE7066B3FABC1659AB8E1B929613 -:10EEE00014762EAD4DFD1ECE27A9FA758B2332BBAD -:10EEF000669D213000ECCE1BAE67791217E7CB047C -:10EF0000E879D14C787C5EC8596F41BC1E28E07608 -:10EF10006F77BAD27680679E172ADAD7025D293DCD -:10EF20006B385D2F3E774D01D0F5C29E6B0A80AEE7 -:10EF3000EBF4AD3E58179F390303011FA7C7F9D162 -:10EF40002E1479B057CB6FA332FE67F5F078819716 -:10EF5000EFA887E12FDE5FF2D23F58BE6AB09D9DD9 -:10EF60004FEDF2D39DC37BB62E5F912590C3BD8D2F -:10EF70007792EF935C261204FBABB43C8AFD4AFF08 -:10EF80002613B00385FDAB857F3AC7DF820CDF4BCC -:10EF90002EC023F7EB56F3B14DA14F999DBD5D42B5 -:10EFA000BFADC9134C1A8DFBAA39C37528577E858E -:10EFB000E72048BB6483FDC9FCED8D587F69DF2CD9 -:10EFC000AC974D9108ECC36A693D94578D51E73574 -:10EFD000EBF71647E2F7BD148E03B09F4970C40CDF -:10EFE000C09F7560575310EB14E6DFAE7310F4AB9F -:10EFF00094EC53EF1345DC76A39FDDE3B2B15DC221 -:10F00000FB9CD20C81BC2CA0AB267E7B7F866F1D27 -:10F01000AC571147BFCDE97B2083E597E5009E8281 -:10F02000190C9F51BD38AFA73E4F78ECD0ED680763 -:10F03000FD85F8937BCE370BA9E2EB73F979CFB955 -:10F04000FCBC27C8E788463EC7976BE2F2CD223D5D -:10F05000E50DC4E59BC5F78BCF378BA8E41A5BFFA2 -:10F06000E9BAC518D7AEA77CBE7458171FD610FED4 -:10F07000B73EF6019E6BD961447F5A0DCF33ADAFD9 -:10F080003E85FB947A3827C3D623CBC7E6F71CD43A -:10F09000D0FD1FE6DB86D5F9A8BB7B951BFF77FC6F -:10F0A000E4FB843CE0EB51CC4BCCA3A65D62EB4788 -:10F0B00003A776DFABF5778B7DEBD5CAA5E3FFC35E -:10F0C00072E9AD7F935CEA1637E81B4BF2FE1BE258 -:10F0D000061F795AD3C095D822317E1DAFB3FA5896 -:10F0E0005C52C7F216B4F15ACF788C430A3FADE9AF -:10F0F000795D68451EB6C7386CEDC144CC23A8F6CF -:10F1000054A39DAD8D4F2E207BC60309FE428EE396 -:10F1100079AC7F351F806476E603E47DC77C0063AD -:10F12000E677884FBE6CFD343510C727E545D460BF -:10F130002FEA3D5FCB99C9F82E81E78D989420B1D5 -:10F14000C7F5EFAD5F7626CB037B99E7193D9A981B -:10F1500080E7F65D0676FEC025B37CA8332E7F6E71 -:10F16000E608D0038C8E3FD97F0781FCC29FE8C39D -:10F17000788E3E586BF582FE127E2631FE83DCCF00 -:10F1800072B5EBA724F3DFBB7EBE4D6E5C2FBE775E -:10F19000B5F1B5F5140771EB4ABB0E7AEBD79B5C62 -:10F1A000B935D33F2113E5966F08C629AE521E2507 -:10F1B0009450790DFA79AFD103FB05133F2743D65D -:10F1C000BA55FBED598F66A3DEBA6866FB07719EE0 -:10F1D00047CC7F66AFF8FEE7ECBBE34EFF6C98CF01 -:10F1E000E9321F9E07782891E995D84E9617A43DDD -:10F1F000D7A2D527E25C86F8DE7DFF667EF8AEF208 -:10F20000B4497CFF5F94A754BFA27FA5D7386CB7E1 -:10F21000FE419E9FD9E1E3F1293CE720E0AAEF609F -:10F22000F9748F674A2A7FF37D5CFE9FCCF4B501A9 -:10F230001D2EBC653241DCB3A484C9CF3ABF15E3AF -:10F24000067561964753B78CE03E5F9C5FCD4B0FD0 -:10F250006C0139F5D0DB56BC77B46EDFD6967CCC2A -:10F260002F08A05D77E92DF6FE445A601B8C5FBF26 -:10F270002CAA8A4F947EFDE9AACA128417F7E90ED8 -:10F28000A3FA5CD0914CB6FF16CF439DF8A5FB12B4 -:10F29000DAEF4235CBDFAE77F86C659857C0FCDF0C -:10F2A000099E0EF45BD7ED452541309914EA1FCC39 -:10F2B00042BEA9DB5B568CF70884CDC578FFCC3BFA -:10F2C00056DC5F5D782023A463FEF2FD006F624987 -:10F2D000E826B02F73E977C0FF7D61CF4DC5E80FF9 -:10F2E000D4AC3BB1DE3ACF83DE650A35495DEB71C4 -:10F2F0009D9EE947A1D77682318B79153C2FB07D51 -:10F30000129963ED2A5B1DEA7CC90519E376023C7C -:10F310003B33591E8988A3E799E8EE33BF3B1FE6CC -:10F32000F138FA249EFF4082A6AEBC87FC6F8FA303 -:10F330000BF84459C4D113AE30FB36DF6640BE48EB -:10F340006C61728350BE00FB7A4CAC632C9CC3EAA8 -:10F35000DB161903F84A06F463FE69F4C743215E1D -:10F3600091AA8C8178C596A5C30E9B1CE03FEAB894 -:10F370000E48E369B595C3D6322FDD7F06F59ED2E0 -:10F380005008FC5FFE073DCB535C9D80FABE2DA765 -:10F3900006F3142FBD6D549DBFD13E8364850BFCD5 -:10F3A00044F92DBFC77841E25EA9C7FCD37E60F463 -:10F3B0008F60EDC1EF94D8D2111C097E9487257619 -:10F3C0007723855E72C1FE5F91C1EE98B58F9DE394 -:10F3D0009ED56A2F37A13C9558BC658C03E5A4B235 -:10F3E000FA6619F6674A23C17BD2B2B2D839817E58 -:10F3F0006D3619E8FEEB2F753DC6D112B2985E85C9 -:10F40000BC374057AD31761442FD22FE27F2DDC4F1 -:10F410007EA853BEF2FBC4853ED2DAB1DDEC57AE16 -:10F420008F3AED780D1FF7D64FF0B7E0E75FEB09A5 -:10F43000DA61BF964C78BE4BF075B3C8DFFF92F926 -:10F440007173793ECDA9357F1FC2EE0F14F1931071 -:10F45000CB83D247576522BEA2D70761DE7BED7210 -:10F460005D11FABFEA709CD5ECBEB3DC963E2B462C -:10F4700096C0D3460005A70E2CCC857519A47CD068 -:10F48000AF073E3897C9F29694D5094837E531BCA5 -:10F49000D99928F634A49BF204A3CF69CEE7227E43 -:10F4A0002BFC94273303A3B39C71E7B2965AD8B9C7 -:10F4B0002C7EDE3771E9DBBBE1BCD316EE2F3EFCC0 -:10F4C000D220FCDD85CF572B12F88D3EB757E5C211 -:10F4D0007E6F1CA76BA2D2416CD678FE3C8CF9B231 -:10F4E000F90759DE9FC2EF4F52563BB6023EBDA907 -:10F4F00001CC0BBEAE39823F59F092ED34C6E5A87F -:10F500005D84E79FCFED97845DA4D28762BFA6DDBF -:10F51000874DCFFAEFB5936667A9F71557BDBF22A0 -:10F52000EA7D66677BB16FD4EE2334FD7BB37F88C1 -:10F530002FA8CA8BB99FE7450BFD9EC165A3C8974D -:10F54000E93CBF4C42663807910CB9AF4CAF63DE63 -:10F55000D07AC9E2053B499B2FD499C7431AFAB325 -:10F560003C9286A1EC5E8A866BE029F289CC904FB2 -:10F57000129FB79AC8F281CC904F42DF37F57ADEFE -:10F58000D9D308DF6FFB914D9C77667EF64AC2E3C4 -:10F590000CDBF03C74ECB62C3C5F33B692F9EF52C6 -:10F5A000FC0619F8F2F9AF743E90BB31BA6EC1BED9 -:10F5B0004AE9EB7383BD65A6F590A7D279DEB98AD7 -:10F5C000F478DE59E43389F86E46FF7512E89FCE71 -:10F5D0003C93FAAE73D0F0DDB6451EF40F77E63DEE -:10F5E0007D9FE03CCB859C31A9E997E463ED92A631 -:10F5F00019D0CE4893033B318EB7B1C38CFE8AAC91 -:10F600007CE4ABA69121BC3F37A5A815FDAF2B53D9 -:10F610007DBBB24674F18F808FAC67F3BF0CE7BC43 -:10F62000A4AEEF5E9EFFB71CB0A7CADB8D8C0F3572 -:10F63000706CECBC6F857E873E0F6531FA7B35F6CA -:10F64000AD781E12FCCEE5B0F87E6FF314FCF86DB9 -:10F6500076BB96BF82E59C3EEF99432C5F49CD5F18 -:10F660008797570E3F4D65C991E57E7C5E364B61AD -:10F670001DE4159963334002FE38BBFE7B700FC753 -:10F68000E5C4580EDCE3F178CE6DB7C23D1D979D01 -:10F69000B1F7A0FC4CF643ACDC2FB605EEF568CF15 -:10F6A0004E6465F85606216F6D926E0D5AF11EADCF -:10F6B000551DA09F4A34F9299AFB07208F12EF4B62 -:10F6C000B0327AA6F33C5652C1ED77882CD17293B2 -:10F6D000BBD80BF90756E2D9DB01F55946764F0145 -:10F6E0006179534DFDF2589E03E77792C5FDCF2413 -:10F6F0001A04FE6DCAB363FF4E79BDD7C8E34EEC62 -:10F70000FB279E63E7CB447E2E21B66CB07BAC1EFC -:10F71000A22A8BFB3B8862CB86F3FA4DC2AFC7CBE4 -:10F72000EF5A027FCF8AB38B4E8CBBBF087FFFE3BB -:10F73000F907FBC27C6F34A8EF4F16CF65394CFE3A -:10F740005EE6F70CB659024A362D9F4C98311EAE34 -:10F750006E9D965A66B0A39DB65307F2C8C9F9C20A -:10F760003E95C167AFF04BF0BB1BE29E3F67404147 -:10F770007F0009B4E9407F3A4FFB310FB0C614CB8C -:10F7800051F2C1AB1FB065431CB0EAFDFB300E98CF -:10F7900071E23DC8DB38A16F1D9B04FA228FDF03A5 -:10F7A00041377E415A3E9A998BFBBECE7B41FB4945 -:10F7B000281F264E65E7562790B082FE171B3B4751 -:10F7C00035BE24CFDB44BF3791E77D8C3FE94F0244 -:10F7D0003FC0F83BA20A8BB7C494F83C0BF1242E2F -:10F7E000BD277E1DDCE4892B13B84F585DBEC5AB29 -:10F7F0002EDF3AF2CBFEF1E564E21B04F37C518A82 -:10F80000E239E4E0286263F362F9843FE3FBB64146 -:10F810002E62CA857C478714847DC1A01732308E42 -:10F82000F2C24882E5B41DA66DA6F8F93F26B338AA -:10F830002DF7738BDF0D823AD0ABCFBF9586F84A98 -:10F84000B3CA284FC1030EFC569A69B2807CD771A7 -:10F85000392FCE6D8F4B32E17DAF4D8BD8EF0D68D8 -:10F86000EFBB6CD2DB0E011D9B3EA273A0DFD99EC5 -:10F870006888C849402F420C8E2E792CF807C6BBE9 -:10F880001EF87E04FB5D27CAE57DE3EF1B6F723235 -:10F89000589B7EA4F0F81CFB7D89C2CEDF9BA0CBD9 -:10F8A0008EB6079B92E03A61F1B16C314FA2F8A09D -:10F8B000BD9B88323B9F95C6CBE29E4D42CA14BC8D -:10F8C000674712ED1AB1FC246F27B5BFFA57E08FD6 -:10F8D000BE49743EF4D994CDE4C453F289F5C827E7 -:10F8E000D68007F8C49BD0F379A1BA6CB66EC62552 -:10F8F0008D7441DE4093DBEB02BB4AE0A7F33D1F72 -:10F9000057D48BEF79537B1EB7898F1BE6E78DB5F4 -:10F91000F53FCA66765BE7F87A3AAEF51BBEEB5464 -:10F920007FB7ABBEB77EECBD688F3F07550AEB8C47 -:10F93000E16D02CF732585EAFC1432D26B62F25E70 -:10F940009D8F72A3B4CC0DEBF326536D7B94F67FA1 -:10F9500095F3C98D72E0338837BC3AA3E008ACCF89 -:10F960004AB8D09E8E733389AC0266B95C16F889AA -:10F97000BD0FCA8B75208FEA7481FE29B47C51DFDC -:10F98000DA77511EAEAF27B34774874FF061279CDB -:10F9900094FF80EE82FFB4700B3E20DF0B6342DFEA -:10F9A0006612C1A78BB03C6AAABF58BEB427BB6B16 -:10F9B0005E9439C79B1AFA827E7FB53188F2E7469A -:10F9C000FBE39837B63337B00BD6FDB4A11FE33D48 -:10F9D00039C45585F6168577F7FF24BC745DB9E107 -:10F9E000BDB00385BDD72D7FF823832A7F58C0A7DC -:10F9F0005DC7028E7AC2EE3F1ADBBE15EDBBFAA9D7 -:10FA0000562F9CF3A887BCD8128C7F619EF101BE53 -:10FA10002F0B4A2CDFB79BBDD87B9E31BB0FA0D6E6 -:10FA2000C6EEC111F729DD9B2FEEC9617053F9C5F0 -:10FA3000EFC9C1725B9507F77F9D76E31C6687DE91 -:10FA4000506069867B07BBDF97C3FC7BE405A38717 -:10FA5000DB89A8BFDB12D9772E9A595E7B9C1C27C5 -:10FA6000525AD73D5EEBF4CC1EBC949DC7E278B2EF -:10FA7000B714E8B111E256BAEE7EC8CF9C818F81EF -:10FA80004FE614F972E0273D6619989F91F2D5A6CA -:10FA90000E02E9710DDBE17ECB9B48C39B721FE434 -:10FAA000AB2F807FA60DFA98DD7BD9C55757185F1D -:10FAB0000551087EDB3A7D2D3520E58CC03CEF7783 -:10FAC000EA4A20CE6844FC8BFC43EDFA8D83E7B410 -:10FAD0009EC1E3807B75293CE61C677778AE86BFC4 -:10FAE000E3F9289D303EEE8DCF21CF3F7158179F0F -:10FAF0002793800BE0EFE4F755DE165D9F1EE0D6FE -:10FB00005991EEB74F67F198FA0466A7425CC69D1B -:10FB100006FE27F6FDDB5733FEB8DD6C447E99D434 -:10FB20005E8BF11752C1E2295EFA3F80671AF18DB0 -:10FB3000839FE698629B84E736A74E54C75BA699DD -:10FB40006EC4F8CE6D84F9D36E9FAA57FDEEA0C0A7 -:10FB5000C334B2F663C8E798A6F9BD412D5EB4F18F -:10FB60001A818FA691DFBCEEAFCD4974609CD8435B -:10FB7000FA7FC7B84E790ECB9FBBAAB8CE117D0CC9 -:10FB8000CFEBBFE29CB769115D17FDFFB308EFE94A -:10FB90001E97367FFB63B4FCD38D03B1FC4ADA5D5C -:10FBA0004B4E40FD96022C57C81FCFC07BD34BA7AE -:10FBB0004F80FBCD8F98D9382E4BA00D7EAFC2352C -:10FBC000247F186CC92A0C316C77F3D0DAE19007E6 -:10FBD000536161E5E3C5FF6B1896F37979D88B0320 -:10FBE000A17C44FA78464F71A1418552047E97AAC0 -:10FBF0002285B59F386C6706F8092ACA597990B7EB -:10FC00006C751FA8973F99D1933E6EE0F6B1B0B7DF -:10FC1000FC7CBDBFE07BBF19CE87F9AD9217CE0546 -:10FC2000F847BECFEEC732B13C02BFAF5881FB13DD -:10FC3000CB7DCCBF37D6DAE806F9F7BD80A104FC4E -:10FC4000B8366B5E33FCBE40F2C8B21140EFB1D49F -:10FC50000C03FD47D7D5125C57D77C9C93847688DC -:10FC60007A5D09BE9D24D653857ADD5079F04346EE -:10FC700047F57AA0E32E87F7D3AE55EBA54EF9AE44 -:10FC800059B75A7EEC55EF13B51CECD44FABC2C834 -:10FC90009759849DFFD90C7CCAD66F2BC061903BCD -:10FCA0003CF03E57F20EC4C48A5EEC07011F983D3B -:10FCB000645877B8E04F11F62283C0664B83EFB2E9 -:10FCC0007ADACF073F2226E0A2DF0F217E56317875 -:10FCD000364B0DFC7729985D2EF6BD7562BEFBD4C0 -:10FCE000F32DB5B073EC2E42E50EFAEE8B077E13C2 -:10FCF000DCF55CCF4E35F91F36D239DC669F857452 -:10FD0000BE83049F03FBA6C312F825D05B27070F11 -:10FD10004625F85D091FC693291D7F9513672F0897 -:10FD2000B8B4F8A8EB45AE6AE1D6E2A18B3E1D68F7 -:10FD30009FB9F9EFCF75CE4B339F267EFF7CACD8B1 -:10FD4000A8CA133D5EC5F260055CC72552887A5289 -:10FD5000B2601CB5D3EFA4956FBD9C6713FA59C070 -:10FD6000793F3F4FF585CCE4DEFDBA08C2995BD9F7 -:10FD700061063C7E92C3FC2E02FEA691416C679008 -:10FD8000A51EE3C49FE4C8C25FA6A2B7B8D74CC4FF -:10FD9000B9045E1D064F16E67B6AF039D364EC3970 -:10FDA000AEAA8DBFF6D24EA2F8CB4CE98E67112FCA -:10FDB000BB45EB87BB89F9A76EE17EB8B1950CFF17 -:10FDC000294B1371DF965272422183BBEE5D16F40C -:10FDD00078C711F82A07E316D111E027787DC44FC0 -:10FDE000314E24EE37D4E2C792DB337E7A5B0FBD0F -:10FDF000C1FFAEC56FCDA5E35C943AF01EB4BFBBA6 -:10FE00006C7CDC401EAC17BB2DAF0CFC0B54AE7EE3 -:10FE1000FD356C36A10AE8E70C38729DB03EFCE374 -:10FE200020F73AA532A067FE7982FEE1C57C9F38B3 -:10FE30008EEBF74F76B1F3F315BE014F8E01FBF356 -:10FE4000989E843C90C7CDF0F3C9261DEAF579AFA2 -:10FE50000D77817DFE01E7B7FEEB65D5EFD30D0889 -:10FE60005954F76C0CDA91A22A0F0E67A8DA0FDD4D -:10FE700097AFAA2F8E0C54D50F3F364C551ED1315B -:10FE80005AD5FE9A93E5AAF2A8E80455FB6BCF4E2B -:10FE90005695AF8BDDA9BE2724E8EB284C83FBF9F0 -:10FEA000193E6EB83253D5FE7CD2F863B0EE66AF21 -:10FEB0006579DB6564A1AAFF425D0DE64393566652 -:10FEC000C734D0FF213D75772B982746EDF754C0F6 -:10FED000DB7AB59D53DDFED82A90B5DDEEA7D0D8EC -:10FEE000335AFBA5BFA30AAE7726B7E6F2BC936BE5 -:10FEF000C835FCF74AB474C5F3FE9FBCA9C37DC4E2 -:10FF0000E2D7987DBF7837CB872B20FD92F11CD8A4 -:10FF1000311D094970EF41C3BA3152971DA3C58BFA -:10FF2000D1A5A6B3D9A3A67342A19ACE895E359D69 -:10FF30009347AAE96CF7A9E99C5AA9A6B3D3AFA63F -:10FF400073FA34359DDD01359D33ABD574CE6E50DB -:10FF5000D33977A99AAE79C105AA7A2137FBB42C97 -:10FF600056BD6F92C2A5545292D9FE6ABCEFA15FF2 -:10FF7000EB0F7BE40F41FF20FD1F5BCF0D985F3F30 -:10FF800097D21FF2EBFF42D61E855094960FEAF6E9 -:10FF90003D8671B5EFCA078F6AE97F95F629D58747 -:10FFA0004F803CA176CC7A900FD3FAF37D87BF6760 -:10FFB0003B46C8AD78BB217E5FDD9B3CEBA627F9B5 -:10FFC0003EBB573DA9D967BF05D94D688FAF45BF27 -:10FFD000D674CED79FC2AB51E0577D16F5FF5B14A8 -:10FFE000909114AEB7006EFA9DB72C83D00F7217A4 -:10FFF00089E8F19E6BC8DCD4E17D9998875945ED7D -:020000022000DC -:100000007278CEE2F6C11CEE27F9CA183890CBFC04 -:1000100023B969F0DDAC0E76EEEB78EA55DD0BF135 -:100020007BF827F8DD73FD87619C0A9367C913F499 -:10003000D561EE7F221359FE2751FC83E3EF61EC7B -:100040001A87C54D5F940201DC67BB4D5ED8670F10 -:10005000CA242637E83757281FE25427347A652008 -:10006000E791DD19E1C576C4572805E304DFF1BB4C -:100070007FCAF59D047E10EDBF6DBE06437811F377 -:1000800027B0DF4B7993D3E5A9DB8D11D897093ED3 -:100090003A9930E3A8D383FEF033C86F77DCB40A13 -:1000A000CAD2E154CF620ADFE5AA28EEEF29FECFDB -:1000B00001DE6A4C14FF748A17B303FD938119FCA7 -:1000C000A9DC49E91FDCD3792401CF58897DFF5D84 -:1000D0004BE05318E7B0DC91E3057C281D786E8F68 -:1000E00058D1B821170D3DFB03051ECA13B2EFC648 -:1000F0007B788D462FEC2FCA2546D7D3A9F7CC8025 -:10010000D8E21CD99F16D1A9E0963C00B7AD2AD7FA -:100110004DF9F1FF00AA42FBD90080000000000069 -:100120001F8B080000000000000BE57D0B7854D504 -:10013000B5F03E7366CE4C924932492024848499AE -:10014000843C20214C82202AE2F0088D1A30BC1415 -:1001500030E2E401843C2080DEC6963603E1A5420D -:100160001B2C2A2ACA8040D102068B801AEC206AF6 -:10017000F16A356DB5A55AB90950E54D0C3E68EBED -:10018000ADFF5A6BEF9D9973480AF6DEFB7DFDBE0D -:100190003FDEDECD3EFBBDD6DA6BAFD7DE73DEE2EF -:1001A000CD8C561963B6DE8CDD00A9D999531CC9D4 -:1001B000D8B7F8774B3065CCC718546954E09FBD69 -:1001C00020F723C5BFCDC5F81FE4F7FB62FC0F4144 -:1001D000DE6ABAF4C114C8770C36B9B740D1C6701C -:1001E000E83A9FB1F7B11EF4FFB405F2B1F47D35E2 -:1001F0007E4F08E7ED131E33F91BA17DF198971789 -:10020000B2EB187B76BEDDADC258A5CCA931985FA4 -:1002100039F3682C8DB1BF8CFEFBC1362763FD9D81 -:10022000DEBECE618CDD1B674AF980E6E1CD9E041F -:10023000F36623E3184BBC72FEC67530B6C6C4869F -:100240003336D9C197301BD705EDA6308F05C79936 -:10025000C6BC161CF77717340F8B82D404E530DF49 -:10026000BB988FBECF607E4AEF6601AA7F0F6BA35B -:10027000FC6F237293EB617E931ECF4C67D0E662D6 -:1002800069DB702CFF87D5EB76C2B83536EFBDBD84 -:10029000E0FBF964EF677D10EEEB39DCAF36DF4948 -:1002A0000A87DFC5FEC52370DDE36CCEEBF2521981 -:1002B0007BDDC42A9BED5036AE37CD9F991DE99367 -:1002C0000777D7CF32C6A05D6B67542E1B82798F1C -:1002D0003D11D6FF3D81C2EF79AA8B709D05AA9D85 -:1002E000F502F8B73A55BF15C62C1C5DDA17D705CD -:1002F0007F913EC0D3448FCA10CFBF5E0A5FA0DE9D -:10030000AFF3543FD2C4C40DE34F63FBA2D1539665 -:1003100047C3FAC77FD3765D00D2C27E96E36D599C -:100320007C8C6FE17F5FB28DE36220BD2D618F9980 -:10033000C1FC6F1BA02F2FCA81BC2D989FC8CCC1B8 -:100340007218F710C201E8A7FECF79A3DE0869C7CB -:1003500058935A0CEB2E7146F6FA3402B283D8A0A9 -:100360006F71DE6A49B4D7DE337CBF6E708F7A035B -:1003700068F276C553EE24BA706A48FF6566E6698E -:10038000EEA6DDAE7445D00F60379EB13BC45C3B3A -:100390008B2E691761BD4F3ABDF3B19F4513FE32F5 -:1003A0000BD7C7CCEC3743016EF3DF03B841F9F14B -:1003B00006807C2663271B6CCC6365ECD30607E5BF -:1003C0004F3524507AA6C149E9B9862C2ABFD0E01E -:1003D000A6FC2167F1F7B1DFB2D59F9BBD398CAD8B -:1003E0000A9378E4F3582CE87855F2F03FBA61BCF0 -:1003F00055EF5A285FD9DC341EC1B138F9F8B2087C -:10040000F8BEF839C58DDFAB5B3C9A1DE633FB0DBA -:10041000EF4A249FB9EFB64D04F0B1DACB0AF3E20C -:10042000161A50BC02C71BF6E1C97884DF670D239A -:10043000683EA71B3C341F4F4BFB5B71D0FE6C43E7 -:1004400021E53F72163F8CF53DEC730DEB4FD8D98B -:100450006E4E82F2028FE2C1FD3DCAC3FC7EC0DF58 -:10046000068BD78B74B321D1E6C6FD3E7AF0E4A7A4 -:10047000EF83713FE9EF7D14E97A5A6C79411C7C76 -:100480009F38A2D48CF5EEFA8631CC4BFABEFABE78 -:10049000E6F0A8157839FF9A42703ABF2FFB8E9B81 -:1004A000A0BFD78EA84C8579755E36D1BC3A8F86B1 -:1004B000FB9912ACB7E82595E87AD160CDCF5C986E -:1004C000CFEEC372709DD019AC3F4B71B27AA0BF12 -:1004D000B3BBBE9F807890E39F8D6DFEEA23E47BE3 -:1004E0009F70BEC758F3A74F225FEC97E07E08725B -:1004F000172C6C3AED5356173119E86BBEC6BC3C4D -:10050000EFCDC6FCD970766F31E487EF4E1A83FBCE -:1005100008C7736606F95AC6EEC7537FE80C8EB754 -:10052000A379F6474F42FEBCDFE4B34443CA9A2F97 -:10053000BC827C79ABDDBD8DE13CCDE138CF872D30 -:100540007C5EBE6DE1EE6D4EECCF4F7C00CA352C6B -:10055000AF79F189BEB88E5701062320FFEABA08A9 -:10056000E277AF5ADCC7EAB1DDD3BCBF9FFFE481BD -:10057000E307305D5B9BFF00A4BF73C612BC2B1E5C -:10058000993708DB6727017A803FFE62BF1208CBEC -:10059000656CF0FA43CB1261BC211BDB4D7D21CD94 -:1005A000DBAA34629A9D5C784485FE8F3A9D348F35 -:1005B000A13B5D6A126ED7BEFE8F6E4923C02988AB -:1005C000BF41027F39EB3F1FD317D25D7D9B17C51B -:1005D00040F920A5F9CC5217D2F91FF2BD04BF266D -:1005E000EAE7A59629BFBF9BE13A7C89369C77A9AB -:1005F000E6A6F309966B81FCF9BD699B1F8235EE77 -:1006000033F936D3F95566736F43BC17FB9E407CB4 -:10061000D7427D1FE46BF37C51374279ED2703DC31 -:1006200040512CF999EF15223CE6EF7D747C5FA8D0 -:10063000777E24730309B0CA972E8DC7762C993123 -:100640006409E7F736C6CF84760FE78C1986F45530 -:10065000AC36D3386C011FE77171EEB136004EBC79 -:100660002055A8F7307CC6EFB12D31879258103F46 -:100670000B5A96BACCD0FE3AAFCDADE2BE71F912AC -:10068000EBECC17314CEBFBFE17E4BD444BF8E29C7 -:1006900029C5DFE1FCD3C47926FB7B5C63BE30E86F -:1006A0002719BE2B783E6BFCDCDE067CA53E3F782E -:1006B0006EC3B8E1AE61D4DE837C38090EE93C98A4 -:1006C00067D2E3563A07AE75FC8B16FB6A05E876EF -:1006D0004138E76363C4F93B3DAEF1601BACF760A2 -:1006E000B837DE05F5668B739F99DD4EE4EF5BC38B -:1006F0003D7D70FC1A5B470AAE01CED524CCCF57A6 -:10070000BDFDE3D3E85CD5C933579B476BB8C785BC -:10071000EDAFB5BE91DF2EFED2C4F2800E163F6A59 -:10072000257ED1887C19D6D51839DC867C83BD61BD -:10073000AA790BCED99B79CBAEFE1647E6135F693B -:1007400064AC5B78BD06FBDF0BFC2600E78417F882 -:10075000C0A8CB1D2AA7F7D6C3D1D7219F659E4835 -:10076000A09F5B2E9B9837E41C34F603F8F2201C04 -:1007700047B308E60D39573D2C46C37DCBECB1FF9E -:10078000DABAC5FC470AFC8DEC3C1AC1EC080FF83C -:100790006EEF795D07C5BA7E85EB82747B7AF16472 -:1007A00084FFCD5F38CCB8BE9BCD935250AE8179DB -:1007B0004FC7798FFAC2A49FF737E1BAFCB5CEFFD5 -:1007C0007E85F94CB81F3FD7FCB81F5BF078043822 -:1007D000B6CCCBF1E3BEDFA7F1BC2F4A23B9B625D7 -:1007E00092F9908FB44C8AF7FB5CC80F19977B7B0A -:1007F000335E1E26DACF88A7F67DAD0052E4077778 -:10080000878BFEEBDE198CE54B93888F345AFCAB5B -:1008100053B1FF1FA9C4878F0ABEBD3E2670B70A19 -:10082000FDAEFF3C9EE13847592069018E53194EB9 -:100830007CF72693E9DE4976ACE7498C0578EFFB37 -:10084000874AE7C4FA3CC8DB896F4F6F86EFEB2716 -:100850007912C3B19F49F1269A8FCAEAE8BB8BB7D8 -:10086000FBC8C2EBCD14F8FA93C00FEC6BDAF7DEDD -:10087000891166A4DB4DAEB247683F304FA202F348 -:100880007DB2229D21DF9C5975AB8BE8A5E971E211 -:100890005FD3050E647FD8C0361CE566FE3763F66D -:1008A000B630C4E7B4CAB0763859D9D1CA65914ECA -:1008B000683FCDAB06ACC04FD9D4024F975C978A46 -:1008C000E37A68DCDAE681692743E8B9CC0A7C027E -:1008D000FA7F21CCFB04CDEB401E951F00A1E65B07 -:1008E000D84FC72BD277E3BE621571427F0994239C -:1008F0001E5EEBB0919CDA133D3422FC87083A452A -:10090000BC2CE17807798DF28DD307913EB3C9C233 -:10091000E9C6B7278CF05A38D94678EE9C1EBED966 -:100920000AE5F70ABED5383DDCA340BDC697AC7ECC -:10093000938BF424AAE73B1849FDD6683C5FF36229 -:100940003AD1D33ECDFFDC762C7F2D8CE8A1268AD0 -:100950008F5BF34A92A0378F6B058E7BD04A745021 -:1009600013EE8CA6F2FF8C233A1967F3BE82F000D7 -:10097000BAAB4339A2460B64C4007C8F09BA3A066D -:100980006D107FBEBA489A376D79C87B1B93B7202C -:100990003EBD1A2F673F50A9FC98838F7F6C0D1FB7 -:1009A000BFE4A7D5EF32C0DBB1E2F189B3611EC766 -:1009B000EA22486EFC73BD1AD0A250EFE9782C03EE -:1009C000EA5D587262F806987FDBB28F53903E4A18 -:1009D00096D51661BB92AA2513F1DCEC695F96D41B -:1009E000C0E60FD9C7275C9EDFE17ABE75793FC4A8 -:1009F0007DBF20A76D0ECACF17B4D66750FF888D74 -:100A0000F31EC5EF175FFE6C3B97AB3B32F03C9893 -:100A10006FE6F421CFD50582FE56A57A8FD1391124 -:100A20001E9885E747444E2BE7774BAE8DCF9F69E5 -:100A3000D9B64F8171AAC35BE653AAFA73B19FB3CB -:100A40004A204A4923F879713F9D7304A210EE5E53 -:100A50001397E7AA77E8D7857F66985735FE03DABC -:100A60005537AB9E30C435F36B38FF6AA605EBBB38 -:100A70008278827E084FCCFEE7593F04F8573D3715 -:100A8000301FF587EA98033FB989EA413BB94FD453 -:100A90002BF3723D57CE87AFEF9CA0FF7392FEA75A -:100AA0006B529FA7F12FBCDC87C63F3BC99F81F0EB -:100AB000BFA0887ACF59793DA00633CEF3054E4FBB -:100AC0008F597CA670B20B30A2E7EAB8E6E10817AE -:100AD000C987600E3E13D43FBB3B89EA4BBEC58A33 -:100AE00019C376D5BB13B770F94CE8B33851A85F7A -:100AF000F50BDE3FE6711F9E793E498CC7E5692301 -:100B0000FE8CEB4D4E35D17A1F93FC3B52EE737742 -:100B1000C224807FE6064D57FF42A476AF07FA1D38 -:100B2000E8D77F97FD0F4C55483EEB6FC05B5FB534 -:100B3000E39015F7D3B38CF6AB715EEE54AE373E4F -:100B4000FF7C179E548E371003257D38B91C6E41EB -:100B500038FFA90B1FF725015FAD4618A406E1B3C6 -:100B60002FCF9B84FCFF02E6F15C88817C0ECA419A -:100B70001CDE322FE16CA4B3657F9A93D406EDEFAF -:100B800046F810BF77F7417AEC925F2CA08FE4A073 -:100B90003E5A39F4643AEAA97503E128E85ACF9C31 -:100BA0000D7936DC4F7337E6D9CA42F0D0B863E826 -:100BB0001127C0F9DC0EB31BD972A3D9FF1394A778 -:100BC0001B77A8CD3E46E53684EF39FBEBEF61BDE0 -:100BD000391B63F2515E96EDE76EB87F604508DC25 -:100BE000B377E8F130B8599F1F72409F9F8DBC6169 -:100BF000D8776F9717D0E7871ED1E75907600BF0BA -:100C0000A0DA389EF68F701F71029EFAFB55377E70 -:100C1000EA6F9F3C6502CA171B55773A94F75F52FB -:100C20007CFB60C89FDA38DB8D68AE547DF37F08AB -:100C300038ACFC78FC113C0FCFB2E63F4C003CCC0A -:100C40006959A7999DB86E3DDDEE33097A7D9EDB2B -:100C5000D9E6F9F5E557EEEBA5028F2C2B949E8C87 -:100C6000788771EFF4C0846AEA170F3D094766651B -:100C700011103AC0EC86E6751ACA6D571FC7C7E552 -:100C800041BBC789F0281DC1CB6EAC1FCB4E0C8574 -:100C90007FACF9ED789C77E9C30AC90DA5BFCC7C80 -:100CA00003CF81F63D336EA3F4CE425ABFB4E7CDF5 -:100CB0006D51029190778C701E688376B3FD8A1B0C -:100CC000E75DB6DC1AE467F0BF8A358679AC0F2998 -:100CD00087F9CF3D70E8AF0AF45FB951DF6E1EF0BF -:100CE00059E45F555BBFB5867E977AE38D2D9B55A2 -:100CF0005CF76C397FDF2886EBBA915765BD847C41 -:100D0000731233706E4CEB5DBC2315DBADE7ED80E9 -:100D10005D96E27A6BED9A13D75B6B63810898C797 -:100D20009148CDE380EF973644921D6D8E15E4C94E -:100D30007C4A59583EB6734763BB4FDFE7F6B4DAD7 -:100D4000388EEFDA4D0AE951B568FCC4FCB33C3F7C -:100D50008F05681D48279ED0F5F9F579D6C4F5AF03 -:100D60001A73E010C2A38AB571FD09F0E891F0038F -:100D700078D5C03A8FC6A2BC6568CFDC5E1C77818F -:100D80009DCB4F0B0E7C6B0D2D977AA0D453A57D78 -:100D900077534671388EB342F13C618379AE10F2DD -:100DA000B56F5D18D1EFCCCDFCBC01393603E1B293 -:100DB0007E5DA21BE58C99209787E1BE99174EF5C1 -:100DC00040DE25BB4C07C8D55B5C58BF3980E7C601 -:100DD000FA475D244783FC4B70E9581BE6DFA2A06D -:100DE0001CCCE598F5EB32490E7F559E536BB9DC70 -:100DF000D58D5C4CE5AC0F97E33FC2A584C8C15FBD -:100E0000F4F67E9ADA3BB8AE8A659E443C772A2691 -:100E10006B26B457B1CAB86B921FB60939B203D664 -:100E20008FEB38A914BF650A9147BF16E7C8F031A8 -:100E30009EEDA29E1BEB5598263D740B8EF798C92C -:100E400089E375C1DBE3C9C0799C5C17968F743662 -:100E50007C0CB7171DCBE3FC3DE23AE6F1E3799A4F -:100E6000C6FB6569265D9A100EF407FD9C2CE0F622 -:100E7000EAC8EB8AC94E076735F179E33AECA29FDD -:100E80000AADF83F6FEE663E123E6C1C97174E2E71 -:100E900054B6F079017E213FFC9130B2EF9D14E70A -:100EA0008F8433D0CD30B2D30B7EB54ED0CB3A0B3E -:100EB000A703DF3CAE3F05E985113DAC177AD64C60 -:100EC000815FB696CBB5402F1CCE6B1305BD30F6B7 -:100ED00037A487022797B3AF515F02BC0F48EB7D61 -:100EE000A5DE24F1CDCCFE61FFCC2F52BB7FD73ED7 -:100EF0001F9C9F552F3C1AC5A0DE697353BC1BDA9B -:100F0000D76C5B11E581F494D917E580F14FFBD5DF -:100F1000427F37F02E4D9376658F5D01FE331FFFC4 -:100F2000E94479E7E189B8BEAFB6591CC81216EC9E -:100F3000B092FE347FEF3C92B321DFCEF3AB3E574D -:100F4000317F406F3FAFFAF9A3F14E82B72FC994BA -:100F500080692089413A7FABC51D40BBF407AA1BBD -:100F60008601B9B96325CECFD81EE77119F0BDA0AF -:100F7000592DD5A2AF2C5F20F8CB82BD0F7F8E7686 -:100F8000BD05067B7DA5F05B18EDF593D2227B7D38 -:100F90009A0DFFB89E5D8F7210C0C51DC07D0BF30A -:100FA000492732E1F6DEC6E71ECF6D477961EB3B9C -:100FB000514A4ED05E2FFD199DCDE59B5E71F6BC6A -:100FC0001F2F08BB6D105F9C6F390F28C80340416D -:100FD000E7698D25107513C0A366B385F84CCDAEB7 -:100FE00067B73F8974F6272B9DE7D5BBDEFCC38D21 -:100FF00028EFEEB1F42AE2CBB02BF1413C2D707218 -:101000003B99C44BD52FDFD49C83F9F725B141FC24 -:1010100054EF39A4B1C157C2716CF321ADCDDE0DCF -:101020009E9ADBC7939DE8B9AF35DC07A75F53589D -:101030001FD795ED2B37BF1985F218C209CF258927 -:10104000AF2EFC19EA43FF135FB98EEA3950AFE8BF -:10105000097FF97876A05EBE3F92C5C0F8951F590A -:10106000FD4588D7DD8BA3701D9F99EB389D3FBD53 -:10107000221EE5BA4A8B2FDE4129FF5EF9CCFD44E2 -:101080007F7395BA78470ED177A28964065F22AE46 -:101090006FF6C669B4BE39CC4BF457F9B45AEC8735 -:1010A000F44B332BDCD3CD3EF958F0A5CFB600522C -:1010B000617D9FA1DD06F9C6EF54A1E72EA4F3FBE5 -:1010C0007EB156C61651FE4B21B7ED4E33497B9685 -:1010D0002D545F5CB075552BE2E74CB2A70FCE13D1 -:1010E000E0E013F052BE857ED5DF16F4E1F8614EE4 -:1010F000F370D10ECED1B1F81DEBB75A3C68F70EA4 -:101100006927F4393EFE7D627C987738EAAB9FC54B -:1011100073B9DDB8BEB001920FB056164A5F3DED0F -:10112000FBAD0F125D7DF101E72BF3FD930AA9BC26 -:10113000D512E883E5FE435315E20B5616E86E5FC1 -:101140006FB5887DAD2F87799A9550F8BEC6E5D0EA -:101150003920770542F671906EB4E0775AF7236232 -:101160001D6DE44F937EB8B9821F18D76DE40F1F31 -:101170001AF8836CCF3676EF070AF2051F8D5B03F2 -:10118000E709CA19357FB2D2B951B3CB528CF039C5 -:10119000BBF3F01F66A21EDA2CF7B19EDF1AF771BF -:1011A000E58BC3BADDC767D7E475BF8FE17BB7FBBB -:1011B000788D42FCED7FCA6FE1A423BB414FFB75E4 -:1011C0006E0FFCF6DB34E11715F0FC92E544DF848A -:1011D000858ED2FE841F035C253C8DFCF3F1342701 -:1011E000C1D7C83FE1EF03160247093F499F8C79F9 -:1011F000699C2E3A96742AE9B88B4E8DEBD5C3D1F3 -:10120000587E18F913CCA7F8650BB79FB528246F43 -:1012100043BBB792AEA37DEAA1E38F35BD95D42B36 -:1012200034EF37E49B0DF53D867CB1A1BED790AF7E -:10123000D3D5AF397058E3FA414057CF5A7F3BE9D5 -:101240001957CA117EEEF7D9FBB9E643BAE8D7A120 -:10125000215FB42C63BE4894770FAA24EF5E7476A6 -:1012600044A15CB2228CCB6D171D221FC3F31DBDA0 -:10127000B595C817E5F78E306E27B958DC111513F0 -:10128000A2A7B7B7A851688F6DF3B3C2EEEC28647C -:101290001905B8B6B19ECAB9FC56A0DA53EAD11EF8 -:1012A000DAA4BA814C58C5D2BBA228EEA125ED8E96 -:1012B000E9F07DF6DB2A850F5C0CE77605E6F3980E -:1012C00031EEA09CA3909D62BEC746C2BACA5B78AD -:1012D000FC41C51A3D7EE7D8A746079CC877F47144 -:1012E000027351AF4B437D4FFFBD8AAD217AAB32C4 -:1012F000EC0BAFB0D31AF745D900B12FF2589EB01E -:10130000C7909F6391E0D7056ACE1DD301FE178F6A -:10131000A8CC0AF9CE1695ADC4F5EE54C8DF830EFD -:1013200001DC6FF3615FE27C247CCEE1BEC9EC5945 -:101330002E39F7D227C37F8874B2EFE3DCA7203DB4 -:10134000B7EF4F19AF627EFF1F533E6657D61FFBA4 -:10135000DA5F67211FBEF89A95217D5F7CEDD72962 -:101360006817BCF88A95F4E58BCBACDCDEFC5AA49C -:101370001FFD911793B99CDB78F0EBDC363A779739 -:1013800013BED60ED0B8DCD4F2F76368AFEE6C8132 -:1013900055A13CF15A04ED9F05AF84913FFCE2C199 -:1013A000AF8787C64DFC4FD723FDDD1723D9F41730 -:1013B000916E855CBFE0D51B9E457F6EEDDE435A86 -:1013C00039948FFDD57FE722FFBCF82297932E58E2 -:1013D000DA9E415BE386AD373C624944FB1C74D620 -:1013E00017D0B5ED81C9B84FAE840B87C3458003D4 -:1013F000AE0BE052897CBF2778BCF06F0B8FCF67B4 -:10140000717E763D43FF6F102E0AF723B444FA6DC8 -:101410000AAD9F7F7FEDEB5CE437575BEF6F70BDEC -:10142000BDFFFF59EFD97F5BFC727A5F3CC049F387 -:1014300033D2FD9574BDFF3F28BF3BD24DF3BDC6EF -:10144000FD1E91FEEFBAFEFF1B7C0FFCB75DEFD5D2 -:10145000F0FDB6C077A403FD8A170FFE770AFB0ED6 -:10146000EB2E4CFF77DDD7FF7CDD525E1FA3BA8FDA -:10147000E441FD7758F3076E17491FDDCA1DF707D2 -:10148000E3EF483F1ACBF8393DD6564DF2E6D87E09 -:101490006B492E6E64F9E487F0F553C91F43C117F9 -:1014A00000875F27E4F9C99F640EF45B0CF93149AA -:1014B000B5149F65D41BC7864F284479F4F0529821 -:1014C00017F47338D2E4405FF1B87E6AC09A4B6972 -:1014D0003BA66FA5DC7E04E5967176BDFE74BB412C -:1014E0001FBAD5A92F2F642FF642FF59618E85F9B7 -:1014F000613EE3B17E88DE3825DD41F0BA95352DB9 -:1015000077D8BF3B9CB6A5733DF94A38FC73B85DEC -:101510000127A1279B457D23DCCCF6875AB19D99F5 -:1015200081DECBD74BFAB2D47BAF064F26F469B33A -:10153000185AC2D7DC8FFB4943FA25B848B87F5701 -:10154000784B3C19E12EE12BE166C4433D1AA37AA6 -:1015500007E1DFCF9C67C67D77B390E3C7996378D7 -:10156000BE5FAB5A4CFBD1CFE9FC0BB719E593D169 -:10157000F6188AD764CEE418D46751C4FC3609E45F -:10158000CE1131C315586F9299F9ACA06FA20F8D8F -:10159000ECA80F9AFDCB5C380EB7D7269BB95D1A25 -:1015A00076B72F3C9FEA7B34C897FE6C2EF340FD44 -:1015B000D224E656787D161D4BE1684CC5B82C4800 -:1015C000B15D6934EFB7B40FF32FE3F824BC0CC05E -:1015D0003495FAF5986279FBA87C6AEF33F1F61E30 -:1015E00033C67BA571FB7AC70A2BE91FA5AB9233E3 -:1015F000907F148DD1DB8D9333B89D59A6AB33F812 -:101600007E574DEE04948BCB960F247D480D2FAE64 -:101610007D09EDFDBB23881E4B57DE336118CE6F6D -:10162000779C1BA77766E29EE1BCFE8CFB3F84EFB4 -:10163000DE1D61F47D6786F7683AF4774671CE7AED -:10164000093E944D3BAC25C010DEE649E7D1FE379C -:10165000D1B7E73DF4334E9CAA52FD898CC73DB209 -:10166000E511E48F9EE0FBDC9C00FD4D006503CBA3 -:10167000DBC31C290B61FEA5C2DE7B52EC17359C37 -:10168000795FB4E3BC923352E1FB04D67D1C706AEF -:1016900086A83F46D988FEA1FE63B93D5ED6C77EC7 -:1016A000B0DF2C018F8BE9DCEE24F30057AA5FB189 -:1016B000DADA9E867ACF6A4B2013D25959632EE12B -:1016C0003A8B52D9F80D08F70754B685E6DB514A34 -:1016D00076EEC82C27E2C10B244DF1854D2E27DA7A -:1016E000BDDA473707D03FD0FE84CBDDE8242C534A -:1016F0003C8ED4B3DA470706A05DBE238FFB198E5C -:1017000039DA22513F2CB7DB283E47C6F5CC76F0BC -:101710007DDEBFB16DEDF5A8773EAABAB7407EF683 -:10172000A3DCEFF217BBCDAFA0BEB69EEF53B6461B -:101730001FC7C31C6EB2F794378DD650BFACB07BB9 -:10174000345C6776A6372603F7D13700BFE118C7A8 -:10175000C96833943695529C891A05FB0EF789D9CE -:1017600019857AAF310E688188FB91F917C2BC7D6B -:1017700033004E65D1CEDD482FC7EBD3C8EE3943D9 -:10178000D05D11C631A27FC2DC9688F379078DB88F -:10179000307E51AC23C34EF41CC6100EED16470626 -:1017A000D277FB8A3013FAD98A9671BA867D66336E -:1017B00043FB07CD2C1CFD06A7D279BF254BCDC519 -:1017C0009B21DFCFC6CC91B148577944D79BB3BC9E -:1017D00017D3A1FF533F6223901ECAD7AC23FF8AC1 -:1017E000A40B666E1D1707E39CDAE6CA47BE29E91B -:1017F0006873D6983C844B173D4C55880E203D9419 -:1018000046F430793896178D090C589483FA680D90 -:10181000F3E0F99EC0DC282774B20EF23F76DA3589 -:1018200027DAB9243F917C03F0EAB1C507E9603BB0 -:101830009CF7660B633B1A6C943EDFE06066E071D8 -:101840003B1B1228BFBBC149697343167D7FB1C1E1 -:101850004DF9BD0D2328BFAFC143F9030D8594BEDB -:10186000D2504CDF255F02B8101F927C45F2A37264 -:10187000BBD68EFE48C9978C74330BC03B2A9FDAC7 -:1018800013DF93FC0ED761CA0FF22389DF54A5D86A -:1018900097E0423ED63603F15FA09EDBB51FF5F21E -:1018A0004ABB9BF474C6F95E27D02BC2254563075B -:1018B000D0EEDAB8D0D3BECA1584FFDD950A3387DF -:1018C000D0D53D7561CC1C726EDC5B1FA3CB97D469 -:1018D000FFFECD3ED0FF1DBDBC55487FC77EFCE955 -:1018E000D37F84EF9B7E7C261DF10DF3D8F6388ED6 -:1018F000BB24BC6B1EB1985F6E217F547F6907814A -:101900003FC44B19E3FB6DD38FFF46FBBBBDDEEA43 -:101910004479F823C413C0F5CF024F65F556825FB2 -:10192000E98A13BBF6E33E5FA2119F2B5B2EF6E123 -:101930006A8067887FF77822237B0448D314AF7EC0 -:10194000FC475A2002FA3FAEF0FDAB805050827146 -:101950007FAB7F7D14F7BF527F84FCE75E9B3D40E9 -:101960007280CF722EB43FA5FE2DAAC7DAFAC5A0A9 -:10197000BD84CEB15BD0EFE8D19CB06EA469C45BEE -:1019800059D6EB2C11FD264D8A03B74C85F85EB174 -:101990005AE1FE49B33B612AC87D8F64A884C7F72A -:1019A000D2CDB42F733298885F68A2F349D26BC549 -:1019B0001A6887FBA2294F9B13C287CBC4F7F22C6E -:1019C00013A5F2FB16D16FDFD579D3519EE88BE5D5 -:1019D0003998E64F47F8F6B58F372B21F8DF986135 -:1019E00016F3E0E3E7E06683FF7B282B559B9D839E -:1019F000F8E1E7971CA72C2B7F25C67196AD198DB2 -:101A0000DC97355ADC09BDA0DEB6AE7E1C5C5EB04C -:101A1000F178E59A1ECE0F693F3B85FFBC81D64D1C -:101A200076DDAADDBFD88D71FC551F5B09BF55431C -:101A300044FC548E7FF8143234EAEDD5E37EF1494C -:101A400014F91FF6F2B84A48B93D754925B7BFBA2F -:101A5000615F75E3FF7963F7C751DDDAA9F7AAD7AC -:101A600064A75EA07C1385F2835C4FC1C12FE3693C -:101A70001ECA65F2FF2C38B822BEBB7B37467B7589 -:101A8000973D5BD8ED8CE5467BDDD10CBD1D1B047D -:101A900044BAC725ED754CCD8946FBFE97E29E47BB -:101AA0004F7A8DB46F2FD8009DC4C1FE343BA3D1B3 -:101AB0005F75B10779DA99C9CFFBF3C21E7E71A7B2 -:101AC0004A7ACEC59D91B49FE6EFFCD95BE83F9C76 -:101AD000BF55A169D4B256821BC093D942CF318C75 -:101AE000378BBB72DE9DFEF4683C47AA7F11598795 -:101AF0007436AF59F16C83F974DA9CD1BD43E6F3C7 -:101B00008DA0B36A6BF37082B39C3FF2C5DEC17ADD -:101B1000F35A7E46F663A87781E4A0172218BFFF28 -:101B2000D1F11ECEF3ECC6A16EF4FBCD6BDE339F7C -:101B3000E4889D110E1481CE883861D98F2D938F42 -:101B400067CBE472CB59E10F3ABB5B257E86F3C4C9 -:101B5000FD7546D1C7E345897651026E2FE2FEEE50 -:101B60001DAC3FAFB93D6A00D4FFECC0EF294DC8B2 -:101B7000E47C609EBD3517CFDFCFF646903FEBB3D8 -:101B8000BD4F8D7F15C63BDF3CBA17EE07D97F46A8 -:101B9000A685EA9FDFA81622BC989FC7BDD4227CE9 -:101BA0008786CE336EB3CF15BAEF78DCCFD9BDBF01 -:101BB0008C32E504F1596BF3DA125371FF9416235A -:101BC000DF38A538A99E65EF681FDE635AD092C73B -:101BD000909E69DF2552FDD5A6907A9AC54D4CD1CD -:101BE0007C60922789E02CEE21897879BC5747F7F1 -:101BF0008A26D9C83F316B88F3AEBB914FBE63E1F3 -:101C000078E9E77C1CE5B759EFC751DCD42297F39C -:101C10002E9CFFE2DFAA14EF3B6BA8E003096DC323 -:101C2000306EB166B5C23CB0CE7617971B6AFC2AFF -:101C3000F342BE2FD0830F4031313355F0D34006ED -:101C4000DE077CB2D2E4D1E0FC3BA6319F8A76A3CA -:101C500017793C734D2A8F1B7E12E91ED29AD84009 -:101C6000461CF4774EE0B366722003E3246A5E4CB0 -:101C7000A43889731AF75BE277F493D6E4437BA820 -:101C8000D74BC4C362FB9810FAA929733BB19E1AC3 -:101C9000EB76E6D971BE8E0B24C7BE14C9508E35C3 -:101CA000ED8FE4714E3F0FDB620DC15399A0B75E1B -:101CB000028F6C268F877C4CC4633FB62DD18FFA80 -:101CC0009BACFF98C53B03E180EB40F97D9ED69429 -:101CD00081F2AD9CEFBCA8269AE73941DFF3C29BA5 -:101CE00078BCB4C6E329B13EE6DB2D8CE2B83B9E5E -:101CF000B3523CC999C4D67D38FE99E706325C7F61 -:101D0000BBCB3FE7009583FC0878AB7ADE1AC0F5C1 -:101D10009C7E8EDB9B4F5BB83C767A528213F156E9 -:101D20003879C32CB2C76CB52A88F7D30AD312B05E -:101D30007C5B6FB70FDB37D4539C7415B009BC8F35 -:101D4000036921DEAB39BD6D20C5879D7E5BC51B58 -:101D500051F87D357EF7B2A6593F4078ECE0FAD3D2 -:101D600099E7FF3E30F41E9A4CABB6EAE3E0249DBF -:101D7000C8F246B12F1B059C5765F273AB36A2F92A -:101D8000B1545A27873BE089F43E38F8239FBA0EB6 -:101D9000E320D215E41B4F025D3D8576851D5CBFB7 -:101DA0003AB3D34271E155FB233D1477B6EA7A1377 -:101DB000C541A85C0EAF3201F82855A8DFAAC95961 -:101DC00074DF17E04D7A6CC736558CC3981DD7BDAC -:101DD0009DC7F916A1AC48E583A9FCB4C89FDE37BE -:101DE00098E43AE8DF83F795AA7EF0430EC7299579 -:101DF000EF32B263D888BFD674F9714646E379579B -:101E0000BBEAA668BC07C8DE5719CA2746385D3248 -:101E1000BBFB205FFD83E05FD5FB9ED6901F548BFC -:101E2000FB21D5CF2BDC9F0CFB0CEF4956AFBCE957 -:101E300071A2CFF72C2C1DD673AEF96751A1F8080B -:101E400008BED6555F7353FD6AA88FFD54AF7C273B -:101E50008AE6B3DD427126463C5E73FBE7D56B6ACA -:101E6000DF451FCDDC8E72C5FA59EB7F7C0CFD7F00 -:101E7000B133CCEDA3AFCD74AFECACA5790EAEFF12 -:101E8000ECAE30E2476763387FF80CF8A72F13E712 -:101E900071FB4F292EEB7753E83EDC5CBFBE5F3908 -:101EA000EE9BC8B7319E24CE1D8D717DB5EF73FEBC -:101EB0000678B983DABF6FA1F6C6756C15FCBE6BE8 -:101EC0007FEE8A207A38DB97E3E5ECEE4C3A8FDA46 -:101ED00063389DC37C53F0FEDCD95D9979742F0D76 -:101EE000851BA0872AA1DF9E8D694E718494B75B04 -:101EF000849E16809A4837D806E4BEAA7A2E575593 -:101F0000DBD6507C08C6D50ECFA734608DBD323EDF -:101F100016E895F4C77E597C7F311C2F5EC46F9301 -:101F2000BCD3AC21FFF60AB9B066A731BE9697FFC5 -:101F30005DEC4F9C6D2F19CF8B74E85328CEA47A9B -:101F4000F9C27948E7D575EBEEC67D26E75F6D6689 -:101F500085A887B52B2ACDA33D8CDD3B19CF8DD02D -:101F60007142E4362DABCB9ECA1CF124AFD2391698 -:101F70009EE5E474832726DE135DAEACA1715C524E -:101F80009FE5EB927002706818D7D73E5A94F7B06D -:101F90006E394FE3BAE57C52B2B89DA4DDE5FCE9A9 -:101FA00048C4F36F54BA4F7BE99BA1D1B1DDC8653A -:101FB000C1735D0BC6B7C2FCB391F6D0EE92C9ED0A -:101FC000A8D5183F0BF3CCD8A88FEBCEDAAACF0F49 -:101FD000DAA9CFE7ECD5E7735BF479F71BFA7C1C41 -:101FE0008EDB9BEBD9787F17F56C4C51CF765AB9C5 -:101FF0009E8D79D4B331453D1BBFA39E8D79D4B35B -:10200000318F7A36E625BC51DFC63CEADB585E22CA -:10201000E05423E224110F48EFECE530DD7D9F8B87 -:1020200007F93D0EA003BE6F6668B46F9EC41AA484 -:102030007770BB52DF293627C6FBFA62BDE3B38651 -:10204000E17D8FD695898837731BC59D2E7885C70E -:102050009DD6E487D9D1BED1B6E2B39518CE393535 -:10206000D67B7B566FBCCFD9B11DE15B5B7F98EE11 -:10207000BDB72D75BE7F0BC71FD95958652CC94DEB -:10208000A578CEC5F68C4763DC375BA38FF336C6E5 -:102090007D1BE3BD8D7420E5BD4D968E44E4EB279A -:1020A0009EB3ADC1F99F0813F74FA6DB0CFE7E214E -:1020B000A7AD55B6E0795D9315CBFD4947403EEF9E -:1020C000E69C9569F9E5A1248777E5D72826BA1714 -:1020D00097104FE7D06231A714A5A37D15F2B97907 -:1020E000263A372F815C86E35DFA4025F921738318 -:1020F00049B79E81FE701D7D65EF8835DC6BE8ABCE -:10210000AB3FE440AAE15EC3207D1CFDD4A587500F -:10211000BF9FB266A8AE5E45F14D06388A790BF9CD -:10212000B502CE0F0FACEFC9251B5210BF8BE77560 -:10213000B6AF42F9F4A530BA175689FF0FF86225F9 -:10214000F489F7192BF78AFBC0F5FA73B85C9C4346 -:102150009566E673C406E9B0D2C13C31D07EDEA0FC -:10216000D6DC00EA156FFF7EB82315F58AD17D9085 -:102170001FA5583C14075BB3273D6629F4BB22CD4D -:10218000FB14D2DDC9A6C33F29C1F3700FD7F74EA8 -:10219000ACF96514C589097A4BB138C211EF9B9B24 -:1021A000787C1CDAC7D4D8205D6C6E8A0B1F600F58 -:1021B000AE374807DF109E003FDC8E53F93AF93DF9 -:1021C0003A9BC57A472B3E94A7E5FA168973850D8D -:1021D000E0FDDC27F227857E21D7796EE0A15C2720 -:1021E000DEBF683890A2223F37EDDC9E08A9DBEA0B -:1021F000DD87FBAE7273FA1F47C238551FF2F5FC3C -:1022000065FDD8A81B50FEDC657117417E55D3B320 -:102210001AEAD95566BF46F195CF6DD630BEF87B28 -:102220003B36D3F7393B4A299E722EAB23FDF394FC -:102230007C7740C0A3728CB2D101F34E1AC8E5BEC0 -:10224000CA70EEBF03F9E84D7CF7E3D20E250FE329 -:1022500078A616EFD14AE1FBFB82CF18F749E7BB1E -:10226000530A7A133CF87D8D0F1968F16957EE8B8C -:1022700029975DB42FA65ECE26BD6C5A6020D77F0D -:10228000730CFAEFBBFCDD85CE16BE0F2AB540AF4E -:1022900029B84F5EB3909C5B0BE7CD887CD4AB191B -:1022A000BB11D2E291AA8E5E178C8BD0D1F374163B -:1022B000B24FA0BF3B316824243FB5284D57FFAE35 -:1022C000A9D906FACF0F96131FB95177BFAE7689F9 -:1022D000CFA9909C3946FF9DF13841C66ED3B5AF6A -:1022E000659383F590BEB77239B8766FCC16B4F7A4 -:1022F000559AB8FE34DDCBBFCF3FC0BFB3E94CB772 -:102300000FFBA7B9FFC8CF450BF905A43D7D3AFEE9 -:10231000BB1BF8C349DE753F1CEFC5A33D42777F69 -:102320005AF80371DE88875A6137AACDE276A35A3C -:102330005FAB86EF0E00FCCD71B154CF1687F191E3 -:102340004D0AD915315D42F192FA382CEC0FE318A1 -:10235000E71F514B719F18CB2BF1DD1FC4EF2B3CB6 -:10236000AE74EE06631CE41AF247CE477B5008DEDB -:10237000EE1EE814F28A7F655F845F919247F72230 -:10238000771ED230CE6EEAD4983CDC3746FA927C87 -:102390001DF633E9DF9DEF1E26FAEAAC3413FD5E2D -:1023A0000D0EF33DDC8E6AA4BB39AC55C37BE273E2 -:1023B000F62A6ED447B11EC2A32FD2A3011E71B15B -:1023C00057C241C2A70B5E7B8D716E1C4E730F28E6 -:1023D000FE40377032CEBB27B8C9F5CCF17AC7239F -:1023E0005F90EB9A8BF3C7FE61FED8BFF443B01148 -:1023F000C6FD9946F6A9F9C53C3ED6480F932F7302 -:10240000BBCB9D97CD944E2DD2EF476C87FB62DA04 -:10241000E5782AFFAEF4321FE6C9EF3F5D1B9DC889 -:102420007548BE1BDC0FFCDEC0D5DE0532DA1DE7C9 -:102430000E14F1C8C3D8305D3CB2E0ABC6F6C67826 -:1024400064290718CF97D24813C54D76DA5349BE91 -:10245000907CD62BCE0FEF8A2FA99E17EAF1D9C414 -:10246000EBCE1BAFB0FF2D8A4CA5F7185296C6C510 -:10247000239E4AC31C147F5FBA54A5B8E752A8E74D -:102480000C914F562E4F4BC1F3E2F88399CFF84091 -:102490006E3FFE40AFF81130CE8915965E3667B0BC -:1024A000DEF115052918A771629D75BABF1B78ADBD -:1024B0001BC8CF87DA1F1FA5F3ECBCE9DDA8E9D064 -:1024C000BE66C54B5118E65FBD829FE303D3BC4D8A -:1024D000037BE379BE79BB03E1E7D89C8B76DF4DC4 -:1024E000701C607B293F54AD28E883F245CD3F0E38 -:1024F0003FE3C07BD64B2DF1287F9EFE00CE438567 -:10250000CE33921B4E854117E44F8B243BC2298565 -:1025100079D0AF74CE74E8AB55A817E635670420C0 -:102520005D68F56E1A88F2FF8A67496EA97A686954 -:1025300086AA62BFE9D1DDD94D64BA5D9CDB28BFB4 -:10254000638AF23BC6C9A0FC8E7994DF3145F91D40 -:10255000BF2FD8A097FF5E10FE42694FEEDFD891E3 -:1025600087FE3BDF18965547E7AD3D0BE5F5C54ABD -:10257000B81BF9D162949530FF4918E9B16C6B2210 -:102580003F6F059EEB6DDC6FF4B5B89F7B7307C89A -:102590006421F479CB651B0BBD373B9AC5E8F26328 -:1025A0006D89BAFA050E97AEFC7B090375E5B73A5B -:1025B000F374F9DBB36ED0D59FE01EADCBDF31E213 -:1025C000565DFD499E49BAFC94C219BAFAD38A4BAA -:1025D00075E5774D9FA72B9FE15DA8CBDF5DF98067 -:1025E000AEFE3D754B75E55F9B4023057A6941BDA5 -:1025F000CB8AEFA7D828FDBEEA3023DF58FC9B74B6 -:102600003BE27BE458535D77F6FD53421E4ACFF61A -:102610009C407A4916EFE3248B776EBE1AC8F19975 -:10262000C480AA48DF6D4D44FA35D633968F8C7836 -:10263000FD92137058FC7CF43433F08991D7BF3E7F -:10264000340DF20F3E3F9EE76F7AFD97A9905FF73A -:10265000FCC3D3CCC0A7460E79FD129627FCE276C8 -:102660009E9FC248F4787AD0DFA7FA70FEB7A4AE76 -:1026700071733B49B7F7CC658A70C0FBDA08074C29 -:102680000340BF98BE0EF48BE91B40BF15C09FDE10 -:1026900002FAC5F408E89FF8FD3F41FFC4F45DD09D -:1026A0003F317D0FF44E4C5B41EFC4F4770DD329DD -:1026B000FDA0C14BEDFED05049E9D1863AFAFE515A -:1026C000433DA57F6EF0D1F7D841D28E1160BAFBA1 -:1026D00001E867447FE201CBB9503FB0F4574AFFAD -:1026E00064631D6B8B407ED1668EF9D416F43BF685 -:1026F0006C0730B34F43E4B168E6491E44E3F77317 -:1027000090DF487CFF557F6FEA20E03B1FBAA6A40C -:102710000F55F1DCAA7B13DDB21F8AFBF5C67EBF25 -:1027200012F4F1D7419E4C6C27FDEBD2BFDD15377B -:1027300013E27F3785C4EBD05F48DC8DF483CB3860 -:102740009F9B6DFC9EB1F473CB781ED95FC1178C33 -:10275000F8C3A8D566925F22CD2C80FDCBB89D51E1 -:10276000B6E63C8C63185563A77BB57DE0BB964FFE -:10277000F53C2AA45BFF0AF573837EF53E62FE50AA -:102780004EF32FF8C24B76D85122AE00DBDB78B97E -:102790000FDB8F42DBC27594127F7A1AEFEDE607EA -:1027A000FDFC583F82D70F607F03FE06E34505F727 -:1027B0004D726C731EF2EBE4F976BA17BA7174803D -:1027C000DEB322A313C0658AD49F6C222FFD793B10 -:1027D000FA901D69ACD8EBC39CDE1988CF62ABE3DD -:1027E0009308DA6769C9689F9C24E4E77F82B75938 -:1027F000D84EC253E245E251E223247E8AF0D01340 -:102800005E8DF834E251E2AFE08B205E10AE57E20D -:102810002D8857B4E7FEBBE0ED3A337FBFCC5A6357 -:10282000A377D1AE86C77B3BD8F868A8F295D3FBD7 -:1028300015F2CFD2CBCEB7305FCE468F47D4CAF297 -:102840006F7B28F77ED161890EC1F7CD02DF19AE0B -:10285000EEEBCB7AF23D06D97F410FF5DF0993719C -:10286000171E7BDEF060FCE3E2020EFF42974AF0A7 -:102870001F9B3397E46466E772A613FE43BE34FEE3 -:102880009B627AD7F24BB6133DB76C7C2FBD7C5A56 -:1028900068F05BDF26E4D2DB0C72A951AE7C71904C -:1028A000F067BB98EB3BBE57F932E76BD7FA5E2572 -:1028B0007FEF749CD8674982CED29C2A1B8974C44E -:1028C000BC744EBE81EF9DE6E2BBA03ECADFCAFCEF -:1028D00094DECE0274BE4E00468CF93B18A37BE416 -:1028E00087232696E0DDB8B143C70EC0EF21EFB2D3 -:1028F000BD87F39BAF7AFFCB11F22EDBEBE39C7429 -:10290000BFF2755B1AC95FB80F2D21F6C0B7E17C25 -:102910001A00E7C76138BF307D13CEAF01B0DE5F6C -:10292000C3F985F9DBB296326C37DEA98FDB91ED06 -:102930006F778C05C5A467F8DD9EFB723F84EF3B83 -:102940003199E3D07EFE4ECCF5E370BDEFC4F43197 -:10295000F1D4AA513A78FF80EEE443B90F82E38DB7 -:10296000A7F18CF095F034C251C2F75F80E7E5EE35 -:10297000E0F995909F3B6DBF8F4A4845FF5D947885 -:10298000C7F237B92AE44FE3D412315EF5269AE74D -:10299000A8FA1B987928F96D7210AE35360E2FA360 -:1029A000DD8A6DED630A8DDF3DA379C3B2619CCFF3 -:1029B00036AA746FFCFC8B61648F3AE5E7F6B6DBF0 -:1029C000156F5436CCAF4675AEC1F747D93BFC9D69 -:1029D00033F6CDE194C991DF814EB7F2FBF635B6FF -:1029E000F1DDE251EA53D12E0FED7326DE8B9472A6 -:1029F000453F2B7F9740BE5FD8939C313C9CF3C1F1 -:102A00007E56CEB7255EA11DE593A09FE1C0E7925B -:102A10007E1A4EFA45636F4F06AE4FDA113AFB4508 -:102A2000F891DF8E0A64D3BB5C8547548A277E5DAC -:102A3000C4777D2FBBCE9E0A789A94EE756793BEBD -:102A4000F98D8A7CE65D58671CDA1F8E0CB593FE03 -:102A5000F81DF5D011D9825FE4B25CDD7D35497790 -:102A6000AA9DE2773A3FE0F7F116BDCDE33617F5C0 -:102A70005629FEDF1817378A65FC14ED8D637B59E4 -:102A8000DC7E6790BFC87780AC0926E60C91B3C3A3 -:102A90009CE1CC19329F88AC585D3ED2DD57573F40 -:102AA0007A44AAAE3CC63348571E5798AFCBF72E90 -:102AB000BE5157BFCFF431BA7CA2F7365DFDA4CA30 -:102AC000C9FA3CEE3B807B72DD4C5DBBFEF565BA1E -:102AD0007A2E5F95AE9CF93CAD59F1C8C7F95FDA23 -:102AE000EA45BAF2A7A20A79FCB87D0EDD534C6F15 -:102AF000FA81AE3F89DFA4388E5FE6E4E7830FFEFC -:102B000023BF85C0734182FEDC18EB18FD8683521B -:102B1000BD5D23E92A71500FFCAB7450CBF474D027 -:102B20008BC7F114BC3DD489728C11FFE88F085D0E -:102B300027FA2342E182FE88D03CFA2342EBA33FEE -:102B400022B41CFD11A1E5438FE8F13FAC558FFF86 -:102B5000EB8F8EF9A778BAA14D4F0F463CDD744A32 -:102B60004F1FA3BCE10497B1208F21BD4B3C4D8783 -:102B7000FFE89C67C5D16837B88579E85EC0FF1665 -:102B8000BE5EC816F62381AF2FD99A61F8CEE5C58F -:102B900052CEC77B3AE79FEBEF7909F9EE09E4F3F0 -:102BA000C3AEB403C87852DF188E4FDFB130E2579E -:102BB0005F9BDA22F1FCF8BEDA4676F944D6F126BC -:102BC000BE3FE3E8E53D84FCA80F460F40F993F3D0 -:102BD000EECCC3736ED6AFAC2928D7CCEACFDF13C7 -:102BE00064396DF44E8B9CCFAC241E7FF476B6E036 -:102BF000D36E1E87F46E36B7FF44BA1D14075D9A74 -:102C000023DEA131B3945983910EDF0DCB443A5B9F -:102C1000CFED5C6D1627C5B5F8801ED14F89F23611 -:102C2000CAC3C9421E6DFC93CDC6E98EE9CEF781B9 -:102C30007E9B2E0E377B8743971FDC9CA0AB3FE427 -:102C40008053579E17C8D2950F3DE2D6E587B58EC3 -:102C5000D0D5BFFEA84797BFA1AD5057FFA653C51B -:102C6000BA7C12EB7802E1A9E6A4123CFA2BC20E60 -:102C7000E0E47899F5FD78BA4F23F5081997ED153A -:102C8000746CD447FA6B5E8AF36E4C646EBA0F6252 -:102C900013FA20D3EB295E11572DE579E6D3C755FA -:102CA000CB78EA2E7D46E82F529F0889A7F6E0FCF4 -:102CB000653C7517DEC5FB9246FA74E408BF906167 -:102CC0001DFD357EFFABF1018DEEB1C8F919E73579 -:102CD00043C4036EB375FFFE504A0EB71B6C4E2DF6 -:102CE0008ECF817ACFC0F144F0BC623C779B0FE07D -:102CF000DBF823CDBDCC79F5F1660DE1EB29C17789 -:102D00005573E89D4EBAB726C7CD15E3F6CA55BA36 -:102D10005DDFAC681EDFC5A235BA77D1F3781CAE93 -:102D2000091A5B4EEF24897B08F7AC695E9B094565 -:102D3000255A9385BFABEFB7A09DA8680CC88179D1 -:102D4000C027B6ED5B6F07F9E7997A33D97D86E541 -:102D500024DFE91B10BC57D21FF434A49322C43FD4 -:102D6000F4FBFC601EEF7C670E5F5F81FA4DD77D40 -:102D700000AB8ECF73FDAF1BBA237A94EBF8BFBACA -:102D80001F20E9D70827A95F33717E0D10F392F059 -:102D9000EBB29F08F8C9FB19CE8596E22D76BAE70B -:102DA00051887165127F070773BA5C2DE081F59039 -:102DB0001FF554AF40CD89463B782773463BAE6242 -:102DC0000FFE3FBA3741F0EFE9BE574F7CE20AFEF3 -:102DD000D0C3FDAF9EE893FEBEC33DB0103EC1E33D -:102DE0007D043EFC034CE4575F15A9DFC7FB73B8B5 -:102DF000DDA544EC2738B7ED797A3EC1D0AEDFB817 -:102E000042157C624ED7EF4FE0F7D92B2C245F336D -:102E100056FC18C619FC65BD85E262477918C931B0 -:102E2000651B15FF6605CFD1910938FF529FFE3C07 -:102E3000BE85B957A2FFA37CB5FEFB5C3BFF9D8A14 -:102E4000D9C6775384BE3EF72AFAFA8E1C718EBB20 -:102E5000999BE42EE1FFAF146D8C7257A79FFBCDB9 -:102E600050DF56B9DD89E2C6E4F9EE44FF4DC87B78 -:102E70002000CFF02C3CC7979BBB8DE7EB82670F00 -:102E8000F10AE7EC225EC1CEE3333AF78671FFA682 -:102E9000F42B89FAE77C97A81CEB636FE7F378DCE7 -:102EA00085F42719FD559D7613F95B3AF746927F15 -:102EB0001EFD38D14007674C7BE247B882F3F3B67A -:102EC000A93A3F8831F52E7D89F4C58169DEDF217D -:102ED0005F3F6B76DBDC907FD0FE3ABD1F5524EC64 -:102EE0005EC6F976E95D23F9FB2E9D3E2ECF761660 -:102EF000F27738802F32DC47320E6112032D15D263 -:102F0000D2C00D349FEFEACF9972398FFB312FDF9A -:102F100044EDBDAB6FA07CFFE56B17E23D98698D7A -:102F2000732DE8C26E7B62494138346D4BF62F0B2E -:102F300047BC8D56BAB5CB5F12786B33C4D7CBB4D0 -:102F40005CF0237C438EF3251187B454A17DB048F7 -:102F500061322E89F8B8CC5F6A12F9029E5FBC829A -:102F6000E7DBC4FBFADB851D05D78D29AE1BF5FE1B -:102F70009DC2CE82EBC614D78DDF916F611EF9160C -:102F8000E6916F611EF916A6C8B7F07B192B4EC9E2 -:102F900053B91F6A5CE8BEBB6C63E342F60BFAA14F -:102FA00042F3E8870AAD8F7EA8D072F4438596A3DA -:102FB0001F2A348F7EA8D0FAE8870ACDB311B7064E -:102FC000F3C8E73C9374F92920E78F0BD9DFE88732 -:102FD0000AED1FFD50BAFEBC0B75EDEF66F5BAF6B3 -:102FE000E8870AAD7F6FBDA2F353DD2BDE392DDFFD -:102FF00010C7E9C759EC1E0C74F05F11FFB8DF92DF -:103000008A786E99C7F5B27037C7735321C7BB89E9 -:10301000713C77CC203C2FD178BE80C7271BE907B5 -:10302000FD3DE32CDCDF8329FA7B30457F0FA6E8EA -:10303000EF1997CEFD3D98A2BF07BFA3BF0753F47A -:10304000F7608AFE1E4CD1DF8329FA7B30457F0F63 -:10305000B6437F0FA6E8EFC1EFE8EFC114FD3DF8DE -:10306000FD18FA9D2CC179A11C3F40A73F021DEA23 -:10307000F447872E8F727C687D94E343CB518E0F8B -:103080002D47393E348F727C687D94E343F3753964 -:103090004EDA5F28CF87B643793E343FB8C9F7266A -:1030A000DACE266CBCF006A66D91CA330AB08C85C8 -:1030B000BBF6DE897EB9B63025250638A74579E509 -:1030C000CE7190F78AF8BF5CD661427C7BC57BEA03 -:1030D000DE00A378CBC17F4DA4F217C4BD7EFA03F6 -:1030E000BCE7ED65F4BB24D25F2CDBBB9943C55430 -:1030F000D60FE6BBAF671C5FD623FE19320FBC01AB -:103100008CF12A794BECF918EFB9DDA4509CC4F688 -:10311000653C4ED84857DB045FDA6EDAF33ADE03DB -:10312000E92855E83E7086991DB1E4239CEAF2F146 -:10313000FC5D3B3846ACABEE46BC6F22E72DED9B09 -:10314000C027E8FEDCC88ED6B1D1D08FD7379A7EA3 -:1031500027A548E37203B6437D32DBA778B684D057 -:10316000F7E38339DFF4FAF8F83FDF3491B70BE780 -:10317000ED7EBE298AE03871B942F1522377320FD1 -:10318000DECFF58B7967EF0CA8385EE9723E9EECD6 -:10319000B774630ADD5B2C656DE312C847A230E4A7 -:1031A000DB126EB0BE37707DA0361C41FBF4B5DE7D -:1031B000FBB9F9BA98028CA3632D8CDEB19C70DD4B -:1031C0006F75EB25B40FA77EE95CCBF429F45EF0B4 -:1031D00044DFD265A86E4CF02D7CB337D6DFCADC55 -:1031E0002E271D45742F56CE6790678F098E459602 -:1031F000C35A4D610AE29B1D8E0BA11FD8F95311D2 -:10320000DF796E0BBDDF3BC9ECB0D0FB113DC49F35 -:103210005CB2CBF81383BC608833695C723405ED13 -:10322000C98B224D64FF5DF412FF3D00EF0685F867 -:103230009A94834A459CDAA5E56FF6BE0BE1BEC7BA -:1032400042FDC9F893DA347F8A09E3EAFB6ECE8D3A -:1032500055490EF8FD6094037CBFBC7304D65BC176 -:10326000DFB1BCB47C5A74807AE2FE9A0A01AF0ADC -:1032700011C7548A0F7AABC1DFD392F73B5813972B -:10328000F7A43DA7F43743DF42FC963E2DDE955E62 -:103290005D4AF7B28D7144F3965B28EE689E412E2D -:1032A000AC167261F555E4C2B3830D72A1FCBD1476 -:1032B000D186A9FDFE80717BF25E628985EFFF9267 -:1032C0003D8CECB0254BC79AE81DE49738DD942C73 -:1032D000E5F24DC9CB1EBA5F28E5C5F7851C33F969 -:1032E0007212C1FDF7426E9986F19500DFA2B630E9 -:1032F00011879548E95D9779BCE5643BE7036D0765 -:10330000F93B109D3E2B97A7DE60FC1D33035D4EFD -:1033100032FB4D78E1CE3D12E812F213500E82FEE0 -:10332000A6A35C148774EE2AA0F8BD4285EEBD18F2 -:10333000E9BCC852F726C687166D636E1F0BA573CE -:10334000A05FECCFA7D0FB005EA1D74AFA35D2FB35 -:10335000AC08618FB2737B53975D0265547CA4DB2C -:10336000177517CA8DB3D0B7D797130CC69D45E60E -:10337000F0F2F4DD51772D4725A7073B85FA038D41 -:10338000E0E195EF20F46037407B01F2C97BEECBA2 -:10339000D3CA42F8E49743C6140CE91DC47759D741 -:1033A0007DBF1C7A1774D183E9F47B383DC9C3E52E -:1033B0000057DC17B3A2DBEEC75F661B97CB3CE37D -:1033C00046E0EF0B32F9087900E308678AFCC2DCBB -:1033D000EBFF88BAEDAC089EF7ECEE7717C685D404 -:1033E000DADAC623D92DC8F116E23DC6207F2AF6C7 -:1033F0002429C89FF202A813CEC810E78FC11EB1BE -:1034000030D7C9D769B04B94E770BE2D7F17E5F868 -:1034100083FB77E37925E77FBC87DF6198976BFAB9 -:103420005FBD0761BCFFF0FDBEDE99B9D0FF63262A -:103430007E9FBFAFDAC4847D88FCC2925F30F10EFC -:103440004610EF1E7A47B7F141C5116A9FF2AE569A -:10345000F83DFA1EEC382CABE3896DD06E568346EE -:10346000BFE3B72983D3CF26A01FFABD14ADF54D16 -:103470009B2B08C78FEB1FB1D0EFD2B0403ABEBF35 -:1034800033B32ECC8DFCF8CB21C575B9C3F0F7480A -:10349000DCC4870A30861CCFF35EC58B713DB56BEB -:1034A0000E3D83EF092C6871D1EF95941EC85B899E -:1034B000EF9C7C39C45B8FE5A57607BDA7317F798A -:1034C0000C9D5FB3FA887BA1AC83FC6C12FE4DC2ED -:1034D0007E75AB9B89DFDB12F71D80414ED2D5EBA9 -:1034E000DE8E27ED84463B83F17D899EEC0BD29ED8 -:1034F00080F6032DC4CE28ED1396ACE333506E282E -:10350000D1F4F712657A2857E8B9420F9CDD756E41 -:10351000E58CEF83F2F13AC541EF4DDA9D77DD009E -:10352000F98A23168CEC6445B14E0DDF1FE800FCD0 -:10353000627C7419EC57E43325224EAB62C30DB4A0 -:10354000DF2AFC9076F30EA74CEF5E7738F965A47E -:103550009F8087FC96150E8F161BB2EFCB9B14DD58 -:10356000BB0332BF2797DBE34A602B23FCEEB9CFC6 -:10357000A5E1DB3E25204660FCDFA15CA7CE7F0CE9 -:10358000F5281EA42895BDC5DF818779BBF878F999 -:1035900021FD9735F17BD3320FF549FE793537920E -:1035A000F057EA8075BB3075D03C010E04A78EB58C -:1035B000D09F93C6217C9407FC16D4B74B300E05E0 -:1035C000F2331D7E0B8E53B69CBF63E25DC3C7F121 -:1035D000AE8ED106A37C647668C9083FF13BAD305E -:1035E0003F92232B002E781F0BEFBBE1D962844F53 -:1035F000A9986F45530CBDA310FCBECE82F898D19C -:10360000C3BB08E705DD962D1F4DF7D72BCC1EBA9F -:10361000E7E015F0FDCBC2B087D03F3063FDE31685 -:1036200017E43F11F47B5EECBBA2D4403ABD57B423 -:1036300030CC8DF39CE168A2F575C1F7518087828B -:10364000EFDC14137C812E7C18B757B15E8FCFE06E -:103650007C387C2BD697D27E9B63F66A8ED0796CB1 -:1036600038948EF7AA66C0FEC6772598C34BF72517 -:103670003F7DF4AE145A27CC13E11AE9768EC7F7D2 -:1036800087804EF83D18B11E79AF5B8E6719C2EF87 -:103690009D5A8670FB59CFFBD243724D23E017ED44 -:1036A000DE3DED4B0D19378CAB55F0DF9130EE530D -:1036B000B93FE5BE94FB54EEDF672CC5810425C8F5 -:1036C00067E09CAD7BB11B38150CE1789829F00AB6 -:1036D000707D23F49E57EE10BE9F4B52F5FB1DFBF1 -:1036E000C37EFB0EE1782F191348C77799647D39A3 -:1036F0006E492C6F87748FF4D6578C87F517517DE0 -:10370000938E5F9477F18B9D2BE2915FEC51B81F04 -:1037100074EDE1E4EFA3FCBA8BCBAF676BB6CDC71A -:10372000F39299FD29A1EFFBCF063907F9C41C716B -:103730003E5704BAE7173B33BCD94342F673C5CFB3 -:1037400076657839BF0920BFF9F3AE573FBCD11970 -:103750003C4FE57ACA56FFD6526A0F859F22DE1D7E -:10376000E9A4FB78E576CD89F1CEE5CB4B89FFB2B4 -:1037700004900B9590F833035D942E57E81E597909 -:10378000FD70BFFABFC8A7CBD74CA2770F24DEE4E9 -:10379000FB2CF27C95F39F28F0356908DF87330511 -:1037A0007DCFAC1CAD25F622B91BC32CD90CF17D05 -:1037B0004685FE7B17DEBAFCD7392B71BFE0FD22B0 -:1037C000D24FD658B8BD6F27B73F9E5DB4FFBD3B03 -:1037D000A1DE99C736A730558F379453E70879751E -:1037E000AEB0FF7583B73294DB647EEE268EB7F2FF -:1037F000DDBFF904DF132B4915FC6E2D7F07A0AC4C -:10380000790FE171C6EA751617CA75435CBAF736C7 -:10381000CAEBF21C68579EB97AB305F9C4A2211C01 -:103820008EC6FD5022E284259CF15C5242FC1BB204 -:103830003EF2477CFFFEBE85615118CF23C7794A0F -:10384000D07D795D4C2C8E575E57FA13D487E4797E -:10385000605CE78930BE5FCAA03FDCB72746BB5338 -:1038600016E504E55963FD47041D3E65E1BF53932A -:1038700014D1FC1CC5352C087723FF1830A0CD8F40 -:10388000E3227DE3BC3513FF5D9B01356D9FE33C77 -:1038900040D4A6B81A4CF17D2C14BDE321BFC5C499 -:1038A000EF6FA5AA3C3D20E003E5012C67BDDAE8F7 -:1038B000F73542E26675F4ABB1ADF4FB895A2F4699 -:1038C000EF9B497A95FD487A95F4DCD3FA9AAF716B -:1038D0007D275C1C9E9AF8DD946B5E9F95FF8EAEF3 -:1038E0005C979C1FC8F01E7ADFE38783C9DE736292 -:1038F000A93B05E3267B5EEFFA82F86ED66B5CA7E8 -:10390000DC373216BECB9FD5C4FD0E271438DFA09E -:10391000DD89856114DF26D7F55DEDE11F0C899502 -:10392000EFF947A29C59121EBC2F8FF03B56CF7F58 -:103930005F577E9772817C674EF2EF9375E2DC648D -:103940006D6B717FB3FA347AFFE458D389487C8F6A -:10395000E5C4683E3FD9EE3E0BBF9FCC223527DE43 -:10396000138BB8EFB7057DD03FB4DE95A740BB7B86 -:10397000EA871EC3F7C7EF59DE87F4FBD976E74A1B -:103980003C1767FB5CE40F8E589FF729BEA3377B7B -:103990007936FD6EEF7D0A2B267D52E8097358D7E4 -:1039A0001FE90973055F9B8BFC12EF4BD51FA677B0 -:1039B000F3E6B8C3F2F07C9FBB81EB094526B61A4B -:1039C000FD89FD1B8BC7231FEB7842E1BFFBBC5178 -:1039D000FF0E577666F1453C1F8CEFDEDD6769F61A -:1039E000E03A18C82368779A6D2FE672BDE09FC74A -:1039F000D6B7D3EF6522BCE9F7720CF69BFE1ABF6F -:103A000047DC1169227B1CE0FD7DFC3D327C6FDDD3 -:103A10004AE78DDE7ED3FFC723E8F7DAE43DA10A4B -:103A2000E177FA7F89106A7A0080000000000000C8 -:103A30001F8B080000000000000BCD567D4C535733 -:103A4000143FF7BE7E53E8E31B44B08060B7157C9B -:103A500005257126FA066A4C66B4B8A13451A851FE -:103A6000192A65CC2C019739AB9DCE68B6B10415E7 -:103A7000892C8529FB675B4A249B666C6924CE6C84 -:103A8000928CC83F266CA4240BA299A16359906420 -:103A9000D39D735F9B1A3F92FDB9F7CF79F7DEF3A1 -:103AA00075CFEF77CE7B506FE29005D06C02F1ECD2 -:103AB000ED7B2D0BAC28BB25B05702F4D0E62A8055 -:103AC000135D35591127C09E4FD69FF597011430CD -:103AD000708750EF375DA4165600CCF465A71D65BE -:103AE00078EE0B94029EEFE9FBA080E44C9FB93E78 -:103AF000887AEBE4DA75A919004D17525D921DE042 -:103B0000113D6BD18F82469900FB7D35D95004D091 -:103B1000F270E453B918E31702C8E8F7AF5052D077 -:103B20008F2A2D47AE14481C40317A7395950007B3 -:103B3000F8F0B655E8E71E0B0EE40A7D7BB66C4D37 -:103B4000F87D524E1F01B01B017CEFDD167EEEF3B7 -:103B5000D1CD1EB46FF15D4E213F07CE8C57C9B851 -:103B6000FF42B1B744C924BF7D03B28477EFEE2B87 -:103B700077E33D4A1510796E4A736FF3605ED11F8B -:103B800025A5DFFEFC78CD5730E9CAC47A67D06638 -:103B900000AC9F370C0699A40C86349433127484BD -:103BA000506E2A82C6ADD6C4FEAA585D666C9D05CD -:103BB0006EDCDF3770AEC08EF26EB2B6DE31B0FDB5 -:103BC000274841FD8B4603E1E5D5814141BBDD7EC0 -:103BD000A6065142731A406E227E8D92048075DBD8 -:103BE000D78D49A527F6018262FFAE0E36521E4BD5 -:103BF0000251D75B282774E1BD84EB449B59F11730 -:103C0000124E7691CF44A7B481F6FD6F332861B48C -:103C1000BE9CBC14E337D8A08DEC935784C21C71B2 -:103C2000F60DA556481AA504BF5A656DB15EB26E71 -:103C3000C8C3F383834C36A2CB8357AF6F006D0D9F -:103C4000C09E5FCFFD0F5683FDB1BCF70F0D1AEC80 -:103C500018AFE50BBC2FC66F090DFEB008FDB45EB2 -:103C6000D955A9C5ED04A8C23CE815E3B40E6975A1 -:103C7000F10D4D19763B137E7639D24EE421B64DC7 -:103C8000A135DBCFA0DE2EC2ED6580C3E515F5477B -:103C9000979294C5BD41172D7027039C72DC327832 -:103CA000C9CFFB317F8E5B278AC47D6BD3E1313E68 -:103CB000BCA1E8855DDC1EEB21ECC23ECB49580E71 -:103CC000A0B65A7524033E6B0AC90B6DDCA1C3BABA -:103CD000AACCA24858EF0E534A39D800E6CD9A1C18 -:103CE000B668B29DBB079B30C5793E6606E47DBBD6 -:103CF000D4C948AE75B631AC34C819DEC3C4DF1CB4 -:103D0000083110850833CA7BF6BB3B95147FCD92F2 -:103D1000C89F8029E9995ABF0EF9715C9105FEE0B0 -:103D20008C5412CF33AF4123F1AB570F27CD15740D -:103D30006F376C2D232FF84EB82FF0E025CC6F98FD -:103D4000853F23FFF1FB5E25BEA21FB7D17A9261AA -:103D50009E06BBF723CA630BD397B93861209590B1 -:103D6000FF59BD760E9DE75413F2A25AA305E473E2 -:103D7000F00352D6B028C74ABC66AA0A1D18FF989D -:103D8000F3DA6EE2C7E9A8098C183710AB4775D48F -:103D900032C5502F7FD1460EE5A86FCF801D687FBA -:103DA000CDC9FD46CCF3349882A40FA6F56AC4A110 -:103DB000C57884F3C5C0CDAAD01FBEB1C050E649B6 -:103DC0007F8CD8503FAF9D2901D469989BEEFD1997 -:103DD000E50E08BAA8AE5B32BC9FD3BC999CDB3819 -:103DE000E5457C4FCB2113F5193D8FE73F7C6821DA -:103DF000258D27F29A8D4E7FF9CD0A922685A15DF9 -:103E0000F5B01436963F9DCF6C8E5D4771502FCC28 -:103E100049DFCA838C91FEC86DCAAFDA640D4B29A5 -:103E200064A7FF3D624AD8C1587EEAF44B20207E49 -:103E300094079015D0705B13EBC3382E37152E7096 -:103E4000B919C3275E3F913CF6C74193D61FDF5B8C -:103E50000776127FE2FDFA666C7FEE41918DE6CB2C -:103E6000DC70B10D9CCFEFCF719CAFB00CE75CA1C3 -:103E70003A4EB8E3A39AD07F5DAC3E8837905F2975 -:103E8000E6B72E56A73A2BD7EAF2FA137589F12432 -:103E9000CE8378DE719CE3F8C13B63D76D8502B7B2 -:103EA000B28F41E0F52BC59F5C183D8E6D058B24CC -:103EB00075CA5BF87FC42B6C5E86BC8E9EE14A3F60 -:103EC000F19F0A5F21A4CAF17EE000310F1A248B12 -:103ED00072EA19F3C04BF36039CD834ED1E7F33C5E -:103EE0007A9D339A076D629D03D1A33A5C4FF248E5 -:103EF00032E51B3123EB5116BA8AC43CCAA38E2E7D -:103F0000D670A2BEEE3D94DC7F0AF5034C3D6F42B5 -:103F1000FB803ED6EFFBACC14BB83F1BE47E3DC6F9 -:103F2000EB4A0D9E6FC2FDAEBAC58A1FEB340B3152 -:103F3000BD668B980BAB3917EBA8272BD85F48FAD7 -:103F4000D8D778CF2ECF8BE23BFEF543744EF72EB9 -:103F500001EDDC05A5DD745EEB10FEBE8DCF990F83 -:103F60009385BFAE5A35D722CEB338D91F4FF7E667 -:103F7000B93209574D0F7F04845E4F8F9A4B78F406 -:103F80006C3508BDB3CCEDD94B7ECAACCA25F41B49 -:103F9000F158BE1AD0E00833DC9FECD0EE1BE7AF3F -:103FA000A7549B834BFC53E7E93FC45F0D8E36E477 -:103FB000FD24F17079021FA6221669099CE27CF4A7 -:103FC000EB11AF0C0DAF63EC69BC326278B10EE45B -:103FD0006D0AE11612F59FE71A0EED124492F04EAB -:103FE0001257728C282732BC55DA3DC772E9BCC122 -:103FF0001859D9E9243CA139F48C3E7CC5A5F53982 -:10400000D0571479DE18E379639C8FEF3EC1C7C89F -:10401000E2D4E9A4181FD1FE178BBB86E2DD67E36B -:1040200055B439FA8F54FFAC389B5CDA7FC99CD108 -:10403000FB2AE9C3C56C2EE688ACF5F5A8EB4E3E2D -:104040007D67E0EF91C5F4DDE94D776F263DF3D252 -:10405000A8C14BF5CC8DEAE93E939E7BF9F43FD3A2 -:10406000D87143F4CD7FCDF35F8E8A94E2B00A001D -:104070000000000000000000000000180000000028 -:1040800000000000000000400000000000000000F0 -:1040900000000028000000000000000000000010E8 -:1040A00000000000000000000000002000000000F0 -:1040B00000000000000000100000000000000000F0 -:1040C00000000008000000000000000000000000E8 -:1040D00000000000000000000000000000000000E0 -:1040E00000000000000000000000000000000000D0 -:1040F00000000000000000000000000000000000C0 -:1041000000000000000000000000000000000000AF -:10411000000000000000000000000000000000009F -:10412000000000000000000000000000000000008F -:10413000000000000000000000000000000000007F -:10414000000000000000000000000000000000006F -:10415000000000000000000000000000000000005F -:10416000000000000000000000000000000000004F -:10417000000000000000000000000000000000003F -:10418000000000000000000000000000000000002F -:10419000000000000000000000000000000000001F -:1041A000000000000000000000000000000000000F -:1041B00000000000000000000000000000000000FF -:1041C00000000000000000000000000000000000EF -:1041D00000000000000000000000000000000000DF -:1041E00000003328001000000000000800003330F9 -:1041F0000010000000000002000033280010000042 -:104200000000001000003A780000000000000008E4 -:10421000800000000000000000000000800000009E -:10422000000000000000000080000000000000000E -:104230000000000000003120000000000000000825 -:10424000000033600001000400000001000033683A -:1042500000000000000000020000337000000000B9 -:10426000000000080000337400000000000000029D -:1042700000003A70000000000000000800003A4012 -:10428000000800000000000800003D880040000019 -:104290000000004000003A50000800000000000844 -:1042A00000003A60000800000000000800003A88A2 -:1042B00000C800000000009800003C1800980000B2 -:1042C0000000002800003C58009800000000002872 -:1042D00000003378036000300000036000003EB04F -:1042E000000800000000000100003EB100080000CE -:1042F0000000000100002008001000000000001075 -:104300000000200000000000000000088000000005 -:10431000000000000000000080000000000000001D -:10432000000000000000000000000000000000008D -:10433000000000000000000000000000000000007D -:1043400000000000000000008000000000000000ED -:1043500000000000800000000000000000000000DD -:10436000800000000000000000000000800000004D -:1043700000000000000000008000000000000000BD -:1043800000000000800000000000000000000000AD -:10439000800000000000000000000000800000001D -:1043A000000000000000000080000000000000008D -:1043B000000000008000000000000000000000007D -:1043C00080000000000000000000000080000000ED -:1043D000000000000000000080000000000000005D -:1043E00000000000000000000000000000000000CD -:1043F00000000000000000000000000000000000BD -:1044000000000000000000000000000000000000AC -:10441000000000000000000000000000000000009C -:10442000800000000000000000000000800000008C -:1044300000000000000000008000000000000000FC -:10444000000000000000000000000000000000006C -:10445000800000000000000000000000800000005C -:1044600000000000000000008000000000000000CC -:10447000000000000000000000000000000000003C -:10448000000000000000000000000000000000002C -:10449000000000000000000000000000000000001C -:1044A000000000000000000000000000000000000C -:1044B000000000000000000000000000000012C822 -:1044C00000800000000000800000000100000000EB -:1044D0000000000000004000049000000000049074 -:1044E000000019C800000000000000080000494852 -:1044F0000008000000000008000049280008000033 -:104500000000000800004938000800000000000812 -:104510000000200800100000000000100000200033 -:10452000000000000000000800004010049000405F -:104530000000004000004998000800000000000151 -:104540000000499900080000000000018000000000 -:1045500000000000000000008000000000000000DB -:1045600000000000800000000000000000000000CB -:10457000800000000000000000000000800000003B -:1045800000000000000000008000000000000000AB -:10459000000000008000000000000000000000009B -:1045A000800000000000000000000000800000000B -:1045B000000000000000000080000000000000007B -:1045C000000000008000000000000000000000006B -:1045D00080000000000000000000000080000000DB -:1045E00000000000000000000000000000000000CB -:1045F00000000000000000000000000000000000BB -:1046000000000000000000000000000000000000AA -:10461000000000000000000000000000000000009A -:10462000000000008000000000000000000000000A -:1046300080000000000000000000000000000000FA -:1046400000000000000000008000000000000000EA -:1046500000000000800000000000000000000000DA -:10466000800000000000000000000000800000004A -:1046700000000000000000000000400000180000E2 -:10468000000000180000430000400000000000404F -:104690000000430000400002000000010000430150 -:1046A0000040000200000000000030000040000058 -:1046B000000000408000000000000000000000003A -:1046C000000030000008004000000004000030043A -:1046D000000800400000000400004B00002800001B -:1046E0000000002800004B500010000000000010E7 -:1046F000000038000080000000000080000038004A -:1047000000080080000000020000390000200000C6 -:104710000000002000002008001000000000001031 -:104720000000200000000000000000080000510808 -:1047300000080000000000080000512000080000F0 -:1047400000000008000051300008000000000008D0 -:10475000000051C00008000000000001000051C12D -:1047600000080000000000010000394000100004B3 -:1047700000000004000051D00030001800000010BC -:10478000000051D800300018000000028000000036 -:104790000000000000000000800000000000000099 -:1047A0000000000080000000000000000000000089 -:1047B00080000000000000000000000080000000F9 -:1047C0000000000000000000800000000000000069 -:1047D0000000000080000000000000000000000059 -:1047E00080000000000000000000000080000000C9 -:1047F00000000000000000000000000000000000B9 -:1048000000000000000000000000000000000000A8 -:104810000000000000000000000000000000000098 -:104820000000000000000000800000000000000008 -:1048300000000000800000000000000000000000F8 -:10484000000000000000000000000000000023E85D -:104850000080000000000080000000010000000057 -:104860000000000000002008001000000000001000 -:1048700000002000000000000000000800002DA043 -:10488000000800000000000800002DB8000800002B -:1048900000000008000024E802D00028000002D038 -:1048A00000002E58000800000000000100002E59F2 -:1048B000000800000000000100002D90000800002A -:1048C0000000000880000000000000000000000060 -:1048D00080000000000000000000000080000000D8 -:1048E0000000000000000000800000000000000048 -:1048F0000000000080000000000000000000000038 -:1049000080000000000000000000000080000000A7 -:104910000000000000000000000000000000000097 -:104920000000000000000000000000000000000087 -:104930000000000000000000000000000000000077 -:1049400000000000000000008000000000000000E7 -:1049500000000000800000000000000000000000D7 -:1049600000000000000000000000000080000000C7 -:1049700000000000000000008000000000000000B7 -:1049800000000000800000000000000000000000A7 -:104990008000000000000000000000000000250072 -:1049A0000040000000000008000025080040000052 -:1049B00000000028000009C00120001000000008CD -:1049C00080000000000000000000000080000000E7 -:1049D00000000000000000000000402002D000287D -:1049E000000000080000300000000000000010007F -:1049F000000050990000000000000001000050B0CD -:104A00000000000000000002000045A00090000827 -:104A1000000000088000000000000000000000000E -:104A2000000029600008000000000001000029616A -:104A300000080000000000010000297000080004C8 -:104A400000000002000029780008000400000004B3 -:104A500000002FB0000800000000000400002FB488 -:104A6000000800000000000400002FC0000000004B -:104A70000000000800002FC800000000000000082F -:104A80000000300000000000000000100000504056 -:104A900000010001000000010000500000000000C3 -:104AA00000000020000008080010000000000004C2 -:104AB0000000080C0010000000000001000008B712 -:104AC0000000000000000001000008B60000000027 -:104AD0000000000100001000003000180000000479 -:104AE000000010040030001800000004000010084E -:104AF00000300018000000020000100A003000180A -:104B0000000000020000100C00300018000000013E -:104B10000000100D00300018000000010000100E11 -:104B200000300018000000010000101000300018D4 -:104B30000000000400001014003000180000000401 -:104B40000000300001000080000800040000300474 -:104B500001000080000800040000000A00000000BE -:104B6000000000000000306801000080000000012B -:104B70000000306901000080000000010000306C7E -:104B800001000080000000020000306E0100008083 -:104B900000000002000030700100008000000004EE -:104BA0000000307401000080000000040000306646 -:104BB000010000800000000200003064010000805D -:104BC00000000001000030600100008000000002D1 -:104BD0000000306201000080000000020000305040 -:104BE000010000800000000400003054010000803B -:104BF00000000004000030580100008000000004A4 -:104C00000000305C01000080000000040000307CE7 -:104C100001000080000000010000307D01000080E4 -:104C20000000000100001C1800100000000000043B -:104C300000001C30001000000000000400001C38C0 -:104C400000100000000000048000000000000000D0 -:104C500000000000800000000000000000000000D4 -:104C60008000000000000000000000008000000044 -:104C7000000000000000000000004C1000080000D0 -:104C80000000000200004C120008000000000002BA -:104C900000004C14000800000000000400004C203C -:104CA000000800000000000800004C300040000830 -:104CB0000000000800004C00000800000000000296 -:104CC00000004C02000800000000000100004C043D -:104CD000000800000000000200004CD000080000A6 -:104CE0000000000800004CE0000800000000000484 -:104CF00000004CE4000800000000000100004CF03F -:104D0000000800000000000200004CF40008000051 -:104D10000000000200004D00000800000000000438 -:104D200000005000001000000000000400005004CB -:104D300000100000000000040000500800100000F7 -:104D40000000000400001400000800000000000241 -:104D5000000014020008000000000001000014041C -:104D6000000800000000000200001410000800000D -:104D700000000002000014140008000000000002FF -:104D8000000014160008000000000002000019B81E -:104D900000080000000000080000142000080000C7 -:104DA00000000002000014240008000000000002BF -:104DB000000019C8000800000000000800002C10C6 -:104DC000000800000000000100002C110008000095 -:104DD0000000000100002C1200080000000000018B -:104DE00000002C13000800000000000100002C004F -:104DF000000800000000000200002C020008000073 -:104E00000000000100002C04000800000000000267 -:104E100000002C30000800000000000200002C32CE -:104E2000000800000000000200002C340008000010 -:104E30000000000200002C2000080000000000011B -:104E400000002C21000800000000000100002C22BE -:104E5000000800000000000100002C2300080000F2 -:104E60000000000100002C240008000000000001E8 -:104E700000002C25000800000000000100002C2686 -:104E800000080000000000010000140000080000FD -:104E900000000002000014020008000000000001F1 -:104EA00000001404000800000000000200001412BA -:104EB00000C00018000000020000141000C000181C -:104EC000000000020000141C00C0001800000008D0 -:104ED0000000141400C0001800000008000014278F -:104EE00000C00018000000010000142400C00018D9 -:104EF000000000020000142600C00018000000019D -:104F0000000015900008000000000008000015A037 -:104F10000008000000000008000015B000080000B4 -:104F200000000008800000000000000000000000F9 -:104F30008000000000000000000000008000000071 -:104F400000000000000000008000000000000000E1 -:104F500000000000800000000000000000000000D1 -:104F60008000000000000000000000008000000041 -:104F700000000000000000008000000000000000B1 -:104F800000000000800000000000000000000000A1 -:104F90008000000000000000000000008000000011 -:104FA0000000000000000000800000000000000081 -:104FB0000000000080000000000000000000000071 -:104FC00080000000000000000000000080000000E1 -:104FD0000000000000000000800000000000000051 -:104FE0000000000080000000000000000000000041 -:104FF00080000000000000000000000080000000B1 -:105000000000000000000000800000000000000020 -:105010000000000080000000000000000000000010 -:105020008000000000000000000000008000000080 -:1050300000000000000000008000000000000000F0 -:1050400000000000800000000000000000000000E0 -:1050500080000000000000000000000000000000D0 -:1050600000000000000000008000000000000000C0 -:105070000000000000000000060205000000000023 -:00000001FF diff --git a/firmware/bnx2x/bnx2x-e1-6.2.9.0.fw.ihex b/firmware/bnx2x/bnx2x-e1-6.2.9.0.fw.ihex new file mode 100644 index 0000000..0ed7f58 --- /dev/null +++ b/firmware/bnx2x/bnx2x-e1-6.2.9.0.fw.ihex @@ -0,0 +1,9484 @@ +:1000000000003BB0000000680000070C00003C202E +:1000100000001AF8000043300000007C00005E3051 +:1000200000007A2C00005EB0000000B00000D8E0B4 +:10003000000080200000D99800000088000159C00D +:100040000000398800015A5000000090000193E040 +:100050000000AC040001947800000FFC0002408016 +:100060000000000400025080020400480000000F5D +:100070000204005400000045020400580000000083 +:100080000204005C0000000602040070000000048E +:1000900002040078000000000204007C1217000037 +:1000A00002040080221700000204008432170000BE +:1000B00006040088000000050204009C12150000E0 +:1000C000020400A022150000020400A43215000062 +:1000D000060400A800000004020400B8021000009A +:1000E000020400BC00100000020400C01010000058 +:1000F000020400C420100000020400C830100000F8 +:10010000060400CC00000004020400DC0010000023 +:10011000020400E012140000020400E422140000B3 +:10012000020400E832140000060400EC00000004A1 +:100130000104012400000000010401280000000067 +:100140000104012C00000000010401300000000047 +:1001500002040004000000FF02040008000000FF89 +:100160000204000C000000FF02040010000000FF69 +:1001700002040014000000FF02040018000000FF49 +:100180000204001C000000FF02040020000000FF29 +:10019000020400240000003E0204002800000000C9 +:1001A0000204002C0000003F020400300000003F69 +:1001B000020400340000003F020400380000000088 +:1001C0000204003C0000003F020400400000003F29 +:1001D000020400440000003F020420080000021155 +:1001E0000204200C0000020002042010000002049F +:1001F00002042014000002190204201C0000FFFF6A +:10020000020420200000FFFF020420240000FFFF62 +:10021000020420280000FFFF0604203800000080B0 +:100220000204223807FFFFFF0204223C0000003FC7 +:100230000204224007FFFFFF020422440000000FD7 +:1002400001042248000000000104224C00000000CC +:1002500001042250000000000104225400000000AC +:1002600001042258000000000104225C000000008C +:10027000010422600000000001042264000000006C +:1002800001042268000000000104226C000000004C +:10029000010422700000000001042274000000002C +:1002A00001042278000000000104227C000000000C +:1002B000020424BC000000010C042000000003E83C +:1002C0000A042000000000010B0420000000000AC6 +:1002D0000605400000000D0002050044000000205B +:1002E00002050048000000320205009002150020BF +:1002F000020500940215002002050098000000305D +:100300000205009C08100000020500A00000003358 +:10031000020500A400000030020500A80000003122 +:10032000020500AC00000002020500B0000000055C +:10033000020500B400000006020500B8000000023B +:10034000020500BC00000002020500C00000000021 +:10035000020500C400000005020500C800000002FC +:10036000020500CC00000002020500D000000002DF +:10037000020500D400000001020501140000000184 +:100380000205011C0000000102050120000000021E +:1003900002050204000000010205020C00000040FA +:1003A00002050210000000400205021C00000020AF +:1003B00002050220000000130205022400000020B4 +:1003C000060502400000000A04050280002000002B +:1003D000020500500000000702050054000000075D +:1003E00002050058000000000205005C0000000843 +:1003F0000605006000000004020500D800000006A9 +:10040000020500E00000000D020500E40000002DE0 +:10041000020500E800000000020500EC00000020DA +:10042000020500F000000000020500F400000020BA +:10043000020500F800000000020500FC000000209A +:100440000205000400000001020500080000000190 +:100450000205000C00000001020500100000000170 +:100460000205001400000001020500180000000150 +:100470000205001C00000001020500200000000130 +:100480000205002400000001020500280000000110 +:100490000205002C000000010205003000000001F0 +:1004A00002050034000000010205003800000001D0 +:1004B0000205003C000000010205004000000001B0 +:1004C0000406100002000020020600DC000000010B +:1004D000010600D80000000004060200000302200C +:1004E000020600DC0000000002060068000000B800 +:1004F0000206007800000114010600B800000000A8 +:10050000010600C8000000000206006C000000B8F0 +:100510000206007C00000114010600BC000000007F +:10052000010600CC0000000007180400007B00005A +:100530000818076000140223071C00002A040000AA +:10054000071C800032110A82071D00001E0C1707CD +:10055000081D4550575602250118000000000000F4 +:10056000011800040000000001180008000000004D +:100570000118000C0000000001180010000000002D +:100580000118001400000000021800200000000103 +:1005900002180024000000020218002800000003D6 +:1005A0000218002C000000000218003000000004B7 +:1005B000021800340000000102180038000000009A +:1005C0000218003C00000001021800400000000476 +:1005D000021800440000000002180048000000015A +:1005E0000218004C00000003021800500000000038 +:1005F0000218005400000001021800580000000416 +:100600000218005C000000000218006000000001F9 +:1006100002180064000000030218006800000000D7 +:100620000218006C000000010218007000000004B5 +:100630000218007400000000021800780000000496 +:100640000218007C00000003061800800000000271 +:10065000021800A400003FFF021800A8000003FFDA +:1006600002180224000000000218023400000000FA +:100670000218024C00000000021802E4000000FF13 +:100680000618100000000400021B8BC000000001CF +:10069000021B800000000034021B80400000001894 +:1006A000021B80800000000C021B80C000000020A4 +:1006B0000C1B83000007A1200A1B830000000138E7 +:1006C0000B1B8300000013880A1B834000000000FE +:1006D0000C1B8340000001F40B1B8340000000054D +:1006E000021B83800007A120021B83C0000001F4CD +:1006F000061A100000000273041A19CC0001022728 +:10070000061A2008000000C8061A20000000000297 +:10071000041A499800040228061A2E280000000234 +:10072000061A2E2000000002061A0800000000022F +:10073000061A080800000004061A08180000000243 +:10074000041A08B00002022C061A2FD0000000067E +:10075000041A2FE80002022E041A2FC000040230EF +:10076000041A300000010234061A300400000003AD +:10077000041A301000010235061A3014000000037C +:10078000041A302000010236061A3024000000034B +:10079000041A303000010237061A3034000000031A +:1007A000041A304000010238061A304400000003E9 +:1007B000041A305000010239061A305400000003B8 +:1007C000041A30600001023A061A30640000000387 +:1007D000041A30700001023B061A30740000000356 +:1007E000041A30800001023C061A30840000000325 +:1007F000041A30900001023D061A309400000003F4 +:10080000041A30A00001023E061A30A400000003C2 +:10081000041A30B00001023F061A30B40000000391 +:10082000041A30C000010240061A30C40000000360 +:10083000041A30D000010241061A30D4000000032F +:10084000041A30E000010242061A30E400000003FE +:10085000041A30F000010243061A30F400000003CD +:10086000041A310000010244061A3104000000039A +:10087000041A311000010245061A31140000000369 +:10088000041A312000010246061A31240000000338 +:10089000041A313000010247061A31340000000307 +:1008A000041A314000010248061A314400000003D6 +:1008B000041A315000010249061A315400000003A5 +:1008C000041A31600001024A061A31640000000374 +:1008D000041A31700001024B061A31740000000343 +:1008E000041A31800001024C061A31840000000312 +:1008F000041A31900001024D061A319400000003E1 +:10090000041A31A00001024E061A31A400000003AF +:10091000041A31B00001024F061A31B4000000037E +:10092000041A31C000010250061A31C4000000034D +:10093000041A31D000010251061A31D4000000031C +:10094000041A31E000010252061A31E400000003EB +:10095000041A31F000010253061A31F400000003BA +:10096000041A320000010254061A32040000000387 +:10097000041A321000010255061A32140000000356 +:10098000041A322000010256061A32240000000325 +:10099000041A323000010257061A323400000003F4 +:1009A000041A324000010258061A324400000003C3 +:1009B000041A325000010259061A32540000000392 +:1009C000041A32600001025A061A32640000000361 +:1009D000041A32700001025B061A32740000000330 +:1009E000041A32800001025C061A328400000003FF +:1009F000041A32900001025D061A329400000003CE +:100A0000041A32A00001025E061A32A4000000039C +:100A1000041A32B00001025F061A32B4000000036B +:100A2000041A32C000010260061A32C4000000033A +:100A3000041A32D000010261061A32D40000000309 +:100A4000041A32E000010262061A32E400000003D8 +:100A5000041A32F000010263061A32F400000003A7 +:100A6000041A330000010264061A33040000000374 +:100A7000041A331000010265061A33140000000343 +:100A8000041A332000010266061A33240000000312 +:100A9000041A333000010267061A333400000003E1 +:100AA000041A334000010268061A334400000003B0 +:100AB000041A335000010269061A3354000000037F +:100AC000041A33600001026A061A3364000000034E +:100AD000041A33700001026B061A3374000000031D +:100AE000041A33800001026C061A338400000003EC +:100AF000041A33900001026D061A339400000003BB +:100B0000041A33A00001026E061A33A40000000389 +:100B1000041A33B00001026F061A33B40000000358 +:100B2000041A33C000010270061A33C40000000327 +:100B3000041A33D000010271061A33D400000003F6 +:100B4000041A33E000010272061A33E400000003C5 +:100B5000041A33F000010273061A33F40000000394 +:100B6000041A340000010274061A34040000000361 +:100B7000041A341000010275061A34140000000330 +:100B8000041A342000010276061A342400000003FF +:100B9000041A343000010277061A343400000003CE +:100BA000041A344000010278061A3444000000039D +:100BB000041A345000010279061A3454000000036C +:100BC000041A34600001027A061A3464000000033B +:100BD000041A34700001027B061A3474000000030A +:100BE000041A34800001027C061A348400000003D9 +:100BF000041A34900001027D061A349400000003A8 +:100C0000041A34A00001027E061A34A40000000376 +:100C1000041A34B00001027F061A34B40000000345 +:100C2000041A34C000010280061A34C40000000314 +:100C3000041A34D000010281061A34D400000003E3 +:100C4000041A34E000010282061A34E400000003B2 +:100C5000041A34F000010283061A34F40000000381 +:100C6000041A350000010284061A3504000000034E +:100C7000041A351000010285061A3514000000031D +:100C8000041A352000010286061A352400000003EC +:100C9000041A353000010287061A353400000003BB +:100CA000041A354000010288061A3544000000038A +:100CB000041A355000010289061A35540000000359 +:100CC000041A35600001028A061A35640000000328 +:100CD000041A35700001028B061A357400000003F7 +:100CE000041A35800001028C061A358400000003C6 +:100CF000041A35900001028D061A35940000000395 +:100D0000041A35A00001028E061A35A40000000363 +:100D1000041A35B00001028F061A35B40000000332 +:100D2000041A35C000010290061A35C40000000301 +:100D3000041A35D000010291061A35D400000003D0 +:100D4000041A35E000010292061A35E4000000039F +:100D5000041A35F000010293061A35F4000000036E +:100D6000041A360000010294061A3604000000033B +:100D7000041A361000010295061A3614000000030A +:100D8000041A362000010296061A362400000003D9 +:100D9000041A363000010297061A363400000003A8 +:100DA000041A364000010298061A36440000000377 +:100DB000041A365000010299061A36540000000346 +:100DC000041A36600001029A061A36640000000315 +:100DD000041A36700001029B061A367400000003E4 +:100DE000041A36800001029C061A368400000003B3 +:100DF000041A36900001029D061A36940000000382 +:100E0000041A36A00001029E061A36A40000000350 +:100E1000041A36B00001029F061A36B4000000031F +:100E2000041A36C0000102A0061A36C400000003EE +:100E3000041A36D0000102A1061A36D400000003BD +:100E4000041A36E0000102A2061A36E4000000038C +:100E5000041A36F0000102A3061A36F4000000035B +:100E6000041A3700000102A4061A37040000000328 +:100E7000041A3710000102A5061A371400000003F7 +:100E8000041A3720000102A6061A372400000003C6 +:100E9000041A3730000102A7061A37340000000395 +:100EA000041A3740000102A8061A37440000000364 +:100EB000041A3750000102A9061A37540000000333 +:100EC000041A3760000102AA061A37640000000302 +:100ED000041A3770000102AB061A377400000003D1 +:100EE000041A3780000102AC061A378400000003A0 +:100EF000041A3790000102AD061A3794000000036F +:100F0000041A37A0000102AE061A37A4000000033D +:100F1000041A37B0000102AF061A37B4000000030C +:100F2000041A37C0000102B0061A37C400000003DB +:100F3000041A37D0000102B1061A37D400000003AA +:100F4000041A37E0000102B2061A37E40000000379 +:100F5000041A37F0000102B3061A37F40000000348 +:100F6000041A3800000102B4061A38040000000315 +:100F7000041A3810000102B5061A381400000003E4 +:100F8000041A3820000102B6061A382400000003B3 +:100F9000041A3830000102B7061A38340000000382 +:100FA000041A3840000102B8061A38440000000351 +:100FB000041A3850000102B9061A38540000000320 +:100FC000041A3860000102BA061A386400000003EF +:100FD000041A3870000102BB061A387400000003BE +:100FE000041A3880000102BC061A3884000000038D +:100FF000041A3890000102BD061A3894000000035C +:10100000041A38A0000102BE061A38A4000000032A +:10101000041A38B0000102BF061A38B400000003F9 +:10102000041A38C0000102C0061A38C400000003C8 +:10103000041A38D0000102C1061A38D40000000397 +:10104000041A38E0000102C2061A38E40000000366 +:10105000041A38F0000102C3061A38F40000000335 +:10106000041A3900000102C4061A39040000000302 +:10107000041A3910000102C5061A391400000003D1 +:10108000041A3920000102C6061A392400000003A0 +:10109000041A3930000102C7061A3934000000036F +:1010A000041A3940000102C8061A3944000000033E +:1010B000041A3950000102C9061A3954000000030D +:1010C000041A3960000102CA061A396400000003DC +:1010D000041A3970000102CB061A397400000003AB +:1010E000041A3980000102CC061A3984000000037A +:1010F000041A3990000102CD061A39940000000349 +:10110000041A39A0000102CE061A39A40000000317 +:10111000041A39B0000102CF061A39B400000003E6 +:10112000041A39C0000102D0061A39C400000003B5 +:10113000041A39D0000102D1061A39D40000000384 +:10114000041A39E0000102D2061A39E40000000353 +:10115000041A39F0000102D3061A39F40000000322 +:10116000041A3A00000102D4061A3A0400000003EF +:10117000041A3A10000102D5061A3A1400000003BE +:10118000041A3A20000102D6061A3A24000000038D +:10119000041A3A30000102D7061A3A34000000035C +:1011A000041A3A40000102D8061A3A44000000032B +:1011B000041A3A50000102D9061A3A5400000003FA +:1011C000041A3A60000102DA061A3A6400000003C9 +:1011D000041A3A70000102DB061A3A740000000398 +:1011E000041A3A80000102DC061A3A840000000367 +:1011F000041A3A90000102DD061A3A940000000336 +:10120000041A3AA0000102DE061A3AA40000000304 +:10121000041A3AB0000102DF061A3AB400000003D3 +:10122000041A3AC0000102E0061A3AC400000003A2 +:10123000041A3AD0000102E1061A3AD40000000371 +:10124000041A3AE0000102E2061A3AE40000000340 +:10125000041A3AF0000102E3061A3AF4000000030F +:10126000041A3B00000102E4061A3B0400000003DC +:10127000041A3B10000102E5061A3B1400000003AB +:10128000041A3B20000102E6061A3B24000000037A +:10129000041A3B30000102E7061A3B340000000349 +:1012A000041A3B40000102E8061A3B440000000318 +:1012B000041A3B50000102E9061A3B5400000003E7 +:1012C000041A3B60000102EA061A3B6400000003B6 +:1012D000041A3B70000102EB061A3B740000000385 +:1012E000041A3B80000102EC061A3B840000000354 +:1012F000041A3B90000102ED061A3B940000000323 +:10130000041A3BA0000102EE061A3BA400000003F1 +:10131000041A3BB0000102EF061A3BB400000003C0 +:10132000041A3BC0000102F0061A3BC4000000038F +:10133000041A3BD0000102F1061A3BD4000000035E +:10134000041A3BE0000102F2061A3BE4000000032D +:10135000041A3BF0000102F3061A3BF400000003FC +:10136000041A3C00000102F4061A3C0400000003C9 +:10137000041A3C10000102F5061A3C140000000398 +:10138000041A3C20000102F6061A3C240000000367 +:10139000041A3C30000102F7061A3C340000000336 +:1013A000041A3C40000102F8061A3C440000000305 +:1013B000041A3C50000102F9061A3C5400000003D4 +:1013C000041A3C60000102FA061A3C6400000003A3 +:1013D000041A3C70000102FB061A3C740000000372 +:1013E000041A3C80000102FC061A3C840000000341 +:1013F000041A3C90000102FD061A3C940000000310 +:10140000041A3CA0000102FE061A3CA400000003DE +:10141000041A3CB0000102FF061A3CB400000003AD +:10142000041A3CC000010300061A3CC4000000037B +:10143000041A3CD000010301061A3CD4000000034A +:10144000041A3CE000010302061A3CE40000000319 +:10145000041A3CF000010303061A3CF400000003E8 +:10146000041A3D0000010304061A3D0400000003B5 +:10147000041A3D1000010305061A3D140000000384 +:10148000041A3D2000010306061A3D240000000353 +:10149000041A3D3000010307061A3D340000000322 +:1014A000041A3D4000010308061A3D4400000003F1 +:1014B000041A3D5000010309061A3D5400000003C0 +:1014C000041A3D600001030A061A3D64000000038F +:1014D000041A3D700001030B061A3D74000000035E +:1014E000041A3D800001030C061A3D84000000032D +:1014F000041A3D900001030D061A3D9400000003FC +:10150000041A3DA00001030E061A3DA400000003CA +:10151000041A3DB00001030F061A3DB40000000399 +:10152000041A3DC000010310061A3DC40000000368 +:10153000041A3DD000010311061A3DD40000000337 +:10154000041A3DE000010312061A3DE40000000306 +:10155000041A3DF000010313061A3DF400000003D5 +:10156000041A3E0000010314061A3E0400000003A2 +:10157000041A3E1000010315061A3E140000000371 +:10158000041A3E2000010316061A3E240000000340 +:10159000041A3E3000010317061A3E34000000030F +:1015A000041A3E4000010318061A3E4400000003DE +:1015B000041A3E5000010319061A3E5400000003AD +:1015C000041A3E600001031A061A3E64000000037C +:1015D000041A3E700001031B061A3E74000000034B +:1015E000041A3E800001031C061A3E84000000031A +:1015F000041A3E900001031D061A3E9400000003E9 +:10160000041A3EA00001031E061A3EA400000003B7 +:10161000041A3EB00001031F061A3EB40000000386 +:10162000041A3EC000010320061A3EC40000000355 +:10163000041A3ED000010321061A3ED40000000324 +:10164000041A3EE000010322061A3EE400000003F3 +:10165000041A3EF000010323061A3EF400000003C2 +:10166000041A3F0000010324061A3F04000000038F +:10167000041A3F1000010325061A3F14000000035E +:10168000041A3F2000010326061A3F24000000032D +:10169000041A3F3000010327061A3F3400000003FC +:1016A000041A3F4000010328061A3F4400000003CB +:1016B000041A3F5000010329061A3F54000000039A +:1016C000041A3F600001032A061A3F640000000369 +:1016D000041A3F700001032B061A3F740000000338 +:1016E000041A3F800001032C061A3F840000000307 +:1016F000041A3F900001032D061A3F9400000003D6 +:10170000041A3FA00001032E061A3FA400000003A4 +:10171000041A3FB00001032F061A3FB40000000373 +:10172000041A3FC000010330061A3FC40000000342 +:10173000041A3FD000010331061A3FD40000000311 +:10174000041A3FE000010332061A3FE400000007DC +:10175000041A4CB000080333061A400000000124AC +:10176000021A492000000000061A2500000000109F +:10177000061A258000000012061A09C00000004861 +:10178000061A080000000002061A082000000012D5 +:10179000041A2FB00002033B041A4CF00002033D70 +:1017A000061A500000000004061A449000000124AC +:1017B000021A492400000000061A2540000000100B +:1017C000061A25C800000012061A0AE000000048A8 +:1017D000061A081000000002061A0868000000122D +:1017E000041A2FB80002033F041A4CF80002034108 +:1017F000061A5010000000040200A468000AFFDC72 +:101800000200A280000000010200A294071D29111D +:101810000200A298000000000200A29C009C042488 +:101820000200A2A0000000000200A2A40000020921 +:101830000200A4FCFF000000020100B4000000014F +:10184000020100B800000001020100DC00000001FC +:10185000020101000000000102010104000000017A +:101860000201007C0030000002010084000000281A +:101870000201008C000000000201013000000004A1 +:101880000201025C000000010201032800000000C8 +:101890000201055400000030020100C400000001F4 +:1018A000020100CC00000001020100F8000000016C +:1018B000020100F000000001020100800030000081 +:1018C00002010088000000280201009000000000D2 +:1018D0000201013400000004020102DC00000001EA +:1018E0000201032C0000000002010564000000302A +:1018F000020100C800000001020100D00000000148 +:10190000020100FC00000001020100F400000001DF +:10191000020C100000000028020C200800000A1130 +:10192000020C200C00000A00020C201000000A0427 +:10193000020C201C0000FFFF020C20200000FFFF13 +:10194000020C20240000FFFF020C20280000FFFFF3 +:10195000020C203800000020020C203C0000002176 +:10196000020C204000000022020C20440000002352 +:10197000020C204800000024020C204C000000252E +:10198000020C205000000026020C2054000000270A +:10199000020C205800000028020C205C00000029E6 +:1019A000020C20600000002A020C20640000002BC2 +:1019B000020C20680000002C020C206C0000002D9E +:1019C000020C20700000002E020C20740000002F7A +:1019D000020C207800000010060C207C0000004F54 +:1019E000020C21B800000001020C21BC0000000123 +:1019F000020C21C000000001020C21C40000000103 +:101A0000020C21C800000001020C21CC00000001E2 +:101A1000020C21D000000001020C21D400000001C2 +:101A2000020C21D800000001020C21DC00000001A2 +:101A3000020C21E000000001020C21E40000000182 +:101A4000020C21E800000001020C21EC0000000162 +:101A5000020C21F000000001020C21F40000000142 +:101A6000020C21F800000001060C21FC0000000F10 +:101A7000020C223807FFFFFF020C223C0000003F4F +:101A8000020C224007FFFFFF020C22440000000F5F +:101A9000010C224800000000010C224C0000000054 +:101AA000010C225000000000010C22540000000034 +:101AB000010C225800000000010C225C0000000014 +:101AC000010C226000000000010C226400000000F4 +:101AD000010C226800000000010C226C00000000D4 +:101AE000010C227000000000010C227400000000B4 +:101AF000010C227800000000010C227C0000000094 +:101B0000020C24BC000000010C0C2000000003E8C3 +:101B10000A0C2000000000010B0C20000000000A4D +:101B2000020C400800000562020C400C0000055148 +:101B3000020C401000000555020C40140000057214 +:101B4000020C401C0000FFFF020C40200000FFFFC1 +:101B5000020C40240000FFFF020C40280000FFFFA1 +:101B6000020C403800000046020C403C0000000C13 +:101B7000060C40400000005E020C41B8000000016D +:101B8000060C41BC0000001F020C423807FFFFFF9B +:101B9000020C423C0000003F020C424007FFFFFFE6 +:101BA000020C42440000000F010C424800000000FB +:101BB000010C424C00000000010C425000000000EB +:101BC000010C425400000000010C425800000000CB +:101BD000010C425C00000000010C426000000000AB +:101BE000010C426400000000010C4268000000008B +:101BF000010C426C00000000010C4270000000006B +:101C0000010C427400000000010C4278000000004A +:101C1000010C427C00000000010C4280000000002A +:101C2000020C44C0000000010C0C4000000003E85E +:101C30000A0C4000000000010B0C40000000000AEC +:101C4000060D400000000A00020D004400000032B2 +:101C5000020D008C02150020020D009002150020DC +:101C6000020D009408100000020D009800000033DF +:101C7000020D009C00000002020D00A00000000008 +:101C8000020D00A400000005020D00A800000005E0 +:101C9000060D00AC00000002020D00B400000002BE +:101CA000020D00B800000003020D00BC000000029D +:101CB000020D00C000000001020D00C8000000027B +:101CC000020D00CC00000002020D015C00000001CA +:101CD000020D016400000001020D01680000000215 +:101CE000020D020400000001020D020C00000020A1 +:101CF000020D021000000040020D0214000000401E +:101D0000020D022000000003020D02240000001852 +:101D1000060D028000000012040D030000180343AA +:101D2000060D03600000000C020D004C00000001D5 +:101D3000020D005000000002020D005400000000DF +:101D4000020D005800000008060D005C00000004B1 +:101D5000020D00C400000004020D0114000000097F +:101D6000020D011800000029020D011C0000000AEC +:101D7000020D01200000002A020D012400000000D5 +:101D8000020D012800000020020D012C00000000BF +:101D9000020D013000000020020D0134000000009F +:101DA000020D013800000020020D013C000000007F +:101DB000020D014000000020020D0144000000005F +:101DC000020D014800000020020D00040000000187 +:101DD000020D000800000001020D000C00000001CF +:101DE000020D001000000001020D001400000001AF +:101DF000020D001800000001020D001C000000018F +:101E0000020D002000000001020D0024000000016E +:101E1000020D002800000001020D002C000000014E +:101E2000020D003000000001020D0034000000012E +:101E3000020D003800000001020D003C000000010E +:101E4000060E200000000800020E004C00000032C8 +:101E5000020E009402150020020E009802150020C8 +:101E6000020E009C00000030020E00A008100000CE +:101E7000020E00A400000033020E00A80000003093 +:101E8000020E00AC00000031020E00B000000002A3 +:101E9000020E00B400000004020E00B800000000B2 +:101EA000020E00BC00000002020E00C00000000292 +:101EB000020E00C400000000020E00C80000000274 +:101EC000020E00CC00000007020E00D0000000024D +:101ED000020E00D400000002020E00D80000000133 +:101EE000020E014400000001020E014C000000013E +:101EF000020E015000000002020E02040000000168 +:101F0000020E020C00000040020E02100000004011 +:101F1000020E021C00000004020E0220000000203D +:101F2000020E02240000000E020E02280000001B18 +:101F3000060E030000000012040E0280001B035B6B +:101F4000060E02EC00000005020E00540000000C1A +:101F5000020E00580000000C020E005C00000000A1 +:101F6000020E006000000010060E00640000000475 +:101F7000020E00DC00000003020E01100000000F42 +:101F8000020E01140000002F020E011800000000D4 +:101F9000020E011C00000020020E000400000001DF +:101FA000020E000800000001020E000C00000001FB +:101FB000020E001000000001020E001400000001DB +:101FC000020E001800000001020E001C00000001BB +:101FD000020E002000000001020E0024000000019B +:101FE000020E002800000001020E002C000000017B +:101FF000020E003000000001020E0034000000015B +:10200000020E003800000001020E003C000000013A +:10201000020E004000000001020E0044000000011A +:102020000730040000AF0000083007680013037693 +:10203000073400003305000007348000327F0CC2F3 +:10204000073500001A951962083539E058C403783D +:10205000013000000000000001300004000000001A +:1020600001300008000000000130000C00000000FA +:1020700001300010000000000130001400000000DA +:1020800002300020000000010230002400000002A5 +:1020900002300028000000030230002C0000000085 +:1020A0000230003000000004023000340000000163 +:1020B00002300038000000000230003C0000000147 +:1020C0000230004000000004023000440000000024 +:1020D00002300048000000010230004C0000000304 +:1020E00002300050000000000230005400000001E7 +:1020F00002300058000000040230005C00000000C4 +:1021000002300060000000010230006400000003A3 +:1021100002300068000000000230006C0000000186 +:102120000230007000000004023000740000000063 +:1021300002300078000000040230007C0000000340 +:102140000630008000000002023000A400003FFFC3 +:10215000023000A8000003FF02300224000000004B +:1021600002300234000000000230024C0000000087 +:10217000023002E40000FFFF0630200000000800EB +:1021800002338BC000000001023380000000001AFF +:10219000023380400000004E0233808000000010B7 +:1021A000023380C0000000200C3383000007A12010 +:1021B0000A338300000001380B33830000001388CA +:1021C0000A338340000000000C338340000001F418 +:1021D0000B33834000000005023383800007A120F9 +:1021E000023383C0000001F406322A88000000C2D6 +:1021F00006322008000000C806322000000000025D +:10220000063223E80000004004322E580004037A0E +:10221000063250A000000004063250B80000000250 +:102220000632508000000006043250980002037EFF +:10223000063250000000002006323000000004008A +:1022400006321C0000000004043218300002038033 +:10225000063224E8000000B402322DB00000000075 +:1022600006324000000000B40632300000000020BA +:10227000063231000000002006323200000000204B +:102280000632330000000020063234000000002037 +:102290000632350000000020063236000000002023 +:1022A000063237000000002006323800000000200F +:1022B000063239000000002006323A0000000020FB +:1022C00006323B000000002006323C0000000020E7 +:1022D00006323D000000002006323E0000000020D3 +:1022E00006323F000000002006321C1000000002F1 +:1022F000063245A000000024063227B8000000B4D2 +:1023000002322DB400000000063242D0000000B4BA +:1023100006323080000000200632318000000020AC +:102320000632328000000020063233800000002098 +:102330000632348000000020063235800000002084 +:102340000632368000000020063237800000002070 +:10235000063238800000002006323980000000205C +:1023600006323A800000002006323B800000002048 +:1023700006323C800000002006323D800000002034 +:1023800006323E800000002006323F800000002020 +:1023900006321C20000000020632463000000024F5 +:1023A0000720040000870000082007800010038237 +:1023B000072400003165000007248000081D0C5A26 +:1023C00008248EB06C9003840120000000000000FF +:1023D00001200004000000000120000800000000AF +:1023E0000120000C0000000001200010000000008F +:1023F0000120001400000000022000200000000165 +:102400000220002400000002022000280000000337 +:102410000220002C00000000022000300000000418 +:1024200002200034000000010220003800000000FB +:102430000220003C000000010220004000000004D7 +:1024400002200044000000000220004800000001BB +:102450000220004C00000003022000500000000099 +:102460000220005400000001022000580000000477 +:102470000220005C0000000002200060000000015B +:102480000220006400000003022000680000000039 +:102490000220006C00000001022000700000000417 +:1024A00002200074000000000220007800000004F8 +:1024B0000220007C000000030620008000000002D3 +:1024C000022000A400003FFF022000A8000003FF3C +:1024D000022002240000000002200234000000005C +:1024E0000220024C00000000022002E40000FFFF76 +:1024F000062020000000080002238BC0000000011D +:10250000022380000000001002238040000000121F +:102510000223808000000030022380C00000000EF3 +:102520000C2383000007A1200A2383000000013848 +:102530000B238300000013880A238340000000005F +:102540000C238340000001F40B23834000000005AE +:10255000022383800007A120022383C0000001F42E +:10256000062250000000004206222008000000C899 +:10257000062220000000000206224000000000C6E3 +:1025800004224318000503860622432C0000000B9A +:10259000042243580005038B0622436C0000000B05 +:1025A0000422439800050390062243AC0000000B70 +:1025B000042243D800050395062243EC0000000BDB +:1025C000042244180005039A0622442C0000000B44 +:1025D000042244580005039F0622446C0000000BAF +:1025E00004224498000503A4062244AC0000000B1A +:1025F000042244D8000503A9062244EC0000000B85 +:1026000004224518000503AE0622452C0000000BED +:1026100004224558000503B30622456C0000000B58 +:1026200004224598000503B8062245AC0000000BC3 +:10263000042245D8000503BD062245EC0000000B2E +:1026400004224618000503C20622462C0000000B97 +:1026500004224658000503C70622466C0000000B02 +:1026600004224698000503CC062246AC0000000B6D +:10267000042246D8000503D1062246EC0000000BD8 +:1026800004224718000503D60622472C0000000B41 +:1026900004224758000503DB0622476C0000000BAC +:1026A00004224798000503E0062247AC0000000B17 +:1026B000042247D8000503E5062247EC0000000B82 +:1026C00004224818000503EA0622482C0000000BEB +:1026D00004224858000503EF0622486C0000000B56 +:1026E00004224898000503F4062248AC0000000BC1 +:1026F000042248D8000503F9062248EC0000000B2C +:1027000004224918000503FE0622492C0000000B94 +:1027100004224958000504030622496C0000000BFE +:102720000422499800050408062249AC0000000B69 +:10273000042249D80005040D062249EC0000000BD4 +:1027400004224A180005041206224A2C0000000B3D +:1027500004224A580005041706224A6C0000000BA8 +:1027600004224A980005041C06224AAC0000000B13 +:1027700004224AD80005042106224AEC0000000584 +:1027800006224B000000001704224B5C00010426C7 +:1027900006224B600000000304224B6C000104275A +:1027A000062238000000004006223000000002002F +:1027B000042251C00004042806221000000000C0BA +:1027C000062215C00000024004221EC80008042C86 +:1027D0000622390000000008022251180000000003 +:1027E000062251D00000000606221300000000025D +:1027F00006221410000000300622392000000008D4 +:102800000222511C00000000062251E800000006D0 +:102810000622130800000002062214D00000003037 +:102820000216100000000028021700080000000235 +:102830000217002C000000030217003C00000004F7 +:1028400002170044000000000217004800000002C8 +:102850000217004C0000009002170050000000908A +:102860000217005400800090021700580810000062 +:10287000021700600000008A021700640000008058 +:1028800002170068000000810217006C0000008041 +:10289000021700700000000602170078000007D041 +:1028A0000217007C0000076C02170038007C10043F +:1028B000021700040000000F06164024000000026A +:1028C000021640700000001C0216420800000001C1 +:1028D0000216421000000001021642200000000112 +:1028E00002164228000000010216423000000001DA +:1028F000021642380000000102164260000000018A +:102900000C16401C0003D0900A16401C0000009CCE +:102910000B16401C000009C40216403000000008DD +:10292000021640340000000C02164038000000106F +:102930000216404400000020021640000000000182 +:10294000021640D8000000010216400800000001F5 +:102950000216400C000000010216401000000001A9 +:10296000021642400000000002164248000000002B +:1029700006164270000000020216425000000000DD +:1029800002164258000000000616428000000002B5 +:1029900002166008000006140216600C0000060013 +:1029A00002166010000006040216601C0000FFFF03 +:1029B000021660200000FFFF021660240000FFFFE7 +:1029C000021660280000FFFF021660380000002099 +:1029D0000216603C00000020061660400000000265 +:1029E00002166048000000230216604C000000241C +:1029F00002166050000000250216605400000026F8 +:102A000002166058000000270216605C00000029D2 +:102A1000021660600000002A021660640000002BAD +:102A2000021660680000002C0216606C0000002D89 +:102A30000616607000000012021660B80000000167 +:102A4000021660BC00000001061660C00000003ED7 +:102A5000021661B800000001061661BC0000001FEC +:102A60000216623807FFFFFF0216623C0000003FBB +:102A70000216624007FFFFFF021662440000000FCB +:102A800001166248000000000116624C00000000C0 +:102A900001166250000000000116625400000000A0 +:102AA00001166258000000000116625C0000000080 +:102AB0000116626000000000011662640000000060 +:102AC00001166268000000000116626C0000000040 +:102AD0000116627000000000011662740000000020 +:102AE00001166278000000000116627C0000000000 +:102AF000021664BC000000010C166000000003E830 +:102B00000A166000000000010B1660000000000AB9 +:102B100002168040000000060216804400000005F6 +:102B2000021680480000000A0216804C00000005D2 +:102B30000216805400000002021680CC000000043F +:102B4000021680D000000004021680D400000004A9 +:102B5000021680D800000004021680DC0000000489 +:102B6000021680E000000004021680E40000000469 +:102B7000021680E800000004021688040000000429 +:102B8000021680300000007C021680340000003DF8 +:102B9000021680380000003F0216803C0000009CB6 +:102BA000021680F000000007061680F40000000501 +:102BB0000216880C010101010216810800000000C4 +:102BC0000216810C000000040216811000000004AF +:102BD0000216811400000002021688100801200469 +:102BE00002168118000000050216811C0000000575 +:102BF0000216812000000005021681240000000555 +:102C00000216882C200810010216812800000008F6 +:102C10000216812C00000006021681300000000719 +:102C200002168134000000000216883001010120E4 +:102C300006168138000000040216883401010101E3 +:102C400006168148000000040216883801010101BF +:102C500006168158000000040216883C010101019B +:102C6000061681680000000302168174000000014E +:102C7000021688400101010102168178000000015E +:102C80000216817C00000001021681800000000114 +:102C9000021681840000000102168844010101012E +:102CA00002168188000000010216818C00000004D9 +:102CB00002168190000000040216819400000002B8 +:102CC00002168848080120040216819800000005B9 +:102CD0000216819C00000005021681A0000000057C +:102CE000021681A4000000050216881420081001B5 +:102CF000021681A800000008021681AC0000000640 +:102D0000021681B000000007021681B40000000125 +:102D10000216881801010120021681B80000000186 +:102D2000021681BC00000001021681C000000001F3 +:102D3000021681C4000000010216881C0101010175 +:102D4000021681C800000001021681CC00000001BB +:102D5000021681D000000001021681D4000000019B +:102D60000216882001010101021681D8000000012D +:102D7000021681DC00000001021681E00000000163 +:102D8000021681E4000000010216882401010101FD +:102D9000021681E800000001021681EC000000012B +:102DA000021681F0000000010216882801010101CD +:102DB00002168240FFFF003F061682440000000218 +:102DC0000216824CFFFF003F0216825000000100F5 +:102DD000021682540000010006168258000000020C +:102DE00002168260000000C002168264000000C06B +:102DF0000216826800001E000216826C00001E008F +:102E0000021682700000400002168274000040002A +:102E100002168278000080000216827C000080008A +:102E2000021682800000200002168284000020002A +:102E30000616828800000007021682A40000000126 +:102E4000061682A80000000A021681F400000C0891 +:102E5000021681F800000040021681FC000001000B +:102E600002168200000000200216820400000017F3 +:102E700002168208000000800216820C0000020088 +:102E8000021682100000000002168218FFFF01FFE8 +:102E900002168214FFFF01FF0216823C000000139D +:102EA000021680900000013F021680600000014081 +:102EB00002168064000001400616806800000002CF +:102EC00002168070000000C0061680740000000723 +:102ED0000216809C00000048021680A000000048F6 +:102EE000061680A400000002021680AC0000004814 +:102EF000061680B00000000702168238000080002D +:102F000002168234000025E40216809400007FFF40 +:102F100002168220000000070216821C0000000733 +:102F2000021682280000000002168224FFFFFFFF25 +:102F300002168230000000000216822CFFFFFFFF05 +:102F4000021680EC000000FF0214000000000001E7 +:102F50000214000C000000010214004000000001F7 +:102F60000214004400007FFF0214000C0000000067 +:102F700002140000000000000214006C00000000B9 +:102F800002140004000000010214003000000001DF +:102F900002140004000000000214005C00000000A5 +:102FA00002140008000000010214003400000001B7 +:102FB000021400080000000002140060000000007D +:102FC00006028000000020000202005800000032CB +:102FD000020200A003150020020200A40315002035 +:102FE000020200A801000030020200AC081000003C +:102FF000020200B000000033020200B40000003002 +:10300000020200B800000031020200BC0000000310 +:10301000020200C000000006020200C4000000031B +:10302000020200C800000003020200CC00000002FF +:10303000020200D000000000020200D400000002E2 +:10304000020200DC00000000020200E000000006B6 +:10305000020200E400000004020200E80000000296 +:10306000020200EC00000002020200F00000000179 +:10307000020200FC00000006020201200000000025 +:103080000202013400000002020201B0000000014F +:103090000202020C00000001020202140000000102 +:1030A00002020218000000020202040400000001F3 +:1030B0000202040C00000040020204100000004064 +:1030C0000202041C00000004020204200000002090 +:1030D0000202042400000002020204280000001F73 +:1030E00006020500000000120402048000200434DF +:1030F000020200600000000F0202006400000007EE +:1031000002020068000000000202006C0000000ED5 +:103110000602007000000004020200F40000000437 +:103120000202000400000001020200080000000189 +:103130000202000C00000001020200100000000169 +:103140000202001400000001020200180000000149 +:103150000202001C00000001020200200000000129 +:103160000202002400000001020200280000000109 +:103170000202002C000000010202003000000001E9 +:1031800002020034000000010202003800000001C9 +:103190000202003C000000010202004000000001A9 +:1031A0000202004400000001020200480000000189 +:1031B0000202004C00000001020200500000000169 +:1031C00002020108000000C802020118000000020B +:1031D000020201C400000000020201CC0000000055 +:1031E000020201D400000002020201DC0000000221 +:1031F000020201E4000000FF020201EC000000FFF7 +:103200000202010C000000C80202011C00000002C2 +:10321000020201C800000000020201D0000000000C +:10322000020201D800000002020201E000000002D8 +:10323000020201E8000000FF020201F0000000FFAE +:1032400007280400008E00000828076800130454B3 +:10325000072C000033C80000072C800038050CF351 +:10326000072D000038B61AF5072D800007762923B0 +:10327000082D8CB04E6A04560128000000000000A2 +:1032800001280004000000000128000800000000E0 +:103290000128000C000000000128001000000000C0 +:1032A0000128001400000000022800200000000196 +:1032B0000228002400000002022800280000000369 +:1032C0000228002C0000000002280030000000044A +:1032D000022800340000000102280038000000002D +:1032E0000228003C00000001022800400000000409 +:1032F00002280044000000000228004800000001ED +:103300000228004C000000030228005000000000CA +:1033100002280054000000010228005800000004A8 +:103320000228005C0000000002280060000000018C +:10333000022800640000000302280068000000006A +:103340000228006C00000001022800700000000448 +:103350000228007400000000022800780000000429 +:103360000228007C00000003062800800000000204 +:10337000022800A400003FFF022800A8000003FF6D +:10338000022802240000000002280234000000008D +:103390000228024C00000000022802E40000FFFFA7 +:1033A0000628200000000800022B8BC0000000014E +:1033B000022B800000000000022B8040000000185B +:1033C000022B80800000000C022B80C000000066F1 +:1033D0000C2B83000007A1200A2B8300000001387A +:1033E0000B2B8300000013880A2B83400000000091 +:1033F0000C2B8340000001F40B2B834000000005E0 +:10340000022B83800007A120022B83C0000001F45F +:10341000062A3D4800000004042A3D5800020458D2 +:10342000062A3D6000000006062A30000000004821 +:10343000062A2008000000C8062A2000000000021A +:10344000062A31280000008E062A33680000000397 +:10345000042A33740001045A062A3A780000000254 +:10346000042A3A800002045B042A3A700002045DD8 +:10347000042A3E280002045F042A3EB000040461CE +:10348000042A250000020465062A25080000010020 +:10349000062A297000000004042A29600004046739 +:1034A000042A2F480002046B062A3378000000D853 +:1034B000022A3A3800000000062A3A88000000324A +:1034C000042A3D880010046D062A502000000002E6 +:1034D000062A503000000002062A500000000002B8 +:1034E000062A501000000002022A50B80000000115 +:1034F000062A50480000000E042A3D780002047D90 +:10350000062A3C1800000026022A50400000000055 +:10351000062A36D8000000D8022A3A3C00000000F3 +:10352000062A3B5000000032042A3DC80010047FE8 +:10353000062A502800000002062A50380000000227 +:10354000062A500800000002062A50180000000257 +:10355000022A50BC00000001062A50800000000E24 +:10356000042A3D800002048F062A3CB00000002699 +:10357000022A504400000000021010080000000160 +:103580000210101000000264021010000003D000AE +:10359000021010040000003D091018000200049100 +:1035A00009101100001006910610114000000008DB +:1035B00009101160000806A1061011800000000229 +:1035C00009101188000606A9061011A000000018B5 +:1035D000021010100000000006102400000000E09F +:1035E0000210201C0000000002102020000000013A +:1035F000021020C0000000010210200400000001A1 +:10360000021020080000000109103C00000506AF70 +:1036100009103C20000506B409103800000506B961 +:1036200002104028000000100210404400003FFF3C +:103630000210405800280000021040840084924A82 +:1036400006104C000000010002104058000000006D +:103650000610806800000004021080000000108046 +:1036600006108028000000020210803800000010C0 +:10367000021080400000FFFF021080440000FFFFA6 +:1036800002108050000000000210810000000000C5 +:10369000061081200000000202108008000002B520 +:1036A0000210801000000000061082000000004A96 +:1036B000021081080001FFFF061081400000000297 +:1036C0000210800000001A80061090000000002404 +:1036D000061091200000004A061093700000004A76 +:1036E000061095C00000004A0210800400001080FF +:1036F00006108030000000020210803C0000001024 +:10370000021080480000FFFF0210804C0000FFFF05 +:10371000021080540000000002108104000000002C +:1037200006108128000000020210800C000002B583 +:103730000210801400000000061084000000004AFF +:103740000210810C0001FFFF0610814800000002FA +:103750000210800400001A800610909000000024DF +:10376000061092480000004A061094980000004A93 +:10377000061096E80000004A0212049000E383401D +:103780000212051400003C10021205200000000285 +:1037900002120494FFFFFFFF02120498FFFFFFFFD5 +:1037A0000212049CFFFFFFFF021204A0FFFFFFFFB5 +:1037B000021204A4FFFFFFFF021204A8FFFFFFFF95 +:1037C000021204ACFFFFFFFF021204B0FFFFFFFF75 +:1037D000021204B8FFFFFFFF021204BCFFFFFFFF4D +:1037E000021204C0FFFFFFFF021204C4FFFFFFFF2D +:1037F000021204C8FFFFFFFF021204CCFFFFFFFF0D +:10380000021204D0FFFFFFFF021204DCFFFFFFFFE4 +:10381000021204E0FFFFFFFF021204E4FFFFFFFFBC +:10382000021204E8FFFFFFFF021204ECFFFFFFFF9C +:10383000021204F0FFFFFFFF021204F4FFFFFFFF7C +:10384000021204F8FFFFFFFF021204FCFFFFFFFF5C +:1038500002120500FFFFFFFF02120504FFFFFFFF3A +:1038600002120508FFFFFFFF0212050CFFFFFFFF1A +:1038700002120510FFFFFFFF021204D4FFFF3330D6 +:10388000021204D8FFFF3340021204B4F0003000EB +:1038900002120390000000080212039C00000008BE +:1038A000061203A000000002021203BC0000000484 +:1038B000021203C400000004021203D00000000042 +:1038C000021203DC000000000212036C0000000181 +:1038D000021203680000003F021201BC0000004019 +:1038E000021201C000001808021201C400000803FF +:1038F000021201C800000803021201CC00000040BF +:10390000021201D000000003021201D400000803DB +:10391000021201D800000803021201DC00000803B3 +:10392000021201E000010003021201E4000008039A +:10393000021201E800000803021201EC000000037B +:10394000021201F000000003021201F40000000363 +:10395000021201F800000003021201FC0000000343 +:103960000212020000000003021202040000000321 +:1039700002120208000000030212020C0000000301 +:1039800002120210000000030212021400000003E1 +:1039900002120218000000030212021C00000003C1 +:1039A00002120220000000030212022400000003A1 +:1039B00002120228000024030212022C0000002F31 +:1039C0000212023000000009021202340000001945 +:1039D00002120238000001840212023C000001833E +:1039E0000212024000000306021202440000001905 +:1039F00002120248000000060212024C00000306F8 +:103A000002120250000003060212025400000306D4 +:103A10000212025800000C860212025C000003062B +:103A20000212026000000306021202640000000697 +:103A300002120268000000060212026C000000067A +:103A4000021202700000000602120274000000065A +:103A500002120278000000060212027C000000063A +:103A6000021202800000000602120284000000061A +:103A700002120288000000060212028C00000006FA +:103A800002120290000000060212029400000006DA +:103A900002120298000000060212029C00000006BA +:103AA000021202A000000306021202A4000000138A +:103AB000021202A800000006021202B00000100468 +:103AC000021202B400001004021203240010644029 +:103AD0000212032800106440021201B0000000012D +:103AE0000600A000000000160200A06CBF5C0000F1 +:103AF0000200A070FFF51FEF0200A0740000FFFF9E +:103B00000200A078F00003E00200A07C00000000AA +:103B10000200A0800000A0000600A08400000005B4 +:103B20000200A0980FE000000600A09C0000001416 +:103B30000200A0EC555400000200A0F05555555568 +:103B40000200A0F4000055550200A0F8F0000000AB +:103B50000200A0FC555400000200A1005555555527 +:103B60000200A104000055550200A108F000000069 +:103B70000600A22C000000040200A0600000030761 +:103B80000200A10CBF5C00000200A110FFF51FEFB6 +:103B90000200A1140000FFFF0200A118F00003E0E2 +:103BA0000200A11C000000000200A1200000A000F3 +:103BB0000600A124000000050200A1380FE000006B +:103BC0000600A13C000000140200A18C5554000026 +:103BD0000200A190555555550200A194000055557D +:103BE0000200A198F00000000200A19C55540000C2 +:103BF0000200A1A0555555550200A1A4000055553D +:103C00000200A1A8F00000000600A23C0000000491 +:103C10000200A06400000307000000000000000094 +:103C20000000002E00000000000000000000000066 +:103C30000000000000000000000000000000000084 +:103C40000000000000000000000000000000000074 +:103C50000000000000000000000000000000000064 +:103C60000000000000000000000000000000000054 +:103C70000000000000000000002E004D00000000C9 +:103C80000000000000000000000000000000000034 +:103C90000000000000000000000000000000000024 +:103CA00000000000004D008B00000000000000003C +:103CB0000000000000000000000000000000000004 +:103CC00000000000000000000000000000000000F4 +:103CD000008B009000900094009400980000000079 +:103CE00000000000000000000000000000000000D4 +:103CF000000000000000000000000000009802DE4C +:103D000002DE02E802E802F200000000000000000B +:103D100000000000000000000000000000000000A3 +:103D20000000000000000000000000000000000093 +:103D30000000000000000000000000000000000083 +:103D40000000000000000000000000000000000073 +:103D50000000000000000000000000000000000063 +:103D60000000000000000000000000000000000053 +:103D70000000000000000000000000000000000043 +:103D80000000000000000000000000000000000033 +:103D90000000000000000000000000000000000023 +:103DA0000000000000000000000000000000000013 +:103DB0000000000000000000000000000000000003 +:103DC00000000000000000000000000000000000F3 +:103DD000000000000000000002F202FA00000000F3 +:103DE00000000000000000000000000000000000D3 +:103DF00000000000000000000000000000000000C3 +:103E000000000000000000000000000000000000B2 +:103E100000000000000000000000000000000000A2 +:103E20000000000000000000000000000000000092 +:103E300002FA02FF02FF030A030A03150000000052 +:103E40000000000000000000000000000000000072 +:103E50000000000000000000000000000000000062 +:103E60000000000000000000000000000000000052 +:103E70000000000000000000000000000000000042 +:103E80000000000000000000031503160000000001 +:103E90000000000000000000000000000000000022 +:103EA0000000000000000000000000000000000012 +:103EB000000000000316035700000000000000008F +:103EC00000000000000000000000000000000000F2 +:103ED00000000000000000000000000000000000E2 +:103EE0000357037B000000000000000000000000FA +:103EF00000000000000000000000000000000000C2 +:103F0000000000000000000000000000037B03BB75 +:103F100000000000000000000000000000000000A1 +:103F20000000000000000000000000000000000091 +:103F3000000000000000000003BB03F700000000C9 +:103F40000000000000000000000000000000000071 +:103F50000000000000000000000000000000000061 +:103F60000000000003F7043D043D045204520467BE +:103F70000000000000000000000000000000000041 +:103F80000000000000000000000000000000000031 +:103F9000046704ED04ED04F204F204F700000000ED +:103FA0000000000000000000000000000000000011 +:103FB00000000000000000000000000004F704F80A +:103FC00000000000000000000000000000000000F1 +:103FD00000000000000000000000000000000000E1 +:103FE000000000000000000004F8050A00000000C6 +:103FF00000000000000000000000000000000000C1 +:1040000000000000000000000000000000000000B0 +:1040100000000000050A051F051F052205220525D1 +:104020000000000000000000000000000000000090 +:104030000000000000000000000000000000000080 +:1040400005250555000000000000000000000000EC +:104050000000000000000000000000000000000060 +:10406000000000000000000000000000055505DC15 +:104070000000000000000000000000000000000040 +:104080000000000000000000000000000000000030 +:10409000000000000000000005DC05E305E305E783 +:1040A00005E705EB00000000000000000000000034 +:1040B0000000000000000000000000000000000000 +:1040C0000000000005EB062B062B06330633063BEB +:1040D00000000000000000000000000000000000E0 +:1040E00000000000000000000000000000000000D0 +:1040F000063B068806880695069506A20000000085 +:1041000000000000000000000000000000000000AF +:1041100000000000000000000000000006A206AE43 +:10412000000000000000000000000000000000008F +:10413000000000000000000000000000000000007F +:10414000000000000000000006AE06B40000000001 +:10415000000000000000000000000000000000005F +:10416000000000000000000000000000000000004F +:104170000000000006B406B70000000000000000C8 +:10418000000000000000000000000000000000002F +:10419000000000000000000000000000000000001F +:1041A00006B706BD0000000000000000000000008F +:1041B00000000000000000000000000000000000FF +:1041C00000000000000000000000000006BD06BE68 +:1041D00006BE06D006D006E2000000000000000087 +:1041E00000000000000000000000000000000000CF +:1041F000000000000000000006E2074F0000000081 +:1042000000000000000000000000000000000000AE +:10421000000000000000000000000000000000009E +:1042200000000000074F0750075007630763077639 +:10423000000000000000000000000000000000007E +:10424000000000000000000000000000000000006E +:10425000000000000000000000000000000000005E +:10426000000000000000000000000000000000004E +:10427000000000000000000000000000000000003E +:10428000000000000000000000000000000000002E +:10429000000000000000000000000000000000001E +:1042A000000000000000000000000000000000000E +:1042B00000000000000000000000000000000000FE +:1042C00000000000000000000000000000000000EE +:1042D00000000000000000000000000000000000DE +:1042E00000000000000000000000000000000000CE +:1042F00000000000000000000000000000000000BE +:1043000000000000000000000000000000000000AD +:10431000000000000000000000000000000000009D +:10432000000000000000000000000000000000008D +:1043300000010000000204C00003098000040E40D8 +:1043400000051300000617C000071C80000821406C +:1043500000092600000A2AC0000B2F80000C344000 +:10436000000D3900000E3DC0000F42800010474094 +:1043700000114C00001250C00013558000145A4028 +:1043800000155F00001663C00017688000186D40BC +:1043900000197200001A76C0001B7B80001C804050 +:1043A000001D8500001E89C0001F8E800000934004 +:1043B00000002000000040000000600000008000BD +:1043C0000000A0000000C0000000E00000010000AC +:1043D0000001200000014000000160000001800099 +:1043E0000001A0000001C0000001E0000002000088 +:1043F0000002200000024000000260000002800075 +:104400000002A0000002C0000002E0000003000063 +:104410000003200000034000000360000003800050 +:104420000003A0000003C0000003E000000400003F +:10443000000420000004400000046000000480002C +:104440000004A0000004C0000004E000000500001B +:104450000005200000054000000560000005800008 +:104460000005A0000005C0000005E00000060000F7 +:1044700000062000000640000006600000068000E4 +:104480000006A0000006C0000006E00000070000D3 +:1044900000072000000740000007600000078000C0 +:1044A0000007A0000007C0000007E00000080000AF +:1044B000000820000008400000086000000880009C +:1044C0000008A0000008C0000008E000000900008B +:1044D0000009200000094000000960000009800078 +:1044E0000009A0000009C0000009E000000A000067 +:1044F000000A2000000A4000000A6000000A800054 +:10450000000AA000000AC000000AE000000B000042 +:10451000000B2000000B4000000B6000000B80002F +:10452000000BA000000BC000000BE000000C00001E +:10453000000C2000000C4000000C6000000C80000B +:10454000000CA000000CC000000CE000000D0000FA +:10455000000D2000000D4000000D6000000D8000E7 +:10456000000DA000000DC000000DE000000E0000D6 +:10457000000E2000000E4000000E6000000E8000C3 +:10458000000EA000000EC000000EE000000F0000B2 +:10459000000F2000000F4000000F6000000F80009F +:1045A000000FA000000FC000000FE000001000008E +:1045B000001020000010400000106000001080007B +:1045C0000010A0000010C0000010E000001100006A +:1045D0000011200000114000001160000011800057 +:1045E0000011A0000011C0000011E0000012000046 +:1045F0000012200000124000001260000012800033 +:104600000012A0000012C0000012E0000013000021 +:10461000001320000013400000136000001380000E +:104620000013A0000013C0000013E00000140000FD +:1046300000142000001440000014600000148000EA +:104640000014A0000014C0000014E00000150000D9 +:1046500000152000001540000015600000158000C6 +:104660000015A0000015C0000015E00000160000B5 +:1046700000162000001640000016600000168000A2 +:104680000016A0000016C0000016E0000017000091 +:10469000001720000017400000176000001780007E +:1046A0000017A0000017C0000017E000001800006D +:1046B000001820000018400000186000001880005A +:1046C0000018A0000018C0000018E0000019000049 +:1046D0000019200000194000001960000019800036 +:1046E0000019A0000019C0000019E000001A000025 +:1046F000001A2000001A4000001A6000001A800012 +:10470000001AA000001AC000001AE000001B000000 +:10471000001B2000001B4000001B6000001B8000ED +:10472000001BA000001BC000001BE000001C0000DC +:10473000001C2000001C4000001C6000001C8000C9 +:10474000001CA000001CC000001CE000001D0000B8 +:10475000001D2000001D4000001D6000001D8000A5 +:10476000001DA000001DC000001DE000001E000094 +:10477000001E2000001E4000001E6000001E800081 +:10478000001EA000001EC000001EE000001F000070 +:10479000001F2000001F4000001F6000001F80005D +:1047A000001FA000001FC000001FE000002000004C +:1047B0000020200000204000002060000020800039 +:1047C0000020A0000020C0000020E0000021000028 +:1047D0000021200000214000002160000021800015 +:1047E0000021A0000021C0000021E0000022000004 +:1047F00000222000002240000022600000228000F1 +:104800000022A0000022C0000022E00000230000DF +:1048100000232000002340000023600000238000CC +:104820000023A0000023C0000023E00000240000BB +:1048300000242000002440000024600000248000A8 +:104840000024A0000024C0000024E0000025000097 +:104850000025200000254000002560000025800084 +:104860000025A0000025C0000025E0000026000073 +:104870000026200000264000002660000026800060 +:104880000026A0000026C0000026E000002700004F +:10489000002720000027400000276000002780003C +:1048A0000027A0000027C0000027E000002800002B +:1048B0000028200000284000002860000028800018 +:1048C0000028A0000028C0000028E0000029000007 +:1048D00000292000002940000029600000298000F4 +:1048E0000029A0000029C0000029E000002A0000E3 +:1048F000002A2000002A4000002A6000002A8000D0 +:10490000002AA000002AC000002AE000002B0000BE +:10491000002B2000002B4000002B6000002B8000AB +:10492000002BA000002BC000002BE000002C00009A +:10493000002C2000002C4000002C6000002C800087 +:10494000002CA000002CC000002CE000002D000076 +:10495000002D2000002D4000002D6000002D800063 +:10496000002DA000002DC000002DE000002E000052 +:10497000002E2000002E4000002E6000002E80003F +:10498000002EA000002EC000002EE000002F00002E +:10499000002F2000002F4000002F6000002F80001B +:1049A000002FA000002FC000002FE000003000000A +:1049B00000302000003040000030600000308000F7 +:1049C0000030A0000030C0000030E00000310000E6 +:1049D00000312000003140000031600000318000D3 +:1049E0000031A0000031C0000031E00000320000C2 +:1049F00000322000003240000032600000328000AF +:104A00000032A0000032C0000032E000003300009D +:104A1000003320000033400000336000003380008A +:104A20000033A0000033C0000033E0000034000079 +:104A30000034200000344000003460000034800066 +:104A40000034A0000034C0000034E0000035000055 +:104A50000035200000354000003560000035800042 +:104A60000035A0000035C0000035E0000036000031 +:104A7000003620000036400000366000003680001E +:104A80000036A0000036C0000036E000003700000D +:104A900000372000003740000037600000378000FA +:104AA0000037A0000037C0000037E00000380000E9 +:104AB00000382000003840000038600000388000D6 +:104AC0000038A0000038C0000038E00000390000C5 +:104AD00000392000003940000039600000398000B2 +:104AE0000039A0000039C0000039E000003A0000A1 +:104AF000003A2000003A4000003A6000003A80008E +:104B0000003AA000003AC000003AE000003B00007C +:104B1000003B2000003B4000003B6000003B800069 +:104B2000003BA000003BC000003BE000003C000058 +:104B3000003C2000003C4000003C6000003C800045 +:104B4000003CA000003CC000003CE000003D000034 +:104B5000003D2000003D4000003D6000003D800021 +:104B6000003DA000003DC000003DE000003E000010 +:104B7000003E2000003E4000003E6000003E8000FD +:104B8000003EA000003EC000003EE000003F0000EC +:104B9000003F2000003F4000003F6000003F8000D9 +:104BA000003FA000003FC000003FE000003FE001E8 +:104BB00000000000000001FF0000020000007FF87C +:104BC00000007FF80000016A0000150000000001ED +:104BD0000000FF00000000000000FF0000000000D7 +:104BE00000000000140AFF000000000100000000A7 +:104BF00000201001000000000100860000000100FC +:104C00000000860200008604000086060000860878 +:104C10000000860A0000860C0000860E0000861048 +:104C20000000861200008614000086160000861818 +:104C30000000861A0000861C0000861E00008620E8 +:104C400000008622000086240000862600008628B8 +:104C50000000862A0000862C0000862E0000863088 +:104C60000000863200008634000086360000863858 +:104C70000000863A0000863C0000863E0000864028 +:104C800000008642000086440000864600008648F8 +:104C90000000864A0000864C0000864E00008650C8 +:104CA0000000865200008654000086560000865898 +:104CB0000000865A0000865C0000865E0000866068 +:104CC0000000866200008664000086660000866838 +:104CD0000000866A0000866C0000866E0000867008 +:104CE00000008672000086740000867600008678D8 +:104CF0000000867A0000867C0000867E00008680A8 +:104D00000000868200008684000086860000868877 +:104D10000000868A0000868C0000868E0000869047 +:104D20000000869200008694000086960000869817 +:104D30000000869A0000869C0000869E000086A0E7 +:104D4000000086A2000086A4000086A6000086A8B7 +:104D5000000086AA000086AC000086AE000086B087 +:104D6000000086B2000086B4000086B6000086B857 +:104D7000000086BA000086BC000086BE000086C027 +:104D8000000086C2000086C4000086C6000086C8F7 +:104D9000000086CA000086CC000086CE000086D0C7 +:104DA000000086D2000086D4000086D6000086D897 +:104DB000000086DA000086DC000086DE000086E067 +:104DC000000086E2000086E4000086E6000086E837 +:104DD000000086EA000086EC000086EE000086F007 +:104DE000000086F2000086F4000086F6000086F8D7 +:104DF000000086FA000086FC000086FE00008700A6 +:104E00000000870200008704000087060000870872 +:104E10000000870A0000870C0000870E0000871042 +:104E20000000871200008714000087160000871812 +:104E30000000871A0000871C0000871E00008720E2 +:104E400000008722000087240000872600008728B2 +:104E50000000872A0000872C0000872E0000873082 +:104E60000000873200008734000087360000873852 +:104E70000000873A0000873C0000873E0000874022 +:104E800000008742000087440000874600008748F2 +:104E90000000874A0000874C0000874E00008750C2 +:104EA0000000875200008754000087560000875892 +:104EB0000000875A0000875C0000875E0000876062 +:104EC0000000876200008764000087660000876832 +:104ED0000000876A0000876C0000876E0000877002 +:104EE00000008772000087740000877600008778D2 +:104EF0000000877A0000877C0000877E00008780A2 +:104F00000000878200008784000087860000878871 +:104F10000000878A0000878C0000878E0000879041 +:104F20000000879200008794000087960000879811 +:104F30000000879A0000879C0000879E000087A0E1 +:104F4000000087A2000087A4000087A6000087A8B1 +:104F5000000087AA000087AC000087AE000087B081 +:104F6000000087B2000087B4000087B6000087B851 +:104F7000000087BA000087BC000087BE000087C021 +:104F8000000087C2000087C4000087C6000087C8F1 +:104F9000000087CA000087CC000087CE000087D0C1 +:104FA000000087D2000087D4000087D6000087D891 +:104FB000000087DA000087DC000087DE000087E061 +:104FC000000087E2000087E4000087E6000087E831 +:104FD000000087EA000087EC000087EE000087F001 +:104FE000000087F2000087F4000087F6000087F8D1 +:104FF000000087FA000087FC000087FEFFFFFFFF2C +:10500000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFB0 +:10501000FFFFFFFFFFFFFFFFFFFFFFFF0000000399 +:1050200000BEBC20000000000000000500000003DE +:1050300000BEBC20000000000000000500002000B1 +:10504000000040C000006180000082400000A3001A +:105050000000C3C00000E4800001054000012600FC +:10506000000146C000016780000188400001A900DE +:105070000001C9C00001EA8000020B4000022C00C0 +:1050800000024CC000026D8000028E400002AF00A2 +:105090000002CFC00002F08000001140000080003C +:1050A000000103800001870000020A8000028E00D8 +:1050B00000031180000395000004188000049C0088 +:1050C00000051F800005A300000626800006AA0038 +:1050D00000072D800007B100000834800008B800E8 +:1050E00000093B800009BF00000A4280000AC60098 +:1050F000000B4980000BCD00000C5080000CD40048 +:10510000000D578000005B0000007FF800007FF872 +:1051100000000166000015000000FF000000000014 +:105120000000FF0000000000000019000000000067 +:1051300000000000FFFFFFFF00007FF800007FF885 +:1051400000000361000015000000FF000FFFFFFFDB +:105150000000FF000FFFFFFF000000FF0000FF0046 +:105160000FFFFFFF0000FF000FFFFFFF000000FF29 +:105170000000FF000FFFFFFF0000FF000FFFFFFF19 +:10518000000000FF0000FF000FFFFFFF0000FF0016 +:105190000FFFFFFF000000FF0000FF000FFFFFFFF9 +:1051A0000000FF000FFFFFFF000000FF0000FF00F6 +:1051B0000FFFFFFF0000FF000FFFFFFF000000FFD9 +:1051C0000000FF000FFFFFFF0000FF000FFFFFFFC9 +:1051D000000000FF0000FF000FFFFFFF0000FF00C6 +:1051E0000FFFFFFF000000FF0000FF000FFFFFFFA9 +:1051F0000000FF000FFFFFFF000000FF0000FF00A6 +:105200000FFFFFFF0000FF000FFFFFFF000000FF88 +:105210000000FF000FFFFFFF0000FF000FFFFFFF78 +:10522000000000FF0000FF000FFFFFFF0000FF0075 +:105230000FFFFFFF000000FF0000FF000FFFFFFF58 +:105240000000FF000FFFFFFF000000FF0000FF0055 +:105250000FFFFFFF0000FF000FFFFFFF000000FF38 +:105260000000FF000FFFFFFF0000FF000FFFFFFF28 +:10527000000000FF0000FF000FFFFFFF0000FF0025 +:105280000FFFFFFF000000FF0000FF000FFFFFFF08 +:105290000000FF000FFFFFFF000000FF0000FF0005 +:1052A0000FFFFFFF0000FF000FFFFFFF000000FFE8 +:1052B0000000FF000FFFFFFF0000FF000FFFFFFFD8 +:1052C000000000FF0000FF000FFFFFFF0000FF00D5 +:1052D0000FFFFFFF000000FF0000FF000FFFFFFFB8 +:1052E0000000FF000FFFFFFF000000FF0000FF00B5 +:1052F0000FFFFFFF0000FF000FFFFFFF000000FF98 +:105300000000FF000FFFFFFF0000FF000FFFFFFF87 +:10531000000000FF0000FF000FFFFFFF0000FF0084 +:105320000FFFFFFF000000FF0000FF000FFFFFFF67 +:105330000000FF000FFFFFFF000000FF0000FF0064 +:105340000FFFFFFF0000FF000FFFFFFF000000FF47 +:105350000000FF000FFFFFFF0000FF000FFFFFFF37 +:10536000000000FF0000FF000FFFFFFF0000FF0034 +:105370000FFFFFFF000000FF0000FF000FFFFFFF17 +:105380000000FF000FFFFFFF000000FF0000FF0014 +:105390000FFFFFFF0000FF000FFFFFFF000000FFF7 +:1053A0000000FF000FFFFFFF0000FF000FFFFFFFE7 +:1053B000000000FF0000FF000FFFFFFF0000FF00E4 +:1053C0000FFFFFFF000000FF000000FF000000FFD4 +:1053D0000000FF00000000000000FF0000000000CF +:1053E000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFCD +:1053F000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFBD +:1054000000001000000020800000310000004180FA +:1054100000005200000062800000730000008380E2 +:10542000000094000000A4800000B5000000C580CA +:105430000000D6000000E6800000F70000010780B1 +:105440000001180000012880000139000001498096 +:1054500000015A0000016A8000017B0000018B807E +:1054600000019C000001AC800001BD000001CD8066 +:105470000001DE000001EE8000000F0000000000CF +:1054800000007FF800007FF80000021D00001500FA +:1054900010000000000028AD00010001FFFFFFFF29 +:1054A000FFFFFFFF00090206CCCCCCC17058103CB6 +:1054B000000000000000FF00000000000000FF00EE +:1054C000000000000000000000000001CCCC020140 +:1054D000CCCCCCCCCCCC0201CCCCCCCC00000000D1 +:1054E000FFFFFFFF0000FFFF000000000000FFFFC4 +:1054F000000000000000FFFF000000000000FFFFB0 +:10550000000000000000FFFF000000000000FFFF9F +:10551000000000000000FFFF000000000000FFFF8F +:1055200000000000000E0000011600D60000FFFF82 +:10553000000000000000FFFF000000000000FFFF6F +:10554000000000000000FFFF000000000000FFFF5F +:10555000000000000000FFFF000000000000FFFF4F +:10556000000000000000FFFF0000000000720000CB +:10557000012300F3FFFFFFF3318FFFFF0C30C30C5B +:10558000C30C30C3CF3CF300F3CF3CF30000CF3C5F +:10559000CDCDCDCDFFFFFFF130EFFFFF0C30C30CC1 +:1055A000C30C30C3CF3CF300F3CF3CF30001CF3C3E +:1055B000CDCDCDCDFFFFFFF6305FFFFF0C30C30C2C +:1055C000C30C30C3CF3CF300F3CF3CF30002CF3C1D +:1055D000CDCDCDCDFFFFF4061CBFFFFF0C30C305C2 +:1055E000C30C30C3CF300014F3CF3CF30004CF3CE6 +:1055F000CDCDCDCDFFFFFFF2304FFFFF0C30C30C00 +:10560000C30C30C3CF3CF300F3CF3CF30008CF3CD6 +:10561000CDCDCDCDFFFFFFFA302FFFFF0C30C30CF7 +:10562000C30C30C3CF3CF300F3CF3CF30010CF3CAE +:10563000CDCDCDCDFFFFFFF731EFFFFF0C30C30C19 +:10564000C30C30C3CF3CF300F3CF3CF30020CF3C7E +:10565000CDCDCDCDFFFFFFF5302FFFFF0C30C30CBC +:10566000C30C30C3CF3CF300F3CF3CF30040CF3C3E +:10567000CDCDCDCDFFFFFFF3318FFFFF0C30C30C3D +:10568000C30C30C3CF3CF300F3CF3CF30000CF3C5E +:10569000CDCDCDCDFFFFFFF1310FFFFF0C30C30C9F +:1056A000C30C30C3CF3CF300F3CF3CF30001CF3C3D +:1056B000CDCDCDCDFFFFFFF6305FFFFF0C30C30C2B +:1056C000C30C30C3CF3CF300F3CF3CF30002CF3C1C +:1056D000CDCDCDCDFFFFF4061CBFFFFF0C30C305C1 +:1056E000C30C30C3CF300014F3CF3CF30004CF3CE5 +:1056F000CDCDCDCDFFFFFFF2304FFFFF0C30C30CFF +:10570000C30C30C3CF3CF300F3CF3CF30008CF3CD5 +:10571000CDCDCDCDFFFFFFFA302FFFFF0C30C30CF6 +:10572000C30C30C3CF3CF300F3CF3CF30010CF3CAD +:10573000CDCDCDCDFFFFFFF730EFFFFF0C30C30C19 +:10574000C30C30C3CF3CF300F3CF3CF30020CF3C7D +:10575000CDCDCDCDFFFFFFF5304FFFFF0C30C30C9B +:10576000C30C30C3CF3CF300F3CF3CF30040CF3C3D +:10577000CDCDCDCDFFFFFFFF30CFFFFF0C30C30CF1 +:10578000C30C30C3CF3CF3CCF3CF3CF30000CF3C91 +:10579000CDCDCDCDFFFFFFFF30CFFFFF0C30C30CD1 +:1057A000C30C30C3CF3CF3CCF3CF3CF30001CF3C70 +:1057B000CDCDCDCDFFFFFFFF30CFFFFF0C30C30CB1 +:1057C000C30C30C3CF3CF3CCF3CF3CF30002CF3C4F +:1057D000CDCDCDCDFFFFFFFF30CFFFFF0C30C30C91 +:1057E000C30C30C3CF3CF3CCF3CF3CF30004CF3C2D +:1057F000CDCDCDCDFFFFFFFF30CFFFFF0C30C30C71 +:10580000C30C30C3CF3CF3CCF3CF3CF30008CF3C08 +:10581000CDCDCDCDFFFFFFFF30CFFFFF0C30C30C50 +:10582000C30C30C3CF3CF3CCF3CF3CF30010CF3CE0 +:10583000CDCDCDCDFFFFFFFF30CFFFFF0C30C30C30 +:10584000C30C30C3CF3CF3CCF3CF3CF30020CF3CB0 +:10585000CDCDCDCDFFFFFFFF30CFFFFF0C30C30C10 +:10586000C30C30C3CF3CF3CCF3CF3CF30040CF3C70 +:10587000CDCDCDCDFFFFFFF3320FFFFF0C30C30CBA +:10588000C30C30C3CF3CF300F3CF3CF30000CF3C5C +:10589000CDCDCDCDFFFFFFF1310FFFFF0C30C30C9D +:1058A000C30C30C3CF3CF300F3CF3CF30001CF3C3B +:1058B000CDCDCDCDFFFFFFF6305FFFFF0C30C30C29 +:1058C000C30C30C3CF3CF300F3CF3CF30002CF3C1A +:1058D000CDCDCDCDFFFFF4061CBFFFFF0C30C305BF +:1058E000C30C30C3CF300014F3CF3CF30004CF3CE3 +:1058F000CDCDCDCDFFFFFFF2304FFFFF0C30C30CFD +:10590000C30C30C3CF3CF300F3CF3CF30008CF3CD3 +:10591000CDCDCDCDFFFFFF8A042FFFFF0C30C30C90 +:10592000C30C30C3CF3CC000F3CF3CF30010CF3CDE +:10593000CDCDCDCDFFFFFF9705CFFFFF0C30C30CC2 +:10594000C30C30C3CF3CC000F3CF3CF30020CF3CAE +:10595000CDCDCDCDFFFFFFF5310FFFFF0C30C30CD8 +:10596000C30C30C3CF3CF300F3CF3CF30040CF3C3B +:10597000CDCDCDCDFFFFFFF3300FFFFF0C30C30CBB +:10598000C30C30C3CF3CF300F3CF3CF30000CF3C5B +:10599000CDCDCDCDFFFFFFF1300FFFFF0C30C30C9D +:1059A000C30C30C3CF3CF300F3CF3CF30001CF3C3A +:1059B000CDCDCDCDFFFFFFF6305FFFFF0C30C30C28 +:1059C000C30C30C3CF3CF300F3CF3CF30002CF3C19 +:1059D000CDCDCDCDFFFFF4061CBFFFFF0C30C305BE +:1059E000C30C30C3CF300014F3CF3CF30004CF3CE2 +:1059F000CDCDCDCDFFFFFFF2304FFFFF0C30C30CFC +:105A0000C30C30C3CF3CF300F3CF3CF30008CF3CD2 +:105A1000CDCDCDCDFFFFFFFA302FFFFF0C30C30CF3 +:105A2000C30C30C3CF3CF300F3CF3CF30010CF3CAA +:105A3000CDCDCDCDFFFFFF97040FFFFF0C30C30C82 +:105A4000C30C30C3CF3CC000F3CF3CF30020CF3CAD +:105A5000CDCDCDCDFFFFFFF5300FFFFF0C30C30CD8 +:105A6000C30C30C3CF3CF300F3CF3CF30040CF3C3A +:105A7000CDCDCDCDFFFFFFFF30CFFFFF0C30C30CEE +:105A8000C30C30C3CF3CF3CCF3CF3CF30000CF3C8E +:105A9000CDCDCDCDFFFFFFFF30CFFFFF0C30C30CCE +:105AA000C30C30C3CF3CF3CCF3CF3CF30001CF3C6D +:105AB000CDCDCDCDFFFFFFFF30CFFFFF0C30C30CAE +:105AC000C30C30C3CF3CF3CCF3CF3CF30002CF3C4C +:105AD000CDCDCDCDFFFFFFFF30CFFFFF0C30C30C8E +:105AE000C30C30C3CF3CF3CCF3CF3CF30004CF3C2A +:105AF000CDCDCDCDFFFFFFFF30CFFFFF0C30C30C6E +:105B0000C30C30C3CF3CF3CCF3CF3CF30008CF3C05 +:105B1000CDCDCDCDFFFFFFFF30CFFFFF0C30C30C4D +:105B2000C30C30C3CF3CF3CCF3CF3CF30010CF3CDD +:105B3000CDCDCDCDFFFFFFFF30CFFFFF0C30C30C2D +:105B4000C30C30C3CF3CF3CCF3CF3CF30020CF3CAD +:105B5000CDCDCDCDFFFFFFFF30CFFFFF0C30C30C0D +:105B6000C30C30C3CF3CF3CCF3CF3CF30040CF3C6D +:105B7000CDCDCDCDFFFFFFFF30CFFFFF0C30C30CED +:105B8000C30C30C3CF3CF3CCF3CF3CF30000CF3C8D +:105B9000CDCDCDCDFFFFFFFF30CFFFFF0C30C30CCD +:105BA000C30C30C3CF3CF3CCF3CF3CF30001CF3C6C +:105BB000CDCDCDCDFFFFFFFF30CFFFFF0C30C30CAD +:105BC000C30C30C3CF3CF3CCF3CF3CF30002CF3C4B +:105BD000CDCDCDCDFFFFFFFF30CFFFFF0C30C30C8D +:105BE000C30C30C3CF3CF3CCF3CF3CF30004CF3C29 +:105BF000CDCDCDCDFFFFFFFF30CFFFFF0C30C30C6D +:105C0000C30C30C3CF3CF3CCF3CF3CF30008CF3C04 +:105C1000CDCDCDCDFFFFFFFF30CFFFFF0C30C30C4C +:105C2000C30C30C3CF3CF3CCF3CF3CF30010CF3CDC +:105C3000CDCDCDCDFFFFFFFF30CFFFFF0C30C30C2C +:105C4000C30C30C3CF3CF3CCF3CF3CF30020CF3CAC +:105C5000CDCDCDCDFFFFFFFF30CFFFFF0C30C30C0C +:105C6000C30C30C3CF3CF3CCF3CF3CF30040CF3C6C +:105C7000CDCDCDCDFFFFFFFF30CFFFFF0C30C30CEC +:105C8000C30C30C3CF3CF3CCF3CF3CF30000CF3C8C +:105C9000CDCDCDCDFFFFFFFF30CFFFFF0C30C30CCC +:105CA000C30C30C3CF3CF3CCF3CF3CF30001CF3C6B +:105CB000CDCDCDCDFFFFFFFF30CFFFFF0C30C30CAC +:105CC000C30C30C3CF3CF3CCF3CF3CF30002CF3C4A +:105CD000CDCDCDCDFFFFFFFF30CFFFFF0C30C30C8C +:105CE000C30C30C3CF3CF3CCF3CF3CF30004CF3C28 +:105CF000CDCDCDCDFFFFFFFF30CFFFFF0C30C30C6C +:105D0000C30C30C3CF3CF3CCF3CF3CF30008CF3C03 +:105D1000CDCDCDCDFFFFFFFF30CFFFFF0C30C30C4B +:105D2000C30C30C3CF3CF3CCF3CF3CF30010CF3CDB +:105D3000CDCDCDCDFFFFFFFF30CFFFFF0C30C30C2B +:105D4000C30C30C3CF3CF3CCF3CF3CF30020CF3CAB +:105D5000CDCDCDCDFFFFFFFF30CFFFFF0C30C30C0B +:105D6000C30C30C3CF3CF3CCF3CF3CF30040CF3C6B +:105D7000CDCDCDCD000C0000000700C00002813069 +:105D8000000B81580002021000010230000F024097 +:105D900000010330000C0000000800C00002814038 +:105DA000000B81680002022000010240000702503F +:105DB000000202C000100000000801000002818003 +:105DC000000B81A80002026000018280000E829810 +:105DD0000008038000028000000B8028000200E021 +:105DE000000101000000811000000118CCCCCCCCD7 +:105DF000CCCCCCCCCCCCCCCCCCCCCCCC00002000F3 +:105E0000CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCD2 +:105E100000002000CCCCCCCCCCCCCCCCCCCCCCCCD2 +:105E2000CCCCCCCC00002000000000000000000022 +:105E30001F8B080000000000000BFB51CFC0F003D7 +:105E40008ABB5819180238107C7AE0A58C94E9DFD7 +:105E5000C8CCC0B00388AF02F17E66D2F5B34A2346 +:105E6000D8F7241818182419184E893130EC9244A8 +:105E700088E702D5084A3130DC858A0500D967A554 +:105E8000E81B4EA39836F8BB3A2AFF912A84CE87A6 +:105E900089A3C93F86CA6F5480D03FD5B19BBB0947 +:105EA0002A0F00FE694F6760030000000000000039 +:105EB0001F8B080000000000000BED7D0B7854D50F +:105EC000B9E8DACFD933994C7642422610700703ED +:105ED000040D30208FA85427E1D1E0E5E8F0462EEC +:105EE000CA80AF0892448D356D39373B6412020287 +:105EF0008ECAA1B4A53A207AA247DBD4464B7BF5E3 +:105F0000DC206A73DAD37B9152A52DB6413D281669 +:105F100068F49403BDD796BBFE7FAD3DD97B672661 +:105F20000F5FDF395F1B3EDD597BAFBDD6BFFEF78C +:105F3000FAFF7FEDA8A297A8971072117EAE256494 +:105F40009D4008C9EBBD5AF78916AD26B9845405A2 +:105F500055632B7DB65E0A1B8DD3E8FD4BC4D01371 +:105F600004EE8F9B432611A2C07B05844C85FF4D18 +:105F70002744CE691D1EF5D37BD2AA2CB85AE3590B +:105F8000D72A99107D2A3CDF362ED5F3E4FC09A5EB +:105F9000A75B23F873710C21F5C76F9CFF8AD5A608 +:105FA000FF8D2499B9272FA7BFCC24332F4A847C97 +:105FB00054B828ABD3483FDE070D5DBA3C9690F34A +:105FC0000D2BE6BF32B6EFF3F512A96D2FED7BFF77 +:105FD0002AA2215E8866AA9189BDEB5E4F48A72759 +:105FE0008790CD859BD87A7329B2AEA4F7DBFE45A6 +:105FF000974B7AE15C2FD37E53FBAE871013C7B566 +:10600000C649BE9FE872BCEF7E2F391E7F9FC8F441 +:10601000DF0C42B00B5DFF74217A2DDCF7142E32B9 +:1060200047D0F6FA67CA49B4343DFC497A7D42F854 +:10603000ADF7D2D291F7FB687F530BA1EF9D54E3EC +:10604000D75F45F9E8BDEF4BA14DC0477BC6CF21D7 +:10605000017A9F303EB2E8746A7FD3F054FC918E8F +:106060004E7F4FBCC87F167F5589ABB23AC927E730 +:10607000AF3B80BF326CFCD5BEB8DFF13E297FC597 +:10608000DCFCC5F171BA9DAD9FEC1EC6E8C2E9E526 +:10609000A64F5ABA7CD2F7FAF2D316C0ABA77DB19D +:1060A0003982A4E0270EAF45AF4F0BEF407C444848 +:1060B0001CE94C484482F97BEFB36B469921009F61 +:1060C000D1E6615847904D4582B7B6DC2D52380372 +:1060D00024D13AAE88B6BBD72C00B803C7E79F02DD +:1060E00079680E5568B3E97AF569C643F3E835A3D4 +:1060F0005417603D5B89084A808E576D969702BDA4 +:1061000008B69F366F099B80071226643821F7F185 +:106110003511221A326DABF0EB9854EB504927C37E +:106120008770D1D3F7FD74EB577BDF23178BE0FF2C +:10613000F71058DF40EF91287BCFA4FF00DF39AE86 +:1061400071F439B46DE3FB00B1B5E9F3A3F00BE2F0 +:10615000FBEE2F64BE6CB24F33A87E504B443D0122 +:10616000FD89912DD37646255544F03C480E528A40 +:106170000C489766422ADB811F493B5938B117BE4C +:106180005344C0F514DCBE734D0B555DE7CAFC21CA +:10619000E0F3A04EC8B09CBEEBD9D6401979BCAD97 +:1061A0001D7A0EF93F46F9680C7DDF0C317BB8B5DE +:1061B000E4653D6A93EF0C41E07CE9E60F62C83389 +:1061C00040CC8055E8B5440C7B039F9E3F64171E6E +:1061D00007CB1FFEA88D3E64E8F40A72BF61B0FCD5 +:1061E000F169E7B3E8DA57AE1A2DBA6A84D2614B87 +:1061F000F1A294FE477ABAEE23D03FA384841329F8 +:10620000DE1B25085C0E4C87BEC12BA58F9424EFA6 +:10621000BD0E7A49F93356ECED071F52AE131FD667 +:10622000B8DE7AC97897AA4422EB228CA7C2789468 +:106230004FB7041F3609958773C0DB141F527C4A81 +:1062400027B44931413EA43F9D026D7B83E1C45692 +:10625000E48304D2C582CF63880EFCCAB93E479B53 +:10626000AC30053BFCDE7A15E150D147A0E3E87481 +:10627000408A0AD94F3A816F2D7E0536B87829B405 +:10628000BFEEE08356632A4945078B5F01AD8C5F03 +:10629000BF3E38FDE29E6F8913DE41BFE7978D93C5 +:1062A000363B94FE3D999CB4E84391580503D8F8D9 +:1062B00060B3420E089309692A5C46A2F4EE667840 +:1062C00044ED580B5C0BC03F9C8A7A81B40932C004 +:1062D00069D95512CCC17ED30503C713B55AD42B47 +:1062E000923FCCEC2B7F9E1E2E36FF70231ED629AC +:1062F0007EF3493C2C52FA505D19EA24A037C304BE +:10630000F88084185F48DC4FB7DE8F717EF692A369 +:10631000F83ED5AEA68EF6CC29C77325FA908EB37B +:10632000A584243C48A7B8066DB94426B02FA0FA2E +:10633000C95F40FB6759EC2F2D0801FC59DCBE9268 +:10634000599CBF05AACF289EFDD39CF2ED73C9BF0F +:10635000CCED711F7D96663F615DDDFEDB6302F76C +:10636000DF32881FE9CDDF27FED4FEAAE5B75978D2 +:10637000CD1309E293FC54493C51C4D746DBF7BC2A +:10638000959D80759B159135CD140FE6DB42A809CC +:10639000E829877BB2E8F3934F4AB85FCA5B567F20 +:1063A00009CCB7BDC11C5B6CF307B7CBB51AE09B3A +:1063B000F28566B7173790E80B826DFFE509B68C5A +:1063C0002D1E86FCF7767709980A01F9CFEB8F0529 +:1063D0005F05B9E4F793F8B1B7A5BEEDDC7CC2ED7B +:1063E000E50DE5613A6F2BE8AE11F8D814283CAD05 +:1063F00005ACFD93C6E1E5603F5B3359FBA3C6776F +:10640000C28DC817512D42EFD5138E972E8A17A42F +:10641000BF916FB7AFEEAB7BFD3B64DD077CB6D7BA +:106420009F735D09D8CF32310468DF1B3BA2AFB147 +:10643000E1E39B9E8A37001F2349422040BF582E2C +:10644000CA8FE5CF01E341BB80CB5321398CFD4698 +:10645000477ACA15B8B5427F19AE2DC1E7B2519E31 +:10646000C81CFD24CABF245CBC7CF0F29E6EBD013A +:10647000814452F9F3F74B392857816974DD0EBD19 +:106480005EA8233FF271BF063402FD914D619A0C64 +:106490007A24BE229262BC9F0822F6D3C01E5C41C1 +:1064A000D150B8ACECDFE87A352D3CE5550A97279A +:1064B000D71F32116C66270C2E039E78A306F82591 +:1064C000472502F2AF158623B7019F924858A0F7DF +:1064D000B56038B4D5E8BB3E9530FB9043AF179913 +:1064E0007C13E87F4F9E8EFD09D80B6B5D63002EF9 +:1064F00015E1FA0CE89D2B4E1F98CE23487B3918E6 +:10650000B374F4FEACE99CEE7D377D030293AFFBE0 +:106510009BCE874D2A4F2DC7055102A5182F46BA8D +:10652000689C2EE795A8067EE396AF8A641F6D3FB0 +:106530005ADFBF9F12033FC563B39B3AA3DFC8BBBB +:10654000F4A9C042E9DEDB7597589948C14F9522FE +:10655000D3FB5BEE7A383E16E8F98A73BFA7AC0A24 +:10656000A35F4AF77D95400FEB3D6F31B34F643F1A +:106570005D0FEDAF707FE47CDEA22C92621EEBBA61 +:10658000C7057F21C5732AB9B94FE2FED54E36BE85 +:10659000E5EF9C2FE87F7C0B3F172A4572B814C9A2 +:1065A000EA23A57C3114EF8549BF3B0FDB1EFE2893 +:1065B000512BFA08D8BDC2CE72B82AA4A711F8741C +:1065C0009748AA52C1B7561211BEC230DD7A50BDEB +:1065D0005F688AA099C8BD9281F7F357D51E5428E9 +:1065E0005D5A47911098994B603CD0AB07BD683F0E +:1065F000D55C92F0523DFD5AD1574CB0CB7A21096F +:10660000032C7A2DEC39E97FD4BE1AF4B9B2316A81 +:10661000225CC108EE110E152D437AB750FFCEC390 +:1066200016E2E0A71653EC04BE8DD3F1C11F8C1BFC +:106630001528AFE782D4F2C3CFC7147E6BBF712990 +:10664000C485282901CE0932C2494762F4D4195EB3 +:1066500046EE9E453AA9DD69CDDE85F2605E495081 +:106660005E6572D814C0CEC80953A4F0C6AA983E7D +:106670005072E382DD8EED21D107ED7C23EB9DE8A6 +:10668000FFB5FE595A910AAFD522D36FF7717D78C5 +:106690005E699F8FFE4633958FA2BEFDC39C0EDFC1 +:1066A0008E2D7A703CEA336697ACE75D82E18863B1 +:1066B0008EBCA0E27ADC7ECD3CEED7B41452BF068D +:1066C000E59D2C003F2683F3470B608F3EF76493D4 +:1066D0008449E1C8007F86FA25A494F9251AFD07AC +:1066E000FA2F7F85D39FF1B8FC9674FECCD784C86F +:1066F0000F50DF515505F0EF16E2F3C701BE0BE86E +:106700007ED2E8BBEE2EBE9F9C2B6D2B6AA1703D06 +:10671000962B3AF861349797C78879E2227D1E2F2D +:10672000140D803B5E2FE23ACE19CC6F27EF7A1D15 +:1067300076A2D95CA4119BFED9C1E5695B83E69082 +:106740005BF7D5AFC6A391147A4BE7F4C99815C689 +:10675000F8873F9440FAC33A53F9E90F945668FD1D +:10676000E93FB9445D83F82BAC3825C3B5CCBD5F98 +:106770004A3DAEFB4AEC7EA694BEDF60AF5B289E2E +:10678000DE561CFE78A704FB2E93A0FFE70D5153A5 +:106790001580AB3E1CE0F786A8B8C1B5BBBC12EEB5 +:1067A0001BB3221AC891659FBDA1C856B89FF52595 +:1067B000790BD0CB5B2E8A12A59F269B24C7263748 +:1067C00053E1A68DBF33A9BAB4E3438B7EA512FC77 +:1067D00054522892B1148ECD1F3768763A75D16D18 +:1067E00008DBB73AF9265EDFBF9EFDB47CF173D1BA +:1067F0008A8738E9853FF67808A77392FE7DE21A0A +:10680000FF39E8AD71FA19947E9B0CA027D3177459 +:10681000E385FE435C33C3D08E1B8668DAF4D8C7A9 +:10682000620EE241BE20A35EDABDA6250CF4D2E9D9 +:1068300018405A7A0DA7B2DB5D828A7245F5C655BB +:10684000D27454C802C43FE74A1B91DE8F517A8349 +:106850001E7B8CD4765DCCED957F2DAAA21FDFD553 +:10686000689637160F456F52F8A85F47F630FFE578 +:1068700012CB7FF97BCA2783F057CE53A3C1EDB16A +:1068800017F84AEEA62C4DE12ADCC8EC26F86A3946 +:10689000B46D50BBD729F4F2A387CFA394260E8FF3 +:1068A000477A3BEDD363852F0B1EB06FC5CCBEA9D5 +:1068B000666718F44CA098DA2782F66735E06744DB +:1068C00049BC1CDA2377CFC3757C1BFC503FD8171B +:1068D00082F8F8A698683429CD7CE148A728C1FE43 +:1068E00099E0FECEA29F7B5E6AF5909EBE6C712FF2 +:1068F000D029507B189669B77BD5525EAF3D1C51AD +:10690000D289EAD6ED2FA4F513FE2CF1FDD8CCC622 +:10691000306D8F825FA93FB9537CBC11F663114F74 +:10692000B81EE9EEDA4724E3503CDEBDB6CC122AAD +:1069300063F96FE83C7776291400027E80648F0348 +:10694000DD097689EA9BB5DCAEDD4A2201787886DE +:1069500088185F3B438E04AEB0F1E14E4965F3B455 +:106960002A6F43FCDE8AEFDE16676D4BFFDCB1DB7E +:10697000D9BE9D2C1A0EF1DBDB772AB8FE3B5DFBFE +:10698000D698A4E3B87790DA16C043B342D04F58F4 +:10699000AB1319E2B11B7EF89D19B04FF836B72B37 +:1069A0001F50FE326CFA679D3FA1C27EF69D8E2B72 +:1069B000965D4DE0FD44CB08D89767939476F496A6 +:1069C00056277C03C1EF8697904DFDC221B7092958 +:1069D000E3874F4982236E58AF052641D0E4BC9728 +:1069E0005DCD0AA63FCCDF7A134DE0274A06EF5F64 +:1069F0003B99E5396A67C275A0F77EC6FDD1A1BE95 +:106A00007738CD7B1BB46E15F8BF46362B05B137F2 +:106A10005EA529B5E19120C707CA3B471247BFD6FB +:106A200041F6AB14FBE9E786F794AE99E2E4BE7059 +:106A3000DF40A26F81DC9D17A3D51827E0707B0093 +:106A4000CF125C65A427C64F8A605E7FAB9005714C +:106A5000940EF44FBC86ECA0778DA507A85E82B893 +:106A60004F4689F3B93BAED293A46B27CA1786442D +:106A7000E992029ABF53027FB14C3E9DEC4FE7ABC7 +:106A800086754DC64EA85FEAB87EA926C683B3A612 +:106A9000A17C61BCAE6EFE1813E0A8CB3342A60108 +:106AA0006A3414C6315C7C5573412009DBFEBB4659 +:106AB000EE51418E6AA8FEB6DFBF27C8E2C9E9F4ED +:106AC000B64234C35F027EAD88789274DAB6ADFB0D +:106AD000A3B850D9CEF655594BFAD917DF1364F144 +:106AE000E2B55BC666B1B88B535F9DE5F6E127CF93 +:106AF0003CAE76839E79FAC4F5B0CEF5FF53221AE8 +:106B00009DF7EC3399A413ED464205BBB1AE434A61 +:106B1000690F096962F9F3EF6522BDD63DE7492C9B +:106B2000A0EFAF7BE19D4984C2777653CF6B23C141 +:106B30009F7E5A607171B37BD2627A7F9D4C56A75B +:106B40008AB34C90D93EE4F48F325680FC0A6D072C +:106B50006FC671DB972B6057AD7E86AC20BFD27EAF +:106B600068B7CDA784C45821157C2C1F71FA2981E0 +:106B7000C17740C1FDDFBAB6BD6A94C251D3F621D8 +:106B8000EA8BD9DF7B360078A8392039FCB89A36F1 +:106B9000A9D33309AF27E00A71566106F009E797D8 +:106BA0008E0D185FAD6E7FE0432900EF3BF516C5F3 +:106BB0004BA813F0FAA6145A00ED1FFC63C0A0A85E +:106BC000FAE0F01301C02B1D778D9A05717C277FA9 +:106BD000C3F81772FA8E47391DF3BD35ED5BD87CCB +:106BE0002EBDF801FC52D0370E1B919D7974D23620 +:106BF000B83CEFFA67CF3D6AD2F94E3FF7FB474DFD +:106C00000AF75D7FF9F747BF0E72F9CF5E1DF47A80 +:106C1000CDD3BF0C101B1FAE9359FCE0EC28BA85F6 +:106C2000A2FDCEFECA930087E0EC4BEF8D36E87AEA +:106C3000CF7EFF4FC30DDABFEEA5B9F9B0FEBAE7BC +:106C400067E7F7E7C7009F263C76B81238BE714069 +:106C500060CEC28BFCEAA2CBA18E43A301CE33C788 +:106C60003CB83FABA1F7EAA7029D36A09D85F6464A +:106C70008ADFEA67367F08FAA12F9ECD912206BFF0 +:106C8000A81A0C029DDF9987F4223D681FDDFD6B79 +:106C90008E523A4E4E4FB773E46315F45CCD335BBE +:106CA000D87C2EBA9D815FAEEC4BB7CD2EBA9D231A +:106CB000773D560089D78E618E3C8275ED8D9F475A +:106CC000B222FDE8074BFE07C22BE659285C4BE5D4 +:106CD000F0376490A3E73292745D00747DF6DC684F +:106CE00042F9E27DA5E766B0073D2F79F47DF4FE19 +:106CF000BA97DE44B93AFBFCEBAA81768CF805EA38 +:106D0000579E25C99FC3E06756339F93D4ECCFECC1 +:106D1000F4047AE9539D58586904F0FE09BC9F6059 +:106D2000FC5E9D38B8444841AFD7E5314CFF27F2AF +:106D3000102F1BF6FF46257E271D8532A0E389799B +:106D4000703F1D1DADF5EBB0FE99367AEE6772EA25 +:106D5000EE5F4DE511EC5D92AE09E14D92422ECF12 +:106D6000EEF5C860EFCE825F95326FCAFC99A1E65E +:106D7000577E263BEBAF92F9158E87F4FCC1E47B7E +:106D8000A0F50D157F3F920D1CD78DC7D31FA7D639 +:106D9000F7EF717D514DCCCA1197F6F5436412316E +:106DA0004716F5C27B1A36A894FF4E3F2D613CA8CA +:106DB000A5FD10EA6DB79EA84E13DFBC20333FA19E +:106DC000FAC0C149A0CF4EBFFC23E4CFEA674EA86A +:106DD000102F7EADED076A7769AF3C803D48D8EC57 +:106DE000C1E9EF1E9CC4F4001D3F059D14858D5F15 +:106DF000F3A273FC9A673E748CBFDE6C47FF60A001 +:106E0000793E90C3CB61BD1F1C5608E8D10FDAA5AF +:106E1000CA547EED07DC1E5A786A797DDE6F200F3A +:106E200036ED88CF00BBD9B1299CBF1DFCB5230A24 +:106E300001BD4DE4F0EF3DB4DDF1BACF80FC74C785 +:106E400091659261DB87FED085CF9947CDD9997442 +:106E5000BC99DD9169E0A2BAF546D971BAAFB2F139 +:106E600041DDEB95F9A0EF611F6A8C87F94241D8AB +:106E7000E74A8179952C7F2DEADE94F69A8DA7F862 +:106E80002318AF5274311923837147924423C45796 +:106E900089DFEFCE4F44347B1E6AC5E183B0C5CC99 +:106EA0005DFC62018C132031FD24FA9F2474B11F14 +:106EB000FFCB9D8FB0F09994BF34F9890CFDE6E0CB +:106EC00041D277BCBE7998A806F1ED16FFDAD6223A +:106ED0005B1EA625D8270F3357A178681548CA78B6 +:106EE000ED78A562BE9287BBE368AAE737294CAE6E +:106EF000AE25DDF7AE0138232C9F33CB85AF2F7144 +:106F00007CFDF364BA70AA42CBC1B3A2F89DBD2444 +:106F10001C53E8FDB9AB7A2E7F19BBF37C8E395E2A +:106F2000BC983178FC0D356F17F12CBA5D1944DE31 +:106F30002E5DFEB8170E93EFC7731C798C436FDD7F +:106F4000AF75639EA1B6B5C816F71BDEE92561CC07 +:106F5000E319E81F0EEFBCF39BB741DC39B730E40F +:106F6000257DC7912F5C8D71232B9F2F17863B2189 +:106F7000DE2FEB46B984F32C0F437E61B3C1F205DB +:106F80009B83FDC7F56628D16605E351D7E0B8A21B +:106F9000C6EB0F06B9CE6F2C0E209E0314CF20EF48 +:106FA000B8FF81F51D1778DEBCDB94207F78221BAB +:106FB000F305019994403CE0BCE00B6DC27C823348 +:106FC0006F9E8E7FB7CB26E6CD5B8D3E79F3EF28A3 +:106FD000B67C8396266FAEF99760DE5C23367FB76A +:106FE000A8B75FAFDCB9F2E63016C665B6CF86B893 +:106FF0004C733671E4CD9B41F0AF22E439E5EAD918 +:107000005877E6E5CFCD59B3C3F63639FE32B679B7 +:10701000FCE98FCDE73641FFDC91A416EBD4E40800 +:10702000596AD383EF292C4EBB4109FF50B1D71DBC +:10703000717EB0F23F87DE7A0FF90AAE63285E9B5D +:10704000295F7990AF4E11BB5EB5AE16FF341BFDC4 +:10705000F3857A610AC6CD92EDA0897C110846C3FA +:10706000E114EF4DF230B9B7E60D94513D4AE54DCC +:107070003122988F5275BAE135060F7F3AB82C3E0F +:107080006D36C6B03A289D60FD5EFA754C63714C52 +:10709000887051B876DD787BA83F3FC75AE70C254A +:1070A0007CD28EF7DC4B52D7EF56AB6CDDCD9155D1 +:1070B0002CBF5EE5CCA742FADA1E679D2E44FF5D29 +:1070C000C13821CBA78A5A84E7474C2B3E1E4CC6B9 +:1070D000C30DA833BCCB047DA8AC6A3705B8E6B2B3 +:1070E0007C4AAE16FD58B1D90759EF6672EBCA0F4C +:1070F000CE954E0F09BF565DDCD6061DFDF42D0D55 +:10710000416C6F6E30F0DAD210C6FB6E3A361B2F30 +:10711000076FC1BA341FC665D38DFF604308C789A6 +:107120003594B1F178DE9C90CC26E02B55B4E46523 +:1071300018B6FD127F6E163481FC6D17D8F36B5AAA +:107140002E4579B3F86787D17F5C5A4ACC403E1808 +:10715000EAF87DF9F527B8CEE6597ED4AF03C951D8 +:1071600056279B77B0F328497BC1E6D9314BC379C9 +:1071700076E40E304F9CCD3330FC0C5FDB0E9EC2AC +:107180003A0485F203A828450FA7AED3E3F2D677D9 +:107190001C0FEAF9E620AB0B538BFD6150FECD06C8 +:1071A000CF3716B27CA35A32BC02EEABA1CBB04EA5 +:1071B0005C2DF5633E4F2D1E7E0BB4B71DDCA25730 +:1071C00080FD2814435E03EC76379173516C307E5A +:1071D000AB1697DC06FD7590630AC7280FDB6FA915 +:1071E000C557DD01EF1F9CF29AD144FB3717FA42D5 +:1071F0001E90B76ED9C1FF83D61385CE3C1A91A9D4 +:10720000BEA0FA6BDB94DB4B503E355B9D648A7A03 +:10721000419BDED8A0DAF4864AE6988087747A87A4 +:10722000DADFFBD4BCBEE358EF6F5022F52AEA85C3 +:107230000871D6BBA7CE675BF400370BF2917230B2 +:1072400059A7B7A060786F7EDBAAD373E7B5E3F4E4 +:107250005FAABCB6BBFEFCB3AAD3DBA926EBF446FF +:10726000419DDE8F1512EA84BCFC2FA5D03EA32FD2 +:10727000DFB9C7739FB7A0FE8F06FB9C7472F9330A +:10728000D5993F2D88BAE87EABD731DF2B202FA5CB +:1072900003EB979155CE7146D53AEB6A2FA9CF7182 +:1072A000B48BCC118EFE97B68E713C1F1BBFCCF1F8 +:1072B0007CFCEEA98EF684C4558EFE97B75538DA5D +:1072C00013DBAF73F49F7C6091A33DA573A5A3FF6F +:1072D000155D6B1DCFA71F5EE7783EF3D83D8EF698 +:1072E00095DD5F73F4AFA7EE900A729BCBEB9073C2 +:1072F000F3457B9EB6358FDA25BACFDF9147190665 +:10730000E3DFACAE4B658F937943F77BB2A1867513 +:10731000CCFB8F9B035722D7A13D958DE11506DE4F +:107320009F310FAE649AB3BE5635587D32ECE39C64 +:10733000F502CE3A6355DA86793ACFF12F77099381 +:10734000FAD2552D74CAC160EB9415C3F5DE10E571 +:10735000E2BC2517A3A85C60FCED6309CFB5CCC9DE +:1073600044FFC2B69F423C5AFBA96B34120317D3A9 +:10737000928BF2553D235FC56ED63ECA230EA52ED5 +:10738000CE92BF804DEFC37EC5D233CD6583D3AFE0 +:1073900052E20A873FE9BE3605D6A5D38F051E9B6C +:1073A0007FEFD68F339448213CD7E4B0496CF11A73 +:1073B00052AB38E01E2C9C9FD40EDC45198EA4D015 +:1073C000E32AA9C5BAAB9615610C02903AE2E0D364 +:1073D0009D8BFF47198C4BFDC219CE7532BFD0ED86 +:1073E0004F53FD86FEF40EEA4FA3BD73E947AAA7EB +:1073F0004C5EFF65303F82E943F73A3F2F3FFADFAB +:10740000C059ED875E81A25025EE0FF34402FBC305 +:10741000E6599120C4E7ACBA79EBBD56CFA5384EFA +:107420002C5715217E19EB9A8BF1FA262DAAB13C27 +:107430007114C769CA16F5547562751E962FD6EA7F +:107440001F18BBBF9FB88BA69268AA78DA4E0FCBE5 +:1074500007C5F4B55D604733F35403F6DCAD074F61 +:1074600045208E2497C93AECD70905E61D5B7E8F2F +:107470009028C699B4A0887657ABDF81F30F04EF4C +:10748000CD1E819FFBD8D22FBC5E3575DC251DBC7F +:107490005B00DE6903C3EB05788B60FE6D387F8D82 +:1074A000C748897F85842B6703DD4E7C3982E95686 +:1074B000CA36201F3BCAD8BE9C1A02077F5BFB1C42 +:1074C000CADF0F7BF2B07E15F9DA3AE770A347C73F +:1074D000792CBA92C21C8C6B04A2B1B1C594DF3274 +:1074E000A36C3FDFAB9F181F652A6102F12CD92FD7 +:1074F000627E50E5F110ABDF1F383E9B667523BD01 +:10750000365F29934D426F9D75AC90AE6B72EFBAAA +:10751000FE8F279BF1279FD7479664615D8AF44CC5 +:10752000B03FBDEDE3F872EBEFEF79B8FE2E20052A +:107530004C7F972E877C77BA71DC7E4C3D8FF30EA3 +:10754000BDBE9E9F2FF0DFD30571262BCE4782D381 +:1075500052C6E57BF1CAF295BDF45D6E7452FAC96C +:10756000D3A7629EDC3AAF40D599B35E98D3D7A239 +:10757000AB15472741163FB2E8EC4DE2734FBFF819 +:10758000F482BC5CD1179FBFF2F07CC37F317CBE1C +:10759000023E0DBD6666B2F3E9E4D05709E6A50ADE +:1075A0009D7268BD67F1BB7BFD7FFA2FCA4FD6FA8B +:1075B0002D7E48DFDF4CB9AFB1F2AB999CDF343898 +:1075C000654515CFAB656FB75E0AFBD7A01FF77D8A +:1075D0009965313CDFAB105307BD9069ED6BF879CD +:1075E00023AB5EC957EAF4CB34D7FE45E575517D30 +:1075F000CEDB72FFCD7D8E2A895F17BD266B69F2C7 +:1076000063833C7FB48BE7EB0AEAE28DB01F2EB8B0 +:1076100095D5FBEF51C86AA8AF1C51658ABE5CC8FE +:10762000DF147D3F83AEBFE0C5871A4702496E3540 +:107630008AC0CD7846331C76B8E0AE78B98F3D9FCE +:1076400002E33CA531BD5B5019C773CE4DCF8FCF40 +:10765000023FE195B796EB101FF828B718F74F6770 +:107660005EF08441FF9FC921555817F6C2CCD7C0A0 +:107670008FFF7D43578E6CE39333DF7D7D86428998 +:1076800074E6B9D767C848AC8463FE0D177F310331 +:10769000E0362B48492DE4EF7495C0B8351ACB97E6 +:1076A00059F53EBB86AB2D70FDA9379BC513F3C5BD +:1076B0001DD0AE878018F80D3C9E7FF5696339D4E4 +:1076C0005F66772902D4E33D2498A69F5ECF9F781A +:1076D00048003F4BEDAC85300BBD1F3A042837C73F +:1076E000B27DC9F922525244F5BEEF70ED78F4A78D +:1076F0005DF54E16FFCBB309E6FB7A6ED41260AF90 +:10770000B7CBC6375681FD5E25633DCE76F930CACC +:10771000859B8EC7BD639CF5B93C1E7DE8AD3BE201 +:10772000E5F4FD7BA688C8AFFE1353B2480AF9DD25 +:10773000DE5086F3070ADEAE2C07B03EA67767F46C +:10774000EE93FC3231B3A889548A4453A178F1975F +:1077500011F2B68DEF5A4412D6E9F3171A088ED3F8 +:10776000D1A0E1B5AD411F5B4C3706DF6A08E27579 +:10777000678381D7871B4AF0F9830D2187DCC37C9F +:107780006F97F0760A7FE5F3BA3ED040E7B5C1B116 +:107790006B22957A4AAF5D3C1FF540E9D4ACB5FD4C +:1077A000C4C1F634740D9B3396230BEA4DEBF4BD44 +:1077B0005BFB817F4FA3B07A11F83577CB917DA821 +:1077C0001FA3058B6CFA91FA6D0584B2E2BD2D23DF +:1077D000E6CC29407944799976388AFE7841302E72 +:1077E000401CB1E028BB6F9DB7407A5141FB61EE70 +:1077F0001C4101BD594ADA012CB5344A2A68FF9967 +:10780000794BCAE13E99E8BC3F4365F20DE356D09F +:10781000EB6C2DF2236D3A7CA763B7F92C5DCF1F7B +:107820003B3C06E4791E7CF94F2AEC0B62BF5235D3 +:10783000F0630A5E3C81750F31A15B85CAD8E35ABB +:10784000F51C99EA19DC0C627C952A16CA2731D0FE +:10785000B118FFEC89CDF1C37997E8297BFF5DBEB4 +:10786000E8DDFCE448580B523E4AE62FD6C7C27406 +:10787000D3F902CF5F1CD7D6C5CC4268D3FE53588C +:107880003B46DF7F213B3A52CC86A28BAA58D79742 +:10789000A06DF5AF8A41BDED9B5CEF107FB408E4AD +:1078A0002DD9D6693BD3D696599B68EC6AAD77C380 +:1078B000A13FBD067AAEFA45A11D40A37A8FE1FF34 +:1078C000C0435877DBD6D0A5C7144E7F8B0E542407 +:1078D000270409D6D3A909213186EA8F09FCFB14B4 +:1078E00005D3C24623E8D7841202BD19F231BF7115 +:1078F00042828E6393AB0969BE8382795FA0E336CF +:107900005637ECE6AF67BD2C3F504FCCAD90072308 +:10791000CF283AE623799CF2B465E7F87EF52E2F5E +:107920006B2A9B4CDF65A07FD6C818075B5F142FBE +:1079300057E93CEB7F5414A29615F24A58D7B03E53 +:10794000BB7DF854969772B41FE275B4C16C331BBB +:10795000CE0F541F786834D4055493F8CD5F037864 +:10796000FF95E51F4F1DBC32EB6ADADE40DB107F6E +:10797000DDD0F1BA1AA5FD8671B8AB3BA65C07EB6A +:10798000ABDE2612B188C967783CC573387E994C46 +:10799000F9E49AAD23E77A299D9F1A13D645CA07C1 +:1079A0002B7DE39A3568ABFA04909B95BE89CDC0D8 +:1079B00057EB27F2EF359089AF86655E2F45F96268 +:1079C000D8968618D427EC5F59791D98D9E122936F +:1079D0005BCA88983F94B26398B7F843333BEF0291 +:1079E00029FD8D940EC532E992E97597CAE867B60C +:1079F000C8182FA6F75B95A940977818CF57B432CF +:107A0000BD3FF6450FC69D8B6BC377A25FA097E283 +:107A10003E653449FE605EFA12F88D8E335E27E5CE +:107A2000700EE1C75E162F2C5EB16C3DBC27652E33 +:107A3000F1E1BE5C62E7A0C8B7599C7A979868D715 +:107A400040CE03C548DF5D01C617E6C3A5C817FBD6 +:107A5000C58ACBEE86B8A4B066EBBF005DB38B09D8 +:107A6000D015EEDF43EFEFE7F494B2433AD06F3F27 +:107A7000A7672C219A501F63DD7F41587B27C8DB05 +:107A80003AEFF373348AD7E19E707C18A5C39DDE6C +:107A9000E763C102A4C3188DE2FDCE2D1D316D1424 +:107AA0001DA7313C42B7B5C7FF997A23989FEC4098 +:107AB0007996B31F5E07F24E9FBFA2D1753E95C364 +:107AC000F5057F5E3C26A93FC284DA1AA9B1579F0B +:107AD00068D43E14DBFACFA1FAE0C947591DFBF583 +:107AE000743E9077BA0ECCFFF64C9013509FE5A3EE +:107AF000B080DFE29B3806EBF3E8BA09F8253D13C6 +:107B000065B4B3561CDB3341C4F812F4077EF08D24 +:107B100062FDA9A044406FCA8532EE5765694F786F +:107B20008201E16396D715F485786ED55B62CBE36D +:107B300092DE3A606C17E1676E1CEDB19EEE029129 +:107B4000FA95B9C7170AA3E9787778B9BF9D4BFDB5 +:107B50006D7A7FBD97E9A5FB23E69721C4418CEEA2 +:107B600002D44F243215AEF93715E747FBB14B7DF0 +:107B7000FDEA6EF41F76F8539FD39CEE63FBF92663 +:107B8000FF111DF8AD9E50F907B9D019BF59FAC3BE +:107B90003A9FE0AE27B6F48992CDD65837BF221F60 +:107BA000F480CCEB93643DA4437D6579E634F4FB2B +:107BB0009EF432BD271DBCF20638A7A1FE2BCB0BCD +:107BC000EDF146319ED45340DA815FE56098D8F3F9 +:107BD000BF963E6869D0F0FAC4D4711520274F4C87 +:107BE0001D5EA153193834E9C75D90673AB787C95C +:107BF000EFB9C3B7E1F9C773268B37015B615CB29C +:107C0000F3113CAFFBB81C7910EB6AA13E8282B441 +:107C10002DDB59BF55CCF16272FDD4ACB0E79B1B94 +:107C200058FC58BD7039C6B554AEC73DD15BF1DCC8 +:107C30008687DA32385FA911D364DF3B6078D00AD7 +:107C40009DDFC3502F4CC2F74D2F8B1F59F522EEED +:107C5000BA100B9E191C9EBEE7329CF4B0F65F165C +:107C60001DACF7EB8470BEDE0FDFD45C9048C2160B +:107C7000FFE8ADEF56F1FE59A88BCF823A9E68FC23 +:107C8000EA22908304EE8FBCFE3A42F8F795904FBB +:107C900083728FBD0E3DC35517DF475E0C67DB5DFA +:107CA00017B11E9883D7F1613DAB4CBE29507A9F26 +:107CB000C9F8ED0CF06B6BA87AD02040249B3ACC2D +:107CC0007F96FBFBF28B7787471A363E170CC73E31 +:107CD000A1FAC0428C23D4ECF763BD7F35E8BFC95D +:107CE000706EC0ECF238CE0B843BA13E4F39C0C65B +:107CF0007B12E0A1F7FFA85715C0BA8FC3FE270F6C +:107D0000EC495462875E0E231E62DEF031A2337DA1 +:107D100026539E88655BFAAC3A061B865D2A71F88D +:107D20004BBB7CBCEDAB8EC54A7BEB3F8E6BFF0F34 +:107D3000F59B55DF715CFB0FF48776A9F14ED07788 +:107D4000E60B1E03EC177D1FCFEF9A2B4BD00EC412 +:107D50008AC808C0C32BD92AEAB9D8F39E7DA0E708 +:107D6000666BD13735DBBEE14CF61BA361FF956234 +:107D70003CD331DEA8A18D47E7EF00BC5ACF5FC9E5 +:107D8000DE85E716E97B06E60D0B0F8F5E43DBC34E +:107D90005FF0E0B9216BBFE9E6CB7C2E5F2DAEF33F +:107DA000802AC89B1FF46D2DCA9927E8CC8359728D +:107DB000A75E98E0C8073C097696D24F95A310A21B +:107DC000A4CF4BF1B9C9F9AC85D723A49F2727CD00 +:107DD0003C57A03CA79F67069777C2E558D693DF2C +:107DE00085E9E7DCA03B4FE2D653D6D5D253DFE29C +:107DF000FC2993E8153E3ACFBA44FB3C1FBE1D9DBB +:107E0000047EF0071A3B0755D2F6D0CB609EBFE93F +:107E100009DFEF9D8EE7BEFEC99B37747958E923D1 +:107E2000BC2EB38F1E62FED5ADCC5FAD9B3F15FD62 +:107E3000BBBAED6374FB3945F7B5EA4286430F0DD3 +:107E4000F31AFC7B7B26EAA3AA0B017CFED9CDE7C3 +:107E5000759C5FE93B9F1F9F5BF3DDE5D2B38726EF +:107E6000FD74179C73AFFBBE227A6CF3D47D9FD751 +:107E7000FF7BA9DE75CA7B18E45D2E22C9FA2ED0DD +:107E80000FDB54AB1D6E9E330BFC5A9B7E2803FF09 +:107E9000ABF77DF8CEDD361FEF6F56A6EE9FE1EA19 +:107EA0003FC61A7F21F677C393D43FB01FA3FDE5E9 +:107EB0003F7B2CF8507F3D24BAC6CBB1E6BF11C73B +:107EC000B3FCEE8BDADA574D19F8345E0EFBA79E41 +:107ED000DB8801DF9F785C0EF94276BED518BF566D +:107EE0005DB8D441EF5EBC8F73DC7FAF21E8A8D7CB +:107EF000BD235A8775DA1779FCA98A7AE6F8DE9EDF +:107F0000918E3ADDBFC1F149E1B83A0D1CD77CC171 +:107F1000701439E4B3178E62C7FD4F0AC7428DE96A +:107F2000AFE5FC3A5767E766E71A42A889DE9A4B45 +:107F3000EF7B29AF7F995E357A9D2B13D38FDF4579 +:107F40004DB0FEB40DFBFB1BFE7CEFBBD762A22A3B +:107F5000E8A82B90789DB75BEFC0396F56EFA63934 +:107F6000BE0F675D7D12ABD774DFFFD0C7F0F28D17 +:107F7000CBAB09F8D3D4574F796E6D975FE0DFFB39 +:107F80000C8A8E38376F5B75BE9F155C72069BEF4F +:107F90001B975F4F20AE2BE7A6FEBEDD413F83BFA0 +:107FA000450B639D784CEFFFBB349F149EE14978ED +:107FB000AE413C4969F0546BC1A3B3BC604BF0F3D4 +:107FC00081A724C3A25BFFF8D9CAE126172E413E40 +:107FD00092389D5A60FF96A2BF95FF68D13E5FF828 +:107FE000C383A4EF73195F0C7D170D92BEC55C0EA1 +:107FF0005AF4CF179E5B0709CF7516BF05C348AF6C +:10800000CF0B9EAF0C129E6316BD8CCF173FAD49B0 +:10801000FEEF1F9EBF70B8F333581CA4A5849D27A4 +:10802000F14991078B8481E5C257ECDC676B853E93 +:10803000679DCDBBCEBAAF74EBFC355F673A795A1A +:10804000A924F2807EC71A583CE00DBE3FF9755551 +:108050005326C6E75DF3B404F765F617B7F9EF5595 +:10806000CE73B903C9F1A40C96FFB931EA7C6FF95C +:108070008A0C571D9989FD2CFCA51BEFAF056F617C +:1080800048620E026F145F5945FDEC1B3E6B7CA5E8 +:1080900093BBA1E22BA60F0D5F03C9FB5786882F68 +:1080A0004B5EFF5AF1950FF89AFE37FE1A2CBE165A +:1080B000FD4D1E8784AF5B872A8FDCAFFD6BC5D774 +:1080C00060E5D1BD6FA3FBBB507FDF17F8ACF1E7D4 +:1080D0009EFFD3E2D11A6F659A7D5E3A7C0E0487CB +:1080E00075FDD03748BCBAF79F5F345E5DF37F6A99 +:1080F000BCF2F1868CD701E0B0AEF220E5DBF2EB0A +:10810000DAD4D4DF111D97C9BEE3365EA83D321F15 +:10811000F2C77F27617EFAC89E391BECF540E33237 +:1081200099BF7DA472F606889F9E8B6460EDD9513D +:1081300031F4F36990575EC4DE738F7F84E3CB9391 +:10814000996DC57FF380AE47238BFB954752695BE2 +:1081500017E68D6CF495FAE2FB0831B64F833CC408 +:1081600082D47058744E37EF50E97B34F2F890F4B3 +:10817000CF40EBFD0FFF9841EA9F04F6CB25C9BF26 +:10818000BB7319E0B34D64F570C7E156017CD78D20 +:1081900060A7E52BF2F7029DEECE64F9C30ED5D8A9 +:1081A00000F913CFE2050F6452BA1D5D9A2DD8CFA6 +:1081B0005FCEC964FBAF19AB52EFBB16723EE87DD0 +:1081C0005F20E353F07798F75BBA8A7D7F8CC8E134 +:1081D000518B6CE74ED7BB9EF7A1476600E1389AFA +:1081E000E6DCFF02FEFEF225FDBF4F6AD9F77D28CF +:1081F000DF8DB29F7B4DF219978F33FEE8D24C7A18 +:108200007D43887EE73EE0A3097E766E4826455092 +:108210007F658D932B934E95E2FD5DC5180579CD55 +:1082200014E3DC9C393DFD38E9F06AADC79A074498 +:1082300011BED333576371C46961426641FCD013E8 +:10824000BA9BE50F191FE4F03AC499B5198946D8CD +:10825000F7CA749D36783BFEEFECFF06CF3B8E8865 +:108260003A9E6F77E16120FDD094C9F2C9B952748A +:108270009317F226AB8594DFB1DB98C9FEDED1A45B +:10828000CC64BD14CE336E675481EF5F2C9359FEDE +:108290008B90E8A885B6F927717E73BF972BB17ACA +:1082A00023F22693E7B67DEB46A5929F5F70399D3A +:1082B0009459E2A8735C12B95B01F95CB260A162E7 +:1082C000F8E1B981E32FE570B4A9D15153FCBD7831 +:1082D0004AAB87387E3A8E459BE0BB1FABEB05ACC3 +:1082E0001328DDC8F86EF5C683E2067ADDCBE56FAC +:1082F00021D0C036DE77395DDBF6F94603FC6DC967 +:10830000FC0D1D98C271F36E82F99027B79F6E81A4 +:108310007C48B74078FEE4C64AA86BE8E6F56D2FC6 +:10832000D3E78D80BF397928DFE3367E5807FAB965 +:108330004325785EE6775B3C09384F60F14B524F3E +:108340006C3CDF00F5C38FA89D13816FF29A6AEF32 +:108350004B953F7D89D3E18FFE48562A3FD0BA5ACC +:10836000FADCEAB748369454FD1757BAEC1A877B03 +:1083700098A7F30C4991C74CF261A27F3FED975C3F +:108380008FFFC295E75D722C759CF1579C7FDB12C5 +:1083900015EBD16E991E3C8762C163E12BD76478DF +:1083A0005AB64472E8DBD50B325C7E0FC3EB0D1E70 +:1083B000E35158C723FB7E3A11CF51B9EC834F8A62 +:1083C000AAF0FC0ED2A9809E785F32F0FA4683F3C1 +:1083D000EFBCBC41A2DBA783FDAC9752CAD51F39C5 +:1083E000FFBCB1E296A5087F4CD201FE13AB865DBF +:1083F0005F06FA65851282EFA69F88DD9B799B6DEB +:10840000FD49BFC605D7AFAB6EE9D76E2D5FE1A4BE +:108410005B9BCAFC02F33A268777521E9D85FCD5EA +:10842000BD7D269DFF482267CA56D69DC0DF995A5A +:10843000CC7F7F5F8CEE9849F5CD2991E549CCAF93 +:1084400030BDB16467A41952A7A7EAAF78A99BF61B +:10845000F30618DFFDB6BE7FFBE8E6A7713B9DFE85 +:10846000DE8C634485F7A375A9EDC1B7F50CFEF763 +:10847000C442A341BFDCB43175BFFF05CC4CE13928 +:10848000F517A92A557CF22A9DC1BB3A92FAFDAB99 +:10849000F44CF61CEC520A3C9F0B64703DA78F060F +:1084A0003DBD3A0DBC1F060208EF3BCDF7DF04755A +:1084B00020EFBBBE03FF4E80F1C5C100E3EF53FBCD +:1084C000562A7940A71641077E783B3B3401F86D68 +:1084D0004DEC049E7739C0F1FCA62F3225301DE407 +:1084E00065D1DC3C4A978E55242418E9F5FF9501A7 +:1084F000E637E4F2782DB57FEF82FDA3AFBE8BFEA9 +:10850000871C1E7DE34456020575E0A744731DD603 +:1085100019EEF3B1BA52129A6EF7E3BFCCE138B557 +:108520007F68F45E1A71F9417DFCBF7835CEBB3FA0 +:108530004387BA94239552E7B514C893FB33F0FBF5 +:10854000B86EB94837FF50FDC053FB87E6070EB43D +:10855000EE0D81A241F981E72A1FD9310DE4488D42 +:108560004F4AA57F2D3D7D94C7DFDDFC635DBFCA0B +:10857000F9E8FD44FF70DDB1DB09CF4DB54E782C35 +:1085800079793FD1E45B0378229D13ED7E299933FD +:108590007D003BCBF253E9E0DCEED213C07940879B +:1085A0003BB9BEF96DFD23013B1DDCEB3F25F2FD20 +:1085B000C1A3AC2E776C644D459ED1CB9FDFFA9C56 +:1085C000F8D2B233EE71FEB3F3A165E706E2C3DC85 +:1085D00034799C4970D099BEBF46D655C8D74F0A4A +:1085E00018AC4DF47970548B94F1BA51628C86F3C7 +:1085F0005FA7F6F9F0EF43995B3D89B15404DEDFE4 +:1086000077F504FB7A7EC5F974F5926CFCFCC4FB2B +:1086100062687E3ED69D49F81DB7378EE5CC83F65D +:10862000238745D0D0E4A6BA3512ACEF8D00DB77B6 +:10863000AEDEF83AFA8343E5F3D5B54EFB7F155F1E +:1086400047D2CF927BA601FFA4C3C36B1C0F4B2361 +:108650000BE7827EBE65A380FAF627300E5DC82D3B +:108660007218F5368931FB48348A0F6A424EC022AF +:10867000001FFFC0BF5B254754FB39B9DBB6DD3FA8 +:1086800017FC43B7BCACC8627C5C91C5ECC29BBE16 +:10869000E81F40DF5BFAF96DA1F6603EEDB231A054 +:1086A0005BDF094639B5D6B391C345FDB467F1FB2D +:1086B000C57C7DA4C7C56F62BCFAC780FF0A0DFDEB +:1086C000029F87EA7DA88B7EDC877554965C59FEF5 +:1086D0008EFBFD6572D4E13766661539FC77B71FEE +:1086E000F2377B91BAFF15595FACBDB836EBB3B129 +:1086F00017C3389FB9ED4652AE5BD8799013C73E89 +:108700009A9B4AAE239F100EB73CBFBFCFC7BE9BFC +:108710007C4D26EA9DDEFD547E02F6CB6EB980FDCF +:10872000147CF7E3917D3F9B0875BD27B6DF7F532F +:108730002A7ACED299DF44BAF31DF1BCB50182F595 +:10874000DF84CEF7846D7CEBBDA4BC0C10BF5CB69F +:10875000F24ADC4FBEB1F2EAD16B4AFBEE2BFAF4DF +:1087600017A2FFB014E66DE4FBE91D9EAA7DA9F6F1 +:10877000811CAF7DE3C44EFF7EE9C6F266D8526F1E +:10878000CAB8E64BD114F327F7351B53C7E31EE4F1 +:108790007A2AB9AF31E9BE86E2A37B9514289BD62D +:1087A000BBAFE9363F9F7DCDEF48CFCF67A2FCA797 +:1087B00086EF7B167FA9D11D5752F84ED1FD8F0948 +:1087C000F223D2F7805FBE957ABFF6387FEF771B32 +:1087D00087A8AF8E39F733E9E4EF7B9F91FCB5A909 +:1087E0003DA3400FFC6EEFC76FDD0FEBD9EB437C71 +:1087F000BBC789E812DF5FF8906F2DFBDCA132FD6B +:10880000FFBBBF1B817F37DB2D1F84C4AFBF8A3EF8 +:108810003FBE4F9C02DF596CDB9751956A9FB35E58 +:1088200017787CC919EF21DCBF5BCAF94DDFF774FB +:10883000AD3D1EFD26D757561CE07F67313BBB641C +:10884000C14215E23DB725E34D04372BFA65857B20 +:10885000E1FB17BFE4E7B9CCB59929CFC7FD86E3A3 +:1088600077A038C48A55CE38C19205FDDB9B938929 +:10887000D47559163FA79B6FA8F6A52D31B4BCD867 +:1088800040EB1CA10FCEBE2C25B55F8278C73212FB +:1088900052E0BA84D44EFC3145E5C9DD8B119E5FB0 +:1088A0005A7FFFF8E37B27DAFD98FF0F11FE85A1C1 +:1088B00000800000000000001F8B08000000000086 +:1088C000000BDD7D0B7854459670DDBEFD4AD24924 +:1088D0003A9DEEBC091D020818620742001FD02114 +:1088E0004482B2DA810041519A87184948A2E2CA0B +:1088F000FEBA438720467466C2AA8CBFE3B80D82D5 +:10890000EB286AA2D1418CD8A0F8D8D59DA0AE8B17 +:10891000B3E846C7415E4322A32BB3CB0CFF39A774 +:10892000AAD2F7DE744370C7FDF6FBE338D7BAB7B7 +:108930009EE77D4E9DAAB63915C63C8C7D5B73FBC8 +:108940005F4D628CFDABB579BCD3C1D859FC9B1E81 +:108950007DFECB3AC6221731F6E13A3B8BD8A01CFC +:1089600036558563D4FB53AA8931E8E85FE1C14AF3 +:10897000190B2D50C33B94C1F5B2705CACB7785E57 +:108980006A30463FF2B9A04665113BA3BFB3F06F12 +:10899000CD9C245DF922A753F4D39A182C62EC885D +:1089A0001CF7513EEE91307F2FFBBB488C7B247C23 +:1089B000EE716F7E04C61D131DE78666FDB8BD2CE3 +:1089C000B48AB9619C70A2734701C3FF8CD8264456 +:1089D000DBEF759A08AEEC48A689653076876C1B8C +:1089E00067BC0F057C8DF56BCC7E8B161FB7A77A05 +:1089F00069FEB25C33473F4F6F8A938FCB9CF981FE +:108A000064C68E6E4BF4133CA6258747C13C2BED04 +:108A10002CE480793EF8E4C59FB1118C2D13F8AF9A +:108A2000097C6D41781C35F5DF938CEBFAC0E4DCF2 +:108A30000143951DF45BB4F0BB2B85C3EFE8F673DF +:108A4000C3EFAE143ECF7955FAF9CD3F98A82B1B52 +:108A5000D7FBEF7F7BEF04ECF7DFFFF63B8BB6FF36 +:108A600005A77359243D5A5E52ABF8C34583C77DB1 +:108A700029D53A24B8BF6480E392D3F9D4BF5B65AB +:108A8000CD1D31D655EEB453FDF981728B07E0B997 +:108A9000FC6EC5A74017339CBC9FE566E6EF80F9E6 +:108AA00030B337BF1AE0EE696DBE2310A39FFF23DA +:108AB000E0FD8D23901A8BCFE4F363410FB2DE0209 +:108AC00073D012ABFEC25A3D7C7B19AB8A35FF1FB7 +:108AD0003B395F0E951EE5F8C6FA439DC7DD820E51 +:108AE000D36D91DF33155E9C807ECA2E605C437D22 +:108AF000E3B8F73BF5F8338E7FF4CF6A5D2C38BCD2 +:108B000026F83F1800FA89F93D99BE7FC0DA1B7735 +:108B1000137F27F9762018B62FFF09A09DAD9C7D05 +:108B2000C75BF09A25A614D0FA16070E5412BB9D07 +:108B300079B018F1FE6DD5833F2985A91DB5065B77 +:108B400093A1C1D1F58A2FE41D3CCE07B84E90A366 +:108B50001FA13CBD08FB639C6E67C2FF65333646B0 +:108B6000F5D7A3506177D9BC3B347CEB5EFBDD3A93 +:108B700056CCD853D6C0FA64783FFAEEAFD73094CB +:108B8000792C4CF3FEC2E2BB85E0CD18F1FDA16D5E +:108B90008EAD9BA05E6A0A97938CF9F203E335725F +:108BA000C2ECA4F250F1F3611CFC5CA89C92EB8C2B +:108BB000370E409EE6377786A34D4965ACCBEABDBC +:108BC00009D7D33F3BC1B90D5038D7EABF1AE1F3FB +:108BD000C10193A9A580BA35239DCEE343B0826B32 +:108BE0000AEE1F578AF2C7E24F80A954431B36157D +:108BF000E868862384FD957E38E719C4CF83B536AF +:108C0000AF8AFD4DF37EAA4279EE5536EF7AE8AF92 +:108C1000AC67C45E37F43F7F8EE264D07EE6EC51F1 +:108C20009E5E585FD25AE8270747B8B7AAC2CCD889 +:108C3000D3F89F97323E6180C55C45965F6C9B0977 +:108C4000F2609CA7CBE40050AF4C7BB1CD0EFDDEB3 +:108C5000D312C872A6C1D236DFD7661FC658468661 +:108C6000BF67BA8FB1D99BEFAFB25F01EB7C54B451 +:108C70000F3DD0E6CF63EC5553B04081EFCD9B77ED +:108C80005499015EEE4239FE2B6DFECB613D57DDFE +:108C9000B2630DF4BF25ED9FAACC38EFC572FC9EE0 +:108CA000AA8A9130FFCB65F95FEC385F77926C0F41 +:108CB000F39DC298654474FEE62C18DF25CB9F54C3 +:108CC000CD84F13F2E6FAE30C3F8C7D2FEBDAD6884 +:108CD0002C6393E7943BFD50EEDBFC1F5549809FCE +:108CE0002E06740AE53F6C3E4DF377AB26DE7FE837 +:108CF0008F34BFB2C5A171F85D617F6AAB8275AF79 +:108D0000B6F7BE85E4DAB43664CF4091A4703AB1C8 +:108D10005B9AFDB9003BCBAEF2482E4DA79DD36BBD +:108D20005E643CEAB181F218288FD794B378B96BAE +:108D30003D5B124BDE76BAB81EEE4A8CFDBD228D2D +:108D4000CB03801BE993D483CCBF33865E1997E6AF +:108D5000A07EF627B290DD15E5B76B8187A7005F8F +:108D6000323B9FA7EC6790FE48E3729F85AE75216A +:108D7000DFCCC12E60E9853E258474CD9A93C2A3D1 +:108D8000907658C43C0FF5876AA2F97A5465493544 +:108D9000F49791C8829DF0F4A4332A437B7FA723E4 +:108DA000DADF7B82EE2B0B03DBB1BFCACCEC92D6B1 +:108DB00082683F30EF0DF609BA799BA7B8F0FBDC6B +:108DC000925B8B34F02CE2EB003AA07630CC33D3BC +:108DD000810FBA7AC68DD804F3FB06E5AE27BAAE8A +:108DE000B29EB91606F5B6B8843CF1F2F69E0A2E8C +:108DF0007FFA6F4D0A6F43FEB4FB4A104FB2DD0D90 +:108E000002EE15F7CEF919D66BE8B1301BD45BD35F +:108E1000599EC9CEA1171B4E5FC6C213356573C4D8 +:108E20008A72A7E1F4347A5F71EF7B56E453ECC7A2 +:108E30000BEB5A93E0CFF421DC5A63E39FB1169A0F +:108E400047C3E934169AA87DCFE114EDDF4DDFCF9B +:108E5000B7AE687F2A0BA79FAB3F2B7D1F80BB5906 +:108E6000C0DD1A7B9E1B04FD20BC4D1AFA9A2FE828 +:108E70000DA49F1FE5E1A16B8AB6A1BC8F8EBB9E9E +:108E8000FAEF32031ED10EEC49F4A25D5C66E6F205 +:108E9000B3ACC7E50C2951FA907421F1DAE56A2EDA +:108EA000A7F5562BCE6D0583E775BF9C97D0A79984 +:108EB0008B83EA52CDFC243F40FF5DA2FFD229C440 +:108EC0003FBFE0F4027C7303F22FDA2DB80E5F642B +:108ED000FCDCE4C1F33F0DE4854FC02387FF5F391D +:108EE000C2A80724DC06C33FF73CF8CCA7EF653DDA +:108EF000FBACB8CE86387CFB802B85DA651E8CA453 +:108F000078A1DE19617774754C4CB80CF9628E89C2 +:108F1000A108C375A3BD5A36206FAF7C7706C8DBA6 +:108F2000CC8132C85B2FE26140FE46ECF668FD1F43 +:108F3000B9AE9CBD01E4B5DB06F82F223BD4CE349C +:108F4000FEC4EE346EBF4D09B29876CBDFB9927590 +:108F500072ECFFAEAD60BF85F599D3B8DE9FD21B32 +:108F600052102F92AF8D72EA13C18F1F8BE7FFBC97 +:108F70009C52CE23A7AA859CE2EFF783998FF53206 +:108F80003222E315D089CBDE9D380AFD99DBB2543D +:108F9000EF97C057F314DFB067A1DF1ABBF79E64E9 +:108FA0006F944E6A98DDEB40B883D17416F5FE9C41 +:108FB000042AE31FDA25A7DA154E87CC9B5A333EE5 +:108FC000BE1C92F3B82DCB4AE32DBB6F546A503BC5 +:108FD0003FA127AEB5459E658583F95C9661FEABE2 +:108FE0004DAAE6BB83EBB3B1C9FE6FD2D00E555884 +:108FF0002DCDC7602F3904DF19EDA587B16F0FFDA7 +:109000002F62233E3691739AD9660B33DE24847E19 +:109010006A660713FC1A313568E8C0EECAA3792CDA +:109020005E081F2F01A6B4BF71C9971A3E7A07E7E1 +:10903000437A213209F934C1C57476DE623590A7CE +:10904000A0DD9A69F3A19C013C111CF62730730244 +:109050008CFB363C116F95EAAD7B2D6EA403C5D712 +:109060004AD0DF2AFC5616417D73EDF424B25BD959 +:1090700099DB4756033C3C499C6EA11FBBE8C74E99 +:109080007422E4DEAFF3C76E43FD24E5A7C4033BBF +:10909000A3527FF2FB7EA53ACF09E5FD9E8B4A5A8B +:1090A00015BDFD83F650D47E4ABF6F16F0E3E4AAE7 +:1090B0008E880958A825E4997D27D4AF4CE26B1E11 +:1090C000E9E27A707F41484DC1FE46C13AE0D55B86 +:1090D00089C1A26647141F60E304117F1956783ACC +:1090E000387FE0739F8BF3D99C748E942DE9BC9CE0 +:1090F00091C2EB1BE9ED49F17D95C2F1BBA99CCB77 +:109100000963BDE92EDEDF6A7BA82A6384D6BE0A26 +:1091100030A44333E37696DF25E8A482C3ABE2DED6 +:10912000C5A9A837BFED999FCA8AA272F41E25E887 +:10913000F441FD7B2C819F52BCE35F5486FE883551 +:109140002DE87441BDF4A4D8FEF24D621EE9E84F4B +:1091500043BD9F087FC772FA62F2B317BAB83C4B9F +:10916000C9AA21798E30F4A29FC2FA434E0DFE5255 +:10917000A798747E83E57431B5BF70BBA1248EDDE2 +:1091800050AAB31BE4B846FBE1D37559347FD9FE2E +:1091900086AC8F2A99A6FE8DACF71EECEFC635B9CA +:1091A000BA38513CBBE32E011FB4134231E765D5F9 +:1091B000BDFF14FCC49076FC237CFCE8B849C06871 +:1091C000D171FD2EFFDD2EE2A7CB9D872F864702B2 +:1091D000BC5749DF90DC07BDE4DFEA207D5485F20F +:1091E0005AFA47C8F7CE54A4F1F20DAE491AFD2839 +:1091F000DA19E5D09F453CE3CF4E6EFFA51E94F6ED +:1092000062A25751A2FA66B0BE127AC62017CF6783 +:109210005F03BD86B4FADFD8EF53AEEF6B5716C6C7 +:10922000A18FD1FF237665D9E541753CCACD2A854A +:109230008D82C7E4997A3DDFEDE2FE47B72B49A75F +:10924000E7E72ED6D78B60BD49F84C1A92BFA2D55E +:10925000438A8AF28EF7D728E8A1E0D807562FC8AC +:10926000DFFF1276D017E9FEB791AE3624A614A31D +:109270007ED8FAA78A315B61DEFDEF5B7CDBB0BB99 +:109280005D9C3ECA17AD6935C37B4B87E2B4318D17 +:10929000DE5ADB79C90A58EF0792FEDD7C1D0DEE20 +:1092A0008875248C9BD3C0C7CFEBD8AB9835F22DF3 +:1092B000AF8ED73BE4B2E8F45EAF287F26FD0F16F1 +:1092C0006EA92CC5FA7EF326107D391D0AC583735D +:1092D0009A01004007393EDEBFC31756961745D79F +:1092E000D966AA2E42BDD09691E443BD30D61D3C2E +:1092F0008CF4DF70281241304D3ED46346FBAEC281 +:10930000EDFF0ADFCB757A55670ECAD5A4437C7E84 +:10931000ED067A070B59D0F9362E6F55F60E437CC1 +:10932000A0EC80F132D68F21BD24EB67B8849EC8B3 +:1093300060C117C8AE626D8CF0C5681D19EB47930C +:109340007D2FF119B5A3C64E403BAAF0818879194B +:10935000B4DBFD58ECF8BC45E81158074BF744D78F +:10936000118F2FA41E93F52C71FC6849EF4955B15C +:10937000ED53D000F4BD7C91FB3A5C77C3062BB370 +:109380002951F857B803E9389F9C8EAD0AC246D2DE +:10939000D706D7D34A2EACEFF65B985365F1E7DBDF +:1093A000B0F6C54B5668FC2DE89FF0B1D5CAEAB4BB +:1093B000FA54FA1317A773FD73A73B3002C76DDC8D +:1093C000B5D98AF8BD65FBE7566DBC7BD03A8608F7 +:1093D0002FA58EFB290DB5F630AEB37C9199F057D1 +:1093E000BFC11A4679D4B0B33362427BFA6EE6430A +:1093F0007E6FE8E87C2B07E092DBE09FA47AA3FD78 +:10940000E53684159C4F0610610FF979112BEA6738 +:10941000235DA33D8C76C95B099CDF4F943B420AD8 +:10942000C0EF8425D880F54E6427F942055178BFF6 +:10943000DD39EB1D05583AF9055B049F6DA66D59A2 +:1094400076A8D736CEEA433AAA700767A5037C5CB4 +:10945000E64017B64F7327FB5AA0ADD7C626907EBD +:109460001E221C261BE861F2DD9C4FFE263D45DADC +:109470007B13500E2D4D4F96F612C9A7B72C7C1DAD +:109480001B189FEF3E977F01D1ABD345E3E63444F1 +:1094900014B4F78DE346E9C9BFF842E81BEC3C2B56 +:1094A000CAF57A2167CA176D577EABA1837A3064FB +:1094B000905E72766E55D00F84EF2D956EAACF6CAC +:1094C000286776F2FD887AF87E9346AEC875C49018 +:1094D0002FB7217C1D877ADEE4F22542F427E76B63 +:1094E000C4E78FD2B91D77259805F4DE1A1AE385F3 +:1094F000FEDE1A9148FD497E37F2E78F049DE7D4DE +:109500006E57306EE04EE276A39C9FACF745FA8C26 +:10951000F5389FC9553D0487D5B566C29B9C4FA5BC +:10952000353012FDAF76D1DFBE859F597BA1FCD0CF +:10953000AF0E103DAE6E57FCE417B41FB0CEC7F8A7 +:109540005CE8972AC663AFE62609DBF2D201D22394 +:109550005777F138C1EAAE4EF37247944E0B8EED59 +:10956000BB11E96C75878D2528883FBE5E239D82DF +:109570007C21BA67212BED67817C0C913C65C1028F +:10958000F447A4FCDD27EC4BE6E0EF9F10F396FDDB +:1095900046E56602D17BC1B109FBEC00CFD53EC5E3 +:1095A00007A612D8DBBC1EF41F21F9CBD808F4CBD8 +:1095B00064FF46F8FD5AC8D518787E3E3D861E9158 +:1095C0007AB5E0F1190C9F127F660177D9EF9E748E +:1095D000BE9FB527DD4CFD6F28E7F1EB0D16AE3FC2 +:1095E00036B4D8C3C8D76FA75DF98E520C707259C4 +:1095F00023F8DC6F5AD680DFF7E7F079B499D68F7D +:1096000069E6FAEBF574C25F0AE3F289CBA3875EE1 +:10961000E4F2A421E4203FB12158B382F61FDC0913 +:109620003EB4F759F04DEBFCE4283D18F1EB7D61B9 +:10963000AFD50BDFAFEEE07C10855B5847B720E776 +:1096400008EFFB5C723F2258807005FFBD05E30CFC +:10965000D27F4F591C08257B07F36BBAF0DF27092F +:10966000FFDD32C5FE17F5DFEBD7FE5336965765A3 +:10967000BD4B4FC92FE027EAF8EA84F0DB0E08BCA7 +:10968000FF41D04B7D6907F143FD97CDC4478E2A3A +:109690002E4F1C87F47290B11F8BF53F40FD54266E +:1096A000755CA9A23FFCF78AB395C59FF7CD4AF335 +:1096B0003F4F45BC74AAB42FC5CE80555F06704D90 +:1096C000103010F52C6E1EF73EF1142002F9D2DC9A +:1096D0006C3D97FD7BBE7E59E42305F15D2F607DD7 +:1096E0006267C5D4DF613CF1A954DF2858FAF19DC7 +:1096F000F3FEE677D0FEC4F6E93ED4D3EED600D131 +:109700004FBF27C1877143B70A962DD0434BC71B64 +:109710002997E1BED833974C40B999E7E67C79ECBC +:1097200045752DC267FD3F3C3F0DBFD7879574B48B +:109730001B4F3CF5F77F46BD58B7BD093D0DD6FA26 +:10974000CCEB64879BC25BF9FBA752C9BE3CFAC451 +:10975000E66908F7D68E56FA7EEC89AD54DEF70F2F +:10976000CFEFF94FB43702293EAC77ECC5CD3FFAC5 +:109770004FA4F39A141FAEA32168E6FBB692BE8DE8 +:1097800072AB732FF1A9A497AB51EF229C6AB9FC7D +:1097900091F4FC85D8575A56E1684379F6C5A6E49A +:1097A000BA58F144BF582FC65C488ED52A144F6B67 +:1097B00003AAC1B8465B229B82CFA4A2883517C6F4 +:1097C00059B8B8731AD93DA1CF5762FD79BB12D8E9 +:1097D000268ABF61F016EC7F2275C6C683183C0C42 +:1097E0007E32F4BEFD2CD8D71F5B309643FDE9ECEA +:1097F000FF796DEFFE11E5688DBD77AFC71B7DDF8B +:1098000026E234509FF44ED99AD8F1D02AB743D0EB +:109810002DD79B395DD5795E921336DF288D5D3A61 +:10982000EC60F32610432CA7AEE74A5CC75563965D +:109830004E24BAC0381FEA9F9083FA5F8D714AE0C8 +:10984000B3456ECE4F194EE6BE14C6AF3433B703E0 +:109850009F8C7D642139B283FA05FB83EC2AEFEB00 +:109860000B77A03DB2C512CC9E84FDB409BDB59D59 +:10987000CF1BDA3B71BF14FA735E3A81FAE9B1B8D3 +:10988000A87D88B79FB5BD4589CE1728351FF51629 +:10989000F657EA403D13AA25FC78ADB4AE635825CF +:1098A0009BD65D7CC3F828FF1AE33B28CF701FF8D6 +:1098B0004E77F96DEE49D1A78CFB18E1F9327E871E +:1098C000757FEBF6D3933D95AED32BF1EC957D0BE5 +:1098D0004F72FDFBEAE7246F1A918E71FCE0973A14 +:1098E000FDBB5CD2F12B9F131D2FDFC5F56FE3AEDF +:1098F000122BD2EDF1757EF65B30401BC53EEB16A8 +:10990000A57725C5795E497062FCEEA4D037F50FC6 +:109910007C7E18F74747ECCA26BFFEE42B09B5D872 +:10992000CF7E9389E0B97FDBC55B5B15ED3CB93F2A +:10993000007630916A23D8A9DC0E5EB119FDB3D54B +:1099400075CC87FCDF68A09FC65D07885EA41D5CA0 +:10995000F0F8DC15DCFE4CF025A0FF3693DBA30C01 +:10996000EC51AC9F3633DC6225FA2A2943FADAB788 +:1099700070CF46D4E38D339913FBDF32CCFF4A2EF0 +:10998000AD476198CFB2C5D23EC30CEDB7547A9DB6 +:10999000004980DB76B27BD918ABD0732BC85E6EE2 +:1099A000CCBADE477C669407AFB490DDD5E84DA411 +:1099B000F95CBD4BB98DDB230EC6E7AF107D5E1D94 +:1099C000BE2C8CFBCABF17F093703C69E9B911E15A +:1099D00071F2252044F87EF54C4EAF69333B488E3A +:1099E000BCFDCA2CD2E3922E935FB6913E77999D2F +:1099F0008A8FF4DA3C9B16AFED16AE97D2849E297F +:109A00007C80E33722F82922F440C46DD5C75B9CE3 +:109A1000A162D4BBBF17F8273182F25DC893D52B62 +:109A200022C44F0D3B797F6E9BBFE4760DFDBA2BB0 +:109A3000B85E94717FDC07A88E212F7EE7E6FAB12D +:109A4000E0F1659BD15EBE0AF08E2A25678C90A35B +:109A5000401708B79CBA00D1C155EE9B7D6A01ED55 +:109A60001F909FD8DF6265B1E23C47851CF5A407D3 +:109A70004A31DEECC94C263BC7A3969B12B05D89E8 +:109A8000E2DBE6A5FD4DB2F3FA3DD9BE6D3A7E0F9D +:109A9000949AA0DE918C648EE7F0AFCD73C7231F3C +:109AA0007AA59FAEB3FB06FBDBDC6E9CD31E2A4679 +:109AB0003F44EE5F4838845B126BB5F2B34FC02170 +:109AC0003C96C7F3C1BE7750FCDA09E3A05FBFED57 +:109AD000B227B85FDF4AE31F74F3784625AC0FED79 +:109AE000364F61600DD7A7C9BE58F0B853E079DF93 +:109AF000C21B4BD0AF6CAC71F890DF1E7A55594643 +:109B0000F48CC141F4B7832B080F0CF080FCC082A9 +:109B1000DC2F6D6C0E8463D37B35F15F23F29F42A3 +:109B2000F44EF176A0F730A777AEFFA4DF8FF2B145 +:109B30003AC67EA8942F8DD6DED148C7921F1AA7A9 +:109B4000F58E46B80D559E9CB400FF23FF001C9077 +:109B50007F24BF24EFE67CB2A9C55B8EDF37553288 +:109B600067AB461F19FD259C27FA9D52AE8F7507DE +:109B70000A3D1807304536621E8594C38DBBEF1B26 +:109B80001D2BCF4DCA61BB99CB377B3829DCAAA1ED +:109B90002FDCDB4B9E404FCADB495A1B3B2E52E663 +:109BA000718878FDD0F222325097A3BCD996144622 +:109BB0007925E344C67EC778145D3C46FA2DB8BFCC +:109BC00080F5E77A38BD547AB89CB85E3CE5FC2550 +:109BD000FD7B4DC1CF319F289EFE92EDFE52712B31 +:109BE000398ED4A346FCCBFD115C4F7551FC7AED48 +:109BF0007BB97C32D2E372C1275E5C2BD47B4EEC06 +:109C0000670DC62FEF87D59A75F96F6DA6CEBA5836 +:109C1000F12FB9BFC11E320F29BF6EEF3A9E47F533 +:109C20009CC8A7658BCDBA7C2A87CFDB82F1D3197C +:109C3000F6821295C6E571ACE469EC6BD4C3C5BB82 +:109C4000DAC7609E9227A0DF1FC9AC4DD4ED3F64F8 +:109C5000075DBA726E5D8EAEFEB0E611BAEFC3D785 +:109C60008ED37D2F084DD0950BDB2ED5D51FD53E3D +:109C7000439F8FFBC855BAFA63C37375E54D2D1D1D +:109C8000B588978B9FBA4ED76E86D9692E01B88E4C +:109C9000EF58A6CF1333C033F5CF6A4C3A7CD2537A +:109CA00040789D61D6E70B5FB24B0F0F4C8BC3FE24 +:109CB0008A99E86FDA9109E7CA632D66E66F7A65DB +:109CC000FB82C1F4C0ECBDBE400C3F53D2B92C1B8B +:109CD000F7B1A4FCB850FA8B374F497FF1BEC78368 +:109CE000DBBB1EB90FC3E16219804BADEF5C70B1F5 +:109CF0009C0F2E0CE092FCFDE162EC6F7D5223E59F +:109D0000037F84058D7DDC2BF84896178452B91E9D +:109D10000ACC3B8F1DCDE3C0411BDF9F347EB7676C +:109D200070B9361AE640F019225F7F26F070281EBF +:109D30005FAFFD7A7F26CAEF2A467EB3B3B9E56BE3 +:109D4000D45B4BCC1186F4FF9058CF169117FAC80C +:109D50003A27F5F3A8D87F7C6C9D97DE3FBE6E0C4A +:109D60003DC3EB7CF47EDBBA29F4DC0EF61C3E9F8F +:109D70005C5745CFA7D605A8DED3EB6AE9B9735D7A +:109D800090CF6B10BE5819D93981F498F1D2A52122 +:109D9000754878626A5E4C7D19B71F75F139F3C852 +:109DA000D71E5A34FB4D0DFF666524BB0F630EE3CF +:109DB000643619F733CFD7FEBB75B5B3DF1C3574E6 +:109DC0003E92F4C4CEA48F8EC5D741913FF9BB8794 +:109DD000CF6E0A15C5875794CE62C3A9C67E3207D7 +:109DE0009DF562B41934ED0F1AF8B826981AD36E9F +:109DF000A811F4596BE3FBEF8B0CFCFD92F8FE52BB +:109E000006D7779FC49133576798A43F6FA1FDC0D1 +:109E1000417CF7932B62C1777F8657C7C78B820639 +:109E2000BC1AFAF9C4D23ECC1783CFCED78F5C9F31 +:109E3000B1DDC3195C6EBDF8FF297F7E725332F924 +:109E40000F08378F66FD9FDC94541B2B2EF35A06A8 +:109E5000DF0705EB9C15B8C8D40F59D1561CC3BCFD +:109E60007C9F77A413E343320F203EBD9A298E4492 +:109E7000305407C315F0E1B51642FFE68171226642 +:109E80001CC7678AEA59CCA9619A731EEA607A8076 +:109E9000F6212BE5EFF4E6D0BEFF05D213531F1BCE +:109EA00075AE7DBA41ED2F50CEECF881E58CE473B0 +:109EB00076E6C151B1F4642D8E7D29AC63CBD4FB21 +:109EC00049CE9CA7DF0B855FADDA4BFBD64386DF1F +:109ED0002EF790E2526BED29C50CFCBAEF12F83365 +:109EE0003483F1F3589F2584D1CE3F20E6098EFFBD +:109EF00025DCAF6E9E8CCF7FCE0A7C9801ED975902 +:109F0000B99F383EC3FF119613C53EB035D3BA1181 +:109F10009FCCC9D7718958C74693371FD7F1A5E29F +:109F20001B8B7E8AD314F6E1338545C6F3BCBB7028 +:109F300010FDB3F48B13BDE8DF268E66AC87E2E13B +:109F4000BE048C9B5993FAFF7124F2FBEB268C30F4 +:109F5000B2E79D7CBECF3F924BFB2AE801A17C2853 +:109F6000C6F730F54D688743FB6B59F018CEEFA864 +:109F7000D31E32C1BC8A677FE1C27CA8E7BB67D031 +:109F80003E42E4293564C5730B3D27FEEE6AE8EFD7 +:109F9000921E0BC59B2F612AC9F37A337B00F926E9 +:109FA0001E3C8FFF75ECFCAE2B32B9DC93795BC69F +:109FB000EF79E2FBF13879C48E4CAE17647E8C45A4 +:109FC000E6C778FCE7CC8FB118F2632CE600C37DBE +:109FD00060CB407ECC6246F931D08F363FE6F88CBC +:109FE000D8F3708B79584E27C5E93785DE1F1F716E +:109FF000EE755A4E27E8F2ACA3ED1DF43E5E7ECE20 +:10A000007831FEF138F9496307FACF66A1746D3BE8 +:10A010002F9FF7C03879F4DD62C8F3897EE7F93DF8 +:10A020001BD2389DECCD72BA9742D74B59AF05E998 +:10A030007489C36DC1F85180F93AE9DC8ED9D2DF59 +:10A040002BF96E04D6337F8176B609242DDAD94BED +:10A05000D65ABEE8D5C8A96ABFBECCB0BE46EE6E21 +:10A06000CA6234DFC4716328AFEF14F3A63ACF217C +:10A070003717DB55BB59B3DE4371EC865B05FC0E2D +:10A0800065C786DF7599DCEE88771EE2D6CC14DDD5 +:10A0900039BDDB9DE7969708DF60BAB67F231EDCEB +:10A0A000F4FD7C70F6E0E61AC6D1CA159EBFFF1714 +:10A0B00087779A3857C5CF05580C79E89BB2B8FC1A +:10A0C0008BCE9BE7A17FE40CDC9E8972D1EC1DADA9 +:10A0D0003D07D065F6274D80E72121778C70D99D0B +:10A0E000C9ED37E3BABB443E7DA2CA9A3B35F0378F +:10A0F000AEF73941E7B2FE060BDFBF82BF801DF02D +:10A100007203E372EFE1CC11222F3CCD8CF270315F +:10A11000EF82DDE07C8BF693249C07C14FC0DD0805 +:10A12000C700F3DE8879DBE783674796FF6184CB5E +:10A13000D203895694FF37DAFBF7A38FDADB63FA91 +:10A1400078243C3F778C3CBC9DE1FEDB9897F7C1BF +:10A1500033658A8FE751B09964EF28A15CF5ECC5AF +:10A1600043B77736A604C7207F7C29F2AEA53EDA36 +:10A1700098736C34E6CF7B5DE5ABB23C1477F7A700 +:10A18000231DBD66E374F408F404E5A63D63B7A29D +:10A190009E79302B5887F5641E1FF3F78FC63C84D9 +:10A1A0000B8513FC59908ECE07A7273219E1E75093 +:10A1B0004A6C3AF94D1C3A31F2079D2F2BFDE1F81C +:10A1C00043C253EE5BC8F9D565713A944F093763C2 +:10A1D000FE505D9649D4E3F9880F660508CE7DC32D +:10A1E000BE3E9C00733F64C8F792CF93421E9D6FA2 +:10A1F000FD12DE3F941C3E94187B7EA6ACA1E1E7E5 +:10A20000879A5FBD9C5F71ECF965660D0D7E01D686 +:10A21000FF59DA0FA0C700CFF58867B6A19FE4E326 +:10A220002157EC79960D799E41CB0FA16F257DB317 +:10A23000D0D23ADAAFCF4A8CB95FBF00FC27F47FA7 +:10A240008CFBF6727F1EE407ADB7C6DE7F633AE291 +:10A250007DA65877068BA4E17EE61E1BC5FF8DEB1D +:10A26000BF42D011C0AB82E035A79FE2188746C736 +:10A27000960B15C6FA6D7C9C78E70BAECE528674B1 +:10A28000BE80950629FE576E774454C0C36D021FE9 +:10A29000D6DC553EB40FCBB3DE3B88EB04F89F18F9 +:10A2A00080A7269FEFD8BA779C232DF1E576BDFADB +:10A2B0004259738CF5043DC11BB3347E50FD53EFFE +:10A2C0003A476AF0359EF59AF8F9E87E93CE2FCE9C +:10A2D0006417E41757639F988FE00A903E40FD8013 +:10A2E0007A67E3EEA925884CB433309FA73F3991B4 +:10A2F000E4686BCEA563BC1A7886B2A47DA9C6B10A +:10A300001BFF7BF9FF51BB49D1D9AFD1FECDF45E24 +:10A31000E2A7DCF18F31F111F4F8EF213DE6F26FA5 +:10A32000C4A7117EA17B2F4FA3F30508BFE9D1FE7F +:10A3300006F01F07CF1D1E7F3BF6D720CED1283257 +:10A340008F6F205E61761EB647E13D54BC248A784B +:10A350001AD80D8F211D586D821F9983CE874BBB54 +:10A360008519EC1B3686FBB73764BDF7478CF76C55 +:10A370004CE12CBBF14709E4072E519C565C37D8C1 +:10A380001F9FFE1CEA0759E4D3BBC83F9476469250 +:10A390007A3669E8F394FEF2F9F2A9F7A13D06F3E3 +:10A3A000996172D0FEE63E585F36C88D1956FE2C74 +:10A3B0009F055405FDCD50F3BA7B615EDFB2338952 +:10A3C00057C0F3A78CC361CD81DFB9D01F9D61B6A3 +:10A3D0001CD3CA2D63BCE38DAC6437E151C43BBED2 +:10A3E00065737E7D31C2E57217C1A5F8959999DA3A +:10A3F00078CB40BC43AC635E682997A7063927E554 +:10A4000099C9CEEF11617EE6756650DC88C33DA424 +:10A41000303394AF90657452A07CB9409282ED6164 +:10A42000DD5788275B16CC423983693C381E787F1C +:10A4300059F86C9DEAF3E273BA1230F3798479DE4D +:10A44000216BCEC3FA267BAFCACFE7C10C32B0BDB9 +:10A450001C8F9793457943CDA91B6FF20E8E633005 +:10A460004732D9BD5631AFA34E47C804EF6D8EC8F1 +:10A4700051CA4F154F63BCE33B532884F9D977AADF +:10A48000619A6F128B447A303E61071098288EF0E3 +:10A4900007E403F06E1A719E09CE5391BB18E6399A +:10A4A000FA152CA71BF491C7B186F29E3D01B3416A +:10A4B0000F0515E49BCC5AE37BBD7EB2B343741EFB +:10A4C000488904B2CEA69F3F5E638CD35866701451 +:10A4D000F7DFC2EDDE8F13793B4917E9D95CFF3610 +:10A4E000BAAC8CF25D32EC76B4DB4F261FC12397F9 +:10A4F000A837DA506FD82D7E8287D41FABBB6E652C +:10A50000889FC65DD50CE5E86F14BEFF19BA41A15E +:10A510003C05796F436D117B1F5AB2A6EC1134CE06 +:10A52000FC7782373440B9E63D363E02F54AA6074D +:10A530002AF17E96D6F1CCB71ECAAD09C1675FC2BB +:10A54000F51C50A99F26712E963167FD4EE87FEBD2 +:10A5500075C37C9B704915FD1B310FA8FF3EE6C4F7 +:10A56000BC9141747A06D607F87F02CB30EFA6156E +:10A57000C15FDC01F5B3DF633EAA23BEA32F82785F +:10A5800053043DE0FBE9F0BE49D04D61B7C2F7EF9F +:10A59000DD36CA9F600733895FE6DBF9384DDDE5BC +:10A5A000D74E827915F64C24321E09F531BF093396 +:10A5B0000C787E1D237FD9587F24D6F752B48AE7C2 +:10A5C000D5E458E9FE2326E4DC6403BF5D16A57FCD +:10A5D000FA5E22CA4D421FE9F804FB01FFDC5FC6A8 +:10A5E000B7F3A99D9BF3838FC93FCEB797B2E81FFE +:10A5F000F65B111D87E4EF4CF16DFFA2D994D73DB6 +:10A60000D91CD98B7C7D9978968827F2B51DE0B846 +:10A61000D0DCBCDF03EB495BCB7C2D38CA626F2BEF +:10A62000F657CA022AC2B9CC795F2BCE6FEAE20391 +:10A63000E9485F4F6617123D5D6EF715260089B435 +:10A640004EF1F99CF0AA76B14270995F6B0F63FEF0 +:10A65000DAFC81FB7A82050B806F160615718E3E3F +:10A6600058B058138F95797D0B6CE047C7DA77CED9 +:10A67000E67A5CB66F12E74EE4F76DD90E9E5F99ED +:10A680007D655336E557F07C67E0FBDBB22745E597 +:10A69000088C4BF928F398DF82EB9A27F856F2FDE5 +:10A6A0007CFFED64B7CE0FE8EDCFDF281CDFA145BE +:10A6B0000AD9830B6BCF6D9FB664CBFDDE3C27C5FB +:10A6C000B799D4479CAEA4DC9E8B7A1CE56D15E847 +:10A6D0006D8D7DBCF8CE3369D42EF3C9D56787471D +:10A6E000CFB93419CEB9348A732E4DBB5A2C1948C0 +:10A6F000EFE29C4B53F7E71BB5F97D124E83CFB9C0 +:10A70000F4535EE3026B782F9EFF59B00AD608F52A +:10A71000DF10E722DEC4731113A274947C5D4284BF +:10A72000E7CDF9297F2FCF99E4C37C9336D304CAB0 +:10A73000176A4B49F669F37336B53457623D99276A +:10A7400024CFB52C88B31FFC9C906B5B149EAF1577 +:10A750005A6427787B5476507B4EDF5318A03CB95F +:10A76000A66C2F8DB345C41130AF74223CC3608EEC +:10A77000717CF1F646F900FD6DC0FE2A0A7D941F3A +:10A780005391CAF3CC3CE98192DB8AA2FDD674F3E3 +:10A79000BCBC9AC0D76FF1FCDAEA5284A7519E4B39 +:10A7A000FA32CA75A0BF7D488FDF99B8DE89CAF733 +:10A7B000C0A29BA0BFBEF7AD943FC7EEF62B1668B4 +:10A7C000F7E2BB4E1F9EA7DB501EA8AEA4EF663A71 +:10A7D000EF9751CB2236F85EFA9E751BE6EDD5B1A8 +:10A7E000762BF65767D05BAB1C6F5A913F576DB70E +:10A7F00044E99161BEA1AF10055DC3CE41710F92D6 +:10A800003F522E19E9988DD4CB9F12296F412E709B +:10A810007DB598EB39F6A482F19FBEE423AAF09FA0 +:10A8200049DE4D9242CA20E72775BF4DF6CA3490E3 +:10A830000FE89F29582EA6FA5406F93906F3472F38 +:10A840006389445F83EC0431AFD28179737B48CA5A +:10A85000C5F2298CE17D06122F300ED1B3DCAF9BFF +:10A8600084F7F0C0F33231EE9D267F5144413CB174 +:10A87000B0A910ED8820D93B46FBA7CCDE9C6487AD +:10A88000F54D61ED241727EF7F93E424E0F92CCAFE +:10A8900099D798C4B3CF8E72A61213FF547CEAF1F5 +:10A8A00034CBF19019E1342BCB888F9019E13ADB4E +:10A8B0003B084F744EC01F074F7E2947985E8E1489 +:10A8C000B033FC5CF27D6FDD817EEFF9EC900F3DE3 +:10A8D000C1AC1C929F7A7B245E5E5D418EE382F266 +:10A8E000EAFA2CDC4FB894F5AEDCA90CA68B93FBEE +:10A8F000D7AA591AFA9174B95BE4D92BAF8BBCDD96 +:10A90000D264D27351BDC8F15F264A97225D69F0C7 +:10A910007FC5AE84880AF45622DA5F8AF43021AA11 +:10A9200017232687D70AE36E547C6D6A0CBC67B880 +:10A93000BCA4FF269AFC2AD953CC978E7806BC4F2C +:10A9400043784DB177B49A619E87ADBE9FA3BF5245 +:10A95000CEBC84F772837EA970D498913F2BEC46CD +:10A96000FCFA09EF95CE41EF4DDF07EFC311EF522F +:10A970007F0CC1FE04BC2FCC89B15F180FEFC1EF73 +:10A98000897723BE25DF7726382B1C18D7ADE3F94E +:10A99000C413DF1FD98AE58CD50574CEA533CDF756 +:10A9A000067D6FE6DF4B7BFC2ADE9F58B806BE4370 +:10A9B000B9B3205081E5A6B50AC9CB491F055BB1E3 +:10A9C0003CF26EFEBD647DF31B780F595388B7DFF0 +:10A9D0007D7423DD2711DE28DA97B75760B9A98D7A +:10A9E000B7FF2AD91E42FFBAEC60B815DF8F7D8011 +:10A9F000CF43DA75D3059D752A2FBC41EDDA79BBBB +:10AA00009BDFB227927C1276DA34B1CEE98FF175F2 +:10AA1000BA7F7B559517E8F0A6FE9005E9E0B0A94E +:10AA2000A18CE4651C7FAB5C69CFC3E72C900B8CD9 +:10AA3000F00DF43982E79B6E83211ECBE17686CC44 +:10AA4000D3C47CF16A0DBE1ECBE17127592FC3C55B +:10AA5000785EF1A3C964B7CA3CD2C8CF98827100AE +:10AA60005C23E9D73879A5B30A9B495FCE1A2EF348 +:10AA7000497BCDCB60DC92B37FB832967FFD8418E2 +:10AA8000F788C87F97EFEBC20526F43F3A9178E844 +:10AA90001EB3DAF7D12EE94C63BA7B423A0B78B990 +:10AAA000F3D19A1FB7E5017C4DCDE6100AFD7C85F8 +:10AAB000EE3DB9A68745525306CF7F96994578DE7D +:10AAC000039FFFCA56EBB64D1A3B7DBE141B978FF2 +:10AAD000223D5223F024E5C57C812FE0EFDDC8DF65 +:10AAE0000BECCD64172E12F2FD1616A638C52D06F6 +:10AAF000FEAE777CF399C984F1303D1FAF86E970D3 +:10AB0000BDD0FFF82700FFBA47929DA8E75777E826 +:10AB1000EBD53DF2FE416E5FE9F9BC4EF27958CFBC +:10AB2000E76038703EFFD938DA7F91E7FA12ECFD22 +:10AB30009F855874BD03FADDC07F0978CE6F0CFA8B +:10AB40002D269E5F28CA72DC53ED5C0F87400F0BE9 +:10AB50003F8744EDA943B3C3480F25827F251F9744 +:10AB6000087D3E485F5719FD9887883F268A928462 +:10AB7000BBD4CFD00FE967796E10F4F2FB7EF2EF11 +:10AB8000C1FFC4798ED3F3CB2605E47341D45F01B2 +:10AB9000BC7D8D7803796CE7718A7686F22CAEDD08 +:10ABA000EF5813D3EE074947FB0083EDFD88CE8EA7 +:10ABB00037E22B9E5D3F80AF04B09792D08F67C481 +:10ABC0001FFF88CF21E475809C76E4C690D3D67DA4 +:10ABD000BC5EFFD6048A17C8F8B8E437258FDBD5EA +:10ABE000EF66F95DB9B8FF20FA3F74EB2CDAAFFEDF +:10ABF00086F969BF1AF38D7263E44BE07EF5064D6A +:10AC00009CF4505AECB8F5F05CCEEF4B72F9BAC632 +:10AC10007BFC5E1CEF8895C7C58F248A670ADF57C7 +:10AC2000B83897C7B9978867B9781E1179D8475C43 +:10AC3000FA78BAAC5721C6F9729DDDBE412357BCE4 +:10AC40003FB335A3BEF2148ABCF5359C5EFB5E496A +:10AC5000DBAABDAFED9ADCF22508474FA1DF9A8D44 +:10AC6000719657B85E6834F75A31BFE41A77702A84 +:10AC70007E6FF432FF0BD88FB7D73A0FE0DC27F6A0 +:10AC8000E9FB2CDCDFE84BE04F39AF6B72AB97E0B0 +:10AC90007AFB6EED25F93050AEEE25FEBF2637402B +:10ACA000E3F6CD97DF45F9C7BCCC847F582EF882F8 +:10ACB000E2BC31E2BA83E3B8FAFB679AACB1F7972A +:10ACC000595EB22E3E7B43378F1BDE68671B73E1F4 +:10ACD000FB92EE4CF21FEA5242A39D14C7FBEFC554 +:10ACE0005DFB86F5D0BA3695F7E73F5A4AFBB814B4 +:10ACF000F759DDFD36C9B9D5924FBAF47C522FF021 +:10AD00007BBEFD0F635C7C08FCB32616FFBC8CFA8F +:10AD1000C91285FF6D220FA9526DA8C0B8D0A91520 +:10AD20008CCEBFDEF6AE4AF474DBB30ADD0721ED4C +:10AD3000B3D502BEF1D683E707BC1AF981E707BC99 +:10AD40001AFF0CCF0F68CB787E405B1FCF0F68BF18 +:10AD5000E3F901ED773C3FA02D97B0E5AD18676BA7 +:10AD60006A63CEB0979F27D0B6C7F304DA329E2726 +:10AD7000D0B6C7F304DAF229C6E178EA3195E2F4F5 +:10AD800078AE40DBFEE677276621DD7425F03C32A5 +:10AD900016F2F714015C5608B8E079036D7FC753CB +:10ADA000AE7C8701DDADE85939079F97EC5AA5EBDA +:10ADB000AF5E6D203A64ED5CEE36C33F243FD52292 +:10ADC00015E7F1ED2E85A517E0FDE106FDD9BD796A +:10ADD000238A9E5BC2FAF7F54C13AF2D181C977FA0 +:10ADE0003957E421E6B01C6D9C264A070E5F04D754 +:10ADF000FF91EA8B450725ECA2548ACFBCA362ECF5 +:10AE0000817DC59AB75CAE68E2F70678D8B2F4F4F3 +:10AE100090E0D5D343D2183D3D24FBF4F4903A455D +:10AE20004F0F69FE71E7846F7A959E3E8CF09D020C +:10AE3000FF207C27E0CD9018578275629CF72F0584 +:10AE4000DF2F72C5BE8780EFB7ECF20A87973ED737 +:10AE5000D8CBA2F649E93BCDB4496B8C7B4A384A42 +:10AE60003B41C62F2731EEA7DBF1BC6521DA01DCBF +:10AE70007F43FD8F7C7ED8CAFD36A420949337B1E2 +:10AE800020C9A39B0CFAFF66C74356D4FF83D60B99 +:10AE90001617DE1B685C2FDA514C134F32EA7FA580 +:10AEA0005B892417E372BBA55C0E9E2563C7AF0CBC +:10AEB000455EFCDEE1B7E579681C662FD3C57B6390 +:10AEC000DA73721E122E727C1B6B56B3909EC718DB +:10AED000ED2FBDBF2CFD6BEA54138F96FEB1F44FDE +:10AEE0008C7056871790DD35D129FDE29EEBF1BDC0 +:10AEF000F4878D7EE8F9F6A5E68594DE9F1744ED8C +:10AF0000C92BC4739E8817C1B27EFB6FD0F872C57F +:10AF10003B0CC79BBBFB220FD2CB46A59919E6770A +:10AF2000F055E84735F5A7F3F84B50B75FF5B6D2C3 +:10AF30004BF35EC0FCF7E0B351C4D31ABBDEA67D71 +:10AF4000D4C62E1E2F60BBF47831DAFBAB5887B520 +:10AF500040196CEF37B01EEACF68DF0FA293F3E819 +:10AF6000F18E3C79DF16CF1760422ED50978C5F3F4 +:10AF70000BCC08E0A9D1FB3B811FE6E54D8AE6D169 +:10AF800066B8C08F51310FC36B8D9527C5F0721510 +:10AF9000B049973B6A484E2C6F1B1497B0123FB5CF +:10AFA0009F7B7DD20EB81F7C377C96E67979DC20BA +:10AFB00071CE3B7EFC5CDA93AF3DFFD164E5E70EDA +:10AFC00059B3FE7CFEDA3C933C3FA50E65FD83E160 +:10AFD000FAFDF2F265FE01C0EF2E2DFCE43E825C2C +:10AFE000CFEF27F53C89F1433579A61DFD5AAF2BEC +:10AFF000D882F5871DEC3DACA03C7378293FE4E492 +:10B00000AEA31FA3FF2ED7C758EF16BCDFB66E97AF +:10B010004AFE60DDAE37C82E8AEFEFB50FDCA32005 +:10B02000F6377E126B5E32AFB9522D4AEDD5D8E9B4 +:10B030004B851F307978E0216C57FA615E0ACED7D4 +:10B0400032A283EEC5EABF83DBC16E95CD44F881A1 +:10B05000DEE37ADF61A67D077752484D413B6E29DA +:10B06000E3F7D0F99A7D482AEAB0228AD366DCA1B8 +:10B0700006D0FEFE74CDF2343CAF9C91BC22AD10E4 +:10B080009ED36DFC5E9A0CC514E0E74E97A5E13D9A +:10B090002037D8F8BE7CC15F27450A81DF5EB7F252 +:10B0A000FB46DD4941BABFA03F4DA5F91C5B074BEC +:10B0B0001B85FB1EDF4CC47B0772CE3826E07CB2BA +:10B0C000C5BD163FCAE3F7DC1C7FF6BB89E8AFAA13 +:10B0D000671D74BE5DD29FBB30B6BFB242C0A3D164 +:10B0E000C3F3DE4F0AFBF190D86F9579F06BC43E45 +:10B0F000E0A1D103F78379302FA431C19FBA10E3C7 +:10B10000110754CA6BFFC6E94F4D23BB99E7B3AF94 +:10B1100011F6C34991F7B966F68C4CF42FE2E54B72 +:10B120001FC8E376EF0F755FA5CC3F8D0B873433D7 +:10B13000335F42F72E05CE55EFD53FAB31E1795A5B +:10B140007C8F9737DF97A7E8F2E21B312F1E5EADA9 +:10B1500079A53C939D235FBA11EF23D7E4D7A09F35 +:10B1600086EB6BC4FBC8E99ED213744F07F683F7D6 +:10B17000869DEFDEC815621E8D984F9EAE7DCFF97D +:10B1800039DABF9BBE3F2DE0F6F43BA6AA6D31E64F +:10B1900099378CCBA7711E7300F7252F8EF07B3F5C +:10B1A000E3D593E7B8E3CDAB6B46EF8D386FCCCFEB +:10B1B0008C355ECA304E2772BE5DAEDE9501BE9FF5 +:10B1C00037BA3A595376F6E7CFD5C8D7D9023F5D9B +:10B1D00057F5E6D37D00B3B9FF1A0FCF65E66605D4 +:10B1E000E190E00A06D11E91F715E37DC63CCF231E +:10B1F000744E7C47E1ACEACE1F0C86B395BECBFE05 +:10B20000A4DC39FA884A72E7E807821F99DFA19423 +:10B21000A1BEE27C7594F1B8EED176FEFB1FCB8225 +:10B22000A02B407E2CDD5E3F070F1FAFDC3171236A +:10B230008A7F7C7F37C89FA5598C4D83E7B20DFA72 +:10B24000FDB16FD903A4E7563C60D467012BCAD97E +:10B25000950FE9EBD7B107BE46FBA0CE60F76608B5 +:10B26000BD6BB47F670C13F66F192BBB90734E8FB9 +:10B2700030FFEC61A4FFF97EDB24B19F6EACFFBC14 +:10B2800097D3C36D3BFE60C59F048AD7EF319017FB +:10B2900023A1DF13EB9CF45C32CC5F330CDA350D69 +:10B2A0000B2EC471FA0E70389F6A38B592E2D2B58F +:10B2B000DC0EB0E1252BF09FB6EBEDE447DF8BF71A +:10B2C0008C019C6D366E5F48BB4A556F57F1275B0A +:10B2D000A6FE6E451AAECFFDCCAC2AF43F3CCF247F +:10B2E000F9111F9BCAFD2528BF37553B689F78ABD6 +:10B2F00089DF4368B7F1FDB9F0D353F7613878645B +:10B30000C7E619E86738BBF746302ED166E2FBAFD7 +:10B310006DD398B8C79A8FD7D45DDD89F3CAAF01D2 +:10B32000790FFD6D2AF0973835FD33612F350A5CB2 +:10B33000F4BD76D14FF1DEAB9FBF43E62AAC730478 +:10B34000C5BFC6314E3732BF847E1B43132F3A012F +:10B35000FA8769CE3F8FEB50229614BA5F8FE2D8FE +:10B360000DEB2319D7A3FEFC25DFAF95F373BF9E2A +:10B370003D03E3FD529F5E8FF96D18071676EF22AD +:10B3800026FFF87E41ADA0EB45C2DEBD3E89C37904 +:10B3900019F3D1F9ABEBEC2C05E3CBD757744CA2E6 +:10B3A000FBAFEB2D6968AFC8B8773CBCC78BCF3417 +:10B3B0003E99CCEFCB51FA476327C73006521ACDDE +:10B3C000B737F6B36398E0E7D1C24E1BC9FCB8CFDC +:10B3D000D2B8E722CAC7B725F27D35906F76C4EBA5 +:10B3E0007ED4E7B0EE5B5E4D88F07DE3B0B81787A2 +:10B3F00085683F664F26ED2BB80BFDB4EF7ED2D2A9 +:10B400009B4FF200E49702BA73CFB04FAE31E3FD29 +:10B410002039604741F9F82F0E5F83BFCFD238A2A1 +:10B420007725DE179EFEF8595E1ED77B18CBC31E0C +:10B430004FBC96CA137A57AA509EF278D6B5D41E3E +:10B440001D2820ACCAC7875F8BE7FC8E89F825F3DF +:10B45000F5D23D418DBB2F3269E38325F95C4E1F48 +:10B460004BE0F58E15B0257311DE637A476B7F379D +:10B47000C1932FED526E97C975CA762C2B76FFEFCC +:10B480000B3D708BB8DF677A126B4BE0FB1521B474 +:10B49000AFDEECBE88E0F2C2309780572FDDDB28AC +:10B4A000FB319EEF97E3AE42BD8D72DDA23F4FF4BC +:10B4B0001BA12F609C0D344E91BF04EFE5699C9B4E +:10B4C000578278037C9905BECCDC0FDC4A78C67EB7 +:10B4D000D38A498F4CC43CB137CF40FD82E8BC8D44 +:10B4E000F471588C734B2BDF67EA4F2B243A9A9EEA +:10B4F000C4ED3F560AF003393645C0AD245F9CE3E6 +:10B5000019C043A642FDB70AF8E5F1FA17BADED32F +:10B510003FD07A3578F263DEF19BBBC6129EA60C53 +:10B52000D0C1665D3FC75A0CEDA6F0BC94465721CA +:10B53000B5BB57DCB32FEF2DC67605D06E7A45FF2D +:10B5400044E407796F1B0B4D2367BD41488B817B1A +:10B55000D83A787E0A1BE9E7F711CD9D532AD6E742 +:10B5600014EB736AEFA51BE0C38FFAF36B34F75249 +:10B57000CBF703701FE8AF6882E84FC7CFB1FA433B +:10B58000BE88878F71F97F617CC8791AE0390067BE +:10B59000C3FC243C918FA95D919E9FE43C87E59B71 +:10B5A00084BF6DE0E782EF399EC8EF5FFD37221F51 +:10B5B000D2ABA7E7D55D0526DC3F95EDDA3A5A0216 +:10B5C00028E765BCDBD6551D42FDD7D45D4E799B7F +:10B5D000AB7FF5ECCB2168BFEAF987533099F6A829 +:10B5E000B93D03EDDC861DF7A4F871BFC41C4A41C8 +:10B5F000F97934AC56C53A0F181278907654A3D026 +:10B6000037C79EBEFF1A84C77FECB038518F363DD6 +:10B61000658BD8280E720BD95150FE9C97EFFD1AFE +:10B62000FDD2A65D7A3B69D53F3C9CE1257A0AE5CF +:10B630009AF08C0B8BE43278366EB7F8226E1E4F80 +:10B6400084615813EBDF88F333B6C7799C06BC37A7 +:10B6500075A84BF13CAFF13B4812B2C39ABAEE2742 +:10B66000BBAB491B67003CD4C5B1BB6ECDD7E75B14 +:10B670004BB8B0B087EC9AD65FFEACF87307DEA784 +:10B68000F94F294A91565FAE27389DEA58FEF7BB1D +:10B69000BDF1F5EA49B40B6CDA761CAFDE5D0AED5C +:10B6A00049B06EFE6CB04452D0CF6FD86AF181E6DB +:10B6B000650DCF3EF124EE87B04F6C74FF41FDB3B2 +:10B6C000FB3FBE14CAF59D16F71C3E7D879211C53F +:10B6D0004F9397DB27121FAB5EDC4FF70CE27BB476 +:10B6E0006B255EEA3BF75AD9F8C1F0ABE8D82B7E60 +:10B6F00077C1809F8ECFAFA4FB3C7FF99D15E9FAFF +:10B70000E81E8565160C6E5FB7757F0AD21FC209E9 +:10B71000FD4B89A701BC0DC257E49ADDA5548FE209 +:10B720001AF1F036379FF178D0AF9E7D0E7F07B0CB +:10B73000EE37361FAEBFEEB9DB53701D5F999B39F4 +:10B740007DFFE29E0C3F8C5B67096538E9C9DFD756 +:10B750003D7E07D1DDCD07EEC8E0BFA7E1CF364D76 +:10B76000A17566E3FA6E7A6C3EAD6F250B12DDD5DE +:10B77000FD82C727BE15BFC760C4E769C11F5F6DE3 +:10B78000B3E18F64B0AF30111DF3083F50459EEF19 +:10B79000AD4C7B8F0558DC54FE56C407DE1FD0032A +:10B7A000CCCE3471D9A6EDF7F6207E8E0DF367E28C +:10B7B000BE1AC02124E0A5E0FDBAEA81CA4C8E1F62 +:10B7C000E635CBB832D8DF15F81EEBF758FC09C5C3 +:10B7D000BA7662BF9E8F2FE31330EF44DCF7FB2A6B +:10B7E00023F6B9ADD1C31521DF580FD3D2573C7E14 +:10B7F000DF7E1FD1D5371F71BE690C5757D1F71E99 +:10B800004B048F163786F7D628240F6CBAFB9F0699 +:10B81000E862BB45F0B3FE3BCCD3AC68E1BB87E745 +:10B82000D5AE7CC8A6BB0F214A37D6E8FB82287F5D +:10B830004A3FEA66C1FFC6F51AE5C11F0CF2803D1A +:10B84000E619D2BD320D96F0938F22FF02BFA29F60 +:10B85000D9F0AC85FCFCE33BDFF8F83AA0F3E31D3C +:10B86000926FF572D5C8B7752F4C62B1F8F6B8C3B0 +:10B87000C762F22DBC8FC9B78EE83E8D97FD7072FE +:10B88000F5E63872356FB8F11C4B512AE6BA1F7BCA +:10B89000BA7E38C5050C7095FEAC515EBE9CEF8D2E +:10B8A000292F195E41A581A3849FA4C755CFACA6BB +:10B8B0007106E856D2A5A4DB01BA1C945FA983A344 +:10B8C000F1FB17288F2645F16E590F7E0ADAB1AFCA +:10B8D000A9F43B287D30978D00F7BE9D05B40F7A03 +:10B8E0008FB0F3FB9CFD2918D7BB47F815FD184F07 +:10B8F0004C8DBEEF4F10790381FE94348D5DF47949 +:10B90000B79A82765C6F38F6EFC9CA7B2A7BE3FC74 +:10B91000DEAC3CBF54A93AF2D7629CB69DEF4FAE65 +:10B9200068599882F18CBEEE42FA3DA19BDE057FFC +:10B9300017E6DB27E39A21BF39BB2C7ABFE9111642 +:10B94000A2FDCAE5DDF5B45F688C83AC74D4A4E2D3 +:10B950007EA0310E7233E641611EF263FAF7AB301E +:10B960003E827832D05310E9297B303DAD1C2EF653 +:10B970005F4B58896EFF55C8B54AB5E8A7689FF474 +:10B9800081DF8EF120A616FD1AF5E9B7E8C723037B +:10B99000843C44A7F5C12332CF8AE85AD29DD17F97 +:10B9A000373E4FBCF469199E076A78F9DF8A7F0E2B +:10B9B000CF132F7F32FA552CFFEA5FF3FF8D0DAEC8 +:10B9C0005FB1E78FE4AFF4EDB1D17CFAF6BC9D7FB7 +:10B9D000179677DB7C38DFBEF536FE7BD07B92E9AD +:10B9E000DEE9BE613CCED6FADA77C5BDA4A7361033 +:10B9F000DEFE6E38BF2FF654F77F7D86F7AB9EEAEA +:10BA0000B67931EED0B42789FCF0A6DD09744F7CFD +:10BA1000DF6BDF9569E345FFDDF5348AF3167DC9F9 +:10BA2000AC16F35BFAD2B8BFD6F4EAD4275A0AD0E0 +:10BA30002EDD4BF71657BCFEA762943F7D2F70BBDF +:10BA400002FCF3C77113F117C3BB7F6A998AE78DB4 +:10BA500018F9D553BD7FBA36E48805170E873E80A6 +:10BA600003AE0BE042F775C78347D7707E0FFFFF29 +:10BA70003E787C4DFE4243F764E2A3285C14FEFB53 +:10BA800023DDC961BB42EBE7EFF77C578C76D2F13F +:10BA90008E16D2FBE75BF787FF6BE9E0FBAE5B89B5 +:10BAA0000C65DDA7FED7AE9BD3FFDAE15C3F19F949 +:10BAB00060309DFFEAAFA9FC5CB28FE66BE0FFFF50 +:10BAC00007ABA359F3008000000000001F8B0800A3 +:10BAD00000000000000BCD3C0B7814D5B9FFECCC76 +:10BAE0003E926CC22604084260F2244A1E0B791072 +:10BAF0001EA99B842008E206A4A2222EF8E015923B +:10BB000008B6C66ACD622202F5B6516CAF6DD16F30 +:10BB10004141DADA6B8A41B1025D10115AAAAB8257 +:10BB2000A246BA52AB50031B41052ABDDEFFFFCF30 +:10BB30004CB233243CFCAEDFD7E423C733E7CC3927 +:10BB4000FFFB75CE18498599ADB9004DDB4EE587F1 +:10BB5000B1056806280648526D00FD004E6CFDFADE +:10BB600090944CAD5D853480BAED710045D8FE31BE +:10BB70002600124064DBA9129F13E01BFAB912A041 +:10BB8000A3119718D6DD37B71D9B3F2CB917A7D443 +:10BB9000BCF041FEAFB1ED78E1BDEC97A9FFE2BB8F +:10BBA000433EC0B6D606BE565C2F120F3337213C3B +:10BBB0009144F000EE5FF7F2E8A796E1FE8BDB3EE2 +:10BBC0009F4DFBD76C1D0532F62BFFF4EFFC30CDFB +:10BBD000DF2479C4F3F88003E1AADC7E463CDF7EF3 +:10BBE0002A1FB0FD6C93149413B0FF807D7E80D625 +:10BBF000ED05EF118477F17F22DE3B6CB7E278C36D +:10BC00005095E1EBC67B870DF208DFBDB3697E641A +:10BC10007BBCCB9E46F0FD7B0844E17F21BCBDFF91 +:10BC2000B1FC3E3FDE007E86DB2A7B1DE908DFC3D8 +:10BC3000100CA9D83E0830B1D5792E3C3FA6C16280 +:10BC40007A0F42D01F4006F123272F9C0209D4AE61 +:10BC5000FA5CCEA7F7A74D4C4338FCAAC5BD5EA53C +:10BC60001916A6C38AC1EEC02A840B14EFFCB5D8FE +:10BC7000B70EAD71AFE215EE042801F881435BAF5A +:10BC8000FF948912AED7B40CE1C2759AFA595C4D93 +:10BC9000B88EA25A82F67C6E3FA2F6A1FE57EFA1A3 +:10BCA0007D15A70D82DABBDFE03F27603F47EBE35E +:10BCB0007EB199517DFC17033B5D0AEE1FE35620D0 +:10BCC0008028D921EA7D9C7F93EA62BAC442C0EF02 +:10BCD000725E3A9D7E4F83FD7AA793993E3ADDCE00 +:10BCE000A1138083DE57E8BF08FFE45521D2430546 +:10BCF000147F58E0237D23113DDD290E5CCFDAE768 +:10BD00000EF72A899FAB4A89F69E85FE2C31D01703 +:10BD1000E9E789C9EFA673D47A8CBF99CE974A5FB9 +:10BD20009D2F31308DF91C33D8E90E20FC0FAA82EB +:10BD3000EE0F22DD25A99BBE3ADDCC7CF093EC14FE +:10BD400077D3BFBB1DE7FA64383312BE41E2FA2B4A +:10BD500020A71ED7A992C785FDB8FE89D238B79D06 +:10BD6000F44582A03412DBF2FE15807874A4DA1454 +:10BD70006ACB3A11A72878AF3CED00250ABF72487C +:10BD800034F43B52B3F9FD4AC740C37B1D034B1D3E +:10BD9000F4BCCA956698FF464C423E14D07B1326ED +:10BDA000D2F85529971BDE9B7AB863CD1C6CAF95F2 +:10BDB000C245241C1D7B675510BD26A9230CF3B674 +:10BDC000A059217DEEAC9203EB901ED552B07F3E80 +:10BDD000D26D72CE68237C128C273C6B2C285A388B +:10BDE000EF1A77B961FCDAD2498675AB3DD5867E0C +:10BDF0004DC357A0F40518DB70169442B4E3C15646 +:10BE0000C3FB857BB618E627EC03391EDB11FBD597 +:10BE1000266A0BDB434924BEB6BE0EBFA50F8A704F +:10BE2000D85B89E840C991FA57A86D70203DF0F9B8 +:10BE3000A918D122BF58CEFD8762024D08EF294BC9 +:10BE4000C04774B85B0EE4501B3BE88E7C48073853 +:10BE50009AF2B0DC87E0075FA78A7230FA8B401352 +:10BE6000F5AF3CDB2AFBC80E6F94FDB602E2FB94F3 +:10BE7000B8BF92DD6D9580F85EE3B47802E4B792C6 +:10BE80005AF39746C9D7673F845BBCB9E7EAEB8BA7 +:10BE900059E596345CBF39C5D3B283EC66C587B328 +:10BEA000E5F473E7814BE90CEB7449A7F7BC4583D4 +:10BEB000511EE5F8F10EB2EBB19532E30557590387 +:10BEC000EB719DE516778CA6FCEC5F5D13AC6B49BE +:10BED000AFD7A409FB10FB175025843FB6AF4FCE58 +:10BEE000A3F77E26C17AE8DEEFD652603CB2D22CB0 +:10BEF000420F1457BF9BF3E8FD787EBFA454D011C6 +:10BF0000A6580259B864C241F76E2BF657E7EC7792 +:10BF10009119689B72D82F235DDA0E86CA24D4A5A6 +:10BF2000010F979FCC14F3210BFB6D39E3E3F2D89B +:10BF30008FE558C8CE2C41B347766647D93339E4EC +:10BF400027965C7EC500E8C1BEE96DC26909D4C20E +:10BF5000EEFE9A3495E14A50C2407A9D705AE171E2 +:10BF600068C8B690FDD1D74F98A5BEBB94E0D86302 +:10BF7000852CDA5EF12C223C565DD1AEAE623C04DB +:10BF8000DE00E1142FA2FA4FF4932A315609A7DC00 +:10BF90001C7F2E1CFFDC589CA8221E7DCBDD896EE9 +:10BFA0006A7F8F441FC374F7131D7E4A7F2EA3DE62 +:10BFB000DAD0781CDF4836518C0701E57A954D1BA5 +:10BFC000279382FDBE9236EE5FEB1D4F7C958DF37D +:10BFD0000BD2BBE67B1C29DDEB7BD7AE0D35F748DA +:10BFE0004F3BFBE55513AC01BB7431748DBB005D59 +:10BFF00013045DCFA2F5C77DEE72887D3E96D421F5 +:10C00000246FAB2D68053200F6BB7CD7935CC7CAA2 +:10C01000C13C7A3E37C133A00CE5AFCDE619720FB3 +:10C02000D9956D31EE75F85EF59D9F3DDE407A3D08 +:10C03000F59F39CD24378A276E24EE53E7FA8AED2F +:10C0400041959CDB87E29D2E3A923CE39E3FB5747E +:10C05000F7C93E2474D3D59389E3ABA2E8EC709082 +:10C06000FD12FD47D3DABC4CA7DB1C4CA7A59A4EAA +:10C070003527428B05F5E1A46BC3F7491E4E6EB41C +:10C0800002C54D6D3448FE32C7C17A05C9E1946AD4 +:10C09000D483BC372D5E8ACBDA513E3C241FF5D9C0 +:10C0A00086F54E8E7B37290FDF3B99AC24117D1628 +:10C0B000866D4CB79B1508DAD15EB625DF5659CE92 +:10C0C000FAA1F278ABB6CE6B599EFBD2D8EF8C7743 +:10C0D0007D8278499E31F237C37BE71779D04F7460 +:10C0E000FB8874AE2334937A9783E6724780E2CC60 +:10C0F000BAD265B9E41F9624660F00C4A36EBCC40F +:10C10000FEB6AEE10BA6BBBEBE725A06B56F777F18 +:10C110007C86CAF640513C2C0FCA691B8FD7349CD1 +:10C12000643B8EE0A491DE742C13F6AEC50AB754BE +:10C13000635BF3BFF22DD538BF06430CF617B0D3BF +:10C14000B624CA1E42EBE75D76BF0079B77ACA5BB8 +:10C15000B16467AB25D70C401C8EA6BBAA95D1D87D +:10C160008F71CD90B0DFB6EE8C97FBA9AE1916ECAF +:10C17000EF4ABB498C0F74FDDCE206F87CDD5DA262 +:10C180009FE63A40FD0FD31EA95606623F5EC8C126 +:10C190006FD26AABFDB9245F4EA6CB891571AC1F77 +:10C1A000BDD1795EC3CB06BA9C332E4BB778C96E2E +:10C1B000CC1476F1D8CA416B391ECA0C65D39E5B8C +:10C1C000D344FCDA1F79538AFF5E45BD77201D9268 +:10C1D00033C063C1F9C92FA23FA2F91F878610FDA2 +:10C1E000E6BD181394901F8B9F78C546FE68AEACD1 +:10C1F00066935EBD3FCCB793E4E3787C88FBF31A8B +:10C20000B6335C29592E61A75D9DB95E94CFF9D0F4 +:10C2100062A3F1F9A01C26BF614161A6B866A173B3 +:10C22000978DE2B2854F5B0F87A3FCEA22081F229D +:10C230003DAD79D67A381CE57F81DE8F92AFC3168B +:10C240000187A2D163AE1C9A6D13701D20B816270A +:10C25000617C2F93BB08F5F7715C5493C379494A0D +:10C260002C90DC2DBFECFD7C5F0F7EB0B511FD3E48 +:10C27000AADCA6C62DDCAEC135C9EE0C50C23637DD +:10C28000AE53ABD9E592D0611B44BD7F42A36B9FF7 +:10C290002D128FEBF6A27B3C5ED025D733C2827085 +:10C2A0002C9EB66F1CF145E7E79571D01A93C47CBC +:10C2B000716B7C71135F74FA233D0B157C6FD7593A +:10C2C0007C2FAD27B9D0E92FE06D8B15F6A27373E3 +:10C2D0000CC74D66F8E3D205BC3A1E43D3CF0FFF1F +:10C2E000D0F4EF06FEA1E9428FCD78E87AAC3FD7D3 +:10C2F000F5D88CB70EF7A5CB59C8763172A6DB9965 +:10C300005AF0E5D0FABA5DD1E9ACC3A9D3AB8DF24E +:10C31000A11EE0541A5E32E0A3842A28898071E9C4 +:10C32000E9C28EB54E02E283D2B095E75D2A3EBAED +:10C33000BDED0D2FDDCE9AF1D3EDAD8EA76E7775E5 +:10C340007CCBD090B03DC4349EF2AC2B4FFB0C7133 +:10C3500070392C30C4C9958E3B0DFD2AD73D86F926 +:10C3600057A52C338C4F52571AC627E73C62E85F1B +:10C37000E3FEA5298E5F6B8AE37F63181F170E719A +:10C38000DCFD7AE344509047DF3BD2C9F177B0D16E +:10C39000C5FD9D8D29DCEE6A5459BF7737E670BB29 +:10C3A000A7D1CDCFFFDC58CAEDBE460FB7A1462FAF +:10C3B000B766BB30F5F9EB15CA574A432D9564CAE9 +:10C3C0007764F87E928EF47BC312688A473A8D6A4E +:10C3D00017F139CC37FBE35387EE25BFEEB2B9C96D +:10C3E0001F36EF182DA93DC47309E8EF3C51F292B6 +:10C3F00030250C1E8A7BD03DF7245F2DE916964729 +:10C4000032FB807A37D301D664D4B79933257713BA +:10C41000F0733F24711BF4E1F85405FCE4FFAB9D7D +:10C420004AD09EC0A0791D08E70C0126D8699CFC63 +:10C4300077725F85E2D6EBE821C22B7B64F81E3E63 +:10C440009F51FA97339437DFE86CB5929CDCB0E7E4 +:10C450008163F7E23834FB8B493FBAE206FFFB9673 +:10C460004B891B5A28AE443A462477C843F14EA262 +:10C47000E28ECE07F4F6B674910F4C6DF2CB0948FC +:10C48000CFCE3781E3385D1F11BF1504BFAE17D57E +:10C490002E25382C81FCFD239534BF66BFCA74D18C +:10C4A000F542D7033D0FD4F5A04A7EB689E69F3802 +:10C4B000089C4F8FEAF01D799EF034C59DA59D2DF7 +:10C4C0009594975D286F1C73BAF5159AB7BDD1C7BF +:10C4D00072B4B57126B7C1C6F99A7CD6737F57631B +:10C4E00003F77737FAB9DDD3B84293CF161EDFD7FB +:10C4F000F838F75F6F0C6872BA919F8FCF10FEF714 +:10C500008B50E50092BF17D3451D071CE59C478063 +:10C5100022DA8B95939A9497453C65920FB35CE829 +:10C52000F200683724A4D78DE867C93FDC04FEBC5D +:10C5300039D8CE9CD7621D2B7D7BB958E86CE6F8C4 +:10C54000C36C0F174090EDDDB9F65DC4FF17B2EF75 +:10C5500032E6ABE4AF74FBB718C2BC9E5DBED34DF0 +:10C56000F594EFCEAFB834BF0273687E57DE1DDBA3 +:10C570003E5BB65C38EF2E1A2CF8AAE7DD183F02B6 +:10C58000F9E54840E6B87A7E5A4B02E7DDA59D09F9 +:10C5900014072CD826333F30CF540622DFE6697CBF +:10C5A000EB80E03BC49779E3E6715D6EFE1A233EB3 +:10C5B0000B9DD7F509AA3DC6693DE2590B0F7F4E89 +:10C5C000F5B95A8D5EFC1CE16968BF61D2AEA879ED +:10C5D0003119F1C99FC49142C128A207C2EF0E923E +:10C5E0009EED9759CF7A938BE3989F909C9F6A9C7E +:10C5F000396917CAFDF1B38D9C7F25653CF2887FB0 +:10C60000DC77C7AFB559DEA1199C0F856DA43F3A01 +:10C61000FF96938D44B8975738029468478A5D0A0D +:10C62000ED1F913C723CF1E323702F43FA956F7D2F +:10C63000ED20E947B9C3C9E708884447343F47EFCD +:10C64000F7353971DEA87D1E99C2F7E25DE1269AC1 +:10C65000A6FB1BDDFF8CEDE8947D5C17C8643D02F2 +:10C66000CC25BEC9B8783D32E79B4D946FA2413AC4 +:10C67000E99CC0F09E0C829B9E77D7B544BD69ECC7 +:10C68000598F9C80F02DD7F2C3D11F7B198E6A87FA +:10C69000CA7268D7F2497B8A053C517474D97C1BF5 +:10C6A000A9FE097F8CE13AAF19BEC919C28EAB4908 +:10C6B000DEC94C5FA79A4D794395DCB1E1D7240FD1 +:10C6C0006D716E3BBE67B6B7BA7DEB2D6EAF739DD5 +:10C6D000EC318ED4DB3A8B38371859A91652FE4705 +:10C6E000F125E5857A9E689EEFCBAA989DD18FEBC8 +:10C6F000AB210FC1E5B29C574EEB1A3E3F6F9EA691 +:10C70000EF5FB7ADD83537AA0EB226433F5F505C16 +:10C710009F38BAF976B1FC2DEB9C69F03FFFE9F147 +:10C72000DA540C7324D4A13C2920E20810F1C42C63 +:10C7300008713B1B3AB9F5A124513B17DCDCDE063E +:10C740005E6EBFCEF4AD26B989583BFB931E1F7BAE +:10C75000E1EB5C928B63DF1BEB4A53BBFDABEE6FEF +:10C760002FD5AFC6D2F9520FF2B041935BDD6EF711 +:10C77000CA1F93DD8E8C40FB807046368B73B148A8 +:10C780007C6C80CE0174FB007E63BCA8DB8BC2593D +:10C79000EE37B85EB84FE6BAA5D97E5429228F0786 +:10C7A000C59D43F5517DFF260BCC2739DB88ED1F56 +:10C7B000108F3EB3C28A1A85CF760D8FF21BC60347 +:10C7C000E52F535D223FAC724032E57370F664EEA4 +:10C7D0000C340453291E45791E95E4F913D1DBFF6F +:10C7E000D0B8443E7F20FB3314F9F79138B7810568 +:10C7F00052200BE9B1A54DF4F36E4F64FC6E82201C +:10C80000F3F166085B09FF5B00D8EECE0195DB5BB8 +:10C81000C1C3FCC495E3F2D10EDDDEA68C5C857845 +:10C82000162475A6937EE68D7E2F4942B8F229FE26 +:10C8300075726D6605C5293A1E964C81C765999E2D +:10C84000B709BE82A4D0AAD514176EB600C5859FBD +:10C850008EBEE70E88F2AB2559150769DE73923854 +:10C860002FF46FB38BBA1A74F6F746C5E35F6756B9 +:10C870001E22BDFF07C1C6F9EF2A3E47AA7609DA94 +:10C88000C3F87E4C037C6F8837AF27FDF4B37D2C53 +:10C89000205A8A3AA11F4A795FEE7FF5D417D5CD89 +:10C8A000021F3FC5632559BE08ED5760435348F04A +:10C8B0003F610FACE3B8A97E08D52FE63D69B7907C +:10C8C0001F7F0FED309D9B7ED0E8E0F643CC6FA834 +:10C8D000FD1BE637D47E84F90DB57FC7FC86DADB15 +:10C8E0004F8F402102F861A6E77F33CE8347EF7672 +:10C8F00046E0119160664FE77DA73244FE91DFF676 +:10C90000F1037124075B6437C969DE6685EB10C7E4 +:10C91000B78E0AC869D174F5C565221CF95BDE7E45 +:10C92000746C11BDA7B8249C7F7CCBC9FE9C379941 +:10C93000E0EBA2C7369BA08706EF7389A155F4FEF2 +:10C94000739BD30942B42320E490F8D9431D0D60B2 +:10C9500019F3F1F50C113F5D6BEF2C8A3EDF040AF1 +:10C9600019A85EA9F9992AF96C423857ABDB8E26D3 +:10C97000B9CE7C83F6F3EF117A887C35D4252A353D +:10C9800039D4DBBC6D362FE9D373DBDE993619E978 +:10C990003075CCA46259ED9E5F98D98FF7CD1B7D81 +:10C9A000E657AB93793E9F5BDC006BAB5C38EF26C0 +:10C9B000C78E57890437BB3EAA4AC4FE2D29D26EC2 +:10C9C0006AE7A8691392C80E4080F7B935A77C378B +:10C9D00089D81477B58DFC7239295594DDAD74C4AE +:10C9E000D1496A57BFCAD5D7D0BF2A659061FE2406 +:10C9F00035C3303E3967B8615CDF778ABBD0308F92 +:10CA0000F495E266C483F90EEB653E97C9DBFCC57D +:10CA1000FB8B18FF1B8A08FF08D2CF8681C591D2F5 +:10CA200095BF584D6663F3CE043EA735C5A735DBE9 +:10CA30009EDAED517B8F4FBF84AD3DC675B5BDC449 +:10CA400075171B9FA2FD7894EC47C10BD7F1B9FB7A +:10CA500073A3CF5CA6225EBE4C8C5BC9EE99E2D676 +:10CA60008816B79AE5A74B4E2555C8CD5E19280EF6 +:10CA7000D2E357B3FC003CA0F97FD15EAA9E4F7D64 +:10CA80004BF8AB7F90BEF78D966BAD35D5230A6C16 +:10CA9000E857A84EF85719D6D183B308874EFF8CB4 +:10CAA0006EB987DBD6BE3AB0889FFBE371CB5AAD37 +:10CAB0003EF1AB4CED9CBF66C7AB0393BBC7E1AE89 +:10CAC0008F0CF3E13E69B7A1DF9C66EC3F5CBE3B97 +:10CAD000FAFDDEECD0BC3577DA7C54977E4CD42955 +:10CAE000CDE33A3C553B633C642F95AD76CE876AE7 +:10CAF0005D1EAE9F28BDD44F74BB70830CF53DD92D +:10CB0000B7F5DABA5376C680FC2DD67D0F6585E081 +:10CB1000F1BF28FCCC7B7D3CE08DDAA73553C47D8A +:10CB2000C7125B7EFC15CE3BF612B889F4C712859E +:10CB3000BDCD6FFBD462213F112BE425DF15B62458 +:10CB4000D17D97F9717E3A4FAE5B10EFA773A38248 +:10CB5000F4CE771CC8FA2D4FFB1E75A0DCBD6FB15B +:10CB600018FC4E846C1DF67764FAA691DF99BC33ED +:10CB70002668F916F8ECC804E1D72A84BECF26B996 +:10CB8000D1CFC5D0D4D43D08867332C29FFA679EF8 +:10CB9000BEF5ADC728EEDD2BF41F879DE67CF4A61D +:10CBA000A87C14D608FD75E02FC5390B77B5D828B9 +:10CBB0004FFAAEF4BE3DD3D9ADDFC3CED5675DDF4E +:10CBC000EB0E087D3FB1F5CBB7C8AE9F407F17ADE8 +:10CBD000EF5D7E51D3F3BAC765D647FDF9F1ADF2EB +:10CBE000C4400FF47D4D930370651BCECD96949D8C +:10CBF0009A467E6DC93685CF037BF3D7752B8CE7BC +:10CC000064CF6DB7CF17E7C8028F88EE4FB77D9915 +:10CC1000549E2BDA657C5EDBA2D91D11C7A01FB51F +:10CC200026931FAD96B8FE7660DB00BE9F714082F2 +:10CC3000A03A9297B8CE817C9B2E96A3E74E8AC7E6 +:10CC4000202547A17DA669FC9CAED585666C9B918D +:10CC500045FC7AA76DEE010FA19795C1F2733DF8DF +:10CC6000391E3C90E84DA57B0A539B847C1F48EC01 +:10CC7000ECA03AD281B23889CEA370FDE6E878EF15 +:10CC800080D59B5ACF78E9E79357C8DFC45D421E31 +:10CC9000ACD943E4A75F12F91CCBBF32F06196AB6D +:10CCA0000510D8EDC17D6BDD418E4B1781C8EBCDF2 +:10CCB000F17CEDB8CF6CE417CCF967F9961D07E964 +:10CCC000DCE39C3A84495E2F547730E7BDBDD50F35 +:10CCD0004625790BB3A2EA7EE6F8BC2B0ED5E3A875 +:10CCE000F5717C2EF44AD97F1F5F84FDBBD6C7B98E +:10CCF00028CF3EFAA4DD4F76F9E83A7B40C2F1A393 +:10CD0000499DED94771CDD94E7C615609E45FDDDD9 +:10CD1000B3E4D77F6B65B90030DE6B58527637DFEE +:10CD2000FF5BB23E5EA27B389022C6F59C4F7E260A +:10CD30009EE38205CF0FE4734EDDBF907ED0B9F441 +:10CD40009127623C14E41FDD33BD0FD5FB3A2C7FE5 +:10CD5000E0F37C90EF3B44E7F58B36C48FA4F801F9 +:10CD60007281F9367FDDE57CBEF973C53783F0AF9C +:10CD70007CE69A0174AF6CC1DBFD80F0896C7D9E0E +:10CD8000CFFFBAE3F49EE3BB135B33FA406E379DEB +:10CD9000F43AE08AA7977989EFC5922ACE69A0DE96 +:10CDA0003388E4624B35D0BA2365716FB473651C68 +:10CDB000C7A566B9ABC91271608D5E6FE80B8E14A2 +:10CDC000D21F1F301D222B87AFA3F3B0E6AC24CDBA +:10CDD0004F77664F8BBA975825B7D7BE4CF2B9C676 +:10CDE000CE75908E989ECFC11AB21279FE3C87F113 +:10CDF000DCBCB6E18CB19F8BF91DBE3FB2492DBCA6 +:10CE000013DBA51AFD57A77AEFCDC2F717B63EF28E +:10CE1000C23EA6CB9A1FBE4FFBEE718AFACB3E41B3 +:10CE20003F73FC3FCF21EA1C006B797FFDF9A74FD0 +:10CE3000BCCBE7AB9F6E1E9E2DCE8D439FFC3A8DE3 +:10CE4000CF8B0FDD8BEDA63D6F315FCCF09E73EE87 +:10CE500027498C6F0DE1D197CE77BD8F109CC80804 +:10CE6000CEDBE6AECA63FAE9E76F91A33DE7273A66 +:10CE70009CFAFA3A7CFAFAFABC27B3441E335BCB2D +:10CE80000F8ED942C7F91CFD85E112D5F7BA9E274E +:10CE900085F213A3E4E5BBAAA7DFA8D5430E5A96F3 +:10CEA000FDC046F7E45A575B7DD176EF12EBE85DA3 +:10CEB00071A00754577FE14AD86F21724A7F3AEF39 +:10CEC000D3FAA40CD81FA78127113C746F506B6153 +:10CED000A12F85EBE4B49E4CD71003DC6F2A77AB0F +:10CEE000D45E29791571EF2BC0F23F01EA07131EBA +:10CEF000164798CFC5F47B2E3312975F9386FB3588 +:10CF0000F783E514C7345B855EF8E7C471FEA6D3EA +:10CF100049F733E0CA35F8976617A80AAE3353814C +:10CF200015D624316F28D2F9C09EB9AF529CF0AE0D +:10CF300052DF8FF67DCFF9589E64A1F82E104F393D +:10CF4000E2FB6FFDB6F8AF38F703F09439517EAECF +:10CF50007BCDC176DF5C8FB81D7CDC9F0761EB1752 +:10CF6000F8DEDF46FF6BFD4EE8C6EB6F63BEDA4CC2 +:10CF7000F9C14D890F14D3FBFA3D4CF37DBFA32EAD +:10CF800027DF0B34DFFBBB167C9F91DD3A65F1D5C3 +:10CF90008AFA47FD28F2BF91441B48383FD24FA37D +:10CFA000C731607A44ACDAFB9FABDC2FAA1CC9F511 +:10CFB0004838A5B23D1E6BF23745C32D220FFB4604 +:10CFC000CC2FEB540CFEA6A840ABDB7CAD725C7A98 +:10CFD000E569E5BCFEE8A16C61CF8AFA5AEA7B8A72 +:10CFE0000FD56CA13F4D1094053E224E18DB2557FE +:10CFF0001E99F857ABF56BC99FA13C45121C7EBA30 +:10D00000E83876AB90AFB14A7007B5685DA181E2B0 +:10D010008A2DE8EF7438E88C306538CBC1185D3E56 +:10D0200071AD59386FB954CF798B83E2196C574978 +:10D030002186E37BD0C9AD47F3E315E0E6763C7883 +:10D04000B945F9E47622B4707B35B4723B0542C22F +:10D05000EF5F116C627F06F7B9F8DC62D23C0BC55A +:10D060001B45D7F79C2F546874EA9D0EA87025972E +:10D070004E8709807A97D1033D06E7B0FD30D3C3D0 +:10D08000AC9F651096593FC93064509D40653DADD9 +:10D09000040FF7AB2E920EA5619FC2751A333D2A7D +:10D0A0007B968BC91A3DFE950D2C1F3A9FEECF56ED +:10D0B000F9B9CE2FD4AB14927F331FF5E745711524 +:10D0C00027E96AFA1DD9C3A7D3BDAAA2C28AA5645B +:10D0D00092EFDE30663ADDAB2A1A5BF13C1D79DE59 +:10D0E000933D4EF40B2A0AAD6ECC5AA4B2E9E3711B +:10D0F000BE4FBB970C33457C7D9716B7F896FDC0A5 +:10D10000ED423DF1A53ADD849F03837BAA7FCA19D6 +:10D11000E27C70C8C4E04E2BCE3BA4F8E664537C9E +:10D12000E00826A848F7BB9655F1BDB5876C62BEEE +:10D13000DD2EEAB03A5EF8DC1F83FD4D9B862F950D +:10D14000D27BDF1FD7ADA5757DCBB2FCA4AFBECD22 +:10D15000925B70B262C04CD4CF8E9015A81EAAEF1D +:10D16000939DEA5B9ACDE7BAD95C271BA4C5331D12 +:10D170009B860F27BEDC9FADDDC34A4E2B24BA2D04 +:10D180004BF5DE4FF323F142BEEED7F8D05BBB2167 +:10D19000DB735F76F1B9CF23FF4000F0FD9F65FBA5 +:10D1A0001EA0F5EAE2CEB27F3F3EE2EDE5E1B46ECD +:10D1B00039959049B310EF260F046CEC07B4FBEAE5 +:10D1C000DA7955E4765C07E950E4F53591491B3589 +:10D1D000ABB384EC27AEFB5FBCAE2D3C6404BEF762 +:10D1E000D8F44336216783859C697668DBF6BDF702 +:10D1F0000E125D2F44E955DDF6335F7D80F4AB3BC5 +:10D20000E174D3F46E7DFAE552CE27C169B01BBA42 +:10D210009E8DD962E7B87AECD6CB6FA779656FB7E8 +:10D2200067105E57B687F91C2CB2EDDD41020E3D4A +:10D23000DF38257D1BBF4BE7B49CC76D16E7B44BA9 +:10D24000A4FA57E2A9FF7BC9ED47F83FD5FC869EBB +:10D2500017CFD7F05ABC77FD72AA8BCC5F73EB1453 +:10D26000BEC7131079838ABFA4FF5FC23E3E1F5F13 +:10D27000B4D19C4F74DA88FF8B5B4DF781281FA6D1 +:10D280007B0FD1F6BD877C787BB6764E9B0AA98C46 +:10D29000873CAB8FAF077B67CE771F07CFAB2C9F49 +:10D2A000E09569FF62A5E77AC273DDDFD3B03ECCBB +:10D2B000D3F6263A3939DFB589FBC24F2C75BBA8A6 +:10D2C000AFE9E75A9495528AA33B7FC9F2AFBFA753 +:10D2D000EBEB8215E25E36ACE9CB3257B0C1EE2102 +:10D2E000BE166C18C0F905E6411CF7ADDD605F4164 +:10D2F000FDA60763FD7201D5933B2FA3BA4A538C59 +:10D30000F8CE89DC23DD132D4817758E33BA5DD72F +:10D31000FCBA7EDFB62BFF89CFE67BCD5DE361C52E +:10D32000906F3469F17311C1477160BD55E44F319D +:10D3300002FE1D6F7E3F8EE2D8CD8A378EEAD2275D +:10D34000F6A7F7811EE8A6B7C5E85EE03CE78CC506 +:10D35000EF4EC9381FBF8A1ED7EEA76BF2F9C7463A +:10D360000FFCDDDACD0F1DAF2AF9D94A1BD5396E76 +:10D370000317D53D96EC7DAA89BEB759B212B8A263 +:10D380007082FE50BE70C4C2E7E063F616A6903C01 +:10D39000B669F68ECE85D528B92AA1A210CE2F1E49 +:10D3A0000C01FAFE28468D05352A2F8ECB4932F422 +:10D3B000E3DD9719DEEF539A6E1807BF27945BD20F +:10D3C0001DBF267AAE30CC7F2861027F8F5316BAFC +:10D3D00083EB4A7D278E348CDB51AEE99E037C21A2 +:10D3E000E29F52FC65BF0AF532C139360CF02B942E +:10D3F000BB311DC6F8A834DCC27960CC7EC590D79D +:10D40000DB2F5067BA7C98A6578361B0B00F667A5D +:10D410001BEF432CD92B731CB7241503CFB4DEE9C3 +:10D42000ADEB9F4EF77E5E23DD07CC34D279A0CFE3 +:10D4300048E741F38D744EAD37D279688391AE6978 +:10D440007E231D33568C31CCCF6AA930F4873D7EC4 +:10D45000B561FEE5816986FEF08D371AE6E7B5CE47 +:10D46000358C176C59785EBE8F082E318C9BF95E17 +:10D47000B8E74726395498CEC5DAF7593AFFFDF890 +:10D480004BFC1F0BDE3E4189CA81FE26D2C7FF2F0F +:10D49000FE2F18A69D23E8FCBF48BB7A95E687CDF2 +:10D4A000DF794D8D13F6E6F53D27F67BB0FF865A02 +:10D4B000684DA1B8498B0FBCFA798429EFD3F39456 +:10D4C0006B4B25D3397D8CE19CFE42F7DA8A4341D0 +:10D4D000437FC47EF17DD4C883EE57A82DFED823A8 +:10D4E000477F0F35FA0B76CBE7E49DFAFD383D6FA9 +:10D4F00082E627390F9DA5C34F4A50726E7D51CFEA +:10D500004FCD79AB9EAF9EFBBD95884BEE967BCB06 +:10D510006345FEAAE7ADDF070F7F5776D560DFDAF8 +:10D520006168FF654B675F1AD7F359222C9D1B4733 +:10D5300088B0FCDDCC3BD33DB9FC3D2AD7BD174AB2 +:10D540006F4FA77BFE08BE2B5C22CA3FF4F3D2309C +:10D55000DFEF68BDC3926B7921BEFBFA98CF86D00E +:10D560007AFF334CC46F76192984FE67C02C0FD024 +:10D57000F351499EE768BEF97EB6B935DF1B6A6B89 +:10D580000C72ABB8DC7C6FC75C1F0C5B548E3BFD30 +:10D590003F92F89ECE6704DCE8EE78E5C40A2BC71C +:10D5A0002BA0E5E3376BF4D7EB16B3347C0EE31214 +:10D5B000F3D1FFDEBCE535E6CBA2940EADDE51CF54 +:10D5C000F1F5AD839D23F91E9AA7D02DEA5C7A1D53 +:10D5D00063D0257D5F7221FC17A51C35D491E0D95D +:10D5E000BE1775BEDD8DB758FFF04A518F3CBC3277 +:10D5F00095EBDFDDEB1FE77AD2CDF56F1AF4E296FB +:10D6000086F70C7A30C7FF91613C9CDC69A5FA6112 +:10D61000F88581136E42FA1DDB6CE7EFA1510E3ADB +:10D6200088AFFAFAE195C3C7F3779517C4F3338649 +:10D63000A3BD31C4FCD5F13CD47890FBE1C630B732 +:10D64000663CF53A85DEDA76420EDDCFEF9462DD98 +:10D65000541736D72FEEB6A89F901E3C9493AEC5B4 +:10D660006BF5055EE69FA857B46BDF97B66BDF9747 +:10D67000B66BDF8BB66BDF87B66BDF8146ACCE1542 +:10D6800054D76897C4BD9F5992E7C939B85FDA602B +:10D690009F3387E2FE859DF90AEE5357109E2D2198 +:10D6A0009FF3FAF9FAD07309D38581FC3D919FEF7E +:10D6B000871DB1F8F3E9FB9BC91BB3AEA33CF0484F +:10D6C000ACFF384522953969D751DE77C426F4700E +:10D6D000FAC6D8EB48EF3EC6C5083FFF4B92A82BD1 +:10D6E00039C336FA7E6A6AB26F504EB1B8F7C5DFF9 +:10D6F000CDE073924BBDCE19B18A3830A2C583E913 +:10D7000039E21C302347C4AD7A5B463CC7E7D3A956 +:10D7100065FD7C389BBF375963078A5F717FFEBE0A +:10D7200046BF6762FEFE66E49FECFC9D845E0F2DA3 +:10D73000C949E375E8BB1CD2CBE49FC4B1DD82705C +:10D7400068087DC7D305EF7EF15DE531AA2347D593 +:10D750009F4B72441D066E03C377408BF71E3E44F9 +:10D7600079D6FBC37C6388AE732D6A09F17571C2EB +:10D770000EAE774DC951795F8497F145FBD34C7C50 +:10D780005AEC08737DEC42F5F0DEF03F767BE8174B +:10D79000B95CFF55F3F93B3C6D5F84630AD15FC709 +:10D7A0005B87A37B9DF3CBBF5ED7D5FB9F3EF1503C +:10D7B000B65697BFC5DB833FBD55A34BBBB5E73A14 +:10D7C000FAFD1A7FCFE1CF3000AADBDB63D14760DF +:10D7D0005BAFD1E9D80D880FD7273C2388BF8BA733 +:10D7E00039F9FB737D7D5CC7F787F3ECB33AD5BBA2 +:10D7F00090F05F582FEAEEFA7844127CF5AF14757A +:10D80000D0C5DBDF3B44FF1F8405CFE415727EAF3C +:10D81000BD6FA633D297BF8B9A2B8B732BA4EFDDF2 +:10D82000C46773BDFDDBD235922ACE57236BCF0C74 +:10D83000A17B648BE9DE1A7D1FA6D5AFA0CD5897DA +:10D84000427AF9A95E71EE7914F0B9965DF3237608 +:10D85000FDFDC18AE1FD634EEF4F893E2F687603DF +:10D86000E7072CB87F9B9E279BEA286D2151EF6C20 +:10D870004BB1719C4CF10EF9273DDEB9EB4D51EFE8 +:10D88000BC2B4DC4D1041FF1573AB89BE3842EFF43 +:10D890002FB955A29FD3EA0BD0FEE05BCAFE4B1E08 +:10D8A0008AFCA5F38B3F5FADD503843F2CD6FC5F8C +:10D8B00031AD43014E6E1FF68B45DABE183F72DD67 +:10D8C0006D34F89A04305ADD6CE56E431DE1FF00BB +:10D8D00090CECABD504500000000000000000000CE +:10D8E0001F8B080000000000000BFB51CFC0F003AD +:10D8F0000917B1A1F26FA0F1B33851F9BF5951F92D +:10D9000097D0F884B02E1303C30A46D2F420E39DC7 +:10D9100040FD0780F838109F6322DF1C103E210C69 +:10D92000F48F1803C34220DD0DA4AF00F11F207E49 +:10D9300004E44B8B30306801F1325106864420BD3F +:10D940000688CB4520FA4E02E96651F2ECD4E3A1F9 +:10D95000CCCDA39832BC411A955FA3C2C0B05695F6 +:10D9600081E1931A84BF02499E5D9D81A15605C243 +:10D9700036956360E807AA59208DDD5C33A0FC046E +:10D98000A0BCB83A840F00134DDDCB680300000043 +:10D9900000000000000000001F8B080000000000D5 +:10D9A000000BCD3D097855D599FF5DDEBEE42679A3 +:10D9B000819705B8090183067C09612DE24D8C1819 +:10D9C0006C8A2F88364E197DA0D56859223235B61B +:10D9D000DABC4012C2A6416D8741A52F5A2D525A7A +:10D9E000A3624B67D4792C1DD1B1355AAA76A49D78 +:10D9F000C8388E5A65E242AB558739FF7FCE4DEE6F +:10DA0000BD7909A89DF98ACBE1DC7B96FFFCE7DFB5 +:10DA1000CF7FEE73CB3E80090027F1CFB900574B83 +:10DA2000009037548237D608118026CDAD6F2A0674 +:10DA3000F886123BAC57B1E763E5D8FD3A3E9F5CF0 +:10DA40000B610005DBE703C4F07FACDFFAE0BA311D +:10DA500089207BA62CCDC2D21CDF2C9B5400AD129A +:10DA6000DF6F999CE9BD5942CA35D0EF05FA73B210 +:10DA700004A0E5E86FA71E32EBECBF0208455E0F7D +:10DA8000B0BFCC8259271580F7828BB3D230F278A1 +:10DA90006FB5769FA54E02F853EBCB530F4D1AFE90 +:10DAA000FE1B0A34F7960F7F3E0BD8A433101F4994 +:10DAB000777CEAD0BA07D71964489AC3FA03A43D21 +:10DAC00039ACDCB5ED2CB56C084EE73A00921CBFC2 +:10DAD0009FB39F2752932E60B50A29318FE052D908 +:10DAE0003F3301A829DB97EB763500C1E580B723EA +:10DAF000F2978177C4FD12EDDE0BAEEB04D66FBD5D +:10DB00008BD34B7B9E1C5B07C3E9C5DC0F138FA730 +:10DB1000BB1F37818FE631E9A8495E3AEABE9F8A8A +:10DB20008EAE443A3AEBFF9E8E927FBD74D441E3B1 +:10DB3000FC95D1114037C717F4AB38FFD0735E4660 +:10DB400096F64A4867ACDA87708FE353C1B896CE31 +:10DB5000EBE5694C4C41ECE93398DC1AD7BFAC1EBD +:10DB6000E11E7B74E19B58762EA9A93B9FAD2FBF88 +:10DB7000B1F7F90B581989A7A404DBAF3B4046A1C4 +:10DB8000C2C65B91AC66EB6BC7C1E6023C905C66BB +:10DB90002471BD60008C01F83BB126005957593DF6 +:10DBA000447FCDB40E37A4393EA4939EE1FD475A7D +:10DBB0007F08FB996D8AF1FF6B00D777AA7EB0963C +:10DBC000CF9764FF20BE0B87E6A771F29B2C7540B0 +:10DBD000FCD8DFF7E15F08BFD7FFBFCC5700953E09 +:10DBE000940FA17A594B617BE8CD56593DB24285DD +:10DBF0003493110555DD924B3FF5BE7402D4F5F216 +:10DC0000FD911A4243F0FD2748443FE3BFF55ACF48 +:10DC100006467227960663441F1A406ECEF0F57CC6 +:10DC2000B71509D9525F52232568BED8D3A5AC7F5A +:10DC30007209D77B77D42FCEB6CA2B8F2409BC3973 +:10DC4000E903747526B215A70FB55E367CD3BE38CE +:10DC50007DA89F933EF2D65AFAC167DFAF88691755 +:10DC60009C267D7CD1F9CC7D1DCE576D625F4B7DAE +:10DC7000C0F8F6F6BAC519ED8C91F7B592F83D5299 +:10DC80000F462A43BFFCC1FD4C0E2FD9FE2883DB73 +:10DC90007B836DBF94B1331B7B46C18712B1AFD775 +:10DCA0001CD7D7A2E8AFE5B2AAAAC9389E1BC763A2 +:10DCB00074B6317A7B12183F9C40DA66F850BA2B62 +:10DCC000D258875288DD2F209059DD1735529B8816 +:10DCD0000E52B42F267C1E5DB6E15F8DF86D75681F +:10DCE0004C4A56F87D2D6E82C38DF3317A57343607 +:10DCF0002043851A84B42F8C2D38FC4806272762D0 +:10DD0000FDDB363AE8D22B21D33E98F48A68E5F45D +:10DD1000FAEDD3932FCEF996D8E13DED7E41557FB4 +:10DD2000DDA28746EEA7C2EBE6FE30245E8503CC7B +:10DD300018DAA70D2ED8279DCDF475D1A590604F88 +:10DD400037E0AB3944A764CF6C28AAD490AE609773 +:10DD5000A4229CA61E85680EB5AB90741A47F636B1 +:10DD600003B653820695E6FB91E112F49734F697D9 +:10DD7000B271BF22F6F72B42AF4195EBB57E136E21 +:10DD8000D2B3EA509DADE39D9BD8FF189D242BA4F0 +:10DD9000D4FDD2F0F7F5A817995CAAC7E716B9B277 +:10DDA0007D900FA2B45FF5E2DDC1C75E9A3C9DD1C4 +:10DDB000475F4C01145BEB1EF318B56CFCE7CF9189 +:10DDC000521E49C0CBE05C24E07CD6C81D8774DAC3 +:10DDD00057EB213A5E74C19F2248C6C7F7FD5ACD62 +:10DDE000442F8BE6B986E060FFADB6AE8FFDF7C37A +:10DDF000C17D29A2794CB856562A0447DF3C2985B3 +:10DE0000F31CFADD7FDDFA2506E7B35552CCA313E8 +:10DE1000BC2160F3F519EF4746F53BCCF975D010FE +:10DE20009FCEF9CDFD081702E115FE9DE195CD9736 +:10DE3000AC19E85F8F783E26C5D6B3F9B2E6B74C89 +:10DE4000C0798A6599E0DD38CF2B2B8C7EE0E531F7 +:10DE500032E23328F83CCBDDED9DC8E0EC9C24C3D6 +:10DE6000BDECD1C6D2D1E559BB439EA95ADC90582E +:10DE70007F3DA9552AA3F045CA90EB32C9BB672460 +:10DE8000AE273B928BB5525CDE21BB1D887A296E92 +:10DE9000D1ABCC5E7C4662EB7745381D67D7C6B9FF +:10DEA0009DD83786E45740EC47D6B4C55990C10E8B +:10DEB0001E711D6CA24C7673B6CCE183A37C7CD51D +:10DEC0001C3F67F4F13788F13F6C92A00FE153E3F8 +:10DED0005EDC7F302A889EFD823E616D0ED54DB995 +:10DEE000EB298B7715B37DF44465D0755C5F92F6B2 +:10DEF0007933DBE322068ABF96BD674D377FAA9050 +:10DF00005D922D9F4826191C9BF75F0B3AB353FD7A +:10DF1000D114507DEAD55EC4CF66A614F8FCBD804E +:10DF2000F30718D9A27C0D30F9AAA37CD57BD33294 +:10DF3000ABAB751033D8AB901693FC8C640E444B8E +:10DF4000DA54F6BC7D2910FD025A1116FCB6475F63 +:10DF5000301406576723905DD319A9A1F5B597D75B +:10DF6000788BD1DEA957E9397CC2F061DA214C1EE9 +:10DF7000FACBC0C0F936E7432A88BC549B47F4E883 +:10DF8000D6F8FAF5EDA5909ECEDE67CFDC8FF327AD +:10DF90006F81D8243E25C935D5A40B359194D0BFC7 +:10DFA0006BD1629B32D0DD764864C9336C744A7A97 +:10DFB000D789B72C375C88F8EDAC60F45F3C7C9C6B +:10DFC00022E41F466FA9D8E28B4A32CC532CEB4493 +:10DFD0001F665DFFD04DF08FD47EA81DB3337371E3 +:10DFE000684342BC406D84D69703837F0CACE78ABC +:10DFF000F58E81666A179DDDBD1FF9ACC0E8AD46A0 +:10E000005C7C3774E9F3B46F70B786F108066DE98C +:10E01000C9DC21396104B99C782F26937C0CC9692D +:10E02000CD6003847C7D5152D63A901F91855D1856 +:10E03000C09B5ABBA7A27F19869884EF43313569EC +:10E04000953F59C0EA36FB0F8E94CE24D2E27C0174 +:10E05000DA7E6419ADACF90C1CEF0E06908FF9C98D +:10E060005B4209D2177FF285A7E1647F92E3596989 +:10E07000DEBF0CEDEE1B157F6C13D2438CEB072F2C +:10E08000FB07E55FD66CD5268FB30D7B3DD7A13757 +:10E090001628415A6FF65740E803A37ED29821F81C +:10E0A00018640D4837DB6A55C0F982410E9709673D +:10E0B000AEF2495A0682E318C2C1D0437084CB80C5 +:10E0C000FC3D06CF31073CC71CF01CB3C2D3E2E5D0 +:10E0D000EB75FAFDCB65E1F733BF17F5E00978DBA7 +:10E0E000A8438231C6915E096BBC6DD0DB47469573 +:10E0F000061AEDBFD3EF67FBF39E4D3FCC16759D1F +:10E10000D9F525049FFD3D14119D505D8141FF759A +:10E11000F96C133FFA575F617C77ED6117205F312F +:10E12000FE55F0BD4BBCBD56F8B1CB51FF33BD7DA4 +:10E1300015C4C308DF3B2093BDFC0EBC109E6E913E +:10E140008B77C86EA1C7D9865AF9176251F4ABD53F +:10E1500060679F1226349874269DA47D8B01F9DD9B +:10E16000414E6F49F0B6917DD1C5F5A3E9F77DBD6C +:10E17000DBAEAFAFD96EAF5F0D8BC7207D5D7DA7E6 +:10E180000B526CDC6BADF607DB9F6FC91AC1770DC4 +:10E1900034776A41B2B31A711DCB3550D14F5BF958 +:10E1A000B37B662E63EBD921F4E85B4CAEEB16BD76 +:10E1B000715D24E536CA87AF6FBD145BF42569E451 +:10E1C000F56D70F52D42FB20B9D5457E1D38FDB5A6 +:10E1D000BD0AF96B967E04EF955DF6F59D6AFDCE5E +:10E1E000F5328F85D67BDDAE65A437475A8F7B9796 +:10E1F00064A432E8B7874D7D28E48B49DF265F278A +:10E200006B80DB7BBFF7A5D6B3F97E83F291F6BFB7 +:10E21000F96C1E47699E85E5A9FAFDDBE7ECF7EF8F +:10E220009FB3DF6B428E3BFBADF4F6BB713F57AB48 +:10E23000C93A491EB2A3BDAE66A390A1C2B5AF3A1A +:10E240008DA698A55DD769B63B2C959C56BB3A79AF +:10E2500094F18E0B3BE3A93DF7B9FB91FF76BFBA72 +:10E2600008F5FB37FE49012F5BD7F13D2148237D9F +:10E27000AA2937DA2BD731BA4A513D3DF3628B5D7B +:10E28000C52896C6FFC64321B20FAE7BC493AA67CA +:10E29000FDAFFBE97F4C038687E3EB06FEA510E9A3 +:10E2A00075B7C4FDBF64FFB48BD9F3EB54B8229E9D +:10E2B000814E6485F3CBDB3F0F34A2DD27EDDA7F9F +:10E2C000398DDBFB5517CA65B3DD47B28BE665EDCB +:10E2D0000C7C9F7C504A4D92387C0D5387FBDD6F40 +:10E2E0003F2871F8F6B9523E846F578F3BC1DAADC3 +:10E2F000DEF52ED1ED790FFD388C7858BD4FB1F990 +:10E30000BBAB772969CF342A5FC51235A3C4F86D3A +:10E3100095E0D7557B57921E58D5BBF95DE4D7D50C +:10E32000FB5C36B9CEF0124B235E5F5262F5587F2C +:10E33000F487619DA1EAADE8EEB0564EE32E73334B +:10E34000BABA68B6BD1F8EFF61CEF0F1000628AEE6 +:10E35000B9BA77239F0FB8BE31F9F42DFC4BFE708C +:10E36000BD3145B19F3B9C806767521C72576E461A +:10E370003FCED41726BF7EE3C7277626D9BC6F3F92 +:10E38000F2879D4906FF8AFF797FE7B7D9BAE0494E +:10E390009F867268F5EEDF84C182F75A85FB61C7FC +:10E3A0001FFCE1033B18BF1CFFAD87ECBAE34FFC39 +:10E3B000D7789DADFBF8C31F8D41BB73ED13E78F7D +:10E3C00045FA5AFBD879636114FF01E935E5B1EEEE +:10E3D0006B8AF655DF27611006E071513AF6E7E0E7 +:10E3E0005E258DA1DB775EF6A43C0C3FABD9B396DE +:10E3F0004ADCAF95A487B07E33C3F3AA3D1BDE553C +:10E40000A665C277B2508E62C9D8268AFB7DF145D7 +:10E41000E75461E98AE9481F3040F2DFD96FF5110E +:10E42000B6AF678FBC8F27E01337E27FF59E8D7CF8 +:10E430005EC73EBE837F999341FF0FDBC715DFDFC9 +:10E44000812FF7E6D2BE8FB48F2B1FBB6454FFCC55 +:10E450009407A7C26F93C4E13A5B31D628C8578F9F +:10E46000FCE8811D11BEBFF50C21C77F7C623C0614 +:10E4700097DF700D5C8E7272E0098F762FEB73DD83 +:10E48000132F119F1D7FEC79B74E72128212D37B2E +:10E49000C761F04F1FEAC15512AFACFE4128ED092C +:10E4A0000FEDD3AA54439D1EA6E7AFD2F314A7FFE6 +:10E4B00055A9FD4BA40CFBB65B29E1723995477851 +:10E4C00059A9F7B9B5A07D3FA5D9B88FAF2E40BAED +:10E4D0001B691FCDF56BB8FE5996FDFC01E7DB917A +:10E4E000F8F3788F4795B286F6F7B8B00F56A7A421 +:10E4F000972003DF02ACE3F08E70FE68964E7AF848 +:10E5000081831ECCFEE6BA4FC5D7A75ECF67C3D7BF +:10E510009D8A6EA31B136F6F7F9259DEA7859C584F +:10E5200005C9BA8289C3F5950AF16461F110BC9DF1 +:10E53000BD0AC9F1B7772964A73BE5C2AA11FCF16E +:10E540005F29DCFE58B56FFF34945F6F1FF8B9A0E8 +:10E55000434EE7ABF6BCEA4E0AF99FB2CA7F1C2FC6 +:10E56000C37EBC2CE05EFD78E6F156EF7937E378A8 +:10E570006FA9C65711FEB7FA5C906443BCD5AB6473 +:10E580008C6F1C505CB6386E6768E6CB5918DF0C90 +:10E59000FB755CF7FA75C64B49B4435E7001D981CF +:10E5A0006AEC0D0F7BBF3EE4A773EFF5E1AB41B71B +:10E5B000E8E976079ED4689CFC603512AFE2B1D7DB +:10E5C00094CD1F7569B20D6E509345184FF955F1F2 +:10E5D0007FA938EE7368FF9D31D4FE39153A72D9A0 +:10E5E00078CF1952AC0D32C4A71CE3C7E729A05B52 +:10E5F000E9CC2893ADF1D5F0819B282ED102CD69CD +:10E600008C134111F4DE6F19F7EE560DD26C7EA813 +:10E610002B93ADF1554F73B3E1617014ADD54AD072 +:10E62000341B69FE71CDB23DAE2DE65F23E209B029 +:10E630006BF7EEDD6CDC3A7C57827E0C8F573177BE +:10E640008AEC98F3841CFC6761071F90E287D0CFA7 +:10E6500032F46D2ACA39A9749B8AF6C4C24FBAD55E +:10E66000E5167A5C58DA5684F472F853A531135DD6 +:10E670002D51395DB5156F28C2FE877D371671277C +:10E68000344AEB2C10EB3C34EE9A603F1B777FF161 +:10E69000355B2633B8EAA20A60BCA52EB26C4B05E6 +:10E6A0005B7FC11125E663F582A6A49A983A7C9E09 +:10E6B0009D28EF19FEEE453C32F87FD01AA5FA03EB +:10E6C000AD3A95BB5ACBA8DCDD1AA3F77B5A67534A +:10E6D000BDB7B58ECA475AE3F43CFC2D7F02E977FB +:10E6E0006F6B233DFF696B82CA1A95F3DB42810F82 +:10E6F000CBBAE91C6C497B781DC6514CFC39F15DE5 +:10E70000CB282E87CE0D241DF13D56E572C589D745 +:10E71000969620D9A53B25B0E173A6CAEDC8B8806E +:10E72000E3903771A1CACAF7EA4ACBC9EE81780CE7 +:10E73000E5F44E297E5B05E397A7C6CD8A5AE56EC0 +:10E74000249888AB7943F5F15D3C3E334BE5F2A963 +:10E750000EDA0E6531F88C4F40473A33D779A05A1C +:10E760002F42B978A08DC1538EEF6528B3D0993967 +:10E77000DE5C011F0433CBE921BAE5FC1F9D5BB6CB +:10E780000DE3C4CCF18C4DD2C9EAB6F5DBA69A7183 +:10E790006F9DE8D8A413C63F4F8D8BD030DC5F6CE3 +:10E7A0002AE6EF7D9CCE5BFADFA5F856740CD8E222 +:10E7B0008D1D4D32F9393B8EF2B8F489A6926D93D6 +:10E7C00059FB6A8637F4DB73169666252C74BD45B3 +:10E7D000D0D30E6F3C4B1B457F758A7666FD155F67 +:10E7E000E23B88E7BF9FF0937CA4E71DAED4652889 +:10E7F0001F5B8E7AF475129E37C493B86FF122F6C0 +:10E800009C8174A26EAD879616E4E70F2D37EBDB83 +:10E81000CEB0F0792866E7EB9D2DA3C7A54DB8775C +:10E8200022DCA3C4654DB8CDFD3851B764E01A1899 +:10E830008E07E7B8390B978C3AFFDDC8771EC2C345 +:10E840004ED5229F8A9A353A6730FB9BEB75F67757 +:10E85000AE77285FE1F4CE677A5D908BFBF9F0C765 +:10E86000E31F7D0E70CBE30ACAB12BD4442FEECB4D +:10E870004C68A63AA803F9C82FBFF373FADFD1F9A1 +:10E88000403EF1919A2A46BD70BAF375403C5E8DC8 +:10E890007A2B26C7ACF2DC2C7FA19A718234C58F0B +:10E8A000E888994D29076E8E66C2F3E0F845EADBE9 +:10E8B000D6F3A42D00DC4F4F7BE99C0303221AAB57 +:10E8C000171F86CA4D6CBCDD429E54ABDC2F9C7E6C +:10E8D00058EF5178FC48690859F028E2A9661CAB4A +:10E8E000036E068D7575AB15FBB1B9C9870DEEC406 +:10E8F0008B882F7754A7F3775724417C0522FE3D60 +:10E900004EC4E9CF1771C6FB5B789CB105E2179E38 +:10E91000817C7D4401F28F13136DFCEB5CE77E413B +:10E9200057FF24F4DFCF85DC2E55F74B596CFCD014 +:10E930001BE9036156FE4CC8F1C7841C3FB0ED5F74 +:10E940008A319FA023E18E214EC355FEB4C4ECD082 +:10E950005B67BEA15FCBDA77744F6E47FC6C58CB18 +:10E96000E3F28FA2DC67FD1E16723FDCDC793D9D71 +:10E97000DB09F95264E60B08795224E4C9C16D2F12 +:10E980002EDB80EB4B78699E16483F8D717D582BAE +:10E99000939D12EEFDDE0D38CE43AD061FB77BF71B +:10E9A000DFA17D7F8F375DF9AF18FF9FE78E25517F +:10E9B0004EA526D9E454B877DF8DD82EDCFBCC4D9C +:10E9C000940F23F0E0799CAD9735C9BAFD703AC435 +:10E9D000DA15F6A7D1EC66FBDAB3700A1BAFB45EAA +:10E9E000A670F51E297E5E08E9A1819F4367552C1C +:10E9F00069C3F6DD2B5E4862FF31CF364BB8ED3987 +:10EA00007F776F35E2EFFEA2D79EAE66E5645731A1 +:10EA1000D141F0A89EFF43C0F1E3D16BF591E9F03D +:10EA2000E08A358072CC73A74CE7F4F7DFB906AE05 +:10EA3000B1E65DAC5033C6C726BB3CFC3CEBCEC553 +:10EA40007D2867CDF3ABC295B55EE2FF67C1763E28 +:10EA50006B9E6399FD2BA4C464571E9D57F0732DC4 +:10EA6000D1BF40411B8F556F90391FC4D33E6BBE41 +:10EA700049F07A399E099E592E95E0698FD5EEFAB4 +:10EA800017369F3AEB52D2CBD06D87C3D98FC131A5 +:10EA90008BC3C1E133E118C74C82209BFFF6852F61 +:10EAA000E6237C1FD60DEA1B3FFAFF1DDF95D3132B +:10EAB000D8FE6C6D97E9FCFE40D5012FE2714B55F5 +:10EAC0008D9FDB3F9CEE72041FFDA04E26BE3D5184 +:10EAD000C5CFFBE19393741EE612EF73F20E78E953 +:10EAE0000C236904AB6762FA81F9C7925FC0705367 +:10EAF00099F4DBE4A7DC9263CB371807058EBC954D +:10EB000092A1F6E87FD71D91502F85C47974A97919 +:10EB1000BEAD1C8DE1FAEF32F562AB97CA9EE603FB +:10EB20003E9DC1F58B664627B42E7B5E8AA7096899 +:10EB30005D05CDFC9C6D8BD6B7DFCDEA45DF65A8C2 +:10EB4000D7D19EEB25F902DD3C5FC03CEF98B4C203 +:10EB50009EB752E4C8B719969FF519FDCCEB5DF648 +:10EB60007CC313B0650AD1435F896D5F7AE630B725 +:10EB7000E6ECE1FEE6E0B8C29F82289773393E3E9C +:10EB8000C7ADDF529AD05E0A5F58996D3D1FED7494 +:10EB9000713BE9D0EF3C80F1F80DB55E8AE398E770 +:10EBA000E8E67E6FC5A42BCC77687FC087F4B223DC +:10EBB0005242E5C1B9CFF8FA890E793E8047AC6977 +:10EBC000DDDC67163631BCDE9327938EE9287A2187 +:10EBD0001FCF176FAFF5D2797F38D0DF7B90D58309 +:10EBE0007FEF8EE1F9F6FDD5E946ABFFFA908BDBBE +:10EBF0005BDB5D425F6DB19F3F333ED88E7CE009A9 +:10EC0000C6E9FC52F68ABC09879F63E2237C205F39 +:10EC10002E9ECACB92A943F6F9DD826E760879BFA3 +:10EC200045C87BE738C54DDA0137DAFD2BB44A25F4 +:10EC3000035F4E68B1DB09E39AED7935854D76BA0D +:10EC40000FC50A1C76459AF498A98F37F88213915C +:10EC5000EE2B99BEE4F681265BCFDB9DFA78B76A8E +:10EC6000EC7391BD7B7A764238106F467C3BEDDCCD +:10EC70004302DF1F2BC601C46F408D1F72511E68F7 +:10EC80009CE48CD36E1806273038A78E0AE72F5DD8 +:10EC90009FC17E3AD5F9C09FE4F8F6E718C8F3B3F0 +:10ECA00040E45D84480E7784B8BFD2E1E27EC27B47 +:10ECB000625DFFE15268DC01415FF303D09C399F44 +:10ECC0008CC78B3E40C304DB8DCD9CBF8B160BBD28 +:10ECD0002FCCFCFE03173F679B3F61F479FE88F35E +:10ECE000B0F257AAF1AECB728EF384CB78DF658990 +:10ECF000537CE8D2383F98FB21F2734DFB699F6A41 +:10ED00007C64ED6F96390B553ACF3D01FE98C2F009 +:10ED1000F3643EEC0526479E94043E7FE7A33C2027 +:10ED200013DF83F635CA0FD4034703298CA798FB5A +:10ED3000609EC30CCA11D1FE4C3797278C6E026EB1 +:10ED40009A3FCECF0B214DF2A140D0CD0EDFD2DBCA +:10ED50006A5979EBDCB75EC67C85771EF3E908D784 +:10ED6000D6AA6361ABDC84263BFD98CF5D1F16D22B +:10ED700039FD37A544BEDBE247BA22036EECFFA49F +:10ED8000A4933F97FC8D42F6C893526A0A192A2A27 +:10ED9000D079C693D746539B2CE71D4E3B3FC7D730 +:10EDA0007FD76A5C7713B39760F8BE9976FAA0DDD7 +:10EDB00011B5F78FBB41D8D96CB98CAF2BC4BA63EE +:10EDC000AAA1201C332041E52CD0A964FE40A59BBC +:10EDD000B59F0E03F9C847EB02E3BFC4ED8CFF33C8 +:10EDE000BC197F8D781BA25BBBDE36CF1DF2041EE3 +:10EDF00042D04CE7EFBF685CBE71129BCF5D14241C +:10EE00007B38AFB1FD7A398CD97E7D1AFA9B79E2D5 +:10EE10003C1C9670FD6C9E4FE7D4DBF5B9537F7BAD +:10EE200084BDE11941AF3BE5E6487A7D85DBAED78D +:10EE300007E3C723C83F67FCF8D4F24FBFADB6184D +:10EE4000F3348C976AD1AE9BA752BC333C11AE8889 +:10EE50005BE8E1F76E223A56F2BC994D8C5F53673E +:10EE6000703E07F413024C01E179C2383985F93656 +:10EE70001B92A93ACC3FDBA04ED2ACFB583D8EDBB7 +:10EE8000B35B6BFC4D56BBF60F7E178DFFCD40F587 +:10EE90003348C7E5C1540DB97B067304C7F0BC4BBA +:10EEA000DCB7B334E8C773580F70BDCD38C2CBF5AB +:10EEB0004AADF63AE56726E0646034BD60CFC7DC52 +:10EEC000ADA6D6F9111F111E7F096D97283947E9A4 +:10EED00035D298CB5515587CB79BEBAF329C67FF6A +:10EEE0004C66EEB2F67FDCEF263BA73754A8A23D76 +:10EEF000F9A4BCFCFB68070EFCD603789ED2FBE9A4 +:10EF00009974AFA137F4A5054807BD1230CF96AD6F +:10EF10009FF10F4FFE8100C6EDC3E7198071CB81D1 +:10EF20005F40EC5E36BF2BFA689CF276C108C8B32E +:10EF3000593F1F7461FE4AECCFFEF7CF6574F74866 +:10EF4000B0F28EB361280E60FAFFB5FEC4A3086765 +:10EF5000C7987F6B423EEB62702A6487195184BB6D +:10EF6000324F26FE83BC606A127B5E7D38528BF97D +:10EF700068D56A054A1A0607DFEF577C892710FF14 +:10EF8000B55A436D366B5F7544277B6541F4FA4390 +:10EF9000589F7994D73BDC40F620F22F58F8AFFA0F +:10EFA000C3F1B4BEC3428EB7478D3E431A653F34AA +:10EFB000D5719FC39EC762A5036DA68D0E122E2B21 +:10EFC0001DCC667430D54A0786F459E8E07B42DEF2 +:10EFD0009E9A5F389FDCA870BE194EF7CDDE9CF27A +:10EFE000E1FC61CEBBA92A2782E7AB261F68B36E7E +:10EFF000D6B0EE59E68E23DF997C61F283E21BE402 +:10F000008B8B7C6C7F9704F5F333F105FA7156FA1C +:10F01000BF78043E5904038730E77E910AC92C2645 +:10F02000427E35E78DD2F116BA77E269D13C098E7E +:10F0300059E4D1C993BC6EC1A3369807AD9C3EBEBE +:10F040005F50F58E8885EF3A99FD8C4661971C8359 +:10F05000BC62E4BBE541CF0CBCDFF07094E2FB9EE8 +:10F060007813E5ADCD7A3B7035A3C33F8E91755CC7 +:10F070007C87BEFC21E2DF97038076DBD699D74DF3 +:10F0800040FFE48FD72626609C7323C3FF31326E86 +:10F09000526365CA85EA1FCBCFCBF4282F1351FEEC +:10F0A0001CC4FB94A81BA25D3FB563FB6C9387DB7C +:10F0B000BD5C0E6EF7723B70A3BBDB8BFC3550EC76 +:10F0C000A5F354E7FACFF5707E38D70355B108CDD4 +:10F0D00046F1960EAF52D7C3E350E973D9F37327C5 +:10F0E00096DD6BD58F66BF3B5A53F1D726E17A7612 +:10F0F00051995B9F023C37F09725758CDB7BD7419C +:10F1000022937DB8C3CBE304DE03FF40E74DB9A5EE +:10F1100031F24F23F56C3CCBBE2E6228CC62728656 +:10F120002DCB407AEFD0FD64AF2D8AD4BCA94E1B05 +:10F130004E07F8E798653FBDFFA3247AB91F477EC5 +:10F14000C85AE1F7D59678897F3A5ADC3D184FBB0B +:10F15000CC934DF8FA2052336A9E2DFA5749460F48 +:10F1600029E65F6189E720C933F83908D6F11C0424 +:10F170004B3C07C112CF41F03D9E8360FD27AD0699 +:10F18000D5F13C04EB781E82753C07C13A9E836042 +:10F19000B9AFB589CA7F6C6DA6F78FB7B6509DED34 +:10F1A00013D9E350968C2E6678EEBAC96DE0F976E5 +:10F1B000B7D88F8346492EEEA32FC2FD53DFB3B7D6 +:10F1C00003AEC717E571A5CEE8ED70252BBB6684AD +:10F1D000BA30E0E57D2848A54FBD0330BEB0534AA4 +:10F1E000366124EFC60DFBCE53991E2F8D5E5F93C3 +:10F1F000C3EAB76C78723DE6F74CD6DB62CBB5A1BB +:10F20000BA1EAABCEE614B7D42798FEA67EDD779D1 +:10F21000F6AF477E4638D0C8DBB2E1E0796DA58C09 +:10F22000984A80EE790C14BB53488F57E17E4D42CB +:10F23000F8B9FDFF65581F457F7A82EEAE443E6205 +:10F24000EDD39C7E4FAF7D371E66CD18DE6FB47652 +:10F2500072D569B5036594F1F0BD34CA381DB05E4E +:10F26000C33B679B91E731EFC817207FAECBC5F951 +:10F27000B7CBC7CBFF167C7BC85B13F7B232EEE58A +:10F28000FBDAE58BD7613C7460AA4C71855E171B75 +:10F290000293775B8A7F5DC2E6FDE6332A607CFAE3 +:10F2A000871ECEFF932684B85EFDB697F4EA051359 +:10F2B0007EDC9EC3EA93EE8BC5504F6E86981FE9A5 +:10F2C00024B985F3FB8FAA26E634B0E667CD782C07 +:10F2D00007E30DAA802385F79258BDADE3EA09182C +:10F2E0000FF9E3F35C7EFD54CCD3E3EA6BA6FD9CFF +:10F2F0001124FB82618CEC87B6A84AE7F7723E2F97 +:10F30000DD2EED6FB09D9B29E82483C7FDE92C2FEE +:10F31000F9E91F7AC47DB63EB22BDCBE8496CD9E41 +:10F32000772765E2F7F59A3F8529FB9B839574BFA4 +:10F330003659AE527EF6E6721EC70B842E4DA13DA5 +:10F3400071DB7E1F970F412FE569A5CAF71EAE89B5 +:10F3500060296BC8EF2963711DE15D9335CAF762BF +:10F360007FA3F74D11CAE7DE0C625F9A64F2173B88 +:10F37000C6FCF95FCFC673F1AF6B3171C788F22558 +:10F38000C90492F1BEEFC08100C2F3B7E6FDA4FE4E +:10F390007501D6BE7DB916C37D98A6D5D4611CB1C2 +:10F3A00043ABF1225F05A6D67A97911C1ACC67A6CB +:10F3B0007B70EDE5DCAEC5F7C897D00E87F0DE4B6D +:10F3C000A1906581EC4A09EDA18E7A0A2F61BEAF4A +:10F3D0002D3FB33DE742CA7F5716E5109C1D60786C +:10F3E000B17DB25E25FD5518F4A6D1DE2B34E38B3A +:10F3F000989A6CF1377257D8F39BF39B54DBFD8FCF +:10F40000B1097B3D4FF80F798E3C68C96B9E23DABA +:10F41000F1E45C6F6EE4DE6C8437172F34EBC3D7F6 +:10F420007347A4B201D759A8F909EEA8B6AE1AE5F8 +:10F43000D758686E43BAFBCCF03AE09C56DEDE87C4 +:10F44000FB3E4D57E9BEC3D930B00EC7DD2CE8BC3A +:10F45000ABD8AE4F7FE851C43970CD1CE4478C87E0 +:10F46000252DF31727FD90B4CC37B12BC7569FD469 +:10F470005D606B7FC6F612DBFB29A9336DEFCFDA37 +:10F480005569AB4FED9D6B6B7FF6BE1A5BBD227D60 +:10F49000A1ADFDF4C38B6DF5197D7F636B3FEBE58B +:10F4A000E5B6F773FAAFB3BDFFD21B6B6CF573060D +:10F4B000BE656B6FDAD74EBD38DDFBF9EC6A0FDE47 +:10F4C00007B3C50FED76BBD3EEF6FECF7A7D1DCA2E +:10F4D000B5B09BE85B453DCEEA6B6EE27E8F777EF2 +:10F4E0004C47B93245D063246818B86FD5612FE90D +:10F4F0000335C8DBA9C10564778CDFCEE4D174B4D1 +:10F500001661F07D00E5726B325EEA1A82DBA77548 +:10F51000D3DD86EA701DC5DFCDFEAA66402284F3E6 +:10F52000E93CFF887995D8CEA7B3FE96753C29CBE8 +:10F5300074157C80F967F75AFCB391FC31A7FF750D +:10F54000BAFED67819FC58F648F1662CCB9B9FAFD3 +:10F55000C1343CE6875DE565FBB3D51D6FEA61E329 +:10F560006E2DF1F3F332E1877515F7125F0C14ABD2 +:10F57000A45F40D5CB175BE260B709BB32E0BD8B1F +:10F58000FC40B564F6611DF1DEA6527C62B3C4E3B3 +:10F590002849B60FA8D776CE7DE3DD5BD8736F8997 +:10F5A000B7D0CBE451ECA0DBC073D23B045E4BB4CC +:10F5B0008A1A667131FBA2E1009693756667B0B254 +:10F5C000AC6CDB012CDBBC2534DF99B1876B50962A +:10F5D00078E773FB4F99E64EADC3FDD3381C23D1BA +:10F5E000999AB39D9F6795AAAF23BDA1557E521EE0 +:10F5F000A2031FD2814425D18F2F1224BDE1C30362 +:10F600001FACAB522AC0DE474A0D09F333AAC3DB55 +:10F61000E97CCE97B6DBABCC2FBD0DF11AA9B7EFC5 +:10F6200077C0BB93E06B97789CB62B5B7FB686C1A7 +:10F63000DF9557928331168C633458E4CD76A14F11 +:10F64000AFF0C9A6FE2779E343DEC81BB27718FDE9 +:10F650006F9727227CDD8072CB77733720BDFB3418 +:10F66000B69B686F7F2749F46FDABB3708DEAA2D97 +:10F6700069A473B1F7239564DFFA5A7E92117FBEB5 +:10F680007E058CE923E3353C7907E97B2871EB683B +:10F6900057B4E86EA327D339A047F81F981F82F00C +:10F6A00088FC902E810FF35CEE7D336F4A9C07DF60 +:10F6B000900DB6F3C11BF22AC78E668FFB987F9818 +:10F6C000B0C0BB91CD8378E9F8A4A12E4EE784C0E9 +:10F6D000EFB37D5ADE43F7863F59AFE339E62C811D +:10F6E000EF733D1CBFE3DD407EC27918E7988E5E64 +:10F6F000E997EB902FCDB8C89BDE1CC27F2C094A3E +:10F7000033D92B2E536FC927CF269875B719CF241D +:10F710009397EB35F6EF7EBC7F31B1CB7EAF69526C +:10F72000B7BD7EC6767B7D4ACA5E6756F311B40BC1 +:10F730001A80E3E7AC5DF6F70D663CB096DFC7F0E4 +:10F74000B2994F72FD6BBBFF0A42FF9B71D771BD2F +:10F75000E96A14AF456BED7AB540E8F90287FEAC73 +:10F760000C29140FA83E1C3984F6A319A779C5A744 +:10F77000DBE29F66BCC529CFFD47B7017B437E75A1 +:10F78000C2C3E31009E6DFB41489F8C6385EBA14C0 +:10F79000FDB9A564A7359F81F2E99037F1B197E2F1 +:10F7A000CEF6FB12EFD5A9BF90743E4FC232CF8D7B +:10F7B00065C90BF8F253947F62C63B4C7F5E091A11 +:10F7C000711C6F73EC85E683186FFAAD07709CF3BC +:10F7D00095670FB7B2FA9A712AE54B6AB3567CDF88 +:10F7E0008FF1427CCFEAD5C5FA58A2FFA75DE4D7D6 +:10F7F0006F10F46CDEE331E323519FD03F3ED32EF4 +:10F800004AFA453EAC1FEDDCB37631D96CD3733C7C +:10F81000EE66C6D7A6F6DADFF78294ABB1FD3BBB46 +:10F82000312573BBCA08565BE2EF678AFD9AB6348E +:10F830007DFB5256DF03A94AFCAE4485A08BD8213C +:10F84000FBBDB13120D1FD82314794588AB59FF676 +:10F85000B8FD7DB9E35ED999CE7B668E787048811C +:10F860007797B1F9B6E8CD12CACF2D4B99CCC2F932 +:10F870007D22CF78324C46FA3B5F09C6D288DFDF63 +:10F8800028A4373CAF9EF1D232D4E7CFF33C166DBB +:10F89000A2BEAD96D5B57F55483F6901A8A8080E10 +:10F8A000C58FBF773206EDAEA178D46EB6AFA59303 +:10F8B000D0BFF602EA959FB0FDC57A2FF3C7B1FE1F +:10F8C00008F3C7B1DCCBFC717CFE53E68F637D1F70 +:10F8D000F3C7B1FC47E68FE3F3C7993F8EF56F0698 +:10F8E000AA1738E359D6F8DE503CAB5F32E359280B +:10F8F0004A3E70EBB4EF8371AD048F6B9D7A1CC3ED +:10F900001C87E286C3C611F1C3776EFAB707F09E73 +:10F91000F5CA19EBBAF0BEACD765C6CF789E84990C +:10F92000FF6CF2DFCABDD7D3B9B13BFF4833EEC796 +:10F93000DEAA207D8BC8ED4A68281F9DFE97E977D7 +:10F9400039ED5FB374EA233FDA01D3D14EEAA6B8AA +:10F95000CF261794D1FD59C91F43BE70C62B4D3E0B +:10F960007ED15792F1BED4601EAD88CF7820E5C518 +:10F97000B89A5B12EB14799E24C2D8109B919F2DEC +:10F9800079C9C1F234C539824183EC2F89D96564C4 +:10F99000A7698928C6A13A47C89BBD4FF0675BBEDF +:10F9A0009BBE37D199CFF3046A8B6251ECBF3E7F87 +:10F9B00066D49A476BE6F91E0ACDF4F65BC65B1374 +:10F9C0002A19554F294CAFEAA3E855C5C3F3DCD734 +:10F9D0001F98E3C5FCE54DC1E57D685F6D8A46E88B +:10F9E0009EFBFEFC99647F0CB68FCEA63C6725C8B3 +:10F9F000ED5625EA25BB55C5F5970FB537DBB5FAAA +:10FA0000385D31F6A3F85C20D84BED3C6A9CE21FD0 +:10FA10009E08D0B996C7CBF30A82CCBFF6DAE2AB28 +:10FA20007CDE1611F7DDA427E2D86F5354D5511CA4 +:10FA30006D2AAB243CAF17785E9F67EAFD18D91B8F +:10FA40003F137836C7592FFCF5F54D6EB2BBE22D4A +:10FA5000D9466D2EE56DEEF1E1F8C17BBD9807EF5B +:10FA6000CEAF1A75DC0338EE8CD1C67DB5A6763ADA +:10FA70008DFB331CD71D5AAEE1B8AE11F2F39F13C4 +:10FA8000707E5EFB92614EA3733130F56D2A6A3D44 +:10FA90004F76967EB413A70FEFB752EF5F80F9C190 +:10FAA0002A24EBFCCAF0FB0DABF6F1EF556D55FBCC +:10FAB000C8DED9FA8994F19EC418BF24CE6B07FD25 +:10FAC000709BBD5228F8A950BCD7D15E2946BFD241 +:10FAD0006E5F4C3F6CAFCFE8B3D767BDECB4578CCB +:10FAE000DFA0BDB244C8BB3E269F7972C5808A7232 +:10FAF000209E4C5523DC0DD0DB86E7992E85E7113F +:10FB00002C11FAEA22A1CF82FE6C82BFB0C96FF33A +:10FB100013CDEF6E1489F1C7D51EBABE1D856BDCFF +:10FB2000B47F74F22FC72D7CA49AC4A4C30E6A308C +:10FB3000ECF7562F72D8394E7BA85AEDA1BCCC02F7 +:10FB400047FCC13CCFC475E2FD5DE7FC9F755E7369 +:10FB5000BC1D4C6FA1BD627ECF80BEF7C5FA8F532E +:10FB6000D3522C48795E940F58B8168C9E0C747C36 +:10FB70008ED8F761784B9E4B783B4F3C2B08F2EFC9 +:10FB8000A514D42A29BD98E789A13C59BC82AD8728 +:10FB9000ECE593745E6DB6CFC9EEA5BCB21DF5124F +:10FBA000F71F93407688B9CF3B82FC9E4DC33952F4 +:10FBB0004AC6FECD25343FC15532B4BF0C4FC738BD +:10FBC0009E781EDAC575F6FB400D0E7BC3A4878BAD +:10FBD0001CCFFB7DDC2F32F9E09D392F4F1ECFE08B +:10FBE000582925EB02CAE9EB490B7FB84E221FE2E8 +:10FBF000DFC7D052883F0E781FD5288F20BBFF2E3D +:10FC00006024D9E08764ED3C807FF60F9C25B17AB3 +:10FC1000E3A6B33BBAC6E1B5C6811FA151E6D950F0 +:10FC2000757EDD394375FF2683EA11310F732D92FE +:10FC30007CBF2DDF3760F0EEC43C02B44B0DD8A67C +:10FC4000600EA6AC6D8B150FF5CBC17ED228FDE200 +:10FC5000B04DCDD02F68F663E8EA34BF0752822555 +:10FC60007F2F0B78ACF3AB88374D0FD27D9F05AA61 +:10FC700086E73F5F148E31A75A7702B6B9260EEF9A +:10FC8000C7C06E33E19733C39FC2F7D6F95DA3C0F7 +:10FC9000FF97C6C7A9C6738BF79F193ED67CDD9820 +:10FCA00091D78B70B9E8BB1A7A50B68C73DBFE8F94 +:10FCB000287EAD5E06749F4775195A8CD179B97646 +:10FCC00027F9E16A76AD8676C04656473B60636F9A +:10FCD00037C5A9CB4B6FEF42A22F4FFB01E5C154B3 +:10FCE000D0B2F7B071A76A2A66EC807ACE2119E308 +:10FCF000DEF015A0FB2459FBFDFCFB17C573EF4399 +:10FD0000FF283BDB4B71A040F6CCFBB8B1CBE3C185 +:10FD100026FC81EA23351827571B2086ACA84A29E0 +:10FD2000A846269B02740EE137F6DE88F73299E288 +:10FD300023FD44DF8440BD2AE2E26339C940975B7A +:10FD40006B403F21F98C4AF1F7B17864C188B2BCAD +:10FD50003C671BC2539E600348083F8F6B4D4DC8E4 +:10FD6000B1341BBFF25DDE0F7EC9EF11305FA2F12F +:10FD7000B1E0105E4DB93256C4CBA34BEDF164181F +:10FD8000606B66FD2B7FB9F87E8C278C1926BFB976 +:10FD90007F6D7E6F27EB5D883F46E79A76BDE11762 +:10FDA000DFB5F03BBE97303968BFBF37CC6FF84E38 +:10FDB0009CF48007625E37D9174BC96E30FD911DE8 +:10FDC000D810E3FFE3807FFFCAD97F26EF0F51EE03 +:10FDD0009F78FCCCCCAB64EFAFF31B9417E4617558 +:10FDE0008647C90DDE7CF6BC40E67191360954ACFD +:10FDF0000FCD97A6F3FC0D52AC2B260DF9BFEBB53A +:10FE000018E519C0DA1C9BBD6CE6ABAEB9B6786CD0 +:10FE10000E2BB386EE0D69488F6BF24AC97E0EE752 +:10FE2000F67F0DE5EB47FE5BCFF7A23CC53C87B9FB +:10FE30004C286FEEEA483279EBF9B010748B5DE62E +:10FE4000519B290EE6F970BCED79BAD57ECFD0086A +:10FE5000CAB5384F514027BC5683D68EFDAAC17E05 +:10FE60009FD0F361BECD4E1F1ABFC8F63CCDEC1932 +:10FE7000EB772C461E3F007A9975FC89238C3FD97D +:10FE800031BE9671FCA171736DE376A83C3E9A8CED +:10FE9000F869DF9DF64055A0A63890374AFC3EC071 +:10FEA000E3F71BA2CD14BFAF01C6F08C4ECEFDE42C +:10FEB00098C2EFBD01D96D50648FDFD708FA95194C +:10FEC0004520FD9EABDABF1F361F9CDF13B3DB431B +:10FED0002F21A3B079E550551FC5F13F0AEAE87F0D +:10FEE0008D642FF7B502C58FE707FA6FC073EAFA82 +:10FEF000C0F75D1DB3459E6C01C0DF04F69E8FF711 +:10FF000003FBC4BDBE8E884C7889D78CA57B3AE6AE +:10FF10003871374C42791897797E02FD61F3F7E525 +:10FF200015D8F21CCCD2790FB4C190E2A516BAE96B +:10FF300093195EADF39D57D8A358D611F7C00C9A0C +:10FF40004FD8B983F38DF97CF33D2FE24EE67C0D5B +:10FF50000BECEB6B706BB4BE06C1BFE67CCFE3FA73 +:10FF600032E0F794F3C99C6E06E7BBC0BEBE068FB5 +:10FF700046EB6B10DF031E9C6FCCE79B6F83AB39A6 +:10FF80008176DB3689F3FF77373FDE81FBFA7EFD32 +:10FF90009A28E90361175F841D58BB8B543EDFA28A +:10FFA000226FAACD32DF0E26070C910F6F78307FBB +:10FFB00043A37AAA354AE5BDCCCE36287FA38CDE92 +:10FFC0003FD01AA3FAAED6D9549AE394CDE6DFA770 +:10FFD00099324FCA686FFF32C0FDC66DF9DA6557B6 +:10FFE000A15EAAF6F37B93B3BF0486C5FE6506F156 +:10FFF000011F9EBF5C0A15A8DB266FE770476AC722 +:020000021000EC +:10000000A470FFFC1587FA5A59DDE372E9A84F196D +:100010002FC433F9A98703DC0FF7B8B9BC87B9FC43 +:100020007B878B845E01A55E72213E2ECAA6F3FEFD +:10003000C54B8C90C6F0B644927E532AF414DE6F02 +:10004000B9446C95D3CE8FA0C660E3460C2585DFFE +:1000500031BAA4E87023EAE578E862F20FE2AC6313 +:100060000E1BE712A127AB5FF500E63BC0F96E82DD +:1000700063C912BB3DBFCD97D6D03ED9561101DC26 +:100080009FC5F5F6F71E37E7C3B8E3FB068B4EF1C5 +:10009000BD03FAE656867C53677CF24040E4AB8AA7 +:1000A00038E40928BFAD165F164546FDDEC14D0197 +:1000B0002E9F4CFD369C8E393C7F10726C47EB3E78 +:1000C0008A8799F015A82909E57561D33E5B5E130F +:1000D000432C19C3661C1E943D15E88738D7B343DB +:1000E000DA933FDAF74D0A407DBDBF4C7CFF531ACF +:1000F000BEEE5703F6F8EB0998F75C2964E21F1E81 +:10010000775D745889B5E9437831F1F0FFCD475BED +:100110001166563E77DE0755DC7F2BB27D67D3FC38 +:100120007EF0C5837515540B3D5F749D9BEC1930B3 +:1001300006CA91EE8E9C13E0DF7B33ED97F46F657A +:10014000B45FBEF8F8C6385B7EA71877A4FD72E6E8 +:100150001B5AEE8B0EE5C3637E89C4CFB10A30CF44 +:100160002DCC9F1FB3DB99B63CB7F5FB1F9430CE67 +:100170007717E6E359CEAD0B993F8FF1AEA215F696 +:10018000BC3A275C665ED5E07DDB794BB43D3A7DB9 +:100190005FB11B3F58D3B53D19074B1EA5798FD0D2 +:1001A000F4A79DF7079520FFCE5E54DCCB70C68385 +:1001B0006F94935AB18479AB296F352BA7E72466E6 +:1001C000E195F61B95641D3E57C6CE6D423C2C6DE5 +:1001D000F9760CE3775A6EE6B8F452A1BF6B829CB5 +:1001E0006E8EBAD2E3308E7D4D4E4D4D302F43FB97 +:1001F00096EFD078F347F86EFDD7823C6E7297D0B9 +:10020000E7CEF74BC4FBAFAE94E93B183E08A5A47C +:10021000623C37EE9E4DF7F656ED8865BA1FF75CE7 +:100220003871B1151E5F29BFA70DD03B07F1B5F19D +:10023000E3BB7B1F62A8CCF93848723447E1E35A2C +:10024000FA7F2D386378FF273F7A91EE373F89F7A1 +:1002500059E6E2F6DDB300E3DF5BCD3A86E4B19E1A +:100260006DD6BFCDDF0FD6672CA866FDB7220D3245 +:1002700022FBFD960B3A51CF6E95407C87BC6E01F8 +:10028000FA875B5DBCFD3F89F7F32F7CFBBEDB503B +:10029000DECF74931FB855D823267CFD417E1FA95D +:1002A000FF14F8BC45EC5B10F119F94CF8BC2513B0 +:1002B0003EFB738CEF209E7C9849C140F07DEC5D45 +:1002C0008BF9C6FFD00AB1ABD81AEE8AED7DF036B5 +:1002D000A0FE1D99F019CF313AF17970E5315A5FDE +:1002E000A83488EE0D6C9C05344E06386E1D6D5F8B +:1002F0009FCAE272EC93102F7384FDA778FAA2785C +:10030000FEAF557DEF068DC991CEE2EEC64CF47D71 +:100310007788DBE5D923C4AB1F15F8FDBD16DF894F +:1003200070B76BB7D37758DD12B71B36CEEE07C95F +:10033000D2EF85106FCFE07E00E176CFE1DF470D91 +:1003400031BC638259A88AC3BF513F0298FF1D8AFE +:100350001EA1BCD050553FF13B5D6928E07485FE7D +:100360009A57D8678F6E59BA00E54C8E62D2E1F188 +:100370004EA41B65A84E74D493C3FBBFBCF578276D +:10038000FA733B99FD82DFEB4816F0BC11E7FA9E49 +:1003900014F0DE13367E8EEB1B864F4FFF7DB7B118 +:1003A000FE5B27F17B39F3E5BEC62B912E2F0C9215 +:1003B000FDC59E375ABF93F307416F7F0872FB69F3 +:1003C000EB475E7AEFDC8F91E8F5D702DF9F835E23 +:1003D0007F9D89DE18BD1E71D0EB0790995E5FC9C5 +:1003E00044678C5E8F66C28BB3AE80B11DCF67D57C +:1003F0003F2FD885E3A95F9EB7FD21562A7FBE39DE +:1004000049BB19936CF750CD792AA4C45B418B7C0E +:1004100037BFE34D391099C69D35733BCAB1D31828 +:10042000F704C2ED1CF7208E3B03E54B3091E9FB4E +:1004300046DF0FF1BCF107C5BA46E29BE74EC13774 +:100440003F0D713A607CE30A9D06DFBC2EDAB37D76 +:1004500008854E8B6FEEA4D257CAF986AE2BCF1DFE +:10046000CE3700AF74A23CEE2CE67C313EF44667FA +:10047000B2C8C247F011BD5786EA24BF4D3E7A3B51 +:10048000F411F191B37F7884EF594D1A5C47BC1495 +:10049000D76D9CA5B5F3FB38FDA4B77B6060BF8723 +:1004A000F26C795EAB3F9934B8D9D007F87DC4A916 +:1004B000821F77A20F867ECE4C116752FB60716857 +:1004C000383F87AAD255D6EF0D1C12F37F1A8A57F0 +:1004D000E1FC3DD03F05EDAF91F6698E98EF7BD9F9 +:1004E000C69C50063A3F951EBA3CC4F3372F17F30B +:1004F000E67CEC6D46FBD3C9EFF357FDE39B0F8C15 +:1005000032CED744FF8B439F9BFF2F0E65E6FF251E +:10051000213BFF57E1773A33F0FFD74299F97F69E2 +:1005200026BC7C017E6F0A65E0CBEAD3C4F78F045A +:10053000BE7FF405F1BD51F46FFBFCF86E1B01DFCB +:10054000EB108FA781EF8D23E07B5388EC95470854 +:10055000FE901EA43876D72CD82B956484E376EBD6 +:10056000385E9D8FC3F0FE81C4E87EFE9FBB62991A +:10057000BE4FC3FAFD83157EB3DF9C90B8270DFAFA +:10058000F5E89FDFF5E520C5FB997EBC27F497953C +:10059000FB0F8632C8FDF93297431F6FD9DB89FA0A +:1005A000FE0B8CFF58263A5B2DE03E955D7058D0CF +:1005B000075BF7E3A1BCE1F2AF47FC9ECA3DE1C493 +:1005C000C110F957FD0B515EEDFC568E84F1A82247 +:1005D000232DA19FF073A1C72A433ABFCF20FAED84 +:1005E00054D312E6B3EC6CD624BC6F6419EF97A118 +:1005F00019238FE78483C1D7172279673C8FFDE6E3 +:100600000CD9819FC94E6ACC367E1B22BB2DFE0AB7 +:10061000C9ED33EC72DB5C871CEFA6BC17DFECCCBA +:10062000BFF7F2F3A02AECBFF86B56F97F34A409A8 +:100630003F948FF759F50F83EF9D10D72BFF8DA5B2 +:10064000133E275E4E056711EA793EDE4799F49422 +:10065000733CD36F35F7C98D3AC912D7718707ED4F +:100660005E5718E549874CF790160979B26876B657 +:10067000B0DB353F8E7F978893DFB5E2F66A3CEFBB +:10068000EEB959AB4014143471BDA7AF184FF14FF8 +:100690002D2CD9CE93CD72B0BFBB770A7E9F9CCD57 +:1006A0001BC179CF9D0769F41BB3D06EA078844637 +:1006B000BFF795E3E98E62FC74A3D4DDB81CF5EABC +:1006C000C220BF57125D728AEFBCF1F893B96E88F1 +:1006D000569DA27D1BB5D702DDF49D8CD36EEFE94C +:1006E0006ECC945F32232C9B788D8D8AD76884E200 +:1006F0005A267E87CFC3F7AF3ADE2C21BE435592F0 +:100700008657AF428C4ED05E924BFB289FE92B550B +:100710009C5E80F925A37F67A3D3B4D7CE0BE77D7A +:1007200071B8CC7623CF27DA39EE2BE0B917C5673D +:10073000835C8E5143567FEF706EC6B8BF596E68AA +:10074000D58A549775FC148F430EE64FC7A2686F85 +:10075000B500A747887AC90EA3EFB95BF6F39A30C4 +:10076000CF73DE99155F1E26F862F4FD42D0B4D334 +:100770005A0FEB772DEE2BA8AC5FE8F4FB8D5C9A5B +:10078000BF7317D3E396EFA599FC3A369104FC1E8C +:100790008DBF1C3489ED7F24649E13723AB8336890 +:1007A000D69374481E2FEDE679F9BA49275CAE68F6 +:1007B000815E43AE00D81EAEBF203A858D579A8821 +:1007C000E2A7F759FD2995E42FAF03D43F7588F4CC +:1007D0008576A614637A4AAD7BEAF038E057A5C85F +:1007E000CFAD7B8AE4DD601DD298CFDCE31FAC1B6C +:1007F000DE28AB970CD69358DF29F4E4F670DD536E +:10080000EDC4FFF13BACFC512DE8F02F4D7F3D7A5C +:10081000BB86F70C925195ECAA8D0E7AF8E7B09B47 +:10082000F05FA525EE477A5874F3808A5757BCC508 +:100830009110F2C384E80749FCCEDE8479224DB5DD +:10084000947FCFA127BA96F8B207F705785A02C667 +:100850002787F62795797FCA52B43F7E9DBF97B10F +:100860004EFE368FBF05CA383F6B1E1EDFDB27E406 +:10087000C9536145945CBE6645DBC99FF2D6C91475 +:100880003FCEAA936D7A837E298FDAAB367AEBCF8F +:10089000491C0C5BE523A4E3656C1DFE29911C3CFF +:1008A0007FA92E53D7A2BFFD7D61FFB17DBA97E42A +:1008B0004545C49FE0FBF64CC67D137839D5BEBDD7 +:1008C000D89A88D5BA46DEB74B2FE3F9F4CEE7BF06 +:1008D000137838DEF89FDF437659E91DA0EF7E7765 +:1008E00095B6511CD68CBB7AF656A70BF5A17CC0E9 +:1008F0007581F03C2C9DF3BEF8C9DF6B744FE42387 +:100900004FC6F324258BE3F9486B23F5631B4CBFDB +:10091000D372052E85E7B1D9EEF199F7112E074E66 +:100920000C4BE2CBBE82726879A342DF77B802EC4F +:10093000F914979B795F2D667E1CCFFB4A40F60227 +:1009400064C36549C7EF4C406C01DEB71FF6FB136B +:10095000E27CEBEB8EBC89AF362E8BD58A76EFD35B +:10096000FF5384BF253A97BF4B62FC3B3F97C42F90 +:100970008BD55ACEA35FFA54C99837191FC4473C88 +:10098000563B69383E96C725B7A69F1A2FA78B8777 +:10099000656AC5823C7D381E9CEB6718DB8A78FE51 +:1009A0003AC333DA9D23E183B5A3FD78E932857E2E +:1009B00077668152EFC273902B1B243A6362F80D65 +:1009C0008BBCB8FAF32DF03AF1E8C4D7954F00DDAF +:1009D0001BB8F2BB218AB7BD60E2277D2E9D5F98D0 +:1009E000E72796751EE3F95B1AAD73F1EC8A5FE0B9 +:1009F000F71512ED4CDAF2F5DACE019733CCE3BD00 +:100A000005B6EE6323ECBBED3CD0099F137E9FD06F +:100A10002BCE733150D3E5A807CFCF12E763D32095 +:100A200026CEC7B2281DB734B3BC757E97CEA4B30B +:100A30002B5A1A06E7C5F125480CD635BCAFF5B4DC +:100A4000B2F512F6F73551FEFB87F1CB723BF0DDC4 +:100A500022307F97C8A0F3A62B04FE1A98C787BF41 +:100A600099762E134E78AEB7C8F0E941CB3ADFEB5A +:100A700096EAC43DAAAC2553B15F72BF326D38BC53 +:100A80006BA2FC770E191D7E60A543DF24FEFD5985 +:100A9000275E4C7C350DE165DA67C1CBEF5171E61D +:100AA000D1790DD9B9039297EEC39BE738ECAF49E2 +:100AB00037139DB764150B3B80AFDBFCCE1740337B +:100AC000D9F74BC57DACA32E687C38C8CF752A2DCD +:100AD00072EB3B39D5B76459FC63F35CC7FCAE9449 +:100AE00049CF977B836985D3A1EDBB5143794C09ED +:100AF000CA6352B256E8888F2E7C3587EC9EAE2CA6 +:100B0000F49F03FCBCCAF7F4A35D97E843FBB7E985 +:100B1000AAC7BA67B0BAFFEBBF4ED2A07A0EE12DDA +:100B200024F6AD5AEC9B099FBF9C3FB7EC1F8F9FEB +:100B30009589F899D8C791F484B98FE6BEA11D852F +:100B4000F4EB2B53FF9CE9F7FAE050D500F2692251 +:100B5000AA520E5D427AAD83BEC705FA4E3C7FBFF6 +:100B6000A2C565FB9DA604DED3C7F61B7DC22F89F7 +:100B700051FFE5F9BC3F9471BB7190EE93ACBF257A +:100B80000F08BCE131B86FFDAC2FE689B1F1C6A00A +:100B9000BE872ECB3C25C3E71D713C473F65F0DC8B +:100BA00024168B59E4F5BE2C6EDFBE17ADEA9533E3 +:100BB000C45FCC72B937B748B5E4871DCBF736664A +:100BC000FA7EA939DEE0F7E506EDC481A70ECD1B5C +:100BD000B2133777BC65B713936F7D213BB1FFB676 +:100BE000B79E6A67FDFFF43B0FE9ABF7EAFCB40F71 +:100BF000B92DE7C17FE07D5B157F0390EC7BFA3E6A +:100C00008EB7A590D623A90C73F83B627A4C427C30 +:100C1000BF891FF3C5B88A0EE910032E578D498886 +:100C2000AFDB853FCAE86C8AF53BAE6F66713BC3AC +:100C30009CC7E38524DE3336C76574D04679A5F5B5 +:100C4000407AC43C8735F9D91CE74496DD0F3E0D48 +:100C5000FE3D91897F9F959BFFFD16B45F9F5128B4 +:100C60001FF46FA337D1F34B5BAEA4F2B2966BF9CE +:100C7000BC62BE6F4A8993384E5FE3AFFFF64646CB +:100C8000AFABF77AE85ED9CA6FBE792BF2A7B7850A +:100C9000ED3B6BFFBFCC8E383800800000000000B9 +:100CA0001F8B080000000000000BE57D0B7C54C585 +:100CB000B9F89C3DFB4AB2BBD9DDBC96BC38E11902 +:100CC00025C44D801010EB86575109049F51026CCA +:100CD0000884008104A4BAAD1436246040ACF155F8 +:100CE000F1AA7451ACB657BD4169E5B6D16E442D39 +:100CF000540AB1BED00A06A516154DE45156ABE50F +:100D0000CEF7CD4C72CEC92E84DAFBFBF7FEFEF196 +:100D1000D77ECC9939F3F8DEF3CD37676F5C587521 +:100D2000FF986442CC430D4E8910D29C45CA5B6D3E +:100D3000B4DC209501DCA898A7EDA4B0CE5132D246 +:100D4000398690B3F0773994276399781C0652441A +:100D5000C84A2BFDB742C89943B77BE6D3FEE26D84 +:100D6000362F7D42FBC9B9CB40CB64AF4C1EA740A8 +:100D70004E20F3CAF228B43038D069242405A001EB +:100D8000611A40DAAF3542679304EDBCDE7A3ABEB1 +:100D9000D518244E8011233E374B747E79BDF31154 +:100DA00050F4678DC8848C82F1F4EF9BF139AC0B61 +:100DB000DE9793D83CC4FBB9F0FE1880621E096C24 +:100DC0001E49FA7E1CECB94CEA014FFA7934254EE3 +:100DD000CA73A6009E7C230112D2692AB31332D7AC +:100DE000F68783523E85565B58A690044CC73B73EA +:100DF00009FE9D1D04FF5FE1FC78042112E994CEF9 +:100E0000D2A1677C23850752FCC595C8A17539140A +:100E10004ACED2D1A369B3129317F0D93124D93E67 +:100E20004835FEE540453AEFD78D4E3BCCB36C8A52 +:100E30005C16CAC3EE53AE857EA654156D62C359C7 +:100E4000492A21F3D8BFC9EBCAF6E641B43E1834AB +:100E50007987523ACEB3064330BF79C418ECB462F6 +:100E600013E9AC84503116F1F7E87CE74D967D71BB +:100E70000E4D3B7296CE9334919787D0FEE74A7C15 +:100E800080202DD3F70EF3E207934F5E07CBE824C3 +:100E90004EF320DA7E6E67E574928F5536E0A785B3 +:100EA000BCDDBC80E9684FBFF47F95416D797E71F0 +:100EB000C1AB940C142FA169A381CF2E32209F5572 +:100EC000356BDB2D7CFF8A4F8803FA351EEDC13769 +:100ED000CC93DCCDF8654AA353A1781AED54B03C0D +:100EE00063F24793092DCF24E43AE877E664D919F1 +:100EF000A6AD37070CC44727BEDF278724BAB6FD47 +:100F0000B99D7B2F07BC159B94C761ADB9E4CE6B2F +:100F100092A17E9413F05C06CF06607B42A09DC731 +:100F20001A1A4A9F75F83EB255A9F86E7FF1471715 +:100F3000F929BDB61A484D347E22A401E9FAF28F90 +:100F4000E2B19F0FEE9342163AFF29F2377F1C4B16 +:100F5000E753F56393D7A2E0B20C40D7E95E268F42 +:100F600084F86C53283EE71256FE88941585E9F8FC +:100F70005505874A2CB49FAAF512CAA9C03FC5F7E8 +:100F8000876ABCF9EBCB12C30AE25DF39C76660676 +:100F90007EA678FE30069E3F54E339F0FEBB235F09 +:100FA00056B5BBDB694F063E2785A4F02C45CD69BD +:100FB00032217114E9BB6E01CFAC3D38F2E5A1845A +:100FC000DC477C5B50EF904E63D9484A2723F145BC +:100FD000D303A50E260753E4E3489F13C5B202F8D6 +:100FE000DA1FF8D446398CECFF469E0678263E4A36 +:100FF000EC71BDEF3DE334E37B5BCDC40778DE9A53 +:101000006E0D35D0AEDA7F74715A27D247796002FF +:10101000D0F10F26F2B8127BBEF6804C8650C62C5B +:101020000D480805FD0606E28871944A5F91E8F3D1 +:10103000FF1DC8319D5ACA6A6250E8B8AE20F185DA +:10104000A2F08568B7CCDA3DD548B07DD845E7B782 +:101050005C318424BADE0289F1B3D554EFCBA04DC4 +:101060008D6DB3821904E621E33C143A3F239D5F62 +:101070004E2001CB8302490807075C08870432B081 +:101080007E686030C261811C7C3E3C3002CBB981FD +:1010900051082F0A1420BC387029C2118149D82E5A +:1010A0002F50827064E02A7C9E1FB806E12581598A +:1010B00008BD81D9585F10A8425818A8C4E7A302F8 +:1010C0004BB13C3A703396C70456202C0ADC86702C +:1010D0006CA0116171A001DB8D0BDC81E5F1817BDE +:1010E000115E1AB81BE184C043580F0A08F010CFF4 +:1010F000E5F10E6581934A0A70B8027C1C4BEEFE46 +:10110000C1ED52B5D3F731F09D68673610BFBABD57 +:1011100068F735B71B2EA06B94FE4E73FDFC85F768 +:10112000C39F0E27BD746BF6349411B9975E969DDC +:1011300025E10CFACFE5BB6611D00B243759C3A7C4 +:101140007DF5035BDF5FB8FEDA6AECF0C9C0BFF57E +:10115000C41BA48F4A47BF2E413FDB14E3B4501495 +:101160007ECB7799705EA39D7E938BC2849CA32FC8 +:10117000833E991974FE7122F04B5EF21F26D2FE57 +:101180000636196004AA4A9CED13A9DE512613D431 +:101190008BDB084179DA16AFB5A7C35C0C1F84B4AA +:1011A000EE1984F234A490D99FCE2B40BECC3F1AC6 +:1011B0004436E580BC852523ED2FB89290C785CDB8 +:1011C00080F61BE6FF1CEA7BFB33337FA199BC64EE +:1011D000A513C9695126C65138788BEFA538FACACC +:1011E000D0907F623C2D0F7F32F812C08B5A431390 +:1011F00013281CB12BFC1235A76464B873A28D961A +:101200002FD94376035A0B3A9449765A1E75D0B7B4 +:101210009BB20119D3E99FE450603EA146079DCFE0 +:10122000D6C3C4DB40CBC5C75BE444A2A2BF99F8D8 +:1012300077A8E8621FDD313989FE337395B34086A4 +:10124000F78D9D71AEBCBEF4D906EB8675523BF2AC +:10125000385D57A62F2C39557C72B54B1274280275 +:101260003ACC58DD6D84756E6B72DB917EF1CE12D7 +:1012700018B27B0A713EAA001F1B114FE6F583507E +:10128000DE05DF51FC5E34CBAEC69B24F45A4D6BB9 +:101290005E6CFC5EFD6F86DF23C06D6362E3D70A80 +:1012A000BC32EEFC725CE5EA91E379AE31B1DB353C +:1012B000BB983ED5E3799B81ECA1B68A8E4BF9941D +:1012C000C91509D2A68D9CBFCF87D71FBB985DF9E2 +:1012D00077C1EB4D2EA62762E19528C9A82729BF23 +:1012E0005E4406C7D637D05F34FB758FAB8F9E3315 +:1012F00083BFD8ECA47A6E706C3D37D7C5E81D5318 +:101300007F713D63E67A5C8CF7334EB7038EB2474C +:1013100080BEB6F58620C85909B1A35C104F32E7EC +:1013200013673CF0C974D95902FA860C27E847279D +:10133000E48582B04F1918540A6568064A19F09876 +:101340009E1BDA44BBCEA17E8691D29F761506689D +:10135000559C86F974DD8942DE9C951EB5BC097BDF +:10136000DF2B8F822FDCDB36E5307E9D45FD97C37A +:101370007CDEBDFD48D86EC30FD3B76D52E9C16D99 +:101380001E0F9645FB58FCFB8DE0DFA675C40FF2DF +:101390003121BADF70D02573BEEDF6019F07BF473C +:1013A0009CE0CFB89A3E44FDE4A2FA4942FDC4C68F +:1013B000CF0CC4FF3C48CBEFB852B17FC0E3F5F689 +:1013C000FF77FCFC948B30799AE06C9769FD406A5A +:1013D000871490D30974EEA3015F66A4BB42181D65 +:1013E000950924047E2FC55BD800FAD7600F819D34 +:1013F000319B5B7C20CFC4ECC2F51F70F83F769D1B +:1014000043DF3813940220EA99BBFF3ECD46F96FC3 +:10141000438E331ECAA76879B3878EEBEE24BCDCFB +:101420006C43F9A17FE948C530DD1B807D14659FC1 +:1014300015DA0FEA2907A1BC157C92F1B47FD7D742 +:101440007B9A2862CA5DBED3301FCAD76700FA866E +:10145000D30DEAE05E7E3E9F3F20E4B3579E9C059D +:10146000429E2AF3501F4AEE94DEFE62F937BFE532 +:10147000FAD3ED6630967F23F8FE82FD1B3E5FE2D5 +:1014800056CEE9BFC4ED7D63CB765A5EE99195A354 +:10149000D4BFB3A7BFDD61A4652BF5373FA2658339 +:1014A000B5C308ED4AA984DA28BE7DD4C983FD8777 +:1014B00075342BC31FEC3F4EB448D398BE5612AFC1 +:1014C0001D792E3C86703D2B3D661C2F6EE89044A6 +:1014D000902B07E72B62944260C71DC54EE37CEC5E +:1014E000AF935C4DFBBBC4CDEC82906BD05BCFE681 +:1014F000815E721B61BF6EB192A0DDDDDB3F941394 +:101500000B7BF513E1FBB89BF99EA9659D3771082C +:10151000C8E97E16476959C3E4B2349384D6819EE4 +:10152000F011C549DBC711F1470597964DBC34FD55 +:101530006B89F8E8FCF77D2D23948690B09DEEF73B +:101540004ABD5218F68166833504B6B424DD4ACC10 +:101550005076184216908F0F255CA7B9302104CA27 +:101560006F727A7162275DC7C97DBB6DFE28F4BFBB +:10157000C15FE99D3C2A361E7BDACD79C509787CAE +:10158000486972821F19F41831EEB0119AAAF4FA60 +:101590005C37F347A83F540E7C3A6341779319E8D0 +:1015A0009D938CFE1019E246BE1DE0D9B9B1044CE2 +:1015B000562DF34FD349A841ED5709FEEA74FBE7D6 +:1015C000BBE93C1EE276848A65C73088575D94EC9F +:1015D00006BFB4A42EBD0DFCDD07D712EF0213EA3F +:1015E00083EB605C5F526B01F0EF43DE9DBFB80B95 +:1015F000F069A1FB62D0E3A30ED9144AAF8A31BBD4 +:1016000053603D7FD4CD5FC08AC01AC48B7E1FBC9F +:10161000D2CDF7C1F9241FF6C127BDD7248691B7D3 +:1016200092A2CA7745E036EC47EC87DF3785B39C5A +:1016300051E5508B6F317E85C4F6B5C42431FDC7AA +:10164000ED28D52F4DA8074204EDA6CF223D0AF67E +:10165000E6A4779417EC762C7D23E643F138B4CCDE +:101660001EA55E2265D1F4C45637F30F2A4C74BF11 +:1016700040EBA51563EA615E15769B047C27DA6D65 +:10168000E2ED043F8B78959CF8CD18A03FC407A3EA +:10169000AD7F1E319E52C7A33681ACA5307C79A3A5 +:1016A000F82BB1F075D0D4520AF33AB850260DB4E5 +:1016B0009F93FEB16924CAFB02BE077C43E9B22AAC +:1016C000898DD743CF21D1F177706D8D77B2A997EE +:1016D0009E7DEA2BE3CAC17E97031E55E31E70333D +:1016E0003B7F8C4362F12B4E5A6F9E7FBF938C04DD +:1016F0003D756A4CD00E71B1EE5F3500BD7F6CC791 +:10170000784579E5E9310D2355F82C266824E7ED75 +:101710007ED0A9D0E7E5439B5282B6D8783C0678C4 +:10172000A478BA031E8CC378CC1FDC17108F2179E4 +:101730006EE437B23BCE1B8678E45BB217FC06182A +:10174000D78FFA93C5935739D9BCE2747E5E79601E +:10175000B946BF244424124A52958DAD189F4D8836 +:1017600018F1B95EDE9ED2C99BC07F2C7A0AFCEBD1 +:101770009FFF9EF3E5C1CAC50AC40DCDF1D1FDE0BE +:10178000EC2449C3576FAFF56BC67BE75B59B35F7A +:1017900016F0EFBCFF93FE716910AF2A370787F68A +:1017A00047CE057EDEFEE60127F41BF79525AAFC51 +:1017B0009DE2F689DAD3E6EB14953DBD516E02BC8D +:1017C0002718B97ED3C99D0FEC2AC5E7E56057E914 +:1017D0001413CE6357E791603BC491F5E30B7BAAEA +:1017E000E72F615FF574137CE049A2F44BE8A59FF5 +:1017F000881BC6922F21579D5CFEF5F8D7C31BCCE2 +:101800005ABF47C0CFB99C9DF4C79120D58F379759 +:10181000C82122217FA07D3C78BF84FE66B8D28299 +:1018200076B9AA320EE3B3550532D657DD29A3FDAA +:101830000C53FD504BE7F347AE27F4F1D912227950 +:1018400027ABD63D63749CA67CE3C27BFFB816E24F +:10185000CBC52605C6DBAFB07873D027A3FF4AFB04 +:10186000F086213E7DDF655EB067821FF6FB6494E3 +:10187000B7E09BB21786EDE0F1E8FDCD052119E850 +:101880002CF97BC6510643FF550AD0E15DCF1627E0 +:10189000E8BBB86F1F282BC3FDA35F2940BB499D40 +:1018A000553AEF382EA793D28BAF073BFEC1661394 +:1018B00081B8D107AB4FA23C77AEADF74E1EDA1B15 +:1018C0005F16F1617D9C591F5FEE1357D6C59305D6 +:1018D0003FE8F9A422067F087D158B3FA81EAB4A7E +:1018E0004AB9703D26F4C77B7C9D93D2B7DCD940C2 +:1018F000F190B040463C08BE7CF79BDB1F013D1CCD +:1019000047F9631DF0F3B74FBC02FB10B2588A1AB7 +:1019100047DEDE63F7285D727BE972A37F714F19A2 +:10192000C47F76CD8A9E32AC5F6F5762EBB573EBA6 +:10193000AD61492C5EA1B73B7A79F857DB9DF2CABD +:10194000FB73E1FDF2CA8521801BD3AD35A07FF585 +:101950007A426F27C47CF4F34C88C824344A3D6F24 +:1019600005DBF5DA0933D607AC8E7C70D6CFC431EF +:1019700018042710FCD2C371A1461CAFFE92329C02 +:101980007FFD588001E2ED0CC2FA3CF1183F68C9B6 +:1019900064EDE52BE2993F3EDA8DEB9485437ECAF8 +:1019A00085E546BE86516EFF734914BF8D3E431CCC +:1019B0009C2B4CB21BF742C8A565A28158482F9EAC +:1019C00084FF4E203240D78B7512EC3B0BACE6C146 +:1019D000E89FFE16FA216BE8BE90F2FBBE7DF2CEC8 +:1019E0006D7489FBBCA312A3F9E702CEF1FC10F5DC +:1019F000C2F5812A84877EF04E36C8EB2D92FF55C2 +:101A000090838EF2AA3BE15CB86E978CE74A736EC6 +:101A1000797718DBA769CF2765873517E2288D52BC +:101A2000BC17F488C063BBDD8CFAA5F110D3838D9D +:101A300047245E66FB889779FDC9F7EDB8CF10782B +:101A4000A7EB790BC6F7DDEBC2F5887DC677584F5B +:101A500027E027F67A329DA82F80AFE4DEF9CB7617 +:101A600023AEAB8BC47B61FE011E0F22EFC7A1DF4B +:101A70002CE85BC7F94FD07739A76F57DBE99F5C3C +:101A80004ADBB7F8DC78CA2067115C6FD7FB09C85E +:101A90001F62BD940F4EC1FC76B7313BD172D8CED8 +:101AA000F0652FCA85F909FFDA99C4FC64FDBA2BE9 +:101AB000C43E9DFB19E0DF429C62917BE2D9A431D8 +:101AC00051DA73BF96E2D9904CEB4B9CE45488F406 +:101AD000E2598C23C615EF3992B57E4C058F2BBC8D +:101AE0006F22E5104F84710B55F35BE32E7124A731 +:101AF000F41DF73BD07140F239F9524BC73AA3AD10 +:101B0000594A243DFB620CA5297DE55C2F67525B99 +:101B1000FB57703EAF97FF33867A22D17E6F95FDDB +:101B200007DD1436FA49A765705F79389F1EA1F466 +:101B30002E484EE9AB4FFA4BE709C952CF3E86D348 +:101B400079427214BD27F03DDC5DF63DA887F5674C +:101B500014E23ECF0774073D611E84E3215F76BB2C +:101B600048E851DA2889C751C47C202E1147DF9BF1 +:101B7000999C83E34A461234D17252AE5702BDDFBC +:101B80000F3E98F92FE6839B92CF29CF61F44B96B5 +:101B9000717A2F1379163BCF9D67D10FBAD5C03A12 +:101BA000CE18BCDDFE9C0BA7DBCDC97DE4F3E6E4DB +:101BB00073C8E770B7FF1618AFD14C4EA11F5E5C1B +:101BC000E981F10E387C9F24D2E72F36707D924355 +:101BD000E946EB5F4996515FDD432E463DFC3D8370 +:101BE00001E7DF45F5EFA339D1F83E6874D3F7CFAD +:101BF0005C4DF03C8EAE6F3DE3CBA004CF6F9D47B4 +:101C00000CF0DCA33410C305E8A196BEFCD9722EFB +:101C1000FEA47AE85EA8A7FCB80AF8D1AA388DE736 +:101C2000D2433F4BD6DAF97EF0DFCFD478FE17F0FF +:101C3000DF2FCFCD7F17CC57CF45D307828FC5BEBF +:101C40002056BE10954792E1EE3B2E215E3C0F2BB5 +:101C5000715899DDDD21A19D6D3C52E0C7B2DD8A4E +:101C60004A41D8E1133B59BD3C31BA3FD896EC66A6 +:101C70007906AD2BBC464D1E48109FDFE53BE11CAD +:101C800042F5E254D986EB4B2A65F143B17EAA674F +:101C9000A74F49E57153BA9EA42C868724EA0FC04A +:101CA000399A83EF0F128B8D1ABF5FE0ED56B94C56 +:101CB00082B8B72B9940DA0DF5EB570F87F37B9776 +:101CC0004FDB3E856CFE52C64108CA839BDA6F88A3 +:101CD00063254DD3B5837D483EB4573DCFE9BB9FC7 +:101CE000F83899EF27CCC4037685C815E7E41BD5EF +:101CF0007EE2F3E47EC4454E261BF8798AD67EB593 +:101D0000C691A871818614BE2F38E542FF57E6764A +:101D10006B72670EE6A7ACB42B182F9065AF757A7F +:101D20004EDFF75D3E035154EB4B9A164F14D5FE30 +:101D300021A5CCAD29A795A76BDA0FF00FD2D467F8 +:101D4000D45CACA9CFAA2FD4940706C66BDAE750AF +:101D500001509707375FA9693FB4E56A4D79F89656 +:101D60009B34ED2F0ACDD7D48F787289A67E64EB91 +:101D70004A4DF9925D3FD2B46FE4715F3D5E2673C8 +:101D8000BC361A99DE69B015623CB2D1A68D4766A1 +:101D9000F37625891372210EDEF861412EE0FB6592 +:101DA000C7788C8BC7E20BBD1E8BA53FF5CF2F4BA1 +:101DB00061FAEE8B97CC069083E5BBA9BC5E42CB63 +:101DC000B6F736C09A9AF3D879AA91B0FC1E71BEC4 +:101DD00022DEEF395F317A597CD561239BA2F04531 +:101DE000768A1235FE29F82816DE1AFA89B7297C78 +:101DF0001DDF156FEF4B2C3F55ADFF774499D79AF8 +:101E00001416DFA2F6655E0AF37746C7A327EE44F1 +:101E100079BC50FD2FE641F5FF9214F443DF98732F +:101E20002BE8FF9D162FECC9BE287FA3FA0105DA27 +:101E300057B3F6066F2ED02556FC7B4D4A9FF87798 +:101E40000D8B7FC76BF0562BE45D17876B747C8D11 +:101E5000F1EF46B337B73FF1EF5AD031294007C60B +:101E60001F3DF4E5F1F358FBA000217B25D8F7D8FE +:101E70008C0A9C739D6F5F4BF7B3B9709EDA02FBBF +:101E800026D53E87EE6FF9FE260EED02B57BF7A64E +:101E9000A0DE237B15FAFC0CDDF76E52A028EC9F28 +:101EA0004FE3975B88D76A96919E0FA6E07E97AC2A +:101EB0008A93215E16DE3721E73BD9F3ED291760BF +:101EC000CFC9F9CFE5D0EE94D2F5AF8BE277E9CF69 +:101ED000E17AFC6FF0D3243C8F433CADA77611CE62 +:101EE000E3DA53987D5E7F88ED93D71F99E541B97A +:101EF00049293AE7395C7FF5CDAB297DFCD25753B0 +:101F0000CEE1978AF5AFE4FBDE29725E2BC41B4F4E +:101F100044CC883799B0FCC8BA3D2612427AB23C0C +:101F200063414753644307D86713D1E7152B89B042 +:101F30006ED31E19F5134966F541626D003F27B156 +:101F4000586BB75C3EADDD4A9AE6D6D931ADDD4A75 +:101F50002BD7DAAD017EADDDCAA829D4D931ADDDEC +:101F60001A1898A8B3635ABB35B8F96A9D1DD3DA1D +:101F7000ADE15BB476EBA290D66E8D7872A5CE8E75 +:101F800069EDD625BBD669EA0BC29B34F5A3F6DC16 +:101F9000A3298FE9F80F4DFB457B9FC3FC9BB1073D +:101FA0001FD5B41BD7F94B4D3B8AF00EC8D35E80CA +:101FB0002421E4D263CF6AEA17703FEDB2EEDF6806 +:101FC000FA212D2CDF3A48FF037AFD95F8CDE09CED +:101FD0001849F7AB1994AECB4392374C9B2DDEB525 +:101FE000A308E6F1D9E12BF6403F8BB668F3B417AE +:101FF00087B4E53A322811F4431DE58B10E593A52B +:1020000090BFADD26B4B49BD03F321FAC9678BF684 +:102010005E4330EF33E8EB80FC74B14EC16F3ECECF +:102020006F627E62BD4BA9DF17567AD7E9A3FFB175 +:102030007D64A719F8B67A9744FE43EABB9E9AB628 +:10204000BB37644459977E1D7ABF734CAA368E3DC8 +:1020500045B6615CFFC49BB297C507B572B8722FD5 +:102060008BE7AF7C5AC2F89A1E1FC22F8D85173995 +:10207000C8F60975C9241452C99FC2F161F168E517 +:10208000EF04FC03E6F3B01C82BCA038255ECF6FE2 +:102090004561D217CF09B95A39D5E3D9EE4D8FCA68 +:1020A000570AFD0FE6514DD8B9949EAFF4785FBE44 +:1020B000EB6E33E8C50BC5FB8254EDF9A0383F2821 +:1020C000A1AB3547C9831378A5FBF225A929B1F740 +:1020D000ADB7A45EF0BEF596D47FEDBEB521F51C7C +:1020E000F1B32E889751BF521F2FEB1B1FDBFD95BD +:1020F000E4C038348B7FF9BD5696AFA2B393B91EB6 +:102100008D9DECD9F77E28851A69E7F50E5F0BAC3B +:102110006F85C37737C0990EDF3DA92AFC3452BCC6 +:10212000E0FD1C6AA77644F10FF7A50ABFA80CE3EF +:1021300022EB4B587B7DBB5FA7B2FB40ED29451ED0 +:10214000F43B8F1430FB692F3AA7DF79173FCFB9E3 +:1021500003CE0B87F6E6F1DCC9CF55A8D8F9806E1F +:10216000EB4D651E759EEF83A92E1CCF31EED90E67 +:10217000C8776E741A9C9202FEB301CF459B7CB661 +:10218000693BF3D87BC99AF7D8BD2319F00DFEBC83 +:10219000CDF8B59A6FF7515C42BFB1D6B92F95F91A +:1021A000BB26E2B382DE15E7B9A60F0BACA06F8D9C +:1021B00092D7192D8FD3C4F3A426F2F35CD9C9CEDC +:1021C000777BE4FC3C7952373BFCAFA9F9549CEB9C +:1021D000CE76F8F6C1F380316801FF32608DBEFF24 +:1021E000FD13A7E35DB03EA4A70DF908C797FB1543 +:1021F0003FF9732AC6E58298AF78ABEC3D06F1B99A +:10220000FEC6AB3E4EED13AFFA58CD877AF9A3FE6A +:10221000E72789908797986EC4ED84D19B0BFCDFEC +:102220000CFF1E87F1D5CF61DD7DF24F1537CFA7AB +:1022300055CE994F2BFA2977F94EA5B2BCBFBFA551 +:10224000B2BCBF2659D58FE33CFD503CE5D6DBFA46 +:10225000853F396D0CC6358FB160C285C5351D69A6 +:102260007DFC4747DA39FCC733878627C279B288B5 +:102270005BE9DB59034999EAFB31CD2EEDF81B0AE6 +:102280005979001F777922E3FB91698C8E220F50D8 +:10229000C4ADADD3890FEE3BDCC3F3B3453F23D3CD +:1022A000ECD83ED53D71645A0A9CA749B8AFDCE032 +:1022B0009234FBCB4F524B46C27A86F3FE47A6318F +:1022C0003EDD3688C567F479902778FB13A9131192 +:1022D00052825D04F834CB72543C16A6B1F97F9259 +:1022E000C8E45BC4CFAAEE67F7BB44DC4CC4010969 +:1022F000F1BE9D40F5CA479B4D04E25A0B65DB06D3 +:10230000E0C39EFB73FC5CDD49FF037B5999578654 +:10231000F947DFF5FE16E033C1DDD75E5E99D6E3FF +:10232000A7782FF01ED7ACB40B386FEF8C677CDB2F +:102330006DB7613C5BDF6E29E787CD3C4E01FA1A31 +:10234000EC865B26F5D1ECC7528EF733872C3EF432 +:1023500063A6C5633E8738FF3052FE4C74631A781B +:1023600010A035909109F7897ACE3F1482EF25D9D4 +:102370006CF89E5121613B5C09357A25C82FEB34FE +:1023800077AE4F83F95E2679E1FE405A85B33D2D45 +:1023900019EE112A28661B7288A318EA0B0C58EF55 +:1023A000BAD6B9C10479D70A81936C62A2E3D8E99D +:1023B00038F7A6E5B07505AF694FA3ED12956E32FB +:1023C000280FF48873AA07E4B89CE5AFEBD7D7C40D +:1023D000F9D5B69EEE1B001F4AF43CF0A63483C824 +:1023E0009B6F047E2D51C84E762F8AE5A1429A3507 +:1023F000E60B7A59BE7402E41B0D667A06EA7FEAA0 +:102400009AB411DE13F225737C03DFABF3E1EFE541 +:10241000E324E9E453E0930ED000F910C6E904F98F +:102420007A6645F4F93EC3E9BCCA51F620F0CFCC38 +:10243000090D98E74EBE397B562E02A797C9097D34 +:102440009F401C222E99E9DF3845417D4C9C12E6C5 +:10245000995A156F0D94E36CE39D32D83D0B3F2FD5 +:102460005C6020462A6F93783FBE72227D9CCBE24F +:10247000AC4CBF1AC9C7422E648E9C22B09FEC8F11 +:10248000FA459B13E87A26D9F6E13962DC90FA1214 +:10249000B857F0CA3CD6C73D31F2F63FE17ACC2DB1 +:1024A000FB3D06F0E9837F79EDE50948E78BE1869E +:1024B000E61DA6CED7F65CC6E3E7982FDEF99A2F85 +:1024C000EF9FCF2F7F2DADF3B5A6BCEFC2FF5E0906 +:1024D000F4F82794B160DE7AFE17FAECA0EC3F78AE +:1024E0001BC5FF7594A90285008DA402E9CDF28772 +:1024F000AEE5780E7E4DF16CEDC5F3756D7B117F09 +:10250000074D74DE747CD344866AD38F12793E46BD +:1025100008C7BDDEDA3205FC9B2E73773E8CDBF5F7 +:10252000C23B5941AA4F0EFDF8A49D50FEFBC0D8F6 +:102530006D87E7C756BF61F751BC1F5A2DE3FD37C2 +:10254000BC97ACCA07FA9CCBCB959EB2A3C057F3FD +:10255000D67E5BA4F6B3492005EDEEE2900C777CC5 +:102560007BF4DFD2271338D3B1F2B2D6244D59D839 +:10257000E36596E8F7C40779985C2C7E6A9B19F2AC +:10258000E1AFF4F8FF06E31FE3F906C776DA717FDF +:1025900025E633FFA90233EC273F68B39030F0BD46 +:1025A000B1C344304EE59B2E51BEF5733ED4CFF3FC +:1025B000D51713B0BF85F7CB1847AAA46305285ECB +:1025C000FD6D8BD9FE56B78E858794A9A0AF166E88 +:1025D00094485061ED5753BAF903B7E3F98A7E9DE9 +:1025E0007AFB729AAC36831ED1DB9705C4DB3C01C3 +:1025F000EC568BF6F9A2B63BB0DF45E7398FF178A0 +:10260000F8FEAC888C3D3B18E2CC83305F3096BD41 +:1026100039B69609E5A76BAD088FAF75223C0ACA9B +:1026200094E279E9AEF6573350AC3B8AC00EC5ED63 +:102630009D64BD89F4FACFC66DD7841F52802FB533 +:10264000F990151CCFC27F5EC4EF199CCF7FAE807E +:10265000759E231FB2A29FF99027F68CB2C2F3F1A8 +:10266000021F63293ED0FEE61D50C8F9ED6F2CBC59 +:10267000C47A6F197CE7200A9E85DC1CE5FA7DC1CF +:10268000F6591BD2E9041A5FF86B7627F2258B43C3 +:1026900088732AD9B3A103D62F135DFC2F48DE24FB +:1026A0002AFED5F3E722E26576C7C6DEB3F2B84468 +:1026B0000F5FB6DD8978157C04370A0C1E80618FA8 +:1026C000A1B8EF7703FA7C1FA0455BFEC2D4990D39 +:1026D0007A63912E5EF085147DFF35DD3388AD5F22 +:1026E000F14D85BC8885A46C038BABB7A09E3A6680 +:1026F0006C79F53690E7ED4C9E963DFFF4AF414F77 +:102700002DF9AFFB1DA0A73E31B6A4C278B58FAF9F +:1027100077805E3F660C3AE0FD4F4272D4FBBA4FC1 +:10272000787ACE056C9017B61C590C042C3803F43B +:10273000E4DF1E3739218E5AF7A4256CA1F858BE64 +:1027400093E191968FB0F2ED88AFBA5D5A395CF2A1 +:10275000C4FDA90AEEE783191C7F19A0AA976F3759 +:1027600061FEE8F237652F0C5347BA717DFAF761C5 +:102770001E114AB7BA56B9D29CD8B79E7A3C669019 +:10278000B3BA9D8C4E753A3FB386EB653DBF3FE0D3 +:10279000E17E26E7738A178C87897C561262FAB924 +:1027A000F1170FE41FA1F33ABEFD358794D7CBEFA5 +:1027B00004B22EC12F6FAD9A077906B1F8FC0B2E2B +:1027C000173D7A9FDB1965179D18F8FE6D0CD69A98 +:1027D000C28E4B293E6AB799BC41FAB8F669D967EF +:1027E000033FE95D0B7EDF61E9D3AFBC3D9ECE6F59 +:1027F000E90E53F274B60C1BE86741A73AE0EFC24A +:102800005EBA2C79EE1533E441C2F3D5EE5EFA2CB4 +:10281000DDD16E86BC4A3D1E27B5B69B997CE9E8A2 +:10282000D47A642AD8E5C65F9C31031F7CF2A244A7 +:10283000C085D4BF5FB3ED1507E80FC013D80F41B3 +:10284000AF1EFAF5A15B78C66F46633B279CD3C4E5 +:10285000A25F00E63206F9FB99DFD0F16BDEB378B8 +:1028600061FD35CFDCEC8075FCD558CFF8FC91F5D7 +:10287000A9608F6B4CC1542742F6BC66EB0F90FFEA +:1028800016BDFE8354827AD33700E497AE7300AC52 +:102890006FE1C3D7E1FAAA891FF9AFE611B90CFCC1 +:1028A000C4D346322D9A9FAF0C60FAE9AF8F5A70AD +:1028B00053F0573361DFE1F893CCF2F8C80AF443E0 +:1028C0007EC0D74A3531964F5B199D4E79C4FD7550 +:1028D000A6C7EA78ABBAEDB7A31EFB34CB9706F2D6 +:1028E0004EF1A08DA7BE3E258DEB3FFC5E0ABE4794 +:1028F000F96E123C87F61D265F5CBEE63D9ED7CA88 +:10290000C65FC5C7A7F38E87B8DC5F53B5FB570119 +:10291000670C107A807410357FC592FBED1B91AF68 +:102920004EBDC9F4CAF2D0AC6958DF610AA7417D37 +:10293000A8FD5A09F502F52FA2C9F57613976B6D1C +:102940003D9DA75152E3F745762FAEFA3EDA4EE5AC +:1029500087F4F28DB9F7794EAF7C8AFC8A453AFF4D +:102960004C40BD5E481FA0B57FE27DF2704AD47B2B +:1029700058BDFA20887C516B0AFDFC3F408EDFB5C4 +:10298000E03DC3DAA74DF8BD9CCF9EDAFDF64D942D +:10299000DF3F6B15F2ABD5B37AF9AD79F63A124D4C +:1029A0007E3F4B2E2351E5973E8F2ABFC92C7FFFD8 +:1029B0007F5BCF2E8AA167270FD0EA59EA4F245EAA +:1029C0004A8B9FFE72E940DC67E9F02AF0A9D79BA9 +:1029D000873C0AE257AF37E9DF9B448547813FC117 +:1029E000974BFE73198ED3C3BF823F05FFF6F0A746 +:1029F0007EBD5A3CEAEBE3E0CE514A2FDD4DEBE8D9 +:102A0000FE1ACE5D5F90F1DCB54BE976B8212ECB96 +:102A1000F36EBA9CBCEC62E5EE14F306D01FE279CB +:102A2000771CCB43E82AEB76B8547EFD9136D9016A +:102A300079F59DA1E8F91298499102B74463D53719 +:102A4000F0EFD6D8B203B02F6B61E73D0B1A6E7072 +:102A5000803FDDD536786639F8F17B65F4A9BAE2B6 +:102A6000797E55D0671C40F15AC5964C8E91E04F47 +:102A7000C1CFAE6A5B3A1D368D0B366BF1516DBB23 +:102A800016CFB3AAEF33F5F205017F2764063FABFB +:102A9000E661EDF325905705F4D1F1911FF828CAAE +:102AA0003D8C3B051F159002B64FE6E7555CAF4DD8 +:102AB00091F3669643FEE21E764FE2449B4C36C08D +:102AC0007A9FE2E757C114E4CFE5948FD571CEE346 +:102AD000C067C363DBEFE3BF3A54741B6D52FBEB7B +:102AE0003FE73F44E1F15FBF3BECB7507EFE9DEC1A +:102AF0003F93BEED27BDF8D55CCCA37CD142605F8F +:102B0000D4F5E2EFB36F83F26F2C5E9867D73AB6D5 +:102B10003F0EBE6847BBDE95C5FCBFC617CEE47747 +:102B2000A27D6A427AED1AC0EEA99E68FBFB61099C +:102B3000F2E9DAE8AAC0EEF27D57DD6FE2707FDDE0 +:102B4000F5C219CDBEF2BBAE6739BFAFD46527E57C +:102B500070BFB8CBC5EE77D6FD76DC63705F71D9F8 +:102B6000CE767315AD9FF4BB6FF341DF743DCBFCA4 +:102B700009EADF6E05977AF780039B4D14CF5F80DB +:102B8000CF974EF71FE989A5700FA32F5E181EBAC5 +:102B9000281E605D142F35A02763E1E3BD01ECFE24 +:102BA000C8BF1F3EBE9C0BE3D7B68D25104FEFC5A7 +:102BB0008BE463CFED987741D7CF9EBF78261FFC7B +:102BC000A3F3AD37F2FFD97A53D3FF5DD7CBF87DAE +:102BD000EB00667FF47CDF97AF9FBF05CBCFD8BDFE +:102BE00038DF7ECA7B51FABFABBCFFEFD0FBDAFF08 +:102BF000B3F4DECBE96D77C2794AD70BDF66930B6E +:102C000058F7CDFF47D7DDE3E718BCD6D1747EEF88 +:102C100091D0752552EC3CCE50BA761F3183FB1112 +:102C20003392ABD17F98E163F1954652B807EEA994 +:102C3000057D329E3B60320DC543C7B50521CCDB17 +:102C4000320687FE14F2B8AE5FE665DFF9D2EEAF6A +:102C500066A44E9B06FEDBFE063A2FDA6EBFDDE071 +:102C60006CA44B98E993D1DFA310FDBCB7265E8519 +:102C70007921338BB5FB8C9B74FB861BCAB5F5D7CA +:102C800093475320FFEEFA1A13E60B5DA76BBF269E +:102C9000DD89EBBC81D4AF67F1990BC353473ADBB5 +:102CA0004FF6C5C3B9F1D6074F7C3F89B93C4A5F9F +:102CB000BC59FC6C7F69A115DCDFE279722BFB85C6 +:102CC0004FC2F79D163EB4C0AFC5C7BED7A9EA171D +:102CD000F122F07EA1F81674D2E35DE057E04D4F8B +:102CE00087C7E04C42E58FF7429147E227EA7CCB69 +:102CF000193D7EA30DF178603BBBAF70A0B86A733D +:102D000001949F92D05F3B3D6114B1D2F5EE3791B3 +:102D10005DECFE974F7116F5E6B348C5BFC7730566 +:102D2000C82754EF4B219F50BD2EC8275497219F91 +:102D300050DD1EF209D5F5904FA8AE877C4275197B +:102D4000F209D5ED219F505D867C42757BC82754E2 +:102D500097219F50DD1EF209D5F5904FA8AE877CD4 +:102D6000427519F209D5ED219F505D0FF984EA7A79 +:102D7000C8275497219F50DD1EF208D5F59047A82B +:102D8000AE87BC417519F205D5ED2F8FBCA42997EC +:102D900090D734ED2759DFD094A738FFAC69FF7D79 +:102DA000CF479AFA2B94CF34F582FE57E59ED43C58 +:102DB00087338B6011EC63D85FA9F7EF9A7E8CA400 +:102DC0000CE3CC66528FD00AF15B0AE3492B421B1D +:102DD000157380570EF35F9C01FCBA35B801986BF0 +:102DE000FFB833D9A0FF0F4CB886C51FF839C14CC6 +:102DF000F8A7429938E19B4CD8D78A734F474426AD +:102E0000E151940F2312426724818493281F46E2E4 +:102E100010BA2349F83C29E242981CC9C0E729911D +:102E2000010853238311A64572107A2223100E88BD +:102E30005C84303D320ADFCB881420CC8C5C8ACF96 +:102E4000B322E310664726E1F3819112844AE42A13 +:102E50008439912B100E8A5C83ED064766211C1283 +:102E6000998DCF87466E44382C52857078A41261B4 +:102E70006E6429C28B228B115E1CB919DF1B11599C +:102E800081302F721B3E1F19F921C2FC4823C24B0F +:102E9000220D08BD913BB05D416423C2C2C8BDF89C +:102EA0007C54E46E84A3230FE1F33191071116459E +:102EB0001E433836B20D6171E43F118E8BFC02E186 +:102EC000F8C873F8DEA5911D0827447E8BCF2F8BA1 +:102ED000FC37C2EF4576E3F3CB23ED087D91D7F0C5 +:102EE0007949642FC2899137F0F9A4C8EB082747C4 +:102EF000FE8CCFA744DE453835F211C2EF478E2055 +:102F00009C16F90CE115914F105E193989EF5D158A +:102F1000F912E1F4C8DFF17969E42B843DFBFD0986 +:102F2000B1EE25FA0D6721AE6573F7EB3B5F846C5C +:102F3000D19C4B3D90E0403D397335CB23D9507245 +:102F40007232FAB52B2C0AFFBEA64EAF7E6303FF8A +:102F5000613DD40C607D401EE01CCEBF078A77A780 +:102F600080BFB4A1B0B316E22177E6745600BC2F3F +:102F700083F90D776430BB784F068B97560E73B28A +:102F80007B062B86E2F91549EEDF3ADEE4F659B40A +:102F9000BF398B976DDDD9782FA09FFDF4B7DDF990 +:102FA000F2A37E98E17F2203FD22FDFDBC7EBFFFE0 +:102FB0005FA827FEF9F79F3FD7FB1F707AA564969D +:102FC000FD16E769F4E543FDC47503E464DA4FE5F3 +:102FD00066C90976B2AAA9602AD0AF90F8309E38A7 +:102FE00027465E5727A7DFFC7A1381B8E27C85600D +:102FF0003C77FE4E96E70B71D052CA17359C2F9640 +:103000006DDC610617B4A67E11CB3F0AB1389395EB +:10301000FE07FCBC64F32CCC3F5AFAA436FE540BDA +:10302000711D19CE91B5CFEB789CA9CFB9822EBE78 +:10303000F46E068F2F7959DE11913371BDA7E97AAD +:10304000219FC37F8BDD0AFA9FE201CF49C4FA4575 +:10305000BC52E081F4BDCF8079A127F60CC53CB508 +:10306000138A9206EDFC549C3A6C90FFE01F0BCF44 +:1030700029FE309FA4BB2101F3918E507DAE40E22A +:1030800093D33F16BE9FD6F95E16E1DF6FD49E1B29 +:10309000583763FE75A5890E4CDB553E9E84F71F9D +:1030A000697FF9BB201EF9B809F3818264A58714F2 +:1030B000F73D57285B6F42FE98BFCBC5F2C382BE77 +:1030C00037215F5FD0E348D3E0A9905734BF39A7D9 +:1030D00000C36EBB4CE8E789F35241A7BE79D165C6 +:1030E00089F07DC425CDAF233D29BD34F5B59BBF07 +:1030F000C4FB03945E4763D0EBE8B9E89598A9A5B3 +:1031000017C4956F80CAD54928A715EBC243EB5564 +:10311000FCA88FD3934C1BDE7714F9C4D3D2193D8E +:1031200088D19B0A743DB9790CD24B4FA769FFA88F +:10313000427A90F7ECF8BDDD3983C9BCABE9F3798D +:103140003C6E39A7F10AF49F7333991E3BB0167297 +:103150002D09797DAD95F8A8F3FCC65A2796DF5A5C +:10316000EBC1F23B6B1584EFAECD4578D4CCF27950 +:10317000843C5106C0BCBAFC4C2647F999625FB545 +:10318000CA0371E969FF78638C0155A367C6942C63 +:10319000F4BB35791AE5D76AF3303A4D3CCF6BA3CF +:1031A000E485EFA8CC2FBB54D39EE48EEA2D83FD9B +:1031B000E07923F39B5DF8FDB61BA72769DA5FDF93 +:1031C0009CA1294FCD5410BFB3A60DD63CBFA96218 +:1031D00084A65CC97F378158E30DEAF329EA19B167 +:1031E0003C6F276B7BAA7E6CDAAD74FC53FB4C58AA +:1031F000AFA7C7517310F7E3C1472D5EB043C7E0D7 +:103200001E192D1F7B4B467D77CC44824EAABA8F68 +:1032100049A409203132793A7D90C9D3B47FC804DA +:10322000F6E1E497163CBFABDA229120DCA1EAA6D6 +:1032300098A7E3AEFA8505D7BD608B4CFC785F4953 +:10324000698573EB558F0FF7C2B9E59CC1E12CB8C6 +:10325000B7D7FDAB38EFA3B4B6AA93BD7F8CEEAF62 +:103260005D90972415E2F9C1E7A52DD506C83790E2 +:10327000F7A5809C7EFEAC8CF194C52BDE2A728271 +:103280005E7BB5F5ED623ACED11619C7FDEC49CBA0 +:103290003619E5DD9706DF75ED5D7708E30CAF794C +:1032A000CAEA32291F7C5A1DCA47BDB39AC5B7FB6B +:1032B000E287AE17E80DFCAAD263BD768B9D9351D1 +:1032C000E53300F44395C98BE7A647379BF03C8F65 +:1032D000EA7F3CFF3FDA926460FAE759E4BBF946C3 +:1032E000C5AC1E77FE66D9C77E174231C37CC9DDE7 +:1032F000B29F8C8532CB5708364B7E765EA3A5EF06 +:10330000CD2BC6E2FD627DFE94805F5099F2ABCE7C +:103310008196BCC0CE67C9E84EA33A7F5CC457888B +:1033200087F52FBEE3533BE8819F4CA0F0848F7D4F +:1033300072F0F4763BEAC7E386978A6EA5F0B3D2C3 +:10334000E0C7464A977AD9FF5026E4EF18366F95C2 +:10335000F05CE4A39FC079FCA74F9BBC28863C5F30 +:103360006BC92F170F3C577E10CC809D2F8753259C +:103370000F7C959760FEC66CD2CAE3032176FE0FE0 +:1033800093A0F871D6B273AC8FC6D837C13DDC2A92 +:10339000DDBDDD8FF8BD856732258D7D3ECECB55F9 +:1033A00006269FE445F6FD45C87B19A2B2A7429FB9 +:1033B000BE90C9F2497AEC2A6945BD52CDBF0F5C77 +:1033C000FBA485DDD3518813E47131230FF90AE49E +:1033D00099CE7789F9E99F023B2F221D68E73E3598 +:1033E00085AA3B72E0FD6D4D6E7CDFE40D81FC72C1 +:1033F0003B60A58A03F4C722C2E6B7AC450A8555EF +:10340000710AF17B1C04EC824ADFF4B5075A3BB029 +:1034100090DBBB854497EFD3A2B54B6509765CD7AB +:1034200092169EF7DC332F999CA538ABF6875E9DEC +:1034300081F396BCA128F35844BAC3F01DE0654F50 +:10344000B1FB40FA79E9D7D1DF79567B674D86EF3A +:1034500009F78CAB9BB7C037810B4A2A3A08BC5797 +:1034600007193EABDB24A4D75FB85F25EED909BAB4 +:103470002F22653340AF2DBA8FEE0B737AF9A0C7B8 +:103480005EEF08A1BFF4196971D828FFD76ED97112 +:10349000FD3878EFE1D7CDC0DF15EEF050838BEE2D +:1034A00017833FFEC9B4AC28F65D67CFFF55F821FE +:1034B0003CCE84EF517C2CDC2E635E83AA1D3FDF63 +:1034C0000F327E0E12CC23AA7953F636D2A735F0EE +:1034D000733E85173E5F819FFFED79EBFD98DC2CF5 +:1034E0009E6F10C38FD1EB973E7E8CCE7EC2BD09FE +:1034F000B097DD292C0FFC94D197E846BDACD3BB27 +:103500002985F8DD51A177ABB9DD13E32C047B47A6 +:10351000CB1F6F79CE01F187BFDCF75C2AE65180C3 +:103520007DC9EBB52FB754B1F16E793E0EF3963EDF +:103530002FEDC807BFAFE291DF3BD4DF35ADF3F825 +:10354000A766C17CB93D5C266FCB76823D0C44CF2B +:10355000ABE8B3FF8AB54EFB79D669D7AE733EAC04 +:1035600053751FA48AAFF3C366B6BE8F36B3F52E6C +:10357000E8B3CE209E83DCF298C51B443F238C76B3 +:10358000FCD80E99C0FDB31E3F4367F74F9396AD2D +:10359000808F652BDF396CA47CB17818C50FE5836B +:1035A0008ABB2D68E717FF8A9D7F7E2A95A4E101DB +:1035B000FCCB61C70FE9F325D43F00FFA2771E3D86 +:1035C000767F7996DAEEF7137FCB791C6A79DBEF99 +:1035D000F1F7A2241FCB875C2EBE03B34BF71D1857 +:1035E000057400BB276F053A651285ED13B5F1D45C +:1035F000BF0DFD72EE4AE4FFEE61EAEFF5D6C58736 +:103600004D90EFDBBD4342BF68D9AA12470981FC48 +:10361000561607BB238BD92FC9E7C3BC170BA56B65 +:103620003C1DEF27590A7BAE38595EF7C304BF3BF8 +:1036300023E6AB7F0EF1712BD83F9B01ED9F7EFD02 +:103640002FF07196C906F4A76BCDCCAFEEE2DF7D0B +:1036500078288BF9D30F6531FF7A1B8F0F74811F88 +:1036600009E7D39759F0F77A08998C71722361FCB6 +:10367000671478731ABFE8916FF497BB33014F73E7 +:10368000498709E839A3789602F7060EA75AF13B55 +:103690004AF4AF0CFA99CDFBD96F62F7040EC31848 +:1036A000745DB3793CF9307C06948E7F788019FD87 +:1036B000D8E00B16F4136E8F67F13E929C68043EBF +:1036C000BF89EBA939132C3E381F983DE1F63280B3 +:1036D000B4BF20A1F8AAB076AF2FA0E33418989D0C +:1036E0006F7013BC2F499A3AC700FE2EA16E31E4C9 +:1036F000C9D3D5EF3C9B742E3ED2DE53A885B8C209 +:1037000078C218AC18F1AB29D79A59FD1B8F1C99B8 +:10371000715F26217F826C26B0338023E08BCA4400 +:10372000DCE7CE843C7E374023F2DBD546123430D2 +:10373000D86CC3EF10B1BC7E710E725D310927D217 +:10374000F585F76AEF51DC10368487C3F98E31DCDA +:103750000EF833581593938E53364D2A04BCD7AECA +:10376000EBDF7C3F7EE4F88CFB26D0327CEF0AE670 +:10377000F94309F3796653A1073E9D6B242FCB854E +:103780008C7EC087756E2588ED56303E17F737045E +:103790005D0A68F76AFCCEE6F3A3FD343BE07D7377 +:1037A000F4B8C9892CB1CF637EDA522EB74B05DF4E +:1037B0003DA595D7E46C2E37E00F52BCCDE6301610 +:1037C000DFBBB2995CB8B2599EF5B71738DE320B41 +:1037D00009E3BA5FB0201DC5B833394CCC1E84FD57 +:1037E000897908FEAD26F5987F53CDE33106AA49C5 +:1037F000304FB7E531CCEFD7E709510709F3CE9643 +:103800006CD73F57C573648D5EC238A764EE5E0007 +:10381000F393BE17E7057E9F6D6EC57880BE9DA9A8 +:103820004542393735537F4AE2E75BB46CD92CE126 +:10383000EF3BCCCEEC1E89DF2BE77E7535A72BD571 +:10384000DE53E11E5035F85378FEC5BF13B585F938 +:103850009146EEFFCEDFACF5336637A9FC4C06345B +:10386000F7EA2DBAFC7013F7373E30778F047DAF3F +:10387000BF67FF8181CD3F984A303F52DCB337723A +:103880007F52F093926DD29C8B89FB9C15A0A7D898 +:10389000F70E74F95436FCEE4A85C4BF57C9E38A63 +:1038A00027A8BF89DF95391487764BC419BB4AEC2A +:1038B0004143227CCE9295E724DE3203FCCC0A877A +:1038C000D908F08CA113C7B955EEB0E7E4F4C6717E +:1038D00037948CDA027943D7678F9869CDC2530E3B +:1038E0007EBFC87B00F2D6AFFD86CE1FCB05337DF1 +:1038F000747FD4F54AF75C2B55D1B55B0B661AA9DA +:103900003DEFBABF7B2B94D76C1D3FD348ED60D7FA +:103910009DDDD9F00DE135D997B3FA06D1DFE53356 +:10392000213FB8EB41569E4DEB83E0E7F27B40151B +:10393000E325D4B36BB8FD11F1A30AC34B0C4E645D +:10394000BFF371BE76B76797AD01FB2CDB8FE2EF5B +:1039500009DCADF8D680DFD394E9AFCEA670C92CD0 +:103960002968867BF16F868671FB15F5772FD66403 +:1039700031B9DC3890F527F045FBA9FB67FA49839C +:103980007E5234FD04FE997E8EF6EDA7E19FE9E7B5 +:10399000FB8AB61FE19F89EFCCFD31C7F708F4BB66 +:1039A000740DDB0F93A336CDFDFF93F5CF0F03BB53 +:1039B0007FF2294B12F0E1D267FE3BBB1AFC3FEECF +:1039C0000F7DD6FEAE19F2BE9747D87771EA22EC8A +:1039D0003B39CB77B69BA7E6411E6BBB79926A7EDB +:1039E000B5BDBF7365BC5AE5C73C9A2DF2B5D9EF9A +:1039F0003A2E7DE613FC9EE05243EBC790E74BC6A0 +:103A0000B3389A7E9D9BF87B87E1DC3F4ABCE0C9D6 +:103A10006CA66FFF31D8F74436851BB309F62FC764 +:103A2000F86ED797BCBF8A78A6C7AB8AEC5685E2FA +:103A30007BCC9BFE46C83BAD7E38A750A6F37822D0 +:103A400073E20EE82F767CB39BC537DB587CB3C29C +:103A5000DDB18A1A29723C7BDE5DD6CB08B9EA015A +:103A6000D273DF0FE286D32CA27CCBCCC91358BC17 +:103A70000CCA07B6D6DD05F2B387FF3EDB9CB12347 +:103A8000E341CE3B73120C4E2AFFBB322A8FC33C5C +:103A9000E68CBD6C2A3C2FB1D88755B2F838F2C7F6 +:103AA000AE8CB2DF037DA13DC43DFCE670CA0D744F +:103AB0001DFE3FC89837EDCF4FF047BBA7F20AB7BE +:103AC00057C7B3999FB6C740E759D83B0F313E75EA +:103AD000CC567540DC6ADD8002F0A353324B3ECBFE +:103AE0001ED33B7E4AA6FF2094C5F874B9F9F0BCFA +:103AF000BFF3788BD3E333A01B85651364F8524280 +:103B00008F5EBF7A7282A67CEDF424E253C74DAF7C +:103B1000CDD094CB2B066BDADFB46084A6BED4D2B2 +:103B200031BAFE02FCFD3AFB9398DF7BA8EDF4DB93 +:103B3000B3C18FDD2E7B25BA9EC52F3CFE36E45FD8 +:103B40009F809F2029647131F6BD467E1E63F41963 +:103B500035E7317B9F3383DFAE8AF3EBEEE5EDC3D0 +:103B600038BEFE3C46E48BFFB3E7310903F5BFE7FF +:103B700079FC55BA323269573BD2A7712FCB636EAD +:103B8000A47E0B7C4FECFB3B2D21F886FBE7FF7DF1 +:103B9000C4ACA8CE65EA220DF8BBBA93761DC173FA +:103BA0009BA7B89FB4BCED4B33DC93FA7EDB0A9441 +:103BB000E7A9547F2552BEE968272377423C39C7DD +:103BC0008E79384B9BAFC03875626436C2DA962B5B +:103BD000B0BF65916BB0BC9CFF9EEF9EF88EA96054 +:103BE00087F7FCDA85FBC1037278D843D08FC58E86 +:103BF000FAA13463CE3AF013F6C407F36EA6E39548 +:103C0000FED7F7310F7DF94E09E3A6A532D923413E +:103C1000FE7D240EFB2B95FF347A057D7ED5246630 +:103C2000574BC1C7A1F572917D137E4F3AC6EFA4E1 +:103C30008D1DC8FC3A53279BF794C82CEC4FD45FDA +:103C4000367090E6BB7CA694EDC6F9B6DEF5983AE0 +:103C5000258457464620ACDB39CB08F9E77FC87D81 +:103C60002C19F044DBE3F7C1FAEAE3B189248ADED8 +:103C700012D0C2F5F06CD0C370FE9EE3BB66600A42 +:103C8000FC1E61A7D10A7AD4667582FF32A3B840C0 +:103C9000A956AD4B7EE946BC076149EE3681FD9ED3 +:103CA0004DA15A6FCF8B61676E1C28F47603426179 +:103CB0008F48E407EC3BA83C3E20E469EA4083E6F9 +:103CC0007B3A1D12938BE0AFD8B940698E7FE940F3 +:103CD000DA4F4709297F16F5684736DC47FF57CD8D +:103CE0009FD2D70AF477183B09C431EAF97C843CA7 +:103CF0009F6FFE7379FB033209005F1CB8FCF20E64 +:103D00001F9D57FB6DA346815D10E3350C6479A6BA +:103D1000C4D9FD0DE61BBE98A0405CBF14CE3C4646 +:103D2000F7FAF3908F08F1C3BA172D8FC20752EB41 +:103D30001C747F6F83BCC0B830F06DFBEFE28C6009 +:103D40003F0A87F81B002F937E377C327CC7C7D78A +:103D5000663112F4837CEBE079ACF99E4F7F0979F0 +:103D6000D4F399BF99C99F9FCB6125E7DBF95C0E1E +:103D70002B8DDE44388F99B74FC67B91F3574B2379 +:103D800077427C40B1E33D7D218742DE4CC097A362 +:103D9000803F195FD6465C5CBE7378BF4C0E4A65A7 +:103DA000966F573AC285FBE7E591246C27E455C826 +:103DB000E91D39FE1DC0D7A58D54BEE938FE750337 +:103DC0004683BCF4F289D909FC44F9C453ADE283BB +:103DD000C6F6AF8CC027A60912F28985C2492A3ED1 +:103DE0002AEBF14F9C5353E93C6634E5E0F79445E8 +:103DF000FDAF7BF8A57FFCFE18978FF9B6F050F069 +:103E00006B4DF5715EF88EFC896405F5D8CA8D128C +:103E1000FE38E14A53D924F02F563E28617C0FFC2E +:103E20000ED03F4507EBCDEA73901B23F9785E7DFA +:103E30004D6408C22732FD2F03FD2B23D7733CE6C8 +:103E4000473DEF3B557F3BC6D54E852C5EF69D31F9 +:103E50006DFC6E8CCF8BE77FA67D26B24D81B89B23 +:103E60005FC6F3BD2CE2BC5762F13B88E789F89B43 +:103E700038A71371380B7C0F5765474F1B5BB26136 +:103E80001FD2271E57C2ECFEF1ED26766FABFD4F19 +:103E900045065AFF698E0FE372AF79FC87613D4B8F +:103EA000AE0E3D63A2E5A5773EE78078B9C067AB6B +:103EB000313C14F64BAD148F101F6CDD2C4F0B31C1 +:103EC0007F2761962ABF22165F2F890C46FC087B4C +:103ED00023F4F7F36B3DB829157AFC7C7648F0F7AC +:103EE000322E07CB400E88DADECC2A83DF3523B9A9 +:103EF00012DE73EDB5374C1E849EA6FC8E72533ACB +:103F0000380BE3EA426FEBEDD16EB9F5DEF1C03765 +:103F10008ADFA950FCFC0F4D62B3890080000000CD +:103F20001F8B080000000000000BB55B0B7854D518 +:103F3000B55E67CE9C994932AF3C0986C43393077E +:103F4000700D383C22E1E1C78140002138C15B455A +:103F50004D65402411131250AE51B8DF9C90808003 +:103F6000D486EA55DA824E28285AB551B0C68A302E +:103F70003CB4A15A1DABADF456E8A014791BB15660 +:103F8000FCA472D7DAFB9CCC9C4982526F874F37D6 +:103F9000EBECB5F75E7BAD7FADBDD63E8789BFFC50 +:103FA0007AFBFF0240ED8B4F4F820C8009570920AE +:103FB0000A00339747CD36A4C16E736FF5205D3A82 +:103FC0004C5E500C70917EE301C4BD5F49F210005D +:103FD000EBF24A50EC00B7625B668FF54B004A3B50 +:103FE000D20051F32C47EC79A66CC2FFD1F32680A6 +:103FF000129C57E73BBF14E01A80DBDCC07F8DC802 +:10400000D41FD7217EE49B6A85397E5C1FCC91BC8E +:10401000F8F92A3C1307CAC85A2C0B6CDEFF2FB9DB +:104020002B44B00969004E7314D28A697E5D6E9587 +:10403000AFF32D725FA1F1BF2342633B8E7F67FC1C +:10404000F8888272ED5936628428C7D61B2F5B1818 +:104050005F453A8E1D09D0F59A35B419E5069C4F97 +:1040600040FE4F5F1B1C5A8B5B3B0C5D17C83EEA42 +:10407000CE1499F655BF2B85F1D727BB4202F6D750 +:104080003BBB8AFC284FD9EEA4300CC57576279926 +:1040900001D7FD26FFF6F1A49FB2DD0327094E14D8 +:1040A0007AA7D50CC8F7409EA2D0F3BEE4D7E54B63 +:1040B0006CF5FD97570AAACB0530BDCCA19AB05D2F +:1040C000783E1F6004C05DABA7B1F6E560362A19E3 +:1040D00060F2F94A00DC5BDDF91BD8F345E75318C1 +:1040E0003DFDC14839ED075E16602BCA5F91F3C3F1 +:1040F0001580F27526C3901DB8AF4E6FAEAF9970A4 +:10410000D93A8DF157FC6ACA54DAD7A21DC84CE3DC +:104110000609A142D2D351BB09B200EEB671F13FFC +:104120006FF860A48CE33F1FE91806C8BA4F6C7F94 +:10413000788CC0ECD949F69CA8E15D3A2F8282F2D6 +:1041400058CF0BACFD400E2C964B181F401AF9436C +:10415000FF9101FB77C1D32B928C78946A3F93082F +:104160004F566CCBE2FAE7683849D4E37F5DA61F6F +:10417000CCFF8E785A43782AF9B7E2690DE9A9177E +:104180003CADFD3E78BA841D7DE089E16CFA9B1C54 +:104190001F90EFF06D0586172677A72537D48C7C06 +:1041A000B7925D095F17A181F43987EC9B1EC3EBC1 +:1041B0000E4FE0F9783B7726ABC58B8BBF8B9D6F9D +:1041C000068A1BB766348082CFE7601B1F37AC645A +:1041D000BFE29EFBDB7E99766EFB8E76DEAFD91951 +:1041E000DC68C791CC7E32D935D1EE6457B27BFD05 +:1041F0002EEBE64BD9757841E09DDEEC0AEE6413B8 +:10420000C919B38BF506C2CDE76133907FF56557C9 +:104210006903D7BB4EAF0C9BA786D87900E99543BD +:10422000185E22DF072F1565ED7FB7A5029C0DDD17 +:10423000ED378F06B8B114BBAEA0EE7B5A95028A5B +:104240002FF8F7316C46056C4C9F9C56974626E13B +:104250007EA73FDCDDAF52FFE4712E3E1EF9715B9D +:10426000DDFC67424B22EB98DCAD5CDF81A8D93FD7 +:10427000248E1E89B4238E2E4DA037727E3A47DCE1 +:104280006C9E10F74F9C5F184EB43E9FE607D055CA +:104290009E8AF69BB94370AF457BDF32EE530BD954 +:1042A000A7A22CFA460EEE57685BEEB70FC6E714CE +:1042B0000751DED4B69656B5401B8FFE53ABA9D13D +:1042C000DA2E2822DAA9B65408793D3DF598EA316C +:1042D0009E67F4331BC78365E4E58D273BB2F15E2F +:1042E000363E6CBD8CF56F1A074AA8973879A587BA +:1042F0009FFF7001697D7ED4DD0DB8BF502FFE3663 +:10430000509B376232D501EAEBEAB60DADB65CB42C +:104310002F707C0C6B7BCCAF721C8292B0DF4BC9D0 +:104320009BA9CB11B75FD9383E7C297DE5F4D097A6 +:10433000868F1A235E5C66FFFECF510E5786E056CD +:10434000D1FE8BFC49EBC045F6D7F1BDD9AF0CC00F +:10435000FD2541375E8DF8FE859FF0BD0874FEADEA +:10436000AD742EF94DDDFC1CEF3B85EEF183D0954D +:104370005DC0C74F6FDBD2AA16337BB07E469B2F42 +:1043800081F7F6047A5C827F68F866FE49711BF556 +:1043900053D84BDCA8D1F47B4680D914F72213798B +:1043A000BE17F1F276B587E7770D1A5FA36EE7E4E3 +:1043B000383D0C88D9197F611864D837D3D3CD190B +:1043C000FABEF7FB67A0DF44D26088803859E10964 +:1043D000B7B6C4E1A4C5B39FE12436DFDE08C5FD4E +:1043E0009B353DADF6EC8B683812C8EFEA1820100B +:1043F000073B0455C47DD6110E7AD9E7AC9E3852DE +:1044000013C62BD225C6CFEE395E49180F52C6E52A +:104410008CD7EC3423C18E5313EC382981AED2E90A +:1044200090219EE9716E5EC7FA955928C75DDB043D +:104430003A26285E5B8461009BDA7EEFB7F727BCE3 +:10444000CA520EC6FCB6B6772236C47225C533866C +:10445000DF48AB8278BB81FC9DD1EFFA1517E1A74D +:10446000616536F23FD5F687561BB2DED2B25EA248 +:104470009CE6976DEFB79A71DE9B47FEEA0D9ACFE7 +:10448000DCF4A7C80CCF25F0DA9AB08F8D09B49A66 +:10449000C0FFC8B7C4F79684F1CB13FAD725D01B59 +:1044A00012E8D5C6F173E70BCC4FE6A2FD4871DFE9 +:1044B000E6377B347B76FB3FEE40B0B33CC980FBF4 +:1044C000E9CD9C7EB3EDA87FB53D8EF61CF393BF7E +:1044D000EB389680FF6ECD0095CE0FA98F78F64A07 +:1044E0005F381A9478DEF1FEBFD25FFB53DE098697 +:1044F00073799F68A4F788BADC7F8FDC63A7873A5B +:10450000FDB99FF2F1E98F19F78575A1467FE69F06 +:1045100084FE3FFDC71AAD76F995B87DEAFCE5FF4C +:10452000BC28D27A473C5DFE2DB8EFAA89E1C206CD +:10453000E4AB4AE32D9E33229D63F536EE4FE5AFA3 +:10454000897E3A67AA92C3854B8AE3F609ED45B4A2 +:10455000CF3DCB44661FB599D723F3C067012C85A7 +:10456000F6B85C8D4F22FFBE6562239D6B871BD31F +:10457000B348FEE15E5EEFED735D997507D27B5245 +:10458000E65864E4DBF3C064D6EE1595555D88E328 +:104590008B6D17D939BF27C5C5F4F3B5E76B7F130A +:1045A000C6AB6F3C325B3F90E6CEEAA07C75AD04B3 +:1045B0005B6592C7F738C3CD8FACC3D6A21C739B83 +:1045C000AECAA2FC6DDEFF5496F747BE792B259F3D +:1045D000C0F86028C91D583BD942FDF35BB4569D15 +:1045E000C2DADDDF6C7F7328F277AD117D9B9179A4 +:1045F000D779AF731ECAF571128FC31F9D2E7092AB +:104600009C8F7A03C95EC2ABD3912CD0E1E1969D19 +:10461000B370DE87F395146F668C7FF737E21CCAA0 +:10462000375F3D3D2F2B8074A697E366D7F9795904 +:10463000F3E2CEFB0567CC4CCFBB2DF23D945FEE91 +:104640004ECE155481E939BD12FD65BE965F235EDD +:104650001AB7F772EE9BBC22D3EB516B237C8C20F4 +:10466000DEF360E63892531F57F27EA0D941781EE0 +:10467000200F8FCFA3B3F2267A48DE18CEB2DE2504 +:10468000DCB03C1AE9E2CD69EB553A0BF761FE4F1D +:10469000726428E5D40FCB9101F34EC86E2F8ABF08 +:1046A0008F88E5A92BB478C0F90EA90E56B71E7AEB +:1046B000362944F5CC21F52F0EB0C7F3733FA97608 +:1046C0003A543A8C3F7138CCA4D7C3E6E0B1FB70C2 +:1046D000DC824D128BA30B36652EEFA27880F62C70 +:1046E000849EEBAEF44A6C9E3EFD44CDAF34F80997 +:1046F000E457D2B9D6979F946FF6566EB1F7ED276F +:10470000D55ADE5EBE49F213CEAB4B1C66B81AEB2F +:10471000EC4DAF6F253C562F4E1A6E45C1AB375945 +:10472000997DA30E87EAC6FE80D3614EC5F6560D6D +:104730000FD1A62456A788591616F7C4552532E975 +:10474000A74C04B30DCF15D1E993FD9C6E7163DDC9 +:10475000B6D2512A937D577865B6DFEE7ED7ECEB63 +:1047600004AC6BCEE13ED271DC89C6871F1D85F299 +:104770009D84D08DA350EFE7C8D0B8CEB91D624854 +:10478000A573C2AC982B30EED500F7F7BA03DB2D3A +:1047900013F0AF350DD533A83EBA33247D14D56A56 +:1047A0009F8BF8DF17F09685F2DBBBB6199FA3C786 +:1047B00058C8AFEADA8DCFEB61DD67E2506ACD1FF2 +:1047C000450769CF71DDC60FFF3C647F1CDFDD5EEE +:1047D00047C6312CC161380C47CDE23AC5AE9B08C3 +:1047E000768D2293575C9114223D8A79FC7C980245 +:1047F00042288900E1C67DE3BA5F060F0ED98F809B +:1048000010EF1FC1F4723488781A88FA70DA18BF72 +:1048100078BF18B2E2BA65E9A0A4923E1FAD047059 +:10482000307DAA6EA4A7643498293E7579B83EE716 +:104830000AE06F677EEFCBA3FA78C1A62466BFEAD1 +:10484000C7EFFCD34F4792BD2A32E2FDE821C25D9B +:10485000099B0F6C69B1793E69FAEF3C92A7EC09AC +:10486000AC2BA9DE14038FDECCE2658A8FC52D77D1 +:10487000F447A308274D29C3D602E1A47F9EB73889 +:1048800036BE7AC5B2223E1EEB5527C5AB24B69F75 +:10489000DA1D568693B96B44859D8FB916763E7E98 +:1048A000D492C4E8DA01A5CCCFE69A2040FBC05CE4 +:1048B000309BC575AE72A8B583B2DD4E717E5D4486 +:1048C0007432FBA89ADD2C649FA7BDE96CFD39A466 +:1048D000633CB70E68389B6BE2F8815D42682B8BB6 +:1048E0004F0D32F97F954960712ED11F7F434918D2 +:1048F000C5C93CDF6D34AEEE21AB6F8587CB20EAB6 +:10490000F2209EEA4C91053FA7797F6D65F71AF575 +:10491000B88F2427AB2F941751FE7A33982D742F1C +:1049200025F378A6CB532F574E219C62FF4133F6D7 +:10493000D739783CAE4BE5F73DE0B085B6C6AF471A +:1049400032E7F371B293FC6C34C30BF9BD09FB3F42 +:1049500005DE5FE62C95A3F8BCD304ABE99E84E4A6 +:10496000193C346E5DA4FB0F253C2E367B1D6487FD +:10497000F41B67D37ACF892C2EA1333D544AF9DF3B +:1049800073E208AA63E7AED957BE81E81786B94932 +:1049900084B9CFBFC7CEA7BB349C4529EFA7F30A84 +:1049A000E917B0FDC8CBF3FB80C8EF713EF2F2FC13 +:1049B0005FD7ABDE5FB74662F6A85BC9F150D7F4AC +:1049C000019BB7CE11C9227BD4BD245D43B83EA55F +:1049D000C93DAF2977DC41C4C73CC9E516F051ADEC +:1049E0005A6121BAB65560B4BE5EDD9A3F66998AB7 +:1049F000F97CD45A351CC5E6CDCCA3F3ECD4B3E98D +:104A00007973E3EC7EAAE565A76C27BF0917BAE9BD +:104A10001E6671926F33F3536E8F532D859BE99E03 +:104A200066BE3BE210B07FFE3DF96974CE1D76870D +:104A30002DD47FB8DD63225A71BBC711AD98AF6624 +:104A4000F4290CE1EDC51A78D14E8B048E9BDA6700 +:104A5000F759BCB89E3B9FEBE7CC73EF15D17D4176 +:104A60005D5EA488CE5FC455510ED9E51981E50974 +:104A70008B9E1595A4A1315C2D225CA1FF2FD470D3 +:104A8000B568C7CBF7929F2E223C0DEF894BAC2B1C +:104A9000F7B3E72FB695031FBF9F70A79FF748B7DF +:104AA0004874AF66D1685C87E8D47C99F901F64F09 +:104AB000E2FD6A313B47206AA17CB85EE47902FAE4 +:104AC0005336E511F51D92DA1D2F695DEA2F8EF53B +:104AD000F7859BE1F926CDCE56761E0DD7F4125DF3 +:104AE000F392937071E6B97D6F8CA1FAEA45C14DDE +:104AF000F1BE871F6A7AAB273D39D93E595E544FC4 +:104B00007A71C6F4D4ED6F1A2EEA81EB41D74BBD12 +:104B100059D393DEAF8D1FA1E9A11634BDEE18C89D +:104B2000FD5DF36FFD1CD1F71748E3E3757CCDD72E +:104B3000F637219F9F9BB5881B5F31C39762B946AB +:104B4000ABFBB1EBCC0B6DECDE48B7A72EF7F27CDC +:104B5000EE0718A795D4B4989DA326A8E9ED9EFA70 +:104B6000264D7F929DC795234D39B735A2FE163E3F +:104B70002BFA98F2A8E68A5BD76A8A3A585E7ABF1F +:104B8000E8A67D95FDB2F23ADAB78E3B699B60EEFE +:104B9000184975462AD3BF2E5F593FFF75A91C7768 +:104BA00061924797F3881066F6525F10DC3CCF8D18 +:104BB0005AE8FE50F7D34479E76BF28A4E618C7065 +:104BC00035C9E393C9BF01CF41268FFDE032B69EC0 +:104BD0007A689967686C9DC3AAC34C7C8781C701BA +:104BE0001D9747B4FB88232B5F6679B0BECEFD3D91 +:104BF000D7093466F45C47E75F92CFCF01DD2F3AE7 +:104C0000D338FECB5A3E607C7A9CA51FDDC3E9FAFF +:104C1000D4F516E79706FDE8FEA5FB936ED77FD582 +:104C2000AF607926CB571FD0F6CD7C242B762E1083 +:104C30003EE9BCB35A109776C3B9C9F29A29033E2C +:104C4000B3047A79AEEB29F179AC9E72E791FEA7B5 +:104C5000D8B34D9407404BF6FE82B8BCEC63BAEF74 +:104C6000A2789A09FC7D06A057C69DE77ABEA69F4A +:104C7000D7F85BD78D4B1C5F9FA19CA0FE9A918BB0 +:104C80008B288FF847BE97E9EF24B45B26E07CB50C +:104C9000C723E54E3956AF5CFBF7B0E8A2FBC01D59 +:104CA0001E43BD507B7A3FF3EF3A88ACA2FA76EE12 +:104CB0009AF72A4691DD9FC67C1CF9E6B77AD8B9E7 +:104CC0007762CBED23A8949DBBB290D1776EBD8364 +:104CD000D36B783E377765C993741FFF7192524E3C +:104CE000F8EE5A2FB8A9DE1ABBB564F92DD83FD615 +:104CF00071652AC97D68CBC71563A86E681499BF12 +:104D0000285B1EBE91FA950ED1475B9D0FEEE5B76D +:104D100010BECD2EE66F87B573A259E2387B578B54 +:104D20001307BA5B8EC3B2E6E62213ADDB86E71348 +:104D3000EEBFCA22B787A9EE7BAD9F6F33E90BCBDD +:104D4000D46CC4D17181E7DF3516B011AE0E489135 +:104D5000A524FF81A58E614D248078E11AF20B45D0 +:104D6000ABB3B06E62EBEAFAD2D78F68FEA2CFA3E4 +:104D70008FEBA47C8ACE0F4DDE132D4FDF4879C216 +:104D8000896D856910A7F713B42FD4F79D18175FA5 +:104D9000ECA5FE3B94AFDF4784585BA3DD1B1E9060 +:104DA0005A07D0FB5BCCE38FC6E7E59FB425D90853 +:104DB0008F98C71B9F4BFC3CC13CDEF01CFDE6A856 +:104DC00031DFD7EA3BB1CA15E8250EE96D629EDFF7 +:104DD000956FCF387615F4C8F375BF4B1CAFE7F568 +:104DE000DDF72C1FDA13DEC78C72C125D63F1D44B8 +:104DF000C360EDB78D7C17E59D94F2CFED11AA2726 +:104E00005BAD6E2BEAF728F915BD077C49E479A262 +:104E10000D7C61C4C5D13F8EF0911F2EF890FBDD53 +:104E200082762144AFD8F7AF7F4024FE3B360AD0CC +:104E30004F88ABB31E597F23B9DD395F60557FE4DE +:104E40003FB74DF0A94C42C59E505FBDD15FEEBB50 +:104E5000BEFABE75957ECF94A8F72B0BB4FACA079D +:104E60003EA3DE797DBE1BE1533ABCA7DE4F0703AC +:104E7000AC8E3A1BAC61EDE8F6B6B21C94FF53E180 +:104E8000C84363C97F1C2E764F723AD8C05E029E1B +:104E9000ED18716126EAE755BBCB4D71E36CB0911B +:104EA0003DEFC68B86CF6B77EC117380F1EF1C8BD7 +:104EB000FCBBEC2E7AADD1CBFB366E5F8064FE7E00 +:104EC00054ABB7EF5E3CAA1F3DD7F77BF23E6E674F +:104ED0005DFE93DB6E77527EBAE7E7E93B47937D51 +:104EE000535C6E8251F506110223008E6DE071E86D +:104EF000B8CDF524DD971EDF784316D58377485D5E +:104F0000161FCEEB7BADD249F7027F33479D6E6A09 +:104F1000913F4C72984322C5BF315381BD071C138A +:104F20003683EC61AFE8194E469F3687C2489FA290 +:104F3000F783746E5F48E6EFE9B5F77E77BCC2EFA2 +:104F4000D3BAEF4FB47B84B1DA7E9715A4E9EF7B37 +:104F5000D8F3B252FEFC938DDB67D27C27B6486E45 +:104F600092F7EC1689CDBF10EB7813E2F038E28DA2 +:104F7000E2D7C2F7451F41FAC4365E272F44DCD280 +:104F80007D71DD6249B1B87AE2B14CE7DB29B0FA54 +:104F90005AC7E5422554CEF4AEE1D3867F2EE29186 +:104FA000910AEDAB481F8938FD57EBFE2584CBDE17 +:104FB000E241020E747DE97888E113182E75BBA7D3 +:104FC000B50F9B90C306A82C5EA8136110E505CD14 +:104FD000161864261C98927DE4E78D36E750BA6770 +:104FE000FA3289B7F79ADCAF53BDFCA54996046C39 +:104FF000FF56E061E3EF157D93899632A2EC7E4087 +:105000002C3329263AEF9AAD2C5E24C69B870A786A +:105010007EEA25B061FB4C819BE78FD0C0F207BDD3 +:10502000C50DE6527E529992F6858C2C3F2F983111 +:105030008BDEE3568E4D5B9A8F99E52F0A66CD3253 +:1050400023AE2B47A4BDE4457AEB163FA7AF4E2B0A +:1050500091906E126E983509F9F716283F2D288920 +:10506000ADA3CF8BCF37D2F3B7FA059EA0B6DE62E1 +:105070005F4DF1FE53A16B91498CF1BF2BC0E157FD +:1050800085181D95208FF2E967E89D6A49DFEDD903 +:1050900002655B412FCFE701AC243DCE537F7B906F +:1050A000F235FCF96D88B7EB35BCCDB3D9C3840BB1 +:1050B000582D9DEEC68597E292CB4CFE3D5333F7BB +:1050C000F5E6F01E1A3F185ADCC76C2C15DC783157 +:1050D000BDEF388F8E09C7F4F9707F9F4AB85FB46F +:1050E000ABA0A0ADD1A504547215C63761E76FBF60 +:1050F000A2799B558826313B54B9097F02044C178D +:10510000B1AD4B413CA09E96BC74663FC1FF4E3D85 +:105110009FCAE6DF672CD5F0787D4479AC0D85FA1F +:105120002408190568EB33B0F7AC19D73D610ABC08 +:105130005D807AAC35BD95B74426BF6D7652FE7260 +:10514000E679D13703C7D56A793B5C10C3E3F179BF +:10515000A767F0E6B57138FA40C3CF694F386F19C9 +:10516000C50F0FAF3BE1C2BEBC65C83FD53BAD84A8 +:10517000CEA54740F97301B3377FDF30D3DCFBF7AF +:10518000177FB882E73BB0859FAF5633A88E34D6E1 +:105190008213F5310D6529455A425A64EFE3438C79 +:1051A0009FF89C94A7C8B767F3F735E0277FD4ED45 +:1051B000A8DBA787DD5064CACF4D3690C85F06C311 +:1051C00046379D3BBAFD268B76166F96BCC4EFE33F +:1051D0009608D19674A29FC3F392F4A5F965CF7394 +:1051E00073AB854C51B3F176169FF4B824E31FC21C +:1051F000CFBFEB5ED252A89D9BC36018E1EADBF201 +:105200001D3D2EA17D1C8571EF7FBFD53EA422DC04 +:105210006FB5B6F664B14A36935E326D3E8ACB4BBB +:1052200036E5F7E3F1F82710CF071BD3193E57797E +:105230004466C78A8E1C90F1D19D1D02C878CECDE0 +:10524000E84867B4F37C7F46573CD56F22E5FFDD25 +:10525000EF2D9F1AC8E8134FBE3932C0EF576C3498 +:10526000BF1F74398ADB291F3A674739D00E7EFB8E +:105270006A765FE887EE3A46B828108D28217F527B +:105280002495DBC5D6C4FC5ADBD71237B7E39203AB +:10529000FCDC5D3281BFDF33AB835D8407A95384BF +:1052A00010D23F3820968491B5598BCBD66C13C859 +:1052B00071F6489293418EABDF4055225427CDD6EC +:1052C00070923228CDD0FF80109048AED9F6050CF0 +:1052D000370EDF1586F92279E59D4C1F019EDFEA26 +:1052E0007802F1B499E4FC629C00E9888B1FCCC67B +:1052F000FEB879A5719F4D12586BCC8B512F472F5B +:105300008527BF8EA7C13098E129413FE81F2CFFB8 +:105310003C87E738A54D985D3C360EE91B3B2508D8 +:10532000C92CDF64FE734E4961F7F72B353DE9B8B0 +:10533000F30F048782F3BA4A8D7A4B558C7A4B9FD0 +:105340006AD453A6DFA8977EB3BD86FEFE81FF30E8 +:10535000F4E7D40C37D0B90D630CFC57364E34D07B +:105360001EF53A037FFEEA5906BAB0F51603FFC0F0 +:105370000DF30CFD83430B0DFD576D5B62A087B4ED +:10538000DF6FE0BFBA6385A17F5878ADA17F44E7A6 +:105390004F0C7449E46706FE5107371BFA47479FD5 +:1053A00031F48F3DFEA281BEB6EB3706FEF1E7F782 +:1053B0001AE809F0A681BFCCF69E819EECFE8B8197 +:1053C0007F4AF6C786FE69F22943FFF4419F1BE836 +:1053D0000ADFD706FEB62B024F1462C89F6D5A77BC +:1053E00048058ACFF28FC7219E6FCA30FBC2C474B2 +:1053F0009975DB53855A9EA6E1F60BB0DF66F27E07 +:105400007B1C5C47794126E17A06D07DEFB9768135 +:10541000E1BAAFF3D985F9AE396E1FA98A0D0BF049 +:10542000189D3ED56DA033FDD906FE7EB365437F42 +:10543000FFC020437F4E8DCF40E736941AF8AF6C03 +:10544000540CB4479D6AE0CF5FED37D085ADB30D06 +:10545000FC0337040CFD83433586FEABB63518E8F4 +:1054600021ED8D06FEAB3B5443FFB0F06A43FF884D +:10547000CE56035D12D960E01F753064E81F1DDD54 +:1054800066E81F7BBCDD405FDBD561E01F7F3E6CC3 +:10549000A027C001037F99ED5D033DD9FD6703FFA0 +:1054A00094EC2386FE69F209437FED29841FE5CF42 +:1054B000AF0AECFDD7F4419F19FAA50CCCD3E97ED5 +:1054C0001A927DF41D7E629EAEE76F15BEAF0CEBA7 +:1054D000DC6B6A60DFC57D69E2799DA3C8CBCE37FE +:1054E000CCDF6D361667F1841AC2AE5A9A283F7522 +:1054F000A902C31DA51A55ECBE3083BD576047A352 +:105500004CDFA1617E83449AC9E3A1FA21259687E5 +:105510000EB838E2BBE7A13945C0F07F5D51C05DF0 +:105520005442F5D80BE5549FDC09EA2A9203CF5781 +:1055300017BD677A3BC9786FA4B7D36CA8BFB8F51D +:105540000E24B50E187E09BF9D663BCDF8BBE7D58E +:10555000EE9504DCDF92B8F91FC2BAC98C25646BE2 +:1055600010FD0BFDF4274137A31F096633FAD1A0C4 +:10557000CCDA0DC141ACFD59D0C7FA37064B19FD45 +:1055800078506174283895B59B837EF67C4B7036D5 +:10559000A39F0C0658BB2D58C3DA67820DACFFD908 +:1055A0006023A39F0FAAAC6D0FAE66CF5F0CB6321F +:1055B0007A477003A37F1D0CB1B623B88DB5BF0920 +:1055C000B6B3FE9DC10E46EF0A86191D0E76327ADD +:1055D0006F30C2E8FDC1838C7E2318656D67F0389B +:1055E0006B7F17EC62FD6F05CF33FAB476DF3FB502 +:1055F00088E75FBA5E741A6012C3839ED7CEA4BADE +:1056000085C0512A9D35D42D09F543A23D4E6AEB44 +:105610004813F1D8A63CE78AA2CDCD71F9FE7F16DA +:10562000F17BC10792414DC2F8D744C53C42B12934 +:105630000D42CDECFD2ACFBBAB355C4206CFB71790 +:105640006872556BFE5042F81CC4F0F9D6E5D44997 +:105650007A9DDC322030BF08DB85B92695DD13D872 +:10566000434594F73F3520504DB83DD770C71B6C6C +:105670003DB7AF8816A9B086336FA2FB9F0322BB4C +:105680002FED6BBD7AEDDF2FF4D9BFEBC4003A8765 +:10569000A67E23B2FBF4B725C76CBA1FB94FD3CB94 +:1056A0007D4526433B34D7DF48727E52D8F0E4DD97 +:1056B000C852B5B8D04579EBF5545AA3DF57822CC0 +:1056C000B1EF6341799D3E99FC01267644DF042ABF +:1056D0006B3B72024D34FE662C20880E8CB1E6F5D1 +:1056E000B69F44791ED470F16091C9D04ECFF5AF0A +:1056F00025FD1C2D540CF2A8B9B2F6BD7BD7E324CE +:10570000D73F5EFBEC98901FD3B77E2FB16A82F62D +:10571000FDD462417F4FCDF3411BE8F920EBAF5A36 +:10572000CAEF677E887519BDAFFC508B87E71A24D6 +:10573000162FAB84641FE5D3E71A960EA4FD24C68A +:10574000CD2A1C67C27155C0BF87A8FA3085E10B0E +:10575000E7037AEF5685993BD57F77E7EAF71E5145 +:105760007B269747A1F7B073765ADBA84E459C3C41 +:10577000CDE2D86851B5609DFCB6295424880C1F31 +:105780001601E5ADCE407CF49217E83858A4FDFB35 +:1057900018FD39E26B3BCD77F6955183D87B935D4D +:1057A000A365D25FB309ED41F735BF13F9771274E2 +:1057B000C54EDF71B88ADBD877FE944490BD463B76 +:1057C000D8FB903D2234BED04BFC7C5FB3DBDBD9F1 +:1057D000D2D4109BD7F89EEFF71AAE7EAFE1AD6240 +:1057E000EF81DC7B71DE459D12AB776064B4D8DF5E +:1057F000CBF74DF58D6FF62F88DB477DC711FE5D2A +:1058000014448BE3BF873AADCDABE349B438026DA6 +:10581000F678F9388E10D7EF911E10D7C728AF9FB2 +:1058200069955D37E1D028AA268C6DE00937FBAE7B +:105830004EFFBE6E3EF8595B8D70201CFBD5F5AC5B +:10584000FE5D08EDECF9A2D2DBF388AE87AE49D954 +:1058500054BFAC6E7A3D1BA5BBA175FD64BA7F9E9B +:10586000159AFB3AB5955B84635477A35F1C25BFFB +:10587000880A0D2BA924BDE5D9092BE99E77A6C876 +:10588000ED006F723B208E1431ADE7FED00F4ED18C +:1058900078F40326BFEE07552B387EF47F8FD1EDC9 +:1058A00017A577FD3587DE7D98BBD87721F5BBAC92 +:1058B0006984AF8554798AF179A17E3EF3BCE02EEC +:1058C000CC0B88EFA4C4ED7FF25012FB772F270595 +:1058D000C4C7F09EB8D7F3CC2F4DFCDEED5E11B7F8 +:1058E0002852BDFC30D3538D2D3494F484E7B33467 +:1058F0009070FD71FBAA6174DF37319447F9AAF407 +:105900008CD5D7EC31C479B89812BBC77B48E2F785 +:105910006A89F2F6C85B4ADFF88AF209AB05547A65 +:105920009F84FECFFDFE3097FF4B5320FB1A91E77B +:105930002BAC8E1EE067F53F64D97C6B859EEBB780 +:1059400068EB76FE93D7D36A2EB0EF7112E510DCC8 +:105950007CDD4479ACC95C0EFDDCE9290FB7832EF0 +:10596000CF90811E7E2EE6296CDF4DA65416BF3ED9 +:105970001503C5A437FD7E4CAF633B3D9FB0B80E09 +:10598000179A07F0EF7BC37D9DA7A7BBEB676FEC72 +:10599000BCD3EF99605CEFF7827E9B5B22BBCD02AC +:1059A0001F8BFB83E1435D3F867BC2FF035073AFD8 +:1059B00086E0390000000000000000000000000048 +:1059C0001F8B080000000000000B7BC4CEC0F0A3BA +:1059D0001E822538106C62711D0B03C30756D2F569 +:1059E000C17025507F0910E703711610A7027102DC +:1059F000104703711810BF069AFD0C881F02F11D95 +:105A000020BE0EC49780F82C109F40B277191B035C +:105A1000C35A36D2EDFF83E4E78940763910CF24AC +:105A2000231C46F1F0C0F23C0C0CDABC08FE3E5ED2 +:105A30005479051E047BB92065766D03EA0700E9F9 +:105A4000CD424A800300000000000000000000007A +:105A50001F8B080000000000000BD57D0B7854D58B +:105A6000B5F03E8F79253393C9839040C493970452 +:105A700009382421F2AA1E0842A4D406F42A5AAEF8 +:105A80000EC823869044B02DB7729B21092F411B6D +:105A9000152D5AB483458B0A36F268D106EEF028EC +:105AA000C65BB4D1A282D536D45B450B4944116F95 +:105AB000B5BF77ADB5F7C9CC393349406BFF7BC370 +:105AC000C7B7B3CFD967EFB5D75E6BEDF5DA3B76E5 +:105AD000D9C5E42B19FB027FA09CA330C60644CA9B +:105AE00051775EBB687B09FCFE99DDFFB8166967DC +:105AF00094173389B1D1F09E653056CAD8954EF8C7 +:105B000015DA95BD70EA0F97A531B69F29CC018FA4 +:105B1000C26A59EAB7A09FFD9F333FBE975F706787 +:105B200075B8F1BB2063E98C5DC1F877E16C2DCBD2 +:105B300057881526E373DD49BF433FB99BEAE0FB75 +:105B4000B39FBAE97B2B1C46C93E9759587CF34555 +:105B50000EF6AB7EDC5120EAD90C066702DE2C1A69 +:105B6000D780F7D0DBEF11BC075480578B33BE13BF +:105B7000E04F8BC0BF9F5D9BC40A39FC7A6904FE6D +:105B80000B8587E60F786EACD7BE9997CFD8BA7AD7 +:105B900046E5DA7A2795ABEB7DDFCCB331B6B23E82 +:105BA00083CA46153E01381AB7B0501050EF2E8404 +:105BB000F646FFF03F21CF69AA3BB37CA6BA3D0D64 +:105BC000FA2988D455B766AA37BA2739036E1C1F3D +:105BD000E6EEC0F19D5402984733001F978A79BAC8 +:105BE000B4E02C06EB91E7B66B2180E352F782E933 +:105BF0006C24B6CB27BCD9055E9764367420BC1FD5 +:105C0000433B06F31DE69EF23EF332F69FD94FF07A +:105C1000796C606C203C5FFDEF751D12F4B732D3D8 +:105C2000AE35407F4FC0F86B1C5178DCAAFEB9033B +:105C3000FA74C23FC4E3D08DBC1E9937D4A3E631B9 +:105C40008C45BDCF8EF473A1FDE6379BEBD67EF37A +:105C5000347D12D2ABD16F3EAB68F0B9FFF7F67B63 +:105C600029E03C3525D2AF314EBFFD023954C0B7D3 +:105C7000F91B59289C1D3B4E9EE62F0FC2FBBC8D85 +:105C80002A0B65F3E769C01779FC57D6E49B94109B +:105C9000288C8587458F93135997BC34FB1C19E8D2 +:105CA000292FE3FA4512D25573D4FAE63066F0CDC7 +:105CB0008FEA7D4C1FCAD8DDF505546EA9F7E9C8F7 +:105CC0002777FF5D99D55218CB8F7F11F2EA1E1B03 +:105CD00023FA0B3ECE428F4BD85FC5AC39505F3FA5 +:105CE0002ABDE82E8D885C4679E61274BC5ED26EC1 +:105CF000C8C1F6AF280CE5A0951FEEB6E9D3B0BF3A +:105D0000B5A364A901F19CC7F921CF1676E662BF5D +:105D1000CD39A382D88FFF55E287BCFC4B3405C632 +:105D20001D9627F861F4834E94873DF35F96AEE7A6 +:105D300015339664A103DF79D2816F42DF74F07569 +:105D4000F1C3D7475FCD7DD2D77AFF7DEF3BE0FD32 +:105D5000963CBBA664C7C295797138A3C21D4B6F30 +:105D6000797982CEFC7DD399B57CB03EC4DE011A30 +:105D7000BABF3E83E8EEDE7A8DCAB5488730EF07BA +:105D8000B0E958A8231DE2B8D71551BDD77D8BAD1A +:105D900020BA4C9FD5CC50FEDE8FF4390E875BA91C +:105DA000EB1360AE79A20E5BA40C7BC0BDF87E1035 +:105DB000D575DCCAEE928CF6CF0675C0778A683F3F +:105DC00075C5B3C146F8FD7E17AF5FBDA2530F6620 +:105DD000457D1F5CA7EB5991F6500F4F52A3FAC3B4 +:105DE000FE0BA3E13948ED8DFEE6AF38A10701BEF9 +:105DF0007B5DBCBFB52B8EFD53FA5F2B053240B5E2 +:105E000060AB2CFDACEDA9DFAB231E8C7172A45FDF +:105E1000E8C1E8F7C16774DD1D797FB9746F10DFE1 +:105E20006F64157912AC43E6F48A0C06EB6FAF6829 +:105E30000EE296DB039FC077647E0F12BCAE0CFEB1 +:105E40007EC48ADFEB8D51EB3369C5CB4184D7D05B +:105E5000731441AFF20B594B8F00BD2A49763FE9CD +:105E60001BD701D364C278B32A980670C969150C90 +:105E7000E58192A6BE1BCD0706FD019C6309CEC934 +:105E800015B37A8133180DA701477F701B70F44E4C +:105E9000A77C7C2B3D4DBA66CCEF26C0FE6D6FB75C +:105EA000F9515D48453C4157ECF35B8336789E3AA7 +:105EB0001370ADD1BACD62B9B1FDA64D1FC4425128 +:105EC000FBF73F7A5DF3B0CEF116885E5FA8CF9501 +:105ED0000644F03856B4B3D29F313F5BCCFCAE35AC +:105EE000CD8FA9818C0A4FFFF3BBD7E59F55E18E7B +:105EF0006DF75B49A2F1274D19F36DC6C7630E908C +:105F00005FC9385E5164BCE469301E76A636C71D91 +:105F10002F65328CE7FCFAF069E547035E7B0CBC29 +:105F2000B79AE05D6B03BE8DB3FE5F37BCE7CB7FF6 +:105F30002E90BFC47F797DF3DF3FBABF64FC153E6E +:105F4000F94865E12B015F775CE524FDDE9073FF86 +:105F50006C7CA5E2A7B07E77BC547CE24A192B404A +:105F6000D72322E3D74A1AED57BDD1776FF3810DBE +:105F7000D6D4CFFFAFF9F486D7AF5B0E9DAF7C6D63 +:105F8000783D81213FAD2C642107F4B1B2ED2AB2F6 +:105F900037571E291BC8A05FDB9AE14C8749256350 +:105FA000FFD0DF4A43CF985CD24FFF5CCF00FB4E5F +:105FB0006F02A56BB7B782F4A29512A3EFD783DE69 +:105FC00016023DA6E4950DCE3958F7EF70CEC1719B +:105FD0006D8CF4E992570EF9CA80CE5D23524629A2 +:105FE00040022B5DC6F3A3E5A8E7DE55289E7B782B +:105FF0007FF0BC02DB2788F6BDC1959007F044AD69 +:106000007FA2BD395011477FD76599F0F390D0BB7F +:10601000EE46BD0B047262424B00F56A57BA5D7BD7 +:106020004C8AFDEE265912F306BD0DEDEC115332EC +:1060300051CF3A30E389157684AF90915C77E5854E +:106040007419EAEE02CEDB0F59F67D37AE21E95D19 +:106050009952994ADF99EA77F7E831D913516FF3EA +:1060600016F0F7650D574C6C8C7ECFFC1371FF3525 +:10607000DE071A4AE97DA6B3E2D804183F13E468A4 +:1060800023E02B536D96EA685DD3E2EA8F1BE63B73 +:10609000678500860D331ECC9E1F673F81D534F186 +:1060A000E9A079663E7B48E0EF6E81CF4CE4F5D104 +:1060B000820E41BEB978D31EF9E61ACAE55B4241A9 +:1060C000F30AC4F7A079CC8FFAF686194F90DE6AEE +:1060D0008CE32A30CBB94CD53CAFAF6B3E1B99FE5D +:1060E0001D7974EFFD5BF96C230BDC8AED33C57E03 +:1060F0009E5010920285FDCFDF3ADFDEE6FD2DC413 +:10610000271FA74E1E103BCE3F0B2F996E18A7E4FA +:106110001F3F4EC23CB3BC3C5FBCC33E20E88C2951 +:10612000B81F58EDAB84129FC464AAB6A31D4EF2EB +:106130001BE0F6B0E6F24B80DE522B56DD2E83DDFF +:10614000EC79EBEAF7D1CE4EED9843F676536151F8 +:10615000DB246897E4F7CD984274CA08CF6BB1335B +:10616000E2BBAA1513615E8D8CF3DD66F996895C3E +:106170003FD069BDBF2B70062BAEA950477665395D +:10618000F1E66167613E6FE90B47ECF7BDCDDF16C5 +:10619000F94EF8FF9690DFB4BFEFD8743BF9118346 +:1061A000F00FEDD2644B3F49BA3DE2676488A7A87F +:1061B0003ABCFF6D0F5FDFFE4F19CFC7EE736A4029 +:1061C0000AB63CD987F67A12F325AB2867278342B3 +:1061D00000A2D897D61D94B5FED7A589B1F29642F4 +:1061E0004E7733A2F4DC0E99EBC969332767AF848D +:1061F0007ECF9670BF70AA0FFE17C5CE671DEC6BE1 +:10620000E1283FC7BAC2C7887F1B819E72802F8258 +:106210008532F9B7D7E6EDF045F3B5AC18FE6D2B36 +:106220007D304D2D15FA1FE047C99375D7C8AF4E85 +:106230001FCA97A48FC4E951DFB10B5FAF24E5C239 +:10624000E8E3AB8E67AC6B2C5F71FD246DE63C27F9 +:10625000EA3BAB326626C593B3BDAFEB7DB4AEA8C7 +:106260004F84E2F49FA64871FD39567D9EB1A5A6E4 +:10627000F5520696CEDADCD7BAA599F161F4EB5A5D +:10628000A668FF85C24BF5915FDC29FA5BABDD1791 +:10629000C4FDF32CEEED800FA5795418F53D96C79B +:1062A000FC8FF326A487B8343D443A24CADDD208D3 +:1062B0007CF62CD9349E9A9660C2379B05DA761408 +:1062C000FCAE657682C389E3C1388A0F3A94D0FF69 +:1062D000CFC22E2FF548FDE1505FE462FD4E131D45 +:1062E000ACCE2A8ABBDFA9625DD16CE5F47AE7F90E +:1062F000C917EB78D799E13DEFEFDCAAF66E1CFFEA +:1063000071EC772A7BD7C01720F1961E7AE7EBB4A1 +:10631000CAC6F64849200F32AE67010DEAF80A36C0 +:10632000EB35588E453A2CF2915EB05552114E62C3 +:10633000690DFF737DBE10955BE84F7606084F8AA6 +:106340005B67D45E3B3F7DFF9CD0AFD3843E6FBC88 +:10635000FFA162A77E5556C1D06E3EF7F6D40CEA77 +:10636000578747A51138ACFD162A811F2A0390ECE8 +:10637000383CF801FA09584701F9B5F305CECE3D8E +:10638000303389F5C15F0F59F8EB2189C3C92ACE93 +:10639000CFCE380763B6637B359040F1B29305C426 +:1063A00007B962FC27D6CF4DC0F19FD8D8379F1BC5 +:1063B00070FCB4DEC9C2A0A786EA7D541AEF43C2BE +:1063C000DFBF59D831C6F3738A4C70EC137CFF845D +:1063D000B32281FCE7076F9C360CF82BE7A8E24755 +:1063E0001D4F5BCB52FA1A3F3B68E637A6CCEE1343 +:1063F000DE656F4D9C71288A1F7FA178D2DE1D0E4D +:10640000BF5CCE2E47FAEBEFFB73F5FA8C43F95FD6 +:106410001D2F9B85FD79AEF1772B48CF095F49FC95 +:106420009923E448CE3C2E0F72AB594843FEFDFC45 +:106430000B164D1F6099109E32AB558DFC4D4C775D +:10644000CF81F743C5DB4C65BA8C5BF850D4BF50A5 +:106450008E6CE2FE73C3CF0FEB7E17CAB9CDAF29A6 +:10646000640BE7556A0DB8DE39EBCDFEFDC12CCAD1 +:10647000EF8EFE7AA1D7655AFCF85F751D3A701D44 +:1064800012FFF9EB105219D19D51D72456116FFF0D +:10649000FB44D0A9B6E210B743C0F87B272A1E01FF +:1064A000EB99829BC04F83F74D44BB35B886F9F317 +:1064B000E3C84B9B9A48746F637A7828FA0FE65CBE +:1064C000DFB117E5D50466925F71E4864DC5EFD262 +:1064D000B8DC080567F2F27385E265F9EB5908E369 +:1064E0005B9337D4ED47BF5E6635B79B33D7042542 +:1064F0003BD473EA981F87C9AD64BCFD6C16D27992 +:10650000BCE66806D0CD104137430C7A5966A69791 +:10651000C17596B8D01A737D20D2057C37D0422F32 +:10652000D67E723446F1B8BCF5328F17CD32C77DB6 +:10653000F259F7FB3F0778F30FB9FD61161B6FB2F5 +:10654000F6AFB24001E265F70FDDFF590013FCD949 +:10655000FA49A98817902749244F2AE2DB3D31F4F4 +:106560006AE81BBDB48FC84FDEAEB7F7ABF2D39766 +:10657000CE0538D67A7446E307B349AE2B225E794E +:1065800030F37A6707FA6DDC4524DFF7631DFD3CC5 +:1065900019970C8C96F78AF02319F546E147B28ECD +:1065A0003755E57AF07B4C9F8A7818E50864605C83 +:1065B000CF9691BE730E8C67F381BE15E7BBB16AAF +:1065C000029FAFA6FE2D1AFFB071FB481E32BE1F00 +:1065D0003377CA79E1A3440DDCA442199C04660414 +:1065E000D27F0E0B35E2FAD635F3FD2DD2EE16D161 +:1065F0002E8879053DED02D06E84A9DD3C9C0FB458 +:10660000D34DED2A62DADD26FA63A671F598716B37 +:10661000447FA4CFF5B4F3C7F4B754B4233DB0A777 +:106620009D16D3DF3231AE6E6AE78B69F7EF067CD9 +:10663000A6719979DC9EF7A576E33DF9630FE44FE7 +:10664000217A39943FA57C2E8CB3F4451B97115BBE +:10665000793E874157FB45BB26A4AB42CC5B6163C7 +:10666000AA294F85E7AD34BA673A0351CF7BE8CA10 +:106670003DD317FFF95C537B758D8BE9C5F49CDA2C +:1066800037FD5D11F1AA1F4C427FEBEA3459F8DB6C +:10669000AE69D05590630354537D4D86786FBBA689 +:1066A000810262223E02B2F29B8551FCDD33FE3F45 +:1066B0000B7EE13F8EC03FDB02FF6C33FCA2EECCD1 +:1066C000E4EFD595B327E17C0CFFF2D9A6E50D41A7 +:1066D000F7FFE6F95559E65765995F95697EF69596 +:1066E00055938279FF97E6B7CC32BF6596F92D3383 +:1066F000CDCFB972D905AD9FB5DDDDB66692B76B6A +:10670000F35F27FD7FAD88E326ACD41B56E07BE02A +:10671000ED76EA4F23F93E8AE99FA33CE8EFBB47B9 +:10672000548DE482D323935C60F9F6507E36876BF8 +:1067300026C885E7541F97DF02CED72CF50F2D759D +:10674000F8E56FB86FFA9861475AE47C3FFBDACA04 +:106750004CBE9FACF2F8E5E87D4D15B83938A094F1 +:10676000E44FA38FCB9FFD03843C4A837D8DFC4483 +:106770001924AF6C425EDD57CFF3D89A457E506343 +:106780005A11E1A759D80B2C9465DA370F4C9CD2DB +:10679000867EAB334779DEE23A1BD7C756D6339DA8 +:1067A000E8ABDE49F945FBA0DF003468057D0FCB7F +:1067B000E741DFC3724F7D0695BFACD7A8DC01E38C +:1067C00062F94CBD9F0560FC6DF563A8FC31EA8B56 +:1067D000503E20F4C52BD264F2576CAE872D339F08 +:1067E000F4482A1FA9F78D5561BC9FD46750FD233B +:1067F00069E6581BD9AD1D8D4900E7EE57F3285FB8 +:1068000069429A4AFB2F53C34A5249E4B981D78F50 +:10681000A44957E077E33264DECE196AF4C66F57B5 +:1068200086EDC664A8040F7307156F5ADC76E5364B +:10683000C04BA95BF4E70B347AE2F7F72D6C57E411 +:1068400016FDA5698DEEF8FDCDC47147FA381E58C6 +:1068500046474362FC763760BB429F986F56584E5E +:106860008C3FEE6C1C3725A53980F1AD2B6733D2F8 +:10687000476D69DA66292A3E141A50C164A0F39460 +:10688000D4E63A6CF78D809FE5C0F89AD7CF64A024 +:10689000679B1BDE17624E138F478DBF0EDEA33E34 +:1068A0008CEF4744BDC7EFA11C3B4B7C9F647EDF50 +:1068B000A397AF613D793C98BC646B32D79365CEAA +:1068C0009FCB571E98847C9F6CE7EF7F8A75D4B767 +:1068D0009633431EF1F609FCFD8F8CF65EFEFE1723 +:1068E000A27D4A0A9FB76B8A338471B147BE7B4948 +:1068F000E6DCC2C87C2FFA5EC1B0B951F37BE47B01 +:10690000E332E7BA23F3B9E8FB1386CDEDC3EE49D2 +:106910002D977B7264516E25371792FC1CE5A820D9 +:10692000B9336A60A98EFCACACE770FD87EDAE862A +:10693000863C822B88F2C680EB278BCD700DAE3162 +:10694000C3F5931A335C836BFB866B9D8DCBB5DEF1 +:10695000E083F1F5E8F11FFD37F3F8437E601EFF99 +:10696000D11F98C71F72E7571E3F1CBD2E9B6E3765 +:106970008F9FB5C43CFEA625E6F1B3967EB5F1FF28 +:1069800051FA78922D70C426F45D255AEFAC0B981D +:10699000F45368F78A681754A2F5D840C0A49F4200 +:1069A000BBD76D42DF35B5AB8869F707D11F338D93 +:1069B000ABC78CDB21FA0BCBD1FDF963FAFB8B68FB +:1069C0001794A3FBD362FAFBC080CFD4CE17D3AE0B +:1069D0004BB463A67199795CF82950A19FEFB30479 +:1069E0003FFA47964D5E4371AF812C20A1BFCF97F0 +:1069F000CA461D82EF592ECFBF4F9EB2EC62B43B08 +:106A0000D7249BFD5CE9766E9FD9EC0A95BE44566F +:106A100047F900CE60E68CA87C8B6A3BDFCF7ADE3C +:106A2000BB8399D746BD1F28BE5F23E2D469F6D247 +:106A300046942BBEC1D03E8EBF22538C6BBC67697F +:106A4000FE761DE0DDF8AF3347A3BF2832AE8DB729 +:106A5000BB588C9B151FAE35D97CDC45386E213E6A +:106A600037F48B6026E1D7C74BE3F9839EEF49FFEC +:106A70000578593DD9292B49F07E3DF76F1A7EF6EE +:106A8000647B9D13F3761B2F92D963D82EAB6F3F97 +:106A90004E53BDD9DFA9FA2A74B4F70655FA8A1401 +:106AA000D6FB770F97CBE5F1E20DA3C5BC9A2A2759 +:106AB00035E7C1F8EC90D96F0B84CDA2F3610A954C +:106AC000C0687B3CBF6D538129AF3E7950DF7EDBD0 +:106AD00046A15FF4CC033A8AB77E370AF8D8C602DB +:106AE000939E959C3293F4ABE486AB9DBE38DFADAC +:106AF000B5F4EF6233756C9798D6CC64EE5C34E9EC +:106B0000614DBEC7F83E94093209E33F693BC2C8F4 +:106B10003F674BF8790A3523149428CEC1E7896A78 +:106B200025FE24AAE1A00CED076D54593895B1FB60 +:106B3000E5C08D881F575E33F9C7549F2E219ECE26 +:106B4000D94257D379025017E3E57FCCB3733FF0B6 +:106B5000C3DACCDF65C759C7DBEC9A492F1DF4A90E +:106B60009D858B7B6F1F69C7E1EAA1D30CA04FE421 +:106B70006F8DD3E9ED8ABED84EFA5A968FFC8E8679 +:106B80007C35F85FC4B7E78E61E247BBE10F308F19 +:106B9000DBDA6C3CBFEF73681D15F7B94DF8BFE643 +:106BA0008A78F73C56E1C597A7995C8E7C759ABDAB +:106BB000EA2D8E5AAFB5763B1F678D8DFC5B463C48 +:106BC000777EB3CDE4EF5AB8D15C5FC066A6A35C14 +:106BD0005AB0C1C6F07CC76D167FD8BFE17C615E3C +:106BE0000B59DD2AD4D38DFCA0B93EA662FEF7E294 +:106BF0005F3D528A7943CD769EAFF301D08B16C5A7 +:106C00005755EE901DEDF97776155F3F9EE1F7A1A0 +:106C10005583509E26B3B8E78C6E5D6386AF3FF810 +:106C2000ADF032D640F0F60687BA558AEBBF7AD47B +:106C30002E99E244CB9CDE910CE4CC39172F7BFCDF +:106C4000297F74917CDF27E80836C0CBB89CAFBBA6 +:106C50001CCBFEBE3BD8CB778B9D1D76E48F5AB5FF +:106C6000AE5C92237126872DA00F86EF6C7B268663 +:106C7000073353BB35E7D9AE4DCA39AF76E5721F3E +:106C8000FD750A79F9C2B69FD9D1BF78FAA913D791 +:106C9000201F2EFAB5C29CD0AE739B8785715F50C2 +:106CA0004376942755BB94B871598AFCC3FC17FDF1 +:106CB000C24372A26A8723341DBEAFFAE53B231993 +:106CC000E0A1B3A1FBF060DC479F92787C34D8311F +:106CD00012F7AD2A95DD122F4FEC84A0BB53CF25C0 +:106CE000CEC27595B6EEBF99FA6DB9C1E688920F1E +:106CF000C7C4BE04EDB87FED4929941F477E18F143 +:106D0000AC534F4A1CBE3DB6900BE1DBBAD91E0016 +:106D1000386AB77E487454F68BED5EC443ED1EC5E9 +:106D2000E4F7ADDDAA841D23A93C8125C65124E0EA +:106D3000EB1AC6E563CDAEC5E40FAF6959F7A1E222 +:106D4000C5EFCDF40C78F18711AF6F28FEE958DF5D +:106D5000F973AF06A8FAA0FD712FE215FA9D634FF3 +:106D6000C278AED98F8DFD7F9A12DB1F63DD76A4CA +:106D7000AFDA96B57C3C0BBF7C80BF64C6C64F9C27 +:106D80000E4B1C6B6BEA79E9898BB69F7D3408E367 +:106D90009DDAF1D74783B87FFFBF8F1EBD13F59AE9 +:106DA0007D2E1FF27BED53AF7959D43E98E3E07C02 +:106DB000D7F9E4CF9F7818F8A4F3B8838EEE75EE78 +:106DC0007D6F8806F3ED7CF6BFD335687FC7DEABF9 +:106DD000C8EEBF6377D9C0BEF643A4D350F43917C9 +:106DE00091C7A4ED9150D902435E94967539B84B82 +:106DF000612E80F3F4314708F39A6BE1D9B2225C3B +:106E0000A7C5247FB1BE1CF05BB36DF587CAC878F7 +:106E1000780E0E9631C79E01BB64E03A5FFBED6FC2 +:106E2000946069A338492DEB26F969FDAEF628ACCC +:106E3000E765BDAFDF59F6B91D8378B5DBD6F271D2 +:106E40002DEB771A7F191BBB7EBA65FDCEB2EA9F88 +:106E50003E8C2F77A5C68DE71AF1AFC5BBFFA54FB6 +:106E6000BDC99003FDE1B752E270791C7A8503F940 +:106E700069C7D34F3C9CC6D7773A20A473FBD9216E +:106E80000CE8E3A4ADFB66948FDD7B1D3EDCCFAB4D +:106E9000F6BE41FCD5B9FB15BB46F291B925D0131E +:106EA0003A59CF4F3BEA0D3512AFD46EF1841DDE57 +:106EB000C83AD58466946B5E7A7E829E8738DDD729 +:106EC00084F65F27C559B7D58E1C2E8F433C696F5A +:106ED000F1963FD899DBBC9ED2185CC71353F0796A +:106EE0006FEB68CCDF87F3BF3C6A3DB7707EED8DFA +:106EF0002F3B373B54CC4730D6B7D3C6F5FDDA909D +:106F0000F4068BC3AFC6FE76A1F1D00687251E2AF4 +:106F1000E6DB1F3FF73F8F0BC3D3124CAA1C1D8B20 +:106F2000AF539FC797EF8F382401475DF9A0DCD896 +:106F3000FD496515C1C1D911784F8973B3A79E5218 +:106F4000424178BEAAE520C969AB5CA8E9454F7EFD +:106F5000C6186FCFFE9128BF4E1D788EE8B066DB55 +:106F6000093BDA4787B7EEB4771446E81EE57F742D +:106F70005EE4A967F68F24398DFDC7599F5F0B79B1 +:106F800057DB6AEEBF76DB87A6FE17055BECE417DE +:106F9000ED679C0F54FD069CEF07ED368679F71FD1 +:106FA000B428E5F1F49B90C366CA835AE5293D866F +:106FB0007E4525C5AEA1BC6B5AA1BF11A4738F3607 +:106FC0007EEE51D58F39802F1B93ED1ADAAB4D9E93 +:106FD000EB991625B79B2DF8F4A5F926625CCD3701 +:106FE000B9A224DA7E32E04FD66513FC7778CA075F +:106FF000E27909B4C3344C3250FDE45756BC53CA4D +:10700000713E8A4FF6B9E2EECFBC3FF4B721FDDB0B +:107010007C32D3A2E86B54D9F5C3D1D5A632CD9436 +:10702000BF7AEF641EC735E67FEF456C1303B97B6B +:10703000AFD4DD86F9ECC1AB795E201376BA17EDDB +:10704000F4EC587D8EE9BA86F287C40F6FCF7423B3 +:107050007F147EBE0FE0C898BF23FB4999FFBEA2F4 +:10706000533E8F1DC7CD45FB2944CF135998EA8A5B +:1070700093CB1F0FABA3E749ACA319CF30BDEDA84D +:10708000F8D401CFEF2B4F9138DC61CAD74816E313 +:10709000C88959997DF13F9BAC9E8AF6FB38D8266A +:1070A000B24BD0EDF8456A040F463E9CD1EFBDAE21 +:1070B0000912EE3738BFC178AE479C9FF7F5CC5721 +:1070C000A7FA00A36E19075BFA4AC5164BAC1890D5 +:1070D00054056F0D68263FC720D64265166BA73250 +:1070E000C5E9935482EF2DF24BC9ECCFEC8B440BE6 +:1070F0007CE7A18F9F93F5E301281B6DE2F9DB9EEE +:10710000D0E350DF90CC4CE783739D9CBF2F77CAB0 +:10711000865F26106D7735B26A9ABB2B8D1F63315F +:10712000BEBBDE1918EE8CA227C5DDCEF3BE84FDF2 +:107130006BD8EB5729CB29FEBE3A83DBD5BDADCF4B +:10714000CAFA0A935D6D2D9B0738E76C66043FF71A +:1071500053494E7E7E59679A2F9AFE605C67697428 +:107160003EA3AE937D2FDEDB607AF8D28178546245 +:10717000E96F06D2DF68A4BF0ED14937F9296E57EF +:107180000257E37C33F2EA24FE3C2071BF97AEE065 +:107190007CD345FF72627566A08F79B259401F514A +:1071A000792D1B84FDA8AA4C4D284278368975B7E5 +:1071B000D2A5393FD5D0D7DCA2E6107972BF2979A4 +:1071C00095CEA3A8696ECA4F719734DD8EE77C55C2 +:1071D00056E743F9E936F24FFC3C9FD0B08B5D0592 +:1071E000E63C4E87256FD526ECEF983C6EB1EFDE7E +:1071F000830FE2E8C3D67DF77667FC3C2436267E13 +:10720000BEA0A1879D2FDD5BEDC86A67FB611ADC1C +:10721000A7539EA52AFC0D13AFF3911FBC6B9BC413 +:10722000CFAD59E8A86B47D2489487C8BF78CF45FF +:10723000A2782E6DDBBF1FF5A6262FD3935348CE21 +:10724000694A2E9E971AE594A05CBCEBC3977F8D8C +:10725000FEF55685E1D6DCE536E2937A322E5622EB +:107260005B6F5ADF0B9D4F6C5C91F3DB129FC16F1C +:107270006EFAFECC3689CE4F296CF88FF1FC436D47 +:107280009B8D85E0FD19C6FB3FB389EB030B5F8443 +:1072900051F03CA8181FF7A5E8FD23B53C8169D142 +:1072A000793C41BD1DCFFFCF13F8185091627AFF92 +:1072B000D7B9E56DE49F09F07B0006CE1A64EA6F4A +:1072C00091B27C2825E1093F8606FF90FE8CF99F4C +:1072D000930376BE4F542485499F01FB17ED86909A +:1072E00044F94A567F47CD1E89F6A7DB607FC2F37B +:1072F00038B7852CF6A3258FCEC0B7952E0F3985CC +:107300007DE066EE5EF0EA0F97507C94F86AC98BD8 +:107310003C2F6CC976294479CC1D439318E159213F +:10732000BFD17BACEE41D83922F46BC19B23C38C17 +:10733000679766C673628119AF1EBF198F563C27C7 +:107340008DC931B55FA454DB89C8049E0BE01FE2F0 +:1073500019E420CDA306E611D662F159D97AEF2AB5 +:10736000F46FF48B470BFE4E59F07796B5EEE76F4E +:107370005985339D589BE69DA986897FACFC66E0C4 +:1073800029CBD73E919EF93DE42FCE109D48F3F8CE +:1073900077839C2D9C798AFCC46F467E7062CF7E79 +:1073A000F90EFB02CAA5330E9D98CB62F96B1396BA +:1073B000C0D72DF54EDFBC7C8C4F33DF3C1BC6ABFA +:1073C0007D54C6D947A97FA047DA0FEEC1B8641A29 +:1073D000F2B54AF12B5CAAE9504F6CB5F9D06F7940 +:1073E0004F51F735A8B7D7CEE7798E372770FFEB27 +:1073F0009204BEBFDA12785EF35D1532D3D1BE6F50 +:10740000554212FA8B7CFA8B57A2DED56AD3685F9D +:10741000F375BFFC1D7A5FECC3F86EA6DC3C0AE195 +:1074200080F6E46FEF6A7DC77B6B94BED3B9E7FE4D +:1074300061B8EF3C24B3CA787A7CBE8BC3D159F0D3 +:10744000E77424C7C5CE6EB2A35777D455E0BC0C01 +:107450003BC2BE8BFBB76AF6CC207DF2D0027E1E0B +:1074600073F7297E1E738A32FB9B23A03EF6359567 +:10747000CB4DA64F9F93CE5328701D3760BE24F28C +:10748000C17FC9A106C24FF3EF314ED5F81795A1C0 +:10749000FE5852B780F69F5F7BA7B46159AAB71414 +:1074A000235F4F6E4D9E88E7646ADFE27995A3DB28 +:1074B000CDFE1CA6541F443FD8D9637C5BBEFC980C +:1074C0006AB5BB14DC8FC776989F8FEF876ECB5C55 +:1074D000623FF2B2F40BC98BFD91AC4F73917F9474 +:1074E0009FE3F2ABF1EDA74713B87D037891504EBF +:1074F0007575337F03E0A96BDE209A6FD7C7FC6AEE +:10750000A6AECF95F278F6D12D2E4E2F0FD979DC7D +:10751000F6A105EED00A98C781055517A35DF4C9F9 +:10752000BF052E8E17A788D8072C49A63D4F4F625E +:1075300063902F9AF8F932D69C19EFFCBCC10F0664 +:107540007F187C91B9202110CF7FF98E8BCF6FD21D +:107550008202CA83EDDC27518CA7B301E0EA038FD6 +:1075600041D63018E1A9DDF311F9179CADF1FDD03A +:10757000F5784803E9B621B8623CE0EB7BC0D44122 +:10758000E4077B7376BCFE836C03F99B16B834E288 +:10759000B74E27B7A399DA9C39D3837C5276F52A64 +:1075A00080F361E03F24F9876C7E823BB89831F22A +:1075B000AFAA9CFFB3AE619BEF8AB2B7D6BA263EA4 +:1075C000E082FE1E70F178476AC02F21DCFEBF9F6B +:1075D000F362FF5D9F3A68FD06093F8FF15D8BC046 +:1075E0004F5982FE23FC9E55A69130F407BCBE790C +:1075F000B0FF5FB607F01D27BFCBD077520220FB4C +:10760000009E14B74CE756D0DE427BA296193F414C +:10761000523E0DFEC34366783ECB90B752AB14F694 +:1076200080DC2C71BAC3E84F49A98479633C8A395C +:10763000797FED667D14252FCA5D94013C599EDB50 +:107640003B861C36E477533297834DF7AAA146094F +:10765000D3DF3B5CE83FCED6B549985A95A26A94F1 +:10766000E7705125F3075148E63E92DCA3F78C679B +:10767000ECD9BF2B71FD1B275DDC1E294B08FC0AD2 +:10768000F135B2ADFB00AA4F7E174BC5F59E22F433 +:107690009BB1A7B93C32F2FA6B85BD619547CF012A +:1076A0009DA3C018FB0DBEEF8D3DEDF623FDF4C884 +:1076B000A10553681F2D6A2D3E88F939456F717EEB +:1076C0006442FE80F54678296D0B2A880FABDCE911 +:1076D0004FDE18F2C4BACEA05CF7D4B30029C56D52 +:1076E000C06751FBB7554E1D7389FD55C8A9B36CD2 +:1076F000C2C0ABB4083D152DF31F7444D18F21A730 +:1077000022F414223AB48E2331674FDD978BF2E5D1 +:1077100088827E90AE893C3EB942F051F2C7A1AB5F +:1077200071FE1B5AA7BA90EE77B4953991AD966465 +:10773000F0735EEAFEEB824C904F745CD7C69C1AE5 +:107740009E291F0F2B8FF8507C508F9AD79966492E +:107750009C73D492AE8B733F82512EC9E0E7B8760A +:10776000B4E524713B334CEBDE43F7C20F61F08587 +:1077700041EF56FA36F8A19171BF84A13F28528B90 +:10778000B00BCD7E8146C3CF1174519CF80EA10F72 +:1077900036BA2F5937017E6D0A4FF2615CE20E4F07 +:1077A0000EE533DF3180E3CD8A07A3ACFD14F4C3CB +:1077B000A8BCF35AB59BFC5AB59FDA4DCF0DBCF669 +:1077C000860F03AFE310AFD297C7EBA7B8BEA36392 +:1077D000F1FB65E79DB5644CDCF372FF57E63D9E17 +:1077E000057EDD4176173FB761D097212F4A976E0E +:1077F000CC24E26837DFEB65C891317BEA0EA28AC0 +:1078000068951397B5B26B114F63C32AC3A32EFDBE +:10781000C98D8FF1974C3A7F716302F0DFA817662C +:107820002DDA068F466A2C753A0035B25D2539C6C9 +:10783000DACF2F0ED512FE381DFD8B865E1A8357C8 +:10784000A1971AFB8B11075A9710A8C4F1A53DC048 +:10785000375ECC3FE5F6EE5A57605102B44F0498BC +:107860001330D7AE209CCDED53335FF6C687891613 +:107870003E6B01BCD03904D8E7F2A558388CF1F33F +:107880001292399C406DA8BF6495323E580DBFCF0F +:107890002E6B240BE03E8CC736719E6B85FE759770 +:1078A000A55CEBAA68C079D9541674147D79B80D1B +:1078B000BFE0BA043D88F87096EB348FC13EE647CE +:1078C000BD7EB0DA22F9018E946A4DEA71D618FBBA +:1078D000379EFB99AE4D44BA189CC7E83CEC60D487 +:1078E00083E2ACCFA6041EAF5DECEC388C21F3DA5A +:1078F000E975E5DE3EE2D3917B06FCC24F65CEC35F +:10790000E8DAFBC64518977CFBDF3FF260DCE94F05 +:107910006AB707E13CB9FCF71EBCBFE5EDE5DCCE7C +:10792000B8D9A2CFEC14F84B4EAC780AF1774BFDE6 +:10793000DF4BA3F99D2DE37194DB420A1A9D3DF4C0 +:10794000BD686B22F9E68CFAE2965453DDA0D3C5EC +:107950000E9E27659DFFFBC28EBA6DDB66FB600D38 +:10796000C70FB422BE4F0A7DEDE42E0FF9330C7819 +:10797000E66E1B65473CFCA9D521E2F0ED368E7F13 +:107980007D3AC6CF026229AC701EDE9748FDCD7FDE +:107990004021FD620E8CB50CE83BD07A1BD9D9D6BC +:1079A00079CC7F5B9B3210D66FFE5A89F4526CBF44 +:1079B0001CE821B06C35C5D9ACF39C13B4C6339721 +:1079C000939D6ECDF398C7B47513B2E3E47BB4F224 +:1079D00038F9C27EEC9A3F26087DA1945D8EF9E8C5 +:1079E0006759E18F0AB5FEED9A93F58C92B43EA8E3 +:1079F000775279AADE47E553091A8F67EFD97F9846 +:107A0000E84B6D2F457EDFD1F64EE24D5A446E5F56 +:107A1000B1F9A3833F817A31E3FE1BC33F3E5BE0B4 +:107A2000FB4A21BF170A7DA0F8D3BEE5F76C9CEF97 +:107A3000C858780DB93D1BEF958DC28321C7ADF8AD +:107A400038D3969B887421255AE3C05F0D2FBD7DE6 +:107A5000B758899F3768F0CF53C21F306FCB8C5512 +:107A60008360FCC6BDEF0DE1F702B3A3281F0CFA3B +:107A7000B4D21F637576E4E71E3A6BBD9BF063D00A +:107A800005F05186883F66A0DD67A5B7FEF2893A0A +:107A90006D1D43500E58E9AB536271EF154D4DE427 +:107AA000FEF2799A3E05ED50D85E56F1381D973FAB +:107AB00027D5E6C377227F6EE1FCB1F857DB7F89DB +:107AC00072A7EA170F7851EEBCAF36A7E378D58FCF +:107AD000AFF4629CFBA41AF4E2F7EF8794B87985BF +:107AE0000B1325E10F37E72BB035C16B906F3F7952 +:107AF000DCE6433F43ED56078F83EFE278833A8F0E +:107B00007FEF8A9FAF50F5F307D2359EC76ACE5BF1 +:107B1000D862A3FC13F497E130BDC5717BE2C22D9E +:107B20007DC7B76B77AD8B9B7762E40758E9F606A4 +:107B30000BBD025EC88E09023CE4161771EBC62726 +:107B40007F3CF204C0756ACB6FBD5261B4DF9CC745 +:107B5000C7CFB4DCFA530CF1F446AF9D82BE237A52 +:107B600043286E1E43B52DEC453BBC7AB38DECBA71 +:107B7000EAED0A73623ECB7107EDDB8BB6FFE6F5EB +:107B80007100DFA2676D69D3F934285FC158A79EE1 +:107B90003C12B12E553B7FC3E3BD9AC82711EBB30E +:107BA000E8D9FD76CC8BB1E2B1AC65BFBDC3928F95 +:107BB00040EBD472620A9DCB7BF29C1DF7D3F7F7A2 +:107BC0004974BFB2F5FBCACDBFF1A27C403C515C09 +:107BD0005EAC57EFF942E16B9E2FA176E487EB6D27 +:107BE000FDC6E0DE3A9AE8FB99E761FCCA371D94CE +:107BF000AF54F9CC52CAEF794FADE374FEC8CA74E2 +:107C0000DC5F2B6DC1741F95FC79E5A3DF25FA5B62 +:107C1000F8CA77D3F9791E3D93FB6D829938BFF985 +:107C20009BFE85E6B7800588FE2A1F512AD05F7229 +:107C30005665E5CFC6E1933F093E79EF310706511E +:107C4000D97BC26F197C5511F7FE5AE349FCBE95EA +:107C5000B3C28EDE95281BF71439A3EDAADA2DAB3B +:107C6000DB717D3EB8481FE8A3B8BE1A14F89248ED +:107C70001F7FE5AA81428ED13D31869E5386CFB1CA +:107C80007DBB8DEE8B89FACE74DFCB1D627C803B91 +:107C900041BA0CCAF4F8FE4C8F5B32E0E3F92F06D0 +:107CA0007DF5C6F75B783EC9C747B95CC1BC187A99 +:107CB000DF6E0B0F34E5C3384CF78944F23D6C821C +:107CC000AFCDEF014ECA57E9C1EF3E89E2AC0B36AA +:107CD00038CC79703D7463BDE7C69CBFB2D0A26F4B +:107CE00019A5552EBC69910B6CD3F9E5AF54DB4255 +:107CF0009477547DDC41F643F5765B05E2E3AFDB38 +:107D00000EBE7E13D0F95F5B0CBE35CB572BDF5612 +:107D1000EE18CDE2F1ED5FDD7E16976FE1795CBE86 +:107D20007547E2111AFBFAE4EBC25EE4ABE28ED1D6 +:107D30000792302FF783A7165D4C7E060B5E0DB9B8 +:107D40006A95978F246AFCFE8298BC3ABE9F47F2E0 +:107D50001D39FE0C7AAC7A7A318DD343B7065D1AA1 +:107D600074DB4B9E96158FD6F72FA23C1A10EBCFE3 +:107D7000084E620578AF5EA39D15A0FF392827F84D +:107D80001FCF8E93D7C1EA86A29ED1E8CE8E9B9F4D +:107D9000EB77FBD08CC573654ABC78B7BF4C8EAB14 +:107DA000C797B8B95CD98BB40065B59BE3AD49C43E +:107DB00057C012A4BC7FF429123F257B899F6CF029 +:107DC0009CD1B94A3F9DDBF627CA1F69A08255B8EE +:107DD000B5292AFA538BE5A5B9505FE82EE6F5F1EF +:107DE000F2CE1CA8DFE62EE1F5CBE4621B90E61391 +:107DF0006CF494C950AF31E6392FC9E4DF50E51374 +:107E00000F62DC457D9EDF17B70EF8DA591489F74B +:107E1000263A58D05584F7344209F555D9BF5F85C5 +:107E200046E00647E01A37C9A3491AE2F594CF495C +:107E3000F932773C7715E56756BBB9DF78F8CEF1B4 +:107E400074FFEED730FECDEE01BD8FDF64E3FD9C05 +:107E5000DA31BC0CF13AFC62467E0803FF45AA46C3 +:107E6000CF5D2D78F494F83F03CF7F3426DBA99FB4 +:107E7000EA9EF53ABFB251E43528899C0E9424B9A4 +:107E8000EE5928978AF5BF43E0037FD05EEEDA3BD8 +:107E9000F0317EDF53F7105C5F4539F347D41BBBED +:107EA000FF35D18FE757DE4CE0F8BA2169BDED52BE +:107EB000A81739872C45A27E53DAF65D2CBFED0951 +:107EC000FC90E39F85B1BF9B6E56787FEE3A0FDE44 +:107ED0009F26E95C8F96806866031E1A75A6D97383 +:107EE0009145CDF9168A52D41DA6713DA671591639 +:107EF000EC83B04E378CE5EB0438A57DF18D31BCB9 +:107F00003E2B94D3D8A1111CF7201CA31CA18BD00D +:107F1000FEB909D4224ED766FBDB88D3D7FE4526AF +:107F20003BB356D21ADD50DFF91623B9DC99E015C0 +:107F3000F907FCDE19C32F31F6A5B965B864257BB6 +:107F400016F13C0EE18732E2E86759AB829389F182 +:107F5000535BE4E178B69EE4647FF1B19FBB457C5E +:107F60006C101B7481F1B167DCE7111FBBC86DE8B1 +:107F7000F322DE2EF6FF334772285F485531278FF4 +:107F800031BBA6508A88F1DD2E8BFC35E878C451D0 +:107F9000DFAD88971147D92DDC5EEA253FE224A3A7 +:107FA000BCE6511D05941F61B3E6471C9329E1A966 +:107FB000F4C5620DF1D924E2C6171AB737E2FEC53F +:107FC000FC514C1CFF796F39C5418B7DF1E3F8E31F +:107FD00094D914776047F8FA19717CA6142A08E737 +:107FE000D930D86008E751F3DF01B93C2DA8505AC9 +:107FF000CD5BE6E7E32C74605DEFBF58D7FB7CF305 +:1080000020DEE7F7AA8D6223290FC226F2207EC95F +:1080100002F747E7411878EC2FCFC49A5762CD2377 +:10802000C90C98F134B8F252D3FB8BEA8A4CF58B29 +:10803000978D33B5CF868D30BA9EBB669AA97D7E6B +:10804000F34C537DE8C69B4CED8785E69ADE0FDF47 +:108050005AD5E7BA8F6859627AAFC8A162BC0FD20D +:1080600058F7CBF6FC202E5D18EB6EE46961BA116F +:10807000E27734ACFBC3D9E43F2A93B4D8F5F78751 +:1080800083B42F5FE8FAE77B843E7481FC3E0A8963 +:108090000DE3443AD713BB6CEE35A81727036C28C1 +:1080A0006FADFA4572EB0BFF2D79E3E55B682B9022 +:1080B0008EBEAFE86371BF1F20F2239B64719E7474 +:1080C0009293F4817B64F996E87BE4AFF0703972A7 +:1080D0008587FB557E02FB26EE9383135990F64F5E +:1080E00071BE9CA1430AE6EB4D65E2FCF963AB2649 +:1080F0004FC078664781968C2205EADF88C8FD9BD1 +:108100001C5A23C60346295C8E837C9FE6198DFB8F +:10811000CE721BD77F8236C4F360270B7A8B68DF61 +:10812000A3B866324B939614A2E9D5B3BF685F003B +:10813000311CAC1A9E8476D0CB383406699D09B4C4 +:10814000FFDF68C8BDCA6124F7CEB87BEEB5A0F3E7 +:108150008E67E6E5D2F3E33703D701FF1CB79BED4B +:10816000A2FEFC53959BEFF7A0FFFF780133E519C2 +:10817000547BB81D55ED5178BC3CF49774444BD7F3 +:10818000FCCF2E41A06BA5F65528A2576FBCBD822F +:10819000F27677CD08A2FFCFF03B1BFDD4B64E643C +:1081A0003DF707433F37BCC1FD5F377C66F6E7DE2E +:1081B000E9E179D7778AF1AE87C20778BB1EEFF481 +:1081C000C6F2850953901FE0795882FAB7DB40F573 +:1081D00003BA9F11C8B6213CBF67FED7764B98AF54 +:1081E000ADD1F7D7B10A1BC2F5FACD8B3DD8AEA7FA +:1081F0003FA39FC178A613F6E9E4A02D1DE8A7FBD5 +:108200001B12EDEB309E139F57CC1EBC12B70E63B2 +:10821000BCD759E0F46BB0DE33999FFA35FA672C7E +:10822000C1240777542EFA536A0ECA3F99FC1F4B9C +:10823000F63A48FE75559DDBFE20BCBF6570C7450C +:10824000A85FBC59F5D92588971B372A4C83F50FB1 +:108250002504EEF344E1EDF8BC8F3CF81EF484C72E +:108260001FC44DFE69079DF37AB3EAE94BA2F5EA14 +:108270004D9E893FF6E03E39E6FCE23D654F0D2319 +:108280007BDBA0AFDB047D2D797228E9834B3CE6D4 +:108290007B53963C9E4BE7894A2516D78EC47B3F7D +:1082A000302F7D07D0159E23DCF729CF1FDF7924DF +:1082B000A598CEA3B2C07684CF68BFF3E59B865362 +:1082C0005EE7B1B4F3BB1719E00BA27EC5389C2F53 +:1082D00009FE98D59A5A2CF4BBE7106F37FDFAC9FE +:1082E000D37F40FCEC7DFAF13BB14DC9F9E18389C4 +:1082F0007DCC2FF000FB18D93F5D2CC1EF8863FFC8 +:108300003C2BF4AFEFCB3AD925E7E40A91BFCEED91 +:108310001045F667601E774BAB928878F3A2C16276 +:10832000C817D009BD78FFA2B83FDD09F6D9702182 +:108330007FDA3D1F4F69E27108935E5772A8CAA4A5 +:10834000CF55C03F94F7976F0A34E23D8DBDEA7573 +:108350006199ECE12FABDFBDF325E57DA787F37FC6 +:108360004B0197DF2DE18410B71B5831EA7BCFE03A +:108370005CE0FDB464BE2FD8A5CE0227FC7EC6F318 +:10838000C9AA3559B0DC791C1F58C7BFD3C3DA3826 +:108390009DF6E87F872EE57F674E9C032E11E7A2AE +:1083A00063EC49E02BBEC92698F4C7F0E1BFD13990 +:1083B00097ED29DAEFC6A33E0F7A0AF2BD4BEDB076 +:1083C00027C799DF2F517E027D8FF572FBC4B987D5 +:1083D000C7E19C9A4EF79EB97CBE51682F19ED4FAC +:1083E00089FD66F1E13787D8619D4ECB47BC1847C0 +:1083F000A8DEBDC38B66F2658981242FC64B8EBF74 +:108400005AEAA37CABCD43D0AE6D09F3F8C408950E +:1084100005D538F735D76E2CA64BBF6B36A652392B +:108420000CFD09F0A836CCE7D9B9A731259EBD5D72 +:10843000FB1F7B07E1BA3D3D809F971AD15ABC10C4 +:10844000E51FC2620339F7D4A7C3A9BF4BBCD93417 +:108450003F185FC5E7209164BCEFE86961AF757EA6 +:10846000AA503BA3DF117B262A3E58CBC270F301F2 +:10847000B20F5B1D1AAEB36B0BBF0FCED5EA22B99C +:1084800057BB6F2AB7E39279DC737B42F71FC5397C +:1084900036FABB042E5F334B81FEB7DBF9FE380C96 +:1084A0001860873BF2DC18CFD5FA634A6A77E6F1A9 +:1084B0007BF55C6A33FB863B1AEF1EC2FB542FA789 +:1084C000ABED096119F376BA81261F23B822703209 +:1084D0001AD7807318E9F3DBEDDDEFE2F94B3A5F71 +:1084E000A7211C1C4ED63A5443BDC2E5E3F15B976D +:1084F0004FF307A558B86A47829E0BFC764F038B53 +:10850000FC7D04CC634B88D49DC013DB739890072B +:10851000C3564FCE8AAE83401A13F97EF63DC35739 +:10852000374D203B27A8A05D0FA52705E7C9F737E2 +:10853000BCBF604011C703FA89139DFC7D4F7B27A8 +:10854000BFB24475F376FE245FE23489F5DC676AD6 +:10855000F89DEE90C2EF5E89FEADF081911AC05297 +:10856000FDC2F344B78BE4D6074768782E31B000DC +:10857000E9F5576FC90CEF47FAE049179D432E788C +:108580006E33F9ABADFDAD3ED6701FE665773D2786 +:10859000699807DA65EBA6B8514DEB7B745E71EA1A +:1085A0009E13746E4B490AD47947635EC48A32C401 +:1085B000DF58D6DC88FE3D908714A76FC9E0F2E350 +:1085C000CCD14B1E5B1185EF07BDC2BFDB1DB818B8 +:1085D000F9A655F0E73ED46FA0DC2DF4ACDDFB6FBF +:1085E000CC8D3E87156407C81FD6C00E517EA1F101 +:1085F000BC2BA4D239B0E1AF3B6FD1A3E8AD59F0A9 +:108600007BB3182F3F29B08AF876FF9FED5E0DF3FC +:10861000585B86A0DC6D013DACAF7CC65A0BDFF425 +:10862000E4B79CE4F771C3BA3625C13A3DFDFA9E22 +:108630004BF1EF8B00FC8CEEAB3AEE20B9B93B9BD3 +:10864000F3DF8AD73E198972EB93BD8B2E467C2DC2 +:10865000F3DA0C3A9F9480FCF42C233966F0632102 +:10866000F2A384F742713F4A21D239F29FBD7D1AAD +:10867000F1DF6E7E2F04D039D13DD0B90FF58B429A +:108680001FD03D7D3F94F8797BBBCCCF81831CCF3D +:10869000A7FA24CA57D9DE3ED947FC2C036A8B902F +:1086A0002FC307A89F16FADB75ACC4729FEB294C49 +:1086B000D21810918F7FF3703E6D29D092FC309FBD +:1086C000444531F141D43EC9EB621F957F74D3EA32 +:1086D0000DF8F7C3DAC5BE20F4AE7D42CF65C7B84A +:1086E000BC5F2AF6B225BF19F7ED6D30DF252F29C3 +:1086F0005CFE0B3A3920F4E043F51954C7FD428380 +:10870000751A0D25DE0754AAD7E19F2F6163CA9B16 +:108710000F6239AEA2A50C8F4C4D98D57E909F610B +:10872000D38723FDED3A70F570CADF3DEE6098A265 +:10873000B8EB6FDD7F7C0AF351F701FEE3EC4BE809 +:108740009F6514BFA9207AEC8D6EBAA48E6BC6FB10 +:10875000410FBCA77AAA0A1B7D0D1206E0E3F57B48 +:10876000AA56E3BD803725E9C7911E97FB02C79142 +:108770008FBA5EF95B3ACAF4DD47FFEC4579BFCBAF +:10878000AE0F473ADB9503F6401CFA3C2CE8A7A451 +:1087900097BC8ACFBCDC5EBA24C8D621FDD4EC528B +:1087A000E8EF169CDEA5E8780EFB5D3D908E7ACE54 +:1087B0004916BC7E3CEEEFC2AE9DCFD1CEE6A3DE25 +:1087C0003292EECB30D9994C592ED33DEFAD12F900 +:1087D000272A2D7A48356B5E3518F78DD6CD769CD5 +:1087E00047D516F3F7D5A8BF8CC4B26F7BF533AF6E +:1087F000D05F72592EEA2F403FE49FE87E4DF13F53 +:10880000C628BFA70DF37B9E96397E405E121F1AC5 +:108810007ACC569F7E1AF5CAD3824EB70B7BB47BB7 +:10882000BB44F9FDC3B6F2BCEB7127B5CD8CCF9F2D +:10883000F2C22A851C1CA7F2F8C5B8A3B9140F1DF3 +:10884000A333F2872C68954288C74A43AF13E729C0 +:1088500060DB25BD6E2C0B35E2FD720BB74A740E42 +:1088600063D156B3FFBE7AE32B87D13C5CDC62391F +:108870001F2FF0628D6FECC05FE2C4372E4E12FEE8 +:108880009C216C88E9BC55DBF99DB7FAAB387FFDBC +:10889000AAE8DF68372189D34D8D986F754809891B +:1088A000BF4FE9C6FCDB5B057DDC2AE8A39685EDBE +:1088B00098BFBF78039F2F5B6F33DD5BBC60D7ED44 +:1088C000741EC14A4795DB78DC0D1048F19DCA4DF6 +:1088D000E6F755021F55167CD404240B5C5CDF8E32 +:1088E00085ABE57A5CDFC5DB6CF4F739AC709D6570 +:1088F000B3298FE81F0D9F759DAE33D6E95276A937 +:10890000699DCAFBBE9F2062DF98F5DF670F5F4A53 +:10891000F92E67DA72C87F60D087B59F29427F9EA3 +:10892000BA91EB99A7F794258E40BBE888EA97A007 +:108930009FE2973EF6E2798FA2BD0AC3B860576BFB +:10894000F13A3CA7BDB32DEF5ABC8FA2E82595F6AE +:108950008DE2978AE85E90A2978A1273298F424B24 +:10896000457C403FB4EF761DC9FB7D21CACFB6C917 +:108970002588E615478A12513FD8C9B83F427AA9DF +:1089800024B5236A1F599CC4FD03AB32DEB907F539 +:10899000F7A9CFDAE8BCC9545BF7CB987FB0B34DE9 +:1089A000F5AF807AF54B731BF09E8AEA27253FAA24 +:1089B000D987DB97A47D07E9ACD5E67310BCDF3D12 +:1089C00080EF83DB247F3EB4AFDD7BD5F0ED98E70D +:1089D000BDB9D81F7D2EBB2859BB1FF32A5966226B +:1089E000D9DF532FB2D17E7A6A50E2CFE83E167DAE +:1089F000F31494B3A79EDF69A77383DB2596011355 +:108A0000399C71F019BADFE397AF50BE42D9AE5727 +:108A1000283FA137797F3AA4B030D9DDCD742FCC6F +:108A2000E2CD46BD83CE415408BDA966CB09AA5705 +:108A3000A1FE0FE3556D52421AFC7A70EFAF28BFCA +:108A4000A1661BCF6F80F7247FAA307EAA45E87C01 +:108A50002EE3743057C89F458CDF33B4A8999FA389 +:108A600033EE4532E87CFEB639948716936F86F66E +:108A700025C5219A89BE63EF1BE2F46DBD77C84A14 +:108A8000DF2D067D0F63C390BE3F99C8F3C33E79C7 +:108A90002521B110E6F3C98B0AE5DDF741E7B49F64 +:108AA0001E11FBFF99B04CFB93D1AE73CF47B48F2F +:108AB000D41E3963477D754AEB87B40ED35BF74FFD +:108AC000463C7F8B05AA116FDF6A4DF4219F4FEF63 +:108AD000E0726B5AAB23847EEA6FB196265CDFAE00 +:108AE0007D3F6F4A417A7982D38B21CF160A7C2E43 +:108AF00014F85CA8F2FB9EAA0AF73F88F9D0D318B5 +:108B00009737D35A84BCD964C66F97AD4525BA1937 +:108B100021B1E6ECD8FD6E11EBA0738F5D99C3E92E +:108B2000EF4906C15E453DAC7A9B350ECEEDFA1A93 +:108B3000CB7E7A30C9F6A5EEC178C7B22ED3BBF989 +:108B40007E360DE809E3216DE18642947B067EAC1A +:108B5000EBD2A6E526F575DEF965A1B71BF56F8B9F +:108B60007B265A7CCDEE683BBCDCC7F5F0AAB14A47 +:108B700010D7B5C75EC93B38529323F60AD8299F50 +:108B8000250DE076CB28E8FA852C85A5A545EC9542 +:108B9000D519F74F2F4AC3FB23B8BCE81C03FD616E +:108BA000BE80CA484ED56E7384D0CEF81F85B75AA2 +:108BB0003D008000000000001F8B08000000000046 +:108BC000000B8D576D6C53E7153EF7C31F8913FBE0 +:108BD0009A78662C34BB31F9202584DB109A40D773 +:108BE000F626A51D83141C58296AABE2B65BD90A88 +:108BF0004E5085281295B889A9D6956942DA7E54D7 +:108C0000EA56DD226D621BAB4C096A9892C8A1A19D +:108C100025E990A0401BD0D659FC60EB9490C0345D +:108C2000D24D95D873DE7B8D1D12B43A528EDFAFD4 +:108C3000F39EF39CE77DDED75D7DFFF29AF544DF7E +:108C4000EDBFEECDC2C6FBA54709B63A94F069DF89 +:108C500020EA20F2449A60FB242343B0ABAF7B139D +:108C6000254423558B4209CCBBA1EAF335B46FF1FF +:108C7000E7E1BCEDFA52212A23EA84D5CBF2FD9D2F +:108C80006AD6CBF33BFB25D386ED3DF99F8ACA52CA +:108C9000A2C981E98AE760576832FE71FFF796A89A +:108CA000D877EA928F6295D8D8322FD0FD442F9290 +:108CB000F3D9A611ED9987F6F04BEDD4800E697FBC +:108CC00039B5C0AF878C0CD6755E540C4B47FF0985 +:108CD0000F513351F7277F1A9E1721BAF6AE64F869 +:108CE0007467FDAB8D683F6FEF9F87F9377F27195A +:108CF00016A6BFF84DA287D0BFED4DCF95ACDFD9FA +:108D0000EB96F89FBEB217F39247FCFA1B687553B7 +:108D10004F39616E0FED1736493FBBAE04E1AF2FFF +:108D2000E5655CC82E581F23DA7E78A6BF24A9F912 +:108D300036F2DBF397D68EE182F1355A69E46A00A8 +:108D40005FEAA8EE96C2F1171F90B0FFE488A2F97F +:108D50002481DBDBDF2AC4E734C058C0FD4526216F +:108D6000CFC973257611E6FD731FC66A89C6F7C1A0 +:108D7000B90F7E5A148187BCD2B14B06DF8F713D8B +:108D800019FFC452A23F0CBE7F2FF30109883A6C31 +:108D90003F8C798B0BE24E23A88238119791C17ECC +:108DA0005D9F2A06DC735C35DE483EAEE36A3668BA +:108DB00014F0637A9FD9315C8D72492745BD64698F +:108DC00058D8DBBC39A1C4EDFA7C1BF96C35B1FE77 +:108DD000299717A44E45E388F3590D45043FBBFB83 +:108DE0009DFACA038EC5FE9B8971419BF79F35DEB4 +:108DF00066EDE0F19B9501B218B72FAD766EEF8E60 +:108E000029F406DABB3F79A9960AF6278E13F5ED09 +:108E1000F24C4599B75DE764115FD7B91BD12AB40D +:108E2000D7D23BAB35B4D7517A3F8F7F180BFC8834 +:108E3000796DF1BEF3F37EBE0829225EE27CE1CFBC +:108E4000A25F3A7EDD7C7B68A3C0A1C7E5D50B217C +:108E500059CC7F554BBCC2E770F2DC7FA3489B8E98 +:108E60005FB812E47AE5EA7DE7B9BB1D3776E0F535 +:108E7000375BF5F34F83078D23AA15429EC7C68A39 +:108E8000EC76C66560DBDFF672DD2EFB88CFC3EEC5 +:108E9000C16DB5C47E138965719CC39B833F5EC65B +:108EA0003890D423E2B2383EC435D17731AAA33FFB +:108EB000397031CAE3C9E32B7E6161FEF2338DEB79 +:108EC000B8FFD86955F0AFF14C93E0DFB13F37956B +:108ED0002DE2C0C908B0DFE4881A677C92234D1FD9 +:108EE000B7635EF24C5B93C4DB9C692A63FD592E29 +:108EF000513C8D7169A44AB473F9FC5C73F09B1CFE +:108F0000021FD02F51CCE10F55CDE0CF8EDE535E46 +:108F1000CE63479F6216F228B7EE90A60A3FBF6560 +:108F2000FE804FDD69C914FC38EAD81D7DC7447E38 +:108F3000DB3D6951EFEE231E67FC8F8E253A28D664 +:108F40005934CF623C3EE62ED461ADD75E480871FD +:108F5000B492B6A4E7D0C39AB024D68D5E4A7C9B67 +:108F6000F932DA9AA8D5EA67CFB3A84DE443928BD9 +:108F700077AF678D3D87BF2AF6873C8265B4353E63 +:108F8000C77838ECF067AD971273C5F379EE3C11F2 +:108F90001D90C18BF3ED1E8DF94F64962C80CEAEE3 +:108FA000777576D3E31ED3BB0CE3A49D2AC2F8FAEF +:108FB0009CDEB640CFA00B71FCB1BEC5DF8C873202 +:108FC00080B4C39CA9731B29EEA145F0B36666FF6C +:108FD00013AC970D6C55E1E76E3AF829EBE0127C83 +:108FE000A9A11AD641524A021278F3EFD31E4D11AD +:108FF000F1DA55AC0777E697D3990FA17F3AF4EFF2 +:1090000034F48F6D77DD670D59E0313A74E9DDB0E6 +:10901000D0CF228A3101BF8277E49DD4DCBDEFF04E +:10902000D77DFB7C7E7F06DF72F5998064A7EB67B6 +:10903000D7E786E6D421E91FF782ACD4453B5F979A +:109040009147BDE2F0CFE74998E5C8C3D3D79A2945 +:10905000673DAD838A22BF8947259B751E7156F8EF +:109060000A747E628124C6776F966C0B5F87EA3E36 +:1090700013F7763273D6CB7CAAE97DEE35716E2D6F +:10908000BA40D17C1D37F89DFBF276FD72F9F2A053 +:10909000CEF981CF428F23C2F27CBE1FD7BBF7E14E +:1090A000869699F5ABA5B38F95238E274DC9B0E76A +:1090B000AAFB96FB4EB1DC7DDDBA2F09272261E0C9 +:1090C0003179F6C6E6A5F0375AF7F70ABE473BEF07 +:1090D000C2DF0A97DF5D81600385A02EB57A2A0B77 +:1090E0003CDE2B4DDC13669D90BF0ADE4BBC3EFB85 +:1090F000F6CB12D78304DE773B2F55AEBFAAB0E67E +:10910000E874849633AF7EAF69CEB9F5D80B590FAA +:10911000A81E8F9995FF5F77BB4F7CD4C075B93679 +:1091200034D2E02DA8DFF8CB38F77C8F0C7C10D53B +:109130004B0AF925BBFC528595A48DEEFD38936F43 +:10914000E3CC37AEF7D10FD63FCD3CE9DD1491F437 +:1091500082FBF3F8F9607581DF897E45CC27355BAA +:10916000F34469619CAF893827D28E3FA26CCDA6AB +:10917000A585E32997B759C1DB9F2CDE19E7739CBE +:10918000E3AD4A0E6F3BFB3A48DC476EDE692FBE0B +:10919000202E6BD067FF06E3939EA98A70C1B9F8B1 +:1091A000A18B737346127C5C4996C27E9BE1F119D8 +:1091B0006EAB9451611FA08CE8275A48CCE3FB5D4D +:1091C0001E37AB9921A941CCB354F072159D15F30C +:1091D0001EA229614D82C0C3B691216C8B3FB38E14 +:1091E000E5A33E9D56984F99A81ABE0A3EB294CC6C +:1091F00055BF7CFE2A5DCDF11393F1B8D91A9F4378 +:10920000AF0FBAE7DCE0B71AD77982EC43E87A907F +:10921000B20A6FF2804A6B14E4F3A04AFE62C47B88 +:10922000745816E77730ABDBAC5F4699BBEE0BACFE +:1092300043BBD974CE295F35CF34E6F3BD138755D0 +:10924000F017E2792ABDEE113866C47E0F73E0C8CC +:10925000BB957495DBA970A5C3679A7A96F779A434 +:10926000DF27DE39B2DF1278FC34ECD433003C83E4 +:10927000F0B3EAA04463D8D758E4E49BF3BF0AAF45 +:10928000BE5023CF77EE31B4690CFD01BFB38E68B9 +:10929000B5C6784999A87C2BF0F5719D8C92883BD6 +:1092A000F8C2D4B5BDE2DDE6D30E2124A3FFA3317D +:1092B00009EF69C934690FC7E32FC9F0FB1AEC182D +:1092C0002F7C57FF3AFCFC5B7CDE255D13785182D6 +:1092D000747E67CCA75F697C6FC83CAFCC81EF1F01 +:1092E000C0EF4957EF2E173BBA71D8DEA8CBA8C7FD +:1092F0009688DFE07A34FA2B9613FC6E284D08BF6F +:1093000097A523D5C2896AAF60BF399E07C86C6133 +:109310009C25B75E7BFC8EBFE922C7F299643E07AD +:1093200020E77EC47500E7C28FB6D5E6D4DBFABC71 +:10933000C84E61BF69392EC8F88A62F805DF6389B3 +:10934000B16658B5CDD47796F0931D7904F279A41F +:10935000781FDCC7F4033C1041865D9A934FAA4402 +:109360005ECCBF9752546CE07144BB4A1D9EEDFA2F +:109370006B914D95B3E33BE94B9CE4FCA665636CB4 +:1093800054DCA33B9B59EF18A7EFE47092F3386DC0 +:10939000B163A9AC2E7019619DBECF67DF93C1BACE +:1093A000A77C7635C79FC303051224D55C9C73F850 +:1093B000685C3FE6B189FAE5EA1FCBE374A0D8C147 +:1093C000073FDF1C1C74D471E9ECFCFF0753B7A7FF +:1093D000EBB00E00000000000000000000000000E4 +:1093E0001F8B080000000000000BFBC6C7C0F0A3E5 +:1093F0001E81C3D1F8E878022F7E7952B10C038226 +:109400005DC1C5C010CBC1C01007C42780F82410AF +:109410006B70323024027112102F00F21702712586 +:10942000101700D5363333301C6663603805C41717 +:1094300081F8061BE9F66B483030EC9241F0396454 +:109440001918D8E4A9EBC7513C78F15A0354FE5BD4 +:109450004D54FE576D06063D4304FF9D2669E627E1 +:1094600001F526033100FBB288BA68030000000052 +:1094700000000000000000001F8B0800000000003A +:10948000000BED7D0B7854D5B9E8DA8FD9F39EEC5B +:109490004942184248765E1030E01042048A9E49E4 +:1094A0000A8896D2889E165BAB4340823C035A4C96 +:1094B0008F78B2212104083050AC91224E10305ADE +:1094C00068A3A2D216DB8094A2F5F4466BABB53E3E +:1094D00002521E3E68EAA38EF7D4C359FFBFD6CE10 +:1094E000EC3D9909D89E7BEEFDBE7BD2AF2ED65EB9 +:1094F000EF7FFDEFF5AF358AE824F23F117211FEE0 +:10950000683A4C24840C8AA784C85A8F0352A25FFD +:109510002CB4E4C945E972F27F1B61CDEBBCDF7F5F +:1095200021248B90EFF032FA1782FC149E31E6630F +:10953000A424A890AE92783F5308CB6BA2402E0A89 +:10954000F0D55A6E8C53EFF08D2169847CEA64A9C2 +:109550005E458BCA69FA9633DA984F88430817B28A +:10956000F9D45D593D1AD3AB206D14C8EC4E4F921F +:10957000799035848CA7C9FE2122A988CF3FB19E5E +:1095800091363510D2658FE765998492F55B41E796 +:109590000FFD9E13C215381F0F91011E0A87878D7C +:1095A0000409A1EB3AE29F169843E7DF3A5909DA3A +:1095B000A160FB10684C7C061C67E761DEC1F39577 +:1095C00044E3F0EE6A29A4ED9C41916CA0B9A6FC9D +:1095D0002A07292564F3C4BF06C2743E4E3942549B +:1095E000483DC9E7379388BC9F7BC9E5AC3B713FD9 +:1095F00064D8A3F19815615DC67CB7D8E8BC32E9A0 +:109600007E8C17C95E9ADF543E2B0DE663ACCB917E +:10961000629C6680EB0842363638306D9A302B8D6E +:10962000403BD23B1BF677F3C42C718310AF7F64B1 +:10963000E271470F5D6F236FD7AA1D75407D639F51 +:1096400013E1B699C32744049CF7C6D1AED9D1D251 +:10965000FEF308111F966F76D246B00E2F89EECD1D +:10966000871E7ADAE6D2BC6F825AB641EB8F2F534F +:1096700046CBC12E3A4F8FC713B4D3724F80B57704 +:10968000BC2144356C1FF20CA1F55DC6FE4F10E302 +:10969000F0A4FFF7916A42283DFA727A5F8371EC79 +:1096A0006FD88321FADDFDD947AFCDA5FD92934256 +:1096B000702F8C4B965BF68BEC6170B5A9F4DFB420 +:1096C000DC3579FE0C5882FBF327AB016EEB8B5631 +:1096D000B856C35E95B0FD53E9FF2E16D0FE35C5D2 +:1096E00032BECDBCBFF9809AD6BCBB78D6D70AB5FE +:1096F000D4F8E1EEF191AE0C5A59BA05F73B55BDDD +:10970000FA37C65E73CC346E1BF1669E71D37F5CF4 +:1097100045AE423ABF44FB4F1B82D71CB3E1BA456A +:1097200033BF49557F2DC78F3E3CCBA7F8518AFBED +:1097300019B86174FCFB4B8017400F7A25F231A4F5 +:1097400045BADEE6AB49AF44F7A3A958D1D65038A5 +:10975000D855A54BF0B1317B01BFE01FB4A9BDA81E +:10976000B95B180399EF58F860CBE07F0D760D30A8 +:10977000BFC47DF8A2F0EB02F85D11879F9D54A74E +:1097800075C17E5707103E5E3E8F7557AFD4BAE85D +:109790007AD6657F3F749298E07815A3B3BEF9E45A +:1097A0004489797C83BEAE14422F027C2425F85A6A +:1097B00098C2834C52827B93AC4B16185F89C3D9F5 +:1097C0002113034E80BF87F5C00D5E9C52B5C304C4 +:1097D000677BE0F867003F399374B9C7E0F7263933 +:1097E0009DF2AF4CA2BBD3B01719F29F917CA44F4E +:1097F0005A3E452903BE302D18A6E334DBF878EA3B +:109800006ACBBE7EC6F7355EAE07FED9526EC3FE8A +:109810009ABD9C6FA88D38BF7EEDFDAC7DE27AFFCE +:10982000027C743CD45339FE340640DE3886344F13 +:109830003F02701F51D73917D6A8128483C1FFA9E0 +:109840000024508FCA87CFA09D43AB46B8DB73423C +:10985000248C70B3CAD3947C39418EF6C32795E625 +:109860008D3E0AE0BF392AD21B4994DF3C0D0DBB67 +:109870002C39D8984057B4ABA47266B4C0F82DD137 +:109880003371FDB281075C3FB019E0D8CEE859E5ED +:10989000E32A301FCA0F9D248A9DBB29A643DE4BB5 +:1098A000EA30FF49A8AC4B00BC91C97AE073F6904E +:1098B00048F4FCFEE36FE6F224D53A364F4C2E070F +:1098C00086094C0E489E3ABE1FB7A84067821E26E6 +:1098D0001781DE4884CBBF20EEF7BA867AF20E5DA0 +:1098E0008CEBE87544A3F823E7D48542B49D04B417 +:1098F000485934F194B3540E6A66FCEADB47B21A55 +:10990000FBB351B0C03A6D1EC71C320652F5064C6F +:109910004B46DD0EF4614B9B560FAA1CC59B4A01BA +:10992000C67724C72BE2A1443A11F35A75D2F1F855 +:109930007EF37A29F1AB0F3F8CF56A4AB5B73FDE6B +:10994000B8CA5501488166BB613E83F96C06879BA6 +:10995000978B6360DF22D387D3FD19DC3307E59350 +:10996000F78DEBCEC3BAD696969D00152E2DA8DEA8 +:10997000308DEEA7AB840800EFF5D0D924E8E18460 +:109980005E09721DFE994DC8B7856743BA87A18FDE +:1099900055DF1435D9E027E280FA8B70D1DEBF7D28 +:1099A0004AFE4C4CF483727CC5E5E94BB7B0F174C8 +:1099B000FA3FA03B7F823C4D0B99FA25001FEB3804 +:1099C000EB006F10BECBFF5BC653C93687067A47E4 +:1099D00091A846E9D86944F5535E4C5C536402F2A1 +:1099E00044CDE9D5617B2FB52F6B09998E7C94D23C +:1099F000AD19CF77723E10A869CA6FA6FD7E52EEF0 +:109A000009021F184CD966467AFFF56C4CD0B33763 +:109A100096EE46FED848F1A800F4FD5211F5A1F5E6 +:109A2000454FA86679F57383DFF4C30FA2C915C843 +:109A30003A08A1F0918AC49073CC3F8E1F897AD2E4 +:109A4000E5E287FB16EB7E7CD1FDFA759FFE7D7902 +:109A5000F8F18F8E67EC6B2ABE45F715F5EF166DA2 +:109A6000D680FA4BFF7DDD86FBEA2A22A1647CB812 +:109A70005B10ACF2C99C9AE507B9D3B25FB6C2AF2E +:109A800007760F000F5B49829CE4FD3AEB25ED342D +:109A9000E8B1B28AF2C8B01FD66BDB74D0E73FC919 +:109AA000214CDF8B2CEF12400F2A22A807410722FE +:109AB000CD3BB5507483C0F01FF6C5D06F6C541DFC +:109AC00033C357525D963C99AD0BE6F93BEB159CC1 +:109AD0008703C603BAF4D00E69BF520EE972A2FE24 +:109AE000C9E60F43313BFE9ECBC203035F01AC0CC2 +:109AF0005FADED9A036524D9FEF51BEF26EB7C5391 +:109B0000F2A5C4761E593B63D24752B793C9199345 +:109B10005E33B4CF7FA11BFADC2181EA858D81AF52 +:109B2000EB386FF80F95AF2D905279260DA9226171 +:109B30000DE4A4C6E8444B67F2B743B0D8E1C6F7DA +:109B4000D4F360E3C56EA7B8087C4DD62CFA7262D8 +:109B5000DAD810F8924C91D25DFFF024791C55624E +:109B600057876657D3FAEB1B3A26C177A3DE54D149 +:109B7000B0BFA9D834E9C732A1F51CF8955C1C0721 +:109B80001F55A299E4BB83746239FDCAF78FE03E8A +:109B9000A05E45BBAC1335EC572187B01E7404F5AD +:109BA00028179F2497B0EE20BFD1160AE1BCE488A5 +:109BB0006305A5BB8D4E9ED778DECFF32ACFE7F3A2 +:109BC0003C951390772B344F53A72DA262DEC5F33B +:109BD000F93C9FCEF37E9E2FE079611BE6372AACDD +:109BE000BF0D7294F5EFE2798DE7D3795EE5F90266 +:109BF0009E27BBD9F8769677D9A2AC7F37CFE7F30B +:109C00007C06CFFB79BE90E785DD984FB57FAEA28D +:109C10000E06A73EBED019CFA3F0E070EDCB77259E +:109C2000E419BE64080C0F635F35F02688FC917858 +:109C30007291DE86F0368DF3CAD877EE47317D3FDC +:109C4000A15139F749584439996ABEDFE7FC743BA2 +:109C5000E8B934DDDAA062BAA521807AEFA6068DD4 +:109C6000FB554AF0FBFA8620E6D7354CC0746D43AD +:109C700008BF37364CC7FC630DD598EF68988DE95F +:109C8000BE8630A67B1A1660BABBA10ED328D57744 +:109C900021DDD5A063BAB3A105D31D0D114CDBE6C0 +:109CA000953D5F04F35F40E73F007F183CDBEA0728 +:109CB00019546DE58BE953D22DE5EAE46CABDFA4D2 +:109CC000BCC092F7948EB2E45D456596FE1C399354 +:109CD0002CE54A6695252F7BAEB7E4AFE89865C9B9 +:109CE0008F8C7ED3D2DF88B61A4B797164A1A5BC64 +:109CF000B06585259FAFFF8BA57E5EFD1A4B799BD6 +:109D000033FCAC48F9D5B0BA0D967A43176CB3CA98 +:109D1000AB199997C5B7C8C77A96D99F91C8EFA5CF +:109D20005C120AA1DC62F2A511F016FC5EC3487455 +:109D3000AF00FEAB6B4F80DD612F6272A79F7D99F4 +:109D4000D09FE2D9F79A4EC7A9F49D08F498E88C01 +:109D5000044CED28DF3F2532BB79C3BDCCAE6EBDD0 +:109D600037B97D8D9C9DAEA3F5F3E4FEDB1E51E279 +:109D70007A906EB1535AEF15B0FE3FDABF519ED8BC +:109D80006F7C3C8A7315663D246AF845899E15B739 +:109D9000776D3DFEB960F71876AEE460DF2B4B823D +:109DA000279B28BCD7AA04FD866B3D5504F48A4F37 +:109DB000544637644F2EDAE346FDFEF333E915C807 +:109DC0007F5C563FAD6716FA3DD7660EAC972931DA +:109DD00009FD77524C205D54EE2872F5F47C4ABFA1 +:109DE000CA2B52703541F993D4BE27641BC2414A35 +:109DF000D06F9AE625F0BD29C370DD36BE8EC6CC85 +:109E00002AFCDEA40E3C2F3BCC0BE6C3E7658BB9E6 +:109E10003195624E9CEFC45806E627C4FC985E1547 +:109E20001B8A69456C08A6E363859896C7F2311DC5 +:109E300017BB02DB95C546623A36360EBF07636331 +:109E400031BD32F625FC3E263611D3D1B12FE3F7D2 +:109E5000D25825A657C4BE82DF47C5AEC37464EC92 +:109E600046FC5E12BB01D311B16F613A3C7633A65A +:109E7000C5B1B99816C5E6605A185B84ED0A6277D9 +:109E8000609A1FBB13BF6BB1E598E6C5EEC13437CE +:109E9000F65D4C87C51A31CD89ADC674686C23B6A2 +:109EA000CB8EADC77448EC7BF83D10DB8A6956EC6D +:109EB000014CFDB187B15C8DB5639A16FB217EF72D +:109EC000C51EC5D41B7B12BF7B628F63EA8EFD0C5F +:109ED000BFBB623FC1D4197B0EBF3B624730BDD4CC +:109EE0003E2939563E2E65BA2CF909A7D32DF851D3 +:109EF000F186958F97BF5260292F7BD1CAC783C740 +:109F0000CA2CF931872759EA971EACB2E447EDB75E +:109F1000F2F1923D563E3E7CA7958F176DB7F2F158 +:109F200082562B1FD79AAC7C3C7795958FE7DC65E2 +:109F3000E5E3D98BADFC3B30CFCABFB3C80EABFD58 +:109F40003D65B755AE4D7ECCD29FA7FC09ABBDC0D9 +:109F5000F98CABF4A796768EA2A349ED9A447F398B +:109F60008044A6F47D377105CDE72A469ACEF941A3 +:109F700006D01D4D3339DD0D02BAA369FA5716E339 +:109F800039D3A75F6DF95513ED2C7D28617E017DD6 +:109F90005B15F8BD9A87F03CFD22D07ACDC308FA54 +:109FA0000988FE6E2596E7B3FC0FA433953AF3DFDC +:109FB000B2727281953B59FEB1C67F5B0DE5E969CE +:109FC000A1EC20ED678F2D391F7F4262E76D17C42A +:109FD00050BB44D7FBE7CA9E95E047B33BC27B2505 +:109FE000FA7DB1239C07AEE90F6CE14764E08B2456 +:109FF000B40FBEA791D02312F26BAB5FB415146EF1 +:10A00000DACFC762F57E28CF98D9817691B1EE6616 +:10A01000EFC0F3894A4C2E35FB09DA8DFAA30ACA40 +:10A0200053FC33E4059583F7BB7D2128DFF5A8B207 +:10A03000DBCECB2D72A33E0BE586ADA37939B824D8 +:10A04000EDB09F5232BF680FE6D340E32F04FBBE52 +:10A050003757A6E9527B5733C8F5BFFABBDF122446 +:10A0600084C7AF003E2BAF0F63FD35EE9913603D03 +:10A07000141E27E03B85C7F3D2A0D4F02070B24075 +:10A08000E71F30B068BF60F13F9E13C2BF954C7EA2 +:10A09000CC403888703B20A9080F037EF4EFAE74E3 +:10A0A000C31FC3DAFD11C74DE84FE6E762BF95F85D +:10A0B000F85C1E1A789C21927032F81BE73EA423AC +:10A0C000F70BF9B39D8A98741C9B5C8DE7A9FDF88A +:10A0D0005E66825D9F1986B35E2A3FA9BC4C32AF93 +:10A0E000690AF74FC97997757E15E5FA3DD99FFB47 +:10A0F00085CEBBC0D083FA438D7D3A968BF951BC97 +:10A10000FD50D0EB283E3DF7A6FDE812CA07765178 +:10A110009E614FE20FD8D521E2F9FA503F45385AF7 +:10A120005ECFF5006A13A13E688C2B2FB6FA8F2202 +:10A13000360EC7C356380EA588FD536A72134F1EDC +:10A140009B1F3FB734FA69EF9BBF751EBBF52031EB +:10A15000DBDDF9ABA322E83572079DC798FEE31358 +:10A160007EBE60D091ECE17E13350FFB35C64D1CF1 +:10A17000874833F03C29157CFB8DF305CFEB2AE4AF +:10A18000E4E79D747F104E4529F43CE3BCCEC83F04 +:10A19000F7662D9E7F37476A50BF6B0EF073F6BF90 +:10A1A000D15EA11F921C4FF6727C7A889F8BECDDEA +:10A1B0005EE5C0769979967D2ABEEF265798E967C5 +:10A1C000E990EE6B63F5863F308F7FAFC1EF0FAD47 +:10A1D00062DFF3EEFDD8C9BE7FE88734AAB3EFDAB9 +:10A1E0006A99D717B13EA9A77FA673A0E16AB508FF +:10A1F000FAEEF0ED2404DFF2D45E01FCC89A4A4482 +:10A20000DD04D7ECED472BAFA3E5D991EA59D7C1CF +:10A21000797898048B35F8FEF2EA91B88FC401FB87 +:10A22000BD83AF3B2712DE3012EACDA6F548BCBC99 +:10A230008D8F3B2C12DE761DF8EF4A583F46F9F71A +:10A24000797B97511EB2B68FF0F2DC55A7BA46D093 +:10A2500076B991DE97AE857A1DD67A9B79BD51503D +:10A260000EF3085AC769E5F390F4DD04D0438A90F1 +:10A27000F4E9D08F6AED678381BF505E8EFFC6F22E +:10A28000870DBE90C0478C762D29F6DFE0273BC1B5 +:10A290004F3002FD5598E6B426F7BF96717E65E013 +:10A2A000572A3C270B448B7D47C22E6B7EB649FF55 +:10A2B000837C28DB5A3EA1C05A1E1C65CD97945959 +:10A2C000F3DA244BFED33E3F4BD409F460F8590C2B +:10A2D000DFCC0E95D149DC8FD7ED34DB2539BCDEE0 +:10A2E0008375CC1FD3E8E1F4C4FD322E4E97CD2503 +:10A2F000CC6E31D6FD24E75711EEF7D8D5D0C6FC89 +:10A300003063438E7CBA9F2DBF938203F9A11FE770 +:10A31000FBF1634E8F07B8FFE6877C5F1EE5FE9B6F +:10A3200047C07F03F40AFE1B3BEC3FF3DFB473FF2F +:10A33000CD43E0BFC17DADE67E98D958DE06FE9BD9 +:10A3400011E0275A80E916EEBFD9C4FD371BC17F43 +:10A350003302FC422D980EB231BB7CEBD45036F860 +:10A36000CBF64C4D6E170FB231BCC8074586A6B967 +:10A3700024F46517E02F456C3897293F167ACE4DA7 +:10A38000F323A20CAEE50743CF4179711BCB17F243 +:10A3900071409E807CA1FF60713639541B32E1EF21 +:10A3A000B817A3640EDDB7B7657E0EA051D5232B79 +:10A3B000EE2F8572D8A73785508F3C1EFA25CC8F9B +:10A3C0001F0E0B401E83EFEAD5155A4F5DDC1D8230 +:10A3D00036BE96CE2EB0B335BD0BDB6DAD0CA29F55 +:10A3E000CDD8273ABA051FE8DC902F0EE3FB4F26A5 +:10A3F0005BF12137B60BF5E1E6BA596988771A198E +:10A40000D05E2FD969D517866FB7DA49CD77CD1AC7 +:10A41000D0BF9CE82F53275BFD65CD2503B7F7958B +:10A420005BC7F79426B4F70CDCDE199B39A03D78A6 +:10A43000855893611B14CF17C6AEC1FA89FA9F0CD9 +:10A44000F16F54AF93A72821380796A7A8187A254B +:10A450004FD1781AE4DF433C5FCDF22A8B93A0FA08 +:10A46000623E8C43F727E1FC3B44E07C7AEB48C238 +:10A47000ED91DA35A11C9AFF6782F6C449F9CE2A1C +:10A480009DE677CC7088D295806F2CDE41E1FB95FC +:10A49000A144D723DD6E15C96E9ADF131998EFF525 +:10A4A0008B83F084D07F3374B15A260D40F7DB17CD +:10A4B0008BD3A349FABD86D315394612F5EA6B6CE6 +:10A4C000F4FBDAC5B354E0FFF24D41B41F88C6E691 +:10A4D0006FF0B98CF481F76F57C27C7353F87556DF +:10A4E000DB38BD9530FE68E07FC64A86E7A9FA5F93 +:10A4F000C7F959AC53B0F87F06DD545D69CB447B96 +:10A5000028E8013EFAB9C4FC688759FC9A414F8D8E +:10A51000252F23FF36C6CFCEE902B38D341F99C84D +:10A52000E22A287CD15E3C42F97829F27B02F55D73 +:10A530000B7A2A991F3D8AF10FAEBAA00E79C9C3D2 +:10A54000F005EC515E1FE7B3E1AE5921D8A7C61C58 +:10A5500012E420C6751A78D018103134E29312A68E +:10A56000F7CA2AE51330FF9132CE9FEA59172F1A06 +:10A57000F68B04E789BACEEC37167765C4E30D6D28 +:10A580001B83F8DFEC5D89E785FA58A60748A49B92 +:10A5900088F9381F5D2C077FBF1A04596FCBD4058B +:10A5A00033BE7D4D08DF0BFB1EC7AF4E8C4731E03D +:10A5B0009708FF6F71BE9A4792DB1F83B97D93A105 +:10A5C000745E077CB7E5518AE749E266FCBCDE0FA2 +:10A5D0003A66A5012919746B941F90341CC7C80FE3 +:10A5E0008D292CFEAFCB6AA7FCFFAEEF1FB459E359 +:10A5F000F3FE47DFFF1F7DFFFF117D9FCBC7A96BD8 +:10A6000060236C1E962F6F9EBA46C7F559ED7649AA +:10A610000E5AFC1FBD40FF26392F7BAC7AC9E5F3EB +:10A620000D19F527121C66E1BF19D903CB19C3CF49 +:10A63000F1E930439F0F215D90A21262D6D79A8034 +:10A64000CF5338EEA470E47187384E365F97ABA7CE +:10A650005A17317EC2CAB7772E38EA1C81FC5FC612 +:10A66000769E406708E4AD43EB46FE6BF069CA9FF7 +:10A67000C72A8380CF5720FF739544307E6D2DD736 +:10A680004313E10AFC305006E325F021A2A53BA0CC +:10A69000FCBB0C0764F0E3819FB27E603FCBE5C654 +:10A6A0007D187118B9F40FF8D04699CD8F1CB2C639 +:10A6B000B1537C7458E275CF3D8CF2D4E8C7D077A3 +:10A6C00012DB35A9556A32BEF8A610FEBA32009EDA +:10A6D00024FAB548021FA71C54007D6EE88CE9E8F7 +:10A6E000AFEAF36FC956BE2E078CB898FF5EFE5EC8 +:10A6F000A7FC9DF1EB5FD0FFB78B9FEF27D2716274 +:10A700003FA24EC49E24E3E7EB62C2B9B355EF17F4 +:10A71000648DDD13AAB39ED3C89EECE4E7093CCE5A +:10A72000B366421FFE7EE38F147FEF3861633C8C7B +:10A73000CB25C3BF7B07C47BD2FDA981F84F2ABFBD +:10A74000E7916A1F147E40448C2BFB80BCEC1B6796 +:10A75000DAA77D0AF3E79316DB29B86F64C435DE08 +:10A760001E6179633EB56DD6FC7C322B0BCE35E68F +:10A770006FB7118863BC83C8A77A8CF9533DE7FB98 +:10A780000A8BD3AE2575CDC0CFD672FF7D8D4A64BE +:10A7900088435CF2CC8315606F1E50981EF52E85A1 +:10A7A000BF668A575BE8892A703EF1CEC1715FFFB0 +:10A7B0001281F6D1E66C8847A47A2DD8BD89709FA6 +:10A7C000DB629DDFA5E69F385FE37E52AA79C81D54 +:10A7D0004228991DF133C51A3777A97B536F8391AE +:10A7E0008CE720D67B53976A775AD148B2FB5697AD +:10A7F0006A77FEEF1CEF428AF196387A14E003CBB9 +:10A80000E4F074A1201EF7A5D8AA43432928E44305 +:10A8100063BBC0176EAAD77299F54E80017219F505 +:10A82000A68B03F47781D3F1AFF63FAC007D7EF0C9 +:10A83000D8C99970EEB3E8671271C0BAF67B4917B0 +:10A84000B34F1490630B0F4AE88F237257C58DA640 +:10A85000385A8CB8A5EB5FF4632FC6692C7CC21EF6 +:10A860009D41DB2F7CFA9D3184C2E1C29ADEE34335 +:10A87000C1CE784C6071897ACF981BE9F78532B9DF +:10A88000AD3A091FF4D8199EBFFF13F76CC023A17E +:10A89000E3C8ADD86FE7376C76D3B9A064B7E1B839 +:10A8A000B45E889D6709D16281CDCF7CDFC2880705 +:10A8B0007DFF5181CDEF902DEA84F975B42B615A5B +:10A8C0006F59C75F106FBFFCE3033E80C3B2439272 +:10A8D00085BF2CEB90BAEC63303D69C7FB34218F08 +:10A8E00040F9C8526431343DB804E3C797766EFC32 +:10A8F0008BE483F656FAA1700976015C5F9582338A +:10A9000020FFE4233EB01BDFEDDEEB03B8D27EE791 +:10A910002814AFAEF9D8446784F51F4BEFDF1FD57D +:10A920007414C0AF659DEBD97809F4F92EFC634827 +:10A930007FB930CE6E950B9F90172BD05EEFC84835 +:10A940001A6FDF271738BD2E3AF0C92E9D8EFBFEF9 +:10A9500013EFEDD2E9FC17FFC747BBEE01BDECE7F3 +:10A960004E15F8CCB2C77EE72326B8CFB433BFC1AB +:10A9700085471FD9B783D2CB853FD8D1AEBDF0EC88 +:10A98000D95C8DAEFBC2E39F6569B4FE5DCF4E1D01 +:10A990000C70B8EBA92F0F1EC84F00F81AB59BF723 +:10A9A000358AFD6B870416DC7F98A709FBF3DCC1B1 +:10A9B000E772619E1FBC66C7FB8CCBE8B7FA32D842 +:10A9C000AF25C8F721BF8AC279E9FE757F91C624F9 +:10A9D00083B73E54C4C3454A3601D8EF1BBF7675D2 +:10A9E00039A4B6A006FD915EE4DB89ED96BD42F781 +:10A9F000F5CAD4FBF809F99B02F05FB67F3D1B371F +:10AA0000611F3F807F4CECBF8F8BFBEDE3E287D073 +:10AA1000E638989134FECAD8C7254FFDF3807A8076 +:10AA2000C10F2E05DF053C8E70A23DB4CA0E74F531 +:10AA3000845B0FB0FD8DCEA065170E7C924B287EF7 +:10AA40009CB3F5DE0A7CB2F759BBBA9B7E5FF8EC8B +:10AA5000AB4867179E7A49D1904F128F40F5840B0F +:10AA6000A4EFAF1BF486A5FCCC79D91E6F97DD1738 +:10AA7000DFA7A5D11BA66B3EFC7E12BF4719FE2F98 +:10AA80008D1EB94948B26F4FDB0B183F8F0E42B88D +:10AA90002C21DD8A5A6ADD4F6102ECE3C9698077B7 +:10AAA000A9F6D158BF0AEBBFCAB49F7B18DD26D6E2 +:10AAB0005F4AE913FC887DFB1A155E2549E8F442DC +:10AAC000BB5D8678E10BB64BDC03FE82FA5FA73DE7 +:10AAD000857DCFE170293ABFD4FABE28FC76817318 +:10AAE0007B507F38BEFFB7E4FCFF45CE379692F02F +:10AAF000F46CA9BFFC9248481F9A1F9F6F73A784EC +:10AB00007CFDFD0E290A4D13F9C4D2147EA7D7EDA2 +:10AB10004C1F597AE8C818E067EF1FFD09C74B863C +:10AB2000F74BF79F54742E0FA2667990C23F799A23 +:10AB3000CF7BD9E1E4FD2DDBFF97A4FDBD2B87BEC4 +:10AB400001F37FB7DB4674DAC5BB9D52523FEC6F11 +:10AB5000EC364B5C61B3B7E2B534DA4EF2B9341877 +:10AB6000BA714DE8551DF492976D78DE41E4E039F5 +:10AB70003BF813BD2E6D038557A36F3EFA2B8DFE58 +:10AB80009A12E02407AA75B04BE5CCEA72A62347D7 +:10AB90002D76B14D152DF3A6723607E4D05B63CF49 +:10ABA000DA609D6F27E8836FCBA47930EDEF6D5DA0 +:10ABB00008AED692E1B7B5FFF02A896866F967EF6B +:10ABC0007D0BE6437EE12410A722FDDCA9033F595B +:10ABD000B6CB1985B880E79EFA741FC0EDC24376E4 +:10ABE0001E27C0E2CE6B55D6C7D9A73EDDF5EFB420 +:10ABF000FC2C34A6E3D7EEA2F5410FDFEFC6E0FF51 +:10AC00003F3F91368650FE5CFB8B7B66027FA90539 +:10AC10009E4AEBD7FE7830EA756706B1FC9903C30C +:10AC2000A2B02F8B9F7C7629C891453F7213701973 +:10AC30003CF7D4ABB742FEC22FBC182779E11767A7 +:10AC4000AF013AA0FAB36696E37798DF2BA0FD2E0A +:10AC5000823C2B172E9AE26F16414AF9C6A243692D +:10AC6000780FC8540FDB2DB3F7AE0CA23F59CF16A7 +:10AC7000D1C6E9CA063A5CD4611D6FA483F949972D +:10AC800029BDF359FD4836A3D76E6C57E1E078CA69 +:10AC9000CB13DB1BF5CB1D05967A46FBA5765297A9 +:10ACA0000CFF2B79BF8B3A3E1F61ED8FE16BFF717B +:10ACB000D8F7EF08EC9E0A79DC89E76D8B95AEE159 +:10ACC000E9945E9F56C802A0DBC5BEAEE17E3ADEC7 +:10ACD000CF389F5CECA279FA3D9BCF03EA439E38C4 +:10ACE0007A7E04FBBBE41927017C5FF20B2F9ECF19 +:10ACF0002C79FAD3333FA0DFDF7FCA8D7E9325BF47 +:10AD0000B81BF77B89BDEB56F0FBF53E6E477FF332 +:10AD1000FB8F3F9F0B7AC8FBB6AEDCF401ECF3254A +:10AD20009D76EE8CB0AE83DA052575743EFA561624 +:10AD3000C7564F5CC1D5109F028E03C0E3379C2CD1 +:10AD4000DE8A9FEFAEE0FEA00FE7696938FF52E6AA +:10AD5000DF5AC1FD072BBEAA0DF69BE60171A66462 +:10AD60001C21772B752380CF4AB1AF108DE6E558B3 +:10AD700021A6463D490DE2F98394C9CECF6D994194 +:10AD8000525B0AED585C12F15CDF4767FF8B6EF196 +:10AD90008A07B4C1D0DF4207D3A7DB9CA1BB1D68E3 +:10ADA000CF78F07E29AE933204FD29B6AE4F05B6BA +:10ADB000AEC4F97E6AD3EDC0CFE3E7DEEC9CA55EBE +:10ADC000D65E85F34C7282F3A57EEB6774F6A19A8A +:10ADD0008E7466AC6363838AFC647D4300D3750D17 +:10ADE0002544C3FB0141CC4B1C1EF6529D4870DF2D +:10ADF000566373B57BAA43707E017DE2B986278CCA +:10AE0000F8650FD4A1EDEFF010B44F258F4E6A3DD9 +:10AE1000E80F4338C1B90CC049E179B96D06C29554 +:10AE2000B6C7EF2B9DE15D001747CE280B9F52322E +:10AE3000CB2CF97E7033F0E2C07F37FC08C26B7D0B +:10AE4000830353B85F017083FB1590FFBF00BFE31E +:10AE50008EF1ECBE8366A21FB8EFA059E82905FC6D +:10AE60001EA0F0CB8CD355221CEA797C9B414FA9C4 +:10AE7000E817EEA7C0E5836D0D6D981ADFD353C8B0 +:10AE8000F5E14E81C7058457DBB87F1CF7215327B6 +:10AE900039267F1209E8782F0AEF5743B987F9114D +:10AEA0008DFD9554F98C95FF69AFC27AEE7EC1266F +:10AEB00002BF92EA1F26EF6498E87846B5534338FC +:10AEC00007D17FDBC8E5EBDABEFDB4D2C7C6060DFD +:10AED000D34D9C4EB6703AD90AFB0EFEB9A0887BC2 +:10AEE000DA3A9DA0FCBC8FE6997DDF45CC7E6D7F74 +:10AEF000B0B3CB46F71F7992866917F2AFD7ECD182 +:10AF000062DACE5D4A42802FFED7BE1BC5B592CE17 +:10AF100000F843FD1C7EE47081FF66F69E828DC9B9 +:10AF20002922B1346203FB2911BE8DC1A30EB0BB2F +:10AF300053CD272BA8DB73E978596FD8917F67DE53 +:10AF4000D2F95A0D5D87A7D58DF6645690E1A327F7 +:10AF500018166A4DFB979542EFDBE7BC2ED349E903 +:10AF60007810C4F3D2745B5BA113E0BBD1D6190097 +:10AF70003EB8D1CFE48C369B8E7695A93DE78FBE47 +:10AF8000722BFD1BFC589D5C66C16383DFA64FB12D +:10AF9000E2BBC16FCF3B983ED7E6AC1EEE8478DEB5 +:10AFA000D84EA4C744FC6FB429BA40F59446D025C6 +:10AFB00041BF3B29B0B894FE7C00E3563EECC9DFAC +:10AFC0000DEF0EACE1F1D43AA517943BDCFF699C80 +:10AFD000CB1F20D52DF00E4C0BC52302EFD550FC16 +:10AFE000017AD84CF107D208C51F4627133035F037 +:10AFF0007326384FCCE7BF45C745769F4304994336 +:10B00000646A077AC0CF7464A203F442D9C6E259D5 +:10B010007ABD6227C4B3ACF5CC7284C0AFE32FC74E +:10B020007DFFABB7266FA07315785104F046F50489 +:10B03000C9A9D2F8BD5F492D23604F1EF074E3F912 +:10B04000DED54ED132AF3667F846A7C9CF3F1A4694 +:10B05000E7FBF64FB8FEE4F7876F73723F658E4EDD +:10B060008A4CF46DC499124D2725263A5F533C8DC6 +:10B07000C039687FFA4EC1C7F6FED7F0B1C6BC280A +:10B08000EE9B2D916F6452FEEEC154175538DF3B95 +:10B09000D4F42D3FE2D95D000FE2D9DDA7BFFC5308 +:10B0A00041FF7926F2ADB83CD2D05F45E5D1FD1322 +:10B0B000800FA6904747DE1CF1358596BFF3BC2470 +:10B0C00098FD750B62EB511ED4C626128DCEB7A625 +:10B0D000ED7B98CE6F6B47BC3F175DEBC3389A167C +:10B0E00066CF9D8BDAA2523EE2ED4509FCFA84F56B +:10B0F0007F6E6723D623E07D318D7B6E276B4FCA31 +:10B1000035D4A73FE46BACD9620FC139CDB936DA7B +:10B110006E0078D6803194443FC5F704E0EE00A974 +:10B120001B017CCEA0F7BB15CA97000E6FD993FA0E +:10B13000D9573AA7EE00BA5EE90CB533B8A75FD687 +:10B14000BB16EF8854EF4578877D3758FCACCC8F21 +:10B15000F90ED78B892345B98FB75793972F697D00 +:10B16000EFF8BD34D75C1AAE2626FB5A22CCBE5E61 +:10B170007AA892BF2FC2E693043F993EDB6A473E0E +:10B18000348FFB830C7C8DE34BD8C7EF975AF0E9E3 +:10B190008ED856DC6F61E3E8FB2752F87D44F10856 +:10B1A000FC72C2C6AB07031DADDEF0A52DB7D0FE05 +:10B1B0003F7E51C2EF0B624EAC7FFEDEE0FDB780FA +:10B1C000BEFE6F36027CE4E31353F13CF6BCCDEADD +:10B1D0004758E462F2FA1CA7E3F9B18D16FD787EB8 +:10B1E000CB5C05FC8FF3639BF1FB7C3894C17B2027 +:10B1F0007F3E5629C3790DC1F3D173CEF7A7AC01B9 +:10B20000381C2E433F56ED267BD27B29E79C9AE5DE +:10B21000DCB9B6A715FB25543FCACCE2FD99F84727 +:10B220006D0C2EB1C0FEE804EE2DCCE77CA46F7E41 +:10B230003B6D163E72DE99DC4F12E37AC9FCD8975B +:10B24000908EFAAFEF1A465FC6B83D8CEEE2EBB9CE +:10B250007F62B2F5C4D73119EB9FF7271F3F8FC329 +:10B26000F94CC30212A27CA8C64EEB7960FC3B9B52 +:10B2700027809DBDD39F2E98D655DBB688844CEB96 +:10B28000AADD3947A931F51BDF07E72FCDFB90B7C2 +:10B29000419EBAC60372BBDAEDA270AED978F598BA +:10B2A00030DAD98C9FBC630BE6025F3DDB766752D8 +:10B2B000FACE736916B950DBC6F787EABDE5A6FD7D +:10B2C00031F625B1FD99376BFF7A2FF8011E604AE0 +:10B2D0004D2A78F5DBB7FCE4709BE862787986CA82 +:10B2E000D930C24D7BFA35C0EB4D6E8CF74C0DBF9B +:10B2F0002B487820F8A5D05FA9BE53E61A0FE312B9 +:10B3000084436D1BC3834BC12D3E2EC783CAE4EB20 +:10B31000A9EDC3837AA253823DA55C0A0FEE21BA40 +:10B32000638075F4E1C1680B1ED4BA8AA7023D9E02 +:10B33000033D6544FFFD3FA5E8BE49700EB441C220 +:10B3400073A6532E3DEB9B2C3F16F8F3295F64E662 +:10B35000A4F278FE8EBDC5BE39A671CFB6DCE94B2E +:10B36000E667AD4D853F453A29ADF83F873FEFA4ED +:10B37000B8C7B5D259B908F6934492FB738DD4E09F +:10B38000DF529AA7CFEE04797ACA53F0D7282D3D21 +:10B39000E40CAF047ABA5BD4C6CC11E2F6673FFD89 +:10B3A000B361FAD5A78BC15F587DF5691BEA43D815 +:10B3B0001F01BD329FC745A07F6308CA83C4F3D273 +:10B3C0001FB8F2939E8FAE6DA81B07FD12874E54D7 +:10B3D000739C1C617AD4FF86F1F3E3EB516C613509 +:10B3E00008F6A540AA01CF6D72B805EE03DB0299FD +:10B3F0006375135C1F7031FF97F3D8B1967CDADE6A +:10B40000F9A7175582F7CC74F4AF3972E40FCDFE6B +:10B41000695B268B5F2445A6EF0510874CF3163B2E +:10B420009FCE77003BF567028383EEB5F37B75BA59 +:10B430000472EF662731FE50FFFE8311072237B1F9 +:10B4400072BF51DCC4CAB9FF72590DF34F26EEEB3F +:10B45000CD87D775833E73F3E12173C18F75B367D1 +:10B46000C49FE07CE167E0C3077CF733B99CD8EE6A +:10B4700030A7D36FB58BBA8DEECB315BEF5137CCA4 +:10B48000F73BEC1DC76FFEEE98CD4DD3D75F396506 +:10B4900083773B6E83001DBAAE39445398121CC5A6 +:10B4A000F67349A797E53B07CDF29AFBA3A62AF4CA +:10B4B000B79C9DF37EF377AF4C05F14FFB5B0BE937 +:10B4C0006D2F1205FA9F73506B66D7F8787F8769E6 +:10B4D0007F62BCBF381C1566E7C80E844B1C4E0E3D +:10B4E000849B012778E606CBE370467DC380731FFB +:10B4F000DCD2665F4FC6A4A6979B3DC3FF44C6C47B +:10B50000E79508E78FA188D2DB7157E88F403707AE +:10B510005CA137205DECE8CD950BF01E630FE4973E +:10B520004AE1BC2C8A671F0C0B8F1804715CDDC9C3 +:10B53000CF5713E9F42DA01788FFE67198B7F2F5FD +:10B540003DF7DDB35E8CB37CEAD55C4897483D9B04 +:10B55000BE01F4F66B09F5EF0F0F8E18302EED2DAE +:10B56000EEEFF8D425F2F303B6BEDBB81E77DB416D +:10B570007714DEE3BCAD5EB2E8BFB7D5B3380E22B8 +:10B58000778FB9C9A24736A5EC07ECCEC47E8CF5FF +:10B590001DCDCDBE02ECC387C62B1AF81F8EBCF89A +:10B5A000E11F6A69DE35CC81E7B29BFC1C7F2B452D +:10B5B000DCF787FC21F768F03B6D480FEA749D1BB0 +:10B5C0007E493A450A9FA3235746ABE8789BAF16BE +:10B5D000D167B525F670A40ADA95B2778F54AE8F8D +:10B5E0006EE93ED506F878F6353BFAFBD3BD12CEB0 +:10B5F0006383AD3A17F4F73FB52B49DFD97378650C +:10B60000ACD72EF460BCDB5C127100DF38D83D6B28 +:10B6100030CCC717242AA0FFD99D92C8F464C3CFA9 +:10B62000D125333FBB2EB37C88A7AAD3FCDEDDFA3D +:10B63000E953309E625EEB4B184FEC2B4F7ECF6987 +:10B64000829BDDD7F576A7635CB4778A886F24790F +:10B6500083BD02B4CBEBAE52B07D4418B07DDE2A80 +:10B66000F53A802BB407FE9F7799ED836E05E1B024 +:10B6700095DBC9EDB660F314DA4FFB26BF00FB6122 +:10B68000D4BBCECDF499B3530CFF4D04FD37B9456F +:10B69000AA13DE5BC90D2171136F79C401F0DA0DB5 +:10B6A000F5987F13E1D03EF2E92E383FDE00B2017B +:10B6B000F6D9C6F069C32601FD99147ED9202FFE64 +:10B6C000749FFD2BB08EBC164105DB9BA649E7BDE0 +:10B6D000DAE360F2A6F57EB403C13D0AFDE6EEFCB6 +:10B6E0002DCECB9B62BD3FF430FCF8D325F023C7B1 +:10B6F000CDFC36B9F5DDDC4EEAC2F716230027C8CB +:10B7000087CAD93B87724833C7A1C4E987D9617416 +:10B710009D18075A334189821F406C69C77785E7B6 +:10B7200046ECE45ABABE56A13B04F4A28F17F97B4B +:10B730005EA1B7004E9BB70EC678B675622817FD9E +:10B740003BFFAAE0F9D8D1D0870FC0BBBCBB2628ED +:10B7500048174743EC9EEC43AB0ADAC10EF7D657C5 +:10B76000E17BC1515541CED2584E5E8078D2C6554C +:10B77000A22AD0FA916AE33E82EA02BC182B7D74B9 +:10B780005D099C9F0D11C19744CE0AEC9D91B5AB0C +:10B79000AA54D8D7B56AA660B65B748E077FF457F3 +:10B7A000EB6EBABEC0BDDB548801DF12CBB802FC21 +:10B7B000857A8BA2B1778BD9FB24197C5F32BAC50D +:10B7C000AEF93ECC7B16501379CB64E6A7FCDEF5D0 +:10B7D00061E65F8433C90AF42FF2BF00EE6B26CF17 +:10B7E0006D18E5C2CCF635F3B13EF49345FBC9289C +:10B7F00017BB2A68BFBBFDA15D284FA63A104E4477 +:10B80000EE69033845A76607E1DDE46D1387BF04E1 +:10B810004F54659CE89D0572343ACCF57A3BF0A90B +:10B82000B58A06749EB1EACC2DF0DD1FFCFE9D901A +:10B830006634FDFE1E9007FE9EBF34E0F7E98AC520 +:10B84000BF97F1C6F9CFA13CA35AB1F8093FF3570E +:10B850003FECA6F0D9551A89D468EC7B282BBE8E14 +:10B8600003ABBBA7C3FBD9676F1083BB7939AE6B42 +:10B87000BB1ADDC0E0560E72CD80DB3A51EB84F787 +:10B880009DF5990EC48F22D28DFC6A089C2217C6A2 +:10B89000F725E38DF5CB214E22713ECFB885BE77DB +:10B8A00061E09D4A8CD7A7724C1932C50578FD78A6 +:10B8B000597700F4F84DFEE4F1099F7A587B7B8AB2 +:10B8C000FBEE1F79183E004B6C2BC334341A520F19 +:10B8D000D1D320CD7184203EF67151FB23E2F9369D +:10B8E0004983FD81FA36BA7F475E7817FD83472288 +:10B8F000BFC5F4654F097BD78F125C16BCB35B7E66 +:10B900000ACF4736AB0C476A5B18BFA80DF438E086 +:10B91000BCA2B694A8BB39BEE9069CC1DFC5E555FB +:10B92000CD4D0CAE99A504CF5BC12706EF9E6541B6 +:10B930003D0ABFCC96D5CB711F49B75E48EB6D86EB +:10B940007E617F9AD8FD14427A1C48BF1109CF1B33 +:10B9500029BDFF06CE136B5A07E3793B5C7787FE60 +:10B96000D2F9B8E9BCBF76DA0FF8FFCEB648643733 +:10B97000F2B76E78639868AB282E237EF65696D081 +:10B980007EB57255DD60E081C1C72869CCA3F202A3 +:10B99000E0364FD79703FE9D72A82FC03CDCDBED4D +:10B9A0001AAC7FDEF667EE06BDC51DE86901FE50E4 +:10B9B0003B81CD37BD957E47FD46FB0DD4AF6DB5C0 +:10B9C0006B6C3C0EBF728E671C0EB7F379DFBE93B3 +:10B9D000CDDB352C1A01FCAC5D45E10A656186F7CB +:10B9E000E0D2BC28225D9D80F57BF52CEC77D0EC75 +:10B9F00004BA48C03F635D357C5D35ABD8BA08A753 +:10BA0000273AAD2EE8B7A69CAD731E61ED45F84E02 +:10BA1000FBBF9DAFA7467F1AD3DB5BEC96FE779505 +:10BA2000ECE986F9E4972A9A807066EF6DE6F27584 +:10BA3000E536B1F1724B9F4678917AD37CD12F6A6B +:10BA4000CA53BA3AFB3C252C78CC22D781C874EA79 +:10BA5000BB0A9EA3146DB7AEEBECFA110FB782FFD1 +:10BA6000F33E05CF2B1E17836FE5A11DAA688CFF3F +:10BA7000047F3B03F8F4ED4D78BFEA402583FFD9FE +:10BA8000AF9228E043F189EA748077F189304FEB77 +:10BA9000F01C9B0244E8E37B747ED4746A11805FDF +:10BAA000C60A7FB800F800DD67D0078799E74DE741 +:10BAB00097D192550571489913D2AB147C4238A1A5 +:10BAC000FCC48E59F01E6EE6B11D77C238438869FA +:10BAD0003DB4FC4A6F21BB9F758C9642BDFA33F78B +:10BAE000C27EB4F277ED8B6166E9981E833483D20F +:10BAF000F7C67498A74CA694C5F9C1DEFB2AC60206 +:10BB00005FC1BB2565987691B2FE7CC3547F24AF9C +:10BB1000AF0B49EA5578358B5DBEF7BE6923C17E10 +:10BB2000DF0C7A621ABC0BA87E04F1317A5044B85B +:10BB30006FB675394A33E1DD719180FEB2A5E4F745 +:10BB400022D0DDE6832408F89151FD1F76F33ED61E +:10BB500079FCB86E59211B81FE8F8E3C331DF6296E +:10BB60007A84EA9DB47ED5AF3C3BE03E71FB1F5822 +:10BB7000FC49FBF37528BF57E62A49DF7D2697D09D +:10BB80001313EBA717CF423F5EDEF6ADF8BE6CEDA8 +:10BB90007439782DAD9DB9BDB212F418AD9A62D743 +:10BBA000603AEF9D635703116A33D87995369D7DCE +:10BBB000D7A6B07463C3827160B7473A6467119DBA +:10BBC000EFA8F5ECFDBE8DA51F3AC2542F2DAF7C1A +:10BBD000C2F155FAFD74399582F4FBE9C91F3AE1C7 +:10BBE0007CE6A1F2AA0C80E7C116AB5E47E0713695 +:10BBF0006A078DB647425E3AAFD6DF1184A764EF7D +:10BC00006AABA179E9190F6838FDEC9BF5ADEDB38E +:10BC1000014FE795607872FF7DE7F2626E7DEFF489 +:10BC200002A05B9DB073D4C8FDC8946FE72C235F5E +:10BC3000EF46A6E3DDCEEC93881C3A0E7C39521A0F +:10BC400056A089C1CF5A8B6BF6013F53B8DE4FEA3D +:10BC500016E0FD48A47F09F4A1DECA6476D3B7DDFF +:10BC60002EC4ABB33B6F7C15FCD3F3EA99BE9FB7F0 +:10BC7000F32301F783EA7D4368FF79E5F8E425992A +:10BC8000B72AE2180DFB5324124D83F97412B01336 +:10BC90002254FE98E160F4FBF7B6DFE1B1E33ABE6F +:10BCA0000DC6F3F8F87A3C7C3DB9C1DECA64F1B345 +:10BCB000DFE2E37EE7C18F8E4C04F8AF6226525E6E +:10BCC000E4A4E030CD234FBFBC79DC02FDD1793C48 +:10BCD000E961F7A7BDE53D78EF2891BF833A0F747E +:10BCE000BBCB7D612CB3EFADFCB45F9EE355E2F7B7 +:10BCF000DC047E35DADE793DEEEF01F6BE3A2194C2 +:10BD00006E1DF8ACA8C6DE9D8D1AEFA0D741BD51BF +:10BD10005E8F0A78D03AF2F765009F4D5C5FB8BD40 +:10BD200094A0BD7A7B4E37EA0B739BB8BE20079B6D +:10BD300081C9BA77FAC90693FE802E2C702D357111 +:10BD40007DC190FF5C6ED706BA5B50AE827E60927A +:10BD5000AB353A93AB790126D76B5BE8381A47E6E7 +:10BD60000AB35EC2E4B8B69DEB0F5C0E67F07133A8 +:10BD70005B98BCCA003DC207E1073ACA653CCBCB21 +:10BD80008AEB2D834A99BCCC687D1CE5DA1FC0E99B +:10BD90003208F8069397C35E7A45073005E8E73620 +:10BDA000CAA78FF1F2804AF5B3F4B87EB64EE4E745 +:10BDB0004C84E987185B4FE77998D737BEEFE1F3FA +:10BDC0007BFC58FA5780BFEE8D148C954C748B5EBB +:10BDD0004F9ACF2D67E7F4B9F5EC9CDA1B9CBF4F67 +:10BDE000329D3F6CF5707BD3C0ABFAAE00F48BF79D +:10BDF0001D918FB3F7AAD6537D09FD4FDCBE9AEB98 +:10BE0000E67E0D8E3FA9E489C187BC24E42BA5F012 +:10BE10003D1DDD87FC5AA7F612ACED74A4317B21E1 +:10BE2000D07BE4867298FFE6897FC5B88BBC14F698 +:10BE3000A2C3EB30E0F085F8BA77FA2BCC0EED1602 +:10BE400093DE9399CAFD0F9D3271033C9D11F6DE7E +:10BE5000A1738292B4FE042FE39B195E768F68F380 +:10BE6000C47D78BF31A57C96892E2591A786BC6DAF +:10BE7000857D9E44C8CCD65B9B75B4D3A3D512F206 +:10BE800057760F30C27F77462F51D06FD86A8B38E4 +:10BE9000603FB694F37D551DED703FFD0BEF0B85B4 +:10BEA00007ECF3FA901815F2619FA3EA68E6D7C190 +:10BEB000DFED394BED77F339C52CAFC8E1A489101C +:10BEC0009F98D7C2F06BF34405E7B1616C56BB9401 +:10BED0006FE6BF02E79F0C4E1B261E47FCBADCF93B +:10BEE000CDAFBF67D269D339E299071E290038C7A1 +:10BEF000DF6F090D787F617EFD4B93F624391FE8D3 +:10BF00002B073BCA037660F49BE67396855E6667F3 +:10BF10002DF11AEF3333FE06FCD586C645341BFCE3 +:10BF20004B07AE8EFAD07FBF989DD7DEC1CF6BDFB7 +:10BF3000DD7323BEBF301AEED426D9F7F30DD6F742 +:10BF400017CEEF7D249BF935A216FDEA8E7D3F19B1 +:10BF5000C5DE9FD1F9EF72102DB382BDA38D72FAA9 +:10BF60007850B74BF1F7D114F85D0CF0B703051713 +:10BF7000C22BA09D987A807E0BE1F7857A315541DE +:10BF80001C15829D14C4349354639A45EA300D9075 +:10BF900008A6D9A413D31CB0730B412EF462AA11C6 +:10BFA000552426BE5F4082982F22D598CAB06F19BB +:10BFB000F17309B9C381F117707E01746F9C531836 +:10BFC000E7FB377B6B1EF02639AFB8C71BDAC1BE63 +:10BFD0007721DF9ECB59F8891F8DEA84FB3D2B36F4 +:10BFE000B1FB25065F47BB86F6FFC3742607F46DD9 +:10BFF00002F2AF35EE99D7201C5B6DEF9BCF1B880B +:10C00000C35104BF3F63F43B97FB17E672F907EE99 +:10C010006D76FF2E88F77FE6829FC1544EFACAD90B +:10C02000FD6BA31FD13D79F840E77BA6F6188F5C26 +:10C0300093A0FF5F526E27E4E725B6FF1B9D505685 +:10C04000DC0FF7C36BB45C76CEC4E43645240DDB5D +:10C05000B5D84FA21D16991A32C3E5258EFF863C2E +:10C060009997E0D74F4CE7C99C2E12FAA192CF0FB7 +:10C07000F766F00D14135D1BEFE81ABFD375472860 +:10C08000AC0C61CD02B08F2A9F7784ECAC1A42D3FE +:10C09000739037F9F37FE70BBFED35D1891AAA13F7 +:10C0A000CDEF34CDE77438556AAD04FE76364C8258 +:10C0B000603FDC41EA36833E465E9190BFC13D6CF5 +:10C0C000F8FDA06170A0918E795DA1E9070DEC5E8D +:10C0D000CE1978476904BC7FCDDE517A0FDE4DA2C0 +:10C0E000E9E8B6BB67021EBC0BEF27C1FD5B4EFF44 +:10C0F000C6B8A33BDD7340EE8FEEBCBA16EA8DEEF8 +:10C10000B0E3EF45951C5C5F0D7E2178CFC545C738 +:10C11000C9A1E339D2818F1094B7EFB5BAA26BE809 +:10C120003CDF6B93902F7F522AE2BB23F06CA6C4B6 +:10C13000E797960EFDFCFBADA087BCCBF988F17E9E +:10C14000E47B951ADAC7BF3CB04E807B09EFCDD1B6 +:10C1500070DDEF0DE9CC4D07B9E463F1E545FBED8A +:10C160005D05741E0B1FFB43410DF0BF82C8C26406 +:10C17000E7CCB93E264FDE7B8A603CDC7B4EFEFB83 +:10C18000488E4E9FD9CF1AF00916BEF59E97FFCE66 +:10C1900052CE25EAF1F872E2E9F431BAEFF4C1794E +:10C1A000D4FDEE1FE1FDB5334FB1738A5F3E509B66 +:10C1B0000BFEA8229FC6CEBD0F3C8971E3B00EB026 +:10C1C000A3E9FC3498DFFDEEB7DE05FF036D87F7CA +:10C1D000338C76670ED4B2FA6DB4BE0FE14E7C6537 +:10C1E000800F0CEE643FE31386FEB8289A85BFDF0C +:10C1F000102F17B11CA6E8A4F01FBDFF063CD7AA5C +:10C20000F0A5337C563B47CDC2F94772611D07AE9E +:10C210000EE7821FEF8CF17B52722417E070B33768 +:10C220005CE133ADFFFCC96790BF9788756FDF0B8A +:10C2300078F904FB3D93BBDFD82A9AF9C7541FD382 +:10C240007BEE772FF5C179D499BE7775222CDEE786 +:10C25000307BD77511A7BD33EDD47EA2F038BFFF78 +:10C260007B587EA6EFDD9B4E8C273BBFFFB9744801 +:10C270006B783C3F89DE88F445E1D2E24822AFFA90 +:10C28000EE4545D97DB70B027FCFF441036E75CAE9 +:10C290002CCB7915A3EF9C9DF9C7505F8E26BF2745 +:10C2A0009728EF13DFA7BDD43DE0539C4E4FF377A3 +:10C2B0004DEEF1866B7C49E448CDC625B900E71AFE +:10C2C000B85387710E95D782BD8DF74DD8FBB45DFD +:10C2D0000827E3FD59FDAA6B21CEF18C9FE5BFBB7A +:10C2E000B97A9DCEE1C8EA4F63EDF359F97D504E1E +:10C2F000EBFFDE5BBD9C8D4F04F6FB48363FFCCE6A +:10C3000085C1FF52AFDFFA3B171DC093C7637FF7AC +:10C31000607F32ED6FF43FDE9FC16FFEE17E1CFF58 +:10C32000B5FD187C18E81242F6483038EABF027EA4 +:10C330007F6F7B323BCFC2CF3F7DA0B019CE813E15 +:10C3400009B077A2ECADAB09C8A5DBB76F4DFA3BDE +:10C35000797D791E4FA214523A33D1F3F39CAF3E4C +:10C36000EF8B9F07C0F9CC7042F87B175455C9C2B8 +:10C37000901BB4FF46F077E34B4804F5AB51A41390 +:10C38000D352D28DE918D28B291E931682AB2F88F7 +:10C39000E99F2B7B2A60F18B1DE1872054D7EE08A3 +:10C3A0001F077CFA6058F8117807788D7BE924988C +:10C3B000FFAF7DAAF17BA224E1F7D9E2BF2BA281D6 +:10C3C0005E332330905E4354F9FDBEF88D027C4706 +:10C3D000F8651FAE2FD5EFCD25FC8E25BF476CC06D +:10C3E0006109E9C438885FEE5CF102BCEBB370BF51 +:10C3F00017E5C1F09D4DF87B620B497716DC2F1DC8 +:10C40000CEDF93206DEC1D0FE39D88916D76CB3BC5 +:10C41000164B127ECF6811FFFDB14589BFEFC5EF06 +:10C420006F6E840F49E20812EF7FF6FA52BCE75AAA +:10C430009AFC776512EF7FEEEF1431BE6705C40BEF +:10C440000971BE37724F9DDD8A5F9DD71499DE83D7 +:10C450006A1482CC9EF6BA427B85FEE38C53197E29 +:10C460001D1084A47164DF4C33EC9B26723DEDA754 +:10C4700071B1AC82BDD91875E13968A3CAECC2A10B +:10C48000DE2A07D8E9C42FAA703F659A3419E3CB96 +:10C490009525F23838F73CB67B6137DC5F680CC80D +:10C4A000E8A71DEA67E7A0648888EF0334A94FF87E +:10C4B000E7C23E79D839E33095E0EFA11E695F29E4 +:10C4C00042BE919A2D83611C21DC8DF76E86C88453 +:10C4D0009FBFCE189B85EF98F138A556BC7F3C6571 +:10C4E000C96927C8F53CBEEF5569F9B84E99EFE721 +:10C4F000AEFA537EC0D3E7DB9B5F9E46FBB3456538 +:10C500008C6B2DF9BCF1F56974BCDE768598DFE3A0 +:10C51000CC5D255BEECFE6DC65CD2B09F788656247 +:10C520002AA7F972181FE148F544735C55668839EB +:10C530000B550FDE0F0EA5094C2FE6F90AC85390D4 +:10C5400074D822552E3ACF8E3705F43B1C6D9F9F31 +:10C550008771FA3F09E7017E1BF890B87F4A9A6617 +:10C56000BCEFE1E4F7839D705897883F4D0DA41808 +:10C57000FCD18EE831D715B08F276CF89ED45AAE17 +:10C580007FCB1E16FF6EE04B62BA3601EFD67E7E81 +:10C5900023E25D2FC5BBDD03E09DAC6AA827D872FE +:10C5A0004810C8C396D99DADD276573CA3043D141C +:10C5B00064D37E5C9A06FACC15CFDDCCDEF5A3F011 +:10C5C000C27721EB9562B0FBEDF599C57206D4F305 +:10C5D000203E7EE861E73F72BD3B08E58DED150129 +:10C5E000CD84D7CD0D6AB15C0CEFE3388AE1779644 +:10C5F0009A53FCDEF330BF580DFE2585DBFF77A68E +:10C60000B1F9DE99E6C674451AF35B3C28EBB360DA +:10C61000FE0F52FC817881237731FC5D31C481F7B4 +:10C620009E573C5F3878A038A07D0D816280DBCEBC +:10C63000BB6AD0EF51B9FC9813DE055BE175A880A9 +:10C640008F926FF8FD9301DF5FB0E1BDAF466F855C +:10C6500036D7D49FE49B807E2549D4B3C1286AD9BC +:10C66000F2D6B5F244C0177D0748A248DAF16B65EF +:10C67000CA5F3ABC7AB640CBDBD25E60E583F41D7C +:10C68000022D8FA6FD86E587E9D9F04B221D692F83 +:10C69000B37CB1BE03F29D69BF67ED41B7A07ACC10 +:10C6A000A1B4D7AF053DA7D1169C0DFE9D1FD1F9B2 +:10C6B00097D2F977F2F4A71C4E46F913F09DC2FB0E +:10C6C000204F13CB9FE6ED0EA528FF292F3F9CA2FC +:10C6D000FF9FF3765D29DA1FE5ED8EA5687F9CB795 +:10C6E0003B91A2FC055EFE628AFE7FC3DB75A768F4 +:10C6F000FF326FF74A8AF6BFE7ED5E4B51FE3A2FE5 +:10C700007F23A1FFB778FD1EFE3DC7DBF23ABC1BBD +:10C7100096D3CE5E022DF1B6A0FEBEB3AE1CF1BF25 +:10C72000713CD3330C7CCF81784D9ABF52657ECD5E +:10C730002B55C6E75FE1785DB9BC680BE0DD8A7F09 +:10C7400093509E523982BFE7AB2F67712F2B9E67A4 +:10C75000F741562C97F1F7800C7C34DA1BF3DFC5D8 +:10C76000E7D764C031AD809FB7048A6798E33D5531 +:10C770006BDE41E90942769A32997C29595EE518C7 +:10C7800001F283CA17E09B6B3D4A17DCA35FABCA7B +:10C7900058DE9459A542B9AECA287FD6665639E606 +:10C7A000A23F271DFD13793C6EAF4995F11EBFECEA +:10C7B0009F82E5D37E3C43053EDA447AFD95B0BEC8 +:10C7C00055329ED71EA9ABC2EF79FE8FFDC09F7F69 +:10C7D000E367703FE63DEE84775FE5EF88282F86BC +:10C7E00003FCE8B805ABC4A846AB1C535788907F40 +:10C7F000B889C92BFAE71D6B7A77B16365C50B1051 +:10C80000BFD3B8490EC2790EFCC9267950C47FF750 +:10C810005453D32DF2EA41EEC7D5030E8CC32B92AD +:10C8200049C0FC7B989A2AF17729D83B668511ABE1 +:10C830007CCA6FB1BE63F39FD7EF7F0B008000000F +:10C84000000000001F8B080000000000000BDD7DD1 +:10C850000D7854C5B9F09CB3677FB309BBC96EB2FC +:10C860009BDF4D801024C006420C88BA090122A229 +:10C870002E880ADAE286DF00493670A962C5B22145 +:10C880001103450DB71181825DA85AB462438B1222 +:10C8900031E88A88F8157B43AFF6A2F67A17A48AA6 +:10C8A00080B06A45FB63F9E67D6766B3E7245168AB +:10C8B000FBDC7ECF870F1EE69C397366DEFFBF99D7 +:10C8C000CD23CA89A889E09F8BF984289A764EA344 +:10C8D00069B052C4DBF4AFD16553B52DB664C787D8 +:10C8E00049F41F5EE2BDA82364D9EE65932DB439E7 +:10C8F000E917C503A2C584AC30A58C2003685FF896 +:10C90000732D21CDAB3AAE19A42764EB2A3A2EBD84 +:10C91000367F3D7A26292524966CF1ED900859B38F +:10C920008A8E3FB8A7FF681BBD3986906D4A683A6A +:10C9300071D06B58214D745EAF2C9709B497B94DE7 +:10C940006123EDB2EC8DFFBC6E08B497CA5EE2E9DC +:10C95000795F7B7D72956B307CFF2D3A2718571FCE +:10C9600090069F1C4DFFAD045CFE644206B625ACEC +:10C970009FFECD6FA5ED84F5EAF57E9BCD4A48DE9E +:10C98000B7C04DEF7CCB1E2886F1151C5F3B8F6F27 +:10C9900083EB1AA9B1880CA4573A57804FC829874E +:10C9A0009FA0EBCC5E71EFB8936984641DB2B400B4 +:10C9B0005C49DBA384A413A2836FD3752B92CF436E +:10C9C000281E5AF24BBC12BD1E7ED6C2E0946345AF +:10C9D0003819246FC6F5F46A94FD36189FFEF1C12C +:10C9E000F80FE458B6AFCB8766C00470C8DE4907BD +:10C9F000CC84F6C0B53E85E289829B8CA37F43BF81 +:10CA00006BF5D175ED94E2ED6A6877840DBC3F89D2 +:10CA1000C0FF76CB127B4EC7575C84EC9224F63C69 +:10CA2000E4ADAECAA6FD15DB30C54B48D056DAAA38 +:10CA3000CF81E7B278DF47CAE9FAE07BBC0D70F935 +:10CA4000F941F1BCB2B56A101DDF40C4F821E8BF5E +:10CA50005B9679FBAA56187F57A5787FF05A5F3608 +:10CA6000CEE77A9D9D90FBDA26B65ADD3DF37D68D0 +:10CA7000C3F5AD4D747D9F78A2297419A47EFBC9BE +:10CA80007442875A3333E007380261FB8713724AD6 +:10CA9000F220BD08FCE9F75484B2E8ADF387FE9CB0 +:10CAA000524CAF415DF45012855F7D67C0A42FA04A +:10CAB00070D6FB4259F93DEFD5EF994602946E824C +:10CAC0005D2578EDE3BDC38AFC77BD67325CC2F7B4 +:10CAD0003E89FCB6E119FAA85E1768B50EC4FE845B +:10CAE000E1BFEFF589F73F79E6B7B7C2F7CE79A294 +:10CAF000E953802E23142E7DBC27FA37745610A0DC +:10CB00007B29C9B7DEE624641E853971027F357A38 +:10CB1000A17F87A9CDE6A5CFCDFA36BF97F6A7A806 +:10CB20000CCBE53DD7876D83703CED7D2DFF749870 +:10CB300048DA544AD7A13AC5FB0481762869046DC6 +:10CB4000AFAF574637D129AD2EF9DDA862683F67F0 +:10CB50002546DA6EAE3BE82A063EF21A08152F6427 +:10CB6000FDD80E37F0714BBD61E6E340BF9165AE75 +:10CB7000F9C53DE33F64D7E33CD6BE46F96C24BD1E +:10CB8000EA3BEC12BC3F5821C087663BC5336D9B26 +:10CB9000DDA924940FFDACEB811FD7EA03D595D016 +:10CBA000CF2D9327E877CD83675457D279B89CB2BD +:10CBB000A4C379541D5B409F37DB0C20D9C87BF69A +:10CBC00039CF019C7EAE781B810F7F6EB5DA42F4BF +:10CBD00001958D3EE05B65B0230C6DA38E3476D05D +:10CBE000F96595107F87B5679EEF71F9F89ECD8046 +:10CBF000705E6FEE985641C7B12C936D21FABDB5AA +:10CC0000F51BBB27D1EFFCB8FEF9A34DF4FEBA74B7 +:10CC100085C03CAC0E256248A1747C039D239DF722 +:10CC2000AE26BF0DE467CCA9901DF4B9659081785C +:10CC300012E4A0B598B613E4539A43F199E9FB7F47 +:10CC4000B2078EC0FC47BFF99609DE778D9165600B +:10CC50009B0E85E139A5543D8E6DBC7A9CD42AF596 +:10CC600073C754F5F3F419EAE7AEEFA8DB99F3D4F0 +:10CC7000ED5B80DEC640473AE732BA0EF68858A22E +:10CC80009FAE2229089F7700FE9642D90BF031D73C +:10CC90003F7E6A017D9E05F284CE9F8C20E127288D +:10CCA0003E0FE47EDF13A57036A6367AECC5BDE1F3 +:10CCB000919563BA1EF0651DA4D808ED6FFDFDC700 +:10CCC0005FC3F85692D02F1FE0E3FBC43686B55DF4 +:10CCD000743EC9F00F0FC0BBF17FEE03BD7754E780 +:10CCE000057867D52BF8FD076778C2BA7CD69DD04A +:10CCF000FE29BC7F8A697DB76E04BDFE7EED525D64 +:10CD00004A6FB8A6934609F892D207EA0B524350ED +:10CD10005F3C20935AA01BCAAE04C6B3C10B54CECD +:10CD2000F8530D0827C5CEE887FE4B86E7E936366F +:10CD3000A6C13DCF0CFC7CFF2146FFF71BD838F184 +:10CD4000F13CF851544120276D765935CE461BEF02 +:10CD5000C3DB4E3B6BEF3E987A3DF0E5C619A9A3C5 +:10CD6000804E8C3209C07803B24DBEA1747DE63787 +:10CD70000C21890E3A402107F5A9B4BF85DCE9A74B +:10CD8000F3D87CD812D2D1FBE6F9FF6EA34026255A +:10CD90007CDEBB577BFF13E440AC4641389A9D6D67 +:10CDA000B651C56C0D213ABF54F807958F1583DB3A +:10CDB0006D804F73451BEA6F73495B1BC069F35469 +:10CDC00019ED89D47932D2B339A7E3E8207A5F3FED +:10CDD0005FB6C178A954B11BE8203FCA6EF3FB616E +:10CDE0005C0A73B98C910A8C8B2BA4DF49E37075B4 +:10CDF00038F6DC2DD171D260BC11AC3FC0C9CEE198 +:10CE000034D6EE413E75F071D306D1FE23D8382DCD +:10CE1000653DE3083C6EAE2661989FF8AE18273E4C +:10CE20003EF1492057F5BFA670A37892724D38B9EC +:10CE3000FB1793B0311FE0E36FDC8E7C6D253B80E8 +:10CE40005F1CD99540479987B74C9747C07B16FC24 +:10CE50008E7E3E09031D672AC4744D2AD82F7E8416 +:10CE6000A3965FDD07DB6EA63C12C78B967FDD0ABB +:10CE700069D5A5F6E663B7C3515938A20F7ED6F03F +:10CE80008BFB70EC7B40F45ABE7E2CE95C09C085BC +:10CE900024F6D77D7B5BA7EB383A09909541F504E2 +:10CEA000057DAEE67B84FCCD086D89C89E8B034171 +:10CEB000EEDB391D537D459975F728DB042BF0E92E +:10CEC0005282F455B977FDEDBFA6E35D186CB081D1 +:10CED0005EC939DCD60DFA91740686001EB62A8129 +:10CEE0009F24D1E75B8F651090DB6BCD6426D0B7B4 +:10CEF000C2E95CAB5F1E02BE71226B8465D7DF7F27 +:10CF000015F660C7A0F461361B8CFBFA6193F37FC2 +:10CF1000D1CE0A0D433B2BFB60779315BE6F9BDC94 +:10CF20006AA2F035BFC9FA3F48DBA14100BFBA3C55 +:10CF3000E0C303390B104ECABB4602743A5CE70BE0 +:10CF4000439BBC6726207F773EF79D5A0FC89FF40E +:10CF5000291E90433F017EA7EBD9C6F95EBB7EC573 +:10CF6000E00B803DA1BDFF685C2EF94FD5503C0E13 +:10CF7000FFA981ACA30F8BE439ADF9C0176BA9FCF5 +:10CF8000A54FE7E83C0D3F947AF0D369AED86587AA +:10CF9000EFAD32918091AEEB2B89042873E6387E99 +:10CFA0005B01F227974424D0B3B98DD4E005BA5A77 +:10CFB0006E2181047ACFFE4AC1FE9D66DF2E3B972B +:10CFC000FF262A07F4EC9FE4E7A97E52E360320AC9 +:10CFD000EC17FD3396E3203788A3CA17F7370A808A +:10CFE0007EA9DEA7DFDBC7D7ADA76A423F8AFEB5C1 +:10CFF000CA11E388DEFD5FE6FD14933502F252B1FB +:10D000001E3986F2C5A69C4DEC670A337D43EA487B +:10D0100078B0C4E082ED7FB3613B8BCA5FE328B494 +:10D02000FB434698670AF33F88CFE771A403BF101C +:10D030000472B689B49A683FA476CA6F6ED26D4600 +:10D04000BBF920F1003F5088D9C13F845B00D7ADC8 +:10D05000845427F281B88EB4313E5056E8D05F1A1E +:10D06000F6AA19E7A36F246133D84330370A6F65F6 +:10D0700039092BE06FAD3060BF91360FBE67208D50 +:10D0800068CFEEFAFAFD4C90D39643D41E1B097874 +:10D0900096514E592C6AFE23A409E1F409E7BF6DAD +:10D0A000AB6C88E7B87F16788BE339DA04FA22771D +:10D0B00079AA0ABFA25FF6575924303A71DC308E44 +:10D0C0009B3DE8A0448AE1792E3EDFB6CAF32DE30A +:10D0D00017F433BE1BE9A8FFF1B3F1F9B6C85BF64C +:10D0E0001B2928B6C60EDAFD9E1EFB5A0BE7ECE59F +:10D0F0006AB93CB253DD167031EB7D8E6914E6E6F9 +:10D10000EFC9DEED74BC2B8FA9FB55E7BF8DFE6D1B +:10D110004FFF88E366E84FFDEFED201D4EA9FBFBB6 +:10D120002B5EB3031FF7F467F3BBF62B753F2D7E21 +:10D13000B4F3A5F372DE9230AF0926A3EAF9CC9AD4 +:10D140005EF372DE9630AFC92E75FF4053DFF3BA3F +:10D15000BEC8F88DF312FD6E2ABFB47EDA75DC5CB2 +:10D160006DEC07EEACFF6D332F6DDC3B6ABFB9DFB2 +:10D170009D2BB4DF0921BD5F2FF97CA9F43A076E1E +:10D1800081BD68B5A0DDABA5975D5C7E4E067B8E4C +:10D19000F69F95EC9B9C4ADB1305DF3DF5BBDB411D +:10D1A000BE1C7EF68A0C90EB59A0E7109E2CAEB008 +:10D1B000BBCE857185EFF2FE549FB480BCD8BD9381 +:10D1C000BE97C2E695683FA5D531BFC24662C8CFBB +:10D1D000C25E4A253689F9E3CCDEE9EF3BDAF1D7C6 +:10D1E00071FF73EE8A09E403CA87CF1B6C150AF836 +:10D1F000678F49680FCCADF2E992297D8C6B953031 +:10D200006E34F79E7F1B0D7265EC494F6794DE9F6D +:10D210001BB67BE1B30DDDC417A67495A15B5A72F2 +:10D220001FBD3E7280DA3FBCBD14E8CDEAF380BF7B +:10D23000510333A2E39CD53796D8406E7ED7EA03DC +:10D24000B95933C3F70EAEF7AFD42AA1FDE6B3A5A3 +:10D2500093BDEDD30C1E6A67D47CC7530E764F4D39 +:10D2600087D9875713512C741D35D41E836B868143 +:10D270002866B85A8809AE65AB99FD9552EE37D449 +:10D28000D0EFD774FDEC0B786FA1127985D993613B +:10D29000C45B4DD71B7F027B6DBECF6F0079316CB5 +:10D2A000A781D9A49C1E8677A8DB200F12DB25114D +:10D2B000757BF46175FBC35406DF7D527818E06717 +:10D2C0001F5570E017877619515F1CD86F44FC2CEE +:10D2D0003963D90EF1A7094BAC28D7CF3C6DC6787E +:10D2E000D43EB9E35968879E4D42BFFA9577F795CA +:10D2F00049B4BDF817C9323C7FF16B1DC21996A322 +:10D30000A7F7973C3B74FB3A7A7FC9E88E321BBD86 +:10D31000FFFC158474C373253C02D6F7FCDF743818 +:10D320007EEC29637807A587332FFCECD97BE9F7DE +:10D33000CF3C95952A51BC5C05FA80F61BF75393B8 +:10D3400005FC8C71679E1908F262C94EA36A5D4F95 +:10D35000A7327B83223305E8ADBF78E289B53FC3AE +:10D36000F78B4E1D437ADBA70FC91658FF5A465F4D +:10D37000DAFEBB5399BE11F380F7F2297ECE7F6CA3 +:10D38000B913E2684336A9E13B34AC6EBF90CAF4EE +:10D39000FB1C92703F1FC62B58E3023B753B417B41 +:10D3A000A6E8D4EF6FCF073BDAC8EC07ED3C0EA43C +:10D3B00032BE7EFA693A0E930F3A663FD315537E1A +:10D3C0005CC2E9F84589D9AFF4CFF22C4AB74B409B +:10D3D000F117F4DC5FA2998718FF077C9D0EEE57CA +:10D3E000C7DED4213E4EAFAA1D7D7270EFF97CB826 +:10D3F000AA716895BEA7BD60D3D2436EFA5EDD6E9A +:10D4000027FA89E27EDD53AFA6DF41EF9FDDA978E1 +:10D41000C174AD9BF5E443E3A0DF53BA0E982F3CF3 +:10D42000F7D1F59EED782D05FA2DD86A1FA54BC0D2 +:10D43000C3C24DDF1B5A95200F2F971F04FFD671D3 +:10D44000FF766F79F7A42CA0EF4D9217BA2DE9B8AB +:10D45000E5E61BC056D9AAF30EA6CFCB14E2D78DB2 +:10D4600042D77B065CEB763F7728933E0FEE1F5347 +:10D4700006EB5A27FBAF1F0EF4FF981EE3585AB86D +:10D48000FC85E39BBE1F91E9FBEB6EB5D686AD38FC +:10D49000EE41681F28DAA183387BCA292A9FD8FD6C +:10D4A0006332E5C9535DF78F8078E23EBDB515E87C +:10D4B0007C5F32C34368970EE53C89B0758CE3719D +:10D4C000E325FFDD6E50E8F5D4A9D529158C8F50E2 +:10D4D000BE805076D0F5D5FE7438F2DDC24D6A3E7E +:10D4E00011FDC47C1785D5CFB5F4919526E20DA426 +:10D4F0002891CEB4FDD2A6860CC057752BA83C4E01 +:10D50000B07FEA4EB619C06ED27E072C4022F0AA38 +:10D5100043FA241E5CAF99AD979AAC26BADED3F0DD +:10D520002F16F796C02F5F2CE112C9922B489587D2 +:10D53000C273C974520DD77D52E4211D9767187FBD +:10D54000DF9584F2ECAC2DFAE48F81FE9EC9F18662 +:10D55000E8A34C1E973BEB89A4A4D2EB79E00BA087 +:10D560003F1B6B2FEEA2F29CF2F7994F0C28D79B32 +:10D570003A5E4D017C9D7DD62CCB142F6776A75546 +:10D58000423CE76CC7AF53605DA73BD22A212ED740 +:10D590009FBCD1CA29A1CF8FC33FC7526598E6BBB4 +:10D5A0002A0DE4564B1A18E32423ADB1A4B10FFEA3 +:10D5B00017EF390C8D251E901BDFB57A77303811A7 +:10D5C0001F6D7F76386D07E05BC8A91A898D2FDE45 +:10D5D000BF318EC76F968FD5EB86621EE833E21996 +:10D5E00000F27A1A287AFADEE1570A0780BD20EEA7 +:10D5F000373AFD33D2E87D5765B74F0771C429C468 +:10D60000DB4CBB7EA0F3DE65A3F89A47A8FE826BD5 +:10D6100069C08071971627AE6FAE42220AA5F7B98E +:10D62000A05F47601BF13577AB146EA6EB99B75E30 +:10D630000DAF05EDC61E3AA17F17112A608111B703 +:10D6400026F4A3E32F023D4AF1B0D844224974DC0A +:10D65000C58FABDF5B4222389FBA672E1AFBC2C769 +:10D66000171C1F8D4E5F7D9A4A0EEA510E2E21FE29 +:10D670006BE0BB4B84BE7E8BE12B78CF3D43E75103 +:10D68000FBE3FC8A7B87CE4B837822F1811D41DA54 +:10D6900093918E975491480E9DD7922E29323CA596 +:10D6A000675CF24B89F96744C1F57FF116C3DFED82 +:10D6B000DCEE994F6F831D7115F8EF80EFCD12CE20 +:10D6C00063DC33522899FA49F34DD4C503F9C4D722 +:10D6D0000BFD07D0F6421242F83C9C968F785B44D3 +:10D6E000BA0D8C7FC2CDE9F4BB0DA7A84C2297429E +:10D6F000076311DF9F132FE2FBDFE3745086F421F1 +:10D70000EE53FB8698537BBF0F78F325C0B976ABF9 +:10D71000BA4D1E4F6817005E683B015F0D7B2E1AE5 +:10D720007D7DE0E991B87E0B0F9D363C913F98FDE1 +:10D73000FC3EC7E323B72C70833C7A18ECC94C3EFF +:10D740004039C86F22E22311131DDF329AA8E22567 +:10D75000D44EC3F62FD2FEEBBA4DD9846CD4073029 +:10D76000EF3057E73F0429B281E9815F01DDCF95B2 +:10D770007DB90AC2D557887EF30A460F8F8E6A1C80 +:10D78000DAD887BF2CE6BF51EA88C8209F5E60F6D2 +:10D790004672694C1F48E0F737D3981D33E040F4D8 +:10D7A0005016D0DF7312C6F7374BA445A2707651DE +:10D7B0003C835EDA2C1D3F047A6CF3751ED24C9FBD +:10D7C00097EE99B6F435F4B92D5EC897D4EFA9D089 +:10D7D000D55B71FDCCEE4D6ADC2ED3E71977168D43 +:10D7E000023EA3EBBE733ABDFFDB340FC2CD6D65C5 +:10D7F000F4E35A1DCA5F06F1DD03FEA5AF01DD0D9E +:10D80000B7601C2D83C22A3915AFAD60CFBA4893DB +:10D8100004FDD63825C4C79A1A32F397C548CDCA35 +:10D820008054763D46AF92425A202E9CA150FB98E0 +:10D83000DD6F81EF3C92C2E6E59475774E03FB7C89 +:10D84000146BA7AE947C3B508F6D403864184935FB +:10D85000AC1BEE833D4FA7E1DB8DCFC338EF8C09C6 +:10D860008D25308F8C81ECEA3044B2619C23824E4E +:10D87000BADC32E88DE55CFF2FDF5D91914ADF3F36 +:10D8800072D6A4803C3FE212F668C40AF628195406 +:10D89000C4FA733DBBBC64420630B52357DDEFBC10 +:10D8A000DE376034E8ABA33ACC1BFDD1EA1B60A79E +:10D8B000FDAE32B07568F1AF7330BC06BF92483828 +:10D8C00021FE109C7901EDFCE0578AEAFED955262D +:10D8D000124E883FD4D51E9804FDEA49F71AA0C716 +:10D8E000FA8E24124EE08FAB2C7D7F57F045F02B43 +:10D8F0001D098D46B2CF8638E9117D6CCD7CA0C361 +:10D90000FD12C6B382D4AF0F25CEEBAB34124AEB77 +:10D910006B9EE9EAFB743DAA76E797D88F9447534C +:10D92000E03BE76CD1143B5F1FF413FAF77C580E11 +:10D93000E947629E92E96188335999FE9A06F85543 +:10D940006229D3937BC615CF61BCD484759E9B6935 +:10D950002011C44B0CBF0B700B0D21644BD7A706D5 +:10D960000FD8235DAF20DC04BD24C22F9498B76A82 +:10D97000EE8EC854565CDD9EB3AED84C517580CB4C +:10D980008550DE3ADF78FA5C27ABE44452695C6E7E +:10D99000A0987A04B2681857F5AC83386BBCCDFBFD +:10D9A000C7DF0FE54FA9A2E39516B3F727B717FC1A +:10D9B0009FD5A003491BD3CF4A2CD79F9CD0366953 +:10D9C000DA56DA1E9ED0B6699E3B34CF5D9A763623 +:10D9D000EB7F363992ABF31232BDBD708A42E5D689 +:10D9E00059776436F5A8C97ADDD02955B45D5FCA88 +:10D9F000F47A4397E44535C5E1D7E06576ABD51BAE +:10DA000035CC2D0638741F02B952D729D924CA073C +:10DA1000D68EDD116CC37B9E84F73A247CAFAEE3D7 +:10DA200038BED7EFF84532F2F9BAA213AC5FC74758 +:10DA3000683FAC69A9C1FCBEC85FEB88DF9725F5DC +:10DA4000E4AF857C3DE7F6BD2A33BAB625FA7341CB +:10DA50001837216E24FABF37BCEB6D304F92967F9A +:10DA6000DA04F6F47FD77F3406ECCBF7B81ED9285A +:10DA70008587C277B790C050D0A3DFAD1FFC8A4C1A +:10DA8000FBBDAF8F6E831CDD86F66B107EEF2747E4 +:10DA900073242A637EE4B88EB59DD16D00CF8F1DAF +:10DAA00053A628749CF773A239326D3FDABE9CB539 +:10DAB0000747B741FB654780F51F1ECDD1D9C0553B +:10DAC000AB9952459F3F61EB9B9F5BB91C11F333B0 +:10DAD0000FF4353BC07EAC63FA671BB57F4D545ED7 +:10DAE000CE5E7C7AD713140EB3BF9F8472EC89B3D9 +:10DAF000374F61FE41C8AF9441FC97FD41FD8872EC +:10DB00005E41FBC20D3A31B5071FC9B9DD1ED41FF6 +:10DB10005734EE06BB25637631EA8FB169BED3F088 +:10DB20005D71FD4526BB9E76D8985CD6C9980FCF0F +:10DB3000B83719EDBA87CD6C3D946F10BF568E8FF4 +:10DB40006D0E66976E7330FF7649DAC4D30E7A7D18 +:10DB500057F26D3651B8BFAB272133C8D94516B43B +:10DB600097EED84EE50695DBED7CDEED1BDC61C85B +:10DB7000E7DF21113FC815213FDAED3E776A825F6A +:10DB8000D45E42DBD61E3FB87D9ACF6D71C0355D45 +:10DB900086BC8F904BEDF9EC3DA18F329AD977324C +:10DBA0001E1EBA03D691A4B0F8D5FC99853B9AD035 +:10DBB0001E988EF3253E9F1BE220271715C810D70D +:10DBC00012F8B962A06F2FC0E5769E17107812F890 +:10DBD0003CCDD73D5747ED09BADEBF380308476A49 +:10DBE0005F8CE0F133B42F4E836E4F802F51A263D0 +:10DBF000E0FEFF4770FA3D3CFF47E154BF82CA0B8D +:10DC0000F912E40587DF4629A2CF60F202FD79B858 +:10DC10000F7AA7332D1083F1C5F767DF5B8FF6A46A +:10DC20009857D2DD7BAB6F23BDF94C6BEFFD19F03C +:10DC3000E5ECB14BBD220ECABFF3FEBB26CC7BBCCC +:10DC40006FE840B9F93EF5A39A40BEF0BC7DD9F724 +:10DC5000971C017F548C1B70EA70BCB592CF0DEB02 +:10DC60005B4BF16E82F94F33A0BF21F46ABB3DBC20 +:10DC700019EA26DA6FC9C6BA89F384D5A78456246F +:10DC800061BFABE41304E2AAB1B136CC9B533AC1F5 +:10DC9000E7EDB30AB17E85D243C80CCF293D419D43 +:10DCA0005F7B095D108C37EB0A7C0EFE3AFAD9B324 +:10DCB0004C385E1F74C2E2D443587D467B3EA7C3F6 +:10DCC00045054887E9CD2C1E4A14DF8869097A7E0C +:10DCD000BC93E139A934FADC7F01CDAF37A33D0B0A +:10DCE0003A16734A6D19381EC5FF60278B4B209D6D +:10DCF000CD7B2899D7C379CB00AE0F2433BADC6A29 +:10DD000066F9AEADD47E46B9C8E957D4E105B89DF1 +:10DD100017AD9553C05E18ED8CC73B7C107FC07863 +:10DD20003B7D3E272A1D07BF6F4E481731425CB826 +:10DD300075A22F9AE0BFC01FC817DEC9E52AD944D3 +:10DD4000D0BFBA13DE4B81F12D29901FBD13DE0722 +:10DD5000FF71E544551E7022C8F0313DF3D3CAFD72 +:10DD6000894E1EDF6C7BD497F81D31BE763CEAC726 +:10DD70004E723A11CE9101E04734E9108FDA7946BC +:10DD800037B1B87974531ED29D18AFBF79FE8F2E6C +:10DD9000F63D89EAC10513987F2FFC9EF9DCFF262A +:10DDA0002BD57E1DC479E26D5DEFB6D64F84FCBEE7 +:10DDB000BA3FB35B928A6306CCFB7824D5FC05BCE2 +:10DDC000FA83439DC0E725C24DE8BD47CD549E521E +:10DDD0007AD904759094BE36DD93847ACC61080FAD +:10DDE00005BADA02F535A84F99FFFEF91175FC4521 +:10DDF0008BBF1FC4E9EAF2FCEE26C0B9B3B7DF1D42 +:10DE0000B4C41E03F8072D8C2FCFED4F46BE2283DE +:10DE1000A2B3A1EEEDFC3E23017E6890A2852027EF +:10DE2000CE49BE1AECD794E401FEFC406671812015 +:10DE30006084AE3318FA0BD65B053BD57EF839FA11 +:10DE4000B796F2CF39395A06E308F902F204EDAC7D +:10DE50005A96876A904908FCB4ABE4398BD09E98F7 +:10DE6000954976E0FDE385E09709BD41FB1D94529D +:10DE7000191902FFD5717C34C827B05F1DD44D013C +:10DE80005EC05F83781F3C4C885337AC3F83755B23 +:10DE90000D7BD47453D74357D24509DE4BA033943E +:10DEA0000B218423DAED2047AA581E3D99B793AA87 +:10DEB000BBB18E2BC8E32FCE03D149209F924B3BA1 +:10DEC000C81C7A0D9E6276CBB8AEEDAF825F6EAFA6 +:10DED000EECE01760AF278A7A01B31CFB15D1B749C +:10DEE000E0370A7B27C16F1D3A5D15B7588DEF816A +:10DEF0001F0CDF8BC22D379015D3931BB99E4C029C +:10DF0000871AF469DB10D4A7A0EF40CE093F1AE4CA +:10DF10001ED0D5C0F4CA23C0F72FA657BEEE74B2E8 +:10DF2000EFA17F00CED7D8FEE94EC047F4037FFAB9 +:10DF30009BE3905C7E13167F5CF686F31BE9FFFD86 +:10DF40004BA6FFA11940E7CB244F06D0F9F138FDCD +:10DF50001762BE52DCFF5017C038A388772D82F8B5 +:10DF60001EBDD67139B480C7C71688B8D826755E6D +:10DF700015E2D189EDC5224EB6D3D8536F04F2A372 +:10DF80008A4492E978F51067836B87FABD061263BD +:10DF90007CD479D1A8CADBB63338DEC9E9C95E15AD +:10DFA000D681FCDA6C66F13221D7C6ADDC8E7432D4 +:10DFB00060942FFF7EE09B37F4186FF903A70301ED +:10DFC000974667E551C0A745C7E381F71B519E9F60 +:10DFD000A476C26E1EE7990EFEF1AAC050A897273C +:10DFE0008A2D37D17F16D775FBCCB5687FA7CB2A92 +:10DFF0007A7DDEC9EA9B30FE85FA2209FD012ADE20 +:10E000004600BD9615087D4D4640DCEDB89EC5CD59 +:10E010001B6EB50660BCA8CCE4A13B9DE929773A0C +:10E02000AB5714EDB8FFC9E951E443210E95988F21 +:10E03000F0C4FB6FE075C804D7BB7111AF778FF3E5 +:10E04000858CF22DA9D88F7AE12AB912E55BEC63B1 +:10E05000AB07E0527DA66E11ACE3B399160279C905 +:10E06000793C1EEE4DB7E3B8228E7DB9F1F0D1E9CF +:10E07000717A54C5C3F771B9B88FB0F9865A8C2C30 +:10E080008FC1E7BFEFD41561CE1F21909BB1DD6634 +:10E09000A68FA99D0CF27ADF9E216158CF713DB306 +:10E0A0006742FB93F9FB81CD10A7D9F74BA717EA7D +:10E0B000A0828B4F8F00FB76DFA9A77FF51BB8BF2F +:10E0C000DFE8057F741FCF63D419228568CFF3FA88 +:10E0D000CFBA944821C4A55EE4F8AAB3D036BD7F78 +:10E0E00083293035DDD9936F84F7E0FE8930F31B47 +:10E0F0004E104607A1F52C2F4CE1EB8679C4D6666D +:10E1000060BE12D60578F860FF709CF7463DEFFFC1 +:10E1100020B32F4FF0F689174AB01EF2BCDF80F50E +:10E12000CBC187993D3B57F63CB60264EF4B49188B +:10E13000079DDF7E14F347C187164E85E7C1C52BC7 +:10E140006F24DF9057013D9518C73F4762B9E8A794 +:10E15000D7167444E877CF750DF5B2F4A80B937118 +:10E160000DBC4EF624852FCC3BB65F8FF0BFD4F1AB +:10E1700031A059C6F4257C279898BF42FDA2CE67EE +:10E180007D5BFB9C3E5A780FFDFEDAD4C00FD213A4 +:10E19000ECD8E04B6E94A31F3CF8652EDA3B6D2C57 +:10E1A0006F7252EF9B0D7C62AF8A18E624C8D78D40 +:10E1B0009C8FE71AB95D4BE56022DF8BE765956AB6 +:10E1C0003E13D747D2995C4EE6F512BD9F8B7ABCC1 +:10E1D0009B8DA08F59C80BC6F5E0FD3C9EC71C77F0 +:10E1E0002AF60AD49DD57594609E346F6504F99221 +:10E1F000C23B02FEC9C9CDC94C9ED065C2380BCA0C +:10E2000009DAD50B74ACFE638191DAE9CC2EC0FE3D +:10E210001F6ECE403894AD66F669EC3909E5A2C8A8 +:10E22000E7D610F6FEDE96E3211DED5FB3532AA17B +:10E23000A295D4B454607DC8E2ADF988FF715CFE4C +:10E24000CE35FA0A3703BDED4D467AA3DF437FA0F2 +:10E250000E6AE046A15C32807EADDD29617E44AC71 +:10E260005F9B3F256175DE695C0793DFA03748A29D +:10E27000DDC9F510E80BA2B16FD57411BA247DAADF +:10E28000D50787E372F2F2F4E9AF417E8DE9AD4F35 +:10E29000A9BF70249DD10993FFBB59BEA99E34B27A +:10E2A0007C1BD767F175717DF8A18EE9DF05C60D7E +:10E2B000783D9E9E8FF35A4CA23CEF1433C0FCFA7B +:10E2C000A3AFE3FDD097A0AB139CCEEA4E91C8D587 +:10E2D000F47B752B49A47E04BB268F40FDCEF4BC95 +:10E2E00089E979B85A2E41DF6BF5BC56AF6BF579E9 +:10E2F0008681E96D414F89F907B093C6AD0CEB58A3 +:10E300009C39DB86FBEB387E97A4F92E668EE9B14B +:10E310000383C74C26CF4868FB498115E26715EB9C +:10E32000B2212F40F500F06F1285D376888B71FFF4 +:10E33000E3EE6CB67E17AF93D22B7E5262053C752E +:10E3400063BC20E624E8BF0BF86E4BA6EF8D82F786 +:10E35000185FC7DF3791164BC2FB95FBCCA8972EF1 +:10E36000BC908C753D54CFE4D9E978E9EF51BF8179 +:10E37000B6CFED4B463BE11CD71B0E1197216B101E +:10E38000BFCE0C86E710A9CC82F83691A66481A88E +:10E3900015F66CBDBDBF7C047F9EDF7D2BA33323B0 +:10E3A000EAEB0BF6E85DD0A6F3C13AECE40C36EFED +:10E3B000E09E0925F742FD85DFEA65500D9480FD5A +:10E3C00061D42DBF15E25E93742B63F7D075D4E74B +:10E3D00058B1BEBB2AEFF7BF9B45DB1FEFD113231C +:10E3E000E0FD899B0744E035C5E7EA8B4F1685F5CC +:10E3F000AAFD834B76AADBF51DEA769024EC2FA4C8 +:10E400002058F1FB926B0E26D0495946B2E3C36106 +:10E41000C096C40BF5E944F79D01813EE4AEB87E99 +:10E42000B9CA7BCD413DD6F75D9DC1F8D900F6D183 +:10E430001CA0873EDEFB23E77BA3B1F114EC133075 +:10E44000BE68F436D1B7CC198149F07E831C3B04F9 +:10E45000F834E69D1D01FAB432EFAF9827BC701F67 +:10E46000F1027C2E982BD04EBAB0D9EC017FB13D91 +:10E47000D7CAE2322F496189F91553C750F95A8B2F +:10E4800053A1EBDD74DDC76C530B31C9885FEA55CE +:10E49000B9405EF9D0CFFB709AC5B69ABE57BB891A +:10E4A000E9ED3AD29D0272E087803FA06BDD330632 +:10E4B00013FD677E8B6F68139DEF12BF05F733293D +:10E4C0005F2B7EA0AF0760C804BF644E069307F5BC +:10E4D000A6A8A102BEFFD779D5CE829E389E41CF95 +:10E4E000E2784A6749248BBEBA70C55CF4BFE2F992 +:10E4F000FACDAC8E6CE13D3578FFD5CD465CDF873B +:10E50000FB25A4F30FB7B1F52FDC64F640BDFBB5D6 +:10E5100076E6BF2FA4EFF5BDFEC91FC3BA3EDA7A77 +:10E52000B717F2101F11F69D908DC5DB3EB2B1BA40 +:10E5300002E80BE37CB46720DA43B59B164DC5FABD +:10E54000BE6D3A2FD823647F32C6B1166EFBDE6FE4 +:10E55000C6429C6CFAEDA500876BEDCBD3212E440F +:10E56000FBF9C3CCBE6675D3A9E54F021F5EFBF570 +:10E5700084EE6BC1EEDA46F9249FED4B007BFFE0A1 +:10E58000B6C968DF2E9C66B1C3BA3C5B9F98047A1B +:10E59000E8A3699932AE6797446C0007FB8A74B8A8 +:10E5A000BF5052FC7DD1537E860EE15A9167F546ED +:10E5B000E0BDB775482794AF6E053D5CBF4D8FF643 +:10E5C000F3C1E9EFFE6E96A387AF16EADA6E1D97E8 +:10E5D000603F05B7DE20E88444CAC02F6330D1F223 +:10E5E00097316F6521CC47CB670B573716B2BCDC30 +:10E5F000E5F11BD9CAF8EDF10C89C56F2E9DDF7EC0 +:10E600007E39FC46B25355FAB7B75C0B613F91D7E0 +:10E61000307989EF092BE6AF7D1295BB6F6528F83D +:10E62000FCAD0CBE8FEB4FCB76BE49E1332B23B054 +:10E630003F03EC28E22B013AF2C46C95B047CBCAF9 +:10E64000ED41B295D9DFE02700BE373AC993EB120E +:10E65000E221DD196C1F21E5FF4330CEB977FE7A48 +:10E6600008F0D3907B7604CBEBFE11F3A0D62E9668 +:10E670003FB77A635857A077F891FE845C0F7A9978 +:10E68000DED1AE2BC3C5FCC2A02386E37CE6627C50 +:10E6900028F20A5B5658301EBCC51136B37847883D +:10E6A000805E9A5AAE63F93F6EAFDDC0E3ACA6D28E +:10E6B0005709E4FDC878566FF766E9AB4A1A6DFF53 +:10E6C000A67CA217F73996FEB4B500D63D5ECF9F63 +:10E6D0000F0CC1BAFFC35781CF97B9741EE0EBA9E5 +:10E6E000A5AC6E94D4A6601CE7CDD20F1CF312E645 +:10E6F000EF27268F95D2C974EA2C25D639DE38DE6D +:10E70000ECB126D0D7676D5235B39B3D03660C67DD +:10E71000711AD4C3A56A782C7319F0BB2FA6577C45 +:10E720000A70BEF61A868FD3BB8C61907FA7F9BEA4 +:10E73000A15E74E1E2F4F39D22551D82C3D0910BDA +:10E74000FAF18CA47E6F71AB0EEB0016B54A244C27 +:10E75000BF77FAA9BDB920C73F7E626FEE9C84F9EE +:10E7600068DF13578BF81E8F776AE3D7FDC5AD4579 +:10E77000BFF39B48C034B0A7FFF9DA3F63DC7A4EA1 +:10E78000178F7BFB7C831CE04FF1FEDAF146BB194F +:10E790007D489D12C64D44DCF6C4E19F4286288E1A +:10E7A0003F7357BE9C58272AAEE338DE6E06BCD1B5 +:10E7B000A5985B59BB3F7CF5C78FFFC1F58FC0DBC8 +:10E7C00089D68103008E8606AB42D8FEBD22B0F703 +:10E7D000B7118B17F8C990E9B282FC12E71F7C6968 +:10E7E000665787855EA9BD96935984EFDD2DFBB1F1 +:10E7F0001EF14BB90DF76FDEAD6BC43AF73217FB64 +:10E800005EB6CDBF7B01FA391D58F74E5AD5F04D93 +:10E810000728809EAA31A09E1270BE6ACE5DE8EFE6 +:10E82000F6819F4D403799E5EC5ED095CFEDE52818 +:10E83000E643CCE5C4067181E6B1219C8FC04F90C0 +:10E8400075275297847632D4EF24A562DE37C4AFA1 +:10E85000C49A4AE2799024EE1F134DDE838AAD10EC +:10E86000F413F304310675400FDB3BDA0A59DE1866 +:10E87000ED4F1817EECF2956306F00FD0CA3BE9D4B +:10E88000DEE274C9EB3BA78AFBB5963EF32C5361DD +:10E890009F14ED9F43F520D87FC4AB57ED93DA4A20 +:10E8A000ED66F0EB441E5B277794B8D00FE98E42FB +:10E8B0009CC55066F2805E4DD2751401DEB4796D50 +:10E8C000DA2F9FD55364DB41AF887D500D2B26F89E +:10E8D000619F41DCCED8CFFCA3867B2AF0FE842E3C +:10E8E000962708B61A711F67B053C2BC5C83DF104D +:10E8F00036613CC4D304F80A513B0CFCCF763BABE9 +:10E90000036BBFCEE60D91C4B87AF4B17B31AE6E25 +:10E91000C57CE4DF9BA73D9F4C013032210F37C0FF +:10E92000C4EB0D59DC3D9DD393C0BFE06791D74D3B +:10E930002EF6E783C5FDE5C6D0AF2DCECBA87F214F +:10E94000B73DF88DF52FE4A31BA0FEC504D63C7F90 +:10E950000ED3A27A33BEAFD1ECC1FC5DFC399C472B +:10E9600061EA94F8FBED374C1C8475BBBC9E66D6FF +:10E970007AA8C37FD84C54DF4B9C9FA2195F4FC726 +:10E98000B77A44FF7BAF9FA8601E9BB7DFFD21D401 +:10E99000FB3CAC578F872428F6619A7ABEB72E6B62 +:10E9A000C883EBC7F7E86FAACFF7BAC6F4E8F10758 +:10E9B000DE9DDA36D203FCF539D6410B7D1C74B0EE +:10E9C0007A18ADDC3AE09284FD3B0954EC9A993513 +:10E9D000787E433C8FDD35CD07E758883C7670A5BF +:10E9E0001FEBA141FFBB50FF9FFDF01580D2F4D378 +:10E9F00068FF07BF52585C89DA1112A543535705C7 +:10EA0000C64FA13C17F4A6C0FF62AE97C05607FAE6 +:10EA10000E6EBDED091D7D9EEBF6FD078ECBFD4014 +:10EA2000ED7C4FB9D8BE816051E5669007E47189ED +:10EA300080DE5E57F419DA190D2F4C1C9358CFBFA6 +:10EA4000A8F311560FBE53DFE7FA4FB9983DDAF03D +:10EA5000C27318173D1D66DB886A95F0DA71109F46 +:10EA6000A995C1D222A5E19A59A8FF67D275D075A0 +:10EA7000FD86DB25C19D3787607F4190FE05906D47 +:10EA8000F12F407B7FCB4C9315F248C1A2394B91BB +:10EA90001F6C161FAC5F3BCF781EFC1E0BC62DD71C +:10EAA00075EAABC16E2AA376D2AFE87C7352A75445 +:10EAB0007BA95CCAD2ED2EF9372BD40FF4AD87D7E2 +:10EAC00067323DDC22F943379562BD2749AC47CA1E +:10EAD000EB64F6D84597411587BFE86276E2F850B7 +:10EAE000F704A0B997946812D8C541E2FB14FC5C06 +:10EAF000E2B77A601C380103EC2CC72A0FC6854D9B +:10EB00008EE80F47A2DDA4A09F21FC88732FB038A8 +:10EB1000DA5277C0EA86F88E2EFAA39B006E3F6425 +:10EB2000FBAB89C2E44DEECDD65110F7323BA23F8C +:10EB3000AAF6601D11C61F065CDD827878C9416C9B +:10EB4000009F09A11A454AD033426E4C88EF637288 +:10EB500060BCB5928B97C1145B1F9A90445B2EA644 +:10EB6000F5D80587FF3A43819BC25E904D01F4675B +:10EB7000AA6652FF10E8724DEC900CF17D4737DA2F +:10EB80008BF51D127EA7BEE89758E7B784D793C5CB +:10EB9000EBBA9428D6B915BA93785CAC85D103E961 +:10EBA00046FF973CC3E04FF526D6BFF5D8ED4DACF8 +:10EBB000EE888F67E079897A1EAFA180C2E7256E63 +:10EBC000116F5BCDF5AFA8D763DF258AA72C31BEC7 +:10EBD000B0711AD524382F4F0ACCB7D3EC1FE7A653 +:10EBE000EF9FA895595CBC35290C9B72374ADD3ED6 +:10EBF000885F864AFADE7F7413FFEE8003B149987E +:10EC00003778A1BF7A6056FFBB79CC1558875FDA99 +:10EC1000F9E924A00F524D901FA9BCB8A47AE019BD +:10EC2000800FE7FF43F5C05EC9B7835EE7BBEDEA3F +:10EC30007A602FC397C8AB6AEB80CFB9230AABDBEE +:10EC40008B3EF604E8DD4E23D6034EED7CFD18C462 +:10EC50002FA79A4807E69935F6C3C9B49B1B004F06 +:10EC6000E73FF9F0B1FB09D4913FEF65F5856A7B89 +:10EC7000A03FFB1F7323097E6248D0CD3FC9FE171A +:10EC8000F23AC8FDA93352ECA14258DF7E9DADAFE8 +:10EC9000FD480FBA45DEB59F7A96AEBEEB5944DC0F +:10ECA000B93A9AAFCA733D1AE783CBCB9B6D819C6F +:10ECB000761F793385D7A92912131D24C7A0CA9BB3 +:10ECC00029F6C2FEF266117CFEDC107CFE40AFBC71 +:10ECD00019AB7768D99FE101FBBECE197BF2490FD2 +:10ECE0008C67C0715A5E480A433D7F0B877FDDA564 +:10ECF000E7CD7EE5EE236FB69DDB6F1F14C91103D0 +:10ED000085EB76C2E61FEA12F93319FDD8D88339AC +:10ED100062FEF8FCFC83C3305E3457E4C55E62716A +:10ED2000B4B93CFFF5C1F442AC67EB0FCE735BD5D1 +:10ED3000F985D7389C2F982B301E7FD7BF4FC3F84B +:10ED4000D40288E30F84B8561B8FCBB3789EA79567 +:10ED50009D2BE0D929853D2C3F6392D136B4C970F3 +:10ED60007F0915A35B40F48628D55C496F4B146A74 +:10ED7000F4B9A785B6A9D1AFAC55422EDA6FFBB175 +:10ED8000248C9F3DE0F0E07C1F686179EAD07A290D +:10ED90003C988D8BE7B5855A641F8CF30737D3F306 +:10EDA0005FBB0D7D9E0FD1A2E7F910FEBD26224765 +:10EDB000E02A4BECFA804DA9EECB7E10E3B5E81BC0 +:10EDC0004D1500EF1C762ECC05836F26C697530B8E +:10EDD000F1FCA796E4C6D66AF61C79F68239E6C736 +:10EDE000E7572BCC20259E5498EF7B6E9E5FD3C0B7 +:10EDF000797E9BBAADCD1369F7BBCD258121EE811C +:10EE0000BDF783BDC7F5DF8575F91C2F5ECC97B4C0 +:10EE1000E83DBFCD077A5FCBCE776ACA6670937341 +:10EE2000D8B5C05E85E7F0113BB7E3089B7FC1D53D +:10EE30000E09F8A1C5CEE8F61F9DB776BEFACC4202 +:10EE4000065F3BE3D796B55298C18BCDFB52E322C8 +:10EE50000333FFB972F103C9FB64241FDF43B91008 +:10EE60007A508F7C778284B3587DA80DE5E61CEE3E +:10EE7000E716677AF0FB5B6A0B52209F3AF7D41AC9 +:10EE80003CA769C2CD569C7FC34B66F4E3EA574664 +:10EE900073819EB57084D92A429ED2E7731C849DEB +:10EEA000EFD3AACE0F6AF3BE6B53FDE3201FD450FD +:10EEB000192D84BCD123F207BB5F67720DF56AC3BD +:10EEC000CAD8931067FE6E6AA002FA9DBDE7DD49BD +:10EED00092075F47F9767EFF10DCD739A745BDBFA3 +:10EEE0008DAC57E71F496B2AC6D549BBFA3EECC328 +:10EEF00052BDD72B1FC9EC9A8D86C050B03BAFBD19 +:10EF000086D55B7CB2482680CF4FCC84E7F9859CC0 +:10EF1000F51626EA81D9FDE295F60338F3FA57D1C2 +:10EF2000BF1EF04AF159C7F1FAC9735716025ECFF6 +:10EF3000EEBEB210F0BA51DFE603BE18981E980379 +:10EF4000F03839D18F76A1A8F7BD547A5B9AC9F50C +:10EF5000E0BF480FFF407CFF32F530FC498C97BC86 +:10EF6000F45756971BEA62FB827BE274A7F17CB3ED +:10EF7000F35FC912C8E1FEC6B371FBCE652221B0B2 +:10EF8000BFCA2AA3F85ED99F650276A0B07FB5F309 +:10EF9000DFC0F1BA23D377C105F8E571DD5A3EB67B +:10EFA00029FC39B3B31F97306E6BF28452C6A15F50 +:10EFB000357FB40EE5CAAF70BF07E9926CE09F2CB5 +:10EFC0007ABC099F9FEB9C8BCF655324027E583DF2 +:10EFD0007D0EED35E3D5F5DBFA3D259144BF97CEA7 +:10EFE000E333F04B931C3103D06703D8D5748A0DFB +:10EFF0000A8B6F373808C6554A3BD57EA2C8DB6EF0 +:10F00000F1B3F373B67449788E56BA21909F0D7898 +:10F01000D5E46F7F91E93B96E9ECC9BF373A7DBBF8 +:10F02000810E1D06928BF57A7AB11F51BD8FB3BF49 +:10F030003AB897057F7CABFD340BEDA42F881FED0C +:10F04000A403107BC0BCFDAD685789FBBDEBE0C2DB +:10F05000AA7CFD02BEDF7601DF6F0BF23EA291F7C4 +:10F0600089EDBA843AB8485FF50C09757089EF25C7 +:10F07000D6C1455472B28DEF07598679F220E59BCF +:10F0800015A37AE8BA8EF03F9B621FE07EA09D46F2 +:10F090008CCFD5F1FADC60ED09F47B82B0BF88F14A +:10F0A00037AB63E7E755D4517F12EB943BD475BC83 +:10F0B000E7FFC9FA45F4EB2FEEFE670D7F8B7589EC +:10F0C00075D475498C1F35F3D4FAD1DAF8B9F083C9 +:10F0D0002F55CEA564FD6BE55C5696A0EF7F4CCE18 +:10F0E000F5CA430C8AA578FF0979888F3D6DE91030 +:10F0F0009A6C9518BD4ED2597D2CCFA9637510DA44 +:10F10000FCAF6712E63545DCD7F4BC2EBC3A1FFBDA +:10F11000635EB77E7F32D625D47A6AD16ED7E63B5E +:10F120001793DD9300055F9023B88FED1FAD2FA8D7 +:10F13000CC8AD717E45F667DC175599791EF7CD56E +:10F14000FA795A20814E2A8BA90350DC7F1DD96D94 +:10F150009CEE92781D8A4909117BC2FBFDBD776741 +:10F16000168B1FBECAEB9F1E4E4EC2F3175C06B62F +:10F170006FC325B33AAD5CB7BF266B0CE81586C7E5 +:10F180009FBC701B81BAC79FE83BF03C8450BDD543 +:10F190000BFA50C4ADC4F8BFE2F1D44BE59FBBFEFF +:10F1A000C9FCF36D722324BE77A9F9BA4D14060980 +:10F1B0007CA5E583FEDEEB4FAE6CC8F2AFCF42B963 +:10F1C000E51B81798F4B944749A5545E83BEDF636D +:10F1D000F480FF61E2FB8BC87AB7CA7F9FFB700E99 +:10F1E000EAC34FCCCC1F11FBA0C4FA1FEF17DE7F80 +:10F1F0009FBDF817A7FF4958CFC90A1FEE7B78209B +:10F2000099E995D853ACCE48BB1F48AB4FC47E1686 +:10F21000F1BD4E21CFFE45F2F4B57F923CA5FA1523 +:10F22000ED8D7EF3BABDDE0FE177CB2ABB7D3CDFEF +:10F2300085FB39C4BC82DDAC3EEF6D8E3F71FF595A +:10F24000AE7733B37DBF033C9C7DC764823C6A6963 +:10F2500029939F0D7E2BE6211A3A585D4EC34A82B0 +:10F260007103B1EF775646200A72EA8177AD787E56 +:10F270006C43E7F6D602AC5708A09D78EE1D76DF0A +:10F280009C113809E307574655F98EB28B9FAFA9F9 +:10F290002EC5F9A2DFEF30AAF75319B2993F2FAE6E +:10F2A000BA6CA1B7A99F43DF3B5BCBEACA830E9F31 +:10F2B000AD02EB14583C3DC9D38D71F0863DA824B6 +:10F2C0000816B9C2F37BB3916E1AF65494E0F90BA9 +:10F2D0001DE6123C47E83D2BFA6B67EFC90C433C37 +:10F2E0007BA93BF017986F7269F83AB057F3E8774B +:10F2F000209E7E76F77525185FD4F09DE0B7F83E26 +:10F30000DA3B4CE166A9871F37EA997E147AED0C47 +:10F3100018C74ECC7BB03AC3AE6964BEB5A76D7555 +:10F32000A8EB2F77644E3C03703E93A5F03C39CB9D +:10F33000CBE79BA8375BD09B0EF3795E7E1AAFA715 +:10F340002021534F1D45C1B7E7E5C5FC445BE4E50B +:10F3500093BE62767381CD807491DCCAE406A17499 +:10F3600001F6FAF858F704D8BF36A83D321EE0354A +:10F3700000C00F312E12FDE148C87FA429E321FF10 +:10F38000F1D88A51074C0E8847755F0DA8F1B4D9A2 +:10F390002AC1559D95E12F82FA4AA2341601FD57E4 +:10F3A000BEAD67758F6B9350DFB7E7D661DDE3B90C +:10F3B000778DAA7D46BDE43459ED82B85341EB7F89 +:10F3C00062FE21798FD4673DEB427022C6B0FE10F9 +:10F3D000C74A6EED0E95435CE641899DC149672F92 +:10F3E000B9209EA0C86077CCED64FBDFE7B6D92BCF +:10F3F0004D284F2596BF19EF4039A9ACBD5E067F59 +:10F400004F692278DEDDEC6C76DEEDE0769B0C78E1 +:10F410007FF96B5D9F79B91BB27BEAE8005CF5C6AA +:10F42000D821281D10F944513F27FCABB87CE5E7F3 +:10F43000C20B7DA4B5637BD9AF5C1FC5ED780D1DF4 +:10F44000F7F79EA06F41CF2FEB09DA612F4B26DC37 +:10F45000C726E8BA45EC2BF89AC585F3787DCE89A6 +:10F46000757F19C1CE8114F99830ABABD247D76400 +:10F4700021BCA2D78460DD7BEC724331C6D31A7005 +:10F480009CB5ECDCBABCD681ABCB4BE16A230082E5 +:10F4900013FB96E4015F86281D0CEE830E8AB35998 +:10F4A0001D94B23609F1A66CC013BA89624F47BCED +:10F4B000298F30FC1466333A17F96011F7CCCC0E63 +:10F4C000ACCC1E93B0FF6C8585ED3FE3FBA4935756 +:10F4D000BCBB0BF6753DC6E3CF075E1A86BF9F71B6 +:10F4E00061AD22411CEA82BD260FFCBD07385E9348 +:10F4F000956E62B326D2E701ACBF2DD8CFEA0815CE +:10F500007E0E96B2D6B11DE039362D8075C657B73E +:10F5100044F0A7275EB29DC43C1FB58B70DFF8E9AD +:10F5200017246117A9F4A1F0D7B47ED88FB3FF7761 +:10F53000FDAB27E372FA32FD2BA2F633E3FD85DF44 +:10F54000A8F52334EFF767FF105F485567F302C74C +:10F55000BBD0EF995C368AFA9BF8BE6F1236C3FEB9 +:10F560008CC9504BCBD68375489B248B17EC246DEC +:10F57000FD51BC2E88340E6175298D23D9791E8DDD +:10F5800057C255D42799A13E25B10E3699D5179962 +:10F59000A13E85DE6FEE779FB8A709BEDF7E9F4D47 +:10F5A000EC136771FB6AC2F3163B701F79EC966C23 +:10F5B000DCF733A19AC50353FD0619E8F2F9BFE958 +:10F5C0007C207763946FC1BE4A1DE47383BD65A63A +:10F5D000CFA1EE25BE4FBC86F4B94F5CD447897CE1 +:10F5E00071E6908D12E89F78DD4AB067FF387CB7EE +:10F5F0007DA907E3CDF13AAAEF125C67A590332607 +:10F6000035FE527CAC5FCA4C03DA19E972E029CCB2 +:10F610000B6EE936037FEECE2E40BC359787F11C8A +:10F62000E4D4E2368CE786D37CE7B29D3DF423E652 +:10F630004736B1F59F87FD6752CF77CF2FFA732EEC +:10F64000D853955D4646879A796C899F5343BF434B +:10F65000AFBA1C867FAFC6BE15575D8EA4AAE31352 +:10F66000DFEF6F9D821EBFCD6ED7D257A892E3E722 +:10F670007D7398D53FA9E9EBC0AAEAD127A92C3917 +:10F68000B8CA8FD7F366A94307754AE6D86C90804D +:10F690006FE6B4DD08E7999C4F8EE5C2F9276FE766 +:10F6A000DE7513B69DB1F7A17D2AE769D61E1C7BD6 +:10F6B0000CCE43F95BCE889BE0BC93F3F0AD4C429B +:10F6C000B2B615DC142A867D26D135DDA09F4A35D9 +:10F6D000F52E9A731BA02E13CF99B0327C66F0BA28 +:10F6E0005852C5ED77C854D176B3BBC40BF50C5650 +:10F6F000E2D9D30DCFB38DEC7C07C2EAB09A07E70D +:10F70000B3BA094EEF249BC7B3493404F4DB9C6FB2 +:10F71000C7F7E3F27A8F91E7B1D8F78F3EC7F6BD0E +:10F72000897A5F426C3960F7583D44D516E79E10E0 +:10F73000C59603E71C348B78216FFFC112B83A27B6 +:10F7400041FF1E9D787731FE8ECBF3F70E82F54E8A +:10F7500036A8CFC116D79772197D9CE7E7456EB3DF +:10F760000426C138C792664F82237867A65518ECE5 +:10F7700068A73DA50379E4E474619FC1E667AFF231 +:10F780004BF0FB29E2BC466740C1780009B4EB406E +:10F790007F3A4FFAB1AEB0CE14CB55287D194D81CA +:10F7A000E9399057AC397E17E615338FBE0F7520B7 +:10F7B00047F56D1352405FE4F3F333A8E317A2ED6E +:10F7C000435979E8F7C5CF771D2CA17C983A83ED92 +:10F7D000A79D423A148CBFD8D8FEAE49A5F9DE6683 +:10F7E000FABDA9BC8E64D2317F0AC40126DD16554C +:10F7F00058FE26A624D66D882B71E93D897C709D24 +:10F8000027A14DE05C6875FB06AFBA7D53F9D7437D +:10F8100012DB0388AF1EE0F8A214C5FDD6A1B1C467 +:10F82000C6D6C5EA139FE67EDB301731E541FDA45D +:10F83000430A815F306C6F26E665F696136CA7EF7E +:10F8400034ED3025AE7F83CCF2BE3C6E2E7EFF09B8 +:10F850009E815E7DFE9D748457BA5546790A117566 +:10F86000A0B7B22C9305E4BB8ECB79B13F7D628A01 +:10F8700009CFED6D5ECA7E37427B6E69B3DEF60A54 +:10F88000E0B1F96338928AFAD9C986889C02F8A255 +:10F89000BE8FA3471E0BFA81F1AE01BA1FC37E9F34 +:10F8A0008B52F9A0C473E39B9D6CAECDF7293CDF6E +:10F8B000C77E27A428FEBB2194ED687FB02909F2FA +:10F8C00009CBB7E5887512C507FDDD44B4D97EAF15 +:10F8D00074DE16E7A51252A1E0F94492E8D784ED50 +:10F8E00047793FA9EBF53F017D0C4AA1EBA1D7D7A2 +:10F8F000723C48DC3F958F6E423AB1063C4027DEB1 +:10F90000A4BEF71F75E4303B62624AB90BE2EBCD4F +:10F910006EAF0BEC2A011F715F8C2B9E8BEF79D39E +:10F92000FA1EF7352EAF3BF83E68EDF3977364F59A +:10F9300077F5745CEB377CD7A9FE6EFCBD9CBEDF0F +:10F9400013F7457FFC59AF32E03306B729BC6E96FA +:10F9500014A9EB5D48B9D7C4E4BDBABE65B2B4D250 +:10F960000DFC799DA9BE2B4ADF7F9DD3C96439F078 +:10F9700047C837BC3EBBF020F06735FC30011DE7BF +:10F980007A125903C472BE22F013FB409417C78049 +:10F990008F1A748121A9B4FD89BE6DD0D27CE4AFE9 +:10F9A0007772C6F49E9FA0C3F83C29FD01DE05FDD9 +:10F9B00069E72DE880DCD8810582DB4804AF2EC2E0 +:10F9C000EAB2A9FE62F5D79E9C9E7551E29C646ADC +:10F9D0001C04FAFDF5A610CA9FC9F61F611DDAF9CD +:10F9E000BCC03998D7CC919FE2F942C45583F61632 +:10F9F0009DEFF97FE57CA18208EE0B3B50D87BBDE3 +:10FA0000EA913F36A8EA91C5FCB47C2CE61124ECBF +:10FA1000DCA8095DDBD1BE0BCEB07A61DF4810EA0D +:10FA20006C4B319F8675CBFBB85F169258FD702FDB +:10FA30007BB1FFBA65764E41BD8D9D1F24CEA1FAE4 +:10FA40005E81385F88CD9BCA2F7EBE10B6DB6B3CD3 +:10FA5000E8FFC5EDC6F9CC0EBDB6D0D202E735F64B +:10FA60003E6788C5F7C85EA387DB89A8BFDB93D94B +:10FA7000773E31B33AF904394EA4F49EF3CF36EA17 +:10FA8000993DE8CDCD677941D95B06F8D802792B4D +:10FA90005DEF38E4C0F4C0E85CDA6F7EB12F177E0A +:10FAA0009A65AE81C519295D6DED26506ED7F8387F +:10FAB0009C0B7A1D697C4B1E88743516FACF1CF698 +:10FAC000293B2FB487AEC6E53A99DC0421F86D7C5A +:10FAD0007A322D3001C669B777BCD7500A794B23EB +:10FAE000C25FD4336AF937613E27F56C3E0E381F8A +:10FAF00099CEE7FABEE67329F49D48471984D1717F +:10FB00007F740EFB069247F5D0F90012B81DBE1B9C +:10FB1000A7F735DE56DDC03EE6ADB322DE6F9DC5EC +:10FB2000F231C12466A7425EC69D0EF127F6FD5B49 +:10FB3000D732FAB8D56C447A99D6558FF91752C591 +:10FB4000F2295EFA1FCC6726F14D849F58B9D93649 +:10FB50000DF781CE98AACEB7CC344DC6FCCE2D84FD +:10FB6000C5D36E9DA157FD7EA480C34CB2FE53A8A1 +:10FB70000F99A9F9DD482D5CB4F91A018FE6F26FEF +:10FB8000E6FBFB72E3799D219799D769C945F97422 +:10FB900069799D83FA189E23F09A73E1D6A5942F74 +:10FBA00086FCB818CF5B9F98BEE8F10DB4FDB32D6D +:10FBB0005760FBB5F43B961F85E78F1562BB4AFE85 +:10FBC0007436F04151D9AC29704EFD41331BC765E5 +:10FBD00009B4C3EF8EB846148C0297ACCA10C37E2A +:10FBE000D78FAC1F0D75355516D63E52F25FA3B0B8 +:10FBF0005DC0DBA35EBC02DA07A54F67F795171A55 +:10FC0000562445E0F7C5AA5259FFA9A39ECA8438D5 +:10FC10004155256B0FF356AC1D08CFE5CF66F7A510 +:10FC20008F7FC9ED63616FF939BFEFF51D6F81FDFE +:10FC3000667EABE4857D06FEF2E3EC5C3113AB4BF4 +:10FC4000F0FB4A143877B2D2C7E27B13AC4D6E900A +:10FC50007F37060CA510C7B559F35BE07CE701E5DB +:10FC6000156300DF13A81906FA8FF2D5F3C0CF335E +:10FC7000AFFC343705ED10355F09BA9D26F8A94A67 +:10FC8000CD37541E74313CAAF9818EFB0A8E7B95C8 +:10FC90005A2FC5E5BB866FB5F4D8AFDE276A391891 +:10FCA000D74F6B3A902EB309DB4FB40DE894F1EFC8 +:10FCB0006F617E06B9DB03F7F324EF1558A8D18FE7 +:10FCC000FD20E607660F19D57B5EF04711F6229BF3 +:10FCD00081CD960EDF65CFE97B3EF83138312FFAC2 +:10FCE000FD13089F356C3EDBA446FEFB22CC2E178D +:10FCF0007E6F83586FA77ABD6516B62FDE45A8DCE8 +:10FD0000C1D87DC915DF34EF20D7B3334CFE078D42 +:10FD100032FC4EE15CC4F36D24F41CD837EF58027A +:10FD20007F84F9E8E4D0FEA804BF0FE2C37C32C5AB +:10FD3000E3174CAE33BC887969E1D1D08F5CD5CE66 +:10FD40005B0B871EFC74A37DE6E6BF23185F9766F6 +:10FD50003DCDFC770462254655DDE9911A56572BB7 +:10FD6000E675442245A827250BE651E37127AD7CB3 +:10FD7000EB677F9CD0CF629E77F3FD595FCA4CEE54 +:10FD8000DDAD8BE03CF3AABBCD00C7F2BC02763EF2 +:10FD9000109F7F737908FB1964A9CF3C71799E2C61 +:10FDA000F260A4CF73DC3CF956E08B3B4DFCDC3AAF +:10FDB0000D5D104DFEAC3F3A11F1BB4AEEB7C4F3F6 +:10FDC000A99A73E2E698FACE9B4914BE59A9BDF1EF +:10FDD00020F2693768E374D7B1F8D50D3C4E37A1EE +:10FDE0009AE127754532FA75A9A5471532BCE73C5B +:10FDF0006B81AF0B8E40551EE635A263208EF0E678 +:10FE0000989F611E499C1BA9859F3F4F16F1C64BC9 +:10FE1000E297FEE6FF078B7F3A7CF713A91BCF839F +:10FE20001BEDE6E79192403EF093DD965F01F1070E +:10FE30002A772F5E0467141E51FCEE74066E87F756 +:10FE40006E23FE8950EB9D5A1DD0B3F83DC1F8F1E9 +:10FE500032EE474EE4FAFFB367D87EFD2ADFD04783 +:10FE6000C7837D7A584FC21EA81B67F0F96CAB0E92 +:10FE7000F5FEC23746BBC07EFF80D3E3904DB2EAA9 +:10FE8000770887862DAA733D86ED4C55B587776434 +:10FE9000AAFA8FEC2C503D2F895CA17A3EFAF0280B +:10FEA000557B4CF73855FF2B8F55AADA63A3535473 +:10FEB000FDAF3A355DD5BE3A76BBFA5C9290AFBBEA +:10FEC000281D7E3F81C1E3DAAFE6A8FA9F49997405 +:10FED00018F872DE7A56275E4196A8DE5FA2ABC3A1 +:10FEE000FA6BD2C6EC9C46FA1FDF17AF607D1AB5DD +:10FEF000EFE1A701166E52DB41B55D1BD6802CEEFB +:10FF0000751E86C6DED1DA37431C35706C3679240F +:10FF10008FFFAEF895E44AFEBB345ABCE2F9029F6B +:10FF2000BDA5433F63D91BCCFE5FB68BD5DF1592D1 +:10FF3000C10370DFD9611D094B70CE42E3C6F15297 +:10FF40008F9DA3858BD1A5C6B3D9A3C67352911A31 +:10FF5000CFC95E359E0794ABF16CF7A9F19C56AD05 +:10FF6000C6B3D3AFC673C64C359EDD01359EB36AAA +:10FF7000D578CE6954E3396F851AAFF9A1C5AAE7E0 +:10FF800042AE0E6C5DA6BADF2C759451494AE6F973 +:10FF90006BF17C89C16DDFEF933E04FE43F43FC6F5 +:10FFA000CF8D58CFBF80E21FEAF9BF20EB0F414A47 +:10FFB000564B070D9D1B30EF76B974F0761EB75F78 +:10FFC00005FE2FD17EA5FAF2BDBC3168E7BC0FF269 +:10FFD00061E610EE97F8FBB67384DC4AB42B12FD91 +:10FFE000EEFEE4592F3DCAFDF07EF5A8C60F7F074F +:10FFF000AA9FD05E5F8F71AF599CAE3F875B632134 +:020000022000DC +:10000000EEFA2CDA07EFD08994D379BD03F31E0101 +:1000100076C2308C93DC41227A3C3F1C2A4675A87C +:10002000BFB04EB386DAED709DCBED87F93C8E62A2 +:10003000340588C789F193BC74F86E7637EE33FBCC +:10004000BF17F44F2B008000000000001F8B08003A +:1000500000000000000BE57D097C94D5B5F8FDE6B5 +:100060009B2DC92499241012026126210B908449EA +:100070005804451C9660D4806193C58833498090AC +:100080008504D0D7B4A5CD40C2A28536B4A8A8A80F +:100090000302050B345804D4688745A44F5B636B97 +:1000A000AD4BCB4B0045F618B4D23EDFF37FCEB953 +:1000B000F766E6FB480AF6BDF7FBF5F7FBE3EBBB9B +:1000C000B9DFDDCF76CF3DE7DC3BECED38C612196A +:1000D000FB06FFDD717DCA988FB1DE8CFD01FF84C8 +:1000E0007A231C455607E4275A1D0F3D069F8E189C +:1000F0005879B30DFE28847E46436A2CCA9E96DD4D +:100100005D3F2BA13163AF2A1E0F1B0EBD265A5D2A +:10011000DB15C68624316B622C1427F853A64532B2 +:10012000D6C761A07AF04F61F18C0DB6D2DF6C4F6B +:10013000DFE6A531A9F8973FB628FBDB8F9BEA7075 +:10014000273B4604EBDF68BD6673F3129C6747B537 +:10015000CDB5D5C9D87B5804ED9EBFCF1250A3189A +:10016000BB62B2AD55A219FB2062DEF1DE0EC69E67 +:1001700009F764215C66CFBA6B35E69523718EA5CD +:1001800030BF2BDEB6910CE66DB17A5C585E65F53A +:100190000C8887255EEAEFC98856A1CF220E7FF82A +:1001A00023BBA8DBF9F3F94C50F8F89F847B46E3B6 +:1001B0003A8E185A935D080F63EB486CC76CBDA963 +:1001C0009F4B660E979EE0303EA27F31AEABCC6275 +:1001D00071A9D0E77885E3F54CDC83F36AE0CFF9C9 +:1001E00086A2F880AA99F79D346FBB7740620AF423 +:1001F0006F12F3B6F6167077641545F63CEF06EC11 +:10020000BF17E47EA0F8B73B392E317FD017E37FCC +:1002100014F216C3D5F7A643BE23DBE0DA0A459BEA +:10022000C3A1EB3CC6DE11F07EC604F958FABE1637 +:10023000BF2784F3F6098F1BFC0DD0BE68FCCB846E +:10024000A7E717DB683D5EE63033985F29739B7143 +:10025000FE9F8CFBCFD7DA001FF31D1E0FC2EDC12E +:100260003843F27B340FCF90A9306F36E6E6E89F33 +:10027000B175063692B16976BE84F9026ED399DB08 +:1002800084E3CC641E138EFBFBCB663703FAF83D88 +:10029000E098C17C67311F7D9FC3FC94DECF025480 +:1002A000FF01D646F9772372FAD7C1FCA63E919199 +:1002B000C60C1AB8FF1BCE17E8E5C15E9C5ECEF6F1 +:1002C00041B86FEC7D53F43B55D00BF0EB0FB11FF1 +:1002D000E0D7E1B929217C3391D30B33DAD3FE1176 +:1002E000DFB47646E5B0A19877DB1261FD770A149A +:1002F000DEE9AE2CC475E6AB36D60BE0DFEA50FD86 +:100300001618B3609CB72FAE0BFE45FA004F53DCB6 +:100310002A433CBFB902BE40BD3773553FD2C49497 +:100320004D93CE61FBC271D31BA361FD93BE6E1BC7 +:100330001E80B4A09FE9545B261FE31BF8DF976C77 +:10034000F3C41848EF4ED8676430FFBB076ACB0B85 +:10035000B3206F0DE6A73063B01CC63D8C7000FA69 +:10036000A9FB73EED86321ED186B52916FB63A2258 +:100370007B7D3A04B283D9E06F70DE6A71B4A71B4B +:10038000FE91E957F5AEB1C78026EF51DCBB1C44A6 +:10039000170E33D27F8991B9BBE3BB8B698AA01F4B +:1003A000C02EC8B37BC55C3B0BAF9AAFC07ADB1CD9 +:1003B0009EFDD8CFD2C99FCCC3F53123FBED308051 +:1003C000DBE2DF01DCA0FC543D403E03F8B3DECAB3 +:1003D000DC16C63EADB753FEB3FA044ACFD73B286E +:1003E000BD589F49E597EB5D9467CEA2D7B0DF92E9 +:1003F000B59F1B3D598CAD099378E4F35826E878F6 +:100400004DFF917F72C1786BDE3651BEBCB9695227 +:1004100004A4CBFA9F5A1901DF97ED525CF8BDB2E4 +:10042000C56DB6211F1DF3AC46F259F876DB1414E6 +:100430003BD5D714E601169A3DB0E82D1C6FC41FBA +:10044000CFC423FCCED68FA2F99CAB77D37CDC2D16 +:10045000EDC7E3A0FD85FA02CA273A8BDE45BA74E0 +:10046000B3CFCD587FF2EE76631294E7BB1537F227 +:10047000F75837F3FB017F9B4C7CBFD804FB05F298 +:10048000FBB8EC69CF3CC4509E7B3EC6F166C69675 +:10049000E6C7C1F729A3BC46AC37EB6BC6302FE9E2 +:1004A000FBC67CCDE1512DF072E97585E074E9C0A1 +:1004B000907B6F83FE5E3FA13215E6D579CD40F388 +:1004C000EAFC20DC0F3B5357BDA52FA5F661364C47 +:1004D00087F46159B83EE804D69DA9180D75C0FF90 +:1004E00017F67C2701E12FC7BD10DBFCD78F50DE4C +:1004F000FD85CB3BC69A3F7D0AE561BF04D7A3903B +:10050000BB6C62B3893F596D04EE878BCDCCC3F3CE +:100510009E2198BF10CE1E2C82FCC8BD49E3917F5E +:10052000703C4746509EA5EF7D22E5FB8EE0783B70 +:10053000F63CD9F98A03CBFDC4CFBBF63ED3F769AD +:10054000C855ED5B158EF37A15D6320AF8E3D50D52 +:100550001124B75E35B94ED6A1BC7EC6E6DA0EF5DB +:100560007EFEE3EF9E3A84E9FAEABCEF421AE38C9E +:10057000A57ECA7EBA6830B687FD9B25C23A7F71D8 +:10058000500984E53096BDF1F0CA44186FE8E6766C +:10059000435F4873B7290D980EE95F7002F7CD3EAF +:1005A0004E07C17DD86EA79A846CD7D7FFD11DB4F2 +:1005B000AF6BF7FBAC8D9F8FEFCB82FBFE60A5F995 +:1005C000FC0A27D2EBFB791E824713CDE3A596E9FF +:1005D0007FB89FE13A40A3C0797BCD2EDA6760B93E +:1005E00026C85FDA9FBAE55158E301836F0BED43EC +:1005F000255CEFB854E47B12E9A51AEAFB205F9D65 +:10060000EB8BBA15CAABFF32D00594C1FA3F7B67BA +:1006100001C263F1FEC726F5857A97C6309702536B +:100620002F7FE9EA246CC7FA3386AC7D697F43FCEF +:100630005C68F7A3ACF123904E8AD4661A87D5F094 +:10064000719E10FB176B03E0C40B92837A3F82CF3D +:10065000F83DB625E670120BE2A7A66585D308ED36 +:10066000877BAC2E15E9DFE94BACB505F743D8C75E +:10067000463B91B4CDA25FFBF4E4A26FB18F99C564 +:10068000BE24FB7BC2CC7C61D04F7FF8AEE03E6BDA +:10069000E6FBEF76900F48BF72FF8571EF728EA078 +:1006A000F66E94A749B0D9E6C23C939EB0903CBF89 +:1006B000D9F1A5DE5413CEE591D43F66C735BCD63B +:1006C00006EB3D1EEE9989E3CC17FB3733BA1C28A5 +:1006D000A7F784BBEF73D27ED8918C6B80FD712E0F +:1006E000E617ABA04FA586E853D69BDB1F3F0C77E0 +:1006F0007BB0FDCDD6D7CBCD655F1A582ED0C1B219 +:10070000C72C7E06F36E40F90AEB6A881C694539EE +:10071000C08E19AA8EC37E793B6FD9D5DFB2C83C93 +:1007200092130D8C750BAFD7819F3D203F0220EFB8 +:100730003DC0D763AF75A89CDE5B8F460F4779C974 +:10074000DC91403F775C33304FC87EA6EF07F05511 +:100750008FEB1BC7229827647F74B31833F22DB335 +:10076000C5FE73EB16F31F23F037A6F38308947FBF +:10077000CBBECC2339D8D3BA5E13EBFA35AE0BD24D +:100780004FD28A36201DDFFE85DD88EBBBDD383594 +:1007900019F51398F71338EFB15F18B4F3FE3A5C0C +:1007A00093BFD9F93FAC309F01F9F173B31FF9B191 +:1007B00005B7398063CBA22C3FF2FD0133CFFBA2FA +:1007C000CCA49FB644321FCA9196A9F17E9F13E52F +:1007D00021E3FA6B6FC6CBC344FB39F1D4BEAF053E +:1007E000408AF2E0FE70D17FED5BD958BE2289E4E9 +:1007F0004883C9BF3605FBFF81EADA0E78FBC06F7C +:10080000F099804E36C604EE57A1DF8D9FC7331C8A +:10081000E7031648AAC171CAC349EEDE66303C3808 +:10082000D586F5DC89B100EF03FFAD92DCDF980BD4 +:10083000791BC9EDD9CDF07DE354776238F63335B5 +:10084000DE40F351592D7D77F2761F9978BDB902BC +:100850005F1F0AFC005F13DF7BA64418916E4F3ABE +:100860004BDE7512BEDD890ACCF7A9B234867273ED +:100870006EC55D4EA297A627487ECD163890FD61C5 +:1008800003EB48D47FF9BF39F3B787213E679687DA +:10089000B5C30EC93E285F19E980F6333D6AC00230 +:1008A000F294CDC87777E9672938AE9BC6AD6E1E46 +:1008B000947A26849E4B2C2027A0FF43619E0F88AC +:1008C0004F0FE552F921504EBE017E3A5596B617AC +:1008D000F98A95C9F35FA014F1F07A8795F4CD9E5B +:1008E000E8A101E13F54D029E26539C73BE85D94B6 +:1008F0006F983D98CE25CF9938DDF8F685115E0BBF +:10090000A65909CF9DB3C3B758A0FC4121B71A66B9 +:1009100087BB15A8D7F092C56F70D27987EAF95EC8 +:100920008BA47EABCC3C5FF5621AD1D301B37FD7E9 +:100930000E2C7F3D8CE8A12A8A8F5BF54A92A03766 +:10094000B773158EFB9A85E8A02ADC114DE5FF1ED2 +:10095000477432D9EAF91BC20BE8AE16F5822A7346 +:10096000203D06E07B52D0D5496883F8F3D546D2C6 +:10097000BC89E521EF69E8BF15F1E931F372F63D75 +:1009800095CA4FDAF9F827D7F1F18B7F52F9360380 +:10099000BC9D2C9A94381FE671B23682F4BF3FD7C3 +:1009A000A90173149E5F3A1E4F877A97979F1EB9CD +:1009B00009E6DFB6F2E364A48FE295D585D8AEB838 +:1009C00062F914DC377BE2CBE22A60FE103E4E492E +:1009D00071C7A4C07AC6A6787A615A93D5B600F5D5 +:1009E000E0CBE6D667F11C9114E7E983DFAFBC7C6E +:1009F0007607D78F3BD2713F586CE4F421F7D51AB4 +:100A0000417FC7533CFD53709F080FCCC3FD232289 +:100A1000AB95CBBBE53727E7CFB76C3FA0C0389588 +:100A2000E12D8B2955FD39D8CF052510A5A412FC41 +:100A30003CC84F17ED812884BBC7C0F5B3CA9DDA07 +:100A400075E13F23CCAB12FF807695CDAA3B0C71AC +:100A5000CDFC669C7F253307EB3B8378827E084F75 +:100A6000CCF6E779DF07F857EC1A9487E780CA9845 +:100A7000433FBE8DEA413BC927EAF579B99EEBE7D2 +:100A8000C3D77751D0FF4549FFB3CDF25C4EE35F4A +:100A90007EB90F8D7F61AA3F1DE17F5911F576590F +:100AA000783DA00623CEF3979C9E1E37F90CE17487 +:100AB000BE6744CF9571CD23112E520EC11C7C060A +:100AC000A87F616F12D597728B153186ED2AF726B4 +:100AD0006EE5FA993897E244A17EC52F78FF9847D2 +:100AE0003E3CFF4292188FEBC77AFCE9D75B9C62D1 +:100AF000A0F53E2EE577A4E47357C254807FC62646 +:100B0000B3A6FEE548F3836EE877905FFB5DF65F82 +:100B10009EA2907E364087B7BE6AC7610BF2D3F3C0 +:100B20008CF8553FAF9A147EFE7BE1852E3CA91CC4 +:100B30006FA0064AFA70703DDC8470FEB00B1F0F88 +:100B400025815CAD4418A404E17320D79384F2FF9F +:100B500032E6715F88817C16EA411CDE322FE1ACFF +:100B6000A7B3951F2E486A83F64F09F80042FB2071 +:100B70003D76E92F26385F64E1B9B27CD899343CE0 +:100B80006FD60E82ADA06B3D0B36E55A919F166E67 +:100B9000CEB59684E0A161E7B0130E80F3C59D4603 +:100BA000178AE506A3FFC7A84F37EC549B7D8CCA74 +:100BB000AD08DF8BB623BFC37A0B36C7E4A1BE2CCA +:100BC000DB2FDCF4F0A0B210B80FD9A9C54376B37F +:100BD000363FF49036BF0D6543EF6FDF2E37A0CD63 +:100BE0000F3BA1CDB30EC016E041B5723C1D1CE514 +:100BF0003AE1003C0DF0AB2EFC34C0366DFA64D403 +:100C00002F36ABAE34281FB0BCE89E6CC87FB679D7 +:100C1000BE0BD15CAEFA167F1F7058FEF1A413B85C +:100C20001F5E60CDEF4F063C2C68D960363A70DD10 +:100C30005ABA3D6010F4FA02B7972DF26BCBAFE7CA +:100C4000EB15D25E9A194A4F7ABCC3B8F7B9614224 +:100C50005575CB869D812DB3BC10081D6036BA79C1 +:100C60008319F5B61B8FE3E3F462733B101EDE516C +:100C7000BCECD6BA09ECF430F863DDBB9370DEDE71 +:100C80001F29A437787F95710CF781F67D73EEA646 +:100C9000F4BE025ABFB4CB2D6C51029190B78F7243 +:100CA0001C6A8376F3FD8A0BE75DD26809CA33F8C4 +:100CB0005FD93ADD3C368694C3FC171E3AFC3705F3 +:100CC000FA2FDFAC6DB708E42CCAAF8A6DDF58424B +:100CD000BFCB73E3AD2D5B545CF77C397FDF588667 +:100CE000EBBA955765BD847E730633B06FD4F62E8C +:100CF0003A8BFBCAAD1B793B10975E5C6FB5CDECB0 +:100D0000C0F5565B592002E67122D2ECB6C3F7ABB0 +:100D10009B22C91EB6C002FA641EA52C2C0FDBB99B +:100D2000A2B1DDA7EF70BB58751CC777F5730A9D9C +:100D3000A3AAD18889F9E7797E110BD03A904EDCCD +:100D4000A1EBF36BF3AC899FBFAA8C81C3088F0A18 +:100D5000D6C6CF4F8047B7841FC0AB0AD6F9412C07 +:100D6000EA5BBAF6CCE5C1716B6C5C7FAA39F48D95 +:100D700025B45C9E03E53955DA699F4B2F0AC7718C +:100D80005629EE27AD30CF5542BFF66D0823FA9DA8 +:100D9000BB85EF37A0C7A6235C366E4874A19E3191 +:100DA00017F4F230E49B45E1540FF45DB2AF748068 +:100DB0005E8DF6F68D31CD01DC37363EE6243D1AE8 +:100DC000F45F824BC7FA30FF5605F560AEC76CDCA6 +:100DD00090417AF8AB729F5ACFF5AE6EF4622A67F3 +:100DE0007DB81EFF112E25440F4E8DF7A4A586ACAD +:100DF000AB6CA53B11F79DB2696603DA9D58F9CD3E +:100E0000F90DB60B3DB203D68FEB38A3141D378412 +:100E1000E8A32353F93E3272BC7B87A847FE853294 +:100E2000C3D447EFC0F11E373870BC2E78BBDDE964 +:100E3000388F331BC2F290CE468EE7F69F93B95C93 +:100E4000BE470C676E3FA477887EEF483568D28432 +:100E500070A03FE8E74C3EB73B470E2F227B1BECD0 +:100E6000D524E7F5EBB847F453662EFAF7DBBB99C8 +:100E70008F840F9BC8F585334B94AD7C5E805FC833 +:100E80008FFC6918D9E9CE88FD47C219E86604D9F4 +:100E9000DB85BCDA20E8658389D3816F113F3F058C +:100EA000E985113D6C14E7ACB902BF6C3DD76B818D +:100EB0005E389CD7270A7A61ECEF480FF90EAE67CF +:100EC000DFE47909F05E9ADAFBFA7393C43733FAF8 +:100ED00047FC23FF46F5C13D077CB07F56FCF2B1CD +:100EE0002806F5CE199BE25DD0BE6AFBAA2837A47E +:100EF0009F197D517618FF9C5F2DF077036FBF809F +:100F000037DAD715903F8BF14F07EA3B3F9A82EBD8 +:100F1000FBEB76931D4542CD4E0B9D9F16EF5F4434 +:100F20007A36E4DB797ECDE72AE60F69EDE0153FFE +:100F30007F2CDE41F0F6251912300D243148176F51 +:100F400033B902685F7E4F75C130A03777ACC6F900 +:100F5000E9DBE33CAE01BE6B9A55AF39FAFAF21AFF +:100F6000215F6AF6FFE873B4EBD5E8ECEEE5C2FF6B +:100F7000A0B7BB37A546F6FA140DCCB7B05B500F3F +:100F800002B8B802C8B7309F3422136EB76DD8F5D7 +:100F9000444E3BEA0BDBDE8A52B2827677E997E871 +:100FA0006C2E7D0EED9A3DF1E36561870DE28BCBF2 +:100FB0002DC7210565001CD0795A650A44DD06F06D +:100FC000A8DA62223953B5E7F91D4F219D7D68A14A +:100FD000FDBC72CF1BEFDF8AFAEE3E53AF42BE0C70 +:100FE0009B121FC4538D83DBC9245E2A7EF586D9EC +:100FF00091CDBF2F8F0DE2A772DF6133CBBE1E8E66 +:10100000139A0F9BDB6CDDE0A9B97D12D989767D3F +:1010100065463E38F7BAC2FA38AF6F5FBEE58D2835 +:10102000D4C7104EB82F497C75E14F571FFA9FF275 +:10103000CA70AA67C773454FF85B827B07D17724D4 +:101040008B81F1CB3FB2F80B11AF7B9745E13ACEE4 +:101050001A6B399D3FB32A1EF5BA72932FDE4E29C3 +:10106000FF5EFEECC3447F0B95DA787B16D177A246 +:101070008174065F22AE6FFEE699B4BE05CC43F4E0 +:1010800057FE8C5AE487F44B232BD8D70D9FF41DC1 +:10109000C8F9E4EC56402AACEF2CDA6D506EFC5ED9 +:1010A00015E7DC25B47F3F2CD6CAD852CA7F29F475 +:1010B000B64BA95D7E656BE879B166DB9A56C4CF05 +:1010C000F9FEEE3E384F80834FC04BF906FA55DFEC +:1010D000CDEFC3F1C31CC691A21DECA313F03BD608 +:1010E0006F35B9D1EE1DD24E9CE7F8F80F89F1614A +:1010F000DEE1785E3D1BCFF576FDFA0A062AD2DEE8 +:10110000D6CA42E9AB27BEDFF608D1D517EF71B9D1 +:10111000B2D83FB580CA5B4D813E58EE3F3C43217B +:10112000B9606181EEF87A9B49F0B5B61CE6695466 +:1011300042E1FB3AD7431780DE1508E1E320DD9852 +:1011400083DF69DD3F15EB6823BF98F4A72D14F208 +:1011500040BF6EBD7CE83550F8E3847C90EDD9E665 +:10116000EEFD3941B9E0A371AB603F413DA3EA43D5 +:101170000BED1B557B4C45089F0BBB8FBE3F17CF1C +:10118000A1CD928FB5F256CFC7E52F8EE8968F2F5F +:10119000ACCBED9E8FE17BB77CBC4E21F9F63F9541 +:1011A000B7B0D391DDA0277E5DD883BC1D3B502B0B +:1011B0006FBF6459D1B761A1DD3B80F0A383AB84DD +:1011C000A75E7EBE9FEA20F8EAE527C3D0881038E4 +:1011D0004AF849FA64CC43E374D1B1A45349C75DDA +:1011E00074AA5FAF168EFA72C34046F3297AD9C447 +:1011F000ED672D0AE9DBD0EE78D270E253376D7FD0 +:10120000ACE97852AFD0BC5F976FD6D577EBF2459B +:10121000BAFA1E5DBE5653BFEAD051333F1F0434A5 +:10122000F52C75F7D039E37A3DC2CFFD3EFB3F3751 +:10123000FB902EFA7598512E9A56325F24EABBAF76 +:10124000A9A4EF5E717444A15EB22A8CEB6D57ECD9 +:10125000221FC3F31DBDCDAB512ECAEF1D61DC4E65 +:1012600072A5A8232A26E49CDEDEA246A13DB6CDC7 +:10127000CF0ABA8F136920B8B6B19ECAB9FE96AF2D +:10128000DA92EBD01EDAA4BA804C58D98A5951149C +:10129000BFD0927AEF6CF83EFF372A85015C09E7F0 +:1012A0007605E6731B317EA094A3907DC67C8F8F5C +:1012B000817595B6F03882B2755AFC2EB0CD880E85 +:1012C0003850EE68FDFD0BF15C978AE73DEDF70ABB +:1012D000B68EE8AD42C7171E61A7D5F3C516C9176C +:1012E000B92C57D863C8CFB154C8EB7C35EBDED9E5 +:1012F00000FF2B275466817C678BCA56E37A772BD5 +:10130000E4EF418700F2DB62E04B9C8F84CF45E441 +:101310009B8C9EF5928B2FFD65E4F7914E0E7C9C85 +:10132000837ED88B073E4C7F15F307FF94FC31BBBF +:10133000BEFE84D7FF360FE5F095D72D0CE9FBCA2A +:10134000EB6F26A35DF0CA2B163A2F5F5969E1F6C1 +:10135000E6D723FDE88FBCD29FEBB90DAF7D95D3C7 +:1013600046FB6E23E1EBED8166AE37B5FCE749B491 +:101370005777B6C0AA509F783D82F8A7E69530F21D +:101380006B5F79EDAB91A1F10FFFD3F548FFF595B8 +:101390004836FB45A45BA1D7D7BC3AFA79F4E756A7 +:1013A000EF3F6C2E85F209BFFEAF1C949F575EE4A1 +:1013B0007AD26553DBB3686BFCD3C0393F3525A2C5 +:1013C0007D0E3AEB0BDC96F6E434E493EBE1C2E1FC +:1013D0007005E080EB02B894A3DCEF091E97FF656F +:1013E000E1F1F93C2ECF6E61E8FF0DC245E17E844C +:1013F0009648BF55A1F5F3EFAF7F9583F2E646EB34 +:10140000B5A59989AFFF7F59EFE0B47F55FC727A9B +:101410007F71A083C7F5E9E8FE7ABA3EF86F94DFE2 +:101420001BE9A2F9DE24BFDFFD2FBBFEFF1B7C976B +:10143000FFCBAEF746F8FE8DC077A41DFD8A575E40 +:10144000FBAF64F62DD6BDE65F96AFFFF1BAA5BE41 +:101450003E5E759DC885FA6FB1E6F75C4ED23EBA26 +:10146000D53BF6A7493B093F1F4D607C9F9E60AD71 +:10147000247D7342BFF5A41737B03CF243F8FAA9B4 +:10148000E48FA1E00B80C39B09B97EF2271903FD0D +:1014900096417E7C5235C55BE9CF8D13C22717A0DC +:1014A0003E7A7405CC0BFA391A69B0A3AF78623F63 +:1014B0003560C9A1B41DD3E3C9F79C40BD65A24DF9 +:1014C0007B7EBA47771EBACBA12D2F602FF642FF45 +:1014D00059419689F9613E93B07EC8B9F1A7697602 +:1014E00082CB5DACA9D16EFBF6703A23E0743D1C53 +:1014F000FE31DCAE839338271B457D3DDC8CB6473F +:101500005BB19D91C1B997AF97CECBF2DC7B2378CD +:1015100032719E368AA1257C8DFDB89F34A45F82EE +:101520008B84FBB785B7C4931EEE12BE126E7A3C55 +:101530001C446354EF20FCFB19738DC877B70B3D37 +:101540007EA23186E7FBB5AA45C48F7E82FB842F3D +:101550005C46D44FC6D96228EE9239FAC7E07916B4 +:1015600055CC6F92182B1915335281F5261999CF46 +:1015700002E74DF4A1911DF511A37FA513C7E1F674 +:10158000DAFE466E9706EEF685E7517DB719F2DE74 +:101590009F2D646EA8EF4D622E85D767D1B1148E52 +:1015A000C6548CCB8214DB79A379BFDE3ECCBF92CC +:1015B000E393F082C726B45F40BF6E432C6F1F9544 +:1015C00047ED7D06DEDE6D8474402AB7AF77ACB29E +:1015D000D0F9C3BBA67F3ACA8FC2F15ABB71713A28 +:1015E000B7ABC8F4CD74CEEFAAC195807A7149E348 +:1015F000203A0FA9E145D52FA1BD7F6F04D1A37774 +:10160000F5039347E0FCF6C6B9707AE7A7EC1BC96F +:10161000EBCF79F88FF0DDB3338CBE5F48F7F44938 +:10162000877ECF2B8E792FC187929947CD09308441 +:10163000A779EA25B4FF4DF1EDFB1DFA19A7CC50AF +:10164000A9FE14C6E32B596304F9A327FB3E3726F2 +:10165000407F93E1B081E5ED61F6E425307FAFB0E6 +:10166000F7A6A673BB8B1ACE3C2FDA705EFDD35360 +:10167000E0FB64D67D3CAF57D61FAF6C46FFD080F1 +:1016800009DC1E2FEB633FD8EFC274EE5FCD117003 +:101690009179802BD52F5B6B694FC573CF5A53203F +:1016A00003D26732C7E7A54379610A9BB409E1FE1B +:1016B0005D956DA5F97678C9CE1D99E9403C788095 +:1016C000A429BEB0C9E940BB57FBB8E600FA07DA67 +:1016D0009F74BA1A1C84658AC791E7ACF671818140 +:1016E0006897EFC8E57E8693F6B6483C1F96DAAC5D +:1016F000149F23E37AE6DB399F0F68685B7F0B9EBC +:101700003B1F535D5B213FFF31EE77F9C466F52B3C +:10171000785EDBC8F994ADD3C6F130BB8BEC3DA548 +:101720004DE3CC78BE2CB3B9CDB8CE8A0C4F11AEF8 +:101730008B7D0DF01B89719C8C98C1DBE4A538135F +:10174000350AF80EF9C4E888C273AF3E0EA846C445 +:10175000FDC8FCA130CF1CECAF24DAB117E9E55489 +:101760005D2AD93D3709BA2BC43846F44F18DB122D +:10177000713EE1F81DE05F186B4FB7113D87318472 +:1017800043BBC99E8EF4DDBE2ACC807EB6C2959C3A +:10179000AE81CFAC4668FF889185A3DF2043B42F8C +:1017A0005E612CDA02F97E56668C8C45BACA25BA7F +:1017B0006ECBF4E4207D7EF603360AE9A174DD06E3 +:1017C000F2AF48BA60C6D6897130CE67DB9D792802 +:1017D00037251DB5658EAF4D0FA587190AD101A418 +:1017E0008753891EA63D8CFD168E0F0C5C9A85E7EB +:1017F000D12AE6C6FD3D81B9504FE8641DE47FEC77 +:10180000B4991D68E792F244CA0DC0ABDB1A1FA45D +:10181000831DB0DF1B4D8CEDACB752FA42BD9D1954 +:1018200041C6EDAE4FA0FCDE7A07A5CDF599F4FDDB +:10183000C57A17E5F7D78FA2FC817A37E50FD51760 +:1018400050FA4A7D117D977209E0427248CA152903 +:101850008F4A6DE676F4474AB9A4A79B7900DEB1BA +:1018600079D49EE49E9477B80E435E501E49FCA640 +:101870002845BE0427CAB1B63988FF7CF5E29E83AD +:10188000782E2FB7B9E89CCEB8DCEB047A45B824A3 +:101890009BD921B4BB362C71B7AF7106E17F7FB9FC +:1018A000C28C2174F5406D183386EC1B0FD6C568C9 +:1018B000F2C5757F78A30FF45FD1CBB30BF176F24D +:1018C000879F3EF327F8FEDC0FCFA721BE611EDB0A +:1018D0009FC071978777CD2316F38D26F2470D9021 +:1018E0007610F8877829619CDF9EFBE1DF89BFDBFA +:1018F000EB2C0ED4873F423C015CFF2CF054526726 +:1019000021F879579DDE7310F97CB999E45C49A3FD +:10191000E0C3B500CF10FFEEA94446F608D0A659A3 +:101920001DC0EDD40FCC8108E8FF94C2F95701A582 +:10193000A018E3FED6BEF901F2BF527782FCE71E83 +:10194000AB8DEE35319FE962687F4ADD71AAC7DA57 +:10195000FAC5A0BD84F6B13BD0EFE8363B60DD4868 +:10196000D388B792CC232C11FD264D8A1DFD266508 +:10197000E27BD95A85FC9318773303F4BE77D355AD +:10198000C26364BA91D2CA7426F4BA26DA9F24BD1F +:1019900096AD8376C8174DB9E6052172B8447C2F01 +:1019A000CD34502ABFB78B7EFBAECD9D8DFA445F00 +:1019B0002CCFC2346F36C2B7AF6D925109C1FFC789 +:1019C00038FE089C071FBF12910AFFF768668A79E4 +:1019D0007E16E287EF5F729C92CCBCD518C759B2D5 +:1019E0006E1C4A5FD6607225F4827A67BAFAE17A91 +:1019F0001BB3F278E5AA1EF60F693FFB0CFF1C4DE6 +:101A0000EB26BB6EC5DE5FEC7D057AAEF8D842F8FA +:101A1000AD182AE2A7B2FC23A793A1516BAF9EF8A1 +:101A20008BBF4491FF613F8FAB8494DB53979773D7 +:101A3000FBAB0BF8AA1BFFCFB1BD1F47756BA7DE31 +:101A4000AFDE949DBA46F93A0AF507B99EFCD7BEB7 +:101A50008CA77928D7C8FF53F3DAAAF8EEEECFE8BF +:101A6000EDD55DF66C61B7D397EBED757D32747E85 +:101A70000123A3FB58D25EC7D4AC68B4EF7F29EE34 +:101A80006BF474AE91F6ED9A4DD0491CF0A7D111CC +:101A90008DFEAA2B3DE8D30F66F0FDFE92B0875F66 +:101AA000D9ADD239E7CAEE48E2A7C5BB7F761CFDA7 +:101AB000878BB729348D6AD64A700378326BE83E3B +:101AC00086F16671D7CFBBD39F168DFB48E52F22D9 +:101AD0006B91CE16352BEEED309F4EAB23BA77C807 +:101AE0007C6ECBE0745669691E497016F3CFCD70D9 +:101AF000D077596F51CBCFC87E0CF52E931EF4CB07 +:101B000008F4F523BC7F87F3BCB079980BFD7E8B7E +:101B10009AF72D263D6277841D8F0CE7459CB0EC2B +:101B2000E7CE0CCE9F776670BDE582F0075DD8AB3F +:101B3000923CC379227F9D57B4F1789345BBC9028B +:101B40006E9F0BFE92F51735B7470D84FA670FFDB0 +:101B500081D259625D8B6CAD39B8FF9EDD1F41FEAD +:101B6000ACB3FB9F9EF42A8C77A9795C2FE407D94C +:101B7000FFFC0C13D5BFB4592D4078313F8F7BA9A2 +:101B800046F80E0B9D67DC169F3394EF78DCCF850B +:101B9000FDBF8A326405F1596DF558F15E63CD7E63 +:101BA0006F11CA8DCF140E4FD3FE713EBC8F54D32C +:101BB00092CB909E89EF12A9FE5A43483DB3C94586 +:101BC00042D17868AA3B89E02CEE13897879BC1F52 +:101BD00087F267E9542BF927E60D75CCBA1FE5E4C7 +:101BE0005B268E977E8E27507F9BF74E1CC54D2D12 +:101BF000753A66E1FC97BDAB52BCEFBC61420E2466 +:101C0000B48DC0B8C5AAB50A73C33ADB9D5C6FA892 +:101C1000F2ABCC03F9BE400F3E00C5FA8C14214F45 +:101C200003E978AFEFA97283DB0CFBDF4933F3A93B +:101C300068377A91C73357A5F0B8E1A790EE21AD88 +:101C40008A0DA4C7417F17053EABA605D2314EA22F +:101C5000EAC5448A93B868E67E4BFC8E7ED2AA3CE5 +:101C6000680FF57A8978586C1F13423F55252E0767 +:101C7000D653635D8E5C1BCED77E99F4D89722191C +:101C8000EAB18683913CCEE9E7615B2D2178DA9257 +:101C9000C1F5E55E028F6C2E8F877C5CC4633FBE0E +:101CA0003DD18FE73759FF7193670EC201D781FA93 +:101CB000FB2273533AEAB772BE8BA29A689E17054D +:101CC0007D2F0A6FE2F1D2E29E2CD6C77CBB8951F0 +:101CD0001C77C72E0BC5939C4F6C3D80E39FDF356F +:101CE00088E1FADB9DFE0587A81CF447C05BC50BA5 +:101CF0009600AEE7DC2E6E6F3E67E2FAD8B9A9090E +:101D00000EC45BC1B44DF3C81EB3CDA220DECF29F3 +:101D1000CC9C80E5DB7BBB7CD8BEBE8EE2A42B4096 +:101D20004CE07D1C480BF05ECDB9ED83283EECDC29 +:101D30006F54BC1185DFD7E2770F6B9AF73D84C7EC +:101D40004E7E7E3AFFC27F0E0ABD5726D38A6DDAD9 +:101D500038384927B2FC4806B70F1C11703E9EC1A7 +:101D6000F7ADEA88E6C753689D1CEE80273AF7C1B5 +:101D7000C61FF9F4708C834853506E3C0574F534DB +:101D8000DA1576F2F3D5F9DD268A0BAF3818E9A615 +:101D9000B8B335B718280E42E57A788501C047A94F +:101DA00042FD564CCBA47BBB006F3AC7766C57C53F +:101DB000388CD970DD3B789C6F21EA8A549E4DE5C2 +:101DC000E744FEDC816CD2EBA07F37DE57AAF8DE59 +:101DD000F7391CA797BFCDC88E6125F95AD5E5C73D +:101DE00019138DFB5DF59ADBA2F13E1F7B4765A8B9 +:101DF0009FE8E174D5E8EA8372B577A690B3079EB1 +:101E000031A33CA814F7432A5F50B83F19F80CEFF0 +:101E10003B56AEBEED09A2CFDF99581AACE762F38C +:101E2000CFA234F81072B0ABBED945F52BA13EF667 +:101E300053B9FAAD289ACF0E13C5995CB75FDD6C24 +:101E4000FB17D49B6ADF451FCDDC8E72DDFA59EBA0 +:101E5000BF7D0CFD7FB13BCCE5A3AFCD74AFEC8271 +:101E6000A97901AEFFC29E3092471762B87C380B49 +:101E7000F2D39781F3B8E7271497F5FBE9741F6E47 +:101E8000A15FDBAF1CD79869E27416E78AC6B8BEBB +:101E9000EA77B87C03BCDC4BEDDF31517BFD3A4E79 +:101EA00067F0765DFCB92782E8E1425F8E970B7B95 +:101EB00033683F6A8FE1740EF34DC6FB7317F66407 +:101EC000E4D2BD34546E801E2AC4F9F6424C73B27B +:101ED0003DA4BCDD24CE6901A88974836D40EFABBD +:101EE000A8E37A55A5751DC587605CEDC83C4A031B +:101EF00096D8EBE363815EE9FC787FA6B053E27885 +:101F0000F1227E9BF49D6633CA6F8FD00BAB76EBCC +:101F1000E36B79F9AD998A8C0371F492F1BC48872F +:101F20003E85E24C2A1B972C423AAFACDD703FF263 +:101F3000999C7FA59115E039AC5D51691EED61EC6E +:101F4000C169B86F848E13AAB7C979E254E3495FB7 +:101F5000A57DECAE4CBEAF61BE09FAAB6A54D6D1DA +:101F6000384E799EE5EB927002709831AEAF7D9C51 +:101F700028EF61DD729EFA75CBF93C90C9E551BB43 +:101F8000D3F1933188E7DFAA743FF6EAD7C3A2639F +:101F9000BBD1CB82FBBA3918DF8AF1BE487BD04F68 +:101FA0004E26976B95183F0BF34CDFAC8DEBCEDCD8 +:101FB000A6CD0FDEADCD67EDD7E6735AB479D73134 +:101FC0006D7E1A8EDB9B9FB3F13E2E9EB331C5739F +:101FD000B6C3C2CFD998C77336A678CEC6EF78CE2F +:101FE000C63C9EB3318FE76CCC4B78E3791BF3781A +:101FF000DEC6F2A7059CAA449C24E201E99DBD1C13 +:10200000A6B9EF73E5357E8F03E880F3CD1C33F17D +:10201000CD535883CE1DDCAED477BAD581F1BE8FB7 +:10202000C47A5665A25F54695D9D887833B651DCE9 +:1020300069CD2B3CEEB42A2FCC86F68DB65567576A +:102040006338E703B19E47B1FE1553C70E846F7521 +:10205000DD51BABFDEB6C2F1CE1D1C7F646761E5FB +:10206000B1A43779719F8BED198FFAB86FB64E1BFB +:10207000E7AD8FFBD6C77BEBE940EA7BCF993A12FD +:1020800051AE9FDE655D87F33F1D26EE9FCCB6EA1D +:10209000FCFD424F5BAF6CC5FDFA1799B1DCAF7226 +:1020A00002F4F36EF65999965E1B467A78577E9D38 +:1020B00062A07B7109F1B40F2D13734A563ADAD737 +:1020C000A09C5B64A07DF32AE86538DED5F754D286 +:1020D0001F32361934EB19E40FD7D0D7909DB1BA1F +:1020E0007B0D7D35F5871E4AD1DD6B18AC8DA39F26 +:1020F000B1E2309EEFA7AF1BA6A95756749B0E8E78 +:1021000062DE427F2D83FDC30DEB7B6AF9A664C4BA +:10211000EFB2459DED6B503F7D298CEE8595E3FF39 +:1021200003B9580E7DE27DC6F2FDE23E709D761F3A +:102130002E15FB50B991F9ECB1413A2CB733770C1D +:10214000B45F34B8352780E78ADFFC61A43D05CF52 +:1021500015E3FAA03C4A36B9290EB66A5F5ACC0A92 +:10216000E8F758AAE7A34CC0CB99A6A33F2EC6FD1B +:10217000701F3FEF9D5EF7AB288A1313F4966CB285 +:102180008723DEB734F1F838B48FA9B141BAD8D279 +:1021900014173ED0165C6F900EBE263C017EB81D13 +:1021A000A7FC08F93D3A9BC57AC7293ED4A7E5FAB2 +:1021B000968A7D850DE4FD3C24F267C4F942AEF3B6 +:1021C000E2A0C3390EBC7F517F285945796ED8BD36 +:1021D0002311D2D116CF97B89EF22D697F1A03E34F +:1021E00054FC91AFE7938D13A246A3FEB9C7E42A2E +:1021F00084FC9AA6E7CD78CEAE30FACD145FB96BE9 +:102200008B19E38BEFDCB985BE2FD8E9A578CA8599 +:10221000AC96CE9F9FC97704043CCAC72B9BED3078 +:10222000EFB983B8FC280FE7FE3BD08FDEC0F73B49 +:10223000AEEE5472318E6746D13EB317BE470D12D3 +:10224000F783747CD2F9F6F4FCDE040F7E5FE38F33 +:102250000C4EF1A9D7F3C5F46B4EE28B19D786D09B +:10226000B96C6660103FFF66E9CEBF6FABDC5ED72E +:10227000C2F9A0DC1CE8351DF9E47513E9B9D5B045 +:10228000DF8CCAC37335EC8D90168D5135F45A33FB +:10229000314243CFB359ACE6DECB7D183412929F66 +:1022A0005198AAA93F6BC6101DFDE705CB498EDCEE +:1022B000AAB95F57BDDCE75048CF1CAFFDCE789C74 +:1022C0002063776BDA57B369C17A48DFDBB81E5CED +:1022D000BD3F662BDAFBCA0DFCFC34DBC3BF2F3ECF +:1022E000C4BFB3D94CC38703525D7FE2FBA289FC14 +:1022F00002D29E3E1BFFEE06FE8C8577DD0FC77B6C +:10230000F1688FD0DC9F16FE409C37E2A15AD88D31 +:10231000AA33B9DDA8DAD76AC6770700FEC6B8586F +:10232000AA678DC3F8C82685EC8A982EA778496DD0 +:102330001C16F687718C8B4FA85EE4137D7939BE2D +:10234000DF83F87D85C7952EDCA48F835C47FEC8AC +:10235000C5680F0AC1DB53831C425FF1AFEE8BF0FF +:102360002B5472E95EE4EEC3668CB39B31232617CF +:10237000F9464F5F52AE033FD3F9BBF3EDA3445F81 +:102380009DE546A2DF1BC161B19BDB51F574B780AF +:10239000B59AF19EF882FD8A0BCFA3580FE1D117B1 +:1023A000E951078FB8D8EBE120E1D305AFFDFA384A +:1023B000370EA78587147FA01B38E9E7DD13DCE41F +:1023C0007A16783C93502EC8752DC4F963FF307F80 +:1023D000EC5FFA21D8283D7FA6927D6A71118F8F1C +:1023E000D5D3C3B46BDCEE72DF3523A5330AB5FC5D +:1023F00088ED902F665E8BA7F26F4B2F8B619EFC52 +:10240000FED3CDD1895C8794BB417EE0F7066EF4A4 +:10241000BE8FDEEEB8639088131CC14668E29185DA +:102420005CD5B7D7C7234B3D40BFBF78230D1437CA +:10243000D9694B21FD42CA598FD83F3CABBEA47A23 +:102440001EA8C76713AFD96F3CC2FEB7343285DE12 +:1024500063485E11178F78F286D929FEDEBB42A54C +:10246000B8672FD47384E827AB1B539371BF38F53B +:1024700048C6B33ED0DB4F7DB757FC2818E7F42A97 +:10248000532FAB2358EFD4AAFC648CD338BDC13290 +:10249000DBDF0DBC5AC5FE50FDC30F683FBB64783F +:1024A0003B6A36B4AF5AF5521486F957AEE2FB7860 +:1024B00079AAE79D41BD713FDFB2C38EF0B36FC90A +:1024C00041BBEF49D80EB0BDD41F2A56E5F741FDF8 +:1024D000A2EABF8F3E6BC77BD62B4CF1A87F9E7BB9 +:1024E0000FF64385F633D21B3E0B832EC89F164949 +:1024F0007684CF14E646BFD245C3E1BFAEC1736157 +:102500006E737A00D2EF593C2771DCCA55CF93DE47 +:1025100052F1E88A7455C57ED3A2BBB39BC87487B9 +:10252000D8B7517FC714F5778C9341FD1DF3A8BF31 +:10253000638AFA3B7EAFD9A4D5FF2EA7713925ED6A +:10254000C9031A3A72D17FE71BCF326B69BFB565F9 +:10255000A2BEBE4C0977A13C5A86BA12E6FF1246CB +:10256000E758B62D91EFB702CF7556EE37FA4ADC31 +:10257000CFBDBD0374B210FABCE39A9585DE9B1DF6 +:10258000C76234F909D6444DFD7CBB53537E67C204 +:10259000204DF95D8E5C4DFE9ECCD19AFA935DE3A1 +:1025A00034F97B47DDA5A93FD53D55939F5E304764 +:1025B000537F669157533E6BF6224DF91CCF124D57 +:1025C000FEFEF2EF6AEA3F50BB4253FE95014EA475 +:1025D000402F2D78EEB2E0FB29564ABFA3DA8D28B2 +:1025E0003796FD36CD86F81E33C150DB9D7D3F63A7 +:1025F00030D787CA86B85306F7E6EFE0203DF617D6 +:10260000EFDC8C18CCF199C480AAE8BCDB9A88F482 +:10261000ABAFA72F1F1371E4AA0370F893C14367F0 +:102620001A410E8DB9E5C8B054C89F18BC60A611F8 +:10263000E4C698DB8EFC2A05F2AD837FC1CB871EF2 +:10264000B98AE5B38654F2F2E98C548F3FBFD07754 +:10265000A60FE77F47CA3A17B793747BCF5CA608EB +:1026600007BCAF8D70C03400F48BE911A05F4C8FB4 +:1026700001FD96817C3A0EF48BE909387FE2F77F01 +:1026800087F327A66FC3F913D3DFC1B913D3563825 +:102690007762FAFBFAD994BE57EFA176EFD797533A +:1026A000FA417D2D7DFFA8BE8ED23FD7FBE8FBD43B +:1026B000C1D28E11609AFB01E867447FE221D3C545 +:1026C000503FB0F4574AFF64432D6B8B4079D1667D +:1026D0008CF9D41AF43BF66C0730B24F43F4B1686E +:1026E000E62E1E4CFA423F3BC96FF1DDE4F0781153 +:1026F000CF7F744E4F1BA6E2BE55FB06BA65FF683E +:10270000E8FEDDC411823E460D712F20FA10FE75E1 +:10271000E9DFEE8A9B09F1BF1B42E275E85F48DC06 +:102720008DF483CB389FDBADFC9EB1F473CB781E68 +:10273000D95FFE178CE4C3D8B546D25F228D2C80BA +:10274000FDCBB89DB1D6E65C8C63185B65A37BB509 +:102750007DE0BB398FEAB95548B7FD0DEAE704FDC6 +:10276000EA7DC4FCA19CE69FFF8587ECB063455CD5 +:1027700001B6B7F2721FB61F8BB685E194927C7AD0 +:1027800006EFEDE605FDFC583F82D70F607F03FFA3 +:102790000EE34505F9A67F6C732ECAEBFE8B6D74B4 +:1027A0002F74F3B800BD6745462780CB74797EB29D +:1027B0008ABCF4E7EDEC4376A40982D7BFEFF06C56 +:1027C00042F81759EC7F89203E4BED8FF6C9A9429C +:1027D0007FFE07787B06E940C253E245E251E223DF +:1027E000247E8AF0D0135EF5F8D4E351E22FFF8BFC +:1027F000205E10AED7E32D8857B4E7FEABE06DB88E +:1028000091BF5F66A9B2D2BB6837C2E3831D6C5229 +:102810003456717A46207EBCD71CC7315FCAC64D7C +:1028200042D4CAF2B1583EE2FA72CF171DA6E810A0 +:102830007CDF2EF03DBF87FE643DF91E83ECBFB107 +:1028400087FA6F85C9B80BB72D776430FE71593E92 +:10285000877F815325F84FC85A487A32B3713DD3E8 +:1028600001FFA15C9AF47511BD4FF925DB8D9E5BCC +:1028700036A997563F2DD0F9ADEF167AE9DD3ABD6E +:1028800054AF577E3E58F8B39DCCF92DDF9DBCC6A2 +:10289000E5DACDBE3BC9DF2D9D28F82C49D059AAD9 +:1028A000436563908E9887F6C963F86E690EBEEF34 +:1028B000E9A3FC5DCC4FE93D2C40FBEB6410C498D0 +:1028C000BF174428E68F464C29C6BB7113864D18A6 +:1028D00088DF43DE658B1CD29BDE65FB0F7BC8BBAC +:1028E0006C47263AE87EE5116B2AE95FC887A61097 +:1028F0007BE06F607F1A08FBC751D8BF307D03F6BD +:10290000AF81B0DE3761FFC2FCDD992B18B69BE4C6 +:10291000D0C6EDC8F6F7D827C0C1A467F8DD93F399 +:10292000723F84EF5B311913D17EFE56CC2D1371AB +:10293000BD6FC5F431F0D462A634FBE0C0EEF443C1 +:10294000C907C1F126D1787AF84A78EAE128E1FB93 +:102950004FC0F396EEE0396230E3F649EB1FA21266 +:1029600052D07F1725DEA3FC6D8E0AF97338B5446B +:102970008C57BD8DE639B66E34330E23BF4D16C26B +:10298000B5CACAE1A5B75BB16D7D0CA1F1BB57CD4E +:102990009E8221B0EEB39B55BA377EE9C530B2476F +:1029A0007DE6E7F6B67B14CF649C5F95EA5887EF27 +:1029B00088B2B7F83B67ECEBA3C9D322BF059D6E85 +:1029C000E3F7EDABAC93BAC5A33C4F4D71BA47707A +:1029D000FAE7EF454ABDA29F85BF4B20DF2FEC49A8 +:1029E000CF1819CEE5603F0B97DB12AFD08EF249BE +:1029F000D0CF489073493F09A7F3C5CEDEEEF9B8B2 +:102A00003E6947E8EC17E147793B363084DEE52A3A +:102A100038A1523CF11111DF75E7905A5B0AE0A929 +:102A200029CD5383ED98FAB58A72E66D58671CDAA2 +:102A30001F4E0CB3D1F9F15B9E43BF3344C88B1CCE +:102A400096A3B9AF26E94EB551FC4EE77BFC3EDEBE +:102A5000D2DFF0B8CDA5BD558AFFD7C7C58D65E9D2 +:102A60003F417BE3845E2697DF11942FF21D204BBC +:102A700082813942F4EC3047387384CC27223356B4 +:102A8000938F74F5D5D48F1E95A2298F710FD6948C +:102A9000C715E469F2BD8B6ED5D4EF337BBC269F9E +:102AA000E8B95B533FA97C9A368F7C0770EF5F3B98 +:102AB00057D36E405D89A69ED357A129673E776B99 +:102AC000663CCA71FE2F75ED524DF9D351053C7E1F +:102AD000DCB680EE29A6357D4FD39FC46F521CC74C +:102AE0002F73F0FDC107FF91DF42E0393F41BB6F1B +:102AF0004CB08F3B66A7546BD748BA411CD4A17F1A +:102B0000960EAA99960E7AF1389EFCDF0C73A01EE1 +:102B1000A3C73FFA2342D789FE8850B8A03F22348A +:102B20008FFE88D0FAE88F082D477F4468F9B013EC +:102B30005AFC8F68D5E2FF960FC6FF433C8D6ED3DB +:102B4000D2831E4FB77DA6A58FB19E7082CB04D0D5 +:102B5000C790DE259E66C37FB4CFB3A268B41BDCEA +:102B6000C1DC742FE07F0B5F9775F8FA92AD1B8183 +:102B7000EF5C5EF17239DED33E7F6580FB0B94BB68 +:102B80002942CEEBED00329ED4379EE3D377328CD0 +:102B9000E4D55786B648DC3FBEA3B6915D3E91753D +:102BA000BC81EFCF0CE9E56159BDF1CA36703F94A5 +:102BB0003FB5E8BE5CDCE7E6FDDA928C7ACDBC017D +:102BC000FC3D4196D546EFB4C8F9CC4BE2F147D66F +:102BD0002C21A75D3C0E29228BDB7F225D768A8328 +:102BE000F6663111E7C992E765231DBE1D96817413 +:102BF000B691DBB9DA4C0E8A6BF1013DA29F12F55A +:102C00006DD487FB0B7DB4E143AB95D31DD3ECEFC3 +:102C100083FC564D1CEE909D764D3EBB3941537F53 +:102C2000E82187A63C3790A9291F76C2A5C98F68DD +:102C30001DA5A97FCB076E4D7E745B81A6FE6D9F9F +:102C40001569F249ACE34984E7F8AC141EDFAF081C +:102C50003B8083E365DE77E2E93E8D3C47C8B86C94 +:102C60008FA063FD796480D94371DE0D89CC45F76F +:102C700041ACE23CC8B4E7148F88AB96FA3CF369E8 +:102C8000E3AA653C75D779469C5FE47922249EDAF5 +:102C90008DF397F1D45D7817EF4BEAE9F35E817716 +:102CA000FD3A0698F9FDAF86EF9AE91E8B9C9F7E50 +:102CB0005E9B443CE0766BF7EF0F3D20E8AC2DA522 +:102CC000686616D47B16B62782E775E3B9DA7C000E +:102CD000DF861F985D2B1D371E6FDE50BE9E627C07 +:102CE00057358BDEE9A47B6B72DC6A31EEF41CA5F0 +:102CF000DBF5CD8BE6F15D2CDA4CF72E7A1E8FC317 +:102D000035C1CC1AE99D24710FE18175CDEB3154A9 +:102D1000B3D8DC64E2EFE3FB4D68272A1C0F7A602E +:102D20002EDA0DDFDF68037DEDD93A23D97D1EDA77 +:102D30003DE63ED020BBEE950C80731AD24921E2CD +:102D40001FFA3D97CDE39D1FCBE2F2215FFDBAEB69 +:102D50003E804523E7F9F9AF1BBA237A94EBF8BF1D +:102D6000BA1F20E9570F2779BE6662FF1A28E625A9 +:102D7000E1D7653F11F093F7331C4B4C455B6D7405 +:102D8000CFA300E3CA24FEBECEE674F96616C737A9 +:102D9000D64379D453BD7C352B1AEDE09DCC116D13 +:102DA000BF813DF8FFE8DE04C1BFA7FB5E3DC989D6 +:102DB000EBE4430FF7BF7AA24FFAF72DEE8185C8F7 +:102DC000091EEF23F0E11F6820BFFA9A482D1FFF6C +:102DD000358BDB5D9E96FB850FCEDD5A39C1D0AEBB +:102DE000DFB04A15726241D7EF48E0F7F9AB4CA467 +:102DF0005F3356F438C6197CB2D14471B163DD8CAF +:102E0000F49892CD8A7F8B82FBE898049CBFD7A769 +:102E1000DD8FEF60AED5E8FF285DABFDBED0C67F8D +:102E20006F62BEFEDD14715E5F7883F3FAD92CE128 +:102E300007723117E95DC2FF5F2EDAE8F5AE4E3F4B +:102E4000F79BE1795BE576278A1B93FBBB03FD3794 +:102E500021EF81003CC333711F6F34761BCFD70540 +:102E6000CF1EE2152EDA44BC828DC76774EE0FE3E5 +:102E7000FE4DE95712F52FFAAE5239D6C7DE2EE5D0 +:102E8000F2B80BE94FD2FBAB3A6D06F2B774EE8F96 +:102E900024FF3CFA71A2810ECE1BF6C58F7206E7A5 +:102EA000E76953357E107DEA59F1129D17CB533DEA +:102EB00031D918876D74595D907FC47684DE8F2A6E +:102EC00014762FFD7CBBCE5D63F8FB2E9D3EAECF0E +:102ED0007616F07738402E32E42319873095C129D1 +:102EE00015526F6034CDE7DBFA73A65FCBE57ECC7D +:102EF0006BB7517BCFDAD1941FD0B87E09DE8399AE +:102F0000D9B0D0842EECB62797E78743D3B6FEFE20 +:102F100095E188B7714AB776F9BC6C85F8A14D1771 +:102F20005F2FD3ADD99C5F7E9D2DE5B888435AA114 +:102F3000101F2C55988C4B22392EF3579B443E9FE3 +:102F4000E797ADE2F936F1BEFE0E6147C175638ABF +:102F5000EBC673FF6E6167C175638AEBC6EF28B776 +:102F6000308F720BF328B7308F720B53945BF8BD20 +:102F7000841525E7AADC0F353194EFAE59D9C4107A +:102F80007E413F54681EFD50A1F5D10F155A8E7E2B +:102F9000A8D072F44385E6D10F155A1FFD50A179D0 +:102FA00036EAAE601EE59C7BAA263F1DF4FC892113 +:102FB000FC8D7EA8D0FED10FA5E9CFB344D3FE7E11 +:102FC00056A7698F7EA8D0FA0FD6291A3FD583E27B +:102FD0009DD3D24D71443FF31D4535D980DFFF8825 +:102FE000F8EF874D2988E79645FC5C16EEE2786E8F +:102FF0002AE07837308EE78E3984E7E5669ECFE7A2 +:10300000F1C97AFA417FCF4413F7F7608AFE1E4C6C +:10301000D1DF8329FA7B26A6717F0FA6E8EFC1EFE7 +:10302000E8EFC114FD3D98A2BF0753F4F7608AFE94 +:103030001E4CD1DF83EDD0DF8329FA7BF03BFA7B96 +:1030400030457F0F7E3F897E2753705EA8C70FD41F +:103050009C1F810E35E747BB268F7A7C687DD4E3C1 +:1030600043CB518F0F2D473D3E348F7A7C687DD402 +:10307000E343F3BFCC72109FA13E1FDA0EF5F9D0E7 +:103080007C7693EF0DB49D4DDE7CF918A66D91CA48 +:10309000B30A888CE6ECF7EE433F5D5B98921C0325 +:1030A00092D3B4E2C3FB2682BEE611F17F39ACC3F2 +:1030B00080F8F688F7D43D0146F196D97F4BA4F20B +:1030C000CB78AF5FC4DB22DE73F733FA5D12E92FF2 +:1030D00096ED5DCCAE622AEB07F3DDD7D38F2FEBF5 +:1030E00091FC0C9907DE00C67895DCE5B63C8CF7C0 +:1030F000DC6150284E62C74A1E27ACA7AB33424F53 +:10310000DA61D87704EF81747815BA0F9C6E642762 +:103110004C7908A7DA3CDC7FDFCE8E11EBAABD1517 +:10312000EF9BC8794BFB26C809BA3F37A6A3754267 +:1031300034F4E3F18DA3DF49293473BD01DBE17978 +:1031400072884F716F0DA1EFF785DCF4F8F8F83F46 +:103150007F6E0A6F17CEDBFDFCB92882E3944685AB +:10316000E2A5C6EC666EBC9FFB1F429E0ED91D50A9 +:10317000713C6F231F4FF6EBDD9C4CF716BDAC6D19 +:103180006202F9481486725BC20DD6770CD707C766 +:103190008613689FBED97B3FB70F8FC9C7383AD611 +:1031A000C2E81DCBC9C3DFD5AC97D03E92FAA57D4E +:1031B0002DC3A7D07BC1537C2B56E2B63ED9B7E4D2 +:1031C0008DDE587F1B73391DB415D1BD58399FC191 +:1031D000EE7D06D81659166B358429886F76342E05 +:1031E000847E80F36720BE735D267ABF77AAD16E96 +:1031F000A2F7237A883FB96A93F1273A7D4117678E +:10320000D2B0FC8364B4272F8D3490FD77E94BFC5A +:10321000F7003C9B14926B520FF28A38B5AB8D6F5E +:10322000F49E8570DF67A2FE64FC4975AA3FD980D1 +:1032300071F57DB7E4C4AAA407C4E6A01EE0FBD5DF +:103240007DA3B0DE2AFE8EE5D5C699D101EA89FBC1 +:103250006BCA04BCCA441C93171FF45683BF8B254A +:10326000EF77B026AEEF497B8EF7B7C38E237EBDD6 +:10327000CF8877A5D77AE95EB63E8E6851A389E2FA +:103280008E16E9F4C24AA11756DE402F1C9CA3D328 +:103290000BE5EFA588364CEDF73EC6EDC97B89C539 +:1032A00026CEFFC5FB18D9618B574C30D03BC82FB9 +:1032B00071BA295EC1F59BE297DD74BF50EA8BEFCE +:1032C000083D66DAB52482FB1F84DE3213E32B014E +:1032D000BE856D61220E2B91D259D778BCE5341B87 +:1032E00097036DAFF177203A7D16AE4F1D63FC1D3D +:1032F000331D5D4E35FA0D78E1CE3506E812F293B6 +:10330000510F82FE66A35E148774EECCA7F8BD024F +:1033100085EEBDE8E9BCD054FB06C687166E672E65 +:103320001F0BA573A05FECCFA7D0FB001E71AE955D +:10333000F4ABA7F77911C21E65E3F6A62EBB04EA2B +:10334000A8F44877CE2CD41BE7A16FAF2F27188C99 +:103350003B8BCCE2E5653939B31AF190D3839D42BA +:10336000FD9E99E0E191EF20F46037407B01CAC9EE +:10337000071ECA359784C8C9E1AEF18D434704F1F1 +:103380005DD275DF2F8BDE055DFA481AFD1E4E4FAC +:10339000FA7029C015F9625E74DBC3F80B6B0D3946 +:1033A000CC3D31017F2750AE8F05308E70AEC837CF +:1033B000EFBDEF4F6B6D0417CAD7E78C998571216C +:1033C000D5D6B649487635599E02BCC718944F45A4 +:1033D000EE2405E5536E00CF849BE4FD649D3DA281 +:1033E0003987D7D7DB254AB3B8DC96BF8B72EA9111 +:1033F000837B71BF92F33FD5C3EF30ECCCE1F2F7A2 +:103400007FEB1E84FEFEC32FFB7A9ECC81753C6E43 +:10341000E0F7F9FBAA4D4CD887C82F2CE50513EF30 +:103420006004F1EEA677741B1E51ECA1F629CF5A69 +:1034300085DFA3EFC18EC3323B9EDC0EEDE6D59B4C +:10344000E9F7F89E4BE7F4F31CD00FFD5E8AB9F55F +:103450000DAB3308C78FEB7E6AA2DFA56181347C98 +:103460007F676E6D980BE5F17057D12F71DE1159A2 +:103470002E92438D18430EF9BB7A15BD88DFABD76A +:103480001D7E16DF13A86971D2EF95780FE5AEC6E1 +:10349000774E86BB3C07B1DC6BB3D37B1A8B1B63C7 +:1034A00068FF9AD747DC0B651DE46793F07F47D828 +:1034B000AFD6BA38FD5E11E70E14905335F5BAB7A2 +:1034C000E3493BA1DECEA07F5FA227FB82B427A009 +:1034D000FDC01C626794F60953E6A939A837149B0E +:1034E000B5F71265CA86F27D5F9E03E777ED5B59FB +:1034F00093FAA07EBC41B1D37B9336C7ACD1902F59 +:103500003B61C2C84E5618EB30E3FB031D805F8C55 +:103510008F2E017E4539532CE2B4CA368D267E2B80 +:10352000F343DACD3B9C32BD7FC3D1FE2F23FD0494 +:10353000DCE4B72CB3BBCDB1217C5FDAA468DE1D1F +:1035400090F98E1C95F311A8E308BF071E729AF13B +:103550006D9F62502330FE8F0D7568FCC7508FE25F +:10356000410A53D871FE0E3CCCDBC9C7CB0BE9BF77 +:10357000A489DF9B9679A84FFACFDF732209AE5E4C +:103580003BACDB89A99DE60970203875AC87FE1C31 +:10359000340EE1A334E037E179BB18E350203FD784 +:1035A000EE37E138258DFC1D13CF3A3E8E676D8CCA +:1035B000391BF523A3DDDC1FE1277E6F15E6477A73 +:1035C0006419C005EF63E17D37DC5BF4F0F18AF943 +:1035D0009635C5D03B0AC1EF1B4C888F393DBC8B5B +:1035E000903594D36D49E338BABF5E6674D33D0716 +:1035F0008F80EF274BC21E45FFC09C8D4F989C903B +:10360000EF3794D36FD6504E5F852981347AAF68F7 +:1036100049980BE739C7DE44EBEB82EF63000F05F7 +:10362000DFB92922F8025DF8306EAF6CA3169FC196 +:10363000F970F8966DF412BF2D307ACCF6D0796C13 +:103640003A9C86F7AAE6007FE3BB12CCEEA1FB9280 +:103650009F3E362B99D609F344B846BA1C93F0FD29 +:1036600021A0137E0F46AC47DEEB96E34D1CCAEF5C +:103670009D4E1CCAE567CF7CE926BDA601F08B767E +:10368000EF9EF8D28C821BC63597F1DF91D0F3A95B +:10369000E44FC997924F25FF3E6B2A0A24284139EF +:1036A00003FB6CED8BDDC0A951CC77AEC02BC0F510 +:1036B00058E83DAF6A81D7E2142DBF637FD8EF1C75 +:1036C000C1EFC5E30369F82E93AC2FC72D8EE5ED4E +:1036D00090EE91DEE688F1B0FE52AAAFBDA752DAB5 +:1036E000252F76AF8A4779B14FE17ED0F547FB7F32 +:1036F00007F5D73D5C7FBD50B57D31EE97CCE84FE7 +:103700000E7DDF7F3EE83928271688FDB92CD0BD15 +:10371000BCB890EEA9181AC2CF653FDB93EEE1F278 +:103720002680F2E6CF7B5EFDE3AD8EE07E2AD753A6 +:10373000B2F65D93D7160A3FBEFE47333BE93E5EC5 +:10374000A9CDECC078E7D2462FC95F96007AA112C6 +:10375000127FA6A30B6FA342F7C84AEB46FAD5FF28 +:1037600045395DBA6E2ABD7B20F126DF6791FBAB40 +:103770009CFF7A31FF2621DFE60AFA9E5B3ECE9C53 +:10378000D88BF46E0CB36473C4F73965DAEF5D78E7 +:10379000EBF25F67AD467EC1FB45743E5967E2F6CA +:1037A000BEDDDCFE7861E9C1DFDD07F5CE3FBE2579 +:1037B00099A95ABCA19EBA40E8AB0B85FDAF1BBCD2 +:1037C0006D19DA3B985FF81CC75BE9DEDFFE05DFA9 +:1037D000132B4E11F26E3D7F07A0A4791FE171CE2D +:1037E000DA0D2627D4DB37D44970EA92FFB5B976D3 +:1037F000B42BCF5DBBC58472629F84838E1F8A45C4 +:103800009CB08433EE4B4A887F43D647F988EFDF7C +:103810003FB4242C0AE379E4381F093A2FAD8D898F +:10382000C5F14A6BBD3FC6F390DC0FF4EB3C1DC6FF +:10383000F9A504FA43BE3D3DCE95BC342BA8CFEA92 +:10384000EBBF2BF0F8B489FF4E4D5244F32E8A6B38 +:10385000A80977A1FC1838B0CD8FE3227DE3BCCD59 +:1038600006FEBB3603ABDA3EC77980AA4D713598A8 +:10387000E2FB58A87AC7437EAB81DFDF4A5179FA71 +:103880009590D7501EC072D6AB8D7E5F23246E56A6 +:1038900043BF66B68D7E3FD1DC8BD1FB66925E6501 +:1038A0003F925E253DF7B4BE2B42AEDC687DA79DFE +:1038B0001C9E66F1BB2937BD3E0BFF1D5DB92E393D +:1038C0003FD0E1DDF4BEC7F7B3C9DE737A852B19AB +:1038D000E3267B5EEFC6FCF86ED6AB5FA7E41B1950 +:1038E0000BDFE5CF6AE27E87D30AEC6FD0EEF4926D +:1038F000308A6F93EBD2DBC3FF1FB640B5F6008072 +:10390000000000001F8B080000000000000BCD56D7 +:103910007D6C5355143FF7BE7EAFDDDEBAB1751B2B +:10392000DBBA8D8F46BAF1CA80F891681D8CF0C75A +:10393000A2DD14DD0C6C25B031C68A9360A8C6B830 +:10394000B2229211E24C3618044C876C7F18205D2D +:10395000208AB19A8689468311E11F1292A60B38FC +:10396000D16856310A44649E73DF2B9D08897FFA23 +:1039700092E6F4DE7B3E7FE7E3DE0F7A658085002A +:10398000C77B1D00468093BD4E41A3BD2EB19FA7AE +:10399000D801E6007E495B930D60AD05DA7C565C8C +:1039A000C6F1970F9008568DF4B3CC7E831DDA9A3A +:1039B0009026E4A4CDEEC67DBBBA7FADC7DC0F393F +:1039C000002D90DCE7588AB2C12A1845538981AB93 +:1039D000368E7C579F463E77466EBB3EB51E88CFDF +:1039E00066708E5600646DFFAEBE10EDB50F567852 +:1039F00018CAAD0BD6268278BE6E57A102B86EB734 +:103A00003A773BE83C54A1F4E13A6BD033358CE78C +:103A1000EDBB1629C4BF9D812F4A7E0F1C002800D4 +:103A2000E8807B9FD7B41C6013FD43BE4D56C32472 +:103A3000ABC1F3E0C43C19E53B14B387A1FD4DC312 +:103A40002C6EC4FD060E7BD81280F2B06F5511DAD1 +:103A50004B1D64CA51923D5CEF4D9A5485339500DD +:103A60005D0B7D35CA325CDC99999941FD8F20460A +:103A700020515C512FC501434C1E05F2DB67207CB1 +:103A80004E2C760A9C13839336A75BC5BB11F106B7 +:103A900047010794DF6652FD2B37A426DF46BF524D +:103AA00036AE1CC575BDE4FED649717E2581D1496F +:103AB000721ABFACF1BFF9A8C98FFAB6D92A0B01A7 +:103AC000E9C66174A216CF9A4D9C70E8D47C6E1F33 +:103AD00079AE00D08F763C77E2F921DA7C0C60F782 +:103AE000E08A8224C9BD5BBF3F540D50A6E1784DEA +:103AF000976CA4FC5C1F29B4EFC4D83606C20B0037 +:103B0000CF378EBC5D46F4FA88B939827C2BE5C686 +:103B100095B9186FC7E15C8F84FECCD0F714E64DE1 +:103B20004121C4A72BB0A21010AFEEBB13EFC955B3 +:103B3000681FB126DC7F8F664542C8D2DD7BA64C6C +:103B4000E2E88AD1DF4C786EE1B1171E433D3FB108 +:103B5000C85891E07716CAD68CDEFBE9542FC28094 +:103B6000F51C78F3B2D0F30B3FFF4C0BCA77074E2E +:103B700065939E2D439796CBB8DF59E5DFA8CC21FE +:103B8000BD2363324204C323353E8CA35D01E1674C +:103B900083DDF7420BE1FE9524707F98BDCE334C58 +:103BA000E07B2FCE488E8170F7C7C1201395C140AE +:103BB000F57D5D8260146943A5DA2FE9FD20E1827D +:103BC0007E5CCF1928A3BAD83C76A0CC89F4479B59 +:103BD000BA5E3BF6E2D7908DFCC78C06CA975F07AA +:103BE0000605E5368498374275D389FD5A94B1DFCE +:103BF000A764097D9B87D1A9BCCC3E4044C4F5A3F2 +:103C00000E56931FE5E194E715A45774F176CAEBBD +:103C1000951EB312AAA03C3905DF95016915ED8701 +:103C2000B091E6335A9FB2CD43FBAD39D043F2B6E3 +:103C3000A5D138C73C074EE72E91D49212F5B55561 +:103C40005617F5927555099E6F1B6732D5E9B68FE9 +:103C5000CFAD02750DC01E8E67D7AD27C039CBEF33 +:103C6000AED3E306EA8FEEE3182FDAEF8E8E7F51A4 +:103C70008C7AB69E595FABDA1D00AAFF80D6CF5B67 +:103C80004FABB8044E4F1A36B8337AD6BBECBB4BA9 +:103C900030B7A34AEB8B43C8BA9EF2F63840EC64C7 +:103CA00063F3CE79486B641137E852653EECC37E0E +:103CB000D74503F5516097A6CF757177A588B731C1 +:103CC0000F66D5C398A217726979C443C8C5039615 +:103CD0003DB01887CD56AB8E683860CD267AB88750 +:103CE000BB7488AB97591409F10E9AB26B684EDE1B +:103CF00034AB346651E90EEE1BEF40176FF20B66E2 +:103D0000C0BADF210D30A24FB97B18220D8BF2FD16 +:103D100031AA5F0744190820E28CFC9EFEF4875A02 +:103D2000B2FF6479F2374097F43BDB9A57627D7CAF +:103D3000AE68F1B993B554E773CEAA73FA881EF64C +:103D4000989750DC3E68AA262DF89FF27E9B476824 +:103D50000EC758FC7DD29F8EF796D6C73EA3750F2F +:103D6000433F1B9CFE6FC88F6799BEDAC32907D2F9 +:103D70007CD23FAD57CF71FE7A4D581775DAF02DD2 +:103D8000E510022C5943B1C34A75CDBC5E08A2FDB3 +:103D90003EF7D90D541F7B532630A2DDB086475D18 +:103DA000CA32C990AFB47835079CC7CC994F770C0D +:103DB0009C75F39011FDDC0BA608F18309E7B12B8C +:103DC000338F0DDCEC15FCB12F6FD37C2F917E9DD2 +:103DD000C841FE921D4C09234FEB8DA923DF225DC4 +:103DE0000B110FE1DA95EF9FA2381237564FFA31D7 +:103DF000BF7BE5A84971ABFA66FB1F7BED76B69DEC +:103E000067FC9A4E4D9DF868295193B877EA629203 +:103E1000B837EEF767DAE1D4911DE48B73E2B7F2BD +:103E20000863C43F7199FCAB3359E35236C9E97F4B +:103E30009E7DAFC085D2DCA945E22A8199129CF60D +:103E400061356F4F6A7D98CE8B85C05F4654CD4FEC +:103E50001A3FE1FCACFBE433EBD83AAA9F74BFBE37 +:103E6000ACEDDFB8559943F3E546AC2A07DC0FEF1C +:103E7000CF4B385FE99D70B8C26BF72CCBDCA76BDA +:103E8000D2B7AB76DF4A9ADE351A4E6BAC5CC5E52D +:103E9000F9FB70D1EA245D0769BFD3794EE70F5E65 +:103EA000BF702EA742E4ADFA1D10F99A4BF613B776 +:103EB000CFBF856D05C59277D25FF17FCC57DCBC53 +:103EC00090DE0D435CBC1B4A09F825827A39C6078F +:103ED0002E10F3A055B228FD0F98077E9A078B6924 +:103EE0001E0C883EBFC953E738A379D023D60E48AD +:103EF000EDD4E13AC19336F23769C6AA47EAF754DE +:103F00008A7BA0843ABA4ACD13F5F591D76C47E97C +:103F1000FD1666DE8326940FEBB57EDF6C8D8CE29A +:103F2000FE748487F4686F303772B003F707D7CC1C +:103F3000554288D334687C9D1631179EE05CAC53A3 +:103F40002D0591A315C48F7D8D710EB63C22EEF127 +:103F50000FEF4AE2BD989A0FEAB907160CD379A37E +:103F60004BE8FB243D67F6D984BEC1466F91459C62 +:103F70001770928FE4F95FA2FC164B2A1F3E0404CF +:103F8000DFA143DE22CAC7A12683E0DBCF7C2DED73 +:103F9000A4A7DAAAD0FB32D9623939A6A623CE96D5 +:103FA000D27B558D375DBFC30B64814B7968F2209E +:103FB000BD434275E0EAA1F72BD5E1E24C7E9817AC +:103FC0007361CFE4295D8F213DE62B5FCD571FFB49 +:103FD00077BEF2B57CB120D66D36E52D2AF0BFC98B +:103FE000D53CEC9020998531495C711891FE91EF98 +:103FF0007F558DF342119DB71A93CB06E85DCCA196 +:1040000033FA803E0C519F8BF739DEA258E76D5A88 +:104010009DB7A5EBF18DFBEA313937772A4BAB47DA +:1040200094FFDEE2EB237BBFB04BCB69F3FC5F5226 +:10403000F383ECECD5E6C89F467FBFE8F36385FFCA +:1040400078679EF7FC504AF70CDC99984BF7CE99AD +:104050003CDF3EE233CF4B19FC8467514A4FF124D9 +:104060005A7E2AA5F74C5BF04BD137FFD5CFB41F52 +:104070007F03DC4DE081B00C000000000000000078 +:1040800000000018000000000000000000000040D8 +:1040900000000000000000000000002800000000F8 +:1040A0000000000000000010000000000000000000 +:1040B00000000020000000000000000000000010D0 +:1040C00000000000000000000000000800000000E8 +:1040D00000000000000000000000000000000000E0 +:1040E00000000000000000000000000000000000D0 +:1040F00000000000000000000000000000000000C0 +:1041000000000000000000000000000000000000AF +:10411000000000000000000000000000000000009F +:10412000000000000000000000000000000000008F +:10413000000000000000000000000000000000007F +:10414000000000000000000000000000000000006F +:10415000000000000000000000000000000000005F +:10416000000000000000000000000000000000004F +:10417000000000000000000000000000000000003F +:10418000000000000000000000000000000000002F +:10419000000000000000000000000000000000001F +:1041A000000000000000000000000000000000000F +:1041B00000000000000000000000000000000000FF +:1041C00000000000000000000000000000000000EF +:1041D00000000000000000000000000000000000DF +:1041E0000000000000000000000033280010000064 +:1041F0000000000800003330001000000000000242 +:1042000000003328001000000000001000003A7881 +:104210000000000000000008800000000000000016 +:10422000000000008000000000000000000000000E +:1042300080000000000000000000000000003120AD +:1042400000000000000000080000336000010004CE +:1042500000000001000033680000000000000002C0 +:1042600000003370000000000000000800003374FC +:10427000000000000000000200003A700000000092 +:104280000000000800003A4000080000000000089C +:1042900000003D88004000000000004000003A504F +:1042A000000800000000000800003A60000800005C +:1042B0000000000800003A8800C8000000000098D4 +:1042C00000003C18009800000000002800003C5846 +:1042D00000980000000000280000337803600030E0 +:1042E0000000036000003EB0000800000000000174 +:1042F00000003EB10008000000000001000020089E +:10430000001000000000001000002000000000006D +:104310000000000880000000000000000000000015 +:10432000800000000000000000000000000000000D +:10433000000000000000000000000000000000007D +:10434000000000000000000000000000000000006D +:10435000800000000000000000000000800000005D +:1043600000000000000000008000000000000000CD +:1043700000000000800000000000000000000000BD +:10438000800000000000000000000000800000002D +:10439000000000000000000080000000000000009D +:1043A000000000008000000000000000000000008D +:1043B00080000000000000000000000080000000FD +:1043C000000000000000000080000000000000006D +:1043D000000000008000000000000000000000005D +:1043E000800000000000000000000000000000004D +:1043F00000000000000000000000000000000000BD +:1044000000000000000000000000000000000000AC +:10441000000000000000000000000000000000009C +:10442000000000000000000080000000000000000C +:1044300000000000800000000000000000000000FC +:1044400080000000000000000000000000000000EC +:1044500000000000000000008000000000000000DC +:1044600000000000800000000000000000000000CC +:1044700080000000000000000000000000000000BC +:10448000000000000000000000000000000000002C +:10449000000000000000000000000000000000001C +:1044A000000000000000000000000000000000000C +:1044B00000000000000000000000000000000000FC +:1044C00000000000000012C8008000000000008012 +:1044D000000000010000000000000000000040009B +:1044E0000490000000000490000019C800000000C3 +:1044F0000000000800004948000800000000000813 +:1045000000004928000800000000000800004938A9 +:104510000008000000000008000020080010000053 +:104520000000001000002000000000000000000853 +:104530000000401004900040000000400000499836 +:104540000008000000000001000049990008000078 +:1045500000000001800000000000000000000000DA +:10456000800000000000000000000000800000004B +:1045700000000000000000008000000000000000BB +:1045800000000000800000000000000000000000AB +:10459000800000000000000000000000800000001B +:1045A000000000000000000080000000000000008B +:1045B000000000008000000000000000000000007B +:1045C00080000000000000000000000080000000EB +:1045D000000000000000000080000000000000005B +:1045E000000000008000000000000000000000004B +:1045F00000000000000000000000000000000000BB +:1046000000000000000000000000000000000000AA +:10461000000000000000000000000000000000009A +:10462000000000000000000000000000800000000A +:1046300000000000000000008000000000000000FA +:10464000000000000000000000000000000000006A +:10465000800000000000000000000000800000005A +:1046600000000000000000008000000000000000CA +:1046700000000000800000000000000000000000BA +:104680000000400000180000000000180000430077 +:104690000040000000000040000043000040000215 +:1046A0000000000100004301004000020000000083 +:1046B00000003000004000000000004080000000CA +:1046C0000000000000000000000030000008004072 +:1046D0000000000400003004000800400000000456 +:1046E00000004B00002800000000002800004B5094 +:1046F00000100000000000100000380000800000E2 +:104700000000008000003800000800800000000267 +:1047100000003900002000000000002000002008F8 +:104720000010000000000010000020000000000049 +:104730000000000800005108000800000000000808 +:104740000000512000080000000000080000513067 +:104750000008000000000008000051C00008000030 +:1047600000000001000051C100080000000000012D +:10477000000039400010000400000004000051D087 +:104780000030001800000010000051D80030001860 +:104790000000000280000000000000000000000097 +:1047A0008000000000000000000000008000000009 +:1047B0000000000000000000800000000000000079 +:1047C0000000000080000000000000000000000069 +:1047D00080000000000000000000000080000000D9 +:1047E0000000000000000000800000000000000049 +:1047F0000000000080000000000000000000000039 +:1048000000000000000000000000000000000000A8 +:104810000000000000000000000000000000000098 +:104820000000000000000000000000000000000088 +:104830008000000000000000000000008000000078 +:104840000000000000000000000000000000000068 +:1048500000000000000023E800800000000000804D +:10486000000000010000000000000000000020081F +:1048700000100000000000100000200000000000F8 +:104880000000000800002DA0000800000000000843 +:1048900000002DB80008000000000008000024E817 +:1048A00002D00028000002D000002E5800080000AE +:1048B0000000000100002E59000800000000000167 +:1048C00000002D900008000000000008800000009B +:1048D0000000000000000000800000000000000058 +:1048E0000000000080000000000000000000000048 +:1048F00080000000000000000000000080000000B8 +:104900000000000000000000800000000000000027 +:104910000000000080000000000000000000000017 +:104920000000000000000000000000000000000087 +:104930000000000000000000000000000000000077 +:104940000000000000000000000000000000000067 +:104950008000000000000000000000008000000057 +:104960000000000000000000000000000000000047 +:1049700000000000800000000000000000000000B7 +:104980008000000000000000000000008000000027 +:104990000000000000000000800000000000000097 +:1049A000000000000000250000400000000000089A +:1049B000000025080040000000000028000009C099 +:1049C000012000100000000880000000000000002E +:1049D0000000000080000000000000000000000057 +:1049E0000000402002D00028000000080000300035 +:1049F00000000000000010000000509900000000BE +:104A000000000001000050B00000000000000002A3 +:104A1000000045A000900008000000088000000091 +:104A200000000000000000000000296000080000F5 +:104A300000000001000029610008000000000001E2 +:104A4000000029700008000400000002000029781E +:104A5000000800040000000400002FB0000800005F +:104A60000000000400002FB4000800000000000453 +:104A700000002FC0000000000000000800002FC848 +:104A800000000000000000080000300000000000EE +:104A90000000001000005040000100010000000173 +:104AA0000000500000000000000000200000080886 +:104AB00000100000000000040000080C00100000BE +:104AC00000000001000008B7000000000000000125 +:104AD000000008B600000000000000010000100007 +:104AE000003000180000000400001004003000181E +:104AF0000000000400001008003000180000000250 +:104B00000000100A00300018000000020000100C25 +:104B100000300018000000010000100D00300018E7 +:104B2000000000010000100E00300018000000011D +:104B300000001010003000180000000400001014E5 +:104B40000030001800000004000030000100008068 +:104B50000008000400003004010000800008000488 +:104B60000000000A000000000000000000003068A3 +:104B70000100008000000001000030690100008099 +:104B8000000000010000306C010000800000000205 +:104B90000000306E01000080000000020000307054 +:104BA000010000800000000400003074010000805B +:104BB00000000004000030660100008000000002D8 +:104BC000000030640100008000000001000030603F +:104BD000010000800000000200003062010000803F +:104BE00000000002000030500100008000000004BE +:104BF0000000305401000080000000040000305824 +:104C000001000080000000040000305C0100008012 +:104C1000000000040000307C010000800000000162 +:104C20000000307D010000800000000100001C1821 +:104C3000001000000000000400001C300010000004 +:104C40000000000400001C380010000000000004F8 +:104C50008000000000000000000000008000000054 +:104C600000000000000000008000000000000000C4 +:104C700000000000800000000000000000000000B4 +:104C800000004C10000800000000000200004C1260 +:104C9000000800000000000200004C1400080000A2 +:104CA0000000000400004C20000800000000000884 +:104CB00000004C30004000080000000800004C00DC +:104CC000000800000000000200004C020008000084 +:104CD0000000000100004C04000800000000000279 +:104CE00000004CD0000800000000000800004CE06C +:104CF000000800000000000400004CE40008000070 +:104D00000000000100004CF000080000000000025C +:104D100000004CF4000800000000000200004D00FC +:104D20000008000000000004000050000010000017 +:104D30000000000400005004001000000000000407 +:104D400000005008001000000000000400001400E3 +:104D5000000800000000000200001402000800002B +:104D60000000000100001404000800000000000220 +:104D700000001410000800000000000200001414DD +:104D800000080000000000020000141600080000E7 +:104D900000000002000019B8000800000000000830 +:104DA000000014200008000000000002000014248D +:104DB0000008000000000002000019C80008000000 +:104DC0000000000800002C10000800000000000196 +:104DD00000002C11000800000000000100002C124F +:104DE000000800000000000100002C130008000073 +:104DF0000000000100002C0000080000000000027C +:104E000000002C02000800000000000100002C043B +:104E1000000800000000000200002C300008000024 +:104E20000000000200002C32000800000000000218 +:104E300000002C34000800000000000200002C20BC +:104E4000000800000000000100002C210008000004 +:104E50000000000100002C220008000000000001FA +:104E600000002C23000800000000000100002C249A +:104E7000000800000000000100002C2500080000D0 +:104E80000000000100002C260008000000000001C6 +:104E900000001400000800000000000200001402DE +:104EA00000080000000000010000140400080000D9 +:104EB000000000020000141200C0001800000002F0 +:104EC0000000141000C00018000000020000141CB4 +:104ED00000C00018000000080000141400C00018F2 +:104EE000000000080000142700C0001800000001A6 +:104EF0000000142400C00018000000020000142666 +:104F000000C000180000000100001590000800001B +:104F100000000008000015A00008000000000008C4 +:104F2000000015B00008000000000008800000002C +:104F300000000000000000008000000000000000F1 +:104F400000000000800000000000000000000000E1 +:104F50008000000000000000000000008000000051 +:104F600000000000000000008000000000000000C1 +:104F700000000000800000000000000000000000B1 +:104F80008000000000000000000000008000000021 +:104F90000000000000000000800000000000000091 +:104FA0000000000080000000000000000000000081 +:104FB00080000000000000000000000080000000F1 +:104FC0000000000000000000800000000000000061 +:104FD0000000000080000000000000000000000051 +:104FE00080000000000000000000000080000000C1 +:104FF0000000000000000000800000000000000031 +:105000000000000080000000000000000000000020 +:105010008000000000000000000000008000000090 +:105020000000000000000000800000000000000000 +:1050300000000000800000000000000000000000F0 +:105040008000000000000000000000008000000060 +:1050500000000000000000008000000000000000D0 +:105060000000000000000000000000000000000040 +:1050700080000000000000000000000000000000B0 +:08508000060209000000000017 +:00000001FF diff --git a/firmware/bnx2x/bnx2x-e1h-6.2.5.0.fw.ihex b/firmware/bnx2x/bnx2x-e1h-6.2.5.0.fw.ihex deleted file mode 100644 index 5f04df6..0000000 --- a/firmware/bnx2x/bnx2x-e1h-6.2.5.0.fw.ihex +++ /dev/null @@ -1,13181 +0,0 @@ -:1000000000004F48000000680000070C00004FB8D7 -:1000100000001ED4000056C800000094000075A027 -:1000200000009F4C00007638000000CC00011588CD -:100030000000DC4C00011658000000940001F2A8FA -:10004000000040000001F340000000A4000233481B -:100050000000F38C000233F000000FFC0003278047 -:100060000000000400033780020400480000000F75 -:1000700002040054000000450204005C0000000679 -:100080000204007000000004020400780000000078 -:100090000204007C121700000204008022170000F6 -:1000A00002040084321700000604008800000005E6 -:1000B0000204009C12150000020400A0221500009A -:1000C000020400A432150000060400A80000000489 -:1000D000020400B802100000020400BC001000007E -:1000E000020400C010100000020400C42010000030 -:1000F000020400C830100000020400CC40100000D0 -:10010000060400D000000003020400DC0010000020 -:10011000020400E012140000020400E422140000B3 -:10012000020400E832140000020400EC4214000053 -:10013000060400F000000003010401240000000098 -:1001400001040128000000000104012C000000004F -:100150000104013000000000020401D00000890603 -:1001600002040004000000FF02040008000000FF79 -:100170000204000C000000FF02040010000000FF59 -:10018000020400140000007F02040018000000FFB9 -:100190000204001C000000FF02040020000000FF19 -:1001A000020400240000003E0204002800000000B9 -:1001B0000204002C0000003F020400300000003F59 -:1001C000020400340000003F020400380000003F39 -:1001D0000204003C0000003F020400400000003F19 -:1001E000020400440000003F020404CC00000001AF -:1001F00002042008000002110204200C000002008A -:10020000020420100000020402042014000002195D -:100210000204201C0000FFFF020420200000FFFF5A -:10022000020420240000FFFF020420280000FFFF3A -:1002300002042038000000200604203C0000001FBB -:10024000020420B800000001060420BC0000005F8A -:100250000204223807FFFFFF0204223C0000003F97 -:100260000204224007FFFFFF020422440000000FA7 -:1002700001042248000000000104224C000000009C -:10028000010422500000000001042254000000007C -:1002900001042258000000000104225C000000005C -:1002A000010422600000000001042264000000003C -:1002B00001042268000000000104226C000000001C -:1002C00001042270000000000104227400000000FC -:1002D00001042278000000000104227C00000000DC -:1002E0000C042000000003E80A04200000000001C4 -:1002F0000B0420000000000A0605400000000D006D -:100300000205004400000020020500480000003201 -:10031000020500900215002002050094021500203D -:1003200002050098000000300205009C0810000043 -:10033000020500A000000033020500A40000003008 -:10034000020500A800000031020500AC0000000218 -:10035000020500B000000005020500B40000000620 -:10036000020500B800000002020500BC0000000207 -:10037000020500C000000000020500C400000005E6 -:10038000020500C800000002020500CC00000002C7 -:10039000020500D000000002020500D400000001A8 -:1003A00002050114000000010205011C000000010B -:1003B0000205012000000002020502040000000105 -:1003C0000205020C0000004002050210000000407F -:1003D0000205021C0000002002050220000000139C -:1003E0000205022400000020060502400000000A69 -:1003F00004050280002000000205005000000007F4 -:10040000020500540000000702050058000000002B -:100410000205005C00000008020500600000000109 -:100420000605006400000003020500D80000000675 -:1004300002050004000000010205000800000001A0 -:100440000205000C00000001020500100000000180 -:100450000205001400000001020500180000000160 -:100460000205001C00000001020500200000000140 -:100470000205002400000001020500280000000120 -:100480000205002C00000001020500300000000100 -:1004900002050034000000010205003800000001E0 -:1004A0000205003C000000010205004000000001C0 -:1004B000020500E00000000D020500E80000000059 -:1004C000020500F000000000020500F80000000036 -:1004D000020500E40000002D020500EC00000020F1 -:1004E000020500F400000020020500FC00000020CE -:1004F000020500E00000001D020500E800000010F9 -:10050000020500F000000010020500F800000010D5 -:10051000020500E40000003D020500EC0000003090 -:10052000020500F400000030020500FC000000306D -:10053000020500E00000004D020500E80000004058 -:10054000020500F000000040020500F80000004035 -:10055000020500E40000006D020500EC00000060F0 -:10056000020500F400000060020500FC00000060CD -:10057000020500E00000005D020500E800000050F8 -:10058000020500F000000050020500F800000050D5 -:10059000020500E40000007D020500EC0000007090 -:1005A000020500F400000070020500FC000000706D -:1005B0000406100002000020020600DC000000011A -:1005C000010600D80000000004060200000302201B -:1005D000020600DC00000000010600B80000000078 -:1005E000010600C8000000000206016C00000000C7 -:1005F000010600BC00000000010600CC0000000065 -:1006000002060170000000000718040000910000BD -:10061000081807D800050223071C00002BF700006C -:10062000071C80002DD10AFE071D00002F461673FF -:10063000071D800016342245081DB13049DA022515 -:100640000118000000000000011800040000000074 -:1006500001180008000000000118000C0000000054 -:100660000118001000000000011800140000000034 -:1006700002180020000000010218002400000002FF -:1006800002180028000000030218002C00000000DF -:1006900002180030000000040218003400000001BD -:1006A00002180038000000000218003C00000001A1 -:1006B000021800400000000402180044000000007E -:1006C00002180048000000010218004C000000035E -:1006D0000218005000000000021800540000000141 -:1006E00002180058000000040218005C000000001E -:1006F00002180060000000010218006400000003FE -:1007000002180068000000000218006C00000001E0 -:1007100002180070000000040218007400000000BD -:1007200002180078000000040218007C000000039A -:100730000618008000000002021800A400003FFF1D -:10074000021800A8000003FF0218022400000000A5 -:1007500002180234000000000218024C00000000E1 -:10076000021802E4000000FF061810000000040058 -:10077000021B8BC000000001021B8000000000343F -:10078000021B804000000018021B80800000000C4B -:10079000021B80C0000000200C1B83000007A1206A -:1007A0000A1B8300000001380B1B83000000138824 -:1007B0000A1B8340000000000C1B8340000001F472 -:1007C0000B1B834000000005021B83800007A12053 -:1007D000021B83C0000001F4021B14800000000112 -:1007E0000A1B148000000000061A1000000003B36A -:1007F000041A1ECC00010227061A1ED000000008B1 -:10080000061A2008000000C8061A20000000000296 -:10081000041AAF4000100228061A3718000000041E -:10082000061A371000000002061A500000000002ED -:10083000061A500800000004061A501800000004B0 -:10084000061A502800000004061A50380000000460 -:10085000061A504800000004061A50580000000410 -:10086000061A506800000004061A507800000002C2 -:10087000041A52C000020238061A40500000000656 -:10088000041A40680002023A041A40400004023C84 -:10089000041A800000010240061A800400000003D0 -:1008A000041A801000010241061A8014000000039F -:1008B000041A802000010242061A8024000000036E -:1008C000041A803000010243061A8034000000033D -:1008D000041A804000010244061A8044000000030C -:1008E000041A805000010245061A805400000003DB -:1008F000041A806000010246061A806400000003AA -:10090000041A807000010247061A80740000000378 -:10091000041A808000010248061A80840000000347 -:10092000041A809000010249061A80940000000316 -:10093000041A80A00001024A061A80A400000003E5 -:10094000041A80B00001024B061A80B400000003B4 -:10095000041A80C00001024C061A80C40000000383 -:10096000041A80D00001024D061A80D40000000352 -:10097000041A80E00001024E061A80E40000000321 -:10098000041A80F00001024F061A80F400000003F0 -:10099000041A810000010250061A810400000003BD -:1009A000041A811000010251061A8114000000038C -:1009B000041A812000010252061A8124000000035B -:1009C000041A813000010253061A8134000000032A -:1009D000041A814000010254061A814400000003F9 -:1009E000041A815000010255061A815400000003C8 -:1009F000041A816000010256061A81640000000397 -:100A0000041A817000010257061A81740000000365 -:100A1000041A818000010258061A81840000000334 -:100A2000041A819000010259061A81940000000303 -:100A3000041A81A00001025A061A81A400000003D2 -:100A4000041A81B00001025B061A81B400000003A1 -:100A5000041A81C00001025C061A81C40000000370 -:100A6000041A81D00001025D061A81D4000000033F -:100A7000041A81E00001025E061A81E4000000030E -:100A8000041A81F00001025F061A81F400000003DD -:100A9000041A820000010260061A820400000003AA -:100AA000041A821000010261061A82140000000379 -:100AB000041A822000010262061A82240000000348 -:100AC000041A823000010263061A82340000000317 -:100AD000041A824000010264061A824400000003E6 -:100AE000041A825000010265061A825400000003B5 -:100AF000041A826000010266061A82640000000384 -:100B0000041A827000010267061A82740000000352 -:100B1000041A828000010268061A82840000000321 -:100B2000041A829000010269061A829400000003F0 -:100B3000041A82A00001026A061A82A400000003BF -:100B4000041A82B00001026B061A82B4000000038E -:100B5000041A82C00001026C061A82C4000000035D -:100B6000041A82D00001026D061A82D4000000032C -:100B7000041A82E00001026E061A82E400000003FB -:100B8000041A82F00001026F061A82F400000003CA -:100B9000041A830000010270061A83040000000397 -:100BA000041A831000010271061A83140000000366 -:100BB000041A832000010272061A83240000000335 -:100BC000041A833000010273061A83340000000304 -:100BD000041A834000010274061A834400000003D3 -:100BE000041A835000010275061A835400000003A2 -:100BF000041A836000010276061A83640000000371 -:100C0000041A837000010277061A8374000000033F -:100C1000041A838000010278061A8384000000030E -:100C2000041A839000010279061A839400000003DD -:100C3000041A83A00001027A061A83A400000003AC -:100C4000041A83B00001027B061A83B4000000037B -:100C5000041A83C00001027C061A83C4000000034A -:100C6000041A83D00001027D061A83D40000000319 -:100C7000041A83E00001027E061A83E400000003E8 -:100C8000041A83F00001027F061A83F400000003B7 -:100C9000041A840000010280061A84040000000384 -:100CA000041A841000010281061A84140000000353 -:100CB000041A842000010282061A84240000000322 -:100CC000041A843000010283061A843400000003F1 -:100CD000041A844000010284061A844400000003C0 -:100CE000041A845000010285061A8454000000038F -:100CF000041A846000010286061A8464000000035E -:100D0000041A847000010287061A8474000000032C -:100D1000041A848000010288061A848400000003FB -:100D2000041A849000010289061A849400000003CA -:100D3000041A84A00001028A061A84A40000000399 -:100D4000041A84B00001028B061A84B40000000368 -:100D5000041A84C00001028C061A84C40000000337 -:100D6000041A84D00001028D061A84D40000000306 -:100D7000041A84E00001028E061A84E400000003D5 -:100D8000041A84F00001028F061A84F400000003A4 -:100D9000041A850000010290061A85040000000371 -:100DA000041A851000010291061A85140000000340 -:100DB000041A852000010292061A8524000000030F -:100DC000041A853000010293061A853400000003DE -:100DD000041A854000010294061A854400000003AD -:100DE000041A855000010295061A8554000000037C -:100DF000041A856000010296061A8564000000034B -:100E0000041A857000010297061A85740000000319 -:100E1000041A858000010298061A858400000003E8 -:100E2000041A859000010299061A859400000003B7 -:100E3000041A85A00001029A061A85A40000000386 -:100E4000041A85B00001029B061A85B40000000355 -:100E5000041A85C00001029C061A85C40000000324 -:100E6000041A85D00001029D061A85D400000003F3 -:100E7000041A85E00001029E061A85E400000003C2 -:100E8000041A85F00001029F061A85F40000000391 -:100E9000041A8600000102A0061A8604000000035E -:100EA000041A8610000102A1061A8614000000032D -:100EB000041A8620000102A2061A862400000003FC -:100EC000041A8630000102A3061A863400000003CB -:100ED000041A8640000102A4061A8644000000039A -:100EE000041A8650000102A5061A86540000000369 -:100EF000041A8660000102A6061A86640000000338 -:100F0000041A8670000102A7061A86740000000306 -:100F1000041A8680000102A8061A868400000003D5 -:100F2000041A8690000102A9061A869400000003A4 -:100F3000041A86A0000102AA061A86A40000000373 -:100F4000041A86B0000102AB061A86B40000000342 -:100F5000041A86C0000102AC061A86C40000000311 -:100F6000041A86D0000102AD061A86D400000003E0 -:100F7000041A86E0000102AE061A86E400000003AF -:100F8000041A86F0000102AF061A86F4000000037E -:100F9000041A8700000102B0061A8704000000034B -:100FA000041A8710000102B1061A8714000000031A -:100FB000041A8720000102B2061A872400000003E9 -:100FC000041A8730000102B3061A873400000003B8 -:100FD000041A8740000102B4061A87440000000387 -:100FE000041A8750000102B5061A87540000000356 -:100FF000041A8760000102B6061A87640000000325 -:10100000041A8770000102B7061A877400000003F3 -:10101000041A8780000102B8061A878400000003C2 -:10102000041A8790000102B9061A87940000000391 -:10103000041A87A0000102BA061A87A40000000360 -:10104000041A87B0000102BB061A87B4000000032F -:10105000041A87C0000102BC061A87C400000003FE -:10106000041A87D0000102BD061A87D400000003CD -:10107000041A87E0000102BE061A87E4000000039C -:10108000041A87F0000102BF061A87F4000000036B -:10109000041A8800000102C0061A88040000000338 -:1010A000041A8810000102C1061A88140000000307 -:1010B000041A8820000102C2061A882400000003D6 -:1010C000041A8830000102C3061A883400000003A5 -:1010D000041A8840000102C4061A88440000000374 -:1010E000041A8850000102C5061A88540000000343 -:1010F000041A8860000102C6061A88640000000312 -:10110000041A8870000102C7061A887400000003E0 -:10111000041A8880000102C8061A888400000003AF -:10112000041A8890000102C9061A8894000000037E -:10113000041A88A0000102CA061A88A4000000034D -:10114000041A88B0000102CB061A88B4000000031C -:10115000041A88C0000102CC061A88C400000003EB -:10116000041A88D0000102CD061A88D400000003BA -:10117000041A88E0000102CE061A88E40000000389 -:10118000041A88F0000102CF061A88F40000000358 -:10119000041A8900000102D0061A89040000000325 -:1011A000041A8910000102D1061A891400000003F4 -:1011B000041A8920000102D2061A892400000003C3 -:1011C000041A8930000102D3061A89340000000392 -:1011D000041A8940000102D4061A89440000000361 -:1011E000041A8950000102D5061A89540000000330 -:1011F000041A8960000102D6061A896400000003FF -:10120000041A8970000102D7061A897400000003CD -:10121000041A8980000102D8061A8984000000039C -:10122000041A8990000102D9061A8994000000036B -:10123000041A89A0000102DA061A89A4000000033A -:10124000041A89B0000102DB061A89B40000000309 -:10125000041A89C0000102DC061A89C400000003D8 -:10126000041A89D0000102DD061A89D400000003A7 -:10127000041A89E0000102DE061A89E40000000376 -:10128000041A89F0000102DF061A89F40000000345 -:10129000041A8A00000102E0061A8A040000000312 -:1012A000041A8A10000102E1061A8A1400000003E1 -:1012B000041A8A20000102E2061A8A2400000003B0 -:1012C000041A8A30000102E3061A8A34000000037F -:1012D000041A8A40000102E4061A8A44000000034E -:1012E000041A8A50000102E5061A8A54000000031D -:1012F000041A8A60000102E6061A8A6400000003EC -:10130000041A8A70000102E7061A8A7400000003BA -:10131000041A8A80000102E8061A8A840000000389 -:10132000041A8A90000102E9061A8A940000000358 -:10133000041A8AA0000102EA061A8AA40000000327 -:10134000041A8AB0000102EB061A8AB400000003F6 -:10135000041A8AC0000102EC061A8AC400000003C5 -:10136000041A8AD0000102ED061A8AD40000000394 -:10137000041A8AE0000102EE061A8AE40000000363 -:10138000041A8AF0000102EF061A8AF40000000332 -:10139000041A8B00000102F0061A8B0400000003FF -:1013A000041A8B10000102F1061A8B1400000003CE -:1013B000041A8B20000102F2061A8B24000000039D -:1013C000041A8B30000102F3061A8B34000000036C -:1013D000041A8B40000102F4061A8B44000000033B -:1013E000041A8B50000102F5061A8B54000000030A -:1013F000041A8B60000102F6061A8B6400000003D9 -:10140000041A8B70000102F7061A8B7400000003A7 -:10141000041A8B80000102F8061A8B840000000376 -:10142000041A8B90000102F9061A8B940000000345 -:10143000041A8BA0000102FA061A8BA40000000314 -:10144000041A8BB0000102FB061A8BB400000003E3 -:10145000041A8BC0000102FC061A8BC400000003B2 -:10146000041A8BD0000102FD061A8BD40000000381 -:10147000041A8BE0000102FE061A8BE40000000350 -:10148000041A8BF0000102FF061A8BF4000000031F -:10149000041A8C0000010300061A8C0400000003EB -:1014A000041A8C1000010301061A8C1400000003BA -:1014B000041A8C2000010302061A8C240000000389 -:1014C000041A8C3000010303061A8C340000000358 -:1014D000041A8C4000010304061A8C440000000327 -:1014E000041A8C5000010305061A8C5400000003F6 -:1014F000041A8C6000010306061A8C6400000003C5 -:10150000041A8C7000010307061A8C740000000393 -:10151000041A8C8000010308061A8C840000000362 -:10152000041A8C9000010309061A8C940000000331 -:10153000041A8CA00001030A061A8CA40000000300 -:10154000041A8CB00001030B061A8CB400000003CF -:10155000041A8CC00001030C061A8CC4000000039E -:10156000041A8CD00001030D061A8CD4000000036D -:10157000041A8CE00001030E061A8CE4000000033C -:10158000041A8CF00001030F061A8CF4000000030B -:10159000041A8D0000010310061A8D0400000003D8 -:1015A000041A8D1000010311061A8D1400000003A7 -:1015B000041A8D2000010312061A8D240000000376 -:1015C000041A8D3000010313061A8D340000000345 -:1015D000041A8D4000010314061A8D440000000314 -:1015E000041A8D5000010315061A8D5400000003E3 -:1015F000041A8D6000010316061A8D6400000003B2 -:10160000041A8D7000010317061A8D740000000380 -:10161000041A8D8000010318061A8D84000000034F -:10162000041A8D9000010319061A8D94000000031E -:10163000041A8DA00001031A061A8DA400000003ED -:10164000041A8DB00001031B061A8DB400000003BC -:10165000041A8DC00001031C061A8DC4000000038B -:10166000041A8DD00001031D061A8DD4000000035A -:10167000041A8DE00001031E061A8DE40000000329 -:10168000041A8DF00001031F061A8DF400000003F8 -:10169000041A8E0000010320061A8E0400000003C5 -:1016A000041A8E1000010321061A8E140000000394 -:1016B000041A8E2000010322061A8E240000000363 -:1016C000041A8E3000010323061A8E340000000332 -:1016D000041A8E4000010324061A8E440000000301 -:1016E000041A8E5000010325061A8E5400000003D0 -:1016F000041A8E6000010326061A8E64000000039F -:10170000041A8E7000010327061A8E74000000036D -:10171000041A8E8000010328061A8E84000000033C -:10172000041A8E9000010329061A8E94000000030B -:10173000041A8EA00001032A061A8EA400000003DA -:10174000041A8EB00001032B061A8EB400000003A9 -:10175000041A8EC00001032C061A8EC40000000378 -:10176000041A8ED00001032D061A8ED40000000347 -:10177000041A8EE00001032E061A8EE40000000316 -:10178000041A8EF00001032F061A8EF400000003E5 -:10179000041A8F0000010330061A8F0400000003B2 -:1017A000041A8F1000010331061A8F140000000381 -:1017B000041A8F2000010332061A8F240000000350 -:1017C000041A8F3000010333061A8F34000000031F -:1017D000041A8F4000010334061A8F4400000003EE -:1017E000041A8F5000010335061A8F5400000003BD -:1017F000041A8F6000010336061A8F64000000038C -:10180000041A8F7000010337061A8F74000000035A -:10181000041A8F8000010338061A8F840000000329 -:10182000041A8F9000010339061A8F9400000003F8 -:10183000041A8FA00001033A061A8FA400000003C7 -:10184000041A8FB00001033B061A8FB40000000396 -:10185000041A8FC00001033C061A8FC40000000365 -:10186000041A8FD00001033D061A8FD40000000334 -:10187000041A8FE00001033E061A8FE400000007FF -:10188000041A62C00020033F061AD0000000007254 -:10189000061AD24800000010061AD6B00000002038 -:1018A000061AD47000000090061AD46800000002E6 -:1018B000061AA000000001C4061A30000000001043 -:1018C000061A308000000010061A310000000010D7 -:1018D000061A318000000010061A330000000012C2 -:1018E000061A339000000070061AD4580000000257 -:1018F000061AD34800000002061AD3580000002040 -:10190000061AA710000001C4061A3040000000109B -:10191000061A30C000000010061A31400000001006 -:10192000061A31C000000010061A334800000012E9 -:10193000061A355000000070061AD460000000023C -:10194000061AD35000000002061AD3D80000002067 -:10195000021AAE2000000000061A5000000000022B -:10196000061A508000000012041A40000002035FB3 -:10197000041A63C000020361061A7000000000042C -:10198000061A320000000008021AAE24000000000F -:10199000061A501000000002061A50C8000000127B -:1019A000041A400800020363041A63C800020365B6 -:1019B000061A701000000004061A32200000000809 -:1019C000021AAE2800000000061A50200000000293 -:1019D000061A511000000012041A4010000203679A -:1019E000041A63D000020369061A70200000000484 -:1019F000061A324000000008021AAE2C0000000057 -:101A0000061A503000000002061A51580000001259 -:101A1000041A40180002036B041A63D80002036D15 -:101A2000061A703000000004061A32600000000838 -:101A3000021AAE3000000000061A504000000002FA -:101A4000061A51A000000012041A40200002036F81 -:101A5000041A63E000020371061A704000000004DB -:101A6000061A328000000008021AAE34000000009E -:101A7000061A505000000002061A51E80000001239 -:101A8000041A402800020373041A63E80002037575 -:101A9000061A705000000004061A32A00000000868 -:101AA000021AAE3800000000061A50600000000262 -:101AB000061A523000000012041A40300002037768 -:101AC000041A63F000020379061A70600000000433 -:101AD000061A32C000000008021AAE3C00000000E6 -:101AE000061A507000000002061A52780000001218 -:101AF000041A40380002037B041A63F80002037DD5 -:101B0000061A707000000004061A32E00000000897 -:101B10000200A468000B01C80200A294071D29114D -:101B20000200A298000000000200A29C009C042475 -:101B30000200A2A0000000000200A2A4000002090E -:101B40000200A270000000000200A2740000000069 -:101B50000200A270000000000200A2740000000059 -:101B60000200A270000000000200A2740000000049 -:101B70000200A270000000000200A2740000000039 -:101B8000020160A000000001020160A400000262E6 -:101B9000020160A800000002020160AC0000001811 -:101BA0000201620400000001020100B40000000113 -:101BB000020100B800000001020100DC0000000189 -:101BC0000201010000000001020101040000000107 -:101BD0000201007C003000000201008400000028A7 -:101BE0000201008C0000000002010130000000042E -:101BF0000201025C00000001020103280000000055 -:101C0000020160580000FFFF020160700000000741 -:101C10000201608000000001020105540000003054 -:101C2000020100C400000001020100CC000000011C -:101C3000020100F800000001020100F000000001B4 -:101C4000020100800030000002010088000000282E -:101C500002010090000000000201013400000004B5 -:101C6000020102DC000000010201032C0000000060 -:101C70000201605C0000FFFF0201607400000007C9 -:101C800002016084000000010201056400000030D0 -:101C9000020100C800000001020100D000000001A4 -:101CA000020100FC00000001020100F4000000013C -:101CB000020C100000000028020C20080000021195 -:101CC000020C200C00000200020C20100000020494 -:101CD000020C201C0000FFFF020C20200000FFFF70 -:101CE000020C20240000FFFF020C20280000FFFF50 -:101CF000020C203800000020020C203C00000021D3 -:101D0000020C204000000022020C204400000023AE -:101D1000020C204800000024020C204C000000258A -:101D2000020C205000000026020C20540000002766 -:101D3000020C205800000028020C205C0000002942 -:101D4000020C20600000002A020C20640000002B1E -:101D5000020C20680000002C020C206C0000002DFA -:101D6000020C20700000002E020C20740000002FD6 -:101D7000020C207800000010060C207C00000007F8 -:101D8000020C209800000011020C209C00000012A0 -:101D9000020C20A000000013060C20A40000001D6F -:101DA000020C211800000001020C211C000000019F -:101DB000020C212000000001060C21240000001D5F -:101DC000020C219800000001060C219C0000000775 -:101DD000020C21B800000001020C21BC000000012F -:101DE000020C21C000000001020C21C4000000010F -:101DF000020C21C800000001020C21CC00000001EF -:101E0000020C21D000000001020C21D400000001CE -:101E1000020C21D800000001020C21DC00000001AE -:101E2000020C21E000000001020C21E4000000018E -:101E3000020C21E800000001020C21EC000000016E -:101E4000020C21F000000001020C21F4000000014E -:101E5000020C21F800000001060C21FC0000000724 -:101E6000020C221800000001060C221C00000007D2 -:101E7000020C223807FFFFFF020C223C0000003F4B -:101E8000020C224007FFFFFF020C22440000000F5B -:101E9000010C224800000000010C224C0000000050 -:101EA000010C225000000000010C22540000000030 -:101EB000010C225800000000010C225C0000000010 -:101EC000010C226000000000010C226400000000F0 -:101ED000010C226800000000010C226C00000000D0 -:101EE000010C227000000000010C227400000000B0 -:101EF000010C227800000000010C227C0000000090 -:101F00000C0C2000000003E80A0C20000000000177 -:101F10000B0C20000000000A020C40080000101109 -:101F2000020C400C00001000020C401000001004D5 -:101F3000020C401400001021020C401C0000FFFFA6 -:101F4000020C40200000FFFF020C40240000FFFFB5 -:101F5000020C40280000FFFF020C40380000004641 -:101F6000020C403C00000010060C40400000000243 -:101F7000020C404800000018020C404C000000F029 -:101F8000060C40500000001F020C40CC0000000175 -:101F9000060C40D00000003A020C41B800000001DD -:101FA000060C41BC00000003020C41C80000000107 -:101FB000020C41CC00000001060C41D00000001AC8 -:101FC000020C423807FFFFFF020C423C0000003FBA -:101FD000020C424007FFFFFF020C42440000000FCA -:101FE000010C424800000000010C424C00000000BF -:101FF000010C425000000000010C4254000000009F -:10200000010C425800000000010C425C000000007E -:10201000010C426000000000010C4264000000005E -:10202000010C426800000000010C426C000000003E -:10203000010C427000000000010C4274000000001E -:10204000010C427800000000010C427C00000000FE -:10205000010C4280000000000C0C4000000003E86E -:102060000A0C4000000000010B0C40000000000AB8 -:10207000060D400000000A00020D0044000000327E -:10208000020D008C02150020020D009002150020A8 -:10209000020D009408100000020D009800000033AB -:1020A000020D009C00000002020D00A000000000D4 -:1020B000020D00A400000005020D00A800000005AC -:1020C000060D00AC00000002020D00B4000000028A -:1020D000020D00B800000003020D00BC0000000269 -:1020E000020D00C000000001020D00C80000000247 -:1020F000020D00CC00000002020D015C0000000196 -:10210000020D016400000001020D016800000002E0 -:10211000020D020400000001020D020C000000206C -:10212000020D021000000040020D021400000040E9 -:10213000020D022000000003020D0224000000181E -:10214000060D028000000012040D03000018037F3A -:10215000060D03600000000C020D004C00000001A1 -:10216000020D005000000002020D005400000000AB -:10217000020D005800000008060D005C000000047D -:10218000020D00C400000004020D00040000000164 -:10219000020D000800000001020D000C000000010B -:1021A000020D001000000001020D001400000001EB -:1021B000020D001800000001020D001C00000001CB -:1021C000020D002000000001020D002400000001AB -:1021D000020D002800000001020D002C000000018B -:1021E000020D003000000001020D0034000000016B -:1021F000020D003800000001020D003C000000014B -:10220000020D011400000009020D011C0000000A6B -:10221000020D012400000000020D012C000000004E -:10222000020D013400000000020D013C0000000B13 -:10223000020D014400000000020D011800000029F9 -:10224000020D01200000002A020D012800000020DC -:10225000020D013000000020020D013800000020B6 -:10226000020D01400000002B020D0148000000207B -:10227000020D011400000019020D011C0000001ADB -:10228000020D012400000010020D012C00000010BE -:10229000020D013400000010020D013C0000001B83 -:1022A000020D014400000010020D01180000003969 -:1022B000020D01200000003A020D0128000000304C -:1022C000020D013000000030020D01380000003026 -:1022D000020D01400000003B020D014800000030EB -:1022E000020D011400000049020D011C0000004A0B -:1022F000020D012400000040020D012C00000040EE -:10230000020D013400000040020D013C0000004BB2 -:10231000020D014400000040020D01180000006998 -:10232000020D01200000006A020D0128000000607B -:10233000020D013000000060020D01380000006055 -:10234000020D01400000006B020D0148000000601A -:10235000020D011400000059020D011C0000005A7A -:10236000020D012400000050020D012C000000505D -:10237000020D013400000050020D013C0000005B22 -:10238000020D014400000050020D01180000007908 -:10239000020D01200000007A020D012800000070EB -:1023A000020D013000000070020D013800000070C5 -:1023B000020D01400000007B020D0148000000708A -:1023C000060E200000000800020E004C0000003243 -:1023D000020E009402150020020E00980215002043 -:1023E000020E009C00000030020E00A00810000049 -:1023F000020E00A400000033020E00A8000000300E -:10240000020E00AC00000031020E00B0000000021D -:10241000020E00B400000004020E00B8000000002C -:10242000020E00BC00000002020E00C0000000020C -:10243000020E00C400000000020E00C800000002EE -:10244000020E00CC00000007020E00D000000002C7 -:10245000020E00D400000002020E00D800000001AD -:10246000020E014400000001020E014C00000001B8 -:10247000020E015000000002020E020400000001E2 -:10248000020E020C00000040020E0210000000408C -:10249000020E021C00000004020E022000000020B8 -:1024A000020E02240000000E020E02280000001B93 -:1024B000060E030000000012040E0280001B0397AA -:1024C000060E02EC00000005020E00540000000C95 -:1024D000020E00580000000C020E005C000000001C -:1024E000020E006000000010020E006400000010E8 -:1024F000060E006800000003020E00DC000000036E -:10250000020E000400000001020E0008000000019D -:10251000020E000C00000001020E0010000000017D -:10252000020E001400000001020E0018000000015D -:10253000020E001C00000001020E0020000000013D -:10254000020E002400000001020E0028000000011D -:10255000020E002C00000001020E003000000001FD -:10256000020E003400000001020E003800000001DD -:10257000020E003C00000001020E004000000001BD -:10258000020E004400000001020E01100000000FC6 -:10259000020E011800000000020E012000000000E1 -:1025A000020E012800000000020E01140000002F9E -:1025B000020E011C00000020020E01240000000099 -:1025C000020E012C00000000020E01100000001F8E -:1025D000020E011800000010020E01200000000091 -:1025E000020E012800000000020E01140000003F4E -:1025F000020E011C00000030020E01240000000049 -:10260000020E012C00000000020E01100000004F1D -:10261000020E011800000040020E01200000000020 -:10262000020E012800000000020E01140000006FDD -:10263000020E011C00000060020E012400000000D8 -:10264000020E012C00000000020E01100000005FCD -:10265000020E011800000050020E012000000000D0 -:10266000020E012800000000020E01140000007F8D -:10267000020E011C00000070020E01240000000088 -:10268000020E012C000000000730040000C9000009 -:10269000083007D8000503B20734000033320000C9 -:1026A0000734800030A70CCD07350000353518F70A -:1026B000073580002A6226450736000018D330DE31 -:1026C00008364660373403B40130000000000000D3 -:1026D000013000040000000001300008000000008C -:1026E0000130000C0000000001300010000000006C -:1026F0000130001400000000023000200000000142 -:102700000230002400000002023000280000000314 -:102710000230002C000000000230003000000004F5 -:1027200002300034000000010230003800000000D8 -:102730000230003C000000010230004000000004B4 -:102740000230004400000000023000480000000198 -:102750000230004C00000003023000500000000076 -:102760000230005400000001023000580000000454 -:102770000230005C00000000023000600000000138 -:102780000230006400000003023000680000000016 -:102790000230006C000000010230007000000004F4 -:1027A00002300074000000000230007800000004D5 -:1027B0000230007C000000030630008000000002B0 -:1027C000023000A400003FFF023000A8000003FF19 -:1027D0000230022400000000023002340000000039 -:1027E0000230024C00000000023002E40000FFFF53 -:1027F000063020000000080002338BC000000001FA -:10280000023380000000001A023380400000004EB6 -:102810000233808000000010023380C000000020DE -:102820000C3383000007A1200A3383000000013825 -:102830000B338300000013880A338340000000003C -:102840000C338340000001F40B338340000000058B -:10285000023383800007A120023383C0000001F40B -:1028600002331480000000010A33148000000000CD -:10287000063280000000010206322008000000C875 -:10288000063220000000000204328EA0001003B6C1 -:1028900006323EB00000000606323ED800000002BC -:1028A00006323E800000000A04323EA8000203C641 -:1028B00006323E00000000200632500000000400F6 -:1028C0000632400000000004043274C0000203C855 -:1028D00006324110000000020632D0000000003035 -:1028E0000632DD40000000440632DA00000000D06D -:1028F0000632DEA0000000020632E0000000080000 -:1029000006328450000001180632100000000188D1 -:102910000632500000000020063251000000002066 -:102920000632520000000020063253000000002052 -:10293000063254000000002006325500000000203E -:10294000063256000000002006325700000000202A -:102950000632580000000020063259000000002016 -:1029600006325A000000002006325B000000002002 -:1029700006325C000000002006325D0000000020EE -:1029800006325E000000002006325F0000000020DA -:1029900006328DF00000000204328E00000203CAED -:1029A00006328E08000000020632DE9000000002AF -:1029B00006321C4000000038063288B000000118C2 -:1029C00006321620000001880632508000000020E8 -:1029D00006325180000000200632528000000020A4 -:1029E0000632538000000020063254800000002090 -:1029F000063255800000002006325680000000207C -:102A00000632578000000020063258800000002067 -:102A1000063259800000002006325A800000002053 -:102A200006325B800000002006325C80000000203F -:102A300006325D800000002006325E80000000202B -:102A400006325F800000002006328DF80000000290 -:102A500004328E10000203CC06328E1800000002F1 -:102A60000632DE980000000206321D200000003809 -:102A700002328D50000000000632401000000002BB -:102A800002328D5400000000063240200000000297 -:102A900002328D5800000000063240300000000273 -:102AA00002328D5C0000000006324040000000024F -:102AB00002328D600000000006324050000000022B -:102AC00002328D6400000000063240600000000207 -:102AD00002328D68000000000632407000000002E3 -:102AE00002328D6C000000000632408000000002BF -:102AF000072004000091000008200780001003CE8A -:102B0000072400002AF300000724800015090ABDED -:102B10000824A9F0692803D001200000000000006B -:102B20000120000400000000012000080000000057 -:102B30000120000C00000000012000100000000037 -:102B4000012000140000000002200020000000010D -:102B500002200024000000020220002800000003E0 -:102B60000220002C000000000220003000000004C1 -:102B700002200034000000010220003800000000A4 -:102B80000220003C00000001022000400000000480 -:102B90000220004400000000022000480000000164 -:102BA0000220004C00000003022000500000000042 -:102BB0000220005400000001022000580000000420 -:102BC0000220005C00000000022000600000000104 -:102BD00002200064000000030220006800000000E2 -:102BE0000220006C000000010220007000000004C0 -:102BF00002200074000000000220007800000004A1 -:102C00000220007C0000000306200080000000027B -:102C1000022000A400003FFF022000A8000003FFE4 -:102C20000220022400000000022002340000000004 -:102C30000220024C00000000022002E40000FFFF1E -:102C4000062020000000080002238BC000000001C5 -:102C500002238000000000100223804000000012C8 -:102C60000223808000000030022380C00000000E9C -:102C70000C2383000007A1200A23830000000138F1 -:102C80000B238300000013880A2383400000000008 -:102C90000C238340000001F40B2383400000000557 -:102CA000022383800007A120022383C0000001F4D7 -:102CB00002231480000000010A2314800000000099 -:102CC000062210000000004206222008000000C872 -:102CD00006222000000000020622B000000000C60C -:102CE0000422B318000503D20622B32C0000000B07 -:102CF0000422B358000503D70622B36C0000000B72 -:102D00000422B398000503DC0622B3AC0000000BDC -:102D10000422B3D8000503E10622B3EC0000000B47 -:102D20000422B418000503E60622B42C0000000BB0 -:102D30000422B458000503EB0622B46C0000000B1B -:102D40000422B498000503F00622B4AC0000000B86 -:102D50000422B4D8000503F50622B4EC0000000BF1 -:102D60000422B518000503FA0622B52C0000000B5A -:102D70000422B558000503FF0622B56C0000000BC5 -:102D80000422B598000504040622B5AC0000000B2F -:102D90000422B5D8000504090622B5EC0000000B9A -:102DA0000422B6180005040E0622B62C0000000B03 -:102DB0000422B658000504130622B66C0000000B6E -:102DC0000422B698000504180622B6AC0000000BD9 -:102DD0000422B6D80005041D0622B6EC0000000B44 -:102DE0000422B718000504220622B72C0000000BAD -:102DF0000422B758000504270622B76C0000000B18 -:102E00000422B7980005042C0622B7AC0000000B82 -:102E10000422B7D8000504310622B7EC0000000BED -:102E20000422B818000504360622B82C0000000B56 -:102E30000422B8580005043B0622B86C0000000BC1 -:102E40000422B898000504400622B8AC0000000B2C -:102E50000422B8D8000504450622B8EC0000000B97 -:102E60000422B9180005044A0622B92C0000000B00 -:102E70000422B9580005044F0622B96C0000000B6B -:102E80000422B998000504540622B9AC0000000BD6 -:102E90000422B9D8000504590622B9EC0000000B41 -:102EA0000422BA180005045E0622BA2C0000000BAA -:102EB0000422BA58000504630622BA6C0000000B15 -:102EC0000422BA98000504680622BAAC0000000B80 -:102ED0000422BAD80005046D0622BAEC00000005F1 -:102EE0000622BB00000000530422BC4C0001047207 -:102EF0000622BC50000000030422BC5C00010473E5 -:102F00000622BC60000000030422BC6C00010474B3 -:102F10000622BC70000000030422BC7C0001047582 -:102F20000622BC80000000030422BC8C0001047651 -:102F30000622BC90000000030422BC9C0001047720 -:102F40000622BCA0000000030422BCAC00010478EF -:102F50000622BCB0000000030422BCBC00010479BE -:102F60000622880000000100062280000000020006 -:102F7000042212700010047A06223000000000C003 -:102F800006226700000001000622900000000400F5 -:102F900004226B080020048A022212C0FFFFFFFFF8 -:102FA000062211E800000002062212C800000009F3 -:102FB000062212EC0000000906228C000000000826 -:102FC0000222114800000000062213200000000623 -:102FD000062233000000000206226040000000309C -:102FE00006228C20000000080222114C0000000084 -:102FF00006221338000000060622330800000002F3 -:10300000062261000000003006228C40000000080B -:10301000022211500000000006221350000000069A -:103020000622331000000002062261C000000030BA -:1030300006228C60000000080222115400000000EB -:103040000622136800000006062233180000000262 -:10305000062262800000003006228C8000000008FA -:103060000222115800000000062213800000000612 -:1030700006223320000000020622634000000030D8 -:1030800006228CA0000000080222115C0000000053 -:1030900006221398000000060622332800000002D2 -:1030A000062264000000003006228CC000000008E8 -:1030B0000222116000000000062213B0000000068A -:1030C0000622333000000002062264C000000030F7 -:1030D00006228CE0000000080222116400000000BB -:1030E000062213C800000006062233380000000242 -:1030F0000622658000000030021610000000002843 -:1031000002170008000000020217002C0000000354 -:103110000217003C000000040217004800000002F3 -:103120000217004C000000900217005000000090B1 -:103130000217005400800090021700580810000089 -:10314000021700600000008A02170064000000807F -:1031500002170068000000810217006C0000008068 -:10316000021700700000000602170078000007D068 -:103170000217007C0000076C02170038007C100466 -:10318000021700040000000F061640240000000291 -:10319000021640700000001C0216420800000001E8 -:1031A0000216421000000001021642200000000139 -:1031B0000216422800000001021642300000000101 -:1031C00002164238000000010216426000000002B0 -:1031D0000C16401C0003D0900A16401C0000009CF6 -:1031E0000B16401C000009C4021640300000000805 -:1031F000021640340000000C021640380000001097 -:1032000002164044000000200216400000000001A9 -:10321000021640D80000000102164008000000011C -:103220000216400C000000010216401000000001D0 -:103230000216424000000000021642480000000052 -:103240000616427000000002021642500000000004 -:1032500002164258000000000616428000000002DC -:1032600002166008000012240216600C0000121002 -:1032700002166010000012140216601C0000FFFF0E -:10328000021660200000FFFF021660240000FFFF0E -:10329000021660280000FFFF0216603800000020C0 -:1032A0000216603C0000002006166040000000028C -:1032B00002166048000000230216604C0000002443 -:1032C000021660500000002502166054000000261F -:1032D00002166058000000270216605C00000029FA -:1032E000021660600000002A021660640000002BD5 -:1032F000021660680000002C0216606C0000002DB1 -:1033000002166070000000EC0216607400000011EC -:1033100002166078000000120616607C0000000FA4 -:10332000021660B800000001021660BC0000000137 -:10333000061660C00000000C021660F000000001DC -:10334000061660F400000031021661B800000001AA -:10335000061661BC0000000D021661F000000001BD -:10336000061661F4000000110216623807FFFFFF25 -:103370000216623C0000003F0216624007FFFFFF9A -:10338000021662440000000F0116624800000000AF -:103390000116624C0000000001166250000000009F -:1033A000011662540000000001166258000000007F -:1033B0000116625C0000000001166260000000005F -:1033C000011662640000000001166268000000003F -:1033D0000116626C0000000001166270000000001F -:1033E00001166274000000000116627800000000FF -:1033F0000116627C000000000C166000000003E86B -:103400000A166000000000010B1660000000000AB0 -:1034100002168040000000060216804400000005ED -:10342000021680480000000A0216804C00000005C9 -:103430000216805400000002021680CC0000000436 -:10344000021680D000000004021680D400000004A0 -:10345000021680D800000004021680DC0000000480 -:10346000021680E000000004021680E40000000460 -:10347000021680E800000004021688040000000420 -:10348000021680300000007C021680340000003DEF -:10349000021680380000003F0216803C0000009CAD -:1034A000021680F000000007061680F400000005F8 -:1034B0000216880C010101010216810800000000BB -:1034C0000216810C000000040216811000000004A6 -:1034D0000216811400000002021688100801200460 -:1034E00002168118000000050216811C000000056C -:1034F000021681200000000502168124000000054C -:103500000216882C200810010216812800000008ED -:103510000216812C00000006021681300000000710 -:1035200002168134000000000216883001010120DB -:1035300006168138000000040216883401010101DA -:1035400002168148000000000216814C00000004B1 -:10355000021681500000000402168154000000028F -:103560000216883808012004021681580000000560 -:103570000216815C00000005021681600000000553 -:1035800002168164000000050216883C2008100124 -:1035900002168168000000080216816C0000000617 -:1035A00002168170000000070216817400000001FD -:1035B00002168840010101200216817800000001F6 -:1035C0000216817C000000010216818000000001CB -:1035D00002168184000000010216884401010101E5 -:1035E00002168188000000010216818C0000000490 -:1035F000021681900000000402168194000000026F -:10360000021688480801200402168198000000056F -:103610000216819C00000005021681A00000000532 -:10362000021681A40000000502168814200810016B -:10363000021681A800000008021681AC00000006F6 -:10364000021681B000000007021681B400000001DC -:103650000216881801010120021681B8000000013D -:10366000021681BC00000001021681C000000001AA -:10367000021681C4000000010216881C010101012C -:10368000021681C800000001021681CC000000046F -:10369000021681D000000004021681D4000000024E -:1036A0000216882008012004021681D800000005B7 -:1036B000021681DC00000005021681E00000000512 -:1036C000021681E40000000502168824200810017B -:1036D000021681E800000008021681EC00000006D6 -:1036E000021681F0000000070216E40C0000000042 -:1036F00002168828010101200616E41000000004CB -:103700000216E000010101010216E42000000000A1 -:103710000216E424000000040216E428000000045D -:103720000216E42C000000020216E0040801200446 -:103730000216E430000000050216E4340000000523 -:103740000216E438000000050216E43C0000000503 -:103750000216E008200810010216E44000000008EC -:103760000216E444000000060216E44800000007C8 -:103770000216E44C000000000216E00C01010120DA -:103780000616E450000000040216E01001010101D9 -:103790000216E460000000000216E4640000000469 -:1037A0000216E468000000040216E46C0000000247 -:1037B0000216E014080120040216E470000000055F -:1037C0000216E474000000050216E478000000050B -:1037D0000216E47C000000050216E0182008100123 -:1037E0000216E480000000080216E48400000006CF -:1037F0000216E488000000070216E48C00000001B5 -:103800000216E01C010101200216E49000000001F4 -:103810000216E494000000010216E4980000000182 -:103820000216E49C000000010216E02001010101E3 -:103830000216E4A0000000010216E4A40000000447 -:103840000216E4A8000000040216E4AC0000000226 -:103850000216E024080120040216E4B0000000056E -:103860000216E4B4000000050216E4B800000005EA -:103870000216E4BC000000050216E0282008100132 -:103880000216E4C0000000080216E4C400000006AE -:103890000216E4C8000000070216E4CC0000000194 -:1038A0000216E02C010101200216E4D00000000104 -:1038B0000216E4D4000000010216E4D80000000162 -:1038C0000216E4DC000000010216E03001010101F3 -:1038D0000216E4E0000000010216E4E40000000427 -:1038E0000216E4E8000000040216E4EC0000000206 -:1038F0000216E034080120040216E4F0000000057E -:103900000216E4F4000000050216E4F800000005C9 -:103910000216E4FC000000050216E0382008100141 -:103920000216E500000000080216E504000000068B -:103930000216E508000000070216E03C0101012024 -:1039400002168240003F003F021682440000000041 -:103950000216E524003F003F0216E52800000000A3 -:1039600002168248000000000216824C003F003F11 -:103970000216E52C000000000216E530003F003F73 -:10398000021682500100010002168254010001005B -:103990000216E534010001000216E53801000100BD -:1039A00006168258000000020216E53C00000000E6 -:1039B0000216E540000000000216826000C000C050 -:1039C0000216826400C000C00216E54400C000C0B8 -:1039D0000216E54800C000C0021682681E001E00E4 -:1039E0000216826C1E001E000216E54C1E001E0010 -:1039F0000216E5501E001E000216827040004000B4 -:103A000002168274400040000216E5544000400057 -:103A10000216E558400040000216827880008000BF -:103A20000216827C800080000216E55C8000800027 -:103A30000216E560800080000216828020002000CF -:103A400002168284200020000216E5642000200077 -:103A50000216E56820002000061682880000000299 -:103A60000216E56C000000000216E5700000000080 -:103A700002168290000000000216829400000000EE -:103A80000216E574000000000216E5780000000050 -:103A900002168298000000000216829C00000000BE -:103AA0000216E57C000000000216E5800000000020 -:103AB000021682A000000000021682A4000000018D -:103AC000061682A80000000A021681F400000C0805 -:103AD000021681F800000040021681FC000001007F -:103AE0000216820000000020021682040000001767 -:103AF00002168208000000800216820C00000200FC -:103B000002168210000000000216821801FF01FF59 -:103B10000216821401FF01FF0216E51001FF01FFEA -:103B20000216E50C01FF01FF0216823C00000013A3 -:103B3000021680900000013F0216806000000140E4 -:103B40000216806400000140061680680000000232 -:103B500002168070000000C0061680740000000786 -:103B60000216809C00000048021680A00000004859 -:103B7000061680A400000002021680AC0000004877 -:103B8000061680B000000007021682380000800090 -:103B900002168234000025E40216809400007FFFA4 -:103BA00002168220000F000F0216821C000F000F69 -:103BB0000216E518000F000F0216E514000F000FA3 -:103BC000021682280000000002168224FFFFFFFF79 -:103BD0000216E520000000000216E51CFFFFFFFFB3 -:103BE0000216E6BC000000000216E6C0000000025B -:103BF0000216E6C4000000010216E6C80000000339 -:103C00000216E6CC000000040216E6D00000000612 -:103C10000216E6D4000000050216E6D800000007F0 -:103C2000021680EC000000FF0214000000000001FA -:103C30000214000C0000000102140040000000010A -:103C40000214004400007FFF0214000C000000007A -:103C500002140000000000000214006C00000000CC -:103C600002140004000000010214003000000001F2 -:103C700002140004000000000214005C00000000B8 -:103C800002140008000000010214003400000001CA -:103C90000214000800000000021400600000000090 -:103CA00006028000000020000202005800000032DE -:103CB000020200A003150020020200A40315002048 -:103CC000020200A801000030020200AC081000004F -:103CD000020200B000000033020200B40000003015 -:103CE000020200B800000031020200BC0000000324 -:103CF000020200C000000006020200C4000000032F -:103D0000020200C800000003020200CC0000000212 -:103D1000020200D000000000020200D400000002F5 -:103D2000020200DC00000000020200E000000006C9 -:103D3000020200E400000004020200E800000002A9 -:103D4000020200EC00000002020200F0000000018C -:103D5000020200FC00000006020201200000000038 -:103D60000202013400000002020201B00000000162 -:103D70000202020C00000001020202140000000115 -:103D80000202021800000002020204040000000106 -:103D90000202040C00000040020204100000004077 -:103DA0000202041C000000040202042000000020A3 -:103DB0000202042400000002020204280000002085 -:103DC000060205000000001204020480002004AA7C -:103DD000020200600000000F020200640000000701 -:103DE00002020068000000000202006C0000000EE9 -:103DF000020200700000000E0602007400000003C2 -:103E0000020200F4000000040202000400000001AD -:103E100002020008000000010202000C0000000184 -:103E20000202001000000001020200140000000164 -:103E300002020018000000010202001C0000000144 -:103E40000202002000000001020200240000000124 -:103E500002020028000000010202002C0000000104 -:103E600002020030000000010202003400000001E4 -:103E700002020038000000010202003C00000001C4 -:103E800002020040000000010202004400000001A4 -:103E900002020048000000010202004C0000000184 -:103EA000020200500000000102020108000000C8E8 -:103EB0000202011800000002020201C4000000001A -:103EC000020201CC00000000020201D40000000246 -:103ED000020201DC00000002020201E4000000FF17 -:103EE000020201EC000000FF0202010000000000DD -:103EF0000202010C000000C80202011C00000002C6 -:103F0000020201C800000000020201D0000000000F -:103F1000020201D800000002020201E000000002DB -:103F2000020201E8000000FF020201F0000000FFB1 -:103F3000020201040000000002020108000000C8A3 -:103F40000202011800000002020201C40000000089 -:103F5000020201CC00000000020201D400000002B5 -:103F6000020201DC00000002020201E4000000FF86 -:103F7000020201EC000000FF02020100000000004C -:103F80000202010C000000C80202011C0000000235 -:103F9000020201C800000000020201D0000000007F -:103FA000020201D800000002020201E0000000024B -:103FB000020201E8000000FF020201F0000000FF21 -:103FC000020201040000000002020108000000C813 -:103FD0000202011800000002020201C400000000F9 -:103FE000020201CC00000000020201D40000000225 -:103FF000020201DC00000002020201E4000000FFF6 -:10400000020201EC000000FF0202010000000000BB -:104010000202010C000000C80202011C00000002A4 -:10402000020201C800000000020201D000000000EE -:10403000020201D800000002020201E000000002BA -:10404000020201E8000000FF020201F0000000FF90 -:10405000020201040000000002020108000000C882 -:104060000202011800000002020201C40000000068 -:10407000020201CC00000000020201D40000000294 -:10408000020201DC00000002020201E4000000FF65 -:10409000020201EC000000FF02020100000000002B -:1040A0000202010C000000C80202011C0000000214 -:1040B000020201C800000000020201D0000000005E -:1040C000020201D800000002020201E0000000022A -:1040D000020201E8000000FF020201F0000000FF00 -:1040E00002020104000000000728040000A00000F4 -:1040F000082807B8000904CA072C000034DA0000B9 -:10410000072C800038F80D37072D000037B91B76D3 -:10411000072D800031782965072E00001C7A35C4F0 -:10412000082E48E036E404CC01280000000000001E -:104130000128000400000000012800080000000021 -:104140000128000C00000000012800100000000001 -:1041500001280014000000000228002000000001D7 -:1041600002280024000000020228002800000003AA -:104170000228002C0000000002280030000000048B -:10418000022800340000000102280038000000006E -:104190000228003C0000000102280040000000044A -:1041A000022800440000000002280048000000012E -:1041B0000228004C0000000302280050000000000C -:1041C00002280054000000010228005800000004EA -:1041D0000228005C000000000228006000000001CE -:1041E00002280064000000030228006800000000AC -:1041F0000228006C0000000102280070000000048A -:10420000022800740000000002280078000000046A -:104210000228007C00000003062800800000000245 -:10422000022800A400003FFF022800A8000003FFAE -:1042300002280224000000000228023400000000CE -:104240000228024C00000000022802E40000FFFFE8 -:104250000628200000000800022B8BC0000000018F -:10426000022B800000000000022B8040000000189C -:10427000022B80800000000C022B80C00000006632 -:104280000C2B83000007A1200A2B830000000138BB -:104290000B2B8300000013880A2B834000000000D2 -:1042A0000C2B8340000001F40B2B83400000000521 -:1042B000022B83800007A120022B83C0000001F4A1 -:1042C000022B1480000000010A2B14800000000063 -:1042D000062A9AF800000004042A9B08000204CE73 -:1042E000062A9B1000000006062A90800000004865 -:1042F000062A2008000000C8062A2000000000024C -:10430000062A91A800000086062A900000000020DE -:10431000062A93C800000003042A93D4000104D0A5 -:10432000062A9DA800000002042A9498000404D1E3 -:10433000042A9D58000104D5062A9D5C0000001146 -:10434000042ACB20001004D6042A3000000204E620 -:10435000062A300800000100062A40400000001034 -:10436000042A4000001004E8042A8408000204F82B -:10437000062A9DA000000002062AB000000000509E -:10438000062ABB7000000070062AB150000000022F -:10439000062ABB6000000004062AD00000000800C6 -:1043A000062AC00000000150062A94A8000000322E -:1043B000062A502000000002062A503000000002A9 -:1043C000062A500000000002062A501000000002D9 -:1043D000022A520800000001042A9B28000204FA65 -:1043E000062A963800000022042A96C0000104FC28 -:1043F000062A96C400000003062A976800000022DF -:10440000042A97F0000104FD062A97F40000000337 -:10441000062A989800000022042A9920000104FE30 -:10442000062A992400000003062A99C800000022E9 -:10443000042A9A50000104FF062A9A54000000033F -:10444000062AB14000000002062AC54000000150C3 -:10445000062A957000000032062A5028000000024B -:10446000062A503800000002062A50080000000208 -:10447000062A501800000002022A520C0000000117 -:10448000042A9B3000020500062A96D00000002274 -:10449000042A975800010502062A975C00000003D1 -:1044A000062A980000000022042A988800010503CB -:1044B000062A988C00000003062A9930000000228A -:1044C000042A99B800010504062A99BC00000003DB -:1044D000062A9A6000000022042A9AE800010505D5 -:1044E000062A9AEC00000003062AB14800000002E8 -:1044F000022ACA8000000000042A9B38001005062A -:10450000062A50480000000E022ACA84000000005B -:10451000042A9B7800100516062A50800000000E21 -:10452000022ACA8800000000042A9BB80010052651 -:10453000062A50B80000000E022ACA8C00000000B3 -:10454000042A9BF800100536062A50F00000000EE1 -:10455000022ACA9000000000042A9C380010054678 -:10456000062A51280000000E022ACA94000000000A -:10457000042A9C7800100556062A51600000000E9F -:10458000022ACA9800000000042A9CB800100566A0 -:10459000062A51980000000E022ACA9C0000000062 -:1045A000042A9CF800100576062A51D00000000E5F -:1045B000021010080000000102101050000000015D -:1045C000021010000003D000021010040000003D93 -:1045D0000910180002000586091011000010078656 -:1045E0000610114000000008091011600010079625 -:1045F000061011A00000001806102400000000E0C2 -:104600000210201C00000000021020200000000109 -:10461000021020C00000000202102004000000016F -:10462000021020080000000109103C00000507A648 -:1046300009103800000507AB09103820000507B045 -:1046400006104C000000010002104028000000107D -:104650000210404400003FFF0210405800280000B4 -:10466000021040840084924A02104058000000006A -:104670000210800000001080021080AC00000000DA -:1046800002108038000000100210810000000000BD -:10469000061081200000000202108008000002B510 -:1046A0000210801000000000061082000000004A86 -:1046B000021081080001FFFF061081400000000287 -:1046C0000210800000001A800610900000000024F4 -:1046D000061091200000004A061093700000004A66 -:1046E000061095C00000004A0210800400001080EF -:1046F000021080B0000000010210803C0000001099 -:104700000210810400000000061081280000000251 -:104710000210800C000002B502108014000000009E -:10472000061084000000004A0210810C0001FFFF07 -:1047300006108148000000020210800400001A8068 -:104740000610909000000024061092480000004AD5 -:10475000061094980000004A061096E80000004AEF -:104760000210800000001080021080AC00000002E7 -:1047700002108038000000100210810000000000CC -:10478000061081200000000202108008000002B51F -:104790000210801000000000061082000000004A95 -:1047A000021081080001FFFF061081400000000296 -:1047B0000210800000001A80061090000000002403 -:1047C000061091200000004A061093700000004A75 -:1047D000061095C00000004A0210800400001080FE -:1047E000021080B0000000030210803C00000010A6 -:1047F0000210810400000000061081280000000261 -:104800000210800C000002B50210801400000000AD -:10481000061084000000004A0210810C0001FFFF16 -:1048200006108148000000020210800400001A8077 -:104830000610909000000024061092480000004AE4 -:10484000061094980000004A061096E80000004AFE -:104850000210800000001080021080AC00000004F4 -:1048600002108038000000100210810000000000DB -:10487000061081200000000202108008000002B52E -:104880000210801000000000061082000000004AA4 -:10489000021081080001FFFF0610814000000002A5 -:1048A0000210800000001A80061090000000002412 -:1048B000061091200000004A061093700000004A84 -:1048C000061095C00000004A02108004000010800D -:1048D000021080B0000000050210803C00000010B3 -:1048E0000210810400000000061081280000000270 -:1048F0000210800C000002B50210801400000000BD -:10490000061084000000004A0210810C0001FFFF25 -:1049100006108148000000020210800400001A8086 -:104920000610909000000024061092480000004AF3 -:10493000061094980000004A061096E80000004A0D -:104940000210800000001080021080AC0000000601 -:1049500002108038000000100210810000000000EA -:10496000061081200000000202108008000002B53D -:104970000210801000000000061082000000004AB3 -:10498000021081080001FFFF0610814000000002B4 -:104990000210800000001A80061090000000002421 -:1049A000061091200000004A061093700000004A93 -:1049B000061095C00000004A02108004000010801C -:1049C000021080B0000000070210803C00000010C0 -:1049D000021081040000000006108128000000027F -:1049E0000210800C000002B50210801400000000CC -:1049F000061084000000004A0210810C0001FFFF35 -:104A000006108148000000020210800400001A8095 -:104A10000610909000000024061092480000004A02 -:104A2000061094980000004A061096E80000004A1C -:104A3000021205B0000000010212049000E383405E -:104A40000212051400003C100212066C0000000166 -:104A5000021206700000000002120494FFFFFFFF24 -:104A600002120498FFFFFFFF0212049CFFFFFFFFEA -:104A7000021204A0FFFFFFFF021204A4FFFFFFFFCA -:104A8000021204A8FFFFFFFF021204ACFFFFFFFFAA -:104A9000021204B0FFFFFFFF021204BCFFFFFFFF82 -:104AA000021204C0FFFFFFFF021204C4FFFFFFFF5A -:104AB000021204C8FFFFFFFF021204CCFFFFFFFF3A -:104AC000021204D0FFFFFFFF021204D8FFFFFFFF16 -:104AD000021204DCFFFFFFFF021204E0FFFFFFFFF2 -:104AE000021204E4FFFFFFFF021204E8FFFFFFFFD2 -:104AF000021204ECFFFFFFFF021204F0FFFFFFFFB2 -:104B0000021204F4FFFFFFFF021204F8FFFFFFFF91 -:104B1000021204FCFFFFFFFF02120500FFFFFFFF70 -:104B200002120504FFFFFFFF02120508FFFFFFFF4F -:104B30000212050CFFFFFFFF02120510FFFFFFFF2F -:104B4000021204D4FF809000021204B4F00050005E -:104B5000021204B8F00010000212039000000008D6 -:104B60000212039C00000008021203A000000008CB -:104B7000021203A400000002021203BC00000004A1 -:104B8000021203C000000005021203C4000000046A -:104B9000021203D0000000000212036C00000001AA -:104BA000021203680000003F021201BC0000004036 -:104BB000021201C000001808021201C4000008031C -:104BC000021201C800000803021201CC00000040DC -:104BD000021201D000000003021201D400000803F9 -:104BE000021201D800000803021201DC00000803D1 -:104BF000021201E000010003021201E400000803B8 -:104C0000021201E800000803021201EC0000000398 -:104C1000021201F000000003021201F40000000380 -:104C2000021201F800000003021201FC0000000360 -:104C3000021202000000000302120204000000033E -:104C400002120208000000030212020C000000031E -:104C500002120210000000030212021400000003FE -:104C600002120218000000030212021C00000003DE -:104C700002120220000000030212022400000003BE -:104C800002120228000024030212022C0000002F4E -:104C90000212023000000009021202340000001962 -:104CA00002120238000001840212023C000001835B -:104CB0000212024000000306021202440000001922 -:104CC00002120248000000060212024C0000030615 -:104CD00002120250000003060212025400000306F2 -:104CE0000212025800000C860212025C0000030649 -:104CF00002120260000003060212026400000006B5 -:104D000002120268000000060212026C0000000697 -:104D10000212027000000006021202740000000677 -:104D200002120278000000060212027C0000000657 -:104D30000212028000000006021202840000000637 -:104D400002120288000000060212028C0000000617 -:104D500002120290000000060212029400000006F7 -:104D600002120298000000060212029C00000006D7 -:104D7000021202A000000306021202A400000013A7 -:104D8000021202A800000006021202B00000100485 -:104D9000021202B400001004021203240010644046 -:104DA0000212032800106440021205B40000000142 -:104DB000021201B0000000010600A0000000000C7B -:104DC0000200A050000000000200A05400000000FB -:104DD0000200A0EC555400000200A0F055555555B6 -:104DE0000200A0F4000055550200A0F8F0000000F9 -:104DF0000200A0FC555400000200A1005555555575 -:104E00000200A104000055550200A108F0000000B6 -:104E10000200A18C555400000200A1905555555533 -:104E20000200A194000055550200A198F000000076 -:104E30000200A19C000000000200A1A000010000EF -:104E40000200A1A4000050140200A1A8000000006C -:104E50000200A45C00000C000200A61C000000037D -:104E60000200A06CFF5C00000200A070FFF55FFF75 -:104E70000200A0740000FFFF0200A078F00003E031 -:104E80000200A07C000000000200A0800000A00042 -:104E90000600A084000000050200A0980FE00000BA -:104EA0000600A09C000000070200A0B8000004005B -:104EB0000600A0BC000000030200A0C80000100013 -:104EC0000600A0CC000000030200A0D800004000B3 -:104ED0000600A0DC000000030200A0E800010000C2 -:104EE0000600A22C000000040200A10CFF5C0000E0 -:104EF0000200A110FFF55FFF0200A1140000FFFFF8 -:104F00000200A118F00003E00200A11C0000000054 -:104F10000200A1200000A0000600A124000000055E -:104F20000200A1380FE000000600A13C00000007CD -:104F30000200A158000008000600A15C0000000368 -:104F40000200A168000020000600A16C0000000320 -:104F50000200A178000080000600A17C0000000390 -:104F60000200A188000200000600A23C000000042C -:104F70000200A030000000000200A0340000000089 -:104F80000200A038000000000200A03C0000000069 -:104F90000200A040000000000200A0440000000049 -:104FA0000200A048000000000200A04C0000000029 -:104FB00000000000000000000000003000000000C1 -:104FC00000000000000000000000000000000000E1 -:104FD00000000000000000000000000000000000D1 -:104FE0000000000000300031000000000000000060 -:104FF00000000000000000000000000000000000B1 -:1050000000000000000000000000000000000000A0 -:10501000003100520000000000000000000000000D -:105020000000000000000000000000000000000080 -:105030000000000000000000000000000052008995 -:1050400000000000000000000089008D008D00912C -:1050500000910095009500990099009D009D00A188 -:1050600000A100A500A500A900A900AE00AE00B1F6 -:1050700000B100B4000000000000000000000000CB -:105080000000000000000000000000000000000020 -:105090000000000000B40309030903130313031DF8 -:1050A000031D03240324032B032B03320332033990 -:1050B00003390340034003470347034E034E0355A0 -:1050C00000000000000000000000000000000000E0 -:1050D00000000000000000000000000000000000D0 -:1050E00000000000000000000000000000000000C0 -:1050F00000000000000000000000000000000000B0 -:10510000000000000000000000000000000000009F -:10511000000000000000000000000000000000008F -:10512000000000000000000000000000000000007F -:10513000000000000000000000000000000000006F -:10514000000000000000000000000000000000005F -:10515000000000000000000000000000000000004F -:10516000000000000000000000000000000000003F -:105170000355035B0000000000000000035B035CBC -:10518000035C035D035D035E035E035F035F036017 -:1051900003600361036103620362036300000000B4 -:1051A00000000000000000000000000000000000FF -:1051B00000000000000000000000000000000000EF -:1051C00000000000000000000363036D036D037B1B -:1051D000037B0389000000000000000000000000C5 -:1051E00000000000000000000000000000000000BF -:1051F00000000000000000000000000000000000AF -:10520000000000000000000000000000000000009E -:10521000000000000000000000000000000000008E -:105220000389038A00000000000000000000000065 -:10523000000000000000000000000000000000006E -:10524000000000000000000000000000038A03D6F8 -:10525000000000000000000000000000000000004E -:10526000000000000000000000000000000000003E -:10527000000000000000000003D604010000000050 -:10528000000000000000000000000000000000001E -:10529000000000000000000000000000000000000E -:1052A00000000000040104330000000000000000C2 -:1052B0000433043A043A0441044104480448044FC6 -:1052C000044F04560456045D045D04640464046BD6 -:1052D000046B04A4000000000000000004A404A863 -:1052E00004A804AC04AC04B004B004B404B404B81E -:1052F00004B804BC04BC04C004C004C404C4051342 -:105300000513052A052A05410541054305430545C1 -:1053100005450547054705490549054B054B054D1D -:10532000054D054F054F0551055105E805E805E90F -:1053300005E905EA05EA05EF05EF05F405F405F9C9 -:1053400005F905FE05FE0603060306080608060D18 -:10535000060D0612061206130000000000000000F1 -:10536000000000000000000000000000000000003D -:10537000000000000000000000000000000000002D -:1053800006130624000000000000000000000000DA -:10539000000000000000000000000000000000000D -:1053A0000000000000000000000000000624063994 -:1053B0000639063C063C063F0000000000000000E5 -:1053C00000000000000000000000000000000000DD -:1053D0000000000000000000063F0675000000000D -:1053E00000000000000000000000000000000000BD -:1053F00000000000000000000000000000000000AD -:1054000000000000067507780000000000000000A2 -:10541000000000000000000000000000000000008C -:10542000000000000000000000000000000000007C -:105430000778077F077F078307830787000000003F -:10544000000000000000000000000000000000005C -:10545000000000000000000000000000078707C8EF -:10546000000000000000000007C807D107D107DADC -:1054700007DA07E307E307EC07EC07F507F507FE94 -:1054800007FE080708070810081008670867087C67 -:10549000087C089108910894089408970897089A3E -:1054A000089A089D089D08A008A008A308A308A6BC -:1054B00008A608A908A908B2000000000000000022 -:1054C00000000000000000000000000000000000DC -:1054D00000000000000000000000000000000000CC -:1054E00008B208B800000000000000000000000042 -:1054F00000000000000000000000000000000000AC -:1055000000000000000000000000000008B808BB18 -:10551000000000000000000000000000000000008B -:10552000000000000000000000000000000000007B -:10553000000000000000000008BB08C100000000DF -:10554000000000000000000000000000000000005B -:10555000000000000000000000000000000000004B -:10556000000000000000000000000000000000003B -:1055700008C108D008D008DF08DF08EE08EE08FDF3 -:1055800008FD090C090C091B091B092A092A0939FC -:10559000093909AA00000000000000000000000016 -:1055A00000000000000000000000000000000000FB -:1055B00000000000000000000000000009AA09BF70 -:1055C00009BF09D009D009E109E109E209E209E3CB -:1055D00009E309E409E409E509E509E609E609E75B -:1055E00009E709E809E809E90000000000000000F7 -:1055F00000000000000000000000000000000000AB -:10560000000000000000000000000000000000009A -:10561000000000000000000000000000000000008A -:10562000000000000000000000000000000000007A -:10563000000000000000000000000000000000006A -:10564000000000000000000000000000000000005A -:10565000000000000000000000000000000000004A -:10566000000000000000000000000000000000003A -:10567000000000000000000000000000000000002A -:10568000000000000000000000000000000000001A -:10569000000000000000000000000000000000000A -:1056A00000000000000000000000000000000000FA -:1056B00000000000000000000000000000000000EA -:1056C000000000000000000000010000000204C013 -:1056D0000003098000040E4000051300000617C0F7 -:1056E00000071C800008214000092600000A2AC08B -:1056F000000B2F80000C3440000D3900000E3DC01F -:10570000000F42800010474000114C00001250C0B2 -:105710000013558000145A4000155F00001663C046 -:105720000017688000186D4000197200001A76C0DA -:10573000001B7B80001C8040001D8500001E89C06E -:10574000001F8E80000093400000200000004000F9 -:1057500000006000000080000000A0000000C00009 -:105760000000E000000100000001200000014000F6 -:1057700000016000000180000001A0000001C000E5 -:105780000001E000000200000002200000024000D2 -:1057900000026000000280000002A0000002C000C1 -:1057A0000002E000000300000003200000034000AE -:1057B00000036000000380000003A0000003C0009D -:1057C0000003E0000004000000042000000440008A -:1057D00000046000000480000004A0000004C00079 -:1057E0000004E00000050000000520000005400066 -:1057F00000056000000580000005A0000005C00055 -:105800000005E00000060000000620000006400041 -:1058100000066000000680000006A0000006C00030 -:105820000006E0000007000000072000000740001D -:1058300000076000000780000007A0000007C0000C -:105840000007E000000800000008200000084000F9 -:1058500000086000000880000008A0000008C000E8 -:105860000008E000000900000009200000094000D5 -:1058700000096000000980000009A0000009C000C4 -:105880000009E000000A0000000A2000000A4000B1 -:10589000000A6000000A8000000AA000000AC000A0 -:1058A000000AE000000B0000000B2000000B40008D -:1058B000000B6000000B8000000BA000000BC0007C -:1058C000000BE000000C0000000C2000000C400069 -:1058D000000C6000000C8000000CA000000CC00058 -:1058E000000CE000000D0000000D2000000D400045 -:1058F000000D6000000D8000000DA000000DC00034 -:10590000000DE000000E0000000E2000000E400020 -:10591000000E6000000E8000000EA000000EC0000F -:10592000000EE000000F0000000F2000000F4000FC -:10593000000F6000000F8000000FA000000FC000EB -:10594000000FE000001000000010200000104000D8 -:1059500000106000001080000010A0000010C000C7 -:105960000010E000001100000011200000114000B4 -:1059700000116000001180000011A0000011C000A3 -:105980000011E00000120000001220000012400090 -:1059900000126000001280000012A0000012C0007F -:1059A0000012E0000013000000132000001340006C -:1059B00000136000001380000013A0000013C0005B -:1059C0000013E00000140000001420000014400048 -:1059D00000146000001480000014A0000014C00037 -:1059E0000014E00000150000001520000015400024 -:1059F00000156000001580000015A0000015C00013 -:105A00000015E000001600000016200000164000FF -:105A100000166000001680000016A0000016C000EE -:105A20000016E000001700000017200000174000DB -:105A300000176000001780000017A0000017C000CA -:105A40000017E000001800000018200000184000B7 -:105A500000186000001880000018A0000018C000A6 -:105A60000018E00000190000001920000019400093 -:105A700000196000001980000019A0000019C00082 -:105A80000019E000001A0000001A2000001A40006F -:105A9000001A6000001A8000001AA000001AC0005E -:105AA000001AE000001B0000001B2000001B40004B -:105AB000001B6000001B8000001BA000001BC0003A -:105AC000001BE000001C0000001C2000001C400027 -:105AD000001C6000001C8000001CA000001CC00016 -:105AE000001CE000001D0000001D2000001D400003 -:105AF000001D6000001D8000001DA000001DC000F2 -:105B0000001DE000001E0000001E2000001E4000DE -:105B1000001E6000001E8000001EA000001EC000CD -:105B2000001EE000001F0000001F2000001F4000BA -:105B3000001F6000001F8000001FA000001FC000A9 -:105B4000001FE00000200000002020000020400096 -:105B500000206000002080000020A0000020C00085 -:105B60000020E00000210000002120000021400072 -:105B700000216000002180000021A0000021C00061 -:105B80000021E0000022000000222000002240004E -:105B900000226000002280000022A0000022C0003D -:105BA0000022E0000023000000232000002340002A -:105BB00000236000002380000023A0000023C00019 -:105BC0000023E00000240000002420000024400006 -:105BD00000246000002480000024A0000024C000F5 -:105BE0000024E000002500000025200000254000E2 -:105BF00000256000002580000025A0000025C000D1 -:105C00000025E000002600000026200000264000BD -:105C100000266000002680000026A0000026C000AC -:105C20000026E00000270000002720000027400099 -:105C300000276000002780000027A0000027C00088 -:105C40000027E00000280000002820000028400075 -:105C500000286000002880000028A0000028C00064 -:105C60000028E00000290000002920000029400051 -:105C700000296000002980000029A0000029C00040 -:105C80000029E000002A0000002A2000002A40002D -:105C9000002A6000002A8000002AA000002AC0001C -:105CA000002AE000002B0000002B2000002B400009 -:105CB000002B6000002B8000002BA000002BC000F8 -:105CC000002BE000002C0000002C2000002C4000E5 -:105CD000002C6000002C8000002CA000002CC000D4 -:105CE000002CE000002D0000002D2000002D4000C1 -:105CF000002D6000002D8000002DA000002DC000B0 -:105D0000002DE000002E0000002E2000002E40009C -:105D1000002E6000002E8000002EA000002EC0008B -:105D2000002EE000002F0000002F2000002F400078 -:105D3000002F6000002F8000002FA000002FC00067 -:105D4000002FE00000300000003020000030400054 -:105D500000306000003080000030A0000030C00043 -:105D60000030E00000310000003120000031400030 -:105D700000316000003180000031A0000031C0001F -:105D80000031E0000032000000322000003240000C -:105D900000326000003280000032A0000032C000FB -:105DA0000032E000003300000033200000334000E8 -:105DB00000336000003380000033A0000033C000D7 -:105DC0000033E000003400000034200000344000C4 -:105DD00000346000003480000034A0000034C000B3 -:105DE0000034E000003500000035200000354000A0 -:105DF00000356000003580000035A0000035C0008F -:105E00000035E0000036000000362000003640007B -:105E100000366000003680000036A0000036C0006A -:105E20000036E00000370000003720000037400057 -:105E300000376000003780000037A0000037C00046 -:105E40000037E00000380000003820000038400033 -:105E500000386000003880000038A0000038C00022 -:105E60000038E0000039000000392000003940000F -:105E700000396000003980000039A0000039C000FE -:105E80000039E000003A0000003A2000003A4000EB -:105E9000003A6000003A8000003AA000003AC000DA -:105EA000003AE000003B0000003B2000003B4000C7 -:105EB000003B6000003B8000003BA000003BC000B6 -:105EC000003BE000003C0000003C2000003C4000A3 -:105ED000003C6000003C8000003CA000003CC00092 -:105EE000003CE000003D0000003D2000003D40007F -:105EF000003D6000003D8000003DA000003DC0006E -:105F0000003DE000003E0000003E2000003E40005A -:105F1000003E6000003E8000003EA000003EC00049 -:105F2000003EE000003F0000003F2000003F400036 -:105F3000003F6000003F8000003FA000003FC00025 -:105F4000003FE000003FE00100000000000001FF12 -:105F50000000020000007FF800007FF80000014010 -:105F600000003500000000010000FF0000000000FC -:105F70000000FF00000000000000FF000000000023 -:105F80000000FF00000000000000FF000000000013 -:105F90000000FF00000000000000FF000000000003 -:105FA0000000FF000000000000000000140AFF00D5 -:105FB00000000001000000000020100100000000AF -:105FC0000100900000000100000090020000900419 -:105FD00000009006000090080000900A0000900C5D -:105FE0000000900E0000901000009012000090142D -:105FF00000009016000090180000901A0000901CFD -:106000000000901E000090200000902200009024CC -:1060100000009026000090280000902A0000902C9C -:106020000000902E0000903000009032000090346C -:1060300000009036000090380000903A0000903C3C -:106040000000903E0000904000009042000090440C -:1060500000009046000090480000904A0000904CDC -:106060000000904E000090500000905200009054AC -:1060700000009056000090580000905A0000905C7C -:106080000000905E0000906000009062000090644C -:1060900000009066000090680000906A0000906C1C -:1060A0000000906E000090700000907200009074EC -:1060B00000009076000090780000907A0000907CBC -:1060C0000000907E0000908000009082000090848C -:1060D00000009086000090880000908A0000908C5C -:1060E0000000908E0000909000009092000090942C -:1060F00000009096000090980000909A0000909CFC -:106100000000909E000090A0000090A2000090A4CB -:10611000000090A6000090A8000090AA000090AC9B -:10612000000090AE000090B0000090B2000090B46B -:10613000000090B6000090B8000090BA000090BC3B -:10614000000090BE000090C0000090C2000090C40B -:10615000000090C6000090C8000090CA000090CCDB -:10616000000090CE000090D0000090D2000090D4AB -:10617000000090D6000090D8000090DA000090DC7B -:10618000000090DE000090E0000090E2000090E44B -:10619000000090E6000090E8000090EA000090EC1B -:1061A000000090EE000090F0000090F2000090F4EB -:1061B000000090F6000090F8000090FA000090FCBB -:1061C000000090FE00009100000091020000910488 -:1061D00000009106000091080000910A0000910C57 -:1061E0000000910E00009110000091120000911427 -:1061F00000009116000091180000911A0000911CF7 -:106200000000911E000091200000912200009124C6 -:1062100000009126000091280000912A0000912C96 -:106220000000912E00009130000091320000913466 -:1062300000009136000091380000913A0000913C36 -:106240000000913E00009140000091420000914406 -:1062500000009146000091480000914A0000914CD6 -:106260000000914E000091500000915200009154A6 -:1062700000009156000091580000915A0000915C76 -:106280000000915E00009160000091620000916446 -:1062900000009166000091680000916A0000916C16 -:1062A0000000916E000091700000917200009174E6 -:1062B00000009176000091780000917A0000917CB6 -:1062C0000000917E00009180000091820000918486 -:1062D00000009186000091880000918A0000918C56 -:1062E0000000918E00009190000091920000919426 -:1062F00000009196000091980000919A0000919CF6 -:106300000000919E000091A0000091A2000091A4C5 -:10631000000091A6000091A8000091AA000091AC95 -:10632000000091AE000091B0000091B2000091B465 -:10633000000091B6000091B8000091BA000091BC35 -:10634000000091BE000091C0000091C2000091C405 -:10635000000091C6000091C8000091CA000091CCD5 -:10636000000091CE000091D0000091D2000091D4A5 -:10637000000091D6000091D8000091DA000091DC75 -:10638000000091DE000091E0000091E2000091E445 -:10639000000091E6000091E8000091EA000091EC15 -:1063A000000091EE000091F0000091F2000091F4E5 -:1063B000000091F6000091F8000091FA000091FCB5 -:1063C000000091FEFFFFFFFFFFFFFFFFFFFFFFFF4A -:1063D000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFCD -:1063E000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFBD -:1063F000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFAD -:10640000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF9C -:10641000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF8C -:10642000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7C -:10643000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF6C -:10644000FFFFFFFF0000000300BEBC2000000000B3 -:10645000000000050000000300BEBC20000000009A -:10646000000000050000000300BEBC20000000008A -:10647000000000050000000300BEBC20000000007A -:10648000000000050000000300BEBC20000000006A -:10649000000000050000000300BEBC20000000005A -:1064A000000000050000000300BEBC20000000004A -:1064B000000000050000000300BEBC20000000003A -:1064C0000000000500002000000040C000006180C6 -:1064D000000082400000A3000000C3C00000E48070 -:1064E0000001054000012600000146C00001678050 -:1064F000000188400001A9000001C9C00001EA8034 -:1065000000020B4000022C0000024CC000026D8013 -:1065100000028E400002AF000002CFC00002F080F7 -:10652000000011400000800000010380000187008E -:1065300000020A8000028E00000311800003950013 -:106540000004188000049C0000051F800005A300C3 -:10655000000626800006AA0000072D800007B10073 -:10656000000834800008B80000093B800009BF0023 -:10657000000A4280000AC600000B4980000BCD00D3 -:10658000000C5080000CD400000D578000005B0010 -:1065900000007FF800007FF8000000D50000150023 -:1065A0000000FF00000000000000FF0000000000ED -:1065B0000000FF00000000000000FF0000000000DD -:1065C0000000FF00000000000000FF0000000000CD -:1065D0000000FF00000000000000FF0000000000BD -:1065E000000019000000000000000000FFFFFFFF96 -:1065F0000000000003938700000000000393870061 -:1066000000007FF800007FF80000068E00003500D3 -:106610000000FF000FFFFFFF0000FF000FFFFFFF64 -:10662000000000FF0000FF000FFFFFFF0000FF0061 -:106630000FFFFFFF000000FF0000FF000FFFFFFF44 -:106640000000FF000FFFFFFF000000FF0000FF0041 -:106650000FFFFFFF0000FF000FFFFFFF000000FF24 -:106660000000FF000FFFFFFF0000FF000FFFFFFF14 -:10667000000000FF0000FF000FFFFFFF0000FF0011 -:106680000FFFFFFF000000FF0000FF000FFFFFFFF4 -:106690000000FF000FFFFFFF000000FF0000FF00F1 -:1066A0000FFFFFFF0000FF000FFFFFFF000000FFD4 -:1066B0000000FF000FFFFFFF0000FF000FFFFFFFC4 -:1066C000000000FF0000FF000FFFFFFF0000FF00C1 -:1066D0000FFFFFFF000000FF0000FF000FFFFFFFA4 -:1066E0000000FF000FFFFFFF000000FF0000FF00A1 -:1066F0000FFFFFFF0000FF000FFFFFFF000000FF84 -:106700000000FF000FFFFFFF0000FF000FFFFFFF73 -:10671000000000FF0000FF000FFFFFFF0000FF0070 -:106720000FFFFFFF000000FF0000FF000FFFFFFF53 -:106730000000FF000FFFFFFF000000FF0000FF0050 -:106740000FFFFFFF0000FF000FFFFFFF000000FF33 -:106750000000FF000FFFFFFF0000FF000FFFFFFF23 -:10676000000000FF0000FF000FFFFFFF0000FF0020 -:106770000FFFFFFF000000FF0000FF000FFFFFFF03 -:106780000000FF000FFFFFFF000000FF0000FF0000 -:106790000FFFFFFF0000FF000FFFFFFF000000FFE3 -:1067A0000000FF000FFFFFFF0000FF000FFFFFFFD3 -:1067B000000000FF0000FF000FFFFFFF0000FF00D0 -:1067C0000FFFFFFF000000FF0000FF000FFFFFFFB3 -:1067D0000000FF000FFFFFFF000000FF0000FF00B0 -:1067E0000FFFFFFF0000FF000FFFFFFF000000FF93 -:1067F0000000FF000FFFFFFF0000FF000FFFFFFF83 -:10680000000000FF0000FF000FFFFFFF0000FF007F -:106810000FFFFFFF000000FF0000FF000FFFFFFF62 -:106820000000FF000FFFFFFF000000FF0000FF005F -:106830000FFFFFFF0000FF000FFFFFFF000000FF42 -:106840000000FF000FFFFFFF0000FF000FFFFFFF32 -:10685000000000FF0000FF000FFFFFFF0000FF002F -:106860000FFFFFFF000000FF0000FF000FFFFFFF12 -:106870000000FF000FFFFFFF000000FF0000FF000F -:106880000FFFFFFF0000FF000FFFFFFF000000FFF2 -:10689000000000FF000000FF000000FF000000FFFC -:1068A000000000FF000000FF000000FF000000FFEC -:1068B0000000FF00000000000000FF0000000000DA -:1068C0000000FF00000000000000FF0000000000CA -:1068D0000000FF00000000000000FF0000000000BA -:1068E0000000FF00000000000000FF0000000000AA -:1068F000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA8 -:10690000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF97 -:10691000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF87 -:10692000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF77 -:10693000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF67 -:10694000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF57 -:10695000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF47 -:10696000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF37 -:106970000000100000002080000031000000418075 -:10698000000052000000628000007300000083805D -:10699000000094000000A4800000B5000000C58045 -:1069A0000000D6000000E6800000F700000107802C -:1069B0000001180000012880000139000001498011 -:1069C00000015A0000016A8000017B0000018B80F9 -:1069D00000019C000001AC800001BD000001CD80E1 -:1069E0000001DE000001EE800001FF0000000F80CA -:1069F00000007FF800007FF800000344000035002D -:106A000010000000000028AD000100010005020692 -:106A1000CCCCCCC5FFFFFFFFFFFFFFFF7058103C41 -:106A20000000FF00000000000000FF000000000068 -:106A30000000FF00000000000000FF000000000058 -:106A40000000FF00000000000000FF000000000048 -:106A50000000FF00000000000000FF000000000038 -:106A60000000000000000001CCCC0201CCCCCCCC5A -:106A7000CCCC0201CCCCCCCCCCCC0201CCCCCCCC80 -:106A8000CCCC0201CCCCCCCCCCCC0201CCCCCCCC70 -:106A9000CCCC0201CCCCCCCCCCCC0201CCCCCCCC60 -:106AA000CCCC0201CCCCCCCC00000000FFFFFFFF1F -:106AB000000E0000011600D6002625A0002625A005 -:106AC000002625A0002625A000720000012300F367 -:106AD000002625A0002625A0002625A0002625A00A -:106AE0000000FFFF000000000000FFFF00000000AA -:106AF0000000FFFF000000000000FFFF000000009A -:106B00000000FFFF000000000000FFFF0000000089 -:106B10000000FFFF000000000000FFFF0000000079 -:106B20000000FFFF000000000000FFFF0000000069 -:106B30000000FFFF000000000000FFFF0000000059 -:106B40000000FFFF000000000000FFFF0000000049 -:106B50000000FFFF000000000000FFFF0000000039 -:106B60000000FFFF000000000000FFFF0000000029 -:106B70000000FFFF000000000000FFFF0000000019 -:106B80000000FFFF000000000000FFFF0000000009 -:106B90000000FFFF000000000000FFFF00000000F9 -:106BA0000000FFFF000000000000FFFF00000000E9 -:106BB0000000FFFF000000000000FFFF00000000D9 -:106BC0000000FFFF000000000000FFFF00000000C9 -:106BD0000000FFFF000000000000FFFF00000000B9 -:106BE0000000FFFF000000000000FFFF00000000A9 -:106BF0000000FFFF000000000000FFFF0000000099 -:106C00000000FFFF000000000000FFFF0000000088 -:106C10000000FFFF000000000000FFFF0000000078 -:106C20000000FFFF000000000000FFFF0000000068 -:106C30000000FFFF000000000000FFFF0000000058 -:106C40000000FFFF000000000000FFFF0000000048 -:106C50000000FFFF000000000000FFFF0000000038 -:106C60000000FFFF000000000000FFFF0000000028 -:106C70000000FFFF000000000000FFFF0000000018 -:106C80000000FFFF000000000000FFFF0000000008 -:106C90000000FFFF000000000000FFFF00000000F8 -:106CA0000000FFFF000000000000FFFF00000000E8 -:106CB0000000FFFF000000000000FFFF00000000D8 -:106CC0000000FFFF000000000000FFFF00000000C8 -:106CD0000000FFFF000000000000FFFF00000000B8 -:106CE000FFFFFFF3318FFFFF0C30C30CC30C30C329 -:106CF000CF3CF300F3CF3CF30000CF3CCDCDCDCD66 -:106D0000FFFFFFF130EFFFFF0C30C30CC30C30C3AB -:106D1000CF3CF300F3CF3CF30001CF3CCDCDCDCD44 -:106D2000FFFFFFF6305FFFFF0C30C30CC30C30C316 -:106D3000CF3CF300F3CF3CF30002CF3CCDCDCDCD23 -:106D4000FFFFF4061CBFFFFF0C30C305C30C30C3AC -:106D5000CF300014F3CF3CF30004CF3CCDCDCDCDEC -:106D6000FFFFFFF2304FFFFF0C30C30CC30C30C3EA -:106D7000CF3CF300F3CF3CF30008CF3CCDCDCDCDDD -:106D8000FFFFFFFA302FFFFF0C30C30CC30C30C3E2 -:106D9000CF3CF300F3CF3CF30010CF3CCDCDCDCDB5 -:106DA000FFFFFFF731EFFFFF0C30C30CC30C30C304 -:106DB000CF3CF300F3CF3CF30020CF3CCDCDCDCD85 -:106DC000FFFFFFF5302FFFFF0C30C30CC30C30C3A7 -:106DD000CF3CF300F3CF3CF30040CF3CCDCDCDCD45 -:106DE000FFFFFFF3318FFFFF0C30C30CC30C30C328 -:106DF000CF3CF300F3CF3CF30000CF3CCDCDCDCD65 -:106E0000FFFFFFF1310FFFFF0C30C30CC30C30C389 -:106E1000CF3CF300F3CF3CF30001CF3CCDCDCDCD43 -:106E2000FFFFFFF6305FFFFF0C30C30CC30C30C315 -:106E3000CF3CF300F3CF3CF30002CF3CCDCDCDCD22 -:106E4000FFFFF4061CBFFFFF0C30C305C30C30C3AB -:106E5000CF300014F3CF3CF30004CF3CCDCDCDCDEB -:106E6000FFFFFFF2304FFFFF0C30C30CC30C30C3E9 -:106E7000CF3CF300F3CF3CF30008CF3CCDCDCDCDDC -:106E8000FFFFFFFA302FFFFF0C30C30CC30C30C3E1 -:106E9000CF3CF300F3CF3CF30010CF3CCDCDCDCDB4 -:106EA000FFFFFFF730EFFFFF0C30C30CC30C30C304 -:106EB000CF3CF300F3CF3CF30020CF3CCDCDCDCD84 -:106EC000FFFFFFF5304FFFFF0C30C30CC30C30C386 -:106ED000CF3CF300F3CF3CF30040CF3CCDCDCDCD44 -:106EE000FFFFFFFF30CFFFFF0C30C30CC30C30C3DC -:106EF000CF3CF3CCF3CF3CF30000CF3CCDCDCDCD98 -:106F0000FFFFFFFF30CFFFFF0C30C30CC30C30C3BB -:106F1000CF3CF3CCF3CF3CF30001CF3CCDCDCDCD76 -:106F2000FFFFFFFF30CFFFFF0C30C30CC30C30C39B -:106F3000CF3CF3CCF3CF3CF30002CF3CCDCDCDCD55 -:106F4000FFFFFFFF30CFFFFF0C30C30CC30C30C37B -:106F5000CF3CF3CCF3CF3CF30004CF3CCDCDCDCD33 -:106F6000FFFFFFFF30CFFFFF0C30C30CC30C30C35B -:106F7000CF3CF3CCF3CF3CF30008CF3CCDCDCDCD0F -:106F8000FFFFFFFF30CFFFFF0C30C30CC30C30C33B -:106F9000CF3CF3CCF3CF3CF30010CF3CCDCDCDCDE7 -:106FA000FFFFFFFF30CFFFFF0C30C30CC30C30C31B -:106FB000CF3CF3CCF3CF3CF30020CF3CCDCDCDCDB7 -:106FC000FFFFFFFF30CFFFFF0C30C30CC30C30C3FB -:106FD000CF3CF3CCF3CF3CF30040CF3CCDCDCDCD77 -:106FE000FFFFFFF3320FFFFF0C30C30CC30C30C3A5 -:106FF000CF3CF300F3CF3CF30000CF3CCDCDCDCD63 -:10700000FFFFFFF1310FFFFF0C30C30CC30C30C387 -:10701000CF3CF300F3CF3CF30001CF3CCDCDCDCD41 -:10702000FFFFFFF6305FFFFF0C30C30CC30C30C313 -:10703000CF3CF300F3CF3CF30002CF3CCDCDCDCD20 -:10704000FFFFF4061CBFFFFF0C30C305C30C30C3A9 -:10705000CF300014F3CF3CF30004CF3CCDCDCDCDE9 -:10706000FFFFFFF2304FFFFF0C30C30CC30C30C3E7 -:10707000CF3CF300F3CF3CF30008CF3CCDCDCDCDDA -:10708000FFFFFF8A042FFFFF0C30C30CC30C30C37B -:10709000CF3CC000F3CF3CF30010CF3CCDCDCDCDE5 -:1070A000FFFFFF9705CFFFFF0C30C30CC30C30C3AD -:1070B000CF3CC000F3CF3CF30020CF3CCDCDCDCDB5 -:1070C000FFFFFFF5310FFFFF0C30C30CC30C30C3C3 -:1070D000CF3CF300F3CF3CF30040CF3CCDCDCDCD42 -:1070E000FFFFFFF3320FFFFF0C30C30CC30C30C3A4 -:1070F000CF3CF300F3CF3CF30000CF3CCDCDCDCD62 -:10710000FFFFFFF1302FFFFF0C30C30CC30C30C367 -:10711000CF3CF300F3CF3CF30001CF3CCDCDCDCD40 -:10712000FFFFFFF6305FFFFF0C30C30CC30C30C312 -:10713000CF3CF300F3CF3CF30002CF3CCDCDCDCD1F -:10714000FFFFFF061CBFFFFF0C30C30CC30C30C396 -:10715000CF3CC014F3CF3CF30004CF3CCDCDCDCD1C -:10716000FFFFFFF2304FFFFF0C30C30CC30C30C3E6 -:10717000CF3CF300F3CF3CF30008CF3CCDCDCDCDD9 -:10718000FFFFFFFA302FFFFF0C30C30CC30C30C3DE -:10719000CF3CF300F3CF3CF30010CF3CCDCDCDCDB1 -:1071A000FFFFFFF731CFFFFF0C30C30CC30C30C320 -:1071B000CF3CF300F3CF3CF30020CF3CCDCDCDCD81 -:1071C000FFFFFFFF30CFFFFF0C30C30CC30C30C3F9 -:1071D000CF3CF3CCF3CF3CF30040CF3CCDCDCDCD75 -:1071E000FFFFFFFF30CFFFFF0C30C30CC30C30C3D9 -:1071F000CF3CF3CCF3CF3CF30000CF3CCDCDCDCD95 -:10720000FFFFFFFF30CFFFFF0C30C30CC30C30C3B8 -:10721000CF3CF3CCF3CF3CF30001CF3CCDCDCDCD73 -:10722000FFFFFFFF30CFFFFF0C30C30CC30C30C398 -:10723000CF3CF3CCF3CF3CF30002CF3CCDCDCDCD52 -:10724000FFFFFFFF30CFFFFF0C30C30CC30C30C378 -:10725000CF3CF3CCF3CF3CF30004CF3CCDCDCDCD30 -:10726000FFFFFFFF30CFFFFF0C30C30CC30C30C358 -:10727000CF3CF3CCF3CF3CF30008CF3CCDCDCDCD0C -:10728000FFFFFFFF30CFFFFF0C30C30CC30C30C338 -:10729000CF3CF3CCF3CF3CF30010CF3CCDCDCDCDE4 -:1072A000FFFFFFFF30CFFFFF0C30C30CC30C30C318 -:1072B000CF3CF3CCF3CF3CF30020CF3CCDCDCDCDB4 -:1072C000FFFFFFFF30CFFFFF0C30C30CC30C30C3F8 -:1072D000CF3CF3CCF3CF3CF30040CF3CCDCDCDCD74 -:1072E000FFFFFFFF30CFFFFF0C30C30CC30C30C3D8 -:1072F000CF3CF3CCF3CF3CF30000CF3CCDCDCDCD94 -:10730000FFFFFFFF30CFFFFF0C30C30CC30C30C3B7 -:10731000CF3CF3CCF3CF3CF30001CF3CCDCDCDCD72 -:10732000FFFFFFFF30CFFFFF0C30C30CC30C30C397 -:10733000CF3CF3CCF3CF3CF30002CF3CCDCDCDCD51 -:10734000FFFFFFFF30CFFFFF0C30C30CC30C30C377 -:10735000CF3CF3CCF3CF3CF30004CF3CCDCDCDCD2F -:10736000FFFFFFFF30CFFFFF0C30C30CC30C30C357 -:10737000CF3CF3CCF3CF3CF30008CF3CCDCDCDCD0B -:10738000FFFFFFFF30CFFFFF0C30C30CC30C30C337 -:10739000CF3CF3CCF3CF3CF30010CF3CCDCDCDCDE3 -:1073A000FFFFFFFF30CFFFFF0C30C30CC30C30C317 -:1073B000CF3CF3CCF3CF3CF30020CF3CCDCDCDCDB3 -:1073C000FFFFFFFF30CFFFFF0C30C30CC30C30C3F7 -:1073D000CF3CF3CCF3CF3CF30040CF3CCDCDCDCD73 -:1073E000FFFFFFFF30CFFFFF0C30C30CC30C30C3D7 -:1073F000CF3CF3CCF3CF3CF30000CF3CCDCDCDCD93 -:10740000FFFFFFFF30CFFFFF0C30C30CC30C30C3B6 -:10741000CF3CF3CCF3CF3CF30001CF3CCDCDCDCD71 -:10742000FFFFFFFF30CFFFFF0C30C30CC30C30C396 -:10743000CF3CF3CCF3CF3CF30002CF3CCDCDCDCD50 -:10744000FFFFFFFF30CFFFFF0C30C30CC30C30C376 -:10745000CF3CF3CCF3CF3CF30004CF3CCDCDCDCD2E -:10746000FFFFFFFF30CFFFFF0C30C30CC30C30C356 -:10747000CF3CF3CCF3CF3CF30008CF3CCDCDCDCD0A -:10748000FFFFFFFF30CFFFFF0C30C30CC30C30C336 -:10749000CF3CF3CCF3CF3CF30010CF3CCDCDCDCDE2 -:1074A000FFFFFFFF30CFFFFF0C30C30CC30C30C316 -:1074B000CF3CF3CCF3CF3CF30020CF3CCDCDCDCDB2 -:1074C000FFFFFFFF30CFFFFF0C30C30CC30C30C3F6 -:1074D000CF3CF3CCF3CF3CF30040CF3CCDCDCDCD72 -:1074E000000C0000000700C000028130000B815832 -:1074F0000002021000010230000F024000010330C0 -:10750000000C0000000800C000028140000B8168F0 -:10751000000202200001024000070250000202C0E7 -:10752000001000000008010000028180000B81A80B -:107530000002026000018280000E82980008038031 -:107540000010000000010100000281100009013854 -:10755000000201C8000101E8000E01F8000002D895 -:10756000CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC5B -:1075700000002000CCCCCCCCCCCCCCCCCCCCCCCC5B -:10758000CCCCCCCC00002000CCCCCCCCCCCCCCCC4B -:10759000CCCCCCCCCCCCCCCC040020000000000067 -:1075A0001F8B080000000000000BFB51CFC0F00350 -:1075B0008AB7B13130ECE644F0E98159181818F86F -:1075C00099C8D7BF1168C04E20BE01C4075948D71B -:1075D0007F551AC15E26C9C0700A8827883330B427 -:1075E0004A21C4ED651818EE01F92BA16272403DE5 -:1075F00073A4C977F3281E3CB8D014951F620CA160 -:107600005F9840E82234F950A8BCB81E842E36C5D5 -:107610006EAE841E71F6A7A9A0F2BD55F0ABCFD512 -:1076200040E5C7A2A90F81F2017EE9B234D8030078 -:1076300000000000000000001F8B08000000000098 -:10764000000BED7D0B7455D5B5E8DA9FB3CFFF6421 -:10765000278470123EEEC400C1063C4280A0A83BC5 -:10766000FC1A7DD41E1025E5A11C446B004922A6FE -:10767000D78C96D76CC8870450E3E751BD457BA0F3 -:10768000D88B0E5BA3A68ABDB43D887AA9C3DB2242 -:107690005AA52D7A83FA2C58A0B1572ABD4FCB5B3F -:1076A00073AEB592BD77CEC9C74F47EF788D43769D -:1076B000D6DEEB3BFF6BCEB95634D943F22E27E42E -:1076C0001CFCD0A7291142A6F73DC92D5932C92368 -:1076D000E41B3E823F1FF923534816210D3EF6BCA2 -:1076E0003D10D905CF2D8D84A426C2F771491221F2 -:1076F000244848899A0B2D02B1870BE15977617CA8 -:10770000323E67C23387C8848C84F218FDBD20EBFB -:10771000FB9C42FF399AA880F114F68AA8A43C96F3 -:10772000C2F6DF226446DF3C48DD57F578B86FDEED -:10773000EEA7A26B24C5EB9E837F94E5598950E6A2 -:10774000FA0D47A5C79FB7D51F4FC2B9382F95A8C7 -:10775000382FDE9E108BD8E7E7EEE7A346F2F8F36A -:10776000E3FBC32DD3B8026E6D8D3E7CB636EA24A2 -:10777000E5258436333B4BE93344CC5DA5FDDBCDB9 -:107780002312871F9F0F8C63D0FAF47F42E1DE9CA7 -:107790004B9241C0214938E0D61C5AEC33D3F42730 -:1077A0009E2497C2AD84CFB9A8FF7AFD302F0A0777 -:1077B0003FCC2B0D3C97C2BCA6F79F97BFD83DAFDF -:1077C0006A6287CF70E7159844C821C0876A128221 -:1077D00078B9CDD19FAC9B56779AFE08A70BD5E020 -:1077E000EB1B229E822572DFF8000723E0A02F6F9B -:1077F00034C7496F6EBA067820BE3A387CE20AE395 -:1078000007AB0F8FF4199A1D93803568F110E02DA6 -:107810009F30F8E557B7DE2A4F2194D53A0F4EA096 -:10782000F0CBEF5EB99040F9E8152780DF9ACBA640 -:1078300056CEA5F5B2CB63AF2CA04D423143027AB0 -:10784000DD0A9D15407F5FB32A68B909FAA365CBAD -:10785000BACAB4106EA6036E1472864ACB1EF8B56F -:10786000280DFC482F1EA473DEFEED33C1CF436C00 -:10787000F8437E5EEFA0CB8C78BF91E1CBA2FF01F5 -:10788000BE46101B5FD37EB22B35075EB25CE33C75 -:107890000ABF20BC6FFD9B8C97439EF41994CE3D8C -:1078A000A5B29EA478CA26B16CB58CE263A14A4009 -:1078B0008EE5E4EA1290C360786926A412F89F4A24 -:1078C00007B2C826E77ECEF9AB60CDEE9DAD749CC5 -:1078D00033B34331A895AFD3B94EEDBF9E3B40BE05 -:1078E000786DE5B2E74802C7EB3C5844E76595C9B7 -:1078F000B18729DD6C2D3DACDBE5E3B15EF9E2A695 -:107900000F62A833B83CA0F0514A65D31FF9ECF4DC -:10791000A17C4AFA08DFE8C4C770F1757A98F4F1DF -:1079200059C71378EDCF571B055E7D847EDF52B2B9 -:1079300078407DD51FAF4F92046D172A2566324DD2 -:10794000BBFFB4EB0BF7D326DFDD72541935A36A06 -:10795000E74078CB75AE57F4EB6F508C7747D0A2E9 -:10796000AAA37CD5B81E688FDE63114A776740F6FC -:107970005078281D17A5A04C8A49EC61D64D4AA223 -:10798000657FD44C6E413A48225EC4FCBC86EC90C4 -:10799000B36AAE530E932A4BB2CFDFDFA0E13C3483 -:1079A000182F17EC02DA2105851A2229A05B41AFB6 -:1079B000A092CE9D0F65A79DD1664C25E9F0A072DF -:1079C000BC4B92A0D76F0D4DBEB8C75BE29CEF9049 -:1079D000DB8554E33DD1268D9CEE6BA792F7047EA8 -:1079E00028102F13761DC7D3660FD92B5D48E5C12C -:1079F000986BC152209BE1D32C6A87C0932A9FCDFC -:107A000063A6EA4057648FA4C23C71488A4742F596 -:107A10001DD40B4A06F623FBEA90FE9490894FF1A1 -:107A20003DF3BCD8F8BD655FA206F0531DD58C2D83 -:107A3000748E6B15D3D80874318DC9A7EAE88479A0 -:107A4000A0EF3C129BD7B7A57C5C879AD39687762C -:107A50005906FBAE5AA52A7F2A7CDF3661207E229A -:107A6000494F4FB70D9E6E7BF06689DA835FA2BFE8 -:107A7000CC2433018E7F8A2DCE4A0D80AFF71B0FA9 -:107A8000EAEAF83E7BD0FD7DAD42EAD2C98156C913 -:107A9000C7F8D26769601F8875AF0576A720DD1625 -:107AA000DBC4D69B9B8BF05DBBE717BA6AE3BFB51F -:107AB00054CD78A7F65F8F80B7E8A7B77DF2A0A373 -:107AC000BDBB5D6F7F425E507B18E85CD041504A81 -:107AD0006C95E87B6F6CB105EA6CED63150CFF19D2 -:107AE000E6DF8BAF4F397FD16E30BAFAD3EEA656B0 -:107AF000D04FEF691D575D4CE9E8F74F28B14DF4C1 -:107B00006BF58E89F3C05E7A8FD3B7C0D389DD4D14 -:107B100079E9E823139E7E21F9711C415FD5F2F2C9 -:107B200001E96130FA7ACA4D5F9D577F21F475C82B -:107B30004D5F1C1E273BD9FAC9FD23185E38BEDCF9 -:107B4000F8C988974FDBAE3F3DFD5AA27CEDEDBCF6 -:107B50003A3D3DF1F90A7C7DD6F90E4647798669B2 -:107B6000EA74FC51D48E91407F9491588ACE53A7E9 -:107B70000FD45B31A6B7845C12ED4F4BCC4E53C98A -:107B80006BD85E21294B477BDB6967CC57E84BDA22 -:107B90004F7309497A715F64FA504F95A884E93FA1 -:107BA00033943F03EC08FEA3CC8EC1BAB3C0FE07EA -:107BB000FD359BEB5F89DA5B747DA132E7BE37E070 -:107BC000B23F14BE5FE8676F0D737FEC97F9FE3824 -:107BD0004842A88FC4FE38037FF6EE8B395C476AB3 -:107BE000C494E9BAB5839EE42609B41B41FD4C8ECA -:107BF0004A49E62F20256037AF970A62A00FE83E7A -:107C0000AF278B7E7FEF070AEA878668DD8A1658E2 -:107C1000F6B50D13BBE9B8F7349269C59EBEF1EE17 -:107C2000513B7C00EFF6E2F50EBBF6BB52A250B61C -:107C3000E91D7F549B563C0D8653DFEEA6F090293C -:107C40002081FF02A1FBA22F18003FF6BE174EF6BF -:107C5000B2D2BF9C0B364F011653B02F6DA7B63B67 -:107C6000B9188AA3A50A4A07ED1EFEDDFA4D05ECF8 -:107C700077DBFDACBC63D3AC8D169447F2FA561596 -:107C8000FB9ECFCAB76DFA4105EC0BDAB2E99AA9AF -:107C9000BE6EF324ABE269F8FB365976D85F4DC669 -:107CA00082F2FF43D7E1F79917BD40E1498112B352 -:107CB0000CD26B97150ABF41C7DD952500FFD7147D -:107CC00002F4EC3762F19B0CA43FA47B7FAE19DB7E -:107CD000424B0DF4850CF528DE1E96605FC7EC3133 -:107CE000F0E79C43FAA57C41BFAFCFD6B13ED16D42 -:107CF000F659519F3DD68B2717DEEE557BFC80B79A -:107D0000EF8DF9F01713693FD642390664F3BD0DC4 -:107D100045D92B6D787CCC37A70AF0489A73D12EC1 -:107D20008992DE1F13CA62DF5C403A2BC0781C4385 -:107D3000251FA1743A2EDE53012830AAF4E7708F74 -:107D40004BE6E9EFA15DA548E7BE34743BCA0D07D9 -:107D5000DAE3A845543E8D90483C9DDC5DA9E6A041 -:107D60003C185149D73B809FE09B549F30FB2CE14E -:107D700003FF56A67132CDF333C073934CC71D4D2C -:107D80009208A7C1E09A099EADD127B3515E7FCE7C -:107D900070CDD4DE0DCF1112E397956A39F2CB5036 -:107DA000FD3B6D7C3FD5027E38FA6CE27E38777BF6 -:107DB000BFDA416269F0EB379CFE210DF625B67201 -:107DC000BD6C307D1072FB89189EDD7A6101D70B86 -:107DD0002D51AA17983C5C087A20C8E1DF02BB7ECF -:107DE000909F6192B4E8F720F707915226FF7DF447 -:107DF0003FE0B751554E7DA00D511FBC2BC55F9084 -:107E0000910E8904F3BB5FEAB86202D04F3EB3C75C -:107E1000A337B445133638D4CB4CDF097D962C16E6 -:107E2000FA8C20FCCEE37348920E3FE8C307362C51 -:107E3000CE42BFDD8D41871C8AB62EC6FDAF8D9E1A -:107E4000D12FDAC1FDA399F0A76BC9443A7958A89C -:107E5000307918317B52E0F34342CEE32E434ED6C5 -:107E60000CFEC4B10F8B4CED39783E5DEFCE8BE448 -:107E7000D826DA4E9DADA63C14BE6AF98B55127D0C -:107E8000EE2C64F0B76611A4D390B1E08402FA58E6 -:107E9000ED467F4DA8D2BD2FB69515E8A7E77AD459 -:107EA000DF763FF500FBB8A13E9B28BCDEB6F13F74 -:107EB000855C4AA1EB50371003EC09D5A4223102AE -:107EC0004F3D0FE8453563217C765754C2F3BCD94A -:107ED000F14AD9A6075433BE05EA8FF8CA7DEDB042 -:107EE0005EF526595624C6073936789B4AA1633F6A -:107EF00097ADBBFCA589D62AD4EF8646C617F69F58 -:107F000077BDAC72B9E7A417412703C8BBCF441FA4 -:107F10006FCAC25FEDC4BF834E8AFAF02BDA85FACE -:107F2000F9AB9CF875973F6FBCFA014F141FE751EE -:107F30003C017D9E379BD123B547D17E7AC0D76166 -:107F400002BC1F2836644BEA6B175672989FF92CB7 -:107F5000DD6851BBE7FE95DB4D68975F4C6580841B -:107F6000CFB4FEA37A59C376542E542ACC6E97C050 -:107F70001E9FAF6CAB82F63B295E81DF77027F43A9 -:107F80007C20A1A11CAE97DB2B36D2BE5B8F4AB200 -:107F90000246ACBE14F1EBE7FCFE912751097EC806 -:107FA0002DFF4B26BB0CD04B03FBBD9A38BE4519A9 -:107FB000FC0D609F8CA9D3A702D833B5DB5E275791 -:107FC000A65B57B5C2F07F47DDE10E344F9F77EED9 -:107FD000473CCB4DA048D897542B36FA0E97317FAB -:107FE0000749D0F5407D4E371F150E4CAF0FBAE64E -:107FF0003F96C753DCF55E56B8BFCE60F03244FF03 -:108000001B07EE5FC0E76C9BC2E323D40043221E34 -:1080100049ECFA5BB9F15005BCA75CB709F0B55D56 -:1080200026D5CCDF1C473D14E1E3ED2CCFC1F60B88 -:10803000552647C79AFA16C0F7D866192C05F2B824 -:1080400062E0FB51CBEBF67B281EDA0B492C64E097 -:1080500010D8EF8BE335A4CBFC5CA6C7F2EB290963 -:10806000D07AF9A52469D0F6EDFB1FA8D068394273 -:108070003754600AFBCA193E7D252406A690C72204 -:1080800029997D4F424C5229EFB140951E183F036C -:10809000F75F77E69298D7E8931B82AEEE6CBEC787 -:1080A0000F7AE481E27BAE9800FEC65215FDE4E44F -:1080B000630A27E14F54205E163761BCF6596CDE27 -:1080C000F40DE253D5D9FAC7DC3F1BF9A43DFC34CB -:1080D000CEC35A4762E3B15E8C60FC860A54F05707 -:1080E0003655337BD78D8FF524F1B832DD4EAF870F -:1080F000906EDA3F51F8BEE0C58D60E78F835F690F -:10810000F9974D7FDC381CBB45C40F85DDB245EDCA -:1081100044BEB728CF815E12768CBFB813C7FDBFAF -:108120009CDE87DABFBFC4E96F75DB356E7BA65E68 -:10813000D61DF6AB7B5D1F795257C0FCB6E4537E6B -:108140004FA3077E03FA9AB6DF115DFCAB89465F49 -:108150003F7D72C8C0EFA23CE6AC86F8197A7D2A52 -:10816000F7608F6632BE1A2BE4D037285F0D107F80 -:10817000147CF511151287804FD40EA42F6296201F -:108180005F097E51BA3BDACFA7F460D4CBE0B906E1 -:10819000FE2239B45C48E93D65B38784BC504B3B53 -:1081A000E313A5FE74F7A021231ECF94317F7596AB -:1081B000D56D4293606927C6F5285DFD17D095AA55 -:1081C0002725C0EB98FB17E0BA7EA93056F7AB2CF9 -:1081D0007EEC5EC7CF397C89BE1BED793F1B8EB22A -:1081E000F87D31363F579CBDFE5703C6D9FD319708 -:1081F0009D334C3F428ECAFD08DCEF3558FBE1C68B -:10820000D795B323903E7ACB19E4ED4D2AE78BA3A3 -:10821000BB1C70E9070F65476CA0F9F9859FFE53F9 -:10822000C60550870D010E6E385EA23AFD879F3756 -:108230001CDDF1EF97B8DC1F4C1E044D33252BE0FD -:108240003F23CCBF1322DCBFE3A4F79DCD32DA215C -:10825000C1B0BC134CC9ACFA6ED4C1627C4AEF55B4 -:10826000AA8DDE47971E4A413BB73ECAA4870693B4 -:10827000B7AB7CE60D2ACAADF4FBF1BE7C03CA2580 -:1082800069F20D32E2B5EEF3C937182ABC7BFD9BCB -:108290003C7FE0867241C7C6D2DF51B8AC3EE821D0 -:1082A000E897F998AECE16575BCDF78137F07DE4AD -:1082B0008D241E818FA7885C09FC728A1C8E4CB3AA -:1082C000C993FB548DF14B9BE76DF0AF8A78F94D64 -:1082D0001DAC2CE673F3FDCEF2D7C9E23CF0EB7D8A -:1082E000FD3E0FE26BB5CBBFD6AC32FD7133A96B4F -:1082F00005BCB5784815C8B11B74A28EA0A6EBBA10 -:10830000671E9CB19296BFCBED91F7A95C366C715C -:10831000D035A1A406F87DA76BDAB59710689F6CDD -:108320002D807D5A36C17DAB1BCEABDA9CF31B6C26 -:10833000FEEEF952F2C2F9669A87BA474A6B4F3F8E -:1083400022E40DC757A6BC2A914FF50B20205ADF17 -:108350009A43D8BEF3AD60B209E535CBA71AACFDA0 -:108360002F55463F9FB6FDAB83B45FE7EB5900CC7A -:10837000D6966BC5C12F24E28235A4CE1C4D7F5505 -:10838000F72DB246135BBDE810EB150F5C2FD3BC85 -:108390004FE83E4BBEB06FFEDF9512C7D434F3BF3B -:1083A0005D49D440FF5EC083024F15F18D7E608A27 -:1083B000DF5A35D4266541BE5317EE03FD86EAA089 -:1083C000875AF805E45A09936BC112E777B77FF82B -:1083D0004355C4E153C87F188236C07E08A514F007 -:1083E000DF94AB277BEBD3F16A605D1742298E7275 -:1083F000A35E67F56B8871D7EC32E43F8C3FD4B74E -:108400009F8F71F5FA9106FA77551233B10F17DD88 -:10841000D59E9548D2A60F6BD51E0DF8AC96DA45C1 -:10842000F6F7EBA38AC34FEB7E7AA8E51C2A817D81 -:1084300092CCFC483A2DDBD6FDA70E89E7AF185940 -:108440004B06F0DFAD8F327FF00DEDE3B398DFD058 -:10845000297F4F3732BFDCBF3DF67D0DFCFCA71EE8 -:108460003D7615C07BEDBF2AC407F91B8F85490AED -:10847000EDB1A406F6D89A2EC54CA6CDAF6862F130 -:10848000CFC7C388AF354F7A930B69FB354FBF33E6 -:1084900085D0F99DDED4F3E268B09B1F95581E820B -:1084A000D53DE56AFA7E8D4A56A4F31B4CF630F9A9 -:1084B00073F2D96015F0B7B467FFF5D86FE7528F44 -:1084C000D7B6DF2EF678906F693D66973F2225C7B5 -:1084D0004BE9E6C7F23F4E3E22B1F9EDF524FD30FF -:1084E000BF3D3BB5049D47ED9E0F509ECC7DFC8764 -:1084F000118043ED5EC5A1076AF72829EF147C1EA1 -:108500008327C48DA41940279C5EBAD661BCA8A657 -:1085100073EB07E0C7A8DDEB946B142EB114C0F524 -:108520000D25B610CA4FFD4BC4A0A07AFFD0C311D1 -:10853000802BED77A59605FAC649DFD0FFD99CFEC2 -:10854000FD11D283F1BADACE76365ED7577E0F7A36 -:10855000A5D6253FDF875FF2FBDB33D7785CF6CC0F -:108560009EA1C5EBD6FEF0CC43161DF7E4937F78B1 -:10857000C8A2F3BFE5AFFFF9D0B7803F7FE6D74190 -:10858000FED73EFAEB08B1D163AD87F1E3E9B1C4A0 -:10859000A27B5472FA37DE24F84B4EFFF4F7E30C5B -:1085A000BAEED34FFC25CFA0F5EB7F3A7F14C0A1E4 -:1085B000FEC773470DB4FF067A4D7AEDF34A225E8B -:1085C0008DBD123382F6F1A70B3F07BA0E8C83796B -:1085D0009E3AE28D81DBB996BE6B980AF85A87FA0B -:1085E00018CA1B289C6B1EDBFC01C889FEF0B6462E -:1085F000CBE8AC4F8D06A77D4DD73B0B106FA40782 -:10860000F5A8BB7EED6B149F1766C6DF19F2B106A5 -:10861000F2AEF6B176365E27C55FA43FFE4EC12F9F -:10862000B3FAE3EF0E17FECE905BBE970F798D5D28 -:10863000231C7152F1EC8B0FC6B3E203C80B210F60 -:1086400006836FB5C4E6B5CC633EE801BE7A32D886 -:108650008BDF8580DF1F9E1947287D1CF7F45C0F98 -:1086600072B3E7A75E7D177DBFE6A76F209F9DFED3 -:10867000F12B9A81F9992424E5F13C31F67308E451 -:10868000700DDBCB91DADDE19437D287A79AE4A2B3 -:108690004A2382EF8FE1FB24A3FF9AE4FE25521ABE -:1086A000BCBDE1296276407224C265DDEEDF69CC93 -:1086B000BEECC3A7540EF83CB600DE67C2A758BF95 -:1086C0000EEB9F69C3EB6EC6B7EEFA35943F41EFF0 -:1086D000F5C36F527A039EA7777A55D07BA7C1FE68 -:1086E0000AF5C77B1FFC99FD33DCFDCA2B6EFE1615 -:1086F000F1630E87CCF461713B60E0F50D177E3FAE -:10870000F7180E3A12703CF9717AF97F8ACB8D1AFC -:10871000625516D8EC139F87DA27905F46E2D6E8B9 -:10872000C2BEF99E847D04A5BF938F2A18AF69ED60 -:108730003C8072DC2D2F6A48FA7DFB5F3DCC5EAC3D -:10874000D9BB7F0AC8B593CF3D8BF459F3D8310D0F -:10875000F62F2FEE794AEB2EEDE307D00F499B7EE3 -:1087600038F9A3FD53983C48BFFF0D6AACFFDA7D92 -:10877000CEFE6B1FFBC0D1FF5AAB5363790C038F46 -:10878000F3BE6A2E85F5BE7FC843409EBEDFA9A416 -:10879000F5BFF670FD28E0D4FACA82DF419CBFEC39 -:1087A00070C0003DDAB5C91C7507D86B873D04E47D -:1087B0003751CD3F7869B9EB9500C633BA0E5FAB40 -:1087C0001836FFC4332E78CE7CCD9A1BA6FDCDEC97 -:1087D0008E97C116CA2D37CA8FD27DA3DD7FF54A89 -:1087E000E52890FBCD60CF4F84F16251F07F289156 -:1087F00005952C7F50D6FD69F537EBCF138A63BE04 -:10880000A047977B7DB6488F62BFC5FD4DADA1F4F3 -:10881000FEE8059AD817D0716D7290DAAA55E9F082 -:10882000364B637648A6EF976ACCDF93E97BC52089 -:10883000ED7BF99BE3470BCBF174F39EC6FB71FB19 -:108840005733C9030FEFA74C331CEB05782FB2E564 -:10885000C58F26C98D90274A4221773C3AEEB3C78F -:10886000A3AB0EED87F873EED5FBF201FE11D2AC8F -:10887000BF87763C899D1BC08E75C79FDD7989991E -:10888000E2D1BE50CD9114E9DF5FFFF8BB897928B2 -:10889000CD63E6F90A6DF1F766BD5FFC7DBD46C7A5 -:1088A0006DC9808725DA9C7FD280BE649248F77DAF -:1088B0000BA79BCB49F7532B619E3116BF9FED82CF -:1088C000D7A51C5E3F3B9F2E9CAA9E0A62A81E0A4B -:1088D000DFB94BCC661081F397F7ACDD0F7C26E255 -:1088E000F7D644F95C70E8F01B6E5EC42ADFE27BC9 -:1088F000B521E445103D27AD5EE89B87C5F755518E -:10890000DC2779389F1D78F3661FC82D95242A0B24 -:1089100061BFC4E39A986F4FFBCB4BF98949E7AB32 -:10892000E906DADB79A9D50FDC0471757D0CC62365 -:1089300094B397A0FFD0DDAF128D59980F16322A4D -:1089400014DB38ADB92C3EA3EAF1B479C3ABB4C49F -:1089500013B05EE5EC65D8AFEC8B613D121A5ABEE0 -:10896000EC77AE8E207C7D14BE201F1164B02E9E4D -:108970003775F7D511D433FE839E9DF0DD1F6279E4 -:1089800054B7CB8118E459B9F3A82ADE6A27D05F1F -:10899000EB3109E328827E5B0BEBCE03393E401EB0 -:1089A000D54B9ACDAF9E298FCA1FBA11F3A8FC9F51 -:1089B000368FCA2A9807F6586B361179559644E7D0 -:1089C000D1CAF3A2FEA3F5A5B9A09F5AFDE2FBCB45 -:1089D000734D7BD95A7F00CB3CEF6AB4B7BD09EA2F -:1089E000E78E26759DE8CF33C93536391BF1AA08C5 -:1089F000E77FD6CC7735479E7CD4115F3AF0E666A8 -:108A00001FE86FFAAC2C02F851BA02BB3D2FD54ECD -:108A1000ECFA483C051DB5160F1CBF53CF5E847E93 -:108A20007C51F6E949D34C537FBE8FD91F827E7D9E -:108A3000B924097AC967241EB809E83937140B32FA -:108A4000BAC438595B08DD53FDD6D1567C03C6DB6A -:108A5000CEE804B95ED071FFF95FC6E75F64615C80 -:108A60002244309E96791D65B88E559A19F6DAE043 -:108A7000987B5EFABCD4BBBD6C3D2DF1E52CEFAC10 -:108A8000DA198715791AA27E504A1478411EE6B287 -:108A900038ACEC63FCD6872FAA2A6CFECD26B2DC5C -:108AA0000212509777E2D146554F62FD127FE27C69 -:108AB000AF233ED7CDE2BAAE78E27CE516C6DF83BF -:108AC000E04F9CCBD80A71B789109F8BF2F37D06DB -:108AD0008FD3992CAF28033DB5150F1C87EA688CFE -:108AE00061FBBB1ACB59BE9244B85F3BD9047402F8 -:108AF0006E0946F73F6802BE092B822F7E88E53B50 -:108B00002556BEC9FBCC5CC8373CF0E61B55AB28EC -:108B10007DB49A01E4FFC1D6A72767205E873B4E4C -:108B2000FFF5B271DBCC10EE77075BB79E62E30E08 -:108B3000751C115FEB5B9F0FC769350619A7838D05 -:108B400033F8FC199FDCB17F35E62FF828FFFBE9ED -:108B50007BDFEC1E9248D37F16E79F036F7A515E4E -:108B6000B7E5B2FC284F49C8644E4067FF9ED2BCAF -:108B70003978DEA1EC02CC9FBF637F3BCA190DC6DA -:108B8000A1553CB1D04AD62E61C239DBC83C82F136 -:108B9000674F49DE2A78DF403AE273400F97CB2CCB -:108BA0003FB9A4E426E8271BF892CEA3DCC7F69DC4 -:108BB0009E928B6F86FAFBA7BF9E68023895333A68 -:108BC0002007F31D706C358AC4B99D01F9DE53EEA0 -:108BD0008C5B109F33FF93A84B306E4EE54287D7D6 -:108BE000665752BD781FF23329B3C0DEDBFEB56B8A -:108BF00063767EFE672DFE1D565FE46B093E4F9F38 -:108C000037D79A2BF2E6123EA50CCE29F5E6532F64 -:108C1000CCB7E77FF17CEA90C8A7E6F1CC0EFA5F0B -:108C2000BAFC39F739C6CF2B9FFA292FDF0F07C9B6 -:108C300058C8A7FE8987C4529017F36B250679316F -:108C40006EFA70F7E73E07D06B8F64E0E7F7013804 -:108C500036B9979F70E1ED463FC6E7C478CF837C75 -:108C60002A1D9C4F47573BFB195BE73C9F755E8372 -:108C7000335E55681538EA9FDF56E4F83EBEE302DE -:108C8000C7F789F74F759427252F76D4FFD29E39E1 -:108C90008EF2E4CE2B1DF52FDCBBD851BE28B5CC0F -:108CA000517FDAC11B1CDFA71F5AE3F83EF3C87AD5 -:108CB000477956F7371DF51BA87902F92C7040004B -:108CC000F7ABDB46CB76FA6CCFA67A250BF3B8353B -:108CD0009ED48FF166968BDC9767E06EA7146BA627 -:108CE0004EF9573126CCD331CFF046E423A5386F67 -:108CF0008E81EF672C00BF132963E7B444FCDA537D -:108D00004C527EC8EF0BB9F0EB8A4B7B946D29C0B7 -:108D1000B376F4CB07A5487FBC7AA2EE7CC6A1C58A -:108D2000B555E3B3E507E4F9385F8CA57C817EC4D3 -:108D30008F15D8B7907961B40F6CFB1B84A3D8DF73 -:108D40005CE623CD0053C11715CB7B46BF80D5C44D -:108D5000BEC62B0F272FB9BF5EF1A2DD25E4CC6084 -:108D60007A45494E73E421B89F54FE95F9609F1EE1 -:108D70005986F2A8775FD02B1FE333E1BB478DA163 -:108D80007CEC957F7B0A1C7261A8F6995B4EDF052F -:108D9000421FCF05A597D711C80BA372E9CEABAF81 -:108DA000C23818A9278EF3807955711FE83D6A975C -:108DB0007DC567DB3F47CA997DF6F766A78660BD2C -:108DC00036F927EC5501D7118575718CEB85650255 -:108DD000FBAAA6D9B128F801DBA08A6D9FF65DDF5A -:108DE000F958BF39A4C9E02F6D3E381FE3035E7FF9 -:108DF000DC0779CE4D9E7825ACAB295BD6D3E53B1D -:108E00006DF631FF8CD6109CB67B00FAD034BAEFE9 -:108E10004FB3DE7FF131BF4BB3BEF820E8B99CB051 -:108E20006640FE44EBFE598B305F77A1AAC3BE9625 -:108E3000D04DDC3BB6B8222171F46769B932EA45FE -:108E4000AD2182E30F36DF5B7DCCCFE06DF00F38D4 -:108E50005FAF96DE4F9169BE9B61BEB983CFD70BE2 -:108E6000F39560FC108EBFC9C7F0E886BF87986D88 -:108E7000F368BD96635FEE28468A61F97AF72E9C07 -:108E80008A744A05B5837EC53E82D2EFC340BF6275 -:108E9000FF2ECEB3DEE263790902AFC460FE881113 -:108EA0000915F7BD3909B6FFED931F8C8E723C3161 -:108EB00082E7BFC6A8189704378DDD8FA1F8D9BE09 -:108EC000C77B690CF1D5FE15956C027A2BA6EB8158 -:108ED00073B90759DCA9DD13AB8A87FAC613EDDF36 -:108EE000E1FB40952CC9C27B529485D174F6672F63 -:108EF0009D73B8B9E5EC011FCFC3CA27F94CCE96D4 -:108F00002E85A34499FA71DB1B0DDCAF3CFCF329E1 -:108F10001D08CFF631F7A11D2DFC63245A3688BFFA -:108F200087C54BFBF0BCD448513CAA574C45A75FC2 -:108F30007B31C7739D2B9F97E359E057F8ED493478 -:108F400017F95AE05B017802AE94D9D181F495C249 -:108F5000F9C60DCF53FF4DE17904D600743B96AEB0 -:108F60001FF8E6C01504E3602E7E14ED04DDBBD7C8 -:108F70001FF6FFF75EBFA087CCF5ADB4FB0F11D78E -:108F80000D737AF371BDF942F9DB6D709E44CD65C6 -:108F9000FBDD7079F3AD329CC320960EFEB5B03880 -:108FA000BF53E6BC7F2450EADC7FF85CF74D78F8CD -:108FB000FEA3DFFD2ADCCE12E7F9DDF377E36BAE2B -:108FC0003F7D1E261993DEEFEA8EC789F886C88397 -:108FD00015710084035DBF67961C47F95746CC9D09 -:108FE00069E4D3323FD30B5DCFF9314F225CA5A1A9 -:108FF0003FB6A02C5501E5823A12033D71F1F143D1 -:1090000024413BBD20C0E47E41595202BF47C149C3 -:109010009617B89DC72B0BEA93D24ADB38969FE987 -:10902000AD8FDEBC1DE5E37363595EFA6D15CC7E32 -:109030003B14BDA1A302C62D67F9E461BA5F84BCED -:10904000B1F0116F12EDADB26E027E54AA05AC30D4 -:10905000FD7EBC914CBD713CE47DF9F079B251C705 -:10906000E781B1DAFECB69BDF5850103FA6D290A06 -:10907000B0F3BD611FEEF7FF9CFD75F4AB9E6E8CE7 -:1090800062FDB66F9B685734EF3F817EC3A0392DD8 -:10909000C6FCA8A642CA613E874CF0731035662C08 -:1090A00086EF077E83F5142DF11B0BEC93651AEE0A -:1090B000EF010E104F68F2B37CB9CDFEBA68363CB2 -:1090C0000BC98A4569E0BD82EB1D4A518A96D79744 -:1090D00087A495A7942CF02797914EC873F7B424D2 -:1090E0002B404F93D5BA01E38CF1252BC07F3CA6D2 -:1090F0005A8F810F5D2B67E745043E3C7E127F222D -:1091000004F552D2AD74DC89011DC7293892C4BC64 -:10911000E58FDE9C99D6FEBFFD68057EDFD65879C7 -:10912000789E8D9F4319E2951B8BE73CE0A7E3BD3A -:10913000EA67FC9AA95FF11C6ABFAF723A39F0E6A0 -:10914000C451605F3664C8A356748AA7114C3E812F -:109150003F62FD78635476C8DE0F8387F2DCB30C80 -:10916000AFA58C3E9B7E3C310BFA7DFECDA53AF837 -:10917000FBFE945B8CFB86534F7B4DB05F4EE590BE -:109180006ACCB77C7AE68BB03FFC43E3C11CD526A2 -:10919000174FFDE895191EDADFA9275F99A1227301 -:1091A000251D76ECBA73AFCE003BC19A434AEAE87C -:1091B000B356D708F45BEB63EB107972DBF3B4566C -:1091C000785E19CCC6F679A3E43BA1ACF85E1DF736 -:1091D000EE345C378B2BF0380E5D5F5308E95AA7ED -:1091E0001B1088175ADE7110CF7AD38BF4F75121F8 -:1091F0002929BC10FC820AB6EB594D92904FA1A5CB -:10920000EA803D89FFE52401BE09BEA6EF475AE387 -:10921000F7C1DDE9E7F90F3C8F70E39BB74F04F826 -:1092200008B9AECE2518CFE8F99A2F09F6E83DAA7D -:10923000F19DE560075EA7E23C6819CF1BB9F1B369 -:109240003C58E488E3E5F0F884C06B263AD9DA4864 -:1092500062C514DE3F6BF4C560FC7D8D3A967FD20B -:1092600018C5F2DE46039F4F3796E0B3AB3186DF79 -:10927000F73496E353E4F5E1D65E417B3A5E017A3A -:10928000E81AE687D30DD9847C852C95F8E0BE26B4 -:10929000FDE8BF55C17E1BE44A560EF2BD04ED73D6 -:1092A000799EDFC8FC39ED15469F7C15F2B4C943A1 -:1092B000249047D62CE66708437FB47DEE1242DE49 -:1092C000B6C9F573F49FB74BF8FAE87CB24CE77770 -:1092D00077FD884A1790D3BF1D958B58EEEB373D2D -:1092E000FC86FB047FF9DB36FADE3E9DAE9AD2D1D6 -:1092F0007689C9B13BF9F73BA6CFC8BA01CAB366B4 -:1093000064815CDF3E8B183A85E35D866C79B2FA46 -:10931000EAEF683C98376F3CD74120A7EAF59D5BA0 -:109320006CFB9831165911B7D1CB5D756AE52EB437 -:109330003312F98B2763BE31F76BEF9E678EC17EC8 -:10934000B13C21F0E23C8BEB159033979D657AA8F8 -:1093500057FF7CCCDE0BBDA771FC6F9BBD4989001C -:109360009F803C057959962073E83C4397B2F8F703 -:10937000AC775304F2FBB4187D0FF6A8C6F24D0A81 -:10938000A24909CA3FF2C7670620EF3DE7FED42E87 -:109390008AEF0FBBBC06C41BBB9EFB0BE6672853C2 -:1093A000341FF077C1BE6398B7A4C8DD1AEC789774 -:1093B0000526CF57C19E8589607C802A6A8A6725E9 -:1093C0008FAF8F3CD5322F04E7BE1227ECF5B707DD -:1093D00012B7B21D33317D51CA0F7ED1FE82168085 -:1093E000C7560F2B2F0B4C6AB1B04CEB67B37233DF -:1093F0006DBF35BB332A6743D2D4C4968397425995 -:10940000D49FD862CD26E41AAE0F48285108FCDE5E -:109410005BD669396C2BABAC4C7CEC29D6BBEEC06F -:109420005F5E1C4DE150B34FEAC410DFBE9D12AC2D -:10943000BB60EF4E94AF054982FBFE82A49484A3E7 -:109440009D7B1A0FEACDC2B926F04245C3A428BBC2 -:109450005F484B7A62B0BD9CC4EF0F1174F17490F9 -:10946000E9C74949DADE1E9776DD273289DF57835F -:10947000200579B98D9D0776D37929EFAF81585BA7 -:10948000E03C2E79CCA3637C9CFBD94F0ABB89FBC3 -:10949000736EE10E3CCF262B7001C8BF952AFA816E -:1094A000D7162637521B8AAC7DB630462D56D2E2EF -:1094B00067F4B236BB336F2AC5674BB6B3DCC4F36F -:1094C000E7A3D956369CD7ADD97BF738C8EFA92189 -:1094D0001DD77F13E6FB328B879FD83F2BEB125AA9 -:1094E0005EF7328B63ACEB7A4503FABE27C0F38E8E -:1094F000BA2EBA12D657B34D267221E34B73229D72 -:10950000AED971019CAC7B7EEB5BF3FD630979A462 -:10951000C8D4E58B08E90E9E68F151FC3FA2E9939F -:10952000803EBA833D2D405F6B67C99C9E7A5E305A -:10953000559EFF5800E35CDE027196DDCB2AAF0436 -:10954000732B4F66FC4B0912E3DA4A76B30FECF942 -:109550003FB6C8683F838B7403857BB14A0EAAF47B -:10956000B95DA3F8043E6B55511ED2F76D1EC44B76 -:1095700007DE3342DAD83D2DE3F77957829D5D5CF3 -:1095800067AE467B5B2F453FC038D2FB837912E73D -:1095900011267F27EAA442A5F566050B117FC55564 -:1095A000D7AE85764A784900F83D4F495AD8FF77BB -:1095B000991CDE2E273B7D2097234588DFED114641 -:1095C00017D63DA54817BBE53917805DD422ADDC21 -:1095D000F20BC06B76119E7B85F7EB61FD1C9F4DF6 -:1095E0007ACC07F8DBCDF1A9EC942DC8D714EFB7EE -:1095F0004A37AC06B89ED8523FDF47E19AE735DBE1 -:1096000046503C1CDF52DF129D857828F2D1EFC70F -:1096100003F52D3E8A97DD1BCD02DD569EF8099598 -:10962000EA48B4F52DE66CF09FDCB7069410FDFE19 -:1096300002F83F1EC9117CCFBE1717F5CA1113ECF3 -:10964000D226AB4FAEF8A85E28B6D59F47E5C20F2D -:109650001E5210AFFF4EC7033941D76101DDF74CF1 -:1096600052D12E08D0B904683930B908F36DE9BA7F -:109670004900EC86C92AEA7911C7D126C96837435F -:109680007DA087407E11E6CF51791D87733E4A94B5 -:10969000C5751465874979980479FEBEA42FC2FB6D -:1096A00048FC25B6BC0290BFAE3C04C5551EEFED8C -:1096B000CE97A97ECD3DBA481A47F1F25E80EF8B76 -:1096C00072E93E96BE7F3FC0FC40B7C7AD2F43BE98 -:1096D0000C31BAF3593C2A3E159EA3AE2B1E359091 -:1096E000FFA5FF7E3586F6CBBD63D4B4F960FF1AC3 -:1096F00064FE41EFD862BC57A38150FE07BE08F15B -:10970000FBF2B8FCF0707BC17D4E40C8134F365B56 -:10971000637DFBDC5139A1BE73704AC8F4813CD82B -:10972000AF4FCD027B743C9753CDA9595F05BB4524 -:10973000E5F260879F9DCBEDC9269DBB08D8BF3160 -:1097400062CF4B10F2605BA30F9F0F5F3601E39770 -:109750000F5F963707E215072E7E1FF7BF6776303B -:10976000FE3D73E805B84B899CB1A8B6311859A1E4 -:109770005F3E752FDE17F27D357E17E6CB43BE0EBA -:109780009DD25DD9CE3CCC47395CCE0578DE808752 -:109790007D17F778A867BF847EE06D7C3DBEC43C32 -:1097A000DC57821B0FCE1DFB4907DEC724E0E0BE5D -:1097B000BF433D3B85F9EB036C5F2AF297DC794AA6 -:1097C000623EFB8219EE3376E143F835041E44FB1A -:1097D0007AC91CA50F4037B5671592B4E585F49D8D -:1097E000DBD0F0FD6938EF9205F7AF243A2E29045B -:1097F0003E48A29DE80F353BEE712551B5C77EBEB0 -:1098000024E83AEFE2E617B83F18F4B4660C7CAEF1 -:10981000E57DBACD1579B998A7AE9207C0AE3D15D2 -:109820007C6B06F8E36AA998005739512D3C4F7AB2 -:109830009AEF4BD47DB7E2791E313FE18F13E59A61 -:10984000BD8BD04F57BB3B84E7796A924C0EAEF389 -:109850005907BDB23DEFD64C41BEAD672FEB6F3C13 -:10986000E080D2C7877A753EAC3FD870FE4C38672F -:109870009227D79D370EE0A3323CC07EF9C9109ED7 -:10988000D355BDB6FB53DFE2FBE365DC1E09124B8B -:1098900006782A8158376167164D95DA474AAFDC5A -:1098A0009BDC02FCB0DD656F6D0FB0726B70724BAC -:1098B0007329EA67948BCB023F437BA8C52FCACF9D -:1098C000A29CDCAEB1FB3AACA7BD06E83DDA1ECFE8 -:1098D000A75BCB4A507F2845A400E0360F1C2D2003 -:1098E000FF9EF6EE023FC38FFC896B0236B89D0ADD -:1098F0001F1907FBCA34FD598EFEC60DAF3F3A7ED5 -:1099000017E0417C9F17B91FFBA7EDD0DF41C61CB4 -:109910007A8BDABA24EF692F9E33DCE171DADBE26D -:10992000F920E7CB36D7BD1DBE44B3099B73C19F59 -:10993000EE7B9605BFAA672739F2A4C607593C5BA0 -:10994000554D7055D2EFA5EC7B80D1411BCFC7C9D7 -:109950003C4E4E86719C71BBFEE3CCE07282F07D82 -:10996000ACAAF7DECB3940FEAB3BBEE8966FBD4FED -:109970002EDFF2393DC7A5C4B3415A5E93EC5C10AB -:1099800060FC3905F87335A7D3923D773F076AFD30 -:10999000319FF967D837ACF2991704A70F9F7FBAA8 -:1099A00083623DFDE417B3CBAA999D5BDF3EED4A90 -:1099B00028D7DF51A45B69E245E2597D36E8905F24 -:1099C000F7707F51B56AA11CAB3E1BC1EF9FDF78DA -:1099D0007EC779B6FEE385F0BB18EF16977C3E7024 -:1099E000F14BDBCB291DD73FE191BDB671EA9FE07A -:1099F000E780FC545E3BF9DD047E570B496F9E22E5 -:109A0000C887BB3451565AC12E7AC42E1FCAC16EA4 -:109A1000EB6B0FF716DE15E0F5AD60FAFA4157FD76 -:109A200022D17F2ED677CF47C81F28839DA67EE2FE -:109A300015F343F975B7ECEA2F478C3F06FB13F695 -:109A4000FAB703E35F843B25EECA4E568C66FE1DD3 -:109A500003EC80EFABB180FD3EAC6F737AAD3E7B23 -:109A6000BE03DF7D709FE078FFFBC6A8235FFFE6A3 -:109A7000443D9ED3F87680D16535B5E8B1DD8ED111 -:109A80008E3CFD7FCCE3D3CEE3920CF3B8EC6F3C7D -:109A90008F42077FF6CDA3D8F1FED3CE631FF70B1D -:109AA0003FC79FF375762FC07C4342BFF57C5AD7E2 -:109AB0004F69FDCBF4E9A3CFF92AB14278CF6D927B -:109AC000DD6346CBE00FF8EA27B7BD7B39DE0B6DCF -:109AD000623E8E57E4E3F0731E9BC70C7C5F91FBE4 -:109AE000EF3BB8BF0733DCD3DA1862FBEEBB2FBC09 -:109AF0008A60FE7A28817182FDF90BA260A77FE758 -:109B0000C21A7C36E7CF88823C6A0A7FDD916F4EAD -:109B1000F70869CFC1FE91F74BCE7E59B69F47D962 -:109B20000CE751D2D41771B1CDBE3ACC03FFA2D607 -:109B3000FBE017B4DE4BC38CDE36FB1218176C8DBE -:109B40007E31F37F26C4C6B9FBC2CB089BEF6529E3 -:109B500016F7D10CFB7960F1DC1F9E118575366517 -:109B60002F88023D3767CF70AC47C9B09E5561065C -:109B7000A7CDFA17BB9EC39F793D0BD2E6C1AAB908 -:109B8000E9EF176B17788A2690CEBEA8759DFA1B51 -:109B9000AF6B14C7577588F90D361B8C8F824AFC42 -:109BA0005785D2E07C38D8DF1D21C5863C943CBC6B -:109BB000DF727865E2DF659EE44898D79146B67F0C -:109BC0007E9DDF27F5DBEAA630FAB55DE36C1EB3B8 -:109BD0002B3C909FE37F563BCFA70F26375A422C52 -:109BE0005EF3B584B3DDD2AA60DAFB4D28FCEE2A21 -:109BF0002CEC83673FFC7FCE70CB448FC3855B6BBF -:109C00007478701B8C0FAAE1929BE983C34DD05BE3 -:109C1000A67EFE7FA1B307870E2FA4AFBF15BCFEA3 -:109C20005EE9EB1980D710F8F21FF03AC7F5E6D0DD -:109C3000E025E4D81E8DDDBBE8EEE74498DDAF34C7 -:109C400051AA3B7C05C417BEA2A0BFF7F08E79EBEA -:109C5000886CAFC7F4D9E1CAB9EB30DF351EC47BDD -:109C60003C5F9363FF5E067187C5AC5DBF7972F898 -:109C7000BC14CEE67E4B6324F8115E8B5F3DE0FAA8 -:109C800048A56D5D989769BB8F4AE90FDFC3C4B8DB -:109C9000A30CFC4D0BD3CF43E033D3B8C3C5E76B64 -:109CA000F1EF0F0B9F83ADF7D970D190E485D837D2 -:109CB000E492DEBF977101C0738FCCF2398EC2ABD4 -:109CC0007CB89F8C60A5A555A376029ECA223CEF66 -:109CD0004933D6819FCC7BF5C2AD618AB7D7AEC977 -:109CE00096BC367879230CCF3396A7B70B73233CF9 -:109CF0002FB7B7BD44E03E44773D85D7BB6639BB3F -:109D0000978AA8E6D8C5B67375535CDFDDEDC74604 -:109D100022F8FD351E6F777FCFE2ED972E19B83D03 -:109D2000A963F7B950BA1B9BEE7E41C11F9DE14468 -:109D300034429FAF4B8907BF01743429C4E21E2A05 -:109D4000298478BDE8275725298DC2FD5D8F3116FE -:109D5000FCB469FA291CA89F4C7015EB11E3002B89 -:109D6000C2BD2C74FF88FBC5329390D9B04FF4C6A6 -:109D70006E65870D191DE4F0FC999975C1E446B034 -:109D8000F354BA4EDB7CBBFE6BEEFF80EF5D876564 -:109D90007D53617F380C261F1670BAC955129BFC83 -:109DA000E01F5B21A5BDDFECF208FB3B251F847B98 -:109DB000E3EA38CE84FB121EB8E7E05A9EDF44483F -:109DC00062ACFDEF8C7DC0E58ABB5DAEC2E2D1E442 -:109DD0000DC6CF7B76AD199B8E7F5EE57CFA41B8D0 -:109DE000C4919FB4247EAB07F873C9C2451E2304F7 -:109DF000DF99BCBC86CF638F96187B51A80F4E1994 -:109E0000E510874FD7914413DCEFB0A241C238521E -:109E1000E90646772B36EC97D7D1E74ECE7F8B00FD -:109E200007B6FE6EE578DDB32B300EE6BFA7D74F41 -:109E3000473BA6F3B8FE7E827EAFD591AB3683DF7B -:109E4000AB5B22FCEF32FCA412F20DBA799E480BF8 -:109E5000FDBE11E63B6F24F2F7840D1FD4837CEE28 -:109E6000D2089E97FB8F762FFE7D0B412FBD72622D -:109E7000C3478D907477AF969A0C7433B2A9EE1BDA -:109E8000E9FCE416E7FB0F43F1AC7476AE780A798F -:109E90002EEA2D560D4FBAFA57573AE59898F7081B -:109EA0006FEA54BAFB1A7AE93039B0DEFB3597E332 -:109EB00002EFBDF83E927E5FB423C2E2777B9273DD -:109EC000D6A2DEB2BC06C843311F01AF5C8BC1E92C -:109ED000DA258A43DEAE5818749D476270FDAAD712 -:109EE0007808D671EFAE9726E3DF5174E987809248 -:109EF000D0E0FBCD24E50139715C31F0F97AA3F3B0 -:109F00005EE6D749E28EE9A03F1B94B47CF50CA72E -:109F10009FD7AB565D83F36F567498FFB1E523AEC0 -:109F20002A07F952E5C17B828F35DF16BEC9B67E9E -:109F3000A1EFDCF3FA6DF5AA01F5D6D22A27DEF6F9 -:109F400068CC2EB0AE647CB89ACA9BD9485FDD77E6 -:109F5000CCA4E31F4EE65CB4855527F0F71CAFE6B2 -:109F6000BF1F971377CEA4F2E684CCFC61D63F31B5 -:109F7000B9B1E4BE780BC4794F344CFB6937ADF707 -:109F8000325FDF5B0D03EB47373D4DB8CF793FE5DF -:109F90008C234483F689FAF4FAE0FAEC2093AF6A52 -:109FA0006C1CC897EB36A4AFB709922B69BD137F21 -:109FB00055AAD3E56D7EA2333E59114FDFFE133D06 -:109FC000CCBE835E4A03E7BD59412EE7F47120A75A -:109FD0005764986F575604EBBDD372FB7510EF3B77 -:109FE0002E3BE5F30FB278FC3C8BC9E713BB9679A7 -:109FF00046029E5A251DE8E1EDECD824A0B795CD88 -:10A00000C7D08FF02D5EFFBA50FC43D04F4B8E2C43 -:10A010009E3F92E2A56B3989494666F9FF31E79F79 -:10A020005C85DD6340F5DFBBA0FF68D377D1FE50D0 -:10A03000CD715F9BCCAE6C84BCC213B2B506F3503D -:10A04000760558DE11894DB7DF2F13E0F338B17B69 -:10A0500078F8BE261E1CD08E3F4C3A6A70DCDD417B -:10A060001DE28F872B95D4E57492EFED0EE23DAFA4 -:10A070006EBEC834FE70EDC013BB8767070EB6EE28 -:10A080005856E190ECC03395F7DE59067CA4754C28 -:10A0900049277F859C7E8DFBADDCF4239EB3393E42 -:10A0A0008E27079ED7CDF73BE7735D9D733E825F9A -:10A0B0008E279B02901F4E479F6CB74BC9BCE9830C -:10A0C000E859E6FFCD34CF389FA790134079104F61 -:10A0D0005BCDE5CD5B0DF746EC7870AFFF84CCF738 -:10A0E000070FB1BCADF1F19573461A7DF4795D1699 -:10A0F00093439F375D0A3DE3EEE7EF9D0E859E1B80 -:10A100008C0E855C70B7FF00E2FC23E1EFE3E81AF8 -:10A11000C4653E8818AC4CF40570448694F373CB48 -:10A12000C41807E76E4EEC0AE0FDF6D6166F12FE75 -:10A130006EC7F15D974CB2AF6707C7FF8A25D97824 -:10A140005DCA713976C528CC2F50F0BEAED78FE4EA -:10A150002C80F2BD876490D0E4BAFA950AACEF8106 -:10A160002C9677BE62C32B680F0E97CE57D439F565 -:10A17000FF277C1DBD7696DA5306F493090EED5940 -:10A180003EB6CF892F9A0FF279D50609E5ED962CC8 -:10A1900003DFAF524D94DBA499E947E2A3F0A02A74 -:10A1A000E4182C02E0F1BFF9DF2953E39AFD7CD2D9 -:10A1B0004DDB6E9F0FF6A19B5F46EB8C8EE15E3010 -:10A1C000785E174A3C9935B24F3EBF2DD5ED1F45FD -:10A1D000AB5C9EC5ED6DCEA7623D9767B1F5513B77 -:10A1E000ED87F8F799F8FA48CC456F7247CD4F00E4 -:10A1F000FE737C681704BC54EE43DEDCF7033ACBF5 -:10A200009B637C25EC1D77FB6BD584C36E3C94551A -:10A21000E8C8C771DB21FFD017E9EBFFF96FAC2F5E -:10A2200064FDD3E98BFF0779B222080080000000AB -:10A230001F8B080000000000000BDD3D0B7854D59B -:10A2400099E7CE9DB9994966924932933738930080 -:10A250000625780321449E370991A0A803040C1A0F -:10A260007044D4282144C54ABFD2CD0D893120DAAB -:10A27000505DB4D67587885DB6D235586AD1D2762E -:10A28000B0828FEA365A45DA8D1A1FA5800FA2AD2B -:10A29000ABDB8FAD7BFEFF9C93B9F76626046DFBAD -:10A2A000F12D7C7ED733E7FDBFFFFFFCE7B0A22591 -:10A2B00085449D04FF7C49FF3B9C1A20C44FC8F194 -:10A2C000BFCA8DBD6E428E45DA93AF81AF4D5D90B2 -:10A2D000ED2344EF94C9A3B4DD3B473EAD81F2BD0D -:10A2E0007D36AF44CB2BD65F238769BB4C28F9A1C1 -:10A2F000DF9234287F097FE60EFFDEF0804CA2C596 -:10A30000B179AF867518CAC77A923502F3CDF14498 -:10A31000C60709D9AB109D9411F2F6E6ECC8265A8F -:10A32000AE7112DD3D8590B9696CBDBE8D9FB77A67 -:10A3300027D3F5F4FCBA8414D2F5DD7DFB8AF0A4B2 -:10A3400038F37B6D844CA3130402369245C86D7CB0 -:10A35000EFAB528906E3133ADFA386F145BFC3ADE5 -:10A360008444CFA5F5E368BFF2583FEBF8CBAEBC11 -:10A37000702CECFBF09533C75E3329D62F111C9659 -:10A3800049E17F5E0AF3B6C92AC075D73D498D3DC4 -:10A3900071E0A673B85AE7873F76BA8F25FCFF971E -:10A3A0006EACBCC34341B22965CEEC709CF90F93EF -:10A3B000F0DDD3E87CFA46369F759EC57C9EC3F5DA -:10A3C000D72E05F87FA6CB5E99C263A0414EAD8023 -:10A3D0007EF50E753C1D7F40BFD5739D619DBF4FBF -:10A3E000009FDF375EEB898B07FEBDA2DE4C076F57 -:10A3F00093C197A7C33C3BE3AFEF16581FC5DF31AE -:10A40000257CCF85747DC72F96559DAEE7B88DF618 -:10A41000037A7990F60B0CEF773DEFF7F6C691E9EA -:10A420007249AD793D4B8F249BE9D2461A7BE3EC10 -:10A4300067685D6748F72B2CFCB74B191CE3A5FD3B -:10A44000DFDE71EACDDB613F3B9211DED67132D3A4 -:10A4500065C6A7C02700AF2D499C4FBA9B9FA6FD9C -:10A46000DEBE344FDD4486F30721DD97CDA0F5FD38 -:10A470003DB6D22DB46A574F4A6324CE7A27A7330C -:10A480003AF0C97AF279B43D7983E103C80DF866F0 -:10A4900029A7376FCF0F5B882DD6EF0DA0832442FD -:10A4A0007EDBEAC4EF36AF13C7A95BB84809D079A1 -:10A4B000AEB3130DE0877FE8B8DEF30A766CA153E4 -:10A4C000BD6E63657D15E53F69F87A1EE674B92BAC -:10A4D000B27844F8D637C82678D62D34C3D74A9FE9 -:10A4E0004723B6DA78FB17F49C68BE2B1D113FE0BA -:10A4F000E908DFEF61BEDFDF37B67BA0BD759E5D8B -:10A50000919E11F9E0AA46335D9C6E9F6F7A830895 -:10A510008FE56173BF2BEACDFB5D4A5A66134A2A69 -:10A52000CB88EA806F1D6929799A82F2E8034B7023 -:10A530003DAF13520B729E9CBAB56451496CFC1727 -:10A54000393D7F5677EBA5202EDF505A4ABC71D695 -:10A55000F33A8793C0F7EB09E019E572F70DC033C2 -:10A56000D0EB32392E9EFF8BCFFB46C3C87CB4ACF8 -:10A570006E643C9FF07A113E6F34B427C33E8F89DE -:10A58000791F64F3825E33E2E3C457D45B56FE1D49 -:10A5900020FA4D48C791642FE8111F9087418F74AE -:10A5A000A4DB981C2F1E598F88EF6F855CB5B4AF64 -:10A5B000B36B0E233ECABD01849B28D72D34AFF365 -:10A5C000BD54060FCA7163431E83DCE0FA55E8BB35 -:10A5D0007B7F70FE5BA03FC7A7333CD4853E7100F4 -:10A5E0003CA87CBDC303FB7AD5E605F95A7E4473CB -:10A5F00018E137278DB53FBE7364F8CD4963EB3C56 -:10A600009D9CB5EEF7ED6FDF3905C67DFBDB9F3B0B -:10A610008CE32FFB229F443363E5ABEB252D1287A0 -:10A62000CF36789551C17D83058E577F3116C7F798 -:10A63000C9A4A537CEBEECE94E6CBF3454E9F05343 -:10A64000785EBB5152253A84239DC9DD6B85BCB32E -:10A6500007C62EA270F7B7B7DC168A33CE6C0EEFA2 -:10A660003FBB4369F1F84C7C853E17ED96D9C38E0C -:10A6700078EDAD7A7580F3B9B55DE80CE971C80E77 -:10A68000B2B41FED3AE6A6313ACC4C8A7E04F28889 -:10A690004C32DB61A79DD7D2DE3AEF651CEE89E62E -:10A6A0001776AD757C9DC33F1CA2F413B7DE83F50E -:10A6B000AF12A65FF5480AEAC3633BAFBD07CCB74C -:10A6C000EB17DC7608D4E4CBA9416CD7107AA50649 -:10A6D000D9EDD4BD9301EF9FD5DE7B4F195DDA71C3 -:10A6E00025DCEEA11D8E6F92D06EB1CEF32AD72756 -:10A6F000AF813C3D17C623CC5E9D4747CBA56097F5 -:10A70000B5352054C8B79202463BD5B7E1F356326F -:10A7100019EC87D0260FFD7DC2C64FD6835E262456 -:10A7200082FDDF75A83722BC09B373FB7BDC3BB627 -:10A73000D076AF825C80F1893A3654629013762FDE -:10A7400096478B9FDF26C0CF99CA29B1CF44F350DB -:10A75000C8E3FA1657B9BBA434B07702D7C17E0656 -:10A7600017B8BC3D14858B15ED1280CFABAFD86CFC -:10A770006D411C16ED15611F072F0BDE755E19C8A4 -:10A780001F87E6A24B5904CECB85948EAADC3A8C67 -:10A7900057F6DB858F017EEEAD4F0AC830DE9CC0D8 -:10A7A0009B322D2FBE3829007E47795FE1011F1DA6 -:10A7B0007FE942C94B68FF790BC6FB07E8FE5236BA -:10A7C000D071F26079C76AABC711F243986C066129 -:10A7D0000BA6B0582CF1B2EEDB3C8FB63FCFBFD703 -:10A7E000E6A6A09EF85DDF66271DF78EB6508E3771 -:10A7F0009DDA13E91F743967139295A5F5CD5509B4 -:10A8000071677C540BE5BD0F8AF13EEED20A08F960 -:10A81000992D1C9468FDD48CA405760A2F5F91981D -:10A820003F6FB3368BEEE7E21B1F5D4FC75FFEDD68 -:10A83000490BECB0EE06317FE90258DFD259A25C39 -:10A84000EE82B22F85F787F55650F955185BBF3D5C -:10A8500087CE9F21DACF58308FF63D5CD9526DA755 -:10A86000F3FFE8BBDAE649130999BEB0D2ABD1F2E7 -:10A870001319F50B52287EF6124AA7B4FC64C6954C -:10A880000B60FD3ED9C6C7BF6A33ACBFBC413F0FAA -:10A89000EA257DE5E65ABAEFB5CE814340AEEB3608 -:10A8A000E8CE2CFA3F2912E363A7A345CBA7B073E8 -:10A8B000ECAB8CE6E372BA19BD16444B408F0D9594 -:10A8C0008B69B9C450CE61E5BD9BC8D5F1E4ED6D8F -:10A8D000994CEEED4D8E5FAF64307B80C20DF54933 -:10A8E000DA11A2ED8EA3573E4A77E37C079389EEF7 -:10A8F000CC88F1DBE594872B285F12275BA71867CC -:10A9000098FEC8607287E89767803C5D0843D0ADC9 -:10A9100017A912FABBA42525321E688744ED4B40C7 -:10A920007FC8365CAF5F96AE5E44C7CB4A26E13D3A -:10A93000F4EBCF2458A6FDB53DEED8782F71BAAF11 -:10A94000290AED84F16AB2734BDB83B171E8BA3B3B -:10A950009C534CEBB6576440FDE2D29B2719E0397B -:10A9600089ED83D201F6A3D33C3697F2C1DEBEF364 -:10A970000AC17EFFA945EE96F72D7610DAEECA4C95 -:10A980002E5F02ACBFBF9AC99FC19B53223DC09F9F -:10A990004EB53464B03B031C1ED5772EBC1FDA3590 -:10A9A000F53948126DB77E4F653619412F367D3126 -:10A9B0009344A61ACAF6A80272A7E98B39F87BF568 -:10A9C0009D2F29C0A7304E80EE6BBD4BCB56016E3C -:10A9D000EDF1F14F1D725C47D317E9449F6AFC9D6E -:10A9E000C12936BE0FEB4FB7AFD8783289648E34A9 -:10A9F0009E82F54370B773B82BF1D7395FD02985A4 -:10AA0000B7CD405F4B39BD51E9877194FECB26F538 -:10AA100080BC8FCDBB09C7DF6BA778043BB02F3953 -:10AA2000007671B99DC9CFF2BE0CAF2EC5E843D0F8 -:10AA300085C0EBDE8C964ADCEF22C9DB131CBEAE70 -:10AA4000CBC4BAB83ECD6E08CBD718D627F8818EC6 -:10AA5000BF978F5F5681FCF32F4CFF50BE5901FC0E -:10AA60000B760BEC438D962CF60C5FFFCFA8EC8099 -:10AA70002FC52383FFA5EE08E80101B7E1F0CF3F22 -:10AA80000D3EC7627D79DF330AECB32901DF8632E0 -:10AA900053B15FF691682AF8B5BF4C677A6D6FEFD6 -:10AAA00054D74CE08B853602220CF60DF66AB9902D -:10AAB000B764D70B5576FAFB5099CADB00E06148C2 -:10AAC000FE469DCE58FBAACC5D0B3A689D2F89E2CD -:10AAD0007F12DAA14E62F027BE9DC1E4584598C4AA -:10AAE000B55B966532BB45C0FB7B1BAAC97B747FF7 -:10AAF000CFA533BEAC18D025C08BE06BAB9C7A8859 -:10AB0000E3F17BFCFB8F9753D269E4D4222EA7D8C4 -:10AB1000EF07A9990FEDB2B2A22512D589AB5E98C5 -:10AB20003A1EFC995B72E4C0FB94AF9648EA981F0A -:10AB3000D171EB9C018C93093AA923CE801BE04E86 -:10AB40008DA62F41EF2F746119FE805DF269B7C4A5 -:10AB5000E89004D2EA4A12CB21B18E5B72149C6F4A -:10AB6000D5E6F16961E3FAB89EB83C29FA2352347C -:10AB70009CCF4599AE7FAD4D36D4BB993EFBD0A35B -:10AB8000FD3483E2E15589D4E37A2CF6D26F78DC88 -:10AB9000C66A2FD5733BD20FE625F2B10D9DD3ECDB -:10ABA000AEA408615D74F053B37B09E7D7A8ADC9C3 -:10ABB0004007BFCE286076ED15B4F202CA94CE6A83 -:10ABC000ED7D831C7B1ED6837A213A0DF8F4A50C0B -:10ABD00062B2F31AE4508104766B76920A7286E2CE -:10ABE00009E170D045EC2E3AEF73F40B78AB916F1E -:10ABF0003EE0F0011D486A3B427F07F75B4914F4D1 -:10AC0000CDE57353D06E25A76E1D07F10A7F0AA309 -:10AC10005B3A8E938FE3443AE172EF376327F68015 -:10AC20007E12F253E0819C92713C517F505A54E065 -:10AC3000A5E583FE734BDB25B3FD03F650CC7E5AAE -:10AC4000BF793EB597A6D7F6466D5E902AB72FB866 -:10AC50009DB6AFA1F6938BEEE78F194C0F1E0CEA51 -:10AC6000722A8C379EEE83FE7428393CA9C51DC319 -:10AC700007B571C280BF2C857EDD8C3FE0DB99C9B2 -:10AC80009091E163DF06FECD4A65ED87E93D5EAF59 -:10AC9000490CDE5B2A999CB0B6B3F171D73AF5DA6C -:10ACA000AC42A37D1522408776C2EC2C19748F1F0D -:10ACB000F519C2ABFACE8634D09B9FF52D4D239368 -:10ACC0006272D4E1FCEDD8F7A91C899225DF017EE0 -:10ACD000555E9709D8CB7738185D2AE9616F06FD74 -:10ACE00066A6C4F79B27F2F564825F4DDBDDC3FDEA -:10ACF0001EC717E7A3BF9D9FC9E245A9397528D78D -:10AD00000196018AF73432A87B0D784CABB099FCE0 -:10AD100007C71793B1FF99DB0FA509EC873293FDA5 -:10AD200020E6B5DA116FB6E6E0FA45FF1539AFD582 -:10AD30001043FB9564E00E186FE5FA7C53BC289134 -:10AD4000FD3137531AB217F4B8EB524CBFBF49FD6F -:10AD500045DD38FF31367F6CDE14CA70B179E54CC1 -:10AD60004DCB44BF6F96F7E8F9F4E3A2BFCBA877C9 -:10AD700050FE53FDA4ED70A35EAA05B92DFC24E09E -:10AD80007F6F1AF077656DA6DFA027793FAB3C3A5D -:10AD9000C0FDEA035CDFA41D117663724092627A03 -:10ADA00067B8DEE276B1453E9ECECEA674AB1BED13 -:10ADB000806178CEFCAAF6655102FA98F00FB12FA7 -:10ADC000CB6785E512909FB512194F3FD3E799F5F0 -:10ADD000BD9EC9FC109D329CD16F59DC606ED701BD -:10ADE000EDFCF04D1995DF62D447920C728F8DD730 -:10ADF000CCE92178E2552540E57094DB43BB7CDA51 -:10AE00005D40171DC9A993414F74248F8D405C622A -:10AE1000C7FF5617EFA0EB1F7CD9A1F6C0B0FB18F7 -:10AE20009D542E5FDF6EA7BF3B7A256F1289ADD38D -:10AE3000BD41D256533EBE9FCB89261FDB4F932F79 -:10AE4000AA8CA3F3E735B17514F41E90EC0679577C -:10AE5000D0C8DAEDC87498F4CFA350A6E33C22FC26 -:10AE6000111269AB2983F69A1DCE41F27A258C0F17 -:10AE7000E7B55040507AC853D9F86E35225D3B296A -:10AE8000B6DF2EDBA249A027BAB25254D013277DD9 -:10AE9000E1C760BF4DFDD128806B7A7F9F1DEC3DDF -:10AEA000975FDB0DBF8B7D06646F1EC8D9947EB69D -:10AEB000BE6E0BDD1372175F570F93BF32799E0082 -:10AEC0005E4086D0F9B23615A39E12EDB332B8DEDD -:10AED000C822E127D0CE225D04F146701F599B267F -:10AEE000A0BD2FF01AB3AB264E01BBAA686BD4BE2F -:10AEF0008AF67BFAA1F8F1FA17399FD07D1C34EE5F -:10AF000023117F08BD26DA3912F8D582EE536AE3A1 -:10AF1000DBAB5413607DE572DF95B0EFA60E8524A0 -:10AF20004931F8BBFCA12320B7F27A7748001B2BEC -:10AF30009D7564FC50CAA7FBBCF546E29549E275D5 -:10AF4000376D90B5D5467EEE5018DD28E6F33DE12D -:10AF5000677CC2E305B3FDA163008FE67DDB14C00F -:10AF6000F38D3BDF51463AD7192DDCA446E6BF34BA -:10AF7000D53B23B0DFCAE576C4E39A0E2502F2A9D9 -:10AF800069F79EA80DECEC8D4405FE6FEADD732891 -:10AF90008FC227BF499B260762E3E5374524584FF8 -:10AFA0001625C63EF4FFA20AE86D2B7D839D0CF6A4 -:10AFB000CA2117E3FF0F2BDDBA44E1F8A123DC041B -:10AFC000ED3ECC4D51F5600CEECFED99FFBC4459F0 -:10AFD000DCF3445214BE5DB69E1C276DD7759EA24D -:10AFE000023DB9FC618F8FC229C31EDA0BFDD37DF0 -:10AFF0001EB58DF60D249129A8AF470987E916BA29 -:10B0000098BE91F1CB5C5FAAB003A7805C3AD7E70A -:10B01000117614CAAB430EB68F0EC2D6DB99A915B2 -:10B02000C07A883703E7CD6B8A4AE00758E78DD1AD -:10B03000955688ED47BDCE5E05E4FC1A2E6F2A9723 -:10B04000EF94DE33D041A98F9DCFE6EDDE21817FE5 -:10B0500048EBDB6A7CD89E2481BCD9CDCE29D6D0E2 -:10B06000FAEB0CF245EC238E9CA980F5B9FBFB9E14 -:10B070006572268AF427D66BC5E73C1FB3EF2EA274 -:10B080006602FEAEE8C5013ADEA1C2641C4FF0BD07 -:10B09000954FE7F9189DE7D5EF94209EE04B61F6B8 -:10B0A000A4589F68B7CB5755EB4338F4211CD6D62C -:10B0B000DB116F623D354A681CF865CBF878CF5CD0 -:10B0C000F1963240CBF7FDF415A4C7B5DD9286FEAC -:10B0D00042F72BCA5288DBE9FF2E439CF61266A288 -:10B0E00090ED3F7905F5CA257B59FC60EDDE3DF614 -:10B0F0006BDD313A0D9E786625D0D9DADE24E292F6 -:10B10000007F01E4532B9D523983744F7405CFB9EE -:10B11000A89CD451AE927010FC1421873B397F1348 -:10B1200037FBFD46BE6E316E4C7EBA90DE8327A69D -:10B130003CE3A4F05CAB4AAA0BF891C39B8E1F457D -:10B14000394C4821F86B627C2BFCFE99DBED71F0E9 -:10B150007C1BE0D9AA4F849E0D3E5C45E02BF06736 -:10B16000E7701FD2EF3E05D7DBE1B3333D5FC9E2A5 -:10B17000DA1D0EA6473ADA9C11E0EBE7D22F7A5E91 -:10B18000A2F2D293A144E17BD0B6AA09EA0FE6B1BC -:10B190007574D93615B7303D76870FF1974A987C8C -:10B1A00062F2E8BE1F3379D2A4BBD17F6C0AD7AD5F -:10B1B000C673099F4B857309127E5659EA89D1835C -:10B1C00015BF81270E28015A7F492FE38318DC9889 -:10B1D000BE12744BE51CE2BD33539C5F868300575F -:10B1E000EAD7B741FC41F8F5A90D21DD1318CEAF20 -:10B1F00099DCAF9FC6FD7A4785F36FEAD7AFD9F0E8 -:10B200006BF4836ECA7901BF825FA8FF68E2AB2747 -:10B2100038BEEFF731BDFA948FD1D59AB25EE4878C -:10B2200035EFB7201FB96B993C71F79BE52021776B -:10B2300073FB602B8E5393D27B910C7EF2BF4ADE60 -:10B24000769278DD37482DFF097932640FCFDF38E9 -:10B2500045ADFC720A571787016FF76B1FF3B73EB6 -:10B26000DC4511017C696F5146B2874F372E89BE8C -:10B270002601BED770587FB8BBFAC23F409C7157B9 -:10B280001AE6B37CB07BC937FF40FB7FB873AE0AC8 -:10B290007ADAD71E42FA19F4BB54882752F1592B97 -:10B2A000517A68EBFD55EA4C382F7BEC8229203728 -:10B2B000DFE57C79E2C7F20680CFA67F7B7C0ED4E7 -:10B2C000AF894899603F7EB8EB5FFF0A7AB171E7BA -:10B2D0003ACC4B6B7FEC976897DB223BD8EFBBD225 -:10B2E000D0CE3CFEC8B63900F7F6DE76AC3FF1C8EA -:10B2F0000E2C3FF36F8FFFE22F60778452556877F3 -:10B30000E2C7DBFEE92F40E775A92AECA3296C67A9 -:10B31000E7B982BEAD726BCF01E453412F9780DE57 -:10B320000538D533F923E8F95D7EDEB4AADADD0508 -:10B33000F2ECDD2D9EC6787146C5CFF002B11894AF -:10B3400063F512C6D9BA28D540BCA32B9954C0378F -:10B35000655254C9A7F35CD1B0670EDA3DFA3BD70A -:10B3600043FB25FB5C640BC6E520A84BFD0124755F -:10B37000424AA8183C4AFD663AFACE2F29DD1EA69D -:10B38000F201F58EC51F58D2F5C2FF801CAD730EB9 -:10B390001C0051287EEFE2F11BDA1EF54EF9FAF897 -:10B3A00071D254BF9BD32DD39B797B171504504E7C -:10B3B00024A9E30DF6E998232D5B203D29AFB1EFD9 -:10B3C00022D8C7C5C5D74C45BA80F81FE81FDD8D08 -:10B3D000E3AF85F825E5BF73FC3C2EE225BE19746A -:10B3E000FE1A3BF1B9E14BC86B0E94238FE2B8D43F -:10B3F000FE40BB2AF0CB2B1E057B64BB239C3B0D80 -:10B40000C6E9E27A6B275B37EDEF8573543A9E7796 -:10B41000C6141CA7CF9181FD75D67FFECE3629B606 -:10B420005E4AA963416FC178656ED0337A3DE227E9 -:10B43000A0E0BE4E40935CDCF7E4152531FEB5C6B6 -:10B440007D409EC1F9F06C7F65857F5AEC2BE2410F -:10B4500056786EE4F53FF36BF825BB324D7A2591B3 -:10B46000BDF2CC151F33FDFBB37750DE34031DC393 -:10B47000FCE1F74DFAF75A41C74FBD83747CED3EAE -:10B48000A67F9BF7952A40B71FB46AE43D6A8036D1 -:10B49000F3F3D7EDD2C0F598EFF294CB0B71BD8FDB -:10B4A000B9BE59B3F59DA3706E5AB82F17FDFC8F26 -:10B4B0009F72D5C338076D3684E7C19EF377B44BCE -:10B4C000C67532BF80DAC148AACDD44E6576F0EA9F -:10B4D0006DE0A7AD6D242AF07FB3857E9AF7BD821B -:10B4E000F422ECE0E0C38B5733FBD3A5BAC08F9BAB -:10B4F000C7EC5142ED51689F3E2FD2A6207D959614 -:10B50000037D3D73C52F3A418F37CF235E187FFBF4 -:10B5100018EDA97CDC8F4420CF65BBA3BBCA4EFBD2 -:10B520006FAF0978292429DC76A2DD4B8A15AEE7B6 -:10B5300056A3BDDC9C73958A7C6695074FB5A1DD4B -:10B54000D51C48C6F55CB24FBA85D9236EC2D62F3A -:10B55000217D5E12991981F8D9471C7E028E1F3B0E -:10B56000FA56023C3EFE0925445A7FC93C46AFE9E3 -:10B57000F37A518E3CF7D47CD4E3822E3D4F26A142 -:10B580003ECFB07B2515F5DA9224235EBB1D4C2FF0 -:10B59000A5733D53B495E1B793F353A7DFC6BF8AB4 -:10B5A00039FEE2D52783DEFD88E31FC508C8772E64 -:10B5B0004FD6AE8E223F35ED66E3F992B4D25B0DE5 -:10B5C000F4EBAB667A519C07C0F9C0A238F2E231C5 -:10B5D000BE8EE0C3ABB681BD7C31C53BA894BC62D6 -:10B5E0002E47295D00DCF21A43480717FB6E5021F5 -:10B5F0003FD59F49D05F1C6C5348BCB8CFE35C8EED -:10B60000FA3343651087F6677BD0CEF1CB953617BA -:10B61000F42B95D49E009E7BA29D37E8CF557B4CA2 -:10B62000FC1E2AB3D176C7B23C0CCF91DFD8179756 -:10B63000001F06D8B816BB6FB8DFCDECC685DDFAA3 -:10B6400064F043C4B9868043A42DB9DE283F7FC28D -:10B65000E11099C8E2A9D4BE77635CDB4BE701FF38 -:10B66000BE67E623CCBF6FC7760FFB997D5443F7C7 -:10B6700007769BBF28B49EE9538F1A0F1EB3FDC2F5 -:10B680002E5F590A7E65739D5B057EBBEF67D22AEC -:10B69000A467081682DF1D5E8D7820140FC00F246A -:10B6A000CCFCD2E69650243EBD2F42FE6B06FE93A4 -:10B6B00090DE310E4FE93DC2E89DE93FE1FF837C1A -:10B6C00034E61D0A3920E44BB3323001E858F04328 -:10B6D000F39C810900B7D1CA938F1D94FF817F2805 -:10B6E0001C807F04BF789E667CB2A52D5009F55B57 -:10B6F0006A88B7DDA08FACFE12AC13FC4E21D74F89 -:10B70000FA42C7FD1007B0453B21BF42C8E1E6A79A -:10B71000374F8897FF26E4B0D3CEE49B339212696B -:10B7200037D0179CF979A6E017F3795236C48F8F7A -:10B730009CF2BB791C7F74F91259A0CB41DEF4A4B2 -:10B74000605EBB881759C7FDD82F99E232C26F815E -:10B750007307689F93C5F827258BF3679688CF46B4 -:10B760004CF41FB085DF813CA344FA4BF4FB5BC56E -:10B77000AFC43C428F5AF12FCE4D603F8B26256ED1 -:10B78000D77D80C9272B3D4EE47C72147C0FDAEE06 -:10B790003FF839D770FCB2714878A2292FAECBB6EA -:10B7A000A7315E1C4C9C779087268E2AEFEE402BAB -:10B7B000CBAFFA0F9E674B564F34E559B9D5401BB6 -:10B7C000C451AB9CC15219E765712CCF1CF209E83A -:10B7D000E1C9FBBA8B217FC91F329F9764D7279B92 -:10B7E000CE2372C319A6727E639EA9FD989642531A -:10B7F000FD391BCE33D507F529A67251D70C53FB63 -:10B80000F1DD55A6F2B90F5C6C6A3F31B2D854DE57 -:10B81000D2D65B0F78397FD795A67E5576AFBD948B -:10B82000C2B5A47795397FCC02CFB4BFCA71E9B055 -:10B83000292B8878ADB29BF3882FD8678607A4CBD5 -:10B84000019C27133EDE9C635346CA6F9D4CEC7FE0 -:10B850001E10FD83C3E9813807D4501C3F53D0B973 -:10B86000285BCFB584FC3853FA4BB44E417F89EA4C -:10B8700013C1ED3B9CFF055C1C4370A95747828BAD -:10B88000E3747021142E9EAF0E17EB789B529A3101 -:10B890004FF8352818ECE38156F37D98657A1AD372 -:10B8A00043A125A7B1A3591C389CC4CE2BADF5FFED -:10B8B000C9E1F2218509E261947CFD16C7437F222C -:10B8C000BEDEF0C9C16C90DFB504FD666F4BDB27AF -:10B8D000A0B7AEB64709D0FF7D7C3FDB79BEE80359 -:10B8E000AD5E1CE7417E1EF9506B007F7FB8B51836 -:10B8F000BF9156157FEF69ADC0EF4E6ACFC1F70714 -:10B90000ADB5F8DDD51AC2763F6CADC7EFEED630D7 -:10B910005BD7307C9172B473429971E3A5D7E8F29A -:10B92000A8F044E482B8FA32E13872C388F9E51B22 -:10B93000FAA5C79F35F0EF5B591EDF51C86D9C4ECD -:10B94000A6C3F9E6E9FA7FDE4A1E7F76FCE8F948ED -:10B95000D013399539211E5F87795EE563DB57DDAA -:10B96000A54F4A0CAF189DC587539DF3E33C70D695 -:10B970002783CD60E82FEE9F88725D382DAEDD9075 -:10B9800097CDF46E7D123B8F5F6EE1EF6F6533FAFA -:10B99000FD5636D377BF4B2067D2793D5DA703CFE5 -:10B9A0000787F1DD3DB3E3C1F7AEEC80292FC57AFF -:10B9B0006FC53ACEEF1CDD63D4387C76BA71C4FE15 -:10B9C000ACFDAEE2FBFF663661EBFF7FC69FBFBBFF -:10B9D000CE83FE03C0CD6FD8FFEFAE4BA98F179774 -:10B9E00069CF66E7A1D43A27C10C34F575056CC55B -:10B9F000621260E7BEE3BC101F12790189E9D58E9F -:10BA0000712484A13C1CAE141F01A5888E6F1F9A5F -:10BA1000276A8779545B4CCF42AE0D31DCFF9087AB -:10BA2000D303EDAF2B98D7339007EB3B537A22F239 -:10BA300043E3473AA71BD6FF0CE5CC9AECBFAF9C7B -:10BA4000117C4E4EDD3B3E9E9EAC87B967507BEC31 -:10BA5000FE87989C39CDB8670ABF7A7900CFAF4787 -:10BA60000DBF7DBE51C5A53E77A54E26D4AFDBE008 -:10BA700064DFDB93537BE0FBB96B6C84A4527E8163 -:10BA80007552BED5AB08BBBFF596F09B5AA683BCDA -:10BA9000DD9E1B7A309B8EB34A61FEE29FB2B4EF0B -:10BAA0004339999F0B27F37361255BE98432D18A6F -:10BAB000715F17F07D75DA0263615FEF4BEA44F066 -:10BAC0005BBCB6880ADF54122D61F9799130F86BAE -:10BAD00099E72707C0DF4D9E40481FC6C75517C4CA -:10BAE000D19494C117C701FFFFD286F7A21FF7B206 -:10BAF000753EFE403E9EB350818FF26232FC4EB7DF -:10BB0000B205EC72DAFFFB52F8896CBAAFE35EA7BC -:10BB10006EA3EB9ABCF9BD8C0CFAFBE3FBABF05CBB -:10BB200021BA4BD615B8DFD0F7E1772FA1E35DD06E -:10BB3000E7C0F8F3054446F9BEC64EB6021F25829B -:10BB4000EF07DF889F07E6C8914CF95DD6FAF7B991 -:10BB50001EF82041BEF16BBC5EE4CF3844FE8C5F22 -:10BB60001B317FC661C99F71D84304CE851D43F93F -:10BB7000330D04F367E838C6FC990FAAE2AFA39F20 -:10BB8000CB73C7172909C64DC5DF3F281C799F8E87 -:10BB90002F5CA67CEC587F37FE9E287FE73301A7F9 -:10BBA00004F94B9F0CAD2F97E899C67E8CEF62F39A -:10BBB0001460BDC3920714AB67F93F1DE98C4E0EAC -:10BBC000E4787DD7D0A1AF2103789FF36AB7CF0186 -:10BBD000F1A41051F7E0FD1EBB637040F06121B489 -:10BBE000B3BF0B76B78D4A5EB0BBAFDEE07877C0EF -:10BBF00020B71669E63281F60639BC1862D8741F80 -:10BC0000C9E71563FEDFA72490E61D418E3638E5AF -:10BC100090DDB08FFE0476C4859C0EFB73E3C3AF4A -:10BC200030C766CA631ADE9FE703F07B68B77A47BE -:10BC3000969F00DF70A6717C2B1E7C587F3A38FBE4 -:10BC4000E1B00DE26A9512CBF3FF9BC33B9DE7BBCE -:10BC5000B1FB030E4BBEFAE25CEBBA59BEFAFDE94A -:10BC6000A19939D82F30C1785F60AF5D4B9942BF41 -:10BC7000FD5CEE58E1B289C3D9BAEFBD3CEF3E5945 -:10BC8000262D7B0CF0B7EEF71B398CCE45FB0E074B -:10BC90003BCF02C1E7A4726F0561726F454E21CFA1 -:10BCA0001F4FB703BE1AD8106485F7109E2F0938AE -:10BCB0000F831F87BB158E21125809F9DDA783E773 -:10BCC000865C6D450E9DF79A57921590FF2B9D83CC -:10BCD00007C1671DE8B31D1E47BFEFB8C71DDD498B -:10BCE000E03CAEF8C967E837B542657915641EDAFD -:10BCF0003F929E2F7F79FEE8ED9FCED47031F0C742 -:10BD0000FB3C3F5BE8A5CEBC131320CFFEBD8CCA25 -:10BD100029B97E8CC36B9940473F4F6274F4001D74 -:10BD20008996D7FD6222DE87BF2A37AC423B91E776 -:10BD300047B4C109909770A670A27F1C4047A783A3 -:10BD4000D39A1CC2F831353E9DF4E4B0F8DFE9F82F -:10BD500003EFA195FDFDF843C0539C6388F5A9B995 -:10BD60008C0EC557C0CD9A4FA4E6DA783B96AF78D3 -:10BD7000556E08E17C72CC27475D74EDFD4AFCF7F7 -:10BD80001D9E1CE5FE05BCFF5E72B83F39FEFA5EE3 -:10BD90004CC0C7FFA8F54DCDE5F43339FEFADE1EE1 -:10BDA00025FC4264F0ADF4BF831EA3789E0A78267A -:10BDB0001D83281FFB33E2AFF3AFA35E67D8F1F713 -:10BDC000D0B782BE897E4D239EDFE724C73DBF5F8B -:10BDD00046FD29F087ACE7F8E2BC9ECA0FDC6F9DF8 -:10BDE00073706526E07D1EDF771689A6C3F9E62FFE -:10BDF00092F03C60989EE4FC41E195920BFA64E17C -:10BE000020C635FA27C4970B29B98CEE86DA77B1AC -:10BE10007912DD43C8CC9546750F819485311E5843 -:10BE2000E97447658A875B383E94FC9B54B00F2BBE -:10BE3000735E3A02FBA4F0FF70089E86FCBE13AD51 -:10BE4000CF7BC73912CBED35F213E52D71F63321D7 -:10BE50002B3C21D7106F5CB3EB05EF3803BE4AC80B -:10BE6000808DDDA31EB499FCE46C72467EF27E17D1 -:10BE7000E397F73242A80F403F80DEE97CFAC252D6 -:10BE80004026D81990DF33E8494639DA9E37A3387F -:10BE90006080676DAEB02FE50476E3D7BB1F10B3AB -:10BEA0009B2493FD1A1BDF8EBF0BFC54BA5F8C8B57 -:10BEB0008F0959DAA500CFBF646897C1D70A3FFD43 -:10BEC000CE59E978FF00E0373736DE10FE13E0F98F -:10BED0001B595A3DC04DCD0CB0BC0191D73714BF92 -:10BEE000B07B8F3A63F01E2D5E92797C8DDA0DABBC -:10BEF00061BD4A12E747E2C67BE4C26E2116FB86AB -:10BF000014337F7745CE4BFF03F19FCE54C6B29DCD -:10BF1000FFE4423FF06AC9ABC0BEA9FDF1E6F76994 -:10BF2000FB3089BEF92DF40F859D91227F9932FA5D -:10BF3000750AFFF97479D6CF803D46D7536573E310 -:10BF400079E733747FB9546E5429EC5B399F5215ED -:10BF50001DAF4A2ED83F40D7F51939953C9B7EBF7F -:10BF600043181CD6BFF2870CF047ABEC8E1346B9D2 -:10BF7000658D7FDC956B8E7F7C4616FEE67C80CBE4 -:10BF8000AC0C84CBE4A7E6651BE32F43F10FBE8F17 -:10BF900025FA354C9E5AE49C906736277B6F84685F -:10BFA00024E0CDC2381283BB2EE1FB57B345199C68 -:10BFB000145A9EC59124417FBAEFD9FC4B56857324 -:10BFC00040CE405A0FCC47BDBF1CF8B65FA806E074 -:10BFD0003B570AD9D93A222C0F91B414407B9B735A -:10BFE0004086F945BC02579205E3887959D9C3CBFD -:10BFF0001D759FAEBC2E303CAE41DC1EB47F15BE1D -:10C00000BEE35EB76E33C43B92DCD1E398BFCABFD8 -:10C01000D6B8C7EDB2AE43FE7632E94579E9767F10 -:10C02000A40330BCC42B41F9FB52F8E7C017479575 -:10C030006E12A4BF9FFCF9E704DF65831B6245F025 -:10C0400035EB27BF7B3DE645FB43768B5E0A4BC055 -:10C0500047D9F5D6DFCDFACA49FAF1FE90140DE5BD -:10C060007C9979FA784EA2388EA38AA17EF0466632 -:10C070000F1F4E66FD0F27B37E6F71BDD49CA110BC -:10C08000CC8BC9723AC19EFFD8730CAE6C823EE96C -:10C09000027DE274688857A157D6EEBD9900DE9AFA -:10C0A000F72D4238FC5E62E7A4FA0A09F319C4BB13 -:10C0B0000FF593C8CBB4279991C7FC94A5CF8757A8 -:10C0C00034D172DD4BA4244ADB95CE0DD5C0FB2EB6 -:10C0D000ED2544DD44CBEDAEF08F7E02FB7885BDCF -:10C0E00037B68EDFABA59858B39B8EBFE3CA31EA53 -:10C0F00016D852F56027E40B0D6E265EC82F194640 -:10C10000BFA7283F507A7804CA74DDEB5687FFE555 -:10C1100036DA3EF725A2621B5E0F3E0AE04FE2745C -:10C1200001BFCFA5BFAFE37454B45F62E7FC3EF636 -:10C130000E180E0EEF7439D9FFAEDB5F79F934BA01 -:10C14000AEA2BEA948DEE3687BC883824C04D69EBB -:10C15000D8E2B51F07ED0370AECFF043F2147C3F79 -:10C160008970F937DDC2873363FC80F5A5BCBC8ECE -:10C17000EB2913DFC038D46FD7CAD9B13FF6F331FA -:10C18000FE5089F8C3F8790689FD8171AB63F3A08D -:10C190005C9EC7EB0E2E5F80F9DFD3EDD103C0EFBD -:10C1A00033F9B7947F81DF9D148E57D85B0EFAE97F -:10C1B0007ED23710B50D666908B4C37865242403B0 -:10C1C0009CCBBD9BDB617D1736BC9209F475735E19 -:10C1D00011D2DF2CA75AE4A224D25EA1AADE2278D3 -:10C1E0006F4C42B82CAD774620CF6DE9D07B3FE154 -:10C1F000E032CA3F5784257E0F3F1C6C30C46D452A -:10C20000FEDFB224EA5FC791DF37E731FD2EFAAFD8 -:10C21000E3F75344FDDA3C37CBCFCCBB68461E9ED8 -:10C22000C7B0BC68CAFFB3F3A6C5E40A9D17F356AE -:10C230009610CD01FB5AC2F957F0FF52ED56B46784 -:10C240009786CC76E9EF25866F7DB98476E215F581 -:10C2500023DBAD0BF3C4B9708117F500117A8AD1D5 -:10C260009590E78B41BF831CAEA5FADC603737DCC5 -:10C270007E2A1DFB65FF60ED97E7C4EEC3ACB3DC1F -:10C280008769E6F761D6ED6B736401BDF3FB30EBB4 -:10C29000F6BFD369CC0314701A7E1F6610F31F9784 -:10C2A000299103704F68D94D748FB4FDAFF8FD89A3 -:10C2B00067E1FEC494181D79AE7445597E9D867958 -:10C2C0007E05DE1415F252BA6C5330AFA82BD5A3FD -:10C2D0001AF378B6B4B5D4403B914F24EEBF2C4B43 -:10C2E000706EFCCD3C663F6F97585E97BEDC89F060 -:10C2F000F6CBE488F19EBFBF2884F97433F202388C -:10C30000CF761E5F80FCD3A9F41BA1661AC317EB7E -:10C310006F950F74BC0E18AFBA48C53C9AEA3496B4 -:10C320008FE6CF0C95DE3229366EDD7E96BF57172D -:10C33000FAE410CBC35D5406F04C24D7ADFA8BD28F -:10C34000DF3D408FC3F556B819E8CF51155A7E1D11 -:10C350001DF7E4CB0AE6DB918D9AE4A0ED7EFC822A -:10C3600057857B781D95A14535586FC77B8259F558 -:10C37000249A44EBCB5E527A20CFAF91742B304E8F -:10C38000A3458FDDE47E56013EBD69A72346970491 -:10C39000F213D52210784DBB87C545500E09F964BC -:10C3A000A56732CE2C874A85DCA5F281E5F73530CA -:10C3B000BD477E20417CE8A4E798CCFD6B947BD3FD -:10C3C00084B0B2C8FB69FB9F437B46C0730E9517D0 -:10C3D000E0C749F0FB64EC87652A4F8B21EF742698 -:10C3E00049467A1B6647F0F5950DAD9FD94D424EF3 -:10C3F00056561002EF2358F143E7433A17E77D7092 -:10C40000B402E70833F9FC9FDBB449D120E08B4448 -:10C410006C14CE9D520BEA1D27E481D2EF16298CB5 -:10C4200072F1A7BA2E035C2F242D4B160611EF2FA5 -:10C4300001DE6739FB52000F4715D509F5359030FD -:10C44000885F33BEE6BBEFB303BCE6E758F1A2DB7F -:10C4500001BE0B02C3F085F70BB404F8D2845C2153 -:10C4600066B91224A7D8FDE6CD876E03FFF874F6EF -:10C47000C9F7B2C247E3D1AFB05312E5E59DE4F28C -:10C4800078B47979271DCCAF984106AEDF2D0DA782 -:10C49000938F0F6E90730CF424E8F4699EA72FFD20 -:10C4A00092E7FD967950FFC5F425A383725E9A0149 -:10C4B000F465A083D9FB5C5199EEB394F79F01F426 -:10C4C0003025A62FA33677402904BCAB5DB23CDCF7 -:10C4D0004ECECA0820FEA7DA34C4FF34EA8171BB0D -:10C4E000D39D4FF75FE1EC6DB70710FFDF07FFA6A5 -:10C4F000920410FF9516BD53EDAEB3039D543BADB2 -:10C5000078D610FF35DE61BFDBBE0AFECF01FC0B23 -:10C51000BD320AFB94E27F42FE08E78D89F07F413D -:10C52000BEFB8CF23205FEAD781772608FCB5BEDEF -:10C5300086787023CB4B9EFAF2B8762867AD0DE271 -:10C540007D993DE9EAAFB0BE85D597F56932BCCF9C -:10C5500058B49ED6D3F29E60A81ACAEB3648284734 -:10C56000A7BD166E87F2B88DACBE7453CBAFE09DFD -:10C57000B3753AEBFFF4F14E7CAF22D2C9FB57768C -:10C580005743795D17EBFF478F5307BFBCFC48A4A7 -:10C590001D7E9FB895AD43D87D7339BDED919EF852 -:10C5A00015F6EB66FD6E38E44C66FE12B3E3E6F07A -:10C5B0007DCE7D88EDD3F7DEC5B5010AF7EB0675B4 -:10C5C00007CA0D5B5339CAD1047E5AA5D45D00DF7A -:10C5D000F9544E10C43BA5D34296B7DA43A75893FB -:10C5E000CFEC2691EF0979E78B0CF85A93CFFC0832 -:10C5F000D12E2B83B0FCE407D9BBB3221F357A3F81 -:10C6000091207E007B44FD9B203F757E510BEAD339 -:10C61000F9E788BCD401FB2A3A6FE9977FBA289ED4 -:10C620005F7E4B3EB3938EF13C7AF17B63246803CB -:10C63000FF640F100FBE03147D19EC963DF0BE9100 -:10C64000E11D923D4156D6F3F7DFDD459DDC1B6CC5 -:10C650002D761D94C05809DF55B9AC8F44D352874D -:10C66000AF7FBE9D4459FE045BFFF5ED4ACF1683B4 -:10C670001DBF54888F59E351AFD4713C09B9B194AF -:10C68000E38BF2F9E67CBAFE65CE16B41B9713A6CF -:10C69000D76F24118C6FDC68E1F335EE3FBF65B3D3 -:10C6A000411CCDCCCF6BE972D8F9FAE0C3BFA3F03F -:10C6B0006F7CC0E305FDBFB6D7DCAEF181978F304C -:10C6C000FBCBCCEF8D82DF23667EA70605E3F7FB6D -:10C6D000CFC3731B713FD0E51C7C4B27B1FD0EE926 -:10C6E0007D0BFFB9E0BE6031F8353696A7C8CB6246 -:10C6F000DE4FBB995ED6A95EE67E108ADC4FFB2F2B -:10C70000C17CF852A147B99C11FC5CCAF5FC303DD4 -:10C710005E6BF577EE433E99CA4B56FD2DF4B6B8E5 -:10C720008748C745FD4DF5F5CB1A5D6F9FCD1D01BF -:10C7300078C7F47604F9688A93CA6B1BE2EF00E0CD -:10C740006F1AC75B3BD7EB09FD03F7FAB8FE01F59B -:10C7500037F01C61B85F1035D9FBC3CE3112D8FF5A -:10C76000437873517B2A05FC7DC2ECE23C32AA3C43 -:10C77000112AB7DFCC1F416F2BCFB0DF0777B8305E -:10C78000BE20E2EC82FF5E2F6076F8B65CED3D9055 -:10C79000FFFD7CBE7E3E7EFFCDF3F1FCFBCF44C3AC -:10C7A000F36FC867CA8F937F01E7DF1D8678697FC3 -:10C7B0007AFC38F8275CFE941610FCFEC9AF7D0A9F -:10C7C000EB3FA6B038FBB164FE4D65E714FF3BD4E8 -:10C7D0009EC98F4CFE15EF911FCB30C7E7453B3FFD -:10C7E000FFBEDFEA0C7518E2E181FB935A408FF936 -:10C7F0008B785EFC7A46C7279F4ADF617C272E50E4 -:10C8000050595A300DDA694A2EC4679E62FAA2D98D -:10C810003EA0C0FB3E3E7F38A5C00FF79B88F604C4 -:10C820008C1318509650789FE4E7FE27F97B402739 -:10C830005DEC2BD6152858540AFD4EDE3C80726301 -:10C84000A8BC6800E542A02084F39E5C2AEA79F93E -:10C850006E5626DCAFACE47C8271E33871E2E171A4 -:10C8600061F37B37EB94F8E7D5A4C0638AF7AED8C1 -:10C87000CFE2902B9DA4339FD65FBD3F1BFD8DC69D -:10C88000547D02D0C3D78DE39E1CD387FBDA523987 -:10C8900038F6C1323C17C678D1DAFDCFA1FC5B2B4C -:10C8A000F866AF996F66178CEE3CC51A671F053F97 -:10C8B000CD2F18C10E7A12F4972386875B787E53AA -:10C8C0008DDC540D71A54F5713BC677BCB0B32D257 -:10C8D000D52D3F92F0DD0961C7ADE5704EB42FB89C -:10C8E000A71030C815B8A71030F875704FC158861A -:10C8F0007B0AC6F6704FC1580FF7148CF5704FC104 -:10C90000582E25D7B6439C6E5D17F14602ECDE82A9 -:10C91000B13FDC5B3096E1DE82B13FDC5B30963FBD -:10C92000250C6E9F3E2463FC1FEE2F18FBDFF0C228 -:10C930008FCBA3B06D17CB536B7751F8031DEA5A19 -:10C94000DF240A9FD51C3E70BFC138EE07A9173DF2 -:10C950000FF859DD77FD42F85EB0EF26D3B8A49BFF -:10C96000C9E316FA17E0783D09A5813F37850C1E0B -:10C9700082784773445261DE1B1E30CBEDA1F74C29 -:10C9800022E6DFD71043FC37383CEEBFA5C0E343B7 -:10C99000BACA2379C6784F8C1EDC6A14E0F09AACD0 -:10C9A000C6A38752726E1AC6799E97218641FE48A9 -:10C9B0005AB6CF920CE703167824E598E9C21530F1 -:10C9C000D3454AB1992E3CAA992ED22ACC7491AE65 -:10C9D0009D37227C336BCD74B2466E42BE1770AE6B -:10C9E000A07F01CE53E0854A802FDD27C48BADF0B8 -:10C9F0006DDCBFAD13ECFE3385EF9316F87E466613 -:10CA000055BB03585DE72C8FD93165CFB7E021B016 -:10CA1000357E2AE028EC081107A5FA1FEDE9985F9A -:10CA2000CFFC3D6A1F1C2CC0F303E6E7012581DC27 -:10CA3000BC8E84513E5D67B10F6E70DFA7807D3084 -:10CA40006CBFD43283F70BADFB057B8B18E25256DB -:10CA5000FB40DA2F453D9361BBFB859C0E7F89C669 -:10CA600090268D466EF47AB4FF02B9058EA2B3DC2F -:10CA700014378E6BF7897508B888F993488B9C0337 -:10CA8000F45C6CB5CFCCFEB5F0C745BC5DC4B585D4 -:10CA90003F2DFC182B9CE57382ED40FF53BDC28FE8 -:10CAA000EEBB0A7E17FEB3D56F1DBA170090857BCB -:10CAB000373C4E7FA77F9593BDCBC7F84EFCDEE990 -:10CAC0005B9C36523EE61DADE67B30741BDA88F780 -:10CAD0008A00645970EE4420A842B65E7A6800DE8F -:10CAE000DAD97AD98B83CFD2EF96921F0C6C82BAA7 -:10CAF000535FCA00D7A1783E61F78415DE4F29E85D -:10CB0000BC19F468B26A27EF1AE8C24935D5BBC52B -:10CB10007C5ED0133943F5BF319EEBFFA3BE775146 -:10CB2000F8BC3B7E847A456D8C67D759E1259EC35E -:10CB3000704DBAE838D8272E62D837EA4343598E69 -:10CB4000C10B55AB8CF7A644BD06EF977CDD7D018C -:10CB5000DEDF7518CBD157DE7718D71F617905F660 -:10CB60001081FC5BC547EB8DFA65880E2943951B48 -:10CB7000F6378A7D01D380FBC9EC1286EFBFD5BEA4 -:10CB80003A2CF88271435967F5FAF4B37C7DD1B33E -:10CB90001CBF64D1D90D3F6DD1D90D3FFD2C5F5F16 -:10CBA000F42CC72F597C76AF4F5B7C76E3573FCB95 -:10CBB000D7173DCBF14B969CDDF0D3969CDDF0D39F -:10CBC000CFF2F545CF6EFCEA6807BA2BA204DE97D8 -:10CBD0000874103518A0262BFD19FCF92295609ECB -:10CBE00006E17E4921F74BB66D6DA90717EA115D85 -:10CBF00009603C88FAF739B47E2261F58F742DC63E -:10CC0000386BDB980979F05E95BBEBA2E3707F6F20 -:10CC1000A2CEFC71EBBF1BB64833FFFB6B9757648A -:10CC20009ACAD3FACCEF575CD55864AA5F1E3EDF90 -:10CC3000F2EFE74D35FFBB64A19996F7206E26C64B -:10CC40007B918524AA427CA5F06E5B159C9BD9C183 -:10CC500067BE90FEB753C17E1AFD6BF45F0AA92729 -:10CC600034347E10E0A698C6775BEACFF41EEAFE65 -:10CC7000B1F1EFA112786432CEBD736B1E26B1DF25 -:10CC800088F13981AF3B37DBD0E5FD6C2BC1771ED6 -:10CC9000AB23011BBE83CEF1763E273DB1EF48ABFF -:10CCA000F93E7AA14EAA009F451DC406F1B5E04E9B -:10CCB000A26A04E34248278FE8F1E9E411E2AD8279 -:10CCC00077B91E8910FC77B2045DDCE908E4C1B9CC -:10CCD000DAF95D8C1E049D04804E52212FC8FAEEB5 -:10CCE00080155F644A94AEF591AD8519C67C54B247 -:10CCF0009BC1DD49FF8E84AFE29D667C0588A1FC67 -:10CD000015F0F5E9D7C497E20B45D37C10CF240189 -:10CD1000C8933A3866820DE011EC52D1FFAFA5CD31 -:10CD200000CEC12EF69E9AC093186F6B2B89CE331E -:10CD3000F87F4135AA019C6BE44955907FBEA30C56 -:10CD400043C6C3F0B383789321EEBDA3CB968C6F1B -:10CD500054EFA3782921E4BF372F4B2BA6F53D4193 -:10CD6000920CEF6CF5B4D9F0DDB29EA7A47AF3BBB8 -:10CD7000CAD1245B0EEE23C956815F3BFB6AFC4B94 -:10CD8000ECAC3E2A4379ECC661EF7EC8509F5E6BE7 -:10CD9000F97703892641FBE473581E679A667ECFB4 -:10CDA000C651619607148C7D39E5106FE1F4CEDF32 -:10CDB000498DD490C826BAEE73B8DCB1D251FA1DB1 -:10CDC0008B9198DAC67C03E5594F9B82F077707996 -:10CDD000453632BAD0E95FA0A7740B1D7954331DD4 -:10CDE00039E402CCC3157C25D623E66F1B93956CE2 -:10CDF000C775D9F13D6C87554E58D6E7866020C57A -:10CE00009DDB4722115AEFD0197F10B91F7F774C55 -:10CE1000272433F815D6F935E553E89CBF8D7CF20D -:10CE2000F031EF9CC6F6F999CADEB5AEEE60F4EECD -:10CE3000D9CAE81D6E74B37C2D6D61AEE15C752FAF -:10CE4000975356B879FAB46AA0E78BE49734C88F41 -:10CE5000B8FB3546FF6D630E3F0FE5AD7733F8073E -:10CE60005586674A2F6A942EFDEE3BDC98173CB539 -:10CE70008CE20BF0FF92599E4CEB33C3B1C82237C2 -:10CE80008209E06AE5D74470FD96806B39856BD1E5 -:10CE900099C355D1997C4E9FC5DE593C384661FFF8 -:10CEA0003EAFCEE098AEA9287F2F924F45D368BB06 -:10CEB0006D1A9537749DB51A83B7779690E36678A7 -:10CEC0000AF922E05FC8E1EF55BD2FC0BFF3E2D6FB -:10CED000ED2420017CFF5B033BA27B9A9037830407 -:10CEE000F096A631BA1570EE9ECDE05CA871387749 -:10CEF00071B8494402385BE9D52A9FD3BE269C7796 -:10CF00009DC3E3F159A4FCABC0795B0A7B47D931DF -:10CF10008EC1D5E11E8C829CED0ADA715F07820A10 -:10CF2000D67795B0FAFB5356E680BEEDF277E60071 -:10CF30005DB605AFCF01F9EECAE1728668EEDCF2AC -:10CF4000D8BD831A792BBE43DA1950103F9E407C1E -:10CF5000F995362BECC47926D9898C7078488D07E1 -:10CF6000076799629297F98D66F8A658E0EBFA9AEE -:10CF7000F2E1B5AF291FEE216CFD778E17EF347407 -:10CF80003B513F55DC8471F34C3ED7E685DF65BFEE -:10CF900073BD66F8BDB610E489DBAE023C13ADBBD1 -:10CFA000A795F0F75A9CFCFD16F6AECB3678D785E0 -:10CFB00096BF03EFBA2401FDB3775DB6C0BB2EF474 -:10CFC000DB05EFBA9C0BF6B4865FF9D2427C7FF0AA -:10CFD000B35A82F1F14D297F25F1E055D465D67F12 -:10CFE000413DD9F20E9B59CF65CCCB3395BDB3CC27 -:10CFF000EFB67954F66EDBFF0164680340008000F1 -:10D00000000000001F8B080000000000000BDD7D09 -:10D010000B7854C5D9F09C3D6737BBC966B3B9924C -:10D0200040124E42081B0861810483829E84406343 -:10D030004D71435151A88D40314248285E1A7FF509 -:10D04000C94282841834A0585A2F2C378BB56AB441 -:10D0500051A922DD2052FAD5964551F152BFF55221 -:10D060002F40258A177C3E5BFF79DF99D93DE76425 -:10D0700013C0E2FFF8FDF1C1C99C993367E6BDBF5B -:10D08000EFBC332184906FE8BF04CF0412F410FC8E -:10D0900081BA433D9704EDD1FA23C3EB1C6A3A21D0 -:10D0A0005677A5E139F1F7115F22562D248390546C -:10D0B000DE365DBED71E2E26644DCDAC24520CFD4F -:10D0C000B450266D4F80469590D5566F968F3E4F43 -:10D0D000A85954435C84AC6A2124388A90F6163BE4 -:10D0E000962B726CDE601A2177BE2C7BE3E82B3620 -:10D0F000CDA7B969FFDE9C5B09A1CFD7B80919920A -:10D10000479FBB9711924F88423F20D1BA5233E3D9 -:10D110002352425F98B3849049D1F9ACA9B1788386 -:10D12000A584C4253BBDF07D52ACBC13A66D6EFA40 -:10D13000DF37F4FD6FE0E782681947583BAE13BE56 -:10D14000A3EAEA04BE676C6F7E537A74AFAE7DAC1F -:10D150009A98F63E2CF61C72CE37322DE579497539 -:10D160004E5A96A71092D5FF7B5FB69047F78E4434 -:10D170008012920E653D01782A7CCCD5C9B3ECC4EF -:10D180001985B378BECACDE01B27D1CAE4FEE3B649 -:10D19000015CE3A2758510AD1BF0915D1AB3BF2849 -:10D1A0002906082923A4B32578F03D6BF4B9730A46 -:10D1B0007DDFD9BFFF4C55C679CF55552C9D4A9080 -:10D1C000B869BF442F7D5F0717A77666DFA73FA525 -:10D1D0006974BD2E4E37E477920278B5F37A8254A3 -:10D1E00037572D037CF9081941FB956BA4AE987D48 -:10D1F0004F13EF49502AE41D41DF79AC74D3760612 -:10D20000522869BBDDD8AE6620BC705C25FABEF63C -:10D210008D34F0BCBFAB12F0F8CEC841DA6DDE7AC7 -:10D22000E0A77ECF558B80635F1A859BCCD71B030D -:10D230008E6DC0DF028EB293C1B14DCADB19A6FC60 -:10D2400066D55C5E8A115291A676035FB6694EE49C -:10D25000CBB6B4EE5025AD9F28B57861A8C49195A2 -:10D26000C88F6D43F71D5E08709DB9FFC36D08350B -:10D270002D5425E04BDB133DD5A12A9DBC11F88A26 -:10D28000E7BF778C7D20BC9296A917CF236E4A2AE0 -:10D29000CE21362253BC384656D9EB9C51FCD8E0FF -:10D2A00017FA3C3E6DC64732E5FB78AF0E8FF0EFC4 -:10D2B0001B564778D0C5DBB26FFDB904449119E91C -:10D2C0007700E6A3A8BEE8FCC8D9C717C94E43BE7D -:10D2D000278A3713E4657F7AF733BEE7FD06E60B4E -:10D2E000D66FBA5C93791585CB9A17987C241E2645 -:10D2F000176C7686CF354463EDD98A97BE41D664E4 -:10D30000AE44F9D1AECE6F07F9F979A685C8123CC3 -:10D310005F6F07F9A198E447BACF62D00743E6C42C -:10D320001BE4FE9A825928CF069A67569DF1FD614B -:10D33000F5C6F77396A518EAE23D6BE6452F55A5AD -:10D3400046EBAB943A3BC8915B33D74B753AFA1E28 -:10D350005254F73AD0ABA8DB3267E27B7139A53182 -:10D36000E7B5CFA3BD0572A25D65F326EED870BE0A -:10D370008BEBA1BBB91E3AD53A37F2FEBFE6FDEF03 -:10D380006D716319C167C13506BCACCEA2F29A8E2D -:10D3900007B0D77FFF29B5EE73985F14CF96287C2E -:10D3A00080698B175B805FC5386D59F90EC0DBFA59 -:10D3B000EAC1E727F4AAE867557CC44BDFB312A3A0 -:10D3C0001CB7A5590CF89890C7E5C6B66B0CDFDD05 -:10D3D0009B3C63631EA5ABF587648274F73BE3FA5D -:10D3E000FAD3AB711DEB33D9FA07A66FD3BAA944B0 -:10D3F00088D011D6534CF5A1A6FEF9A6F6D1A6F613 -:10D4000009A6FAB9A6FE95A6FA0F4DFD6799EA5747 -:10D4100098FACF37B52F36B52F37D5FF8FB17F2983 -:10D42000C3F3F5E2D920F205F4BAB9BFA268885F68 -:10D43000A1E7237CE536F2E30F722AB43C66671855 -:10D44000F02BE8F374F1B39ACAB810F093A23A50F3 -:10D4500099962F267A7A589F998FFAA38D4E0BF5BD -:10D4600037B75F52041D5773FB70CE12031DF5E6EC -:10D47000143AC07E24CE34944BA7A20B89A418DBA7 -:10D48000B5A1D1F67CF8FFD9A58B53D37180EBDD24 -:10D49000C1E72DE4C023C37DD7223E02D49E1E1BCC -:10D4A00085931AB1A7E9C728DF6D49238138AAEF10 -:10D4B000B6F82D58FF3C937E08EC952AC687237852 -:10D4C0007F42C2128C23E6D3CEE9651DC8295ADEFD -:10D4D00001728A96B7B56462B97AAD256B218C5713 -:10D4E00063433CA58EBBD5AF4059595E04FAFBB6E9 -:10D4F000B13B340BAD279E94497022B5174AAE2834 -:10D5000087E5244C9F9FB9173EF735FDCE24E04EAA -:10D510008246C6E62A12B08E2364ED9EAC1F7AE8DE -:10D52000B86A81E275405BB177859286FDFCE03692 -:10D53000A84ADFFE11B43EBCC082F685B5BCAF057B -:10D54000EC7731EFB53FA4844B3BE6557B2D7E0A4B -:10D550008215C3EB7E05701ADE492C1AADAB7E55E1 -:10D5600002B9F6469E8AF276EB1F28438E800FF5AD -:10D5700065819EFD62AD6D25CC73603C11D952FE74 -:10D58000ED4B310EDA9943F1B906F4AC2A484274F6 -:10D59000951F76C13C9D32AB3F9777CCB7B2385AD6 -:10D5A0007F2CEF987B256DEF9C986B8175E4A5B976 -:10D5B000B4400CBA3A0CF218D6B776D170BD1E340E -:10D5C000976A0D1D77082D8B7909B4760EC09F9749 -:10D5D0002A7F9EC9EA0738DCD466DE9EC6CAB3FD40 -:10D5E0001DF3F8AFE5B9855D3A94FB8FC5CE8C414C -:10D5F000EDD3C37965FDED532AE886029D6FB27ABB -:10D60000875AE8D89BD6DA889FF2D4A61C827EA2DD -:10D610007F8D2DB01DF84351875EAAB3BB026B32DC -:10D62000AED0E8FB0189CCD1CBC97B399CEFCA973E -:10D63000707ED3E5637E99D2EF263F413B6B137139 -:10D640003BC01E89E0DBFFB90FE990E3BB2ABF6A4C -:10D650001DD02959C8F4667E549EAD50E8389B61B0 -:10D660001C5ADFDC6EC1F96DDA45F9977EEAF39B4F -:10D67000DFB180DD3C96042DB0BE312480A5872C1F -:10D68000B30050BAB91EDFC6F9B790F237FA3B20A3 -:10D69000FA68FBA5C3EBBE06BE48222AD655BF1BBF -:10D6A000E9A9715772652CFBC0966FE17E26A957D8 -:10D6B00026713F87C1D9965FD61FFE56B20CE17E18 -:10D6C00093C767CF07FF6EE7C1E030DAF4C4AB461B -:10D6D000BA05A8CCD2C99D1CFE9D24AF4F93E93852 -:10D6E0007B72EB92E1FDC6FA4FF665C0D07E3FBE7D -:10D6F0003F39DF8DFDAE08764F8761C679C395400F -:10D700000B63AB7BF700C98CD136839B413CE53F73 -:10D71000DF93AAC23CEA86C23885A17005908FB318 -:10D72000FE603003E773BE05E86204CC87D3472D63 -:10D73000D2978A7422F00DF4504BEB573430F850E6 -:10D740008310DB89E236CC7FCB2A4A27CEFE749247 -:10D750009ACFEC236F148EC43AB87FE5CD8F41BFCA -:10D76000022EB37ABC560817F87EE75E053ED0CC91 -:10D7700040DF5E077DDE9E5B770EACB374A3AF1512 -:10D78000E8CFB92BE4877E024ECE29214DC27EDA46 -:10D79000B9D06FD3CD9595A817BA08FA4B427F9AA6 -:10D7A000F16F9D62B4F708E9C2F58CEC32DAE994C6 -:10D7B0008E519FF7A3E39B23741CAF8F4B08FD137F -:10D7C000E8B4C47BC0CFA0FE078E35801C7980EB07 -:10D7D0002541D7E27901891D67B8323FE2CF66CA99 -:10D7E00083C3FBCAFC18FEAC0BF86304F2CB7CC00D -:10D7F000879BF461FBF09B8DFCD2B8F3937DC3E86B -:10D80000FC9DA5EA04C08FF87E03C737A5E3C54891 -:10D81000C71BFBF6815E1B7E33A3E36BC1D6488F2B -:10D82000D2E34D1E6D297C47D099793D4BF87ADAC9 -:10D83000737DD7C278576CEC7EDE81EFF9AE473E40 -:10D84000DB180A3A4814BEC3397CE36E89E0D90D6F -:10D85000F263568DF779D0CF3E8F7B3A9433D5BEA5 -:10D8600036302DE6D6CB06BBCF8C5F4A5FAD485F26 -:10D87000C4374D92C09AEDB6A2FE1C806EA27AD338 -:10D880002FE8FEE653C8ED3B62E1E174C73F99EB38 -:10D89000BB1BDE4FA9F611E4D3D39DD769F61371F4 -:10D8A000B3A81D1BB0EBED5841F71DEDB3D04F16DB -:10D8B0007810CF57B5CFAACE033A772ADE58FE4F5D -:10D8C00044DF703ABF9FD3F97A6E7F7571FBEBF638 -:10D8D0001615E57B678B07CB8E162F8F879663B95E -:10D8E000AA45C37EF29A4F2BD07FBF99605C6B65CF -:10D8F0004289148BAEF2FC467B7F78B311EFA9D539 -:10D9000046FF3B596F2FD37F49E5F986F644EF6810 -:10D9100043FB69C48B0F00DDDBD22A0DFD48F813F1 -:10D92000837D2BE0385D9E87F1620A4FB4AB853D65 -:10D930002BDA09A9C378AED5E467769AECD80E80C5 -:10D9400023C297C1B10BE088F02DE7F0AC667E13DF -:10D95000F77BE285DF53B47ECE7C8C8B1094572B03 -:10D96000726CA89F3BF298BDDD8F7E3275F293F208 -:10D97000FCEA354C9F0B7BFCF99C57AAC1AEDD92AB -:10D98000694139B9256D8F672BD6E3BD4C9FFABB32 -:10D990003C147F560F8F57538ACDA2EB4DE47CB3D6 -:10D9A000DA4A30FEDD91EEF4421C2CD1B3A806FB1E -:10D9B00099BE4BC8CF89DEFF23EFD51BEC0EA25CCE -:10D9C00063586764FEA536368E44241827A5D866AA -:10D9D000C09F9DE8EA79305F5B148F79B05E8E2737 -:10D9E000939D23E214663CB96B8CFA6675117BBF7C -:10D9F00037E701C4BB19BEAE2A23FD7670BA684B67 -:10DA0000DF827C68EE6F1E9F4C8937F87F1D9EC1B8 -:10DA1000E324C29F16FDC08F76C7E86FF6A3CF86BA -:10DA2000BFEEC6EF19F55D0C7F7DD2085D3C49C0A5 -:10DA30003B8207115FE47E98885B8BF114C2C6C3FA -:10DA40003AC6B7FD28FF7E99E0423FB2C0690B801D -:10DA50002C2CA0F3003A6EFB55426025ADAF4B98DD -:10DA6000D99744EB05DB6415DB9DBEA11067EEDDA5 -:10DA7000306368987EF71EA9EEA211BA38DCB6E4CE -:10DA80001B32993DA0BC13F600934BE8E7FAD74D43 -:10DA90000C69608F1711EF76025E306B17F444F457 -:10DAA00075B97FFDB3114CEF66CE25CBBA63E07F2D -:10DAB0000D6F8FCA715F3CCA6B2EC70B38BCB6772F -:10DAC000CD8AD7CB71DDF3A4587475B6E4771BC843 -:10DAD000EF51F09D1735D4DBA584CBEF47C8F75144 -:10DAE0007E2FCBAB5B3DA22CC67E9F1246F93D51EB -:10DAF000D5DA01EFE9E0EF015E7E4AF112631DCF56 -:10DB00008E60F6CDF7152F42AF6EEF7A9CE1A558E7 -:10DB1000E0E57612CBFFFD1EE0E569807B3FBD4A64 -:10DB2000C2B80FFB45B6F60CB43FA56ABB007F1127 -:10DB3000FC5C169B6FFEF91DE3E77EEEB7AEE7F8DF -:10DB4000E9E2F1F1DB397E3AB9BEEEE0F869E7FAD5 -:10DB5000FA56C04FDC99F3CDF066237E52ABE34D0D -:10DB6000F830E227A9DC889F44AF113F099ED126F7 -:10DB70007C18F1935EA022FCE2328D78EAC737A7C9 -:10DB8000F057D2609C187672765DA802F6B886CE01 -:10DB9000E9EEB5C220BEAE0A28C57AEF35F9A5A2D6 -:10DBA0004C2F6078CD9C161BEF16DE1EC8D7A40242 -:10DBB0003D9DFC20361FDB79FF63AA1667E87F5185 -:10DBC000ECFE2EDEFFF5E15AA2BE3FFDB94B1EC4AE -:10DBD0005F30AF3F41D2D20B701DEACE30C5FDB6EB -:10DBE000156C1F729B43ED86FD7CFF0AA777BB8AED -:10DBF00023F9ECE01FF171883F09C7CDE59F19EECD -:10DC0000DCFF15ECFBE52DC81E7A356DCF5B9E79E8 -:10DC1000A48E96A30B46E03CF3EBBD7B00CEB26B2B -:10DC2000CE50B67F3CCFFDFE184A6AC154E91B7046 -:10DC3000B8DDB1F7ED4529F42995836807D2890449 -:10DC4000B6533A8D5388929802EBD5705D56B06307 -:10DC500065586F17D6E34937964E1262FBD7DC1F23 -:10DC60003DAF200FC7731337FAAB29C48BA5E06310 -:10DC70007B1A51D227E0F86D7113082AFCF3C05FBC -:10DC800075666FEE009F46A3509884AC82F090EECC -:10DC9000DA87EB271EA2B278DBCD6ECC4FF8335D6E -:10DCA000DF98D35FDFE9F6FBD2E12A21498434DB38 -:10DCB00059F98B78D71628BF74E4062068A58DA87B -:10DCC000FB31E0D55F49D0FEF0BF951068C5C92E85 -:10DCD0003B87F907A73DCEBCB334CECFCED2388D2B -:10DCE00005E9A71EE736F87532EC63FA9643FFB6EE -:10DCF000E44968778AD20CD77D1EED06989F627F33 -:10DD000029F7BDD4A8DDE67C5342BBAD4D0A12888D -:10DD100053FADF96D0BE22C50C4F4E9578F2C64519 -:10DD2000C7717A970D67F12E16EF59F1F75F8C02E4 -:10DD3000FBFB970933C349F4FDAD07A99D0779346F -:10DD4000D3BCAFD7537A4A4FB579B750FA49E57E7D -:10DD500072DCDA4907EAE9AF9F8C62FCBDA365BFBC -:10DD6000BB8D0AA444C57BE104FA9E93EFDF12B990 -:10DD7000260C7663E22445853D8E2239580DF32525 -:10DD80004D16027C714F83713FB7B3B008E122EAB0 -:10DD9000C3F87E2E2955FA227936D48EDF58C0F387 -:10DDA0006A5CC40576A1F26F2D2956DE8328C5FC76 -:10DDB0004AD3A8DE4A82B820E5145A96760631F98D -:10DDC000A3D21BB4831DBB2140FC360AA707E7FB87 -:10DDD000AE81F13ACB7D0960976F3834EBA2B17414 -:10DDE000DEA1B0E205100447A5E0BA439ABC368133 -:10DDF0003EDFF9A6C50DEBDBCADFEFF449C8FFF73C -:10DE0000CC23013F85C7D6863D7619ECDE90858C04 -:10DE1000443B973A5C93B82854215ECBF8FE965168 -:10DE2000E9F8B027B43C19E0B22EE1FC9046C7AF48 -:10DE3000AD6671E71972F6F3306EA8D386F849E73C -:10DE4000F94712A945FB39659ECE5EA6FF123B99A4 -:10DE50005F19BA8E60DE535299D3EBA7DF7B22CCD9 -:10DE6000F68DEEA96671671709E2F767C8BB1C1645 -:10DE7000FABCA75A71033D2599EC73278C4749AE2C -:10DE800067231BCF359E8D9768CA83B28B79B9E91A -:10DE9000BC28FEE44405F1ECAE36E64FB94CEF3950 -:10DEA0004DDF7B59E0399B14029E4FF86E98F812B3 -:10DEB000B67AD558F9139D2D2454A5CBB7700E1002 -:10DEC0003FFCB290F909B6ACBD7698D709DF2B6953 -:10DED00010EE7AE15FFBDEBB03CA7FFF574F135D95 -:10DEE000D75FBF3ABCED518063F36D2F221D72BF27 -:10DEF0006A084C81CEE7F95A1BC2B14C63F101525A -:10DF0000DABBD75A8AEDB8AFB5768F03DB87959326 -:10DF10008083C27398A265FD0CF835247B57A83026 -:10DF200088E6CC9A44D85615ADAFBD92120E950F27 -:10DF3000E9F334D95F0CF190174822C5F7064D522A -:10DF400059FE9BF43CF0534E95847E58CE219F039E -:10DF5000E8E1C46C0BE6BFACA8BDF4C29174FCFB55 -:10DF60002A148C375457555C0EEDC30E317A715D0F -:10DF7000C7F047E114ACA2FC30E2108B279492B0BA -:10DF80003748DB877989350DF4C73C0A60985F27ED -:10DF9000C70F8F0F949686FC00D444AF118F6E1379 -:10DFA0001ECD78758DA47804FD52448A985FC7EC25 -:10DFB000C75ADE6743D544F45FEF5189DF3AAE3F7D -:10DFC000BE5EA4F6A346EDBF10B51FA1FC1BB51F96 -:10DFD000A1ECA1F62394895AC545A574BEA1743A53 -:10DFE0002EF05F4DD94AD81FB86FEAD537FD93960A -:10DFF000657C9F8D726A4A25FDCE2CE062565FAF2C -:10E00000519BE4A552D9505F9BA6887D3C3FE8D444 -:10E01000C42C0BDFE79971A746EB9D990ADFD76304 -:10E02000F511C5C450EFA9B118EAE7EDD18D3F0550 -:10E03000F01387F5092377AEF71744DBEF28A475B3 -:10E04000DA7E80DB73B54B2DBE2D31E877D948469B -:10E05000BFCABF895FA2F8FAAC80A09F2E5B349440 -:10E06000DFA4505141BEF6D7CB540EEAFDEB022A95 -:10E070005775F191C3853CAEEEAB60713612FDF978 -:10E080007A12CFB322F0BC330476C4ADAF5EE90D93 -:10E090009281E5AE355339A2A7938B051D8C2423BD -:10E0A000D19F27530E54009D754D54801E4A391F31 -:10E0B000106EC761889FD2CF539FDEFD174D053F7D -:10E0C000ADDDDD3612F37E2E1FA9CB935995BE68C8 -:10E0D00022E83391F7434895FB7DBA2EC97FA90505 -:10E0E000ECB681ED1485BCAF83476FED8C24D00373 -:10E0F0004E2EC7CDFD57B5EC7C05BEBFBAA51B4B58 -:10E10000679A0F858C5DF163FC669FA7AE11E6658B -:10E11000CFA6ED3A396C4BA3EF19FC806C667709FA -:10E120003CB809C683C4BEC986CE09F17114189DD6 -:10E13000545F807CDE109A8579159DDE0983C6AF19 -:10E140004EC5275BAB5E2269148E4FBE3AF32FB3E8 -:10E15000697910F88DEAC12738DFE4943FF6DAB523 -:10E16000067E396AE297A3267E397A0A7EB9E04EA6 -:10E1700068EFC9540CF51CE0175D7D6B845F583D5A -:10E18000CA2F47915FEE79D986F58D238F1AF865EE -:10E190004521AD67EBF865BAECDB12C30E78E53BC1 -:10E1A000E2975F9F29BFBC7166FCF2C4D9E3973F39 -:10E1B0008E4CFFEEF8C5779AFCE2EBCF2F87605EBE -:10E1C00067CA2F9DEE20E60376CEB6540762E0FBC9 -:10E1D0007A8E6F11F72EE3718A69F3B4CBC7823D53 -:10E1E000CBF3D6443E4DE73CA6BF57D4CE407DB9D5 -:10E1F000F520D397423F97713CFE8DC731CA424C00 -:10E200006FA6974BF8FE4C4D0AA8F4D74E6A12A49D -:10E2100082BE9E22912E1596BAAC76A414B59BE8C8 -:10E22000F7D06EBACFCBF266C92166EFD8E97F404E -:10E230004F17975B0D7A7588D9FE32D5C53EA6D8A3 -:10E24000BFBC0FF212283CBE1EC9ED2693BE15704E -:10E25000D870A812ED90CFB36D83EE5775F2F546E6 -:10E26000ECA9525F45AC78587DA184F0BEC9A3C526 -:10E270001796813EBE0AF5AED0E766BDDC53F59237 -:10E2800051CEF8C7A75616EBE48C7F3CEACD889CAC -:10E29000E1F501E50C3907E546442FF37A442FF305 -:10E2A0007A442FF37A44CEC0F8D951BD3CF281F1C3 -:10E2B00077FA757A7B19D4B34FAD9717707970B62A -:10E2C000E5CC1FB8BDFA5DE9E5CA424E2FFFB99C07 -:10E2D000A929FC0EE54C2DC899A453CB995A90332B -:10E2E000C506397355E1B7D0CB890DBD7ED8BFBF08 -:10E2F0006200BA77707C371568D7C0F8A4E6F4F2EC -:10E30000B6CD74D55BFBC0AA0CA0172FF3F3067A29 -:10E310003FB1F9F7AFB4E9F2A21395103B5FD1FC1E -:10E32000243E9FDB7010E365A79A6F7D21C1D2ACBC -:10E33000477B6BF7D9916EBD16DC13FFB6F3E89CF3 -:10E34000CDF8F28DED4FAF073EBA8FC7FDCC76AE5C -:10E35000C0EBE9DA3FE6EF5E3F52C571CDDF3F1516 -:10E36000DD523ADD0C747A22FBBA31E0E7C98977D5 -:10E370002500BCBE07FAF0C96F43A7AF8C64F83C18 -:10E380008D750761FCEF6ADDFF017FBEFC6DD6BDB8 -:10E39000A090D1D569ACFBBFBF4B7CFF07FEC26725 -:10E3A000DF66DDCB04BE093B2FE3865F289FACFF11 -:10E3B00057E1DB10BF58FFEFD18FC13ABBBEB26F40 -:10E3C00086F805F9FA1BD9AD3F3F45D8B99944FE07 -:10E3D0005EA28F9D877157EBCE4791E879295C0F3C -:10E3E000C63722ED07629D97FBAE4BB047DEB10EFC -:10E3F000D26E63713BF3F3FF2E90D83936A9D60164 -:10E4000079F1BDB3F760BE41E7EC09B86F65B6536B -:10E41000C47B3D2D1AC6933A5B7C58DEDE521D82CA -:10E42000B8C9932FBD25413E58E94B0DA8DFD64E04 -:10E43000FAE130CCE39B5A1A0FF5DB4D768A8BDB81 -:10E4400029DE51AFDFA9F75F9EFC4D13CA4111874A -:10E45000BA2362BFD0F7549D9F44EB400E113F0991 -:10E46000EA063F69D97AB05F7AC07EA1FDA78E5ACD -:10E47000B63ED677D65A483DD82F6B1B2CD5B1EC7B -:10E480009770416CFB85D671DFCD91680FACCC03E2 -:10E490007B86D4E9E36AA7B25F1E1EF5DDFA495711 -:10E4A0008C3A3B7E52846FB9DD32A4485B0821D997 -:10E4B000B32527869DA69C18D65F4EDC38EA5BF80C -:10E4C00049E102965F2DE86BABEAC578726735C10A -:10E4D000F8636768656A09AD3FD1602112AD5FFFDF -:10E4E000328B0B6F2827013847BB219B603DE465C9 -:10E4F00074304376FE08E2E03D55D47F52216EF73A -:10E50000E35A80EDBA8499B73928BDD4962B04FC20 -:10E51000A619F214FC4E4863F9A1B54EF2A338F0E7 -:10E52000ABA62A64E519C4AD13E562897224E54FF0 -:10E530003519F876A078B439FE4CE417BC802F73F7 -:10E540001CFA4CE3CFDB055D7DFBF833F2DF970F60 -:10E5500034CD8278EEA9E871C12815F599594F9903 -:10E56000F958D0D340F4E7043B69A2AECECFE186A0 -:10E57000F93EB513ECA48951BAE8AD9D94142BFF74 -:10E580004A9409CD7F78457F1E2F41E9C6F1129A42 -:10E5900077E1F3BB206F00D6A778519E3E5849E53E -:10E5A000708CF9ED6E597608E4E7AE96662C2F5024 -:10E5B000FAE414DAFFE916FF2180DBCE96762C9F71 -:10E5C0006CE9C2F69E968D58DED112C0726DCB0EEC -:10E5D0002C6F6BE9C6F2C17CF69D294A10C7B9E0E1 -:10E5E000241D5F474753FBE87774F83EEF43BFA114 -:10E5F0007D72B8DDD07ECEE12E43BD2CB4D1D0DF0C -:10E600003D2560686F2AA83B067CE92ADD6178EE2B -:10E610002CEE36BC77BA7EC1D9EE976B7F04B6C9B3 -:10E6200049329CBBA0AFC8706E88F2F190662A5E3A -:10E6300069FDFE441EE7E866FBE49924F283740951 -:10E64000A964601FF426B23CC8D62CF67EEB8DACD4 -:10E650007E7F0EDB3F12799AB23D42D744CA88EEE4 -:10E66000E7DF9FC8CF2915B0BCC8DCE200442448CE -:10E670002E24A8C17E4829DB2713FBDEAD3CEE70BB -:10E68000BF95EC94A83DD9AAB0F9B76A24B082F638 -:10E690006B2D66F57BAA48C002F3D7A814CFD0ED46 -:10E6A0007337EFFB4A2A89EE9793D11AEED7C87CCD -:10E6B0009F3DB2EFED7897E0BE3E87D7CA848F3199 -:10E6C0008F36B9B94F02FE1AD2DCD70BF3BBFF1657 -:10E6D0009B1ACB1FEABDE58B2CE09B4D377E910545 -:10E6E000CCBE29923FD3E7D0E7CFE472B86C6ACEB4 -:10E6F000C7FC854DF52E2F87B3C5D48EF90C9FD757 -:10E70000F3FB0988827ED1307714AE01913F22431A -:10E71000DE1D5DFF88E8F9D3FF34BF6653F37296C0 -:10E720005F934D787ECD4CF427051E364139AEFF00 -:10E73000B9DEEF3ABFE6947935A63C0703FD42DD2A -:10E740006FA66F15F112C7E95BBA99E5456499E8C0 -:10E7500046E45D08BA14F919225F43E46FD8785E85 -:10E7600007FD2CCF6B8E4D5FB63DC403E7DE644BD7 -:10E77000BC774BDEA9F3089A3DF95C392C1BC7C660 -:10E7800065F903FF334AFB85A72C3A6E9E47BB51C0 -:10E790005F17E556F875321DC21BAE027BB5A85C4B -:10E7A0006B85F37C29A504CFE994964B58161D621E -:10E7B000F5DB3C327EAFCDC3E24DA27EB1A63D0774 -:10E7C000EF2799DEBB38F29E15FBFDDE63E1A5C2A3 -:10E7D000E6CDF3906772FA5E3D5966F9D155129312 -:10E7E0001BB0A13A89EB430ABF8B89FB92025DDC27 -:10E7F000F5C71C5BB7B7B0FC3E910FFDB79765CC72 -:10E80000877696FBA6C1D9B3B2502808FBEBA5DBEF -:10E81000883B4585F98535E0C7153977EF817C88D8 -:10E82000272E647BB6171F62F6C28FCBAFC6FB469E -:10E830005C5FCB188F754F49F406E0433556A6FF51 -:10E84000453E74B9D15EA835D90B179FE2FE8F14EF -:10E85000D2E7073DF988C7148FE5F7800C24BFA3E2 -:10E86000F78030F950CAC77496BB1D10BF2E3A64AA -:10E87000C1E39EF2364DC6F3B19D2CCFE389906F74 -:10E88000D0F3A82F723886B89CF81BCF93ECE172B6 -:10E89000E2752E270E839CA0E52B3C4FF210CF9300 -:10E8A000349F97D8D152FD92DEDE319745927F1684 -:10E8B000E6416D56089EBF1BE0BE8FA2001DC790AB -:10E8C000C7B802E9676FF2DD15401CEB350BDA952E -:10E8D0005D5348562CFFAEEBC2CA41F30F3B5BE6DB -:10E8E000BCD43688DFE8B4517F26D6FB1E71AEABB0 -:10E8F0000BCF5BA4955B08E45565D9FBD8FE43AF0D -:10E9000003E97988D78EFBFB649E93BCABCB53B9EC -:10E91000DDD7350BE6FFE03605CFE7887113BD7410 -:10E920003E3A3A499BB22713E6DF39359809F64C4F -:10E93000D7F87D1B0B205FE4A04C800CCCF3B21603 -:10E94000717F96AF2B4DD1A45879EA03ADEB038FBD -:10E9500064B867C20CFF01ED0EC80818FCBC95B383 -:10E960002846FEE269CC13EDDB6F765C3B1BCF4D96 -:10E970009EE6FD17099C0EB3161207FADD408F8341 -:10E98000E0D9650D21DED62EB454C73A5F5B54C47E -:10E99000F0BDB6F453B48B4971EC7924959BE9959D -:10E9A000CDE70E858E4FDFEB2A8D3DFEE51C6F9483 -:10E9B000AE5F0379D5556D41BB22092E62C0FC1CA8 -:10E9C0006A074948EF28973E2BB5313BC1242FFAFF -:10E9D0007DBF54474FF9FDE5D0F9454E437CFF44D8 -:10E9E000F6ECA4600C3C8B52C051C8A1FE70247898 -:10E9F000FEB58BC39114C7E6EB28BE56887855DD6B -:10EA000029CEEBCD2E2A8B714E6C003C98E9E18E1D -:10EA1000853E5C1779EE35A282BE2CA5FCA88B43FF -:10EA20000C043F33BC167EC7F032B7FFA888C74737 -:10EA30004E739DA7DD8FDA456E9D5D0C87A2155A3A -:10EA40009FCAEB3FF64BE17BA85C9576FD09ED9EF6 -:10EA5000A9BCFC3194543FEE9282EFBE415F9E22EE -:10EA6000A93980B4594F8F820819B9555A66B07FB9 -:10EA70003A24EFE167302ED4970AFDA6933A852118 -:10EA80003980EBFA93146E05857529D15641D94822 -:10EA9000BA6CF05E63CF9F0EC3771A7B1C4119825C -:10EAA000933BADC7F471A36BF4E747F2E0168D6EAC -:10EAB0005B1E9DCF921DC67DD20612C2F196761BBB -:10EAC0009F9BCF8F4832050C5C4E10C97F9D82F909 -:10EAD000BDC4C1DAE3478BF3E87D85FAFBCCEA39A4 -:10EAE000BCEAEDCE20DC2F4402C6798A7B739EA758 -:10EAF00072CC3E01CFC33C0C74FC91DBEEB7507B73 -:10EB00003923A5AE11E07115516DAC647683589729 -:10EB1000B887668173B60DE0BBA0DDBC0ECD06F3F1 -:10EB2000F959D7E0EB1378FF4711C175DC5EA46299 -:10EB3000B934BE66BF06CDA5A15CFD7D104D5C3F1E -:10EB40009065A906FE7D51D023D1E4D3597F7FB8CB -:10EB500016609C4CC075603A35C6C976C121D77421 -:10EB600084DFCB7AF811A5AE04C615EBF96759E836 -:10EB70008120ECAB26B27BA0DE4DA97B03FAE71C1B -:10EB80000EBF2FD1A913A75A08EBFC78E747AFC8EF -:10EB9000F9D1F51112BE1BF2A3EB77CAEE0E58CFD6 -:10EBA000CEE70E03BD0FB42E911F4BE901E146E7FE -:10EBB000F521E837F3BC8EDE407E0A76C974B9D8F9 -:10EBC00010477986C3F19E62DFC7F05EE94BD92E0C -:10EBD000BC7F27BF7BDF503A8FBEEB25CCAB4D937C -:10EBE0004915C04FE4237CEA54D0CF4E4BF0CB2ED6 -:10EBF0005AEFBB8A78B7C034BCCBBC402A724EB146 -:10EC0000B783D24DC6F5B20FE4C9DFAF5B90BC80CD -:10EC10009619890B9347D0F28238E277D0F13224EB -:10EC20008BAF1B8350F3932FA1F3FC491C9D27ADA1 -:10EC3000E7DD90101C41F9ED8F3662077A4D4BA845 -:10EC40005B371DBE932CE37C8E503B51A172ACE22E -:10EC5000F2CF26DAE9F7867EED9C00F3C96A9E467C -:10EC6000DEA5A03C5CC4F8E4E8C35F4E8473E0F228 -:10EC7000374E2F9E33E7F4973682C1C38CEFDD1CED -:10EC80001E6FC6337FA731DD762BC4DB3FE6FE0F58 -:10EC9000D13CE82F5CC7FD8537E3991FF466A18856 -:10ECA0002F05D3F5F66DA3434BBA0C9C076A274199 -:10ECB000BEF3676E2D2919FA111FF2ED75DC6FFE98 -:10ECC00098906AA0F3EBD64C1B9242DF4F6F6570B1 -:10ECD00030CF6FEC68A69F1B4E5282D6C5CF1A94D8 -:10ECE000A00DE477C3499BE1F9DFA91DEDD79D573E -:10ECF000FFC98787A6C3FCAE24E155D0FFCAEB123B -:10ED000058E09EF36B0F9FC74070694C568842E1F4 -:10ED1000D12811DF60FD9EF9B71C13BEB34733FB4A -:10ED2000257D5AECF55DC4D7376D75CD2F81CE1A90 -:10ED30004356B4E5AFFB43C590C1ECE7C693E791FA -:10ED4000802EFED7A884111E8D27CFC7E7D3561F6C -:10ED5000B301DDC3382A7D7E9D431B02F1DA81E0D9 -:10ED6000BC9BDB418D2793893F55FF9CF17774FC59 -:10ED7000346CFF2D87DB6FF75BAA63E577358F6611 -:10ED800070199DAEF8201F684C90689B637C57F407 -:10ED9000CB4831EE5F98E7D55319BE12E67D4E158C -:10EDA000D1627D6F3187A3986F4F4A78910FE9B395 -:10EDB000AF10EE9988D4DD7DB9FA7B24B672FCF5EC -:10EDC000FC309C0BE37F7C61EC733B02CF9394653A -:10EDD000682FBF9052F734C8B77997D10AA58F2111 -:10EDE000F38216763EC53F28BEA370964960E26066 -:10EDF00070B661BB18EFA317393F523F1CF2D4AF76 -:10EE0000E2F2FFAA6D4B30EF49C8A98F36CA28A796 -:10EE10003E42DD42CB8084F6EBFC3A0A6B2A571661 -:10EE20006D9FB60FD4C15599D4064D61CF6F86B290 -:10EE3000CD6A88F78BEF2D38CCECB7859D463D57D2 -:10EE40004F3A3F01FBE0A317993CA0FC6D0379BC4E -:10EE5000E82EE338F5DB2EFA00E6576FF2CB33B835 -:10EE60007E36DB799B47F3F8FE2432E94CFCF24610 -:10EE7000A2ED188D7AC127C33CCA14E33D5BA24CB6 -:10EE80002F61F05FBEFD84CDA50E3CEE112A470A2E -:10EE9000E8B8C7A83F0EE51F476BBF1F4DF170FCD8 -:10EEA0002083CB81D1754FC1F78E1F64EBFFB4E196 -:10EEB000D345704F0C99C3EC8638387C407F8D9BCE -:10EEC0006B0FB4D2F5AEA662CA01E782E2983D228A -:10EED000EC3059BE5676D1F6C9FF58980CEB4C7BF6 -:10EEE000E807D5305EFA43091AC0ADA3421B0FF202 -:10EEF000BEA3D6E985F32A9B291996D3F7ED741C96 -:10EF0000D02781DF4EDE03DB9105DDEB2AE1DE1742 -:10EF1000F7AEDEE030BAAE760BBB27A3FD7CE26D28 -:10EF200025D1EF35EDAA7D0CE6953B9BEA0709CE8E -:10EF3000D16BE3DDBAF109B7AF1A394E8E3F3BEA28 -:10EF40008EF3E05CC27E19CDC74F1BF2D1AF1F4DCF -:10EF5000183D89FC7BF836D891027EC7A8BE22BA3C -:10EF60003CB5D1DD52D04AD7B5B4E731BC8FA361EF -:10EF70006530632EE8DB0715A647F9FCD2FE9855ED -:10EF8000A9BAA2FA77AEE4463B52D8C99713F15317 -:10EF90008CF1C2399C0F2EE7F6F1DC0406E7F9C4C8 -:10EFA0009B0BEF5D61272E0B85D9DC69DD65CB40BE -:10EFB000EF2EB126837D036B898577519AED20C1B1 -:10EFC000878D0F24FA21EEFAB1D45708831CB13291 -:10EFD0003EEB7B362EB025AFFF38D631CCAF6F2C51 -:10EFE000E4765D01D1E0FC40E3EE51781E2C2E9ECC -:10EFF000E27102CA3F3BE0F579D0FF74DDD73CE314 -:10F0000008E2B930715F999BF813E9779A760FD9C6 -:10F01000027646DA086DFC723ADEC7D6702ECA0B4D -:10F020002ADF24AA5B73C7ACB944A17CD53894DA33 -:10F030005DB47ED14377B37A7E789185D6AF7DE893 -:10F04000D14B144A9F8DA3C3EF43FD96879E66F56F -:10F0500009E14532AD6F7C683FEB0F7BD894B0B6C9 -:10F060003F74E012F0FF8F2433FB8178C35702FD19 -:10F07000343E3DCAD2A15BEFBA314C3E1E71B07E28 -:10F0800047F2C84F6701BC3DE1C259BA7DB9EBC731 -:10F09000083B96D971629DE23D92197BFCB1639861 -:10F0A0001EBD661AEB7741026977B0F3757EB0C773 -:10F0B000F6EE1A8570491993C2E145C7298D8E2352 -:10F0C000E028C613DF5D0C7A1DE4BE95CA7D9D9CC9 -:10F0D0003997E38D7EA70DBF53AC8D877BAC1A6744 -:10F0E000658F07BC517C291C5F8A1D2F57DBCCE63E -:10F0F00047C74D2E413D3311E2CA7BBFA6FDF3A2A7 -:10F10000F336D3C78C314C1E5DD3CACEF7F7258FAB -:10F11000403ABA2081D98BA494C28FCAB38D1C6E99 -:10F12000EBC624333F32828721128EDFCAE197CDAE -:10F13000FA9FE97AE7F0799CEDF5EAF0A4417C6565 -:10F14000EFCE22C4D3C6081DAC338C736485E9BDF1 -:10F1500072CA78308F9411F8DE6A07B1E373B22572 -:10F16000F25E1E7DEF82697D13811F96727B98F897 -:10F17000CFC7BC86062E2D96B6876C10975EDACD6B -:10F18000E2E4A480AE0FE863564D295F9F9BAFCFAA -:10F19000CDD61730D02739D4973B3BB13FDD46E081 -:10F1A0001E19AF78021FCFC0CFB1C603BE18081F0B -:10F1B0001D671B1F629E267846E06C9A9F8027F091 -:10F1C00031BE576CE42731CF5BC644E2B1467ECEF8 -:10F1D000FB96DFAB60EF2DBD91E211EC1FD548CF60 -:10F1E0004B7BF22CF38BA3EFB577AFF0819C4F9064 -:10F1F000541607EFA9F583FE6BDA558171AAA54F66 -:10F200003DFCA49FBEBFF8D10D2E48AEFA48E9CA16 -:10F21000003BB861FB2A17DC33F7A1E27781FCFCE5 -:10F220002820C7CC5B7F9BCB01617735727D73E46F -:10F23000B7B7CD04787CB1DD8AE70C9B76C405E3D3 -:10F24000306E720DDA63B4FE36ABAFFE04FCD8A6A6 -:10F250009D46FB69F16F3664A8484FFE6116DC04D9 -:10F260000B0E83CDB0C66D56DC4F693C247BE9673D -:10F270004813E9BB15E6677E1FE67192E2BDA95B04 -:10F28000BE0AF2FBCCED5492A03DD6D4731BDA69D2 -:10F290004D3D177E00764593299FA27E003BECC52D -:10F2A00031DC0EE3F7A40BF890403ADA37AD0FFEED -:10F2B000B2E46D3AAF63DBFEE2928AF57A7325E23F -:10F2C000E9D3EE059B9E5607D6AF1F837D10A77F1F -:10F2D0008FE157DD29B18DA15DAC6CB0065D101FCB -:10F2E00068D86CF5520D4C1A1EDEFAC0AFC1BF7C57 -:10F2F0002DCE0BA9A64B1E7EFE9573697DC963D6E4 -:10F30000B41A367D27EC730B3C41CE06D829022F68 -:10F310008B7FFFBC0DE290F01CEC5E819F258FF58A -:10F32000DAE09C9F198ED3BA7B6D980F6BC653F7AA -:10F33000DB33C004697DF04B1BD0F747BB25BCF71E -:10F34000DEFC7EFDE6E75D40870027F04305BE2238 -:10F35000F8EB87B7E0CCA74BB11FC6434E85BFC7BC -:10F3600001476548E78F3C0D7194D7E3BC0087FAED -:10F3700047AE75C17A3E5096317ABF6F5506DC971D -:10F38000576FF567B8B164CFEBEFBF1EE9F0EA83C2 -:10F39000D767B07B24B42C768FA63F0BD6F9B37B0E -:10F3A0002FC1752E22754887F5F7B1F8C6E70AA96F -:10F3B0007E2C06BFCC2D66FCF2C19638480E221F6B -:10F3C000C03E02EC9BBC28E3B9FB7EF72291E558D6 -:10F3D000FF9CC717C61547EEEDB3837DD7C47B35B9 -:10F3E0006D5B1D023C1DC9D186403C9FC2C1CFE16F -:10F3F00026C1BDEFF2C1E943189E880AFB21F81E21 -:10F40000B5C7A7C173E81FB26A8E12C37BFC7E1B0F -:10F41000F67D11DFA0F38E87FDF40F32585E9E79E2 -:10F420007D1DC5421E9010D1D3D940FCBF6D0DD2B9 -:10F43000D7678718FF34066AABB13D640D0E81F6BD -:10F4400040EF6C09E5439C61FF3C421FDBAC9CBF75 -:10F450008DED749E8AA487EF6E09EFD314F4B2E8A1 -:10F46000AE38C37E7D947E8CF745097E157ED6D559 -:10F470005C1E98D76D960F97169BFE8EC2BDE9A7AE -:10F4800015FF6EB0061EF835F033E55FBF0AFC6C61 -:10F49000C5F8C0D1DF3DF7CA1594EE8F760B3E3626 -:10F4A000CA5B331FD73F5E4662F1F151A797C4E4B0 -:10F4B00063FA3C261F3BD9B9E9FF57F2F6EA01E4AB -:10F4C000ADBFD8286F3F27C549E711D0334BF0BEF9 -:10F4D00057337C85DF6B96A399C56A4C394A7F0EFA -:10F4E000111D3C051C057D2E7E68297E2742C782A2 -:10F4F0004E051D47E8D4BC6E233CCDED5530775DFD -:10F50000FE837525F563C0CE7D560E6CA1533B4E30 -:10F51000E7722B85FFF1DFE561BED12AEE071C778C -:10F52000F7B9207F6C15F73BFA202E99147DDEE7A2 -:10F5300060F6D2715F9F2B596737BDBD4B76819DB9 -:10F54000170E90EA58F1242AB1711E6132503BDB4C -:10F55000173BCEE3A1C779BC73BAECCC6D8638708B -:10F5600017BBD77FE18ACB5CB02F707CD7883B80FC -:10F57000FF7EF66799DDEBE9D714C89358C0404089 -:10F580003E24FEBBA7D0752ED8B504F31BCC7194D6 -:10F5900045CE6DB8BFF039B9194B73FC6431C4590D -:10F5A00080DEEF353DDF7511D2D762137DD5017D49 -:10F5B00065F5A7AF1704BF8E27E3F5E7CF9673B9BC -:10F5C000375D2EBE03EC99E3D4CFC75C02B9F800D7 -:10F5D000E8DDCFC1EF07C6F0A723DD2EA9FBD0C61B -:10F5E000EF71467A177468F6F7CDE5B127FE3EE96C -:10F5F00026DAA5E1C9374AEEA1E5B1275F2B7C06E3 -:10F60000EA4FBD9AFB06E9DF7FDAEEAFD0BF39BE25 -:10F610003B0EE7737CF79F726F82FAD37198877500 -:10F620007C651CE645F9772706E03CDFF11C16B740 -:10F630006B7DF6CB12CCBF206D88C793C536668F25 -:10F64000ECFA9FB7207FFAD35D712AC4299A7627F6 -:10F65000A0DFDEF4B403F35E8E3FFBE5247D9CE97E -:10F660003F5D4FA38DC5338F2792398F033D2733DD -:10F67000FFAEE999C95B215F6E694FAF0DF607A632 -:10F68000FDF15F2520978E3FCEEC0FEACFDF0F37DD -:10F690001DCA639BEEB652787F0C3622F5C3378DB8 -:10F6A000EDBE14FCF0FE706170384EE100EBA2700C -:10F6B000A907793A103C868EB521FD7FFFE0F1095C -:10F6C000FA170DBBCE413E8AC245D2D8F3C4805D45 -:10F6D000C2F5B3E7BBBF2C017BEA68F70AB40B4E57 -:10F6E000B5EEC963BFAF74F06DD72D054F67DD73FD -:10F6F000BEB7F866F4FF16D757663EE84FE74FDD12 -:10F7000080F54712BD38DFD3E4FFE6FFDFF0FEB837 -:10F7100084FBF2A7C2FB2FFFD7E2FDCF1CEF896E5F -:10F72000C82F3BFEECBF72896EFDA75AF793FF4BC3 -:10F73000D71DB18F649F1DAEB8EF24C1109C5F5FD1 -:10F7400035809DF2EE5849E4EFA01F22F277E4B431 -:10F75000C56867C8691D6837AC22EC1E64BF6AE1E2 -:10F76000F7B1B1BCEFF66C6F00E3A28AAF7E33ADA8 -:10F770005B8737783B7004A37F2667D454439CA5EE -:10F7800075059D171DA735DDE26E55E19A764B3064 -:10F79000AE04CBB7A15C9DF1C3FDF05DC569BCAF04 -:10F7A000D669F237E20B6CC6BC62B2C70DFBD50E50 -:10F7B000AF0277B95353D678BF6DEF58B6AF1D4F30 -:10F7C0000298B779A6704A2D191C4E66F808B8F54C -:10F7D0008313F747C57DFC4A5A4708F85021D49F48 -:10F7E00064EB413F14FE8E14ECD7589316793BD846 -:10F7F0007E8A1AB9C71FF220B8BF19B96756B5A0DB -:10F800005F2AE0AC1B0FD76F86F399C257E0C54162 -:10F8100066219E1DD94E6F80CE7F95CAE0BE8AC2FA -:10F820001DEE1717F0157033E3E17DA0519D1D1FEC -:10F830002D8DF93AFE4AE2817D96E9F294B01FECF3 -:10F84000E5F204B4978F49242851FFED5845462529 -:10F85000F815C7726C0A9453FBE89A74F3BDE0A4E0 -:10F860003DF237F4A05E41920DF5633985F8FE3420 -:10F870007B96E1BD0390B74DFDF66359E576DC0F4D -:10F8800075E719DE9B99E0DA02ED07208F1BBF3F79 -:10F8900003FD9B1F641619C699F9CEB17BAFA2E593 -:10F8A0004EEE57F74DB5623CFED89FE755021C2F30 -:10F8B00054C71BFA1F24EE74202ABABE2A58DF450B -:10F8C0009EC986EF36BCBDA710E2103FF256189EC7 -:10F8D0005F5C7EA1611C9F3D1C04F2AED56A0DCF1A -:10F8E0001B9ABF204A2A21E7357F4D9489D47C0F8B -:10F8F000761BC699B87FA7A1BF37E49E0626E3848E -:10F90000C3DEE7A014F9ECB654BBDF42CBB16F57AE -:10F91000CAB0EF59F65E5D2B84A1CF3B463C400751 -:10F92000E79078DC0F1C28EFFD4B4BA00ED6F90BAF -:10F9300039E081327ED8A21258D747999D326C4B5C -:10F94000DF23D55D5E0276D6678156A85FF075B776 -:10F950000CFE64EB0E19CFD74D976B12FE0AF2B86E -:10F960005BC21CFF06A705E3F04753BA4BAED5D1E7 -:10F970009DC8DB31F371D1C48A25307E5BA6D6D514 -:10F980000BF2B4F2EF57CA31CEBB12B7F15EBAA296 -:10F9900089BEDB619F5EE425C54F935972FB0FACB6 -:10F9A000182FB9D5E27570A1807AD73DC3BA19F87E -:10F9B000DD3A8EC98DF8BF1015E241F1A975329C70 -:10F9C000B323774898D722BEB7A09CE5DBDF5E2241 -:10F9D000EE3771A7FF642CBC9FC8F205209606EF96 -:10F9E000D558D04E711DF6EE83FBC8EEF41C728321 -:10F9F00078E8A979C70FFB223D874353258A9721D1 -:10FA00009D15270A587F02F1CD1E4F55C258D46F5D -:10FA1000E59887B39CE7CFF44EFD8D07F4C7F2A2BB -:10FA2000D14306CB2F779D9488AACB33B08E5371E8 -:10FA30005E2E258CE7C55C27156C27E1F1CC1FE411 -:10FA4000E3BBE6A9AF5E0BF3D86FC57C67A2684B3A -:10FA5000601D1DA3DF543B701D84FF5D9130FEDDF2 -:10FA60003CC84FC20BD19470E64F629CC33BB2A31B -:10FA70002C19FCF2D40A2F9E1B4C7D588E9C9B05A2 -:10FA800038DC0EFFC373B597BE5A45C7DD01B2928D -:10FA9000B50709A5EF0E9B68A7A2C6C3EF3DC4F644 -:10FAA0004B2F831843BC6CEC3F2E3FD25FB36746AD -:10FAB000C7FF43C9A5AFB6C584671CEAEB8E1956CC -:10FAC000CC9F38355C134E01571783EBD7542B640A -:10FAD00044E38BEF496A2ED0DB9D705C80FAD1BF86 -:10FAE0004CAE0B96A4C3FC8363E1F97C9736642A81 -:10FAF000A5BF1E9B967B23C6491C98FF55FBF3A30D -:10FB00001BE1C8986BE6114F1BD08DA2254C8038A5 -:10FB100095FB0B940B22CF2D0A474ACFF49BB75B82 -:10FB2000A2759013AE285C35B82BB84307673BAD80 -:10FB3000D772B8FECF23F597B5017E17DA912EAEB6 -:10FB4000E53CD5964CBA20CFEE84FB814B811E4E0E -:10FB5000ECB062326B0F34821EF5D8D9DFF5490B59 -:10FB600067C2DF71197BD082F1BD37297D68401FE4 -:10FB7000C1F1087731DE8929AFA6C0F98913694A36 -:10FB80000AC06771D88670FB894282707F6A4FDA3B -:10FB9000C26915C81F2AB677F371264FD4FE518269 -:10FBA0007A9D9FFFD5CE95E1BED481F065DECF87EB -:10FBB000F8F0B92903D3415B851DEF1F6A2A5F5115 -:10FBC0000C7A62797221E663355549A8879B9A3F82 -:10FBD00043B88BF1959332517579533D104D4CD705 -:10FBE000DD237FD286ED0DCD27509ED3E9E401DFE2 -:10FBF0001CE3FB9D5D56F2D35A5A36FC5BFE69ADA1 -:10FC000013F72DDB419F34903DB6E53A7948BA3F72 -:10FC100089C8FF71147777D6BC180F72B656725F19 -:10FC200002970ECCEADE7B19ECE7D73ADC97C0FEF0 -:10FC30007F8EF71156CF715F02FBFD631F4D9A0354 -:10FC4000FBFBB559EE0DF09741AFF016CDC1F63C78 -:10FC5000F7CB509F316E06AB27323A4879347F8E0E -:10FC60001FF5B913E1F2697B4260B07B48AE6E7E4E -:10FC7000C600977EEDB284795198B841E9E79F6B51 -:10FC800086B17B710B4298A735721C8BAF67A4B00D -:10FC90003FC92BF277D346100DF657D39E72B07B37 -:10FCA0005BDF0BE502FCAE7ECA1184B8E4D2FB9E9A -:10FCB000B3813E9A2FAB85C057B3CBEAC68C2B835A -:10FCC000F84908EB5737EFC679754C70F3FB72FBB8 -:10FCD0008A217E55CFF39EEB4DF9BF8B9D7B311E64 -:10FCE000B7789B31EEB68484DF023E6DF8DDE079B3 -:10FCF000BFEF58D83C140E8FF972E84A1B9BD7F916 -:10FD0000E3E8F797A6F462DEB1E20E65D4217C1B2E -:10FD10003CE8AF64C6E3B99A5B87BE5E12EBBE985F -:10FD2000EE16AAFF29CB3DDEB2134BE77882EB1922 -:10FD3000A2846D5E3A4E2397CB9342EFD8F4F983B9 -:10FD400073395C9376B2FD6F735EEC5CD05700172D -:10FD5000BECFBC74D60B53002F029F1724906ECCDD -:10FD60005F4D215E8E172FE045C03FBADF4CDFCBE1 -:10FD70008B451702FE84E5DBC53379D1F78403EDAB -:10FD80002BF3FCAFE3FA57ACA39DD7079A7F3BD781 -:10FD9000B7677BFEED5CAE9BD721F8583C177C6CB7 -:10FDA0005EB798F799D359C8763A7426E44C23A9DC -:10FDB000F3605C96CB150167314F01AF9E01F25D98 -:10FDC00095E63F18D6A3842AF1B0FC7650A420C74C -:10FDD000BA2FC4942BA57917F63BD3F508793BD0FD -:10FDE000BA849C35AF4FC85BB14E2177C57AA75214 -:10FDF0004182F210EE7E90C07FA833D8C3157062A6 -:10FE000041BF0F64FFB9A13EDD7DA3A1FF0F3257B3 -:10FE100018DA2F54D718DA2FF2AC33D47FE4FD95DB -:10FE2000C9AEDF6C68AFD51E34B44F0987A681DD3B -:10FE3000FDB7966ACCE73EFFC3BEE7A01E6C7163B8 -:10FE40007D4F4B26967B5B54E4EF7D2D1E2CF7B740 -:10FE500078F1F97FB59463F9428B8665A8C587A5CB -:10FE6000592ECCFCFD650AD8EDE5A12EF407C68F0E -:10FE7000AFFB0CE4E1014BA03591C2E99C37997DC1 -:10FE80004E02667DFCE55B37815E77B37BE8DA7A0C -:10FE9000274B6A0C7BCE45F59DA6A317574D98C0FE -:10FEA000FEB28BC4CEBBFC6A1CCBF7C17C3D4A9B27 -:10FEB00073ECEC5EDB397324CC4F9C43D879055A44 -:10FEC00006EB68FB4C85F841FFD73A15DC8F22FC26 -:10FED000FCF0256C9A70BFBA3F0EF4775A2A9E57F1 -:10FEE0009A0D0FE97C654DC6BCD64BCAFF82F980DE -:10FEF0005738D9DFCDBA7CFFCA7FDE44DB499BBFD0 -:10FF00008C9D8710F786BC6E3913BBE12B386300DC -:10FF100079A09297FDDD9464C5ABF70744F9D771DA -:10FF2000CC1F98D9CACF0B1C2468C7097EA4EB6BE1 -:10FF300087F90BBEA8752BC1512ED0F7EBA641FF58 -:10FF4000FF0B270420E00080000000001F8B08004A -:10FF500000000000000BB55A0B74146596BED5D591 -:10FF6000AF904EE88400411E76886020AF4E271D7A -:10FF7000C26B2812C01762A3B2038A52A0189E490E -:10FF80000CCC8AA37BBAB11904D6B39B193DAEAE93 -:10FF9000E869705076D6738890B8194D980695C761 -:10FFA000ACA3514141B3D820F258133A121470381F -:10FFB00087BDF7FE5574572701F4ACC9C9B9F9AB31 -:10FFC000FEFAFFFFBEEFFDAA961D70B98300505DDB -:10FFD000B63A0F0A904E918EDA902E5BF50398FB9D -:10FFE000E178D5393017034C95DF08A696009C3D83 -:10FFF000046E1BCE1FD3AE9EDAE1C27F2E5D9660EB -:020000021000EC -:1000000000C04A3BFE8FE3B2CEBA8ABEF86F51B849 -:100010001ECC740D7F2EE35FF1BE2630E7C4C6E32D -:100020002ED4BF4BF376FA55305B009AFDB3998618 -:10003000FD8BC03C0260B7BF86C7EFF957F1788FE0 -:100040003FC0749F7F1DD3BFFAEBF8FE07FE177801 -:10005000FCA13FC4B4D5BF95AF37B89D00FD01CE1C -:10006000B5560C54F3F06834F6E286F6C999BE141E -:10007000A4664167D3813C48ED60C9C8403A5B62E1 -:1000800079E0F500A4330DAB787F59E63B2C0FFCEB -:10009000F1D991DF59A0FD64F4334329C0BD20F8A4 -:1000A0009F55F6DF17A5541AA83912CAEBBECC3EED -:1000B000B04102B81F02F9F391CEAEACB38C97E811 -:1000C000FE14E709948714F8C274391765423F9308 -:1000D000BA533C289CD0E526032C71ACB1C2700009 -:1000E00094D2B108CAD704125CCE02580C612BD04E -:1000F000FD3F5A8E45E2E4BC14200BB2F1FC6F5870 -:1001000078BE7E1DE8F9B875E50A19CAD2496E2E87 -:1001100096DB7288F07A36F951778D83F6ABB3D2DD -:100120003A89FB2E71BC67C5410FFBB6F2F3D7DAF3 -:1001300057D75315C07C9ABF2653A9DB85EB2EEF0A -:10014000D3F6A06CEA411E4E73E795F5500EFF32D0 -:100150004AE8554E9962571D64A70E30A11EA3218F -:100160003964C3751665D5A5D2BA6898A980D71722 -:10017000B7C8AC0F302BE641A8B74A4D6FED10FE63 -:100180008CF45239A1723AA0FE166D34F2B3C471E8 -:100190009CE5FE3D34F7C86F153CF39D9CDA9DDF6E -:1001A000AA09B79CA4F5AA34B9F1753CD7AA366957 -:1001B000DB7B71F356B853324E249363C118920B14 -:1001C000F2E10E93BF1D90D9DF7AB38F337E607B4F -:1001D0003FEF876DEFA1FD9FB984176E0078D23D88 -:1001E000ED85C0845F4E6FFD8A7DEBDDE44F6827AF -:1001F000E447BA1ED7A20D019E7B6DB93D1440792C -:1002000046BD4E33ED1F9542C154D2CB4570AF462B -:10021000794F6EDE7B88FC64B2DD1126B92113EDC7 -:10022000F17A9DD42E2E4F3C1E0AA6E0FCF16D0102 -:1002300099DC76EC0135E8C0F1980F14D434C699F6 -:10024000F77C32E97DBBBF89E550EFAF671AF39FBA -:100250009BD8CF60105ECBBE7E3F8387ED268A6B36 -:100260002BB43305D3A0CE8401ABCB314D4E413EF0 -:10027000BAC2E0A6EB45075C413A57719B22A7E260 -:10028000B9BCC7D5209D7B2DAA41B1519C0CC87D1E -:10029000F1BACD0C611BC6115BA6099438B98E3D2D -:1002A000170A521CD4E35A7392B0E74997EA658A59 -:1002B0005B4EABBA7513CA13DE4E726F71753FF7A2 -:1002C0003B6E13CBFDEB74DF3B6EA4E0708DF4E569 -:1002D00093FDB4BFF612D94F43B2DB86CF25C66972 -:1002E0003D2EEAEBE872D3E558EDECE2B8BF6C5571 -:1002F00017C7BDC47DAB4DA0D6A3DC3D15AEE25AF9 -:100300005CA77D35CC9B89E33A0BD2BCEEF33FF181 -:10031000947F48F632559ED0AAD0B99CA6ABDA7528 -:10032000F5AAEF78FF5EEF6BFB57B7789D0B1CB11A -:10033000EB8E2249C479303B4FD863FABC5EBD4F87 -:10034000EC9C6DC85B932EA886BC3519236DFCFD13 -:100350000AFBA386F154E7E386F9B764AE36DCBF47 -:10036000CDB5DE70FF8E9CDF1BC677BA5F34CCBF85 -:10037000AB6C93E1FE4CE53F0CF767C8A048E8730F -:10038000F952C8427E3607EA99CE8556A60F422713 -:1003900053152D89E80270337D187C4C977B54B936 -:1003A00008ED266AE91C407EDFF1D6DFF3C82E3A5D -:1003B0007E35DE99E58AE5653D4FFFD47CDCC78A52 -:1003C0007AEAC11E061409BBD5E37DAFFA4988F766 -:1003D000D1228C2778CE686332C799684A9F9024CF -:1003E000C5E2095AA489F2B1EEB77A7C299EEBFEE8 -:1003F0006805F9D107328C70758F3753CD581A784C -:10040000E8BA3BE781FCD8FE41132C223BDB8AF49F -:100410004DE4A3EFDC88D915C74F01F181F6367999 -:10042000CE1488E0F5194E5042387F861D322E508A -:100430002CBCD495370B03C48C0BA828B4E71FD36E -:1004400095429277E0E909692772B5B87423EAEF1B -:10045000A889F981C5526804CAA3A9418CF317A6DB -:10046000317FF74398F5F800442CC4FF3C008ED34D -:10047000F3C1C5F42150589FB8727201C6A7850D0B -:1004800066CF06E4B330BD7338F967FED8C3E9120E -:100490009E0B4B3B85F82934C13AAA6F743E6A35EE -:1004A0003E3614291574BEC2F4D60DCFE2FE9D8DE2 -:1004B00026D88CEB9C1CFBF82310978FB77ACA6F59 -:1004C000A579DB245028AF065A6CA12D59B47FE7DB -:1004D00000CA07FABCE59E8A1945B8EEAC22607DD9 -:1004E00043EB5F80F433D329640F53FAB30CF0B9B4 -:1004F00061BEFC9EFC33C0CF15922C6F0071A18CA5 -:10050000F7E5F1236FBE317B4D1EF313A03A6EABBE -:10051000479DC7E7B7622CA0F3BF6C0B6DE67AABC3 -:10052000669884E7AC7CC566A2FC7F18E333DC0CDC -:10053000F0A5DFCEF47FFC4EA65FF933991EF5BB24 -:10054000987EEDCF61BAF0023280FA3B59A4541183 -:100550003FBDF1D17B9C117C4425985DEFE87EBFC7 -:1005600052F3878286E34F25931D34C96EB2D3FCC4 -:1005700046344C3CF799E63121392B5EAEEA13C480 -:100580006741D3A77F185F42CF999D12CE3FD3D446 -:100590003580FC37F17C57E4D16215F2D0CEBB2D0B -:1005A000AD75033DBFAD71389D10E308083B247D58 -:1005B0004A3DF1B19AEDE4574522DFDF65EB2C713E -:1005C0003A62FC01951898676AB53C3355BE944A67 -:1005D0007E3193D61D4B767DD347B45F609FF04349 -:1005E000D4EB3C5F9C3FEDD0E4A0D3FC16AB8FFC7A -:1005F000695BCB6777DF81729831EE36AFEC8ACDDD -:100600007F9584E025FBBEF8EFCF66F07C276D3543 -:1006100007364D75E2BCFBEDBBDE27113CE03C3AF2 -:10062000350DC7F332A53D44E7BBB2A6A5531C80E8 -:10063000103FFF50CEE43D6462D3DD33AD544F4CE8 -:1006400026A78A8BBB15768C378638DFCF30BE2540 -:1006500073B061FE6DAE6CC3FD3B72720DF7F57D3C -:10066000A7BB8B0DF3C85FA9DE463E58EFB0450E21 -:100670008D90C80ECE7DB194F99F5342FC47517EB8 -:10068000562C1C4E95AD7FFE590A1B8DBB53C93F9E -:1006900013EBDA652DAFEE515CBDD7B555E0EB1B22 -:1006A000967AAF677BAB07AFB7AEC538F2078A2340 -:1006B000856FDDEB0CE239B68DBD78830BF9FBB8A5 -:1006C000A8E77A37AAD5BB897674C55E2597B09F0F -:1006D000FD32503DA4D7BD897604F094560708FA40 -:1006E00053FD7DC627226F7D437EDF2FDEBE351A88 -:1006F0002A32E499422BE617D44FE7DF64D84C172F -:100700002EE139743D64C7EC1F1EDEF4FEA012BE5C -:100710001EA0BAB68AF202AE9FEC91C4BACB76BDE7 -:100720003F2823761F561E35CC8727A53D86F19A94 -:100730002CE3F899C97BE29FEF2D1E556E7CD4AA5D -:10074000629CAE7C4EE27C95785F3FCFD4DD490A57 -:10075000C54D73B38DFBA92AA7028A83AA26CC2391 -:100760003DE4753D3ECC91A1A6A73837405B77FAB2 -:10077000EE24907FC6BA87D156E83C81FF12F9E695 -:10078000705F057C71FB647944FDD79156F74F3F4C -:10079000E0BC8E3F839B44DF9126E26E41C34993C8 -:1007A00089F25F1F612F05CE88291D69745172007F -:1007B000D09FAA17A7044C85787F78E7677654FD09 -:1007C00028CFA017EDA8B72F4C2643FE8952CCC3E3 -:1007D000B1677BE61CCA3F77EC4E0A9B7E063F1E44 -:1007E000AA399016960BBF7F90EC46ECA300FA470F -:1007F000F5EF40DF57A13841FCD378A967C8E1E79E -:1008000070DDEAFD220EE06D47623F7B7F5C3F0BAF -:100810001B85FFDAF197EA9D2A084D73106E10468A -:10082000FF875FCEFF67781C195CE7909FDFDCDDF8 -:10083000AF75BFAF3E28FCFE6CF3F79F509C3F8B1B -:10084000F92FDEEF75B9E9FE5EFD82CC7EA95F3F30 -:10085000D32CDF1AEA41CE65BA5F296EF6D75AA7C4 -:10086000D8B776E2F9BB29CFD5B6A086A4EEFBE8CF -:10087000B47A9D0CAEB87DB6EDB42D0A39627C44D5 -:10088000F5FCDAF27DFAE43C415753FE853A2DFE41 -:1008900088BA06F3AA2583F2EA4CC9BD05C9C196F8 -:1008A00081E524BF8312845D1E5EE25E3B9EEF1EE7 -:1008B000B11C5D77507D06993966DAE76E4DAFF76A -:1008C00068F8D2AC96592328DE7FD6B0E0A042511A -:1008D000CE93CDFBFD1A025C1F1E4CF30D5D4175DE -:1008E0006850D8F9C1B4CE76C2A30E4E4C9682128F -:1008F000AFBF26BEFE3B68F10DAD61BE345C4A1948 -:100900002D5F4EFE09FDB21617519F0149F477EC99 -:1009100007E641CF30CEB018427B14DCB7CA1DE6E3 -:100920003A7529085C20B1BEAF9AF0AD95F24362EA -:100930003F3AB969D721A9A0071C23C16EAF855BD7 -:1009400024F6C1BDE10F3FA6FBB678E2F0C3C47A3E -:10095000FD4A5DAAD7555B92439BF13CEF4EFCB735 -:10096000334B71BC724BB293FAEED3AFD802149FE3 -:100970004F6FB68524BC7F3ABDB38DFA90D3DBF3BD -:10098000DDB802549A5CFFF906E5F93F59D82E000C -:10099000DCC23FAED8E9634728DED56E499180EAD4 -:1009A0006B55DCD77B40F9F514AE1316EF1814B273 -:1009B00049B13C43FEE1C2D2E2D4CB490A15FDA7BE -:1009C000F7DDD397F0AB76D39BC3180F939F3CF220 -:1009D000383EB7F4B5140FD5139007ACB7459B4715 -:1009E0006DA2FAF8258BBA97F8AF78FDCE8159B48D -:1009F000FEA7FD81F88936EF1840F551AC6EEFB9CE -:100A0000DE3BDB9CDD17F26272D2F1C4757F5CEDD8 -:100A100023BD274B2EBE6E861A6530D945D34CA018 -:100A2000753DB2A4905F76AE4FE63A35D1EE8E7842 -:100A3000449FB24CC71FFA813D93FC47059643740F -:100A40007DEEE60D28A71F3CE95ABEEE1C79777EA5 -:100A5000BC7DB655BD43F6B9D1C6B8487B92B16EE0 -:100A6000D0E9FF7AD2789F4AFB39030E51B5EAA24A -:100A7000719C87FD1E3EEF09BA8A1F45BA42937FDB -:100A8000D7685F87079F5F52FFFBB73E60B96CFC7A -:100A9000C72F68DF7D0E81C77C20E497D80F54DA1A -:100AA00005EE01B089CFAB5F3FF9F2E70564872718 -:100AB0001B7347921E17C8AD275E423ECFA4B41EDB -:100AC0007902E9F67D9FB05E12CF9B88DFB44B12AE -:100AD000F3BB8CF8C0EBF77A7D72717F7667EEE33B -:100AE000166CC867F94D95F3FA921EA3A77BE957D8 -:100AF000B473EAEBEBE7D3D7D7E7398B85BE3ED4A7 -:100B0000F0F70E6BEB19D26FC75BB912E18357AEEA -:100B1000A7B716A4C5D9CB2F85CBDFA7E123874C78 -:100B2000AB7F63457B6CAF7FD6A2C6C7BD9F88C72E -:100B30005FA907157039078854C2790B9933E37898 -:100B4000A23E2667C0F104ED78129D07FD72A24611 -:100B500061899AC9783BAD873409423C0E4E76BB19 -:100B6000884E927C8C7BE87DC334A819427C98EC3B -:100B700011C609D7103E8975CBACB4B57766E17E56 -:100B80006BFAC35AAA67D658845F04E627733FA757 -:100B9000CB49CF33E0CC33E497354E7099719DD972 -:100BA0006658674917F36E44391FDCB7E07DC25DB4 -:100BB0003F37D7F4A77D0F3B9ECB974C54E7855228 -:100BC000A867FCE2933F79FF8673BF046522D515C1 -:100BD000F7EEB573DC4FC4271682CAE34A8858CEB5 -:100BE000E1735F8DFD71CB6E88F1F5D5B81F1AA941 -:100BF0004FB83FED292F3D1F28871CCA4BE7935262 -:100C00000B889F5576411FEB93BA99E869A723405B -:100C1000B8ECF9A46121CAA72F49EA8364CFF81C74 -:100C2000F7B18123C921CA778FC96A15E3D0695604 -:100C300090707EB4BF26970E60B9442DDAFCEF5C4D -:100C40003C2EA9F0304E09E75D1C97C727E49D9222 -:100C50005C93E8CF2E8BF9133BCD86BC5352A8E1B1 -:100C6000397F77719D3AE982F9AA79E952B1E8773B -:100C70004BFA996A7AAA179FD5EE07212C0B9C474D -:100C8000D40BE3AFD89722931EABB47115E535B4FE -:100C9000AB68AA3D2023BFE39B859D8D37877711E5 -:100CA000C5280BABA8BE68C2BCA79F03E30A64E6D5 -:100CB000B23D8CD3ED14D79A8BF3D64A35DCC7D826 -:100CC000A9AE41BA416AE573FC0A3A992A5A3E2F05 -:100CD0000737D329E0638A76CAF456A8637A3BD4EF -:100CE000339D0EAD22FF8F0E0739AFC1934EEE0735 -:100CF0006FAB3451DD51F2EB9EFB87462D9EF42EF7 -:100D00000774BCD29F2E876980FE97DD833C86E402 -:100D1000701C499447A29F4E8488CC7E4A01229B36 -:100D2000F00317FB6B05283C9E7A9D72288BA86602 -:100D3000C66F12E551D1B35DECD4ECA2966CAD7FD9 -:100D40004C4F5DC52E1EEBFA42FFCAA43A34518FB8 -:100D5000FAF592E4F22E1786E22F761C9F63C6BC4A -:100D600054525CBE221BC7EDC5DFCF31633E2B1949 -:100D70005FBE63388ECFECF8418C0BCB8B2D6EECC5 -:100D800062569F9F3305E7ABE49F8544D10F299EB0 -:100D9000A9A23F5EA9D531EAEADFB89DE82FEA5063 -:100DA000879BF8B463B19F847294B3C57BC761B766 -:100DB00086775B70DE718B7A90FC77B93D9CEA4256 -:100DC000F9AF5C3D752085CEA7AD62BECD26705AC9 -:100DD0009D3FBC1E48C2F1F6EDB92BA4E1D73E07FA -:100DE000AEFF35ADAFAE1E1120FF551B25B7D06C41 -:100DF000F9C0D928C3F6560B106EAAEFF7D468F5E0 -:100E000014E747979BE3F760ADCE69DF9E9B4B7A73 -:100E1000EA2A163818646415931C8F8EF675D1FC77 -:100E2000688AB0B72ECAE5DEDEE9E012E53B9A9F9C -:100E3000783DFA0D1E009F3797A8E7E97E75F225E9 -:100E4000CEFB678A3E5D1BC98AD9AD844A9B8BFC69 -:100E500007150859393F4C705EA95329DE2DC4751A -:100E6000501E253E3548216ECCDCCE528AABB8AE42 -:100E7000A904F7A9B6468615E173CFDD73C42AEC41 -:100E80006E88B03B2D2EB5ECDCFFC46031F4419C84 -:100E90009F55EFBCF8C39728BFEAB30E374D8FF9C3 -:100EA000D78B2BB8DF0487218EE87E37AEC9C6F515 -:100EB000F6F8E6510B69DEC44FDBB289AF496D111C -:100EC0007E8F166DF97CB03887DE879C977E4E3E0C -:100ED0003EA9E58993769117E8BD30F77B8DE2BD99 -:100EE00070AD8673D6B648A100C71FD13F2FD2F888 -:100EF0005BBEBF710FE1278B363E349DED2824FA8F -:100F00000A17FE525C587248F4CD4BB71AFB8D6A33 -:100F1000EA9B693E84AD640FCBEB13EE6FACE0BE91 -:100F2000B93A3EFEF7D0377B4B347C6C280C65BE5B -:100F3000E4B97DD51EE261625F5C05CA8412AE7BB6 -:100F40007D32EDEF35F78C3FF42FD0DF9389FABD7A -:100F500052DB9BE4E460B958B99FA87D7985DB49F1 -:100F600063CD6F3799A8A7C689EF7D04F1CFE97EDD -:100F7000BC789DC47D076CECC73658F89A4D217E2D -:100F80000B5F1BC87D08F64B5C1F6E7ACDB68EC614 -:100F9000C1DFF509C885844377DE40384C3009EB62 -:100FA0004D81E783E4611C867191474BB4B8AFD59E -:100FB00001102E32F4F3412DFFD7A68C1C889D73AF -:100FC0006CDEBE4186FE24A8D5DB25744EAA1BB775 -:100FD000DE20EE27093E767DFC0FC954F7369A7D58 -:100FE000C9846B9F3D309CFB98DEE4EEC53404570A -:100FF000794FE9FD7C7AF6D5F456F28259C84BB3A5 -:10100000DBB7FD0A7C6D89E945E76FAAFC4685954B -:10101000709187C1493849EDFE578376EA0BD703B3 -:1010200023106741D8F3D953267EEF5E0A39FF3A81 -:1010300001C7DE536677089F6FD0E222BD7F76C579 -:10104000D9994DC37F935C7DC015D74727E7A41B73 -:10105000C629EE1B0CCFF52D1B6EB88FF2DE4CEBC4 -:10106000434069CD2B8DD5BD69CA68C3734FA74E68 -:10107000DBC77EDFFA08E352FD6EF518CF2337CBCE -:10108000140FE09CA897CAF097FC6D0C0482A48F03 -:1010900071EDC63AAA2C52C77D63D201B30107B0E5 -:1010A0005D0397DA44FE457172080C11712351DE1D -:1010B000C6EF2F6AF7CB5CEFD50EC54235AB27796B -:1010C000DF6490B7EE8FBADCFBFB8C721F38DB2835 -:1010D000EF41AA51DE831719E53DB4C628EF1B572F -:1010E00019E59A1530CA317BDD38C3FC1175E586E8 -:1010F000F1CD2FDC6E983F2A74B7619CBBF53EC3DF -:10110000FCFCFA0586FB854D4BAE4BFF45E15AC30F -:10111000BC44FD17EFFBED55F51FC05FA17F607D5F -:1011200094A13EC2AEFF3F3B38A6C759DD0EAE3399 -:10113000CEBE4D3ECB78C2844880ECA02C99ED64A5 -:1011400046B2883B1FEE3B7B40C1F147AE624B2667 -:10115000D5595AFDE0D3E290DECF24F68D7795493C -:1011600009EFFB930CEFFBAFF55D9DB7356C1817DE -:101170001D00FE6EC673C8FD2E51EF7185E1AED223 -:101180005335EF121D7B8ED376B77E55FF3E2FB1C0 -:10119000DF826507F8BDE25CFDBD0C394569777CEF -:1011A00052EFC7F43E37B1FFD5FBDEEE7D9AA86360 -:1011B000BAF71BEE4C33D7D12AD7D57B259571CE04 -:1011C0004DA3D4C15E2F3501D8279BA84F8E04852F -:1011D0003015A0F7D051FA9F8A90C0B3F7111E1FA7 -:1011E0004D03C6CF15A9EEBE401E1FDF192915F00D -:1011F00011FD147BD5115ED4EB31C9B9B698F089D5 -:1012000071DF0EA37A24C72BEA3C9B8C92C2BC34BC -:1012100070AE0274FDC7746594D71BC34B7AB39B41 -:10122000C4EF931AFC61A666A79BBF5F4AC417234D -:101230002617D7A781DF4AFCDDCFB774B8B1B13A22 -:10124000E6EC3A0BD731A0F5F30F68F2D7718FB9FE -:101250001A3FC770894598971F68DACB7A599AD98F -:10126000AEE125355C8F3F34C4E1E1EFE19462B734 -:10127000C0C9741C64B0FC53EAAE6BF1BF34F3B464 -:1012800001878237FA5DD7FBF218DF62FD63EB0559 -:101290009E796CFD50C6CF63EB9F613CEA819A8FCB -:1012A0000DFE316FD561833FCC0F1C35DC8F64742C -:1012B0005A087F8CBC3568DAFD28BF8E465B29E969 -:1012C00003EDE011D2ABBE7E647DEE14DAF7DA7C7A -:1012D0007ECBE768F3B7B27E753E8FF80FF138E248 -:1012E0008F247C9F26F8D4710E9D5A77438E99DE09 -:1012F000274A7DDC842BF7867FE87E662A1DCEEBAD -:101300009C37B94E089CA8660CD57F6D930794D383 -:10131000B9DB865ACD828E14E3416576319E762BF9 -:10132000D1A8C5B18E709136497C4F3457525E9921 -:101330008FFB3E314A7D9AFCA17A496701F95F75BE -:1013400061E44109D7EFEAAF6E20F948D85E0C4A54 -:10135000673EF8BBB353A6408184AEB2C7FBF57DB0 -:10136000D4279EEA13384315CACEC623626C15FEF5 -:10137000F8A1771FFBDF715C8CF80CFC5912F89414 -:1013800023629D89EB64F4579FA77DE97B327ABF86 -:1013900047D7C93E75BC346A11756254AB175FF606 -:1013A0008A7AF69504DA44352EE18F44395E3F336C -:1013B00092F0F4B31B6D40F52DEEAF984A62DFAFAB -:1013C0000C405EA88E7DDF2AFA4CCF5F6C618A5399 -:1013D0003AAEFAA6378BD7CBC8167869C63F63DC1E -:1013E000223F8CB40E9B991277DE03C0387607E15A -:1013F000D17138F69B5ED1AFC3C322EE75AC1FCC62 -:1014000078FBF2FDC78E50FCBAD7AB36925C1798CA -:101410005CA5FC7D56EA2EC6CDF67A5DBC2F9E9764 -:10142000F9C538B486F4B4DC1E619CED5AB87A6F05 -:10143000FC772C6C7D3E8F71645701D98DBE2F9E39 -:1014400063AF370EFFD6CF115BE7EA7EA0E3C3FAA6 -:10145000F8E4CB4F8FD4F0FD79BE1EF2EB114D2E88 -:101460006D969EF1F88B5EF11EAF9B7E6E0620FCA2 -:10147000DFD607733FD26FBD82FF8E39C80FE31BE3 -:101480004A11E977F9DD0E37C9595F1FD751DFBC23 -:10149000CA3E5DA37DDF10FF4B6A047EAFDF8F4A3B -:1014A00042AF81F5024F5DBEF3F091277097C5AF53 -:1014B000E717533ED09F4F9433CA77247F7F278B03 -:1014C000F75F28DFB3B47E226EFF73E51A1D2ADEB4 -:1014D000D346375D1C46DFA72DA7EFE10AC83E04BF -:1014E000FE050D465C0BE515207CA3FB7B2DE0F78C -:1014F00063362D9FD8F4E787980DCFD7A7F8924A87 -:10150000F1FC6F697103E7874CF43DB7169F1AB47D -:10151000BE3B117F696815B86943A695EB68AA7F41 -:10152000E8BE5EFFACFC58E0A62BB3449D4DE7241B -:101530003D4B87F670BD7005179730DFA31CD3AD08 -:10154000EA9052F2277505E733F946D433BD0FF917 -:10155000EBED1A8E20F2A357CB875E5A87CE95D734 -:1015600097F36489B62FF6178CDF8D0555AB1F34C2 -:10157000FC6DFD1E03FEF07FDDF5EC49303100000F -:1015800000000000000000001F8B080000000000A9 -:10159000000BFB51CFC0F0030947B0A3F20FA0F13D -:1015A00067B2A1F2D3B850F9875950F9FE68FAD161 -:1015B000713B13030323137E35F8B0083303830C08 -:1015C00010AB00B10E33F9E680B0BE2803438104AE -:1015D00003033B90FE23CEC0E00E641702B11790C8 -:1015E000DF02C45381581C287E16484B8931303C99 -:1015F0001185E8B300B23F8B9167A7192F656E1E66 -:10160000C594611359543EAF1A03839B3A03439F19 -:101610000684AF8D24BF1428C6A70661EF976760C4 -:10162000D004F29564B19B7B0028AF0594DFA681BE -:10163000DFFECD3AA87C0733547E269A7CA30B2A82 -:101640005FC30D95AFE30EA101C062BAC4D8030019 -:1016500000000000000000001F8B080000000000D8 -:10166000000BCD7D0B7C54D599F8B98F99B933997E -:1016700099DC241398BCE02604081A7012C243C4F3 -:10168000701322468D6182687197BA23AD36A240ED -:1016900040D6C647CDE41D5E1AC4EE22B874E213EC -:1016A00094D6D462FFB4AB7402B8D2966A54ACB488 -:1016B000B5DD485D6BFD2BBFA0A2D4D2B2E7FBCE57 -:1016C000B9997B6F2601B4DD5FE3E3E6DC7B1EDFC7 -:1016D000F9CEF73EDF39718A0EA2CE23E40CFCD09E -:1016E000E71B84FE64269E84741332039E03727883 -:1016F0002A3CA3FC3D7B0696F60AA4008BFD6426DB -:10170000217984FDE43576AC16A7113296847E3AB1 -:10171000399F96076EAC217E5A7EEB8A3FC2B36337 -:101720007165F5651A21594B7A5FBD9C3E03E198BE -:10173000102926640B1109C986FE0AA3155E42DA38 -:10174000A0B339848C8966E9D16228E8B440C8BF67 -:101750002A7C20226A322DFBF0D7C43C8C27214EF4 -:10176000122FC28AC219D7F0F6F6FAC6D307ED8C4B -:101770003AF9F0FF3504E677B676642D1B2F4AFF61 -:101780003943F19293181FFBC9AA379509E0C7FAAC -:101790005D1FC2FBEAFF93F1B249A95B2BA3F3AD36 -:1017A00011D518D427BD69322D076E93495CA0DF8F -:1017B000CBBA058776F675E920A4BAD78BF815EA77 -:1017C0007C09F8AE2502CE67DC5DEFF474060839BB -:1017D000B9D41B42FA5009C9481F3E9F6F371112F6 -:1017E0007799CA8B2B85088E17FA69216D1F5D2C9E -:1017F000861E07786A16A5C17BA3DE37F938C3E9D0 -:10180000836832C5A3CCE943AE1175F7B42F4F1FDF -:10181000F217A48FCCB5A676E4FCD70BF13EE3DC3F -:10182000E9E3CB8E67ACEB70BE6A4638C6DD55E89F -:101830002674FD1FA85E941A49526FE4752D457EEB -:101840000FD4103D96A4DD3A584F9C67D4226FF018 -:1018500049D7471A5ADEDB2DEB258D9DB9A46714B5 -:101860007C4801EB7C8D7E9D8D92F64E062DCAAA9A -:1018700008FDC9BCBF0E75599400DD026D537C484C -:10188000DD257142F9830449E8710E8148CB4E553C -:101890008FAD17A014C37531E0530A45CB788E5C29 -:1018A0008F653DC892A86086DFD9E844386460132C -:1018B0002EEFC228DC18DC30C4990950BEDBB2FE22 -:1018C000B297C4DD54AEAE2B2C25E67530E854102B -:1018D0000C3ABDFBDCE48A7DBCC55638CFB99D57B8 -:1018E000D6DE35DA148CD64E26EF1A78A2C87B1DC8 -:1018F0007E31AD7BA783EC152E22A435B7230A6F6A -:101900003BE17F17237D82D0229DB9A52AD013D930 -:1019100029C800A7DB208F603AD6EB211AD2535496 -:10192000B883403DC91B463C19DF47868BD35D54C5 -:10193000EF2BA4FD5ECDBBBD9AEB3352E67867C0BA -:1019400080BB00E79128D3797C7827FD1FA58F689D -:1019500089107B5C18FEBD06F421954735F0DE2426 -:101960004F5C82559ED5F06F079E7B73D2744A8F71 -:10197000FD218980B86A79CEA557D1FE5FBD548814 -:10198000B9040E2FAD5FCBE13CAC67E4017DF657A7 -:10199000B9907E6B2FFF2C00E47B7CEFEB72327EE4 -:1019A000AD9DEB48C041FF5B659E1FFD6F0C8C81B8 -:1019B0007C59857464C0B5A2544238FAE70A3118DC -:1019C000E7E06FFF70DF2514CEC36542C8A521BCD8 -:1019D0003E42C7EBD73F0E8C26278831BE4654C007 -:1019E000A77DFCA1F550424B802FEB55A7B69E8EEC -:1019F00077AB143A047A8C8C65FAA15E9D5405EBA2 -:101A000023098C3EE60B59D8AED5DB3206D75D5A9A -:101A10009A545ED55345A196C2F78D93468533E619 -:101A2000181C30D175E35BF9F71D34C13955F00549 -:101A3000DE4DA1BFCC22B3609D3FF22E4A8D939123 -:101A4000FB7BBF4969961D847CD6A4DD77D031FC31 -:101A5000FBAD1269E82D1EFEFE4A41E1F8883AC14D -:101A60003E33E63D344F6F00E9FB5610BF94D46F10 -:101A7000DDE96E96CDF2C7368F21FC7EC1764A60D5 -:101A80004D345B037E8B2C14A01F99FE3333C18F22 -:101A9000B7EEAE637C6783B73DF0B781F76C7CFC33 -:101AA00091B7A503ECD55607A397B64C31D442861F -:101AB000D38BB11E061ECF753D360A6EE40F838EA2 -:101AC000EAC5A5A3AEFBD9E8E80EA0A30BFFFE7400 -:101AD000B405E868C63F241D6DFD47A4A344F97210 -:101AE000B41716F2BEFA067EFF20C8E75FEA12CAF4 -:101AF000BD5FCE65F2FF97112617FB4964D30CD06A -:101B00000747249453FD7AAB0FE1A52631CC03FDA2 -:101B10002E4A7FAF83BD3499CAF526059F74F679A6 -:101B20008BE8F7572FFB2C17F4D7AB746DC1FE264B -:101B30006450D769FB5786CAD40087B29B95079B30 -:101B40004F45C13EEF1758F927CDA7F4288EB7B1FE -:101B5000E3728ACF85F02B8563F15C418F25A18BE1 -:101B60009F094E86972A62D1AB745D7E26507A51CA -:101B7000C2ABD1AE26244CD03F2CA47682C9BE681D -:101B800004050672B9CA85FACFDEFF2BDC2EB4DB62 -:101B9000718BE79638405FB8C227E401FA5C1816EB -:101BA000B00CF8574D708BBAA0831E08CF753D025C -:101BB000FA2F2C13879A845F17EA2E8BDD7582EB40 -:101BC000318A9725CC6F51F3EAA626EA9F30F4AF0D -:101BD0006D3E23D185310FA37CCDDC13073360DE4E -:101BE000D54268223454D4BC1B7CE6FE530CFBC6A1 -:101BF0000778FBE5926B52191D4450AF1AF4F4D3E9 -:101C0000B7BFE180F993C51948978B6B248B3DB919 -:101C1000A82AC552BE6EEE35A3DAE12462C28389DA -:101C2000EEFD3904E994FC37B553289D462B072374 -:101C300068B71C13B4565A4E2D6F1C0FFDDE2DA62F -:101C4000637DA1BC71F200DA5B0B90FE53789FA913 -:101C5000CE863F14805C9D28924734B04747F70BEF -:101C6000DA399D1B6547201215E87A6A51B5541A76 -:101C700005DF315DAC4EE6374C10D9BAB54717A930 -:101C80008500D041ABDC48AB6A40FBCFA84FE97878 -:101C9000829809E346F1FD101D77D179D1761E6651 -:101CA0008B90D40B16A59251E6D1665B7F2AFEF588 -:101CB0006472F6560E1FD9CBFA3764526A3AED3F7A -:101CC000497DE3D9C9FB3F1512493FC0298715E477 -:101CD00087A24A62EE87E8255876F2A22B1856F2C0 -:101CE000293E5DC5224C83B4173FA2CB1AE0218A5E -:101CF000EBBD81AE6DAE892F37FC45423FFF56B13B -:101D0000A019E4C686BE5B8846F1E109C60896A71D -:101D1000DEAC009E365027AB1FC6977B09C0919260 -:101D20004B7FA7E3A4A824A6D1FE64AD372ED2B280 -:101D30005C4D423AFDE453438287CA89FDC1826605 -:101D400099BE6F5B4A503E12901E26FA690BBEA6E2 -:101D50004B403F4B4808006E0B2CC37976142FEB99 -:101D6000CAA7EF4FD6C8183F20A729BC865F4FFDF2 -:101D70000C4F11D161BC0D5924E6453B5847FC3A44 -:101D800055B67EDAD642129F4EBFA7CDEC83F1A3A3 -:101D9000DF228C2F09936B32972744A6F407E33791 -:101DA000AAA1F549E84F21915BC419A67556C3E86D -:101DB000C7DAF196EA2457027EDB4A281F24917B7A -:101DC000778822D2412CB46861419271EE16359425 -:101DD0004F46593BE544F847AA9FA82793780674D5 -:101DE000AD0B8017120EE0FCD2C9D08F0EE50C3E71 -:101DF000DF31A401EB056777F701BF65EBBD158007 -:101E00008B6FFBAE7B15D78D3CAC821D4BA12D3C5F -:101E100093919017A073607E1F8544F43B7C625CB5 -:101E2000D569073E777F109D5F8D605C2E159A50B7 -:101E300080D737296D6097F8494880EFBE901C35F0 -:101E4000DBF5A984962DF11472A4702661221FBFC0 -:101E5000AB7DC03A6A51C34500CC16BFFE5FE03788 -:101E60006DF445D00FFBCCED9F06837DD3E37F045B -:101E70009E9FB9C7C5D03F0B317F4BA1FF80BC4BA4 -:101E80009D2D5BFC9B34DD5ACEB0F9610B242FCE27 -:101E900033ED6AC2FD2BBD66E298045C14A23AA041 -:101EA00097CD553201FFDFEB65F018F06548F7CCB0 -:101EB00042FD18928F011C142D08C749723A0E4B2F -:101EC000EC2F22183FA5701DB3C175CC06D7313356 -:101ED0005C8D0A9BAFDD5E8C5692A2060ADC0B225B -:101EE000F73FA8DD0476E349F2815E0D8413BE124C -:101EF000F5AC5F656DBC4A3F062B54A2221DD8EDA0 -:101F000046BA4E1F59FCAFD9BCAC1101E641E1B451 -:101F10007E27B9482F5896C8505C78D96C035FDA91 -:101F2000577E43F9EF96430E02FC45F95882EF0EB7 -:101F3000FEF5161E1F5E06FE35C5DFD749D80FF029 -:101F40007D48448C437D485EF34F37C9C9E322B7CF -:101F50004F6089CD7C4C424190E3B2B7A35FF2233E -:101F60001A0C7A13CEE03A86989CF732BA8B12A5F7 -:101F700019F56117F33F8D78EA4DDD567FF81B5B4D -:101F8000ADE59BC9A231102FBDF9410789D17E6F04 -:101F900031FBF7749DDE105584EF1BA4A103EC9276 -:101FA0004E07B33796A94486F8E78AFFF71F336FC9 -:101FB000A4F33909F26006D8EF147C931E591E88E9 -:101FC00039F5E2E1F36B1542B5970823CFAFD3D1D2 -:101FD0005F0BFE77749303ED4C628F83EE91300EAE -:101FE0006A6A87F07EADCB3ABFB3CDDF3E5F421E5B -:101FF000C0F92EDF7923DAE723CDC7B933B9BDE9BC -:1020000095044BDCC7E06B83DEEDFC5D26692CAEEE -:1020100043D520DA2BBF4B89B5E2FA36CC82F53DA9 -:102020005BFB8BA17DE6176F5FFE25C79F7F96F652 -:102030002B94C105B0DEEB02DD61E04F238EB5923B -:1020400044F51CFAABE3F9D55130DD86EA05CFB192 -:102050005E2EAD279D43BDC2D1FB3BCEED92977660 -:102060003FEA043BF5C3A7DEAE053BE0D6FF94880C -:1020700042E9E1F86E1F89A3BD1273827DB39CD241 -:102080005D0CCBF199D798EC614AD1B80EB73EE31D -:10209000433B62F9B3AE580D6DBFFC87BF9F462826 -:1020A0001E8EB70CFE570ED0F353028BBB4607A60D -:1020B0005D43DF2F97C9BF8493D0D18D12E3A70F63 -:1020C0007E94B204EC446167DF0DD86FEF571C2E8D -:1020D000933E5E2239705C5A0FFD88E82E213651FE -:1020E00060F099FD0123DEFDC12E81C1B7D71173C8 -:1020F000037C3B7B9C115A6FD5CE1348D7F39FF9D5 -:10210000AE1FF0B06AAFD54E5FB5538ABBA6E1F300 -:102110006D7882061566023E193FAFDCB302F5C644 -:10212000CADE0D27809F57ED7558E43FC54B280E3A -:10213000787D530AD540F9074FFA358AAAF7FB1F75 -:10214000F7035E69BF373A295D2D9C6D6D07FD9FD2 -:102150004A1FDE1FF50CD16F5ED5BB8E8DB7E7EA47 -:102160003F80BC5D45989E32F8F97DF8256BB89E9E -:10217000592759E35B27C9E199B80FB83323A9FF61 -:102180006CE81583AF6FFDEEC91D513AFE07CFFE17 -:10219000FF1D513A8FDBFEFAF18EBBE9FCC83EB75A -:1021A0000AF26AD5536FF88909FF8F496C3FE0F84E -:1021B000AE279FD846F9E4F8AF5C68071E7FE10FB1 -:1021C000E3343AFFE3DFFFD318B053D7BE70D958DA -:1021D000C0C7DAE7E68F1DCD5E07BA8DB9CCEB1B21 -:1021E000C3FEB5BD026C8210F23C7FDAD6E9C01E98 -:1021F000290E21820F8FBA622E8A9F55F45D6329C2 -:10220000ACDB0AD45750BE87E27BE5EECE13D2B4E6 -:1022100064788FE6884178C6734810D6FD9A859712 -:1022200096C1D311D2804EC820EA097BBB5547E83E -:10223000FA5E34F27A527BC209F85FB57B1D1BB798 -:1022400097AEA77FF87A7E08BF5C3C7C3D0F48D6EE -:1022500038D34972DB77B6C1C73D19B8FE23ADE765 -:102260008AE7AE1DD5BF33E4C3D9F05C2F30B8EE9A -:1022700097F4D725E0C7679F7E625B80AD730D45FD -:10228000CCF1EF9E1C079BBCEF39066F003939F883 -:10229000824B05BB7AF90B6F22DF1D7FEE55A786B7 -:1022A000FBD3C42B503D799C0CFDF483DE5C29B03C -:1022B000C2AAC77C71973FB15E2B6375D59A1FDFA9 -:1022C000BF8DEF638C1F56C6FA160B49D6CF2B175E -:1022D00030FD14CB44BCACD0FA9DAAD7BAAEC26CC8 -:1022E00058CFB71700FD8DB49EC6FC5598FF2CD370 -:1022F000BA3EC6F878247E3DDEE39285D4E1EB7CDD -:102300009CDB15AB62C29BC9D69D901616DF1B21C4 -:10231000EE6D3CED74E194AD7C6EB437E67F363EF5 -:102320003FFBBCCE0F6F27B9BEB6E3EF83D3C9F531 -:1023300040812C70BDD55D9D6DD2776E07D563F958 -:102340006077364473F213F076F44A28DF3FD829D9 -:10235000A1BD6F97132B47F0EB43C6387BFBA681DB -:102360003CFB60FF8F383D327A5FB9FB6D6794EBC1 -:102370008598592F407F49D6630EEF6FD5F3C9FB7F -:102380005BB5FB44D2FEDE97F5AF00FCEFF73B48B0 -:102390009476F17EAF94344E52283B2C7656876F5C -:1023A000E6D154DA4EF27B3498776B8BFE6614ECF0 -:1023B00091D71C04ED4739F49E8B7E6FF57970BF81 -:1023C000A5D57F33D14CFABBCD86273918463F5A65 -:1023D0000E84CBD85E68CCE2CF3A54D1023791A3B9 -:1023E000B9B0CFF972FE1F64E817E2699A292EF49A -:1023F0008A4CDA219EF68A2E849A4992B896ADFFCD -:10240000F05C8968663AD3C78BE6F8A27FFF9D1817 -:10241000D768240D718837915CD2FBB8A9DF879B00 -:102420003416770D8F17CDF13F574383EEA270E43A -:10243000AE550BC07F1B69FCBC06EBBEAF31FE1A6C -:102440001E8F203B9F7AEA295A1E0FDF44A0C3B09B -:102450008E709C66FBCAF3B93C7C89DBCFFB0572AE -:1024600010ECB0EA7B2232C83B217823C64517E442 -:10247000DE282F33D1E382E0892CD0ABDFF98BB497 -:1024800024199DEEE574D5FCAD27B2A0FD36F757B3 -:102490007299331B46F87278BCEB60E6E55E88EF14 -:1024A000F5DDB2E0F0243ADF6C552210AFC92615F5 -:1024B000DE120A67CE1129E44EB20EC673078FEB07 -:1024C0003DD2A4A2FC7FAC2988E527385E7736157B -:1024D000E1F3A9A6107EDFDD341BCBBD4DD5F87C22 -:1024E000B6298CEFFD77FDB8CF0978B997F442BCD7 -:1024F000664FD312FCFEC3A6083E1FE7F3590078CF -:10250000F15AE68FF198BD6DF35A201E63E0D18E2B -:10251000F779247AD085FBF9820678BF5366F2C535 -:102520008EDF71AE5E01E44BE36D04EDD71D3C6EB2 -:102530006CCCF72199D99B7B383C3F7447BE27C3AD -:102540007E53756131DA45241C02F9BD4308A79614 -:10255000D02A2F66CE0A9AE570B62FB24736ED2BF9 -:102560008CEB62F19E6D329357E3B5137D69140FC6 -:10257000D5B98206E10463BEFB2BB45C9093FB05E6 -:1025800001D7BB3A57224526BA37FAFB0F59E4FB6D -:102590001BC9E576828E993C48BF422E02BFF624C5 -:1025A000F18424CAEFFBB2C81E42ED8F7D40972014 -:1025B000177E9B827162C3BFD9C8D73B1D8802F2C8 -:1025C00025DEF2C540FE8CE4F774F0FA1F71B856B0 -:1025D000C8E1D765DC57E6F15712C73826A41C01BD -:1025E0003D6E732FBDBF8A3EEF9BF3FE51880F7E79 -:1025F000F89C5B03B836951DF39BF148EAE50FCCD8 -:10260000FBF143F2E6540EC6C5FE8744DE96CD725A -:102610002830E884F6FB046D33EC5F47DF9090FFD1 -:10262000F609B12918C79209FA05FB6E09627E877F -:10263000D1CE17B2F277BA7B60FB2A9877BD3314FC -:102640004DC217BF4ED12CFB46AEA0B57D1074E62F -:102650000C56D6287D96F07987645D02386690081E -:102660003E67110D9F598EC8E7308FE9A4370BCA1A -:102670002D29E32E61FB077F37BC298E7F40BC19D3 -:10268000F41A9C53847090BBC4D0440DBD490B9D7B -:102690002F74081CBF0ACAF3ECA1FDA98697F202A9 -:1026A000D80D8B93A8292807B3DD0C7F8D03273025 -:1026B000BE1B1C472C71F7F67A11F960DB5B6C5F6F -:1026C000EF647DC1E649B47E05D1EEAFCA1F3E0F6F -:1026D000833FB629E1D464FB53C6D3E00BA3BC7996 -:1026E000FC0D04E4D0BF8FBF01F38EB2DF726BE04C -:1026F0007754FC6E5733C8C5F6B7597EC5514F6441 -:10270000AE634642CEB4DFD2301EFC20B72F5C0E43 -:10271000EFC3B9B1EB41DE9DAC5EEBC2A97B59DEE4 -:102720004BE33DDAE6C9DAC8EBB3A371F4FD1B63F2 -:102730005E3B605EA3EC5F18F332D6EB64F5E2C15A -:102740009B35903385A99124ED86E4C9158B471DEF -:102750007F07D72B74FE4BCDF439AE51C5FC16A3C1 -:10276000BD315F7B7BFB7C13FBC0E79617D4EB206E -:102770001940EFDFFFF3B81FBC82A2312C819EA667 -:10278000FCB912E099491AB04CE4DE2CB06F0C7A17 -:10279000DED6F14416EA0539968FF95DE7385E3BDF -:1027A00009872B80DF4262C86CAF18CFD6213A8FE1 -:1027B000635CD5C5E58098724F30199E87FACFB516 -:1027C000F2FF4642989C8F2B28E72150A8D272FE38 -:1027D0002152BA9EF6570F49A1749C0A99C543A687 -:1027E0001FD27A24165795EA7C263CF2FD0623BEBA -:1027F000DB4EEE21AA067E45491F5437F8F480339C -:10280000F2A003F2F0821AE67B3A021181EDC7B121 -:10281000FDA1226E975C262D55C02E692461E5022C -:10282000E0DB23126179788CAF5DC63E18E7631751 -:10283000E763CAC1589EC4BF3FCFE96B2FD8276852 -:102840004F303ADAC3ED93AAC1C1033EDAAEA8BF56 -:10285000BB12A6F32CD82B2EB04F42F8FD7B60AFF5 -:10286000D0F281B47FBFF2028A979DBA18025CEF62 -:102870006ED2193F34D5E3F74612F5AC06B9F4B081 -:10288000A8029C9D0FB7487E5ADEA50818BF78B8ED -:10289000A901EBFB4F7BE2E06FEE52E202D8232767 -:1028A00043241405B8A97B04F39AC4E751F14E3FC1 -:1028B0006E973F11FBE8F7F7D37A5B667B709FCC8E -:1028C000E0AF498D83EA95C0578F1FD35603FC3381 -:1028D000D6E8507F63A800F7299EA4F88275DAB97C -:1028E000F5A3ADFDF4BB5FEE5C0D7EF0E4BC456886 -:1028F0000FF9957FBF1DCA7EF5E97FC5A7F2A36FCB -:1029000082BE9E1C132DFBE77EE5E777C2F7CA81E6 -:1029100050552AED67CA91FEAE2BE8B33DB456047C -:10292000124F4DFF23EE6BEC17D4AF77435CED46AF -:1029300027D2AB7E546F0676749459F320330F4739 -:10294000206D818C3D48F14E00EFBA0CFDBEE7C80A -:10295000473A0BFAB3AAFCB4FCC463C77E7A05FD00 -:102960007E60EB1A948BAE8765B4C726FFC75AF218 -:102970000D939C703D2627CD2B7DCFE1627CF4F03A -:10298000E2EE291A234FE0BF298F572928270E5B33 -:10299000F31C8C7DE11E1279CF81F4CCEC135965C8 -:1029A000FBC8B0E705FB8964BBC8F8241CF198F3A9 -:1029B0009F8B1E12C3C9E2DCA71C32CEAB2D56552D -:1029C00004EB209FB903F7C948B7757C633C3AFE16 -:1029D00029B37C935506571EA87EBA9E7DCEDF6430 -:1029E00001FCA71A0C3D15473D75B0448C8FA7F02C -:1029F0003DF0A01883A4CC03D54C6F6D9259BEE076 -:102A0000265E7EEC348909F9093E9ACCF9EDB1874E -:102A10004566CFC508EA3972FA0CDA175EFE3DBD8D -:102A2000E43505F727A2BAB762266605F21F13BD83 -:102A3000501C5D14F558E4ACD8986E59FF3C6AB14F -:102A400058F3A90B12F52590E34714A0DF93D46F38 -:102A500005FA9DC7F789AA8C3C4CE9F47498FF7677 -:102A600043CF1A7933B63CE9C71B9679205EF8A2AA -:102A7000413FF50D3AFA3FAA0BC733F6098B6E0BAF -:102A800047417F3A72ADF9D315B6FCE879B6F2F951 -:102A9000C6574A9DF638EAC62948079A1FE55521C8 -:102AA000C7F3E31753773E75789C65A85F1E4720F0 -:102AB000DD7E5CBF424E40F7DD25D5835FE07FA021 -:102AC00034CD9C5F70B993D9DD077FEB2260E7EFCF -:102AD000AA52309E69E4753AF8B8B54E0DEBED7A1E -:102AE000F00E05DA77060ADC80AF0373967B30FFC1 -:102AF00083E7A71A72B765CEF22B6F01799829A2E6 -:102B0000EE69CF6DC9867DF907AA14CC3FF5A70CF5 -:102B1000F41EA065EF93CED023F4FBAE8AF81273B7 -:102B2000DCE60E27D35FD73BF93ED0466BFE06E5C9 -:102B300083EB9D901FE66DC07D4B51E179BC36FF64 -:102B4000DEC0877FFFF562BE8F3D0B7CE08F32FADF -:102B50008871FAD8C1FDD38741FEBB806E98FCDF37 -:102B6000C8FD537BBF13EBC3FB9D6087DDA6964278 -:102B700028CABEBE13BAACF6447ED42AE7C6DBE947 -:102B8000BE21DB523FA7BEC0F2DD17BAC0669FC4AC -:102B9000995E236C7D3ADDDE0920B74BA9DE6576B0 -:102BA000862A86CDFB2A36BD5EEFD09B9CE761DF8F -:102BB000F853C20DB03E767B7A035F9FAFCAFA3AF4 -:102BC000E70CF4DF36C093DAC73C5FDD6A7F0C8325 -:102BD000935038A78E0AE783E703E7D9F6D9ECFBD1 -:102BE0006BDF94C25B5FA1CFF254960FD9EE63FE08 -:102BF0007C3BC45169F9C79C0E9F764AD8FF5E3E64 -:102C0000DFF2145A3F097F1BF1D5E721F106EA8D67 -:102C10004D9E670916107ECF49FEFD7927DBCF2E2A -:102C20001F3FFA38FB601CFADCE8D07FE434C5F1C2 -:102C3000DA9CFA7F9ACB7127DB7F1E5A179E476971 -:102C4000D8637738F43E73FDC4D32A378D7D904C1A -:102C5000BE9E3EC2F8EFC525CBD64DA4FCECCCF50C -:102C6000A2FD93B9A46DB5E887FCA37E15FC814C49 -:102C7000BE8F4F1633396AECABA7D758E5AAFDBC17 -:102C8000958BE7C5BBECE76CB87CB5D3E348F2F5B0 -:102C9000774EEBBEC650FC7A04BAB2C7AF1BE15701 -:102CA0006667723B389CBA68EAC8F4F872D3E0A64B -:102CB000831313E557E0FC4C523A60FB89FEFD7F1D -:102CC000AC595C06FB762C9ED6DF142F7F676242E0 -:102CD0007E85E7A6BD0871CF70551ACA9BDAE0A7BA -:102CE0009B0E527FBC4EEF2B7FC734CF7E95423B6D -:102CF00061143ED11D9F9BF9EB4981D14F3B1FEFE2 -:102D00007E8E4FBB1DDD29465DD0EF2764401792B4 -:102D1000F8B5E679B721DE06BC406723CD3BE46217 -:102D20007CE59FDD1082389DEB8C847CE01A6FD8A7 -:102D30002D21B45BA6BBD2D8B90F6F01EEE3513F92 -:102D40007DB00FD6C1CBF2FB0DFDF8B1114FE57A86 -:102D5000EFF63456DED0C4E2C7AE0317BFA9D17672 -:102D6000BEC30EE2A6EFD751B90E71C02E6AC7C31B -:102D7000777FD90081387A2BAD1F31F9DDADA14ABB -:102D800015EC84B6E25245A3DFA5A9655896F34B2E -:102D9000D54A3AE605AE6FCFCF843878A18879B5A9 -:102DA000C5B4DC4C4DBA54978AF37BB9E81D2FD8D3 -:102DB00067A9E09CCF48ACA7A32CA24B141E475098 -:102DC000AD845C8C21BDCDE98CBE7F04E2254F0A29 -:102DD00091992E3AFF97F9F9AB4E6743D11AF07BE0 -:102DE000E4A80BE2078D0ADB87007A689B9E807B54 -:102DF0001EC7AF938F3BE407F1F5FC441E88426A7F -:102E00006BA748EA93ADCF152E26E7DA545D1D95E2 -:102E10009E54F9734BFEF45CC64FCE00A5A724F177 -:102E200047BBBC26AE709D2B3391AF441756453E31 -:102E300025CCDE33CEF7BCE3D4AF75D1797CCBCBD8 -:102E4000E5586E3AD2297D5FE9F942729FC567F66F -:102E5000CF2D7BB50AFC927E07C68BFC13C8BF84BE -:102E60004DF2F6900B836EF4C9ECA4F5943E629398 -:102E7000595C8200DDA450450CFB907962EC917C9A -:102E800080B7A77A02EDAF539E482DF3443F1579E2 -:102E9000CCFEDF54E9A937FB01EFA5B0FD97B5DE05 -:102EA0008A67010FC5DE5825BACF909D39869D9F50 -:102EB000023ABE502503820872304C98DE0C294C31 -:102EC000BF56A9705E4A201172266534FD683D57D1 -:102ED000F5941C6BF1003E022CDEE5DB2A6032A08B -:102EE000D4ABC73DB44EA977519B8BE98B2218A771 -:102EF0006FA6877869FD4FFB9C681FF6FA7264C065 -:102F0000EB3E71D97720FE34F82B17E637F6FEE555 -:102F100002CCBFEFF55DB200E476AF400E51654FD5 -:102F20002A4EE5F064439202FB7CFEF93A817D8EE5 -:102F3000C1174908F2831DC19F97BF331D279E22E9 -:102F4000CEA6EDDCA4CB4DDB853EF77C3C8FD2D505 -:102F5000B3DED22D1791445CC588A754A444B603B0 -:102F60009CED637E5D0F7CD345E194D07ED58300DC -:102F70007769A688F14792E98D4D8478D9A14015EB -:102F8000E48F56C825981AEB9FCFD6FBA827F238B6 -:102F9000F453A5D655417CBDEC888672764170F518 -:102FA0004128CF7C8B95DB9D8C5F205E444C72B7B3 -:102FB000E2D4389C5F2FA793B6A0DEAF0BA3F28DAF -:102FC000EDDC81355FCE4C0790E76EA28388C34C61 -:102FD00007B3291D4C35D3812E9C0F1DDC8BCAFAFB -:102FE0008BF08FFE66959088DB0DE783D54A7AF1EA -:102FF000707E31E0585F961E00396AF0853AEB1E0C -:1030000094ABAE1B9D61F0D70D3E31F8E353B7038F -:10301000F990F2C9551EFA5CECD52E4BC627E08715 -:1030200098F9E19A11F8A6960C1E0CD046B5328993 -:10303000A65251F2F2C5EF158E33F1811D6FB573B3 -:103040000572CC22CF58D9845775E87CA374EEF86A -:103050007F4DD6DA03263EECA07E0818CB5D628851 -:10306000805E29F52EFB14E852AEF97E10FC4187F4 -:103070002B5C8F79B3B33E48B999D2E5A763440D71 -:1030800026DFAE2D7B06F9F9680A01FB64D3CCE597 -:1030900018F7FDF496C878D013EB28FE8FA15E8E4A -:1030A0008D15310773602CDB6FD782EC1909B2F7ED -:1030B000847F8FF1B2CEEB0D603DBACE16F9B8DE4B -:1030C000CDF6BBD6BB99BE59E7EC5680DF06F315AB -:1030D000D59CEF3C4F62766C89C2F79F4EB76A1061 -:1030E0001F2951989ED9D2D48BF6C7BAA6BDF8CC69 -:1030F000A88911C8A7F2144535D8F756FE3A5F7073 -:10310000001F5FC0F667E17DB3C9FECA51181CCA33 -:103110005FA508F0A7D212D5D24D7256118548325C -:103120003B7AA39BC55F941682DF95FD0FE17E7607 -:10313000466148B809CA2DDD2404F1F3387B1F2805 -:10314000D485AF9BFA0DD4F45AF45C2D5D82D45231 -:10315000B49EF0BC4BBBE6C1FDAFDA40E51FE569AC -:10316000C3E9087E8E99E8C180DFD8875DCBFDEF8B -:10317000AA0205F9AFBDD1D903AAF92A85D9459F7D -:10318000042A473D2F00FBAFD472433F179EB00F78 -:103190001B9DCCF661A10CFBB0F0847D5878C23E3B -:1031A0002C7C877D58287FAF49C732ECC74219F67F -:1031B00063A393D9FE2B9461FF159E7B9BEAF1F9E3 -:1031C000E3A606FCFE7C532396E7B9987F438AA2C8 -:1031D00041B097BBEE74EA9067D3C2D7EB805E90A4 -:1031E00011A2EBEA0EB03881FBF00378DED91D1492 -:1031F000316ED7117C807C8D3EBB66F8BA20EEA183 -:103200003CE3C5A75BDE42C01EDB2144EB4988904E -:103210005BBA4AAA646A2714065757A6D3F2AAAE25 -:10322000596D907738496B0E2D531365CD57BAFC05 -:10323000FBA6F2F8E21ED913023CCF6903790070B5 -:10324000C0A6D9BD5D73AB9A0BA9DF54400D159094 -:103250006BF9CE18D0F3D761BD2602FCCCBEBB8A79 -:10326000B40621AE315E7396021FD2FA7146FFE7B3 -:1032700056BF45D1F0BDBDDD68F5C4B273AA47A401 -:1032800051FA83EFC228FDB49356B59FC2BE0164C4 -:1032900006D8476EB6CFDBE560FCDFE566CFB7DD6D -:1032A0008C7F7FE8AEAC74D367A59BF177973B5CCE -:1032B0000DE74D06A78A18DFE975D02EE0F04163CF -:1032C000FEEB702EE88E9FC904F60F1EE27430717B -:1032D000BC8FE9E9BB15D4D3978FFF6E5B3A2D4FB6 -:1032E0007C341402BDBB81843C4027D18D22E6A1F1 -:1032F0003C5D3621BD8E56BF70C673E9A07F3E553A -:1033000098FC89717FA3B9FDE6F11097FAF4552670 -:10331000FF7672B9D3E3E86FC0F59CE1457B853A4F -:103320000C688F340765CC1F12B3D8D3E950FF095E -:10333000EA39A9C28F52789C7F99A560FCE3948BEF -:10334000DF6FD18F768AD31D51D3E8FBEEA888FCBE -:10335000DEAA7A6260576FF096E2B9D268B18CE764 -:103360004B3614B3F8698AEFBA18D827F7F7B9992A -:103370007CF02A983F1A2BDE73A832004F51057E4D -:103380008FE98BAA11EFAAA8621E2AFD0DBFD707ED -:10339000F03CCA06C2D7A55EC4F374ED633EFFF9E4 -:1033A00045909773931AE2770E609E379A5C22ECF1 -:1033B000070DEE4F0178BE6ADC5730D09242EBB772 -:1033C0002D5343B00ED3D4CA6AC82368572BD1CF2C -:1033D00049995AA5DC887268E83C06DE8BD1562CE8 -:1033E000631E117C07BE246DE4209C87CFE1B22CC4 -:1033F00025AD5400FBAABD06C37C705EC19257DEAA -:10340000967E259E43926AD311CE76A22B503F5AC8 -:1034100023A3FECBF12A71B037728C782E1CB13009 -:10342000C51B326EB39ED3C8AA972DE7C2C746AC60 -:10343000E54C1E3FC8B49DE7F85831F6C7AC78B2EA -:10344000CF3723F0481AC09B010779B5E1F3D912B1 -:1034500028AD8379E6A81E843BA8B65480FC1A4B9D -:103460001A9A81EECE1B5E1B9CD38ADBFA61DDA724 -:103470006932D1E8F81791C116E87703A7F3AE7C5B -:10348000AB3E7E48910C7EBC10F8717CA348A2A68E -:10349000F1210E19358D37A12BDD529ED89D6DA9D6 -:1034A0003F796B81E5FB94D80596EF17EE2CB59428 -:1034B000A7F6CEB1D4BF686FA5A55C12BFD2527F6C -:1034C000FAA14596F28CFE7FB2D49F757499E5FB04 -:1034D000C503CB2DDF2F796F8DA57CE9E05D96FAD2 -:1034E00086BD6ED78B13B9DD72BE76BA0BEE89B08E -:1034F000C465AD7E80DD8E57FEDAAAB5805CF33BF5 -:1035000091BE65D0E3B4BCE64EE64729E5210DE463 -:103510004A0E97A3D93EBDD40DFBA97E05F581ECDB -:1035200065F564EF02B43FC66DA5F2683A589B6436 -:10353000E87B0AC8E5A66879A129DEE456BBF16CF0 -:103540005685BF1AF7378CF6B2AA93880FC6D3D820 -:10355000F96AEAA5423DB746DB9BE6B54F14F10890 -:10356000F420F5F71E31F97B23F977767FEE5CFDC9 -:10357000B77122F1E0B90221DC00CFE286572B219E -:103580001D98FA75D701FD6E7286EB7B68BF9B0AAA -:103590003C6C1F94FB755DF9BDC81783F932EA17BF -:1035A000226BC5E6785C33D74329CAD3E85752BCAF -:1035B000A3BC35F0BE411888B582DCB9D383F27064 -:1035C000DC7FBB5E03FE520A941C85BE0F1D70EAB1 -:1035D000B0BFB485E3B5402DA984905261B06E3F71 -:1035E0003C2769D4CEA0CFA2A2CDFBE179BB9BE55D -:1035F000035F10FA7E25C812A59CD97FF23467AC10 -:1036000085F623A9148E247E85F194FC5BD9FE45B2 -:10361000A1FC2ED01B58F567E8142AD215CCF77000 -:10362000031D08F844FA7107BCA837DC70B815CA46 -:10363000B21083FD3FB04F611FAE227D2BAEBB6148 -:10364000B7823D1B617E6E33D057A0C6BADE29CA51 -:10365000F7104F6D028B7B77A569872BE9B85D99D1 -:1036600005E9106385B8489D49DEACE7FAF49F3D53 -:1036700022CF7363F2E6CFD0E78C84BD43E97FAB02 -:103680003801E0EB2620B7DCF77413A077B74A5770 -:1036900013EDFAA816467DCAECDDDB394C55054B17 -:1036A000707FFFE34029DAB7EEC67D49F1E71E904F -:1036B000883E7D64BCFA276D437D4F0A9C1AD8155D -:1036C0008D9A53EF49220FA6703F64DD38E33C2BFF -:1036D000CBEFE9E2F830E2A14371461E4F33E28CB2 -:1036E000463FB767968E1DCD1E7753FF32628277B5 -:1036F0001D1D07F0D27EBAAE1AF12013761EF72FE9 -:10370000C53DEB719F95F9495338BE4B387EC7399B -:1037100009FA09F3216E92015EED55D5C097469CDA -:10372000E537606CD17AA12891585CCD61E82DF124 -:10373000CC4508B3E634F2C3D0E4657A8DFEDB07EE -:10374000E7C6267459CF654EECB696276FB596A797 -:10375000C4AC656A351F01BB006C348C5BECB47E75 -:10376000AF33F603AAD83932858E7C86E95FCBBDAC -:103770003884EB7F238F2DAF375E01E23577AD556F -:10378000AF66733D9F6DD39FA53E09E30915870280 -:1037900007C17E34E23E473D9A259FCC88DFD8E5BD -:1037A000B9E7ADCD847E41BF3CE262710C880F7FEA -:1037B00096C7E325B93C5E328EC74BF258BCC42194 -:1037C00069AF2C1530FFF3B81B8D97868B589C86FC -:1037D0009DE7FAA85A7E51D0D87811D378DF2C8A89 -:1037E0005ECED010CB827A46DCC4880BB87D7A25B9 -:1037F000F0EF86D06B0D07289D54FECA45A09FCBE5 -:10380000A4C3879A40BEE5C998B7ADCEBAED3B1EBA -:103810008843C2775AAECCD7C6221FFCD481F1812F -:103820004E4ED7C6394423CE92E2617691CB63D80F -:1038300047510FCFCBF780BD7BE14E2AA32DFA8EE7 -:10384000C5F38CB8DDD45EEBF75E2264A8B0EFBFA1 -:10385000242632FB4AF75698F21A2FE0EB366D69B0 -:10386000FC81A5B4BC9BC44AE1BEB9124E1FA18322 -:10387000D6F3AF638880E79FC61C9142315A7FDA46 -:10388000F3D6EFC5B6F3B117D8CFCBDAF6857C12F5 -:103890003971231D6FA3D620801CDDB894DAF2B4F1 -:1038A0005CE8E1FB4593C824A0C3CB246F280EF845 -:1038B0007D43C2FD2DD7DB93DFBC11F4FAAB2CEFB7 -:1038C000489DA06D8638B2FA7309F5949A424A4A27 -:1038D000BC897DA47F3B1322B02F62C4B59EA2EBAE -:1038E0000A7A6537F5CB0B1DE067AB58EEA57E393C -:1038F000949FA57E393CF750BF1CDEFF90FAE5503F -:10390000DE4BFD7278FE98FAE5F0FE79EA9743798E -:10391000ADB7A212E262FDB43ED08BA7648F3281B4 -:10392000C2DBA93854A00FBB1CAAA8B85D594C49EA -:10393000EA2B9D4FE3FE45E5652C4FBA72FDD3B8E7 -:103940007F618EAF99E38F89F8DA8060C4D720E475 -:10395000F93BBECF3014678BB038DBD9FBD18D7EFD -:1039600030AE39AC1F1EDFFCF0CE5F3FD14A3FAD19 -:1039700098F14097A700CE6D34F0789E9117A35927 -:10398000F2EE57EC69C6BC1867D6910658D73D656C -:103990005ECC17713A222AC85BBB3F67F871767B11 -:1039A000DA78DAF59B8FDB1546DC749383609E74BE -:1039B00054A0F604D8174DB1F2771C23C7535FF714 -:1039C000F0F34336B930743E80C77D5C60CDD27968 -:1039D0003A058E0F9EB78EA2B180C5F5CC71554FBA -:1039E000610C0FA57BBC3ADA7502B5F7D0FE532304 -:1039F0004188A375C0798024F38B7998FE6BCE72D1 -:103A0000A2BDD191C5F240AA72434168DF9A353315 -:103A1000683E1F609C5F38E89BA90C98FA5BE32B1B -:103A20001855FF49545F6BA3E86BC9C5CEEFB4EEE0 -:103A3000BF588173195DDE65FDE047770503187F88 -:103A4000EFCB9A49064CFD4BC1D9787E43F2327BCD -:103A5000580A2A680FCB30FFE2447DA3DE3D1E46A4 -:103A600027949D31BEE8F676633D971CC67B235CA8 -:103A7000015099F4A9B2FD384FA1481493BC30C647 -:103A8000FD570F93975DC51115E22C5D4159837366 -:103A9000205D5A29E2B995E3B935CFB0274268C70E -:103AA000ECE17836FA69E57180D67A27DA73E1C6F7 -:103AB00034B52A03F37577C1BE5697B745817D4962 -:103AC0006756D9A8FDFE84CBEB91FB2D1953351D0C -:103AD000FBDD03FD3A7DCB54E8D731C2B9A3C31C4B -:103AE000CE2F6AB7DAF7F128B441733E8AFDE9E3D5 -:103AF000F6A7BDDD8AE20127ACFBBAC7ACE7941D8F -:103B0000849DDB5AB97735F2F926B91FEDA84DA788 -:103B100085A4E7BF325204CE6F43FEBDC50ECAE195 -:103B2000FC94C3BF03A981BE28895BED96E987ACED -:103B3000E519FDD6F2ACA3763B487F03ECA0C55C4B -:103B4000EEF55379CF92610665C047381AAB00B8DD -:103B5000EB486F33E44938789C7C31D77F0BB97ED2 -:103B600074A7B0786F4EBDC7E27F127ECF5F2EEF95 -:103B70003FAFEAE0EA3610B261C3AED2D06FCDBB40 -:103B8000E2D90A149736FBAA4EB79EE35F68B39F4B -:103B9000EC765685DC83F9B8D9B6B886B19F0BF3BD -:103BA00084FB0CECE39FEFB8467F908705F2CDB81D -:103BB000E705EF15A6EDF3E4B810A278CA6E60E74A -:103BC0007072D612BD27091DCF49617C310C6FD1AF -:103BD0007988B7F9FC5DB697DDCF955D25C5343A98 -:103BE0007E767D2FDA038B6EA3F3413BFC0CE6C19E -:103BF00018F5D3D37AF13CD2B61A81E7E712B46B49 -:103C00008C75DEE665E707EB2E156222B46F28C0DF -:103C1000F111AE82C4FA523C1D637862F986D75422 -:103C20005BCF39D6D9EC17831E16DADEFFD6C3F682 -:103C3000C50D3EF8F0E2A393C651385608DDD529EC -:103C400013CE5D5F9AF8C37106F8107E1FC3525FF2 -:103C5000308F57F9818AE73DD206B6134A92B529CB -:103C6000245A3517E4CFE085022D5F9BF2BDF6AEF6 -:103C70004BE1F8F6E0D360E4B95C3FB8AC3A2F51C1 -:103C8000F6787E82E5001F07B616D97A9BEE7DA1F5 -:103C9000A8DBCEF3E337E864B304B9B5A2BA39942C -:103CA0009F68970EED8451DA85C96639493BAFD1DB -:103CB0008EA2AB03EE75E2F3F2F0EF2287C73CBEB3 -:103CC0000C7853352F9E635C20AB9097F165E1181B -:103CD00073B67947C866C784E1ED28D8CD06FC6283 -:103CE00072F863F0DD3CBE6314F8FFD6F8385B7FF2 -:103CF0004EFEFDBCE1A3D55BC68C3C5F80CB81F75B -:103D00000D695ED1D4CFFD7D7FC2B8B87C3D09413D -:103D1000C84B76E82AECE715AB0FA27F2FA755A971 -:103D20006007ACA365B003D6F57663FCBBB8F08141 -:103D30002E20FAE2B887803C984AD4B4DDB4DFA9DB -:103D4000AA0C27AB887CE94111E2E9E46A82792375 -:103D5000A97D1E763F50FE9C47C1DF4A4B53703F02 -:103D600023256DE6A3CCE865716603FE948A23954E -:103D7000107F97EB484800B88418A900269B427032 -:103D80007FC3A3EFF9269C032032D34F78470EE878 -:103D9000551E6F1FCB48867439D53ACC5FF9998C84 -:103DA00071ACB170051825CAE2E2F4CD004F718400 -:103DB000762000FC2C5E36352286E2B4FFD213ACAE -:103DC0001DF9053B3F427D9325CF79137835E4CA31 -:103DD000581E870F2EB5C6A9C9209D336D5FFA8B7B -:103DE000458F439C62CC30F9CDFC760F8733F504C8 -:103DF0000943FF811AABDEF0F0FC6D8FEDFE988B6E -:103E00007C0EEBBDCF76FFE1DE30EA011709294ECB -:103E1000B42F96A2DD60F825DBA022D8E37984DDFB -:103E2000B76B6F3F93B52741E6A7B83C44514AE9C9 -:103E3000F7E51E1DF30D5DB44CF12838899245DF7E -:103E4000678B2CDED22C1019CA89F1E29867E052F8 -:103E5000AE6A03FB65BF321DEF4533FCEA5635847D -:103E60007910A4A8D262371BF95E6B4A0AC6C2F762 -:103E7000D43143712715E8724D6621DAD1FE8C8169 -:103E80007F0639FB598A6F81027215F230E6C0B5A0 -:103E9000B4AE8E2895BBAE53394433D9672EB901E1 -:103EA000E36CAE53E32CEFE34DD673D4BA57AC8238 -:103EB00071B2BD1A3BBF43D436685741ACE7A55D2C -:103EC000A7B22CF67AA2FF5CCBFB38B56BCCF7FB24 -:103ED0008CDC7F0AD18ACCFD4F18A1FF49B6FED5F4 -:103EE000A4FD27FACDB0F4DB2EB3F86B34E0497AA9 -:103EF000DF64A9B772BC77C6C8FB03255E16D7EC92 -:103F00000C36E0FE4025A18C4FE965DEE963123BEB -:103F1000C74BD07E23B9D6FD814A4EC722A50C3CA3 -:103F200017205BEF2D2E27F67B8CAD76D111086E16 -:103F3000517A177D65FDB84FF0272F9EF31BC96E90 -:103F4000EE6F22189F2E4F19B81DF6C1AFF48E7375 -:103F5000B607319F19FDF925DEE90BF8BD9F2CAF9F -:103F60003920225EC29563F19C96D14FD8492682B2 -:103F70005C0C8B2C0F027FE8F8FD99D98FAC4F8237 -:103F80003FFB39F73A5D282F34CDAB1FF20ACDE362 -:103F9000CDCFE9914CF308BBC80C1C8FDBBB43E3CE -:103FA0008DF962E3BDCAE359C678750BACF3AB7308 -:103FB000AA38BF3ACEC7C678AFC2FC92E0F7ACE3EE -:103FC000F1BCC9A1F12EB7CEAFCEA5E2FCEAF83D17 -:103FD000BB43E38DF962E319719D4E674303D0E162 -:103FE00048F11D23AE734DE72E4B5C874477CDAF70 -:103FF000282464B3C0E4C7F68DF33AC0FFFBB8666B -:104000004D11EA156E5FE37DAA541F2F9419BCB5BC -:10401000B9DE58B3098FDBA81CD127C3390985C085 -:1040200081323837A1E3398A203E1FA1F6BA8EF9D2 -:104030002545F8FD89A610967736CDC6A7D14FD174 -:104040006C76EFD794B94252BBFD752FB3DB37675F -:10405000A9D77F1DF45B8587E5FBCEBE84E8263BB0 -:104060009A1AD6FBDDB03F741D29011D39692B83D7 -:104070003B50352606EBEF2939D8DF047150D9A122 -:1040800061BEAB96FCEF18BCEC65FEBCCBC5DA9309 -:104090004BD8FDA7B55C3F11A906F38F6A17A6613F -:1040A0003EC2A2C5BA4FA5785B2C086F14727D077B -:1040B000E79EAEE54B6DF71702A079E87A05742903 -:1040C00006F7C35D9B7B788940FB0DFBAE413F2328 -:1040D0004C1BA6D37EAEE5FAB6E26D17817804B923 -:1040E000CC89F26BF162AB5FB0D91D57C1CED95C00 -:1040F0001220CDB4DDA21AEB77978BF155D876FF5D -:104100004BED59EE8331F26DEDF8B1C74D0F79F9F2 -:1041100079251E1F3D498AEFC7335F3C2FD7DEDE6E -:1041200088833679997CEB7432F9309C0F183CEF18 -:104130007139B8ADE928C6D10CF8B2E59800F23E65 -:10414000A7FEA825EF9D22168D6A639F8048BB4B72 -:10415000500FDBE6B34DD89D35DA7D50D9447E77DC -:10416000A088FFDD0261F8BCFFE0B5C6854F92B9BB -:10417000AF149264FCC3E2C1B587A450B396C08B60 -:104180008187FF6B3EDA0278A7CF57E67F52C6FCE5 -:10419000C05CCBDF0730CE6F5D335496896CA2E7ED -:1041A00085CB9D3AF357078B812E8F5C9A12627FE5 -:1041B000E782DB41F15F8960077DF9FEF53C4B5EEC -:1041C00033EF77A4F5B2E7539ACE1B27EE3F80FC7E -:1041D00097E65010ED814C91003F65433E9E9F7DD8 -:1041E0003F66B55B2DF978AD7DBB04881B6E87FCFF -:1041F00044D339BB9CFA5EA11DECBBE6188B43C4CB -:10420000693D0A776E7D5C682B4EE47DD9E57AEED8 -:104210006DD67CC1F6B98BD5DD1AE4D55476C3C50D -:104220005FEBB6B23897517F28DEC5CF9F3A48037F -:1042300081F3179297C59B83FC5E8EB3E5EF7E26D4 -:1042400046D5FC7CC8DB8D291574FE0F65442A7C9D -:10425000B4DFAE4069430FD0A71CC23CEFA58D77F9 -:1042600087214EA866248F832FE5F6418D8FC5D315 -:10427000DE72C4F3206EFE8B8CCA1ADF8C24F51B11 -:10428000EFC5FECA47B86FFE261FA3CFED62727955 -:1042900070031FE72B2B44BC47C84D7C783ED55D8F -:1042A000D83D1BF0B17DE5B650B27396D3D5C85753 -:1042B0007DA638ABBB90DD034048EFC530CF757F9E -:1042C0007EB8F7193AEFF43F7B51CEA64BAC5F5363 -:1042D000FB9BCCF331DAEFFBD32FF1FCFC3E7EAF3E -:1042E0003A89165C0E71F64D4619B600A09C3654FC -:1042F000BE1CFCCA44F9C70BE0EF266D021AA5C428 -:10430000F7DEA6C3A887370984EBE95F2CC0FEF867 -:104310003DEE2FF2EFE5577EF0E8FDA00F663AD1B3 -:10432000DFDCC4ED1D03BEF77DEC9CC2FB1C5F23EC -:10433000E1B393E3DB0BF80C9C173E3B93E1634145 -:1043400040EF023CBB21138482E0FEB3B216F2AD13 -:104350001F6A22E1AFD3396C0FEDD905678A68FB7C -:10436000FB93ADC70F33F46E1FC2730CE7E72BF45A -:10437000860015EB6611EC27091C5B475BD7A96922 -:104380004CCEC11D63F04CE7F6A5E4EA0F42FE8275 -:104390005AF66FB7AB54CE74E4F72F4916277EC296 -:1043A000CFECFEB411E2E22F70FC55A5877702DC5A -:1043B0006DEA03E8EF39051286FAEB660F10C1D4F7 -:1043C000EE2D3F5B0F0A772FC0EDBC98DD4FEDA3BC -:1043D000788704395F19837F9D768440FEBB2F78F0 -:1043E00004F35A7D6503C8EF280AB3195D813FA81D -:1043F00070FBED854D6F2F00BA48970C3ABCBD138A -:10440000E84C4A9491EE7AD259FB63F7DDDE09FE5F -:10441000E20E276D037230DB89F68D7D7E8738BC16 -:1044200082AA1F80F90DC3A76BE051B86F60D34417 -:10443000764F4BB9D8BFE46B4097577AD13EA3EF84 -:104440009798CFDB9FE4F83AE963F6D5A63F29F8C1 -:10445000DDBE1E23D1EB6FBF38BDFE76047AFD9D15 -:104460008D5E3F21C9E9F57F46A0D777E1BD1D2FBD -:10447000F6B244F4ADB0AF2C7FBE6027F4275F35B1 -:1044800077EB33F4297DBE318AAB19122CE79913EF -:10449000F23EF209F46FDC2B60FC7DA2BB7C23F4BE -:1044A0003B6BE6569063E7D0EF19C087BDDF5FF046 -:1044B0007ECBAFF44692DD93B0CBCFF2E37FE067E3 -:1044C000F546E29B5FF9597ECA487C13F70FF14D20 -:1044D000AA3FF3EC7C33C8EBD37518EB9F712E7CAD -:1044E000F3203EDD858C6F70FE7386F30D2111E4A1 -:1044F000938E7CC61745FE159DD15C131F917BAD35 -:104500007C44EEB5F0D1A7FE7B918FECEDFD23DC72 -:104510000778D110FF87A7C13CF40BD536763E69EA -:1045200000CFE1F690C13E17E609B3BC5C4F34AA58 -:1045300033F3A09FC0BDB3B378FB1DE0A3811F344C -:1045400093C7B3E47EB2C8379C9F7D65F132F3FD1B -:104550002E2FF3F6AED47039E0BD870C4C01FB6C06 -:10456000A4759ACFEB9F4ED7E7FB93D0F9D9F450BF -:10457000BD9FE9A17ADE4FFA9F9506B04FEDFC5E34 -:10458000BEF2C77F7C62947E6EE2EBFF55DECF17F2 -:10459000E0FFAFFA93F02FE5FF1B601D4CFC5F2698 -:1045A0001424E5FF9BFC49E407E5FF9BFD7F5B7E50 -:1045B0005FE34FC2975701BF659E1DDFCF717C3F00 -:1045C000F725F1BD85E37B83FF0BCBDB0DC9F04500 -:1045D000F1BDF11CF1BD65047C3FE8C7F57F16E134 -:1045E000F7695E8C9777CD227BA09F24703C6CEEA0 -:1045F00047D1583F94A73E1128DD977FDE154A76B4 -:10460000FF116DF768B276F3FDAA917CBE1AFC87A4 -:10461000ED5779715F81EAC72793F1C797A0831F90 -:10462000F893C8FD7291C921C77D1777421CEF4BE3 -:10463000F4FF9364FDDFC9E5FAD9EC82D7385DD089 -:1046400079FF977FC670F9D7C3CF270B6AE4177E2F -:104650008CDB0F5C01F26AC75DE902C4BB72F5B87E -:10466000007E025EEA43E1980B97F8CC48B4DB2168 -:10467000C705B83F6747832AC07929537F6FFA334C -:1046800047EECF0E0785EFD77E9477FA6FE0399F1C -:10469000CFEF7CEDA47DE9FAEFFD4C6EFF0F3CF50A -:1046A000C956B96DCC430C77B33CDBD9C9FF7EE565 -:1046B000019FCCF558F8B859FEBF3B4457ACBFF347 -:1046C000D53F14BECF387C7FC27E6DF0D9F17236F3 -:1046D0003827819E67FD49A999C3F594BD3FC3CF93 -:1046E00036D609AEC530C77DD4D421FD9D0AFD79EB -:1046F000DB453C4755CBE549EDEC346EB7AB1EE8E6 -:104700007F3B8FC36FBFED810AD857EFB9472D01AB -:104710001464D733BDA7DD360EE3ABD9BC5F3BFCD9 -:1047200043ED9DBD53E0EF42D071C7C1B8F3E692AF -:1047300038F88DA9603760BC42C5BF5F9CEEEA0EB9 -:10474000427C769DD0BD6419E8D52BBCEC5C4C70E6 -:10475000F159EEC56CB1D02D09969DA57E33D65783 -:1047600053BAF1FE9473AEEFEA4E6A67CD4B150D66 -:104770007F62CEA8780D0630EE65E077F8386CFDE4 -:104780002AC20D02E0DB5726A8907AE7A37402F64E -:104790009258D88F79535797317A21D42F19FDFE2B -:1047A000950E03AEABFF167019F5461E8FD7B39D5D -:1047B000B718FA3B635E26C7B0222D7F742823E921 -:1047C000BE82F1EC6C5275B80AF92355C37B193BD4 -:1047D00087F2BE43C145BEBF7FBDC4BC626CDFC9AA -:1047E000567FE8FE91A082F61FFEFD0E131D75A4F4 -:1047F00032BF554A0BDF9D8AF23784F73FD2F2B7BA -:10480000B0ACD0B20FCB4DB03E441D2A37E3F720F9 -:10481000AB4F54F59CF04EDB75613B79A89FF5D802 -:10482000AF7768DC8D580E0C95EFC3FAB9ACFEB9C2 -:104830008E33ECFE957E09E7FF89ACA7C2BEE97511 -:104840008D5FC3F8D2F58DB7E0B3AB49AD80389D2D -:10485000710FC975D77F4D057FFAFA9BB6E0BEBED2 -:10486000D1FF42F03B80FF35B91AEC2567BE187EB8 -:10487000CC9BE0BF041C6D58AE95D97DFE0B679FA5 -:10488000D8D4668ADF29F077D121BF4633DD834152 -:1048900012F2F04941DF9D7A1EF43C7C9E841CA4F8 -:1048A000F4FB89B73016457AAE5493F18D31DF9120 -:1048B000FA37E63B92BC31F066BC5F57C8FF8EAE5C -:1048C0002D7EE99E5885F93F0B050EA78FDF0BC99A -:1048D000EBD5D2719E2D46BAD0806E6BB97F67D76B -:1048E0000FC6B84F0A91D7013F1027BEA774387E74 -:1048F000CF156F46FF63235102F772798A09EE8B59 -:10490000057CC6BE3A936B0F7A8D7214934BC285A9 -:10491000DD28E7DC9A21F7989E54537A75B184FA22 -:1049200041A97FBD3C3805F2402341F8133EB4FC59 -:1049300012DCCF9C2EB132217F7DE920DA3FEA05DF -:104940007093A3227FFED2A13CC28E2E62DCE6F3DE -:1049500097209ED733542671385FD0E3192AEB4A4B -:1049600090960B86CA5128EFE076DFE9D4CF5F6AD4 -:10497000437D16FE0CF8C790AB155CAEFEADE4E9C6 -:10498000FF02CED174B20080000000001F8B08002F -:1049900000000000000BE57D0B7854D5B5F03E73A8 -:1049A000E695642699BC27BC721240A23C9C040286 -:1049B00041B14E78355E790CF51524C824E1119E7D -:1049C00001A432ADB60C24202868AC2FEA833B2822 -:1049D000F66AAFF682C55BFE16F907410B2D62AC95 -:1049E000A8F840C3A3151F2511B44CAD2D77ADB564 -:1049F000F7CE9C733203C1B6FFDFFFFBC3D72EF7A0 -:104A000039FBECC75A6BAFB5F65A6BEF612CCC583B -:104A10002E639BB566CFE8618C85BD565F7F8DB1F7 -:104A2000750CFE0A183B877F5733D6D76367AC9C5B -:104A3000B1473283291EA83FE98E0EAB13EA398BAA -:104A400072DC41176385DE2FC295F07DE128C63404 -:104A5000FCB65F166323A15DEF32C59E037010F3B1 -:104A6000288CDEADF240FD1C3763AD009935C2D80D -:104A700020C61E70C9328C0760A024C2DAE079AA71 -:104A8000C6DF5BB00CCF55075BBC15CA6925CC1FD0 -:104A900081B2C7C1660400F6F258681E033DAA80C1 -:104AA0000A8D37C3DBCC34A8EFACB2F82300331047 -:104AB000BAE2F362AC99EA0DF4580932818FF13908 -:104AC000C1011E286F66AC6A2B8E8B450325308F83 -:104AD000D44B73B2EE825265897519832EFF7D0522 -:104AE0000BCCB43136D413B0637D57694E6A701065 -:104AF00095875079B525CC002F95CC1D518AE27849 -:104B00008191A706DCF171C4C7C3FB7F6B453030D0 -:104B1000D6D6F5BD84374E5503FA79485889788042 -:104B20007E4F55FFFE219CCE4267879D15033DFBBE -:104B3000DD17602ACE47A3F7CEED53A23DE1FDA2DB -:104B40001D4B188E77555AFA28A4A3B9DFB7BE7E3D -:104B5000D81380F7297F7604B626E86F0EE219C6CF -:104B60007B6845357D07CD6BD63CC666E0548A1917 -:104B700011B4CD899029E71C34BD43FDE0FD2D8C97 -:104B800033C3F581DA890CF05A57AD32B508BFEB63 -:104B9000ACCFCE41F996B6DA096C081442B613F8D8 -:104BA000DC09FFCE41BB419639DE038F6BC3FC3974 -:104BB000D587FFCD62BEF1B9F05DFD5AD3F3F7AFF3 -:104BC000F998A5E37BEB89B69278FB3755D706C6F3 -:104BD0008A7A67E8FF23849FEB35E647BA5DEF4B9F -:104BE0008B84618A3704A606C696C4DB7BFBAFEADA -:104BF0000CC48B191FDB05DF1D5A11088CEDDF1566 -:104C00001F7501C5EED12E8C97EEE2A1D65A3A3E21 -:104C100057EB8A07F3FC01631B10CFB300CF771566 -:104C200025C707D4237ABC3D15EAC154C6AB136C23 -:104C300016C043FD14853914C26F3AEB8BF5FC1393 -:104C4000C6E9C66BC6A3195FF52F325F14DAAD7FD4 -:104C5000D0ED030E67BF93F88902D286833CE155FD -:104C6000F5F33C86E3F7C03F9CE7772A4A5FCE81A5 -:104C700071049B151FE3F33DA69F5F1D0B64441554 -:104C80009AF7B124743FA69FA7797CE6F1A7A0B05C -:104C900002F9177ABFE89EBDBA7ACC1A1D1418CC57 -:104CA000D8331E77CE1FD2A03C84F9CEC1BAFA9277 -:104CB0008DCA188AEFFBE5D0FA36F3C5D915DA3D6F -:104CC0007B6DFA75CEF96C46684A67BFD8BEC28262 -:104CD0009D650FE0393055DD7003FCF75BFBB25783 -:104CE000E3B3A55E553B918DF882F912BDFC8C496A -:104CF000FE6208C3BB55C0DF14E6D45CD0CED5201D -:104D0000A4CEC15C26F95334976E1EA75B942A94F7 -:104D1000A340BC8CEB07C7E76B1EF752AF9DFA03AD -:104D20007EFC42CF8F66BCBC55DD3703E5C88138B9 -:104D30005E865C0C5E46E3620639E2C9665105E8B0 -:104D4000DCA138234FC0986A42B707C60E45BCB0F5 -:104D5000B01D44E7514F11D593F3B631F9B798A17F -:104D60003CADB1B320CEEB7D1BABDEE64218ED5D72 -:104D7000A6935B27B22B8FA25C96E59AD00FA97DF4 -:104D80006044E243C9CFB7385D5195F3E1679D7C3C -:104D900043F2ACC6F387814427760EE6A9662CD091 -:104DA00070DE6A5AFA1096C1D85AAC02F354330333 -:104DB0007F443DA9A6F58920FFA54E7D722DA7E36E -:104DC000FD5537EAE89832EBE7616A5CCB32E03FA9 -:104DD0004DD0AF52D02FA5C469A61FC3751A2E613E -:104DE00091A7148102289FEEE78FE0BA4DA63724E1 -:104DF0003D534AAC5FB5E9F99AB5103F4A3AB2BDA6 -:104E0000C33A70BD06BD567617BD2F21FC043D1276 -:104E10003F1D36D4273342B6D3FA76820533232B8F -:104E2000F1BB750E1F3EABB36879580FF0E4413DFE -:104E3000CE4A7C3E5C3F2C0CDF497E42BCA231A1B5 -:104E40006BBF0DE6505086ED81F4C4EFD6EAFA2927 -:104E5000EEDA6FE7BA32B76BFA4E55C17E203BC22D -:104E6000E7F3E9E4779F4C6E3F9CF60EDB6A294E30 -:104E70008EBF3A67B6DF9A1D2F1F2B70564712E878 -:104E800001D99ED4E7596AD06BC1B9B127F7ED1D9E -:104E9000857AD87319483276F7EAC7F7EDEBCD90EB -:104EA0004518EB81D51FDFE77791DDC1CBC898307E -:104EB000FECDA99D65BFD30BE5E2CE7218CB9BA0BA -:104EC0003B7605C8EBFB1EDFD70CDF9F3DE220FDE4 -:104ED00075BA2A35828B273B34861D87715BC1CC1E -:104EE000C90056031046E80CF5A4F92856C01CE08A -:104EF0003B5BF32988EFC9991AF183556351370C4D -:104F00002EDBEA53105F3FB2B30621372E9DA2B3CA -:104F10005F266772BB43F6E370B2704A59BC5DC648 -:104F20007C2B518F582730D22BB0CEC96E93EB5BC0 -:104F3000B6332D93EBCFCEF579E1F53C2D33C17A25 -:104F40003E6059FCE10FD09EFD8DCA9E82A94CF7B0 -:104F50007E8F9EDF18AA2738353497E0AC4C6EBFA1 -:104F6000FC9E056765026CAD7E63FA72E0DFC6EDFC -:104F70000E1FAAE585B77D7C4FB9867802BAE37724 -:104F8000B3EA1F2C87F7F6FE16B267D7F666D5C8C8 -:104F90004FF6950AD947EB347BD576800F6454DE03 -:104FA0008FEDC9713D903196CAAC4AB3209F2F75E1 -:104FB000723E3F7BE44E6F1DDA952E17AD17FBCA8C -:104FC000A27B2D5066FB61DC0CE507233B4375702B -:104FD000B83A93DBA9AB05BE7F20F8CC1943227306 -:104FE000BE5E0CFD3BAD618676B63366A5E7760501 -:104FF000C697804F657BCE182CD2A1D89FF97B3BFA -:105000003DC779E1F76A3633D83DF7E0F7B908E5EF -:1050100038D2F838B2CDEDA4F3E762FD99C771D26A -:1050200033E647889F0732FCF767921DDE664379B7 -:105030007E8BEB37879521DD91C76D0ACAE3495F07 -:105040002BD142C05F4AA51A5955847ACD337118C5 -:10505000F001ABB4F9109FADFD72DCC5BAFE9F1232 -:10506000F47FDDEA71E33803E3C0AE26FE66B9D70C -:10507000633BE3EA8773F90706974ECFBEAE6D59DF -:105080005B8CF2376CA3FDD20C673882E3D3D96D09 -:10509000CA392E9735EBF0B8FD3763ACEA4F49EFCC -:1050A0006ADFC136642FD97F529687A10CDF7D203D -:1050B0008A1F8E3D73034EA38D79ECC57A7B1077E2 -:1050C0004BC3D1BEE17F334246BBCF6C17D655945C -:1050D000BE026400BC44AA86219F5D6A213EEBAEFD -:1050E000BDCCD87D9CCEE39A3CB8AF7A04E504EE03 -:1050F00007C71E1F4B72034C2B6C77F258D51385D4 -:10510000DAEB4316E687811FF4AB1105E676B0A40F -:105110006DFFD588B70A9B467AAB846DB82E07DF42 -:105120000FF5209E03C20E81FA5CBF799D91FEF0BF -:10513000ACD57FDC55AFE3BB8315C72FC5FD0AC8CF -:10514000BD8644FCC4D84AE2EBBDDF4FA5763E7C69 -:1051500040893860FCE3D4AF5F1D81F6EC0F6C3EF4 -:105160008746D3B2205D27F898D8B8FA5DE3747605 -:10517000C07116184E7665E9914A07DAAFAB155A39 -:10518000A712FF3342467B33B818EC32ADAB7D0A31 -:105190008DD9919FBB6B9F9AEDABB399C2AE2A6339 -:1051A000657ABB2A999E92769595F9FF467287B5E6 -:1051B0005951EF4E820789E4C04D195CEE8E533F82 -:1051C00023FA9CAE5035C4D7C1D0272EDC8F1FFCEC -:1051D0005AE5FB607FAEC18ECBC9E27E814D763051 -:1051E000C8E0BB4D3D9C9195D0D4EEEF5F96DF4675 -:1051F000F4D11E1E8574FC8D8DE470B2F1BA432A81 -:10520000EB078C3931A41094F42B0CA530AB4E3F36 -:1052100014B2C4E3EF9FC5C79F7B07B368D06F6626 -:1052200098F913ED8F653DD8178FB732AA1FCD843B -:10523000F12DEA6721FE94FBE3145BD8DF13E66FE0 -:10524000DBB9248CFBE442181F8E4383F1A1BE2CF2 -:105250000AA551B938944DB06F289360BF504F7A6A -:10526000DF3FD497E025A1227A3E203490CA25A1C1 -:10527000A1042F0D9512BC2C7425C181A037B1DE7D -:10528000A05025C1C1A16BE9F990D075042F0F4D35 -:1052900021E80B4DA3F7A5A17A8265A15A7A3E3485 -:1052A000349FCAC342B752B93CB484E0F0D0ED0495 -:1052B00047849A0856845652BD91A1BBA97C45E803 -:1052C0007E825786EE23382AF428BD97764BAA585B -:1052D0008F776B333DE8EF000ED7908F93ADBB997E -:1052E000595C2F1DC8F44FC82A8FD7B35B408FBBC2 -:1052F000BAD60B6671BD9189744DD0DE3441AF537F -:10530000BE630F0D6071BAADF39EDF9FC14A12EF0D -:1053100037E2F281CFEFDA2C2EBF36595BFD2AF24D -:10532000EF62E60BC3A389C35E5750BE6CD6AC5583 -:1053300089ECBB07B26CF4DD2399C1F95900D38A1B -:105340004EEC45793239EC797534F2CBA09CDF8C88 -:1053500086F60A9B2DB4DDD7986737FAD7B4B18C9F -:10536000E4A2F42B815D67D0A7EB055E18DBBAAF32 -:1053700098D653BF32AE7FDAAEC1F565FF7E31ED10 -:10538000DF37D9A38A15ED9BA5A0C374F6FFA63518 -:10539000753FC1F7F1F6EC34CEC2B5EC2534B18BD4 -:1053A0005AB4D12900FB6EF4BF94029FF48F0447D6 -:1053B000A74279C0D3E197105EBA35323A0DE0C00A -:1053C0001DD19750DC0C8EB68D7641F9F27D6C0FB5 -:1053D0002EFFD2566D8C1BCA430FFBF7001BB0F299 -:1053E000B6E098740DC713694A87F16CFA000C3D5A -:1053F00028577CD6A2C276284E7FB0E3D07E937425 -:10540000710F6B1D9B0DFFD96B99A754C5EFAD6D47 -:10541000299983BAD26733CE1BE7097AE4299857D2 -:105420002F7F54F1E8F864479622E9F018F29BF4D4 -:105430004B6E6ECE22BFE4E6544F2576D9318E797D -:105440009ED0908FAD8427FBEA62F2C749BE03FC71 -:105450001AECD9F582EF3675DABB89F1BB43C8BFC8 -:105460007F15FC7E5BF07332FC3A9157465E781DE7 -:10547000EF17EB12D6F1CBC8DFC9EA9D12F837E37C -:1054800079B385ED035D05FD029FF275C5D08FF6FA -:10549000B1E0EF0BE1F5F8BF18DF462F8057A6E526 -:1054A000909C047EBD14FD63C9E48D5DEC67CCEF78 -:1054B000635DE51CF7DB7A40CEF54D2EE7F666F12D -:1054C000E749E597903376937FC796CDFB1BEA09B2 -:1054D000A8D989FCD4DE1C839F7A82EAA94479C3C7 -:1054E0000630B2A3D30645C2B84F290C6B652A56C5 -:1054F00043A18C78EC5142FE8722B033AC407F68E8 -:105500002A8AD0A9792C75E87F97EBCD53EBD5AFDC -:1055100037A9EFE3EB51F245D6E6BBB85F529B02E9 -:10552000F6CB5831EE783BDC0FB2E67B3D36DFA59B -:1055300093839BBD5E2ACBFAC9F8B72E5BF06FF35D -:105540002AC2A7735462BBE15BD9AAE0DB0E3FF22B -:1055500079F85BCC83F64C66F331924F99209F1417 -:10556000924FBCFF5EA1D49F84A17C55769EF00330 -:1055700078526F74FFDFE3E72CB4A9703D8DF2EC35 -:1055800056314E037A48C3753A0AC63E0CF1652778 -:10559000BA6B8CD3511BC52268F702DEA2B86F0F1D -:1055A0005BDCE467B2DB5BFCB89E993D93E63FD4DD -:1055B000139C907D9E75E149D34A91A8D3EFFFD902 -:1055C000352EE0BF35459E542CDF0CE5F515D06F28 -:1055D000561B13E575AE91DFDCEF313DFBB9FDCD18 -:1055E000D0DFAE2CFF341C0FF0F57484FE011E2BAF -:1055F000F9ABBDDDB307E4FA8CAF274FA95C4FB51B -:1056000083481ECEC176657BC9EC9BA26C2EE74217 -:105610000226B36F24DF5FB47D23C63B3BFBFCEB6C -:10562000FFAD7DF76FDCC274FEC61E0FB55A35F4B0 -:1056300067703F8DC5D94AEDB985BFD18FFE46E071 -:1056400003673F5EC6BF44FEE2E4788CD078A49F37 -:1056500051FA13D3055F31AB12413D9E5EE1B1D6E5 -:10566000517B6DEC3BD0DE83024F725DA3DC7A7E12 -:1056700010CAA52C2BEED7D19FE4CE8AB78FE58C2C -:10568000B2B87C62621F77AB1873CB2A5F06BA9CF4 -:10569000C307B91FA5E5877C5D4EECC522AB504E14 -:1056A000F899E681FA294CFEF90DFEE4095F29CC50 -:1056B0000FE33FF0954A50E9C7A26ED8EF4DF429A9 -:1056C00051DC07DA2DCE08EAD2CA1E4E86F14D7B98 -:1056D000BA2582F111FB3185E6692F4B8BA0F01BB7 -:1056E000DBA32203E398670EEC710513D0FFA660DD -:1056F000ADC1FF65C66367BDE92F7B108F8F5E204C -:105700004EBB37BB334EBB0BF974D2CC8E66BB1687 -:105710008FD3CAF8638177FBBA4A54590BB87DDA44 -:10572000834556EAED2A5D1C741FB6F3683C0EDA19 -:105730007A893E0EDAD86327DABB3FEE8C83067F88 -:1057400085FAC49FBDB514F9F751DFF667EE457CC5 -:105750003A44BC62E81197867EFAF23DB9389F5709 -:105760004DE39750FAF1CCFBE0C3D9C6F8C219DF7C -:10577000751951E2ADEC84EB5BFA17E57E18FD87F5 -:105780009E84EBD0886FD97F8DC2F7B5CCA670F917 -:1057900027F428C8974F480E4418E94DBF437902B3 -:1057A000F5CD19DF501FC53D93C81B391EC063FFDF -:1057B00044F15FE82F619CD59AC3F5588D8DFB4D60 -:1057C0009525E58B715C356E97E2D0F9FB3B84BE85 -:1057D00033C785D48CAFCB83C2EF9D68FEE6F84E0D -:1057E00087D017882FBD9FFC42F83A6C6BA1F8E177 -:1057F000E1592A5B09ED9C098EC86709BE97F05DE7 -:10580000E49BFE0073787F9DF44C122F3ABCA2817A -:10581000E2CCE6785AE7FBDA946AD4DFD588475DB4 -:10582000BFE5395CCF4F129039829A07DEDBEB1E61 -:10583000F4308C7FF5FFA23CEC46BF58C70B18BF75 -:10584000603F7093BFA2BAF6CBF2958375F8AC6057 -:105850003C3EBBE7C71E0D9E57F76FCE0DBB92E3D4 -:105860007112B60578BA1B1F8C247F8C2F87FB37EB -:10587000BBE58F6183785C88ED49A1F869CA9BAA72 -:105880000FED06EC97EB01EE4F5E26E226E6385E62 -:1058900075689141BEA4C51416D1C52FD2AC5BC9A1 -:1058A0003F9B16B3D273F37ACBCA81F53630BEDE96 -:1058B00024FE93D153E2DFFC7CB0C0FBE1DAB91ADD -:1058C000FA0DEDA989EDE066514F96CDF908C9E2D0 -:1058D000EEB5627D9C098ECC477F55B53DDCBF3B64 -:1058E000EB5CE2E742790E37E7F0FD907BEA1B22A2 -:1058F0008EA736636B52AFA659CF1F8FF59BE2B1CF -:1059000069C3BAC4F3FE29F1D81F9AE8D7DD78EC51 -:1059100078B11E2F94877293DD68F748789DA0E3D5 -:1059200099600A0B837CBCB552A53814F007E9C70F -:10593000C30F2A646F466B1DA497EB6B53C83F5B84 -:105940005FAAD2FBFA0D2AE9CF28C88705201F5E7F -:105950001572C2EC9FAD648A217E3E69588AA13CD3 -:1059600075D6FDAFAE40FF72854DC3FE0E6ADCDF1B -:105970001CF6AB64BF421BBE28FAA71FB8CA87FA41 -:105980004CF2C341BF4AEB2D7C48F561B7ADC21F55 -:105990007D706D6904F35498128FD36B7DB1FD7ADD -:1059A0008A03BFE3DD4871CE94BF3E1C08D0FE31B0 -:1059B000A89592DEE4F1D314B14EC7F4A8B811F55E -:1059C000F887EB6D0CFD461FDE7186D673DB8AC54A -:1059D000941721FDCBD23F6CF6339BFDCB5DFCCA07 -:1059E000267F72B27C86977212C7EBA5BC4AC61F8F -:1059F00020B6F67F133926E5C7BB629E637A6CDC5E -:105A0000B012F0903653253C48BE7CE7EB3B1F4775 -:105A1000399C02FCB18A213EFFE365DC87B0B94ABC -:105A2000423F72AA94EB983F5112A7CBD4E0DCCE50 -:105A3000322EFF690D4B0C791F66BD925CAE9D5FE7 -:105A40006EADCFE1FE0AB3DE31AF877FB4DEA9AE23 -:105A50007DB004BFAFAE9D1541B8AE87B301E5AFD1 -:105A6000593E98F5C47526391BD70F2A8B0CD58F54 -:105A70005BA37A713D61A7F7675378BE43C8C9E15C -:105A8000F2D4F427109E4DE1F90E61340AD14EFD97 -:105A9000202DD244FBF2C523904F42CCD716C679B5 -:105AA0007A53C98FD0D28BD753AF49E576F9DE4A06 -:105AB0009AAF2A0DF3E64A5A374D622E3FCE0EF6C4 -:105AC000C885F134F92D29185F18E3B6EE47D74B96 -:105AD000CB680B73B038BEE27921CCA3C0F7F44E8B -:105AE000C1FD67A9D3DE97ECD4E25CE4CB1FC2FE14 -:105AF00010F8FEC00175FB6698EA01DFD08C447691 -:105B0000BA84E638F291EFBEDD07D7EDEF59703079 -:105B1000B6D75A5DBF01E3C38D3B548A2F4DBFED0D -:105B20009D4BC8EE36C529D5746709FA539A94542B -:105B30001FCA1389C7DD6E3BC999A62369B49F6844 -:105B40003AAA88B29BE4A1C4FB5EA857300C7395B7 -:105B5000DC243725FE615E57217E241D2A59F4C0BE -:105B6000A8A2BF6B5E55E79F572F0FC90FE43335CF -:105B70003E0FD56DA5F9B5B3541F8E2F24FC43EC11 -:105B8000FD34DAFF493A370A7E94745E24E8DCBEBD -:105B9000F3CB7BAE84FA2DFE2C8A3AA8BD19E1A185 -:105BA000FD7D37F189C4839C37F0C574FDBCF7ECEB -:105BB0001C7A3888DFA7A7521C5FDADD32EFC03CC1 -:105BC000FF1AB17F6FC8553AED5EF45FBC9A3DBADB -:105BD00021B73C417D61EF02BEE763BF951EF645EC -:105BE00084C5F779C9F21B96E72A179BDFB05CDF03 -:105BF0007F677EC337A7E7AA8BA167A3D5B556C930 -:105C000088E35BEE9B69496B5DD7BF79FD497A28D4 -:105C10003B77FF19E3F866B9B05C5DCC14E867CD5B -:105C200060BE2ED91D4CA3FC20D37AB990BC01FADA -:105C30003F8E74482677BA4BFFA7BBD2FFE9F3D15A -:105C40007F4376E0A7F81EBBEA5946FBC267B18CDA -:105C5000F2C45E4CFD11DF766432CA6793F931728B -:105C60003C324FE65798B49AABCBC329F129A82709 -:105C7000BAC11FBFFA07F3C72BE7E78F28ADD3855B -:105C800082FE0B655EC6F6F3E76574837E6F26A21F -:105C9000DF72D5D7112CEA3EFDDABAD2AFEDFCF4B3 -:105CA0000B1E277D62675F90FD5E51EB457E19EA12 -:105CB000F14FC6B8F9AE9542EE1401FDE0FDCB39C7 -:105CC0002AC9B51FB1CB486E7FCB62A1F1B683BCA8 -:105CD0007E42E9D63CCF90DE61616B16B4BBFC3AE4 -:105CE00046F13DAFB652C172BE067A5AEBFE7CFF5A -:105CF000D675BE7FBB80BC52F272893F97217F3A36 -:105D0000358FF57CF2CA9D67B413BAC18FEEBCDC47 -:105D10007F283F7AF32E42AF7603FFC5D85E323933 -:105D2000D1DD3C5058A7AC6756D7FE19F3515CAD96 -:105D300032DDC9F5F63645E8F1D22095DD4E121672 -:105D40007B859E3FBD9DBF574727B62B07E6651154 -:105D5000FE176E5D12B01AF249C2F4FC5EFF694F85 -:105D60003F15F3B45D349FEC89DC0F29E72FF3B4C2 -:105D7000D3C57CB27BF379671FE179ED125FE962ED -:105D8000BF91516135EC2324DE96AB0105FDE89906 -:105D9000390CD324609F3048413F57A6DF585FE25B -:105DA0003B97ADFF5CC594AF2AE3FB5CDCCF0CC135 -:105DB000F7BAE709F6AF409F12CC1FBB314FEC4F4B -:105DC000ECCC8BFA88A935E7E523DDFE647A5E37F3 -:105DD000F627F57932DE6ED47B5B5358423FC3E73A -:105DE000623D80BD42FE6655E8B9B16D4594EFB2A3 -:105DF000D4AD91FF41557DCE09455DBFCFF4C3F2CF -:105E0000D6E123BB2A9569BA79E706B20CE5FCEA2C -:105E10001E86FA05C162C3FB9E0D9719DEF75E5C14 -:105E200066281786AE30D42F02C4EACB7DD7FE9BFE -:105E3000A17EFF96EF18CA0336DE6CA87F69A4CE58 -:105E4000F07EE0D3F30CEF076F5D6A285FBEE3FBE3 -:105E500086FA4DC28F6CC6CBF63C6E173559B91C0D -:105E60005AE92A23FF6693CBE8DFBC47D4ABCC18B2 -:105E700055827EF5A663A52588EFBDE957909F3D25 -:105E8000195F98E55A32796A7EFE9CA0F7A997ECD3 -:105E900016E4EB457B60DD5E0E65D7BB6B704EEBA9 -:105EA00006F1F8AC8DF17C2119AF91DF77C66BACB0 -:105EB0003EEEAF4D77B1BB12F0C53D795A427FAA95 -:105EC000E4A3647893FC7821BCBD20EAFDBD787B17 -:105ED0005FE1F9AE7A7DB02DC1B84E897505FAE65D -:105EE000B53C6E0F0D4B254BDE43EBF162F5811C8B -:105EF00007E8837751BF98F3744F55BF31FB610DAD -:105F0000EBCFE6F52DBE12A44B327FFAA9BC2EFED4 -:105F1000F406EE4F4F35E0ED7DB9DE4D7EBDA6F4C3 -:105F2000AFC89FDE64F79574C79FFE3E7C8BFDBDB6 -:105F30008074CED5D157F8E393EDA3428CEDC7F32F -:105F400010CC65D5F4FBA664FB6329CF617F5C822E -:105F500071DA16DC7F2909F5A035BF9CF6CFA40FB6 -:105F60005A400F3AC84FC0F66B505E3EC6C2EED2E2 -:105F7000E2F396F6BC83F99C7695E89A9A8F78F9C5 -:105F8000215B96A2FE43F699B9F917A1E7D985E3FB -:105F90007D64A74D84F9AFD2EDAF257ECCF13D896C -:105FA0009F893E1EBF5B0DFA11E37BBB73B99E5EFA -:105FB0000DFB6FC4A3273BE0ED83F63C3C7F02C999 -:105FC000913B9CD68FC4AB39CED75DB933229FF3BA -:105FD000A3CE8E1B919FC03F133FAFC2E7BF54ECCF -:105FE0009FC7A983B6A21FF374CC4E785319CFBBB9 -:105FF0006CDC676311A223CF5F9674B4C5D6B4A2DC -:106000007EB63173BEB29681F3B7EDE3E7C4580EA6 -:106010007F1F66CE9568F7645418F557A6DFA8BFB2 -:10602000B2ABB24CFACCA8BFF2AB8DFAAB2068D4BD -:106030005F3D1BCA4CFACCA8BF0A43A34DFACCA8BB -:10604000BFFAAEFD8E499F19F5D7808D46FD756963 -:10605000C4A8BF063EBDD4A4CF8CFAEBF21DAB0C96 -:10606000EF4BA37719DE0FDDF72343B9BCF51143DE -:10607000FD39FB7F4E793D230E3F61A837B2EDA776 -:10608000867A80F056CCFF9E492461ECCA93CF1BE0 -:10609000DECF14F6DA551DBF34B4C35A781E771814 -:1060A000FE21BD3E62413B1A2956D6F14A4FA0EB74 -:1060B000A288E28B42B5B93BB60DC7717CFAC135F7 -:1060C000FBB09D391B8DF9DF7323C672232BCE40A5 -:1060D000B9D0087C11013E998F79E13AF9369F2DAC -:1060E00016E702BBC76773F65FC7289F34EC6FC51E -:1060F000BC77394FC96F7EC16F727C72BEF3C1FE2F -:106100008B6AF179FAE11FDF6FB6D9916F67EF50B3 -:10611000D8234AD7F934ECBC6F4DCF04F332CFC348 -:106120006C87FE24DF183F19A7BA285E70FA90EA40 -:10613000E3FE46E33A5CBA9FC709963EA790BFCEFE -:106140008C0F699F26C38B1AE6FB86C61C1689E84E -:10615000D69F26F0E1F01AD7DF69FC0F1CCF636AE7 -:1061600004F38D52B45433BF0D8FB2AE784E2B3141 -:10617000AE53339EDDBE1E09F94A837F388ED9E2C5 -:10618000FCA199AFCC785FB4E33E3BCAC38BC5FB9F -:106190009BF989E312A0ED86D913E4D749BCC2BEAE -:1061A000FD3DD423C9F6B31FE55FF47EF6A3FC7F63 -:1061B000EC7EF6F4F9F45C3BFADBC0BE34FBD9CCE0 -:1061C0007A58D9B9E7CF4A3AF9B5DB1CB8EE823E26 -:1061D00027CF8331E9C99212839EECDCF71E536806 -:1061E000DFBB2DC3AF78613CAF64F82D08A766F81C -:1061F00055AF6EBE4D80173AF7037A6A5B023BF1EA -:106200006AAFB48F02E437595DC9EB9BEB0DF0F236 -:106210007342BB73877BC9FE3C5AEA25FBD33DFC26 -:10622000BCF6E7BD224E7437C621FBC7F383368820 -:10623000780D2C3B3FD26DB52DE0D5E70FA77A3313 -:10624000499FA68F7CBE15F3A89B3C168FA221E424 -:10625000F9DCCD2E6BD516F15D8EE13B3E4E15F18E -:106260000D78B5BAAC5FE9F9F66A2FE3E7AF92CCE7 -:10627000F36A2F8F13DB587003DA43323E6C3B56C0 -:10628000E94479D7C4FC1E2E277D1E7DFE878DF143 -:1062900078F068111F96CF55CF37CBC3FA6D46F013 -:1062A0005BDE047958CB32FC57237D43D6B003ED37 -:1062B000CE9033F1BE789C57C4EDC47CC10025BE9E -:1062C000A271A8171FFF017B3380FD2E57C39427AF -:1062D000D9E41E5E127475DFCF35CDDBC53E9AE67C -:1062E0003D8F7D04F6E9643C47E6CFE861A56D8704 -:1062F000D55782F85E8BFF3D92FCB475889F2E794E -:10630000AFE21C2EECE3CE9BC72BDBD995E59FEBD0 -:10631000E5F986F3B13DFF004FB3AA6B27FD02ED0F -:10632000483F4737FC56DFF326F05B2D577D27515A -:10633000BF77178FCDDE2EFEC266EF79FC85678FA3 -:106340000CC8C078B6F47799EBC97391B2BC36D358 -:10635000D8FF9A325EBE57D0EF77E27E8A27C538E3 -:106360009CA6F3A2CE098CEEE990E74C653B4F7AF0 -:10637000DD54FF8EECD14FE278D71429B40F5D9332 -:10638000A918F6A3B7782B9F447A3C2EFA7B52F0DB -:10639000EFE662EECF31E761CE11F5E7784713C43F -:1063A00073AD28C7ECAA9A108F4F7BF9F8274343A7 -:1063B000941F27FC6EF50F2A62FF64BC1701D6F903 -:1063C0005B69207F8EAFB7D1B9D759AA6B0DF26345 -:1063D000B27B0E6A070528FFE9EF3D3F86F84CCBFC -:1063E000EAAA57A3DE4E7BC67791E7C87ECDF1D3EC -:1063F000BD787F5B2AE7D30EB78BFCE6E67A4705CC -:10640000FDD70BBF06CA75D42F592A5B9C48CF1CF9 -:106410001572F59B9F6BE6F77964BB5CF49DF95CA4 -:10642000739BBD6D753E8EF72AC587E717F26B3CEF -:10643000BBF373F01CA3463EBE35452CBD02DF976F -:106440005AE87DE6F59E3536CCFBD61866EE331B52 -:10645000F4E3867E520A781C677DF8BADDF9502F86 -:1064600043EB60C583E8BCF7782FAEDB6A9E3F6FD5 -:106470009EDF57021FAED5B0BF407C6889F3D0BF06 -:1064800012780079F367A447A5C6B6F373593C0F99 -:1064900016D992F2157D3C5F3B0DF39DFA7279831C -:1064A000EFBFCE1A730EBF93EB4B15F8369FE74E36 -:1064B00029B8B8F3DC936B128FB75F01E787C31974 -:1064C000818C02E877F2A895DC1FF6F5B973EA70C3 -:1064D000348EF93A81EF19FA2B5272B81C4ED1342E -:1064E00092CBCCA3509EAB53F3356039C57585472D -:1064F000453BD9C1E3926CA685E1FD2A63443BFE8E -:106500006AA6FCA184FB65B99CB5B23F48FE57055D -:106510007286A39EE57F603FAD4F83F98C711DA00D -:10652000F8644ABFC59578AEE1E519BC8D1F2539E1 -:106530003720CFBB779EEB0F470E18CEF5DB1E3D05 -:106540006038D7CF1E3DF0F79CEBAF2C78F4C03FFE -:10655000F35CBF946787D5E0E1DB01FF370053852B -:10656000CA105A590DD1DB4B78BB5EE039FC15E0FF -:10657000D919C7F30D3BF713FE0EDB60DCD0BF6DFE -:106580003447B5EDFB199126928B11EAF74667CB9C -:1065900038DC77B6DB3B8660BFED2FBEDD3B0CF20F -:1065A000E4C80FCEB819F0DF87D60E373E3F79C763 -:1065B0001B6EC4D7913B54B2D7E85CB42E1FA95EC2 -:1065C000F0D54B05819B91AF66ACF8EB70BD3DCE2D -:1065D00042B9A47FE746544ABD92F26FFED3698266 -:1065E000E97879E1D66C4359EAE5858EC4E7D41F92 -:1065F00011EB62EEB39BED3D35EC3FB800FB3F295C -:10660000F21B4E6E77D33E4C8EA7EED9523BEE3B3B -:106610003FDCE96051F203B7DA18F9B3FC13943C9C -:10662000BCC788FF99C7F9CAAE346A6FD6832AF906 -:106630009D6AA1AF10E035B8732EDF079BE631EB02 -:1066400088361EE5D5AC750A0B6BBCFE1D787F46FF -:10665000E84E8AC398E769D62F7392DC9F3367E7C9 -:10666000DDF4FD4CE6BF1BEDD9592DE6F7D77C8450 -:106670004C3EE702F19C7B0B84DE19CE469CEB4B33 -:10668000F1A38CC1DA85F5CEC9157C917EB2C249E1 -:10669000F0B3151E823717703E9EBF63F72B3D691E -:1066A00099B70E47BDF4D6BEFAB49BB5B8DD3D7CB4 -:1066B000F3AD7B1EA5AAC6FCCC1A81F711222F735D -:1066C0008E38F7507EF8FC799935888F215DC72B7D -:1066D000EDEC1A93DF57DADD667C9CDE37260DF988 -:1066E000E3F902B1CF1D017851FF7EBC24FB6EA1FE -:1066F000CAEF4D333F97EBE866C1D733B74C59D358 -:1067000003FA6F7AF1A33E6DC4A7DC7F512EF055DA -:10671000EE5AD38AF32F6726BF61981D623A7E0630 -:106720007E5251EF98F956F2133BC4BF770ABF4629 -:1067300027BFEEDC40F8957C85271D2C68C381E5DA -:1067400062A9B8F03D57B35A8CE553B6B63E284F10 -:10675000E698FC0DA794C4FBB7BD05C51C0F9A7F36 -:106760003CE65FCC628135DC3FCFEFC739696D799C -:10677000E5765CE75BF83A5BF88BE7FE1BE5D7BC98 -:10678000FF7A301DE5D7C7D6963CEC6FC153ABD32B -:10679000FD28C7ACE174FCFEE3889AF01C71510F30 -:1067A00045E6EBBB304F6D11B11AFC6F667812CA2B -:1067B000CF3F3D65F3A01FB6F16947D401F858B447 -:1067C0009DE311CA4779F94EC257E30EE3BA9CF72D -:1067D0001F0FE669E40F08F714F8EB89227CD11645 -:1067E0001BE5B52E3AA4FAB09B46D641F3337F8F12 -:1067F000E38801DD1AB7AAB5F68CAEEFC112B2E399 -:106800007A6BDCCEE9D9B89DD3ABD164873608B9B1 -:106810006DE6FFCC1E46BE07FC905F4DE6DBB2087E -:1068200097DF4DCF3C3CE4288CEFB32DBF4D57068E -:10683000C5F99F615628E0EDF4D6FA19F6F3DCD7D6 -:10684000734AAC934EBD20F490B60306960FC59DD7 -:106850001C2EB045D3AF04BC2CD86CF385E1F1827B -:10686000E754BF0BEDA8771C74FFC4FCE75E7EEB1A -:106870000A18DFFC6DB69C097C1A2E94DF925E8D9F -:10688000C8E76571FACCFBF9CB76CCD3C4E7776463 -:10689000C5E9347FDB6E3BE67D9AF13966EB6E3BF2 -:1068A0005F6F267A6D3D3A1EF576D33367EDC80FDC -:1068B0001FEF52587E51D7EF1B36BF9C8E7206F1E8 -:1068C00084FA45D2AD938E5DE8179DF4CB6154CF29 -:1068D00083719E0BD1F1733C83504EFCFEB35FC2BB -:1068E000381ADE75F8100F0D3FBB351DE7F39175B3 -:1068F00031E7FBC757E7A1DE6EB085F33C04F9F33F -:10690000864DDF257E9CF3FA77F97D4ECC5F80EBD8 -:1069100019E65B80F39CF5D80D34CFD92C48FCD810 -:10692000F038BFDFF04B2BAB4AB41F784CAC9B8FD9 -:106930009E70D0E6E1233BE3F785FC4E15F7612D11 -:10694000217BE5BB62CE20A1A9FCA553D0AB878CEF -:10695000FB73F9D6286A356EB993E4DB27BDFDF9E0 -:10696000B8FE010F46FFECEBE3F2855CA47B5DE82B -:106970003BE0BF31F81CEBB7DAFC29430CDF89FCA4 -:106980005BDEFF32D13F8C3B15FD7C1FE519F7B96B -:1069900012FEB687F4ABB156A6E7B3647260CB3A89 -:1069A000E2AF2F0E7139B32832A58ADEB7DAA2F929 -:1069B000F83EB2FB7A85E404D82189D6F9169B58B3 -:1069C000E7C6F7304EABA2C7EF2E7E7E4FF2CBEC80 -:1069D00007A0BE6E5DC7F9C71E7F5E145FAF327F32 -:1069E000638EC99E93D02C271E32C909F93D7B2C9A -:1069F00037E1F988B87C0813FE16D8223F7904D70E -:106A0000F53B0E3A17B9E0391BDDEFF3E9B37BDE56 -:106A1000BA19F8FFD3AD723D1BE5AF793D373C7F26 -:106A2000034BB49E3FCD09B084EB199E275CCF3950 -:106A3000FCBCC1FF29F93B2789FCDDDD43D8633A63 -:106A4000BBE34A287EF2D3F985B43F33E157E2D560 -:106A50002C4FABD158C8ED2A4FE1EF10D3E153E2F0 -:106A600051F2E9BCFF5C48FD74F2B3E457C9CF9D15 -:106A7000FC6A9EB7119FE6F7CDB877CA8DD3DFB613 -:106A80000AF6E518AF7D51A5FCBC76AD233D0BFAA7 -:106A90005D2DF27BDA3DA29CC9CB1DB9F635284F9E -:106AA000E4F38E149EEFD01EE848CFD4ED078EEEAF -:106AB00054D3F13C405B24715E06656CE4E2E9D698 -:106AC00064EF57D27A684FE5FEBEF654EEE71BA797 -:106AD000BAFA84707FD7C2E34B3357DE948EFBFB48 -:106AE000F69D7D2757E37E60BFCA738EC27E6B0121 -:106AF000E0B79E4F9D9D64E18746A1FDBE73FE04F5 -:106B00006C67E67A235E66BBB6D8B19D2FD91D04AB -:106B1000673F608BF309FC6F1EE66B219F3F667A2F -:106B2000BEF35AE2AB7926BE0A225F25384FE2EA6D -:106B300029F8AA9495F2FDB6888F09B9374E1D340D -:106B4000B91AF329F7F1F31EA777AA6C0DCEF759FE -:106B5000112F0BE712BF2E02FED6FB4D3F43BE1B8B -:106B6000905CCF7FF6C291E1B7439505FFFDDE90C3 -:106B700047017EF6DFEF5CF22B2CFFE2ED3EEFB13A -:106B8000AEF5C7ECFAF32D94D7B9CB41F79AB6EF2F -:106B9000FA759FDBB1FC4B07DD2FDABE8AEFB3C37A -:106BA000BBDCA4FFDB7B737BB1E9C5B343DA487F71 -:106BB000F17B8347F4E4E73E4EEFFCCB070AE6F3B4 -:106BC000ED8459A17C14FBB7C65FA6D03EBDFDC5C0 -:106BD000B386FDE9DF3B9F45E2DC55BB9B55E339BE -:106BE000E9F64C7E4EB5F157239FC473970BB7EF70 -:106BF000B6D7C3FB31FFFBAF43500EB53FCFED0E11 -:106C0000B08737311F63A31FBD67830DE8770A6D17 -:106C1000445833EF3D7A7062785022BC703CB40324 -:106C20001E705E809706949FC9F031B5273F7FFCA8 -:106C3000AF878FCF6FC1FE17EC1C41F70CC7F1A2D5 -:106C4000F8F97337E57BC0FCF9F35D6787A01D7524 -:106C5000A1F92EFFFF6CBE0FFECBCE97F37BEF9E0C -:106C60005C1F99F9BE2B5FFFE2362AFFCCEDA3F142 -:106C70007673BDBFF02FBBDEFF39F47EE35F76BED7 -:106C800017A2F77E416FB707E332ED2FFEB50FBBBA -:106C900088799FFE7F74DE9D768FC5E71C06E37BB7 -:106CA00097456EA85492E78F16F632EE33E43DDC3A -:106CB000937266931D31C9CFFD314DAC6C1F9EB3ED -:106CC0000BFB558A5F50F20EE0A1F5FAD208E58978 -:106CD00059C3FD1FC2BCB11B17FAF87D65C6FDD7AD -:106CE000A4BCAA2AB4E70EAE847141BD836E8BA703 -:106CF00009A630D9AF92FD0790ECBE37475F4B79BC -:106D000028932B8CFB909B4DFB899BAA8DEF6F6486 -:106D10004FE462BEDF8D0D36CA4FBAC154FFAF3D9E -:106D20003D44D79BD8E2D5DC9F7371789A2CF0D480 -:106D3000150FE7C75B173C89FD26E50E695DF1E697 -:106D400008F2FDA7035E087B4BE4E52DED163E99A6 -:106D5000D8973A44D712BF0E3FBF7754D72EE1459C -:106D6000E2FD62F12DE964C6BBC4AFC49B990EC5B8 -:106D700078DE53679FC7A1F15E6D26ECC6499D760C -:106D8000A38BF0F8DA167E5EE2B58AFAF5A5587E96 -:106D900096DF07FFE5A8A1CC09F33D68633B282EE9 -:106DA000E4F76B9EE1F1FC19A5E2D7149FC0FC4506 -:106DB000FD7E15F317F5F3C2FC457D19F317F5F5C4 -:106DC000317F51FF1EF317F5EF317F515FC6FC4550 -:106DD0007D7DCC5FD497317F515F1FF317F565CC74 -:106DE0005FD4D7C7FC45FD7BCC5FD4BFC7FC457DD6 -:106DF00019F317F5F5317F51FF1EF317F5EF317FCA -:106E0000515FC6FC457D7DCC5BD4BFC7BC45FD7BD7 -:106E1000CC53D497313F515FFFEAD84B867225FBA4 -:106E2000ADA1FE18E71B86F238CF7B86FADFF61E8F -:106E300037BCBF46FBD4F05ED2FFDA923386E71848 -:106E4000FB080FC77D0CFF9BE8FB8BA11D2B0B5094 -:106E50009CD4CE161374A2BF17602ADB4AD005CB90 -:106E60001CE18901C1677A21BF6E0AAF41E63A3859 -:106E7000F26C1F94FFAF8DBA8EFB25447C6132FE0D -:106E8000A7064C9CF6752FDCE7CAF8697A4C65D1E9 -:106E9000A1C0873185A02796C6A2D9C087B1148228 -:106EA00059B16C7A9E1DCB249813EB49CF736305BF -:106EB00004F3627D09E6C78A087A63030916C42EC3 -:106EC00025D8233694BEEB192B25D82B76253DEFFC -:106ED0001D1B49B04F6C0C3D2F8C5512D462D7123C -:106EE0002C8A5D43B038761DD5EB1B9B42B05F6C9E -:106EF0001A3DEF1F9B4AF092583DC101B15A8225BD -:106F0000B1F9042F8DCD257859EC56FA6E606C09D5 -:106F1000C141B1DBE9F9E0D8F7080E893511BC3C75 -:106F2000B692A02F7637D52B8DAD235816BB9F9EDA -:106F30000F8DDD477058EC517A5E1EFB31C1E1B117 -:106F400027098E886D265811FB4F822363CF10BC12 -:106F500022F673FAEECAD83682A362BFA2E757C5FB -:106F6000FE17C16FC5F6D0F3AB63BB09FA63BFA5CB -:106F7000E795B1FD0447C7DEA0E76362AF131C1BB2 -:106F80007B8F9E8F8BBD43707CEC38C16FC78E1298 -:106F9000AC8A7D4AF09AD8C704FF2D7686BEBB36F0 -:106FA000F639C109B1BFD0F389B13F13ECDCFF8FD3 -:106FB0004AFABB029673B87F766575EBBEB2FBD218 -:106FC000D2492E4EBA83CBC587D34EED253939D25F -:106FD000A13948F86D34C4BBE8472460DFB77BE4CF -:106FE00047BDD0DE595379FCFD5B519F2D7130A117 -:106FF000CF4C72F76B97F07732CC479C2EF8FAB5EE -:107000008A3DB96847AD296B5B807E930D456D3530 -:1070100008F37A73BFAC5BC09CDE3C5FE12F03B822 -:10702000FEAD59D29FFFBE404EF7E6775D2FFE9D25 -:10703000ACFF751F0FD717AE8E3E745EAF9BED741D -:10704000B7DE85F2B062BD8297F5CE3DDFF9C16E45 -:10705000B733B477827CAE6FD0CEA8EEB4F3A1A0E4 -:10706000FB63BD037E1C3FB3FA87E0FBD1AB0A5440 -:10707000FC5D95DAF58A07F9A5BEB9743CD2B58CEA -:10708000F9C92F393D493ED96C41D7BAC53686FE7C -:10709000C93A8D917FB86E3BCF43467FEA44E09773 -:1070A00006C12F0BD77D4E7EA786C57378DE53842D -:1070B000FBA7E4EFD8CC6FD9FC0ABAF5BE64072869 -:1070C0003F7EFED346FF55A3F04F2DDC6A7ABEF813 -:1070D000DB09FD9E66BFD48CDEC22FE5E3794F4C01 -:1070E000ED45F3FE12E68DF924C1DBDC4ED41B80A6 -:1070F0000F8AC3483C48BFA7C407EB7AEE82F25719 -:107100004FEFEB4F7972A7352D1FEB05D3F9EF59F0 -:1071100029D6E0087C0E78A47C968E9569940F752C -:1071200014F4808689579EE008BC3FAEEDDDDE4C4E -:10713000DC5F698C4738D7539E782D8C01F3526AF7 -:107140009FCAA6739BD0DE901DE8D77CCA46F9483B -:1071500061B6D4CB2ABAC62B02AB6DC417753B32CD -:10716000797E5AD87F08CF1548BA1C6DEE3B1EF3C6 -:107170009AEAD6169592BB6E878DEC43199795F4D3 -:10718000EA9ABFCDF3051A59640DA62E01BD4E240F -:10719000A457CB6EA22BD0ED4412BA9D381FDD1E32 -:1071A00032D10DFDD437E1CB3BB2693DD7AC8AF685 -:1071B0005FACE34FB3FF9FCDBC82EE3D91F9CF555D -:1071C0003DE4EF8CF9F290BE67D69713DDCCF4AABC -:1071D000FA5B3DD185BDEBA67B87A7F76533BE0380 -:1071E000CF6708BFE7F4A66BC8FEFEAFDE7C5FF09A -:1071F000DA0ACCFD64ECF5154EE607E3FB8D151EAF -:107200002ABFB9C24BE5B7576804DF595142F08431 -:107210009DE715C9F5058C40F97D2FF4E671A91796 -:107220007ACBB8F0322FFAB9ABFEF64639E619E55B -:1072300086DF9B34EE2AB2DB0DF922D5D71BF34152 -:10724000DA6C22DF6C9DE2C3FB64EA02571AEAB3F0 -:1072500092A1F132EA1F91BF52B73693EEB19B3A39 -:1072600021DB50FFC6B53D0DE5577B6B34BE29557C -:107270007D0DCF6FAE196828D78ADF8F605A05ADB4 -:107280001B19FF02CDCDE9E2E175BF583C227F39E1 -:10729000F4FFC5011BBD37D3E3843D4CFBF9F0136C -:1072A0000E1FC6F74EE2F937289F7C53A5FCA29328 -:1072B0003616F680883FA9B06684CCCAD7D59787A2 -:1072C000F9BAAAFA9BCA701FCF7EEAA0F860FD4601 -:1072D0008585F16E860EC03CF4BBEC1907CD7BE6CC -:1072E000469505E97C95B615E3E4CB9E1AE0C3F814 -:1072F000E8F4BED1DE78DEB0E385141F9EFBAA6FF2 -:10730000E3DF9F84FD7926E6472965148FF8E3C4FF -:1073100096D916CCB7530FE4E27AFDE3F3FC77CDB0 -:10732000E62E7973B807F03CEF95AD6F55403F27D7 -:107330005A54EAF7D3A71D9B555AF7FE7CBCDF369B -:107340003EEF08F929C6F708FC09E5FB27B32343FC -:1073500048FEDCC1FDE35DF103F3457A23BFEAE4B7 -:10736000595CBFF1F81B08A1029413F5361FC565DF -:107370004FACB751BC10F401E51B9C68C9B670391D -:10738000F43CF15D9D55B3EBFBAD5BAFFAF9EF63F8 -:1073900068761C2FBB4F0DB21158E6F911E1B54AC2 -:1073A00090C77F8CF4BD75C9083A176DCEE392F093 -:1073B00014ACA9A02EAE34EF451EFF65C3DAACFABB -:1073C0003C77E99F61C10AC37D460B8A1FBE6714E3 -:1073D000C0D37E7EF5E2975BDC24273FB3BC347CD0 -:1073E00039C04F2786FF6005BABCAE068BFB60DE56 -:1073F0009065FD2685E22AC7EFC1B8FF27CFD97C6B -:10740000B40C45DED8BC9FCEA5F854727B81797947 -:10741000FC3A9AA778F1766246F922D3D856E15F12 -:1074200088F03C031C04E0C7B380C7C58E97BBEF50 -:10743000C2F3C3F5A6F3C6C7C5398BF23E8A415FD6 -:107440002F13E57A0B5F9F6C17BF8752FE5E9C94EB -:10745000E352DE4A793DAE4F317D27E52C635B492F -:10746000BECC16F7252F78DAC1CF1769CC83789C6C -:10747000CBC9C456F5D1E8BB79F6E71E42B69EC328 -:107480005A49EF7D628BCC6E2DC2EF373767D1F74B -:10749000365F04D77144FE1E9D95E4C81CC6C7B96B -:1074A000B045894475FE0EF9FB240CF5844EEE744C -:1074B000D10B267D304BE8BF59CC946FD462D453A6 -:1074C000813437CD6B5E8BC8C3EE1C97CACE61BCCE -:1074D0002B187965128D5BF145128C630EEB88E2F7 -:1074E000BDC80B9FE5E798CCE332CFA3BBE39CED8F -:1074F0009B3216EF57EEECD7346E896F8607AB746C -:107500007490789F1DE6F89CBD53217AFD5ED85B90 -:10751000F27CA099FE73586012CAB9390FC03EB30D -:1075200028CE0F920FE66E8BD079C04F594BBA0B15 -:10753000D6C3828DDB6E1C09DFCF79EC753BF27B05 -:107540004D56B4BF25137FAA67F4BD55BD13E87D22 -:10755000939EFF47E18909BF157D077899B545A539 -:107560003C0A5D3D914710267C3584F9EF09361CB5 -:10757000527D4DF0B4017FE6A8ECE2C72BF1F6CFC7 -:107580001EB7D9AED9D6E7FC768D59DE74B16B4CF7 -:10759000FA14CF73A0FEECC8E5F9E95F58FD19595C -:1075A00024A74D7238B78CEE63957278B6D083B24B -:1075B0009F59A8FFA0FC878D3F4F477FC6EF1FF85C -:1075C000791EE56BA0BE1914D737B7D5F3FE6EFB55 -:1075D000450AE54BFD7162EB10B4076B1EFF75BAEF -:1075E000FEBED79305C1D7FAE078857E5CA86EEE23 -:1075F00083BF6B28E5EC05F76DC9E6E9BEC03CDD4D -:10760000C679D6E13C75E754EAC53C8FADE5F33B5E -:10761000BE9ECF776697798629AE72DB930E5F9810 -:10762000EC8E28E9F593DB5486FBAC4EBBC36407B4 -:107630007CC95A36213E162E7DFB032BF0C5DC4B50 -:10764000003FC00735F73948EFCF7D81C7533F5121 -:107650002AF329A0BF379AFE3D783E0FEC05B437D8 -:10766000E2E3E8B403CE221E3BED806EE26F91F0C0 -:107670006B2DDAF96BFA1D2DC5CFF33117C97B6D70 -:107680007698EEB5D15006F073FE4EA4532FF37DDD -:107690005CDC3FFBA7FE9FDFB294F8BFE312FD392D -:1076A000B6C6D4A80DF3903BB62964272D5C569935 -:1076B0005EC9F07C1BF7ABE51472BB56F1FB29BF2A -:1076C000C601744D85FEF20B35FE5CF3F07CF3C70A -:1076D00018DDA323C76B7E8EFE7627EA439785F4D9 -:1076E000A179FEE30BB9DE5CA85AC8BE5E60E776FE -:1076F00076BBB8BFA29F1847BF426E6F5F56C8FDEA -:107700000AED685762BCFB2A07FD8E116363C9EF5F -:107710006E659CFFAC126F1EEBA9CEF54DF673475C -:107720002FC4D32DAC957E177152C5140DCF337C69 -:1077300090E7A47BA2E02F80ED4C13ED1CB4F1F395 -:107740000B1F601F30AF69C23FFD015E8F0AFD7FD6 -:10775000506027BB36FCA283EC863B53B9FF90E513 -:107760006458713DDC2CE4D4F4510E3FCAF569A392 -:10777000EE0C2084F6C20CF055E3EC585D0AFDAC2B -:10778000B4707DBF328B71BF40735B39E2EF7230F2 -:1077900093317F1F66BFFD5CF6F9F8C8787E620101 -:1077A000FA19AE609CC12A08BF86F2023B7F5F5384 -:1077B000F893C90FF462EC779835857A0671847C6A -:1077C000519B41FBDFC978BE200BA195F8ED3B56DC -:1077D00016B670B8D645F72A790DBF0B7B43058BDB -:1077E00066C0FCA2FB8DE73B6E8A5AA203305E6442 -:1077F0008DEE46FC599C9ACD03FD04AA9432C4FB3D -:107800008255DD1B6F63E1361AEF02BCCF0BC7F95F -:107810003D85F285A6C1A2473EBDC5CAF6AA659CB4 -:107820007EC8878D595A98EA2DE17C2ECF9548BAAB -:107830009442F37AFC4E13E38376D6A6E3F7F6C4BC -:107840007E95DB0BE5BE8FDB6BF3C5BA9D2FF9EEA2 -:1078500059E37A7D1CD70DF02DDAB248F76902267C -:10786000E3FB4744FB8F08BE5F5328E37FDDEB6FEC -:10787000A1834569DE2F3A888EB2DFC9026E2CE4FF -:10788000F9D3721C927F67B3C594CF335BF8692C30 -:107890002049283FB8E549EE1732E51D81A144F99A -:1078A0006DF3B6989FEBFC3CAA412E91DF54B17763 -:1078B000CCC4F129DF4AF121BF4FB36F25FF80B956 -:1078C0009E0D7F3F15E36E6BC1AE5244BC0CCA8E59 -:1078D000F50AFDEEC5B45E1D83519F83B41E4FE7CC -:1078E0004285BD3D5BD0D721EEB79A8DF615C6D542 -:1078F000D0BE427C6DE476A555D8C375EB8DF6C637 -:10790000B4669DDDC981E17E0087294FDD26EC8EBE -:107910000FED1D8351EE9BEF0BF8D0C2E711CE6344 -:10792000FC5ECD1CFEDE2AEC4BC9573F2DB419E29C -:107930006DF2DC690DCA2B7E6F83294FCB45F7C7EB -:10794000D428FCFE4EE9877C5FC0D36087D27D39A6 -:1079500047D2280E6EF64FB657BAC3169D9F727A5D -:10796000C66D93103F35E9762BC2F73BEF156BA33D -:10797000FE8F788AC9FE5953397423E6271D2BFCE4 -:107980007CB2B3374553C479A83FBD86F9F4D77F9D -:107990000DF3A1F2D9C97ED847B5BFDC718B134472 -:1079A00077ECDFCF4EB6829E6F7FB0631396532382 -:1079B0002C6005FDD8BEA1A30FDEB99CAAD902F4A4 -:1079C0007EA56CCF16C0F6DA7FCCCB1F15DA027815 -:1079D0009F6E8D38B754738542F2D721D697F43312 -:1079E000D5585EE27034FF5D940BD5CBD6028EC2C3 -:1079F00072BC0FF504FDFE429F62BFA310EAA5F51D -:107A0000099E46386F8A12B6E379FF43914B845E34 -:107A10004BF83B218E42EE6FCD2B0AD0F7D28F0E62 -:107A2000EDFCE59BB4B3458CEB7F0053DFF7AB0077 -:107A3000800000001F8B080000000000000BE57DA7 -:107A400009785445B670DDBEBD656FB260622076C0 -:107A50001212020668208100419B84252C810E2889 -:107A60004689DA2C02622091D131333A7F77D844AB -:107A70007434A84F19079D169161E6A92FA32C41D4 -:107A8000B60EA0823ADA282A3AC04445058D4E4403 -:107A90007813FF87FA9F73AA2ADD75495866E6BDF9 -:107AA000EF7DDF1F3EBECAB955B7EEA9B39F537530 -:107AB0006FAA6ECF49F0E6331693E1353B53185B5E -:107AC00050A1F9AD0318638702B99E38C62633E684 -:107AD0006E8C65EC27FCB93ADCDAAE303106E36F28 -:107AE000CFF4D8AE2864AC2A3C4FDC3F32CF21C360 -:107AF0003C376970EF30F8CF5C4EBCFF866C771F67 -:107B000027F4DFF67F9817E761A34798D810C67E61 -:107B10006667F4F35DEDD65C7B01B4CFD99258264D -:107B20008C7B615BC65C9887D5C1E4698C7DD5FC94 -:107B3000A1D509F32C6AD7993B89B19A768DDA459C -:107B40009B9AAD63615C0DB4A511F8550B7C196B64 -:107B5000314F8D0B5FEFEF047C0BF1FA6AC2FBB67D -:107B6000174E9ABD30EE3653E3E74F24C3E5E19A52 -:107B7000EB59E7B9EBECEEE4EB3CC6585963FEB9C0 -:107B8000FD054E8DFA7F9DE31E8CF44B8139F03953 -:107B9000BA89AFD738FE57028FAA6876B307FA675B -:107BA0000F89B33B81DE8587BC4BE3008FB96B3314 -:107BB00007E93047FF8C929148373667B842AFB239 -:107BC000CB190BE1FACC6DDD19B4DFED284C6080E8 -:107BD000575562E80E3610C8E6CC69B08F646CE287 -:107BE000E330E672BAC5CDE0DE329B848B3DA38BD9 -:107BF00001FE51277846A0B0C10FF3EC477C609E90 -:107C00001B87F68B66FD817A993126470263237BB9 -:107C1000CEACC375DD3874E458BC3ECA16973B93AE -:107C2000E8CB483E46F6F44C433C713C837578AD56 -:107C3000C194EB601DDED775971FD6E1ED1FE30DF4 -:107C40007442B70A41D73AA783E8B1DF04780E0A35 -:107C5000E3219FCF98E38E10CC777C49DAC0553072 -:107C6000DFDA9EA3EE427CE4F3D7F6F4CE897C3EC5 -:107C70002CB73F5EBF583C660A3CEE42BE41EB2942 -:107C8000063913B4FE09FE4F1D1DA3C0D74C4A622E -:107C9000EEBC303CFD9A7405AEACCA56C6DF30E788 -:107CA0004AA5BFDC162AA88D0DCBB7111FD932E625 -:107CB000277C6AE236C63340F1E88E33EFCF003DD1 -:107CC000F9DB7ADDA501AEB7EE7CF6FD1130EA14E2 -:107CD0002C3809E876CA0D00ACF7D4263DE0CF4435 -:107CE000F9709BCBBB33361FA782F10B0FBC641D11 -:107CF00005BFCEAF9D3709F9786BC0F2494B049EA2 -:107D000067D8592BCB027DD8A85EAF610F7CABF74B -:107D1000472868F5F483791A0DFDB5E3BE60F138A4 -:107D2000CEFC498B5C273CBFEE48E683FB22D6BDE8 -:107D3000C61997FCF995F0CB2036E8271D9FD7FA96 -:107D40002AAC90953635139F961ED05D28A24B7BAA -:107D50006A4C83758EDB640B44816A7DBDED63AB39 -:107D600013E8F5779FF3C17D16D4FF7AC692F0BE73 -:107D70008FAD2D70BDC8E9243A2DDAF1AD9501DF44 -:107D8000C7EDB89DF47A2CD8B104909F5033EBB76F -:107D900009E6F767C6B99E85F96F5B399EB1C18C5C -:107DA00025B4CFA0B6BA613CCDB7B07D1AC18BDA8D -:107DB0006308DE1F1D1ACB008FFD5BBAB1A580C71B -:107DC000DB7A30F7B7388F2D8EEC4479FA8D4B7013 -:107DD000DDFBA3FDF93F83E795FFC7B832A4EBA213 -:107DE0004D9A1BE5AC5C67FBB544C4378AE62BD7DC -:107DF000DF29B81DAE4F2C8DF39B12A89F31E8D719 -:107E000087C4AD6200EB56B0179DC8E73E615F2C9A -:107E10002D1CEF31ED15349FEC7FDD9945FD12B639 -:107E2000A4AC37CF8A0DAFC7D2A2513BA1FD4A6A9D -:107E30006B3655989DF09CD7F39E49463AC1F85849 -:107E40006FA776796802EBC47E75D87F618F67A0D3 -:107E50003D86799BB3DC2DA88793EF6931DBD19EFA -:107E6000C6DA1DCF821C4C2E1AE89C1BB12E7DCF8A -:107E7000F5CC0972644B6EB3B861FE19D046DAEFE7 -:107E80009BBBF0379F0B3D65AC9EEC85F44BACC7BC -:107E90003D0CF1BEC9C1F1967AF5AE182FEF0F690E -:107EA0005C3FFC9B6D8167E1F78FB2BCED68474298 -:107EB000A358E58B644F43191571FF3AFC81BF76D7 -:107EC000E47FBCB98525C2FD3F74E0CFF5FA42F8E6 -:107ED0007F25FCC4DB3AAB43B978FBEAAB436EC009 -:107EE000ABF9EEC183D13FC8E7C5675AF9BC8EB67E -:107EF000B328AF35BB629CAB607DE5C01B84DB76ED -:107F0000DA02EB32E93AD392B1B5ADD3A0BF26BEC7 -:107F10002D17FD4FE9EEA820CA6DF3EE2833FA9134 -:107F20003D39DEF8CC14BCDE7BB406F2EDDE613305 -:107F3000A31C2439DD0978BD2B7C2F64C7A43E1A0D -:107F4000E5CCBB92EB9F57E8E14C21B7B3841ECE42 -:107F500034BB12EE02BC6F7E536768C767DDA3F5C2 -:107F6000DB5480362DCE9513A18752DF2C289783C2 -:107F7000513EB95C56B77713FA9D29E6E57A500E63 -:107F80000E1AE9537E65B700EAF7A2F6241A27F520 -:107F900055EA696AB6F7AA4CE043F952D06F788E79 -:107FA00077495A01EA4B584EAC0E94279093D4B9B6 -:107FB0001172B0B4F97B33CA89A5582339B1415B3A -:107FC0001A21479E8E38C531B63BE0317959A669F2 -:107FD000150BF79766CA78E5E2E4DD95C9E56B56BF -:107FE0006C30C704F3596AA35C4B00AF53C94EB25F -:107FF000638BEF030048B0D8E229C53863F16F34D2 -:1080000017DA5F8C3FD0FE0C395C6BF546E0777D6C -:108010007B7FE6043A4D6BEF456DFF0C6F05F27FF9 -:1080200066FB7441C7FED432679189819FB9C3CE84 -:10803000FDCCE9DA7B6FC2E79D0ED85CF83CB0D08E -:108040009CDF02DF42B7EBB2BB10BF372DEC6918E3 -:108050007F22CAABA35E9EE8C91C8F008AB3D700FB -:108060009F61DE1316E677003FE700EC45B81B730F -:10807000771B847A07EB8CF02B67CC0D192C1BF83F -:10808000BBF88363663085B7E686FA07E1B955A386 -:10809000B8FF6F5D6F21FF5FDDFCCE1013F47F9999 -:1080A000E9BE8C81ED1D7BB9F7365CCF82A98117C3 -:1080B0002C00DFF6EB97E28739C3F46C340773CCFE -:1080C000707F23D0D10F78353EA0970578DC13530D -:1080D000D1EFC272BDA03D9BE823FD8DB4DF5B7D77 -:1080E000A9B088B01DBF901F92F2BD50E8C142D424 -:1080F0000316E96F2A3CA3500EF334570E8BF43766 -:108100005C1FA49D067927BD29CFEEE95ACAC27625 -:10811000DBE88FF6EA8D8F0C87F5FAB2BC4FA2DC54 -:1081200097FCFB7FBDF4117455BFF887D1C8A751E8 -:10813000576A4CD72EC64E7E6F213B794F05233BA5 -:10814000096DA49DB47411A7AFBB44B96F10720F31 -:10815000F12DC58D68C723E7FB28AB6413F2795B6B -:10816000A6C6E7FB17E16DB4EFDB3AF0BE38FBFEC5 -:10817000FBCC8BB3EF6FA27D2F3CD79E33980FEDD6 -:10818000F9DF76F609A0BD3FC6C0FEA37FDB11E391 -:108190007C56D87BF207D10981F3D9FB5FE7CC7E0F -:1081A000B30B7BFF67E4FF3F6BEFA57C19F5C1A81C -:1081B0000746B99F783FC45FC8A7AD1A43FB1A8E24 -:1081C000B718C9F1FE2C2EC7526F22E22FF2F3A08E -:1081D0000F819CCC73F5F2BBDA0F0A9C986F16C422 -:1081E0000D645A58DEA5BE487937FA913959DE1F19 -:1081F000C90F083DA97ED1E807BA92A76D16CC5FDA -:108200002DD5DF723F006DA41FE82ADED1B32E2DDD -:10821000DEF9F622E5A97B168F17FE1BE5A97B5632 -:1082200061A7F27459D63F113F9C878FE467A49CE5 -:108230004D7C83CB07CBE6F13EC80BE1BDDFDA33E3 -:10824000B03413ED1EB787137F62B548CF9B453D11 -:1082500041CAEBA86CEF88AC083E637C8F71FBC50C -:10826000C68533926B991BAEDF0C6DA4DDB021FF88 -:108270003A89EFDD599766EFFA0BB9B8109F2BB228 -:10828000FEE5716155677C656EEEFFC37CB14D43C1 -:10829000B9F92E6866A85F5DF1D5B286D35DC2CB11 -:1082A0008366E95F93D0BF82BCDC98F54FD89FF21C -:1082B000D2C6D37608FDEECE1A5E611E06797A111B -:1082C00013F58F11ABDD66B42FF0EB709A91EA23B2 -:1082D0006FEB122E3E381AF098F84847BF1FFBC7C5 -:1082E000142774D453309590E37F9935ECE00384E0 -:1082F0007703E7A3B7C5ECE9170117001C170117AF -:1083000019E0B57C3CFA1107CD13E0F61EE6D7065E -:10831000212CE7137AC0DAC676C3787193E6C07A67 -:10832000C80DC57FB3227FCA4B5B5E4D87F53E9873 -:10833000555A110B21C00D680701DFA7B226AEF612 -:108340009BC5FDDDA93E463FB646CDAD039FAA8B3A -:10835000B44056E6B9747C2A4BF567F86356EF676C -:10836000D6824BBB1FF948F767D1FD41DB253CFFA7 -:10837000BA62E60E7462279F9376F22CC0727EA0DA -:10838000DDB4469E871BC76F12E34326D34206F433 -:10839000DA9175F36AAC978D615C3E7665DD54E1E8 -:1083A000CFE7E8BA0DEB3D1FBEEB3A59AF53BD3FE7 -:1083B000783E7A6D3CE77E211FF3557949307BF694 -:1083C0007D077824246B0E8C6B1779A21EC0F8BD34 -:1083D000BC54CAF7AD15EE62585F1453EA7F61F9D9 -:1083E0005E50311AD6B788C9FEEAD5E8973CA68E0A -:1083F000F15CDE77681DF7E781FC50290EEE3F9CAB -:1084000075DB6AA40FF083FA09369F47DE1B0D70F7 -:10841000B1413F847C937EA2DD06FAE4746237CEDC -:1084200008BE7DADB14AB47BA1121EEF85B2789B28 -:1084300092CDEB243F083A5AB2791B8A8EA0438F23 -:10844000309FE127887944C4BA894ED7278B75FBC2 -:1084500057554CEA05F727B27E1AC849C2332B5646 -:108460002FEB19BEBFDB33AB484E3AE6F3AF3C8887 -:1084700074BC5ED029E599FB0E0A39D250EF1692F2 -:1084800040801C6CD2FC3AAC7321CA4127EBFCEB58 -:10849000B972E437DCEFB69CE7FECFCEBDDF6DB836 -:1084A0009F59922FE57EC1A749063E9619F838DA02 -:1084B00000574938A0D83369E76635AD5EDE3D190F -:1084C000EB8D1ABA09B4D7566D20637DB31FAD8802 -:1084D0001D86F2EAB4A483CDEF9FFDD8413BC8725C -:1084E00005DA3392DFC7C97E4F437D27784D857B00 -:1084F00000CA4FEDF254185F90FD9BD576D0AF1BAC -:1085000096ADB6604C5394FDDBD56698F7FA82FFC2 -:108510007815E7336B4F1E9C94791E796D30AC63F0 -:10852000AD01F61BC63F7A01FBBECC70FF3D86FE57 -:10853000070CF01A03BC52BD7FE61C8DF46426F0D4 -:108540000F097721BD999CDD111776F8332D96E23E -:108550002445EE272EE57065F6BF57AC8C8D809FC5 -:1085600079AE22528E2D8CFFCC48667EF41F962E5B -:10857000ECD9D86CB5DED5B19E3CA3BFE3FD7FC579 -:108580005FD3689F45F1CB7B75156ED6A5BEBD7CCC -:10859000F08E58BC28E16D1558BFE872DFC3BFB537 -:1085A00002F73D263E24FBB756B823D629C78FFDD8 -:1085B000E1271D9FB7E8992D15EBA1BFAA24988349 -:1085C000F5FAAA44DE829FD1D18FD5887AC7D89D8B -:1085D000BA07FD4C55743067717EC43A59632EAEAC -:1085E000B3F96E9DF8E35FCAF39159CC65C57A453E -:1085F000734242DD0618BFF76EBD0EFDDAB1BAA4B4 -:10860000EE984FECCEE6F9DEDE842BBADF02707313 -:10861000CCCD56ACD736DF3B86DA3DBA7B451BC89E -:10862000F103D9AF56C4F6C1FE04A2CFCA679A2B94 -:10863000EAC15EDD9FEDA4FBBD898EEE4D18AFAEA5 -:10864000B230AC5733E67A8AE4E6D7B681AB008F16 -:1086500099F557D2FED1AC7FAB189B06E3662DB7D8 -:10866000D0BE02FCF447BCBDABC658B17FCE32D100 -:10867000FAC751BBFBC797DEE80FE3DBEED35DEB38 -:1086800060F0AEF6ACF85980D7A751DC0E7FD2DA95 -:108690002B1EF1ECD5CBFB7836CA6B7C5CB486CE56 -:1086A000C3E18C9F0AF366E6B8D7E075397EF78F91 -:1086B0003AED836D6F9DD51DF9B74EC8CDAEF65915 -:1086C000DD6745F8FBB95F9B89CEBBADCE3B30BEC5 -:1086D000DC1DDD53C3BA0CD03909EBB673447C0DF5 -:1086E000F252F752277EFFA16C9DE872DC56C73E1E -:1086F00005216EBE3FA518F194F7C9FD374B0FE772 -:10870000A0C838FA775794BC909D122967470E622B -:108710007C4F7134C0DBB23F5CED07BFC2F642FC58 -:108720008F7824BBC7A25CB17B92F83E686A636E07 -:10873000643D221CA72E11F6808F3BEA8FA3BCF567 -:10874000E8735101CC678EFAFF1217597F977A327E -:108750002F3ECE8FCEF88BB83833D2F598D9F7F9B3 -:108760002F70DFF0490BD9D1B94FA6DCD386F600C4 -:10877000F889F520E373937A59689EAEF707BF54E2 -:10878000F5C47FF2BC7AF26EF6C98AF5F95DEBC9E1 -:108790003C11B78F7DD2E241399F571867C67DBA29 -:1087A00092275F7916E571DEED51836C80F8BC2766 -:1087B0006DC4DF96B838BF03F711E3E3CCDDA03D0D -:1087C00021EC574B7D14E5297A772BD93D7D45A1C6 -:1087D00013E953AA33B31DFC8A1EEF727A38BC0C1E -:1087E000EB86CBE38A9CC85F472FAE0F1DFD099532 -:1087F00013B4FEE17DB393758F3C361457CD02D38D -:108800008766FEF3FB6835CC9380F5C7FFAE7D34F9 -:10881000AD575CF2E7908A87F7D1F213AE43F1AB24 -:10882000D3096F7D495400E9A967703F318E69B45F -:108830008FC61CB0FE7EE17D34FD9783893EC77DE7 -:108840002057BD812EF1761AAFFF520FD8E0B9A59F -:1088500049BCDEAA3F56C1705F0DE8EA77003C2EA6 -:10886000B996F6D77E25ECCC4C8D791A49FF5D1967 -:108870009827CF7D328AF838EFA95BDFFF4D01F2F0 -:10888000AD3C39529F7A08F983F9983D313CCF17B6 -:10889000F5BFCA407C4A7F07F925E69DBAF7B1EBE0 -:1088A000C96EC6D07E1B73B4FC7A28CA4B7DCC40FF -:1088B000AC93CF7B322D232B3F7CFFBC2577E7F297 -:1088C000FB216F8D47BB1545EBA9DE6423799979B0 -:1088D0009FEE263FD9D34A7EF29365510457F7287D -:1088E000227D9B69E2FB6F1013A6927DE72467D57A -:1088F000B1CCFD522CDAFB07423AE78F5FF0CD8A0C -:10890000FC19DA2B899E7F33D218FCD77542DE66BC -:108910009AB81CB15D1AED373156EB443B5065D225 -:10892000C8DE19F5B2AC178F5F6766B86EC2FB166A -:108930003E68732DC9E438E8121FC89B169A42732B -:10894000711F926DB1517DA306D61115CFCF3DBCDD -:1089500008F8D79899D98AF52927B76B129F1A6713 -:10896000C5389457E83F6C86FE8571DC2E2FECC627 -:10897000EB3E2CCE1E7836F279887336BFCF198F36 -:10898000FA368CE405F5DF04FD7F63BCBF34BEC856 -:10899000D9924FFBF72BB15E82F8F4E91FF15C80AE -:1089A000D3FAA33CDE6ECE8A433E244DAFC4E73DEE -:1089B000AF937D02A57AB008E3C0E7F5C198CFCEAA -:1089C000BC6FEFD83508FF69A0035198F9C2BBE42A -:1089D000A76E1372D682F13FFA2D80FF046D6D2FC2 -:1089E0006E1FBC3AAFE7D4F6E2755E4957D9BFF0C7 -:1089F0003E0BF163E1722E0F0BEB3FA07917C6859A -:108A0000BA233F166EB60C41B9FE85C07B567DCFAA -:108A1000E2C3201FB32C090E0D2E55FBCBAD08571A -:108A2000376804CBE72DBCEFBDEEA67C3E1FB63603 -:108A30002147E1795332D0AF7DF55C52C6CC08BEF8 -:108A40007FB56C6B3CEE6B7F1A15CC71603DE6F622 -:108A500028D73AD253CE8FAF96E5ACC37ACD1C4718 -:108A6000280EF7C3E7DC919D88FEEE982368C5FECB -:108A7000638D992684DD0E4731C26EF30082BF12EA -:108A8000E754E807F8B448E37253FDDC5E6B163C2C -:108A9000EF29419FAF9F7F3717EB060B3342B9E8B1 -:108AA0008741AE72D3912F7FD4285E58F49CEE8E0E -:108AB000EA1F96AB452857A0FF0B845C2DDAB4F56E -:108AC0002ED4D345284F83CE954BC82FF7D1F51719 -:108AD0009F1ECBF8FDFB50EEA4DF07789905EB6BEA -:108AE0005601C37310FE1DD23F85FA47F37E7F3EC9 -:108AF000F913D662C5B8B846E7F102703615E389B6 -:108B00009A268BBF25C23E2EC2FEFC707F57721381 -:108B1000EC25F6CBEA6DE4978242FF5AEEDB1C8F20 -:108B200072F1F5F37B5F1D8E79D68B9A03EDFE39DA -:108B30007A28E85683748AA775527C548374890F07 -:108B4000D3A943DF845CD4304E0749971AB3A0936E -:108B5000EC17F7370B39AC6682AE9B7A737D17FA48 -:108B60000D12437E44AECF9BA89E1F3825E4FE6DB8 -:108B7000B1CE6A901B573EC997DB3A44E4FFD0F56B -:108B8000F59F9EA6FA91E4A7C43B3A873F1FECB439 -:108B9000BB5B6298CF2D2636BFB37AF56742AE2C09 -:108BA000B1DCAE7C5C9F7E531DD06FC173BA8B88E5 -:108BB00087B957C4736DA696388A4F7FA93B705DFD -:108BC000A5FF5E3101D72DE5CEB2513337E13E210D -:108BD000EB46F497F8955EE699D08DCB5D10F19158 -:108BE000787EAC05895FFE3F690E1EEFB658B18EE8 -:108BF00028F5D488EF2981AF1EAF0DD706203E2E71 -:108C000027EA37033F48F8C41EBE9B9EE73F7A77AA -:108C100066FFF0738EF9E3CC38EE18E37640CAE5D0 -:108C2000C7A22EF1F1F2AD140FCBE7D873B85C45B3 -:108C30003CC75B977CEE733AE2BC1C8E97D48BFDED -:108C4000895CFE4B977D40E3A49DC51FACC7497A64 -:108C50004ABA45E8A5421FA95F529F245FFF51BD54 -:108C600062F7A450DC7AAF5837E948F7B05F40F9B3 -:108C7000447F67B3F27370117E93E29A713DBEB583 -:108C80007A3BB92EE964BC1ECEAB1C1948FF71B10A -:108C9000A9B45FCE96A5EEEB15119F7D8A752FB412 -:108CA000A77FD003644F196865843F97715BFDED22 -:108CB000E31CA350BE9ED3E8DC91F4DFF0F34087C1 -:108CC0009CC27CF30B6ECFC57862794E16F767C9EC -:108CD000EE93787FF589D0D87867387F19793AA8EC -:108CE00027607D7053A6923F54B7EE233D5FC84284 -:108CF0002B30DF9D79DFBBE54391FF7FB0D0F98555 -:108D0000390D99E4FF4EAE9F3D1853DB99CB7308A4 -:108D1000BEF5D95B387C1F8FEB662E2FDC80F5F912 -:108D20004FA3DC6351CEDB566B0ECCBF463C5B7869 -:108D3000CF0DD03F22EE8A6E88EFD1F59F960FC7F8 -:108D40003CA24E27BD71AF7F643AF6BB9B74172ED1 -:108D5000710E73DC7303CAB93981F44E9E6B5C6A81 -:108D6000E1F2E6CDE176A33287DB8D4A21BFA54B48 -:108D700097E6E2B982B6A7C14FE1FEBAD5D918C4C9 -:108D80003C70E765AE75F09C1A485B53419E4E6897 -:108D90003C1E9F6F657694AF0396D09D88FF813B04 -:108DA000E306D62302FAD921A81F6E9177411E450A -:108DB000CF95F492CFBF59E8819C47DEB71FE32AD5 -:108DC000F42302DF93CBFE301DE385931B7312590E -:108DD00004DD4FE2BA80DEB7827D7CB1937CB03A8D -:108DE00047D6B902FC39A28E78C0D2D003F77321DE -:108DF000AE3F1E199F7FF174941DE512E27AF5BA19 -:108E000085FB1588E795EBA03F0ADC91EFE9550952 -:108E1000DE4EEC916C8DF1BE2F27B6D3785FEA9FC2 -:108E2000F17E19DF77D45D7A5DDAB9AE561F300670 -:108E3000146228066780EFE8981F5EC2F397731BE1 -:108E40006C0E1BD0F738EA17EE0B6ED679BC68E7CC -:108E5000FA767CE7C000D615E61E61AE20C0730F1F -:108E6000E92E278CDFB7FA5E3ADF71CB5A8D5DA60B -:108E700045E45D8FAE9E8EEA76CAE55D9106E34FCE -:108E80006DE4E751A03BD6906FBD9AE6EC3ADFFA6D -:108E900057E559B2FE64A4FF7FE4887CCBC55C2A09 -:108EA000FD79DEBE1BC4A868D0B9F46FF57929AF8F -:108EB000FAC6379FDA618D4F97A6C33AFEA67DFCAE -:108EC000E008D4A3B804AA9FB4FA6A6973F09BA619 -:108ED000C16727039DB6C72638D07E7CE3ABA3EBE2 -:108EE0001D7223E474E4A6663D9DD1F81D2360FC49 -:108EF000AED804DCEEE8641F8EF3D978FEE667B7DF -:108F00000FBD0CAFCBF57EF90BCE6F89FF971B67BA -:108F1000C763BCDAFCDBA41DC390CF31090E1485F6 -:108F200079E21CCEE76BB83D3A614FD88075D41317 -:108F30006BA775C7FCF0164B9BD505F3BA7656C4E4 -:108F4000637DE433734BBC035B181F443CCC011DB1 -:108F5000EDE0F03246FB83C38366E6CCA4AD7B92A2 -:108F60009F61ADE600E6CD5FE1BE21FAF1B3D17CB1 -:108F7000FF5EEC07DEB28DD7D93AEA2AA2BE3042B4 -:108F8000AC37363751EE03D1F5D2227EFD8BB52FAB -:108F90004DC6F94EAEB73810DF6FD65B68FE059050 -:108FA000DF9B401E4F6CE4E70516EC803C3913ED67 -:108FB0008846F2BB00E4D78EF277BBC56D4D3857BB -:108FC0002E4B37F2FC7A41A346F9B694CF05EEC09A -:108FD00058A2BB90533BFCFB095C4737D6B802E96B -:108FE000D195BCFEA3F5003DB7F37A80511E24DD78 -:108FF000A45C84E594917C4AFE27360E1C954E377E -:10900000F8899EFE129687F1C2522BCBC3F3507E95 -:1090100053B40BF5FEEF51F1FDB10E5567E7ED5D71 -:10902000D1F1EBB0FD7B544600F1FEBBC9F10AE67D -:1090300059BFCCCD24B9BD4B775A34F8755A72CB91 -:10904000687203A526B709FDE0521BD911A31D7252 -:10905000E672FFB32D97D1FDC5B9FC9CB885D552FA -:109060007C215B88077A62FC52119378068F92F715 -:10907000CB4D996606B9AE1891786736449E85B98E -:10908000E9D370FFB76270E2E62C80876E48E3FD9B -:1090900003120B2D00D76B3DA68D86FE6B72DD573C -:1090A000E6463C47CE0BD7FBE3F59234EFC0DC1429 -:1090B000F473B12BD10FFC4D6B5B64D2C3E30F6A29 -:1090C000ECD8762D0CB7585806C6DBC5887F4AD732 -:1090D000EDD25CF770FE5CF5FA2C0839B02E31CB7E -:1090E000FFDA618DEC19F3D8819F5384FCCDB2C7B0 -:1090F00006C9CEADB4B476C84716DAA90433F27DFA -:10910000B260FB1473B019EFEFC396393EB753A8A2 -:10911000B8F6A7A4AEED3F282AFB5CCE07EBFB9B7D -:1091200005D60B7CD5DCC06B50310D885C05F64E46 -:10913000DBF1DAF738EF523F6B89223E5439F07C8D -:10914000B7C6BCA69FA05D18037231005B900718DC -:10915000B778F3D7FB502D6E957196B788E2C53B73 -:109160001C7C3DCC3B9CE4F54E21AF5FF82075079D -:10917000F99C120AC5E351D8D6C9C15CB40F65BACF -:109180007736F2E18BB54B7B2C06F9F9FA459B6BF0 -:10919000128C3F1178291EFD6AB588F7D9593D78A0 -:1091A00035F4EFCFECB36E55847C55E772BFDF9A90 -:1091B00019CCB81BED4C26CF57D9D9BD1977C3F8B8 -:1091C000B2ACF185AB880AEE45B911FB9393CD9D06 -:1091D0009FDFA8E8C1E323B69EFB639B99F9E312E6 -:1091E000A965F140A7F1804B119E4B0558A7FDFCE6 -:1091F000003D1FC7C5635CE39C9DCAF77B9807EDE4 -:1092000096E4AFE4DB39FC049431AE37D99905D745 -:10921000DB87AD75A0FE4BBE7E21F4F10B3BD7C3BF -:10922000317A2CD9A9C59B795D6FB1C6EDEDE29D70 -:109230001AAF6F9EE36F37AF409B3C7FED6CB26718 -:10924000D28E39E11FCAD702872721E8FC07FCEE3E -:10925000DAD28BB2674FE68AF70406B281287F170D -:109260008A97A41D03F6ACBF247E21C960DDF304F8 -:109270008E63F42AA719E9926277A13D5FFC6436F8 -:10928000F94976620D8B1CC7D62691FCAEC8D489ED -:10929000AFE54DE9CC09976E6DD2E89CECA4A6240D -:1092A00082E3DBD3082EFFFD6525B8EE8E7DD0DF8F -:1092B000F726F8E486370ABCBC4E63C7F93D4CE29A -:1092C00091DF88FEE7542CE00174F6C4AEA4BAA383 -:1092D0008775E443DA4F1AC22035A8776E8B9FF367 -:1092E000C75E4FFA2FD6B558E8D5E203DC5F2F1ED4 -:1092F000C5F70BCDFE3E09C87FCB7E9D0500BEF6AF -:10930000805E1884A14B853DB7A59A9833826F5132 -:10931000CE68E68CE00FF3BB43986F550A79B937F6 -:109320008ADBFD98BC44655C65EC5C929F50C6D8B6 -:10933000FDB8DE38D7E5CABCCCCBE3632957D345AB -:10934000DD7C326B5B867EF2DA4AE88F98CF52FC86 -:109350002DF90D4BB11A57035D8E9F4F9EBE90FEA7 -:10936000B10FEB43F264A00FE807F9FB5387F8FB5A -:109370002710953C5E0CF0F4FD161680FEE5822E5B -:1093800018B762FE73CA1D477A23E52E847E0FEC60 -:109390005C42914AB76E6E956E49652A7D523C2AB1 -:1093A0003D2EABCC52FAD3BC7D95FEF4F98314B8B4 -:1093B00067ED7065FC1575250A9CE99FA08CCF5E52 -:1093C000395581731A6E50C6F75E334BE9EF135867 -:1093D000A0F45FB971B102F76BFCA5327E40D312E5 -:1093E000A57F607095D23F78FFC30A5C187A421956 -:1093F0003FF4F03AA57F58CB1F95FE11275E54E04D -:10940000916D2F2BE3AF6EDFA3C0A3D81BCAF85218 -:10941000FBBB0A3CC6F11765FCB8D44F95FEF1CEF4 -:10942000AF94FE8979DF29F07211E794BBFE4BB946 -:109430002FC496E5A01C3B7B788B7A53DDE784191B -:10944000F5EFF08D1A4BC2FC67FF3407E9FD25E606 -:1094500081EEDEAA1C9F61B137E179F60BD9C50C0C -:10946000114F8CD127D17B55A71A79BDC3E8D76599 -:109470003C97006ED91CF1DC6E6E3B24F46138A978 -:10948000CCA1C0299E5465FC65954EA53FCD9BA7F8 -:10949000F4A7CF772970CFDA2265FC15756E05CE5B -:1094A000F49729E3B3577A1438A7A15219DF7B8DBB -:1094B00057E9EF1398AFF45FB9B15681FB35D62960 -:1094C000E30734F995FE81C1954AFFE0FD0D0A5C82 -:1094D000185AA38C1F7A38A0F40F6BD9A8F48F38D0 -:1094E000D1A8C023DB9A94F157B7071578143BA095 -:1094F0008C2FB51F54E0318E0F95F1E3523F56FA91 -:10950000C73B4F2AFDD55FB982B42FB59DBFEF2A67 -:10951000E3B98979DF2AE32CC910EF63FD9B45BBD2 -:10952000F0BC7F5771BE8C03CB5DDF2BCFFDBB89B9 -:10953000C7E7BFEFCDDF4FBB4BE771E252BF87CE2E -:10954000E725E28157D09304BF46F287295615D507 -:10955000239369DF825CA613CFBB411C0440A22980 -:109560003313F39098701CDBE3A7C1171FC76E86F7 -:109570001C07F138DEDBFBC7DE8598B7FD692CE6FA -:1095800039B732FF0AC403FC6E02EE63BD15A5D6DF -:10959000A3643BDE0E748C78DE81A8861E83CEA386 -:1095A000BFE3EDAD34BE635E51AFD2607D8B23E689 -:1095B0007F10F22F33E869830FF40C12ED877D0ED4 -:1095C000821FF5A512FC98CF49ED1A5F1EB54FF822 -:1095D0005CD4BFD65744F0533E37C1015F19B5EB99 -:1095E0007C1EBABEDE5749F0069F97DA8DBEF9D4CD -:1095F000FED1574BFDCFF9EA087EC1E7A7B6D1B738 -:1096000092AEBFE86B2078936F0DC15B7C016A9BC3 -:109610007C1BA97DD9D748FD3B7C4D04EFF20509A1 -:109620000EFAF613BCC71722789FEF30C1AFFA5A73 -:10963000A8DDEF3B41EDEBBE36EA7FD3D74E70ABF2 -:10964000D84FF8A4B7A6BCAF2761C646933CC8F86C -:109650007732E63D281C45966F94BCC7907F18F979 -:10966000F1A5788EA504C25F8C7F2ECF5DB7342222 -:109670002FF8463CEFDE68E68F027DA837F1BA404E -:109680007D22A3F7C39888CFE709B964C93C2E9F10 -:109690002BF09A27F4A010E5338FE4F3CD4BC9B338 -:1096A00064BE1D93E1FD91E4B3A7C94F758758FED1 -:1096B0001E7EFF0CAF9607FDA76A6F79959EE77037 -:1096C000E5E243CA6DC194EBB09E7440A73A6C5773 -:1096D000CFAB11EF4974D9BFEB640FF447653FEA94 -:1096E00054AF7FCB125789F596A43C5E874DCA33A1 -:1096F00029EDD60C4F621EEEDBE7D46EF899167E8C -:10970000FF7F0AA6E6A0E715CC69A173B8CCFD0AD5 -:10971000BE7A732D047C085FC7FCD48EECE94DC77C -:10972000F55C0F0906C2DEE1B68CCED663C42747CE -:10973000E09323F090EDA10C4F2FC4E7788E5BC12E -:1097400027EA0AA73857DFF614E2F59F3BBFFD5C16 -:10975000CB0ED35BD637568C12E7B46ED7E43E38C7 -:109760008F13ED4CC689D45F7527AFF7487F79A476 -:10977000A3E5F6F054AD85EC669516EDC278FB5482 -:10978000ED9D0370BFF046C8F770FF54DAD12A8010 -:109790004D0057317EEEA2EA481CC999D1BEC27D68 -:1097A0000CF7FBAA2004C0FCF16C06AFA7BCE5F9DE -:1097B000D682F3B2E4367A6F15E4660CAE7FC13020 -:1097C0009DBEDFF0962990ABE9242F560DF09F97B0 -:1097D0000CF2D249BC20E56291782F475E07799B55 -:1097E00082FCF966DBD03CDAA7D935CC89F45C6A17 -:1097F000E2EFD5F95FD7F9B90C2CE5E3B99184FC18 -:10980000A7E9FD020C2E907FC3E2E8FD82669DD59C -:10981000FDA9137B5A2BF8F856AAA52C40F3AAFBF6 -:109820008AB7E6F1FACFAD795C2FCBF71CE889EF68 -:109830000D2EDA6FA1BC8815B4E47B3A3957555325 -:1098400077FFCF7B45C8794DD3C7FC3C166BC98FDA -:109850003C87B552CC2BE54BB7C6799F8E8DC4AFF4 -:1098600043CE6B849C7F8E71FF649B33E13AB8B525 -:1098700005481384D6FB3B079DE793E7FAE6300FD4 -:10988000B5F380DD28D71EFF6A7AAF7E016BA4EBAB -:109890008B8A6667205CC3DA46A7C27CD7AEAC7FF2 -:1098A0002515B09BD6B07A0CD6B9A70666BE826DD8 -:1098B000C57AED73BF93F4C48FCF6FD16A975F0EF3 -:1098C000CFBBE1B951CBB18E3C59E77C606F703EA4 -:1098D000803CB9F5C473D7077A71AFD00BC25FEA89 -:1098E00045D512E6D692C3EF8174E849D16D7F4D1C -:1098F000C73D16731B9D43A9D9654BC4FAC902C65F -:10990000FD76B80EC4FDB5D4832F2D9CEF5F3EAF1E -:10991000D17B365F6A8CBEE7D055DC20E34FD03F69 -:10992000AE77C762B8FCEBA2AE97E14D1D941DF671 -:10993000CF5F9A0243E2B3C97F3F83EBB194781FB4 -:109940001888E7F55ED05C4B01972FBB0532F839DC -:10995000810E3FC07E8A09D7091FB4F0BA9D31DE5F -:1099600095EBE80A4F9B95F9713F4B2B7AF57B8C71 -:1099700043CEC5D79B3A04E8B214598475C9128FF7 -:10998000B3333C9689E7EFFF81E7E3FE9E8CCE057B -:1099900019E9A939F873BAAAAFDAA2393ED24F4908 -:1099A0003CCFC58BF3EBADBC4C5E6714F831E6C819 -:1099B00073C0F3CDE66817EA6B85D9FB67D473599A -:1099C0007F9379F1FECC2FC81FB0B34B7BF0F3C768 -:1099D000C1AEFC706B473E9E15F693B28EC58A3BB6 -:1099E000AF477AEC0EB25F53998BFC451F7644D299 -:1099F0008BEA583AEE10529DD74BEBB0A1BD86369C -:109A00000AEB28E42F0324AF318817AD2B841511FE -:109A1000B63A269EE830FC30233B3D1CD700EBDDF8 -:109A2000F9310BE079AAE633D34BE3A07FE7D766A1 -:109A3000CA831E8F79211DBF23B1F3E4FBE958EFE0 -:109A4000A93FB385E021AD634FF2FAD9911938DF10 -:109A5000F6D356A78DE280DB890EB24EB99D311741 -:109A6000EE83167D184BEF19171E6A8C21BA89BA3E -:109A70005AB15877F1695E0FD985C030C803DAACA6 -:109A80002C18112F5B1C2A5CC422E04C7C24C011D2 -:109A9000758E4BCD1FED7D445D6D281B1A595763A4 -:109AA000ED899DBE4F65DC472CD038DE9FE679BA44 -:109AB000F5A13ADB549DD3FB471DE975756C200D6C -:109AC000E3DBE65B37A461BCFB78CC8F44C7277E21 -:109AD000B0A6215D1B46FD27F99106B83784F9AF82 -:109AE0003910C5A8FEB590EA6B570B3FFBC4D94FA0 -:109AF000582AD0B3A18891FF64C20FCBFE86B3A7CA -:109B0000E6233FCF14DB9D681772453DB4FEAAFFE4 -:109B10009BDA12418F9D10570781C1DB21AE0E42A7 -:109B2000ECBF0DE26A84F1BD536C37435C8D6D0070 -:109B3000E26A6C9F82B81AC7615C8DED131057639F -:109B4000BB06E26A6C1F83B81AC73D0A7135B60FAF -:109B5000435C8DD71BCECE2A257C0E337ABF7E493F -:109B60004CBC09ED2BE01F8D75A1B7DD83A2911EC2 -:109B7000579D3629FC2D6E8D56E0E1C713C3FC4579 -:109B8000FE1FB95CE91F72284BE9CFF4F755E02BB3 -:109B9000EA062930D68722EF4F9F5FA2C069DE090F -:109BA000CAF8CB2AA72A708AE706657C52D92CA569 -:109BB000FFA178031F03D526958FFCFB0A678A63F4 -:109BC000E97C655772FAB0E08B841FF9855ED9593C -:109BD000DD766E1FB95FCFF381CB056E8BFA384906 -:109BE0003EF71D1DFA87DC02E487896F9BBADB62B2 -:109BF0007A015F721F31313C5748270E003F87B80A -:109C0000EF9192533128977BCBAD51C89FDDEE92F7 -:109C1000688497945BD322E5A821D33B88DE53F078 -:109C2000F2F5C9FB1F2A997ADE7DF48751FE7A9FEF -:109C3000A77FC2822CD48773E8C8E6D37E6D988E46 -:109C400053E9FB4ECC3B5FC1DFA8170C37E9D3F0DB -:109C5000B976959EEEACFB900E4F3C6AA673581DEC -:109C6000F389FBE57C63F4B3312DF9E7E2BFDBCD8B -:109C7000C743FC1B8574816729F825BA9CA3903ED5 -:109C8000BF11FAF66F42DF1E177CC53C1661E6E095 -:109C9000F749BE35CC7F787C2EEA4D11C76BDD3598 -:109CA0000F6B686E9298ABDE1141D747051E4F8946 -:109CB00075ADC579014EB9C6AD21FD32EA3C1AEA4F -:109CC000DB15F7B410FC84D0EF1EB56D74BDE71D35 -:109CD000416A2F9F1FA2FE31FA73B48E0E3AB85418 -:109CE0003A1AF91410EB91F386EF7FF100CADB19F1 -:109CF00037C73FDE1FEB467F11EF77B878EB14AD27 -:109D0000CB85763FDEEF16706D3EC2DBC4BAE2FD56 -:109D10007E8203625D0DF3930F6C70869FC79C3546 -:109D2000A6487FD3953C6D15F4DF2CE864BC6F9B8F -:109D3000A576B0A313BD92ADF4A745474C06BB135F -:109D4000ADE8FD01FC85FB8177C80FF83DBAD8BFAF -:109D5000223A4EEBC897AA489E56C7DCF406E6DBCB -:109D6000D71CD219F7B7935F417BF9EE781BF9D373 -:109D7000E6F1E37A46CA5D9358C75641F7617EF72C -:109D8000D13B60FC448F8DEAF14399BBE79D30DF06 -:109D90008449BA2B08F31DEAF0279E187EDE81FB6A -:109DA00093A9620D7B264DBB1F9FFFEE21B00BCE0A -:109DB000309EB27F73D9B489FD908F21CEC7AEE8B3 -:109DC000F39AE0D72B02AFBD825FCD42BE770B7F07 -:109DD000B253F893EDE84F6CC8E722B11EEE4F3650 -:109DE0000B7F12427F02ED5BC29FBC89FE04DA82C8 -:109DF000F1D9A3C96EDA35E14F2041A1F3048B9468 -:109E00007549BCCA7AE80ABFC626C728FC1A1D9B3A -:109E1000A4F49798D315D87D364B81AF3ADDD7E0BF -:109E2000A754BF32FCF870839F2A51E0218726286F -:109E3000F757B8A729FD538A6628FDE5AED94A3FF2 -:109E400013FB6185FC775618BD56A73C57EC3BC900 -:109E500078EADD329DF66D86BDA7BB22F5B690751A -:109E6000EC9399709F0CC217A759CE97A5F4531C79 -:109E700075C8E249C7F37BF5152087D0161F8238D5 -:109E80008D8A8F20D710F7167AC6511C08F1D26040 -:109E9000E2431BDF6F92FB56C30CFB4F13F2D5FD61 -:109EA000A9C20BEC4F8DE8DB455CD62BE9A2E23270 -:109EB000D02F8ABF1E8FB9692FCACDB60F214EC5CC -:109EC00038F7C39F53FC25E3B6AD9FFD9CE2DBADA5 -:109ED0001DFAE255F4A550E8ED9643594D2DA06FBB -:109EE0009B5335972035E94B91D497166137CB6A50 -:109EF000E8FA1071DF568B2706E3BFCD8797887984 -:109F000023EC08C5EB117604F34896A8F6A7A687BC -:109F1000FBB338B322C733D6D730DF20033CDC3065 -:109F2000BEC4004F308C9F6A806F308C9FA5F43781 -:109F3000C1BACF176F6F16F6418E2B347B7457273B -:109F4000F676C821D5BE324F8D72EEA1F9E85CB22B -:109F50009B5B8EAC10749CAFF0678F7CCE21A0739E -:109F6000FEB9F79798FD31FD410E4A0E9B5DF5CE87 -:109F700030FF249F18E6C311F395DA7545FF9A0E5A -:109F800073FE76B5CE5DC23EEF107EE66543FCA65D -:109F9000FF70FADD29203F5B5A4C945F6D393435F0 -:109FA00009E7DB7D760EE1DB74D844EF91ADFFE38A -:109FB000A46BF17D45899FC4A7F0BD2531B8CF7A48 -:109FC000A6C544F6AFD0E24972744277A37C7535DA -:109FD000AF945B08A092902EBBC10FD1B961614FC5 -:109FE000255DF61C7D8CE8BEEDF0E224A4FBD5EDEA -:109FF00026852E23DBD4787DC48944051EFA318F53 -:10A0000007C1EF2AF4BD10DE46BDC09D1115BE5C30 -:10A010001D7F91F1C076C1A76D824FDBA35C959D3A -:10A02000ED6B6C3B669D1FF95D854FFBF2BAD1A7C6 -:10A030007D79FD6D33F011EDEC99E326B2B3231C6D -:10A040008D7A6D27FC286E3519FC841A375C6ABE40 -:10A050007AACAFD8EF34D8C5AEEE9776B1447E3F38 -:10A0600025744DA7E763C37C10E72A0DF49471F4BF -:10A0700085F926CFA31BF8D7C5FDE179FCC67CFA8C -:10A08000BFFA62FDA5A582FCCDEA98B7843D7F8B1F -:10A09000ECF93BDF0B7BFE7D778A930E8EBFAC27FE -:10A0A000EAD1C10E3BCEE222EDB83C0F196A7D2702 -:10A0B0002632CEF70879DCE97E77E200E4672FFDEF -:10A0C0007F34DE794BC43B6F62BCD31BF78178BC15 -:10A0D00073C03D9BC73BA91A7D2F6649CC55666F5F -:10A0E0002772FABF3DCE9952A4C639E52E35CE91DE -:10A0F000FB07BB1D1A9DC39A98A7C63DBBF117ACC1 -:10A1000033D9B500BEC7B5DD3DEDBC763828F4FBCC -:10A1100080E0CF6BC20EBF22F2861D487FE24B99D2 -:10A12000E00BAF57149F76C5BA9CC89FF93C2FCB64 -:10A13000ABA17C7AA4F4EFBE5A1A7FF0CCACD3F872 -:10A140007EFF6E470CD55976233EB0848316EF69A7 -:10A15000FC7EC56EB7E65CD2495E3FA24DB50332C8 -:10A160004E9072B9BBF51392CB5DEDE7F7A7D27EA7 -:10A17000C971AFB1974A913E57B5328679C385EC24 -:10A180008FD12F5EE839C6F123CC8D7A677EC7F870 -:10A190001C4F7B50C7F3CF3BDB4249B85DE7091E3C -:10A1A000D0F13DF0E2B620E1BBCFAD39F44C1A5707 -:10A1B0008AE7A25F3BFBCE44BCBEEBB4D964A37D6F -:10A1C0002607E96DB1D0CF37CF9A625D445F9DF627 -:10A1D00039826D9FDC8FFAEAB7EBF4BEC8EEB38329 -:10A1E0009223E9B6EA4A9DECC9F6D13613D697B761 -:10A1F0009F368BF3D6418A1F76B467C562BBDD0DEF -:10A20000FA43F62244F47FEC4A07DDB713E6E3761F -:10A21000C249784839089E369575F6BD9DC7AEE4AB -:10A22000EFD18F38FBD718A4CFABA7F7C4A0BDDA06 -:10A23000D5C69F33E29E9618CC33DF6837C5F1BA96 -:10A24000CAE064BCDE3CE6DED841B8AE3613DFBF00 -:10A2500011718D7CDEEED1F3A89EBFBB8DE761BB93 -:10A260004FF3FAD1F6003FB7C6841D93E3B79F9E24 -:10A270003AB11FD60F02161A3F820556C4C3B8570B -:10A2800052B65E49E76BFCD52CD2EE953AD438A78E -:10A29000A4CDE09FBCD5A407920F07BF9D7A4D05C2 -:10A2A0009DAFE77672BC59B52FBB4E2F499E8ACF22 -:10A2B0008FE5CF67017EBFCCCFF0C71CF1DD95FAEB -:10A2C00031D74D2BC7F936F373662362557B767011 -:10A2D000D4ECDF2EC4F3FF9B62C8CF6EC7F5E3FC5E -:10A2E0008718D5CF76973D521A8F75EB56E6E271F7 -:10A2F0009C6AD74BCF6CDA1B0FE3DF59AF117DC7D8 -:10A30000E5A9EBDDE9CEFE35E6C1675A397D653D4D -:10A3100049EAE59ED6C41BC93E8D86BB818EEF946B -:10A32000BD4475EC5B03EA3C4337C628782F6C4983 -:10A3300034E46F6A7D1CE24D591F882D1F12CEDF59 -:10A340000ADB797D7DE80F53070701DFE2D1FCFCD2 -:10A35000BCB12E3EDE6C53E32C435DBCD0581737A6 -:10A36000FA73118F0D11FB1AE7C43FC2CFC97AC32C -:10A37000364B7086E712E2876166485DE85CAF376E -:10A38000A900E8FFB2882F87591B7E9606AAB2550E -:10A39000F78F6011710173F859F290707E3BFCB831 -:10A3A0009A0F141D51E512F2C7CF319F5C897B9A39 -:10A3B000A4077E7E2EE222E38CD531FD9B5A80AF2E -:10A3C000430F31B1DFF17FF6A25C357D26F73320F4 -:10A3D000F4E88EFBF38CE2EDE6CFAC24775BC6703D -:10A3E0003F25E314B94F730D6B5956AAE1B96CFBC5 -:10A3F000F216A0E7A68373D317C1FCEF7D44DB9D63 -:10A400006C4BA1FC3E7D83925F0E9575A823267F41 -:10A410005201C6EB3645AF657FD3912531F87D916A -:10A42000332113C969F38756867F1FA069878DF68C -:10A43000739A0E5B69BF65DB0EAE27B2EE2CE3FCB0 -:10A44000D7853DDF2FE2DE5745DCB24FC42D7B447C -:10A45000DC121471CB2E11B7EC1071CBCBC26F6E26 -:10A460003A22F4EF9E9800FF8E2DAFCB4A3C6FEE60 -:10A47000DD72D40C0BAEF968C89A20437FAEEAC9EE -:10A4800078A7AA27E35255FB31C691AE8C2FB5674A -:10A490002BFDA3D8954AFFD5ED830CF9C870433E38 -:10A4A0005262884726AA7A792822DFA5FC5ACD77FE -:10A4B000AF8DCC7733914F3C0FDCD6F230F171DBAE -:10A4C000F1AC84C8B8EC65A137DB8E73FFFCF28970 -:10A4D00053719DC56D27043FBE14FC6815718A2712 -:10A4E000CD7D7D7E0AE615A7AC78EEA32B7996F795 -:10A4F000CBFB4E043E8D8FF47F9F51D21886BFDE7A -:10A50000F2975CAA9F5CA47E2C8DE3E7DC366BD1CE -:10A51000F4FEFD85DE6BA9CBCF12E7926A07F07DD2 -:10A52000D1DAA1D86EB078D2F1FDA7CD9A6706DA5C -:10A5300071FF6FAC9DFE3D095FBE3CD7C49AD03F12 -:10A54000F023C9F0F39C6646F98A12E0D3CCEB43C2 -:10A55000FAD8315F87417AAC87E1BA36595813FA95 -:10A5600079E6664E4777C655089E73AA9F77398E5F -:10A57000D7427CFF18DC2B7DEF038F66E177B7B005 -:10A58000C57D329B9DBF7760C9F7DE9F5FC8BF67FF -:10A590009B3008E72DC9E6FBA841B2DF33C4BCA657 -:10A5A000981D3DC99F7665570D792EAB56DF473113 -:10A5B000CA4B93B0B32F677A6674F61D8C67F3F9B4 -:10A5C000B9906D5F4CD6F1B905F67837FF2EA45BD4 -:10A5D000C7F7C05EFE7242CCCC4EE42CD87FE6B307 -:10A5E000F911725010AAD5C5DFA930A9F52D531065 -:10A5F000F97D26D64A7A3D1C179C78EE7C234EA81E -:10A6000071DEB01635FF0FEFEF376878DEAC439E92 -:10A610009021C8FF83FC7B1A179227E3BEFD07F940 -:10A62000F2BCA4F72F788E584F88A5F3359B0EDA2D -:10A63000D7611C69ACF7BDFD1EB7E346FC9BDF9BF1 -:10A640009E8EF1D7E691D7A5A31E6F41034FDFF38E -:10A650005934DD1D09E3FA63D1DE33FE9D2D7FF50C -:10A66000743C2FB365BC8417F2F1A3F8F8F79F7B15 -:10A67000EB31FC1ED8961B453F7B808F97B0BF66A1 -:10A68000FA28ECB79808AE781EC6437F7B5FF707C1 -:10A69000246FF9EEC328A71B5077001ED5D7FD11F4 -:10A6A0005EFF00650CAEBFDDC77D24128EEFE33E7A -:10A6B00016096FEEF02F6DB191FBC7520EDF3E3CD5 -:10A6C00055F81DCEF72932AF29BEB83AFF9F859CB9 -:10A6D000BE21ECD501E13F5E13FEE315F41F940F9C -:10A6E00073FFD12CF68D770BFFB153E4BDE1BCCBEA -:10A6F00023E28B4A910FF33CAC606429CF7B1DB2FF -:10A70000CE9F61EE2C1F9A5CA0C68993F255BF3292 -:10A71000A1579222A7653DD20D7972B6214F56FD01 -:10A720004A8979B0214F1E6EC893D5BCB7B87582DF -:10A73000214F9EAA8CFF20DF29F6916E30E4CBB327 -:10A740009471613EAAFB36617ECDEE948F5B8A6781 -:10A75000DFFFBF8B8F9DEFD7FCFFC7C77F501F6305 -:10A760004DCAFE8DB17D53F8FFD785DFD82FE2802B -:10A7700057459D639F88E7F6201F7B635CE7127156 -:10A780001D3FC721EB202F8B3A549338C7B145ECBE -:10A79000BB6D1275A8A5C5DFF1731C6799E0E35B7B -:10A7A0009DF2B1DCA5C67913F3543E8E772619E2EB -:10A7B0003E35CE1BE350E3BC52BBCAC7516CB0213F -:10A7C000EE53F938B2ADC410F74D30F829F51C0737 -:10A7D000C405ABFA15E27B09EA798EC2907A9EC372 -:10A7E000E8DFE5FB8A326EE888137CEA3EF326F464 -:10A7F000A1B85F9466E5DFDB307B2FC7B843D2EBAF -:10A80000B7FDB83FDFF2979B889E85E8CF3BF1DF2D -:10A810001BFAF1B868433F5E97C0F723A30761793D -:10A82000D3CFE39F84490E7EAE8A85F0FB53E78940 -:10A830009B36F44B09C74B66472DC33842B799FC8A -:10A84000F8FD5DA6DBE9DCDDDB5DC451C7FA65CA56 -:10A85000EF9F6A38EF5FC4BC5AF16B14579DEAE76B -:10A860006EA4F94B5D6D5817DFFCA1D5558FF21C16 -:10A87000C5BF83628CB75EEF97CBFF7E8FA01F9E14 -:10A88000FFFF39FA4BFC502CF9DF16D57F6220010F -:10A89000F36C88E6F09BFD3E9E8EDF1794FEFAFD7A -:10A8A000E74F913FCD8DBD7C36E6CBDA1A7F22DFB4 -:10A8B000AF0C927E19E3B62EE35F439C7624CFFD66 -:10A8C00006AEEB1BE19773F1935283BABE7F43B49C -:10A8D000E736FE3D18B78ECF957492FDFB04DF5F1F -:10A8E00017F375D045CA157E9F2631E23D5803FE09 -:10A8F000925E2B0EEE0DE111C64B5D8F5C4727F289 -:10A90000E3B940DCFD4D67F2C326B9C47BBA9DC7ED -:10A910007D16114746F27F38AD2B20D7CFC60CC22B -:10A92000F75FE47BEBDC1ECA7766121D0D8E4CD000 -:10A93000A39B0EE974CE81897D7073073F8B35F43C -:10A9400033E6B11A4B8AA8BB1AF7138DF503E3B9A6 -:10A95000B2E2D6CB15F8AAD3EAB932F7D9BEE7F5F9 -:10A960002BA3634718FC52A9C16F4D34F8B5690693 -:10A97000BFA7D6C5CDCC2CBF3324F6EB35277E7FC1 -:10A98000C7CC2914D92FBE03C4E9BDAC0BFD95E794 -:10A99000674FF57312DD3BF4632D7372FEF995F783 -:10A9A0004CF4582FF1F9A121D28FB928EFB50687C1 -:10A9B000D1F73CAD2EF5EF33047CF68F46E7E07B14 -:10A9C000368CDAA77C8E8F46D3FB38A9D43EE17350 -:10A9D000D2F535BE3C6A1FF3B9E8FAA3BE226A1F5E -:10A9E000F6B9A96DF09551FB80CF43E356F92A09DA -:10A9F0005EE9F3529B05E10DFEBD812C3F7301C65C -:10AA00002C7B253C2F82CE997EC023828E57D43951 -:10AA100014B8676DAA323E7DBE53E94FF3E629FDB7 -:10AA20009755BA1438C553A48C4F2A732B703777B7 -:10AA300099323ECEE551E098BC4A657C94D3ABF4A4 -:10AA4000EFB96A7842CB79F4B9C1E73E8A7458E528 -:10AA5000F31CE5742A3BCAE95349ED2DFDBB117F78 -:10AA60001DE64637FA6D47BE83E1F976AB9DBFF729 -:10AA7000DDCDECD0BA45CCDFCD0DF329F8C27C4A50 -:10AA80003E17E0E789F33C4755BC2B95FB4007C9CF -:10AA90004FCA38668CDE230EF3B1FB2D8E3F0F06B6 -:10AAA0003CEE1BA3337C6FE5E0E8695417C12D4CE5 -:10AAB000D6891DFD4CC4A731FDED942F4E7954A3CA -:10AAC000FC0E56528E75C4B987B25D917F0F4AB69F -:10AAD0006FFF8A7F6F2866CF3627D6C5A614CF4C66 -:10AAE0008A8AC8FFA604BF1F9D46F30D1C12057875 -:10AAF0004C5933D33A3B3FBC3E396EEEA36A3C1A05 -:10AB000096FF805DC4E3B44E699F5639D6D1F555A2 -:10AB100079E7DFB73929D6F58588D73E13F1DAA76B -:10AB200022EEFE58C4DDC744DC7D44C4DD1F89B875 -:10AB3000FBB088BBDF17F1DA2111AFBD23E2EE15C0 -:10AB400022EE5E95B78EFEAED5998D1AD3CF73BE29 -:10AB500074C17A759DF3D7AAFB86731F55E3EE394E -:10AB60000FA8F1DAAC656ADC7D739D1AAFDD58ABD6 -:10AB7000C66B33E6ABF6F17A6FA9025F57A9D6E54B -:10AB8000AEF5A8FB86924FD3CA543B694B55E3B54B -:10AB9000AED6BB35385EC7BF4382CCFC34C21F463D -:10ABA0007C0F5E39EF58E07097E27E4D21F32CC5A3 -:10ABB000FD9C91A6D0BBB8DFC4DED7E93B904D78B1 -:10ABC000C730D0D73343264D7146F81DBF4AD7AAA8 -:10ABD000236A7DE4863BD438B8A25ACD67AC656A57 -:10ABE0001CECEEA1EEC74E33F81D26FCA195FFCE5E -:10ABF000467BCEEF874C31D5F4BED2A5FA232B335A -:10AC00009E1FE3FE889E9BA5F4933F320FE0E7244E -:10AC10008688F714EAA386BE89FB777B3EE4EF17AC -:10AC200000D943BDE0FEAB18A7B7D53E8EBE1FB717 -:10AC3000D3C2DF1BD89D16EB5A025D579DE5EF0787 -:10AC4000B076339D1FF3E27B235938AF7A7EAC3068 -:10AC50006456CE97590DFD97A14F3C2F3EFC1CDD4D -:10AC6000FF1C3EE21CC7003680CE47B474FEBE41D6 -:10AC7000471C679053697F0A823C3E2AE8323EAA0D -:10AC8000A2EF8C99DF67F49EBDCDD476E2197C3FAC -:10AC9000EA735E871DC5D4BCED9A496ADE36C6717B -:10ACA000FEBC6DBC5395D78979AA1D2877A976E09B -:10ACB0009CB8A6859F43EC2AAEF10CC892EFE91030 -:10ACC0007DA272F6C5F07D4C2E3F23C43A1FB27AA6 -:10ACD000E8FD95653D19F16984839F57ACC77D1BDD -:10ACE0003CFFF71E7FEFC5CC3C4903B03D3E569C70 -:10ACF0005F9CE4A2F95A39BF8AE0DF4F59E79E4FC3 -:10AD0000B485CCCA7737CC2C82BFD03F07E5AB30B7 -:10AD10002C47FF7BF012E728A59CC5265E60FFCE7E -:10AD2000AFC481B21D1572EBB88E571C7C1FF59510 -:10AD3000506D08BF13F95D2AAF53DCDB63AA997F1E -:10AD4000B7C51D3B06F83256ACBF48EC936DF1B168 -:10AD500010C6739B7C766AE5FEE78AD4C549E8375E -:10AD6000B76478D3F15CE096946ECB18D8E9CD96B1 -:10AD70006E3D3A7B8FA0D93294FCEC96E63433C614 -:10AD8000A1A3CC0E33DE37AAC72C1DEBB1E3F07DB7 -:10AD900093648419EDD36DF20543A3E95CA897CEC3 -:10ADA00011C13A4A318E1DED98497FEFB1F93DFC52 -:10ADB0009B4A181F77ABC2FBF6A5F0F3D736073FC7 -:10ADC000DF3A36791EF1ABC0C5BFDF57D023D615A9 -:10ADD000C0E952F9777CE6C33FCE17EE2740EF95E6 -:10ADE000EFFB0C651130F2CB00AF31F2C7702E7162 -:10ADF000C561717EAEA5F37D9BBF8AB8628BA83B0F -:10AE00001C1171C54722AE3828E28A15863AD0BB9C -:10AE100022AED827EA40AF8A7ADE7E51CF7B5DC46E -:10AE200015F2FCB5948BD495CC694B60ECAD999C34 -:10AE3000CE692BB54019ACA3740E8753EBF8FEE82E -:10AE400015DE064F4901F65B5CE3601DA9950D63B5 -:10AE5000701D69556DF49E52A5D7EA746BF87ED2C9 -:10AE600013F45E947C2FEC164E1A76D39CB1647F5B -:10AE70006FF18A73C77A6B21C9D7A316FA4E92FC79 -:10AE80007E5CE51CF57B4AB30CF4BDC9005B356EF6 -:10AE9000475E93741FCC0647D23D4D8C8DBA459CBE -:10AEA000E7C597AE3AD1973582EE922ECD574D88B1 -:10AEB000E3EBE0FBA13631CFA1E21BE2709EF77A13 -:10AEC000F0F9A60A7D30CEB74ACE27DEA78916FC58 -:10AED0007FA8EFF9CF9DBEED63CA39D3B7057F3A9E -:10AEE000E62DB9DF82DFD3AE0CDED713F525FC5E8D -:10AEF0008D3B8EBFBF32E9CF99C0A755E23D0469B3 -:10AF000057AF13FA6B7CDE7BBEF3BFBFF35EC90C99 -:10AF10000B7E0FFDDAE02FF8DF0336D7A6469EF74B -:10AF20007D0FF1035B79EFB53FA3BF2319CAE0F2B0 -:10AF300060BBC6E6C4EF0C5ED1C3BD1CE998DAC3A2 -:10AF40003546D447C99FD9043EA698B55A0A8E1FE4 -:10AF5000AE91DED65F3581CEFF5D770D3F27F1FFE5 -:10AF60000010785941008000000000001F8B08008D -:10AF700000000000000BED7D0B5854D7B9E8DA3320 -:10AF80007B1EC0A0838A1912B003A819531F230F78 -:10AF9000051C70A39812436410548C8803A2D0D669 -:10AFA0001892A6B7F4D4731804110951D3A63DDA48 -:10AFB000F818CDA3BDB9DE9698DCA64D73CE21C698 -:10AFC000A4696F12B1471BED6D0DBE92F46BBF1EED -:10AFD0006DD236A7ED77BCFFFFAFB566F6DE0C6825 -:10AFE00052D3263D852FD9AEBDDEFF63FDCFB5B967 -:10AFF00072057EE633E6606A78C8C7F0C77245819D -:10B00000FF4798579D83EFF18DA19E5DC9C4FFB79F -:10B01000B26032BC0F7EEA176C266335ACD53F00B8 -:10B02000EF7BF3B454F774A8AEB35D187232E683C5 -:10B03000DF2B59D047CC239F354CA57A39DE920AB5 -:10B04000682FC767349FA17E6B0FF33AC642E14F6A -:10B05000B0BA89D05FD46D55234E9CAF37F839A76D -:10B06000E6622C2BDDD2E080F554666C5ECD264086 -:10B07000832A877B0AF60F2CFA796E1E3C7DEBBD86 -:10B08000B83D6CD70CED4E4DEBCEF04E8FAD6BEB6B -:10B090003656128279B666FC0FCFFA646CF7BBF6AF -:10B0A00010B6B3B1DA7E18BF77C12FD3335DB1F6D6 -:10B0B0008766954EF3E7C380E5A98CA53136D51E8A -:10B0C000CAF24F1FBE5FC6C28C41938E9244C660C7 -:10B0D0001DE71B948803D655DB07F01B83F5975AB1 -:10B0E000F07D439FC3DB8B0B649AEB0ED8E77ABEEF -:10B0F0004DD630A52B7F009EEBFB9A2BA8FD2EDBB7 -:10B10000398497137E11BE19ADEAB928BCB03DD37E -:10B1100095711E53D98E73C07A17F89327BCF949DD -:10B12000F8772ECBBD62E5F847F8D68AB6090DD57B -:10B130006319E2D303C02C1CBEAF95EF59D9C07878 -:10B140004604C3F263EF4F37652786B01FD28D5395 -:10B15000D0D52CF8BF9779ED7310FF9CAE6A045DD3 -:10B1600079197B9EE82A6C0B47D709FB62F7D962F5 -:10B17000749765188FE17A97EBCBD45F3B3919D67A -:10B18000BF9AD15C6C75A085C3EB3E4E8F4E78297B -:10B19000C689D11B8C1334D11FE16BA258278CB305 -:10B1A000ACACECFFFC1060F6E8CEAC3B104FCBFE35 -:10B1B000D1CAAC305F3534C37275AD12894079792C -:10B1C000E056E287E5FAF1E17D4D8DED821E3F6F9D -:10B1D0006CCAA671D694F371D826DDFCB4BE9D046A -:10B1E000CF20635BDC3A7A7B33934D6600C7E77709 -:10B1F00037EFC3FE171F7430A423867DE720DE39A6 -:10B200005C4F02ED22FDBFB54D891C84755FD8ED02 -:10B21000A075BEB94E8930C43F733F3E00EFBBFD01 -:10B22000294497171342FBBE08F58D5B93FC61D848 -:10B230006FCFB8D68D4198F7624AA81EC769DCFA6D -:10B24000494B18DAF724869D59386EA3D57F10A68E -:10B2500058A9024CC7C113FE7D133C1B7A74F883B6 -:10B26000FF8EF9151A7F898585FA5DC3E9C7319B81 -:10B27000D723C01DBAF52FC9B2D07A4F3DE4A0F54F -:10B2800026CCF6123C1A0A12B484318847A6A93992 -:10B29000B09E746D12AEF38202FC09F4767E9912B0 -:10B2A00046F83095E3C57ED38D07909F1E15FBBCF5 -:10B2B000F0C0DC4948CFE75378FD394F6204F77599 -:10B2C000CECBCB618F2BF218F2861AF22D4FE6FB14 -:10B2D00050800E1AC5BA1ABD162D01F0DBF8D08ABF -:10B2E000CF229E1B3D7DF7E0F36472385981FE6FDB -:10B2F000EDB6328437C2C39983F545CD586F86CBFE -:10B30000257F16ED07E1371EE0F6E6AECEE410EC41 -:10B3100083B959C83E310687869DCF7C419949FC47 -:10B320001CE6FCCEF94461BAF318E877A5D71E2EC7 -:10B330008771D8D1C944B72BDD9C6EED855B52B3C4 -:10B34000783357943EBC54EEC3F3BD51941B906EBA -:10B3500001AE2B915F66223CC6CD1980F7B54D46F4 -:10B36000BADD3261F303D5B0CF7505366685FA755F -:10B370001ED5C037556D463E827D1BCA636633DAE3 -:10B3800077CF38419FDD9C3E81D2270567C4E862B4 -:10B3900097DF42ED7075B651E06F86EBC70D0EE793 -:10B3A000905E41DE9CCFF0EE2B24B900F4C3D7C5EC -:10B3B000AC3A7E68E87110DD33200F8413D0A7BD4E -:10B3C0006A468C5E247C1A7675103D3608BA6BECA2 -:10B3D00003FA19A3A32313BC70CFAA9C273B46678B -:10B3E000541F87CEBEE767C44792FF1A58B09E59D4 -:10B3F00087F3B57C129E8B109F9FA90DA7E3286150 -:10B40000EABFA3A4682CD1BBC007173DF4E344BC3A -:10B41000254BFC84D9093CCF5DA2D2DDA69C2E032E -:10B42000796315E7AC5D1B8C0CC0FB94362BBD47D4 -:10B43000F9A2427B9C9621C29F9BFBEDA9504E1026 -:10B440006597C0ABD5EA4A43782533A3DE338E999E -:10B45000E4899FE355CAD99D369686E7718238DF25 -:10B460009B17652BD86EA7A2907E602F33D281D513 -:10B470002407BCB32DE2BC0BCB738FE4ADDDC9F761 -:10B480009B906621BEF86D3A085425060FBBD8FF85 -:10B49000B8016FFF00D4D77B9CFE0894C73337C92F -:10B4A0008752986940376F4D45121BD0E179917BE7 -:10B4B000BCA1FC29CF4D86F6B779B30DF5B7FB3E9D -:10B4C00069A8BFC39F6B28DB994EAEE33A8738DC8F -:10B4D000ED02CEBA7A299707118FD5621F3BEC2176 -:10B4E0004F10CEE16ACF7A92CF1D259FF10CC13E5D -:10B4F0001C1ECE7F76D42761DC84294D6ED2238436 -:10B500007C2E805FC443270E9216A333BB09CE6600 -:10B51000FE33EB930DB385DE730BBB85F41ED7B8FA -:10B52000B8FA8D597F031961417A4D14F85A647540 -:10B5300091DCD85A03FA9C82FAE552AE2FF9EE2636 -:10B54000BC06453B16B690DEBA5CEC5FEA5FAFB571 -:10B5500033367033C06301D7B396175CAA41FA340F -:10B56000CFDF2BDAC97262C1014D8B234FDB057D22 -:10B57000250578FD722753510EC9FAB090B7CB85D7 -:10B58000DC5E027C8C745B894F9DDEDA27C6E98B1A -:10B59000D22B1BCCD1F3E9214545382488E2011692 -:10B5A000EA9B9D8A700E5323AB2BC888BFFF04D043 -:10B5B0009D437A0CFD94CE6EDAFB79A05F474DB2C5 -:10B5C0001F6D0B87D6F0D857017E8935497E8B37A2 -:10B5D00046EF64774079828FD37B6DBAD34FD561C4 -:10B5E000EDC4E43931BDAC46E877A9AC95F8609874 -:10B5F0001DE3E47439B21DC3CF1F399F439CFFCCB8 -:10B60000BAC94F7417E4E7BE057E91EE96D51AE9E4 -:10B610006A4568743AFB96A4B3B96C2ED159680395 -:10B62000D18543B4D93109E885C389E82351C2578C -:10B63000E8DB36950DA880A763887F58A4CBC69217 -:10B64000719F83DA0BC417833E66D3D3413060D534 -:10B65000223A3C0E16B24437C897411BCB7810DA19 -:10B660008DD1562C76C3FE064B1DC90D74A8460C11 -:10B670007AFB3118F7AC8B8DA8EF9BF9612AFC039C -:10B68000E5C0D68C373DB89EAD3646E73D0B5FAA88 -:10B69000D5A0BC5D96D92F6A4B61DCED09B2FCEEFA -:10B6A0002EAC7F3C91972F3FF9A75D241F805E1140 -:10B6B0001F49021F49527F9FAE832BE0C13921876A -:10B6C000CE19A709DE66BD5ECA09F3396C9EF74D37 -:10B6D000139E46DAF7B0F50269DE323A5FFCC76CBA -:10B6E0009297AD06BE183ECE00E9EFABC4BE2D4921 -:10B6F000CF6584E2D89151F86FB0FD4A6F2F009C5E -:10B70000BFABA0DEAB41EF398C8B0E18472978E92F -:10B710003F51FE2BBBC2E3108E56688072DEC642DC -:10B72000B41EC9AF0948075684FB00D583FC1D52DF -:10B73000B271903A37C24581F6571029D77A4E96A2 -:10B7400073B9B6529C7F9538258C57D9C34AD13EE0 -:10B750004F58B7F6E03694739A03350A787FA914E8 -:10B76000D707F59A839E9734C41BD0B341EE3C5F54 -:10B77000F287B71F817EDD8356BF03C6ED0E3CCB3B -:10B7800050EF7E673AF3E3A6BBB021ACAF3EE45E78 -:10B7900064F722DF0C9CEA9AC2D8D9763658661B29 -:10B7A000BEDEC12309762F6C36144E99F9348CD342 -:10B7B00053E070A33EF7C626AB1DF134B8B9218C17 -:10B7C000C0389D16EE57E07D8F1A6268DFDB377553 -:10B7D0002E42BE3B6D0BFBC7C1B36773F82EB4435B -:10B7E000346F457926ACFF608F5A1E89733E6FC84F -:10B7F0005188DF5E7BFED3B4FF6369767F028C3BAA -:10B8000084FE0DC0DF31DBCE0C3F8EDBF1950C1CCE -:10B81000FFD8BAADFE23B0AE631D0EB4A4D8B1DD1F -:10B82000CE5A1CF75871B367BD6E7CE74DF6567C57 -:10B830003F78A3DD9E4DFBB99CECC1FD6CCA1D8F0A -:10B84000B4D99D669FB416EBD73733DCAFDDB3D3E5 -:10B8500086FB73AA6C179E2F9FF05C7A752EDA4BCD -:10B860005ECB9C4F41FBCFFB43B7E6001E57B69D16 -:10B870005D8472C95E96B2059FDD629DF2BC92F84E -:10B880001D4A6B74E239D6DDB496FB613C9606C264 -:10B89000639A2588E75177609D73EA74FEBE79CC80 -:10B8A00070B874A3DF6516AE73BD67FD0C6CF7BB93 -:10B8B000F610B41B2A76D4C68363630E9763CECE8C -:10B8C000E6AC365877F76EA71BE1D3AD847635002A -:10B8D0005CC3992EFF63DEE1FDBE25FA49FA003C08 -:10B8E000111F6E387CC3EEB08AFA2AC723C0C5691F -:10B8F000D3C9CD43B34A9B111E51789BE74DEB262C -:10B9000079D1AD70BEFED6E159BBC3509EE90FDDC3 -:10B910008DFD8EF500AFCDA27D4E427D7F24FE19B8 -:10B9200012F5DD1DB0EF38FC3FD46465378FE5CFED -:10B930001BE03975B3759212073E43C56BB3D04F08 -:10B94000750CEA2D30CED06E277FC2FB2CA4AF1130 -:10B95000E873560E97F7BE99C12D39687F4DF7935E -:10B960009FEFE5D9C1AD39A407B47AB0FC31A0DFAF -:10B970007D1F11FA65EC46A4D7E9BBC3609232F78C -:10B980003883DE3AD2F91964432A9EC71D257F68A1 -:10B99000417BA07786DDEBD0F905A51EBDC4C7E5C8 -:10B9A0005B70CA853C38B959F5F4F564DF80BE4C4C -:10B9B000FE4137FCC6F30F06D11FA893874B4C6599 -:10B9C000A99FBE94037211CF7DA127A77B7706178D -:10B9D000A0FDF18AD51F01B86560072857552811C9 -:10B9E000D4D73B4A9E203D9E093D6E8958E74FDBE8 -:10B9F0009DAC6C0A8BDA732BC5FBA496B38FA27D2A -:10BA00009D84FE4FF4D7B638BCE47F41E4C3FCD537 -:10BA1000627FD2AE233D12F6B3B245F841D9835CC2 -:10BA2000DE5803F9480FB00F835D1264263BA4C9AA -:10BA300066B0E75699F407B3DD506DD21B76A0EEE1 -:10BA4000847AA1DAEF447A7A777ACEB12C2F5587AF -:10BA500007A47E0FED420527B60CE9CE9F1342FEE8 -:10BA6000FCB85D3B8DF2684BF011E710FAADD5885C -:10BA700013E5496FF9E79291EE7AEBACE5486F83F5 -:10BA8000EDE5D4EEB5F6203DAF08B951E1D77E4FD4 -:10BA90007C29F4B3EAF2D2D35D3ABC5669B79DEE85 -:10BAA000D2ADBFB2A0CA5096F4556965ADFD71CE56 -:10BAB0009759B9D2EFA231833E6A3DE40FC5392FC1 -:10BAC000E43391A9EFEAE1989C2BE846E853F74F5D -:10BAD0005F3076347D46EE53C247EE5FD68FB4DEDC -:10BAE000DFE55C9FF566BFCFF59AD719C5D308EDA2 -:10BAF0002BF1108373E077873B56A25CA8F0877226 -:10BB000073010FD565CA96F140273F16FECA1F077D -:10BB100092236158CF8B3EEEFF4C6CE17665625903 -:10BB2000D5223C9FDE2FBEEF2C50883F6B024A444B -:10BB3000837FDE2AECD59FFA18C51F805F5F4D8694 -:10BB4000F2EBC536EE47665AC51D7362766A621D12 -:10BB50008F4FECB033FF00F69BE6F26F86F7CB25F4 -:10BB6000FFD51AE310353536C33953698A3B249A19 -:10BB7000CE99A512EE7300EED931B88F647F8C4454 -:10BB8000274CBD94877E31337C369AE063B6772AA2 -:10BB90009F33F1C735DA3D077BF25E9C807A469988 -:10BBA000E29F82F8C32AE897A83D49E1905EC94721 -:10BBB000C2DE93F1AA1D4BABC9DE7B0DF581B1143A -:10BBC0006F9A84FE6A39BEB4F366FAB5FB725347C6 -:10BBD0005EC709D16F6B557C3DE104EA09B3F8F308 -:10BBE00006784E5DBA30239E9E70A250E809508FB1 -:10BBF000FAC189DDE5FC5968D4135879EE55E0D2D5 -:10BC000041FB4D989237361EDF1D9B157A30570742 -:10BC1000F7245F2B2BD3C17DFD6CEDCBB8DF2AE180 -:10BC20008790F3817C3FAAD7C3CCF33D95E316F60A -:10BC3000C6789217F27935FCA9EE56867476BF4D18 -:10BC4000AB457DCFEC4F3A9CCBF5C49E2CAD05EBBC -:10BC5000992BE72AE376487FB56FF6441E7E20BF16 -:10BC60008FC91E94F6D301ACCC8FD985AA9BDB85F6 -:10BC700089E9978EBAA1AA3937F40CC2A3F85224E5 -:10BC80006C01BE735428A43F39D219E93DD76C87A3 -:10BC90005D63BB1E646AA0E7AD8DDC1F5F3A5BA5E8 -:10BCA0007262C87A90CE05931F2751BB4C76D8128A -:10BCB000D00384DF86F4A953429F0AB256B2F75CE0 -:10BCC000B68813FD1566BF4D6DBA65602AC8F5DAF2 -:10BCD000824B35DE99D4DFE0F7A9F5661D4D15F5E9 -:10BCE0006E782E09723FD072F403E1F835919E2CE4 -:10BCF0008CC3F955BFC6B89D87FAC58AB55F98F160 -:10BD000035EFF5F30349FF92D417A53E03F2A5677B -:10BD10003CE265A1E225DBDFE42732FB85A45FC6B8 -:10BD2000EC3F32FB8BDECBCD247C48FD4BFA7F7E93 -:10BD30009F6BD4C3FE0BD803DBF516C2910AFCDD62 -:10BD40006B63193BA773FF0EEA4BC74A7FE046FDC2 -:10BD5000E2BF4CFDAEF57CEB8673E83C9EAB2F2436 -:10BD6000D850DF0E7A42E44F5CA218F9242D4FF828 -:10BD70001BF35C7C1E1147EE6E6F93FDC3286F8230 -:10BD8000E9F64882121B8715E45F133F8D9DADA530 -:10BD9000E6E5933D72431ED2B31FEC9119688F08FC -:10BDA000BE2F48A5FD302D959DD7C78DC5BAA3EBF5 -:10BDB0007082DD32E3FDCF3F218F19E6B91ADC76C0 -:10BDC000941439EDE88F001C5B395DB9A3FEFB2CA0 -:10BDD000F4EB6CF0EAF58A7A8C5BE4A2DEC9E31A34 -:10BDE000F2BDCE7FAE22FD26A687B4609C73F5CE51 -:10BDF000BC689C8CE2A751FFBB8F51BC488EA3321C -:10BE00004F07F101F2AA5C8F358E9F5EACB749F007 -:10BE10000100DCE9009259BBD3CA785E02E713192E -:10BE20008F500B83E599B0DFB5DB148A1BB370ED3F -:10BE300051D4EFD7897ABBF0BF99E348EB441C8615 -:10BE40005937909ED6F49031BED6D8672C9BF572A8 -:10BE5000E9EF576191B8EE7F403C713844ACA3C321 -:10BE6000E100EDF36F140E920E2B723FEBC1BC9606 -:10BE7000EE84D0AE068C6BEF75923F846C48E497ED -:10BE800001F885FD6CDB53F008EE675B9E95E0D70B -:10BE9000ADF03C97A3695F730EE9E86D9BE0F35B3F -:10BEA000F2BCDCEF82E7128844963E81F848E6B5A2 -:10BEB0001C4BE37AA53DC0F5C643938F2CE5715723 -:10BEC0009EDFE20BC4F25B4A013E33047C7C539A52 -:10BED000FC03F09C116826784C7FDA68AFDEEE3305 -:10BEE000EA953EB3BD6A2AEFCD8B9FD7128BB3097B -:10BEF000BFBB58BF99AFBED9CEE32D4F80DD8ACFEF -:10BF000043ED6E7A7EABDD43CFFE762FE96987DBAA -:10BF10007DF49470BFDF16ACC7B896F4434AFFF8BF -:10BF2000F7F3B8FDC6027C1D95622F8BACE9C908FA -:10BF3000E7E301AE178E74BE54971BFDA0CB82C6FB -:10BF4000F8DE8A5A637CEFEE99DA73785E26CDF4D8 -:10BF5000D842BA78D43AB1FF1D5FE3F12639FEF139 -:10BF60007FE47897E58B62FFAF0ABA483A9266F3AE -:10BF700002B2AA1EAABA15FDF6CC9D734DFAE0498D -:10BF8000C197499BDD36F40B550DACB4E338EB7625 -:10BF9000C138AE6B1F676BC6C40C637CE1EE3BB16E -:10BFA000FFF1687C61E39DA5507F5CC417DE7EBA1B -:10BFB000F5EB6117D2ABF673941FD63CED0CC2E3E0 -:10BFC0006D719E437908DFCB32FCBC9C3271543FCB -:10BFD000FEDB79F9C3FDF8D6854A6BBCBC96CB79FC -:10BFE000513FDAAF496E39A37EB44BBCCCE5919A90 -:10BFF000CFE7EFFC296BC1713A9F652D87E3E8F32A -:10C000007FCC53E478EFE591FD2FE560F00FF1C6AA -:10C01000B33AAA2621BC2FDA785E8C793C35DF2E24 -:10C02000C7B3E463FFF4E8FAD47CDD783B00068311 -:10C030008827D59D4C714D7617C53F251D25D5BB4D -:10C04000EFC0BC05302C199E2F49DF71DF91877E30 -:10C050009C9F64FB1F6323E3F51782BEDE12FC7511 -:10C0600011F90BF8E8BCE0AFB3C85FF03C23F8EB84 -:10C0700067ED7E2AFFB4BD80CAA7DA352AFFA4BDCA -:10C080009C9E27DA83F4FEC7EDB554EE6E0FD1F314 -:10C0900078D923B7E2B9F3DB6F2A248F475ACF67E9 -:10C0A0001EB51AF8A7654F9281DFD63F34DE506E79 -:10C0B000EA33C6CF1BBBB20DE5356DC6F8F9EA56BB -:10C0C00063FC7C55CB3CC37C2B430B4DFC7CBB8978 -:10C0D000DFAB0D652D9FEB89D5E5AB0CFD1C9E46B6 -:10C0E00043BBA4A52C140FFFE5F99C3E8F94148D3F -:10C0F0001D1AC5CF616FBBFDE7A89F44CB6A88A11D -:10C100003E6F6F5B42EFEF4FE0E79DB95F7D3E3FD3 -:10C11000EFBACB9A820B18EA458BAD7ABDE7D3B361 -:10C12000424BF375F6A0DDC3EDB17726D7583D40FD -:10C13000474BCB2EBF7803D051689091DDA381BAD5 -:10C14000E7013DB8A0F5C1853740B9267C8FC17E97 -:10C150002C6A79F205605F16283BDE3901FAFB672D -:10C1600087EA71FC12CFA517B0FF828AD92A92F50F -:10C17000FD298CF4D18B19F6C8C138F4706FBE62FA -:10C18000885FBDDF73DA1CA7CFF2B152F42367F9E1 -:10C190002E95A25C83B286F1AF43B342F7229FC1D2 -:10C1A0007B0DE5E4FD33D667E1793252DCE86B02C2 -:10C1B0005FD29F20D7B5A384AFE7B8882F0C99E250 -:10C1C0000B3A7FC23FE58FE24FB828FA0D7D35BEAE -:10C1D0003FE1A2883B5C947187AF55C78D3B5C5CA7 -:10C1E00024FC09508F7E848BBB6BF973D1E87107F7 -:10C1F000B93F388F1EA2F3271A77107ABEF09B1F23 -:10C200009BA5FD33D6AF9FADEDC2E76F6668BB114E -:10C21000CFC775F14FF7445DFCB3EC0786F8E753E1 -:10C2200039A103F93C6ECDD0AEEA0CB3A1846C8C7D -:10C23000C70637C6A3E3FF9D2FF5EB813F2B3EAB2F -:10C240008BA35AAE7C925D731CE09ADB15F0BC1494 -:10C25000B37E9384101917D3FB9EC80B1D417875CC -:10C26000A57CC7CBF3AF2CB1F30385DF08FA907937 -:10C270003E391ECA2B945B278063F09CD99E72A91D -:10C280000EED94410137F3F3DFF3DD029EEE0988F2 -:10C29000DF27F2823F267C3FDDEFA5BC36F1FE5A58 -:10C2A000D7F1B83DF873D463BB1BADDE835C6F2759 -:10C2B000BFC5CD819448AF2E1EFC6B3C2FF3D1FF40 -:10C2C0003834D90EF8EE0CBDE0C27CF037F6A898F1 -:10C2D00011C3BE911CB621FE6B7DFC7C5BE0097D29 -:10C2E0006268143E077A186FF1D03A2C96023E2B02 -:10C2F0007F86157C9ADB0FEE7937D50BE37D632FB4 -:10C300008F7FDDBCB7C9D9A81B3F6B0E3F77BA91B1 -:10C3100066F2303EA9443051BD3670F9D5B9185F88 -:10C32000F15AC8CFF1C6A6DF9E5C817E47CD4A7E1A -:10C33000C73736BD43E5535E4B2EA2EF0DCF6F4E90 -:10C3400062FB9BFF71DD446EB77078ACD994FB78CB -:10C350006F26C5C59439008753DA3BC9D9D363F139 -:10C36000B3350A0BC6D363D2E670BC2DD65AEFC4E0 -:10C37000752D0E3918E6399F6AD8FA732C7FA354AD -:10C38000F15AD1AEF7F1796AF7A8944F0BF0D98042 -:10C39000E557FC490CE75D107A52C5F6BF9BA1B08A -:10C3A0001B94EB0857ED9D54E4C33790FEE2ACFFBD -:10C3B000D7F2DC147C345505BECF41F81F75E9FD7A -:10C3C00094929EBE94A765CF21BF5FA825487AEEC0 -:10C3D000D2ABE8A79B799EF6372FA9187B487CB48F -:10C3E000F546F42F0D5BE708EBCB9BC3E5E46F0448 -:10C3F0005FDCBC577DF536A4E74D36CA43B8252F20 -:10C400003807F115B5B7AEF3B921F3D7060BF87DB0 -:10C410000450A7691E58AF4F8575242889FE30E760 -:10C420002BF2CF39C5F907EDB4B1D06E0DEB1F403B -:10C430003F1F53B59D56F41F16DAC83E5EB1DA961B -:10C440008C7889C5CBFC067BC3FC3C8FF131CAD309 -:10C4500070D27310EC6C8C97E00F68E250A90ABDA3 -:10C460007FC6C31AFCF37191577A6FC16D0F8703B2 -:10C4700060675878795DC16D376D862D9D9FD47A40 -:10C480007219ECABF741C5DFE1C5E7815D8D78BF7F -:10C49000A24DF19743D3FA8169F518626CEE719061 -:10C4A0008E7F6EDB176E457A7DC7C3DC48CF2BD2FB -:10C4B000383DAF3DC12216287FAAEF418A7B064F47 -:10C4C000A894B726E3B267D2785CF6CBED03B46EDE -:10C4D000B46B17CDE12636FE8CF3C33AD08F5AA643 -:10C4E00052BC743C7377E3F992A86596727DDA6D5D -:10C4F000A7384F05635F473F4F1BB79B0B455EA4B3 -:10C500008C63B10BDCBE6D815F9427E3CB8DF6713C -:10C51000BEC9FE95F2CD1C6F01FA0FE3FB8E3946C2 -:10C52000FB7824BFBD7C3E0D7A04EEEF3B228EFBF0 -:10C530005DD0D7319EF92CE8EBF87C0EF4757CFFCA -:10C54000AFA0AFE37300F4757C1E017D1D9F4741D2 -:10C550005FC7E74BA0AFE3F365D0D7B1DF8F405F94 -:10C56000C7E72BA0AFE3FBA78BF9F9D73DC51ED9D1 -:10C570000CEBEDB6B19F215D854B455C58C4C9B647 -:10C58000A54CA5F3DDF927A072D0A70695D06710BA -:10C590001FE10C27B51B4CBEF4C7FFC0F2B64CB26E -:10C5A0004398EAFDEE10F4EBFA62A6BF178A3D76D7 -:10C5B00046F2FEEC71E656409F796B993213FDA866 -:10C5C000E7EF50FAB13C788742FAC45464BD9CD876 -:10C5D000395AF4AEF7209E679DC94CD0E3237BB552 -:10C5E00074E88F6B237A1D5B8F76E97C872CBBEA1E -:10C5F00035A0CFC63645D8A9EE7D48BFDB14D93F5C -:10C600006D2FB6EF92FD45F98445F6FFCC1EB4B709 -:10C610004F46E76B5885E39DCC92F54D75583E1B10 -:10C62000CDAB2B5E8DED07A3E3E7EEC5F2F90C3938 -:10C63000FEFA5554B6C9F2E3D4FE7C2A6F7F4B71E3 -:10C64000EA7EB49BAFF7789D217EFEC139A6E9E36F -:10C65000399B8AACE67C70F2BBC938BF25C935E589 -:10C660005AFCA5BA383FF94B613E1BF2D9E74B5350 -:10C6700026A1DC3D9BE18F6BA72C2C1AC17FAA2938 -:10C680003CDFDECD42981F9F28DE27F6F13C7ABBC7 -:10C690004F1D96477F2DFE4499F720FD89B54DA388 -:10C6A000FB136B4B8DFEC435A27E247FE21A933FB1 -:10C6B00071E526531C22F4FEFC89756CC086761841 -:10C6C000D314E2A33A77FF8B13D1DEBFE0257F229C -:10C6D000F3BE4CFE56797F02FF6F9983F7CD78F950 -:10C6E000ADBB140FDA15BD772913F179E62EE546B7 -:10C6F000E4AF0B77296EE4B7CB73F93D98FCB7FD37 -:10C700002F7BF1BCF558FC1C1CC17FC15045B029E2 -:10C71000C5DB0BE39CBD4B1987FD57DF9769477A53 -:10C7200000BD53D023DB83FC624D520CE5BC499223 -:10C730001EF73E8CFC317FBCE497657B905F4BED30 -:10C74000B27F3B95578614D1FEDE3DDA64E0AF053B -:10C75000B2FD843AAC5F962DC7DB4FE3CF4F92E535 -:10C76000AF12FFF544C7FB5F34DFEB2821A9FC00C3 -:10C770008D575A25E5D9742A77D7C9F15BF7625EE0 -:10C78000EC2A8BEC7F1BF1FF5A26CAA8BFC37EFFA1 -:10C790009F381FD6CDFDE32AE4A73BA3F57F7C1885 -:10C7A000F9AD4E949B9F79620FD6FFCDEFEF2F3CF2 -:10C7B0009FB9BC9A0D2EBA212FC617E673A5AE906D -:10C7C000EB9D052D4FA2F86275AD07ACC88FB1B8CF -:10C7D0005A5A4D10E9DB69A5FCB9A087DD1A2F9FD5 -:10C7E000FF0F73F9F9F485B92E83BC1E39BE167F8D -:10C7F0009C86423E4ECF0216D7CE3D346BC1E6B981 -:10C80000F931BD0155443B3C4BE06981E77B334244 -:10C810003D588FB20BFD30D2AFBD44E41377947C0A -:10C820003DB800EF2F15DAFCC21D3EA88FF7AAE233 -:10C830009EEBAA053CCF2BD4EB207BADA647E49121 -:10C84000585D148F506FB21FA0B89988A78630EF3B -:10C85000388BF2BA46BDDFA19AE2A89D62BFA5B3AC -:10C86000DFA538F5DA5778BEB08C63D78B75AD4548 -:10C87000B90CEB6E6C522216E8D7888207E3BA3EF9 -:10C8800016F166C6E2CA2BCBD4013BDE0B13F7339D -:10C8900098D087A3F1F01A6F3FE6C7A85A825FC30A -:10C8A00079D84090F2E2305E94C9A2F1672947AA94 -:10C8B0009A6FB80BE3D43AB94571EA44364C6E909E -:10C8C0005C88E63589387A343F47C801199F6E1075 -:10C8D000FB5A1E9503154B50CF4DBC5FC4A945FCB8 -:10C8E00059C6A9AB4CF7DA1A030BC7903FD7AFFA7A -:10C8F00029AD26DD789F29D18487A945FC5EA58CCA -:10C9000053BF32D7186FBEDFC648EEF66419E9AEE2 -:10C91000A488DB3D9F2C927EC8C48104D4BF999328 -:10C92000EC905EF4E78CE5F6085DE632F975D4B676 -:10C9300055E47FC47A05E850F1BDF49F2897B15CB7 -:10C9400004ED55BCDF82F87059C81E95FE1F545384 -:10C9500016E5901FE8DC5CCC0369ABA771E47DF6BB -:10C96000C713E3F3C7AFE74A3DA1DF86ED56795E13 -:10C970003A85F3FDD97E20618745F5182FCF7F4991 -:10C980009DEB9571091BBFEFC76C4B6790BFE4BD72 -:10C99000B9E41FEBF7E23AE4B9B4EC7B4FD1397656 -:10C9A000ED7170DEAFA1F0DF5685278C1CC7981A99 -:10C9B000E078F2CD0C3A3064CE26C8B883E6C49055 -:10C9C0007854CEE2460A0C72B6AEE5BF819C8DE982 -:10C9D000FDDE3A1CEFE3B67EA0A70584D772EE7F9A -:10C9E000FBB8ADFF07F9DA4AA4C30F7B9EEFE5075A -:10C9F0009B719EAD8A56EBA27B31CCAF8C1E2FDC97 -:10CA000088EDCDF1C2ABF931FEEEB718DD6FB1ABF9 -:10CA1000E0A3E9B7F832C00ECF6BE0A743C44F01E3 -:10CA2000CE4F7FEBE71FECF747B8DFAD4A7F24D14D -:10CA30007AFDFD064FE4855EC7F1A7A63B1B509F1C -:10CA40008179BCC87F517F08AEBBC0E00FD9D3F25B -:10CA500021F843609F6F115ECB385EFF06F0A6148D -:10CA6000E27E34AE47FC0DD2654621E2B09FEFEF87 -:10CA7000AF30FF0C9AFF10A797287C849EA4834FA9 -:10CA80005DCB5F073EA5B4BEEFF2F57D0CF0B98239 -:10CA9000E8D5CFD77B35FB7BC35CAEB742BF7AEA24 -:10CAA00097C7E960A3D0ABC12E5F78833766978FB5 -:10CAB0009DAD3516F2F87353A121CF545B87E55134 -:10CAC000ECE64F17A68E6A37DF8DF51F17BB798FFF -:10CAD000805B2C6E13A17B7120C129BE5C2FDAF61E -:10CAE000B6552F9E867935007F2C3B703F56DD7EF4 -:10CAF00032546E6F9BEEABC9EF1DC87DA9D6BAB19B -:10CB000003DE183C5F1BD36AC7FB50CD5A4A37DEA1 -:10CB1000BB5DD87599F206ED9AC38B76E1273CDEB2 -:10CB20006E8CCB566B7CFFF61637DDEF93F7DDE4AA -:10CB30003D94E681692FD9F1DE1CD82F69307E65DE -:10CB400099ED9C7EDF0ED3BD14D5546EFB59E6F6ED -:10CB5000A3BAF6DF284C36E437837E534EDFE9E88C -:10CB600052DC22CF97F2329AC5181D25772E46FF48 -:10CB700025E8715E84C3C29D0F0E623CCDDE65A5C3 -:10CB8000D8F9EFDBBDDB8F024B25ECB592BFE1B7E7 -:10CB90006D0AFFDE47058FE3AF15717C66F23348FF -:10CBA0007FB88463C2033CFFC35E70B68CEE37D699 -:10CBB000AD1BCCE7B443FE0695AF8CC9EF6F5409AB -:10CBC000BAAA0F5CEEC27ECB3D1643FE90D91FA1E0 -:10CBD00032739E3CCFE354359EC7A9FA789E7C22DF -:10CBE000D3E87B1D895BAA099F551ACFE304254929 -:10CBF0007C778BE3A532700FE5F998FD088E02A3D0 -:10CC00001FC24C97667C9C36E1E33195DF4FEA3ECC -:10CC100061F587E175F7434D3DE83F0F3F64213FE4 -:10CC2000C605991F028B447FFE0A16852FE9CBDDCE -:10CC3000AD3C5F40E265C54E9E3742AD0C7EFB7455 -:10CC4000A6FF8EC70AE157B893F5D37D87D56CC888 -:10CC5000867CB0065DE956F4C778E9B99685B730A9 -:10CC6000825FA82713E67BAC75BC1FFDDA0337DAB9 -:10CC700052DEF4713B229EFE1A8BD7AAEC4D9D9F8B -:10CC8000FFEF7EADF7EBD7B286E97EA9C71E99A26A -:10CC90005CDDAFF5238C4BE8FC5A17768AEF6D8884 -:10CCA000FB1683B6D6493B5DD8CE4BE7E5983D2BC6 -:10CCB00016231D1CDBFB03B7B8FFBA69E2E8DF856A -:10CCC000C8298A934F7A7C2EE379209943748FFA8E -:10CCD0008CCD98971BF51305ECC22F139A57941A15 -:10CCE000D38F993B9AC7595C44FE237E5F5BFA99C8 -:10CCF0009A73430BF07DF125410F154A4481FD568F -:10CD0000BA9417156F6C7E66CEA3FF7B3C8CCB0963 -:10CD1000840FE63325F0BCDAC14C567B380E7E26F4 -:10CD20001773393A383B3EFE643DE827F716A57283 -:10CD3000FB690CF72BFCCA3EBA5FE18BF1E846E2D7 -:10CD4000F7D07CED4B1CEFBC9C9413EAC0F69DA180 -:10CD500020E5EBBCD567F57620FC075A5F2B80F207 -:10CD6000927FB2BA311EFE61C7F952E7665E539CEC -:10CD7000EFB280EF99685EF7A67AD4077BA57D268F -:10CD8000F4C755E3746538928B4EF0F6DF7B76EE90 -:10CD9000BEB03AB2BE79F773757BF1FEADD437A160 -:10CDA000BC1ACBB23F0B574C2A057D766D8B8C2776 -:10CDB00056EC43FD363A5F78F93EB4872ED88CE3C3 -:10CDC0004B7DF5FF3EBB681F8E1794F38717ED432D -:10CDD000FDF7ACA93D7D9F12C67BFDD9526ADFC825 -:10CDE000E4F8A5B4DFA85F31BC7135F63F6997E57B -:10CDF000CF523EC1F64C3EDEB1E736EE45BFD147DD -:10CE00006D3D1FF6F8EFB7FD487AFF191BCF1F0CD9 -:10CE1000839EF65826A651F65B39F369762BD07FB0 -:10CE200091A6D079F45BF48343FFA0CB22E8EE1FF8 -:10CE3000F6A24EBFAA44EEF320E5818C44771B0294 -:10CE4000CF3C6CF4173FB3CAB06EB6B11EFBCB75C6 -:10CE50009FC0F6B0EE551B3FEDC175AE92FE8D70D2 -:10CE6000E75EDC5F778AEC376DDF68F38602DBF71D -:10CE7000E2BCABA2F37C85FAAF4A94E37DDD98BFB8 -:10CE800012DE4FFE8FD8BAD61BE0F9FC73FB099E69 -:10CE90004177640B9E0F410FA3F3F8CE960ECAEFB5 -:10CEA0008EF2117B2083F8C8132DEF35F2D17DB4BB -:10CEB000EEEBBD2E384FD3E7E1F9E7E376E2F5DF9D -:10CEC000379C93B8EF3E2E87241DD5B9653F803F30 -:10CED000C893B55E39EEDDF52DD3AFC7BCDCDE0DF2 -:10CEE000FE8A917E2BF90938C9C43FD7365EA7EB7D -:10CEF0005ECAA36806B91E2F1F7BE35C45FA336F39 -:10CF000025781648FB9949BD63F13C9D5F8E79A356 -:10CF10007A47C53C32408C7A4737E659CDA27C2E01 -:10CF2000929B1AD4787479403717F3F85AA7C893AC -:10CF3000CCDBCCD6EBEDEDFF399FAFE71BF3B9DCD3 -:10CF400094DFB73DBF41A13CB1CEBEEC3178DFEDFF -:10CF50005CBA773BCAB5C14C0B7DA7E08CF8BEE646 -:10CF6000E0171D19F7C1FB53194E3FCAAB53293BBC -:10CF7000E93B6AE7FC56419FDF7903F959E7570C13 -:10CF8000A35C917EC396EF77911FF0B4979773FFE0 -:10CF9000ED9937F01C633EF3FDCE00E931F65BE11D -:10CFA00018C1BEE2FB9C45A2BE6ADB535FADC63131 -:10CFB00084FE22E5A7F9BE27FED8F4FA578F95EB39 -:10CFC0005F1EDECEC3863AAE58705C5E768EF05D34 -:10CFD000D85A797FD9A44F5599EE2733F11D54A91A -:10CFE0008F174D68F4A31D57B4C1A81F9DEB79A1FD -:10CFF000AF00ED5ABFD58DC7E4ED3E63BDD4C31677 -:10D00000F73C42F628E885867964FEEDEDACBF8BEF -:10D01000EE857B5F3E6A9D18B35B3ADD55A4A7346D -:10D02000FBA004FB39F9A5D2E47CD40FFAACF84597 -:10D03000589E7BAFDB07B4B35926D039ED57147D2A -:10D040005ED0E6FDC6BC205E8EF9E3DBF61BF2E89F -:10D05000C277AFC172D4CFC956EE473E8AFAC5D85F -:10D0600052AA3FAF0A3F186BD88FE759CCAF779AD7 -:10D07000F83AEA27634BF6233D05A3E7DF0ECAFB28 -:10D080005BEE16EB613F23F9D1A97179F2DCF7135E -:10D09000CEE0F781DE6F7BE0CF67893F83FCBC3356 -:10D0A000D7179D88748E117A1DE68B9BF93C39C089 -:10D0B000F3EFCAB4D95DA95EEEBF72007EB4D5D6D7 -:10D0C000D5E83788E5AB14D277D2D68E905F725B05 -:10D0D00080F3EF2BF346CF53592BF254461AA7A9EE -:10D0E00084E7030C2AEE1A2E97AD0CE572E983D97A -:10D0F0002E8C4DC976A525FC1C786F86761ACF1B21 -:10D10000B33FED02FAD388CFB8DF63A9A01D75271E -:10D11000FF5EBDFC9EC9F914977F33BC5FDA27FC24 -:10D1200015E57F9EFFEC57F38CDF151D29FF2120AD -:10D13000D69F57727DF21F1E4FD43484D710B4454A -:10D14000FFE0B07C0891E720F32012033CEF4EE6AD -:10D150004374865B097ED7FD9E8B38FF814EC706E0 -:10D16000904E6BB91C917476749E97D3DFDB7EA2D0 -:10D170003F4977D03E358072A486B72F7A9B7FF7E0 -:10D1800042EA17C9CF0DEDED984C72E8A6805E0E0D -:10D19000B9A2F722330271E4D0F185DA27023AFB13 -:10D1A00008FA670752E3F69F1288633FFB66067D25 -:10D1B000346EF43EA7360DCBFFDDF320589F39EFD8 -:10D1C000849F17E6BC13A90F36FDEB2F5663DEC90B -:10D1D00095055A15C713876F54AF1CE27A4E4C9FC2 -:10D1E000F4733BECFAEB8B8D34BFC8A7F910C6DFA4 -:10D1F000A81F5FEA4FF0FE9E802E8FE7A366BFC197 -:10D20000FAB6047471930FD0FF01DA9F88D7FC053A -:10D21000D6FB30AD57E8FD1F41787E3B90FA915E1A -:10D22000DF0BB4BE0A713ECF63F2DC7E89DE0FA352 -:10D23000836BA6FFD702BAB8B96EDCE3FAF946B23F -:10D24000CFA1DD4FA87FC530FE39AD1F7794FE67B3 -:10D25000689E68BB68FFB37AFABC0E7CFE4B3D7ECD -:10D260003F8473E4F7B4DFC97CFC378BA270FC0306 -:10D27000CD2BDEFFDD4F76553AF71623BC5A393DEC -:10D280005D837E3DB598FB6743DC3F1B96709F2610 -:10D29000DE0FE17DD2A5F3385DDD92179C5E9C1F09 -:10D2A000B36FA3F6087B781FAE376A8FE040D30DCB -:10D2B000727E9FDEDE58F82F07F7E17AAD0B79FB1F -:10D2C0008262F71A94B3E632E82345B49F585EE6CB -:10D2D0003C2C5F6D5C8CFFE33ACDF17F5DFDA2627B -:10D2E00063FE02E9AFA0B7391D80E3D7EBAC131A98 -:10D2F000A15C59CCF557D03FE2DEEBAE2C8EFA1193 -:10D300002A8B75F918278256BA1F18D553C209649B -:10D310004FC5F4A843FB8CF736BE4DE51281DFC63E -:10D32000E2C3F5629D77D23E26887D5CBD7D88DABA -:10D330007B78FB38F54DB4CE74BE4EE67AF9825553 -:10D34000170F434EB3609C17FF05E74CA96D593189 -:10D350007E23EA488FE2B542B9718FC4EFF7F7191F -:10D36000ED43CE7F2B05BD6F2E3E528FF85BF9AE9D -:10D370005CAF8DECC5BC681ED311E29FD3C21FE128 -:10D380002E81F6E9B4BE365ABF97AFEF4318BF8B74 -:10D39000C6671C3EB52C6C9B384A9E459FC03FF427 -:10D3A000BB9FFA39F9BA6A430AE9EBC126E068C0C3 -:10D3B00073FD0916D7CFF49562BBECFF15EAEF12A7 -:10D3C00076AC3FFE7DD9DDB1B8C96E6AEFE6F359A0 -:10D3D00041FE23DE02A1E30BF13B10B5E27BE3B596 -:10D3E000652A7D6FA1B6E0D252E107A1F8A68C8331 -:10D3F000973E3099E29B896509DC5E741AFF8E4581 -:10D4000070AD83BE2727BF5B2BF332AA98F1FB7266 -:10D4100071E25B067F8BF48B44BF27674D27FBD6F9 -:10D42000BE5FFCFD27D3F7E312DB18F9B71C5DFCE8 -:10D430001EB8394ED5B0A9F5B542CCFB506D149746 -:10D4400035C733CD7F0F63BE93696372281FE5F93B -:10D45000E2D4581ECA5B7BB25DC88766FBF9AD910A -:10D46000ECE73D46FB7950DACFDAF5B19F4F141B5C -:10D47000EF0FECCF0DFE84F0AC6A74BE1D29295A63 -:10D480008A7E8477441EC5D987262C417F54B88F65 -:10D49000DF573827E2FC32DE7FB690B9DCF8DCE2F9 -:10D4A00020789E5D9712C123784C5773057E5750A4 -:10D4B000DAD10879F47F558A7D9AEDEDC402C0E790 -:10D4C0002C6233B2B3CFBADD1417A8EC11DF97107A -:10D4D000F902D2CEAE14F7F8D796F17BD5E8B14376 -:10D4E0007A90DF0FAC1476B8B4C7077EC8147D1EDF -:10D4F000C052E627FAAD01C2C0E772F13DC55A3706 -:10D50000DB828BFACD8CD01FE99CDAC3E9846D579E -:10D51000E9EF5C9DED7B90CED591EE313884BF81F3 -:10D52000E4D8C40FC5CE7795E8CE8F6B386FC6515F -:10D530007B95F37117DEFF4D8D7D5742DE9BDF9E9D -:10D54000C2FD283797703F93F929BF1BF17EE5078D -:10D55000C8CFAC128447CC9ECF2EB936F9398DFA9C -:10D5600089EF56A4611C889F4BD34BB85EE01DC366 -:10D5700083B83DF6D1F300724B4689E7B2ABE711B1 -:10D58000CCC3F9CCFD2F0B7DA43937A495F0783F9F -:10D59000D1AD39DE2FDB9D44FF549CF3F673255C3F -:10D5A0007E9702895A7286DFE77FBD5D3B833ADE54 -:10D5B000C9F6727A9E52C3C998BFF59AB8CF0F8A3E -:10D5C00016E533C9BC28396E6D5DE9990BBAF3AC29 -:10D5D00072D1A39467D6E93BF8B202EB3C27F2BDC7 -:10D5E0000693BD74CE858FF3EF4B2DAFB9EDCC050F -:10D5F000DDF9615E2FE6458581D5379470BFE60B76 -:10D60000A58E81F979F8BD26CE874D7D67E93E4C20 -:10D610007D5B030BCDA0BC2915F17B6A1EFFFE428A -:10D620006581958575EB1A3B5B5B57C2FD3ECD442A -:10D63000A7B1BCC0167C5F6AD3C6E0DF9F94FE49E9 -:10D64000192F282DF915C5DD065318CD1FF4B00884 -:10D65000C6DD176AF7D88730EEE2F1927FA4A1C445 -:10D660004BEB6CEC3940EB490C5CA6F594AA00EF4F -:10D6700071C3E12DF9A25BC05BB76F82F748FC5B19 -:10D68000B9484D46F8BE86F882763D826F8EA997DE -:10D690005CEE38788FF62B2835C0DBE12937E0AD1A -:10D6A00053FBDC18DC8FC473A3A87BABC7FA2AE258 -:10D6B000F15DC023233CC6CF83388EF8BA99B17F81 -:10D6C0002FE1DF9993F8AAEFE2DFBDAEEF2AA5EFD5 -:10D6D000C5D517DC664FA33880D28FF725D796358E -:10D6E00030D4F7ED5A0A7DDF4EE26F6919E04FB78B -:10D6F0005EE0C77D253ABDF303F8D71F27BC0B3D7D -:10D70000F8C3F6FFC37C4F97C4D1CBFF52F187E13A -:10D71000DFF3E1E7EECF84DC303FE5B93B627E33F7 -:10D720005BB2A6E503AC43F20DF26D8782F9938AF2 -:10D730000DE92C88FC8BF7D70A7EB105E3A1CD1E3D -:10D74000D68F67E16EE423809BBD3CD38EFCD3B8BB -:10D750002793E802ED7F82A738A75F8E9DD367E904 -:10D760007D0BA78BBF76DC07D6F30EADA74EDC2F63 -:10D77000F888C5A56E2A0F3AE6A37F563B40F2E52E -:10D78000E83CB7944F19FCBB4DEF2F0E5AA4F1BCE7 -:10D7900031190F8D13FFF42A1F20FE698EAB8E14F2 -:10D7A0000F8D13FF34E8EB23C53F99294E6A8E7F16 -:10D7B0002EEEC9A6F8F3629F85BE532DF57E19F7AC -:10D7C0007CA5E72995BE8B345D612999C3E3A33B12 -:10D7D000857F8CA156A7DBFFA90CFEFDEBDE34276D -:10D7E000FDDD55FCC17C2C094F900F4E07CCDBB5FD -:10D7F00088E76556651E36C3D52EEC926B82AB8CDE -:10D80000AFDB7B94C866240D0F8BE6FFD97578B625 -:10D81000FBBE437864EA800BBFC7DDE81F4FF964A5 -:10D82000663C14F5F0BF4B59E49E437F9752E2BF2C -:10D83000C8333C6F5095EB8B9337F817C7A777B376 -:10D84000336B147CCA38F64878BC252FB811F946DA -:10D850007EBF49BE3F95C1E17B7E1A137FFFD4880E -:10D860004F80BF46F7FA7DECC06665383D14897C71 -:10D87000CC225FF81ECA834FACF060DC2C0ADFF4C8 -:10D88000EF127C3B5BBDDBD13E3A5E66A37C9538F4 -:10D89000F4407FDFF66AF4300CEF7D1F0C7FAB0A9B -:10D8A0001F5B9819873E3E305EAF824FBBF5504FED -:10D8B00081371E9FBED0477CEAB7BA11AF129F12C4 -:10D8C000BFC3F1C9F50B89EF53F9DA37E7E7EBF19D -:10D8D000AC3D81788EF16F98DB312CFE776F0E8B2B -:10D8E0007C1618E749ECF7D4FCE8384FE1B8D59F2F -:10D8F00088FFF74E0E9772B95BC7FA5F9C8876DF98 -:10D900000526F235FD2F7BD14FD3961D375FF3E40B -:10D91000FD0AFF3B3D1E76C022CE578BCEDE3D8BEF -:10D92000799B60DF9EC6BC4D78FE707E26EDB717F2 -:10D93000F337C7823E2EF23BEB706C9C07F4598C98 -:10D94000CB3335C4F05EFA207E9F65167E9FA5839B -:10D95000E46E2C0FE31D531E062F5705A4BC714522 -:10D9600028EF261AFFF4840CF14F363362947705C2 -:10D970002143FC53E4E948F9B6595B100A1BE29FC6 -:10D98000E534FE993AD97E47A474BA3EFE591DD1BA -:10D99000F4F1CDF01D54AE8B968354967EE8C70605 -:10D9A0001E08A11FDA3733F44BC493BC370F02486B -:10D9B000C3BF436775B90FA21D0EF601D3F247D658 -:10D9C000AB3F2ACFFF0F526BA57D00800000000007 -:10D9D0001F8B080000000000000BE53C0D7454D5BF -:10D9E00099F7CD7BF39364422621E200415F02E880 -:10D9F000D442187E020109BCF94932B62003048DD5 -:10DA000005E903722C746D1B6CA9B4AB9B81C4989F -:10DA10000485D0B2DB9F6DB72342CFB1DAB371EB8F -:10DA2000A944A41DA4555A2AC6363962976AA0296A -:10DA3000075ADBA295D5EEE929FB7DDFBD77E6CD60 -:10DA4000CB84A0D03DF674389E97FBEE77EFFDBEF9 -:10DA5000EF7EFFF73E972F54185BC0E0E74D1A1A90 -:10DA6000630361F87302B6FDA651C6D8AAC9B25DB8 -:10DA70009934A631B6B840B6AB4D6321631D2E264E -:10DA8000C6B30403F8579893DADB8DB09998C2585F -:10DA900068B92AE06334FF6B6B24FCAE6408E65B74 -:10DAA000ED10EDC4CAA4E165EC634CB697527B4D12 -:10DAB000BA1DA7F69D8CAFBF3FF5B09980F1DF99F5 -:10DAC000139F605C03EFA23D7A7CFADF1FFEA7156F -:10DAD00089CF6413FB3FE8F802BF6346154ECFF9C8 -:10DAE000FD7780EF5A928F031CDF0F207EF7103FE7 -:10DAF0009FE0F87D00F069237C7A009FC2BFFD7A29 -:10DB00002F5419BB71BDBF011DDFA47D9FC6E9B8AD -:10DB10000CF84789EE20DF077BFF84908F31EC9F64 -:10DB2000C3E77BD529E428D164A2DC9F725AF60DA5 -:10DB3000DA0BFAE57A5BF49066C57F0BE9C9EA1265 -:10DB40003EFE77A97BCD4459A60D3F03F75D8EFFBE -:10DB50003DF6678DFF3C8DEF72A6E1693D97E85772 -:10DB60000E6F237C33F42608BECF06DF28E82B3A5D -:10DB7000DC914C58F8C1120F127FD27629F130D9BE -:10DB8000A501976CEF20BDD959CEE71F7FF8E1249E -:10DB9000E20FFC3B46FC9EC2F9F78FCE8F3F184246 -:10DBA0005E029C1F520EBF33C7F823CAD9070D5F10 -:10DBB000D83F35744D46FEFF1FD62BA6F5843EBDDB -:10DBC000D7F1697D147E9F2D49F3776208DE8F0FB0 -:10DBD000EBD45FBDF1C9C8B5F0E79AE6475413E747 -:10DBE000051856CA587C9025B7C39A37B3A4CAC043 -:10DBF00087C58326F34DB3E835FB0AE1E1F23A44E9 -:10DC0000FB5B64FF562F92727D2289F145066FEF10 -:10DC10003ADCA734DEEC9B59782F3CEC7D44D01DD8 -:10DC20000C59F4E46ACFEF0F035F2CF150BA2DF8D2 -:10DC3000B3FAD35F9B847C585D21E7FD7612E779C8 -:10DC4000B558CEFB24ADBB3ABDCE0F783B5FC2FFCB -:10DC500094E033780D985978257E417197C4EBB1E3 -:10DC6000C303B45F2E5FF2817173E0D9A40413B0D3 -:10DC70001F1FDBB84D35AD7681F5E821F06F77B029 -:10DC8000749BE42A63077A68DDAB8DD7E690E08F5A -:10DC9000D0D3349E832C986056FC0EF0FDB9CAEBAD -:10DCA0005BECC23D28B7579FEF29E7B516BE4B3D49 -:10DCB00058E34BEBB7C13CC0775DCEF36373A3F77A -:10DCC000CAD705397FD86A4FAE9C8EBE5AA2E30DE3 -:10DCD000BE2F19FBF392996D7F2E1BBF4742167F13 -:10DCE000FE9EC787B2F5CC627F1E47BA5BBD252E6C -:10DCF00094EF757E662401BF8BF85B9C798E0F2BA9 -:10DD0000649FD2FA59CDC7AFDCC59A7BA60D87BFF9 -:10DD100036EC20B8D667D8C61E982FE43ADF14B781 -:10DD2000C0A542BCFF5048A127D07788F8BF95E333 -:10DD3000772CA4D37A21A6310374AA61E5A4329486 -:10DD400083D65FF2F9983FC8561466E63B2BE693FC -:10DD5000EB1C5E5ED868A5E327629D63214E07FA3F -:10DD60007FE2E77D9C0EB5E86E3FCEAF16C8FCF2B1 -:10DD700077C4D776A76827DE22BF3690B6437F24C4 -:10DD8000795FE59672F90EE9BF8CD7DF0AFD6F3235 -:10DD9000B110F167CC31CB3AEE0F6407471B37283F -:10DDA000FD459BD8AF447ABF4E21DEA38D57234A51 -:10DDB00033F1C9C3520AF80FD5EBDBDB05A4042A03 -:10DDC0008D7338FEE84CE3B797330FF0E93CEDCBA9 -:10DDD000E7B2F3114BFFDBA1AC7CE0FCDD719C07EB -:10DDE0005676C3BEBDB2462D5D0F7CFB2BEE4F15A4 -:10DDF000E507B15CF2F5D7CCBEFC359415CF470AE8 -:10DE0000AB408FD8784770AA3E7C9C37AC4839131A -:10DE1000FBA43D8274B4A7F58DB77716F3FEBCE77B -:10DE20009CEB843E1584719DA7047F99AF14D76342 -:10DE3000D38EA6D4B9E05F59FA6738A0BD1EFF8221 -:10DE4000F50722A79C28076B3B14239943EE87E92B -:10DE5000498798FFA1F4FE8D0F5F43F39A6CAEF0F3 -:10DE60001FF01BF8C4369AB7B14921FDB3EBCBE4E0 -:10DE700030E7DFE4709A4F93097F43C8EF9CF85472 -:10DE80006C032873CFCACCBF56E01D72C60F5D0B62 -:10DE900072D0DEA6E8688FD66D5DD7510E6DA639BB -:10DEA0008353E17103720AC6B5FB2BBC68075E148D -:10DEB000EBE17C2ED847F425FE1282631A3CE7C6BC -:10DEC000361FC1E1EF4E37AB909EEAF8EE0892B5EF -:10DED000A0F1C923F8BC15CC34C629DB167D3D1E44 -:10DEE00086FDEB9BEF0CA2A84174D63705F06A10B3 -:10DEF000786946FD393606B228170BA6E6A05FF70B -:10DF000006B7C3FB86A64F2C61950013770E0D7ADA -:10DF10009018935DACC079B5A1C100E7D945B07147 -:10DF2000CBB73A336DC40DFB3D99FE95D773FBB467 -:10DF30003A0CFCB4C8DD0F057D3F14FCDC0538F459 -:10DF40004DA3090A19EA0DDBE840FEAD1373F5B5E0 -:10DF5000ADFCC88700BF0B0116C4B61BE95333F4F0 -:10DF60009D9AA471FA98E15D3A0ED615FB7ABC052C -:10DF70006CDD8D306D1BD009F468EA9AA294458E51 -:10DF80008F8F315910E3B640E20106721231773BB0 -:10DF900007018FEB9BDEDC8871DF5AD3ADD7038A94 -:10DFA000776CF4D5625CBBD2147C59E23C8D747BF7 -:10DFB000E01FF2C5953AF76317F279A1C2C6C3FC18 -:10DFC000CBA2BC5FF2C5CDB4D356BE68B6F6D6932D -:10DFD000E53B7F6481FF4CB8B0F4CC87E18FD96C0E -:10DFE000F645A0130CC852C4E74287E253CB09CCD4 -:10DFF000C1804E9787EFE3FE8ECD2FA29EAEF56BCC -:10E0000041878EF831E25FA358E39D167DE78F20AC -:10E01000568D6CDDDD8D727747BFCADC00D7BE66DA -:10E020003FCE843F0FCEA709B970147CA34F0338AD -:10E03000ED8B2AC3F5241F81DFBEB9F0FEF4008CFE -:10E0400007D03BAA814FB0EEAD865BD7012E7FE1B2 -:10E050009B6DC8A77CD69C1A0BEDDBFC0E96F26478 -:10E06000E802BA13822F8E8B0AADA56B725D4756FC -:10E070003FF125FF0B11C6D076278CBE2900B75C77 -:10E08000CA6D07DFCFE506DF0FB9AF2CCAE555EE45 -:10E090004BBE4D5EDDD5CE8C7CE69057FB3E246DAD -:10E0A000FBB05FE37A72AA5FA5F8E8D49ED25BABBF -:10E0B000811F893D0ED263C8D30E2845F0474A61BF -:10E0C0001AF0FF76812FFD006E7F7371B2AB3CB307 -:10E0D0001FB7079EFFB352C938D4B88C3D6298C4AD -:10E0E00042FB36D1BAFDAB8912D4D38FB11E27EAD9 -:10E0F000F59D6CD089F2FF714C0555B48F4117BE68 -:10E100006FF4F85CC8C7FD7B9E2B443B929AE02CD1 -:10E110003E13205561563B697F2227CE48BA01380D -:10E1200025EDA7C7F4935DF6C293ECB4C1B05D5C76 -:10E130001BF59839FCC8E1D9E60B6807655BF33538 -:10E1400033C4E35BB3E33F217B29C6EB95C64FB1F4 -:10E15000FDBD59C6317C7E1BE33DF00FE7C3F7518F -:10E160005EF2EE74E338DA35BB1D3B8D764CCFC8DA -:10E17000C30A9B3C483B7602ED1874AD407D05BE5A -:10E18000B1D895D9B153520E6E6237217F809E5F10 -:10E19000931FD1801EE0CB6BB8EF331856DF52AC23 -:10E1A00084C8D47D809F22F0C3F70AD87765EB0B33 -:10E1B0007F56C6F0F6028053C4BE621A598B7EE3C6 -:10E1C0003F821ECF64B417E609A4DBCE1770CC4E95 -:10E1D000CACBFCCF9F40B971143C3BC9CCE107D3FB -:10E1E000FB7AB7F38D345DA84710C9231D0A331D90 -:10E1F00017911E1F2031FE5272912039685FAA10BC -:10E200007DEDE5AC11ED791B76CD07795FAAF4A021 -:10E21000BC3F1E29E1F1D2141E17761527FD415E81 -:10E220006721781608B295D333F33E1E5109FEA636 -:10E230003946013A2E88FB285E92F1AA84F345788C -:10E240005C3936C2E38C4065BC841C5D6990F80E75 -:10E2500071D4586A7B5349C7385117E13FDD618952 -:10E260002306262619C621F946EEB8E1BA48DAAFE8 -:10E270005F17413AF648BF6E5C8FEDC5637D0D6850 -:10E28000E75C80F7DEF28CBFFEFED2FB5558967D30 -:10E2900038524EF85537ED6E1D07FB1D0A4DF662DC -:10E2A000D894AA49FA318EE81A0F7CC8A12F5B23B3 -:10E2B000DC0FCEB94EC0097E49BFEF81F0DB09EB20 -:10E2C000609AEFC038A08CC70177462A689C8C07FB -:10E2D000003EE102B8D00D26CDD33E35F77A770A5D -:10E2E0007E66FC6DB008ED3563CDE42FE2C29FBCC5 -:10E2F000D262BC36044239D012A327D8FFBE2818F8 -:10E30000B8135AA23098837FCB6AF779D06FB706DB -:10E31000D67B0631FE3322346FE39AD06B43167BF3 -:10E32000DB55C626611C705BC32DAF0D59F4ADAF34 -:10E3300090E38B7E26E1CECCBB0AE504F03D127261 -:10E34000A7160343F3FD2CE956E8E9D4510F223A0E -:10E35000F5C78D75CCC47CBCFA9446F5AF62968641 -:10E36000DF065B13093027E215F727198ECB8736B6 -:10E37000C2C717BE49F0CBAA5596B0E009F6672D83 -:10E38000C9812D5EDA850206F3B6CF5792DB61DED6 -:10E3900006FF5DE47FB62DCAA7F7B06ED20DEF6F12 -:10E3A0009DDA447E4BC657EDD16890FCD315C65319 -:10E3B0008767C7EF41BC5CFEB45DFD1CC97FC6AE7C -:10E3C0006E8970BBFA797C2FEDC7DE23AF90FD809C -:10E3D0001C84F8DC05FCFEAF1CFBB84DE84157314E -:10E3E00097437BFFD784BCBE3B3DDE8AF31BE0D363 -:10E3F000FCB3DE7FBCD92EE34DC1C72BE50FF0E3A4 -:10E40000DF2216BB0CFCF84AA46A381FE0D786F658 -:10E410004295D6E2094543F9CF13CD479899C47187 -:10E420001ED64C40AA37CED0DF0D9F27C570DC6AC0 -:10E4300041DF7BB5C7FF09E10DB76BC61311CA0BEE -:10E44000B93C4BBB0C7AC9FDEFFBB4DBFD0EB0A7AA -:10E45000804F07BE9A9FE93F24F6B9B7CA3C84EBC8 -:10E46000DE50E65987FC7F5031FC5E15EB9E66233B -:10E47000DA11A6CFCA1A377C9D6D34CF4085B91109 -:10E48000F59AE92B4681DF2ED6D5B9BFD0391DB01C -:10E49000EE57F32767DAA3D1F5FD88F173C4BBD536 -:10E4A0008CFF0AF5EEA580434F28F4243DECAACE5C -:10E4B0004B2AD02E9865BECAF711EC284CDD157892 -:10E4C0008BE2A2654B148AD396792083CB6127CF48 -:10E4D000087FB34CE7FDECA4E1B7D63B8AA38EECF2 -:10E4E000BC1744C2B0D62FA28EF5589797FE0CEBFE -:10E4F00026B9F4EDBCD027D5FD6619DAD5979CB9BD -:10E50000EDF65B1117C12951519710FE6F959BE7EE -:10E5100057EC67809FC5BFF65685FF47D8AF84622A -:10E52000F18B0313CF93BDA31ECBFB65A2EEC4FA00 -:10E53000B3E79174964459D6BA20AF8E28AF63A83A -:10E54000514BFF2A95F1BA475F36BF001F4F94E247 -:10E550003F3634023EFB72E273221B9F9228DF9704 -:10E56000DE2AA304E703FF3C16D7EF0883FCE5E0AF -:10E57000EF1333C2D762BFC6121D15E5978C5BAF90 -:10E580004338D9B6C4AD7A34DBBE9647B97DAD8881 -:10E59000927DCDBD6EA5E0DB95DA87F7ABF73B6CDE -:10E5A000FA2E9F5D834F1554021E6E77E2B3A4AF1F -:10E5B000D32E4FBF3F7E5DDF44A4F390904FB4ED68 -:10E5C000186F183A8F473E1DE5721CBA214970CF6B -:10E5D0008C107FA4E1803158971B290E99FF3EE3F0 -:10E5E00090AE850305384FEBDB7B0B308F7F6628C1 -:10E5F0009C330E3954D64D78DAE390DE11E290BBAD -:10E60000A23C5E3DF21B17C5153567B99FAF39DBDC -:10E61000ADEA209F7747B9DD9E3FD4A79A202735E2 -:10E620001887C03CBD220E41F86D20BA91B7BB558A -:10E63000C46BFED93E1A57036D8C43E68F108700DA -:10E64000162ACADD819AAE5FE0BED9E97DA1D2DC8F -:10E6500012B5E45BD5837D744E22C77505B6179855 -:10E66000B4CFD972737836B7BF99715CDEED702381 -:10E67000C957ADEA0D607DA093E507910FEFE48DDA -:10E68000A964453CAFC1B8B8134181EECE9305C92A -:10E6900004E6D51EDE7F6FFE98BDF894F6C723F41E -:10E6A000E29DBCEB92220F328A60FCBDAA915A0C0B -:10E6B000FEA073CA977C9C9ECDA4475B046FC2BB2F -:10E6C00035CAA76FF6F37D90F1D78BAB148A0F6133 -:10E6D0009A254B017E9E98DF3587E78775AA97E0DC -:10E6E0007604781C7973E23CD52FE60FBA741DDAF4 -:10E6F000F306EFE2F9A2FAECD1028CF73FAC311548 -:10E70000DEAF6A8BB7927C9E74513DC3807FA89F19 -:10E7100055FD3DC4B7822157569D231F2C59CA125F -:10E72000B7B86C6DA6AE29CA6587E4D35E87783228 -:10E730002AF2CF4A36E322F0E502BBAF0369734FFA -:10E740000D1F79940D1F2FEB0B9B66184FA37C4C6C -:10E75000710E7EF769E057EF1B2EAA5BF4EED9F33A -:10E76000D14AA02FD1AD515D57E6334059C972CC83 -:10E7700067910754973EBE1EE5F260A16C8341038A -:10E78000BC0FA6CFEB37AD372CED63D1074EA3DF1F -:10E790003B788D843FC7C7CB7662703DDED7383873 -:10E7A0009EB72F44D54713B4BF831AE5D15B7FEDE5 -:10E7B000CD651F8FD772FD92ED5BAB3773791D6509 -:10E7C0001CD8F557ADFA21C7E52D35774C077E1CCF -:10E7D0001C72D0F910E459298C0F36CD305F47F800 -:10E7E000074F70BE1E7CE31E1FEE937BECE0E772CA -:10E7F000D9F9DF0B7F94CEF36672FB016E4E43BFF7 -:10E80000B56BD133C72A619DE3F3A7CE528104E0F3 -:10E810008507E36539DE5D5B91A587B756BFACAE72 -:10E8200047FBF3C6E9865CFA5E1535FF944D0F3F52 -:10E83000176DEDD688FF25CFD7EFC57B3FA99AEEA0 -:10E840003E0DF6B7F7F70E86794AEF7491878F84FD -:10E850005710F02AB92CBCF6CCCB216F8097ABF6C1 -:10E860009AE178BD54CB883F2F541A9EDAAAE178FA -:10E870003251C75C20EC7DDEB92F51DDB177D0413C -:10E88000C5930B437B55143D59FFEE3A518111104E -:10E890005BBCE4948A2265DEA766E9DDBC13F95906 -:10E8A000ED3B9BC766B5576F9C98D143F86F457495 -:10E8B0007256DBEDBF29AB1D62B3B3DA0D4B6ECEE2 -:10E8C0009AAFD617C96AD7FB3F9A057F8BBE32AB8A -:10E8D000FDD1C0EA2CF8A5C10D59FD35BEDD0F6094 -:10E8E000F9283E6DA63696913CCE44BE16F41B2404 -:10E8F0008F0F9EB8C7877291AA894F42791B28EC67 -:10E900002BC3FAF58BCEDCF9DA7DB5AAF4DF65E826 -:10E91000EF0DC6F335091FAA18CCAACB6FA8E5FEE8 -:10E92000796DAD92B34E60F7C7D20F4BBF6C5FDF0E -:10E93000EE77EDFE76D987F67A78BD9FFBFD5542DE -:10E940000E5A033FF762BEFE6203AF237495C5A95A -:10E950006E3020FCF39155B74FC273B5FC8039D6A9 -:10E960005D9EF1D7914092FD1AEB3CBE249B3C1D6D -:10E97000FB936CC374AA4B6B9169FCFD0DE2FD5DCA -:10E98000F8043F5D67E19BDDFF863C337F5CC4326A -:10E99000F14AC3BB46B408F0FB48D3935A293C2341 -:10E9A000DEC39AD50E1DAFF96DE9087EFA93B53630 -:10E9B0007DC271BD432B2EE9075E6FE175F7EFB79E -:10E9C00078580AE83BD9E2A3E72F5BFCF4FEE51692 -:10E9D0009D9EED2D017AA65A82D4FF8B966A7AFE0F -:10E9E000A8C5A0E7F32D317A1E6D8913DC4F5B1AA1 -:10E9F000E9F9B31693DEEF147AFA41C1C708C8BA31 -:10EA000042FC884321BE36E055DD05670DD56AE737 -:10EA100081AFFF9A8BAFEFD79FA46A7A26A29C8121 -:10EA2000BFCAA94F3DB532AE4FEF37E125E361CC08 -:10EA30005F504E649D0EF07B0CF173637DAEE4CAB3 -:10EA4000F13BA870BC0E16F3FA0DCEB3BC10EDF975 -:10EA5000D7E361B2E7D7CC247BEE675AB63D2F1FD0 -:10EA600066CFD791DEB1A35827C5FA229D53D8EAC5 -:10EA70002045753A8D93759045EFF23AC868F403D6 -:10EA8000DD47D16E49BB7DB974DBE93D3CDB7809DC -:10EA9000E791FE7998FF30EF26FF512D7496696F4C -:10EAA000539C5820E8D9757A4511DA173722C8F3F4 -:10EAB000748355E33E33791F60EFC6B2E1F3BE5E67 -:10EAC000D343FE7C473ACE7993E298E1FE2B9B0F2D -:10EAD000180B59FD3BF0E15CB65FE47CA8559F1D27 -:10EAE000DC0EFEF9E020E375B239FCBC4EFAC183BE -:10EAF00067791DE382A624196C5D983577CF83E78B -:10EB000081FB59691CCF9B263982FB01B4E0B95EB9 -:10EB1000DD0370A141736C1EF457A7F2685C78C9DD -:10EB2000CC24B61BE26F927D0A6BD97E1223D4B43B -:10EB3000DFA1225889AD3D2103AFE2FE5664DA30F1 -:10EB4000EF27669B5A1DD0B5E27C33D3617E7719DF -:10EB500073D2FD90E1FEFD6EC55267D358B003E954 -:10EB6000D0BEB0839FEBD9E44DF249D6DB641EFEE4 -:10EB700008337C7539E2873671EE623F6F796BBA84 -:10EB8000E94778C5F73C9DB7B08D8CDF8F70407E2C -:10EB900082FC1BE34AEE2F1F2E77DF9B75CBA43A36 -:10EBA000AA532494AB93B7772B94B78BBC89E99F76 -:10EBB0007158F3189937D9F3A387849DDD897616A8 -:10EBC0009E0F3919E55BED4A7E70AF92C997C06F11 -:10EBD000CE40BA16D589F317D63C8F9FD3DD9F95CB -:10EBE0002F8D88B7C84B9CE97D2FF39D29C8ECBBBE -:10EBF000D7D5EDC77B8E9D33BFD1B81EF936D34331 -:10EC0000E79C4C4BE96877ECF4305F8295CECDEC15 -:10EC1000B7CAB433589FED806006CF7B1FC62F0163 -:10EC200060BEC2A0232BEE29AACE8EDB6EAF9376F8 -:10EC3000F6EAD0810240E7DB124F1617E7993CFE57 -:10EC4000F488F76D3AB7170CED9DE57CBDCD6B7878 -:10EC50007C96FD7F10F7C73D323E6A799B0FEBE053 -:10EC6000DD5E07E97787AE759643BBC3ABF1F84627 -:10EC700077C4729D43EDAA5304DD1C2F9FC04B0D3A -:10EC8000ADA03868A4F5BA84BCC876FE34D3207D24 -:10EC9000D48371CC935BBDA50AD64765FFA63A45E0 -:10ECA000C84B37F1A153C455F9819E9403E56CFC20 -:10ECB0005DB3916D1E8893CEC07BCFB41E8AABBC72 -:10ECC000135C662EBCBF2CE6EB74066394F7173A10 -:10ECD00018E6FD9DE5B9FDE83FD7F138B3559F151E -:10ECE00047F804F065AA321CEE53420E1E70821CD7 -:10ECF000C2FA9D536FA37B629D9318D9EF8AFAE9FC -:10ED00008F6EF3E69043FD33B47F4E1F93E7EF59C8 -:10ED1000F7255AF586C675B0AEF6320BA2CDB0EB2C -:10ED20009B73FC8AC67578DFA23A3F88F0B5EACFBC -:10ED300012C8C7F620A37A8756DCE441BC1F2CD347 -:10ED4000E87E449AAF33CCC7D07E8C26DF767C60D9 -:10ED50003D92BB91F6D78E1F85F2B32E015F6C36C4 -:10ED6000C673CCF7CBB45E65CB977314F91A8D9E3E -:10ED70002CFF5A96F1AF3FA9DBBC01EFA93DCC783F -:10ED8000FFB1BA30E5FBF6F6D5D2F356ADBB11F7BD -:10ED9000A5758A8BE4CF3EBEB39CE3D5F57C8D5838 -:10EDA000D7A7A0FCEFAC2EC943FBEE45436DE16B4A -:10EDB000AAD23C5567F1DFC5D1661EB7D731925F45 -:10EDC000AF1EF74D01B9F0F6AB2053C077C75FDE39 -:10EDD0003DA5BF7F3EB26E83E4964C3B975BF61732 -:10EDE000E04B9110EB31ECA13E7E5F640BC1497E9C -:10EDF000EDBAFE0FC1D425F8366661767DEABDD640 -:10EE00009F94FAC252E2731ECB433E5F60F729E43F -:10EE1000BFA306E99D2F6D57F9BD9552D90472B075 -:10EE20004D22A764EA520CCF3D50BF4C46F10D4134 -:10EE30008E13475E44B78FC64D14D34CC00B352A92 -:10EE4000CA3FB7BB17D81B7C7D1886F756948483BE -:10EE5000FCECF528D70057CECC3F9FCA719F679234 -:10EE6000AFE9C90DF09C582FEA69829ED1F821F1D3 -:10EE7000FE5BC9AD8C0FEC755459677D1AEBACCABB -:10EE8000E87554A69D27BEC9F8D75E5705BF5680C2 -:10EE90007C7FE7068D7511DF79BC90C9F34D8FF546 -:10EEA000FE9DF497EDBE1559F5F97923D0FBD428D2 -:10EEB0007EB1AB1FEC26C6D1FEED549F3F7072FDB4 -:10EEC00051CCE32FF85D3AB3D8FFF6C2ECF3033927 -:10EED000EFF67A51871F5FC770BCD66732BCB7E7C1 -:10EEE000F207C92FB42AB9CF1DBAEA1DE2BCD1E698 -:10EEF000276CE733FF9DE74DBA2A58DA7FA8C23E58 -:10EF00004BFFCA34F0A2E3ACE3B91D95FC3820E214 -:10EF1000D1AEE736D13D03E6B7D47D2B72AC6F8F0F -:10EF20001B0D43F7CDCDC4B1CA208F5FE5FAED22AA -:10EF3000EF6E3DC9F7235FDC37B2D30BF1EF17EB70 -:10EF400081DE8280C356DFCAB637F678D8ED618994 -:10EF50007C8BFD8378B8A59EE284EC7876428CF1B8 -:10EF60007B41C526C3FA4FC46FAA58AF99DBDFAC0B -:10EF700032A07BDEC94BEF47633D8F17DA03EBE32B -:10EF80009837C9FAF3AE451F21FB0A7EB4BBDE6297 -:10EF900077E57D87F75A8F92F23A57EC637A7DFBDB -:10EFA000BD94855BF8B9D1C97B8EA13C1E00794424 -:10EFB0003FDF5E98D8311DE3939755B65F1F5EBF64 -:10EFC000B2D325EB506363FCDE8ACBDF7E64B1C332 -:10EFD000C29FC1665527FE180CCF8934714E64AFAD -:10EFE0003BB9DD4633FAEF548DD168AD3B4BBE35AE -:10EFF0000A797EBDA699CEB19E1EE1DC58C2E1E73A -:10F00000659887CB3A56D90CF359E4EFDCD86615EE -:10F01000CD48757C33DDBF2CF81746F923CB5792CA -:10F02000FB61A9E7163D43F9E59FFC8CEA6C2ECC09 -:10F030002F4B319FE4F9A5CC5BA59DA8559FE8A86F -:10F04000C07B1DFD1ADDD32B786E9307E3DE50FFE6 -:10F0500006CAF10C655501EEA3BCB724F1BCD2FC85 -:10F06000B40AF353CBF94AC66EC47E8572D0D5126A -:10F07000FF5514E4A3B7C5A0767B4B233DABB4A4E6 -:10F0800081F4540528E3630B86A0DF8247555F2C8B -:10F09000ABDD5569FE86EB553CEBBDDB0FF359E468 -:10F0A00002F2E3730837F724E7A76B8942F711965A -:10F0B0000DB207B86EFFC3D8A182D8D5B143BED870 -:10F0C00025ED103F67750D8A73569BBE3D5EAF936D -:10F0D0001EA4F50ECF5BC9CF25683C9D19CE077ADB -:10F0E000C67C92DBADCCBD0EFA9E3124BEB3BEF120 -:10F0F00068CD3E8C67DB5F95FDCBF719967E9688D1 -:10F100003661EDEF3026C71067761E2D6DA2EFB089 -:10F11000C5773491C6E2B20196B9EF68E7D74331BB -:10F1200047D67D9A10E3F534D9BF3926F24320073C -:10F13000EB76F2BE443EDE97C811BFFF9398EF5EB8 -:10F14000E453157E1FC2EF2B2CB67D1F62C42EFD2B -:10F150007D4842F48FF63DC81D319E5F98623DFCAC -:10F16000FE3F86F8C6F97718EBC57E2DE84FB68EC0 -:10F17000C120D1CF72CE138F713FFF428CDF7771E8 -:10F18000F90D0DF705E65B4172D0C8EF67CAFE05C1 -:10F1900067D3FDB7D17A0DBC7FC15993EA48F2BB62 -:10F1A000BC78ECC67DDBB4CCBD9C76AC4778F1FB7B -:10F1B000147EDFE9DF059DF6A7FC3EE5369FB8DF4C -:10F1C000C326EFC3DA66ABC1BFC7BC2576D35042B6 -:10F1D000A3F5EFA2F5C5F738D5825E78BF89DEDBEF -:10F1E000FEBF024DB1B27DE23B9E4F115DCD1CEFE3 -:10F1F000F4FF2721319BE44BC257C7663509F8CF8E -:10F2000012FC460E9F431E843C56119E9731DFFD33 -:10F2100084DF1A8EDF87627AD6F75F526E016E3B0B -:10F22000C189EF83FAE31B3C68CFD3DFFD27A6ED4E -:10F2300033A65C169F76D03CA65C8FF3497573BDF0 -:10F2400090F22FE5E1BB621F66C61429575FA6F155 -:10F250004D578DFE6F123F6DDF238D4647A032BEA6 -:10F260008FF0F0A7EF23EF8FE5D6CFF7848FFC7EEA -:10F27000CCAE17CF0AFA61DDEFD13A6541BA9704F7 -:10F28000EB3E7535D685797F407CF0A4E7FD21B54E -:10F29000AF705E56567A59F74AFE0FED913B6F609C -:10F2A00046000000000000001F8B08000000000066 -:10F2B000000B93E46660F8510FC181486C62F11A4B -:10F2C0007606866816068699AC0C0C15402CC74944 -:10F2D0009AFEE540FD8B80782E10CF00E2C940DC1D -:10F2E00007C49D40DC02C49240F34480981F88B953 -:10F2F000809815881980F8370703C3370E8439378B -:10F3000080620F48B41B84AD7810EC3340FF6F046B -:10F31000E2AB6484C3281E1E389D9F81A15A00C1A0 -:10F3200017104495CFE047B0B94429B34B1AA81F32 -:10F3300000656D40B4800300000000000000000084 -:10F340001F8B080000000000000BE57D0B7854D5F2 -:10F35000B5F03A8F79666672124298842027103091 -:10F36000680A4380088AF51022624BED48A9622F93 -:10F37000B5038D80104854ACDC4ABF0C4C8020286B -:10F38000415141910E0816156D44AC58D13B20B542 -:10F39000B4B56D6CB9D55AED0DB5AD2F0C8852FDD5 -:10F3A000FBEBE5EEB5F63E9973CECC24E0EBB7F778 -:10F3B0000F9FEEECB35F6BAFD75E7BEDB577DCB242 -:10F3C0000B0A07029CC49F0B006E7103C098743A2D -:10F3D000F2C66FCC7F6834FBFDFFBA23DBF5743DCA -:10F3E000331D0812D50330008A012EF0B25F59BDDB -:10F3F000893F3FF2A7114500FB40010FFB945227C4 -:10F40000F6F91AEB67DF8710C172F9E781B2CE0017 -:10F41000B68B53BB2F036F972AD7CBB42ACC808CE3 -:10F42000DF0D2FFDCEFA19BCA989B53FF14180DA75 -:10F430003BE13053F850869468737210F6ABBED738 -:10F440005929F2E5C00607016F1D404D1ADE03AFD2 -:10F45000BC46F0EE5719BC7A96F1BD0CFEA234FC06 -:10F46000FBE01BF950C5E1376AD2F09F2E3C34FF18 -:10F47000BE002B9BF5272B5C003737C39315430049 -:10F4800056377B29BFBC59A37CA2394CF9952A6B0E -:10F49000C2F0B0721B24E3AC7D6834AB6FF6C7FEDC -:10F4A0000B54796D7977116BEF4DE7D540D896F70E -:10F4B00096E9B63C03E75098CDFB2C319FE5CD0C87 -:10F4C000071E1CDF0BC69958FE6DC28B4FE02D1135 -:10F4D0001C7AF9208697D6E715466900976E4C4747 -:10F4E000F82A026E3DC958E3ACC0EC29309C8D1B54 -:10F4F0008A01B07A89DB016E65700F0B4C7A03428A -:10F5000000F7B1FE5B59FF4AA8F5450F2B5F55EE9A -:10F51000D615C4CB0EF52F9D6C0C2FFB87783B7353 -:10F5200003CFA7E7C5F296790E034B396BFFCB8269 -:10F530003B5E94181C890AB7EE91D2E374D3A59769 -:10F54000FE87B4D9F3CEFE2B74A316F9D4EC77085A -:10F55000449769812F6EBF6731DCF6294CF76B8EBB -:10F56000D36BBF8CFC51D676C80648A6CA33C7A950 -:10F57000D02393E3ACBC62830AC972FEBD88C94341 -:10F5800005FF155696D5FA635599F080759C41692B -:10F59000BA54E8EE9932E38B8A8ACBE64B8C6FA0A3 -:10F5A000CD42E7419C41515ED6366BC48F37375709 -:10F5B00052BAAD596B27F9F94899DE5E9529877FD4 -:10F5C000453DC5DADDE202E2C3F876486E97B0BF8A -:10F5D000E8F4992CBF666471F54D3AE6A7CBA817FD -:10F5E0004CFE5E23E9C4DF71C6DFA8FF9CF271B355 -:10F5F000CBF80AF6B76AA42C2D433C57707EAF7047 -:10F60000A5BC83B1DFB64123E3D84FE4779D58AF63 -:10F6100062C8505D61E30EABE0FCFFCB31777851FF -:10F620000F76CF7F71717BC528807C071F68A7C8C4 -:10F6300007DAF89EF9C01CE7D39687CF8EBFDA7A37 -:10F64000E4AF35915BDF40BDB1AD82EB0D275C25AA -:10F650000353E1682093DF2A2A189F219D223DF35E -:10F660009933BDBD3909AF321EBAAD394C7CB7AE46 -:10F6700059A774B5E04317F25409CB0B3E84A2D1CD -:10F6800094CFB95EC1525A8FFA4E4B428CC1791B4E -:10F69000F2E7B9F87DB96194B1E695661E5232D3AE -:10F6A000FDEBB0BC94F20694217F9AE58FC40DD691 -:10F6B000BE50D49F243D124F3024DDE6E3F9C952F9 -:10F6C00097112FB3B65F6D18E3D3F5593E555B61C3 -:10F6D000ED8FF55F6585E719AA6FF6572F1D36E2A6 -:10F6E0002CBFCEC7FB6B955EFC5CFABF496A0BE38F -:10F6F00042B3CAD1CF4D663EDE661855E971CA974E -:10F700003E6CC4ADE5F0B0ADBC66695B3CCEF07656 -:10F710002744074B8CBE2553A26160F4F7459371D3 -:10F720005C6AD3F0717CA7E77707C1EBAFE0E555E2 -:10F73000D2EF8D84853E13A4DFC4117ED3BE510465 -:10F74000BFCA3F2FBBEE39C6AF4ABE3B4276461119 -:10F75000CB8C63E34D8B81CEE090C331407DA084A0 -:10F76000D5BF5BE5C0E43F06E75882B32E3A3D07BC -:10F770009C712B9C261CBDC16DC2919B4FF9F84E0C -:10F780007EAABD64EC6FC73316F775B82268E7F53B -:10F79000413C313D001FDE66B8D8F73E5319EE7587 -:10F7A000A2DB74189CD96FD19452485AD6F14F9B62 -:10F7B000AE83313F86F0F61D694C9ABE2C3FD38A4A -:10F7C000C7B1A29E93FFCCF9B933E6F75DDBFC40ED -:10F7D0006D0B4783BDCF6F9D2F323D1AC8ACF74BE1 -:10F7E00089DBD1B593C67E1DF878E061FAAB00C71E -:10F7F000AB4E8F57F015361E76A626B38E5758C7D8 -:10F80000C6F37E76F874CAA309AF2F03DEDB6CF073 -:10F81000DEE462729B85FE9F35BCA72A7F7EA67FB1 -:10F8200049FE2A7B96BF4FBBBF02FC95F1D3BB2A92 -:10F83000A42E60F85A74A1371997D27AEEF3C657FE -:10F840001F2C62F45BF4EB51872F9031C3F8FA4B15 -:10F85000E9F1174A3AC19D8BBF73CD072069EBE7E9 -:10F86000FFD57C72E1F5B3D643A7AA5F97FDC14FE0 -:10F87000FBBBE5159044795A7EF042DA672E7F6E25 -:10F88000623F60FDB85ACF06834DAA40D819CBD14C -:10F89000CEC0FEEB4ECDCEB8A919DA5B98D1F558A3 -:10F8A000284A76D17209A8FD1A66B72599FD32FA61 -:10F8B000F96DDE9901B2AB285DEE02B263463F7F7F -:10F8C000409BC8A6E01F523812797FB9CFFC7E68F2 -:10F8D00032DAB9AB2BD877C61ACB83BC3FF63D8A58 -:10F8E000F5F386F0EFB9E0CAAB64F058F0EE732799 -:10F8F00063D9F4E3976599F0B351D85D37A3DDC5BB -:10F9000014B2CFDF1643BBDA5FECD6B74A99EDA647 -:10F91000CBDCEE5F3FE427717469AC42FB8DCD7F99 -:10F92000FFA5F7416715AE836D868CED23DC35B0FE -:10F93000D1B1DE07D086A375332C4D646BA6DF9161 -:10F94000BFD9AC1FD727A0BD16AAE4E513969D3FEB -:10F9500021612D87111370DD35CBAF5C3686CA4B24 -:10F96000BCD117C7B3F14B98FE4C303C95A86D52F3 -:10F9700013D1333BBFACBFCA3B3DC960587FE91DC3 -:10F98000E55765C113A322D1D9CC97D6DBE56BA38C -:10F99000C0DBCD028F6194718B5EF3F1AADD7ACD6D -:10F9A0007726D76BFECAB6A588E7D27A88A09DBD18 -:10F9B0009EE12F6619DF5769D76F25AA7D5E9FD517 -:10F9C0007CEE04E30AB96FEEFE9DF27527C4666211 -:10F9D000FD12B18EFB2B9352ACAAF7F93BE79B6B60 -:10F9E000DE5F15F864E32CCC36CEE7859792001BDA -:10F9F00067F4A73F8EBFDEAE274F15EFD0B0CDC066 -:10FA00007D359A9AB86FF6415D2445FBB91BC90F45 -:10FA100077BD801D621B35B46B120059F5995AE110 -:10FA20004EFBD3F07FCA8CFC6C7431D3C52FBF530F -:10FA300070C0523F29078BFE9EC77E3907CE39A979 -:10FA4000A4DB83F0F7A9261C8142DBBCDE6F3E56A7 -:10FA50007000FD72DAD47CE861BCED4C8FA6987C16 -:10FA6000DDDBEC851493AF2DCD1AE57FC8E40DD313 -:10FA70007B98FC617A37DB2F62F9C6E608E5EF6C0C -:10FA80001E4BE9EDCD067DBFAD7932E5D73547296F -:10FA9000BFB6793AE5BBF1F9211BAF46F02B9BC706 -:10FAA000908A645C463FED6888303061257EB7C03F -:10FAB0007FB33CE16919FD9ED37DE4DF0808FF8632 -:10FAC0009FD17730B63BA4C076C83DAF04CE8BC182 -:10FAD000F11545E6FE53B592E4C56FCACB7A20BF57 -:10FAE0008A2FC2D62DA672D582BA42E4775F847F70 -:10FAF0000F54AA4974C1048160C40D7C727B39958E -:10FB0000A77CC3A90B15FB1B21F8A3352053BD35DA -:10FB10003B787F4E3E1951BD4B6614036F50E5F59F -:10FB2000927CBDAC1A752B7D6FD5641A77CD06DE3D -:10FB3000DE57C9F8C6C2B7616510CD6367E8406992 -:10FB4000391BEFC7C1FD8306B3741DDBDAE0FA751C -:10FB5000EF9AAD85332D7E24AFC2EDF360DDD6A9DB -:10FB600015AC1E1BD6C0719535FEE4D672A28782F5 -:10FB7000F09DE5E3F007BD7CDE4A0324715D32CBE6 -:10FB8000CF2EE03004B58811ADB27C178A27A827A4 -:10FB900097F9B15D2B44B6EAE9F24AB39D616F571C -:10FBA00069B68BB7EFA7764B583B48970F2B10F0F1 -:10FBB000C0485BBB61269CB04CA676717BBBA1A202 -:10FBC0009D39FF61DB3A24AB9C0DDDD02971B9B1C1 -:10FBD000D32517FF8C0021B7FBE3D249C4473BCFA5 -:10FBE0004B92B7F52423D5D93BEC723D2CE990F329 -:10FBF0000D6E9B1F3D8AB2CBE8B156D06B53537646 -:10FC00007AAD558F1D44FB44D9A1DAF069D269ADB4 -:10FC100057D0B1C94E47934E6B3541C7A8838E026A -:10FC2000EF6B4D7ACDC84EAFB539E8B5D6A457CCF9 -:10FC3000DECEA4D7DA1CF45A6BD26B5A767A39E945 -:10FC4000316C5B8CD69D34DD2294FFACE8E1D40BA3 -:10FC5000CFC93A7D97D71BDA04D40FF52ADF275591 -:10FC6000A600F7035056D88BDD1A17F64913E0BAF1 -:10FC7000700BFE6AB1CBEF75F3FC9589C313D00E00 -:10FC80000F75DBE1FB27A03F6C9328BF2E7182CA62 -:10FC90001F97A33185FA4BF2F11DF8F24493B0811E -:10FCA0008154AE6A175730BE285F2347E21639F0F9 -:10FCB00080892710E737A7C6FF005CFF2078270759 -:10FCC0009F129CD72B84CF24CD3B034EB6BFDCC004 -:10FCD000F635A582BF4B9B189CF0E9C309F57CBDA6 -:10FCE000E85E9F859DE482ECFD54AC916D7A765080 -:10FCF0008BDF96D79714DAF2672C2AB5F15559C3E2 -:10FD0000205BBEB4FE2C5B3E3CA3DA962F9E76AE03 -:10FD1000ADBFA229B5B6F20C7E11F96DCA4B4B6D81 -:10FD2000FC121F5A8BFBB64DA27C4762682DEEDB9E -:10FD30007A2BFFFA55AAE165F8578BDCB4FE300A3E -:10FD4000127E4C7CE56B1077A3BC16059217B1723E -:10FD5000BF66C4C91FA019807684ACC528EF0ADB32 -:10FD6000D7A7AFA1A1C4F8F4EBEB54E8A57FE3E378 -:10FD7000F4DFDBBC9CFC62AEEF4A115F4FD7B1ED04 -:10FD80009284E7224C3FE23AEE62668E2F847C2119 -:10FD9000F887F133EA154D9584FC9E9E9C0D6CB559 -:10FDA000EB9B01717BBEFF62FB7C4E95BF3F2FF941 -:10FDB000ED0D7F6B2112574E017F115512E7D5A72C -:10FDC00027FFE11976FC144F733BE4C4A1CF3F67D2 -:10FDD000FCB598EB0568B5B8FE065AB80FE5DE35F8 -:10FDE000FBB55816FC99FCB2AEAEDA6FB543206293 -:10FDF00099D7A0F4389457B2E5BF687C929C40F63E -:10FE0000F15C36FF72B46372CC5FD07BEDF8FDBE5F -:10FE10007FA5F9A7E9FC83D36A1FEE86B74CA3FD43 -:10FE20009A9977ECCB32DBC7B9BE89F964AB9E6493 -:10FE30003F952AE3B310F82388E7F77DA1E190CF3F -:10FE4000F6875E9E7ED6FBB67BEBF87E26FE725E64 -:10FE50007208E253C471DCF2F2979244F7F132DC9B -:10FE600081E5553295DFE00F6D45B8BEA9C46E50EF -:10FE7000FB22BC6724F1BC18D44E6DEA972CF31416 -:10FE8000769139FF5CF6D1B296EBECEB194CABB541 -:10FE9000F2E39D2D2BA99CD91D2D2AD1EB8B621F3E -:10FEA000E58473A3FA05B68FCCF30167FB7F15FBDE -:10FEB000E8A0DAB0CC6E1FEDE17410E5CFB5ECA987 -:10FEC0003D9572D33EF207DC621FEFB05F2A997D49 -:10FED00084E7470161BF5426C95EF15526B9FD523A -:10FEE00069DA33F6F5EA1A3440C7A4EDA31EFA37EF -:10FEF0003E4EFFBDCD2BD7FAEE0B98F6511BB78FB8 -:10FF000018EE31CE44A9E47E0EC5B1BE8F76E55819 -:10FF1000DFFFD7D847D9E5B737FCAD85366E1FF57B -:10FF200082BF69B9F0F72F6E1FED50E1FF33FB2858 -:10FF3000179FFCEFB68FD274FE74EC1CA75D63DADA -:10FF4000119FB57D63DA27CC8EA954516E999D859A -:10FF500076CCFB72BBF70E369F1B944E2F2E8AB7C2 -:10FF60000A795DAC46D7B968FDEE247FFF06D4E779 -:10FF70007D859EC5F601119FA74600ED9DC56A6C63 -:10FF800083CB720EA1043AB558E08B870766E7D998 -:10FF9000E72FF062E261B7AB40D0BBE99C289FD766 -:10FFA000A38407E8E4768CDAE9C5F449B1BEDD9BA9 -:10FFB000810F20BB5119AB27511FB0F64FBAFADAA7 -:10FFC000F0E2B5E185AD437C3C50A236BB91A7FE83 -:10FFD000D19A84FE7296ED40FEA5F3721DFDC26DAE -:10FFE000938732F8FBC4565C83F198C1972F7E0348 -:10FFF000E31AFB74CEA4F8C696AAEA83B5AC5E7E7B -:020000022000DC -:1000000044BB74928EEB2A905F71157646EB2624E2 -:100010002604C4394E29C06F969F10EBA60176BB0B -:100020005CD655D39F3428B7BCB01FE9A427B37D55 -:100030002EF97059E59AE4F3DA53934FA1F7E3EC04 -:100040001FEA8B02473FF9867D5D088225CFCA3FB4 -:10005000107CCC2C94CF653C0D6EF5EA8C3F5C1582 -:10006000B286F191F9A01520FFF9EB5448A1FFA544 -:10007000E8581C5DB0BDD1A505FDE87C3F0A975A44 -:10008000F613413797D7F0AC96F215ACDF13A3798E -:10009000FC7D1F8DFD579D399FD542BEBAF3555B40 -:1000A000E9DC34C1F86910DFDFD03D825515BB347F -:1000B000AB9E1EE1966CF7082CFB365DAD11F63455 -:1000C000C38F52211B68077C52FE503E267FE44DB1 -:1000D000B1DB09A74BAFF1E25EC5A9F2C7271DCF7F -:1000E000A46BA65C2D1574ADF7A2DDBF223CB5C78D -:1000F00073D44CBADE4A74F5578091CCD2FF04B762 -:1001000094357ED6B93F72DAEB4ABF9AE95B7AA2A0 -:100110005B91D3AEE5FDFA162BFA5F5179A91AADC2 -:10012000035ED1DF2AFDD638EACF13A813193E9417 -:10013000B6912971FE18D9CEAB50FC874F37489F36 -:10014000D279774D1A3E77997DBFA616F9ED76E103 -:10015000F4B86485DFB7D84D7078713CD4D31AD029 -:10016000B9A71AE0FEBD8CFDA3C36E5859569D3544 -:10017000CE40FDB4F6ABD3ECF09E72BB80AAFFDD9F -:100180006C93454FA7DBA9F0778B3DB506F9DD42AF -:10019000FF152ED823B1753811BE0C623ACB6351CE -:1001A00009402BA6E3900FABB97DB743A2F36012D1 -:1001B000691DFFE3E74457B875EA47F6C6084F4A9A -:1001C000C000AAAF9FDA39D2FB0378DCD220096CD9 -:1001D000F51F74BBA95C8528609CE2FBAF5C14A68C -:1001E0007E0DF6A9260D87B3DF2BDCB107DDD84ED7 -:1001F000E3F060035AC7C772BF40D8CBDBBD3F7383 -:100200002AC571E5826F43333F5FEFCE8BB82C6810 -:100210003DB5B8AEF7D9981D55C4FF7EDCD7421B5B -:10022000B787060A9A6D595248DFB7B4F42CE777BE -:100230000939DF8CF69187EE55D8E47E9B8837DB51 -:100240002E81ED9EC5100F8FCF7A4BC8FD166FDC47 -:1002500047F7159E59E51B8AF12E8794888FE1A1F7 -:10026000E22AA330D6031E86B4D9E5ED74E33B5EE3 -:1002700076678FEFC8D5DE8CEBF8A47821DBAC1461 -:10028000F1303B41FB96D405249F25826F4AD8FE6E -:1002900005F5D0C0382475ACFBE149B0F207FBD9B5 -:1002A0008F7E8AD27A3616D22B26D3B974E9EDEE38 -:1002B000A44CF2AEDD84EDC387141E6B0846606665 -:1002C0000DB12AB50F2BCF4D40511B2CEC33586389 -:1002D000BF7751B6C47E5FAAD4714F228CF65D08F9 -:1002E000FDAE967AE59F9C1E210FA3C7D99F3F3D87 -:1002F000B6A9865FB3B4AF9020DA9EA5BF0A0FB748 -:100300003B2AD6ADE77160F50178D5B25FDC2E19D6 -:1003100085B8186C6EDBBA14CFD9E2F51019C2F0AB -:10032000DDBF01642B1F8FF2E4513F2E30E26732B4 -:10033000BC2DFFF6659D4F215DC7834D8F65D11F95 -:10034000A33C4C5E5C455C7F6C6B9BCAD30F155A1B -:100350003FC24B20B98C8158178B2D7521FDE702C8 -:10036000C5A187EB9BF6617C754903447018C6579D -:10037000C45FE1E99034885FE05098F1C7003E1512 -:1003800018807C81EBCF224E5F932F4A1BECF76DD8 -:10039000C2F5F67CB1B0FB8B9DF7B71CFD94E8FC71 -:1003A0001E94BE4406BCF707D3ECF76DC2D079FFAC -:1003B0008F10BE0381480AF935EE18C7D1BF0AB1C4 -:1003C000CB3C0C9F8F7D7FCA2FCF64F57FB8A4B63E -:1003D0000FE2658B379A4FF78A5AB3C79D65F0AB2A -:1003E0006977E4A89FD6A3715B5CB3335D31A4F851 -:1003F000BA590C8E55410348AFC5AF20FDAE08F980 -:100400007DA6E4322FC6932E0F54537CD83ECCB336 -:10041000747978683F6BBC9822E277CD7C42E853D0 -:10042000E778D77BB81EFD3B18D7231E467A62615A -:100430009CB72B5CFCE84C9DCE0B8D649676733C90 -:100440007E6E5FEAEA3FADF8670BB8467208705AF5 -:10045000FE85599E582BF267BC966D2790FF074189 -:100460003281F46F6A137EF7EE7A378B7A71BC773C -:10047000D95D2FD606D67D27AB772BCE87D5336CAB -:10048000F5A219F5EE14F5C036AE9131EE26133E05 -:10049000B0F617C9E86F8BE88FECC1EE7A7A467F29 -:1004A000F789FE0C5B3D2DA3DE83267CB671C13E31 -:1004B0006E77F959EE6482F4368FA7DF3F6412F14C -:1004C000CB81219326CF62E35CF70B97D01157D2F3 -:1004D000BA6DF2D53E51AF05F9AA8AE2F05A1BF087 -:1004E0001EB0B8279C084CF5C62CDFBBF92A305546 -:1004F000CBFE7D96ADBEDAEA0363147DA7FA2D1F0D -:10050000293CBE395E5087FEB89545B28877FE5BC0 -:10051000C250991EEBABDAF2AD615E3EDCFBB74434 -:100520001CEF14897B304C573E596591EFEEF13F3B -:100530002FF8C579461AFE77134685157E9E37E15A -:1005400037F3DE125E5EDDFAEE44BC5865DE03185A -:10055000DCDAA785FC175FD8F9492DF6F9F17C7A2A -:100560007E3C6FCE6F74AB54F7AF35BFFC163BFFCC -:10057000F17C7A7E3C6FCEAFA635FFB4E6E7AC8760 -:10058000F79550CFAF1A725F18D79D55B890B27ECD -:10059000C7B6BE9058CAF237F535ED6D9DF4FB48ED -:1005A00030CEF28EE9BDDDAF30F8AD2FC6ADF2F33F -:1005B0006018E216E7C16D61F473BEE6D1441C1DFC -:1005C0008753F1DAF30331DF379D67BFFC13D7613F -:1005D0000C53E4FB49879EEF655D5B5EC2D79315C4 -:1005E000C1886C5DD7CC38E867FAD690FE49685C64 -:1005F000FFECEB2BF451115BD7B83F8FEABB84BE05 -:10060000BAB599BF17D026EEC3268AAA093F6DE670 -:100610007DD8F8249B7EDB3F61D241F45F1D3FC44F -:10062000DF8978C2CBD7BDE5CDD0CEDF3DF0D2BDDE -:10063000EEA759BF3156612FB3F730FD29B3F7301C -:10064000DDD31CA6F427CD3AA5BBD8B8983EDC1C58 -:1006500081181B7F67F3584AEF14FBABDB85DFF78C -:10066000CB4532F92DB634334BD985FE5F2FA5F734 -:10067000346B6BD421E8FF0D53FEB834758E97F6BA -:10068000AF9D897C06E763BFABA07BE2E38B545A46 -:100690007F414D29F9A3D3DF4DBC1E976A1BB0DD06 -:1006A000B96199D7F32613A1ECF5AEC17A63C32AD9 -:1006B000C10381B8122ACA5AEF7BC85F3501D19FA6 -:1006C000164B04B3F77723F6571D10FD15E9894043 -:1006D000F6FEE2D8DF708DE301C29DCBF2B2D75BAC -:1006E0008EF5AA3431DFB2949C977DDC9BB05E61BD -:1006F000611BDDDFB96006903DEA2AD2B790CF4298 -:10070000D44BF68D82CCF8BCB04F5B13D63B3F1672 -:1007100081416C7C3D140199F1B32BC0CAABF02E22 -:1007200039EB87A5E74D63E5AC5E12CBBF6429C703 -:10073000F62C1D375DB4CFB7979BE3B95AA1FBFEEA -:10074000345E1A77B5D8F3053297CF075AAFA8436E -:10075000B92F10E74FBFC63C1BD7B5044C7DC4EB87 -:10076000FB79F95366FD102F7F45E40B0BF9BC7D37 -:1007700093BC142F7CCFF5434B6655A5E73BE07B3C -:1007800095C36659E677CFF7CE2D991548CF67C048 -:100790000DE387CDEA61DFD367B2DCFD2609EAAD60 -:1007A00082B62AD29F233D51B20F47F6AB31509EFD -:1007B00095351CAEB7BDE52DCB54822B4EF73405D5 -:1007C0005C772FB0C3D57FA11DAEBB17DAE1EADF9E -:1007D000D8335C4F78B95ECB051F1BDFB08EBFF9F5 -:1007E000DFEDE39FF17DFBF89BBF6F1FFF8C1B3F8D -:1007F000F1F8292B5D365D631FBFEC5AFBF89BAE09 -:10080000B58F5F76DD271BFFD3B2C7CFF7C6FEE9F2 -:1008100015F6AE62B53B9B6236FB94D53B29EAF1F7 -:1008200073F46E7B3C66B34F593DD527EC5D5BBDE1 -:1008300068463D9F4FD8BBB6718D8C7143A2BF9463 -:100840006CED2F92D15F1F518FEEADA4EDF18CFEB8 -:10085000C2625CC3564FCBA837C084CF362ED8C7F0 -:100860000511077603C6814942DE59FDC533D83EDE -:10087000BB1CF7A15109F7FB5A1F1879807D87C16E -:10088000FCDDA382498B07E27A2E4D5A7C26AE7F8F -:10089000AD0560DBB74DF2713FC2189F42A99607C4 -:1008A0004DE4BFF336955C6AB9F7BA59D4EB2E0F15 -:1008B00034957CC3527E9168DF2AEE0DD6F97E4BCB -:1008C000F688D69FD5CFE237BBD8EC4F944351A4DE -:1008D000C36070DF79C5D43156FDBCD9E7A2F96B8E -:1008E00003C5B865D9E16A2DE7E3DE83E306F0BB13 -:1008F000697F349510BE359E9ADF6F0FCE96FE8AC3 -:1009000058DDE6A575DD2DD6F50277D38FCA191C03 -:10091000890132E0FD8695653DFB735A9AEDE70B40 -:10092000AA163570DF573A57AB46F1C8D5EEAEC9B7 -:10093000F2E46CE70FF5623E2D736BDBF0BE0E1C2C -:10094000B0FB71198383F53EF215EE58BD2F9B1F46 -:10095000B7C56BB36F0A8A7BBEFF65DE93EA9E075D -:10096000EB281BDD56FBC4F9C821AFCDDE2A289445 -:1009700069DF79A28A9F1B40BC84FC84DD782DADA1 -:10098000F55AC75FE518CF07530D5C077099427998 -:100990007157F07755FC456D5AB98EFE830E3A0FAC -:1009A0000471DFCDECB7253C95F6E327C43D5835FF -:1009B000DC3681FB1D057C9AD055629CD20D2AA4A1 -:1009C000FAB0B15DB1D5BE3156BAC5E95ED0FBAE65 -:1009D000E4C5F4DE5339A3BF9439FF3B7CDC5F7C74 -:1009E000973EF5B7E559E87B373A8B2DFD967EE0CB -:1009F00086D4A8DCF5D3F5385CDD7C1B66FC8AF276 -:100A0000AF0BBE751B3FF4658BB730F58338079F7E -:100A10003516C48F7EF99FD83CAE3EE8E2EF2E88B3 -:100A2000FB36E6F9D0D5C26F3A4BF85DEB211AC21E -:100A3000C2B741A67B496FC3EF42A32CF47FD2E734 -:100A4000E670B5BAC8DF659EFB5ED5E6B2F9C3E6CF -:100A50006CB0E767C3D462D45BB3D7BBC8BF76B50D -:100A6000C34FFBA098EF1C685A8176BC796F7B96C8 -:100A7000062ABECBB3E0F17B6AF07ED47E1FBFBFF7 -:100A8000F726E31BDD226FF3024937DE037875F7A3 -:100A9000A8CBCE036C9F5C518AFAB600B2BEFBF6BF -:100AA000DD563B7CBDC1EF841760598F70A83BA415 -:100AB000ACFEAD0E9F794ECCE9952BCEC38CBB38E6 -:100AC0002EF8A8DB0FF3E73CE187E1F117BDB57F16 -:100AD000BF97F60BBC9D6E949F46B569B224A7CF15 -:100AE000A73CAE98D19FCDD3B56742AA3FD8EAB50F -:100AF000F65CEFD824207DD914453E32EB2D045608 -:100B00000FE572EFA5715BBD0A566F70EE7A5D421C -:100B1000AFFE7CE7BD6EF447BEFDC0E14B502EE753 -:100B20003FA980978DDBB5330829DAC726DDB89F4A -:100B30009BB75BC97A9E4B1103ACFFF93F0ED27A8B -:100B4000396F97273985B59FF793578703C343D7E5 -:100B5000B263CFF6C775F701899FABC63B87E3BA8F -:100B6000364F85EF44B3F4D7D7CFF9F0C81379D314 -:100B700091CED28E7D5752BFED97BB3C167D11F0C2 -:100B8000BBCC7ADC1F77BF941C92459F98E76047E7 -:100B9000EE97387C7B5C491FC2B7638B3BC6E0682D -:100BA000DCF10EF1D5C41F3F14423C34EE516C7E93 -:100BB000E2C61D4ACA339CD2C31EBA8F6A04A41A65 -:100BC000C427D78F0B772F20FFF9C2F6D5EF282146 -:100BD0006C6FE76F8697480AF1FA82129982F9479B -:100BE0007F14D219AADEECD81E42BCB27E67BAF3DB -:100BF000F11CD8EEF7C6FE3F28CCEC0FE0981BF9AD -:100C0000ABB17D151F6FF7D75E43FDD2E890A337D8 -:100C1000F19792CC7397F3FD8E73B01D7D4EC9BED4 -:100C20009CFFD089CD7136EE915D6F6D8E33F81BD0 -:100C3000FEFBDDCD37A21DF4B44F433DD0F8C07F9D -:100C400086C0B26E5EEEE7F2D875FF8FEEBB8BC941 -:100C500047D71F3DB47E743DF5DA193A9B77D72309 -:100C6000FFA75867F5173D7521F90B163D36B15FA3 -:100C70004FEB27F26BD2FA2E99B87FAEEF61E3F417 -:100C800063D9BD2275D0E799DD0AF8189C6FBFE8DB -:100C9000A17B528DECDBE26AA4D702D2CB985FC273 -:100CA000F0BC70E7CA7794E1D9F01DEF2FE3A503FC -:100CB000606218467A7FE3EBE78FC6D445E72B8D59 -:100CC000708CF4AAB35DE32146D711B9E978023EEE -:100CD0007463DC4AE3CE557CDC7646C750261DDFC4 -:100CE000C65FC665D2F17B0E3A9E80861FE2F92070 -:100CF000ECEE93F55CD83C3F5BF0D8377BB4B74C57 -:100D0000BDD01B9EE74A1CAE5ABFB1C28FF2B5EBF5 -:100D1000C1FBEE2AE2749EC210D3F5D08933F052A3 -:100D2000F7EBAE6357A27E3CF69447C3F57EDE53E5 -:100D30002F90BC753DF6BC5B27FB1B0212B337BA84 -:100D4000A0FBA703ED8F8512CF346E0BA63CA13418 -:100D5000BD16262F9DAC87E8FB61FA9EE472B03089 -:100D6000B96F9A94857E4FFBF97D6E48F625BC2CB1 -:100D7000D8F627379D835BE82A8D457A1E9E84DF4F -:100D800073D1D39CBF86F33FC742D76D5C7E73C9D6 -:100D900069D7168F8A710D4E3A77B9F83EA131297D -:100DA000BD908DEEE63A78BAE7AA4F38E55BCCBB4A -:100DB00037F9EE7D3EA787AF1D7EDDC63726DE8E76 -:100DC0007C985DEF1FF24B028EA6C9A58333D741F5 -:100DD00015A2F1FEE569788FD0DB642C7D40A1F788 -:100DE0004E57B43F43FADBA92716E6B0B3FF26F40B -:100DF000D3C23DFB86A33E3BB2FF09E2C7853B0F52 -:100E0000BB717FF3EC8E47DD9D5569FEC775C1FA56 -:100E1000BEC59187F70D27FD8DFD67A1CF71D17FED -:100E2000E35E7BFF8D3BDFB1F53F3FDEEE26FF6AE1 -:100E30002FE3BCA91A97E37CDFEC7001BE9BF4663C -:100E4000BB32399B1DF4825817BBE36A82352FA24F -:100E50007F522974EBA8FF5A961A2FE0BB89F1E75D -:100E60005DFCDD4AD578D1C3E43351E0D671DFDBD8 -:100E700012BC0C748B1E6F73E0532BD226E07E40A5 -:100E8000AB8B8EB6EEBF4CF80B0CD906FFA2E0E49C -:100E90007EF8DE15EEE3747C27568D70FF7568D200 -:100EA00064BAF7A8C99A2FEBBACDFB43BF1DF2BFB6 -:100EB0004B9341B7F0D7C889979D8D2E3B1574DBB6 -:100EC0007E605D1D3F0F36E7BF6E006CC2C723D644 -:100ED000493CDE3F7E318F3334ED3B70DCFF72DA0C -:100EE0007B60183AEA2352473A1FDFB0DC734EC7E3 -:100EF000F1822E533C738436012AC42808C38B71B7 -:100F0000B68371DFD54E6980A9374CC7E70DE2FC87 -:100F10000DC7287FEBE4BF50DC63515E74645E5FF5 -:100F2000CC178A771452B4CF13CF06809C5756D271 -:100F3000933E803AF588D59FE4814DB49F4177E692 -:100F4000C93E69BC98F17666BFEB7CE3255C8F7087 -:100F50009EFDF19D367CE4A8989F1FF0791B94EFCD -:100F60006BE61DE3604DAD462CC1249A31C935189E -:100F7000CFF7DB249C5F29B4535A061D94167A35AB -:100F80004925F85E267F970C7F8193790EF84EC134 -:100F90008E77DADF3728FA4B3146C784D8E76C2DD5 -:100FA000B0C7237D3B8FEB996BF26433FE3966DD6E -:100FB000B725A08170E02BE2CF9375CB415EECAA00 -:100FC0003C0B9F29810E1E5FE6D82F5FA82CA1F352 -:100FD000FD95E19EE3BA968BF8F05CE56D7DBD333F -:100FE000B700C1CFFD609297C7791BA06B567EC436 -:100FF000589E1A6BDCA4617B4FC7857CA8209EE3BA -:1010000094FA50AE589A877CC5E8B05AF061103A0D -:101010004527C7C8FFB1D91D4B201FF6AB88493CF7 -:1010200098282A71BF9AA158F940CE9B51D253DC1F -:10103000164C637C62899BD92AE8A2AAA0FAAB115C -:101040009E4D82FE4EFEB4C7C19A765D40E43C22BE -:101050001EEF67A37F47EF8CA945018A7F098C6E3D -:10106000B906DF6F55A14943BD1A30E35BC47D0F5C -:10107000735FED7CF7C5E3888F7589FD7B46BCB84F -:10108000588FE97E5C16BBD9B91E3F98973DCE09B3 -:10109000C6668F4B34EDB48FCBFFE6FEB3C1DBF1F8 -:1010A0002C01A11914D7A90ABFC584691AF9DB8FCD -:1010B000EE94F87B1B0E7E3ABA2B7F387F6C47A3E9 -:1010C000F7CBF3C47769E7BE7D685FB584C0282895 -:1010D00024FDA72B0CFF2BA4915E89A50B76BFF3F3 -:1010E0009B27D18FBF57017CD7ED289B6307CE5339 -:1010F000350A906879B0C646E78F3BAFCC734C2E6B -:101100007FD76AA6FC05A8DDF19D12DD1753E0EC40 -:101110003BF1BDABC6832E48B2F2E3C0FB3DBE89B6 -:10112000DB0D737EF1680D9304D820E0C1F5CBBAD6 -:10113000CEF499EC07DDC22761735D881B1DF8DED4 -:1011400073BDC04FDF68A1AD9E39BFB7664D3E4845 -:10115000FE9F187FFFB9DFF4525BFF20FC233AFBB0 -:10116000877C99E16790636EA075259A9F223B88E2 -:10117000EDA771FF91942208B7D39FB2708F44EB13 -:10118000D9D56C3DC3F7D8AE4E3AF6A38E782A1364 -:10119000FF4EBE9503C28E0C4020079E23A9D1743A -:1011A0003E4B7277ED2F14B2C7AE7D484A523C7564 -:1011B000E799F9407857C82FF51A34DDC1569834AD -:1011C0007F3BF0E709DBF1EED3ED78CFABB4E3374B -:1011D00018B1E3D189E7FCB1836CF5E72B0D6E62A2 -:1011E0003E81EF4AF60FF1CDF424CD63219B474AAF -:1011F000CFC4E7DCBDEB56A0BFA4573C3AF07796CE -:10120000037F2760EF3E5E0A516FB125FE534D917B -:101210005C39E5D0C45399D63181BE4582E4A70E2E -:101220008B4EA47ADEAED4DBCE85AA3A427268C673 -:1012300029E775AFABAFC249965E77E981C3B320AA -:10124000B7DCB5377B23F52E3C1F8748FD103C2FBC -:10125000D728DD84F547F4B4DE1A349E0B221AA693 -:10126000B7887393A355FC5DA4F6D47BC568FFDDF6 -:10127000527DEC12B4FB1BAF8228EAFF6490AFBF33 -:10128000BB455A17E471D637456530D05FB0574932 -:101290004AE887D28C5F5C8076DB5E974EEB9F7668 -:1012A000EC37FF46E5A3343CC72891DB46E2B8ACF7 -:1012B0003EF9FB8FEE7D35F45D8B7DD4B5E7B661ED -:1012C000B83E6D94616EB67D407D808FDF55F99795 -:1012D0006264CB05DE63B42F5FD969F7B3B9777366 -:1012E0003FDCC23D97923D7A60367F8FF3B123FC9D -:1012F0005EEA2465C657BFC4F2E3FE53BC6304C66E -:101300009499C53C9403E999F0313C333CAE17F114 -:101310009B8D7F95297E73DCF920A1BC8EFB23D0A9 -:101320003DD4D14DB369BD7A3234E920A6757B2511 -:10133000F21F351EE1EBDB980EBB9FE89C3AA61727 -:1013400058FF357BB97FABA6939F0F9CF3A2BDDE00 -:10135000B84E7BFEBC5EF8775940AC5B21283E9DC1 -:10136000F8DCBD2E6355809FA7D1BDB2889A7DFF62 -:10137000D519E47618C307CDFFE831882C63F3381C -:101380005A5F3A01EF291D7D8F9F371CFD50999CB4 -:101390006D7FB539C0F965A39B9F1F6F9C1D482EBB -:1013A00065F3D83F7BDE40DC57FDE3DF6303B59E8A -:1013B000EC12A622645A138D7C188BF2D1C2EFBBBB -:1013C000415B49B6F7934DB930E5C4948F92D9FE8D -:1013D0005836BFE8A020DFFFD5CEAE94307EBBEB01 -:1013E0006989CE98BA9631B87AC0631C96F5477869 -:1013F0001AF7BC4B7E0AEFDEECFEEEA703219A7FC4 -:10140000D7B2F8D2F318BEBEC7843B8EF2E06E2B83 -:10141000CFD67F1CD693FF6A7B80F3739797EFC379 -:10142000416D2B991A44399978F10A06E75D4CFE13 -:1014300070FDDEE88A10DCF10540EFFF81B85F58EF -:1014400076096CB9C9B25F3B18987008E97D28C06D -:10145000E38FFAC42212C21DF9E8FD10F67FF403EF -:101460000FD1AF54F88BCC764703E21C2E68FC8674 -:10147000F8656E1129C5482C14A91F0530620FC3E9 -:10148000B7457FA7E916A7710A634C0732780A03AC -:10149000323F0F63FB34DC7F3482F913A7FD8A29C6 -:1014A0007F78E94DB5C4DD4B7BA55490E9CFD1DE03 -:1014B000400AFD328573657C8387D9A35EDE5F8732 -:1014C000DD6E450D8CFA177500509EEF8F4C7D6CCC -:1014D000EAF19602AEFF5AD6A9A41F37A99D3EF4A1 -:1014E0004B971B7AADCAC62D54758AB7183097CB67 -:1014F0007BDEE07B0ABAEDA2F3001EF948C9EA1FC1 -:10150000393368E22BF60FC4D7F083C7F6A37915F9 -:10151000F1411FA4F72461F78C7B5BBC8B28EE198B -:101520003476DF23B0EBA38D3E61C740DBEFF1DC07 -:10153000FE89BFAA747FA05BFFCC9E44EB2928558F -:10154000CF207F9DF72BB13D10FA87EDF6082FE7EE -:101550003C174B201C4E7D3316985E927AD73B4E3B -:101560003A3323BC3B5FC69032EA2093334B7BA7D0 -:101570009EEA1714EBACD05327607CBF0BF5343FC9 -:10158000552F8E3CE3B1F08FA9A7D2FC9424BC3A2E -:10159000C791C0DB9DD706A37E794E413FCAD109D2 -:1015A000FCEFFCA4841C15BC97BC18F961FDDE8B14 -:1015B0007CC8F7BB0E4EF4A2585D1BE6F7CED47D77 -:1015C000D3E220D8C77AAEEC02AF1EA8447CC88410 -:1015D00007456379CBF8C7DB2471EF52CF9F96E5BF -:1015E0007D6C33BD36CCEF95ED3A38289FEF4753ED -:1015F00044F76EBE17FE0B532E4C7E77F2B7290FC1 -:1016000009D64AB6D8118AD42EF68F763F4242D8F0 -:101610001109F3FD997809D9878B847D98080C5DB1 -:101620008D7FE6A02555ABE1B9C7A2E0208AAF5E69 -:10163000D497E3CF890F336DFC80D98B9638F84669 -:10164000F518F9C71A3F70DBBE9BF8CD851713BF9D -:10165000E7227EA58F8FDF73829CCE4E3C7FD2F92E -:10166000975D3B36EB7DBE7F95F99F07B1273BC960 -:101670001FCBEF9398FC66EA8F9AEB5A13797A5A4C -:101680005F98F7414CBD63EA97731ADA9EC9CBA203 -:101690003F9C7A23E2D2BEBB86E12FF2B300BD7736 -:1016A000E2D423EFE12F25E477BB3BC8E07DE4D90A -:1016B0003765F49B3CF6533677561ED957C7FD82E3 -:1016C0001DA776DE65DAADA6BDEAAC67DAABE6BA91 -:1016D000639E37FD3A187B00C797F630790A617C24 -:1016E0002CDF271F0CC41EC2EF790C663FC60256C2 -:1016F000A6CAF97ED62EAFB9E433CF217FED299566 -:10170000D6BF385BFF8648997098E3D707C5BB0200 -:101710008CEBD0AE29AB013ED842FE6E40D970882A -:10172000E1FA8CD74B719EBF1276D97362BD31D36B -:101730008381E80184DFA542DC53FDF1E136FD8BB6 -:10174000BF0E1AFBB13FEF6483E6D15F8308DAFB7B -:10175000FDD57629C2E0286CD0A56E678FB9AEB3EF -:10176000FEFA4FD1E9DD8FFE78A700EBA37D9485CB -:101770003E7F0EF2B8A605DECE67D1846F9CD234D0 -:1017800039D4C3F97AFA3D8488F073D9E3408E3EA8 -:10179000F5C2003CFF7CE507EF06F15CEBBFD463CC -:1017A0004184F3F525BF0FE27D885796F0FDC7957C -:1017B0000E3BE784C0DFB450F44890A5DF69FEA873 -:1017C000C6F60EC9627E3E737552C14D6937BFCFF2 -:1017D000DF9147BE3D33BFA0BD8F2D6FF2E9020FF1 -:1017E0008FDB72CEBF2AC4E368AEDEB9C5DD5FC74A -:1017F000F163FF8DE3BF2EECB8D77707C9FF61C255 -:10180000336BE74837E2E1BFF67AC4B97F878BE3F1 -:10181000DF9882E77331410A279CCF3E9D47FD5DEB -:1018200075BB4276C74C36D662C6DFB1BD57D33ED4 -:10183000DC398FAB5ED127F563F4BB6A9544F62A99 -:10184000D65FC2F821B678259DE339E73933EE88B3 -:101850001F11768533CE64CE5E7EFE5E0FFAEAF10E -:10186000E559E24EF65E4CE76E737AD9F7948784B9 -:101870003D5103E760DCFC09A85A5BA5F7BEEF7990 -:10188000BD192888ECCD662FA5479A359E0AFD39EB -:101890007FCFBE6789CFD48E1A94FB5D075FCDFBE7 -:1018A000969ED6E35FDEF2EE3377B3FC28E07E1E31 -:1018B000D3DF3E43E0FD02A1CFE7087B61D4073DC3 -:1018C000EBF319888FE199F09A7A7C06FEBD410B03 -:1018D0001E4CBDEEC4C7F18383F3903FEA42CEF3C2 -:1018E000E64F86975CED1628D9E3194D393A12E494 -:1018F0007C5DBFEDD215A56CFCC453AF9DD1C9F57D -:10190000C421D413269F0234B9518E9DFC68F2493C -:1019100037DFEDBD99F064F20793ABB038E70CE325 -:10192000FED0C97FBDC53775B93ACF40BDE0E4B33D -:101930002EC7BD6833BD2CC4FDEFF5BA3109F7AB36 -:101940006CB959C1CF03B93E7A5D6D7BF64694D729 -:101950006D5C5E163CFED04F500FCDFBF1ED21D4F7 -:10196000436FA86DC5385EC3F6E5213C577F5D8D9A -:1019700087B0FD1B49256BFCE3CE9064BEA7618B4D -:101980009380D6F82528C7FFD8EED2F01CAC71871B -:10199000879FBBEFE67863797EDEBE3B7B9CC4BC51 -:1019A0001FDD5EACF3B85B7BBCC43617F92FD0BF2C -:1019B00086C3E43A2FEE3E7F6EEFF93CBD71B788E7 -:1019C000B3D97D71D67809332EC1C9C79B1CFCCB16 -:1019D000F0437EBF38838BDCEDE29C3C71FF9DC3FE -:1019E0000F33F88E6CFB5548AAB2FAE3F979FCF193 -:1019F000F6EFFED02BE7E6DF2EC1EF697B229935AB -:101A00007EA2C1950AE1BEAA618B8BF6810D0F29DA -:101A1000F45E1DFCD143EBF9FC877EF68773197CDD -:101A2000F31F71154DE1D3A03809935EDD712C824F -:101A30003EF31EFD193F5FD6453C8BA0D3FC47F615 -:101A4000B9312EC789CF89EDFBDC9D8E3808A257AE -:101A5000FBE149749FF0FEF7DDB8CEBEF1B404FDA2 -:101A6000CA33DBCFDDF2B310EA0BC413C50108BAE9 -:101A7000E58E5B4A5DF2D3D1548FFC76BDD17109FE -:101A8000CAE218E2F7877FCAE098FB9287E2A7E6EE -:101A90003E7C1DC519BDA63671BEBF677931AEBF8C -:101AA000735DF1628D52FE7DEEE6EB891FE73C7FB0 -:101AB0007DB1B88F54C2FD3DF1129CE7559BBE49E4 -:101AC000F39C0D31E2C7B9F72851F4B39C5061F291 -:101AD0002359E466683E979BD7B67AF0311D784D5E -:101AE000F839E3BF53C4DF8B749E57F177634E8898 -:101AF000FDF73F43DDE78D5EEB7EAC71DBCA0EA4E4 -:101B0000D39B038C7E1AC513A87181377A7F5D79C8 -:101B1000FEC27E42BFD17B37A61D3411BF63FD0ECE -:101B200017BD7B6369677BB76691189FC1ED9746C8 -:101B3000B0B438BB1FF49BF9921907CFE36F4C3E4A -:101B4000CBA507B6F17896F70E713D83713954DE57 -:101B5000E14AF5B3C5E3786CEFA2A4E34C5C42CE56 -:101B6000EDE50C4E8A97E9C6EFD312FD3D08935F71 -:101B700066AFF7D8E3F3BAF9C7F96E8F3D7E668E8C -:101B8000C32E33D38CF53FDF715EB7E9D4E2671A19 -:101B90005C498A7F6AF8A387F6270D0FB9A2889758 -:101BA000B7763EF3876F31BE7FABDD9463BBDE75E6 -:101BB000CAF1DC5D63209B1CBF158840563966DF87 -:101BC000B3CA71207DAEA1C367AF77E7E4D0BB5F36 -:101BD00075E093D90DF91847FCE603F30792BFC2ED -:101BE000815F53DF3AF5E8AB219DF09C19EFC7D731 -:101BF000FD743C26C7A3C99FF31E5C40E374F3B198 -:101C0000C9A7261FE7881B73E2D3599E8FBEB33145 -:101C1000997E91782D54E2DF694AB881BFF726FB9F -:101C200023C8BFBD9D77FE36BFDC7CFF6D04DF1788 -:101C3000F2F3CE4840C3BF5881F7E5946CE7EC91CE -:101C4000897256FBFF07F9DC4E42B72CA68FE7736B -:101C5000FCB52851E1C86BA77B0C74B68A7016845A -:101C600048CE5C224E85F54CF7D12379F2BB3AEB96 -:101C7000E3AEB5072E52D13F3B4ABE6E30CBEF5A92 -:101C8000FBE2452AA377E43CF9D1412CBF7BED1F51 -:101C900079F90879948BB1EA8EF84B17D5B1FC42EB -:101CA00031EF85A69FA4658CCD4FA2CA87EFC0F304 -:101CB0001CF5A7FCEF11AD6672EFAD4E9F33E779CF -:101CC00020EE63F93C374B597E45F9EF57E026F299 -:101CD00057FED8867CC257AD8E783EA279297E67A2 -:101CE000D11317521CE9E3F9DC1F7DF6A3E7D1DF1E -:101CF00075FC0CE1B83FBF6F6E385A5CBC9F23BBCC -:101D0000CE9E88783E7B20FAD4D2F4A85675FAEE9F -:101D100063688F73BB3F8CF75B12056EEAE771C196 -:101D200067A79A9A712F4A1EE70B255F6E7A84A5E2 -:101D30004F0B7EF88F7CCD5C8768DF7DF4A97E5BDE -:101D4000F9BB31C7CE407A2BCAF13FA3BD79ECDB9A -:101D500079F4F7475EF273BCBDE4E778BB3C7F8D56 -:101D6000EB2CF6BDDA7BC675C8F42F493BAFC774C0 -:101D70008B16FB25A707A4B0DF6F5DA9F07E034D8E -:101D8000417C374E32B81D2E31669AC1F0913040F9 -:101D9000770F4611B6C77F284AF5B1148D1FB48D51 -:101DA0000F656CDD64727EF9384E2F865B5A475F93 -:101DB00018CBF3267CD39383129D3AC1F327846713 -:101DC000A4273900F753DF626615E77BFBBEBECB65 -:101DD000CFCF37BBB0FDF074FC40E3DF64DACF3621 -:101DE000E21C58FED12320FE5E217F5FC7F47B8C6E -:101DF000FBF5B5E4FF1EBD673E8F3311FE2EF33CAD -:101E0000BFE6003F9F73FAB7CE8335A44FC739F4BE -:101E1000E8797BBE4AFAB5B7F3B97F987AB5144A28 -:101E20004FF37CEEA3FC53389FFB1F7622B26E006B -:101E3000800000001F8B080000000000000BB55A56 -:101E4000097454559AFE5FBDDA92AA54AA2A45082D -:101E500004E34B0224210B45122004D42220D0316C -:101E60004A801681F64881B298AD98B4DB699D43EB -:101E70008520D2DAA319756CCE69BAE785D611250B -:101E8000E92924D1E05432C52204254E9045A01DF5 -:101E90003BED7423DA64313D824BF761FEFFDEFBDC -:101EA000A82541E93E67C8E1DCBAEFDD77DF7FBFF7 -:101EB000FFFBB77BDFBA4409600CD03F1D2403D47D -:101EC0009BF19702307C3C2311F200F47A00D9098F -:101ED00060546428C1F62AFDBB0DA06D338E338596 -:101EE000FB6F252A6C9EFC53F6FBC1462DAC868207 -:101EF0008879ED7CDEDB652B4031CE7F1154533A7F -:101F0000C0B4BEEC9FCFC1BEA1DB002ABD979EA08E -:101F1000FB6775AA1F459B71ECD74521BCB435CE34 -:101F2000560053F195293A50CC6C5EB88AFFE39481 -:101F30007850B2C37D4BB633AA2FC7DB764122FE61 -:101F4000F07B7A53508E227E0B12DCE3A3E679DB22 -:101F5000B6A89BE42EB2AFAF20B9134B32A2E681F4 -:101F6000E3FA4FFAB09F8D7F573300A643656208AE -:101F7000E52F844A8F84F2BA3F027708E59F718A81 -:101F80008FD39E7387FCB217712CF928FA7A2944F3 -:101F9000F4719EC73EFAC27138429EE9F604D70535 -:101FA0000BFE180FE3AFCAA3E2E80E114EA7643789 -:101FB000AA01EA8FE12017B69F810A88DB342848FE -:101FC0000486AB0C2AF6DF04EF0B73B0BDB279C800 -:101FD000717852184F87271ACFA445D1788EA98CD3 -:101FE000C673EC8A68DCC679A3714ADD3825EAFE3F -:101FF0004D9B0AA3FA373F561A353EDD5F16D5CF03 -:10200000DC5E1E357E52D3D2A87ED68E5551E37348 -:10201000D4B551F7737757DD90FEF303F551E362C2 -:10202000F53FB5E32751F396CAF7CA9011E6811F31 -:10203000FF880785A462D23FEA210423F53FD3E558 -:1020400027C6FFCDFA7F98F49F1BA17FF9DE44AF2E -:10205000356C6FB1ADA6D79FD05AC7905E714E1444 -:10206000EE0AE919AF0D1AACDB256C1DC89D7BF19A -:10207000FA63667EFD5181CF95B83495D6EF081E80 -:10208000FD5AC216D5C2ECD0FFB1456D44DE3C2AE4 -:102090002B0DC4AB17E54A09509E54549D2E13795D -:1020A000A4838D01E4F7B33ADDEACA08F99EB3735D -:1020B000BFF29C5DC7DA5F18D156F1BDA916F09B3F -:1020C0000BD973B436FAE7015CB72D8981822F2CC6 -:1020D000DF3E7F0EDE77F4652B0E0033F56F01389F -:1020E0001FCFE53D1FCFE55C65521AFBC87FC8EAEC -:1020F0002492A7D9EEDD69C7F79C979E30E09BC17B -:10210000E0F21BC8EE52CDE0B7E1FB1A0DB0BA12F7 -:10211000FB0E7049F5D826C24E3BE18B62285791E1 -:102120001487AA7213FBF0FAFB24D138B231B70E30 -:102130006600ACD4FCE1C61CE60F87718DBDA450CF -:10214000BD9208D80E3F90C9AE9FBB0FAD10EDE910 -:102150009C91E3A1E17051F8C9CF379B597B69B3DA -:102160003DCA6F6E6C7E2141C179CE65C3A2400429 -:102170007E5D84DF746A6586DF80FAC7648267707B -:10218000DDB79349689FD4BBCD8A439EDAF10F95A2 -:10219000807A30B62DF1A34E60A55161E3B5797C0C -:1021A000C1B940381063E9FA3D1FC22692EF9E6F15 -:1021B000B18D785F8FDDC0DED743EFC376393676D9 -:1021C000C46D39EAC541EDD1390BC82EF07A48C249 -:1021D000FEE26E30903D2CF1A61B489E93E03EDD62 -:1021E0008EF29CB52BECF91F42A581E43A735F6D2A -:1021F000028DBB369F360F0AEBC078F2A1C36F4841 -:1022000046BF35748BE4DEA5B0F799E97AE5BDA940 -:102210004F5A95F0FBCE80B7FF34EA7B29B8D9BC82 -:10222000DAFC6879517EF18D8DD5BF4BCA207FA82D -:102230000333F9C34E13F3878355575A5FC2FBAB81 -:1022400053FB6E32E273E7ABBE9D4CB8ACDC21832E -:1022500082FAFF24C1FB07FBF4301EE71EF873026D -:10226000DD5F65525F7909ED00F698DCAF003DB7A0 -:10227000873DA78D1BB0CFFD8C78072508D4ACEB2C -:10228000DBA786FFBCD773C612CF347E3D28F85536 -:10229000FF5AD658E2537DC2357EF1FE2B996389F1 -:1022A0005F3324CECBD879BB905F4A16AE1B79A59D -:1022B00020AFBABE2A4B223FB1EFB8B388E4D48333 -:1022C000F76AE4BAF6BDBF2A97EEC359D70DC94BDA -:1022D000B6E94739EF012E678FB08F15C1A422D21E -:1022E0003BDA9DC581E356FDC76BFDBF257C3AF700 -:1022F000BCF2388D29BE313C34FFB4379EC7231061 -:1023000071CE2D70C13897AD47510721DE4DF9C20E -:10231000F5FCD65EF20BC8AB2B3A747C99E4AF2A7D -:1023200081FC8205DC0AB5E865DE9B8D7A6C3CA0F9 -:1023300083A7B16B23A7A6F99F12ECCB3AEE7FB02F -:102340006F4EC13822FCD324C7BF2EDACAECC76354 -:102350005D3383B9442657F1E1AA0A7A2FF4A21F0C -:1023600047592BF18FE2C16CD874280EE59CB1035C -:10237000F3031C37F32CBFAFF9F55921DD1A6322A3 -:102380008DFBD917B28D208A8E03B30F977F4AF346 -:10239000CE8688E746890FB31C7F5F7C98EFE0FE0E -:1023A0002190CDFD7B2014AFFAD3D9B44595F9C85F -:1023B00017278F1F2D8839D9B1511AC836A31F5E30 -:1023C000E468DEBE7D02D26122C785FA8DF45B2906 -:1023D000623CBE96371E9EC2FC21FC05A522BCECC9 -:1023E00042E618798AD1EE78307647E59DA123DF61 -:1023F000D8FA701DAD4EE5BF485F4398D7905F880F -:10240000D3F7191DA3ACEF4DF2AFC8FFE71C3A2676 -:10241000AFB943F2A8F87EB3E20109D71067B74F0E -:1024200093A5F0F832078F4BB547CEA719515FFD42 -:10243000BAE3B63C9CBFA6FD0D1B2E1F7E6CF3AE0F -:1024400073E03CD5E73E9841A10B199E5699403860 -:102450006524923DE5EBC1AF2F1C29876F072E063F -:10246000295FB72389B5391D125B9F2FC4D739D097 -:10247000D1E88CF41BD79EFBCFCEF1A4B73D6360AF -:1024800005F9E3FC60D106E231C962405DBCFE554E -:102490002E9BEF09473ACFAFF5A0A7EB00AA6E2914 -:1024A0000EDA63C0E770DE81AF64364E9B37BF63E0 -:1024B000AE6C471EE5859A0E525E18173429A4E7C4 -:1024C000B89781E3128C637ED1D7B510287F1D7435 -:1024D000805BC2FBADF1431F132F863A4DCA2E8994 -:1024E000F06B0227CEDF6AE4F133070DE10D6BF8E4 -:1024F000BAF6BEB8E0CF81FC15F2C3A3D27D7D133E -:10250000DC628DC43D81C9FF4B07E7576B7C486790 -:1025100025BF8F9CDCC5E40ACB09ECBD9A9C39AC85 -:102520000E68350E5D78DCC5E4B2131F7280CB09EE -:10253000C12CE5157ADEEE61EB88B32B6EBF345209 -:102540002E5F01E6C56877CF6E816B764E76EF8B96 -:102550000FF7CD6813AD1920FCC229968784FBE8DC -:10256000B04AC2CFBFF1CF67B66F9DC3EA23BF8C1D -:102570007CB0609BE0A47572FBC2B2C933A690E345 -:10258000E0469C2C667EFFDA78E4BB95FA563ECE98 -:102590009D68B7944BCC6E80ECA64EF89987A4D07A -:1025A00085DB50B55F860E1628284BCDD1B7196F45 -:1025B000AB75C197F2F17E59BC3748FEF7AD8F7409 -:1025C00060C3F57FFE5A9C5A817864EF6F4EF658CF -:1025D00047CEF7D4D92DCFA792BEF74B0A228D79DB -:1025E000E1501AC95717FCD4E8C17661C7EF8D14C2 -:1025F0009F5639BD47C80E4A3A1AE6117EB3A0A9C4 -:10260000D16E657ED14B3C0DA470FF317C6AF2AE79 -:102610008608BC2F3978DE0243DE9BC96E82C23E3B -:10262000BB28FFC1B65DE461ED0756662AF9E1E714 -:10263000FC70301570CE2D70389570D6AE0FAAFA9A -:1026400045C4A7DC33E6D59E08BE5D10F67E41BCCE -:10265000EF1F9DDE8F0887EA039F186DB82EDF1FDE -:102660000269149F0298A7D9BFC32FFA62ECC6A7CC -:102670001F32D278DF45607E04F5BA3511F5B4E734 -:102680004CC7943556263F24E2BADBCF9998DF6CCD -:102690004FE7F6D770FA7201F9ADCB9DD537135ECF -:1026A000EF3B0C1ACFCBE2C99EF602F3639A3DE6EC -:1026B000913DA2E879C4F362EAE7B0F95A8DBDE52D -:1026C000CCFEDA7540F6873C67BC479EDB29FFC825 -:1026D000B323EFD9F359CC9E5B7B31E061DF8F7E72 -:1026E0007C12EB972DA37E6BEF7C3BB3671D425BA7 -:1026F0004876193AC8E609604C23D549501999A77C -:1027000096396C4C5ECD3F563AB8FF0F642B896EFC -:102710005C8F4596A3EC20225EF2BE88A72B9F37E4 -:10272000FCF4C509644D222E88BCAC4BE4C1E02DFD -:1027300062FEFEC72296D5BF53BAB805D75BDF232A -:1027400073FF2F787250E4C98737A7B03EC50B05D9 -:10275000F5341D5B0FFAD3199E4DF3D0C6A064511A -:10276000D3216A4B2B03F3107198B3A2F790819B8E -:10277000732EF1AFEDE00F72F5C4F77326884311A5 -:10278000DBBE19FAF875C4E1912EC47F94B884CBEE -:1027900061FC4304181FAFC79B41A9EFAED96E4C33 -:1027A000F99F1FFB037D1CDA0F1103F1C87B7ECC60 -:1027B0004FFD2850BBD333D58938FE36C93BD58968 -:1027C000380E9EF826997C7AFBA94F6CE4EFDB8CDF -:1027D0009E5CE2595B06D60BA3F0738293F3A7D8F5 -:1027E000149DA76BED5227E7FF643F3C43FCA96BA8 -:1027F00093ED2AEABBBF4DF618318FBAE0F126EB14 -:1028000011D28BE05F3E9BE2BBA87FD771D8611DE0 -:10281000E52F1867D6BF6888AA4B6BC4BE4616F46E -:102820006D4B459C7C2F4BACAEDD18938FD450FE86 -:102830005240F545B391D653F572CC3C94C714D0B1 -:10284000B8EFAE73973AC53E472664521E833C628A -:10285000F5F4D069D9BD8B62A01EBA4DC8DF3D3AF0 -:102860008E13FA4D668F5A3E637279E691DDCFD3AF -:10287000E28AA85B875A2595D9CF6EF4F3D82FBD8D -:10288000A83403C7E154CA0C5A0FE765A99E8F2FDD -:102890000DA633FB2BF1603D8FEB5E8FF5BC4AEB51 -:1028A000D6F23CD5C0D68FE197E579B3406DB4E15F -:1028B000B80DBB25B6EF53BDDB1095E7F9043E35E7 -:1028C0003B4E1CA172B23610735FE0E38BC1E70D83 -:1028D000FA316B244E8F3A45BE97066991F91E7402 -:1028E0003B47AD0B347CB43CFB4F069E5F7C20E63F -:1028F000D7C6FD8B93D7E7751E60FB4735AAACAAF8 -:102900003C1FB4AE41BEDC2FF872BFE08B0FF8B8AD -:10291000DADD921AA278F533AE7733FE112EEB0290 -:102920006B16A42A23795525F0D8D86260F92FC0F8 -:102930002623D9E7C69D31E3042E5531B8D479A5B5 -:1029400018F9783EFEB7CA576DE0FB35D5C82FBFE2 -:10295000F2FF276FACFEFE5DD3DF149812A5BF45D2 -:102960004937A4BFD83C79EF9129167A7EB83B83CA -:10297000ED4368BC899D6781C8B317EEE0F9687FB5 -:10298000C73C4B3ED553C7F56E09E729EAF95F5BB3 -:102990003EE251D82943054E31182C7AC68FEBDC24 -:1029A000D73D719982F1A1B047CFE24B514FA14A77 -:1029B000754D614FA1253381194F12D50B380F8BFF -:1029C000CF83C7279ECC233FDB3DBF98606F385E27 -:1029D00068A13C621FF07D0DA9A738A92F22DE74E3 -:1029E0003BF9BEC6B694FF7996F2FC857B0D6ECAA4 -:1029F00047161A86DE9FEDA2F7EBDD0DD8AFE95939 -:102A0000BB258EF4FE9AE4A674FC486FBDEB47A488 -:102A1000DFA0C16E62F23E7C90EEFB5B24F7241CCB -:102A2000EFEBBC3DB715FB85CD456E82597B5FA1B1 -:102A30004379A182F2C5711656C72FBCC9C0E2EE18 -:102A4000A5F1965F53BE54E5695E40FEF8D2DBFB0C -:102A50008CE40F065B2548C1851C4939F41B3FAE49 -:102A6000F3D29B278C9494CF6B3B61ECFB8E7CA2C2 -:102A70005F9521C4EAF72623D541B5CD5ABFCF488B -:102A80007AAA14F955DDCBBF67FD2AAA13F07D554C -:102A90003B6555C19F873ADF3212DE752D128C4D92 -:102AA0008FB8FFB2C4EE6BBC5F0B9C076B857FAA2F -:102AB00016FB90D5B40F89D7613BF7371AEF1FD8B3 -:102AC000BDE40885EF754DD17EE841C1F30D549703 -:102AD000B2FADB6B24BD6ED811334EF0FCC1EFE1CE -:102AE000B93549F8F31CC8219E5F9ECBE3C9E513B5 -:102AF000F1963C5CD7E563B21BE03BF9CEE2EF71A7 -:102B0000912F0C87742C9E69E3063AFECCE28DEF80 -:102B1000F8B091F2DB05C12F983E2A8207E613DE5A -:102B20007782B786F0BB3368B193FD57F4717F505D -:102B30001E34A9B40F7E2704B6929E07BB5EDDEA61 -:102B400024DEFC1BE70D087FB741E0BA41E0BA0183 -:102B50001D7E12BAD8AABC032F61BA0FE5C0FD5082 -:102B60007940F8A19DD13863E4B98FF4551734C189 -:102B7000D378FF0EE18FEE68E1FE28364ED6897DD0 -:102B800080C171B98BD97E2BD6BB94C7D5B444E331 -:102B90005F27F605EA62E2F0CD497CDFEEFBEAFF53 -:102BA000583DCD8DD153C510E74F39C53D5C7F777A -:102BB000684B1EEDDB6978C5EAA95BC94C1CAD9E6C -:102BC000D5DAF745DEAFF517237129DF0CD89BACBA -:102BD0009175FCAB493CFE54CD92FDA4E76BF5CE5C -:102BE000C443058A2E5CEF609DB332690CAF7BA6AF -:102BF000E1D44727C8E07285EB9DA7525EA828A4C0 -:102C00007CA585FB9181129C2F91F27960FECBD738 -:102C10006252A94EF1217F589D43BCC1B63228DDD6 -:102C20004EBCC1FA611DCDBF84B68E1187251D3CF7 -:102C3000EF5932FF0BC6B76313F97A87F5CAD8D1BB -:102C4000EA09AD8EA8FB8AE7A9DAF53AB47B1A5FE8 -:102C50001794585DDC76F0EBB474F49F839D57D2E3 -:102C6000D660FBA258BF96A70E619E9A21F214CAA5 -:102C70009FD77395C1064C871F431EAE17710EA4D4 -:102C8000ADCC4EEA28D925BEB54B7C1F673F5E9878 -:102C900089FEF7837896C70C9CE1E743F4FC139810 -:102CA000470DAC0D1C76E2F8CBAD128B7FEB31C734 -:102CB000BDB570A4BDD70A5E36C01651976D656D5F -:102CC00079F6DE4F1E277FD46256C8BF0E74341AC1 -:102CD000D9FEB21AF17CC6C87CA856F0B7F67BF6CE -:102CE000B55E4D127152F012D7C1F2DBC163B2DD95 -:102CF0002431FC7E353E122791FFB41D8C637A1E71 -:102D00003C615529CFFF5CF0EF92D8776F2891197D -:102D10002EBA59BCCDED7A2B83F44A7AF0D23E4AD2 -:102D2000D75B533C6C9F4F65F654BD5BA6C3BEB0EA -:102D3000FC010BDB0BD5FA1ABE3E812FCA35D9E850 -:102D40000ACBD5AEEFB3B947B11B493AC8F4A69345 -:102D5000A2EB5CDF7EB9528DB0275CCF6AF26FFBCD -:102D6000053F403F944C7EB9334961F23504B99E2A -:102D7000759DBCC5F72FE7FB3606F6FE11F7CBFCB9 -:102D80003574FF72BA05184FBEF25750FF910C9977 -:102D9000F9A9473EA8CA8288F783C4EB719F6128CE -:102DA00099D5C327744C3EDF89E1E48956F283CD7F -:102DB000F3ED79E4DFB87F389261D948FCF6D37B34 -:102DC000C786E75998C4E33CD07A53289B7991CFC2 -:102DD0002BD6BB0596321CB6089E75897C14EBA6D3 -:102DE00033648FB175D3F5F2DD88FA8D3D7F79AE0E -:102DF00072F247C883C2637A3FD5EBFBCE723FD1F4 -:102E0000D0B9E1775407FBCE9B80FCC4235D1BB295 -:102E1000280E83D73B95F2BBCB5D0F4E65FB97D257 -:102E20001626979FE44BA1BCE97432E543B59DA7F4 -:102E300093595C6F9FFE02E5499817DD41D7315FDA -:102E400061FC2BEC2966FCDB77BC3829930407B7BF -:102E500085E6AD3DA6AF247C6A8F15BF5741F94B7F -:102E60004F19CB93B4BCA888EA71CA938E4D8CCA13 -:102E700093FA057E8307E2D8FE8704199C3F303120 -:102E80008A3F356DEFB07CA2A643F644F2E8DA73D0 -:102E90002E3DE38DC1A5B0F91A029287F1632F6F21 -:102EA0006B3AF6B1F5551B024CDF0D2D067EBF9532 -:102EB000B7004DEC793F38FD84C77B7409F5506E3F -:102EC0005427D0FEFABBE9BCBE88D5C77617DF4FC2 -:102ED00078F79CF766E2CBBB73BD59F651E2861FCB -:102EE000CA78DD2D09BCDB0C2CAF8C1DB7CDC5F726 -:102EF0007B6C491075DEA8B5F52ECE9F7223DFA737 -:102F00008ABD7FAB8BD7CDF8EF191DF2E26485C186 -:102F1000FEB4A827C6A1BFBD4BF8DB65771A58DE03 -:102F200071529C33DDA5F9DD121EBFB5FDFE253BB8 -:102F3000E1492CFFE14BC863E7604B3CD17EEF6E6B -:102F4000915F2D5B14735DE453777F4F3E35C3254E -:102F5000FCE16498CCEB06AB85F645BFEC36D86552 -:102F600026B73AB1327FE43A357F73449C0F75A39C -:102F70001FA4B621E743B64FF5EE8173BF71303F12 -:102F80001A07197CDF91EDD7D75E67BFBEE19A9D26 -:102F9000FE308A779A9EFA29CFCF1BA9A7A502EF08 -:102FA0005AF325233BB7844DDB7572F89CD264F04D -:102FB0007A52711D868EB9213ABF6CC831B17CA995 -:102FC000FF7649257F8F72A69922FC7DFF389E7F70 -:102FD0003DB25C62FBC207723E6471BC36D46B24A6 -:102FE0005E4D6E5BF324B35F3F9CA27A49D3E762E8 -:102FF000338F9FD7F4A8AD976E2AB43EA79FFB6589 -:10300000176B693CC5CBBB447C5C5C12ADBF2CE844 -:103010005D40FB23F77824962F5D4FEF4B574C7B99 -:1030200087DCDF8DEAFF9F5CDE875D64EFBDC3CB8D -:10303000697FF7DD9C4FD328BED65D87CF7E81AFF9 -:10304000CFC2CFC57C167E1EE6CE521AFB101FBD26 -:10305000C3BBD945FB4FBABFD8A600CDD3F7AB7AD7 -:1030600089F4030CFFEBD9D13631EF36979DDB8B1A -:103070008B9F0FC5519FECD9A04E203F0179377629 -:10308000CED7B0FF6801E969E0C0B10263843E2F8A -:10309000D5A33FA0F8D2792859B146F24D27F8A61A -:1030A00067AD242D1571339A7F97887FA4FFBD8764 -:1030B000EEA2BAB0BF6D994B5222E26AFB49DBA483 -:1030C0008879FB83321B8FF5D8E4BB1322E57C9211 -:1030D000C9D91FE0F301F44D5E961F79BF919F1B84 -:1030E00099FB188F9FCADEC4CEDD351EEB81F3B885 -:1030F000AE6309B03825D61D30E20FAA33BA4C2A88 -:103100009D53D07EBB23C24E8E0A9C67627140FCE9 -:103110009C057E99E69D8933DE4B7D3D84E84C6EAF -:103120003684647EDE3D0188D73304AF67EA430707 -:10313000A402368E9D4B95422F1B772B0CB1D603E4 -:10314000763DB565E0666D89397407B993BC4080FA -:103150007D97144AD63B2E98D951298CA6BFF0FAF8 -:10316000F57041E3290EC6A487EDE3C78E1B1676E2 -:10317000EFA6DA82F4DC0F6C1FEE16E893E925B3B4 -:10318000F5B088BE27BB450FE6789477EF611DB395 -:10319000E7AE3E45257FE64E12CF7D86CF617FA606 -:1031A00087DB2D8520FA6E455B6F2C0EA5381FED51 -:1031B0000BCED463E5CB700CB1F7DD4682E3BAE702 -:1031C00082A2A7FE1F5DE9623F85D769F3449DA6F1 -:1031D00033FB191E7F12F191CE736C384F69930443 -:1031E00067E97C2693AF579BBF14B3C1C4421ACF83 -:1031F000E31B6D859F75F2731E1B3B9F9B6F27BC66 -:10320000A450B2EEAAE5C6711D4C0626B7EDFEA18C -:1032100081C78BC3E75DEEE0D1B3F45D8EE4F1B01E -:10322000EF7ADC666B88F27364C7A5C8BCFBAA6B37 -:10323000ED5FC9DE25C5CEF0022F28947F8C0D7F6F -:10324000EF025793C2DFD3108C1793C3E7FBDAF773 -:1032500035BBD5A58A0EF5B2C26576935E0ACD69F7 -:1032600045540F36DBBD7F75B1EF6C5A26B1C9F4FA -:10327000EAF4CA8430DF2DE02921BCB5737D49E82A -:10328000EF7AE7F664ABC4730BBA7DFA2EE819B493 -:1032900017B373B4EF8FF8793E5AA142DF1DC11303 -:1032A000F314FA2E609BC3EC7E5AA2141FD7670951 -:1032B000AFAFD1CCBF276834F3EF0260EB74B67FB9 -:1032C000F690388F68B4EAB2A9DE6A84783795F44C -:1032D0009ABC0F25703E3EF4DF16763E1A2BF7D7C8 -:1032E000F1DE9C31D3C3F23F2ABBCF62EE1385E7F8 -:1032F0001C0D4F5D18CF156A46639FC2F09B46CFE9 -:103300004F33A937D1BEC82A13FF7E49C30D15CA52 -:10331000486D17FAD0F0B393BE691D1ED4B7C69797 -:103320008C307ECFC473DC0CF4E544267B56217FC1 -:103330001D8BCBFF01AF6B7F8EF0290000000000DA -:1033400000000000000000001F8B080000000000CB -:10335000000BFBCACFC0F0A31E8143D1F8E8389D13 -:103360000F534C941182D7B3E0D78B0D5B3122D829 -:10337000FEDC0C0CCA9C0C0C2A40DC07C4FD40FC93 -:103380001E880DB818180C81380DC84E07627B20B6 -:1033900076E386E869666760E806E2C9403C9B9D83 -:1033A00074FB39241918A6C822F84F806C4505D241 -:1033B000CD19C54313F31BA1F235B451F9C1BAC0FD -:1033C000F481A446539B34F34F01F59E36C22DAFD2 -:1033D0006E8ECA97B344E52F3343E55F7487D00000 -:1033E00093DDE134B803000000000000000000009D -:1033F0001F8B080000000000000BC57D0D7C54C52C -:10340000B5F8DCBB77EF7E6F361F840D24E1260410 -:103410001230C125060C56DA4D0405451A502BA86A -:103420004F970009C857502A69C57F2E49080102E5 -:103430002C186B50C4E553ACD006053F5EAD5D1053 -:103440002DFA7C362A2AEDB318104129D014A56C28 -:10345000DFD3F29F73666EF6DECD6EC0E7FBBF7FF3 -:10346000FAABC3DC993B77E67CCF39676665D14C14 -:10347000D206107209FE7E44C81813216444B42495 -:1034800015AA404612F2532BC13FAD5F6CD9584785 -:1034900048D842486426211D4EDA51AAB192425AB8 -:1034A000DE7EB348D2094982F715429A849A4303D3 -:1034B0004B0851B344B29D3E5A9E393929E04C3CE9 -:1034C000EE2E3EEEAFEAAC58B6D779B07CBECE8BCE -:1034D000E5DE3A8584F30979B1AE00CB97EB7CF851 -:1034E000FC5FEB4AB17CB5CE8FE56B75E3B00CD7D2 -:1034F000556079A06E0A9607EB02F8DE9B75B3B0B3 -:103500003C545783CFDFAEABC5F29D3A159FBF5BEE -:10351000D78C65475D10CBF7EBDAB03C5C17C27E09 -:103520001FD5EDC4F2485D3B3EFF53DDCB587E52C4 -:1035300017C6F24E924C481F42EEB8E382751A5DF0 -:103540006FFE538BDE1F9F46C8DA11A20FC095FF96 -:10355000D4096FA030BAEEB5DF9AA6B4C781CB4FBD -:103560008880E3AC75116C5FBBFF8F44292264CD6A -:10357000884EAF4AEBE3F977866C3F6C9D5618EDA9 -:10358000173BCEE7C4C4C631D376DA6FF006D65FF8 -:103590006B1F0FDF19116DDFD1F6BE75BA53DFCE89 -:1035A000DE7F66E3FB56C0DFEA8844C28877951069 -:1035B0005ADA95AEB63E14CFB6231662C9A1F857B3 -:1035C000DA49271D67CDA85F84C5125837EDA6C01C -:1035D0003A3F20028583EA22480F0A8C716DF43B42 -:1035E000D71211E791FFD461F69DDB2F60F9DA3F26 -:1035F0006442E87B6BEE10420E3AFE9AD1E7BD7E44 -:10360000A037F55913D01B92AB02FFE9F456D0B1A5 -:10361000D78EFEC8AB5238ADFEF68329D381FE8625 -:10362000131F7C6FF5FE578802ED455D08BF06BE8F -:10363000EED553A70DF01426A64B4A49442CA5CB32 -:1036400075127F280E7CFF058040E163F284704D87 -:1036500076DA2F1E1EFE85C8D86FB5ABE243808B8D -:103660007A87D9B79DCEFB065F989C7446E70DF527 -:10367000CF68DDF97598985C30EF2FBD26BA7E478C -:10368000A97C8D8DCEC6D9D57504DE775E5FE587C2 -:10369000B5AF19DEE9ADA2FDAD051DB85EE223BEF2 -:1036A00041745C7B814AA617021C4C88D7D8F94C20 -:1036B0000778F7013CFDDD0B38D1E8F0C3DB3FB004 -:1036C00056EAFA3FA3D187C0E88BB484AD935CD1AE -:1036D000F6A7B4761BA31F6235B66F88A1639299D3 -:1036E000A0DD4C018DF81243DB0584BB757251CF10 -:1036F00079B784DF423E70FAC2D6409C75513EB124 -:1037000082DC492A117D00AF35A329BF1446D77941 -:1037100039BE6BE670595D32D905E35F4E6E15B563 -:103720008B245CC06526FDFFD52FDBE9CCA3F5E13A -:10373000E11443FD9A43FD0CFD4774E41ADAAF3DF2 -:1037400032D4D03EAAB3D850FFC117D719FA8FEEA2 -:103750002A37D47F14B9D9D0BF8CDC66A8DF60BD0E -:10376000DBD07FAC67BAA1FD26EF1C43FB78E541B7 -:1037700043FD9682870DFD6FF53518DA7F5CBACA76 -:10378000D03EC9FFA8A17EDBB8270DFDEFA8D86AFF -:1037900068BF73CA7386F6A981170CF579F6C05114 -:1037A000C0CFDDB37E6378EF5F6A5E37D43F2464B9 -:1037B0005C3CFC1281C9194A419E9357F1FE54C4E6 -:1037C0007980E6808EFB303A2DD89C404EF2F66729 -:1037D000B7BD6F9D6990936646C719AC7D67E8FDDC -:1037E000F8EF67713E211DD6C92E7D3B9BD755FF53 -:1037F000A0F215DA25F53BC95797C787FD35B94AB9 -:10380000E99B90EB287CD5FEAA8ADFA3E351796976 -:10381000624B26B584C929421EC4E79ADE27992443 -:103820006CA2E336B83237AF0498D0B1A534A817EC -:103830006E81BAA8F849671CB89A3CB2014FB1F042 -:1038400025CE144ACCBDC95915E1A78E2505127C99 -:103850005FB0FB96D2F54A24D04FA0CF2F8A012F1C -:103860004C7EB149FD7D2027DA7FE968FA4FE87F79 -:103870004C08D5637F05E1D85044FCA037D40C39FF -:10388000B43D07E1690179A2BD471F289D6CBEEADE -:10389000A581863A9BEF65EBDFE41BEBDAB83F3797 -:1038A000C293C219EAF7F14A8F75FBE428DD9AA0AA -:1038B0001FAB2BA2402EA11C34B66BDFB968730F6F -:1038C0002349148F56562EB6BBB74079D1961D2288 -:1038D0006E420AC54039C04D2D67F0518F3A420DF6 -:1038E000385ECDB5154500DFF8F60221F58C3F3E78 -:1038F000192FEAD791086F0D60B7E5EBE820D38761 -:10390000729CAE1AF55B6CFF3B05998DEFA4A8A2E3 -:10391000E35B08A3B12453E04E6104ACB68248389F -:103920004F1FA9407C8D2360975A3578066762DD6A -:10393000C9EDCCFDAE91470214CFABFDB20FC6AAC4 -:1039400014148E079F17F480A554242B696DB5F2CB -:10395000BE15F8A33947CE00B96E916A8887D62D77 -:1039600079940FE2E89105DD72E211722576712CEF -:103970009E0AE8EB6C1E04E1A8CD3F98D561CD0509 -:10398000BA1C4DED623AD5B5D7F7AE5F9671F8AE79 -:1039900002BB98966B94C94904F9964C05FA6ECE11 -:1039A0004917914F399CBAE192F39115F874057F4C -:1039B0007FB5EF7DB4D357687A3C068ECDC38F2395 -:1039C0007CA6094C1FAF2AB24F09C581CB34C18DEB -:1039D000EDCDC05369685F31FE8AA117DAE2ADA46C -:1039E000ED56C553BC928E3FA6489A0A74E12A252B -:1039F0008A05F9D7EFCCA0DFB7F3DE92221AE4876D -:103A00002B8DD1ADF51321A4D0FE4E2FFB9EC549C1 -:103A1000427E7C7FA1012FF6D2C004328CDA49FFAE -:103A200030E17B748ECC8E383C1EF9D1EC61EB24F6 -:103A3000050C4F1EFABF4BB9743C4536E88DA565A1 -:103A4000B22F4CBFB3D8ED447A32EBF14ABFEBF85A -:103A5000F6850A187F79E603F6A574FC8B654DCBD5 -:103A6000812D4D9F8CFF12F8CE14DB3F6BF21F06A9 -:103A7000C6E103AD7474BA49381506B8A7573A7051 -:103A80007FB2F9ED83BA79BE2AB8D250BE5E4BAE92 -:103A900045B97099F72FD685DE3E3808E1215E09D9 -:103AA0003D2F8BE1EBA61C4D6FA9DE493ABBEC82A2 -:103AB000C0F41A51CB10CE12E7E7A6D1A40BECD676 -:103AC0003539B2524FBB48A572184807FEBAE8F71D -:103AD000C1362320AF95A60EF6FCA706B9B9A2EF12 -:103AE000445FB817B8497931FAE632EBAF05F8E927 -:103AF000FA9F00F839A2F0B3908AA430D04B709CA2 -:103B0000611FBBBCEC21254CFFB9BCDF2FFCC78873 -:103B10000E8E3FA27CA8E30F4B6688E8BFAFC9C5F5 -:103B2000DB447F17C86193EC4339457265DC8FC471 -:103B3000CEAF4064F2260A67AB4474FC4126841081 -:103B4000EEF4AFC29ACEE147FF6CDE37FF01F0A37F -:103B50003A3AEC1886CF1BA5623A9F34A23AAEA639 -:103B6000EF4B44827A9698837C4BDBC7C829C0BF51 -:103B700037FA400E36F17D1FF16CF6EAEDF22C912A -:103B8000E135DA1EF2DE616867F64E9366D77BB6E2 -:103B90001AE8A2FBFD641277FFD14764767696E8B7 -:103BA000E1F4B315F76F2BD22644000DB68C1B7DC4 -:103BB00095C0AF1E8270D0F484A617A8BEC812FBB1 -:103BC00044C793F32A8880ED46FD9B505EC7E85DAD -:103BD0005B81510E10BD3D930BFFCDF420BD90587D -:103BE0007DCFCB8A9BAF88AF7AE84B127FBF384935 -:103BF000647298A869B87E8DAF08B727CC1A5D109B -:103C000046AF6EFE5D19E63310F01CC2C11D745B39 -:103C1000057517A9C1FA85D2E230C0C922753613DD -:103C2000AE1FD59C38FB28EE8749B48EB5A3E3EBD5 -:103C30008732D18DF834396B4800E9F81EB403059A -:103C400035402EA13D18E47AD5E7053C2EAFAB25D3 -:103C50009FD1C5D80F8CC7FDB994E9F7C3FEDE0428 -:103C6000449041FFEF2C61A5E453F4F4D98D47B2A1 -:103C700014C73353B0C03ACD4EEB34D00366A767B8 -:103C800012960543670A5026DD582B225BC5A727ED -:103C90006D3C4A57B344182F2D80FC2C792AB02450 -:103CA000CE34B45F697FA522EE3C381DF07E09E971 -:103CB000AE9B6E343828328C174B4F361FDD308860 -:103CC00058ED80F9A6F3F9A6DFD3B41040EC24AA8E -:103CD000753085517AE734D47B4EAE7F1A0B8A9BC0 -:103CE000CB693F772149BE9196B6BC2E9C3FEE6BC7 -:103CF000FBC178772F2D43FF07C17A637D4519DB20 -:103D00001FF863EC565191343ACBEDD5DE112E59A4 -:103D10007ABE9F68FDB1FA949007AECCBE9AC2F805 -:103D200051A5FF037EF4101D7FD271DCD71BF581F6 -:103D300033E63BBF025822BC17FEAF7C2F89D45B11 -:103D4000154A0A6645F484289E286A92611F65F325 -:103D5000D3FD1DB4A775FA45E5F27869847D6C2121 -:103D6000A3173DFDBFCEE56BDF7B171D5B46C7BDCF -:103D7000E073FAA0573A15A7A9C53DD7B33246EE6E -:103D8000AC2C588F74D140E92817F6070522EAA514 -:103D900066658B47EF57F95C93433DE88328D2482B -:103DA000BE9FA4F03129A2DFE6FEFEF4116B3F5D59 -:103DB000297DD8A718F1F15DF175FE3BD2C7F7FD5B -:103DC0009E86D744F28CE215EDF1CBF99F7AE2B5ED -:103DD0001EE5AE4D89EFAFBCD88D4FB56769F0A732 -:103DE0001AFD02D6BB9BDAE2D92D5A69BD2776FFB0 -:103DF000CFC6B5D59A941360DF4A1EC33E6885B21C -:103E00005E057BFE02D8E5601F06CBD03F4CF298E2 -:103E1000BF160610815F147F88ED6F4244AF07E53F -:103E20004CA3DFCD946637EAEF29AAA09FBFAD5619 -:103E3000C67958E17B69E8CF0DC1774D1E12B6B93E -:103E4000A3F40A9F62FE8087AF880E347A05339808 -:103E5000D1ABF1BDE599C5241EFE7A7CEF76E37CFB -:103E600013CAA5D8F79C92725267A7247E4F2227C7 -:103E700075F64EB916F7E178A276DECB42129507B9 -:103E8000DE9F9000856F133465807C22A8CF9ABC9A -:103E9000C52817C84E2166DFAE30FA5152B0BF6850 -:103EA000657A53AB279E0FFB6E348EA4E0BE36516D -:103EB000FF86BAD2C724AA8C1CB5AFB74A148F8D1F -:103EC0004BFD532A707F7BA8551A14ED37CFA4ED14 -:103ED000DBA9FA1C19A56789D07E0837915CBA0660 -:103EE0001E7A883212A0C9E99B74603B7DCAF148F2 -:103EF00084EEFD0C1DB20DD689FE8923D80F06BABB -:103F000084FEA64E56A72F427D95D9EFC779494129 -:103F1000EB03145EAB6CBCAEF07A32AF7B783D87BE -:103F2000D7C97AAC3B645A07FE35073D58B7F37AD8 -:103F30000EAFA7F07A32AFE7F2BAB01EEBAB643641 -:103F4000DE4A29C4C6B7F3BAC2EB29BCEEE1F55C80 -:103F50005E275BD8F72DAC6E3787D8F80E5ECFE1C1 -:103F6000F5545E4FE6F581BC2E6CC17A42799947D3 -:103F7000E16F900F1DD13A2A110ED7EE7A674C3BB4 -:103F8000A3975481703B2C940176D3FED9BFC8000F -:103F90007FE88663D77A613FD670AB464F3E949FE9 -:103FA00024F3169463197CAC86195BD00FD1304B87 -:103FB000C6FD27E1FE99687BF12185B65F08883E42 -:103FC000A09B2792E3FBC97E51C7E295ADDC4E5E14 -:103FD000C7E3956B215E09FE161EAF5C05F14A0B27 -:103FE000D0A90FEBCB215E990FFB6B16AF6C8078DD -:103FF00025AD3F07F14A5A3E0BF14A5A3EC3E395BD -:10400000DB79BC722BC42B69B919E295B47C9AC7D1 -:104010002B9FE2F1CA2779BCB26D46F15B7930FF84 -:10402000B96CFE89F0D1778A517EF6A930C62D523F -:10403000C6A418DA3DD71BE316EE925C43DD59683F -:104040008C5BD8F38A0DE35933AF33B4CB69E58683 -:10405000BAE434C62D0A774D36D4876EBBCB502FC9 -:10406000D85869187F70EBFD86F6BC96070CEDB941 -:104070008D3F37D49525F586FE4F9A7291BEB217C3 -:10408000AD34F4CB9CBBDED06F9EDD7FDA04F26EE4 -:1040900042DA15C937F2B59AAE9797B1FAC1944D85 -:1040A000FC7ED4734C1FA18F16FC6A59CC7F65FD32 -:1040B000E4A643B07FB1E4313D15EBAF8A1D4F76E6 -:1040C000EE38A2D2EF94B90F793B75FC48BCBAF731 -:1040D000E85293242627573EC2F6E72D8FC4DFA768 -:1040E000A326A0EB68F9363E1FB82493418F68FBE6 -:1040F0009A964704ECFF7DC7D7DA63C78D7E8FD2CF -:10410000DE48FD7E38C4E7437584CE5E3077264FA7 -:1041100027A8E7D97ED9C4FD3B65134B8F35527E66 -:1041200059E6213E0BAD2F7396FB995D42AD73C0EE -:10413000C5925B715FAFF5D7E6D5E89CCCE40BD1B7 -:10414000F92D514ED90D7E856569BDDB6F72C48432 -:10415000FE3F53442061AA9764A9625C0E9D8F7C48 -:10416000D8E45B4A503FC5F50F10B29EC59DBD46D1 -:10417000BF69E38C18F9C7F332CC7CFE0D69E5F812 -:10418000BCD1D3FBBC2C302F980F9F9739E2C0D203 -:1041900014B1E17C474552B15E1A49C6F2DA487F54 -:1041A0002C474632B01C11198865492407CB6B2275 -:1041B00057E17BC59121580E8F5C83CF7D91E158EB -:1041C0005E1DF9013E1F1619856551E4067C5E18D7 -:1041D00029C3F2AAC82DF87C68643C964322B7E153 -:1041E000F382C8242CF323776339383215CB4191FD -:1041F000E958E645A66139303207DFCB8DCCC632AF -:1042000027F2203E57220BB11C107918CBECC8CFF7 -:10421000B0CC8A34609919598A65FFC82A7CAF5F8F -:10422000640596199147F1B937B20ECBF4C8062C44 -:1042300093235BB1DD13D98C6552E4397CEE8E3C5F -:104240008BA52BF2023E7746F660E988FC069FDBE1 -:1042500023AF60698BBC8ECFAD91FD585E0E4F973A -:10426000B3834B4F18E3CF233F31CAF192C3C6F853 -:1042700073F13B4639EE3B688C3F0F7BD5187F2EA0 -:10428000DC6B8C3F0FDD6594E305DB8C727CF0C644 -:10429000BB0CFDF35A2B0DEDB92DF71BE574A351A3 -:1042A0008E672FF9B9A17FE6A27A437BBFB92B0DA8 -:1042B000EDDE1946F99D4E9E30ECD33C63B618F501 -:1042C000DAF5BF34EEDB4A9E8FD9D78450BED80BC7 -:1042D000FFD5F09E35EF408C5C56997C8AF1B70390 -:1042E0004820BEB998D87DB0AF89C5670A9707A99D -:1042F000C077B44CE37CD707F88E9629B7CCF5028B -:104300003DA44E2C9D0676CCC5638202BE3261620E -:104310006D3EC47B52FA138CFB1275C80D7E5A6F2A -:10432000CAE075FA44807A1661FE06B2B41CFC6CD1 -:104330004D39ACFE56E39272C88B6932F376B5B153 -:104340001CDFB7B1FA91C619F5D09E92E4EBE7A352 -:10435000EF6D35C797D79F4A2CBED75FF2FF41A2BA -:10436000EBFF6B59E743E097FB776BE003893E9FD8 -:104370006B0D0C80D0DA5973E019501DB982FF30F3 -:10438000F42B12FC1F4A28B78D7ED609A038E9F31A -:104390001CC9FF4768D7D6DFE4EA7D1EEF72BDD4A3 -:1043A000944C709FA93E26F3BC1282FA52F36B3DE7 -:1043B000EE70A3BC5FFE98BC05E252E6CCF4E9E0E7 -:1043C0004F833F83FE686D5A087E762BE8A18120DB -:1043D000E5DBB174920E2CDDA40B4B0F64120C8C38 -:1043E000AEBB7BBD596CBD140E5F4BB88FA8C1FE30 -:1043F000F58E89A5B01E0A870B1C0E7F97FA2486BE -:1044000003FDABF08E642E51B4277609067F6692C9 -:104410002940CC3C8E0ACE998C193EDC8FFD49F2A6 -:10442000203D6AF0A37F8B524646F301E87B56732A -:104430009F9EE369E320C0E0FB5C1F6AF45C9B4045 -:104440003F697E6EA2DEFA9DE24DBF97C5B8DF31AF -:10445000493E8CD7C6BE27398DF2CFEC0C601E8446 -:104460002CC58FEBCA161EAFDA38F18AE2DB3BB8F7 -:104470009D4F1A6FBDA2FE5BB475534A80FE591A58 -:10448000D76FBC15E96E107F3F0BEC3A4A4FAFFF78 -:10449000B9BABE05E80F62D2F1FC07AD22DA835942 -:1044A0000BA9E0C989C23BB390DA83C3A2DFCD5C1C -:1044B00064F4BF8465165F21AD57067F2DAF338B43 -:1044C00012FCBFA6F49C07D93691AD87C751A50D44 -:1044D00015CD362A7F0639593DB3B5F7F9101EB709 -:1044E000C8E47495E9E47E979DC6717B7CD7F4CED1 -:1044F000F078795E09BFF31DE38033CDF1E3A814B2 -:104500005F88EF81DA3C6AE91F9DD7603E7F6D3C92 -:104510002D1EA8D5293EAD607737B554A29DD5E4B0 -:1045200065FA9B7C43471F892C4FE2EDCB421CFE72 -:104530009BF87E32A49663FE23D965A45365A964D3 -:104540000FA0FD26A640B9B991F5CB59966607385C -:10455000357A5252A0DC542BD6DB28DD34AAC40FA6 -:10456000CBCAFED9091B6B3F9E0C654E5BD75BF92E -:10457000147F391ED127D1F964A8E7DFBA09CA161A -:10458000BF3507FC704B24CC23CC6E23F602DA2F08 -:104590007B2EC17E0444209DCF931A1ED556611CEC -:1045A000FD67664BD7521BBE47FC8374FD3670F027 -:1045B000E5353E50066C9AD7E2993C0EE2F385C48D -:1045C000378844FB3DCEC773403B8C3386E5316A68 -:1045D000EDEB78BBA5F6BC9A0F654BE7BA9BA05FE5 -:1045E000AB719CB5BCDF20ADBDC4D8BE5A23AB2592 -:1045F000CF87611C534BD77B37C17CDA58BF6EB96C -:10460000C5FBAFE2FD63E5C560788FFB2BF5F35C7E -:1046100011835F4D7E84C03F900FF865FE018B755E -:10462000EB53E08FD4FA2D17D8FE4889C9337DC5E6 -:10463000CCE46197CCFCB61A3D25A26F3257B71F68 -:1046400080B8E50CBBB17E4F8A611F48C6F433B613 -:104650005F9F6B6C2F196AAC17161BEB79D719EAA1 -:1046600017BBFD2F411BE68573FFCB60FE8D0D6DE3 -:1046700095988712F5FBF9EDFA7D4A26EFB7ADA6BE -:1046800018F9A7C1C9F987FB691CBCBDA9B0D2AE96 -:104690008FBF6BFCD30C7E100BF85958DEF68EB62C -:1046A000DEE1B589E37B23CFAF7982E3A98DE3E92E -:1046B00017DC8F13E47E9C353CEFBC85E79DAFE4AF -:1046C0007E9C469E77FE02F7E3ECE17E9C6DDC8FDC -:1046D000F36BEEC7D9CDF3CE9FE37E9C15C3BBA68B -:1046E00082FFEC59EECF7986FB73C670F9BD62ACE0 -:1046F000AF1FF8F7B68E8DBF7F1EC3E9E2C7E0C8D3 -:10470000EC037ADB536F06BAF4B13CEB9C5A8F682A -:1047100029013B97D165CE2C8F2897809DCBEA93BA -:10472000B8BE05BD827933993C6F26936A9D74EEBD -:10473000FF85AEAA4AC01FDF778A6738B842DD32EC -:10474000D7A30AF1EAE3067DD58000712DC9E44FB5 -:104750009247C0F86C5EF9C1AE0390A7E8EBE82879 -:1047600007740E3BD45E0FFD0A0B83109120E6B454 -:104770009008726945990FFD6F4F7F68F26D813126 -:10478000D388812EE81C519FE5F1FD2CB9DE481736 -:1047900096C826B49B9B6A587E06ED1377FFAE95AC -:1047A000C97EA3FD90546AF483350527F7EA97F68E -:1047B000BD6A7C7FD85EE3FEABA9D09827125B165A -:1047C000EE1263FC5C31EF3B7BFF7E7E6422AE37F2 -:1047D000119DDF66AA2C97757912CEC80F711F1133 -:1047E0006B0F4A60E70DC4BC1A3FD8BF529EC70F7B -:1047F000FE12294FE1A58F3FF7F37A05D6A9DDF820 -:1048000063189FE2C560379A480063222B8610BE6A -:104810001FF967BD9F2AFF157710DC4F789AEC3798 -:10482000A84083FE99881F99E32755AE7906FC1F9F -:104830004FAF1609E07F6B4BEFFCDB239FC2E9C74C -:104840003852D6224F31E8BD44EFB52E12C7C58B82 -:104850008FCDE774BD6CD1640FEA8D8397CD179827 -:104860000FEBD7F205FADCCEF305CE8C37F8955373 -:10487000AB7AC7E3062EBFB47A06896FBFEEE1FCC0 -:104880004E9C2CDF44A3FBD461BD8FDF7D6E2724BB -:10489000920EE00B2980F2B3CFED01CC8B27145F91 -:1048A0007A3E69FA76FADBC087EA3A96A748FB892E -:1048B0007A3B4C9B4786275C2640FFFDA3307F63F5 -:1048C000B0332042DCBA693FE1DF69477BDC31A3CA -:1048D000C6CFFC65ED04FCF68E1A9F0ADF077C61EB -:1048E0001E5246777FD40FAB8222A67E349430BB13 -:1048F0005793FF1A9D34788B0F417CFD4289847158 -:104900006F6A5F5DBAA4ED67E87F06B7313A68EA7F -:1049100043F0DC8D54A086811E897F1CC20DC81F08 -:10492000FE9A5C3FF1E3B99422A6FF4D70DE03FAD4 -:10493000491D7ECC830E787C90BF98D5360CF94CFF -:10494000F2D40880DF87C4C06E3D5F999C2CFFAB1A -:1049500029C1B982162E67FB25C0EB87BC3D55EEF9 -:10496000180F72F8E9C728FDC7C9CBF903D70B4F59 -:10497000B54EFE438112E55FADFD4F60A4E9E695BB -:104980001591597E61DB77DB078C35139E7F647C44 -:10499000CF2C5518F6615966E3F7E434A33FF2CA09 -:1049A000E729A15C2285371BF09CDAAF77F9A9F1E2 -:1049B000FFC5AC18BB23AF00E9396A7794233D6C7F -:1049C000F412462F9C9E343DE2EAF4ABE2C09EF422 -:1049D000B13178C00676B246671667C80F7E038786 -:1049E000378CE9823A7AF82BD04356DB4884B7AB50 -:1049F00044C5E7FBB8FECBADED2AF3C7598766DFA8 -:104A0000C1BECB5B0C5F88D9FF908A20D8D559599D -:104A100010C303B5CCFC0B999997DB6F5D59FC5A19 -:104A20008B2767D33FD8FFBCA2E1FD8B18BF9587CA -:104A3000AA785D3CB5EF17D30531A7271E62DF6B5F -:104A4000F4947BE2C96FC91448B7E8F01FBB8F8F9D -:104A5000DD6F13BE7F94BBAB8B500E5B268CC3F80F -:104A600048F7BE7BE3445CB785E34F6ED1E2FBB110 -:104A7000FBCAB9BEDEFDAADF6F5FE9B318F34BAF27 -:104A8000383FF73BFA25B672BB35767F113B8ED89F -:104A90001610E39DDBC86F33C23DAFC568FF0CE362 -:104AA000FC9DA31AFDC8036AFBC5F777F27CB5CA63 -:104AB000520D4FCA9DFF41E977F62133E6E16BFBCA -:104AC00060CDEF349BE7AD55F23CB619A4C20D8D15 -:104AD000678988E777CE92F7DDD7E8F8A6CAC2CE15 -:104AE000D19166F371387FA1E567CD0CB2BA369FDC -:104AF000EA3663BD8A4C4E07BF6B55AB99403ED634 -:104B00006C221DEFD4E64FE9F8271696875A4D6AB6 -:104B10009A40BE2DE379AF951E22A5A61032EFA5CF -:104B2000A746C2799E7916267F4F53F82B3A7D7D92 -:104B3000BF3324037F7FB6F79A9FFC80C0FBA1A6FA -:104B40007EA03F93E39F8398DE6C9CDFE5E61F3BEE -:104B50005FED9C46A279483B85B8F93F0F6BFEAFED -:104B60002B3C47B215826223129F23B9DCFB3B2DFD -:104B70008C7EFEBBEFEFFE9EEF3F7F99F9CFB376C1 -:104B8000DD8879DE6935152057B57C96F924E00774 -:104B900057BAE9D5496A7F45D7CF7B85FD32693F52 -:104BA000D315F4CBEB7DBC739CCF7FBF6BAB0CFC00 -:104BB0007BF697C726823F70CE6F4CC44AE9E0DC93 -:104BC0002E173F2F169241EFDDBFD7E40F613D3C1A -:104BD000F2365DBE206616D2F1E7FCDA85FEC4FB34 -:104BE0009FB78426D0F7EF7FF1B36184C2E15C7D8B -:104BF000D79BFDC10EFAA5C0F2AFD4CE61B7D1E705 -:104C0000F74BE4BE8A387AAB83F3C199571C5380C3 -:104C1000CE849DFBEFC571DBEF345B74718DDF5B80 -:104C2000CC087FDA8F9DC77A56080D12D8FCF4F9AC -:104C3000E25ADEDB99670536BF97CD211BCC6FE7C3 -:104C4000663940FB2DD8F937A4EB1B7EBDDB0D7018 -:104C500058F0B2C9207F16EC34852DC3B03C6641B4 -:104C6000FFBDDF298C047812D457F3F7CE9B00F4F4 -:104C700030BF7DD5DF4C6E78DFC85F142E78EE63D1 -:104C8000CEC726DF04A8BFF08C1BECD9D31DDBDD1B -:104C900000573AEE3499D2D50FBFD6F12161E347E0 -:104CA000527A8E071E1BA0AF05ED2BD8F7F6DE7AE1 -:104CB0000AE4DB82183E3E0DFFC8E8A93F2216A396 -:104CC0005FF202796724D81D64676ADCFCE26EFD3E -:104CD000C1F97ACEEE0B9BE03CF199E7FFB209EC0B -:104CE000FBB9FFFC6AD3C3E01778CDE60179B4E0E5 -:104CF000971FBA890EFEA95666CF9F7BF6991D4F66 -:104D0000503E39F7470BDA3BE77E7B2A5BA1EB3F4E -:104D1000B7E71FE970EE76D16FC7F605782CDA7722 -:104D200043DFDEF61B40B7218B1EBF21C4AFF2323A -:104D3000FD4E5F020758581983A7D7F7BE9E0DF3A3 -:104D40003C7BC482E76F16D067B5C580B779A81FD2 -:104D5000A0BE84C27BFEAEE57F330D8B0777B5BF67 -:104D600008678548B83FF102DE6FFBF1E81228CDF5 -:104D70003E05C6235D28DF63DF5B7098E2F7EAC477 -:104D8000F8BC40BE9101FE0B76AD60DF6DA7F874F4 -:104D9000F7C4E759F8C7A89EF82CB6C6E273EED35D -:104DA0004F40E3DED4B879241A3EE7EDBBA357BBEE -:104DB00041930F9783F32C9E37F54F8BBFDC0A7C12 -:104DC000F6BC43F5323C8726D0B673BB2F64134A3A -:104DD000275F98BBEE0539D9F55B8B670B7D7EFFAE -:104DE0006F3F46BE3BB7EF3D5961E74F9C02B52B85 -:104DF000CE91EEBF0EB033E6F3D8DA826DAEB0C519 -:104E00001DC5D7FCD0A4718A1B9F1FC3E721C60F05 -:104E1000F343FB6F17E2E06F893597E9A7501F84D2 -:104E2000CB3CD221C3F97C3D5E8552C0E7B11B81EA -:104E3000FE12E1535BBF07D67FAD0EAFDB181FC775 -:104E4000F69F4FF915E4700FFC86848FA13CB7D90B -:104E500022417EE4391E6F8CC57B14FEFCFCE47796 -:104E6000B4171FB226884370385C8EDF2FB7BEEFB1 -:104E70000ABF195605C78D85E3996FE2EB83F55C90 -:104E80007ECC2735E3FAE9F499C54CF5590ED87B69 -:104E9000156A7F213ADFA67613CAF9333B4D21D03C -:104EA00017B1F2627E827D72C8CAEC97F92FEF1FAC -:104EB0000672EDCC8157385D32BA9FBFEB98AC7269 -:104EC000FD10D2EB870471CA5FF2F116BC1A7FBCE9 -:104ED00005BBFE1677BCD392FF4E98FFE90E335107 -:104EE000E910A7DB4D71FD49AD56B331CFD635F290 -:104EF00048127DCFE4B62BB0EE867AFFC72AD825BC -:104F0000EF9BD1CF4224DF17163C6F6D575652B836 -:104F100035B8ABD0AFA28DD7180327C95BA10A253E -:104F200070FEABA284D9D46CDE5ABBD9231AE64DED -:104F3000F56E26E8A5A3C34F99619D9FC6D88F9FA4 -:104F40004AA4A92F1DEF5355F02D55E2ED178DE31F -:104F500007969888A2D78796AEA3301FF23B1B0115 -:104F60003FB2E9359B0AF264C1265B08E29BAFEFD2 -:104F7000BBB803E076EE690B8F77B23CDB6ABE5FAD -:104F80003BB5EFE2A6FFA2EDA7E065FAFDEA4DB45E -:104F90003FD8EDBB1C98F4FCD7E79386112AA7AB4A -:104FA0007FF7F044902FD5B0C7A2FDAB7FDD37D49B -:104FB00040C73BD987D54FEECE0A015EE6BEF0DB97 -:104FC000F9A04FE6FCCA4180245FDFF7F1BD503FF6 -:104FD000F73B17E67B9DFBDDA91F021F507B5BD1D2 -:104FE000EBF5D9FAF3DE74DC395067EDC2255D1EAE -:104FF000C11C2829BDCF7939C90FFB715D3F7C6F7A -:1050000081A5EB21744011B59F887BA2703FE0C35E -:10501000393B8DDFFBAB95D9530BE4AE2AD63FD895 -:105020008FF16B07BEF78D46A7BC3DF67DADFF7FC8 -:105030005A7363C661EFCFB7909A78F46FB1B171CC -:10504000E7ECFC36DF381EA3D79EDF61CF7F2AB0A6 -:10505000FC7CB2C786E77FE7CAE1C129945F5F9411 -:10506000C92CE0DBB9EEF0E064FABDDF707939D726 -:105070004EEBF4793F3E0FE80F7562EDFC15E077DB -:10508000DE4B3602F43EEF772EF42BCF7BF1E2C9F4 -:1050900027E9F333FB1C98C73AEF778B11DFF32C2A -:1050A000E17BC18FD3B5C782FEB1337BDECA067BFD -:1050B000E48C399C9DD28B9F685EBB853B2F8CEB2B -:1050C000A0FB82821A27F839595E4E2D61F70ED463 -:1050D00042E207D0F12736160FE1F1A907B8BFE881 -:1050E000FC0C2509E77FFD2DEC398F5F3F70ABD2BB -:1050F0003759370FC89B23D7D07D895C930F72D661 -:1051000014B98528B42E450662A9F533C1FD0DE01A -:105110000F4D2368BF9BD37CA49A968B534800CF36 -:10512000FF386FEEE6B33F50143FB041E90BE3F9AF -:105130006C4CBECCB3FB47DB306FC478EF82BA8FC8 -:10514000ADEB22BF4F2176BE17CDAA05E479346EB0 -:10515000C7F2066B25E563F0FF92435C2EF5583FDE -:10516000E3B3F39E14E4336D1DABEA3C284F56D4F1 -:1051700079B15C5E574014CC77F661DDC4E16129FA -:105180005409F8578107E1CFE2ACF0C37D16302611 -:10519000C4534DCE00D297C55B83BE022B8F8B9A32 -:1051A0009C2AA976429E078393C959817092795DA2 -:1051B0006A9B8070A5EFE3F3B1F6C00CDB08C83F33 -:1051C0001E6A9053725AB1A1DE036E1A5DECFEDFC7 -:1051D000861F4178ADA8B36209F9E20037C8178786 -:1051E000FAFF07F8B530F85D47141DFF40FEB662C0 -:1051F000E0A704F0DB40E19716E5AB5838D4F23C69 -:105200001D8D9F12F12FE4DB4310667D5D1B96DA46 -:10521000F394047AFDAC8DD923B524B014E3A11E18 -:10522000E68721692AC9D4F99F8857C5732078DE9B -:1052300014DA336F41FFA5865F93473A69947FCABA -:10524000C7B09EC56F9B459057A6DAADE4335D1C91 -:10525000DF34A1C2A6209C7D02C4351AB87E5DD67B -:105260008D4F237FACAA53B05CCDF9642DE79375C5 -:1052700080775A6FF0B1FC9F967104F5E763B4CE66 -:10528000F6FB61A2F78B27FBDAC3668A7F94490A93 -:1052900096EC1E8E2396D020FA9EA390603C23F9B4 -:1052A000C8CF42B856D28EE7AD93B57B605ECD4D88 -:1052B0009E8A712062667A8A98581934C33E2A16EB -:1052C000BE0DBE0378BF44A2F9941D9D2DC0F72EDC -:1052D0004E65B1B3B47BDA8FC07D10CE16073BA705 -:1052E000E8AB19908DF2D582F4EAF405846A1D1EAC -:1052F000D313D87F4BECE3FF03E8F113C84BA4F8BA -:105300005DDF3610F35A5699DBBD200F57F1F31AC3 -:10531000CA140A05DDFD626F7039E92E31CA014DEC -:105320002E7BAE2F36D0B3267753C618E95E93BBDB -:10533000BFEE96BB156741EEA64636225FC6F24128 -:1053400083595685ABF13E1AE67F3A26B0FB327A96 -:10535000CA038CBF9FEFCCD902E7B135FE895DBF90 -:10536000D43C1EBFD36D0F26C87FECCFEF6568A677 -:10537000F446F2215F414144ACA174066590D21914 -:10538000E3A7522C353AAE274C86A87B45364FEE24 -:10539000AFD5CEE2D45B8BFD80C765ED8C87B2ECD8 -:1053A0008CCF96A589A0BB8844F7934EFA48DA3F84 -:1053B000CA0AF6A56466F1FC2E97D80EF1DC65CE1C -:1053C000C956C82B15924B907EFEEEAA1CD05B7C72 -:1053D00007EE5F03FAF3387DE438EDB78CDFEB645A -:1053E000F21413D897EE7676603E94D32E1AE249E3 -:1053F000F3EC815CBBAE5E045FE77887617727B82A -:105400001F6A185F0FC954499E4E4E74DF97A4A8B7 -:10541000A440272FEA07DD88F731F5941309E4E16A -:10542000F6FF1979D83020847835C7CA9F343FDE1B -:1054300001454B15AE56A0D6F9B2BB87239DDE6061 -:10544000877D88734BB71DF4A3DC9EF38C957F5149 -:10545000BDA6A01F8CEAB5C74B419E26D46B35F77D -:10546000211DB7F457808EF7AF79F869A87FB6C6CB -:1054700082F7BE5445561085CEB73A320ACB596DE5 -:105480008F6259D9B6993211214B5757AF990AFDFE -:105490003798D0FF733274CDB95A5A3FD96241FB65 -:1054A000FDE4C6070780FD77B2C5A198C0DEDF38EE -:1054B000C2D8DECCEE7F39D9660E9918FD5E324136 -:1054C0003C8270F90E5E20DD7C49898276FCF99879 -:1054D000784BE55A8B5F7027867F655B7C7B12CFAC -:1054E0006F63726E4D3EC8D7B2A33F1B00F4A1C9D3 -:1054F00099C52954EE01FC8E5A48BCB8C058FBD857 -:105500000580A7B176FF6286AF2BBB37EB3391DA0C -:10551000DD88A7807B92C1EFCBFCAA9F71BB9C5812 -:1055200013B4BBF9FB9EF8EDF35AFEF2E62304F246 -:10553000548D7E6D13F8AB05D88F4F62790F5A1CCE -:10554000A8275D337BBAC582726506F74769741E6A -:10555000A5B3809B9FDB33D0E1ECC83A947BC2AA11 -:10556000A2C74751F87D45E90FE8435835BA2FC027 -:1055700077E9CA1FACBD878EFFF53B267C3E2B62C8 -:10558000C3FE5F3EE27BFC1ED82FFCBB19F349BE75 -:105590003E3416E3C95F9A8D7E8C32079397AF71C4 -:1055A000FEAF8AAC32D8E755CDD365F0835645D6E9 -:1055B000E0F32A0822619EFC5D6F9449105F2298F7 -:1055C000E7F29AFDCEB1F5A84F8BD18F56BDDA1216 -:1055D00037CFFF35BB629057D59D2D382EA1F65998 -:1055E0005A3A1F4F2777AA23A9C81FC4A312C8FF7E -:1055F000AEE2F2A77B7E1BCD06F9F3A52DBE9FE69A -:105600005D3B5B6755E407C8773DD7F7437C5EA5F4 -:105610007DB793F169743D8F8F8AB79EE83AAEC724 -:10562000FE5F26C7FFFE050EDF9375B3889FCAAFE6 -:105630004A0BEDE784EF3FD8540AFBFC8DC9298261 -:105640006E5DD56D73885FB7AEEA8DD364FDFD9452 -:10565000513C2C32E0E1C2CA05888725F68A63A056 -:10566000072A578D1E16C07DFE0A84F367665F36D3 -:10567000C8E3536D0FBAE3E5175F88C54F1BC70F2B -:10568000B5BB4B74F8D1F012FBFEC93F57FFFD11BB -:1056900090531B5C06B9125BF6C05B4E7CB825715B -:1056A000FA3C49F57700E1A6BC7804E87AB503F343 -:1056B000E412C3EF2A12E80D7E09EC676A67591DF0 -:1056C00023E0BB04E150DDC6E8E072708B7E97D327 -:1056D0004159FCF58C766874504B54CAB0C7E5CB81 -:1056E000D1C1C344B5F6B28E6E3A687BA32C2F4A63 -:1056F00007A31DC1B1F5B4DF1760FFE4F7C4FF7164 -:1057000059755F07F6CE4A13C6BD8EDBD5F4BB587C -:105710007D38C8E7E3EEE0C4EB4AA2F5D9DB07B970 -:10572000F5F73A9E6AA6708803BFD18E04F493A75A -:1057300092C291FFEFE8E73373FC3CD1B1F6B2328D -:10574000C02709C6F7276BA526BF4D49CEEE7D2F92 -:10575000E8D1E3CEDCBF8768EB1A7BE056076D6FBC -:105760004C7E08F5FCF1E302EAE1A57F5E9C0F7236 -:10577000B887FD5B1779E2C420F45B3E79C28CF6F2 -:10578000148E4BA8FD037A00CFD7E03EA03FFA5914 -:1057900012C5731F84CB7F4744E3BA5AFC76595D28 -:1057A000C7A3303EB1AAC4A39DD757A064F6D87F43 -:1057B000C23C74FE79D91CF0C0B92159201540F7BC -:1057C0006629D00CF986666FDA705507E7850E9664 -:1057D00097633B78B03987BE6F9BF9070FF8F92CB8 -:1057E000F43B505A33A5F37A7FB939AD9DDD7794F8 -:1057F000A77B9E0BE7A269DDE077A0F3ED65DFFCF8 -:105800001BA1FB9E35BCDF78AA76D117808ED2CD46 -:105810001FB5FC15A991B5276BCD8DAC9DFB51171C -:1058200054323FE9EBD392107EDABAA6BEBA1CEF2F -:105830005B9BFA6A069E739AEACCFF1CE0F91BC8D0 -:10584000FB01BA4F66FA39962E1EE5F2E7EECDA2BD -:105850006AA6E31D34771D70005FFC54C07DF55DC2 -:105860001F1E3403C9FFE9F07133DC97701FA4EAEF -:10587000D0F54C238ACC8CE810BE3F9DB4BB58BDFC -:10588000BD0FDC7F1A1D8F6E9961BC852CFE7CD705 -:105890008787C7821AA5E32D83F2BE77880CE34F72 -:1058A000DBAB34B163517CBC57E9786274BC6EF8F1 -:1058B00049568447143E568497061FB85E04DBA3FE -:1058C000F0457B45836F03C08DC26F6AD2949BC93C -:1058D000B0C4FC32D539F873765E8CCD2716BE5F26 -:1058E0004313E5B7A71CFE3DC07F8D0EFFF3C03FFD -:1058F00073AD5DD9522E9E077B119ECF370506A44E -:105900000FC47362F97D200FAD237E9C37964F8FB5 -:1059100002BF5C0D25E50B98073FB7722F5FE7EBE1 -:105920003F3BE5C2F328FB3ECE86729EA973F59DF0 -:10593000C06FFF6642FBF3FCDEFC5EF3EB8E72BFD2 -:10594000CBBB0E7E9E88AFF33E6ECFDDB7D7118204 -:105950007B10EFAB3575EFAF80AEEFAB65F9274449 -:10596000EA1876BBC19E6CE4F1909EE3C07E21767E -:105970001C6D9D07B2FB5D05FBCBA747C8B88FD850 -:10598000FFCEF93F56D3BA3DCB8AFB84D5C99C7E66 -:10599000CBD8BEF5E964BFA308FC5F2B537C2A5D1E -:1059A000E7CA3748BB48E17460C843A1F212B81790 -:1059B0005A44DFD9DAC8D66039BC57C8EE9DF170B9 -:1059C000BB746DC7F136A0C753472C1877F8D2C502 -:1059D000CE13AE345764831DFFF96639EEFD679F21 -:1059E000BA249CEF66A153003A9F4E825690177BD3 -:1059F0003B26F785F9B87DC403E47F6AA34964F7C1 -:105A0000A369FE96B0C4FCFDAAC4EA7E5E7A6CFA75 -:105A1000FBC6568C1B83791E335ADEC3BC5A7709EA -:105A2000F3DBC5CE23C9C9E6EBEA48C17C52D718DF -:105A300011F3B15DBE2E01DE1BD0512EE3FB41A15F -:105A4000D7F7072CF18C07B8C2FB20E7075CE1FB16 -:105A50001627CBD35AC7F7D99BCDBEA631749CCDA0 -:105A6000AB9305C087D64F7132B9726A8CE6470A8C -:105A7000A21F293BCF63837B2CB2FDC8DCC4551227 -:105A8000C4FBBEB7403FE66745386C1EF26218E2C1 -:105A9000D82BC1BF027836337A5AB95A40BF2A850B -:105AA0005F3FD0139F3F66B905D631A059F0C0DEE5 -:105AB0009D9671E73DC5656574DEF238EE0BC14D0C -:105AC0000BE3666FFC00E7E54AB0DE7A17BB27FF01 -:105AD000F3CBD0C7570E766F62766D07BF1F2F8C42 -:105AE000F7E005B57BBEFC25EC7E13C9AFE8F36398 -:105AF000A2FCB394D321F1439CADB2540E811F415B -:105B00006CDE3C05D63D3D682137D1F5B5081D7EDC -:105B1000E0177584C8EF53F21F0538AD59D717F356 -:105B2000F0968BFE6CD0C3EAFF91314E77C07F7E3A -:105B300003DC1FBFA95446BE380070A7F5A797E441 -:105B40006E8638A5ABB6BC6D3A1D2FE49151B234C8 -:105B50009490B7F3214EB944F408B47FB042CBDF40 -:105B6000F6E0799EE1A6AFC617401C2F43449FD2B2 -:105B70002981DDDBB06C49B907F0BACC9326E8F790 -:105B80002F77723A389A5271A793C2C7FBC87A0F1F -:105B900035E3287FA65E057E44B55956B6B3782115 -:105BA000DEF790CAF192DA2186ABDC5877CE4A81D3 -:105BB000FB7499BFF4D19B03CCCF09B1D191E8E735 -:105BC000E47F5EC46B1AAFAD1C6AC74A6B7D15F6E5 -:105BD0008771D2E938A9256278241D774BB27F13EB -:105BE000FAEDC65A114E44EA6C033885C6F6C3BCBA -:105BF000F0F5A306BF07E758520F754D063D1ACAC8 -:105C0000B2FF6933C8A965B2027C9EBAE4E43D786C -:105C1000F99BEF170F4299DAF8D1C320A7933BFF06 -:105C20005687CFC7C906FF62EA275F7E0BEDA9152D -:105C3000B2C14FF94D4AC5CF012E9B0A8341BC1713 -:105C400013309A1E5DC7EEA51DE3E0BEE3539344F7 -:105C5000DF16DE8EEB6AF5845632B895805ED0E0B2 -:105C6000B65C54DAC3B0AE8956A48F3CD281F22A16 -:105C700003A2D903A37849FD64C542C8D7889DCF44 -:105C80001AA7D07DFF06DC1308B882FC1839630C14 -:105C90009E43DC53DCE1057B7E7582FB73DE75B1D0 -:105CA000F72D22F3B3C6B6BFED62F40022B1AD18F2 -:105CB0004B7F11944EA226419969C5FBE6F688CA2E -:105CC0007F209DAF3729801FE86FA6F8DBFFF669BC -:105CD000F42FEE0F7E80E5B3AE02FC1E6D0FA7D34E -:105CE000F7D794B0FB8ED778188D5437337951EDB0 -:105CF000EDB442DCA4BA9078B6707A53353883BFDD -:105D00008CEBABCADB195CD30A09C67DC11704F75B -:105D10004DA5433F0ABFB4E6A50B118FA4431D4810 -:105D2000FBAD8171013F8D2CAF9F904E2BF26FD058 -:105D300084714FCAEFEF825FABB2A52FC6FDE1F8C9 -:105D4000308C97C2BF9BC2C7DB4CC701FFE1A9667D -:105D500013D982F2AD03EF675796505A46FAEC2AF0 -:105D600083F39A4A89C7B352A3034D8E51D6984103 -:105D7000F505C06D86AA2E04FA3B6EF5BC0DF370D6 -:105D8000B45A1458FF8CD6971683FDE2F07636830A -:105D90007CA82E65F34D69A1CFD1CE51DE85FED50D -:105DA0002D16857D8FC3AF84D31987C34C3EEF99E1 -:105DB0001BD9BCED59A120D067F5120A57680B30EA -:105DC000BA0797E82511F9EA10ACDFA5A6E3B87D7C -:105DD000A6C4F0450CFD69EBAAE4EBAA5CC2D6456B -:105DE000383FD1698561DCCA12B6CE1984BD2FC295 -:105DF000733AFE4CBE9E4AF5452C67365B0CE36F4A -:105E00002AD8D601F3C92994153C3742D87D87D9C1 -:105E10007C5DD98DEC7BD9852F22BC48AD6EBEE868 -:105E200057D5D5295F9D7A8B3216B573856C2B12A9 -:105E3000D3F19FC918CFC96B35AEEBD48AFCAD70D6 -:105E40001EFCB3C7648C7BEF117D4707E07E545680 -:105E500098FCF17D3001E4F4CC461FC8F1DD650CFF -:105E6000FEA76E2521A08741872A5200DE830E05FA -:105E7000785983F1740A10A15BEED1F9D12D53B397 -:105E800000F23232F0B95920074AD9399F2CFDBCB3 -:105E9000E9FC529BD3CB211F2AAD34A55CC6AB5D78 -:105EA00063DA0F3D315984F6834F3C08DFC920BACD -:105EB000F5D076D93D909D6B39485BA15FEDC94720 -:105EC000001F2DFC1EF24130B3142C0F42994AF9E9 -:105ED0007B550ACC53226374F7586E7F6C249E0363 -:105EE000C794A7622CC324CE3D97BAFE43787F5552 -:105EF00088D3CFE5560CFBF3ED8FDD3804F6F16B5C -:105F0000C04E4C8273BC9EAF204F47F58908F735D1 -:105F1000E6B0B590D69753BB11EC97B5051F89C075 -:105F2000776BF6121FD0476AC53F2D7A3CDEE462DC -:105F3000BFCF23C96415F0FF812127C7019E42FB13 -:105F4000A9DD49FB97FFDEF98403ECA13FB23C9841 -:105F5000CD6FD5A0FE7E285B8E7B1F2FB98C9D1840 -:105F6000DB3F65D064F4E70D685D370EEEF7AC1EDD -:105F700027F96EA2BDD35ACBCAC08E512A2875F517 -:105F8000A5F3DE387C2930A13281C5CB9471ECB900 -:105F9000328695ABEA0E3D0AFBF6E04EC99647E71E -:105FA0003B7405BB576C55E1796B80DAA52565CF4D -:105FB0005B6FA5CF4F94502D489F9FB8FEBC0DE25C -:105FC0003B4F9794A7023CF7361BED3A02975DD101 -:105FD000FD509125E877D179B57C48109E264BB8C5 -:105FE000AD92D64D2F39C1C2E9B1CF59D1B2790A9C -:105FF000D0E98C0219DDF6B1EBFD88EB93E9B55DD4 -:10600000E3E07EFD1C9530FF7EF07114CA33B9C801 -:10601000C8513B50E8B85AD9FE2428F9DF04B91C0E -:106020002C0CC8F08A26CF5A0655EE0079F6676E1A -:10603000D7919A5978BE0CF9DF04F6505759BC7DB8 -:106040005389D38EFD4F6DBCED63F053CFA865F639 -:10605000FE808D5F09880F6AF765D0F10794E055DF -:106060008364C692A0B508F09327124581F9B41352 -:10607000D82704A9FED1C3411BF7BFFBFE429705F9 -:10608000F9B0046C67DD7A9C7C3DD93EBA9E387AC3 -:10609000BA987FF7A74F7DB57F14C07F09DB220D2B -:1060A000081E13ACBA790C50AF6C1ED7C07860BF15 -:1060B000BAD8F9535749279E938A95EF60CE03DFEC -:1060C0006E729C1BCEF6F74679DAA3CEE92AF679F2 -:1060D000768CBC2AB2B4DF8CF8DDCDEEBD868C5850 -:1060E000681788A8B07B3F43DAFDD435D06FA8CBC2 -:1060F000E9013A6819F25131C06735B717661612CF -:10610000DCAFCECCEC407B617A23B717245F130859 -:1061100059C7C664B252673FA0A9045BE8466E2F18 -:1061200068FA9FEBED6A6F4733EA55B00F747AB5A2 -:1061300052657A758097E9F5EA66FA1D8513F3488A -:10614000BD5DC2F4B8D2CAED07AE8753F977D39AD2 -:1061500099BE4A053BC20D69102AEA658C61A547C4 -:10616000ED963E854C5FA6B6EC41BDD60E87B64790 -:1061700080DC60FA32EBBDC32A80C94B1FB75139AE -:10618000FD246FF77AA87D9612B5CF968B3CDE443E -:10619000987D8839FF749E8F427F9DDDB88DCF6FCB -:1061A000CFC1945B40BE6E0FE6E2F9728D6FD1FBFA -:1061B00049EBD9252C7F25BB96C5C95DBEAA1D26F6 -:1061C0005D1C62968BDD3B344BA3ABDAB017C60D7A -:1061D000C2FB28C7D9FD3F2BE0BE1EA017BEBFBA29 -:1061E000CEC9FD1A9C7E12E9134D0EB988DF5D48B9 -:1061F000E17B22B403E5B54AF74BB0B613C1867E06 -:10620000F703BF072795C0FCD78CFA3BE67F0C4805 -:10621000B05FFC54DB677E47B9EE1A7798ED433BDD -:10622000C4B8E77B32DDCCFFD02E1107C0D3166493 -:10623000F7C8D94AE5B8FD93DCCCCE3ECDE1B666D1 -:10624000D40E3CA799503F4B4435C5D1A79ABE6D9B -:10625000013C5F47FBBBDE6E52719F1EAA30A17CE2 -:1062600025B8EF0C924EDC47AA0532FA0D5BCC4103 -:106270002BE0636D09C7ABC7BA19CEFB7E67BC5074 -:1062800078009E57F8C5909003780E798A985F073A -:10629000EF413845F7EFFA78C510B7C8E1A4E00F31 -:1062A000F30D6866F4B566948CF358393C7DB329D8 -:1062B000472F7F052E3FD939B195A3DE44FABAD2D4 -:1062C000F955D53EF7D4095D3CF1E486677201CEFD -:1062D000BA7B307A3D4F5155FBB7D66D71E204DD84 -:1062E000EDB08F72C23E30749721AEC9F13BC62D1E -:1062F0001AFC6E205FCDB8B908F503FFD2EED121AC -:1063000037BC4796B0B8ED6C1EB73DBDED363C5777 -:106310005E44C9CA1C07EF5FD619CFDF7FB9FD996C -:106320007ECCAF1132E409CFDEF1CA50437CD84FA6 -:1063300094B491EC1E63D4D36FFA548B297A0F81F5 -:10634000763FD695DEB79542CD30DC77910A2CD3D7 -:10635000490D965E12C4B21F6967E766619F3B10E4 -:10636000F44217960AF1884427F773890FEB79A452 -:10637000024B09F0961A8D4B483BAD98BF01F10BCB -:10638000E0FB44E7CE7CEECA856EE4EF9AABD9EF32 -:1063900018B178C564B7FF0137E2218CF27B3A1758 -:1063A000E5877E35B41DCE1F3DB09A9D7BD1E43B81 -:1063B000EE6FE8779E4B61FA405D2FA01CAB774CE7 -:1063C000FC21C2B3C57C461F6F20566B1EFC3E8865 -:1063D00036EE74EE6798CEF520B8BBD9F9411F9E12 -:1063E0004F9A0EFE065D3BE96E67F7D968E3888E2B -:1063F000EB07F716EFD3BD8FF9D19531FB80CBEAD0 -:10640000EF98FA8CD8F7BFA1134A8FFAE39EFBA14D -:10641000928DF4CAF537252805DF6BB61CC3FD58ED -:1064200070AC5F0F9767391F687A65464CBE476C42 -:106430003943E2FC11330ED580C970AE17EF96D008 -:10644000F1B7763FA9F6BB5AB3FD013983BDE60526 -:106450003C7AF8BC83646379062DBF80BACEBF7FD7 -:106460003829F0925BB71FF1F86B44FDBD377339E3 -:106470003F8E35B594819C3B15203ED847CC2635C0 -:10648000EE1F803FFFB009E55C7F3A6FB918EF1D42 -:1064900053C514ACABF07B2F67EBD839A193FC7ECE -:1064A0009A1DFC7E9ABFF07B858BDA164F043A3832 -:1064B000CDEFA529D8BBA202FC3E45ED8E69A0F721 -:1064C0008BDA4757437BD14E0BFB1D1F2E27B47928 -:1064D000C1B96C3BFD4E26FD9E3505E40941BD7BEF -:1064E000B6C51E82DFFF39DB6E62F7AA168A789F77 -:1064F00003DC8B66E2F34B4A81EFFDD7BD608F9CD6 -:10650000E6F2E48C3B99E14B5205350DD252880FEF -:10651000EC9A758EF9780EB2CA19DAF1441AE4874A -:106520005B7DF5F4FBFBF7BC940DCF1F77CCC7F276 -:106530002F1B3ECE06B97576DFC7723CBA9D278504 -:1065400065F04FCDD92B88103F296B9F26437CA443 -:106550006AD77EF42BCFF304B07D6EDB1EAC8FD9EF -:10656000F51EC64F06262938AFB31901F4F3E6B578 -:1065700059C2F07B1CBB7383F7C78DDB27313DB35A -:10658000CEF11A8EFFB8E3B537112E1B2C78FE63BF -:10659000FF86DFE3B867F6BDC4E74B305FF0ACAD14 -:1065A000FDE8CF417FEDE1E731AD1D6EBD3F584ABB -:1065B000120CF2F5AC8BC7BD322FD38FE70B1267ED -:1065C000879BC9A50E37C4CDAADA191CFE620ECB73 -:1065D0006047CE691714F83DBDB25D9BF13CE09C6D -:1065E000BD563C2F3107E00170A3F042B8B4EDC7AF -:1065F000F9E7025CFAC03A3EC07CFCBCBD142EC375 -:10660000A2EB9EE30C20BF6AEBA57060EBDE7D3948 -:106610003C058C786A7B4F06BFCCDCBD02C26FEEB6 -:106620002E368FAABD6C5E63764D43FC9FD947140E -:10663000F0B79CDCF3F16958CFD97D56BCCF579B9E -:1066400017A553E22E06FE61744AF632B9AAD9DDC7 -:10665000F342E9F8BB03DDEDBBD8EF9202C86C94BE -:106660005E8BF64EC2B86009102FF0BFA77D28FBE5 -:106670007DC16036C075F7E87036CCFB8CF6FB4800 -:1066800052301BF0E273074A9274F8F8F2D84BA824 -:10669000170BC49A4F1F013E7E5E44BB68F127EB87 -:1066A0000CF7ADDC003F483502E0F6AE1BE1D67DCD -:1066B0008F4B90E54B9100F26315E7C7B39BE9BEA2 -:1066C00093AEFFCBB617B0FD6C8631BFEA2F6DAF2E -:1066D000A700DC2AF9790C12BA0DE511854BB33508 -:1066E0008E9EEF3ED71662E715CF09FC5ECDA7342C -:1066F000B8D5C8930D713E260F3337E61CC47D46CE -:1067000028FE39C7583B29F6BED444F900C7B93C26 -:106710003BC1EF3FD0F4EE6477605A529FC4E7BDAF -:106720002B57CDCB067857C2D948BC0775FF4DE033 -:10673000AFC07343EC9ED430C0E7A4760F2A79E94A -:1067400026C8333D99CCEAB5491DCBC1AE3DA9DD84 -:10675000ABAABEC1DECF61EDADD04EFBFFCA5D512D -:1067600093C4EC7B81FDBE8F39197EA741D31B8971 -:10677000E160FC9D8667E85A012E74BC9FE37812A5 -:106780001DAFE8FB8FA7C9E9EF3D8EF57F761C4D65 -:106790007F017F42EA23F1F986FE4FC0EFBFFB3E47 -:1067A00009CE34F0D5C50D039B208E7681DF23639F -:1067B00069594A409FCF6C5D17F7F7DFBAEB3C2F62 -:1067C000471E48F94DC7D78792985D7E88CB69F8F8 -:1067D00083F89676CF24FCB5A463EA12EE9FF3F912 -:1067E0003DE6052488F6E950D28E6521E9C072188D -:1067F000E9C212C3CC03C155EA33F1FB6847C2E2D8 -:10680000E75A034FDB44CC3B7803E410DC4B2B9876 -:10681000C09E9C7F1DCCFFED240F8757D8F07B2BAB -:1068200044FF7B180AD88313BCBDD983C4239DE9D8 -:10683000CE7BC9C57B6DDF4BC2F525FA1DB5853111 -:10684000F7DEB073E11A1CE69176CC237963E3039B -:106850006F0FA1F0BF7F970BEDE4C11B1B17823CAC -:10686000BF9F74A4C339E1C1FC1E11D266FCFDA612 -:10687000216D16E3EF08C7FC5ECF1CB88704CFEF8D -:10688000199F6BE770F11EC838F918B1E778FF9AC5 -:1068900014FFDE175218FFF75062CFF1EE6A17317E -:1068A0003FEA01C8BBD2ED2F866CABB118E94BF9BA -:1068B000B73CB3AE2EF8983FC265F76F177A7EE704 -:1068C000FF020F2194E60080000000001F8B0800EB -:1068D00000000000000BDD7D0B7854D5B5F03E3391 -:1068E000679E99849964924CDE131E2128E004432C -:1068F0008C68EB49881811EDF0A845DBE20404022E -:10690000249940D1E22D2D131220206AD08840090D -:106910000EF828D64727BDA888813B20225AED0DC6 -:10692000D5B6D45A3A20554484F145B9BDF57AD745 -:106930005A7BEFCC83A460AFDFBDFFF7A79F3DEC90 -:10694000B3DF6BAFF75AFBCCE50E85B14CC69E5654 -:1069500094DBBC2319FB12FFAE893D6FB1EB181B12 -:10696000CBE0AF8D4D2C67ACB541B5AF81526BD04C -:10697000AAE99DF0B4EB824A316379A9D5E6F950D2 -:10698000660E9D7D989BB109FAAB0FBAA1BDB151BE -:10699000BDDC04E5FDDBE6F71AB0BF4B6526983297 -:1069A000CF01E34299E5E882C3A0DC66FFA5631648 -:1069B000CC5F6283F7304E819D05DD30EEDEAD7732 -:1069C000EAB0DCDACC5836CEA3F87ADDD44F658F46 -:1069D000E1B29836A92C8BB122FC27CCA3B2B51F0B -:1069E000EBD318AB693C6E89D8E07DA46E121BCD49 -:1069F0005895BD98F6A9BE73FD0758DEB2E498C35A -:106A000007F3BDBA75E56F26C0788620AC0B8628E3 -:106A1000FDA2F5ED09305F74AB916D633138142E32 -:106A2000558F45CC3421FB12FECB5F9C5836322863 -:106A3000978A7231AE23AE1ECA978BF9199BCEC2CC -:106A400059582FD6EBD418837532BBCDF9DEA58CFF -:106A50005D6357D8978363E5B1A2BCDDD0516D85E6 -:106A6000756EFF93E26981EA7D5BE714E1FECEBEBD -:106A7000E02BB2C33E9698D346B341E79F9FC1EE49 -:106A800016E717B0E85CF80C5B982BD67EC4A3CD54 -:106A9000261F8CD3B68C798E0F63CC1CDC6FBD1493 -:106AA000CFF1A0C10345B64261D34350AFDA981687 -:106AB00082792E17F892FC5CB1CCFDABA186D8BCD4 -:106AC0002BBE983A1DCF379A6AD5B629E7AF4BF659 -:106AD00053EDEE009EAF219F7952603E83B337D7CE -:106AE0000EFD2E7DDEE8B101C826FC62E4A008CCD4 -:106AF0007BE94BB730772A8717AE575D62F41CCF1E -:106B000060CCB4C4E9512FC77636C2C74F6CC6A05B -:106B100009E1BFE4EE0EAC6FDD5AE172C7E1F5CAE0 -:106B200065768F0AEBDCBCCCEC5161832BC5FE9201 -:106B3000D757E0D07983D0CFA8633EAC5F04E7801D -:106B4000705C644FA1E74251EE52035370FD5D80CB -:106B50003F2D88AF8B39FE2ECA310711CF17BD3AB2 -:106B6000249BF54357F2F9F832976728AC63F3E2B8 -:106B7000992E065DAB16EEB75C07FB5F946AB623F1 -:106B80003EEAD34A1EBA1AF1FD350343BA6A4DAD47 -:106B900070CF8A1B4F9F56E94278E875815C666723 -:106BA0006C957D46AD9A83F812D8C43C8CDDD771C4 -:106BB0002D2FA7067215A87FA8E37A5ECE0C6C5223 -:106BC000A0FEE18E1B79B92090AB83F2CF3A26F379 -:106BD000F2B0C0262CFFA2E3DBBC3C0AD690CBD897 -:106BE000F31DB7D40660FE568367BA07E67D06D666 -:106BF0003F12D61F12CF17ECFC5C65FD2FF13DC094 -:106C00007B877826D73F27FAED1CA07E97A8EF193F -:106C100060FC3DA25F7880FEFB44BFFD03F43F2093 -:106C2000FA1D1CA0FE3551FFFA00E3FF5AF4EB1DDC -:106C3000A0FF6F44BFB706E8FF3BD1EFF000F56F50 -:106C40008BFA7792C63F22DA47C4FBFCD4F6B7032F -:106C50008077F9C0B7F0AF34B53D1DF16E7373396D -:106C6000E17FEB58C0F391317CCF579817CBA31D30 -:106C70002A8D371AF9313CDF14E3572D1C7A1FE2B5 -:106C8000DDA237F41EC4C356C573D807E30716EA5E -:106C90003CC87717BDAAE778BE500DB238FA7E33EC -:106CA00069FD5BC4FADAC47A7F651F4C7453B4C4BF -:106CB000E59924F925D2BD3DB16C067AD260FE3645 -:106CC00027972FA50BABCDC3517E807C41BEB9C2A7 -:106CD000660C9B60FE157695EADB9CD576AC0FD8EA -:106CE00055923F2B9CD5E659C8576DC0EC2A603EA3 -:106CF0003B1FBBCDAED606917F386AA87EC22F2639 -:106D0000D9918FB6B1A8A30AF7B714E40AF4DFDB70 -:106D10005C4DEF8B1C9F39903F1F4AE7FBDA9F7A4F -:106D2000C0520CEDD43B74242F4AEC2AC9B1C14B9C -:106D300075413734D96F5FA4C3F2236D5C5EC15FC8 -:106D40006A19CC3F944FCFB6DF59F15A29CAB37BA9 -:106D5000548FDBCDDFA971F26028CAAB349C373D7C -:106D6000415E7595330DC70DB8CCC1C760DCA12A53 -:106D70007365A4C7E05EE4D073F9A29FE441B9361D -:106D8000A423513E15B7C7C92786F232513E25CB01 -:106D9000AB8266E08F71FD4D2E7B42D9E24825F92A -:106DA000043CC6F3254CBDA87BD1755616E3D7C964 -:106DB000F2A855C807C9775BBFB83C413E48BE9CA6 -:106DC0002C1F2ECC5FDFBC7E38E121702BF785F9BC -:106DD000EC9B8807807F069F42F283A93E9737F598 -:106DE000C2F03218BC76BBEDC2703364BE457A8502 -:106DF000C1A7D2F8E7C9950BC055B6339A1FE93A37 -:106E00000E72EDB3777E58CA806456026CE8FC338C -:106E100075C1C760DFF94B9EECC2F1F30E58DB1071 -:106E2000CE46D7ACAE36DC4FC7438C013EE9CD1C15 -:106E30009F8C39D576ECAFEA3457FA10283FF1BB76 -:106E40005B15C0277D46B387C1B91D7CE6B5F41B31 -:106E5000107E6F1888CE4D3AAF9D0DA1E510BEADE6 -:106E60002AB06E5D4378EC33239CF2B79B490EB099 -:106E7000C0A3AB3540EA56380E360EEBA7AFD6604E -:106E8000DFDB95BEF2F5580E058DBC3DB068FCBF4A -:106E90006E9D22EA99A6BA48EF14F5BFACADB91AB7 -:106EA000DAABF64B55903B8BD63DDB6E28C07A9D16 -:106EB000ECAFB14AD82FCE27CA2A9CCF93FB457D91 -:106EC000E0A5F61A20A26EA39C9F05B07DB74EC721 -:106ED000CB819E761CFFE96AD13FF0F86A2D9FD6E0 -:106EE0007383DE0145C72BEDB62B63EB5D97FE4642 -:106EF0007B0BECEF2377240DB6C11AB71ECF42F9F6 -:106F0000BC6A7AB317E18688EF05993848EF263CCA -:106F1000ED3BB71D930379507BE6C0DFD246429527 -:106F20005F1F399002F06BDCD96C36407F93C11B38 -:106F3000C82B8EF56BDC5147FA8CBFA78C9EFDF4F5 -:106F40003BA80EFEA7FA998D1731DF47E1DF343DEC -:106F500005558DFAE6769B9EDA337EFEFDEF4FF601 -:106F6000FFE8A9DFDC8CF39D7647B22642EB556142 -:106F7000804B3FFD64FBA69D93E9793845BBCF016B -:106F8000EFE702EF227EA5367BB07DC8DC61F7001B -:106F9000A02D860E2FCA0D007D5057197BDEEF18ED -:106FA0004AED93DF27D357C8CC3226211F6F5049B3 -:106FB0004E85CC8194D1505E0B76480B2C6979D9E3 -:106FC000EFC68CC4F2B3368676496BC37ED748A42D -:106FD0002B8F91A1BEBBF6CA500ED2795BA371FA7A -:106FE000A388BFE145AED971FAD6BA7403AD63F593 -:106FF000CB407797C1D3107228D87F18C80D05F9F8 -:10700000A2CF8C768E25279D058AB19D6D2DD2E766 -:107010006A83AFB61ADBE5E848BE58864DABAD864D -:1070200075B832758A9ED65173780ECA37BB112552 -:10703000283B923E7327C2E949D5D38C74F8A4CD7E -:10704000660F4005F0480DF99F3ACC19C4B249CFFC -:107050009A518EE795813C8FD3638F08FE79C46186 -:10706000247EB7D6129A5C05E35817E9EC01986FB5 -:1070700075E3FADE0930CF4F1B9F3BD402EFD76494 -:10708000A90CD76173AA6123C81FC38DB04658F7F6 -:10709000D32D5E3BF2D768A6CAB641BD75A891B99B -:1070A000E3F8956D2494E3F8648653D52CD0FFEF74 -:1070B000E9BE7F77C0BC97BFF19619FBBBC6EA74E7 -:1070C000483621959F735A79E238F6AB13C749AF1A -:1070D00049AC774E4AACCF9A9658EFFA5E6239F7D0 -:1070E000F6C4F274896FC0736C208FADBC8A5923CB -:1070F0001F2F43790BF0F903C2DF5AA2F3207C2C37 -:107100008D8F9E9803F579C84FD01E1ACD48EEEEAC -:107110002BFC1737EA05A6F466B763E4F9F0C82B31 -:1071200030DF80E7651BAADA19B4B7BDF3C11738A1 -:10713000BE8DC5B52B46F8685147262FBB603DA9CB -:10714000F80F37C2BBF9CF3F46B97848EF4178E72F -:1071500035AA34FF3DD3DC413DD7275CA8CFA489B5 -:10716000F669E6B5BD7AE0E769EFAC5E88766F3226 -:107170005CB358B3827409F8C1EDED3A46F26395F9 -:107180008ED523DEA08D80E3917A04FC626A86911D -:10719000E0644A5784DDA8EAB03E4BE84FC69CDB6A -:1071A0002D48C72B0E70FC5F61E4E3F48DE7A64920 -:1071B00011E519F2C98C745DC238EBEDA28D286718 -:1071C0003A78B97B7FFA0D4897EBA7A58F413C3100 -:1071D000A1DD05E30DCA376B23607F96578D01054E -:1071E000061DA4B2FD0638CB6E2BBBCD0BEBD878B9 -:1071F000D01AD0C37BCBECFBEDA8A7958B75772F6E -:10720000F7BC897C205AA7121C2D991DF63123F951 -:107210001E02B03E4407948B55C33A49CFB3547510 -:10722000907CB7947574209C364ED291BE917EBBF3 -:107230008EF0D952103A3414FD04B375761C2F1D0C -:1072400004BF11067920BFC38B7E130630D755705B -:1072500054C1716987304F8680ABD3B9E3870A8CFC -:107260009381E38DE6ED114E0E01A7ABD3DD0477DC -:10727000A718376328B41FCDC769AB888D23CF719A -:10728000632D0BE2FAE4BC729CBEF199A6205F3537 -:10729000FC0AE006E7A4149A69712BE633B28FBBAF -:1072A000977B9BB7125DDBC8CF91EBCCAF463CCA56 -:1072B0003DB8698A6E34F6B3D23C86D92C88789C66 -:1072C000AB32F337D351BFF1121C93E935677FC757 -:1072D00054D453E5B924D36F8ECADAF5E9E7D371F4 -:1072E0008ED3595D32BA1F7A4EA2979C83D13B1040 -:1072F000E993E97A4BCAE932840B8B6FAFBF7059BF -:10730000AF0F1D423F0FCB063901A02F4C9A8FB112 -:10731000FF326159613AF7974390EF3B84FF06E4EF -:1073200015106BF718FB781BD2E94246F855FDFCA7 -:10733000DA5B7F05E39D1D66B4A35C2938D8D18B49 -:10734000F291EDF40DC773D8ACFA1E4E81FACD87D9 -:10735000B319F2EDD5166E8FA902CF93E5CB3A4162 -:10736000376E9473AE7FFE29F5C3D0D0AC4BED40A1 -:107370007BEBEEAF7DD59CF9BFA867B1A749CFCA1B -:10738000DFDFDB62C3F9D71D6C37037C2D6FF0F6AE -:107390001D500EA808BF06F267ED2B98437052DF10 -:1073A0003631C4D3517A2D8865F6470B43FEBBFDB9 -:1073B000D9EFD5BB91FF644D74231FDA26E83D2831 -:1073C000ECB3E4FDAB46CD87FA44F2FB4DE93A71EC -:1073D0009EDE1375708EA31E31B2355059AA9BD90B -:1073E0008EF65D7435F05FA89DA97737DD1D67DFE8 -:1073F000DE6BAD0AA5A35DB2CCCC7CA030E79F5379 -:10740000980F88B3C0F99B2AE43F852CACA09C2D33 -:107410006C068517F16AB195F9E2F03DFF9C4AEDE3 -:10742000EFB56AA1F4B1FCBD19F88081FF933D99D5 -:10743000EE65754ECEA3507F313C653D8A7C833925 -:107440006BB43E7B6430E22FC87D986FB7D8B7012C -:1074500060681803FFD97461D3E8F3DBEF1370524F -:10746000CDB630F24BD5F6FA61E22F76F5547C3B7F -:10747000B4BB89893530F2CB225CA8FC033B95F381 -:1074800080FF9AC690DE1F40FB3B90C6ED11A669B7 -:107490006E6716D20B2320E79B59BB19DA11B6038E -:1074A000BDE5B05E0BE9CDFB991BE9013D6CEFA595 -:1074B00010CB6208D7CD8CD5C6D3817C4ABF84BAA5 -:1074C000444FF6D4A52F59683D866616B4A03E8475 -:1074D0006B0378AB8B59502D8EF905473BDCD4CF2D -:1074E000C89A499F7DFA8B23B9C8A7AD07401FBB37 -:1074F0000CCF59477CCA6A4DA43FC65A084E5181E9 -:107500001F5DCBEC74CE7DF69BEF2D71CE91169462 -:1075100017858BD313CE57B6CB3F97C77C97C78FB2 -:107520001BA471F387EE57D02F937FAE90EABB96E2 -:10753000B92F30FEE001C6CF213C1A78FC7CAAEFBF -:107540000ABFE5B80940B139BADFE175C7F4EB64A9 -:1075500038E72F4EE4CB97ED4C2C4BB8580C9A7370 -:1075600032C0DC7287CEB315C6BBE27062BBDAE212 -:10757000DF92FD1B6B1F764EC5F6609F6F85B75778 -:107580009D486CEFAD7AD981741C6BCFD777CDB99C -:10759000C476C9E793BC5E5857E6B7E3D635DE6CD0 -:1075A0004AA89F5E77DEBA32BF13B7AEEB5C89EDB7 -:1075B0007D2DFDAFEB8652D33F5C976CF7ADCA8B48 -:1075C0006B97BC8FA9B5A601E0CEDB7F67FAC58DAE -:1075D000FBDDFA7FDCEEB625C9F30408DF17E9B45A -:1075E000F119503F135FA1BE68B392DE7B9E9D25CB -:1075F000E4D344543CA09F274D9B88FD6A25DD09B8 -:107600003FC3C1672EC946BE9E27FCE84CF815BA99 -:107610001B5CE457F089F6204FDA905F746F877E29 -:10762000697C5DF1FA534603B72BEC2C4AF42CF538 -:10763000A5746657B83DCEF59D81E6491EFF1E54E0 -:107640000061BDB3968C67EF021D3E67B457A96811 -:107650009F6D51481F9855A3E953013FC6B52BE4D0 -:10766000579A75D79B0FA03FE6CAE3EE9D11783F6E -:107670002BE8F0E0B44DBD4CC33841B67E61D98FE4 -:10768000E1F9E03E4671342C2F447CB3696EB43787 -:10769000EA704530CE294373991DF9E6F76D1AF269 -:1076A000CDBA69DA1F68BF7F07AD04DACDE65B6744 -:1076B000CF774E3662BCA3EE7BEE4AD47BEA42160D -:1076C0008D9E66A65A611F75A08FE133DBC8540BEF -:1076D0003EADCC8CCF8AE55CFF4AABF41AEB60FE82 -:1076E000BA9E9F7D8EFDE6AAE1BD5C9F0CD2BEEBEB -:1076F0007A5EFD0FD4D7666B5E23F28B4BB71BB956 -:107700004E2AF0615428B18CFC20BE5C164E2C5FD2 -:107710007E30B1FC710687EF38E1C7DAB7DB447C15 -:107720007BC18756D23F7781C0433B39F0B489E4AF -:10773000C7F805363AAF0F4F5AB7A25F6FEFDB5667 -:107740006A3FFF490B6FAF0B3D83E5C03329646788 -:107750002FC80855A4C3BA5FFC424FF0C66D19701C -:10776000FC67466C5D83F597872A302EF6DC258C06 -:10777000F562BD1A1C8DFB7CEEBFB8DF3AFA842996 -:10778000B80DC6FDF0859F3DF3239CF789BC7405B9 -:10779000CEE72A940BD06EDC23662BDA1BE33E7C0B -:1077A0006A08F28D05DB4D09FB7B264311FA833B0A -:1077B0000DF16E20BFE3B1D53FA3FEA5270E13DE6A -:1077C000ED32047418C70BACE678B6CBC2FDA4BB8F -:1077D0002C85413CA7DD199CAEAED26DFB6913EA46 -:1077E000976F703D64A0F14B5DB3BA6AFAF133F65E -:1077F000D5C3BCC570CE673EB0DE86FEB8E11B12B5 -:10780000CF694430B1FC7206D71366B2B8F7C5B879 -:107810009EC12B5DB89EAD8CD6537AE29D5B8B5199 -:107820001F37713D2479DE5F6770F9F9F39FC33824 -:107830009CCFE8B91E0E1003BA5E20E8E14585EB47 -:10784000C1F0B7380FF07F012A108363EF1724AD22 -:10785000438EDF22E0F4A9396D1BCA73A791E3FDC3 -:10786000C965071FC038A66CF7DE324DAB89F32B14 -:10787000CFD9B0F0400E9C7F437726D999F27DC3D3 -:10788000132F657D17DE9FDAAE7A50F56DB8E5F1FE -:107890007BC761BB27F4215C27D66B30FEA9D0CB18 -:1078A00069D86ECE66C718F497C8FE73375CABD53F -:1078B000C4F1D3AF4A4F92FE1B847DFC7C65EF84FC -:1078C0003C80F7820D8A079B2D087D7BEA8DA8EB13 -:1078D0006CD67B30BE51A132AF7E0C99EED3F0D97D -:1078E000D0FDEC815CA8F7EF1E5B81FB5AA3F3DEB1 -:1078F000300AE9658B81FC60C9E7637472FC85FE20 -:10790000611DF45F73B3AD1EE32230EE7E2CEF2BCE -:10791000DDA6473F7EDA09E06FFCFD611DF0CC1368 -:107920003D2B4683CD02786C6B47FAD8858E0B9C35 -:10793000E7693DC90916E6FB1827FCCF0BFED469A1 -:1079400054E179E2C4F2B42A4E7F744EC8D49DB09B -:10795000BFFA474611BDCEDD90485FB29D5CEFBCDB -:1079600060627D325E9438A5BF8295C6E35772BBD4 -:107970008C490123D263C312E0E77174D370BCC396 -:10798000887A57F23CA8413279AE7AC24BE6A6FD1E -:107990005AF87E41E535C37E4FE2BFB8DF5C41BB9C -:1079A0007EBE425B640B2E61356E80E78229AC1689 -:1079B0009F921F9EAA0C8DC6F6BB0C91C77F4A7C76 -:1079C0003095F8C1297B380DFD4AB9C2AF77CA1D81 -:1079D0004E433E7746C4EDB01ECBF37B401E005DA8 -:1079E0007FF89191E4424BE8A5343CAF53CF5874F3 -:1079F0003A38970FBB33AAD11F742AF4AB34DCD7C3 -:107A0000C9504635FAF506E213C9FC4DEA0347F1C1 -:107A10009F5782DEE3D4263811BE1864C8017993DB -:107A2000D15CD6DC0FDDCB7E4E637319E66944BFB3 -:107A30006FF3209F9DEA74D3FB3A858F877F18DF11 -:107A4000FBE460C6363CFF837B4B06A19EF00973C6 -:107A50000F42BEBD20CB7B33CEE7AAEEA5B8BE6BEE -:107A600022F3B4429F77F59E3BED00B7DB19C82D9A -:107A70007C96FB8CE46F69CBA475CD525958053CBC -:107A80009D8572753495498F99B55909B6C23A6E7C -:107A90005F9BB8CF399DA6D8F9C27FF31830442434 -:107AA000A0CD71ED60FC79283F017EF3CD2C9C02C6 -:107AB000E3CE7F34B1DF0216A6F5343CF5A5A93F2D -:107AC000387E2EE0B8204BF33BA1AC4C31D3BA7ECC -:107AD000F0B442F2CD29FC8CD1070705311EB64027 -:107AE000C8EBD9A6BDB41EFF5D75DAED8037679689 -:107AF000CCD26ECFE0292364976D50080F17D4B015 -:107B00007001AC6F418F121E85FAC45BFC9CE4B817 -:107B10006C0B6F77ABD07766035C507F18F79412CD -:107B20004805FE39DB0CA61CF211B13FAC1F04E581 -:107B30007AD641FB6A64115AC75A3C47EECFA3F587 -:107B40007FFE163FBF71F55BF5B8A8837B2B28FE3F -:107B5000F729F3D039825EC22CE9E7E309C25D8BD5 -:107B60008353FDE6C4327B34AE3C18E10AE5387835 -:107B700037EDF8D2A4F503E707FBE44970C4E451FC -:107B8000EC3CBDF788388707BF3D2707F9C07DA8C3 -:107B9000BFE68A012A916F32E9D7089B617CEBE549 -:107BA0002CC1CF01FA15959F704E9BB8219FB1F55E -:107BB000061FC50B66E9BD0730B49592ED7B1AF13F -:107BC00076964E2B54891F682564EF2EE1E7F1D09D -:107BD00098E611CDFDD8B972FDEB95505887FCE0C1 -:107BE00005AE1FA496470DBE383A7B45F0B941FB60 -:107BF0002207F2105F9E55C82FBF51616D0AC0D990 -:107C000005C782F260A372F400CA8F8DD7BB592BCF -:107C1000D497EF98BCF065B295AD94D7D3B8A34A8A -:107C2000DF68A3FD737D35A579AB0EEAB36F2B1D1D -:107C3000837402FBBE6D0ABC7F5DD06D8E8DE383C5 -:107C40006B79A07811FA65F77917BE8CF43DCA4AB2 -:107C5000FEAF6C80556A3A3DDB510F75B11605DBFE -:107C6000ADCC5478DE411D9BFECB918435EAA074E7 -:107C7000FE3C0C4F45656DE8CFCD5641AFE5EFDBDF -:107C8000709E07D3F8BA3275FADB26A35E3D86975D -:107C9000D3972ADA3642FE75B4AE6C13ABC57DE3DA -:107CA0007BD4C361195A37D507094ED9E39BCB70F2 -:107CB0001DD943F8D3690CE7E338AFF7E1894F8763 -:107CC000FC7AB190BB8BB75667237F7DFD945945F5 -:107CD0003EFABA4BEA8F611BEA8F6C68296F2FE47A -:107CE000DBE2B2F1D988F7CEC2C476670CDAA0CB5A -:107CF000514E1CD253BCE7339B36C801EDAE32B2B5 -:107D00007EF3ECBE10E7EA3FA7B0609CDFC03FFD0A -:107D10002CE9E7FE736AC2FB53CBCC2C18E737681B -:107D2000A8DF3701DB35B2DE95888F8DA114168C64 -:107D3000A38FABACFDCF2BE9C27F4ECF02FDCE6B44 -:107D40004C7C7F2E830532FA6B9795F81EF6915086 -:107D5000DEF9D7BE7DE07B561949433FEA2494877C -:107D6000503E13D4050CC0875E37703977DA1E4950 -:107D70009083A7DD112E07D14F64E37AFA643C6744 -:107D8000359A362535368FACC7FEE971FB3D3DDDB2 -:107D9000C8C2743E515A07C22F309CB14D3D1F1BC3 -:107DA000313FA6A1672FC14FE24D3C1C03F171A7E3 -:107DB000D6DEB00E784665E64FD78C1C0128B84F4A -:107DC000F287AE35E8E7CCD2EB12F8454A791FFFCF -:107DD0002076F52046C188DF6C59837ED25899B74A -:107DE0008FF57F78620D8C573E92F7AFCE0CBEB602 -:107DF0009C92443A38FF55A385DED4B8B239A96CB9 -:107E000083F2A8B8B23DA9DE9954EF4A2AE7F3F607 -:107E1000A752C3857A0F6337663E3A5105BE792A69 -:107E2000273C03F3C6D6B63E3EB106F859633997F0 -:107E3000CF4D3D8A877C7F027E4D1EAE37DA3C11E6 -:107E400023E6ABA594F71E40FED2B053B12B400FF2 -:107E5000B6507798CAD8CF1DD72FA450BF86D0511F -:107E6000EA37E0F8A53AA2F735A5C778BBD0FBA45E -:107E700007AC6A5B48F179197FD6339F96A7C4E2B5 -:107E8000CF92CF9ECED15E223EBB5BB1237DF6E189 -:107E9000298E1BE7F791EDFF38AAE7B7A866A42C57 -:107EA000FEB805F5D93F35BE3F16F5BB3F0A79B29E -:107EB0005E098EC0793731DF089497DF6F1CB657A3 -:107EC00007ED8E18225D18635B9BD93311F3E88EA2 -:107ED000A4460A300FEFDE070F103C8F6446BA103D -:107EE0009EC71F7C85D717440A30EFEEFECC4F7833 -:107EF0007958A40BCBBB1EFC132F8F8A14E8A1FF6B -:107F0000E0C0918935D0FF317BFF74DD9AC9F57BE4 -:107F1000B9BE2B866A3FC9447BB581CBA12EB089FF -:107F2000CCC03767CC3FF9F463008719FF9242FC5D -:107F3000ECB153532772FD3CE0552BD07FCBFF486B -:107F40004E12BF57C96ECE41D9981E3B8FD4C25E28 -:107F500037C9914B9ABB51DFC89E3192E4488D538B -:107F6000FB0BCE2B9FF7E7C113DAFF25D3CEF9B772 -:107F70005E47F1ECEC1FA5927E769F85EF07E886C1 -:107F8000CED726CE6383D8CF864C6E57363AAFA570 -:107F9000716E15FA74E7EAE0131680FFDB324F6664 -:107FA0001DD7CFBFBB15F80AF0F14E879683FCE4CE -:107FB000BB22EF4DF20F7C9F1E6797749641D91636 -:107FC000B33F3B276B3956273EB37418B791FCA8D3 -:107FD000B398F7937229BB95CF9B7DDF886DB88FDF -:107FE0001495FB9F664F2FD9D6427AC1145A2FD3CE -:107FF000B41C05C63B3E6FB00EFD52F27CA60FD5F9 -:108000007E89F0B955F8F5E539C9F3FC8BD8F72C22 -:108010003DE815B0CF77B37C341EE819A385FF8BFC -:10802000F48CBFE019C7C197A991B1F8FEFF2338BE -:10803000FDFEEB8053E312E017BA8BE017027EEBF4 -:1080400095B0219BF30BB2A7F13DCA9D5F3A7D1F0E -:1080500066C6E5C7CCF85123E995725D293F7CBE21 -:10806000F63BEC7C3A4BD6FB3EC7F38AD34F3DD26E -:108070008F29E639F2B699E216478C21E29B47C078 -:108080001E6A41FE22E2EE15FFB2E075B407E5B8C4 -:10809000DFCDD2737FB03C77C5DB3DA718F35058D6 -:1080A000C08CFB986CA4739772B7D3C1F34A3AEFB4 -:1080B000CAA3BC92332CC2C81F5AC9883F021E50A3 -:1080C0007DF4962CA27F681FB060FB7997507BC02F -:1080D0008B00F1875BAC64BF74629C1AEB6F290D57 -:1080E000621E0CDACD846FF374346F3FF8C2FDCD9D -:1080F000C3799E85C49BAC56EED761AA367A729C32 -:108100009CBF228B9F734A79E4D9DFA35EBBD64222 -:108110007A2DCA588A097564D33870FEEE2CEE1792 -:10812000203CBBFDDE5491CFE6A940B8AE4AE578CD -:10813000B9D9C2E3559B418F26BE28F057E6D3F943 -:1081400084BE17A9D7A5A1BE303AABCFDFA0A1FD51 -:108150004FFE72A89F19518EA2DD3633A00F9BD01F -:108160000E6BBF568BC4D931F887F1BEDB045F6557 -:108170001B18F90F6FC37E6938BE350DE39BB761DD -:108180007FF4D72EBD36218EA76571FA96EB4BE6AC -:10819000FB5A96F04B763CA4C5CF23C74F1E0FEC7D -:1081A000D12A840FC0393C08CFB7454FE797BCCEE2 -:1081B000C806EEF78E6C2822BC93E30DB4CE3FEBDD -:1081C000A377282007E78CE776BAB47F660B3B9A43 -:1081D0002D4DB4EFD0CFD257D69F5F4EB617313E5C -:1081E0009FD89EEB2D2923A346A25BB792B07E09B0 -:1081F000AF81E030F72BC24DCABD872C4007E9683C -:10820000862B84BF1BEE4A2139E6340647205E2DBB -:10821000CA7253BB4D9827437295DBCD9FBE2EFD8E -:108220001E89F6B2DF1ADD82F0F25B19D1D3E9DDE7 -:10823000A9443F6C686406E6999DD9656288BF4D84 -:108240004AA404F9D66945ABA3762D296EA423E987 -:108250005778F739EE57F02324617DFEC07F529E98 -:10826000937F67A21D7D1AFEAB07BC3FAD8B54E028 -:1082700078921F801EAD917E54CFE33F4D3A164059 -:108280003BEB2ADDCC799CCE73D9367A7FB464512E -:108290009C9E0EEDF62BE91C7D906E1A041C9B74BF -:1082A000C7A85D03E62B213CD1DE423F1956C6F933 -:1082B000759BD67E48F9524D3B12CFBB21860FCA23 -:1082C000970AF68BC30FA2E780E0078CFB3B6A7826 -:1082D000FC3A5594536A7B297FCA2FFC1F99FB22D5 -:1082E0001390AFA49687D84C78FA4F707D635CCF1B -:1082F000D697D0AE76D4F6162019F8859F509EB743 -:108300005CE7953DEBC8DF21F59438BB73C494045A -:10831000BFC372EA87762CCE17C1573988065CBE78 -:10832000AD17F22D050D6294831DC3490EA29C4228 -:10833000FE24ED60E457C82752B2ABF720BD3E9251 -:108340005DFD02E76B8067A8D7A35175E5C0FE3DD0 -:10835000091FD90EEDE17FE4BF7B55E0ADF4ABD34F -:108360008ACA31DF3A53FAEB28AEB748716723DE89 -:10837000BEA7F7915F6E2E0B909F681EFAC3E0D9DF -:1083800020E87D8EF02FCD117E25F4F7C6C71FD1D2 -:10839000EF1A5F9ECF7A39DFD86E8AE5E5A01FA875 -:1083A00086855361BC46F453E13394D8AF8945A91F -:1083B0009F7FE797A684F86627DFF76DE2FC1D35FF -:1083C000413DF2898D16EE9F92FC63DC52EEC71A96 -:1083D00034462B5E8178FEAA81FC1B7F11E7D6E72D -:1083E0002FCDAA7E290BE064D5F37B6CD11526E254 -:1083F0009BC7411E770BBFCA14B44397310DF3DE00 -:10840000996A2F8CB753E573CD2E4B3DE2CF67426F -:108410009EC9F7DBB30CB41EF237115F4E21B90BC6 -:10842000EC6334E257C5602917D968F4731D1576DB -:1084300073D3CD361F8E17D1717EA3647339A564B3 -:10844000F3BC3E59EEB3F304FEC8B821FA7DE2FD59 -:10845000EEE6BEF6EB843EC968BFEBE789BCF03EB2 -:108460003CD6115F4A19E925FE7B95AE9AF852F485 -:10847000039B1BE152FB61C33CDCC727D3AD74FFF8 -:10848000EF76E10776653B687CE9F7BD503CAD7659 -:10849000CD08E297B27D1E1A2863CFF71FEF127C3A -:1084A0006C17E3EB0D9CB0F23C15950590AFED0A0F -:1084B0008D08E27AEB84FF01F51BE4AFD167F9394F -:1084C0003295EB43BB7A460511DF8F1A7C1B67A3FD -:1084D0003FA7DB407E39A6069F781CC7D993E3C12E -:1084E000BCA1D3BAE8965F43BB5D277E9E8771A28D -:1084F0005DC25FDF600C9790DE2CF2241BD2C22598 -:10850000E8077A519C578315CAF03EC3E22BCF1E71 -:108510001B8BA7613F7C7F2CC8F5F2638CE3416025 -:108520002D8F97027C7366E37A5767533C0ECF0515 -:10853000CFE1DDDDA3685FEB0DA2FD0B0AB557A609 -:1085400094CE20B9B0C69481F03FE335529EAFFF80 -:108550003EAE37CED2B9B72C415EB92785F637BBD0 -:10856000F310C549FCF7CEA5FB93FEF94B6F62FFF4 -:10857000207E807225DEEF7D9A450BC91EAE1F1C42 -:108580000AC33A4EF78CF0F0F01FBF8FD324F249A4 -:108590008F1B9886EB8EEE3604FBBB2738D0F8E4B1 -:1085A00040ACE0F28DFCE3F1711A920789719B0BEC -:1085B000954F1B222577C1FC6B337C73B2E3F445E6 -:1085C000FF9E1CE277EFDEF3D742D22B3A789CE194 -:1085D000B8419B8174E2A8091B67C6E9613FC916CF -:1085E000F68749E88FC007E3E95ED6575427D2994A -:1085F0007CFE389BEB21A922AFE0FC7A99B736D5F7 -:1086000084F293BB96705C37BD2F12F1BA7127A22A -:108610007B313FAB215446F1C0A2A561A24B8077CC -:1086200018F5FFE31B53393F816DE238732A19E9CE -:10863000AF73F43C4F628E09F4612EC7A9FD7B1B1A -:10864000B3090E15CBB91E187D5621BE28E39675C9 -:108650008CF77FBEED68400FEDEBB62B65C05A5925 -:108660005D5B15E551CCDF5C4CE73F4EF0DF5926F2 -:10867000AD6423E2DBF33CEE05F391DEDD80B9620D -:1086800063882F19511ED66F5718DE3796FB4F8E11 -:1086900013B260629C665C88F36F941B2C4E5F93F0 -:1086A0007208E5054BD22313F12220E257FC7C7EB1 -:1086B0002EE02AF93F41EC1FC841D0A79F44FCA9F6 -:1086C000A8E6F417ED5608CE8DAC99C795841CEA40 -:1086D0005B8F9063EFE9B9DC9C635A47CF305E1E35 -:1086E0001B8B7230C2E520C835E48B03E14578006E -:1086F000BC90F8B017F701E3359C60E16FC07C0DCA -:108700004B59B871347FA68E26B9CCE5B399CB67A7 -:108710007C5A2F424E27CBE764799C2C87510CA1C1 -:10872000BC957810EFA7477D64DCD2A09EFB61F377 -:10873000ED981F28CFA5D1A91DCE1B1BD3B7FC8751 -:10874000CD66F76558F6B2C136F42F55DD5E00FBF5 -:10875000F7ABFC9E720AC0692BBCEF12FAF9E40277 -:10876000BE7F97C80332A85E5666C373EA257B3A7C -:108770009AC928AF5BC2B72B15FA8DC17E5CFEF596 -:10878000F537B3366B5CFFEA5D16922F675F48A53D -:10879000FB684CF5153960BCAC3F829E0EE5D3BB3F -:1087A0005249BE9F16FCDE29FD166C259DD76778C1 -:1087B000CE998875D579E8FF65CAC43C46F7B4B947 -:1087C000DED8E818C86F2FEA8B7B6FE6786622390F -:1087D0007BD611B913CBB01ECA333E25CEDDBF63A5 -:1087E0007CD98F303FC06BF370A8FACA506F30E964 -:1087F00017DF6CD6E37DFDA5D1BB601F8D0536CAA2 -:108800005FAE297AE777B740F9831D06BAE738EFFC -:10881000B1A983C2D84DD55CFDC9E7794143C2FDFA -:10882000B905DB13CB8DA1C4B23FE9BEFC9277B68C -:10883000BEB63FAE3ED395EAA4F377330FE65F337F -:10884000FDF706F9FAE197F2F9D765C1D7F60FA35C -:10885000FCB57C17CFCB31A25E3313F1A19F7E6FA5 -:108860000ABDC6646A3E8179F0A6174D74AFFE4416 -:10887000B66F18F66FD2450FE0799A8A4E8D463959 -:10888000585DF4778AA79DFD31F3207CCE5AAA4823 -:10889000BF39BBD1E246FBACB3D04678D0B947096B -:1088A0002A5C7F9F34B602E3A7B407E6DF70FD07BA -:1088B000FCD20633F37BF860BDB890CF68644FBD3F -:1088C00037D96A5F0EFDEA377079DBC07AD3900F33 -:1088D000CC7771FEE3D73F6534C33F8BDBB4112DFA -:1088E000B0DE055E2BDDD751BF50E99EFA2A1C325F -:1088F0004EFFAF72093FA93962ACC2F9FFBEB8168C -:108900005D63D2CF6532F834BC1766D85916CE8372 -:10891000577397BC44764E5F1C7A37E75B73EFDA88 -:108920004BEF9529B5B4DFF760BF089797369A6883 -:10893000BFEF15D8C8CE7CAF8BDBBF73EDC6A09957 -:10894000F48D7319789FF6BD2E03DD633F1F1ED78C -:10895000D1BDD6F737BF427EB8F7199F37B0434F26 -:10896000FACAFBF6684518E1E86E4E437DB77EC350 -:108970003CBA173BB74BEF457E36B7EB8E5F5F894E -:10898000FEA329B796E396AE712CCE72DB62F55248 -:108990004F55D32B1F473ABCE68BF1BDD7A0BED4B1 -:1089A000057452CCF3EE514FDFDF751DE9A5732737 -:1089B0005B1DB82FF7E6C726A0FC787F722EDDE39B -:1089C0009DFBB4C2F0D30D731D4BB2F0FD5C45F5B9 -:1089D000F6874FCCC5FD6D5545364F18FBFD564FFC -:1089E0007802747533CACFC62E03E9BDFBA7BCFD60 -:1089F000BB5B9C31BA52A66CB8691CB6FF9981DA90 -:108A0000F7E93B9B6F94F8C2C215685771B825D33C -:108A100099A9686909AE2B99DEE62E6F2EE1F1ABBC -:108A2000AF46776C33BFD7DBE652D897BAAF4477FF -:108A300077BBC65E3CDDB1FCF4047BEA7CFE16200D -:108A40003C95FE7FB387698FD928DEAB29C07F773D -:108A5000B8F8BDF51D2E7EBF4DFD8F45DBDF00F85C -:108A600054BA7C5DB88E22A695A1DC7447EDD5780A -:108A700017C926F439B6D924ED00D2EFD767B2C7AB -:108A8000D7C4F91F422E6E27011F781CC739FD87F6 -:108A9000BF1FC0736A2A3C351AFDBEFE739F51BCCE -:108AA000D0D6C3E3CD364F94E2F006A797F050F24C -:108AB00077BF87CB9FF3E0E5E2F73BFCCE288DF351 -:108AC000560EE7CF9D22BEB2698995FCA99B9C41B9 -:108AD0000BF72F0418CAA749957A1E2713FAD68DCB -:108AE000C21F692E7F89617C8C5DCDF3C2DE287F39 -:108AF00049CD80F2AF2BAFF5D07DBEF247DA07E368 -:108B0000BEAF3688FA21F4BD8D7FD7AAA87E914BDF -:108B1000EF46FA9E54CEF322597D1AF94DDE287F96 -:108B2000D7797BDCFABDCCECB601DE4C01628DCF8F -:108B3000C3BBE96A8BDB16873F9F7428B55CEF7572 -:108B40000F9A368AFB45481E9727C26391CB48F39C -:108B50003E925D7508E17CCD37F9799C7CDA14444E -:108B60003E7852DC8F49865FC425F0471D9110B7CF -:108B7000771A438528273F5412FBCD6FD753DC7CEF -:108B80005EBBC28230DFC9279E2F447EFEC163CF09 -:108B900017CE8C5B4F723FF93C29E7137EC1643FCF -:108BA000EF40FE5DD9EECC06E6330F89B53F53FFAB -:108BB00037F2EFCEEC11FE614D1BEA447B48B44F17 -:108BC0001E2F3397F36B65A7427E0FE9DF3C76F0EB -:108BD000118CA4F49D9FA5A758179FCF289FE3C48D -:108BE000B94DC57383AD58DA7979A0F31A881E7F21 -:108BF00021E4903CB763ED4306211C8D4D3695F181 -:108C00007B6AA5A8AF7731AB07E9E9AF22AFD56999 -:108C10008527E869C65C970DF999FC2EC00FAD69F0 -:108C2000DBF0F95791F7EAB4C213C629C82DA5F1B4 -:108C3000FEAAF3925DF7437D07DD5F74093AC966CA -:108C40006145C14F1D2C784EA1BCAFF6447867B585 -:108C5000723912AD3392FC9270BF6AE69D64BFF622 -:108C6000735E1B108F722BF9BBC939C5C2DF11A10E -:108C70003882A592D9D1BE6FBD3240EB90E7E5E7CF -:108C8000CD99D2A390FE8CF92F29E9142F0D8827B6 -:108C9000B3A5B3BEF8418AB0775952BC201BF46E1D -:108CA0006C27D70965CAA3B9CF11EA28E1F156D2DA -:108CB0004B715C7C3F73A44AFE766C671C7361FC4D -:108CC000EBC35391973849BEAFB7F61B9F9884F713 -:108CD00083F01C403EA25EC83C8684FB419B419FC2 -:108CE000463B4DC67FF5BA50998BEC93DE08FA4FA0 -:108CF0008C156637CADB147DA814CF2F391E0CEDF6 -:108D00008A791E42BE03E58CBCFFD3B464BC17E372 -:108D100054A07F04CC787E93F9F935DD5545EF9565 -:108D200029A52D885FFEA58CBE5330BEA79BF2A45B -:108D3000FCB55C1FF3EF3C6A6480BF33853F870955 -:108D4000FF739638D76342FF8EC5BB225B30EFBB03 -:108D5000735E3EDDF74DCE2BF9AAF1CE33A900901C -:108D6000CBE2E25883CC5CCE88F397F42DE35AA98A -:108D700023BDC5A889FF2E3BFA2BEBD8AF90371245 -:108D80003878CF3FCE1B997613E68D9851CB17F5E7 -:108D9000B80C90A37DF7F92C6E8A7BF5D5E3771894 -:108DA000CC3B15717F8FDD74ED50CA3715E5D7D6F2 -:108DB00062DEF87D1696305FFCFAD4A4F10D30BE69 -:108DC000CD2DDA074EDE70AD4AF15F513F712DE6D1 -:108DD000C9DC67481C8F5050DE3F34C7E6BB7DF3CB -:108DE000867BD6E6C7E439C8F78D396363727DD5D3 -:108DF000DB933A2E73237D7D4AF9BB523EFB9D3CAB -:108E00008F24998F3D9AA348BD78028ADC55D317E9 -:108E1000D2770BFAE2BF3D751AEAC332FEEB5FEA86 -:108E2000A53C5ED007B6E7903E70EABDBD0CF5CE1E -:108E3000936417F8CFA9DC4F047A057E87C6DC530C -:108E400045FE504C4F1D1677FEF3859C421D1EE9D2 -:108E5000C1BFF93B8FE9B13E57EBCEC98CD987C969 -:108E6000EB7D2D87E7B9FB4BAB37223F608F2AF4B0 -:108E70001DA835A59F90DED1F4C2B563E3F3D0E71A -:108E8000ED7C90E7316F37F4BBFFD772F877629AC9 -:108E90005E7896FC9D2783FCFA4CBD1A5C8D7A683F -:108EA0007DBD0E352F561EACBB85F481E9B00FD8C1 -:108EB000572887C3C7BF7D6A00F3E2FDF09F02AF6A -:108EC0003679E7905DB069BAD986711C7FE9CC85A7 -:108ED00084FF76AB86FB4F5E672CCE6CA5FBCB6B1D -:108EE000761A6A518FAA00BDE95F61BD05E9136B6F -:108EF0003DC097F2F4DD653FB061DCBD7FB9ECCFDA -:108F0000E3E7D8A67803DF2A273F278BCFE329DAC8 -:108F1000C9F5B3A339C604BFFAD11C95E07975A091 -:108F2000773CE2DC1E3592827AB29F691FA3FDCBAB -:108F3000BC3637F977198FB33B97B9C9BF6B764603 -:108F4000EEBE8CF42895E2CCD2BE38FD02F78B4DF4 -:108F5000CDF59D46FCA8D0471EF816C2ED6E55F81B -:108F600089399F299C6A1B837E2C8B33F240AD9BF1 -:108F7000F26FC82F31E81B6D740E7B9CCC8EF019FC -:108F80001FA85395383923F9C6F8BEFB3B4EF29F14 -:108F90005673B6C686C169BD6726146DFB3223A61B -:108FA000271CFCFB34155F4AFD4167F6919D533346 -:108FB0001DEC46C4BB95D1033AF4D73B7B497F6C8B -:108FC0000C29344F63E92F293F6E81C8C3EACB8750 -:108FD0005223941F66CE4D117EA6368E97AC97EC29 -:108FE00062F614873FC84DCA1B8BE9F12DD44E8E13 -:108FF0006714718646E1C70140517D46AE22C65DC9 -:109000009E189F10F332D55D11EF77583F19240950 -:10901000ADCB9D86EBBDD7EACDCF85F6C7EA75040B -:10902000A263ED29F45DAAF54AAF86FEC84019CFC8 -:10903000A74DC6A33231EFA07DD109284FA22F0C36 -:10904000944FCBF367378EBD84F2D0CB777E3C0153 -:10905000F183D532A2C7A69D17974F5B81E731F602 -:10906000FFA17C5A8FA26D83E775B98EC47C5A0F1D -:109070003F2F19D74CCEA33D9D135679BE5B64CBD1 -:109080006368B7EF34519EC8A49DAF1C46BFE62469 -:10909000330B519C37497F38E29CEACD8579CE7CF1 -:1090A000F4DE96150CF3B09FF3F07B9989FAC0407B -:1090B000F600C53AE2ECC699126FBE267B40F26B11 -:1090C000BFB0AF3E54A2F796E0FE76EBEDFDDDA318 -:1090D000F1E7CAF8D80079203DFDE781C87B66B585 -:1090E00091E284B8D55D7D74F0D5E2604B5176F69F -:1090F000130753455E97AA70D6C11C3CEF47C6C103 -:10910000D4EE1114DF32C5E26061D64F1C4C1571EC -:10911000A55506AD8EFC34BB4D6E6E477B897FB581 -:1091200075677A90BFF9E79F7C063F05A03A26B89D -:10913000506F6813F06FB8F838D883B9FDC4C1B662 -:109140000ABDEDDD525DD80870DDCA38FF0DF4C8E8 -:1091500078988EECDAE83D05B46E658A99D6FDEE16 -:109160001ED336F44FCD9271AE3DDCBF364BC4B347 -:10917000DE9D5242FEA781E03CAB3D315EF0330103 -:10918000E7B3962AF2D3DF79FF64F2CFCF41FFFE37 -:1091900090D87D0926FC7CEE767E9FDEBD5DA1EF3A -:1091A00099229AE84827B5D3774D17001BDD84AC88 -:1091B0003700587305BC56740AEA43EE362883D24A -:1091C000AFAE56032E68B7F5700AF9155739DD2290 -:1091D0006F8DC79D036B95E0303E2E7DC72CD0A6CA -:1091E000D3709C5772B93FEACFB9C67EBF23D16610 -:1091F00010F163315F0B837387A74EE1CF55E23BDC -:1092000079C9F090E3B5199ACDE8DF8B16F0EFA19C -:109210009C356AD3C9EF9C5E42DF3D6A4B6D6EAFF1 -:10922000E5F544B3672D512FD57F43E50A2973A790 -:10923000E37A77E772FD2619CEB33B12CBC9719F53 -:10924000E47B5AB3986F78CE90F3EF31ED16FCF6CD -:10925000EC9A62712E1E8AA3B419DCBF29A6F829E4 -:10926000FFAE514B3E879BAE803F073B6AE8FB74E5 -:10927000402F5C8F637CFD83BFE154905EDA1C1C41 -:109280006FFFA7EB4E5EEFFBB9251CBE0E4EAF6D18 -:10929000AB952087175FF7C5FA490C795F2F5F7C84 -:1092A00057F13C1E2EA67EC41F02F71888EE765991 -:1092B000F8FD4BC9AF28B107ED4F61EF0E42651ABB -:1092C000E3A12756D2F78936D50F4EC378E9F8A91E -:1092D00036DA47D31E7EBFB77169A410F1BAA93A36 -:1092E00052D2DC0F5C710255F2576837D3C9F87758 -:1092F0006EDA13E37FC971DDB5195A415E26DA4B88 -:10930000EF76BF82E7DD6D21F9DAB434FA38FA0F6F -:109310007C19BEA1587FEAAEB727286EEA46FAFC50 -:1093200099DDC3E95EE2CCB6C47B5E6C6D625C9194 -:10933000B5A7F3FB6C9D89EFF13E5342BFF3E28C7E -:109340005CBF596FF48D40FDF39A6FF23C8A8FE653 -:10935000E9189EEB47167EFE817B5205BFF694C44A -:10936000CB83AA01CF17DA8DC4783ECF1F95ED1BB2 -:10937000F17CE15C1BC4F97EF4EC152578BEA7BA3C -:10938000AF28C1F35D6FE8D0903E52B27DD7629CAA -:10939000EDF8B55ED20F65BEECC5E2DDB4BCAFD76B -:1093A0003FF755E5719D9CFF2BCA63FC8BF79BEC47 -:1093B000F9BB3E6021F9C2EFB5C6FC7727E9FB5E39 -:1093C00067CEE914E4C7038DF789B0975C66164051 -:1093D0003DACA23A42FD2AFEA663A80F4A3D387969 -:1093E000FD8BC5B9AEC8D30EA35D28FDBDF5626C7B -:1093F00073F053AE6F3FAA903FD7EC0EA48D23FBC2 -:109400006AF6E57AE22FFF4AF725588F62473B65F7 -:10941000DEA32D547F7AE72CAAD799C361B4C71A6B -:10942000A11ECBABAE4ECC7F36EEE0F12069FFC281 -:109430003ADEC275A438A346C4CF26D4AF61894DA5 -:109440002AF77B37399927C0501F4EB417655C77D0 -:1094500093977F3F66538F42DF91CA32FA8AF3F1C6 -:109460005C93E2BBF7E769DD887732CEBE204BEB39 -:10947000CCE3F9678508A79FE2A2A01C31C87B5BFB -:1094800089F70F0FEEBD99F4A1CF997750FFF968D6 -:10949000C184F8FB1C714F748EB8278A7C3A9CC437 -:1094A000A7E3CB0D71F968E1FEF20AE2F2D1E2FB2B -:1094B000C5E7A38513F819A7FF6CFD228A7BFB0182 -:1094C000CF978C89E16103137F1BA2EFD2FD97ED4B -:1094D00026F2AB35887C547FFD31B257FC789F86ED -:1094E000D3A3C6EF61737DA801EC40CACB0D25E67E -:1094F000AD1EFC9AE953B61BC87FFE66123DCA7DBD -:10950000C97D34F4289C7E92D6996CFF26FBC1A5B8 -:10951000FD7AB17CE9FDAF591E7E55BEF4D9D7C4A2 -:1095200097CE8B270C8DA679BE8678C207EE8E2C3F -:109530007429CAFCE1F6DD3C7F7882DEA6F1F8A54D -:109540009EE73724C771DD13284E29E3C6E6E7F40A -:10955000C1E5C5D4DE83795F8DBB5329DFA0DE5D15 -:109560004F7A7772FC723EEB9E8047F1397B9DEE1D -:109570006FFD4FF306F2F3C57789DDACF82BE60DEE -:109580000CC9FF0AF1CB976C9F66F8E2F0A57A242C -:1095900028F02307CEEB2ACBE7F89722F24BCC6AD0 -:1095A0008039E2FA0FD4EFCA7CAE1FBF24F291EEED -:1095B0004B4DA17BFF2E23BFAFE0D2F1BC2996EB30 -:1095C000BD2A3F13E5013FCF875FF80EC3FB670F4E -:1095D0001B42740F3FD068F3A01C937E2739FE8393 -:1095E000397C3F174B47DEFCFF5DFE71AB9CEF62A1 -:1095F000E36F1B000671F4954C0F03F51B88BF2C1D -:10960000C8F7CEC9277B5C1B4D718B8BE44B29E5DA -:10961000C0B7514EEF30B9D17E403F0AC9C7B53906 -:10962000D2FEE6DF25B8AF80E4D747166E4FC8FB01 -:109630003F72FF3F1910DEFF9C9EF76E96378078D1 -:109640007EBC4AA3FB03AB52B97C893EC1F387922F -:10965000EFC124CB15798F43CE777FFEFF2D5F7D41 -:1096600058C2E77FC85741CE92FD32609CF6BCFEDF -:109670000191C7D9AB897C19BA0F21D7E5EFE579FC -:1096800077BF10EB93EFD70939F059BE1642BC3AB9 -:10969000F507B319E3A0E5E59C7F36796D144768BB -:1096A0000AF1FC9AA6A58CEC7E79DFB5D2E5DB85C4 -:1096B000FD56BD6DA3EF9E36EDDCDA3E98F20F7CD1 -:1096C000A4DF9DFE037F7F22DBB707DBF9974612FD -:1096D000E215155F7EBAB2B69CD64B76BBD39478B2 -:1096E0008F2892CFF386E4F34F7DF005FB04FA9DBB -:1096F000AAE779DE7EA766AFA2BC03EE0F4F71F733 -:10970000921FA8690709094649A758FFA37CC29B75 -:10971000A61D5565F4FD8190A58CBE5FF347FEBD87 -:10972000A75377E506F5DC7FFE5B5C6F6A79F07A1C -:10973000D4338B601E54494F755F5F46FEC124BA17 -:1097400093F4D6777FF4BBE660AB12A3C7F5062E81 -:1097500027A57C7B39DFCDFDD54E913FD83399CD00 -:10976000B6C5CA3667625EE58ABC6B5FC6F5BC9C4F -:10977000CFE30532CE5E6C06EB73F0F978582CE23D -:10978000EC93457E040B98637911832F1C6797EB4C -:10979000936519674F39277E5FC06E24BC486DE71B -:1097A0007C83015EA09E7D75B4773CDEDB1ADA19FE -:1097B000BE1AE13508C14F79AA91BB2FC3F845867F -:1097C0007A35C62FB62C19B30FE3AAEAEADE6FE0AA -:1097D000D1B83BECD5686256BABCBA02E22FCDA52F -:1097E00088FFD5BF35F07CC6D52924EF3B0B1B285D -:1097F0009FF1F4DBA6847B3AC9CF005BEE42BFD178 -:10980000E0F637297E90BA43E9374FB5AAC046FB48 -:10981000C4F6E8874A6DEF0D54A25FE51E857F3BD5 -:109820001256AFB8D0FE5775A877CCDAC9EF7DCF06 -:10983000EA70549B899F2A3CFE72B593F8A4BAFA49 -:10984000061DDA696A0BA3EFB45516703FF6B04EE9 -:10985000BB0ECFFDDFBED0F71B571B5E10CB8F4377 -:1098600070359AA2075CC5B178A0CC8B1BE8FBE7EA -:10987000521E25EBB3E7E9B1421EF5E9F349783C06 -:10988000503F89DF129FFFCDC0480FFB37C54CF713 -:10989000C1245EB7C93CFF2FB85FB748E4DB1C5B4F -:1098A000F39FA3F97D77194F09F23C294364651EA4 -:1098B000C12BF2CD00EE7B8743D73492FC614D344F -:1098C000CE6AFE7DB5A2F621CB2BCBF169670A2CBF -:1098D000E1D8AE0545489701C08361FDE081B180C4 -:1098E000DF575157A7D0B9A9EBE8CBD24C7564D15B -:1098F000B9A90FF2F361057C3F329E2BFD969FE5DF -:10990000FB6E463CECBBBFB5C4CAEF6F89FBC1A977 -:109910004BDE7E1AEF456D11FEE37D7B2EA5DF85C4 -:1099200038BB5A55504F3DEBA8A3DF41AA2BE0FAB4 -:1099300052AADACBECB678FCDC4779B58377F3FC36 -:109940004055DC7F56573BB7223C6B9C3ECA1FFEFE -:10995000465B987E3A618FFD38C5E9402FA27BAE09 -:10996000275F50A45E94200FA5DD966C8FDD51F02B -:10997000BFAB2705E47C5FD5CE6289F6665F7B6965 -:109980003F26DB1349FD07D27F981648C8937940DC -:109990009CBB94EFB98237CAFC99BEFBCE2C68C140 -:1099A000FB12239028C7C6F28898C82FDAA0583D2A -:1099B000A82F0D9447D497E7C39A2FE3FEC8E62B50 -:1099C000F029F390649E9105F34D32CECF37B1600C -:1099D000BE4906FE7E06BF372DF3455A0D6ECA3FBF -:1099E00009FC98511C5199524BFEBA74AF91F0EF9B -:1099F0000C0B6EC4EFC707A6D9E87E38DE2742BC41 -:109A00008F2A2E1A777CAD26DBEBB07DDF7708EB53 -:109A100018D5A70FD572500FB3403D7E1FB9EFBECA -:109A2000F46CFEBDF6E47C1399F724E3C0B9C39F40 -:109A300053D02F8A6E7FCA3FF881E857CCC7E9FC24 -:109A4000BE9BF846562BCF6B8A5EC9ECE897AF9663 -:109A5000FCC79C78AEEB155F31D2E77A2BFF5E40F6 -:109A600017F3B4EBA17C77C160EED761EEBD3A622B -:109A7000D81DF47B0F9B9CDA6B0599317C92EB62CD -:109A80001BF8BECFE0FD302536DF99797F2B44FDF2 -:109A9000AABAC7C4F13269FE4D7DDF6B095A509EE8 -:109AA000FCB980F1EF8C26E9BBF2F96789FF822FC0 -:109AB000CBF907DA9FC4CF0BE9F112FF06C2B7401A -:109AC000B538A72329A47F487CDBB76C3B7D877022 -:109AD000FFB2103DCF5894901EEFD55AA233903369 -:109AE0001EDFF25F37E1F73CCEA4460BF17B20D1BD -:109AF00087F55E2A67468F6099155DC1CBC3A25B6F -:109B0000F0FB20590FBFF82D2AE379E63276AE201C -:109B1000F4AD808DBECBB5B217E55679521E4BD24F -:109B2000770C52C4EF0765DB8CA44F668BB81EAB75 -:109B3000117A3D46A0A0DC9A5346713C1B73EFE8B6 -:109B4000C5FA7C13FFDE0103FCC7FA61C53C1F8226 -:109B5000F17DB37CE19F669100FD1E60B183FAF751 -:109B6000F1F11D26119FE2F31F7A96C711655E2F52 -:109B700063F602D4876C6E965096DF0161AABD0031 -:109B8000EFFDB74ABF9F28BF98E2CB2D8CD3970E2D -:109B90005DFBC391F4BB24CFFD6828F2CDEB8C892B -:109BA000DF7596CF3F14717BE58CF87EE11D29BEF1 -:109BB000218599F8BB243326E0A768A76754191DAF -:109BC000A4BF3DA1473E9529F0C3318DAFCF51E3EE -:109BD00055F0F740E4F703337D2AF90998AF538F26 -:109BE0007235F3B897F2051BCCD142FCDD9637CC29 -:109BF000BECB70FCB37547EFA47861EEA12398DF6C -:109C000071C8D0313E0DE548B1F89E040664A17CD0 -:109C100020AF88ECC13EFE304CA178E6A469FCDEA2 -:109C2000EB441652F19C27D8F93DAC09E5C59E5688 -:109C3000986F92C80F9970D89B86FC6DC277222AC4 -:109C4000FFDE45548DCFC7904FE632B8E3E9E17AA5 -:109C5000775C99E1778E13CB377A12CBDFAAFC625F -:109C6000787C7994A24DC47DBEA888EF46007FE140 -:109C7000FBE279873F17F6DCA52E662E427F8553DF -:109C800009A0BD70E9F3B9146779BE9251396BBB75 -:109C9000799B397EFFEB743C0E2DFCE0F2778DB0A2 -:109CA0000EE5ED737FC8227865D980DF3A89FB1015 -:109CB000BEED1374BB4FD069459ED98AFC7F9FC10E -:109CC000BD99F03CD5EC463FD5DE54237D37B675C3 -:109CD00021FF5D0425CDCC8C30AE7E262F433BF694 -:109CE0004DA8D75798299F649FC8D36EFDB14A7E6F -:109CF0002EACC7EFF9EAEFB5927FBB26ADF47B58E7 -:109D0000AF4F33D23D89BDA9153E311F7DCFFED166 -:109D10005473187F5F21F9FB9D87705D083758D712 -:109D2000637C1D448FFA0A23E9E1F2DE3A8C43F1A9 -:109D3000377DAE99E6DBE7B0EF45BC6BFD80343D87 -:109D4000A8AF7463FE97C4EF9AB44AFABD12A0BEDE -:109D5000A1F1DF67D76779DCFCBE2DFF1D8ED2BE77 -:109D6000DFE58069A11DFE861123BAE5F1BC020979 -:109D700077A66AD83E87C932BF6F96D557AE52E9EB -:109D8000BB418A2CB750F921512FBF37FA4EA19B06 -:109D9000DF4BEE79E53F106F87A6015CE09C3C2924 -:109DA000FDDF777AB290F3F7F3CFAFC2857E7F0500 -:109DB000F73932B6FF7D0E8FCB1B57EEE75C8288FA -:109DC0006FC9E7B2CFE271A39FEDC2E371B8CA7D5C -:109DD000E873393CFBF691D1FF3EDE11FB0889FBAD -:109DE000D9C9F5070B755FF73EFBC5BF7F7A9F5951 -:109DF00089FBFC1AD71951BE8675EA0B617DB6D86E -:109E0000FAE867C72A906F72FC9B28F29B59696237 -:109E10005E12ABF498B9BE989887749DB2B90DE5FF -:109E2000EB4322CEFD8AA0AB03293F198AFAD62B39 -:109E3000334AF613BF1DD4D286C425F9B3E4FF67B5 -:109E4000738E566019E44014E5D59D830FCDC0C1D3 -:109E5000F73B1E1A8AF20AF8E6C78599E7AF53D294 -:109E60006FDF7A817E918E24FD26AF5FD211BB29F0 -:109E700044099D5D2C4C4F17E3F9F3A097D0F7D11F -:109E800099BB20B63F20F209E666BE8F9600ADFB77 -:109E90003AC7039437682DF6198B605DD32FFB9872 -:109EA000BEA3C45C75C3518EC07A4D4563FFEFD627 -:109EB0000BFC2907DF4B3D3F59AFBF501EB95C6714 -:109EC000323F94EB51A66C273DDE0F7A3CCF3357DF -:109ED00088DFFBEB759C0FEF5448AF6F023983723C -:109EE0004A7ECFF79A126B1B7E2F729781FB53032A -:109EF000CF9ADC89DF574ACE3717F6C45226ED05D4 -:109F0000FE1D89463BFF7E9290339D770C96DF576E -:109F1000E2F210E454C2F795EADC89DF571AC05E1A -:109F200000BB80F433364827EC022EA73BAF74DB2E -:109F3000038CFCCFFCF7256F310A7D10609115FB77 -:109F4000FE1BD801F45DBB1B8A8AC5F7B582FCF7FE -:109F50003C84FE9FEC8F4EC9F6DD8478327BA4569C -:109F6000883F2D33CBC8FDCD806F9B7B19A64D3626 -:109F70003F8ADF47BD9E35BFA51B42F8360DDB4F3C -:109F8000BFF463FEDDD418BE7DBB2893CB2514320D -:109F900017A2E3234EDF0C1CA7D311FA237E3F7DCB -:109FA000538F89E02DF35293E93B6E3DC70D7C3D05 -:109FB0004EBD9ED63387F03F693D1783F7F1789504 -:109FC000CD387E0F84FF78FF23754C0CFF4729BEE8 -:109FD0003B70DE3E3A58C9EDAEF3D6ADB7D179DF6E -:109FE0007C0B8FCBF953A49DAC4DCAC9423F249F33 -:109FF000FFE6D51C2F6EAEE37944937B1A290EC77A -:10A000006A785CCD03FFA3DF8711FC6D9AB3CC8027 -:10A01000A8F739FB9E01FD9CD32625C6DFA69BAF82 -:10A02000A378DFCDD30C09BF8F29E1305DFCFEF6AC -:10A03000F4A4DFC54C864B72DCAE8F1F88FDE6E1D1 -:10A04000EFC5C0339FF17B3739E277CC3614F5C5C5 -:10A05000F7867FC5F8DEC31C8F2E2EBEB7DF10A596 -:10A06000EF3BBC9C3977F342A09BE13F1D49DF7B6E -:10A07000BF366BDEA3EBA0FCB34D9750F9E5ACEF18 -:10A080002E3E84F55B4AA85CA3FB7806D24169C5E5 -:10A090002D13F1FBF8FB2D7C1C97D5D789BF9BE2D4 -:10A0A0001A3D780CE60FD718A3D4EE86CB1A2FC72B -:10A0B0007CA81A2B2FBF5EF6FB31541E2CCA635EA0 -:10A0C000BC04CBFB958F67F4171FBCB45409E3EFB6 -:10A0D000A3D5A4F3F693C63C918BFEA29A6A5EBE0A -:10A0E000D453B57A08D6EB3E99D19F3EF286B0871D -:10A0F000A47EED15F4FEBC76B40DEF117A6D8A07DF -:10A10000EF8B782B8FF2EFAA99795E89572B53F159 -:10A11000BB9BD51AF7F38EB7B5E4205FBCC9672C9B -:10A12000477FBEDD56DC867AF1A0CAAAB178DEE3AD -:10A13000CD8CF009E8EA10D1D5151F17A62132DB26 -:10A1400012E94AE2ED64494F35897403FCE0F7FCFB -:10A150001C13E901C67D87F8C75589F2AA8FDF274E -:10A16000D16D323E0EA817B0443E18C3D390128F63 -:10A170009F5D48AF9C7E3FC2751875BD6E7C5FA425 -:10A18000782EA1449B01F40BB93E745BB231E7AF6A -:10A190000BFF54A98FF315D8ED59382FAF877E1ACE -:10A1A000FE989D5C17CCFF05C167255F4F97D22CA9 -:10A1B0007E1F85DB61D2DFD124F6FBDF798429C3E2 -:10A1C00000800000000000001F8B0800000000005D -:10A1D000000BE53D097894D5B5F79F7FB6249364CD -:10A1E000929090100893044280244CC222CAE2B09C -:10A1F00004A32C0E9B8022FE095BC84202E833B602 -:10A20000D80C844D8B6DA8A8A8A80302A2450C0AFF -:10A21000881AE8B088585163D5D6A5D244ADEC1061 -:10A2200083B6D8FAEA3BE7DC7B33F3FF498AF4BD17 -:10A23000F77D7DDF83DACBFDEF7ECEB9E79C7BCE69 -:10A24000B977D83ECBB9C64C467F7E48636C503850 -:10A25000F385E53196C8DC6B54153E76CAEDE3CD47 -:10A26000C6D2AE315FF5650C3FFD703D63172D8E94 -:10A27000354A346315E15139AC1F6353ECDE076C8A -:10A2800026C6A6C6CCB630E8671AF3ED894967EC56 -:10A2900085082DDA3510DA997CFB1B15C6E6328F5E -:10A2A00095C1F76CC5E3C4EF8C056050C616E23F5C -:10A2B0005DC17EBB415F0CE6B1D0EE08A839F06FFE -:10A2C0000FEBD129813145D4638679437D0F8B858E -:10A2D000F2FA37BE53B0FEAA3A05C7E9CA1A92305D -:10A2E0004D6295946F5D97613D3591B856C69A73EE -:10A2F0006DFECD388819FE1BC0D8F1C20CFFFD4A97 -:10A30000705EC7159669867A3E25DCBD3595B1BF6E -:10A3100086C1FAE17B2701872145FF318145B59D43 -:10A320006F959DD7BB3B3C6A33A6D76784AF30455A -:10A3300063FB143FD6EF140E694E70FE7F3531CDAE -:10A340000EF3BD5B8575A8B88EE6656618EF0956F5 -:10A350004BF9492E5834C0AF73EB7A7C0AE2C96AD4 -:10A3600052EEF03A604DF8E7FA603AC905008D27E1 -:10A3700070292C21086FE652981DF245222FE1DD4D -:10A38000C9EAEA8AFD18E15C64B735117CD7E47B41 -:10A390001AEDC1EFACF6114F683F1DD55300AEC9A1 -:10A3A000B16DE10FF3A7F98DAF1AE5FD320EC717B6 -:10A3B000F8B82792F031FE9E11F45D9994A934C249 -:10A3C000BC4615B8288D1DF09E9965135EA6D7650D -:10A3D00005F1F475BC368BE8CBDC387022E0F6ED85 -:10A3E00081CFE46A507EC2C48AB19E113E25089F87 -:10A3F000816DE1D34A7F06387434FFD722BC6538BB -:10A40000EE79A5611016C677710AB86BA9889F18F6 -:10A4100067EA881884FBF7302ED0FD142C023C3FED -:10A4200096A0DD89EDA6316FBE19D61B5BA059340D -:10A43000070D67C2F92C76F2F9E4AB0EA2CB961D9C -:10A440008ADF06F5467B7A3F3214F215C72CCC0F13 -:10A45000E52D8CD36DCB46D5EF037A99FFE64B8380 -:10A460006087B12F049DF6DA60622E890FF8AFB7CE -:10A470003F9CB93283F9BEDB6375F9ECBA2EBAFAA8 -:10A48000FDF6A5E9CA73037D74E5FD8FE5E9F203E6 -:10A490001BAED3D5BFE6A391BAFCB58D37E9EA0F61 -:10A4A000393549971FD67CABAE7E4D18EC9F7E08A0 -:10A4B0006E4F4326C0658EC0D3F5978B74EDCE46A4 -:10A4C0008D3986FB6ACEDAF9E3705F8D60A5BA7EBE -:10A4D00058ADE573A4CB4AF88BF89CC7BCD101807A -:10A4E000573E6B3E9A0CF05BE857DC08B7F91B78D7 -:10A4F0003DD96EC1BE45236330F5EBBF9732733053 -:10A500000FFD54FD71D36F8F84948F76169A90FE51 -:10A51000EA5C919D906ED835EC9A1FD476F1EB0EE3 -:10A5200020FE3E50DD36F8B4F84D95F6C1E2E71551 -:10A530003F837E3358CF68CC571C53991FF07F92CE -:10A54000553E3C14D2BF56FB7F7BA467103EB644F9 -:10A550003D9EC35C7A3C4764EAF11CE9D6E3397A54 -:10A56000B01ECF311E3D9EE30AF4788EF7EAF1DC8F -:10A5700079BA1ECF499A1ECFC9C57A3C77ABD4E3CE -:10A58000B97B951E9FA9BE123DFE0CF897FC377D46 -:10A59000CD625DBD563AF0168FC3B467ED4F74FDC2 -:10A5A00096AA6556660AD2830FFE223DF462CC1D40 -:10A5B00000382F043C045C6DE9A0B87EDDAAE47F7E -:10A5C000810E9A11FF1121F85767466BEDF06B99D8 -:10A5D0004ABC82BCFC8B0BF84878AAF61DA6D37B3C -:10A5E0007D9D6206BEC1BC85BDBC9141BE6794A77E -:10A5F000528EA23C320F0ACAA38EF85A1B393A4136 -:10A60000CA9F0EE4A8AB5B900F02403E665CCE335F -:10A61000B6D684F39821E8FA5038A7CB4B58742D5E -:10A62000D4833A83615E1FE3BC619C8FC3FB1EC170 -:10A630007D7A2BABB360FF335903A5B35833A51A0A -:10A640007392DE50C4DC94CE615E4ADFB66BC9A95A -:10A65000C037CBEC8D8350EFF84BE17B27149CCCBB -:10A66000F1389C6C877095FCFA7DFC27D4F3A67AB0 -:10A67000D353213FDAEEBAF321F87408E504F2DF90 -:10A680007171345F66F6664FCA6EAF9FE524375E20 -:10A6900053340DF9AE2FC9EEDE0A6BEB9BCCEC49BF -:10A6A00028E712FD6993003F79A97AF9D247D0C40F -:10A6B000F35DEA16A39EC4983F16E5C3D58E3B3CD6 -:10A6C000D5732DAE5FD6BFD27AADD6BA4538CFE6B8 -:10A6D00072877B33D0E707021F4FDF620BA851411F -:10A6E0003AFA2862D6D178C0DB5D11DA0DD8FFF4D2 -:10A6F0006937AEC2BC7228CEB518E677B110E0CD8E -:10A70000E13F96C35FEB9E004B3CDF4DEB158DF0B8 -:10A71000F772F8C33FB2BDEDCE9FCF6794C2C77F3B -:10A720002D429B82FD1C3235A4B8111EE68641A441 -:10A73000773AE2A99FF3560E978EE03032A2DB4CB7 -:10A740005CD71C9BCDAD429F23158ED72FE3EE988F -:10A750005501FF9C6BF2260454DDBC8B10DF65CEE7 -:10A76000C2EE494037E72D62DEF67801775716EEE4 -:10A77000AB8EE65D83FDA31E78AFE2473D90FE40C1 -:10A78000FE655F8CFF7EC8DB4C973E988CFA4BB61B -:10A79000C9BD198A368643D740EFEF0A783F6181F9 -:10A7A0007C2C7D5F83DF13C379FBC4874DFE1A6861 -:10A7B000EF1DF90AE1E9E9850E5A4F2173597193AA -:10A7C000CD16FAF39F47FC7D7F23E0C397AAFD14C3 -:10A7D000D771479C29E5039A87D617F51D36F4C72C -:10A7E000D1BFDCA7939C7C097305DC26330FEDBB3E -:10A7F000A94CB3E0B8BFBB60F520FFFC9DE027A0EB -:10A80000DFD3F719CC4FE96D2C40F56F678D947F3E -:10A810002F22A75B15CC6FE223BD7A227F0D81FB2F -:10A820003A82BB5DBBA313A797939D11EEEBE37F29 -:10A8300014FD4E14F402FBF551A417D8AF0372D3E4 -:10A8400042F6CD684E2FCCECECF9CFF64D430B978A -:10A8500017C0181D49B0FE1B040A6FF094929C406B -:10A860003DAB13C0BFC1A5929E5530A2C98CF3DF8A -:10A87000F635E7636F2C63913E287F6384CA105FCF -:10A8800013368C398DED8EB340A701503FFFB27661 -:10A89000241AD63F01F83B706456D015E444885C16 -:10A8A000BA2971DD68D4236EEAA1FF3E96D5AA08C5 -:10A8B000BF71597AB93201E58AAC07E31D4438C447 -:10A8C000B6952FF5A942BEF4617DAE46BE2C367911 -:10A8D0000E131F013A43BA2F32334F7BFBCDD54BBA -:10A8E000917C8CF4969BC5D82DE32E592FC27AFF0C -:10A8F0009EAABD83FD2C1EFFE759C88FE11CF5768B -:10A900007F94A3EFA8EC7E28FFBC1A200EC2F5CBE3 -:10A910006A3BF38082F355B593F2A7AA13293D53FE -:10A92000EDA2F45C7526955FA876533E2DCDFB070E -:10A93000ECB768CDD766D4A3568749FCF1792C11C2 -:10A94000F4BB3A8C9FA396442EF9A810C65D420230 -:10A9500010E4755DED18044BC9BEBAA398C277D553 -:10A9600081E5EB1437CAA7B947B455483EF38F3792 -:10A970004E40B633F0C32F13106EE59715A6C1569F -:10A98000BABFA7E72B1CFF64F5609AD7E96A0FCD21 -:10A99000CB53DF74340EDA9FAD2EA0FC9034EF3928 -:10A9A000ACE7615F5BB1FDF81D4DE66428CFF72889 -:10A9B0001EDCDFC33DCCEF07FC6DB07079B101E464 -:10A9C00005D2CF88EC494FDCC9909F6B7FC1FD3128 -:10A9D0003576767E1CD2D5E04233D69BF63DE85CD8 -:10A9E000A941FABED23E397F4021F89C3F1043F086 -:10A9F00090702A17F83ABFB7EFCD43A0DF03A04706 -:10AA0000AA30BF96CB269A5FCB47E17E54128CEDDD -:10AA100017EF49EFCC1CB84E686CC37CDFCE0CF04E -:10AA200010617FFA093C979D7DFEEE44C4CBD9D8D6 -:10AA3000BABF7C827CEF33CEF740E3FDEA31E48B92 -:10AA40005D13DDF743EE8205CE6974AEA98C40B983 -:10AA5000B8D0CA349ED7FA62FE6C38A3F3EBA09D3F -:10AA6000C923713FE178AE5E41BE96A9B85815D0B2 -:10AA70007DC6CE47D27E0AF3DE5E37F793C7203D10 -:10AA8000EF37F92C20B7CEB3BA0BAF225FDEE270FE -:10AA90006F6558DF1C8EF57F6EE1F3F26D8573BB39 -:10AAA0000BFBF3131D43B915CBCB5E7CB40BCEFF70 -:10AAB00035D44B20FFDABA08E277AF59DC27AAB0C9 -:10AAC000DD13BCBF677E71CFE7FB307DA03CEF1E7E -:10AAD00048FBA7C5523F737EB5A00FB607B9CF920A -:10AAE000803FFEFA6525100670CB5E7F7079128C70 -:10AAF000D76F6393A90BA4B95B941A4CFB762B38E0 -:10AB000086F2F6DA3417E1ABFF8E5415F5C93E5DD7 -:10AB1000FC9F5C4FFA805E4FC85AFFF5C82E2CA8E8 -:10AB20002FF451EACE2C037A58DDEDF779FC9C58CE -:10AB30004BF3D8533FF9FDDB18AE0334119C77A1DA -:10AB400095EC14B85C0BE4CFEF4EDF84F68CBD2699 -:10AB5000DF26925F455C5F39EFF53D8A74560EF54E -:10AB60007D902FCFF5455D07E5E59FF5700345B175 -:10AB70006E4FDE5080F058B8FBA1315DA0DEF9A128 -:10AB8000CC0DA860C57B2E8DC176AC1BE8D6D8CF86 -:10AB9000EE9A845BA1DDCFB3460E44BAF2AA7534B7 -:10ABA0000EABE0E33C22E41E6B04E024081104F544 -:10ABB0007E0E9FF17B6C7DCCC16416C44F45FDB207 -:10ABC00054B4B70CD0EC6E15F74DAA2FA9D211943E -:10ABD000A320FF6E4B837A4956D1AF73728AF72A4E -:10ABE000E49F55C833D9DF2356E60B8BE57AB38251 -:10ABF000F2D9CAE5F656E02F557941B90DE396E250 -:10AC0000B856A12F278390CE8579263F62F3936EA5 -:10AC1000F023C737DAD1A4DE323DAE667F23DA7B7C -:10AC200022B4BB711C69376366B70BF5A215119E80 -:10AC3000AA34D2BB9A53700D205797A6417F0B556B -:10AC4000D0C3D243F430FB8F93AB2F447896637F0D -:10AC50003FB6BE91EF2EF9D6C472810E963C64A326 -:10AC6000736A8DB037D408FB564DE4203BF20B7667 -:10AC7000C4547614E4ED30DE436BBF4B22F3889F5F -:10AC8000D430D62EDC0E001FD080EF04406E68C09A -:10AC90000F865F6E5639DD371C8E1E80FC9679223A -:10ACA0005D680730312D449E1AFB01BC6DC6758E60 -:10ACB00060114C0B919B1E1663C5FDCB1CB1FFD2DE -:10ACC000FA870AFCC9750C15F6BCA12D1F4520DFBB -:10ACD0005CF26D1EF1CF8ED6B75FACEF37B83E4851 -:10ACE000937A79F7E03C877DE334E33A879927A6A6 -:10ACF000A09E03F37F0DF13CFC1B937EFEDF87EBF0 -:10AD0000F23F761D7729CC67C2FDF9B5D58FFBB32D -:10AD10001EE81BF773FD822C3FF281BDB01FEC785B -:10AD2000AE9964253DB75ED849EBE39D645F7ACD6B -:10AD3000C2F3BE19A27D182339523FA30BB5EF62AF -:10AD4000AB7C2B1BFBAF8920FE596FF1AF49C3FED3 -:10AD5000EF8D73FB005F2ACA8FFE70DE10FCBBC64E -:10AD600012B84DC5FEBEB6321C6F7D4C20B902EA4A -:10AD7000AF5FD085EA7F04AA14DAEF86984C774C4F -:10AD80007460B9272916F27BFFA192DC589F0B79DA -:10AD900007F171B207AE9FE8490AEF84698289E63C -:10ADA000A3B24AFA9ECADB7D62E1F56E15F8FB5844 -:10ADB000E007F639F1016D428419E9D8945EF46D2B -:10ADC0001AE1DD93A4C07C1E9BD393211FBDB5E483 -:10ADD000C654A29BDA47889F4D173890FD6103FB4C -:10ADE00020D4A3F99F1973B786213EA71687917DBA -:10ADF000F4A3E2E5912E683F55530336B41B4FC9C7 -:10AE0000F7849EC74DE91E1AB7BCAE77FA97217436 -:10AE10005D6403BE01FDFF225CFB9EF6EDBE5C2A75 -:10AE2000DF07CACD0FB0AF3E9FD37327D935E6C831 -:10AE300073646036E2F540B39DE1F9A4237AA8413A -:10AE40003C40BFDD855C277A45FC4F0FE7E71C33AC -:10AE5000D00BE46BEA7AD339E7290BF32888AF3DAE -:10AE600036C27FC124BB87EC8FD3C337D9A0FC0E79 -:10AE7000C1CF6AA687D3F79AFD917E9342E727CA8E -:10AE8000FB7659A85D99D5FFEC36E8A7EC406F92A8 -:10AE9000377BAD62DC57237879942775E5002CEF7A -:10AEA0004C74F09AC5154DE56FAA8CCAC3031931CD -:10AEB00000C7B830AD5BFA40A43BC0B303FBE5DF8D -:10AEC0004F08FA3A01DD22FE7C9591D42F6D7DC8A2 -:10AED0006B35DD36233E352B2F673F51A9FC84D3DC -:10AEE000933417F2272A93695ED2CE74C26B25BAC7 -:10AEF0003F51A690BEF4C72A35600DB5E34FDA7E08 -:10AF00005F06B4FBE28085EC78337F597A1CBFCFB3 -:10AF10005C5E4EF6C899254BC94F7061E9178336C0 -:10AF2000C07A1A977F9AA285D8A5679641AB90FD03 -:10AF30007C43BA67503AE06776BA762DAEAF22AB63 -:10AF4000711EEAD717AC0D4FE27921A3933614BFD7 -:10AF50005F7CE5E436AE773767A09C5868E67422DC -:10AF6000E56D85A0C34BE9DA48AC0F709B8572256F -:10AF700022AB81F3BFA53F8EFF9FA9DFBA57817136 -:10AF80004AC3EB1752AAFA73B09FB34A204A492723 -:10AF9000386AB8AFCE390351087FCDC4F5BCD2EDC5 -:10AFA000FA75E11F7302DACD18D9C14BEB544F1873 -:10AFB000EE03E6B7E2FC4B9935583F35882FE8871A -:10AFC000F0C51C7F9CF553C043C9B3BDF3F07C5161 -:10AFD0001AB3EF1743A81EB493FB456D9B97EB691B -:10AFE0003B1FBEBE73621F9C832F16A4971D36792C -:10AFF000CEA7F12FBCD299C64F10FBE48222E8F510 -:10B00000D9304E576E5817CEF3054E570F4B3EF9B9 -:10B010002CEFA734CE6742BE545AED24BA927C0975 -:10B02000E642FBEBECCE646A27F918F33246F5777B -:10B03000266DE6FA9B38EFE284A17EC9AFF9389815 -:10B04000477E7EE6B964392EE9DB46796C5CF7EA27 -:10B05000746E9F0239DDF99F9D173313673F31A747 -:10B060007FC87A22AD822FB8132766A37FC1AAEBCF -:10B07000F742A4F50E8F03FD0CFAEFB2BF07D3F928 -:10B0800079B2BB01CF5DD4E68336DC874F33921BA8 -:10B09000C6793C26DA3DF75C2B5E55614F672E4939 -:10B0A0004F2EAECF13FE3EB64AFCDD990CFCB81411 -:10B0B00061951684E3DE5C2D19E5C605E11FDA1BF8 -:10B0C00003F92CD4A7385E645EE2C34897CB3F9E59 -:10B0D000978CFEA837D2B99FCD08EF6500572CAFEB -:10B0E000B1C0F9260BCFB9C71EFCB267703D5F55E2 -:10B0F0007B3C7342F2F336E4DA713FCEDF986B2F7C -:10B100000AC147CDF6FEC75C00F773DBCD6E64EF76 -:10B110003566FF2F504FAFD9AED6211D41B91DE185 -:10B120007DCE71E81DAC376F634C1EEAE1B2FDFCC9 -:10B130000DF99E392178E8BB5D8F97EC3A7DBEDF33 -:10B140003E7DFE3DD441E3AFBE5D6E409FEF7F4C40 -:10B150009F67CD80BD41A80F70BCBD3CD87DCC059C -:10B1600078EBEE57DDF8A9BB63D2E4F1A8476C5445 -:10B17000DD3DA1BCFB52EF58D42B4E6D9CEB46B489 -:10B1800017ABBE853F059C167F3AE618CAD5B3AC0F -:10B19000EEF7E3012FF3EAD759CD2E5CB79EDEF729 -:10B1A0009A04FD3EC7ED770BFCFAF2B67C6199B4C8 -:10B1B0007B6486D297910E60DC5B3C30A1B2AAF72B -:10B1C0001F44BE503C0E081FE8ECDABA7556D4FF97 -:10B1D000AE3C8E8FEB970E8F0BE1513898975D57F1 -:10B1E000358A7D01FB8EAD7D6F0CCEBBF0E70AE9A1 -:10B1F0001F852FF53A82F4D5B46BC64D94DE5240CC -:10B20000EB9776C2F9F54A2012F2CEC1AE7D8DD011 -:10B210006EAE9FDB3B8A56D882FC90A19FCC308FCC -:10B22000F521E530FFF9FB0E7EA740FFC51BF5EDCC -:10B2300016009F46F953B2E5075BE877791EBDAE6D -:10B240007E938AEB9E2BE62FE527F30D273FC575EE -:10B25000BC09FB12FF0FE44E698216DF233E28472C -:10B26000AF5BCFDB03DB2DC475973BAC2E5C77B9AE -:10B270009D0522603EC722AD1E277CBFB42192EC03 -:10B2800074F36CA0AFE651CA308E011831F9CBBE11 -:10B290007A5725BDA73C8EE3BDFC2985CE69E568BC -:10B2A0005CC5FCD33CBF8005683D482F9ED075FA35 -:10B2B000F57956CBCF7765E6C041844B096BE4E75F -:10B2C00033C0A727C4DF5D06EBFC2816F537437BA8 -:10B2D000E6D6C88FE7E0FA58C5BE1F6CA1E5F29C20 -:10B2E00029CFC1D27EFC5486371CC7B108BD79FD79 -:10B2F0007D9E0C9CEF4A8B2703E1E05B1746E7FD40 -:10B300005B3771F9B53E06F4D84EA43F933E7EAB51 -:10B31000C2F5733683F3C321A61703286F9A1F8AD9 -:10B32000716F76517D9263EB1FE8CDF5FF7FA8A486 -:10B330000F35AFE37111EB7339FCD63F90CDF57F3C -:10B3400029F7E219F5D756DFF664A01D823DC8E75C -:10B35000F5092E2944BF8EE8AC4D467CCBF549BD9E -:10B360009C15FF387FC65611A7D1BC2ECC8FFE8C02 -:10B370002F15EF5153887E3BA707971383467AB664 -:10B38000897AE4F798639A78FFF530AF390F9B5CC0 -:10B39000687F6B85B7C79381F2F3CB756179486796 -:10B3A0008346727BD4895CCEF72306308F1FD2721E -:10B3B000D16F790F932E4D0C07FA837EBECCE7F642 -:10B3C000F0C8015EB2036E7571BE6F5CC73DA29F8F -:10B3D0003956EF6F87B5331F0917369AEB1D5F2E6D -:10B3E0005236F37901BE213FE85761643FFC52C8F1 -:10B3F00025095FA01B8A7B907C2BA6955EFCCF86DF -:10B4000001BDACB3703A90E7B6107A11F8EF46F888 -:10B41000BD55E0973D1026E8C5C4FE8670CC777216 -:10B420007AB8CAF317E07B5D8F816DCF6112DFCCF4 -:10B43000EC1FF8CFFC2EE52F3FBFD7077A46C90B8C -:10B440000F4531A877DA5C9BE086F6655B57467955 -:10B45000203D65F6453961FCD37EB5C0DF0EBCDF0B -:10B460004578F3739C4309F1939E79EEE713709D41 -:10B470007FD96A71224BA8D86EA3F3D8C2DD0B48DE -:10B480005F877C13CFAFFE1AFDA615FBF4F6F99289 -:10B49000671E4A7011BC7DC9A6444C03C90CD285F5 -:10B4A0005B2CAD7E641806F4EFE655383F637B9C59 -:10B4B000C765C077459D5A688D6E5B5E21F84BC5A8 -:10B4C000EE9F7F8D76C38ADD379E447E5F61F00BF1 -:10B4D000140BFF88D12FF09B1E7ABF33C087E20C7C -:10B4E0007C30AF9E442EDCAE5CF3EC23394DA83F9C -:10B4F0006C792B4AC90AFA07A4DFA4A56EF653AFEC -:10B50000BA3ADE9717847D388837CEBF5CFB140CBF -:10B510005682833F4FCB2C81A82178DEDB6421FD4E -:10B52000B7ECF9A7B73D8674F6B18DE47BE9F3AFCC -:10B53000FFFE3AD49F77593A8DE3CB7028217139B9 -:10B54000152E6E8F93F82979E975AB2B9B7F5F1AC7 -:10B550001BC453E9AE83568C0F32C27354DD416B6A -:10B56000A3A31D7CD5358D213BD4B37FB5E2FE3836 -:10B570007D40619D53DBB62FDEF47A14EA6708271D -:10B58000944F126FAD7834D487FE27BC3A80EA39E5 -:10B59000F19C72253C3ED58371BEF272248B817979 -:10B5A000147F62F38F43FCEE5C1285EB3969AEE4E5 -:10B5B00074FFC4CA04D4F78A2DBE0427A5FC7BF10E -:10B5C0009377113DCE572A139C5944EF4926D22533 -:10B5D0007C49B8CEB91BA7D23AE7318DE8B1F8095A -:10B5E000D5EB87F45B332BD8D5CEBE19DB93F3A90B -:10B5F000939B01B9B0CE93223ECBF73B559CA3174A -:10B60000913CBF4BAC99B1C594FF56E873DD7AB657 -:10B61000FABFEDA1E7D08A2DAB1B104F67BA793A7C -:10B62000E33C010E3E0137E507E8577D2FBF33C7E6 -:10B63000137361FC02B503B93A0ABF63FD068B07B9 -:10B64000EDEC21EDC439918F7FA7181FE61D8EE721 -:10B65000E09309EDC77FFDA4A7E40BAC2134FEAB5A -:10B66000433EB0E53EA2AF6F3EE07C66A17F620143 -:10B67000953758029DB1DC7F708A427CC2C602EDCC -:10B68000EDF32D16B1CFF5E5304FB3120ADF035CB1 -:10B690003F95F4320FF4B240889E10A41F6BF03B2C -:10B6A000ADFF57623D8DE4CF937EC0F9823F18D73E -:10B6B0006FE417F93D0D714AA23DDBD8BEFF29C8E2 -:10B6C000277C346E19C877D447CA3EB6911E51F60E -:10B6D000BCC58B703ABBE3F0EF6FC5F36D9DDCD753 -:10B6E0007A3E6CDCD7C52F0E6C775F9F5D9BDBFECF -:10B6F000BE86EFEDEEEBB50AF1BBFF2E1F06C94784 -:10B7000076892BEDDFF91DF0E14A035CBF6559D165 -:10B7100043B0D059D89DF06480AF84AB91AF5A91BB -:10B7200049B6C35719867484C053C251D22B631AC9 -:10B730008DD34AD7926E255DB7D2AD71DD7A781A76 -:10B74000CBF310F7301FEF2B16D217CAEA797C2201 -:10B75000B4A378BA0AB4CF53EDDAA3C99D42F37EFD -:10B7600043BECE50DF63C87B0DF53543BE5257BF95 -:10B770006CDF612B3F3F0474F56C5563E93CD25696 -:10B78000CFF073BFD3EEAFAD3EA48FAECD56E493F2 -:10B7900096E5CC1709ED9BF7ABA4F75C743547A190 -:10B7A000DEB2328CEB75179D221FC3F3CDF1D65557 -:10B7B000C827E5F7E6306E87B9E86D8E8A0939CF7C -:10B7C00037D5AB5168FF6DF4B382F6E35B6A683F2F -:10B7D00035B28ECAB97E77319CDB1B2E86737B43D4 -:10B7E000BEEA48A9423B6C2D8F239CB36C5A14C50A -:10B7F00061D4A7DF3C1DBECF7D93C20C308ECE8CB2 -:10B80000F10FB3392AD929E6A378C2D9F53C0E62E3 -:10B81000CE5A3D9EE739B650BCDCB76C29A5F3D6AD -:10B82000EBE3174AD85AA2B3E28D86EFF563699F1E -:10B830009418F68926ECC3C67DF2A1DC27B92C57F3 -:10B84000172729F879BE9A75F374C0C7C5632AB360 -:10B8500041BEA55E65AB06F0B858F43FE18104F740 -:10B86000DF42D8AFA83749789DC37DD4AB63FDE5EF -:10B87000DC9ECF06FD14E966EFA7398F437A6EEFA1 -:10B88000C719AF61FEE53FA47CCADAD61F75E0BBDD -:10B8900059C8A72F1EB031A4F78B07DE48417BE4BF -:10B8A000C5576D74CEBEB8DCC6EDDC0722FD28623C -:10B8B0002E76E37A71CDFEBFE634925C5EC1E5621E -:10B8C0008695F0DC52FFF713684F6FA9875521DF8B -:10B8D0003F1041FBA9E2D530B2335FDCFFD741A175 -:10B8E000F6B9FFEE7AA4FFFD62249BFE22D2710C12 -:10B8F0003F1754BC76EDD3E85F2EDF7DD03A1BCAEC -:10B9000047FDE63F7390AF5E7C91EB53172C8D4F54 -:10B91000A28D3322E3D2AF2C4968E783CEBA30B68A -:10B9200025A3FF645F567B70E170B80870C0750195 -:10B930005C8A511E74048FB47F5B787C3D8BF3B7B7 -:10B940006B18FAA38370513CFC7BA4DFAED0FAF9EC -:10B95000F7037FCD41FE73A5F57A70BD03FFFFAC01 -:10B9600077D6BFED7A39BD7F85F235BE2DDDB7A51F -:10B97000EB97FF83F23B23DD34DF1FB9DF7FF6FF58 -:10B980008CBE37FEDBAEF74AF87E53E03BD289FE31 -:10B99000CC8BFBFF33855DC5BA5FFB3FBA6EA9C791 -:10B9A0008F54DDC772A1FE5BACEE03772A6923EDED -:10B9B000EA21A7321479BEA3F3D328C6E5F4287B85 -:10B9C00029E99FA3BA3E40FA720DCB23FF85AFABA6 -:10B9D0004A7E1D0A020138BC91984BF7AC9839D0C9 -:10B9E0007509E447269753BC98F15C392A7C7C01A1 -:10B9F000EAA78797C1BCA09FC3912627FAA84777DB -:10BA00005503B61C4A9B303D9A3296E2FE473BF402 -:10BA1000E7ABB18673D28D2E7D79017BB113FAED40 -:10BA20000AB22C74BF620CD60F39571ECD70D23AB1 -:10BA30006F64B52B9C8EAB8753622F7ECE6C0B87C9 -:10BA40007F0EB7367012E768B3A86F849BD9717FF9 -:10BA500003B633333817F3F5D2795A9E8BAF044FC0 -:10BA600026CEDB6631B484AFB92BF7CF86F44B70AA -:10BA70009170BF5A784B3C19E12EE12BE166C4C3AB -:10BA8000D90C26CEB71CFE5DCDB966DC77C3845ECB -:10BA90003FDA1CC3F35D1B542FED473FE16DD437F4 -:10BAA0006E33EAF5231C3114476ABCBF5034386644 -:10BAB0009002EB4D36339F0DCEA1E87B23BBEB7D8F -:10BAC00066FFF2541C87DB77BB99B9FD1A76B72F56 -:10BAD0003C8FEA7BAC902F7C703EF340FDC264E665 -:10BAE00056787D161D4BE1714CC5383148B15D610A -:10BAF00034EFB7B033F32FE7F824BCA0D907ED1B20 -:10BB0000D0AFC714CBDB47E5517B9F89B7F79821AE -:10BB1000ED9ECEE3149A5772BB7CE1EA6E19C83FE2 -:10BB2000C68DD4DB996B7B717FA44CBFEFC5F7BB8F -:10BB30006A7227D27D8A15BDE97CA4867BCBF7A0EB -:10BB40009D7E278FD3295C75FBF88138BF9D716E70 -:10BB50009CDE9909BB06F1FA33EEFA10BE6BDBC32B -:10BB6000E8BB2B531BDB0BE30114D7AC3DF0A16802 -:10BB7000EA616B220CA1D54D3C8F76C209BE5DEF08 -:10BB8000A07F72C21495EA4F603C0E93AD88A03836 -:10BB9000CCF1BEAFCD89D0DF78387460795398335B -:10BBA0006511CCBF50D887A7897863359C692F3A37 -:10BBB000705EDD32D2E0FB78D67E7CF243627FA9F4 -:10BBC00023958DE867EA3E8ADBEF657DEC07FB7D18 -:10BBD000BC17B747158954E601AE547FCE1A5B53A4 -:10BBE0003A9E7FD65802BD20FDB0F7C879BDA07C33 -:10BBF0005C1A1BB301E17E8FCA36D37C9B0BC9AFA5 -:10BC00001099E9423C6840D2E45FA94D75A15DAC52 -:10BC100069445D00FD094D8FA6BA6B5C84658A0797 -:10BC200092E7ADA611811E68C76FCEE57E8913CE5F -:10BC3000C6483C2FCE76D8F9FD4911573457DCA3BE -:10BC4000E95ED3F8C035780E7D48257FCDDC87F8D6 -:10BC5000FDB03F3BEC7E05CF6DEBF93E656BF571BA -:10BC600044CCE9263BD0ECDA11563C6FCE7178AC6F -:10BC7000B84E7FA6B602D725EF23F641244097851C -:10BC8000B58514AFA246C1BEC37D627645E139D801 -:10BC900018875421E28E64FE17E1DA03D85F51B4AD -:10BCA0006B27D2CBE755E9641F3D2EE86E1CC655C5 -:10BCB000A23FC3DC9884F3198EDF11AEB1CE0C071E -:10BCC000D17318433834599C1948DF4D2BC34CE8C5 -:10BCD000971BB79CD335EC33BB19DADF6766E1E815 -:10BCE00067B84DB49FB9CCECDD04F9AE76668E8CA6 -:10BCF00045BACA25BA4EECA315E17C4EDDCB06232E -:10BD00003DCC5EBB8EFC31922E98B961741C8C7355 -:10BD10006A6B6A1EF2CD563EDD67E4965EA1F43092 -:10BD200045213A80F4603AD1C3A46791EEC78D0CE7 -:10BD3000F4589C85E7D132E641F99EC8DCA827B4C7 -:10BD4000B066F257B638AC2EB47F497E22F986BC75 -:10BD50002F2BE9601BC87BB385B1EDD5764A9FAB2D -:10BD60007632734FC6765427527E67B58BD2BAEAC5 -:10BD70004CFAFE62B59BF2BBAB07537E6FB587F200 -:10BD8000FBAA0B287DB5DA4BDF255F02B8101F92A6 -:10BD90007C45F2A3D90E6B13FA2F255F32D2CD2C3E -:10BDA00000EFF03C6A4F7C4FF23B5C87292FC88F35 -:10BDB000247ED314AF2F3115F958E30CC47FBE7A1B -:10BDC000EEF997F15C5EEC70D3399D71BED702F449 -:10BDD0008A7049B1B27D6897AD59E4695A9D1A8459 -:10BDE000FF6DC50A3387D0D5ED9561CC1C2237EEA7 -:10BDF000A88AD1E56756BDFF7A67DC0FF1DA67885C -:10BE000097133FFBEA893FC0F7A77E76A627E21B80 -:10BE1000E6B1F5111C776978EB3C6231BFC2427E16 -:10BE2000AEEEC27ED25DD84FF04FE87DE6A77EF63B -:10BE300037DAE74D553617EAC59F20BE00BE7F149E -:10BE4000F82AAAB2111C0B577EF1FCCBB8DF975A27 -:10BE500089DF15AD10FBD1700FFAF324467609D0B7 -:10BE6000AA299EFDF37BAD8108E8FF7385EF63058A -:10BE7000948399187FB8E68D8F900F2855C7C8FF17 -:10BE8000AEE1BD3D9C9FCF724E77AFBAEA28D56335 -:10BE90008D5D63D0CF23EF25470CF0585DB07EA4B5 -:10BEA0006DC45F51E62196847E965AC589AADF1C2F -:10BEB000F17DCE1A85FC9A18C73305EF9167AAB4B5 -:10BEC000AF46F432135E9FC2187CD2EF6A494E49E6 -:10BED000BA9DB316DAE1FEA8CDB5CE0BE1C745E2B7 -:10BEE000FBEC4C13A5F27B02F60BFD7559933B1D41 -:10BEF000F58A2E589E8569DE74846F17C718B312B1 -:10BF00004207CE4CB398071FFF29442EFCEFFECC0E -:10BF100034EBDC2CBA0F48724C8E539499B70AE379 -:10BF20004B8BD68E402ECC6A2CEEC44E502FA9B52A -:10BF30001F711FDBCEE3A8CB3A9023D2AE760AFF67 -:10BF4000792DAD9BECBE253B7FBD13EF17947C6A2A -:10BF500023FC96F413715B59FE4193C900A9B7679E -:10BF60008FFEF56751E4A7D8CDE33B21E576D6A552 -:10BF7000C5DC2EEB86FDD58EBFE8C8CE4FA3DAB563 -:10BF800063EF567F941DBB42F93E0AF508B99EFC4B -:10BF9000FDDF26D03C94CBE427AAD8BF32A1BD3820 -:10BFA0002FA31DBBD5DE2DEC7A154B0BDAB5771B15 -:10BFB000ED77E3330DFE0333A37B66D27EC7D4ACAB -:10BFC00068F4037C2BEE9F7474CE91F6EF8A0DD04B -:10BFD000491CEC57B32B1AFD5B173BD0AF1FCAE4CB -:10BFE000F2FFBCB0975FDCA1D2B9E7E28E48DA5726 -:10BFF0000B773C7814FD8E0BB728348D72D640F049 -:10C0000003B8327BA85CC338B6B8B6F36EF1F78CD0 -:10C0100046B952FAEBC84AA4B705758A672BCCA774 -:10C02000C5EE8A8E0F99CFA24CBE6F4A6D758308FC -:10C03000DE62FEF3335D4457B2DE82FA07C9BE0CFE -:10C04000F52E905EF44204E3F7539ADFC1799EDD4A -:10C05000D8DF8DFEC20575BB16925EB123C289760C -:10C060008533226E59F673AF18EFDE4CAEE79D159F -:10C07000FEA3B33BF93B00384FDC6767146E87962D -:10C08000ED6AC4BEA8C9E47A5606C2203E587F4174 -:10C090005D53540FA87F72DFFB943E20C659E068C1 -:10C0A000C841797C727704F9BF4EEE7E7CCC6B3050 -:10C0B000DEF9BA119D705FC8FE1FCFB4707C6C545E -:10C0C0000B105ECCCFE366CA11BEFD43E719B7C9BA -:10C0D000971ABAFF78FCD0D9DD2F4599B282F82C97 -:10C0E000B757DA934CB88F167991BEA39178A07F99 -:10C0F000EBEE893E946115F5B90CE99AF65F12D51D -:10C100005F630AA967B3B829CED4B2AFD0C3EF99A1 -:10C11000887B51228E3F5FCD22BFE2AC7EAE69B7F5 -:10C12000219F7CCB42F858DCDB350DF9D3A5069571 -:10C13000E13C17A7B200EA274BEE89DC84724CCEB3 -:10C140007B567FCE0FCAD628CC03EB2BF3AB4C83A8 -:10C15000B40BE0DF87F494D83810E3249B52B95E27 -:10C1600021E3471F2B3679AC20075FCF8C157C5617 -:10C170007B742EFACF2665D279EE8495F954B42BD0 -:10C18000BDC8E34BCBD2785CF363221EBE2C369045 -:10C190001107FD9D13F82D9B14C8C0B88BB21793DF -:10C1A00028EEE29C95FB3DF13BFA59CBF2A0BD8312 -:10C1B000DED9D064FB98107A2A2B72BBB09E1AEBA2 -:10C1C00076E53A70BECE0BA4E7EE8964A8E79A5EE6 -:10C1D0008EE47153CF846DB685E0EDE34CAE47CB72 -:10C1E000F73BD8AD3CCEE8610B8F4B7D786B92DF8F -:10C1F0001F02AF872DDA0C8403AE03F5FB05D6DAF8 -:10C200000CD47FE57C1744D5D23CCF097A5F105E11 -:10C21000CBE3B9C57D60AC8FF9261187DEFCAC8D10 -:10C22000E280CE2435ECC5F1CF3CDB9BE1FA9B529A -:10C23000FDF3F65139E89780CF92E76C015CCFE9C6 -:10C2400067B93DFAB485EB6BA72726BA10BF0593F3 -:10C2500036CC227BCD169B8276BED30AB32662F9FA -:10C26000D6788A3F2FA9AEA2F8ED12601B787F081E -:10C27000D202BC07747A6B6F8A373B8DEF3628F495 -:10C280007D0D7ED758EDAC9F203CB6F3F3D599E7F2 -:10C29000FEDE3B34DE5BA6255BF4F175924E64F95D -:10C2A000DF047FFB9BD8E7FFC8E4F688F288BA87F3 -:10C2B000D3689D1CEE8027FE8E0D6B8C7C7C00C6A7 -:10C2C00053F454908F3CC602198FA3DD613B3F7F2E -:10C2D0009DD961A1B8F59297233D14C7B6FA1A13F8 -:10C2E000C553A85C4F2F3101F820557EB69DE2CB97 -:10C2F0003A3D17966723FD9CD139B779AB2AC661C1 -:10C300000CEF539EDEC6E38EC7A12E49E5D9547EBD -:10C310005AE44FEFCD26BD0FFAF7E0FDAA929FFC3D -:10C3200094C37172F171AE77D989DF96B5FA7986C7 -:10C3300046A31C2C5F3D241AEF2BB27755867A8BCF -:10C34000114E97CCEECEC867C7F7E6FCAC74EF137E -:10C35000E49F2A15F7084A9F53B81F1AF621DEE713 -:10C360002C5D35E411A2CF772CAC27ACE75CDD83E4 -:10C3700051A1F8B8A637E773ADF5AD6EAA5F0AF51F -:10C38000B19FD2556F45D17CB659285EC588C71F6D -:10C39000DDFE39F547B56FA58F3A6E6769B37ED676 -:10C3A000F01F9F42FFDFEC0873FBE86B1DDD833B52 -:10C3B0006BA99B87EB3FFB7C18F1ADB3319C3F9C95 -:10C3C000047EEAEB85F318FB4B8AEFFADD64BABF13 -:10C3D00037DFAFEF578E3BB437E7E3E571EE688C9C -:10C3E000172C7F97F341C0CBCDD4FE5D0BB537AE94 -:10C3F0002359B46BDD9FCF47103D9CEDC2F172769F -:10C40000672F924F4D319CCE61BE2978DFEFECF360 -:10C41000BD72E91E1D2A3D400F25E2FC7B36A62E8B -:10C42000C51952DE6411E7B800D444BAC136C0DF82 -:10C430004BAAB8BE556A5F4BF12518AF3B288FD287 -:10C44000802DB66DDC2DD02B9D2F1FEC2DEC983858 -:10C450005E828813273DA8CE8A7C5B13FA62D90ED0 -:10C4600063DC2E2F5F2CDBC36C3BC93861A4439F78 -:10C4700042712AA52B162DA0F8FBCA75B7E13E9391 -:10C48000F32F35B3023CA735292ACDA3298CDD3102 -:10C4900009F5CAD07142F4B97B83E3306702E9B190 -:10C4A000A4F42FEBEDA2EF98AFC57BAD2B94B53480 -:10C4B0004EAA3CEFF27549380138AC1827D83442FF -:10C4C0009477B06E394FE3BA5BF5AEDE9CEF37A5DB -:10C4D000BA7E3914F1FCB64AF77F2F7DDF3F3AB6BA -:10C4E0001D3D2D28E7ADC1785998FFE6DE8CFA99FD -:10C4F000D79BF3B5528CC78579666CD4C78B676EB2 -:10C50000D1E7FBECD0E7B376EBF339F5FABCFB8867 -:10C510003E7FBF1817CFE178DF18CFE198E239DC12 -:10C5200065E3E770CCE3391C533C87E3773C8763D2 -:10C530001ECFE198C77338E625BCF13C8E793C8F5D -:10C5400063F9FBBD39DF2E13F1968807A477F64A0D -:10C5500098EE3ED2C5FDFC7E09D001DF3733ACB486 -:10C560006F1EC31A741EE176A72E93ED2E8C1F5EEC -:10C570001BA7EDEF1D8FF7501A562521DECC8D1429 -:10C58000C75AF12A8F632DCB0B73A0FDA371E5C9A8 -:10C5900055181EAAC56987B0FE454BF336846F79DE -:10C5A000D561BAAFDFB8CCF5EEF51C7F648761C505 -:10C5B000B1A44715A29C8BED188FC67872B6561F92 -:10C5C0003F6E8C2737C6911BE940EA7F4F599A93FB -:10C5D00090AF7FF1AC7D2DCEFF8B30711F66BADD41 -:10C5E000100FE0207EB2F8016533CAEB2F7A733D5D -:10C5F000AAE518E8EBEDC85999CEBEDC9FF4F2D657 -:10C60000FC5AC544F1E99A87E4D01231A714A5B9C0 -:10C610006935F2B90526929B97405F237DF003951B -:10C62000F4077C572B743DF8AE56287DE1BB5AFACF -:10C63000FB125D74F5F15D2DFD7D893EFAF8FC2954 -:10C64000CB0EE2B97FF2DAFEBA7A73BC430C7014F7 -:10C65000F316FAEC1C901F1ED42F976E4841FC2E47 -:10C6600059D0D2B41AF0BB644F981BCB8BF1FF802A -:10C670002F16439F78EFB278B7B8BF5CA597C3B3C6 -:10C68000851C2A36339F33364887C54EE68981F6A6 -:10C690000BFA34E4E0FB590BDE7C7F90330DCF19AD -:10C6A000233A233F4AB17828AEB66C57CF9865D06D -:10C6B000EF373DB4D83E80972F6B0FFF6226CAC379 -:10C6C0005DFCFCF7C5DA97A228BE4CD05B8AC51981 -:10C6D0008E78DF54CBE3EBD07EA6C606E962536DBD -:10C6E0005C780F4770BD413AF89EF004F8E1769E01 -:10C6F000E243E41769A913EB1DA1F850CF96EB9321 -:10C70000EF6EB115BC9F3B45FE4B71DE90EB3CD705 -:10C71000FB608E0BEF7554EF4B51919F9B766CC372 -:10C7200073C83F6C5A769F788C07EDF9077C87AD0C -:10C73000E443BE9E3FAF1F15752DEA9FCF5BDCE340 -:10C7400020BFBAF6692B9E2B4ACC7E2BC5673EBB19 -:10C75000C98AF1CA376CDF44DFE76D2FA478CCF9C2 -:10C76000AC92CEA3A7E43B09021EC523958D4E983B -:10C77000F7837D389F2D0EE7FE3DD08F5EC7774A49 -:10C780002E6D577231CE678A7797B510BE8FE9C389 -:10C79000F98C719FB41C9F9C1F4FF0E0F7403E64E2 -:10C7A00070BA4F6FBB2F265F4EA57D31E5725F3AA1 -:10C7B000A74D0DF4E6E7E12CC379F8B8CAED79F599 -:10C7C0007C1F145B039D26E33E3960213DB7DCCC22 -:10C7D000DF792A877F5F07A977A8AAA3D78AD11113 -:10C7E0003A7A9ECE6275F7696EC1A09290FC947100 -:10C7F000E9BAFAD3A6F435D07F5EB09CF8C875BA12 -:10C800007B7FE54B7D2E85F4CC91FAEF8CC71732F8 -:10C810007693AE7D399B14AC87F4BD45E1E79EDD90 -:10C82000319BD10E586CE2E7A7E91AFFBE701FFFDB -:10C83000CEA633DD3EEC9EEEFE03978B16F21B4830 -:10C840007BFB74FC773BF0672CBCF51E3BDEE347BB -:10C85000FB84EE7EB7F017E2BC110FE5C29E549E3A -:10C86000C9ED49E5BE062BBE9300F037C7C5523D62 -:10C870007B1CC655D62A646FC47429C559EAE3B433 -:10C88000B03F8C7F5C784C2DC47D622C2FC6778A9C -:10C8900010BFAFF2B8D48568178A6AFB3EDA42B49B -:10C8A00013A17DCBF01EDA877D5CC26FE75FD505F3 -:10C8B000E1384EC9A57B9B3B0E5A313E6FCA949816 -:10C8C0005CDC3F463A93FC1DF635C515B61C3F4C63 -:10C8D00074D6526C263ABE123C167AB89DD5487F63 -:10C8E000F3588315EFA7CCDBADB8F15C8AF5102EB9 -:10C8F0005D902E0D70898B6D0B0F09A756B819CA64 -:10C90000E7330EAFF9FB143FF2C7367012F033CEA7 -:10C91000BF23F8C975CDD3B431C827E4FAE6E33AAA -:10C92000701C58078E23FD166CB071BFA693FD6A6C -:10C93000A197C7D91AE963D2656E97B9E5B299D2C2 -:10C9400029E3F4FB13DBE13E997A3981CAAF967E85 -:10C9500016C23C512E5C2DDDC8F5487E1CDC27FC40 -:10C960005EC295DE3932DA279BFA88FB1003D94084 -:10C970005D7CB3E0B7C6F6C6F866A91F18E54E6140 -:10C98000A489E22D5B1C69A47748FEAB09B9A2AD6E -:10C99000FC96EA69508FCFC6A393439AB0132E8EAC -:10C9A0004CA377245296C52520BE0AC39C14D75F9A -:10C9B000B84CA538EA42A8E70AD15B56AD484F41CA -:10C9C00039F2F97DBD9EF4813EFFF93D9D1206C30B -:10C9D000385FACB474B2BB82F53E5F999F82F11DA3 -:10C9E0005FACB34DF7B703AF88BEE23ED3CF3E2274 -:10C9F0003977DE743C6A3AB42F5BB9270AAF0F94DB -:10CA0000AEE4F2FDE11E5A78DF8128E7376D73222C -:10CA1000FC9C9B72D04E9C8436DFF8A05E51B232F3 -:10CA2000BF33EA1D65FF38FCA413EF852FB324A0A4 -:10CA30005E7AFA0390930AC939D2274E854117E4EA -:10CA4000878BA4F7CF4E29CC83FEA873A6837F598A -:10CA50008DE7C5DCBA8C8082CE532DA92FDA5557CD -:10CA60003E4DFA4CC9FDCB32F01D426D59CFE8F670 -:10CA7000EC2932DD26E439EAF598A25E8FF135A87B -:10CA8000D7631EF57A4C51AFC7EF151BF47A619A44 -:10CA9000F06F49BB73F79AE65CF4FBF946B2CC4AF7 -:10CAA00092C30E7A17788912EE46FEB4047528CC2C -:10CAB0007F16417607F6C18D3A3CCB7783E5BBC044 -:10CAC000C39A41570BD927D75FB6B3D07BBA235847 -:10CAD0008C2E3FCA9EA4AB9FEF4CD595DF90D85BC0 -:10CAE000577EA32B57971F9B79ADAEFE78F7085D55 -:10CAF000FEE6C137EAEA4FF44CD4E52717CCD0D58F -:10CB00009FEA2DD4954F9BBE40573E435BA4CBDF9D -:10CB1000567C8FAEFEED95CB74E5F29DE47A3C8FAA -:10CB2000D9F0FD173BA5F2BDE4BB5546EFB10D1D95 -:10CB300065E276461B97474BDEEEE908A583D97D73 -:10CB4000B91E7430CB330BE955BE8729DFB95CD4ED -:10CB500097E3359905147E1E6E48423A36D63396D1 -:10CB60000F8D3874C905B8FCA4EFDB53CDC02F86F8 -:10CB70005E73A87F3AE4D3B2E26EA1FC90432FA586 -:10CB800039F15C3AE31633F0ABA1FD0E5DC2F2DD84 -:10CB900059893C3F99916A3268C7BEA9182F3BF466 -:10CBA000FAB4B56E6E4769F7BEBB4C111E784F1CC8 -:10CBB000E1816900E818D34340C7981E013A9E639B -:10CBC00061EC28D031A6C7E07C8ADF7F0BE7534CAD -:10CBD0008FC3F914D377E05C8A69039C4B31FD5D08 -:10CBE000F5744A3FA8D6A8DDEFAB8B29FDA8BA9211 -:10CBF000BE7F525D45E91FAB7DF4FD81BE8A90E3A7 -:10CC000001DD7BA31DBD2B2AFD9CD2AF5953C91A50 -:10CC100023906F349A63BEB207FD951DDB09CCECFF -:10CC2000AB107D2D5BF16CE84BE37775121F17DFBE -:10CC30005DA9DA1388E70F5327F7ECAFA21CAB7C92 -:10CC40001D436D3E34B5FF7EE422411FEBB33C9B98 -:10CC5000B1DD303BBF9F3CCCCEEF1F0F3337D4202C -:10CC60007DD57CC75C18FF733092BFFB51739FD991 -:10CC70008F7650E532DFE7C33B31CAD77CD748F720 -:10CC8000958739DD8928AF64BED5EF8F7F42E27C7E -:10CC9000A41F5EC6F78CBEDC300AF585E10EAB0B37 -:10CCA000F94868DC00FADB0F467E25E7C3703CE9F3 -:10CCB000DFDFF21D0B9872827EFC61F68654B41B96 -:10CCC0000CBFD3EE0E8D5B92FE7AE572A38A765589 -:10CCD000199F24C791F38D34437F79C1F8A361CEA6 -:10CCE000BA5CF477D4943BA8BFCEF0DD9A47F53C0C -:10CCF0002AB5ABCB45BBDCF03207C5C1CA3881CE03 -:10CD000062DD508FD639FAB2467112C3459C04F6E3 -:10CD100063E7E53EEC6778A74012C6810DAFE4EF0C -:10CD2000903DA1F0F7E865DC02D68F08D9B7384FFF -:10CD3000ECB7C7DF60BEA847793C04DFC9F25CE707 -:10CD40001279E977B48F24FBD628C16B1E4ED5BE6D -:10CD5000403AF2DA9C9F45D0FE4EEF8676D3894268 -:10CD6000AFFF27F4720ADBFDF7E9C5C3F1DD95914A -:10CD7000BDCD4837122F12CF1DD191C47B489C19CD -:10CD8000E1B9356E4CF463A4AF8EE84AD2D3303BA0 -:10CD9000C73BE215E3D4241D2997F9BB6EC3CBEC46 -:10CDA00024EF241D19E9A02D1D71BAACB9CB4EFD9D -:10CDB000B5A5A320FE111EFF3A1D35AAE8BFBA5A39 -:10CDC000FAB9A3998D8986A26969DA22C46FE165EF -:10CDD000D751CCCF6623C62049C9720DCB07B62DDB -:10CDE000D7BE69B64487D0D9304167AB3BA82FEB9B -:10CDF000C9772F64FFCF7430FE5B426F782B4CC62F -:10CE0000A9781CB9838271A34BF2397D15A4AAA419 -:10CE1000778CCAE2EF9F3307D7B35DF017F9F14D76 -:10CE20004C3B129D8AEF947AE97DD2319D0CEF93B1 -:10CE30000AFDBCC0E0E7BF29EB06D2CF6FBAC23B08 -:10CE4000D7E3B3847E9DCA52AFF21DD2295964D76D -:10CE5000FEB1EF90F2F76B478BFD9E2CE829DDA524 -:10CE6000B2A1B1F89EBB6646E17204DFAFCDC177D7 -:10CE70005E7D94BF91F9291DCB02A4478C074184A4 -:10CE8000F99B19A37BFB872326CCC43B87A3FA8F8E -:10CE9000EA81DF43DED95B90154FEFECFDC919F253 -:10CEA000CEDEA1D12EBABF7AC89E4E7A28EE574B5D -:10CEB00088BDF44D90CF3D607D87417E63FA3AC8CE -:10CEC000EF1E2047DF00F98DF99B3297316C37C692 -:10CED000A58F7B92EDC73A47C141AD63F88DCD79FF -:10CEE000A52BC2F7AD985EA3912EDE8AB96634AE4B -:10CEF000F7AD98CE269EDAAC9466BFDCA33D3D59D3 -:10CF0000EE87E07863683C237C253C8D7094F0FDCF -:10CF100017E0F9607BF05C84E708B4DFDADF8F4A62 -:10CF20004C43FF26E7B3E51129E23DD2B773D43471 -:10CF30008CF71D42F31C5E752D33A3BFDDCEE1746B -:10CF4000B29AF910BEA7710968F036D8F79879A49B -:10CF500029340EFA659BB615E9EEE44695EEEB9F93 -:10CF60007F318CEC76A7FCDC2EB9D8A43D87E56533 -:10CF7000AA6BAD1BF5CDB754FE8EE8F78753264557 -:10CF80005E05BD6EE1EF1C94D9C7B48B4F79BEAC82 -:10CF90004CF310BF6086DFA3E86AE3EF41C877294E -:10CFA0003BD2B7E4EFB874B5717E2DF1BBD12AF452 -:10CFB00000E86710F0D9E45F86D379EBB104CF21A4 -:10CFC0005C1F9C63E8FDA996AE91249F0E89B8B8BA -:10CFD000E181BEF4DE5A81F8DD8137C47BEE8744FF -:10CFE000BCDC910CED6D6CFF86EB5057B43F5CCF11 -:10CFF000B81FE846077F3FFF6ACFE71F6689F8A1A1 -:10D000001C967355BF9310AFD27D8AE12C83FCF040 -:10D01000A370BEC8E7DE9C6D463919F23B09B4AE79 -:10D02000FF6BBF93C058B38AEB4A762AECB1D4ABFE -:10D03000FFDD04559CABE4EF2714F0A236BF9BF054 -:10D040007854018FCB77CC6BF7771392C5BBD6CCD6 -:10D05000C5E586FCDD84FC44BD1C19E51C71C44992 -:10D06000A9DECE937C85F8B1F86C213FAE16FFE5C2 -:10D070008CF0DF1A67DA89C73F0DD7FAFC12EDF39F -:10D08000A33A59DC7E575B3AF877FB5D948EF064E7 -:10D09000FCBD14239E8CBF9F92AC9699E91D4881DC -:10D0A000A7E9F017F174BDF87D8BD1F8FB16EC7F82 -:10D0B0000E6FE30C78FB96AD1D88EF965E2CE47C3A -:10D0C000BD23B91F9EEA99940DFC6396B01F49FBDE -:10D0D000888CCB35FE7E92B403C8785DDF488E6FB6 -:10D0E000DF8908F25FDDAD3646A29C3961E2BF9769 -:10D0F0009411AF69D8FF1D59950AC223917977CD54 -:10D1000083F9CFFA8D2D05F3B3BAF3F7225916FF41 -:10D11000BD2039BF59C93C9EAB385BF06F378FDFFC -:10D120002ACDE676B248B793E2CC0BB398889F65D8 -:10D1300029B3B2913E8F87F542FA5BCFED818DF82E -:10D140005E65A7E07B95A8A7A35EDC4DE8A5351F2B -:10D15000DBED9C0E994EFEF7F6DB7571CE7DB73B8D -:10D1600075F9ECBA445DFD7EFB5CBAF2DC40A6AE1C -:10D17000BCFF31B72E3FB061B0AEFE351F7974F9F8 -:10D180006B1B0B74F5879CF2EAF2C9ACF95184EF82 -:10D19000E6EC34C25B7745D8495C1C1FB3EE4EA069 -:10D1A000FB4AF2FC21E3DE3541CFC6734D772BD726 -:10D1B000EB6B92183FB7DAC5F994E9CF379A885BE1 -:10D1C000977A3DF3E9E3D665BC7AEB39489C73E482 -:10D1D0007922245EDD83F397F1EAAD7817EF871AA1 -:10D1E000E9F5856CE15733ACA3BB95DFAFABB9C7AD -:10D1F0004AF784E4FC8CF33A2EE298B7DADB7F0F2F -:10D200006A7F36B7AB44F6F0EE417A7D12D815C18D -:10D21000B3CD78EE46FCFD819A7BADEEE5AE2B8F6B -:10D2200037AB1F5FCF4C7C37378BDE5FA57B8172BE -:10D23000DCB7057DEFE9A7B4BBBE59D13C3E8E45B6 -:10D240005BE95E4BC7E371B8265AD90A7AB74ADC64 -:10D25000F3B87D6DDD035834D35A6BE10F0FF82D11 -:10D2600068471B3712F4C45CC0C3334B1E72805E28 -:10D27000F4649599EC621F3C7FEE16D0305BEFEDC5 -:10D280007487731AD2C938C43FF47B533F1E9FFE84 -:10D290006D365F5FBEFA7DEB7D0B9B8EFF33E2FF49 -:10D2A000EDD01DD1A35CC7FFD6FD0B49BF4638C9E1 -:10D2B00073391372AD879897849FDC17127EF2FE44 -:10D2C0008B6B91C5BBD941F7680A302E4FE2EFF660 -:10D2D0007E9C2E7BE57078603DE4471DD5CB57B32F -:10D2E000A2D15FD0C25CD1CE2BD8CDFF97EEA510D6 -:10D2F000FC3BBA4FD7119F68C31F3AB85FD7117D67 -:10D30000D29FABB86717C22778BC94C087BF878904 -:10D31000E2125647EAF7F1B41C2E17FE2EE5850FF0 -:10D32000CEE77A3EC1D0FF51B352157C625EEBEF7F -:10D330008DE0F7B92B2DA47733E67D18E334FEBCDE -:10D34000DE42EF3C0EF730D26F8A362AFE4D4AF0AD -:10D3500077BE0A7D86775AD4EF493FFC76ADE2C4AA -:10D36000DF8B98BD465F3EDFC17FA764AEF1BD1A7B -:10D37000E98FBBC2B9BE2047E8E56EE626BD4CC4C6 -:10D3800051148B3A46BDACC5CFFD8D782E57B91DD3 -:10D390008BE2EFA4DC77A1BF2BE41D16806B78260F -:10D3A000CAF115E676E3225BE1DA41DCC73987880A -:10D3B000FB70F0389796DD61DC3F2CFD70A2FE39E2 -:10D3C000DF252AC7FAD8DBF95C1EBF22FD6F46FFB6 -:10D3D0005E8BC344FEA996DD9114E7807EAF68A002 -:10D3E0008733A65D09835383F3D31A559DDFC8980D -:10D3F0006ACBF6D079F2E11EDAE21C8C6F37BBED16 -:10D400006EC8DFE73844EF788D137630E37C5B7FBE -:10D41000F76F287F57A7C5C7F5DD9602FEDE09F036 -:10D420004786FB49C6734C64A0DD415A18B896E69E -:10D4300073B5FEAFC99773B9FFF7F2106AAFADB914 -:10D4400096F2DD573CB008EF194DAD996FC1508091 -:10D45000C64797E68743D3C66EFEE5E188B7114A13 -:10D46000BBFE8B0773B85C6934DC5B90A9DA8FEF85 -:10D470001B573FC9CF453CD73285F6C36285C9F8F3 -:10D480002EE2E7327FA956E4F3797EC94A9E6F14F3 -:10D49000BFABB04DD85B70DD98E2BAD12EB043D8A7 -:10D4A0006370DD98E2BAF13BF22FCC23FFC23CF26D -:10D4B0002FCC23FFC214F9177E2F62DE945C95FBFC -:10D4C000ED4687EC0FF4DB8D0ED18FD06F179A47A6 -:10D4D000BF5D687DF4DB8596A3DF2EB41CFD76A1CD -:10D4E00079F4DB85D647BF5D689E0DBE3198477ED7 -:10D4F000E799A8CB4F06FD7F74C8FE46BF5D68FF65 -:10D50000E8B7D3F5A72DD2B5BF8D55E9DAA3DF2E45 -:10D51000B4FE1D558ACEAF7787788776F68638A217 -:10D520001F5FAAB701E9FE4F11FFB8CB82E745B5EF -:10D530007E013FB785BB399E6B0B38DE4DFC9E8567 -:10D54000D23C83F0BCD4CAF3F93CCEDB483FE817A9 -:10D550001B6DE17E314CD12F8629FAC53045BFD8ED -:10D56000E89EDC2F8629FAC5F03BFAC53045BF1886 -:10D57000A6E817C314FD6298A25F0C53F48B613BBD -:10D58000F48B618A7E31FC8E7E314CD12F86DF4F49 -:10D59000A07FCE129C17EAF33D74E74AA043DDB9A1 -:10D5A000D2A9CBA33E1F5A1FF5F9D072D4E743CBC3 -:10D5B000519F0FCDA33E1F5A1FF5F9D07C748E8B5F -:10D5C000F621EAF5A1ED50AF0FCD67D7FA5E47DB44 -:10D5D000D9F88D178E60DA18A93CA900CB8879613B -:10D5E000C534F45F3686292931C0392DCAFDD346AA -:10D5F0002701998838CA1CD66CA2DFEBC3C323C6A7 -:10D60000390418C5AD667F9744E569F2FE1DFE0139 -:10D61000BCE7EE66F47B34D2BF2EDBBB9953C55416 -:10D62000D60FE6DBAF671C5FD623FE19320FBC694D -:10D630008DF13EB94B1D791837BB4DFC5EEEB6E55A -:10D640003CDEDA4857F9425FDA66DA7508EFD33420 -:10D65000172A74EF3AC3CC8E59F2104E9579A84729 -:10D6600064F78B11EBAABC0E7F774CCE5BDA41815D -:10D670004FD0FDC4A1CD0DA3A2A11FCD37827E1F27 -:10D68000679C95EB0FD80ECF957D7D8A6773087DDB -:10D690005F23F471CDC7C77FE6A909BC5D386FF77A -:10D6A000CC535104C7092B148A3B1BBA8379F01E53 -:10D6B000B447CCBBEF8E808AE315AEE0E3C97E0BA6 -:10D6C00037A6D0BDD042D6381AEFB5B0010A43BE56 -:10D6D0002DE106EB3B82EBCB80AD8276EC1F7B9F8E -:10D6E0006AD880987C8C4764F58CDE151D3FE03D40 -:10D6F000DD7A09ED83A85F926BBD7C0ABDE33CC176 -:10D70000B76C39826FBC6FD1EBF1587F0B73A7BA3E -:10D710004814D1FD63399F3E9E5D26108B2C8B35BE -:10D7200098C214C4373B1C17423FB0F3A720BE7306 -:10D73000DD167A5779A2D969A1773A3A88D7B9E440 -:10D7400090F13A067DC1109753B3F4A314B4372F68 -:10D750008E3491DD64F19E08D21BB40D0AF135A917 -:10D7600007158A78BF4B2B5E8F9F8670DF65A1FE01 -:10D7700064BC4E79BA3FC584F713BA6CCA8955495F -:10D780000F58D20FF500DF4BB70CC67A2BF9BBA2AE -:10D790009756ECE1BF4B2AFC3BF2774EE788F8AF97 -:10D7A000C26C6F34C6C3C8DF5393F764E4EF984A82 -:10D7B0003B4FE1DBFD8F227E0B9F10EF7EAF29A454 -:10D7C000FBEFC6B8AB52A1FF2D5861A1B8AD05065D -:10D7D000FDB054C4655DE9F74DD7F633E887F277BD -:10D7E00072441DA676FD3DDA85E5BDCF9916CE07BC -:10D7F00066EE62E4AF9AB96C9409DFAB667B38FDE4 -:10D80000CC5CC6F59C99AF78E8FEA6D41BDF15FA70 -:10D81000CCA4CBC904FFF785FE3215E35501CEE356 -:10D820001AC3441C5B12A5D32EF3F8D5490ECE0FB4 -:10D830001AF7F377375A7C36AE571D61FCDD380393 -:10D840007D4E34FB4D78A1D13D14E813F2E3511F16 -:10D8500082FEA6A37E1487F49E9A4FF190050ADDFE -:10D860002332D2FB384BE5EB186F3B6E2B73FB5822 -:10D8700028BD031D637F3E85DE63D0C43957D2B116 -:10D8800091EE674508FB9483DB9F5AED14A8ABD259 -:10D8900023EA7F9A86F1C4B3D066D88596E1C1B8F1 -:10D8A000BDC82C5E7EB4DF9FA6ADC0BB1F1DD82DAA -:10D8B000D49F58091E9A7C77A2033B02DA0F905F2F -:10D8C000DE7E67AEB528845F3E9C3BF22BF7C0201E -:10D8D000BE8B0CF72917DFD7937EFFA823BD7836C0 -:10D8E000C015F7C7ACE8C6BB8052D99FFB31CFE863 -:10D8F000C1F8FB92727D2C80F198B78A7C6C9DED0B -:10D90000A3350E820BE59BFA9D9F867134E5F6C622 -:10D9100031487615599505189F1DE4539A273915F6 -:10D92000F9546E007F8FEFB8944306FB44AC9BD74D -:10D9300037DA29666771FECDC47BE39FDFF7F24ECD -:10D94000945B72FE9F5BF4F76A651AEE16F2A3FA17 -:10D950007FE65E89F13EC9AF92B5BFF783FE1F3601 -:10D96000F1F713BAA8B54CD88BC8AF2CF90613EF52 -:10D970008E04F1EEA1F78DFF0B290E70D50080000B -:10D98000000000001F8B080000000000000BED7D70 -:10D990000B7854D5B5F03E73E69564122621210F1D -:10D9A00048980402A94698BC20BC0F9147B068076C -:10D9B00092286812268447B068236A0D2D2D139291 -:10D9C0006040F0068D82D4C780CA45A51A955B4198 -:10D9D000693B48B56A513148F5D6DE303C7DB535F6 -:10D9E000E2F5AAFFE76DEF5A6BEF9D99733213F0E2 -:10D9F000D1FFEF7FBF8E9FDF669FBDCF7EACBDDEC8 -:10DA00006BED93960D8A735D36635E87F5849200A5 -:10DA100065BB12B08D618CF9666AC13C46BFBFE53B -:10DA2000307678B48BB114A8E4F5DEF3703263B5C8 -:10DA30006BAD6C233C7A6014D318D41FF891D5EFEA -:10DA40008371AAAD475EB04399E4E6FDDF69BAC3CE -:10DA5000C24C384A20D705FDAE6E8C716F84F6BB80 -:10DA60000B3C896E688FCB775BBD0EC6CEBA19F5BD -:10DA70009F91E249C6E7D76D3A78FF5BF0E8070768 -:10DA8000B2ADDE7CC6EAF615AC4F73E17BDE74778F -:10DA900009D41D4EAB07DEBBBE35D1EA82B2369546 -:10DAA0003576E5E33CBD59F3E361CDF89BC658817B -:10DAB0005B610CFA7F50C0A8FCC8C216F07E1D96B0 -:10DAC00079BA7E266A671D5B35FB108003DF3ACB8F -:10DAD00034339FA990B1E1562FD360FD2DE9CC8D51 -:10DAE000F01A0ACF6D85BC3D2629043F23DCAC8C9F -:10DAF0006926681F0AA5B53004C74C6857E1B925E7 -:10DB0000EFE442968370638B703F723DB25C2CD61B -:10DB1000CF16D84D0CD6B5D40EFF862166AAF9B320 -:10DB2000528B195BB54571DAE0D11287EBAA095027 -:10DB30005FF29285AD83FADC2497351DEABD70BE95 -:10DB40003BA1BEF8A602AB0BF65D8D6701EB58B2A8 -:10DB50006D02730D86D20F6551FF796579CD9643BD -:10DB600099FB5D787C9AD503F05AE2D4AC49F9A1CF -:10DB7000F6FA0E45F33BFAD7E7BB55DA67351C29B1 -:10DB8000C2AFE6A66CEB6207D65FB2ACCAC77DB97E -:10DB9000685FF23DE817C07E7373D88B0CD70DFB1E -:10DBA000DA99CDE72B0C1B7F318E1F363FF45FE4F3 -:10DBB000C17DB9E369BE3A27EC3B1B4B27AD13E0AF -:10DBC0004070EADD0CE3B9681E3A8FFA80DFE2C6E6 -:10DBD000F598615EA85FEDF45B709EC5AD055606D5 -:10DBE000A577139FC7DB9E68BD04EA7566A735134A -:10DBF000E789055824D3FAFC3BE16896005C921C47 -:10DC0000380F5B34DFD11F3E7562BD4B3A12AD4B0E -:10DC100075CFB758F03C16C27ABA229CFBED78EE6D -:10DC200029B89EE95686EF9B35AB1BD723E07BE6F0 -:10DC300086988D6C10BCDFB9D5920DF59F22FEA69B -:10DC4000E07B1CBFE6E6047215DCF70D316E5CE785 -:10DC5000426707EDAF0FBE77013CE0F952A787E0BE -:10DC60000B78E1630087259DFAF30CAD87C37749F4 -:10DC7000671DD1DB32B3D7EA0C5FC7B683B90AC0E0 -:10DC80006521D0B702F0674E6F16E2CBD9BBAECAA2 -:10DC9000A27DC23A11AEF16ED7ACB462C213C263B8 -:10DCA000892FB5459C7EE57CBBDC669A6F97D8577B -:10DCB00074BAD45E4C43BA84F35DE78A4E97560635 -:10DCC000E3C1BCD6258ABF45E94FA7923E255D4AF0 -:10DCD0003A95F47BBFC5134853427CA676106B7C03 -:10DCE0002A029CCE0A3E72B5385780EB6F10AEB256 -:10DCF000FD7571AED5397A7AC7F170DCE7647B596E -:10DD000020F786FC507F396F75127F0FF11EF1ED01 -:10DD100039011FECBF8AFA0B78097E51DFC72FF655 -:10DD2000B40D417EF1A4E2467EB16AF3A1CC5B0062 -:10DD30006EAB7E1E879C977DB8F2E1EBD3010ECCD3 -:10DD4000ECA77393EB5AFA7901F189659F4FE2FCD6 -:10DD50002210995FB8F2BC87916FCBFA923B7F3E5D -:10DD6000CACBF94D00F9CD1F7FFEDCB189C84798B9 -:10DD7000DFE2B924B49FC5ED6F58EA1CE1F0E3FC83 -:10DD80006E63DEB93A3CAF7A87D5A5C2A3FAD63A1C -:10DD9000E2BF2C8DB97395D0F91BF1A2AE55D1E835 -:10DDA000BDA6717EF55BE4D3F59BE6319453F2DCBE -:10DDB0006062C6C6C13E1987AF5CFF4762FDE704DB -:10DDC0007FBB5AE0F7D50DD3ADE9C9B8DFBA22E081 -:10DDD0008C6CA178BE7089FE79DFB939FBF8FC7ACA -:10DDE000A497735DFCDCCE6DB210FF39B727DECF90 -:10DDF000607F1FAE7AE6B52BA1DF0777EFC862AA76 -:10DE0000FEDC58113F372C97C3B9B1C111CF4D2D4E -:10DE100008E3C3CB1FE0E756FFF8ABFFF1AC8BF68E -:10DE2000CBF9DD669B1FF9F1E2AE27E91C17B66F4F -:10DE3000B16443BFC105D93A3E5EDF58E06400DFFC -:10DE4000ABDB7758904F0C2EE07034D203941A0B52 -:10DE5000A333944B4A12E25F301DF14FF647FEF8B0 -:10DE600024CC73D30D31096C6C689EC9059CCEEA35 -:10DE70001B139370BEFAC6BADBD998903C30EEF310 -:10DE8000540CA797C5301ED2EDA9E9EEAC55849F7E -:10DE9000A68872B7A8809FE3CF00DC31800F43E3F0 -:10DEA000BA1E41380CFD41AC1BF9C7C891413FCEA9 -:10DEB0008BF88DEBB602FFB443BF912B831FE33A7F -:10DEC000460286E17B58C62751C986407D272CBB78 -:10DED00014CA1C95970B0B389E407B00DB5972B01F -:10DEE00004F72FF1DB88BF56F6507B0EF2B164E6E3 -:10DEF0006E7185F0558E23F155E273B4FDCD2BE0A4 -:10DF00007CE57CFB3B95CDE1698D85FD257D85FD1F -:10DF100001B2962685F625D7C7F2605DA83FFEF8C8 -:10DF2000921D1B619E53CDEEAC46C740FBED9C3964 -:10DF300024C27E8DFB9474B3C4CE691AE866501077 -:10DF4000D67DAE63C420943BA714906FF0DEA91B6E -:10DF5000624CB87EB9AF5D6BA133AC75F75A3B9597 -:10DF60008FAE05C21BCDD89EB569547F7CAD8BCAE0 -:10DF7000AEB579F4FCE68224BE0F168C473D13F44F -:10DF800001CE0F029C4E7A9A46D0BEE473A917F4D4 -:10DF90003883F14961FCFB74A3909B2CB819E99B71 -:10DFA000358D600FC3543D1DA7E24DF9889F7C7DE0 -:10DFB000F2BD9B2CBDC40F59BCD5F530905CDC4D37 -:10DFC0006FCC4C85F99676661728F05E4D53514F0D -:10DFD00013B4D7B4A6BA916F2C75B8D6A35C5CEA1B -:10DFE000CB76A35C8CEB2C38BB0DDA97B65EECC617 -:10DFF000FE3729CC83F405FC9321DC96B1BE9F66E5 -:10E0000007BEB65CF0B5E5C82F015ECB9A0E8D74E5 -:10E01000C2FBCBDC310528DF976FE376C25C136B64 -:10E0200057500EB77866211FEBBD4771A3BEC9EEEE -:10E0300005FE6A0FF1577F9EA7A300E5D297807F68 -:10E0400030FE45288355DC579786FB60A08F3CCC7B -:10E0500070DD1ED2EB07097CE9E93C11EFCAE7F05D -:10E06000467D9D793513F2DD5542AE0DB7F69EB86B -:10E0700015F59978937B27E797AFBB709F2FABCCB3 -:10E0800046F246F417FC74F84F4BEDC8DF56C5E76F -:10E09000A4925EB54D25FE28F1A741AC79E98E8AA0 -:10E0A0002188374BA11DE5DD767C082C747DE7A522 -:10E0B0004310AF966C9979B70FE4589680E3697373 -:10E0C000701E9ECF7B3B52939A512FBCAE6514833A -:10E0D000F6253B6ECDC2F2BD1D310B90DFCF70CE69 -:10E0E0009B9108FB5D766F62811A26377E2DE8F1E1 -:10E0F000DAEB2E4D457B60E55F0FDDEF1C01F3038E -:10E10000AC11EE9F76C5F97DD065E5DA7D592AD050 -:10E11000D85F6DDE67916F7FDF74E0CA09C8FF15B5 -:10E12000FFAE74EAEF4A7546A0F73EF90AF8EE0230 -:10E130007CBEEEA76FD3387F361DBE6221BCBFF216 -:10E14000BAA713709CEFDF75749C139EDF3DD2FB62 -:10E15000229ED707CA8E5D4E144CDB768C41B9FDEA -:10E160005B6147CD4DF25CB910E1FEB24A708F366B -:10E170005FC33E85E02BEB35FE41A4CF7A03CCEAAA -:10E18000C4D2C9485F7E4F654DA80F48BD463EFFCB -:10E190008380CB7B833AB2102F56ECDA9A8572E5F6 -:10E1A000FD785EAFDE75D52BC8A7BC0FD9B8DE6E83 -:10E1B00066A427D7FBB8DECD1A805ED343F39F2E2B -:10E1C00088A3F5AFD856A4938780A1F4FC7D332BA8 -:10E1D000C7750C6FE92D40FDEB1D7360299EEB3B6D -:10E1E000A0D7A27DFB6B21CFDEE95067E1731F1042 -:10E1F00012EA23EF743C1D3FD211D2E3E28BBB0243 -:10E20000C8E7AEDB9B58A8729422FCBADE29F993CA -:10E2100063D6D064D2C79C88A7ABF6BF308BF13AE7 -:10E2200008C2E8F0BC56E8617DF5BD4F925DB7725B -:10E230000FD72756763DF962068C73FD3EA14F0835 -:10E240003DE53A41CFD7EFE570B96EEF096B7DB888 -:10E250003D9297B47E286882B6C2410BEE72A1BD92 -:10E260000D8B9808F8DD655AD80C4C3CCBEDE47A60 -:10E27000A5B997F4C38D79DD64975FD72AC6CBEB38 -:10E280005E9F43FB9D37385C1FB2175A08AEF27D84 -:10E290008007BDF7594CC218E47F81EB62DB51AEB9 -:10E2A0006BD73BCC58B65CE720397F6FA329CF0CE6 -:10E2B000F0D5945837EA714D76DEFF96D8849D5894 -:10E2C0001E88E5F5CF62B2484E7D66F23CB90CFA85 -:10E2D000DDA21E896123F0C87B0F99A03E2AC53BB1 -:10E2E000BC10E64F65403D2ACA8F8082ED1FFDF2CB -:10E2F000DD225CC7D4E1C14F182CCDA2242E9C0195 -:10E300007832BAD0C9F97B7EB008F13DE579CEAF5D -:10E31000EFB3B0769477CCEC61F3E17900F9179E16 -:10E32000FF17263FF2E3034AE0C170FDABBA90EB62 -:10E330000F1E9BA35D81752ECFF6BA711DDF532C86 -:10E3400097A0EAC25C6A2E8EFF9185B74B3DB64C12 -:10E3500030E14C618F5933D21CB8BF16012F45D321 -:10E360005813AC635DFEF3F5882FB7F5DA990DE627 -:10E370002FEB8D25BD3633A39CE45B8B808BE24A6B -:10E380004699C39ECF37F96CB0DEDB98DD8FFD99DF -:10E39000DDA0FF9A62347C4F39F0DB2F90DF0F5500 -:10E3A0003F3E3408FA0FBD4571B7409FDA7367EFFF -:10E3B0007B9DA1FDEC2F40F82D4DF15E5608E7D96D -:10E3C00073AEFC8417CEFB366797DD9DCFC70BDF9E -:10E3D000C781D55F24249942EBFBA8F7ECCF9F2996 -:10E3E000C6D24E72A8EC80CAFD4D86F57C94E6320A -:10E3F000D339F5DA0326ECEF30F91505FB1F7A1B4C -:10E40000D75766770454D4E3ED963F85CB1976242D -:10E4100033F1ECC5245AD8DF405918D2C2CF6FEA85 -:10E4200020BD7DF98342AE3FFE409C9384AF841BA8 -:10E4300073692C5CCEFCCAB1AB86FBB1381DFF40C2 -:10E440003C3FF7790EE917E70E809E1141EF94E506 -:10E4500051D433407F08E468B7149684E46C9594F3 -:10E46000BA420EAB62DC2A01AF2A8789C3A7D20069 -:10E470001F813746BC309EBB3C4FF6A3232F0CCAEE -:10E48000A673BCE45F189DDF3A5C47CF1787DB803B -:10E49000DC5886AA9DF066FF239E5F206634EA154D -:10E4A000779948AF40BD0FF544C93FBCC807C6D2F5 -:10E4B00073AE07E631E21BB56A2CF9198D7C43F285 -:10E4C0000B6F2C9463906F74103FB845ED7DC1A421 -:10E4D00084F8C4F0F2E02528877BC0F4C7F6A0A931 -:10E4E0008B9EBF549843F8328C1D49C7E760AF94A8 -:10E4F000A01EA8DA1FBCEF348894CE0D9C3E5A2C87 -:10E50000FE7B96217FA872B851AFFBC86FF25960AD -:10E510009D9D899C6F74AEC82079FE11137C648127 -:10E5200095F8C82493C947F6D6C20CB2B7FAFAE7F1 -:10E53000BAC8BFFA8BBFAAA3B661FB3C3BC9DD4E8C -:10E5400094C750EFDC7C09B53F27F9D20ACE973A41 -:10E55000E769E9B1D83E6F8809E7DB9EEC7D1ECF05 -:10E560003D43F53F1283FAE4F763D9C3F0BC335B54 -:10E570004B47797BB7E259B814DFBF84AF3BB83063 -:10E58000F6F15DFC7802E84FEA698ADFB9314C3E6A -:10E590001D1ECDF9FA70DF897B105EBE329687FAB8 -:10E5A0007C0FE2E7D8D0798155CE9A9242E7966CFB -:10E5B000383789AF3E0B9C5F323FBF754AF4F34B4F -:10E5C00016E7A734017E13FFE7E7738BCAF93BFB1D -:10E5D0001518E0507E9CE20DE27E5B6E8073218117 -:10E5E00018BC19E175DFEA780DF7D163620D5D1192 -:10E5F000E8F643C11F184A63A08745821E1649BC2E -:10E600005D63C0DBE0B0C4B371026FE1FDE7E23CE3 -:10E610007FC679FFAC1C1D870F0FFFB7BA20D23C15 -:10E62000FF25F8CF41BBF7D34292AF653A7DF57035 -:10E63000C1BB9928A7D8978786A1DC7D2AD9F33951 -:10E640008E1B33B297FCE63DE9BD16DC67CFC20FE7 -:10E6500032512F5AD4F45BA2AF0B5DE7BAB85A0B14 -:10E660008E9358996D0942995A99FD02E2CFB139BA -:10E6700036972D821E7270CEE84CD47FBBAB4667B6 -:10E6800022DFEB86033C82EB33BBE291FFB17D35A9 -:10E69000C4C7AA041FEBAE1CC19F0BBE19F67C7346 -:10E6A00031EAB50E933B5C5F3096EF03DF0C00DF81 -:10E6B0007C17EC332CCF807D1600FDF514D86758FD -:10E6C0003F01F61996C7C13EC3B27BAD9BDA5B2A08 -:10E6D00047EC0BC2397FDAAED0F8E8BF8DA4175FE4 -:10E6E000FB90CA02123EF07FC3BD712C9017AA2F77 -:10E6F000EB1CACAB2FD93454575FDC3A4257977AB6 -:10E70000A477CDC5BA712BCA8B74FDD6C58DB1E087 -:10E71000B926961770B8971710DCBB2F8F02F7CB6E -:10E72000C713DC8FCE199F89F03C8A7047FBCDEC74 -:10E730008EC77390709F2FE63C5A5EC49F0BB887BC -:10E740009E570C28A73E4478DB10EE762ADF4578EA -:10E7500013DC39BC4F21BC6D08F73C2A8F23BC4722 -:10E76000E3B800EFE2F3C37BE51E5507876B1FD2CA -:10E77000C3BBE1DEC106F80FD5C171C9A611BABA93 -:10E7800084F7E2563DBCBD6B8A0CFD18DB0470A813 -:10E79000C07F001D1C2D994D7129B39DF9E280AFFA -:10E7A0002422BDC1FACD950AD78FE0D70174381F56 -:10E7B000FF01F46576F0F6D6858A1FF912EA4468FF -:10E7C00057005C0371406715CE5167902F5D851C23 -:10E7D0004C45BBDE4FE5352C40F459C382545FC431 -:10E7E0007AB3AC505EAF06D6A3FFEE55BBF7C62298 -:10E7F000A0FBFF9AF3468F8244E9AE1B8D74CE1CBA -:10E8000049646F463B27E0945C1FC7AEE3C4BEE09B -:10E810005789FC1FDEEB8E1B73F3CD700E1FD505E1 -:10E82000C7E1FC2BEDDE07924D345F7311F2258BAF -:10E8300077F46078FE6AC9F84CA47FE649D1D949DB -:10E84000D1E6DB829B0538D495039C148CC371B848 -:10E850009CAEE27039B8C566457FC6E90D16F25721 -:10E860006E8DCBCA42BC3DDD363B0BF1AE79CBE8B9 -:10E870002CC4F7F9EDB3DF47FE3D539D5B8BEF9F53 -:10E88000ECE078CFD80DA477DD2CCEEEA48BB903C5 -:10E89000D05E3527DEED83FD787DD909B45EA639DB -:10E8A0000AA05FBDD8777DC7F2B9389EDCFFE24D84 -:10E8B00036DDF97FAF545FAF62D6109E65E3395BFA -:10E8C00043ED78FE6AF520EF007674D31F77BCF233 -:10E8D0009BB0F11E2B8A4F46BECAC6B3F17F53438D -:10E8E000EF4783EB676BFDAFFC26370457894FEB8F -:10E8F0008B3C7B111FE031C5DB8096481E5CDFE757 -:10E90000D73A9080F0DB12F7ABDB27215CDEE47EA8 -:10E910008EAD71B5C43F3E44BE9D8D7CFAAACC60DD -:10E92000185F90EF07053F3DF6F3AB888F1CAA4AAE -:10E93000A5784CF75EEE5F3E2EE8BEBBF2AA9A9B2E -:10E94000817F76EF5149CFEBDEF7C90BE8A7E9EEFF -:10E9500052DC02E4A6F071BBF7013F477EEBB150F9 -:10E96000FBC13D4FD33ABF2D7E5EB95FF0F36D7CA6 -:10E97000FEA5660FF117E65DA0DBDFDF8BAF9F8F93 -:10E980009F1FB3703CED3EA692BF8DF9B42379432F -:10E99000C2F0B39CE36773958D71F9CAF9CCFC4A58 -:10E9A000A003D4F399AB046DCA0FF755A490BCDC57 -:10E9B000643989FAB413FE43B96D846315339F0C2F -:10E9C00086E1EFCABDD03F6C7DF3B13D0C9F8DF861 -:10E9D000AA1403BE5E1CC2D74FD99759D61CDE7E3F -:10E9E000644888EFE12F9CBF48BE25F117F8562DEB -:10E9F000F235E02B8E62C0DB1F1666FF32A884F171 -:10EA0000950BE4635BE2FE4A72706BDC5F098F8FEB -:10EA100056093C063D039F775FCEF50DE65F40F457 -:10EA2000B048EA11164F3CFA498FAD199C80ED278A -:10EA30005A2B88EE243D19E73B2EF04FF65B64EE2F -:10EA4000B5B823C843EF1A3DFEB0DD0B08DF6F36C3 -:10EA5000E059B4F18DFDE53C8B0CF15EE33C938B0A -:10EA600085DED9557341F32119F6BD4FFA6D6C0857 -:10EA70002F55E4039FC50749FF5AA0D3CB8E978F2C -:10EA800027BDEC68E52711F5B3E3959FBC3A1EE975 -:10EA9000ADDC22E8BD81DEAF10EDC675BC2BF4867F -:10EAA00033827F9C12742DDBD51D6D43AE46BC5F57 -:10EAB000A3BA915F1D9B5B4478FE9EBF8AE63F5ED2 -:10EAC000A992BFA976EF77AE467F935C8F9CAFE2A9 -:10EAD000F24FE2D19FF629C00BFD631516774A2449 -:10EAE000FDC2088F68E34AFC017DF618EEF328F2B8 -:10EAF000516CF5EAE17414DF87F6F93B548AB719D3 -:10EB0000E17468CE68E24BC7770BFE0970453DBCE7 -:10EB1000E15EFDB92EEB8C33F09BC1BAF6F9555C82 -:10EB20002F93FC5AAEEFE89A1129CC71E1E72DC77B -:10EB3000B9507CB956BC8F62F36F247F9374E38124 -:10EB4000A568982FC7D07E91A1BD505FBF403C3EC5 -:10EB500021F047CA9F1331EE9A4871BCE397D91A46 -:10EB6000C2F313FEB598FB87FFB558C4BDBFA2DC46 -:10EB7000DE69E083E77B5FF2BDA622CF23C8EF58B2 -:10EB8000A082E2D917CAE7C2E4FC93C548E741C5B1 -:10EB90008AEF4BBDEADA722E17B6C63D4E791A7F60 -:10EBA0006EE67AD1C1661BE1E15F2EE7ED7FF9B732 -:10EBB00077499F3AB47F6B42B89C9778F9FEBED9EB -:10EBC00009E8173E5DF96042B81D20DB3FA87CF0E4 -:10EBD000F68944DFAA7BA073F9BAF64077A5B0079F -:10EBE00084BEF07D73D7FF157BC06807CC54EF4D12 -:10EBF00040FE67B407DE7769094E828FA03B21573C -:10EC0000AE15F0F98B454BA038DDEE222E570CF8EF -:10EC100029E17056C26153C580787346C805595FB3 -:10EC20006A66040FAF9D91BECC3A1537C6BF304D12 -:10EC3000A514CEE54865C183E8BF92FD7F54C2F3B9 -:10EC4000A9E43CC7EE53BAD0BFF2DBD68A9A9B3117 -:10EC5000DF616E1CF155D97F996F60F9756C73E2B5 -:10EC600015388F779BEAC6475EDF8994F0F54B3DF8 -:10EC7000CDF8DE0A73C705D9D15EDF8E04B46F8389 -:10EC8000629DC1833156577CFFF7305E83FB5F3155 -:10EC9000577537C3FA576CE2EBAAF2A9EE1CA8FF2E -:10ECA000B6E3C12B900E4E35594CDC3E70EAF0FCB9 -:10ECB0007047D16BD8FF7439972B272A2F4DC03C52 -:10ECC00038DF368B3BD7D57FBED108478CF3ECB30A -:10ECD00099D07FFA7E938505C87FE1217BF9D8A67C -:10ECE0001154BE8FF0E3F6359D7F5109F7739DEA0D -:10ECF000A81FC2E9C945EB90F87262B75AEE8FC0FF -:10ED0000AF8AC47C67BE7C82F0EDC5DD15248F4FD1 -:10ED100055F279CEAC7127203C7FB749253A3EEDBC -:10ED2000E3E31FDC7F6BC244D8C7FB957C5FEFEF4A -:10ED3000BBE5B509B0CF60A594C75C4EC9FC9EE0A9 -:10ED4000A61114EFFD732BB7BF25BDCB78F8A5AB8B -:10ED50008F25D0FB52CEED59A05B7FF7EE53648731 -:10ED6000BDBF0966E372CE5180F986FC75B66CAE04 -:10ED7000FE7CE757C6E9EA8BDAF5F2AC793FE75754 -:10ED8000463D77E926D083D12F65B0F3EA9B8B12FD -:10ED90004A917E510FC63C93872B5E48C57D74D542 -:10EDA00050BF4A1137ABEFB4E9F84155ABDEAE5B6B -:10EDB0006CB0E3FAD975067924E1745D14F924F591 -:10EDC000B96E61AF1CB7786A22E553AC2EE17ADBED -:10EDD00022A0DF348C1331AD6A9280F746848FB560 -:10EDE000F7D35CD0A7BB55F714D4ABFBD181410F4F -:10EDF000AC28D7C397B97DAC54FA235CA4DF9F45F8 -:10EE0000FDBF7DB090DB3E9043F12897B41F97A0E3 -:10EE10005CBA50FFC105EBE7B5423FAFD5E9E7DD8E -:10EE2000D825ECFD835557919FEAD8E55791BE7ED2 -:10EE3000ACCF4FE5D1F9A9A45E776C6E854EFF0C7F -:10EE40007B3E880DC04FA3E99B27901F139FE6725E -:10EE500069BDB0235B851D796CAEB0239319D19148 -:10EE6000D9ACB148FCECABEA6F8B5BF572C9BB4621 -:10EE70006F3F3E33DDFB5409E0872DED22DD738BC0 -:10EE8000B350EF3F34E0E750C6FDE7B7A22F00E0F4 -:10EE9000DE52C5F34EF139E6BF48B9C4A03FF28B4C -:10EEA000AA4D17F937F2769F5A88E9720C553AEA5B -:10EEB0006FE6754DE1759F43B4AB22EFCD02F513BC -:10EEC000D9EE05A877615E4F5C126F4714190A7876 -:10EED0009D9014927FE8D78FE1A1755F02BC37AC9B -:10EEE00032FB3748D798EF330AEAC74AB2096FD2E4 -:10EEF000D0A55F48E30730AF27D8328DFCCD15F69B -:10EF0000041E9F073B7A60FC6BE6F650F9609A6C32 -:10EF10009899AF272A3E8B7EE7C3E7303DEC24D19A -:10EF20000B3391BF654BDC180BE2EF7C872713E1B5 -:10EF300000F84EF2B5FB9756E2C307ABB81FB67B9D -:10EF4000CEF8FB6E82E7639E70902FBD7BA9F483A1 -:10EF5000F7C687E3EDF135A74CC8977FBF8FB9316E -:10EF60008FF1F89EEA175E81710EADA9DF5C8274A5 -:10EF7000745825BBC1E8BF9DFEC464B2BFAEBC5C83 -:10EF8000A5FCEEA3E52A43B9767453ACCE0E09F97D -:10EF90007555C28F4F0F98A91D4D9D3CCCBF42FFA8 -:10EFA00026E66995F3737956F0B32E718E8F083D7E -:10EFB0006697A09B4E41377708BAD960F4EFDECB55 -:10EFC000E9E6E83E301C40AEBF3EB7BE8CFCD6DB67 -:10EFD00018C5A1B3E7A81B8B617F17DBDC1684DFA4 -:10EFE000F4B9051C9E958A09E33715E50516A4F7C3 -:10EFF0008B07BB2CC8472BCAE7517D466536D9F92C -:10F0000007D7807C447B3FDE9D89743972AE2D60CA -:10F010004A40BBB188F8C4A4F74C3A7A2908C4EA3C -:10F02000E8EEA2879274EDA3B765E8EA299E1C5D1D -:10F03000FFC1E57A7A8C1D59A8E7BB8CEB8512CE0F -:10F0400033D5C9E4E73A1E92A3D42EF511E9AF9364 -:10F05000FD015A3ABED62EE4C818A8633EDD86CA22 -:10F06000163BE64D7CDA6576F3F1AB493FB067EFCE -:10F07000B5239D606815F3ABDAA5FE29FCF74C6358 -:10F0800086756D6218673D5ECE089F62463205F553 -:10F09000AF4E71DE778A7981AF4EB7909F8E9FE336 -:10F0A000E0B91EEAC73C7AFB200DE9AC10F184BF41 -:10F0B000FF88787F97C097E3E50FAE8B457C58C0FB -:10F0C00048DF98A9AE5C87F1C4E37319D14957E0D2 -:10F0D000F9585C3F8E83F981CF461BA7F2E977AEE2 -:10F0E000C7F5ECB6D238150FB1A98827177DEFC444 -:10F0F00007AF21F8B6390FC5B0FE7278CC439A1B22 -:10F100008193F71E0B58A80C68C87FF2DE3BA26102 -:10F110003CF0A2BFECFEE07186F372B9D02EF0DBBA -:10F12000C85F1F7BF8178B513E3FB66B7BE1DB500E -:10F130007E67DD3D194D503EB2EEFBDB6F7285FC04 -:10F14000A5BBAE58BEB313EAA3BFFB9347F7225E3D -:10F150005DF1933FECC5F55EF1C57F3860FDA35AC4 -:10F16000E219D2B75C9F719E34D6AE605C14F92868 -:10F17000F165B38FEA753EBDFD6394FBD8DF0CF0FB -:10F18000AB687A8CE2CB69E2FDA397DFAAA830EFE7 -:10F19000DB759CAF74AFEDED9C61A1FE01EC0F7CC3 -:10F1A00092F235870E03B682EF5B7D0AC6C54141F8 -:10F1B0007263BC371DDA919F33978BF4AB2C89BFF8 -:10F1C00082AFE0350746FE4033E1599E884722FF73 -:10F1D000457E7FE7381E071FEA601A9E6FF9739B12 -:10F1E00014CC537BCBEB72935EB096DD3503ECE42D -:10F1F0008B549E779157FED6D5782EB055B3B73045 -:10F2000034EE6EA1D7953FE7A0BCEDB7763B769084 -:10F210009E7FE40A53B87E58F6D89F9EFA1DE257A7 -:10F220005D0CE197516FE916F4D157B7B8EEBB0901 -:10F23000E0E3FBA59DDB559A2B93EC74B72B13F3FE -:10F2400077FAFAFD44C6D3DCFF81FC7C7E751CC5D1 -:10F2500019645C492DFFB80DE97151696309EAEF42 -:10F2600019780E834371ECB7575829DFC0A7C452F1 -:10F270005E7AB478F5A171D9229EDC3896D6C11A8F -:10F28000C763F9C98296FBACAEE8F2AA559C6BB491 -:10F29000768B957923C5950F8DE3FE90163C074B31 -:10F2A000D839387E7F35C687A39D0333FB0B29CF22 -:10F2B000D26E1F897920A9E2F1D6B89FBE8AF2AA40 -:10F2C000E7189757A94D9FAD45FA937E8BDA34D650 -:10F2D0001737D3E03D8B782F55C459908651FFAE38 -:10F2E00015F1A29E1A46F1A2D4A677FF1BE1B34501 -:10F2F0008C5FFB261FDF6A0E1C447CA975B848EEA4 -:10F30000F4A424B8F15E13FB92E7A764308E8F72E9 -:10F310007C26C6C795B3B075A7C656BF4ED7A7A65D -:10F32000B2401CE28F62A77933D6D828AF55EA578E -:10F33000A94DB7DEA08ED18DA7A05EFD5635B7B71B -:10F34000D1ECEC1B375BA757919E655C877CAFC700 -:10F35000C2F6A1FD1BA667911EC6C2E719A1AB0BA1 -:10F360003F9ABE6E49B3EAF8C45B5F560C6AE4721A -:10F37000C0953C8EFBEF101E521F937A5BBF710548 -:10F38000BD87E9973EE417328FA24F4F6A08B39BBF -:10F3900072FABF27F3D5E4394878467BFF99E95ADA -:10F3A000C278D2B302348E570C638A7364117C0D19 -:10F3B000FC12D816CFA7177A286891BA3C06A9572D -:10F3C0004AFEDC23F86E303B487E4399273E0CDE34 -:10F3D000C9423D687C22D183D44F8FAFFD88E2EFD4 -:10F3E000B5A887C2FCC1751FEAEEA114974D1F395D -:10F3F0009EFC73FA7C89B0B82BADD72BF8E64CD5C0 -:10F4000041792B3D2CD68DFCABC727F4B13FC6917B -:10F410003E26F985913F5CEED6F3FFEF95EAF9FFC2 -:10F420003C6DB0C12ED4C7A9AA3C8678F89B7374F2 -:10F430007C53F29F5BD0CDA7A27BC943719DC38251 -:10F440005FBE26F4402B6BA4E776CC171D81FCBF72 -:10F450008B4A073B426502EBA5D2C99C945F93C4DB -:10F46000DC5426330F9543582395698CE75365B0D8 -:10F470002E2A87B1235466B15E2A5DCC69C23287D9 -:10F48000B9A91CC93C547A9893E2E46FC607338F3C -:10F4900002FCE65EC5C86FCF7C7BAFD1E09C7AAA48 -:10F4A000441D1108E96A26E3C8E77B8AB7CF91F5C6 -:10F4B000A7AFD1B07D3AEF5F3F7EFFCF7C0EE23742 -:10F4C000A2FD17BCBDAFFE6FD74CC7F72D26AAFF14 -:10F4D00040F47FBC585B82F8DA349ED17927166BF2 -:10F4E000CBC2EB4F16690DE1F5E325DAB5E17556B0 -:10F4F000A4AD44FC91F5B145DAF5E1F5B612AD9154 -:10F50000D779BEE99B168DF45DF8ED56C6717CC3C4 -:10F51000DF20D5DB4474B34731E3B9DA04BD59F1D8 -:10F520001C55A423B7DD86A587E7FD04631CC138FD -:10F53000D300F68F818E82C89F000F2F51BC6D348F -:10F540008F819F283E913F98AC8F9B00BE935F3583 -:10F55000B886DBE98C456E97F39E0FCF9916E6E7E8 -:10F56000CD098D1B6D1F46FC3D22F4BC6EA1E7BD8D -:10F5700029E2C87DFB0E9A13CFDA43741CDD3E34BA -:10F58000B3B3E1FCB2DFBEFF546301BA0E36D99CBF -:10F5900028EF7A62D86B68A7F98EA90CF58CAFBA00 -:10F5A000DE9AA2594F72BE38CC49F903725EC16728 -:10F5B0007AF09FA0E75C3C48DA976E3B8737B73B11 -:10F5C00012C5BA5A66245D9647FE7CAED7E75B8EBD -:10F5D000CC9B0DEB4CDDC4FDAA0948DF183A7BE259 -:10F5E0008F4E8CA375CC3431E4536DD2CF6BF0C702 -:10F5F0006D99B1CA19EE0F6E4BF02B18BFCC08C431 -:10F60000703F4432F3C7A01C2D779753DE8C4F75A3 -:10F610009663BD9A5D9107F5C59DAAAB1CE63DD4E6 -:10F62000F9F42AF4032EA9B6521CC3A2CD7A9FFB8B -:10F63000FF78FE4692C0F3D60D367700E198E220BF -:10F64000BF6D7E5B6139DABB2D8EA424C4C5A4EAEC -:10F6500065E4376C71B85FC2FB1D3EA789F2139950 -:10F6600053B35780BEB2E3267339F2F1CC278B1324 -:10F67000D4B0759F6A3D17837190079C266A7F609E -:10F680004D997D9903EF3182BD00E521E7490DF5E4 -:10F69000F7EDD007FD8DB7379CEC1835C0392694AF -:10F6A0005B75781BE7D6D76D067FA3C5A017F48ED0 -:10F6B000177922E3D8383CE7B18F7E49F6EF2287ED -:10F6C0008BFCEA65ED0AE5C7040FBAB350DF3CB521 -:10F6D0007934E5BBB4B6EBFDD1C14C9685F77DEA34 -:10F6E0003A14D257D5D68F9BF1BDE179AE741C6721 -:10F6F000B8BB37DD19467F0FFCE4873128EF5AF19C -:10F70000C21AE111E3712161AFCA7BE575CE733591 -:10F71000A8F72FE978C383F04FD44C4433C72DFEAC -:10F72000343CFF8DD3E7135DE23D2DD463FAE9A3AA -:10F730009FC33AC3EE27B425E7C4E2BC21FCD5122F -:10F7400070BFA73B8A483FDAD95E46F7018CE3DCFD -:10F75000B69675A1DEDAB6D6DE1549FFBD2DCB9380 -:10F7600085F7B7CF6C99BE9EC1F99F39B8220DEFCE -:10F77000BB2FEDB0B11857FFFEA7B78CA7F996E2E3 -:10F780003D6A9CB7639E15E5C6ECCEE95684DB6DF9 -:10F790006B173C193ECFCFCABCA34A81FEE23A9E0A -:10F7A000243C71B0800FE1FAEB295A16EA17A773CF -:10F7B00059C47C4E77A942FCFC77533C743FE54C1E -:10F7C00066E47EC5A55C3F7FA4D445FDEBCCECB5DB -:10F7D000E5C9640F3A915E4FB51751FCCE8271773F -:10F7E000908B967D5FAE45FCFFA4BAFEEDE5D0DEC2 -:10F7F00036E7CAF7B01C6B6D24BD99FD5E257A0013 -:10F80000BD90EE89FD67A5DDD912964788FAA3A6BB -:10F81000F36B7818DA1F9676356005FE6E397096B0 -:10F82000F470C4572D0C7FE9374EE8F3223F246D66 -:10F830001CDDBBA35FDB6557FA03509E6CAFB74777 -:10F840003AC7E8F3878D8BFAED0CA6C584CD0F522D -:10F8500031407E6D2F9FAFAF9F68073354A3F509EA -:10F86000BDDCD82ED73F7A9B9E3E9789F391FA79DB -:10F87000B4F57EC7AF7FAF058313949771858E5E15 -:10F880002E52BB56615C85BDC5F93FD875CC13219E -:10F89000CE15E2B3B0F621027E00CFF5C9F3C93E22 -:10F8A00089B60EABFF88963D2664BF7D274DBF2EDF -:10F8B000D9AFA594C7C16D7E16B0246019A0FB1CFA -:10F8C00036781FE5F7A7D5373A2F8B4017B234F2B9 -:10F8D0002DFCB9C2E23F463E81683052EA2326FE43 -:10F8E000BE16C6E7E2EFE2FAEFE96D0AE9BF1BB721 -:10F8F000F03C8A4FFD5027E5829F13AA167F13CA5A -:10F900008E23ECDEE1B2E7DA6FBFC8A583DB128A93 -:10F910006789F6F71EFDD16BD8FEEEE33FF2E07289 -:10F920006F4D5E92C0F9D689C538CF998BADE48F03 -:10F93000C19F5DE207745CEEB7E9F070E3FE47B784 -:10F940002D46B9B3DFEEC674BCA5DBF4EDB6B4B09A -:10F950007D318E5F3E1D9C8239F3808E8EFFE45F89 -:10F96000E97E782CF24FA4C73536BA17D68F0E4AE7 -:10F97000FBBE334278BB381487A2FB2092AE4E6E9A -:10F980006A39A3C238EBD7585DF43D0583FD75DCB9 -:10F99000354F4B0B8B0F5BD7F07B9A2CDC4ECC0991 -:10F9A000ED5F8E7BDC576F7739FA8FD70FEFA28C24 -:10F9B00037A84CFB2DF2C5B432CFCBA5148FAEA720 -:10F9C0007D37ED5B73FC15E8737BACF7D5D2125C29 -:10F9D000FF88710ADE9731BBE8DE606BAB2906F960 -:10F9E0007E4797396624C2BBD54472BEA32B3976B5 -:10F9F00024CA258789E2A72857D430FF3E9BC0F947 -:10FA000064487E7812C2F59F58818F67F284FE3376 -:10FA100083EB3FCA130748EF686DE3712AA96F387B -:10FA200005FE385B791C329AFE838C07D71D5FB2C6 -:10FA3000C4897CAD2D817F7F63C90CB70FEF735EE6 -:10FA4000EA60243786E3A50AD4B31CCC3F1BE651F9 -:10FA50009D5CBFF17630D267921C0E37823AB5D3E7 -:10FA6000EFA3756B9CCEECF01FC233364F6338BEEC -:10FA7000D9A057580D7A836AA87F51AAD72398D066 -:10FA8000BF653C387EF3C07940D2AFDB21FC13A0C8 -:10FA90003FF9E8DE4829F323DE324D73250F09D9FB -:10FAA00001E877C4F6B452B6A3252CFEA4682F92C1 -:10FAB000DF40FA25A5FF41FA39C69482BD9610E6CB -:10FAC0008FF81598962AC5C39226009E64033B20A2 -:10FAD0007B329F29FC7AC6D7D4D39B2E2CEEF3B36E -:10FAE000E7F9FDA05653AC7B6776FF7EC593397D61 -:10FAF000C61EC21C4998E52A3BDDC399A9EEA17B2D -:10FB0000F75B8B4D3CAF991D71A23E903F81CB932B -:10FB1000EC32CFC5B81FE6F06423DE003C7C16BC97 -:10FB2000BF27FCB69937E7C4A23EFC76FAD92DA8C8 -:10FB300097FBDA4CC46F241CB39B4D77201A86C503 -:10FB4000E702E6C2509C6DA3E79C0FEF0BA74EE6C1 -:10FB50007ED7D879A70FA21F74C34813F9D96F8D28 -:10FB6000D7286E07F4635779BCEE258CB7B5BB92E6 -:10FB700092F0BB3B8F27F27626CEF1EEF8213BC206 -:10FB8000F34BE2C4BEEF5622EB2B7F9CC4E54BCF78 -:10FB90007E00E420F26B097BFC0FD59A23BC0E702B -:10FBA00083F7FFC5C7EDE97913FE50ED33939D242C -:10FBB000ECF9981AB2D7D1C708ED7B263C58ED83F3 -:10FBC000FAFDD991E7ED98CCE7BDFF65EF70D467FA -:10FBD00083FB017F06453ADF003395D2B859189769 -:10FBE0000AAEB62D88F41D9B33629F5BA1CD3628EB -:10FBF000A4C76EAD36EAA97EE2579F349C7C81D2C1 -:10FC0000B4817F94003D24B2C8FCF2FCFAAA3B0DFB -:10FC1000F5CE96D5CA7AE41F2DA0AF625C30D569C7 -:10FC2000257DB535F187D3F15C3E69604EBCEFBAF6 -:10FC300013D43EE45FE857C57BACB39B389FF13AE1 -:10FC4000B99F15EC38CFA5888FE966C247A9BF9A3E -:10FC5000AB39FFB9D8C6F3917B121DE4374D6CE286 -:10FC6000F9C7713ED067717F3378FEB006FF211F60 -:10FC700092FAAD23DFACCB23B61AF28CCD86BCE270 -:10FC80008D13F47C28BEA47840BDEA5760FFE23AA9 -:10FC90000F00FFC13200763096CF83DD8EE56FC056 -:10FCA0006EC7B8C18B6BF3A87C69AD9B9EBFB2B623 -:10FCB00094CA6959418A2B921F999C8F2CA0901F3E -:10FCC0004FE2D71BC3CA10DFA7F3F65F4EAC7EC06E -:10FCD000370CDA9365FFB1847F7D755F750DF6AFE4 -:10FCE0004DE3F551CF5E5D83FE9FDE99DA4313004D -:10FCF000EF524C9EBA36ECFB239B3B927D5F30511A -:10FD0000DE138B6CBF33FC4482DE9FF314F1892831 -:10FD1000FE9CBB15BE8E3F4E7AF05EA48B41F3CCA9 -:10FD20001EC4E3AC1CBD9F7FF044CE77168B32EB34 -:10FD300015A08F01E02EE9235A7BCB7E4081087409 -:10FD400025CBADF16C2ADDCFAEB12E8894E774409F -:10FD5000D055D4F11DCC651B1BA2B7168791DE824E -:10FD600014DFFDA4E9C683282FBF39BD31B20F834C -:10FD7000351AC9EB20D01BF273B581D39B6AE6F725 -:10FD8000336B0F73FFC84EA42FCC87437A837FCE8B -:10FD9000F6F17AAA81DE5A8CF4E6D0D35B10E90D35 -:10FDA000C64BF471FD22AEBAEB5BA5B7CFBF21BD48 -:10FDB000FD7A4A90F21A7AB21BD3113E5BC5F7F076 -:10FDC000BE2A1DDE35D1CABFCF7189467E81561C41 -:10FDD000C741FAFC26FCCECAEC61CDE62480DFDC0C -:10FDE000E402FA0EC1E48943043D1C71A0BF266100 -:10FDF000BAE69C88F475E57B74BF31C5C4E9B7E009 -:10FE0000D937491E64B675CF9B8D74B75A253969A9 -:10FE1000DC57EB548E6F2D0A9F174E2E3D3CAE37AC -:10FE200042D0A56B758B62477DBC8EB973B3E9BBBD -:10FE300032F4BD9B7F69FD4F278EDB3A3589D6E5CD -:10FE40006A7E33D1CBFD6B6968BFD195E6C2FEF403 -:10FE500008BF2ECB101D3DE74F1CC03F7B3EFEF17F -:10FE6000C80445F209CA03F68AFB9B322E12959EFE -:10FE70000D7EDCA8FEC34B387C8CEFC74FE1F3B698 -:10FE800008FFAF51DF93FB3F3ADD3B1BF7A7385E1E -:10FE9000E47EE003CC85EB9471B3BE3C23A91FFA4A -:10FEA00098BF05F56D33A83243B8BA81E3F5E51F75 -:10FEB000093D714599773E8EBB83B90EA27C73B81C -:10FEC00079BEC233D3B50A82E7D7D4034BCBB46B28 -:10FED00006C2AB15B3B54503B5B32F619471A1B894 -:10FEE000D6F47966CE179A14C1071CEBAD50DF9A91 -:10FEF00008FCCC857A3BDFB713F8868BEC0CBD1D74 -:10FF0000310B9D91C837908F1070B5B998579920D3 -:10FF1000C60FC9EBE00BA8970601B6774053828F56 -:10FF2000CBEB96C39CAF5881AF505CBA94DB09F21F -:10FF30005E505CBE9BEC2F551BD87E301BECFBE665 -:10FF40008922EFBD901523DCB24CAE3B27C0F3A253 -:10FF50007B661E9D008F4BEE5B3A18C5E9F81D6D60 -:10FF600015F8BDAF150F9FD9817ED209FF6E63E2F0 -:10FF7000BB6A9467F0779433742E07269FE1FA6387 -:10FF800076643CBE620A977F32CE3A001EFB098F30 -:10FF9000459CF32BE0B1E33C78FC58143CDEF30DB8 -:10FFA000F178EF44D8D7357808304ECC6CED17583F -:10FFB0008F86B7B36669CF0ED41E163FE0F943AC07 -:10FFC00081EC6719BF34AEA70DE56BEE007EA90D7D -:10FFD0003B63D09E6D69D8F9327EF7B1A589DBD934 -:10FFE0003DF16E7B29DA376FA8F43DAB68EFA3DDF6 -:10FFF000ED036639730ACF8F3EB4DA169806E364D0 -:020000023000CC -:1000000038B8BCCD70680CF3C5CDCEA0C51B8FFA37 -:100010009A87A19D614D36315F983F66ACE508C96E -:10002000E51E90E3481F409F9CDE12F938523E4F78 -:100030005B7D274672D8945E90836174F2F2FE5223 -:10004000F2C3C597EC5D85EFA9355617E2F7B4CF3B -:10005000416E86CD331D3491F0FAA5F674DD383348 -:100060009DD9BAF6D969DFD1B55F06F862A53836F1 -:10007000BF1728F59A39AE025DBF4411E7F86EDE6E -:1000800004DD7866F5CB3BC623FD0B3D6232FC8771 -:10009000F4AF1AF405A33E61D41FD824FD3DD53139 -:1000A00066918766E6F9115B999DBE4B017C90BE17 -:1000B0007B501BCA13203A19630DEEBC0DFD2A0BB1 -:1000C000ED6E1F3C6BDD7F595A5D71C87FB6B589F7 -:1000D000FBFD5AF6D977203D6C177429E92B3FFEBA -:1000E000E4424672DDCA501E1BE955E63B497F815A -:1000F000F427280DDCCFF0D4D46CA207C97FB65604 -:1001000073FBF7674A204619C1E9D29514FA3E5DA0 -:100110001A537C73387D6B49A254453EAACC7BC5EB -:1001200071D0CE4EE3F3B19778DE64F38FF17D2783 -:10013000F30D13FE8CCCA4909F02F31356F2F77CC0 -:1001400073C47BC345BEE520BEFEC04C31DF18281A -:10015000D5464DF8A7BD54DA301E0E658EE28E45A9 -:10016000FFC708D543819604115FCF10F1F43825FD -:10017000C099C7D7E42363818D625E024BE2DF172B -:10018000297BCCC154A20FEB4E9447B79E70BF8E13 -:10019000A9BAADF13F7C751A3C6F7F4375A39FF4FC -:1001A000D64CDFDB48D76640061FF9B53C75786E44 -:1001B0006AA5DD391BDE537D3B9A31BE3BD6EA3F53 -:1001C00048E7B9CE46F41E84F7101FB6C7039D2238 -:1001D000BEA2A76B5C281F48C6318213DC7694A3AD -:1001E00041ECC7FDCD3AFF67847C13F2979A45BD79 -:1001F000D5B193F4F7F5C956FCE226E6F76435214C -:100200005EA6C4F2FBB78CC70D86E33FC2F2EDAD2C -:10021000CEC87E4DD0D7080EC1E6E56903E95D5131 -:10022000E3280E53C09A70E17194B66BAFF407C225 -:10023000D629F7BDDEB15359CCBECAFC4C1F476965 -:10024000605ACC98087194A05FC1750E6FE07196EA -:10025000E1C25FFF75E3285953BF5E1C45EEF7729C -:10026000F1EFB980D8E29E31C513E8BC4CA1F58509 -:10027000C1EF21E247841B0245A0FE3D517F754F2F -:10028000F79F1E857F1EDEFDFC1E2CA51E374FB47A -:100290005F31FAB30398BB356FC32A11C7D2C71FAA -:1002A0002E07AB2EDCCF8FDF0B08AFCF33ACA7CC44 -:1002B000AC8F13CC70E8FBCF4AD6B7970FB3F53BA2 -:1002C00037F4CBD37E95FEFBBD35EE76C6BF371532 -:1002D000760EEAF9EB76CC9BC3B88FAB3F9E84C712 -:1002E000013CBF34B3A462C41713E9A5DB7DCBEF97 -:1002F000AA02FA590F7294F362978EFE42718F72BE -:100300000DF149FAFBA3D1D349470EF9FF87371DF9 -:10031000EC9A3198F5C5016E8FF5BE3109BF17E42F -:1003200038A7A01E32BCE937D47EE5C29201F1287D -:10033000B7E950D78CB0EF08E69A3D26B49F739B7F -:100340005EA4E751F5F9FE7C84F2D672055EC8BC66 -:10035000C0ED98170870CF6D10DF07EE1C38FF4D09 -:10036000CAC3D6B0FC3E4A6670292C7C7C29F7FAB9 -:10037000F9D319F7FBCAF9FAF2020DF3F6C93F27D0 -:10038000977FCF4CF77E312925EC5E86B8C701FBFD -:100390008E9807CA268B7BB1D1F3D8B8DD59F9D234 -:1003A000DB38FE57B63BA38C3B2D2B18F19ED4A017 -:1003B00089C28F1C13CC44BF418F25B25EFFB39915 -:1003C000B392270F60A761DE2CC232DA3ABF6EDE2D -:1003D000EC04116F92F156993F2BF362CF973FFBDC -:1003E0004DFDF065C21F10379951698C4318D73BFA -:1003F00059F8C7B3CB3C9326D37DAEC8F107D9FFDC -:10040000ED746B44BFF8FD53059EF4BF7F44F9A122 -:10041000B0DEE4703B48BE27F3F28DE3815D74C526 -:10042000E4307FA0B73997FC7D61F696CC8725FA3A -:10043000D82AFC107D7460D40B453CC4A817CAF8B8 -:100440008852CDFD13401F350807D4BB302F5DDA2D -:1004500079329F54E68D625E28C5A3BEA65EF5ADD7 -:10046000DB53CD3329AFABC559F6D237B1A7DAA7E5 -:10047000F27BC2D29EF23AB8DFC18BF6D425FDEDF5 -:10048000A9E2326F2BC2CB68571DFFE987941F0B7F -:100490007668DBE46F834F18FC53232670FC96725A -:1004A0005AFAD30E8E34E9FCAEB3D43507295FBCBB -:1004B00081FB5B32B42EB2D3AC0EAB0BFD2DE61933 -:1004C0009C8E2CF9CCAFF1382FF957645E599263AA -:1004D00059C4FBA6D24E0C4A3BD1C7EFA7F61CE687 -:1004E00071DB38F4B760C7722ED7A4BFC5922CFC5D -:1004F0002D867CEC38837FC5E86F7962B2DEDF72CF -:10050000BFE2BA0D49FDE96D337F87A0F8B77B974D -:10051000C6A1A9FF8CBFEDBBC2DF728F03D6B7FFA8 -:100520006DBDBFC518FF8A10F722E7D599034F901C -:10053000DF44C257D2ADF4676534F1EF37CD52F7DF -:1005400028C85FB63A387C55F4672587FC59CA132A -:100550007FEAF34BD17DDC7E71F2C697719D6660B8 -:10056000381B23F9B7045C8DF1A88426710FF85B62 -:10057000F267BD63806FE13D4577E2778D8BEFAB2E -:10058000388AE5B81D370EBE1ACAD287EFACC0F262 -:10059000BF5E0E66A3DE69F463BD821F414EE90FA4 -:1005A0005F231C259E7A1B249E3AAC44B7D51C8E33 -:1005B0004638A56A1C4F73014F4145E8C3BF9E44AE -:1005C0004E9F1933DC2FA17F6D78BE9945C26373AE -:1005D00013FF5E9684E37601C7A48665E42734E2C0 -:1005E000E9F0CEAF869FEA14E11710F07B6A5BD189 -:1005F0006D08B7BDF756FC0ECB5FF86F8C43B8EDB6 -:100600007BE8CEEF0AF8A5D3F7740DF05B14057EF6 -:10061000D3DCDCBEFEB8CC9B3805E4C265C021D07B -:100620001FB2B3BDD0AE8F03E9F969EAB7E49F0A00 -:10063000F6F153F65AEE57E0A74F1BFC53A93E4E76 -:1006400037A9BE13449F19409F31E8AF6AE07A246E -:10065000887D7F9C823637E7AF52AE21CB3181F067 -:10066000D9EEE471E7087ECA007DEFD7C087D1815B -:10067000138E772057274C4909C9BBED0D3C8E7668 -:10068000E34CCF2484AB8CAB3D335D9B3C85EE2F9C -:100690007C6DFFE30C9C47FA1F014F69FF2AE03B8A -:1006A0007EDFFC52902768FF9B1B8216942BB54D72 -:1006B00037285E28DF9EC8CF3F35CDCB30CEDADF7E -:1006C0005F178C47BD7DDAC83E7CA808C787B1ABF1 -:1006D0003FB913FD5CD1F021234ABED2F9F1A14C00 -:1006E000275FB7F6E143E38651C9178E0F478DF8B0 -:1006F00020E83FB521780FD2AF59E083D9097C0CAF -:10070000E0A1221EE487E29E921E8222FFC0089F83 -:10071000A06F44943C84554AE900EBBBE0FC031114 -:100720000F6D11F1506F13CF97ED596D9BA5CF3F12 -:1007300070D3BA673B1A95F03CFE0879B2B7E1F97D -:10074000C938A78C6B7E5CE6D98CCFA7E5F1730E18 -:10075000468F3305F07E2BA09FD380E777139ECB87 -:10076000FB07428FBB71A6B6159F8FB1FA29CF192F -:10077000F4BD7BB1BE7DFFA3FC7BBBC20F29F3F2AE -:10078000BEB1DF2CC1EAC7FB92D26FB635DEBA1319 -:10079000CFBB8E0567D2777E314E817EA7CD36CA1C -:1007A0006BAC57C0F046BE78A9B76B0AE94D1ECABC -:1007B000C7F556DA9DA8E7B726CE4A43BE51BB5EC1 -:1007C00025B91ECDBE91F4560BFC86E8AD89F39B8E -:1007D00054C02FC2379F42FC2603F80DE73F1A434F -:1007E000BDCE8C74E7E8CF6FB60E00FF0BE43B2F55 -:1007F000E17946E03BAFE03EC3F8CEEFA67C83B89C -:10080000C7A553188FE788FD633C80F68FF415BEAB -:100810007FA33EDBB76F3D7D49BAFB5F40679F23F7 -:100820005C23D0D9FFF98674A64E8D4C67E6A97A71 -:100830003A8B99FA8F496799534BCE4F675D02AF58 -:1008400064FEB6D42B2E52BBCEE5E2FCFF8FF3B78D -:100850006F9FC4FDA9E7CBDFC6DF85F84F8DF9DCBC -:10086000FFF4A7FEAFF5A7FE78EAB7E04FFDF74922 -:100870002ED2DB8C7ED5BDE3B5B6A903C495259FEA -:10088000364B3E0DFC18796F2DF033E4CFA9D5BD62 -:100890007F7E86DB9BEE3817F91BEEC0F566087E7F -:1008A0006DE4CBA077DE39F5EFE86FF87BF90DCB7F -:1008B000265FD87DFBB2C92EE1778D7CEFBE45D88F -:1008C000F72D3006DED3DBBEDAEA6F8505A78BF3A2 -:1008D00019D370E5654864AFAFB0C60607B09BE4B6 -:1008E000DF91E858EB7DEE746EF8FE5844B9D5B749 -:1008F0003F839E1C6E37B9BE82DD94324DEF873246 -:1009000037703BD70CF28EE2FA5A6900F975864FC0 -:10091000E9C2D4606F72A3827230B5C143F9F05F4F -:1009200035AE6FC4A36871FE6F3BAE6FCC1BF8474A -:1009300089F3FFF754FD772D659C5FFA5F8D71F9A0 -:1009400031D68E7292AF3526FC0B18AC75FF073B83 -:100950006FC3F35E68A77B1AC67C806871FB314960 -:10096000D6605C4EF4F8BDF417DC6F697C19EDF0CD -:10097000FB9B4D74BEC6BC81FC789E3FFED4AF3657 -:10098000DD47F93F521FAE167CA649B1D2771DABA9 -:10099000FDC467BCDAEE668C27A73A5817EA5947B8 -:1009A000A7727A51D334E233E66A2FE1958C4FD4A3 -:1009B00066F17B733102BFD4918DAFE2F889475461 -:1009C00037C6B7376357E019F1282B518F9860A2CB -:1009D000BC884EA591FC1E1D8A8BFEFE4762BE930D -:1009E000F4A3C713DDBF5F80EB4FE17FA7E4D09C8A -:1009F0006569C807D73737A7E1FDC4E2693C1FF135 -:100A00008E39676B288E9E07FA9F42A5EEEFD9CAF2 -:100A100072A7A688BFB7E4A77C4458F7367A6FA4BC -:100A200095FC6CAA76F78DC807D451B308AF3B1478 -:100A3000E7C2C5785EB956D2635A73C72D5802FB18 -:100A4000DA90E229CFC6734D1C49FB6C4D1C928095 -:100A5000FAE886F41C9ABF5DF19667E37BE926A26B -:100A60006B55C4E737E42E7B09FF0E484B8689E1BE -:100A7000BD83CEDCB3EDD8AF7302FF2338C6F5AA31 -:100A80004EFD3D29FCF011F26F358DC7C55511178C -:100A9000570D71E5324D917F6783E20E31826FD53C -:100AA000E6AE5B40DF4F70589D88642DF1C12AC2CD -:100AB0008FD51686713A66EED0E969B7ADD57FFF5E -:100AC000C591AF5F4F7BDFFD846C2FF219FA1BB02D -:100AD000942F9EE845FC407ECB93FEE2783D46D4C1 -:100AE0000316AF2FC2F9FCB3FC67F9CFF29FE5FF05 -:100AF000EFE5FF00834DEAE8008000000000000001 -:100B00001F8B080000000000000BC55B0D741CD596 -:100B100075BEB3333BBB2BADA459FDD82B90CDC8CC -:100B200096880C421E0BCB488D8D66A595B4322E4F -:100B3000D938FC98C476D6D8B8E43427559D26B168 -:100B4000135AADAD95254BB62C09829C43CFE9DAFB -:100B500024396DF00125E9690C01CE1A1C420834D4 -:100B60000A10427A92208CE39496E698828968690A -:100B7000E9BDF7CD6877462BFFC53D1187F3FC66CD -:100B8000DEDCF7DEFD7BDFBDF72D0078600180EC59 -:100B900007001D6073912709E500676B200DD5D80C -:100BA000F74E576841800FE9AF35DB0EF702647CE2 -:100BB000D97EB05E05B30EF8EF43D1B8E88E9B1630 -:100BC0005DF863D21DAC5537A48373E9DAE3DA4CE0 -:100BD00009A029EF3C205DD43CA77FA6E3F8E4CF31 -:100BE00064A8D5E7CEE7FEDEFE6E73D1FA12A8FF49 -:100BF000FF1B3F1F5F979A1E800AD18755B86F6A07 -:100C00009788AE8E7C5040F0A1AF73553A83FF9C1D -:100C1000901283D5B4BF90C7F806CCE583DDCADA5D -:100C20001CF965E9CB827CB94D1F9720EF0C9881A8 -:100C3000627A85DF21EF355CF6872812A5DCC3CF09 -:100C4000C1A2170678E6435CDFD1ACBC405B90A53F -:100C50002B6F5479FC72B5E785A695F8EC15D9F899 -:100C6000869EA5CBEBA9069E00ECEFAAB3EF156B11 -:100C7000DE8F1C5221638FC7FF8F9921E6D3C4A654 -:100C8000FB2181FCFDF9C64F9424F2E881DD2E4B57 -:100C90003BBF7F036902F30DD2DFC07FA77E312AFD -:100CA000F1E4C7C4F3D40A2D3D84CF87A4F4D03532 -:100CB00034EE2EC15F5B0E85961CF02F5C837CF4B6 -:100CC0005A72F2BAF7857FCA02E693C59C1C392C8A -:100CD000611A35B4EF3E9B9E6E6400F934BCBC6172 -:100CE000C5904EFB1FFD876FE13A0E1DDDF3E6B7A1 -:100CF000F075A0BE61A419D75360780C99F4F9532C -:100D0000C78EA1B860A0FE0BA34476DBA8646AF886 -:100D1000DEAF058FC8B447BF64123DE5E042DE4F49 -:100D2000789B530F2624634125ED6F4C02924BA113 -:100D3000E17CEFD373F683FF1F2239B37EE63C4795 -:100D4000BE21F7364CD6CFE5FB2B963E2B383E69BD -:100D5000D345BE8C7BF59B89CFE3FB644822C9F168 -:100D60005D68145700FC5BE6BE4FEF46DBFE42BFFA -:100D700097E5301151D3128E9F28D26EDB40FD0AC9 -:100D80008F7184998AFFE3BE46975DCDFBB2E76B16 -:100D90006AD579BEB1C8824AB2471C5719BF6EAE38 -:100DA000FEB9D77FB1FA77B7596AE9FB28107D9869 -:100DB000BCD943F6E4B7C65C234F362EA1F97E2E8C -:100DC00083D09B1E8817CDE54F3FF9838F64F54490 -:100DD000B5F4686FF9FA9F10F9F9F4594D4F99D5A8 -:100DE0000D340FF410DF97859DEBB3C77DCE92973E -:100DF0002F0D196F31B519131AA89D32256CCF6EBE -:100E0000FCBCB6569F7F1E1FE4D0AD267AC0FBF611 -:100E100042829945723573E4BAA7B0E10E924BFF56 -:100E20004D2AB0FEB9F97C9EBEAA648E4BC5A40FB4 -:100E30001F61FD48A27ED4221D6FD8A987F12756D5 -:100E4000C27450C829C9CF6326C96959AB77D67F08 -:100E5000FA73FC25E8BB7F2323BD7B63AA3E84EBAA -:100E6000BC37BEFDABB7929D3F2F1B12BFD7D91F1A -:100E70007EC19A034627581F4AAC7367E7B17B5E71 -:100E80007B8E6414535F27BE911DCFF245F867D364 -:100E9000BF2A3BDFC1E693834B910FA9C1FCF4EF5E -:100EA0002CD33F47FCB3F93C1FDD59FFBDF3F86479 -:100EB000F4FA6C7FA4201188A01C4682063A017ABD -:100EC0007F82DFC34AD4CBCAF9E5891C65FEBC46E4 -:100ED000FFC471DD51538B605F3E864B5F8E7EB1E8 -:100EE00048BF793DBEEA287F7D13F17F5BD0A3C95F -:100EF00039F6D5B7DF0B99203102E745BD5B07D343 -:100F00009BD6E338A8F1B29ECBE52BF8F9D6A2B870 -:100F1000E2C1F6EAC8129ECFFEBE1BEE5376E0F3A6 -:100F2000E55EED15D29354B9442BC2E7C8405CFA94 -:100F30005A05CC626CBBF4889FCEB5D8E33411401F -:100F40006B68BC9CCEA586C70E5525C8AE93E654EB -:100F50001DCA276489EB5ADF54BC1DE9F5BD201B6F -:100F60007BB01F0A6E5F07A847D22341F6137DE8C6 -:100F7000E77D287725D8F9263D5F7306209AA34F91 -:100F8000AD337E88E6F8BD0852CEEDB7FB2B1DE3EE -:100F90003BB46AC77B194C23837CEA0A2F738C2BE2 -:100FA0006A5AA9D17ABBF5158EE737D5B538BE8711 -:100FB000A872721AFBABF13F92BB0CA2CFEFAB0948 -:100FC00027603FE77B0572FAF87E6DA4A8FC341D0C -:100FD0004A37C00D6447289723C3E47F36F8F9DC0D -:100FE000EAF3C231A904C8F493D048CC36F9BC97CF -:100FF0002C7D4D46AA594E52F099F7590F1F9FF676 -:1010000010CE82C7A091FCEBDF6AFA710F0EB99285 -:1010100048E2F76154741DE584AE3A1968E4E7E6E6 -:10102000D2523AE7A46437F617E1B8B05045789643 -:10103000C6F961F757C4385844E3344856615F3302 -:10104000A080E45A85743E5BCADF25BBADEFAE12CB -:10105000DF254B4A05FD86463E47331DD81E060355 -:101060007CEC7FE2089AC88BF4707B15AD0A9F3F39 -:10107000084623F56B619AFD148A5FA2FE4298D45C -:101080008493CF08BF3DAD844EFB85DFCF672F59DA -:10109000BB51E0B42D0F1C7C55ABF925B2BFDBEE84 -:1010A000683A27EE50763EEDB0DBEF4474711EEEE9 -:1010B000EC623B51763EC3EF5F8AC4F7901D12EBA2 -:1010C000FD8D73F9DDA06680FC572A02461249A403 -:1010D0001E5D1BDE82F24D3EEA376AE1F2C9E36231 -:1010E000E59006AD80F82AF75CAA1C80CFF9E031C4 -:1010F000FFE121564693CFC93F402EDFBA14B9B85D -:10110000E501F79401B49CDF8F3E206502D252E6E0 -:1011100087196ECCF21FFBC96516BF4A2D79C8A28C -:10112000CDC8D673A5747EB910BDB2D2AC7CCE2723 -:1011300097701CDF3766E523F798CC3CFB9CF6C123 -:1011400019C6B74B2483E5B5548E7BA85F28652C60 -:10115000D093E673BD183496CF15D0C36DB9777AA6 -:101160000BE3E19D3811E1D90FF094CD89C752C14D -:10117000367F35F9D73AC5F060BFBEC8134F231F7D -:10118000AF542043FBAB542049FE1C9101D34F3D8B -:101190008AA7159E33293CA63DF4DD2E7F3A2565AE -:1011A000E76FB0FCF64F8ABEA94DD767F97C92FC79 -:1011B000D772C10F0FFB9FC90C7D1F8E81D1A7CFA6 -:1011C000F567382E295B7E8ADACDF4A285F9962C54 -:1011D000C6BE34F8C3F70967103D05FBDF8B24DE7C -:1011E00021BD219C1E2C65BF345D48C07A2E2E3057 -:1011F00009576CB1E6D970A3BE388EEBDC32E87BC0 -:101200009DE841CAE7C405EEEF750972BFB7BF9B01 -:10121000D52BF7F7976807B0B3E2827040E491D519 -:1012200025D37970FB2CCE243B29CBFD4EC8492D0C -:101230004F30EE50C95ECACE4FC7EBC22F361D2FBE -:101240002A2ED1F15AF8C53EA7B6C319AFB2D45A67 -:1012500027F26B2BD87FE5CCCFCD16FF3E4DE7555F -:1012600031F1130315DCF73688ABA4B77F86109AEB -:1012700070FC927DDB8A192F405423FE48998FCA57 -:101280001F5E7B117CB4F8B439F3A65727BFB4B303 -:1012900008DEC88DDFACF7EF6CFC8488D3FDFE1A46 -:1012A0007F4E7C5878EC835E72EA7B0AFFE68556B7 -:1012B0005C7AFF4BB22157D37B819B0320CEEF4258 -:1012C000B2535C77E1E3A7FF87C617BA7035518642 -:1012D0001CBA9EC2FD8C670B8B559D71B64BCF6CB3 -:1012E0001C0D1F081C1CB4B897435722BC6CC73D8B -:1012F0004C579A3BEF75163EC757910F2F00CFBB47 -:10130000713ACCE273F13E1854859D609C9971C48A -:10131000C17A5E3BB3D76D7F57A1C6AB8DFA3CDF78 -:101320005B72A8A7401CFDC2C22A48EFC6F50E0E8C -:10133000EE8814627FAC02748C3061A0F38B12E1F2 -:101340008DB672A14AA166810B690AB0E378FC0BE5 -:10135000FDAB3E5487EFB757050D5C192C7C0B7124 -:1013600032D2B9ABCA6F98F82005E27DB2D923E238 -:10137000C924BC4C78749B251FEFE30267B26CD084 -:101380000EF7B7097CB5EDD867D7917C474A6F3126 -:1013900032386E1BFAA732C263A35EC67388EB1C99 -:1013A000B8DFD79C8303F1FFBB0E791D7DAF0B2700 -:1013B0000EB7210E44FDB671E0FD6DC07646EBA27E -:1013C000F3E472CD03C172F6A7D729539E7CF93797 -:1013D0005B1E36FE7EA242F0D9FBAEE00B06CC3B94 -:1013E000E8B9EF5D118FA1030F362DA0D35FF0CFC9 -:1013F000D784FCA1A7EF8AF300BFE4759BF81FAD6B -:10140000DB8D877D2E3CEC5EAF2D87476CFEAC827A -:1014100055C41FC4E78C13ECFDB8F7F138C6E7518B -:10142000548A277BFDDC667A356E9FEA0D737BA2BA -:1014300057872802B0677AEBB87DB6D7E0E7CFF5DB -:1014400036736BF3612E7F445EF32A6BCD4AFD54F5 -:101450009CCED12BA21E3685B17B3CCCB7B3A89FC6 -:10146000647CC506E5DE707CCC93A690DE8E7F168C -:101470005AFA7AADEFCC711F8E1FA904630F7EBF9D -:10148000B0793BEBD99A339EAC9D00C539058E3CB3 -:101490004104CA1CFD76FF958EF11DDA52C7FBD2BE -:1014A000C834FBA9AEF0B58E71B69CFF8EE22C5C01 -:1014B000DF58F4A4467CEDD6AF778C53EE41F93774 -:1014C00050FCF351075D90D719E4A74B373AF5B0BC -:1014D000D82557F5EE73C741B69CDF6A73C643F350 -:1014E000C9D7ADAF365F4B67F92AE2CA14C595C8B4 -:1014F000D7524DF0D5DEEF88B55F7B5EA559ECEF96 -:1015000072C797C5145F56E78B2F4F597C3E4F7CAF -:101510001973C6976EBE9E2FBE5CD0EEF42B17CA11 -:10152000CFCD8B45DEADF47999E31639D6C3E760AC -:10153000D9946C74914BB4705911F9001CB7B94926 -:101540004D13CE1C83E9309DE70725E42AEA5B5959 -:10155000BD51497EE6E190F1CA06C28DDD220FF849 -:1015600074E4B630E18EFEDD87C37858414BBB870B -:10157000FDDD68E434E72F141D387F81AD99CE83FB -:101580004FECF176BEF1E026352DE1F88356BEF141 -:1015900060F76CBE91EB1B134D22DFF827EDBA9577 -:1015A000FF4B86295EB977D3AA4A3EAC14EC5F475D -:1015B000C30DB693A180564C71746A9347A37DC93D -:1015C0002BEFFF3CE9C701A9675F0DC56F151ECE64 -:1015D000BBA642AB2AB7E0387933C218EA6F5AF596 -:1015E0002AF9EC890A7D5F0D7D1FAA61FEF5AFBE69 -:1015F000CD4FF38C841674537E64A4C3C332920916 -:101600006714339DBA73C53DEE3A804C1E97E2B71E -:10161000724F46A5F38AF0474EDEDF96FF5048E54D -:10162000FCECD6F6870E276BF831FBAF85765D664E -:10163000531BE799CF129E90E6AFCBECB5F29DB36A -:10164000E74ED8B99E3CF3302EB0EB12F4A7DB790D -:101650005AFC4BDDDC99A673741CE231F29FC9E0A1 -:10166000B9EB204AF0DC7590F9EA1EBBDA451EF5AD -:10167000CB2477915F74D44B94985517B1E2D783FC -:10168000940F277D70D549EC75F459F452B37AE480 -:10169000AA9BAC562D7A06E4CB5FFFA1F593FBDB4A -:1016A00045BDE662EB26DF6D07B15E2BDFEDB5E4ED -:1016B0007F8D3CB983F4F18F9DEFFE6EFBE5CD7716 -:1016C000CFAD13A5D95EE0D89937D8AE972DB0F03D -:1016D000CBB9EB404304F4517EE32B109752FDC38A -:1016E000EA27AF1374DD75A1809547F951FB5211BC -:1016F0006F913F21E12AC662E26B50F97652C37DB9 -:101700001404C72084ADAF7C4B92DAD6C53AD78794 -:10171000C69779F8BC1A2F4A1CEEA7F52F0BE6B531 -:101720008B572DFF3768D56F48813D646F926D1CD4 -:1017300090F0A09C2640C8F9ADF6108F57B4D1E6C2 -:101740003B516F4E913E54F07EF2D67F4EB78BFAEE -:101750004F0EFDAF939EA62CE244670BD2F90F4BC0 -:101760001F810E8E0514EC88F9FCFA6833E182DFE4 -:10177000B56BE2BDB2C2207B180FE59FEF77D67E36 -:10178000805231ABB2F868E1464107FCE2FB83D2FC -:10179000990D2757B25CD99E681DF4DE5DFF72D3A8 -:1017A0000FD439E31BB5CA39FE83D97D38E3A203D0 -:1017B000F3D4C7164585BEB62E167A46FAB1278FE2 -:1017C0007EB8ED5DA5BC27C553D190359FF03B4158 -:1017D00065AA8DE29D603D185C53548EF37EE34F05 -:1017E000D41C9B5E497EBED8A03848F1A3AB6CCC1C -:1017F000C689EE7D9F2FCE5314487A1BE7C67B48DF -:10180000D72C6914E74C3287DE5551A127726E3C04 -:10181000584DE1887E33D7F1A80E48FD5DBE0DF925 -:10182000CEE9DA76EFAC9FCC57D73914C73882822D -:10183000D447F6EFDB8AFD77348FE6E3317ADEBA00 -:101840008E66F567EB3AF10BABEB8C464BBB6B2E20 -:10185000A6AE330FDDD9F3786E5D271AC57D8E05F0 -:10186000457D65B6AE734BF905E573C03A974B2DD0 -:10187000BF5CD46DC5113B258E239E6AFAEDF072D4 -:10188000D2B3262FEB01EC9F805C3B59B751FF5A36 -:10189000199D33AFFAA056F83593E8D971B1CD3F11 -:1018A000D5A2DFF6D0F30A8D1FAFF4AC627A90F1C7 -:1018B00079B8D89D54AD56A676B99A914B886E29C1 -:1018C0005875F48C44CF23C8ACDCF86064E6C5F6E8 -:1018D00012CA9304C120173412D17697D03FA80AB8 -:1018E0004478A75A4F93BF6DF7173AFCFF48B72AC1 -:1018F000FC6BADB82F337E5CFFDA361C3FB033C0D3 -:10190000B8E9409547D85752E27A7287E68C7BC691 -:101910002797083CB6DF6BD03D91A39362FCD6C8F5 -:10192000AAB4CCB8DB191775EBCEB8686B65E32B9E -:101930008417A1DFCBF978CDC2B537D539E3A4A29E -:10194000EA9E6709A76CEE1778786FB874C156F4F1 -:101950007FBF8AEA8E38714BFF5D5C37EA5781EBB7 -:10196000A9239B54B68F11EFEB87B6326E2C603EE5 -:101970004E6C522B1339F652D6E1B3EE4508FC817A -:10198000F0323199E77D5987F03BA8D87C8EDBFA9D -:10199000F2A79F117C2EAE82B44E38AE7B4786E212 -:1019A000CAF12ADC13BEEF0FD7741FA7F95F968127 -:1019B000F6E9D6C3EA8E5AB6D3D9F3B4D9E3E093A5 -:1019C000D717EF21FA7013E8E4D7A231EC531E6069 -:1019D000A30A941FF085FF8AF75B8AFD00F6FDB12C -:1019E000D1A4827D7F4DE27AC2C54FEFBA7D3052DD -:1019F0004EE79DB06FDFC6EDF14FD0F8955E08D091 -:101A0000FA4097C2B4BEA4B8CFE0B687BDA91F44C0 -:101A1000494E7B0D8945B4B97BFDDD7C6FA9BC8047 -:101A200071D3A837BE85FDD1AD7E2DC967E034C71F -:101A300011DEAFF880F46E62D76F2A087FFF382A74 -:101A4000EA9A01DD195FFB6194CFEDD5E6D446FA41 -:101A50006E75B34A150F78AAE534CB6DA2C967F845 -:101A6000701D132D12F3F9BD266F9AE679529D92DF -:101A700069DE27DFC3B9ABF3D9777EBBB2EDC83DD2 -:101A80007EA479BD9FF4622F4CDD42FC49CE883C98 -:101A9000957B5CBC439C577B53B7D6299CCF52B9EE -:101AA000DEAE9C31CC12A41E9A89FF3DE55E9351B7 -:101AB00045C449959EA484F406BAC5BD8C81A2C4D0 -:101AC00020E9F300EA3DC749E5E23ED27865B93145 -:101AD0009433DF78CB6D75E4CF5E680A30BEEF3BA0 -:101AE000F1177712BE6F93DFFAEE23145755A92C26 -:101AF000CF016FCFAB1407259B02BCDE138B54F0D4 -:101B0000933F28BFF3418AB3E1E846C8D5D7899807 -:101B1000B0D3892A61F7D2231B390E189764E6B334 -:101B2000597144223CE68BD9792791678A58EE6C2B -:101B300062E377380F7545B7C8A3466256BE490EB3 -:101B400026592F6F083C48F66F2A5E477CBCE68C0E -:101B5000335EBEC2152FBBF351FF1BB5F21156DE2B -:101B6000C9D6CB626BCC44B3E5A757FAD2420F7B00 -:101B70002AB5FAB9F6FDCF167E9EEAF5F33DB21707 -:101B80007B35EE179B6FEF2E433A2FF786F9F9C797 -:101B9000561F9672BF1B5979AB5F677F321D26BAFD -:101BA0006E3FE2D68BA16881E33CB1D759D4D226EF -:101BB000EEDF9D618F0C6B82D3ED7C36C254301703 -:101BC000EF677AC53DB7A7AC759EA075FA284F267A -:101BD000D6F76CAFCEED73BD75DC6EEA00510FB079 -:101BE000FDC355E81F900FD12AD1277F40F22F2D3A -:101BF000BF93F364BEB0A291BDFBAB4633528E7F60 -:101C00009828EAF9C55DE4F72B82AC8FEE7DADE94B -:101C1000F0E4DDD7E6961DEC77CEE23CC47FF433EA -:101C200077B31F42BFC0F36E54EFE07598E897D8C2 -:101C30002FF47CED76F60B5E203D77FB81D2A4B0CD -:101C4000EF842EF277F63DA159BF80F3A4719EA7D1 -:101C5000D0AF537F00FD00CD33D0F2FA9FD3BCEF5D -:101C6000BD5FC0F7A22636BDC27EE185B3E8B32FC3 -:101C7000A35FB0EDF0B5139123B9F17C56CEEB6FB5 -:101C80003F26F8A181E0EB86789E38F162E50CE60C -:101C900085E198B4327D87A83BAACC8779EB8E4941 -:101CA0008F416981BE492566D51D81EA8E76FD3159 -:101CB000A7EE58E0AC3BAAE914E39BB45577BC6DA2 -:101CC000ADA83BAA05D3C1EC3AEC7A633F3DAACC60 -:101CD000D6E7EFEC48ECEA68CAD6197549D4C15F7B -:101CE0008A985FA6E7505ECAE7BFBB4E69D723114B -:101CF000DE49899CFA66033EF79766EB5FEE7AA6AB -:101D00007D2FA3419D3E328C7CE9BBC3CFF8C15EE1 -:101D10005FDFA37FF26AA23C7B1FC0AE77DAF54C8F -:101D2000BBEE89EB1ECB5D373C0EEC77E031FF61FB -:101D30003ADFDCEBFD5E24717F47459E755F607D79 -:101D4000711D58F41177913DBF66F1D11EF7906572 -:101D50008FCB5591DF866295E39DB687822013CEA7 -:101D60002E528F905D6C81E90EE26F5F48E0BCD42B -:101D7000012FFBC9A31D3ACBAF4235F93E44C597AD -:101D800003C66E24933AAE1553FEA93B6A1EEDE0DE -:101D9000758CDEB29ED681B89DFCDDAF6BBF5ACE8E -:101DA000F57EBAF75442F19FB198F220CF77E4BFA5 -:101DB000AFD4BAF8CC7A9EB7C803149FA502C6B3B5 -:101DC0007CAFF80985E9752309B391EF2F45D5520A -:101DD000A223EEA7F6054FB2BC5A6B7D2B38AF5746 -:101DE000943F0E7CA643C4AD6B91968A743ED39605 -:101DF000F801AD9B72A561D66311DF3D4F7E52F8AD -:101E0000AF7B3CABB279B01239F13C8D87A39242E3 -:101E1000E7A3CFD21B3B4E7CBBCD7C81E48EF2305E -:101E2000697EFB1E903DFF4B961C921DE68B34EEA7 -:101E3000756B9E062D19213B6C48A03E486C3FAE49 -:101E40003ABCD00BB7BEDAFA365B87B7F450D2444F -:101E5000BD16F5EA755EEF93FA718F44F5F6C4E1AD -:101E600061FAF612EBDD57B69B6FD2BA4BDAE2FF9E -:101E70004E747FBDEB76BE177CA1F7385A17F784F6 -:101E8000A98E3F1010B8F9E188E1F0778B3A857C94 -:101E900016750ABC742DEACC14DF2F35F8DE37C076 -:101EA000DD8CA36DFF34DA9BF8FEA9DAECF7A95EAE -:101EB00098A47AD07CEBF0EEDBC179DDBEAA363F88 -:101EC000F91FF46F25D41FA832C3B9EB4815093D9B -:101ED0004F2E12790BCAA72573EE939776CABC9F33 -:101EE000F62AC890EEF882A2EEE643C3D5F1FCF1E3 -:101EF00099CD7CBF189F4F528AE18A4E5DC4E5E5BB -:101F00000698146F56C581ECDBA765BFA73A6A7BBC -:101F1000550FDFB79C8F8E1CB6BF4FF0F737766A30 -:101F20004C572DF738F200E7E39B9B2FFDC4B7DA3F -:101F3000F9F9A65E30DF84DDB9F9B5CAE2D7D3A1DD -:101F40002FF2FEE08376B6339F86FBC47675A7F04A -:101F50002F72D0844411F9A8382248CAB3F700D5AB -:101F6000A16D3ECB9AE0B3ACF5F077BE2A0312D751 -:101F7000115F12CC17371FD04F00F9891F3D7AA887 -:101F80009CF0692BF6C3C27F800FDB073A845C6C40 -:101F90003B5D073F0D8AFCB7F3BC70FB53BB7DD89C -:101FA000CA3FBB9F4B5D01E13F7470F0BDC8FAFDB5 -:101FB000C291C146C607787E26E95E4C67656D0111 -:101FC000F52F771DD15D3F74D709DDF5C1ACDE98E3 -:101FD0007E5AE73BDAC9E4C7F3E88BDD0E5BF6D641 -:101FE000DFEBCF6B77C368EF24BF8116334975A34E -:101FF000BDA1E930EBCDF13719172BCFCB06E14B63 -:10200000451172EE5C34CD72EC6A3681EA4DC3BD87 -:102010001BBE9D4BF781B6C4573A514F0AB5499341 -:10202000E8042193A4F3676D99D9930F370D587E77 -:10203000E4EDB6F86EFA8EAEAD93FC4F45CC3DD4D0 -:10204000BF50BF359F3D2936EF2EDA9E4E0A7B6A80 -:10205000DEC1F63452D5C3386BE4A73221A92C8EE9 -:10206000B4EC69A4E534DBBB6D5769DBFF340BBB13 -:10207000A03C029DDFC55526FB8D6F5AF6A4A09D9E -:10208000903DF92C7B2AD6B2E3293FDE4E7CC6E791 -:102090004AD5347F57DC6CD91FD95390EE0F03E338 -:1020A0008001B43BCA8BB8EDABB5469C9B8FB7257E -:1020B0001EEE247CB1683DE7E507AAFEB38CF18BE8 -:1020C000A5FF59BCDBC8E7F9D9418F41F6D04000E4 -:1020D000BA316B07F6BE57CFC89041D1AC9991B8D1 -:1020E000BD71A690DBD69900B7E64C19B79199104F -:1020F000B76D335772DB3E53C96D7406EDE07AB4A9 -:1021000087996A6E3B67AEE5B66B6619B7B199EB16 -:10211000795CF7CC0A6ED7CE7C94DB9B665AC43CC4 -:1021200075625F79EC81CA6097C11E8C2414911D81 -:102130007CE655F6EF9ACA779452A1555C27F229AE -:10214000D36C0F479A85BFEF0A0A39B9EDE1EDB6B6 -:10215000C4AFF2D9C32CBE554023FEAB60FDB9F02D -:1021600003E29FDFD0F736EE55C326EB19E293D397 -:1021700024CF4BC509B33873B1CA78D4C699238B21 -:102180001067566771E6408B88CB52077C1CBF6D89 -:1021900095C4FDB22BDB13FFC5F609224F94B8C5D9 -:1021A000AF116E4E853AC341CAEBED9581F20588B9 -:1021B000433EE0752A71719FF502EDF95444F87DB4 -:1021C0007B7C039CF4F45C048EF935FDB3657EBF23 -:1021D000507AA9E7ACB75DF8054DF8855455CF2086 -:1021E000D7A55D7EC13E67911F0EBFB0B4CBF20B89 -:1021F000969D975689F3B294FC02F2675997ED17B2 -:102200009CE7AC62E390988D432CBF1013DF216EE6 -:10221000779CB3286E3FE4E062D4A3E55D79700853 -:102220009FE739E75C5F4D6D847E4B103A03115296 -:10223000CFE2197DAD91E7DC49698D6C07C79576D2 -:10224000C8CDAF5CB49D85EC73C7E473C73DCEB613 -:10225000B781E3DD629FD639741CF76FE6D85B97D0 -:1022600026CE233C7F6EA27DBAEDAD75B19988E78D -:1022700059E727BB04DEFFF11A0BF722AE34828C3C -:10228000EFF3E2864F92FC9AC4EF341E43FFD31162 -:102290004BA6149DEDFC9334EFEAE8944C79A01B17 -:1022A0009B475FA69208DAE9A7BA9A2EDD4E9BDB20 -:1022B000AC7ADFCE3271D9D96ACFA7FF362EB2ED14 -:1022C000C03DEEE16A73433E7E3C63F1A36FD0D321 -:1022D0004D17FE6CBD38AE2C65FC93C7DF9AC66502 -:1022E000F1B717863F8EE33948723F07FE18CE27B5 -:1022F000FFF9F0C778D72CFE182339B5D60BFCF1BF -:102300004C179C33BEB9645C1139C97CBB545CF179 -:1023100050D7B971C5B7BB84DF54B469F61FC597F0 -:10232000882BDC7E02F1C33F317F0C71EEDABF37C0 -:10233000E10B9439E717FA99EFD338C20D7479ECB1 -:1023400048B02D29B11DC49FA0E7A3E612D6A3CBA8 -:10235000650F88137FD895D33F9F5D5CF0B8C94D5A -:102360009C07B4EB99BF0F1437507E64A75FB45F2E -:102370002A283E42ED58AFC843EFB7F27E635EE0D5 -:10238000FA41BF54601C91E8BBC569916FEF594E8B -:1023900079CFDF76D9BF97ECB9817F77037FEDA83E -:1023A0009BCEBF2E71CF97487DC8F7C1AB34CEA36B -:1023B0005B7CA174109DD343CBFC8C03873A8E1EAB -:1023C000BA93F2321D220F860A51FD713A7F11D65F -:1023D00034E79C0B3228A7293F3F4877DB19746C00 -:1023E00010F7A035F1BE348AF17B6EDDCEB8DBD1BB -:1023F000072B5F6AFF3EB070CD7ADB4E988E6D275B -:102400008545939A96E36F067B9DBFFF76B772ED85 -:102410007D71BA9B3C5AEFE1FAC5BE1A2540F5948E -:102420007D7522CB3E5CE389E5AB8F5F1B931C7906 -:102430006DBBBE5D1011EB9A6FBE01D77A7C7ADC62 -:10244000243D1DD6D371FE1D725DB994CCC93B7B72 -:10245000AD79862423D38ACC1C2A12E785AF2A09BA -:102460001EC203A1EDD7138FFD553D703A48F737D3 -:1024700092F006B6A1523591CEE38796C7841F1A13 -:10248000F24EC6588ED77938DF8B982A6F9E6C61D2 -:102490004CF8E9E19A23BCBE24F285EA55EE7101BD -:1024A0006B5C813ACAF58E7DB5DFD4695FFBE807C6 -:1024B0003757A07CBBFFFBC1DD41D2DFBB394F33B7 -:1024C00046F91AF4A705D71C8BB521DDFD372A1A6A -:1024D000EDA343AEDA4DEB1A8D82C17500975E9481 -:1024E000AC51025C2F353D7C07D4AD2705C554198E -:1024F000213D9CF20BFD107A16B4F4E68021EA3EF1 -:1025000007A2A27E65CB2FE77D80EAD267A30AC728 -:102510002576FD8A6A3DF970DC7ECB2EFB2DBB440F -:102520009CCA7587D9F78B337CEEEC6FC984E99C24 -:1025300029D2FC468CE81E75AE6B6FD39403971CB2 -:1025400058F1A2DFBA8CEF5A9FD02FE5A95FB03FB8 -:102550002D52A6F8BC2A5A7D8AFDE97DD67ABA9A10 -:1025600081F759BCD2F2DB713322E8FDA5C30F48D5 -:10257000D7BC6A7AE95CB855DC49F0368BBA5D8124 -:102580000A4606F97CA022C8F79ACA565A75BA7547 -:10259000E25E857D2FBC22EEBC1716829CDF0954BB -:1025A0008B7B59B97D90379EF3FEDBCE5F1E7EEEAE -:1025B000440EBD2FC59CF7C7CFF7FDEF7BD3CF9D52 -:1025C00040FD1A35CE6D87B6BCEEED6D667ED9FA4C -:1025D00068EB6788B6D838FFF763A178DEFACC31AC -:1025E000CB0ECEE7CFCA7CF11EC245F7AD893BF0DA -:1025F000D103967D3E1013F94F75F119CEAB1DB482 -:10260000EE5F1D0CC086EFE499371353797C56FFBB -:102610009D38C2D69FB97C380F8E5813B5E2104F43 -:1026200080CEF151A3ED59AA47BEABA93AE4F80117 -:10263000779EDDC61105DD76BEEF3DC65125C12969 -:10264000A1B72B9D71871B070C2BE90D64E7C375A0 -:10265000AAED9FD88F5CFD6CE1D7938C939252EEDC -:10266000B9B93F7307D30DB9F2EC50EEFCDDCAFEE9 -:1026700018F07A42FA9929BA671E8A29E2DED6A8AA -:1026800009B9F76EC63CBF9C3965FDFB031B77B0EB -:102690003EEF9FE2DFD3C0172077FEBD1FDBCCBF2C -:1026A0002F399FDC67FD7A5875E4DF2ED62EFE2584 -:1026B00066D5B7031020BB380BF770DD1D46638E5F -:1026C000F3882B100BF8C8167FB84D6595757449C3 -:1026D000597B817651D73F9B98F58B0A7D67589F30 -:1026E00055D2AD0A8AC721C3BF53B4EF959E855F0B -:1026F000F2BCC9A7246916675D89E13EFDFE712918 -:10270000A99CE6A1D6BDFE2560F0F31A88737B353F -:10271000F4705B07A3DC5E0393DCD6C314B70D70C3 -:1027200086DB15A0CB34C9F560CAC0573513DCBFB2 -:102730000192DCB640E2FD53B8FEFE8AED2B385E16 -:10274000B4FD87C5279BCF79EC9D71A4CD0F9BEF7E -:10275000FF48CEFA02EC3915127EB87D6586F53C4D -:10276000181438D98EAF6D3AF3E1DECB85CF6C5CAF -:10277000F97FE7ADB141E048000000000000000033 -:1027800000000018000000000000000000000040F1 -:102790000000000000000000000000280000000011 -:1027A0000000000000000010000000000000000019 -:1027B00000000020000000000000000000000010E9 -:1027C0000000000000000000000000080000000001 -:1027D00000000000000000000000000000000000F9 -:1027E00000000000000000000000000000000000E9 -:1027F00000000000000000000000000000000000D9 -:1028000000000000000000000000000000000000C8 -:1028100000000000000000000000000000000000B8 -:1028200000000000000000000000000000000000A8 -:102830000000000000000000000000000000000098 -:102840000000000000000000000000000000000088 -:102850000000000000000000000000000000000078 -:102860000000000000000000000000000000000068 -:102870000000000000000000000000000000000058 -:102880000000000000000000000000000000000048 -:102890000000000000000000000000000000000038 -:1028A0000000000000000000000000000000000028 -:1028B0000000000000000000000000000000000018 -:1028C0000000000000000000000000000000000008 -:1028D00000000000000000000000000000000000F8 -:1028E0000000000000000000000090000010000048 -:1028F0000000000800009008001000000000000226 -:1029000000009000001000000000001000009DA8D2 -:10291000000000000000000880000000000000002F -:102920000000000080000000000000000000000027 -:10293000800000000000000000000000000091A0E6 -:102940000000000000000008000093C00001000427 -:1029500000000001000093C8000000000000000219 -:10296000000093D00000000000000008000093D495 -:102970000000000000000002000094980000000029 -:1029800000000008000093D80008000000000008C4 -:1029900000009B3800400000000000400000941838 -:1029A0000008000000000008000094580008000023 -:1029B00000000008000094A800C800000000009873 -:1029C000000096380098000000000028000096786B -:1029D00000980000000000280000C0000540003002 -:1029E000000005400000CB200008000000000001AE -:1029F0000000CB21000800000000000100002008BA -:102A00000010000000000010000020000000000086 -:102A10000000000800009D600008000000000002A7 -:102A200000009DA000000000000000010000000068 -:102A30000000000000000000000000000000000096 -:102A40000000000000000000000000000000000086 -:102A50008000000000000000000000008000000076 -:102A600000000000000000008000000000000000E6 -:102A700000000000800000000000000000000000D6 -:102A80008000000000000000000000008000000046 -:102A900000000000000000008000000000000000B6 -:102AA00000000000800000000000000000000000A6 -:102AB0008000000000000000000000008000000016 -:102AC0000000000000000000800000000000000086 -:102AD0000000000080000000000000000000000076 -:102AE0008000000000000000000000000000000066 -:102AF00000000000000000000000000000000000D6 -:102B000000000000000000000000000000000000C5 -:102B100000000000000000000000000000000000B5 -:102B20000000000000000000800000000000000025 -:102B30000000000080000000000000000000000015 -:102B40008000000000000000000000000000000005 -:102B500000000000000000008000000000000000F5 -:102B600000000000800000000000000000000000E5 -:102B700080000000000000000000000000000000D5 -:102B80000000000000000000000000000000000045 -:102B90000000000000000000000000000000000035 -:102BA0000000000000000000000000000000000025 -:102BB0000000000000000000000000000000000015 -:102BC00000000000000012C800800000000000802B -:102BD0000000000100000000000000000000A00054 -:102BE000071000000000071000001EC800000000D1 -:102BF000000000080000AEC000080000000000084F -:102C00000000AE4000080000000000080000AE8098 -:102C1000000800000000000800002008001000006C -:102C2000000000100000200000000000000000086C -:102C30000000A01007100040000000400000AF405E -:102C400000080000000000010000AF410008000083 -:102C50000000000100001ED0000000000000000184 -:102C600000001ED8000000000000000200001EDA74 -:102C70000000000000000002000012B00008000088 -:102C800000000008800000000000000000000000BC -:102C90008000000000000000000000008000000034 -:102CA00000000000000000008000000000000000A4 -:102CB0000000000080000000000000000000000094 -:102CC0008000000000000000000000008000000004 -:102CD0000000000000000000800000000000000074 -:102CE0000000000080000000000000000000000064 -:102CF00000000000000000000000000000000000D4 -:102D000000000000000000000000000000000000C3 -:102D100000000000000000000000000000000000B3 -:102D20000000000000000000000000008000000023 -:102D30000000000000000000800000000000000013 -:102D40000000000000000000000000000000000083 -:102D50008000000000000000000000008000000073 -:102D600000000000000000008000000000000000E3 -:102D700000000000800000000000000000000000D3 -:102D80000000B00000180000000000180000B300B0 -:102D900000400000000000400000B30000400002BE -:102DA000000000010000B30100400002000000002C -:102DB0000000800000400000000000408000000093 -:102DC000000000000000000000008000000800403B -:102DD000000000040000800400080040000000041F -:102DE0000000BB0000280000000000280000BC40DC -:102DF00000100000000000100000880000800000AB -:102E00000000008000008800000800800000000230 -:102E100000008C00002000000000002000002008BE -:102E20000010000000000010000020000000000062 -:102E30000000000800001108000800000000000861 -:102E4000000011680008000000000008000011A840 -:102E500000080000000000080000127000080000D8 -:102E600000000001000012710008000000000001D5 -:102E700000008D000010000400000004000013207A -:102E80000030001800000010000013280030001867 -:102E900000000002800000000000000000000000B0 -:102EA000800000000000000000000000000011E8A9 -:102EB0000000000000000001800000000000000091 -:102EC0000000000080000000000000000000000082 -:102ED00080000000000000000000000080000000F2 -:102EE0000000000000000000800000000000000062 -:102EF0000000000080000000000000000000000052 -:102F000000000000000000000000000000000000C1 -:102F100000000000000000000000000000000000B1 -:102F200000000000000000000000000000000000A1 -:102F30008000000000000000000000008000000091 -:102F40000000000000000000000000000000000081 -:102F500000000000000083080080000000000080E6 -:102F60000000000100000000000000000000200838 -:102F70000010000000000010000020000000000011 -:102F80000000000800008D1000080000000000088C -:102F900000008D7000080000000000080000845050 -:102FA000046000280000046000008EA000080000FB -:102FB0000000000100008EA10008000000000001D8 -:102FC0000000840800080000000000080000844899 -:102FD000000000000000000100008DF40008000067 -:102FE0000000000200008DF6000800000000000252 -:102FF00000008E04001000000000000480000000AB -:103000000000000000000000800000000000000040 -:103010000000000080000000000000000000000030 -:1030200000000000000000000000000000000000A0 -:103030000000000000000000000000000000000090 -:103040000000000000000000000000000000000080 -:103050008000000000000000000000008000000070 -:103060000000000000000000000000000000000060 -:1030700000000000800000000000000000000000D0 -:103080008000000000000000000000008000000040 -:1030900000000000000000008000000000000000B0 -:1030A00000000000000030000040000000000008A8 -:1030B00000003008004000000000002800003390AD -:1030C00001C00010000000080000320000200000D5 -:1030D0000000002000003720000000000000000871 -:1030E0000000102006200038000000080000A000AA -:1030F000000000000000200000003EA900000000C9 -:103100000000000100003EC80000000000000002B6 -:1031100000001C4000E000080000000880000000E3 -:103120000000000000000000000040000008000057 -:103130000000000100004001000800000000000144 -:103140000000404000080004000000020000406051 -:103150000008000400000004000040000008000017 -:10316000000000040000400400080000000000040B -:10317000000040400000000000000008000040483F -:1031800000000000000000080000800000000000B7 -:103190000000001000005040000100040000000189 -:1031A0000000500000000000000000200000500857 -:1031B00000100000000000040000500C001000008F -:1031C00000000001000052C70000000000000001E4 -:1031D000000052C6000000000000000100003000A6 -:1031E0000030001800000004000030040030001817 -:1031F0000000000400003008003000180000000249 -:103200000000300A00300018000000020000300CFE -:1032100000300018000000010000300D00300018E0 -:10322000000000010000300E003000180000000116 -:1032300000003010003000180000000400003014BE -:103240000030001800000004000050000100008061 -:103250000008000400005004010000800008000481 -:103260000000000A0000000000000000000050689C -:103270000100008000000001000050690100008092 -:10328000000000010000506C0100008000000002FE -:103290000000506E0100008000000002000050702D -:1032A0000100008000000004000050740100008054 -:1032B00000000004000050660100008000000002D1 -:1032C0000000506401000080000000010000506018 -:1032D0000100008000000002000050620100008038 -:1032E00000000002000050500100008000000004B7 -:1032F00000005054010000800000000400005058FD -:1033000001000080000000040000505C010000800B -:10331000000000040000507C01000080000000015B -:103320000000507D010000800000000100004018F6 -:103330000010000000000004000040900010000099 -:10334000000000040000409800100000000000048D -:1033500000004110000000000000000200004112C7 -:103360000000000000000002000041140000000006 -:1033700000000002000041160000000000000002F2 -:1033800000006040000800000000000200006042F1 -:103390000008000000000002000060440008000077 -:1033A0000000000400006080000800000000000829 -:1033B000000060C00040000800000008000060003D -:1033C0000008000000000002000060020008000089 -:1033D000000000010000600400080000000000027E -:1033E0000000634000080000000000080000638047 -:1033F00000080000000000040000638400080000D2 -:1034000000000001000063C000080000000000028E -:10341000000063C400080000000000020000640017 -:103420000008000000000004000070000010000010 -:103430000000000400007004001000000000000400 -:103440000000700800100000000000040000700080 -:1034500000080000000000020000700200080000E8 -:1034600000000001000070040008000000000002DD -:1034700000007040000800000000000200007044DE -:103480000008000000000002000070460008000074 -:10349000000000020000764800080000000000085C -:1034A000000070800008000000000002000070842E -:1034B00000080000000000020000768800080000FC -:1034C000000000080000804000080000000000012B -:1034D0000000804100080000000000010000804260 -:1034E0000008000000000001000080430008000008 -:1034F0000000000100008000000800000000000241 -:1035000000008002000800000000000100008004AC -:103510000008000000000002000080C00008000059 -:1035200000000002000080C200080000000000024D -:10353000000080C40008000000000002000080803D -:103540000008000000000001000080810008000069 -:10355000000000010000808200080000000000015F -:10356000000080830008000000000001000080844B -:103570000008000000000001000080850008000035 -:10358000000000010000808600080000000000012B -:10359000000060000008000000000002000060025F -:1035A00000080000000000010000600400080000A6 -:1035B000000000020000604200C00018000000028D -:1035C0000000604000C00018000000020000604CD5 -:1035D00000C00018000000080000604400C000188F -:1035E000000000080000605700C000180000000143 -:1035F0000000605400C00018000000020000605687 -:1036000000C0001800000001000066400008000033 -:1036100000000008000066800008000000000008AC -:10362000000066C000080000000000080000D94249 -:1036300000180000000000020000DE400000000052 -:10364000000000000000E000000000000000000496 -:103650000000DD4000000000000000040000DD4428 -:1036600000000000000000040000DD480000000031 -:10367000000000040000DD4C000000000000000419 -:103680000000DD5000000000000000040000DD54D8 -:1036900000000000000000040000DD5800000000F1 -:1036A000000000040000DD400000000000000020D9 -:1036B0000000DA0000000000000000040000DA0052 -:1036C00000000000000000680000BB600000000077 -:1036D000000000000000D000000000000000000416 -:1036E0000000B0C000000000000000040000B0C4F2 -:1036F00000000000000000040000B0C8000000004E -:10370000000000040000B0C0000000000000001035 -:103710000000D6B000000000000000040000D6B495 -:1037200000000000000000040000D6B80000000007 -:10373000000000040000D6BC0000000000000004EF -:103740000000D6B000000000000000100000D348C8 -:1037500000000000000000080000D3580000000036 -:1037600000000080000000100000000000000000C9 -:103770000000D35800000000000000080000000016 -:08378000060205000000000034 -:00000001FF diff --git a/firmware/bnx2x/bnx2x-e1h-6.2.9.0.fw.ihex b/firmware/bnx2x/bnx2x-e1h-6.2.9.0.fw.ihex new file mode 100644 index 0000000..ba1ce53 --- /dev/null +++ b/firmware/bnx2x/bnx2x-e1h-6.2.9.0.fw.ihex @@ -0,0 +1,13192 @@ +:1000000000004F48000000680000070C00004FB8D7 +:1000100000001ED4000056C800000094000075A027 +:1000200000009F4C00007638000000CC00011588CD +:100030000000DC5800011658000000940001F2B8DE +:100040000000400C0001F350000000A400023360E7 +:100050000000F4240002340800000FFC00032830E4 +:100060000000000400033830020400480000000FC4 +:1000700002040054000000450204005C0000000679 +:100080000204007000000004020400780000000078 +:100090000204007C121700000204008022170000F6 +:1000A00002040084321700000604008800000005E6 +:1000B0000204009C12150000020400A0221500009A +:1000C000020400A432150000060400A80000000489 +:1000D000020400B802100000020400BC001000007E +:1000E000020400C010100000020400C42010000030 +:1000F000020400C830100000020400CC40100000D0 +:10010000060400D000000003020400DC0010000020 +:10011000020400E012140000020400E422140000B3 +:10012000020400E832140000020400EC4214000053 +:10013000060400F000000003010401240000000098 +:1001400001040128000000000104012C000000004F +:100150000104013000000000020401D00000890603 +:1001600002040004000000FF02040008000000FF79 +:100170000204000C000000FF02040010000000FF59 +:10018000020400140000007F02040018000000FFB9 +:100190000204001C000000FF02040020000000FF19 +:1001A000020400240000003E0204002800000000B9 +:1001B0000204002C0000003F020400300000003F59 +:1001C000020400340000003F020400380000003F39 +:1001D0000204003C0000003F020400400000003F19 +:1001E000020400440000003F020404CC00000001AF +:1001F00002042008000002110204200C000002008A +:10020000020420100000020402042014000002195D +:100210000204201C0000FFFF020420200000FFFF5A +:10022000020420240000FFFF020420280000FFFF3A +:1002300002042038000000200604203C0000001FBB +:10024000020420B800000001060420BC0000005F8A +:100250000204223807FFFFFF0204223C0000003F97 +:100260000204224007FFFFFF020422440000000FA7 +:1002700001042248000000000104224C000000009C +:10028000010422500000000001042254000000007C +:1002900001042258000000000104225C000000005C +:1002A000010422600000000001042264000000003C +:1002B00001042268000000000104226C000000001C +:1002C00001042270000000000104227400000000FC +:1002D00001042278000000000104227C00000000DC +:1002E0000C042000000003E80A04200000000001C4 +:1002F0000B0420000000000A0605400000000D006D +:100300000205004400000020020500480000003201 +:10031000020500900215002002050094021500203D +:1003200002050098000000300205009C0810000043 +:10033000020500A000000033020500A40000003008 +:10034000020500A800000031020500AC0000000218 +:10035000020500B000000005020500B40000000620 +:10036000020500B800000002020500BC0000000207 +:10037000020500C000000000020500C400000005E6 +:10038000020500C800000002020500CC00000002C7 +:10039000020500D000000002020500D400000001A8 +:1003A00002050114000000010205011C000000010B +:1003B0000205012000000002020502040000000105 +:1003C0000205020C0000004002050210000000407F +:1003D0000205021C0000002002050220000000139C +:1003E0000205022400000020060502400000000A69 +:1003F00004050280002000000205005000000007F4 +:10040000020500540000000702050058000000002B +:100410000205005C00000008020500600000000109 +:100420000605006400000003020500D80000000675 +:1004300002050004000000010205000800000001A0 +:100440000205000C00000001020500100000000180 +:100450000205001400000001020500180000000160 +:100460000205001C00000001020500200000000140 +:100470000205002400000001020500280000000120 +:100480000205002C00000001020500300000000100 +:1004900002050034000000010205003800000001E0 +:1004A0000205003C000000010205004000000001C0 +:1004B000020500E00000000D020500E80000000059 +:1004C000020500F000000000020500F80000000036 +:1004D000020500E40000002D020500EC00000020F1 +:1004E000020500F400000020020500FC00000020CE +:1004F000020500E00000001D020500E800000010F9 +:10050000020500F000000010020500F800000010D5 +:10051000020500E40000003D020500EC0000003090 +:10052000020500F400000030020500FC000000306D +:10053000020500E00000004D020500E80000004058 +:10054000020500F000000040020500F80000004035 +:10055000020500E40000006D020500EC00000060F0 +:10056000020500F400000060020500FC00000060CD +:10057000020500E00000005D020500E800000050F8 +:10058000020500F000000050020500F800000050D5 +:10059000020500E40000007D020500EC0000007090 +:1005A000020500F400000070020500FC000000706D +:1005B0000406100002000020020600DC000000011A +:1005C000010600D80000000004060200000302201B +:1005D000020600DC00000000010600B80000000078 +:1005E000010600C8000000000206016C00000000C7 +:1005F000010600BC00000000010600CC0000000065 +:1006000002060170000000000718040000910000BD +:10061000081807D800050223071C00002BF700006C +:10062000071C80002DD10AFE071D00002F461673FF +:10063000071D800016342245081DB13049DA022515 +:100640000118000000000000011800040000000074 +:1006500001180008000000000118000C0000000054 +:100660000118001000000000011800140000000034 +:1006700002180020000000010218002400000002FF +:1006800002180028000000030218002C00000000DF +:1006900002180030000000040218003400000001BD +:1006A00002180038000000000218003C00000001A1 +:1006B000021800400000000402180044000000007E +:1006C00002180048000000010218004C000000035E +:1006D0000218005000000000021800540000000141 +:1006E00002180058000000040218005C000000001E +:1006F00002180060000000010218006400000003FE +:1007000002180068000000000218006C00000001E0 +:1007100002180070000000040218007400000000BD +:1007200002180078000000040218007C000000039A +:100730000618008000000002021800A400003FFF1D +:10074000021800A8000003FF0218022400000000A5 +:1007500002180234000000000218024C00000000E1 +:10076000021802E4000000FF061810000000040058 +:10077000021B8BC000000001021B8000000000343F +:10078000021B804000000018021B80800000000C4B +:10079000021B80C0000000200C1B83000007A1206A +:1007A0000A1B8300000001380B1B83000000138824 +:1007B0000A1B8340000000000C1B8340000001F472 +:1007C0000B1B834000000005021B83800007A12053 +:1007D000021B83C0000001F4021B14800000000112 +:1007E0000A1B148000000000061A1000000003B36A +:1007F000041A1ECC00010227061A1ED000000008B1 +:10080000061A2008000000C8061A20000000000296 +:10081000041AAF4000100228061A3718000000041E +:10082000061A371000000002061A500000000002ED +:10083000061A500800000004061A501800000004B0 +:10084000061A502800000004061A50380000000460 +:10085000061A504800000004061A50580000000410 +:10086000061A506800000004061A507800000002C2 +:10087000041A52C000020238061A40500000000656 +:10088000041A40680002023A041A40400004023C84 +:10089000041A800000010240061A800400000003D0 +:1008A000041A801000010241061A8014000000039F +:1008B000041A802000010242061A8024000000036E +:1008C000041A803000010243061A8034000000033D +:1008D000041A804000010244061A8044000000030C +:1008E000041A805000010245061A805400000003DB +:1008F000041A806000010246061A806400000003AA +:10090000041A807000010247061A80740000000378 +:10091000041A808000010248061A80840000000347 +:10092000041A809000010249061A80940000000316 +:10093000041A80A00001024A061A80A400000003E5 +:10094000041A80B00001024B061A80B400000003B4 +:10095000041A80C00001024C061A80C40000000383 +:10096000041A80D00001024D061A80D40000000352 +:10097000041A80E00001024E061A80E40000000321 +:10098000041A80F00001024F061A80F400000003F0 +:10099000041A810000010250061A810400000003BD +:1009A000041A811000010251061A8114000000038C +:1009B000041A812000010252061A8124000000035B +:1009C000041A813000010253061A8134000000032A +:1009D000041A814000010254061A814400000003F9 +:1009E000041A815000010255061A815400000003C8 +:1009F000041A816000010256061A81640000000397 +:100A0000041A817000010257061A81740000000365 +:100A1000041A818000010258061A81840000000334 +:100A2000041A819000010259061A81940000000303 +:100A3000041A81A00001025A061A81A400000003D2 +:100A4000041A81B00001025B061A81B400000003A1 +:100A5000041A81C00001025C061A81C40000000370 +:100A6000041A81D00001025D061A81D4000000033F +:100A7000041A81E00001025E061A81E4000000030E +:100A8000041A81F00001025F061A81F400000003DD +:100A9000041A820000010260061A820400000003AA +:100AA000041A821000010261061A82140000000379 +:100AB000041A822000010262061A82240000000348 +:100AC000041A823000010263061A82340000000317 +:100AD000041A824000010264061A824400000003E6 +:100AE000041A825000010265061A825400000003B5 +:100AF000041A826000010266061A82640000000384 +:100B0000041A827000010267061A82740000000352 +:100B1000041A828000010268061A82840000000321 +:100B2000041A829000010269061A829400000003F0 +:100B3000041A82A00001026A061A82A400000003BF +:100B4000041A82B00001026B061A82B4000000038E +:100B5000041A82C00001026C061A82C4000000035D +:100B6000041A82D00001026D061A82D4000000032C +:100B7000041A82E00001026E061A82E400000003FB +:100B8000041A82F00001026F061A82F400000003CA +:100B9000041A830000010270061A83040000000397 +:100BA000041A831000010271061A83140000000366 +:100BB000041A832000010272061A83240000000335 +:100BC000041A833000010273061A83340000000304 +:100BD000041A834000010274061A834400000003D3 +:100BE000041A835000010275061A835400000003A2 +:100BF000041A836000010276061A83640000000371 +:100C0000041A837000010277061A8374000000033F +:100C1000041A838000010278061A8384000000030E +:100C2000041A839000010279061A839400000003DD +:100C3000041A83A00001027A061A83A400000003AC +:100C4000041A83B00001027B061A83B4000000037B +:100C5000041A83C00001027C061A83C4000000034A +:100C6000041A83D00001027D061A83D40000000319 +:100C7000041A83E00001027E061A83E400000003E8 +:100C8000041A83F00001027F061A83F400000003B7 +:100C9000041A840000010280061A84040000000384 +:100CA000041A841000010281061A84140000000353 +:100CB000041A842000010282061A84240000000322 +:100CC000041A843000010283061A843400000003F1 +:100CD000041A844000010284061A844400000003C0 +:100CE000041A845000010285061A8454000000038F +:100CF000041A846000010286061A8464000000035E +:100D0000041A847000010287061A8474000000032C +:100D1000041A848000010288061A848400000003FB +:100D2000041A849000010289061A849400000003CA +:100D3000041A84A00001028A061A84A40000000399 +:100D4000041A84B00001028B061A84B40000000368 +:100D5000041A84C00001028C061A84C40000000337 +:100D6000041A84D00001028D061A84D40000000306 +:100D7000041A84E00001028E061A84E400000003D5 +:100D8000041A84F00001028F061A84F400000003A4 +:100D9000041A850000010290061A85040000000371 +:100DA000041A851000010291061A85140000000340 +:100DB000041A852000010292061A8524000000030F +:100DC000041A853000010293061A853400000003DE +:100DD000041A854000010294061A854400000003AD +:100DE000041A855000010295061A8554000000037C +:100DF000041A856000010296061A8564000000034B +:100E0000041A857000010297061A85740000000319 +:100E1000041A858000010298061A858400000003E8 +:100E2000041A859000010299061A859400000003B7 +:100E3000041A85A00001029A061A85A40000000386 +:100E4000041A85B00001029B061A85B40000000355 +:100E5000041A85C00001029C061A85C40000000324 +:100E6000041A85D00001029D061A85D400000003F3 +:100E7000041A85E00001029E061A85E400000003C2 +:100E8000041A85F00001029F061A85F40000000391 +:100E9000041A8600000102A0061A8604000000035E +:100EA000041A8610000102A1061A8614000000032D +:100EB000041A8620000102A2061A862400000003FC +:100EC000041A8630000102A3061A863400000003CB +:100ED000041A8640000102A4061A8644000000039A +:100EE000041A8650000102A5061A86540000000369 +:100EF000041A8660000102A6061A86640000000338 +:100F0000041A8670000102A7061A86740000000306 +:100F1000041A8680000102A8061A868400000003D5 +:100F2000041A8690000102A9061A869400000003A4 +:100F3000041A86A0000102AA061A86A40000000373 +:100F4000041A86B0000102AB061A86B40000000342 +:100F5000041A86C0000102AC061A86C40000000311 +:100F6000041A86D0000102AD061A86D400000003E0 +:100F7000041A86E0000102AE061A86E400000003AF +:100F8000041A86F0000102AF061A86F4000000037E +:100F9000041A8700000102B0061A8704000000034B +:100FA000041A8710000102B1061A8714000000031A +:100FB000041A8720000102B2061A872400000003E9 +:100FC000041A8730000102B3061A873400000003B8 +:100FD000041A8740000102B4061A87440000000387 +:100FE000041A8750000102B5061A87540000000356 +:100FF000041A8760000102B6061A87640000000325 +:10100000041A8770000102B7061A877400000003F3 +:10101000041A8780000102B8061A878400000003C2 +:10102000041A8790000102B9061A87940000000391 +:10103000041A87A0000102BA061A87A40000000360 +:10104000041A87B0000102BB061A87B4000000032F +:10105000041A87C0000102BC061A87C400000003FE +:10106000041A87D0000102BD061A87D400000003CD +:10107000041A87E0000102BE061A87E4000000039C +:10108000041A87F0000102BF061A87F4000000036B +:10109000041A8800000102C0061A88040000000338 +:1010A000041A8810000102C1061A88140000000307 +:1010B000041A8820000102C2061A882400000003D6 +:1010C000041A8830000102C3061A883400000003A5 +:1010D000041A8840000102C4061A88440000000374 +:1010E000041A8850000102C5061A88540000000343 +:1010F000041A8860000102C6061A88640000000312 +:10110000041A8870000102C7061A887400000003E0 +:10111000041A8880000102C8061A888400000003AF +:10112000041A8890000102C9061A8894000000037E +:10113000041A88A0000102CA061A88A4000000034D +:10114000041A88B0000102CB061A88B4000000031C +:10115000041A88C0000102CC061A88C400000003EB +:10116000041A88D0000102CD061A88D400000003BA +:10117000041A88E0000102CE061A88E40000000389 +:10118000041A88F0000102CF061A88F40000000358 +:10119000041A8900000102D0061A89040000000325 +:1011A000041A8910000102D1061A891400000003F4 +:1011B000041A8920000102D2061A892400000003C3 +:1011C000041A8930000102D3061A89340000000392 +:1011D000041A8940000102D4061A89440000000361 +:1011E000041A8950000102D5061A89540000000330 +:1011F000041A8960000102D6061A896400000003FF +:10120000041A8970000102D7061A897400000003CD +:10121000041A8980000102D8061A8984000000039C +:10122000041A8990000102D9061A8994000000036B +:10123000041A89A0000102DA061A89A4000000033A +:10124000041A89B0000102DB061A89B40000000309 +:10125000041A89C0000102DC061A89C400000003D8 +:10126000041A89D0000102DD061A89D400000003A7 +:10127000041A89E0000102DE061A89E40000000376 +:10128000041A89F0000102DF061A89F40000000345 +:10129000041A8A00000102E0061A8A040000000312 +:1012A000041A8A10000102E1061A8A1400000003E1 +:1012B000041A8A20000102E2061A8A2400000003B0 +:1012C000041A8A30000102E3061A8A34000000037F +:1012D000041A8A40000102E4061A8A44000000034E +:1012E000041A8A50000102E5061A8A54000000031D +:1012F000041A8A60000102E6061A8A6400000003EC +:10130000041A8A70000102E7061A8A7400000003BA +:10131000041A8A80000102E8061A8A840000000389 +:10132000041A8A90000102E9061A8A940000000358 +:10133000041A8AA0000102EA061A8AA40000000327 +:10134000041A8AB0000102EB061A8AB400000003F6 +:10135000041A8AC0000102EC061A8AC400000003C5 +:10136000041A8AD0000102ED061A8AD40000000394 +:10137000041A8AE0000102EE061A8AE40000000363 +:10138000041A8AF0000102EF061A8AF40000000332 +:10139000041A8B00000102F0061A8B0400000003FF +:1013A000041A8B10000102F1061A8B1400000003CE +:1013B000041A8B20000102F2061A8B24000000039D +:1013C000041A8B30000102F3061A8B34000000036C +:1013D000041A8B40000102F4061A8B44000000033B +:1013E000041A8B50000102F5061A8B54000000030A +:1013F000041A8B60000102F6061A8B6400000003D9 +:10140000041A8B70000102F7061A8B7400000003A7 +:10141000041A8B80000102F8061A8B840000000376 +:10142000041A8B90000102F9061A8B940000000345 +:10143000041A8BA0000102FA061A8BA40000000314 +:10144000041A8BB0000102FB061A8BB400000003E3 +:10145000041A8BC0000102FC061A8BC400000003B2 +:10146000041A8BD0000102FD061A8BD40000000381 +:10147000041A8BE0000102FE061A8BE40000000350 +:10148000041A8BF0000102FF061A8BF4000000031F +:10149000041A8C0000010300061A8C0400000003EB +:1014A000041A8C1000010301061A8C1400000003BA +:1014B000041A8C2000010302061A8C240000000389 +:1014C000041A8C3000010303061A8C340000000358 +:1014D000041A8C4000010304061A8C440000000327 +:1014E000041A8C5000010305061A8C5400000003F6 +:1014F000041A8C6000010306061A8C6400000003C5 +:10150000041A8C7000010307061A8C740000000393 +:10151000041A8C8000010308061A8C840000000362 +:10152000041A8C9000010309061A8C940000000331 +:10153000041A8CA00001030A061A8CA40000000300 +:10154000041A8CB00001030B061A8CB400000003CF +:10155000041A8CC00001030C061A8CC4000000039E +:10156000041A8CD00001030D061A8CD4000000036D +:10157000041A8CE00001030E061A8CE4000000033C +:10158000041A8CF00001030F061A8CF4000000030B +:10159000041A8D0000010310061A8D0400000003D8 +:1015A000041A8D1000010311061A8D1400000003A7 +:1015B000041A8D2000010312061A8D240000000376 +:1015C000041A8D3000010313061A8D340000000345 +:1015D000041A8D4000010314061A8D440000000314 +:1015E000041A8D5000010315061A8D5400000003E3 +:1015F000041A8D6000010316061A8D6400000003B2 +:10160000041A8D7000010317061A8D740000000380 +:10161000041A8D8000010318061A8D84000000034F +:10162000041A8D9000010319061A8D94000000031E +:10163000041A8DA00001031A061A8DA400000003ED +:10164000041A8DB00001031B061A8DB400000003BC +:10165000041A8DC00001031C061A8DC4000000038B +:10166000041A8DD00001031D061A8DD4000000035A +:10167000041A8DE00001031E061A8DE40000000329 +:10168000041A8DF00001031F061A8DF400000003F8 +:10169000041A8E0000010320061A8E0400000003C5 +:1016A000041A8E1000010321061A8E140000000394 +:1016B000041A8E2000010322061A8E240000000363 +:1016C000041A8E3000010323061A8E340000000332 +:1016D000041A8E4000010324061A8E440000000301 +:1016E000041A8E5000010325061A8E5400000003D0 +:1016F000041A8E6000010326061A8E64000000039F +:10170000041A8E7000010327061A8E74000000036D +:10171000041A8E8000010328061A8E84000000033C +:10172000041A8E9000010329061A8E94000000030B +:10173000041A8EA00001032A061A8EA400000003DA +:10174000041A8EB00001032B061A8EB400000003A9 +:10175000041A8EC00001032C061A8EC40000000378 +:10176000041A8ED00001032D061A8ED40000000347 +:10177000041A8EE00001032E061A8EE40000000316 +:10178000041A8EF00001032F061A8EF400000003E5 +:10179000041A8F0000010330061A8F0400000003B2 +:1017A000041A8F1000010331061A8F140000000381 +:1017B000041A8F2000010332061A8F240000000350 +:1017C000041A8F3000010333061A8F34000000031F +:1017D000041A8F4000010334061A8F4400000003EE +:1017E000041A8F5000010335061A8F5400000003BD +:1017F000041A8F6000010336061A8F64000000038C +:10180000041A8F7000010337061A8F74000000035A +:10181000041A8F8000010338061A8F840000000329 +:10182000041A8F9000010339061A8F9400000003F8 +:10183000041A8FA00001033A061A8FA400000003C7 +:10184000041A8FB00001033B061A8FB40000000396 +:10185000041A8FC00001033C061A8FC40000000365 +:10186000041A8FD00001033D061A8FD40000000334 +:10187000041A8FE00001033E061A8FE400000007FF +:10188000041A62C00020033F061AD0000000007254 +:10189000061AD24800000010061AD6B00000002038 +:1018A000061AD47000000090061AD46800000002E6 +:1018B000061AA000000001C4061A30000000001043 +:1018C000061A308000000010061A310000000010D7 +:1018D000061A318000000010061A330000000012C2 +:1018E000061A339000000070061AD4580000000257 +:1018F000061AD34800000002061AD3580000002040 +:10190000061AA710000001C4061A3040000000109B +:10191000061A30C000000010061A31400000001006 +:10192000061A31C000000010061A334800000012E9 +:10193000061A355000000070061AD460000000023C +:10194000061AD35000000002061AD3D80000002067 +:10195000021AAE2000000000061A5000000000022B +:10196000061A508000000012041A40000002035FB3 +:10197000041A63C000020361061A7000000000042C +:10198000061A320000000008021AAE24000000000F +:10199000061A501000000002061A50C8000000127B +:1019A000041A400800020363041A63C800020365B6 +:1019B000061A701000000004061A32200000000809 +:1019C000021AAE2800000000061A50200000000293 +:1019D000061A511000000012041A4010000203679A +:1019E000041A63D000020369061A70200000000484 +:1019F000061A324000000008021AAE2C0000000057 +:101A0000061A503000000002061A51580000001259 +:101A1000041A40180002036B041A63D80002036D15 +:101A2000061A703000000004061A32600000000838 +:101A3000021AAE3000000000061A504000000002FA +:101A4000061A51A000000012041A40200002036F81 +:101A5000041A63E000020371061A704000000004DB +:101A6000061A328000000008021AAE34000000009E +:101A7000061A505000000002061A51E80000001239 +:101A8000041A402800020373041A63E80002037575 +:101A9000061A705000000004061A32A00000000868 +:101AA000021AAE3800000000061A50600000000262 +:101AB000061A523000000012041A40300002037768 +:101AC000041A63F000020379061A70600000000433 +:101AD000061A32C000000008021AAE3C00000000E6 +:101AE000061A507000000002061A52780000001218 +:101AF000041A40380002037B041A63F80002037DD5 +:101B0000061A707000000004061A32E00000000897 +:101B10000200A468000B01C80200A294071D29114D +:101B20000200A298000000000200A29C009C042475 +:101B30000200A2A0000000000200A2A4000002090E +:101B40000200A270000000000200A2740000000069 +:101B50000200A270000000000200A2740000000059 +:101B60000200A270000000000200A2740000000049 +:101B70000200A270000000000200A2740000000039 +:101B8000020160A000000001020160A400000262E6 +:101B9000020160A800000002020160AC0000001811 +:101BA0000201620400000001020100B40000000113 +:101BB000020100B800000001020100DC0000000189 +:101BC0000201010000000001020101040000000107 +:101BD0000201007C003000000201008400000028A7 +:101BE0000201008C0000000002010130000000042E +:101BF0000201025C00000001020103280000000055 +:101C0000020160580000FFFF020160700000000741 +:101C10000201608000000001020105540000003054 +:101C2000020100C400000001020100CC000000011C +:101C3000020100F800000001020100F000000001B4 +:101C4000020100800030000002010088000000282E +:101C500002010090000000000201013400000004B5 +:101C6000020102DC000000010201032C0000000060 +:101C70000201605C0000FFFF0201607400000007C9 +:101C800002016084000000010201056400000030D0 +:101C9000020100C800000001020100D000000001A4 +:101CA000020100FC00000001020100F4000000013C +:101CB000020C100000000028020C20080000021195 +:101CC000020C200C00000200020C20100000020494 +:101CD000020C201C0000FFFF020C20200000FFFF70 +:101CE000020C20240000FFFF020C20280000FFFF50 +:101CF000020C203800000020020C203C00000021D3 +:101D0000020C204000000022020C204400000023AE +:101D1000020C204800000024020C204C000000258A +:101D2000020C205000000026020C20540000002766 +:101D3000020C205800000028020C205C0000002942 +:101D4000020C20600000002A020C20640000002B1E +:101D5000020C20680000002C020C206C0000002DFA +:101D6000020C20700000002E020C20740000002FD6 +:101D7000020C207800000010060C207C00000007F8 +:101D8000020C209800000011020C209C00000012A0 +:101D9000020C20A000000013060C20A40000001D6F +:101DA000020C211800000001020C211C000000019F +:101DB000020C212000000001060C21240000001D5F +:101DC000020C219800000001060C219C0000000775 +:101DD000020C21B800000001020C21BC000000012F +:101DE000020C21C000000001020C21C4000000010F +:101DF000020C21C800000001020C21CC00000001EF +:101E0000020C21D000000001020C21D400000001CE +:101E1000020C21D800000001020C21DC00000001AE +:101E2000020C21E000000001020C21E4000000018E +:101E3000020C21E800000001020C21EC000000016E +:101E4000020C21F000000001020C21F4000000014E +:101E5000020C21F800000001060C21FC0000000724 +:101E6000020C221800000001060C221C00000007D2 +:101E7000020C223807FFFFFF020C223C0000003F4B +:101E8000020C224007FFFFFF020C22440000000F5B +:101E9000010C224800000000010C224C0000000050 +:101EA000010C225000000000010C22540000000030 +:101EB000010C225800000000010C225C0000000010 +:101EC000010C226000000000010C226400000000F0 +:101ED000010C226800000000010C226C00000000D0 +:101EE000010C227000000000010C227400000000B0 +:101EF000010C227800000000010C227C0000000090 +:101F00000C0C2000000003E80A0C20000000000177 +:101F10000B0C20000000000A020C40080000101109 +:101F2000020C400C00001000020C401000001004D5 +:101F3000020C401400001021020C401C0000FFFFA6 +:101F4000020C40200000FFFF020C40240000FFFFB5 +:101F5000020C40280000FFFF020C40380000004641 +:101F6000020C403C00000010060C40400000000243 +:101F7000020C404800000018020C404C000000F029 +:101F8000060C40500000001F020C40CC0000000175 +:101F9000060C40D00000003A020C41B800000001DD +:101FA000060C41BC00000003020C41C80000000107 +:101FB000020C41CC00000001060C41D00000001AC8 +:101FC000020C423807FFFFFF020C423C0000003FBA +:101FD000020C424007FFFFFF020C42440000000FCA +:101FE000010C424800000000010C424C00000000BF +:101FF000010C425000000000010C4254000000009F +:10200000010C425800000000010C425C000000007E +:10201000010C426000000000010C4264000000005E +:10202000010C426800000000010C426C000000003E +:10203000010C427000000000010C4274000000001E +:10204000010C427800000000010C427C00000000FE +:10205000010C4280000000000C0C4000000003E86E +:102060000A0C4000000000010B0C40000000000AB8 +:10207000060D400000000A00020D0044000000327E +:10208000020D008C02150020020D009002150020A8 +:10209000020D009408100000020D009800000033AB +:1020A000020D009C00000002020D00A000000000D4 +:1020B000020D00A400000005020D00A800000005AC +:1020C000060D00AC00000002020D00B4000000028A +:1020D000020D00B800000003020D00BC0000000269 +:1020E000020D00C000000001020D00C80000000247 +:1020F000020D00CC00000002020D015C0000000196 +:10210000020D016400000001020D016800000002E0 +:10211000020D020400000001020D020C000000206C +:10212000020D021000000040020D021400000040E9 +:10213000020D022000000003020D0224000000181E +:10214000060D028000000012040D03000018037F3A +:10215000060D03600000000C020D004C00000001A1 +:10216000020D005000000002020D005400000000AB +:10217000020D005800000008060D005C000000047D +:10218000020D00C400000004020D00040000000164 +:10219000020D000800000001020D000C000000010B +:1021A000020D001000000001020D001400000001EB +:1021B000020D001800000001020D001C00000001CB +:1021C000020D002000000001020D002400000001AB +:1021D000020D002800000001020D002C000000018B +:1021E000020D003000000001020D0034000000016B +:1021F000020D003800000001020D003C000000014B +:10220000020D011400000009020D011C0000000A6B +:10221000020D012400000000020D012C000000004E +:10222000020D013400000000020D013C0000000B13 +:10223000020D014400000000020D011800000029F9 +:10224000020D01200000002A020D012800000020DC +:10225000020D013000000020020D013800000020B6 +:10226000020D01400000002B020D0148000000207B +:10227000020D011400000019020D011C0000001ADB +:10228000020D012400000010020D012C00000010BE +:10229000020D013400000010020D013C0000001B83 +:1022A000020D014400000010020D01180000003969 +:1022B000020D01200000003A020D0128000000304C +:1022C000020D013000000030020D01380000003026 +:1022D000020D01400000003B020D014800000030EB +:1022E000020D011400000049020D011C0000004A0B +:1022F000020D012400000040020D012C00000040EE +:10230000020D013400000040020D013C0000004BB2 +:10231000020D014400000040020D01180000006998 +:10232000020D01200000006A020D0128000000607B +:10233000020D013000000060020D01380000006055 +:10234000020D01400000006B020D0148000000601A +:10235000020D011400000059020D011C0000005A7A +:10236000020D012400000050020D012C000000505D +:10237000020D013400000050020D013C0000005B22 +:10238000020D014400000050020D01180000007908 +:10239000020D01200000007A020D012800000070EB +:1023A000020D013000000070020D013800000070C5 +:1023B000020D01400000007B020D0148000000708A +:1023C000060E200000000800020E004C0000003243 +:1023D000020E009402150020020E00980215002043 +:1023E000020E009C00000030020E00A00810000049 +:1023F000020E00A400000033020E00A8000000300E +:10240000020E00AC00000031020E00B0000000021D +:10241000020E00B400000004020E00B8000000002C +:10242000020E00BC00000002020E00C0000000020C +:10243000020E00C400000000020E00C800000002EE +:10244000020E00CC00000007020E00D000000002C7 +:10245000020E00D400000002020E00D800000001AD +:10246000020E014400000001020E014C00000001B8 +:10247000020E015000000002020E020400000001E2 +:10248000020E020C00000040020E0210000000408C +:10249000020E021C00000004020E022000000020B8 +:1024A000020E02240000000E020E02280000001B93 +:1024B000060E030000000012040E0280001B0397AA +:1024C000060E02EC00000005020E00540000000C95 +:1024D000020E00580000000C020E005C000000001C +:1024E000020E006000000010020E006400000010E8 +:1024F000060E006800000003020E00DC000000036E +:10250000020E000400000001020E0008000000019D +:10251000020E000C00000001020E0010000000017D +:10252000020E001400000001020E0018000000015D +:10253000020E001C00000001020E0020000000013D +:10254000020E002400000001020E0028000000011D +:10255000020E002C00000001020E003000000001FD +:10256000020E003400000001020E003800000001DD +:10257000020E003C00000001020E004000000001BD +:10258000020E004400000001020E01100000000FC6 +:10259000020E011800000000020E012000000000E1 +:1025A000020E012800000000020E01140000002F9E +:1025B000020E011C00000020020E01240000000099 +:1025C000020E012C00000000020E01100000001F8E +:1025D000020E011800000010020E01200000000091 +:1025E000020E012800000000020E01140000003F4E +:1025F000020E011C00000030020E01240000000049 +:10260000020E012C00000000020E01100000004F1D +:10261000020E011800000040020E01200000000020 +:10262000020E012800000000020E01140000006FDD +:10263000020E011C00000060020E012400000000D8 +:10264000020E012C00000000020E01100000005FCD +:10265000020E011800000050020E012000000000D0 +:10266000020E012800000000020E01140000007F8D +:10267000020E011C00000070020E01240000000088 +:10268000020E012C000000000730040000C9000009 +:10269000083007D8000503B207340000332B0000D0 +:1026A0000734800030A40CCB07350000351A18F52C +:1026B000073580002A8A263C0736000018D830DF0C +:1026C00008364630373A03B40130000000000000FD +:1026D000013000040000000001300008000000008C +:1026E0000130000C0000000001300010000000006C +:1026F0000130001400000000023000200000000142 +:102700000230002400000002023000280000000314 +:102710000230002C000000000230003000000004F5 +:1027200002300034000000010230003800000000D8 +:102730000230003C000000010230004000000004B4 +:102740000230004400000000023000480000000198 +:102750000230004C00000003023000500000000076 +:102760000230005400000001023000580000000454 +:102770000230005C00000000023000600000000138 +:102780000230006400000003023000680000000016 +:102790000230006C000000010230007000000004F4 +:1027A00002300074000000000230007800000004D5 +:1027B0000230007C000000030630008000000002B0 +:1027C000023000A400003FFF023000A8000003FF19 +:1027D0000230022400000000023002340000000039 +:1027E0000230024C00000000023002E40000FFFF53 +:1027F000063020000000080002338BC000000001FA +:10280000023380000000001A023380400000004EB6 +:102810000233808000000010023380C000000020DE +:102820000C3383000007A1200A3383000000013825 +:102830000B338300000013880A338340000000003C +:102840000C338340000001F40B338340000000058B +:10285000023383800007A120023383C0000001F40B +:1028600002331480000000010A33148000000000CD +:10287000063280000000010206322008000000C875 +:10288000063220000000000204328EA0001003B6C1 +:1028900006323EB00000000606323ED800000002BC +:1028A00006323E800000000A04323EA8000203C641 +:1028B00006323E00000000200632500000000400F6 +:1028C0000632400000000004043274C0000203C855 +:1028D00006324110000000020632D0000000003035 +:1028E0000632DD40000000440632DA00000000D06D +:1028F0000632DEA0000000020632E0000000080000 +:1029000006328450000001180632100000000188D1 +:102910000632500000000020063251000000002066 +:102920000632520000000020063253000000002052 +:10293000063254000000002006325500000000203E +:10294000063256000000002006325700000000202A +:102950000632580000000020063259000000002016 +:1029600006325A000000002006325B000000002002 +:1029700006325C000000002006325D0000000020EE +:1029800006325E000000002006325F0000000020DA +:1029900006328DF00000000204328E00000203CAED +:1029A00006328E08000000020632DE9000000002AF +:1029B00006321C4000000038063288B000000118C2 +:1029C00006321620000001880632508000000020E8 +:1029D00006325180000000200632528000000020A4 +:1029E0000632538000000020063254800000002090 +:1029F000063255800000002006325680000000207C +:102A00000632578000000020063258800000002067 +:102A1000063259800000002006325A800000002053 +:102A200006325B800000002006325C80000000203F +:102A300006325D800000002006325E80000000202B +:102A400006325F800000002006328DF80000000290 +:102A500004328E10000203CC06328E1800000002F1 +:102A60000632DE980000000206321D200000003809 +:102A700002328D50000000000632401000000002BB +:102A800002328D5400000000063240200000000297 +:102A900002328D5800000000063240300000000273 +:102AA00002328D5C0000000006324040000000024F +:102AB00002328D600000000006324050000000022B +:102AC00002328D6400000000063240600000000207 +:102AD00002328D68000000000632407000000002E3 +:102AE00002328D6C000000000632408000000002BF +:102AF000072004000091000008200780001003CE8A +:102B0000072400002AFF00000724800015090AC0DE +:102B10000824A9F0692803D001200000000000006B +:102B20000120000400000000012000080000000057 +:102B30000120000C00000000012000100000000037 +:102B4000012000140000000002200020000000010D +:102B500002200024000000020220002800000003E0 +:102B60000220002C000000000220003000000004C1 +:102B700002200034000000010220003800000000A4 +:102B80000220003C00000001022000400000000480 +:102B90000220004400000000022000480000000164 +:102BA0000220004C00000003022000500000000042 +:102BB0000220005400000001022000580000000420 +:102BC0000220005C00000000022000600000000104 +:102BD00002200064000000030220006800000000E2 +:102BE0000220006C000000010220007000000004C0 +:102BF00002200074000000000220007800000004A1 +:102C00000220007C0000000306200080000000027B +:102C1000022000A400003FFF022000A8000003FFE4 +:102C20000220022400000000022002340000000004 +:102C30000220024C00000000022002E40000FFFF1E +:102C4000062020000000080002238BC000000001C5 +:102C500002238000000000100223804000000012C8 +:102C60000223808000000030022380C00000000E9C +:102C70000C2383000007A1200A23830000000138F1 +:102C80000B238300000013880A2383400000000008 +:102C90000C238340000001F40B2383400000000557 +:102CA000022383800007A120022383C0000001F4D7 +:102CB00002231480000000010A2314800000000099 +:102CC000062210000000004206222008000000C872 +:102CD00006222000000000020622B000000000C60C +:102CE0000422B318000503D20622B32C0000000B07 +:102CF0000422B358000503D70622B36C0000000B72 +:102D00000422B398000503DC0622B3AC0000000BDC +:102D10000422B3D8000503E10622B3EC0000000B47 +:102D20000422B418000503E60622B42C0000000BB0 +:102D30000422B458000503EB0622B46C0000000B1B +:102D40000422B498000503F00622B4AC0000000B86 +:102D50000422B4D8000503F50622B4EC0000000BF1 +:102D60000422B518000503FA0622B52C0000000B5A +:102D70000422B558000503FF0622B56C0000000BC5 +:102D80000422B598000504040622B5AC0000000B2F +:102D90000422B5D8000504090622B5EC0000000B9A +:102DA0000422B6180005040E0622B62C0000000B03 +:102DB0000422B658000504130622B66C0000000B6E +:102DC0000422B698000504180622B6AC0000000BD9 +:102DD0000422B6D80005041D0622B6EC0000000B44 +:102DE0000422B718000504220622B72C0000000BAD +:102DF0000422B758000504270622B76C0000000B18 +:102E00000422B7980005042C0622B7AC0000000B82 +:102E10000422B7D8000504310622B7EC0000000BED +:102E20000422B818000504360622B82C0000000B56 +:102E30000422B8580005043B0622B86C0000000BC1 +:102E40000422B898000504400622B8AC0000000B2C +:102E50000422B8D8000504450622B8EC0000000B97 +:102E60000422B9180005044A0622B92C0000000B00 +:102E70000422B9580005044F0622B96C0000000B6B +:102E80000422B998000504540622B9AC0000000BD6 +:102E90000422B9D8000504590622B9EC0000000B41 +:102EA0000422BA180005045E0622BA2C0000000BAA +:102EB0000422BA58000504630622BA6C0000000B15 +:102EC0000422BA98000504680622BAAC0000000B80 +:102ED0000422BAD80005046D0622BAEC00000005F1 +:102EE0000622BB00000000530422BC4C0001047207 +:102EF0000622BC50000000030422BC5C00010473E5 +:102F00000622BC60000000030422BC6C00010474B3 +:102F10000622BC70000000030422BC7C0001047582 +:102F20000622BC80000000030422BC8C0001047651 +:102F30000622BC90000000030422BC9C0001047720 +:102F40000622BCA0000000030422BCAC00010478EF +:102F50000622BCB0000000030422BCBC00010479BE +:102F60000622880000000100062280000000020006 +:102F7000042212700010047A06223000000000C003 +:102F800006226700000001000622900000000400F5 +:102F900004226B080020048A022212C0FFFFFFFFF8 +:102FA000062211E800000002062212C800000009F3 +:102FB000062212EC0000000906228C000000000826 +:102FC0000222114800000000062213200000000623 +:102FD000062233000000000206226040000000309C +:102FE00006228C20000000080222114C0000000084 +:102FF00006221338000000060622330800000002F3 +:10300000062261000000003006228C40000000080B +:10301000022211500000000006221350000000069A +:103020000622331000000002062261C000000030BA +:1030300006228C60000000080222115400000000EB +:103040000622136800000006062233180000000262 +:10305000062262800000003006228C8000000008FA +:103060000222115800000000062213800000000612 +:1030700006223320000000020622634000000030D8 +:1030800006228CA0000000080222115C0000000053 +:1030900006221398000000060622332800000002D2 +:1030A000062264000000003006228CC000000008E8 +:1030B0000222116000000000062213B0000000068A +:1030C0000622333000000002062264C000000030F7 +:1030D00006228CE0000000080222116400000000BB +:1030E000062213C800000006062233380000000242 +:1030F0000622658000000030021610000000002843 +:1031000002170008000000020217002C0000000354 +:103110000217003C000000040217004800000002F3 +:103120000217004C000000900217005000000090B1 +:103130000217005400800090021700580810000089 +:10314000021700600000008A02170064000000807F +:1031500002170068000000810217006C0000008068 +:10316000021700700000000602170078000007D068 +:103170000217007C0000076C02170038007C100466 +:10318000021700040000000F061640240000000291 +:10319000021640700000001C0216420800000001E8 +:1031A0000216421000000001021642200000000139 +:1031B0000216422800000001021642300000000101 +:1031C00002164238000000010216426000000002B0 +:1031D0000C16401C0003D0900A16401C0000009CF6 +:1031E0000B16401C000009C4021640300000000805 +:1031F000021640340000000C021640380000001097 +:1032000002164044000000200216400000000001A9 +:10321000021640D80000000102164008000000011C +:103220000216400C000000010216401000000001D0 +:103230000216424000000000021642480000000052 +:103240000616427000000002021642500000000004 +:1032500002164258000000000616428000000002DC +:1032600002166008000012240216600C0000121002 +:1032700002166010000012140216601C0000FFFF0E +:10328000021660200000FFFF021660240000FFFF0E +:10329000021660280000FFFF0216603800000020C0 +:1032A0000216603C0000002006166040000000028C +:1032B00002166048000000230216604C0000002443 +:1032C000021660500000002502166054000000261F +:1032D00002166058000000270216605C00000029FA +:1032E000021660600000002A021660640000002BD5 +:1032F000021660680000002C0216606C0000002DB1 +:1033000002166070000000EC0216607400000011EC +:1033100002166078000000120616607C0000000FA4 +:10332000021660B800000001021660BC0000000137 +:10333000061660C00000000C021660F000000001DC +:10334000061660F400000031021661B800000001AA +:10335000061661BC0000000D021661F000000001BD +:10336000061661F4000000110216623807FFFFFF25 +:103370000216623C0000003F0216624007FFFFFF9A +:10338000021662440000000F0116624800000000AF +:103390000116624C0000000001166250000000009F +:1033A000011662540000000001166258000000007F +:1033B0000116625C0000000001166260000000005F +:1033C000011662640000000001166268000000003F +:1033D0000116626C0000000001166270000000001F +:1033E00001166274000000000116627800000000FF +:1033F0000116627C000000000C166000000003E86B +:103400000A166000000000010B1660000000000AB0 +:1034100002168040000000060216804400000005ED +:10342000021680480000000A0216804C00000005C9 +:103430000216805400000002021680CC0000000436 +:10344000021680D000000004021680D400000004A0 +:10345000021680D800000004021680DC0000000480 +:10346000021680E000000004021680E40000000460 +:10347000021680E800000004021688040000000420 +:10348000021680300000007C021680340000003DEF +:10349000021680380000003F0216803C0000009CAD +:1034A000021680F000000007061680F400000005F8 +:1034B0000216880C010101010216810800000000BB +:1034C0000216810C000000040216811000000004A6 +:1034D0000216811400000002021688100801200460 +:1034E00002168118000000050216811C000000056C +:1034F000021681200000000502168124000000054C +:103500000216882C200810010216812800000008ED +:103510000216812C00000006021681300000000710 +:1035200002168134000000000216883001010120DB +:1035300006168138000000040216883401010101DA +:1035400002168148000000000216814C00000004B1 +:10355000021681500000000402168154000000028F +:103560000216883808012004021681580000000560 +:103570000216815C00000005021681600000000553 +:1035800002168164000000050216883C2008100124 +:1035900002168168000000080216816C0000000617 +:1035A00002168170000000070216817400000001FD +:1035B00002168840010101200216817800000001F6 +:1035C0000216817C000000010216818000000001CB +:1035D00002168184000000010216884401010101E5 +:1035E00002168188000000010216818C0000000490 +:1035F000021681900000000402168194000000026F +:10360000021688480801200402168198000000056F +:103610000216819C00000005021681A00000000532 +:10362000021681A40000000502168814200810016B +:10363000021681A800000008021681AC00000006F6 +:10364000021681B000000007021681B400000001DC +:103650000216881801010120021681B8000000013D +:10366000021681BC00000001021681C000000001AA +:10367000021681C4000000010216881C010101012C +:10368000021681C800000001021681CC000000046F +:10369000021681D000000004021681D4000000024E +:1036A0000216882008012004021681D800000005B7 +:1036B000021681DC00000005021681E00000000512 +:1036C000021681E40000000502168824200810017B +:1036D000021681E800000008021681EC00000006D6 +:1036E000021681F0000000070216E40C0000000042 +:1036F00002168828010101200616E41000000004CB +:103700000216E000010101010216E42000000000A1 +:103710000216E424000000040216E428000000045D +:103720000216E42C000000020216E0040801200446 +:103730000216E430000000050216E4340000000523 +:103740000216E438000000050216E43C0000000503 +:103750000216E008200810010216E44000000008EC +:103760000216E444000000060216E44800000007C8 +:103770000216E44C000000000216E00C01010120DA +:103780000616E450000000040216E01001010101D9 +:103790000216E460000000000216E4640000000469 +:1037A0000216E468000000040216E46C0000000247 +:1037B0000216E014080120040216E470000000055F +:1037C0000216E474000000050216E478000000050B +:1037D0000216E47C000000050216E0182008100123 +:1037E0000216E480000000080216E48400000006CF +:1037F0000216E488000000070216E48C00000001B5 +:103800000216E01C010101200216E49000000001F4 +:103810000216E494000000010216E4980000000182 +:103820000216E49C000000010216E02001010101E3 +:103830000216E4A0000000010216E4A40000000447 +:103840000216E4A8000000040216E4AC0000000226 +:103850000216E024080120040216E4B0000000056E +:103860000216E4B4000000050216E4B800000005EA +:103870000216E4BC000000050216E0282008100132 +:103880000216E4C0000000080216E4C400000006AE +:103890000216E4C8000000070216E4CC0000000194 +:1038A0000216E02C010101200216E4D00000000104 +:1038B0000216E4D4000000010216E4D80000000162 +:1038C0000216E4DC000000010216E03001010101F3 +:1038D0000216E4E0000000010216E4E40000000427 +:1038E0000216E4E8000000040216E4EC0000000206 +:1038F0000216E034080120040216E4F0000000057E +:103900000216E4F4000000050216E4F800000005C9 +:103910000216E4FC000000050216E0382008100141 +:103920000216E500000000080216E504000000068B +:103930000216E508000000070216E03C0101012024 +:1039400002168240003F003F021682440000000041 +:103950000216E524003F003F0216E52800000000A3 +:1039600002168248000000000216824C003F003F11 +:103970000216E52C000000000216E530003F003F73 +:10398000021682500100010002168254010001005B +:103990000216E534010001000216E53801000100BD +:1039A00006168258000000020216E53C00000000E6 +:1039B0000216E540000000000216826000C000C050 +:1039C0000216826400C000C00216E54400C000C0B8 +:1039D0000216E54800C000C0021682681E001E00E4 +:1039E0000216826C1E001E000216E54C1E001E0010 +:1039F0000216E5501E001E000216827040004000B4 +:103A000002168274400040000216E5544000400057 +:103A10000216E558400040000216827880008000BF +:103A20000216827C800080000216E55C8000800027 +:103A30000216E560800080000216828020002000CF +:103A400002168284200020000216E5642000200077 +:103A50000216E56820002000061682880000000299 +:103A60000216E56C000000000216E5700000000080 +:103A700002168290000000000216829400000000EE +:103A80000216E574000000000216E5780000000050 +:103A900002168298000000000216829C00000000BE +:103AA0000216E57C000000000216E5800000000020 +:103AB000021682A000000000021682A4000000018D +:103AC000061682A80000000A021681F400000C0805 +:103AD000021681F800000040021681FC000001007F +:103AE0000216820000000020021682040000001767 +:103AF00002168208000000800216820C00000200FC +:103B000002168210000000000216821801FF01FF59 +:103B10000216821401FF01FF0216E51001FF01FFEA +:103B20000216E50C01FF01FF0216823C00000013A3 +:103B3000021680900000013F0216806000000140E4 +:103B40000216806400000140061680680000000232 +:103B500002168070000000C0061680740000000786 +:103B60000216809C00000048021680A00000004859 +:103B7000061680A400000002021680AC0000004877 +:103B8000061680B000000007021682380000800090 +:103B900002168234000025E40216809400007FFFA4 +:103BA00002168220000F000F0216821C000F000F69 +:103BB0000216E518000F000F0216E514000F000FA3 +:103BC000021682280000000002168224FFFFFFFF79 +:103BD0000216E520000000000216E51CFFFFFFFFB3 +:103BE0000216E6BC000000000216E6C0000000025B +:103BF0000216E6C4000000010216E6C80000000339 +:103C00000216E6CC000000040216E6D00000000612 +:103C10000216E6D4000000050216E6D800000007F0 +:103C2000021680EC000000FF0214000000000001FA +:103C30000214000C0000000102140040000000010A +:103C40000214004400007FFF0214000C000000007A +:103C500002140000000000000214006C00000000CC +:103C600002140004000000010214003000000001F2 +:103C700002140004000000000214005C00000000B8 +:103C800002140008000000010214003400000001CA +:103C90000214000800000000021400600000000090 +:103CA00006028000000020000202005800000032DE +:103CB000020200A003150020020200A40315002048 +:103CC000020200A801000030020200AC081000004F +:103CD000020200B000000033020200B40000003015 +:103CE000020200B800000031020200BC0000000324 +:103CF000020200C000000006020200C4000000032F +:103D0000020200C800000003020200CC0000000212 +:103D1000020200D000000000020200D400000002F5 +:103D2000020200DC00000000020200E000000006C9 +:103D3000020200E400000004020200E800000002A9 +:103D4000020200EC00000002020200F0000000018C +:103D5000020200FC00000006020201200000000038 +:103D60000202013400000002020201B00000000162 +:103D70000202020C00000001020202140000000115 +:103D80000202021800000002020204040000000106 +:103D90000202040C00000040020204100000004077 +:103DA0000202041C000000040202042000000020A3 +:103DB0000202042400000002020204280000002085 +:103DC000060205000000001204020480002004AA7C +:103DD000020200600000000F020200640000000701 +:103DE00002020068000000000202006C0000000EE9 +:103DF000020200700000000E0602007400000003C2 +:103E0000020200F4000000040202000400000001AD +:103E100002020008000000010202000C0000000184 +:103E20000202001000000001020200140000000164 +:103E300002020018000000010202001C0000000144 +:103E40000202002000000001020200240000000124 +:103E500002020028000000010202002C0000000104 +:103E600002020030000000010202003400000001E4 +:103E700002020038000000010202003C00000001C4 +:103E800002020040000000010202004400000001A4 +:103E900002020048000000010202004C0000000184 +:103EA000020200500000000102020108000000C8E8 +:103EB0000202011800000002020201C4000000001A +:103EC000020201CC00000000020201D40000000246 +:103ED000020201DC00000002020201E4000000FF17 +:103EE000020201EC000000FF0202010000000000DD +:103EF0000202010C000000C80202011C00000002C6 +:103F0000020201C800000000020201D0000000000F +:103F1000020201D800000002020201E000000002DB +:103F2000020201E8000000FF020201F0000000FFB1 +:103F3000020201040000000002020108000000C8A3 +:103F40000202011800000002020201C40000000089 +:103F5000020201CC00000000020201D400000002B5 +:103F6000020201DC00000002020201E4000000FF86 +:103F7000020201EC000000FF02020100000000004C +:103F80000202010C000000C80202011C0000000235 +:103F9000020201C800000000020201D0000000007F +:103FA000020201D800000002020201E0000000024B +:103FB000020201E8000000FF020201F0000000FF21 +:103FC000020201040000000002020108000000C813 +:103FD0000202011800000002020201C400000000F9 +:103FE000020201CC00000000020201D40000000225 +:103FF000020201DC00000002020201E4000000FFF6 +:10400000020201EC000000FF0202010000000000BB +:104010000202010C000000C80202011C00000002A4 +:10402000020201C800000000020201D000000000EE +:10403000020201D800000002020201E000000002BA +:10404000020201E8000000FF020201F0000000FF90 +:10405000020201040000000002020108000000C882 +:104060000202011800000002020201C40000000068 +:10407000020201CC00000000020201D40000000294 +:10408000020201DC00000002020201E4000000FF65 +:10409000020201EC000000FF02020100000000002B +:1040A0000202010C000000C80202011C0000000214 +:1040B000020201C800000000020201D0000000005E +:1040C000020201D800000002020201E0000000022A +:1040D000020201E8000000FF020201F0000000FF00 +:1040E00002020104000000000728040000A30000F1 +:1040F000082807B8000904CA072C000034F10000A2 +:10410000072C800038A60D3D072D000037B61B6731 +:10411000072D800032632955072E00001C6835EEFC +:10412000082E48B036EA04CC012800000000000048 +:104130000128000400000000012800080000000021 +:104140000128000C00000000012800100000000001 +:1041500001280014000000000228002000000001D7 +:1041600002280024000000020228002800000003AA +:104170000228002C0000000002280030000000048B +:10418000022800340000000102280038000000006E +:104190000228003C0000000102280040000000044A +:1041A000022800440000000002280048000000012E +:1041B0000228004C0000000302280050000000000C +:1041C00002280054000000010228005800000004EA +:1041D0000228005C000000000228006000000001CE +:1041E00002280064000000030228006800000000AC +:1041F0000228006C0000000102280070000000048A +:10420000022800740000000002280078000000046A +:104210000228007C00000003062800800000000245 +:10422000022800A400003FFF022800A8000003FFAE +:1042300002280224000000000228023400000000CE +:104240000228024C00000000022802E40000FFFFE8 +:104250000628200000000800022B8BC0000000018F +:10426000022B800000000000022B8040000000189C +:10427000022B80800000000C022B80C00000006632 +:104280000C2B83000007A1200A2B830000000138BB +:104290000B2B8300000013880A2B834000000000D2 +:1042A0000C2B8340000001F40B2B83400000000521 +:1042B000022B83800007A120022B83C0000001F4A1 +:1042C000022B1480000000010A2B14800000000063 +:1042D000062A9AF800000004042A9B08000204CE73 +:1042E000062A9B1000000006062A90800000004865 +:1042F000062A2008000000C8062A2000000000024C +:10430000062A91A800000086062A900000000020DE +:10431000062A93C800000003042A93D4000104D0A5 +:10432000062A9DA800000002042A9498000404D1E3 +:10433000042A9D58000104D5062A9D5C0000001146 +:10434000042ACB20001004D6042A3000000204E620 +:10435000062A300800000100062A40400000001034 +:10436000042A4000001004E8042A8408000204F82B +:10437000062A9DA000000002062AB000000000509E +:10438000062ABB7000000070062AB150000000022F +:10439000062ABB6000000004062AD00000000800C6 +:1043A000062AC00000000150062A94A8000000322E +:1043B000062A502000000002062A503000000002A9 +:1043C000062A500000000002062A501000000002D9 +:1043D000022A520800000001042A9B28000204FA65 +:1043E000062A963800000022042A96C0000104FC28 +:1043F000062A96C400000003062A976800000022DF +:10440000042A97F0000104FD062A97F40000000337 +:10441000062A989800000022042A9920000104FE30 +:10442000062A992400000003062A99C800000022E9 +:10443000042A9A50000104FF062A9A54000000033F +:10444000062AB14000000002062AC54000000150C3 +:10445000062A957000000032062A5028000000024B +:10446000062A503800000002062A50080000000208 +:10447000062A501800000002022A520C0000000117 +:10448000042A9B3000020500062A96D00000002274 +:10449000042A975800010502062A975C00000003D1 +:1044A000062A980000000022042A988800010503CB +:1044B000062A988C00000003062A9930000000228A +:1044C000042A99B800010504062A99BC00000003DB +:1044D000062A9A6000000022042A9AE800010505D5 +:1044E000062A9AEC00000003062AB14800000002E8 +:1044F000022ACA8000000000042A9B38001005062A +:10450000062A50480000000E022ACA84000000005B +:10451000042A9B7800100516062A50800000000E21 +:10452000022ACA8800000000042A9BB80010052651 +:10453000062A50B80000000E022ACA8C00000000B3 +:10454000042A9BF800100536062A50F00000000EE1 +:10455000022ACA9000000000042A9C380010054678 +:10456000062A51280000000E022ACA94000000000A +:10457000042A9C7800100556062A51600000000E9F +:10458000022ACA9800000000042A9CB800100566A0 +:10459000062A51980000000E022ACA9C0000000062 +:1045A000042A9CF800100576062A51D00000000E5F +:1045B000021010080000000102101050000000015D +:1045C000021010000003D000021010040000003D93 +:1045D0000910180002000586091011000010078656 +:1045E0000610114000000008091011600010079625 +:1045F000061011A00000001806102400000000E0C2 +:104600000210201C00000000021020200000000109 +:10461000021020C00000000202102004000000016F +:10462000021020080000000109103C00000507A648 +:1046300009103800000507AB09103820000507B045 +:1046400006104C000000010002104028000000107D +:104650000210404400003FFF0210405800280000B4 +:10466000021040840084924A02104058000000006A +:104670000210800000001080021080AC00000000DA +:1046800002108038000000100210810000000000BD +:10469000061081200000000202108008000002B510 +:1046A0000210801000000000061082000000004A86 +:1046B000021081080001FFFF061081400000000287 +:1046C0000210800000001A800610900000000024F4 +:1046D000061091200000004A061093700000004A66 +:1046E000061095C00000004A0210800400001080EF +:1046F000021080B0000000010210803C0000001099 +:104700000210810400000000061081280000000251 +:104710000210800C000002B502108014000000009E +:10472000061084000000004A0210810C0001FFFF07 +:1047300006108148000000020210800400001A8068 +:104740000610909000000024061092480000004AD5 +:10475000061094980000004A061096E80000004AEF +:104760000210800000001080021080AC00000002E7 +:1047700002108038000000100210810000000000CC +:10478000061081200000000202108008000002B51F +:104790000210801000000000061082000000004A95 +:1047A000021081080001FFFF061081400000000296 +:1047B0000210800000001A80061090000000002403 +:1047C000061091200000004A061093700000004A75 +:1047D000061095C00000004A0210800400001080FE +:1047E000021080B0000000030210803C00000010A6 +:1047F0000210810400000000061081280000000261 +:104800000210800C000002B50210801400000000AD +:10481000061084000000004A0210810C0001FFFF16 +:1048200006108148000000020210800400001A8077 +:104830000610909000000024061092480000004AE4 +:10484000061094980000004A061096E80000004AFE +:104850000210800000001080021080AC00000004F4 +:1048600002108038000000100210810000000000DB +:10487000061081200000000202108008000002B52E +:104880000210801000000000061082000000004AA4 +:10489000021081080001FFFF0610814000000002A5 +:1048A0000210800000001A80061090000000002412 +:1048B000061091200000004A061093700000004A84 +:1048C000061095C00000004A02108004000010800D +:1048D000021080B0000000050210803C00000010B3 +:1048E0000210810400000000061081280000000270 +:1048F0000210800C000002B50210801400000000BD +:10490000061084000000004A0210810C0001FFFF25 +:1049100006108148000000020210800400001A8086 +:104920000610909000000024061092480000004AF3 +:10493000061094980000004A061096E80000004A0D +:104940000210800000001080021080AC0000000601 +:1049500002108038000000100210810000000000EA +:10496000061081200000000202108008000002B53D +:104970000210801000000000061082000000004AB3 +:10498000021081080001FFFF0610814000000002B4 +:104990000210800000001A80061090000000002421 +:1049A000061091200000004A061093700000004A93 +:1049B000061095C00000004A02108004000010801C +:1049C000021080B0000000070210803C00000010C0 +:1049D000021081040000000006108128000000027F +:1049E0000210800C000002B50210801400000000CC +:1049F000061084000000004A0210810C0001FFFF35 +:104A000006108148000000020210800400001A8095 +:104A10000610909000000024061092480000004A02 +:104A2000061094980000004A061096E80000004A1C +:104A3000021205B0000000010212049000E383405E +:104A40000212051400003C100212066C0000000166 +:104A5000021206700000000002120494FFFFFFFF24 +:104A600002120498FFFFFFFF0212049CFFFFFFFFEA +:104A7000021204A0FFFFFFFF021204A4FFFFFFFFCA +:104A8000021204A8FFFFFFFF021204ACFFFFFFFFAA +:104A9000021204B0FFFFFFFF021204BCFFFFFFFF82 +:104AA000021204C0FFFFFFFF021204C4FFFFFFFF5A +:104AB000021204C8FFFFFFFF021204CCFFFFFFFF3A +:104AC000021204D0FFFFFFFF021204D8FFFFFFFF16 +:104AD000021204DCFFFFFFFF021204E0FFFFFFFFF2 +:104AE000021204E4FFFFFFFF021204E8FFFFFFFFD2 +:104AF000021204ECFFFFFFFF021204F0FFFFFFFFB2 +:104B0000021204F4FFFFFFFF021204F8FFFFFFFF91 +:104B1000021204FCFFFFFFFF02120500FFFFFFFF70 +:104B200002120504FFFFFFFF02120508FFFFFFFF4F +:104B30000212050CFFFFFFFF02120510FFFFFFFF2F +:104B4000021204D4FF809000021204B4F00050005E +:104B5000021204B8F00010000212039000000008D6 +:104B60000212039C00000008021203A000000008CB +:104B7000021203A400000002021203BC00000004A1 +:104B8000021203C000000005021203C4000000046A +:104B9000021203D0000000000212036C00000001AA +:104BA000021203680000003F021201BC0000004036 +:104BB000021201C000001808021201C4000008031C +:104BC000021201C800000803021201CC00000040DC +:104BD000021201D000000003021201D400000803F9 +:104BE000021201D800000803021201DC00000803D1 +:104BF000021201E000010003021201E400000803B8 +:104C0000021201E800000803021201EC0000000398 +:104C1000021201F000000003021201F40000000380 +:104C2000021201F800000003021201FC0000000360 +:104C3000021202000000000302120204000000033E +:104C400002120208000000030212020C000000031E +:104C500002120210000000030212021400000003FE +:104C600002120218000000030212021C00000003DE +:104C700002120220000000030212022400000003BE +:104C800002120228000024030212022C0000002F4E +:104C90000212023000000009021202340000001962 +:104CA00002120238000001840212023C000001835B +:104CB0000212024000000306021202440000001922 +:104CC00002120248000000060212024C0000030615 +:104CD00002120250000003060212025400000306F2 +:104CE0000212025800000C860212025C0000030649 +:104CF00002120260000003060212026400000006B5 +:104D000002120268000000060212026C0000000697 +:104D10000212027000000006021202740000000677 +:104D200002120278000000060212027C0000000657 +:104D30000212028000000006021202840000000637 +:104D400002120288000000060212028C0000000617 +:104D500002120290000000060212029400000006F7 +:104D600002120298000000060212029C00000006D7 +:104D7000021202A000000306021202A400000013A7 +:104D8000021202A800000006021202B00000100485 +:104D9000021202B400001004021203240010644046 +:104DA0000212032800106440021205B40000000142 +:104DB000021201B0000000010600A0000000000C7B +:104DC0000200A050000000000200A05400000000FB +:104DD0000200A0EC555400000200A0F055555555B6 +:104DE0000200A0F4000055550200A0F8F0000000F9 +:104DF0000200A0FC555400000200A1005555555575 +:104E00000200A104000055550200A108F0000000B6 +:104E10000200A18C555400000200A1905555555533 +:104E20000200A194000055550200A198F000000076 +:104E30000200A19C000000000200A1A000010000EF +:104E40000200A1A4000050140200A1A8000000006C +:104E50000200A45C00000C000200A61C000000037D +:104E60000200A06CFF5C00000200A070FFF55FFF75 +:104E70000200A0740000FFFF0200A078F00003E031 +:104E80000200A07C000000000200A0800000A00042 +:104E90000600A084000000050200A0980FE00000BA +:104EA0000600A09C000000070200A0B8000004005B +:104EB0000600A0BC000000030200A0C80000100013 +:104EC0000600A0CC000000030200A0D800004000B3 +:104ED0000600A0DC000000030200A0E800010000C2 +:104EE0000600A22C000000040200A10CFF5C0000E0 +:104EF0000200A110FFF55FFF0200A1140000FFFFF8 +:104F00000200A118F00003E00200A11C0000000054 +:104F10000200A1200000A0000600A124000000055E +:104F20000200A1380FE000000600A13C00000007CD +:104F30000200A158000008000600A15C0000000368 +:104F40000200A168000020000600A16C0000000320 +:104F50000200A178000080000600A17C0000000390 +:104F60000200A188000200000600A23C000000042C +:104F70000200A030000000000200A0340000000089 +:104F80000200A038000000000200A03C0000000069 +:104F90000200A040000000000200A0440000000049 +:104FA0000200A048000000000200A04C0000000029 +:104FB00000000000000000000000003000000000C1 +:104FC00000000000000000000000000000000000E1 +:104FD00000000000000000000000000000000000D1 +:104FE0000000000000300031000000000000000060 +:104FF00000000000000000000000000000000000B1 +:1050000000000000000000000000000000000000A0 +:10501000003100520000000000000000000000000D +:105020000000000000000000000000000000000080 +:105030000000000000000000000000000052008995 +:1050400000000000000000000089008D008D00912C +:1050500000910095009500990099009D009D00A188 +:1050600000A100A500A500A900A900AE00AE00B1F6 +:1050700000B100B4000000000000000000000000CB +:105080000000000000000000000000000000000020 +:105090000000000000B40309030903130313031DF8 +:1050A000031D03240324032B032B03320332033990 +:1050B00003390340034003470347034E034E0355A0 +:1050C00000000000000000000000000000000000E0 +:1050D00000000000000000000000000000000000D0 +:1050E00000000000000000000000000000000000C0 +:1050F00000000000000000000000000000000000B0 +:10510000000000000000000000000000000000009F +:10511000000000000000000000000000000000008F +:10512000000000000000000000000000000000007F +:10513000000000000000000000000000000000006F +:10514000000000000000000000000000000000005F +:10515000000000000000000000000000000000004F +:10516000000000000000000000000000000000003F +:105170000355035B0000000000000000035B035CBC +:10518000035C035D035D035E035E035F035F036017 +:1051900003600361036103620362036300000000B4 +:1051A00000000000000000000000000000000000FF +:1051B00000000000000000000000000000000000EF +:1051C00000000000000000000363036D036D037B1B +:1051D000037B0389000000000000000000000000C5 +:1051E00000000000000000000000000000000000BF +:1051F00000000000000000000000000000000000AF +:10520000000000000000000000000000000000009E +:10521000000000000000000000000000000000008E +:105220000389038A00000000000000000000000065 +:10523000000000000000000000000000000000006E +:10524000000000000000000000000000038A03D6F8 +:10525000000000000000000000000000000000004E +:10526000000000000000000000000000000000003E +:10527000000000000000000003D604010000000050 +:10528000000000000000000000000000000000001E +:10529000000000000000000000000000000000000E +:1052A00000000000040104330000000000000000C2 +:1052B0000433043A043A0441044104480448044FC6 +:1052C000044F04560456045D045D04640464046BD6 +:1052D000046B04A4000000000000000004A404A863 +:1052E00004A804AC04AC04B004B004B404B404B81E +:1052F00004B804BC04BC04C004C004C404C4051342 +:105300000513052A052A05410541054305430545C1 +:1053100005450547054705490549054B054B054D1D +:10532000054D054F054F0551055105E805E805E90F +:1053300005E905EA05EA05EF05EF05F405F405F9C9 +:1053400005F905FE05FE0603060306080608060D18 +:10535000060D0612061206130000000000000000F1 +:10536000000000000000000000000000000000003D +:10537000000000000000000000000000000000002D +:1053800006130624000000000000000000000000DA +:10539000000000000000000000000000000000000D +:1053A0000000000000000000000000000624063994 +:1053B0000639063C063C063F0000000000000000E5 +:1053C00000000000000000000000000000000000DD +:1053D0000000000000000000063F0675000000000D +:1053E00000000000000000000000000000000000BD +:1053F00000000000000000000000000000000000AD +:1054000000000000067507780000000000000000A2 +:10541000000000000000000000000000000000008C +:10542000000000000000000000000000000000007C +:105430000778077F077F078307830787000000003F +:10544000000000000000000000000000000000005C +:10545000000000000000000000000000078707C8EF +:10546000000000000000000007C807D107D107DADC +:1054700007DA07E307E307EC07EC07F507F507FE94 +:1054800007FE080708070810081008670867087C67 +:10549000087C089108910894089408970897089A3E +:1054A000089A089D089D08A008A008A308A308A6BC +:1054B00008A608A908A908B2000000000000000022 +:1054C00000000000000000000000000000000000DC +:1054D00000000000000000000000000000000000CC +:1054E00008B208B800000000000000000000000042 +:1054F00000000000000000000000000000000000AC +:1055000000000000000000000000000008B808BB18 +:10551000000000000000000000000000000000008B +:10552000000000000000000000000000000000007B +:10553000000000000000000008BB08C100000000DF +:10554000000000000000000000000000000000005B +:10555000000000000000000000000000000000004B +:10556000000000000000000000000000000000003B +:1055700008C108D008D008DF08DF08EE08EE08FDF3 +:1055800008FD090C090C091B091B092A092A0939FC +:10559000093909AA00000000000000000000000016 +:1055A00000000000000000000000000000000000FB +:1055B00000000000000000000000000009AA09BF70 +:1055C00009BF09D009D009E109E109E209E209E3CB +:1055D00009E309E409E409E509E509E609E609E75B +:1055E00009E709E809E809E90000000000000000F7 +:1055F00000000000000000000000000000000000AB +:10560000000000000000000000000000000000009A +:10561000000000000000000000000000000000008A +:10562000000000000000000000000000000000007A +:10563000000000000000000000000000000000006A +:10564000000000000000000000000000000000005A +:10565000000000000000000000000000000000004A +:10566000000000000000000000000000000000003A +:10567000000000000000000000000000000000002A +:10568000000000000000000000000000000000001A +:10569000000000000000000000000000000000000A +:1056A00000000000000000000000000000000000FA +:1056B00000000000000000000000000000000000EA +:1056C000000000000000000000010000000204C013 +:1056D0000003098000040E4000051300000617C0F7 +:1056E00000071C800008214000092600000A2AC08B +:1056F000000B2F80000C3440000D3900000E3DC01F +:10570000000F42800010474000114C00001250C0B2 +:105710000013558000145A4000155F00001663C046 +:105720000017688000186D4000197200001A76C0DA +:10573000001B7B80001C8040001D8500001E89C06E +:10574000001F8E80000093400000200000004000F9 +:1057500000006000000080000000A0000000C00009 +:105760000000E000000100000001200000014000F6 +:1057700000016000000180000001A0000001C000E5 +:105780000001E000000200000002200000024000D2 +:1057900000026000000280000002A0000002C000C1 +:1057A0000002E000000300000003200000034000AE +:1057B00000036000000380000003A0000003C0009D +:1057C0000003E0000004000000042000000440008A +:1057D00000046000000480000004A0000004C00079 +:1057E0000004E00000050000000520000005400066 +:1057F00000056000000580000005A0000005C00055 +:105800000005E00000060000000620000006400041 +:1058100000066000000680000006A0000006C00030 +:105820000006E0000007000000072000000740001D +:1058300000076000000780000007A0000007C0000C +:105840000007E000000800000008200000084000F9 +:1058500000086000000880000008A0000008C000E8 +:105860000008E000000900000009200000094000D5 +:1058700000096000000980000009A0000009C000C4 +:105880000009E000000A0000000A2000000A4000B1 +:10589000000A6000000A8000000AA000000AC000A0 +:1058A000000AE000000B0000000B2000000B40008D +:1058B000000B6000000B8000000BA000000BC0007C +:1058C000000BE000000C0000000C2000000C400069 +:1058D000000C6000000C8000000CA000000CC00058 +:1058E000000CE000000D0000000D2000000D400045 +:1058F000000D6000000D8000000DA000000DC00034 +:10590000000DE000000E0000000E2000000E400020 +:10591000000E6000000E8000000EA000000EC0000F +:10592000000EE000000F0000000F2000000F4000FC +:10593000000F6000000F8000000FA000000FC000EB +:10594000000FE000001000000010200000104000D8 +:1059500000106000001080000010A0000010C000C7 +:105960000010E000001100000011200000114000B4 +:1059700000116000001180000011A0000011C000A3 +:105980000011E00000120000001220000012400090 +:1059900000126000001280000012A0000012C0007F +:1059A0000012E0000013000000132000001340006C +:1059B00000136000001380000013A0000013C0005B +:1059C0000013E00000140000001420000014400048 +:1059D00000146000001480000014A0000014C00037 +:1059E0000014E00000150000001520000015400024 +:1059F00000156000001580000015A0000015C00013 +:105A00000015E000001600000016200000164000FF +:105A100000166000001680000016A0000016C000EE +:105A20000016E000001700000017200000174000DB +:105A300000176000001780000017A0000017C000CA +:105A40000017E000001800000018200000184000B7 +:105A500000186000001880000018A0000018C000A6 +:105A60000018E00000190000001920000019400093 +:105A700000196000001980000019A0000019C00082 +:105A80000019E000001A0000001A2000001A40006F +:105A9000001A6000001A8000001AA000001AC0005E +:105AA000001AE000001B0000001B2000001B40004B +:105AB000001B6000001B8000001BA000001BC0003A +:105AC000001BE000001C0000001C2000001C400027 +:105AD000001C6000001C8000001CA000001CC00016 +:105AE000001CE000001D0000001D2000001D400003 +:105AF000001D6000001D8000001DA000001DC000F2 +:105B0000001DE000001E0000001E2000001E4000DE +:105B1000001E6000001E8000001EA000001EC000CD +:105B2000001EE000001F0000001F2000001F4000BA +:105B3000001F6000001F8000001FA000001FC000A9 +:105B4000001FE00000200000002020000020400096 +:105B500000206000002080000020A0000020C00085 +:105B60000020E00000210000002120000021400072 +:105B700000216000002180000021A0000021C00061 +:105B80000021E0000022000000222000002240004E +:105B900000226000002280000022A0000022C0003D +:105BA0000022E0000023000000232000002340002A +:105BB00000236000002380000023A0000023C00019 +:105BC0000023E00000240000002420000024400006 +:105BD00000246000002480000024A0000024C000F5 +:105BE0000024E000002500000025200000254000E2 +:105BF00000256000002580000025A0000025C000D1 +:105C00000025E000002600000026200000264000BD +:105C100000266000002680000026A0000026C000AC +:105C20000026E00000270000002720000027400099 +:105C300000276000002780000027A0000027C00088 +:105C40000027E00000280000002820000028400075 +:105C500000286000002880000028A0000028C00064 +:105C60000028E00000290000002920000029400051 +:105C700000296000002980000029A0000029C00040 +:105C80000029E000002A0000002A2000002A40002D +:105C9000002A6000002A8000002AA000002AC0001C +:105CA000002AE000002B0000002B2000002B400009 +:105CB000002B6000002B8000002BA000002BC000F8 +:105CC000002BE000002C0000002C2000002C4000E5 +:105CD000002C6000002C8000002CA000002CC000D4 +:105CE000002CE000002D0000002D2000002D4000C1 +:105CF000002D6000002D8000002DA000002DC000B0 +:105D0000002DE000002E0000002E2000002E40009C +:105D1000002E6000002E8000002EA000002EC0008B +:105D2000002EE000002F0000002F2000002F400078 +:105D3000002F6000002F8000002FA000002FC00067 +:105D4000002FE00000300000003020000030400054 +:105D500000306000003080000030A0000030C00043 +:105D60000030E00000310000003120000031400030 +:105D700000316000003180000031A0000031C0001F +:105D80000031E0000032000000322000003240000C +:105D900000326000003280000032A0000032C000FB +:105DA0000032E000003300000033200000334000E8 +:105DB00000336000003380000033A0000033C000D7 +:105DC0000033E000003400000034200000344000C4 +:105DD00000346000003480000034A0000034C000B3 +:105DE0000034E000003500000035200000354000A0 +:105DF00000356000003580000035A0000035C0008F +:105E00000035E0000036000000362000003640007B +:105E100000366000003680000036A0000036C0006A +:105E20000036E00000370000003720000037400057 +:105E300000376000003780000037A0000037C00046 +:105E40000037E00000380000003820000038400033 +:105E500000386000003880000038A0000038C00022 +:105E60000038E0000039000000392000003940000F +:105E700000396000003980000039A0000039C000FE +:105E80000039E000003A0000003A2000003A4000EB +:105E9000003A6000003A8000003AA000003AC000DA +:105EA000003AE000003B0000003B2000003B4000C7 +:105EB000003B6000003B8000003BA000003BC000B6 +:105EC000003BE000003C0000003C2000003C4000A3 +:105ED000003C6000003C8000003CA000003CC00092 +:105EE000003CE000003D0000003D2000003D40007F +:105EF000003D6000003D8000003DA000003DC0006E +:105F0000003DE000003E0000003E2000003E40005A +:105F1000003E6000003E8000003EA000003EC00049 +:105F2000003EE000003F0000003F2000003F400036 +:105F3000003F6000003F8000003FA000003FC00025 +:105F4000003FE000003FE00100000000000001FF12 +:105F50000000020000007FF800007FF80000014010 +:105F600000003500000000010000FF0000000000FC +:105F70000000FF00000000000000FF000000000023 +:105F80000000FF00000000000000FF000000000013 +:105F90000000FF00000000000000FF000000000003 +:105FA0000000FF000000000000000000140AFF00D5 +:105FB00000000001000000000020100100000000AF +:105FC0000100900000000100000090020000900419 +:105FD00000009006000090080000900A0000900C5D +:105FE0000000900E0000901000009012000090142D +:105FF00000009016000090180000901A0000901CFD +:106000000000901E000090200000902200009024CC +:1060100000009026000090280000902A0000902C9C +:106020000000902E0000903000009032000090346C +:1060300000009036000090380000903A0000903C3C +:106040000000903E0000904000009042000090440C +:1060500000009046000090480000904A0000904CDC +:106060000000904E000090500000905200009054AC +:1060700000009056000090580000905A0000905C7C +:106080000000905E0000906000009062000090644C +:1060900000009066000090680000906A0000906C1C +:1060A0000000906E000090700000907200009074EC +:1060B00000009076000090780000907A0000907CBC +:1060C0000000907E0000908000009082000090848C +:1060D00000009086000090880000908A0000908C5C +:1060E0000000908E0000909000009092000090942C +:1060F00000009096000090980000909A0000909CFC +:106100000000909E000090A0000090A2000090A4CB +:10611000000090A6000090A8000090AA000090AC9B +:10612000000090AE000090B0000090B2000090B46B +:10613000000090B6000090B8000090BA000090BC3B +:10614000000090BE000090C0000090C2000090C40B +:10615000000090C6000090C8000090CA000090CCDB +:10616000000090CE000090D0000090D2000090D4AB +:10617000000090D6000090D8000090DA000090DC7B +:10618000000090DE000090E0000090E2000090E44B +:10619000000090E6000090E8000090EA000090EC1B +:1061A000000090EE000090F0000090F2000090F4EB +:1061B000000090F6000090F8000090FA000090FCBB +:1061C000000090FE00009100000091020000910488 +:1061D00000009106000091080000910A0000910C57 +:1061E0000000910E00009110000091120000911427 +:1061F00000009116000091180000911A0000911CF7 +:106200000000911E000091200000912200009124C6 +:1062100000009126000091280000912A0000912C96 +:106220000000912E00009130000091320000913466 +:1062300000009136000091380000913A0000913C36 +:106240000000913E00009140000091420000914406 +:1062500000009146000091480000914A0000914CD6 +:106260000000914E000091500000915200009154A6 +:1062700000009156000091580000915A0000915C76 +:106280000000915E00009160000091620000916446 +:1062900000009166000091680000916A0000916C16 +:1062A0000000916E000091700000917200009174E6 +:1062B00000009176000091780000917A0000917CB6 +:1062C0000000917E00009180000091820000918486 +:1062D00000009186000091880000918A0000918C56 +:1062E0000000918E00009190000091920000919426 +:1062F00000009196000091980000919A0000919CF6 +:106300000000919E000091A0000091A2000091A4C5 +:10631000000091A6000091A8000091AA000091AC95 +:10632000000091AE000091B0000091B2000091B465 +:10633000000091B6000091B8000091BA000091BC35 +:10634000000091BE000091C0000091C2000091C405 +:10635000000091C6000091C8000091CA000091CCD5 +:10636000000091CE000091D0000091D2000091D4A5 +:10637000000091D6000091D8000091DA000091DC75 +:10638000000091DE000091E0000091E2000091E445 +:10639000000091E6000091E8000091EA000091EC15 +:1063A000000091EE000091F0000091F2000091F4E5 +:1063B000000091F6000091F8000091FA000091FCB5 +:1063C000000091FEFFFFFFFFFFFFFFFFFFFFFFFF4A +:1063D000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFCD +:1063E000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFBD +:1063F000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFAD +:10640000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF9C +:10641000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF8C +:10642000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7C +:10643000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF6C +:10644000FFFFFFFF0000000300BEBC2000000000B3 +:10645000000000050000000300BEBC20000000009A +:10646000000000050000000300BEBC20000000008A +:10647000000000050000000300BEBC20000000007A +:10648000000000050000000300BEBC20000000006A +:10649000000000050000000300BEBC20000000005A +:1064A000000000050000000300BEBC20000000004A +:1064B000000000050000000300BEBC20000000003A +:1064C0000000000500002000000040C000006180C6 +:1064D000000082400000A3000000C3C00000E48070 +:1064E0000001054000012600000146C00001678050 +:1064F000000188400001A9000001C9C00001EA8034 +:1065000000020B4000022C0000024CC000026D8013 +:1065100000028E400002AF000002CFC00002F080F7 +:10652000000011400000800000010380000187008E +:1065300000020A8000028E00000311800003950013 +:106540000004188000049C0000051F800005A300C3 +:10655000000626800006AA0000072D800007B10073 +:10656000000834800008B80000093B800009BF0023 +:10657000000A4280000AC600000B4980000BCD00D3 +:10658000000C5080000CD400000D578000005B0010 +:1065900000007FF800007FF8000000D50000150023 +:1065A0000000FF00000000000000FF0000000000ED +:1065B0000000FF00000000000000FF0000000000DD +:1065C0000000FF00000000000000FF0000000000CD +:1065D0000000FF00000000000000FF0000000000BD +:1065E000000019000000000000000000FFFFFFFF96 +:1065F0000000000003938700000000000393870061 +:1066000000007FF800007FF80000068E00003500D3 +:106610000000FF000FFFFFFF0000FF000FFFFFFF64 +:10662000000000FF0000FF000FFFFFFF0000FF0061 +:106630000FFFFFFF000000FF0000FF000FFFFFFF44 +:106640000000FF000FFFFFFF000000FF0000FF0041 +:106650000FFFFFFF0000FF000FFFFFFF000000FF24 +:106660000000FF000FFFFFFF0000FF000FFFFFFF14 +:10667000000000FF0000FF000FFFFFFF0000FF0011 +:106680000FFFFFFF000000FF0000FF000FFFFFFFF4 +:106690000000FF000FFFFFFF000000FF0000FF00F1 +:1066A0000FFFFFFF0000FF000FFFFFFF000000FFD4 +:1066B0000000FF000FFFFFFF0000FF000FFFFFFFC4 +:1066C000000000FF0000FF000FFFFFFF0000FF00C1 +:1066D0000FFFFFFF000000FF0000FF000FFFFFFFA4 +:1066E0000000FF000FFFFFFF000000FF0000FF00A1 +:1066F0000FFFFFFF0000FF000FFFFFFF000000FF84 +:106700000000FF000FFFFFFF0000FF000FFFFFFF73 +:10671000000000FF0000FF000FFFFFFF0000FF0070 +:106720000FFFFFFF000000FF0000FF000FFFFFFF53 +:106730000000FF000FFFFFFF000000FF0000FF0050 +:106740000FFFFFFF0000FF000FFFFFFF000000FF33 +:106750000000FF000FFFFFFF0000FF000FFFFFFF23 +:10676000000000FF0000FF000FFFFFFF0000FF0020 +:106770000FFFFFFF000000FF0000FF000FFFFFFF03 +:106780000000FF000FFFFFFF000000FF0000FF0000 +:106790000FFFFFFF0000FF000FFFFFFF000000FFE3 +:1067A0000000FF000FFFFFFF0000FF000FFFFFFFD3 +:1067B000000000FF0000FF000FFFFFFF0000FF00D0 +:1067C0000FFFFFFF000000FF0000FF000FFFFFFFB3 +:1067D0000000FF000FFFFFFF000000FF0000FF00B0 +:1067E0000FFFFFFF0000FF000FFFFFFF000000FF93 +:1067F0000000FF000FFFFFFF0000FF000FFFFFFF83 +:10680000000000FF0000FF000FFFFFFF0000FF007F +:106810000FFFFFFF000000FF0000FF000FFFFFFF62 +:106820000000FF000FFFFFFF000000FF0000FF005F +:106830000FFFFFFF0000FF000FFFFFFF000000FF42 +:106840000000FF000FFFFFFF0000FF000FFFFFFF32 +:10685000000000FF0000FF000FFFFFFF0000FF002F +:106860000FFFFFFF000000FF0000FF000FFFFFFF12 +:106870000000FF000FFFFFFF000000FF0000FF000F +:106880000FFFFFFF0000FF000FFFFFFF000000FFF2 +:10689000000000FF000000FF000000FF000000FFFC +:1068A000000000FF000000FF000000FF000000FFEC +:1068B0000000FF00000000000000FF0000000000DA +:1068C0000000FF00000000000000FF0000000000CA +:1068D0000000FF00000000000000FF0000000000BA +:1068E0000000FF00000000000000FF0000000000AA +:1068F000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA8 +:10690000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF97 +:10691000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF87 +:10692000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF77 +:10693000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF67 +:10694000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF57 +:10695000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF47 +:10696000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF37 +:106970000000100000002080000031000000418075 +:10698000000052000000628000007300000083805D +:10699000000094000000A4800000B5000000C58045 +:1069A0000000D6000000E6800000F700000107802C +:1069B0000001180000012880000139000001498011 +:1069C00000015A0000016A8000017B0000018B80F9 +:1069D00000019C000001AC800001BD000001CD80E1 +:1069E0000001DE000001EE800001FF0000000F80CA +:1069F00000007FF800007FF800000344000035002D +:106A000010000000000028AD00010001000902068E +:106A1000CCCCCCC5FFFFFFFFFFFFFFFF7058103C41 +:106A20000000FF00000000000000FF000000000068 +:106A30000000FF00000000000000FF000000000058 +:106A40000000FF00000000000000FF000000000048 +:106A50000000FF00000000000000FF000000000038 +:106A60000000000000000001CCCC0201CCCCCCCC5A +:106A7000CCCC0201CCCCCCCCCCCC0201CCCCCCCC80 +:106A8000CCCC0201CCCCCCCCCCCC0201CCCCCCCC70 +:106A9000CCCC0201CCCCCCCCCCCC0201CCCCCCCC60 +:106AA000CCCC0201CCCCCCCC00000000FFFFFFFF1F +:106AB000000E0000011600D6002625A0002625A005 +:106AC000002625A0002625A000720000012300F367 +:106AD000002625A0002625A0002625A0002625A00A +:106AE0000000FFFF000000000000FFFF00000000AA +:106AF0000000FFFF000000000000FFFF000000009A +:106B00000000FFFF000000000000FFFF0000000089 +:106B10000000FFFF000000000000FFFF0000000079 +:106B20000000FFFF000000000000FFFF0000000069 +:106B30000000FFFF000000000000FFFF0000000059 +:106B40000000FFFF000000000000FFFF0000000049 +:106B50000000FFFF000000000000FFFF0000000039 +:106B60000000FFFF000000000000FFFF0000000029 +:106B70000000FFFF000000000000FFFF0000000019 +:106B80000000FFFF000000000000FFFF0000000009 +:106B90000000FFFF000000000000FFFF00000000F9 +:106BA0000000FFFF000000000000FFFF00000000E9 +:106BB0000000FFFF000000000000FFFF00000000D9 +:106BC0000000FFFF000000000000FFFF00000000C9 +:106BD0000000FFFF000000000000FFFF00000000B9 +:106BE0000000FFFF000000000000FFFF00000000A9 +:106BF0000000FFFF000000000000FFFF0000000099 +:106C00000000FFFF000000000000FFFF0000000088 +:106C10000000FFFF000000000000FFFF0000000078 +:106C20000000FFFF000000000000FFFF0000000068 +:106C30000000FFFF000000000000FFFF0000000058 +:106C40000000FFFF000000000000FFFF0000000048 +:106C50000000FFFF000000000000FFFF0000000038 +:106C60000000FFFF000000000000FFFF0000000028 +:106C70000000FFFF000000000000FFFF0000000018 +:106C80000000FFFF000000000000FFFF0000000008 +:106C90000000FFFF000000000000FFFF00000000F8 +:106CA0000000FFFF000000000000FFFF00000000E8 +:106CB0000000FFFF000000000000FFFF00000000D8 +:106CC0000000FFFF000000000000FFFF00000000C8 +:106CD0000000FFFF000000000000FFFF00000000B8 +:106CE000FFFFFFF3318FFFFF0C30C30CC30C30C329 +:106CF000CF3CF300F3CF3CF30000CF3CCDCDCDCD66 +:106D0000FFFFFFF130EFFFFF0C30C30CC30C30C3AB +:106D1000CF3CF300F3CF3CF30001CF3CCDCDCDCD44 +:106D2000FFFFFFF6305FFFFF0C30C30CC30C30C316 +:106D3000CF3CF300F3CF3CF30002CF3CCDCDCDCD23 +:106D4000FFFFF4061CBFFFFF0C30C305C30C30C3AC +:106D5000CF300014F3CF3CF30004CF3CCDCDCDCDEC +:106D6000FFFFFFF2304FFFFF0C30C30CC30C30C3EA +:106D7000CF3CF300F3CF3CF30008CF3CCDCDCDCDDD +:106D8000FFFFFFFA302FFFFF0C30C30CC30C30C3E2 +:106D9000CF3CF300F3CF3CF30010CF3CCDCDCDCDB5 +:106DA000FFFFFFF731EFFFFF0C30C30CC30C30C304 +:106DB000CF3CF300F3CF3CF30020CF3CCDCDCDCD85 +:106DC000FFFFFFF5302FFFFF0C30C30CC30C30C3A7 +:106DD000CF3CF300F3CF3CF30040CF3CCDCDCDCD45 +:106DE000FFFFFFF3318FFFFF0C30C30CC30C30C328 +:106DF000CF3CF300F3CF3CF30000CF3CCDCDCDCD65 +:106E0000FFFFFFF1310FFFFF0C30C30CC30C30C389 +:106E1000CF3CF300F3CF3CF30001CF3CCDCDCDCD43 +:106E2000FFFFFFF6305FFFFF0C30C30CC30C30C315 +:106E3000CF3CF300F3CF3CF30002CF3CCDCDCDCD22 +:106E4000FFFFF4061CBFFFFF0C30C305C30C30C3AB +:106E5000CF300014F3CF3CF30004CF3CCDCDCDCDEB +:106E6000FFFFFFF2304FFFFF0C30C30CC30C30C3E9 +:106E7000CF3CF300F3CF3CF30008CF3CCDCDCDCDDC +:106E8000FFFFFFFA302FFFFF0C30C30CC30C30C3E1 +:106E9000CF3CF300F3CF3CF30010CF3CCDCDCDCDB4 +:106EA000FFFFFFF730EFFFFF0C30C30CC30C30C304 +:106EB000CF3CF300F3CF3CF30020CF3CCDCDCDCD84 +:106EC000FFFFFFF5304FFFFF0C30C30CC30C30C386 +:106ED000CF3CF300F3CF3CF30040CF3CCDCDCDCD44 +:106EE000FFFFFFFF30CFFFFF0C30C30CC30C30C3DC +:106EF000CF3CF3CCF3CF3CF30000CF3CCDCDCDCD98 +:106F0000FFFFFFFF30CFFFFF0C30C30CC30C30C3BB +:106F1000CF3CF3CCF3CF3CF30001CF3CCDCDCDCD76 +:106F2000FFFFFFFF30CFFFFF0C30C30CC30C30C39B +:106F3000CF3CF3CCF3CF3CF30002CF3CCDCDCDCD55 +:106F4000FFFFFFFF30CFFFFF0C30C30CC30C30C37B +:106F5000CF3CF3CCF3CF3CF30004CF3CCDCDCDCD33 +:106F6000FFFFFFFF30CFFFFF0C30C30CC30C30C35B +:106F7000CF3CF3CCF3CF3CF30008CF3CCDCDCDCD0F +:106F8000FFFFFFFF30CFFFFF0C30C30CC30C30C33B +:106F9000CF3CF3CCF3CF3CF30010CF3CCDCDCDCDE7 +:106FA000FFFFFFFF30CFFFFF0C30C30CC30C30C31B +:106FB000CF3CF3CCF3CF3CF30020CF3CCDCDCDCDB7 +:106FC000FFFFFFFF30CFFFFF0C30C30CC30C30C3FB +:106FD000CF3CF3CCF3CF3CF30040CF3CCDCDCDCD77 +:106FE000FFFFFFF3320FFFFF0C30C30CC30C30C3A5 +:106FF000CF3CF300F3CF3CF30000CF3CCDCDCDCD63 +:10700000FFFFFFF1310FFFFF0C30C30CC30C30C387 +:10701000CF3CF300F3CF3CF30001CF3CCDCDCDCD41 +:10702000FFFFFFF6305FFFFF0C30C30CC30C30C313 +:10703000CF3CF300F3CF3CF30002CF3CCDCDCDCD20 +:10704000FFFFF4061CBFFFFF0C30C305C30C30C3A9 +:10705000CF300014F3CF3CF30004CF3CCDCDCDCDE9 +:10706000FFFFFFF2304FFFFF0C30C30CC30C30C3E7 +:10707000CF3CF300F3CF3CF30008CF3CCDCDCDCDDA +:10708000FFFFFF8A042FFFFF0C30C30CC30C30C37B +:10709000CF3CC000F3CF3CF30010CF3CCDCDCDCDE5 +:1070A000FFFFFF9705CFFFFF0C30C30CC30C30C3AD +:1070B000CF3CC000F3CF3CF30020CF3CCDCDCDCDB5 +:1070C000FFFFFFF5310FFFFF0C30C30CC30C30C3C3 +:1070D000CF3CF300F3CF3CF30040CF3CCDCDCDCD42 +:1070E000FFFFFFF3320FFFFF0C30C30CC30C30C3A4 +:1070F000CF3CF300F3CF3CF30000CF3CCDCDCDCD62 +:10710000FFFFFFF1302FFFFF0C30C30CC30C30C367 +:10711000CF3CF300F3CF3CF30001CF3CCDCDCDCD40 +:10712000FFFFFFF6305FFFFF0C30C30CC30C30C312 +:10713000CF3CF300F3CF3CF30002CF3CCDCDCDCD1F +:10714000FFFFFF061CBFFFFF0C30C30CC30C30C396 +:10715000CF3CC014F3CF3CF30004CF3CCDCDCDCD1C +:10716000FFFFFFF2304FFFFF0C30C30CC30C30C3E6 +:10717000CF3CF300F3CF3CF30008CF3CCDCDCDCDD9 +:10718000FFFFFFFA302FFFFF0C30C30CC30C30C3DE +:10719000CF3CF300F3CF3CF30010CF3CCDCDCDCDB1 +:1071A000FFFFFFF731CFFFFF0C30C30CC30C30C320 +:1071B000CF3CF300F3CF3CF30020CF3CCDCDCDCD81 +:1071C000FFFFFFFF30CFFFFF0C30C30CC30C30C3F9 +:1071D000CF3CF3CCF3CF3CF30040CF3CCDCDCDCD75 +:1071E000FFFFFFFF30CFFFFF0C30C30CC30C30C3D9 +:1071F000CF3CF3CCF3CF3CF30000CF3CCDCDCDCD95 +:10720000FFFFFFFF30CFFFFF0C30C30CC30C30C3B8 +:10721000CF3CF3CCF3CF3CF30001CF3CCDCDCDCD73 +:10722000FFFFFFFF30CFFFFF0C30C30CC30C30C398 +:10723000CF3CF3CCF3CF3CF30002CF3CCDCDCDCD52 +:10724000FFFFFFFF30CFFFFF0C30C30CC30C30C378 +:10725000CF3CF3CCF3CF3CF30004CF3CCDCDCDCD30 +:10726000FFFFFFFF30CFFFFF0C30C30CC30C30C358 +:10727000CF3CF3CCF3CF3CF30008CF3CCDCDCDCD0C +:10728000FFFFFFFF30CFFFFF0C30C30CC30C30C338 +:10729000CF3CF3CCF3CF3CF30010CF3CCDCDCDCDE4 +:1072A000FFFFFFFF30CFFFFF0C30C30CC30C30C318 +:1072B000CF3CF3CCF3CF3CF30020CF3CCDCDCDCDB4 +:1072C000FFFFFFFF30CFFFFF0C30C30CC30C30C3F8 +:1072D000CF3CF3CCF3CF3CF30040CF3CCDCDCDCD74 +:1072E000FFFFFFFF30CFFFFF0C30C30CC30C30C3D8 +:1072F000CF3CF3CCF3CF3CF30000CF3CCDCDCDCD94 +:10730000FFFFFFFF30CFFFFF0C30C30CC30C30C3B7 +:10731000CF3CF3CCF3CF3CF30001CF3CCDCDCDCD72 +:10732000FFFFFFFF30CFFFFF0C30C30CC30C30C397 +:10733000CF3CF3CCF3CF3CF30002CF3CCDCDCDCD51 +:10734000FFFFFFFF30CFFFFF0C30C30CC30C30C377 +:10735000CF3CF3CCF3CF3CF30004CF3CCDCDCDCD2F +:10736000FFFFFFFF30CFFFFF0C30C30CC30C30C357 +:10737000CF3CF3CCF3CF3CF30008CF3CCDCDCDCD0B +:10738000FFFFFFFF30CFFFFF0C30C30CC30C30C337 +:10739000CF3CF3CCF3CF3CF30010CF3CCDCDCDCDE3 +:1073A000FFFFFFFF30CFFFFF0C30C30CC30C30C317 +:1073B000CF3CF3CCF3CF3CF30020CF3CCDCDCDCDB3 +:1073C000FFFFFFFF30CFFFFF0C30C30CC30C30C3F7 +:1073D000CF3CF3CCF3CF3CF30040CF3CCDCDCDCD73 +:1073E000FFFFFFFF30CFFFFF0C30C30CC30C30C3D7 +:1073F000CF3CF3CCF3CF3CF30000CF3CCDCDCDCD93 +:10740000FFFFFFFF30CFFFFF0C30C30CC30C30C3B6 +:10741000CF3CF3CCF3CF3CF30001CF3CCDCDCDCD71 +:10742000FFFFFFFF30CFFFFF0C30C30CC30C30C396 +:10743000CF3CF3CCF3CF3CF30002CF3CCDCDCDCD50 +:10744000FFFFFFFF30CFFFFF0C30C30CC30C30C376 +:10745000CF3CF3CCF3CF3CF30004CF3CCDCDCDCD2E +:10746000FFFFFFFF30CFFFFF0C30C30CC30C30C356 +:10747000CF3CF3CCF3CF3CF30008CF3CCDCDCDCD0A +:10748000FFFFFFFF30CFFFFF0C30C30CC30C30C336 +:10749000CF3CF3CCF3CF3CF30010CF3CCDCDCDCDE2 +:1074A000FFFFFFFF30CFFFFF0C30C30CC30C30C316 +:1074B000CF3CF3CCF3CF3CF30020CF3CCDCDCDCDB2 +:1074C000FFFFFFFF30CFFFFF0C30C30CC30C30C3F6 +:1074D000CF3CF3CCF3CF3CF30040CF3CCDCDCDCD72 +:1074E000000C0000000700C000028130000B815832 +:1074F0000002021000010230000F024000010330C0 +:10750000000C0000000800C000028140000B8168F0 +:10751000000202200001024000070250000202C0E7 +:10752000001000000008010000028180000B81A80B +:107530000002026000018280000E82980008038031 +:107540000010000000010100000281100009013854 +:10755000000201C8000101E8000E01F8000002D895 +:10756000CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC5B +:1075700000002000CCCCCCCCCCCCCCCCCCCCCCCC5B +:10758000CCCCCCCC00002000CCCCCCCCCCCCCCCC4B +:10759000CCCCCCCCCCCCCCCC040020000000000067 +:1075A0001F8B080000000000000BFB51CFC0F00350 +:1075B0008AB7B13130ECE644F0E98159181818F86F +:1075C00099C8D7BF1168C04E20BE01C4075948D71B +:1075D0007F551AC15E26C9C0700A8827883330B427 +:1075E0004A21C4ED651818EE01F92BA16272403DE5 +:1075F00073A4C977F3281E3CB8D014951F620CA160 +:107600005F9840E82234F950A8BCB81E842E36C5D5 +:107610006EAE841E71F6A7A9A0F2BD55F0ABCFD512 +:1076200040E5C7A2A90F81F2017EE9B234D8030078 +:1076300000000000000000001F8B08000000000098 +:10764000000BED7D0B7455D5B5E8DA9FB3CFFF6421 +:10765000278470123EEEC400C1063C4280A0A83BC5 +:10766000FC1A7DD41E1025E5A11C446B004922A6FE +:10767000D78C96D76CC8870450E3E751BD457BA0F3 +:10768000D88B0E5BA3A68ABDB43D887AA9C3DB2242 +:107690005AA52D7A83FA2C58A0B1572ABD4FCB5B3F +:1076A00073AEB592BD77CEC9C74F47EF788D43769D +:1076B000D6DEEB3BFF6BCEB95634D94FF22E27E422 +:1076C0001CFCD0A7291142A6F73DC92D5932C92368 +:1076D000E41B3E823F1FF923534816210D3EF6BCA2 +:1076E0003D10D905CF2D8D84A426C2F771491221F2 +:1076F000244848899A0B2D02B1870BE15977617CA8 +:10770000323E67C23387C8848C84F218FDBD20EBFB +:10771000FB9C42FF399AA880F114F68AA8A43C96F3 +:10772000C2F6DF226446DF3C48DD57F578B86FDEED +:10773000EEA7A26B24C5EB9E837F94E5598950E6A2 +:10774000FA0D47A5C79FB7D51F4FC2B9382F95A8C7 +:10775000382FDE9E108BD8E7E7EEE7A346F2F8F36A +:10776000E3FBC32DD3B8026E6D8D3E7CB636EA24A2 +:10777000E5258436333B4BE93344CC5DA5FDDBCDB9 +:107780002312871F9F0F8C63D0FAF47F42E1DE9CA7 +:107790004B9241C0214938E0D61C5AEC33D3F42730 +:1077A0009E2497C2AD84CFB9A8FF7AFD302F0A0777 +:1077B0003FCC2B0D3C97C2BCA6F79F97BFD83DAFDF +:1077C0006A6287CF70E7159844C821C0876A128221 +:1077D00078B9CDD19FAC9B56779AFE08A70BD5E020 +:1077E000EB1B229E822572DFF8000723E0A02F6F9B +:1077F00034C7496F6EBA067820BE3A387CE20AE395 +:1078000007AB0F8FF4199A1D93803568F110E02DA6 +:107810009F30F8E557B7DE2A4F2194D53A0F4EA096 +:10782000F0CBEF5EB99040F9E8152780DF9ACBA640 +:1078300056CEA5F5B2CB63AF2CA04D423143027AB0 +:10784000DD0A9D15407F5FB32A68B909FAA365CBAD +:10785000BACAB4106EA6036E1472864ACB1EF8B56F +:10786000280DFC482F1EA473DEFEED33C1CF436C00 +:10787000F8437E5EEFA0CB8C78BF91E1CBA2FF01F5 +:10788000BE46101B5FD37EB22B35075EB25CE33C75 +:107890000ABF20BC6FFD9B8C97439EF41994CE3D8C +:1078A000A5B29EA478CA26B16CB58CE263A14A4009 +:1078B0008EE5E4EA1290C360786926A412F89F4A24 +:1078C00007B2C826E77ECEF9AB60CDEE9DAD749CC5 +:1078D00033B34331A895AFD3B94EEDBF9E3B40BE05 +:1078E000786DE5B2E74802C7EB3C5844E76595C9B7 +:1078F000B18729DD6C2D3DACDBE5E3B15EF9E2A695 +:107900000F62A833B83CA0F0514A65D31FF9ECF4DC +:10791000A17C4AFA08DFE8C4C770F1757A98F4F1DF +:1079200059C71378EDCF571B055E7D847EDF52B2B9 +:1079300078407DD51FAF4F92046D172A2566324DD2 +:10794000BBFFB4EB0BF7D326DFDD72541935A36A06 +:10795000E74078CB75AE57F4EB6F508C7747D0A2E9 +:10796000AAA37CD5B81E688FDE63114A776740F6FC +:107970005078281D17A5A04C8A49EC61D64D4AA223 +:10798000657FD44C6E413A48225EC4FCBC86EC90C4 +:10799000B36AAE530E932A4BB2CFDFDFA0E13C3483 +:1079A000182F17EC02DA2105851A2229A05B41AFB6 +:1079B000A092CE9D0F65A79DD1664C25E9F0A072DF +:1079C000BC4B92A0D76F0D4DBEB8C75BE29CEF9049 +:1079D000DB8554E33DD1268D9CEE6BA792F7047EA8 +:1079E00028102F13761DC7D3660FD92B5D48E5C12C +:1079F000986BC152209BE1D32C6A87C0932A9FCDFC +:107A000063A6EA4057648FA4C23C71488A4742F596 +:107A10001DD40B4A06F623FBEA90FE9490894FF1A1 +:107A20003DF3BCD8F8BD655FA206F0531DD58C2D83 +:107A3000748E6B15D3D80874318DC9A7EAE88479A0 +:107A4000A0EF3C129BD7B7A57C5C879AD39687762C +:107A50005906FBAE5AA52A7F2A7CDF3661207E229A +:107A6000494F4FB70D9E6E7BF06689DA835FA2BFE8 +:107A7000CC2433018E7F8A2DCE4A0D80AFF71B0FA9 +:107A8000EAEAF83E7BD0FD7DAD42EAD2C98156C913 +:107A9000C7F8D26769601F8875AF0576A720DD1625 +:107AA000DBC4D69B9B8BF05DBBE717BA6AE3BFB51F +:107AB00054CD78A7F65F8F80B7E8A7B77DF2A0A373 +:107AC000BDBB5D6F7F425E507B18E85CD041504A81 +:107AD0006C95E87B6F6CB105EA6CED63150CFF19D2 +:107AE000E6DF8BAF4F397FD16E30BAFAD3EEA656B0 +:107AF000D04FEF691D575D4CE9E8F74F28B14DF4C1 +:107B00006BF58E89F3C05E7A8FD3B7C0D389DD4D14 +:107B100079E9E823139E7E21F9711C415FD5F2F2C9 +:107B200001E96130FA7ACA4D5F9D577F21F475C82B +:107B30004D5F1C1E273BD9FAC9FD23185E38BEDCF9 +:107B4000F8C988974FDBAE3F3DFD5AA27CEDEDBCF6 +:107B50003A3D3DF1F90A7C7DD6F90E4647798669B2 +:107B6000EA74FC51D48E91407F9491588ACE53A7E9 +:107B70000FD45B31A6B7845C12ED4F4BCC4E53C98A +:107B80006BD85E21294B477BDB6967CC57E84BDA22 +:107B90004F7309497A715F64FA504F95A884E93FA1 +:107BA00033943F03EC08FEA3CC8EC1BAB3C0FE07EA +:107BB000FD359BEB5F89DA5B747DA132E7BE37E070 +:107BC000B23F14BE5FE8676F0D737FEC97F9FE3824 +:107BD0004842A88FC4FE38037FF6EE8B395C476AB3 +:107BE000C494E9BAB5839EE42609B41B41FD4C8ECA +:107BF0004A49E62F20256037AF970A62A00FE83E7A +:107C0000AF278B7E7FEF070AEA878668DD8A1658E2 +:107C1000F6B50D13BBE9B8F7349269C59EBEF1EE17 +:107C2000513B7C00EFF6E2F50EBBF6BB52A250B61C +:107C3000E91D7F549B563C0D8653DFEEA6F090293C +:107C40002081FF02A1FBA22F18003FF6BE174EF6BF +:107C5000B2D2BF9C0B364F011653B02F6DA7B63B67 +:107C6000B9188AA3A50A4A07ED1EFEDDFA4D05ECF8 +:107C700077DBFDACBC63D3AC8D169447F2FA561596 +:107C8000FB9ECFCAB76DFA4105EC0BDAB2E99AA9AF +:107C9000BE6EF324ABE269F8FB365976D85F4DC669 +:107CA00082F2FF43D7E1F79917BD40E1498112B352 +:107CB0000CD26B97150ABF41C7DD952500FFD7147D +:107CC00002F4EC3762F19B0CA43FA47B7FAE19DB7E +:107CD000424B0DF4850CF528DE1E96605FC7EC3133 +:107CE000F0E79C43FAA57C41BFAFCFD6B13ED16D42 +:107CF000F659519F3DD68B2717DEEE557BFC80B79A +:107D0000EF8DF9F01713693FD642390664F3BD0DC4 +:107D100045D92B6D787CCC37A70AF0489A73D12EC1 +:107D20008992DE1F13CA62DF5C403A2BC0781C4385 +:107D3000251FA1743A2EDE53012830AAF4E7708F74 +:107D40004BE6E9EFA15DA548E7BE34743BCA0D07D9 +:107D5000DAE3A845543E8D90483C9DDC5DA9E6A041 +:107D60003C185149D73B809FE09B549F30FB2CE14E +:107D700003FF56A67132CDF333C073934CC71D4D2C +:107D80009208A7C1E09A099EADD127B3515E7FCE7C +:107D900070CDD4DE0DCF1112E397956A39F2CB5036 +:107DA000FD3B6D7C3FD5027E38FA6CE27E38777BF6 +:107DB000BFDA416269F0EB379CFE210DF625B67201 +:107DC000BD6C307D1072FB89189EDD7A6101D70B86 +:107DD0002D51AA17983C5C087A20C8E1DF02BB7ECF +:107DE000909F6192B4E8F720F707915226FF7DF447 +:107DF0003FE0B751554E7DA00D511FBC2BC55F9084 +:107E0000910E8904F3BB5FEAB86202D04F3EB3C75C +:107E1000A337B445133638D4CB4CDF097D962C16E6 +:107E2000FA8C20FCCEE37348920E3FE8C307362C51 +:107E3000CE42BFDD8D41871C8AB62EC6FDAF8D9E1A +:107E4000D12FDAC1FDA399F0A76BC9443A7958A89C +:107E5000307918317B52E0F34342CEE32E434ED6C5 +:107E60000CFEC4B10F8B4CED39783E5DEFCE8BE448 +:107E7000D826DA4E9DADA63C14BE6AF98B55127D0C +:107E8000EE2C64F0B76611A4D390B1E08402FA58E6 +:107E9000ED467F4DA8D2BD2FB69515E8A7E77AD459 +:107EA000DF763FF500FBB8A13E9B28BCDEB6F13F74 +:107EB000855C4AA1EB50371003EC09D5A4223102AE +:107EC0004F3D0FE8453563217C765754C2F3BCD94A +:107ED000F14AD9A6075433BE05EA8FF8CA7DEDB042 +:107EE0005EF526595624C6073936789B4AA1633F6A +:107EF00097ADBBFCA589D62AD4EF8646C617F69F58 +:107F000077BDAC72B9E7A417412703C8BBCF441FA4 +:107F10006FCAC25FEDC4BF834E8AFAF02BDA85FACE +:107F2000F9AB9CF875973F6FBCFA014F141FE751EE +:107F30003C017D9E379BD123B547D17E7AC0D76166 +:107F400002BC1F2836644BEA6B175672989FF92CB7 +:107F5000DD6851BBE7FE95DB4D68975F4C6580841B +:107F6000CFB4FEA37A59C376542E542ACC6E97C050 +:107F70001E9FAF6CAB82F63B295E81DF77027F43A9 +:107F80007C20A1A11CAE97DB2B36D2BE5B8F4AB200 +:107F90000246ACBE14F1EBE7FCFE912751097EC806 +:107FA0002DFF4B26BB0CD04B03FBBD9A38BE4519A9 +:107FB000FC0D609F8CA9D3A702D833B5DB5E275791 +:107FC000A65B57B5C2F07F47DDE10E344F9F77EED9 +:107FD000473CCB4DA048D897542B36FA0E97317FAB +:107FE0000749D0F5407D4E371F150E4CAF0FBAE64E +:107FF0003F96C753DCF55E56B8BFCE60F03244FF03 +:108000001B07EE5FC0E76C9BC2E323D40043221E34 +:1080100049ECFA5BB9F15005BCA75CB709F0B55D56 +:1080200026D5CCDF1C473D14E1E3ED2CCFC1F60B88 +:10803000552647C79AFA16C0F7D866192C05F2B824 +:1080400062E0FB51CBEBF67B281EDA0B492C64E097 +:1080500010D8EF8BE335A4CBFC5CA6C7F2EB290963 +:10806000D07AF9A52469D0F6EDFB1FA8D068394273 +:108070003754600AFBCA193E7D252406A690C72204 +:1080800029997D4F424C5229EFB140951E183F036C +:10809000F75F77E69298D7E8931B82AEEE6CBEC787 +:1080A0000F7AE481E27BAE9800FEC65215FDE4E44F +:1080B000630A27E14F54205E163761BCF6596CDE27 +:1080C000F40DE253D5D9FAC7DC3F1BF9A43DFC34CB +:1080D000CEC35A4762E3B15E8C60FC860A54F05707 +:1080E0003655337BD78D8FF524F1B832DD4EAF870F +:1080F000906EDA3F51F8BEE0C58D60E78F835F690F +:10810000F9974D7FDC381CBB45C40F85DDB245EDCA +:1081100044BEB728CF815E12768CBFB813C7FDBFAF +:108120009CDE87DABFBFC4E96F75DB356E7BA65E68 +:10813000D61DF6AB7B5D1F795257C0FCB6E4537E6B +:108140004FA3077E03FA9AB6DF115DFCAB89465F49 +:108150003F7D72C8C0EFA23CE6AC86F8197A7D2A52 +:10816000F7608F6632BE1A2BE4D037285F0D107F80 +:10817000147CF511151287804FD40EA42F6296201F +:108180005F097E51BA3BDACFA7F460D4CBE0B906E1 +:10819000FE2239B45C48E93D65B38784BC504B3B53 +:1081A000E313A5FE74F7A021231ECF94317F7596AB +:1081B000D56D4293606927C6F5285DFD17D095AA55 +:1081C0002725C0EB98FB17E0BA7EA93056F7AB2CF9 +:1081D0007EEC5EC7CF397C89BE1BED793F1B8EB22A +:1081E000F87D31363F579CBDFE5703C6D9FD319708 +:1081F0009D334C3F428ECAFD08DCEF3558FBE1C68B +:10820000D795B323903E7ACB19E4ED4D2AE78BA3A3 +:10821000BB1C70E9070F65476CA0F9F9859FFE53F9 +:10822000C60550870D010E6E385EA23AFD879F3756 +:108230001CDDF1EF97B8DC1F4C1E044D33252BE0FD +:108240003F23CCBF1322DCBFE3A4F79DCD32DA215C +:10825000C1B0BC134CC9ACFA6ED4C1627C4AEF55B4 +:10826000AA8DDE47971E4A413BB73ECAA4870693B4 +:10827000B7AB7CE60D2ACAADF4FBF1BE7C03CA2580 +:1082800069F20D32E2B5EEF3C937182ABC7BFD9BCB +:108290003C7FE0867241C7C6D2DF51B8AC3EE821D0 +:1082A000E897F998AECE16575BCDF78137F07DE4AD +:1082B0008D241E818FA7885C09FC728A1C8E4CB3AA +:1082C000C993FB548DF14B9BE76DF0AF8A78F94D64 +:1082D0001DAC2CE673F3FDCEF2D7C9E23CF0EB7D8A +:1082E000FD3E0FE26BB5CBBFD6AC32FD7133A96B4F +:1082F00005BCB5784815C8B11B74A28EA0A6EBBA10 +:10830000671E9CB19296BFCBED91F7A95C366C715C +:10831000D035A1A406F87DA76BDAB59710689F6CDD +:108320002D807D5A36C17DAB1BCEABDA9CF31B6C26 +:10833000FEEEF952F2C2F9669A87BA474A6B4F3F8E +:1083400022E40DC757A6BC2A914FF50B20205ADF17 +:108350009A43D8BEF3AD60B209E535CBA71AACFDA0 +:108360002F55463F9FB6FDAB83B45FE7EB5900CC7A +:10837000D6966BC5C12F24E28235A4CE1C4D7F5505 +:10838000F72DB246135BBDE810EB150F5C2FD3BC85 +:108390004FE83E4BBEB06FFEDF9512C7D434F3BF3B +:1083A0005D49D440FF5EC083024F15F18D7E608A27 +:1083B000DF5A35D4266541BE5317EE03FD86EAA089 +:1083C000875AF805E45A09936BC112E777B77FF82B +:1083D0004355C4E153C87F188236C07E08A514F007 +:1083E000DF94AB277BEBD3F16A605D1742298E7275 +:1083F000A35E67F56B8871D7EC32E43F8C3FD4B74E +:108400009F8F71F5FA9106FA77551233B10F17DD88 +:10841000D59E9548D2A60F6BD51E0DF8AC96DA45C1 +:10842000F6F7EBA38AC34FEB7E7AA8E51C2A817D81 +:1084300092CCFC483A2DDBD6FDA70E89E7AF185940 +:108440004B06F0DFAD8F327FF00DEDE3B398DFD058 +:10845000297F4F3732BFDCBF3DF67D0DFCFCA71EE8 +:108460003D7615C07BEDBF2AC407F91B8F85490AED +:10847000EDB1A406F6D89A2EC54CA6CDAF6862F130 +:10848000CFC7C388AF354F7A930B69FB354FBF33E6 +:1084900085D0F99DDED4F3E268B09B1F95581E820B +:1084A000D53DE56AFA7E8D4A56A4F31B4CF630F9A9 +:1084B00073F2D96015F0B7B467FFF5D86FE7528F44 +:1084C000D7B6DF2EF678906F693D66973F2225C7B5 +:1084D0004BE9E6C7F23F4E3E22B1F9EDF524FD30FF +:1084E000BF3D3BB5049D47ED9E0F509ECC7DFC8764 +:1084F000118043ED5EC5A1076AF72829EF147C1EA1 +:108500008327C48DA41940279C5EBAD661BCA8A657 +:1085100073EB07E0C7A8DDEB946B142EB114C0F524 +:108520000D25B610CA4FFD4BC4A0A07AFFD0C311D1 +:10853000802BED77A59605FAC649DFD0FFD99CFEC2 +:10854000FD11D283F1BADACE76365ED7577E0F7A36 +:10855000A5D6253FDF875FF2FBDB33D7785CF6CC0F +:108560009EA1C5EBD6FEF0CC43161DF7E4937F78B1 +:10857000C8A2F3BFE5AFFFF9D0B7803F7FE6D74190 +:10858000FED73EFAEB08B1D163AD87F1E3E9B1C4A0 +:10859000A27B5472FA37DE24F84B4EFFF4F7E30C5B +:1085A000BAEED34FFC25CFA0F5EB7F3A7F14C0A1E4 +:1085B000FEC773470DB4FF067A4D7AEDF34A225E8B +:1085C0008DBD123382F6F1A70B3F07BA0E8C83796B +:1085D0009E3AE28D81DBB996BE6B980AF85A87FA0B +:1085E00018CA1B289C6B1EDBFC01C889FEF0B6462E +:1085F000CBE8AC4F8D06A77D4DD73B0B106FA40782 +:10860000F5A8BB7EED6B149F1766C6DF19F2B106A5 +:10861000F2AEF6B176365E27C55FA43FFE4EC12F9F +:10862000B3FAE3EF0E17FECE905BBE970F798D5D28 +:10863000231C7152F1EC8B0FC6B3E203C80B210F60 +:1086400006836FB5C4E6B5CC633EE801BE7A32D886 +:108650008BDF8580DF1F9E1947287D1CF7F45C0F98 +:1086600072B3E7A75E7D177DBFE6A76F209F9DFED3 +:10867000F12B9A81F9992424E5F13C31F67308E451 +:10868000700DDBCB91DADDE19437D287A79AE4A2B3 +:108690004A2382EF8FE1FB24A3FF9AE4FE25521ABE +:1086A000BCBDE1296276407224C265DDEEDF69CC93 +:1086B000BEECC3A7540EF83CB600DE67C2A758BF95 +:1086C0000EEB9F69C3EB6EC6B7EEFA35943F41EFF0 +:1086D000F5C36F527A039EA7777A55D07BA7C1FE68 +:1086E0000AF5C77B1FFC99FD33DCFDCA2B6EFE1615 +:1086F000F1630E87CCF461713B60E0F50D177E3FAE +:10870000F7180E3A12703CF9717AF97F8ACB8D1AFC +:10871000625516D8EC139F87DA27905F46E2D6E8B9 +:10872000C2BEF99E847D04A5BF938F2A18AF69ED60 +:108730003C8072DC2D2F6A48FA7DFB5F3DCC5EAC3D +:10874000D9BB7F0AC8B593CF3D8BF459F3D8310D0F +:10875000F62F2FEE794AEB2EEDE307D00F499B7EE3 +:1087600038F9A3FD53983C48BFFF0D6AACFFDA7D92 +:10877000CEFE6B1FFBC0D1FF5AAB5363790C038F46 +:10878000F3BE6A2E85F5BE7FC843409EBEDFA9A416 +:10879000F5BFF670FD28E0D4FACA82DF419CBFEC39 +:1087A00070C0003DDAB5C91C7507D86B873D04E47D +:1087B0003751CD3F7869B9EB9500C633BA0E5FAB40 +:1087C0001836FFC4332E78CE7CCD9A1BA6FDCDEC97 +:1087D0008E97C116CA2D37CA8FD27DA3DD7FF54A89 +:1087E000E52890FBCD60CF4F84F16251F07F289156 +:1087F00005952C7F50D6FD69F537EBCF138A63BE04 +:10880000A047977B7DB6488F62BFC5FD4DADA1F4F3 +:10881000FEE8059AD817D0716D7290DAAA55E9F082 +:10882000364B637648A6EF976ACCDF93E97BC52089 +:10883000ED7BF99BE3470BCBF174F39EC6FB71FB19 +:108840005733C9030FEFA74C331CEB05782FB2E564 +:10885000C58F26C98D90274A4221773C3AEEB3C78F +:10886000A3AB0EED87F873EED5FBF201FE11D2AC8F +:10887000BF87763C899D1BC08E75C79FDD7989991E +:10888000E2D1BE50CD9114E9DF5FFFF8BB897928B2 +:10889000CD63E6F90A6DF1F766BD5FFC7DBD46C7A5 +:1088A0006DC9808725DA9C7FD280BE649248F77DAF +:1088B0000BA79BCB49F7532B619E3116BF9FED82CF +:1088C000D7A51C5E3F3B9F2E9CAA9E0A62A81E0A4B +:1088D000DFB94BCC661081F397F7ACDD0F7C26E255 +:1088E000F7D644F95C70E8F01B6E5EC42ADFE27BC9 +:1088F000B521E445103D27AD5EE89B87C5F755518E +:10890000DC2779389F1D78F3661FC82D95242A0B24 +:1089100061BFC4E39A986F4FFBCB4BF98949E7AB32 +:10892000E906DADB79A9D50FDC0471757D0CC62365 +:1089300094B397A0FFD0DDAF128D59980F16322A4D +:1089400014DB38ADB92C3EA3EAF1B479C3ABB4C49F +:1089500013B05EE5EC65D8AFEC8B613D121A5ABEE0 +:10896000EC77AE8E207C7D14BE201F1164B02E9E4D +:108970003775F7D511D433FE839E9DF0DD1F6279E4 +:1089800054B7CB8118E459B9F3A82ADE6A27D05F1F +:10899000EB3109E328827E5B0BEBCE03393E401EB0 +:1089A000D54B9ACDAF9E298FCA1FBA11F3A8FC9F51 +:1089B000368FCA2A9807F6586B361179559644E7D0 +:1089C000D1CAF3A2FEA3F5A5B9A09F5AFDE2FBCB45 +:1089D000734D7BD95A7F00CB3CEF6AB4B7BD09EA2F +:1089E000E78E26759DE8CF33C93536391BF1AA08C5 +:1089F000E77FD6CC7735479E7CD4115F3AF0E666A8 +:108A00001FE86FFAAC2C02F851BA02BB3D2FD54ECD +:108A1000ECFA483C051DB5160F1CBF53CF5E847E93 +:108A20007C51F6E949D34C537FBE8FD91F827E7D9E +:108A3000B924097AC967241EB809E83937140B32FA +:108A4000BAC438595B08DD53FDD6D1567C03C6DB6A +:108A5000CEE804B95ED071FFF95FC6E75F64615C80 +:108A60002244309E96791D65B88E559A19F6DAE043 +:108A7000987B5EFABCD4BBBD6C3D2DF1E52CEFAC10 +:108A8000DA198715791AA27E504A1478411EE6B287 +:108A900038ACEC63FCD6872FAA2A6CFECD26B2DC5C +:108AA0000212509777E2D146554F62FD127FE27C69 +:108AB000AF233ED7CDE2BAAE78E27CE516C6DF83BF +:108AC000E04F9CCBD80A71B789109F8BF2F37D06DB +:108AD0008FD3992CAF28033DB5150F1C87EA688CFE +:108AE00061FBBB1ACB59BE9244B85F3BD9047402F8 +:108AF0006E0946F73F6802BE092B822F7E88E53B50 +:108B00002556BEC9FBCC5CC8373CF0E61B55AB28EC +:108B10007DB49A01E4FFC1D6A72767205E873B4E4C +:108B2000FFF5B271DBCC10EE77075BB79E62E30E08 +:108B3000751C115FEB5B9F0FC769350619A7838D05 +:108B400033F8FC199FDCB17F35E62FF828FFFBE9ED +:108B50007BDFEC1E9248D37F16E79F036F7A515E4E +:108B6000B7E5B2FC284F49C8644E4067FF9ED2BCAF +:108B70003978DEA1EC02CC9FBF637F3BCA190DC6DA +:108B8000A1553CB1D04AD62E61C239DBC83C82F136 +:108B9000674F49DE2A78DF403AE273400F97CB2CCB +:108BA0003FB9A4E426E8271BF892CEA3DCC7F69DC4 +:108BB0009E928B6F86FAFBA7BF9E68023895333A68 +:108BC0002007F31D706C358AC4B99D01F9DE53EEA0 +:108BD0008C5B109F33FF93A84B306E4EE54287D7D6 +:108BE000665752BD781FF23329B3C0DEDBFEB56B8A +:108BF00063767EFE672DFE1D565FE46B093E4F9F38 +:108C000037D79A2BF2E6123EA50CCE29F5E6532F64 +:108C1000CCB7E77FF17CEA90C8A7E6F1CC0EFA5F0B +:108C2000BAFC39F739C6CF2B9FFA292FDF0F07C9B6 +:108C300058C8A7FE8987C4529017F36B250679316F +:108C40006EFA70F7E73E07D06B8F64E0E7F7013804 +:108C500036B9979F70E1ED463FC6E7C478CF837C75 +:108C60002A1D9C4F47573BFB195BE73C9F755E8372 +:108C7000335E55681538EA9FDF56E4F83EBEE302DE +:108C8000C7F789F74F759427252F76D4FFD29E39E1 +:108C90008EF2E4CE2B1DF52FDCBBD851BE28B5CC0F +:108CA000517FDAC11B1CDFA71F5AE3F83EF3C87AD5 +:108CB000477956F7371DF51BA87902F92C7040004B +:108CC000F7ABDB46CB76FA6CCFA67A250BF3B8353B +:108CD0009ED48FF166968BDC9767E06EA7146BA627 +:108CE0004EF9573126CCD331CFF046E423A5386F67 +:108CF0008E81EF672C00BF132963E7B444FCDA537D +:108D00004C527EC8EF0BB9F0EB8A4B7B946D29C0B7 +:108D1000B376F4CB07A5487FBC7AA2EE7CC6A1C58A +:108D2000B555E3B3E507E4F9385F8CA57C817EC4D3 +:108D30008F15D8B7907961B40F6CFB1B84A3D8DF73 +:108D40005CE623CD0053C11715CB7B46BF80D5C44D +:108D5000BEC62B0F272FB9BF5EF1A2DD25E4CC6084 +:108D60007A45494E73E421B89F54FE95F9609F1EE1 +:108D70005986F2A8775FD02B1FE333E1BB478DA163 +:108D80007CEC957F7B0A1C7261A8F6995B4EDF052F +:108D9000421FCF05A597D711C80BA372E9CEABAF81 +:108DA000C23818A9278EF3807955711FE83D6A975C +:108DB0007DC567DB3F47CA997DF6F766A78660BD2C +:108DC00036F927EC5501D7118575718CEB85650255 +:108DD000FBAAA6D9B128F801DBA08A6D9FF65DDF5A +:108DE000F958BF39A4C9E02F6D3E381FE3035E7FF9 +:108DF000DC0779CE4D9E7825ACAB295BD6D3E53B1D +:108E00006DF631FF8CD6109CB67B00FAD034BAEFE9 +:108E10004FB3DE7FF131BF4BB3BEF820E8B99CB051 +:108E20006640FE44EBFE598B305F77A1AAC3BE9625 +:108E3000D04DDC3BB6B8222171F46769B932EA45FE +:108E4000AD2182E30F36DF5B7DCCCFE06DF00F38D4 +:108E50005FAF96DE4F9169BE9B61BEB983CFD70BE2 +:108E6000F39560FC108EBFC9C7F0E886BF87986D88 +:108E7000F368BD96635FEE28468A61F97AF72E9C07 +:108E80008A744A05B5837EC53E82D2EFC340BF6275 +:108E9000FF2ECEB3DEE263790902AFC460FE881113 +:108EA0000915F7BD3909B6FFED931F8C8E723C3161 +:108EB00082E7BFC6A8189704378DDD8FA1F8D9BE09 +:108EC000C77B690CF1D5FE15956C027A2BA6EB8158 +:108ED00073B90759DCA9DD13AB8A87FAC613EDDF36 +:108EE000E1FB40952CC9C27B529485D174F6672F63 +:108EF0009D73B8B9E5EC011FCFC3CA27F94CCE96D4 +:108F00002E85A34499FA71DB1B0DDCAF3CFCF329E1 +:108F10001D08CFF631F7A11D2DFC63245A3688BFFA +:108F200087C54BFBF0BCD448513CAA574C45A75FC2 +:108F30007B31C7739D2B9F97E359E057F8ED493478 +:108F400017F95AE05B017802AE94D9D181F495C249 +:108F5000F9C60DCF53FF4DE17904D600743B96AEB0 +:108F60001FF8E6C01504E3602E7E14ED04DDBBD7C8 +:108F70001FF6FFF75EBFA087CCF5ADB4FB0F11D78E +:108F80000D737AF371BDF942F9DB6D709E44CD65C6 +:108F9000FBDD7079F3AD329CC320960EFEB5B03880 +:108FA000BF53E6BC7F2450EADC7FF85CF74D78F8CD +:108FB000FEA3DFFD2ADCCE12E7F9DDF377E36BAE2B +:108FC0003F7D1E261993DEEFEA8EC789F886C88397 +:108FD00015710084035DBF67961C47F95746CC9D09 +:108FE00069E4D3323FD30B5DCFF9314F225CA5A1A9 +:108FF0003FB6A02C5501E5823A12033D71F1F143D1 +:1090000024413BBD20C0E47E41595202BF47C149C3 +:109010009617B89DC72B0BEA93D24ADB38969FE987 +:10902000AD8FDEBC1DE5E37363595EFA6D15CC7E32 +:109030003B14BDA1A302C62D67F9E461BA5F84BCED +:10904000B1F0116F12EDADB26E027E54AA05AC30D4 +:10905000FD7EBC914CBD713CE47DF9F079B251C705 +:10906000E781B1DAFECB69BDF5850103FA6D290A06 +:10907000B0F3BD611FEEF7FF9CFD75F4AB9E6E8CE7 +:1090800062FDB66F9B685734EF3F817EC3A0392DD8 +:10909000C6FCA8A642CA613E874CF0731035662C08 +:1090A00086EF077E83F5142DF11B0BEC93651AEE0A +:1090B000EF010E104F68F2B37CB9CDFEBA68363CB2 +:1090C0000BC98A4569E0BD82EB1D4A518A96D79744 +:1090D00087A495A7942CF02797914EC873F7B424D2 +:1090E0002B404F93D5BA01E38CF1252BC07F3CA6D2 +:1090F0005A8F810F5D2B67E745043E3C7E127F222D +:1091000004F552D2AD74DC89011DC7293892C4BC64 +:10911000E58FDE9C99D6FEBFFD68057EDFD65879C7 +:10912000789E8D9F4319E2951B8BE73CE0A7E3BD3A +:10913000EA67FC9AA95FF11C6ABFAF723A39F0E6A0 +:10914000C451605F3664C8A356748AA7114C3E812F +:109150003F62FD78635476C8DE0F8387F2DCB30C80 +:10916000AFA58C3E9B7E3C310BFA7DFECDA53AF837 +:10917000FBFE945B8CFB86534F7B4DB05F4EE590BE +:109180006ACCB77C7AE68BB03FFC43E3C11CD526A2 +:10919000174FFDE895191EDADFA9275F99A1227301 +:1091A000251D76ECBA73AFCE003BC19A434AEAE87C +:1091B000B356D708F45BEB63EB107972DBF3B4566C +:1091C000785E19CCC6F679A3E43BA1ACF85E1DF736 +:1091D000EE345C378B2BF0380E5D5F5308E95AA7ED +:1091E0001B1088175ADE7110CF7AD38BF4F75121F8 +:1091F0002929BC10FC820AB6EB594D92904FA1A5CB +:10920000EA803D89FFE52401BE09BEA6EF475AE387 +:10921000F7C1DDE9E7F90F3C8F70E39BB74F04F826 +:1092200008B9AECE2518CFE8F99A2F09F6E83DAA7D +:10923000F19DE560075EA7E23C6819CF1BB9F1B369 +:109240003C58E488E3E5F0F884C06B263AD9DA4864 +:1092500062C514DE3F6BF4C560FC7D8D3A967FD20B +:1092600018C5F2DE46039F4F3796E0B3AB3186DF79 +:10927000F73496E353E4F5E1D65E417B3A5E017A3A +:10928000E81AE687D30DD9847C852C95F8E0BE26B4 +:10929000FDE8BF55C17E1BE44A560EF2BD04ED73D6 +:1092A000799EDFC8FC39ED15469F7C15F2B4C943A1 +:1092B000249047D62CE66708437FB47DEE1242DE49 +:1092C000B6C9F573F49FB74BF8FAE87CB24CE77770 +:1092D00077FD884A1790D3BF1D958B58EEEB373D2D +:1092E000FC86FB047FF9DB36FADE3E9DAE9AD2D1D6 +:1092F0007689C9B13BF9F73BA6CFC8BA01CAB366B4 +:1093000064815CDF3E8B183A85E35D866C79B2FA46 +:10931000EAEF683C98376F3CD74120A7EAF59D5BA0 +:109320006CFB9831165911B7D1CB5D756AE52EB437 +:109330003312F98B2763BE31F76BEF9E678EC17EC8 +:10934000B13C21F0E23C8BEB159033979D657AA8F8 +:1093500057FF7CCCDE0BBDA771FC6F9BBD4989001C +:109360009F803C057959962073E83C4397B2F8F703 +:10937000AC775304F2FBB4187D0FF6A8C6F24D0A81 +:10938000A24909CA3FF2C7670620EF3DE7FED42E87 +:109390008AEF0FBBBC06C41BBB9EFB0BE6672853C2 +:1093A000341FF077C1BE6398B7A4C8DD1AEC789774 +:1093B0000526CF57C19E8589607C802A6A8A6725E9 +:1093C0008FAF8F3CD5322F04E7BE1227ECF5B707DD +:1093D00012B7B21D33317D51CA0F7ED1FE82168085 +:1093E000C7560F2B2F0B4C6AB1B04CEB67B37233DF +:1093F0006DBF35BB332A6743D2D4C4968397425995 +:10940000D49FD862CD26E41AAE0F48285108FCDE5E +:109410005BD669396C2BABAC4C7CEC29D6BBEEC06F +:109420005F5E1C4DE150B34FEAC410DFBE9D12AC2D +:10943000BB60EF4E94AF054982FBFE82A49484A3E7 +:109440009D7B1A0FEACDC2B926F04245C3A428BBC2 +:109450005F484B7A62B0BD9CC4EF0F1174F17490F9 +:10946000E9C74949DADE1E9776DD273289DF57835F +:10947000200579B98D9D0776D37929EFAF81585BA7 +:10948000E03C2E79CCA3637C9CFBD94F0ABB89FBC3 +:10949000736EE10E3CCF262B7001C8BF952AFA816E +:1094A000D7162637521B8AAC7DB630462D56D2E2EF +:1094B00067F4B236BB336F2AC5674BB6B3DCC4F36F +:1094C000E7A3D956369CD7ADD97BF738C8EFA92189 +:1094D0001DD77F13E6FB328B879FD83F2BEB125AA9 +:1094E0005EF7328B63ACEB7A4503FABE27C0F38E8E +:1094F000BA2EBA12D657B34D267221E34B73229D72 +:10950000AED971019CAC7B7EEB5BF3FD630979A462 +:10951000C8D4E58B08E90E9E68F151FC3FA2E9939F +:10952000803EBA833D2D405F6B67C99C9E7A5E305A +:10953000559EFF5800E35CDE027196DDCB2AAF0436 +:10954000732B4F66FC4B0912E3DA4A76B30FECF942 +:109550003FB6C8683F838B7403857BB14A0EAAF47B +:10956000B95DA3F8043E6B55511ED2F76D1EC44B76 +:1095700007DE3342DAD83D2DE3F77957829D5D5CF3 +:1095800067AE467B5B2F453FC038D2FB837912E73D +:1095900011267F27EAA442A5F566050B117FC55564 +:1095A000D7AE85764A784900F83D4F495AD8FF77BB +:1095B000991CDE2E273B7D2097234588DFED114641 +:1095C00017D63DA54817BBE53917805DD422ADDC21 +:1095D000F20BC06B76119E7B85F7EB61FD1C9F4DF6 +:1095E0007ACC07F8DBCDF1A9EC942DC8D714EFB7EE +:1095F0004A37AC06B89ED8523FDF47E19AE735DBE1 +:1096000046503C1CDF52DF129D857828F2D1EFC70F +:1096100003F52D3E8A97DD1BCD02DD569EF8099598 +:10962000EA48B4F52DE66CF09FDCB7069410FDFE19 +:1096300002F83F1EC9117CCFBE1717F5CA1113ECF3 +:10964000D226AB4FAEF8A85E28B6D59F47E5C20F2D +:109650001E5210AFFF4EC7033941D76101DDF74CF1 +:1096600052D12E08D0B904683930B908F36DE9BA7F +:109670004900EC86C92AEA7911C7D126C96837435F +:109680007DA087407E11E6CF51791D87733E4A94B5 +:10969000C5751465874979980479FEBEA42FC2FB6D +:1096A00048FC25B6BC0290BFAE3C04C5551EEFED8C +:1096B000CE97A97ECD3DBA481A47F1F25E80EF8B76 +:1096C00072E93E96BE7F3FC0FC40B7C7AD2F43BE98 +:1096D0000C31BAF3593C2A3E159EA3AE2B1E359091 +:1096E000FFA5FF7E3586F6CBBD63D4B4F960FF1AC3 +:1096F00064FE41EFD862BC57A38150FE07BE08F15B +:10970000FBF2B8FCF0707BC17D4E40C8134F365B56 +:10971000637DFBDC5139A1BE73704AC8F4813CD82B +:10972000AF4FCD027B743C9753CDA9595F05BB4524 +:10973000E5F260879F9DCBEDC9269DBB08D8BF3160 +:1097400062CF4B10F2605BA30F9F0F5F3601E39770 +:109750000F5F963707E215072E7E1FF7BF6776303B +:10976000FE3D73E805B84B899CB1A8B6311859A1E4 +:109770005F3E752FDE17F27D357E17E6CB43BE0EBA +:109780009DD25DD9CE3CCC47395CCE0578DE808752 +:109790007D17F778A867BF847EE06D7C3DBEC43C32 +:1097A000DC57821B0FCE1DFB4907DEC724E0E0BE5D +:1097B000BF433D3B85F9EB036C5F2AF297DC794AA6 +:1097C000623EFB8219EE3376E143F835041E44FB1A +:1097D0007AC91CA50F4037B5671592B4E585F49D8D +:1097E000DBD0F0FD6938EF9205F7AF243A2E29045B +:1097F0003E48A29DE80F353BEE712551B5C77EBEB0 +:1098000024E83AEFE2E617B83F18F4B4660C7CAEF1 +:10981000E57DBACD1579B998A7AE9207C0AE3D15D2 +:109820007C6B06F8E36AA998005739512D3C4F7AB2 +:109830009AEF4BD47DB7E2791E313FE18F13E59A61 +:10984000BD8BD04F57BB3B84E7796A924C0EAEF389 +:109850005907BDB23DEFD64C41BEAD672FEB6F3C13 +:10986000E080D2C7877A753EAC3FD870FE4C38672F +:109870009227D79D370EE0A3323CC07EF9C9109ED7 +:10988000D355BDB6FB53DFE2FBE365DC1E09124B8B +:1098900006782A8158376167164D95DA474AAFDC5A +:1098A0009BDC02FCB0DD656F6D0FB0726B70724BAC +:1098B0007329EA67948BCB023F437BA8C52FCACF9D +:1098C000A29CDCAEB1FB3AACA7BD06E83DDA1ECFE8 +:1098D000A75BCB4A507F2845A400E0360F1C2D2003 +:1098E000FF9EF6EE023FC38FFC896B0236B89D0ADD +:1098F0001F1907FBCA34FD598EFEC60DAF3F3A7ED5 +:1099000017E0417C9F17B91FFBA7EDD0DF41C61CB4 +:109910007A8BDABA24EF692F9E33DCE171DADBE26D +:10992000F920E7CB36D7BD1DBE44B3099B73C19F59 +:10993000EE7B9605BFAA672739F2A4C607593C5BA0 +:10994000554D7055D2EFA5EC7B80D1411BCFC7C9D7 +:109950003C4E4E86719C71BBFEE3CCE07282F07D82 +:10996000ACAAF7DECB3940FEAB3BBEE8966FBD4FED +:109970002EDFF2393DC7A5C4B3415A5E93EC5C10AB +:1099800060FC3905F87335A7D3923D773F076AFD30 +:10999000319FF967D837ACF2991704A70F9F7FBAA8 +:1099A00083623DFDE417B3CBAA999D5BDF3EED4A90 +:1099B00028D7DF51A45B69E245E2597D36E8905F24 +:1099C000F7707F51B56AA11CAB3E1BC1EF9FDF78DA +:1099D0007EC779B6FEE385F0BB18EF16977C3E7024 +:1099E000F14BDBCB291DD73FE191BDB671EA9FE07A +:1099F000E780FC545E3BF9DD047E570B496F9E22E5 +:109A0000C887BB3451565AC12E7AC42E1FCAC16EA4 +:109A1000EB6B0FF716DE15E0F5AD60FAFA4157FD76 +:109A200022D17F2ED677CF47C81F28839DA67EE2FE +:109A300015F343F975B7ECEA2F478C3F06FB13F695 +:109A4000FAB703E35F843B25EECA4E568C66FE1DD3 +:109A500003EC80EFABB180FD3EAC6F737AAD3E7B23 +:109A6000BE03DF7D709FE078FFFBC6A8235FFFE6A3 +:109A7000443D9ED3F87680D16535B5E8B1DD8ED111 +:109A80008E3CFD7FCCE3D3CEE3920CF3B8EC6F3C7D +:109A90008F42077FF6CDA3D8F1FED3CE631FF70B1D +:109AA0003FC79FF375762FC07C4342BFF57C5AD7E2 +:109AB0004F69FDCBF4E9A3CFF92AB14278CF6D927B +:109AC000DD6346CBE00FF8EA27B7BD7B39DE0B6DCF +:109AD000623E8E57E4E3F0731E9BC70C7C5F91FBE4 +:109AE000EF3BB8BF0733DCD3DA1862FBEEBB2FBC09 +:109AF0008A60FE7A28817182FDF90BA260A77FE758 +:109B0000C21A7C36E7CF88823C6A0A7FDD916F4EAD +:109B1000F70869CFC1FE91F74BCE7E59B69F47D962 +:109B20000CE751D2D41771B1CDBE3ACC03FFA2D607 +:109B3000FBE017B4DE4BC38CDE36FB1218176C8DBE +:109B40007E31F37F26C4C6B9FBC2CB089BEF6529E3 +:109B500016F7D10CFB7960F1DC1F9E118575366517 +:109B60002F88023D3767CF70AC47C9B09E5561065C +:109B7000A7CDFA17BB9EC39F793D0BD2E6C1AAB908 +:109B8000E9EF176B17788A2690CEBEA8759DFA1B51 +:109B9000AF6B14C7577588F90D361B8C8F824AFC42 +:109BA0005785D2E07C38D8DF1D21C5863C943CBC6B +:109BB000DF727865E2DF659EE44898D79146B67F0C +:109BC0007E9DDF27F5DBEAA630FAB55DE36C1EB3B8 +:109BD0002B3C909FE37F563BCFA70F26375A422C52 +:109BE0005EF3B584B3DDD2AA60DAFB4D28FCEE2A21 +:109BF0002CEC83673FFC7FCE70CB448FC3855B6BBF +:109C00007478701B8C0FAAE1929BE983C34DD05BE3 +:109C1000A67EFE7FA1B307870E2FA4AFBF15BCFEA3 +:109C20005EE9EB1980D710F8F21FF03AC7F5E6D0DD +:109C3000E025E4D81E8DDDBBE8EEE74498DDAF34C7 +:109C400051AA3B7C05C417BEA2A0BFF7F08E79EBEA +:109C5000886CAFC7F4D9E1CAB9EB30DF351EC47BDD +:109C60003C5F9363FF5E067187C5AC5DBF7972F898 +:109C7000BC14CEE67E4B6324F8115E8B5F3DE0FAA8 +:109C800048A56D5D989769BB8F4AE90FDFC3C4B8DB +:109C9000A30CFC4D0BD3CF43E033D3B8C3C5E76B64 +:109CA000F1EF0F0B9F83ADF7D970D190E485D837D2 +:109CB000E492DEBF977101C0738FCCF2398EC2ABD4 +:109CC0007CB89F8C60A5A555A376029ECA223CEF66 +:109CD0004933D6819FCC7BF5C2AD618AB7D7AEC977 +:109CE00096BC367879230CCF3396A7B70B73233CF9 +:109CF0002FB7B7BD44E03E44773D85D7BB6639BB3F +:109D0000978AA8E6D8C5B67375535CDFDDEDC74604 +:109D100022F8FD351E6F777FCFE2ED972E19B83D03 +:109D2000A963F7B950BA1B9BEE7E41C11F9DE14468 +:109D300034429FAF4B8907BF01743429C4E21E2A05 +:109D4000298478BDE8275725298DC2FD5D8F3116FE +:109D5000FCB469FA291CA89F4C7015EB11E3002B89 +:109D6000C2BD2C74FF88FBC5329390D9B04FF4C6A6 +:109D70006E65870D191DE4F0FC999975C1E446B034 +:109D8000F354BA4EDB7CBBFE6BEEFF80EF5D876564 +:109D90007D53617F380C261F1670BAC955129BFC83 +:109DA000E01F5B21A5BDDFECF208FB3B251F847B98 +:109DB000E3EA38CE84FB121EB8E7E05A9EDF44483F +:109DC00062ACFDEF8C7DC0E58ABB5DAEC2E2D1E442 +:109DD0000DC6CF7B76AD199B8E7F5EE57CFA41B8D0 +:109DE000C4919FB4247EAB07F873C9C2451E2304F7 +:109DF000DF99BCBC86CF638F96187B51A80F4E1994 +:109E0000E510874FD7914413DCEFB0A241C238521E +:109E1000E90646772B36EC97D7D1E74ECE7F8B00FD +:109E200007B6FE6EE578DDB32B300EE6BFA7D74F41 +:109E3000473BA6F3B8FE7E827EAFD591AB3683DF7B +:109E4000AB5B22FCEF32FCA412F20DBA799E480BF8 +:109E5000FDBE11E63B6F24F2F7840D1FD4837CEE28 +:109E6000D2089E97FB8F762FFE7D0B412FBD72622D +:109E7000C3478D907477AF969A0C7433B2A9EE1BDA +:109E8000E9FCE416E7FB0F43F1AC7476AE780A798F +:109E90002EEA2D560D4FBAFA57573AE59898F7081B +:109EA0006FEA54BAFB1A7AE93039B0DEFB3597E332 +:109EB00002EFBDF83E927E5FB423C2E2777B9273DD +:109EC000D6A2DEB2BC06C843311F01AF5C8BC1E92C +:109ED000DA258A43DEAE5818749D476270FDAAD712 +:109EE0007808D671EFAE9726E3DF5174E987809248 +:109EF000D0E0FBCD24E50139715C31F0F97AA3F3B0 +:109F00005EE6D749E28EE9A03F1B94B47CF50CA72E +:109F10009FD7AB565D83F36F567498FFB1E523AEC0 +:109F20002A07F952E5C17B828F35DF16BEC9B67E9E +:109F3000A1EFDCF3FA6DF5AA01F5D6D22A27DEF6F9 +:109F400068CC2EB0AE647CB89ACA9BD9485FDD77E6 +:109F5000CCA4E31F4EE65CB4855527F0F71CAFE6B2 +:109F6000BF1F971377CEA4F2E684CCFC61D63F31B5 +:109F7000B9B1E4BE780BC4794F344CFB6937ADF707 +:109F8000325FDF5B0D03EB47373D4DB8CF793FE5DF +:109F90008C234483F689FAF4FAE0FAEC2093AF6A52 +:109FA0006C1CC897EB36A4AFB709922B69BD137F21 +:109FB00055AAD3E56D7EA2333E59114FDFFE133D06 +:109FC000CCBE835E4A03E7BD59412EE7F47120A75A +:109FD0005764986F575604EBBDD372FB7510EF3B77 +:109FE0002E3BE5F30FB278FC3C8BC9E713BB9679A7 +:109FF00046029E5A251DE8E1EDECD824A0B795CD88 +:10A00000C7D08FF02D5EFFBA50FC43D04F4B8E2C43 +:10A010009E3F92E2A56B3989494666F9FF31E79F79 +:10A020005C85DD6340F5DFBBA0FF68D377D1FE50D0 +:10A03000CD715F9BCCAE6C84BCC213B2B506F3503D +:10A04000760558DE11894DB7DF2F13E0F338B17B69 +:10A0500078F8BE261E1CD08E3F4C3A6A70DCDD417B +:10A060001DE28F872B95D4E57492EFED0EE23DAFA4 +:10A070006EBEC834FE70EDC013BB8767070EB6EE28 +:10A080005856E190ECC03395F7DE59067CA4754C28 +:10A0900049277F859C7E8DFBADDCF4239EB3393E42 +:10A0A0008E27079ED7CDF73BE7735D9D733E825F9A +:10A0B0008E279B02901F4E479F6CB74BC9BCE9830C +:10A0C000E859E6FFCD34CF389FA790134079104F61 +:10A0D0005BCDE5CD5B0DF746EC7870AFFF84CCF738 +:10A0E000070FB1BCADF1F19573461A7DF4795D1699 +:10A0F00093439F375D0A3DE3EEE7EF9D0E859E1B80 +:10A100008C0E855C70B7FF00E2FC23E1EFE3E81AF8 +:10A11000C4653E8818AC4CF40570448694F373CB48 +:10A12000C41807E76E4EEC0AE0FDF6D6166F12FE75 +:10A130006EC7F15D974CB2AF6707C7FF8A25D97824 +:10A140005DCA713976C528CC2F50F0BEAED78FE4EA +:10A150002C80F2BD876490D0E4BAFA950AACEF8106 +:10A160002C9677BE62C32B680F0E97CE57D439F565 +:10A17000FF277C1DBD7696DA5306F493090EED5940 +:10A180003EB6CF892F9A0FF279D50609E5ED962CC8 +:10A1900003DFAF524D94DBA499E947E2A3F0A02A74 +:10A1A000E4182C02E0F1BFF9DF2953E39AFD7CD2D9 +:10A1B0004DDB6E9F0FF6A19B5F46EB8C8EE15E3010 +:10A1C000785E174A3C9935B24F3EBF2DD5ED1F45FD +:10A1D000AB5C9EC5ED6DCEA7623D9767B1F5513B77 +:10A1E000ED87F8F799F8FA48CC456F7247CD4F00E4 +:10A1F000FE737C681704BC54EE43DEDCF7033ACBF5 +:10A200009B637C25EC1D77FB6BD584C36E3C94551A +:10A21000E8C8C771DB21FFD017E9EBFFF96FAC2F5E +:10A2200064FDD3E98BFF0778BAC08E008000000080 +:10A230001F8B080000000000000BDD3D0B7854D59B +:10A2400099E7CE9DB9994966924932933738930080 +:10A250000625780321449E370991A0A803040C1A0F +:10A260007044D4282144C54ABFD2CD0D893120DAAB +:10A27000505DB4D67587885DB6D235586AD1D2762E +:10A28000B0828FEA365A45DA8D1A1FA5800FA2AD2B +:10A29000ABDB8FAD7BFEFF9C93B9F76626046DFBAD +:10A2A000F12D7C7ED733E7FDBFFFFFFCE7B0A22591 +:10A2B00085449D04FF7C49FF3B9C1A20C44FC8F194 +:10A2C000BFCA8DBD6E428E45DA93AF81AF4D5D90B2 +:10A2D000ED2344EF94C9A3B4DD3B473EAD81F2BD0D +:10A2E0007D36AF44CB2BD65F238769BB4C28F9A1C1 +:10A2F000DF9234287F097FE60EFFDEF0804CA2C596 +:10A30000B179AF867518CAC77A923502F3CDF14498 +:10A31000C60709D9AB109D9411F2F6E6ECC8265A8F +:10A32000AE7112DD3D8590B9696CBDBE8D9FB77A67 +:10A3300027D3F5F4FCBA8414D2F5DD7DFB8AF0A4B2 +:10A3400038F37B6D844CA3130402369245C86D7CB0 +:10A35000EFAB528906E3133ADFA386F145BFC3ADE5 +:10A360008444CFA5F5E368BFF2583FEBF8CBAEBC11 +:10A37000702CECFBF09533C75E3329D62F111C9659 +:10A3800049E17F5E0AF3B6C92AC075D73D498D3DC4 +:10A3900071E0A673B85AE7873F76BA8F25FCFF971E +:10A3A0006EACBCC34341B22965CEEC709CF90F93EF +:10A3B000F0DDD3E87CFA46369F759EC57C9EC3F5DA +:10A3C000D72E05F87FA6CB5E99C263A0414EAD8023 +:10A3D0007EF50E753C1D7F40BFD5739D619DBF4FBF +:10A3E000009FDF375EEB898B07FEBDA2DE4C076F57 +:10A3F00093C197A7C33C3BE3AFEF16581FC5DF31AE +:10A40000257CCF85747DC72F96559DAEE7B88DF618 +:10A41000037A7990F60B0CEF773DEFF7F6C691E9EA +:10A420007249AD793D4B8F249BE9D2461A7BE3EC10 +:10A4300067685D6748F72B2CFCB74B191CE3A5FD3B +:10A44000DFDE71EACDDB613F3B9211DED67132D3A4 +:10A4500065C6A7C02700AF2D499C4FBA9B9FA6FD9C +:10A46000DEBE344FDD4486F30721DD97CDA0F5FD38 +:10A470003DB6D22DB46A574F4A6324CE7A27A7330C +:10A480003AF0C97AF279B43D7983E103C80DF866F0 +:10A4900029A7376FCF0F5B882DD6EF0DA0832442FD +:10A4A0007EDBEAC4EF36AF13C7A95BB84809D079A1 +:10A4B000AEB3130DE0877FE8B8DEF30A766CA153E4 +:10A4C000BD6E63657D15E53F69F87A1EE674B92BAC +:10A4D000B27844F8D637C82678D62D34C3D74A9FE9 +:10A4E0004723B6DA78FB17F49C68BE2B1D113FE0BA +:10A4F000E908DFEF61BEDFDF37B67BA0BD759E5D8B +:10A50000919E11F9E0AA46335D9C6E9F6F7A830895 +:10A510008FE56173BF2BEACDFB5D4A5A66134A2A69 +:10A52000CB88EA806F1D6929799A82F2E8034B7023 +:10A530003DAF13520B729E9CBAB56451496CFC1727 +:10A54000393D7F5677EBA5202EDF505A4ABC71D695 +:10A55000F33A8793C0F7EB09E019E572F70DC033C2 +:10A56000D0EB32392E9EFF8BCFFB46C3C87CB4ACF8 +:10A570006E643C9FF07A113E6F34B427C33E8F89DE +:10A58000791F64F3825E33E2E3C457D45B56FE1D49 +:10A5900020FA4D48C791642FE8111F9087418F74AE +:10A5A000A4DB981C2F1E598F88EF6F855CB5B4AF64 +:10A5B000B36B0E233ECABD01849B28D72D34AFF365 +:10A5C000BD54060FCA7163431E83DCE0FA55E8BB35 +:10A5D0007B7F70FE5BA03FC7A7333CD4853E7100F4 +:10A5E0003CA87CBDC303FB7AD5E605F95A7E4473CB +:10A5F00018E137278DB53FBE7364F8CD4963EB3C56 +:10A600009D9CB5EEF7ED6FDF3905C67DFBDB9F3B0B +:10A610008CE32FFB229F443363E5ABEB252D1287A0 +:10A62000CF36789551C17D83058E577F3116C7F798 +:10A63000C9A4A537CEBEECE94E6CBF3454E9F05343 +:10A64000785EBB5152253A84239DC9DD6B85BCB32E +:10A6500007C62EA270F7B7B7DC168A33CE6C0EEFA2 +:10A660003FBB4369F1F84C7C853E17ED96D9C38E0C +:10A6700078EDAD7A7580F3B9B55DE80CE971C80E77 +:10A68000B2B41FED3AE6A6313ACC4C8A7E04F28889 +:10A690004C32DB61A79DD7D2DE3AEF651CEE89E62E +:10A6A0001776AD757C9DC33F1CA2F413B7DE83F50E +:10A6B000AF12A65FF5480AEAC3633BAFBD07CCB74C +:10A6C000EB17DC7608D4E4CBA9416CD7107AA50649 +:10A6D000D9EDD4BD9301EF9FD5DE7B4F195DDA71C3 +:10A6E00025DCEEA11D8E6F92D06EB1CEF32AD72756 +:10A6F000AF813C3D17C623CC5E9D4747CBA56097F5 +:10A70000B5352054C8B79202463BD5B7E1F356326F +:10A7100019EC87D0260FFD7DC2C64FD6835E262456 +:10A7200082FDDF75A83722BC09B373FB7BDC3BB627 +:10A73000D076AF825C80F1893A3654629013762FDE +:10A7400096478B9FDF26C0CF99CA29B1CF44F350DB +:10A75000C8E3FA1657B9BBA434B07702D7C17E0656 +:10A7600017B8BC3D14858B15ED1280CFABAFD86CFC +:10A770006D411C16ED15611F072F0BDE755E19C8A4 +:10A780001F87E6A24B5904CECB85948EAADC3A8C67 +:10A7900057F6DB858F017EEEAD4F0AC830DE9CC0D8 +:10A7A0009B322D2FBE3829007E47795FE1011F1DA6 +:10A7B0007FE942C94B68FF790BC6FB07E8FE5236BA +:10A7C000D071F26079C76AABC711F243986C066129 +:10A7D0000BA6B0582CF1B2EEDB3C8FB63FCFBFD703 +:10A7E000E6A6A09EF85DDF66271DF78EB6508E3771 +:10A7F0009DDA13E91F743967139295A5F5CD5509B4 +:10A8000071677C540BE5BD0F8AF13EEED20A08F960 +:10A81000992D1C9468FDD48CA405760A2F5F91981D +:10A820003F6FB3368BEEE7E21B1F5D4FC75FFEDD68 +:10A83000490BECB0EE06317FE90258DFD259A25C39 +:10A84000EE82B22F85F787F55650F955185BBF3D5C +:10A8500087CE9F21DACF58308FF63D5CD9526DA755 +:10A86000F3FFE8BBDAE649130999BEB0D2ABD1F2E7 +:10A870001319F50B52287EF6124AA7B4FC64C6954C +:10A880000B60FD3ED9C6C7BF6A33ACBFBC413F0FAA +:10A89000EA257DE5E65ABAEFB5CE814340AEEB3608 +:10A8A000E8CE2CFA3F2912E363A7A345CBA7B073E8 +:10A8B000ECAB8CE6E372BA19BD16444B408F0D9594 +:10A8C0008B69B9C450CE61E5BD9BC8D5F1E4ED6D8F +:10A8D000994CEEED4D8E5FAF64307B80C20DF54933 +:10A8E000DA11A2ED8EA3573E4A77E37C079389EEF7 +:10A8F000CC88F1DBE594872B285F12275BA71867CC +:10A9000098FEC8607287E89767803C5D0843D0ADC9 +:10A9100017A912FABBA42525321E688744ED4B40C7 +:10A920007FC8365CAF5F96AE5E44C7CB4A26E13D3A +:10A93000F4EBCF2458A6FDB53DEED8782F71BAAF11 +:10A94000290AED84F16AB2734BDB83B171E8BA3B3B +:10A950009C534CEBB6576440FDE2D29B2719E0397B +:10A9600089ED83D201F6A3D33C3697F2C1DEBEF364 +:10A970000AC17EFFA945EE96F72D7610DAEECA4C95 +:10A980002E5F02ACBFBF9AC99FC19B53223DC09F9F +:10A990004EB53464B03B031C1ED5772EBC1FDA3590 +:10A9A000F53948126DB77E4F653619412F367D3126 +:10A9B0009344A61ACAF6A80272A7E98B39F87BF568 +:10A9C0009D2F29C0A7304E80EE6BBD4BCB56016E3C +:10A9D000EDF1F14F1D725C47D317E9449F6AFC9D6E +:10A9E000C12936BE0FEB4FB7AFD8783289648E34A9 +:10A9F0009E82F54370B773B82BF1D7395FD02985A4 +:10AA0000B7CD405F4B39BD51E9877194FECB26F538 +:10AA100080BC8FCDBB09C7DF6BA778043BB02F3953 +:10AA2000007671B99DC9CFF2BE0CAF2EC5E843D0F8 +:10AA300085C0EBDE8C964ADCEF22C9DB131CBEAE70 +:10AA4000CBC4BAB83ECD6E08CBD718D627F8818EC6 +:10AA5000BF978F5F5681FCF32F4CFF50BE5901FC0E +:10AA60000B760BEC438D962CF60C5FFFCFA8EC8099 +:10AA70002FC52383FFA5EE08E80101B7E1F0CF3F22 +:10AA80000D3EC7627D79DF330AECB32901DF8632E0 +:10AA900053B15FF691682AF8B5BF4C677A6D6FEFD6 +:10AAA00054D74CE08B853602220CF60DF66AB9902D +:10AAB000B764D70B5576FAFB5099CADB00E06148C2 +:10AAC000FE469DCE58FBAACC5D0B3A689D2F89E2CD +:10AAD0007F12DAA14E62F027BE9DC1E4584598C4AA +:10AAE000B55B966532BB45C0FB7B1BAAC97B747FF7 +:10AAF000CFA533BEAC18D025C08BE06BAB9C7A8859 +:10AB0000E3F17BFCFB8F9753D269E4D4222EA7D8C4 +:10AB1000EF07A9990FEDB2B2A22512D589AB5E98C5 +:10AB20003A1EFC995B72E4C0FB94AF9648EA981F0A +:10AB3000D171EB9C018C93093AA923CE801BE04E86 +:10AB40008DA62F41EF2F746119FE805DF269B7C4A5 +:10AB5000E89004D2EA4A12CB21B18E5B72149C6F4A +:10AB6000D5E6F16961E3FAB89EB83C29FA2352347C +:10AB70009CCF4599AE7FAD4D36D4BB993EFBD0A35B +:10AB8000FD3483E2E15589D4E37A2CF6D26F78DC88 +:10AB9000C66A2FD5733BD20FE625F2B10D9DD3ECDB +:10ABA000AEA408615D74F053B37B09E7D7A8ADC9C3 +:10ABB0004007BFCE286076ED15B4F202CA94CE6A83 +:10ABC000ED7D831C7B1ED6837A213A0DF8F4A50C0B +:10ABD00062B2F31AE4508104766B76920A7286E2CE +:10ABE00009E170D045EC2E3AEF73F40B78AB916F1E +:10ABF0003EE0F0011D486A3B427F07F75B4914F4D1 +:10AC0000CDE57353D06E25A76E1D07F10A7F0AA309 +:10AC10005B3A8E938FE3443AE172EF376327F68015 +:10AC20007E12F253E0819C92713C517F505A54E065 +:10AC3000A5E583FE734BDB25B3FD03F650CC7E5AAE +:10AC4000BF793EB597A6D7F6466D5E902AB72FB866 +:10AC50009DB6AFA1F6938BEEE78F194C0F1E0CEA51 +:10AC6000722A8C379EEE83FE7428393CA9C51DC319 +:10AC700007B571C280BF2C857EDD8C3FE0DB99C9B2 +:10AC80009091E163DF06FECD4A65ED87E93D5EAF59 +:10AC9000490CDE5B2A999CB0B6B3F171D73AF5DA6C +:10ACA000AC42A37D1522408776C2EC2C19748F1F0D +:10ACB000F519C2ABFACE8634D09B9FF52D4D239368 +:10ACC0006272D4E1FCEDD8F7A91C899225DF017EE0 +:10ACD000555E9709D8CB7738185D2AE9616F06FD74 +:10ACE00066A6C4F79B27F2F564825F4DDBDDC3FDEA +:10ACF0001EC717E7A3BF9D9FC9E245A9397528D78D +:10AD00000196018AF73432A87B0D784CABB099FCE0 +:10AD100007C71793B1FF99DB0FA509EC873293FDA5 +:10AD200020E6B5DA116FB6E6E0FA45FF1539AFD582 +:10AD30001043FB9564E00E186FE5FA7C53BC289134 +:10AD4000FD3137531AB217F4B8EB524CBFBF49FD6F +:10AD500045DD38FF31367F6CDE14CA70B179E54CC1 +:10AD60004DCB44BF6F96F7E8F9F4E3A2BFCBA877C9 +:10AD700050FE53FDA4ED70A35EAA05B92DFC24E09E +:10AD80007F6F1AF077656DA6DFA027793FAB3C3A5D +:10AD9000C0FDEA035CDFA41D117663724092627A03 +:10ADA00067B8DEE276B1453E9ECECEA674AB1BED13 +:10ADB000806178CEFCAAF6655102FA98F00FB12FA7 +:10ADC000CB6785E512909FB512194F3FD3E799F5F0 +:10ADD000BD9EC9FC109D329CD16F59DC606ED701BD +:10ADE000EDFCF04D1995DF62D447920C728F8DD730 +:10ADF000CCE92178E2552540E57094DB43BB7CDA51 +:10AE00005D40171DC9A993414F74248F8D405C622A +:10AE1000C7FF5617EFA0EB1F7CD9A1F6C0B0FB18F7 +:10AE20009D542E5FDF6EA7BF3B7A256F1289ADD38D +:10AE3000BD41D256533EBE9FCB89261FDB4F932F79 +:10AE4000AA8CA3F3E735B17514F41E90EC0679577C +:10AE5000D0C8DAEDC87498F4CFA350A6E33C22FC26 +:10AE6000111269AB2983F69A1DCE41F27A258C0F17 +:10AE7000E7B55040507AC853D9F86E35225D3B296A +:10AE8000B6DF2EDBA249A027BAB25254D013277DD9 +:10AE9000E1C760BF4DFDD128806B7A7F9F1DEC3DDF +:10AEA000975FDB0DBF8B7D06646F1EC8D9947EB69D +:10AEB000BE6E0BDD1372175F570F93BF32799E0082 +:10AEC0005E4086D0F9B23615A39E12EDB332B8DEDD +:10AED000C822E127D0CE225D04F146701F599B267F +:10AEE000A0BD2FF01AB3AB264E01BBAA686BD4BE2F +:10AEF0008AF67BFAA1F8F1FA17399FD07D1C34EE5F +:10AF000023117F08BD26DA3912F8D582EE536AE3A1 +:10AF1000DBAB5413607DE572DF95B0EFA60E8524A0 +:10AF20004931F8BBFCA12320B7F27A7748001B2BEC +:10AF30009D7564FC50CAA7FBBCF546E29549E275D5 +:10AF4000376D90B5D5467EEE5018DD28E6F33DE12D +:10AF5000677CC2E305B3FDA163008FE67DDB14C00F +:10AF6000F38D3BDF51463AD7192DDCA446E6BF34BA +:10AF7000D53B23B0DFCAE576C4E39A0E2502F2A9D9 +:10AF800069F79EA80DECEC8D4405FE6FEADD732891 +:10AF90008FC227BF499B260762E3E5374524584FF8 +:10AFA0001625C63EF4FFA20AE86D2B7D839D0CF6A4 +:10AFB000CA2117E3FF0F2BDDBA44E1F8A123DC041B +:10AFC000ED3ECC4D51F5600CEECFED99FFBC4459F0 +:10AFD000DCF3445214BE5DB69E1C276DD7759EA24D +:10AFE000023DB9FC618F8FC229C31EDA0BFDD37DF0 +:10AFF0001EB58DF60D249129A8AF470987E916BA29 +:10B0000098BE91F1CB5C5FAAB003A7805C3AD7E70A +:10B01000117614CAAB430EB68F0EC2D6DB99A915B2 +:10B02000C07A883703E7CD6B8A4AE00758E78DD1AD +:10B03000955688ED47BDCE5E05E4FC1A2E6F2A9723 +:10B04000EF94DE33D041A98F9DCFE6EDDE21817FE5 +:10B0500048EBDB6A7CD89E2481BCD9CDCE29D6D0E2 +:10B06000FAEB0CF245EC238E9CA980F5B9FBFB9E14 +:10B070006572268AF427D66BC5E73C1FB3EF2EA274 +:10B080006602FEAEE8C5013ADEA1C2641C4FF0BD07 +:10B09000954FE7F9189DE7D5EF94209EE04B61F6B8 +:10B0A000A4589F68B7CB5755EB4338F4211CD6D62C +:10B0B000DB116F623D354A681CF865CBF878CF5CD0 +:10B0C000F1963240CBF7FDF415A4C7B5DD9286FEAC +:10B0D00042F72BCA5288DBE9FF2E439CF61266A288 +:10B0E00090ED3F7905F5CA257B59FC60EDDE3DF614 +:10B0F0006BDD313A0D9E786625D0D9DADE24E292F6 +:10B10000007F01E4532B9D523983744F7405CFB9EE +:10B11000A89CD451AE927010FC1421873B397F1348 +:10B1200037FBFD46BE6E316E4C7EBA90DE8327A69D +:10B130003CE3A4F05CAB4AAA0BF891C39B8E1F457D +:10B14000394C4821F86B627C2BFCFE99DBED71F0E9 +:10B150007C1BE0D9AA4F849E0D3E5C45E02BF06736 +:10B16000E7701FD2EF3E05D7DBE1B3333D5FC9E2A5 +:10B17000DA1D0EA6473ADA9C11E0EBE7D22F7A5E91 +:10B18000A2F2D293A144E17BD0B6AA09EA0FE6B1BC +:10B190007574D93615B7303D76870FF1974A987C8C +:10B1A00062F2E8BE1F3379D2A4BBD17F6C0AD7AD5F +:10B1B000C673099F4B857309127E5659EA89D1835C +:10B1C00015BF81270E28015A7F492FE38318DC9889 +:10B1D000BE12744BE51CE2BD33539C5F868300575F +:10B1E000EAD7B741FC41F8F5A90D21DD1318CEAF20 +:10B1F00099DCAF9FC6FD7A4785F36FEAD7AFD9F0E8 +:10B200006BF4836ECA7901BF825FA8FF68E2AB2747 +:10B2100038BEEFF731BDFA948FD1D59AB25EE4878C +:10B2200035EFB7201FB96B993C71F79BE52021776B +:10B2300073FB602B8E5393D27B910C7EF2BF4ADE60 +:10B24000769278DD37482DFF097932640FCFDF38E9 +:10B2500045ADFC720A571787016FF76B1FF3B73EB6 +:10B26000DC4511017C696F5146B2874F372E89BE8C +:10B270002601BED770587FB8BBFAC23F409C7157B9 +:10B280001AE6B37CB07BC937FF40FB7FB873AE0AC8 +:10B290007ADAD71E42FA19F4BB54882752F1592B97 +:10B2A000517A68EBFD55EA4C382F7BEC8229203728 +:10B2B000DFE57C79E2C7F20680CFA67F7B7C0ED4E7 +:10B2C000AF894899603F7EB8EB5FFF0A7AB171E7BA +:10B2D0003ACC4B6B7FEC976897DB223BD8EFBBD225 +:10B2E000D0CE3CFEC8B63900F7F6DE76AC3FF1C8EA +:10B2F0000E2C3FF36F8FFFE22F60778452556877F3 +:10B30000E2C7DBFEE92F40E775A92AECA3296C67A9 +:10B31000E7B982BEAD726BCF01E453412F9780DE57 +:10B320000538D533F923E8F95D7EDEB4AADADD0508 +:10B33000F2ECDD2D9EC6787146C5CFF002B11894AF +:10B3400063F512C6D9BA28D540BCA32B9954C0378F +:10B35000655254C9A7F35CD1B0670EDA3DFA3BD70A +:10B3600043FB25FB5C640BC6E520A84BFD0124755F +:10B37000424AA8183C4AFD663AFACE2F29DD1EA69D +:10B38000F201F58EC51F58D2F5C2FF801CAD730EB9 +:10B390001C0051287EEFE2F11BDA1EF54EF9FAF897 +:10B3A00071D254BF9BD32DD39B797B171504504E7C +:10B3B00024A9E30DF6E998232D5B203D29AFB1EFD9 +:10B3C00022D8C7C5C5D74C45BA80F81FE81FDD8D08 +:10B3D000E3AF85F825E5BF73FC3C2EE225BE19746A +:10B3E000FE1A3BF1B9E14BC86B0E94238FE2B8D43F +:10B3F000FE40BB2AF0CB2B1E057B64BB239C3B0D80 +:10B40000C6E9E27A6B275B37EDEF8573543A9E7796 +:10B41000C6141CA7CF9181FD75D67FFECE3629B606 +:10B420005E4AA963416FC178656ED0337A3DE227E9 +:10B43000A0E0BE4E40935CDCF7E4152531FEB5C6B6 +:10B440007D409EC1F9F06C7F65857F5AEC2BE2410F +:10B4500056786EE4F53FF36BF825BB324D7A2591B3 +:10B46000BDF2CC151F33FDFBB37750DE34031DC393 +:10B47000FCE1F74DFAF75A41C74FBD83747CED3EAE +:10B48000A67F9BF7952A40B71FB46AE43D6A8036D1 +:10B49000F3F3D7EDD2C0F598EFF294CB0B71BD8FDB +:10B4A000B9BE59B3F59DA3706E5AB82F17FDFC8F26 +:10B4B0009F72D5C338076D3684E7C19EF377B44BCE +:10B4C000C67532BF80DAC148AACDD44E6576F0EA9F +:10B4D0006DE0A7AD6D242AF07FB3857E9AF7BD821B +:10B4E000F422ECE0E0C38B5733FBD3A5BAC08F9BAB +:10B4F000C7EC5142ED51689F3E2FD2A6207D959614 +:10B50000037D3D73C52F3A418F37CF235E187FFBF4 +:10B5100018EDA97CDC8F4420CF65BBA3BBCA4EFBD2 +:10B520006FAF0978292429DC76A2DD4B8A15AEE7B6 +:10B5300056A3BDDC9C73958A7C6695074FB5A1DD4B +:10B54000D51C48C6F55CB24FBA85D9236EC2D62F3A +:10B55000217D5E12991981F8D9471C7E028E1F3B0E +:10B56000FA56023C3EFE0925445A7FC93C46AFE9E3 +:10B57000F37A518E3CF7D47CD4E3822E3D4F26A142 +:10B580003ECFB07B2515F5DA9224235EBB1D4C2FF0 +:10B59000A5733D53B495E1B793F353A7DFC6BF8AB4 +:10B5A00039FEE2D52783DEFD88E31FC508C8772E64 +:10B5B0004FD6AE8E223F35ED66E3F992B4D25B0DE5 +:10B5C000F4EBAB667A519C07C0F9C0A238F2E231C5 +:10B5D000BE8EE0C3ABB681BD7C31C53BA894BC62D6 +:10B5E0002E47295D00DCF21A43480717FB6E5021F5 +:10B5F0003FD59F49D05F1C6C5348BCB8CFE35C8EED +:10B60000FA3343651087F6677BD0CEF1CB953617BA +:10B61000F42B95D49E009E7BA29D37E8CF557B4CA2 +:10B62000FC1E2AB3D176C7B23C0CCF91DFD8179756 +:10B63000001F06D8B816BB6FB8DFCDECC685DDFAA3 +:10B6400064F043C4B9868043A42DB9DE283F7FC28D +:10B65000E11099C8E2A9D4BE77635CDB4BE701FF38 +:10B66000BE67E623CCBF6FC7760FFB997D5443F7C7 +:10B6700007769BBF28B49EE9538F1A0F1EB3FDC2F5 +:10B680002E5F590A7E65739D5B057EBBEF67D22AEC +:10B69000A467081682DF1D5E8D7820140FC00F246A +:10B6A000CCFCD2E69650243EBD2F42FE6B06FE93A4 +:10B6B00090DE310E4FE93DC2E89DE93FE1FF837C1A +:10B6C00034E61D0A3920E44BB3323001E858F04328 +:10B6D000F39C810900B7D1CA938F1D94FF817F2805 +:10B6E0001C807F04BF789E667CB2A52D5009F55B57 +:10B6F0006A88B7DDA08FACFE12AC13FC4E21D74F89 +:10B70000FA42C7FD1007B0453B21BF42C8E1E6A79A +:10B71000374F8897FF26E4B0D3CEE49B339212696B +:10B7200037D0179CF979A6E017F3795236C48F8F7A +:10B730009CF2BB791C7F74F91259A0CB41DEF4A4B2 +:10B74000605EBB881759C7FDD82F99E232C26F815E +:10B750007307689F93C5F827258BF3679688CF46B4 +:10B760004CF41FB085DF813CA344FA4BF4FB5BC56E +:10B77000AFC43C428F5AF12FCE4D603F8B26256ED1 +:10B78000D77D80C9272B3D4EE47C72147C0FDAEE06 +:10B790003FF839D770FCB2714878A2292FAECBB6EA +:10B7A000A7315E1C4C9C779087268E2AEFEE402BAB +:10B7B000CBAFFA0F9E674B564F34E559B9D5401BB6 +:10B7C000C451AB9CC15219E765712CCF1CF209E83A +:10B7D000E1C9FBBA8B217FC91F329F9764D7279B92 +:10B7E000CE2372C319A6727E639EA9FD989642531A +:10B7F000FD391BCE33D507F529A67251D70C53FB63 +:10B80000F1DD55A6F2B90F5C6C6A3F31B2D854DE57 +:10B81000D2D65B0F78397FD795A67E5576AFBD948B +:10B82000C2B5A47795397FCC02CFB4BFCA71E9B055 +:10B83000292B8878ADB29BF3882FD8678607A4CBD5 +:10B84000019C27133EDE9C635346CA6F9D4CEC7FE0 +:10B850001E10FD83C3E9813807D4501C3F53D0B973 +:10B86000285BCFB584FC3853FA4BB44E417F89EA4C +:10B8700013C1ED3B9CFF055C1C4370A95747828BAD +:10B88000E3747021142E9EAF0E17EB789B529A3101 +:10B890004FF8352818ECE38156F37D98657A1AD372 +:10B8A00043A125A7B1A3591C389CC4CE2BADF5FFED +:10B8B000C9E1F2218509E261947CFD16C7437F222C +:10B8C000BEDEF0C9C16C90DFB504FD666F4BDB27AF +:10B8D000A0B7AEB64709D0FF7D7C3FDB79BEE80359 +:10B8E000AD5E1CE7417E1EF9506B007F7FB8B51836 +:10B8F000BF9156157FEF69ADC0EF4E6ACFC1F70714 +:10B90000ADB5F8DDD51AC2763F6CADC7EFEED630D7 +:10B910005BD7307C9172B473429971E3A5D7E8F29A +:10B92000A8F044E482B8FA32E13872C388F9E51B22 +:10B93000FAA5C79F35F0EF5B591EDF51C86D9C4ECD +:10B94000A6C3F9E6E9FA7FDE4A1E7F76FCE8F948ED +:10B95000D013399539211E5F87795EE563DB57DDAA +:10B96000A54F4A0CAF189DC587539DF3E33C70D695 +:10B970002783CD60E82FEE9F88725D382DAEDD9075 +:10B9800097CDF46E7D123B8F5F6EE1EF6F6533FAFA +:10B99000FD5636D377BF4B2067D2793D5DA703CFE5 +:10B9A0000787F1DD3DB3E3C1F7AEEC80292FC57AFF +:10B9B0006FC53ACEEF1CDD63D4387C76BA71C4FE15 +:10B9C000ACFDAEE2FBFF663661EBFF7FC69FBFBBFF +:10B9D000CE83FE03C0CD6FD8FFEFAE4BA98F179774 +:10B9E00069CF66E7A1D43A27C10C34F575056CC55B +:10B9F000621260E7BEE3BC101F12790189E9D58E9F +:10BA0000712484A13C1CAE141F01A5888E6F1F9A5F +:10BA1000276A8779545B4CCF42AE0D31DCFF9087AB +:10BA2000D303EDAF2B98D7339007EB3B537A22F239 +:10BA300043E3473AA71BD6FF0CE5CC9AECBFAF9C7B +:10BA4000117C4E4EDD3B3E9E9EAC87B967507BEC31 +:10BA5000FE87989C39CDB8670ABF7A7900CFAF4787 +:10BA60000DBF7DBE51C5A53E77A54E26D4AFDBE008 +:10BA700064DFDB93537BE0FBB96B6C84A4527E8163 +:10BA80007552BED5AB08BBBFF596F09B5AA683BCDA +:10BA9000DD9E1B7A309B8EB34A61FEE29FB2B4EF0B +:10BAA0004339999F0B27F37361255BE98432D18A6F +:10BAB000715F17F07D75DA0263615FEF4BEA44F066 +:10BAC0005BBCB6880ADF54122D61F9799130F86BAE +:10BAD00099E72707C0DF4D9E40481FC6C75517C4CA +:10BAE000D19494C117C701FFFFD286F7A21FF7B206 +:10BAF000753EFE403E9EB350818FF26232FC4EB7DF +:10BB0000B205EC72DAFFFB52F8896CBAAFE35EA7BC +:10BB10006EA3EB9ABCF9BD8C0CFAFBE3FBABF05CBB +:10BB200021BA4BD615B8DFD0F7E1772FA1E35DD06E +:10BB3000E7C0F8F3054446F9BEC64EB6021F25829B +:10BB4000EF07DF889F07E6C8914CF95DD6FAF7B991 +:10BB50001EF82041BEF16BBC5EE4CF3844FE8C5F22 +:10BB60001B317FC661C99F71D84304CE851D43F93F +:10BB7000330D04F367E838C6FC990FAAE2AFA39F20 +:10BB8000CB73C7172909C64DC5DF3F281C799F8E87 +:10BB90002F5CA67CEC587F37FE9E287FE73301A7F9 +:10BBA00004F94B9F0CAD2F97E899C67E8CEF62F39A +:10BBB0001460BDC3920714AB67F93F1DE98C4E0EAC +:10BBC000E4787DD7D0A1AF2103789FF36AB7CF0186 +:10BBD000F1A41051F7E0FD1EBB637040F06121B489 +:10BBE000B3BF0B76B78D4A5EB0BBAFDEE07877C0EF +:10BBF00020B71669E63281F60639BC1862D8741F80 +:10BC0000C9E71563FEDFA72490E61D418E3638E5AF +:10BC100090DDB08FFE0476C4859C0EFB73E3C3AF4A +:10BC200030C766CA631ADE9FE703F07B68B77A47BE +:10BC3000969F00DF70A6717C2B1E7C587F3A38FBE4 +:10BC4000E1B00DE26A9512CBF3FF9BC33B9DE7BBCE +:10BC5000B1FB030E4BBEFAE25CEBBA59BEFAFDE94A +:10BC6000A19939D82F30C1785F60AF5D4B9942BF41 +:10BC7000FD5CEE58E1B289C3D9BAEFBD3CEF3E5945 +:10BC8000262D7B0CF0B7EEF71B398CCE45FB0E074B +:10BC90003BCF02C1E7A4726F0561726F454E21CFA1 +:10BCA0001F4FB703BE1AD8106485F7109E2F0938AE +:10BCB0000F831F87BB158E21125809F9DDA783E773 +:10BCC000865C6D450E9DF79A57921590FF2B9D83CC +:10BCD00007C1671DE8B31D1E47BFEFB8C71DDD498B +:10BCE000E03CAEF8C967E837B542657915641EDAFD +:10BCF0003F929E2F7F79FEE8ED9FCED47031F0C742 +:10BD0000FB3C3F5BE8A5CEBC131320CFFEBD8CCA25 +:10BD100029B97E8CC36B9940473F4F6274F4001D74 +:10BD20008996D7FD6222DE87BF2A37AC423B91E776 +:10BD300047B4C109909770A670A27F1C4047A783A3 +:10BD4000D39A1CC2F831353E9DF4E4B0F8DFE9F82F +:10BD500003EFA195FDFDF843C0539C6388F5A9B995 +:10BD60008C0EC557C0CD9A4FA4E6DA783B96AF78D3 +:10BD7000556E08E17C72CC27475D74EDFD4AFCF7F7 +:10BD80001D9E1CE5FE05BCFF5E72B83F39FEFA5EE3 +:10BD90004CC0C7FFA8F54DCDE5F43339FEFADE1EE1 +:10BDA00025FC4264F0ADF4BF831EA3789E0A78267A +:10BDB0001D83281FFB33E2AFF3AFA35E67D8F1F713 +:10BDC000D0B782BE897E4D239EDFE724C73DBF5F8B +:10BDD00046FD29F087ACE7F8E2BC9ECA0FDC6F9DF8 +:10BDE00073706526E07D1EDF771689A6C3F9E62FFE +:10BDF00092F03C60989EE4FC41E195920BFA64E17C +:10BE000020C635FA27C4970B29B98CEE86DA77B1AC +:10BE10007912DD43C8CC9546750F819485311E5843 +:10BE2000E97447658A875B383E94FC9B54B00F2BBE +:10BE3000735E3A02FBA4F0FF70089E86FCBE13AD51 +:10BE4000CF7BC73912CBED35F213E52D71F63321D7 +:10BE50002B3C21D7106F5CB3EB05EF3803BE4AC80B +:10BE6000808DDDA31EB499FCE46C72467EF27E17D1 +:10BE7000E397F73242A80F403F80DEE97CFAC252D6 +:10BE80004026D81990DF33E8494639DA9E37A3387F +:10BE90006080676DAEB02FE50476E3D7BB1F10B3AB +:10BEA0009B2493FD1A1BDF8EBF0BFC54BA5F8C8B57 +:10BEB0008F0959DAA500CFBF646897C1D70A3FFD43 +:10BEC000CE59E978FF00E0373736DE10FE13E0F98F +:10BED0001B595A3DC04DCD0CB0BC0191D73714BF92 +:10BEE000B07B8F3A63F01E2D5E92797C8DDA0DABBC +:10BEF00061BD4A12E747E2C67BE4C26E2116FB86AB +:10BF000014337F7745CE4BFF03F19FCE54C6B29DCD +:10BF1000FFE4423FF06AC9ABC0BEA9FDF1E6F76994 +:10BF2000FB3089BEF92DF40F859D91227F9932FA5D +:10BF3000750AFFF97479D6CF803D46D7536573E310 +:10BF400079E733747FB9546E5429EC5B399F5215ED +:10BF50001DAF4A2ED83F40D7F51939953C9B7EBF7F +:10BF600043181CD6BFF2870CF047ABEC8E1346B9D2 +:10BF7000658D7FDC956B8E7F7C4616FEE67C80CBE4 +:10BF8000AC0C84CBE4A7E6651BE32F43F10FBE8F17 +:10BF900025FA354C9E5AE49C906736277B6F84685F +:10BFA00024E0CDC2381283BB2EE1FB57B345199C68 +:10BFB000145A9EC59124417FBAEFD9FC4B56857324 +:10BFC00040CE405A0FCC47BDBF1CF8B65FA806E074 +:10BFD0003B570AD9D93A222C0F91B414407B9B735A +:10BFE0004086F945BC02579205E3887959D9C3CBFD +:10BFF0001D759FAEBC2E303CAE41DC1EB47F15BE1D +:10C00000BEE35EB76E33C43B92DCD1E398BFCABFD8 +:10C01000D6B8C7EDB2AE43FE7632E94579E9767F10 +:10C02000A40330BCC42B41F9FB52F8E7C017479575 +:10C030006E12A4BF9FFCF9E704DF65831B6245F025 +:10C0400035EB27BF7B3DE645FB43768B5E0A4BC055 +:10C0500047D9F5D6DFCDFACA49FAF1FE90140DE5BD +:10C060007C9979FA784EA2388EA38AA17EF0466632 +:10C070000F1F4E66FD0F27B37E6F71BDD49CA110BC +:10C08000CC8BC9723AC19EFFD8730CAE6C823EE96C +:10C09000027DE274688857A157D6EEBD9900DE9AFA +:10C0A000F72D4238FC5E62E7A4FA0A09F319C4BB13 +:10C0B0000FF593C8CBB4279991C7FC94A5CF8757A8 +:10C0C00034D172DD4BA4244ADB95CE0DD5C0FB2EB6 +:10C0D000ED2544DD44CBEDAEF08F7E02FB7885BDCF +:10C0E00037B68EDFABA59858B39B8EBFE3CA31EA53 +:10C0F00016D852F56027E40B0D6E265EC82F194640 +:10C10000BFA7283F507A7804CA74DDEB5687FFE555 +:10C1100036DA3EF725A2621B5E0F3E0AE04FE2745C +:10C1200001BFCFA5BFAFE37454B45F62E7FC3EF636 +:10C130000E180E0EEF7439D9FFAEDB5F79F934BA01 +:10C14000AEA2BEA948DEE3687BC883824C04D69EBB +:10C15000D8E2B51F07ED0370AECFF043F2147C3F79 +:10C160008970F937DDC2873363FC80F5A5BCBC8ECE +:10C17000EB2913DFC038D46FD7CAD9B13FF6F331FA +:10C18000FE5089F8C3F8790689FD8171AB63F3A08D +:10C190005C9EC7EB0E2E5F80F9DFD3EDD103C0EFBD +:10C1A00033F9B7947F81DF9D148E57D85B0EFAE97F +:10C1B0007ED23710B50D666908B4C37865242403B0 +:10C1C0009CCBBD9BDB617D1736BC9209F475735E19 +:10C1D00011D2DF2CA75AE4A224D25EA1AADE2278D3 +:10C1E0006F4C42B82CAD774620CF6DE9D07B3FE154 +:10C1F000E032CA3F5784257E0F3F1C6C30C46D452A +:10C20000FEDFB224EA5FC791DF37E731FD2EFAAFD8 +:10C21000E3F75344FDDA3C37CBCFCCBB68461E9ED8 +:10C22000C7B0BC68CAFFB3F3A6C5E40A9D17F356AE +:10C230009610CD01FB5AC2F957F0FF52ED56B46784 +:10C240009786CC76E9EF25866F7DB98476E215F581 +:10C2500023DBAD0BF3C4B9708117F500117A8AD1D5 +:10C260009590E78B41BF831CAEA5FADC603737DCC5 +:10C270007E2A1DFB65FF60ED97E7C4EEC3ACB3DC1F +:10C280008769E6F761D6ED6B736401BDF3FB30EBB4 +:10C29000F6BFD369CC0314701A7E1F6610F31F9784 +:10C2A000299103704F68D94D748FB4FDAFF8FD89A3 +:10C2B00067E1FEC494181D79AE7445597E9D867958 +:10C2C0007E05DE1415F252BA6C5330AFA82BD5A3FD +:10C2D0001AF378B6B4B5D4403B914F24EEBF2C4B43 +:10C2E000706EFCCD3C663F6F97585E97BEDC89F060 +:10C2F000F6CBE488F19EBFBF2884F97433F202388C +:10C30000CF761E5F80FCD3A9F41BA1661AC317EB7E +:10C310006F950F74BC0E18AFBA48C53C9AEA3496B4 +:10C320008FE6CF0C95DE3229366EDD7E96BF57172D +:10C33000FAE410CBC35D5406F04C24D7ADFA8BD28F +:10C34000DF3D408FC3F556B819E8CF51155A7E1D11 +:10C350001DF7E4CB0AE6DB918D9AE4A0ED7EFC822A +:10C3600057857B781D95A14535586FC77B8259F558 +:10C37000249A44EBCB5E527A20CFAF91742B304E8F +:10C38000A3458FDDE47E56013EBD69A72346970491 +:10C39000F213D52210784DBB87C545500E09F964BC +:10C3A000A56732CE2C874A85DCA5F281E5F73530CA +:10C3B000BD477E20417CE8A4E798CCFD6B947BD3FD +:10C3C00084B0B2C8FB69FB9F437B46C0730E9517D0 +:10C3D000E0C749F0FB64EC87652A4F8B21EF742698 +:10C3E00049467A1B6647F0F5950DAD9FD94D424EF3 +:10C3F00056561002EF2358F143E7433A17E77D7092 +:10C40000B402E70833F9FC9FDBB449D120E08B4448 +:10C410006C14CE9D520BEA1D27E481D2EF16298CB5 +:10C4200072F1A7BA2E035C2F242D4B160611EF2FA5 +:10C4300001DE6739FB52000F4715D509F5359030FD +:10C44000885F33BEE6BBEFB303BCE6E758F1A2DB7F +:10C4500001BE0B02C3F085F70BB404F8D2845C2153 +:10C4600066B91224A7D8FDE6CD876E03FFF874F6EF +:10C47000C9F7B2C247E3D1AFB05312E5E59DE4F28C +:10C4800078B47979271DCCAF984106AEDF2D0DA782 +:10C49000938F0F6E90730CF424E8F4699EA72FFD20 +:10C4A00092E7FD967950FFC5F425A383725E9A0149 +:10C4B000F465A083D9FB5C5199EEB394F79F01F426 +:10C4C0003025A62FA33677402904BCAB5DB23CDCF7 +:10C4D0004ECECA0820FEA7DA34C4FF34EA8171BB0D +:10C4E000D39D4FF75FE1EC6DB70710FFDF07FFA6A5 +:10C4F000920410FF9516BD53EDAEB3039D543BADB2 +:10C5000078D610FF35DE61BFDBBE0AFECF01FC0B23 +:10C51000BD320AFB94E27F42FE08E78D89F07F413D +:10C52000BEFB8CF23205FEAD781772608FCB5BEDEF +:10C5300086787023CB4B9EFAF2B8762867AD0DE271 +:10C540007D993DE9EAAFB0BE85D597F56932BCCF9C +:10C5500058B49ED6D3F29E60A81ACAEB3648284734 +:10C56000A7BD166E87F2B88DACBE7453CBAFE09DFD +:10C57000B3753AEBFFF4F14E7CAF22D2C9FB57768C +:10C580005743795D17EBFF478F5307BFBCFC48A4A7 +:10C590001D7E9FB895AD43D87D7339BDED919EF852 +:10C5A00015F6EB66FD6E38E44C66FE12B3E3E6F07A +:10C5B0007DCE7D88EDD3F7DEC5B5010AF7EB0675B4 +:10C5C00007CA0D5B5339CAD1047E5AA5D45D00DF7A +:10C5D000F9544E10C43BA5D34296B7DA43A75893FB +:10C5E000CFEC2691EF0979E78B0CF85A93CFFC0832 +:10C5F000D12E2B83B0FCE407D9BBB3221F357A3F81 +:10C6000091207E007B44FD9B203F757E510BEAD339 +:10C61000F9E788BCD401FB2A3A6FE9977FBA289ED4 +:10C620005F7E4B3EB3938EF13C7AF17B63246803CB +:10C63000FF640F100FBE03147D19EC963DF0BE9100 +:10C64000E11D923D4156D6F3F7DFDD459DDC1B6CC5 +:10C650002D761D94C05809DF55B9AC8F44D352874D +:10C66000AF7FBE9D4459FE045BFFF5ED4ACF1683B4 +:10C670001DBF54888F59E351AFD4713C09B9B194AF +:10C68000E38BF2F9E67CBAFE65CE16B41B9713A6CF +:10C69000D76F24118C6FDC68E1F335EE3FBF65B3D3 +:10C6A000411CCDCCCF6BE972D8F9FAE0C3BFA3F03F +:10C6B0006F7CC0E305FDBFB6D7DCAEF181978F304C +:10C6C000FBCBCCEF8D82DF23667EA70605E3F7FB6D +:10C6D000CFC3731B713FD0E51C7C4B27B1FD0EE926 +:10C6E0007D0BFFB9E0BE6031F8353696A7C8CB6246 +:10C6F000DE4FBB995ED6A95EE67E108ADC4FFB2F2B +:10C70000C17CF852A147B99C11FC5CCAF5FC303DD4 +:10C710005E6BF577EE433E99CA4B56FD2DF4B6B8E5 +:10C720008748C745FD4DF5F5CB1A5D6F9FCD1D01BF +:10C7300078C7F47604F9688A93CA6B1BE2EF00E0CD +:10C740006F1AC75B3BD7EB09FD03F7FAB8FE01F59B +:10C7500037F01C61B85F1035D9FBC3CE3112D8FF5A +:10C76000437873517B2A05FC7DC2ECE23C32AA3C43 +:10C77000112AB7DFCC1F416F2BCFB0DF0777B8305E +:10C78000BE20E2EC82FF5E2F6076F8B65CED3D9055 +:10C79000FFFD7CBE7E3E7EFFCDF3F1FCFBCF44C3AC +:10C7A000F36FC867CA8F937F01E7DF1D8678697FC3 +:10C7B0007AFC38F8275CFE941610FCFEC9AF7D0A9F +:10C7C000EB3FA6B038FBB164FE4D65E714FF3BD4E8 +:10C7D0009EC98F4CFE15EF911FCB30C7E7453B3FFD +:10C7E000FFBEDFEA0C7518E2E181FB935A408FF936 +:10C7F0008B785EFC7A46C7279F4ADF617C272E50E4 +:10C8000050595A300DDA694A2EC4679E62FAA2D98D +:10C810003EA0C0FB3E3E7F38A5C00FF79B88F604C4 +:10C820008C1318509650789FE4E7FE27F97B402739 +:10C830005DEC2BD6152858540AFD4EDE3C80726301 +:10C84000A8BC6800E542A02084F39E5C2AEA79F93E +:10C850006E5626DCAFACE47C8271E33871E2E171A4 +:10C8600061F37B37EB94F8E7D5A4C0638AF7AED8C1 +:10C87000CFE2902B9DA4339FD65FBD3F1BFD8DC69D +:10C88000547D02D0C3D78DE39E1CD387FBDA523987 +:10C8900038F6C1323C17C678D1DAFDCFA1FC5B2B4C +:10C8A000F866AF996F66178CEE3CC51A671F053F97 +:10C8B000CD2F18C10E7A12F4972386875B787E53AA +:10C8C0008DDC540D71A54F5713BC677BCB0B32D257 +:10C8D000D52D3F92F0DD0961C7ADE5704EB42FB89C +:10C8E000A71030C815B8A71030F875704FC158861A +:10C8F0007B0AC6F6704FC1580FF7148CF5704FC104 +:10C90000582E25D7B6439C6E5D17F14602ECDE82A9 +:10C91000B13FDC5B3096E1DE82B13FDC5B30963FBD +:10C92000250C6E9F3E2463FC1FEE2F18FBDFF0C228 +:10C930008FCBA3B06D17CB536B7751F8031DEA5A19 +:10C94000DF240A9FD51C3E70BFC138EE07A9173DF2 +:10C950000FF859DD77FD42F85EB0EF26D3B8A49BFF +:10C96000C9E316FA17E0783D09A5813F37850C1E0B +:10C9700082784773445261DE1B1E30CBEDA1F74C29 +:10C9800022E6DFD71043FC37383CEEBFA5C0E343B7 +:10C99000BACA2379C6784F8C1EDC6A14E0F09AACD0 +:10C9A000C6A38752726E1AC6799E97218641FE48A9 +:10C9B0005AB6CF920CE703167824E598E9C21530F1 +:10C9C000D3454AB1992E3CAA992ED22ACC7491AE65 +:10C9D0009D37227C336BCD74B2466E42BE1770AE6B +:10C9E000A07F01CE53E0854A802FDD27C48BADF0B8 +:10C9F0006DDCBFAD13ECFE3385EF9316F87E466613 +:10CA000055BB03585DE72C8FD93165CFB7E021B016 +:10CA1000357E2AE028EC081107A5FA1FEDE9985F9A +:10CA2000CFFC3D6A1F1C2CC0F303E6E7012581DC27 +:10CA3000BC8E84513E5D67B10F6E70DFA7807D3084 +:10CA40006CBFD43283F70BADFB057B8B18E25256DB +:10CA5000FB40DA2F453D9361BBFB859C0E7F89C669 +:10CA600090268D466EF47AB4FF02B9058EA2B3DC2F +:10CA700014378E6BF7897508B888F993488B9C0337 +:10CA8000F45C6CB5CFCCFEB5F0C745BC5DC4B585D4 +:10CA90003F2DFC182B9CE57382ED40FF53BDC28FE8 +:10CAA000EEBB0A7E17FEB3D56F1DBA170090857BCB +:10CAB000373C4E7FA77F9593BDCBC7F84EFCDEE990 +:10CAC0005B9C36523EE61DADE67B30741BDA88F780 +:10CAD0008A00645970EE4420A842B65E7A6800DE8F +:10CAE000DAD97AD98B83CFD2EF96921F0C6C82BAA7 +:10CAF000535FCA00D7A1783E61F78415DE4F29E85D +:10CB0000BC19F468B26A27EF1AE8C24935D5BBC52B +:10CB10007C5ED0133943F5BF319EEBFFA3BE775146 +:10CB2000F8BC3B7E847A456D8C67D759E1259EC35E +:10CB3000704DBAE838D8272E62D837EA4343598E69 +:10CB4000C10B55AB8CF7A644BD06EF977CDD7D018C +:10CB5000DEDF7518CBD157DE7718D71F617905F660 +:10CB60001081FC5BC547EB8DFA65880E2943951B48 +:10CB7000F6378A7D01D380FBC9EC1286EFBFD5BEA4 +:10CB80003A2CF88271435967F5FAF4B37C7DD1B33E +:10CB90001CBF64D1D90D3F6DD1D90D3FFD2C5F5F16 +:10CBA000F42CC72F597C76AF4F5B7C76E3573FCB95 +:10CBB000D7173DCBF14B969CDDF0D3969CDDF0D39F +:10CBC000CFF2F545CF6EFCEA6807BA2BA204DE97D8 +:10CBD0000874103518A0262BFD19FCF92295609ECB +:10CBE00006E17E4921F74BB66D6DA90717EA115D85 +:10CBF00009603C88FAF739B47E2261F58F742DC63E +:10CC0000386BDB980979F05E95BBEBA2E3707F6F20 +:10CC1000A2CEFC71EBBF1BB64833FFFB6B9757648A +:10CC20009ACAD3FACCEF575CD55864AA5F1E3EDF90 +:10CC3000F2EFE74D35FFBB64A19996F7206E26C64B +:10CC40007B918524AA427CA5F06E5B159C9BD9C183 +:10CC500067BE90FEB753C17E1AFD6BF45F0AA92729 +:10CC600034347E10E0A698C6775BEACFF41EEAFE65 +:10CC7000B1F1EFA112786432CEBD736B1E26B1DF25 +:10CC800088F13981AF3B37DBD0E5FD6C2BC1771ED6 +:10CC9000AB23011BBE83CEF1763E273DB1EF48ABFF +:10CCA000F93E7AA14EAA009F451DC406F1B5E04E9B +:10CCB000A26A04E34248278FE8F1E9E411E2AD8279 +:10CCC00077B91E8910FC77B2045DDCE908E4C1B9CC +:10CCD000DAF95D8C1E049D04804E52212FC8FAEEB5 +:10CCE00080155F644A94AEF591AD8519C67C54B247 +:10CCF0009BC1DD49FF8E84AFE29D667C0588A1FC67 +:10CD000015F0F5E9D7C497E20B45D37C10CF240189 +:10CD1000C8933A3866820DE011EC52D1FFAFA5CD31 +:10CD200000CEC12EF69E9AC093186F6B2B89CE331E +:10CD3000F87F4135AA019C6BE44955907FBEA30C56 +:10CD400043C6C3F0B383789321EEBDA3CB968C6F1B +:10CD500054EFA3782921E4BF372F4B2BA6F53D4193 +:10CD6000920CEF6CF5B4D9F0DDB29EA7A47AF3BBB8 +:10CD7000CAD1245B0EEE23C956815F3BFB6AFC4B94 +:10CD8000ECAC3E2A4379ECC661EF7EC8509F5E6BE7 +:10CD9000F97703892641FBE473581E679A667ECFB4 +:10CDA000C651619607148C7D39E5106FE1F4CEDF32 +:10CDB000498DD490C826BAEE73B8DCB1D251FA1DB1 +:10CDC0008B9198DAC67C03E5594F9B82F077707996 +:10CDD000453632BAD0E95FA0A7740B1D7954331DD4 +:10CDE00039E402CCC3157C25D623E66F1B93956CE2 +:10CDF000C775D9F13D6C87554E58D6E7866020C57A +:10CE00009DDB4722115AEFD0197F10B91F7F774C55 +:10CE1000272433F815D6F935E553E89CBF8D7CF20D +:10CE2000F031EF9CC6F6F999CADEB5AEEE60F4EECD +:10CE3000D9CAE81D6E74B37C2D6D61AEE15C752FAF +:10CE4000975356B879FAB46AA0E78BE49734C88F41 +:10CE5000B8FB3546FF6D630E3F0FE5AD7733F8073E +:10CE60005586674A2F6A942EFDEE3BDC98173CB539 +:10CE70008CE20BF0FF92599E4CEB33C3B1C82237C2 +:10CE80008209E06AE5D74470FD96806B39856BD1E5 +:10CE900099C355D1997C4E9FC5DE593C384661FFF8 +:10CEA0003EAFCEE098AEA9287F2F924F45D368BB06 +:10CEB0006D1A9537749DB51A83B7779690E36678A7 +:10CEC0000AF922E05FC8E1EF55BD2FC0BFF3E2D6FB +:10CED000ED2420017CFF5B033BA27B9A9037830407 +:10CEE000F096A631BA1570EE9ECDE05CA871387749 +:10CEF00071B8494402385BE9D52A9FD3BE269C7796 +:10CF00009DC3E3F159A4FCABC0795B0A7B47D931DF +:10CF10008EC1D5E11E8C829CED0ADA715F07820A10 +:10CF2000D67795B0FAFB5356E680BEEDF277E60071 +:10CF30005DB605AFCF01F9EECAE1728668EEDCF2AC +:10CF4000D8BD831A792BBE43DA1950103F9E407C1E +:10CF5000F995362BECC47926D9898C7078488D07E1 +:10CF6000076799629297F98D66F8A658E0EBFA9AEE +:10CF7000F2E1B5AF291FEE216CFD778E17EF347407 +:10CF80003B513F55DC8471F34C3ED7E685DF65BFEE +:10CF900073BD66F8BDB610E489DBAE023C13ADBBD1 +:10CFA000A795F0F75A9CFCFD16F6AECB3678D785E0 +:10CFB00096BF03EFBA2401FDB3775DB6C0BB2EF474 +:10CFC000DB05EFBA9C0BF6B4865FF9D2427C7FF0AA +:10CFD000B35A82F1F14D297F25F1E055D465D67F12 +:10CFE000413DD9F20E9B59CF65CCCB3395BDB3CC27 +:10CFF000EFB67954F66EDBFF0164680340008000F1 +:10D00000000000001F8B080000000000000BDD7D09 +:10D010000B7854C5D9F09C3D6737BBC966B3B9924C +:10D0200040124E42081B0861810483829E84406343 +:10D030004D71435151A88D40314248285E1A7FF509 +:10D04000C94282841834A0585A2F2C378BB56AB441 +:10D0500051A922DD2052FAD5964551F152BFF55221 +:10D060002F40258A177C3E5BFF79DF99D93DE76425 +:10D0700013C0E2FFF8FDF1C1C99C993367E6BDBF5B +:10D08000EFBC332184906FE8BF04CF0412F410FC8E +:10D0900081BA433D9704EDD1FA23C3EB1C6A3A21D0 +:10D0A0005677A5E139F1F7115F22562D248390546C +:10D0B000DE365DBED71E2E26644DCDAC24520CFD4F +:10D0C000B450266D4F80469590D5566F968F3E4F43 +:10D0D000A85954435C84AC6A2124388A90F6163BE4 +:10D0E000962B726CDE601A2177BE2C7BE3E82B3620 +:10D0F000CDA7B969FFDE9C5B09A1CFD7B80919920A +:10D10000479FBB9711924F88423F20D1BA5233E3D9 +:10D110002352425F98B3849049D1F9ACA9B1788386 +:10D12000A584C4253BBDF07D52ACBC13A66D6EFA40 +:10D13000DF37F4FD6FE0E782681947583BAE13BE56 +:10D14000A3EAEA04BE676C6F7E537A74AFAE7DAC1F +:10D150009A98F63E2CF61C72CE37322DE579497539 +:10D160004E5A96A71092D5FF7B5FB69047F78E4434 +:10D170008012920E653D01782A7CCCD5C9B3ECC4EF +:10D180001985B378BECACDE01B27D1CAE4FEE3B649 +:10D19000015CE3A2758510AD1BF0915D1AB3BF2849 +:10D1A0002906082923A4B32578F03D6BF4B9730A46 +:10D1B0007DDFD9BFFF4C55C679CF55552C9D4A9080 +:10D1C000B869BF442F7D5F0717A77666DFA73FA525 +:10D1D0006974BD2E4E37E477920278B5F37A8254A3 +:10D1E00037572D037CF9081941FB956BA4AE987D48 +:10D1F0004F13EF49502AE41D41DF79AC74D3760612 +:10D20000522869BBDDD8AE6620BC705C25FABEF63C +:10D210008D34F0BCBFAB12F0F8CEC841DA6DDE7AC7 +:10D22000E0A77ECF558B80635F1A859BCCD71B030D +:10D230008E6DC0DF028EB293C1B14DCADB19A6FC60 +:10D2400066D55C5E8A115291A676035FB6694EE49C +:10D25000CBB6B4EE5025AD9F28B57861A8C49195A2 +:10D26000C88F6D43F71D5E08709DB9FFC36D08350B +:10D270002D5425E04BDB133DD5A12A9DBC11F88A26 +:10D28000E7BF778C7D20BC9296A917CF236E4A2AE0 +:10D29000CE21362253BC384656D9EB9C51FCD8E0FF +:10D2A00017FA3C3E6DC64732E5FB78AF0E8FF0EFC4 +:10D2B0001B564778D0C5DBB26FFDB904449119E91C +:10D2C0007700E6A3A8BEE8FCC8D9C717C94E43BE7D +:10D2D000278A3713E4657F7AF733BEE7FD06E60B4E +:10D2E000D66FBA5C93791585CB9A17987C241E2645 +:10D2F000176C7686CF354463EDD98A97BE41D664E4 +:10D30000AE44F9D1AECE6F07F9F979A685C8123CC3 +:10D310005F6F07F9A198E447BACF62D00743E6C42C +:10D320001BE4FE9A825928CF069A67569DF1FD614B +:10D33000F5C6F77396A518EAE23D6BE6452F55A5AD +:10D3400046EBAB943A3BC8915B33D74B753AFA1E28 +:10D350005254F73AD0ABA8DB3267E27B7139A53182 +:10D36000E7B5CFA3BD0572A25D65F326EED870BE0A +:10D370008BEBA1BBB91E3AD53A37F2FEBFE6FDEF03 +:10D380006D716319C167C13506BCACCEA2F29A8E2D +:10D3900007B0D77FFF29B5EE73985F14CF96287C2E +:10D3A00080698B175B805FC5386D59F90EC0DBFA59 +:10D3B000EAC1E727F4AAE867557CC44BDFB312A3A0 +:10D3C0001CB7A5590CF89890C7E5C6B66B0CDFDD05 +:10D3D0009B3C63631EA5ABF587648274F73BE3FA5D +:10D3E000FAD3AB711DEB33D9FA07A66FD3BAA944B0 +:10D3F00088D011D6534CF5A1A6FEF9A6F6D1A6F613 +:10D4000009A6FAB9A6FE95A6FA0F4DFD6799EA5747 +:10D4100098FACF37B52F36B52F37D5FF8FB17F2983 +:10D42000C3F3F5E2D920F205F4BAB9BFA268885F68 +:10D43000A1E7237CE536F2E30F722AB43C66671855 +:10D44000F02BE8F374F1B39ACAB810F093A23A50F3 +:10D4500099962F267A7A589F998FFAA38D4E0BF5BD +:10D4600037B75F52041D5773FB70CE12031DF5E6EC +:10D47000143AC07E24CE34944BA7A20B89A418DBA7 +:10D48000B5A1D1F67CF8FFD9A58B53D37180EBDD24 +:10D49000C1E72DE4C023C37DD7223E02D49E1E1BCC +:10D4A00085931AB1A7E9C728DF6D49238138AAEF10 +:10D4B000B6F82D58FF3C937E08EC952AC687237852 +:10D4C0007F42C2128C23E6D3CEE9651DC8295ADEFD +:10D4D00001728A96B7B56462B97AAD256B218C5713 +:10D4E00063433CA58EBBD5AF4059595E04FAFBB6E9 +:10D4F000B13B340BAD279E94497022B5174AAE2834 +:10D5000087E5244C9F9FB9173EF735FDCE24E04EAA +:10D510008246C6E62A12B08E2364ED9EAC1F7AE8DE +:10D52000B86A81E275405BB177859286FDFCE03692 +:10D53000A84ADFFE11B43EBCC082F685B5BCAF057B +:10D54000EC7731EFB53FA4844B3BE6557B2D7E0A4B +:10D550008215C3EB7E05701ADE492C1AADAB7E55E1 +:10D5600002B9F6469E8AF276EB1F28438E800FF5AD +:10D5700065819EFD62AD6D25CC73603C11D952FE74 +:10D58000ED4B310EDA9943F1B906F4AC2A484274F6 +:10D59000951F76C13C9D32AB3F9777CCB7B2385AD6 +:10D5A0007F2CEF987B256DEF9C986B8175E4A5B976 +:10D5B000B4400CBA3A0CF218D6B776D170BD1E340E +:10D5C000976A0D1D77082D8B7909B4760EC09F9749 +:10D5D0002A7F9EC9EA0738DCD466DE9EC6CAB3FD40 +:10D5E0001DF3F8AFE5B9855D3A94FB8FC5CE8C414C +:10D5F000EDD3C37965FDED532AE886029D6FB27ABB +:10D60000875AE8D89BD6DA889FF2D4A61C827EA2DD +:10D610007F8D2DB01DF84351875EAAB3BB026B32DC +:10D62000AED0E8FB0189CCD1CBC97B399CEFCA973E +:10D63000707ED3E5637E99D2EF263F413B6B137139 +:10D640003BC01E89E0DBFFB90FE990E3BB2ABF6A4C +:10D650001DD02959C8F4667E549EAD50E8389B61B0 +:10D660001C5ADFDC6EC1F96DDA45F9977EEAF39B4F +:10D67000DFB180DD3C96042DB0BE312480A5872C1F +:10D68000B30050BAB91EDFC6F9B790F237FA3B20A3 +:10D69000FA68FBA5C3EBBE06BE48222AD655BF1BBF +:10D6A000E9A9715772652CFBC0966FE17E26A957D8 +:10D6B00026713F87C1D9965FD61FFE56B20CE17E18 +:10D6C00093C767CF07FF6EE7C1E030DAF4C4AB461B +:10D6D000BA05A8CCD2C99D1CFE9D24AF4F93E93852 +:10D6E0007B72EB92E1FDC6FA4FF665C0D07E3FBE7D +:10D6F0003F39DF8DFDAE08764F8761C679C395400F +:10D700000B63AB7BF700C98CD136839B413CE53F73 +:10D71000DF93AAC23CEA86C23885A17005908FB318 +:10D72000FE603003E773BE05E86204CC87D3472D63 +:10D73000D2978A7422F00DF4504BEB573430F850E6 +:10D740008310DB89E236CC7FCB2A4A27CEFE749247 +:10D750009ACFEC236F148EC43AB87FE5CD8F41BFCA +:10D76000022EB37ABC560817F87EE75E053ED0CC91 +:10D7700040DF5E077DDE9E5B770EACB374A3AF1512 +:10D78000E8CFB92BE4877E024ECE29214DC27EDA46 +:10D79000B9D06FD3CD9595A817BA08FA4B427F9AA6 +:10D7A000F16F9D62B4F708E9C2F58CEC32DAE994C6 +:10D7B0008E519FF7A3E39B23741CAF8F4B08FD137F +:10D7C000E8B4C47BC0CFA0FE078E35801C7980EB07 +:10D7D0002541D7E27901891D67B8323FE2CF66CA99 +:10D7E00083C3FBCAFC18FEAC0BF86304F2CB7CC00D +:10D7F000879BF461FBF09B8DFCD2B8F3937DC3E86B +:10D80000FC9DA5EA04C08FF87E03C737A5E3C54891 +:10D81000C71BFBF6815E1B7E33A3E36BC1D6488F2B +:10D82000D2E34D1E6D297C47D099793D4BF87ADAC9 +:10D83000737DD7C278576CEC7EDE81EFF9AE473E40 +:10D84000DB180A3A4814BEC3397CE36E89E0D90D6F +:10D85000F263568DF779D0CF3E8F7B3A9433D5BEA5 +:10D8600036302DE6D6CB06BBCF8C5F4A5FAD485F26 +:10D87000C4374D92C09AEDB6A2FE1C806EA27AD338 +:10D880002FE8FEE653C8ED3B62E1E174C73F99EB38 +:10D89000BB1BDE4FA9F611E4D3D39DD769F61371F4 +:10D8A000B3A81D1BB0EBED5841F71DEDB3D04F16DB +:10D8B0007810CF57B5CFAACE033A772ADE58FE4F5D +:10D8C00044DF703ABF9FD3F97A6E7F7571FBEBF638 +:10D8D0001615E57B678B07CB8E162F8F879663B95E +:10D8E000AA45C37EF29A4F2BD07FBF99605C6B65CF +:10D8F0004289148BAEF2FC467B7F78B311EFA9D539 +:10D9000046FF3B596F2FD37F49E5F986F644EF6810 +:10D9100043FB69C48B0F00DDDBD22A0DFD48F813F1 +:10D92000837D2BE0385D9E87F1620A4FB4AB853D65 +:10D930002BDA09A9C378AED5E467769AECD80E80C5 +:10D9400023C297C1B10BE088F02DE7F0AC667E13DF +:10D95000F77BE285DF53B47ECE7C8C8B1094572B03 +:10D96000726CA89F3BF298BDDD8F7E3275F293F208 +:10D97000FCEA354C9F0B7BFCF99C57AAC1AEDD92AB +:10D98000694139B9256D8F672BD6E3BD4C9FFABB32 +:10D990003C147F560F8F57538ACDA2EB4DE47CB3D6 +:10D9A000DA4A30FEDD91EEF4421C2CD1B3A806FB1E +:10D9B00099BE4BC8CF89DEFF23EFD51BEC0EA25CCE +:10D9C00063586764FEA536368E44241827A5D866AA +:10D9D000C09F9DE8EA79305F5B148F79B05E8E2737 +:10D9E000939D23E214663CB96B8CFA6675117BBF7C +:10D9F00037E701C4BB19BEAE2A23FD7670BA684B67 +:10DA0000DF827C68EE6F1E9F4C8937F87F1D9EC1B8 +:10DA1000E324C29F16FDC08F76C7E86FF6A3CF86BA +:10DA2000BFEEC6EF19F55D0C7F7DD2085D3C49C0A5 +:10DA30003B8207115FE47E98885B8BF114C2C6C3FA +:10DA40003AC6B7FD28FF7E99E0423FB2C0690B801D +:10DA50002C2CA0F3003A6EFB55426025ADAF4B98DD +:10DA6000D99744EB05DB6415DB9DBEA11067EEDDA5 +:10DA7000306368987EF71EA9EEA211BA38DCB6E4CE +:10DA80001B32993DA0BC13F600934BE8E7FAD74D43 +:10DA90000C69608F1711EF76025E306B17F444F457 +:10DAA00075B97FFDB3114CEF66CE25CBBA63E07F2D +:10DAB0000D6F8FCA715F3CCA6B2EC70B38BCB6772F +:10DAC000CD8AD7CB71DDF3A4587475B6E4771BC843 +:10DAD000EF51F09D1735D4DBA584CBEF47C8F75144 +:10DAE0007E2FCBAB5B3DA22CC67E9F1246F93D51EB +:10DAF000D5DA01EFE9E0EF015E7E4AF112631DCF56 +:10DB00008E60F6CDF7152F42AF6EEF7A9CE1A558E7 +:10DB1000E0E57612CBFFFD1EE0E569807B3FBD4A64 +:10DB2000C2B80FFB45B6F60CB43FA56ABB007F1127 +:10DB3000FC5C169B6FFEF91DE3E77EEEB7AEE7F8DF +:10DB4000E9E2F1F1DB397E3AB9BEEEE0F869E7FAD5 +:10DB5000FA56C04FDC99F3CDF066237E52ABE34D0D +:10DB6000F830E227A9DC889F44AF113F099ED126F7 +:10DB70007C18F1935EA022FCE2328D78EAC737A7C9 +:10DB8000F057D2609C187672765DA802F6B886CE01 +:10DB9000E9EEB5C220BEAE0A28C57AEF35F9A5A2D6 +:10DBA0004C2F6078CD9C161BEF16DE1EC8D7A40242 +:10DBB0003D9DFC20361FDB79FF63AA1667E87F5185 +:10DBC000ECFE2EDEFFF5E15AA2BE3FFDB94B1EC4AE +:10DBD0005F30AF3F41D2D20B701DEACE30C5FDB6EB +:10DBE000156C1F729B43ED86FD7CFF0AA777BB8AED +:10DBF00023F9ECE01FF171883F09C7CDE59F19EECD +:10DC0000DCFF15ECFBE52DC81E7A356DCF5B9E79E8 +:10DC1000A48E96A30B46E03CF3EBBD7B00CEB26B2B +:10DC2000CE50B67F3CCFFDFE184A6AC154E91B7046 +:10DC3000B8DDB1F7ED4529F42995836807D2890449 +:10DC4000B6533A8D5388929802EBD5705D56B06307 +:10DC500065586F17D6E34937964E1262FBD7DC1F23 +:10DC60003DAF200FC7731337FAAB29C48BA5E06310 +:10DC70007B1A51D227E0F86D7113082AFCF3C05FBC +:10DC800075666FEE009F46A3509884AC82F090EECC +:10DC9000DA87EB271EA2B278DBCD6ECC4FF8335D6E +:10DCA000DF98D35FDFE9F6FBD2E12A21498434DB38 +:10DCB00059F98B78D71628BF74E4062068A58DA87B +:10DCC000FB31E0D55F49D0FEF0BF951068C5C92E85 +:10DCD0003B87F907A73DCEBCB334CECFCED2388D2B +:10DCE00005E9A71EE736F87532EC63FA9643FFB6EE +:10DCF000E44968778AD20CD77D1EED06989F627F33 +:10DD000029F7BDD4A8DDE67C5342BBAD4D0A12888D +:10DD100053FADF96D0BE22C50C4F4E9578F2C64519 +:10DD2000C7717A970D67F12E16EF59F1F75F8C02E4 +:10DD3000FBFB970933C349F4FDAD07A99D0779346F +:10DD4000D3BCAFD7537A4A4FB579B750FA49E57E7D +:10DD500072DCDA4907EAE9AF9F8C62FCBDA365BFBC +:10DD6000BB8D0AA444C57BE104FA9E93EFDF12B990 +:10DD7000260C7663E22445853D8E2239580DF32525 +:10DD80004D16027C714F83713FB7B3B008E122EAB0 +:10DD9000C3F87E2E2955FA227936D48EDF58C0F387 +:10DDA0006A5CC40576A1F26F2D2956DE8328C5FC76 +:10DDB0004AD3A8DE4A82B820E5145A96760631F98D +:10DDC000A3D21BB4831DBB2140FC360AA707E7FB87 +:10DDD000AE81F13ACB7D0960976F3834EBA2B17414 +:10DDE000DEA1B0E205100447A5E0BA439ABC368133 +:10DDF0003EDFF9A6C50DEBDBCADFEFF449C8FFF73C +:10DE0000CC23013F85C7D6863D7619ECDE90858C04 +:10DE1000443B973A5C93B82854215ECBF8FE965168 +:10DE2000E9F8B027B43C19E0B22EE1FC9046C7AF48 +:10DE3000AD6671E71972F6F3306EA8D386F849E73C +:10DE4000F94712A945FB39659ECE5EA6FF123B99A4 +:10DE50005F19BA8E60DE535299D3EBA7DF7B22CCD9 +:10DE6000F68DEEA96671671709E2F767C8BB1C1645 +:10DE7000FABCA75A71033D2599EC73278C4749AE2C +:10DE800067231BCF359E8D9768CA83B28B79B9E91A +:10DE9000BC28FEE44405F1ECAE36E64FB94CEF3950 +:10DEA0004DDF7B59E0399B14029E4FF86E98F812B3 +:10DEB000B67AD558F9139D2D2454A5CBB7700E1002 +:10DEC0003FFCB290F909B6ACBD7698D709DF2B6953 +:10DED00010EE7AE15FFBDEBB03CA7FFF574F135D95 +:10DEE000D75FBF3ABCED518063F36D2F221D72BF27 +:10DEF0006A084C81CEE7F95A1BC2B14C63F101525A +:10DF0000DABBD75A8AEDB8AFB5768F03DB87959326 +:10DF10008083C27398A265FD0CF835247B57A83026 +:10DF200088E6CC9A44D85615ADAFBD92120E950F27 +:10DF3000E9F334D95F0CF190174822C5F7064D522A +:10DF400059FE9BF43CF0534E95847E58CE219F039E +:10DF5000E8E1C46C0BE6BFACA8BDF4C29174FCFB55 +:10DF60002A148C375457555C0EEDC30E317A715D0F +:10DF7000C7F047E114ACA2FC30E2108B279492B0BA +:10DF80003748DB877989350DF4C73C0A60985F27ED +:10DF9000C70F8F0F949686FC00D444AF118F6E1379 +:10DFA0001ECD78758DA47804FD52448A985FC7EC25 +:10DFB000C75ADE6743D544F45FEF5189DF3AAE3F7D +:10DFC000BE5EA4F6A346EDBF10B51FA1FC1BB51F96 +:10DFD000A1ECA1F62394895AC545A574BEA1743A53 +:10DFE0002EF05F4DD94AD81FB86FEAD537FD93960A +:10DFF000657C9F8D726A4A25FDCE2CE062565FAF2C +:10E00000519BE4A552D9505F9BA6887D3C3FE8D444 +:10E01000C42C0BDFE79971A746EB9D990ADFD76304 +:10E02000F511C5C450EFA9B118EAE7EDD18D3F0550 +:10E03000F01387F5092377AEF71744DBEF28A475B3 +:10E04000DA7E80DB73B54B2DBE2D31E877D948469B +:10E05000BFCABF895FA2F8FAAC80A09F2E5B349440 +:10E06000DFA4505141BEF6D7CB540EEAFDEB022A95 +:10E070005775F191C3853CAEEEAB60713612FDF978 +:10E080007A12CFB322F0BC330476C4ADAF5EE90D93 +:10E090009281E5AE355339A2A7938B051D8C2423BD +:10E0A000D19F27530E54009D754D54801E4A391F31 +:10E0B000106EC761889FD2CF539FDEFD174D053F7D +:10E0C000ADDDDD3612F37E2E1FA9CB935995BE68C8 +:10E0D00022E83391F7434895FB7DBA2EC97FA90505 +:10E0E000ECB681ED1485BCAF83476FED8C24D00373 +:10E0F0004E2EC7CDFD57B5EC7C05BEBFBAA51B4B58 +:10E10000679A0F858C5DF163FC669FA7AE11E6658B +:10E11000CFA6ED3A396C4BA3EF19FC806C667709FA +:10E120003CB809C683C4BEC986CE09F17114189DD6 +:10E13000545F807CDE109A8579159DDE0983C6AF19 +:10E140004EC5275BAB5E2269148E4FBE3AF32FB3E8 +:10E15000697910F88DEAC12738DFE4943FF6DAB523 +:10E16000067E396AE297A3267E397A0A7EB9E04EA6 +:10E1700068EFC9540CF51CE0175D7D6B845F583D5A +:10E18000CA2F47915FEE79D986F58D238F1AF865EE +:10E190004521AD67EBF865BAECDB12C30E78E53BC1 +:10E1A000E2975F9F29BFBC7166FCF2C4D9E3973F39 +:10E1B0008E4CFFEEF8C5779AFCE2EBCF2F87605EBE +:10E1C00067CA2F9DEE20E60376CEB6540762E0FBC9 +:10E1D0007A8E6F11F72EE3718A69F3B4CBC7823D53 +:10E1E000CBF3D6443E4DE73CA6BF57D4CE407DB9D5 +:10E1F000F520D397423F97713CFE8DC731CA424C00 +:10E200006FA6974BF8FE4C4D0AA8F4D74E6A12A49D +:10E2100082BE9E22912E1596BAAC76A414B59BE8C8 +:10E22000F7D06EBACFCBF266C92166EFD8E97F404E +:10E230004F17975B0D7A7588D9FE32D5C53EA6D8A3 +:10E24000BFBC0FF212283CBE1EC9ED2693BE15704E +:10E25000D870A812ED90CFB36D83EE5775F2F546E6 +:10E26000ECA9525F45AC78587DA184F0BEC9A3C526 +:10E270001796813EBE0AF5AED0E766BDDC53F59237 +:10E2800051CEF8C7A75616EBE48C7F3CEACD889CAC +:10E29000E1F501E50C3907E546442FF37A442FF305 +:10E2A0007A442FF37A44CEC0F8D951BD3CF281F1C3 +:10E2B00077FA757A7B19D4B34FAD9717707970B62A +:10E2C000E5CC1FB8BDFA5DE9E5CA424E2FFFB99C07 +:10E2D000A929FC0EE54C2DC899A453CB995A90332B +:10E2E000C506397355E1B7D0CB890DBD7ED8BFBF08 +:10E2F0006200BA77707C371568D7C0F8A4E6F4F2EC +:10E30000B6CD74D55BFBC0AA0CA0172FF3F3067A29 +:10E310003FB1F9F7AFB4E9F2A21395103B5FD1FC1E +:10E32000243E9FDB7010E365A79A6F7D21C1D2ACBC +:10E33000477B6BF7D9916EBD16DC13FFB6F3E89CF3 +:10E34000CDF8F28DED4FAF073EBA8FC7FDCC76AE5C +:10E35000C0EBE9DA3FE6EF5E3F52C571CDDF3F1516 +:10E36000DD523ADD0C747A22FBBA31E0E7C98977D5 +:10E370002500BCBE07FAF0C96F43A7AF8C64F83C18 +:10E380008D750761FCEF6ADDFF017FBEFC6DD6BDB8 +:10E39000A090D1D569ACFBBFBF4B7CFF07FEC26725 +:10E3A000DF66DDCB04BE093B2FE3865F289FACFF11 +:10E3B00057E1DB10BF58FFEFD18FC13ABBBEB26F40 +:10E3C00086F805F9FA1BD9AD3F3F45D8B99944FE07 +:10E3D0005EA28F9D877157EBCE4791E879295C0F3C +:10E3E000C63722ED07629D97FBAE4BB047DEB10EFC +:10E3F000D26E63713BF3F3FF2E90D83936A9D60164 +:10E4000079F1BDB3F760BE41E7EC09B86F65B6536B +:10E41000C47B3D2D1AC6933A5B7C58DEDE521D82CA +:10E42000B8C9932FBD25413E58E94B0DA8DFD64E04 +:10E43000FAE130CCE39B5A1A0FF5DB4D768A8BDB81 +:10E4400029DE51AFDFA9F75F9EFC4D13CA4111874A +:10E45000BA2362BFD0F7549D9F44EB400E113F0991 +:10E46000EA063F69D97AB05F7AC07EA1FDA78E5ACD +:10E47000B63ED677D65A483DD82F6B1B2CD5B1EC7B +:10E480009770416CFB85D671DFCD91680FACCC03E2 +:10E490007B86D4E9E36AA7B25F1E1EF5DDFA495711 +:10E4A0008C3A3B7E52846FB9DD32A4485B0821D997 +:10E4B000B32527869DA69C18D65F4EDC38EA5BF80C +:10E4C00049E102965F2DE86BABEAC578726735C10A +:10E4D000F8636768656A09AD3FD1602112AD5FFFDF +:10E4E000328B0B6F2827013847BB219B603DE465C9 +:10E4F00074304376FE08E2E03D55D47F52216EF73A +:10E50000E35A80EDBA8499B73928BDD4962B04FC20 +:10E51000A619F214FC4E4863F9A1B54EF2A338F0E7 +:10E52000ABA62A64E519C4AD13E562897224E54FF0 +:10E530003519F876A078B439FE4CE417BC802F73F7 +:10E540001CFA4CE3CFDB055D7DFBF833F2DF970F60 +:10E5500034CD8278EEA9E871C12815F599594F9903 +:10E56000F958D0D340F4E7043B69A2AECECFE186A0 +:10E57000F93EB513ECA48951BAE8AD9D94142BFF74 +:10E580004A9409CD7F78457F1E2F41E9C6F1129A42 +:10E5900077E1F3BB206F00D6A778519E3E5849E53E +:10E5A000708CF9ED6E597608E4E7AE96662C2F5024 +:10E5B000FAE414DAFFE916FF2180DBCE96762C9F71 +:10E5C0006CE9C2F69E968D58DED112C0726DCB0EEC +:10E5D0002C6F6BE9C6F2C17CF69D294A10C7B9E0E1 +:10E5E000241D5F474753FBE87774F83EEF43BFA114 +:10E5F0007D72B8DDD07ECEE12E43BD2CB4D1D0DF0C +:10E600003D2560686F2AA83B067CE92ADD6178EE2B +:10E610002CEE36BC77BA7EC1D9EE976B7F04B6C9B3 +:10E6200049329CBBA0AFC8706E88F2F190662A5E3A +:10E6300069FDFE441EE7E866FBE49924F283740951 +:10E64000A964601FF426B23CC8D62CF67EEB8DACD4 +:10E650007E7F0EDB3F12799AB23D42D744CA88EEE4 +:10E66000E7DF9FC8CF2915B0BCC8DCE200442448CE +:10E670002E24A8C17E4829DB2713FBDEAD3CEE70BB +:10E68000BF95EC94A83DD9AAB0F9B76A24B082F638 +:10E690006B2D66F57BAA48C002F3D7A814CFD0ED46 +:10E6A0007337EFFB4A2A89EE9793D11AEED7C87CCD +:10E6B0009F3DB2EFED7897E0BE3E87D7CA848F3199 +:10E6C0008F36B9B94F02FE1AD2DCD70BF3BBFF1657 +:10E6D0009B1ACB1FEABDE58B2CE09B4D377E910545 +:10E6E000CCBE29923FD3E7D0E7CFE472B86C6ACEB4 +:10E6F000C7FC854DF52E2F87B3C5D48EF90C9FD757 +:10E70000F3FB0988827ED1307714AE01913F22431A +:10E71000DE1D5DFF88E8F9D3FF34BF6653F37296C0 +:10E720005F934D787ECD4CF427051E364139AEFF00 +:10E73000B9DEEF3ABFE6947935A63C0703FD42DD2A +:10E740006FA66F15F112C7E95BBA99E5456499E8C0 +:10E7500046E45D08BA14F919225F43E46FD8785E85 +:10E7600007FD2CCF6B8E4D5FB63DC403E7DE644BD7 +:10E77000BC774BDEA9F3089A3DF95C392C1BC7C660 +:10E7800065F903FF334AFB85A72C3A6E9E47BB51C0 +:10E790005F17E556F875321DC21BAE027BB5A85C4B +:10E7A0006B85F37C29A504CFE994964B58161D621E +:10E7B000F5DB3C327EAFCDC3E24DA27EB1A63D0774 +:10E7C000EF2799DEBB38F29E15FBFDDE63E1A5C2A3 +:10E7D000E6CDF3906772FA5E3D5966F9D155129312 +:10E7E0001BB0A13A89EB430ABF8B89FB92025DDC27 +:10E7F000F5C71C5BB7B7B0FC3E910FFDB79765CC72 +:10E80000877696FBA6C1D9B3B2502808FBEBA5DBEF +:10E81000883B4585F98535E0C7153977EF817C88D8 +:10E82000272E647BB6171F62F6C28FCBAFC6FB469E +:10E830005C5FCB188F754F49F406E0433556A6FF51 +:10E84000453E74B9D15EA835D90B179FE2FE8F14EF +:10E85000D2E7073DF988C7148FE5F7800C24BFA3E2 +:10E86000F78030F950CAC77496BB1D10BF2E3A64AA +:10E87000C1E39EF2364DC6F3B19D2CCFE389906F74 +:10E88000D0F3A82F723886B89CF81BCF93ECE172B6 +:10E89000E2752E270E839CA0E52B3C4FF210CF9300 +:10E8A000349F97D8D152FD92DEDE319745927F1684 +:10E8B000E6416D56089EBF1BE0BE8FA2001DC790AB +:10E8C000C7B802E9676FF2DD15401CEB350BDA952E +:10E8D0005D5348562CFFAEEBC2CA41F30F3B5BE6DB +:10E8E000BCD43688DFE8B4517F26D6FB1E71AEABB0 +:10E8F0000BCF5BA4955B08E45565D9FBD8FE43AF0D +:10E9000003E97988D78EFBFB649E93BCABCB53B9EC +:10E91000DDD7350BE6FFE03605CFE7887113BD7410 +:10E920003E3A3A499BB22713E6DF39359809F64C4F +:10E93000D7F87D1B0B205FE4A04C800CCCF3B21603 +:10E94000717F96AF2B4DD1A45879EA03ADEB038FBD +:10E9500064B867C20CFF01ED0EC80818FCBC95B383 +:10E960002846FEE269CC13EDDB6F765C3B1BCF4D96 +:10E970009EE6FD17099C0EB3161207FADD408F8341 +:10E98000E0D9650D21DED62EB454C73A5F5B54C47E +:10E99000F0BDB6F453B48B4971EC7924959BE9959D +:10E9A000CDE70E858E4FDFEB2A8D3DFEE51C6F9483 +:10E9B000AE5F0379D5556D41BB22092E62C0FC1CA8 +:10E9C0006A074948EF28973E2BB5313BC1242FFAFF +:10E9D0007DBF54474FF9FDE5D0F9454E437CFF44D8 +:10E9E000F6ECA4600C3C8B52C051C8A1FE70247898 +:10E9F000FEB58BC39114C7E6EB28BE56887855DD6B +:10EA000029CEEBCD2E2A8B714E6C003C98E9E18E1D +:10EA1000853E5C1779EE35A282BE2CA5FCA88B43FF +:10EA20000C043F33BC167EC7F032B7FFA888C74737 +:10EA30004E739DA7DD8FDA456E9D5D0C87A2155A3A +:10EA40009FCAEB3FF64BE17BA85C9576FD09ED9EF6 +:10EA5000A9BCFC3194543FEE9282EFBE415F9E22EE +:10EA6000A93980B4594F8F820819B9555A66B07FB9 +:10EA70003A24EFE167302ED4970AFDA6933A852118 +:10EA80003980EBFA93146E05857529D15641D94822 +:10EA9000BA6CF05E63CF9F0EC3771A7B1C4119825C +:10EAA000933BADC7F471A36BF4E747F2E0168D6EAC +:10EAB0005B1E9DCF921DC67DD20612C2F196761BBB +:10EAC0009F9BCF8F4832050C5C4E10C97F9D82F909 +:10EAD000BDC4C1DAE3478BF3E87D85FAFBCCEA39A4 +:10EAE000BCEAEDCE20DC2F4402C6798A7B739EA758 +:10EAF00072CC3E01CFC33C0C74FC91DBEEB7507B73 +:10EB00003923A5AE11E07115516DAC647683589729 +:10EB1000B887668173B60DE0BBA0DDBC0ECD06F3F1 +:10EB2000F959D7E0EB1378FF4711C175DC5EA46299 +:10EB3000B934BE66BF06CDA5A15CFD7D104D5C3F1E +:10EB40009065A906FE7D51D023D1E4D3597F7FB8CB +:10EB500016609C4CC075603A35C6C976C121D77421 +:10EB600084DFCB7AF811A5AE04C615EBF96759E836 +:10EB70008120ECAB26B27BA0DE4DA97B03FAE71C1B +:10EB80000EBF2FD1A913A75A08EBFC78E747AFC8EF +:10EB9000F9D1F51112BE1BF2A3EB77CAEE0E58CFD6 +:10EBA000CEE70E03BD0FB42E911F4BE901E146E7FE +:10EBB000F521E837F3BC8EDE407E0A76C974B9D8F9 +:10EBC00010477986C3F19E62DFC7F05EE94BD92E0C +:10EBD000BC7F27BF7BDF503A8FBEEB25CCAB4D937C +:10EBE0004915C04FE4237CEA54D0CF4E4BF0CB2ED6 +:10EBF0005AEFBB8A78B7C034BCCBBC402A724EB146 +:10EC0000B783D24DC6F5B20FE4C9DFAF5B90BC80CD +:10EC10009619890B9347D0F28238E277D0F13224EB +:10EC20008BAF1B8350F3932FA1F3FC491C9D27ADA1 +:10EC3000E7DD90101C41F9ED8F3662077A4D4BA845 +:10EC40005B371DBE932CE37C8E503B51A172ACE22E +:10EC5000F2CF26DAE9F7867EED9C00F3C96A9E467C +:10EC6000DEA5A03C5CC4F8E4E8C35F4E8473E0F228 +:10EC7000374E2F9E33E7F4973682C1C38CEFDD1CED +:10EC80001E6FC6337FA731DD762BC4DB3FE6FE0F58 +:10EC9000D13CE82F5CC7FD8537E3991FF466A18856 +:10ECA0002F05D3F5F66DA3434BBA0C9C076A274199 +:10ECB000BEF3676E2D2919FA111FF2ED75DC6FFE98 +:10ECC00098906AA0F3EBD64C1B9242DF4F6F6570B1 +:10ECD00030CF6FEC68A69F1B4E5282D6C5CF1A94D8 +:10ECE000A00DE477C3499BE1F9DFA91DEDD79D573E +:10ECF000FFC98787A6C3FCAE24E155D0FFCAEB123B +:10ED000058E09EF36B0F9FC74070694C568842E1F4 +:10ED1000D12811DF60FD9EF9B71C13BEB34733FB4A +:10ED2000257D5AECF55DC4D7376D75CD2F81CE1A90 +:10ED30004356B4E5AFFB43C590C1ECE7C693E791FA +:10ED4000802EFED7A884111E8D27CFC7E7D3561F6C +:10ED5000B301DDC3382A7D7E9D431B02F1DA81E0D9 +:10ED6000BC9BDB418D2793893F55FF9CF17774FC59 +:10ED7000346CFF2D87DB6FF75BAA63E577358F6611 +:10ED800070199DAEF8201F684C90689B637C57F407 +:10ED9000CB4831EE5F98E7D55319BE12E67D4E158C +:10EDA000D1627D6F3187A3986F4F4A78910FE9B395 +:10EDB000AF10EE9988D4DD7DB9FA7B24B672FCF5EC +:10EDC000FC309C0BE37F7C61EC733B02CF9394653A +:10EDD000682FBF9052F734C8B77997D10AA58F2111 +:10EDE000F38216763EC53F28BEA370964960E26066 +:10EDF00070B661BB18EFA317393F523F1CF2D4AF76 +:10EE0000E2F2FFAA6D4B30EF49C8A98F36CA28A796 +:10EE10003E42DD42CB8084F6EBFC3A0A6B2A571661 +:10EE20006D9FB60FD4C15599D4064D61CF6F86B290 +:10EE3000CD6A88F78BEF2D38CCECB7859D463D57D2 +:10EE40004F3A3F01FBE0A317993CA0FC6D0379BC4E +:10EE5000E82EE338F5DB2EFA00E6576FF2CB33B835 +:10EE60007E36DB799B47F3F8FE2432E94CFCF24610 +:10EE7000A2ED188D7AC127C33CCA14E33D5BA24CB6 +:10EE80002F61F05FBEFD84CDA50E3CEE112A470A2E +:10EE9000E8B8C7A83F0EE51F476BBF1F4DF170FCD8 +:10EEA0002083CB81D1754FC1F78E1F64EBFFB4E196 +:10EEB000D345704F0C99C3EC8638387C407F8D9BCE +:10EEC0006B0FB4D2F5AEA662CA01E782E2983D228A +:10EED000EC3059BE5676D1F6C9FF58980CEB4C7BF6 +:10EEE000E807D5305EFA43091AC0ADA3421B0FF202 +:10EEF000BEA3D6E985F32A9B291996D3F7ED741C96 +:10EF0000D02781DF4EDE03DB9105DDEB2AE1DE1742 +:10EF1000F7AEDEE030BAAE760BBB27A3FD7CE26D28 +:10EF200025D1EF35EDAA7D0CE6953B9BEA0709CE8E +:10EF3000D16BE3DDBAF109B7AF1A394E8E3F3BEA28 +:10EF40008EF3E05CC27E19CDC74F1BF2D1AF1F4DCF +:10EF5000183D89FC7BF836D891027EC7A8BE22BA3C +:10EF60003CB5D1DD52D04AD7B5B4E731BC8FA361EF +:10EF70006530632EE8DB0715A647F9FCD2FE9855ED +:10EF8000A9BAA2FA77AEE4463B52D8C99713F15317 +:10EF90008CF1C2399C0F2EE7F6F1DC0406E7F9C4C8 +:10EFA0009B0BEF5D61272E0B85D9DC69DD65CB40BE +:10EFB000EF2EB126837D036B898577519AED20C1B1 +:10EFC000878D0F24FA21EEFAB1D45708831CB13291 +:10EFD0003EEB7B362EB025AFFF38D631CCAF6F2C51 +:10EFE000E4765D01D1E0FC40E3EE51781E2C2E9ECC +:10EFF000E27102CA3F3BE0F579D0FF74DDD73CE314 +:10F0000008E2B930715F999BF813E9779A760FD9C6 +:10F01000027646DA086DFC723ADEC7D6702ECA0B4D +:10F020002ADF24AA5B73C7ACB944A17CD53894DA33 +:10F030005DB47ED14377B37A7E789185D6AF7DE893 +:10F04000D14B144A9F8DA3C3EF43FD96879E66F56F +:10F0500009E14532AD6F7C683FEB0F7BD894B0B6C9 +:10F060003F74E012F0FF8F2433FB8178C35702FD19 +:10F07000343E3DCAD2A15BEFBA314C3E1E71B07E28 +:10F0800047F2C84F6701BC3DE1C259BA7DB9EBC731 +:10F09000083B96D971629DE23D92197BFCB1639861 +:10F0A0001EBD661AEB7741026977B0F3757EB0C773 +:10F0B000F6EE1A8570491993C2E145C7298D8E2352 +:10F0C000E028C613DF5D0C7A1DE4BE95CA7D9D9CC9 +:10F0D0003997E38D7EA70DBF53AC8D877BAC1A6744 +:10F0E000658F07BC517C291C5F8A1D2F57DBCCE63E +:10F0F00047C74D2E413D3311E2CA7BBFA6FDF3A2A7 +:10F10000F336D3C78C314C1E5DD3CACEF7F7258FAB +:10F11000403ABA2081D98BA494C28FCAB38D1C6E99 +:10F12000EBC624333F32828721128EDFCAE197CDAE +:10F13000FA9FE97AE7F0799CEDF5EAF0A4417C6565 +:10F14000EFCE22C4D3C6081DAC338C736485E9BDF1 +:10F1500072CA78308F9411F8DE6A07B1E373B22572 +:10F16000F25E1E7DEF82697D13811F96727B98F897 +:10F17000CFC7BC86062E2D96B6876C10975EDACD6B +:10F18000E2E4A480AE0FE863564D295F9F9BAFCFAA +:10F19000CDD61730D02739D4973B3BB13FDD46E081 +:10F1A0001E19AF78021FCFC0CFB1C603BE18081F0B +:10F1B0001D671B1F629E267846E06C9A9F8027F091 +:10F1C00031BE576CE42731CF5BC644E2B1467ECEF8 +:10F1D000FB96DFAB60EF2DBD91E211EC1FD548CF60 +:10F1E0004B7BF22CF38BA3EFB577AFF0819C4F9064 +:10F1F000541607EFA9F583FE6BDA558171AAA54F66 +:10F200003DFCA49FBEBFF8D10D2E48AEFA48E9CA16 +:10F21000003BB861FB2A17DC33F7A1E27781FCFCE5 +:10F220002820C7CC5B7F9BCB01617735727D73E46F +:10F23000B7B7CD04787CB1DD8AE70C9B76C405E3D3 +:10F24000306E720DDA63B4FE36ABAFFE04FCD8A6A6 +:10F250009D46FB69F16F3664A8484FFE6116DC04D9 +:10F260000B0E83CDB0C66D56DC4F693C247BE9673D +:10F270004813E9BB15E6677E1FE67192E2BDA95B04 +:10F28000BE0AF2FBCCED5492A03DD6D4731BDA69D2 +:10F290004D3D177E00764593299FA27E003BECC52D +:10F2A00031DC0EE3F7A40BF890403ADA37AD0FFEED +:10F2B000B2E46D3AAF63DBFEE2928AF57A7325E23F +:10F2C000E9D3EE059B9E5607D6AF1F837D10A77F1F +:10F2D0008FE157DD29B18DA15DAC6CB0065D101FCB +:10F2E00068D86CF5520D4C1A1EDEFAC0AFC1BF7C57 +:10F2F0002DCE0BA9A64B1E7EFE9573697DC963D6E4 +:10F30000B41A367D27EC730B3C41CE06D829022F68 +:10F310008B7FFFBC0DE290F01CEC5E819F258FF58A +:10F32000DAE09C9F198ED3BA7B6D980F6BC653F7AA +:10F33000DB33C004697DF04B1BD0F747BB25BCF71E +:10F34000DEFC7EFDE6E75D40870027F04305BE2238 +:10F35000F8EB87B7E0CCA74BB11FC6434E85BFC7BC +:10F3600001476548E78F3C0D7194D7E3BC0087FAED +:10F3700047AE75C17A3E5096317ABF6F5506DC971D +:10F38000576FF567B8B164CFEBEFBF1EE9F0EA83C2 +:10F39000D767B07B24B42C768FA63F0BD6F9B37B0E +:10F3A0002FC1752E22754887F5F7B1F8C6E70AA96F +:10F3B0007E2C06BFCC2D66FCF2C19638480E221F6B +:10F3C000C03E02EC9BBC28E3B9FB7EF72291E558D6 +:10F3D000FF9CC717C61547EEEDB3837DD7C47B35B9 +:10F3E0006D5B1D023C1DC9D186403C9FC2C1CFE16F +:10F3F00026C1BDEFF2C1E943189E880AFB21F81E21 +:10F40000B5C7A7C173E81FB26A8E12C37BFC7E1B0F +:10F41000F67D11DFA0F38E87FDF40F32585E9E79E2 +:10F420007D1DC5421E9010D1D3D940FCBF6D0DD2B9 +:10F43000D7678718FF34066AABB13D640D0E81F6BD +:10F4400040EF6C09E5439C61FF3C421FDBAC9CBF75 +:10F450008DED749E8AA487EF6E09EFD314F4B2E8A1 +:10F46000AE38C37E7D947E8CF745097E157ED6D559 +:10F470005C1E98D76D960F97169BFE8EC2BDE9A7AE +:10F4800015FF6EB0061EF835F033E55FBF0AFC6C61 +:10F49000C5F8C0D1DF3DF7CA1594EE8F760B3E3626 +:10F4A000CA5B331FD73F5E4662F1F151A797C4E4B0 +:10F4B00063FA3C261F3BD9B9E9FF57F2F6EA01E4AB +:10F4C000ADBFD8286F3F27C549E711D0334BF0BEF9 +:10F4D00057337C85DF6B96A399C56A4C394A7F0EFA +:10F4E000111D3C051C057D2E7E68297E2742C782A2 +:10F4F0004E051D47E8D4BC6E233CCDED5530775DFD +:10F50000FE837525F563C0CE7D560E6CA1533B4E30 +:10F51000E7722B85FFF1DFE561BED12AEE071C778C +:10F52000F7B9207F6C15F73BFA202E99147DDEE7A2 +:10F5300060F6D2715F9F2B596737BDBD4B76819DB9 +:10F54000170E90EA58F1242AB1711E6132503BDB4C +:10F55000173BCEE3A1C779BC73BAECCC6D8638708B +:10F5600017BBD77FE18ACB5CB02F707CD7883B80FC +:10F57000FF7EF66799DDEBE9D714C89358C0404089 +:10F580003E24FEBBA7D0752ED8B504F31BCC7194D6 +:10F5900045CE6DB8BFF039B9194B73FC6431C4590D +:10F5A00080DEEF353DDF7511D2D762137DD5017D49 +:10F5B00065F5A7AF1704BF8E27E3F5E7CF9673B9BC +:10F5C000375D2EBE03EC99E3D4CFC75C02B9F800D7 +:10F5D000E8DDCFC1EF07C6F0A723DD2EA9FBD0C61B +:10F5E000EF71467A177468F6F7CDE5B127FE3EE96C +:10F5F00026DAA5E1C9374AEEA1E5B1275F2B7C06E3 +:10F60000EA4FBD9AFB06E9DF7FDAEEAFD0BF39BE25 +:10F610003B0EE7737CF79F726F82FAD37198877500 +:10F620007C651CE645F9772706E03CDFF11C16B740 +:10F630006B7DF6CB12CCBF206D88C793C536668F25 +:10F64000ECFA9FB7207FFAD35D712AC4299A7627F6 +:10F65000A0DFDEF4B403F35E8E3FFBE5247D9CE97E +:10F660003F5D4FA38DC5338F2792398F033D2733DD +:10F67000FFAEE999C95B215F6E694FAF0DF607A632 +:10F68000FDF15F2520978E3FCEEC0FEACFDF0F37DD +:10F690001DCA639BEEB652787F0C3622F5C3378DB8 +:10F6A000EDBE14FCF0FE706170384EE100EBA2700C +:10F6B000A907793A103C868EB521FD7FFFE0F1095C +:10F6C000FA170DBBCE413E8AC245D2D8F3C4805D45 +:10F6D000C2F5B3E7BBBF2C017BEA68F70AB40B4E57 +:10F6E000B5EEC963BFAF74F06DD72D054F67DD73FD +:10F6F000BEB7F866F4FF16D757663EE84FE74FDD12 +:10F7000080F54712BD38DFD3E4FFE6FFDFF0FEB837 +:10F7100084FBF2A7C2FB2FFFD7E2FDCF1CEF896E5F +:10F72000C82F3BFEECBF72896EFDA75AF793FF4BC3 +:10F73000D71DB18F649F1DAEB8EF24C1109C5F5FD1 +:10F7400035809DF2EE5849E4EFA01F22F277E4B431 +:10F75000C56867C8691D6837AC22EC1E64BF6AE1E2 +:10F76000F7B1B1BCEFF66C6F00E3A28AAF7E33ADA8 +:10F770005B8737783B7004A37F2667D454439CA5EE +:10F7800075059D171DA735DDE26E55E19A764B3064 +:10F79000AE04CBB7A15C9DF1C3FDF05DC569BCAF04 +:10F7A000D669F237E20B6CC6BC62B2C70DFBD50E50 +:10F7B000AF0277B95353D678BF6DEF58B6AF1D4F30 +:10F7C0000298B779A6704A2D191C4E66F808B8F54C +:10F7D0008313F747C57DFC4A5A4708F85021D49F48 +:10F7E00064EB413F14FE8E14ECD7589316793BD846 +:10F7F0007E8A1AB9C71FF220B8BF19B96756B5A0DB +:10F800005F2AE0AC1B0FD76F86F399C257E0C54162 +:10F8100066219E1DD94E6F80CE7F95CAE0BE8AC2FA +:10F820001DEE1717F0157033E3E17DA0519D1D1FEC +:10F830002D8DF93AFE4AE2817D96E9F294B01FECF3 +:10F84000E5F204B4978F49242851FFED5845462529 +:10F85000F815C7726C0A9453FBE89A74F3BDE0A4E0 +:10F860003DF237F4A05E41920DF5633985F8FE3420 +:10F870007B96E1BD0390B74DFDF66359E576DC0F4D +:10F8800075E719DE9B99E0DA02ED07208F1BBF3F79 +:10F8900003FD9B1F641619C699F9CEB17BAFA2E593 +:10F8A0004EEE57F74DB5623CFED89FE755021C2F30 +:10F8B00054C71BFA1F24EE74202ABABE2A58DF450B +:10F8C0009EC986EF36BCBDA710E2103FF256189EC7 +:10F8D0005F5C7EA1611C9F3D1C04F2AED56A0DCF1A +:10F8E0001B9ABF204A2A21E7357F4D9489D47C0F8B +:10F8F000761BC699B87FA7A1BF37E49E0626E3848E +:10F90000C3DEE7A014F9ECB654BBDF42CBB16F57AE +:10F91000CAB0EF59F65E5D2B84A1CF3B463C400751 +:10F92000E79078DC0F1C28EFFD4B4BA00ED6F90BAF +:10F9300039E081327ED8A21258D747999D326C4B5C +:10F94000DF23D55D5E0276D6678156A85FF075B776 +:10F950000CFE64EB0E19CFD74D976B12FE0AF2B86E +:10F960005BC21CFF06A705E3F04753BA4BAED5D1E7 +:10F970009DC8DB31F371D1C48A25307E5BA6D6D514 +:10F980000BF2B4F2EF57CA31CEBB12B7F15EBAA296 +:10F9900089BEDB619F5EE425C54F935972FB0FACB6 +:10F9A000182FB9D5E27570A1807AD73DC3BA19F87E +:10F9B000DD3A8EC98DF8BF1015E241F1A975329C70 +:10F9C000B323774898D722BEB7A09CE5DBDF5E2241 +:10F9D000EE3771A7FF642CBC9FC8F205209606EF96 +:10F9E000D558D04E711DF6EE83FBC8EEF41C728321 +:10F9F00078E8A979C70FFB223D874353258A9721D1 +:10FA00009D15270A587F02F1CD1E4F55C258D46F5D +:10FA1000E59887B39CE7CFF44EFD8D07F4C7F2A2BB +:10FA2000D14306CB2F779D9488AACB33B08E5371E8 +:10FA30005E2E258CE7C55C27156C27E1F1CC1FE411 +:10FA4000E3BBE6A9AF5E0BF3D86FC57C67A2684B3A +:10FA5000601D1DA3DF543B701D84FF5D9130FEDDF2 +:10FA60003CC84FC20BD19470E64F629CC33BB2A31B +:10FA70002C19FCF2D40A2F9E1B4C7D588E9C9B05A2 +:10FA800038DC0EFFC373B597BE5A45C7DD01B2928D +:10FA9000B50709A5EF0E9B68A7A2C6C3EF3DC4F644 +:10FAA0004B2F831843BC6CEC3F2E3FD25FB36746AD +:10FAB000C7FF43C9A5AFB6C584671CEAEB8E1956CC +:10FAC000CC9F38355C134E01571783EBD7542B640A +:10FAD00044E38BEF496A2ED0DB9D705C80FAD1BF86 +:10FAE0004CAE0B96A4C3FC8363E1F97C9736642A81 +:10FAF000A5BF1E9B967B23C6491C98FF55FBF3A30D +:10FB00001BE1C8986BE6114F1BD08DA2254C8038A5 +:10FB100095FB0B940B22CF2D0A474ACFF49BB75B82 +:10FB2000A2759013AE285C35B82BB84307673BAD80 +:10FB3000D772B8FECF23F597B5017E17DA912EAEB6 +:10FB4000E53CD5964CBA20CFEE84FB814B811E4E0E +:10FB5000ECB062326B0F34821EF5D8D9DFF5490B59 +:10FB600067C2DF71197BD082F1BD37297D68401FE4 +:10FB7000C1F1087731DE8929AFA6C0F98913694A36 +:10FB80000AC06771D88670FB894282707F6A4FDA3B +:10FB9000C26915C81F2AB677F371264FD4FE518269 +:10FBA0007A9D9FFFD5CE95E1BED481F065DECF87EB +:10FBB000F8F0B92903D3415B851DEF1F6A2A5F5115 +:10FBC0000C7A62797221E663355549A8879B9A3F82 +:10FBD00043B88BF1959332517579533D104D4CD705 +:10FBE000DD237FD286ED0DCD27509ED3E9E401DFE2 +:10FBF0001CE3FB9D5D56F2D35A5A36FC5BFE69ADA1 +:10FC000013F72DDB419F34903DB6E53A7948BA3F72 +:10FC100089C8FF71147777D6BC180F72B656725F19 +:10FC200002970ECCEADE7B19ECE7D73ADC97C0FEF0 +:10FC30007F8EF71156CF715F02FBFD631F4D9A0354 +:10FC4000FBFBB559EE0DF09741AFF016CDC1F63C78 +:10FC5000F7CB509F316E06AB27323A4879347F8E0E +:10FC60001FF5B913E1F2697B4260B07B48AE6E7E4E +:10FC7000C600977EEDB284795198B841E9E79F6B51 +:10FC800086B17B710B4298A735721C8BAF67A4B00D +:10FC90003FC92BF277D346100DF657D39E72B07B37 +:10FCA0005BDF0BE502FCAE7ECA1184B8E4D2FB9E9A +:10FCB000B3813E9A2FAB85C057B3CBEAC68C2B835A +:10FCC000F84908EB5737EFC679754C70F3FB72FBB8 +:10FCD0008A217E55CFF39EEB4DF9BF8B9D7B311E64 +:10FCE000B7789B31EEB68484DF023E6DF8DDE079B3 +:10FCF000BFEF58D83C140E8FF972E84A1B9BD7F916 +:10FD0000E3E8F797A6F462DEB1E20E65D4217C1B2E +:10FD10003CE8AF64C6E3B99A5B87BE5E12EBBE985F +:10FD2000EE16AAFF29CB3DDEB2134BE77882EB1922 +:10FD3000A2846D5E3A4E2397CB9342EFD8F4F983B9 +:10FD400073395C9376B2FD6F735EEC5CD05700172D +:10FD5000BECFBC74D60B53002F029F1724906ECCDD +:10FD60005F4D215E8E172FE045C03FBADF4CDFCBE1 +:10FD70008B451702FE84E5DBC53379D1F78403EDAB +:10FD80002BF3FCAFE3FA57ACA39DD7079A7F3BD781 +:10FD9000B7677BFEED5CAE9BD721F8583C177C6CB7 +:10FDA0005EB798F799D359C8763A7426E44C23A9DC +:10FDB000F3605C96CB150167314F01AF9E01F25D98 +:10FDC00095E63F18D6A3842AF1B0FC7650A420C74C +:10FDD000BA2FC4942BA57917F63BD3F508793BD0FD +:10FDE000BA849C35AF4FC85BB14E2177C57AA75214 +:10FDF0004182F210EE7E90C07FA833D8C3157062A6 +:10FE000041BF0F64FFB9A13EDD7DA3A1FF0F3257B3 +:10FE100018DA2F54D718DA2FF2AC33D47FE4FD95DB +:10FE2000C9AEDF6C68AFD51E34B44F0987A681DD3B +:10FE3000FDB7966ACCE73EFFC3BEE7A01E6C7163B8 +:10FE40007D4F4B26967B5B54E4EF7D2D1E2CF7B740 +:10FE500078F1F97FB59463F9428B8665A8C587A5CB +:10FE6000592ECCFCFD650AD8EDE5A12EF407C68F0E +:10FE7000AFFB0CE4E1014BA03591C2E99C37997DC1 +:10FE80004E02667DFCE55B37815E77B37BE8DA7A0C +:10FE9000274B6A0C7BCE45F59DA6A317574D98C0FE +:10FEA000FEB28BC4CEBBFC6A1CCBF7C17C3D4A9B27 +:10FEB00073ECEC5EDB397324CC4F9C43D879055A44 +:10FEC00006EB68FB4C85F841FFD73A15DC8F22FC26 +:10FED000FCF0256C9A70BFBA3F0EF4775A2A9E57F1 +:10FEE0009A0D0FE97C654DC6BCD64BCAFF82F980DE +:10FEF0005738D9DFCDBA7CFFCA7FDE44DB499BBFD0 +:10FF00008C9D8710F786BC6E3913BBE12B386300DC +:10FF100079A09297FDDD9464C5ABF70744F9D771DA +:10FF2000CC1F98D9CACF0B1C2468C7097EA4EB6BE1 +:10FF300087F90BBEA8752BC1512ED0F7EBA641FF58 +:10FF4000FF0B270420E00080000000001F8B08004A +:10FF500000000000000BB55A0B74146596BED5D591 +:10FF6000AF904EE88400411E76886020AF4E271D7A +:10FF7000C26B28124054C446650714A540313C9317 +:10FF800018981547F774633308AC6737337A5C5DAC +:10FF9000C1D3E0A0ECACE7102171339A300D2A8F69 +:10FFA0005947A3828266B141E4B126742428E270E5 +:10FFB0008E7BEFFDABE8AE4E02E859939373F35797 +:10FFC000FDF5FFFF7DDFFB552D3FE4720701A0BA71 +:10FFD0006C4D1E14209D221DB7215DBEFA3B30F7EB +:10FFE000C3F1EA0B602E06982ABF164C2D01387F0C +:10FFF00004DC369C3FA65D3DB3CB85FF5CFE5182A1 +:020000021000EC +:100000000100ABECF83F8ECB3AEB2AFAE2BF45E1B8 +:100010007A30D335FCF911FF8A0F34813927361E27 +:10002000F77DFDDB346FB75F05B305A0D93F876966 +:10003000D8BF18CC2300F6FA6B78FC8E7F358FF78B +:10004000F9034C0FF8D733FDABBF8EEFBFE77F9EB0 +:10005000C7EFFB434C5BFDDBF97A83DB09D01FE084 +:10006000426BC540350F8F46632F6E689F9CE94BEE +:10007000416A16740E1DC883D40E968C0CA473248A +:1000800096075E0F403AD3B08AF79767BEC5F2C0B5 +:100090001F9F1DF99D0DDA4F463F339402DC03820A +:1000A000FFD965FF7D494AA5819A23A1BCEECDEC1D +:1000B000031B2580FB2090BF00E99CCA3ACB7889BE +:1000C000EE4F719E42794881CF4C3FE6A24CE867E3 +:1000D00052778A078553BADC6480A58EB556180E10 +:1000E00080523A1141F99A40821FB3009640D80AD3 +:1000F00074FF8F96139138392F03C8826C3CFF6BC5 +:10010000169EAF5F077A3E6E5DB94286B274929BCF +:100110008BE5B60222BC9E4D7EC45DE3A0FDEAAC39 +:10012000B44EE2BE4B1DEF5871D0C3BEADFCFCB562 +:10013000F6D5F55405B080E6AFCD54EAF6E0BA2B1B +:10014000FAB43D209B7A9087D3DC79653D94C3BF98 +:100150008C127A9553A6D85507D9A9034CA8C7681D +:10016000480ED9709DC55975A9B42E1A662AE0F5B6 +:10017000252D32EB03CC8A7910EAAD52D35B3B8458 +:100180003F21BD544EA89C01A8BFC59B8CFC2C757B +:100190009C64B97F0BCD3DF25B054F7F23A776E7CB +:1001A000B76AC22DA769BD2A4D6E7C1DCFB5BA4D69 +:1001B000DAF14EDCBC95EE948C53C9E4583086E4F9 +:1001C000827CB8C3E46F8764F6B7DEECE39C1FD88B +:1001D000DE2FFA61C73B68FFE72EE3851B009E70A8 +:1001E0004F7B3E30E197D35BBF62DF0637F913DA0E +:1001F00009F991AEC775684380E75E576E0F0550E9 +:100200009E51AFD34CFB47A5503095F47209DC6B7F +:1002100050DE939BF71F213F996C7784496EC84449 +:100220007BBC5E27B58BCB134F868229387F7C5BE6 +:100230004026B71D7B480D3A703CE63D05358D7173 +:10024000E61D9F4C7ADFE96F6239D4FBEB99C6FC5F +:10025000E726F6331884D7B2AFDFCFE021BB89E2BF +:10026000DA4AED4CC134A83361C0EA724C93539022 +:100270008FAE30B8E97AD1215790CE55DCA6C8A907 +:10028000782EEF493548E75E876A506C1427037271 +:100290005FBC6E3343D88671C4966902254EAE6347 +:1002A0002F84821407F5B8D69C24EC79D2E57A998C +:1002B000E296D3AA6EDF82F2843793DCDB5CDDCF7B +:1002C000FD96DBC472FF32DDF7961B29385C237D77 +:1002D000F9643FEDAFBC48F6D390ECB6E173897199 +:1002E0005A8F8BFA3ABADC7439563BBB38EE2F5F23 +:1002F000DDC5712F71DF6A13A8F528774F85ABB87C +:1003000016D7695F03F367E1B8CE8234AFFBFC8F89 +:100310003CE5EF93BD4C9527B42A742EA7E9AA7645 +:100320005DBDFA1BDEBFD7FBDAFED52D5EE7424787 +:10033000ECBAA34812711ECCCE53F6983EAF57EFDD +:10034000133BE718F2D6A4EF5543DE9A8C9136FEA4 +:100350007E85FD11C378AAF331C3FC5B32D718EE5A +:10036000DFEADA60B87F7BCEEF0DE33BDC2F18E6E7 +:10037000DF59B6C5707F96F21F86FB33655024F4B3 +:10038000B97C2964213F9B0BF54CE7412BD307A097 +:1003900093A98A96447421B8993E043EA62B3CAAA0 +:1003A0005C847613B5740E20BFEF78E3EF796417A1 +:1003B0001DBF1AEFCC72C5F2B29EA77F6A3EEE63F4 +:1003C000453DF5600F038A84DDEAF1BE57FD24C484 +:1003D000FB6811C6133C67B43199E34C34A54F4810 +:1003E0009262F1042DD244F958F75B3DBE14CF73ED +:1003F0007FB092FCE83D1946B8BAC79BA9662C0DA0 +:100400003C74DD9D737F7E6CFFA00916939D6D4744 +:10041000FA3AF2D1775EC4EC8AE3A780F8407B9B7E +:100420003C770A44F0FA4C272821CA4376C848A2F0 +:100430005878B92B6F36068899DFA3A2D09E7F48E3 +:10044000570A49DE81A726A49DCAD5E2D28DA8BF4E +:10045000E326E6079648A111288FA60631CE5F94C1 +:10046000C6FCDD0761D6E3FD10B110FFF301384E85 +:100470002F0017D30741617DE2CAC905189F1635C1 +:10048000983D1B91CFC2F4CEE1E49FF9638FA64B58 +:10049000782E2CED14E2A7D004EBA9BED1F9A8D593 +:1004A000F8D858A454D0F90AD35B373E83FB77368B +:1004B0009A602BAE737AEC630F435C3EDEEE299FAD +:1004C0004EF37648A0505E0DB4D842DBB268FFCE42 +:1004D00001940FF4792B3C15338B70DDD945C0FAAC +:1004E00086D6BF00E9679653C81EA6F46719E07365 +:1004F000C37CF93DF967809F2B2459DE00E2421945 +:10050000EFCBE3875F7F6DCEDA3CE6274075DC7684 +:100510008F3A9FCF6FC55840E7DF6C0B6DE57AAB24 +:10052000669884E7AC7CC966A2FC7F14E333DC0CDC +:10053000F0B9DFCEF47FFC4EA65FF833991EF7BB0F +:10054000987EE9CF61BAE87B6400F577BA48A922C2 +:100550007E7AE3A3F73823F8884A30A7DED1FD7E00 +:10056000A5E60F050D279F4C263B6892DD64A7F991 +:100570008D689878EE73CD63427256BC5CD5C7899E +:10058000CF82A68FFF30BE849E333B259C7FAEA9D1 +:100590006B00F96FE2F9AEC8A3C52AE4A19D7747C5 +:1005A0005AEB467A7E47E3703A21C611107648FA34 +:1005B000947AE2630DDBC9AF8A44BEBFD3D659E259 +:1005C00074C4F8032A3130CFD46A7966AA7C39958D +:1005D000FC6216AD3B96ECFAA60F68BFC001E1873E +:1005E000A8D7F9BE387FDAA5C941A7F92D561FF95A +:1005F000D38E964FEEBA1DE53073DCAD5ED9159BF8 +:10060000FF3209C14BF67DE9DF9FC9E0F94EDA6A96 +:100610002E6C99EAC479F7D9F7BC4B22B8DF797C04 +:100620006A1A8EE7674AFB882E70654D4BA7380023 +:10063000217EFEC19CC9FBC8C466B86759A99E98B3 +:100640004C4E1517772BEC186F0C71BE9F617C4BCD +:10065000E660C3FC5B5DD986FBB7E7E41AEEEBFB13 +:10066000CE70171BE691BF52BD8D7CB0DE619B1C26 +:100670001A21911D5CF86C19F33FB784F88FA2FC26 +:10068000AC58389C29DBF0DC3314361AF7A6927F7D +:1006900026D6B5CB5B5EDEA7B87AAF6BABC0D737DB +:1006A0002CF55ECFF6560F5E6F5D8B71E40F14472D +:1006B0000ADFB8C719C473EC187BE90617F2F761B3 +:1006C00051CFF56E54AB7713EDE88ABD4A2E613FEA +:1006D0000765A07A48AF7B13ED08E049AD0E10F432 +:1006E000A7FAFBCC8F44DEFA8AFCBE5FBC7D6B347C +:1006F0005464C8338556CC2FA89FCEBFC9B0952E61 +:100700005CC673E87AC88ED93F3CB4E5DD41257CF0 +:100710003D40756D15E5055C3FD923897597EF79E7 +:10072000775046EC3EAC3A6E980F4F48FB0CE3B561 +:1007300059C6F1D393F7C53FDF5B3CAADCF488557B +:10074000C5385DF9ACC4F92AF1BE7E9EA97B93142D +:100750008A9BE6661BF753554E051407554D98477F +:100760007AC8EB7A7C982B434D4F716E80B6EE8C35 +:10077000BD4920FF8C758FA2ADD07902FF25F2CD47 +:10078000D1BE0AF8E2F6C9F288FAAF23ADEE9FBEF9 +:10079000C3791D7F063789BE234DC4DD8286D326EB +:1007A00013E5BF3EC25E0A9C11533AD2E8E2E40070 +:1007B000A03F552F4909980AF1FEF0CE4FECA8FA58 +:1007C000519E412FD8516F9F994C86FC13A5988755 +:1007D00063CFCECCB9947F6EDF9B1436FD0C7E3C8C +:1007E0005473202D2C177EFF00D98DD84701F48F2C +:1007F000EADF81BEAF427182F8A7F132CF90A3CF7A +:10080000E2BAD507451CC0DB8EC47EF6BEB87E16A4 +:100810003609FFB5E32FD53B55109AE620DC208C36 +:10082000FE0FBF9CFFCFF43832B8CE213FBFB9BB1B +:100830005FEB7E5F7D58F8FDF9E66F3FA2387F1EC3 +:10084000F35FBCDFEB72D3FDBDFA7999FD52BF7E39 +:10085000AE599E1EEA41CE65BA5F296EF6D75AA7F9 +:10086000D8B776E2C5BB28CFD5B6A086A4EEFBE804 +:10087000B47ABD0CAEB87D76ECB62D0E39627C44F0 +:10088000F5FCDAF26DFAE43C41D750FE853A2DFED4 +:1008900088BA06F3AA2583F2EA2CC9BD0DC9E196F0 +:1008A00081E524BFC312845D1E5EE21E3B9EEF6E97 +:1008B000B11C5D77507D06993966DAE72E4DAF772A +:1008C0006BF8D2EC96D92328DE7FD2B0F0B042513B +:1008D000CE93CDFBFD1A025C1F1E4EF30D5D89E722 +:1008E0009C1914767E38ADB39DF0A8C31393A5A0D0 +:1008F000C4EBAF8DAFFF0E5B7C436B982F0D97520F +:1009000046CB3F26FF847E598B8BA8CF8024FA3BB1 +:10091000F603F3A0A719675802A17D0AEE5BE50E66 +:10092000739DBA0C042E9058DF574DF8DA4AF9211E +:10093000B11F9DDCB4E78854D0038E9160B7D7C255 +:100940002D12FBE0DEF0871FD27DDB3C71F8616287 +:10095000BD7EA52ED5EBAA6DC9A1AD789EB727FEA9 +:10096000DBB965385EB52DD9497DF7D9976C018A19 +:10097000CF67B7DA4212DE3F9BDED9467DC8D99DEC +:10098000F96E5C012A4DAEFF7C8DF2FC9F2C6C173A +:10099000006EE11F57ECF4D16314EF6AB7A548402D +:1009A000F5B52AEEEB3DA0FC6A0AD7094B760D0A95 +:1009B000D9A4589E21FF706169716673924245FF08 +:1009C000D90377F725FCAADDF4FA30C6C3E4278EF5 +:1009D0003D86CF2D7B25C543F504E401EB6DF1D6B3 +:1009E000515BA83E7ED1A2EE27FE2B5EBD63601652 +:1009F000ADFF717F207EA2CDBB06507D14ABDB7BAB +:100A0000AEF7CE3767F785BC989C743C71FD1FD755 +:100A1000F848EFC9928BAF9BA146194C76D1340BA5 +:100A2000685D8F2C29E4979D1B92B94E4DB4BB6332 +:100A30001ED1A72CD7F1877E60CF24FF5181E5100E +:100A4000DD90BB7523CAE93B4FBA96AF3B47DE95B5 +:100A50001F6F9F6D556F917D6EB2312ED29E64AC2B +:100A60001B74FABF9E34DEA7D27EC1804354ADBE54 +:100A7000641CE761BF87CF7B82AEE24790AED4E4CF +:100A8000DF35DAD7E1C1E797D6FFFE8DF7582E9B09 +:100A9000FEF133DAF78043E031EF09F925F60395EB +:100AA00076817B006CE1F3EAD74F6FFEB480ECF007 +:100AB0007463EE48D2E342B9F5D48BC8E7B994D653 +:100AC000638F23DD79E023D64BE27913F19B7649DE +:100AD000627E97131F78FD1EAF4F2EEECFEECC7DBA +:100AE000DCC28DF92CBFA9725E5FD263F46C2FFD5E +:100AF0008A764E7D7DFD7CFAFAFA3C67B1D0D7FB51 +:100B00001AFEDE616D3D47FAED782357227CF0CA6C +:100B1000F5F4D682B4387BF9A570F97B357CE4888E +:100B200069CD6FAC688FEDF5CF58D4F8B8F713F1F5 +:100B3000F82BF5A0022EE700914A386F2173661C4E +:100B40004FD4C7E40C389EA01D4FA2F3A05F4ED433 +:100B5000282C5533196FA7F590264188C7C1C96E57 +:100B600017D149928F710FBD6F98063543880F9347 +:100B70003DC238E15AC227B16E999DB6EE8E2CDC8B +:100B80006F6D7F5847F5CC5A8BF08BC08264EEE7CF +:100B90007439E979069C7986FCB2D6092E33AE33D6 +:100BA000C70CEB2DE962DE8D28E7C30716BE4BB8F4 +:100BB000EBA7E69AFEB4EF51C7B3F99289EABC50AD +:100BC0000AF58C9F7DF427EFDF70EEE7A04CA4BA06 +:100BD000E29EFD768EFB89F8C42250795C0911CB28 +:100BE000057CEE8BB13F6CDB0B31BEBE18F75D238D +:100BF000F509F7A53DE9A5E703E5904379E96252D8 +:100C00006A01F1B3DA2EE8A37D52B7123DEB74040A +:100C10000897BD98342C44F9F445497D80EC199F20 +:100C2000E33E36702C3944F9EE5159AD621C3ACD91 +:100C30000A12CE8FF6D7E4D2012C97A8459BFF8DE0 +:100C40008BC725151EC629E1A28BE3F2F884BC539D +:100C5000926B12FDD98F62FEC44EB321EF94146AD9 +:100C600078CEDF5D5CA74EFADE7CD5BC74B958F453 +:100C7000BB25FD4C353DD58BCF68F783109605CE4F +:100C800023EA85F157EC4B91498F55DAB88AF21A6D +:100C9000DA5534D51E9091DFF1CDC2CEC69BC37B11 +:100CA00088629485D5545F3461DED3CF817105327B +:100CB00073D91EC6E9768A6BCDC379EBA41AEE63AD +:100CC000EC54D720DD28B5F2397E059D4C152D9FBB +:100CD00097839BE914F031453B653A1DEA98DE069F +:100CE000F54C6740ABC8FFA3C341CE6BF08493FBC8 +:100CF000C15B2B4D547794FCBAE7FEA1518B27BD05 +:100D0000CB011DAFF4A7CB611AA0FF65F7208F219F +:100D1000391C4712E591E8A7132122B39F5280C8DE +:100D200026FCC0C5FE5A010A8FA75EA71CCA22AACC +:100D300099F19B447954F46C17BB35BBA8255BEB48 +:100D40001FD35357B18BC7BABED0BF32A90E4DD4F3 +:100D5000A37EBD24B9BCCB85A1F8B35D27E79A314A +:100D60002F951497AFCCC6717BF1B773CD98CF4A4E +:100D7000C697EF1A8EE373BBBE13E3C2F2628B1BFE +:100D8000BB983517E74EC1F92AF9672151F4438A18 +:100D900067AAE88F5769758CBAE6376E27FA8B3ADF +:100DA000D4E1263EED58EC133E2A678BF78EC3A69E +:100DB00087F75A70DE498B7A98FC77853D9CEA422A +:100DC000F9AF5A33752085CEA7AC62BECD26705AD6 +:100DD0009D3FBC1E48C2F1CE9DB92BA5E1D73E0771 +:100DE000AEFF25ADAFAE191120FF551B25B7D06C56 +:100DF000F9C03928C3F6560B106EAAEFF7E468F570 +:100E00000CE747979BE3F760ADCE69DF999B4B7A80 +:100E1000EA2A163818646415931C8F8FF675D1FC76 +:100E2000688AB0B72ECAE5DEDEE9E012E51B9A9FBC +:100E3000783DFA151E009F3797A817E97E75F26571 +:100E4000CEFBE78A3E5E17C98AD9AD844A9B87FCF0 +:100E500007150859393F4C705EA95329DE2DC2751C +:100E6000501E253E3548216ECCBCCE528AABB8AE62 +:100E7000A904F7A9B6468615E173CFDE7DCC2AEC2E +:100E80006E88B03B2D2EB5EC3EF8F86031F4419CF5 +:100E90009F55EFBEF4DDE728BFEAF30E374D8FF91B +:100EA000D70B2BB9DF0487218EE87E37AEC9C6F594 +:100EB000F6F8E6518B68DEC48FDBB289AF496D115D +:100EC0007E8F166DF974B03887DE875C947E4E3E57 +:100ED0003EADE589D3769117E8BD30F77B8DE2BD55 +:100EE00070AD8673D6B648A100C71FD13F2FD6F884 +:100EF0005B71B0711FE1278B373D3883ED2824FAF1 +:100F00000A17FE525C587A44F4CDCBB61BFB8D6AAF +:100F1000EA9B693E84AD640F2BEA13EE6FAAE0BE34 +:100F2000B93A3EFEF7D0377B4B347C6C280C65BE5B +:100F3000E4797DD51EE261625F5C05CA8412AE7BF6 +:100F40007D32EDEF35F78C3FF42FD0DF9389FABD7A +:100F500052DB9BE4E460B958B99FA8DDBCD2EDA494 +:100F6000B1E6B75B4CD453E3C4773E80F8E7743FF7 +:100F70005EB25EE2BE0336F5631B2C7CC5A610BFD5 +:100F800085AF0CE43E04FB25AE0FB7BC625B4FE3BC +:100F9000E0EFFA04E442C2A13B6F201C269884F5DE +:100FA000A6C0F341F2300EC3B8C823255ADCD7EAF5 +:100FB00000081719FAF9A096FF6B53460EC4CE39F4 +:100FC00036EFC020437F12D4EAED123A27D58DDBED +:100FD0006F10F793041F7B3EFC8764AA7B1BCDBE7A +:100FE00064C2B5CF1F1ACE7D4C6F72F7621A82AB06 +:100FF000BCA7F47E3A23FB6A7A2B79DE2CE4A5D9D0 +:10100000ED9B7E05BEB4C4F4A2F337557EADC24A53 +:10101000B8C843E0249CA4F6E0CB413BF5851B8097 +:101020001188F320ECF9FC1913BF772F859C7F9D65 +:101030008063EF19B33B84CF37687191DE3FBBE229 +:10104000ECCCA6E1BF49AE3EE08AEBA39373D20D90 +:10105000E314F70D86E7FA960D37DC47796FA5F5AF +:1010600021A0B4E695C6EADE3465B4E1B9A752A77B +:101070001D60BF6F7D9871A97ED33DC6F3C8CD3288 +:10108000C503B820EAA532FC257F1B038120E96354 +:101090005CBBB18E2A8BD471DF9874C86CC0016CB4 +:1010A000D7C0A5B6907F519C1C024344DC4894B73E +:1010B000F1FB8BDA8332D77BB543B150CDEA49DE01 +:1010C0003719E4ADFBA32EF7FE3EA3DC07CE31CAF1 +:1010D0007B906A94F7E0C546790FAD31CAFBC6D55F +:1010E00046B966058C72CC5E3FCE307F445DB961F7 +:1010F0007CF3F3B719E68F0ADD6518E76EBFD730CA +:101100003FBF7EA1E17E61D3D2EBD27F51B8D63012 +:101110002F51FFC5077E7B55FD07F057E81F581F6D +:1011200065A88FB0EBFFCF0E4EE87156B783EB8CFE +:10113000B36F92CF329E302112203B284B663B99F1 +:10114000992CE2CEFB07CE1F5270FC81ABD892499E +:101150007596563FF8B438A4F733897DE39D655200 +:10116000C2FBFE24C3FBFE6B7D57E76D0D1BC6451E +:101170008780BF9BF11C71BF4DD47B5261B8ABF42B +:101180004CCDDB44C75EE0B4DDAD5FD5BFCF4BECEB +:10119000B760F9217EAF384F7F2F434E51DA1D9F44 +:1011A000D4FB31BDCF4DEC7FF5BEB77B9F26EA98CF +:1011B000EEFD863BD3CC75B4CA75F57E49659C734C +:1011C000CB2875B0D74B4D00F6C926EA93234121B1 +:1011D0004C05E83D7494FEA72224F0CCBD84C7479B +:1011E000D380F17345AABB3790C7C777464A057CC1 +:1011F000443FC55E758417F57A4272AE2B267C6239 +:10120000DCD7C3A81EC9F18A3ACF26A3A4302F0D7C +:101210009CA7005DFF215D19E5F5C6F092DEEC2686 +:10122000F1FBA4067F98A9D9E9E6EF9712F1C588EA +:10123000C9C5F569E0B7127FF7F3351D6E6CAC8E4A +:1012400039BFDEC2750C68FDFCFD9AFC75DC639E3F +:10125000C6CF095C6231E6E5FB9BF6B35E9665B6E8 +:101260006B78490DD7E30F0E7178F87B38A5D82D30 +:1012700070321D07192CFF94BAEB5AFC2FCB3C6B34 +:10128000C0A1E0B57ED7F5BE3CC6B758FFC4068105 +:10129000679ED83094F1F3D8FAE7188FBABFE643C7 +:1012A000837FCC5F7DD4E00F0B02C70DF723199D20 +:1012B00016C21F236F0C9A761FCAAFA3D1564AFAE3 +:1012C000403B7898F4AAAF1FD9903B85F6BD369F76 +:1012D0005FF339DAFCADAC5F9DCF63FE233C8EF843 +:1012E0002309DFA7093E759C43A7D6BD9063A6F7E7 +:1012F00089521F37E1CABDE11FBA9F994A87F33A65 +:10130000174DAE530227AA1943F55FDBE401E574DC +:10131000EEB6A156B3A023C57850995D8CA74D2792 +:101320001AB538D6132ED22689EF89E649CA4B0B57 +:1013300070DFC747A94F913F542FED2C20FFAB2EF4 +:101340008C3C20E1FA5DFDD58D241F09DB8B41E942 +:10135000CC077F7776C6142890D055F679BFBC9716 +:10136000FAC4337D02E7A842D9DD784C8CADC21FA8 +:10137000DFF71E60FF3B898B119F813F4B029F72FD +:1013800044ACB3709D8CFEEA73B42F7D4F46EFF7EB +:10139000E83AD9A78E97462DA24E8C6AF5E266AF41 +:1013A000A8675F4AA04D54E312FE4894E3F5D323A7 +:1013B000094F3FBFC90654DFE2FE8AA924F6FDCAE1 +:1013C00000E485EAD877ADA2CFF4FCC516A638A50F +:1013D000E3AAAF7BB378BD8C6C819766FC33C62DD6 +:1013E000F2C348EBB0592971E73D048C6377101EB6 +:1013F0001D8763BFEE15FD3A3C24E25EC786C18CB3 +:10140000B7AF3878E218C5AF7BBC6A23C975A1C9EC +:1014100055CADF67A5EE61DC6CBFD7C5FBE27999E1 +:101420005F8C436B494F2BEC11C6D9AE85ABF7C629 +:101430007FC7A2D6E7F21847761590DDE8FBE239C0 +:10144000F67BE3F06FFD1CB175AEEE073A3EAC8F54 +:101450004F6F7E6AA486EFCFF7F5905F8F69726950 +:10146000B3F48CC75FF28AF778DDF4733300E1FFE1 +:10147000B63E98FB917EED15FC77CC457E18DF508B +:101480008A48BF2BEE72B849CEFAFAB88EFAFA55EE +:10149000F6E91AEDFB8AF85F5A23F07BFD7E5412C1 +:1014A0007A0D6C1078EA8ADD478F3D8EBB2C79353A +:1014B000BF98F281FE7CA29C51BE23F9FB3B59BC34 +:1014C000FF42F99EA7F51371FB9F2BD7E850F19EC1 +:1014D00036BAE5D230FA3E6D057D0F5740F621F061 +:1014E0002F6830E25A28AF00E11BDDDF6B01BF1F20 +:1014F000B369F9C4A63F3FC46C78BE3EC597548A11 +:10150000E77F438B1B383F64A2EFB9B5F8D4A0F551 +:10151000DD89F84B43ABC04D1B32AD5C4753FD43F7 +:10152000F7F5FA67D58702375D9525EA6C3A27E922 +:10153000593AB28FEB852BB8B884F91EE5986E55F1 +:101540008794923FA92B399FC937A29EE97DC85F36 +:101550006FD37004911FBD5A3EF4D23A74AEBCBE34 +:101560009C274BB47DB1BF60FC6E2CA85AFDA0E156 +:101570006F1BF619F087FF037A5FA88030310000F7 +:1015800000000000000000001F8B080000000000A9 +:10159000000BFB51CFC0F0030947B0A3F20FA0F13D +:1015A00067B2A1F2B3B950F9875950F9FE68FAD180 +:1015B000713B13030323137E35F8B0083303830C08 +:1015C00010AB00B10E33F9E680B089280343A904BB +:1015D00003030F906604D23E405C06C4FE407E27A3 +:1015E00010CF0262197106864B405A5E8C81E1A5CC +:1015F00028449F2D90FD438C3C3BAD792973F32803 +:10160000A60C5BCAA2F285D41818BCD51918266B93 +:1016100040F80648F2AB8062C26A10F611790606FD +:101620003D205F5D16BBB94781F2FA40F9DD1AF83B +:10163000EDDFA183CA773543E5E7A1C937BAA0F248 +:1016400035DC50F9AAEE101A00B1C92A3BD80300C4 +:1016500000000000000000001F8B080000000000D8 +:10166000000BCD7D0B7C54D599F8B98FB9736732D7 +:1016700033B949263079C14D081030E02484808A7E +:10168000701322449BC204698BBB6C77C4D646148A +:1016900008EA6A7C6C33790701096A77295A3AB1FA +:1016A000A2A0B44D5DDC3FB5D69D40DCD2D6D6A01D +:1016B00058E9AE6D23F5DF5A57D9A052A9D2B2E747 +:1016C000FBCEB9997B6F2609E8EEFE363E6ECEBDA5 +:1016D000E7F19DEF7CEFF39D1345F4106D0921E7D1 +:1016E000E1873E5F25F4273BF924A48790F9F01C9D +:1016F000922373E019E3EFD933B8B64F2045581C55 +:101700002495841410F653D0D4B9599C4BC8641254 +:10171000FEF1CC425A1EBABE8E0468F9F5ABFF004A +:10172000CFCED5D5B557E984E4ACE93BB69C3E8332 +:1017300091B8102D25E4412212920BFD15C7AA7C09 +:1017400084B44367971332299663C44AA160D002D8 +:10175000217FA7F28188A8CBB4ECC75F93F3309FB9 +:1017600084282451821585F3EED1ED9DF5CDA71F78 +:10177000DA99750AE1FFB71298DF44EDC8ED6CBC49 +:1017800018FDE73CC54B5E727CEC27A7C152268052 +:101790001FFB776304EF9BFF57C6CB25E51EBD8279 +:1017A000CEB74ED4E2509FF465C8B41CBC452609A0 +:1017B000817EAFE8115CFAC4EBD249486D9F0FF10E +:1017C0002BD4FB93F07D8E08389F2977BFD9DB158A +:1017D00024E4CC5A5F18E94323242B73F47CBED64F +:1017E0004C48C26D29AFAE16A2385EF8C7C5B47DAD +:1017F0006CB518DE0BF0D4ADCA80F766BD3BF93886 +:10180000A3E983E832C5A3CCE943AE130DCFDC4F87 +:101810004F1FF227A48FECDB2DEDC8C5AF17E27D7B +:10182000FE85D3C7A71DCF5CD7D17CD582704CB9BC +:10183000BBD843E8FA3F50BB2A3D9AA2DED8EB5A08 +:101840008EFC1EAC23463C45BB2DB09E38CF984D38 +:10185000DEE093AE8F34B2BCB7D9D64B9A5CB9A652 +:10186000771C7C4841FB7CCD7E9526497F338B16C7 +:10187000654D84FE64DE5FA7B62E46806E81B62974 +:101880003EA49EB204A1FC414224BC974320D2B2A4 +:10189000A219F1FB0428C5715D4CF8D462D1369EC3 +:1018A0002BDF6B5B0FB2262658E1579A1484430650 +:1018B00036E1F22E82C28DC10D439C9F06E57B6C02 +:1018C000EB2FFB48C243E5EA96E272625D07934E56 +:1018D00005C1A4D37B2E4CAE38C75B6D87F382DB8A +:1018E000F964FD77669BA2F1DAC9E477269E28F2B7 +:1018F0005E815F2CEBDEE52287844B0969CBEF8CA0 +:10190000C1DB2EF8DF65489F20B448577EB906F446 +:1019100044F60932C0E931C9239489F57A898EF4F5 +:101920001413EE20504FF245104FE6F7B1E1E27488 +:101930001733FA8B69BF9FE5DD7E96EB3352E17A70 +:1019400073C884BB08E7912CD379BC7B17FD1FA516 +:101950008F589910DF2B8CFE5E07FA90CAA33A7855 +:101960006F91276EC12ECFEAF8B723CFBC36631E26 +:10197000A5C7C1B044405CB53EE3366A68FFC7AE58 +:1019800014E26E81C34BEBAFE070BE686415007D5E +:101990000ED6B8917E572CFF3008E47BEAD02B722C +:1019A0002A7E5DB1C8958483FEB7C93A3FFADF2429 +:1019B0001803F9B206E9C8846B43B984700C2E127F +:1019C000E230CEC0AF7E7FFF1514CE172B84B05B04 +:1019D0004778FD848E3768BC1F1C4F4E10737C9D6A +:1019E00068804FE7F823EBA186D7005F36688A7ED0 +:1019F0001F1DEF66297C14F41899CCF4438336A399 +:101A000006D64712187D2C1572B05D9BAF7512AECD +:101A1000BBB436A5BC6AA08A422B87EFDB668C0B71 +:101A200067DC353C64A1EBA6D70BEF1FB0C039478C +:101A3000F0077F97467F594016C03ABFE75B959EF7 +:101A40002063F7F776B3DA22BB08F9B059BF7FC03D +:101A500035FAFBCD1269EC2B1DFDFE1A41E5F88825 +:101A600029609F99F31E99A72F88F47D33885F4AD8 +:101A7000EA37EFF3B4C856F9E398C7087E3F613BF5 +:101A800035786B2C57077E8BAE14A01F99FE5399A7 +:101A9000E4C79B0FD433BE73C0DB11FCEF81772208 +:101AA0003E7ECFD7DA09F66A9B8BD14B7BB6186E98 +:101AB00025A3E9C55C0F138F17BA1EDB040FF2874D +:101AC00049470DE2DA71D77D223ABA03E8E892FF7E +:101AD000793A7A10E868FEFF493ADAF57F918E92FA +:101AE000E5E5682FACE47DF50FFDF62190CFBF3022 +:101AF00024947BBF58C4E4FF2FA24C2E0E92E8F62C +:101B0000F9A00F8E4B28A7068D363FC24B4D629829 +:101B100007FA5D94FE5E017B692695EBCD2A3EE9CE +:101B2000EC0B56D1EFC7AEFA301FF4D731BAB6601E +:101B30007F13326C18B4FD4B23656A8043D9C3CA46 +:101B4000C32D6763609F0F0AACFC2F2D678D188E25 +:101B5000B7AD7339C5E74AF895C2B17A9160C453FD +:101B6000D0C54F0485E1A586D8F42A5D979F0894D7 +:101B70005ED4C866B4AB098910F40F8BA99D60B11F +:101B80002F9A4081815CAE71A3FE73F6FF12B70BF2 +:101B90009D76DCEA45652ED017EEC86979883E57F8 +:101BA00046042C03FE350BDCA22118A007228BDC97 +:101BB0008F82FE8BC8C4A5A5E0D79586DB66779D8E +:101BC000E67A8CE2650DF35BB482FA39C9FAA74D67 +:101BD000FDEB98CF587461CEC32C5FBBE8F4401680 +:101BE000CCBB56084F8786AA56F045BFB5FF34D305 +:101BF000BEF103DE7EB1E6DA74460751D4AB263D72 +:101C0000FDF88DAFB860FE647516D2E5EA3AC96694 +:101C10004FAEAA49B3953FBFE8DA71ED7012B5E057 +:101C2000C142F7813C82744A7E43ED144AA7B1EA6F +:101C3000E128DA2D2705BD8D96D317374D857EEF28 +:101C40001133B1BEB0B869E610DA5BCB90FED37841 +:101C50009FE94AE3EF8B40AE4E17C9A33AD8A3E3FE +:101C6000FB051D9CCECDB22B188D09743DF5985601 +:101C70002E8D83EFB821D6A6F21BA6896CDD3A62C1 +:101C8000ABB4620068C02E37326A1AD1FE33EB5310 +:101C90003A9E2666C3B8317C3F42C7DD745EB49D70 +:101CA00097D922247DF6AA7432CE3CDA1DEB4FC5BB +:101CB000BF914ACEDECCE1238758FFA64C4ACFA481 +:101CC000FDA7A86F3EBB78FF67C322190438E588DB +:101CD0008AFC50524DACFD10A30CCB0A2FBA431115 +:101CE000B590E2D35D2AC2344847E9A386AC031E0F +:101CF00062B8DE5BE9DAE65BF872EB9F25F4F36F1E +:101D0000168B5A406E6CEDBF89E8141FDE509C6044 +:101D100079CE8D2AE0692B75B206617CB98F001CE3 +:101D200069F9F4773A4E9A46E23AED4FD6FB122221 +:101D30002DCBB5246CD04F7E2D2C78A99C381C2A35 +:101D40006A91E9FBF6B504E52301E961A19FF6D0AC +:101D5000CB8604F4B3868401E0F6E03A9C6767E939 +:101D6000BAEE42FAFE4C9D8CF103728EC26BFAF50C +:101D7000D4CFF0961003C6DB9A43E23EB4830DC481 +:101D8000AFA2B1F5D3771593C43CFA3DA3B21FC6F9 +:101D90008FFD3D617C49985C93B93C2132A53F1889 +:101DA000BF490BDF9782FE5412BD499C6F59672DC6 +:101DB000827EAC136FE90AB906F0DB5E46F9208536 +:101DC000DCBB4314910EE2E1552B8B528C738FA830 +:101DD000A37C32CBFA5905E11FAB7EB29E4C12595F +:101DE000D0B521005E482488F3CB24233F0694B36A +:101DF000F87C279146AC175AD8D30FFC966BF45554 +:101E0000012EBEE6FFFC315C37F28806762C85B6E3 +:101E1000F87C56525E80CE81F9BD1716D1EFF08B5B +:101E200009CDA01DF83D8321747E758271B9746857 +:101E30004201BEAF596D07BB2440C2027CF787E563 +:101E400098D5AE4F27B46C8BA790E3C59584897C59 +:101E5000FCAEF503EB68258D9702300F068C7F05ED +:101E6000BF699B3F8A7ED8879EC05C18EC4E6FE0AE +:101E700051787EE8991247FF2CCCFC2D95FE03F299 +:101E80002E7DA16CF36F320C7B39CBE1872D937CD7 +:101E900038CF8CCF12EE5F1975D32725E1A210D56C +:101EA00003BDECAC9109F8FF3E1F83C7842F4BBAEA +:101EB0007701EAC7B07C12E0A0684138CE90730980 +:101EC00058E24009C1F82985EBA403AE930EB84E41 +:101ED0005AE16A52D97C9DF662AC9A943452E07E03 +:101EE0002872FF83DA4D60379E21EF18B540389194 +:101EF0006B50CF0634D6C6A70E62B042231AD281E9 +:101F0000D36EA4EBF49ECDFF5AC8CB3A11601E14D9 +:101F10004EFB77928FF48265898CC485D72D34F17E +:101F2000A57FE1DF29FFDD74D44580BF281F4BF07A +:101F3000DDC5BFDEC4E3C3EBC0BFA6F8FB12890456 +:101F400000BE77898871A877C9CB81791639794A1B +:101F5000E4F6092CB1958F493804725CF6750E4A87 +:101F6000014483496FC2795CC73093F33E467731B1 +:101F7000A2B6A03EEC66FEA7194FFD728FDD1FFED4 +:101F8000CA2E7BF946B26A12C44B6F7CC845E2B4D4 +:101F9000DF9BACFE3D5DA757450DE1FB0A69EC04F4 +:101FA000BBA4CBC5EC8D751A9121FEB9E1FF7DA3D1 +:101FB000F27A3A9F33200FE683FD4EC1B7E891F5E0 +:101FC000C1B862948E9E5F9B105E718530F6FCBA3C +:101FD0005C832BC0FF8E6D77A19D499C71D08312CD +:101FE000C6412DED10DE1BBAEDF39B68FECEF91253 +:101FF000F200CE77FDBEEBD13E1F6B3ECABED4F6DB +:10200000A64F126C711F93AF4D7A77F27785A4B308 +:10201000B80E558368AFFC3A2DDE86EBDBB800D6F0 +:1020200077A2F69741FBEC4FDE7EF1A71C7FE90417 +:10203000ED37A8C3CB60BDB7047B22C09F661C6B85 +:1020400023891979F457D7739B6360BA8DD40B5DDC +:1020500060BD7C5A4FBA807AC5E3F7778ADB253FAB +:102060003AF02D05ECD4779F7C6305D80137FF400B +:10207000222AA5875307FC2481F64A5C01FB663DB2 +:10208000A5BB38961395D75AEC614AD1B80E377F65 +:10209000D78F76C4FAA7DDF13ADA7EFD3FFF762EC0 +:1020A000A17838D53AFCAF7940CF4F0A2CEE1A1BF5 +:1020B0009A7B2D7DBF5E267F1B494147D74B8C9F66 +:1020C000DEF97EDA1AB013857DFD5FC47EFBBEE0CB +:1020D000725BF4F11AC985E3D27AE847C4F60BF1D2 +:1020E000E90283CFEA0F98F1EE77F60B0CBE43AE10 +:1020F000B807E0DBD7AB4469BD4DFB4E235D2FFD38 +:10210000EEB70380874D87EC76FAA67D52C23D1765 +:102110009F6FC01334A85009F864FCBCF1E006D4EA +:102120001B1BFBB69E067EDE74C86593FF142FE171 +:1021300004E0F535295C07E57F7A22A05354BD3DC4 +:10214000B8370078A5FD5EAF50BA5AB9D0DE0EFAA6 +:102150003F9B39BA3FEA19A2DFBCA96F0B1BEFE026 +:10216000677F0FF27613617ACAE4E7B7E1979CD1F3 +:102170007A668B648F6F9D212F56E23EE0BEAC9451 +:10218000FEB3A9574CBEBEF9DB67F6C4E8F8EF3CD6 +:10219000FD1F7B62741EB7FCE5FD3DF7D0F991E7AA +:1021A0003D1AC8AB4D4FBE1A2016FC3F26B1FD802C +:1021B00053FB9F787C37E59353BF74A31D78EA8760 +:1021C000BF9FA2D3F99FFADE9F26819D7AFB0FAFB6 +:1021D0009A0CF8B8FD99A593C7B3D7816EE36EEB5F +:1021E000FAC6B17FFD90009B20843CC79F8E753A54 +:1021F00072504A4088E0DD13EEB89BE267137DD74A +:10220000540EEBB601F51594EFA5F8DE78A0EBB40B +:10221000343715DE637962089E893C128275BF7679 +:10222000E59515F0748575A013328C7AC2D96ED3FA +:1022300071BABE978EBD9ED49E5000FF9B0E6C61FE +:10224000E3F6D1F50C8C5ECF77E197CB46AFE71183 +:10225000C91E673A436EF9E66EF878300BD77FAC4B +:10226000F5DCF0CCE7C6F5EF4CF930119E1B040607 +:10227000D70EC97845027E7CFAA9C77707D93AD725 +:1022800051C49CFAF69929B0C9FB966BF88B2027AC +:10229000877FE8D6C0AE5EFFC3D790EF4E3D734C4C +:1022A000D1717F9AF804AA274F91919F41D09B1B2F +:1022B0000556D8F4983FE10E24D76B63BCBE560F89 +:1022C000E0FB37F07D9CF1C3C678FF6A21C5FAF9BF +:1022D000E422A69FE2D988970DFAA0A2F9ECEB2A96 +:1022E0002C84F57C6319D0DF58EB69CE5F83F92F1E +:1022F000B0ACEB638C8FC7E2D753BD6E59481FBD9E +:10230000CEA7B85DB1292EBC966ADD096965F1BD1D +:1023100031E2DEE6D349178A6CE773B3BD39FF8932 +:10232000F87CE2795D1CDECE707DEDC4DF3BE752C8 +:10233000EB812259E07AABA736D7A2EF3C2EAAC791 +:102340000AC1EE6C8CE51526E1EDEC9350BEBFB3EF +:102350004F427BDF2927368EE1D787CD710EF5CF2F +:102360000579F6CEE1EF737A64F4BEF1C01B4A8CB6 +:10237000EB85B8552F407F29D6E372DEDFA6E75202 +:10238000F7B7E9C0E994FDBD2D1B5F00F8DF1E74AF +:102390009118EDE2ED3E29659CA45876D9ECAC4E3F +:1023A0007FE58974DA4E0A787598775BABF15A0C41 +:1023B000EC91975D04ED4739FC969B7E6FF37B7142 +:1023C000BFA52D7023D12DFABBDD81273914413FE4 +:1023D0005A0E462AD85E68DCE6CFBA34D106379169 +:1023E00063F9B0CFF9F3C2DFCBD02FC4D3744B5C09 +:1023F000E8259974403CED254308B79014712D47AA +:10240000FF914512D1AD74664C15ADF1C5C0E1BB6D +:1024100030AED1441A13106F22F9A46FAFA5DF4775 +:102420009A7516778D4C15ADF13F7763A3E1A670D1 +:10243000E4DFAE1581FF36D6F8058DF67D5F73FCBF +:102440005B793C82EC7BF2C92769792A7C13810E87 +:102450002306C2718EED2B2FE5F2F047DC7E3E2C79 +:102460009001B0C36AEF8DCA20EF84D0F518175DD4 +:10247000967FBDBCCE428FCB42A77340AF7EF3CFD9 +:10248000D29A54747A88D355CBDF3F9E03ED777B85 +:10249000BE90CF9CD908C297C7E35D03D9CB7D100E +:1024A000DFEBBF69D98B33E87C73358940BC269755 +:1024B00054F9CA289C79C7A5B027C53A98CF3D3CA6 +:1024C000AEF768B386F2FFB1E610961FE778DDD766 +:1024D0005C82CF279BC3F8FD40F3422CF735D7E24F +:1024E000F3E9E608BE0FDCFD6CBF0278F92AE98348 +:1024F00078CDC1E635F8FD9F9BA3F8DCCBE7B30CA4 +:10250000F0E2B3CD1FE33187DA97B4423CC6C4A3EF +:1025100013EF4B486CC08DFBF9820E78BF4B66F20F +:10252000C589DF29EE3E01E44BD32D04EDD73D3CB8 +:102530006E6CCEF7EB32B3370F72787EE0897E4750 +:10254000A6CFF76A8B4BD12E229130C8EF3D4224A3 +:10255000BD8C5679217B41C82A87A7FAA30765CB92 +:10256000BEC2946E16EFD92D337935553FDD9F41AC +:10257000F1509B2FE8104E30E77BB84ACF073979EE +:10258000581070BD6BF3255262A17BB3BF6FC82298 +:10259000DFDF482DB79374CCE441E6D57209F8B576 +:1025A0006788372C517E7F3E871C24D4FE781EE836 +:1025B00012E4C2AFD2304E6CFA37DBF87A670251C0 +:1025C00040BEC4EBFE38C89FB1FC9E4E5EFF3D0E80 +:1025D000D70639F28A8CFBCA3CFE4A1218C784948B +:1025E00023A0C7DD9EB53B6AE8F3FECBDF3E01F1D9 +:1025F000C1779FF1E800D7F68A93012B1E4983FC2F +:102600008E753F7E44DE9CCDC3B8D8FF27D137649A +:10261000AB1C0A0E2BD0FE7941DF09FBD7B1572541 +:10262000E4BFE785F82C8C63C904FD82E76F0A617B +:102630007E87D9CE1FB6F377A667E8E14D30EF0667 +:10264000251C4BC117BF49D36DFB46EE90BD7D08DD +:1026500074E67C56D6297D96F1798765430238E683 +:1026600093283E17101D9F39AEE847308F79A42F6D +:1026700007CAAD6953AE60FB07FF6378535DFF0780 +:10268000F166D26BE8F2128483DC2D86A7EBE84D6D +:10269000DAE87CA54BE0F855519EE78EEC4F35FE0D +:1026A000A82088DDB0388996867230D7C3F0D73439 +:1026B000741AE3BBA129C41677EF6810910F76BF97 +:1026C000CEF6F5CE3414ED9C41EB57117D474DE12C +:1026D000E87998FCB15B8DA4A7DA9F329F265F98BA +:1026E000E59D53BF48400EFDE3D42F62DE51EEEB73 +:1026F0001E1DFC8EAA5FEF6F01B9D8F106CBAFF8B3 +:102700009537BAC8353F29673A6E6A9C0A7E50C031 +:102710001F59ECA2F889E4C7AF037977A6F676379C +:102720004EDDC7F25E9AEED577CED4C75E9F3D4DA3 +:10273000E3EFDF98F3DA03F31A67FFC29C97B95E01 +:10274000676A570FDFA8839C294E8FA66837224FF0 +:10275000AE5E3DEEF87BB85EA1F35F6BA5CF294D71 +:102760001AE6B798EDCDF93ADB3BE79BDC07BEB044 +:10277000BCA03E17C9027AFFDEC753FEE925148DBF +:102780001109F434E5CF8D004F2569C43291FB72F5 +:10279000C0BE31E97977E7E339A817E47821E67715 +:1027A0005DE0781D2412A9027E0B8B61ABBD623EF9 +:1027B000DB46E83C81715537970362DABDA1547856 +:1027C0001EE93FDFCEFFDB0861723EA1A29C87407D +:1027D000A146CB854749F97DB4BF06480AA5E35415 +:1027E000C92C1E32EFA8DE2BB1B8AA54EFB7E09186 +:1027F000EF3798F1DD0E722FD174F02BCAFAA1BA1F +:10280000C9A74794E84340A74A48C77C4F57302A96 +:10281000B0FD38B63F54C2ED92ABA4B52AD8254DD1 +:1028200024A2CE06BE3D2E119687C7F8DA6DEE8340 +:10283000713E76733EA61C8CE519FCFB739CBE0EA4 +:10284000817D82F604A3A383DC3EA9191E3EE2A784 +:10285000ED4A067BAA613A4F83BDE206FB248CDF7A +:10286000BF03F60A2D1FC9F8C76B6653BCEC33C40F +:1028700030E0FA40B3C1F8A1B901BF37919877337E +:10288000C8A547440DE0EC7AA4550AD0F27E55C0A5 +:10289000F8C523CD8D583F70CE9B007F73BF9A1033 +:1028A000C01E391326E118C04DDD2398D70C3E8F8A +:1028B000AA370771BBFCF1F87BBFDD41EB3DB8D017 +:1028C0008BFB64267FCD681AD6AE01BEDA7B52DF61 +:1028D0000CF0CFBFD580FADBC245B84FF104C51765 +:1028E000ACD3BE5DEFED1AA4DF0372D766F0836749 +:1028F00016AC427B28A0FEE36D500E684FFD1D3ED6 +:10290000D5EFDF09FA7A665CB4ED9F07D49FDE0548 +:10291000DFAB87C235E9B49F59C707BBAFA6CF8EDF +:10292000F0ED2290787AE61F705FE3B0A07DA907F2 +:10293000E26AD72B48AFC609A305D8D15561CF832A +:10294000CC7E310A690B64F200C53B01BC1B32F43A +:10295000FB96AB10E92C14C8A909D0F2E38F9DFCBB +:10296000F1D5F4FB915DB7A25C743F22A33D36F331 +:102970001BB793AF58E484FB3139655EE95B2E37B2 +:10298000E3A34756F7CCD2197902FFCDDA5BA3A2B5 +:102990009C78D19EE760EE0BF792E85B2EA4676609 +:1029A0009FC81ADB47863D2FD84F240F8B8C4F22B0 +:1029B00051AF35FFB9E4EB6224559CFBAC4BC679B3 +:1029C000B5C76B4A601DE4F377E03E19E9B18F6F3C +:1029D0008E47C73F6B956FB2C6E02A00D54FD7B37D +:1029E0005FF9F71C80FF6CA3A9A712A8A706CAC4A9 +:1029F000C4540ADF030F897148CA3C52CBF4D6761F +:102A000099E50B6EE7E5C7CE91B85098E4A3999C81 +:102A1000DF1E7B4464F65C9CA09E23E7CEA37DE191 +:102A2000E3DF33CB5E56717F2266F8AA2A312B9002 +:102A3000FF58E885E2E8D298D72667C5A64CDBFAAE +:102A400017508BC59E4F5D94AC2F811C3FAE02FD8D +:102A50009EA17E2BD0EF12BE4F5463E6614AE7E69B +:102A6000C1FC1F36F5AC9937E3C893DEDBB8CE0B5B +:102A7000F1C2174CFA696834D0FFD1DC389EB94FE7 +:102A800058724B2406FAD3956FCF9FAE72E4472F4E +:102A900071942F36BE52AE38E3A8DB66211DE801E3 +:102AA0009457C51CCF7B2FA3EE7CFAE838CB48BFE8 +:102AB0003C8E407A02B87EC59C80EEBF5B6A00BF48 +:102AC00020F040798635BF60B9C2ECEE815FB9096C +:102AD000D8F9FB6B548C679A799D2E3EEE0A45C758 +:102AE0007AFB1FBA4385F65DC1220FE0EBC8E5EB28 +:102AF000BD98FFC1F3534DB9DB7AF9FA6B6E0279D9 +:102B0000982DA2EEE9C86FCD857DF9076A54CC3FB8 +:102B10000DA40DF51DA165DF134AF851FA7D7F550F +:102B2000628D356E7387C2F4D7750ADF07DA66CF18 +:102B3000DFA07C709D02F961BE46DCB714559EC7CC +:102B4000EBF0EF4D7C040E5F2716FAD9B3C80FFEE9 +:102B500028A38F38A78F3DDC3F7D04E4BF1BE886A8 +:102B6000C9FF6DDC3F75F63BBD217258013BEC1689 +:102B7000AD1C4251CEF59DD66DB7270A6376393725 +:102B8000D549F78DB9B6FA790D45B6EFFEF06C87E9 +:102B90007D92607A8DB0F5E9F2F8A681DC2EA77AF5 +:102BA00097D9199A18B1EEAB38F47A83CB68562EC0 +:102BB000C2BE09A4451A617D9CF6F456BE3E7F2331 +:102BC0001B5B94F9E8BF6D8527B58F79BEBADDFE32 +:102BD000180527A170CE1917CE872E06CE89F6D9F3 +:102BE0009CFB6B774A915D2FD1E7E274960FD9E198 +:102BF00067FE7C07C45169F9594E874F2912F67F49 +:102C000088CF77711AAD9F82BFCDF8EA73907803B1 +:102C1000F526A7CEB3040B08BFE7A5FEFE9CC2F6BF +:102C2000B3174F1D7F9CE7611CFADCE632BEAF583C +:102C3000E278ED8AF1036B39A1B0FDE79175E17996 +:102C400094A63D7687CBE8B7D64F3EED72D3DC072E +:102C5000C9E6EBE9278CFF5E58B36ECB74CACF4A46 +:102C6000BE0FED9FEC35ED9BC500E41F0D6AE00F34 +:102C700064F37D7CB29AC951735F3DB3CE2E579DEC +:102C8000E7ADDC3C2FDEED3C67C3E5AB931EC7929E +:102C9000AFBF56ECFB1A23F1EB31E8CA19BF6E82C5 +:102CA0005F999DC9EDE048FAAA3963D3E3CF9B87CA +:102CB000B70F4C4F965F82F33329E980ED27060E5C +:102CC000FFA16E7505ECDBB178DA607362F19BD31E +:102CD00093F22BB228E305887B466A3250DEAC08BB +:102CE000FD71FB00F5C7EB8DFEC56F5AE639A851A3 +:102CF00068A78DC32786EB232B7F3D2130FAE9E0BF +:102D0000E3EDE0F874DAD15D62CC0DFD7E40860C17 +:102D100021855F6B9D773BE26DC8077436D6BCC3D7 +:102D20006EC65781858D6188D3B9CF4BC807EEA990 +:102D3000A6DD1246BB659E3B839DFBF015E13E1E62 +:102D4000F5D387FB611D7C2CBFDFD48FEF9BF15443 +:102D5000AEF76ECB60E5ADCD2C7EEC3E72D96B3A12 +:102D60006DE77FD1453CF4FD162AD7210ED84DEDF5 +:102D700078F81EA8182210476FA3F5A316BFBB2D25 +:102D80005CAD819DD05E5AAEEAF4BB34A702CB7233 +:102D900061B9564DC79CEDFEDAD26C8883178B98CB +:102DA000575B4ACB2DD4A44B776B38BF9F97BCE9B8 +:102DB00003FB2C1D9CF3F9C9F57455440D89C2E33E +:102DC0000A69D5908B31A2B7399DD1F78F42BCE407 +:102DD00009215AE9A6F3FF393F7FD5A53496DC0ACD +:102DE0007E8F1C7343FCA04965FB10400FEDF392EE +:102DF000702FE1F855F8B8237E105FCF0FE4A118CB +:102E0000A4B67689A421D5FA5CED6672AE5D33B4C2 +:102E100071E949933FB2E54F2F62FCA404293DA517 +:102E2000883F3AE5357147EADDD9C97C25BAB01A41 +:102E3000F22961F69E79BEE74DC5F89C9BCEA3D5DD +:102E4000C7E5587E26D2297DBFDCFB89E43E8BCFC7 +:102E50001C5E5471AC06FC924117C68B02D3C8DFCE +:102E6000462CF2F6A81B836EF4C9ECA4FB287DC4A3 +:102E700067B2B80401BA49A38A18F6210BC4F8A3B3 +:102E800085006F6FED34DA5F973C9D5AE6C97EAAE4 +:102E90000A98FDBFBDDADB60F503DE4D63FB2F77DB +:102EA000F9AA9E86F995FAE2D5E83E4376E62476BD +:102EB0007E0AE8F8128D0C0922C8C108617A33AC89 +:102EC00032FD5AA3C179298144C9F9B4F1F4A3FDB3 +:102ED0005CD59372BCD50BF808B278977F9780C900 +:102EE00080529F91F08298F4AD6A77337D5102E36E +:102EF000F4577A898FD6FF63BF82F6619F3F4F06F2 +:102F0000BC3E2FAEFB26C49F867FE9C6FCC6BE3FF3 +:102F1000CFC6FCFB3EFF15CB406EF709E42855F603 +:102F2000A4EA6C1E4F362469B0CF17586A10D8E750 +:102F3000187E8184213FD815FAE9E237E7E1C4D34E +:102F4000C485B49D87747B68BBF047DEF79750BAA1 +:102F50007ADA57FEE0A524195731E329CBD2A20F24 +:102F600003DE3A26FD5B03F04D37855342FBD5085F +:102F700001DCE5D922C61F49B62F3E1DE265478315 +:102F800035903F5A2597616A6C60295BEF5F79A3A2 +:102F90007B61BE355A7D0DC4D72B8EEB2867978594 +:102FA000360F40B9F27556EE5018BF40BC8858E451 +:102FB0006ED5D92938BF3E4E27ED2163D010C6E526 +:102FC0001BC7B9037BBE9C950E20CFDD42075197EE +:102FD000950E16523A9863A50343B8183AF82A2A70 +:102FE000EB4FC23FC66B3542326E379A0F36AB9904 +:102FF000A5A3F9C584E3BE8ACC20C851932FB4059C +:10300000F7A25C755FAF44C05F37F9C4E48F8F3DB2 +:10301000237C12017E5FEDD3AF4AC527E08758F9C4 +:10302000E1DA31F86605191E08D2462B64124BA767 +:10303000A2E4E797BD553CC5C2074EBCAD582490ED +:10304000933679C6CA16BC6A23E71BA50BC7FFCB0C +:10305000B2DE11B4F06127F543C058EE16C304F494 +:10306000CA02DFBA3F025DCA75DF0B813FE87247D3 +:103070001A306F76C13B693752BAFCE3245187C9D5 +:1030800077E8EBBE8BFC7C228D807DB2BD723DC6A5 +:103090007DFF7853742AE8892D14FF27512FC72705 +:1030A0008B9883393499EDB7EB21F68C86D87BC2A7 +:1030B000BFC779D9E0F586B01E5D679B7CDCE16116 +:1030C000FB5D3B3C4CDF6C517A54E0B7E142554B21 +:1030D00095EF5CA9B2FA4BDCA4221CC4D1705FB995 +:1030E00043956A7B599C2FB184BE5F32ADE451EBAE +:1030F0007E81D9EEC1E63EB453B6341FC267565D39 +:103100009C40DE95B724A6C3FEB8FA97A5820BFAB9 +:103110009DCDF671E17D8BC54ED355C69FEA5FA468 +:1031200028F0B1DA1AD3332DF2581585682A7B7B43 +:10313000A787C569D45682DFD5C35FC77DEFACE2F0 +:10314000B0F06528B7F69030EDC79360EF83C58681 +:10315000F0254BBFC1BA3E9B3E5C41972ABD1CADDA +:103160002C3C17D3A17B719F6C45B0FA0FF2DCD1D8 +:10317000F4063F272D7463C26FEED7DECEFDF49ABE +:103180002215F9B4A349E9C573302AB39F3E085606 +:103190008F7BAE00F669A98587FE303C61BF36366D +:1031A00093EDD74219F66BE109FBB5F084FD5AF8AF +:1031B0000EFBB550FE4EB38165D8B78532ECDBC649 +:1031C00066B27D5A28C33E2D3C0F3537E0F3D9E671 +:1031D00046FCFE5C731396293DA0FD474A6221B070 +:1031E000ABBBEF520CC8C7E9E2EB7EC428CA027A37 +:1031F000F104593CC1F3E203782EDA131231BED741 +:10320000197A80DC409FDDF3FDDD101F51BFEBC359 +:10321000A7477E9080DDB64788359030211BD58A40 +:103220001A99DA13C5A1CDD59961C0DBE5ED909F60 +:1032300038436F09AFD39265DD5FBEFE7B96F2D453 +:10324000D25ED94BEBDFD5BDA81DE406C0019B6B58 +:103250006DEA929A96624AB445D4A001F957A8C47F +:1032600081EEBF04EB351DE06776E067485B08E25E +:103270001F5375A51CF895D64F303EB9B0FA5DAA1C +:103280008EEF9DEDC6AB27565C503D228DD31F7C43 +:1032900017C6E9A783B4698314F6AD205BC08EF22C +:1032A000B0FDE06E179313DD1EF6FC9DC7DC0FAF7B +:1032B0005EEEA1CFE51EC687DD9E482D9C4B199E74 +:1032C00023621CA8CF45BB80430A4D85AFC0F9A13E +:1032D0003B7E2213D867D8C3F976FA543FD3E7F779 +:1032E000A8A8CF974FFD767B262D4FFF56380CFAB6 +:1032F000792B097B814E62DB985C79AA625A663D24 +:10330000AD7EC9FC6732414F7DAC32BB36CEFD92FB +:10331000968E1BA742FCEA8FC7989CFC361FA7D746 +:1033200035D888EB39DF87760D752CD06E6909C9E1 +:10333000986724E6B0A7E2D2FE0AEA29D430885181 +:1033400078943F2F50314E72D6CDEFC118447B4652 +:10335000F144B50CFABE272622BFB769DE38D8DFA4 +:103360005B7DE578FE34562AE33994ADA52CCE9AE0 +:10337000E6FF7C1CEC981DFD1E261F7C2AE699C6E4 +:103380004B0F1EAD0EC253D480DFE3C6AA5AC4BB96 +:10339000266A98AF4A7FC3EF0D413CB7B295F075EE +:1033A0006910F1DC5DC7A48F7E7A29E4EF7C590BAC +:1033B000F3BB09301F1C4D3311F68D860FA7013C5E +:1033C0007F63DE6B30D49A46EBB7AFD3C2B00E73D7 +:1033D000B5EA5AC837E8D0AAD11F4A9B53A35E8FDB +:1033E0007268E4DC06DE9FD15E2A63BE117C07BEF4 +:1033F00024ED6400CECDE771599696512E801DD6EE +:103400005187E14038D760CB3F6FCFBC06CF2B4907 +:103410002B3211CE0E62A8503F5627A39ECCF3A9A3 +:1034200009B04BF2CCB82F1CC5B0C425B26EB19F09 +:10343000E7C869906DE7C72747EDE56C1E67C8765A +:103440009CFB38CBE9C58927E77CB3828F6600BC3B +:103450005970E0571F3D9F0783E5F530CF3CCD8B7A +:103460007087B4D62A905F9349630BD0DD45C3EBD8 +:1034700080736E69FB20ACFB5C5D263A1DFF523207 +:10348000DC0AFD6EE574DE5D68D7DB7B54C9E4C7FA +:1034900030F0E3D42691C42CE343BC3266196F5A52 +:1034A00077A6AD3CBD27D7567FE6AE22DBF759F1B4 +:1034B000D9B6EF97EC2BB795E7F45D6EAB7FE9A13A +:1034C0006A5BB92C718DADFEBCA3AB6CE5F9837F53 +:1034D00065ABBFE0C43ADBF7CB86D6DBBE5FF1D687 +:1034E000ADB6F295C377DBEA9B76BD532FCEE6F6F9 +:1034F000CDC5DAF36EB84FC216BFB5FB0B4E7B5F7E +:10350000FD4B9BDE0A722DA0207DCBA0C769F9D6AA +:10351000BB98BFA52E0EEB2057742E47A9185C0050 +:10352000EB561550511FC83E564FF62D43FB63CA4C +:103530002E2A8FE681554A46BEA7815C6E8E2D2EBF +:10354000B6C4A53C5A0F9EE1AA0AD4E23E88D95ED1 +:10355000D60C12F5C3783AB37BA8370BF53C3A6D1D +:103560006F99D7F3A28847A587A95FF8A8C52F1C34 +:10357000CB0F74FA7D17EAE74D118917CF1F089119 +:10358000467896361EAB86B461EAFFFDB587F2E752 +:103590007625D2D04BFBDD5EE465FBA5DCFFEB2E90 +:1035A000EC43BE182E9451BF10592FB5C6ED3AF911 +:1035B000FAA6A94FA1FF49F18EF2D6C4FB566128A5 +:1035C000DE0672E72E2FCAC329BF71BF0CFCA516F9 +:1035D000A9792A7D1F3EA218B00FF520C76B91561E +:1035E000560DA1A7E250FD6178CED0A99D419F253F +:1035F000253B0FA35AF314E178B3C3DFAB0659A2FE +:103600002E66F69F3C5789B7D27E248DC291C2FFA9 +:10361000309F526017DBE728967F07F406D6FF79C4 +:103620003A85AA4C15F3423C4007023E917E3C414C +:103630001FEA0D0F1C8285B22CC4619F10EC53D879 +:10364000AFABCADC85EB6EDAAD60CF46993FDC09E3 +:10365000780DD6D9D73B4DFD0EE2A95D60F1F1EEB4 +:103660000CFDC56A3A6E77765126C462217E526F90 +:1036700091373BB83E8D7AD9D39437B891333F69AF +:10368000EF50FADF254E03F87A08C82DCFBD3D0470 +:10369000E8DDA3D1D544BB3EA647509F327BF73629 +:1036A0000E534DD11ACC03783F588EF6ADA7E9F9E9 +:1036B00094F8F30C49C49837365E033376A3BE27DB +:1036C000458A0E764593AE18BD29E4C15C95FB3959 +:1036D00053CC73AF2C0FA89BE3C38C9B8EC4237970 +:1036E000DCCD8C479AFDDC965D3E793C7BDC43FD6E +:1036F000D0A805DE2D741CC04BC7B9FA5AC4834C40 +:10370000D8B9DD3F97F6DE87FBB16D3AEC37CFE5F0 +:10371000F67225E087E27B8A42D04F580AF1952C59 +:10372000F07E3F530B7C69C663863CEC1C773846C1 +:1037300024167F73997A4B3C7F29C2AC2B661E19E5 +:103740009ABC4CAFD17FFBE17CD9B46EFBF9CDE9DB +:103750003DF6F2CC5DF6F2ACB8BD4CADE6E36017D9 +:10376000808D86F18D7DF6EFF5E6BE410D3B6FA6AF +:10377000D291CF33FD6BBB3F8770FD6FE6BB15F475 +:1037800025AA40BCE6DF6ED7ABB95CCFE73AF46759 +:10379000B95FC2B843D5D1E000D88F667CE8575EE8 +:1037A000DD967766C6799CF2DCFBFA4E42BFA0FF3D +:1037B0001E75B37807C4913F2CE071957C1E579914 +:1037C000C2E32A052CAEE292F497D60A9827FA3E75 +:1037D000F20569BC94C573D8B9AFF76AE517049DC3 +:1037E0008D17B58C7767496C3943433C07EA99F1EB +:1037F00015337E10F01BCB817FB7865F6E3C42E9AC +:10380000A4FA976E02FD5C25BD78B419E45B818C47 +:10381000F9DDDA825BBEE98578257CA7E5EA427DA1 +:1038200032F2C18F5D1847E8E2746D9E5734E33180 +:103830009A97F181CF6BDA47312FCFDFF782BD7BCB +:10384000C93E2AA36DFA8EC5FDCCF8DE9C3EFBF77F +:103850003E226469901FB0262E32FBCAF05559F201 +:103860001F67F3759BBB36F1C05A5A3E40E2E570C4 +:103870002F5D19A78FF080FD9CEC2422E039A94927 +:10388000C7A5709CD69FFB9CFD7BA9E31CED6CE754 +:10389000B95AC7FE915F22A7AFA7E36DD31B05906E +:1038A000A3DBD6525B9E966779F9BEFD0C3203E826 +:1038B000F02AC9174E007E5F95701FCCFDC6CCD78D +:1038C000AE07BD7E8CE52769D3F49D106FD67E2AA6 +:1038D000A19ED2D24859992FB9DFF40FE7C304F65D +:1038E0004FCCF8D793745D41AF1CA07E79B10BFC2F +:1038F0006C0DCB7DD42F87F2D3D42F87E741EA9785 +:10390000C3FB7FA67E39940F51BF1C9ECF52BF1CB4 +:10391000DE3F47FD7228DFE5ABC278F920AD0FF43A +:10392000E22D3BA84EAB0039ECD2803E9C72A8AA97 +:10393000EA36753525A92F743D85FB1CD557B17C1A +:10394000EAE5F73D85FB1CD6389C354E998CC30DB6 +:1039500009661C0E42A3BFE6FB1123F1B8288BC7F2 +:103960004DDC8F61F683F1CF51FDF038E8BB77FD78 +:10397000DBE36DF4D386F90F747B8BE07C47238FF8 +:10398000FB99F933BA2D3F7FC3C116CC9F51728E7C +:1039900037C2BA1EACF0615E89E28A6A206F9DFE72 +:1039A0009CE9C739ED69F3E9D46F7E6E5798F1D57C +:1039B000ED2E82F9D43181DA13605F34C717BFE985 +:1039C0001A3BEE7AC25BC4F3F8EC7261E41C018F1F +:1039D000FBB8C19AA5F354048E0F9EDF8EA2B18866 +:1039E000C5FFACF1576F711C0FAF7B7D06DA750216 +:1039F000B5F7D0FED3A22188A375C2B98114F3DB39 +:103A0000CBF9BD2547417BA33387E58BD4E48743BE +:103A1000D0BE2DA732643D47609E7318F057AA436D +:103A200096FE6EF5178DABFF24AAAFF571F4B5E4E1 +:103A300066E77CDA0E5FA6C2F98D6EDFBA41F0A3AD +:103A4000BB43418CD3F7E75492214BFF5268219E30 +:103A5000F3907CCC1E96422ADAC332CCBF3459DFB5 +:103A6000ACD7C2E53E65678C2F7A7C3D58CF2D4799 +:103A7000F07E09771054267D6A6CDFCE5B2C12D560 +:103A8000222FCC71EFF63279D95D1AD520CED21D16 +:103A90009275382FD2AD97239EDB389EDB0A4C7B84 +:103AA000228C76CCF7B97C35FB69E37180B60605CC +:103AB000EDB948538656938579BDDF017EEEF6B5A4 +:103AC000AAB07FA9E4548CDBEFC084FD964DAA997F +:103AD00087FD7E1FFA55FCEB34E8D735C6F9A463A1 +:103AE0009C1E3EA9DDEADCEFA3D086AC792BCEA7E5 +:103AF0009FDB9FCE761B4A871458F72D8FD9CF3383 +:103B0000BB083BDFB5F1D066E4F3EDF220DA51DB20 +:103B1000CF0929CF8985D204CE6F23FEBDCD0ECA31 +:103B2000E3FC94C7BF03A981BE284BD8ED96794723 +:103B3000EDE5F983F6F282134E3BC87815ECA0D57B +:103B40005CEE0D5279CF92668665C0472416AF02AF +:103B5000B8EB495F0BE453B8249617B29AEBBF95C4 +:103B60005C3F06D23210FEBC06AFCDFF24FC3EC047 +:103B70007CDE7F41CDC0E67610B211D3AED2D16FDC +:103B80002DB8FAE92A14970EFBAADEB09FF75FE979 +:103B9000B09F9C765695DC8B79BBB98EB886B9EF11 +:103BA0000BF3847B0F9CE35FECB8667F90AF05F26C +:103BB000CDBC0F06EF1FA6ED0BE48410A678CA6DEE +:103BC00064E775F26E27466F0A3A5EC2D77D14DE4F +:103BD000624B106F4BF9BB5C1FBBC72BB7468AEB20 +:103BE00074FCDC863EB40756DD42E78376F879CC78 +:103BF0009731EB6766F4E1B9A5DD7502CFE325687F +:103C0000D798EBBCDBC7CE19D65F29C44568DF580F +:103C100084E3235C45C9F5A5783AC9F0C4F212AF34 +:103C2000ADB59F87AC77D82F263DAC74BC3FE96516 +:103C3000FBE7261FBC7BD9891953281C1B849EDAFD +:103C4000B46917AE2F2DFCE13A0F7C08BF4F6229F3 +:103C50003298EFABFE9386E74232861E269424AF5D +:103C60004D23B19A4584FC8B77F8128196FF6A6BDD +:103C70005F4777011CF31E7E0A8C3C77D73357D5FC +:103C80005E992C7BEFEBC772908F035B906CBD2D20 +:103C9000F7C350D4C5D3187C5B0DB253821C5C5162 +:103CA000DB192E4CB6CB8476C238ED2264A79CA2D9 +:103CB0009DCF6C47D1D509F73FF17979F97791C359 +:103CC000631D5F06BC69BA0FCF3B2E9335D8BFFA90 +:103CD000B4704C9A68DE51B2D3356D743B0A768B62 +:103CE00009BF981AFE387CB78EEF1A07FEFF6E7C6C +:103CF0004CD49FC2BF5F347CB47AEBA4B1E70B70A5 +:103D0000B9F05E22DD275AFAD9D1FF278C8BCBD7A9 +:103D1000913084BC6497A1C17E5EA9F610FAF77257 +:103D2000468D0676C0165A063B604B5F0FC6BF4BEA +:103D30008B1FE806A22F4D7809C8833944CB384041 +:103D4000FB9DA3C970028BC8570E88104F279F2573 +:103D5000985F92DEEF65F708155EFE2DF0B7323200 +:103D600054DCCF48CBA8FC16337A599CD9843FAD9C +:103D7000EA7835C4DFE57A1216002E214EAA80C9F2 +:103D80006611DCDFF01A07EF84F3024466FA09EFEC +:103D9000D201BDCAE3ED9319C9906E45ABC73C97FC +:103DA0009FC818C79A0C578551A22C2DCDDC09F05D +:103DB0009446690702C0CFE26573A2623841FB2FC7 +:103DC0003FCDDA919FB17326D43759F38C2F8957A1 +:103DD00053AE4CE671F8D05A7B9C9A0CD339D3F68B +:103DE000E53F5BB517E2149346C96FE6B77B399C94 +:103DF000E9A74904FA0FD6D9F58697E7797B1DF72D +:103E0000CC54F85DF6FBA19DFEC35723A807DC2424 +:103E1000AC2A685FAC45BBC1F44B764345B0C70BD9 +:103E200008BB97D7D9BE92B52721E6A7B8BD4455A0 +:103E3000CBE9F7F55E03F312DDB44CF1282844CD4D +:103E4000A1EF7345166F6911880CE5E47809CC473A +:103E500070AB9F6907FBE5B03A0FEF4F33FDEA36D1 +:103E60002D8CF912A4A4DA66379B7961B796154DAB +:103E700086EFE99346E24E1AD0E5ADD9C56847070B +:103E8000B286FE1AE4ECB9ADE9CB5490AB90AF71B9 +:103E900039E4477B3B6354E9BBCFE611DD629FB950 +:103EA000E5468CB3B9CF4EB1BD4F34DBCF5B1B3E83 +:103EB000B106C699EA637C5845B476685745ECE785 +:103EC000AADD67736CF67AB2FF7CDBFB04B56BACE2 +:103ED000F7008DDD7F1AD14BACFD4F1BA3FF198E70 +:103EE000FEB594FD27FBCDB2F5DB21B3F86B2CE8D2 +:103EF0004D792FE5025F75311C951D6B7FA0D2C7F0 +:103F0000E29A5DA146DC1FA82694F129BD2C3977E1 +:103F10005262E77D09DA6F24DFBE3F50CDE958A435 +:103F20009481E70764FBFDC68B89F3BE63BB5DF438 +:103F30004B8839507C89FE8A41DC27F8930FCF03E8 +:103F40008E65370F36138C4F2F4E1BBA0DF6C157A7 +:103F50006ED3958E10E63DA33FFF37DBE62F033B84 +:103F6000DFBC07B32328225E22D593F13C97D94FBB +:103F70004421D3412E46449607813F74FCC1EC5C3A +:103F80005BBE86F9749E87AF3784C5C596790D42AE +:103F9000FEA175BCA579BD92651E1137998FE3719D +:103FA0007B7764BC499F6CBC633C9E658E57BFCCDD +:103FB0003EBF7A45C3F9D5733E36C73B06F34B8106 +:103FC000DF09C7E3F99523E32DB7CFAFDEADE1FC01 +:103FD000EAF97DBC23E34DFA64E399719D2EA5B106 +:103FE00011E870ACF88E19D7B9B66BBF2DAE43622D +:103FF000FB97561513B25360F223EEABEE04BA787A +:10400000BFEED612D42BDCBEC67B57A93E5E293349 +:104010007857E4FBE22D163CEEA672C49809E72916 +:10402000540207CFE07C8581E72D42F87C94DAEBDF +:1040300006E69794E0F7C79BC358DED7BC109F668F +:104040003F250BD9FD60B3160929EDF6133EE67F37 +:10405000EECCD1AEFB12E8B72A2FCB0B5E78053140 +:104060002C763435AC0F7B607FE8F3A40C74E48CC1 +:104070005D0CEE60CDA438ACBFB76C60B019E2A0A7 +:10408000B24BC7BC583DF5DF3B78C5C7FC79B79B41 +:10409000B52757B07B525770FD44A43ACC3F5AB174 +:1040A0003203F31156AD36FC1AC5DB6A4178B59878 +:1040B000EB3B381FF539BED44E7F21089A87AE57A7 +:1040C000D090E2708FDCE7F25F5C23D07E23FE6B42 +:1040D000D1CF88D08699B49FCF717D5BF5869B4008 +:1040E0003C825CA5A0FC5ABDDAEE17ECF42434B097 +:1040F00073769605490B6DB7AACEFEDDED667C158D +:1041000071DC13B362827B63CCBC5C277E9C71D371 +:104110009FF9ECF1D133A474079E0DE3F9BBCEF601 +:10412000661CB4DDC7E45B97C2E4C3683E60F0BCC4 +:104130000B7DA3FF7702E368267CB9725C00799F50 +:10414000D770C2961F4F118B46B5B94F40A4036577 +:10415000A8871DF3D92D1CC819EFDEA85C22FF6EBD +:10416000A884FF7D0361F4BCDF1935EF452F15935B +:1041700054FCC3E2C12B8E4AE1163D8917130FFF91 +:10418000DB7CB4CBC7F0F9D2D20F2A981F986FFB13 +:104190003B02E639AF6B47CA32912DF4BC72BD6267 +:1041A000307F75B814E8F2F8956961F6F730B81DFC +:1041B00094F8A50876D0A7EFDF28B0E53FF37EC7D7 +:1041C0005A2F67DEA5E55C72F29E04C87F690987F5 +:1041D000D01EC81609F0532EE4E305D8F79376BB3A +:1041E000D5968FD7D6BF5F80B8E1C3909F68398FCF +:1041F00097D7D02774807DD71267718804AD47E1C7 +:10420000CE6F4808EDA5C9BC2FA75CCFBFC59E2FB8 +:10421000D8B168B5764087BC9AEA1EB8206CCB2E20 +:1042200016E732EB8FC4BBF83955176924704E433B +:10423000F2B1787388DFDF31519EEF87624C2B2C0F +:1042400084FCDEB85A45E7BF272BBACC4FFBED0EF6 +:104250009637F6027DCA61CC075FDB744F04E284B7 +:104260005A56EA38F85A6E1FD4FB195DBDEE4A144F +:1042700040DCFCE5ACEA7A7F768AFA4D5FC5FE1633 +:104280008F712FFD7A3F8BCF3C2CA6960737F0EF2E +:104290005FD820E27D431EE2C773AC9EE29E85801C +:1042A0008F8737EE0EA73A8FB9508BAEF35BF0EEE7 +:1042B0002966F70510D27719CC73CBC78FF47D9799 +:1042C000CE3BF3631FCAD94C89F56B69BFDE3A1F39 +:1042D000B3FDF37FFA059EB37F9EDFBF4EC8F4E5C2 +:1042E0001067DF3E52263138E8BC3D839763E272A7 +:1042F000F02B93E5E796554119689412DFBBFE97C2 +:104300003AE1FE9AED02E1C43AB80CEBF3FBDE7F32 +:10431000C2BF2FBEE69D6FED007D50A9A0BFB99D25 +:10432000DB3B267CFFE967793FFFC9D7652C7C6EB4 +:10433000E3DF7D80CFE045E1735B2A7C7E26686CFD +:1043400087F71EC804A120783E566F87BCECAF37B4 +:1043500093C897E81C1E0E1FDC0F678F68FB8752FF +:10436000B5FF4196F1353FC27312E7E72FF685019D +:10437000155B1610EC27051CDF186F5DCB33989C7E +:104380004B4B67CF4C6E5F4AEEC110E42F6815FFB0 +:10439000709B46E54C67E1E09A5471E2A702CCEECF +:1043A000CF18232E7E98E3EFEACCC8B701EE76ED66 +:1043B00001F4F7148144A0FE96854344B0B47B23F6 +:1043C000C0E897C2FD0CC0AD5CC6EEB1F653BC436D +:1043D000829CBF82C1BF453F4E204FDE1F3A8E797F +:1043E000ADFE8A21E4771485B98CAEC01F54B9FDA7 +:1043F00076D8FF26DAF5999249777774011D4AC974 +:1044000032D2656F266BFFFBC01D5DE02FEE516859 +:104410001B9083B90ADA37CEF9FD2CC0E6A768C62F +:10442000518077143EDD43DF827B09B64F67F7B9D1 +:104430002C1607D7DC0074798D0FED33FA7E8DF5DD +:104440005CFE479C7F3FF233FB6AFB9F54FCEE5CB3 +:104450008FB1E8F5246FFF09E8F5642AFEA5F4FAA8 +:104460005B786FA1D70F486A7A7D7B0C7AFD0F6865 +:10447000EFC48BB32C116317EC2BCB1F2DDB07FD87 +:10448000C99F59B4EBBBF4297DB42D86AB19166CCA +:10449000E79E93F23EFA2718D7BC7FC0FC3B46CD7F +:1044A0004008F353F4BBA07217C8B10BE8570E6471 +:1044B0008FEEF7653F8377F135BE68AAFB14BE1314 +:1044C00090D9F9D800AB3716DFFC3AC0F253C6E2F8 +:1044D0009B17381F50BE0906E64FCC3767927C9376 +:1044E0001FB820BE79089F9E62C63738FFCB47F3BE +:1044F0000D89ADEB02F9DA59C8F862CEFD9B902F19 +:1045000046F82816C3EF52B28CF2DBE4A38FEF8F8C +:10451000617D67FBC018F70656707E5AA845E60114 +:10452000FE8D4BB476768E6908CFEBF692E17E373E +:10453000E609B3BC5C6F2C6630F36090C0FDB48BB1 +:10454000381EF6808F067E50258F67C98364957F5D +:10455000343FFB2B1215D67B605EE1E3FBD2234B8D +:10456000018FBD646816D86763AD532D1F4FC832E5 +:104570006A0329F87F223DB421C0F4D0063E6EE6DE +:10458000C76A23D8A74E7E5FBCF1D93F3C3E4E3F61 +:10459000EB391CEB029F585FAD0BA4D6573704ECE8 +:1045A000FAAA42284AC9FFEB0329E407E5FF9B5317 +:1045B000E1E553F0FB9D8114FC1E095C18BE9FE5EC +:1045C000F87EF653E27B176FDF13F8C4F2B62715B7 +:1045D000BE28BE7706B22F08DFBB52AD17C5F7D78E +:1045E00003B8FE4F23FC7EDD87F1F2EE05E420F4F4 +:1045F00093028E5E6B3FAACEFAA13CF58140E97E24 +:10460000F147DDE154F724D176FB52B5AB0D683CA0 +:104610000EAD6F06FFE1E1CFF8705F81EAC703815D +:10462000FF5EB97F28151D2C16991CF206167581A0 +:10463000BEFF14FD0FA492FF5FE57436915DF01A82 +:10464000A70B3AEF9F029C4EF9D7CBCF312B5AF4F0 +:10465000E500E26BE86A90577BEECE1420DE956FA2 +:104660002404F0138E723D560597FDCC4FB6DB2324 +:104670002704B867674FA326C079294B7FAF07B2DD +:10468000C7EECF090785EF3730BE2FDD188276B52C +:104690007C7E176B271DC934DE0AA0FE89BC0D4F36 +:1046A00063A65D6E9BF310233D2CCF7661EABF734A +:1046B00079D42F9BF2FF7DABFCFF8F11BA62FD5DB9 +:1046C000ACFEA1F09DE3F0FD25157C4EBC4C04E74B +:1046D000250199EBDB889A9E424F39FB33FDEC9123 +:1046E00075029D6489FB64A78FE8EF603AAC478749 +:1046F00088E7A8567079B2626106B7DB352FF4FF00 +:10470000308FC33F7CCB0355B0AFDE7BAF5606285E +:10471000C86D607A4FBF650AC657A7F27E9DF08FBD +:10472000B457FA66C1DF8FA0E34E83792C59441247 +:10473000E037A683DD80F10A0DFFCE71A6BB27040A +:10474000F1D92D42CF9A75A057AFF6B17331A1D5EB +:1047500013DC9FD96AA35B12AA98A07E0BD6D7D28E +:104760007AF09E950BAEEFEE496967D5A48B9C9EBF +:10477000A24BC6C56B2888712F13BFA3C761EB5727 +:1047800015691400DFFE0A4183D43B3FA513B0979F +:10479000C4E241CC9BFA6C05A31742FD92F1EF698C +:1047A000E934E15A0578FFB47099F5C61E8FD773C6 +:1047B0009CB718F97B643E26C7B0222DBF77342BF7 +:1047C000E5BE82F9EC6AD60CB832F93D4DC7FB1B49 +:1047D000BB46F2BEC3A155FEFFF97AC979C5597C23 +:1047E000D4517FE49E92908AF61FFE9D0FEB7D3D93 +:1047F0009C2ED48C482C1DE54A18EF89A4E5565808 +:104800000FA2D2B21FCBED58D646CA9D583FC4EA7C +:10481000134DBB20BCD376DBB11F79A49F1DD88F6D +:104820006F64DC9D580E8E941FC4FAF9ACFE858E21 +:1048300033EA9E964109E7FF816CA4C3BEE9E79B7A +:104840006EC0F8D2754D37E1B3BB59AB82389D7954 +:104850005FC9E7AFBB41037FFABA2F3F88FBFA6617 +:10486000FF2BC1EF00FED7E55AB097944231F29882 +:104870002FC97F4938DAB1BC4266F7FEAF5C787A5F +:104880007BBB257EA7C2DF4F87FC1ADD725F06491E +:10489000CAC32704E37BE91741CFA3E749C800A5B2 +:1048A000DF0F7CC5F118D273B5968A6FCCF98ED51F +:1048B000BF39DFB1E48D8937F3FD9662FEF7761DCF +:1048C000F14BCFF41ACCFF59297038FDFCFE485E3D +:1048D0006F051DE7E952A40B1DE87605F7EF9CFA7A +:1048E000C11CF709217A02E804E2C4F7968FC6EFEB +:1048F00085E2CDEC7F723446E0FE2E6F29C17DB19A +:10490000A0DFDC576772ED219F598E617249A4B810 +:1049100007E59C4737E51ED3935A5A9F2196513F8E +:10492000A887D48666411E6834047FEA87968FCABA +:10493000684FB0321DFEE800DA3FDA6CB8F1516D15 +:104940003FF7A3A35712767411F7DDCEFD08F5B734 +:1049500059860B7C4B68D93B5236D4102D178D9459 +:104960006350DEC3ED3EA1E7DC8F60CF84EAE573E0 +:1049700056795FC5E5EA44F2F4BF00B9E905CA001B +:10498000800000001F8B080000000000000BE57D88 +:104990000B7854D5B5F03E73E695642699BC270490 +:1049A000C8090F098A38090482623BE1D558790C9D +:1049B00015359628938447782620D5B1D2322180A8 +:1049C000A0D886AA156BC509C57B69AFB6A0B4E5AA +:1049D0007AD17F10B4D0521A2B55B4A25150F15154 +:1049E000938294A9D572D75A7BEFCC39273321B45F +:1049F000DEFFEFFF5DF874B3CFD967EFBD1E7BAD6F +:104A0000B5D75A7B0F6361C6721963DE1CC6C63107 +:104A1000761EFF7CB967C944BB366DAD67C268A816 +:104A200079ADBEA11A631BF15541BC5D89C74EED3E +:104A30001ECD0CA67BCA199BBEAACBEA8476CEE219 +:104A40001C77D0C55891F79370257C5F349E310D4B +:104A5000BF1D9245E3B679572A769842DB08E651A6 +:104A600018BD5BE381F6396EC6DAA164D60863230C +:104A700018BBDF25EB301F28032511D601CF533596 +:104A8000FEDE827578AE3A58D34EA8A795307F04E3 +:104A9000EA1E079B1380B2D863610CE6E5F3A834E5 +:104AA0004F1F8E06F50CEF5AA6417B6795C51F81F7 +:104AB00032034B971EFEB5E23B2B95121FD7E6043F +:104AC00047209C6D8C55EDC479B168A004E0481D69 +:104AD0009E937537D42A4BAC2B190CF9E86A1698BB +:104AE0006B63ACC21348C3F6AED29CD4E008AA8F65 +:104AF000F2403FAE75963003BC54327744298EE3C2 +:104B000005669E1A7027A7C7CBAB838149B6E474AC +:104B1000BBE12635A087439653100FF0FDC7D5EFB4 +:104B20007C1FC159EAECB2B34140CF219B034C45F5 +:104B3000783482D3B97B66B410DE2FDBB39CE17C82 +:104B4000D7A4A58F473A9AC77DF9B3073D01789F4F +:104B5000F25747606782F196083C1F5D5D4DDF416B +:104B6000F79A358FB13908CA204604ED7062C994AE +:104B7000F30E02EFE810787F0BE3CC302B503B8D27 +:104B8000015EEBAA55A616E377DDEDD979A8DFD251 +:104B9000513B958D844AC876129F3BE1EF79E83707 +:104BA000C832A778E0716D983FA7F6F0DF3CE69B2E +:104BB000920BDFD56F303D7FFD9AF7593ABEB79E15 +:104BC000EC2889F77F63756D6092687786FE1F21F8 +:104BD000786669CC8F749BE54B8B8401C4EB0337FB +:104BE000052695C4FB7BE573750EE2C58C8FFF44EB +:104BF0007CE4223E028149437BE2A32EA0D83DDA29 +:104C000085F1D2573CD45A4BA7E46A3DF160861F28 +:104C100030762FE2791EE0F9EEE2E4F88076448FF8 +:104C2000576E827600CA1475AACD0278A89FA93063 +:104C30008742F84D6783B19D7FEA64DD7CCD78348F +:104C4000E3ABFE19E68B42BFF50FB87DC0E1ECF790 +:104C5000123F5140DA189027BCA91ECEB771FE1E34 +:104C6000F88B707EADA2F4F91C984770ADE2631C1E +:104C7000DEB7F5F0D5B140465421B8DF4E42F7B764 +:104C8000F5709AE7679E7F0A0A2B907FA1D78BBFAA +:104C90007340D78E59A323029733F6538F3BE7DD3A +:104CA000CBA03E92F9CEC3BA3ACBC6678CC2F743CB +:104CB00012CBDB73ABB5EF1CB0E9D739E7B339A141 +:104CC00099DDE362FF0A0B76D73D80E7C04DEABD70 +:104CD000D7C3BF5F3E98BD0E9FADF0AADAC96CC4C2 +:104CE00017C04BF4F23326F98B6119DEA702FE667A +:104CF00032A7E6827EBE0C42EA3CC032DD9FA2B9FA +:104D000074709C6E55AA508E02F132665D1E87D774 +:104D10003CEF155E3B8D07FCF8899E1FCD7879B975 +:104D20007A7006CA9117112F69849791178397AFEC +:104D3000E0628675E3C9665105E8DCA53823DB60CF +:104D40004E35A13B039346215E58D80EA2F35D4F2A +:104D5000B190D31C6E1B937F9A18CAD31A3B0B22B7 +:104D60005CAFDB58F52E1796D101653AB9F57E7622 +:104D7000E5BB28A765BD26F46DEA1F1891F850F22F +:104D8000F32D4E5754E57CF85137DF903CABF120C2 +:104D9000DD814EEC3CC0A9662CD1106E352D7D24F2 +:104DA000CB606C033601389D9981D328FFD5B4813F +:104DB00011E4BFD49B7EB481D3F1BEAA1B74744CA2 +:104DC00099F754983AD7B20CF84F13F4AB14F44B4C +:104DD00029719AE9C7709D864B58E43145A000EAD5 +:104DE000A787F823B86E93E90D49CF9412EBA71D5E +:104DF0007ABE66AD8457494776607417AED7A0D7A0 +:104E0000CAEEA6F725849FA047E2A7CB86FA644E98 +:104E1000C8765ADF4FB0606EA419BFDBE8F0E1B38B +:104E20003A8B9687ED004F1ED4E3ACC4E7C3F5C3BD +:104E3000C2F09DE427C42B1A13BAFE3B00868232CF +:104E4000EC0FA4277EB74137CEA09EE376AF2B733D +:104E5000BFA6EF5415EC07B2237C3E9F4E7E0FCECB +:104E6000E4F6C369EFE89D9641C9F157E7CCF65BDC +:104E7000B3E3F5B70B9CD591047A40F627F5799604 +:104E80001AF45A10B6F063070FF4473DECB9142436 +:104E900019BBC71639787000431661AC1FFE2F721C +:104EA000D0EF22BB43D4813161FE6DA9DD75BFD344 +:104EB0000BF541DDF530D6B7C270EC4AB05B32235A +:104EC00007D7C27CCE1D7790FE3A5D951AC1C59377 +:104ED0001D9AC84EC0BCAD60E66400AB4111C6D29D +:104EE000192A2478142B600EF09DADF914C4F7AC88 +:104EF0004C8DE66FD558D40D93CBB6FA14C4D7F7C2 +:104F0000ECAC41C88DE13375F6CB2C01AF1CC7E189 +:104F100064E194B278BF606135A31EB14E65A457B9 +:104F2000609D93DD26D7B7EC2798C9F567F7FABCE3 +:104F3000F07A0E662658CF872D4D6F7E0BEDD95F28 +:104F4000ABEC3100E566EF1DF4FC86503D953785EE +:104F50001652B9488CF70E0B2ECA84B2BDFAA59B27 +:104F60006F07FE6DDCEDF0A15A5E7ADBFBDF29D71F +:104F7000104F4077FC6E5EFD03E5F0DE3ED442F656 +:104F8000EC8601AC1AF9C9DEAC907DB451B357ED93 +:104F900086F2A18CCA2D993A381ECA98447556A536 +:104FA0005990CF5738399F9F3B7E97B70EED4A9760 +:104FB0008BD68BBDB9F8BB16A8B343306F86F2838E +:104FC000919DA13A78797726B753EF16F85E93C989 +:104FD000ED3D670C89CCF9BA09C6775AC30CED6C64 +:104FE00067CC4ACFED0ACC2F019FCAFE9C3158A452 +:104FF000A3703CF3F7767A8E70E1F76A3633D83DCA +:10500000F7E1F7B958CA79A4F179649BFB49E7CF76 +:10501000C5FA33CFE34F9E890F227E1ECAF06FC9B7 +:10502000A475D36143797E8BEBD7C794917D91C7EB +:105030001D0ACAE3E99F29D122C05F4AA51A595324 +:105040008C7ACD336D34F001ABB4F9109FED43721F +:10505000DC8374E3FF44D0FF45ABC78DF30C4C06F3 +:10506000BB9AF89BE5CEC27E26D78FE1F20F0C2EBD +:105070009D9E7D51DBBE6110CADFB08DF64B739CE7 +:10508000E108CE4F67B729E7B95CD6AC63E2F6DF3B +:105090009C49AA3F25BDA77D07DB900364FF4959C2 +:1050A0001E863A7CF786A8BE39E9CCF5084607F398 +:1050B000D807E9ED41DC2D8D41FB86FF991332DAEB +:1050C0007D66BBB0AEA2F4052003E02552351AF987 +:1050D0006CB885F8ACAFF632639B399D27B7787012 +:1050E0005FF528CA09A84F9F746212CA8D19605AC9 +:1050F00061BF3326A99E28B4DE14B2303F4CFC8831 +:105100005F8D2800DB91928E435F46BC55D834D228 +:105110005B25ECDEEB72F0FD280FE23920EC106825 +:10512000CFF59BD719190ACFDAFD275CF53ABE3BBC +:1051300052716238EE5740EE3524E227C69A89AFA5 +:105140000F7C3395FA79F37E25E280F94F563FFBC9 +:10515000ED58B467BF65F3393402CB82749DEA63BE +:1051600062E3EA774DD6D9012758600CD995A5C7D7 +:105170002B1D68BFAE53689D4AFCCF0919EDCD6069 +:1051800013D8655A4FFB143AB3233FF7D53E35DBAE +:10519000579F650A7BB38C95E9EDAA647A4ADA5584 +:1051A00056E657B3F87AB2A2DE9D0E0F12C9819A65 +:1051B0000CBE0E26AB1F117D4E57A81AE2EB48E835 +:1051C0000317EEC78F7CA6F27DB03FD760C715648A +:1051D00071BFC0563B1864F0DDD67ECE483374B53F +:1051E000EF9B97E677107DB407C7231D7F6D2339AA +:1051F0009C6CBEEE90CA8600634E0B29544AFA1589 +:1052000085529855A71F8A58E2F95F9AC5F7A1B948 +:10521000AB9845837133C3CC9F687F2CDBC1BE78CC +:105220008A9551FB6826CC6FD9100BF1A7DC1FA71C +:10523000D8C2FE4280DFB6777918F7C945303F9C67 +:105240008706F3437D591C4AA3FAA0503695834341 +:1052500099540E0915D2FBA1A1C1545E122AA6E7EA +:10526000C3429751BD24348ACAE1A1522A2F0D5D51 +:1052700045E565A037B1DD885025959787AEA5E750 +:105280002343D7517945682695BED06C7A5F1AAA18 +:10529000A7B22C544BCF478516537D74E856AA9776 +:1052A000879653392674279563432D5456849AA9BB +:1052B000DDB8D03D54BF32741F9557853653393E03 +:1052C000F430BD97764BAA588FF768733DE8EF002E +:1052D0000ED7908F93ADBB85595C0FBC98E99F8921 +:1052E0007C27DBD92DA0C75D3DDBCD136526D235EC +:1052F000417FC12CCE971FFBDEFEFE3016A7DB469A +:105300006FEFFE0C56D237BF57208BCBAFADD676A2 +:10531000BF8AFCDBC47C6178346DF48B0ACA973693 +:10532000CD5A95C8BE7B28CB46E33E9A196CCA82FB +:10533000EFD38A4F1E40793223ECF9ED04E4971144 +:1053400039BF9E00FD15ADB5D0765F639E7DE85FE9 +:10535000D32631928BD2AF04769D419F6ECE92764A +:10536000E3CE8383683D0D29E3FAA7E31A5C5FF679 +:105370006F0EA2FDFB567B54B1A27DB38231BDFD01 +:10538000BF757DDDBFE1FB787F7C7D166D60CFA1B1 +:10539000895DDCAA4D488172F016FF7329F0C9D0EF +:1053A0004870422AD487ED083F87E5F09D9109694E +:1053B000505EB627FA1C6EE32E8F764C7041FD8A44 +:1053C000836C3F2EFFD2766DA21BEAA38EF9F70302 +:1053D0001BB0F28EE0C4740DE713694987F96C7D48 +:1053E000030C3DA8577CD4AAC276284E7FB0E3D0E8 +:1053F0007E9374718F6E9F940DFFECBFD253AAE21F +:10540000F7D68E94CC113DE9D38670239CA0471E1D +:1054100003B8FAFBA38A47C727CF08FE003AB42196 +:105420001DA45FB26D6D16F925DB523D953864D72A +:1054300064E6D9A6211F5B094FF67583C81F27F9BB +:105440000EF06BB067370B39B1B5DBDE4D8CDF6723 +:1054500010BFE5FF3AF89D9AC5D74332FC3A915701 +:10546000C65D781D1F117C08EBF8D788D764EDCE98 +:1054700008FC9BF1DC6661074157C1B8C0A77C5DA1 +:1054800031F4A37D2CD6FB85F07AEA5F0CAFCF0B0D +:1054900039910CAF4CCB213909FC3A1CFD63C9E4AE +:1054A0008D5DEC67CCEF3F17FCA69373DC6FEB01CF +:1054B000393738B99C3B7421F925E48CDDE4DF49A8 +:1054C000CDE6E3557802CEECF2047E6A1137907E89 +:1054D000EAA9AAA712E50D1BC6C88E4E1B1109E347 +:1054E0003EA528AC95A9D80C8532E2B15F09F91F19 +:1054F0008AC1CEB002FDA1AB28964ECD63A943FF71 +:10550000BB5C6F9E5AAF7EBD497D1F5F8F922FB2ED +:10551000DAEEE67E496D26D82FD764737E8BF7C30B +:10552000FD20EBEFE8D776B74E0EB679BD5497ED78 +:1055300093F1EF02F1BE6DED1AC2A7737C62BB61FD +:1055400062B62AE441971FF93CFC25E6417B2673AD +:10555000EDDB249F32413E29249FF8F8FD43A9FF4B +:105560001686FA84EC3C21CF3DA937B8FFDFF173F2 +:105570003EDA54A807C67BF6A918A7013DA4E13A74 +:105580001D0F731F8DF8B213DD35C6E9A88D6711A5 +:10559000B47B016F51DCB7872D6EF233D9EDAD7E50 +:1055A0005CCFCC9E49F057788233B37B91379E34E1 +:1055B000AD14895A97BDEB1A17F0DFFA624F2AD65D +:1055C000E7407D53058C9BD5C1447DA36BDC3FEE4A +:1055D000F7A8BBEF6787D0EFB13FCB1FCCE67C5D70 +:1055E00087A57F98C74AFEEA3EC6C1E4FA8CAF277A +:1055F0004FA95C4FB523481E2EC17E657FC9EC9B29 +:105600004BB2B99CFB56B6C5C0D73DC76D36AFFB94 +:10561000BED93762BE8BB37B5FFF2F1FBC6FCB76CB +:10562000A6F337F6FB7EBB55437F06F7D3589CEDB8 +:10563000D49F5BF81BFDE86F043E700EE175FC9390 +:10564000C85F9C1C8F119AAFF4334A7F62BAE02B7B +:10565000665522A8C7D32B3CD63AEAAF837D0DFA14 +:10566000FB81C0935CD728B79E1C817229CB8AFB33 +:1056700075F427B9B3E2FD633DA32C2E9F98D8C7DC +:10568000DD2AE6DCBAC697812EE7F011EE4769FD08 +:10569000365F97D3FAB3C81A94137EA679A07D0A11 +:1056A000937FFC067FF2D44F15E687F91FFE54A5C1 +:1056B0005219C2A26ED8EF4DF32951DC07DA2DCE74 +:1056C00008EAD2CA7E4E86F14D7BBA2582F111FBE3 +:1056D000DB0AC1692F4B8BA0F09BD4AF2203E39868 +:1056E000670EEF770513D0FFC660ADC1FF65C663D7 +:1056F00077BB9B9FF7201E1FBE409CF65076779C81 +:10570000767F36DA4373BBD6DAB5789C56C61F0B64 +:10571000BCBB3756A2CA5AC2EDD37E2CD2ACB7ABB3 +:105720007471D0DF22BF3F1C8F83B65FA28F833698 +:10573000F6DB8BF6EE43DD71D06014C7F567EF2C16 +:1057400045FE7DD8B7FBC7DF457C3A44BC62D471C7 +:1057500097867EFAF2FDB908CF6F4DF397A5F4E373 +:1057600099F7C1C7B38DF18533BEEB32A2C45BD9C3 +:1057700009D7B7F42FCAFD30FA0F3D09D7A111DFC1 +:1057800072FC1A85EF6B994DE1F24FE851902F9D15 +:105790002407228CF4A6DFA16C437D73C637CA4769 +:1057A00071CF24F246CE07F0383451FC17C64B189F +:1057B000674DC9E17AAAC6C6FDA6CAF2F2269C5771 +:1057C0008DDBA53874FEFEB342AF9BE3426AC66729 +:1057D000E541E1F74E04BF39BE7356E80BC497DECE +:1057E0004F7E217C1DB3B552FCF0D83C9535433F2C +:1057F000678263F35982EF65F91AF2CD50C6DECCA9 +:10580000E1E375D33349BCE8D8EA068A339BE36900 +:10581000DDEF6B53AA517F57231E75E35E29F077A6 +:105820009D289923A879E0BDBDEE010FC3F8D7D01C +:105830004FCAC36EF48B75FD1CE317EC5B6EF25719 +:1058400054D79E2D6FBE5C87CF0AC6E3B3FB1FF211 +:1058500068F0BC7AE8DADCB02B391ED1B78578BAAB +:10586000071F8C237F4C79CE45F863D8081E17623A +:10587000FB53287E9AF207D58776038ECBF500F787 +:1058800027AF147113731CAF3AB4CC205FD2620AF5 +:105890008BE8E21769D69DE49F4D8B59E9B979BD34 +:1058A000E5E774C73969BD49FC27A3A7C4BFF979E7 +:1058B000590EE7CB63B50B35F41BDA5313DBC11B71 +:1058C000453B5937E723248BBBCF17743D131C97F7 +:1058D0008FFEAA6A7B78685FD6B9C4CF85F21CE6D2 +:1058E000E4707DEEBEE92511C753D7626F52AFA6B3 +:1058F000597B8FC7FA4DF1D8B4D13DE279FF23F13E +:10590000D8969C7F2C1E7BADE0DB0BE5A1DC6837D5 +:10591000DA3DDD7815743C134C6161908FB756AA5F +:10592000148702FE20FD78EC0185ECCD68AD83F490 +:10593000727D6D0AF967EB4B557A5F7FAF4AFA3398 +:105940000AF26109C887DF0A3961F6CF5632C510FD +:105950003F9F3E3AC550BF69DE7DBF5D8DFEE50AC3 +:105960009B86E31DD1B8BF39EC57C97E853E7C517B +:10597000F44FDF7FB50FF599E487237E95D65BF86A +:10598000A8EAC361DB853FFAC886D208E6A93025BC +:105990001EA7D70663FFF514077ED5BB85E29C29B9 +:1059A0009F3F1808D0FE31A89592DEE4F1D314B1E0 +:1059B0004E27F6ABB801F5F89B9B6C0CFD466FAE1D +:1059C0003A43EBB9637513E54548FFB2F40F9BFD0D +:1059D000CC66FF720FBFB2C99F9C2C9FE15749F85C +:1059E00043CAAB64FC0162EB484EEEC5CB31293FA4 +:1059F0005E13704EECB7E5DE66C043DA5C95F020CE +:105A0000F9F2D5CFEE7A04E5700AF0C71A86F8FCF1 +:105A1000F7E7711FC2162A09FDC81952AE63FE448A +:105A2000499C2E37051776D771F9CF6E586EC8FB93 +:105A300030EB95E472AD77B9B53987DB5D66BD6350 +:105A40005E0F5FB4DEA9AE7DA004BFAFAE9D17C1EF +:105A500072633F6703CA5FB37C30EB896A939C8DA6 +:105A6000EB07954546E9E7AD51BBB89EB0D3FB7354 +:105A7000293CDF21E4E4E5EDA9E9DBB03C97C2F382 +:105A80001DC26814A29DFA465AA485F6E54D63919D +:105A90004F42CCD7114638BDA9E44768EDCFDBA90A +:105AA000D7A472BBFC4025C1AB4AC37C6D25AD9B1E +:105AB0001601CBD6EC60512ECCA7C56F49C1F8C2F8 +:105AC00044B7F510BA5E5A27589883C5F115CF0B25 +:105AD000611E05BEA7770AEE3F4B9DF6C164A70E77 +:105AE000CB457EF936EC0F81EF0F1F5677B701A833 +:105AF000877DA33212D9E9B234C7918F7FE39581B4 +:105B0000B86EDF61C1B25C8A1FD7DF8BF1E1C63DA1 +:105B10002AC5976EBEEDD54BC8EE36C529D574673C +:105B200009FA535A94541FCA1389C77D6E3BC99909 +:105B300096E369B49F68794B117537C94389F703B8 +:105B4000D0AE6034E62AB9496E4AFC035C13701E7D +:105B5000920E952C7A787CF13F05D734C47772B8D1 +:105B6000FA7B487E209FA9713854B795E0EB64A971 +:105B70003E9C5F48F887D8EB69B4FF93746E14FCC1 +:105B800028E9BC4CD0B973EFD9EF5C05ED5BFD594A +:105B90001475500730C243E7EB6EE21389070937EB +:105BA000F0451DCE53C2BD7FEFA86341FC3E3D953D +:105BB000E2F8D2EE9679073DE494D8BF2FCD55BADE +:105BC000ED5EF45FFC3E7BC2D2DCDC04ED85BD0BF8 +:105BD000F86EC2712B3DEC93088BEFF392E537AC76 +:105BE00012FD77F773E1FC8655B989F21BFE717AD5 +:105BF000DE7531F46CB4BA362819717CCB7D332D47 +:105C000069ADE7FA37AF3F490F65EFBEBF621CDFF2 +:105C10002C176E579B9802E3ACBF9CAF4BB68A69BA +:105C2000941F645A2F17923740FF6D085732B9D32B +:105C300057FA3FD193FE4FF446FFEF65077E86EF9C +:105C400071A8C232DA17EEC23ACA13FB201A8FF8D3 +:105C5000B62B93513E9BCC8F91F3917932514C5A94 +:105C6000CDD5E5E194F814D4137DE08FA87E7E5F56 +:105C7000007FFCA6773916A575BA54D07FA9CCCB86 +:105C8000D8DD7B5E461FE8F75A22FADDAEFABA820B +:105C9000C57DA7DF3B3DE9F74EEFF40B9EC2F72D24 +:105CA00076F609D9EF15B55EE4970A8F7F16E6A15F +:105CB0003CDB2CE44E31D00FDE3F9FA3925CFB1EF9 +:105CC000BB94E4F6972C169A6F27C8EB6D4A9FE0B9 +:105CD0008CE5D2FE2F6CCD827E6FBF8E517CCFAB18 +:105CE000352B58CFD7404F6B7D8757CDE37A5C0774 +:105CF000AF9A9740AFEBE4953D8FF3E74AE44FA7A7 +:105D0000E6B1F626AFB2F28C76421FF8312BEF8B5C +:105D1000E5C70179BDCAAB8BE6B36138BF6472A237 +:105D2000AF79A0B04E596156CFF119F3515CAD3245 +:105D3000DDC9F5F62E45E8F1D220D5DD4E12160765 +:105D4000849E3FBD9BBF572724B62B7D7959C4CF76 +:105D50004B772E0F580DF924617AFE5DFF69CF1045 +:105D600015F3B45D044FF634EE8794F0CB3CED743C +:105D7000014FF6000E77F6719ED72EF1952EF61B89 +:105D8000191556C33E42E2ED7635A0A01F3D33877C +:105D9000619A04EC134628E8E7CAF41BDB4B7CE766 +:105DA000B24D7F5631E5ABCAF83E17F73323F1BD4C +:105DB000EE7982FD2BD0A704F3C766E709FF839D28 +:105DC00079511F31B5A6573ED2ED4FEAF2FAE0679E +:105DD00069C8B3887D8351EFED4C6109FD0C7F11DB +:105DE000EB01EC15F237AB42CF4DEA28A67C9715B4 +:105DF0006E8DFC0FAAEA734E2DEEF97DA61F96B7A5 +:105E00000E1FD955A94CD3C19D1BC832D4F3ABFB8F +:105E100019DA17040719DE17365C6A783FA0A9CC97 +:105E2000502F0A5D69685F0C88D5D7076FF8AAA163 +:105E3000FDD0D6AF19EAC3B67CDDD07E78A4CEF013 +:105E4000FEB21D8B0CEF2FDFB9C250BF62CF370DF2 +:105E5000ED5B841FD98C97FFCCE372BBC5CAE550BC +:105E6000B3AB8CFC9B2D2EA37FF33E81FFCA8CF13C +:105E700025E8576F79BBB404F17D20FD4AF2B327C2 +:105E8000E30BB35C4B264FCDCF9F14E37DFC9CDD31 +:105E9000827CBD6C3FACDB2BA0EE7A6D3DC2B47151 +:105EA000048FCFDA18CF1792F11AF97D77BCC6EAC2 +:105EB000E3FEDA7417BB3B015FDC97A725F4A74A22 +:105EC0003E4A8637C98F17C2DBD302BFFF2CDE5E86 +:105ED0005778BEAB5E1FEC4A30AF337916115F0EB8 +:105EE0001E15FA66742A59F21E5A8F17AB0FE43C3E +:105EF000401FBC9997DB334FF7E3EA97E63FA86171 +:105F0000FBF9BCBDC557827449E64F3F23F0A6F3A9 +:105F1000A737707F7AAA016F6FC9F56EF2EBB5A44F +:105F20007F4AFEF416BBAFA42FFEF4B7F218E1FFD0 +:105F300069A473AE8EBEC21F9F6C1F1562EC109ECB +:105F400087602EABA6DF3725DB1F4B790EFBE312F4 +:105F50008CD3B6E2FE4B49A80753F2CB69FF4CFA4B +:105F6000A015F4A083FC04EC9006F5DB275AD8DDDD +:105F70005A1C6E69CF3B98CF695789AE19F83DFB23 +:105F8000365B99A27E21FBCC7EF917A1E7D985E388 +:105F90007D64A74D03F8D7E8F6D7123FE6F89EC414 +:105FA000CF341F8FDFAD03FD88F1BD7DB95C4FAFEE +:105FB00083FD37E2D1931DF00E447B1E9E6F43722A +:105FC000E48EA1F523F16A8EF3F555EE8CCFEF61E7 +:105FD000B78ECFEFC56E95F0AF10FBE7C9EA889D8D +:105FE000E8C73C1DB313DE54C6F32E1B0FDA5884EA +:105FF000E8C8F397251D6DB1F5EDA89F6DCC9CAF5A +:10600000AC6520FCB683FC9C18CBE1EFC3CCD98CEB +:10601000764F4685517F65FA8DFA2BBB2ACBA4CFEC +:106020008CFA2BBFDAA8BF0A8246FD55D85066D23B +:106030006746FD55149A60D26746FD3578C3D74C44 +:10604000FACCA8BF866D31EAAFE111A3FEBA6CC7E6 +:106050000A933E33EAAF2BF6AC31BC2F8DDE6D7860 +:106060003FEAE0F70CF5F2F61F18DA2F38F414E5E2 +:10607000F58C3DB6CDD06E5CC74F0CED00E1ED98D0 +:10608000FF3D9748C2D855A79E34BC9F2BECB5ABBB +:10609000BB9E36F4C35A791E7718FE22BDDE6341DB +:1060A0003B1A2956D6F54221D0755944F145A1D95C +:1060B000C23DBBC6E03C3E7CE39A83D8CF822DC66E +:1060C000FCEF851163BD910DCA40B9D0087C110168 +:1060D0003E598C79E13AF9B698358973817DE3B3FD +:1060E0000587AE63944F1AF6B763DEBB8453F29B09 +:1060F0005FF09B9C9F847731D87F512D0EA71FFEA8 +:10610000F2FD66871DF976FE1E85FD40E9094FC345 +:10611000DECDEB0B13C06586C36C87FE47BED13F57 +:106120003E597551BCE0F451D5C7FD8DC675B8E236 +:10613000108F13AC7842217F9D191FD23E4D8617D8 +:1061400035CCF70D8D392C12D1AD3F4DE0C3E13583 +:10615000AEBFD3F80F9CCF0FD508E61BA568A96684 +:106160007E1B13653DF19C56625CA7663CBB7DFDC2 +:1061700012F295067F711EF3C5F943335F99F1BEA4 +:106180006CCF663BCAC38BC5FB6BF989E312A0EDEC +:1061900046DB13E4D749BCC2BEBD03F548B2FDECF3 +:1061A00047F917BD9FFD28FF8BDDCF9EEB4DCF75C7 +:1061B000A2BF0DEC4BB39FCDAC8795BDFBFFAAA44E +:1061C000935FBBC381EB2EE873F23C18939E2C299E +:1061D00031E8C9EE7DEFDB0AED7B7F91E1B77B61B2 +:1061E0003EBFC9F03BBC00E72D197EA757076F0BD8 +:1061F000E085CEFD809EDA95C04E9CE495719700B7 +:10620000F94DD655F2F6E67623BCFC9CD1BEDC31C6 +:106210005EB23FDF2AF592FDE91ED3ABFDF95D11B9 +:1062200027BA07E39043E3F941F78A780D2C3B3F07 +:10623000D26D9D2DE0D5E70F67783369BCF4714FBF +:10624000B6631E758BC7E251342C793EF75A97B569 +:106250006ABBF82EC7F01D3FCFA422BE01AF5697F0 +:10626000F5533DDF4EF232EA37199C93BC7C3F690F +:1062700063C17BD11E92F161DBDB954E94772DCC0F +:10628000EFE172D2E7D1E77FD8188F074F10F161A5 +:10629000F95CF5FC637958ED19C189DE047958770A +:1062A00064F827E1F39035EC40BB33E44CBC2FFE9F +:1062B000AA97AF139B80170C50E22B9A877AF1F1C3 +:1062C0001FB037AFC7716F57C39427D9E21E53125F +:1062D00074F5DDCF15F4F6B08F82DE5EEC23B04F9F +:1062E00067E179327F463F2B6D3BACBE12C4F706A7 +:1062F000FCF738F2D32EC0EF7BE4BD8A73B8B08FC1 +:10630000EB358F57F6B33FCBBFCCCBF30D9BB03FF4 +:10631000FF30CF5A55D74FFA05FA917E8E3EF8AD31 +:10632000BEED4DEC1F3D85FABDAF78DCE8EDE12F09 +:10633000DCE8EDC55F78EEF8B00C8C674B7F97B961 +:106340009D3C1729EB1B328DE3AF2FE3F5FBC5B85E +:10635000AF887B3A7688BAD3745ED43995D13D1D27 +:10636000F29CA9EC6787D74DED9BB327ECC0F9AE43 +:106370002F56681FBA3E5331EC47EBBD953B900E4C +:10638000DB44FF3B907F73296F94FC39E63CCC25BE +:10639000A2FD12EF042AF15C2BCA31BBAA26C4E38A +:1063A000135E3EFF5999BC5FE977AB7F4011FB2735 +:1063B000E3BD08B0CE5F4E03F97362938DCEBDCEC0 +:1063C000535DEB911F93DD73503B2240F94FFFEC7F +:1063D000F931C4675A564FBDFABC37F1BD05C9E45F +:1063E00088CE9F76D87B11794B1DA99C4FBBDC2EA4 +:1063F000F29B9BDBBD2BE8B349F83550AEA37EC9B9 +:10640000525953223DF3AEC0FB3F7EAE99DFE79178 +:10641000ED72D177E673CD1DF68E75F938DFAB15C9 +:106420001F9E5FC8AFF1ECCBCFC1738C1AF9F8D6C1 +:1064300017B3F40A7C5F6AA1F799B33CEB6D98F748 +:10644000AD31CCDC673618C70DE3A4171473B8C29E +:10645000D7EDCB8776195A171B3482CE7B4FF1E2EA +:10646000BAADE6F9F33DF02DE49B6B1DEC2F101F48 +:106470005AE23CF4F342BF80BCF93BF26BA5C6760E +:10648000F373593C0F16D992F2157D3C5F3B0DF327 +:106490009D06737983EF95EC89D682DCF8FA520574 +:1064A000BECDE7B9D30BF8387D3DCF3DA326F17CB7 +:1064B000871770B88E67047270DC19E39BB93FECE4 +:1064C000B3F3E7D531681CF37502DF33F457A4E466 +:1064D00070399CA26924979947A13C57A7E66BC0E5 +:1064E0007A8AEB4A8F8A76B283C725D95C0BC3FBC5 +:1064F00055268A7EFCD54C79B784FB65B99CB5B22C +:106500007725FFAB02396350CFF23F603F6D4A03FE +:106510007826BA0E537C32654853259E6B787E0EE2 +:10652000EFE37B49CE0DC8F3EEDDE7FAD98F0E1B02 +:10653000CEF5AF7BE4F0C1AB75E7FAC38F1CF68FE5 +:10654000F8C7F3DBA73CF4C8E1B5AEFFB973FD5261 +:106550009E1D5383C7EE04FC5F0F4C152AC3D2CA9D +:106560006A88DE5EC2DB2C81E7F0A78067671CCFFC +:10657000D7EF3D44F83B668379C3F8B6091CD5B61E +:106580006F66445A482E4668DC1B9CAD9371DFD978 +:1065900069EF1A89E3763EF3CA8030C893E3DF3AA5 +:1065A000E366C07F6F5ABBDCF8FCD4AA97DC780F97 +:1065B000C2F1552AD96B742E5A978FD420F8EA5716 +:1065C000058139C85773567F3E466F8FB3502EE909 +:1065D000DF85119552AFA4FC5BBC234D301DAF2F5E +:1065E000DD996DA84BBDBCD491F89CFAA3059CEE37 +:1065F0000B1F6FB3176A387E70398E7F4AE4379C61 +:10660000DAEDA67D989C4FDDE3A576DC77BEB9D7A1 +:10661000C1A2E4076EB731F267F9A72A79788F1122 +:10662000FF639EE70BCFA6517FF31E50C9EF540BBB +:10663000638500AFC1BD0BF93ED804C7BCE3DA14D3 +:106640009457F3362A2CACF1F6ABF0FE8CD05D14E7 +:106650008731C369D62F0B92DC9FB360EF3DF4FD09 +:106660005CE6BF07EDD979ADE6F7D7BC874CBEE055 +:1066700002F19CFB0B84DE19C3C69E1F4CF1A38C58 +:10668000CBB50BEB9D53ABF922FD60B593CA8F568A +:106690007BA89C53C0F978F19E7D2F14D2326F1FD6 +:1066A000837AE9E583F5695FD7E276F798B65BF719 +:1066B0003F4C4D8DF9993502EF63455EE60271EE70 +:1066C000A1FC58EF799935888F913DE72BEDEC1AB5 +:1066D00093DF57DADD667C9C3E38310DF9E3970590 +:1066E000629F3B16F0A2FEF37849F6DD5295DF9BE0 +:1066F000667E2ED7D11CC1D773B7CF5CDF0FC66FB4 +:1067000079E6BD811DC4A7DC7F512EF055EE5ADF1E +:106710008EF0973393DF30CC8E321D3F033FA9A814 +:1067200077CC7C2BF9891DE5DF3B855FA39B5FF769 +:10673000DE4BF8957C85271D2C68C3B1A8D7527114 +:10674000E17BAEE6B51AEB1FDB3A06A23C5960F2DC +:10675000377CAC24DEBF1D2A1844F898ABF9A7603B +:10676000FEC53C1658CFFDF3FC7E9C53D6D617EEE3 +:10677000C475BE9DAFB3A5BF7CE21728BF16FDEC64 +:106780008174945FEF5B5BF370BC258FAD4B4779F1 +:106790007FCA1A4EC7EFDF8FA809CF115FD24FEE25 +:1067A0009FFD2ECC535B46AC06FFCD0D4F47F9F94C +:1067B00097C76C1EF4C336EE70441D808F65BB39DD +:1067C0001EA1FE16AFDF45F86ADC635C978BFEFD09 +:1067D000813C8DFC01E14281BF4214E1CBB6DB2854 +:1067E000AF75D951D587C334B22E82CFFC3DCE23AD +:1067F00006746BDCA9D6DA337ABE074BC88EEBADD4 +:106800007137A767E36E4EAF46931DDA20E4B69961 +:10681000FFF3FA097920F81EF0437E35996FCB22F9 +:106820005C7EB7FCF8C1916FC1FC3EDAFE9B7465DB +:10683000449CFF196685023D4EEFAC9F63EFE5BEB9 +:106840009E8FC53AE9D60B420F697B6062F950DD35 +:10685000CBCB25B668FA558097256D365F181E2F6D +:106860007942F5BBD08E7AD541F74F2C7EE2F9976D +:10687000AF84F92DDE65CB99CAC170A1FC96F46A8C +:10688000443E2F8BD367D153CFDB314F139FAFCA19 +:106890008AD369F1AE7D76CCFB34E373E2CE7D76AC +:1068A000BEDE4CF4DAF9D614D4DB2D3F3E67477ECA +:1068B00078FF5985E517F7FCBEA1EDF9749433888C +:1068C00027D42F926EDD74EC41BFE8F4A747533B09 +:1068D0000FC6792E44C7BFE019845CE2F79F3E0DD6 +:1068E000F36878CDE1433C34FCF4D67484E73D6B27 +:1068F00013E7FB47D6E5A1DE6EB085F33C54F2E723 +:106900000D5BBF41FCB8E0C56FF0FB9C98BF00D7A2 +:1069100033C05B8070CEFBE1F504E77C16247E6C0F +:106920007884DF6F78D6CAAA12ED07DAC4BA796F15 +:106930009B83360FEFD919BF2FE4F7AAB80F6B3935 +:10694000D92BDF10308384A6FA5927A7D7CA7EF245 +:106950009C3D976F8DA255E3F6BB48BE7D30C09F2E +:106960008FEB1FF060F4CFBE38395FC845BAD785CA +:10697000BE03FE9B88CFB17DBBCD9F32D2F09DC8B8 +:10698000BFE5E3AF14E3C3BC53D1CFF75E9E719F65 +:106990002BCBF66EB9C0DA999ECF92C981ED1B89D7 +:1069A000BF3E39CAE5CCB2C8CC2A7ADF6E8BE6E3AB +:1069B000FBC8BE590AC909B04312ADF3ED36B1CEDA +:1069C0008DEF619E56458FDF67F9F93DC92FF3EFD3 +:1069D00087F6BA751DE71F7BFC79717CBDCAFC8DFB +:1069E00005267B4E966639F1B0494EC8EFD90F7334 +:1069F000139E8F88CB8730E16F892DF26F3FC07572 +:106A0000FDAA83CE452E79C246F7FB7CF8F8FE97A7 +:106A1000BF0EFCFFE14EB99E8DF2D7BC9E1B9EBC03 +:106A20009E255ACF1FE60458C2F50CCF13AEE71CC3 +:106A30007EDEE0FF96FC5D9044FEBED0AFA7DD7128 +:106A400015543FF8C9E222DA9F99F02BF16A96A714 +:106A500037A3B190DB539EC29FA34C874F8947C990 +:106A6000A78BFE63298DD3CDCF925F253F77F3AB04 +:106A7000196E233ECDEF37E2DEA93C4E7FDB1AD8FC +:106A80009763BCF61995F2F33AB5AEF42C18779DDE +:106A9000C8EFE9F4887A26AF77E5DAD7A33C91CF3F +:106AA000BB5278BE4367A02B3D53B71F786BAF9A9C +:106AB0008EE7013A2289F332286303FD2049F2363A +:106AC000E4B9DFCE54EEEFEB4CE57EBEC9AA6B60B5 +:106AD00008F777AD3CBE34B7F9C674DCDF77EE1D3E +:106AE0003CA31AF70387549E7314F65B0B00BFF5A3 +:106AF0001C74768A85BF3F1EEDF7BD8BA7623F737E +:106B00003719F132DFB5DD8EFD9C65ABA89C7FBFE8 +:106B10002DCE27F0DF22CCD7423EFFA1E9F9DE6B74 +:106B200089AF1699F82A887C95E03C4966A158AF50 +:106B3000A5AC94EFB7457C4CC8BDC9EA8819D59877 +:106B40004F79909FF738BD5765EB11DEC745BC2CD8 +:106B50009C4BFCBA0CF85BEF37FD08F96E58723DA0 +:106B6000FFD1CF8F8FB9139A2CF9C51F473E0CE583 +:106B700047BF78F592FFC2FA2F5F19F847D6B3FDE9 +:106B8000C467FF7A0BE5753EEBA07B4D3B9FFDD5BF +:106B9000C03BB1FEB483EE17ED5CC3F7D9E167DD0E +:106BA000A4FF3B07707BB1E59973233B487FF17BE2 +:106BB00083C717F27B2A4EEFFDDB1B0AE6F3ED05D8 +:106BC000A8503E8AFD5BE3D329B44FEF7CE69C617D +:106BD0007FFACFC2B34C9CBBEA74B36A3C27DD9901 +:106BE000C9CFA936FED7B81FE1B9CBA5BBF7D9EB02 +:106BF000E1FDC4FFF3F94894439D4F72BB03ECE100 +:106C0000ADCCC7D8570A37DF6B03FA7D8C3622AC80 +:106C1000998EC217A7E179929E78E178E8043C202A +:106C20005C809706949FC9F0714B213F07F3AF87B3 +:106C30008F3FDF82E32FD93B96EE198EE345F1F3C8 +:106C4000E76ECAF700F8F9F367CF8D443BEA42F0EC +:106C5000AEFA5F06EF0FFEC5F97D5021D74766BE3D +:106C6000EFC9D7BFBC8DEA3F75FB68BE7D5CEF4FB7 +:106C7000FF2FA3F7B1FF6FE97D48D0DBEDC1B84C22 +:106C8000E7339F0F641701F7B97F593AF70E77B7CB +:106C9000DD63F13947C3FC5E6391EB2B95E4F9A307 +:106CA00043FA2B721F44FB0C790FF7F49CF96447ED +:106CB0004CF7737F4C0B2B3B88E7ECC27E95E217B9 +:106CC00094BC0378689F551AA13C316B78E8F73182 +:106CD0006FEC86A53E7E5F9971FF353DAFAA0AED48 +:106CE000B923CD302F6877C46DF1B4000833FC2A86 +:106CF000D97F5092DDF78709D7521ECA8C0AE33E2E +:106D0000E4EBA6FDC48DD5C6F737B06DB998EF7723 +:106D100043838DF293AE37B5B7F4F7105E6E644DD2 +:106D2000EBB83FE7E2F034AB3FDF8FF5C443EF78D9 +:106D3000EB8127B1DFA4DC21AD27DE1C41BEFF744F +:106D4000C00B616F89BCBC157DC22713FB5287182D +:106D50005AE2D7E1E7F78EEAFA25BC48BC5F2CBEC1 +:106D6000259DCC7897F8957833D361189EF7CC8D14 +:106D7000E33F5E1AEFD566C26E9CDE6D37BA088FB0 +:106D8000BFDBCECF4BFCAEA27E5329D61FE7F7C1A7 +:106D90009F1D3F8A3901DE2336B687E2427EBFE679 +:106DA0001913CF9F512A7E45F109CC5FD4EF57319B +:106DB0007F510F17E62FEAEB98BFA86F8FF98BFA78 +:106DC000F798BFA87F8FF98BFA3AE62FEADB63FECC +:106DD000A2BE8EF98BFAF698BFA8AF63FEA2BE3DA5 +:106DE000E62FEADF63FEA2FE3DE62FEAEB98BFA89E +:106DF0006F8FF98BFAF798BFA87F8FF98BFA3AE675 +:106E00002FEADB63DEA2FE3DE62DEADF639EA2BE33 +:106E10008EF989FAF65F8E3D67A857B2DF18DA4F10 +:106E200074BE64A84FF6FCD1D0FE2BDE1386F7D7D4 +:106E3000681F1ADE4BFA5F5B72C6F01C631FE131FC +:106E4000B88FE17FA6F9FE66E8C7CA021427B5B37A +:106E5000262A9DE8EF853295EDA4D205CB1CCBF711 +:106E600087057FDA1FF9756B783D32D79171E70698 +:106E7000A2FCFFDDF8EBB85F42C41766E03F356067 +:106E8000E2B4CFFAE33E57C64FD3632A8B8E023E5D +:106E90008C29547A62692C9A0D7C184BA1322B965E +:106EA0004DCFB3639954E6C40AE9796EAC80CABC8D +:106EB000D8602AF363C5547A63975159101B4E6505 +:106EC000BFD828FAAE30564A65FFD855F47C406CDE +:106ED0001C95036313E97951AC924A2D762D95C523 +:106EE000B16BA81C14BB8EDA0D8ECDA472486C3623 +:106EF0003D1F1ABB89CA4B62F5540E8BD5525912ED +:106F00005B4CE5F0D8422A2F8DDD4ADF5D165B4EE3 +:106F1000E588D89DF4FCF2D81D548E8CB550794587 +:106F2000AC994A5FEC1E6A571ADB486559EC3E7A09 +:106F30003E2AB699CAD1B187E97979EC212AC7C42A +:106F40007E44E5D8581B9515B1FFA0725CECC75480 +:106F50005E197B8ABEBB2AB68BCAF1B1FFA2E75786 +:106F6000C7FE93CA2FC5F6D3F32FC7F651E98FFD9D +:106F7000869E57C60E513921F6123D9F187B91CA45 +:106F800049B13FD2F3C9B157A99C123B41E55762C1 +:106F90006F515915FB90CA6B62EF53F9D5D819FAA6 +:106FA000EEDAD89FA99C1AFB1B3D9F16FB2B95DDA3 +:106FB000FBFFF1497F57C0721EF7CFAEAC3EDD57E5 +:106FC000B6392D9DE4E2F4555C2E3E98F6F101921F +:106FD00093E31C9A8384DF1643BC8B7E4402F67DC8 +:106FE000FBC6BDD71FED9DF595275EBF15F5D97280 +:106FF0000713FACC24773F73097F27C37CC49B0512 +:107000005FFFAE627F2EDA51EBCB3A96A0DFE4DE73 +:10701000E28E1A2C0B07703D9925CA8201C2CF5A05 +:10702000C2F56FCDF2A1FCF70572FA065FB5D0DBB1 +:10703000B2BD5224EAAEAE81745EAF8FFDF4B5DD11 +:1070400085F2B03EEF1FBC62406E6FE707FBDC4F7E +:10705000C517D44FE580047961E67EDE14746F1B9A +:1070600010988CED99D53F12DF4F5853A0E2EFAA4C +:10707000D46E523CC82FF56B4BA7205DCB989FFC7C +:10708000923727C9275B2CE85AD76463E89FACD3B3 +:1070900018F987EB76F33C64F4A74E037E6910FC85 +:1070A000B274E39FC9EFD4D0B480E73D45B87F4ABE +:1070B000FE8ECDE2D6B617D0AD77961DA6FCF8C5EC +:1070C0003B8CFEAB46E19F5ABAD3F4BCE92B09FDD9 +:1070D0009E66BFD4DC01C2DFE9E3794F4CED4F700F +:1070E0009F05B8319F24789BDB897A03F0417118A2 +:1070F0008907E9F794F8603DCF5D50FEEAE98343E4 +:10710000294FEEB4A6E563BB603AFF3D2BC51A1CC0 +:107110008BCF018F94CFD2D59C46F9506F811ED072 +:1071200030F1CA131C8BF7C775BC368089FB2B8DD9 +:10713000F108E726CA13AF8539605E4AED63D9745A +:107140006E13FA1BB907FD9A8FD9281F29CC5678E0 +:107150005945CF7845609D8DF8A26E4F26CF4F0BD5 +:10716000FB8FE2B9024997B7D60E9E82794D751B07 +:107170008A4BC95DB7C746F6A18CCB4A7AF5CCDFFE +:10718000E6F9028D2CB21E5397805E2713D2AB75A1 +:107190001FD115E8763209DD4EF646B7874D7443A8 +:1071A0003FF58DF8725536ADE79A35D1A14D3AFECF +:1071B00034FBFFD9DC2BE9DE1399FF5CD54FFECE03 +:1071C000982F0FE97B665339D1CD4CAFAABFD713A7 +:1071D0005DD86B6EBA77F8E6C16CCED7E0F91CE1EA +:1071E000F7BCB9E51AB2BF770B39F7BBD598FBC925 +:1071F000D88BAB9DCC0FC6F74BAB3D54FFC36A2F6A +:10720000D55F59AD51F9EAEA122A4FDA795E915CFD +:107210005FC00894DFF7B458574F0F90FBB2955EEC +:10722000F47357FDFDA5720B89BE37A64F1E40763D +:10723000BB215FA47A96311FA4C326F2CD362A3E25 +:10724000BC4FA62E7095A13D2B1915AFA3FE11F9C9 +:107250002B751B32E91EBB9BA6661BDADFB0A1D0E3 +:1072600050FFFD008DE09E5935D8F0FCEB359719A5 +:10727000EAB5E2F723985641EB46C6BF407373BAAE +:107280007878DB4F9AC6E6DF0EE37F72D846EFCD03 +:10729000F438690FD37E3EBCCDE1C3F8DE293CFF54 +:1072A00006F5537F5029BFE8948D853D20E24F2994 +:1072B0006C2D96CCCAD7D5D9637C5D55FD5D65B87C +:1072C0008F673F71507CB07E8BC2C27837431760A6 +:1072D0001EC65DF96307C13D778BCA8274BE4ADB67 +:1072E0008971F2958F0DF3617CF4E6C1D10178DEEE +:1072F000B0EBE7293E3CF755DFC1BF3F05FBF34C40 +:10730000CC8F52CA281EF1A769ADF32D986FA71E26 +:10731000CEC5F5FAA727F9EF9A2D5CFE87311EC07E +:10732000F3A21776BE5C01E39C6C5569DC0F7738DD +:10733000DA545AF7FE7CBCDF360E7784FC14D7F69D +:107340000BFC0DE5F507F3232349FEACE2FEF19EAD +:10735000F8017891DEC8AF3A7916D76F3CFE064245 +:10736000A800E544BDCD4771D9939B6C142F047DD3 +:1073700040F906275BB32D5C0E3D497C5767D5EC81 +:10738000FA71EB36A97EFEFB189A1DE7CB36AB41AE +:107390003616EB3C3F22BC4109F2F88F91BEB72E66 +:1073A0001F4BE7A2CD795CB2FC18D6545017575A40 +:1073B000F40C8FFFB2D11D567D9EBBF4CFB060851B +:1073C000E13EA325831EFCCE78284FFBF9D58B67C1 +:1073D000B7BB494E7E64796ECCED507E382DFCAE45 +:1073E00015E8F2A21A1C3610F3862C9BB62A145705 +:1073F00039F11D8CFB7FF084CD47CB50E48D2DFA05 +:10740000C9428A4F25B7179897C7AFA3798A176FD4 +:107410002766942F329BED14FE8508CF33C04900B8 +:107420007E3C4B785CEC44B9FB6E3C3F5C6F3A6F42 +:107430007C429CB3B872A062D0D7770CE472A0DE15 +:10744000C2D7277B96DF43297F2F4ECA71296FA5AC +:10745000BCFEEA409EC722E52C633B49BECC17F731 +:10746000252FD9E1E0E78B34E6413C2EE4646277D6 +:107470000DE4EB7A91FD89EF235B2F60EDA4F73EDD +:10748000B045E6B717E3F76D6BB3E87B9B2F82EB54 +:1074900038227F8FCE4A726401E3F35CDAAA44A2F9 +:1074A0003A7F87FC7D12867A4227777AE805933EF9 +:1074B0009827F4DF3C66CA376A35EAA9409A9BE010 +:1074C0005AD42AF2B0BBE7A5B2F318EF0A465E9889 +:1074D0004EF3567C9104F358C0BAA2782FF2D2C76B +:1074E000F93926F3BCCC70F4759EF37D3327E1FDAA +:1074F000CADDE39AE62DF1CDF060958E0E12EFF322 +:10750000C31C9FF3F72A44AF7784BD25CF079AE9C0 +:10751000BF8005A6A39C5B703FEC338BE3FC20F996 +:1075200060E1AE089D07FC90B5A6BB603D2CD9B2CA +:10753000EB8671F0FD821FBE68477EAFC98A0EB52B +:1075400064C2FE333CE9BB555727D0FB263DFF45BF +:10755000E18909BF157D077899B75DA53C0A5D3BB8 +:10756000914710267C3584F9EF09361C557D2DF0A6 +:10757000B4017FE6A8ECE2E72BF1F63F3D6FB35D87 +:10758000F38B81BDDB356679D3C3AE31E9533CCF94 +:1075900081FAB32B97E7A77F62F56764919C36C9A0 +:1075A000E1DC32BA8F55CAE1F9420FCA71E6A1FE99 +:1075B00083FABB5B9E4A477FC63BF73F9547F91A64 +:1075C000A86F46C4F5CD6DF57CBCDB7E9942F952BF +:1075D0007F9AD63E12EDC19A477E95AEBFEFF54F2A +:1075E00005C1A30371BE423F2E55DB06E2EF1A4AE6 +:1075F000397BC17D5B3238DD1780D36D84B30EE1FA +:10760000D49D53A91770BEBD81C377621387776E6F +:107610000F38C31457B9ED470E5F98EC8E28E9F583 +:1076200053BB5486FBAC6EBBC364079C65AD5B115A +:107630001F4B57BCF28615F862E125801FE0839A44 +:10764000CD0ED2FB0B7FCEE3A91F2895F914D03FB6 +:10765000104DBF039E2F027B01ED8DF83CBAED80EB +:10766000CF108FDD76401FF1B74CF8B596EDFD15C4 +:10767000FD8E96E2E7F998CBE4BD367B4CF7DA68ED +:107680002803F8397F27D2A9BFF93E2EEE9FFDCB04 +:10769000D03FDFB282F8BFEB12FD39B6C6D4A80DD9 +:1076A000F390BB762964272D5D59995EC9F07C1B48 +:1076B000F7AB151471FDA6F8FD945FE300BAA6C2FE +:1076C00078FD8B34FE5CF3F07CF31F32BA4747CE73 +:1076D000D7FC1CFDED4ED4872E0BE94333FCD716A7 +:1076E00071BDB954B5907DBDC4CEEDEC4E717FC572 +:1076F00070318FE145FC9CC315C2AFD0897625C699 +:10770000BBAF76D0EF18313689FCEE56C6F9CF2ADA +:10771000F1E6B17EDCBDBEC97EEEEA8F78BA85B5F2 +:10772000D3EF224EAF98A9E1798637F29C744F14BB +:10773000FC09603FB3453F476CFCFCC21B3806C0E8 +:10774000355BF8A7DFC0EB5161FC370AEC64D786E4 +:107750009F7190DD70572AF71FB29C0C2BAE87AF3C +:107760000B3975F378871FE5FAECF17705B084FEE5 +:10777000C20CF055E3EC5A570AE3345BB8BE6FCE47 +:1077800062DC2FB0B6A31CF1770598C998BF0FD063 +:10779000EF3E9FDD1B1F19CF4F2C413FC3958C330C +:1077A0005805E1D7505F62E7EF6B1FDD31E3FEF173 +:1077B000B04FC0AC29D4338823E48BDA0CDAFFCE87 +:1077C000C0F30559585A89DFBE6665610B2F37B87B +:1077D000E85E25AFE17761AFAF60D10C802F7AC84A +:1077E00078BEE3C6A8253A0CE345D6E83EC49FC55B +:1077F000A9D93C304EA04A2943BC2F59D3B7F9AE82 +:107800007CF4A919F7F7873ADEE785F3BC43A17C3E +:10781000A1D9B0E8914F6FB1B2036A19A71FF26105 +:10782000639616A676CB399FCB7325922EA5D0BD35 +:107830001EBFB3C5FCA09F0DE9F8BD3DB15F252C6F +:10784000F852DA6B8BC5BA5D2CF9EE71E37ADD265E +:10785000D70DDA8780B7D9A24CC6F78F8A75F16841 +:1078600011DF67DE5324F7997D1B6FA9834509EE6D +:10787000671C444739EE0C513E523488FA93F3901A +:10788000FC3B9F35513ECF7CE1A7B18024A1FCE0B9 +:10789000D61F71BF9029EF080C25CA6F5BB4DDFCC1 +:1078A0005CE7E7510D7289FCA68ABD6B2ECE4FF9BD +:1078B000528A0FF97DB67D27F907CCED6CF8FBA94C +:1078C0001877DB00769522E26550776C52E8772FC7 +:1078D00066F7EFBA1CF53948EB29742E54D8DBF360 +:1078E000057D1DE27EABF9685F615C0DED2BC4D7B1 +:1078F000166E575A853D5CB7C9686FCC5EABB33B1B +:107900007961B81FC061CA53B709BBE34D7BD7E5A6 +:1079100028F7CDF705BC69E17084F318BF573387AA +:10792000BFB70AFB52F2D5CF8A6C86789B3C775A58 +:1079300083F28ADFDB60CAD372D1FD31350ABFBF63 +:1079400053FA215F17E569B043E9BE9CE369140768 +:1079500037FB273B2BDD618BCE4F7973C66DD3117F +:107960003F35E9762B96AF77DF2BD641E31FF70C37 +:1079700022FB677DE5A82D989FF4DEA36766380794 +:107980005034459C9F8AFD0EF3E9677D06F050FD5B +:10799000AF33FCB08FEA7CBEEB162788EECF8B3E70 +:1079A0009D61053DDFF940D756AC67686A80EAF70C +:1079B000760DC43B9733220E5E6F96FD3902D85F79 +:1079C000E743BCFED1A38E4018ED5F716EA9E64A75 +:1079D00085E4AF0BD75779DCCF5463798E9713F8D2 +:1079E000EFA25CA89D570BB88ACAF13ED493F4FB72 +:1079F0000B8307F95D45807FCFC0E0392C17CD544C +:107A0000C2763CEF7F347289D06B097F27C425D6BC +:107A10006B617180BE977E74E88769E53DFBF96F05 +:107A20008E8B3EA000800000000000001F8B08002D +:107A300000000000000BE57D0978545596F07DF5B7 +:107A40006A4B52498A244042162A090901031490BC +:107A50004080A04512202C810A28A2A0168B10106D +:107A60004840EDA65B7AAAC226E216D4B1691B9DF6 +:107A700012D1C66EB5A3B204D92A6C823A5228DA62 +:107A8000A8A041504163774418E30CB6FF39E7DE04 +:107A900097AAFBA8B0F4F4CC37DFF7878FEFE6BCEA +:107AA0007BDF5DCE7ECEBDF7651C63AE7A1B633F88 +:107AB000E3CF0DA1D2D6D5C05821632F3ADCB6AEA4 +:107AC000504E5D9813EFC967CC9EE18972003CB7B8 +:107AD00052F199FB30C68EFA73DDB18C8DBB423FFB +:107AE000BFC8BCA49F847FA49F8F74FDDCAEC0BBC5 +:107AF00083E03F733AF0FD3BB25DBD1D1D19BBEB4A +:107B00005F9807FB6165430C6C0063775B19FD7C34 +:107B10005FB335D75A00E54B96449609ED5ED9968A +:107B2000310BFA618BE1A514C6BE69FCC8EC807EFE +:107B300016B4AACC95C85875AB42E5824D8DE611B6 +:107B4000D0AE1ACAD2B0F9CD13F365ACC93821361C +:107B5000F4BCBF83CF97B1358CE17C5E396BF440C8 +:107B6000BBBB0CF55F3E95048F072BCEE71D97AE90 +:107B70003355BCF72963E5F5F997D60F722854FF02 +:107B8000588EAB08D7D905FA405835F0F5EADB2F07 +:107B900015FD4D8D6677B8A17EC68058AB03F05DAC +:107BA00078D4B32C16E6316B5D663F15FAE89F5129 +:107BB0005282FDB19983257C9577612C88EB33B691 +:107BC0007462507EBFA3309EC1BCA62604EF617DC7 +:107BD00019FB8DBF7B9D752863637E0B6DBAD02B1F +:107BE0002E06EF965B04ECBBDE5D560CF0DF558293 +:107BF0003D8EA23A1FBC7F10E703E56D037B45B3C2 +:107C0000DE80BDCC18833D9EB192F469BF41BEB801 +:107C10006DE0D011F87C982536771AE197117F94A2 +:107C2000A4BB27633DB667B00E8F39D0F166588785 +:107C3000E72DD5E98375787AC778FC11F03649E0ED +:107C4000E1370E3B95070D30CF7EA17968E30367DE +:107C5000DE1384FE4E2F4DE9BB1AFA7B367DD81217 +:107C6000C28B18FFD974CF9CF0F161B9BDF1F9D581 +:107C7000CE639698C71241377731F099C0F5CFF0AF +:107C80007F42598C04DF383691B9F242F0A41B537D +:107C90002578F2D46CA9FDAD33AF93EA2B2CC182C9 +:107CA0001A5B88BFF5F3D14A2014F16975ECC63828 +:107CB00006533CB1E3C28753404EFEB641752A30AD +:107CC000D7393B9FFF7008B43A070B4E04BC9D7335 +:107CD0000100EB3DB749F5FB32913F5CC68A4E8C03 +:107CE000556157D07EFEA1D7CDC3E0D7AA9AD963FC +:107CF000918E73FCA6CF9BC2E679815D34B32C9044 +:107D0000878DF2F36AF6D0776A6F840266772FE880 +:107D1000A75E575F33F22B1687ED8C9F3769EB8494 +:107D2000F1171FCF7C645FD8BA9F76C4267D791D7A +:107D3000FCD28FF5FB59C5F19A0FC00A596943234C +:107D4000D169D921D5892CBA2C5D610AAC73E4269E +:107D50008B3F0A44EBDB6D27CD0EC0D70F5EC723E8 +:107D6000FB4C28FFB58C25E27B27CD4DF07CA8C3CA +:107D700041785AB0E33B3303BA8FDCB190E47A0424 +:107D8000E8B178E09F6023EBB509FAF765C63A9F42 +:107D900087FEEF5A350A848BB1F8D62954CEAB1B37 +:107DA00045FDCD6F9D48F082D618820F46074730BB +:107DB00098C7C12D1DD83298C7613590FB7BECC7A1 +:107DC000124B7AA222F5B6A5B8EE83D1BEFCBB61F8 +:107DD000BC8A3F8F2C47BC2ED8A4B890CF2A5476AB +:107DE0005049C0F946517F15EA7B050BE1F998D25D +:107DF000589F219EEA19837A7540EC6A06B06A069C +:107E00007D11813F0F09FD626AE2F31EDE5A49FDD2 +:107E100069F5871D59B47E0D3675DC609C6E0BAD1F +:107E2000C7D4A45039BAF53A2AAB37551A1D30CE0B +:107E30005B79CF25219EA0BDCD13512F0F8C6711EB +:107E4000F497565A843E9E82FA18FA3D90E5FA025B +:107E5000E572DC9226A315F5A9CD6A7F1EF8605C59 +:107E6000515FC7ACB075A97B6E610EE0234B528B9E +:107E7000C905FD4F81325C7FDFD18EBDF9A64D7FF4 +:107E8000D752A9D925E65CC218F0F9ED763E6F4DC0 +:107E9000AE8E89F6DAFB4185CB876FB3C5FF3CFC1C +:107EA000FE5996E7279C6F70189BFC1AE9D3604631 +:107EB00065EC3F6FFE405F2BD23FCED8C412E07D11 +:107EC00043A6367F2ED7579A7F8B98FF61952D4614 +:107ED000BE387CC30D4117CCABF1BEFEFDD13E6870 +:107EE000E325669AA93F666FB988FC5ABD2BC6B1D7 +:107EF0001AD65701B441B865A7C5BF3E939E332536 +:107F0000094BCB7A05EAABE35A72D1FE94EE8E0AA6 +:107F100020DF36EE8E32A21D7933C79398D9119F98 +:107F2000772F5380BF5D3B2C46E48364872B29B3B6 +:107F3000B0FDF95E498F69F2A8E733CF2A2E7F1E84 +:107F40002187D304DF4E177238CDE88CFF25CCFB98 +:107F50008E7754867A7CFA12A5D7A602D469B1CE60 +:107F60009C3039D4E4CD847CD91FF993F3E5BCD699 +:107F70000E42BE3345BF5C0E2AC040237E2AAEEBC4 +:107F8000E047F95ED09A48ED3479D5E4343DDB53CF +:107F90008AEBAE5806F20DE37896A614A0BC84F8DE +:107FA000C46C477E023E499E15C607CB1A7F342219 +:107FB0009F988A15E2130B94A5617CE46EF353EC51 +:107FC000233AC13CC62DCF34AC66A1FA72E4978E39 +:107FD00057CFEF85A2FD745B20C700FD996AA29C74 +:107FE0004B615EE7921CA4C7163D0000A06091C9DA +:107FF0005D8A7EC6A2DF294ED4BFE87FA0FE19703D +:10800000ACC6EC099BDF2DADBD9903F034B1B51BB7 +:1080100095FD333C93100FD35A27093CF6A69239AD +:108020008A0C389F7BACDCCE9CAFB9FF761CEFBCD2 +:10803000DFE2C4F1182BE2F416F32D74393BFF1282 +:10804000E7F78E893D0BEDCF44795494CB33E9CCDF +:10805000FE384C71C65AA033F47BC6C47C76A0E7C8 +:108060004C803D087760AE0EFD50EE609D6176E578 +:1080700082B12E8365037D17FDE55323A8C239B96C +:10808000C1DE011877EA306EFF9B3798C8FECF6BD0 +:108090007C6F8001EABFCE747566A07BC774F1D493 +:1080A000E07AE64EF0BF6202F8AE875F8F1BE4080D +:1080B000E1B3DE18C831C2FBF580471FCCABFE210F +:1080C000B5DCCFFD9E98CA5E57E6EBB9ADD9841FEB +:1080D000CDDE68FA7BAB37191611D2E357B2431ADB +:1080E0007FCF1772301FE58085DB9B4AF730E4C3F2 +:1080F0003CC599C3C2ED0D97074D4F03BF93DC54A8 +:1081000064A73B97B190DED6DBA3BD6AFDE3836134 +:10811000BDCBB33CEB510F94FCE9BF5EFF18AAE660 +:10812000BDF66219D269D8750A5395ABD1933F9ABF +:10813000484F2EA964A427A10CD793A676FCF43F40 +:10814000645E9B9EFF57C1F7E0DF92DF887A3CBCFC +:10815000BFCFB24AB6219D77652A5CEFFE93E6ADAC +:10816000D7EFBBDAE4F5EAF4FB4BA2FD95F4FB1183 +:10817000D4EF8597EA7306FDA13EFFDBCE1E7ED4C9 +:10818000F79F32D0FF68DF76C4389E17FA9EEC4125 +:1081900074BCFF72FAFEB19C1947103F11F4FD7BCD +:1081A000FF0C7DAFF1975E1EF472A0E7FB310F82EA +:1081B000FF8574DAAA30D4AF217F8B111F1FCCE268 +:1081C0007CACC94D98FF45761EE4C19F9379A95CAC +:1081D0007E5FF3970207C69B05B17D9912E2774D4A +:1081E0005E347ED7DB9139591E35AB302427F35EE0 +:1081F000D3DB81F6F8699B09E357D3BCEFB81D8048 +:1082000032DC0EB4E7EF58B3AE4D0EFEE32AF92987 +:1082100035EB7F9C9F52B322F3535A56C77F9C9FE6 +:108220002E4347B2331A9F8D799BF307CBE6FE3E70 +:10823000F00BCDFBA039DDBF2C13F51ED787637E75 +:10824000663588CF3B443E41E3D711D91E17CE5344 +:10825000A333FAF7E8B75FAD5F3825A986B9E0F92F +:108260001D5086EB0D0BD22F827F3FFC1AE9DC3FBD +:10827000EBEAE83C49D0F99FE8174ECB8AE0173289 +:1082800017B7FF21BA582622DF7C1F303294AFF691 +:10829000E86A5ACBF1AEC12B0246CDBE26A27D05BF +:1082A0007E99FEDFE1978AD2FAF35670FD7CEB8B64 +:1082B0002B8D83001F454CE43F86AE717543FD0254 +:1082C000BF0FA61E293F725815B0EFFA2365308FF5 +:1082D000318FB7D5FBB07E78717C5B3E054309AD2D +:1082E000BD77FD90230FD1BCEB38BE3D4D4677AF37 +:1082F00030B800E0D830B84807AFE3EDD18ED8A948 +:108300001F3F974FE85FE987B0D69F9003D632A210 +:1083100003FA8B9B143BE6436E2DFE9B19E95351E8 +:10832000DA742015D6FBF8FAE195B61EF01CF5209C +:10833000CCF7B9F5156B7C46F17E27CA8FD18FA596 +:108340005E71A940A779458A3F2BF3523C3E9725A1 +:10835000DB33FC31CAEF3373C1B5BD8FF24BEF672E +:10836000D1FB01CB358C7F733173F923E8C957B545 +:10837000761701D6FA07DC4DACE771B8BEFD3621A1 +:108380006F4183613E037C35AE9FB606F365C3192A +:10839000E78FBDEB3D95980F2342EBD67BB9F9FEF5 +:1083A000214B8EEFF0C721BF1FB81CBE5EBEE47D1F +:1083B000C11F5532BFC41BDDFBBE8779C427297698 +:1083C000F46B17B8A31E42FFBDA254E3EFBB2A5DB6 +:1083D000C5B0BE2826E5FF42FC3DAF12F97B01D3B4 +:1083E000DA2F588376C96D686BCFF97D87D2F67E18 +:1083F0001EF00FA5E2E0FD13EBE7AFF1D9881E54A4 +:108400004F70B7CBF07BBD0E2ED6C987E06F924F71 +:10841000D4DB809F9C087AE33F059DBF55D864D488 +:108420007BC112EEEF05B378D9259BFB77866CDE16 +:108430002E3A5BD0393A0C0F69213AC34F00E388DA +:10844000B075139E6E49D2D6FD70E55858573081ED +:10845000F552804F92B21F58B33C8C4F3A653F5C47 +:10846000897808F5F7E011D4FBB7083C75C97EE8B8 +:10847000888FEB3305E56E3E3104F0C126C5A7C2F7 +:108480003AE7231F4458E7E94BE5C6A77BDF65BA07 +:10849000CCFB5F5FCA872EDDFBCC94742DEF0B3ACB +:1084A0008DD5D1B15C47C7321D3C5583FD923ED37B +:1084B000F4DCF486352B3A2561BE51413381FADA7A +:1084C000ACF465ACCF734F56DA0621BF3A4CA9A085 +:1084D000F3FB3FB7F6881578B912F519F1EFEFD62F +:1084E000B8801F27A2BC13FC54A5AB0FF24FCD8A56 +:1084F00064683FE8B9DFAFB142D35B97AF31A14FBA +:1085000033F4B9A7D718817EB714FCF900F667AC2D +:10851000FDB72363332FC3AF75BA75ACD3C13E5DCE +:10852000FB27AEA0DF97EBDE5FA2AB7F4807AFD59E +:10853000C1ABE4F7A7CD54484EA601FD1071579288 +:108540009B89D96D79A4367BA6D8C84F92F87ECC8A +:10855000320EDFF6DCCB95ABF2C3E0EC3F5786F38F +:10856000B189F19F2949CC87F6C3D48E3E1B93DD98 +:108570000E1FE5E9ED1DAFFF0C7F4DA17D16C92E45 +:10858000EF5565B851D5E6BDF3C83D367CA8C13B73 +:108590002AD11F6F77DF83BD5189FB1E631E15B083 +:1085A0006F5B25EA3D6D9D5AFB113FFDACE278778C +:1085B000676FABDC80FB2A25811CCCD74F4DE025B3 +:1085C000D81915ED58B5C8778CD8A9BAD1CE4C8D2D +:1085D0000EE42CCA0F5B27ABCFC57536DEA7127D24 +:1085E0007CCB783C329D39CD98AF688C8F5FFC0294 +:1085F000B4DF7B9FBA18EDDAA78B133BE1FCF7657C +:1086000073BF6D6F7CD74E7702DC18738719F3B593 +:108610008DF70FA7728FEA5AD9027CBCE6B9836442 +:10862000E71B63E2093F0F67EFABAC05B9A8CB7658 +:10863000D0FB9E047BA706F457579B18E6ABC1916D +:108640007A86F8E6614BDFD5308F69B5D7D1FED198 +:10865000F47FAD1C9102EDA6AF30D1BE02FCF4C692 +:10866000797B560F3763FDCCE5A2F48DA472F7DF5A +:108670005F7FBB37B46F794075AE87C6BB5AB3E234 +:10868000A6C3BC4E45713DFC7973B7389C678F6EAD +:108690009E75D9C8AF71B1D10A1A0FBB236E02F40F +:1086A0009B9BE37A3ABB63A8FDEEBFABB40FB6BDAC +:1086B000797A27CC3FFD41E8EF5DADD33B4D0FB359 +:1086C000F7B3BE35129E779B1DF7A07FB93B3A5D8D +:1086D000C1BC0CE03911F3B633857F0DFCB2F8F55F +:1086E0000876FF896C95F072DAB2989D02266E7C4E +:1086F000B06331CE537B4FDB7F33A539FA85FBD195 +:108700001BBA96BC8EEB08F1D96747906FC88F06ED +:1087100078D7739FACF1A12DDC0BFE3FCE23C9357A +:1087200002EBD99244BE0F9A5C9F1B9E8F08F9A959 +:108730004B853EE0ED4EF862296E3DF152941FE309 +:108740009913BE4F62C3F3EF9A9CCC8E8BF5A13187 +:10875000FE2A36D68878FDD4E8FDF257B86FF8B413 +:1087600089F4E8ACA73B2E69417D00F4C47C907E7F +:10877000DCE46E261AB7FDFDC1E6CAB2B430396139 +:10878000CD95AEFCF6E5E4D873DF546EB0B52F2777 +:10879000B385DF3EE269931BF97C7661AC11F7E9A2 +:1087A0004A9EDEFF3CF2E3EC8551FD2C30F1D94FBF +:1087B0005B88BE4DB1B13E3BEE23C6C51A3B40F9C6 +:1087C000ADD0234DB55114A7A89DCCA4F7D4958561 +:1087D0000EC44FA9CA8C56B02B6A9CD3E1E6F07246 +:1087E000CC1BAE882D72207D3B76E3F2D0561F3F26 +:1087F00079B4D23BB46F7676F1E34F0E84F97DCD38 +:10880000FC930666FEF7F7D1AA993B1EF38FFF5340 +:10881000FB68E66EFA7DB4FCF89B91FD16AB346FF5 +:108820007569941FF1A966703B319229B48FC6EC2B +:10883000B0FE5EA17D34F5D7FD093FA7BDC057DD71 +:10884000012F71566AAFFE5AF55B60DCD2449E6F11 +:10885000559FAC64B8AF0678F5D9011E995443FB17 +:108860006B4B859E99A630773DC9BF3303E3E4592E +:108870004F47111D673F33E7C3DF1520DD2A92C242 +:10888000E52953F01FF4C7AC09A17EBEAAFD4D0631 +:10889000CEA7F4DF20BEC4B853F53C790BE9CD1860 +:1088A000DA6F63F6A6870722BFD4C6F4C53CF9EC9D +:1088B000A75332B2F243EFCF5E7A5F2E7F1FE2D62C +:1088C00038D45B51B49E799B2CC42FD31E505D6469 +:1088D00027D3CD64273F5F1E45F0BCB42292B76911 +:1088E00006BEFF063E6132E9778E7236CFC65CAFB8 +:1088F000DB50DF3F1454397D7C826E66A44F71B724 +:108900004492CB3B10C760BFA622BF75A4FE781E61 +:108910006A9742FB4D8CD538500F4C3528A4EFF4A4 +:108920007259D18DFBAFD3329CB7E37BF31FB138C3 +:108930009766F239A8DA7C206E9A6F08CEC27D481D +:10894000B6C542F98D6A5847541C3FF7F01ACCBFA0 +:10895000DAC88C66CC4F39B85ED3E653EDA81C89D3 +:10896000FC0AF5C78C503F3F96EBE5F91D78DE8792 +:10897000C55AFDCF878F8773CEE6EF39E250DE060A +:1089800011BFA0FC1BA0FE6F8CD797C615399AF2B9 +:1089900069FF7E15E64B703E3D7A878D0B704A6FFE +:1089A000E4C785C6AC58A443E2A4C938DECB2AE9A3 +:1089B0002710AA478AD00F7C59ED8FF1ECB407F647 +:1089C0008E588BF0AB7DED388569AFBC4F76EA2EC3 +:1089D000C1674DE8FFA3DD02F85528EFEDC6F5832A +:1089E00047E5F99C7BBB29D2BE9F563FFF0113D1BF +:1089F00063FE0ACE0FF36BFF42FDCE8F0D76427AF7 +:108A0000CCDF6C1A807CFD2F62DED36BD38B8F01A1 +:108A10007F4C37C5DB157834CF576146785E9D4271 +:108A2000B036DEFC073EE864C8E7FD6169117C14DE +:108A3000EAB76306DAB56F5E4ACC981646F76F96CA +:108A40006F8DC37DED5351811C3BE663164639D7CC +:108A5000939C727A7CB33C673DE66B66DA83B1B86F +:108A60001F3EF39EEC04B4779FDA0366ACFFB43E7E +:108A7000D380B0CB6E2F46D865EC43F037E29C0A2A +:108A8000FD009D16289C6FE6BDB4D79C05E33D27ED +:108A9000F8ECDB97DFCFC5BCC1FC8C602EDA61E05F +:108AA000ABDC54A4CB1F15F21716BCA4BAA27A876C +:108AB000F86A01F215C8FF5CC1570B366DFD25CA77 +:108AC000E902E4A77E97F225C497FBE8F96BCF8E05 +:108AD00060FCFD7DC8779ADD0778B909F36B660104 +:108AE000C338086F10FA1AEACB78BD2F9FEC096BD8 +:108AF00032A35F5CAD727F01E42919FD89EA069318 +:108B0000AF294C3F2EC0FAFC507D7B7CB3BF9BD875 +:108B10002FABB5905DDA2FF0D2F4C0E638E48B6F5E +:108B20005FDE7B6030C659AF2976D4FB97C8A1C001 +:108B30005B35E2298ED649FE5135E2252E84A736D3 +:108B400079137C51CD381E34BC541B059EB47AF188 +:108B5000FE01C187F398C0EBA6EE5CDE857C03C7FF +:108B6000901DD1D6E74990CF0FFC20F8FEA858E71A +:108B70003CE01B673EF197CB3C40C4FF50F5EDABAA +:108B8000CF52FE48A3A736EFF81C87A6A75D1D129B +:108B900042746E32B0AA48F9EAAF85DC996C5CAFDA +:108BA0009CAC4DBD7D31E06FEE4BAA939087B157E1 +:108BB000D8B81643532CF9A7BF56EDB8AED23F55DF +:108BC0008EC6756B7C67DAA8181B709F907520FCA9 +:108BD0006BF32BEDEC1EDD81F35D00E7A3CDF3A479 +:108BE00012207AF95E55ECDCDF6D32631E5193532F +:108BF000FD7C7F10F355E394C14A1F9C8FD381F213 +:108C0000CDC00ED27C6CC7EEA3F17C27EECBEC1D61 +:108C10001AE7535FAC11DB7DCAB81ED0F8F2A4C8C6 +:108C20004B9C5CB195FC616D9CD81CCE5761E37880 +:108C300016275D3A8ED6DE94C3E7A5C9C5C104CE1A +:108C4000FFA5CBFF42ED343D8B3F988FD3F0A9E1D8 +:108C50002D4C2E25FC68F2A5C99346D77F54AED87B +:108C6000928EE4B7DE2FD64D32D2296417903FD1D1 +:108C7000DE59CCFC1C5C98DD24BF6664DA77664F55 +:108C800084E71A9EF4CF4371953D03F13FD2964C91 +:108C9000FBE56C79F2BE6E61FED929CC7BA13E7DED +:108CA00051F5933E65209561F65CF3DB6A178EB44F +:108CB0000F43FE7A49A173479AFD869F87DAF8141D +:108CC000FAAB2A58988BFEC4EA9C2C1ABF3AC97595 +:108CD00016DF9F77263822CE118A5F869E0FA8F175 +:108CE000981FDC9429C50FF39AF7919CCF67C19523 +:108CF00018EF4E7BE0FD8A8148FF174D747E616658 +:108D00005D26D9BFB31B66F4C7D076DA8A1C82E72A +:108D10003C7F27871FE07EDDB415852F607EFE54E3 +:108D2000946B04F279CB1AC58EF1D790E70B97DCE0 +:108D30000AF54362BB76C0F99ED870AA6230C611AC +:108D40008B55921BD786C72761BDAB4175E2126771 +:108D500032FB925B91CF8DF12477DAB9C66526CECE +:108D60006F77E670BD715B0ED71BB709FE2D5DB640 +:108D70002C17CF15B43C0B760AF7D7CD8EFA00C668 +:108D8000813B3B3BD7C338D510B626033F9D51B836 +:108D90003F5E656656E4AF43A6E0BD38FF43F7C6C5 +:108DA000F6ADC509A81707A07CB844DC0571148D81 +:108DB000ABE14B1B7FA61857EB477BEF20FA5568BA +:108DC00047C47CCF2E7F7112FA0B6737E624B03090 +:108DD000BC9FC57501BEE7807E7C2D423CB8304704 +:108DE000CB4FF8A9AC1279C443A6BA34DCCF05BF87 +:108DF000FE74B87FFED5B35156E44BF0EBE5E726A1 +:108E00006E57C09F979E83FC48705BBCA74E8DF742 +:108E100044D0475AA9F7F797E7D822FAFB9AFC5DA6 +:108E2000A2D7847FDF9677E9766DE7BA9ABD4018BE +:108E300010886274CEE0FDB2989F5EC7F397B3EAE4 +:108E40002C760BE0F734CA17EE0B6E56B9BF68E507 +:108E5000F2767A675F3FE615661D67CE00C0B38E77 +:108E6000AA4E07B4DFB7E67E3ADF71E73A8575565A +:108E7000C2E2AE27D64C42713BE7F4AC4C81F6E738 +:108E800036F2F328506DD3C55B07521CEDC75BFF6C +:108E9000AC384BCB3FE9F1BF2907E2AD18F8C5C9A3 +:108EA0009C32FE79DCBE1BD8A8A8DFA5F86FF67A45 +:108EB00028AEFAABB78ACA41F5CF96A6C23AFEA64B +:108EC0009C7C6408CA516C3CE54F9ABD35B439F8B6 +:108ED000D786FE17C7019EB6DBE2EDA83FFEEA5D2E +:108EE0004CCFDBF846F0E9D04D8D6A2AA3F63B86DD +:108EF00040FB5DB678DCEE88B00FC7E9AC3F7F730E +:108F0000F7C2819DF1B9B6DEAF7FC5E9DD66C7372F +:108F1000CE88437FB5F1F7893B06219D63E2EDC81A +:108F20000AB3C5399C2FD7727D74C61AFF02E65169 +:108F3000CFAC9BD809E3C33B4D2D6627F4EBDC593E +:108F40001987F9822F8C4D71762CA17D00E761F491 +:108F5000ABA807079733DA1F1C1C303247266DDD9C +:108F600013FF0C6A36FA316EFE06F70DD18E5F8C58 +:108F7000E6FBF7623FF0CE6D3CCFD6965711F985F0 +:108F80002162BD1D7213B47D207A5E5AC49F7FB5E5 +:108F9000EEF571D8DFD90D263BCEF7AF1B4CD4FFD1 +:108FA0005C88EF0DC08F6736F2F3027377409C9CAC +:108FB000897A4421FE9D0BFC6B45FE5B687299E348 +:108FC0002FE5CBD28D3CBE9E5BAF50BCADF1E75CD4 +:108FD000977F04E15DF0A915FEFD0CA6A303AB5F2E +:108FE00089F8688F5FFFD17C803537723E40CF0FA4 +:108FF0001ADE34BE08F12923FED4E89F50DF7758EB +:109000002ABDE0237CFA4A581EFA0BCBCC2C0FCF9A +:1090100043F90CD14E94FB1FA2E27A631E6AB1950C +:1090200097BF8C8E5B8FE50F51197E9CF70F06FB67 +:109030007E8CB3BCB999C4B7BF541D26057E9D98DC +:10904000D4544666A0D4E032A01D5C66213DA2D770 +:109050004339B9220F98CBA81C96CBCF899B580DCA +:10906000F9175A09FE403AFA2F95310917F0287975 +:10907000BF173A4FC4FDDECA2109F76683E739F806 +:1090800085F48946E0F3CAFE099BB3002ECE4DE37A +:10909000709F844213C0B5B51913CBA0FD2DB92E16 +:1090A000676ED8385ABFF0BC3F3E1F99E219908BCB +:1090B000F6DF6C5B8576E06F4ACB02831A6A7F44E9 +:1090C000619F6E574270938965A0BF3DAC6DFE9164 +:1090D000CB55B9AE1B72233C9FCED80ACC4B4CF774 +:1090E000BD794C217DC6DC56A0E778C17FD3ADB6F3 +:1090F00000E9B955A6E636FEC8423D156F44BA8F61 +:1091000013641F6F0C34E2FB3DD872FB9756721547 +:10911000D7FD9CD8BEFE0741655F6AFDC1FAFE66B9 +:1091200082F5025D1517D01A444C01244F057DA726 +:10913000EC78F347EC77998F3545111DA6DA910F3E +:1091400015E631FC0CE5FC18E08B3E58023F40BBB5 +:10915000459BBFDD87623147F3B33C45E42FDE63B7 +:10916000E7EB619EC1C4AFF70A7EFDCACB6A3055FA +:10917000343E188CC3A3B0CDE302B9A81FCA554F23 +:1091800015D2E1AB75CBD21601FF7CFB9AC539161F +:10919000DA9FF1BF1E8776759EF0F7D945357003CB +:1091A000D41FCCECB17E75187F2DCCE576BF39335A +:1091B00090711FEA994C1EAFB28B7B33EE83F6E5BC +:1091C00059A30A5713165C77E786ED4F8E33463E58 +:1091D000BF31298DFBEB6C03B7C71623F3C52650AF +:1091E000C9E2004FA3602E45782E156095F6F3FD79 +:1091F000D41EDBC5A15FE39891CCF77B981BF59655 +:10920000465F8D6E97D013A68C7EBDC1CA4CB8DE6A +:109210001E6C9D1DED9346D7AF843C7E65E572388C +:109220005CB5919E5AB499E7F516295CDF2EDAA950 +:10923000F0FCE625F676F34AD4C955EB66903ED3AA +:10924000F49803FE217FCDB5BBE3038E7FC0EEAE65 +:109250002BBD2A7DB65ED3677D595FE4BF2BF94BEA +:109260009A1E03F2BC98DBF11AE885288375CF16A5 +:10927000731CAE4E7518112F1DAD4ED4E78B9ECECC +:10928000263BC92EAE65E1EDD8BA44E2DF95992AB6 +:10929000D1B5A2219539E0D19C0685CEC98E6D4805 +:1092A0002438AE3585E08A3F742EC175B7ED83FE54 +:1092B000A13BC1675F78BBC0C3F33456ECDFCDB4CC +:1092C00079E4D7A3FD39678379009EDDB65594779D +:1092D00074B3B67848F9594118B806E5CE65F2710D +:1092E000FA586B49FEC5BA1609B95A7488DBEB45C2 +:1092F000C3F87EA1D1D7231EE96F3AA8323FC03709 +:109300001D520B03D07499D0E79664037384D12D5A +:10931000CA11CD1C61F4613E5710E3ADC9825FEE06 +:109320008FE27A3F262F416A37D9368BF82798315A +:10933000E220AE37D6D945EA9779B87FACF1D5248B +:1093400091371FC75A96A39DBC6932D487F5672A07 +:10935000FE8EEC86A958F6AB012FA72FC74FCD1A6A +:109360003FF5603D889F74F801F9207B7FEE28BFB0 +:109370007F025EC96F8B019E74D0C4FC50BF42E077 +:1093800005FD568C7FCEB962496E34BE0BA2DD035B +:109390003D175F24E3AD834BC65B62B98C9F8E6E35 +:1093A000191F9D276749F5299E9E527D6A553F09E1 +:1093B0004EAF192CB5EFBAB84482337DA3A5F6D9C8 +:1093C000AB2648704EDDAD52FBEE6BA74BF53DFC76 +:1093D00073A5FAEB362E92E05EF5BF96DAF7695880 +:1093E0002AD5F70DAC96EAFB1F7C4C820B834F49C4 +:1093F000ED071E5B2FD50F6AFAA3543FE4CC6B1226 +:109400003CB4E50DA9FD0DAD7B2478187B5B6A5F4C +:109410006A7D5F8287DB3F91DA8F4C3E25D58F7264 +:109420007C23D58FC9FB5E8257083FA7C2F95FD264 +:109430007B4188D8908F73D23C43BB53DEE78C11BD +:10944000E5EFD86D0A4BC4F8E7E0443BC9FD35C6EB +:1094500081C3BB8B3844F0F10566BB1DCFB35F49B8 +:109460002F66A33F51887C3E96EE559DABE7F90EE3 +:10947000BD5DD7FCB97830CBC6B0713BB8AC10D06D +:1094800087E0C472BB047774274BED3B4F7648F5F9 +:10949000299E3CA93EB5CA29C1E9354552FBAE8B90 +:1094A0005D129CE92B97DA67AF724B704EDD64A9B1 +:1094B0007DF7B51EA9BE87BF4AAABF6E638D04F7AC +:1094C000AA5F2CB5EFD3E093EAFB065649F5FD0FF2 +:1094D000D649706170ADD47EE031BF543FA869A316 +:1094E000543FE44CBD040F6D6990DADFD01A90E070 +:1094F00061EC90D4BED47A448287DB3F92DA8F4C01 +:109500003E29D58F729C95EAE77DE30CD0BED476D8 +:109510007EDF55F3E7C6E47D27B5332581BF8FF99C +:109520006F16EDC4F3FEEDF9F99A1F58E1FC511ADC +:10953000F70703F7CF5FEA9E25FC7FEE272EF3B9EE +:10954000E97C5E021E78053989F729C47F18624DCF +:10955000A57C6412ED5B90C974E07937F083004814 +:10956000306466621C1213F263D37EEE7FF57EECEC +:109570001B10E3A05F7DB6BBE7CF289773EB5F1DA1 +:109580008171CE1CE65B89F300BB1B8FFB58EF4655 +:10959000C9F928AD1C65053C868D7728AA2EADDF5C +:1095A00065E47794B599DAB7F52BF2550AAC6F51AB +:1095B00058FF8F40FC650439ADF3829C41A0FD98B3 +:1095C000D74EF013DE64829FF43AA85CEBCDA3F291 +:1095D00029AF93EAD7798B087EC6EB22D8EF2DA767 +:1095E00072BDD74DCF37782713FC82D743E5466F3E +:1095F00015957FF4D650FD4BDEC504BFE2F55159F9 +:10960000EF5D45CF5FF3D611BCC9BB96E02D5E3F41 +:10961000950DDE8D54BEE1ADA7FA1DDE0682777989 +:10962000030407BC0709DEE30D12BCCF7B8CE0030B +:10963000DE262A0F7ACF50F996B785EADFF1B61207 +:10964000DC2CF613BEEAAE48F7183598B132E207C3 +:10965000CDFF1D87710F324791E9AF52DCA38B3FDD +:10966000F4F4F85A8C632A01F717FD9F2EB9EB9793 +:1096700085C505DF8BF1EE8F66BE2890875A03CF34 +:109680000BD42630BA1FC6847F3E5BF0254BE27EAA +:10969000F92C31AFD9420E0A913FF3883FDFB996DA +:1096A000384B8BB7ED191E350FF933DDE0A3BC83C2 +:1096B0008DDFC3EF9FE131E7811C9DABB9F3008DD6 +:1096C0006777E6E220159640C79B319F7448A53C1A +:1096D0006C7BE3558B7B12EDD6EF3A9B86F6A8FCAC +:1096E000EF2AE5EBDF35C54EC67C4B721EC74B72C9 +:1096F0009E412A7764B83BE33CBFCAA979E16E2555 +:1097000074FF7F3C86E620E795CC61A273B8CCB5A8 +:109710001FAFDEDC040E1FC237331F9525E91E077D +:10972000BE7F0B0418087B065B3222AD473F9F9E2D +:1097300079DC7FEF996790CA8F32DC3D103FA773C9 +:109740005CD27CE2BA3AC47D9C9667705EFFB1F34E +:10975000BB2F95EC10BEB5FCC6CA61E29CD6424553 +:10976000DB07E77EA295697E22D54FBD97E77B3464 +:109770007B79BCADE4FAF05C8D89F4E65425DA8996 +:10978000FEF6B99A7BFBE07EE16D10EFE1FEA9A643 +:1097900047A7026C00782AE3E72EA61E8F253ED34A +:1097A000EB57788FE17EDF54F03F317E54BAF27C84 +:1097B000CABBEEEF4CD82F4B6AA17BABC037A3716D +:1097C000FD7307A9F4FD86770DFE5C45257E312BE0 +:1097D00030FFD949C02F11FC058D2F16887B39DA4F +:1097E00073E0B71B913E7FDD36308FF669760D72E0 +:1097F000203E9719F8BD3ADF5B2A3F9781A97C3C50 +:1098000037129FFF2CDD2F40E702E9372896EE172D +:1098100034AA6CF1AB11F4E9BD828EEF269BCAFD30 +:10982000D4AFBCAFB840D075816857B1E7503ADECD +:109830001B5C70D04471112B68CA7747385755BDEF +:10984000F8C15F740BE3F3EA8693FC3C166BCA0F16 +:109850003F87F5B0E06B8DBF5473ACE7595BF8FC04 +:10986000F8F8C0E7F7083EFF12FDFE711647FCCD81 +:10987000F06A13A02600A5E7DFEC749E4F3BD737B4 +:1098800093B9A99C0DE446BE76FBD6D0BDFAB9AC1F +:109890009E9E2F289A918170356B294B86FE6E5AB9 +:1098A00055BB3F196637B16ECD70CC734FF04FDBAF +:1098B0008F65E506E54B9F83E464058EDFA4D4AC99 +:1098C000E802E3DDFAD2B01598471EA7723AB0B7A6 +:1098D000391D809F5C6AC2A5EB03B97848C805CDE5 +:1098E0005F938BA94B994B490ADD03699393A2BB04 +:1098F0003E4BC53D16630B9D43A9DE6549C0FCC9BF +:109900005CC6ED76280FC4EDB526075F9B38DDBF3A +:109910007E59A17B365F2B8CBEE7D09EDFA0F99FDE +:10992000207F5CEE3E8DE1FCAF8ABC5E8627B95F8E +:1099300076C83E7F6DF00F88CB26FBBD11D7632A1A +:10994000F13CD417CFEBBDA23897C15CBEEEE0CF9F +:10995000E0E704DAEC00FB392694277CC4C4F376F4 +:109960007A7F575B477BF3B498990FF7B394A203C0 +:109970003FA21F72E97C3DC903002FCB904498970A +:109980002C713B22CD63B918FFE04F3C1EF7A53385 +:109990003A17A4C7A762E7E3B4975FB544F3F96841 +:1099A000764A9BE7A5F3E2F47A3F2F93E8AACD0F1E +:1099B00034459E1DC6371AA39D28AF9546CF7B8898 +:1099C0004F2DFFA6C5C50733BF227BC02E2E4BE30C +:1099D000E78F03EDD9E1E6B6783C2B6427B53C165A +:1099E0002B8E9C8F745BEDA4BF263027D98B1EEC89 +:1099F000B8862FCA63A9B84348795E0FADC382FA0F +:109A00001ACA28CCA390BDF4937CC6E0BC685D4123 +:109A1000CC88B03531718487C1C718E9E9C1B8066F +:109A200058EFCE93CC8FE7A91A2F4C2A8D85FA9D3B +:109A3000DF1A290EFA6DCC2BA9F81D899D673F4CC2 +:109A4000C57C4FED852D040F681E7196E7CF8E4FB4 +:109A5000C1FEB69F373B2CE4072C243C6879CAED45 +:109A60008C39711FB4E8231BDD332E3C5A1F437819 +:109A70001379B562B1EEE2F33C1FB20B81411007DE +:109A8000B4985920CC5F36D965B88885C1993824F7 +:109A9000C061798E6B8D1F637B883CC84036303C3B +:109AA000AFC65A1322DEA7D2EF2316287CDE67F258 +:109AB000DC9D7A50FE6C82CAF1FD7715F17583CD7D +:109AC0009F82FE6DE39C1752D0DFFD6DCCDF098FC6 +:109AD0004FFD644E41BCD60DFB0FB22375F06E10E6 +:109AE000E35FA33F8A51FE6B3EE5D76E1076F6A981 +:109AF0008B9FB364C0675D1123FBC9841DD6EAEB5D +:109B00002E9EAB427A5E28B63A502FE48A7C68EDEE +:109B1000F5FF99DC14868F9DE0570780C0DBC1AF4D +:109B20000E80EFBF0DFC6A84F1DE29969BC1AFC6A3 +:109B3000D20F7E3596CF805F8DEDD0AFC6F229F083 +:109B4000ABB15C0B7E35964F825F8DED9E00BF1AE8 +:109B5000CBC7C0AFC6E77517A797D27C8E31BA5F67 +:109B6000BF3426CE80FA15E61F8D79A1C3AE7ED113 +:109B7000888FEBCF1B24FA1637474BF0E0D309212F +:109B8000FA22FD8F7791EA071CCD92EA337D3D25BD +:109B9000B8EBE27E128CF9A1F0F753AB4A2438C53A +:109BA000335A6ADF79F20409EEE8BE556A9F583EDF +:109BB0005DAA7F344E4747FF3C834C47FE7D850BB3 +:109BC000C5363A5FD91E9F3E26E8A2C18FFF4A9D47 +:109BD0001C296F7B570F83140F741173BBBB8783D2 +:109BE0009EEF3B31F0C5DC02A487816F9BBA5A62BD +:109BF000BA015D721F37303C5748270E607E76F100 +:109C0000DEE325E762902FF75698A3903EBB5D25D3 +:109C1000D1082FAD30A784F3515DA6A71FDD53F007 +:109C2000F0F569EF3F5A32E1B2FBE88F21FF75BFD3 +:109C30004CFDE8B959280F97E09155D17E6D088FFA +:109C400013E8FB4ECC5325CD5F2F170C37E953702B +:109C50005CAB8C4F57D6038887A79E30D239ACB601 +:109C6000FEC4FB5A7FC3D58B314DF997CE7FB78B9E +:109C7000B707FF370AF1026349F34B703A86217E3A +:109C80007E27E4ED5F85BCFD56D015E35884999D91 +:109C9000BFA7D1ADAEEAB151B92837457C5EEB6FB5 +:109CA0007C4C417593C89CB5F630BC3E21E6F18CE6 +:109CB00058D73AEC17E08E37BA14C45FC662B78241 +:109CC000F2D6754913C14F09F94EAB69A1E7E9F71F +:109CD00004A8EC5215A4FAE1EA4BB48E363C386580 +:109CE0003CEAE9E417EBD1FA0DBDFFDA21E4B70B4A +:109CF0002E3EFF389FCD85F622CE6777F2D2214ADD +:109D0000A713F57E9CCF25E09A7C84B78975C5F9A9 +:109D10007C04FBC5BAEAAA920EBDE0088DC71CD52B +:109D200086707BD31E3F6D15F8DF2CF0A47F6F9BF0 +:109D3000A9A6BF3D825C69A5664F8B8E1B747A27EE +:109D40005A92FB43F80BB7037FE981F2E873AB62E9 +:109D5000FF8AF038B12D5E9A4AFCB426E6F6B73198 +:109D6000DEBEF1A8CAB8BD1DB71FF5E5FBA32C6484 +:109D70004F1B478D4C0FE7BB06B18EAD02EF837CC6 +:109D8000AE13F740FB316E0BE5E3073257FABDD057 +:109D9000DFE8B1AA3300FD1D6DB327EE187EDE812A +:109DA000DB9309620D7BC64E7C10C77FFF28E80558 +:109DB00047689E5AFDE6F289637A211D839C8EEDE9 +:109DC000E1E74D41AFFD625E7B05BD1A057FEF16F1 +:109DD000F664A7B027DBD19E5890CE45623DDC9E4D +:109DE0006C16F62488F604CA77853D7907ED099448 +:109DF00005A3B2CB486FE22536B22710A0D07982F6 +:109E000005D2BAB47995A7A912BD4624C548F42A4B +:109E1000B3254AF525C65409765DCC92E0EBCFF721 +:109E2000D4D929D9AE0C3E3D5867A74A2478C0D171 +:109E3000D1D2FB95AE8952FDF8A229527D85738659 +:109E400054CFC47E18DFA283327A9D4A71AED87790 +:109E5000D2FCA9F7CB55DAB719F481EA0C97DB42AB +:109E6000D6B64F66C07D32705F1C46ADBF2CA99E32 +:109E7000FCA8A326772A9EDFABAD043E84B2F82867 +:109E8000F869947C04BE06BFB7D03D92FC40F097C1 +:109E9000FA131D5AF87E93B66F3548B7FF343A5F10 +:109EA000DE9F2ABCC2FE94AB673B7E59B7C4ABF2BF +:109EB000CB40BEC8FFFA6DCCED7B916FB67D047EC2 +:109EC0002AFAB91FFD82FC2FCD6FDBFAC52FC8BF60 +:109ED000DDDA262F1E495E0A85DC6E399AD5D0045C +:109EE000F2B63959710A5493BC1469F2D224F4665B +:109EF00079353D1F20DEDB6A72C7A0FFB7F9D85263 +:109F0000D16F981E217F3D4C8F601CC912E4FAE48A +:109F1000D4507D162756787BC67AEAFAEBA78307DA +:109F2000EBDA97E8E0D1BAF61374F0ADBAF6D3A540 +:109F3000FA0658F7E5FCEDCD423F68ED0A8D6ED587 +:109F40001941DF0E382AEB57E6AE96CE3D349E9887 +:109F5000457A73CBF195028F55127DF668E31C05A7 +:109F60003CE75FFA7E89D117D31BF8A0E498D1595A +:109F7000EB08D14FA313C37838ACBF52AB2AC95FEB +:109F8000C3314EDFF6D6B94BE8E71DC2CEBCA1F314 +:109F9000DFD49FCEBF3F1EF8674B9381E2AB2D47C6 +:109FA0002724627FBB2FCEA4F9361C33D03DB217D5 +:109FB0007B8EBFA9B65B687EDA7C0A3F581A83FBAA +:109FC000AC179A0CA4FF0A4DEE447B04BCEBF9AB32 +:109FD000BD7E35BE05072A11F1B21BEC109D1B1684 +:109FE000FA54C3CB9E134F12DEB71D5B948878BF23 +:109FF000A1D520E165688BECAF0F399320C1034FE9 +:10A00000727F10ECAE84DF2BCD5B2F17B83322C3E9 +:10A010005DE4F657E90F6C1774DA26E8B43DCA39E7 +:10A0200039D2BEC6B64FCD55E1DF5538D393E7DB05 +:10A03000CEF4E4F9AFCD4047D4B3174E1B48CF0E52 +:10A04000B1D7AB3511E851DC6CD0D909D96FB8D68E +:10A0500078F5543B7AB1BDF735BD58A27D3F2578E0 +:10A0600063C4F3B1213A8873953A7C6A7EF495E92A +:10A07000A69D47D7D1AF9DF743FDF8F4F134BB0E51 +:10A08000FB69AA247BB326E65DA1CFDF257DFEDE3A +:10A090008F429FFFD889FCA423A33AA7A31C1D6964 +:10A0A000D3E32C365C8F6BE72183CDEFC584FBF9BE +:10A0B0006EC18F3B5DEF8FE983F4ECA6FEAFFA3BF8 +:10A0C000EF0A7FE71DF477BAE33E10F7770EB96623 +:10A0D000707F2759A1EFC52C8DB9DEE889C0A7FF95 +:10A0E000D7FD9CF145B29F53E194FD1C6DFF60B715 +:10A0F0005DA1735863F264BF6737FE827926ABE2D5 +:10A10000C77B5CDB5D132FAB870342BE0F09FABC34 +:10A1100029F4F07E1137EC40FC135DCA055D78BE72 +:10A12000A2F8BCD3E674207DAA785C96574DF1F472 +:10A1300050CDBE7B6BA8FD910BD3CFE3FDFEDDF6CA +:10A1400018CAB3ECC6F9C0128E983CE7F1FB15BBF8 +:10A150005D8A636984B87E488BAC07343F41E3CBAA +:10A16000DDCD9F135FEE6ABDBC3DD5F497D6EE4DB5 +:10A17000F67A29E2E7FA66C6306EB892FED1DBC500 +:10A180002B8DA36F3FC458AF46B23BFA71DCAD01D3 +:10A1900015CF3FEF6C0926E2769D3B7048C57BE00A +:10A1A000C52D019AEF3E97625733A95D299E8B7E9C +:10A1B000F3E27B63F0F9AEF3468385F699EC24B7BE +:10A1C000C5423EDFB968B03909BF2AED73045A3E73 +:10A1D0007F10E5D56755E9BEC8EE8BFD92C2F1F65A +:10A1E000E8752AE993ED651603E697B79F378AF37A +:10A1F000D601F21F76B466D9B0DCEE02F9217D11EA +:10A2000024FCFFFE3A7E4E7527F4C7F58483E6A151 +:10A21000F141E0BCA13CD2F7767E2FC61B72F1B3B0 +:10A2200018C4CF81F37B62505FED6AE1E30C59D231 +:10A23000148371E6DBAD86589E57E99F84CF1B8758 +:10A24000DF6FEB87EB6A31F0FD1BE1D768E3ED2EA2 +:10A250009B4DF9FCDD2D3C0EDB7D9EE78FB6FBF9B7 +:10A26000B93526F498D67EFBF909637A61FEC06F92 +:10A27000A2F643987F651CB4DBDF71EB7574BEC634 +:10A28000378F85EBBD52BBECE794B4E8EC93671EC7 +:10A29000C981468723DF4DB8B192CED7733D39CA05 +:10A2A00028EB975DE797264DC0F16D7C7CE6E7EFE4 +:10A2B0006BF119FE18C3BEBB523BFCE68915D8DF13 +:10A2C000667ECE6C884DD6674786CDF8FD7C3CFF18 +:10A2D000BF2986ECEC765C3FF67F9451FE6C77F9F3 +:10A2E000E3A57198B76E664EEEC7C97ABDF4C2A6F3 +:10A2F000BD71D0FEBD0D0AE177649EBCDE9DAEEC63 +:10A3000087310EBED0CCF1ABE59334B9DCD39C7071 +:10A310001BE9A732781BF0F85EF9EB94C79EE39730 +:10A32000FB19B831469AF7FCA6045DFC26E7C7C1C5 +:10A33000DFD4F203B68A01A1F8ADB095E7D707FEE6 +:10A3400034A17F00E65B5CC6CFCFEBF3E2A38C16B3 +:10A35000D9CFD2E5C50BF57971BD3D17FED800B157 +:10A36000AF7189FF23EC9C966FD8660A4C715F83AE +:10A37000FF30C808A10B9DEBF5241600FEDF10FE90 +:10A38000E52073DDDD29202A5B55DF1016E6173046 +:10A39000BB8F250D08C5B7834FCBF140D171992FE5 +:10A3A000217EFC12E3C955B8A74972E0E379D0AB2E +:10A3B000F433D6C4F46E6802BA0E3CCAC47EC7BF7A +:10A3C000EC45BE6AF842DBCF00D7A313EECF33F2E1 +:10A3D000B71BBF3013DF6D19CEED94E6A768FB34D1 +:10A3E00037B2A6E5A50A9ECBB6AE68027C6E3A32BD +:10A3F0002B7501F4FFC1C7B4DDC9B6146ADFA7AF7E +:10A4000093E2CB815A1EEAB8C1975880FEBA4592B2 +:10A410006BADBEE1F8D218FCBEC885A081F8B4F1DE +:10A420002333C3BF0FD0B0C342FB390DC7CCB4DF59 +:10A43000B26D0797132DEFACF9F96F097D7E50F8D7 +:10A44000BD0784DFB24FF82D7B84DF12107ECB2E48 +:10A45000E1B7EC107ECB1BC26E6E3A2EE46F498CD6 +:10A460009F7FC796E765B579DED1BDE98411165C9B +:10A47000FDF180B50186F65C9693510E594E462645 +:10A48000CBFA63B83D556A5F6ACD96EA87B1EBA413 +:10A49000FA1B5AFBE9E291C1BA78A444E78F8C9188 +:10A4A000E5F26858BC4BF1B51CEFDE141EEF6622D6 +:10A4B0009D781CB8ADE931A2E3B6D359F1E17ED95C +:10A4C0001B426EB69DE6F6F98D33E76223F96D67A0 +:10A4D000043DBE16F468167ECA4D29AEDBF30B317F +:10A4E000AE3867C6731FEDF1B3F6BEF6DE19FFA9ED +:10A4F000B870FBF705058D21F8DB2D9FE452FEE4D3 +:10A500002AE563592C3FE7B65989A6FBF757BAD716 +:10A51000F29BFC2CB10F51D387EF8BD60CC4F20504 +:10A52000933B15EF3F6D56DC53508FFB7E678EF8E3 +:10A53000F72496E72B9AF037A07DE04792E1E725D4 +:10A54000C588FC1525C067996739E2C78AF13A3496 +:10A55000526D6E86EBDA64620D68E7998B39EC9D7B +:10A5600018172118E7875E9ED5F9302F25C8F78F79 +:10A57000C1BCD2F73EF068167E770B4BDC27B35890 +:10A58000F9BD83E87C4F5D7E21FF9E6D7C3FECB77B +:10A59000249BEFA306487F4F11FD1A6276A4933DDA +:10A5A0006D4FAFEAE25C364FBE8FA2E79706A16718 +:10A5B000DFC8744F89F41D8C3F0AFC6CFB6A9C8ACF +:10A5C000E31658E35CFCBB902E15EF81BDF1F5E876 +:10A5D000986911F86C7FEF697FCC0FE38382608DFF +:10A5E0002AFE4E8541CE6F190248EF0B3633C9F56E +:10A5F000605C70C2A5FD0D3923FB79839AE4F83FB6 +:10A60000B4BF5FA7E079B3367E428220FD8FF0EFC2 +:10A61000695C899FF4FBF6C7F3B5F3929E4FF01C7B +:10A62000B11A6FA3F3359B8E58D7A31FA9CFF71D7F +:10A63000FE80EB71FDFC1B3F98948AFED7E6A137A4 +:10A64000A7A21C6F41054FDFEF5938C925C1B07E65 +:10A650001BEA7B26BEB355CDEB476970CD243C3F4A +:10A66000B365186FFF49FE9127F17B605B6E13F5B0 +:10A67000BE4778BD06B3459386216C32103CA917BE +:10A68000B487FE7EEAE93A8EFC199DEF3A81E59F98 +:10A690005076A01CD1D3F519C2C791C760DD477BA6 +:10A6A000B84E86C3893D5CA7C2E1CD6DF6A5C5163F +:10A6B000BE7FACF1E1E1631384DDE1741FAFC5350A +:10A6C000C55797E7FF77C1A76F0B7D7548D88F37C0 +:10A6D00085FDD88FF683E2616E3F1AC5BEF16E61CB +:10A6E0003F768AB8371477B9857F3159C4C33C0E99 +:10A6F0002B185ACAE35EBB96E7CF30468A87C61549 +:10A70000C87EE2D87CD9AE8CEE9628F169795AAA37 +:10A710002E4ECED6C5C9B25D2931F6D7C5C98375CF +:10A7200071B21CF716378FD6C5C913A4F6C7F31D2F +:10A7300044D7A2E3B7EAE2E5E952BB101DE57D9BF1 +:10A7400010BD6644A4E396E2190FFEDFA263E4FDA8 +:10A750009AFFFFE8F80FCAA3CD20EDDFE8CB77849E +:10A76000FD7F4BD88D83C20F3820F21CFB843FB78E +:10A7700007E9D81DFD3AA7F0EBF8390E2D0FF28648 +:10A78000C8433588731C5BC4BEDB2691875A56FCD0 +:10A790003D3FC77191093ABE1B918E154ED9CF1B13 +:10A7A0009327D371942351E7F7C97EDE70BBECE7A2 +:10A7B000955A653A0E63FD757E9F4CC7A12D253ACB +:10A7C000BF6FB4CE4EC9E738C02F78B45721DE4BE7 +:10A7D00090CF731406E5F31C7AFBAEDD57D4FC86EC +:10A7E000363FC12BEF336F421B8AFB452966FEBD06 +:10A7F0000DA3A70BFA1D1ABEFCBDF839C42D9FDCB2 +:10A800004EF82C447B1EC17EFFA917B7FB7FEA657B +:10A810006FBB1F19DD0FD39B3EEEFFC48FB5F373E3 +:10A82000552C88DF9FBA8CDFF4275CAFE62F19ED3B +:10A83000350CFD08D562F0E1F777996AA573778743 +:10A84000DBF1A34EF5CAD4BEBFAA60BF9F887E9538 +:10A85000E237F9B9BC5EAECDBDF05E4FA9B305F3EA +:10A86000E29B3F323B6B919FA3F87750F4FED6E119 +:10A870005EB9D49F863F3CFFFF0BB48FF8A158FA16 +:10A88000DEDEE73AFB090B867E5E88E6F091974FA5 +:10A890004DF2A585ECF527BD2E903DCDB57599817E +:10A8A000F1B2B2D697C0F72B03245F7ABFAD5DFF3C +:10A8B00057E7A79DCC7305116FDFA35D2EA47355D9 +:10A8C0002E63BFF6DF7F21DA7D17FF1E8C4BC5712B +:10A8D000353C69F58704DD0F8BFEDAF0A2F1157EB9 +:10A8E0009F2621EC1EAC6EFE1ABE561ED91BC42339 +:10A8F0008CD7BA1E6D1D11F8C77D05BFFB7BA2AFBB +:10A900008E7FD858A7B8A71BD9EF33093F329CFEDA +:10A9100083695D7E6DFD6C783FBCFFA2DD5BE7FA6D +:10A9200050BB339360AFB367821CDD7E54A5730EBA +:10A930004CEC831BDBE859ACA09D318E505862581B +:10A94000DE55BF9FA8CF1FE8CF9515377791E0EB75 +:10A95000CFCBE7CA5C177B5ED6AE94D986E8EC52C3 +:10A96000A9CE6E8DD1D9B5893ABB27E7C58DCCA8C4 +:10A970007D6748ECD72B0EFCFE8E916328BC5E7C75 +:10A980000788E37B793BF2DB767EB69783F0DE26A1 +:10A990001FEB9883D3CF27DD33516D1EA2F3A303A2 +:10A9A000343BE6A4B8D71C1844DFF3343BE5BFCFF3 +:10A9B000E0F75A3F2ECBC17B368CCA67BCF68FCBF3 +:10A9C000E83E4E32954F791DF47CAD378FCA27BDD6 +:10A9D0004E7AFE84B788CAC7BC2E2AEBBCE5543E2B +:10A9E000E47553BBD5DEC904AFF27AA8CC02F706F2 +:10A9F000FFDE40968F3961C62C7B158C1786E74C9D +:10AA00001FCC230C8F5D17DB2538BD26596A9F5A52 +:10AA1000E590EA533C79527DE7C94E09EEE82E9263 +:10AA2000DA2796BB24B883AB5C6A1FEB744B704C7F +:10AA3000DE64A97D94C323D5EFB97E707CD365E431 +:10AA4000B9CEEB3A817858ED759FE0782A3FC1F195 +:10AA50003399CAB9BD3B107DEDC67A17DA6D7BBE5E +:10AA60009DE1F976B395DFFBEE60B42B1DC2FAEFE2 +:10AA7000E082FEA4F9427F523CE7E7E789F3DC2756 +:10AA8000E4794F96DE0319243BA9F931C3D5B458B4 +:10AA90008CC71E34D9FFBD3FCCE381E12AC37B2B99 +:10AAA00047CA26525E04AF6CB2087AF40BE19FC627 +:10AAB000F4B652BC38FE0985E23B584905E61167F9 +:10AAC0001DCD7686FF3D28AD3CFC1BFEBDA1983D0B +:10AAD000DB1C98171B5F3C2D312A2CFE1B1FF8B185 +:10AAE0002C85FAEB3B200AE6317EED34F38CFCD06A +:10AAF000FAB476B39E90FDD110FFFBADC21FA775CF +:10AB00006AFA69B57D3D3D5F9D77F97D9BB3625DD6 +:10AB10005F097FED0BE1AF9D127EF749E1777F2A58 +:10AB2000FCEEE3C2EFFE58F8DDC784DFFDA1F0D7ED +:10AB30008E0A7FED3DE177AF147EF7EABCF5F4773E +:10AB4000AD2E6C54987A99F3A57337C8EBAC5A279D +:10AB5000EF1BCE7A42F6BB673E24FB6BD397CB7ECE +:10AB6000F71D8B657FEDB61AD95F9B5225EBC75B4E +:10AB70003CA5127CF364392F77935BDE37D4E8343D +:10AB8000B15CD6939664D95F6B6FBD5B03A354FC35 +:10AB90003B2448CC5361F630EC7BF0D279C702BB42 +:10ABA000AB14F76B0A997B19EEE70C3504DFC7FD90 +:10ABB00026F6A14ADF816CC0370681BC5E1830766C +:10ABC000BC23CCEEF864BC4E3D2EE7476EBD47F685 +:10ABD000832BE7C9F18CB95CF6835D69F27EEC44A6 +:10ABE0009DDD61C21E9AF9EFACCC7D793B648899FA +:10ABF00047F795AED51E9999FEFC18B747346E9667 +:10AC0000544FF628AA0F3F273140DC53A88D1AF87D +:10AC10000EEEDFEDF988DF2F00B407BBC1FBD733A1 +:10AC20008E6FB375247D3F6EA789DF1BD89D62733D +:10AC30002E85AAEB2FF2FB01ACD548E7C73C786F15 +:10AC4000240BFB95CF8F15068DD2F932B3AE3E0D96 +:10AC50006DE265E7C3CFD1FDEFCD479CE3E8C3FAD2 +:10AC6000D0F988A6C8F70DDAFC381D9F6AFAA7202C +:10AC7000C0FDA38276FDA3A9F49D31E3878CEED9B4 +:10AC80005B0C2D679EC3FB515FF23CEC3026C76D19 +:10AC9000378E95E3B6E1F6CBC76DA31C32BF8EC9E4 +:10ACA00093F5408553D60397F8354DFC1C627B7EA7 +:10ACB000CD4D7DB2B47B3A849FA89C7D317C1F939F +:10ACC000F3CF10B1CE47CD6EBABFB23C9D119D8679 +:10ACD000D8F979C55ADCB7C1F37F1FF07B2F46E660 +:10ACE0004EEC83E5E911E2FCE25827F5D7CCE955B3 +:10ACF00004FF7ECEBAF47CA2256894BEBB61646179 +:10AD0000F485FA39C85F1D437CF47F675EE2FB0877 +:10AD10001A9FD912AEB07FE793FC40AD1C1674A900 +:10AD2000B88EFD76BE8FBA3F5813C4EF447E9FCCD9 +:10AD3000F314F7A74D30F2EFB6B86CC3812E23C4DD +:10AD4000FA8BC43ED9162F0BA23FB7C96BA552DBB5 +:10AD5000FF5C99BC2811EDE6960C4F2A9E0BDCD2C5 +:10AD6000B1C372067A7AB3A9435AA47B048DA68133 +:10AD70006467B734A618D10F1D66B41BE97B52690E +:10AD8000D355CCCF8EC4FB26490833DAA7DBE40DBC +:10AD900004CBE85CA887CE11C13A4AD18F2DB34FBE +:10ADA000A3BFF7D8F801C88503FDE30E53F1BD7DBD +:10ADB0001DF9F96B8B9D9F6F1D91349BE855E0E465 +:10ADC000DFEF2B48B339FDD85D32FF8E4F15FCE322 +:10ADD00074E17602E45EFABECF40160623BD74F03D +:10ADE000D37A3DA03B97B8F298383FD71479DFE685 +:10ADF00033E1576C117987E3C2AFF858F8154784EF +:10AE00005FB15297077A5FF815FB441EE880C8E7E8 +:10AE10001D14F9BCB7845FA19DBFD6F822791573C4 +:10AE200058E2197B771AC773CA2AC55F0EEB289DB3 +:10AE3000C9E1E4C57C7FB4ABA7CE5D5280F526E7BF +:10AE4000485847F2E4BAE1B88E94A92D744F69B21C +:10AE5000C7EC7029783FE929BA17A5DD0BBB93A38E +:10AE600086DD3E7304E9DF3B3DE2DCB1DA5C48FCA1 +:10AE7000F58489BE93A47D3F6EF24CF97B4AD3756D +:10AE8000F8BD5D079B15AE47DED1E4A23FEB1F8EF8 +:10AE9000F714D136EA4E719E172F5D459097B50293 +:10AEA000EF1A5E1AAF1F1DCBD7C1F7432DA29FA388 +:10AEB000C5B7C6623F1FA4F1FE260879D0F7B75A7E +:10AEC000EB4FDCA78916F47FB4E7E5CF9D1EF63281 +:10AED000E99CE961419FB67E4B1E34E1F7B4270738 +:10AEE0001E48477909DDAB71C5F2FB2B63FF3D13AB +:10AEF000E8B45ADC43D0F4EACD427EF5E37DE0BD10 +:10AF0000FCFD9D0F4AA698F07BE837057EC5FF1E25 +:10AF1000B0B12639FCBCEF07383FD095F7DF743766 +:10AF2000FD1DC96006E707CB8D16077E67B06B9ADB +:10AF30006B05E23139CD395CE447C99EFD3FEE81B6 +:10AF4000191B0080000000001F8B0800000000009B +:10AF5000000BED7D0B7854D5B9E8DAF34E32810958 +:10AF6000049C604227E161AC04262FF260083B108C +:10AF7000344524131221981026099068D11BAA3D4C +:10AF8000D27B68B321218418799C6B3D50090EF85F +:10AF900068CFB99E1AACD7D27EEA8D8AD6DEA312CC +:10AFA0007A430B6DC5F092F66B7B2F5ED49ED3A3D4 +:10AFB0001FF7FFFFB5D6CCDE3B93800AADF634F920 +:10AFC00074B3F65E7BAD7FFD8FF53FD78E93C18F57 +:10AFD0008F314BC25E65423263CE62858D87F6A6A5 +:10AFE0009245694333185B5EDDBC98CD64EC12FE7C +:10AFF000CC83E7CCA60D65E24BCC724981FF8799E3 +:10B00000CF361BEFE31DC37376291DFFDFCA82898C +:10B01000703F78CB6F719C6AD6EAEF87FBDD79EAE7 +:10B02000040F8CCFEAEC67875C8C65C2EFA58CE8D7 +:10B030003CF25ACD6CF45C8EB76431F497E3339AEA +:10B04000CFF07C6B17F339C742E323806E22BC2F0D +:10B050009E6DB5855D385F77F05E97EA662C23D5E7 +:10B06000D2E004782AD236AF64B06E56E9F44CC30D +:10B07000F7030BDFCECD836BE65A1F2E0FFB354354 +:10B08000BFE33776A6F96644E1DABA8D9584609E0F +:10B09000AD697FE75D9B88FD3E6C0B613F3BABE993 +:10B0A00083F1BBE7FF2E35DD1DED7F7056E94CFFC8 +:10B0B0000418B01CFE97C2D8744728C33F63F87ABF +:10B0C00019D3189B80F88F670CE038D3A0849D00BB +:10B0D000574D0FE06F0C3EBFD082F71B7A9CBE6EBF +:10B0E0000490A9EEDB609D6BF93259C3B48EFC7EEF +:10B0F000B8AEED01BA61FFDDF6D3882F17FC227ED2 +:10B10000D35A6DA723F8C2FE4CD7C6794C6D07CE33 +:10B1100001F0DEE24F4C7EF726F8772ECBBD64E5DA +:10B12000F447FCD688BE710D556319D2D30BC82CD9 +:10B130001ABEAE15FF6665FDE319310CCB8FDE3FFD +:10B14000B17A4A7C08DF43BE7109BE9A453CE97377 +:10B15000CC46FA73BEAA167C05ACF912F19566D7F7 +:10B160002270C2BAD87DF628DF6518C66308EF32B0 +:10B170007D9BDE578F4D05F8570AFE5F1968E1F891 +:10B18000BA8FF3A30B6E8A71A2FC06E3044DFC4751 +:10B19000F49A28E084716E2F2BFB1F3F059C3DBE67 +:10B1A00033E336A4D3EDDFB4322BCC5705DDB05DED +:10B1B00055A384C3D05E16B899E461997E7CB85FCC +:10B1C0005D6D3FABA7CF3B1BA7D038ABCAF9386C3E +:10B1D000A36E7E826F27E133C8D8168F8EDFDE4DD7 +:10B1E000675319E0F1A53DCDFBF0FD73BB9C0CF955 +:10B1F00088E1BBB391EE1CAFC7807791FFCF6F534F +:10B20000C20700EEB37B9C04E7BB6B943043FA3378 +:10B21000CF93FD70FF017F12CD732E2EB4EF1BF084 +:10B22000BC716B825F83F5768D6BBD2708F39E4BF7 +:10B230000AD5E3388D5B6FB268D0BF2B5E7365E0D3 +:10B24000B88D56FF019862850D703A0EAEF0EFEBA7 +:10B25000E1DAD0A5A31FFC37E85788EF975858A824 +:10B26000CF3D9C7FDCD90ACD8F0877EAE05F926101 +:10B2700021788F3FE42478C764FB689C86C2383508 +:10B280006E0CD291A9B61C8027559D8C709E55409E +:10B290003E81DFCEDCAE68881F66E374715C3F6977 +:10B2A0003FCAD33F89759E7DB06032F2F39924FE88 +:10B2B000FCB4373E8CEB3AEDE36DCDEB0E3F81B243 +:10B2C000610B652E4BE4EB50800F1A055C8D3E8BB5 +:10B2D0001A07F46D7C68F95791CE8DDE9EF5783DA6 +:10B2E00096A8252AF0FEF93D5686F8467CB872F0FD +:10B2F0007971333E37E3E5037F06C183F81B0F788E +:10B300007B77777B6208D6C13C2CE49818C543C391 +:10B31000CE1FDEAFCC2479D6B8BC733951986E3FBE +:10B3200006FE5DE17368E5300E3B3C95F876858757 +:10B33000F3ADA368CB840CDECD1DE10F1FB57B7090 +:10B340007F6F14ED06E45BC0EB0A949799888F71C8 +:10B35000B3FBE17ECD6A23DF6E49DEFC6015AC7382 +:10B360004DA19D59E1F91AAFCD2037951B8C720480 +:10B37000EB36B4C767335A77D738C19F9D9C3F815E +:10B38000D32707B3A27CD1EBB748BEF0D947C1BFE2 +:10B3900019AF5F343C9C467E057D7326CDB7AF88E0 +:10B3A000F402F00F878B5975F2D0D0E524BE67C048 +:10B3B0001E8827E04F476556945F247E1A766F22D9 +:10B3C0007E6C107CD7D803FC3346C747267CE19AB5 +:10B3D0006D729E29513EA3E731F8EC453F875BCA69 +:10B3E0005F030BD633EB70B99657A27331D0B36FAE +:10B3F0005D8D16C0513492E31D25C56389DF053D7F +:10B40000B8EAA11F17D22D51D2476383B89FBBC59D +:10B4100043CF06E54419E81BABD8671DEA40B81FC7 +:10B42000EE276DB0D27DD42F36E88FD33224F8F3D7 +:10B43000054F4F87769C68BB055DAD56770AE22BBA +:10B440009119ED9E71CCA44FFC9CAE52CFEEB4B3DB +:10B4500014DC8FE3C4FEDEBC708A82FD762A0AD932 +:10B46000078E32231F584D7A605AB685D62FF1C009 +:10B4700084BE75B8F87AE3522C24171FA482425573 +:10B48000A2F87088F58FEBF7F5F5C3F37AAFCB1F11 +:10B49000463E621ED20FA53053BF6EDEEAC509AC30 +:10B4A0005F47E7859EF186F62DDEEB0DFDBFE29B43 +:10B4B00062787E6BE64D86E7B7F9730D6D07D3E9C9 +:10B4C00075847388E3DD21F0AC7B2EF5F200D2B1F8 +:10B4D0004AAC638723E40DC23E5CE55D4BFA7953C9 +:10B4E000C95DDE215887D3CBE5CF81F6248C1B378D +:10B4F0006DB587EC08A19F0BE117E9D08E83A444BA +:10B50000F9CC61C2B359FECCF6E4DA6CB07B12A080 +:10B51000F165F665B27BDCE362DA3766FB0D7484B5 +:10B5200005F9355ED06BA1D54D7A636B35D8730ABA +:10B53000DA974BB9BD94F95F88AE41D18F6916B2E5 +:10B540005B9789F54BFBEBAD36C6FA6F007CCCE719 +:10B5500076D6B2C20BD57ABB5C5EBB453FD98E2F87 +:10B56000DCAFAA31F4694736DF371302FCF9321732 +:10B57000B3A11E92CFB764737DBC4CE8ED2520C704 +:10B58000C8B71578D5D9ADBB049FEE8AF02B1BC880 +:10B59000D1CBE9538A0DF110279AFB596857F6046D +:10B5A000C4B3469DACEE2023F9FE08B03B9BEC18DB +:10B5B000FA29CD5EDDFB75F447AA13FDE85B38D5AB +:10B5C0008627BE0DF88BAF4EF05B7C517E27BF0304 +:10B5D000DAC9999CDF6B525D7E7AACA983536747C9 +:10B5E000EDB26A61DF4D60AD2407C3FC1817E7CBED +:10B5F00091FD18BEFFC8F99C62FF67D68D7EE2BB45 +:10B6000020DFF72DF08B7C777B8D91AF968746E717 +:10B61000B31F640BFBBA8015109F85D6115F3845A8 +:10B620009F1D93815F389E883FE2257E85BD6DB763 +:10B63000B17E1BD0E908D21F8074DB5922AE734063 +:10B640007D85E4622093D9F57C100C58D5B08E8EA0 +:10B6500003452CDE03FA65C0CED27641BF31EAF253 +:10B66000451E58DF40A933B18136D5B0C16E3F02C7 +:10B67000E39E72B311ED7DB33C4C877FA01ED89A38 +:10B68000F6AE17E1D96A67B4DF3376B106E1DA2E98 +:10B69000DBDAEF6A4AB11D27DB1FEE56A1FF93F1FB +:10B6A000BCFD61F6A5DD5A2AD18BF82A41D0234191 +:10B6B000DAEF337478053AB89273689F7199F06D38 +:10B6C000B6EBA59E30EFC3E6797F27F70341A7913C +:10B6D000D63D0C5E60CD2F8F2E17EFA35CB8C05FF8 +:10B6E000D6CBC5F071FAC97EAF15EBB6243C9F16D8 +:10B6F0008AE14746F0BFCEFE7BBDBF00783EA4A0E6 +:10B70000DDABC2DBB319571D308E52F8DABFA3FE92 +:10B7100057766BE3108F56E8807ADECE42048F9422 +:10B72000D738E4032BE2BD9F9E83FE1D52A6E02086 +:10B73000751EE45F05FA5F42FC5CE93E59CEF5DA1E +:10B740000AB1FF55E094305E45172B45FF3C6E4D26 +:10B75000D3816DA8E754275A1470FF4229C207CF3E +:10B7600055275D2FA84837E06783DE79A9E44FBFEE +:10B77000790CDEEB1CB0FA9D306E67E0C70CEDEE85 +:10B780008B33981F17DD811D01BEFA9067A1C38717 +:10B7900072D37FBC631A63A7DAD840997D38BC03A3 +:10B7A0002FC7397CB0D8909634F35918A7ABD0E99D +:10B7B000417BEE9D8D5607D26960738386C83891B0 +:10B7C000A2F52970BFCB1662E8DF3B36B62F44FEE8 +:10B7D0003E61D7FCE3E0DAB559BB1BFD10D5B7B825 +:10B7E0003C1DE03FD0652B0FC7D89FD7E7707FE7A0 +:10B7F000AD97EEA4F51F4971F8E360DC218C6F0072 +:10B80000FD8ED877A6F971DC4DFF2D0DC73FB266CE +:10B81000ABFF6580EBC826277A52ECC81E570D8E09 +:10B820007B646EB377AD6E7CD7F58E56BC3F30C966 +:10B83000E19842EB792FD18BEBD9983B1E79B3334A +:10B84000C531B9099FAF6D66B85E8777A71DD7E789 +:10B85000B2B1DDB8BF7CC97BE1CD02F4977C96D94B +:10B86000B740FFFFEA0FDD9A83FEC986530B512FC5 +:10B8700039CA92B6E0B553C029F72B49DFA19446E7 +:10B8800017EE639DAB9B781CC66B69203AA6588265 +:10B89000B81F7506D6B8A6CFE0F79BC70CC74B27D5 +:10B8A000C65D66219C6BBD6BB3B0DF876D21E83749 +:10B8B00034D759130B8FCD395C8FB9DA9B333600EF +:10B8C000DC9D7B5C1EC44FA712DADD0078D5D2DD8B +:10B8D000FE277CC3DFFB81784FF207D089E4707DBF +:10B8E000CEA43D9A0DED554E47C08BCBAED39B07F2 +:10B8F0006795AECBD1ED93C3E64DE9247DD1A97018 +:10B90000B9FE414ECE1E0DC6C9F587EECB81F98E2C +:10B910007481ACCDA2754E467B7F24F91912CF3BC2 +:10B9200037C1BA63C8FFD06A2BBB612CBF5E07D793 +:10B93000E99BAD939518F8199ADB948171AA23F0CD +:10B94000DC02E30CED71F12BDCCF40FE1A813FF3FA +:10B9500072B8BECF9A19ECC6F5B2197E8AF3BD99BA +:10B960001DECA1366BF562FB0BC0BF8F7D4EF897C7 +:10B97000B149C0AFCFCCDCA3814BCA3CE30C76EB22 +:10B9800048FB67900DD9703FDE54F2A716F407BA52 +:10B99000B31C3EA72E2E28EDE825995CBF05A79D78 +:10B9A000CD839D9B55CD584BFE0DD8CB141FF4C0B5 +:10B9B0006FACF86010E3813A7DB8C4D496F6E9BF65 +:10B9C000E608FB45D8C9A9BE9DC1F9E87FBC61F571 +:10B9D00087016F69F802B42B172B61B4D73795FC38 +:10B9E00033D9F14CD8714B049CBF6C73B1B2692C44 +:10B9F000E2CFAD10F7135A4E3D8EFE7502C63F31B1 +:10BA00005EDBE2F451FC05890FF35789F549BF8EDF +:10BA1000EC4858CF8A16110765BBB8BEB106F29143 +:10BA20001F601D06BF24C84C7EC86ABBC19FAB35D2 +:10BA3000D90F66BFA1CA6437EC40DB09ED425B9FBA +:10BA40000BF9E9FD193947327CF458EB97F63DF4D0 +:10BA50000B150E6E19D2ED3F8342FFFCAC4D3D81BC +:10BA6000FA684BF03117C6E1BB6D6117EA93EEF24D +:10BA70007B1391EFBAEBACE5C86F036DE5D4EFAD86 +:10BA8000B6205D6DB95C6F54FAD58F703F91F65951 +:10BA90005579E9890E1D5D2BD5AF9CE8D0C15F516A +:10BAA0005869684BFEAAB0B2D6BE18FB4B5EAE8C8E +:10BAB000BBA8CC608F5A9FF28762EC17F21ACF6C4A +:10BAC000EFEBF1382ED768F73E3063FED8D1EC1992 +:10BAD000B94E891FB97EF97C2478FF2347FA279F46 +:10BAE0000DDECC4F08AF194E09FF48FD2B70139B9C +:10BAF00084F076ACD066201D4385B980E7AA326514 +:10BB00000BE6657E26E2953F0B24863580E7D54C13 +:10BB10001EFF8C6FE17E657C59E542DC9F3E29BDAE +:10BB2000EF2854483EAB034A58857FDE2CFCD55F96 +:10BB30006632CA3F80BCBE9908ED5FCCB5F338329F +:10BB40005317DF363BEAA7C6D7F1FCC40E07F3F75D +:10BB5000E37B37BAFD9BE1FE32297F35C63C447555 +:10BB6000B5DDB0CF5498F20EF1A67D6679AEB0BBCC +:10BB70006703DEA744F13E92FF31129F30DB853C24 +:10BB80008C8B99F1738F093F667FA7E279937C5C78 +:10BB9000A1DF73A02BEFD564B433CA14FF34A41F04 +:10BBA0003E82F7E2D583940ED921E548F87B325FD7 +:10BBB000B5636915F97B6FA13D3096F24D93315E07 +:10BBC0002DC7977E5EAE5FFD466EFEC8700C8AF78D +:10BBD000B656C6B61306D14E98C5AFD7C175FAD2C0 +:10BBE0000569B1EC84C1226127C073B40F06F794D4 +:10BBF000F36B91D14E60E5B997C1CB265A6FDCB497 +:10BC0000BCB1B1E46E7056E8E1DC09D17642662B36 +:10BC10002BD3E1FDABD9EA3FE27A2B451C42CE079C +:10BC2000FAFDB0DE0E33CF7728C7C3F15C3E9EF439 +:10BC300085BC5E8E7E364F2B433E7BC0AED6A0BD0C +:10BC4000678E27FD3097DB895D196A0B3E67EE9C96 +:10BC5000CB8CBB49C6AB33B327F2F403C57D4CFE96 +:10BC6000A0F49FF6E3C3FCA85F68F370BF303EF515 +:10BC7000C2610F3C5A971B7A1EF135F74258B380C8 +:10BC8000DC39172B643F395319D93D57EC875D6177 +:10BC9000BF2E146AE0E7AD8D3C1E5F9A6DA3767CE3 +:10BCA000C87A80F605531C275E7D8FFCB02560079F +:10BCB00088B80DD953C7853D1564ADE4EFB9ED6182 +:10BCC00017C62BCC719B9A544BFF74D0EB3585175C +:10BCD000AA7D33E97D43DCA7C69771788278EE812F +:10BCE000EB92208F032DC338108E5F1DEECAC03C2F +:10BCF0009CDFE65719F7F3D0BE58DE747FD6C3BE7B +:10BD0000AB170792F125692F4A7B06F44BD778A42D +:10BD1000CB02C547BEBF294E648E0BC9B88C397E95 +:10BD2000648E177D9C9B4EF490F6978CFF7C946BF1 +:10BD3000B4C3AC3037F6EB2E822D15E4BBDBCED28C +:10BD400076CEE0F11DB4978E94FEC483F68535CF90 +:10BD500014E7BCC2FDAD13F6A133B8AFBE126747FE +:10BD60007B3BE80D513C7189629493C9797C9FF3C8 +:10BD7000E4B9F93C228FDCD9B641BEAFA1BE09A619 +:10BD80003AC2714A741C56987F45F2949CAD4ECAD3 +:10BD9000CB277F2415AFCC0FFE4816FA231ECEDF2B +:10BDA0008513683D4C9DC0CEE8F3C602EE081C2EFC +:10BDB000F05BB23EF9FC2988E7FCE83C97C3DB8ED8 +:10BDC00092629703E31140632BE72B4F247E9F8100 +:10BDD000719D753EBD5D518F798B5CB43B795E433F +:10BDE000DED7C5CF6DC8BFF1A9213518635F5D955A +:10BDF0006731E44F23F1F74C46F922398E8D7937BC +:10BE0000911CA0AC4A78AC31E2F402DED5420E00BF +:10BE1000E12E27B04CD34E2BE375095C4E643EC235 +:10BE200056142C4F87F5366D53286FCCB49AC368DF +:10BE3000DFAF11CF1D22FE66CE23AD117918665DEE +:10BE40004776DAEA878CF9B5C61E63DB6C97CB7848 +:10BE5000BF0D8044B8DB249D40C15B47C7C37E5AF9 +:10BE6000E75F291E241F2ECEFDAA17EB5A3AE342A4 +:10BE7000BB1B30AFDDEBA27808F990282FFDF00B4B +:10BE8000EBD9B6B7F0315CCFF63C2B977B85D7B9B1 +:10BE90001C4E79D835A4E3B7ED82CF66E5F978DC9E +:10BEA00005F72550892C3599E448D6B51C49E1762B +:10BEB000A523C0EDC6A7A6BEBC94E75D797D4B6601 +:10BEC000205ADF520AF8C912F8C99CB6DADF0FD738 +:10BED000AC00AF4B9AF1ACD15FBD35D36857669AD1 +:10BEE000FD5553FB405EECBA96689E4DC4DD05FCE3 +:10BEF00066B9FA5E1BCFB7FC33F8AD787DAACD43A7 +:10BF0000D7EFB779E9DAD7E6233BED99B64CBA4AD1 +:10BF1000BC3F600FD6635E4BC621657CBC3F8FFB88 +:10BF20006F2CC0E1A8106B59684D4D443C1F0D703B +:10BF3000BB70A4FDA5AADC1807BD3D68CCEF2DAFF2 +:10BF400031E6F7EE9BA9BE9407F024CCF4DA43BAAD +:10BF50007CD41AB1FE1D0FF37C931CFFE83739DD4A +:10BF600065FB9C58FFCF045F24BC9C62F701B12A9B +:10BF70001FAABC19E3F6CC937345F6E02F855C2627 +:10BF80006CF6D8312E54D9BFC281E3ACD90DE3B8D9 +:10BF9000AF7C9CAD6913D38CF985AFDD81701C8DAE +:10BFA000E4175AEFC0FCC251915FF843DEBDDF4198 +:10BFB0003F6B569E7A1AF5862B4F3D83F8F883D057 +:10BFC0009BD03EA76FC3CFEB4913478DE3FF212FD3 +:10BFD0007F781CDFBA40698D55D7F2A19017D05BEE +:10BFE00017711EE68AC4D13EE06DAE8FE2F2397E53 +:10BFF000DA7FC95A709CF61FB3966762D8F32C5F3C +:10C000009171B98F490F7AA51E0C5E8A359ED5595C +:10C010003919F17DCECEEB62CCE3C5E53B247CCE75 +:10C020007C7C3F35025F5C7E7E74BC1D808301A4F6 +:10C0300093CD9348794D7637E53F251F25D47B6E08 +:10C04000C3BA05702C19EE2F09CF796ECBC338CE49 +:10C05000CFA7F89F6023D3F5B782BFCE0BF93A87FD +:10C06000F205727446C8D729942FB89E14F2F5EBE6 +:10C07000363FB57FD95648EDE36D2AB57FDE564E83 +:10C08000D7C1B620DDFF595B0DB53BDB42743D5A8D +:10C09000F6D8CDB8EF7CF03D85F4F148F0DCF5B88A +:10C0A000D5203F2D7B130CF2B6F6A1F186F6EA1EE1 +:10C0B00063FEBCB1638AA1BD6A83317FBEB2D598ED +:10C0C0003FAF6D9963986F456881499E6F35C97B15 +:10C0D00095A1BD309FDB8955E5B586F79CDE4643CB +:10C0E000BF84A52C148BFEB7E5F3B8C9CB25C56377 +:10C0F000874689733836DCFA36DA2791B62DC4D0F4 +:10C100009E776C5842F71F88E3FB9DF9BD26C1AFAF +:10C110009D65AB83F319DA458BAC7ABBE79E59A1D9 +:10C12000E5F93A7FD0E1E5FED8C5A9D5562FF0D183 +:10C13000D2B2F75EBD0EF82834C0C8EF51C1DCF3AF +:10C14000821D5CD8BA6BC175D0AED6D61BFCC7E2D7 +:10C150009683AF80F8B240D9D1F664783F3F3BD4A4 +:10C1600084E397782FBC82EFCF5F9C6D43367F20AE +:10C1700089913D7A2ECD113E10831FEE1770CBFCB6 +:10C18000D527DDA7CD79FA8C4C568A71E48CCC0B7F +:10C19000A5A8D7A0AD62FEEBE0ACD0FD081FDC5730 +:10C1A000514F3E90B53603F79391F2468FE41BE36F +:10C1B0000912AE1D251C9EA322BF3064CA2FE8E2DF +:10C1C00009EDF9A3C413CE89F786BE1D3B9E704EC0 +:10C1D000E41DCEC9BCC3C35531F30EE7168A7802FD +:10C1E0003CC738C2B93D35FCBA70F4BC835C1FEC67 +:10C1F000477BF20D790761E78BB8F9E02C752F3E8C +:10C20000FF6AB6DA8BD73F66A9FB108F4775F94FE7 +:10C21000CF445DFEB3EC2786FCE7A19CD093F93CAC +:10C220006FCDD0AF6AD7D850DC14CCC706EF89C524 +:10C23000C7CFE4CBF862FF67CACFEAF2A8964B37C4 +:10C24000B12BCE035C71BF425E9762B66F121023B2 +:10C25000E3A276DFD379A19F20DE3A929EF3F1FA32 +:10C260002B4B74FF40E537823D649E4F8E87FA0A60 +:10C27000F5D620480CEE33DB932ED4A19F724CD020 +:10C28000D37C3D9E2FE8C93CC948DFA7F382BF207D +:10C29000FDF36C9F8FEADAC4FD2B85E34947F06D0F +:10C2A000B4633B1BADBE03DC6EA7B8C50D81A470A3 +:10C2B000B72E1F7C11F7CB7C8C3F0E4D7500BDDB7C +:10C2C00043AFB8B11EFC9DBD36AC8861DF4DD4ECE8 +:10C2D00048FF9A4CBEBFCDF786BE34348A9C033FDC +:10C2E0008CB778090E8BA590CFCAAF9A825773FF8F +:10C2F00081BDEF4FF0C178DFEDE5F9AF1B7A57BB99 +:10C300001A75E3DF305BEC97C83379989F54C258B5 +:10C31000A85E1378EFCD02CCAFF82C14E77867E372 +:10C3200007C79663DC51B552DCF19D8D17A97DDC02 +:10C3300067C945F2BDE3FD7FC7B0FF0DDF5C3391F8 +:10C34000FB2D1C1FAB36E63ED99D4E7931C76C984C +:10C35000E7B87A3171CA8C68FE6C95C282B1EC98EC +:10C36000C9B339FF2F525BEF40B816859C0CEB9C8C +:10C370008F376C7D1BDBDF2D557C56F4EB33F93C9E +:10C38000357B6D544F0BF85987ED37FC090CE79D51 +:10C390001F3A68C3FE1F6629EC3AE52AE255BD380C +:10C3A00001E5F01DE4BF18F05F94F22BE468BA0DCC +:10C3B000E43E07F17FD8AD8F534A7ED2F2D4CCD978 +:10C3C00014F70BB504C9CE5D7A19FB7433AFD3FEF5 +:10C3D000DE051BE61EE21F6F9D84F1A561708E00D5 +:10C3E0005F91A0FB1FF3791CF3865EDB9B5F417EB0 +:10C3F000DE68A73A845979C139B3F5FED655DE37E0 +:10C4000064FDDA40213F8F00E634CD03F066DA00A8 +:10C410008E3825DEAF71B9A2F89C4BEC7FD04F1D52 +:10C420000BFD56B1BE7E8CF3319BBAD38AF1C32289 +:10C430003BF9C7CB57DA13912ED17C99DFE06F9887 +:10C44000AF67303F46751A2EBA0E809F8DF912FCE9 +:10C45000014B1C1EDA84DDEF7F449D0A722FEA4AED +:10C46000EF3F74EB2358577ACCC2DB771DBAF5FA4D +:10C47000CDB0A433935B8FDD0EEBEADEA5F837F980 +:10C48000F0BA7F77239EAFD8A0F8CBA16B7DFF8D4C +:10C49000F598626CEE72928D7F7ADBFD3723BF5E7A +:10C4A000F4320FF2F3F214CECF4D832C6C81F62DC3 +:10C4B0003DBB28EF191CB451DD9ACCCB9E4CE179E1 +:10C4C000D97F68EB27B8D1AF5D389BBBD8F833CEA6 +:10C4D0000F70601CB5CC46F9D2F1CCD389FB4BBCB4 +:10C4E0009A5ECAED698F83F23C8B19FB0EC67936D2 +:10C4F00070BFB948D445CA3C163BCBFDDB16F845A6 +:10C500007D32BEDCE81FE79BFC5FA9DFCCF916E0BB +:10C510007F0DEF77CE4E34C4EB468ADBCBEBB360B6 +:10C5200047E0FA9E1379DC4360AF633EF3C760AF28 +:10C53000E3F579B0D7F1FE8B60AFE3B51FEC75BCC6 +:10C54000BE0CF63A5E0F83BD8ED7D7C05EC7EBEB4D +:10C5500060AFE37BFF0BEC75BCBE01F63ADE7F7685 +:10C560002EDFFF3AA739C29B01DE4E3BFB35F29529 +:10C57000562AF2C2224FB62D693AEDEFAE8F80CB2C +:10C58000C19E1A504277213DB43417F51B48BCF0C8 +:10C590001FFF17DBDBD2C90F6136DFA12178AFE3C4 +:10C5A0001BE9FE6E68763918E9FB53479947017B12 +:10C5B000E6FCEDCA4C8CA39EB94DE9C3F6C06D0AEA +:10C5C000D913D351F472A2FB68F1FBBE03B89FB537 +:10C5D0002732C18F4FF6AAC07FE71136E4572DA945 +:10C5E0001EFDD2794ED91E538FCF1B3728C24F1D47 +:10C5F000B74F85356C53E4FBA9BDD8BF43BE2FDAD6 +:10C600008316F9FEBABDE8271F8BCCB7BA564D8505 +:10C6100076867CBEB60EC73F15A9AB9BB712DF1F4F +:10C62000888C3FBB17DF3F9326C7BFB396DA76D916 +:10C63000FEA795D49EC0FBCF7AE1BA47B16EE56AFA +:10C640008FD71EE2FB1FEC63AA3E9FB3A9D84AFB1B +:10C650009EAE1E9CE26E32CF6F49704FBB9278A99E +:10C660002ECF4FF15298CF8E72F6F5D2A4C9A8778B +:10C670004FA5F963FA29E5C591FA5663FC5455783C +:10C68000BDBD8785B03E3E5EDC8FEFE175F48E4C1C +:10C69000DBB03AFA2B8927CABA07194FAC593D7A51 +:10C6A0003CB1A6D4184F5C259E8F144F5C658A2739 +:10C6B000AED868CA43843E593CB18EF5DBD10F63D6 +:10C6C000AA427254E7E97B7522FAFB677D144F6436 +:10C6D000BED729DE2ACF4FE0FF2DB3F1BC196F9FE3 +:10C6E000BF5BF1A25FD17DB73211AF27EF5626A114 +:10C6F0007C9DBD5BF1A0BC7D589041F8CFFF8DFFC4 +:10C70000751FEEB75E8B9FA323F802A62A82AB9318 +:10C710007CDD30CEA9BB9571F8FECAFBD21DC80FD7 +:10C7200060770A7EB4EE45FEB426288676DE64C9BC +:10C730008FE147503EE68D176D6DF95E949F5287ED +:10C740007C7F33B5578414D1FFEB7B51BF1C9B2FEB +:10C75000FB4FACC3E7B74F91E31D20799C9720DBDB +:10C76000BB49FEBA22E37DFF11ECFF0BD490D4DE6F +:10C77000B917E5BDB452E8336D268DDF5927C7FFE1 +:10C780005A2FC6AD6A2DF2FDC524FF4D4CB6C17EB1 +:10C7900087F6AFC4FE70D70F3FAEC5B8D61DF2B94D +:10C7A000F6F123084F9D68AF2BF897BDF8FCAF7EDC +:10C7B0007D7FE6F9CCED956C60E1757951B930EF8C +:10C7C0002B0D45DCDF296C3988EA8BD5B5EEB7A295 +:10C7D0003C46F36A29D541E46F9795EAE7825E7695 +:10C7E00073AC7AFE4B057C9C8D05579A5F8B3DCED2 +:10C7F000DA22BECF75CD6731FDDC83B3E66F2DC87D +:10C800008FDA0D68223AE05A02570B5C3FCE0A3DA0 +:10C8100088CF91D618879171ED25A29E7853C9775C +:10C8200082F3F1FC5291DD2FC2E103FA7CAF4D9C03 +:10C8300073AD9DCFEBBC42DD4EF2D7AABB441D8940 +:10C84000D54DF908DBF58EFD943713F9D410D61DBC +:10C8500067505DD7A8E73B6CA63C6A97586F69F6AE +:10C86000FB94A76E7A83D70BCB3C76BD80AB09F5E2 +:10C8700032C0DDB85A095BE0BD46543C98D7CD6460 +:10C88000615F7A34AFBCA2CCD6EFC07361E27C06A4 +:10C8900013F670241F5EEDEBC3FA189B1AE757716D +:10C8A0001ED61FA4BA38CC17A5B348FE59EA91CAC0 +:10C8B000E6EBEEC63CB54E6F519E3A9E0DD31BA4DF +:10C8C0001722754D228F1EA9CF117A40E6A71BC4EF +:10C8D000BA9645F4C0E22568E7C63F20F2D422FFAD +:10C8E0002CF3D495A6736D8D810563289EEBB7F963 +:10C8F000A9AC26D5789E29DE44879B8AF9B94A9946 +:10C90000A73E5A60CC373F6067A477BB328C7CB7B8 +:10C91000A098E743FCC5320E19DF1F87F6377391E5 +:10C920001FD28DF19CB1DC1FA1C35CA6B88E6D43F4 +:10C930002DC51FF1B9027CA864BEF6EFA897B15DC2 +:10C940000CFD6D78BE05E9E1B6903F2AE33F68A68D +:10C950002CCCA138D079E467DB867A1A479E677FB2 +:10C96000323EB67C5C2C9079D63E3BF6ABF5BE767B +:10C970001CE7FBCC7120E18745EC181FAF7F995471 +:10C98000E09376899D9FF763F6A559142FF9B800B7 +:10C99000EFCFE8F3211C725FBAA3E839DAC7AE3CE7 +:10C9A0000FCEDF5BFBA3976AB5E491F3183705223E +:10C9B000790737A6C059B2CC3BA889D88EEA595816 +:10C9C00048A141CFD6B5FC27D0B351BB3FA30E9FA2 +:10C9D0007FD1E0077EBAA590EAA778FCED8B06FF31 +:10C9E0001BF96A3DF2E1B59EE7C5FCE03A9C67ABF6 +:10C9F000A2D6B8E95C0CF32BA3E70BEFC5FEE67CEF +:10CA0000E1E5E2187F8B5B8C1EB7E82D34E6F53F3D +:10CA10002F718B7F04DCE13E09F27490E429C0E5BC +:10CA2000E9AF7DFF83F51EC1F56E55FAC2F1D6ABB5 +:10CA30001F37783A2FF46B94A3E9A9AE06B4676068 +:10CA40001E1FCA5F341E0270171AE2217B5BAE41C3 +:10CA50003C04D6F97BD27F659CAE7F05747314E1EC +:10CA60007A546E47FC15F26506ADAF8FAFEF2F30ED +:10CA70007F4E11EE034F717E89E287DB493AFCD489 +:10CA8000B5FC65F07333C17788C3F705A0671DD186 +:10CA9000D3CFE1BD9CFFBDBE80FB17F05E13BD97F9 +:10CAA000C7F9E05E6157835FBEE03A5FD42F4FCE97 +:10CAB000569B8BB89D7B6791A1CE54BDAB6874BF6C +:10CAC000F99EA2D1FDE6FBF0FD2F8ADFBCBF80DB23 +:10CAD000FBD1BC4DD8C53FBED142F9E57AD1B77B79 +:10CAE00043D5A21BB1AE06F08F6D27AEC7AA5B4F30 +:10CAF0009A8DFBDBA6F36AF27B07725D366BDDD89D +:10CB00007E5F149F6F8D6975E079A86635A913CF94 +:10CB1000DD2EE8788FEA061DAAD3877EE197BCBE9A +:10CB20004ECCCB56A97CFD8E160F9DEF93E7DDE42E +:10CB30003994E6FE1B5F73E0B939F05F5260FC8AFE +:10CB400032FB69FDBA9DA6732936537BC3AFD3B7B9 +:10CB50001FD6F57FAAC8544F687DAA9CBED3D1A129 +:10CB600078449D2FD565348B313695DCB108E39739 +:10CB700060C7F9100F0B76EE1AC07C9AA3C34AB9AE +:10CB8000F33FB6F9B61F06918AEBB552BCE1830DAF +:10CB90000AFFDEC7629EC76F12797C668A33C87847 +:10CBA000B8C463DC83BCFEC35178AA8CCE37D6AD43 +:10CBB00019C8E7BC43F1061B878CC9EF6F540ABE46 +:10CBC000AA0FBCD781EF2DF35A0CF543E678848D7C +:10CBD00099EBE4791DA74DE5759CB64C5E271FCFF8 +:10CBE00054FA5E47FC962AA267A5CAEB38C14812E0 +:10CBF000DFDDE274A908ACA73A1F731CC159688C29 +:10CC00004398F9D24C8F93267A3C61E3E7933A0735 +:10CC1000AD7E0D6E773EB4BA0BE3E7DA43168A6356 +:10CC20009C95F5210024C6F397B3087EC95EEE6C8F +:10CC3000E5F502922ECB77F2BA11EA6588DBA732CE +:10CC4000FD773C968BB8C21DAC8FCE3BAC6443766F +:10CC5000948355184AB7623CC647D726A66D6184AF +:10CC6000BF50573ACCF744EB783FC6B5FB27D99372 +:10CC7000DECDE47E442CFB359AAFB5B1777571FEFD +:10CC8000BFC5B53E695CCBAAD1F952AF233C4DB9C3 +:10CC90007C5CEB88C84BC8B8D6D99DE27B1BE2BC54 +:10CCA000C580BD75F24E37F6F3919E19B377F92220 +:10CCB000E48323BD3FF188F3AF1B278EFE5D88829E +:10CCC000E218F5A43F2F60345E67FA109DA33E6919 +:10CCD00037D6E5CAEBED0159BF19528B75F631F322 +:10CCE00044EA38E717D346C0CF6BCB38D3BADCD091 +:10CCF0002D787FEE05C10F8B95B002EBAD702BAF99 +:10CD00002ABEE8FCCC5C47FFB77C18C11D87F80140 +:10CD10003C0EC4F1BADA817456F34C0CFADC389745 +:10CD2000EBD181ECD8F493CFC13EB9BF7802F79F25 +:10CD3000C6F0B8C2EF1DA3C715BE551C23AE20E92F +:10CD40007B709EAA71BAF3B62727D489FDDB4341D5 +:10CD5000AAD739DF63F56D42FCF7B7BE5508ED255C +:10CD6000DFB27A301F7EADF37C930AD289AF2E9763 +:10CD7000E7FB50E0F764A4AEFB5B944FEF8EF867DF +:10CD8000DC7EAC1DA76BC3965C3CC8FBBF585CBC8B +:10CD90000FCFD98F646FDE1758D58BFE9CB437A1A7 +:10CDA000BD12DBF27D9084C9A5A0349B5A643EB1CC +:10CDB00082F2F5D1F956EC43FBF8ACDD38BEB4573E +:10CDC000078ACBF7A1BD1A8CCC5FBE0FEDD953A655 +:10CDD000FEF47D4A18EFD7C565D4BF91C9F1CBEAFF +:10CDE000B17F24AEC8D6933F7ACC21DBF7D4A33DE4 +:10CDF000BE3D9D8F371858DFAB7D0EE1B9D6E37F7E +:10CE0000D2FE23D9FD27EDBC7E50033BED89742C67 +:10CE1000A3ECB372E1531D78C6AE5855683FFA9340 +:10CE2000888307DD16E1E76CEC45BFA7B644F2E95D +:10CE3000E354073212DFAD7FFE478F68FA756A3F11 +:10CE4000AA35C0ADB5529D8884FB04F68775D4DE43 +:10CE500073A717E1AC95F10DD6D98BEBEB4C92EFA4 +:10CE6000DDB40FDB23CDBBE6F99DBD88EFDAC83C0E +:10CE7000DFA6F76BE3E578BDD48EE2F300C54BA2E5 +:10CE800070B518E07A2D70A017E10A7AC25B707F46 +:10CE9000087A19EDC777B46CA2FAEE881C693BD208 +:10CEA0004A510EBD9136C757448EEE2739BADA7013 +:10CEB000C17E9A3E07F7BF4CEE275EFD75C33E89E3 +:10CEC000EBEEE17A48F2519D478E03F8077DD2E4FC +:10CED00093EDAFD5B7B8AFC6BCDCDF0DFE9E917D3C +:10CEE0002BE58969AB4DF27365E3B5BBBF4675149D +:10CEF000CDA0D763D563DF5B10D14FB7123E0BA532 +:10CF0000FFCCA4DD5181F72376872F627754CE8939 +:10CF1000617774629DD52CAAE722BDA9C213AFAE7A +:10CF20000E68C65C9E076C177592799BD95ABDBF77 +:10CF3000FDFD79DC9F7F6A1E874B7EDFF6CC3A854C +:10CF4000EAC4DA7BA68CC1F36EA7537DDB51AF0D2B +:10CF5000A45BE83B0527C5F73507BEE14CBB0FEEE8 +:10CF60001F4F73F9515F1D4FDA49DF513BEDB70A8F +:10CF7000FE3CF40EEEF3BAB8A2867A45C60DEF9EDB +:10CF8000B3F55194A3133EDE2E9CF7E377509E59E0 +:10CF9000A6F97C6780EC18C7CDB08DE0BBE2FB9CA6 +:10CFA000C5E279E5B61F7CBB0AC710F68BD49FE6B5 +:10CFB000F39EF863D7DB5F5D566E7F79793F2F1B59 +:10CFC000DA74C982E3F2B66B84EFC2D6C8F3CB261B +:10CFD0007BAAD2743E9989EFA04A7BBC38B9D18F25 +:10CFE0007E5CF13AA37D74BAEB959E42F46BFD56DC +:10CFF0000F6E93B7661A9F4B3B6C51D763E48F82D9 +:10D000005D689847D6DFDECAFA3AE85CB8EFF5C348 +:10D01000D68951BFA5DD5349764A7326B4603DC712 +:10D02000FEBE34311FED831E2B7E1196D7DEEBD66C +:10D0300001FDEC9664DAA7FD8AA2AF0BDAF228CAEA +:10D0400045B42E88B7A3F1F8BF7FD45047C7BEB60A +:10D05000CA10E7D46A1FA53A3E1917D3AAE9F919ED +:10D060009B8883694D8FE27E16899369BFEA35C438 +:10D07000C9B4203D0F46F6BF5DFBB0BDCC23E0D167 +:10D080004EF622BFB5AB5C9FBC34C77D52B37DF278 +:10D09000FE209FFF730EC6B7827CBF333F2F1E0C4E +:10D0A000B78F11761DD68B9BE57C5C80D7DF95A969 +:10D0B000D91D137C3C7EE504FAA82BAD2B316E10F4 +:10D0C000AD5729A2EFA4358D505FB224C0E5F7E833 +:10D0D0001CB7C12F37D7A934893A9591C6B9B38403 +:10D0E000E7D907144F35D7CB56867AB974D714379A +:10D0F000E6A664BF9B4BF83EF071967A12D76F8E0E +:10D10000A79DC5781AC9198F7B2C15BC63DBC9BFD5 +:10D11000572FBF677226C9EDDF0CF797F688784561 +:10D12000F9678B9FBD37C7784E7FA4FA87D212BEAE +:10D130009F1589F57ED6FA8727E35515F135047DCD +:10D14000313E38AC1E42D439C83A88B1810C5EB742 +:10D15000C1783D44BBD64AF8BBEAE75CC4FE0F7C0D +:10D160009A1C403EADE17A44F2D94FE7F838FFFD12 +:10D17000C64FFC27F90EFA4F0AA01EA9E6FD8B7FC9 +:10D18000C3BF7B21ED8B718133BD9BA6921EF2053F +:10D19000F4FEAF3B722E322310430F1D5DA04E0DE7 +:10D1A000E8FC23783F33901FF3FD2F13BCA6F7B3A1 +:10D1B0006606B3E8FDC8794E7566E06F7510A03D50 +:10D1C000CC75277CBF30D79D487BF0CE92DFAFC4B3 +:10D1D000BA934BF3D5651CCF1CBF11BB7288DB39EA +:10D1E000517B3287F6C36B602F36133D453DCD35FD +:10D1F00018FF5EFDF8D27E82FB7FA7BFFF79F3DFC9 +:10D2000000BE6E824FE44D3EC5FBFF40EF8B7CCDF0 +:10D210009F01DE30F191B0FB3F87F87CF6730EDFA3 +:10D22000EB44AFC59CDE657398DCB7FF35361F5CF9 +:10D2300031FFFF6F7A5FE4CD75E3FE5C3FDF48FEB0 +:10D2400039F4FB15E16DF130F93919D0E5E347798F +:10D25000FF8C7E7EDDFBEFEAF9F32AC8F9053D7D00 +:10D26000AFC13EF2118D3F958FFFBBE2C83A2EE968 +:10D27000EFFF2D4E76593E9F3617F1D5CAF9E90AD0 +:10D28000ECEB9BE6F2FA96108FCF6A927F678AFBEF +:10D2900043789E74F91C26BE8F12CCC6FB2AE3FE8F +:10D2A0006DC41FD17AF719FD1118688641CFEFD3ED +:10D2B000FB1BE5739FD88774B72EE0FDE7BE306E89 +:10D2C00015E2DFDC067B64DE5C635DA68AEDCB8D58 +:10D2D0008BF97F7ACF94FFD73D5F44CFA3F50B64E2 +:10D2E000BF82DDE672028D7F51674D6E8476B5F0A8 +:10D2F000DBC1FE8879AEBB3A1AE7AE9EABABC7186E +:10D300000C5AE97C60C44E61EE4711FF113B4AFBA9 +:10D31000FE3EE3B98D8314E72A11F46D7EE1D97ADC +:10D3200001E72AC4374B16EBB87CFF35D4DFCBFBC3 +:10D33000C7787E273D4FE57032F7EB67ADBA7C18B2 +:10D340004A9A05F3BCF82F1FC06FBF7D6E32D82BF1 +:10D350002F77293E2BB41BF74A7E7A81E44157F799 +:10D3600041F2B742F0FBD6170ED7233FAF785FC22A +:10D37000EBE4EB8FD4311DA6F59F10F188092F4205 +:10D380007FCEBFDF24F87C1CBE6B30FE36A213E3D9 +:10D39000F8A9619A7DE2287516BB04FDE1BD9D04E4 +:10D3A000978BC3551352C85E0FAE06890638EA073D +:10D3B00059CC38D3EEB90EB98FEDA679DDC28FF511 +:10D3C000C73E2FBB2FCA4FFBA8BF87CFE702FD8FF9 +:10D3D000ED40E8E802FC0E448DF8DE784D998DBEF4 +:10D3E000B750537861A98883507E53E6C14B1F9C88 +:10D3F0004AF9CDF8B238EE2FBA8C7FC722D8E4A410 +:10D40000EFC9C9EFD6CABA8C4A66FCBE5C8CFC96E2 +:10D4100021DE22E32291EFC95953C9BF753C2AFE90 +:10D42000FE93E9FB71F11B18C5B79C1DFC1CB839B4 +:10D430004FD5B0B1F5AD22ACFBB0D9292F6BCE677B +:10D440009AFF1EC63C1753C7E4503DCA6B73F3A343 +:10D450007528E7F74E71A31C9AFDE7F323F9CF7BFC +:10D460008DFEF380F49FD5ABE33F9F986BF49F1F35 +:10D47000CF0DFE8AF8CAA6D2FEF67249F1528C236D +:10D480005C147514A71E4A5E82F128AD879F573839 +:10D490002DF2FC32DF7FAA88B93D78DDE2247C9E44 +:10D4A0005A9314C62D784C47F362FCAEA0F4A31136 +:10D4B000F318FFAA10EB34FBDBF18540CF5924664B +:10D4C000E4679FF278282F50D125BE2F21EA05A4CA +:10D4D0009F5D21CEF13795F173D518B1437E90DF72 +:10D4E0000FAC107EB8F4C7FB7FCA147D1DC052E696 +:10D4F00027FEAD06C6C0EB32F13DC51A0FDB8240F8 +:10D50000FD312BC44A102F7B399FB0ED36FA3B57C3 +:10D51000A77A76D1BE3AD2390677893CC7A0517E28 +:10D52000F61AF8F9490497D83FAE60BFB98EFADB16 +:10D53000B81C6FC3F3BFF9D1EF4AC873F3DB93781C +:10D540001C654609DF6FCC57F9DD884FAA3F407F45 +:10D55000DE5082EF47FDF94C84E70AF4E74C825B2A +:10D560007CB76232E681F8FAB34B783ED73786272C +:10D5700071BB1CA3D70114968C92CF6597AF235033 +:10D5800063BDFFA1B0B3D7E5861696F07C3FF1AD41 +:10D5900039DF2FFB1DC3F8548CFD76838853950229 +:10D5A0008B5A72869FE7FF459B7A126DBC636DE5CF +:10D5B000743D6ED312B17EEB2D719E1F0C2DAA67A8 +:10D5C00092755172DC9ABAD2936775FB59C5C2C77E +:10D5D000A9CEAC3DF3C0EB0AC0795AD47B0D24FA36 +:10D5E000689FD38EF2EF4B2DABFECAC9B3BAFDC311 +:10D5F0000C2FD6456920EAEB4BF877CB5E2975F600 +:10D60000CFCBC3EF3571395CDD738ACEC3D46F687D +:10D6100060A12CAA9BB2217DDF9EC3BFBF50516881 +:10D62000659A0EAEE46CF5AE121EF759477C12AD4A +:10D630000BBC1BDBA576750CFEFD49199F94F98286 +:10D640009B5FFC3F94771B4862347FD0CBC29877B6 +:10D650005FA0AE770C61DEC5EBA3F8C8DA121FCD70 +:10D66000DBD8B59FE0890FBC47F0806DDD8FF58377 +:10D67000667C4BB9E814F8D6AD9BF03D92FC562C75 +:10D68000B425227EDF427A41BF07C53E70C476C111 +:10D69000ED8941F7C87B85A5067C3BBDE506BAB59B +:10D6A000ABF78EC1F5483A378A67E7BBAC6F221DEE +:10D6B000DF073A32A263EC3A88A348AF1B806F4C75 +:10D6C000F4AAEFE0DFBDAEEF28A5EFC5D5177EC504 +:10D6D00091427900A50FCF4B36953530B4A71D6A1E +:10D6E000127DDF4ED26F6919D04F072FC8E3632434 +:10D6F000A7C2EEFC14F1F5FF5EA2B383AF75FC1F69 +:10D70000E6FB51490CBBFCCF957F18FE3D1FBEEFD9 +:10D710009E12FC62BECA7D77C4FA662DB8AAE55394 +:10D72000C021E506E5769382F5938A1DF92C88F2EF +:10D730008BE7D70A7FBB05F3A1CD5ED6877BE13EA1 +:10D740009423C09BA33CDD81F2D3B8379DF802FD42 +:10D750007FC2A7D8A7DFC47D5AF8FF74BF85F3C581 +:10D760005F3AEF03F0FC1BC15327CE177CCEF25279 +:10D77000C9E541F73CC05B50DD4FFAE5A742DEE06A +:10D78000278D7FB7E993E5418B555E3726F3A131AD +:10D79000F29F3EE553E43FCD79D591F2A131F29F5E +:10D7A000067B7DA4FC2733E549CDF9CF455D5328A1 +:10D7B000FFBC28D342DFA99676BFCC7BBED1F50350 +:10D7C0001B7D176986C292D287E747BF2DF431438C +:10D7D000AB4EB7FEE369FCFBD7DD292EFABBABF8F5 +:10D7E00083F558129FA01F5C4E98B76321AFCBAC56 +:10D7F0004C7FC68C5787F04BAE08AF32BFEEE85275 +:10D80000C29B9135BC2C52FFE7D0D1D991F91CD1E4 +:10D8100091D9FADDF83DEE46FF78AA2733D3A1B8B7 +:10D820008BFF5DCA62CF6CFABB9492FEC5DEE175D8 +:10D830008336095F8CBAC13F3B3D7D9B5D19A3D008 +:10D8400053E6B147A2E3ACBCE0BDF32644BFDF24FE +:10D85000EF1F4FE3F83D7323137FFFD4484FC0BF42 +:10D860004AE7FA33D9FECDCA707E2816F598C599D5 +:10D87000DA7AAA838F5FECC5BC5904BFA98708BFB9 +:10D88000EDADBEEDE81F1D2DB353BD4A0C7EA0BF0C +:10D890006F7B397E1846F79E4F47BFDAA22716A442 +:10D8A000C7E08F4F4DD7CBD0D3617DAAABD0174BFC +:10D8B0004E5FE92139F55B3D4857494F49DFE1F4B7 +:10D8C000E4FB9DA4F7DBF9EABFE07E18A5B3FA34C8 +:10D8D000D2392ABF9AA19EC5FCDD9B1F8A3A161831 +:10D8E000E7391CE710FA58143F540FE138555F8AA6 +:10D8F000FDF74E9E29E5FE4E1DEB7B7522FA7D67F6 +:10D9000099A8D7F4BFEEC338CD862931EB358F3DCA +:10D91000A0F0BFD3E365FB2D627FB5E8FCDD535873 +:10D92000B709FEED09ACDB84EB5BF3D2F9F7E5B1A7 +:10D930007E732CD8E3A2BEB30EC7C679C09EC5BC09 +:10D940003CB385189E4B1FC0EFB3CCC2EFB36C2223 +:10D95000BD1BADC3F890F45534EEC9DB9501D97603 +:10D9600087A9EE46E63F993764CC7FCE0C1BF41DA9 +:10D970002B0C19F39FBC4E47EAB7CDEAFC10C6B595 +:10D98000A371C5721AFF649DECBF235C3A4397FFF5 +:10D99000D4AAC2AA5B9FDFBC2DACCF6F82BEA4B657 +:10D9A0008C433FD1FF6008EDFAAC99A10B48377961 +:10D9B0006E1E14908A7F87CEEAF61C403F1CFC0343 +:10D9C000A6E68F6C575FEBEBFF07133449A100808D +:10D9D000000000001F8B080000000000000BE53C69 +:10D9E0000D705467B5DFDD7BF727C9866C42A04B0D +:10D9F00009ED4DF879692561F909044AE06E76135D +:10DA0000B62D9405429B0AC50B64101D5E0DB5280A +:10DA10003EEBCB42421A420BC1E1F937AFBE2D05B6 +:10DA2000677CD631386AA1485DA0459496A63699A0 +:10DA3000521FD280790CD5AAB496577554DE39E7B7 +:10DA4000FBBEDD7B6F3685023A75DC4EE7E6BBF741 +:10DA50007CE73BE77CE7FF7E9745B315C66631F868 +:10DA6000F99386C6585F2DFC79338E83A651C2D8B0 +:10DA7000D2B1725C9934263236374F8EAB4D633655 +:10DA8000631D1E26E6B30403F8D7989BC69B8D5AE8 +:10DA900033318EB1F02255C0C708FF99E5127E4799 +:10DAA000320CF896B9C438B12469F819FB2893E30D +:10DAB00005345E9E1EC769FC00E3EBEF4D3D6E260C +:10DAC00060FE77A6C56F3646C0BD68B71EAFF8C703 +:10DAD000A3FF9C22E9196BE2F30F3BBD20EF9851A5 +:10DAE00085E8B9BCFF01E85D41FAB19FD3FB21A4F1 +:10DAF000EF2192E7D39CBE0F013D6D444F37D09389 +:10DB0000FFB75FEFC52A6327EECFDF808F2768DF7F +:10DB100027723EAE02FE29E23BC4F7C1F9FCE67073 +:10DB200080317C3E8DE37BDD2DF428D164A2DE9F25 +:10DB3000755BF60DC6B37AE57A1BF4B066A57F0374 +:10DB4000D9C9B2223EFFD7A9CF9A8992CC187E06B6 +:10DB5000EEBB9CFF1B7C6E9BFF199ADFE94EC3D383 +:10DB60007A1EF15C39BC89E8CDF09B20F81E077C59 +:10DB7000A3E0AFE07047326191074B3C4AF249FBAA +:10DB8000A5C4E3E497FA3C72BC8DEC667B29C73FE1 +:10DB9000EAF0E349A41FE47782E43D8ECBEF9F5D7A +:10DBA0001EBF3584BE947379483DFCCE34E377A81C +:10DBB000671F367A61FFD4F0888CFEFF1DD62BA438 +:10DBC000F5843D7DD0F9697B14719FCD4FCB77747F +:10DBD00018EE8FAAD5E979F5DA7D919BE0CFE5CDF6 +:10DBE0004FAA26E2051856CC58BC9F2537C39A7712 +:10DBF000B0A4CA2086C543260B4CB4D835FB32D11D +:10DC0000E1F1BBC4F8BFC8FF2D9B23F5FA5412F312 +:10DC10008B0CDDFE95B84F69BAD91336BA671FF67B +:10DC20003F29F80E852D7672A3F1076B412E967C65 +:10DC3000283D16F259F6E057C7A01C969549BCDF5F +:10DC400048229ED70B25DE7DB4EEB2F43ACFF171B7 +:10DC5000AE84FF29C167E8EA336D74255EA5BC4B2D +:10DC6000D2F5CDC37DB45F9E4072CBC869706D5252 +:10DC70004209D88F8FAEDDA49A56BFC0BAF530C422 +:10DC8000B7FB597A4C7A95F103DDB4EE8DA66B7D26 +:10DC900058C847D8699ACE7E164A302B7DFBF9FECC +:10DCA000DCE0F52D7EE121D4DB1B2FF794FB268BE6 +:10DCB000DCA51D2C0FA4EDDB603E90BB2EF1BC60FB +:10DCC000AEF55FFFBAA0E78F5BFDC9F5F3D153470F +:10DCD0007CBCC5F725E37F5E36EDFEE7AAE97B3223 +:10DCE0006C89E71F74FE7F87ED7666F13FDF42BEE9 +:10DCF0005BFD451ED4EF9541662481BECBF89B9B0E +:10DD0000B98EAA55C83FA5EDB39ACF5FB2833577D8 +:10DD10004F1C0C7F53AD8BE05A9F656BBB015FD8E6 +:10DD200073B1296E814B85F9F3436185AEC0DF2164 +:10DD300092FF464EDF89B04EEB8599C60CB0A9869E +:10DD400025634A500F5A7FCEF1B160882DCECFE0C7 +:10DD5000BB20F0C9750E2FCA6FB4F2F113B1CE8992 +:10DD600030E703E33FC9F311CE875AB02E88F8D5C8 +:10DD70003C595FFE9AE4DAEE16E3C43B14D7FAD2BC +:10DD80007EE877A4EF4BBD522FDF23FB97F9FA3BD8 +:10DD9000E13F2513B3917EC65C53ACF37E4B7EF01E +:10DDA0004AF3FA65BC6813FB9548EFD759A4FB4AC0 +:10DDB000F3D588D24C72F2B19402F143F50776772D +:10DDC000022B1595C69B38FFA5C9C6AFAE060FC876 +:10DDD000E922EDCBC3F67AC4F2FCDDB0AD1EB8B8D3 +:10DDE0002E8E7860652FECDB6BCBD5E25520B7BF6C +:10DDF000E2FE54517D10CBA65F7FCDECCB5FC3B666 +:10DE00007C3E925F0576C446B942E3F5C1F3FCB5AA +:10DE10008AD433B14FDA93C8477BDADEF8787B21B6 +:10DE20007F9E73C4BD52D8535E2DAEF33D215F1665 +:10DE300028C6F5D8C4E329753AC45796FE192E189A +:10DE4000AFC2BF60FDBEC85937EAC18A0EC5486679 +:10DE5000D1FB4176D221F03F96DEBF51B52308AF0A +:10DE6000C9A68BF801BFBE8F6F22BC8D4D0AD99F0A +:10DE7000D35EC6D672F98DAD4DCB692CD16F70BC17 +:10DE8000BE69F1F188174099774A06FF0A4177D8B1 +:10DE90001D3F7413E8417B9BA2A33F5AB9716547AC +:10DEA000298C99E60E8D87CB049414CC6B0F96F9D0 +:10DEB000D10FBC24D6437C1ED8478C25C122826357 +:10DEC0001A5CA7C7D61FC5E97FA930AB70DDEAF899 +:10DED000CE08B235AB71DF51BCDE036E1AF3944D40 +:10DEE00073BE16AF85FDEB99E90EA1AA4176D63334 +:10DEF0000EE86A107469C6BC37D930A8A23C2C94CD +:10DF00009A8671DD1FDA0CF71B9A3E3E9F55024C34 +:10DF1000DC3DD0EF43664C76B90CF16A03FDE55C5D +:10DF20006697C1C72DDAE8CE8C91367CEECB3C5F8C +:10DF3000722BF74FCB6A419E16BDFB91E0EF474233 +:10DF40009E3B80869E8984209FA1DDB0B52E94DF04 +:10DF50004A81ABA76DC95DB7017D97CA5908C75EF5 +:10DF6000E44FCDF077768CC6F963867FC148585769 +:10DF7000ECEBC916F075FF0268DB804FE047539762 +:10DF800017A42C7A7C7298C94298B79527B630D0DE +:10DF90009388B9D3DD0F74DCDAF4F65ACCFB5698CB +:10DFA0005E7D1E9078FFDA401DE6B54B4C2197F957 +:10DFB000EE73C8B70FFE43B978526FBEE04139CF58 +:10DFC00056D828C0BF30CA9F4BB9789976CE2A1749 +:10DFD000CD31DE78BA74FBF316F84FD5E6179FFF04 +:10DFE00008FC31954DBD0C7C82035980F45CEA50ED +:10DFF000026A2981B918F0E9F1F17DDCDBB1FE2577 +:10E00000B4D315412DE4D2913E46F26B146BBCD7CC +:10E01000A26F7F1E72D5C8C69D5DA877F7F7AACC00 +:10E020000B70EDCBF72226FCF9109F26F4C295F772 +:10E030009F3D1AC069FFA6325C4FCA11E41D980EBD +:10E04000F7CFF5C17C00BDBF1AE404EBDE63787541 +:10E050001DE07267BFDD8672CA65CDA9E130BE37AB +:10E06000E862295F862FE03B21E4E2BAACD05ABADD +:10E0700026D775D99E935C723F17610C7D77C2E8F5 +:10E080001907708BA4DE76F0FD5C64F0FD90FBCA8E +:10E09000A25C5FE5BEE43AF4D55BEDCEE867167DA1 +:10E0A00075EE43D2B10F7B356E27677B55CA8FCE95 +:10E0B000EE2ABEA71AE491D8E5223B863A6DBF52FC +:10E0C000007FA414A681FCEF13F4D20FE0F63617FC +:10E0D000263B4B33FB715FF9B13F2A958C438DCCC6 +:10E0E000F82386452C8CEF15A3FBBE9228423BFDFE +:10E0F00028EB76A35D3FC0FADDA8FF1FC352504551 +:10E10000FF18F2E0FD465FC08372DCBBEB483EFACD +:10E1100091D4CDEEC2F3E5642ACCEA279D5794C48E +:10E1200079C93700A7A4FFF49941F2CB7EB8929F3A +:10E1300036188E0BEBA23E334B1C3936D5FC31FA28 +:10E140002339D602CD0CE9D83335FE13EE77F9FC2E +:10E15000F195C64FD17FEE9F629CC0FBDFC07C0F64 +:10E16000E2C3C5DA47A82EF94B857112EF3BFDD803 +:10E1700039F4637A461F163BF441FAB153E8C7E01D +:10E18000D162B457901B8B5D9F1F3B2BF5E07676D9 +:10E190003BCA07F8F925F97F0DF801B99CC17D9FAD +:10E1A000C4B0FB966245C4A61E00FA14411FDE5798 +:10E1B000C0BF2B1B7FFC4765181FCF023845EC2BD7 +:10E1C0009691751837BE1EF2F9C6A2BF304F21DFF7 +:10E1D0004EB9406076535D163C760AF5C695F7C396 +:10E1E0003166963898DED775EEB7D27CA11D4126F0 +:10E1F0008F7C28CC745D467E0240C4A8F7D38B0484 +:10E20000E941FB0285F86B2F658DE8CFDBF0D14C3F +:10E21000D0F7054A37EAFBB722453C5F1AC7F3C27D +:10E22000CEC26430C4FB2C04CFCA436C494506EF10 +:10E23000B7222AC14F9A66E461E082BC8FF2259929 +:10E24000AF4AB84084E795C3233CCFA8A88C1751A8 +:10E25000A02B0E91DC218F1A4E637F2AE91A29FA2E +:10E2600022FCA7BB2C7944DFE824C33C24D7C89EFA +:10E2700037DC1249C7F55B22C8C72E19D78D5B1151 +:10E28000FFDCE18106F4731EA07B7769265EFF60E8 +:10E29000C1175458967D24524AF45537ED6C1D0928 +:10E2A000FB1D0E8FF563DA94AA4906318FE81C0531 +:10E2B00072C8622F1B233C0E4EBB45C00979C9B8FA +:10E2C000EF83F4DB0DEB6099EFC23CA084E7010F14 +:10E2D00044CA689ECC07003EE101B8F00493F0B454 +:10E2E0008FCFBEDE03429E99781B2A407FCD5833E4 +:10E2F000C58BB88827AFB51867064029FB5A6274EA +:10E3000005FFDF130507774A4BE487B2C86F61DD6D +:10E310001E1FC6EDD6F255BE7ECCFF8C08E16D5CAB +:10E320001E3E3360F1B79D256C0CE601F736DC79B3 +:10E3300066C0626F3DF99C5E8C33096F06EF52D464 +:10E3400013A0F768D89B9A0B02CD0DB2A457A1ABCE +:10E350005B473B88E8F43C6EAC6426D6E3D5673572 +:10E36000EA7F15B234FC26D89A483973235DF160F0 +:10E3700092E1BC5C18237C7CF6DB04BFB05A6509D3 +:10E380000B9DE07F56901E38F2A51DA86080B77DDA +:10E39000A692DC0C781B826B28FE6C9A934BF7617B +:10E3A000DDA417EEDF33BE89E296CCAFDAA3D1103D +:10E3B000C5A7EBCCA78E4D8D3F84FAE809A6FDEAF0 +:10E3C000C34467C6AF6E8870BFFA19BC4AFFB1FB81 +:10E3D000E86BE43FA00621397782BCBF9B651F37FD +:10E3E000093BE82CE47AE87CFE55A1AF7FA988B709 +:10E3F000221D06C4B4E0946BCF37DB65BE29E478F8 +:10E40000BDF201797C2962F1CB208F2F679303FC49 +:10E41000DAD05FA8D25B3CAD68A8FF3962F824333C +:10E420009338CFC79A0948F5C719C6BBC178520CB3 +:10E43000E72D13FC7D507FFC1D486FB85F339E8E27 +:10E44000505DC8F559FA65B04B1E7FAFD16FF7BA72 +:10E45000C09F023D1D786B66E6F921B1CFCF55997B +:10E4600087701F2794F856A2FC1F558CA05FC5BE6D +:10E47000A7D9887E84E9536CF306AFB389F0F4958D +:10E48000996BD1AE99BEF80AF09BC5BA824F9DF345 +:10E4900001EB7E25776C667C25BE7E10317E86F290 +:10E4A0006A35E3BF40BB7BB9DCA52714BA921D7661 +:10E4B00056E724151807A698AFF37D043F0AA83B3A +:10E4C000CBDFA1BC68E17C85F2B4853EA8E0B2F860 +:10E4D000C9F322DE2CD4F97376DA085AFB1D855174 +:10E4E00097BDEE059530ACFD8BA86B15F6E5653C48 +:10E4F000C3BE49367BBB28EC49F5BE5D827EF5651F +:10E500007776BFFD4EC443704A54F42544FC5BEA61 +:10E51000E5F5157B11E8B3C4D7E7AA6AFF8FE2627D +:10E520008225144B5CEC1B7D91FC1D3DB1DC5F280A +:10E53000FA4EACD78E47F2591465B675415F5D51FE +:10E54000DEC750A396E74B55C6FB1E3D7679013DCD +:10E55000BE28AFBB9B94E959E919C7A667A1E79408 +:10E560009D9EA228DF97E7AA8C22C407F17938D2B2 +:10E57000D1510BFA9745BEFB26D5DE84701A4B7439 +:10E580009495BE6FDE7A0BE291634BDEAA47EDFEF7 +:10E59000B534CAFD6B5994FC4AF6752B85DCAED7B1 +:10E5A0003F5CABDD6F73D8BBBC76F67F2FAF12E854 +:10E5B000F07A139F267B9D7875F6FDB15B7A462332 +:10E5C0009F87847EA26FC77CC3D0793EF26094EBB4 +:10E5D00071784292E09E1D22FF48C38160B02F37C0 +:10E5E000541E32F31AF390CED97D7988A7F5DDDD7C +:10E5F0007958C73F3B509B350F3954D245743AF395 +:10E60000900343E4216BA23C5F3DFABF1ECA2B6A14 +:10E610002EF0385F73A14BD5413FD745B93F9B39A9 +:10E62000D0A39AA027359887009E03220F41F84D6A +:10E63000A0BA9177BB54A46BE6851E9A570363CCAE +:10E6400043660E918700152AEADDFE9ACE5771DFE8 +:10E650009CFCBE58696E885AEAADEAFE1E7A4F22CB +:10E66000E775966FCE33699FED7A736C2AA73733BF +:10E670008FEBBB136E28FDAA53FDE5D81FD8CA72D5 +:10E68000432887F7728655B2025ED7605EBC15419B +:10E6900081EFADA7F39209ACAB7DFCF9677387ED11 +:10E6A000C6ABF43F3E6117EFE5DC92147590510064 +:10E6B000F33FAB1AA9B9100FB68EFB6280F3B39E7D +:10E6C000EC6883904DED4E8DEAE93B827C1F64FE41 +:10E6D000F5D25285F24340337F01C0CF10F83DD3CD +:10E6E000787D58AFFA096E5B39CF23EF485CA4FE02 +:10E6F000C5CC7E8FAEC37846FF1A5E2FAA3F3C9EE4 +:10E7000087F9FE4734A6C2FDA56DF156D2CFD31EC0 +:10E71000EA67C8FE42556F37C92D6FC063EB73E4DB +:10E7200082274B59F2168F63CCD4E505D9FC90BCF7 +:10E730003AFB10FBA2A2FEAC64932E835C2EB14781 +:10E740003A9037EFF8DAA34FB1C1F3657FE1C149E1 +:10E75000C633A81FE3DCFDDF7E06E475E02D0FF570 +:10E760002D0EECDA757725F097E8D2A8AF2BEB19D0 +:10E77000905BD122AC675106D4973EB90AF5F2609E +:10E78000BE1C834303BA0FA6DFD77F629561199F32 +:10E79000886E398771EFE00809FF269F2FC789FE31 +:10E7A00055785EE3E0283EBE14559F4AD0FEF66BD6 +:10E7B00054476FFCA53F9B7F3C5967D7D77BAAD7AF +:10E7C000737DBDC23CF0EBAF47B3CCCB59606EABB1 +:10E7D00000791C1C70D1FB21A8B352981F3C38C98A +:10E7E0007C03E11F3DC5E57AF0AD8702B84FDEE15D +:10E7F000FD0F67F3F3BF11F1285DE74DE6FE83B12E +:10E80000010DE3D68E39CF9EA884754ECE1C3F45B0 +:10E81000051640163ECC97E57C6F1DAFE332F4BD84 +:10E82000A2AE42FFF3D6B9866CF65E15357F1FB5F2 +:10E83000C1F3F7A2AD5D1AC9BFE8D8BCDD78EE27F9 +:10E8400055D3D5A3C1FE1EF88D8B619D72A042D415 +:10E85000E143D11502BA8AAE8AAE5D33B2E81BD06D +:10E86000E5A91B3198AE97EB18C9E7C54AC387CF16 +:10E870009D7432D1C79C25FC7DCE9B5FA4BEE381F5 +:10E880007E17354F2E0DEC5651F564FFBBF354192E +:10E8900066406CEEFCB32AAA94F9886AB3BB19A748 +:10E8A000726DE3079A87DBC6CBD68ECED821FCBF2C +:10E8B000383AD636F6066FB78DC36CAA6DDC30FFDA +:10E8C0000E1BBEBA40C4369E17BCDB067FA7BEC473 +:10E8D00036BEBB7C990D7E4168B5ED794D60E7167B +:10E8E0006C1FC5274ED68633D2C7C975B00F79BD08 +:10E8F00006E9E3A3A71E0AA05EA46AE26350DFFA5A +:10E90000F27B4AB07FFD923B7BBDF6489D2AE377C0 +:10E9100009C67B83F17A4DC287CBFA6D7DF9D57537 +:10E920003C3EAFA853B2F6099CF158C66119979DB9 +:10E93000EB3BE3AE33DE2EBC6DB78FF7FB79DC5FCC +:10E940002AF4A0B5FC677EACD75F6AE07D84CE92E6 +:10E9500038F50DFA447C3EBAF4BE31F85E2DB7DCD2 +:10E960001CEE2DCDC4EB487992FD12FB3C81241B9B +:10E970005B81CF936C7505F5A5B5C8447E7F82B8E1 +:10E98000BF06AF10A7EB2D7273C6DFB06FF20B0599 +:10E990002C93AF34FCC18816007D7735EDD38AE126 +:10E9A0001AF11FD6AC7EE864CDAF8A8788D39FB4B6 +:10E9B000DBC72B641F070616BF6F1C78A385F7DD26 +:10E9C0007FD0E26329E0EF744B80AE3F6F09D2FD48 +:10E9D000575A74BAB6B794D335D512A2E7AFB65426 +:10E9E000D3F5F91683AEC75A62743DDE1227B89F7D +:10E9F000B634D2F5C51693EE6F1776FA61A1C72823 +:10EA0000977D85F8519742726DC0A3BAB32E18AAAC +:10EA1000D5CF835CFF239B5CAF359EA46ABA47A326 +:10EA20009E41BCCA6A4FDD7532AF4FEF37D125F337 +:10EA300061AC5F504F649F0EE8FB26D2E7C5FE5CD9 +:10EA4000D1F5D37750E1741D2CE4FD1BC4B3281F0E +:10EA5000FDF9D7E2B5E4CF474C267F1E649ADD9FCF +:10EA6000970EF2E72BC9EED871EC93627F91DE53DB +:10EA700038FA2005F53ACD937D90397FE07D902BD3 +:10EA8000F10F7C1F47BF25FDF6D5F2EDE4F7D85412 +:10EA9000E365C423E3F3A0F861AEA3F8512D6C96AF +:10EAA00069EF529E9827F8D9716E7101FA172F12EB +:10EAB000C8EB748355E33E33791E60F7DA92C17870 +:10EAC000DFA8E9A678BE2D9DE7BC4D79CCE0F865BE +:10EAD0009703E642D6F80E7278B3AE6AB07ED6A936 +:10EAE0003FECDF0CF1F9603FE37DB269FC7D9D8C6A +:10EAF00083072FF03EC6254D4932D8BA5AD6DC35A9 +:10EB000003AEFBBFC08AE3F8BE698C2BB41740F399 +:10EB10008E1CD07D0017EE3787E7C0F3EA540ECD88 +:10EB2000AB9D3F3989E386F8DBE49F6A357B9CC463 +:10EB30000C351D77A80956E418DF9C8157717FCBEF +:10EB40003263C0BB6EAAA9D5035F8B2F36331DF08D +:10EB50007B4B989BCE870C8EEFEB144B9F4D63A1A4 +:10EB60000EE443FBDC36FE5ECFA16F524EB2DF26D1 +:10EB7000EBF0279911C0F59CF8DBC47B17E7FB96F7 +:10EB8000F72ACC20C22B8163F4BE85AD65FC7C8462 +:10EB90000BEA1394DF304F726FE960BDDB3FE5CEC7 +:10EBA00031F564DF09E5C6D4ED5D0AD5EDA26E62EC +:10EBB000FAA75CD63A46D64DCEFAE831E167655DF4 +:10EBC000F4989B51BDD5AEE486761393CD93F8FBB4 +:10EBD000B8E61978ADA9977EE90BB63AC91FA83FE8 +:10EBE0003330355B1DC7EB11777ABF4B02E7F33249 +:10EBF000FBEDF798413CDFD83E79DD5756A2BC4685 +:10EC0000F8E8FD26D3E23AFA9BC7F1443FDA7320D5 +:10EC1000C18AA767F65765DA79ECC77640F282EFCA +:10EC200077E3F53C9F70D2E5BE46BA7023E93DB567 +:10EC3000B4771617EF25791EE913F7DB746EF70C1E +:10EC4000FD96E53D799BDFF0052CFBF828CAD93B02 +:10EC5000F4BEAAA56D01EC6777F95D64A71DBAB68D +:10EC6000B514C61D7E8DE729BA2B96ED7D5247BDA2 +:10EC700022F8E67405045D6A7831E53343ADD7299F +:10EC8000F65D8E73279A06D9951E8A63BDDBEA2F3F +:10EC900056B0CF299FAFAA57C4BE77911CB68AFC45 +:10ECA00028B7BC3BE5427D19B5662A8ACD07F9CE67 +:10ECB00079B8EF9BD84DF951FB089FED7C96BC3E8F +:10ECC00026F06D75876254BFE7BB18D6EF5B4BB378 +:10ECD000C7C387C5FEB6EA53E2089F00B98C570642 +:10ECE000C3AD11705BDC5DC100ACBB75FCBD74DEF7 +:10ECF0006BEB1872356CF48F6F7B6A937FB07DC0BD +:10ED000098F6CF1D60F23DBAEDDC43ABDED0B81211 +:10ED1000D6D55E6121340B6937DB313F81AB7BD4C3 +:10ED2000E246D4DF4BD5B92184AF535F4CA01CDB46 +:10ED3000438CFA165A61930FE97EB444A3730E9282 +:10ED40005EC8BB77A3FFC80FB96CF9794175AEC334 +:10ED50008FDAE981F548EF86DA5F277D94924F7963 +:10ED60001FF842B3319E05DFAB697BB7EB97FB0A17 +:10ED7000FA75257E6C71B22413278F1CFBD7D5F84A +:10ED8000BEE371C69F3F7F6C0ED5EDCEF18DB2F321 +:10ED900056ADAB11F7A5759C87F4CF397F6B29A7CA +:10EDA000ABB57E965837A0A0FE6FAF2ECA413FED9F +:10EDB00047876B91EB0B95E6CFEB2D71B830DA4CB2 +:10EDC00071F8BBF58CE4E8D7E38171A017FE5E15FE +:10EDD000740AE4EEFAF31FCEEAD72E47D66590DE2A +:10EDE000FA59E6F76790CB30C6F5C4CF1EEBA1B851 +:10EDF000C436109C94D7F65B4F86526CE875FDD5EF +:10EE0000F63ED307ED23FDA93EBF98E49CC37250A4 +:10EE1000CE97D8230AC5E1A841761748FB557EFE58 +:10EE2000A4580E811D1C93CA2999FE12C3F71768B6 +:10EE30005F26A33C8520478A57573AED0BCD1B2D03 +:10EE4000D0DC8C076354D47FEE772FB1B7F8FA305B +:10EE50000DCF9F280917C5CB5B51AF01AE94997FA9 +:10EE60003C9BE55CCE9840D3BED5702D9E27FA62C0 +:10EE7000829F2BC943D2FDB7D25B19E79DFD50D9C4 +:10EE80002F7D06FBA5CA95FBA14CBB48729379ACBC +:10EE9000B33F0A712D0FE5FEDE048D7592DC791EFD +:10EEA00090A9D74D9FF51C9D8C97ED81C5B63EFB73 +:10EEB0000CA94B0E3EBF7785B8D8D90B7E13F3E172 +:10EEC000E066EAB3EF3FBDEA38D6E397821E9D596C +:10EED000FC7F7BBEFD3D80C4FBF979A29F3EAA9ECC +:10EEE000E17CADC76478FECE130C515C6855B2BFAF +:10EEF0003F689D27F209679C70BC67F99F1C7FD211 +:10EF000053C6D2F14315FE59C657A641141D699D3B +:10EF1000CFFDA894C77E9157761EF9049D176041D6 +:10EF20004BFFB62CCBFACEFCCF30F4C0F44C3EAA4B +:10EF3000F4F33C54AEDF2EEAE7D6D37C3F72C5B97A +:10EF4000A141FA5A617E7A1EF67FCA5D8E3E95DD3A +:10EF5000DF38F35AAF8F25722DFE0FF2DA8DF328CA +:10EF60001FB1E7A5C3638C9FEF293419F6712241C5 +:10EF700053C5BECBF4DE669501DF334EBFFF7E2C5A +:10EF80009AC7F39CF6F25571AC7F641F79C79CBB9E +:10EF9000C8BF421CDD3ACF52C7CA730B1FB4AF249F +:10EFA000F575BAD847896FD0F992D91BF8FB9FD372 +:10EFB0000F9D407DDC0FFA8871BE3D3FB1AD02F37D +:10EFC000935754B6571FDC8772F225FB49FE18D7BA +:10EFD000534FB0FDE85C97453EFDCDAA4EF2311887 +:10EFE000BEEFD1C4FB1E67FFC8EB359A317EA76A1E +:10EFF0008C466BFF58CA6D91D0E7376A9AE97DD489 +:10F000003343BCFF9570F89918D6D3B21F553AC94F +:10F01000FC3EEEEBF4D87A15DD48757C3D9DA3CC23 +:10F02000FB77467520CB55927B61A923739EA53A49 +:10F03000F1F74146FD320FD689C55817F23A51D63D +:10F040009FD24FD4A94F7794E1F98C5E8DCEDBE54A +:10F050001DF9840FF3DE70EF6AAAD50C65691EEE08 +:10F06000A33C7F24E9BCDE3AB30AEB4CCB7B928C09 +:10F07000DF88FD02F5A0B325FE8B28E8C781168343 +:10F08000C6ED2D8D74ADD29206F253554E951B9B55 +:10F090003500CF2D7454F5C46CE31D95E619D4CB1F +:10F0A000BCF2B8EDBE3708F82C7A0175EE3992EF54 +:10F0B000692E4FCF7C85CE152CEC675BB86DFFD3E6 +:10F0C000F8212D7663FC504EEC7DFD107F5FEAE960 +:10F0D00017EF4B1DF6B6679E4E7690B63B7C6F4A97 +:10F0E000712E41F3E9DDDF4CE067D827B9DFCA9C18 +:10F0F000CFA0EF12C3E27B693D366B0FE6B3EDAFF5 +:10F1000033F99DF01EC3F21CFE6AC2EF440E63B1D8 +:10F110000B79E6E65861137D4F2DBE87893416962C +:10F12000F4B1CCB945A7BCB6C45CB6733161C6FBBB +:10F1300062F2F92763A26E03765C96730FB978EEDC +:10F14000214BFEDE24F0350B397578F8B983B98E82 +:10F15000EF3C66C6785D30D4771E9F1378AEF45DC1 +:10F16000C76201773FAE5745E722C331A4372EBEB1 +:10F17000CF1274CCEA4DB60EC32431C8B2E2B93313 +:10F18000C6CFEFA562FC3CB1276868B82F80EF6E50 +:10F19000C2D7C8CF59CAE7B32EA49F2F243D69E038 +:10F1A000CF675D30A91F24BFAFBBF3F8D83D9BC626 +:10F1B00065CED7B4633FC28FDF99F0734BBB04FDBC +:10F1C000CEABFCCEE4DE8038A793B8758F81780C87 +:10F1D000FE5D65EDF10903098DD6FF18D127BEABA1 +:10F1E000992CF885FBAB882EC7BF0FF0C0F1E01E4D +:10F1F000F13DCE1A9AD7CCE9CEFC7B07A13DD6EFE4 +:10F200007B261FAF6C12F0EB087E2D87CFA20F423A +:10F210001FA7ECC15EEA55E0FB0CD1B79CD3571693 +:10F22000D3F977590EBD05B8CFD3BAE23B9FDEF8CC +:10F230006A1FFAF3CCF7FBB7D17A5721A736C2631E +:10F24000CAF59838CFC4ED42EABFD4876F08FDBC39 +:10F250003DA648BD7A8CE86DBA61FC7F89E8717C77 +:10F260005774253E2A2AE34FD0BC60FA5CF1D78957 +:10F27000AEEBA4477E07E6B48BEF0BFE61DDA7691A +:10F280009D92109D2F8275BF7D23D605BCCF101E89 +:10F290005F1AEFFE58767FF381F0B292E2AB3A1F2D +:10F2A00022C7FF0F94B0BE363046000000000000B9 +:10F2B00000000000000000001F8B0800000000009C +:10F2C000000B93E46660F8510FC181486C62F11A3B +:10F2D0007606866816068699AC0C0C15402CC74934 +:10F2E0009AFEE540FD8B80782E10CF00E2C940DC0D +:10F2F00007C49D40DC02C49240F34480981F88B943 +:10F30000809815881980F8370703C3370E8439377A +:10F3100080620F48B41B84AD7810EC3340FF6F045B +:10F32000E2AB6484C3281E1E389D9F81A15A00C190 +:10F3300017104495CFE047B0B94429B34B1AA81F22 +:10F3400000656D40B4800300000000000000000074 +:10F350001F8B080000000000000BE57D0B7854D5E2 +:10F36000B5F03A8F79666672F2204C4280134830CD +:10F370006A8A03840882F52420C696DA9152C5FE73 +:10F38000D60E34224A2051B1722BFD726002040164 +:10F390003BBC1414E9E00D8A8A362256ACE83F20C3 +:10F3A000B5B4B56D6CB9D55AED0DB5AD2F0C88520D +:10F3B000FCFBEBE5EEB51F99734E661250F1B7F703 +:10F3C0000F9FEEECB35F6BAFD75E7BEDB577DCB232 +:10F3D0000FF287029CC49F8B00EE7003C0D8743A72 +:10F3E000EAB66FCC7DA49AFCFE7FDD916D7ABA9E61 +:10F3F00048878244EB01180045001779C9AFA4DEA5 +:10F40000A49F1FFED37985007B41010FF9945227F9 +:10F41000157C8DF4B3F7238860B9FCF3406957007D +:10F42000DB99B4DD9781B54B95E9A55A156640C6C1 +:10F43000EF8697FE4EFA19BEB999B43FFE6180B6C9 +:10F4400077C22152F84886146F737218F6AB7ED0DB +:10F4500055C9F3654006070EEF64809A34BCFB5F24 +:10F460007B83C2BB4F25F0EA19C6F712F80BD3F025 +:10F47000EF856FE4421583DFA849C37FBAF0D0F966 +:10F480000F0058DEA23F5DEE0258DD024F97570095 +:10F49000AC6CF1D2FCD2168DE6E32D619A5FAE9290 +:10F4A00026040FCBDB216992F6A16A525FF447FE76 +:10F4B0000B54796D79772169EF4DE7D540D896F7F0 +:10F4C00096EAB63C01E76098CCFB1C3E9FA52D0454 +:10F4D000071E1CDF0BC65958FE6D8A171FC75B3C01 +:10F4E00038E2CA61042F6D2F2A84D2002EDD988164 +:10F4F000F09507DC7A92B0C63981D9536124193767 +:10F50000140320F5E21B00D612B8CF0E4C790B4243 +:10F5100000F793FEDB48FF4AA8ED650F295F51E62F +:10F52000D615C4CB76F52F5D640C2FF987783B6B2D +:10F5300023CBA7E745F296799E0D9672D2FE977976 +:10F5400077BE2C1138E2E56EDD23A5C7E9A14B3F5C +:10F55000FD5724EC7967FFE5BA51877C2AFAAD8024 +:10F56000E8122DF0C5EDF71C82DB82FC74BF629CB3 +:10F570007EFB25E48F92B6151B21992AEB3D4EB9EF +:10F580001EA9374979F946159265EC7B219187725E +:10F59000F62B2C2FADF3C7AA7AC303D67186A5E943 +:10F5A00052AEBB67CA842FCACBAF982B11BE8184E1 +:10F5B00085CEC31883A2BCFCB045A3FCB8BAA59203 +:10F5C000A6ED2D5A07959F8F95191D55BDE5F0AFF6 +:10F5D000A8A748BB3B5C40F9D0DC06C96D12F61702 +:10F5E0009D3193E4578D2A1A7DBB8EF91932EA05B5 +:10F5F000C1DFAB249DF2B749F81BF59F533E56BBC4 +:10F600008CAF607F2B46C9D212C47339E3F77257AF +:10F61000CA3B1CFB4D0C1B65623F91DF7561BDF25F +:10F620008A11BA42C63DBB9CF1FF2FC7DEE9453DBA +:10F63000D833FF85451DE56300721D7CA09D221F08 +:10F640006813FBE60331CE672D0F678EBF127DF284 +:10F65000D7AAC8DAB7506FB49733BDE184AB7868E6 +:10F660002A1C0DF4E6B7F272C26748A748DF7CE6B1 +:10F670004C37B424E175C243EB5AC294EFD6B4E8D8 +:10F68000345DC9F9D0853C554CF29C0FA1B09AE687 +:10F69000B3AE57B098AE4703A6272146E05C87FC7F +:10F6A00079017E5F6A18A5A479A5C8434A26BA7F66 +:10F6B0000D9697D0BC01A5C89FA2FC31D320EDF3D5 +:10F6C00079FD29D263669C20699D8FE5EBA56EC309 +:10F6D0002CB5B65F691813D3F5493E55576EED8FBB +:10F6E000F45F6585E7395A5FF4D7201D324C925F8D +:10F6F000E363FDB5492F7F2EFDDF2E25C2B8D0ACC8 +:10F7000070F473BBC89B09C3A84A8F53B6F851C3A2 +:10F71000B496C3A3B6F29AC509D32478BB0BA2C38F +:10F720002542DFE2A9D13010FAFBA2491397DA345F +:10F730007C0CDFE9F9DD49E1F597B3F22AE9F746F8 +:10F74000DC429F5AE93726C22FEC1B85F3ABFCF352 +:10F75000D29B5F20FCAAE4BA23D4CE282499F1647A +:10F76000BCE931D0091C723806A80F94B0FA77AB07 +:10F770001C08FE23708EA3704E8ECEC802A769852A +:10F7800053C0D11FDC028EEC7CCAC677F253DD6514 +:10F79000E37E3B91B0B8AFD315413BAF00F144F4E9 +:10F7A000007CB4CE7091EF05D308EE754AB71930DE +:10F7B000BC77BF85534B206959C73F6BBA0EC7FC56 +:10F7C000588AB7EF4863D3F425F999563C8EE3F590 +:10F7D0009CFC27E6E7EE35BFEFDAE6076A221C0D50 +:10F7E000F63FBF35BEC88C68A077BD5F4ACC8EAEF1 +:10F7F0009B32EEEBC0C6030FD15F7938DEE8F478B8 +:10F80000795F21E361676A32E378F993C978DE337F +:10F81000874FA73C0A787DBDE05D6783F776179137 +:10F82000DB0CF43FD3F09EAAFCF989FEA5F257D970 +:10F83000B7FC7DD6FDE5E1AF849FDE57217511C190 +:10F84000D7828BBD49534AEBB9CF1B5F055844E8BB +:10F85000B7E0D7630E5D246386F0F597D2E3CF97C8 +:10F86000740A7736FECE361F80A4AD9FFF57F3C9CA +:10F8700086D733AD874E55BF2EF9839FEEEF969610 +:10F880004312E569E9818BE93E73E90B930602E9CE +:10F89000C7D5762E18645279DCCE588A7606F63FA4 +:10F8A000F9D4EC8CDB5BA0A395185D4F84A2D42E19 +:10F8B0005A2A016DBF8AD86D4962BF54BFD8EE9DE8 +:10F8C00019A076154D97BA80DA31D52FEED726914B +:10F8D00029F82BF24721EF2FF589EF07EBD1CE5D09 +:10F8E000594EBE13D6581A64FD91EF51AC9F53C1C7 +:10F8F000BE67832BA792C063C1BBCF9D8C65D28F9F +:10F900005F96658A9F4DDCEE5A8D761751C83E7F13 +:10F91000228676B5BFC8ADDF27F56E37436676FF22 +:10F92000FA8A9F98E8D25881F61B99FFBECBEF87E1 +:10F93000AE2A5C0713868CED23CC35B0C9B1DE0747 +:10F94000D086A3EB66589A44D64CBF23BF5AD4370F +:10F95000F55AB4D74295ACBC76C985B5716B399C64 +:10F96000578BEBAE28BF66C9585A5EEC8DBE3C91F2 +:10F970008C5F4CF4679CE0A9584D48CD949E99F952 +:10F9800065FDB5DE194902C3FACBEF2CBB36039EE9 +:10F990000815299D45BEA4C12E5F9B38DE56733CD9 +:10F9A0008651C62D7ACDC7AAF6E835DF594CAFF996 +:10F9B0002B138B11CF250D10413B7B3DC15FCC320A +:10F9C000BEAFD2AEDF8A55FBBCCED47CEE02E32ABA +:10F9D0007940F6FE9DF27517C46662FD62BE8EFB2D +:10F9E0002B9352ACAAFFF93BE79B6DDE5FE5F82451 +:10F9F000E3CCCF34CEE78597E20019A7FAB31FC74F +:10FA0000DF60D793A78A77686C37705F8DA626EE84 +:10FA10009B7D303992A2FBB9DBA81FEE160E3BC4CA +:10FA2000366968D7C40132EA33B5DC9DF6A7E1FF39 +:10FA300094AB7333D145A40B5F7D2F6FBFA57E526E +:10FA40000E16FE3D87FC723E9C7F5249B707EEEFD3 +:10FA500053051C817CDBBC4EB41CCDDB4FF4C61AB5 +:10FA60006D1AD5C7D9C67B90E8D11491AF075ABC9F +:10FA700034DDD6A2418AC8D9BF1379C3FC56227F90 +:10FA800098FE88EC1731BDB72542CBEF691947F3D3 +:10FA90009B5A0C9ABFABA59EA61B5AA2F4FBBA9622 +:10FAA0001934DF83CF8FC87835946501EDAAB36729 +:10FAB000244DD463B003221504BFCBF1BB05FED5A2 +:10FAC00072EDB332FA3D67F8A87F23C8E7E987A44F +:10FAD00081FA1B0E2AB00DB2CFEB0E3EAFAF28322B +:10FAE000F39FAA957470414FB91DA85FA5A89AAC61 +:10FAF0005B44E5E65ED89A8FFC5E54CDBE07038476 +:10FB000091C877A51A52BE101D5AC5F61A6FDF3676 +:10FB10004EA6F5566B2A6DEFE48B73A193AE33605E +:10FB2000782308A777BCCAEA57B1753278FE3EA49D +:10FB300020B44D94E9FAB9BA9CC1A168767E09D681 +:10FB4000DC0768EF879561741EAB2F50370D473681 +:10FB500080CE9787937E3690AD0DAE6B0F6CDEA98D +:10FB6000CDB4D0D9AB30FBFCDCE93BA315088F4A00 +:10FB7000E49A8C5FB8D99FC47587D0434178737C71 +:10FB80006C3EE7E298048EC24590BCAF2C5D1EC867 +:10FB9000E3F3D18C5AEA9710DFB9E23957EF48C93D +:10FBA000D86E2344EE8374B94FB433ECED7CA29D40 +:10FBB0009942DC42E12A7B3BBF6807B5B6767ED12D +:10FBC0000ED61A74BC0469A7A7CB15DEAE47EE2B80 +:10FBD00035D92A674A409799DCD8E9948D7F34E07B +:10FBE00074D8674A27115FD52C2F49DEB69332AE01 +:10FBF000B3763AF951CEAD7A2660C913D245517623 +:10FC000071BFC6E9953433D36B9D1AF94539CEAF30 +:10FC10004AB5CD4FD0699D97D3D1F467A4D33A8D1F +:10FC2000D33106363A0B7AAD13F46AB4E34FD06B96 +:10FC30005D167AAD13F46ACE4CAF7559E8B54ED067 +:10FC4000ABC1DE4ED0CB490FB1EEA4E9D62C21DDFD +:10FC5000CE143D9C7AE10559A7DFE5F6A39D680F18 +:10FC6000162D50D93EA9B21350CF43697E3F76ABD3 +:10FC7000C9ED93665A7F2DFE2AFC5F28A76E96BFBA +:10FC8000267EA816EDF07C4994EFAB457F5812CB49 +:10FC900089FD7573FC382D7F528EC614DA5F1270A1 +:10FCA0003FE2C497279A848D04A40A357A6905FA3D +:10FCB0002537CB11F4DF0A783C20F004FCFCE6D4B5 +:10FCC000F81F80E10BC13B39FC94E0BC45A1F84C26 +:10FCD000323C39E124FBCB8D645F3384F3F710F3BE +:10FCE000CCC0090D6CBDE8599FB99DE482CCFD5490 +:10FCF0006E966D7C3362BDDFC637E5ABF26DE5C352 +:10FD00005A4B6C797DD1305BFD210BCEB195973686 +:10FD10008EB69597345C60CB87AFAEB3E57BF10BC5 +:10FD2000CFB72BAF2CB6F18B39A20EF76D496074AB +:10FD3000D81E1F5187FBB6FECABF7E8B6A7809FEAC +:10FD4000D542375D870805297E04BE723530DDE86F +:10FD50001F280C242F21E57ECD30A93F403300F72A +:10FD600073B216A37957D82E5F5F4301227CFAF550 +:10FD7000AD2A780BFBECDFF824FDF7372F27BF887F +:10FD8000F55D2964EBEA06B25DC2F33593E8C76D11 +:10FD9000645C97C6D67597E01FC2CFA8573455E26A +:10FDA000F27B7A72367CA31DDEB2843D3FB4CD6116 +:10FDB000079E227F7F5EF2DB1FFED641C4544E01B8 +:10FDC0007F1155E2E7D5A727FFA58D76FC9434B8BF +:10FDD0001D72E2D0E79F33FE5AC57A01D13AC44B77 +:10FDE000CE7AE64341BB2B935D21F865C3F49BFCBF +:10FDF000D6F50CACEBD4B0F43834AF64CA7FD1F88C +:10FE0000A4AB16ED8B9C8564FE65CC8EC9387F4E05 +:10FE1000EF755365BFD50EFBA2CF3F4DE71F9C5634 +:10FE2000FB700FBCA51ADDAF89BC635FD6BBBDC933 +:10FE3000F44DCC275BF524F9A954ABD135E98F20DB +:10FE40009F9DF08546422ED91F7A597AA6F76D0FED +:10FE50004C67FB12F3D59C6405E293C771AC7DF54A +:10FE60004B4984273955863BF19C79B29CAC20F9EB +:10FE70005BFDA1FB10AE6F2AB15BD50108EF9024AA +:10FE80009E1783AAE74D0B5AE6C9ED2231FF6CF6A7 +:10FE9000D192D69BEDEB194CAFB3F2E35DADCB69DC +:10FEA00039B13B5A554AAF2F8A7D9415CE4DEA178A +:10FEB000D83E12E703CEF6FF2AF6D101B57189DDEF +:10FEC0003EDACDE8008C0E2FB4EEAE3B9572611F8A +:10FED000F9036EBEAF77D82F95C43EC2F3A300B727 +:10FEE0005F2A93D45EF1552699FD5229EC19FB7ACD +:10FEF00076231AA063D3F6511FFD1B9FA4FFFEE6D5 +:10FF0000956D7DF705847D9460F611C135C69928FD +:10FF1000446DF846225FD8D7F76A5796F5FD7F8C77 +:10FF20007D94597EFBC3DF3A4830FBA81FFC4DCFC0 +:10FF300086BF7F71FB68BB0AFF9FD947D9F8E47F72 +:10FF4000B67D94A6F36763E738ED1A61479C69FBB9 +:10FF500046D827C48EA1769649EC2CB4734EC89A25 +:10FF6000EF4E32CF5B15DD877EEAB55C5E17AAD116 +:10FF7000352EBA7EEB7968676C447D3E80EB59B4D0 +:10FF800083023C3E4F8DC0B42F61FDD84697E51CDF +:10FF90004209E8793DE7365F203C103BAF522DB473 +:10FFA000CC9FE345E061972B8FD3BBF9FC289BD70F +:10FFB000E3140FA04BD4DE52751FA64FF3F58DAEA0 +:10FFC000C7D5567CB0BC52AF27511E48FBA75D0376 +:10FFD0006C78F1D9F042D621361E28CC9E336DF1D3 +:10FFE0006CFE6A4D42BF39C97622FFD2F3721D20E2 +:10FFF0000889FA11A4FF82D8B21B311E33F8EAA592 +:020000022000DC +:100000006F615C6341D74C1ADFD85A35FA401DA99D +:10001000971BD12E9FA2E3BA0AD4CFB8023BA3E725 +:10002000A110AF0DF0731C22DFBF597A9CAF9B0665 +:10003000D8ED725957853F69587679213FD2494F9B +:10004000EFF6D9E4C365956B2A9F379D9A7C4E6580 +:10005000726D927FA82FF21CFDE41A8EF304B0E4B7 +:1000600049F9879C8F8985F2B98CA7C15AAF4EF8A0 +:10007000CD552E6B181F990B5A1EF29F7FB20A297D +:10008000F4BF141E35D105DB1F5D5AB91F1D25F0C5 +:1000900072CB7E22E866F21A9ED55AB68CF47BBCEF +:1000A0009AC5DF1768E4BFD1BDE7B392CB574FBE07 +:1000B000EA3E7A6E1A27FC340CF9B84AA6F70856BD +:1000C00094333D2EEA9DE7966CF7082CFB365DAD28 +:1000D000E1F634C18F522E1B68077C5AFE503E2138 +:1000E0007FE44CB5DB05A74BAF89FC5EC5A9F2C721 +:1000F000A71D4FD0B5B75C2DE6746DF0A2DDBF2C07 +:100100003CADCF73D4DE745D4BE9EA2F072399A190 +:10011000FF5AB794317ED6B93F72DAEBCAC09A194A +:100120005BFBA25BA1D32E63FDFA162AFA5F51791D +:10013000A91A5D07BCBCBF15FA5A13D793E36833FD +:10014000107C28895129D49F500EF41C111906CF18 +:100150004D7DBA41F7E17405AA49C3E72E956DE3D9 +:10016000A9857EBB5D3DC394ACF0FB16BA291C5E2D +:100170001C0FF5B4C6CE3DD58038F774EC1F1D7644 +:10018000C3F2D2D119E30CD4CF6ABF3ADD0EEF2906 +:10019000B70BA8FADF2D7654F6762AFCDD624FAD58 +:1001A000427EB7D07F990B764B641D8E87AF8098C7 +:1001B0004EF258540CD086E978E4C3D11A5DBFB62C +:1001C0004BF47C988AB48EFFB173A2ABDC3AED4756 +:1001D000F6C6289E948001B4BE7E6AE7482706B31F +:1001E000B8A56112D8EA3FEC76D37215A2F43CFDB3 +:1001F000C46B978469BF06F9549386C3D9EF55EE53 +:10020000D8C36E6CA73178B001F5478C637E81B09E +:1002100097B53B31B3EFB8818D285F6759F23C2E1B +:100220000BDA4E2DAEEB0419B3B38AF2BF1FF7B54C +:100230009060F6D0504EB3AD8BF2E9F7ADAD7DCB0B +:10024000F9DD5CCEB770FBA81DED238BDCB7F3782E +:10025000B36D12D8EE595478587CD63B5CEEB77A21 +:100260004D1FBDAFF0DC0ADF088C7739A8447C0451 +:100270000FE5D71AF9B13EF05091B0CBDBE9C67764 +:10028000BCEACE1CDF91ADBD88EBF8B478D9C6F7D7 +:1002900031159ED971BA6F495D44E5B398F34DF1BC +:1002A0001CA076ED5013923AD6FDE82458F983FC51 +:1002B000EC433F454903190BE915930DD41F251B4A +:1002C000DC4999CABB763BB60F1F5458AC21188144 +:1002D0009935945569FBB0F2422D8ADA706E9FC150 +:1002E0002AFBBD8BD245F6FB52258E7B1261B4EF03 +:1002F00042E877B5D42BFBF4F40879083DCEFDFC39 +:10030000E9D1AE1A7ECDD2BE5C82684786FECA3D78 +:10031000CCEE285FB39EC5813504E07531DF6148BE +:1003200057231F17832D89FB16E3399BD9C0E26B36 +:100330000635826CE5E3319E1CDA8F0B0CF32C82C0 +:10034000B7A5DFBEA2EB19A4EB44B0E9B10CFA6388 +:100350008C87C88BAB90E98FF6C434967EA4D0F519 +:1003600023BC08924B08889363B1C52EA4FF1CA040 +:1003700071E8E186E6BD185F5DDC08111C86F015AA +:10038000E5AFF00C481A945FE06098F0C76036154E +:10039000188C7C81EBCF02465FC117258DF6FB36AA +:1003A000E1067BBE88DBFD45CEFB5B8E7E8A7576E3 +:1003B0000F4A5F2403DEFB83E9F6FB3661E87AF03F +:1003C00001846F7F2092427E351DE338FA572176F3 +:1003D0008587E0F389EF4FFDE559A4FE8F16D5150B +:1003E000205EB67AA3B9F45E515BE6B8B35EFC2A30 +:1003F000EC8E2CF5D37AD4B4C5353BD3651545378F +:10040000CF2270AC081A40F59A7915D5EF0A97DF1C +:10041000E78AAFF0623CE9D2C0E85CD4B37B314FED +:10042000D2A5E111346E57F4A3F0F85D918F737D7E +:10043000EA1CEF160FD3A37F07E316C4C3284F2C83 +:100440008CF376858B1E9FA9D3F3422399A1DD758A +:100450001E3FB32F75F59F56FC93055CA372087081 +:100460005AFE85599E581BF2A75947B613C8FFC3B9 +:10047000201947FA3727B8DFBDA7DE6A5ECFA47E12 +:100480004F512F9600EBBE93D45B8BF321F50C5BA1 +:10049000BD68AF7A77F17A601BD7E835EE66011F49 +:1004A00058FB8BF4EA6F2BEF8FDA833DF5F45EFD9A +:1004B000DDCFFB336CF5B45EF51E16F0D9C605FB37 +:1004C000B83DE5E7B89371AAB7593CFDBE8A2994B7 +:1004D0005FF6574CA99F45C6B9F9172EAE23AEA1BA +:1004E000EBB6E0ABBDBC5E2BF25515DEC385B64660 +:1004F000BC07CCEF09C703D3BC31CBF71EBE0A4CF7 +:10050000D3327F9F65ABAFB6F9C01843BFD3FAAD06 +:100510001F2BDCEF9D3719FD71CB0B65EE9FFB5B4D +:10052000DC50891E1BA0DAF26D61563ED2FBB7B8D3 +:1005300089778AF83D18A22B9FAEB2C877CFF89F73 +:1005400017FCFC3C230DFFFB71A3DC0A3FCB0BF82F +:1005500045DE5BCCCA47B7BD3F092F56897B00C338 +:10056000DB0A5AA9FFE20B3B3FA9D53E3F964FCF8E +:100570008FE5C5FCAADBA4C9FF5AF3CB6DB5F31F09 +:10058000CBA7E7C7F2627E356DB9A7353F673DBCA3 +:10059000AF847A7E45C5FD615C7756E0424AFA1D1C +:1005A000D7F6527C31C9DF3E40D8DB3AD5EFA3C045 +:1005B00038C73BB6FF76BFC2E037D2D61B64E7C16F +:1005C00050E1E6E7C18930FA39DFF0683C8E8EC130 +:1005D000A978EDF9A1981F90CE935FFE89EB308644 +:1005E00029B2FDA443CFF7B3AE2D2D66EBC9B2609F +:1005F00044B6AE6B220EFAB9013554FFC435A67F5E +:10060000F60EE0FAA890AC6BCC9F47EBBBB8BE5A95 +:10061000DBC2DE0B48F0FBB0F1C2D1143F09711F01 +:10062000D69C62D36FFB6AA71C40FFD5B183EC9DBB +:1006300088A7BC6CDD5BDA021DECDD032FBDD7FDA6 +:100640002CE937462AEC21F61EA63F25F61EA6BB4E +:100650005BC234FD498B4ED39D645C4C1F6D894059 +:100660008C8CBFA3651C4DEFE2FBAB0D682F92F4A1 +:10067000CB8532F55B6C6D2196B20BFDBD5E9ADECB +:10068000DBA2AD522BD0DF1BA6F963D2B4EBBC7456 +:10069000FFDA15CF25703EF1BB727A4F7C62A14A1A +:1006A000D75F50534A6E75FABBC0EB31A9AE11DB70 +:1006B0005D1096593D6F321ECA5CEF46AC372EACCA +:1006C000527820602AA1C28CF5BE87FC5513E0FD4C +:1006D00069B17830737FB7617FA303BCBF423D1E11 +:1006E000C8DC9F89FD8DD4181E20DCB5242773BD7E +:1006F000A558AF4AE3F32D4DC93999C7BD1DEBE5A8 +:10070000E727E8FD9D8BAE066A8FBA0AF5ADD46780 +:10071000C1EB25074441267C9E5F9068C67A17C6C8 +:1007200022308C8CAF872220137E7605487915DE27 +:100730002527FD9074C274528EE74258FE254B392E +:10074000B627E9F819BC7DAEBD5C8CE76A839EFBD9 +:10075000D37869DCD56ACFE7C94C3E1F6ABB6A32E1 +:10076000CA7D1E3F7FFA35E6C9B8AE4520F411AB0D +:10077000EF67E5CF88FA2156FE1ACFE7E7B379FB9A +:10078000A67869BCF0BDB78C289E55959EEFE0EF2A +:10079000559E3DCB32BF7BBF7741F1AC407A3E8363 +:1007A0006F9D78F6AC3EF63D05F572CF9B24A8B759 +:1007B000F21255547F8EF244A97D386A608D81F221 +:1007C000ACAC6270BDEB2D6B5DA252B84C7A4F930E +:1007D000C375CF3C3B5C83E6DBE1BA67BE1DAE412F +:1007E0004D7DC3F59497E9B56CF091F10DEBF85B95 +:1007F000FECD3EFE90EFDBC7DFF27DFBF8436EFBE4 +:10080000D4E3A7AC74D97CA37DFCD29BECE36FBE90 +:10081000C93E7EE9CD9F6EFCCFCA1EBFD01BFBA791 +:1008200097DBBB8AD5EE6C8ED9EC5352EF24AF67C1 +:100830002A563B3616B3D9A7A49EEAE3F6AEAD5EC0 +:10084000B4573D9F8FDBBBB6718D5EE386787F2901 +:10085000D9DA5FA4577F05BC9E295BFBD37BF517D4 +:10086000E6E31AB67A5AAF7A83057CB671C13E2E9A +:10087000F038B05B791C189577527FE1D5649F5DA5 +:1008800086FBD0A884FB7DAD0046EDC7FB26C3D90F +:10089000BB477953160EC5F55C9AB2F02C5CFFDAB3 +:1008A000F2C0B66F9BE2637E84B13E85A65A0E34D9 +:1008B00053FF9DB7B9F872CBBDD72DBC5E4F79A061 +:1008C000B9F81B96F24B78FB367E6F70B2EFB7D457 +:1008D0001ED10691FA19FC66978AFE783914463AB9 +:1008E0000D02F75D574D1B6BD5CF5B7C2E3A7F6DAC +:1008F000281FB734335C6D656CDC7B71DC007E17C0 +:10090000F6477331C5B7C652F17D4370B6F457C48C +:100910006ABB97AEEB6EBEAEE7B99B1F282370C4CF +:1009200007CB80F7229697F6EDCF696DB19F2FA880 +:100930005AD4C07D5FC91C6D348A47B67677D7CB51 +:10094000F599CE1F1AF87C5AE7D425CAC9F8B0DF4A +:10095000EEC7250C0ED6FBC857B9630DBE4C7EDC26 +:1009600056AFCDBEC92B9A960B7DCC23DE62F7E342 +:1009700012D56B64A2DB4A1F3F1F39E8B5D95B79FA +:10098000F932DD771EAF62E7066016533F610F5EF6 +:100990004BEABCD6F15738C6F3C13403D7015CA685 +:1009A000505EDCE5EC5D157F61422BD3D17FD049F1 +:1009B000CF0381DF7713FDB686A7D1FDF8717E0FD7 +:1009C000560D276A99DF91C3A7715DC5C729D9A8BC +:1009D00042AA808CED8AADF48DB5D2CDA4F74B4EF2 +:1009E000B89297D2F79ECA08FDA5DEF3BFD3C7FC25 +:1009F000C577EBD37E5B9681BEF7A0B3D8D26FC923 +:100A0000876E488DC95E3F5D8FC1D5C3B761C2AFE8 +:100A100028FF3AE75BB7F1235FA6780BA11FF839EF +:100A2000F8AC71C07FF42BFF44E671FD01177B77B2 +:100A300041DCB7E1A5D773BFE92CEE776D8068087C +:100A40000BDF05B91EE5EC5DF85D688C85FE4FFB9C +:100A5000DC0CAE3617F5778973DF6B132E9B3FECFA +:100A6000BA8DF6FC6C9856847A6BF67A17F5AF5D02 +:100A7000EFF0D33ECCE77B1D342F433B5EDCDB9EA7 +:100A8000A5818AEFF2CC7BF2DE1ABC1FB5CFC7EE90 +:100A9000EFBD4DF846B7C8DB0D81A41BEF01BCBE0E +:100AA0006BCC151300DB279795A0BECD838CEFBED2 +:100AB0007DB7CD0E5F7FF03BE10558D2271CEA766B +:100AC00029A37FABD327CE8919BDB2C57988B88B4E +:100AD000639C8F7AFC307FCEE17E18167FD15FFB5E +:100AE00013FDB49FE7ED72A3FC34A9CDF5929C3EB3 +:100AF0009FF2B862C620324FD7EEDAD420B0D56B61 +:100B0000EBBBDED12940F5657314F948D49B0FA4E3 +:100B10001ECAE59ECB4D5BBD72526F78F67ADD5CE6 +:100B2000AFFE7CC7BFBBD11FF9EE43872E43B99CF4 +:100B3000FBB4025E326EF78E20A4E83E36E9C6FDB5 +:100B4000DC0DBB948CE7B9346280F43FF7C741BA3F +:100B50005EDEB0D3939C4ADADFF093D74702C143FD +:100B6000F792A3CF0FC275F721899DAB9A5D2371D0 +:100B70005DBB4185EF4433F437C0CFF8F0F0533913 +:100B80003390CED2F6BDD7D07E3BAE74792CFA220C +:100B9000E077897ACC1FF7A044E3A37BC3C7CEC11B +:100BA0000E3F2831F876BB923E846FFB56778CC09F +:100BB000D1B4FD3DCA57937EFC4808F1D0B45BB177 +:100BC000F9899BB62B29CF489A1EC214CF57A41A75 +:100BD000C427D38FF377CDA3FEF3F91D2BDF534248 +:100BE000D8DECEDF042F9114E2F525253215F38FE0 +:100BF0003F10D209AADEEEDC1642BC927E67BA73C1 +:100C0000F11CD8EEF7C6FE3FCCEFDD1FC05137F226 +:100C10005753C70A36DEAEAFBD81FAA5C921476F6B +:100C2000E32FC5BDCF5D2EF43BCEC1B6179C927DA0 +:100C300039F791E35B4C32EEE19DEF6C3109FC8DAD +:100C4000FFF5FE96DBD00E7AD6A7A11E687AE83FA4 +:100C500042605937AFF43379EC7EF081FBEF26F236 +:100C6000D1FD470F5D3FBA9F7963884EE6DDFDD821 +:100C7000FF29D249FD05CF5C4CFD050B9E9834B091 +:100C8000AFF513F935697D978CDF3FD77793710600 +:100C900092EC1E9E3AE8F3DC2E057C04CE775FF6DC +:100CA000D07B524DE4DBC2D148AF79542F637E1123 +:100CB000C1F3FC1DCBDF534666C2B73948C64B07AC +:100CC00040C4308CF4FEC6D72FACC6D445CF579A5B +:100CD000E028D5ABCE764D07095DCFCB4EC7E3F00C +:100CE000911BE3569A76AC60E376103A867AD3F19C +:100CF0005DFC657C6F3A7ECF41C7E3D0F8233C1F93 +:100D0000845D0519CF85C5F9D9BC27BED9A7BD25F6 +:100D1000F4427F789E2331B8EAFCC6323FCAD7CE70 +:100D200087EFBFBB90D1792A414CF723C78700E1F9 +:100D300093375D47AF41FD78F4198F86EBFD0DCFFA +:100D4000BC44E5ADFB8917DD3AB5BF2120117BA37B +:100D50001B7A7E3AD1FE982FB14C537B30E509A522 +:100D6000E9353F7979BD1EA2DF0FD1EF492607F3A0 +:100D7000937BA74B19E8F7AC9FDDE786E4008A97E1 +:100D800079ED7F72D373700B5DA57148CF4353F03B +:100D90007B367A8AF96B38FFF32D746D67F29B4DC1 +:100DA0004EBBB77A548C6B70D2B9DBC5F6094D498E +:100DB000E9A54C7417EBE0E99EAB3EE5946F3EEF7E +:100DC000FEE4BBFFF99C1EBEB6FB751BDF08BC1D15 +:100DD000FE28B3DE3FE897381CCDF525C37BAF83F3 +:100DE0002A44CD416569780FD3B7C948FA9042DFEC +:100DF0003B5DD6F11CD5DF4E3D313F8B9DFD37AEBF +:100E00009FE6EFDE3B12F5D9E17D4F517E9CBFE3BB +:100E1000901BF737CF6F7FDCDD5595E67F5C17AC15 +:100E2000EF5B1C7E74EF48AABFB1FF0CF439C6FB20 +:100E30006FDA63EFBF69C77BB6FEE79A1D6EEA5FA4 +:100E4000ED679CB755E34A9CEFDB9D2EC07793DEA0 +:100E5000EE50EA33D9412FF175B127AE2658F3325F +:100E6000FA27957CB78EFAAF75B1F112BE9B68BEBA +:100E7000E862EF56AAC6CB1E229FF13CB78EFBDE7E +:100E8000D6E015A05BF478C2814FAD50ABC5FD80B4 +:100E900036395A6DDD7F09F8F30CD906FF8260FD03 +:100EA000407CEF0AF7713ABE53A14698FF3A34A549 +:100EB0009EDE7BD464CD9771DD66FDA1DF0EF9DF88 +:100EC000A5C9A05BF86BD4A42BCE45979D0ABA6D3B +:100ED0003FB066323B0F16F35F33183603D1C36B56 +:100EE000A4A307F09D08F352166728EC3BE0FBFE35 +:100EF00010EEFBCB7ADB7B60183AEA23AA8E7436BD +:100F0000BE61B9E79C8EE3055D56309E39423701DC +:100F10002AC468108617E36C87E3BEAB83A601A2E0 +:100F2000DE309D98338CF1371CA5F9B5F57FA171A2 +:100F30008F8539D1513903309F2FB179A4E83E4FC5 +:100F40005CE397734A8BFBD20730593D6CF52779E8 +:100F50006033DDCFA03BF364411A2F22DE4EF4BB99 +:100F6000C63751C2F508E73908DF69C3478E2CEF51 +:100F70007088F8C90122EF18076B6A357C09A6A2B0 +:100F800019935CC3F17C3F21E1FC4AA083A6A5D064 +:100F900049D37CAF26A914BE57A9BF4B86BFC0C991 +:100FA0001C077CA760C73BEDEF5B15FD9518A1639F +:100FB0009CEF73EECBB3C7237D3B87E9991B73642A +:100FC00011FF1CB3EEDBE2D04871E02B64CF93F548 +:100FD000C8414EECDA1C0B9F29814E165FE6D82FD4 +:100FE0005FAC2CA2E7FBCBC37DC7752DC5F8F0B372 +:100FF000B297270678676E050A3FF383495E16E7C6 +:101000006D80AE59F91163796AAC719386ED3D1D1F +:1010100017F2A182783669EA43B922690EF215A166 +:10102000C34ACE8741E8E29D1CA5FE8F2DEE581CD9 +:10103000F97060794C62C1445189F9D50CC5CA0771 +:1010400072CED5C57DC56DC174C22796B899FB38DF +:101050005D541554FF68846733A7BF933FED71B0AB +:10106000C2AE0BF09C87C7E3FDACFA77F4FD17B571 +:101070003040E35F02D5AD37E2FBAD2A346BA857B1 +:101080000322BE25C2E216C5BEDA57698F17F538AE +:10109000E2635D7CFFDE2B5E9CAFC777E0870C765A +:1010A000B3733D7E3827739C138CCB1C9728ECB40C +:1010B0004FCAFF62FFD9E8ED7C9E02A11934AE53FE +:1010C000E57E8BDAE91AF5B71FD921B1F7361CFC9A +:1010D000746467EE48D49728CFF87E790EFF2EED22 +:1010E000D8BB17EDABD6101879F954FFE90AC1FF48 +:1010F0003269945722E9BC5DEFFDE669F4E3EF51F4 +:1011000000DF753B42E6D889F3548D3C245A0EAC7F +:10111000B2D1F993CEABF7392693BF9B34217F012F +:10112000DAEED80E89BDF303E7DE85EF5D351D707D +:101130004192941F03D6EFB1CDCC6EB8EE178FD786 +:101140001049808D1C1E5CBFACEB4C41BD1F740B65 +:101150009F84C5BA601A9DF8DE7303C7CF8068BE4E +:10116000AD9E98DF3BB3EA0F50FF4F8CBDFF3C7044 +:101170004689AD7FE0FE119DFC43BEECE5679063C0 +:101180006EA0EB4A343745ED20B29FC6FD47528A28 +:1011900020DC4E7FCAFCDD125DCFAE27EB19BEC747 +:1011A000767DD2B11F75C45309FC3BF9560E703BD6 +:1011B0003200812C788EA4AAE9F92C95BB9B7EA1E4 +:1011C000507BECA647A4248DA7EE3A2B1728DE15FA +:1011D000EA977A039AEF242B4C9ABF1DF8F384ED1B +:1011E00078F7E976BCE754DAF11B8CD8F1E8C473E0 +:1011F000EEB861B6FA73954637653E8EEF4AF20F48 +:10120000F14DF4249DC77C328F94DE1B9F73F6ACA6 +:101210005986FE927EF1E8C0DF390EFC1D873D7BCA +:10122000592944BD4596F84F3545E5CA2987024FEF +:10123000A55A672DFD1609523F7598772235B0766D +:1012400025DE0E2654A323540E459C724ECFBAFAC7 +:101250003A9C24E9CD97EF3F340BB2CB5D478B37F7 +:10126000D2E0C2F371883454E079B946D3CD58FF47 +:10127000BCBED65B838EE7828886E91DFCDCE44831 +:10128000157B17A923F54111DA7F778C3E7A19DA9D +:10129000FD4DD74294BECB1464EBEF2E9E4E0EB2A2 +:1012A00038EBDBA33218E82FD8A32425F44369C612 +:1012B0002F2E42BB6D8F4BA7EB9F76F437FF8B969B +:1012C0008FD1F01CA3584E8CC271497DEAEF3FB21A +:1012D000E7F5D0772DF651F7EE7567E3FAB4498656 +:1012E0003999F6010D01367E77E55F8A902DE77911 +:1012F0008FD27DF9F22EBB9FCDBD8BF9E1E6EFBE1B +:101300009CDAA3FB67B3F7389F38CCEEA54E51AEFD +:10131000FEEA97487EFC7FF0778CC0983AB38885C8 +:1013200072203DE33E826782C7F53C7EB3E9AF326F +:101330008DDF1C7F214828AFE3FF08111351DB3CF0 +:101340009BAE574F87A61CC074F21E89FA8F9A0E67 +:10135000B3F56D6CA7DD4F74FE64A21748FF357BB3 +:10136000987FABA68B9D0F9CFFB2BDDEF82E7B7ED7 +:10137000423FFCBB24C0D7AD10149D4E7CEE1E979F +:10138000B122C0CED3E8BDB2889A79FFD515647674 +:1013900018C1079DFF91A3105942E671A4A1A4169C +:1013A000EF291DF9809D371CF948A9CFB4BFDA1287 +:1013B00060FCB2C9CDCE8F37CD0E24179379EC9B4C +:1013C0007DC350DC57FDE3DF6243B5BEEC12A222C1 +:1013D00064BA261AB9300EE5A395DD77834471A669 +:1013E000F793855C083911F2513CDB1FCBE4171DE4 +:1013F0001664FBBFBAD99512C66F773F2BD133A6BF +:10140000EE2504AE3EF068C29241084FD3EEF7A934 +:101410009FC2BB27B3BFFBD94088CEBF7B89B978B9 +:1014200002C1D7F788709B280FEE4459A6FE4D588D +:101430004FFD57DB028C9FBBBD6C1F0E6AA218DFED +:101440008DE8DE3DE9D26504CEBB89FCE1FABDC979 +:1014500015A1709BF380BEFF07FC7E61E965B0F5C6 +:1014600076CB7EED40A0F620D2FB6080C51F15C470 +:101470002212C21DF9F84408FB3FF2A187D2AF84C3 +:10148000FB8B44BB23017E0E17347E43F9654E214E +:10149000558A915828D23006E0BCDD04DF16FD9D48 +:1014A000A69B49C7C98F01BD479F1F90D97918D9FD +:1014B000A7E1FEA309C48F49F72B42FEF0D29B6A35 +:1014C00089BB97F648A920D19FD5DE400AFD32F9A5 +:1014D00073647C8387D8A35ED65FA7DD6E450D8CD1 +:1014E000FA177500D03CDB1F097D2CF4786B1ED3F6 +:1014F0007FAD6B54AA1F37AB5D3EF44B97197A9DB5 +:101500004AC6CD57751A6F31780E93F79CE1F7E60E +:10151000F5D84513001EFB58C9E81F392B28F015D4 +:10152000FB07E26BE481A3FBD0BC8AF8A000E93D95 +:1015300085DB3DE3DF65FA48DC3368EAB94760D70D +:10154000479B7CDC8E81C4EFF1DCFEA9BFAAF4FED0 +:10155000408FFE993D85AEA7A0543D87FC35E157ED +:101560007C7BC0F50FD9ED51BC9CFF422C8E7038AE +:10157000F5CD38207A49EA5FEF38E94C8CF09E7C53 +:101580002941CA980344CE2CED9D7A6A6090AFB38E +:101590005C4F1D8789032FD6D3FC347A61E4398FE1 +:1015A000857F849E4AF35392E2D5398E04DE9EBC39 +:1015B000361CF5CB0B0AFA518ED4B2BFF393E2720C +:1015C00094F741F252E487F57B2EF121DFEF3C30B6 +:1015D000C98B62755398DD3B53F74E3781B38FF556 +:1015E0005CD9055E3D5089F890291E148DE42DE3E9 +:1015F0001F4B48FCDEA59E3B3DC3FBD822BD29CC3A +:10160000EE95ED3C302C97ED475394EE3D7CCFFDAD +:1016100017422E04BF3BF95BC8439CB4922D7684DD +:101620002275F0FDA3DD8F10E776445CBC3F6316A6 +:1016300053FB7001B70FE381112BF1CF1CB4A6EA65 +:10164000343CF758101C46E3AB170C60F873E243C8 +:10165000A44D1F127BD11207DFA41EA5FEB1A60F59 +:10166000DDB6EF02BFD9F022F07B01E257FAE4F8D1 +:101670003D3FC8E8ECC4F3A79D7FE94DE332DEE7C8 +:10168000FB5799FF04883DDD45FDB1EC3E89E0370D +:10169000A13F6A6E6E8BE7E8697D21EE8308BD236A +:1016A000F4CBF98D89E77232E80FA7DE88B8B4EF82 +:1016B000AE22F88BFC2C40DFEB70EA910FF09762C2 +:1016C000EA77BB2748E07DECF9B765F49B3CF15322 +:1016D0003277521ED93B99F9053B4FEDBC4BD8AD43 +:1016E000C25E75D613F6AA5877C479D3AF83B18793 +:1016F000707C693791A710C6C7B27DF28140EC11AA +:10170000FC9E4360F6632C6065AA8CED67EDF29A4F +:101710004D3E731CF2D79152D93B3201F62E9413F1 +:101720000E317E4390BF2B40B80EED9AD21A6083E3 +:10173000CD67EF06948E8418AECF78BD14E7F92BF1 +:101740006E97BDC0D71B911E0844F723FC2E154C85 +:10175000CFE84F0EB7F02FFE3A68ECC3FEBCF5069B +:101760009DC7200D2268EF0F523BA4088123BF5173 +:10177000977A9C3D625D27FD0D9AAAD7A21C0DC2E7 +:101780003B05581FEDA30CF4F97390C535CDF376E6 +:101790003D8F267CD3D4E6FA501FE7EBE9F7102201 +:1017A000DCCF658F0339F2CC4B83F1FCF3B51FBC62 +:1017B0001FC473ADFF548F0611CE3717FD3E88F757 +:1017C000215E5BC4F61FD738EC9CE31C7FD343D16A +:1017D000C341927EA7E5E31ADB3B240BD9F9CCF594 +:1017E000490537A53DFC3E777B0EF5ED89FCBC8EA7 +:1017F000025B5EF0E93C0F8BDB72CEBF2AC4E2686D +:10180000AEDFB1D53D48C7F163FF85E3BFC9EDB891 +:10181000377705A9FF43C0336BC72837E2E13FF7AD +:1018200078F8B97FA78BE1DF988AE773314E0A27F2 +:101830009CCF3F9B43FBBB768342ED8E9964AC8586 +:1018400084BF637BAEA7FB70E73CAE7D4D9F3290BB +:10185000D0EFDA1512B557B1FE22C20FB185CBE930 +:10186000399E739E334D47FC08B72B9C7126D7EDEC +:1018700061E7EF0DA0AF9C589621EE64CFA5F4DC94 +:10188000EDBA7EF63D65216E4FD4C0F918377F1C46 +:10189000AA7E58A5F7BFEF79B3056810D9DB2D5E96 +:1018A0009A1E6ED158CAF5E7DCDD7B9FA77CA67631 +:1018B000D6A0DCEF3CF07ACEB7F4B41EFFF2D6F738 +:1018C0009FBB87E4C700F3F3087FFBD51CEF1771BC +:1018D0007D7E1DB717C67CD8B73EBF1AF131B2372F +:1018E000BC428F5F8D7F6FD08207A1D79DF838767D +:1018F00060780EF2C7E490F3BCF9D3E1255BBB79C5 +:101900004AE67846214787838CAF1BDA2F5F564221 +:10191000C68F3FF3C6902EA6270EA29E107C0AD03B +:10192000EC463976F2A3E0931EBEDBB39AE249F0AF +:101930000791AB303FE70CE3FED0C97FFDC537759B +:10194000BBBA86A05E70F259B7E35EB448AF083107 +:10195000FF7B836E4CC1FD2A596E96B1F340A68F72 +:10196000DE5413CFDF86F2DACEE465DE938FFC041B +:10197000F5D00D3FDE10423DF4969A28C2F11AB719 +:101980002D0DE1B9FA9BAA19C2F66F25958CF18F3E +:101990003B4292784FC31627016DE66528C7FFD8F2 +:1019A000E6D2F01CAC69BB879DBBEF6278237976E9 +:1019B000DEBE2B739CC40D0F6C28D259DCAD3D5E8E +:1019C000A2DD45FD17E85FC361B29D17F79C3F7725 +:1019D000F47D9EDEB48BC7D9ECBA3463BC84884BEB +:1019E00070F2F16607FF12FC50BF9F49E0A2EE764D +:1019F0007E4E1E7FF0AE9187087C87DB7F1592AA12 +:101A0000ACFE78761E7FACE3BB3FF2CAD9F9B79B38 +:101A1000F37BDA9E48668C9F6874A542B8AF6ADC97 +:101A2000EAA2FBC0C64714FA5E1DFCD143D7F3B946 +:101A30008FFCEC0F1710F8E63EE62A9CCAA641E39D +:101A40002404BD7AE258387D6E78FC67EC7C59E757 +:101A5000F12C9C4E731FDBEBC6B81C273E2775ECA0 +:101A6000757739E22028BD3A0E4DA1F7091F3CE1F8 +:101A7000C675F6AD67251858D6BBFD9CAD3F0BA1CA +:101A8000BE403CD138004EB7EC714BA9CB7E5A4DCD +:101A9000EB51BF5D7F745C84B23896F2FBA33F25A7 +:101AA00070CC79C543E3A7E63C7A338D337A436D36 +:101AB000667C7FEFD2225C7FE7B8CC228DA6ECFB60 +:101AC0009C2DB7507EBCEEC55B8AF87DA462E6EF24 +:101AD000318B719ED76EFE269DE76C88517E9C737C +:101AE000AF12453FCB7115EA1FCB2037237299DC2B +:101AF000BC719F071FD38137B89FD3FC9DC2FF5E87 +:101B0000A4F3BC8ABD1B739CEFBFFF19EA396FF4C5 +:101B10005AF7634DEDCB3B914E6F0F36066A349EFC +:101B2000403539DEE8FBEBCA8B170FE4FA8DBE7740 +:101B300023ECA049F81DEB77BAE8BB379676B67769 +:101B40006B16F0F109DC7EE93C921665F6837E3374 +:101B5000571271F02CFE46F059363DD0CEE2593E78 +:101B600038C8F40CC6E5D0F24E576AA02D1EC763E4 +:101B70007B17251D67E2E2726E2F2770D278991EBF +:101B8000FC3E2B25F11D64C12FB3D77BECF1793DD1 +:101B9000FCE37CB7C71E3F739DC32E1369AFF53FAF +:101BA000D7715EB7F9D4E2671A5D491AFFD4F847D6 +:101BB0000FDD9F343EE28A225EDED9F1DC1FBE4596 +:101BC000F8FE9D0E21C776BDEB94E3393BC7422654 +:101BD000397E2710818C724CBE6794E340FA5C43D7 +:101BE0008733AF77AFCBA277BFEAC027B11B723183 +:101BF0008EF8ED87E60EA5FE0A077E85BE75EAD152 +:101C0000D7433AC573EF783FB6EEA7E331191E0507 +:101C10007FDEF0F03C3A4E0F1F0B3E157C9C256E8C +:101C2000CC894F67792EFACEC6F6F68B9875508917 +:101C30007FA729EE06F6DE9BEC8F20FFF677DEF914 +:101C4000DBDC32F1FEDB796C5FC8CE3B23010DFF9C +:101C50006205DE9753329DB34726C919EDFF1FE495 +:101C6000323B09DDB2983E99CBF0D7AA44B923AFF5 +:101C700083DE63A067AB08675E88CA998BC7A990AB +:101C80009EE97DF4488EFCBE4EFAB8FB87FB2F51CF +:101C9000D13F3B46BE7938C9EFFCE1CB97A884DE43 +:101CA0009109F2E3C3487ED70FFFC8CACF93C7B8E4 +:101CB00008AB6E375FB96432C9CFE7F39E2FFC24BF +:101CC000AD636D7E12553E74279EE7A83F657F8FFA +:101CD0006825917BEFE8F439738E074C1FC9E7B88C +:101CE000494AF2CBCA7EBF0C3791BFF2C736E652E3 +:101CF0007CD5E988E7C39A97C6EF2C78EA621A4741 +:101D0000FA642EF3479FFBF804FA771DCF201C0FCF +:101D1000E60EC80E47AB8BF57378E7B99310CFE7A3 +:101D20000E459F5A9A1EA3559D7EF711B49BCCEE8B +:101D30000FE3FD96789E9BF6F324E7B3534D45DC05 +:101D40008B92C3F842C9959B1F23E9B39C1FFE7772 +:101D5000AE26D621BAEF3EF2CCC0FBD8BB314787C6 +:101D600020BD15E5D89FD1DE3CFAED1CFA774B5E1D +:101D7000F133BCBDE26778BB327795EB1CF27DB4E2 +:101D800077C8CDC8F4AF483B6EC174AB16FB25A332 +:101D900007A4B0DF6F5DA3B07E03CD417C374E3228 +:101DA000981D2E1166BA9AE0236E80EE1E8E226C6C +:101DB0008FFF5094D1475374FCA06D7C2825EB26EF +:101DC00091F32BC7337A11DCD275F4A5712C2FE077 +:101DD0009B911C16EFD2293C7F4278467992837101 +:101DE0003FF52D625631BEB7EFEBBBFDEC7CB31B6C +:101DF000DB8F4CC70F34FD4DA6FBD9269C03C93F92 +:101E00007E18F8DF2B64EFEB08BFC7F85FDF44FDF7 +:101E1000DFD5BBE7B23813EEEF12E7F935FBD9F99E +:101E20009CD3BF350156517D3ADEA14727ECFE2AEF +:101E3000D5AFFD9DCFFD43E8D5122839CDF3B98F3D +:101E4000734FE17CEEBF013359118B00800000001D +:101E50001F8B080000000000000BB55A0974545590 +:101E60009AFE5FBDDA92AA54AA2A450804E34B02FF +:101E700024210B45122004D42220D0314A8016811F +:101E8000F64881B298AD98B4DB699D438520D2DADB +:101E9000A319756CCE69BAE785D61125E92924D135 +:101EA000E05432C52204254E9045A01D3BED74231D +:101EB000DA64313D824BF761FEFFDEFBA82541E984 +:101EC0003E67C8E1DCBAEFDD77DF7FBFFFFBB77BA2 +:101ED000DFBA4409600CD03F1D2403D49BF1970264 +:101EE000307C3C2311F200F47A00D9096054642854 +:101EF000C1F62AFDBB0DA06D338E3385FB6F252AFD +:101F00006C9EFC53F6FBC1462DAC86828879ED7C35 +:101F1000DEDB652B4031CE7F1154533AC0B4BEECAA +:101F20009FCFC1BEA1DB002ABD979EA0FB6775AA0B +:101F30001F459B71ECD74521BCB435CE560053F1FB +:101F400095293A50CC6C5EB88AFFE3947850B2C3BE +:101F50007D4BB633AA2FC7DB764122FEF07B7A5346 +:101F6000508E227E0B12DCE3A3E679DBB6A89BE45D +:101F70002EB2AFAF20B9134B32A2E681E3FA4FFA8B +:101F8000B09F8D7F573300A643656208E52F844AD2 +:101F90008F84F2BA3F027708E59F718A8FD39E73D0 +:101FA00087FCB217712CF928FA7A2944F4719EC77C +:101FB0003EFAC27138429EE9F604D7050BFE180FAF +:101FC000E3AFCAA3E2E80E114EA76437AA01EA8F75 +:101FD000E12017B69F810A88DB3428480486AB0CC1 +:101FE0002AF6DF04EF0B73B0BDB279C871785218CE +:101FF0004F87271ACFA445D1788EA98CC673EC8A57 +:1020000068DCC679A3714ADD3825EAFE4D9B0AA338 +:10201000FA373F561A353EDD5F16D5CFDC5E1E35EA +:102020007E52D3D2A87ED68E5551E373D4B551F7E4 +:10203000737757DD90FEF303F551E362F53FB5E3A7 +:102040002751F396CAF7CA9011E6811FFF880785CA +:10205000A462D23FEA210423F53FD3E527C6FFCD92 +:10206000FA7F98F49F1BA17FF9DE44AF356C6FB106 +:10207000ADA6D79FD05AC7905E714E14EE0AE919EB +:10208000AF0D1AACDB256C1DC89D7BF1FA63667E33 +:10209000FD5181CF95B83495D6EF081EFD5AC21672 +:1020A000D5C2ECD0FFB1456D44DE3C2A2B0DC4AB4C +:1020B00017E54A09509E54549D2E1379A4838D012F +:1020C000E4F7B33ADDEACA08F99EB373BFF29C5D48 +:1020D000C7DA5F18D156F1BDA916F09B0BD973B4BE +:1020E00036FAE7015CB72D8981822F2CDF3E7F0E07 +:1020F000DE77F4652B0E0033F56F01381FCFE53D19 +:102100001FCFE55C65521AFBC87FC8EA2492A7D9A5 +:10211000EEDD69C7F79C979E30E09BC1E0F21BC8DB +:10212000EE52CDE0B7E1FB1A0DB0BA12FB0E7049CA +:10213000F5D826C24E3BE18B622857911487AA72CC +:1021400013FBF0FAFB24D138B231B70E6600ACD4E1 +:10215000FCE1C61CE60F87718DBDA450BD9208D866 +:102160000E3F90C9AE9FBB0FAD10EDE99C91E3A16E +:10217000E17051F8C9CF379B597B69B33DCA6F6E87 +:102180006C7E2141C179CE65C3A240047E5D84DFAF +:10219000746A6586DF80FAC764826770DDB7934929 +:1021A000689FD4BBCD8A439EDAF10F95807A30B612 +:1021B0002DF1A34E60A55161E3B5797CC1B94038DA +:1021C0001063E9FA3D1FC22692EF9E6FB18D785FD2 +:1021D0008FDDC0DED743EFC376393676C46D39EA7A +:1021E000C541EDD1390BC82EF07A48C2FEE26E30FF +:1021F000903D2CF1A61B489E93E03EDD8EF29CB5EF +:102200002BECF91F42A581E43A735F6D028DBB365A +:102210009F360F0AEBC078F2A1C36F4846BF3574F2 +:102220008BE4DEA5B0F799E97AE5BDA94F5A95F0A0 +:10223000FBCE80B7FF34EA7B29B8D9BCDAFC6879D9 +:10224000517EF18D8DD5BF4BCA207FA80333F9C3D2 +:102250004E13F3878355575A5FC2FBAB53FB6E3265 +:10226000E273E7ABBE9D4CB8ACDC218382FAFF245D +:10227000C1FB07FBF4301EE71EF87302DD5F6552F9 +:102280005F7909ED00F698DCAF003DB7873DA78D7B +:102290001BB0CFFD8C78072508D4ACEBDBA786FFFD +:1022A000BCD773C612CF347E3D28F855FF5AD65896 +:1022B000E2537DC2357EF1FE2B9963895F3324CED4 +:1022C000CBD879BB905F4A16AE1B79A520AFBABEBA +:1022D0002A4B223FB1EFB8B388E4D483F76AE4BA5B +:1022E000F6BDBF2A97EEC359D70DC94BB6E947399A +:1022F000EF012E678FB08F15C1A422D23BDA9DC5A6 +:1023000081E356FDC76BFDBF257C3AF7BCF2388DE3 +:1023100029BE313C34FFB4379EC7231071CE2D70D7 +:10232000C13897AD47510721DE4DF9C2F5FCD65EA5 +:10233000F20BC8AB2B3A747C99E4AF2A81FC82057E +:10234000DC0AB5E865DE9B8D7A6C3CA083A7B16B97 +:1023500023A7A6F99F12ECCB3AEE7FB06F4EC1389F +:1023600022FCD324C7BF2EDACAECC7635D3383B91E +:10237000442657F1E1AA0A7A2FF4A21F47592BF1FC +:102380008FE2C16CD874280EE59CB103F3031C37AF +:10239000F32CBFAFF9F55921DD1A63228DFBD91754 +:1023A000B28D208A8E03B30F977F4AF3CE8688E7DB +:1023B00046890FB31C7F5F7C98EFE0FE2190CDFD36 +:1023C0007B2014AFFAD3D9B44595F9C817278F1FCE +:1023D0002D8839D9B1511AC836A31F5EE468DEBE14 +:1023E0007D02D26122C785FA8DF45B29623CBE96DC +:1023F000371E9EC2FC21FC05A522BCEC42E61879E2 +:102400008AD1EE78307647E59DA123DFD8FA701D9A +:10241000AD4EE5BF485F4398D7905F88D3F7191D4D +:10242000A3ACEF4DF2AFC8FFE71C3A26AFB943F2B9 +:10243000A8F87EB3E20109D71067B74F93A5F0F86B +:1024400032078F4BB547CEA719515FFDBAE3B63CB3 +:102450009CBFA6FD0D1B2E1F7E6CF3AE73E03CD51A +:10246000E73E9841A10B199E569940386524923D4C +:10247000E5EBC1AF2F1C29876F072E06295FB72315 +:1024800089B5391D125B9F2FC4D739D0D1E88CF4A0 +:102490001BD79EFBCFCEF1A4B73D636005F9E3FCEB +:1024A00060D106E231C962405DBCFE552E9BEF094A +:1024B000473ACFAFF5A0A7EB00AA6E290EDA63C0AA +:1024C000E770DE81AF64364E9B37BF63AE6C471E4C +:1024D000E5859A0E525E18173429A4E7B89781E370 +:1024E000128C637ED1D7B510287F1D74805BC2FB30 +:1024F000ADF1431F132F863A4DCA2E89F06B022788 +:10250000CEDF6AE4F133070DE10D6BF8BAF6BEB821 +:10251000E0CF81FC15F2C3A3D27D7D13DC628DC4B4 +:102520003D81C9FF4B07E7576B7C486725BF8F9CF0 +:10253000DCC5E40ACB09ECBD9A9C39AC0E68350EBB +:102540005D78DCC5E4B2131F7280CB09C12CE515A0 +:102550007ADEEE61EB88B32B6EBF34522E5F01E65C +:10256000C56877CF6E816B764E76EF8B0FF7CD68AF +:1025700013AD1920FCC229968784FBE8B04AC2CF6C +:10258000BFF1CF67B66F9DC3EA23BF8C7CB0609B61 +:10259000E0A47572FBC2B2C933A690E3E0469C2C5E +:1025A000667EFFDA78E4BB95FA563ECE9D68B79416 +:1025B0004BCC6E80ECA64EF89987A4D085DB50B545 +:1025C0005F860E1628284BCDD1B7196FAB75C19712 +:1025D000F2F17E59BC3748FEF7AD8F7460C3F57FCA +:1025E000FE5A9C5A817864EF6F4EF65847CEF7D466 +:1025F000D92DCFA792BEF74B0A228D79E1501AC987 +:102600005717FCD4E8C17661C7EF8D149F5639BDCA +:1026100047C80E4A3A1AE6117EB3A0A9D16E657E6C +:10262000D14B3C0DA470FF317C6AF2AE8608BC2F02 +:102630003978DE0243DE9BC96E82C23EBB28FFC1F1 +:10264000B65DE461ED0756662AF9E1E7FC703015E6 +:1026500070CE2D70389570D6AE0FAAFA45C4A7DC9F +:1026600033E6D59E08BE5D10F67E41BCEF1F9DDEB1 +:102670008F0887EA039F186DB82EDF1F0269149F29 +:102680000298A7D9BFC32FFA62ECC6A71F32D2782F +:10269000DF45607E04F5BA3511F5B4E74CC79435D3 +:1026A00056263F24E2BADBCF9998DF6C4FE7F6D786 +:1026B00070FA7201F9ADCB9DD537135EEF3B0C1A62 +:1026C000CFCBE2C99EF602F3639A3DE6913DA2E8C4 +:1026D00079C4F362EAE7B0F95A8DBDE5CCFEDA754C +:1026E00040F6873C67BC479EDB29FFC8B323EFD980 +:1026F000F359CC9E5B7B31E061DF8F7E7C12EB97E0 +:102700002DA37E6BEF7C3BB3671D425B4876193A85 +:10271000C8E609604C23D549501999A796396C4CE5 +:102720005ECD3F563AB8FF0F642B896E5C8F45969D +:10273000A3EC20225EF2BE88A72B9F37FCF4C509CC +:10274000644D222E88BCAC4BE4C1E02D62FEFEC776 +:102750002296D5BF53BAB805D75BDF2373FF2F7816 +:102760007250E4C98737A7B03EC50B05F5341D5B31 +:102770000FFAD3199E4DF3D0C6A06451D3216A4BF2 +:102780002B03F3107198B3A2F790819B732EF1AFD6 +:10279000EDE00F72F5C4F77326884311DBBE19FA1A +:1027A000F875C4E1912EC47F94B884CB61FC4304D6 +:1027B000181FAFC79B41A9EFAED96E4CF99F1FFB05 +:1027C000037D1CDA0F1103F1C87B7ECC4FFD28502E +:1027D000BBD333D58938FE36C93BD589380E9EF830 +:1027E00026997C7AFBA94F6CE4EFDB8C9E5CE25966 +:1027F0005B06D60BA3F0738293F3A7D8149DA76B47 +:10280000ED5227E7FF643F3C43FCA96B93ED2AEAB6 +:10281000BBBF4DF618318FBAE0F126EB11D28BE039 +:102820005F3E9BE2BBA87FD771D8611DE52F18677B +:10283000D6BF6888AA4B6BC4BE4616F46D4B459C48 +:102840007C2F4BACAEDD18938FD450FE5240F54533 +:10285000B391D653F572CC3C94C714D0B8EFAE7395 +:10286000973AC53E472664521E833C62F5F4D06910 +:10287000D9BD8B62A01EBA4DC8DF3D3A8E13FA4D0A +:10288000668F5A3E637279E691DDCFD3E28AA85B08 +:10289000875A2595D9CF6EF4F3D82FBDA83403C736 +:1028A000E154CA0C5A0FE765A99E8F2F0DA633FB82 +:1028B0002BF1603D8FEB5E8FF5BC4AEBD6F23CD539 +:1028C000C0D68FE197E579B3406DB4E1B80DBB2573 +:1028D000B6EF53BDDB1095E7F9043E353B4E1CA126 +:1028E00072B23610735FE0E38BC1E70DFA316B24EF +:1028F0004E8F3A45BE97066991F91E743B47AD0B62 +:10290000347CB43CFB4F069E5F7C20E6D7C6FD8B33 +:1029100093D7E7751E60FB4735AAACAA3C1FB4AE3F +:1029200041BEDC2FF872BFE08B0FF8B8DADD921AE7 +:10293000A278F533AE7733FE112EEB026B16A42A84 +:1029400023795525F0D8D86260F92FC02623D9E71E +:10295000C69D31E3042E5531B8D479A518F9783ED7 +:10296000FEB7CA576DE0FB35D5C82FBFF2FF276F02 +:10297000ACFEFE5DD3DF149812A5BF454937A4BF56 +:10298000D83C79EF9129167A7EB83B83ED4368BC39 +:10299000899D6781C8B317EEE0F9687FC73C4B3E5D +:1029A000D553C7F56E09E729EAF95F5B3EE251D8D6 +:1029B0002943054E31182C7AC68FEBDCD73D71992F +:1029C00082F1A1B047CFE24B514FA14A754D614F03 +:1029D000A1253381194F12D50B380F8BCF83C72711 +:1029E0009ECC233FDB3DBF98606F385E68A13C62A0 +:1029F0001FF07D0DA9A738A92F22DE743BF9BEC6B2 +:102A0000B694FF7996F2FC857B0D6ECA47161A863E +:102A1000DE9FEDA2F7EBDD0DD8AFE959BB258EF4B3 +:102A2000FE9AE4A674FC486FBDEB47A4DFA0C16E1C +:102A300062F23E7C90EEFB5B24F7241CEFEBBC3D86 +:102A4000B715FB85CD456E82597B5FA14379A18285 +:102A5000F2C5711656C72FBCC9C0E2EEA5F1965F4C +:102A600053BE54E5695E40FEF8D2DBFB8CE40F06F2 +:102A70005B2548C1851C4939F41B3FAEF3D29B2727 +:102A80008C9494CF6B3B61ECFB8E7CA25F9521C450 +:102A9000EAF72623D541B5CD5ABFCF487AAA14F913 +:102AA00055DDCBBF67FD2AAA13F07D553B6555C1A7 +:102AB0009F873ADF3212DE752D128C4D8FB8FFB230 +:102AC000C4EE6BBC5F0B9C076B857FAA16FB90D591 +:102AD000B40F89D7613BF7371AEF1FD8BDE40885DB +:102AE000EF754DD17EE841C1F30D5497B2FADB6B1F +:102AF00024BD6ED811334EF0FCC1EFE1B93549F871 +:102B0000F31CC8219E5F9ECBE3C9E513F1963C5CA4 +:102B1000D7E563B21BE03BF9CEE2EF71912F0C8752 +:102B2000742C9E69E3063AFECCE28DEFF8B091F288 +:102B3000DB05C12F983E2A8207E613DE7782B7862F +:102B4000F0BB3368B193FD57F4717F501E34A9B4C4 +:102B50000F7E2704B6929E07BB5EDDEA24DEFC1BD7 +:102B6000E70D087FB741E0BA41E0BA011D7E12BA15 +:102B7000D8AABC032F61BA0FE5C0FD507940F8A177 +:102B80009DD13863E4B98FF4551734C1D378FF0E63 +:102B9000E18FEE68E1FE28364ED6897D80C171B99D +:102BA0008BD97E2BD6BB94C7D5B444E35F27F605FB +:102BB000EA62E2F0CD497CDFEEFBEAFF583DCD8DC5 +:102BC000D153C510E74F39C53D5C7F77684B1EED8B +:102BD000DB6978C5EAA95BC94C1CAD9ED5DAF7451F +:102BE000DEAFF517237129DF0CD89BAC9175FCABD8 +:102BF000493CFE54CD92FDA4E76BF5CEC443058A53 +:102C00002E5CEF609DB332690CAF7BA6E1D4472701 +:102C1000C8E07285EB9DA7525EA828A47CA585FB21 +:102C20009181129C2F91F27960FECBD76252A94E0E +:102C3000F1217F589D43BCC1B63228DD4EBCC1FA9C +:102C4000611DCDBF84B68E1187251D3CEF5932FF23 +:102C50000BC6B76313F97A87F5CAD8D1EA09AD8EE6 +:102C6000A8FB8AE7A9DAF53AB47B1A5F1794585D96 +:102C7000DC76F0EBB474F49F839D57D2D660FBA250 +:102C800058BF96A70E619E9A21F214CA9FD77395DA +:102C9000C1064C871F431EAE17710EA4ADCC4EEA81 +:102CA00028D925BEB54B7C1F673F5E9889FEF78308 +:102CB0007896C70C9CE1E743F4FC1398470DAC0DE4 +:102CC0001C76E2F8CBAD128B7FEB31C7BDB570A49B +:102CD000BDD70A5E36C01651976D656D79F6DE4F29 +:102CE0001E277FD46256C8BF0E74341AD9FEB21A9A +:102CF000F17CC6C87CA856F0B7F67BF6B55E4D12DF +:102D00007152F012D7C1F2DBC163B2DD2431FC7E17 +:102D1000353E122791FFB41D8C637A1E3C61552904 +:102D2000CFFF5CF0EF92D8776F2891192EBA59BC7B +:102D3000CDED7A2B83F44A7AF0D23E4AD75B533CEE +:102D40006C9F4F65F654BD5BA6C3BEB0FC010BDBA8 +:102D50000BD5FA1ABE3E812FCA35D9E80ACBD5AEBB +:102D6000EFB3B947B11B493AC8F4A693A2EB5CDFB5 +:102D70007EB9528DB0275CCF6AF26FFB053F403FB2 +:102D8000944C7EB9334961F23504B99E759DBCC53A +:102D9000F72FE7FB3606F6FE11F7CBFC3574FF7212 +:102DA000BA05184FBEF25750FF910C99F9A9473E4A +:102DB000A8CA8288F783C4EB719F612899D5C3277D +:102DC000744C3EDF89E1E48956F283CDF3ED79E47A +:102DD000DFB87F389261D948FCF6D37BC786E759C4 +:102DE00098C4E33CD07A53289B7991CF2BD6BB056E +:102DF00096321CB6089E75897C14EBA633648FB19D +:102E000075D3F5F2DD88FA8D3D7F79AE72F247C851 +:102E100083C2637A3FD5EBFBCE723FD1D0B9E17765 +:102E20005407FBCE9B80FCC4235D1BB2280E83D7C6 +:102E30003B95F2BBCB5D0F4E65FB97D21626979F55 +:102E4000E44BA1BCE97432E543B59DA793595C6F8F +:102E50009FFE02E5499817DD41D7315F61FC2BECFD +:102E60002966FCDB77BC3829930407B785E6AD3DBE +:102E7000A6AF247C6A8F15BF5741F94B4F19CB93EE +:102E8000B4BCA888EA71CA938E4D8CCA93FA057EA9 +:102E90008307E2D8FE8704199C3F30318A3F356DA5 +:102EA000EFB07CA2A643F644F2E8DA732E3DE38D40 +:102EB000C1A5B0F91A029287F1632F6F6B3AF6B190 +:102EC000F5551B024CDF0D2D067EBF95B7004DEC6E +:102ED000793F38FD84C77B7409F5506E5427D0FEC6 +:102EE000FABBE9BCBE88D5C77617DF4F78F79CF7E9 +:102EF00066E2CBBB73BD59F651E2861FCA78DD2D61 +:102F000009BCDB0C2CAF8C1DB7CDC5F77B6C491011 +:102F100075DEA8B5F52ECE9F7223DFA78ABD7FABE5 +:102F20008BD7CDF8EF191DF2E26485C1FEB4A82756 +:102F3000C6A1BFBD4BF8DB65771A58DE71529C33D2 +:102F4000DDA5F9DD121EBFB5FDFE253BE1492CFFD5 +:102F5000E14BC863E7604B3CD17EEF6E915F2D5B28 +:102F600014735DE453777F4F3E35C325FCE16498CD +:102F7000CCEB06AB85F645BFEC36D86526B73AB143 +:102F8000327FE43A357F73449C0F75A31FA4B621AA +:102F9000E743B64FF5EE8173BF71303F1A07197CD6 +:102FA000DF91EDD7D75E67BFBEE19A9DFE308A778D +:102FB0009A9EFA29CFCF1BA9A7A502EF5AF3252382 +:102FC0003BB7844DDB7572F89CD264F07A52711D68 +:102FD000868EB9213ABF6CC831B17CA9FF764925EC +:102FE0007F8F72A69922FC7DFF389E7F3DB25C6286 +:102FF000FBC207723E6471BC36D46B245E4D6E5BBF +:10300000F324B35F3F9CA27A49D3E762338F9FD703 +:10301000F4A8AD976E2AB43EA79FFB65176B693C79 +:10302000C5CBBB447C5C5C12ADBF2CE85D40FB2390 +:10303000F77824962F5D4FEF4B574C7B87DCDF8D65 +:10304000EAFF9F5CDE875D64EFBDC3CB697FF7DD80 +:103050009C4FD328BED65D87CF7E81AFCFC2CFC570 +:103060007C167E1EE6CE521AFB101FBDC3BBD9458F +:10307000FB4FBABFD8A600CDD3F7AB7A89F4030CC7 +:10308000FFEBD9D13631EF36979DDB8B8B9F0FC588 +:10309000519FECD9A04E203F01793776CED7B0FFB3 +:1030A0006801E969E0C0B10263843E2FD5A33FA067 +:1030B000F8D2792859B146F24D27F8A667AD242DEC +:1030C0001571339A7F97887FA4FFBD87EEA2BAB0AF +:1030D000BF6D994B5222E26AFB49DBA48879FB83DE +:1030E000321B8FF5D8E4BB1322E57C92C9D91FE0CF +:1030F000F301F44D5E961F79BF919F1B99FB188FCA +:103100009FCADEC4CEDD351EEB81F3B8AE6309B0D5 +:103110003825D61D30E20FAA33BA4C2A9D53D07EF3 +:10312000BB23C24E8E0A9C67627140FC9C057E994F +:10313000E69D8933DE4B7D3D84E84C6E3684647EAB +:10314000DE3D0188D73304AF67EA4307A402368E19 +:103150009D4B95422F1B772B0CB1D603763DB56561 +:10316000E0666D89397407B993BC40807D97144A35 +:10317000D63B2E98D951298CA6BFF0FAF57041E3C1 +:10318000290EC6A487EDE3C78E1B1676EFA6DA825A +:10319000F4DC0F6C1FEE16E893E925B3F5B088BE9A +:1031A00027BB450FE6789477EF611DB3E7AE3E4548 +:1031B000257FE64E12CF7D86CF617FA687DB2D85EA +:1031C00020FA6E455B6F2C0EA5381FED0BCED46335 +:1031D000E5CB700CB1F7DD4682E3BAE782A2A7FE29 +:1031E0001F5DE9623F85D769F3449DA633FB191E35 +:1031F0007F12F191CE736C384F69930467E97C2696 +:1032000093AF579BBF14B3C1C4421ACFE31B6D8564 +:103210009F75F2731E1B3B9F9B6F27BCA450B2EEA1 +:10322000AAE5C6711D4C0626B7EDFEA181C78BC36A +:10323000E75DEEE0D1B3F45D8EE4F1B0EF7ADC66E9 +:103240006B88F27364C7A5C8BCFBAA6BED5FC9DECF +:1032500025C5CEF0022F28947F8C0D7FEF02579367 +:10326000C2DFD3108C1793C3E7FBDAF735BBD5A5C4 +:103270008A0EF5B2C26576935E0ACD6945540F3663 +:10328000DBBD7F75B1EF6C5A26B1C9F4EAF4CA848C +:1032900030DF2DE02921BCB5737D49E8EF7AE7F6F0 +:1032A00064ABC4730BBA7DFA2EE819B417B373B4C8 +:1032B000EF8FF8793E5AA142DF1DC113F314FA2EA5 +:1032C000609BC3EC7E5AA2141FD76709AFAFD1CC65 +:1032D000BF276834F3EF0260EB74B67FF690388F47 +:1032E00068B4EAB2A9DE6A84783795F49ABC0F25EF +:1032F000703E3EF4DF16763E1A2BF7D7F1DE9C3196 +:10330000D3C3F23F2ABBCF62EE1385E71C0D4F5D9E +:1033100018CF156A46639FC2F09B46CF4F33A9373B +:10332000D1BEC82A13FF7E49C30D15CA486D17FACE +:10333000D0F0B393BE691D1ED4B7C6978C307ECF34 +:10334000C473DC0CF4E544267B56217F1D8BCBFF38 +:1033500001AF6B7F8EF0290000000000000000002C +:103360001F8B080000000000000BFBCACFC0F0A3B9 +:103370001E8143D1F8E8389D0F534C941182D7B386 +:10338000E0D78B0D5B3122D8FEDC0C0CCA9C0C0CF8 +:103390002A40DC07C4FD40FC1E880DB818180C81BB +:1033A000380DC84E07627B2076E386E86966676061 +:1033B000E806E2C9403C9B9D74FBCD251918CECA96 +:1033C00022F8B2720C0C510AA49B338A87267633FA +:1033D00042E5C76BA3F2BB7419184E23A949D02646 +:1033E000CD7C466306062663DCF271E6A8FC504BF2 +:1033F00054FE5D3354FE4577080D00AEA32483B818 +:1034000003000000000000001F8B08000000000007 +:10341000000BC57D0D7C54C5B5F8DCBB77EF6EF6AF +:103420002B9B0FC20642721302040CB8C480C14A1F +:10343000BB89A0A0C85B502B585F5D02242004828A +:103440005A492BFE73212104126041D4A0881B3EEF +:10345000142BD8A0A0B6B576F9D0529FCF4645A57B +:10346000ADA50115D4024DB5C8F63D7DFCE79C998C +:103470009BBDF76637E0EBFBBF7FFAABC3DC993B44 +:1034800077E67C9F33676665318564E6117211FECD +:10349000BE47C8040B21644CBC244155206309F984 +:1034A000919DE09FD6CF5C36D61312B511129B4B7F +:1034B00048A78B76946AEDA49896B7DE28922C42A2 +:1034C00052E17D859026A1F6C8E05242D44122D92E +:1034D000491FADCA999E1A72251F77371FF7B97A0F +:1034E0003B961DF55E2C9FAFF761B9AF5E21D161B0 +:1034F00084BC585F84E5CBF57E7CFE8BFA322C5F72 +:10350000A90F60F96AFD242CA3F5412C0FD6CFC07A +:10351000F2707D08DF7BBD7E1E9647EA6BF1F91BDA +:10352000F57558BE59AFE2F3B7EA9BB1ECAC0F6347 +:10353000F94E7D1B9647EB23D8EFFDFA5D581EAB85 +:10354000EFC0E77FA87F19CB0FEBA358DE4ED20860 +:10355000E947C86DB79DB7CFA2EB1DF6C47DEF4C10 +:10356000CE2464FD18D10FE01AF6C4C7BE50717C9A +:10357000DDEBBFB1CCE8480097EF1301C759EF2648 +:10358000D8BEFEC0EF893292907563BA7C2AAD4FE7 +:10359000E6DF19BEF3A87D5671BC9F799C4F8885E4 +:1035A0008D63A5EDB4DFD0CDACBFD63E19BE3326BA +:1035B000DEFE54DB3BF6D92E7D3B7BFFE92DEFD8B9 +:1035C000017F6B63128922DE554268E950BADBFA4B +:1035D000513CA71CB3115B3EC5BFD241BAE838EBE2 +:1035E000C63D12154B61DDB49B02EB7C9708140EAF +:1035F000AA9B203D2830C6D5F1EF5C4D449CC7B056 +:10360000278EB2EFDC7A1ECB57FF211342DF5B77A8 +:103610009B1071D2F1D78DFFC217007A539FB10072 +:10362000BD21B92AF09F2E5F908EBD7EFCFB3E959A +:10363000C269ED37EFCE980DF4379AF8E17B6B0F46 +:10364000FC9C28D03EB21BE1D7C0D7BD76E6AC3C8F +:103650006F7172BAA49444C432BA5C17094412C0A0 +:10366000F75F0108143E166F04D7E4A0FD12E1E1F4 +:103670005F898CFDD6BA83EF015CD4DBACFE9D7410 +:10368000DED7F9A3E4942B3E6FA87F44EBAEBF478F +:1036900089C50DF3FECC67A1EB7796C957A5D0D9A4 +:1036A000B8BABB8FC1FBAE6BAB02B0F675A3BB7CE7 +:1036B00055B4BFBDA813D74BFCC43F848EEB285232 +:1036C000C9EC62808305F16A9ECF6C80773FC0D3DE +:1036D000573EC0894687EFDDFAAEBD52D7FF698DF0 +:1036E0003E04465FA4356A9FE68EB73FA1B5A7307A +:1036F000FA217663FB66131D939C24ED560A68C479 +:103700009718D92920DCEDD347F69E776BF4B7C81C +:10371000072E7FD41E4AB02ECA2776903BA9A5A2B9 +:103720001FE0B56E3CE597E2F83A2FC577CD1C2E29 +:103730006B4BA7BB61FC4BC9AD911D2289167199DA +:1037400049FF7FE5CB0E3AF3787D7434DD50BFEA54 +:10375000C80043FF319D0586F6AB8F8D30B48FEBEB +:103760002A31D4BFF3E93586FEE3BB2B0CF5EFC558 +:103770006E34F42F27B718EAD7D97F60E83FD13BE2 +:10378000DBD07E836F81A17DB272AFA17E53D10366 +:1037900086FE37FB1B0CEDFF52D662689F1678C879 +:1037A00050BF65D2E386FEB705B71BDA6F9FF1AC59 +:1037B000A17D66E80543BDC6113A0EF8F9C1BC5FAC +:1037C0001ADEFBD7DA4386FA7B844C4A845F2230C8 +:1037D000394329C87BEA0ADE9F8A382FD01CD07172 +:1037E0003F46A745ED49E4246F7F66C73BF6B9061F +:1037F000396965749CCDDA7745DE49FCFE20CE2719 +:10380000A4D33EDDAD6F67F3BAE21F54BE42BBA442 +:103810007E2BF9EAF6FAB1BF2657297D13720D8582 +:10382000AF3A5055F17B743C2A2F2D6CC9A48E30D1 +:103830003945C8BDF85CD3FB2487442D74DC06777A +:103840004EFB1A80091D5BCA847AF136A88B4A8028 +:10385000742580ABC52B1BF064862F71A55362EED7 +:103860004BCEAA083F75222992E0FB82C3BF9CAED3 +:103870005722A101027D7E410CF960F24B2DEA6FC7 +:1038800042F9F1FECBC7D37F42FF13426405F657DE +:10389000108E0D234900F4869A2D4776E6233C6D61 +:1038A000204FB4F7E803A58BCD57BD38D85067F348 +:1038B000BD64FDEB61C6BA36EE4F8CF0A47086FA9B +:1038C0005DBCD26BDD7E394EB716E8C7EA8A289018 +:1038D0008B28078DEDDA772EA4784691548A473BE2 +:1038E0002B973A3CDBA0BC90921B211E428AC5500C +:1038F00005C04DAD60F0518F3B230D385EEDD5C155 +:103900009100DFC4F602212B187F7C3859D4AF23F5 +:1039100019DE1AC06E1BA6A3831C3FCA71BA6AD4F3 +:103920006FE6FEB70B321BDF455145C7B711466343 +:10393000A996D0EDC218586D9048384F3F0922BE65 +:103940002611B04BED1A3CC373B1EEE276E601F7F7 +:10395000D863218AE7B501D90F63550A0AC783DF07 +:10396000077AC056269235B4B65679C70EFCD19C5C +:103970002F67835CB749B5C44BEBB642CA0709F45D +:10398000C8E21E39F120B91CBBD88CA722FA3A9B99 +:103990000741386AF30F0FEAB417005D8EA776313E +:1039A0009DEAFA6BFBD62F2B397C5BC02EA6E53A3D +:1039B000657A2A41BE253381BE9BF3B344E4530E9E +:1039C000A71EB8E4BF6F073E5DCDDF5FEB7F07ED5D +:1039D000F4D59A1E37C1B179F44984CF2C81E9E33B +:1039E00096918E19910470992578B0BD19782A1393 +:1039F000ED2BC65F267AA12DBE4ADA6E57BC256B29 +:103A0000E8F813464A33812EDC6544B121FF065C99 +:103A1000D9F4FB0EDE5B524483FC706732BAB57F8B +:103A2000284414DADFE563DFB3B9482480EF2F318F +:103A3000E0C551169A4246513BE91F167C8FCE9144 +:103A4000D9114727233F5ABD6C9DA488E1C94BFF7C +:103A500077B1808EA7C806BDB1BC5CF647E9779602 +:103A60007A5C484F563D5EE9779DDFBC1084F15784 +:103A7000E5DCE3584EC7BF50DEB40AD8D2F2E1E429 +:103A8000CF80EF2CE6FE83A6FF6E70023ED04A6721 +:103A90009787443360803BFBA403CF87ED6F1CD630 +:103AA000CDF315C19D89F2F56A7235CA854BBC7F8D +:103AB000A13EF2C6E121080FF172E879A589AF9B1A +:103AC000F235BDA5FAA6E9ECB2F302D36B442D475B +:103AD000384B9C9F9BC6936EB05BD7E5CBCA0ADA86 +:103AE000452A93A3403AF0D74DBF0FB6190179ADDF +:103AF0003475B2E73F32C8CDD5FDA7FAA37DC04DDE +:103B00002A34E99B4BACBF0EE0A7EBFF31C0CF19C5 +:103B1000879F8D0453A3402FE149063F7655F9FD59 +:103B20004A94FE73D580470227880E8EDFA37CA8B7 +:103B3000E30F5B4E84E8BFAFC9C55BC44037C861C3 +:103B40008BEC4739450A64F447CCF32B1299BC89B6 +:103B5000C3D92E111D7F902911843BFD0BDAB33898 +:103B6000FCE85F8AEFF57F00FCA88E8E3A47E1F310 +:103B700046A984CE2793A8CE2BE9FB1291A03E48FC +:103B8000CC47BEA5ED13E474E0DFEBFD20079BB846 +:103B9000DF47BCED3EBD5D3E4864788DB7477CB7DE +:103BA00019DA99BDD3A4D9F5DEED06BAE8793F8DCF +:103BB00024F43FFA89CCCE1E247A39FD6C47FF6D80 +:103BC00075E69418A02125FB7A7F25F0AB97201C81 +:103BD000343DA1E905AA2F0689FDE2E3C98541220A +:103BE00060BB51FF2695D726BD9B52649403446F5A +:103BF000CF14C07F73BC482FC4ACEF7919BCF1B2AD +:103C0000F8AA97BE2489FDC5692293C344CDC4F5A3 +:103C10006B7C45B83D61D5E882307AF5F0EFCA306B +:103C20009FC180E7080EEEA46E15D4DDA416EBE765 +:103C3000CB4AA200279BD4D54CB87E54F313F8513D +:103C40003C0E936C1DEBC727D60FE5A207F16971F7 +:103C5000D59210D2F19D68070A6A885C447B30CC0B +:103C6000F5AADF07785C555F473EA28B711C9C8CE0 +:103C7000FEB9941308807F6F0122C8A6FF7795B222 +:103C800052F22B7AFAECC123598EE3592958609DE0 +:103C900056977D16E801ABCB3B0DCBA211730528DF +:103CA00053AFAF1391AD12D393361EA5AB79228CCF +:103CB0009719427E96BC412C892B13ED57DA5F0988 +:103CC000269C07A703DE2F29DDF5D08D0607458644 +:103CD000F1CCF4E428A51E8988D54E986F7F8EED2F +:103CE000FE739A960088DD24DC3C94E2AD7FD7AC6D +:103CF00029A077DCA07FE83A5716971C01932FD5AF +:103D0000EFDD70BD02710022001E56C360D7C0787F +:103D10003F585E8EF10FFA37800A8B15C172E61F8D +:103D2000044C76ABA8489A7D26F669EF08176DBD5E +:103D3000DF4FB67E1BD1F115EAF17B2ECFBEBA93D1 +:103D40007D4FA5FF037E4C33E9D9D480511FB84D78 +:103D5000DF790E6089F05EF2BFF23D2FD96857C05F +:103D60005E2914BD114ACBA9C49B067E946302F55B +:103D7000EF68DD9BD3ADC2942E859795DC8F25949B +:103D80009FF5F47F88CBD7ECAA4DB39AE8B8E74B00 +:103D90005D7EA0E7FE549C66A4F75E4F4B3D31F07C +:103DA000734BF136A4EB06AAF00AC03F2816D15E89 +:103DB0005F5DF8BC57AFC73ED1E4502FFA208A347C +:103DC00096FB93143E9642319032EA9FA70FB3FDC3 +:103DD00074B9F4E1BCD3888F6F8BAF2FBE257DFC07 +:103DE000B3DF5B992C3EC1E559765523F35794BE5A +:103DF000FD83DE78DD88787550BF26917CBED08348 +:103E00004FB57769D02BC6B880F586EFCFD8D107EC +:103E10003CAC33CCFE3F1B37A5CEA27C0CF6ADE408 +:103E200035F841AB958D2AD8F3E7C12E07FB305CFE +:103E30008EF16152C8E2B5308048EB294A20C2FCBD +:103E40009B08D1EB4139C71877B3643A8CFA7B866B +:103E50002AE8E79F5227E33CECF0BD4C8CE746E0B4 +:103E6000BB162F89A6A0FDC9F0079F62F180072E1F +:103E70008B0E347A053398D1ABF1BD553925241119 +:103E8000FE7A7DEF56E37C93CA25F37B2E4939A554 +:103E9000B35392BF2791533A7BA742DBF7E178A255 +:103EA00076DECB422A9507BEEF9310856F133465FB +:103EB000433C94A03E6BF29578519FEF124C7EBB31 +:103EC000C2E84749C7FEA29DE94DAD9E7C3EECBBD2 +:103ED000F17D2405FDDA64FD1BEACB1E9628713ABC +:103EE000EB0E6D92281E1B97076604D1BF3DB249A9 +:103EF0001A12EF5763D1FC76AA3EC7C6F7072442D1 +:103F0000FB21DC4472F12A78E825CA588026FBB3ED +:103F1000934E6CA74F391E89D0E3CFD021DB609D33 +:103F2000189F3886FD60A08B186FEA6275FA22D45C +:103F30005BAC8100CE4B0ADBEFA1F06A49E17585ED +:103F4000D7D378DDCBEBF9BC4EF505D49D32ADD39C +:103F500032C51AF662DDC1EBF9BC9ECEEB69BC5EE0 +:103F6000C0EBC246ACB7C86CBC3552848DEFE0756F +:103F700085D7D379DDCBEB05BC4EB6B1EFDB58DD91 +:103F8000618DB0F19DBC9ECFEB19BC9EC6EB8379D1 +:103F90005DD886F564F8731452F81BE44367BC8E51 +:103FA0004A84C3B5A7DE656A67F49221106E87A9BB +:103FB000D960B71D98757F36C4431F3D71B50FE8B2 +:103FC000A7E1668D9EFC283F49CE4D28C7FA737F36 +:103FD000AEE1CE1518876808C98C89787C26DE5E2C +:103FE0007204F4F6F919A21F1ADB92F82FCF723B74 +:103FF000FE191E97799AEF57EEE4FB95DBF97E6583 +:104000003BDFAF7C92EF573EC1F72B1FE7FB959B41 +:10401000F97EE526D8AFA4FD36F0FDCAF57CBF7267 +:104020002DDFAF6C81FDCA6140EF7558AEE2FB95A4 +:104030002BF97E6503DFAF7CE4CE92DF16D2F59DCF +:104040007789680F24C347F16EA3FC1CB1C3283FD6 +:104050008BB6A41BEA43370D30C8F7C256E3BE4502 +:1040600041E308435D595662A8E7DE778D61BC9C49 +:1040700085C67D8B01736E34D4FB05A71BFAA74F51 +:10408000B8C350F75E5B69A87B4AEF36D45DC5F7CD +:1040900018C67314FEC450B7E7AC30F47FDC52800E +:1040A000F42567AE31F4935C1B0DFD6A1C81CF2DA6 +:1040B00020EFA6645E967C237F57B3F4F2D2AC1F48 +:1040C0002CB92410403DC7F411C66821AE3688C50E +:1040D000AFEC1FDE7004FC175B21D353E6789579B3 +:1040E0003CD9F5D431957EA7DC73C4D7A5A35BE298 +:1040F000D3BD47979A2A3139B9E64146DFAD0F263D +:10410000A673D404741DADDF248E17BB258B418F9D +:10411000687E4DEB8302F6FF67C7D7DACDE3C6BFF3 +:1041200047713D566FB744F87CA88ED0D90BD6AEF8 +:10413000B4D904F53CF3972D9CDFCB27F84F3452CC +:1041400078AFF412BF8DD657BA2A02CC2E1115942F +:104150000FCB6E46BF5EEBAFCDABD1359DC917A27D +:104160008B5BA29C7218E20A2B33FBB6DFE4980546 +:10417000E37F969840A2542FC95270523EE55FF9F2 +:10418000A8C5BF9CA07E4A181F206423DB77F619C0 +:10419000E3A68D734CF28FE7655835F9965981CFB8 +:1041A0001BBD7DCFCB06F382F9F07959634E2C2DE0 +:1041B000B1149CEFB85806D6CB6269585E1D1B88B7 +:1041C000E5D8583696636283B12C8DE5637955EC5A +:1041D0000A7CAF24361CCBD1B1ABF0B93F361ACB39 +:1041E0002B63DFC1E7A362E3B01C19BB0E9F17C7A7 +:1041F000CAB1BC2276133E1F119B8CE5F0D82DF876 +:10420000BC28360DCB61B11F6039343613CB21B1D8 +:10421000D95816C666613938B600DF2B88CDC7324B +:104220003F762F3E57624BB0CC8B3D80656EECC71E +:10423000580E8A356099135B8EE5C0580BBE372047 +:10424000B61ACBECD843F8DC17DB8065566C339696 +:1042500069B1EDD8EE8DB563991A7B169F7B62CF5D +:1042600060E98EBD80CF5DB1BD583A63BFC4E78EB3 +:10427000D8CFB14C891DC2E7F6D8012C2F85A74BAA +:10428000D9C1651F1BF79FC77E68DC7F2E3D6A94EE +:10429000E3256F1AF79FFD878DFBCFA35E31EE3FBD +:1042A00017EF33CAF111BB8DFBCF453B8C727CE815 +:1042B000963B8C7A6493518E17B4DE6DD4238D4671 +:1042C000399EBBEC27463D72DF0AA31E59B8C6D003 +:1042D000EE9B6394DF59E431A39F3E619B518F5C59 +:1042E000FB53C378AED2E74D7E4D04E58BA3F817A0 +:1042F00086F7EC85074D725965F2C9146F0790C0B7 +:10430000FEE652E2F0835F63C6673A970719C0770B +:10431000B4CCE47CD70FF88E96E9372DF4013D64D8 +:104320004C2D9B0576CC85138202B132616ADD305B +:10433000D8EF491F48583C818CB80EE2684DD95AD5 +:104340009DA8026D6F1A4430BE40D4E5150117C612 +:104350009BB1FE5BE9C10AC88B69B2F276B292B535 +:10436000A7B0FAB1C6392BA03D3DB5231B12991E4B +:10437000B72696E75D12DBDF1B28057E27D1F5FF08 +:10438000B5BCEB7E88CBFDBB3DF4AE449F2FB4871C +:10439000F2606BEDAC35F434A88E02217014FA8D06 +:1043A0001402EF4928B78D71D629A038E9F37C298A +:1043B000F807E89731D527C0FA353834B9FB9ECFD6 +:1043C0005B5C3F35A511F437D5D57C3F18FE34BD75 +:1043D00041F5E1A34E0FCAFDC86A799B8DD9854688 +:1043E000FDA166CDC6786273D312D4C7805F4BA29D +:1043F000386B17D653C1BA1C0C7181EE5C89968B51 +:104400006CD126D0275FA5751E172C088FF3B09EA0 +:10441000FB6F0C61FF15CEA965B01E0A8FAF383C4B +:104420002EF4050FFA17F4D1F9F934AADA2D18E2AF +:104430009AA9969060EDC7F653617C5FC88F7ED9CC +:104440001F25166FD7E047FFEE4BD7E23804DF4B4E +:10445000B18EE93D9E368E000003BAE67A51A3EB99 +:10446000BA247A4A8B7713F5E66FB5EF7444E67E8B +:104470009CE93B16C98FFBB6E6F72497510E5A5DAF +:1044800021CC8790A5C4FBBBB28DEF5B6D997A59A7 +:10449000FBDC3BB47534DE7C59FDDBB5FED43184E6 +:1044A000FE391C8E64CBCD4877055C1FE770FBEEB0 +:1044B000D09F6E58D14AF939429FD912C41122CDEA +:1044C00022EE6BE6D45082CB8FC37BA0C2EC42EDD0 +:1044D000BB036B8D7198031A1C375D1EFCB5FCCEB7 +:1044E0001C4AF8BF28E93D0FB2632A5B8F9755A598 +:1044F0000D417B0A9D5701A3253290BA23FA38A0BB +:10450000793E84EF5F0CE4C30D74B1FE649771DCF7 +:104510005EDFB5BC32BA2F3DD8EB3BDF723FB0CA8D +:104520009A783F95E20BF13DD064FF69A5B61FA8CC +:10453000D50FFDA9DA0E7677D3C24ADC6F6FF23160 +:10454000FD4DBEA6A38E8DAFDB3CCE4E0EF7EDDC4F +:104550009FDCB9A902F31FC96E237D0E79F8564777 +:1045600088D96FE9503ED5C6FA0DDD3C873FAFC410 +:10457000E7DB5BD9F3C16B4BF9F3127CBE23CC9E16 +:10458000176E98E080784EA3B7221DE33A75F44F7A +:1045900027EF86784322C4E386B491003C1BECF5F8 +:1045A0008B20FF0BBD012CB5790FDAB4AD7C38ED53 +:1045B0003F6861703AE4B952C2C4FC430221153A23 +:1045C000EFC7F87A73B5F690B1BD8D7F2FAFAD729E +:1045D000F970FACFBC85A18D934BF1997F0889F7CB +:1045E0007B848F63D7DA03C6F6306F575A4FA21811 +:1045F0005016FADF9904FD9A8DDF5BC7FBB928B32B +:10460000C1BC0B16061CC3615E45ACDF131ADF9AF2 +:10461000E482146E249375DF6BE5F3B62C64715657 +:104620004D3E6CE37180AD10071816EFBF46EB6F7F +:10463000DFFEC4C7548F4B0B593EA9D6DECCE7A58D +:10464000E5E514DC678CDFFEC2CAF8B85B66F15B97 +:104650008DAE92D13799271AFC3D127218EB337444 +:104660007621D403038CED6505C676FF0863BDA8EB +:10467000C45857AE31D42FF4C4613A53F471182D95 +:10468000A6F384B712FD9078FCAF3B459F479ECBC5 +:10469000F9EDC9BA12ECD7E0E27C64CAA769522AE4 +:1046A000ECFA7DF8BD9C8FF6413C84962F40FE3697 +:1046B0002DF78F0ED8F341BFBF67F16F23C9E1B665 +:1046C00095E3710BE7C3C7009FB46CE3F87C84C724 +:1046D00075D6F3B8CE5A1ED76981B80EC667585C36 +:1046E00067158FEBFC8CE7A1EFE1719D67795CE7C3 +:1046F000191ED7799AE7A1EFE479E8DB795CA79DE9 +:10470000C7752672F9BD7F624736C4D91E9F98D8F7 +:104710004F9E28337D168480262DAF224A8315E8CC +:104720009AC206F6754AEA148B0DF262030CAE25A6 +:10473000F3148BCCF271F06F3AFF0EE815CC9F7931 +:1047400093E7F5E450AB4847EFA30F4709E47564DE +:104750004DF08E8690682AA747DAE6837E5C0D903E +:10476000ACC35E307388640978E57E303EC17EF963 +:10477000BBC307C19C1911ADAD70D2F78B5E0E564D +:10478000504F9B0C2DF21F1414C8170A8880E7FDA8 +:10479000E5FE234A691C5F741606BAA073447D9631 +:1047A000A7E9876B8D7471556C2BDACB4D753C5F27 +:1047B0004A2109FD78ADF45E2B9AE249463FAA6989 +:1047C0009931DFC35C8ED861F4C38BB698DE57FA9B +:1047D0007E7FE826D1145F33E61137B9A6F7191F9B +:1047E000CF8F4DEDD35FBCC552799D3C265E77C619 +:1047F000BE8BFDCDF6A004761EB557A5A37200ECC6 +:104800005DE9A837007113E9A8C24B3F7F1EE0F5B0 +:1048100020D6A9DD1884F1295E0C76A3850A7CD800 +:104820001BD90FC21DFD908B2B02D418DA7F1B41C0 +:10483000BF224D765EA7827114988BF891397E3233 +:10484000E4DAA7210E12A911C9365A7F7C61DFF282 +:10485000AE575E852B80FB4939B5DE124B1FFCBE7F +:10486000A9569C94689F6C31A7EB95B5D3BDA83F22 +:104870000E5F326F60B1ACCB1BE8772BCF1B38C318 +:10488000F2E20669EBBABF6F3A78D4B48EFE49EC17 +:10489000EAE735BE73B1BC138DEE330AFAA6935521 +:1048A0005C3EC62222E904792B05507EF6BB358496 +:1048B000F9F1A0A0F57CD2F4CD75C887EA83EC1C91 +:1048C0004FBF5B03449F77AFCD63504E17B875A4BD +:1048D000E9C03896C741E10FFBD74D0708FF8E8A24 +:1048E000C2C17E1FA980EFD9492DB1437CB3CEAFA1 +:1048F000C2738B8BC10BFC55DE1FE7D5BC4CC49437 +:104900008A86092C3EAAC97F8D4E1A7C3C5E3F41A7 +:10491000C278B7E4AD8D02DE9B46133C6F43EDAE2B +:104920008B1735FF06F2BC323BF1DFD6A26814E8E4 +:1049300092042621FCB4FCC026775639ECD3ABF3A5 +:1049400035FB82E7A14A7E3CB790D3368AC5C33295 +:10495000C3985771BF187A4EEEA7A7BB0E844F536A +:1049600092F3056B6596F7E44B82D7F7B91CCE90AE +:10497000A393993F4AE93F419CA093F7DBD23CFDCA +:104980007743499C7FB5F63F4A0AB66BF59C988CF5 +:10499000F3266DDFCE0FB85EF3F74CFE9B550A1A77 +:1049A000FCB05CAB82FDB4BA9C699467973F4F89B9 +:1049B000E54316DF68C073C680BEF9A689F3CD85CE +:1049C0004126BBA3B088ED1BF7D81D22F150B86E6D +:1049D00035D193A647AC45DE0DC3F27BD3C5D66572 +:1049E00095AA00FB2A7E82FB426E7F4700F6055D9A +:1049F000399172B08F291DFC15E840A38B9CB6B18C +:104A000008EF1735BD57472A0209E6AFD975E06FA1 +:104A1000F9D2616493DF43825EF0AF7296331B720A +:104A2000208F2B0C54FBF6FB2E77FF5ADB4FCEA5C5 +:104A30007FE0F7FC42C3F7A7A6B89597B2EC589D64 +:104A40007EFF3443B0E8E8B2C7CF37BD47FD0B6FF8 +:104A500022B92D594259361DBD98FD77B39F4D7A25 +:104A6000E5BD9512C89BB24C997404F21F7BFCED16 +:104A70002D5399FCE278B3727FB4B73F79A7BF2F6B +:104A80007D627599F659BEA53FE9B719F34B2F3BE7 +:104A90003FF75BC6231A789E5E2FBFC3348E180E75 +:104AA0008889CE6D0C091BE12EB98C76C79556C648 +:104AB0009F839B8D71E4BCBA0189E39D3C5FADB2DD +:104AC0004CC39372FB1F29BFCD3F62653E10F78335 +:104AD000B578D37C9E375D09796C144F7348D00349 +:104AE0008D678988F93167C93B9EAB747C536563D8 +:104AF000E7E848B3F5249CBFD0F2B3E686595D9B46 +:104B00004F759BB15E45A66741DCB56A9395403E03 +:104B1000D67C229DECD2E64FF9FDFB366607559315 +:104B2000DA26906B2B793CB1D24B24C8A7AA79E93D +:104B300089B1709EA7C6C6E4F7E714FE8A2EEFE699 +:104B40006E574406FEFE68DF55DFFF0E81F7234DEA +:104B500003406FA6253E0731BBD938BF4BCDDF3CA4 +:104B60005FED9C46B27948BB8484E7151FD0E25EB6 +:104B700097798E64BB8DE13FD939924BBDBF0BDE77 +:104B8000EFE31CCAA5DEDFF34FBEFFFC25E65F6343 +:104B9000EFBE1EE4C4AACCDA20C8552D9F651109CA +:104BA0000520566379659A3A50D1F5F35D66BF1CCE +:104BB000DACF7219FD0AFB1EEF1CD7C3BFD9BD5D4A +:104BC00006FE3DFBD31353C12E58F04B0BB1533AA5 +:104BD00038B7DBCDCF8B4564D08F77EFB360DC8007 +:104BE00048D1B1B7E8F20531B3908EBFE0676EDC13 +:104BF0005FBEFB795B640A7DFFEE173F1A45281CF8 +:104C0000CEADE87E7D20D83D3F1558FE95DA35EAD9 +:104C100016FAFC6E89DC154CA0B73A391F9CF9B91D +:104C20007306D099B0EBC00F71DC8EDBAD369D5EA4 +:104C3000F88DCD8AF0A7FDD879AC6784C81081CDF6 +:104C40004F9F2FAEE5BD9D794660F37BD91A498110 +:104C5000F9ED6A9743B4DFE25D7F43BABEEE677B4E +:104C60003C0087C52F5B0CF267F12E4BD4360ACB84 +:104C7000133694F701973016E049500F2CDA57831A +:104C800079B28B3A5AFE66F1C0FB46FEA270C17340 +:104C90001F0B3EB0F8A740FD85A73D60C77EDEB97B +:104CA000D30370A5E3CE92295D7DF7EF3A3E246CE5 +:104CB000FC587AEFF1205203F4B5B86335FBDEBE41 +:104CC0009B4F837C5B6CE2E3CFE11FD9BDF547CC02 +:104CD000668C479E276F8E857D0AB22B23617E717D +:104CE0008FFEE07CBD60CFF9AD709EF8CCF37FD92C +:104CF0000A76FDC2FFFA72EB03100F7835C50BF28E +:104D000068F14FDFF3101DFC33ECCC8E3FF7CCD3B2 +:104D10004F3D46F9E4DCEF6D68E79CFBD5E95C8527 +:104D2000AEFFDCDE7F64C1B9DBFB7E35B13FC0E3A3 +:104D3000BEFDD7F5EFCBCF00BA8DD8F4F88D207E2D +:104D400095970596CCFC0A2F4D783AB4EF502ECCAF +:104D5000F3EC311B9EBF594C9FD59500DE6A503F46 +:104D6000407D1985F7A2DDABFE66199508EEEA4095 +:104D7000113745A203C1C85EB4EF967F195F0AA53B +:104D8000D5AFC078A41BE5BBF9BDC547297EAF4CA4 +:104D90008ECFF3E46B19E0BF78F76AF6DD0E8A4F29 +:104DA0004F6F7C9E857F8CEB8DCF12BB199F0B9F25 +:104DB000C4D8E8BE8C8479241A3E6BF6DFD6A7DD12 +:104DC000A0C9874BC1791ECF9BFA2F5BA0C20E7C76 +:104DD000F6BC53F5313C47A6D0B6737BCEE7124AFA +:104DE000279F5ABB7F0872B2FB57362FF81D77FFFB +:104DF000EA03E4BB73FBDF961576FEC42550BBE2E5 +:104E00001CE9F9EB043B6311DF335BBCC31DB579CF +:104E1000E2F85A14993649F1E0F313F83CC2F8610C +:104E200051E4C0AD4202FC2DB31730FD14E9877088 +:104E3000A9A19E0E9CCFD7E35528037C9EB81EE8FF +:104E40002F193EB5F57B61FD57EBF0BA83F1B1B98F +:104E5000FF22CAAF20877BE137227C00E5B9769B31 +:104E600004F991E7AC2CFE66C67B1CFEFCFCE4B7A3 +:104E7000B417EFB727D97FE070B814BF5F6A7DDF42 +:104E8000167E73EC0A8E6B86E399AF13EB838D5C11 +:104E90007E2C22B59306E8F499CD4AF5593ED87B8D +:104EA0004175A0109F6F538705E5FC995D9608E852 +:104EB0000BB3BC584412EFDB45ECCC7E59F4F281C5 +:104EC0005120D7CE1CFC39A74B46F78B769F9055C7 +:104ED000AE1F227AFD90C4DFFE291F6FF12B89C718 +:104EE0005BBCFB6F09C7FB5C0ADC0EF3FFBCD34A5B +:104EF000543AC4E71D964989ECAD4D76AB31CFD617 +:104F00003DF6582A7DCFE27128B0EE8615810F5408 +:104F1000B04BDEB1629C9648FE4F6D78DEDAA1ACF4 +:104F2000A1706BF054613C451BAFD10427C91744F5 +:104F3000BF54CA0C96329B3A62F0A7ADD4DFD5CFEE +:104F40009BEADD1CD04BC7479FB6C23AFF6CB21F2D +:104F5000FF2C91A6FE74BC3FAB827FB992C85F3430 +:104F60008E1F5A66218A5E1FDABA8FC37CC8AF5380 +:104F700008E4AF595E4D51419E2CDE9A12817DCDE1 +:104F800043FB2F3C05703BF7A48DEF73B23CDB6A0B +:104F9000BEEF777AFF85ADFF49DB4FC3CBF4FBD57E +:104FA0005B697FB0DB773B315FF3AFCFA78E2254D5 +:104FB0004E57FFFA81A9205FAAC1C7A2FDAB7FD6D9 +:104FC0003FD240C73BD58FD54FED191401BC2C7C87 +:104FD000E1578B409F2C78CE4980240FEDFFE0876E +:104FE000503FF76B37E67B9DFBF5E9EF021F507BE7 +:104FF0005BD1EBF5F9FAF3DE74DC055067EDC245E1 +:105000002EEBC08F590025A5F7052FA7E2F9075D04 +:105010003F7C6FB1ADFB7E1688520788E8134507C9 +:10502000001F2ED865FCDE5FEDCC9E5A2C7757B161 +:10503000FEE1018C5F3BF1BDAF353AE5EDE6F7B53A +:10504000FEFF612F308DC3DE5F6423B589E8DF96F4 +:10505000C2C65DB0EB9B61C6F118BDF6FE0E7BFECD +:105060002381E5E793BD29B84FB0508E0E4D2FC672 +:1050700078C73CE0DB859EE8D034FABD5F7279B931 +:10508000D041EBF4F9003E0FE80F7562EF7A0EF0B5 +:105090005BF3520A017AAFF9B51BE3C9352F5E38CD +:1050A000F5387D7E66BF13E37A35BF5E8AF8AEB110 +:1050B000457F08F1BDEEBD36B28DF63FB3F7B7B907 +:1050C000608F9CB14673D3FB880FD574D87832B803 +:1050D000711DD42F28AAA5F35137B0BC9C3AC2EE5B +:1050E0001DA883A00ED0F18729EC1C31DF97BA8769 +:1050F000C7A3BE98A3A4E2FCAFBD893DE7F1867BC0 +:105100006E56FAA7E9E6017973E42AEA97C8B5C3AF +:1051100040CE5A62371105F6FF6283B1D4FA59E0E6 +:10512000FE8662C8DF62FB7ED64C3FA9A6E5D2743C +:1051300012C2F397AE1B7BF8EC7714C5F76C56FAE6 +:10514000C378FE14265F6A1C81F129980F69BC7729 +:1051500041DDCFD67581DFA7609EEF05AB6A03798D +:105160001EDFAF6379837592F201C47DC9112E975A +:105170007AAD9FF1D917DE74E4336D1D2DF55E9481 +:1051800027ABEB7D58AEAA2F220AE629FBB16EE1D0 +:10519000F0B015AB04EE99001E843F9B2B1880FBEA +:1051A0002C604C88B75B5C21A42F9BAF16630576FF +:1051B0007EFF8EC5A5926A17C467189C206E0C707E +:1051C00092795D6A9B8270A5EFE3F3898ED09C94FF +:1051D0003190EF3BC220A7E4CC1243BD17DC34BAB8 +:1051E000D8F3BF0D3F82F05A5D6FC772557D19C26B +:1051F0006D657D00EBFF1FE0D7CAE0770D5174FCB1 +:1052000023675618EA49E1B799C22F33CE5766385B +:10521000D4F1FC1C8D9F92F1EF23F504375F36D655 +:10522000B761A93D4F4FA2D7CFA6307BA48E8496FD +:10523000E33EA897C56148A64A7274F127E253F18C +:105240001C089E3785F69C9B307EA9E1D7E2954EDF +:1052500019E59FF201AC67E91B5611E495A56E3B79 +:10526000F92843C7C75382290AC2D98F71E006AE15 +:105270005F57F6E0D3C81F2DF50A966B399FACE750 +:105280007CB201F00EF13DBF88386D9D44507F3EE9 +:105290004CEBCCDF8F127D3C3CCDDF11B552FCA333 +:1052A0004C52B064F7701CB34586D0F79CC52400FF +:1052B000F49276ECC7115C2BE9C0F3D669DA3D3085 +:1052C000AF14A4CDC4FD1F62657A8A585819B682FE +:1052D0001F65866F83FF20DE2F916C3EE5C7E70BCD +:1052E000F0BD0B33D99E59E69D1DC7E03E0857AB74 +:1052F00013FDCA2C7F6D5E2ECA571BD2ABCB1F127B +:10530000AA7578CC4A62FF2D734CFE23D0E38790B8 +:105310009748F1BBB16D700AC0B9C5DAE10379D81D +:1053200092C6F48D3283424177BFD86B5C4E7A4A85 +:105330008D724093CBDE6B4B0CF4ACC9DDF40946A7 +:10534000BAD7E4EECF7AE46EF02CC8DD8CD816E440 +:105350004B331F34586555B812EFA361F1A7130200 +:10536000DB57EF2D0F70DFFD8BAEFC6D701E5BE326 +:105370001FF3FAA5E6C9F89D1E7BD09A381F60205E +:10538000BF97A199D21BA174D44AE90C10B18ED257 +:105390001994614A678C9FCAB0D4E8780561324499 +:1053A000DD27B279F278ADB67FB2C25E12003CAEB4 +:1053B000EC603C34C8C1F7493345CC0B90A83FE9B9 +:1053C000A28FA403E3EC605F4A56B68FDFED163B75 +:1053D000601F7FA56BBA1DF24A85B452A49FAFDC53 +:1053E00095797DEDEBC0FD6B407F5E979F9C2C8E89 +:1053F0009F9BB4784B08F8A57B5C9D98DFE472888E +:1054000086FDA71A47A8C0A1AB8F84AF73BCC3B0F9 +:105410007B929CBF1CC5D743725452A893133DF78F +:1054200025292A29D2C98B1543AEC7FB987ACB8987 +:1054300024F270E7FF8C3C6CC88B205EAD66F9935C +:1054400019C03BA068A9C2D50AD43A5FF983D148F4 +:10545000A7D739C00F716DEBB183BE57D07B9E6665 +:10546000F917D76B0AC6C1A85E7BB40CE46952BDBC +:10547000567B17D271EB4005E8F8C0BA079E84FA54 +:1054800047EB6C78EF4B556C3551E87CAB63E3B080 +:105490009CD7F61096956DED94890859BEB67ADDC5 +:1054A0004CE8BFD982F19F5391ABCED5D1FAA95622 +:1054B0001BDAEFA7B6DC9B07F6DFA956A762017BD4 +:1054C0007FCB18637B33BBFFE5549B356261F47B74 +:1054D000D102FB1184CB778802E9E64B4A15B4E38D +:1054E000BF30EDB754AEB705044F72F857B625B6C6 +:1054F00027F1FC36E45C93DA61205FCB8FFF380F35 +:10550000E84393334BD3A9DC03F81DB79144FB0266 +:10551000131D1317039E263A024B19BE2EEFDEAC65 +:105520008F446A77239E429E6986B82F8BAB7EC4D8 +:10553000ED72624FD2EEE1EF7B13B7D7B4FEE5F523 +:1055400007696D55B131AE6D8178B500FEF83496BE +:10555000EFA0ED03F5A66B664FB7DA50AECCE1F1E4 +:10556000288DCEE37416F2F07C31031DCE8F6D4092 +:10557000B927B48C7C741C85DF9794FE803E84969A +:10558000F1FD01BECBD77C67FD9D74FCBFBF69C137 +:10559000E7F36229D8FFB307FD8FDE09FEC2BF5BC8 +:1055A00009C89FBF1F9988FBC89F598D718C7227AE +:1055B0009397AF72FEAF8AB518ECF3AAE6D932C45E +:1055C00041AB62EBF079156C22611EFD1DAFC10687 +:1055D00070152CFD1A78FFF6892B509F96601CAD34 +:1055E0007AAD2D619EFFAB0EC520AFAABB5A715C90 +:1055F00042EDB3CC2C3E9E4EEE54C732903F8857BE +:105600002590F75DC5E54FCFFCB6580DF2E7B39492 +:10561000C4719AB71C6C9D55B1EF20DFF55EDF7742 +:10562000F17995F6DD2EC6A7F1F53C3A2ED17AE256 +:10563000EBB816FB7F9696F8FBE7397C4FD5CF2366 +:10564000012ABF2A6DB49F0BBE7F6F5319F8F95B17 +:10565000D2D205DDBAAADB1690806E5DD55B66C935 +:10566000FAFB29E378B8CF8087F36B16231E9639AF +:105670008227400F54B68C1F15423F7F35C2F92355 +:10568000AB3F17E4F1E9B67B3D89EE913C6FC64F25 +:105690001BC70FB5BB4B75F8D1F0627EFFD49FAA34 +:1056A000BF7A10E4D466B741AE98CB5E78CB4F0C8E +:1056B000B7544E9FA7A8FE0E21DC94178F015DAF53 +:1056C00075627E5C72F85D41427DC12F89FD4CEDB3 +:1056D0002CBB730C7C97201CAADB181D5C0A6EF196 +:1056E000EF723A284FBC9EF14E8D0EEA884A19F6A9 +:1056F000A47C293A7880A8F63ED6D143076DAF95B1 +:1057000017C6E960BC333C7105EDF729D83FC37A71 +:10571000E3FFA4AC7AAE017B678D05F7BD4E3AD4AA +:10572000AC3B587D34C8E7939EF0D46B4AE3F5F95F +:105730003B8778F4F73A9E6EA6704800BFF1CE24FE +:10574000F453A892E2B1FFEFE8E7A324E760263A1A +:10575000CACB019F249C389EAC959AFCB6A4BA7A19 +:10576000FC5ED0A3275D055F4568EB3A47E86627F6 +:105770006D6F4CBB1FF5FCC99302EAE1E57F5A3A15 +:105780000CE4702FFBB73EF6D8C743306EF9F8C76C +:1057900056B4A7705C42ED1FD003986F8E7EC04058 +:1057A0008CB324DBCFBD172EFF1D13DFD7D5F66FCB +:1057B00057D6773E04E313BB4ABCDA797D054A66C7 +:1057C0008FFD07CC43179F97AD21AF1FFC5D810470 +:1057D00081EEAD52A819F20CADBECCD1AA0ECE4BC3 +:1057E0009C2C2F27E5F0E1E67CFA7ECADCDF7921EC +:1057F000CE67A3DF81D29E237DA18F975B3359DED5 +:105800001729D43D2F8073C8B46E883BD0F9F6E1D8 +:1058100037FF52E8B9670DEF379EA95DF405A0A3E5 +:1058200074F37B2D7F456A64ED695A73236BE771CE +:10583000D4C5952C4E7A68562AC24F5BD7CC5756A2 +:10584000E17D6B335FC9C6F34C335DC33E0178FE27 +:1058500012126B80EED3987E36D3C5435CFEFCA05B +:105860005D54AD74BCC3D6EE834EE08B1F09E85780 +:10587000DFF1DE612B90FC1F8E9EB4425ED45D9002 +:105880005844D7338B283233A223F8FE6CD2E1661A +:10589000F58E7E70FF697C3CEA32C3784BD8FEF30C +:1058A0001DEF1D9D086A948EB712CABBDE24328C90 +:1058B0003F6B9FD2C48E43F1F15EA1E389F1F17A8F +:1058C000E027D9111E71F8D8115EBFEF395FA2A28F +:1058D0007DA1832FDA2B1A7C1B006E147E33536755 +:1058E000DC484625E79799AEA19F9051F1F998E1E0 +:1058F000FB7768A2FCF68433B017F8AFD119781E95 +:10590000F867A1BD3B572AC073602FC2F34596507C +:105910005E16A5ABB38342C3FAC1BD1E9D89F7795C +:10592000CD7C7A1CF8E54A28295FC03CF879951FA0 +:10593000F2751EFAF169379E47D9FF412E943596CC +:10594000AEB5B703BFFD9B05EDCF2FF60DEB33AF23 +:10595000EE388FBBBCE514F9796BB6CEBBB83D779A +:10596000D73E6704EE41BCABCED2E35F015DDF55AD +:10597000C7F24F88D439EA56833DD9C8F7437A8FA6 +:1059800003FE82791C6D9D0773075C01FEE593633E +:1059900064F4230EBCF9C5EFAB69DD31C88E7EC25D +:1059A000DA344EBFE5CC6F7D322DE01C09F1AF3506 +:1059B000E97E95AE73CD6BA443A4703A38FCFE48E3 +:1059C0004529DC0B2D62EC6C7D6C7BB802DE2B660E +:1059D000F7CE78B95DBABEF3641BD0E3E96336DC79 +:1059E00077F8CCCDCE11AEB10673C18EFFA45D4E5B +:1059F00078FFD99FDD12CEB75DE81280CE6793B0F5 +:105A00001DE4C5BECEE9FD613E1E3FF102F99FDEF9 +:105A10006211D9FD685ABC252AB178BF2AB17A80B3 +:105A200097DE14FD7D63AB274DC03C8F39AD6F63AE +:105A3000329EA734F13D3FA92E365F7767FA64BCEA +:105A40007773828879D86E7FB700EFE57556C8F80E +:105A50007E58E8F3FDBC655ECC4385F741CEE75D3B +:105A6000E6FB3617CBD3DAC0FDEC76ABBF69021D7F +:105A7000A77D6D9A00F8D0FA292E26574E4FD0E216 +:105A800048618C23E5167A53E01E8BDC00323771B7 +:105A90009786F1BEEF6DD08FC559110EEDC35F8CA7 +:105AA000C23EF61A88AF009EAD8C9ED6AC1530AEC5 +:105AB0004AE13700F4C4270FDB6E8275E4350B5ED4 +:105AC000F0DD699970DE33DC7646E7AD8FA25F08C2 +:105AD000615A183777CBBB382F7792F5AE70B37B0E +:105AE000F23FB9047D7CE964F726E6D675F2FBF156 +:105AF000A2780F5E18E004F54029BBDF440A28FABB +:105B0000FC9838FF2CE7744802B0CF56592647203E +:105B10008E2036B7CF8075CF0EDBC80D747DAD42B9 +:105B20006700F8451D23F2FB9402C7014EEB36F4E3 +:105B3000C73CBC55622017F4B0FA7F64DCA73B1861 +:105B4000F86233DC1FBFB54C46BE381860E70D9FC6 +:105B50005C56D00EFB94EEBA8AB6D974BC88574610 +:105B6000C9D2504ADE1806FB94CB44AF40FB878372 +:105B70005ADEB6D7017431DAF2E5E422D8C7CB1683 +:105B800031A6745A60F736AC5C56E105BCAEF466DB +:105B90000A7AFFE5764E07C7D383B7BB287C7C0F14 +:105BA0006EF452338EF267C6151047549B65453B21 +:105BB000B70BF73D6470BC64748AD12A0FD65DF3CD +:105BC000D2E13E5D162F7DE8C6108B73C2DEE85829 +:105BD0008C73F23F1FE23593D7D68C706065D38A01 +:105BE0002AEC0FE364D171324AC5E8583AEEB6B4F4 +:105BF000C0568CDB4DB4239C88D4D506708A4C1CCF +:105C0000E0877B6D378E1BFA369C5FC938D23D1D0D +:105C1000F4686490E30FED20A756CA0AF079C6B283 +:105C20005377C2F334FF23F74299D1F8FE0320A73C +:105C3000D3BAFE568FCF27C986F862C6879F7D03E9 +:105C4000ED1941D910A7FC3A3DF81380CBD6E2708C +:105C500018EFC5048C66C5D7B16779E724B8EFF8AB +:105C6000F434D1BF8DB7E3BA3679236B18DC4A41DF +:105C70002F68705B252A1D5158D7543BD24721E924 +:105C80004479950DBBD983E378C9F870F512C8D76C +:105C900030CF679D4BE8B97F03EE09045C417E8CF1 +:105CA0009CCDCE15EE2DE9F4813DBF362D717CF2F1 +:105CB0002D377BDF26B238ABB9FD0D37A30710892E +:105CC0006D252C5F7E24942EA2A64299630F40FE80 +:105CD000F35E51F923D2F9468B02F881FE568ABF52 +:105CE000036F7C8EF1C503E177B17CC65DA4E5DD71 +:105CF00047B3E8FBEB4AD97DC7EBBC8C46AA9B991E +:105D0000BCA8F675D961DFA4BA9878B7717A533513 +:105D10003843BC8CEBABCA5B195C338B09EEFB429E +:105D20002C08EE9BCA827E147E99CDCB97201E490B +:105D3000A73A98F65B07E3027E1A45C2C6EDB22386 +:105D4000FF862DB8EF49F9FD2D886B55B6F6C77D56 +:105D50007F38360CE3A5F3EFA6F3F1DAE938103F0C +:105D60003CDD6CC17301907E03756519A565A4CFF8 +:105D7000EEF2223AAE52EAF5AED1E84093639435A2 +:105D8000E6507D01709BA3AA4B80FE4EDABD6FC02A +:105D90003C9C9B6C0AAC7FCEA6979682FDE2F47584 +:105DA00035837CA82E63F34D6FA5CFD1CE51DE8213 +:105DB000FED5AD36857D8FC3AF94D31987C35C3EC6 +:105DC000EFB95BD8BC1D832261A0CFEA6514AED0C9 +:105DD0001662740F21D18B22F2D51158BF5BCDC250 +:105DE00071FBCD30F18589FEB47555F275552E6382 +:105DF000EB229C9FE8B4A2306E65295BE71CC2DEF3 +:105E000017E1391D7F2E5F4FA5FA2296739B6D8691 +:105E1000F1B716EDE884F9E417CB0A9E1321ECBE26 +:105E2000C35CBEAEDC46F6BDDCE217115EA44E37A5 +:105E30005F8CABEAEA94AF4EFF9632165C0A00071D +:105E4000D8E8B8277F2CE37E4EE126E3BA4EAF1E9A +:105E5000B6BD95B67FF4B08CFBDE7B45FFF13CF41C +:105E6000476585C91FFFBB53404ECF6DF4831CDFD0 +:105E700053CEE07FFA6612017A187224980EF01E53 +:105E80007224C4CB5ADC4FA700117AE41E9D1F7503 +:105E9000999A059097B1C1CFCE033950C6EE231F12 +:105EA000A49F379D5F46735605E4436596A557C882 +:105EB00078B5ABA9FDC863D345683FFCD8BDF09D5C +:105EC0006CA25B0F6D973D83D97996C3B415FAD553 +:105ED0009D7A10F0D1CACFB90E8199A5637918CAFD +:105EE0000CCADF2DE9304F894C2889CB839D0F8F59 +:105EF0001D0D7205539E4AB08C9292DE7243D77F7D +:105F000038EFAF0A09FAB93D8AC13FDFF9F0F5C3AE +:105F1000C18F5F0776622ADCC7E6FD12F27454BFB8 +:105F200088705F678DDA8B697D15B51BC17E595FFF +:105F3000F4BE087CB76E1FF1037D6404FFCBA6C7D7 +:105F4000E30D6EF6FB3C924C5A80FF0F0E3F350975 +:105F5000F0143940ED4EDABFE237AEC79C600FFD5A +:105F60009EE5C1B4FFB616F5F7FDB972C2FB78C95C +:105F700025EC4473FFF421D3319E97B76903DEEF1C +:105F8000593D49F2DF407B676E2A2F073B46095295 +:105F9000EAEA4FE7BD65F4726042650ADB2F5326DB +:105FA000B1E7CA0456B6D41F7908FCF6F02E29A52D +:105FB00090CE77C46A76AF584BF117F610B54B4BBD +:105FC000CB9FB7DF4C9F7F5C4AB5207DFEF1B55F6C +:105FD000A4C0FECE93A5151900CF7DCD46BB8EC0C3 +:105FE0006557D41F1A690B07DC745EADEF1184A7E7 +:105FF000C5166DABA475CB4B2EB0707AF939AB5B7F +:10600000DB67009DCE2992316C6F5EEFFB5C9FCC0D +:10601000AEEB9E04F7EBE7AB84C5F7C38FA2509EAF +:10602000CB4546BEDA8942C7BD89F9276129F03AD6 +:10603000C8E570714886573479D63AA4F22990673A +:106040007FE2761DA99D87E7C890FF2D600F7597A9 +:1060500027F29B4A5D0EEC7F7ACB2D1F409C7A4E37 +:106060001DB3F7F3B67C29203EA8DD974DC7CF2B93 +:10607000C5AB06C99C6561FB48C04FA1481405E645 +:10608000D341C04F0853FDA3878336EE7FF7FD252C +:106090006E1BF26129D8CEBAF5B8F87A72FD743D5C +:1060A00009F47409FFEE8F9EF8F2C03880FF32E6E3 +:1060B00022E5854F0876DD3CF2D4CB9BC755301ED8 +:1060C000D8AF6E2F8EEB2EEDC2FB5CCCF21DCC79DF +:1060D000E0DBADCE73A3997F6F94A7BDEA9CAECCF5 +:1060E000CF734DF26AA4ADE346C4EF1E76EF35647C +:1060F000C442BB404485DDFB19D1EEA7AE857E23AB +:10610000DC2E2FD041EBF0F74B003E6BB9BD30B722 +:1061100098A0BF3A37A713ED85D98DDC5E90FC4D72 +:1061200020649D5BD2C81A9DFD80A612B8D08DDC7C +:106130005ED0F43FD7DBD5BECE66D4AB8DECBC5F72 +:106140008F9DA132BD9AE7637ABDBA997E47E1C4BB +:106150003C566F97303DAE6CE2F603D7C319FCBBDB +:1061600099CD4C5F65801DE181340815F532EE61F3 +:1061700065C5ED967EC54C5F66B4EE45BDD6013F64 +:106180002E3306E406D39783DE3EAA02987CF47190 +:106190001B95D38FF3769F97DA67E971FB6C95C8EF +:1061A000F79B08B30F31E79FCEF321E8AFB31B771E +:1061B000F0F9ED3D9C7E13C8D79DE1023C57AEF14E +:1061C0002D463F693DB794E5AFE4D6B17D72B7BFC8 +:1061D000EA29FDF9B3796E76EFD03C8DAEEAA23EA6 +:1061E0001817EF8540392E637C7135B59730FEC4A2 +:1061F000FDAB6B5C3CAEC1E927993ED1E4909B04BA +:106200003CC514BE1F479E4279AD527F09D6F67138 +:10621000B861C0DDC0EFE169A530FF75E3BEC2FC27 +:106220008FBC24FEE29F353FF35BCA75F7A4A3CC75 +:106230000FED14139EEFC9F1B0F84387449C00CFD3 +:106240009430BB472EA54C4ED83FD5C3ECECCF398C +:10625000DCD68D7B0ACF6726D5CF12512D09F4A944 +:10626000A66F5B01CFD7D0FEEE379A54F4D323410B +:106270000BCA57767E314CBAD08F548B648C1BB6C8 +:106280005AC376C0C7FA528E57AFBD1DEEB7F9D6C6 +:1062900078A1F0003CAF0E8811211FF01CF18E6434 +:1062A000711D3CB77C9AFAEFFAFD8AE11E91C34951 +:1062B000C11FE6CB6B66F4B56E9C8CF358333AABDA +:1062C000DD92AF97BF02979FEC9CD89A71AF237D68 +:1062D0005DEEFCAAEA9EC57B3FB4E7A7363F5D00B2 +:1062E000708EDF7F11E8F33C4555DDDF36ED48B0B9 +:1062F0004FD0D30E7E940BFCC0C81D867D4D8EDF23 +:10630000091ED1107703F96A45E7223200E24B7B80 +:10631000C6473CF01E59C6F66DE7F37DDBCF77DC50 +:1063200082E7C94752B2B226C0FB67F5C6F3EA9FBF +:10633000ED7C7A008B6B440C79C2F39FFAF908C3A9 +:10634000FE7080289963F915ACC0EFAFFB559B2513 +:106350007EFF800CBF57007176E0E0C170AB620732 +:10636000962EE05F5A7A4837965E504783C14FF2C7 +:10637000639949825866915A2C7D248CE500D2811C +:10638000650EF8B983412F7463A910AF487472BFCA +:1063900080F8B15E4882584A80B78CF8BE84B4CB8E +:1063A0008EF91BB07F017C9FECDC99DF53B9C4836D +:1063B000FC5D7B25FB1D23B65F31DD13B8C78378F9 +:1063C00088A2FC9ECD45F991E74674C0F9A37BD61F +:1063D000B2732F9A7C47FF867EE7D974A60FD48DBF +:1063E00002CAB115CEA9DF4578B65ACFE8F71B88A7 +:1063F000DD5E08BF0FA28D3B9BC71966733D08E1A8 +:106400006E767ED08FE7936643BC41D74E7ADAD959 +:10641000BD34DA38A2F3DAA17DEDF7E9DEC7FCE896 +:106420004A931F7049FD6DAACF31BFFF359D50566D +:106430003C1EF7EC77955CA457AEBF294129F85E66 +:10644000B3ED04FA63E189013D5C9EE17CA0E9952E +:1064500039A67C0F733947E2FC611A876AC0343869 +:10646000D78B774AE8F85BBB9F54BBBF677E20247D +:1064700067B3D77C80472F9F77986CA9C8A6E5A7FC +:1064800050D7C5F78FA6865EF2E8FC116FA056D4F0 +:10649000DF77B390F3E3444B6B39C8B9D321E207FC +:1064A0003F623EA9F57C07E2F9472D28E706D2793D +:1064B000CBF07B2FB0C1918E75157EEFE56C3D3B27 +:1064C00027748ADF33FC14DC4743CBBFF07B85475E +:1064D000B62D9D0A74F039BF5FB868DFEA20C47D2D +:1064E0004676386781DE1FD931BE1ADA47EEB2B17F +:1064F000DFF1E172429B171C7377A4E33976D59ED6 +:106500000EF284A0DE3DDBEA88C0EFFF9CEDB0B068 +:106510007B558B45BCBF0CAE21B4F0F9A5A6C3F7E3 +:10652000FEF387608F7CCEE5C9194F1AC397A40A82 +:106530006A26A4A5103FD8351B9C8BF01C64952BB4 +:10654000F2D46399901F6EF7AFA0DF3FB0F7A55C60 +:1065500078FEA87311967FD9FC412EC8ADB3FB3FDE +:106560009013D16D8D1495213EB5609F20C2FE49D8 +:1065700079C72C19F647AA761FC0B8728D3784EDFB +:106580000BDBF6627DC2EEB771FF6470AA82F33A4C +:106590009B1DC2386F619B2D0ABFC7B1A7207C77B6 +:1065A000C27DFB54A66736385FC5F11F75BEFA3A47 +:1065B000C265B30DCF7F1CD8FC1B1CF7CCFE97F82F +:1065C0007C09E60B9E4DE938FE13D05F7BF9794CD0 +:1065D0007BA7471F0F965205837C3DEBE6FB5E3998 +:1065E00097E8C7F30589ABD3C3E452A707F6CDAA52 +:1065F0003A181CFE628DCA60472EE81014F83DBDA3 +:10660000F2DDED781E70C13E3B9E975800F000B859 +:106610005178215CDA0EE0FC0B002EFD601DEF626C +:106620003E7EE13E0A9751F1752F7085905FB5F57A +:106630005238B075EFB9149E42463CB5BD2D435C4F +:1066400066E13E01E1B770379B47D53E36AF09BBE7 +:106650006721FECFEC270AC45B4EEDFDE07358CFF7 +:10666000D9FD76BCCF579B17DCB7E02901FE6174DA +:106670004AF631B9AAD9DD35912CFCDD819EF6DDD3 +:10668000EC7749016429945E47EE9B86FB82A54026 +:10669000BCC0FFDE8E11ECF705C3B900D73DE3A304 +:1066A000B930EF33DAEF2349E15CC08BDF132A4DB9 +:1066B000D5E1E3B3132FA15E2C126BFFFC20F0F1A8 +:1066C000F3EC7738967EB841D4C3E33AF841AA3167 +:1066D00000B7B73C08B79EFB5BC22C5F8A84901F53 +:1066E000AB383F9E6DA77E275DFF676D2F60FBD99E +:1066F0006C637ED55FDA0EA503DC2AF9790C12B93A +:1067000005E511854BB33D819EEF39D71661E7153D +:10671000CF09FC3ECD2734B8D5CAD30DFB7C4C1E27 +:10672000E66CC93F8C7E4624F13947B39D64BE2F89 +:1067300035593EC0492ECF3EE6F774697A77BA27BD +:10674000342BB55FF2F3DE952D35B900EF4A381BD7 +:1067500089F79C1EB801E215786E88DD931A05F85A +:106760009CEAB907F5A51B20CFF4541AABD7A57640 +:10677000AE02BBF69476AFAAFA1A7B3F9FB56F8242 +:1067800076DAFF394FB03695D9F702FB7D1F6B1AC9 +:10679000FC4E83A63792C3C1F83B0D4FD3B5025CC4 +:1067A000E8783FC1F1243ADEC87F7E3C4D4EFFD3EE +:1067B000E3D8FF67C7D1F417F027A43E12BF7FC408 +:1067C000FF04FCFEBBEF93F05C035F5DD83CB809AF +:1067D000F6D1CEFBD83D30B6D6E504F4F9DC4D1B3E +:1067E00012FEFE5B4F9DE7E5C88329BFE9F8FA4832 +:1067F0002AB3CB8F70390D7FB0BF0577E5A05D4C14 +:10680000FF5AB3307509FDE761FC1EF3221246FB07 +:106810007404E9C0B2987462398A746389DBCC83EA +:106820002154EAC7F2AFE55D6361F10BEDA1275397 +:1068300044CC3B780DE4D0D941A1A7E1A2B615CE56 +:1068400045D7C0FCDF48F57278450DBFB742F4BFAD +:1068500087A1803D38C5D7973D48BCD2999EBC974B +:1068600002BCCFF6ED545C5FB2DF515B62BAF786D3 +:106870009D0BD7E050433A308FE4B52DF7BC319CE7 +:10688000C2FFEEDD6EB493876E695C02F2FC6ED2DD +:106890009905E78487F27B44481BBB0F47BB1F6405 +:1068A000789BCDF83BC2A6DFE359C07F3F6B81F9EF +:1068B000F7A9F839DC167890201FC37C8EF7AFA9B2 +:1068C00089EF7D21C5897F0FC57C8E77778788F911 +:1068D00051F740DE95CEBF18BEA3D666A42FE5DFE4 +:1068E0000AADBABAE067F108B723B053E8FD9DFFDF +:1068F0000B82D8B2B4008000000000001F8B08009B +:1069000000000000000BDD7D0B7854D5B5F03E3360 +:10691000679E99849964924CDE131E21C86B0221F4 +:1069200045A47A122246A43A3C6AC15A9C8040800F +:10693000BCA068B1C59F8144081425D488400107D4 +:1069400044C5FAE8A417E561B00344448BBDA15ADD +:106950002F522F1D901F1111466DD1F66AFDD75A87 +:106960007BEF6466480AF4FADDFFFFFEF4B3877D2F +:10697000F63EFBB1F67AAFB5F70C77288CA532F668 +:1069800082A2DCE31DC4D837F87753D773AA5DC75A +:10699000D808067F8D6C5C31630DD5AA7D15941ADD +:1069A00002564DEF84A75D1750F219CB4A2C33CF16 +:1069B000853273E8ECFDDC8C8DD58F3EEC86F6C617 +:1069C0001A75B809CAEDDBE67618F07B97CA4C3029 +:1069D000649603FA8532CBD005FA41B9D1FE1BC7C4 +:1069E0000C18BFC006EFA19F1C3B0BB8A1DFFD5BDD +:1069F000EFD761B9A19EB1741C47F175B8E93B9519 +:106A00003D85D362DAF8A234C6F2F09F308ECA56C2 +:106A10007FAA4F62ACBCE6B4256C83F7E1CAF16C87 +:106A20000863A5F67C5AA7FAFEAD1F6179CBA25385 +:106A30000E1F8CF7C6D6E57F180BFD1902302FE824 +:106A4000A2F0EB86E36361BCC85623DBC6BAE090D4 +:106A5000BB583D1536D380EC1BF82F7B616CD9C831 +:106A6000A05C28CAF9388FA87A280F17E333368537 +:106A700085D2B05ECCD7A93106F364769BF3CC40C7 +:106A8000C66EB22BEC9BDE5DE511A2BCC3D05C668A +:106A90008579EEF84FC5B314AA0F6C9D9587EBBBB3 +:106AA000B4C7976787752C32270D61BD2EDF3F83F2 +:106AB000DD2DF6CF6FD1B9F019B2305757FB01DB9E +:106AC000EB4D3EE8A77109F39CEEC79839D06E1DD7 +:106AD00088FB78D8E081227B4861538250AFDA98F6 +:106AE000168471860B7C897F3EB4C4FDBBBE86AE26 +:106AF000711FFA7AD214DCDF48A255DBA65C3E2F68 +:106B0000F99D6A77FB717F0DD9CC9300E3199C1D29 +:106B10009976F86EE02EA3C706201BFBEB41BDC2A1 +:106B200030EEC08353993B91C30BE7AB2E327A4EC4 +:106B3000A730665AE4F4A8C3B19D8DF0F1339B31C0 +:106B40006042F82FFA7933D6376C2D71B9A3F07AF9 +:106B5000F912BB4785796E5A62F6A8B0C0E5627D2E +:106B6000F1F3CB71E8BC01F8CEA8633EAC5F00FB4B +:106B700080705C604FA0E77C51DEACFA27E2FC3706 +:106B800003FE2C457C5DC8F1774186398078BEE0F4 +:106B90008D3EE9AC1BBA92CFA797B83C7D611E9B96 +:106BA000164E7731F8B4747EBBE51658FF8244B3B5 +:106BB0001DF1519F54F0F868C4F7370D0CE9AA2174 +:106BC000B1C43D23AA3F7DD24817C243AFF3673219 +:106BD0003B632BECD32AD40CC417FF46E6616C4D03 +:106BE000F3CDBC9CE8CF54A0FEF1E65B7939D5BF6C +:106BF0005181FA279ABFC7CB39FE4C1D949F699EDD +:106C0000C0CBFDFC1BB1FCEBE6EFF3F26098432632 +:106C100063BB9AA756F861FC0683678A07C67D1195 +:106C2000E63F08E61F14CF3D76BEAFB2FE37F81E32 +:106C3000E0BD533CE3EB5F16DFEDEEA17EAFA86F46 +:106C4000EBA1FF57C577A11EBE3F20BE6BEFE1FB56 +:106C500043E2BBC33DD4BF29EA8FF4D0FFEFC57731 +:106C60001D3D7CFF07F1DD3B3D7CFFAEF8EE580F8C +:106C7000F5C745FDFB71FD9F10EDC3E27D7662D344 +:106C8000713FE05D36F02DFC2B4C6C4A46BCDB546A +:106C90005F4CF8DF3002F07C5017BE672BCC8BE5E1 +:106CA000210E95FA1B82FC189E6F8BFE4BE7F75D59 +:106CB0008378B7E02DBD07F1B041F11CF341FFFE31 +:106CC000F93A0FF2DD056FE8399ECF57032C8ABEE3 +:106CD000DF8E9BFF1631BF4631DFDFD97B13DDE44A +:106CE0002D7279C64B7E89746F8F2D9B819E3418CF +:106CF000BFD1C9E54BE1FC32737F941F205F906FD9 +:106D00003E6433864C30FE437695EA1B9D6576AC37 +:106D1000F7DB55923F0F39CBCC3390AFDA80D99562 +:106D2000C07876DE77A35DAD0820FF709453FDD860 +:106D30005F8FB7231F6D64114729AE6F31C815F8F7 +:106D40007E7F7D19BDCF73FCC581FCF968325F572A +:106D50007BE2214B3EB453EFD391BC28B0AB24C7A8 +:106D60007A2FD605DCD0A4DDBE4087E5271BB9BC51 +:106D700082BFC42218BF2F1F9EEDB8BFE4CD42943E +:106D8000670FAB1EB79BBF53A3E4415F94574938CD +:106D90006E728CBCDA5CCC34ECD7EF32079E827E0C +:106DA000FBAACC9592DC05F73C879ECB17FD780FAC +:106DB000CAB53ECDB1F229BF294A3E319497B1F20E +:106DC000295E5EE5D4037F8CFADEE4B2C7942D8E93 +:106DD00044924FC0633CDFC0D00B5A17DC62655D44 +:106DE000FC3A5E1E3508F920F96EC3D7C363E4830D +:106DF000E4CBF1F2E1CAFCF5ED5BFB131E02B772C6 +:106E00005F99CFBE8D7800F867F029243F98EA7328 +:106E10007913AF0C2F83C16BB7DBAE0C3743EA3B62 +:106E2000A457187C2AF57F995CB9025C653BA3F9ED +:106E3000C9CDA741AEFDE5FD9F14322099E5001BA9 +:106E4000DAFF545DE0295877F6A2E73663FF5987E9 +:106E5000AC8D0867A36BC6E6465C4FF3E38C013E3E +:106E6000E9CD1C9F8C196576FC5ED569AEE43E5079 +:106E70007EF6DDBB14C0277D4ABD87C1BE1D7EF1F5 +:106E8000CDE4DB107E6F1988CE4D3AAF9DF5A1E9B8 +:106E900010BEADC8B16E5D4578EC33239CB27798D7 +:106EA000490E30FFF6951A2075036C071B85F553C4 +:106EB000566AB0EE1D4A67F9562C070346DE1E5887 +:106EC00034FE5FAB4E11F54C535DA4778AFADF5464 +:106ED000948F86F6AA7DA00A7267C1DA979A0C3958 +:106EE00058AF93DF6B6C24AC17C7136515F6E7B981 +:106EF0007651EF3FD8540E44D46A94E3333FB66FD3 +:106F0000D5E978D9DFD684FDBF5026BEF73FBD5204 +:106F1000CBA6F9DCA67740D1F17A93EDFAAEF9AEC3 +:106F20004D7EAB6929ACEF1377380996C16AB69EDE +:106F30004E43F9BC624ABD17E18688EF0599D84BEC +:106F4000EF263CEDDCB79D13FC59507BF1D0DF936D +:106F50000641559D3E7C2801E057B3BBDE6C80EFB7 +:106F60004D06AF3F2BBFEBBB9A9D95A4CFD4B51573 +:106F7000D1B39BEF0EABBDFFA5EFCCC6AB18EF9323 +:106F8000D01F6A9F87AA1A7D7D934D4FED19DFFFB1 +:106F9000EED727BFFFE4F93FDC89E35D7087D3C6F6 +:106FA00041EB1521804B37DFC9F6B5BB27D0F3582D +:106FB00082B6C601EF6703EF227EA5D67BB07DD0F7 +:106FC000DC6CF700A02D86662FCA0D007D4037B21D +:106FD000EBF90B475F6A1FFF3E9EBE826696321E2C +:106FE000F978B54A722A68F6270C81F26AB043969E +:106FF000C2949615BD3B6C10965FB231B44B1AAA81 +:10700000DB5D8390AE3C4686FAEEEAEB831948E7F7 +:107010008D35C629DB117F430B5C33A3F4ADB5C9B5 +:10702000069AC7CAD780EE86C2D3107428F87D3F6F +:10703000901B0AF2459F19ED1C4B4632F3E7633B68 +:10704000DB6AA4CF95065F4519B6CBD0917CB1F42D +:107050009B5C5106F370A5EA143DCDA3FCD82C949B +:107060006F76234A50762279FA6E84D373AAA71ECC +:10707000E9F0399BCDEE870AE0911AF23FB59F33D4 +:107080008065939ED5A31CCF2A02791EA5C79E10AA +:10709000FCF384C348FC6EB52538A114FAB12ED098 +:1070A000D9FD30DECA9A751D63619C5FD6BC7C74C5 +:1070B00029BC5F95A6329C87CDA9868C207F0CDFEA +:1070C0008339C2BC5F58EAB5237F8DA4AA6C1BD458 +:1070D0005BFB1A993B8A5FD90641398A4FA638551E +:1070E000CD02DF7F95ECFB77078C3BFCAD77CCF8CE +:1070F000BD6B844E87641354F93E2715C7F6631F92 +:107100001DDB4F72796CBD737C6C7DDAE4D87AD765 +:10711000DDB1E5CC7B63CB5324BE01CFB1813CB65E +:10712000F22A660D7FBA04E52DC0E73D84BFB54065 +:10713000E741F8586AB69F9D05F559C84FD01E1A09 +:10714000C248EE1EC8FDA91BF5025372BDDB31E833 +:10715000727864E5986FC3FDB2F555ED0CDADBDEAD +:10716000FFE86BECDFC6A2DAE5237CB488239597B1 +:107170005D309F44FC871BE15DFFE707512E1ED564 +:107180007B10DE59352A8DFFF0647740CFF5091763 +:10719000EA3349A27D927975871EF879D2FB2BE7F5 +:1071A000A3DD1B0FD73456AF205D027E707BBB92F0 +:1071B00091FC58A1635588376823607FA41E01BFE6 +:1071C00098946224389992156137AA3AAC4F13FA11 +:1071D0009331E35E0BD2F1438738FE3F64E4FD74E4 +:1071E000F6E7A64111E519F2C994645D4C3FEBEC5A +:1071F000A28D28A73A78B9B53DF936A4CB759393FB +:1072000087219E98D0EE82FE7A659BB501B03ECB79 +:107210001B46BF029DF65259BB01F6B2D5CAEEF12C +:10722000C23C361CB6FAF5F0DE32F31776D4D38AB8 +:10723000C5BC5B9779DE463E10A954098E96D4668C +:10724000FBB0417C0D7E981FA203CAC5D27E2DA43F +:10725000E7594A9B49BE5B8A9A9B114E1BC6EB4875 +:10726000DF48BE5747F86CC9091EED8B7E82993AFC +:107270003BF6970C82DF089D3C9ADDEC45BF090385 +:1072800098EB4A38AA60BFB442182745C0D5E9DC5C +:10729000F91305FA49C1FE86F0F608278780D3E87E +:1072A0006437C1DD29FA4DE90BED87F07E1A4BBA40 +:1072B000FA91FBB8A18205707E725CD94F67FF4CD2 +:1072C0005390AF1A7E0770837D5272CD34B987E632 +:1072D00032B28F5B9779EBB7125DDBC8CF91E9CC07 +:1072E0002E433CCA3CBC71A26E087E67A5710C336C +:1072F0005900F1385365E61B9351BFF1121CE3E9C5 +:1073000035A3BD7912EAA9725FE2E93743654DFA08 +:10731000E4CBE938C3E92C2B18D20D3DC7D14BC6BD +:10732000E1C87D88F4F174BD25E14211C28545B7FD +:10733000D75FB9ACD7078FA29F87A5839C00D0E702 +:10734000C68DC7D83F4C585698CEFD4D1FE4FB0E56 +:10735000E1BF017905C4DA3ACC3EC686743A9F1182 +:107360007E95ED5A7DD7EFA0BF4BFD8C76942B39DF +:10737000879B3B503EB2DDBEFEB80F9B54DF130926 +:1073800050BFE9583A43BEBDD2C2ED3155E079BC99 +:107390007C592BE8C68D72CEF5AF3FA57E18EC9BCD +:1073A00036D00EB4B7F617156F9853FF07F52CF6C5 +:1073B00002E959D9ED1D4B6D38FEDAC34D6680AF39 +:1073C000E52DDEBE19CA7E15E1574DFEAC0339B37B +:1073D000084EEA7113433C1DACD70258667FB230A9 +:1073E000E4BF3B5EBABBCA8DFC276D9C1BF9D0364F +:1073F00041EF01619FC5AF5F356A3ED427E2DF6F81 +:107400004CD689FDF49EAD847D1CFCA491AD82CA4E +:1074100042DDF426B4EF222B81FF42ED74BDBBF6B2 +:10742000E751F6ED23D6D26032DA254BCCCC070AF1 +:1074300073F6970AF30171E638FF508AFC279785A7 +:107440001494B3B9F5A0F0225E2DB4325F14BE6778 +:107450007FA952FB47AC5A3079047F6F063E60E04B +:10746000FF64CF257B59A593F328D45F0CCF5B4FE6 +:1074700022DF60CE72ADD31EE98DF80B721FC6DB22 +:1074800027D66D00181A86C17F365DC834E4F2F63F +:1074900007049C54B32D84FC52B51D3946FCC5AE7F +:1074A0009E8F6E87763731B16A467E59840B957F01 +:1074B0006CA77216F05FD330D2FBFD687FFB93B8E8 +:1074C0003DC234CDED4C437A6104E46C336B3243FE +:1074D0003BC276A0B70CD66121BDB99DB9911ED033 +:1074E000C3762681581643B86E62AC229A0EE453D6 +:1074F000FA25D4457AB2A7061EB4D07C0CF52C60D0 +:10750000417D08E706F05617B2809ADFE5171CE2C6 +:1075100070D37746564FFAEC0B5F9FC8443E6D3DE3 +:1075200004FAD850DC671DF129AB3596FE185B4A8A +:10753000708A08FCD8BCC44EFBDC69BFF9DE11FBC5 +:107540001C5E8AF222776172CCFECA76D95F663100 +:10755000DFF0E87E03D46F76DF7605FD32D95FE693 +:1075600052FDE625EE2BF4DFBB87FE33088F7AEE63 +:107570003F9BEA3787DE71DC0EA0D814697778DD8F +:107580005DFA753C9CB317C6F2E5A1BB63CB122E26 +:107590001683E69C0030B7DCA7F36C85FEBE732C27 +:1075A000B65D45FE1FC9FEED6A1F724EC2F6609FB2 +:1075B0006F85B7379C8D6DEF2D7DCD8174DCD59EA9 +:1075C000CFEFA62F63DBC5EF4FFC7C615EA9DF8F99 +:1075D0009AD718B329A67E4AE565F34AFD41D4BC83 +:1075E0006E71C5B6F72DED7E5EB7159AFEE9BC64E7 +:1075F000BB3B465E5DBBF8754CAA30F50077DEFEFE +:107600000753AEAEDF1F56FDF376F72C8A1FC74F28 +:10761000F8BE40A78D4981FAE9F80AF5459B95F433 +:10762000DECBEC2C219FC6A1E201DF7992B471F888 +:107630005D85A43BE16738FCE275E9C8D7B3841FD8 +:107640009D09BF426BB58BFC0A3ED11EE44923F273 +:107650008BD61DF05D129F57B4FE9452CDED0A3BC0 +:107660008B103D4B7D2999D9156E8F737DA7A7711E +:10767000E2FB7F18154098EF8C4563D80740872FB1 +:107680001BEDA52ADA675B14D20766946BFA44C037 +:107690008F514D0AF995663CF0F6A3E88FB9FEB418 +:1076A0007B7718DECF08383C386C6D07D3304E90AE +:1076B000AE9F5FF4203C1F3BC0288E86E5F9886FA3 +:1076C00036CD8DF64625CE08FA396FA82FB223DFC6 +:1076D000FC914D43BE5939597B8FD6FB156825D097 +:1076E0006E265F3ADBD532C188F18ECABBDD2351ED +:1076F000EFA90C5A347A9A996A857554823E86CFDE +:107700007423532DF8B432333E4B9671FD2B69A48C +:10771000D75809E357B63DF357FC6EB61ADACFF5E2 +:10772000C900ADBBB2ED8DBFA1BE3653F31A915F58 +:107730000CDC61E43AA9C087C1C1D832F283E87297 +:107740005128B63CFC706CF9D3140EDF51C28F7512 +:10775000609F89F8F6BC8FADA47FEE05818776B275 +:10776000FF0513C98F31F36CB45F1F9FB36E45BF24 +:10777000DEFEE3566A3FF7390B6FAF0BBE8865FF3D +:107780008B096467CF4B099624C3BC5FF95A4FF04D +:10779000C66519B0FF17076C5D85F5C383251817FB +:1077A0007BF93AC63AB05E0D0CC175BEFC0FEEB760 +:1077B0008E3C6B0A6C837E3FDEF3CC8B3FC3719FA4 +:1077C000CD4A56607F6E40B900ED463D69B6A2BD18 +:1077D00031EAE3E7FB20DF98B7C314B3BE175314B5 +:1077E000A13FB89310EF7AF23B9E5AF90C7D5F7877 +:1077F000F618E1DD5E835F87713CFF4A8E677B2D63 +:10780000DC4FBAD7921BC07DDA97C2E9EA06DDB633 +:107810005FD6A27EF916D7437AEABFD03563737973 +:10782000377EC6CE7A18371FF6F9E247D67BD01FCF +:10783000D77F7DEC3E0D08C4965F4BE17AC274168B +:10784000F53E1FE7D37BB90BE7B395D17C0ACFBEDA +:107850007F573EEAE326AE87C48FFBFB142E3F7FA3 +:10786000F52BE887F3193DD7C3016240D7F3043DF8 +:10787000BCA2703D18FE166601FECF4305A277D765 +:10788000FB7971F390FD2F1570FADC9CB40DE5B90E +:10789000D3C8F1FEDC92C38F621C53B63BB344D312 +:1078A000CAA3FCCAB3D6CF3F9401FB5FDD9A4A76E8 +:1078B000A67C5FFDECC1B41FC2FBF33B540FAABE14 +:1078C000D5539F7E6414B67B561FC47962BD06FDF6 +:1078D0009F0FBE9684ED666D720C437F89FC7EF629 +:1078E000FA9BB5F2287E7AADF424E9BF5AD8C7BB1B +:1078F00046768CCD0278CF5BAF78B0D9BCE0F72765 +:107900007D0F759D4D7A0FC6374A54E6D50F23D3A8 +:107910007D323EAB5B5F3A9409F575FB4694E0BA65 +:1079200056E9BCB70D467AD962203F58FCFE189D37 +:107930001C7FE1FB900EBE5F75A7AD0AE322D06FFE +:107940003B960F146ED3A31F3FE92CF037FEFE9831 +:107950000E78E6D9B6878680CD02786C6B42FAD86D +:107960008B8E0B1CE7053DC90916E2EB1825FCCFF1 +:10797000F3FEB3C5A8C2F3ECD96549A59CFE689F88 +:1079800090A93B617D554F0E267A9DBD3E96BE6403 +:107990003B39DF3981D8FA78BC28704A7F052B8CB7 +:1079A000C6AFF87629E3FD46A4C7EA45C0CFA3E8F1 +:1079B000A6FA74B311F5AEF871508364725FF58462 +:1079C00097CC4DEBB5F0F582CA6B86F59EC37F71FF +:1079D000BFB98276FD5C8596C8E65DC7CADD00CF7B +:1079E000791359053E253F3C3F323804DBEF35849F +:1079F0009FFE25F1C144E207E7EDA124F42B650ABF +:107A0000BFDE79772809F9DC4511B7C37A2CCF6D31 +:107A100003790074FDF12746920B4B83079370BFE7 +:107A2000CEBF68D1E9605F3E6E4D29437FD0F9E05B +:107A3000EF92705DE7822965E8D7EB894FC4F33791 +:107A4000A90F9CC47F5E0F7A8F531BEB44F86290A2 +:107A50002103E44D4A7D517D37742FBF731AEB8BA0 +:107A6000304F23F2239B671B8713C5F33E3B9CB229 +:107A70000DF75BF2D94A85F72FBF9FEABC3ABE5A91 +:107A8000B16A00C5993E63EE5EC8E7EF46DA80F959 +:107A90001DDE5FD00BF50DF9FEC134EF3D4EE8CF92 +:107AA00055D641F901AE71CCD3004D3FD07BEEB736 +:107AB00003FCEF6520FFF059EC3392DFA63195D639 +:107AC0003743652115F07D06CAE72154267D68C637 +:107AD0002625D000EBB977752CBC66B598BAF004B2 +:107AE000FE9BC380B122216E8A6A07FDCF41390C0B +:107AF000FB30D7CC4209D0EFDCEDB1DFCD63219A6A +:107B00004FF5F3DF98BADB8FBF8AFD78304D5B8489 +:107B1000FBA14C34D3BC7EFC824272D229FC9591ED +:107B2000C77A0530AE364FCAFD77F8BED53D50A9AD +:107B3000DD0BF87771D10CEDDE144A3DD1501F6199 +:107B40002D8984CFF3CA592807E637AF4D090D4E6A +:107B5000EAEA8FFD46E1761EE3F1CEBFBEC3F7F140 +:107B60002EA13FCD84D7A88FDCA0E3793D910D0AEB +:107B7000C9D751CF2BFE44E0CF33CD602A229F12CC +:107B8000EBC6F6BDA03C9BF9094EBF74E6D3FAE6FE +:107B9000B00E23A7A340431A8C5B7B167813BB1A45 +:107BA0007CB89EF6FD73E6A17DDF82734E457C288E +:107BB000213C91EF414F6296E4CBBFC7FDD3A2E0D9 +:107BC0005DB529B6CCB647957BE3FE40396ADF6ADE +:107BD000777E63D2BAD9AFC73AE55B60C084C1D1C2 +:107BE00074C2F5F013623F1FFBFEAC0CE44B6B500C +:107BF0009FCE141D8C443ECEA49F256486FEADC34B +:107C0000598CDF05F43D2ABFE2FCD1B8F5D98CAD23 +:107C100033F8287E3143EF3D84A1B6A274DF6F11A3 +:107C20004F66E8B45C95E0AA1590FDBD88E3C3E318 +:107C3000C3EA07D4776377CBF9AF5382211DF2A74C +:107C40003D5C5F492C8E187C5174FF9EE0BBBD0EDD +:107C5000840F6521DEBDA4509C6083C21A1580B3D9 +:107C60000BF619E5D306E5E42194671B6E75B306A0 +:107C7000A82FDE3961FE6B64BB5B29CFA86667A9BC +:107C8000BEC646EBE7FA7342FD561DD4A7DF533854 +:107C90000CE90DD67DCF44787FC2E9A67965D83846 +:107CA000FEB896F9F317A09FF88077FE6B8877836C +:107CB000ADE48F4B07582526D3B309F562175BAAAD +:107CC00060BBE5A90ACF83A864537E3388B059ED21 +:107CD00095CC9FC7E0A9A8AC11FDCBE92AE8D9FC57 +:107CE0007D238EF358129F57AA4E7FCF04D4F3877B +:107CF000F172F26245DB46F26C2DCD2BDDC42A70A9 +:107D0000DDF81EED029886D64AF5018253FA98FAFC +:107D1000229C477A1FFE741A43D9D8CF914E3CF16A +:107D2000E9507E2C147AC0C2AD65E9C8EF8F9C374C +:107D3000ABC8D78FB8A43E1BB2A13ECBFA16F2F661 +:107D400042DE2E2C1A938E44EDCC8D6D77D1A0F5AA +:107D50001A8E72EBA89EE24F7FB169BD1CD0EE0671 +:107D600023EB36EFAF572ADFD7BA2F151688F26309 +:107D7000D44DB944F642DD976ACCFBF34BCC2C10C2 +:107D8000E5C7A8AE3A3016DBD5B08EE5888F35C191 +:107D9000041688A28F1BACDD8F2BE9A2EE4B3DF3BE +:107DA000773BAE31F6FD9729CC9FD25DBBB4D8F7B7 +:107DB000B08E98F2EE2F3AD781EFD9C87012FA75CB +:107DC000C7A37C86F2C580CE6F00BE75C4C0E5EE49 +:107DD000057B38462E5F7087B95C46BF958DCBB367 +:107DE00009B8CF6A24696262D738B21EBF4F8E5A73 +:107DF000EF85294616A2FD89D03C107EFEFE8C6DD3 +:107E00006CFBD488F93AD56DFB097E126FA2E1E8CC +:107E10008F8E8335748474C033C6A56E5F35680059 +:107E2000A0E001C91F9E5EA58D867ABD2E865F24C7 +:107E30001477F20F62578F61548EF8CD33ABD06F49 +:107E4000DB55E6EDBBBEDF310EEB8B07F1EF27A76D +:107E50003EFBE6324A6A69E67A971AC9F5264695E4 +:107E6000CD71651B94074795ED71F5CEB87A575CD7 +:107E7000399BB73F9F18CAD57B18BB27F585712A58 +:107E8000F0CDF319A16998C7B6BAE1D7E3CA819FCB +:107E9000D51473395FDBA678485C09F8D57AB81E2B +:107EA0006BF3848D983F9750DC7108F94BF56EC5E4 +:107EB000AE003DD882AD212AE377EEA8EF820A7D9D +:107EC000571D3C49DFF5D87FA18EE87D55E129DEBD +:107ED0002EF821E9132B1AE753BE808C87EB994FBC +:107EE000CB52BAE2E192CF5EC8D00E129FDDA7D886 +:107EF000913E3BF114FB8DF243C9F67F1ADCF64745 +:107F0000545712167EBA14F5EBFFACF97004EA9BD5 +:107F10007F12F2649D121880E36E64BE01284F7FC9 +:107F200054D36FBF0EDA9D30843763CC6F4BEA6B4E +:107F300004BF1389E11CCC0B0C3CF6EFBC9C1ADE91 +:107F40008CF0BCF458C738CCFB3B9113CEC13CC07D +:107F5000EDA9FFC5CBFDC29BB17CE4B133BC3C387D +:107F60009CA387EF7BFB3F1C570EDF3F65EF9EAE68 +:107F70001F13FC44CEAFB6AFD69C8A7A5E359743CA +:107F80009BC1463303DF9C36F7DC0B4F011CA6FD7B +:107F90003481F8D953E7278DE3F682DFAB96A03F13 +:107FA00099FF919C247EAF929E9181B231B96B3F33 +:107FB00012733BDC2447AEAB6F45FD257DDA209282 +:107FC00023E54EED0B1C573EF767C113DA7F916A2C +:107FD000E7FC5BAFA3F87AFACF1249CF5B63E1EB22 +:107FE00001BAA1FDB589FDF89558CFAF52B91D7AF8 +:107FF000BFF366EAE72EA1DFB7AC0C3C6B01F81FBC +:1080000097793B6BB9BDF0C3ADC057808FB738B41B +:108010000CE4273F147978927FE0FBE4283BA9A584 +:1080200008CAB62E7BB86582966175E2334D8771BA +:1080300024C98F5AF2F977522EA537F071D3D70C95 +:10804000D886EB4850B93F6CE694826D4B492F9827 +:1080500048F3659A96A1407FA7E7F4D6A19F4CEE1E +:10806000CF9ABE5A3BAD47C419E43EC9FDFC2295E8 +:10807000DBF733F4A057C03A2DE93EEA0FF48C2128 +:10808000C21F477AC617B8C751F0656A7804BEFFA9 +:10809000FF084E1F7D1B70AA5904FC427715FC4255 +:1080A000C06F9D1232A4737E41F63DBE47B9D3EE38 +:1080B000F47D9D1A95AF33ED6735A457CA7925FC39 +:1080C0006457C50FD8E57416AFF799D2F87E49FD0D +:1080D000D423FDAA629C13C7CD144739610C12DF6B +:1080E0003C0176D552E42F220FA0E4A7F38EA07DA9 +:1080F0002AFBAD49D373FFB4DC77C5DB3A2B1FF302 +:108100006298DF8CEB9860A47D9772B7C5C1F35C71 +:108110005A1EC8A23C978B2CCCC83F3B92117F04BF +:108120003CA0FAC8D434A27F68EFB760FB39D751BE +:108130007BC00B3FF187A956B2835A306E8EF55340 +:108140000B03989783763CE1DB1C1D8DDB0DBE7025 +:10815000FF777F9EF721F126AD81FB9998AA0D99B3 +:108160001025E76F4DE3FB9C501C7EE93F50AF5D4F +:108170006D21BD16652CC5A89AD3A91FD8FF6169CA +:10818000DC4F417876EF238922BFCE5382705D9118 +:10819000C8F1729385C7CF36811E4D7C51E0AFCCBC +:1081A000EFF3097D2F5CA54B427D414B937633C89D +:1081B000F512E1BF87FAE961E524DA7FD3FDFA9091 +:1081C00009FDCC4D376BE1283B06FF30FE788FE090 +:1081D000AB6C3D233BEB1EFC2E09FBB72661BCF5C7 +:1081E0001EFC1EEDC8C537C7C41527A671FA96F345 +:1081F0008BE7FB13E5BC9A1FD7A2C791FDC7F70712 +:1082000076EDA4B4548273A817EEEF523DED5FFCF7 +:108210003CC3EBB91F3EBC3E8FF04EF6D7D33CFFBC +:10822000AC8FDCA7801C9C3586DBFBD2FE9929EC49 +:1082300071B638D6BE43BF4F67597F7939DE5EC409 +:108240007C81D8F65C6F4918143112DDBA9598F923 +:108250004B78F5048707AE116E52EE3D6E013A0081 +:108260007C598F7995805FEB1F482039E6340606EC +:10827000205E6DC47C1D92A7DC8EFFFC48AC3F26BF +:108280007EFF7E9E26FD6AD7667F3F8278D18DFD78 +:108290005D678D6C41F8D75919D1E7857D89448F89 +:1082A000AC6F781AE6D15DDC6B62480FB54AB80056 +:1082B000F9E00545ABA4764B13DC4897D2DFF1C15A +:1082C000CBDCDF51873B03EBADF3FF17E571D5ED59 +:1082D0008EB5CB2FC07F5540471774E112EC4FF29B +:1082E00017D0CB35D2B7AA787CAB56C7FC68B7DDC0 +:1082F000A09B3E87F38D4CB68DDE9F2C5810A5F7C2 +:1083000043BB762599A323D261B5D8975ADD296A54 +:10831000578DF958B83F68BFA11F102BA3FCD6B5E5 +:10832000AB3FA67CB0DA9DB1F853DD855FCA370A52 +:108330007E17856FC41FFC82BF30EE8F29E7F1F9ED +:1083400044514EA8E8A0FCB03AE18F493D101E8B85 +:108350007C2AB138C8A6C3B3EE2CD75F46B56D3DB5 +:108360008876BAA3A22307C9AA4EF84125FEC87988 +:108370005EDFB6568F76A4D47BA2ECD8011363FCE3 +:1083800018CBE83BB48B71BC30BECA40F4E2F27249 +:108390009D9097096860A35C6DEE4F7215E51EF223 +:1083A0003B695723FF43FC2A4A2F3B8EF4FF467A52 +:1083B000D91F399F04BC453B018DB4EB7BC63F09F7 +:1083C0001FD90EEDEB7FEE9F147C9C71BFE48237CA +:1083D00052FF291D9CEFE4AF57F44BA623BE2F504C +:1083E000DCE988EF17057F3CBCBF80E2A0F2FD19F5 +:1083F000BD8FFC8FD2FF3507FD7EF0AC16FC689672 +:10840000F097CD927EB2F5B1F15AF4534797E74A0F +:10841000BFD90E53571E13FAA9CA592811FAAB41F6 +:10842000BF1B3E83B1DFD5B2087D57B7FB1B534C52 +:108430003CB885C3F11E814F8EF2801EF9D8060B21 +:10844000F79F49FE366AF156C2935EC3B4FC87902B +:108450006EDE3090FFE57F0B3C90707930ADECCF55 +:10846000B8AF56BDF00F3E6422BE7E1AF48556E1C9 +:10847000F7998876F212A6E13901A6DA73A3ED68BE +:10848000F95CB5D75285F89899AE8BC1D7F634030D +:1084900095C91F46722381F402607343105F4B7AC3 +:1084A0004BB9CD86A01FEEA4B0EB6BEFB4F9B0BF13 +:1084B000B08EF3C5FEE97C9FFBA7F3BC5959EEB41F +:1084C00043053ECA382BFAA5A2E314433ADBAF15A5 +:1084D000FA2EA3F5AE9B23F2E83BE942477C2E61DE +:1084E0009097E4C30DBA32E273918F6C6E844BC5E2 +:1084F000C7D573701D9F4DB1D279C97B859FFCC6CE +:10850000749E8726FDDBD7EA272F4DEFC4C7183F9F +:10851000F95EC117F7323E5FFF592BF7F7AACC8FF0 +:108520007C726F704000E75B29FC23A87F21BF8E1F +:10853000BCC4F791A95C5FDBDB3638807474D2E091 +:10854000DB3013FD4DAD06F21B3235F0ECD3D8CF46 +:10855000AB191ECCB3BAA08B6CF93DB4DB7BF657DC +:10856000591857DB2BE21BD5C65001E9F522AFB4F1 +:108570003A2954807EAA57C47E555BA10CEF532C38 +:10858000BEBBD253BBE28FF81DBE3F15E076C329B8 +:10859000C6F1C0BF9AC79701BE193371BE2BD3294C +:1085A0007E89FB82FBF0C1BEC1B4AE7506D17E0FE1 +:1085B000F7732B130BA7919C59654A41F85FF41A86 +:1085C000292FBA6E0DD76B67E8DC5B1621EF7D357E +:1085D00081D637B3E528C595EA1E994DE74DEBE600 +:1085E0002EBE9DFD93780BCAA968FFFE0516C9250E +:1085F0007BBDAA773004F3B8D036C0C3C3A5FCFC5A +:1086000052ADC8BF3D6D601ACE3BB2CF10E8EE5CF4 +:10861000654FFD9383B384CB4B1CA72E3AAE45F236 +:108620002536CE75A5F20543B8E001187F758A6F2F +:1086300075BAD03B115E75AF66101FFDE0E12F7279 +:1086400049EF69E6F194D3066D1AD289A33C649C84 +:108650001EC55FB70B3A9E6112FA2DF0C168BA973A +:10866000F52565B174269F4F0A7A4B14791897D770 +:10867000CB3CBF492694C7DCF585FDBAF9393411E6 +:10868000DF1C7536B21FF3D9AA8345143FCD5B1C9E +:1086900022BA047887D03E39BD2191F3135826F6CB +:1086A000336B2423FD7A969EE795CC3281BECEF5BE +:1086B000026A7F66433AC1A16419D753232F29C4A4 +:1086C00017659CB792F1EF77359EF4EBA17DE50E2F +:1086D000A508582BAB6C2CA5BC93B99BF269FF473E +:1086E00009FE3BC3A4156C407CDBC5E384301ED976 +:1086F00005D5985B378CF89211E56BD50E85E22590 +:1087000072FDF1715516888D478D0A72FE8D728348 +:1087100045E993520EA1BC60717A6E2C5EF8AF4AA7 +:108720009EC6CB8377D3AF56AF8C95A7EF21FF4A78 +:10873000BD5C9E82DD701CF1B0A48CD371A495C782 +:108740009F6A583D8FC30979D6B92E210FCFE8B95A +:10875000FC9D655A4BCF8BE93C0E359785451C2A0D +:1087600062C4F9F5845F17D3657E7B2C7E49BC8A91 +:10877000209E417FD56759E8BB305EF56216AA1985 +:10878000C29F894348BE73396FE6721E9FD6AB9075 +:10879000F7F1723E5EAEC7CB73146728B7253E452E +:1087A000C723504F1AB538A0E7FEE66C3BE665CA12 +:1087B000FDBDDFA939B253BBF4C0BA6366B37B28F1 +:1087C00096BDACB70DFD68A59B73A0BE4EE5E7C393 +:1087D00013004E5BE1FD666187ACCAE174E612F9F5 +:1087E0005706D5CB8A6CB84F1DE43788A432CAA788 +:1087F00097F0DD9C08DF613E420EC78FCEEFCDAC17 +:10880000D11AF57DD95E0BC9A94B7B12E91C205307 +:108810007D790EE82FED4F603F40F9C2DE44D21360 +:108820002E08B9E194FE19B69CF6A38F8BEFB39F87 +:108830009565A19F9B29E3B2189D8FE7FA6C8DA3E4 +:10884000A7F884A8CFEFB893E39989E4F52547F812 +:108850007E2CC37C28BF3BCBC5F7BD6EE798A29F9B +:10886000615E86D7E6E150F515A1FE61D22FBCD33B +:10887000ACC77B1216471E8075D4E4D8286FBC3C69 +:10888000EFFD77A742F9A39D063A5F3AE7A949BDF4 +:1088900042F899AAB9BAA393390143CCB9C5793B37 +:1088A00062CB35C1D8725DDC3D058BDEDFFA667BBD +:1088B000547DB94B9CEB74330FE6BD33FDDDBD7CBD +:1088C000DDF05DF9FC6249E0CDF67E9437789B8B54 +:1088D000D3B311F5A3E9880FDD7CA773F17D35993A +:1088E000EACFE2F903D32B26BACF20DDE59BEC4A91 +:1088F000453B2A7208F7D394777E08CAD3B2BCAF3F +:10890000286E78E941E641F85CB294929E746983DE +:10891000C58D76634BAE8DF0A0E55525A070BB628A +:10892000FC08E0AF55341558EFFA5B3FE2876598D5 +:1089300099DF7F0056950BF9954676DE990956FB2F +:1089400032F8AE6A3D97DBD5AC2309F9C006B97F92 +:10895000FAE78D66F8677EA3366029CC779ED74A02 +:10896000E7A4D4AF55BA1F600576196597D4BB3814 +:108970003FA831878DA538FE570B2BD00528FD79F0 +:1089800026834FC3F37886DD45A12C78357BD14112 +:10899000B2BF3AE3F6FB38DF9AFDC07E7AAF4CAC4B +:1089A000A0F59E81F5225C0E6E30D17ACFE4D8C856 +:1089B000FE3DB399DBF9B3EDC68099F4962F53F0E1 +:1089C0001CF399CD06BA3FE07278DC42E7893FDCC0 +:1089D000F43AF91B3F647C5CFF4E3DE93D1FDA230E +:1089E000252184A3BB3E09F5E6AAF573E83CF2EC29 +:1089F000CD7A2FF2B3D99BEFFBFDF5E8279B785793 +:108A0000312EE926C7C234B7ADAB5EEABB6AF2C805 +:108A1000A7910E6FFA7A4CC74DA8776D063AC9E751 +:108A2000E71D50DF6FDF7C0BE9B7B327581DB82E69 +:108A3000F7A6A7C6A21CFA7042269D9F9EFD82C281 +:108A4000F0CA8CD98E4569F87EB6A27ABBC3A7A1BD +:108A50002E7EEEB934CFE609E1777FD4139E005D18 +:108A6000DD8972B866B381F4E7F689C7DF9DEAEC69 +:108A7000A22B65E2FADB4761FB670CD4BE536FDAC9 +:108A8000F43D892F2C5482F619875B3C9D99F21690 +:108A900017E0BCE2E96DF6B2FA021EA7BB36BA6374 +:108AA0009B38DDFD9B4BDCFF71F574B7D7957AF5EC +:108AB00074C7B29363E4F0E5FCCD4FF094710EB34C +:108AC00087694FD928AEAD29C07F3FC080FE087CA2 +:108AD000F27362EADF16EC780BF1D8E53B82F3C85B +:108AE000635A11CA4D77C45E8667C06C422F649B7F +:108AF0004CD29E203B615D2A7B7A55945FE4CFA2E5 +:108B00003FE0037FC47E2EBCF7D521DCA7DADCF37F +:108B100043D0BF5DF7E55F282E6A6BE371759B2735 +:108B200042F90606A797F050F2F73A0F973FF1EB9C +:108B30002AC8E0F6619D3342FDE833DD546E1171C1 +:108B4000A48D8BACE437DEE80C58B8DFC3CF503EC1 +:108B50008D1FA9E7F140A1B77D4FF85DCDC507197D +:108B6000C601D9689E8FF756F1413505CABF1F79F6 +:108B7000B387CE51163FD9D41BD73DDA20EAFBD0BC +:108B80003D27FFAE9552FD0297DE8DF43DBE98E77E +:108B9000A3B2AA24F2E7BC55FC81F3DEA8F97B99C5 +:108BA000D96D03BC9908C41A9DFF78FB688BDB164E +:108BB000853F9F352B155C7F76F79A3C98FB6B4879 +:108BC0001E17C7C26381CB48E3BE915ECA3200CE96 +:108BD00037DDC8F7E3DC0BA600F2C173E25C523C60 +:108BE000FC7A6508FC5107C4E427388DC15C949376 +:108BF0001F2BB1DFCD6DD2537EC09C26850560BC96 +:108C000073CFEECA457EFED153BB72A747CD27FE78 +:108C10003BF9CCC888F57FC6FBB37BF263CB7617F4 +:108C2000D7339FB94F57FB8B557F273FF6F436E17B +:108C300007D7B4BE4EB4AB44FBF8FECA057E28BBD2 +:108C400015F29F483FEEA9C34F62C4A873FF2C6D75 +:108C5000F9BAE83C52F91C25F66D12EE1B2CC5D270 +:108C6000C4CB3DED574FF47842C821B96FA79AFAAB +:108C7000F442381A6B6D2AE3E7030B51EFDFCCACFB +:108C80001EA4A72F443EB1D30A4FD0D38C992E1BDC +:108C9000F233791FC34FAC49DBF0F985C837765AF8 +:108CA000E109FDE46416527F5FE8BC641FFE44DF07 +:108CB0004CE7466FC9E0704867214541563BEF6578 +:108CC00085F2E49A62E19DD6C0E548A4D248F24B11 +:108CD000C2FD86E9F7931DDCCD7EAD473CCA1CC9B9 +:108CE000DFF933F2851E1DA678896524B3A39FA002 +:108CF000E17A3FCD43EE571D6FCE943685F467CCB5 +:108D0000F34948A6B8B05F3C992D9975C6491284BD +:108D1000DDCCE2E222E9A077633B394F2853BED095 +:108D20001A47B0B980C795492FC57EF1FDF4412A95 +:108D3000C515B09D71D895F1AF134F453EE878F950 +:108D4000BECADA6D1C663C9ECBC27D00F9887A21D2 +:108D5000F31862CE656D027D1AED3D19E7D6EB8200 +:108D6000452EB24F3AC2E887319698DD286F13F44A +:108D7000C142DCBFF8B837B4CBE7F916D90E94334B +:108D8000F2DC55EDA2315E8CC781FEE137E3FE4D8A +:108D9000E0FB57FB4029BD5726162E45FCAA5BCCAD +:108DA000E87E88316DAD940F5657C1F5B1BADD2715 +:108DB0008D0CF077BAF00B31E1174F13FB7A4AE8CC +:108DC000DF5D71BDF016CCB76F99934DE7ACE3F35F +:108DD00067AE35AE7B31110032342A5ED7CBCCE59D +:108DE0008CD87F49DF327E9738C89B8F9AB861BD97 +:108DF000E98875C4B5E4C7841F2ECFFE27F931FE7C +:108E0000FADB313FC68C5ABEA8C769801CED3C47CF +:108E10006971537CAFB31EEFBF30EF56C47839B7DA +:108E2000DFAC529EAF289F5A8D7EB1351616335E49 +:108E3000F4FCD4B8FE0DD0BFCD2DDBEBC6637F8F25 +:108E40000D13657FE56ACC075A6388ED8F50509EFD +:108E5000FB34778DB7393BF8F0EAD15DF21CE4FBC7 +:108E600061941752AEAF383EBE79A81BE9EB73CAC6 +:108E70009B96F2B9CEC9F365E2F9D8DB829F835E97 +:108E80003C1645EE8A29F3E9BE88CE38775BA58685 +:108E9000FAB08C73D72DF652FE34E803FF9141FAF5 +:108EA000C0F933FB19EA9DE7C82EA8FB52E5FE2660 +:108EB000D02BF0FE1F735B29F955319DB75FD4FEAF +:108EC000CF15720A7578A487BA4D3F784A0FF543DB +:108ED00033B530F56BE8FEFEAFBF65703DBEAEB09A +:108EE0006C03F203B65DA1FBB756157E467A47EDDB +:108EF0009E9B4744E7FFCFD9FD18CF1FDF61E8767F +:108F0000FD7FCBE07A6AED9E97C86F7A2EC08F2DD9 +:108F100055A98195A8875655E950F362C581CAA91C +:108F2000A40F4C8175C0BAFE9CC1E153B763921F78 +:108F3000CF23D4C17F0ABCDAE89D4576C1C6296635 +:108F40001BC697EA0AA7CF27FCB75B355C7FFC3CC2 +:108F5000BBE2E9563A37BE6AB7A102F5A812D09B28 +:108F6000FE0DE69B933CAEC2037C294BDF5AF463B3 +:108F70001BE617742F97B764713DA051F1FAEF28E3 +:108F8000267F298BCE57CADBCDF5337BA631C63F72 +:108F90006FCFE4F74C8DF6778C419C7B550D27A065 +:108FA0009E5CC7B44FD1FE655E9B9BFCC48CE713EF +:108FB0003897B8C94F6C76867F3E94F42895E2E9DD +:108FC000D2BEB8B087FBD79665FA7232D13FA80FF0 +:108FD0003F7A07C2EDE7AAF037733E933BC9360CE0 +:108FE000FD611667F8D10A37E519915FA2D7771BA3 +:108FF000691F5E75323BC2678CBF5255A2E48CE498 +:109000001B633ACF4D39C90F5BC6D91AEB07BB7545 +:10901000C64C28DAF84D4A979E70F8ABC92ABE9420 +:10902000FA83CEEC233BA77C0AD88D8897CB238785 +:1090300074E8F7777690FE581354689C9AC2DF5014 +:109040001EE03C916FD699F7A586290FEE3B990952 +:10905000C28FD9C8F19275905DCC9EE7F007FE44AF +:10906000F9715D7AFC526A27FB338A78458DF0E30B +:1090700000A0A8BE2C53FAE19689A7CCE7E3E3321F +:10908000D55D12ED775837012409CDCB9D84F37D52 +:10909000C4EABD2D13E6750AF017D779AA2981EE27 +:1090A000035BA77468E8D7F417F1BCE1783CF28958 +:1090B000717B1D888C457912D9D353DE30CF13DEF6 +:1090C00030E23ACADB2FDEFDE958C40F56C1881ED4 +:1090D0006B775F5DDEF04CB11FFFCFE40D7B146D4D +:1090E0001B3CEFCF7470FD4AE60D7BF87EC9786BB0 +:1090F0007CBEF0858C90CAF3FAC25B9E42BB7DB702 +:1091000089F261C6EF7EFD18FA35C79B5990E2CF10 +:1091100071FA43C4396909D2C9C54FCE6C798861E7 +:10912000BEF9CB1E7E1E36561FE8C91EA098499474 +:10913000DDB83653E8E7DF923D20F9759DB0AF3ECC +:1091400056228F14E0FAF6E9EDDD9D5FDA22C7EFD3 +:1091500029DFA5ADFB7C17E98FAE08E7C7C4BF7652 +:1091600074F6776DF1B4E7507676134F5345FE9A57 +:10917000AA70D6C11C3CBF49C6D3D4D6011427332C +:1091800075C5D342AC9B789A2AE2532B0C5A25F929 +:1091900069F699DCDC8EF612FF6A6C4DF5207FAB28 +:1091A0009B7BEE453C7AA13AC6BAF09C5FA3807FD8 +:1091B000F5D5C7D3DA33BB89A76D157ADB0785BA36 +:1091C0009011E0BA9571FEEB6F9371351DD9B59191 +:1091D000877368DECA4433CDFB83574DDBD03F3500 +:1091E00043C6CB5EE5FEB519222EF6C1C402F23F9E +:1091F000F504E7194DB1718777059C2F594AC94F7E +:109200007FFF2F26907F7E16FAF7FBA07FAB59F8E1 +:10921000EBB99FCFDDC4EF3170EF50E81E59441316 +:109220001DE9A476BA4F761EB0D18DC87AFD80357F +:10923000DF81D78A4E417DC8DD086550FAD595AAF1 +:10924000DF05EDB61E4B20BFE20AA75BE4E7F1F8AD +:10925000B57FB512E8C7FBA5FBE3FC8D3A0DFBB962 +:1092600094C9E57C5296B1DBFB281A0D224E22C62A +:109270005BCA60DFE1A953F87385B89F301E1EB248 +:10928000BF4643BD19FD7B911C7E0FCD25A33685BE +:10929000FCCEC90574DF5463627D5305AF279ABDC8 +:1092A000648978A9FEBB2A5748993B99F2A83345AF +:1092B0005E621C9C6736C796E3E347F1E7E36630DE +:1092C0005FFF8C3E979F1F3B8FFC16FABFB42A5F4F +:1092D000EC8B87E2288D06F71FF2290ECBEF935A0D +:1092E0009ACDE1A6CBE1CFDE8E72BA1710E885EBFE +:1092F000718CCFBFF7779D0AD24BA383E3ED7F77C5 +:10930000DEF1F34DCB2AE07A8D83D36BE34A25C09F +:10931000E1C5E77DB57E92E2AC6FD74FF281E2798D +:109320003A944FDF117FF03F6C20BADB6BE1E75ED0 +:1093300025BFA28423B43F85BD7B232AD318573D84 +:10934000BB9CEE85DA58D53B09E3AE6326D9681D90 +:10935000B5AFF273D5358BC3B988D7B565E182FA5D +:109360006EE08A03A892BF42BBE94EC6EF176A8A35 +:109370008D23C6C78757A768E3B346A0BDF441EB6A +:10938000EBB8DFAD1692AFB58B234FA3FFC097E2CA +:109390009B9405F871FE81E36315377D46FAFCC5A1 +:1093A0007DFDE93CE8F4C6D873716C756C7C923530 +:1093B0002593DF9DB5C4BEC7735B31DF5D16AFE497 +:1093C000FACD3AA36F00EA9F37DDC8F3313E99A387 +:1093D00063B8AF9F58F8FEFB1F4E14FCDA53102DF4 +:1093E0000FEA7BDC5F683708F302789EAC6C5F8322 +:1093F000FB0BFB5A2DF6F79397BE5380FB7BBEF514 +:109400003B05B8BFEB0CCD1AD24751BA6F21C2E36E +:10941000F4CD5ED20F655EF0D5E25DC3B78C77D731 +:109420002A8F9BB3FE35798C7FD17E9357BFD2FBB9 +:109430002D245FF879E22EFFDD39BA57EDE2973A35 +:1094400005F9714FFDE50B3DCF65667ED4C34ACA71 +:10945000C2F45DC9DF750CF541A907C7CFFF4931DB +:10946000FF9D599A09E5A0F4F75689BECD81CFB981 +:10947000BEBD5D217FAED9ED4F1A45F6D5CCE17A60 +:10948000E22FFF46E742589B62473B65CEF6A55464 +:109490007F61F70CAAD7994321B4C76AA01ECB2BD2 +:1094A00046C7E6791B77F27890B47F611E7AD4D7ED +:1094B000129C1123E2672DEAD730C55A95FBBD6B8C +:1094C0009DCCE367A80FC7DA8B32AEBBD1CBEFEDF3 +:1094D000D9D8A6D0FD5D69465F7E36EE6B5C7C77A1 +:1094E0007F96760EF14EC6E71F4CD30E22DD3A8DE5 +:1094F0002C97F2F90CF25C5AECB9CF9EF2E48E761E +:10950000E2C195F4A8A9A42FFD9579495F7A072FA8 +:10951000CD243DEA4ED2AFE4FBCBF3E40231F1FCC3 +:1095200059E29CEE2C714E17F97E288EEF4797ABCF +:10953000A3F2E442DDE53B44E5C9457F179D2717CB +:109540008AE18F9C9FA4EB17501CBD0EE866D1B03A +:109550002EBCAE66E26F7DE4033A37B4C3447EBAF4 +:109560006A91C75B57758AEC9F3A3C87C4E95BE315 +:10957000E7E9B97E550D7625E5330763F37D95EC74 +:109580006F57FF96ED7AF2C7DBB2A59DC8E95BAED7 +:109590004BAEA3BA4DE1F41837CF787B3ADEAF2E4D +:1095A000EDE1ABE573EE6F79DDD7CAE706C7C1E140 +:1095B0005FE57397C527FA46923CDF427CE223774A +:1095C000731ABA28659E74D33E9E273D566FD37892 +:1095D0003C54CFF325E2E3C2EEB114F7947168F383 +:1095E000CBFAC0B27C6AEFC17CB49A7D8994BF503B +:1095F000E5AE223D3E3E1E3A97B58EC5ADF82B3BFB +:1096000042E7DEFEBB7908DFCF4E74129F72B3FCD7 +:109610006BCC43B83BFB1AE2A1076D9FA7F8A2F001 +:10962000A56C101804837ACE379B2BF63F41E4AB30 +:1096300098553F73447DDFD3770BB2B93FF1A0C893 +:10964000935A939840F737B88CFC9C874BC7F3B973 +:1096500086667A17E2FCCD6EBE9F4FECF901C373AC +:109660007B4F1882749F82BFC6E641B928FD58B26D +:10967000FF76E15FBD5A3A5AF93FCC3F1E957473AD +:10968000B5F1BCF5008328FA8AA7879EBEEB89BF97 +:109690006CCFF63EC1F1421B427190ABE44B09C561 +:1096A000C0B751EEEF34B9D11E41BF0CC9DBD5199B +:1096B000D29EE7F742ACC921B9F88985DB27F2DCF5 +:1096C000945CFF2EB9FE6F496FB4A47BF764437FAF +:1096D000A74B353A27B12291CB97C8B33C1F29FE3F +:1096E000FC50BC5C91E75FE478BFFBBFCC578F7D3B +:1096F0004B7C15E42CE91D3DC67D2FFBDECFEFC171 +:1097000029EBD044FE0D9DFB90F3AAEBE0797C673A +:10971000C5FCE4FB90D07306E7681F215E9D7FCFF8 +:109720006CC6B86A7131E79FB55E1BC5256A833C7C +:109730005FA77631233F823C273CDBE5FB1CF76FBC +:10974000C5711BDD5F5BBB7B6B536FCA67F091BE5E +:1097500078E13DFE3EDDE5FB02DBD52D0EC7C43FC3 +:109760004ABEF97C794531CD97FC004E53ECF9ABFC +:109770008C1CCE6FE4332D47C217EC1DF8EE7C1520 +:10978000CF3FAF736AF652CA63E0FEF5047707F97C +:10979000956A77929060940C8BF53FCB26BCA9DD3F +:1097A000595A44F736042D45740FD19FF8BD5DE733 +:1097B0001FC80CE8B93F3E2967049E3B09DC8A7A42 +:1097C0006B1E8C832AEEF9D65B8BC8DF1847779225 +:1097D000DE3ACFDDFED01C6850BAE8719D81CB49DE +:1097E00029DFFE91EDE6F110A7C8476C9BC066DA51 +:1097F000BACA36676C9EE6CEAC9BFF81FBF38F6CDA +:1098000055C4D179DC3EDF0CD66CEFCBF1305FC4B0 +:10981000ED27887C0BE63777E559F4BE72DC5ECE27 +:10982000AF93EF8BB87DC297E27722EC46C28BC430 +:1098300026CE3718E005EAEDA3231D63F0BC5BDFFD +:1098400096D06884572F043F9EA361E19F0FC5788F +:10985000488A3A1AE3215B160D3B80715A7565C739 +:1098600077716BDCCDF632345967BBBC37E4107FBF +:10987000A92F44FC2FFBA381E747AE4C2079DF9250 +:109880005B4DF991178E9B62CE23C53FFD6C990B02 +:10989000FD50BD9BDEA67844E24EA5DBBCD79FE61B +:1098A000D844FEE43217FAB5129B3AFC23D14FF3A9 +:1098B000B0C2EF0085D92B2EF427A83AD43B66EC32 +:1098C000E6E7E567343BCACCC44F151ECF19ED243B +:1098D0003EA9AEBC4D87769FBA94D17D7BF373B819 +:1098E0005FBC5F8B5D87FBFEDBAFF5DDC6E97C39D6 +:1098F0003A19573422B86A4C914398DA29E38B32EB +:10990000CFAEA77BECA53C8AD7672FD363853CEA13 +:10991000D4E7E3F0B8A7EF247E4B7CFEAD81911E27 +:10992000F65BC54CE7DE245E37CAF3075F733F7111 +:109930009EC8DF39B5EABF86F07B02647C26C0EFA3 +:10994000713584976711BCC237FA71DD3B1DBADAF5 +:1099500041E45FABA57E56F27BF2F29AFA2C1B59DA +:109960008C4F3B53600AA7F6CECB43BAF4031EF4E8 +:10997000EB060F6ECAE17952EACA04DA37752DDDBB +:1099800010CE54471AED9BFA18DF9FEB73383C65F5 +:109990007C58FA4107E7F8D6603E70E739B545567E +:1099A0007E4E4D9CAB4E5C74FC053CFFB545F8A368 +:1099B0000FBC3A907EDFE3D24A55413DF592A39227 +:1099C0007ECF6AA3D8D744B583D96DD1F87980F218 +:1099D000747BEFE3F986AA3837AEAE746E4578969D +:1099E0003B7D948FFCDDC610FD04C6ABF6D314F7A7 +:1099F00003BD88CE079FDBA348BD28461E4ABB2D6A +:109A0000DE1E7B51F2CDFF213D694F279FBE463BB5 +:109A10008BC5DA9B9DEDA5FD186F4FC47DDF93FECE +:109A2000C3347F4CDECD11B1EF52BE670ADE28F39E +:109A3000713ACF89B38005CF714C41A21CD1959763 +:109A4000C444BED27AC5EA417DA9A7BCA4CEBC213C +:109A5000563F94FB37EBBF834F99D724F3962C984E +:109A6000BF927279FE8A05F35752F07750F87973F6 +:109A7000997FD26070533E8BFF4146714965620504 +:109A8000F9FF92BD46C2BF8B2CB0017F07C03FD902 +:109A900046E7EAF19C13E27D447151BF632A34D951 +:109AA0005E87ED3BEF93AC64549FDC57CB403DCCDD +:109AB00002F578CF75E739F399FCDEFDF8FC1599CE +:109AC0004725E3CA99FD5F56D0CF8A6104CA67F87B +:109AD000B1F82E9FF7D3F22337F18DB4069E2715E8 +:109AE000B99ED9D1CF5F26F98F39765FD729BE7C51 +:109AF000A4CF75567ECFC266E669D243B93DA7377B +:109B0000EDE346E6DEAF2386DD4CBFDBF1BC53D38D +:109B1000E7A676E1939C175BCFD77D11CFAD295D8A +:109B2000E35D9CF3F75CD4AFCADA4C1C2FE3C6DFCD +:109B3000D879CF4DC082F2C495CBF1C113A7EFCA3B +:109B4000A72B5789C9FB93E3F7B43E899F57D2E30C +:109B500025FEF5846FFE32B14F271248FF90F8764C +:109B600060C90EBA4FB27D49909E172D4A508FE7BB +:109B7000872D9169C81973F2B2EEC07B502E26462C +:109B800072F11E95016EB717EF51B9981A3981E538 +:109B9000EB9FF8BE97EAFB45B6E0BD2A77E41DBB14 +:109BA00083EA713F33192BDA72E40EBF0DCFA9841B +:109BB0009777A0DC2A8ECB8B89BBFF2141FC0E540A +:109BC000BACD48FA64BA8813B272A1D763440BCAFB +:109BD0000D19451417B431F7CE0EACCF36F17B22F8 +:109BE00018E03FD6F7CBE7F9158CAF9B650B7F37B5 +:109BF0000BFBE9771DF31DF47D271FDF6912F12EA2 +:109C00003EFED197785C52E6093366CF417DC8E6C7 +:109C1000663165797F0A53ED39785F4283F4278A8C +:109C2000F22B09BE49B95172F9E8CD3F1944BF2F53 +:109C3000F3F2CFFA22DFBCC5187B3FB77C26BB39D5 +:109C40009FBC28EEA1BC2FC17777EE08FC7D9969F7 +:109C500063F14AE12929A54607E96FCFEA914FA5AB +:109C60000AFC704CE6F373947B15FC5D17790F6466 +:109C7000AA4F253F01F3B5E851AEA69EF652FE610C +:109C8000B539928BBFBFF396D95785F3BC5479F29F +:109C90007E8A3F661E3D81F922470DCD6392508E2C +:109CA000E48B7B3830C00BE5435979640F76F2873B +:109CB0007E0AC547C74FE6E771C7B1A08AFB3CD60D +:109CC000CECF878D2DCEF734C078E345BEC9D8639B +:109CD000DE24E46F637F1056F93D2111353ABF430E +:109CE0003E99CBE08EA6875BDD516586F755C7961A +:109CF000BFE7892DDF31F2EBFED1E5C18AD680EBDB +:109D00007C4511F76D007FE1EBE2798CBF12F6DC48 +:109D1000401733E7619EA553F1A3BD30705726C5A8 +:109D20006D768D64544EDB61DE668E5EFF5A1D8F4C +:109D30006B0BBFBAFC7D2AAC4379FBF27B6904AFA5 +:109D4000341BF05B27711FC2B703826E0F083A2DD8 +:109D5000C9325B91FF1F30B837119E279ADDE8A703 +:109D6000DA9F68A4FB7F1BE6F3DFB75092CCCC08E8 +:109D7000FDEAA7F332B4633742BDBEC44CF92907EC +:109D800044DE77C3832AF9B9B01EEF41D43F622580 +:109D90007F797952E1DD58AF4F32D2B98BFD8925F9 +:109DA0003E311EFD2EC1F64473087F2723FE1ED6CA +:109DB000A3382F841BCCEB293E0FA2477D8991F459 +:109DC00070793E1FFAA1789E3ED34CE31D70D8F700 +:109DD00023DE357C449A1ED48F74633E99C4EFF21F +:109DE000A491F4BB33407D7DA3EFD9D7A779DCFCE8 +:109DF0001C30FF3D95C2CEDF578161A11DBAD51938 +:109E0000D12D8F0FE648B83355C3F6194C96F9F9A2 +:109E1000B5B4CE72A94AF72D29B2BC94CA8F8B7AF9 +:109E2000796F6C6A1EE7534ADBEB7F43BCED9B0402 +:109E300070817DF224747F7EEAB4E0EF97EF5F8952 +:109E40000BFDFE0AAE7350D7FA0F383C2E6F54B993 +:109E50009B7D0920BEC5EFCB018BC78D7EB62BF74E +:109E6000C7E12AD7A1CFE4F0EC5C474AF7EB48CD35 +:109E7000E3EB088A73E3F1F54A9EEEDB5E67B7F821 +:109E8000F72FAF332D769DDFE23CC3CAB7304F7D4D +:109E90002ECCCFD6353FFAF9B812E49B1CFFC68909 +:109EA0007C6956189BE7C4467ACC5C5F8CCD6BBA54 +:109EB00045D9D488F2F57111377F5DD0D5A184FFE3 +:109EC000D517F5ADD7A715B413BFEDB5B411894BB0 +:109ED000F267C9FF2F659C2CC132C88101792067C8 +:109EE000EEEF7D741A76DEEE78BC2FCA2BE09BD79E +:109EF000E58DB87C9E927E3BE70BF48B7424E937AA +:109F00007EFE928ED8ED414A10DDCC42F474319E33 +:109F10008F0F7A09DD73CFDC395DEB03221F6BAE47 +:109F2000E7EB58EAA779DFE27894F2106FC9F7DD22 +:109F30009407FB3D65E8A774FF147355F6273B4D66 +:109F4000D1B4FF9BF3C58C7F7C2FF5FC78BDFE4A16 +:109F500079E9729EF1FC50CE4799B883F4F83AD073 +:109F6000E379DEBA42FCBEAE4AC7F9F06E85F4FA78 +:109F70005A903328A7E4BDCC3715581BF19ECDBDB0 +:109F800006EE4FF5BF6472C7DE4B159FBF2EEC89FE +:109F9000C54CDA0BFC7E8B1A3BBF774AC89996FBFF +:109FA0007ACB7BA9B83C043915732F55A53BF65ED7 +:109FB000AA1EEC05B00B483F63BD74C22EE072BA16 +:109FC000E57AB7DDCFC8FFCC7F2774AA51E88300BC +:109FD0008BB4AE7BF3C00EA0FB001BF3F2C5BD64D7 +:109FE00001FEBB2C42FF8FF74717A5FB56209ECCE6 +:109FF0001CA4E5E24F04CD30727F33E0DBA60E8671 +:10A000006998F5DBF15ED95B59FD3BBA3E846F0F71 +:10A0100013BE0DFC94DF37DB856F8FE4A572B98426 +:10A0200042E64A741C71FA1EC7715B1CC13FE13DD8 +:10A03000F81BDB4C046F99E71A4FDF51F3396DE0E1 +:10A04000F371EAF5349F27BA9BCFD5E07D345EA546 +:10A05000338EDF3DE13F9E27491CD685FF8315DF08 +:10A060008B386E271D2CE776D765F3D6DB68BFEFFC +:10A070009CCAE3727509D24ED6C667A4A11F928FFF +:10A080007FE74A8E177756F2BCA4096D35148763B3 +:10A09000E53CAEE681FFD1EFFC08FE36D9596440BD +:10A0A000D4FB2BBBDB807ECEC9E363E36F53CCB71D +:10A0B00050BCEFCEC98698DF39957098227E477DD7 +:10A0C0004ADCEF9BC6C3253E6ED7C90FC47AB3F0F6 +:10A0D000777FE099CDF8399E0CF17B7447F33AE332 +:10A0E0007BFDAF31BE772CEF1AE27BED8608DD3BBE +:10A0F000F15AEAEC4DF3816EFAFF7210DDDB7F73EB +:10A10000DA9CED6BA1FCCCC6EBA8FC5ADA0F171E4B +:10A11000C5FA2D05542ED77D3A0DE9A0B064EA3872 +:10A12000FC9D83760BEFC765F5B5E0EFDFB886F4ED +:10A130001E86F9C8E5C608B5BB6D68CD70CCAF2AE0 +:10A14000B7F2F291A2FF1846E5DEA23CEC95EBB027 +:10A15000DCAE7C3AADBBF8E0C0422584BF73579EAD +:10A16000CCDB8F1FF66C26FA8BCACB7879A0A7744C +:10A17000651FACD77D36AD3B7DC428EC21A95F7B44 +:10A1800005BDEFD24E36E2B944AF4DF1E0F913EF21 +:10A19000C893FC3E3A33CF53F93F722300BD008091 +:10A1A000000000001F8B080000000000000BE57D90 +:10A1B00009789445D270BFF3CE9564924C0E20215D +:10A1C000102609840492300987288703048C0A38F2 +:10A1D0005C028AF08633E42011748DBBEC6620802B +:10A1E000E8A28615151574404070118302A206BEC0 +:10A1F000E1505151E3B1AEE82E7FA2ACDC1283AE48 +:10A20000B8EBAE7F55757766DE37C902FBFDDFF32D +:10A21000ECF7FCF8EC76FAEDABBAAABAAABABABA7D +:10A22000C7EBC935CFCA626CB847F1F8211DE158B8 +:10A230009268EFC7D858CDDA4F5518733A5296390D +:10A24000E3198B1E38AC3F7341B99D59582A6337C7 +:10A25000A468E1AE0E8C4DB9E6DBE4289531E62822 +:10A26000ECE98D849405181BC0D838FC13EA8FB331 +:10A270003B026A0EFC9D6F39D790C1E8DFCFD03E1C +:10A280005BF1385DFD31D725E6EBDE8C61173F5F72 +:10A290004FFD76C0EF53067D9B6CC68F09BCDF0B6C +:10A2A00016C74A253AD8FF4DA27FE661DDE33B326F +:10A2B000A688FC4D72BC0CFD78F84F817A9D98F809 +:10A2C000BBEEAD1F15ACB7A25661690005F351BADC +:10A2D0009ED528084CB6A2A5E3FCACA67A177EEF63 +:10A2E000A6B87B39119E816EBB37BB35DC12BEAE82 +:10A2F00026F890D71A2EFC67867C1293FF14A7B31A +:10A30000238ECBCBA19D87C506E182F107107E5637 +:10A310007078D62B1594624306ED1688760BE47C94 +:10A32000F7EAE73B209CF9C2008E04E65EA962BB17 +:10A33000F8DC5EFF0AEEF2F0A81CD687B18976EF52 +:10A34000833698C3A4985944E7C9CCB73B06E6FFC7 +:10A3500062845680F0A826DFBE0698D41CE6B1229F +:10A360005E808E37723A72BA48B88CF86881D388AA +:10A370001703DC463C04E9539F886922ABA07CCBE1 +:10A38000BC0CF3A9461E047E6DCAB5F937E22066FF +:10A39000F81FF0F3D1C274FF034A10AEA30ACB300A +:10A3A000433D9F12EEDE9CC2D80F61307FF81E2F16 +:10A3B000F03068E62FC6B2A8D6F056DA79BD7BC277 +:10A3C000A336627A7D7AF8325334B64FF663FDF8DD +:10A3D00070487382F0FF60629A1DE0BD47AD25FAB8 +:10A3E00075614D4BCC29413E7BD80593EE8F7C297E +:10A3F000E7E353904E569332C3EB8039E1BFEB83D2 +:10A40000E9C32E4068078E2F3BC0354370D38C06BE +:10A41000A55141785D290E5C2F33EC6AC096D39A22 +:10A420005F704676A0D3CCCBF00FAB799C61BBE1DB +:10A43000765E6F26F68FF5168FF484D69B89E3E05F +:10A44000B82BE1BB3DF85D01BC27C5B6A60FCC8F8C +:10A45000E01F5339C27B220EF06515F4BA3792E83B +:10A4600035E6DE61F45D199FA134C0FC4714B828BD +:10A470008DEDF7A1996513DDA6D46605E9A876D41C +:10A480009EC275CACC0DFDC7C1BCDFEBFF5CAE063A +:10A49000E5C74DAC08EB19F1F75C107F57B48EDAC5 +:10A4A00083FFF508EF36E4FBF34AFD002CCCEFEC1C +:10A4B000243A32A6A520FD629C29C36210DF3FC169 +:10A4C000B880EF8958047CB0A7A3B613E19DCCBC3B +:10A4D00023CD30DFD802CDA239683813C2B3D0C93A +:10A4E000E119A93A886F9BB72B7E1BD4CBF7643E4A +:10A4F0003E18F2E5472CCC0FE5CD8CF375F33AD539 +:10A50000EF037E9AF7F6CB036005B2AF041FF75C4A +:10A510006B622E490FF85FA63F9CB93282F9DE5B71 +:10A520006375F9ECDACEBAFA7DF6A6EACA7303BD12 +:10A5300074E57D8FE4E9F2FDEBAFD3D5BFE6B3E17F +:10A54000BAFCB50D37E9EA0F3A355E971FD2749B16 +:10A55000AE7E7518ACAF3E886E4F7D06E065B6A046 +:10A56000D3F59766EADA9D8D1A7504D7DDEC55F3BD +:10A5700046E3BA1BC64A74FDB01ACB97C89715F0CC +:10A580001FD2732EF34607005F2359D39B4980BF28 +:10A59000057EC58D789BB796D793EDE6EFBD7378B2 +:10A5A0000CA67EFDF712660EE6A19FCA3F6D78E706 +:10A5B000704879BEB3D084FC77DE1519FF7504228C +:10A5C000825DF3B3DA267DDD01A4DF27AADB069FD7 +:10A5D00016BEADD23A58F882E267D06F3AEB118DD1 +:10A5E000F9F2232AF303FD4FB28AC70643FA4395D3 +:10A5F000FF9DC33D82F8B125E8E91CE6D2D339229C +:10A60000434FE748B79ECED103F5748EF1E8E91CBD +:10A6100057A0A77307AF9ECE9DA6E8E99CA8E9E9DD +:10A620009C54A4A773D70A3D9DBB55EAE999E22B38 +:10A63000D6D3CF407F299FD3562ED4D56BE1036F5D +:10A64000D1684C7BD4FC52D76F895A6A65A6203FEB +:10A65000F8E03FE4879E8CB90380E705408780AB34 +:10A66000351F14D5AD5E91F46FF041760AD0BF77F7 +:10A6700008FDD569D15A1BF25CA692AEA04FFBA68D +:10A68000F4273B6800A6537A821D04728379DBB6F7 +:10A6900083A4FC0AB53BCC0382FAAA3DB9D64ACFC3 +:10A6A0008E95FAA91D3DEBEA1A94838090638CDBAA +:10A6B000018CAD32211C53055F1F0CE77C79118B97 +:10A6C000AE857A506720C0750CE186718E85F73EA5 +:10A6D0008CEBF436566BC1FEA7B17A4AA7B3264A73 +:10A6E00035E624BB622673533A9B79297DCFAE4D64 +:10A6F0004901B9596A6F188076C95F0B3F3CAE209B +:10A700003047E310D876F12AE5F5C7F827D47B3037 +:10A71000C5AB215EF3EDAEBB1E854F07514FA0FCCC +:10A720001D1D47F032B3377B7C765BFD2C25F9FE8F +:10A73000BAA26928777D8976F766985BEF24664F21 +:10A74000443D97E04F1D0FF4294FD1EB975E8227D0 +:10A750005EE85CBB10ED28C6FCB1A81FAE76DC5FDE +:10A76000A5787E8170CBFA979BAFD55A7B27C2D94B +:10A7700054E6706F04FEFC44D0E3D95B6D01352ACA +:10A78000C8479F454C7FB303D0EDEE086D19F1DB50 +:10A79000E41B57605E3918E75A08F05D28047C73A3 +:10A7A000FCAFC4F252BBD6AD234CF17C57AD67343D +:10A7B000E2DFCBF10F7F647BDB849FC33342E1E3B5 +:10A7C000BF1EA1ADC67E0E9AEA93DD880F73FD0011 +:10A7D000B24B1D1DA89FF3568E97F6F0303CA2EBAE +:10A7E000349CD76C9BCD8DFB93E10AA7EB89B819FC +:10A7F000D3CBE1CF39266FC780AA83FB1982DB59FF +:10A80000D82D11F8E6BC45C06DEF20F0EECAC27538 +:10A81000D51EDCD5D83FDA89BF56FC6827D23FC8A1 +:10A82000BFE28BF13F00799BE9E22713D07EC93666 +:10A83000B93742D1BA70E81AF8FD0381EFF516C8AE +:10A84000C7D2F795F83D219CB74F78CCE4AF86F698 +:10A85000DEE1AF129D9E5DE0A0F91432971517D985 +:10A860002C615FFF65D8DFF735003DF6A5687B7189 +:10A870001E33E24CC99F101C5A6FB477D8E02BE30B +:10A880007FB94EC73BF914E608BC4D601E5A77935A +:10A890009866C1713FFAC6EA41F9F991902760FFC5 +:10A8A000D3F7A9CC4FE9ED2C40F5EF600D94FF30C4 +:10A8B00022A76B25C037EEF19E3D50BE86E0FD7DA0 +:10A8C000BE5EB519F19C5F4E7642BCAFE97045FCA7 +:10A8D0003B4EF00BACD74FB11F58AFFD725343D670 +:10A8E0004D3EE7176676F6F857EBA6BE99EB0B10D0 +:10A8F0008C8E4498FF0D828437784A484FA09D156E +:10A900000FF8AF77A96467150C6B3423FC5BBEE5C9 +:10A9100072ECAD252CD207E56F0D5319D26BECDA32 +:10A9200051A7B1DD511688EF07F5475ED20E47C338 +:10A93000FCC7827C0789CC0ABA809E08D14B372598 +:10A94000ACCE473BE2A6EEFAEF37B31A15F1373A31 +:10A950004BAF57C6A25E91F560BC038887D8D6FA84 +:10A96000E547A95F7AB15E57A35F169A3C2C95EC38 +:10A97000549715F97EA69979DA5A6F937B2AC29E6D +:10A98000E576CB2D62ECE6D117AD1760BE0353B56B +:10A9900008EC67E198BF4C47790CFBACF7FAA21EB4 +:10A9A0007D5F650F40F99755807150AE27AAECCCBA +:10A9B0000306CED7554ECA9FAA4AA0F44C958BD217 +:10A9C00073551954FE4D959BF25353BDF1D8EFCCFE +:10A9D00095DF9AD18EBA2F4CD28FC3B148F0EF7D5C +:10A9E000617C9FB52872D1678530EE225280A0AF7E +:10A9F0006B6B46A1D955BCB7F64D4CE1BBEAC0F232 +:10AA0000D58A1BF5D39CC3DA0A649F79471BC6A27B +:10AA1000D8E9FF87131D116F659714A6C1523AD06C +:10AA2000C39386E39FAC1A48709DAEF2105C9EBA49 +:10AA3000C637E3A0FDD9AA02CA2F4CF566A6764018 +:10AA400075FBAD15DB8FD9DE684E82F2911EC58392 +:10AA5000EB7BA887F9FD40BFB516AE2FD682BE406E +:10AA6000FE19963D7EFD5D0CE5B9D617C799143BDE +:10AA70006B641CF2D5C04233D69BFC13D85C2941D1 +:10AA8000FEBEDC3A39BF5F21FC9CDF1F43F89078A3 +:10AA90002A13F43ABFA7F72D83A0DFFD6047AA0071 +:10AAA0005FF32513C1D7FC59B81F8D0463FB85BB29 +:10AAB000D33A3107CE131ADB30DFBB13033A9C7D48 +:10AAC000E19E04A44786623655825C381B5BFBD747 +:10AAD000CF51EEFD99CB3DC66ABF7E12E562970469 +:10AAE000F70390FBC602FB34DAD75444A05E5C60E7 +:10AAF000651ACF6BBD317F369CD1FE76C08EA4E146 +:10AB0000B89E703C57CFA05C4BDFF178EAAF5CC1D8 +:10AB1000F96E79E189E6D75C58EE27BEDCB6637D35 +:10AB2000E7A72057BA737938C2F53ADA19B04E5E02 +:10AB30005F1D41F2EB758BFB7825CAEDF50EF766CC +:10AB4000A8F7DC43F77EB917D307CBF2EE45FE48F2 +:10AB50008DA57E66FF6E7E2F6C0F7A9C25C2BC7E13 +:10AB6000FF8A120843FFCB9A034B1361BC3EEB1ADA +:10AB70004D9D21CDDDA45463DABB6BC111D49F156B +:10AB8000A92E6ADF777B8A8AF661AFCEFECFAF2728 +:10AB9000FDAED7FB596BBE1DDE9905F57F2FA5F6DF +:10ABA000CC12A0EF7D5D3FCDE3FBBE1AEA6777DDF7 +:10ABB000848F6F67380FB02C10EE422BF92570BAD6 +:10ABC00016C89FDF95B601FD177B4CBE0DA48F669E +:10ABD00072FBE3BCD7F704F24D19D4F741BE2CD772 +:10ABE00017751D9497FDB9BB1B3884757DFA8602D5 +:10ABF000C4C7825D8F8EEA0CF5CE0F666E05402FBE +:10AC0000DA7D7114B6635DC156C67E765577BC0D8C +:10AC1000DAFD366B787FE413AF5A4BE3B0723ECE69 +:10AC2000E3428FB1861CF20B904A817ABF85CFF840 +:10AC30003DB62EE600F76D71FA94D72D4941FF4AD3 +:10AC40003FCDEE56711DA4F8122B1C41BD08FAEC45 +:10AC500077B87E12ADA25FE78464EF55E833ABD0DE +:10AC60004FB2BFC7ADCC1716CBED6005F5AD95EB78 +:10AC7000E1CD202F905FA51E867137A6F2F664FF06 +:10AC80002681D2CD0538931EB7F949D75FE1F84642 +:10AC9000BF99B443A6C455EF6B40FF4E84B603C7BB +:10ACA000917E326676BBD0CE5916E1793195ECA80B +:10ACB000A6649C03E8C997B1DE0215ECAAB410BBE8 +:10ACC000CA7E657AF2C508CFABD8FE4AEB1BE5E831 +:10ACD000A2EF4D2C17F860D1A336DA77560BFF415F +:10ACE000B5F06755470EB0E3FA67874DA56F82FE52 +:10ACF0001CC27B68E97751641EC9876AC6DAC4DB67 +:10AD00007E58D71AC89100E8010DD6F7D04B4D2ACE +:10AD1000E7FBFA43D1FD507E324FA40BF7F526A690 +:10AD200085E847633F40B76338CF612C8269217A59 +:10AD3000D0C362ACB87E9923F6DF9AFF60413F39F9 +:10AD40008FC1C27F37B8F9B30894838BBECF237904 +:10AD5000D8DEFCF689F9FD17CE0F526F4FEF39841C +:10AD600073C8774E33CE7388795C32DA2D007F3327 +:10AD70007E1FFA9D490FFF4FE1BAFC95CEE36E8529 +:10AD8000F94CB83EBFB5FA717DD6017FE37AAE9B30 +:10AD90009FE54739B007D603FAF17DE3AD64B7D636 +:10ADA00009BF685D0727F98B5EB7F0BC6FAA681F03 +:10ADB000C6482FD44DED4CED3BDB2ADECDC6FEABB5 +:10ADC00023487ED659FC2B53B1FF5FC7B97D402F76 +:10ADD000D5FEECFA137D61FFE037F92CC82F96C041 +:10ADE000ED2AF6F7AD95E1786B620249E5507FCD2B +:10ADF000FCCE54FF33308DD01F37C8649A31CE81DA +:10AE0000E59EC458C8EFF9A74A7A604D2EE41D2488 +:10AE1000C7C9BFB7669C27313C1ED38E26824765C3 +:10AE200015F43D85B7FBDCC2EBDD26E8774CD00797 +:10AE3000D639C9016D6C8419F9F8DAB49959696485 +:10AE4000C778121580E7C9D93D18CAD1DB8A6F4C83 +:10AE500021BE117ECE298206B23F26FCA493F8675C +:10AE60003675CEE630A4E7A4A230F2837E56B43421 +:10AE7000D205ED2769C2FF3951EF17BD36CD43E347 +:10AE800096D566A69D08E1EB9936901BD0FF43E16D +:10AE90005ADF34E4C7BDB954BE178C959F615D7D00 +:10AEA00039BBC70EF253CC96FBC2C02CA4EBFE26D6 +:10AEB0003BC3FD467BFC508D74807EBB215DE2046C +:10AEC000BF22FDA784F37D8B19F805F2D5B599B49F +:10AED0006F79C6C23C0AD26BB78DE85F30DEEE21D7 +:10AEE0007FE294F00D36289F21E459F59470FA5EC4 +:10AEF000BD2FD26F52683F4479DF4E0BB52BB5FAA8 +:10AF0000B76D817E4AF76792BED96315E3BE16C15D +:10AF1000CBA33C29CBFB617927E283D72DAE682AEE +:10AF20007F5B65541E1E488F013CC6856913111F47 +:10AF30009D6D406707F6CBBF1F17FC751CBA45FA1D +:10AF4000F92A22A95F5AFA90D7AABB6E447A6A56A8 +:10AF50005ECE7EA952F971A727710EE48F57241196 +:10AF60005CD26F74DC6B25BE3F5EAA90FDF3A74AEE +:10AF700035600DF5DB8FDF7A7F3AB4FB6ABF85FC65 +:10AF800072D31E2E398ADFA72D2D23FFE2B4E2C52E +:10AF9000742EF0CDE2AF06AC85F9342CFD22590BAE +:10AFA000F1334F2B855621EBF937699E32E4832725 +:10AFB000D3B40A9C5F7956C35CB497BFB1D63F8DBA +:10AFC000F67F7ABCB608BF5F78F5E4166E4737A502 +:10AFD000A39E5860E67C22F56DB9E0C35EDDB57BCB +:10AFE000B13EE06D3AEA9588AC7A2EFF165F99FC87 +:10AFF0003F53B7798F02E39484D72DA054F5E760CF +:10B000003F67954094924678D4705D9D7306A21078 +:10B01000FF9A89DB6D255BF5F3C27F789E55827FB1 +:10B0200040BB925AD51386EB80F9AD087F09B30671 +:10B03000EBA704E905FD10BD98E34FD37F05742805 +:10B04000DE969987FB859298BD0F0DA27AD04EAE01 +:10B0500017B5755ECEA7353C7C7EE7C43A38075FEE +:10B060002CC82FDB6D72DF4EE37FF36A271ABFA374 +:10B070005827DF28825FB78571BE72C3BC10CE1718 +:10B08000395F3D26E5E436DE4F499CCF8472A9A4A2 +:10B09000CA497C25E512C042EBEBEC8E246A27E519 +:10B0A00018F33246F577246EE4F69BD8BF22C050E1 +:10B0B000BFF8F77C1CCCA33C3FF37C921C97EC6759 +:10B0C000A33E36CE7B7F9A89EC2DD0D39DFED5FE54 +:10B0D0002F2361D6FAD97D43E613691572C19D30DD +:10B0E0002E1BCF0BACBA7EBF89B4CEF038F0DC405B +:10B0F000FF5DF6F74E1ADF1F7633D0B9B3DA74C0AE +:10B1000086EBF059467AC308C787A2DDF3CFB7D0E4 +:10B110005515FE71E692FCE4E2F63CD1EF9855D26B +:10B12000EFAE2490C72588ABD4201EF7E46A49A867 +:10B1300037BE11E73D7B62209F85F614A78BCC4B71 +:10B140007A18F972E9B1B94978BEF4CF34EEB73361 +:10B15000E27B09E015CBAB2DB05FC9C27DEB914717 +:10B160004EF408CEE7EB2A8F6776487EEEDA5C3B3A +:10B17000AEC779EB72ED3343E851BDB5EF1117E07F +:10B18000FDDC56B31BC57BB5D9FF10DAE9D55BD51D +:10B190005AE42328B723BECF390EBE8FF5E6AE8B17 +:10B1A000C9433B5CB69FB776A46776081D7A6FD516 +:10B1B000D325BB569FEFB3579FB7776734BFAB6DAF +:10B1C000971BD0E7FB1ED1E75913506F00DA039CA1 +:10B1D0006EAF0C741F7101DDBAF955377EEAE618BF +:10B1E0003F610CDA11EB54770F28EFB6D87B33DAD6 +:10B1F00015A7D6CD7123D98B54DF825F014D8BBE4D +:10B20000187504F5EA5956FBE918A0CBDCBAD556F7 +:10B21000B30BE7ADE7F73D26C1BFCF737FDC7CBF43 +:10B22000BEBCB55C5822FD1819A1FC65E40318F7F3 +:10B23000560F00545AF9F12328178A4603E3A31E38 +:10B24000AF5D6D45FBEFF2E3F8B87DE9F0B8101F94 +:10B25000850379D9759523D857B0EED8AA0F472121 +:10B26000DC85BF55C8FE287CB9E761E4AFC69D53B5 +:10B270006FA2F4D6029ABFF4FBCDAB530291907744 +:10B280000E74ED6D807673FCDC7F3173992D280F81 +:10B29000199E7B19E05813520EF0CFDB7BE0473C40 +:10B2A000172E5AA76F371FE434EA9FE24D3FDB4267 +:10B2B000BFCBFDE875751B549CF71C01BFD49FCC18 +:10B2C0003794CE1DAEE34DD809FC3FD03BBFEEA86E +:10B2D0008DEEDE3FA847AF5BC3DB83D82DC47997E3 +:10B2E00039AC2E9C77999D0522009E2391560FC65E +:10B2F000955C5C1B497EB7B936B057F3286518B723 +:10B30000008298CEBFBEFE4025BBA72C8ED3BDECDD +:10B310001985F66965E82CC5FCB33C3F9F05683E7E +:10B32000C82F9ED079FAF57956C3F777A5E6C00104 +:10B33000C44B316BE0FB33A0A727E4FCBA14E6F959 +:10B34000592CDA6F86F6CCADD1B99C83DB63E57BF3 +:10B350007FB68596CB7DA6DC074B7FF033E9DE70A8 +:10B360001CC722ECE635F77BD211DEE5164F3AE238 +:10B37000C1B73A8CF6FBB76DE0FA6B4D0CD8B1F162 +:10B38000643F933D7E9BC2ED733695CBC341A69738 +:10B3900002A86F9A1E8D716F74517DD2636B1ECCA3 +:10B3A000E4F6FF3F55B2879A56F3388835B91C7FCB +:10B3B0006B1ECCE6F6BFD47B1D18F5D7DADEF6A4FB +:10B3C000A31F823DC2E1FA1CA714625FE776D21E7A +:10B3D000E81E323F6997B3A22B3B9FD82CE2329AEA +:10B3E0005687F9F17CE284E27DD31462DF3ED59D7D +:10B3F000EB8901C33D5B443D3AC7986D1AF7C0F530 +:10B4000000D7ECC74C2EF4A7B5E0DBE34947FD7944 +:10B410006275581EF2D980E1DCBF743C97CBFD8881 +:10B420007E8CE29B36897E377537E9D28470E03FA7 +:10B43000E8E7C448EEDF8EECE725BFDE661797FB32 +:10B44000C679D48A7E665BBDEF0C69031E891796A8 +:10B45000CFED8E13772A1B395C406FC80FF85D184B +:10B46000F9034F08BD24F10B7C43710C526EC5B437 +:10B47000F08B7F5B18F0CB6A0BE703B96F0BE1171A +:10B4800041FFAE44DFDB047DD98361825F4CEC6F0A +:10B4900088C7914ECE0F57B9FF027A1F417A1BF72A +:10B4A0006192DECCECEFFFAFCE51CA5E79618F0FB7 +:10B4B000EC8CE2171F8D6250EFB4B9A6A31BDA978C +:10B4C0006E5E1EE581F494D917E584F14FFBD50239 +:10B4D0007F1BF8B6F690FE688F430939F73CF3FC02 +:10B4E0006FC7E23CFFBAD9E2449150BED546FBB1EA +:10B4F00005BBE693BD0EF9469EBFEF5B3C072DDF13 +:10B50000ABF7B7173FF7684717E1DB97644AC034DA +:10B5100090C4205DB0C9D2722E0CC380FDDDB40290 +:10B52000E133B647382E01BDCB6BD5426B74EBF2DD +:10B5300072215FCA77FDF65BF41B96EFBAF124CA5D +:10B54000FB72839FBF489C7718FDFC7FEDAE3F47A1 +:10B5500006FC50DC800FE0EA41ECC2FDC4D5DB1EE6 +:10B56000CF6944FB61D3BB514A56D0DF2FCF419AFC +:10B570006B673D83FED3F6D6E537C2DF1BA41B976E +:10B580005FAEBD0A0F9AABE369A925103508F77BBA +:10B590001B2C64FF96BEF0EC962791CF8ED948BF46 +:10B5A00097BCF0C6A7D7A1FDBCD3123F9A4FC3A149 +:10B5B00084C4D994BBB83F4ED2A7F8E537ACAE6C83 +:10B5C000FE7D716C904E253B0F5831DEC788CF1140 +:10B5D000B507AC0D8E36E855DB388AFC50DB7EB003 +:10B5E000E2FA38BD5F619D525AB72FDAF04614DA9D +:10B5F000678827D44F926E2D7434D487FEC7BED689 +:10B600008FEA39719F72393A7E2AECACB2572259CF +:10B610000CC051F4B9CD3F1AE9BB635114CEE7A475 +:10B62000B982F3FDFAE51DD1DE2BB2F83A3A29E5ED +:10B63000DF8B9EBE9BF8719E52D1D19945FC9E68CE +:10B64000225BC29788F39CB36E12CD732ED3881FF2 +:10B650008BD6AB5E3FA4DF9B59C1CE36D6CD52B15F +:10B660006E4E6E04E2C23C4F8A782BDF47AAD84761 +:10B67000DF49FAFC6E3167C61652FE7B61CF4DEC96 +:10B68000D1729E6D0FDD87966FBAAF1EE974A6ABBF +:10B69000A713C20978F009BC293F43BFEA87233BBF +:10B6A000713A3117C623503BD0AB23F03BD6AFB72E +:10B6B00078D0CF1ED24EEC13F9F87789F101EE70F5 +:10B6C000DC079FECD8763CD7CE16B9C0EA43E3B985 +:10B6D000DA95039BEE27FEFAEE132E6716F8C715D0 +:10B6E0005079BD25D009CBFD07262A24276C2CD004 +:10B6F000D63ADF6411EB5C5F0E709A9550FCEEE772 +:10B70000F6A9E497B960970542EC8420FF5883DFDF +:10B7100069FEBF13F86EA0F33979AE374FC807E35F +:10B72000FC8DF262718FB6E34ED8BAB6CF938272B7 +:10B73000C247E396827E477BA4F4988DEC88D217AB +:10B740002C5EC4D3D9ED873EBD0DF7B7B5725DEB66 +:10B75000E5B0715D17BDD4BFCD757D76556EDBEB61 +:10B760001ABEB7B9AE572924EFFEBB7218341FF9C1 +:10B77000252EB77EE7B523879F33E0F57B96153DF1 +:10B78000080B9D85DD884E06FC4ABC1AE5EA1014BC +:10B79000921D5ACB5586211A21F8947894FCCA98A8 +:10B7A00046E3B4F0B5E45BC9D72D7C6B9CB71E9F14 +:10B7B000C6F2F9487B80C7FBAA85EC85D23A1E6F9A +:10B7C00008ED283EAE1CFDF354BBE6CDA4F8D0BC7A +:10B7D000DF90AF35D4F718F25E437DCD90AFD0D572 +:10B7E0002FDD7BC8CAF70F015D3D5BE5CDB41F6956 +:10B7F0006D67F8F9B9D3AE6FAD3EE48F2E4D569418 +:10B800009396A5CC1709ED9BF6A964F75C703545B6 +:10B81000A1DDB23C8CDB75179C221FC3F34D1DAC20 +:10B820002B504ECAEF4D61DC0F73C1DB141513B200 +:10B830009F6FAC53A3D0FFDBE067056DC7AB54131C +:10B840005E1B587BE5DCBEBB10CEFD0D17C2B9BF39 +:10B8500061A4EA48AE443F6C0D8F0B9CBD6472142A +:10B86000C555D4A5DD3205BECF795BE561E03E8FDD +:10B8700019E319667152B253CC47F181B3EA785C8F +:10B88000C3EC557A3ACF756CA2F8B7EFD9624AE7A4 +:10B89000AED1C72314B355C46745EB0CDFEB6EA6DE +:10B8A00075526C58279AF00F1BD789235DC43DE66B +:10B8B000B25C5DDCA390E723D5AC5BA6003D2E1CFB +:10B8C00051990DF2CD752A5BD18FC7B9E2F9136E8C +:10B8D0004870FD2D80F58A7693C4D7395C473DDBEF +:10B8E000B75FCEEDFEF3805F21DFECF92207CF8555 +:10B8F000CFED3996FE3AE65FF963F217AC75FD11AC +:10B90000FB7F9C8E72FAC27E1B437EBFB0FFAD648C +:10B91000F4475E78CD46FBEC0B4B6DDCCFBD3FD2E0 +:10B920008F2AE642576E1757EFFB21A781F4F232B8 +:10B93000A2DF35E9566E5FD5FDFD38FAD39BEB608B +:10B940005628F7F747D07A2A7F2D8CFCCC17F6FDC6 +:10B950003020D43FF7DF9D8F3C4FBF10C9A6BC8479 +:10B960007C1CC3F705E5AF5FFB2C9E2F97ED3A607B +:10B970009D05E523FEEB1F3928572FBCC4EDA96FA9 +:10B980002C0D4FA38F73F896A8472C89E8E783CE38 +:10B990003A33F6C596B1137C596DE185E3E102E0D7 +:10B9A00001E7057829427DD01E3EA6223E3AFC27BB +:10B9B000E2E3DBE95CBE5DC3F03C3A8817C5C3BF78 +:10B9C00047FAED0ACD9F7FDFFF430ECA9FCBCDF72D +:10B9D0009EFFCFE6FBE87FEC7C39BF774D77119C6B +:10B9E00046BE6FCDD7AFFC82F23B22DD04EF15AE31 +:10B9F000F7DDFFB1EBFD7F86DE1FFFC7CEF772F4E8 +:10BA00007E5BD03BD289E79917F6FD23995DC5BCD3 +:10BA10009BFF97CE5BDAF1C355F7915CA8FF2EAB85 +:10BA2000FDC49D42D6489B7648B7609C1FED9F465B +:10BA300030AEA747D84BC8FE1CD1E541B297AB59F1 +:10BA40001E9D5FF8BAA874AE4341208087B712727A +:10BA5000E95E153307BA2C82FCF0A4328AFF32EE7D +:10BA60002B47848F2940FBF4D012800BFA391469DC +:10BA700072E219757E177E4F09D2464CDF4CBE9993 +:10BA8000E2F8F31DFAFDD5CD867DD28D2E7D7901AC +:10BA90007B291ECFED0AB22C745F6214D60FD957E2 +:10BAA000FE23DD4978B991D52C733AAE1E4FB70805 +:10BAB0003CB5C6C3BFC65B2B3C897DB459D437E2C5 +:10BAC000CDEC78A01EDB9919EC8BF97C693F2DF742 +:10BAD000C597C32713FB6DB3185AE2D7DC859FCFF8 +:10BAE00086F44B789178BF5A7C4B3A19F12EF12BA2 +:10BAF000F166A4432AC6F8F50FE2BF8B39D78CEB69 +:10BB00006E88B0EBF3CD313CDFA55EF5D27AF473ED +:10BB10003EFFCE6D46BB7E982386E2428DF71166CE +:10BB20000E8C19A0C07C93CCCC67837D289EBD91E0 +:10BB3000DFF57EB37F690A8EC3FDBB5DCDDC7F0D73 +:10BB4000ABDB179E47F53D56C8173E328F79A07E76 +:10BB50006112732BBC3E8B8EA5F038A6C6F27B9B80 +:10BB6000D8AE309AF75BD889F997727A125DD0ED2A +:10BB700083FE0DE8D7638AE5EDA3F2A8BDCFC4DB51 +:10BB80007BCC90764BE3710A4DCBB95FBEF0BEAE75 +:10BB9000E9283F460FD7FB99DFEAC9FDD232ED9B7A +:10BBA000E1227CA9267702DD8F589649FB2335DCFC +:10BBB0005BB61BFDF43B789C4EE18A3BC6F447F82C +:10BBC00076C4B911BC3363770EE0F5A7DEFD07F844 +:10BBD000AE6D0DA3EF9333B4A53D311E40714DDF23 +:10BBE0000D1F664E3A644D8021B4DA71E7D14F38AB +:10BBF000D6B7F37D3C9F1C3B51A5FA63198FF764C0 +:10BC0000CB601C281FE3FBD69C00FD8D814D079661 +:10BC100037863993EF04F80B857FF8215C2F086F86 +:10BC200038D35E72205C5DD353E1FB18D676BCF14D +:10BC300051597FB8B20ECF99BA8DE0FE7B591FFBE8 +:10BC4000C17E3FEAC9FD514F8854E601AF547FF6EB +:10BC50004A5B631AEE7F565A023D2175F41ABEBE46 +:10BC600027E06F742A1BB516F17EAFCA3612BC4DA1 +:10BC70008574AE1099E1423A68C0D274BE5293E224 +:10BC800042BF58E3B0DA009E27343E91E2AE76110F +:10BC900095291E48EEB71A8705BAA31FBF29979F9B +:10BCA0004B1C773644E27E7196C3CEEF498AB8A228 +:10BCB00039E25E4CB7EA8607AFC17DE8A32A9DD77B +:10BCC000CC7994DFF7FA8BC3EE5770DFB646DCD73A +:10BCD0005CA58F23624E37F98166D50CB3E27E7383 +:10BCE000B6C363C579FE31437B1DE725EF17F642E6 +:10BCF00022409785358514AFA246C1BAC3756276D6 +:10BD000045E13ED81887542EE28E64FEA170ED30D6 +:10BD1000F2C3CC68D70EE4972F2BD3C83FAA0ABE34 +:10BD20001B8D7195789E616E484478EEEEE922BED7 +:10BD30001C1DEB4C77103F8731C443A3C5998EFC83 +:10BD4000DDB83CCC84E772A39772BE867566374334 +:10BD5000FBFBCD2C1CCF197E27DA4F5B62F66E8081 +:10BD60007C173B3347C6225FE5125FDFD24B7B0275 +:10BD7000E777EAD76C20F2C3AC55ABE93C46F20555 +:10BD800033D7E7C7C138A736A7E4A1DC6C91D3BD90 +:10BD9000867F81ED5AF861A2427C00E98134E28716 +:10BDA000F10D38CFD1C303DD1766E17EB49479502D +:10BDB000BF273037DA09CDAC89CE2B9B1D5617FA39 +:10BDC000BFA43C917203E8EAC17BB7920FB680BE74 +:10BDD000375B18DB5A65A7F4F92A2733F7606C7BC9 +:10BDE0005502E57754B928ADADCAA0EF2F55B92952 +:10BDF000BFAB6A20E5F7547928BFB7AA80D2D7AA8B +:10BE0000BCF45DCA25C00BC9212957A43C9AE5B0F2 +:10BE1000D27D5F29978C7C331DD03B348FDA93DC45 +:10BE200093F20EE761CA0BCA2349DF54C5EB4B48B6 +:10BE30004139D63015E93F523DF7C22BB82F2F724A +:10BE4000B8699FCEB8DC6B067E45BC245BD95EF436 +:10BE5000CB56DFE969BC2F2588FFDB8B14660EE12A +:10BE6000AB3B2AC29839446FCCA88CD1E5A7557E4C +:10BE7000FC4627E8FF9E0E5A7C06C071FC375FAF78 +:10BE8000FF237C7FE637677A20BD018ECD8FE3B834 +:10BE90008BC35BE088C5FC320B9D737513FE936EFC +:10BEA000C27F82FF903EF27EF333BFF91BADF3C633 +:10BEB0004A9B0BEDE2CF915E80DF3F097ACDACB4B7 +:10BEC000111E0B977FF5C22BB8DE175B49DECD5CE8 +:10BED00026D6A3E15EF397898CFC126055B34AC065 +:10BEE000DF97BFB60622A0FF2F15BE8E15300EA617 +:10BEF00061FCE1CAB73E4339A0541EA1F3770DEFB0 +:10BF0000E1217C3ECB39DD3DE9CA37A91E6BE81241 +:10BF1000837E1379CF38A29FC7EA82F9236F23FD6E +:10BF200066661C648978CE52A338D185385B7C9FC5 +:10BF3000BD92BFDB80713C13C1FE1B92A1123D2B51 +:10BF40007B9A29FD14F52DF9936B484F49BE9DBD91 +:10BF50000ADAE1FAA8C9B5CE0D91C733C5F7591968 +:10BF6000264AE5F731D82F9EFFADCC9D82764567F6 +:10BF70002CCFC2346F0AE2B7B363945909E1831B33 +:10BF800032CC020E46ED3EC54507E90319A9D63964 +:10BF90005974BF8FF4981C676646DE0A8C2F9DB9D2 +:10BFA0006A184A61566D7127C4433D6F4B3FDC7E72 +:10BFB00063761E475DDA8E1E917EB553F8E7B53481 +:10BFC0006FF2FB16EFF8FD8ED7A0E7E22F6C44DF8F +:10BFD000E23E226E2BCB3F60023920F5FEECFCDF07 +:10BFE000FF398ACE2976F1F84E48B99F757111F75D +:10BFF000CBBA617DB5715E7478C717516DFAB177B0 +:10C00000A957E4C72E577E8A423B42CE67E4BEEF73 +:10C010003B121CCA253A272ADFB7BC635B715E4618 +:10C020003F768BBF5BF8F5CA1717B4E9EF36FAEF26 +:10C03000966518CE0FCC8CEE8D49FF1D53B3A2F13F +:10C040001CE07B719FA4BD7D8EF47F97AF854EE28F +:10C0500060BD9A5DD178BE75A11DFBFA6806D7FF59 +:10C06000E785BFFCC27695F63D17B647D2BA5AB0FF +:10C07000FD9137F1DC71C12685C02863F5843FC08E +:10C080002BB387EA358C638B6B0D77B3BF4734EAEC +:10C090009592DF475620BFCDAF553C9B019E66BBB6 +:10C0A0002BBA43083C5B91DF807F4A6CB50308DF05 +:10C0B00002FEA7514EF60FD69B5FF708F997A1DE57 +:10C0C000376417BD1881B10288F7F711CEB3EBFAC8 +:10C0D000BAF1BC707EEDCE0564576C8F70A25FE143 +:10C0E0008C885B96FDEC12FCBD2B83DB3167C5F9B8 +:10C0F000D1D91DFC5E3FC289EBEC8CC2FDD0B2DD14 +:10C100006B02CED732F8BEE48E0CBECE65FDF9B51B +:10C110008D51DDA1FEC9BD1F537A58D49FEFA8CF22 +:10C12000417D7C7257049D7F9DDCF5D4A8D761BC0E +:10C13000F3B5C3E2715DC8FE3FCAB050FDF3EBD466 +:10C1400002C417F3F3B89932C46FDF5038E336F8FE +:10C150005242D71F8F1F3ABBEBE5285356909E657E +:10C16000F60A7BA209D7D19D5EE4EF68641E80D7F2 +:10C17000BA6B9C0F7558795D2E43BEA6F59748F5AE +:10C18000579A42EAD92C6E8A33B5EC2DF48837548D +:10C19000F83D2711C73F52CDA273C5E97D5C936F6F +:10C1A0004739F9AE85E8B130D33519E5D3C57A956D +:10C1B000219C0B535800ED9345F7466E403D26E118 +:10C1C0009EDE97CB83D2950AF3C0FC4AFD2AD3208A +:10C1D000ED0CF4F7213F2534F4C738C9C6146E5767 +:10C1E000C8F8D1278B4C1E2BE8C19F3262E5FB0FAC +:10C1F0004FCCC1F3B3F119B49F3B6E653E15FD4AB8 +:10C200002FF1F8D2D2541ED7FCA488872F8D0DA40D +:10C21000C7417FE7047D4BC707D231EEA2F4A544A6 +:10C220008ABB3867E5E79EF81DCF594BF3A0BD8365 +:10C23000DECDD064FB98107E2A9DE976613D35D62F +:10C24000EDCA7520BCCE6FC8CEDD1DC9D0CE35BDC0 +:10C2500012C9E3A69E0BDB680BA19B3393F39F7C73 +:10C260008F83DDC6E38C1EB3F0B8D4C73627FAFD42 +:10C2700021F87ACCA24D453CE03CD0BE9F6FAD4941 +:10C2800047FB57C23B3FAA86E03C27F87D7E780DEE +:10C290008FE716F77BB13EE61B451C7AD3361BC5EC +:10C2A000019D49ACDF83E39FD996892FF200FCFE04 +:10C2B000B97BA91CEC4BA067F1F3B600CEE7F436CE +:10C2C000EE8F3E6DE1F6DAE971092EA46FC1F8B583 +:10C2D000D3C95FB3C9A6A09FEFB4C2AC0958BEB919 +:10C2E00003C59F17575552FC7631880DBC3F046932 +:10C2F00001DE033ABD3993E2CD4EE33B0C0A7D5F8C +:10C3000089DF355633FD97888FAD7C7F75E6F9BFA1 +:10C310006786C67BCBB478933EBE4EF2892CCFCDD8 +:10C32000E4F22D57E0B97F267F2FA42CA2F6B1545A +:10C330009A27C73BD089BF5BC31A229FEA87F114B3 +:10C340003D1494234FB240FA53E877D8CAF75F6799 +:10C35000B65B286EBDF895480FC5B1DD778D89E2D3 +:10C3600029546EA7179B007D902ABFD94AF165F129 +:10C37000CF87E5D9C83E67B4CF6DDAAC8A71C026E5 +:10C38000C6796FE171C7A3D196A4F26C2A3F2DF252 +:10C39000A7F76493DD07FD7BF07E55F12F7FC5F194 +:10C3A00038A1E828B7BBEC246F4B5BCE790647A3D6 +:10C3B0001E2CBB6F5034DE3F641FA80CED16239E6D +:10C3C0002E9ADD9D50CE2ECB147277CF7A3A9F2ACB +:10C3D00011F7084A9E57F83934AC43BC9F59B262F2 +:10C3E000D0E3C49FEF5B580F98CFB9DA47A242E978 +:10C3F000B12093CBD396FA5637D52F81FAD84FC9AF +:10C400008A77A3089E2D168A5731D2F18ADB3FAF77 +:10C410005E51FB16FEA8E57E9656F367F5BFF8025F +:10C42000FAFF6E7B98DB475F6BE91EDC594BED5CD6 +:10C430009CFFD917C2486E9D8DE1F2E124C8535F7D +:10C440004F84E3E68729BEEBA309747F6F9E5FDF0D +:10C45000AF1C77512697E36571EE688C172CFB8033 +:10C46000CB41A0CB2DD4FE030BB537CE63BC68D730 +:10C47000B23E5F88207E38DB99D3E5EC8E9EA49F88 +:10C480001A63389F03BCC978DFEFEC0B3D73E91EDC +:10C490001D1A3DC00FC562FF7B36A636D91952DE84 +:10C4A0006811FBB800D444BEC13620DF8B2BB9BD68 +:10C4B00055625F45F12518AF3B208FD2802DB675B0 +:10C4C000DC2DF02BED2FDFC9147E4C1CAFA388139D +:10C4D000273BA8D68A725B13F662E97663DC2E2FBF +:10C4E000DF26DB03B4F1324E18F9D0A7509C4AC9BD +:10C4F000B23BE753FC7DC5EADB719D49F84BCCAC00 +:10C5000000F7698D8A4A703486B119E3D1AE0C1DEB +:10C5100027C49EDB151C87E1FB5FA5F807ACD9BDDE +:10C52000992EFA8EF91AE8AF7499B28AC64991FB2E +:10C530005D3E2F8927408715E3041B8789F276E645 +:10C540002DE134CEBBC5EECAE4FEA5C614D7C38325 +:10C5500091CEEFA9749FF7E24F7DA363DBB0D38246 +:10C560007ADE1A8C9705F88F6532EA677D26B7D395 +:10C570004B301E17E04C5FA78F17CFD8A4CFF7DA48 +:10C58000AECF67EDD2E773EAF479F7617DFE8018EC +:10C5900017F7E1787F18F7E198E23EDC65E3FB707E +:10C5A000CCE33E1C53DC87E377DC87631EF7E1981E +:10C5B000C77D38E625BE713F8E79DC8F6379782F91 +:10C5C0008EA752116F8974407E67AF86E9EE235DB6 +:10C5D000D8C7EF97001FF07533D54AEBE649AC4159 +:10C5E000FB11EE77EA3CC1EEC2F8E15571DA7799BA +:10C5F000FDF11E4AFD8A44A49BB981E258CB5FE35A +:10C6000071ACA579610EF47F342C3FB902C343B5F8 +:10C6100038ED47AC7FC1D2B405F15B567988EEDFC7 +:10C62000372C717D703DA71FF96158512CD9518568 +:10C63000A8E762DBA7A3319E9CADD2C78F1BE3C9DD +:10C640008D71E4463E90F6DF3396A64494EB5F6D21 +:10C65000B3AF42F8BF0A13F761A6D80DF1000E92EE +:10C66000270B1F5436A2BEEEDC8BDB51CD47C05EDC +:10C670006F43CFCA74D6A5BE6497B7E45729268AFC +:10C680004FD73CA4871609989295A6C6FB50CECDED +:10C690003791DEBC08F61AD9839FA8643FE03B5966 +:10C6A000A1F3C177B242F90BDFC9D2DF97E8ACAB97 +:10C6B0008FEF64E9EF4BF4D2C7E74F5C7200F7FDF0 +:10C6C0001356F5D5D59BED1D64C0A3805BD8B3B3DD +:10C6D000417F78D0BE5CBC3619E9BB687E73E37DD0 +:10C6E00040DF45BBC3DC585E84FF0772B108FAC463 +:10C6F0007B9745BBC4FDE54ABD1E9E25F45091992C +:10C70000F99CB1413E2C72324F0CB49FDFAB3E0717 +:10C71000DFC39AFFF6C7039CA9B8CF18D609E55125 +:10C72000B2C54371B5A53B7BC42C817E7BF7D06E2F +:10C73000EC05EBFA44CDA187A6A13EDCC9F77F5FEB +:10C74000AD7A398AE2CB04BF255B9CE148F70D3511 +:10C750003CBE0EFD676A6C902F36D4C48577770493 +:10C76000E71BE4839F884E401FEEE7293A48E72203 +:10C77000CDB562BEC3141FDAD9727EF21D2DB68C00 +:10C78000F77397C89F10FB0D39CF739907725C78C8 +:10C79000AFA36A6FB28AF2DCB47D0BEE43FE69D3BD +:10C7A00066F7EA8FF1A03DFE88EFAA15FF81CFE77B +:10C7B0002F6B46445D8BF6E70B16F768C8DF57F31F +:10C7C000AC15F715C566BF95E233B76DB062BCF224 +:10C7D0000D5B37D0F7B95B0B291E731EABA0FDE8CC +:10C7E00029F9EE81C047D170659D13E07E47C88F5F +:10C7F000A2707EBE07F6D11BF8EEC8C5AD4A2EC6A4 +:10C80000F94CF4EEB416C2F75F8B7AC675D27C741D +:10C81000C2C80E840F7E0FE40F0C76F769ADD7C542 +:10C82000844B29B42E265EEA4DFBB449814CBE1FD1 +:10C83000CE32EC878FAADC9F57C7D7419135103F86 +:10C8400001D7C97E0BD9B96566FE6E5319FC7D1DF3 +:10C85000A4DEC1AA8E5FCBF32374FC3C85C5EAEE4F +:10C86000D3DC8A412521F989A3D374F5274FEC6DD8 +:10C87000E0FFBC6039C991EB74F7FECA16FB5CF4AB +:10C88000BE211BAEFFCE787C21BD086A0FFD3E3E67 +:10C89000580FF97B93C2F73DBB6236A21FB0C8C4E4 +:10C8A000F74F5334FE7DC15EFE9D4D61BA75D82DA4 +:10C8B000CDFD47AE172D746E20FDED53F0EF36F031 +:10C8C0000F9AA2E51E3BDEE347FF84EE7EB7382FCA +:10C8D00044B8910E65C29F5496C1FD4965BE7A2B3E +:10C8E000BE9300F837C7C5523D7B1CC655D628E419 +:10C8F0006FC47431C559EAE3B4B03F8C7F5C7044B7 +:10C900002DC475622C2FC2778790BEAFF1B8D405C5 +:10C91000E8178A6AFDDED902F413A17FCBF0BE9935 +:10C92000A3B74BF811FD2B3A231E472BB9746F7335 +:10C93000FB012BC6E74D9C18938BEBC7C86752BE13 +:10C94000C3BAA6B8C2E6A38788CF9A8BCCC4C797D0 +:10C95000C3C7020FF7B31AF96F2EABB7E2FD94B954 +:10C96000BB1437EE4BB11EE2A533F2A5012F71B116 +:10C97000ADF121F1D4823743F93CC6F1356FAFE216 +:10C9800047F9D80A4F027F46F8DBC39F9CD75C4D1E +:10C990001B857242CE6F1ECE03C78179E038F2DC70 +:10C9A000820D34AED734F25F2DF0F2385B237F8CEA +:10C9B000BFC4FD32B75E32533A71B47E7D623B5CD8 +:10C9C00027932E75A4F2ABE59F050027EA85ABE51A +:10C9D0001B391F298F83EB84DF4BB8DCBB4546FF37 +:10C9E00064426FE19FECCFFAEBE29B85BC35B63732 +:10C9F000C6374BFBC0A8770A234D146FD9EC4825E6 +:10CA0000BB43CA5F4DE8156DF9F7544F837A1C1A82 +:10CA10008F4E0F69C24FB8303295DE91485E12D703 +:10CA200011E95518E6A4B8FEC2252AC55117423DA2 +:10CA30005788DDB262595A32EA912FEFEFF9B40FFD +:10CA4000ECF92FEF8DEF3810C6F96AB925DEEE0A42 +:10CA5000D6FB72F9C8648CEFF86AB56D8ABF0D7C9D +:10CA60000DEFCDFD0A65BFF98CF4DC79D3D1A8298F +:10CA7000D0BE74F9EE28BC3E50B29CEBF7F7BA6B0F +:10CA8000C37AD3B9EF862DF49EB173430EFA89BDF4 +:10CA90001CA72D7645F1F2919DD0EE28FDE7A1A7C8 +:10CAA0009D782F7C89A523DAA5A73F013DA9909EFB +:10CAB000237BE254187441E77091F49ED92985795B +:10CAC000F03CEA9CE9C05FEFC3FD626E6D7A40C145 +:10CAD000C353CDDB1BF7F7CB9F257BA6F88125E958 +:10CAE000F8AEA0B6A447745BFE14996E11FA1CED63 +:10CAF0007A4CD1AEC7F81AB4EB318F763DA668D721 +:10CB0000E3F7F2B57ABB706A4F2EB7A4DFB95B7555 +:10CB1000532E9EFBF986B38C0AD2C30E7A07789106 +:10CB200012EE46F9B4086D28CCFF3982FC0EEC9366 +:10CB30001B757496EF04CB7780873481AD16B24EA7 +:10CB4000AEBF6467A1F77487B1185D7E843D51570D +:10CB50007FA43345577E4342A6AEFC4657AE2E7F98 +:10CB600073C6B5BAFA63DCC374F95B06DEA8AB3FE3 +:10CB7000CE334E979F503055577F92B750573E79DE +:10CB8000CA7C5DF954ED4E5DFEF6A27B75F5EFA80B +:10CB900058A22B97EF22D7E17ECC86EFBFD82995FC +:10CBA000EF23DFA3327A5F6DF00813F733DAB83E74 +:10CBB0005AF45E0F47281F3C29F8F95296E751E4D2 +:10CBC00057F9BEA57CB7722BEAA3FE788E1950F8F0 +:10CBD0007EB83E11F9D858CF583E38E2E04517D01C +:10CBE0003266FBA94966901783AF39D8370DF253E7 +:10CBF000B7E7DC4AF941075F4E857C61D6DDB79A1D +:10CC0000415E0DEE73F022969FDDDE97974F6064D4 +:10CC10009A94657D3209E365075F9FBACACDFD2806 +:10CC20006DDE779729E203EF89233E300D001F6305 +:10CC30007A10F818D3C3C0C7B32D8CBD097C8CE91A +:10CC400011D89FE2F777607F8AE951D89F62FA3E58 +:10CC5000EC4B31AD877D29A61F554DA1F4932A8D4C +:10CC6000DA7D5A5544E9675515F4FDF3AA4A4AFF9F +:10CC700054E5A3EF877B4BFF4340F77E687BEF844F +:10CC8000CA734E79AE595DC11A22506E349863BE94 +:10CC9000B607CF2BDBF71398D9D721F65AB6E2F9AE +:10CCA000A0378DDFC54971E2E2FB1D29DA2748E78D +:10CCB0003FA44CE8D157453D56F10686DAFCC1D475 +:10CCC000F67B905B7B733BF9DD2CCF31EC6F889D5D +:10CCD000DF4F1E62E7F78F8798EBAB91BFAA7F64A7 +:10CCE0002E8CFF3910C9DFFDA8BEDFEC473FA872CC +:10CCF00089AFF3A1F18CF2D53F36D07DE5214E7797 +:10CD000002EA2B996F39F7C77F21713EF21C5EC68C +:10CD1000F7E45FAA1F81F6C25087D5857224346E6E +:10CD200000CFDB0F447E2DE161389E3CDFDFF42332 +:10CD30000B987282E7F843ECF529E837187A97DD0B +:10CD40001D1AB724CFEB954B0D2AFA55657C921C22 +:10CD500047C21B6986FEF282F147439CB5B978DE73 +:10CD6000515DE6A0FE3AC1776B1ED5F3A8D4AE366E +:10CD700017FD72434B1D14072BE3043A8979433D99 +:10CD80009A67FE258DE224868A3809ECC7CECB7DD2 +:10CD9000D8CFD0F84022C6810DADE0EF90AD57F866 +:10CDA000FBF3326E01EB4784AC5B8413FBEDFE3783 +:10CDB0008017ED288F87F03B41EEEB5C222FCF1DD3 +:10CDC000EDC3C9BF3542C89A8F53B4CE59786FC5E9 +:10CDD000E6FC7304ADEFB4AEE8371D27ECFA7FC173 +:10CDE0002FDDB0DD7F9F5F3C9CDEF8807F4A6BBE0D +:10CDF000917491746E8F8F24DD43E2CC88CE2D71B7 +:10CE000063A21F237FB5C757929F86D839DD91AEA5 +:10CE100018A726F948B9C4DF751B5A6A277D27F978 +:10CE2000C8C807ADF988F365F5DD76EAAF351F05AB +:10CE3000E98FF8F8F7F9A841C5F3ABABE59F194DB9 +:10CE40006C5434143D94AA6D45395278C9F526E6E0 +:10CE500067B161A390A564F9E358DEBF75B9F65DCB +:10CE600093253A84CF86083EDBDF4E7FB29E7CF767 +:10CE700042F67FBC9DFAEF0ABBE1DD3019A7E271F3 +:10CE8000E40E08C68D2E1AC9F9AB204525BB6344B4 +:10CE9000167FCF9C39B89DED82FF501EDFC4B4C30E +:10CEA000D129F8EEA897DE1B1D156F786F54D8E7CF +:10CEB000058673FE9BB26E20FBFCA6CBBC5BBD2C33 +:10CEC0004BDCDF49612957F9AEE86FB3687F78A57D +:10CED000EF8AF2F768F3C57A4F12FC94E652D9E074 +:10CEE000587C9F5D33A372398CEFD1E6E0BBAD3E39 +:10CEF000CADFC8FC94DECC0264478C014584F95B30 +:10CF000018A37BFB8722C64EC33B8723FA8EE88E8D +:10CF1000DF43DED9F3237C0B54EDFF3843DED93BEE +:10CF200098EFA2FBAB07ED696487E27AB584F84B12 +:10CF3000DF06FDDC1DE67708F437A66F80FEEE0EF7 +:10CF40007AF42DD0DF98BF296309C376A35CFAB8C1 +:10CF500027D9FE66E708D8A8B58FBF9B735EED8220 +:10CF6000F87D37A6673EF2C5BB31D7E4E37CDF8DA1 +:10CF7000E964E2A9CD4A69F62BDDDBB293E57A08D4 +:10CF80008E378AC633E257E2D3884789DF7F039F13 +:10CF9000EFB485CFADB88FC0FB21F68FA31252F14D +:10CFA0007C93CBD9B28864F1BEE87B396A2AC6FB90 +:10CFB0000E223887565ECBCC78DE6EE7783A59C5BC +:10CFC0007C88DFD3380574781BFC7BCC3CDC141ADE +:10CFD00007FD8A4DFB13C271729D4AF7F5CFBF144E +:10CFE000467EBB537EEE975C68D21AB3D06FAFBA61 +:10CFF00056B9D1DE7C57253F30FBE950F2F8C8AB7B +:10D00000E0D74DFC9D8352FBA836E929F797CFA5C1 +:10D010007A68FD33C3EF4B74B1F1F720E4BB94970A +:10D02000FBDD962E362EAF257DD759851D00FD0CD4 +:10D0300000399BF47038EDB7F674F4FC88F3837D07 +:10D040000CBD3FD5DC2592F4D34111173734D09B6A +:10D05000DE5B2B10BF23F096789FFDA08897FB7BAB +:10D06000BA66CE0678DF721DEC82FE87EB193F07A9 +:10D07000BAD1C1DFC3BFDAFDB9235BECCF7358CEA1 +:10D0800055FDEE410795EE530C65E9740E3F02E144 +:10D090004539F7F62C33EAC990DF3DA079FD6FFBE7 +:10D0A000DD03C69A549C579253614FA65CFDEF2056 +:10D0B000A8625F257F0FA18017B5FA1D84A7A20A79 +:10D0C000785CBE636E9BBF839024DEA9662EAE376C +:10D0D000E4EF208C4CD0EB9111CE61879D94EAFD5A +:10D0E0003C4997891F1B9D2DF4C7D5D2BF8C11FDDC +:10D0F0005BE24CE379FCD350ADD7C3E89F1F116FBF +:10D1000071FB5DADF9E03FED774EDAA393F1F74F98 +:10D110008C7432FE1E4A925A6AA67720059DA6C0DC +:10D120007F48A7EBC5EF55E4E3EF55B0FF7774AB4D +:10D1300036D0ED7BB6AA3FBE5B7AA190CBF5F6F474 +:10D14000FE0D299EFBB341FE3C2AFC47D23F22E361 +:10D15000728DBF9724FD00325ED7379CD3DB773CBE +:10D1600082CEAFEE511B2251CF1C37F1DF471AD8C8 +:10D17000417B1CE5D38CAC0A05F191C0BC3BE702B6 +:10D18000FCD3FFCB968CF9E9DDF87B912C8BFFFE6D +:10D190008F846F7A128FE77A265BE17E3F378FDFCD +:10D1A000DA98CDF701916E27C599176631113FCBFB +:10D1B00092A767237F1E0DEB89FCB786FB031BF04C +:10D1C000BDCAF8E07B9568A7A35DDC55D8A5D5C797 +:10D1D000EC76CE874CA7FF33FD765D9C73EFAD4EAA +:10D1E0005D3EBB364157BFCF5E97AE3C3790A12B1B +:10D1F000EF7BC4ADCBF7AF1FA8AB7FCD671E5DFE45 +:10D20000DA86025DFD41A7BCBA7C126B7A02F17B23 +:10D210002C3B95DF9F50849FC4C5E931FD9E8E74E1 +:10D220005F49EE3F64DCBB26F8D9B8AFE966E57626 +:10D230007D7522E3FB56BBD89F32FDFE461371EB92 +:10D24000D2AE673E7DDCBA8C576FD907897D8EDC04 +:10D250004F84C4AB7B107E19AFDE4277F17EA8917C +:10D260005FBF167437CEA39B95DFAFABBED74AF72F +:10D2700084247C46B8D40CCEDF9BED6DBF07F55DF2 +:10D2800036B713F2BB7BCF21BF3E0DE28AF0D96ADD +:10D290003C7703FE9E40F5AFADEEA5AECB8F37BD1C +:10D2A0000F9FCF347C37378BDE5FA57B81725C7339 +:10D2B0000E1FF75C1FC1E786F1A647F3F838166D1D +:10D2C000A57B2DED8FC7F19A6065CBE8DD2A71CF84 +:10D2D000E38E55B50FA20B759AB5C6C21F1EF05B43 +:10D2E000D08F367A38D889B9E85F7DF85107D86988 +:10D2F0004F579AC92F1691639FECEB1EBCB7D30D05 +:10D30000F669C827A391FED0EF923E3C3E3D0B6DDF +:10D310009F0EE47F6FB96F61D3C97F46F2BF0DBE28 +:10D32000237E94F3F89FBA7F21F9D78827B92F6716 +:10D3300042AF75177049FCC97521F127EFBFB8EEF0 +:10D34000B478373AE81E4D01C6E549FAADE9C3FDA8 +:10D350009CD3053EB01ECAA3F6EA8D54B3A2F1BC1D +:10D36000A099B9A29D97F19BFF0FDD4B21FCB777E8 +:10D370009FAE3D39D14A3EB473BFAE3DFEA47F5748 +:10D3800071CF2E444EF07829410F7F7713C525DCED +:10D3900017A95FC70FE570FCE689F504FADB91ABCE +:10D3A00097130CCF3FAA97AB424ECC6DF9FD10FC02 +:10D3B0003E67B985EC6EC6BC8F619CC65FD658E8E7 +:10D3C0009DC7A11E46F6CDCC758A7F8312FCDDAECB +:10D3D000429FE19D16F527B20FBF5FA538F1F71FF9 +:10D3E00066ADD497CF73F0DF1D99637CAF469EC7BF +:10D3F0005D665F5F9523F4BB9BB9C92E137114451D +:10D40000A28ED12E6BF6F3F346DC97ABDC8F45F1A1 +:10D410007752EFBBF0BC2BE41D16C06B7806EAF127 +:10D4200065E636E3225BF0DA4EDCC7398788FB70AD +:10D43000F03897E65D61FC7C589EC389FAE77C175B +:10D44000A91CEB636FE77379FC8A3C7F339EEF3551 +:10D450003B4C743ED5BC2B92E21CF0DC2B1AF8E15D +:10D460008C6967C7812941F8B40655776E644CB55D +:10D4700025BB693FF95E776D5B0EC6E99BDD7637AC +:10D48000E4EF771CA477BC460B3F9811DE96DFF1E2 +:10D490001BCCDFD569F6717BB7B980BF7702F291FB +:10D4A000E17A92F11CE3185877901606AE2578AE13 +:10D4B000F6FC6BC2A55C7EFE7B6910B5D7565E4B51 +:10D4C000F96ECB1EBC13EF194DAA9E67C150808622 +:10D4D00027168F0C87A60D5DFD4BC3916EC3943646 +:10D4E000CF2FDEC9E17AA5C1706F41A6D7F5E17AE9 +:10D4F0007532C6E6F40F89E75AA2D07A58A83019D7 +:10D50000DF45F25CE62FD688FC489E5FB49CE71BA3 +:10D51000C4EF2A6C11FE169C37A6386FF40B6C17FB +:10D52000FE189C37A6386FFC8EF20BF328BF308FA5 +:10D53000F20BF328BF3045F985DF67326F72AECA50 +:10D54000CFEDF243D6079EDBE587D847786E179A72 +:10D55000C773BBD0FA786E175A8EE776A1E5786E5E +:10D56000179AC773BBD0FA786E179A67036F0CE6E9 +:10D5700051DE79C6E9F213C0FECF0F59DF786E177E +:10D58000DA3F9EDBE9FAD3EED4B5BF9D55EADAE384 +:10D59000B95D68FD19958AEE5C6F86788776D6DA74 +:10D5A00038E29F7D295E5B1FA0EFFF89F8E7DD165B +:10D5B000DC2FAA75F3F9BE2DDCCDE95C53C0E96E12 +:10D5C000E2F72C94A6A944E7C5569E1FC9E3BC8D7B +:10D5D000FC83E762F9167E2E86299E8B618AE762BC +:10D5E00098E2B9587E0F7E2E86299E8BE1773C17F4 +:10D5F000C314CFC530C573314CF15C0C533C17C319 +:10D6000014CFC5B01D9E8B618AE762F81DCFC5306F +:10D61000C57331FC7E1CCFE72C41B8D09EEFAEDB4A +:10D6200057021FEAF6954E5D1EEDF9D0FA68CF87D6 +:10D6300096A33D1F5A8EF67C681EEDF9D0FA68CF8E +:10D6400087E647E5B8687DA15D1FDA0EEDFAD07C6C +:10D65000768DEF0DF49D8D59F7CD614C1B2295A76A +:10D66000151019057DFC93F1FCB2214C498E01C9BE +:10D670006959B279723EE435114799C39A4CF4FB6B +:10D680007BB879C4388700A3B8D5EC1F13A97CAA4E +:10D69000BC7F87FF80EEB9BB18FD1E8D3C5F97ED08 +:10D6A000DDCCA9622AEB07F36DD7338E2FEB91FC0B +:10D6B0000C81036F5A63BC4FEE62471EC6CD6E11DC +:10D6C000BF8FBB65298FB736F2D562612F6D31ED03 +:10D6D0003C88F7699A0A15BA779D6E66472C798857 +:10D6E000A78A3CB42366F789117AA9E23AFC1D3176 +:10D6F00009B7F483829CA0FB89839BEA4744433F9C +:10D700009A6F18FD3ECE682BB71FB01DEE2B7BFB2A +:10D7100014CFC610FE5E20EC71CDC7C77FEE99B165 +:10D72000BC5D386FF7DC335184C7B1CB148A3B1B27 +:10D73000BC9D79F01EF43D429EF6DE1E5071BCC2C7 +:10D74000657C3CD96FE1BA64BA175AC81AF2F15E27 +:10D750000BEBA73094DB126F30BFC338BF74582A6D +:10D76000E8C7BED2FB5443FAC58CC4784456C7E818 +:10D770005DD131FD3ED4CD97C83E80FA25BDD6D3CC +:10D78000A7D03BCE637D4B96225B8CF1DDF946073B +:10D79000ACBF89B9535CA48AE8FEB184A79767A798 +:10D7A00009D422CB62F5A63005E9CD0EC585F00F70 +:10D7B000ACFC8948EF5CB785DE551E67765AE89D5C +:10D7C0008E76E2752E3A64BC8EC15E30C4E5542F6D +:10D7D000FE2C19FDCD0B234DE43759B83B82EC06E6 +:10D7E0006DAD42724DDA418522DEEFE2B2373A4C3E +:10D7F00046BCEFB4507F325EA72CCD9F6CC2FB09B4 +:10D800009D37E4C4AA64073C8FF2F0ACEFE55B07F8 +:10D8100062BDE5FC5DD18BCB76F3DF1915E73BF2FA +:10D82000774B678BF8AFC26C6F34C6C3C8DF4793C2 +:10D83000F764E4EF924A3F4FE17B7DDF44FA16AE96 +:10D8400017EF7EAF2CA4FBEFC6B8AB1261FFCD5F24 +:10D8500066A1B8ADF906FBB044C4655DEEF74A0FAA +:10D86000F531D887F27772441DA676F914FDC2F21D +:10D87000DEE7340B9703D376323AAF9AB664840965 +:10D88000DFAB66BB39FF4C5BC2ED9C69AF7AE8FE4B +:10D89000A6B41B3F10F6CCF84B4984FF8F85FD32B0 +:10D8A00009E35501CFA31BC2441C5B22A5932FF1B2 +:10D8B000F8D5F10E2E0F1AF6F177379A7D366E579E +:10D8C0001D66FCDD38037F8E33FB4D78A1D13D18FA +:10D8D000F813F263D01E82FEA6A07D1487FC9E3250 +:10D8E00092E2210B14BA4764E4F7D1968A3730DE0E +:10D8F00076F466E6F6B1507E073EC6FE7C0ABDC7EA +:10D90000A0897DAEE46323DF4F8F10FE2907F73F28 +:10D91000B5F829D056C547D47D7F9B8CF1C4D3D1AF +:10D9200067D899A6E1C1B8BDC82C5EFE8F17FF3637 +:10D9300079196E7ADAF15BA8BFB4123E34F9EE447D +:10D940003B7E04F41FA0BCBCE3AE5CEBCC1079F9C9 +:10D950007F018165E5A90080000000001F8B0800A1 +:10D9600000000000000BED7D0B7854D5B5F03E7340 +:10D9700066269364122621901048980422A906383E +:10D980007941401E87C82358B40349143009C33B6A +:10D99000A878236A0DBDB499908001C11B340AA2F6 +:10D9A000E880CAA5966AB4DE0A4ABD838855EB03AF +:10D9B0008354EF6F1B86A7A0B546B8D6F67E5EFDF2 +:10D9C000D75A7BEFCC9C9399006AFFFF7EF76BF8E8 +:10D9D00074679FB39F6BAFF75AFBE4ADFCD28CFC2E +:10D9E0007E0C7F2CAC3F630B5CF43B9BA2E6A50650 +:10D9F000F3185BB12E27953919FB067F26F62C17F5 +:10DA0000FEF54AE6EECB584D9FE01D8AC6D8208D24 +:10DA1000E993D3189B83838CA5A1022C97B1B9A25B +:10DA20003E5D1BF2410B8C5713CFEB69ED8ED93E57 +:10DA3000A82F7704A7AAF0E89FF2EACA065818EBC5 +:10DA4000A3BA198375C5D8BCFAC02CC66C7BF20387 +:10DA500003E1919AEBA2E7CC1A1CE04960AC7A434F +:10DA6000FBC6616E1C17FE57CC5895BDD5C67020FD +:10DA7000E6B77986C3FAF298EE77627BF8AF88B1A1 +:10DA8000E3EB9E7F6ABD125AFF711B9BDD1E617F17 +:10DA900093340BCDB3B38131F730C6763538A87CDB +:10DAA000B2C1C5DC318CED6E48A3FA530D6E2ADB92 +:10DAB0001B72E9F9B30D1AD59F6B28A1FAAF1B743D +:10DAC000AAEF6928A3F285060F3DDF3FD05BA0C116 +:10DAD0007A1FB0E8C7EE82FDA5ABAD8C0D8135B6DF +:10DAE0006E66780E8B700B6E829FEE18C598971F2E +:10DAF0000B1B6CD7ED2C85B1A6758A6B35F4F33A08 +:10DB0000EDC79444285B9440CC0868E09BA207735F +:10DB100079DB6FB2115E1C8E2CB7EBC127A05F4D75 +:10DB2000839DAD87478F5EC6741CE7D19FD8FDBE2D +:10DB30002C84DBA1838EAC101C3FACBFD7061881B0 +:10DB4000C797E3867673EB62B5F5F0FEAD7C4F19AF +:10DB5000AE3B3E4FB37B016E19F98CC6BFAE9FE75B +:10DB6000871A94CB37EC7FE47D3CC77D59762FE054 +:10DB7000CFFC3DF96BD3DCD8CFEBC17EF39D2EBB40 +:10DB800007FADDD29C6477231EA4B2BAF63C9CA7A8 +:10DB90002B73564208FEB59A42EBC82AE0E37F8613 +:10DBA000E744ED5A6D330DED2CD40EE0A63BFA8719 +:10DBB000E09461653E4B01C2CBCB7484D700A621B3 +:10DBC000BC06C2F39802FE3E3639043F33DCEC005B +:10DBD000770BBC1F08A5BD2004C70C78AFC2735BD0 +:10DBE000EEF1392C1BE1C6E67922E0CF83B87E84C2 +:10DBF000FB6C07D1D562073F4FA0ABA9A980872B4B +:10DC000036292E4003B6C8E9BE7E0CD417BD666324 +:10DC1000ABA13E23D96D1F00F52E38DF1D505F707C +:10DC20007BBEDD0DFBAEC2B380752CDA3286E86DAB +:10DC3000911FCAC2E87479C3A603197B117F02BA87 +:10DC40001DE964914BB727E785D16DAB427461AE96 +:10DC5000AFD3545A77156393117ED5B767D9173868 +:10DC6000B1FE9A6D451EEE8BC341F68376016C378B +:10DC7000239BBD8AF4D505FBDA91C5E72B081B7FF2 +:10DC8000018E1F363FB49FE781FA7D5A028D37DF40 +:10DC900005FBCEC2D245EB0438109CBA36C2786E72 +:10DCA0009A87CE6361C06FD3703D569817EA735D53 +:10DCB0007E1BCEB3A039DF8E7CCABB81CFE36D491A +:10DCC000B20F87FA7CABCB9E81F08B0358A4D0FABD +:10DCD000FC3BE06816015C929D380F9B37CBD91353 +:10DCE0003EF3C57A17B526D9171B9E6FB2E17900AE +:10DCF0007FD323F18D83E2DC17344FB233EC6FD541 +:10DD0000ED1AAE47C0F7D4ADB1EB591FE8DFB6D975 +:10DD10009605F57F13F87B50C07546762047C17D88 +:10DD2000DF1AABE13AE7B85A697FDDF0BD1FE001C9 +:10DD3000CF17BB3C045FC00B1F03382C6A339E67B0 +:10DD4000683D1CBE8BDAE613BD2DB17AEDAEF075E1 +:10DD50006CD99FA3005CE6007D2B007FE6F2662273 +:10DD6000BE9CBEFFFA4CDA27AC13E19AA0B9A7A675 +:10DD700015119E101E4B7CA929E4F42BE7FBA3662A +:10DD8000A5F9FE28F86774BAD45F4D43BA84F35DF1 +:10DD9000ED8E4E977664DC30AF7D91E26F527AD291 +:10DDA000A9A44F4997924E25FD3E62F304D29410E8 +:10DDB0009FA9E9C3EA9E8D00A78C7C7E0E73C5B92E +:10DDC000025C5F41B8CAF7F67CCE8FAAB28DF48EA2 +:10DDD000E3E1B8E704BFAA2A0DE4DC9A176A2FE74B +:10DDE000AD4AE6FD10EF11DFCE8973C7F62BA8BD53 +:10DDF000E063825F2CECE617BBD7F4477EF18CA280 +:10DE000021BF58B1F140C69D00B715BF8CD7100691 +:10DE10009FDCFCC42D03B251BEF9E9DCE4BA16FF65 +:10DE2000359FF8C412219F170522F38BEB73BD6A4F +:10DE30007E71A8BEE8BE5F5EE6E5FC2680FCE60FCC +:10DE4000BF7CF1C85877489ECAFD2C6879D736DF69 +:10DE5000190E3FBEDFF5B9E7E6E3792D74DADD2A66 +:10DE60003C5AD83C9FF82F4B635A8E123A7F335E50 +:10DE7000CC6F5674EA573FCAAF7E8F7C7AE18699A1 +:10DE80000CE5943C379898B15121F92AD77F593E37 +:10DE9000A7DB1FE4F3FE73057ECFAD9D641F908268 +:10DEA000FB9D5F886AC51CF17CCE22E3F3EE7373A1 +:10DEB00075F3F9B5482FE7DAF9B99DDB6023FE73F6 +:10DEC0006E77829FC1FE3E59F1FCDBD741BB8F1FAD +:10DED000D89E89FA4AF8B9B1427E6E582E8573638E +:10DEE0007D239EDBD8F0735BFA283FB7854FBDF5E5 +:10DEF000C717DCB45FCEEF36C6F8911F2F687F8658 +:10DF0000CE714ECB265B16B4BB3A3F8BCEAB9BFF9C +:10DF1000D7E5BB18C0776ECB761BF289AB251C4CBE +:10DF2000F400A5CEC2E80CE592921CD2C7647BE453 +:10DF30008FCFC03CB7DF1A9BC84686E6B92D9FF34A +:10DF400085857549C938DFC2BAF9F7B01121796002 +:10DF5000DEE789584E2F0B603CA4DB1393B4CC153D +:10DF6000849F968872F74681870F01B863011F0668 +:10DF7000C6B7FF1CE130F09FE234E41F438706FD83 +:10DF8000382FE237AEDB0EFCD301ED86DE1CFC1C25 +:10DF9000D73114300CFB6199904C25EB0FF51DB077 +:10DFA000EC1228B3555EB6E6733D09DE07F03D4B33 +:10DFB0000916E3FE257E9BF1D7CE1E6FC9463E961D +:10DFC000C2B42677085FE538125F253E47DB5FCB9A +:10DFD00045EEEF441687A73D0EF6977C09FB0364D8 +:10DFE0002D490EED4BAE0F7478DD82FAE33F0FDF63 +:10DFF0008EFAF389462DB3CED9DB7EDBA6F48FB043 +:10E000005FF33E25DD2C72709A06BAE98376C7B9B4 +:10E01000D6217D50EE9C5040BE41BF13B7C65A700A +:10E02000FD725FA897B318AE9763897A391BC6F55E +:10E0300072ACA35E8E25EAE5F43C3F99CB23164CE7 +:10E04000403D13F401CE0F029C4E3AEB87D0BEE464 +:10E0500073A91774BA8209C961FCFB649D909B2C5B +:10E06000B811E99BD50F614FC0549DAD27122C7993 +:10E07000889F7C7DB2DFEDB62EE2872CC1EE7E025A +:10E08000482EFEF677A7A4C27C8BDBB2F215E857C8 +:10E090005D5FD8590FEFAB9B5335E41B8B9DEEB5FD +:10E0A000281717FBB234948BF16DF9A7B7C0FBC5E5 +:10E0B000CD5768D8FE76857990BEA49DB08475FF53 +:10E0C000909DB054F0B5A5C82F015E4BEA0F0C75BA +:10E0D00041FF255A6C3ECAF7A55BB89D30C3C25AB2 +:10E0E0001494C34D9EA9C8C7BA1E5434D437D9C39B +:10E0F000C05F1D21FEFA7EAEE7B7C867D857807FA4 +:10E1000030FEE5288355DC57BB8EFB60A08F3CC1F9 +:10E1100070DD1ED2EBA70ABED1D9762CC19DC7E116 +:10E120008DFA3AF3EA16E4BB2B845C1B6CEF3A766B +:10E1300017EA3309166D07E797EFB8719FAFAB2C5D +:10E1400086E48D682FF8E9E09F953890BFAD48C808 +:10E150004E25BD6A8B4AFC51E24FAD58F3E2EDE526 +:10E16000FD116F16C37B94775BF121B0D0B56D576D +:10E17000F547BC5AB469CA033E906399028E27AD35 +:10E18000C199783E67B6A72637A25EB8BCE93206C9 +:10E19000EF176DBF2B13CB33DB636723BF9FEC9A65 +:10E1A000393909F6BBE4E1A47C354C6EFC45D0E37B +:10E1B0008DCBAF4A457BE0E6AF0F3CE2023B6E31D0 +:10E1C000C01AE1FE457BBCDF074D6E6ED893A902F5 +:10E1D0008D7D1DE3FD1CE1799365DF756390FF2B59 +:10E1E000FE9D03A8BD3BD5D58B9D7D1AED50C0E7A4 +:10E1F000E53FFB80C6F9D4F2E6B573A0FFCDCB7F37 +:10E200009588E3DC74FFE1512E78FED650EF7FA3B2 +:10E210003DFFB1B27DA70B05D396ED23506E7F8DE8 +:10E22000765A31E2B5E7BA3908F7D755827BB4F9A7 +:10E230006AF728045F59AFF6F7217DD61B60761781 +:10E24000962E46FAF21995D5A33E20F51AF93CA967 +:10E2500080C3E54C9FD64CC48B653B3767A25C39C5 +:10E260009BC0EB553BAF7F03F994F7F118AEB75B5A +:10E2700019E9C90B7D5CEF66B540AF0342F30F2C83 +:10E2800088A7F1966D2934C843D04BE8F9592B2B58 +:10E29000C3750C6EEACA47FDEB436B60319EEB879A +:10E2A000A0D7A27DFB17C1C73E6C55A7E2731F1014 +:10E2B00012EA231FB6FE2A61A833A4C72514B507A6 +:10E2C00090CF2D7F2EA940E52845F8754BB75FC448 +:10E2D0003975600AE9632EC4D3157B0F4E65BC0EF9 +:10E2E00082303A3C6F147A5877FDB967C8AEBB7973 +:10E2F00037D7276E6E7FE6D57418E7963D429F109C +:10E300007ACA7241CFB73CC7E1B2FCB963F685E186 +:10E31000F6486EF2DA81A0094E78F6F2D9F7BBD151 +:10E32000DE56C8AF52A965CE691C8AA5F4977491D0 +:10E330007EB83EB783ECF2E5CD62BCDC8EB5D9B4D5 +:10E34000DF997DC3F5A1890536EA27FB033CA8DFE9 +:10E3500097B1892390FF0596C7B5A05CD76F715A16 +:10E36000B16C5AEE2439FF709D25D70AF0D5953847 +:10E370000DF5B87A076F7F675CE20E2CF7C5F1FAEE +:10E3800097B19924A7BEB4789E5902EDEE540FC5FB +:10E39000A2FF6300EB3A60817A493FEF7505306F69 +:10E3A0002A03EA51517E04147CFFD96F3E2AC475BA +:10E3B0004C181C3CCF6069B6C6BC3993014F6A0A41 +:10E3C000C43EF3828588EFFD5EE6FC7A9B8DB5A0A6 +:10E3D000BC63560F9B05CF03C8BFF0FCFF66F1235B +:10E3E0003FDEA7041E0BD7BFEE1378EB8971B6286A +:10E3F000B0CEC7B3BC4B711D3F526CC35175616E3B +:10E400003507C7FFCCC6DF4B3DB65430E10C618FFA +:10E41000D9D3D39CB8BF26012F45D7593DAC6375DE +:10E42000DECB0B115FEEEE72B01898BFB42B8EF4FA +:10E43000DA8CF432926F4D022E8A3B05650E7B39E1 +:10E44000CFE28B81F5DECD1C7E6CCF1C26FDD71272 +:10E45000AB633F65DF6FFF86FC7EA0FAF9813ED09B +:10E460007EE09D8AD6046D6ACE9DDEF60E43FBD912 +:10E470009F8FF0BBB39FB7B100F6D779AEEC98177A +:10E48000CEFB6E57BB43CBE3E385EF63DFCABF250B +:10E49000265B42EBFBACEBF42F9F2FC2D24172A85C +:10E4A000749FCAFD4DA6F57C96E6B6D23975390241 +:10E4B000166CEFB4F81505DB1FF800D757EA7006A5 +:10E4C00054D4E31DB63F85CB19762823E9F41524EF +:10E4D0005AD837A02CF46FE2E737A18FD1BEDC59B0 +:10E4E000C0EDA49DE29C247C25DC985B67E172E68C +:10E4F00025E7CE6AEEC7E274FC4FE2F9B9BF669336 +:10E500007E716E1FE81911F44E591E463D03F487C3 +:10E510002FB3F5A7106E52CE564AA92BE4B02AC6E7 +:10E52000AD14F0AA745A387C2A4CF0117863C60BEB +:10E53000F3B9CBF3643F3974B04F169DE3F07F61BC +:10E54000747E7B111F3BFFF6E61A203796AEEAC7B2 +:10E55000BC59FF13CF2F103B0CF58AFB2DA457A0FD +:10E56000DE877AA2E41F5EE40323E939D703731937 +:10E57000F18D1A358EFC8C66BE21F985370ECA11D5 +:10E58000C8375A891FDCA9761DB428213E31B82C22 +:10E59000381CE5702798FEF83E6869A7E7DF146429 +:10E5A000137F18C40E0D203FAB35588C7AA0EA7843 +:10E5B0006CDB4910296DEB387D34D9FC0F2E41FE00 +:10E5C00050E9D450AFFBCC6FF1D9609D6D499C6F81 +:10E5D000B42D4B2779FE19137C64B69DF8C89516A7 +:10E5E0008B8FECAD39E9646F75B7CF71937FF5D739 +:10E5F0005FAB976DC1F7331D2477DB501E43BD6DB4 +:10E60000E3707AFFA2E44BCB385F6A9BA90F88C303 +:10E61000F733FB5B70BEDD29DEBFE1B9A7ABFE9F20 +:10E62000C7A23E79531C7B029EB765E90350DE3ECC +:10E63000A078E62CC6FEC3F9BA8373E29EDAC98FCE +:10E640002780FEA4CEFA841DE17E6FE9471FEC3BD4 +:10E65000F620C2CB57CA72519FEF44FC1C193A2FC7 +:10E66000B0CA597D72E8DC524CE726F1D56783F3D6 +:10E670004BE1E7B75A897E7E29E2FC947AC06FE2CB +:10E68000FFFC7CEE54397F672F696E2CD5FEDED4FB +:10E6900042585FD3AD702E2410837720BCB6AD4CAA +:10E6A000D0711F9D1656DB1E816EB30B85DF09A549 +:10E6B00031D0C33C410FF324DEAE32E16D7050D255 +:10E6C000E97881B7D0FFC578CF509CF753E5F028A3 +:10E6D0007CF8E67FABB323CD33BC90FB0BF68356BF +:10E6E0005A48F2B5D4A0AFBE99FF5106CA29F6D553 +:10E6F000814128775F49F18C2C04FE113BB48BFCDF +:10E70000E69D03BA6CB8CFCE391F67A05E34AFFE6A +:10E71000B7445F17BBCED5F135361C27A922CB16DF +:10E720008432B522EB20E2CF91E931EE98087AC825 +:10E73000FEE9C33250FFEDA81C96817CAF030EF0BA +:10E7400010AECFEA4E40FEC7F654131FAB147CAC9C +:10E75000A362087F2EF866D8F38D45A8D73A2D5AC4 +:10E76000B8BE602ECF02DF0C00DFFC08EC332C4F6C +:10E77000817D1600FDF504D867583F06F6199647C7 +:10E78000C13EC3B2A341A3F74D1543F604E19CBFBC +:10E790006851687CF4DF46D28B6F7C5C6501091F91 +:10E7A000F8AFF6E17816C80DD597B4F535D4176DE6 +:10E7B0001868A82F681E62A84B3DD2BBEA0AC3B8EE +:10E7C000E565858676ABE347D8F05C93CAF239DC21 +:10E7D000CBF209EE1DD74481FB35A309EE87A78F45 +:10E7E000CE40781E46B8A3FD66D512F01C24DC6727 +:10E7F00089390F9715F2E702EEA1E7E5BDCAA94FE7 +:10E8000010DE31087707951F21BC09EE1CDE2710AA +:10E81000DE3108F75C2A8F22BC87E1B800EFA20B3B +:10E82000C3FBE6DDAA010E373E6E8477EDC37D4D56 +:10E83000F01F6880E3A20D430C7509EF05CD467803 +:10E840007B57159ADA31B601E0508EBF001D1C2EA1 +:10E850009E467129AB83F9E281AF2421BDC1FAAD97 +:10E86000150AD78FE0A715E87016FE02F46575F259 +:10E87000F7CD73143FF225D489D0AE00B806E281FB +:10E88000CECA5D979D42BE743D723015ED7A3F95BC +:10E8900037B000D167350B527D1EEBCAB443798B7C +:10E8A0001A588BFEBBB71CDE27919EFF32FDDD4E52 +:10E8B0000589529B3F0CE99C3993C9DE8C764EC08A +:10E8C00029257F62CE51625FF05381FC1FFA75C427 +:10E8D0008FB8E30E3887CFE60747E1FC373BBC8FA4 +:10E8E000A65868BE3D38DFA736EFB0BEF0FCADE2FB +:10E8F000D11948FFCCD3CF6027459B6F136E16E02C +:10E9000030BF0CE0A4601C8EC3E5642587CBFE4DB0 +:10E910003176F4679C5C67237FE5E6F8CC4CC4DB7A +:10E92000936BA66522DE356E1A9689F83EAB65DAE2 +:10E9300059E4DF53D41935144F6DE578CFD8ADA421 +:10E9400077DD21CEEEB89B6901785F393D41F3C197 +:10E950007EBCBEAC445A2FD39DF9D06EA1D8F7C26D +:10E96000D6A533703CB9FF051B620CE7FFA3126309 +:10E97000BD92D943789685E76C0FBDC7F357ABFAC4 +:10E98000787BB1A3EBFFB0FD8D57C2C63B5E98907C +:10E99000827A0B1BCD467FA386FA4783EB970DFE49 +:10E9A000375EC909C155E2D36F0A3D9FE0F9C063E4 +:10E9B0008AB7012D913CB8A5DBAFB52F11E1B7297E +:10E9C000FEA57BAE44B8BCC7FD1C9BE36B887F7C77 +:10E9D000827C3B0BF9F4F519C130BE20FB07053FE3 +:10E9E0003DF2CBEB898F1CA84CA5784CC773DCBFDC +:10E9F0007C54D07D47C5F5D57700FFECD8AD929E0D +:10EA0000D7B1E7FC41F4D374B42B9A00B9257CDC70 +:10EA10008E3DC0CF91DF7A6CF47EFFEE5FD13ABFBE +:10EA20002F7E5EB157F0F32D7CFEC5560FF117E631 +:10EA30009D6DD8DFDF8BAF5F889F1FB1713CED38D4 +:10EA4000A292BF8DF9F443B9FDC3F0B38CE36763C1 +:10EA5000650CE3F295F39959154007A8E733773130 +:10EA6000DA949FEC29EF47F27283ED38EAD32EF85F +:10EA70008772DB0CC74A663D1E0CC3DF9B9F83F683 +:10EA800061EB9B85EFC3F0D98CAF2545467CFD82B9 +:10EA90007D9569CFE6EF0FF50FF13DFC09E72F9269 +:10EAA0006F49FC05BE55837C0DF8CA554580B73FBC +:10EAB0002EC8FA4D5009E32B17C9C736C57F4D72D2 +:10EAC0007073FCD784C7872B051E839E81CF3BAE16 +:10EAD000E1FA06F3CF267A9827F5089B2701FDA4D3 +:10EAE0004756F54DC4F7C79ACB89EE243D99E73BCD +:10EAF0002AF04FB69B67EDB26911E4A17795117FBB +:10EB0000D8AED984EF7798F02CDAF8E6F6729E79D1 +:10EB1000A678AF799EDB8A84DED95E7D51F3211918 +:10EB200076F727FD362E84972AF2812F1382A47F51 +:10EB3000CD36E86547CB46935E76B8E27C44FDEC83 +:10EB400068C5F9B74623BD95D904BDD752FF72F108 +:10EB5000DEBC8E8F84DE704AF08F1382AEE57B754B +:10EB6000FB9AFE7311EF57A91AF2AB23330A09CFB0 +:10EB7000CFF82B69FEA3152AF99BEE2F9A3217FDC9 +:10EB80004D723D72BEF26BCE27A03FED0B8017FA9F +:10EB9000C7CA6D5ABF48FA85191ED1C695F803FA3F +:10EBA000EC11DCE761E4A3F8D66B84D361EC0FEFE2 +:10EBB000676D5729DE6686D381E9C3882F1DDD2561 +:10EBC000F827C015F5F0DA878DE7BAA42DDEC46FFB +:10EBD000FA1ADECFAAE47A99E4D7727D87570DE955 +:10EBE000179E3775A1F396E35C2CBEDC28FAA3D8F8 +:10EBF000FC86E46FB2613CB0144DF3659BDE5F6E42 +:10EC00007A5F60AC5F241E1F13F823E5CFB158ADC7 +:10EC10003A521CEFE8D531B5E1F9099D45DC7FD3C7 +:10EC20005924E2DE9728B7FFA328B2DC8ED65FF224 +:10EC3000BDA70B3D41E4772C504EF1EC8BE57361A1 +:10EC400072FE4C11D27950B1637FA957DD58C6E5E9 +:10EC5000C2E6F8A7284FE3D346AE17ED6F8C213CF0 +:10EC6000FCF335FCFD9FFFED23D2A70EECDD9C18D5 +:10EC70002EE7255E9EDD332D11FDC2272B1E4B0C8A +:10EC8000B703E4FB8F2B1EBB672CD1B7AAF5762EFA +:10EC9000DFD61EE8A810F680D0176EB2B6FF3FB1DF +:10ECA00007CC76C014F5E144E47F667BE0AC5B4FB3 +:10ECB00074117C04DD09B972A380CF9F6D7A22C5DF +:10ECC000E9761572B962C24F0987D3120E1BCA7B4F +:10ECD000C59B53422EC8FA622B2378781D8CF465AD +:10ECE000D6A66818FFC234951238974315F98FA13C +:10ECF000FF4AB67FA65825FC96F31CD9A6B4A37F7D +:10ED0000E5B7CDE5D57760BEC38C78E2ABB2FD1236 +:10ED10005FEFF2EBC8C6A46B711EEF1655C3475EDA +:10ED2000DFB17EE1EB977A9AB9DF326BEB45D9D14F +:10ED30005EDFF644B46F83629DC1FDB1767742CF4A +:10ED40007E18AFC1FD2F9BA16A8DB0FE651BF8BA7E +:10ED50002A7DAA960DF5DFB63E762DD2C1897A9B23 +:10ED600085DB072E039EBFD95AF836B63F59C6E554 +:10ED7000CAB18AAB12310FCEB7C5A6E5B87BCE5764 +:10ED800053CCF3D2CEEE89B1A0FFF46CBD8D05C893 +:10ED90007FE1217BF9C88621549E45F871FB9ACE0C +:10EDA000FFC662EEE73AD1BAB03FA72737AD43E2DC +:10EDB000CBB15D6A993F02BFBA519CDBA9AF9E26D9 +:10EDC0007C7B755739C9E313157C9E53ABB44484DF +:10EDD000E7EF36A844C7277D7CFCFD7BEF4A1C0B80 +:10EDE000FB385BC1F77576CF9D6F8F817D062BA4B5 +:10EDF0003CE6724AE6F704370CA178EFA7CDDCFEBB +:10EE000096F42EE3E157AD3C9248FDA59CDB3DDB3B +:10EE1000B0FE8E5D27C80E3BBB0166E372CE998FB4 +:10EE2000F986BC3B5B32C378BEB32AE20DF5792D7F +:10EE30004679D6B897F32BB39EBB7803E8C1E89721 +:10EE400032D9790B1B0B134B907E510FC63C932785 +:10EE5000CA0FA6E23EDAABA95D85889B2D6C8B318B +:10EE6000F083CA66A35DB7C064C7F5B0EB4CF24847 +:10EE7000C2697914F924F5B90E61AF1CB579AA23DA +:10EE8000E553B41773F9330FE8370DE3444CAFBCC7 +:10EE900052C07B3DC2C7DEF5450EE8D31DAA361E23 +:10EEA000F5EA1E7460D203CBCB8CF0659A8F95483F +:10EEB0007F849BF4FBD3A8FFB7F41572DB0772289D +:10EEC00001E592FE6C31CA958BF51F5CB47E5E2322 +:10EED000F4F31A837EDE814DC2FAEFAFBC9EFC5480 +:10EEE00047AEB99EF4F523DD7E2A8FC14F25F5BAD2 +:10EEF0002333CA0DFA67D8F33EBDE58B47D3378F6E +:10EF0000213F263ECDE5D25A6147360B3BF2C80C75 +:10EF10006147A630A223AB556791F8D9A5EA6F0BDC +:10EF20009A8D72C9BBCA683F3E3FC97B16CF252662 +:10EF3000ED72C3739BABC0E83F34E1E740C6FDE729 +:10EF400077A12F00E0DE54C9F34EF139E6BF48B98E +:10EF5000C4A03DF28BCA0D97FBD7F3F73EB500D3A3 +:10EF6000E518AA74D4DECAEBBAC2EB3EA778AF8A22 +:10EF7000BC371BD48F6569B351EFC2BC9EF864FEE9 +:10EF80001E516420E075627248FEA15F3F9687D6ED +:10EF90007D89D06F5045D62B48D798EF735901DA49 +:10EFA0008C3C2F2C0D5DFA05347E00F37A824D13D4 +:10EFB000C9DF5CEE48E4F179B0A37BC7BF46AED7AA +:10EFC00095F5A5C90659F97AA2E2B36877217C0EB6 +:10EFD000D3C3068C223F9A85FC2D9BE247D8107F35 +:10EFE00067393D190807C07792AF1DBFB1131FDE07 +:10EFF0005FC9FDB01DD3476FBB1D9E8F78DA49BE38 +:10F00000F48EC5D20FDE95108EB747579DB0205FA6 +:10F01000FEFD1EA6611EE3D1DD5507DF80710EAC3B +:10F020005AB8B118E9E84D95EC06B3FF76D2D3E3B0 +:10F03000C8FEBAEE1A95F2BB0F97A90CE5DAE10DFE +:10F0400071063B24E4D755093FBED867A5F768EAA7 +:10F05000E462FE15FA37314FAB8C9FCB0B829FB524 +:10F060008B73FCB9D063760ABA69137473AFA09B33 +:10F070007566FFEEC39C6E0EEF01C301E4FA3B33ED +:10F08000169692DF7A0BA33874D674757D11ECEF67 +:10F090008A18CD86F09B34239FC3B342B160FCA68F +:10F0A000BC2CDF86F47E455FB70DF96879D94CAA90 +:10F0B0004FAEC8223B7FFF2A908F68EF2768194820 +:10F0C000974367C4042C89683716129FB8F28CC521 +:10F0D000402FF9813803DD5DFE78B2E1FDB02DE906 +:10F0E000867A3F4FB6A17DDF32233DC60D2D30F22B +:10F0F0005DC6F54209E729EA38F2731D0DC9517A58 +:10F100002FF511E9AF93ED015A06BED622E4C808E7 +:10F11000A8633EDDBA8A2607E64D7CD16ED5F8F8A5 +:10F1200055A41F38B29E73209D606815F3AB5AA496 +:10F13000FE29FCF74C67A6756D6018673D5AC60836 +:10F140009F62873205F5AF3671DEF7897981AF4E60 +:10F15000B2919F8E9F63DF191E6AC73C46FB200D4C +:10F16000E9AC00F184F7FFB9E8BF53E0CBD1B2C7F7 +:10F1700056C7213ECC66A46F4C516F5E8DF1C4A37F +:10F180003318D1497BE0E5385C3F8E83F9812F4409 +:10F190001BA7E2571FDE82EBD965A771CA1F671351 +:10F1A000104F2EFFD1B18FDF46F06D711D88653D88 +:10F1B000E5F088C7750D81937B86056C540674E471 +:10F1C0003FB9670EE9180FBCFCCFBB3E7E8AE1BC9D +:10F1D0005C2EB408FC36F3D75F3CF1EB05289F7F2B +:10F1E000B1736BC10750FE60F583E9F550FE7CF505 +:10F1F0004D5B6F7787FCA53BAF5DBAA30DEAC37E7D +:10F20000F8D3279F43BCBAF6A7FFE7395CEFB57F79 +:10F21000FBA313D67F59530243FA96EB33CF93C621 +:10F220005A148C8B221F25BE6CF5517DBECF68FF12 +:10F2300098E53EB6B702FCCAEB7F41F1E534D1FF59 +:10F24000F03577292ACCFBC17CCE573A1ABADA2698 +:10F25000DBA87D00DB039FA47CCD818380AD607F34 +:10F26000BB4FC1B83828481AC67B07C07BE4E7CC3F +:10F27000ED26FD2A53E2AFE02B78CD81913FD04AB5 +:10F2800078962BE291C87F91DFBF312A9BF8F2403C +:10F2900027D3F17CCB5EDCA0609EDAFB5EB7467ABA +:10F2A0004103BB7F32D8C997AB3CEF22B7ECFDB925 +:10F2B000782EB055ABB72034EE2EA1D795BDE8A47B +:10F2C000BCEDF77739B7939E7FE85A4BB87E58FA72 +:10F2D0008B3F3DFB3BC4AFF9B1845F66BDA543D016 +:10F2E0004777DDE6DE763BC0C7F71B07B7AB747721 +:10F2F00006D9E99A3B03F377BADBFD54C6D3B43F92 +:10F30000223F9F55154F7106195752CB3E5F83F42C +:10F3100038AFA4AE18F5F7743C87BEA138F607CB1A +:10F32000EC946FE053E2282F3D5ABCFABF843C6452 +:10F33000AC6E24AD83D58DC6F2FCECA66D767774E9 +:10F3400079D52CCE35DA7B9B9D7923C595FF6B143F +:10F35000F72336E139D8C2CEC1F9FBB9181F8E7632 +:10F360000ECCEA2FA03C4B876328E681A48AC79B7A +:10F37000E37FF616CAABCE235C5EA5D67FD980F4B8 +:10F3800027FD163569AC3B6EA6433F9BE8972AE202 +:10F390002C48C3A87FD78878516735A378516AFD78 +:10F3A00047FF8DF0D924C6AF798F8F6FB706F6234C +:10F3B000BED438DD24773AFB256A78AF897DC5F362 +:10F3C00053D219C747393E13E3E3CA59D8BA53E3B6 +:10F3D000AADEA1EB101358201EF14771D0BCE9AB97 +:10F3E0006228AF55EA57A9F577DDAA8E308CA7A021 +:10F3F0005EFD7E15B7B7D1ECEC1E37CBA057919EC2 +:10F40000655E87ECD769637BD0FE0DD3B3480F638D +:10F41000E1F30C31D4851FCD58B7A5D90D7CE2FDA1 +:10F42000AFCAFBD47139E04E19C5FD77080FA98F1B +:10F4300049BDADC7B882DEC3F44B1FF20B9947D16B +:10F44000AD27D586D94DD93DFBC97C35790E129EA5 +:10F45000D1FA3F3F499F329AF4AC008DE315C3586F +:10F46000E29D99045F13BF04B6C5F3E9851E0A5AED +:10F47000A4218F41EA95923F770ABE1BCC0A92DF06 +:10F4800050E6890F823E99D0FF86D149DD79F6A8F2 +:10F49000071D6DF88CE2EF35A887C2FCC1D59F1817 +:10F4A000EEA114954EBA81D66BCA97088BBBD27A5F +:10F4B000BD826F4E519D94B7D2C9E234E45F9D3E48 +:10F4C000A18FFD219EF431C92FCCFCE11ACDC8FFDC +:10F4D0007F5462E4FF33F5BE26BBD018A7AAF49888 +:10F4E000E2E1EF4D37F04DC97FEE44379F8AEE25BC +:10F4F0000FC575DE14FCF26DA107DA591D3D77309A +:10F500007E7F348EB553E96487A84C645D54BA9805 +:10F510008BF26B929946650AF350D99FD55199C6E3 +:10F52000783E553A6BA772103B446526EBA2D2CDCC +:10F530005C162CB39946E550E6A1D2C35C14277F34 +:10F540002F21987118E037E37A26EEFD1EBA418725 +:10F5500073EAAC64A17BC04857539840BEB7F9FB2F +:10F56000E9B2FECE0D3ABE9FC4DB6F7DFEBD87F0D3 +:10F570005E30F01BF1BE83BFEFAEBF7BC324EC6FE8 +:10F58000B3507DA7687FAA487F08CFFFE9D18CCE12 +:10F59000BBAC48DF36BA38543F53A83F1A5EEF3F42 +:10F5A0004ADF1E5E1F5DA83F16DE7F49A1FE44F8BC +:10F5B000FB7DC5FABFF2BA8BF0F23D9B4EFA2EFCF2 +:10F5C000EC5246717CC39F3EAAF769C2C3DD8A151F +:10F5D000CF3546D09B1DCF51453AD21C31587A7851 +:10F5E000DE4F30D6198CB7F462FF98E82888FC0902 +:10F5F000F070B8E2DD47F398F889E213F98329C681 +:10F60000B809E03BF95583ABB89DCE58E4F772DEFC +:10F610000BE139D3C3FCBCD9A171A3EDC38CBF8767 +:10F62000849ED721F4BCF7441CB97BDF416BD269BF +:10F6300047888EA3DB8756763A9C5FF6D8F79FAA59 +:10F640006D40D7C1FA1817CABBCE58F636DA69BE74 +:10F65000232A433DE352D7DB5638F50CE78B835C16 +:10F66000C867BAE7157CA6137F053DE78A3ED2BE80 +:10F67000D41C1CDEDCEE4812EB6A9A9C7C752EF9D9 +:10F68000F3B95E9F673B34731AAC337503F7AB264F +:10F69000227D63E8ECE93FB8308ED63AC5C2904F80 +:10F6A000AD917E5E933F6ED3E415AE707FF09A44C9 +:10F6B000BF82F1CBF4402CF743A4307F2CCAD13267 +:10F6C000AD8CF2667CAAAB0CEB55ECDA5CA82F682B +:10F6D00053DD6530EF81B65FAD403FE0A22A3BC508 +:10F6E000316CFAD4B3DCFFC7F33792059E37AF8B8A +:10F6F000D10208C77E4EF2DBE6AD2928437BB7C9AD +:10F70000999C8CB8985CB584FC864D4EED35BCDF79 +:10F71000E17359283F91B9744739E82BDB6FB796ED +:10F72000211FCF78A628510D5BF789E673B1180722 +:10F7300079D465A1F78FAE2A752C71E23D46B017DA +:10F74000A03CE03AAEA3FEBE15DAA0BFF19EDAE31C +:10F75000AD97F5728E89657603DEC66BC67A8CC965 +:10F76000DF6833E905C34A1252E89C47B15178CEAD +:10F77000239FFC8AECDF794E37F9D54B5B14CA8F97 +:10F7800009EED73251DF3CB17118E5BB34B718FD33 +:10F79000D1C10C9689F77DE6B72AA4AFAACD9F37D1 +:10F7A00062BFC1B9EE0138CE60AD6B802B8CFE1EFE +:10F7B000FDE98F6351DE35E38535C223C6E342C2DE +:10F7C0005E95F7CAE7BBCE55A3DEBFA8F55D0FC2B5 +:10F7D0003F49B710CD1CB5F9D3F0FCD74F9A45740B +:10F7E00089F7B4508FE9A18FFE15D619763F614D88 +:10F7F0004A761CCE1BC25F3D11F77BB2B590F4A3D5 +:10F800001D2DA5741FC03CCEDD0DAC1DF5D6350DEC +:10F810008EF648FAEFDD999E4CBCBF7D6AD3A4B545 +:10F820000CCEFFD4FE656978DF7D716B0C8B75F7AC +:10F830006C7F72D3689A6F31DEA3C6795B67DA5149 +:10F840006E4C6B9B6447B8DDDD30FB99F0791E2A66 +:10F85000F5569700FDC5B73E4378E264011FC2F537 +:10F86000DFC7EB99A85F9CCC6111F33997962844C8 +:10F87000B7BF1BEFA1FB29A73222B7BBA984EBE7D7 +:10F88000C11237BFB76E656F2F4D217BD085F47ADB +:10F89000A2A590E277368CBB0FC1EF567CD580F8DD +:10F8A0007FBE6AE1074BE1FD9AE9D79DC172A4BD15 +:10F8B0008EF466F67B95E801F442BA27F69F150EA2 +:10F8C0005753581E21EA8FBAC1AFE161687FD85AF9 +:10F8D000D4801DF8BB6DDF69D2C3115FF530FCA584 +:10F8E0009F51429F17F92169A3E8DE1DFDACB9FACB +:10F8F0003A7F00CAE32D0B1D91CE31FAFC61E3A2E1 +:10F900007E3B99E9B161F383540C905FDBCBE7EB6D +:10F910006E27DE8319AAD3FA845E6E7EDF4D6F5B9D +:10F920008CF4B94D9C8FD4CFA3ADF7077E63BF177E +:10F930003038818644FBB5067AB95C6D5F817115FC +:10F94000F63EE7FF60D7314F84385788CFC2DAFBE5 +:10F950000BF8013CD7A6CC22FB24DA3AECFE437A22 +:10F96000D68890FDF68334E3BA64BB17C4BE62FC4C +:10F970002C604BC43240F73962A03FCAEF2FAA6E09 +:10F98000735D1D812E6469E65BF8E30E8BFF98F9C9 +:10F9900004A2C150A98F58787F3D8CCF25DCCFF5CC +:10F9A000DF935B14D27FD76FE279145FF8A14ECA60 +:10F9B000053F27542DBE11CA8E33ECDEE192175B52 +:10F9C000EEB9DC6D80DBA2F0EF999C79F2276FE352 +:10F9D000FB8F9EFA8907977B57CAA244CEB78E2D1C +:10F9E000C0794E5D61277F0CFE38247E40C3A5FEA2 +:10F9F00018031EAEDFFBE496052877F63A344CC7B1 +:10FA00005BBCC5F83E262D6C5F8CE397CF00A760EA +:10FA1000F64CA0A3A33FFD57BA1F1E87FC13E97144 +:10FA2000550CDD0B33C3795C49F77746086F1784B3 +:10FA3000E250741F44D2D5F10D4DA7541867ED2A3A +:10FA4000BB9BBEA760B2BF8EBA67EA6961F161FB7A +:10FA50002A7E4F9385DB89D9A1FDCB718FFA163AA7 +:10FA6000DCCE9EE3F5C0BB28E3F529D5BF46BE98A2 +:10FA700056EA6163281EBD90F65DBF67D5D137A0F9 +:10FA8000CD3D715EEB987EB8FE21A314BC2F63754B +:10FA9000D3BDC1E6664B2CF2FDD6766BEC50847775 +:10FAA000B385E47C6B7B4ADC50944B4E0BC54F51C5 +:10FAB000AEA861FEFDD16338BC42F2C39318AEFF1D +:10FAC000C4097C3C952BF49FC95CFF519EDE477AAC +:10FAD00047F31A1EA792FA864BE08FAB99C721A372 +:10FAE000E93FC87870DD09C58B5CC8D7D624F2EF32 +:10FAF0006F2C9AACF9F03EE7554E467263305EAA21 +:10FB0000403DCBC9FCD3601ED5C5F51B6F2B237DB3 +:10FB100026D9E9D410D4A96D7E1FAD5BE774E680C9 +:10FB20007F08CFB85C9DE1F856935E6137E90DAA76 +:10FB3000A9AE8D11792B428F6042FF96F1E0848D42 +:10FB4000BDE70149BF6EABF04F80FEE4A37B2325E8 +:10FB5000CC8F78CB74DD9DD23F6407A489EF1EA5BE +:10FB600095B0ED4D61F127457F95FC06D22F29FD1B +:10FB70000FD2CF31A204ECB5C4307FC44B605AAA77 +:10FB8000140F9B8E789205EC80ECC93CA6F0EB1923 +:10FB9000DF524FAFBFB8B8CF432FF3FB41CD9638FC +:10FBA0006D4756CF76378DE3F8167700F6867AEDF7 +:10FBB000F50EBA873345DD4DF7EE371759785E33CA +:10FBC0003BE4427D60E118CE77B34A3D0BC6503C22 +:10FBD000D593857803F0F0D9F0FE9EF0DB66DC91DA +:10FBE0001D87FAF007034E6F42BDDCB7C642FC46E4 +:10FBF000C231ABD1722FA261587C2E602D08C5D9BD +:10FC0000D67BCEF9F0BEF0B5E3B8DF356EE6C9FDC0 +:10FC1000E8075D37D4427EF6BB12748ADB01FD38FB +:10FC2000541EAF7B0DE36D2DEEE464FCEECE534924 +:10FC3000FCBDFC7ED50309FDB787E797948EE3FAF8 +:10FC4000C8034A647DA5EF3885E759ED0540F621E4 +:10FC5000BF16B7C77D5F54E9CEB03AD21EF4FF1786 +:10FC60001FB7A75BF67E51E51B4A7692789F534DEE +:10FC7000F63AFA18E1FD89BD2F55F9A0FE4856E481 +:10FC8000797F2BE67DE475EF60D467837B017FFA93 +:10FC9000443ADF00B394D0B89918970AAE8C991DF6 +:10FCA000E93B3683C6F37D6E8677317D427AECE69A +:10FCB0002AB39EEA277E75BEF6F8414AD306FE5166 +:10FCC0000CF490C422F3CB0BEBAB5A1AEA9D4D2BEC +:10FCD00095B5C83F9A405FC5B860AACB4EFA6A7323 +:10FCE000D28F27E1B99CAF652EBCEFBA03D43EE4B6 +:10FCF0005FE857C57BACD3EA399FF1BAB89F15ECE2 +:10FD000038CF55888F03AC848F527FB55671FE7300 +:10FD1000450CCF47EE4C7292DF34A99EE71FC7FB1C +:10FD2000409FC5FD4DE6F9C33AFC433E24F55B67B1 +:10FD30009ED590476C37E5195B4D79C5FBC718ED2B +:10FD40009984E2A25EF5AA97C0FEC575EE03FE8314 +:10FD50006500EC602C5F06BB1DCB57C06EC7B8C1F9 +:10FD6000AB0DB954BED6A0D1F3371A4AA89C981946 +:10FD7000A4B822F991C97FC3020AF9F1247E7D3A21 +:10FD8000A814EA4F4DE2EFFFF3853B1FF50D82F714 +:10FD900029A2BDEFEA6AC4D7EE3AABAFC6F6356921 +:10FDA000BC5E3DF6C7D5E8FFE99AA27F88F2AD9F19 +:10FDB000C5337F0DB6FD498C16C9BEAF1D2BE47946 +:10FDC00014FB9DE127128CFE9CB3637AF1E73CA003 +:10FDD000F075F4DDF7D2C348177D665A3D88C799A0 +:10FDE000D9463FFFD563395D3C3896F39FCC3780C9 +:10FDF0003E7A81BBA48F68EF9BF6020A44A02B5980 +:10FE00006E4E6013E87E76B57D76A43CA7F3827FC4 +:10FE1000441DDFC9DC312343F4D6E434D35B90E2E4 +:10FE2000BBE7EB6FDB8FF2F2BBD31B23FB3058AD8C +:10FE300093BC0E02BD213F576B39BDA9567E3FB31F +:10FE4000E64DEE1FD981F485F970486FF0EB341F51 +:10FE5000AFA79AE8ADC94C6F4E23BD0591DE60BCDB +:10FE6000241FD72FE2ABDABF577A1B39F6BBD1DBA1 +:10FE7000BF8F0F525E436756DD0084CF66F13DBCF5 +:10FE80004BA5C337C7DAB93C18AE935FA0597CFFC6 +:10FE90001058CC06FCCECAB4418DD66480DF8C9459 +:10FEA0007CFA0EC16D63FB0B3A39E4447F4DE224CA +:10FEB0007DDA58A4AFEBCED0FDC67E164EBFB5633B +:10FEC000BBAA90FE32D674CC9C8674B75225396991 +:10FED000DED78B1338DD35297C5E38B901E171BD81 +:10FEE000B963393EBA5736290ED4C7E7332D278B6D +:10FEF000BE2B43DFBBF997E6FF74E1B82F4EE0DF7E +:10FF0000737137BE97E4E5FEB534B4DFE84A734158 +:10FF10004F7A849F765B7F033D2FC47D44A3E70B1C +:10FF2000F18FE01845C085511EB057DCDF94719108 +:10FF3000A8F46CF2E346F51F0E8FFC5DCAC9E3F925 +:10FF4000BC4DC2FF6BD6F7E4FE0F4FF2FE6C2C8C5B +:10FF5000A3385FE57EE07DCC8DEB9471B3EE3C235E +:10FF6000A91FFA98BF09F56D2BA832FDB9BA81E334 +:10FF700075E71F093D7159A9771D8EBB9DB9F7A380 +:10FF80007C736A3C5FE1F949FA7A82E7B7D4034BA4 +:10FF90004AF57B71DC6878B56C9AFE406FEFD957F3 +:10FFA00030CAA8505C6BD24C2BE70BF58AE003CE2D +:10FFB000B576A86F4E027EE646BD9DEFDB057CC39D +:10FFC0004D7686D18E988ACE48E41BC84708B8FA89 +:10FFD0000CCCAB4C14E387E475F020EAA54180ED2E +:10FFE000BDF02AD1C7E575D39B9CAFD881AF505CDB +:10FFF000BA84DB09F25E507C9E46F697AAF76E3F04 +:020000023000CC +:10000000584DF6FD9EB1C27E28604508B74C8BFB6B +:10001000BE31F0BCF0C12987C7C0E3E26D8BFBA203 +:10002000381DBD7D4D397EEF6BD913A7B6A39F74E4 +:10003000CC7FC430F15D35CA33F83BCA193A97F327 +:10004000FB58B5CF8AFC2A321EAF19CFE59F8CB37F +:10005000F682C7EF131E8B38E725E0B1F302787CF8 +:100060001CF135021E9FF88E78FC09F6BF170F01B0 +:10007000D61D3B4DFFB437BC9D3A55FFBC377E1AA9 +:10008000163FE0F943AC96EC6719BFEC015794AF0B +:1000900039BDF8A5D6ED88457BB6A976C7EBF8DD66 +:1000A000C7A67A6E677726688E12B46FDE55E97B35 +:1000B00056D1FAA3DDED0366B96A3CCF8F3EB0326C +:1000C000263011C6497772799BEED419E68B5B5DB9 +:1000D000419B3701F5350F43BDCD9E6261BE307F38 +:1000E000CC48DB2192CB9D20C7913E803E39BD2577 +:1000F000F171A47C9EB8F23E8CE4B0F15DC0FBC20D +:10010000E8E4F5BD25E4874B287E6E05F653ABED9C +:100110006EC4EF897F05B91936CF24D044C2EB579E +:10012000390618C699E2CA32BC9F96F603C3FBABE8 +:10013000015FEC14C7E6F702A55E33DD9D6F68979B +:1001400024E21C3FCC1D6318CFAA7E75EF68A47F04 +:10015000A1478C837FF45D5E93BE60D627CCFAC343 +:10016000E82B8DF75D4658451E9A95E7476C660E5D +:10017000FA2E05F041FAEE414D284F80E864843DA7 +:10018000B8E36EF4ABCC71683E78D6BCF7EAB4F94C +:100190004521FFD9E67AEEF76BDAE3D88EF4B05555 +:1001A000D0A5A4AFBC84E37318C9753B43796CA692 +:1001B0005799EF24FD05D29FA0D4723FC3D90959A6 +:1001C0003CEF48F09FCD55DCFE7D4809C42A4338FA +:1001D0005DBA9343DFA74B638A6F3AA76F3D59948B +:1001E000AAC8479579AF380EDAD9697C3EF61ACF9E +:1001F0009B6CFC67ECEF62BE41C29F91911CF25375 +:10020000607EC2CDBC9F6FBAE83758E45BF6E1EB85 +:100210000F4C11F38D8052ADD3857FDA4B650CC640 +:10022000C3A1CC56B438F47F0C513D14684914F185 +:10023000F574114F8F57029C797C4B3E3212D828AF +:10024000E625B064FE7D91D25F38994AF461DF8182 +:10025000F2E8AE63DA3BC5F0BC39E1C76F4D84E725 +:100260002DEFAA1AFA49EFCAF07D80746D0564F08B +:10027000915FCB331FCF4DAD70B8A6413FD5B7BD11 +:1002800011E3BB23EDFEFD749EAB6388DE83D00FCC +:10029000F1616B02D029E22B7ABA4685F281641CA7 +:1002A00023384673A01C0D623BEE6F36F83F23E403 +:1002B0009B90BFD42AEACDCE1DA4BFAF4DB1E317AA +:1002C0005331BF27B31EF1B25F1CBF7FCB78DC6018 +:1002D00030FE12966F6F7745F66B82BE4670083619 +:1002E0002E4DEB4DEF8A1A47715A02F6C48B8FA33D +:1002F000ACB9F13A7F206C9D72DF6B9D3B9405ECAD +:1003000052E667C6384A2DD363474488A304FD0AE2 +:10031000AE73702D8FB30C16FEFA6F1B47A99CC0ED +:10032000F5C74B8DA3C8FD5E237E9F01882DEE1976 +:10033000533C81CECB125A5F18FC1E277E44B82155 +:100340005004EA3F12F5B77677FCE949F8F5CD5D40 +:100350002FEFC652EA7133C5FB6B877DB90F73B7B8 +:1003600066AE5B21E258C6F8C33560D585FBF9F16E +:100370007B01E1F599A6F5945A8D7182C94E63FB14 +:10038000A929C6F76583627A9C1BFAE569BF4ACF43 +:10039000FDDE157F0FE3DF9B0A3B07F5C27507E61D +:1003A000CD61DCC7DD134FC2E3009EDF58597211E7 +:1003B000E28B85F4D2ADBEA5F75702FDAC0539CA74 +:1003C00079B1DB407FA1B847998EF824FDFDD1E8D3 +:1003D000E9B8339BFCFF83EBF7B74FEECBBAE300F2 +:1003E000F7C4791DE3F07B41CE730AEA2183EB5F0A +:1003F000A1F7D7CD29EE158F72EA0FB44F0EFB8E01 +:10040000608ED56341FB39A7FE557A1E559FEFC913 +:1004100047286F2D47E085CC0BDC8A798100F79C5B +:100420005AF17DE0B6DEF3DFA43C6C0ECBEFA364A3 +:1004300006B7C2C2C79772AF873F9D71BFAF9CAF6F +:100440003B2FD0346FB7FC7371F9F7FC24AF36AE95 +:1004500038EC5E86B8C701FB8E98073A5AF8B37B32 +:10046000C963E37667C56B1FE0F8976C7746197729 +:10047000626630E23DA9A9C26FD5191BCC40BF41CD +:100480006794BF9BF0D094A93F1CD78BBE8B79B3E8 +:1004900008CB68EBFCB679B37522DE24E3AD327F7E +:1004A00056E6C55E287FF6BBFAE1570A7F40E93879 +:1004B00016310E615EEF6DC23F9E55EA598178118B +:1004C0002DFE20DB7F30C01ED12F7E6442E4EF0E74 +:1004D000C8FC50586F4AB81D24FBC9BC7CF3786037 +:1004E00017AD1917E60FF436E690BF2FCCDE92F960 +:1004F000B0441F9B851FA29B0ECC7AA1888798F5DC +:1005000042191F51AAB87F02E8A30DE745BD0BF3BE +:10051000D2A59D27F34965DE28E685523CEA5BEAD1 +:1005200055DFBB3DD53885F2BA9A5CA5AF7D177B08 +:10053000EADF2718ED29AF93FB1DBC684F0DEF696B +:100540004F15957A5F447899EDAAA33FFB84F26337 +:10055000C10EDD37EEFBE01326FFD4DC311CBFA556 +:100560009C96FEB4FD432D06BFEB5475D57ECA178D +:10057000AFE5FE9674BD9DEC34BBD3EE467F8B7524 +:1005800032A7235B1EF3EB3CCE4BFE15995796EC3E +:100590005C12F1BEA9B41383D24EF4F1FBA99D6F96 +:1005A000F2B86D3CFA5BB06119976BD2DF624B1108 +:1005B000FE16533E76BCC9BF62F6B79C1E27FCB63A +:1005C000C2DFF288E2BE1B49FD575BA6FC0E41F17B +:1005D0006F0F2F8E4753FF79FF9A1F0A7FCB834EF1 +:1005E00058DFDE0F8CFE1673FC2B42DC8B9C57838E +:1005F000C6FF8EE26E12BE926EA53F2BBD9E7FBFE0 +:1006000069AABA5B41FEB2D9C9E1ABA23F2B25E48E +:10061000CF529EFE53B75F8AEEE3F68893D7BD8E26 +:10062000EBB402C3591FC9BF25E06A8E4725D68B9C +:100630007BC0DF933F2B79BC11BE050F16DE87DF31 +:10064000352EDA567E18CB51DB6FEB3B17CA92275B +:10065000EE2BC7F22FAF07B350EF34FBB114047E7B +:10066000714FF89AE128F1D45B2BF1D46927BAAD28 +:10067000E27034C32955E7789A03780A2A4237FE94 +:10068000752671FA4C9FACBD86FEB5C17956160928 +:100690008FADF5FC7B59128E5B051C936B97909F79 +:1006A000D08CA783DB2E0D3FC79AE0F7EC96C2BB38 +:1006B000116ECF3D5CFE3B2C7FEDBF2D1EE1B6E7FA +:1006C000F1FB7E28E03780BEA76B82DF03F811E9DB +:1006D0007E3DE13751E3F6F5E7A5DEB2F100DFAB91 +:1006E0008143A03F64474B81C3180732F2D3D4EF54 +:1006F000C93F15ECE6A7ECED9C4BE0A71F9BFC5314 +:10070000A93E4E37A9BE63449FE9409FB1E8AFAA16 +:10071000E57A24887D7FBC823637E7AF52AE21CBA5 +:10072000B180F0D9EAE271E7087ECA007DEFD7C454 +:1007300087D181138E772057EB107E52DE6DADE5A9 +:1007400071B4DBA678568CEF178AAB3D3F49BF6D7D +:100750003CDD5FF8D6FEC77FC6FED2FF08784AFBB5 +:100760005701DFF1FBE657813C41FBDF5A1BB4A187 +:100770005CA9A9BF55F142D9E74A4E3FA9695E86F7 +:1007800071FE9EFEBA6002EAED138776E3C37A9C9F +:1007900047E2C3C895E7EF433F57347C488F92AF99 +:1007A00074617C2835C8D7CDDDF850B7EEB2948B94 +:1007B000C787B809FCFB11DDF820E83FB536F82003 +:1007C000D2AF55E083D5057C0CE0A1221EE485E282 +:1007D0009E921E8222FFC00C9FA06F48943C8415FD +:1007E0004A492FEBBBE8FC03110F6D12F1506F3D2E +:1007F000CF97ED5C1933D5987FA0D1BAA739EB9488 +:10080000F03CFE0879B22FE3F9C938A78C6B7E5E05 +:10081000EA79059F4FCCE5E71C8C1E670AE0FD5680 +:10082000403F9709CFDF223C97F70F841E77DB14F8 +:10083000FD6D1C7784DD4F79CEA0EF1DC6765BF78A +:100840003EC9BFB72BFC90322FEF3BFBCD12ED7EA4 +:10085000BC2F29FD669B13EC3BF0BCE7B3E014FA18 +:10086000CE2FC629D0EFB43186F21A172A6078232A +:100870005FBCCAFBD1788AEB79281FD75BE170A1F6 +:100880009EDF9C34350DF946CD5A95E47A34FB460B +:10089000D25B0DF01BA2B77ACE6F5201BF08DF7C8E +:1008A0000AF19B74E0379CFFE80CF53A2BD29DB31C +:1008B00027BFD9DC0BFC2F92EF7C83708FC077941D +:1008C00009C506BE6399F01DF8CE4FC6336E1F8A68 +:1008D000FD633C80F68FF415BE7FB33EDBBD6F2316 +:1008E0007D49BAFB5F4067232744A6B3FC09DF8D2F +:1008F000CEC662FF087476E504239DE913FE67D235 +:100900005905E1DB05E8ECA3F14CD8B7D71AF48A16 +:10091000CBD5F6733938FFFFE7FCED8357723BFE0A +:1009200042F9DBF87331FE53733EF73FFCA9FF6BCE +:10093000FDA9CF4EF81EFCA9AE716EC23FB35FF5A4 +:1009400093D1FABE09BDC495259FB64A3E0DFC1849 +:10095000796F0DF033E4CFA9555D9F3ECFED4D2D5E +:10096000DE4DFE86D771BC74C1AFCD7C19F4CE3795 +:1009700026FC1DFD0D7F2FBFE14AE167BDD07DFB49 +:100980009502CED1EEDD3709FBBE09C6C07B7A5B8E +:1009900057DAFDCDB0608FD0AB47D45E773512D932 +:1009A0003BCBEC71C15EEC26F977245A1BBC2F9E21 +:1009B000CC09DF1F8B28B7BAF767D293C3ED26F7B0 +:1009C00025D84D33261AF5646B2DB773AD20EF286B +:1009D000AEAF9704905FA7FB94764C0DF6A6D42992 +:1009E0002807536B3D940F7FA9717D331E458BF310 +:1009F0007FDF717D73DEC0FF94387FD14461CF9B70 +:100A0000E2FCD2FF6A8ECB8FB0B796917CADB6E098 +:100A10005FC060CD7B3FDE71379EF71C07DDD330B2 +:100A2000E703448BDB8F48B607E3B3A3C7EFA5BF4B +:100A3000E0115BDDEB68873FD268A1F335E70DE499 +:100A400025F0FCF1B313766DA3FC1FA90F57093EE7 +:100A500053AFD8E9BB8E557EE2335E7D5723C693F4 +:100A6000539DAC1DF5ACB8896EC23F354D273E6332 +:100A7000ADF2125EC9F8444D26BF37172BF04B1D5F +:100A80005AF7168E9F7448D530BEBD119B02CF48D1 +:100A90004059897AC4180BE545B42975E4F76855BF +:100AA000DCF4F73F92F25CA41F3D95A4FD7E36AEC8 +:100AB000BF1FFF3B2507A62F49433EB8B6B1310DF6 +:100AC000EF27DE3491F3877BA79FAEA6387A2EE816 +:100AD0007F0A9586BF672BCB1DBA22FEDE929FF25E +:100AE0001161DD5BA8DF503BF9D954FD81DB900F2C +:100AF000A8974D25BC6E555C7316E079E5D8498FF3 +:100B000069CE19357B11EC6B5D3F4F59169E6BD248 +:100B100050DA677352FF44D447D70DC8A6F95B1467 +:100B20006F5916F61B6021BA56457C7E5DCE92D772 +:100B3000F0EF8034A55B18DE3B68CB39DD82EDDA5F +:100B4000C6F03F82635EAFEA32DE93C20F1F21FF21 +:100B500056D3785C5C157171D514572ED51599FF55 +:100B600048718758C1B76A7256CFA6EF2738ED2E65 +:100B700044B2A6846025E1C74A1BC3381DB3B61A28 +:100B8000F4B4BB1B8CDF7F71E619D7D3D27D3F2134 +:100B9000CB8B7C86FE062CDD5F48F2227E20BFE5F3 +:100BA000497FF1BC1E2BEA019BD717E17CFE51FE69 +:100BB000A3FC47192AFF2F0D22483C0080000000AB +:100BC0001F8B080000000000000BC55B0D701CF5BA +:100BD000757F7BBBB777279D4E7BD2C93E816C5614 +:100BE000B6446410F25AB68494D8684FDF322EBDF2 +:100BF000387C88C476CED8B8CE34932A4E49EC845B +:100C00005667EB64C95FB2A414E44C3AD3B34932DB +:100C10006DF08042661AF33967700821D028811080 +:100C200032930461885B529A310127A2434BDF7BE8 +:100C3000FF5DDDEDEAE4AFB81331CCDFFFDDFFFE91 +:100C40003FDEE7EFBDF73F00F0C00200D90F003AEA +:100C5000C0A6224F122200E7AA200D95D8F74E9782 +:100C60006941800FE9AF25DB1EE807C8F8B2FD60D7 +:100C7000AD0A660DF0DF87A271CD3B6E5AF3C29FBD +:100C800073DEE16AB5371D9C3BAF3DAED594001ACB +:100C9000F2AE03D225AD73E6673A8E4FFE4C866AFC +:100CA0007DEE7AEEEFEDEF3615AD2F86DAFFBFF170 +:100CB000F3D175A9E90128137D68C47353BB44744B +:100CC00075A48302820E039D8DE90CFE73424A0CCB +:100CD00057D2F9C21EE39B30970E762B6B73F897B1 +:100CE0009D5F16D347ECF9710BF2CE801908D12B1A +:100CF000FC0E69AFE1B63F449628110F3F076BBE6B +:100D000028C0B31FE2FE8E67F905DA82ECBCF2065A +:100D100095C72F57FB5E6C5885CF5E918D6FEAD9D2 +:100D200079793F95C00B80FD5D65F6BD62ADFB91A5 +:100D3000232A64ECF1F8FF0933CC749AD8783F2465 +:100D400090BE3FDFF089E2441E39B0DB6569E7F70A +:100D50006FE09CC07483F437F1DFA95F8C4ABCF864 +:100D600009F13CB5424BEFC7E7FBA5F4FEEB68DCAD +:100D7000DD82BE361F0A2D3EE05FB40AE9E8B5F811 +:100D8000E4759F0BFF94054C278B38397C58C27350 +:100D900054D1B907ECF974230348A703CBEB56EC05 +:100DA000D7E9FCA3FFF26DDCC791E37BDEFA36BE28 +:100DB0000ED4D68D34E17E0A0C8F21933C7FEAC499 +:100DC0000964170CD5DE334AD36E1D954C0DDFFB3D +:100DD000B5E03199CEE8974C9A4F39BC90CF13DDEE +:100DE000EA948309C958504EE71B9380F85268383B +:100DF000DFFBF49CF3E0FF4788CF2C9F39CF916E47 +:100E000048BDDEC9DAB9747FC5926705C727ED7999 +:100E1000912EE35EFD16A2F3F83E199238E5F82E06 +:100E2000548AAB007E6B4E7E7A3732FD9E412FF3A3 +:100E30006122A6A6251C3F51A4DDDE4BFD328F7139 +:100E40008C898AFFE3B946975DCBE7B2D7FB6C8B01 +:100E5000CEEB8DC51694933EE2B8F2F80D73E5CF54 +:100E6000BDFF4B95BFED668925EFA340F3C3E42D8D +:100E70001ED227BF35E63A79B27E09ADF7731984E1 +:100E8000DCF441BC682E7D06C91E7C242B27AA25D4 +:100E9000477B23EB7F4CD3CF27CF6A7ACAACACA376 +:100EA00075A08FE8BE2CEADC9F3DEE7316BF7C690F +:100EB000C87843D4664CA8A376CA94B03DB7E10B7A +:100EC000DA5A7DFE757C90336F25CD077C6E2F241A +:100ED0009858C4573387AF7B0AEBEE24BE0CDEACC8 +:100EE00002CB9F9BCE17E8AB4AE6A4142279F80800 +:100EF000CB4712E5A31AE7F1469D72187F72154C95 +:100F000007059F92FCBCDB243E255ABCB376C89FE4 +:100F1000632F41DFFD1B19E7FB6AB7AAEFC77D7E90 +:100F200035BEEDBEDB48CF5F900D89DFEB6C0FEF78 +:100F3000B1D680D109968762CBEFEC3C71EF6BCFD5 +:100F4000138FBAD5D7896EA4C7B37411F6D9F43705 +:100F500066D73BDC747A7829D221359C7FFEBB4A68 +:100F6000F5CF11FD6C3ACF37EFACFDDE7972B27D73 +:100F700065B63F529008C4F09C2341038D00BD3FED +:100F8000C5EF6115CA65F9FCFC448AB23CBC46FF5A +:100F9000C4713DEDA616C3BE7C02B7BE1CED6291C6 +:100FA0007ECB7A7CD511797D23D17F6BD0A3C939D3 +:100FB000FA3570D00B99201102D745B95B07D31BC6 +:100FC000D7E338A8F2B29CCB9115FC7C4B515CF175 +:100FD000607B6D6C09AF677FDF03FFA0ECC0E7CBE0 +:100FE000BDDA2B2427A988443BC2E74840DCFA5AE3 +:100FF00005CC10B65D7ACC4F7EADFB095A08A02512 +:101000003C1E21BF54F7D8918A04E975D29CAA41AD +:10101000FE842D765DEF9B8AB7E17C032FCAC61E46 +:10102000EC8783DBD601CA91F47090EDC400DA79C5 +:101030001FF25D0976BE45CFD79C0568CF91A79674 +:10104000193FB4E7D8BD18CE9CDB6FF3973BC6774A +:1010500068958EF732984606E9D4155DE61857D4A0 +:10106000B04AA3FDF6E82B1CCF6FAE69767C0FED7E +:10107000CAE969ECAFC6FF88EF32883EBFAF249C57 +:1010800080FD9CEF15C8E9E3FBB5B1A2C819724A0F +:1010900037C28DA447C8976307C8FEF4FAD96F0D0D +:1010A00078E184540CA4FA49A827629BECEF254B05 +:1010B0005E93B14AE693147CF67D96C327A63D84E1 +:1010C000B3E031A827FBFA8F9A7ED28343AEA629DC +:1010D000F1FB280ABA8E7C4218960CD4F37373691C +:1010E00009F93929D983FD45382E2A44119EA37167 +:1010F0007ED8FD15310E16D1380D9215D8D70C2893 +:1011000020BE56E03C9F2DE1EF923DD677D788EF89 +:1011100092C52562FEBA7AF6A3990E6C8F82013EC3 +:10112000B63F71044D6445FAB8BD867685CF1F0081 +:10113000A39EFAD530CD760AD92F517F214C6AC2B1 +:10114000C86784DD9E56C267FCC2EEE7D397ACDE6B +:101150002870C6E6070EBEBDC5FC12E9CDED773698 +:101160009C1777283B9F71E8ED23315DF8C39D5DA7 +:10117000AC27CACE67F9FD4BB1F81E9A8F48EFAF86 +:101180009F4BEF3A350364BF523130923845EAD174 +:10119000B5D1CDC8DFE4A37EA31AAE1C3F2E950FB8 +:1011A00069D00A88AE72DFE5F201D8CF074FF88F19 +:1011B000EE676134D94FFE097CF9F6E5F0C5CD0F35 +:1011C000B8B714A0F9C276F4EB5226202D657A98B0 +:1011D000D1FA2CFDB19F5C66D1ABC4E2872CDA8CCE +:1011E0006C3D574AE6E70BCD575A92E5CF85F8128A +:1011F0008DE3FBFA2C7FE43E938967FB691F9C65B6 +:101200007CBB4432985F4BE5B887FA8552C6023DF5 +:1012100069F69B21D0983F57411FB711EFF466C67E +:10122000C33B7121C2B31FA097CD89C752C1567F5E +:1012300025D9D71AC5F060BFB6C8134F231DAF56C6 +:101240002043E72B572049F61C9101CF9F7A14BD0C +:1012500015FA9914BA690F7DB7CB9F4E49D9F5EBB2 +:101260002CBBFDE3A26F69D3B5593A9F26FBB55C51 +:10127000D0C3C3F6673243DF47BBC118D0E7DA33C8 +:101280001C97942D3B45ED267AD1CC744B86B02F1C +:101290000DFFE07DC219349F82FDEFC512EF923F32 +:1012A000259C1E2C61BB345D48C07A2E2E30095718 +:1012B0006CB6D6E9BD495F1CC77D6E1EF6BD4EF308 +:1012C00041CAE7C405EEEF750972BFB7BF9B952B06 +:1012D000F7F797A907B0B3ECA27040ECE1D5C5D3FE +:1012E0007970FB2CCE243D29CDFD4EF0498D24187C +:1012F00077A8A42FA5179EC7EBC22FF63C5E145CFF +:101300009AC76BE117DB4F6D83B35E65A9B54FA438 +:10131000D716B0FF224CCF4D16FD3E4DFE2A44F4A9 +:10132000C44005CFBD15E22AC9ED5F2184261CBF4C +:1013300064DFD610E30568D7883E52E663F287D7AC +:101340005F021D2D3A6DCABCE5D5C92EED2C823742 +:1013500072E337EBFDBB1B3E21E274BFBFCA9F1394 +:101360001F169EF8A09F8CFA9EC2BF7FB105B73EA4 +:10137000F8926CC895F45EE0E60008FF5D487A8A52 +:10138000FB2E7CE2CCFFD0F84217AEA69921675E17 +:101390004FE141C6B3852155679CED92331B47C38E +:1013A000070207072DEAE5CC2B115EB6E31E9E5718 +:1013B0009ABBEE0D163EC757B10F2F02CFBB713A45 +:1013C000CCE273F13E1854859E609C9971C4C17A39 +:1013D0005E3DB3F76D7F57A6C62B8DDA3CDF5B7C95 +:1013E000A8A5401CEDC2C20A48EFC6FD0E0FEF884B +:1013F00015627FAC0C748C3061A8F38B12E18DD632 +:101400008810A57093C085B404D8713CFE85FF4355 +:10141000DF5F83EFB755040DDC192C7C1B7132CED6 +:10142000737785DF30F1410AC4FB649347C4934965 +:101430007899F0E8568B3FDE2704CE64DEA01E1EAE +:101440006C15F86AEB89CFAE23FE8E94DC6A64706B +:10145000DC56B44FA584C746BD8CE710D73970BFA2 +:10146000AF290707E2FF771FF13AFA5E174E3CD02B +:101470008A3810E5DBC681F7B702EB19ED8BFCC9A2 +:10148000955A078211B6A73728539E7CF9379B1FC0 +:1014900036FE7EB24CD0D9FB9EA00B06CC3BE8B901 +:1014A000EF3D118FA1010F362C20EF2FE8E76B40A5 +:1014B000FAD0D3F7843FC02F79DF26FE47FB76E3CF +:1014C000619F0B0FBBF76BF3E1619B3E8DD048F43E +:1014D000417CCE38C13E8FFB1C4F607CDE8E42F1DA +:1014E00054BF9FDB4CBFC6EDD3FD516E4FF5EBD023 +:1014F0008E00ECD9FE1A6E9FEB37F8F9F3FD4DDC48 +:10150000DA74984B1F91D7BCC6DAB3523B15273F0C +:101510007A55BB875561EC5E0FD3ED1CCA27295F56 +:10152000C8A0DC1B8EEFF6A429A4B7E39F8596BC68 +:101530005EEF3B7BD287E347CAC1D883DF2F6CDAEB +:10154000C672B6E6AC27AB2740714E81234F10839D +:101550005247BFCD7FB5637C87B6D4F1BE2436CD6C +:1015600076AA2B7ABD639CCDE77FA2380BF737D6DE +:101570007E5A23BAF6E82B1DE3947B91FF7514FF86 +:101580007CCC312FC8EB0CB2D3251B9C721872F1A6 +:1015900055DD7EFE38C8E6F3DBADCE78683EFEBA98 +:1015A000E5D5A66BC92C5D455C99A2B812E95AA293 +:1015B00009BADAE71DB1CE6BAFAB3489F35DE9F858 +:1015C0003244F16565BEF8F24D8BCE17882FBB9D76 +:1015D000F1A59BAE178A2F17B439EDCAC5D273D3C4 +:1015E0006291772B7941E6B845EEEE633F583A2594 +:1015F0001B5D64122D5C56443600C76D6A50D3845F +:1016000033C7603A4AFEFCB0845445792BAD35CAE5 +:10161000C9CE3C14365EE925DCD823F280CFC46EF7 +:101620008F12EE18DC7D348ACE0A9ADB3C6CEF46D2 +:101630006367387FA1E8C0F90B6CCD741E7C628FA4 +:10164000B7F38D8737AA6909C71FB6F28D877B6606 +:10165000F38D5CDF986810F9C68FB6E9569E29199C +:10166000A578E5AB1B1BCBD95929D8BF81861BAC0C +:1016700027FB035A88E2E8D4468F46E79257DDFFFE +:1016800005928F4352DFBE2A8ADFCA3C9C774D8584 +:101690001BCB37E3387913C218EA6F6C7C956CF674 +:1016A0004499BEAF8ABE0F5731FD0657DFEEA775CE +:1016B00046C20B7A283F32D2E1611EC98433423CD4 +:1016C0004FCDF9E21E771D40268B4BF15BC4935141 +:1016D000C95F11FEC8C9FBDBFCDF1F56393FBBA544 +:1016E000EDC1A3C92A7ECCF66BA15D97D9D8CA7982 +:1016F000E6738427A4F9EB327BAD7CE7ACDF893A53 +:10170000F793671DC605765D82FE743B4F8B7FA9FC +:101710005B3AD3E447C721DE4DF633193C7F1D44C5 +:10172000099EBF0E325FDD63579BC8A37E99F82EDA +:10173000EA338E7A89D26DD545ACF8F530E5C349E8 +:101740001E5C75127B1F03D67CA9593972D54D5684 +:10175000ABD67C06E4CB5FFFA9F593FBDB44BDE68B +:1017600052EB26DF6D03B15F2BDFEDB5F87F9D3CBB +:10177000B983E4F1CF9DEFFE6EDB95CD77CFAD134E +:10178000A5595FE0C4D93758AF972DB0F0CBF9EB2E +:1017900040FB09E823FFC657202EA5FA87D54FDE68 +:1017A00020E675D78502561EE5876D4B45BC45F68C +:1017B0008498AB188B89AE41E53B490DCF51101C85 +:1017C0008330B6BEC8E624B52D8B75AE0F8D2FF3D2 +:1017D000B0BF1A2F4A1C1DA4FD2F0BE6D58B572D29 +:1017E000FB376CD56F48803DA46F92AD1C90F02004 +:1017F0009F2640F0F9EDB6308F57B4D1A6BB506E9E +:10180000DE247928E3F3E4ADFF9C6913F59F9CF98E +:10181000BF41729AB226A77936E33CFF65C923908F +:10182000E35840C18E58CFAF8F36112EF85D9B26FE +:10183000DE2B2B0CD287F170FEF57E679D072815F5 +:10184000D398C5470B378879C02FBE3F2C9DED3DFF +:10185000BD8AF9CAFA44FBA0F7EEFA977BFE408DE9 +:1018600033BE512B9CE33F983D87332E3A344F7D56 +:101870006C51BB90D796C542CE483EF6E4910FB767 +:10188000BEAB94F7A478AA3D6CAD27EC4E50996A94 +:10189000A57827580B06D71495937CDEF893552727 +:1018A000A657919D0F191407297E3495F5D938D183 +:1018B0007DEE0BC5798A02496FFDDC780FE7358B29 +:1018C000EB859F49E6CC774DBB901339371EACA40E +:1018D0007044BF85EB785407A4FE2E5F6F3E3F5DDA +:1018E000DD76FEBACE9138C61114A43E7C70DF16A8 +:1018F000ECBFAB79341F8FD1F3D67534AB3F5BD7D8 +:10190000895F5C5D67B4BDA4A7EA52EA3AF3CC3BB9 +:10191000EB8FE7D675DADBF19C6341515F99ADEB54 +:10192000DC1AB9A87C0E587EB9C4B2CB453D561C12 +:10193000B153E238E2E9867F3FB09CE4ACC1CB72A0 +:1019400000072720574FD66DD0BF564A7EE6551F59 +:10195000540BBB66D27C765C6CD34FB5E66F7DF0E2 +:101960000585C68F977B1A793EC8F83C5CEC4EAA79 +:10197000562B53BB5CCDC8C5346F095875F48C44E5 +:10198000CF6348ACDCF86064E6A76DC59427098294 +:1019900041266824A6ED2EA67F501588F04EA59E00 +:1019A000267BDBE62F74D8FF911E55D8D76A715F6E +:1019B00066FCA4FEB5AD387E68678071D3A10A8F3E +:1019C000D0AFA4C4F5E40ECD19F78C4F2E1178ECEE +:1019D000A0D7A07B22C727C5F82DB1C6B4CCB8DBF1 +:1019E0001917F5E8CEB8684B79FD2B841761D0CB79 +:1019F000F978CDC2B537D738E3A4A2CABEE708A7A5 +:101A00006C1A1478786FB464C116B47FBF6AD71D9E +:101A100071E2E6C1BBB96E34A802D7534736AAAC0F +:101A20001F23DED78F6C61DC58C0749CD8A8962722 +:101A300072F4A5B4C367DD8B10F803E1656232CFA1 +:101A4000FBD20E617750B0D98FDBF2F2179F117481 +:101A50000E55405A271CD7B3234371E578059E09DC +:101A6000DF0F46AB7A4ED2FA2FCB40E774CB6165DD +:101A70004735EBE9AC3F6DF238E8E4F5C5FB687E2D +:101A8000B81974B26BEDDDD8A73CC00615283FE04D +:101A90008BFE2D9FB704FB01ECFBBB47930AF6FDC1 +:101AA000558995848B9FD975C7702C42FE4EE8B737 +:101AB0006FC3B6F82768FC2A2F04687FA04B51DA61 +:101AC0005F52DC6770EBC3DED4F7DB894F7B0D8997 +:101AD00059B4A967FD76BEB7142960DC34EA8D6F6E +:101AE000667B749B5F4BB20F9CE638C2FB151F9060 +:101AF000DC4DECFA4D19E1EF1FB58BBA664077C6A5 +:101B0000D77E1865BFBDDA9CDA40DFAD6E52A9E220 +:101B1000014F379F61BE4D34F80C1FEE63A259622E +:101B20003AFFA1C19BA6759E52A7645AF7A93FE050 +:101B3000DA95F9F43BBF5ED97AE41E3FD2B4DE4FAA +:101B400072B117A66E25FA2467449ECA3D2EDE2187 +:101B5000FCD5DED46D350AE7B354AEB72B670DB3B1 +:101B600018670FCFC4FF9972AFC97645C449E59E87 +:101B7000A484F30DF5887B194345896192E721948C +:101B80007B8E9322E23ED27879C4D89FB3DE78F37D +:101B9000ED3564CF5E6C0830BE1F38F5377711BE67 +:101BA0006F95DFFEEEC3145755A8CCCF216FDFAB86 +:101BB0001407251B02BCDF538B54F0933D88DCF5E2 +:101BC00000C5D9707C03E4CAEB44B7D0D3890AA11D +:101BD000F7D2C31B380E189764A6B359764C223C33 +:101BE000E6EBB6F34E22CF14B3CCD9C48647380FF8 +:101BF00075558FC8A3C6BAAD7C931C4CB25CDE1879 +:101C00007880F4DF54BC8EF878CD5967BC7C952B76 +:101C10005E76E7A3FEB7DDCA475879275B2E43D629 +:101C2000988926CB4EAFF2A5851CF6956BB573F55A +:101C3000FBDF2CFC3CD5EFE77B643FEDD7B81F32D0 +:101C4000DFD95D8AF3BCDC1FE5E77FB9FAA894FB16 +:101C5000DDC8AADBFC3ADB93E928CDEBB6236EB9ED +:101C6000D8DF5EE0F027F63E8B9A5BC5FDBBB36C18 +:101C700091614D70BA8D7D234C0573F17EA65FDCBA +:101C8000737BDADAE729DAA78FF264627FCFF5EBAC +:101C9000DC3EDF5FC3EDC60E10F500DB3E5C83F675 +:101CA00001E9D05E21FA640F88FF2591BB384FE629 +:101CB0008B2A1AE9BBBF623423E5D88789A2BE5FAD +:101CC000DC4D76BF2CC8F2E83ED79A0E4FDE736D1E +:101CD0006ADEC176E71CAE43F4473BB39DED10DAF4 +:101CE000055E77837A27EFC344BBC476A1EF6B7799 +:101CF000B05DF002C9B9DB0E9424857E277491BFD4 +:101D0000B3EF09CDDA055C278DEB3C8D769DFA4368 +:101D10006807689DA1E6D7FF9AD6FDC3FB057C2F17 +:101D20006A62E32B6C175E3C8736FB0ADA055B0FB1 +:101D30005F3B153B961BCF67F9BCFE8E13821E1AC4 +:101D400008BAF6C6F3C48997CA67302F0EC7A495A0 +:101D5000E93B45DD51653ACC5B774C7A0C4A0B0C7C +:101D60004C2ADD56DD11A8EE68D71F73EA8E05CE2A +:101D7000BAA39A4E31BE495B75C7DBD78ABAA35A5C +:101D8000301DCCEEC3AE370ED2A3F26C7DFEAE8E0C +:101D9000C4AE8E866C9D5197441DFCA598F9657A5A +:101DA0000E9112F6FFEE3AA55D8F4478272572EA70 +:101DB0009B75F8DC5F92AD7FB9EB99F6BD8C3A75F7 +:101DC000FAD801A4CBC09D7EC60FF6FE061EFDE824 +:101DD000AB8948F63E805DEFB4EB9976DD13F73DB5 +:101DE00096BB6F7802D8EEC063FEA3E4DFDCFBFD98 +:101DF0005E2C717F47599E7D5F647D711D58F32372 +:101E0000EE227D7ECDA2A33DEE414B1F97AB22BFBC +:101E10000D2195E39DD607832013CE2E528F915E20 +:101E20006C86E90EA2EF4058E0BCD4212FDBC9E359 +:101E30001D3AF3AF4C35F93E44D99703C66E9C2644 +:101E400075520B51FEA9A7DD3CDEC1FB18BD753DE7 +:101E5000ED03713BD9BB5F57DF17E17A3FDD7B2A8A +:101E6000A6F8CF584C7990173AF2DF576A597C762A +:101E70003DAF5BE4018ACF5201E339BE57FCA4C2F7 +:101E8000F3F5E014663DDF5F6A574B681E713F75DE +:101E900020789AF9D552ED5BC179BDA2FC71E0B30F +:101EA0001D226E5D8B73A938CF675A13DFA77D5350 +:101EB000AE34CA722CE2BB17C84E0AFB75AFA7310D +:101EC0009B072B96132FD078382E29E41F7D96DCA4 +:101ED000D871E23BADE68BC477E48749EBDBF78052 +:101EE000ECF55FB2F890EC307F4AE35EB7D6A9D349 +:101EF0009231D2C3BA04CA83C4FAE3AAC30BB9703D +:101F0000CBAB2D6FB375784B0E254DD46B51AE5EB8 +:101F1000E7FD3EA59FF448546F4F1C3D40DF5E66D1 +:101F2000BDFBEA36F32DDA77716BFC3F69DE5FEFBC +:101F3000BA83EF055FEC3D8E96C57D51AAE30F0590 +:101F4000046E7E286638ECDDA24EC19F459D022FAF +:101F50005D8F3233C5F74B0DBEF70DB09D71B46D7B +:101F60009F46FB138FBF599DFD3ED50F93540F9A8B +:101F70006F1FDE7D3B38AF3B50D1EA27FB83F6ADC8 +:101F800098FA43156634771FA92221E7C945226FC5 +:101F900041F9B464CE7DF2924E99CFD35601199295 +:101FA0001D5F50D4DD7CA8B83AFA1F9FD9C4F78BC7 +:101FB000F1F924A518AEEAD4455C1E31C0A478B36B +:101FC000220EA4DF3E2DFB3DD551DB2AFAF8BEE5FB +:101FD0007CF3C851FBFB047F7F53A7C6F3AA118F84 +:101FE000230F7021BAB9E9324874AB9E9F6EEA455F +:101FF000D34DE89D9B5E8D16BD9E097F91CF071F37 +:10200000B4B19EF9343C27B6AB3B857D9183262441 +:102010008AC846C51141529EBD0FA80E6DD359D630 +:10202000049D65AD8FBFF3551890B881E89260BAF2 +:10203000B8E9807602C84EFCF0D12311C2A72DD892 +:102040008F0AFB013E6CBFDE21F862EBE93AF849EA +:1020500050E4BF9DFEC26D4FEDF6212BFFEC7E2EAE +:10206000750584FDD0C141F722EBF70BC786EB194C +:102070001FA0FF4CD2BD98CEF2EA02EA5FE93AA275 +:10208000BB7EE8AE13BAEB8359B931FDB4CF77B557 +:10209000D3C98FE79117BB3D60E9DB60BF3FAFDE7F +:1020A0001D407D27FE0D359B49AA1BED0D4F47595D +:1020B0006E4EBEC5B858794136085F2A8AE073E78C +:1020C000A269E663579309546F3AD0DFFB9DDC7930 +:1020D000BFDE9AF84A27CA49A13669D23C41C824D2 +:1020E000C9FFAC2D35FBF2E1A621CB8EBCD31ADFA4 +:1020F0004DDFD1B575E2FF9B31730FF52FD66ECD55 +:10210000A74F8A4DBB4BD6A7D3429F9A76B03E8D40 +:1021100054F431CE1AF9894C482A8B232D7D1A6943 +:102120003EC3FA6EEB55DAB63F4D422F288F40FE84 +:102130003B5461B2DDF896A54F0AEA09E993CFD284 +:10214000A790961D4FF9F136A2333E572AA6F9BB48 +:102150005093A57FA44F41BA3F0C8C038650EF28C3 +:102160002FE2D6AF962AE1379F684D3CD449F862FA +:10217000D17ACECB0F55FCBE94F18B25FF59BC5BB9 +:10218000CFFEFCDCB0C7207DA823005D9FD503FBFC +:10219000DCAB6764C8206BD6CC48DCDE3453C86D3A +:1021A000CB4C805B73A694DBD84C98DBD699ABB94B +:1021B0006D9B29E7B67D06F56025EAC34C25B79DE2 +:1021C00033D773DB35B38CDBEE99953CAE67660590 +:1021D000B76B673EC6EDCD33CD629D1A71AE3CFA4A +:1021E0004065B02BA00F46128A480F3EF32ADB77DA +:1021F0004DE53B4AA97023D7897CCA34EBC3B1268D +:1022000061EFBB82824F6E7D78A735F1AB7CFA30EF +:102210008B6F15D088FE2A587F2EFC80F8E737F4A4 +:10222000BD8D7BD5A8C97286F8E40CF1F37271C23A +:102230002CCE5CAC321EB571E6C822C49995599C6F +:1022400039D42CE2B2D4211FC76F5B2471BFECEAF2 +:10225000B6C47FB37E82C813256EF56B849B53E1B1 +:10226000CE6890F27A7B65A07C01E2900F789F4A5D +:102270005CDC67BD487D7E3326ECBE3DBE0E4E7BEA +:10228000FA2E01C7FC9AFED93CBF5D28B95C3FEB32 +:102290006D13764113762155D137CC7569975DB0B2 +:1022A000FD2CD2C3611796765976C1D2F3920AE11A +:1022B0002F4BC82E207D9675D976C1E967151B87EF +:1022C00074DB38C4B20BDDE23BC4ED0E3F8BECF6A1 +:1022D000430E2E46395ADE950787B03FCFF1730380 +:1022E00055D531FA2D41F82CC4483C4333FA5A23D2 +:1022F0008FDF4969F5AC07279536C8CDAF5CB29E34 +:10230000856DBF63B2DF718FB3F56DE8648F38A759 +:10231000E5874EE2F9CD1C7DEBD2843F42FF73335B +:102320009DD3AD6F2D8BCD443CCF3E3FD925F0FEE4 +:102330008FD658B81771A511647C9F17377C92F817 +:10234000D7207EA7F118DA9F8EEE644AD159CF3F8D +:1023500049EBAE6E9F92290F7453D3E8CB541241D0 +:102360003DFD5457C3E5EB6953AB55EFDB592A2EBE +:102370003B5BED85E4DFC645B61EB8C73D5469F644 +:10238000E6A3C7B3163D06863D3D74E1CF968B9319 +:10239000CA52C63F79ECAD695C117B7B71F8E324CE +:1023A000FA41E2FB79F0C7817CFC9F0F7F8C77CDEF +:1023B000E28F31E2534BADC01FCF76C179E39BCBA7 +:1023C000C615B1D34CB7CBC5150F769D1F577CA74B +:1023D0004BD84D459B66FB11BA4C5CE1B613881F88 +:1023E000FE95E96308BF6BFFDE842F50E6F82FB43B +:1023F000338FD338C20D7479EC58B03529B11EC46F +:102400009FA4E7A3E61296A32BA50F88137FD09570 +:10241000D3BF905E5CF4B8C98D9C07B4EB997F0C78 +:1024200084EA283FB2D32FDA2F15848E513BD62F62 +:10243000F2D07F0C2C4E53DE6CCC0B5C3F18940A10 +:102440008C63223FBA9C7F5F037D37527BA6CBAE65 +:10245000CBFF9DA35E1AD6B63DFE6669BEFD88FB26 +:10246000BD948AFF90EF8157689C3FB7E84169208F +:10247000F6CFD5058CFF00614B538EDD4F75AC1345 +:102480007172A59FEB79322867281F3F4C6BF1FED4 +:102490007AB98E19B0FC212849FDE3BC5F9107B5DC +:1024A0007FF7B76FF5FA627109793B8FB7E57F5F08 +:1024B00070D4AFD53AF4DDF1BB6E772BAF38A5B54C +:1024C000E17EC77485EBAE078D4880EB2615227B35 +:1024D000EE5FE489A7F3E8E9B5DDB3F722785F6141 +:1024E0006B5FBE0E11AFCDB7DEFE7EE73DAB82DA8D +:1024F000B849FEC45FD91727BAF9174524CAABCE2D +:10250000D2BB5BB2EE69189916A4F7B0A587053562 +:1025100093190FD139BC6D25D1D65F938633344FD3 +:10252000ED24BC41FEA2D2DF9B6FDFD759FB1EF624 +:1025300026E38493862B15AE5F0E57E6F72F25DD35 +:10254000C2FEFA17EDE0F1B048E1FAB37B9CD22D60 +:10255000E4689FDAC7758CA145F7F37DB721FA21AE +:10256000CD47D1EEFD70E681DDF8FC50FFF6C7DF08 +:10257000F4929C26B8DD77ED7E8DEE711EAAF76889 +:1025800094870BFB337EFA7D6678B5C87396B4E307 +:10259000B8DC7855AE08909D0DADC27972E2D031AD +:1025A000D002B4EEBE906D1FA7FDC23E0A792AB2DA +:1025B000C68EAC1275A9917576FE5FF02FFB7E7CFE +:1025C000BBB82FA7EAC079685197E2D49E4EF7674F +:1025D000EBC374AE324DD4A30E59F23568E5D9DDA4 +:1025E0007439B4788AFDC9A13553BDE43F429ADFFE +:1025F000E826B93EEEDCD7DEE66907DE1869386DFD +:10260000EDDFBD3F21F7CAD36F093B69E1FE90F1D1 +:102610007BC659F63DAEAED5420F8BAD7BF4C5916E +:10262000B849F3EDBEF6B749AA131D2EB7EF167CD5 +:10263000DE790F03A6191787565B7539F96DBEFF52 +:102640000BB78A7B12F63D6F35A23AF202A5AEFBBC +:102650005921571FE40DE7BDCFB6F397479F3F952C +:10266000C3CFCF773BEF835FE8FB3FF6A79F3F8564 +:102670007E6E6CD5F9F5CFE6D3E1FE266E6D39B4EA +:10268000E5324C47AC9FFFFBB1703C6FBDE5114B91 +:102690004FDCF2EA96D3625F9CFDFEE81AE73CF756 +:1026A000597A7E9F358FBA18CA090F8D86855E8E3E +:1026B00006A0F7913CE77AAC5BE5F159B977E28285 +:1026C000A2CBC5052B5AADB8A284F56D6C55EB7342 +:1026D0002437EF915EE4D82777DEDCC6054A8FC049 +:1026E000A5CF845589FCBA169C66BC3CEBD72D1C43 +:1026F000E0F6EB7E6FB297F4CF5FA9DA7689ED470B +:102700006577E01BC920FB0329D70F1ECADCC9F37C +:10271000865D797388387F87B2B71B984E61DDB2CA +:102720002FDD8AB887356A42EE3D9A31CFDB336FB1 +:10273000E8E2DF1FD838A292DE1F9CE2DFC7C03D6F +:1027400090BBFEDE964DFC7B880BF1DDDE17DDCB0A +:10275000CAD59B4BD58B976DBD084080F4E21CDC3D +:10276000CB757418ED76F821AE282C601320FEF09E +:10277000984AA365C7A4ACBE409755DF4E883A3D42 +:102780005198BE33ACCFCAE99604C5D790E1DF1D9E +:10279000DAF6E51CFC92D74D3E2D49B3B8E96A0C38 +:1027A000DFE9F78C4B690B9A875AF7FE9780C1CF08 +:1027B000AB20CEEDB5D0C76D0D8C727B1D4C725B1E +:1027C0000B53DCD6C1596E57802ED3222BC1948176 +:1027D000AF5E26B87F2324B96D86C4FB742774B01E +:1027E0006CDB0AB257EFBBE864D3398FBE332EB42B +:1027F000E961D3FD2132D20D17E66B2A2CEC6F5B19 +:10280000D314E3D7A2A01DFF0A39B7E7990FC7BABF +:1028100071979F70D7CAB9727021DC65E3C4FF035A +:1028200008E97101B048000000000000000000004D +:102830000000001800000000000000000000004040 +:102840000000000000000000000000280000000060 +:102850000000000000000010000000000000000068 +:102860000000002000000000000000000000001038 +:102870000000000000000000000000080000000050 +:102880000000000000000000000000000000000048 +:102890000000000000000000000000000000000038 +:1028A0000000000000000000000000000000000028 +:1028B0000000000000000000000000000000000018 +:1028C0000000000000000000000000000000000008 +:1028D00000000000000000000000000000000000F8 +:1028E00000000000000000000000000000000000E8 +:1028F00000000000000000000000000000000000D8 +:1029000000000000000000000000000000000000C7 +:1029100000000000000000000000000000000000B7 +:1029200000000000000000000000000000000000A7 +:102930000000000000000000000000000000000097 +:102940000000000000000000000000000000000087 +:102950000000000000000000000000000000000077 +:102960000000000000000000000000000000000067 +:102970000000000000000000000000000000000057 +:102980000000000000000000000000000000000047 +:102990000000000000000000000090000010000097 +:1029A0000000000800009008001000000000000275 +:1029B00000009000001000000000001000009DA822 +:1029C000000000000000000880000000000000007F +:1029D0000000000080000000000000000000000077 +:1029E000800000000000000000000000000091A036 +:1029F0000000000000000008000093C00001000477 +:102A000000000001000093C8000000000000000268 +:102A1000000093D00000000000000008000093D4E4 +:102A20000000000000000002000094980000000078 +:102A300000000008000093D8000800000000000813 +:102A400000009B3800400000000000400000941887 +:102A50000008000000000008000094580008000072 +:102A600000000008000094A800C8000000000098C2 +:102A700000009638009800000000002800009678BA +:102A800000980000000000280000C0000540003051 +:102A9000000005400000CB200008000000000001FD +:102AA0000000CB2100080000000000010000200809 +:102AB00000100000000000100000200000000000D6 +:102AC0000000000800009D600008000000000002F7 +:102AD00000009DA0000000000000000100000000B8 +:102AE00000000000000000000000000000000000E6 +:102AF00000000000000000000000000000000000D6 +:102B000080000000000000000000000080000000C5 +:102B10000000000000000000800000000000000035 +:102B20000000000080000000000000000000000025 +:102B30008000000000000000000000008000000095 +:102B40000000000000000000800000000000000005 +:102B500000000000800000000000000000000000F5 +:102B60008000000000000000000000008000000065 +:102B700000000000000000008000000000000000D5 +:102B800000000000800000000000000000000000C5 +:102B900080000000000000000000000000000000B5 +:102BA0000000000000000000000000000000000025 +:102BB0000000000000000000000000000000000015 +:102BC0000000000000000000000000000000000005 +:102BD0000000000000000000800000000000000075 +:102BE0000000000080000000000000000000000065 +:102BF0008000000000000000000000000000000055 +:102C00000000000000000000800000000000000044 +:102C10000000000080000000000000000000000034 +:102C20008000000000000000000000000000000024 +:102C30000000000000000000000000000000000094 +:102C40000000000000000000000000000000000084 +:102C50000000000000000000000000000000000074 +:102C60000000000000000000000000000000000064 +:102C700000000000000012C800800000000000807A +:102C80000000000100000000000000000000A000A3 +:102C9000071000000000071000001EC80000000020 +:102CA000000000080000AEC000080000000000089E +:102CB0000000AE4000080000000000080000AE80E8 +:102CC00000080000000000080000200800100000BC +:102CD00000000010000020000000000000000008BC +:102CE0000000A01007100040000000400000AF40AE +:102CF00000080000000000010000AF4100080000D3 +:102D00000000000100001ED00000000000000001D3 +:102D100000001ED8000000000000000200001EDAC3 +:102D20000000000000000002000012B000080000D7 +:102D3000000000088000000000000000000000000B +:102D40008000000000000000000000008000000083 +:102D500000000000000000008000000000000000F3 +:102D600000000000800000000000000000000000E3 +:102D70008000000000000000000000008000000053 +:102D800000000000000000008000000000000000C3 +:102D900000000000800000000000000000000000B3 +:102DA0000000000000000000000000000000000023 +:102DB0000000000000000000000000000000000013 +:102DC0000000000000000000000000000000000003 +:102DD0000000000000000000000000008000000073 +:102DE0000000000000000000800000000000000063 +:102DF00000000000000000000000000000000000D3 +:102E000080000000000000000000000080000000C2 +:102E10000000000000000000800000000000000032 +:102E20000000000080000000000000000000000022 +:102E30000000B00000180000000000180000B300FF +:102E400000400000000000400000B300004000020D +:102E5000000000010000B30100400002000000007B +:102E600000008000004000000000004080000000E2 +:102E7000000000000000000000008000000800408A +:102E8000000000040000800400080040000000046E +:102E90000000BB0000280000000000280000BC402B +:102EA00000100000000000100000880000800000FA +:102EB0000000008000008800000800800000000280 +:102EC00000008C000020000000000020000020080E +:102ED00000100000000000100000200000000000B2 +:102EE00000000008000011080008000000000008B1 +:102EF000000011680008000000000008000011A890 +:102F00000008000000000008000012700008000027 +:102F10000000000100001271000800000000000124 +:102F200000008D00001000040000000400001320C9 +:102F300000300018000000100000132800300018B6 +:102F400000000002800000000000000000000000FF +:102F5000800000000000000000000000000011E8F8 +:102F600000000000000000018000000000000000E0 +:102F700000000000800000000000000000000000D1 +:102F80008000000000000000000000008000000041 +:102F900000000000000000008000000000000000B1 +:102FA00000000000800000000000000000000000A1 +:102FB0000000000000000000000000000000000011 +:102FC0000000000000000000000000000000000001 +:102FD00000000000000000000000000000000000F1 +:102FE00080000000000000000000000080000000E1 +:102FF00000000000000000000000000000000000D1 +:103000000000000000008308008000000000008035 +:103010000000000100000000000000000000200887 +:103020000010000000000010000020000000000060 +:103030000000000800008D100008000000000008DB +:1030400000008D700008000000000008000084509F +:10305000046000280000046000008EA0000800004A +:103060000000000100008EA1000800000000000127 +:1030700000008408000800000000000800008448E8 +:10308000000000000000000100008DF400080000B6 +:103090000000000200008DF60008000000000002A1 +:1030A00000008E04001000000000000480000000FA +:1030B0000000000000000000800000000000000090 +:1030C0000000000080000000000000000000000080 +:1030D00000000000000000000000000000000000F0 +:1030E00000000000000000000000000000000000E0 +:1030F00000000000000000000000000000000000D0 +:1031000080000000000000000000000080000000BF +:1031100000000000000000000000000000000000AF +:10312000000000008000000000000000000000001F +:10313000800000000000000000000000800000008F +:1031400000000000000000008000000000000000FF +:1031500000000000000030000040000000000008F7 +:1031600000003008004000000000002800003390FC +:1031700001C0001000000008000032000020000024 +:1031800000000020000037200000000000000008C0 +:103190000000102006200038000000080000A000F9 +:1031A000000000000000200000003EA90000000018 +:1031B0000000000100003EC8000000000000000206 +:1031C00000001C4000E00008000000088000000033 +:1031D00000000000000000000000400000080000A7 +:1031E0000000000100004001000800000000000194 +:1031F00000004040000800040000000200004060A1 +:103200000008000400000004000040000008000066 +:10321000000000040000400400080000000000045A +:10322000000040400000000000000008000040488E +:103230000000000000000008000080000000000006 +:1032400000000010000050400001000400000001D8 +:1032500000005000000000000000002000005008A6 +:1032600000100000000000040000500C00100000DE +:1032700000000001000052C7000000000000000133 +:10328000000052C6000000000000000100003000F5 +:103290000030001800000004000030040030001866 +:1032A0000000000400003008003000180000000298 +:1032B0000000300A00300018000000020000300C4E +:1032C00000300018000000010000300D0030001830 +:1032D000000000010000300E003000180000000166 +:1032E000000030100030001800000004000030140E +:1032F00000300018000000040000500001000080B1 +:1033000000080004000050040100008000080004D0 +:103310000000000A000000000000000000005068EB +:1033200001000080000000010000506901000080E1 +:10333000000000010000506C01000080000000024D +:103340000000506E0100008000000002000050707C +:1033500001000080000000040000507401000080A3 +:103360000000000400005066010000800000000220 +:103370000000506401000080000000010000506067 +:103380000100008000000002000050620100008087 +:103390000000000200005050010000800000000406 +:1033A000000050540100008000000004000050584C +:1033B00001000080000000040000505C010000805B +:1033C000000000040000507C0100008000000001AB +:1033D0000000507D01000080000000010000401846 +:1033E00000100000000000040000409000100000E9 +:1033F00000000004000040980010000000000004DD +:103400000000411000000000000000020000411216 +:103410000000000000000002000041140000000055 +:103420000000000200004116000000000000000241 +:103430000000604000080000000000020000604240 +:1034400000080000000000020000604400080000C6 +:103450000000000400006080000800000000000878 +:10346000000060C00040000800000008000060008C +:1034700000080000000000020000600200080000D8 +:1034800000000001000060040008000000000002CD +:103490000000634000080000000000080000638096 +:1034A0000008000000000004000063840008000021 +:1034B00000000001000063C00008000000000002DE +:1034C000000063C400080000000000020000640067 +:1034D0000008000000000004000070000010000060 +:1034E0000000000400007004001000000000000450 +:1034F00000007008001000000000000400007000D0 +:103500000008000000000002000070020008000037 +:10351000000000010000700400080000000000022C +:10352000000070400008000000000002000070442D +:1035300000080000000000020000704600080000C3 +:1035400000000002000076480008000000000008AB +:10355000000070800008000000000002000070847D +:10356000000800000000000200007688000800004B +:10357000000000080000804000080000000000017A +:1035800000008041000800000000000100008042AF +:103590000008000000000001000080430008000057 +:1035A0000000000100008000000800000000000290 +:1035B00000008002000800000000000100008004FC +:1035C0000008000000000002000080C000080000A9 +:1035D00000000002000080C200080000000000029D +:1035E000000080C40008000000000002000080808D +:1035F00000080000000000010000808100080000B9 +:1036000000000001000080820008000000000001AE +:10361000000080830008000000000001000080849A +:103620000008000000000001000080850008000084 +:10363000000000010000808600080000000000017A +:1036400000006000000800000000000200006002AE +:1036500000080000000000010000600400080000F5 +:10366000000000020000604200C0001800000002DC +:103670000000604000C00018000000020000604C24 +:1036800000C00018000000080000604400C00018DE +:10369000000000080000605700C000180000000192 +:1036A0000000605400C000180000000200006056D6 +:1036B00000C0001800000001000066400008000083 +:1036C00000000008000066800008000000000008FC +:1036D000000066C000080000000000080000D94299 +:1036E00000180000000000020000DE4000000000A2 +:1036F000000000000000E0000000000000000004E6 +:103700000000DD4000000000000000040000DD4477 +:1037100000000000000000040000DD480000000080 +:10372000000000040000DD4C000000000000000468 +:103730000000DD5000000000000000040000DD5427 +:1037400000000000000000040000DD580000000040 +:10375000000000040000DD40000000000000002028 +:103760000000DA0000000000000000040000DA00A1 +:1037700000000000000000680000BB6000000000C6 +:10378000000000000000D000000000000000000465 +:103790000000B0C000000000000000040000B0C441 +:1037A00000000000000000040000B0C8000000009D +:1037B000000000040000B0C0000000000000001085 +:1037C0000000D6B000000000000000040000D6B4E5 +:1037D00000000000000000040000D6B80000000057 +:1037E000000000040000D6BC00000000000000043F +:1037F0000000D6B000000000000000100000D34818 +:1038000000000000000000080000D3580000000085 +:103810000000008000000010000000000000000018 +:103820000000D35800000000000000080000000065 +:0838300006020900000000007F +:00000001FF diff --git a/firmware/bnx2x/bnx2x-e2-6.2.5.0.fw.ihex b/firmware/bnx2x/bnx2x-e2-6.2.5.0.fw.ihex deleted file mode 100644 index aef9aa6..0000000 --- a/firmware/bnx2x/bnx2x-e2-6.2.5.0.fw.ihex +++ /dev/null @@ -1,15456 +0,0 @@ -:1000000000005310000000680000070C000053803F -:100010000000318000005A90000000B000008C18F1 -:100020000000C13400008CD0000000D800014E0850 -:100030000000F1F000014EE800000074000240E012 -:100040000000525C00024158000000B8000293B862 -:100050000001213C0002947800000FFC0003B5B8B9 -:10006000000000040003C5B8020400480000000FAF -:1000700002040054000000450204005C0000000679 -:100080000204007000000004020400780000000078 -:100090000204007C121700000204008022170000F6 -:1000A00002040084321700000604008800000005E6 -:1000B0000204009C12150000020400A0221500009A -:1000C000020400A432150000060400A80000000489 -:1000D000020400B802100000020400BC001000007E -:1000E000020400C010100000020400C42010000030 -:1000F000020400C830100000020400CC40100000D0 -:10010000060400D000000003020400DC0010000020 -:10011000020400E012140000020400E422140000B3 -:10012000020400E832140000020400EC4214000053 -:10013000060400F000000003010401240000000098 -:1001400001040128000000000104012C000000004F -:100150000104013000000000020401D00000890603 -:1001600002040258000000360204025C000000365F -:10017000020402600810000002040264081000007B -:1001800002040004000000FF02040008000000FF59 -:100190000204000C000000FF02040010000000FF39 -:1001A000020400140000007F02040018000000FF99 -:1001B0000204001C000000FF02040020000000FFF9 -:1001C000020400240000003E020400280000000099 -:1001D0000204002C0000003F020400300000003F39 -:1001E000020400340000003F020400380000003F19 -:1001F0000204003C0000003F020400400000003FF9 -:10020000020400440000003F020404CC000000018E -:1002100002042008000002110204200C0000020069 -:10022000020420100000020402042014000002193D -:100230000204201C0000FFFF020420200000FFFF3A -:10024000020420240000FFFF020420280000FFFF1A -:1002500002042038000000200604203C0000000FAB -:1002600002042078000000210604207C0000000F1A -:10027000020420B800000001060420BC0000000FAA -:10028000020420F800000001060420FC0000003FEA -:10029000020421F800000001060421FC0000000F08 -:1002A0000204223807FFFFFF0204223C0000007F07 -:1002B0000204224007FFFFFF020422440000003F27 -:1002C00001042248000000000104224C000000004C -:1002D000010422500000000001042254000000002C -:1002E00001042258000000000104225C000000000C -:1002F00001042260000000000104226400000000EC -:1003000001042268000000000104226C00000000CB -:1003100001042270000000000104227400000000AB -:1003200001042278000000000104227C000000008B -:10033000020422C00000FFFF020422C40000FFFFED -:10034000020422C80000FFFF020422CC0000FFFFCD -:100350000C042000000003E80A0420000000000153 -:100360000B042000000000030605400000000D0003 -:100370000205004400000020020500480000003291 -:1003800002050090021500200205009402150020CD -:1003900002050098000000300205009C08100000D3 -:1003A000020500A000000036020500A40000003095 -:1003B000020500A800000031020500B000000004A2 -:1003C000020500B400000005020500C000000000A6 -:1003D000020500C400000004020500D40000000172 -:1003E00002050114000000010205011C00000001CB -:1003F00002050120000000020205020400000001C5 -:100400000205020C0000004002050210000000403E -:100410000205021C00000020020502200000001C52 -:100420000205022400000020060502400000000A28 -:1004300004050280002000000205005000000007B3 -:1004400002050054000000070205005800000000EB -:100450000205005C000000080205006000000001C9 -:100460000605006400000003020500D80000000635 -:100470000205000400000001020500080000000160 -:100480000205000C00000001020500100000000140 -:100490000205001400000001020500180000000120 -:1004A0000205001C00000001020500200000000100 -:1004B00002050024000000010205002800000001E0 -:1004C0000205002C000000010205003000000001C0 -:1004D00002050034000000010205003800000001A0 -:1004E0000205003C00000001020500400000000180 -:1004F000020500E00000000D020500E80000000019 -:10050000020500F000000000020500F800000000F5 -:10051000020500E40000002D020500EC00000020B0 -:10052000020500F400000020020500FC000000208D -:10053000020500E00000001D020500E800000010B8 -:10054000020500F000000010020500F80000001095 -:10055000020500E40000003D020500EC0000003050 -:10056000020500F400000030020500FC000000302D -:10057000020500E00000004D020500E80000004018 -:10058000020500F000000040020500F800000040F5 -:10059000020500E40000006D020500EC00000060B0 -:1005A000020500F400000060020500FC000000608D -:1005B000020500E00000005D020500E800000050B8 -:1005C000020500F000000050020500F80000005095 -:1005D000020500E40000007D020500EC0000007050 -:1005E000020500F400000070020500FC000000702D -:1005F0000406100002000020020600DC00000001DA -:100600000406020000030220020600DC00000000D5 -:100610000718040000AD0000081807D800050223E1 -:10062000071C000029920000071C8000312A0A657F -:10063000071D000034A316B0071D80002E7A23D9B1 -:10064000071E000003502F78081E07F03F02022506 -:10065000021800BC0000003001180000000000007B -:10066000011800040000000001180008000000004C -:100670000118000C0000000001180010000000002C -:100680000118001400000000021800200000000102 -:1006900002180024000000020218002800000003D5 -:1006A0000218002C000000000218003000000004B6 -:1006B0000218003400000001021800380000000099 -:1006C0000218003C00000001021800400000000475 -:1006D0000218004400000000021800480000000159 -:1006E0000218004C00000003021800500000000037 -:1006F0000218005400000001021800580000000415 -:100700000218005C000000000218006000000001F8 -:1007100002180064000000030218006800000000D6 -:100720000218006C000000010218007000000004B4 -:100730000218007400000000021800780000000495 -:100740000218007C00000003061800800000000270 -:10075000021800A400007FFF021800A8000003FF99 -:1007600002180224000000000218023400000000F9 -:100770000218024C00000000021802E4000000FF12 -:100780000618100000000400021B8BC000000001CE -:10079000021B800000000034021B80400000001893 -:1007A000021B80800000000C021B80C000000020A3 -:1007B0000C1B8300000864700A1B830000000157B3 -:1007C0000B1B83000000055F0A1B83400000000034 -:1007D0000C1B8340000002260B1B8340000000011D -:1007E000021B838000086470021B83C00000022685 -:1007F000021B1480000000010A1B1480000000008E -:10080000021B944000000001061B944800000002F7 -:10081000061A1000000002B3041A1ACC00010227C5 -:10082000061A1AD000000008061A2008000000C8A6 -:10083000061A200000000002041A1BF8009002288B -:10084000061A371800000004061A371000000002CC -:10085000061A500000000002061A500800000004AA -:10086000061A501800000004061A50280000000460 -:10087000061A503800000004061A50480000000410 -:10088000061A505800000004061A506800000004C0 -:10089000061A507800000002041A52C0000202B882 -:1008A000061A405000000006041A4068000202BA0E -:1008B000041A4040000402BC041A8000000102C077 -:1008C000061A800400000003041A8010000102C10F -:1008D000061A801400000003041A8020000102C2DE -:1008E000061A802400000003041A8030000102C3AD -:1008F000061A803400000003041A8040000102C47C -:10090000061A804400000003041A8050000102C54A -:10091000061A805400000003041A8060000102C619 -:10092000061A806400000003041A8070000102C7E8 -:10093000061A807400000003041A8080000102C8B7 -:10094000061A808400000003041A8090000102C986 -:10095000061A809400000003041A80A0000102CA55 -:10096000061A80A400000003041A80B0000102CB24 -:10097000061A80B400000003041A80C0000102CCF3 -:10098000061A80C400000003041A80D0000102CDC2 -:10099000061A80D400000003041A80E0000102CE91 -:1009A000061A80E400000003041A80F0000102CF60 -:1009B000061A80F400000003041A8100000102D02E -:1009C000061A810400000003041A8110000102D1FC -:1009D000061A811400000003041A8120000102D2CB -:1009E000061A812400000003041A8130000102D39A -:1009F000061A813400000003041A8140000102D469 -:100A0000061A814400000003041A8150000102D537 -:100A1000061A815400000003041A8160000102D606 -:100A2000061A816400000003041A8170000102D7D5 -:100A3000061A817400000003041A8180000102D8A4 -:100A4000061A818400000003041A8190000102D973 -:100A5000061A819400000003041A81A0000102DA42 -:100A6000061A81A400000003041A81B0000102DB11 -:100A7000061A81B400000003041A81C0000102DCE0 -:100A8000061A81C400000003041A81D0000102DDAF -:100A9000061A81D400000003041A81E0000102DE7E -:100AA000061A81E400000003041A81F0000102DF4D -:100AB000061A81F400000003041A8200000102E01B -:100AC000061A820400000003041A8210000102E1E9 -:100AD000061A821400000003041A8220000102E2B8 -:100AE000061A822400000003041A8230000102E387 -:100AF000061A823400000003041A8240000102E456 -:100B0000061A824400000003041A8250000102E524 -:100B1000061A825400000003041A8260000102E6F3 -:100B2000061A826400000003041A8270000102E7C2 -:100B3000061A827400000003041A8280000102E891 -:100B4000061A828400000003041A8290000102E960 -:100B5000061A829400000003041A82A0000102EA2F -:100B6000061A82A400000003041A82B0000102EBFE -:100B7000061A82B400000003041A82C0000102ECCD -:100B8000061A82C400000003041A82D0000102ED9C -:100B9000061A82D400000003041A82E0000102EE6B -:100BA000061A82E400000003041A82F0000102EF3A -:100BB000061A82F400000003041A8300000102F008 -:100BC000061A830400000003041A8310000102F1D6 -:100BD000061A831400000003041A8320000102F2A5 -:100BE000061A832400000003041A8330000102F374 -:100BF000061A833400000003041A8340000102F443 -:100C0000061A834400000003041A8350000102F511 -:100C1000061A835400000003041A8360000102F6E0 -:100C2000061A836400000003041A8370000102F7AF -:100C3000061A837400000003041A8380000102F87E -:100C4000061A838400000003041A8390000102F94D -:100C5000061A839400000003041A83A0000102FA1C -:100C6000061A83A400000003041A83B0000102FBEB -:100C7000061A83B400000003041A83C0000102FCBA -:100C8000061A83C400000003041A83D0000102FD89 -:100C9000061A83D400000003041A83E0000102FE58 -:100CA000061A83E400000003041A83F0000102FF27 -:100CB000061A83F400000003041A840000010300F4 -:100CC000061A840400000003041A841000010301C2 -:100CD000061A841400000003041A84200001030291 -:100CE000061A842400000003041A84300001030360 -:100CF000061A843400000003041A8440000103042F -:100D0000061A844400000003041A845000010305FD -:100D1000061A845400000003041A846000010306CC -:100D2000061A846400000003041A8470000103079B -:100D3000061A847400000003041A8480000103086A -:100D4000061A848400000003041A84900001030939 -:100D5000061A849400000003041A84A00001030A08 -:100D6000061A84A400000003041A84B00001030BD7 -:100D7000061A84B400000003041A84C00001030CA6 -:100D8000061A84C400000003041A84D00001030D75 -:100D9000061A84D400000003041A84E00001030E44 -:100DA000061A84E400000003041A84F00001030F13 -:100DB000061A84F400000003041A850000010310E1 -:100DC000061A850400000003041A851000010311AF -:100DD000061A851400000003041A8520000103127E -:100DE000061A852400000003041A8530000103134D -:100DF000061A853400000003041A8540000103141C -:100E0000061A854400000003041A855000010315EA -:100E1000061A855400000003041A856000010316B9 -:100E2000061A856400000003041A85700001031788 -:100E3000061A857400000003041A85800001031857 -:100E4000061A858400000003041A85900001031926 -:100E5000061A859400000003041A85A00001031AF5 -:100E6000061A85A400000003041A85B00001031BC4 -:100E7000061A85B400000003041A85C00001031C93 -:100E8000061A85C400000003041A85D00001031D62 -:100E9000061A85D400000003041A85E00001031E31 -:100EA000061A85E400000003041A85F00001031F00 -:100EB000061A85F400000003041A860000010320CE -:100EC000061A860400000003041A8610000103219C -:100ED000061A861400000003041A8620000103226B -:100EE000061A862400000003041A8630000103233A -:100EF000061A863400000003041A86400001032409 -:100F0000061A864400000003041A865000010325D7 -:100F1000061A865400000003041A866000010326A6 -:100F2000061A866400000003041A86700001032775 -:100F3000061A867400000003041A86800001032844 -:100F4000061A868400000003041A86900001032913 -:100F5000061A869400000003041A86A00001032AE2 -:100F6000061A86A400000003041A86B00001032BB1 -:100F7000061A86B400000003041A86C00001032C80 -:100F8000061A86C400000003041A86D00001032D4F -:100F9000061A86D400000003041A86E00001032E1E -:100FA000061A86E400000003041A86F00001032FED -:100FB000061A86F400000003041A870000010330BB -:100FC000061A870400000003041A87100001033189 -:100FD000061A871400000003041A87200001033258 -:100FE000061A872400000003041A87300001033327 -:100FF000061A873400000003041A874000010334F6 -:10100000061A874400000003041A875000010335C4 -:10101000061A875400000003041A87600001033693 -:10102000061A876400000003041A87700001033762 -:10103000061A877400000003041A87800001033831 -:10104000061A878400000003041A87900001033900 -:10105000061A879400000003041A87A00001033ACF -:10106000061A87A400000003041A87B00001033B9E -:10107000061A87B400000003041A87C00001033C6D -:10108000061A87C400000003041A87D00001033D3C -:10109000061A87D400000003041A87E00001033E0B -:1010A000061A87E400000003041A87F00001033FDA -:1010B000061A87F400000003041A880000010340A8 -:1010C000061A880400000003041A88100001034176 -:1010D000061A881400000003041A88200001034245 -:1010E000061A882400000003041A88300001034314 -:1010F000061A883400000003041A884000010344E3 -:10110000061A884400000003041A885000010345B1 -:10111000061A885400000003041A88600001034680 -:10112000061A886400000003041A8870000103474F -:10113000061A887400000003041A8880000103481E -:10114000061A888400000003041A889000010349ED -:10115000061A889400000003041A88A00001034ABC -:10116000061A88A400000003041A88B00001034B8B -:10117000061A88B400000003041A88C00001034C5A -:10118000061A88C400000003041A88D00001034D29 -:10119000061A88D400000003041A88E00001034EF8 -:1011A000061A88E400000003041A88F00001034FC7 -:1011B000061A88F400000003041A89000001035095 -:1011C000061A890400000003041A89100001035163 -:1011D000061A891400000003041A89200001035232 -:1011E000061A892400000003041A89300001035301 -:1011F000061A893400000003041A894000010354D0 -:10120000061A894400000003041A8950000103559E -:10121000061A895400000003041A8960000103566D -:10122000061A896400000003041A8970000103573C -:10123000061A897400000003041A8980000103580B -:10124000061A898400000003041A899000010359DA -:10125000061A899400000003041A89A00001035AA9 -:10126000061A89A400000003041A89B00001035B78 -:10127000061A89B400000003041A89C00001035C47 -:10128000061A89C400000003041A89D00001035D16 -:10129000061A89D400000003041A89E00001035EE5 -:1012A000061A89E400000003041A89F00001035FB4 -:1012B000061A89F400000003041A8A000001036082 -:1012C000061A8A0400000003041A8A100001036150 -:1012D000061A8A1400000003041A8A20000103621F -:1012E000061A8A2400000003041A8A3000010363EE -:1012F000061A8A3400000003041A8A4000010364BD -:10130000061A8A4400000003041A8A50000103658B -:10131000061A8A5400000003041A8A60000103665A -:10132000061A8A6400000003041A8A700001036729 -:10133000061A8A7400000003041A8A8000010368F8 -:10134000061A8A8400000003041A8A9000010369C7 -:10135000061A8A9400000003041A8AA00001036A96 -:10136000061A8AA400000003041A8AB00001036B65 -:10137000061A8AB400000003041A8AC00001036C34 -:10138000061A8AC400000003041A8AD00001036D03 -:10139000061A8AD400000003041A8AE00001036ED2 -:1013A000061A8AE400000003041A8AF00001036FA1 -:1013B000061A8AF400000003041A8B00000103706F -:1013C000061A8B0400000003041A8B10000103713D -:1013D000061A8B1400000003041A8B20000103720C -:1013E000061A8B2400000003041A8B3000010373DB -:1013F000061A8B3400000003041A8B4000010374AA -:10140000061A8B4400000003041A8B500001037578 -:10141000061A8B5400000003041A8B600001037647 -:10142000061A8B6400000003041A8B700001037716 -:10143000061A8B7400000003041A8B8000010378E5 -:10144000061A8B8400000003041A8B9000010379B4 -:10145000061A8B9400000003041A8BA00001037A83 -:10146000061A8BA400000003041A8BB00001037B52 -:10147000061A8BB400000003041A8BC00001037C21 -:10148000061A8BC400000003041A8BD00001037DF0 -:10149000061A8BD400000003041A8BE00001037EBF -:1014A000061A8BE400000003041A8BF00001037F8E -:1014B000061A8BF400000003041A8C00000103805C -:1014C000061A8C0400000003041A8C10000103812A -:1014D000061A8C1400000003041A8C2000010382F9 -:1014E000061A8C2400000003041A8C3000010383C8 -:1014F000061A8C3400000003041A8C400001038497 -:10150000061A8C4400000003041A8C500001038565 -:10151000061A8C5400000003041A8C600001038634 -:10152000061A8C6400000003041A8C700001038703 -:10153000061A8C7400000003041A8C8000010388D2 -:10154000061A8C8400000003041A8C9000010389A1 -:10155000061A8C9400000003041A8CA00001038A70 -:10156000061A8CA400000003041A8CB00001038B3F -:10157000061A8CB400000003041A8CC00001038C0E -:10158000061A8CC400000003041A8CD00001038DDD -:10159000061A8CD400000003041A8CE00001038EAC -:1015A000061A8CE400000003041A8CF00001038F7B -:1015B000061A8CF400000003041A8D000001039049 -:1015C000061A8D0400000003041A8D100001039117 -:1015D000061A8D1400000003041A8D2000010392E6 -:1015E000061A8D2400000003041A8D3000010393B5 -:1015F000061A8D3400000003041A8D400001039484 -:10160000061A8D4400000003041A8D500001039552 -:10161000061A8D5400000003041A8D600001039621 -:10162000061A8D6400000003041A8D7000010397F0 -:10163000061A8D7400000003041A8D8000010398BF -:10164000061A8D8400000003041A8D90000103998E -:10165000061A8D9400000003041A8DA00001039A5D -:10166000061A8DA400000003041A8DB00001039B2C -:10167000061A8DB400000003041A8DC00001039CFB -:10168000061A8DC400000003041A8DD00001039DCA -:10169000061A8DD400000003041A8DE00001039E99 -:1016A000061A8DE400000003041A8DF00001039F68 -:1016B000061A8DF400000003041A8E00000103A036 -:1016C000061A8E0400000003041A8E10000103A104 -:1016D000061A8E1400000003041A8E20000103A2D3 -:1016E000061A8E2400000003041A8E30000103A3A2 -:1016F000061A8E3400000003041A8E40000103A471 -:10170000061A8E4400000003041A8E50000103A53F -:10171000061A8E5400000003041A8E60000103A60E -:10172000061A8E6400000003041A8E70000103A7DD -:10173000061A8E7400000003041A8E80000103A8AC -:10174000061A8E8400000003041A8E90000103A97B -:10175000061A8E9400000003041A8EA0000103AA4A -:10176000061A8EA400000003041A8EB0000103AB19 -:10177000061A8EB400000003041A8EC0000103ACE8 -:10178000061A8EC400000003041A8ED0000103ADB7 -:10179000061A8ED400000003041A8EE0000103AE86 -:1017A000061A8EE400000003041A8EF0000103AF55 -:1017B000061A8EF400000003041A8F00000103B023 -:1017C000061A8F0400000003041A8F10000103B1F1 -:1017D000061A8F1400000003041A8F20000103B2C0 -:1017E000061A8F2400000003041A8F30000103B38F -:1017F000061A8F3400000003041A8F40000103B45E -:10180000061A8F4400000003041A8F50000103B52C -:10181000061A8F5400000003041A8F60000103B6FB -:10182000061A8F6400000003041A8F70000103B7CA -:10183000061A8F7400000003041A8F80000103B899 -:10184000061A8F8400000003041A8F90000103B968 -:10185000061A8F9400000003041A8FA0000103BA37 -:10186000061A8FA400000003041A8FB0000103BB06 -:10187000061A8FB400000003041A8FC0000103BCD5 -:10188000061A8FC400000003041A8FD0000103BDA4 -:10189000061A8FD400000003041A8FE0000103BE73 -:1018A000061A8FE400000007041A62C0002003BF7C -:1018B000061A1AF000000042061AAF0000000008E5 -:1018C000061AE00000000540061AD0000000007271 -:1018D000061AD24800000010061AD6B000000020F8 -:1018E000061AD47000000090061AD46800000002A6 -:1018F000061AA000000001C4061A30000000001003 -:10190000061A308000000010061A31000000001096 -:10191000061A318000000010061A33000000001281 -:10192000061A339000000070061AD4580000000216 -:10193000061AD34800000002061AD35800000020FF -:10194000061AA710000001C4061A3040000000105B -:10195000061A30C000000010061A314000000010C6 -:10196000061A31C000000010061A334800000012A9 -:10197000061A355000000070061AD46000000002FC -:10198000061AD35000000002061AD3D80000002027 -:10199000021AAE2000000000061A500000000002EB -:1019A000061A508000000012041A4000000203DFF3 -:1019B000041A63C0000203E1061A7000000000046C -:1019C000061A320000000008021AAE2400000000CF -:1019D000061A501000000002061A50C8000000123B -:1019E000041A4008000203E3041A63C8000203E576 -:1019F000061A701000000004061A322000000008C9 -:101A0000021AAE2800000000061A50200000000252 -:101A1000061A511000000012041A4010000203E7D9 -:101A2000041A63D0000203E9061A702000000004C3 -:101A3000061A324000000008021AAE2C0000000016 -:101A4000061A503000000002061A51580000001219 -:101A5000041A4018000203EB041A63D8000203EDD5 -:101A6000061A703000000004061A326000000008F8 -:101A7000021AAE3000000000061A504000000002BA -:101A8000061A51A000000012041A4020000203EFC1 -:101A9000041A63E0000203F1061A7040000000041B -:101AA000061A328000000008021AAE34000000005E -:101AB000061A505000000002061A51E800000012F9 -:101AC000041A4028000203F3041A63E8000203F535 -:101AD000061A705000000004061A32A00000000828 -:101AE000021AAE3800000000061A50600000000222 -:101AF000061A523000000012041A4030000203F7A8 -:101B0000041A63F0000203F9061A70600000000472 -:101B1000061A32C000000008021AAE3C00000000A5 -:101B2000061A507000000002061A527800000012D7 -:101B3000041A4038000203FB041A63F8000203FD94 -:101B4000061A707000000004061A32E00000000857 -:101B50000200A2A4000002090200A270000000001E -:101B60000200A274000000000200A2700000000049 -:101B70000200A274000000000200A2700000000039 -:101B80000200A274000000000200A2700000000029 -:101B90000200A27400000000020100B40000000175 -:101BA000020100B800000001020100CC00000001A9 -:101BB000020100D000000001020100DC0000000171 -:101BC0000201010000000001020101040000000107 -:101BD0000201007C003000000201008400000028A7 -:101BE0000201008C0000000002010130000000042E -:101BF0000201025C00000001020103280000000055 -:101C0000020160580000FFFF020160700000000741 -:101C10000201055400000030020100C40000000170 -:101C2000020100F800000001020100F000000001C4 -:101C3000020100800030000002010088000000283E -:101C400002010090000000000201013400000004C5 -:101C5000020102DC000000010201032C0000000070 -:101C60000201605C0000FFFF0201607400000007D9 -:101C70000201056400000030020100C800000001FC -:101C8000020100FC00000001020100F4000000015C -:101C9000020C100000000028020C200800000211B5 -:101CA000020C200C00000200020C201000000204B4 -:101CB000020C201C0000FFFF020C20200000FFFF90 -:101CC000020C20240000FFFF020C20280000FFFF70 -:101CD000020C203800000000020C203C00000037FD -:101CE000020C204000000021020C204400000020D3 -:101CF000060C20480000001D020C20BC0000000162 -:101D0000060C20C00000003F020C21BC00000001B6 -:101D1000020C21C000000001020C21C400000001DF -:101D2000060C21C80000001C020C223807FFFFFF30 -:101D3000020C223C0000007F020C224007FFFFFF44 -:101D4000020C22440000003F010C22480000000069 -:101D5000010C224C00000000010C22500000000089 -:101D6000010C225400000000010C22580000000069 -:101D7000010C225C00000000010C22600000000049 -:101D8000010C226400000000010C22680000000029 -:101D9000010C226C00000000010C22700000000009 -:101DA000010C227400000000010C227800000000E9 -:101DB000010C227C00000000020C22D80000FFFF72 -:101DC000020C22DC0000FFFF020C22E00000FFFFFB -:101DD000020C22E40000FFFF0C0C2000000003E8CE -:101DE0000A0C2000000000010B0C20000000000382 -:101DF000020C400800001011020C400C0000100002 -:101E0000020C401000001004020C401400001021CD -:101E1000020C401C0000FFFF020C40200000FFFFEE -:101E2000020C40240000FFFF020C40280000FFFFCE -:101E3000020C403800000046020C403C0000000C40 -:101E4000060C404000000002020C40480000001850 -:101E5000020C404C000000F0060C40500000001F37 -:101E6000020C40CC00000001060C40D00000003AFB -:101E7000020C41B800000001060C41BC0000000348 -:101E8000020C41C800000001020C41CC000000011E -:101E9000060C41D00000001A020C423807FFFFFF79 -:101EA000020C423C0000007F020C424007FFFFFF93 -:101EB000020C42440000003F010C424800000000B8 -:101EC000010C424C00000000010C425000000000D8 -:101ED000010C425400000000010C425800000000B8 -:101EE000010C425C00000000010C42600000000098 -:101EF000010C426400000000010C42680000000078 -:101F0000010C426C00000000010C42700000000057 -:101F1000010C427400000000010C42780000000037 -:101F2000010C427C00000000010C42800000000017 -:101F3000020C42D80000FFFF020C42DC0000FFFF51 -:101F4000020C42E00000FFFF020C42E40000FFFF31 -:101F50000C0C4000000003E80A0C400000000001E7 -:101F60000B0C400000000003060D400000000A00BA -:101F7000020D004400000032020D008C021500200A -:101F8000020D009002150020020D009408100000C0 -:101F9000020D009800000036020D00A000000000B5 -:101FA000020D00A400000004020D00A800000004BF -:101FB000060D00AC00000002020D00B80000000297 -:101FC000020D00C000000001020D00C80000000268 -:101FD000020D00CC00000002020D015C00000001B7 -:101FE000020D016400000001020D01680000000202 -:101FF000020D020400000001020D020C000000208E -:10200000020D021000000040020D0214000000400A -:10201000020D022000000003020D0224000000183F -:10202000060D028000000012040D0300001803FFDB -:10203000060D03600000000C020D004C00000001C2 -:10204000020D005000000002020D005400000000CC -:10205000020D005800000008060D005C000000049E -:10206000020D00C400000004020D00040000000185 -:10207000020D000800000001020D000C000000012C -:10208000020D001000000001020D0014000000010C -:10209000020D001800000001020D001C00000001EC -:1020A000020D002000000001020D002400000001CC -:1020B000020D002800000001020D002C00000001AC -:1020C000020D003000000001020D0034000000018C -:1020D000020D003800000001020D003C000000016C -:1020E000020D011400000009020D011C0000000A8D -:1020F000020D012400000000020D012C0000000070 -:10210000020D013400000000020D013C0000000B34 -:10211000020D014400000000020D0118000000291A -:10212000020D01200000002A020D012800000020FD -:10213000020D013000000020020D013800000020D7 -:10214000020D01400000002B020D0148000000209C -:10215000020D011400000019020D011C0000001AFC -:10216000020D012400000010020D012C00000010DF -:10217000020D013400000010020D013C0000001BA4 -:10218000020D014400000010020D0118000000398A -:10219000020D01200000003A020D0128000000306D -:1021A000020D013000000030020D01380000003047 -:1021B000020D01400000003B020D0148000000300C -:1021C000020D011400000049020D011C0000004A2C -:1021D000020D012400000040020D012C000000400F -:1021E000020D013400000040020D013C0000004BD4 -:1021F000020D014400000040020D011800000069BA -:10220000020D01200000006A020D0128000000609C -:10221000020D013000000060020D01380000006076 -:10222000020D01400000006B020D0148000000603B -:10223000020D011400000059020D011C0000005A9B -:10224000020D012400000050020D012C000000507E -:10225000020D013400000050020D013C0000005B43 -:10226000020D014400000050020D01180000007929 -:10227000020D01200000007A020D0128000000700C -:10228000020D013000000070020D013800000070E6 -:10229000020D01400000007B020D014800000070AB -:1022A000060E200000000800020E004C0000003264 -:1022B000020E009402150020020E00980215002064 -:1022C000020E009C00000030020E00A0081000006A -:1022D000020E00A400000036020E00A8000000302C -:1022E000020E00AC00000031020E00B4000000033A -:1022F000020E00B800000000020E00C40000000042 -:10230000020E00CC00000006020E00D80000000102 -:10231000020E014400000001020E014C0000000109 -:10232000020E015000000002020E02040000000133 -:10233000020E020C00000040020E021000000040DD -:10234000020E021C00000004020E02200000002009 -:10235000020E02240000000E020E02280000001BE4 -:10236000060E030000000012040E0280001B04177A -:10237000060E02EC00000005020E00540000000CE6 -:10238000020E00580000000C020E005C000000006D -:10239000020E006000000010020E00640000001039 -:1023A000060E006800000003020E00DC00000003BF -:1023B000020E000400000001020E000800000001EF -:1023C000020E000C00000001020E001000000001CF -:1023D000020E001400000001020E001800000001AF -:1023E000020E001C00000001020E0020000000018F -:1023F000020E002400000001020E0028000000016F -:10240000020E002C00000001020E0030000000014E -:10241000020E003400000001020E0038000000012E -:10242000020E003C00000001020E0040000000010E -:10243000020E004400000001020E01100000000F17 -:10244000020E011800000000020E01200000000032 -:10245000020E012800000000020E01140000002FEF -:10246000020E011C00000020020E012400000020CA -:10247000020E012C00000020020E01100000001FBF -:10248000020E011800000010020E012000000010D2 -:10249000020E012800000010020E01140000003F8F -:1024A000020E011C00000030020E0124000000306A -:1024B000020E012C00000030020E01100000004F3F -:1024C000020E011800000040020E01200000004032 -:1024D000020E012800000040020E01140000006FEF -:1024E000020E011C00000060020E012400000060CA -:1024F000020E012C00000060020E01100000005FBF -:10250000020E011800000050020E012000000050D1 -:10251000020E012800000050020E01140000007F8E -:10252000020E011C00000070020E01240000007069 -:10253000020E012C000000700730040000D60000DD -:10254000083007D80005043207340000322A0000A2 -:102550000734800031300C8B0735000038D018D894 -:10256000073580002F82270D07360000263632EE11 -:102570000836710031E00434023000BC0000003045 -:1025800001300000000000000130000400000000E5 -:1025900001300008000000000130000C00000000C5 -:1025A00001300010000000000130001400000000A5 -:1025B0000230002000000001023000240000000270 -:1025C00002300028000000030230002C0000000050 -:1025D000023000300000000402300034000000012E -:1025E00002300038000000000230003C0000000112 -:1025F00002300040000000040230004400000000EF -:1026000002300048000000010230004C00000003CE -:1026100002300050000000000230005400000001B1 -:1026200002300058000000040230005C000000008E -:10263000023000600000000102300064000000036E -:1026400002300068000000000230006C0000000151 -:10265000023000700000000402300074000000002E -:1026600002300078000000040230007C000000030B -:102670000630008000000002023000A400007FFF4E -:10268000023000A8000003FF023002240000000016 -:1026900002300234000000000230024C0000000052 -:1026A000023002E40000FFFF0630200000000800B6 -:1026B00002338BC000000001023380000000001ACA -:1026C000023380400000004E023380800000001082 -:1026D000023380C0000000200C33830000086470C7 -:1026E0000A338300000001570B3383000000055FAD -:1026F0000A338340000000000C33834000000226B0 -:102700000B338340000000010233838000086470B3 -:10271000023383C00000022602331480000000014F -:102720000A3314800000000006328000000001021D -:1027300006322008000000C8063220000000000217 -:1027400004328520008F04360632875C00000009C1 -:1027500006323EB00000000606323ED00000000205 -:1027600006323E800000000A04323EA8000204C582 -:1027700006323E00000000200632500000000940F2 -:102780000632400000000004043294C0000204C776 -:1027900006324110000000020632D0000000007036 -:1027A0000632DB00000000D40632DEA0000000028A -:1027B0000632E00000000800063324000000011883 -:1027C0000632100000000188063250000000002090 -:1027D00006325100000000200632520000000020A6 -:1027E0000632530000000020063254000000002092 -:1027F000063255000000002006325600000000207E -:102800000632570000000020063258000000002069 -:10281000063259000000002006325A000000002055 -:1028200006325B000000002006325C000000002041 -:1028300006325D000000002006325E00000000202D -:1028400006325F0000000020063284F00000000223 -:1028500004328500000204C9063285080000000227 -:102860000632DE90000000020633286000000118E6 -:102870000632162000000188063250800000002039 -:1028800006325180000000200632528000000020F5 -:1028900006325380000000200632548000000020E1 -:1028A00006325580000000200632568000000020CD -:1028B00006325780000000200632588000000020B9 -:1028C000063259800000002006325A8000000020A5 -:1028D00006325B800000002006325C800000002091 -:1028E00006325D800000002006325E80000000207D -:1028F00006325F8000000020063284F800000002EB -:1029000004328510000204CB063285180000000254 -:102910000632DE98000000020232845000000000FF -:102920000632401000000002023284540000000011 -:1029300006324020000000020232845800000000ED -:1029400006324030000000020232845C00000000C9 -:1029500006324040000000020232846000000000A5 -:102960000632405000000002023284640000000081 -:10297000063240600000000202328468000000005D -:1029800006324070000000020232846C0000000039 -:10299000063240800000000207200400007300009F -:1029A00008200780001004CD072400002AF1000051 -:1029B0000724800027670ABD0824D35063FC04CF96 -:1029C000022000BC000000300120000000000000D8 -:1029D00001200004000000000120000800000000A9 -:1029E0000120000C00000000012000100000000089 -:1029F000012000140000000002200020000000015F -:102A00000220002400000002022000280000000331 -:102A10000220002C00000000022000300000000412 -:102A200002200034000000010220003800000000F5 -:102A30000220003C000000010220004000000004D1 -:102A400002200044000000000220004800000001B5 -:102A50000220004C00000003022000500000000093 -:102A60000220005400000001022000580000000471 -:102A70000220005C00000000022000600000000155 -:102A80000220006400000003022000680000000033 -:102A90000220006C00000001022000700000000411 -:102AA00002200074000000000220007800000004F2 -:102AB0000220007C000000030620008000000002CD -:102AC000022000A400007FFF022000A8000003FFF6 -:102AD0000220022400000000022002340000000056 -:102AE0000220024C00000000022002E40000FFFF70 -:102AF000062020000000080002238BC00000000117 -:102B00000223800000000010022380400000001219 -:102B10000223808000000030022380C00000000EED -:102B20000C238300000864700A238300000001570F -:102B30000B2383000000055F0A2383400000000090 -:102B40000C238340000002260B2383400000000179 -:102B50000223838000086470022383C000000226E1 -:102B600002231480000000010A23148000000000EA -:102B7000062210000000004206222008000000C8C3 -:102B800006222000000000020622B00000000330F0 -:102B90000622F400000000530422F54C000104D189 -:102BA0000622F550000000030422F55C000104D267 -:102BB0000622F560000000030422F56C000104D336 -:102BC0000622F570000000030422F57C000104D405 -:102BD0000622F580000000030422F58C000104D5D4 -:102BE0000622F590000000030422F59C000104D6A3 -:102BF0000622F5A0000000030422F5AC000104D772 -:102C00000622F5B0000000030422F5BC000104D840 -:102C10000622F5C0000000460622E2000000044043 -:102C200004221240009004D906223000000000C0A7 -:102C30000622670000000100062290000000040048 -:102C400004226B0800200569062211F0000000062E -:102C50000422120800060589062212200000000244 -:102C600006224000000005C00622C0000000000649 -:102C70000422C0180006058F0622C0300000000A9A -:102C80000422C058000605950622C0700000000A04 -:102C90000422C0980006059B0622C0B00000000A6E -:102CA0000422C0D8000605A10622C0F00000000AD8 -:102CB0000422C118000605A70622C1300000000A40 -:102CC0000422C158000605AD0622C1700000000AAA -:102CD0000422C198000605B30622C1B00000000A14 -:102CE0000422C1D8000605B90622C1F00000000A7E -:102CF0000422C218000605BF0622C2300000000AE6 -:102D00000422C258000605C50622C2700000000A4F -:102D10000422C298000605CB0622C2B00000000AB9 -:102D20000422C2D8000605D10622C2F00000000A23 -:102D30000422C318000605D70622C3300000000A8B -:102D40000422C358000605DD0622C3700000000AF5 -:102D50000422C398000605E30622C3B00000000A5F -:102D60000422C3D8000605E90622C3F00000000AC9 -:102D70000422C418000605EF0622C4300000000A31 -:102D80000422C458000605F50622C4700000000A9B -:102D90000422C498000605FB0622C4B00000000A05 -:102DA0000422C4D8000606010622C4F00000000A6E -:102DB0000422C518000606070622C5300000000AD6 -:102DC0000422C5580006060D0622C5700000000A40 -:102DD0000422C598000606130622C5B00000000AAA -:102DE0000422C5D8000606190622C5F00000000A14 -:102DF0000422C6180006061F0622C6300000000A7C -:102E00000422C658000606250622C6700000000AE5 -:102E10000422C6980006062B0622C6B00000000A4F -:102E20000422C6D8000606310622C6F00000000AB9 -:102E30000422C718000606370622C7300000000A21 -:102E40000422C7580006063D0622C7700000000A8B -:102E50000422C798000606430622C7B00000000AF5 -:102E60000422C7D8000606490622C7F00000000A5F -:102E70000422C8180006064F0622C8300000000AC7 -:102E80000422C858000606550622C8700000000A31 -:102E90000422C8980006065B0622C8B00000000A9B -:102EA0000422C8D8000606610622C8F00000000A05 -:102EB0000422C918000606670622C9300000000A6D -:102EC0000422C9580006066D0622C9700000000AD7 -:102ED0000422C998000606730622C9B00000000A41 -:102EE0000422C9D8000606790622C9F00000000AAB -:102EF0000422CA180006067F0622CA300000000A13 -:102F00000422CA58000606850622CA700000000A7C -:102F10000422CA980006068B0622CAB00000000AE6 -:102F20000422CAD8000606910622CAF00000000A50 -:102F30000422CB18000606970622CB300000000AB8 -:102F40000422CB580006069D0622CB700000000A22 -:102F50000422CB98000606A30622CBB00000000A8C -:102F60000422CBD8000606A90622CBF00000000AF6 -:102F70000422CC18000606AF0622CC300000000A5E -:102F80000422CC58000606B50622CC700000000AC8 -:102F90000422CC98000606BB0622CCB00000000A32 -:102FA0000422CCD8000606C10622CCF00000000A9C -:102FB0000422CD18000606C70622CD300000000A04 -:102FC0000422CD58000606CD0622CD700000000A6E -:102FD0000422CD98000606D30622CDB00000000AD8 -:102FE0000422CDD8000606D90622CDF00000000A42 -:102FF0000422CE18000606DF0622CE300000000AAA -:103000000422CE58000606E50622CE700000000A13 -:103010000422CE98000606EB0622CEB00000000A7D -:103020000422CED8000606F10622CEF00000000AE7 -:103030000422CF18000606F70622CF300000000A4F -:103040000422CF58000606FD0622CF700000000AB9 -:103050000422CF98000607030622CFB00000000A22 -:103060000422CFD8000607090622CFF00000000A8C -:103070000422D0180006070F0622D0300000000AF4 -:103080000422D058000607150622D0700000000A5E -:103090000422D0980006071B0622D0B00000000AC8 -:1030A0000422D0D8000607210622D0F00000000A32 -:1030B0000422D118000607270622D1300000000A9A -:1030C0000422D1580006072D0622D1700000000A04 -:1030D0000422D198000607330622D1B00000000A6E -:1030E0000422D1D8000607390622D1F00000000AD8 -:1030F0000422D2180006073F0622D2300000000A40 -:103100000422D258000607450622D2700000000AA9 -:103110000422D2980006074B0622D2B00000000A13 -:103120000422D2D8000607510622D2F00000000A7D -:103130000422D318000607570622D3300000000AE5 -:103140000422D3580006075D0622D3700000000A4F -:103150000422D398000607630622D3B00000000AB9 -:103160000422D3D8000607690622D3F00000000A23 -:103170000422D4180006076F0622D4300000000A8B -:103180000422D458000607750622D4700000000AF5 -:103190000422D4980006077B0622D4B00000000A5F -:1031A0000422D4D8000607810622D4F00000000AC9 -:1031B0000422D518000607870622D5300000000A31 -:1031C0000422D5580006078D0622D5700000000A9B -:1031D0000422D598000607930622D5B00000000A05 -:1031E0000422D5D8000607990622D5F00000000A6F -:1031F0000422D6180006079F0622D6300000000AD7 -:103200000422D658000607A50622D6700000000A40 -:103210000422D698000607AB0622D6B00000000AAA -:103220000422D6D8000607B10622D6F00000000A14 -:103230000422D718000607B70622D7300000000A7C -:103240000422D758000607BD0622D7700000000AE6 -:103250000422D798000607C30622D7B00000000A50 -:103260000422D7D8000607C90622D7F00000000ABA -:103270000422D818000607CF0622D8300000000A22 -:103280000422D858000607D50622D8700000000A8C -:103290000422D898000607DB0622D8B00000000AF6 -:1032A0000422D8D8000607E10622D8F00000000A60 -:1032B0000422D918000607E70622D9300000000AC8 -:1032C0000422D958000607ED0622D9700000000A32 -:1032D0000422D998000607F30622D9B00000000A9C -:1032E0000422D9D8000607F90622D9F00000000A06 -:1032F0000422DA18000607FF0622DA300000000A6E -:103300000422DA58000608050622DA700000000AD6 -:103310000422DA980006080B0622DAB00000000A40 -:103320000422DAD8000608110622DAF00000000AAA -:103330000422DB18000608170622DB300000000A12 -:103340000422DB580006081D0622DB700000000A7C -:103350000422DB98000608230622DBB00000000AE6 -:103360000422DBD8000608290622DBF00000000A50 -:103370000422DC180006082F0622DC300000000AB8 -:103380000422DC58000608350622DC700000000A22 -:103390000422DC980006083B0622DCB00000000A8C -:1033A0000422DCD8000608410622DCF00000000AF6 -:1033B0000422DD18000608470622DD300000000A5E -:1033C0000422DD580006084D0622DD700000000AC8 -:1033D0000422DD98000608530622DDB00000000A32 -:1033E0000422DDD8000608590622DDF00000000A9C -:1033F0000422DE180006085F0622DE300000000A04 -:103400000422DE58000608650622DE700000000A6D -:103410000422DE980006086B0622DEB00000000AD7 -:103420000422DED8000608710622DEF00000000A41 -:103430000422DF18000608770622DF300000000AA9 -:103440000422DF580006087D0622DF700000000A13 -:103450000422DF98000608830622DFB00000000A7D -:103460000422DFD8000608890622DFF00000000AE7 -:103470000422E0180006088F0622E0300000000A4F -:103480000422E058000608950622E0700000000AB9 -:103490000422E0980006089B0622E0B00000000A23 -:1034A0000422E0D8000608A10622E0F00000000A8D -:1034B0000422E118000608A70622E1300000000AF5 -:1034C0000422E158000608AD0622E1700000000A5F -:1034D0000422E198000608B30622E1B00000000AC9 -:1034E0000422E1D8000608B90622E1F00000000439 -:1034F0000622153800000002062211E80000000232 -:103500000622F3000000000802221148000000001B -:1035100006225900000000060622330000000002C7 -:1035200006226040000000300622F3200000000860 -:103530000222114C0000000006225918000000066B -:10354000062233080000000206226100000000305D -:103550000622F34000000008022211500000000083 -:103560000622593000000006062233100000000237 -:10357000062261C0000000300622F360000000084F -:1035800002221154000000000622594800000006E3 -:10359000062233180000000206226280000000307C -:1035A0000622F380000000080222115800000000EB -:1035B00006225960000000060622332000000002A7 -:1035C00006226340000000300622F3A0000000083D -:1035D0000222115C0000000006225978000000065B -:1035E000062233280000000206226400000000309A -:1035F0000622F3C000000008022211600000000053 -:103600000622599000000006062233300000000216 -:10361000062264C0000000300622F3E0000000082B -:103620000222116400000000062259A800000006D2 -:1036300006223338000000020622658000000030B8 -:103640000216100000000028021700080000000207 -:103650000217002C000000030217003C00000004C9 -:10366000021700440000000002170048000000029A -:103670000217004C0000009002170050000000905C -:103680000217005400800090021700580810000034 -:10369000021700700000000602170078000009FF02 -:1036A0000217007C0000076C021701C4081000001C -:1036B0000217034400000001021704000000008A02 -:1036C00002170404000000800217040800000081B3 -:1036D0000217040C00000080021704100000008A8A -:1036E0000217041400000080021704180000008173 -:1036F0000217041C00000080021704300000008A3A -:103700000217043400000080021704380000008112 -:103710000217043C00000080021704400000008AE9 -:1037200002170444000000800217044800000081D2 -:103730000217044C00000080021704800000008A79 -:103740000217048400000080021704880000008132 -:103750000217048C0000008002170038007C10045F -:10376000021700040000000F021701EC0000000225 -:10377000021701F400000002021701EC0000000231 -:10378000021701F400000002021701EC0000000221 -:10379000021701F400000002021701EC0000000211 -:1037A000021701F400000002021701EC0000000201 -:1037B000021701F400000002021701EC00000002F1 -:1037C000021701F400000002021701EC00000002E1 -:1037D000021701F400000002021701EC00000002D1 -:1037E000021701F400000002061640240000000247 -:1037F000021640700000001C021642080000000182 -:1038000002164210000000010216422000000001D2 -:10381000021642280000000102164230000000019A -:103820000216423800000001021642600000000249 -:103830000C16401C0003D0900A16401C0000009C8F -:103840000B16401C000002710216403000000028D8 -:10385000021640340000002C0216403800000030F0 -:103860000216404400000020021640000000000143 -:10387000021640D8000000010216400800000001B6 -:103880000216400C0000000102164010000000016A -:1038900002164240000000000216424800000000EC -:1038A000061642700000000202164250000000009E -:1038B0000216425800000000061642800000000276 -:1038C00002166008000012140216600C00001200BC -:1038D00002166010000012040216601C0000FFFFB8 -:1038E000021660200000FFFF021660240000FFFFA8 -:1038F000021660280000FFFF02166038000000205A -:103900000216603C00000010061660400000000235 -:1039100002166048000000230216604C00000024DC -:1039200002166050000000250216605400000026B8 -:1039300002166058000000270216605C00000011AB -:103940000216606000000000021660640000002B98 -:10395000021660680000002C0216606C0000002D4A -:1039600002166070000000EC021660740000000097 -:1039700002166078000000290216607C0000002A10 -:10398000021660800000002F061660840000000D03 -:10399000021660B800000001061660BC00000008B6 -:1039A000021660DC00000001061660E00000000462 -:1039B000021660F000000001061660F4000000032B -:1039C0000216610000000001061661040000002DCF -:1039D000021661B800000001061661BC0000000874 -:1039E000021661DC00000001061661E00000000420 -:1039F000021661F000000001061661F400000003E9 -:103A00000216620000000001061662040000000DAC -:103A10000216623807FFFFFF0216623C0000007FBB -:103A20000216624007FFFFFF021662440000003FDB -:103A300001166248000000000116624C0000000000 -:103A400001166250000000000116625400000000E0 -:103A500001166258000000000116625C00000000C0 -:103A600001166260000000000116626400000000A0 -:103A700001166268000000000116626C0000000080 -:103A80000116627000000000011662740000000060 -:103A900001166278000000000116627C0000000040 -:103AA000011662D400000000021662D80000FFFF79 -:103AB000021662DC0000FFFF021662E00000FFFF5A -:103AC000021662E40000FFFF0C166000000003E82D -:103AD0000A166000000000010B16600000000003E1 -:103AE0000216804000000006021680440000000517 -:103AF000021680480000000A0216804C00000005F3 -:103B00000216805400000002021680CC000000045F -:103B1000021680D000000004021680D400000004C9 -:103B2000021680D800000004021680DC00000004A9 -:103B3000021680E000000004021680E40000000489 -:103B4000021680E800000004021688040000000647 -:103B5000021680300000007C021680340000003D18 -:103B6000021680380000003F0216803C0000009CD6 -:103B70000216E6E8000060000216E6EC00006000B5 -:103B80000216E6F0000060000216E6F40000600095 -:103B900002168234000025E40216823800008000FC -:103BA00002168094000025E3021681F400000C0840 -:103BB000021681F800000040021681FC000001009E -:103BC0000216820000000020021682040000001786 -:103BD00002168208000000800216820C000002001B -:103BE00002168210000000000216823C0000001342 -:103BF00002168220008F008F0216821C008F008F19 -:103C0000021680F0000000070216821801FF01FF73 -:103C10000216821401FF01FF061680F40000000264 -:103C20000216811C0000000502168120000000051C -:103C300002168124000000050216812800000008F9 -:103C40000216812C000000060216813000000007D9 -:103C50000616813400000004021680FC00000000FB -:103C600006168144000000020216814C0000000488 -:103C7000021681500000000102168154000000026B -:103C800002168158000000050216815C0000000544 -:103C90000216816000000005021681640000000524 -:103CA0000216816800000008021681000000000072 -:103CB0000216816C000000060216817000000007E9 -:103CC00006168174000000060216818C00000004B4 -:103CD000021681900000000102168104000000001D -:103CE000021681940000000202168198000000056F -:103CF0000216819C00000005021681A0000000054C -:103D0000021681A400000005021681A80000000828 -:103D1000021681AC00000006021681B00000000708 -:103D2000061681B40000000202168108000000009F -:103D3000061681BC00000004021681CC00000004BD -:103D4000021681D000000001021681D4000000029A -:103D5000021681D800000005021681DC0000000573 -:103D6000021681E0000000050216810C000000042C -:103D7000021681E400000005021681E80000000838 -:103D8000021681EC00000006021681F00000000718 -:103D900002168110000000010216811400000002CA -:103DA00002168118000000050216809C0000004CDD -:103DB000021680A00000004C061680C4000000021D -:103DC000021680A400000000021680A80000000077 -:103DD000021680AC0000004C061680B00000000502 -:103DE0000216E6F80000020402168240003F003F7F -:103DF00002168244003F003F061682900000000435 -:103E000002168248008000800216824C00800080EA -:103E100002168250010001000216825401000100C6 -:103E20000616825800000002021682600040004020 -:103E30000216826400400040021682681E001E00C6 -:103E40000216826C1E001E000216827040004000A6 -:103E500002168274400040000216827880008000C2 -:103E60000216827C800080000216828020002000E2 -:103E700002168284200020000616828800000002BC -:103E8000021680900000004B021680600000014086 -:103E900002168064000001400616808800000002BF -:103EA00002168068000000000216806C000000000E -:103EB00002168070000000C0061680740000000525 -:103EC0000216880C0101010102168810010120046C -:103ED000021688142008100102168818010101201A -:103EE0000216881C0101010102168820010120042C -:103EF00002168824200810010216882801010120DA -:103F00000216882C200810010216883001010120B9 -:103F100002168834010101010216883801012004CB -:103F20000216883C20081001021688400101012079 -:103F3000021688440101010102168848010120048B -:103F40000216E6BC000000000216E6C000000002F7 -:103F50000216E6C4000000040216E6C800000006CF -:103F60000216E79400000001021680EC000000FF3A -:103F700002140000000000010215C024000000002F -:103F80000215C0EC000000010215C0F000000001A5 -:103F90000615C10000000002021400040000000128 -:103FA00002140008000000010214000C00000001CF -:103FB000021400300000000102140034000000016F -:103FC0000214004000000001021400440000FFFF42 -:103FD00006140004000000030214000000000000AA -:103FE000060280000000200002020058000000329B -:103FF000020200A003150020020200A40315002005 -:10400000020200A801000030020200AC081000000B -:10401000020200B000000036020200B400000030CE -:10402000020200B800000031020200BC00000002E1 -:10403000020200C000000005020200C400000002ED -:10404000020200C800000002020200D000000007C7 -:10405000020200DC00000000020200E00000000597 -:10406000020200E400000003020200F00000000170 -:10407000020200FC00000006020201200000000015 -:104080000202013400000002020201B0000000013F -:104090000202020C000000010202021400000001F2 -:1040A00002020218000000020202040400000001E3 -:1040B0000202040C00000040020204100000004054 -:1040C0000202041C00000004020204200000002080 -:1040D0000202042400000002020204280000002062 -:1040E000060205000000001204020480002008BF40 -:1040F000020200600000000F0202006400000007DE -:1041000002020068000000000202006C0000000EC5 -:10411000020200700000000E06020074000000039E -:10412000020200F40000000402020004000000018A -:1041300002020008000000010202000C0000000161 -:104140000202001000000001020200140000000141 -:1041500002020018000000010202001C0000000121 -:104160000202002000000001020200240000000101 -:1041700002020028000000010202002C00000001E1 -:1041800002020030000000010202003400000001C1 -:1041900002020038000000010202003C00000001A1 -:1041A0000202004000000001020200440000000181 -:1041B00002020048000000010202004C0000000161 -:1041C000020200500000000102020108000000C8C5 -:1041D0000202011800000002020201C400000000F7 -:1041E000020201CC00000000020201D40000000223 -:1041F000020201DC00000002020201E4000000FFF4 -:10420000020201EC000000FF0202010000000000B9 -:104210000202010C000000C80202011C00000002A2 -:10422000020201C800000000020201D000000000EC -:10423000020201D800000002020201E000000002B8 -:10424000020201E8000000FF020201F0000000FF8E -:10425000020201040000002002020108000000C860 -:104260000202011800000002020201C40000000066 -:10427000020201CC00000000020201D40000000292 -:10428000020201DC00000002020201E4000000FF63 -:10429000020201EC000000FF020201000000001019 -:1042A0000202010C000000C80202011C0000000212 -:1042B000020201C800000000020201D0000000005C -:1042C000020201D800000002020201E00000000228 -:1042D000020201E8000000FF020201F0000000FFFE -:1042E000020201040000003002020108000000C8C0 -:1042F0000202011800000002020201C400000000D6 -:10430000020201CC00000000020201D40000000201 -:10431000020201DC00000002020201E4000000FFD2 -:10432000020201EC000000FF020201000000004058 -:104330000202010C000000C80202011C0000000281 -:10434000020201C800000000020201D000000000CB -:10435000020201D800000002020201E00000000297 -:10436000020201E8000000FF020201F0000000FF6D -:10437000020201040000006002020108000000C8FF -:104380000202011800000002020201C40000000045 -:10439000020201CC00000000020201D40000000271 -:1043A000020201DC00000002020201E4000000FF42 -:1043B000020201EC000000FF0202010000000050B8 -:1043C0000202010C000000C80202011C00000002F1 -:1043D000020201C800000000020201D0000000003B -:1043E000020201D800000002020201E00000000207 -:1043F000020201E8000000FF020201F0000000FFDD -:1044000002020104000000700728040000B500004B -:10441000082807B8000908DF072C000028E9000079 -:10442000072C800036700A3B072D000035BE17D8D8 -:10443000072D80003B1B2548072E000035D8340F80 -:10444000072E80001B224186082EBFD0280608E1D7 -:10445000022800BC0000003001280000000000001D -:1044600001280004000000000128000800000000EE -:104470000128000C000000000128001000000000CE -:1044800001280014000000000228002000000001A4 -:104490000228002400000002022800280000000377 -:1044A0000228002C00000000022800300000000458 -:1044B000022800340000000102280038000000003B -:1044C0000228003C00000001022800400000000417 -:1044D00002280044000000000228004800000001FB -:1044E0000228004C000000030228005000000000D9 -:1044F00002280054000000010228005800000004B7 -:104500000228005C0000000002280060000000019A -:104510000228006400000003022800680000000078 -:104520000228006C00000001022800700000000456 -:104530000228007400000000022800780000000437 -:104540000228007C00000003062800800000000212 -:10455000022800A400007FFF022800A8000003FF3B -:10456000022802240000000002280234000000009B -:104570000228024C00000000022802E40000FFFFB5 -:104580000628200000000800022B8BC0000000015C -:10459000022B800000000000022B80400000001869 -:1045A000022B80800000000C022B80C000000066FF -:1045B0000C2B8300000864700A2B83000000015755 -:1045C0000B2B83000000055F0A2B834000000000D6 -:1045D0000C2B8340000002260B2B834000000001BF -:1045E000022B838000086470022B83C00000022627 -:1045F000022B1480000000010A2B14800000000030 -:10460000022B944000000001062B94480000000299 -:10461000062A9A7000000004042A9A80000408E325 -:10462000062A9A9000000002042A9A98000208E7DD -:10463000062A900000000048062A2008000000C852 -:10464000062A200000000002062A912800000086A9 -:10465000062AC00000000120062A9348000000033B -:10466000042A9354000108E9062A9FB000000002C2 -:10467000042A9418000208EA042A9CD0000108ECDD -:10468000062A9CD400000011042A9D20008F08ED0A -:10469000062A9F5C00000005042A30000002097C05 -:1046A000062A300800000100062A404000000010E1 -:1046B000042A40000010097E042A84080002098EA2 -:1046C000042ACF4000040990042ACF600002099414 -:1046D000062A9FA000000004062A60000000054092 -:1046E000062A9D1800000002062AB00000000050B3 -:1046F000062ABB7000000070062ABB68000000029A -:10470000062AB94800000004062AD000000008006C -:10471000062AC48000000150062A942000000032BE -:10472000062A502000000002062A50300000000235 -:10473000062A500000000002062A50100000000265 -:10474000022A520800000001042A9AA000020996D9 -:10475000062A95B000000022042A96380001099824 -:10476000062A963C00000003062A96E0000000227C -:10477000042A976800010999062A976C0000000333 -:10478000062A981000000022042A98980001099A2D -:10479000062A989C00000003062A99400000002287 -:1047A000042A99C80001099B062A99CC000000033D -:1047B000062ABB5800000002062AC9C000000150AA -:1047C000062A94E800000032062A50280000000261 -:1047D000062A503800000002062A50080000000295 -:1047E000062A501800000002022A520C00000001A4 -:1047F000042A9AA80002099C062A96480000002272 -:10480000042A96D00001099E062A96D400000003CF -:10481000062A977800000022042A98000001099FC8 -:10482000062A980400000003062A98A80000002227 -:10483000042A9930000109A0062A993400000003D7 -:10484000062A99D800000022042A9A60000109A1D2 -:10485000062A9A6400000003062ABB6000000002DA -:10486000022ACF0000000000042A9AB0001009A21A -:10487000062A50480000000E022ACF040000000063 -:10488000042A9AF0001009B2062A50800000000E97 -:10489000022ACF0800000000042A9B30001009C241 -:1048A000062A50B80000000E022ACF0C00000000BB -:1048B000042A9B70001009D2062A50F00000000E56 -:1048C000022ACF1000000000042A9BB0001009E269 -:1048D000062A51280000000E022ACF140000000012 -:1048E000042A9BF0001009F2062A51600000000E15 -:1048F000022ACF1800000000042A9C3000100A028F -:10490000062A51980000000E022ACF1C0000000069 -:10491000042A9C7000100A12062A51D00000000ED2 -:1049200002101008000000010210105000000001E9 -:10493000021010000003D000021010040000003D1F -:104940000910180002000A220910110000100C22A0 -:1049500006101140000000080910116000100C3210 -:10496000061011A00000001806102400000000E04E -:104970000210201C00000000021020200000000196 -:10498000021020C0000000020210200400000001FC -:104990000210200800000001021030D800000001C1 -:1049A00009103C0000050C420910380000050C47B6 -:1049B0000910392000050C4C09103B0000050C5172 -:1049C000021040D400000030021040D80000003037 -:1049D00006104C00000001000210402800000010EA -:1049E0000210404400003FFF021040580028000021 -:1049F000021040840084924A0210405800000000D7 -:104A0000021041380000000102104138000000018E -:104A1000021041380000000102104138000000017E -:104A2000021041380000000102104138000000016E -:104A3000021041380000000102104138000000015E -:104A40000212049001F680400212051400003C108E -:104A500002120494FFFFFFFF02120498FFFFFFFF02 -:104A60000212049CFFFFFFFF021204A0FFFFFFFFE2 -:104A7000021204A4FFFFFFFF021204A8FFFFFFFFC2 -:104A8000021204ACFFFFFFFF021204B0FFFFFFFFA2 -:104A9000021204B8FFFFFFFF021204BCFFFFFFFF7A -:104AA000021204C0FFFFFFFF021204C4FFFFFFFF5A -:104AB000021204C8FFFFFFFF021204CCFFFFFFFF3A -:104AC000021204D0FFFFFFFF021204D8FFFFFFFF16 -:104AD000021204DCFFFFFFFF021204E0FFFFFFFFF2 -:104AE000021204E4FFFFFFFF021204E8FFFFFFFFD2 -:104AF000021204ECFFFFFFFF021204F0FFFFFFFFB2 -:104B0000021204F4FFFFFFFF021204F8FFFFFFFF91 -:104B1000021204FCFFFFFFFF02120500FFFFFFFF70 -:104B200002120504FFFFFFFF02120508FFFFFFFF4F -:104B30000212050CFFFFFFFF02120510FFFFFFFF2F -:104B4000021204D4F800C000021204B4F0005000B5 -:104B500002120390000000080212039C00000008EB -:104B6000021203A000000008021203A400000002C9 -:104B7000021203BC00000004021203C00000000582 -:104B8000021203C400000004021203D0000000005F -:104B90000212036C00000001021201BC0000004080 -:104BA000021201C000001808021201C4000008032C -:104BB000021201C800000803021201CC00000040EC -:104BC000021201D000000003021201D40000080309 -:104BD000021201D800000803021201DC00000803E1 -:104BE000021201E000010003021201E400000803C8 -:104BF000021201E800000803021201EC00000003A9 -:104C0000021201F000000003021201F40000000390 -:104C1000021201F800000003021201FC0000000370 -:104C2000021202000000000302120204000000034E -:104C300002120208000000030212020C000000032E -:104C4000021202100000000302120214000000030E -:104C500002120218000000030212021C00000003EE -:104C600002120220000000030212022400000003CE -:104C700002120228000024030212022C0000002F5E -:104C80000212023000000009021202340000001972 -:104C900002120238000001840212023C000001836B -:104CA0000212024000000306021202440000001932 -:104CB00002120248000000060212024C0000030625 -:104CC0000212025000000306021202540000030602 -:104CD0000212025800000C860212025C0000030659 -:104CE00002120260000003060212026400000006C5 -:104CF00002120268000000060212026C00000006A8 -:104D00000212027000000006021202740000000687 -:104D100002120278000000060212027C0000000667 -:104D20000212028000000006021202840000000647 -:104D300002120288000000060212028C0000000627 -:104D40000212029000000006021202940000000607 -:104D500002120298000000060212029C00000006E7 -:104D6000021202A000000306021202A400000013B7 -:104D7000021202A800000006021202B00000100495 -:104D8000021202B400001004021203240010644056 -:104D90000212032800106440021205B40000000152 -:104DA000021205F800000040021205FC0000001984 -:104DB00002120600000000010212066C0000000151 -:104DC000021201B000000001021207D80000000327 -:104DD000021207D800000003021207D800000003E7 -:104DE000021207D800000003021207D800000003D7 -:104DF000021207D800000003021207D800000003C7 -:104E0000021207D8000000030600A0000000000CFA -:104E10000200A050000000000200A05400000000AA -:104E20000200A0EC555400000200A0F05555555565 -:104E30000200A0F4000055550200A0F8F0000000A8 -:104E40000200A0FC555400000200A1005555555524 -:104E50000200A104000055550200A108F000000066 -:104E60000200A19C000000000200A1A000010000BF -:104E70000200A1A4000050140200A1A8000000003C -:104E80000200A6A8000000000200A6AC000000007E -:104E90000200A6D0000000000200A45C00000C008C -:104EA0000200A61C000000030200A070FFF55FFFD7 -:104EB0000200A0740000FFFF0200A078F00003E0F1 -:104EC0000200A07C000000000200A0800000A00002 -:104ED0000600A084000000050200A0980FE000007A -:104EE0000600A09C000000070200A0B8000004001B -:104EF0000600A0BC000000030200A0C800001000D3 -:104F00000600A0CC000000030200A0D80000400072 -:104F10000600A0DC000000030200A0E80001000081 -:104F20000600A22C000000040200A688000000FC7D -:104F30000600A68C000000070200A6F40000000096 -:104F40000200A10CFF5C00000200A110FFF55FFF52 -:104F50000200A1140000FFFF0200A118F00003E00E -:104F60000200A11C000000000200A1200000A0001F -:104F70000600A124000000050200A1380FE0000097 -:104F80000600A13C000000070200A1580000080034 -:104F90000600A15C000000030200A16800002000E0 -:104FA0000600A16C000000030200A1780000800050 -:104FB0000600A17C000000030200A188000200009E -:104FC0000600A23C000000040200A6B0000000FCA5 -:104FD0000600A6B4000000070200A6F800000000CA -:104FE0000200A030000000000200A0340000000019 -:104FF0000200A038000000000200A03C00000000F9 -:105000000200A040000000000200A04400000000D8 -:105010000200A048000000000200A04C00000000B8 -:10502000020090C40000E000020090CC0000F300F9 -:10503000020090D400000003020091A000000001D3 -:105040000600917000000003020090EC0000600078 -:10505000020090F400007300020090FC00000003C6 -:10506000020091A8000000010600918800000003E2 -:10507000020091000000400002009108000053006F -:105080000200911000000004020091AC0000000139 -:1050900006009194000000020200919C00000001B3 -:1050A000020090D800006000020090E00000730051 -:1050B000020090E800000003020091A4000000013B -:1050C0000200917C000000010200918000000001BC -:1050D00002009184000000000200912800000300FB -:1050E0000200916C0003F0080200912C0000030004 -:1050F0000200913000000300020091340000030020 -:1051000002009138000003000200913C00000300FF -:1051100002009140000003000200942C00000001F6 -:1051200002009430000000010200943400000001ED -:105130000200942C000000010200943000000001E5 -:1051400002009434000000010200942C00000001D1 -:1051500002009430000000010200943400000001BD -:105160000200942C000000010200943000000001B5 -:1051700002009434000000010200942C00000001A1 -:10518000020094300000000102009434000000018D -:105190000200942C00000001020094300000000185 -:1051A00002009434000000010200942C0000000171 -:1051B000020094300000000102009434000000015D -:1051C0000200942C00000001020094300000000155 -:1051D0000200943400000001021300780000003047 -:1051E0000213003C000061A8061301080000000340 -:1051F000021301040000000002130134000000004B -:10520000061301080000000302130104000000005F -:10521000021301340000000006130108000000031F -:10522000021301040000000002130134000000001A -:10523000061301080000000302130104000000002F -:1052400002130134000000000613010800000003EF -:1052500002130104000000000213013400000000EA -:1052600006130108000000030213010400000000FF -:1052700002130134000000000613010800000003BF -:1052800002130104000000000213013400000000BA -:1052900006130108000000030213010400000000CF -:1052A0000213013400000000021100B800000001E8 -:1052B0000216E6E8000020000216E6EC00002000DE -:1052C0000216E6F0000065550216E6F4000065558A -:1052D00002168150000000000216817400000001D7 -:1052E00002168178000000010216817C0000000196 -:1052F0000216818000000001021681840000000176 -:105300000216818800000001021681B4000000012D -:10531000021681B800000001021681BC00000001E5 -:10532000021681C000000001021681C400000001C5 -:10533000021681C800000001021681100000000062 -:105340000216824000BF00BF061682440000000221 -:105350000216824C00BF00BF0216E6C40000000126 -:105360000216E6C8000000030216E79400000000E1 -:10537000042ACF40000A0C56000000000000000084 -:1053800000000034000000000000000000000000E9 -:10539000000000000000000000000000000000000D -:1053A0000000000000000000000000000034003594 -:1053B00000000000000000000000000000000000ED -:1053C00000000000000000000000000000000000DD -:1053D0000000000000000000003500600000000038 -:1053E00000000000000000000000000000000000BD -:1053F00000000000000000000000000000000000AD -:1054000000000000006000910000000000000000AB -:1054100000910095009500990099009D009D00A1C4 -:1054200000A100A500A500A900A900AD00AD00B134 -:1054300000B100B500000000000000000000000006 -:10544000000000000000000000000000000000005C -:1054500000000000000000000000000000B5031183 -:105460000311031B031B03250325032C032C033308 -:105470000333033A033A0341034103480348034F0C -:10548000034F03560356035D0000000000000000B8 -:10549000000000000000000000000000000000000C -:1054A00000000000000000000000000000000000FC -:1054B00000000000000000000000000000000000EC -:1054C00000000000000000000000000000000000DC -:1054D00000000000000000000000000000000000CC -:1054E00000000000000000000000000000000000BC -:1054F00000000000000000000000000000000000AC -:10550000000000000000000000000000000000009B -:10551000000000000000000000000000000000008B -:10552000000000000000000000000000000000007B -:105530000000000000000000035D035E00000000AA -:1055400000000000035E035F035F0360036003610C -:10555000036103620362036303630364036403651B -:10556000036503660000000000000000000000006A -:10557000000000000000000000000000000000002B -:10558000000000000000000000000000000000001B -:105590000366036D036D0379037903850000000042 -:1055A00000000000000000000000000000000000FB -:1055B00000000000000000000000000000000000EB -:1055C00000000000000000000000000000000000DB -:1055D00000000000000000000000000000000000CB -:1055E00000000000000000000385038600000000AA -:1055F00000000000000000000000000000000000AB -:10560000000000000000000000000000000000009A -:1056100000000000038603B100000000000000004D -:10562000000000000000000000000000000000007A -:10563000000000000000000000000000000000006A -:1056400003B103E0000000000000000000000000C3 -:10565000000000000000000000000000000000004A -:1056600000000000000000000000000003E0040F44 -:105670000000000000000000040F04160416041DC2 -:10568000041D04240424042B042B043204320439A2 -:1056900004390440044004470447047A0000000031 -:1056A00000000000047A047E047E048204820486E2 -:1056B0000486048A048A048E048E0492049204965A -:1056C0000496049A049A04EA04EA05000500051603 -:1056D000051605180518051A051A051C051C051ED2 -:1056E000051E052005200522052205240524052682 -:1056F00005260693000000000000000006930698AF -:105700000698069D069D06A206A206A706A706AC59 -:1057100006AC06B106B106B606B606BB06BB06BCAD -:105720000000000000000000000000000000000079 -:105730000000000000000000000000000000000069 -:10574000000000000000000006BC06E000000000B1 -:105750000000000006E006E206E206E406E406E6D3 -:1057600006E606E806E806EA06EA06EC06EC06EEB9 -:1057700006EE06F006F00705070507080708070B01 -:105780000000000000000000000000000000000019 -:105790000000000000000000000000000000000009 -:1057A000070B074F00000000000000000000000091 -:1057B00000000000000000000000000000000000E9 -:1057C000000000000000000000000000074F07E19B -:1057D00000000000000000000000000000000000C9 -:1057E00000000000000000000000000000000000B9 -:1057F000000000000000000007E107EF00000000CB -:105800000000000000000000000000000000000098 -:105810000000000000000000000000000000000088 -:105820000000000007EF082C00000000000000004E -:10583000082C08350835083E083E08470847085038 -:1058400008500859085908620862086B086B087408 -:10585000087408D508D508EA08EA08FF08FF090215 -:1058600009020905090509080908090B090B090EB0 -:10587000090E09110911091409140917091709203A -:105880000000000000000000000000000000000018 -:105890000000000000000000000000000000000008 -:1058A00000000000000000000920092600000000A0 -:1058B00000000000000000000000000000000000E8 -:1058C00000000000000000000000000000000000D8 -:1058D000000000000926092B000000000000000065 -:1058E00000000000000000000000000000000000B8 -:1058F00000000000000000000000000000000000A8 -:10590000092B0933000000000000000009330934AE -:10591000093409350935093609360937093709388F -:10592000093809390939093A093A093B00000000E8 -:105930000000000000000000000000000000000067 -:105940000000000000000000000000000000000057 -:105950000000000000000000093B09AC000000004E -:105960000000000009AC09AD09AD09AE09AE09AFF0 -:1059700009AF09B009B009B109B109B209B209B357 -:1059800009B309B409B409C809C809DB09DB09EF7F -:1059900009EF09F009F009F109F109F209F209F337 -:1059A00009F309F409F409F509F509F609F609F707 -:1059B00009F70A1600000000000000000A160A1984 -:1059C0000A190A1C0A1C0A1F0A1F0A220A220A258F -:1059D0000A250A280A280A2B0A2B0A2E0A2E0A3020 -:1059E00000000000000000000A300A330A330A36C3 -:1059F0000A360A390A390A3C0A3C0A3F0A3F0A4277 -:105A00000A420A450A450A480A480A4900000000B5 -:105A10000000000000000000000000000000000086 -:105A20000000000000000000000000000000000076 -:105A3000000000000A490A610000000000000000A8 -:105A40000000000000000000000000000000000056 -:105A50000000000000000000000000000000000046 -:105A60000A610A620000000000000000000000005F -:105A70000000000000000000000000000000000026 -:105A80000000000000000000000000000000000016 -:105A9000000100000002070000030E0000041500D2 -:105AA00000051C000006230000072A000008310042 -:105AB00000093800000A3F00000B4600000C4D00B2 -:105AC000000D5400000E5B00000F62000010690022 -:105AD000001170000012770000137E000014850092 -:105AE00000158C000016930000179A000018A10002 -:105AF0000019A800001AAF00001BB600001CBD0072 -:105B0000001DC400001ECB00001FD2000000D90001 -:105B10000000200000004000000060000000800045 -:105B20000000A0000000C0000000E0000001000034 -:105B30000001200000014000000160000001800021 -:105B40000001A0000001C0000001E0000002000010 -:105B500000022000000240000002600000028000FD -:105B60000002A0000002C0000002E00000030000EC -:105B700000032000000340000003600000038000D9 -:105B80000003A0000003C0000003E00000040000C8 -:105B900000042000000440000004600000048000B5 -:105BA0000004A0000004C0000004E00000050000A4 -:105BB0000005200000054000000560000005800091 -:105BC0000005A0000005C0000005E0000006000080 -:105BD000000620000006400000066000000680006D -:105BE0000006A0000006C0000006E000000700005C -:105BF0000007200000074000000760000007800049 -:105C00000007A0000007C0000007E0000008000037 -:105C10000008200000084000000860000008800024 -:105C20000008A0000008C0000008E0000009000013 -:105C30000009200000094000000960000009800000 -:105C40000009A0000009C0000009E000000A0000EF -:105C5000000A2000000A4000000A6000000A8000DC -:105C6000000AA000000AC000000AE000000B0000CB -:105C7000000B2000000B4000000B6000000B8000B8 -:105C8000000BA000000BC000000BE000000C0000A7 -:105C9000000C2000000C4000000C6000000C800094 -:105CA000000CA000000CC000000CE000000D000083 -:105CB000000D2000000D4000000D6000000D800070 -:105CC000000DA000000DC000000DE000000E00005F -:105CD000000E2000000E4000000E6000000E80004C -:105CE000000EA000000EC000000EE000000F00003B -:105CF000000F2000000F4000000F6000000F800028 -:105D0000000FA000000FC000000FE0000010000016 -:105D10000010200000104000001060000010800003 -:105D20000010A0000010C0000010E00000110000F2 -:105D300000112000001140000011600000118000DF -:105D40000011A0000011C0000011E00000120000CE -:105D500000122000001240000012600000128000BB -:105D60000012A0000012C0000012E00000130000AA -:105D70000013200000134000001360000013800097 -:105D80000013A0000013C0000013E0000014000086 -:105D90000014200000144000001460000014800073 -:105DA0000014A0000014C0000014E0000015000062 -:105DB000001520000015400000156000001580004F -:105DC0000015A0000015C0000015E000001600003E -:105DD000001620000016400000166000001680002B -:105DE0000016A0000016C0000016E000001700001A -:105DF0000017200000174000001760000017800007 -:105E00000017A0000017C0000017E00000180000F5 -:105E100000182000001840000018600000188000E2 -:105E20000018A0000018C0000018E00000190000D1 -:105E300000192000001940000019600000198000BE -:105E40000019A0000019C0000019E000001A0000AD -:105E5000001A2000001A4000001A6000001A80009A -:105E6000001AA000001AC000001AE000001B000089 -:105E7000001B2000001B4000001B6000001B800076 -:105E8000001BA000001BC000001BE000001C000065 -:105E9000001C2000001C4000001C6000001C800052 -:105EA000001CA000001CC000001CE000001D000041 -:105EB000001D2000001D4000001D6000001D80002E -:105EC000001DA000001DC000001DE000001E00001D -:105ED000001E2000001E4000001E6000001E80000A -:105EE000001EA000001EC000001EE000001F0000F9 -:105EF000001F2000001F4000001F6000001F8000E6 -:105F0000001FA000001FC000001FE00000200000D4 -:105F100000202000002040000020600000208000C1 -:105F20000020A0000020C0000020E00000210000B0 -:105F3000002120000021400000216000002180009D -:105F40000021A0000021C0000021E000002200008C -:105F50000022200000224000002260000022800079 -:105F60000022A0000022C0000022E0000023000068 -:105F70000023200000234000002360000023800055 -:105F80000023A0000023C0000023E0000024000044 -:105F90000024200000244000002460000024800031 -:105FA0000024A0000024C0000024E0000025000020 -:105FB000002520000025400000256000002580000D -:105FC0000025A0000025C0000025E00000260000FC -:105FD00000262000002640000026600000268000E9 -:105FE0000026A0000026C0000026E00000270000D8 -:105FF00000272000002740000027600000278000C5 -:106000000027A0000027C0000027E00000280000B3 -:1060100000282000002840000028600000288000A0 -:106020000028A0000028C0000028E000002900008F -:10603000002920000029400000296000002980007C -:106040000029A0000029C0000029E000002A00006B -:10605000002A2000002A4000002A6000002A800058 -:10606000002AA000002AC000002AE000002B000047 -:10607000002B2000002B4000002B6000002B800034 -:10608000002BA000002BC000002BE000002C000023 -:10609000002C2000002C4000002C6000002C800010 -:1060A000002CA000002CC000002CE000002D0000FF -:1060B000002D2000002D4000002D6000002D8000EC -:1060C000002DA000002DC000002DE000002E0000DB -:1060D000002E2000002E4000002E6000002E8000C8 -:1060E000002EA000002EC000002EE000002F0000B7 -:1060F000002F2000002F4000002F6000002F8000A4 -:10610000002FA000002FC000002FE0000030000092 -:10611000003020000030400000306000003080007F -:106120000030A0000030C0000030E000003100006E -:10613000003120000031400000316000003180005B -:106140000031A0000031C0000031E000003200004A -:106150000032200000324000003260000032800037 -:106160000032A0000032C0000032E0000033000026 -:106170000033200000334000003360000033800013 -:106180000033A0000033C0000033E0000034000002 -:1061900000342000003440000034600000348000EF -:1061A0000034A0000034C0000034E00000350000DE -:1061B00000352000003540000035600000358000CB -:1061C0000035A0000035C0000035E00000360000BA -:1061D00000362000003640000036600000368000A7 -:1061E0000036A0000036C0000036E0000037000096 -:1061F0000037200000374000003760000037800083 -:106200000037A0000037C0000037E0000038000071 -:10621000003820000038400000386000003880005E -:106220000038A0000038C0000038E000003900004D -:10623000003920000039400000396000003980003A -:106240000039A0000039C0000039E000003A000029 -:10625000003A2000003A4000003A6000003A800016 -:10626000003AA000003AC000003AE000003B000005 -:10627000003B2000003B4000003B6000003B8000F2 -:10628000003BA000003BC000003BE000003C0000E1 -:10629000003C2000003C4000003C6000003C8000CE -:1062A000003CA000003CC000003CE000003D0000BD -:1062B000003D2000003D4000003D6000003D8000AA -:1062C000003DA000003DC000003DE000003E000099 -:1062D000003E2000003E4000003E6000003E800086 -:1062E000003EA000003EC000003EE000003F000075 -:1062F000003F2000003F4000003F6000003F800062 -:10630000003FA000003FC000003FE000003FE00170 -:1063100000000000000001FF0000020000007FF804 -:1063200000007FF800000A90000035000000000126 -:106330000000FF00000000000000FF00000000005F -:106340000000FF00000000000000FF00000000004F -:106350000000FF00000000000000FF00000000003F -:106360000000FF00000000000000FF00000000002F -:106370000000FF00000000000000FF00000000001F -:106380000000FF00000000000000FF00000000000F -:106390000000FF00000000000000FF0000000000FF -:1063A0000000FF00000000000000FF0000000000EF -:1063B0000000FF00000000000000FF0000000000DF -:1063C0000000FF00000000000000FF0000000000CF -:1063D0000000FF00000000000000FF0000000000BF -:1063E0000000FF00000000000000FF0000000000AF -:1063F0000000FF00000000000000FF00000000009F -:106400000000FF00000000000000FF00000000008E -:106410000000FF00000000000000FF00000000007E -:106420000000FF00000000000000FF00000000006E -:106430000000FF00000000000000FF00000000005E -:106440000000FF00000000000000FF00000000004E -:106450000000FF00000000000000FF00000000003E -:106460000000FF00000000000000FF00000000002E -:106470000000FF00000000000000FF00000000001E -:106480000000FF00000000000000FF00000000000E -:106490000000FF00000000000000FF0000000000FE -:1064A0000000FF00000000000000FF0000000000EE -:1064B0000000FF00000000000000FF0000000000DE -:1064C0000000FF00000000000000FF0000000000CE -:1064D0000000FF00000000000000FF0000000000BE -:1064E0000000FF00000000000000FF0000000000AE -:1064F0000000FF00000000000000FF00000000009E -:106500000000FF00000000000000FF00000000008D -:106510000000FF00000000000000FF00000000007D -:106520000000FF00000000000000FF00000000006D -:106530000000FF00000000000000FF00000000005D -:106540000000FF00000000000000FF00000000004D -:106550000000FF00000000000000FF00000000003D -:106560000000FF00000000000000FF00000000002D -:1065700000000000140AFF000000000100000000FD -:106580000020100100000000010090000000010048 -:1065900000009002000090040000900600009008A7 -:1065A0000000900A0000900C0000900E0000901077 -:1065B0000000901200009014000090160000901847 -:1065C0000000901A0000901C0000901E0000902017 -:1065D00000009022000090240000902600009028E7 -:1065E0000000902A0000902C0000902E00009030B7 -:1065F0000000903200009034000090360000903887 -:106600000000903A0000903C0000903E0000904056 -:106610000000904200009044000090460000904826 -:106620000000904A0000904C0000904E00009050F6 -:1066300000009052000090540000905600009058C6 -:106640000000905A0000905C0000905E0000906096 -:106650000000906200009064000090660000906866 -:106660000000906A0000906C0000906E0000907036 -:106670000000907200009074000090760000907806 -:106680000000907A0000907C0000907E00009080D6 -:1066900000009082000090840000908600009088A6 -:1066A0000000908A0000908C0000908E0000909076 -:1066B0000000909200009094000090960000909846 -:1066C0000000909A0000909C0000909E000090A016 -:1066D000000090A2000090A4000090A6000090A8E6 -:1066E000000090AA000090AC000090AE000090B0B6 -:1066F000000090B2000090B4000090B6000090B886 -:10670000000090BA000090BC000090BE000090C055 -:10671000000090C2000090C4000090C6000090C825 -:10672000000090CA000090CC000090CE000090D0F5 -:10673000000090D2000090D4000090D6000090D8C5 -:10674000000090DA000090DC000090DE000090E095 -:10675000000090E2000090E4000090E6000090E865 -:10676000000090EA000090EC000090EE000090F035 -:10677000000090F2000090F4000090F6000090F805 -:10678000000090FA000090FC000090FE00009100D4 -:1067900000009102000091040000910600009108A1 -:1067A0000000910A0000910C0000910E0000911071 -:1067B0000000911200009114000091160000911841 -:1067C0000000911A0000911C0000911E0000912011 -:1067D00000009122000091240000912600009128E1 -:1067E0000000912A0000912C0000912E00009130B1 -:1067F0000000913200009134000091360000913881 -:106800000000913A0000913C0000913E0000914050 -:106810000000914200009144000091460000914820 -:106820000000914A0000914C0000914E00009150F0 -:1068300000009152000091540000915600009158C0 -:106840000000915A0000915C0000915E0000916090 -:106850000000916200009164000091660000916860 -:106860000000916A0000916C0000916E0000917030 -:106870000000917200009174000091760000917800 -:106880000000917A0000917C0000917E00009180D0 -:1068900000009182000091840000918600009188A0 -:1068A0000000918A0000918C0000918E0000919070 -:1068B0000000919200009194000091960000919840 -:1068C0000000919A0000919C0000919E000091A010 -:1068D000000091A2000091A4000091A6000091A8E0 -:1068E000000091AA000091AC000091AE000091B0B0 -:1068F000000091B2000091B4000091B6000091B880 -:10690000000091BA000091BC000091BE000091C04F -:10691000000091C2000091C4000091C6000091C81F -:10692000000091CA000091CC000091CE000091D0EF -:10693000000091D2000091D4000091D6000091D8BF -:10694000000091DA000091DC000091DE000091E08F -:10695000000091E2000091E4000091E6000091E85F -:10696000000091EA000091EC000091EE000091F02F -:10697000000091F2000091F4000091F6000091F8FF -:10698000000091FA000091FC000091FEFFFFFFFF64 -:10699000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF07 -:1069A000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7 -:1069B000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE7 -:1069C000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD7 -:1069D000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC7 -:1069E000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFB7 -:1069F000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA7 -:106A0000FFFFFFFFFFFFFFFFFFFFFFFF000000038F -:106A100000BEBC20000000000000000500000003D4 -:106A200000BEBC20000000000000000500000003C4 -:106A300000BEBC20000000000000000500000003B4 -:106A400000BEBC20000000000000000500000003A4 -:106A500000BEBC2000000000000000050000000394 -:106A600000BEBC2000000000000000050000000384 -:106A700000BEBC2000000000000000050000000374 -:106A800000BEBC2000000000000000050000200047 -:106A9000000040C000006180000082400000A300B0 -:106AA0000000C3C00000E480000105400001260092 -:106AB000000146C000016780000188400001A90074 -:106AC0000001C9C00001EA8000020B4000022C0056 -:106AD00000024CC000026D8000028E400002AF0038 -:106AE0000002CFC00002F0800000114000008000D2 -:106AF000000103800001870000020A8000028E006E -:106B000000031180000395000004188000049C001D -:106B100000051F800005A300000626800006AA00CD -:106B200000072D800007B100000834800008B8007D -:106B300000093B800009BF00000A4280000AC6002D -:106B4000000B4980000BCD00000C5080000CD400DD -:106B5000000D578000005B0000007FF800007FF808 -:106B60000000022A000035000000FF0000000000C5 -:106B70000000FF00000000000000FF000000000017 -:106B80000000FF00000000000000FF000000000007 -:106B90000000FF00000000000000FF0000000000F7 -:106BA0000000FF00000000000000FF0000000000E7 -:106BB0000000FF00000000000000FF0000000000D7 -:106BC0000000FF00000000000000FF0000000000C7 -:106BD0000000FF00000000000000FF0000000000B7 -:106BE0000000FF00000000000000FF0000000000A7 -:106BF0000000FF00000000000000FF000000000097 -:106C00000000FF00000000000000FF000000000086 -:106C10000000FF00000000000000FF000000000076 -:106C20000000FF00000000000000FF000000000066 -:106C30000000FF00000000000000FF000000000056 -:106C40000000FF00000000000000FF000000000046 -:106C50000000FF00000000000000FF000000000036 -:106C60000000FF00000000000000FF000000000026 -:106C70000000FF00000000000000FF000000000016 -:106C80000000FF00000000000000FF000000000006 -:106C90000000FF00000000000000FF0000000000F6 -:106CA0000000FF00000000000000FF0000000000E6 -:106CB0000000FF00000000000000FF0000000000D6 -:106CC0000000FF00000000000000FF0000000000C6 -:106CD0000000FF00000000000000FF0000000000B6 -:106CE0000000FF00000000000000FF0000000000A6 -:106CF0000000FF00000000000000FF000000000096 -:106D00000000FF00000000000000FF000000000085 -:106D10000000FF00000000000000FF000000000075 -:106D20000000FF00000000000000FF000000000065 -:106D30000000FF00000000000000FF000000000055 -:106D40000000FF00000000000000FF000000000045 -:106D50000000FF00000000000000FF000000000035 -:106D60000000FF00000000000000FF000000000025 -:106D70000000FF00000000000000FF000000000015 -:106D80000000FF00000000000000FF000000000005 -:106D90000000FF00000000000000FF0000000000F5 -:106DA0000000FF00000019000000000000000000CB -:106DB000FFFFFFFF000000000393870000000000BA -:106DC0000393870000007FF800007FF800000BA30A -:106DD00000001500000000FF000000FF000000FFA1 -:106DE000000000FF000000FF000000FF000000FFA7 -:106DF000000000FF0000FF00000000000000FF0096 -:106E0000000000000000FF00000000000000FF0084 -:106E1000000000000000FF00000000000000FF0074 -:106E2000000000000000FF00000000000000FF0064 -:106E3000000000000000FF00000000000000FF0054 -:106E4000000000000000FF00000000000000FF0044 -:106E5000000000000000FF00000000000000FF0034 -:106E6000000000000000FF00000000000000FF0024 -:106E7000000000000000FF00000000000000FF0014 -:106E8000000000000000FF00000000000000FF0004 -:106E9000000000000000FF00000000000000FF00F4 -:106EA000000000000000FF00000000000000FF00E4 -:106EB000000000000000FF00000000000000FF00D4 -:106EC000000000000000FF00000000000000FF00C4 -:106ED000000000000000FF00000000000000FF00B4 -:106EE000000000000000FF00000000000000FF00A4 -:106EF000000000000000FF00000000000000FF0094 -:106F0000000000000000FF00000000000000FF0083 -:106F1000000000000000FF00000000000000FF0073 -:106F2000000000000000FF00000000000000FF0063 -:106F3000000000000000FF00000000000000FF0053 -:106F4000000000000000FF00000000000000FF0043 -:106F5000000000000000FF00000000000000FF0033 -:106F6000000000000000FF00000000000000FF0023 -:106F7000000000000000FF00000000000000FF0013 -:106F8000000000000000FF00000000000000FF0003 -:106F9000000000000000FF00000000000000FF00F3 -:106FA000000000000000FF00000000000000FF00E3 -:106FB000000000000000FF00000000000000FF00D3 -:106FC000000000000000FF00000000000000FF00C3 -:106FD000000000000000FF00000000000000FF00B3 -:106FE000000000000000FF00000000000000FF00A3 -:106FF000000000000000FF00000000000000FF0093 -:10700000000000000000FF00000000000000FF0082 -:10701000000000000000FF00000000000000FF0072 -:10702000000000000000FF00000000000000FF0062 -:1070300000000000FFFFFFFFFFFFFFFFFFFFFFFF5C -:10704000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF50 -:10705000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF40 -:10706000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF30 -:10707000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF20 -:10708000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF10 -:10709000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00 -:1070A000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0 -:1070B000FFFFFFFF00000000000028AD00002918BE -:1070C0000000291900000005000000070000FF0073 -:1070D0000FFFFFFF0000FF000FFFFFFF000000FF9A -:1070E0000000FF000000FF000FFFFFFF0000FF0097 -:1070F0000FFFFFFF000000FF0000FF000000FF0087 -:107100000FFFFFFF0000FF000FFFFFFF000000FF69 -:107110000000FF000000FF000FFFFFFF0000FF0066 -:107120000FFFFFFF000000FF0000FF000000FF0056 -:107130000FFFFFFF0000FF000FFFFFFF000000FF39 -:107140000000FF000000FF000FFFFFFF0000FF0036 -:107150000FFFFFFF000000FF0000FF000000FF0026 -:107160000FFFFFFF0000FF000FFFFFFF000000FF09 -:107170000000FF000000FF000FFFFFFF0000FF0006 -:107180000FFFFFFF000000FF0000FF000000FF00F6 -:107190000FFFFFFF0000FF000FFFFFFF000000FFD9 -:1071A0000000FF000000FF000FFFFFFF0000FF00D6 -:1071B0000FFFFFFF000000FF0000FF000000FF00C6 -:1071C0000FFFFFFF0000FF000FFFFFFF000000FFA9 -:1071D0000000FF000000FF000FFFFFFF0000FF00A6 -:1071E0000FFFFFFF000000FF0000FF000000FF0096 -:1071F0000FFFFFFF0000FF000FFFFFFF000000FF79 -:107200000000FF000000FF000FFFFFFF0000FF0075 -:107210000FFFFFFF000000FF0000FF000000FF0065 -:107220000FFFFFFF0000FF000FFFFFFF000000FF48 -:107230000000FF000000FF000FFFFFFF0000FF0045 -:107240000FFFFFFF000000FF0000FF000000FF0035 -:107250000FFFFFFF0000FF000FFFFFFF000000FF18 -:107260000000FF000000FF000FFFFFFF0000FF0015 -:107270000FFFFFFF000000FF0000FF000000FF0005 -:107280000FFFFFFF0000FF000FFFFFFF000000FFE8 -:107290000000FF000000FF000FFFFFFF0000FF00E5 -:1072A0000FFFFFFF000000FF0000FF000000FF00D5 -:1072B0000FFFFFFF0000FF000FFFFFFF000000FFB8 -:1072C0000000FF000000FF000FFFFFFF0000FF00B5 -:1072D0000FFFFFFF000000FF0000FF000000FF00A5 -:1072E0000FFFFFFF0000FF000FFFFFFF000000FF88 -:1072F0000000FF000000FF000FFFFFFF0000FF0085 -:107300000FFFFFFF000000FF0000FF000000FF0074 -:107310000FFFFFFF0000FF000FFFFFFF000000FF57 -:107320000000FF000000FF000FFFFFFF0000FF0054 -:107330000FFFFFFF000000FF0000FF000000FF0044 -:107340000FFFFFFF0000FF000FFFFFFF000000FF27 -:107350000000FF000000FF000FFFFFFF0000FF0024 -:107360000FFFFFFF000000FF0000FF000000FF0014 -:107370000FFFFFFF0000FF000FFFFFFF000000FFF7 -:107380000000FF000000FF000FFFFFFF0000FF00F4 -:107390000FFFFFFF000000FF0000FF000000FF00E4 -:1073A0000FFFFFFF0000FF000FFFFFFF000000FFC7 -:1073B0000000FF000000FF000FFFFFFF0000FF00C4 -:1073C0000FFFFFFF000000FF0000FF000000FF00B4 -:1073D0000FFFFFFF0000FF000FFFFFFF000000FF97 -:1073E0000000FF000000FF000FFFFFFF0000FF0094 -:1073F0000FFFFFFF000000FF0000FF000000FF0084 -:107400000FFFFFFF0000FF000FFFFFFF000000FF66 -:107410000000FF000000FF000FFFFFFF0000FF0063 -:107420000FFFFFFF000000FF0000FF000000FF0053 -:107430000FFFFFFF0000FF000FFFFFFF000000FF36 -:107440000000FF000000FF000FFFFFFF0000FF0033 -:107450000FFFFFFF000000FF0000FF000000FF0023 -:107460000FFFFFFF0000FF000FFFFFFF000000FF06 -:107470000000FF000000FF000FFFFFFF0000FF0003 -:107480000FFFFFFF000000FF0000FF000000FF00F3 -:107490000FFFFFFF0000FF000FFFFFFF000000FFD6 -:1074A0000000FF000000FF000FFFFFFF0000FF00D3 -:1074B0000FFFFFFF000000FF0000FF000000FF00C3 -:1074C0000FFFFFFF0000FF000FFFFFFF000000FFA6 -:1074D0000000FF000000FF000FFFFFFF0000FF00A3 -:1074E0000FFFFFFF000000FF0000FF000000FF0093 -:1074F0000FFFFFFF0000FF000FFFFFFF000000FF76 -:107500000000FF000000FF000FFFFFFF0000FF0072 -:107510000FFFFFFF000000FF0000FF000000FF0062 -:107520000FFFFFFF0000FF000FFFFFFF000000FF45 -:107530000000FF000000FF000FFFFFFF0000FF0042 -:107540000FFFFFFF000000FF0000FF000000FF0032 -:107550000FFFFFFF0000FF000FFFFFFF000000FF15 -:107560000000FF000000FF000FFFFFFF0000FF0012 -:107570000FFFFFFF000000FF0000FF000000FF0002 -:107580000FFFFFFF0000FF000FFFFFFF000000FFE5 -:107590000000FF000000FF000FFFFFFF0000FF00E2 -:1075A0000FFFFFFF000000FF0000FF000000FF00D2 -:1075B0000FFFFFFF0000FF000FFFFFFF000000FFB5 -:1075C0000000FF000000FF000FFFFFFF0000FF00B2 -:1075D0000FFFFFFF000000FF0000FF000000FF00A2 -:1075E0000FFFFFFF0000FF000FFFFFFF000000FF85 -:1075F0000000FF000000FF000FFFFFFF0000FF0082 -:107600000FFFFFFF000000FF0000FF000000FF0071 -:107610000FFFFFFF0000FF000FFFFFFF000000FF54 -:107620000000FF000000FF000FFFFFFF0000FF0051 -:107630000FFFFFFF000000FF0000FF000000FF0041 -:107640000FFFFFFF0000FF000FFFFFFF000000FF24 -:107650000000FF000000FF000FFFFFFF0000FF0021 -:107660000FFFFFFF000000FF0000FF000000FF0011 -:107670000FFFFFFF0000FF000FFFFFFF000000FFF4 -:107680000000FF000000FF000FFFFFFF0000FF00F1 -:107690000FFFFFFF000000FF0000FF000000FF00E1 -:1076A0000FFFFFFF0000FF000FFFFFFF000000FFC4 -:1076B0000000FF000000FF000FFFFFFF0000FF00C1 -:1076C0000FFFFFFF000000FF0000FF000000FF00B1 -:1076D0000FFFFFFF0000FF000FFFFFFF000000FF94 -:1076E0000000FF000000FF000FFFFFFF0000FF0091 -:1076F0000FFFFFFF000000FF0000FF000000FF0081 -:107700000FFFFFFF0000FF000FFFFFFF000000FF63 -:107710000000FF000000FF000FFFFFFF0000FF0060 -:107720000FFFFFFF000000FF0000FF000000FF0050 -:107730000FFFFFFF0000FF000FFFFFFF000000FF33 -:107740000000FF000000FF000FFFFFFF0000FF0030 -:107750000FFFFFFF000000FF0000FF000000FF0020 -:107760000FFFFFFF0000FF000FFFFFFF000000FF03 -:107770000000FF000000FF000FFFFFFF0000FF0000 -:107780000FFFFFFF000000FF0000FF000000FF00F0 -:107790000FFFFFFF0000FF000FFFFFFF000000FFD3 -:1077A0000000FF000000FF000FFFFFFF0000FF00D0 -:1077B0000FFFFFFF000000FF0000FF000000FF00C0 -:1077C0000FFFFFFF0000FF000FFFFFFF000000FFA3 -:1077D0000000FF000000FF000FFFFFFF0000FF00A0 -:1077E0000FFFFFFF000000FF0000FF000000FF0090 -:1077F0000FFFFFFF0000FF000FFFFFFF000000FF73 -:107800000000FF000000FF000FFFFFFF0000FF006F -:107810000FFFFFFF000000FF0000FF000000FF005F -:107820000FFFFFFF0000FF000FFFFFFF000000FF42 -:107830000000FF000000FF000FFFFFFF0000FF003F -:107840000FFFFFFF000000FF0000FF000000FF002F -:107850000FFFFFFF0000FF000FFFFFFF000000FF12 -:107860000000FF000000FF000FFFFFFF0000FF000F -:107870000FFFFFFF000000FF0000FF000000FF00FF -:107880000FFFFFFF0000FF000FFFFFFF000000FFE2 -:107890000000FF000000FF000FFFFFFF0000FF00DF -:1078A0000FFFFFFF000000FF0000FF000000FF00CF -:1078B0000FFFFFFF0000FF000FFFFFFF000000FFB2 -:1078C0000000FF000000FF000FFFFFFF0000FF00AF -:1078D0000FFFFFFF000000FF0000FF000000FF009F -:1078E0000FFFFFFF0000FF000FFFFFFF000000FF82 -:1078F0000000FF000000FF000FFFFFFF0000FF007F -:107900000FFFFFFF000000FF0000FF000000FF006E -:107910000FFFFFFF0000FF000FFFFFFF000000FF51 -:107920000000FF000000FF000FFFFFFF0000FF004E -:107930000FFFFFFF000000FF0000FF000000FF003E -:107940000FFFFFFF0000FF000FFFFFFF000000FF21 -:107950000000FF000000FF000FFFFFFF0000FF001E -:107960000FFFFFFF000000FF0000FF000000FF000E -:107970000FFFFFFF0000FF000FFFFFFF000000FFF1 -:107980000000FF000000FF000FFFFFFF0000FF00EE -:107990000FFFFFFF000000FF0000FF000000FF00DE -:1079A0000FFFFFFF0000FF000FFFFFFF000000FFC1 -:1079B0000000FF000000FF000FFFFFFF0000FF00BE -:1079C0000FFFFFFF000000FF0000FF000000FF00AE -:1079D0000FFFFFFF0000FF000FFFFFFF000000FF91 -:1079E0000000FF000000FF000FFFFFFF0000FF008E -:1079F0000FFFFFFF000000FF0000FF000000FF007E -:107A00000FFFFFFF0000FF000FFFFFFF000000FF60 -:107A10000000FF000000FF000FFFFFFF0000FF005D -:107A20000FFFFFFF000000FF0000FF000000FF004D -:107A30000FFFFFFF0000FF000FFFFFFF000000FF30 -:107A40000000FF000000FF000FFFFFFF0000FF002D -:107A50000FFFFFFF000000FF0000FF000000FF001D -:107A60000FFFFFFF0000FF000FFFFFFF000000FF00 -:107A70000000FF000000FF000FFFFFFF0000FF00FD -:107A80000FFFFFFF000000FF0000FF000000FF00ED -:107A90000FFFFFFF0000FF000FFFFFFF000000FFD0 -:107AA0000000FF000000FF000FFFFFFF0000FF00CD -:107AB0000FFFFFFF000000FF0000FF000000FF00BD -:107AC0000FFFFFFF0000FF000FFFFFFF000000FFA0 -:107AD0000000FF000000FF000FFFFFFF0000FF009D -:107AE0000FFFFFFF000000FF0000FF000000FF008D -:107AF0000FFFFFFF0000FF000FFFFFFF000000FF70 -:107B00000000FF000000FF000FFFFFFF0000FF006C -:107B10000FFFFFFF000000FF0000FF000000FF005C -:107B20000FFFFFFF0000FF000FFFFFFF000000FF3F -:107B30000000FF000000FF000FFFFFFF0000FF003C -:107B40000FFFFFFF000000FF0000FF000000FF002C -:107B50000FFFFFFF0000FF000FFFFFFF000000FF0F -:107B60000000FF000000FF000FFFFFFF0000FF000C -:107B70000FFFFFFF000000FF0000FF000000FF00FC -:107B80000FFFFFFF0000FF000FFFFFFF000000FFDF -:107B90000000FF000000FF000FFFFFFF0000FF00DC -:107BA0000FFFFFFF000000FF0000FF000000FF00CC -:107BB0000FFFFFFF0000FF000FFFFFFF000000FFAF -:107BC0000000FF000000FF000FFFFFFF0000FF00AC -:107BD0000FFFFFFF000000FF0000FF000000FF009C -:107BE0000FFFFFFF0000FF000FFFFFFF000000FF7F -:107BF0000000FF000000FF000FFFFFFF0000FF007C -:107C00000FFFFFFF000000FF0000FF000000FF006B -:107C10000FFFFFFF0000FF000FFFFFFF000000FF4E -:107C20000000FF000000FF000FFFFFFF0000FF004B -:107C30000FFFFFFF000000FF0000FF000000FF003B -:107C40000FFFFFFF0000FF000FFFFFFF000000FF1E -:107C50000000FF000000FF000FFFFFFF0000FF001B -:107C60000FFFFFFF000000FF0000FF000000FF000B -:107C70000FFFFFFF0000FF000FFFFFFF000000FFEE -:107C80000000FF000000FF000FFFFFFF0000FF00EB -:107C90000FFFFFFF000000FF0000FF000000FF00DB -:107CA0000FFFFFFF0000FF000FFFFFFF000000FFBE -:107CB0000000FF000000FF000FFFFFFF0000FF00BB -:107CC0000FFFFFFF000000FF0000FF000000FF00AB -:107CD0000FFFFFFF0000FF000FFFFFFF000000FF8E -:107CE0000000FF000000FF000FFFFFFF0000FF008B -:107CF0000FFFFFFF000000FF0000FF000000FF007B -:107D00000FFFFFFF0000FF000FFFFFFF000000FF5D -:107D10000000FF000000FF000FFFFFFF0000FF005A -:107D20000FFFFFFF000000FF0000FF000000FF004A -:107D30000FFFFFFF0000FF000FFFFFFF000000FF2D -:107D40000000FF000000FF000FFFFFFF0000FF002A -:107D50000FFFFFFF000000FF0000FF000000FF001A -:107D60000FFFFFFF0000FF000FFFFFFF000000FFFD -:107D70000000FF000000FF000FFFFFFF0000FF00FA -:107D80000FFFFFFF000000FF0000FF0000001000D9 -:107D900000002080000031000000418000005200FF -:107DA00000006280000073000000838000009400E7 -:107DB0000000A4800000B5000000C5800000D600CF -:107DC0000000E6800000F7000001078000011800B5 -:107DD00000012880000139000001498000015A009B -:107DE00000016A8000017B0000018B8000019C0083 -:107DF0000001AC800001BD000001CD800001DE006B -:107E00000001EE800001FF0000000F8000007FF8FD -:107E100000007FF8000005F60000350010000000AB -:107E2000000028AD000029180000291900000005F5 -:107E3000000000060001000100050206CCCCCCC900 -:107E40007058103C0000FF00000000000000FF0020 -:107E5000000000000000FF00000000000000FF0024 -:107E6000000000000000FF00000000000000FF0014 -:107E7000000000000000FF00000000000000FF0004 -:107E8000000000000000FF00000000000000FF00F4 -:107E9000000000000000FF00000000000000FF00E4 -:107EA000000000000000FF00000000000000FF00D4 -:107EB000000000000000FF00000000000000FF00C4 -:107EC000000000000000FF00000000000000FF00B4 -:107ED000000000000000FF00000000000000FF00A4 -:107EE000000000000000FF00000000000000FF0094 -:107EF000000000000000FF00000000000000FF0084 -:107F0000000000000000FF00000000000000FF0073 -:107F1000000000000000FF00000000000000FF0063 -:107F2000000000000000FF00000000000000FF0053 -:107F3000000000000000FF00000000000000FF0043 -:107F4000000000000000FF00000000000000FF0033 -:107F5000000000000000FF00000000000000FF0023 -:107F6000000000000000FF00000000000000FF0013 -:107F7000000000000000FF00000000000000FF0003 -:107F8000000000000000FF00000000000000FF00F3 -:107F9000000000000000FF00000000000000FF00E3 -:107FA000000000000000FF00000000000000FF00D3 -:107FB000000000000000FF00000000000000FF00C3 -:107FC000000000000000FF00000000000000FF00B3 -:107FD000000000000000FF00000000000000FF00A3 -:107FE000000000000000FF00000000000000FF0093 -:107FF000000000000000FF00000000000000FF0083 -:10800000000000000000FF00000000000000FF0072 -:10801000000000000000FF00000000000000FF0062 -:10802000000000000000FF00000000000000FF0052 -:10803000000000000000FF00000000000000FF0042 -:10804000000000000000FF00000000000000FF0032 -:10805000000000000000FF00000000000000FF0022 -:10806000000000000000FF00000000000000FF0012 -:10807000000000000000FF00000000000000FF0002 -:108080000000000000000001CCCC0201CCCCCCCC24 -:10809000CCCC0201CCCCCCCCCCCC0201CCCCCCCC4A -:1080A000CCCC0201CCCCCCCCCCCC0201CCCCCCCC3A -:1080B000CCCC0201CCCCCCCCCCCC0201CCCCCCCC2A -:1080C000CCCC0201CCCCCCCC00000000FFFFFFFFE9 -:1080D000030303031342020250505020706080508B -:1080E0000200020006040604000E0000011600D67D -:1080F000002625A0002625A0002625A0002625A0D4 -:1081000000720000012300F3002625A0002625A010 -:10811000002625A0002625A00000FFFF000000008B -:108120000000FFFF000000000000FFFF0000000053 -:108130000000FFFF000000000000FFFF0000000043 -:108140000000FFFF000000000000FFFF0000000033 -:108150000000FFFF000000000000FFFF0000000023 -:108160000000FFFF000000000000FFFF0000000013 -:108170000000FFFF000000000000FFFF0000000003 -:108180000000FFFF000000000000FFFF00000000F3 -:108190000000FFFF000000000000FFFF00000000E3 -:1081A0000000FFFF000000000000FFFF00000000D3 -:1081B0000000FFFF000000000000FFFF00000000C3 -:1081C0000000FFFF000000000000FFFF00000000B3 -:1081D0000000FFFF000000000000FFFF00000000A3 -:1081E0000000FFFF000000000000FFFF0000000093 -:1081F0000000FFFF000000000000FFFF0000000083 -:108200000000FFFF000000000000FFFF0000000072 -:108210000000FFFF000000000000FFFF0000000062 -:108220000000FFFF000000000000FFFF0000000052 -:108230000000FFFF000000000000FFFF0000000042 -:108240000000FFFF000000000000FFFF0000000032 -:108250000000FFFF000000000000FFFF0000000022 -:108260000000FFFF000000000000FFFF0000000012 -:108270000000FFFF000000000000FFFF0000000002 -:108280000000FFFF000000000000FFFF00000000F2 -:108290000000FFFF000000000000FFFF00000000E2 -:1082A0000000FFFF000000000000FFFF00000000D2 -:1082B0000000FFFF000000000000FFFF00000000C2 -:1082C0000000FFFF000000000000FFFF00000000B2 -:1082D0000000FFFF000000000000FFFF00000000A2 -:1082E0000000FFFF000000000000FFFF0000000092 -:1082F0000000FFFF000000000000FFFF0000000082 -:108300000000FFFF000000000000FFFF0000000071 -:108310000000FFFF00000000FFFFFFF3318FFFFFB1 -:108320000C30C30CC30C30C3CF3CF300F3CF3CF391 -:108330000000CF3CCDCDCDCDFFFFFFF130EFFFFFF3 -:108340000C30C30CC30C30C3CF3CF300F3CF3CF371 -:108350000001CF3CCDCDCDCDFFFFFFF6305FFFFF5D -:108360000C30C30CC30C30C3CF3CF300F3CF3CF351 -:108370000002CF3CCDCDCDCDFFFFF4061CBFFFFFEB -:108380000C30C305C30C30C3CF300014F3CF3CF323 -:108390000004CF3CCDCDCDCDFFFFFFF2304FFFFF2E -:1083A0000C30C30CC30C30C3CF3CF300F3CF3CF311 -:1083B0000008CF3CCDCDCDCDFFFFFFFA302FFFFF22 -:1083C0000C30C30CC30C30C3CF3CF300F3CF3CF3F1 -:1083D0000010CF3CCDCDCDCDFFFFFFF731EFFFFF3C -:1083E0000C30C30CC30C30C3CF3CF300F3CF3CF3D1 -:1083F0000020CF3CCDCDCDCDFFFFFFF5302FFFFFCF -:108400000C30C30CC30C30C3CF3CF300F3CF3CF3B0 -:108410000040CF3CCDCDCDCDFFFFFFF3318FFFFF2F -:108420000C30C30CC30C30C3CF3CF300F3CF3CF390 -:108430000000CF3CCDCDCDCDFFFFFFF1310FFFFFD1 -:108440000C30C30CC30C30C3CF3CF300F3CF3CF370 -:108450000001CF3CCDCDCDCDFFFFFFF6305FFFFF5C -:108460000C30C30CC30C30C3CF3CF300F3CF3CF350 -:108470000002CF3CCDCDCDCDFFFFF4061CBFFFFFEA -:108480000C30C305C30C30C3CF300014F3CF3CF322 -:108490000004CF3CCDCDCDCDFFFFFFF2304FFFFF2D -:1084A0000C30C30CC30C30C3CF3CF300F3CF3CF310 -:1084B0000008CF3CCDCDCDCDFFFFFFFA302FFFFF21 -:1084C0000C30C30CC30C30C3CF3CF300F3CF3CF3F0 -:1084D0000010CF3CCDCDCDCDFFFFFFF730EFFFFF3C -:1084E0000C30C30CC30C30C3CF3CF300F3CF3CF3D0 -:1084F0000020CF3CCDCDCDCDFFFFFFF5304FFFFFAE -:108500000C30C30CC30C30C3CF3CF300F3CF3CF3AF -:108510000040CF3CCDCDCDCDFFFFFFFF30CFFFFFE3 -:108520000C30C30CC30C30C3CF3CF3CCF3CF3CF3C3 -:108530000000CF3CCDCDCDCDFFFFFFFF30CFFFFF03 -:108540000C30C30CC30C30C3CF3CF3CCF3CF3CF3A3 -:108550000001CF3CCDCDCDCDFFFFFFFF30CFFFFFE2 -:108560000C30C30CC30C30C3CF3CF3CCF3CF3CF383 -:108570000002CF3CCDCDCDCDFFFFFFFF30CFFFFFC1 -:108580000C30C30CC30C30C3CF3CF3CCF3CF3CF363 -:108590000004CF3CCDCDCDCDFFFFFFFF30CFFFFF9F -:1085A0000C30C30CC30C30C3CF3CF3CCF3CF3CF343 -:1085B0000008CF3CCDCDCDCDFFFFFFFF30CFFFFF7B -:1085C0000C30C30CC30C30C3CF3CF3CCF3CF3CF323 -:1085D0000010CF3CCDCDCDCDFFFFFFFF30CFFFFF53 -:1085E0000C30C30CC30C30C3CF3CF3CCF3CF3CF303 -:1085F0000020CF3CCDCDCDCDFFFFFFFF30CFFFFF23 -:108600000C30C30CC30C30C3CF3CF3CCF3CF3CF3E2 -:108610000040CF3CCDCDCDCDFFFFFFF3320FFFFFAC -:108620000C30C30CC30C30C3CF3CF300F3CF3CF38E -:108630000000CF3CCDCDCDCDFFFFFFF1310FFFFFCF -:108640000C30C30CC30C30C3CF3CF300F3CF3CF36E -:108650000001CF3CCDCDCDCDFFFFFFF6305FFFFF5A -:108660000C30C30CC30C30C3CF3CF300F3CF3CF34E -:108670000002CF3CCDCDCDCDFFFFF4061CBFFFFFE8 -:108680000C30C305C30C30C3CF300014F3CF3CF320 -:108690000004CF3CCDCDCDCDFFFFFFF2304FFFFF2B -:1086A0000C30C30CC30C30C3CF3CF300F3CF3CF30E -:1086B0000008CF3CCDCDCDCDFFFFFF8A042FFFFFBB -:1086C0000C30C30CC30C30C3CF3CC000F3CF3CF321 -:1086D0000010CF3CCDCDCDCDFFFFFF9705CFFFFFE5 -:1086E0000C30C30CC30C30C3CF3CC000F3CF3CF301 -:1086F0000020CF3CCDCDCDCDFFFFFFF5310FFFFFEB -:108700000C30C30CC30C30C3CF3CF300F3CF3CF3AD -:108710000040CF3CCDCDCDCDFFFFFFF3320FFFFFAB -:108720000C30C30CC30C30C3CF3CF300F3CF3CF38D -:108730000000CF3CCDCDCDCDFFFFFFF1302FFFFFAF -:108740000C30C30CC30C30C3CF3CF300F3CF3CF36D -:108750000001CF3CCDCDCDCDFFFFFFF6305FFFFF59 -:108760000C30C30CC30C30C3CF3CF300F3CF3CF34D -:108770000002CF3CCDCDCDCDFFFFFF061CBFFFFFDC -:108780000C30C30CC30C30C3CF3CC014F3CF3CF34C -:108790000004CF3CCDCDCDCDFFFFFFF2304FFFFF2A -:1087A0000C30C30CC30C30C3CF3CF300F3CF3CF30D -:1087B0000008CF3CCDCDCDCDFFFFFFFA302FFFFF1E -:1087C0000C30C30CC30C30C3CF3CF300F3CF3CF3ED -:1087D0000010CF3CCDCDCDCDFFFFFFF731CFFFFF58 -:1087E0000C30C30CC30C30C3CF3CF300F3CF3CF3CD -:1087F0000020CF3CCDCDCDCDFFFFFFFF30CFFFFF21 -:108800000C30C30CC30C30C3CF3CF3CCF3CF3CF3E0 -:108810000040CF3CCDCDCDCDFFFFFFFF30CFFFFFE0 -:108820000C30C30CC30C30C3CF3CF3CCF3CF3CF3C0 -:108830000000CF3CCDCDCDCDFFFFFFFF30CFFFFF00 -:108840000C30C30CC30C30C3CF3CF3CCF3CF3CF3A0 -:108850000001CF3CCDCDCDCDFFFFFFFF30CFFFFFDF -:108860000C30C30CC30C30C3CF3CF3CCF3CF3CF380 -:108870000002CF3CCDCDCDCDFFFFFFFF30CFFFFFBE -:108880000C30C30CC30C30C3CF3CF3CCF3CF3CF360 -:108890000004CF3CCDCDCDCDFFFFFFFF30CFFFFF9C -:1088A0000C30C30CC30C30C3CF3CF3CCF3CF3CF340 -:1088B0000008CF3CCDCDCDCDFFFFFFFF30CFFFFF78 -:1088C0000C30C30CC30C30C3CF3CF3CCF3CF3CF320 -:1088D0000010CF3CCDCDCDCDFFFFFFFF30CFFFFF50 -:1088E0000C30C30CC30C30C3CF3CF3CCF3CF3CF300 -:1088F0000020CF3CCDCDCDCDFFFFFFFF30CFFFFF20 -:108900000C30C30CC30C30C3CF3CF3CCF3CF3CF3DF -:108910000040CF3CCDCDCDCDFFFFFFFF30CFFFFFDF -:108920000C30C30CC30C30C3CF3CF3CCF3CF3CF3BF -:108930000000CF3CCDCDCDCDFFFFFFFF30CFFFFFFF -:108940000C30C30CC30C30C3CF3CF3CCF3CF3CF39F -:108950000001CF3CCDCDCDCDFFFFFFFF30CFFFFFDE -:108960000C30C30CC30C30C3CF3CF3CCF3CF3CF37F -:108970000002CF3CCDCDCDCDFFFFFFFF30CFFFFFBD -:108980000C30C30CC30C30C3CF3CF3CCF3CF3CF35F -:108990000004CF3CCDCDCDCDFFFFFFFF30CFFFFF9B -:1089A0000C30C30CC30C30C3CF3CF3CCF3CF3CF33F -:1089B0000008CF3CCDCDCDCDFFFFFFFF30CFFFFF77 -:1089C0000C30C30CC30C30C3CF3CF3CCF3CF3CF31F -:1089D0000010CF3CCDCDCDCDFFFFFFFF30CFFFFF4F -:1089E0000C30C30CC30C30C3CF3CF3CCF3CF3CF3FF -:1089F0000020CF3CCDCDCDCDFFFFFFFF30CFFFFF1F -:108A00000C30C30CC30C30C3CF3CF3CCF3CF3CF3DE -:108A10000040CF3CCDCDCDCDFFFFFFFF30CFFFFFDE -:108A20000C30C30CC30C30C3CF3CF3CCF3CF3CF3BE -:108A30000000CF3CCDCDCDCDFFFFFFFF30CFFFFFFE -:108A40000C30C30CC30C30C3CF3CF3CCF3CF3CF39E -:108A50000001CF3CCDCDCDCDFFFFFFFF30CFFFFFDD -:108A60000C30C30CC30C30C3CF3CF3CCF3CF3CF37E -:108A70000002CF3CCDCDCDCDFFFFFFFF30CFFFFFBC -:108A80000C30C30CC30C30C3CF3CF3CCF3CF3CF35E -:108A90000004CF3CCDCDCDCDFFFFFFFF30CFFFFF9A -:108AA0000C30C30CC30C30C3CF3CF3CCF3CF3CF33E -:108AB0000008CF3CCDCDCDCDFFFFFFFF30CFFFFF76 -:108AC0000C30C30CC30C30C3CF3CF3CCF3CF3CF31E -:108AD0000010CF3CCDCDCDCDFFFFFFFF30CFFFFF4E -:108AE0000C30C30CC30C30C3CF3CF3CCF3CF3CF3FE -:108AF0000020CF3CCDCDCDCDFFFFFFFF30CFFFFF1E -:108B00000C30C30CC30C30C3CF3CF3CCF3CF3CF3DD -:108B10000040CF3CCDCDCDCD000C0000000700C003 -:108B200000028130000B8158000202100001023067 -:108B3000000F024000010330000C0000000800C0DC -:108B400000028140000B8168000202200001024007 -:108B500000070250000202C00010000000080100DF -:108B600000028180000B81A8000202600001828067 -:108B7000000E829800080380001000000001010030 -:108B80000002811000090138000201C8000101E85B -:108B9000000E01F8000002D8CCCCCCCCCCCCCCCC94 -:108BA000CCCCCCCCCCCCCCCC00002000CCCCCCCC15 -:108BB000CCCCCCCCCCCCCCCCCCCCCCCC0000200005 -:108BC000CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCE5 -:108BD00004002000CCCCCCCCCCCCCCCCCCCCCCCCE1 -:108BE000CCCCCCCC4100200003030303034202029F -:108BF0005050502070608050131313131342121200 -:108C000050505020706080500301020000000000AE -:108C100000000000000000001F8B080000000000A2 -:108C2000000BFB51CFC0F0038A0F093230688A2055 -:108C3000F8C4E05C760686751C0C0C5BB849D3075B -:108C4000C32C0C0C0CDA4CE4E905E1FBBC0C0CAFBA -:108C50008098850F559C871342FF015AC0C7CAC030 -:108C6000A0C1865DFF3A35043B408581A11C88D9AF -:108C7000941818CC5411E2D2EA0C0C3380FC04A8EE -:108C8000D81D201DAB46BE9B47F1E0C1378D51F981 -:108C90005B0DA169012A7E0B4D7E1B54BE4A074223 -:108CA000DF36C66E6EB50E71F69FB546E5AFB4C63B -:108CB000AFFEAE3D2AFF209AFAAD503E00C5D55B0F -:108CC000A7D8030000000000000000000000000022 -:108CD0001F8B080000000000000BED7D7F7C14D589 -:108CE000B5F8999DD9D9D9CDEE6608096C20E02454 -:108CF000861AFB82DFE577A841878034B63CDF8A9D -:108D00005AD3D6F6BB506C551456BF3EE1F56933C5 -:108D1000F941122262049FDAD61F2B554BFB6C8956 -:108D2000942AAD3FDE024AF1F5C743AAD5D7A22F58 -:108D3000FE80AA455FC4D2D87E51DE3DE7DEC9CEB3 -:108D40004C76930DD01F7FBCF081E1CEDC1FE79EF7 -:108D500073EE39E79E73EE8DEAF3C3C7CE05388E06 -:108D60003FECD913028059D9A771F5BCAEBE99006A -:108D70004721D2D35D0AD0A68009AC6C1D88A41F00 -:108D800094007F6A14565E2D7F3CDE5D097067D1CA -:108D9000D7EEC3FA6B2C0502ECD9DD0C9039837D3C -:108DA0000F453743314011A4B6E277F6937890F53A -:108DB00037109C9C866876FC32F0D1B80015FAA179 -:108DC00022AA07C765F6CF81E47C18072083FDB38C -:108DD000067A593FCAF3721AC795E5C5FA8B55D979 -:108DE0007EBC4F595721A389FEF01FF9B2E26438C7 -:108DF0007FFD35072AB73E5D93AD7F06444A0FFDE0 -:108E00001DFB8F020AC123AF07C4C3D130A4E5CA3A -:108E1000FCFD0C341B5B9FF6231EBF509C989ABF31 -:108E20009E8DA7AE668D9E1DCD3A6402000C64B384 -:108E3000B7963DC3606EAE1DDA6E0148842FCDB08B -:108E4000089EF6B02F5D5489502701187EFD881FBB -:108E500009DF2FD1CC1CEDED279432FCD8F36578D7 -:108E60000C02EF0FD8FC1E64FD0571FC1CF8BA085B -:108E7000C72F63DFAB878E6FCD3CF1F1436702EC08 -:108E80000B23BE4D84017C7A0AE282DE9F9486E940 -:108E900047D05931783F23E1BDA8C6971D97FD0DF6 -:108EA0001A21179F0462256EBEF1F225E2A90CE992 -:108EB0006548AF4FC9F6AB22DD72E0EB4A81AFFEE9 -:108EC000F989A604C3C7DA66B05E73B4936360A67B -:108ED00073E069B568678FA794B27A39FA076811A9 -:108EE000EBC772D52F14BE9B4E10BE9BFF42F0DD28 -:108EF00026F89D49287AF6CF4F129CDEFE72AD2FE0 -:108F0000B68807CB21256DF990BF4B21FE207BF859 -:108F100035BECEECEFDF073FF5B303250E1BA74DA3 -:108F2000C0D73F9FCBBFB5D3D4F46689E4910BCEB5 -:108F300087517EB1769224F0A1F502F25FD1070A43 -:108F4000C05884CF844404605D7583369CFC015D09 -:108F5000F9539FCD775543F9EEE36C18842B14CE6B -:108F60008DA7EF0FCAD1CBACD7583F5A90BD3F1D4C -:108F7000FB2D8D55CC069C1DFDF8C577907CF271BC -:108F80005CB7C758BDD942CECAD43FC911A8009218 -:108F9000F7B2A84FE3B0FA01362D733A7BE2FB1A21 -:108FA000318E34B45F6FBB0128E1F811F0D8725DE7 -:108FB0008627A89F41789404E1CBFBDECFDEEBE16E -:108FC000937F7FB265BF9167BC1E89F869A4F6AF35 -:108FD000087E19C29F79E8BA5FAC33057A4D383DF7 -:108FE000CB47367F9D281F9D349FB0E1495FE4E168 -:108FF000130B52B46E5835AB7BDAE8F925079F6442 -:109000009CF5174B63F83C9438F10B834721BED590 -:10901000393C65D34BA93F09D7F819D88328231EBB -:10902000D87C97D9ED214EEB3584768EA33D9B1CE1 -:10903000C12BC99290FBBCDE0D629DCF6BA8E0F006 -:1090400083E8DF032FEB4F73F627438587CF39DCA7 -:109050001B242EDF58FD0CE1D33BBE2211BC322471 -:109060002C1F6BB7598CEF955FF673BBE86FBD048F -:109070004DBD61BE9E9638F4618324E484C6D799C1 -:10908000573EF991AF669C385F152AD7174BB9F553 -:109090000EB38A621746F2EB9D629FAD0F323141EB -:1090A000B751D1FD74A9C445F742E15D7682F04E17 -:1090B0001C0A6F417C76A6E41B959EBCE104E10B83 -:1090C0007AE03B557C3D43F059A1F0DBEB60B4F016 -:1090D000CB43F15BD03A9A3B4AF8369F207ECB7C5B -:1090E000B69D24E0CBB36EE7097A5BC0F9436176A5 -:1090F00038EE730A85EFD191E103F804FB6BBD6A8A -:10910000990AD96B0013009E6E79D5B2942C7C26F7 -:1091100070B93EDAF1F78C4C3F31FE5B96599D1DDC -:10912000FFF996B75CE32B8C7F90D90A1DF7854237 -:10913000E70DEFB9E6FDBAF49E6BDC13C5FBC18207 -:10914000C7FFA36BDEEF4B7F74CF3BCCE67D7AE1AC -:10915000E3FEFE04F9B152AC97064977E9817CF64B -:10916000FB0C41D7BBEDFA36BC79EA9F29E06A2FA8 -:10917000B0FE44D1FFE70AACDF2BFAEFC5FA652356 -:10918000D73F5DD44F15585FF2F175984F7FCE975A -:109190006CFC816BFFD1A6713F88D9A640F09CA1E1 -:1091A0007E13AB21F5ED3E467BAB35A0B79592DF44 -:1091B00084FC226B0012E837F92624EB7CAC1F6399 -:1091C000C74DF761BD238AA677EBC01724FB1E3C71 -:1091D00010D9DC5D991D6FB59C6C929097DAA2FA5C -:1091E00083E45F493549EC59668575F4DB0C5425F9 -:1091F0005A9696E23C0CDD62FDFCFA8A8B76627927 -:109200009326E9322BFFCB39736FFB0C6B35F0E102 -:10921000CE974EC37AD3C655B592BC3425C44F6998 -:109220005C35E5287B5E7C71561FE03F8B1D6566D3 -:10923000077CB6E9122EFFC5F7CF27DDE54B1A2FC5 -:1092400071B5BF34E1FE9E9D0FF07DC7B9DCFF30E4 -:109250005095FA2F0ED7C72A2DEE5FA0F9EA565483 -:10926000EF66F35CFFE1B5545EDF52ABB7B2F2E7F5 -:10927000AEF4B72C65CFB004BACC9652715CA5F9A8 -:10928000029BAF5AC7768FE73CDB35DBC8BFFF2AAE -:10929000363DF38C5F9C8593CDB3E9EADC70ABFA85 -:1092A000FB13DE60F6D2C0CEA089F084F7CAE9A035 -:1092B0004474DD3909E9621527397D40AA66CF2358 -:1092C0008D3AA07FA4A13169C8ACBC31A6C5030604 -:1092D000DAC9190DF11E411ACC65EFE3BE20DA633D -:1092E000AAFE07EA5F17DF7BE255E3D13FF2E3E630 -:1092F000351315B6DE77345BF47CB4B98B9EDB9BFB -:109300007B262ACC88DFD27C173DEDF9A12431ECF5 -:10931000F9C9B8AF365B91DF06FCCC34423CCEF7DE -:10932000D1FE7603CA113FCAE1745B14DFD7C1B422 -:109330006E40B9C4E5CBC6F8B6DDF87E633D4C435C -:10934000926D3437B745D93CAE2B87E9D8F7CE9725 -:109350001FE3DF2B607A8095773536905CED89FBD3 -:10936000D2814A82FF7CE4E79E461F3093078AEB56 -:10937000185C0EBC0662EEF2AE4626B066123ED215 -:1093800001293B7F852D33C4C746B32AE8DC57CF7C -:10939000DAE76E7F66DA5DDE88ED87F14BCDED733F -:1093A000D79FF392BBCC24DB2B837CC0F1F8AF3E7C -:1093B000260F76BF3CDE67E1BC4D3E4FF6E4FEC2B1 -:1093C000982F8DC6E716813F1BBF03112E5F3636DF -:1093D000733F603E78367EEAAAD8707E03B5B1232B -:1093E00081FE54B5B1270167E1332D9EBD09A79FCA -:1093F000D57EBE88C68FC35FD211DB58B2B4360BA0 -:109400008FB7FE785925793750C6BF77C45ED3979A -:10941000D63AFB93BCDFB5CBC3CEEFDCAF32506E98 -:109420007F3FA22D0DE7683F897DCF4197A532FF91 -:10943000FEF4CB81863B901F057E77BFFC13AD1AEF -:10944000F1FDBC0CC8671BF73590BC453E4379B1B4 -:109450008BF1455F2DD27FFD2BCE755B5CE72E3304 -:10946000BEE2FCC5FAC5A17E86F4601DFEBBF0CB52 -:10947000EE157ED93DCD317A3EDD6CD07357730D3C -:109480007DCF34C7A9FC54731D959F6836A9FCE3B2 -:10949000E6462AEF684E50F9D1E6267A6E6F4ED234 -:1094A000734BF315F464FC4BFCBCA13925FCC06B79 -:1094B0005CFCF0F7F1808BFF3E5DE32E9F6F9C918B -:1094C0005DD7ECEF2763EEF279FA275DE5059ABBED -:1094D0003C1FBEE2EAEFDC0FBEEC2ACFEBEF70D50B -:1094E0003FFB4D77796EDF439EF5E22ECFDAB7C7AB -:1094F000B31EDDE5E2BA43AEFE023177F97E1432E7 -:109500005C4E117F74C45A4B72F2CFE0F78DA12FDD -:10951000B9BECBD47E64FE59D65589FC93F6C52DD1 -:10952000943B26E7275BEE78F9C4A6DB48FC65C3CD -:10953000F197E6ABFFE5A7E1F9A9607EA85772F2C3 -:109540008397EE5EFE18226704BFFC2F1FFC6DF0B0 -:1095500001CC64C42ECFAF5773D877649F061240F6 -:10956000F69D1FED34477B75722A69E6D09F57F947 -:10957000E66F95593F8152E8C0786840C9E3E795A6 -:10958000F93E25A0F1EFC16A93ECB26230A6CB633D -:1095900000AE796C5EF932F6FEE7421F765C089603 -:1095A000C4FA1B37414DE23EA6B8DABDDF7B46E682 -:1095B000FB18FBB9E9879126FC0EA5334798378F36 -:1095C000D7C8136737FDC660CF0B666F59CBDE86F1 -:1095D000AA9319F2019596927D9A0C19D4AF5997D6 -:1095E000B67CA518478338DA8972D884241B67AE05 -:1095F000CFFC05CE9BD947FF21CFCADA3D9BC4F3F0 -:1096000047621D5EE4337F29EA3D3F5C3D7BDC1110 -:10961000E905494BE2FEA9F8830C447F69DC653F0C -:10962000D9F353948499C8616FFC4EE04BD2E34D5B -:10963000DC0FA202CA877CF50FCAB6FFC972ED071C -:109640008BA13F23231C311E6F82631719174E1DF8 -:109650000A87AA2492380EC6AB37B371DAC77CC624 -:10966000483AC6F948E67E2A2966123CAACEE1515C -:1096700095B899C8C14703021EBB1F3B6E26C5FAA9 -:10968000A12F9C856F6D30D184FB256B8C4A786A45 -:109690008FB8EDAF190AEFA75A3CDBFDB9ED438057 -:1096A00056BE1F1E57A761FF6D750D1ADAD78C1DA8 -:1096B00068BFD21E5E523C9CBDBD5ED8BFDD280F88 -:1096C00003180FD785BC8AD1B33DBCAD11D7C1D12A -:1096D0005A8687CAFCFD44E2EEB86E514DC813C7E6 -:1096E0004D139C41A3C413EF9DE06AE71FA7F8EC5C -:1096F000B8364823C3DF21E0B7EB752A294DCF895F -:10970000273EBE5D0EC4DCF0FEF9F0C7DB17F97B27 -:10971000F55C709D2ABCE58BC3DA4F75AC9A4A7331 -:109720007F4ACCB90E3E2BF84B1DABA5483E69F9DC -:10973000BE8778FB7082FC5B5A38614055361EABA1 -:10974000E17A70E0E95AD1EED78A4FACCB540CFDE8 -:109750005C92916A427ED22AD83A9286B6B39F49E9 -:10976000D1BEF3C3FFF712AD93328DD68964B075C5 -:1097700094631C4931AF56D8F31DD9BC46C1F8CC0F -:10978000477232D77A5921E0D116270CAD8A427838 -:109790003CDFC303C73A85EB834336FC568AFC564D -:1097A00085C2BFA640F8ED7118FCED02FEB5C3C13D -:1097B000DF26E02901A3857C990697B300171ACE0E -:1097C000BC8B37C4F825424E314C11DDECEFFF2540 -:1097D000FA29743E1B059C23CDE78D2C3DEEC579FF -:1097E000B0F9DC87F3CA379F7B041C6F285CCF6815 -:1097F000898411AB22559F93AF9E1070F42B228E5B -:10980000665D3B2ABEFAD702E7F144962E8F09BA6D -:10981000EC186E1E8F8A79F4C830F70DF4339E2E43 -:10982000F40E2C71D1E5A8C04F4FC0A6CB752EBA4F -:10983000FC4ECCABD0F93C53209F1DCDD2E5393145 -:109840009FFDC3CDC751FF4551FF25519FFCE74701 -:10985000952B5AAD5AFC9E38A0CCCA8EC7EABDECF7 -:10986000AC776DFB2CBBDEABC80F5223D783ACDECD -:109870006BCE7A605DD08AF6DB5A8C897E02E081FD -:10988000F6AF3688766F52BBC583FDBF25D607B5C8 -:109890005BD73EBFD50A53BD77F07DCB828FEC7A84 -:1098A000EFBAE15D61C37184E04D0CC2F1BEB3DE7D -:1098B00013CAE7A9BF217947B19282EC1F7F699251 -:1098C000F2F74A20D283FEC50E2545FE640C36A071 -:1098D0001F7275204EA92A23F9A3CB2EE6ED7445FD -:1098E000237F6A005270177BBFA154A1F8C862257C -:1098F00019F1A31D21252D0AAE827E590BF63FD604 -:10990000A0FC2F1B9EDB8ABED845FD3078B0DF3B24 -:109910008BA23B91AF364E520DE4AB9D936E20BFB0 -:10992000F96D2D3C7FF0B6F355DA676D7A3942FA5E -:1099300077AD12FF2CD6B74CD5403FFAEAD0472F6F -:109940002D67E5BE96625D3A87E641705B3E48B49E -:10995000CD74E42332B80371CAA7233FDC6D8D3C7C -:10996000AEC37ECAB1FDEA0546BCDB40F1C5E418D2 -:10997000FBDE59A792FD7A5B45D57C1C6F539D4653 -:10998000F6C6A6C5552DE4C7AB0B91BFB2246C48F3 -:10999000E8678FCE519901CECAA5460BDA9B91D9C3 -:1099A0002140BF5349051F2F7206901FCA0F3D89E2 -:1099B0006AF68C76A990198BFD2DC97C09ED99BAB0 -:1099C00000F9E1D9C4F6D78EA39437FE23FF0C101B -:1099D0001EFF441910EF367DA33D83ED87CD638CC8 -:1099E000A60BAC9729AC5EA44B81CC8C02EAF51493 -:1099F000582F5D60BD0CAF17800B87CDE78338CF44 -:109A000023D4D81F9EC7E8C82BACE4F6BBD36EF1B5 -:109A10007BBE8F362FF42ABFC80B9D0373785EE898 -:109A2000F0EDED7CD091E60BE0CBC2298F5C7F6D31 -:109A3000F3F07E63FFB81B62987FD959F655F1BCED -:109A4000913FCBC5FBF2353194779DE5E27BF98DF3 -:109A50004DB9F6AF77FAB91CAE81C4B0742811F0D5 -:109A60001F62B0637E4F8DC2EA47F2D7574B7DC36A -:109A7000E6596A8AD540EB76B18FD66D008501AE86 -:109A80009B0ABE8EFD904A54F37855B4DCB17EFC3F -:109A9000F57B68FDFCA25C06A98EE813473C7AF9C9 -:109AA000C4CB170170942B4F9E4FB6FE99F8C4DFBC -:109AB0002517B47EFC3D05D64B17582F53583DB59E -:109AC0004B2A48AEA83D05D64B17582FC3EBAD9D8A -:109AD000AB727D0E7F68C578BFFF139AABBCF613DF -:109AE00021F7F7B3C3AE72C72C777B75B6BB7DC7C2 -:109AF0006C777B750E6F1FEC800518CF2F749D1C43 -:109B00003CC17552A30D5F3F5237C2BAD2F420B6A2 -:109B10002F510CC89492BE4A0BBD95331E7E9ACA33 -:109B2000D77F959FC7CF6F53F420EE23FFD6E72949 -:109B3000A93C9FC09EEF48F0DAF2F7B7B2B0B7F297 -:109B4000E47D438C9F7FF043288E768EB1506B78F6 -:109B500085E1D1FF2CCF7BF7F6FB8A9A9CA63AF6DB -:109B6000C5CC3E83A4C30F737E99C2F36D181DD07C -:109B70001E5221D158C9FA6BABF0913DA28447D057 -:109B80001B150EB995232F2FEB970213CF53D02718 -:109B90000360FE9B7CDC501C08EE08F4D166BA180A -:109BA00053E54E07180386C493BEE212CF13ACD719 -:109BB000519E95064F75BF9751BF92791B1C2F1A66 -:109BC00045BF4A1FE5CB9CF27E478037087753BFDD -:109BD0006C97547A7C6CB65F7F2C452F314F56764C -:109BE000E4CBE1B908CA37F1C53394DF30214AFB31 -:109BF000B2B5A5D7B9F2C1FF59AD72F98754BDE32B -:109C00005A09E3BA15579B7DC3F079331357E4F72C -:109C1000AC586EF6D5E4AF3798A78FF99E39D64188 -:109C2000879A4CA3FD6E4D0EF3FDBC92227F63A775 -:109C300054321DF32DEC7A4A0593B40CAEC84CD3C4 -:109C4000C2FD5EE7585F1CED5405D6EF93CE62ED82 -:109C5000E4C571A7FFD2FB542A94B79DF3B95D65A3 -:109C60007A12E1147AB26D047E1FD1EE51E3C95C21 -:109C70007ED16FAB7C5FEB0FE5FEDE176A78409D0F -:109C800035146F8F217E717F3B06BAA4FFC3D9873D -:109C9000F2A52AF6BC8478585BB62836DC7CD90657 -:109CA000EAF0205D18897F16321F4179300C1C3F85 -:109CB000CC0507840BF37FEB0BE3C48783F65229B3 -:109CC00088FD98199518DF870457DE32737306CF25 -:109CD00043F897864DA49F6C6E01F457DB76936C26 -:109CE000865EF5113DEBB9FD54C3ED2193FDC179BD -:109CF00044EB87B7AB654FF939D56D0FB535EF003C -:109D0000679E9BF75C85FD4C871A5ECC8D8FC2F6F3 -:109D1000C3B7337EC13CFB8DCD1A22057A9A752AD2 -:109D20006F688E51797DB341CFF6E61A7ADE8C4D9D -:109D3000E7E2F9A7545725C35B57EC81D8E5ACCAD5 -:109D4000ED283B288FEFDE05682F770F96D93690E8 -:109D5000C1DD3D09785E9F7AEB02DCE7770741F8C9 -:109D600015DA16A05D9D2DDFD1361FCBC2CF10EACC -:109D7000BC6F01EEF76F17F90FA098DA250EBD77CB -:109D80005AC04FFC477B576A6FB5617F414594E1EC -:109D90009105EE3298084F50E3E505816DD43F8977 -:109DA0000036DEA7033FE0E34D11F96DB54B46C029 -:109DB00023F7EF5BAAC1FD5DB525143F52E3717433 -:109DC000BFC2ED6304DC05F6034A92EB3B718E2FB4 -:109DD000FFBA1941AF093846A23F4307F9D1EDF365 -:109DE00069CA0BB9F5F4A91EF776FFE8F0A2D6F51B -:109DF0005B7886ED09353927C0DA47CCDE4C252B58 -:109E00004717672C5ABE058E3B3660E7392669FD39 -:109E1000DB7856746E77ACF0D0D15FCAE3754171D0 -:109E2000FEA4507893AA1847F4030F37940F67AF36 -:109E300095257C68840DCA8BB18D21E19CE1E531CB -:109E40006689AB5C5C37C1553F12AF727DF7EB1F83 -:109E5000777D3F513A5DE299C7A784DD6897CFF5DA -:109E6000CEB3C07E0F1627560570DD34404D8AE113 -:109E7000F5CE2F3C44F80F0DAED385ED6605E58396 -:109E80008B753D8F9775FB7B5DBB59CFCA86FD7D7A -:109E9000062F9BF6F738AF6FD9DFA7F2EF28F759F7 -:109EA000F96B9D67B45BF81D5AC96F0B152958E211 -:109EB000A0CFD8F10DAD08DFF8CBD2318BBDEFFECE -:109EC00050E6F2007A62CE7A776ADC0FFDCC943BE2 -:109ED00062E8AF5C77E64331207927E58C07FE3CEA -:109EE000C0F3C5CA42899E00AD77B3BF98F1E1A126 -:109EF000876483EB21E535D4873E8BE7E3AB10DF46 -:109F000067A25D54C3FDD521F19DE85899AD3F4846 -:109F1000574FF9EF34AED77F87491B0CCEEF159B17 -:109F2000F7D0B890961AD97AAFB0A01FCF1F81B0E2 -:109F3000FB26F2A6509A48939F6F12C3A7CCBE4F40 -:109F4000BEB8BFC5CF706D5CA6FB7089542D8FFB6A -:109F500048C00DDA9163A5E3ECF93DA417CAE39B71 -:109F60005280FA7BED990F35215E02997F0283E1E1 -:109F7000ED1F27A5C040FF6F80C315B8AC07483E52 -:109F800057F7109EBDF85A3788F7B40BEF3F0970AA -:109F90007F7E2CC9DB0DD65358BDA943EB75077BDB -:109FA000E6AB68BF4DE178F48EF35E4012E776DDF4 -:109FB00070D8FD7AEBDF1210716D2D4DF18D67CEEB -:109FC000BC21867EEDCE298CFEB5F9E97F4B80E77A -:109FD0005B19C76E22B9DB3D6923C533D7556F26A0 -:109FE0007BF228B323F0FC747765EEF69DCD3C3F01 -:109FF000E65CB8BBB18AD1A7F37999FCB4DE7ADF0D -:10A000000954B9E28D5A857B3FC8F8AF0FE5E8489F -:10A01000FC27471EE0EB72947C8766213FCF50D629 -:10A020008EF6805F94EF0E1C6F13FA9FE47FF9F2B7 -:10A030001E70E64BBE2FF82213E0722658C1F9A31A -:10A04000DB6F494EFAC5D8FBF98E76F9E8968F1F7B -:10A050001E17EBE17D25DE44CA5F49E9B9E4B3127E -:10A06000FBF42F173ACE7BB52B694D47F86B364A78 -:10A070004EBBF61B6632A439F627A1D805BF5C8813 -:10A08000FB1F259E739FFE29D38C6A6CFC9B9B61F2 -:10A0900046359E4B50AC00D6BB59C934D2BEA2DA6D -:10A0A00047FEF27515D7EDC53C2BABD617C76A6DC9 -:10A0B00015BB1AAB0CE4976D9467FAA6BE2486FD17 -:10A0C0000462EA8CEAB194DF9DC079876B59BF0EB8 -:10A0D0007ADBE3DE2DF8F65BBA3959E3F2E034EDD2 -:10A0E0002F200FDE87788C1B590CCF39F65743F1A0 -:10A0F000CCF3043A2B86E0798EE6E0EB00E27906B9 -:10A10000C9FB9CFE0B86E7B35D780686E7A9593C40 -:10A110007757703C77D66CEEAA72E2B966D7DE4A02 -:10A1200003C7E7787E48E3E773438867079C5E3C94 -:10A1300087255BFF7CAC1DF9D6CBF70CEF7F8FF04A -:10A14000D8EF3F0AFC82ECE1B1E313176AE43F4920 -:10A15000D1FEE94E29AF5EBA442B402F758A757443 -:10A16000A7C03FEBFF0BD47FA9E8DFD6B7421FFEA5 -:10A1700083F66F0B501FB27ACBA89E9EA27DF06033 -:10A180003D0B86D5A3ACDD95C447614FFF268C4AB5 -:10A190001FB37EAEA37E34CFF8069C949E67FDDE8F -:10A1A00044FD2A9E7E4FB13DC1C6E926FC81070FC2 -:10A1B0007F663B2696F4F083D2E3927B363F942F62 -:10A1C00077D7CBAFD77AB85E1B6AD710DFFEBC73E8 -:10A1D000CF6EDC27BDA99BDF46BC8E761DD876608E -:10A1E0005928B94DE376209D83B0BE51946E636DBE -:10A1F00095E33D511E7F77EBA3F1B63D54CDF5407D -:10A2000070947A699FB0D73AC6301955CC9EFE44F7 -:10A21000532E3FC3339A9DB7E6B69B7F8373243F8B -:10A220005182FC6BEDB1CFECE863B4331B7B20971C -:10A230009C4F86923FC7F9A9BA65927A15FE917C28 -:10A24000FD9626AC9D7B6792DCEDC7BC461072186C -:10A250004D6BF4C74519DE0E69E4C288A37FADECEF -:10A26000626B3ECAB10AC62F587F5CD33E29992B38 -:10A270003E6EEF7F10881CFB97719F9B9DA47CB85E -:10A28000C53347D8DFB4D8F6EB6F715E87D49E0B29 -:10A29000A638F06ED3E90E2971E179284FE7713ABB -:10A2A000158F924E03824EB098E7A19E7BEC5C8D99 -:10A2B000FC8B115F02FDF0417F8F5EE2E0A3713EF7 -:10A2C00048F68E02FE7AE8DF7D1CF77F611FED778E -:10A2D000BBC3CBBE83F7EF58BA1A9F6264C7ED6663 -:10A2E000FABEC4A17FBCFEAAC17DF4E2C2F265A79A -:10A2F000587328DE9FBD3FC89D7FC018AB06F3860C -:10A3000056CBDC7F7E67D1D7280F618D15D003A592 -:10A31000A4C7C8FE5B27F2D93A453EDB5A91CFE687 -:10A32000B7566FC5FA9B0012E8976C9997A2787F91 -:10A3300054D1F4D638C2919A837A225A6AAFCF1F89 -:10A340002FC4F53958B6BED1DEC0E61B8DD9E58DD8 -:10A3500064BFB5B77079F3D9E00B0BAD7A64C53E35 -:10A36000A2C7A6BA25C5308C3F325CEBCE9F0B55F9 -:10A37000875C65ADA2C455564B270C1BB7F819FA7C -:10A380008966E17CFA208E70E6C9179E12E476B6E3 -:10A390002C4FEBCF60BEC1D96A7CB381E7A8DD79D1 -:10A3A0009CED416E0F3E8A0E218AE30ABEA8E3713E -:10A3B000D5A2B955BD180782319C2F304FD0C90F97 -:10A3C000F9F8E2AF8D1F5FD1E118E65DDCD21A0526 -:10A3D000CC73B965EEAFE21903E56A5F0CF333DACB -:10A3E00098246965DF37CCFD9591CB9F7C404B2E3F -:10A3F0000F22FEC209B2BF223393F4FC6BCF6B2451 -:10A400007ADE19E47A6E8AA0A782F49C99A5E7BA4D -:10A410003A46CF99D975BE4EE9D10AA1E7F9387EFF -:10A4200019CAA1FFA67DDBCD75BE46944306F45242 -:10A43000FEED865A9F0FFBFF6BE1C5862B3C97C94B -:10A4400047A25326817A61435CF1A11CF99BE3C3C7 -:10A450008FFAE87D017CF8C35C7CB85CD0432EDACF -:10A46000D7942BEF6E4A5072E1653DD28BE3A591F4 -:10A47000E3C5F757C1CBA0BED0922B916FAE88A990 -:10A48000B4EF564ABA3A285EC4F41EC61B56C8A694 -:10A4900081F126F8969FDFC7847ADBA15FFE180C56 -:10A4A00072FB445EBF88E2186C6AB82F63E58F0DBB -:10A4B0001B0F4DFBFB9DF79478F3325E0BBAE31054 -:10A4C000472A961423BDF2F5F776F35E1DCFD5DA51 -:10A4D000F919DEEF2B6448E53AB72885346167F651 -:10A4E000AA84871B99AE9D86F8F8D8423C9FD9591B -:10A4F000D13A8EEC1871AE61C5966775C501E70A51 -:10A5000085A9BFE943E763E37705AAC91247FBF4CE -:10A510005E577B6FBBC1FE447B66B7F9430C3E536D -:10A5200049EDC578B37D7E43DD323F436A330FDCAE -:10A530008C8E270577A1E7388E3CD0D681FB6DB491 -:10A54000BF3EC1F8E4B78FC8F156F6F58ABBCF58C5 -:10A5500088E75A0F01E7179B3E6F3DD0362E175FF5 -:10A56000E4A3CF79A12087E714F3D759210F7FF512 -:10A570005E549C8153CF5F8BF3F197C0CFE15E8E29 -:10A580000FB86B6C4E3AE59BCF209DEC7682CFBC2A -:10A59000EDF3B5637C95E07C95899E5D085F097855 -:10A5A0006DFA9D2CBC23F155608D6CE079AE4A2587 -:10A5B0004172B3B3F43A4BDCEB48F99E72CFB48CE2 -:10A5C000B8D74AE4B54306ED8940A949767448DC1A -:10A5D000CFA355BBE5A612739F9B8835253276BF66 -:10A5E000E8BF0CAC5169DCC1F8711832C12896790A -:10A5F0009C14C51FEE2B02F04DF27BB27639FD9E06 -:10A60000F65311F96A98CB4BF7B2C1E747C86F719F -:10A610008F13BB78F8FC1A6F7D082BC62107DEF379 -:10A62000B753E090639FB341DC2B6AE3DFDCB29465 -:10A63000F2CA83E08BD3FE20D661E1BEAF43ACE724 -:10A640004E7CCEC573BCD375DAAF55F0788B257DC3 -:10A6500099FC0CF6B9337B3CFBBC995D6F24FAAFD7 -:10A66000C6F594637DEF0A717D3AF0B5D47FE33E81 -:10A67000C4FA1318780FC5E3CD1F509CFA9CCC5B2D -:10A6800032FAF79F098DA37ECEE9EF931738D6E50E -:10A6900039E21C0740AF9CEB9C97DF0AEC427E78C6 -:10A6A000EA30DF8F3D75F808D9E14FFDDE9746BEF1 -:10A6B0007BEA83E1F31E1E17FB22BBDEE3BFE7F656 -:10A6C000D9E34A6F512EFB2E3B7E9AEF070FBBF961 -:10A6D00015945E19F965E0A67D32FA071E6FD6A4BF -:10A6E000D799FC9927E679CEE13E19F74D23CD6B3A -:10A6F000AB87BEF63CB7D6737B746BFD9110FAFF47 -:10A70000B73EC1E77BB49E9F8FCD07EFAE669EDF5D -:10A71000B1F589DCF86898C7F7C70D7EA334A75D4B -:10A72000EB3967B54093DDE7BB4E317CBBEBB9DD60 -:10A73000B55B89874F049EBCEBBBAEA711DD08510A -:10A740004836CE9708BDFB5D7E92035F6FF932E617 -:10A750006B2C0D9B12EE65A12FF3249B5789A92525 -:10A76000F0DE98E2FA1E6932E677C4781EF937AF58 -:10A770007E2DF3322BDFDC5444655D379E5B84F81D -:10A7800028D5C99F72337A5C48407F732DE627D065 -:10A790007A64E5C0CD3DE7A13F4B012E2F98C56BF4 -:10A7A00028E3E85E3F72D2E4931BEC473A1EC8B63A -:10A7B000CB3B4F4FDE6D00960C2FC796F3FA16FB7E -:10A7C0008372A8C49367A22F74E7A5443DFD4F454B -:10A7D0005BB5AC80BCF2931C670C6CD30CDC67D708 -:10A7E000FAF434D607630CE60D861B9981C4E83968 -:10A7F000460709CDE591F0BE0EA091FBBF33E03CCA -:10A80000A7D350C4E5D584AB6E97709F7134CEB892 -:10A81000621A96DFCC997FD52EE4C76059DF45F2E6 -:10A82000B4037AF7525C20E9233BFCE6DAD631CE5A -:10A83000F64B8B24DB1F28E80F86323B4B7F363FDD -:10A840003378D65F8EFEB1E56EBC8F962ED714712D -:10A85000793512FD4F761C9B6E43D7478BA0DB03E7 -:10A860001417EDAE195EEE0FA5DB36D277E1DADC18 -:10A87000F9BAD715492E796C3F3548419CF1892C9E -:10A88000EE6796C7CF6EBA7F18F9233BEF67866CE9 -:10A890003FE38C1E13E356E3A1C7C473DF8CA7E329 -:10A8A0001940FE3601ED24661E111FC99EFDDC46CF -:10A8B000C14741789EDAB35560E9A45752A03BF2F4 -:10A8C00054CE93C371F45FACD3C3742F12CA4F9E9E -:10A8D000BFC3F3FC8B39480CBFFD80F22D542E838F -:10A8E000857EBF7A01AFC4F80EF3FB0FBC7500F78D -:10A8F0002BE1996E3A29078A28AF2DE43D2772E0B3 -:10A900009A6B687FE3A1E368F3FEBF5F24ECFF224C -:10A910000893DD24DAE7CBDFB3ED7E1BBFC6B108B9 -:10A92000E5ED741C90081F659313F7E3FE0C7E257C -:10A9300003CFCB0413F3F656FF74167D1F1A574846 -:10A9400054225DDE3A50A4B75616922F9948B6B0FD -:10A95000FAC68140BCD520D5E2D3908E7D12D1516C -:10A960001AA751BED6EA7FF7DF1F18265FCB8E3FAE -:10A970000E96158BE29B5DC674CD294FCA42C95F06 -:10A980001639E3F622AEEBF5AF07C3EDB16760F41D -:10A99000F18FD2F120E2F29F5F84F64B17AE019E59 -:10A9A0001747797A5DE5BCFC46D1944518DFE98A02 -:10A9B000F07271F8C8792D246713E4FF5BC3180E99 -:10A9C000F1087BFDE21E4963FC85C3C80BEFFCD791 -:10A9D0002BFB284FFE9EF0FEF3CF40FAC47DE48FA0 -:10A9E000BBE7FA6DAEFB93DED41BDE2FA2F5AAB750 -:10A9F000637C7A62D2CED774C74526A0D660F39B1B -:10AA0000C408E3677838ED626845B6A9BCACB71CEA -:10AA1000F7C96B4BB78DE1E7FD17EA87C86E972939 -:10AA20003E9D0F5EAF9D9E6FBE76BCDDDBFEAE0829 -:10AA3000BF47D51B17F3FA831E44FC9651FE2C60CA -:10AA4000FE6CA7BF2F673CEA8D22EED76CAF5894FF -:10AA5000B81CE7A598730F327CDC5B1AA57D90FFCC -:10AA6000A2DA4B7D0E7BC3CE6753C47ECE5F9A22A3 -:10AA7000B9A86866D719182F7A5EC61505153D3B2B -:10AA800025B4E7EDFB2010AD174FE5F3C579058040 -:10AA9000DBC5785EE1B863DE1073F8C1509E88FDB7 -:10AAA000DB29A0F7B4F0ACA1F49DDFC5F3D0635768 -:10AAB000F0F34D1395DCF41E7F99EEE3F1AF534BA9 -:10AAC000E77CEDF3C53DEF8AA8B47EA6E8ABF7E2DC -:10AAD0003D771D567112E33103FE5417CAAB0DFFCB -:10AAE000E883CD34FFD1E937454FD03D7A15297D34 -:10AAF0003A2EEF7CEDEE48ED0A129E2D9ECFE0FD42 -:10AB00007E7998EB9B9E94EF36FC6E3E9DDAE9C70A -:10AB10007D678CEFABED7D783294BC3CECB0CF75AB -:10AB2000D3223E9A92BC94E4C0405961F72F0CE2C4 -:10AB30002B4F1EF31D11AE97A718AB79BF9386F765 -:10AB4000CBDA78F9A04B16BF1721134438FC8C914F -:10AB500013B82E6EE472E2EE35BBE8BD7263DF7CA3 -:10AB6000FEBDBF05F5EA1D3EB82297DFA82DC2E362 -:10AB70004193CDCC3AD41B93533E40FBF4F688412D -:10AB8000EFC75FC6F1D43509E238EC69D81FFBCFB7 -:10AB90009E4A95F4D2D852A0FB92C6AE01D2DB6396 -:10ABA0006B206DB072D7CEB93BD1BE55AB218EAE06 -:10ABB000EBDD953758680F6CAA0013F5B8FF46B661 -:10ABC000C0587DD5F0A53150BC29B58CEE6959CB64 -:10ABD000D6255263ADD140F6C3D1182F072AF839D4 -:10ABE00098AE331582C3BE7F9CEC4EA61FFCB5FD0C -:10ABF000265EFD65C015D48F7F2EA7AB71573D9D96 -:10AC000053EB1AF310DD4B635D033CDE69C7A515FA -:10AC1000C65F6C9CF62BF49CFE9523A1E4B79DFCCB -:10AC2000C0F891E44C17E613E4C0676798E3F30EAD -:10AC300021E706FCF0298A97B4F8E83E176FFD6516 -:10AC400002FF775B4BFEE10C23AB6FECEF078B0C45 -:10AC5000977FA3E20395E6B348BE1174A43BB39378 -:10AC6000E8FE17BC18F4745A9617943BCEB3DC1B5D -:10AC7000EF85C98867DB2EAAE5F68C7DEE91E12190 -:10AC8000730FFBAED705E87ED1F14DB9ED23B5408A -:10AC9000FBA8ABC8FC6918F30D443EFFD7972F21E2 -:10ACA0007D9FEFDEDABB235CCEDF2559951D489FE3 -:10ACB00049FCFE196FBD83C25E64F620F1CD268B80 -:10ACC000DFBBB5896D7D1E45BEBA9EDFF3C7DEF3DF -:10ACD000730E06D079F1D80DCBB45CEBD51B57CEF3 -:10ACE000B7EE826A5F3257BCA556D0AD24AECFF71F -:10ACF000F1E983E9B0478B6A81EEFFD2197DD0F686 -:10AD0000AD805E4ABADFD858528971A15B6F540D8D -:10AD10007C7F5F65AFB510E72D41EF839823A3F4E7 -:10AD20009A781EBD223ECEE8769CF72EAE7894CE61 -:10AD3000C3DFFE54000275783FA9E7F7D938E9234D -:10AD400067E96CEBAB7CF32BF4790BC397F3F780DB -:10AD5000308833388F220B0CBA1FD9E8253BF4A872 -:10AD60001544DD0A467D2FD72BED2178308EF7CCA8 -:10AD7000F2F2A6F054C0FB6735A597EC754DAFA273 -:10AD8000725175A29BECF369DBF55CFAE153914AD1 -:10AD900097DF24E4895369C91B9AB89F56852939DE -:10ADA000D6D9C12285DBD3AC29C573ADE1E5EDC9A8 -:10ADB000F2C79B42DFE8D97D32F107C92E468F707A -:10ADC000C5A2B764C77D9C61EFF9622F3D3DE59355 -:10ADD000A5E73AA4A723BEA0D52735A49FC1EC249C -:10ADE000B2FBEB019CF7A66FD22C7E0F8361F82C8F -:10ADF000077ECB85DDA77CA0D079DBBB9676D0FE25 -:10AE0000632CEB03F37AD933E7BDD3078B785E78F5 -:10AE10005751624984F27281EE195E27E4C679F2D5 -:10AE2000CF8298871504A6E7908F16FBE0C11C74AB -:10AE30002D8F703CA743E6E722B3F2CFF77129F7D5 -:10AE40007DA276FB83C20F50B81CE6F39D620ED044 -:10AE500079D2819B0AD3DF036C6EFBD02E57E25C64 -:10AE60004FF719D03E93EE7F4AA3DEDD145B4278A4 -:10AE7000BF0FF529DA56B55C4FFA53DC4F0C864408 -:10AE8000F7CA86C4BD1BF7A58E3C8B76CFD11A05B9 -:10AE90003D3E10AC485AA85F8BABFB2C09F56C69A2 -:10AEA0009AE2C74C8F598867E3AE4504B75FE96DF6 -:10AEB000417D99562084FA7C008D4966C73D127EFB -:10AEC000A403F35DFCB5695064DCD70338EFF737B2 -:10AED000602FD9597EA687C96E52FA5A502EB5D71F -:10AEE000EB14D739EDC63E70EEEFD8B8B7E2B81321 -:10AEF0004AD97846567F7AED8D7C7606D3B3222FD9 -:10AF0000674107EEDF6829B1F2C3E1ED1D686F7E8E -:10AF10004B37BF4EFC93679FC1F8E29E48D9E8F9D2 -:10AF2000E2B9B09B2F06FD27C2EFBAAC4E087A30CB -:10AF30002EFD0D83FBCABD7EC0F99F7BECBE3DF7A5 -:10AF4000307CC8A84FC972E9D9F324FBBE1CFDB000 -:10AF5000AC7CE581A92ACABD5F4D90F1EC30F25975 -:10AF600014F9E71DF0917FE81DD81F9DE180676708 -:10AF700084AF13E8F2BFD6E7F03F5EDEC3CBB6FC8A -:10AF8000FBCA5DEEF29761C938B4BFBE7CBB1FD26D -:10AF900012FEDE29F7BEF99108CF37FF0AA43A1056 -:10AFA000CF6BC5F9A46B1E9BAAA2FD74E50CBD1264 -:10AFB000E39F361CCF0A3DFD36E363C3210FAF0A82 -:10AFC000A755CC977A7DFB8CCF9C0DD84FBA6302E6 -:10AFD000FA0FC7404E3DFEA52E379C23CDC30BB7BD -:10AFE0007DDE281F1CCA1629A71FECC588DB0F763B -:10AFF000B2F7B31F45FB7856F6F7D7D9796627DB4A -:10B00000EF9FF2F47B8D86175103AC527A1AA5AAF2 -:10B010006CDC2BE8B7CC8968FFED989FC1DC7547E5 -:10B02000BDAE02EB35FA86A937D27C5687EE8DA2EB -:10B03000BFA84F8244AEFB77CA42C931D15943EF12 -:10B04000E101F1FB820EBD62DF63DFBF08FD7C0121 -:10B0500060FB7B7A2AC407E4FF91D05EEDC9989526 -:10B06000183F565CFC5184F11466F7AE12F6655138 -:10B070008DFBBBD71F747A94AFEB7AE823FB3FAA12 -:10B080008533329E6BAD73E73FDD59F44592BB2BA0 -:10B09000F7F9C9CE5C09C6ADF533691D921FECFA0C -:10B0A00075A7539CF8FA32236EA15C83B8496D3DB5 -:10B0B0007CB7EA0309D20E3FC12AA55FC5F5B68A5F -:10B0C000E90FE7FBEB62B2F1468EDFDF643FFDA0E4 -:10B0D00019E11AC4838F9FA7D559D931CF233D5287 -:10B0E000238FCB19C5170FB37FBF2EA6D238CBD66F -:10B0F0004D29E6FE21B7DC7C57E8A99F3CFC2D9545 -:10B10000EEA3FAEEAB17201E563C2E83C6C67DF783 -:10B11000E10864487FA555D45F576D9773EA77CCF3 -:10B1200074A2BC94ADDC7F79D5B6407A316B7FD503 -:10B13000A3AF9F050CBE775BFBF74CC475F05DEECB -:10B140005704ABEFAC8BD8FBAB14F8BFB9ECA9CF6D -:10B1500047B9BD7DF847454DB8BEA52D3BBF48FD5D -:10B16000F65EEA0F38E2734BA2FC7C2CABC7FDA065 -:10B17000DF91D25372C4EF6CBFFBE1EF481CBE1DE0 -:10B18000FE7410E1DB72BF9A6470ACDAF21EC993F0 -:10B19000055BBF17453CACDAE18ED3ADD8FA610749 -:10B1A000E6A1AC90A17F31F2B37C8CCA474DAD5F74 -:10B1B00026B9CFCF57AF2492B07A3FF8EDA2DFB0D7 -:10B1C000EF6FC7640832D1FBF6BE83EAE3584E86C0 -:10B1D00053B8C35DB5C32DF7566D799DF222741F28 -:10B1E000F4579C8DF9016EBEF6D667EB4745FB69B7 -:10B1F00055EFBAF7D0AE5CB5FD9D5FA3FC58E59165 -:10B200009F6FE37FCA87FAA9DBA29EFB69B61496FB -:10B210003FB1E27B47EFB5D8B887B7FDEE5ECCB360 -:10B22000BFFAA3F7EFFD67B4179E0AEA28FF577D20 -:10B23000F7852838F8F11EB1FEDE9D045639ABF7CC -:10B24000EE7F06D278A0F5DD277F3B19CFC9BDFB85 -:10B25000C81FC719ACFEF54F9E47F7F25FFFC30545 -:10B26000E387B3AB905FD301275C69A2ABB143E244 -:10B27000C6CB13E2E9A1C7E1470654B477FF2041EA -:10B280003FEAB995BD1FAAB83FD963423FE267F7CD -:10B29000F6D7F77C9595DF61F409E4A00F9BFF4496 -:10B2A0001FE96F2626D973E5F6D71721BCABA09FFF -:10B2B000F4E9107A3ECFE839334B4FEFF7A3704CE7 -:10B2C000C57DC1AA8719FDCE423A32FA9D35947EDA -:10B2D000EFE07FE60EA5DFE351F7BD0947E1EAFBAA -:10B2E000CA7163BA7D6CCE3C886C9C61F87B506CF3 -:10B2F0007930127EAF90385C5D51F3A728EF0F6F65 -:10B300002B1AA4EF62A4EFF78E4E46E3ED4D7FFFBC -:10B3100017110FFD4F0674FCFD12573DF922ADB316 -:10B32000777FF89C6A505C07A2D26C5686C19FFD5D -:10B33000C0CA2BB90F1CAE79E0FF2FFA356B7F0D19 -:10B34000EB02F7998C6E54DEC3D61DD1217D61A32B -:10B35000817A335D46F35E99E6EB61657AE7C578FD -:10B360001F8517EFFE62FB3ED02C3DF1BE8395DBBF -:10B370005F5D847C978F9EF6FC759CFF1CF6FD013B -:10B38000F77AF5D65FC9D627E9292F7DD33B7F8190 -:10B39000CF77EF0F28783EE35D71AFAE97EE59FCA3 -:10B3A0008B73F3A38C431DF7F0C7601C4AE0293F61 -:10B3B0007FF0753ED2FC468BBF77A2868B8F6C3CAC -:10B3C0001E3E965BFE4F2CE6726325F434A2E9EC38 -:10B3D000B55714485A132BB3F01E46FB82C17BF8B5 -:10B3E000BB32F9853A7A77931CF7CA8B9590FBF7B5 -:10B3F0006FD516737B71E58E9D67A15C3BBCEB47F7 -:10B40000C49F2B1F7E55C57DC79E2D3F50FB6AB341 -:10B41000EB01F543DA81EFC3DFDF79169707B9FD5A -:10B420005E73C57C563DE1EE7FD5C3EFB9FA5F612F -:10B43000F592BD30D2386F2BE6A538DFB7F7F9E9C2 -:10B440001EC2B77BE5C65C76F0E462BFCB0EEE7839 -:10B450006ED16FF03CECCCFD21BA7F717BAB39FE35 -:10B4600016B4DFF6FB457CD1FC1DDAA5DB9F0B9102 -:10B470009F67FBFECF503E90DDDF631E7CCE79DE02 -:10B480005A1061FDCDE94BCC948DA172A3EE00DB87 -:10B49000EF39F8E0FAE71AC7A3DCC7FDB181BF5F57 -:10B4A0004E89D3392C39BA88F2CC65DDA70773EA07 -:10B4B0006FDE9F3FCCF7937EC698CEFBDCCF3DF688 -:10B4C0001FB47FEF88FB72E2E13E817FFBF73FD93B -:10B4D000EFD74B9C6FAC67793C24DFFADAD81C8B32 -:10B4E000573354DEDA5C17C7B8CFB5C5FCBE9EB182 -:10B4F0006F18129E2D99DB674CC7F917432FE0791F -:10B50000FFDB9BF5B8333E5476D86CC17A67BF0930 -:10B5100071AC87E3E27E6DB4E35AC5FCDCF3907155 -:10B520006B7B092F858CAB9DC0B8B79E8271C327FA -:10B53000806780CD058DEBCDB3F28EAF4EE379639E -:10B54000DEF192B63E10F1055A7AC3F8DBFCA29FF9 -:10B55000A5C586EBF7958192A17BABB3791769A955 -:10B560007326C6EF06CF1B2734C77963F69DCE1B23 -:10B57000B7993C0F96B5A375D025FC1318CF5CE6A0 -:10B5800080F705219F0215A918DA5F9D79E211AFB6 -:10B59000083EEF8C346838999DFAF4E2BE61F48677 -:10B5A000B2E69B339CE792153D23B9E2C8E6EB7403 -:10B5B0007F56BEF6DEF8A20D7FE7CE7F82AAA9985D -:10B5C000379B80D61C706E17EB07EB5562BD581287 -:10B5D0005A1CF5D4189FA75DEE147EA1576E7DA569 -:10B5E00093E2F679F0B443D0F30574CC97D1F64DDD -:10B5F000C3F86F57C44772B22B98FB1EFBFF2CF6A3 -:10B60000B9E4A48AE71FC90FBB8FF68DC6B1974D69 -:10B61000BC1FE9D65A95FC6091FAFD543E6AFAC8FF -:10B62000FACF871FFB3E83C1721EFF53BDCEE9BB1D -:10B63000DBDC46F9B1D74D558DE1F22D426BA6C545 -:10B64000316F425B73761CCF6B876AF8EF61D8303D -:10B650000FE26106DF863CFCF13F595ADE2D008087 -:10B66000000000001F8B080000000000000BED7DB3 -:10B670000B5C54D79DF0B93377EE3C813B30C0F082 -:10B68000BE8310D1623A28A2363E2E0F0D3E62468E -:10B69000C4A809D6D13C4A2218B436A11B1B2E02DD -:10B6A00082F8C2266BCDAE4D47A22D6DD31653DA6C -:10B6B000358FF61B4C74ED635B626CE2F6D30613B8 -:10B6C00037AB59D365B7CDD6ED9736DFF9FFCFBD90 -:10B6D000CCBDC30C68DAF4B7FB7D4B7EC9C9B9E7B2 -:10B6E000F53FFFF37F9FC77C4AE4089949C8EE2DD8 -:10B6F000840C151342F8B08DB808D95762B2433A9A -:10B70000284F4F1AA6E987F0B7606C6A6DFEDB1907 -:10B71000553322F9CEBC442E48FBD999F73819A6E7 -:10B72000A9F5831612A0EDAD3C91FB69EA96C960BC -:10B730009287E6E55B7C561F4D5D24C3544ADB953A -:10B74000DFC2EDF08DED7F30E711EF5BB45DBA4CF9 -:10B750003220ED2C17324C3A787ABED04402749CD9 -:10B760008E72612DC0690D7F9E480991F2274513A5 -:10B7700021A9F47B5D8F2CC3FC08C90824C03C4977 -:10B78000468DAE5E0F47D6F4178F1DFF10E087B6CB -:10B79000DFAD96EF9BF3CEA17B29FCA22C95986997 -:10B7A00037FB06AF92FC69341FBE2A73302F0F9906 -:10B7B0006E2763FB817A3E5A2FD11B241B00CEECEF -:10B7C0006112A4E327160D1398BF43229249C27E4B -:10B7D00010FEA4D92344A1F592E60E7B9569BA7EAA -:10B7E000FE608E09A719E649D7D1D15CEA2F48211E -:10B7F000C4D63CDF5F40D725811F2222ED2741625E -:10B80000F88F6EF7CF490C3F1A5E7ACA6F490AC6A5 -:10B81000E87F747D5BCEA4F1165DBEBC670DE0DFF2 -:10B82000E2092A30FFC4D90C2F5A79A2344C643A69 -:10B830006E2261F324A5443E4693845285C0387439 -:10B8400048593F9F07547A7C409D0FFCC969588F27 -:10B8500010FA29415E74D57C2BE479F256112BFF46 -:10B86000D0477041DFB2A979F3D87CBCF94C94EE93 -:10B870006A21E42DDD7C6DD974FE5ABFF4DF1E0B06 -:10B88000C900FC7E54BC09DE61A407EDFB3675FEE1 -:10B8900016CF30E2670CFE8A19FE9CC50C7FCE28BD -:10B8A000FCED55DBEFFD2F86BF513C71A63540877F -:10B8B000D178D4EA578CC2AD205DD276847C0AF26E -:10B8C000816AE0DF1E3BCB1F12EFAC06FE00BE9A82 -:10B8D000805F08C9A44D7AB82E28CF1545ECDF7AD1 -:10B8E0001F9507FA7C50930F6C5C97CF5F4D283DF6 -:10B8F000139F891CA328ED9AAB7861BDBA9153229E -:10B90000FDFFA33809EB774A8289FB244DCF2C4CED -:10B9100007B9D966EBB1C17CBB2C3DD84F5B8E49D2 -:10B92000EC8D21DF4EABF335373B671C9D111F8F2C -:10B9300066810463F1FDDBAA7C6B1B7CEA8C99D2E7 -:10B94000072F09929DC20B4CFFB6B6BEF9B43DE974 -:10B950001FF2F9609C441CC7A5C2E52A349156DF4A -:10B96000C4701E57E98A6FB68F0B270F70C69033CD -:10B970001A9CED00A7273E9CCE9C0AA453BED985F5 -:10B98000E30C8A125B0F4B936D239D9FAB35496A85 -:10B99000A5E92EBEA9AB0ED2210B5168150B91CF94 -:10B9A0005450B8F969D309A1FD745C9A659B04B43D -:10B9B000DFDC43023A391F74042F89B43F5E0C92D6 -:10B9C00020859377293280F1AC4A07DABA91A264D4 -:10B9D00042E6D0F182FC0C90A7CEA080A9D68F467B -:10B9E000274E8B4CC462E8C7248740DF416773222F -:10B9F000F5E6BB19DEDAE6860354F691EE129EEC0C -:10BA0000A09FDA8B28BD24D1BC45EEAAA3F8E87E1E -:10BA1000D5427A757CA08D9BEB66FAC74E6A93C2BD -:10BA2000D0B7F9B037388E3EB603DE68BBE60BBE42 -:10BA3000EFBCA2E115FE15133CEF38917633809FE1 -:10BA4000DF27C5AB4DA6F8FDFCAE45FACE2B3A7903 -:10BA5000D54C98FE20444A5F312D7EBBDD2D6446D7 -:10BA6000416124BF870F213EBB5DBD5DF9749E8A95 -:10BA7000DFE42FA4EB45B24B0D788A4E096965725D -:10BA800070CCBAAE96C2B47D779189B702BD1690DC -:10BA90009019F092ED41BED4D635E8607463F13070 -:10BAA000396976C998DA008F20EFCC7BBCE3C96B8B -:10BAB0001BF0490C3C16B9291E3FF1DF0F8F1E37D2 -:10BAC000C1D499509304F8232FEF22D23400C3C875 -:10BAD0007F5A3B8DDEA3E75FFDDF7CFE1A9DC4AF7E -:10BAE000AF68F6103F48AB660549A89BC37CC0967B -:10BAF000864D29E854A5D8C2ADA09A72EAFA334E11 -:10BB000011D0CFEDE23B36145DFE0F53C6EB9F27FD -:10BB1000EF68F83447C6D3E3C7047AE78C25748C02 -:10BB20008BE02941FCB47790DC089E9A6C208F3A18 -:10BB30005D5BCFF84A2378EACC7E4EDCA0A3F72BDE -:10BB40006285E2A6F8D809766D0C7972AFBBA21DAA -:10BB5000CA05536C797E48956B5480F30BE9380B1A -:10BB6000468C789AA7E2697EFA3B8FC134A994E4A7 -:10BB70000915C815017F15E0AD6A4D00C882085946 -:10BB80001F7C2288F45025025E3865B2E943E78DB8 -:10BB9000E32F1EBE5C1C09C482FB19B1E6881BF4AE -:10BBA0004931C59BCEFEA08421A27CD4D6C5E5999F -:10BBB00080AED8BABD7C31DDA4D0AA9D5E5308FC0E -:10BBC000190B69EA02BC93736602765A5A3803CBA2 -:10BBD000ADDEFC10E8BBB4B09DC8E82788213BADC2 -:10BBE0007F70ED5D7ED443D76F23614A3728CB4009 -:10BBF0008E65CB61B0A779512A374B30CEA336F092 -:10BC00006F3ABD354984D9DB24961ED8E20EFE007A -:10BC1000D68DBF3E1FFB33D998DCBBD1F97C69655B -:10BC200022013BC07E810B812E3BB0727ED77029F2 -:10BC3000C8CD841E2B4DDB78250C7A4CB96097005B -:10BC4000DF5B0B95DB4D342DFF95BD88A7DFBB383F -:10BC5000871FF0D05548979CF6F3BBA79C2142F371 -:10BC60003B572E1F49827E8E9A25287FF2C3A64F0E -:10BC7000823D65FB603FFA8736D53F247CD32C5844 -:10BC80003FFB479413BBF91EA4FF5D05D36D7AF902 -:10BC90009EEA080E035EB4BCDD4BE5DB0CA4A7B73F -:10BCA00086293D99148E7C48E9D3E6DAE63D25C124 -:10BCB0007CE9778D3E7C917A11BE35E63D14D760E4 -:10BCC0006712726431D8919D206FD06E250A07EB00 -:10BCD00096C1CADF3FB06231D8A19D76AD7CE562E6 -:10BCE000599F57FE7006F3AADDEB4FF6EC82FA9EE1 -:10BCF0002CD2C4F01320AB74F64C41328FEBD6E754 -:10BD0000967FEFD6D9CD1A5D761530BA7CF9626789 -:10BD100035C8CD4E4A975609E87097C14FD6528D17 -:10BD20000E3B0B189DC5C3BBE57A0909EBEC408BB4 -:10BD3000A707E9D1E609A01D1D5D7F450AB363345D -:10BD4000FAB77909F2834D0A3E753FF287CB0FECC3 -:10BD5000672D68221CA5138BC8FCE189E6110F3EF4 -:10BD60008DFE3B0BF215A0D7F745E227E3D4B75C75 -:10BD70002FC5F96C71CB93927578F4E451BCC798D8 -:10BD8000CF5792D97C3A027581FB69BF72BDA4205E -:10BD9000DF7889BF1BF412257FB03BA9BDF9C9E448 -:10BDA000543D9E983DA2F5AF704D8316E0730F6D24 -:10BDB00047BFB6939714587A8B2764E0EF2FA604F9 -:10BDC00067EBFBE145E61F2E34BB4CE423E0673F05 -:10BDD000F5CBC293A99FD82262BAA7C58B69578BAE -:10BDE0008469778B4CC256EAFE90EBE7EF053BDBAC -:10BDF000E540F826A28B8E163FB66F6F99CDFAE11B -:10BE0000343A9FBA0BE8C261D2F8C4BF0BE83CC910 -:10BE1000AC959761BE8763E58F242F58AC14E37C03 -:10BE200050EE754D30AE395486EB77F3FDABF25BD7 -:10BE3000C5DFFE798F54E703FDBD6126FA38C618C9 -:10BE40007A09B3F16EB4FFAE6C13CAD3FDF3769EDC -:10BE5000F1D1BCE575DAFF78F4D8C3FA8FDB9F0621 -:10BE6000EFE02E84D74AD7DB4EFBB38A4CDEC7E324 -:10BE700087E8F9D294207F7808CAE9FD836BC9CBA3 -:10BE8000C09F7458BB087C1A9021DE25B4531CFB5C -:10BE900041DF06C2CF80BEB571E418CD0B2ADF505A -:10BEA000B5AFBC4CFB11641BE9A6ED06E7DD45A070 -:10BEB0005DE72B360A13A5D3947CB417EC85B5A4A3 -:10BEC0008DD6DB596D2766FA3D69FE1A02FDEDFC41 -:10BED000991DFBF79D9982FCBA4B647C34A11CF23E -:10BEE0009A4858AFC76D8E483E1FE4E57D24300D5B -:10BEF000F9FA693D5F533DD90BFC24902A8570A067 -:10BF0000871FF0333B4451E569E05832DA81016C18 -:10BF10001FB10B9B8808FC7ACE1CEA06BFC4DC80EC -:10BF200046DF22F361DB30F2B5BC3CA38C10170373 -:10BF300081ECF287492EE025C34C6D31204B818482 -:10BF4000A9DEE8A1FF007CFC85AB17C8AD84A4AFD7 -:10BF5000110CF3E02F382F996E05F8587D4D0FF135 -:10BF6000171A1BA13E4F74F5D19FA94B1ACF2F8CE6 -:10BF7000B6E30793557FD0497240EFB5B79C206F69 -:10BF80005B22FDF05171252DD5ECF9875358DC6209 -:10BF9000949E2446DF2F503F1DE8B1E31766D21B65 -:10BFA00083BEAF27FB0CF66E46D014991FFDF795A4 -:10BFB0008BD68A8306FA1C7FFDB3EA8DED739A1C3B -:10BFC000063CE635271BF23E25D3507F5257BEA1D3 -:10BFD000BCB067AAA17CF2A1E986FC94D0A70CF5BD -:10BFE0003FD15761C84FEB5F62A8FFC91335867C0C -:10BFF00049F86E43FD1967361ACA670E3D64289FDB -:10C00000757EAB213F67F8AF0CF5BD41F1E409E067 -:10C010004F4A8F668AAF5D19CA21D09FC36DD48EF7 -:10C020009BCFEC63D0B7249BA8F631554C694057A1 -:10C03000ECAF1DF400C8F93D8F85BF807AD2E407CC -:10C04000FEE50B16C91BA15DBB68225E9D1C911607 -:10C0500011F85EB1C78DDFE5D256E40F81AA0D7BE2 -:10C0600022E86DE37A10F376D20FF0BDC1E0E3452C -:10C0700025A67C12B28DF46F25F72405C6B1FB2CE2 -:10C0800092B1FECDD2BF2F45A5FF1C4AFFE689DB4A -:10C090006B74FF90499E9CC2FCC3AA731E83DF830E -:10C0A000781DF57B6CA41DD8A9BC6E24EB14ABAE37 -:10C0B000FA3756D3879FB871FF269ABF684A714EE8 -:10C0C000D7C9CBE4B566DF8FD587330CF65974DA60 -:10C0D00096F810CA3B2A17CB530C72315005F31354 -:10C0E0007819E5A2F6DDD73715E57297C8EC944EBE -:10C0F00089F2E538F88A96CB5F4E9698BF18473E8E -:10C100000B54CE82C2DDB9F2D35D8037791B41BDBD -:10C11000447510CAD9E8FEA95D7537C2E965F4A473 -:10C12000F9439ABF65A3F203FC2B9B44105F568A28 -:10C130002F27DA478FA27D49E721817D64F550FBE7 -:10C1400013F43DB53F99BDF9E7B52FF361DE7AFBF6 -:10C150004FD5972187DC94921ABFFF17E3EC479DD8 -:10C1600049D6FCEEFF9EF427A718F1A1D1A146679E -:10C1700056203A3ADEFB125B77DA2291D3F62F246F -:10C18000F84F10E9E5D4ECB34A25AC5BD0255BA9A8 -:10C190005EDD37BB06DB0993780272266178C33215 -:10C1A000D093A494C90985FE03F4E62836CA0D5B32 -:10C1B000941E15401F278ED5BB9A7CD0FCF389E4D2 -:10C1C000CBB752D438D92C324B2F5FE2F9E19A7CAD -:10C1D000D1F0B0E0831611ED8E0F68B9664FD07EB6 -:10C1E0002C397C00E2CC829FC84762F0DFCBAA5E8C -:10C1F000EE3B6997812E5D6B04F4B332FDE172C8AA -:10C200006736113FE067F670980469FF3FF4B0F5B8 -:10C21000C8F48738B0CF332F873880F3A085C58521 -:10C2200032B785387DDCE89AEAC7FDEEE2A37E5896 -:10C23000F78A3C17F2E9671713A48F21EFC69E72A5 -:10C24000D857984BFCC03F2E0F4F32217FDE1A4249 -:10C2500079E21F51A8AF4392E944614DAFB490E930 -:10C26000F751FFFDDD161BA6D75A444C2BF38A0766 -:10C2700017D07A5B7D0E8C1774E43B709CCE5C010A -:10C28000C7F98F9C87F2C02EF8758B17EB773DDED0 -:10C290005404F184CE93FF8971CD083D53AC7901EC -:10C2A0009E30EEF710BEC90BFBBE49F20CDC27ED49 -:10C2B000B404FF7103C413D70AFE6331F837E9E50C -:10C2C0001FA19F0CF8013CB4DB195EACCE26BF1B4E -:10C2D000E2FD93C8FA15B1F854C513A530B340E98F -:10C2E0003789910611E686DA1241AFFA493F059B7C -:10C2F000583A421CEC8790074509E245D9B6D02050 -:10C300009467D78BFE36AC4F705F415B278B9D04E3 -:10C310008EBBA05E98DB42BFBFE811D9FA0D8570D5 -:10C32000DFFD37176E1FCC21F1F97B4F4BF5D92A72 -:10C330005D3CD64562EF0BFFCB6D15160FEDF77622 -:10C34000806D26ACF7AC71F5E38DF67BBB8753E3CC -:10C350001393D3C15E6EE663DB996691AD0FC47F24 -:10C36000C08FDE5A28A5BB5DFA7E183ECC279FC73A -:10C37000F57116B3F9B77DEF8DCD8F513AF977DAB4 -:10C3800010E255AF5CFC0CFA8FEF254BFBC1EF526E -:10C390007E6C26B0CEEF7D7FD669589431F36E392E -:10C3A00093CCEBE249EF7DFBD5320BEDFFBDE75EB1 -:10C3B0002DE3510885101F5A79E387AF9541FC4A58 -:10C3C00068FE4DE6650AAF52418A9A204F0D68E635 -:10C3D000876E591A1E076F07D31ED802F1C2509BF1 -:10C3E0004BE4A8BDF625E71F05A0C766809FA60FF2 -:10C3F000DB4676727489B9F4779754D1FEB6728AA7 -:10C40000E2E2006F8A15FC0A72C1EA07BAD95AC87B -:10C41000F4E5D607C59002722CDCC4C8DDF65AE6F6 -:10C42000652A87ED3F0DC11900D2CE052A13207E63 -:10C43000378D20BDDF76AD290FF695DD44C8073A6C -:10C44000B498CCD8CFC84567A817E56FD32C9043D4 -:10C45000AD171F9D0CEBF57B55BE6871B73453D3F8 -:10C46000813A1FC4DDFC1877DBCDF7639C3EDE7C90 -:10C470009D5EB6AFC0571235DEF5DBEE7076841EDA -:10C4800034FE8A6EB7B785F861BC975A6C98BED0F7 -:10C4900022627AA2C58BE9F75B244C075A8A30EDF9 -:10C4A0006BF1FB0B2C00E76C4C3B2C647D40476729 -:10C4B0005FF0B0FDC87B92CABF0074FE24EDF73276 -:10C4C0006DF745DAFE32AD3FAF366C86B8CCBC11A5 -:10C4D0002A2F2528EFC2EFFB697F506F6CB9AD049E -:10C4E000CA4BABFBC380C7D262FA9D407F7D587FA9 -:10C4F0007FCB093F2B1FAAB450FC96FE96953BE7D5 -:10C50000D27E68DEA9F643C72F61F567637F745C4E -:10C51000CCC7E8B784C173A224163CD1F5A9956FA6 -:10C5200026548F88F0BFE0EF59240EF75138123EA1 -:10C5300006F2F882B51CF4E79E12926FA2FACD9231 -:10C540005AC041FEA966229A4BA8CACBA8D9554E1B -:10C55000A09D8CDF95557CE8980FF513F6ABE9A705 -:10C56000E4EA30EA9D243FC937BB69CAD381A753A7 -:10C5700054DF4722E70D503EB13CAE076D2756937E -:10C58000C8790332717DAA5FA2CA63D3DB474D210C -:10C590003EA63FF771701EB1835F4B7DFD7E924BCF -:10C5A000F3AA7DF645B5DEFE7965491B21BFF8810A -:10C5B000A7200EFE1BE2E5603F7EB47D943D77B878 -:10C5C000E54C5A55A1AA1440DE6F138FE8EDDC6CE0 -:10C5D00085D2AB8E0F7A9AF8EA5E8C2F04336A7498 -:10C5E000FAADC312CCA0CC4BAE3FF18F8B413E8055 -:10C5F000BE06393D7784E9F751BDFE5B261F357BCA -:10C600004250D76B9FBCB12D01F7D3A83E92C0AE6C -:10C6100008920ADA3EB17CEBCBF09D9418BF270854 -:10C620008C8F32BD210EF2999EC04F3CB0DF907CC2 -:10C63000487E86CEF7B7035609E8AFEFE4DA7A888A -:10C640001B3E4C12253BED27F3A54B02C0D1611ACE -:10C65000168008473CCD4B786A0775089A9CA486DB -:10C660000F5DFF8E34552E90DF7757D1FA074DC1FD -:10C67000AB54578ED63FE8086E813CFD936D54AFA6 -:10C68000EF1D8DA36FEB96294DEC55E3E6239ECF6E -:10C69000762BD990A7F5DD2CDF4EDBEF750F794DAA -:10C6A000349FC86DE93E930379ADFE966E85B6BFA3 -:10C6B000EA61E700882BE803B9379A17693E41978A -:10C6C000E7599ED858DA77F23F05D0431D6923A772 -:10C6D000B3009F3FE4FA41BE36BEFCF541C86FAEE1 -:10C6E0002712C4E7324F1CC175F8AAB97C04F0D6F2 -:10C6F000D7724644431DFEB475A176EA142FC17863 -:10C70000B210E242F960BF15F798D07EDB4E49B017 -:10C7100004F0DD9506EB5C91C6FC812921DA8F8E51 -:10C720007FA650BEB34E0775651919D6FB5BC46F63 -:10C73000027811E5F01FE57F2F01FDD4375B714CC6 -:10C74000A5E36DDAC0FB5B25D03FA15601D6FF04FF -:10C75000877AC2772663C73768FE5A7F4A2FF81B4D -:10C76000961D8C3E37F9FAD3A6D3B4C3CEE86293B4 -:10C770005BCDBB8DF976D59EF4BA157732FDBEF947 -:10C78000C4815C3000AF1E9B857EE4660D1E720086 -:10C79000E1B93A3827E9363ADFC69FB2B866E340D6 -:10C7A000C912987FE31E13013F6EF300A5271D7F7A -:10C7B000ECA37C284FA6F3907BA6F2943E02070BD5 -:10C7C00096DAE9FA7E3D5F16015FF569B7EEB6517C -:10C7D000E7E8EB823805E8A13EAD7437D0D3A6393F -:10C7E0006F213D26A596FEA49AE2EBE8DDD54B40ED -:10C7F000ACA599185F5282433967766F43FCFF6B93 -:10C800003919B1BA119DB8CF9907FF47E19B2CCADE -:10C8100015505F5C465D22A053217012EC10A5C23A -:10C820008671D20A711996E7AE21A66E0ACF112938 -:10C8300039B99536B517C826B053F2030E8C7F9AD6 -:10C8400013AA76803F7AEC1CCB47D6E912E2C55199 -:10C8500014EAB7D17E6E71F122F8226966D906EB2F -:10C86000467979E85829F00BB303942F1663BCE797 -:10C870006022A97F8EB63B6ADAD8FD235AEF68B2F0 -:10C8800087805DD9C171EB6BF07BC5D4AD743D8EF3 -:10C89000AAEB6776FB4558AFA36E637E2FB7F141D5 -:10C8A000C0DB23A92F2E81F9A559E59E140ADFE7E5 -:10C8B000525FECF666209EF36DB4FC737FFD42B7C9 -:10C8C0008DE2FD68AB9C29EAF293FF40A536CEE3EA -:10C8D00005E453DEFDC587808F69F98F6D54FF7EB7 -:10C8E0003D59B307587941BEC6D7D4AF9D4DE168D5 -:10C8F0001DCD2BB622D8F78AD4AFA27CFED5A7CD0A -:10C9000044EB1FEC09C79C7E9BC38CF3200EB067E1 -:10C91000A6F168CF38DC6C5D1D53F2D14E3A6A67E0 -:10C92000F81AC93161F922F3B322C407AC53781362 -:10C930009EE5214D01D0CF7C364F58BCF7B03C4529 -:10C9400082B029DB1FE47A56A07F682FD2ED071250 -:10C95000F0638DFB877C54BED03A9C61A27AD87379 -:10C960006105974BFBFB6CAAEA2F7A4806C4631F4C -:10C970004D6572E6D18072BB45021A1B66E75649C7 -:10C98000603AA4E9EB0AD2C73BBF32F65C4018ED2F -:10C99000B23D2E938AB749BBC305D45E763D27824C -:10C9A0001CA16A7EC761D06F1E1EE9A610F89FE623 -:10C9B000B7B9591CDED7B7E44BB3C13E7CB5D00440 -:10C9C000FCCF8B7E11CED99527942681DDC68FD2E0 -:10C9D000E9EB4BC240378373EE043F5000FEA59F46 -:10C9E0000FDBD9F9D0910CD20F7161DE2B13FD3E14 -:10C9F000A1C6BF3B5B6C98527FFE5DD01F5FEB22F0 -:10CA0000B84F2078039897DA09077CF1F2A7EEC6B1 -:10CA1000719FE10349EB40DE9E63763D900BC63982 -:10CA2000C24F7010E778DF16488279EF771BEDBFB1 -:10CA3000B23466C776A632F9D9D9C2E2A0C2F54FA0 -:10CA4000605CA7C3A2C923D7D2F05CB0E783788E1D -:10CA5000D61ADC2683BCB21145117571725BB631F2 -:10CA6000DE255CBF95C58752D938D1E70D5C9CD6D1 -:10CA70007FC1EEF1FC032D8D3E9FD04C02288FC864 -:10CA8000103BF7B06D57657AB2AE9F6D9C9C2E8EB1 -:10CA9000431F0F5F379390EE9CCAC3FC8800F37965 -:10CAA000F8BA80DF897738B115F66528C175C33AC1 -:10CAB0003EFF5DD44B0ED213860373568853E8CEE7 -:10CAC00085122F3F324AFFF911FEC07D752E067F79 -:10CAD00048C67CF47EFAA3E03BD37F77387F2DC035 -:10CAE0003CDFAB242360871232BC08F8B7B1D28197 -:10CAF00071EA87498FCD06062EDF23EAE3C58D0351 -:10CB000097123794E23E960476F0C32F951BE254B9 -:10CB1000DAF9302DBFF9C4068C1F3E7CF49A30B58B -:10CB200014C118B2507FACD1D673C69A1FA96FB783 -:10CB300004952CA0FF975AE52CFAE95B00279CABE3 -:10CB40006A9E340BFCBFDF8AF519802727AFEA8F76 -:10CB50003536D41FED76EAAF019D5E9C8CFA9416B3 -:10CB6000F3A09FB5F15778181D8EA8FE7C023533CF -:10CB700001BF1D8EC01566B41399A7F64E47B24685 -:10CB800037CDDDA0FF0E0A11B908933DE860F9E446 -:10CB9000B4E6EE76A687B1FEC893FC6EB0873AEC99 -:10CBA0006ADE43307F50E8413F41F9BE5502380FFD -:10CBB0003A027EF007951D5324D02755E92E9C8715 -:10CBC000E5EFACBD200F333DC1AB60B7100FB38FA5 -:10CBD000DE4BBD904B5C31FB19E16EA41FAFB11F62 -:10CBE000FB5C36FE7B9C39B0A334528FB60FE3B9A1 -:10CBF000807B6C18FFD1EA1FB618ED642D9D92C69C -:10CC0000E20C204F80AFB5EF42F03EE45F2B69426B -:10CC1000FEB57A8DFB451A3F0BD7A718E297DF4A7E -:10CC2000F5E1FA687240B85E8CE59D2A9DEE847D40 -:10CC3000F471C7498E33CE0C9413F1C72953E5081C -:10CC400051E3493C9E33D3F824BEBC30C671A3E502 -:10CC50009F966AF2EF884AC7FF600F2E4CA3FFFF32 -:10CC600050A87F91035B076F85F5F9A36AF716F566 -:10CC70001D3809E47745945B5353E13C957C1CD205 -:10CC80009BE59BFA3436DE5839C6E20FDB1E945022 -:10CC90003F3FC3FB1DFE1870D75F771AE4577EAA8B -:10CCA00084FDD5F30ACAB1FAEB8958FED1FBB793DC -:10CCB000D08CF1FA7761F968FFFDACFF973FF5E39F -:10CCC00083B3A1FFE3169355E7CF6D3BBE301DE262 -:10CCD00095DBEC542E1BF95606BEE57D64D40F029D -:10CCE0003EDFAFF945CAA2DD5573C16ED5F1F96CCF -:10CCF000B0BF22ED79BACEFB1D5AFB3B77833D34A2 -:10CD0000A6BE33AA7EBED6FF6AEC3F1A1E4D8E40E9 -:10CD10001EEC2DFE0F560D3E9443074C51FD8DCA5F -:10CD2000A520F6B7690EB33392FEBAFE270A0FF4B8 -:10CD3000172ACF023BEB4122C139E768BC27A9740F -:10CD4000587F7D92615D23F8BEC5F0FD9F5BBC24DA -:10CD5000A4E3B7CF04B72D027E4BD2D689283BB1CE -:10CD6000DDE12C12D2F1DDFFC0F151E1B82D0E1C36 -:10CD7000F3FFC270F80C7C1981A3C0F0FDA3C2615F -:10CD8000B65DCFBCACCB5B4492A5CF97846D599771 -:10CD90007576CB8C33A2213F73C86BA83FEBBC6484 -:10CDA000289F335C6428BFED8ADF909F3732DB50C9 -:10CDB0007FC175D9902F278B0DF52B6D2B0CF98525 -:10CDC000E25A43FD696A9CFC76EF0643BDC5D283F7 -:10CDD000867A4273CA77C07E59F0C1021BF8173BAE -:10CDE0005DA6EA10C5CF4E3E684B8E211FCBD47E88 -:10CDF00047F59D370DDB2F149BDA411E2EA4AE7034 -:10CE00001BB5D7D2EB02EDA0F7AB45229AD16F0E3E -:10CE1000B1F8C9072BABE0FB9D8B89D8ED8EE46F91 -:10CE2000FF2B42206FCD96F15C9BBDD884E7067640 -:10CE300017D78CBBFFB04FB5DFF744E9FB51FA3190 -:10CE4000B3F393D1DF8BD3195D1D58B08FC03E81F2 -:10CE5000CD15C27B3E8353767A21FFA505DFF6828E -:10CE60009FD135E5112FD04F67CE570DE7F21C0546 -:10CE70006C7F26BADFBF55FB2DB8FEA80DF4E7EE98 -:10CE80006C86CFE87ADAF9F4DD361637FFB8E6B902 -:10CE9000F8639AE7E5746667EDB68530FEDF5DF40A -:10CEA000F1C07FAF3ACE81058F1306EFE3780EB95C -:10CEB0002B4790F47A564BE1DE28CCA7D3B7D30B9F -:10CEC0007AB7CBF788C1FEB7C27C628C63F3323C81 -:10CED000ED163FDEF93CFE27CF6767CC7D775B9C84 -:10CEE00079156BF3F2AAF7283EA6793DF5179E5700 -:10CEF000581D2F359DD9A7BB25C64749E6C0CFF39E -:10CF00007DF1F92F69B6F19C5282DFE807E417043E -:10CF1000C63D7F745EC54F3C7E5D635152018ED726 -:10CF20005BD839DB7380479A9E0F4EAA80FB0AAF0D -:10CF3000C3792D0EDAEF48186F1DD606CD063827B7 -:10CF4000920F25E9F9888FD56B8CED56059CC6F3B9 -:10CF500052EA39038AA7FD105FD6F036669DFF4C72 -:10CF6000788A476F378AA7EEA29BC3D344F49D9A71 -:10CF70002E21BD4C84278D8EE2F5F3FF2A1D2DBE98 -:10CF800071FC20FD7CDCF8F9AF463FF7A64B37C4B7 -:10CF900067FFBFE2E7F11BC4CFE8796B81D4C73AE2 -:10CFA00007D2E915900E27734D6717839FBDD88C64 -:10CFB000F1B3D70E1734927C7D3DA6075E5B36A990 -:10CFC00011CF8F553BF1ACD65953EC7E5F53F1F145 -:10CFD00090D7AD9EA7F3A782DD7BB67AE5B8F322A2 -:10CFE000CBCCC6F38BC411999F99F64BA40A8C9FA6 -:10CFF00051BC1E1B67DDB5758B37DE8DAEDBD9EA04 -:10D00000B69B5A376D3C8AA798EDEEF6E6DF10DF47 -:10D01000C309768637761EA0EF7166B7F701BE6941 -:10D02000BFBF84A20CB0FF09C6FD56AF493F02F056 -:10D03000BEE665F1F001416AC47741562EDB0DE78B -:10D0400051CEAD727310D2D0E038A6AE67595D6C88 -:10D05000BBF339B53CD29E2393A5B1F58EA876CF0C -:10D06000AA3A0EED07C2CB39FA773FFE21AA3CBAA5 -:10D07000FD4BDE442C3F17E73CE6B7D4F6AB6BC75D -:10D080006F4FEA53F0DC1F21528EFE3EFA285DA955 -:10D090007CB0C21BFCBE97D67F9D0B7EF973104FF0 -:10D0A0009DE2C2F33D84273ED8F71FED8797F1BC80 -:10D0B000C6E54686F7E87E75FD85BDA9F1FB8B8741 -:10D0C0005F6D5EDA78A524807E1DA926E27E36BEDD -:10D0D00019CE39DC59499A707C5E427852DEA4FE42 -:10D0E0009C2F421F174CD23ABC48A3F633F0FBCA20 -:10D0F000A5D0CFC05993B8C3171FEE78F2E09F5464 -:10D10000FAF198833BE05C0159CFC53CB7F72BAFF0 -:10D110001DEBEDF78EEED7E338B73C19B448B4DF1A -:10D12000BBD4736784047356E8C6DFAFCE3BBA9DA9 -:10D13000C7CCF6C7C91B66C45F5FEF4339B1F8E7D8 -:10D1400035D55EDEEF2D32F8C7B5812D16B06B6B8D -:10D1500097ADB0482E289718DDA970F409C19C122C -:10D1600057044F71E58F8A9F81F3413CB7B1BE9957 -:10D17000C373C7C5DB19FDADDF3E686AA4E911952D -:10D180000F57C03E93AE3F77069B5F5FAF2317E01C -:10D19000EFD39FBFA0707CFA10C1B89D2DE3E93D8D -:10D1A00010B71BE6881AE7332D87FD8661755FACE3 -:10D1B0009096B702BC55A9C8E7EBB7AF403FFF96C2 -:10D1C0006AE6E70F0804CF01BD392F2104EF1D10D7 -:10D1D0009B3CF828CDBFF58724D2ED8FD0C71342F2 -:10D1E000781AD0476A5BE073B1E2D35206E3F3DF0B -:10D1F000BAD83E5E3CBC9C55E5A956AF86972CB18B -:10D20000EAAFAC36CA350DFE146BF83D12239E3ED4 -:10D210004A8FA1F1F5DD2F5439FD5A94BF547B3E5E -:10D22000B6DF3237433DA71BAAD884FA4AB14A7801 -:10D23000B65885C7A3AC467C7EB8948890BFD32AE5 -:10D240003D0DF0DD556B8E92C321EC67FD32A76179 -:10D250005E4FF4FE781ADC4BCA2F60F2F7FD2217FE -:10D260009E137F80340970FEAB8E28F3912F896462 -:10D2700001FA3EA7E24F83EF1C91136682BC683629 -:10D28000C7E4AFBB543A3A17A85C85E7DFDBCD783B -:10D290001EE1526DCA72887F2B018B1F8E375D6A2B -:10D2A0005F9970BF6E5D35BDA7D935E78395E3EA19 -:10D2B000AF5501E37AF5093DB8FFA75490A66394F2 -:10D2C000CE267FF9F2DE59347F36642A61E7DCD856 -:10D2D0007CCF86B2B473F1844FA3EBAE165D350DEF -:10D2E000637DE56FD8BCD6D58516C296D83D877AC2 -:10D2F000F6CDA2F9860CB7BAEF387F1EF0EBAF9AE5 -:10D30000C7B707A2E9E996271D867CD97922E07B79 -:10D3100014DB62EB87F7B29C6C5F87F7E7C23AAC2D -:10D32000DB1EBB9E3BDB85F5AEFED15C1FCBEF3E2B -:10D3300090C5D6637D3D17539E1FC84A60E50DB169 -:10D34000FB5F95E954E59D980BEBB23E0EBC2B328A -:10D3500013118EB73B56AF83FDFB2B51F655452677 -:10D360008343CA64E72BAFF6BED09106F4B09313A3 -:10D37000E11CD95B6EFF14A0BF0DED97D0CF4F57C6 -:10D38000EB3BD2034F66D0F4EEF3CF9D82FA0375E8 -:10D39000C4CF49F1F5C0E10C4D0F68F7A2357DD837 -:10D3A00063077D04FF0BFBAB1404252919D65D79B7 -:10D3B00008CFC5F43A44760FCA3F536F577F43A551 -:10D3C000E7AB476F6EBDEFA937DA4567C1FEF3449F -:10D3D000ECBFAB82B4B7948E7B95D25B2B9D0FF9DB -:10D3E000E0895BF5FA46E38778E3DEA81D78F5E887 -:10D3F000CDD98113CDF36719BE1BB203DFAF7E62B7 -:10D400005FA904F3ECB93596BCD5E4F22F55B918F1 -:10D410004D2F5AFA4B55CE5F098D0FD7670E19E184 -:10D4200059D7648447E38F2BA13607BCAB45479F90 -:10D4300006EBACD9A5A46AE60DBD17120FCE5FAB03 -:10D4400074F2AB66338F72EF2887F1E95F353F9155 -:10D45000182B6E153DFFAB264A0F401F4FF3287F58 -:10D460000AEB379C4C9322F4F87F543CFCA974A837 -:10D47000C9574D9F44B7FFAF4A779A3E9B88EE3C11 -:10D4800071E28F07326C88BF0DBC28C0FED1810CC1 -:10D4900089E589B8C80BF6EB6C76EE9D4AA85C78F6 -:10D4A00057E26AAF03EF8329DDD650215DC72BBD5C -:10D4B000B74DD1AFE3EC4CB61EEB1BDC3B61CBFAB6 -:10D4C0008AC9BF381DD6AF86BDEF71EE7CF2A2745B -:10D4D000DAFE892113BC9045D66DDB6086F9CDCC90 -:10D4E000647A64FDF657D1EEBB59BA5EDF64D4E7C7 -:10D4F0005FCE10553DC1ECF03BA95D00E708E3E1CC -:10D50000A13093E1E19EFAE3284FEFDDCEA13CBDCF -:10D510002593E1E35E3E847299B433FB99D8283EAB -:10D52000A85CBA0493007CFC35C7CE77F30141FFB9 -:10D53000FEC6FD7B562F043B309A3FBEA7E2E92B87 -:10D5400099EA3B84E9C13B33D13F0C70D0DF5B9F4C -:10D5500067F0AEDFBE05CF275FCC50ED6B953F2F58 -:10D56000C23ACD8CCC2F459DDF05C7C836D0179465 -:10D570006F4C78BEE47533C275F5ABDF6C827AE22E -:10D580005417DEF7423B96E6FB9627845A75F13A2C -:10D59000CDAEC9F7337EA8E565835DD890E933D871 -:10D5A000E9D1F6C6FFE80396F6A878FA4BE983C3FB -:10D5B000AA5DF0A7EA834754FE8FD60BA37CBC93E9 -:10D5C000F1F1A5F3FFBE10F2D17CFCADCC8FA69794 -:10D5D000A2F9F74AEFDD48D7CA1222161AFCA39C1B -:10D5E00010F8C1A3F41FF1933838DFF644EF4FA6CB -:10D5F000419CEBD2DED5EB628DFF4416B3B33626E9 -:10D600004A267C1FF2754667D17222BADD285FC4B4 -:10D61000892FD6D6CC41FFF05CCD6DB970EF2DDAF5 -:10D620003F18539F935357817FDCAAFAC7FBACF591 -:10D63000BD31E0F566317CE6178C9C027CBFDFC013 -:10D64000E17D62F8D3DBE9779FF7FF60581A0BEFB3 -:10D65000685EF34FB6B3F1A2C779575DB751FF4487 -:10D66000A1FE09C5F370AD3911CEB16AFEC9B0F2A1 -:10D67000E7F54FDE2423FF300BD6F9686CB81CEABF -:10D68000FCAF08C17D73281C579798FD0AF08B8961 -:10D69000B6D3F925D1EDFEA8CEE7CDED37298FCE53 -:10D6A0001BE3C9F1F86D14AE3F91DFFA84911CE0E1 -:10D6B000FB378F7C70F15198CF1107BE3F16DDCF3D -:10D6C000D7B2CCAA7FE0403ED0F4EF80D0B3F905CA -:10D6D000DAEECD3B32FD3B888E2F08E50BFAFDC21A -:10D6E0001F295FF851BE211FF7F53AEB63F9298333 -:10D6F000AA3F141DB7117BBFD1047EB14CFC167D2F -:10D70000DCE90D75DD7FA1CAA5A22CA63FEFAA5DBD -:10D710002140BCE8FED1781141E7429C9A7D04FC8F -:10D72000CBD7D47B02CAC68498F1DE992A5E278AB9 -:10D730001FACA933FAF577D51AE5C73BA1FC513DDB -:10D740005238CE7E9446BFF1C6BB51FDD117BAB94F -:10D75000FD8089E6F7D9AC1BD31FAB48D33C8C7353 -:10D76000D0F581B496344D7B81C2F3CEA19509608A -:10D7700047FD82906AB4E33FF8EC34BD5D1254F18A -:10D78000FC7EED67EF00727943689A164BFF44C741 -:10D79000697E118A7D2EE32E55AEBEA1DDA7B82B82 -:10D7A000763C7F8B3AEE1B75E3F34D74DCA67699DD -:10D7B00071DE4A16B387DEA86B7304995FCDC6FD90 -:10D7C0001B362EE82DBD5DAA64FD79F4E330C4EF6D -:10D7D000619CED84403CA54F50A6EACF5DA5643323 -:10D7E0003CE4178DBF0FA5EDA768F5A2EDAC9F67D0 -:10D7F0004A867BB3B5CB8C70B569F62D11310E72AC -:10D8000015F4A527A22FEFB4FA1F043A202E09CB56 -:10D810004FA878BFBBFEDF2C307F2A3F3BF01EDBDA -:10D82000599308F2B3EC7CC8A2C7CB851BF4AB2E8E -:10D83000A8F6C2447234BF6804E5DBFB2117DE8F13 -:10D8400078F30BBFB3C4EAB7F67A96E11CF1FA405D -:10D85000ECB88A98258C8B6731CB88BFF5D773F1EC -:10D860005C703CFBFF10C8AF99608F1EE9D0DBFFF6 -:10D870004F6549AAFDAFCA339ED9FDF1E2AF432AF5 -:10D880009D4D147FD5F4B3562F7AFDB5345A5F0EF3 -:10D89000ABFC1C5DEF52D68DD1DDA81D1387EEE2E7 -:10D8A0008DABF91F5ADC37BF98B68FB12F33661C8A -:10D8B000B55EF4386F46ADCF183F224EDC2E299B63 -:10D8C000E13718276E9794CDE2766709D38B4AC863 -:10D8D000897AECCAD17BF781B9F7C0E2CF9D06F512 -:10D8E000D6A8C66BEAEA5F3D057EAAE65744ECF18E -:10D8F000601BEC935DDDC1A1BD113D4EB45DDE0842 -:10D90000EF15822055E307456619E3D4E43176BE6E -:10D91000DFD3BC1AED4B2D3EDD27047624D0EFB7C4 -:10D920006CFFB76DA05F353FFE2D8BFF411667661C -:10D93000F6EE855E17DE73DD3AEAFFF931DE38CAAE -:10D94000FF6AFC71A2F518953771D6632279132FFF -:10D950002EA2A5A3FB2C8254F80A9C4BE512FDBD18 -:10D9600034AD11080F78A859CEA19F5923C84B3167 -:10D97000DEFCAAC90479DF72DF6E3807BFB2DA2293 -:10D98000DBA5C8FE4BE96B0D85AF807F41270C7E80 -:10D99000ECC02FA57F82FBC1AF2FB64BB03F727694 -:10D9A0009E34E8A1F9B3777022D83D558BEF374FFD -:10D9B00083F15671F80E8DB399A8E7B56F5D5E5986 -:10D9C00040C8370044DDBD8F1A6D9F4659BB0FEE2E -:10D9D000CD4E4D1D30B9284ABF7B78ED3E1B85AB3F -:10D9E000A335E085FB78F76597EC83FB786969F2EE -:10D9F000D0026A471DCC9EB11CF2037FA3F557BA33 -:10DA00000FEEDFBD680AFA385AFE83EC65CB79D891 -:10DA10008F98A48DBF1ECBEF5AF2E0B16DB4FFB763 -:10DA20000F6F590E67D7CBEAB4F11F595EC953FA8D -:10DA30009FABE51F4B84BCC74922FB4CB309B144E3 -:10DA4000EEF7E179F781D1FB7C2DCBE1FCF8EBE53A -:10DA50004D95708FB3ECCB1DFB8AA710326B59B973 -:10DA600028D3FCDC9C2F2F77C2FE31A1F448F3723F -:10DA7000CE57107E8FD9A4F61FDA2767033CCA540D -:10DA800028E79467F655BBE13EC2F06920CB879B3F -:10DA90007B6C69867B098A0CA68970A23C9C85E018 -:10DAA000A8FBDAD9E169ECBE9D9A2F62718AD1BCDC -:10DAB00097E50776C4BE7FF2610E935F038ED8E5CB -:10DAC0003D2ADF6BFBAF49E789FC6C0CFEFF3CC4D1 -:10DAD000FD6746F8E914C4433CF8E45C532BECC3FF -:10DAE000DA189CF1F671F7A9E314B426E13B45CBB3 -:10DAF0009A9CF8AECE243F9337948BF89520FFCDB7 -:10DB0000268433D5CCE17B26690E123C4ED3D41447 -:10DB1000F6BEC9328A6A787764E1A4C0513CDF9BC3 -:10DB20009E51D206E7EB5A7FCE831DA6B51F0BA7E9 -:10DB3000B805E04C35D7946C29D6E1AF98C14DD7E4 -:10DB40005D6D277F13DE7B19189A9A0F767565B67F -:10DB50006488CB940DD558E05CEAE51C554E48AC82 -:10DB60007D6A25932B235BD4F72A6CFE12435C5FFE -:10DB70009D7F65E7B22F41BD86210B817388DB8EC7 -:10DB800097E33BFDF1F8BF01CEBBEBF476031FC674 -:10DB900073E60D70DE7D06F4F75301CE37423FE0A9 -:10DBA0001FC0BD0EB09B52DB62AFB716576EB8EE0A -:10DBB00026CA0CFD7786AF48FF1E2C9F685E91FE3B -:10DBC0008CF7F8C6F6A7DEE7D3F0CEAB781762C3C2 -:10DBD000F9AA469714DF261D3DAD52E98B4A3F7CDA -:10DBE000D7F7C2F2E25EFD7B0584EC60E73A78BAD3 -:10DBF0008E604F0E39F07DE0329EC9C7B2A16451EC -:10DC0000E1C6D285B6AE03C94DF83ED1C80A2EE6AC -:10DC1000EF0F9CD7E052EDA7F4BAA079830E3E8DAA -:10DC2000FE23FD0F7D41E38F75C8B77B197C606FC4 -:10DC3000C03CFCE169FA73201AFCB753D981E7496B -:10DC4000DB54FCDFE10AF57211BC8DC57FD604EB15 -:10DC5000998BE5654327059867431C3EFD650E3BA0 -:10DC600027927E3E9C08E703966633FD35D03FC37E -:10DC70007E1BF0C53213E124366FB033CB34F94A42 -:10DC8000DEFB590595AFE9A3792A5F2558875179BD -:10DC90001BB6D922F57F9AF3DEF276AA3F3C567680 -:10DCA0001F8CDA8F36A2BB8768CD61F1DBD9C1D872 -:10DCB000FBD6C3390906B9F5547325799BCE6F6538 -:10DCC00036D3E7B387157C2749E3EB68B95498C38B -:10DCD000D6D197C3ECF18F5F2E7113C8A515AA5C3E -:10DCE00062E5C4136880F234937A2F4164EBBEF18D -:10DCF00047330A210EB7D56B96E09EC34ACE9FF3F9 -:10DD00002D3A4EAD4DEA489022F4514B6C920BF0F7 -:10DD10004D47807BAF35CBEC98873FB03BFEBD874E -:10DD200063F447A4A4DA71EC5A0D9EAD5E01C7DB23 -:10DD3000B8AB3029A887930F3C8BF13DA70AA72DDC -:10DD40004A5FF1C67C5A5AB8D164D695BB98FEEAB0 -:10DD5000F6CAE539605FAAE79BA2EDA27BB23983E0 -:10DD60001CD6ECA2DF79199F50FE45FF319DFA8F3A -:10DD700004EE7BF407F03C183C605488F775D9FB3F -:10DD8000C66F1D2773C14FD2FAB92BA7D8D06FDD4C -:10DD90006ABA489FA4CC69AB942FEBE4D919F57DFE -:10DDA0007A4A0F33815F57E710633B73201BEE9570 -:10DDB0009374AB1FE4CD29217018D757246E58DF18 -:10DDC00085E62D87912ECCC4DD86E7A48E60FBEA24 -:10DDD000BA9152B4533F308741EFFC3C3703E339EB -:10DDE000A94E46B7A7EC4DD88E275232CA1155EE30 -:10DDF000FD3C770ABE7FA1C9CFC87D16AD1F567EF8 -:10DE00008A5B910DEFC49E4A9D5CD2C619ED1DB090 -:10DE10007F22F6D2F3FB6EA7FC38ABBA3F4C61A66B -:10DE200052E5A5E58FD2FA5B7298FE3BE50B0CC07C -:10DE3000B8A7DC4404F8670F079F85FC62AF13DFC7 -:10DE400071D3D623CDC47E1F264DFDFD15E01348AA -:10DE5000C55CC66F8773D93ABEA3E6D31263FF9E33 -:10DE6000CC7FA8F57AE0FE1FADD75D1EFBDEE81E75 -:10DE7000958F1B6D3DD570955E77CF13EF2DF38495 -:10DE8000DA55B4CADE1CD60FD56788AFCACE3AFCC5 -:10DE90003DB1F78756E1BBAEA3BFF301EF54D17597 -:10DEA0000F9395FB01EFC22FCC787EB3C3C2E8522B -:10DEB000700745B88794E28CEDEF7E578527C5CC77 -:10DEC000DEEBD6EE2F58D4FBFCC7547B2CD15B8BFA -:10DED000721DDE58937CF02EDB08DECFD5D631FAEA -:10DEE0003CAE45BDC77FF3F643491CFBA1D4603F60 -:10DEF00068E346DB1117E13D6E5DBC7B9DF7DC42BC -:10DF0000A2ABFF6932DC01FD7D7A5B96212E11CF39 -:10DF1000FEF8912A6FC15E5062C22518BE5FA47ED2 -:10DF2000A0A21FFF0A1B3F32AE9328BA71F7E6C8C2 -:10DF30003FCEC1F8CD5C11DFB1B0133C0F5BA6BE84 -:10DF40005F47F513BE5748F55235C86FCD2F02BE57 -:10DF5000179380AFCBCFE6A4EAF4A4DA2E5A1EDDE5 -:10DF6000A1DA0177A8FA26E9BC66373A248E8BE855 -:10DF70009DB17A8B53EDE868F918AD178C7635A50D -:10DF80005B456F078CE11715AF374F1F93E2D0C782 -:10DF90002D7F11FBB26C6ED03C0DE4663547601FDF -:10DFA00064569551DF3B7299DFE1C8751ACEE1D610 -:10DFB000D419EB25423DE0AB5CE70DF9297A7DC42D -:10DFC0009941EEB1FE36ABF4E07BF7AC00EF372EB3 -:10DFD000C965F650499E9C9A4BD3237FA8EC83DFFA -:10DFE000A11869E549AF07DAC97DC31E98974D04AA -:10DFF0003FB57C6D55D1115A6EF9A905DF9D2427D7 -:10E0000062FBF7AE664EBE8FF273BE2AE71A3C6C17 -:10E010005E0D9EB05040E1C86C60F064F70F72BCBA -:10E020004EEE65D7B37AC5B91683FEF1439EC2772B -:10E030006BAE16BF0CB5C2EFA164D7CB3CE8BBCC2E -:10E040007E8EA8EF6EE27BA9997ED6BFCB1FE2EE53 -:10E050002D8ECCBBCBB4A218F445579AD30FFAE25D -:10E060007379C1329877C3857018D036EBC2100F20 -:10E0700076DFFE3C79167CD7E62799C54CD81F770A -:10E080005E60F0F544D13F21BBD575E965F0B9027A -:10E0900025004F5AA284EF10D1BF7CD0AB69C9AA2A -:10E0A000DE482341782F88D8683DB0831CB49EFE9B -:10E0B000DE260994C23E412875DA74D0730B1DFE2A -:10E0C0009336D0AFD37DD3E15DA1170EC78EA7D70E -:10E0D000AA7A87C27FA71EFE78FC31FADEBA5ACF31 -:10E0E00012C78FD6E8DE591DDB5EA59A00CBCBD7D1 -:10E0F0007AEE86F934B40BF81B5D1ADEF7E70536C5 -:10E10000E6A6C23A1DE1805F33FBCB91AE32159E8D -:10E11000805DD1EEC80DC13BB2EDC99F4A07FCC777 -:10E1200083BBA1D92CDFA7E7E77601D7E348D4F971 -:10E1300035CDCF782C97E9A3D37981AD30FEE613A6 -:10E1400007F09CE083472F09E3BDEB73A378E3EA74 -:10E1500099FFD2B086BD9751BE96473ADCD42EE0E7 -:10E16000BBEA0DCF1E0FE37EF17682FBA00DFDC74B -:10E170004FC33BAD590DF24CFDEF126435B077E360 -:10E18000D212467F1F5400BD9DD9BFA201E95A2477 -:10E1900022413A0AA2DD956D63F6A886DFD34238A4 -:10E1A00017E267A74DC4DF46CBAF59942289E6AF8B -:10E1B000F91C7E787FE1EF8FBF213D067886B81885 -:10E1C000BC7B9017FC12E0A3BB959D27EF5E48ED4A -:10E1D0001E5A6FA1936C85FCC2361701FEB8513CE4 -:10E1E000CC8AA28B59DB199FFC283751E55782EF67 -:10E1F000291DCF4D50EDA8601DDAAF741E9D731020 -:10E200002E9C87982B7F15E9564CC671331BC29CF8 -:10E21000FEFE899646E84A7E3637F566E0ECC77D15 -:10E22000C64DAA9C295F7B947B5B47072FE69A919A -:10E230006E329F3DC2817F48CB5B177AB03EC607E6 -:10E24000339F657ED3265A7EBF41AE6CC0F97439C8 -:10E2500098FD48E5CA4980EB94690BBEEF776A3AAE -:10E26000C17766EFB8103E8DE25985F794C0D6931A -:10E27000A77868A5F99FE54A38FE6921781FACFBAD -:10E28000E94C76BFBBCBB403DF3BD5F83E9A4F7F5A -:10E2900096CBFCC9CC3547398827789CCC9ED4E0F6 -:10E2A000D3EA95E4559C05FCCEAA1E423C34AEE16F -:10E2B000D97D0D159E8542A000FCB461B5BF93AB1E -:10E2C000BF6D3E44E16B2CE6909E9FFCBB57912EA8 -:10E2D0001B7B38F6BB413DAF0AAB74FED5C1EFBD29 -:10E2E0008A7A65E9008B1F340E1CE7EF7581BE3911 -:10E2F00089F4D948E9CF5E0AEBC6ECD86B96702E4C -:10E30000E8CB68FA745633B90831D742F60E1CEEE2 -:10E31000FF86D6DAD0EED7E4AFA8C209EF08827C38 -:10E32000FD8DCAEF5AFF117FD5EE07FAF6BD3BFD12 -:10E3300024BCEBD6E8E7FC701EF93F46F50993D7FD -:10E340005222FC7660A4FF68FCE5E631F91A438F9F -:10E350007C184B8F687AD6F77405BE97ACAD1FAFAB -:10E36000E27D54BFE7B1FB578979BC0A8FEC853851 -:10E37000B644F9B9BB14DEF50B144B809F54A71FAC -:10E38000E23B7FEF7E5DDAA0C3D76981F23BCD9F90 -:10E39000CE77203C942F92F274EBD750CC7E67EA74 -:10E3A000C9EFAE40BC36C0DA51BC3604EFBB0FF14A -:10E3B000EC25E231902F4126BF1AD6DCC5DE05D709 -:10E3C000F4DF731CE2BF4171E13BD74BFB57207D6B -:10E3D000128FDD5FC8A15CC375D6F84CCCD5F61D95 -:10E3E000D8BB43D4AF6F857889E6D727D605940488 -:10E3F000692C9FA6A87EFD4CD5AFB7CCB6FD59FDC4 -:10E40000FA4DCD3F41FFE721EF8F30D5F884FA8DEB -:10E41000067EBA2D8FD92D929A56E431BEDC54DA9D -:10E420008FF4BFE97213F28FAB9AC911D705A3FC21 -:10E43000D3E260D4836374E8EC5F04FB110BBFC2CA -:10E44000892007E2C1FD19AEE967705E851C67E7A8 -:10E4500028167CF0F344FD3BA435798CBEAFF599CA -:10E460004918F0CD3709E3D9BFF1FACB0957CDF9F7 -:10E4700027BA7EFFD29784E782AE3DBBF2F3905776 -:10E480008E26E139929C702DD2C535CF1C3FD081AC -:10E49000A78DE1E95A7F25D2CFBBE99209DE096B4E -:10E4A000ED7F623EFC5E74BD0AD7BBDF3537031ECD -:10E4B000767CED3BF3E15DC94D212E05EE9B5DEBD6 -:10E4C000FBCA1F41EFD51F7D18CF7DB57DF37FA11E -:10E4D000DD6D0A1D61DFFB9244A877F59903F30116 -:10E4E000BF6DFD6D58FEEE3347307FF26BDF311F9D -:10E4F0002A8DD0F1BBDF3DF2C3DF433E9088F77237 -:10E500001A824F3E0E79529BC8EE5D055F11F4BF33 -:10E51000DF75F0F820F2A146174BFB39F5DD30012D -:10E52000CF7968F4FB56457119F01DA550BF793EAF -:10E53000CD7727D4C78A23EE51E7DB00B408E3AEDA -:10E54000E142C0075D82D287F25CECCF0579EE2C08 -:10E550000E0BF02EE9EABAE3F3D9CF10B662F94A0E -:10E560001B3B2F368DF20BBC1F457B3BFA21C4F7BA -:10E57000BA1E5C07FD1D3613D19C118177B320A113 -:10E580007FB4B986F3530E231CD9762A15F6C79AA1 -:10E59000897AAE8BD5EBA2EEA52D19F510B1D3B4C7 -:10E5A0006C5BEC38E893792E953E19BF660EACC8CB -:10E5B00006F9413C567FA12FD25FCEF9A66E78DED8 -:10E5C0003FB37E6811CC6349D18619300F0FC4FB6D -:10E5D00040BF282EECBF11E293949FBEAACAC73455 -:10E5E0003180EF8CD8E4402AFC269B640DE0396E24 -:10E5F000697DC0D20A72861FC95D858AF09861FF65 -:10E60000F0A025983113FAEB52F5D351063F6D8FE8 -:10E61000FD4995B207DAD3FEB13F5B9DCCE36FBEF7 -:10E62000D9D83AFCEB0F6E3F668C9787C6F45FEA49 -:10E6300002FDA2ACC17593049CEFBB5015F1ADDC9B -:10E64000AA8F6347C77B409EC17EEFE9BCF2C1BC85 -:10E65000D448AAC581A2F1CC4BB49CF65321C998E9 -:10E6600092BE1BBB77A6C9EDCD7B54BDFBE22594C2 -:10E670003B9B833CD3BBC1CBA877FFA545266F53FB -:10E68000C3F2E0F39790BEEF3DC1F4EEE61325022E -:10E69000D0B3F61EF2E68A6BA87F153341BADE2CA2 -:10E6A000F49FF642FFDDC44D2D7BB279FEF02D20A4 -:10E6B000FF7EFDBC7D0DB43F653221BD9DEAFDC4EA -:10E6C00091364E0F1FF303B8FA10F2E366D52E28E9 -:10E6D0005F7BDF01F0C71AEBD9EF116C1E50F98B8D -:10E6E000FA6380DFCD275E45FAD1EC5EDFD3354893 -:10E6F0006F6E4A6FF8BB095543081FFDF317D2D45C -:10E700005DC5DEC55D52545206F47672F50F778210 -:10E71000DEDE5C4544E8FF608EFC3CBEFFFB3C87D0 -:10E72000EF511EB4F454C03DC9830B2511F8637337 -:10E73000B076543FE1F9EA60ED00F28F679D1FEC7F -:10E7400087EED620DAD5DD194EB40B0E3EDF8AFAFD -:10E7500073B3E4F0C3EF992C3DC16DC5F68A8B30DD -:10E76000F839B4F397866EC3735B1A3E96560DE77D -:10E770003279C1E0FEB565E8D330EF5F7FCF0A6F35 -:10E780007E8FD2DFFF05D640AE560080000000002D -:10E790001F8B080000000000000BDD7D0B7854D5B6 -:10E7A000B5F03A73CE3C1226939327E1E9C90308EA -:10E7B00098841308EF872704102BB583F2B2220E3A -:10E7C000C823424846C48AD77E37830331526F6FCD -:10E7D000AC2FEAA576A06AD12B106DAC51030DA821 -:10E7E00014ABB5D1528A16BDA3222F918CE083DEE3 -:10E7F000D2F2AFB5F639C9CC640262EDFFF9FFE998 -:10E800005737FBECF7DAEBBDD7DE9336D9BFF18E85 -:10E8100032802BD561BAAC03A42B6DBE3B3201D242 -:10E8200000F435986FB07B9D3A9647FE430A6DCE53 -:10E83000C5EFD3C0081501E4DF23192137408A262C -:10E840000164516A335307C008C0BF0691AA811200 -:10E850006F31C027B5067C3800F84FCB0658CEFF85 -:10E860000058B1A8D5A1617F554F89FE329D46E978 -:10E870002D989EA3BFCB305F013778B13C4B966E8D -:10E8800098C1A98D53ABDC4A8799F3C87D64E1BD7B -:10E890005370FEDFA9043D0987E85D88DF310F7EF4 -:10E8A000080DC0F9F7AEF4F6D5A83C73A92E633E67 -:10E8B0002B03BE4FE591350ED82C75ED7724AD6B4B -:10E8C00004D5F39649582FAB678A1EA4A1E4725B66 -:10E8D00012B52B95F4CD1AE5AF7E14084E59BD74D0 -:10E8E000EA072064C2C15B66C37A47B353F4F5F408 -:10E8F0003DF407E56A84C7244DB5CA4BA99DE601DE -:10E90000585FDAD96E4ABE97FB9BD233490FE23C7F -:10E91000A737044A204FC0C1EBEE8443684DF2DCB8 -:10E9200050143CC6131CB07D6830CC6D2C22F87B93 -:10E93000ABA89F6C9B9EB11E3715DC81926B526811 -:10E940009C20C36B00CD03D329B83E3FF59BEF5D00 -:10E95000C5F0C84AD113C163CF25021EBBE76C9333 -:10E960003760BDEA2229E4C4F9DDFFE28C525A6720 -:10E97000F54CB70E98AFF6290B695C08B8E031CCBE -:10E98000836FD1BD53305F5DE9D5D76BBCEE455485 -:10E99000DE3733495F8FE50F3E2F1994AF0EB84332 -:10E9A0004998BFB259E04375F3D3CA8D98F620BC9D -:10E9B0007353BB40C98CE2CEF900ACE1F9544F3A35 -:10E9C000D1FF656C1F9041972762DE111EA8E3FA04 -:10E9D000AB27860712BC4E3E9F3497DABF62B30561 -:10E9E000689C57365FBA292875EDE7A4DDDB44EB58 -:10E9F0003F89EB0F60F96F9FFF7388E8612DD28329 -:10EA00009C837BB4462BA7F2F55340A57DB1F66BF2 -:10EA10008F23504878B5272F99F183E6E945381FB1 -:10EA2000A77FF602B8F5126F8D8670AEB6B5D629FF -:10EA3000D46E4B06C018CCBF70F7409FBB2B9CB167 -:10EA40003DEF8B4B01C65F57A847281885572E17F7 -:10EA5000D2DA304E036E4C7BAC16F089EFE74ECD28 -:10EA6000CDFDAC7085F7E0CE41CDEA065736E29198 -:10EA70002F59E3EF49F680D107E7E3682E6FED8366 -:10EA8000E5D9E9F81FDAB7CD3D42B46FD9D9E07BBB -:10EA90002641BFAB4C3CB3F6A5211D182FB33DA2B8 -:10EAA000FECF4DBAF98949975BCC348A2E62F1DEEC -:10EAB000EDCB253E919D0CBEC604E359ED717E5C05 -:10EAC0006ECD0B5CD84F26B5D36C8CDF717417CA32 -:10EAD0002A1E4674372559DFED227A1A963B2C08F8 -:10EAE0009DE320247267A474C5035A07D10FAD8B30 -:10EAF000E8ACBB7A0DBB047F8AC7CB674C3AA9222E -:10EB00005CC7796F93901E13EEB3E8A7DE966B7B1C -:10EB100010E7FBA3FD32F3D9F87A56BAAB16A0750D -:10EB20001040DEC66B53BDC5DDD7DB66D6FB71ADCD -:10EB30008B53B7AEAD51B0FFA12D5AA90C349E3600 -:10EB400089C60BE078B4CF2913E15319E1E319DD4D -:10EB50005078672EE179E35C5AD750256C2B25BE9F -:10EB6000EBB5416BA1E0DFE7F0FF3DE72643ABAB40 -:10EB700033DFCB971E93EF53D93BA67E3F7F5E4C8E -:10EB8000F925AB87C494E70686C5E4F3EBC7C6D482 -:10EB90001FD03029263F68C37762EA0F0E5D1D93B0 -:10EBA000BF74CBF763EA17372E8C299FF48FFCDDF7 -:10EBB0003F253CA7F527E073561AD17279FF8636B8 -:10EBC000C7AE3F7574ECFA158800D1FBA4E4BFEA28 -:10EBD00089E8D94A5341F92C6CB5233EE0D26C0F39 -:10EBE000E23CCAFF2C87D627988785CF567E922293 -:10EBF000C78C6BF1890BE1579EEFFCF8F263C217EB -:10EC0000E779E6FD0F39215DAAB9820F28E0E5F525 -:10EC1000A74E9C7BDEF5DBE3D70F1AE3BD87D69FBB -:10EC200000EFE3D79F3A3A761FACF5E7F90637874E -:10EC3000B19FCFE74A2C5FF651D198AEFDBD1BB70F -:10EC4000CED9AB52599F01EF3509EB77CEE34E9EFB -:10EC5000C7F54EF02782C374130E95B982DE2F4498 -:10EC60009FEF9BF3F81FA24F4CDD6B73991E619FC2 -:10EC70001C1A805D2DAC9776F544BC48F7B9592F26 -:10EC80005BA8B44269949CBFDFA4EF074DFADE5045 -:10EC9000AB723F0FD7E670BAB156E3EF8FD416725E -:10ECA0001AAAD5F9FBE6DAD19C3E8AFA18A58FD7C5 -:10ECB0004EE3744BAD97EB3D593B97D3A76A7DFC70 -:10ECC000DDDA9FEBCDFD016F06CBB3F8F5CC5F9598 -:10ECD000182F412EE2F6F391CEE4F3F0B52EEDE5D8 -:10ECE00079A9E7C3A3D50773B7BF1C8507D7E5A6E6 -:10ECF000641EEE81FF1805A3CEC9176EFF65ADB681 -:10ED0000FD65FB85E9C2C21738FBE18044F5AEA77B -:10ED100031C722BFC9DDDC1070770F9F4E3C8AC31C -:10ED2000572FE22B7E2D21D9DE8BCAC3BDA3C7F995 -:10ED300093B9CF567EE64C81AFF1FDDE6FE2DF2C5A -:10ED4000C24F2C9F1D47AFA77385FC3C9D2BF4F44D -:10ED5000FDDDF08B7B726DA6FC14FB3E6B9FE04BE0 -:10ED600077F6983FC197605C294F8BA1CFD9336369 -:10ED7000F771BF5DF0B7FD7F92436B12ECFF85DA50 -:10ED80005BEB896FF72773BD9FFE7F466FFBAF4D2F -:10ED9000617D7EBFDDD72F2B6A7FF65FDB636EA2BE -:10EDA0007DFFDF5CBBD8AF421548BE433A18A407CD -:10EDB000E192020ED2E5A0403D4C7482C610D145CE -:10EDC000F778A9C0618B9E64826712EBE39FCF4CFA -:10EDD000E1FD079F6A4054FFA0A8AC976EFB2EEAA6 -:10EDE0000A349E82E3A11E0ABAAD73FFF2E8BFC9DE -:10EDF0009DFC5AEE9EDE2E8407161F994D7CE43C46 -:10EE0000F2BA6BBB8BE32387888F5CFACDF3118B4F -:10EE10008EE1EC8D03BC295DCB67111FE90DF0D3AA -:10EE2000DCB7998F7C6D3859746BEA13F1FCA4DB65 -:10EE300076CD9917907F263F57FCF561C48BDBE4B4 -:10EE40009486F5D8E42EC5FF73CA07020A3C86A94A -:10EE500073F5E9DE878673B7850AD71BC2F69D5323 -:10EE6000F1FF32CCF6A053A57A0FF5F8F7ED945FD9 -:10EE70008D1CD389E99749FD4380B640699EE03FE8 -:10EE8000B2EB4CEF4351F3B3ABD0273A5FDAEAEA87 -:10EE900073286ADF86EF5563F223DA7262EA8F3AEB -:10EEA000A0C5948F0917C6948F3BAAC7E427444690 -:10EEB000C7D4BFEC8C11932F872B62EA57B866C476 -:10EEC000E4A7A8D7C6D4BF3C67414CF915DA4DB1C9 -:10EED000FD157887E7E1BA173ADCF5522ADA69B905 -:10EEE0004619E59393ABFD0BC84E5AE3516122D509 -:10EEF0000E85086E750E97BA1EF9D40792D11F10B1 -:10EF00004FEFB3A1D59D8FF5E530507AD0A697523B -:10EF10009A676CF1119D6E2F4CD6681F920702B450 -:10EF2000919C52F424407EE2E811F95D01EDCB6F33 -:10EF30006CF01826DB5554F4A97E736688ECDFACC0 -:10EF400064DF15348FF5B606CF1ADA671B781FCB4E -:10EF500064BCFAC968CC1F7E41B1119E6D6FB1DDF2 -:10EF60003316F39F61F7329637B59DF8C995981F10 -:10EF7000DA66D7A9F65090D94E5CAEC03D4A7AF712 -:10EF800078F6F10F843D15FFFD677982DF6755083C -:10EF90003B33BEFC8E3C21DF3E76242E5F6EB6AF47 -:10EFA000B86BFA43C4D7EC6D7620BFC5AA2CA32753 -:10EFB0009C4F5F3D930FA1E15179C50BAA9BBE0FFA -:10EFC000E4EF1577CD83B05BF4437EAC5549464FF3 -:10EFD000F23B7C3C29F13C6E31E7613FD3A39B7E41 -:10EFE0003DFCFDE3BCF3AFD37E2609421989DABBB1 -:10EFF000F97B563071FB7BCCF13F4E4F5C5EDFD12D -:10F000007F2F086444B7137CA7739CBE5C6E3F934C -:10F01000068184EBC8E4EF9063E410DEEC423A270B -:10F020007E519E96ED0024F1F91079C540F8CF206D -:10F030009300F1145C7A29F12950EC91B04517281E -:10F040003F1680F201D90B3644C67338B51B56DB28 -:10F050003F0847D1D10C23360F543F4ADE7C427D16 -:10F06000E37A928714A612BE9F022D554D805F56FB -:10F070003ACF257B95A8F51CEC464F6A33E178B072 -:10F080005762383E6FF2B191F320A1BED696E711D8 -:10F090007659A1DEF37C7283E0EBCB88EE377E1FDE -:10F0A00032B9FCABC219F182E57AE4BBEE10FB2960 -:10F0B000BF71785BF8DD27062F3EC98F9F777F2EC3 -:10F0C0002FE8EB7D2B8FE58A3690E4629349BF4DA4 -:10F0D0008AD163989BF8185426827F9F7C534F8D6A -:10F0E0005B771318390BC8AFA1D875E267C932F83E -:10F0F0009F4E00FFF875A79AF3C6F6735BA93D789B -:10F1000074C1E7C0EBCA463D9FFE854B280FBC6922 -:10F11000A7FEE7F93DFA7A54813ECF13FAF40208CC -:10F12000DB890F77819F3BD34E7EDB78387A419B1A -:10F130002FE55F189EE905C6E7041F9B4BCDDE8ACD -:10F14000EB9C1FF000F9696E98079E629C8FEFBBE5 -:10F15000E96F185877E155434AD6527AE9F83A9957 -:10F160005B4F66BD4F0AF491CF5DFAD5F5BE3A8F7D -:10F17000AF90E8E390A42D61384808079237BD8F1F -:10F180000F5C1005C715FDCA7F9F9F45E7036064AC -:10F1900090BF788793FD56B001580FADD9397813D9 -:10F1A000C9852FF27DAF51BD51934DFFAD11197837 -:10F1B00075CAC5C30BFFEC44271782976CD2FB417D -:10F1C0004F62BC19972FF6EBABD24B66BE8043045F -:10F1D000E1B0B9EC9BA717845F0CFF782D5FF05F5F -:10F1E0002BB5E0366A5AAC7FF735731DAFE57B3837 -:10F1F000FD22DFCB706EEFF7E9E12492FF0E5C7F1A -:10F2000002BCF7764337DDADBF3B7AF9A6F8F2C111 -:10F21000E4C4F35CFC2D99E71B344FE2F32589E746 -:10F22000F96F17894FB83F4B5CF9DFFC3CBFC8371B -:10F23000DEC8A779A6279EE74F2F129EC8EC96B48A -:10F2400062BDD9C807A9DE373D5F082C984272E835 -:10F250001A9FF0FF1723C7253E845379F4DC70D240 -:10F260006FF5751B88EFACF4E80195F9C81BF982BE -:10F270000F8281F399394D627F52FB884F97288422 -:10F28000EFD9D09A46FC6AA793FDD9F1EB0F99EB21 -:10F29000473A799CE004D32303899F1C1C98984F1C -:10F2A0003C1E5FBF3EC2F2697D7962FD749B49AF2F -:10F2B0002B5C0DD3B26DD1E72BB84099B86CC0E888 -:10F2C00043F2B64C5D4BFCC4817289E0EAE833A49A -:10F2D00027ED07E6BD12F981735E3F207918DE271E -:10F2E0003AE097D739CEF1DABD6A81BD7B7EBE5C4C -:10F2F0007E66A43FC17AB66ABE5DF95176E3F22D0F -:10F30000AFAA05D1FE7108DB800547C4E6E5F341ED -:10F31000D36FD0132ECA6F509C29E865453F2FCB81 -:10F3200007921B643FD7BD30A6943617F50F20FB1C -:10F33000209292CCF222D87B6CA11605CF0FF32D30 -:10F34000FD53EE46AF74C47C7FB7D685266567FE55 -:10F35000FAA3FBA6903E3F1FC2EBA8FEFC553DE87A -:10F3600008B2639D1DFD9D9162F4DBCEFE15FE5E2D -:10F37000EE72B7CA433175FF2EE17E6CD58CA304C3 -:10F38000CFB5FD8C63B4CE78F805EE1A9FC67E0427 -:10F3900082DF655DF7BDBB7DFEAB669CA6FE5EE8C9 -:10F3A000A75A7E1D9DCFE392ADF361453DECEA8403 -:10F3B000F757DD9764D3BF88FAC4399AB701557EF1 -:10F3C0009ACF3C8BBEE3F41C2814FE803A4FDBBA84 -:10F3D0005D517478832D9225E476781D3999FE6706 -:10F3E0004712F38FF61DBFEDE7E3F3344BEFE8214F -:10F3F0009FEBF1D5E767F917ECC989F569EB1C6359 -:10F40000B7BDA880F5123AE71D8D79495B44F6AA8D -:10F41000A2821EC4F5955F8ED884FD4D92FBB68402 -:10F42000711D9FC3D9E40998FE2788F5AF7AF3A32D -:10F4300074F2634E52ECC7A3F953BC1F684041AC51 -:10F440003FF914CC4B6D25B88C4F67B86C6F99940D -:10F450004AFD943C3FB927A5BB6AEB55C5DEE90FD1 -:10F460008A9F7F793776E9B002A177BE9E6C0C2B1C -:10F47000C0B4BC9BF58F32EB85938D5105599DFD32 -:10F4800051FD44F1106D832C3FAE80EB358105AC0E -:10F490006FD95CC857897FA2FE2AABE4272CB03312 -:10F4A000BD1BA0A9D9EC3714FB8F7C5DC1FC0433D4 -:10F4B0002FD5BF1DA4761B6FF1F03938F83420F931 -:10F4C0008080E173813AC9CF7E0717C57D60BA5E3F -:10F4D000D237902E26DB2219822E4222AE017C0AE0 -:10F4E000E57F2B85831427B0D6F5EF3F273FB81172 -:10F4F00054206922E615603F63E0600A9FCBF1CC9F -:10F50000701E4E6B5E663EC5CCB7CF9A3A6D00A6B4 -:10F51000B7253FE2213C0D4BC847B19F2F93FFBD5C -:10F5200095E9C69FACDB7B937FE93DCE4B2B937572 -:10F530002987FC4F9E42D2535743B2EEC4710C77D9 -:10F540007180C67568C0FEF86468E475B8DD9F0414 -:10F5500008282AA812DB4FC9BE65056CAF009F932F -:10F560001F7E2F6533AD3F493DD57A077ECA0083A4 -:10F57000EB65C4C9C72CF72A89E337BC4A9C5CF405 -:10F580004904FF9E73E3BFC7CA4B171C54899F48A9 -:10F59000ADDE9C73C89FDA086E659D706B53845D09 -:10F5A00067C12D30C9FF4B826BE04EA71ACCECDE51 -:10F5B000DF86001A45FA789BBA642BD547C3096CDD -:10F5C000D45F8E585FA0D229F641F16DA5F6EFD831 -:10F5D0007354B27B2C3C7B68A0C9AFBBF1773C5025 -:10F5E00020F4A3EAF4C3D524E70007B5F50738995A -:10F5F000727424F10D9497F5242F93EC06C3DB92DB -:10F600009B2B9AD600D15575F30220BEF28EE41BD7 -:10F61000F032DB23C076D99C6981576C1AF9B26647 -:10F62000AE7363FA49411EE3D7FE57A6BEC26C48CB -:10F63000761753BBD2CBBC53B270DC6031E8776233 -:10F64000BD60926FEBB3B4AE3765FD318DE2212A18 -:10F65000E0C3E12632E1F74DB333D86F9A5911A9CF -:10F66000A37881C8DDA0527C4F17FA388BEB1B09B9 -:10F67000F00B1E0BFB59A4B612FEF4427C93D4CEC1 -:10F68000F247A93C5FE42FC37C8DD852C86F29FF95 -:10F69000DE0882479B0C141655D322D968FCFC99CE -:10F6A000C359AF29A0F2CCE8F2B4E54F61BE60EED9 -:10F6B000049DC849B3F97E762B95BF01BC0E30F985 -:10F6C000F7A838FA1DD749375C5EDA91F757D07C36 -:10F6D0005FB919D88EAD31E56D0CBDD162B1CC18D2 -:10F6E00049F8D7D10F503F15667E9CA2723F7DFD31 -:10F6F00060F205EFC607F89CC0A6937FB24E6A6021 -:10F70000F840C0CFFA1EC5CD10BDF49FB76BB79DB2 -:10F7100006CB1474A7EF157457065E99E03552BDF9 -:10F720003B48E3CF9997CB7C66CC5160B830E5611C -:10F730007E429AC4FB943F209FF165BC4BAF97116A -:10F740008F64B9343F09C79B3B4FE2F38959735D1E -:10F750002109FF390BE983E3A1145FEE6CC4F7398B -:10F760003E499CFB627E5E943F1EB5613E379BED39 -:10F7700004FFD309F0397F80C077AB7DCD5A478C29 -:10F780007FE792016EE1E71830F59302E6BF22AE03 -:10F79000252BD91B117CA381F9D4611BEADFA4FFBF -:10F7A00082C1FAF63526BD5BFC6296710BDBC1B3F4 -:10F7B000BCB17AF43BB4274407D74AACE7CE997B77 -:10F7C0007E3DFB5C8164C6DDF455599E99DF35D0E2 -:10F7D000D89EBE9AF49C12FC380DF59028FD7EDE72 -:10F7E0006D67D3B87ECFC7579CBB0451A152F09729 -:10F7F0001A8427F1CBF26B15A697EAB50E8EFFAAF5 -:10F80000695E63CF267CFE21E8025FDFAFEB83F306 -:10F81000EC53658C90B528BF4D554822BACE269E34 -:10F82000C3F08F38C82F37DBA157D1BA66A7831A28 -:10F830004843BCBCF68A8DD4FF5A17A832CADBDE17 -:10F840002D6F8608AF9095EB849388391CD7D657D7 -:10F85000EDC1E70BF5B6611CB755EF49D1A3E3A4A1 -:10F86000D6AFE9C43B8AD7D29C304C35F737919D4F -:10F87000346480E0570F4AC0F22270AD8BE19C9552 -:10F880002FE295B2527547308DF88D66D5E338BBBF -:10F8900007EDBE5EC3310DA15A29F647B48BA7FB15 -:10F8A000AC0CB39F1E9A1444629CD9525A6623B87A -:10F8B000B953748A4FB4FAAD4836ECC4B72A8648B7 -:10F8C00023820CCF4DCA22D24F9362F9BEDD2EF6B1 -:10F8D00005DE157C3F5E0EA21C60BE4F7EFB6019EC -:10F8E000CBAF8A01592C0FB89FD58A4B75EAD0450A -:10F8F0009E657A2185FC5CC31064A4AFB7E5786788 -:10F9000050FC5EE07585FD6A6573F5EB1647EDEB1F -:10F91000E60E391099CFF1503FD4FB503CD4DAF2C7 -:10F92000CE3CC53D56428383F0BD324E3E2E73BF62 -:10F93000CC7AE4B247ED9DF80B1427AAE713FFA891 -:10F940007AAA8B3F88F954273F8BB32F417D89D604 -:10F950003302F931F121A3204566FF32CC13721432 -:10F960001E97C82F267B56D793DC6B97521AE4B2AA -:10F970004E3E39C2DCAFBB14EF4B141F1B407DE978 -:10F980003115BACA01F0B3FE3211E526E9D152CBE6 -:10F990001C99C6DDB814FBA6F37C255C41F9DB9607 -:10F9A0008A735208DCCCE760E3024E95E8FFCBE4B3 -:10F9B000FE6BCD71FD7664D6C7D41F727F80FB428B -:10F9C0007A8B44FC10CB7B4FC3A64807E35A8E705A -:10F9D0007F1B33045DC4EB312FDBDC219B8DF86E84 -:10F9E00080E54E128472087E4681E0B36507049F6D -:10F9F0007D2E801AB44CAAACFF9AE9B9AC0772F913 -:10FA0000D80870FCCC0EF0559BFACE5D034650B47E -:10FA1000A85FF071535FB0F4B82971FB78B9FB7E31 -:10FA200085F8D6E5395DF64BA6FEA781C4FAE21546 -:10FA3000DAF9F99661F12588E54BB97096F70FEE82 -:10FA4000DE732BF90982717A50F022F5A05EB9BEFF -:10FA50005FD0FAE2F5A1EEE2299F1A7071F194A845 -:10FA600041CC27F935D6B2B3E2F0A77ACFF1F9F756 -:10FA70004027DE75E07360D375B40E94E72AD97D14 -:10FA8000D26F1E62BA5E8BF5E4F104CD83C1FFC272 -:10FA90007CAB0DFC14AF003EF534E1A92577911342 -:10FAA000319ED42D1678374A11F9BEA8C8125E06C9 -:10FAB00047C7EBEBBE5CF2471B65C51C1F6BC9E378 -:10FAC000E13683F16404E81954CFC2939161518EF9 -:10FAD000F8F11AF19371D3105FF228CE76541FD249 -:10FAE000BBCA4163FC288F936B15EE990AD17985C7 -:10FAF0002B7EFF0D3E779C6CE2C714F5EBE1C7252A -:10FB0000841F96DC423DF9AE38FBE2AE38FBE22BB7 -:10FB1000E0C7918BC18FC845E247BBFD87EF05CA9F -:10FB2000D89EF5CBFDBBE287D472DB927B88DE8367 -:10FB30002940FBFE74925AE1C679D6548AB8F3E1A3 -:10FB4000BF2F08523E7B452EEB854FA7E92F71B999 -:10FB50005F9497B519720AE6F3576139E69FCEF5BF -:10FB60005650BE66359663FD11FB7C41CA17FC50AA -:10FB70009497DEE97F2985E47C40B47FE1589DECD1 -:10FB8000C1F2509DD9BEBCA182F235F5A2FDC803D9 -:10FB9000A120E507DF23C6B7F4CECB4CFEF9B47441 -:10FBA000EAA5DBA93FE49F9B917F8E3B61946EC3E6 -:10FBB000FC22D56623BC5D1C09D8091F0EDBAA46B2 -:10FBC00012FEC0425F0EE19993EC56B9937FD9C8FB -:10FBD000A983ED262A76D6FB5E95FC0AD59B4624A2 -:10FBE000417276B4EE22FE4EF1C89B51DE1499F2BA -:10FBF000C88ADFA57B0433A2F6AB68A090F356BD9C -:10FC0000EC748117F0B0C00B2BBEB8F52190C8DFA3 -:10FC1000426B633F449778633FCBEF50BFE2618410 -:10FC2000B797539C31965F3E56C419979E3B3D351E -:10FC3000915D347CA0B0E78F9AF722ACEF95A15C80 -:10FC40001BD1CFD3843CBD099EDA1F495F7A9AC687 -:10FC50001ACB200DC068DA47912F7FBCEF7DF57D70 -:10FC60000196DAFC0AE111F497749AFF556DFEC90A -:10FC7000BC9E2A80EFF54AB00E53DE2F093A368B30 -:10FC80003811C17F6699FB764C9DF7CAED6C3F7BBE -:10FC9000743B8E3369FC00A6FB9973258BEEBF3352 -:10FCA00090F4603AC1607FB68FE3DD6F8290830687 -:10FCB000B9298EEE97BB3F7B8FE4D2F22DB174BD94 -:10FCC000025A1DC2DF1C79E46DECBF72438A4AF20E -:10FCD0006745636CBDCA0DBF3F209574E50395165B -:10FCE0001F08C5F2015438041F7868089F7FADCC07 -:10FCF00091B54319E4FFF0B3BC4F0221EFEF52F48A -:10FD000030D35F8B53D851A67E7E9B2CF4F32470A6 -:10FD100069EE42E2C336335E55E4ADF1212ECEE505 -:10FD200054C3CDCC6FAC78180420CBFB5381CBD51A -:10FD3000683F5B079F8FA3F7D2969EAD74DFC0F23A -:10FD4000B3A07EC0F6152C424E378EF910EF9BB44F -:10FD50000CFF3F86D6E5E0753DD4A33FF3F7D548C9 -:10FD600010CE52B28B95E256EA7388A02717D111B4 -:10FD7000F1F769B1F65612083D7E789BF0E38CE806 -:10FD800094FB75B4BF4ED05D42EE3700D157B7F645 -:10FD90008A7B55427B852514F63F7B9AE0EB17B2B0 -:10FDA00057BAB3473AF63309F5364C67FA92B6D3E9 -:10FDB000BA2F3B9B9A92289E6A66B9EC25BB6CA62B -:10FDC000DDC84A4FA0E73F60EAD91DF57D6EEE4FD2 -:10FDD000F1656CA7F825ECB795F87FDBEB8E8471A5 -:10FDE000C98AD9BF6237D444FD5F454EA9287FBB7D -:10FDF000E2CBE67EBF017DE579DA977879E4D81D1C -:10FE0000774E098181D171054F0F12FC6E4281F14D -:10FE10009B81744E94D49FF99D568AF6541FCE73DD -:10FE20007F076FBE9CE3243E03E38271126BA3FC49 -:10FE3000E707D3129F8BBC61F2D7148A7DC3F47697 -:10FE4000CDF8038D7FD421CE5D8E269BA9479C5B88 -:10FE5000BDD3515FF0C788C5276DA2FC687AEC79E5 -:10FE60008D55EF94D9EE50ADCBBB36CAFFAA3DE419 -:10FE7000F4939CCECA37EF71AC02B69FDB9F4FDB89 -:10FE800014BDAF670796A70CA2F8A27CC3D18BE084 -:10FE9000F8BC907FD54AD841FBFBF025BEA334EFD8 -:10FEA0006A0D8C67A81F2DECB8A698EC06111FD21E -:10FEB0006E1776607B9248AD799D1D382365109D45 -:10FEC000CBDE1C66BED8919F1166BE7776A097C721 -:10FED0006D9F65959BF9FF10790D549DE65BEE32A1 -:10FEE000ED8742752DFB5D51EF23BF4DFCF901C03D -:10FEF00078A11F9BF19E46DFBFF3395E777E7E9B24 -:10FF0000ABED95FFC2EFF34D7FB0AFF9D357EED015 -:10FF1000187F0ED3B80B4249C071DFFFA45FBFBD8D -:10FF20005F1BAF677D79A4FFC3651C2FC07EB5152D -:10FF30002DBF65BEBEC2A2FBA658BAEF65C2F14294 -:10FF4000E76AF1E72DDF009D0D1C9440EFFB35C9FA -:10FF50006BC4AF29F274E66BA79A24F68768D05673 -:10FF600047705E29897D59F9EA8D150ECA2F0695CD -:10FF7000F97C533C3FF305494F585E0F2CEF4A2163 -:10FF80003F95E05DB357261F02DFB7D1A2F824DD0D -:10FF9000B7D1A2EC62BA6F139DA7FB36D1F5E9BECB -:10FFA0004D7439DDB7892EA7FB36D179BA6F135D51 -:10FFB0009FEEDB44E7E9BE4D747DBA6F139DA7FB4E -:10FFC00036D1F58F80FFC1F112C175E206826BD385 -:10FFD0001AA74A70C5ED7AAB289BC519E31FDDCB84 -:10FFE00089EE67B967AA6305C2614F8E0CD268BA01 -:10FFF00077B32CA6DFE57215FB0950ED6039E2C737 -:020000021000EC -:10000000FF313CE522B6933F6F962003F175E986F8 -:1000100038FDA1E5DE3AD2B76F0AC57E5F0E517E8C -:10002000F7DCAEE7404B0699F1C0BDA137E1F31410 -:10003000D9ADD33E9FDA27EB4E305D00B4CF5B8560 -:100040003FB214063D349EF7D10E218D8E4744F900 -:10005000A98D722890DB793E746AEFAF0EFBB0DE9B -:10006000D25EB24A74E7CC89DDEF242D76BF7B14D3 -:10007000C6EE778A1EBBDFA9A363F73B1ECE694697 -:10008000ECFE833C9DE1BCBC0F9A77387EC6B45829 -:100090007CB0E03B1AFF27F05563F82E41F83E2C68 -:1000A000D1B9DA3D7BFA685DE15CDD7CAF83F4D7E2 -:1000B0008B85F37D7170FE1CC657B819B830D335E7 -:1000C000B2535F2ADBEBE72081636ADF0AF35EAF9E -:1000D00038DF31E18AFA0BDB0B51E750F5B2CCFA8D -:1000E000CC26A267233385F980BEA107EFD73097CE -:1000F000E86F31F8983F2D8ED36B96BAEF77905E0C -:1001000013BF4E9A0DF95D2A5B845E13BFDE2EFE8F -:10011000A842B5B58FE0DB8D0FEBB4CC168B4FFB4F -:10012000C88F91096D0ED263BAE38333728C5F93EB -:10013000DC402E06040F610AF05F427DB2A6A35890 -:10014000F8E79D7EE1E787401ACF6314887970A3B2 -:10015000287FFF2825C47E073429D8BF64D963F1DE -:10016000F084BED2DAB7B05FF92530E1A8CB92AD0A -:10017000D37F8F56A041FAF5C8CF84FE34DAD51864 -:1001800054B4AEF6F927F9E639B762C67F5EE01CD3 -:1001900092E64F7E8E6BCCF8BB092DA35EA17CC787 -:1001A000B9E4CE57FBD07E8DDFF9FB0C4ADF92B469 -:1001B000C7EEC0F1AF96045EC4DB95C11DE334DA2F -:1001C000FFCB242FFB2BA682BFAFB047423CAF89A9 -:1001D0002E1FEBB5369761E7F328D37F09109E4AAF -:1001E0007AFA32DDC1F358AB7E3095FC31CBC1F4E5 -:1001F000C734C7EE5F177B28CE0EAAC2FDA77EE3E9 -:10020000ED9E047814170F102BEF17145AF7CA45F8 -:10021000BC8A06E2FE77A5E947AA746DF4887338B4 -:1002200094737DA18BDDA410E0C7F07985BD90EDBE -:1002300062B407F8BC5F73248AD7033593CFD56FB8 -:1002400074CF64BE7C637D17BF0EE3F5E2860BAC12 -:10025000CBD413C6D3379CFFE1419A90FBC9D3F7A7 -:100260001A545CD6D63F5A9FAD7188FBB9E0CF884F -:10027000B9B730B8509C7B97997A53A5CB8453611A -:10028000A08EF4E30EBDA98BBDF8F5EEC958F12E92 -:1002900008AFA242C6E306CF9ACCCEF31D6B1D9FDA -:1002A0008C687BBC15E125A74C76117F5CD1CF37DC -:1002B0008CEAF73B103E4C74036E8DF5F593CDC779 -:1002C000F6CB799DEB423C7B701CADA35956C5BD66 -:1002D000F940DD38ECB7BD54E05DF7F6AF8027CECE -:1002E000EBB2C2ACAEF3B2E2ECA7C845A9E128BDBF -:1002F0003DC3845FFB10EF146A57F6C7BE1E9AAF6A -:100300003DAF714F6FD28B6F157A31EE2BFB41648D -:100310003B48A4974E91CFDE42F95339A092FD9904 -:10032000D923207B48CF5B00EC2702DDAF13AAC89E -:10033000FD8AD84ECEBE15ED27ECF7DD5537A6D198 -:10034000FDFEEC944569F96E8A6FC2A90EC0BC64CB -:10035000F38AFBD9CFBCF76F65543E8FFDD2D73BF4 -:10036000C53973EE0FFEB69CE900B474E7181ACFD6 -:10037000C7EF0B44D2649E5FF9B59F0D27FDAAF726 -:1003800059F730D2CF7AD1392F8274A8491F9755A7 -:100390004486FBDD9D70CACC4F6CBF649BF03898DF -:1003A0007C72369D8758F7301EEAF1069F879F348E -:1003B000CF4FF28C69A984E707075AE75AAD59E491 -:1003C000B2AA4E3252E7D03CDF94F97EC567AA91BB -:1003D0009A86E527C1CBFA63A0CDCEE744ABEEAE5B -:1003E000E899EEEE3E6E7F4DA1B06FAAE2E2A2AABE -:1003F0009456079D6755FD9371514D6871273A0FCB -:10040000B3D65F9DA68032145309BCE7ABF7E23F39 -:10041000E48470DC629677777FE3E7E6FAACFB1959 -:10042000D5743F033FAD7ABEBC279CC70EAD3E33AB -:100430002EE61E04D96BB4BEEA3313F97BC55D27E3 -:100440001C84DFD40F3D8560DDCFE80ECED985C298 -:10045000DEA8A67B0D19D1DF051D77F69FC9E54FF4 -:100460009A707B72AF6DDAE604F37CBD50D8DD4341 -:10047000B214F6175CDA0AC6A604E35AF5ACF70D17 -:10048000BA9B57D3A4F07C9A37C505271A6FA709E2 -:10049000476BBE4DE9E1255E71CE3A90DE2FE8C88C -:1004A000AB91FE5747F1D3B3A67FA0E93BE1FEFC39 -:1004B0005EC615C28EED6E9FE7F4F3A5137F18A9F3 -:1004C000B4DEFA4A269B5D407EB49EF35A6D242723 -:1004D0003BF84F37FBDD096739E61E4C57383BB810 -:1004E000BCE3FE19181E299BE410B03EF0D01F4B50 -:1004F0001C0E1CFF980D22C477A6C87DA7BE4079AC -:10050000B41F882E8FB1ECC07483CCF7998E3D9ABE -:10051000EF20BB6C49394464E45BC7DEEA5F477196 -:1005200097DA02D424C7A1BAB336F6FCB1128C3DD7 -:1005300029D8EEC603DED456CC2FBA27568E1D7BA3 -:10054000EBC70EB207A4856E3FC515E13CA7BE8080 -:10055000F9C5CD0EBE9FB5E4FEF8FE62F5E06C5322 -:10056000DEC6EBC39F179AFAF048184972E685DA9F -:1005700066F17E8E791F11F53F23119E587A7028FF -:1005800079D2DF99EF43A34C7C699C92B8FE92220A -:10059000B10F2B1F3BEDF068DDD3D971E42705388F -:1005A000FE895A95D3ACC1866B30F63F60B02F659B -:1005B00030B697B548FF4FD8CF29CE4111DF385F0D -:1005C00043F7D448DECE157A8253BEB992F5D13EB8 -:1005D000A006597FF1FBD99F6E43FD248DE2376E53 -:1005E000913DEC6F10EF078DF968511AAD37F3BFED -:1005F000E73C4D70A53B0E40EFB0941BA5C4DFD780 -:10060000CF70F379FF265B80FBA140ADBB109EA1AC -:1006100027C7EC26F77941E3BD93C8EE535B76B567 -:1006200092BD526FFB740FC525D44F043DC8D00E48 -:10063000F138352D339EA6F6FD67BA75BA5FBA3E1E -:10064000D72855A3FAD720F21EE99927AB6CEC37CF -:100650003DD5FC0B3EAF42FB2E42CAF7A9AA3CF6A1 -:100660009B59713F7CF697C06F7802E51B44DDE72C -:100670005ED1B4C946FAF8A5B451517155D6BCAA99 -:10068000EE6CCDBE8EE4EE130ACBD1CCDF5CC1F1B3 -:1006900003B98A26113CAF9354A18F9A7AF2B560C0 -:1006A000FD35BC42FAE942D293110F3F94421CAF90 -:1006B00069839667A9FDDC1CA10F82D63882FCD71E -:1006C000E12AF37DA2E5F634D26FAC7382EEF0A19D -:1006D0003B3F0FF6B4E41D1CF7A404EC6FAAB14530 -:1006E000FAD3FC8EDB13CBD779834D3E30D01F621B -:1006F000799E0EEA6334AF025F2ED165B54D5BC9BA -:100700007EAF7D5E8E0F6997D4F498775ED4865F56 -:1007100093DE5D6353857D73C028A5F398F6194574 -:10072000FCEECB497BB83FF311E47B149775EB13D8 -:100730004D3315845B756FD4BB30BFF9895D3315BC -:100740007A87272FBCC486F95707FF45940F091FE6 -:10075000A6FC1F9FF848940F0B2FA1FD39F9C4691F -:100760009127030C11EC6F4FFCEFCC00AEEBB8E916 -:10077000FF043D3C9FE659FDC2205BB47FF1C86099 -:10078000C1378F27897AC773E186AB49FF280CF3FD -:100790007D18ABDE6B83CDFB0426FEDFF462522BAB -:1007A000C5095BED202771FF41B3DD4DE67B59485C -:1007B0007FBFA27A2FE768E9BCCF479147115C9EC3 -:1007C0001FCCE73D370D4EE7FA049FF4A2AEE32DB0 -:1007D00023394F72C01E7BFFADC1DC2F2812FD579D -:1007E000F756D3683FB2D3859D811B927617BF63BE -:1007F000B0C9D4ABC4FE64CA6A695065B9339CEC15 -:10080000E697CFF62D65BBB9A29BFB9E83851CBBEB -:100810002928C689F4D2D4CD7CEF1C0C8A4779B93B -:10082000396973F47B29274DF81E199C26E0D7B14E -:100830000F3D251E2768C2A52FC2BBB8137FACF69B -:10084000175AF7F67FD1BABBEC5399989FB51E8023 -:100850007B051C707E69A8E71F5F63B61B6DCD43E7 -:10086000637AB8E9C5DB3708FEA7A5B3DD0E3F11F3 -:10087000707059E316F1F9E40A530F96036F38C804 -:10088000DE5851DFC6EFAFAD6814EF6D75D29DB184 -:100890002A9ACE32F3C53A33652333C8F488EB6322 -:1008A0007A34CC788358FCE980773C1D77E94F4B4C -:1008B0008FED4FE3FEBADB87B08917DFD83E041314 -:1008C000C3B383BFC4C1AF831E73CD76458867654C -:1008D0005DE9F18FDDD171EED71CCFBC77B2E27646 -:1008E000335E558BC5E3154DB9B685459DF5EF6E65 -:1008F000BCD71B1D4FEB6A5A1020F957D352CE714B -:10090000B52B9EDBFAEB00B65FB6FD010F05531F5A -:10091000531AB2492FAE7A6C9DC7A0731625E021F9 -:10092000BE792C244F4B747F75D41029461FABA67B -:100930007F62FFC79FFC5BDDBFE1FCBF9050BF4201 -:10094000785737FDB58EECB73D862B4272FBA81267 -:100950009E4A72F4A6056E3FBD2F58D31CAB4F2D97 -:10096000FBE503D91A077707FAD8589F6AED43EDDC -:10097000AA1FB5EB64BF57EF93751C066A20524758 -:10098000F38B6F5FD3F8A183E0AAA23ED8775CD740 -:1009900072E4248CF7354D3FFA54F6507AEC1D285A -:1009A000A1FEA2FC1108F7CA6EF4B2C221B1F7028F -:1009B0002CF840288BF59BE0130F95BC8FF33AF190 -:1009C000E86B1EA9285A5EDE29CEA91A6FFCF90B26 -:1009D0005AF772F524E907CEAE7A80D62C0925BBEA -:1009E00045A455F6560FF905AA36D9F5007EAEDABC -:1009F000FA8BC7E95C05DE76EA74F458B5F5B48382 -:100A0000DE3FAB928C88C47A1678A4919DFBB47CAF -:100A1000EB47C25FD54B86E9B84FCB7EF5B9A86FDF -:100A2000402409EB2F7FFA7DF66F55F9DC7E578263 -:100A30007DAA68DCE508BB13EC53E3FB53490F0ABE -:100A40003EF125EFC3B19D12F4CCEDDABE72D3476F -:100A50000EA29B13B8211969025E649FD634CA0B9B -:100A60001CA989F6ADF52AD2FFB09CFD2017DA3F0C -:100A7000D7101074F1DCD66D640F54BEE3D4A7D345 -:100A8000B8DB6EF100EEFF11C52FF0FD67EBB20D84 -:100A90001CB7D21EC8563915DF2B1FB995F170E966 -:100AA0009BB766B35E07462FDB685E6F2F5AE7E29F -:100AB0008DB3789D4BC0C77858F933E1CFF85C818E -:100AC0006989EE1B6F1F22E487136E2E21FAF81C32 -:100AD0007B223FCC11078878DEB7C43B644EB83A1E -:100AE00035FA9DB93B8708391080D07BF4FE640D40 -:100AF000DAC5C417E4373F9F4AFDACCA55FC4E9592 -:100B0000D71F30E1259D13F11C9A62C59DE6E17E59 -:100B1000BD39A527D9C14E38E5B8BE8CDF69D0C82C -:100B2000FF1BD58EE17664B33359423BFF4876E232 -:100B30007B84EF99EBC0BFB7200A9F6AB61C617C2B -:100B400002B4BB527344FE61A243B48B52116E9F38 -:100B5000EDFBD0D19BFC1D99361840F36DFB88F35B -:100B6000A0676954DFEABFA6D919F32E49CDA31FA8 -:100B7000C5D1B333EEBD133FC3B3065235D2378F61 -:100B80003822535FA471705C8AD75C72BF33E6BDB4 -:100B9000B04E7C71747ECFEDA44FCBBE5A6AD27F2B -:100BA000FCFAE3F9C19371FC0036667DA5F79FAAB4 -:100BB000ECA1C7093E5548AF01A657417FA8A347FE -:100BC00006203D7CFCD44BFBBF4F7EBA467BE674CF -:100BD0001E2D96CF563E83F44BFE348477924E7C86 -:100BE000F64B07E9BD39156807E3BC3F76EB74297E -:100BF000AD2BDDE2F78474EB063ED7FABFC55F97F5 -:100C000076C35FF7C5C1F373284AA53B0CC79F5C49 -:100C10007E09FB15E2E06BD9BBF17CB37A88C67024 -:100C20008EE79BF8B71FA2E0B8ECBF3F61BCFDA206 -:100C3000973807AB7EF4AF2CBF10AC1127E26D756F -:100C4000E853CEAF23F9C5F95D33E9BCBAEBBA631B -:100C5000E1195FBEC1E4471DF7DCEE8400C5DD4548 -:100C600076C8FC0E433BCEA58EF4F3A772F99C70B8 -:100C70009DA9EFB7AB110FE9E7EBD2AC3CDC40EF3D -:100C8000C1B4074AD400B54F32E30FBC114F5A9498 -:100C90009EF47E8BEC21BD2E1C826989DF050CF24F -:100CA0003CC2D05DF91A715F4B3EBB2D6CDAF54E3C -:100CB0001C2FBCE6CB6D746E7E4871F1B9E5A23590 -:100CC000733C7CFFAF25FF3F092F16BF8A70247A43 -:100CD0000A188E5E08E71B0508D0FC08F079B09C66 -:100CE00052B6E745ACB704014CE724F1FE9465E049 -:100CF0004D6DCDEDEA374139E820F9BF14E511FB20 -:100D0000BD37C6962F6BF998F16C591C9EF908CF28 -:100D10007A75C5B3DC4B4DFF4A29949AE7BA6CCF7C -:100D2000B7EF95F93CFF940B58DFA0735EDC3138C8 -:100D3000D522F3FE9C7A4A0A71BC61204BBCDF8A43 -:100D4000F84E7A968587F1F67D7C7AE2D97747D29C -:100D50003DB1AA5FFFA5E4BF303DF1EBB707BE4848 -:100D6000F9E7FEDCFF2FD0B57EC5CEBFB21DD3BEE6 -:100D7000D3C9FED0F69DBFED4F72B9FD05A74EF861 -:100D8000DB7EA753C435EC4CE177CCDAFB09BF5DC1 -:100D900070C7972561965B6B791FA75FEAE0FD3E00 -:100DA000D5F2379623A75A9C1AADA366670FF68F24 -:100DB000D5BC901422FF40FB8E2F4746BF77F5CF5E -:100DC000AEA7DABC4FD39E0273296EA63D4DC4591F -:100DD000D6BC38E6176BC81E69DAE520FF7FC56F01 -:100DE000FE5E427CA9FD995D0EE25B68973E02883B -:100DF0001F732EFDE903F65E745F0CD8DE3E7DE9BD -:100E00003BB3E87DACAE701170684738D0BA102E95 -:100E100095A49775078FEA6F2D3C3E657BA2AA6566 -:100E200014D351275C24437C4F09B9245AFFF31E85 -:100E3000F21BB5E7A1FCD769DD5F9690FE74A17542 -:100E4000FFC7A5E27DEEFFE7D76D838B5AF753DF2F -:100E5000DA750BFC1F76A926DEA78AA383AE78FE7F -:100E6000DC0F38BF2D45E7F97E45FA7FFD5BBBFE01 -:100E7000AFBCEF25E4B7BDD87DFFF85BBBEE0BED53 -:100E8000FBABE6BEA7A874BFAE7DC7DFFBF37ABF9E -:100E9000E2BA938BBEADFCEDFCEBEED08F64AF8B72 -:100EA0009ED8BA075ADB344CD775A3A78C2AB2FC5C -:100EB00010C21E914D7D631D0C3336915D857A06FF -:100EC000D901EB3245BE1EF50799EF0F72B00AD477 -:100ED000F7D5C5BBB68A1F54CCDBFF7C23C7B3ACA8 -:100EE000CBFE0EE495D17985F06304D7E8BE5DD8DA -:100EF0003E9866D3823A3D57B5D2B709CBD5DEB21C -:100F00004AF6CD3AED6A57F43B168ADB1163A7B86F -:100F1000E3EC8DE402478C5D9204BB55F2C327E9F4 -:100F20000AC7FF3921AA3DD6CF2A12EFF42743285A -:100F3000A0BA2F1E4E8BBE3E9C5C7CAF5235E104A6 -:100F40008641EB766A0AEB610AA0FD28D621EC4EB9 -:100F500084A316054730ED50C504B9A20D6338A22D -:100F600001A14D1A4D70F5331C83BD6495E1DAD9AA -:100F70001FAF3B7E1FD6699320CFD4C725FD9B872B -:100F8000F3D822111F100F672BCDF795AF21FD77F6 -:100F9000D51A71CEF5CCEFBEC3F9263BEAC374CFA8 -:100FA00030D5B7A288FC8E5E43223A5D3543BC2F14 -:100FB0005846F7C032C9D41771B899AEBEA0B0BFB9 -:100FC00012ED0CF657AA40F69F3C091AD91FE855B6 -:100FD000E2E27A558E7B0ADE2CE29EA01034F14EBE -:100FE0004B6CFC4F601214525CC314B9AA81E675B5 -:100FF0000A521A28EED2616FEDCFFEE17E008F918A -:10100000BFA5FC8B8D549E8B7A3DD07D32A5F53DDE -:101010008A6FB84D4E058EAB8AE0A728B85D76C6BC -:10102000054A149CCB212D267FA2DFE126B213F2C4 -:10103000024E9582C72A5CBD62DA9FE87586C70BAF -:101040003A5D2AD94753D4DC98F6B267EF7B64D770 -:10105000BC916E63BBE0F29CC131EDAFFAE0C4C657 -:101060000526CED23ABEF7AEB8A78AF6D623AF632E -:10107000BB37EF0720BFF1155A694CBB66D3BF12CF -:101080009962E7F766AE2C1C13336E737837C3A5ED -:101090002A0B243A0FAEB2214960BDEFEAE531F5E3 -:1010A000BE37FA8A987E67183362F255ABBF0025C7 -:1010B0000360DCEAB340EF0796B636C6B41FBEB78E -:1010C00039A6BEE7753485302DDDA705291D75507D -:1010D000DC231D8EFB41E71BCDE1853AC5EB14D324 -:1010E00005D0323A16F0565018F2C8A3FE9728BD24 -:1010F00050FC3298EFB2269BE7AFEB6DA1C605B965 -:1011000014FFD3F0E35D12C743EE263C1D1D69A812 -:1011100048C5EA63CF34BE446953DBF87A7AC7B373 -:101120000AA08DE5AFDBC6E70253E4961289ED9F76 -:101130001EC39D51E72EDDBDD7F9A3D2F27D4548F0 -:10114000476B738C865DC4F727BD3B5FCEEB5A0FB0 -:101150005425128DE73F2AF51EA6384D2B4E2AB98D -:101160004216BF4771B98893A9B3E94926F362FDD6 -:10117000409D6AE738FE65C582BF8D6CDBDCE82EDA -:1011800023BBD3A5D1BE2667C4DEF3BE71B4B8B706 -:10119000F7459179BEA2A859D7931FBC3845B4270B -:1011A0001F1F8D37DDC6FA94E780BEC78EF9FB0A94 -:1011B000F7A9C4CE9AA67F10E0F74D0FB44D903436 -:1011C000809EF794DAC80E87BD76FE7D99A6C2C9C7 -:1011D000A70BA87CFA5B1CC3B86BC22F0B49BEAD32 -:1011E0001C3CE4BCEF8C7ACE48A045C5412C2BD6E4 -:1011F000783E1E25CCEF1279CE285CEE99A7DBFA5B -:10120000478DB77282D0FF560E4EDE4A78EB3960BA -:1012100088B8A842B73680E9239CC37C4209E75CC2 -:101220009F22E2ABB4F3BCF37F7CCB88349263198A -:10123000E57A1AF94133B6CA1DF7CE683D3FA6FFDD -:10124000D0C13AACDF3F19E7B58562D744792BF2BC -:101250002458EFB0CA9125613E43B2CAD7CF9E5CF5 -:10126000C4EF31C6D41F9AD751DF70E574F6AF15BD -:10127000AFDFBFB688E037CA467125EB7F67E777F7 -:1012800006709DAC4FAC447A06E97CF0EC710178B5 -:101290007AB8FC90A4C5BD9FDB5A4CF982BEBE4112 -:1012A000C558FF92B3A9FC0EC067F5492CFF2E3933 -:1012B000FB3D7EAFB3C961F4BF9DFD37491C6F365E -:1012C000E3E68F37AC26BABEEA7821C52858EF5737 -:1012D000D6A85F303FB0E2EC3AE187F88B78FF6345 -:1012E0005B679EF883A7139E06BDCFB53E0ABEF48A -:1012F0009B2F334C78FA8A37CE5E8BFD6B8BA6E53D -:10130000105D9E0637C7F59D561F9F4DF33DBDC529 -:10131000CE41B44D26BF0C149AEF11648673E85E7B -:101320007EF19B368E473A88F860203EE4B7BE993E -:101330005E4CED3295748A6F383DFECFFC6EC2E98B -:101340001F0207172F0B3B185E4D998B2ACA19FFF6 -:10135000B574F23F58F06D34FB79B8D4B8B298FD4B -:101360005CE67D1163EC45BD3FB96BC2977C2EB046 -:101370003617F5FC340A393E5347EF4BAECCB5B3C4 -:101380005C5A99F6C5D44CC2F7725784DE81A859CD -:10139000FD19C317BBC98DBE07A69C91418B8ADF7F -:1013A000D2868AFD571483F75F39E3E0F2AAD5A706 -:1013B000996F5BED4F98E7ABF42E23DD17AAFA8700 -:1013C000CCF746911FD64BC328DDED5819C54FA069 -:1013D000F1D30E3E3F14F7EABEE96F25939F728664 -:1013E000A4CEA2F9B56C3B339BE2056624A9B328D1 -:1013F000DEA06EDBFBB329BE60463F7516C517DC69 -:10140000573C790E97F7521FB0A1FC7AB964BEC859 -:10141000E7AA7FA2FC535BEF98C3F553C4BEDFB6C7 -:1014200075CE9C00F36337D3C1A9FA1E21E779E892 -:1014300060E9EA1721FA3DDB2EE5E6EF49C15CC120 -:10144000F73EB9BB0FBFDB09056D1C2FB6BE58F8C0 -:10145000FB3BCF5741A5F3D5CC7C30C8DF9CF95C72 -:1014600092F85DA2436DFD097E4736DEF203F2A7D6 -:10147000AE9080DFD1AF026D24D1D5425BF83D4AFA -:101480005F1CEEBBB798F5A9368E775DBA7A27CF89 -:10149000EF53DD8C5B562345DEAFF54E04F69FF02F -:1014A0009D88D838E30F6CDA40EA5731E1B2506ECC -:1014B0009BEF10F37A94E6B5227D17C7392B6A5B50 -:1014C000B64FE851856C3FE524F37BD175BDDF292C -:1014D00049F43B088DB528EF91E49EA96DE674F5BB -:1014E00050607CEBA9841D3AF6537D40C89D916DF8 -:1014F0001F38A2E319779BF04D357FEF2A3E1E7708 -:1015000037C9A5A8B88315BD5BFB927E68ED6BE774 -:10151000BEB4F635F70568BE99192F3D45EF9D50CD -:101520009CEB0FE93CE3B9A456F25B778F27D63EDC -:10153000887937250BBE11793689F5A6F8751C34E4 -:10154000E76DAD2762CADFEED61131E5EBBF6A1D4C -:101550001193BFC7AFC7A26FEBBB45DF5DDB8BF954 -:101560005F3CDE897B6D17C23B8BFF5483AF50DC41 -:101570009716FCC682B7354F0B6E4DDDC4E32AAB20 -:101580009F8F598FD236898C1E482D11EF5F298D80 -:101590005700ED87B2BA85EB75B71E39E5333EC704 -:1015A00059A6819FF4DEF875554123B7EBBAAE0812 -:1015B000F3E3159AE0C75DE3F823CC9FABD13E235C -:1015C0007DDC5A77079FC6F5137D4F4086C37C9319 -:1015D000EE124A645FF862F4E372BA31117D6EE58F -:1015E000BA39263F45BD3DA6FEE5396B62CAAFD08C -:1015F000EE8E29BFB2F0DE98FC77F59FC6E9F79B27 -:10160000E2F4FB2762CAC787DB58FF7EA3761AC7BE -:10161000A74F3C1A613DBCB556E5FCEEDA1C4E5FA7 -:10162000AED598FEF7D41672BAB756E7EFBFAB1D2A -:10163000CDE9EBB506A76DB55E4EE3F946595BB84B -:101640008CFCFBA33353F93C6AE350DFF525140708 -:10165000B92F5244F837F640E34B240AF2439FBEB9 -:1016600047F54EAB0E8E475CBB6BCC1F6EC17CC684 -:10167000EB322469E7D38B6430A2F0C7333D0C749E -:10168000FEED01F13E567CFD8525424F9E0B61F13A -:101690009EC06A3E0187B92EF5152393C54684EC9A -:1016A000F6B9E0673DD4B65ABC5333177428237B90 -:1016B000D607FE7B381E29F67D01AF3163DDAFB062 -:1016C0007C36DD3BC5F6DF7737F2BDF267F6A64F15 -:1016D0002EC5EFD77A25FE9D8F033BEFBAD5C5F611 -:1016E000AF75FFF41DDBC5E8130B4B047DB54B7ADA -:1016F0001BCD379026DE2F8A6F37CA5CE755C108AD -:10170000EB1F11D43F28DECCA2CB19EA2173FD9A3E -:101710002D750CD1C71ABEDF50D5A6E94184F798C4 -:1017200043822E46205DD0BE8D3D2AE86024D20142 -:10173000CB41D33EB4E800EDA997A8FDA983A03B17 -:10174000B17DDDC41FC9647F8DF92C14A4F4B2B33C -:10175000915DE7B07C5C9BF8DDA40BD993965EDAD3 -:10176000523B97F16867AD8FD3D6DA4A133FFD9CA1 -:101770007FB97635E7F7D40638DD5B5B6FE2670348 -:1017800097BF5EBB81F36FD4864C3CDDC2DF3592E0 -:1017900067089FBB4B4C39ED2A37ED0A917A8D359E -:1017A00076BEE78F9F889FCCA5B9127E544A21E26E -:1017B000DF75E9013BE5EB92690F68D601AE7F9DCD -:1017C0001B5A490E54E5BC28F4B0383C29CFBC86DE -:1017D000F164A619C77A20BDEE5607E2C389C6FB9D -:1017E000ECB1EF8D5E1C5E2C73AFE57B7DF17CF17F -:1017F000267A8F42EECA0F0174BDAC4CDCEFA238E2 -:10180000BDAFCAEF555B9B795F4CDC7FA9EEEBE681 -:1018100038DB7F9D9C514D39030BA87E87FD9D7C55 -:10182000703EBD8FD7052E71F6F7E141627F2DFB2B -:101830001BF54CF64BB58764B6BF2A731B3C6C7F17 -:101840008F8E78683F6FDA2103EB8B8A38EF5D4A21 -:101850001D6914D7D3BA7F1CCB99557B882F2D33A4 -:10186000CF7BE3CF6DABE9BC574A04EF30C7D52F30 -:1018700037CF7BE3D75D3DFE089FF7565FE05EE91B -:101880007B25B1BFE7137F7FB73B7CA17882E8F768 -:101890005C4F9EAD653BEDC8B63B1E0AF4FDD7ED2F -:1018A000DFADA5DECF4A441C35DF9BB3F6B3CEFCDB -:1018B0005DCEBA492EBEC7D03E42E5F76FDA25F1BC -:1018C000FE4EFB5F415FA3D1FB3AEACB24172ED338 -:1018D0001DCC574787C57B01E3E95E6282F702268C -:1018E0001C0A0553A8DDC100FBA3C6ECF305E9DE25 -:1018F000EDA8D70D99C8ABF465AF4C7860C9274BFC -:101900005E75D295796F8E6232F2BF3AFD698B4671 -:10191000E7907ED761B7BAA7F23B45A75B81A349A1 -:101920002DBFD8F083864CF712461CF20549DED64F -:101930009976E6A813013915BF4FF8CCCF76D018A9 -:10194000B453E552718FDA8882AFE5D7B2F89CC5FF -:10195000D7AC7B7BAAC3B785FCCFF04212BFFF1286 -:101960003FEF41436DD67BD6838612DF33EFE94DDF -:1019700091CFEE3A4776419B8817B8E46CFBE3645D -:10198000F7AC7AB607DF53BB907D50A39E4EA89F5D -:101990005A698D4D9CA30CABD08693BD497A2BD947 -:1019A000A1965D1A5FBFAC74D2D8A15934AFF16D66 -:1019B00006E1B76A3B2F7ED7ACFEF4BC76A1357E3C -:1019C000CD8E11EAC228BFD5EAA19219C7F2F5DE81 -:1019D000A19E10991B23C7BEED7A1FD26119E11792 -:1019E000D98624A7BE4F3B80EBB80E5A595FB9DEAB -:1019F000FC1D8B1B001CD1F7646F0483F9C39F741B -:101A00005F0DE1CD6288CCA77C8D14A97A1141F8D5 -:101A1000C9C4716AAED6555E5FAC7C4E36EFC1C6A6 -:101A2000C3FD4E136F2DFEDFEDFEC4F1FFF65295A0 -:101A3000EF41B73F3BCE46E738EDBF97F9FD54ACD9 -:101A4000C87C25384CDC3B1D3ECF7C8704F9CA009E -:101A5000BD2B5F393D7ECE64F61FD1C106C59F2ADE -:101A60007AE1F551F7CD82E6EFBA6CC194E22553E5 -:101A7000E78595E8F3B39F9AF32FBF7632903D74D4 -:101A8000952AECCEAB5C90798678E1D9D345B390BA -:101A9000415C45FAEC707E87FD618273C73B20C4D0 -:101AA0008F2EC17D7B5F9CF3C14D12FB4B9B9B44F2 -:101AB000BE78711AAFEBABEE23F6DCA304D7BFB848 -:101AC000491946F43D343D924774593CE6ED74099A -:101AD000E75562DEC7C269D743D4EF5BBD6BAEE3A7 -:101AE000F3A1C6369ADFD0F4B6F5F7917EF9AC0DC6 -:101AF000C86F7864CCED4B204A2E7B4A27FD8AEADA -:101B00006D97CC77EA7688DF33C016D9D1FEAD3F2A -:101B1000E915CF53BD56D3CF00AB9EE77BFC3354C2 -:101B2000B1073039CBFC3DC948FF44BF2F649D67E6 -:101B30000D25580AFF23BF2BB6DDF44FBE39F483C1 -:101B400039E45F84D6481ECDE34892B847ED29F5C5 -:101B5000FD8EF8CC50F2F3D23A7E26FC0347D2FC3D -:101B60007C8FE46DE4CF747EFC975A17A7EFA27DBB -:101B700044E9FFA07D44E9FB681F51FA21DA47944C -:101B80002E3E839DE2FECDD08DB799BF76B38EEE0B -:101B9000F94BC0D4EF13FF4ED35B26FC4B9A0EDDFE -:101BA000D983F0A059E6F8E8E26715D64F4FB68C16 -:101BB0008AF95D52A4D7C3B4BE92E63FFE84EE59C3 -:101BC000973429AAA4D1BDECD3D91C7F18373F8202 -:101BD000039D37447638C4EF2999F3DD9ED6B69E2F -:101BE000DA6F7F368F6648E738020F773813FEDEEC -:101BF000B0156FF7C450A17F7DCF19298B3E7F8C24 -:101C00008F4F633FF018C2E7823FD03881BD320C5E -:101C100060BC8CF56FF4D3C53D042B2DDEE1E038BC -:101C2000E5ED3BF65F7D25F6F77F00222F54BD00E2 -:101C3000800000001F8B080000000000000BCD7D1D -:101C40000B7854D5B5F09A39F34A32934CC2000957 -:101C5000123809AF00018664121212E024048A8A45 -:101C60007482D482A28EB462541E23D29ADED23FF2 -:101C700027244012830605CA558401C1C7FDFCAE66 -:101C8000D102175BF44E50A9F6B73422E2A354C731 -:101C900047552C4A8A62EBAD2DFF5A6B9F939933BF -:101CA0004C0222FC97F0E9CE3E7B9FFD58EFC73EE9 -:101CB0003BB3265E5E24C900A7E9670A80CBDB1729 -:101CC000A008604CE9D70FDCEFC1F2599BDB0400A0 -:101CD000F360DB3437F6BBCED1F1A21BEBD7BBDF11 -:101CE0009B968EF51B334D07A8BC49CE999E812546 -:101CF0004088DFFF515EC5810CACCDF456DB024E4F -:101D0000800A9000F2807F4EE37F531D29008E6889 -:101D10007D9ABB8FA1FEBDCCCB0CFD2F978718DA27 -:101D2000AFCC1B6D68D7E79DE92D34F41B97D19597 -:101D30001B74D23EBEBAA71CF70326080FA37DED85 -:101D4000FEF2EDDBB19C35719E8FF67F0CDAAE1999 -:101D50008D1BFDA4A479E3FDF4B245B165F503B88C -:101D6000857EC7F6E3103E5286ED926BF9813BF11A -:101D7000BDDB322590BC00359BADEF4762D6B10488 -:101D8000FC6961EC77DB0EE37380882DEC03B83DD2 -:101D9000E00CB62000173D81ED0E433B8FBB78AFC2 -:101DA000CD4DED4BC0126DCF01A83D9AF3E40B3140 -:101DB000E38DCBE8BCEF7E1C6FDC9E39EE065CDF6A -:101DC00093A55F0F90719FE55E97E723040D4C800C -:101DD00009A711E42039CD80FD4EBD2485245CD7B0 -:101DE00034E99BD4483E3EAF423C67E17B26F90F85 -:101DF00065D8AEBE2CC14E1CE76F75F2932F5869A3 -:101E00007CB8D19F1FA50B80950C5FBD7CAB0E7F6E -:101E10001D01F0C73A07977FAA7373F96E5D269785 -:101E2000EFD5C95C7E5097C7E5AC431068C7F1FE9B -:101E3000FCF7F1007D681C15A06FB41C67F39A07CE -:101E4000E03ABA7E2F85B6E37EBF289F9006B4CED7 -:101E50006F70FE620D0F4802D5448CA5F8DF8FB776 -:101E6000BD98E5E3E7AA0BA75AF27709141C77B9E6 -:101E7000D724C65DD4F1629627DA0ECBDF33F48720 -:101E800015A603867A638EB1DE5A7120F67D1D0E8B -:101E9000F1E52D9BEFB0055C58AE372921E799EDB0 -:101EA000FA7AA6ED4F524C389E659F3D64C7FD2DD2 -:101EB000712BA0607F0B80D29E7FE67B00F50CE744 -:101EC000791204DB138C5B47E312BDEF4F02E93C50 -:101ED000C67D0B6983D6A3FE973DB413DF7B2B4DE4 -:101EE000017FCC3C2DDAF89FA5B7FDE22BECF7D9AA -:101EF00033404FB00E73693D63777D6C3663392E86 -:101F000059D0C95877C49C81E5899A7F6C3CE261BD -:101F100032F59B26637B6ED71107A2FCBEF6AB366B -:101F200039106F6F9BCD00034020BE04FBE31854B3 -:101F30007FD07BD5DC46FCFDCAFD4961F379ECE737 -:101F400041E445A6A34AC1EF3710DD88791440511A -:101F5000B37415E8F32A241F68FF547FADDDFFE654 -:101F60007AA233E8DA48F2E13840B885D7AFA4C6A0 -:101F7000F2FFD2677FC2FCB9280BF99E04E066C16C -:101F8000BF0EFC773A97F83534DD89EBBD358CFC14 -:101F90000F179FFF9FF13AA37C3E22219F1FBA1289 -:101FA000EB4B9F91BC766C3EB96F98E0278DEF7537 -:101FB0003ED7E1B87493C47CA9D73FDF27CD08256D -:101FC00080F7368D2E86285DB369BE65CF5AA00591 -:101FD000D7B76CD288FEB1E3C7BFB7B44902396640 -:101FE000FC279FB3D710BFC8D0D5AF1AF967DCB3B1 -:101FF000A7322AF24559CFF868D3E44DD720FF180D -:1020000094D726FF9F7E8EF301E27127C2A7327319 -:102010006E36CD3FDB094ACB7806CB1C07CA89ABAD -:102020000588E0EA92EBB201E1B919D12521DDCDB5 -:1020300051AA5FBF0EF1F80373E02A92F3C7BC43C5 -:1020400078FC6B5CCBAD606672CD36E17873E7D817 -:102050000B693FB31A045DBF9EDE759C9EBF3E298F -:10206000C5D480EFBD6E8246C888EEE375AB3F9B5A -:10207000E80D37EEFE08F163524649A7537A9617EA -:1020800044C91FE97894A2F26F9AE454699E936E52 -:1020900033D3BD25ABD546EBBA154207149C7789DF -:1020A000376C23F9773BB82D5462D1D54D1F447F4F -:1020B000E5FFE8388DEF2FE9944226ECDF5ED70E7E -:1020C00016C4EFD3757BB91CFCCDE0C6CB101ECB7C -:1020D000C7DBBC2DA4B734FA32AB26389D405F9DD8 -:1020E000499F96683BAEBBC2E10C4BA9F4D87A3C41 -:1020F000761D8DD94ACA78DC8FBAA63C9DE99368D3 -:102100006170749FE36C004E92F33B5358CE1F7B7B -:10211000AED84C783AF63B6BC844F52D23DEB8D3E5 -:10212000C7752079732CC36BB6517B466E48C5F6D4 -:102130005BCCA0925C86ED426E3D3FE9AE77488E67 -:102140002DDFE932D94D828E653401A447D7BEF325 -:10215000EF38CEADC8AC766F546F2C9AF2E8C62734 -:10216000900E1699DBEE29C767A7203CD68DF0FCB0 -:102170008BA97D38E9ED8F1FB287CDF4DEC323B77D -:102180004B38FECBA98191B41FC854FAE7E0F39A0B -:10219000437DA105DF9FFAE83F0F92DEBCF5C9BE83 -:1021A000CC5F3ADD4F233EC4F59C403EA4F59CDC59 -:1021B0003784F92E8A7F0187C5280FC8246ADEB1CB -:1021C000CE4FF80C24CBFCDC02AA7219E17BEF4D58 -:1021D00040765381645288CEBB9A115EA633E9499A -:1021E000196FE6F7169951BF121D06E44282C7091E -:1021F000935CA0F105D07ADE7F6EE4F6167C7FAEAC -:10220000D63F4A774797FC86E86EB3DD6BC7251C3F -:102210004F32EA7DBD9C393E9DF9E516C79760298E -:102220008C3E5F52FBB5B19E0F0AC98D8206B9F094 -:102230000E2CEFD4E07EC548FFF7C7E3FBB7B5AF80 -:10224000DBF38A4CF36EFEE9DB34EF4B4E9E175EF8 -:1022500011F03B6112FAA55BBF3AFECAE3A3E4E1C9 -:10226000F5EACF3F7EE88DB1011CFFE3DDA38703D4 -:10227000D2DD02A9F3A307115F9FBB3ADFF93996BC -:102280004FBF74A81FC12F7EBD8B6ABF004B8C1C33 -:102290003A6E32F17E17D13EF0F96F0AFD3733BE48 -:1022A0002DA827106E0B5AC66C2779304DCA4F23C4 -:1022B000BBE9C431E3FAE2D7A98FAFAF4F1F5FEF9D -:1022C000B78CE08F709838CE2DF4ABADF373C2EFBE -:1022D000677B469B9015A3CF333AC7A6E747F1E447 -:1022E00057EAADD4EF1A12F5888AB90E81D7B935FD -:1022F000A650430EF7E3F6EBF039E1BDC2D3C0F5CB -:10230000394ED467D87F51E66F785D24E81CA8D792 -:102310007E00FA4FF5AA5F61BF3797A5B25C987B44 -:102320004B9B95ECDC6E79A6BE6D3E3DFADBCB3364 -:10233000849EECEE07CCC3A43F013767C1FA24ADFD -:102340006E2AF963C3AF483EDF99EA95D064841AD8 -:1023500019C2C4D7272144F05E6D0AB2BDE7203D03 -:1023600080658BC99B69C1523277F5019E27C47085 -:102370009A06010BD57F6B8A3400BEB7CA539949C0 -:10238000F4FF2638FD6417FD207DF51892A395EE25 -:102390009973E9F96C35D5DD82FB6DB4CA77E793A3 -:1023A000FDF303C94B76AF0E175D7FCCB578AD0456 -:1023B000DF7E41D9AB22FD16BEA2384C0C7F874A86 -:1023C000E3BE6109F6A575BDE55C3FC664263B2DFD -:1023D000E41A839B7DFBD07F14FD1EDFFF2328932F -:1023E000C81E98F35B07CBF19B40667EFF11282C3B -:1023F000C76F8600D76F8188F54B7CEFDDD2FFD9A0 -:10240000B91FA2FB7A77E257BBC9AE9F2BB5F7CDB8 -:10241000C176B512F248CFFCDAF17FB646701D4A9C -:10242000830592D0BEFA35D129D9EF475DA19DD859 -:10243000EFAEE42DA91D588F9884FDA556069FA4E4 -:10244000FEAA19FC0D58F64D0E3C4F7CF8CB14310A -:102450004EADC5E126F94806168DF3D13B2EA67781 -:10246000D2BB3761BD0CB145F03AD157D09BFA577A -:1024700060B97BC2EAED5468DC53B27727BD3AD528 -:10248000CCEFC36999D75116A75F7CA3CDFC3EFC66 -:1024900043E6F72775590CFAC537CE1C7C1AF73777 -:1024A000E5EF965EF5CECD05827F7C7DCCC144F60E -:1024B000E0FF68FC851092683D0D7B4DA116264219 -:1024C000611F94E9F40891D5446FE50041A27BD8DF -:1024D0008B7A4C9F2797F7FFB9EA233AC476B60761 -:1024E000DB9F2739690F0A3EC1FA54DA8F23085E51 -:1024F000B2D750218305EB49F8A290BB6E203BB6C2 -:10250000A502DAA93E092212E17B0A417A08F9C341 -:1025100032D3ED5450B8AED3F1F740E5F272087102 -:1025200079258485BE07B9F1299CFFAA4F40EC6745 -:102530005498E91D1D19F747686FC0E5B798C9EEB3 -:10254000F0FD30B1BF30A840870B22C473EE709904 -:102550000E814C31BF80879D9EFBA2F070C4C123C9 -:1025600089E0E18DC203E710F03803BE023E931408 -:10257000840FCAA7C9D025D13C8A66DF548297CB85 -:102580002AF073D90B5C5EA8F79C09979248C01299 -:10259000C84F009FA989E96684069F3F1600CB2F8C -:1025A0005DFE5C5B20F3735D0E217F66923D1A2F0A -:1025B0009FF4E7BE94CA2F64A487AA82AC7916D48C -:1025C00067BEC2CA3B8760FDEAA7F344BDACF257C1 -:1025D000B958FF41C128511F5759684578D59B46C6 -:1025E000CFABC2FA90806923F1E5F27AB4AB715FA8 -:1025F00081A47B8244C7A60C709BB03D505FE42D44 -:10260000C07A00E912106E7629A79EE06CFF397837 -:102610001B7015196981C905B8DEFCF99DAB053E33 -:102620002BFBCFC5FEC73BAD6CB7ACB10583842790 -:102630006477777D69747FC79FFE790D3D7F7A004F -:10264000B849BF80472EF4BBCE5C8FD9015C5F8C4C -:102650007283E21F38DF4C9A2F80EA49A6753D2528 -:102660008508FECBEBA7B13F7024CFFFFD82BE31C2 -:10267000E3E33EA4F134AFD073E0C92924B8958CCC -:10268000F45F4BFD4EB850BEA651BBC0434F6563CF -:10269000813297E68D7F6E4EF9E6862538CF52A4BB -:1026A0001192D38B0B0237D2B84BCD914185F86C88 -:1026B00065CA3B36A60B05E993E403F12BEDB7069B -:1026C000E991E87ABFE057E40077B7FD8AF8F5F8BA -:1026D000BB6E58E813224EC2FF15CF0D3E8F6635F4 -:1026E0008D7F3BAD63A9D4B590E8F2F3F4D76C7F4E -:1026F00066BE1C28E84E935B4B9FFB9AF9E7593363 -:102700000425CD3F8618BE5BFA5C9285FCC3A59F6D -:10271000422805DF2FDBF77803F93BA5E8FF939FFD -:10272000BC78D753CC6FFB485F22E896FEF7B3CF57 -:102730003F487C7A6512C7A126BD767408D94153FB -:102740008E461A106D70E2D9372E13F4AFFB257F39 -:10275000339D8F1E9F26ADB887F0BD0CF16FC7F972 -:10276000969982A26E75B855967BC24FAED1F6F19E -:1027700019746E9CCF72453D504AFBC99480E56345 -:1027800048F81332FE23FEBFFD686835AD13A46F11 -:102790006C246F4EA15F4CFBBAFDB178BFA3EB4038 -:1027A00029F9DDE417E33E17B71BDB97C6EA870478 -:1027B0007EF296022D1E960DD9B4AF5FA33FF4C1F1 -:1027C000309A777E1AD9871329AE90405EEAFE715F -:1027D00028B9F29102B697DB25E287324BE2FE0B75 -:1027E000F3855FACDBFFCB1E92D88F5BF6509F5119 -:1027F000EC276BFC0A612FF3EF93A45788CE022FCE -:1028000003D1C12DDA9E60731FA6B95B9B4CECC748 -:10281000D8A53BBCA4F7C73DD2FFB67F63BA4975C4 -:102820004326D527CC7DCCC3F655908435FA556C1C -:10283000673E99DE954BF33F992E838AF3352475D5 -:10284000E5929C559F757849EFC6AFFBED02E10F0D -:102850000C098FDF14F1083C139FE7BC54BA89F0D0 -:102860007C12F99CF0B7CC35BC3F38C96E989C19E6 -:10287000C1B241B3D3731E1B95361BE1E2A3F5C66B -:10288000D8D51DAF5E9342F6F26E8B3FC58DFD4EDF -:102890001ECE35F841F16551189153D84BFB1B33CF -:1028A000870412C05D2F7D9B2C0C2F9D6E7F5DA732 -:1028B000C00756C247B9D8876A77DB7D447FA1A994 -:1028C000E44F2EBB19DC2DD87BD9CB0F3738A8DECF -:1028D0000C4CCD27E97FD4FF137388ECF15FA68CF5 -:1028E000BDB71CEBBB8E59849FA22A87F263EC58BC -:1028F0007BA6196403BD764A8B491E13DD23BD26D2 -:10290000C9C920C7D0634A5E86A1EEF20E30BC9FD3 -:1029100056926B684F574619DA8BA13612C0F514E0 -:10292000654AEE10AEB8CF8C0243BB1DE93A4CEBC2 -:10293000FC52D85125F84FE8DB20DB4365118007B6 -:10294000900E261E37DA59259136F637930E5B0C1A -:102950007100FB59E250C9851A7F0D8481C45F481C -:10296000FF5E9263270F8BB893ACC17359B6D0CF7B -:10297000CB5E96D80E5C76CCCC7AE22478BBF14361 -:10298000F251E7BB78B8F7F51BE1DC7FAE11AE5929 -:1029900001235C2FAB31C2353B6884EBE05A235CEA -:1029A0007354231C87344D34F41FD65669A88FD82E -:1029B0007485A1FFC8D06C437DF463D71AFA8F6980 -:1029C0005F60681FB7F736437B3C5D8D0F2F33B4D4 -:1029D000DB538F305D1D40BA32A13E287CE9DFE237 -:1029E000E8C2C2702F1AE8F48662F0AFE23FC27FFD -:1029F00099969798006A03F1E385C2FF1584FF94C6 -:102A000028FE75B9DA139FEAF81D42FA9AE565794E -:102A100084F07EB22485E9E5E04B270F2B40F84F88 -:102A20008502DCEFAC29228E22C9C126A2934E700A -:102A3000B591FDB9C61264FF4545B3702729E53845 -:102A40007FF3FB25E86FC6ACB35A49024BCC7EC777 -:102A500087DB0DF5C297F61AFA1775860DF5F18723 -:102A600041227D55F0A6F7792A8B3E5438FC55FC5F -:102A700049F0792A4BBF0CDE45FA37DECFBD5AAD9F -:102A800097D2C8AFFF7BFBF368D6A07F364825BF3F -:102A9000377247AAD73400E191FC4E03F9DF807604 -:102AA000B4159511B80FB23E98EF10EFFF2D69F2F3 -:102AB0002AEA6F42FF9CF08E70C9237BAF1692BD4D -:102AC0000417B25BC80F832B843DBFDAA4B23D9AD2 -:102AD00084F628D9230D157EB697A74370203DBFF5 -:102AE000069455C4779219ED577CFE3F23028D85DD -:102AF0004562B1443F777D21B3FF3D85FC6906A661 -:102B000002A4F74ED0EFB43E78691EC5E34F902E75 -:102B1000C3F5B7B5BC304F253BC303EE08AE3B2031 -:102B200040069B0B03F7D0B8EF9BDCAB0BF1DD83CA -:102B300013FF3288EC917585C2EEB34B0829A4814E -:102B4000FEF315A0E78DD9CA7D8545D1384B4FF4EA -:102B5000A3C733F5F8E6AEBA309716B75722BA8B4B -:102B60008F3B46CCEEAAF1A4FF9699D8EFFC0B2D33 -:102B7000AE94E7496539EF804E7B3A2F99FDFFEB24 -:102B800035BC991D9DAB7E8EEFDD1014F6D60293F9 -:102B900097FDF5DB338F731CC52E99C047FE505A45 -:102BA000FE76117FD1E3259749DFC6CE3ADB7E6FF3 -:102BB000CF3C668857C1137D12C6D7A3E3ABACFFE9 -:102BC00062F6B9659347E835F2F3DF6FCEAE84D491 -:102BD00044F37CCEF1ABEB83AF1AF8E2C6DAB70C64 -:102BE0007C7093FA9EA13DE2E9B252BC32B2276BEF -:102BF0003AC5D73FDB6D2F263C20FE0F16C6C4EB2F -:102C000022CDA3AB60ECB9ECF72FBC8EA3759D8CE5 -:102C1000577DBFEFD4BDC9F5485D84CBF8FDEAF11F -:102C200011BD4471D844F6CC5D12CA0BF277495EEF -:102C30007862E405401ED9FF7749A3BC44EFB6FD96 -:102C4000C147A9BDABDEEEDEEEE3F808C74D6A91E1 -:102C50002EC86E00A7787F81CDC176E81D3EE12F9A -:102C60001EADF8EA06B25F7320D58B32107FC27FAB -:102C7000A2B8C97C531AEBFFD55907B8FE61338857 -:102C8000BC514DF821F25797A6A60ABB58C1FE5871 -:102C90003F9161E6FAA11181AF981FF3C39CDF5801 -:102CA000DA5FC4F3C01319447CF833D9FFB5E05799 -:102CB0007780DA6B32D0DF46FAFDC4AC8E35116B0B -:102CC000ED1A70AD05F1FE49B2FA395934637CFD55 -:102CD000AE253FF3139BE0DF49BB4ECF53113E1FA0 -:102CE0009A24F6CFD5674C1CAF0167C4568D7ED8A9 -:102CF000038303561F8EDF66457BD2299ECF1E13AA -:102D00008DCB9EB0624971D024513A7DC2EE75F9E7 -:102D1000449E532F4710CCB09CE4D3E57CEB708AE3 -:102D2000BF9DDC6C07925B38BF42FE96FAAC88E32D -:102D3000F7CBF02F028117F71A5CAF6788FC05F11B -:102D40009F4742BF16F721FB720CF167726053B1C7 -:102D5000FDFD3DF66D84BFEEF51E16F1B0CF9A472E -:102D600073BC5BA713D9A7C5BD7F0C20DA2FDB4648 -:102D7000ED8B5F7EFF1D8ACFFDA63030D487ED0B33 -:102D8000CC7231C9C9C5A91D1CA72BF6C93C2FAEF1 -:102D900097F78B72AB117D7158EC88705CEF6CF11A -:102DA000FB9EF6FFD9CD9D1BF3395E2D8F25B9A271 -:102DB000CF8BEB28A675E8FBD4D7111DA777FED1E2 -:102DC000E3D07AFDE387D60CD7F20837FA13E8E5AB -:102DD000AB743AB6268EFBD768F88CC74FC18860B3 -:102DE00088E3796E703760FD5A0D4E9FCDC3FD703C -:102DF0003C44194FF85D3CDBE92538EBE3F7CB8029 -:102E0000C053BDCC73C548FF1CA2BFDB82224FA0BC -:102E1000B723FD893867730AD3EBE2E7DE7AE7E789 -:102E200038CBAD8F8E2924FDA1BF1F0F6784EF70B3 -:102E30005ACF0249E4CF10BE37D1F8F1F981F385BA -:102E4000EB89EC4ED60B27B6FD2C44EB3B91056E7F -:102E500013F2E3E27DBF7DD33496E8C41996B084C3 -:102E60005DC6F857BC9E7243E03A92237694236481 -:102E7000DFD8F5F7065A0CEF55672A77F9D81F55B2 -:102E8000EE2679645785BF362450C1F5E556E1AF8B -:102E9000EDEA34CBC4DFBB2C10223DBEFCD50C9533 -:102EA000ECC7E56877B0A79317E4F54232FA41E939 -:102EB00009EC069357E6785C5A600DC14BFAD1D401 -:102EC000079FC889FAA3BABE2CD2F4BD927F6303D0 -:102ED0008DEFD3E281686772BCB314029A1DA1C55D -:102EE000E19A0F701C4297DB3698EBA0F8CF9ABEA0 -:102EF0000B1CE41FCA382CC7D73CB3D3A0173B72B6 -:102F0000551D4ADA11D1BAB5073F5E3F1FC06BECC1 -:102F100047DB0512D6D07AD5814823FEDA3AEB7723 -:102F20005D2F60D932E691C84A6AFBE6B44476A4C4 -:102F300043B303B8E847EB14EFD906AEBEC384FA37 -:102F400033D96B81F763F4A00339FFFD3C6D5EB2AA -:102F50000732BBDBFF4078EB691F17AB24F8BC6F6F -:102F6000EDA5DDE6AD49240F12C28BC8C433FD18B0 -:102F7000D16332C4EC9BED9E98BA14072F89CAEE38 -:102F800076E57482FCE577DDD7AABAF0AB1F1AECC0 -:102F90008110AFDF6AF18317E9C9E6C176C3390C46 -:102FA00055CB7F220117C7ECEF1CF64576B955DBF0 -:102FB00097F522EF8BC6F5F7BBA4D7A75EE2EB0B24 -:102FC0005FE2F885EA4B1B7E4AF5A50D3FF5125FDF -:102FD0005FF812C72FCCBEB4D7A7CCBEB4F1AB5E9E -:102FE000E2EB0B5FE2F885AB2F6DF829575FDAF063 -:102FF000532FF1F5852F6DFCAA6C073ACB81CFCD0D -:10300000A6379A4374CE46AA0A73DE3857058E4710 -:10301000A73603E72BB67B851FA5C7E947D2103239 -:10302000FA2D567716D9D1DB1BEFABFC318E732A04 -:1030300013174FF9FCEC230A8DB36D1A70FEC2D939 -:10304000F8D1518A7FE540D81BCEA1B89A04E11887 -:10305000BBF4FA600A8463FC896AA58FA15ED43947 -:10306000C0D0FF964D430CED37B78D36B4FFA8A9FD -:10307000D050BF492D33F4B7434E4B1EE55D1B2D99 -:103080005ECA8359686FA567C20D76D8F83D05FF03 -:10309000911F9383167DF7B8B88F74D56618D7192A -:1030A000D77EB67C407C3E614EB1964FE8FE7E41B5 -:1030B000BC0F6E4FC2B8A79E4FD0F139DC92C4F856 -:1030C0005AA78A7CD39A69C28F9C1A729B286FA9CF -:1030D000E36FB44672FABEB7D519FDC9F446772539 -:1030E000FBA34DC0F9DCDC2A7348C9A138C1C04A32 -:1030F00007E239B443D04708047D841A81F385A1DF -:10310000AADC95D47E2A047C0A46A78FD1550B678A -:1031100052DCB53EBB5F16C51972AA043D2CDD6BAF -:10312000A4034AE7D256D30F4BBCFEF4FA8C02CA72 -:10313000E79D819727049CF5F3E7E97170CFDB6188 -:10314000C44B3CDEBE2D5ED614C77F57F2EDF06255 -:103150009B2177A4519C540599E2322F660F373397 -:103160001C9ABC8C9F19D88DF830A70938DF134FF3 -:103170008FAD7510AE8AE1DF1C6F5821FC4C93F2C5 -:103180002B99CFF0DDFEC0A744195FDB9A44FE16F1 -:10319000CB641A1FF6CA0328AE105267F3BAB737CA -:1031A000DB92E93CDF57F566A0F3F2DB73E40194B0 -:1031B00017DBFE8C696EECF920A40ABB3993F7612A -:1031C0003797706911A5A2956011ED6189EA835660 -:1031D00098E3F0A94AD49E3E2339EEB962A2FE5B81 -:1031E0008A73193E694A86015FD61223BF23180FDE -:1031F000E5A37C1C4CBFCB4457824E42AF4BA195FC -:103200001C5FE932D510DD68E72DD257CD06CA47DD -:10321000D567FF742ECBAF7A1BC31D5608BAD0F307 -:1032200082D6264187F1F4E3F21AE9C72A0D3489E0 -:10323000FC96E01F7D1DDB146DDE2C0954967BB6D9 -:1032400001C467D6B8F1EC243C49DE78045F3A61EA -:1032500036D07BCE123BE7B1413ACAF8B74E00E810 -:1032600013734E217EBD675DE777A4F30FBF239DE7 -:10327000EBF267AD57933F45E25CE429A46B8A1FEC -:103280004DADEA04FEFE0ADC26A247A4835959C5C7 -:103290007CF4817F76911CB213BCAAD3A8DDD5A99A -:1032A0004C25FA9D2EBDA2B8709CB587059DA37EC6 -:1032B0007989EAADCD16A0732628674C3FA2794BD9 -:1032C000EDEE952479A481E369DD853E943B1447B6 -:1032D0007CC5282F8A3A8D70CB8D97EB3DC0B127E6 -:1032E0003D110F47D7040D8EC508C721DF1E8E364E -:1032F000AFD0C3E92542CEBE98FD537ED57D589C04 -:10330000AB495780E1FA852AF4F274E97898E4CB66 -:103310003A05E50BB6CFD0DADD25429EE870CED572 -:10332000E0ACCB9375F32183F8DE4DF2C44970FD18 -:1033300088F5765B9180334084F39FA98AE09335CA -:1033400056F0529CB6ADD4E9A57861AEA2C1B7499A -:103350008397094C04DF78BA9421A68EEB4B8DAB92 -:103360007F5BF8964ED0F4643F283E1FF8AE4B4981 -:1033700015FC3654C0C7EA8CF0B9E6A61C8B77253D -:10338000F275470EC21BDB9B5E17F0FEA5D67FD5FC -:1033900018E07A53DFD5990CAF9C859944CF4DD670 -:1033A0003695F2584D3AFD69E7C25C9A9C9886FCC6 -:1033B000BD00DF5F8DF289F290A92501078DD794BA -:1033C0006F0189F7BFD99B68FF0E9FCD20072FABF8 -:1033D00031C235250E8E49DF91FF7F3CE1BBF1FF05 -:1033E00076FA15FBAD1906D0C979C89083E0642B35 -:1033F00099984C74D4D2BA9DEB32849A7271FF0FB3 -:103400003B85FDD5D23ABBD7F351214D2E6CA97324 -:1034100070795F9D9BCBB6BA4C2EEFA993D97E698C -:10342000ADCBE3B2A5CECB65535D0997ABEA14EE05 -:1034300027ADCDA860395C051CCF5E99F239E7DF76 -:10344000E3E7CB518D7A6C706DB201EE7D6618F5B5 -:1034500055BA62D457748E29B6DDE51D65684FC92B -:103460002B30D493E48986FE5326047E3981E48090 -:10347000A7324E0F223F8E899EB36B6915DF4BE951 -:10348000F0D3F59353E3F33556EF00CA3B395B05B0 -:103490009F366B765E13C111CB6405F8DC8CEDB002 -:1034A000E40D01F1FF6AA6F38771EEFE488B1DD98A -:1034B000D7286427B4C8C28EB78238F76BCBF4879D -:1034C0006BF07912EA2FCAEBDAE6A6B05C78D8E3A3 -:1034D000F4D239DB96D6656E5E8F579CA771E3BF39 -:1034E000447980F8F3358EA1C67339D6B39C6FFC4E -:1034F000754FF4DA9491508E9C2167BBF32FEF6BDC -:103500007429F22FF778043CED3DC8A3D6387BD957 -:10351000A9E55F60A02F61FFA83D25F20BAD717199 -:103520007BF4C312E66FDE9A2071FF3F4F9085BF98 -:10353000660903C96B9717DF8FF53B14F17DE8B976 -:10354000CE8F3F3E4F8C7C0A2407FE3C019F2B4FC1 -:10355000083B254916DFA1D84051583E81C887D085 -:10356000591FD237A95ABEA75BCE908888A13BE7E6 -:1035700019FEAEC88BD06716443F96E8FB17C4BF50 -:10358000FDB66523F9C3C37A69A7FC5002B9E02AE6 -:10359000D1BF1F832E4F3180EEBA23FC5C2589E119 -:1035A000172678359AD6CDC8C5E7A95E8B173100A6 -:1035B0001525F25E3A5FB14A4965FDBEAA446E2701 -:1035C000FEF942717A091FADF955ACAC93867DC8FE -:1035D000A2B7B1C4C676BA8E87246D5E444F679594 -:1035E0000E67ECEFCC9B11ADE37FCD6336725EAF1F -:1035F000E5AA4738DFD732EB3F38DFB73A6B7A1EA0 -:10360000C9BDA492E9C7F82097861F660DD2237919 -:10361000C6FCDEE9D3A2CE70A0F8849607048F31F1 -:10362000CF6791FD86F92F349E60A0D0436051F89A -:103630007B8333E95BF0B5DEAF673E50F5EF4E5765 -:10364000D2F9E0268F90A34DE07D3340F55724AFAB -:103650002AD3F38237E9BCE9EA8116C6CBEACCD992 -:103660004DC28E177E53936725E76DE3F5369DD7E0 -:103670008C95DB745E3356BE37C9B37BD5CB59010D -:10368000739CDE37BE9F1D34EA1FFDBDA4CC2B5FAB -:10369000AB8A392FD56CF13B485EACF2DC678AD53A -:1036A000730F2881052531E793AC99B3F83D7BB6BC -:1036B0002FE1BAAE50948544DFB8FF5EED81F59AF4 -:1036C0005CDCA8E997B3ED7393D6FF01ADFF66D23A -:1036D000EB23A2F8193EF4F26496CFEB441C8379F5 -:1036E00020665EA524B082D615C5AB390A17A4D3CF -:1036F000E1F957B0DDD1B06E7632E169E7FADED795 -:10370000A3E7D5F57E7A1E353EBF6EF3980DF0DF48 -:10371000A3C985175C0B2B1F40D0EC6C13F4D4B0FD -:103720004EE891E14F887D9C4987C6F5EE6CEBDD54 -:103730000E8AEF4F91C56E3AE17A465C7D405CFFA0 -:10374000DCB8F65171ED0571F58971FD2BE3EA578F -:10375000C4F59F1D57BF36AEFF82B8F6DBE2DA979D -:10376000C5D5FFCD884FDFB56989E0188F3FBDDF34 -:10377000B9E2EF5D5FC57EA2A3E13083E945A7B75B -:1037800073C543D4DEF5339DD94A46B17CDF81F65B -:1037900015D9433BDB2ADDE27C4760E56E8D3E4870 -:1037A0003F58368879D0CE4AE6F89CD36390236799 -:1037B000C3B709328CEDB17668EE85C7F7D9E93326 -:1037C000A4D917BDAF5BE7E32913FC27490E414895 -:1037D000F899BA5DBB4D15FCB34D5D50B99EE46DD3 -:1037E0009359C49FB5FB50E86E1D11270F684A38E6 -:1037F000C2F18426CD4F68D3E4C95A4D9EDCADF9A1 -:10380000094943839B28EE9B7C988FE740B3AFE048 -:10381000AF0B103FF797166FA3EFC7EE1E53F2F8EA -:10382000C35877FD5D827021DAE9635B14B259DA1F -:10383000948C243A4F946272B4939FB8AAB0CD3F4F -:1038400014FBADDD7FACFD79C4B39C69F3A2CE0758 -:10385000D9D265227A837C2F7F9786EB54C9C6B272 -:103860009677D5253A77BAF60AB7898CB0F419B2AB -:1038700099CE11F79910E85B8AF018DC046605EB25 -:10388000196A98CFE25C532A0BFFEA196428DE6FAD -:103890005716C1EBAB66DB7EAAF68C0F90B438DD11 -:1038A0007995FA38698234E887E38EB245ABAB8FFD -:1038B0006CA6F3D04E49D4A73CF3F8FC95F9D1FAA5 -:1038C00098671E1FB812DB5B0B0799489EA67B52B8 -:1038D00013DE137375A9909FDB9B170E4EE48FE9DF -:1038E000A53C13383021E76B25D1D4042C876AA579 -:1038F000AC3DCF14F52B35B8C9B55ABB4794177AF0 -:103900009EF8F1E794BA753B7B809F8D6CC877F683 -:1039100033D88B5797F6622FA279CCF1DAAD56796E -:10392000009D23DCDA6C03BAFF616B3688EF905799 -:10393000D9F8DC2858DC03AE7145D71D5AD56F1E67 -:10394000D14DC80486386EA6065FFB4493768EF28E -:103950009B307DC7B755CBF36C8588DB9D1F8BE70C -:103960005FCD27BCEA78DE57FAAFCD449F1DD90B57 -:103970002B37E27BEB1ACD1C3759D798CB744EE32B -:10398000907D746AC52133D9ADF9D06E263B7F1482 -:103990007D793D84AE400A70D9AEC9E7FFD4FCF80A -:1039A00061A0F0F341D0C5C0F9B438F01382CB1058 -:1039B000126D12F18FDBE4C07996EC4BAF48A4B7DF -:1039C000EB4AF5EF7AA1C652ACF91732C3B78EF8BD -:1039D000281EBE74429FE38E8ABF9EDA9D7B5F0DD8 -:1039E0005F86D5DD6F18E993F0363B46CF6CD4E0A7 -:1039F000E7F6FA15C2E1B5C581167A7FC9A6BF1EE2 -:103A0000207354565533BDFF14E11D9F2F0C07A79B -:103A1000D33063BCE14AEA3FBA76DB7E8AA7E5058C -:103A2000EFA8EC8FEB1BAE54577A888694C0FD3418 -:103A3000CED0CE48850BEBCE4DAF86B3783D6379C3 -:103A4000BC5C7D3D480FD54C476E11C7D7F04BF895 -:103A5000A773CB0B370BF8607B16EFCFE2CE8A5DF6 -:103A6000FFB669FDF8BB8578BA68D5E0F758148EC3 -:103A70006035FA358F2582A34EA73A3C6E78A26B4B -:103A800015E53AE7873A5F2439E8DFE49EC6F2B0ED -:103A900038F024BDEF6BF337701E7057275D47D4A5 -:103AA0000D1FA7D249D7BB603FE569C2FBD615EF12 -:103AB0005772BC782F88B8589C3ED44BAB129F6786 -:103AC00010F7E58CDB6BB493915E958D9E587A353B -:103AD00073BE33A4E9935013D22FCDB742D06F48B1 -:103AE0005DE64E44678F687A658746B7FAF3A13D75 -:103AF0009CBB3C54DAED27664A46781EEA8DEFD32C -:103B0000C0CBFC807C7084FA65101F607DF00A37A2 -:103B1000D3A7CE074BF6FEF500DD67E3F4C905B188 -:103B2000F7D745343C227DBE43EF2FD9D475807C36 -:103B3000C5C12B047D7E4C77871545E90CFDC7F781 -:103B4000A89F4E3FF1FB78571B4F2EF67F4C785CB9 -:103B5000B829C8E321FF1C2BE5713AC349CC724A4E -:103B600025ED676B1BB8693FF65F1474905C3855A0 -:103B70006B62B8DE981F5E65C6F2FAA160A5EB869F -:103B8000AA33916C72298F6BCCFF0D6B33E20FE976 -:103B9000E76F344F91276013C1EBA08DE5690F7477 -:103BA00011D57BAA0EFF157172D73CB1177A3ED79B -:103BB00071D7162B8E8945DF621DE7D84F8F379D51 -:103BC000193F1DC5FE434BD36CFD9CF00CBA8F67AB -:103BD0003BC54F11AEAB9A7AB7572F58FCB4F9A436 -:103BE000889FAE008E03AD4C196B4A44379740FC5A -:103BF00074CAC444F1D3C87B063B735593900B3A07 -:103C0000FC86578D4C16792948A57C891E1FD3F751 -:103C100075B7664F3669706B21B8313C05DCDA0840 -:103C20006E0C4F1D6E33843F425F8853BCD66316C3 -:103C300079B1910B3651BEE054A6C893D767DB44E7 -:103C40007B8EC82F9C411F9931F634F2C19A667160 -:103C50009F08BECF79B517B30F3886509E33D3CCAB -:103C600071DAED9EFB6AB6733D99F9CF0A6A5B1E65 -:103C7000CE3BFCC3B9EA027A5E62E773F27A3EA7F2 -:103C8000A5AFC8E7B8F2B47C4EDC7C76B8A9B28D9B -:103C9000E6CB137E4B8F74ECD3F2115A1E2823DF30 -:103CA00098AF70C4E52BE2F3956B9A17ECDF2EE228 -:103CB0002B2C9F87FF7824FB63F1F3B8671AFDB7BD -:103CC0003523753FEA1147A2EF1852AB8CF4D8A206 -:103CD000E1BBA1AFC8479C6D7C284F36F8552D79C4 -:103CE000E71647D0FB911FEA4ED03FDE0F3D1FFF86 -:103CF000D6CDE31BEF074CE0DF6E99C8F11441DF2E -:103D00006B9AC5FEBBE3699A5FA59F3FD2C7B16AB4 -:103D10007E1CD773A2724ACF870D75DB985E876AC7 -:103D2000F74535FC7B4A68650EE5D76675513E72EE -:103D3000E80E89F3EE439D7ECE43746C98CEF9F184 -:103D4000BEC981A727C6C49F76B87E9AC9F9022D3D -:103D5000DECFF7E6A0DE53D715762A64EF8E04BED9 -:103D60006727392E1F107F3F4E7C7D4E99D0C39917 -:103D7000D741C27B4F3E9F28DACFF4DFAF6038A136 -:103D8000BF9B2CE4ADA2D7FFBFE4A976B61DE2EF3E -:103D90007D4EF94093B3FF0997A29C3D5112389E86 -:103DA00050CE5ABA58CE8627289F919E5C4E177DDA -:103DB000101E6E4C7C3F8F5C76A9E2E16981877CA6 -:103DC0001D0FF75C92F942C4437659223CA05F452F -:103DD000F06AF32983A85D29510653D98D8F1F26D8 -:103DE000E68B5965C2EEBB58F858A7E1E35EC207FF -:103DF000C769642D4E93C7CF9B357CAC39031FEF49 -:103E00000B7C94E8F878EEBCF09151956168779757 -:103E10001BF191EACB35D49DF9467C240F2D308CD3 -:103E2000B7BC4C16F7240D9C68E877263E8CFEC084 -:103E30009DF45E2FF6E8C04067057D4B34606E7BD5 -:103E400007C9E64C7F5B0595FA3E37C7F9737AB927 -:103E50005CC35FE6D4C4F85DA0F15BC644E526030D -:103E60003D7C2F317FD668FD979728B794C5F2F334 -:103E70009589FB2FD1FADF3641591CDB1F7FD64BCA -:103E800031F6784FFB0E242BCBCB78FD224FB6A317 -:103E90003E95F3663B92E476CA57ABF54EC3BD75CB -:103EA00083E937AC67FEE89B0E95CED9D13D4168DA -:103EB000596DBBA35FEE1A6CDA96317C25C1B1A9AE -:103EC0006C88B8BF7591FF6DCAEF28EA09ED1CD266 -:103ED0007CBEEFC814EE63A27BB2C09D714EF92385 -:103EE0009467E25EB7C120BE238620EB41C90FE98B -:103EF000F4DDB205FC225F4EFDC5F785BCF9140860 -:103F000073DD0511AEA7697EDE0365393C6E3AC8E4 -:103F1000260124AF89E4A8CEA70E4F90E9DF53EB2A -:103F200036AD245FCE0250467EA073207FCF0B9526 -:103F3000A0523ECB040EB6334DEB0F7CCD793AFD4B -:103F4000FBC397FB88EF0FCF717FE7DAAF91EEE508 -:103F5000F344EFE56BD4EC01FD5E3EB532C8DF976C -:103F6000AB2BEDEE06CF99DF973F3A31B08BF0FDEA -:103F7000B7A4412191640E4E98EDBAA0E3872FF2C9 -:103F8000F8AF5CE4F1DFEC6DFCBBE9D752CAEBF9AA -:103F90008F123F37B88AD9EED4CB78BC5DA12811F7 -:103FA000EA27395E1BF0619FA83DE73C6A627FA863 -:103FB000C124CE9FA9EF99D8EE827C41074E19F219 -:103FC00072C645C7717A838345DC49C45FEAFF74D2 -:103FD000D708B2BF7F99322B9286E31D7C55D87FDC -:103FE00096A991CD74BF73FF349B773BF2DD3DDA28 -:103FF0007AEDA513EEBD137FBD798A90172E8BF74E -:10400000F2023EB7343342F6A3ABD82253AEC01906 -:1040100097D76CB5B42553BCB275C77D15A3B0FB5B -:1040200063752FB91B137CEFE9D4F29A23A5C472F0 -:10403000F09F939244DCCB67BC4FD85AAE9D2B497E -:104040008554B2232DFF52D2129D07D04B7DFE2204 -:104050004FA48ABEBF8ED0256E88E7A292EAA464E0 -:104060000F9F8BE824F8567AC30EB27F1F5F10BCF7 -:1040700035F6FBD3D61270911DEF9B22CEC36E5046 -:104080002417DDAFF160C4C2F78E3FB8E8E9E6144B -:10409000ACEF3D6A76133C5AFDEF3993B1FE388E92 -:1040A0004BF2EEE00E71CE529D0FA16108BF56F2A9 -:1040B0002AB1BE5B11E7B2D9212BD6AEEA43F8FF95 -:1040C00075725F016F0856D3BD9DEB5226F37D9646 -:1040D000D973443C78BA74B483DE7FB0C4CEF81B85 -:1040E000A29DD331A9D57C9F65DFF9C6733A0F2E07 -:1040F000EF5409BFEE52BB5BE5F3974ED7587CDF18 -:10410000F5A8192456715D3CF974C929D6E5157EC8 -:10411000EEE37258A5FB8EFBE27BF56EBE35D170E7 -:104120001E68F726E19FA68D777A91D271BD71E75F -:1041300085F475B5E1BAE8DE63D7508E4764CC31BB -:10414000AE2F2DCE6F70C6D5A79677DFE3339CF0E8 -:10415000FD85FFA785AF71AB574EE47FB6D64167AB -:1041600055CCB904670F71C09AC982AE6D592F380A -:10417000C84EF9C27FC4433878E59F073EBC97CA52 -:104180007FFD6ED75284CFEFBF7E73C793B4BFDA83 -:10419000BB0F11BDEAFE189FC1C4F5BC586D63B8D2 -:1041A000F96768E7397D1D2F587DDCCEF9A5B5FB91 -:1041B00093B87D64398492B07DA445C9BA99E8AEBC -:1041C00053F2D6CB3488388FA8E37FED0D7E138C65 -:1041D000213CFA25BA0F639A76BE76C3229009FF76 -:1041E000B645ED7C5EDDB75C9C57F729D5497CDE92 -:1041F000748E99CF87D4575F73F930ACEFBA5CDC1B -:104200004F3563B9328FE75704BDA475169B9713DA -:104210005D6689FB9AF4F3A645D0C5DF7F8CF4B6C2 -:1042200077D848DECC4700D3FA5A357C69718322AF -:104230005FA74AF6A4CB6BC463461CDEE2F1BA4228 -:10424000C7E34818497894A12D99F4E14300ED742F -:10425000AFC086E54FCFA3F36C5FA8690CAF9EF8A3 -:10426000F91DB4579511740F8B83CB4EB457A9DC4D -:1042700085F62A95AE60C575CB71DD7BDE38F8D248 -:104280000F71BA594AF5957444AB48CB7B81BA7427 -:104290005025AEFF06E25E51DF4289C4777D92A1D0 -:1042A000BED66389FE3D00FCD595A5FF7D80D35B1E -:1042B00094A108964C8B968F11F559E487C4B4EFFE -:1042C0009E69EC5FB63F66FC81B8DEC5366E0FEDC9 -:1042D0005BBA45B5C4B43F87F572805735FBF1FA38 -:1042E0009D66FFF604F2EDDD7261475AFE052AC9AC -:1042F000B52FD14E23FF5E322B2CDF21D72227BAD8 -:10430000570F00E561AC5F2E1BE5EBE51A5F58FC2B -:1043100015A0E5C7E01B3DFE803F7BFE388BEF63B9 -:104320005A35C4C2F70FA13EF0F696AFB3782C9F72 -:10433000C6DEDBF5AC2EBF87C1309AFF4B28FF43AA -:1043400005F341CCBD0DC4F76DCF5FB614E7F11D89 -:104350004DE638AAE45A9FC2F731D535B13C7F40CB -:1043600009FCB63CE67C4963FAC242922FFA3999BD -:10437000E8BD47D798BFCDBDF71DD50780F4C297DC -:10438000485AF65EE8B0B16EEF115AC7EABA762E17 -:104390009D6E85858DDD12E4B8CF154AE04FB43EA1 -:1043A0007B26B6C7F089D58DEF19FC0EE37D9CB254 -:1043B0003BE224B86F28F9C049F3B71E167CBDE173 -:1043C000F0EC24E2BB56EFA124E29B2FE8E2C7EF1A -:1043D000C0273EE5559661BBDF48BD9EE8674F4369 -:1043E0001ADB150797DF7F2DF1CF8DBFF801C3BB17 -:1043F0009B6FE0E14195CE18BE818799AEBBF9462F -:10440000ABF7CC377F67BEDADDCD37A2EECB074303 -:10441000FDE04C63FF6EBEA0F1912F1EAFB073BBE9 -:104420007DD2C35BD418BE3A49F558BEF909F24DA6 -:1044300002B93F7D9246DF17986F522E32DF0C9DF6 -:10444000A4C9CFEFCE3763275D14BED9633A1FBE30 -:10445000B9EC4CBEA99AD4F7DBF34DAB3BCCE7E902 -:104460005AE79813FE7D900F347939757EA0B28D8E -:10447000EC1A45DCDF374D9A99E5F3109F497487B4 -:1044800034EA4FA1CF0F5EDFFD7D06EB67FDFEF541 -:10449000F58450B293160BBAE9AC1371DF6952F987 -:1044A000B4C5A477E93B024A3553F694EC02D4FB39 -:1044B00032D985D05EE1C179365499A04DA62D0739 -:1044C000AB87F1F861B6CF8668717FA7942FBE677E -:1044D0009A29FEEE85FE5D4CB562BC5FB6FF59ECD5 -:1044E000265C770AF931EE12F17750164D8AD7BF64 -:1044F0006887E0FA3A07DA984E362857F71A273ACB -:10450000E35CB52F98302FF9D6249376CFBEF233E3 -:10451000A2B3DD6F6C49A673127B24E0F339F383F9 -:104520004FCD23BE73A942DEB4AEF833A52361D7C5 -:10453000B41F1AF5347C6AD4D3F0A9514F6BF51E21 -:10454000E58D7AC2A8A7B57AB79ED6EADD7A5AABCE -:1045500047E5CDA7063DBD61D2A70679F31ED5CFAD -:10456000414F1F9E7471F4F4A88B2C6F9EBE70F2A5 -:1045700066DFA4BE1743DE1C392F79937DA6BC39B4 -:10458000743EF2C6B5B943A5F4CCC21EF8A056C31A -:10459000FB5B65CADB343E949C5BBC269EBE3AAA9C -:1045A00017AEA6BF2BF3A557F87F3DBDEFAAFDD5EB -:1045B00091C6183FDC65E914DF23D4EEE1E7B76C60 -:1045C0007E95E3B1675D2F5D105A74A65E45BBC84A -:1045D000C1F4EB35732EFC7CD7D13A47F0DB95CF95 -:1045E000DEC1FC945C6E9C4FB77F3BAA6D669EAFAC -:1045F00044C8E99EECA19EE6FDA05C16F7FFC5CD80 -:104600001F4FBF489FE9938B981E2D742FF8179D5D -:10461000C07FA7EABF4E6EFCBF8A7C49E9C51193F3 -:10462000CF834EA76BF84CB06FEFC5DDF705E3CF36 -:10463000E993CFC38E3E4CFBEE9B70DFDF67385EA5 -:10464000B47D5F30FFE1E6F3C1F7BBE5DDFBE6EFEC -:104650005132B47D6FF8E735EF515C63C3BFAE7D77 -:104660008AE21AF77D9DB78DE21AFABD726910FDD4 -:1046700091F5EF8F102E2EBFF89E24634ECC774518 -:10468000C0FE7DF4BB13B2377CDDEDFF2BF7CA9182 -:104690007DD2DBBD72AD36635C4F2FAF2A17F64A71 -:1046A000AB691DC72336A05F558F78EB9823E211C5 -:1046B000AD68A7B0DC9953D0AB7DB4AB4EE1B85335 -:1046C0006B9D9FCB7BEB6670B9EBB5256524777D41 -:1046D000AF2D62BDE7F3FAAF7B1881E4AEF8D049A5 -:1046E000CFEFF5E8FE90B05FD2C87EC1FAC393D792 -:1046F0006F8D8D0B8CFAEFE15BD481D178555B66C1 -:104700008CDD23C7FA51A012B944FD28AC1BEC9AEA -:1047100011EC47ED26BB06EBED934718EC1A7D9E96 -:10472000B566A821BB66ED0EF38C4476CDACF2C421 -:104730007E14D6390FE27039F8FB7F49FBFB5F51DD -:104740007EE9DDAEC99D7271ED9ADF4FBE30F18713 -:104750006E3ED6EC990714E50D4DAE7C47F9B1D10C -:104760004CF1E36F2B3F4692FCC837C88FCFCE4742 -:104770007ECC2A771BE2A20765B5CF58B2D37798D3 -:10478000A15ED6F42FD63BD1AF31219C7E5221B110 -:104790009FB3C10BFCF7FDA64BF35F267AD8BDC8CB -:1047A000CCDFBB3FA88873220FCD11E7A91E5E5E48 -:1047B000309B3E235A9772C3DD4914D72E17F70456 -:1047C0004C97CA39CEFDE00C61E7643BDB2FA7FDB7 -:1047D0001FACB000D1D5D9E2DC146EE778B5E6475E -:1047E00081B499FD0ED70F2D6E3AAF1A1FBF769682 -:1047F0007CCCDFCD83F40A7FDF7DB6F8F5B78D5B27 -:104800000F98F29DE3D6CC8F35CF0DBF41759E49F1 -:104810009F4726CBE25C620F7A2C9E9F3BAAA7A7FC -:10482000457A3917E524FB29E61E59FD7BD659E563 -:10483000621E27D94F8551BAE8A82EEEF55EDA94AC -:10484000DA678EC4E685522CED3C5E4AED3E7EBEB4 -:104850009ECE2F90CCB27859AE3E5E89F239C178A7 -:10486000FBEA8287092EBFAEAB3D4C71EA49964EFA -:1048700089FE9EEBDE3A95EB7BEA9AB8DC55D7C60B -:10488000FDD6D76DE2F2BEBA103FBFB7EE31AEDF54 -:104890005DD7CEF5C773C53C132D211E6752178E09 -:1048A0001FC30F659FE03C31782E8DA886F6096FF7 -:1048B0003619DA8B3ADB0CF5BEFE4D86FE7D66843A -:1048C0000CED6F950502538AE85CC363867ECEFCCF -:1048D0007643FD5CFD850BDD6F654AAAE51FC8AF19 -:1048E0008302484F4867E9B5B2CA79F31AC197FD08 -:1048F0006BBD61AA6F71D998BF75BAE433CB26B18D -:104900007E53CC3DB51D2E717EB2A1AF88A734FC7D -:104910004CD4B76489F391C3AB447EA461A0B8972B -:1049200044CFC36F7169F793F8C43D1A83F223FC37 -:10493000DDED20EDEFC139CB45FECC0D6ECECF378E -:10494000D481F67D6284F31D1960F68AFBD5159932 -:10495000FF9E920542F5385F43BE5BBD85E44C3057 -:10496000D56BF6F29F960D99298F48E2899330ED29 -:104970009ADED1F2F2491F009F3BE886CFE7E27B47 -:1049800084DA2EBEB7A97F6D17E7E3B6FC42DC637D -:10499000130FD78E5F7CC5F72A6DFDD95759C4D444 -:1049A0005BBBCFED7425C57E8FB6A52695EF5BD892 -:1049B0005A9BCBE728B6D688EF8D6510FBDDB2C8D1 -:1049C000C6E730B6D69ACD24274F2DB2305CF4F529 -:1049D000C7CFAB7FBFB94E3BD773AF76AE67AD766F -:1049E000CEEA6EED5C4FB376CE6A8D763E76159D3F -:1049F000EBB1133CC5B99EADB50B14ED3CAB7E2FAE -:104A000003C35742F8F2772A56D86B1A07F4870C7B -:104A1000196EF1DFC7665425C79DE7319EB74AF589 -:104A20000D30D49DF9C6F356C9434719CFA90E34AA -:104A30009EEFB1798CE77A2CCE4AE3F9D058FA444C -:104A4000609A566CAC27FC77FF7D477AD88FFF7E43 -:104A50005C37FD86F47340129D4349637ACDAC12F6 -:104A6000F499A17D0FE3864E2E53915EA874529E59 -:104A70005DA273902AD351F4FB37A5577A3ADFBF72 -:104A80000720AD4CFCF700F473087FD1ECA8A553C8 -:104A9000944FA71445E7BB7F8A723CB6AE973DC9D9 -:104AA00085FFADF2FF01C18CE32B00800000000008 -:104AB0001F8B080000000000000BB555CF4B1B41B9 -:104AC00014FEB2BBD144A35934B6865A481A520DCB -:104AD000A4B06D37A225D2D5869283C8163C78E85B -:104AE00021879CFAE358E86D635B904A24A9422F22 -:104AF00052C8C11E0A821EFC03621B7A8E680B52CA -:104B000029C18AE7405B7A11D23793AC899BC47A7A -:104B1000E940F2F266E6FDF8BEF7E6E50D68798158 -:104B200090A2DD137D40245A2A3848065468B930D3 -:104B3000305324E9A2FDB5AA94359114C0A9095CAB -:104B40009ABA1E2F4912D9C9163BFDD4CECEEF8D8D -:104B500031BB0126252EAF1F39000FB015B3E51666 -:104B6000FDC0C20E9DABC0EF315B0E7E96DC49A549 -:104B700032CA4D01917D69BDDE4BC02CFB49F17AF3 -:104B8000C73D0309F29F3180FC30BBF3D0CD745791 -:104B9000343BE5A33C427B4548E42F5284DC078646 -:104BA000AFAC81F6E7AFDE17258AFB6109B84CFB95 -:104BB0000BF652EC11DDDB1AEF945F28CCCFB4FD7D -:104BC000299DCF5C1121325DB71F962855D860AB67 -:104BD0005C237EA25255A755A1CF0334E894F70C6D -:104BE000D347EABAFB243029535ECF0FFC1B8591D3 -:104BF000BA5D805261FBB7B51ECF71376D8410AAC4 -:104C000088751C15B6EE36CB3F866FA360673821DA -:104C100030BED43D21E7A738BD5F96BB183EB1A892 -:104C20008B25B2478C508F13CE3DDD8D73FC7D6795 -:104C3000FC7502078683CBA22173B9650C72796C6F -:104C4000F8B83C3246B83C34142E4BC61897408A0C -:104C5000D7B3D3061E2F63C47763C1F6F1645B59E3 -:104C60006775C78484F7ACCE432AB76BBA17253F64 -:104C70000D7C115DBC190A3D6F2799FDBB27028F82 -:104C8000B91ADDF4EAE166FBD56753E7E24E1B7320 -:104C9000BBAFECEDCF5D1D486CB6F0FBB2D6C740A4 -:104CA00096E711880B58A43CBC0EC529D3FDF4B679 -:104CB00093F7754871E49C0CDF9A0B3F4C1CD43F72 -:104CC000CB696A19829CD524997AEAD46F8F42F90C -:104CD00034F45560FAE320AB677A223FA8138ED5EF -:104CE0009B9FE786C92EB5232288E6BC5E6B369E65 -:104CF00097892B202982DC027F3B5C8F6BF618F2B0 -:104D0000F0B960E5DF7ADFAC3BADB4345A7BA2B4D6 -:104D1000125D898C4675D2D66D9C07A70FFC7D77F6 -:104D200040CB33BC17C80FB8433CE7238994AB9EF4 -:104D30004FBB3A997974D7FACF9B2C3B12846FF909 -:104D40001F7DD8672F3A58BD9692423CD7228FF5E7 -:104D5000DA9C5B526F39D97B44B8751EFD716B9F2D -:104D600056F35991C83F9B4F2AF96FC1F737C67761 -:104D7000B59FF745AA6B46137CAC9FFB891B8D4200 -:104D8000F547904B116FD9A8A0E4E9FC97DAA17020 -:104D9000F796F9D0145F6DE8A36BCD73675B73551D -:104DA000E74D1041366F7E0ECDBAF32DEA6B4A9374 -:104DB0004773EE34F358AEE24C567122DCFA3DD71D -:104DC000EB355F1BEA488867FBE6EB797DD38E7F86 -:104DD0006B1FAC2475779EFE1FF0691FBE1B8C8F66 -:104DE000B3EFAF1D6F569E8EFF334FD6F3A23957E8 -:104DF0002E88F3A2F74CFD2FDBA790A6F00700004A -:104E000000000000000000001F8B080000000000F0 -:104E1000000BFB51CFC0F0030977F3A0F2BFA3F161 -:104E200057F1A3F2CBB851F99E68FC2634FDE7D1C7 -:104E3000E4591820B4233BAA38B158988381410E15 -:104E400088353950C5F3A1E6D6002DE807E215AC48 -:104E500084CD7A27C5C0F05F9681E12890AE06E246 -:104E60004B4036931C0303AF34038307104703F111 -:104E70003B190686A940FA25106F9086E8E3048A5C -:104E80009D9421CFFD6D42E4E91BC5D4C1B7955077 -:104E9000F993B51918AEE93030A8E941F8E791E483 -:104EA0009D806253B421EC70550686BDBA0C0C8708 -:104EB00095B09B1B0194DF07948FD0C36FBF831104 -:104EC0002A7FAB352AFF8B212AFFB2272ABFD61BA8 -:104ED000955FEA03A10135720CD6D80300000000EB -:104EE00000000000000000001F8B08000000000010 -:104EF000000BCD7D0B7C15E595F899C79D3BF79987 -:104F00004972031708308941A2061C204040C44959 -:104F1000081A6C8A17A44A5DAA576A2D228F2B6241 -:104F20004D5D6B26EFF0B08DE856FE6AF5C26A97CC -:104F30005AADD1D296B6DA26802EB61422A5D6B6B0 -:104F4000ECBF415D6D5965A35BD4B5B4EC77CE374A -:104F500093CC5C6E1EF6F1B371BBC337F33DCE77D5 -:104F6000BE73CE775EDF7715D107FA250067F08F25 -:104F70003DCF170160E6C0335A01A57239C0262122 -:104F800068848BD8F34FD2F2CE30FB06567CE9947E -:104F90008176578340F59F2F6A8DF7B2EFED93BE70 -:104FA0001A8732567FBC40F59D7ACEF30690000AF0 -:104FB000004A3A56AA09D6CFA6318D2AD66FD7B75E -:104FC0002D0736DEA91205241CAF287BFBD67A807C -:104FD000AEC90097C056B538C6CA47256333641BAF -:104FE000A788C671CAFEB8085DA5407F67D8FF369E -:104FF0007D290909366ECBA4AF2E47B895AE9B40EC -:105000008F00DC3626093A7B3F0D449A9752618126 -:10501000C9CAAA6EC5AD29678FD38E7829C35E3BF6 -:10502000E24B2303EF97387861F8C8C00BC05C00EF -:105030000DA67759580E00B5CFECD7B4C7D7E223E9 -:105040001BFFECF9F3F1A7824E7800B5239E880C84 -:10505000C0B3C9D7D725317C5B45603CC6AAE4B054 -:10506000712A5DFD648ED73F4FB9C3B3FE5310CE96 -:10507000029A8720BBFACB8467965D6F169B393EF8 -:105080009D79E5CCE3E30CD7FFE588E202ACDF11C4 -:10509000B7222E7A942D0FDE83767DCDF4D61B0CAD -:1050A0003F21C4CF4CC48F15477A74E8580AEB0DE2 -:1050B000356C3E0516F449B94436268C02C8C77FC4 -:1050C000B126B2A65722BD8E32595DF67D74CC6AE8 -:1050D00090D8FB31F3D282CC9E1178487B23040810 -:1050E0004DC9196A6471BAEF9CD1DECBE8F614445D -:1050F0003A36B36793CCFA45BC1D8BA41F632035A9 -:105100005C9C7AA4979523960C8DE5342EF1E1ED05 -:10511000D2F9C66646D29B6DFA6FAF57E9D95AAF3E -:1051200041971FA0B93E4ECFFB4377FD1BF65F674B -:10513000F9353F7BCA9DB73E85E52680048E1789E9 -:10514000F1FE4156B5C7342C8389788F94F0E74B34 -:10515000881706E7571926112F3FB0F1A44317F11E -:105160006B93B13407B2E0D379864ABD7C16D08305 -:10517000ACE540D91FCFF3947DDA584F7D8042C211 -:105180001B9599A85825707914917BC0403819BE99 -:10519000B2CA055BAE48D2B4BE2E36BFF06CC5D8DD -:1051A000C99ADE2D78F96B8CC0E9A34C50E91983BC -:1051B000BE7D67102F8698DECCC60A4E2BEEEC8A99 -:1051C000E1988A3189AD63D097D6F2B2F01794CBCB -:1051D0006FF53A70177FFCF891A4EE5422CBB87F9C -:1051E000B0D7EF92D38755E47F759A98489721BC42 -:1051F00056824D1EB6EAB288F3FEF8E01E7ABD8EE6 -:10520000DBFCDC0A2AD59771BDCA07D6ABDD60EBA3 -:1052100085FC53CED7AB5DB6D491ACD7E3001EBCB2 -:1052200084FAF1D2C9F152F631E3A569EFF244965E -:1052300079B4DAEB29836194121E141DE1DCDAC023 -:10524000E9D662749B4DFE0E860729E7583C5976D5 -:1052500036DEAF12F8380B6C3E71F0B4C9106BD269 -:1052600061C453470DCAADAD25A28872E9E3C2936C -:1052700003D7E67EB8D21CAED28F172E29D4B53C08 -:105280001B3FB666F0E316849BD35D0DA73BF1632D -:10529000A53B07AE00F2035FE7045F67F91F629D5D -:1052A0005BFBD739C9D739FEF1ACB3B39F836A2C06 -:1052B000C7755BA5313E6470DC2C59CAF5B8BF8652 -:1052C0000478CC607480F08F617A66B8F1655D0710 -:1052D000B84F08707D435A919374C1BB4A663ACB6C -:1052E000747CBFF5DCE410F380B4AFAFD78193F1E9 -:1052F0006FDDB186B6FD2E38BF24446204E76C989A -:105300008D70BE1B5E9AD30583F777A25E6D907D8C -:1053100000EFD75B6DFB7D677FBF59825436FDF28E -:10532000415B2E80DAA9D0FCEF643C380DF1706E41 -:105330003544D97A841B47E13C20CC3ECE61FDEC5C -:105340000A34C82EFC0E369F7EBC3AED98BAE3CFE5 -:105350003BBBFD60ED3E14928F080CBF2D31B11A9E -:10536000E1524B208D6BE0DFB5A46B2C0C0E6F4B24 -:10537000EC6F03EFA0EB66D77B37DCD80AAC5D930C -:10538000CF38A0333A692E108D461880C3A1176715 -:105390005D1C3C8E745D7EDB4F5F5B2F05D233411D -:1053A00097A6FDF5747500E9EA82BF3F5DBDF18FF8 -:1053B0004B572784827F5CBA52EA24FD75666714D6 -:1053C000C9269793DA4A8BD61FC7667249EA98D6E0 -:1053D00085F212E2CC3EE3C380C8CA8A6672BD176A -:1053E0000C40FD552DF1CA495FA1574EC6979B5DF4 -:1053F0004EBF9B751C57A171D13CC271E53074053D -:10540000A25856A81F24E733E7303CC18335C5BCFA -:105410009D81ED069B8F8CEDD878A87E9C29C27665 -:10542000FF9493C862F70ECCDF3B4E7C59222711C4 -:1054300019797D08CBFA1B2EBC0FDE4E86371CBCBB -:1054400030FA2F453F49C100FECD5DB790FF2200E5 -:10545000A241765D61AB855FDBF0FFCDC17D9FF33F -:10546000755BE1740DF52D60FB0DBEB7842F0096C2 -:105470003F1474E25B673C299C00A21BBBDE70EB0F -:105480007F3BF25316FE5E21727DE3FDBB52FF8D22 -:10549000F6A0B559D01F63783D54FF01BCC6F87221 -:1054A00065D7790AFA3DAE134751BD95F38A940545 -:1054B000AE7E5602B70B017AE52511F7B80D5C0FE9 -:1054C000ED94F6E2BC5FAD90D2B8FFBD5AF13FA4B7 -:1054D0009FBF6A4A6944F2ABED57E60C25770ED5BB -:1054E000737BD6A977C894687F3F24F786B3E9F128 -:1054F00003E3A769FC2B2A24EF3E2DF7CAB8FEEF81 -:105500007F097CA83F1FAA5785D72631E317E7C933 -:10551000E868654591827E87E1E6B5C8F68339F88B -:1055200075E6D91C16699ECDE12AF25B356BEF92C8 -:10553000FD788ABD47793018BC8EDFAA595B9A1571 -:105540001F4A84EB5B8A2F99DDDEB4E7EB9433FDD1 -:10555000590E7CAD616E17B586395CAD31318DFC6D -:10556000DF1ACF3EAEF36CB2E173EA35C7B85EDA4C -:10557000CCE4C948E091C35E7818DA8EA0BF64BC61 -:105580002D6BF26B7B1A3E8F7676326C4A06BEE943 -:105590001126B0F2B8B8049B35366E4D557B356395 -:1055A00081BC1589171918301A3A2AD10F38F14BD6 -:1055B0001BBBBFC6E6356E8E5FC3767935A9EEE7B5 -:1055C00058BBB14CCC49ACDDE8636BD7A29CFD174E -:1055D000B41351105B3736A01FAB1987980BF0B08E -:1055E000B8A212FD6C3270B9C0A49E2E8F42FF0C7F -:1055F00090736630F9C0FE8433FE817683E12D62BC -:10560000CB2B9A37C9ABA543CBAB8DBC7F8BFD872A -:10561000F266DCC078D47ECC2AC583C7D119DFF707 -:10562000DB74E987257FD771C6C2D200EA2791656E -:10563000A296C6FAD0998B7EA8516B64E8C2EFE5BA -:105640001D0D4C7C0C8B7726F76AB8DF38292C713E -:10565000C1FB2B91FB9926DC715410D0EF6B309578 -:105660007E1A96EBA665A3D36D367DF6976B560A28 -:10567000491A2FB16812CAB55A91ECDE7F59363DEE -:10568000D7DDFE037B9C81F5075D9E8565BEFEF23E -:1056900032D10C4CFDCBD75FFE88EB9FBF51F1ECB4 -:1056A000A71F755D64B43D0A865FFFBF761C67DD8A -:1056B000CEE60F2E1F27DC511D40F9775F6268B9D7 -:1056C00072F6BA2DA5751BB50CCC7416B9129004E0 -:1056D000CFBEEA3C554881C1D6593A2A917C9346BF -:1056E000CF5ABE03061F578A2919F69BDD9F65EE28 -:1056F0002B61EBFF4970FE7A649443B52887502EE6 -:1057000095FB5E77FB4718C607CA0CF76F7F71DF02 -:105710007E9447169347E83FCDFC5E8B65173D5C52 -:105720002AF1FD77EF777E79AEC0C6396CF8753F08 -:105730007B7550E87983FCBE9512EDC7089F3A0B44 -:10574000DB032927874DC9AC66F57BCA05DA47FD1F -:10575000F0D2B5FF4CED4314EFE899F7DA972F62DA -:10576000ED3F79B10F39876302DBC7D93F51AF39BC -:10577000DDFBE58B58FD8317E70FA96FD5E27C5D54 -:105780007472C5B3DEF20AA43784FF3FDEAC7D90AD -:105790008D771872127E7C5670F80E237C48F7BD08 -:1057A000BF7E03F5C243A640FEA8C3153F8FA13DAF -:1057B0005E690AA42F2E9E27A4FD59E6B978DE2D36 -:1057C0001327B0FE1246480BB0EF072BDFD97A1132 -:1057D00083F78AEF4B77E3F3E41EA920593638BCF0 -:1057E000CEFB2B4CEFFB7EBD189216E21D341E97AC -:1057F000F0C58CB89B5EFBF518396166F3B7AD91C7 -:10580000B8FF51D00CD2EFE4B002388FC1EADF38D4 -:1058100008FDE6405F97847038FAF7E92B75B73CCE -:1058200074E050E44412C791340576A29E917B95B2 -:10583000EE9E7FBDC4E34242DC2478148DC3A3C82E -:105840008699CDDF5467C3E3F403D061B7EF83DEFD -:10585000F0007C2D81C472F45B58B9DC7FD81CF158 -:10586000FA0377DBFD3CE6F4E783AC71158046EA8A -:10587000BF6A54858AFD3755703D490783FCE3CDE7 -:10588000CC6E8421F4BAADB6BCD88CF10D3FC639CC -:10589000343BCE11E7FA53F819F2939D2A13C9AE9F -:1058A00019AC9F88E1D54742A55E3BC6D15F027A1D -:1058B0005E861FC8EBF7F18D924547EF437A1D0EC8 -:1058C000FE7E3DCFAED726A7542D2B9ED243EA7342 -:1058D0007F3FFCF1F6215FA7960DAEBF15DE1CBA27 -:1058E000CAEC5FC95752698ADB25E21E7DC09693D8 -:1058F0004ABE9AC27D01D4C1BE0779FB30FB8EF14E -:105900008C7042477F8A043C2EA4221FB8F0F38E8D -:10591000DDEE1A59B4F5F914C541053D457E3BB598 -:1059200090F18F70763BE7D96BB76FFBD3ADAF10BB -:105930007F14A8C41F82CEF827CB388D92F996C465 -:105940009EEB24F36D7CFAFE2C25B3F1C97FD9724E -:1059500045AD4DE86A31C515C91EC9842320F37EC3 -:105960006F74E0B75214A71C29FC1F8C107E671CB3 -:1059700006BF2C1710FC3E7C0E06BF64C393077A4B -:10598000838C724DE7F2156089EED64B6E90B9BCF0 -:10599000C8B3E513C02D71B7BD759DDDCF48E79342 -:1059A000278F6C3ECEB86C3E1364BE1E13E521D625 -:1059B00063BC0DC70D32DFEFD4EA841E67EB923B68 -:1059C000085DCDB3E148C9A2AD57DCF291E8EA82A7 -:1059D00011CE63DEC0BACCB6D7A562A879CCB2E747 -:1059E000D121C19CD7512F3EC7F1F72CF5ACCB6D1F -:1059F000367E3AFCCEBA6CF0ACCBCDF6BC463A9FC4 -:105A000085767FC3CDE7B681755962CF67E950F3DC -:105A100071D5BFDAAEBFDCAE4F76C76D726923DADF -:105A2000198D5262855C30301EABF71977BD779ABD -:105A30004E35D8F5AEC7F7420DDFFF58BD95EE7A6B -:105A400060451BD13FD082B602B3634A9AE756D96C -:105A5000ED5651BBDAFEFE6FB2F983DA059A854640 -:105A60002B4CF5D662BD86057F76EAADF3C27B810D -:105A700003EF0682B7BA1F8E5BDDF5E6C9E3A8BF68 -:105A8000B3E20E23F407F962C9768CF3E741A4036D -:105A9000F33C5AE5D42398076059323C86F9047EDA -:105AA00043401F5BB422F56F582FD762F635AE5BCB -:105AB00055EA292C5B22249ACA299F80F205EA64C0 -:105AC00055F31B987F61C07656D662721AEDF316B5 -:105AD0002169E1BEF83329F96599E4ABB6A201FB6F -:105AE000CFD7B99E0EBDB46F3970DD13BA96F21FD1 -:105AF00072195CE88F6AC980EBFED0846EDC6FEFB0 -:105B00002D50484F66065629CA97DBA5A081FD7522 -:105B1000177C81E0DDD6C0F31BB67DF20B04EF7D70 -:105B20000250DCF63E1FCF6FB8C7A76A8D1AF61772 -:105B30001DF339CA87C8D1FCE5361C08DF278A095E -:105B4000BE7CD02A6F10487C75A37DDB52A190BE2D -:105B5000BC2D36BD92FAAB50494FBD2F31BD81F4FB -:105B60008E8A20F9E8F3C306D9ADD1D90A58588EE8 -:105B7000190DA867466605310706F20B01930B2045 -:105B80003219D258F6414747097B46DB995D924F5F -:105B90007613DC80766F05C33BDA11967904ED92BB -:105BA00030D87FD24113E7ED1B2701FA3D9CF58DDC -:105BB00076F4B71FD2EE8AA64758AF6B64F522ED94 -:105BC000CCEE9F31827A1D23AC971E61BD2E5E6F95 -:105BD000587F87C1ED3D95FD87765B20D36E0E7BA8 -:105BE000ED615FC6F7CC785CE633331E7242F6C6D1 -:105BF00043866BEFC441869B2F3A25FAE19486AF2A -:105C0000EFE89B837D57C65E153759FB9631D7C4A5 -:105C100049AE8D59C19FE3EDF7E397DBE56BECF2FD -:105C20008AE56616F93EDAC7E57029FA4386F23B43 -:105C300000D71FDF60B09F1130796968FF49A6DE89 -:105C40009B29EF54D9AA427EDD96E07E4D3F322358 -:105C5000F26121901FD607A98E1294136046178E09 -:105C60001AE01F9FF98289FC7C688C044205AD8F85 -:105C700041FEF40C3AC9A40B7F863FE7AFA5930B16 -:105C80007DDE78ECDF8A4E94766944FCA3748CB098 -:105C90005E7A84F5BA4656CFDF2E8CAC5EC708EB31 -:105CA000A54758AF8BD76B9DA3F0FD1CBEDB689654 -:105CB00030B8E7AA9E72EBDCA0F7FB45614FB96DE7 -:105CC000A642FBBF53F6CF523DE53626E73DDF67E0 -:105CD00087A9BCA9A5AB8A6D6523E693FFFC0BF9E8 -:105CE000A4541DC62F5D2166D86D197CA5EA016CF0 -:105CF0009F2FEB80F953F931BE4FB1A799CE82DFC8 -:105D0000476CFEDF29F3FCCD6DB21E40FBF11F7D19 -:105D10009E0D3E0EAF33DFE1E075E4EF9B92AD6F79 -:105D20000D96F751CDF3326508525E6649B5596557 -:105D300032B924BFC8E36099FD5EAB249FF6B9EC8D -:105D400061594BF2F89EDDDFA20299F41299C93530 -:105D5000D47B1448D414511C51247F9F1C1E66DF31 -:105D60002874C9ADE221E0B6F358E9930E50F93B2F -:105D70003E6ED00092AF11E825633A07B59E73508E -:105D80004FD305A0F686C0FDE7F334DCF76281BF90 -:105D900075BF2BA85FC1BC07CE843E42BF722FF9EE -:105DA0003BFFE6FD0E036F00F37B2FA01042CC9D5E -:105DB000DFEB8BA7E8259C3E73469A05BC09FD25C1 -:105DC00029BE2E8B06F943616C94ECB296D806D5A9 -:105DD000BDAE7FF4157BFC268AD67A8B1065CFC2C8 -:105DE0003566EF10747E068331E81F29BCC1EC1DB7 -:105DF000623FED8F6762BC3E0B1FB42AC934EAEFE5 -:105E0000D68430B7E7E514F919DB84BCE99BCB5D98 -:105E1000F45BA874215C9172D3427BAF2D5F345048 -:105E20004F95616B8F3095B5936A8D64163D62A076 -:105E3000BD7CC23D9F98E2D5A79A86A1F79661F4F2 -:105E40001E9F6224B3F943272BDCAEF505B37FBF59 -:105E500043AC2A51669E8D37A6E673FB3617DA856A -:105E60000B39F950BE43E10BAF201E5A0A2E8D0F9D -:105E7000355FD0BC7997378AE634656838666683C3 -:105E800063A4F9205AB54174D8AF2FC5385DA39EDD -:105E9000248CC27C0FFE7777F9CE2ECC03F15DCF38 -:105EA000E3B292B90BD04FEDE84D92193C2ED27A65 -:105EB000CEE3FA5329D7874CF61FCE233A6F68BD3D -:105EC0005ACA282F51BCFA5053FD1EC0F8BC03BF5C -:105ED000E3C7CB9CD75CB1EAEAECF818993D7C1F8C -:105EE000A317988CF1281591021DF51A95BF5C1F18 -:105EF000A7F2D67A9D9ECDF5A5F4DC824DE7209FD2 -:105F0000A7DA8B18DEDAE38FC63FC7AADC87B28335 -:105F1000F6FD6B17A09EBCB9BFCCCC4006F7660C53 -:105F200078333DE256E58A0568BF6F0E80ED57581D -:105F3000B0C0F494AF6AAAC4B2ED67D8DC7A1DD5BC -:105F4000BF6F3CD8E7204CF553AE7DEF11C547FC41 -:105F50008D7B0B6F6F36617F01D92EC32D0BBC6516 -:105F600030119E80CACBFB940DD43F890036DE4FA2 -:105F7000955BF97893B81F1FCA960E8347EED70733 -:105F800045E7F2B32C8FF25914C340F72BDC976B23 -:105F9000C33DD27EE424DFEF8E66DF2F07F86698DC -:105FA0007DCD8663B8F567E8B0FD1049B070DC5F61 -:105FB000F038E2DF7BDCFB7C1F0D2F4A459F85E735 -:105FC00047E629C9EF21BD47CCCEAE22568ED67604 -:105FD00059C4BE231CF75E45B3E79D24FE77F0EC61 -:105FE000E81DFFE5F3AEA32F66521E5220CCF96FD9 -:105FF000A4F0F6A27E3573A01F78A26ACC50FA5A9C -:1060000041424425AC5F5EE4D704D118EB2FE79AF8 -:10601000799E724EC5584FFD8851ECF9EED3CEF7FC -:106020007CFF4BD7E91719F3F889AD373AE51F67BD -:10603000CE7384FD3AE5EEDE0562295B87976B251A -:10604000D2EF5EAE7DEDBE19584E4814BF3DB5BCD3 -:10605000C9878C7414CCC84CF4872525DB9F6E8EC1 -:10606000477CFE02FFC9C67B09F73D269F0EDBE792 -:106070007F989C188FE79F0E5F3C7B3CAEEB611FC7 -:10608000E76FB03A483EFDDC071E79F0735BFE18FF -:106090006DDB9BD00F7954E065A96DFB028BE28329 -:1060A0005B5B2F637ACB951C85B0B456C86A0F44EE -:1060B000FC0AE1E3432119F1B3799AD57A4B0CF349 -:1060C000DF74207DD50F09D2CBEAC0AA1451DF615D -:1060D000F447716EB9AF309BDEF1737B3FF7C39528 -:1060E000A4EF2FADCDF5A131EFAF99E6433FEA958F -:1060F00035953EB0F565CD059F9810E8FCD4B25AB1 -:10610000FF4EC4EB32D9F4658B6B5D99F07BF6A939 -:10611000690C8708FF51FBDC03405FA13BDE34CDF7 -:10612000CFED9D78C9D0F68203B7535E523BED792F -:10613000C403C3369D4701B5AFF0DA88BBDF9013C7 -:10614000178E60BF2F2FFF2CDF9F195DA05FF1C559 -:10615000E39FF7515C7659BE87FF96564B1EF813A6 -:10616000F3429EF255B557E60CA97F24FD19F2CCF7 -:10617000B2CF618A2487371F13483EE44CE84B6353 -:106180009E26BC2C01D7FF1CFFEB5CF2BF46C7F577 -:10619000E9A82FC06F43DA632EF9D96CD3E560E329 -:1061A0003FE7E77AAD9C5743F1EDF78F0B3ACE57B7 -:1061B000C8AB9B8CF39515B311C76D2E12D318F78E -:1061C000BEBD789B8AEBBDA9E4A3E981BE188FF719 -:1061D000EB96361DD97FB07669939F23C87CBFC6E6 -:1061E000CFE32D2DD652AD049771BF5689F30F140E -:1061F00042D673A68CFED7F8D16F1FB380C7D713D2 -:10620000A45797A82B290F571E3B74BC36136FB2A7 -:106210001D07CCACF7A44D8F25153BA9DFF7CF1B8D -:10622000BA5F072F1F1822F4D8FA04D65781CD87FA -:10623000E17F4B29CFC36D2E7B86F02C9995A4CF9F -:10624000FAB49489F5B694AD24BA6C6175F2D9D0DC -:10625000B9D59D744E73CB9F787CE2C9B6FD4DA82D -:106260003F6CE9BE0930AF32184F03CA8F2D536E11 -:1062700054110F5B7600F4201DCB9DE4940BD9FEE6 -:10628000F0900669664941A8CC04940B791A3F53F3 -:10629000B9375E05B86E5BCAC140D6CC4FA71A307D -:1062A000F4B325CEE3DFC152B3A608E11E23921852 -:1062B000D021D98EE5E65A99E6D1AA717CA0DD7588 -:1062C000C6C9EFC23C98126E7795A07F9FF5AF7C50 -:1062D00089CF5BDF5E427EA22DB92F9BA8EF5A9F2C -:1062E00004631270BD96F40499D111F65FA7655D41 -:1062F000F7AD62F29B7E57FC5ED67401E934133F22 -:10630000EFFBE0729C77F334117666D137F6F879BB -:10631000BC2E6D2CBDA238CB38CFF9754F9E80FEB8 -:106320008142700F567FA09E4C7E7D343C16B17921 -:1063300014D4707F29649C638D4192ECDBD160356D -:10634000203F3AE757C755277E95644F29B28CF214 -:10635000E9063BCFEAE479AEACB00532E857FF86F8 -:10636000CDF7A6033E40BC5D72FA9117305FCA5765 -:10637000E1D728BF0A3A5EC0FCCD1B983A86E59B60 -:106380008E4D5130FFE7E5B112E6C620FF44910E75 -:10639000DF0691F2CFDE8623D1192E3A7FCBDE774E -:1063A00050B2A21C69CAE5F392C3AD3D5214D75D49 -:1063B000B67A9DFC3D5298785E3B84D97B95B28F2E -:1063C0001A48FEB5F37C21273FF2731DDEFCA1CFF6 -:1063D0006FF7966F84A5A3906F6E640A5D9AF57B44 -:1063E000933BEF8B8D7FD4CFF583CF43AA15F79FD7 -:1063F000363B3F66EDF7A62848D737CDD08AF01C4C -:1064000086338F3FF8B91D7A82F1A9EEE2FFD5B14C -:1064100034E52767CEEFEDDD0BBA92ACFC9A2EA7E0 -:10642000B89DED9D679BAF6731E67B5977FB6CBDEF -:10643000C19BE7B87A57A589F9620C7B7ABEB73D54 -:10644000C1FFD976EF7C87C347E6FC1D7D70B0F9AC -:1064500028BB84ACF97E21D59B2FD5A4F278A3D993 -:10646000244360FED9E7A3ADAA149D6FB61AFD5A66 -:10647000538CE29314FFAB638483F1BD7255A77E06 -:10648000DE0F4C48039D4348CD46FDE8AFED778EC7 -:10649000CAF9F06FDDEFFC41E05DABF62AC89FEB77 -:1064A000E58E1AA178E07C40C06799E318BEFD7BB9 -:1064B00096748D034FBDF611D63B8047A04750AF71 -:1064C000461CA2BF93F6BEF5EF4FFCAB82FBF7DB99 -:1064D0008F1F5F8C72EEE61F4AA0B27A279F88401A -:1064E00017ED3B6905E5F2EADD12AD3FC85DB3AEDD -:1064F000F4E4DB37D1FC6F7E2A42FBC3EA67FCE998 -:106500005AD67EF5775F9B0A8C6F4F36F6BD300EFC -:10651000F1F7B8C0F318ACDEA957B2F7AB65B82EE7 -:106520005B1EC2F52AE7ABB7BE1F5A8EFBBBB0ABF2 -:10653000FB5AEAB7F36A9FDF257F97ABDC9E66F5CF -:106540004CFC6E7D43484F12387CD9F2F2DEFA06DD -:10655000F7A3ACDEE34B639EE2EA5D3B9424ABB76A -:106560007ED73B44DF0B9E7A328A7858BFC77B1EAA -:10657000E1E6A7FED43AB79CCE3BF5D5A2FC934EFC -:1065800053F994A9F6F13C78EE8F59471CCBEA7D7C -:10659000FBCD4B7FC3BE9F884B106022E544CF7F6D -:1065A0002A3FC472329C62A28CF5EF7BD5CD87EB7B -:1065B00077BD46E78E349129B017E179888CEF19C1 -:1065C000F5999EABA03C5CDFB9E91D9497EB77BFD2 -:1065D000FD6BA4BBF520BFEAE6E713F88F3167C770 -:1065E000B336A95E3FDD2938388B1C00BBF2B3DA25 -:1065F0008B4E3CCBE1EF9B9F3CF530EA116F3DF3B6 -:106600005F0FE3FD0C6BFEFC3F0F635E2BFC28A0CD -:10661000A1DC5AFFF82FA2E0C2FFA3B67C38F98DA7 -:106620007FFBFA030C0F277FE527AC9D7CEECD099D -:10663000784FC7C9A7FF7714EA1F1B9F5B381AE979 -:106640006CE377168C1EEA1C28D26DDAEF5EDF341D -:10665000BFDF608F809B20C0B3F633635DE0609F37 -:10666000827AEF7B02F46DCE65EF3BFFA4A0FEF2D1 -:1066700082097D88A77DBB5F7BE10E567E9BAD9333 -:106680003FCB3AB1F98F13697F63ECC39EEB765F22 -:1066900079C5C5E5F8F419D8FD7AE8A37DE3ACF532 -:1066A0003DCAD6B77C607D33BF9F82D30AE27FFDAF -:1066B000136C3DA7E2BAB2F59C7AF67ABE8DFF98CC -:1066C00073F67AEE53BDFEB853B0E69107F0E3EEF1 -:1066D000FCACF6ADB39E6BBFF3A921F572473E0C3F -:1066E00087673ADFCBE0FA8A6AFE5C45BE7DE69BAF -:1066F0005F7F20C6D7B99621E6E493A726E0618D97 -:10670000DFF9FAAE453CF43DE7D7508F5AFDDC2F58 -:1067100089EF4E7EE7253AD7C3FEA202DBEF4E4259 -:10672000FFDF1160E575022FACD5FB2EFD35EB7751 -:106730002DEBC23268FD2EFD7539AE9FDA47EB9125 -:106740005E52A3A3FC4D17D0BCD7A5397FAC4B77C5 -:106750002F437F7626DE2301279F70605DD15FBACD -:106760006EF7F14B91FE065B4F67FE1ACE7F36FB4C -:10677000FEA8977F07E5577B7D4FEE785F41FDAA26 -:10678000EB878A26323BFFA4AF4F198BFBCDD39208 -:1067900086E78D33D77D00FF8D59CF1D673E33E9E6 -:1067A000C31FC81EBF76F0341CBF0F3FBF8F86BF0C -:1067B00053F63E9C89C7B74E67DF0FCE09707B6EDC -:1067C0001D74D4A08A99B99FF920658D2B1A80B7C2 -:1067D000B5532239FFD62EEEA7C99417EB06B1CFD9 -:1067E000A639E3ECE99E8A72EDADBDDFB7E992D33D -:1067F000FDBA278E2B96BD3FA45DF85D3F88BFFB99 -:1068000022BBBFF5CF66EF6FFD13EF64EDEF846C35 -:106810005E8DF09FE8F1515ED2894E29AB9D3B29F8 -:10682000E0F3E85DAD9159AFE4B076523448795762 -:106830004D8DE62FD14F6A1DF1D97E00E377986F19 -:10684000D51409D239F7A6E88D745F92D35F730629 -:106850009EE47882EC27399628E731B0B4C78EF1F0 -:10686000318270C30DB255887AFFA1A23765ECF76B -:1068700030EA912EBBFEB00C2DF9E5782E42301A8D -:10688000208B7F23A3FFC43C0974B79FB06B8CF8A7 -:1068900007D6DE7F544A236AEB20D545E7020AA1DA -:1068A000F3B12CFD3D54AF93FD5C94B88EFC3FFEDC -:1068B00054CA447DAD70A3562CEA838F3B3EE58DD0 -:1068C0005F8F6594FF071CE7808FF441D8F5F8E3EC -:1068D0008F8FE25B0AEAE52FE093C9BF4B56E9854B -:1068E000587EC89E37E3013AC738DE4AC828E78495 -:1068F000D81219F58B85A984BCD2B59E0B63C258FA -:10690000DC4FD383DC03F5BD00DF3F1B1AAEA23C96 -:10691000F607BF24125D3F18B8AC10F96C7FEEEC9F -:1069200030FAD7BAD7CE3A3899C1392E2C019A9C71 -:10693000FBC2439FDB7CD8F62FECB4EF1F7AD4CE9A -:106940002FFFBA8DB75DF5A5F47CBCDEA0EF4FD468 -:106950005750B9B3BE869ECFD427E87DF48E60121F -:10696000E97377FD727A3F0EDE1170FDBF5B9FA465 -:10697000F2A3815C827FE29D2026D9FB85888FF07F -:10698000C0BC1D78D2B6DDFDBDC08F9B912FFAF142 -:106990009881EF4BA04750D17F1513745CF7BA80F4 -:1069A000CEF35C33F03BC1DF27605CAEEE4E9E0F52 -:1069B000F1B0E03DEF70BF2DFFBF6DF3E93BD1E4D7 -:1069C0009301D6CFBB35CB4A491F02AD0CE9E66136 -:1069D0002171D828223C7BCE9DACCE4B7E3BE0F291 -:1069E0000F4F68E776FDF6802DDF368288F4363E5D -:1069F000053AD29B33EFBD957A21CAC5BD8240EBE3 -:106A00008DF456EAA2B77EFA0DD879C9F1ECFBF8FD -:106A100000FD72FE8FCF2DBDA71AF1B241243F4871 -:106A2000137E72B5FBD0A62366B78816D2F32A91DF -:106A3000FCB9138F1D172630F874ED9B01BCB72BE2 -:106A40003E016C7F536700E9EBC155DCBFF8B563CD -:106A5000FC1CD3A98DC54B26B3FA8B197E30189533 -:106A6000B7A8C4E3B774CE2F7C4D4DE46843F8B7A4 -:106A700032F3DEEE9F78D707396C9C71C7423A9E9D -:106A800087B967E28FBA15561EDB2B903F696C38C9 -:106A90003519D7B3F2FF7F634CAF6B1D1E589B9A1D -:106AA000887A63EBC46F09C807634FFF58C07D64E1 -:106AB000A2967C33C0D6619C6C9F139653B3D12EA3 -:106AC000B8262FF17B5CB74461FAD3484FA76A36EA -:106AD000FE3BF6EFC421EBEAF4DCC92EF990799E77 -:106AE000E2A1D4D0FE4C67FE0FE1FC87A8E7CCDF23 -:106AF00059BF5335B135281733F199D96FDEA265E7 -:106B0000438EFF907D8F189BBF3FE8A2CFC254AF4A -:106B10008CED9CF683C55D33E7DBEF271A619CB6ED -:106B2000D307F948174FFF71C2B70F03924E424285 -:106B3000FFD4DE40724C7026DE1F97A232938E94F3 -:106B4000CF7E412EE7DF07467D7D0CF19D9C2EA276 -:106B5000BC8F118ED702894425EE73866864DB07EB -:106B6000A60439DDCF8314F947C5D09D43C7F90B7F -:106B7000BD71FEAD409300AB4BB5E31F206BE80F3A -:106B80003B00D3D10F991FE4FC5E2973FB72C60151 -:106B90007D87C4FD56D292880B7FB6DFCEC7BB6619 -:106BA00070DF099A8EE7BEA6750B2E7E7D3F949C02 -:106BB0008FEBA6C4B93FD2174BD279CB855258245C -:106BC0007F6E0797FF759050CFE37119C079EB1076 -:106BD0001771BF7F68233FDFAE6B2182FBA1984E08 -:106BE000E53A5B4FF9B14D47DFB7E5FEF76C7AF94F -:106BF0000ECA7DF62CE935F7E730B8BE6DCBFFA79E -:106C00006DF9FF942DFF671EED856F94933C363030 -:106C1000EFF9CBDBE28D38CD27EB4DAAB7B37E156C -:106C20003DF7E58E16F7B07A8F6E1477223F3FAAB4 -:106C30008DBE1CEFBB4A9BA221B0C60F59DB164488 -:106C400019FC3B5481E2670FD7A7A8DD0E556F549E -:106C5000319EC2AC650BC9A0AE87C21E95BFEBD3F7 -:106C60006A58BDAF75E45D8E71B87B6B646AE7F0FE -:106C7000913E73033687689E3F886C9557D0A59EDA -:106C80008376FA4691FAF94AE033EA02F61C3FFEAF -:106C9000887A998E8B71DC4CB1EF0B1892711E15AE -:106CA000BDBD16964B5E0F53BEF6AC577AE16956E2 -:106CB0002E5A15A1F278CBCB175376F75A1D0C8EAE -:106CC000F16FF1EFD579BFB73A59FD9C0D51EAAF9D -:106CD000EAF55E01E9D957EE3D7FB5DDF7AB7D11F1 -:106CE000367EEC604240BCED15B4059812627D9A88 -:106CF0009FBF197D00AAF07D3CBA88D6615BB08841 -:106D0000E8E76BCD47E237219E36C69AD1CCD9B79A -:106D100071039D4FF06FDCC8F5A014F77F8FBF6D36 -:106D2000BFF079977C286C96B3FAEDB605FD3C4E22 -:106D3000B271596232076F7F18F5BD12EEAF2C6A3F -:106D4000A9F6E43539F1910F85E4B620D94D3C4ED2 -:106D5000226B297A7FB184BA227B7DBBC8F5A4441B -:106D60004FC0ED87D16FE3F7B365C2B13328131C71 -:106D7000CD56F52A941777CF54E400C231D9BE9F7F -:106D8000C58E43F6EF63427267D0E3B7E7708D6755 -:106D9000A80C21DC5D3D9FEE64FD7C9072F63133E2 -:106DA000487AD23D22F1C7D6727E0E709FF16E17DF -:106DB000DE73E1F0538B2112FF6E9385B4C0FAD9D4 -:106DC000565E9C7B1ED24F0C776F9AAF8A782E91BD -:106DD0007D3C8703CCBDE817F7A35F9CAD77C9B1B5 -:106DE000D07191FC7FDEFCEF22CBBBFE629DF7DC15 -:106DF000DD78A6F4B8F39581114D3F9DD1FE5ABDC3 -:106E0000F73F901F968788CEC032A395A3307DD1DF -:106E1000FE936AE9FC7349C63983076CFBFD61FB8D -:106E20001C219CBE05506E3D609FBF7E608D18D4B6 -:106E3000195E9EB78ED0BE39BEAEAB9202339ADFDA -:106E4000935FEDBF536BC4FDB528E5CD13AACCC845 -:106E50000B2AF92BF3AC8F05BD76EADE134103EF65 -:106E6000C34B1F950CD467BF7CC70C927FD66AAE0C -:106E7000B7A457E53D80E75DF20530F0BDD3AF63C1 -:106E8000BFBE1BCC23BE49CF61DF73985C89742ED3 -:106E90005A85EB05395A630CCF43DF0EDFC2FE572C -:106EA000F1F5AF2C04BA5FA7300674CE993D379F39 -:106EB0008BFCBF51C498389C41398F725CED7911BD -:106EC000DFE75E2ED2FD3945CDD67938CFBD73C709 -:106ED0008E45FAD81AE6E75E9A841468086F01E7CF -:106EE000871D912ECA07BDBB468446A428864B0346 -:106EF000FB5919DC49792C08EF4CA23BD2BB304638 -:106F000081FC685D1FE4FBCE69EB3CF42B4743BD7D -:106F10009DFB583FE136C5D8C9FAD951E9BDA76EE6 -:106F20005288EF778190E0C4F70321F634B702E589 -:106F30002DB2B9107F33BEB280F6058DEC2A27BE84 -:106F40001FDDBB482C9AC29FC52EFEDD69CBD9B48C -:106F50009DB7F0B0BD7F38FAC603B6DDB0D5DE37D9 -:106F60008ACC2B1A15A4DB55300DF154B2A6535818 -:106F700099CDBE6FF7CAD54C7E9998C92F29EF39A4 -:106F8000D571AB8A3DDF23C6F99EEF148AC17567C0 -:106F9000FB37E2B92D5026A1DE370312A65BAE0CFB -:106FA000B6FFE707CDA9A18FA0FF44438914EA9F4C -:106FB00099FAF745F6BA5C1B48CCC1F588CE5D4E10 -:106FC000793C6B03898BA87F392DA03C9D87ED62AE -:106FD00059E1A5E4AF11C05BFD51E005D9A0F35C18 -:106FE000B74BCE7DB6DEF35C90717F6DE6FDB4F3FA -:106FF000FF7827DD4FDB2230450FCB39F6FDB47E1D -:107000007E3F6D4B84DB5D2D761ED53A1B0FD785F9 -:10701000F87DAF6B6C3A9D1FCA7EFF91E3F74AA1E2 -:107020006CC07AA3B3DF3B861A15F6377F5CF6EFA8 -:10703000A9108F3BCE9F38F4381B701CD6CFACA064 -:10704000B936E4F2AFCC0899EBDDE55B43767E918F -:107050009C20BDD294F97E581434378666BAF06B02 -:107060003FF31695D379BE53F6793ED66EBB407882 -:1070700095B491E0DDD1FF5B04FD1E9283BF607A81 -:107080005F96F5783F18B5C49C817894A31FED0AEC -:10709000717B92D1DB263E8F34E5418741BF07EFFC -:1070A000811887F770EBE85738F6F0BFA2BCBDB87F -:1070B000A706F5A7B53F90E87EBBB3F0B586D19D96 -:1070C0002B1FC5793FF6837164074F9492F7875C55 -:1070D000F6C7D8557D0AD23BC25FCDE1E7F9D3426E -:1070E000FA3C6E0F00C5715A6E8A7BF20933ED913E -:1070F0003CBCE780E48A427A5D265C8E3DE19433B5 -:10710000CF231CB2E908FFF451784F38706556362A -:1071100025E4AF9990A4E76CD0E9C9EC964E9C07A2 -:10712000E33F1DE16C0C4DB808E7F177C4DB8F42FB -:1071300033FFF1F0E6D07151F2927E3ACE76FFF550 -:10714000FDA128C9DBBA6311D2FBA37BBF48742D14 -:1071500031BA0EC406F265EAC0CEA30F4327EABDDA -:1071600045C97A3A177A8AD131F62B69FC1CAB0CE7 -:107170005A02E336528CF3874F2ED5440DE3B29674 -:107180001FF30EAC623050D6A23FD20D6F7938F9A2 -:10719000A61B8FB71FBB87E4EDB581E4095CCFDB8D -:1071A0004B2C3F6A762E39FC965B0E0B10D691FF66 -:1071B000E69FE6FB65655297911E16304E47BC2F41 -:1071C0008424952F038B9E8B204DCF4FE09546A4B2 -:1071D000C7D9E716BAAE16DDE716FAF3B9CB9D7C30 -:1071E0000E1EA72AB0E9106C3BF5F9E54B1B16B251 -:1071F000F1D9E29B188FFAEA729ECFE39F2DD3F963 -:10720000D582DEEB6B314E04CBB85EE6E441E4D5CB -:107210007AF5B4B3EEB73AF6FB63D82EF39C9CA391 -:10722000AF65EE5BCE33535FCB0B673F3F39D8BEC4 -:10723000931957A8C37F72FBD5B6AB1339EE7BE326 -:10724000339F87EAFB9AF7BBF2CC0FE3FD4659F771 -:10725000011EEF8DEEFD7DEDB272BA5FCEC094C916 -:107260009EFAAEF9AF4F1AB08313F3729F477F7443 -:10727000A23A77BAC4F0BE38FE5EF3FE7C80256683 -:10728000F7FCD75DF3ECD118B459F484FEF14CDF70 -:1072900087EEFDF76D85CB97167BBC881D1F6B13A2 -:1072A0002D3FF1ABED7FFB4321B7D31DFB3EDB7CD4 -:1072B0009B095FBD61A487C1E6FBD930DF4F472D35 -:1072C00037E8BEFC26FBBEFCA6F14EFE96A1A13E11 -:1072D00079633897DF57102EA1F86A53F71CF2270D -:1072E000171CF4913F7DD4B2A460B9F6C57BEBB90D -:1072F000FFF52B4CBFC37C902D4CAFC3F2DECA59B7 -:107300002ADA0BB746A653BC7673BDE1C917719E46 -:10731000781F5DD2E5DF6B4A546918EF6DAE9DAE04 -:10732000A2DD217DB29CCAF279D33BAA183F7F66C9 -:10733000EBD44B0B302E51C6EF23BB8E951B4A98D6 -:107340001D1DE6FBEC21E3F530E2A92AAC3BF4433A -:10735000EBE85B96347D2817E25A15E6CA38EFC190 -:10736000A62FF69EF4EBB795E44D6136FF43F6BDCC -:10737000586D4AAA7443199E8B670207FDC42AF709 -:1073800013221D34CF18807B838DDFB9F6B84C20D3 -:10739000894FBBD64F89F3F56B136155B6F5B933F9 -:1073A000CCF59B66CDD486A4234DFED0737F68793F -:1073B0008CE7E7C7181DB9F8F96C7AE7FC541E4E44 -:1073C00034870B502E42698AE61F26F943EDA481CB -:1073D0007B2CE361B31DEBFD2CD7CE872EE479D057 -:1073E000EC7D6B0E96E514C977471F6C93B93E3759 -:1073F000527D306FD146D207DF65AC45F6D92737CD -:1074000092DCDEE853E9FEBFBDF3648A6745CF81B5 -:10741000EBDC768B14B1EFFF8F70BF3CFE4E427AEF -:1074200032D77BF09C47340474CEA56F3CCF2F6DD0 -:10743000831D35E7107C9334F77E56399EFB19EE99 -:10744000AE0AAE72FB1BE6E4F27C91FDB995BF4734 -:107450003A280BA7AB90352FD0A017F369A08A9FCD -:107460001F130AF9391B1F182AE7D76A0DEF0D15EC -:107470002049E7CF065D3FF0DE2FFAB89C6E0C2264 -:10748000DE62DCAF13D92E50D29ED46976E1D99D4D -:10749000C6DCA53F0813BE1306F277F7AC20D97BF4 -:1074A000EF752B647FBE7713FC06FD49EFF972C0C0 -:1074B000624BF52351FCCD536CBE7D8C597762FE37 -:1074C00097C6BF4FDB2A90BFE9471F06C721BD1BE8 -:1074D0005110F1F72C16337D8227094208E3B3D10E -:1074E00005D07509B6EF0E13FE7CF19FCE7F7D06A9 -:1074F000ED3F21B102CF6B890FE2FC9F89431EB69D -:107500009FF1BF5512FAAF1C7DE81E2D7904E19D55 -:107510000DD6AA6ED6FE6E85F3D7DD794A1AE394AE -:10752000D30B44D243C0174A4F62DF171F78BD1AEE -:10753000F33B17574CC39A383EADF7442D790CE90D -:10754000AF5A5B529DCBEA971FD549FE5E1ABF65C5 -:107550003F96671DE3659F9FEBF1A8C7B8CF072C47 -:10756000FE6002CDEBCD30D7679BE3668F290CC957 -:107570005719F7F27ACF173874C0B6751DF3D2E9F0 -:10758000DF3AD145D2270EF89FA0C2B0CF9F38F482 -:10759000600A1F851E7687F9BED086F966B1817CA8 -:1075A000B3365B7F1B69BE59263FE52D92691DDE10 -:1075B00065FA16DEE771369FDC42F77F66F29303C9 -:1075C000E7E6F2BC18CA61876FB4D977925CF65FC0 -:1075D000AFD07DA60E1F39FC332BA79F8FBE82F242 -:1075E0006259585FC853344C70F3C995C3F0D562E3 -:1075F000E8DB1F63E5C53258394C041D9AF3BB9292 -:10760000092E3EC9C4E7E27902BCEA9183BCECC210 -:10761000B7D67F0F70163B79B0753922F3730F0E12 -:107620009FE2EFB1E0F9B176D100DC8F1A73571AFF -:1076300011364FB936770DF2C3162191427E88CCB0 -:107640007E2B7423C3FB7BA3981689FE437DE553F1 -:10765000C4EFAF84C82EBB7BD66A8A4BBD7753720A -:1076600022EE2F9B18DE5FA5FD3C3D5AA45CDBDEBD -:10767000D13C6F428FF36732CEDF83FD3D6D974D76 -:10768000BB5E2FD563EBEB919B07A29C0F0E44F9D9 -:107690003EB549E950911EFA8A54CD9DAF7C897D53 -:1076A000BFF0CD113BAE78BA49C7F8C4CD11DEEEBC -:1076B000DEFA4ED25736D5EFA1677E6D1A303F2ED7 -:1076C000586AE9A857A87F5E20E03E0BE7F3783BB5 -:1076D000BE6F70E96B9FB2E5B68AF700B179AB8DEA -:1076E00096EEBE77561585ACF703FD24CAFDBF6A3A -:1076F00023D07775EFFFA3BC84FC1243F81C961BC4 -:107700003BE87763025DFC7DACC4146E70F51BAB87 -:10771000EDF4EC8FAAD82B933D54079A85C69DDCD7 -:107720005B8D7EB7F6A5C10ECC57CEA423FC7BD5CE -:10773000450FEA9FAF24BD088E70BDB4BA5825FA34 -:107740006DA95376A05FEF0FB12ACA536FB2F196BD -:10775000391F8CAB334D8FFC64969FC7D7ADC93CA6 -:10776000BE8E658CAFE313E3EBF8C4F83A7EC7F83E -:107770003A96BF556F5219E3EC58C6383B9631BE66 -:107780008E658CABE3734FFD2A7AFEA03E45DF9FEA -:10779000ADAFA3F225B6DC8452FE3B5FED5F544CE7 -:1077A000CC8BFAA1BD3EFBCCA5AB7E8E7E40881A69 -:1077B000B85F070E36BEF213BB4CF75FC78BF3D131 -:1077C0002F093111309ED01ADFC674CC81F905E43F -:1077D0007B41A778BAB50AF31977460E5D2A33FDC7 -:1077E000A1247E4B551E2BEF8A1C6DC5FCD173F571 -:1077F00086E53B5C653D327DF5D3DA407962D90E92 -:1078000039C8BE3F79F7CBAD28070231AEF77D2FDF -:10781000F2AB4B1B1849741533C506E558919246D7 -:107820003ABE01D76912CE83EB2D9F80A638E6EFD2 -:107830004DD495E9C87FAC7E17A7FB91D5FF2106F3 -:1078400061669EDD6EA87A62F988EAD1F9DBC1EA49 -:10785000E17761887E5AA049EB61B06FF1F1FDD507 -:107860002AE0FEDF761FE7FBF6007F4EC8E1F4F763 -:107870004EB4EAAE287BDE15E5EBDB1EE0F70EF436 -:107880004D11E9F778A04EF827ECE70B6341C3BC34 -:10789000C7E9538AF351FF3F62D3C3A48911BE6F76 -:1078A000FFB34AFBF665139F6CCE63E549FF6A1888 -:1078B000B80F6F012388F7B65A5B45CA23FA66F9F9 -:1078C00039794B58F50B667E270FF5DEE9B6DC49B2 -:1078D000DBF64943CB8D13D13E78EF252EF78EDBB7 -:1078E000E3ECF0F5A4683D6786E91C054007E9254F -:1078F0000D7199F2BFC431FCA9F8B46BE85ECC16E7 -:1079000085EE6152FE345B257FEA077EFB1EE21E98 -:10791000D257944052CB65EF3B2C91FC0F4D5A301F -:107920008DF7616D094FA7DF65B0CA648A876D293D -:10793000E3719D50E42ABAEFEA2BDD01AADF12566B -:10794000290F385DB6FB40550C9FA286FB7EDA5CA2 -:107950004AF7535A9AA8513E31FB177D5F13233FD4 -:107960000F9D2BC6EF6B781CC237FA20959B3EA566 -:1079700051FF60E7ED93EA25E2EF4424BABDF7CD6D -:10798000F6FDF442F483ACE6E752A66A4BBB9F6374 -:10799000DF9B4D3551CCF8A1457B776F08CB2B8011 -:1079A000E2A4A129AF3786B0FE0D9AC1F3B0F83931 -:1079B00008B0EF376E2E5BD6FD1FD8FFF2104C32A9 -:1079C000B07EB58AFC0ACDF002DE475568EB33A1E4 -:1079D000DCE902EA632DB574ED2683CF7B7EA03906 -:1079E000EF7215E9465A9C47E3B480A9627DAB5615 -:1079F000A67DB130AC76A1DFA0D0F63B38F2203FB7 -:107A0000E53A47C0FE37768DEC396730FA066FB934 -:107A100020E37EDD0B6DFAC9C45BE63CF363CFE483 -:107A2000223CF96BE844C459F0DF1B9BBE04E735E8 -:107A300046DB2BEC28279346D3F17E714835B8F30B -:107A400030FE5A78A79635F7203D4CD565D0195EA3 -:107A50002E84BE46EC7F8B4DFFED45DEFDF9886D33 -:107A6000D7303EFD7C7426C63344B05CFD63BCC396 -:107A700072C1734E7B9EA73CA963ACA7FEE4EDC523 -:107A80009EEFE7A5CFF77CBF60D7744F794AE75CDC -:107A90004FFD0BF75479CAD3BA2EF7D49F7160A962 -:107AA000A73CB3E71A4FFDD9AFACF47C9FD3BBDA48 -:107AB000F3FDA2DF6DF0942FEEBBC353DFD1EB33A8 -:107AC000F7CDEBA37F993E8FBFFBE33E4F9C692F21 -:107AD0009C756FCE9F9B748CFF4194DF932BE3FECC -:107AE000CECA1BBEC8ED2E75BEA1A3BCB9DAA6CB0B -:107AF000D579E63A94AF955195F60939CCEBC9E1C1 -:107B00004B491F99B09DC9A919648FF57FC7387477 -:107B10007BBD35BFC4E5AF0A681D80F95F95D11AFA -:107B2000BA2FD0692F6B26605EDCD5519DDF73C301 -:107B3000AC59BA074067ED5DF362F61F5D1DD1C712 -:107B4000EC43D4EBFBED3F3987E2BECCFE23FBD008 -:107B500008727B104E4BF4DDF88A40F7F333FB8E4E -:107B6000ECC367C2CC3E9C86F658EF1694437D3F2B -:107B700093298EC8FEC8FE2B67F6DFE65CB71FBCF4 -:107B8000B7089F69D0C6E2B35BE9124717913D7809 -:107B90001FD2F36736BEB40AFB9D52CEEFD56B1FE2 -:107BA000551B473DB9BDA893F8A4AF48E6FB909C90 -:107BB0002875FBF77E6CAF7748FD26D9A16C1D4870 -:107BC0002E3BEBB045E84DE3FD85D61783E4EF9EF1 -:107BD000F05BFF11E437B5581D87F97FC63EC5C479 -:107BE000F1EEB5F15CAC4DABC29F792C892FD98BEE -:107BF000CF7375A68FB06769E93D7BF1F974949FE7 -:107C00005F3DDF78BA0A658C3A9FFBADE5A94ABAB9 -:107C100051407F3383238BDDD1EF9F886EE7F7FDE3 -:107C200094C86F20FDA1D67F864DA1324FA5B871B3 -:107C300000E942A027D153400ED1FE12C043A858FC -:107C4000AE10D218EA42FD15F3412BF3B6131D38DE -:107C50007A2DEABB496E1FFF18F11AABF5AE7F48CB -:107C6000FD16E1A9D93EEFDC9EAB1FAC62E3B6176F -:107C700014E7A1CF16FD294B5CF2679FBDEF3E9242 -:107C8000237AE4CF6CCC519839A017317ED82E9E40 -:107C900083F02628BE1E3828913D1FB8B3837E5F2F -:107CA00035A0593A90FE6FE9D86F75F172F2FFFD79 -:107CB0004F6C3AE9C181BA1F65C55BA0570273C614 -:107CC000E0F88C9EFB00E903302AA8E33E5B170B2B -:107CD0009A3BB2D8079F8D70FFD9A6098E3F3341DA -:107CE000E75D5BD0DF16C6AD4D15314FE7D69F156A -:107CF000EC74DF07716B01F74F0E367E80D999491E -:107D0000177C9B58BF28C75B4E2FA9A1FB54719BC2 -:107D100029C7F3A0653BC84F6FDB4B9FB5F17A7362 -:107D200084E37182020B76A03CC963FA114369A512 -:107D3000ED5771FC2FF11C1ED7372C90B85FCEE7A2 -:107D4000EC5BE219BC8746075D99651FF127159822 -:107D5000EF6BECFFBAF15CE039EDAE7D0E703FF0F9 -:107D600096276FF796CF4B7BCB4C8B7E19F58065B2 -:107D700000DCAFB1CBFB3D0CA60FE328639DFBF30A -:107D800013FC9CA0CA2040FA2EEB4C777F8DCD2FA0 -:107D9000E1DC7399715FFE94DD69D25FAEB07FCF95 -:107DA00023F31EF7B1F8FB1E53695E9E7D74BA4F34 -:107DB000227F03FA890C979F68A2A67BEC2AC7DF73 -:107DC0009329D783C7EE01F685ECF5A41FEF43D5C1 -:107DD000CAD0AFD05A78D76F8F970FF8575AE5D4DB -:107DE0009BC7C97FC9F4AF18F77FA05FFAD69FDDA4 -:107DF000F6DFC75D7ECA77A2C9A9E8CFB87F226F38 -:107E0000EFDC97EA9CE77BB7467E5ED0391C4917CA -:107E10001CB7975A977175253D06FD438E7FC5F1B6 -:107E2000235C9367DE857CB7C53892DAC7FAADFA72 -:107E3000951FB09F85D2C103F528EFC6CB942FA222 -:107E4000CD5EF34810FD99F89D95AB8AF4D1C41F1F -:107E50002FFAC89FD066F3BD732ED5F1C77CC2B68A -:107E6000032ECB71F4282B689FC708A29E7CC12EDD -:107E7000B6869EFD90FB031DBFDF944EEFF7F3F136 -:107E80008837F93D77507E933187E7378D5A9EDEEC -:107E90008BEB7CA1BDCE18B7AA9C35103F1DBD222F -:107EA000BD17F5D0A9769E52D98BCFD34FF9825406 -:107EB00028217D9D8FF949AC9DB15FF69C0719057E -:107EC00002E5F98C3A2A1969D6CFD467BDDFCBC059 -:107ED000552E42F8BCE5CCB81453B7DEB95EC0DF0E -:107EE000454D0928CFB6AE6036022BAFCAB1F38B31 -:107EF000CE8573916E174A6103EFCDDBF00B89F2EB -:107F00008BFDC727FF12E3A3F012CFA7D4CEE1F178 -:107F100056EDA792C12420682198362D3C10C7FA4F -:107F2000EA1903EFD0EFF78F3DCED61DF7A12798C2 -:107F3000DD5FE2433B5EA37227B3FBB1FC0CB3FBF6 -:107F4000F1B99BD9FDF8FEBBCCEEC7F21E66F7E394 -:107F5000F307CCEEC7F7CF32BB1FCBFB732BC91F88 -:107F6000DF83F7194DC6DFB5DD4DF98C6DAA4F43A0 -:107F7000FAC994679595B7AACB187E378717521C14 -:107F8000A56A21CFA76FCD5948F674BF9F2EC3CFE6 -:107F900039E0B7EB151CBF1D1E6D8EDBF66CBFFF05 -:107FA0003369D0BD05C3F7633AFD90FFF4AC7E6C36 -:107FB0003FEADB5FFCF5D79BD8A7B533B7B5078B96 -:107FC000F13C4F8A7FB7F30A337F4F6BEDEE06CA61 -:107FD000F353C61C4DE1BAEE2E0F93BE81BFB7849A -:107FE000723BD34E74ECC34C7DDC7966EE87997995 -:107FF00030115B2F192E2FE36E5F8AE2D656039362 -:108000002FB85FD4A7E7BFEE3BDB6F3B56CBCB3837 -:108010007FCCF3AEFC07783E5E3B2435F7FC9D73C6 -:108020000F64F31573FFA1DB6F1B2C49D3BD0CC18B -:10803000B049FAA2C0F448D22BB524C5015B07F9B8 -:10804000DDEC376D39D130E62ADAEF5B5FF491BEB3 -:10805000556DE7BF358D51A9DC3466569CF2262359 -:10806000B3D4DE2CFD6C88140FB9BF4A6CFFD787E0 -:10807000D8FF253F3FEFD5B4778E8AE7A2DAC32B2E -:108080007BD06E6F8FC7C8FFDF3D6696E7DE712934 -:108090005E41F7544861AE674B7195F46C19E75F28 -:1080A0003650DFA9B72F87EF238CCDC98F190877FA -:1080B000503DBF9C30D1DFE28FF1FC62BFC6E3854B -:1080C000C11211D42CE7309ECDE1E7ACDACB921A85 -:1080D000FA75DAE3329DE768D7A70F166F25BDE87A -:1080E0008F3982877E9B6CBF43D32A85F4C2445D5F -:1080F000AE569D4FE711FA90CFDBC38D2AC65F9530 -:1081000031E543F6AB68BCDFFF03837E3D1F008093 -:10811000000000001F8B080000000000000BCD7D58 -:108120000D6014D5B5F09D9DD99F24BBC924BB9B80 -:10813000ECE68F09241A34E026243168C449083C4F -:10814000F4212E021A5A2A1B1045050968EB6AB55C -:10815000D9908010A4067F2A4F2CDD58B0F6ABD6FC -:1081600068E92BAF455E50E4F9839AAA55B0A8019F -:10817000ACD53EB511A4A5EAFBF8CE397726D9993E -:10818000CC26417DEF7BD832DC99FB73EEB9E7FF5B -:108190009E7BF7D429F87321636D7B52545609CF27 -:1081A000A58E784A1163E1687976C324C6BE951519 -:1081B000FE22C3CF98C3B3488EB919B333A676C392 -:1081C000F394D64E7F7A658131A827CABF98F29E74 -:1081D00077E877FD29A66F661168CF8AA5F7FB5C63 -:1081E0008CD914269CB24199B9E5F7CF66F4E7948F -:1081F000887FF706C29EE4FD785CBF9CF2DEA4A1F6 -:10820000ED9697F5394485B1F5DB3AC30CCA9F0B5F -:1082100050A842B8636A1ECCEB869D2B59A48CB142 -:108220008D52AF4B0638367E292C0C970DED7F31E1 -:10823000CEA70A7B95620827FCB19D3A07FE5698A7 -:10824000E2A8662C0FDF8CC527FF0EA3EC3905FDD5 -:1082500097F740B9548307FE3FE93963B9AAD75865 -:108260003EF780B1CC58C81E9EC0D8EB2DD0E999FE -:108270008CCD39F4E12196CED8DC58E8D9A77C8C96 -:10828000E5AAAE705C666C1E0B3DFB3694F31AD308 -:10829000584F0806B7B1A5B82E30CD378B01BE4672 -:1082A00046B0B2BCA5A98CB906FB9F2F67D23A3560 -:1082B000F635CD641319FBE1AD6D8C413FB17A21E8 -:1082C000BE1DE09FDDB06DF638783E50692B781802 -:1082D0001B45ECEFE1FC5CD0D929986FA66DE598C1 -:1082E000B1503F3C354D68837A3F3CEFACF5C5500B -:1082F000EE9D5E1242BC03BEDE1B980FE07F5E98CF -:10830000B7D7C77FA5F2D8DC71F0DC52F9E46C7CFA -:10831000CE49AC0FFDCDAAE96A75407F972E532A4E -:10832000B0BF7083B17D5EADB10C90F3F9C0BFBC3E -:108330005943E11D091EF3F87A7F0FB428847FF6B4 -:1083400025D003E0338C9FA07D58EA974280E7DC7C -:108350005A418D03DDE4A982DA65C10F1D1A3F98E9 -:10836000F12FC63218F259FD3C31DE0155725D76AF -:10837000C27FEE4C21AEC0F8B94BFB7B4E41F97287 -:10838000973D2EC2F7ACCC6E01BF3FB08CB1CE2270 -:10839000022FBD2E617D1F70ADB117C2F7794191DB -:1083A000D9800E58ED381A8FE0184BF838C2F1E139 -:1083B000227CE42D0B3DFB6318FF8A1AA72C42FD9B -:1083C0002B1AF9771DBE8D12D0197CDF0874162385 -:1083D0003A938E24E267CEA1E5CB911EE798DE1793 -:1083E000435D9CEFC7930F9C5108702D173A67A40B -:1083F000012829F666C670A1018348D73A3FEA787A -:108400005ABEA395F83181CFECA7909FF1DFD984B4 -:108410001AE2B3A75DBF92516EECCEECDBC2808452 -:10842000B7CA2CD690CFD8BFA7F69F2D4079BB7C7A -:10843000F9BA7517C0F794FE5FB072C69CCE6FCFC5 -:108440009891504E4DBD86CA3E6D1C98428CAFF738 -:10845000C0B8441FFF2973F836A86C930865C92675 -:108460006F0A150DB6CBC276C230EDC26C9364D1E3 -:10847000CEADB7033CAD85F54BD5E695AA7DB76982 -:10848000F0248E2F21DE64C52DC07A48D32519E94A -:10849000E5EBC2913DD2BC236C937DDCD0760076B7 -:1084A000AB0EBFCD1AFE387E4F1CDF3E0CFCDF3416 -:1084B0003E46EACFA17D3F6DF8A0FAEAECE4F34531 -:1084C000B8ECA8AF14C56D4BE8E7AE3DFF78F11CE2 -:1084D000205E693E0BA5401F925D954340E765F223 -:1084E000BD2EEC5CCA6C9023C00FEBA1ACC2FBF5B7 -:1084F000DD9D2E05DE9715DFBD0E89BEAC2795A14B -:108500003C98C0E4CC47A1DF09B2C47A70D52ED81C -:108510006B4B8332BB84854AA0DF8C3DA9244F324C -:108520008BCEFBA900E36666BA546C9F9659FD5347 -:1085300046F4C11429011F6975AFD7A7215CB3594F -:1085400008595112E2AC0E996C3CF0109433A76DAF -:10855000630D50AEF8D8A388C8D312D7771DD81EA4 -:10856000F5743BDB87FA25A8C99F750E7913E98F4F -:10857000EB2486FA236DC2BD02C2F3007425025FAC -:10858000969565CD6E8072D97E5B4851703E9D4256 -:1085900021CE272092DED2F1A9CB918A4F7B38D30E -:1085A0008F67F1ED007FBB3DDE83F22A36F90A7951 -:1085B0003BC0937B5582BCC6BFFA010708EF4B97BF -:1085C0006DEF2842FA96DE4BEC2FE3D3780FCA33D7 -:1085D00056D718C6F6BE999241FEA76AF22CD5A4CA -:1085E000075AB2EC24CF747DC054499161DE8236C3 -:1085F0006FF68330E903270BB91C64AF2C203B4492 -:10860000607DC2A934983F5644B80BF83C86B4AF9D -:10861000E6ED5920E4423BC799DADC8CF5E163567C -:108620002B2057B82E5545FD2C38982B5801F3B602 -:10863000B14837D049ABC0242C0F8ED7C3703CA7AC -:108640002BAD1DEDAEA75D6D36C45FDB73A03F6043 -:108650001E77D85923DA056D72C89505EDA39AFDEA -:10866000B6AA7C6C0E963380B67BD16E90C232D2A5 -:10867000E52A7F710E83F7E9DEBE6FA39CFDA7CCD0 -:108680005FCF7015801CAD873AE781DCDFF4F8BA64 -:10869000582D8C77328F2909769E536A66684F3938 -:1086A0004F161ADEF7B4C08CCE1C2CAB6E5B038E5B -:1086B000735DA64278AD63723BB6AB03642809EBE9 -:1086C000E23C1964CA24ABFEF30DEF7BC04E529C12 -:1086D000A3E93F8D29A589FD8F4BD2FF19A6FE6521 -:1086E000CBFE07FBF51AFA5D2331B2A3633E37AD2B -:1086F000BBD92E589D59BF2213ED51276BEEB6B052 -:108700003B5B336D04F71D81E65E15DAD733607C81 -:10871000A0930BBF3C2232B26760A5805E58BED4E6 -:108720003F40C763B11EA75F5B4C6028972E94EC57 -:10873000063E99C28C65B35D54026B8DE3DA3C95BD -:10874000BD483FABFCA98AD3027EFDD9DBC2A6148B -:1087500097C07C53C34B19F0F10399FB5C6B02503B -:108760004EE774F248E61F67A0BFD02B70FA5BE3B8 -:10877000B3115EC2F5395D6242BF61072B41B91882 -:1087800046FA76737870FC5E7FFE431D16E383D84D -:1087900035D80FB355614A71C2BC7A353B7860BC9D -:1087A000A9795DC80703E33959158D2702FE13C760 -:1087B000CBFE6AE3FD1EE7573638DEECE9C6F9CD9D -:1087C00076C834BFD91AFFEAE3FD1EE757F415C691 -:1087D000C3F9258EF74FC6F9CD76CA34BFD922A783 -:1087E000AF81F1B2BFDA78BD2DA56407DFE100F9F2 -:1087F0000474925ABEC3350EC6BDC365970565B0F5 -:108800005D5DDD8DAEB9A87BDD53A7FB619CFA6988 -:108810005039177B993ABDAE98B14D02A78BFFDC5A -:10882000F4E7754817C767AE2A257DA2D9D79762A6 -:1088300055D0C7974A1CDE59F9EE786B021E1F000F -:1088400039A2021C0F02BFABC08F5B812FB11C6F1E -:1088500009D0F321B0D7F1B90DE0C5EF0FB784A867 -:10886000FC484B0D3DF57E4A6BB8DD3EBED6DA6E58 -:108870003F238BFB7D9B82F2FCAB50AFD5A586508E -:108880002FB29AF3999A6857B3E6A753E0FBC6CB89 -:108890005939EAC6333673B87D0DD964B7A796EF58 -:1088A000ED6D81F21D925D41BD7C87C26658F9CDA8 -:1088B00045A867AAD05EE5EDD9F9DC0FF385FBF694 -:1088C000A2DE9B83763AE0D53FB76F2FFA7F978180 -:1088D0005D4E7A991DDEFB367C7F1DFCBF0E2C8B16 -:1088E0006E264379D61C3F8D0F7FD2EBB2D17EE747 -:1088F0007FEE99798CFC8A700AD70B3E36FBD93D06 -:10890000086FC8A1C4A93F765F18F940B52B1D2494 -:108910000AC276D4D37ED4D3F0BDEEB093D910BEC4 -:10892000690E926B73E71AFD864D293D32DA3F9B43 -:10893000CA7DAC15FABF6CA6F1BBD3C9F92D6CF298 -:108940001B6699CA2021B9DF2D2EC8407BFF0E7C03 -:10895000357928DEA2875AEFD89B40A779591E1F88 -:10896000C501CE6067A03C3BC1CAEE6AC08FF95911 -:1089700064AC98DBFFBD2576C75E40FD2B28F7AAC7 -:1089800090BEB9DC18CA1F1C9EC95ABD075A7AA7E7 -:10899000BC5732085FAE1417500FE42D85F709F36A -:1089A000957C7101FD1D263E5A8EFE8D791E0F08A5 -:1089B0008F0699C578FA339749EF235E7029519E47 -:1089C0009BE73B79C87C6B5F296656FCA46C427BB5 -:1089D0006ED67362A85519C4873EFFFF69BE3AAAD6 -:1089E000E919A6FA580FD0CB2B40EF1DDC8F616838 -:1089F000A7EAF40A15C87EBAF452F88E74A1AA0543 -:108A000088CF57C6F66FBB1ADB81EC68437F57B738 -:108A1000837A0EDAD00EFAAAFD5E7A9D83EC2DC61B -:108A20001AE4F74B07FB4BB63ED8EFFB09FA73C0CD -:108A30004EC43FD59AE843185B4301B2076E01FB71 -:108A400018FDFD68C387523AFF7E24C14EC53F47DB -:108A500012FA6BDBF3734101B8BA5ABAA7BC674F7D -:108A600090174B65DB1AB4E75AE302C5217AA01EC2 -:108A7000D80363972AB676C0FF55D80FD2A749AE60 -:108A80008F6D877E12ED94DAB9F2A3400FED65F594 -:108A90009D2178AEDFCCE3657AFD81B8992F46FE43 -:108AA000B99D353301E074A4FCE0277D301FB54D3E -:108AB000622953A06CE7F60E7BDB4372417437FFEB -:108AC0000CBF076220B770DEF5CD8F63396663E1B6 -:108AD0003678DE9FC6DB472597EC0C619CA47D06AB -:108AE0004E3F3318B92F0BF0B7263B95E4A0E31D9A -:108AF000CF4328A71C99154BD1EE5910FD7E18E3E2 -:108B000091B2972D0C5BD0D702CD7E8867F1B8CBA0 -:108B1000217B4F4126C05D17AC8F63BF43EA477F7F -:108B200040FD4D11ADEDB09D5A3F5B6CD672E10931 -:108B3000EDFB15CB9FFCF061984F5AB13B84E4B636 -:108B4000FE1CB643B00DADBFCB1FE94E8423A55824 -:108B500096280ECABA27A33DB7FE8B07BB1F079402 -:108B6000677DE126399B257AE24291A1FDCEACAA30 -:108B7000A1ED77FFE38D00AECFEE1446FA95B11765 -:108B80002F427F72E34099C5048C73666AE5D8234F -:108B900017A986F2E28BEAB08CB40B4439F99EEF48 -:108BA000AE8F617B819759EC7BBCBE9DD7CFD1BE88 -:108BB0004FB9F8A39FDE85FAA0DA417EE846CD0ED4 -:108BC000D2E13BDF2B12FD9CEF1D1E8F0735B9E074 -:108BD0001A3D1E0F5AE17177507D0BDFA7B06E0171 -:108BE000E938E50BD74DD8FE5F5A58F82A807D8BBF -:108BF000B2E3E77729D4FEB0151ECF0AAA47B0BD6D -:108C00006BF9919FDE0570787438CE65372581E366 -:108C10002FC3ADE78E6C2EE7E6F9B8DEC8D2EC4D77 -:108C200087A337301B9E72E58F6E9441DEAC2DEA30 -:108C30006EB48A3F9FF0DAA85D6692787B8697E3F0 -:108C40006D574EF87384A35D7ED285E3A70A2C8C02 -:108C5000F537D4F43121A1DFB37D7C1D006E9B1765 -:108C6000DAA54E662AD2998779E20CE8CC53C9E19D -:108C7000DF10789D29D0CE530A4F37BEEF23FE4731 -:108C800097830B351074507668F491714FC745483F -:108C90000F59A24E6F791D482F0E9B5E3FEF622C3D -:108CA0007765F172B92FAF23960F7AC6016D502EFA -:108CB000E43AC8DE31CF2F4783B7C3AFFABD7E0B8E -:108CC0007C3AFB689D364E708462B0AE536CBD8DAD -:108CD0008BF1DBC56EB2D7E07D633C61FED3353AE4 -:108CE0009CEEE5F6D6C67FB81AE316EB918C4E27BC -:108CF0007A4F9B4E277AADE9F41CC47F029D7EC655 -:108D0000ACE9B4DAAA3DD0E9B956F8309745A66E79 -:108D10006E0200A5CFA73F72176AAB7FAEDDFC38AD -:108D20003CA77CE196BC50473C83919D687371F9E8 -:108D30003E28F723D3B07F496EA6F7A23B4CFB3504 -:108D40002F65F1FE87F47B6EF566945BA3E8378CA4 -:108D5000F336F73BC6CBE19D72B13B12B7C0FB497E -:108D6000AFC4FD521F1F3F19BF94FAB8DF9C945F38 -:108D700074FACF0947108E91F8E5C2417E593A3A0C -:108D80007ED941FC9256C6F9252D09BFB09893F8BB -:108D9000636D112FDF728F8FF861807F622546FE31 -:108DA000899518F867DABD2554DFDC3E1DE76D8133 -:108DB0009798579F47B805E7A19E2DB78B646FF42E -:108DC0003194535DAC7F8F13F9B056086D87B7B3FC -:108DD00062BD0D2E05BFF7B2D9607FACD3E87E2B04 -:108DE000C283FE50B516CF927AD9659EA17CECA9BC -:108DF000EC298D24E0BF40C3E3E5BEF05D387E176B -:108E0000EB1B8F7669B275BA5783F7A6807AAF15D8 -:108E10009D8FA47776A2DEF1E393C39DF585AB1910 -:108E2000E58099CFA7DCF0DB0F1F1EA69F5F6B705C -:108E30003CA63D4F83EF1FF35AE9E9A0FA4B13DF3D -:108E4000570A632DF9FED756ED81EFFFD50A1F5F54 -:108E500083CF9FB6E2F307BDBCFF91F02CF9389E9B -:108E600025DFD7C3F3116D9DDE3A7D3CBF9504CF5E -:108E70007FF4FA4785E72349E4EB512FC1618BE189 -:108E8000BE00F23BFAEFEBCE8DF5E37EA8051CFFAA -:108E900099D88F4BE1FD8069FF9900743EE5F37529 -:108EA000A188055F42BB6389F0EBEDEEF5CA9A1F1E -:108EB000A1AC44BB7ACB3FBB693F01F4E0DFBCDF30 -:108EC000AC9CB7F92CE4F1141B974397DF73783D02 -:108ED000C669BE46FFE956FD3FAFD1D748FABF2865 -:108EE00041FF633F6679D7C5783CA5C31FC9F71119 -:108EF000BEFA2E42F9B4F5D62C01FDBA7CB5474036 -:108F0000FBDFAFE9978D5EEECFE8EDB64A3D828498 -:108F1000F59B65212618FA3B63B8FECC70007CE314 -:108F200011BECB7DEA59F8BCD73B60EF9D963D540E -:108F30001D502BB03DC8E94A1C5F3DD328A7F579E9 -:108F4000D8C2DDAC0FF50BB8DF710BBAF26BFA12B9 -:108F5000FAB980FAD1E47D954FA72BDEDFE9EA1B51 -:108F6000806FBA06DF0C7C9AE133E36524386F46E4 -:108F700038797F9725C299AC3FDDBFD6D789F46990 -:108F8000425C67E1A0BEBE12FB73ADB1C5986F90A5 -:108F90007F757D0D922915FBDFE2E071D42DCBEEBC -:108FA000AEC37C83AEDBE4724449EE52AEE7946517 -:108FB000851457BD56EBD70CFF407B47F7F8496542 -:108FC00034EE721CF7C25AD683722303ED048A3F33 -:108FD000C812C617B29C9D018CCBAE173A1B17A1C5 -:108FE0001EBDC84DFA9605E65AC6A7F4A71E7FD245 -:108FF000E7CD029523D46FA5FA725A6733DA49A3F5 -:10900000AEEFECB4B4AB7EA8D95530BFF5C3E235B2 -:10901000E0A3F8968EDFA1E3F0F5AB0B370B88EFFA -:10902000D4321812583235DC499BADB6E238EB43E6 -:10903000FBA914E885FA7BDD32EE37D8DF5A1DAE86 -:1090400007911EBF2E5C7ABDE4E3F17AB87F46F14A -:109050000E37975BF401CAC79EF35AEE1FE8CF3B69 -:109060005A645502FD734C5632305E7887A6071954 -:109070000B052EF3FCF7D71B9C479CC73B4DF5A374 -:109080008CD33D0BB8C8BEC3307C22DDBCE6E3FE0A -:10909000684776F8392E1F4321A46B28BF80F867F4 -:1090A0002E287BA8BC9FCAF240F965AA1FE0F5995B -:1090B0002C8F0ACFD0EE0FD44E1AE8E74DEAD73DF9 -:1090C00030EE41FAEE1B28FF91BEE7F3FAA31D270D -:1090D000615DF9FC7B459AFF67929A81FBA39747F4 -:1090E00017539C687EF45A7AAE6B91EB301EF77280 -:1090F0004B7F7B3B3C2F9FBF5846BB7FFE927B68DC -:10910000FF5EEFFF52F42B90DF156906D94545B697 -:10911000F036F720BF0DC2D1AEE599F535201DB967 -:1091200054D6DF510EED6B3E6D6F37E4397552FE4C -:109130004C8A227D9E1857D7E5E0C70EF573DFE90C -:10914000D1B169BE8CED85F13F7317C76344D7F584 -:10915000B215BFE8F34ED6BF3EEF647246C79FFE1E -:109160007E7D7185CCF37FE206BCA4943450BECFE3 -:10917000A58206A7C7A5F11BAF370BC679B28CE84D -:109180004341FA9DA5F97166BDA08FFBB12352E45E -:10919000F7E37E0363B75558E07794783BD0B23459 -:1091A000DC604779DC9D42FBF74CA638BF5EAF31EF -:1091B000C9FC2FF0733DC29C2ACD67C3ED1971B471 -:1091C0003B3634FD5AC6E04ADA84CFAA62F814FA74 -:1091D0004F2C42F972BB87F2311A9B4E54B526F4DC -:1091E000BFF0997F7361BCB771C26A3FC65D16322A -:1091F000E9B3C47C07F3B88DD11B886E63AD42A37D -:1092000095BFF56636E7EB85982223527F4712F724 -:10921000919B940A07C6279A62C6FD1CD0900EA4A3 -:109220008FC5EBCCEF13F67344EC9FD1BC63B899B8 -:10923000877A6F8D8DE86D0BE00DFDC0425097F879 -:109240007C333B4BE3C75EC2E77F373C6F66CB7C2A -:10925000DFCDC562695983749313E964A89F3C9577 -:1092600002ED6FFA3C7A7E4437E9A97BDD7A19F486 -:1092700016E03F5CA6D939C5FCBB0DCBE8FFA4F5D1 -:10928000EEB5011FAFB9EFE98B03E3A1BFB248C050 -:109290002653F905C98FF6172FB3D8D32FEC257BAA -:1092A000563E4B0801FFB7EF7EE1B902F2E7357B8E -:1092B0006CF70B648FE965C67A18CCA72B75A0AC48 -:1092C000BA02501E3B508E6179AB66C7AFB96FF7DB -:1092D0000BED649F8463FE043D59C7787CF99BD6EF -:1092E0008F5D81AB3A319F28566C237F2FD5C48F79 -:1092F0008FFA1D54AF28277237C233EBB67E09E3CD -:109300000D8EE0EB3E9403638A8FA96381FEC7D480 -:10931000F2341956CAC7ED2A5E45764397B62EF049 -:10932000BFD5A8F706D7A7D7B43E7C3DC295BDB43C -:109330003E9EB25E5A2F1B9629EEC7F7E32FA9E493 -:10934000F686ECE4FB0ADBFD9C1F76F8B97FBBC315 -:10935000CFFDD38CE2BB29BE9332C346F533B4A70D -:10936000598EEFF04B9A3CE7F8D81D8C74FB13EC48 -:1093700056781F2EAD44F9E6CBC27DD6BA62E926F7 -:10938000A4E79F68FE29ACD35DB44E45BED4085F08 -:10939000B7DFF8FD16EB563ABA757BA32542F22AE1 -:1093A000D9BA5D3E5F0C5BC5DD5ED0F0F049E39F4E -:1093B0007E84D359EEEA77E03ECCFAE24D86BC6A71 -:1093C000D78ED93D980BADE755AF4E4BAF45B96D34 -:1093D0001EF78D2FFFC387F89DF90FA7A57CFC54BE -:1093E000938FAFB734523B586045CA2639C078DEF8 -:1093F000CB409E9870CA49D37B03F3D0AE24D66786 -:109400006C6EF830ED572F0A880CF7C71732635E81 -:10941000198BEA79C13C0FF60D095C5340E11B3111 -:10942000210498624DD26C5DAE18F2C3E6CD9DBDAD -:109430000FF7E1176BFBF0205F0CDF9798F2C6AED9 -:10944000686C0A3768DF8FD3DF71C2D35C85DB8D30 -:1094500073DD6ED2AFF3C2F3C30D09FB716FFE97DC -:109460006899877E41B68E9770B8A164285E16858C -:109470000587AC8C8C1F333EEA248EAF260D5F66C9 -:10948000FC98F1B078EE6C5A7FF3FCDF7085093FF1 -:109490006F007E305FD88C0FC6229720DDBE395F0B -:1094A00064681F4F1767DA314F60F16C81617ED1BC -:1094B00012164AE7F9C1EAAC6909F09AF168C6D711 -:1094C000E2A758A807FA5D7C9F87D6EF550D3F624B -:1094D000CF5F695E619857079FD7119EBF2AD3BCA3 -:1094E0002E53CB9FF5C1F7483B485BC54A8FF0F937 -:1094F0002C82F974C843F5C90956DB8C74B2C49444 -:10950000B76086CF0CFF4C94839387EEE357646B70 -:10951000FBF8135948DBC7CFA0630D21FFB0790BCF -:10952000837CCEE96B6174F6C078D8AFC022036546 -:1095300019F03BF379EFC679F0EF550151C13CC109 -:10954000D9F3C7ADC1F9875938A3A708EDFD7E3B14 -:10955000CA91CB1898B1D0EE429824EADB70430A46 -:1095600095F57E8F757E6A273D1E61CDDB69FF5DB7 -:10957000C9983B21B97C591570D078663B656679EE -:109580004906CA0B333E743CCD43BCA4115E269EF3 -:109590000E5E5E445D85FE2CC6D1601DFBAF65ECA2 -:1095A000A1F2C1FD6396AF727B329BD1FEFFB5D9AC -:1095B000999ADDD14C7187059A5E3864678D4FB8F2 -:1095C000F93E7245827CFC56B0EEDAEC043B55DF86 -:1095D0004776B33EC2DF952E778F3891E8EEA30130 -:1095E000FA20F9A5E76B46285F53CC58A6505C2CAF -:1095F0002D7D22CB00BB98F179831F7353B61FDFFB -:1096000017C6D10898F9FC4FD7CD5306D76DFD5535 -:10961000DB3B511EA72CF9558C3A57783E479AB63A -:109620006E75DABA0DD8D1A5F03E01BFC73A353B09 -:10963000AC548BE3E31F281F2B56E3C3F9AFFA3A70 -:10964000A69482FF61C823EC247CEBEB094E443FD7 -:10965000F265242051CEB08DB9C83F8EDCC2F33103 -:109660001632652BE6072D8CDA8F25F613094A048E -:1096700047647D8A163709513F8B82BC1F56CAFD4D -:10968000BC01BA8F41FB84FC479B0B4C496C9FC9C2 -:1096900042E83F417FD9A8EFD9BA8471C60E1D3781 -:1096A000597FE676A2B67F2B3A43A150829CDEAE6C -:1096B000D9CFC70295DDB6B1C9F1B7C8E555A584C4 -:1096C000BCD8234157A3555C4CEF4FD7DF0376221C -:1096D000BBE6C5443BD1ED687AF1B90B12EC44D638 -:1096E000F422EEFB7F553BF1E5ECA617DB617E7FB4 -:1096F0007FFB9F287FFC5833084CC0A3373A951D49 -:10970000F5A27C90497F1536824785C9DF92321ECB -:10971000E93D259AA74A09F9B26F662B04BFB758ED -:10972000A5FD3268DA8DAEB8570A0988B7BBB5B85F -:109730001910EEF8D99EC4767CDEFA784E974C70FC -:1097400038F4F158A895F2EB6732D2237A1E88CE0E -:10975000D77A3F47B38DF1BA51F0F3D16CFF507E09 -:1097600016C5E6776F4739F1A2487ED87702B7D0A1 -:109770007B733CE0E36C6E1F8E11231FA35CE86DCE -:109780007CED3B3743BB153B9C2154C3CBBFF7E17A -:109790000FAB14C4135FFFF94B16DF5785F32A9103 -:1097A00064DADF28E0711847AB40FE6B4A9123BCB6 -:1097B000039E877D75B93909701DF6355079EC0C1B -:1097C0000ED731E8B343C1769B1AC95FF4F07DEF41 -:1097D000638A92C148AE30B22744277FBA73785C5F -:1097E000D89DC3E379520EC7B7EBA4408B8474DDD8 -:1097F0008CFB16528CF2A05D27257AEF10044B7B70 -:109800004DEFCF75128433E22BCDDCDE41EF713E9C -:10981000D85EF432837DE3CFE176B27F008E340EE2 -:1098200087D7DC4F3A7FAFF19F198E15D9538388C4 -:1098300097C33E353787C751B81C76BF70409838FC -:109840001A79CCF3F52F094A2E8AEBDD2EC44B4052 -:109850003E75941E5B4372ABC8D58CE7A412EC270F -:10986000819FBBE1E72A06EDD3FE69732A317ACDE9 -:1098700094074243EDAD772B4FCC9B8305EDFCC4A1 -:1098800095BAEC8D4119ECB977B4629332762D8696 -:10989000FA2FADE5F6D962B4CF4224B70C7697D94A -:1098A0003E7383BE9F0374B12420C94817663BAD45 -:1098B000A3721ED9351D60D760BEF6503B8DCB9B81 -:1098C0003BA336A642BD976B45F2335E2EED7BFE81 -:1098D00042D417357685F44569FF9D73E8FB241A59 -:1098E000C7ADF977509F9F7708A5C54BE0DD2BB535 -:1098F00047DD8B13D6FBE59AA3E3D12FD89A24BF7B -:10990000428FD3ECBD95E77FBD7BAF107722DE6E33 -:10991000136DD8EFC2720FE5AD4E13DD34CEE28D7C -:1099200062DC493854D3A7650FDA8D4CACCD7E0D7F -:10993000F170979DE1F9C1829BFA0C76EEC2A8D135 -:109940009E8B3483FDA39CBE1D68B6FFCC76CCF203 -:109950001CCD7EA9601568BFBCDCB2931D2D19B467 -:10996000636625D9FFD6ED98F36CF5DFD5E899F657 -:109970000F6649D6FBFB9768FE290B717F709AF83A -:1099800011ADD7B190A420FEDCB7BC40E73ADCFFB4 -:109990002586ADC6BB33C7A1EFC791BCDD5A914642 -:1099A00079D77B6E3D2BA78FD64BB9BF16D7FF0556 -:1099B0003BC9C164FA2D252AB2629898272AD05350 -:1099C0005FCF31D11496A81FC624C953F8710E9FDA -:1099D00087FF3666433F3B33C6542BBF54AF07FE69 -:1099E000E8748C5143FD9E4C80EF86621BC5FD756B -:1099F000BF34C5CECFFBDA77AD8CA17F3A06E0430A -:109A00003814800FE57051348DCA63A35E7A8E8B53 -:109A100066D2B3389A47DF4BA2E3E87946B488DED2 -:109A20009F193D9BCAA5D149F41C1F2DA7E759D109 -:109A3000F3E97936E82DAC5716ADA3E784E83FD3B8 -:109A4000FB89D139F43C273A9B9EA1E8B7E97B79A1 -:109A500074313D2BA24DF47E52F47A2A57466FA4FE -:109A6000725574253DABA3DFA7E7B9D1367AD6444A -:109A70005BA9DEE4E8062A9F17BD879EE74737D13A -:109A8000B336BA85BEEBFC9CA6D9D32F05B6C994D4 -:109A90006FCF7ACA503E26E3C3439A3CAECF51F70C -:109AA00022FDE9F5F66BE70ECCF50EE40C9F77F39B -:109AB0009AB65E9F848EFC088FD3EAEBB63E307C6C -:109AC0001C8195F946D8B7E2F37B2647E1F42B7564 -:109AD00092BDB1B599513E98A7B2574079D3159030 -:109AE0006658D1913BC0F3C08A722247517FB88338 -:109AF000EFEDC5FDA84B63BDBEA9482F215FEA5419 -:109B0000E86F4CBB8DDC6B85C90296950626F7B0D5 -:109B1000C1780ED85706BD260574FBAD77E62484C0 -:109B2000E7ACE20AB25FB5FDE4FDB78E65E8776C9D -:109B300075F40812CACB558C25DAE15BD72E7A383A -:109B4000F19C8614E0FC39661D7B1AE364459D4A4E -:109B50003D9E271CB7597D1A533C4BE291FA54287D -:109B60009FF948EC697C8EEF8ED7A7C1F3EC9D3D41 -:109B70004FA3F899D0D357EF86F239CFB16730FCB5 -:109B800054DEAB4CF54079D201F519DC26A9EA8BFD -:109B90004C4D57109E785B3AC0B3F51D30B4A05CB5 -:109BA000F351A7086EC9E0FA83DDF644C2BAA414E3 -:109BB000F7AA22FC33FF26B91CE5EC56A92F25B3E2 -:109BC0006CE8FA74E1BC719EA057B66BFBE872C2F8 -:109BD0007A8402821E0FF40512E2815DEDAF523CE1 -:109BE000B02B55AEC35057FF34263FA4201D733F02 -:109BF0002175CD58D24F3ADD017E0DF6A414E074E4 -:109C0000B775C0DEB4C66F08F15BF5BF07BFFF9E36 -:109C1000A3C9AF24F87D09E7111C998FEB029C2F93 -:109C2000818F2F085425AF77B5867F339EB74AF2D0 -:109C300059842F37B3C5CA07D7AD49A3EF91F0FABE -:109C4000EDFF65745B13181EAFACD2CBE3CC5A7E2C -:109C50005A3279B33FC93991E6C01039C7E3A5320A -:109C6000C8B971C9E55C6D6004F99524DFE1F6803F -:109C70009EEF10FE7E601471FD3B6D721DE6BBC44D -:109C80002632F213C0BE6CC7FC9D3131A582B6B13D -:109C90005028231E2BCE263FBD08EC0DA98261AAB9 -:109CA000630F3E2FA9CCB42D2AC3BC068DDFE4A6DA -:109CB0004022BFE9FA7E901F75BAC8EAA273164027 -:109CC000AF984FB84BC3D3603F3C1EB1F696DCAEA5 -:109CD0008E0439D815CAA3B25E3F19FDBEA57D0713 -:109CE0007941FBFD97D45AE79BFC6B40D4EC9C7EFA -:109CF00015E93C3685C974DEB9FD08C9A74C904FFB -:109D000042110F0FE1F8F9D1D487314EFBEB40B689 -:109D100026CFE5D4CB3DFFFFE8B9037C75E2A75A17 -:109D2000790F9EAB18037A484139590BB057A29E60 -:109D300073D0BA2B8CAFA352CBE23D02E1AD07FD4D -:109D4000E6988D9FCFD8EFE85649EF383265CC3F83 -:109D5000D9E58FEC0DF893F3859CA694E3A2FE6100 -:109D6000F37533DD41CCCB9153B1FC2A94EFACC1F8 -:109D70003CA13EA695EF744FFEEAF1873F04AEDDAD -:109D80008FFB54D501F535A467A0EB3F205CEA9921 -:109D9000B244F1E151EE3FE9FC39C84F72B9CE4F00 -:109DA0004D65240FDFC5FEF5FE92D937FFA2C9CF5E -:109DB000FEC0F0F68D4EF7A76DDF68F0BE3302FFF0 -:109DC000CF7CFEB5CDDBD860FCCF93FB46AFA4A023 -:109DD000BD3D951D9D8471AF5E4EF78CC7F9548CC7 -:109DE000FF011DA454BA4C715B6186167719365E6B -:109DF000ABC793F5789F1ED74BD7E80A2F0C403D91 -:109E00009E5E234B8BA8BF3E7619F4E709723CE9AE -:109E10007C8D720BF7E75D6BB2A4B16583FD82A404 -:109E20002439D5D5C8E48E4CBEFF9A01F2A573350E -:109E3000233F2FF6B248FD1F576D1F3AA1DEF14AAE -:109E40004020CA05952972B6760E81885C267A75FF -:109E500032D68DFE36FB41C8E5C038F7E702530124 -:109E6000EEFD9F8BF49430C20D8D2E099587B07155 -:109E70005D466D08F703C5A35006381B326A33B040 -:109E8000BC7FFFA410B388DF5D116932C497CC7822 -:109E90001AA8F79D3594AFB06584FDCF9AA043B75B -:109EA0003B2B8268EF5CD5DFEE5006F73FF57DBDBA -:109EB00060F19317E13D3BC165DCFECC65F1D64412 -:109EC000BB29617FB116FBD932B8BFD87B46E2FE11 -:109ED000E28ADCDBF0E8FEBF0CEC2F46CEC1FAAA2A -:109EE000B7BB1CE953CF87DDEFE0FB006CD28B3EA4 -:109EF000C5823E16943FEB277AD4FC8921DFB5B8A2 -:109F000099D90F9E1534C6F18F87E664F4E0C72413 -:109F1000717C3D9EA7FBC118AF932DF9CE887F7D44 -:109F2000FC0502F763995D2079A7EB4D902791A07E -:109F30009F9A513C5A750A94AF753CB45821BF287A -:109F4000897C19D837603D2556FBAC0BB4BC13F3A4 -:109F5000FB5B825C3F2FB0F338A5B0724904C75D4C -:109F6000107409CE043BE9EA20D75FFAFE8B23F791 -:109F70006415E2D9E1882856F336EFA35C1D64032B -:109F8000E7DD42167A2F199E0ED83B695FEEC012AC -:109F900091CEEB1E8F9C4BF73E24930B6F21FD94CB -:109FA0003016CEE5E30DAEA335DEF43C19F37ED5D5 -:109FB000C0F7A6143A7F63CE97794CC3DB3E0D2FD2 -:109FC000FFDDF932FB34FCBDA4C567F478D6254922 -:109FD000E4FD79B6FA47888E4688CB9CA1E7FB68FA -:109FE000F861CF8CA77B3936F4DAE32902C263A388 -:109FF000FDCBC63F8821B4BFF4766E93BCD0F37717 -:10A00000F472DA4981C513F611D2A46E8A93A69D23 -:10A0100094E8BD99FFEE30F19FBE2EC9D6595F1767 -:10A02000F3FB2E6D5D0E34FD5B00CFBB6C4861967B -:10A03000F9445F048DF177731E40B27DEE835ABB05 -:10A04000E391C93928971B1DB192D1F0BD8E9F377E -:10A05000BEFC8D0BF96CC349E70CABF57835C8FD38 -:10A0600016D0A7EB12F7413DF35F6BC75ED324E335 -:10A070003EA8AE4FF57DD0B44AF33E9AF53EE806D1 -:10A08000662D1F93ED830ED9FFD4F4ED896092FD08 -:10A09000CFB2E1CFB3EFD6E879A4BC8F2B1CFCBCC8 -:10A0A000ACF9FD8B03EBB0BEE047C05737363969DA -:10A0B000F7A9A7C9497CB8B82985E2B28BCB79BC8E -:10A0C00077F17D82B65F678CC3BE04F262199EAFE2 -:10A0D000D7F4CE5116AE467B7456A560D8270FD75D -:10A0E000A618CAF397DCF312DE9BF0728D5DA1F81F -:10A0F00033F41543BBA096E72932A5FF4E8C73EBD2 -:10A10000F1677DFD5FAE3D4AF7A0C5C0CE2F096166 -:10A11000FC5924FE7AF9F549FC5E3A61703F5C0116 -:10A120003B61C379E328DFE360D9B728CEBB01E305 -:10A13000E230D30D5FFE6606D11128E518F2EBC4BC -:10A14000AC38CAC7C5132AB2912E9F99F8B907E354 -:10A15000A2EFDE76DC8FEBD4D7D24C7907E67537E9 -:10A16000C799CDF1E5D38D279F9B3B902740F4F015 -:10A1700092299EACCB2BB3FC4888275F983B8A780A -:10A18000B22EB77439A1CBAF83651D6F3F04FF3C7E -:10A190001871124C6F69F31EE04B8D2E0FEA7CF89C -:10A1A000A593EC916726FE96F2ADF47A2DC14CE2B0 -:10A1B000C36F95C5EDB43F8B790AA583EB323F722F -:10A1C000ED4019BBFDF6D29506FA18905323CAB19B -:10A1D000E1E59498CBE313C9F235753E18AA7F4A9E -:10A1E000C84E4DFBBD3DEE2AFAEA7AA8B1E9D70A7E -:10A1F000B683E7666A3FD111895BE827333C69275C -:10A2000045169F94F85EE1EF07F48083BEC7EA9598 -:10A21000D5AB7DDC9E6E23FE8C3969FFDCA7B6E4EE -:10A22000427D9F5F8D213D3CEC535B7313E4699B42 -:10A230009DEF478A361679C2022F4FE56A7A9985D3 -:10A2400003D8DF9A3AE3792EFDB93D97EFEFEDF1B0 -:10A250005707D0BE6E3B5C1E40FED9EBA9267B3B68 -:10A26000D9BADDA5F313CAAF92417F62A3B6DEC0AF -:10A27000A22AEEE3AEB1870389F1C675B93C8F23FC -:10A280007DF293BD6837B7C936CA136C9379FE75F2 -:10A29000BB5B9AB14D6BE733B493F47354745F8630 -:10A2A000E436E6573FA5D93BC9E6F954AE4DBB5F4E -:10A2B000B4E7DE5A6150AFD88FD4B9E8FE07A6CA1A -:10A2C0003CBF2964C8A7B66BFAA5DE94AF21CA5F6C -:10A2D000CD6F0BFA23BB722DFCB63D3EF5295CEF2A -:10A2E000A81473227D445DD67CFF8CB6AE3FD0E6C9 -:10A2F0006BBE575534DDFB209AEE7D88D537FFAC19 -:10A300000FE96DB5536EF3D13D0F74EF4314AF5C9D -:10A3100082E7DF53783E0BF87FE7F2F306A13E9425 -:10A32000AF2CE0A2785467BEAAE64359F4D81E5A6F -:10A330000DFDB5A9F52A1E5DE974DBBA709F2F33B8 -:10A34000183988F398EA9148EF745E9C4A7A08BEFF -:10A35000A77039C264A19AFC41BA34057D703C5F94 -:10A36000660F38289ED516617DCE71FCFC3FF653F2 -:10A37000C77AF6D716A1BDEDAA443CED0F4DCA88A9 -:10A3800058C809FD69DEFF7FFBBB6F1652BEAA18D5 -:10A39000F908FBEB6D5CBC11F7F557EC1443B88F73 -:10A3A000F09DEF1D3C839F3732EE33DF9F36A50FC4 -:10A3B000F559D4EDA07A7B3CD59D88A736C1D389C9 -:10A3C000FE6EDBE1953F413CB6B5F238B719CF7B65 -:10A3D0003DDFA3FB358EC372627DF3FD1AAC73259E -:10A3E0005F27A78BF62D61BE2CAF8AAF23C5070F61 -:10A3F00079E81EA8E3FB9F71237C5F63DE697955D2 -:10A40000C3CD3B5F26FB45A31F2685D7E1BC6E1657 -:10A410003D9D1D3EBC270DD61BE1DE65277FFFFE5F -:10A42000B4745AD728C087EB2A7A1A5474C9FEBA72 -:10A4300053A4758E4ACD342F1693D8767CBFEBC4C7 -:10A440000FCF473A50B368574B2C6826BCFC15F029 -:10A45000B2DA022F403F4579B85FB4EB46EAA7D3A2 -:10A46000E192D1B269F354D379E5D1DE2F5296C788 -:10A47000F924E17E91B2BC2A8BFA9A9F85FE368E32 -:10A480005B27B3CFE26C10EFC9F257CED7FA1FE8C3 -:10A4900067E4FC95F313C7D7C7FD1AEB3AFD74D6F2 -:10A4A000B5CDF57FA7A39DA58AE9A1944228E33AFB -:10A4B00021FE719D70BDB4B80DA92005E940EEC91B -:10A4C000433AB8313D84F43992DC90185F77BB048D -:10A4D000F40C769D538E1CA0B38B5ABC479727660D -:10A4E0003E6B7319E5559B7E2FDFA1D1C92BA09739 -:10A4F000AB71DDCC726BB474B2324F30DF43B33228 -:10A50000CF9F9C4EECC1F08D8877C4535E05C52B60 -:10A51000BE8BF5F7EF177738C6E2783C6ED61F642E -:10A52000F2430979593A3CEDB8D9CDE3D414FF9000 -:10A530001A19C33C386F694890CB464547ED89F0FE -:10A540007D037474D77074E466BD745E63B99E9FB6 -:10A55000B363F8FC9CAFAB7F603DBB109E36CFF77A -:10A56000883ED7DA5D32BF47EDF4D6F5D1A1EBFADC -:10A57000E8F0EB1A791CBFAB79D5748F11AB692267 -:10A58000BB69975F7D13F3C5981432C8C521FCA33E -:10A59000C9ED9BCF54285F7577AB26E75A9D32DA19 -:10A5A000E3CFFA6E7C1CEBDFCD9430C643A7D856C0 -:10A5B000119EFE0AF37B284472B514F77DA22C3558 -:10A5C000A4E9D1A7110F339456210BDEFB162836D0 -:10A5D000BA8654D9C46C65A3C7C34B43E5E04B238B -:10A5E000C8C15E8D9E6F427AD6CFDB279383874E9C -:10A5F0005F0E1EFA86E5E09FF34E43AF7F03F2E65F -:10A600003384DF2C6FDC1A3F5F1962218C978F3601 -:10A610009F0DEC4D05F9AB2EDD45F4D3F68440F9E2 -:10A6200052608747A8EC7191B0D9EB71F0FCDF1D47 -:10A63000FCBB58CFF16CC6D39779593CEFA67B652C -:10A640005832E449C5881FEE528FC9C522E6F7D7B4 -:10A65000123D7B357B46CFEB4FD7E4FF809E9F6951 -:10A66000A3F1BC055CBE7BC1DE41BB88497D0CFD0E -:10A67000F89BF378FE3EF003D1378C12467EC8A8D3 -:10A68000914C795A9C5FFC12B777327D4C205D83E8 -:10A690007962F0FE04D813783F41A66A6C7773EABA -:10A6A0009502EAADBE2677B340E7F4C37B7E0CE5A6 -:10A6B0002CCCF702BEF1CE30D6F7B384B2857F1E24 -:10A6C000AB67A598B75896AFF9E90E1620FDA8F923 -:10A6D000E9FA7D81E2C8795F95F9A3882F9E97AF4B -:10A6E000E79918F571770AB38CAFFD473E975B0D7C -:10A6F0007D75F56857AFF230B2AB56A1EEC472A6C5 -:10A7000083EEB509EDA97459DD5791A9DA0CF7F379 -:10A710007A67A41AEEBDF587B30CE59CC65C43FDD1 -:10A720006064ACE17BDED2B30CDF0B9A2B0CE5311D -:10A73000D1F30CF58B00C189E571EB2E36D42FE9EE -:10A74000BCCC503E73F3B70CF5C7C71719BE9FFDBD -:10A75000C87586EF13BA5719CAE7ECBCD550BF8D40 -:10A7600059DFDFB9219FCB29E0779263ADEEFA463E -:10A77000FA1D0DD96188F32FD1EAEDC9AC2EC57849 -:10A7800048DB91F252F287D3CF1BD61F36CBC5647C -:10A79000F2D8FCBE5D1BEF93A7DFAF5E86748E42DE -:10A7A0001EE4D227EEB7D6E29CD697F1BC04FD7723 -:10A7B00031CCF7F20FEC534A2ACD67419683599D6D -:10A7C0000F5892AF58EE2FB40B2117EE1525C39BEF -:10A7D0004E8F23E1ED4EADDED7C5DB21C118074218 -:10A7E0007DF284055C7BF307EE3B78389FEBABCAC8 -:10A7F00054F230F83D0EA7AB4F7438409F3C915F48 -:10A8000035343FFC93C6D7AEBE5FC1FA57F3FAB6F4 -:10A810005029AE4BB27DA5BDF9E67DA5AAA528E7D6 -:10A8200016785285C4FB9A7FA5D5D3E3D96DE99FED -:10A83000D3BE529B23543A9A7DA55FE19D1B558858 -:10A840007F858FA7AFAB5D0DC896FE9DD98E61CF7A -:10A85000E33D1831B74479C366FF2EAAC96DDD9F69 -:10A8600093F6D691BFDFE61E4B791F6DEA2AD29789 -:10A870009D49FC5CD0977F447C4EF5DC64F0E70694 -:10A88000E3012A8D076DC96E6A4BF0FF715DD5FB40 -:10A89000F9BDDADF801FFC51FE69D8090AE37EF0BA -:10A8A00071C6F1745CB5919D701CEC0494BF6B246F -:10A8B00046FBDEB14A41B1F28B3B576BF6E16A8E43 -:10A8C00037F37EB7D9CEB824B492F0B606E8C955AE -:10A8D00089F1386EFFAEB1F3FB37656F3880FAB699 -:10A8E000DFEF600F01B47BFD3C3EA7E3E5ABCAA3FD -:10A8F000CC8221767266C13076F234B1AC1BEF6D3A -:10A900003D7692C745143C8AE8C37BC8F9FAAD7A14 -:10A910007E4E6C05EAA922A919F3D745A664205EEC -:10A92000563C27B2B88072CC989F6F67CD3FC278F3 -:10A930001CF3F1F731E66A453B29A3C6A8C7325597 -:10A94000A31EF3CEC832E935A31ECB6934EAB16049 -:10A95000C4A8C7F2965698F49A518F8D89D69BF465 -:10A960009A518F8D5B779949AF19F5D8999B8D7A5C -:10A970006C7CDCA8C7CE7E649549AF19F5D8393B0D -:10A98000571BBE97F77418BE4F7AEE6E43B9AAF7FD -:10A990000143FD730F3C64F83EB9EFFF18BE03A2FC -:10A9A0005FC5F30C780F2D2EE2F91F3C69FCCE54E5 -:10A9B00007E6E35F8FE733611D2FE8FFADA13FD6C8 -:10A9C000C9CF2DC4E03F5CAF3FB308DD0300726C1C -:10A9D0005F1EB4BB212E847A18EAA727DEC77D9BB1 -:10A9E0006B0322F9712B30D88AF4F0A8278EF4700B -:10A9F000CD66E3F9876BE3C6720CE847C1B802D0B5 -:10AA00000FD2D7F5A6DF8D007B90E8ED7A456A4638 -:10AA1000BBD24C5F7FD6E92BA6BE8AE739F4F9EAB0 -:10AA2000F3B3EBE74F35FA5335FA63E22E82FBFAC4 -:10AA30003C917E7F479FAF0AFFF1EF1F39701E27C1 -:10AA4000760ACC8BFBFB2CB62FCF623E37ECDCE4D6 -:10AA500040FE34CFCB3C8F21766A81715F719AE8DA -:10AA60000E11DFBD2E923EA229209F3DC6CFEBAD39 -:10AA70007A5EA47331C887E82F88B146C2CB0AC07A -:10AA80000BDE1BAEDBADC7B476C71E14E97CF34802 -:10AA9000FCA868F870068CFC98A2A49AE8C988DF24 -:10AAA000B452237F5EFFCE450E945FFB00DF420D64 -:10AAB000639E90915FAF1797D13E9F8E6705FEC34F -:10AAC0007125307571DE37C0BC7B94A1F85DBA6B1F -:10AAD000D3DA3C0BBA1909BF8F1618F7E9F4FDB9A0 -:10AAE0003AC08EC322AF54C7DF2EBFFA24CAC76450 -:10AAF000FEF0EE02E3BEFA28FCE1DD89F2F61BF07F -:10AB0000879F2F1856CFF5CF427FCAC9D2431D1653 -:10AB1000713F89C93D18AFB537F3B8DF60FCEE1B54 -:10AB20008FF3BC5B5045F7CE919E4B91F4384FE8C4 -:10AB30004004ED938CB342981735DA38C75F0A8624 -:10AB4000C439FE52307C9CE34D3C4FA866E436D8B5 -:10AB50009099A45029DDEF8C20F03CA44F118F4335 -:10AB6000F2758BB3B4FC6365D8FCE34BB4FDDDEA4E -:10AB7000807A12E180FE3EC7E7C07D6C957EEA27B1 -:10AB80007D847E62F5DC5E8BD93C9D6DDC5EA37DB1 -:10AB9000A66F208E915E887EA99BE3BFCDC1E3B6F0 -:10ABA000A71B670B160EC17BB07018BCFFFDED1C18 -:10ABB0007E6E3504D6417972FAD6CF61EAE5F59911 -:10ABC000467F796D0587AB441BFFDBD9DC1F985CA2 -:10ABD000C8F94FCFBBC4BCC5940A28CFE4E794F4AE -:10ABE00073AD7A3F930B3D54FFB340FDE4423FE623 -:10ABF000CDF2FB77D6661AEFE1F9B8A06E32CE6BD4 -:10AC000092D6FFE442C6F399C772B8CC79A77FD336 -:10AC1000EAFFADA09E9E788E16FD1287285AE27339 -:10AC20004A218F13E8F7DE4CD7CFCFDDC7CFD799B6 -:10AC3000EF5D003E79037F1FEAE89D76F2F7401F43 -:10AC4000D1F9B92579FC1CA2F93E8548A9BC0FC5EC -:10AC5000EB095666792FCF903C8743B750FEDDCB8A -:10AC600093992C0447CE7BB8BCD0783FC257384765 -:10AC70007765E128F21E166AE7E8FA52B91EEB0F73 -:10AC8000BAE20F59F8BB516D9DEED4FC5ADC9FC659 -:10AC90007D72BCDFDB6ABF3C5AC8E967B4E7AAEF44 -:10ACA000764422C8B7E673D5C9CE53F739FAD6E44D -:10ACB00020BCE35908EDF79C05F29E1CA897DAA08A -:10ACC000D0F9C7B5452CBD06BF97DB4278AE2373DC -:10ACD000AEBCD68E7C5ACCB20428F7C5E6D0F87745 -:10ACE00036325904B8BA0AF93EFAC2DB3EA5F1FC85 -:10ACF000B5303585CE9D4F47FF2CD6C8E8DE42F3F0 -:10AD00003CEFD6F8C5B586DF9393516C9D877FB72E -:10AD1000468F20B736215FD415B31DFCFC2C3FA70E -:10AD200080D7D253FE662895F6052F8575E3FBE79D -:10AD3000BDB47E3705A6DE8FEBA9F39B43CB533022 -:10AD40009F27EF2A3CBDF3E4A90BACE1FD9DB6DEE5 -:10AD50004DFEF0CF10DED4D24EFEFBA55F9E3A250D -:10AD6000566B3FEDA860FB4804F55F0AE83F019F82 -:10AD70008A4CE768994BA0F3B02EA599E82AA5263E -:10AD8000E4C5DF456357D918DEE332556BAF363281 -:10AD9000017F4F827201494E9B7E5F420DB5B742E3 -:10ADA000FB69B86F16C2BCEFD052ECAFC19D2A63ED -:10ADB0007C33A5B8B90ED7EBD985BC8FBB939C97D4 -:10ADC000D0CFD90FDE3FB5EC95BDB509F70AACBDC4 -:10ADD000FA15E3FD5357BFF275EE9F3AB8F5EA57FF -:10ADE000FE27EE15D0E51BA8213BDAF507447E8F40 -:10ADF000DE5F9FBAC28EEBB0B68E7523DE639F0313 -:10AE00009E5D8378B6D7879FDD8276C9AAF410FF4E -:10AE10003D91D87710CE77D2988CEDF57C43819513 -:10AE200092BE9EDB2890FDC0A4FE1BB03C7F579ACB -:10AE30008CFEC35F9F7AB32006F4F9F6EDC73D9808 -:10AE40009FFAAED4EF41B83EB8ED350FE2EFEDDB3F -:10AE500044CA43A173DF0979625F6AF4B5604CF8B4 -:10AE600038D2D7C296FFAA4EB4CF58D44FFAFEDAE2 -:10AE700038409C68F73E9266F85DD1E5DD5E435947 -:10AE8000D7F3CB9DD6E7E62BC770B974EDA35D8EE3 -:10AE90003C05C78FD8C7C03C3FD0CE017DB0C3436F -:10AEA00076BC0ECFA247CB1D680FBFBBCBC97A289B -:10AEB0002ED86B676EAE3F30EF22C2871E02E7BE10 -:10AEC000DD790EE4B32502EB771273B37D88EF3F93 -:10AED00069FE9F791E4BDE961DB8BE4BEA583F9E19 -:10AEE0003B5B7493B0F666A8BF28E226BFDF3C4FF9 -:10AEF000B3BEB906EFB311ACEE816BDEF73BE8E70A -:10AF00002AE807EDCF259DC6EFC79EBB71DF161857 -:10AF100077C74E07D98BD78C10EF1F3F46D34BD541 -:10AF2000ECDC53E348FF654C5092DB1DBA3EFAA0BF -:10AF3000855192CA5FF0F77DE1F9518B4CCFE385E3 -:10AF40000AADC7F53BF7ECA3DF16967AAB51DECD21 -:10AF50007C7E71DAB7D8605E517557DB335B88153C -:10AF6000F47CD51E8AEFD568F7BF5CA39DFFA83A95 -:10AF700060CE57DDF3ECEFD06E83F99FCEBD3D0B75 -:10AF800046796FCFB1E7A6A6D1F9001D2FE7025E83 -:10AF9000C4AF8F9764ED9627F9DD169D9F8E6B7A6F -:10AFA000F7AA6DB3D7E6C2F86D4FFDB910E3C7310C -:10AFB000C6E9BBEA41FEFB3F55EE6CA23717D267EC -:10AFC00010F16ABAE721C6DE6009F47DCDAE34A285 -:10AFD0009300D843CE1A7CC3E9B50AEFED44FA7E5C -:10AFE0009DB77769FE6D64D7EDBCFEEF1CB23340B0 -:10AFF0007C19B0D1B32760ABB1B867CB7CBF58A781 -:10B00000B1FC89BDAF10E5CA35263FF413C13A3F04 -:10B01000EDCA3163497E5DA5A8D3310F60090BAF3E -:10B02000E5F15B7E6FCF0752E7BEEF23BF6F13588A -:10B030000CF0B4FC378FFD2BCAB1EB1EBF2F1DE502 -:10B04000D8875267368EB76CFB9A74BC5FE60329CB -:10B05000968EED3F8C737936445F8E11B47D293521 -:10B060005D00997C03911AFCFFAAFEB5B7C2387F38 -:10B07000033C23DFDFB0E31F54DEA7BAFA5900FB1D -:10B08000ED9B8E705CDBE46E6E0DA17F69E4CFEB0F -:10B090007E765FB642791EB13C0D7F79D8EE866D23 -:10B0A00076CAF3453F1E8759C1FA697EE6F62BBA88 -:10B0B0008F3A505ECB36D69F7FFED0EF602139901D -:10B0C000DF56ECD8F0A9988ECF0FDFC2DF835A612C -:10B0D000B24F976AF2DB4CFFBF30D13DE087E20B05 -:10B0E00031808BFF1C1397E36D3FBF7FE26180EFE0 -:10B0F000A36D2FA6E3EF4DE8F4AFDFF37CAC7BF15B -:10B1000042C730F7087DA2F1C9807ED0F493B21314 -:10B1100000CB81E22EFE5C66EF493F1FE6BBACCB65 -:10B120001E429A5FF698A8BAD1AE3AE8247B64D959 -:10B1300063C7896E97096ABF407A8EA5A31CD7D7CB -:10B14000EBFAC7FE341DE5F4F54191CD0456BCEE93 -:10B150005727787DA0F314A87FFD1387A77F1FCB07 -:10B16000204F5C16EB35B57B8FA3CF6DB15EDD87CD -:10B17000A7637CBEEDE77FA7F5F870B7C0728A863B -:10B18000B65FDAF5278A837D040BE3CDE4F8427DD0 -:10B19000B3A25B6C726458AD5FCFACDF56D277CA96 -:10B1A0000B1F691D378C615C3FFEE6B15FFE16E048 -:10B1B00058FA96333413C7FDE58DE90CE8E0CF5219 -:10B1C00033A7FB1FAFC946FDBDD41ECB96E9C9DF2F -:10B1D0002FDDFA5DA2C76B7EFFDD6C6DBF2168239A -:10B1E00079100BE23C973C388FE679358B103D2E79 -:10B1F000FD31BF67F104F8D9567E42A5C2E59693AA -:10B20000AD9C78AB0FE526DED902703818BFAFEBE6 -:10B21000559EFFEE64976524DAB90E85DB7331160F -:10B220007F07EDCE15A09651AE89BF3F311DFBB90A -:10B23000A9486A76527CD4FAFE9AFF075C96D1033D -:10B2400000800000000000001F8B080000000000CC -:10B25000000BE57D0B741445D670F5F4BC425E43DB -:10B260001E100884CE3B488803492001D481400C3D -:10B27000CA63025151220C014380BC445670F5DB75 -:10B28000740820B0AC06659515740704C5E706047C -:10B290008135C2441483EEC128AC8B2F761004791B -:10B2A000C980B08EFFB2F2DF7BAB3BE99E2402BBCC -:10B2B0007EE7EC7FFEEC598BDB555D5D75DF75AB92 -:10B2C000EA4E1583BF04C6F23E1ED5DD9BCE98859F -:10B2D0005D30DF9BC5D845C6A467EC8C5531A3EC27 -:10B2E000B532FABB12CFD889F5962EC28D5076634F -:10B2F000650DD0FE0AFEDDD2564E9704C6B2A9F9FE -:10B30000276C106395F82F09FAD974227F0DF4CBBE -:10B310006244161EC3E167A218B395845487E7C040 -:10B32000F70E1E35F7847A39CAC0926D50DFF20DE0 -:10B33000C1CC1E2D617BB5FFAA1D16E651C703FFC8 -:10B34000AFDAF08D99613F06E6EB35B47D3D63D50C -:10B3500019BF8EC279844BCBA13C61F6E5BF85DF76 -:10B3600081EF6E84EF94AE82F6699AFEB69EFC9CE5 -:10B3700065607B73DBF378FCEF423E2FB138DC1560 -:10B38000C2D84C9826CB6D3FFF055FD63EFAAEA6DD -:10B39000BF0C2934EA7830FC63301B7C456C7B9F02 -:10B3A000AD8D66AC47FBF77FA8911F7DD7846FCB2F -:10B3B0008C41937293FB05C453F96716BB0C782C30 -:10B3C0007FED92D9003013982FB92B63A75FDDF37F -:10B3D000E93D309FD30DA6A831F4554798D0AD0D67 -:10B3E000EF655BBEC95F03ED4D80F720A067E5D632 -:10B3F0001FCC06681F93C77C1618FFE9282763FD3A -:10B40000116FA6AFBD1ABCE5C1736F088D23D610AE -:10B4100083A52796415919C5EC1E78BFF2A06897FD -:10B42000105FCCB7C416D2FEFDAA86A30174D1D793 -:10B4300033E6333BF1BB5B7F7B5E0CD3E2DDF8B5DB -:10B4400057837715CF8178BD3B00AF97587A387C0A -:10B45000869D7A794E1F577A7BFCAA78FDAE8621AD -:10B4600093B73EBFD047223C4B3BE043DDA1AE51FA -:10B470002919FB9469F038FB95B3C4BFFFE821326A -:10B4800011F8A672C38F4B90AF00AD3E0BF06FA5C5 -:10B49000FB3CC18B1D561F23B8A948C8E868DE7A5B -:10B4A0007C06D6F742A466B7D1DFB490C9A1D0AF6D -:10B4B000EF6DD1BD1E86764EF28545C0FC1607B1F4 -:10B4C000A94E28CFD914B8AB0AB3A9D3609CE7E43E -:10B4D0000C9B8CEF05B1490D409F734E5F58D79080 -:10B4E000B6791F6914C32468EF75B3828690F67C21 -:10B4F000C8581D7DDFCB3AABAFA5718E122FBFEEC2 -:10B5000085EF5D908DCC02DFF3D6FEF0BA17CA63EB -:10B5100046AB0DF134A3F6AE306680EF37268E9F32 -:10B5200004EDEEDB07F8A3E939CC3D00BFD3F9D435 -:10B53000D9B74C7E6A18CC4F0CCDDAFB16BC5F0A2B -:10B540008815815F67ACD0E3673673867BE2516E06 -:10B550004D6D7C42FF759B3DF0DE4C5748F572F80F -:10B560006ED95A7DFDECC6D3C45FB303F8CB85FC1E -:10B57000D5A33D7F6D54F96B001B80FC354A0C311F -:10B58000203F9F6B16DD1678E7C222135B02F08521 -:10B59000570537837E2E34422384777098C9D1C4EF -:10B5A000B72A9FAB783B83FC97DA1E9FADF5DBBED5 -:10B5B0001AF43034297FF38B8C35509E79F3B39491 -:10B5C000B710DEFEB7B82F58FBF679BB7E9C42E37E -:10B5D000DA656138AE73BBDE8F7B18E13F5BECC888 -:10B5E000B7E7165A1C0CF5DDAE507732D6F7067E5B -:10B5F00000BAD7BDFD4306EA7BC616111D5B243396 -:10B6000095171AFF7958C079345A249C47D52E4093 -:10B6100002BC5FF5E72037C3F7DFFE61902BE497AC -:10B620009B4FA599B9883F43D9A42DC8BF5D990305 -:10B63000E753F556EEF3B5F0FD8AAD4DE6E9509FC0 -:10B64000B7FB5F19A88FCE6D6932A3BEFACEE47D39 -:10B650008E017F7C214DAE37019EBF0B85CE7A32A5 -:10B66000362F7E8D530EE9082F1C0FE7000F382F61 -:10B67000C04B993BBD737C5CF8AFC5C7F929F8FD99 -:10B68000F2C6C14C8CD7E24570F0E7A16EAB40F337 -:10B69000E7CF77FD90C142AE3E5F5BBC99E4FDFF12 -:10B6A00097F966C4FFB7D297F3FB9B12B74B817C27 -:10B6B000DF9EAFB73F48F0EBA1761AEF35CAFBB873 -:10B6C000FFDAF9FFEFD0BBFCBF76BE57A3F73E858C -:10B6D000DEA1360BEAADB7FF15C7AE63DEBFFD7F57 -:10B6E00074DEADFE8FC16ECD82F17DCEDC770C179E -:10B6F000C82BE9D01FD9112F507BA6AC3BC6297EA1 -:10B70000451DFB7AE434F8AE0CFE04FAFB75215FAC -:10B710001B0F02DC027E02FA170C9D13C0434BD1B3 -:10B7200000F772B4DBC66A6603D8F4E97482279521 -:10B73000FC68CC82F677809F87EDF7D77A67D44292 -:10B74000FDFEAE06A90EE0F18E89C95B01B6F514C7 -:10B750006DB88EA973645A25CDF8C6E7E8D723F7EC -:10B7600004AC2BEE9AA4AFBF93AD8F36427F779691 -:10B7700099981BA6744740FBA7E26D34CFBB58F5E0 -:10B78000625BC8F5E3E9783C5F9FD5B181CD12E2F9 -:10B79000C521DA37B2F678638837C44B4C265B6E26 -:10B7A000C7AF788D0701B628FE15FC913CDE116508 -:10B7B0007D01F1646173D983D0DF25C9588DED2DEA -:10B7C0000CD68D7CDCC215A13DDEE04F320E225737 -:10B7D0009C4830DEF100433CE3F33E31BAF769DECA -:10B7E0008178BE7EBC2E4C7E0AF15A146A77235FA4 -:10B7F000389E8F36C2F7EA00CF82D0864F154F8130 -:10B80000787F0B7943E397AB653AF34D41BF338CB7 -:10B8100085D99743FF61D65ECCC8E7E1B3F4C0C2D7 -:10B82000C670BD268E600DCB61BDC6728C675AE7AF -:10B830009540F59E87E1BDBAFBE17DC46B2F2639AB -:10B8400089FF8B6DC7FBE132CFC5AE04B7F99F1FEF -:10B85000E580FF194F25F1ED471BB8BF7969D81B6B -:10B860004B0680283198B33C08FD5CE54FF616E3A3 -:10B870007B2233D871FDCB1C0EC93608FB65B4AEF4 -:10B8800009CF31E8D6BF5D1D5D74788B2C88D0C19F -:10B89000D1CE9EBAF6DD2725E8EA7BB86ED0D5C7B3 -:10B8A000960DD4C1BDAB87E8DAF759304207C7CB54 -:10B8B000B7E9DA272E9DA08393EBEFD1B54F5D5DFD -:10B8C000A2ABEFEB9EADABEFB769AE0EEEDFF06B68 -:10B8D0005DFB1B772CD4D50FF02CD7D567363FA155 -:10B8E00083B35B9ED1B51F7C68BDAE3ED7FBB2AEC5 -:10B8F0007EE8B75B74F04DBE3FEBDADFE27F4707CF -:10B900000F671FEADAE7590FE8E051B62F74ED6FC1 -:10B910008D391A10EFB0C90F64A11A037E02391BCA -:10B920002D9DD6B587155A31F28D49E187DBD3BEFF -:10B93000D7D58FB5FF53D79F9955031190ADEAA97D -:10B94000ECC21AA80C612D543ED4DF757B02CAC329 -:10B9500073F21264AAFDB93FC4A11DF968D803327D -:10B96000F2DDA518661307C07898CF887C6D08BEF5 -:10B97000DCCBA5891B85F945E6C9043EF40B54DAF6 -:10B98000FCC1CC13097CE80FA232C21F49CF23FDB2 -:10B990005DA98CF2C7D2F3687F0F2ABBF913A9EC1B -:10B9A000EE8FA732C6DF8FCA1EFEBE54F6F467D2F2 -:10B9B0007BB1FE0154F6F20FA5E7BDFDB954C6F9FF -:10B9C000F3E8791FFF702A25FFED54C6FB47539912 -:10B9D000E09F48ED12FD855426F927D3F364FFDD7F -:10B9E00054A6F8A75399EA9F46659A7F0E957DFD68 -:10B9F000B3A8BCC1FF00BDD7CF7F3F95E9FE87E963 -:10BA0000797FFF435466F8EBA8BCD15F4BA5DDFFFF -:10BA10005B6A37C0BF8CCA81FE27E979A67F25956E -:10BA200059FE35F43CDBFF072A07F99FA772B07F68 -:10BA30001D9539FE57A8CCF5BF44E510FF1BF4DE79 -:10BA400050FF662A87F9DFA2E737F9775279B37F8B -:10BA50000F3DBFC5DF44A5C3FF213D1FEEDF47E516 -:10BA600008FF017A9EE7FF98CA91FE2FE8F928FFA8 -:10BA70006754E6FB8F5279ABFF089505FED3548ED1 -:10BA8000F69FA4F236FFF7F4DEEDFEF3548EF1FFDD -:10BA9000939E8FF5FF48656B3C619829402FB6EA6D -:10BAA0003FC3152859484487F1B6D6F7157DBC32F7 -:10BAB000F83986718F71D502ADD39F0EFEEE5DD23F -:10BAC00093B91609E1C5D8B407FF8EAD1B63F7E241 -:10BAD0003F24C69A722DB47EDFFF3FFCBD25C38F85 -:10BAE0007EF900DAC7FB2D0CED63A0FE55BFFB51BC -:10BAF000CE9E68F4C3960CF49663FCE577F1DE62A3 -:10BB00002CB727707FE4F5046E6FB72518A87CBCAE -:10BB1000BF8DCAE2FB93C3294E15756DF3BAA4D845 -:10BB20007DB5FD1F921438C41747F6E21AFBB9D64B -:10BB3000768BADBFF923C6751C7546167433C046A7 -:10BB40006EEFE52F43DD1B614AF288EA1731CE2301 -:10BB50002FB4D8EAA210CFBFF913B65FC098D302B2 -:10BB6000E53309AEFDA8177E088A73837184BFEAA6 -:10BB7000C113427FD1FE3FFF5FEEFFF8CFF5FF77A5 -:10BB8000858F6E4D749E4A40BFC0E8C8403A8C58BD -:10BB9000D8438C82F7A7AD106CC847D3170DC847A0 -:10BBA000FE18C81C1427BD37924D7576E0974524C2 -:10BBB0001A14FF4232DF05E339CB9807FD89128959 -:10BBC000115F96340A6E99E2D08EB0B160BFCB148B -:10BBD000BE2D595A6B9E0FED2A7AF0781973F378BF -:10BBE0009915FE877234A77EDD5E0A378A97293E53 -:10BBF0007609FD5E609D399BDAC763E7639C7987B0 -:10BC0000D98676A3A221209E1B10370B8C9705277F -:10BC10008646A1BC323BB3F3387748E9DFF07B2C92 -:10BC20004C12A3AE8E17353E2B31A93BE27194988E -:10BC30001E8EEB980BCDC9E10C4B49EA8EED5C40B2 -:10BC40008B162805A36B303E077CCA48575F6DB042 -:10BC50007B3D8CEB08D813291385DB35D88CF1C8D4 -:10BC6000CF7BB3E502518DFCB0AA0D22F9F5DE853C -:10BC7000FF5C8271EC59F1465A074CC3983B8E6FBA -:10BC80006757B72C50BF8477DF6B02C55D653637C9 -:10BC900006E3BA9AFD10F26B9D8BA3C7E5209D9633 -:10BCA000761D68415AC98E4F93BA69E8B3A88EF0E1 -:10BCB0005A1213C9E9B3C3447E2DD0A716E933CB7A -:10BCC0006D3AA6C5F32576D98CFB31254BCF13BD34 -:10BCD00066B7D14BD7AEA2BE89E80A74D23DAFAAEF -:10BCE0003EA1C6D18FFD1CBD86272AF14D855E1869 -:10BCF0003FBF0B2B1F8924FD50BCD0935CADE1D31B -:10BD0000C07D89A41943C29D200F053D393D98D1BE -:10BD1000DE0DE9F9FD8A6CA257209D0A7E9A4EF449 -:10BD2000609F87B28D309E7B13D9D409F07CAA1214 -:10BD30007FBDB76E7401C6CBEF4EE4FAF223587F95 -:10BD40003A60FDF9718D953940351FA8B111FCD7C6 -:10BD50009A1882FF562351F9594D1A95C7CCACACAD -:10BD600041235FC000661CDF5445AEA626AAFB52E5 -:10BD7000F36230EE5EF0D3816C03AA50B9A170D4A7 -:10BD80004DB8BE002468F033A928987C6915F69A4E -:10BD90006CF931A83F9609F68D4857E7505D7B96C0 -:10BDA00096D906A3FD32727E02BE588FFC77F798B3 -:10BDB000485DFB3B97C6EAE0F989128DAFB0205190 -:10BDC000F7FC9EE27E3A789A1FD6F3F0A924A9C028 -:10BDD0002043FF17FF62227EBE583DB8FB7C0E1346 -:10BDE000DF05E2FF9859A63882BCDE6247FDF76D99 -:10BDF00010E7EF6FFF2ABAEB68DD2B53DCE592D535 -:10BE000026E13AE5C1E9721CD63F180C2EF900C4B0 -:10BE100097C8307EC05EB690FE9CBE5A6032CA881B -:10BE20008FD17A79DE4B169AE78CD5227365129FF3 -:10BE3000C461FB79D112F5776FA2D480FCECDB688A -:10BE4000B1AF87DAE95EE57D6120ED8354CCFDDB9F -:10BE50006123CA434A4B06C6F78BE33DD1A807CFFF -:10BE60006C30D1BE5785B8AE34044834E7776F8460 -:10BE7000E54A247E84DF531F47AFC3F9B7CDD74DC2 -:10BE800071116F1FE7B38980CF53A5EE0C5A273F7E -:10BE9000C2E3F1EDF1C2484FC986306923CE77BACB -:10BEA0006BB02D5D6B0FF9BEDF7493BD9B3D1DB96B -:10BEB0003FAB07EA81632B4C05187701BD3F0EF1BC -:10BEC00074AC3ED2B09C16555B88BF4A8C9259FB2D -:10BED000DD9215A283DA837E2F447BBD5274B1C1FB -:10BEE00008D753FFF252C185FB4E492CA73BF2ED18 -:10BEF00003F70FEE8EF398D2C93EE37720332ECDB1 -:10BF00003ED6ECB745A71BBF97E53516F5D78E9FF4 -:10BF1000C781925C4B7BCD453A6D0EB22F9750AFE7 -:10BF20002686E33AF5E441B01BF08D59754D1912A0 -:10BF3000B05EF903DB890E65E31A523CF0FC63AB9B -:10BF4000EBFD4498C2B73D1A9E1A8A71A2C6E7E378 -:10BF500064B4830BF8FEDAEC9767F5D1FAF3EDFDE4 -:10BF6000091663C8C1C2D34D00BCB824968FF89D92 -:10BF7000CC1A94F8859BC627A1D2057CD8CAF9FEB5 -:10BF8000DB74837DCA812C447FA80DE9A2F677D4A7 -:10BF9000C4E35C9F270A3A3B1C9DC4E57BBA81CB76 -:10BFA0001DDB25109F02C13E4DD2D8CB2AB682ECB4 -:10BFB000654CACC870DFEE646284A217B8FD9B8349 -:10BFC000F60FF7856D02C947F9268BDB0DFC9598B6 -:10BFD000C4E573B6F9B5A70662F3F86A337E67D68F -:10BFE00056813D034D4F99DCA52DB82F655BB728D1 -:10BFF00082DE33D9DDC8A78A7EB7824240BD3013C6 -:10C00000FF09F515AB04B787F8C549766806C64D34 -:10C0100070FD8F7A5EA347DAE9F700BD7E1FD3DBA0 -:10C020002356AFB72FCEE0502B8E73F62AEED7B63D -:10C030008D4764570057A52EF7DE71345E81E222EA -:10C0400081DF9F89E3C3F1C2F83CF6EB1F4FA99D46 -:10C05000CB6979BDE07677303E15AFE1C39884F6C1 -:10C0600079CE06C18DFC382AEA7EC2EF6CC06F24FF -:10C07000E2557686DD05702930929BE22B1CFF5538 -:10C080006B39FE81CE9F68EDEE37513E33E2F51BF2 -:10C09000B09F32EE0756FF4074DF0BF445F99DB5B3 -:10C0A000D96DC68DC8D3AC3E2C04F97EF5C77B7123 -:10C0B00059F0CDAA37BAE1FAB538C2936C00BD1574 -:10C0C00029473C5170531BFF05DAEB767639003F68 -:10C0D0003273921D6A8727EB8A16DCF76E473F257D -:10C0E0002E761FFE0BF073DF06D11194A16BA79C77 -:10C0F000479089FFCB641FF9096530CF3A1B3E9505 -:10C10000F3112FF7D919E9DDEB1D6FE03899584C81 -:10C11000FC89713DF443FEDDF106FA1F85493FEFCE -:10C120007F04EA9140FFE34B93C3B010FDBE8FF94B -:10C13000BEF845A3A737CAEFC5A8043BB468D3A38C -:10C14000D103BBA39E57F568A962B7D47EEF437BAA -:10C1500005F0F1D56F8421DD55FACF443B91DE66C1 -:10C16000271E9C0EFDC3F71EDC1E44FD9F1D0B7693 -:10C170000AFA2C7EF6FD30A6D17F0BFBB82A92502E -:10C180009FA8764D5C176703FE52F5E5D5D65D9DF9 -:10C19000CE2B24605EA1FA7995E0BC32DBFA9BAE2F -:10C1A000CCEBEBA57C3E4757F0F9CD68372F6EF707 -:10C1B0001F7CDE6297C92FF044A31C7EBB596475B7 -:10C1C000445FEE375CB2023F0DC0F8CD0AB2EB27F8 -:10C1D000A39984719D4EEDF74A0BF905B3B6F1FDB5 -:10C1E000D653C2F0EEB4F1FFAE27EC2194EB2D2232 -:10C1F000433BD4369E56BBBD2A295A63B7AF116F55 -:10C200001867457B5609A843BEAF6CECCEF09CCBBB -:10C210008AE1AC41A47D782FE93160218A4F831FE8 -:10C22000AE8B375898DD6A453A75127FFD47F2F9B3 -:10C230002973091FBE14C4BFFAFDAA2E1E5377F43A -:10C240006B360BE4D754CC1B1E369CE17778DC6C44 -:10C250004B12B753DB143D2738AA292E063E8DED2D -:10C26000711CD75A1E1F66EFB006C42FC2143F368A -:10C27000F07908928D150FE471792BDAB51003D996 -:10C28000B5403C7CAD7CA7423490FF5B6EE67EF00F -:10C2900039819FFF7847B18FEF24717FF8FD241E0D -:10C2A0008738877E20F47BEE268BBB5640B7D54877 -:10C2B000EB64E3308B1BFD19A335C42366207A8D14 -:10C2C000DFB5CA33E06B0A6B31213DC7E5DCBF093E -:10C2D000E773B827B3895DA9DA89FB08934933303E -:10C2E000B6DFF4E57B188F94A1AD086B85C93927BB -:10C2F0007A63FBB508C3FC0F0735BC877196C3F1A1 -:10C300004686FB02F2DB16B2FFA611DEDE14A7ECB6 -:10C31000C258DD008CC7EC598C7CB4372632CD0670 -:10C32000EDA71ABBD845AE7F469EC7F196097CFFA4 -:10C330006691371BE973235B643B6EA5AD85AD57F2 -:10C34000227F8E7F8CECB8CA0730A6F211F08F21C5 -:10C350008C33560EE15307035E09FE2169DE8455D6 -:10C36000BD70D344EA8F742E4FF019713FC527304A -:10C37000DF7AC0C31D393EA303E9E5600DE3817F89 -:10C380003DFB9880DF4111C0EFDEE54918857860FC -:10C3900069120B87FAF14689E05E052C4254F60DCE -:10C3A000308E7568A8407430582513CEDB59200CA8 -:10C3B000C47DD1F285D736CEA08DBF99B06A18C0A2 -:10C3C00006035FCF3EC4D7B393E523A3C84F1AC675 -:10C3D00004E4C3AA880613ADA3415E70FC03A01B4E -:10C3E0002DFE261BBD7C7C6530BE5C948B24E2E375 -:10C3F0007BAA05F227ABCC1DC735A293D57D399B0F -:10C4000084EDE7C0BF90AFE7346E4FC6EFAD103894 -:10C410001FCC51F9EC55BD5C0E4E66C4A79DF1755D -:10C4200096D27F56B2819FE36AFD5E03D9DD398DD6 -:10C43000EF1FC2756567FD57589887F0F2B685E221 -:10C440000782C19744744144021D26A33F092EE28E -:10C45000C064EE27AAFC598AFE4722963C2E620051 -:10C46000E589F6B0ACFE7933222DF0FC11383E742C -:10C470000E68F686C0E79AB88AA8D33B14F714CCA6 -:10C48000BE19381EE1E6203BEAE3C9E6065A9707E3 -:10C49000B633D5733FCBB494FB59B4AF06B0650542 -:10C4A000F73327F7F2F567A4E76CF9423C6BF58B9D -:10C4B0004BF9A7E179B9CE2FB6601C01E35EABB9A9 -:10C4C0003F6854FCD792157A7F61F2228DBF48DD18 -:10C4D000FA2A70BCA6478229EE62417F42E307FC3C -:10C4E000DD5028A31E96138C74FED2C402FD0927CA -:10C4F000E3F14CFEDCA8F88923934DBA7D3779042B -:10C500004B433C14A31E4A4455E35C8AF1BC0B2CFC -:10C51000B41EE366A3C44728FE575CCBCFA505C66F -:10C52000FF2E54BFF72CB6C77A7C3EBFCB4F71B8F5 -:10C53000BF09CB52A77033C87797C3975C281FA059 -:10C54000A84C28EF41FBBF41583084332107BFEF8F -:10C550007916FB97CD561BEAADA783C3A89F050BA1 -:10C56000048A0F2FB27179FBEACBD0F5A8A7D47853 -:10C57000EF92E199ABF1DCD26F92774FB0F646F5CE -:10C58000C0E8DC1218C64F1C309FA2CB203704BF76 -:10C5900037C1110E7CFE9E6F8A15F0B46AE37B13DF -:10C5A0008CC08FE77EEF7B0EE11736EEE7F0EF7C75 -:10C5B000714108271F986004393A57ABF6776082BB -:10C5C00003F7DDFFC0E13AA897012E46FD86F31E72 -:10C5D00022D0BA7F23DAA5E8B6784FB1E11D5E8E8E -:10C5E000601EB49F576BF7A764E746B4D762E8B103 -:10C5F00050F42FB6A63A08DE92E87C2C19FDA083F1 -:10C60000EE6ED118C732B016A40BD8314747FBD213 -:10C610001B93B8FC6E4EE1FDA9F8827E9E4E8EBE45 -:10C62000FE7E6E69DF8FFBDF194F9754E8275BD7DB -:10C63000CF4BFF4E3FE501FDA87E1B38C012EAA993 -:10C64000D3698E77719E737EE318B115F5CF7E9115 -:10C65000F8F4FBEAED2968F7BF7FD51289F66FCEB3 -:10C66000EB3BE34A318EA0F845A79B3E334BF07E6F -:10C67000A55F640ED0D3557E81CACAAD4DE6FC7469 -:10C680003C57DB64CED38CAB5C192770BA7182C681 -:10C690008FD997ACC69F57D278E7BC7ED288F49CDE -:10C6A0006368388EE78FD9101EF70A9CDF16E5BD48 -:10C6B000C378DEA08338C047C9DCEF88E9E7D88FAC -:10C6C000F3DB8CFA1CF9C5C0CF8704B6EF9EC2FB22 -:10C6D0002BEEC2F57CF6417BE9015AF76518442838 -:10C6E000071DAA3697C0F30389230E25771887F410 -:10C6F000F13864238F431647B4CC0363C622522E0D -:10C700003C81F276FBD3AA7C80E8817E29B0A870B8 -:10C71000D0C491C3789C0BE14B1B0D4FE239C2E6AC -:10C720002E2DBF3A80F66159285B0F7276EFE0D06C -:10C73000B82D308EE972B800B6930DB784A64C833D -:10C740007627128647A4F0F327E41F9E48709EC503 -:10C75000F179E3830DE08C309799C7B35C1F88149F -:10C76000CF726504BBDC1DE0EBB482CF8814EE9F72 -:10C77000351B609C03711CFC7C2FFCC56DC178D3FC -:10C78000C23E02F29DFAFD5B1387774DC96EFBFE38 -:10C79000AD89CE9F92A3B5EDC319B6BFD671FC5338 -:10C7A000B1A75D5338BD9CC380BF347A7FC2C860D7 -:10C7B0001D5C34269239B4F1CDA2581D3CA93851E4 -:10C7C000D7FE9E19FD74F5632D2D59D5D7E1EF8B5A -:10C7D0006169E1B4FECFE6EB90AF1A2F7D3A19FD07 -:10C7E000D80DA25D8079CD7A7BE3A743A97789E252 -:10C7F0005CA79A45B247E0DE9AB5FB2767590B9DC7 -:10C800003B36765D44F66F4E0C3FDF3DCBADDFFF30 -:10C8100050E3F21DED9BA03D2BC773311DED9BB482 -:10C82000C5E37F76FF243345590F0F6403F97AF887 -:10C83000CC5E9829CBDBD144F4AADB27DA9155EB07 -:10C840007A0B4C8071DEBAD5E20E82719FDD79C41D -:10C850002C69F64FAAFC600022F1BD23663C4F759F -:10C860002099EBEDCAC6F366867CD1783FC9754B3B -:10C87000932B2A1AED17F8ABDBB290BF1AB2D0FE99 -:10C88000351B6C4EDC0F9BB37434C599C3FD93A963 -:10C890002CAF1F4DFD56F827125CE90F26F823B187 -:10C8A00065EBC7D8CFD3E136B4E71546F955A44BAD -:10C8B00085149C89FB55955B3FBEF86BB4A3367E0F -:10C8C000AF63ACF84916D68FED6333D475C5F10666 -:10C8D000513F2D23BEC842BB5480EB02785EBE257B -:10C8E000D785723FBC2ED486722FE279B20EF874CF -:10C8F0006A0AD72F262F1FEF287F21F5D7BABE4F00 -:10C9000049A0F9ABB0297A8311F5873A0F13187C47 -:10C910002C6FF3F7A3B26A6BA111CFC57F90F67CA1 -:10C9200014E209DA876099347228E999EFAB078736 -:10C93000B30EF4965A5A143D3C19F530F45794E668 -:10C94000F835CAE5B847BC462BEAD110AB0DF73F26 -:10C95000C6E50C904A35F311DFB91B5712E0ABF86E -:10C960004CE8074C8652ABB7A776625FE41483E2CB -:10C9700017D5F2739DAA7E5FF504C375D8147E5651 -:10C98000AB55AE2A94F6EAFB2D02F707E46D3CAEF8 -:10C990005F91E67A12C7DB329C4DDA42FAB425AEDB -:10C9A00030F4971B7F98B185E81C66930CB8AFA054 -:10C9B000D6AF6E9D0797EFABCD63B1D2FE23912D1D -:10C9C00040BEF8E8965B5A1CD06FD3C39999A2C6B3 -:10C9D0004EBD94C2CF35339BEF32E98B5DC112EA75 -:10C9E00081B1B8F790D5E6F7E379488C6B54EDB296 -:10C9F000ACC7F3605561B0CE87EF8FE9E77A09F1F4 -:10CA0000D1B43BF722DEA371E0C20CE4DCD138F8EC -:10CA1000229EB3775841DBD8D10F72BC4CFABF933A -:10CA2000F15E4D9F258D9C1385FEC4F73024B4B76D -:10CA300060F7B30E72D889F8722DE5F2E752E47010 -:10CA40009AC2BF258A1C4E3372399CBA2ADC86F101 -:10CA5000CE924784FE785E8E49A176540126E4CBBF -:10CA60004CE44FCE97E5FEAE8A3CC72BFD70FE0F1F -:10CA700094CF4A7F24B553E5F4E534D7216EE75AC5 -:10CA8000B216C0B86E03B946BDE75AD8230BE5A469 -:10CA90008D4FCC36E427E09398520D1FD435FD68B6 -:10CAA000443E310D13884F2C50E669F8C8D9EA9FEF -:10CAB000D8F2BBA15FB528DEB09CB5D57F95A2FAB0 -:10CAC00029D7C6EF1F28ED4B42C08FA0F84F18C3DF -:10CAD000F8DA852889E2A47397C1200105734D9E79 -:10CAE000648CC3CCBD3F88E260A507AB97844AED58 -:10CAF000E975B73F83F69727FA93A83C90E83A8DFB -:10CB0000F898E6BF53C163C635EDCF653B78DCCD01 -:10CB1000E4B6D8D7C563DCCD25D27E5C6F667B9248 -:10CB2000EC94BA1FC7E36E18CFC3F85EE0FE1AC6D6 -:10CB3000E1703D6D8932E8F609DBC5E386EBF7D39A -:10CB4000CA9B3E196480FA53F10E8ACB79FBB88CEC -:10CB5000A9308FD913DCAF9BB4FB6C0A1E1B8C9ED3 -:10CB600064B4A30DD51C3F0D2BC402DA6F622CB840 -:10CB700050735EF76A7C3CDB9F48F851ED8BAAB797 -:10CB8000B7D7D0A1CF56FD7D35BB53A1F07B05F2C1 -:10CB9000BBBDBD9D51F935909F55FD6C8A3E487ACD -:10CBA000E8367805FD07555F17E40D1D86767EE8AB -:10CBB0004B895BFF0CF38F4C7365A502FFDCF24AD7 -:10CBC000EFAC3500DF66741B6D21D7A20F7F349167 -:10CBD0003E7CA490913E8452AB0F4D9DF8E1B9A9E3 -:10CBE000D7A7CF5395F6E0C772FF10F4B5B6BF8A4A -:10CBF000B4116370FC85A9DC4EFE52E3EE4C8F1736 -:10CC0000A6AAF2796D7AFC66A5FDD5F4F88C54AE2F -:10CC1000C703F5366863D2DBE7DEEE4B71B2C30CB7 -:10CC2000F43CDAB3C6606963BCE69C7B9770B75688 -:10CC3000AFC7F49B3E03F9FD1AF4FA7D88BF7F5716 -:10CC4000AFE7176E26BF0AFE9CE36F86F5C76F61DC -:10CC50007D87F047B0BE8B6F2F0F817210C8F7B081 -:10CC60001ED9FA318CAFF9A93E1477003920BEAF36 -:10CC700000BE473950E5A572EB8070DC37607F114C -:10CC800019EAFF403928C87BC588712AD4E388AFE8 -:10CC90003D20F3A86702ED843FD5B50AE7AFCA830C -:10CCA0002A0757E7A39D265C979ACACF733D0FA525 -:10CCB00056CF77E6CFFCE13AF9FFD1D46BF3035EB0 -:10CCC0004DE5F7207E41FE7935F5DAFC82D752FF3B -:10CCD00023BFE02DE21FD49FB87EBBFD437BF87CD1 -:10CCE000CE3F742E11F8210BE3CECD837ADB314E8B -:10CCF00073FB15EED7834E27BF3ED0AF9EACE8BF87 -:10CD0000A94A9CE0409AB32595CB2BF9EDC3138338 -:10CD100007A0BDBA567F6F725435C338D35428B5B7 -:10CD20007AC28274EBC05FFF6BEAF5D9EF3DD7485A -:10CD3000DFE3A9FFB19FE7BB167D90E4B04E447CD2 -:10CD40007EEF3132C4D3D5D603A6D51CCF2ABCD8AA -:10CD50006354ED6624DA4DE08FF3FF097F8CCD6BD1 -:10CD6000B86805BA86A7198B301E78279EB5A078BB -:10CD70008669952309F50D53F70528DEF191A8C2C0 -:10CD8000E68323611CB73FC9DAF60DA07ED4B0F06C -:10CD9000D6F888C0DADA87A5890757D0B8F97915A7 -:10CDA000E6F21AF93E990267011CAA817302E0B506 -:10CDB000BC7D98D1CB6CDA7E14FD33CEC6F705DA94 -:10CDC000F6F37CF95DD1FFDB2AD8707FE19E61E745 -:10CDD000CC18CF199BE7DD1B0BEDE2D3428B42C091 -:10CDE000C4DFB355A0F10ED814B54A4EA2235B0E92 -:10CDF0003C6F589EC3F74D2C0D4DF98E0EF87040C8 -:10CE00009ADE4EE19FB11BC5C7E8CFD22030731622 -:10CE1000EF2721FEDADE47FAD1FB09F4BEC712750F -:10CE2000EDEFDF358C39DC1DF0D12D698A3EC4B8B9 -:10CE3000B0DA3FD0646283E0E8286E73ABD2BEC53F -:10CE400060A86080A7F19BD25661DC6B14E37C5133 -:10CE5000B829B548E6FCC71C01F3FDB9F166A7E99E -:10CE6000D767F827E9DFF7FC1CBE86B6C39742FFF9 -:10CE7000323D9F841B9DEF7E0FE3088F126CE8A765 -:10CE8000563A8356B070A4BBC2D7F2C022C73098BE -:10CE90005F10D3C5F15AF95ACE2C42BEAE646AFB7C -:10CEA000EC55487FA7A1B53DE7F346A1F5FD342336 -:10CEB000C34FD0FB733665ADC23839D083EA09362B -:10CEC000FE0C9F3704C0C302E4827198E412F5326D -:10CED000E027B983FDDBA50A7ECF0AFC7C53CB0893 -:10CEE000EECFB524F0F2C534EEBF3DAEE0F169A55A -:10CEF0006CE9A2C143AF363AC39F07D7039A7913AF -:10CF00009EEE8E52E62D4F2C1A03F36A8960FD05C2 -:10CF1000E093759BC6AF5AA4E193E7374D2C423C92 -:10CF2000B4F627171E443CDEADE0E9C54D130E22D2 -:10CF30001FE1911394B78A1CBEFF6AD9FA7187F278 -:10CF400036B73DFFC8985FA1821809DF131CA62CD5 -:10CF5000DE4F4207F859D0FE7D47C0FBCC14753D2B -:10CF6000EF2BF4191340BF8200FA8D0C808BF57003 -:10CF70009B1F0C3D83FF54B263E5E26E183FDB2438 -:10CF8000D01D2BD0CF66019E37A6DD5B14D203F9EE -:10CF90005432C5425B4FDAD483D6BE208FA8BF4837 -:10CFA000FFBA485F4F443927785A91E346E49BEA39 -:10CFB000C531D07E6F5AC92ABCF77ACFA2952644D4 -:10CFC000FA0769335619A1DFBBB3FEB417FB330A66 -:10CFD000A507C7083FC3A7F501F3581B00CB01ED18 -:10CFE000575D459F2F0A78FF9180FA1501F0EA00FE -:10CFF00078A9FEFD6933F8FEE534A01F22EE6AF23F -:10D00000E24D6B5D37B4DA2F01EDD9877A7EBFBD73 -:10D010008EC327373D50B4344403A7FDAA48CBBF85 -:10D0200026C55E4C8E723A3AE2DF439DF14F5AA01C -:10D030005D9375E7120F33A6B3BF7B443DDC24AA92 -:10D04000F2B5F0E0BC74CD7EA05C5B84F194CEF7C9 -:10D050002BE422DCAFB8FD71B57D4D9143333FB574 -:10D060007DFEBFAE88F8BD2B6935451B68FF4FD9E3 -:10D07000BF8BE0E52D97AF84215DF2F1FC28D677D8 -:10D08000F124CF4DD7CC8F35A4E0FC9A1EE6F70DE6 -:10D09000E53AA007C87909B3D3FE775378F8821729 -:10D0A000A0FD9E87C50568BF0E2F88A4F346E3FB4D -:10D0B000727F7B4F789F6EF701DC143CD58C71D565 -:10D0C000A6474751F98EE858E203E4F7EAFB5851C6 -:10D0D000485FAC0F27BCC4BCB4ACA816E420B6AF04 -:10D0E00044EFBB226CDD76A01FBADCC470FF89312F -:10D0F000FB73C427BFB3909F3AADB61FEDF794FC06 -:10D10000BE30BF07B42B596CA2F83FFCD17D0CD7C1 -:10D11000F25166AC9FB14829E55BA9DCFDD31B1F2A -:10D1200066D0BE8E48E77676F9238E8324B3AFE5CA -:10D13000FE745FE1A8925F656B5F576A5F18C7D79F -:10D140006792285F0AB3496113D06FBBC191D6378C -:10D15000BAADDDEE9F44DAAF7AEB4C4937DCDF1B2A -:10D16000D897F3CB2E7F49B7128D5D2F3D6B243CB2 -:10D17000EF364BF3506FECEED25B90496E1B2231D1 -:10D18000CE3A43F19B814F16BCD1011FF6E92B1219 -:10D190005E8E5916E05958D6F4DBE861382EF5BD9D -:10D1A000EC83AE3ACC1763EA250DD4FAC7B9C9238C -:10D1B0006EC6F1B6F1D706D2E7E41F033CBAEFBA68 -:10D1C0005532D80FB607FC7A1C4794231FF9493D06 -:10D1D0008FC7621A52B47185363F74A122FFBCDD3D -:10D1E00057783818BEFFD5AB4174EEEB2BF98B5056 -:10D1F000AD7FACCAC7CCB0FF39DC42EBE2704988E6 -:10D2000003BE31D61C7F08DE2B7DD6447AB3F4D919 -:10D21000E8477C580FF4C42DC3C0EF3EDF979F074B -:10D22000E85C3EB6148DECA5958FCD4538DFCEE495 -:10D23000637ADFCD9DC8474D37E4A3FC674D74BECC -:10D24000BAB84BF59D18472C36DCC8EA607C239EA3 -:10D25000FD5537DC6799F9AC85E8EA0D0D3DCEE761 -:10D26000D5271EE7D56A7FFA727DE5ADCD257B21F6 -:10D270001AC03B03FD2D2E31D17A44EC6626BD2722 -:10D2800086D9797D1716BF10ECF2E2D01C09E9EBC4 -:10D2900056E401EA25E4B3BCF049B7E1B996C30B03 -:10D2A00012691FEC6416DF079BF5D0F361E87F7EFF -:10D2B000358F9FEF9E8DF976709DFB6FEE7B552924 -:10D2C000F976FEB7F6BD9EE8ABDC1B6ADDF7E2E758 -:10D2D00040F72CC8CCE278619205F1143780F072E7 -:10D2E000AB95494180173182A5A0FE51F7BDC45FBF -:10D2F00073FD241A045AA71FAB91297F415E9895AC -:10D300003FFF35BFB7273E55C8681F2CAA9AF6C104 -:10D310004211AF18BF159813E5E768903DEEFE7413 -:10D32000E4BF20A2E7CCE7667DFA872CA4DBD828EF -:10D330005D3C41E13FF5FD13B537D1F84E08CC8691 -:10D34000F63EEF8FA923913E4DA2EBA9BB496F0694 -:10D35000D3FE39B3797F3718E099B5B0CE66C837B8 -:10D360003DE212D2DBFA99B9F0E114A477DE1F8313 -:10D370003C78FE66C6A2A0D5780EA3BC91DFF39ED2 -:10D38000B6EC7B3A8FCBE28DD518E7FC7A51103F93 -:10D39000A7BE7530F1CF34033FE7C2E2CC145F2A59 -:10D3A0000F51E05E39046BEE2F99911EEAFD9BBD93 -:10D3B000A857E0FBC7557CA0DF887A573D47CFAA26 -:10D3C0002594FF6283D0E139AFBFF5E5FEE9B438BB -:10D3D0003B9D17AD78CC625F18CFE92C0EC2EF32BF -:10D3E0005A1755187CF9ABB15F0393B6D970FDD0CD -:10D3F000528AEB6DB63595F210541999D11C01CFB4 -:10D4000025AECFD4F1544985B7123F19D921630411 -:10D41000E2B1E5D316E48F85A112C6452ABADA5DDA -:10D42000D46FA8D5C6ED84F25D1C7B22F281DF1C8F -:10D43000817CF0A960B0F0FC030E03D49F63BCBEF6 -:10D44000F53B8B96A5D3BCAD36C3881EC877E7F3F2 -:10D4500057C37BB73229A107DE135B1679E724ACEB -:10D460007F4D24BD04C2F4580EFA7BAF8999B84EA3 -:10D470009DB66C0FCD6FCEE6017883804D7BFD00AD -:10D48000D9A7390A7F7995736B25006F463C2A7AB4 -:10D49000C125B26A8A8729786CC5AF525FB1CC4486 -:10D4A000F4A8586C213A57D4FE8DFAAD086DE98680 -:10D4B000F4A8D866A2FC1DD61BF83C4A6A7B0F3B39 -:10D4C00004E32E3185DB0478542E8F35235C5E2FE8 -:10D4D00010AC7EAF62D95FBB19D2797F585A0C7CF1 -:10D4E0009FB5ADDFE838B467A75F8D8C9BA6A1FB25 -:10D4F000E945DBC370DFF968902719CFF9FAEE0F21 -:10D50000B2E3B942359E767A5132BF0F646B09C5DA -:10D51000FDEA19F31223D0CE1DB679CC587FB8217D -:10D520001E8FCC3187CD360C6187F146824F2BE7B9 -:10D5300048E80FF3070A9C6FCA5FDD634E80EFF582 -:10D54000BF81E3E7EC6B47F70E417C001FD950FF2A -:10D55000C4B5A4A01DAE30B4A4C4227D5E16C85FBD -:10D5600080F5A903F38F54225F0D047DA8F055E5E3 -:10D57000D6EDF3513E2BDE3C998F783D3B969931A9 -:10D580003E56A1CC1FD68FEF1AA17DC59675F98C9A -:10D59000BFFF2EF29D6AEF015E6402B8D9CCE18C28 -:10D5A0001BB87E6E367B29EF5DF39D8CD1FE999181 -:10D5B0008DC47640797E0F401495FB69D531137880 -:10D5C000DE3D597B7EAE12EBD3DBEA3BE39BF137CA -:10D5D00018143A5BC82E8D47BC00EC5DB62D0CF9D3 -:10D5E000E2EC6B7BF60E41B9D822D898561E54391E -:10D5F0008CF3F17AC0DF1388BF2DE7F3310FC5EC50 -:10D6000033A112D250C5932A6F2A5EAA18C7838A03 -:10D61000972AA38227A5DEA9E0A19CF9A83F76A6B8 -:10D62000BFB411FB7FF347DA6F3B3B8D09FC9C30A5 -:10D63000CF8BA6CECF15A1DFDFAFBD81F3FD146583 -:10D640009EE5366E17CBA398543B80F8CC6156F319 -:10D650004B4293B39B8FE8C6BF5A9183567AE33C03 -:10D66000609C5E03BF2718A8BFE6297C75A476B22C -:10D6700007F5CA6C19FAC94279B04DC17D4EF6BAA8 -:10D68000A8E86FB0999AEFE6BD7284F81074971409 -:10D69000016B16D3261807FA5F677A53BC30AFBB0D -:10D6A00097E6BD718C8D19409F1C11BCA13BD01E0B -:10D6B0003C24929E52C7E9903F247A381AB87C22C3 -:10D6C000BF607CB0552F048CB75619AFC560F7E228 -:10D6D000B960B650A0FB6BE2C2B3A187B8BDA34846 -:10D6E000625BFF37BD8BFB918E8B61924035762359 -:10D6F000B6ABBC189680F6FB88127738B2787B58A8 -:10D7000089860E4F75F69D258325A47F5EC8A18767 -:10D71000518E1E53DA359BED2317A03EB81426E137 -:10D7200079A9E608391DFDA866035BCA22381F1ACD -:10D73000BBB5E10FE485F007F5D293B636B954C70F -:10D740000D74F320DDA0BD83CB919DF6312AA3F8A3 -:10D75000BEE8D5E529D34BFAA95690D667B5B5539F -:10D76000EFE53DAACC9B64A45B9B3D40FE447B67F8 -:10D7700051F21805E641BDB557D738C45F5588D575 -:10D78000804BB8C0FA40B86D3D556D443F9F2D8A1F -:10D79000D9ABBD97763448A6FB67BE1E225B0FF45B -:10D7A000A8BDFF7D7E9EB791DFDB52ED34FCAD68F6 -:10D7B000E53F78AF2CEB7C3EEAD717732D74AFA909 -:10D7C0006BBF04FACE29D6601E8EF6FFDB96FC30C6 -:10D7D000A96D7D72D3458F184EFE42BC6E7D507E82 -:10D7E000E65D92E70AD642F7B1A72D3B307630D2FC -:10D7F000FB25139D1F98511F4F76EEE486E999385B -:10D80000DF698B93099EB5F13E0E2FE3F90FA72D2B -:10D81000CE7E01FDAFA3418E7CE467DF4AC186EB7B -:10D82000ABA11BB31FB907EA8786F6E98AE3FE6A54 -:10D83000C3D1B148F7AF1688A49F1C1B9EBC13EB45 -:10D840001D3B44BC3106EB19DB2398D79419C36DFB -:10D85000E817A8E70BEB4C5CDF9E51F4C231454F53 -:10D860001C53F82FAFAE2E05FD25DF3AB047B8EFB9 -:10D870006DF695D2F96EC1665F0FFCF2AD2013CC48 -:10D880006CB684DA5CBCCFB296F2E39C4BB6D8D0CF -:10D890004FBED7C2ECE8D7DEBBBBF7405C2A38945A -:10D8A00075D5D848FE5D155FEAF74F2BDF65E28A34 -:10D8B00052DA7788941250BF352BE7C68F2AE33DA2 -:10D8C000B9E8A53BD12F38B929398269F07E52C910 -:10D8D000D3340BF4E0960ED67BFE1BD4B8839BBEEC -:10D8E00053A6C403F799EA7B61DECFC0FB5D27D660 -:10D8F0000559313F6FE03DAF13266E3FDADDF7DAB1 -:10D90000A18703F3DC068EA7753D1378FFBF5F4840 -:10D91000877EBC2A6781EFB7BB4F9E746DE7AB3043 -:10D920002F19DEF7DE7303A3F74606FFEB0DD4D7FE -:10D93000A5F5161BDEBF3F1624D17A48CE66D24627 -:10D94000B43356291CD7F3C7F665D2F9BFD22F19C5 -:10D95000C955E956D18DA98ADF5D99FAF83080EF73 -:10D96000DB6AB2E3FB2757ADBC938B993ECF420EE7 -:10D97000E3F23913D6491E5BDBBA2870BD347BF560 -:10D9800066BA47F84BAD97D4385220BE73FBE9F323 -:10D990002D04DE9FDB0D6C9333B03DBECFD4B86851 -:10D9A0005DF45D4D1995B90DEBF26225BC4F71E444 -:10D9B000B1A12837A1E1140F3953534D9B78DFED06 -:10D9C000C8BC8CF743DF0A09B7A1BEF8AE66817206 -:10D9D000B940E113852F6FDADA24C6326ADF3814D2 -:10D9E000DAEF0A09A7BB2E498E9C70B4F32A5D03B7 -:10D9F000EF37ABF33BF510A7AB3ADE539BA687A1FD -:10DA0000DFD9B426B23117FA9383C36DE86FCF54D0 -:10DA1000CEBF1C5FCDF5CDB7D6F017C6E0F999B5EE -:10DA200013BBE1BAEE3E93CF6C877EED6F1786E1B4 -:10DA30007AFF1BA3370CEF1B7F03ED3D68278C6E2D -:10DA400011F5DC900246FB78433C4626C5D3963957 -:10DA5000F145EE19A31BE97ADA7371CF15E4A3330C -:10DA6000068A770166F65C81F6F6D03E1427BC6F15 -:10DA7000275F6FB27F75E1F501F7169FE8C7F5D212 -:10DA800089B56F8CA3F5F906930DC7F9DD86BF76CE -:10DA9000C37338B3193F5FFFED2681E6311BF831C0 -:10DAA000281EF5038F83CE06BD6F15DAF361DEA65F -:10DAB0005AE2C3D9C08716F4D31C3C1FF36CCCC701 -:10DAC0002CB176F93FBA2A7C3707F80EEFEFFED279 -:10DAD000793F96F70B3CB7CAF950A5BB8A1795FE5C -:10DAE0006D7CC874F905231A060C8F656DFA40BD6C -:10DAF000DFC18CDE15784F63BE185A8FF9AAF61B6A -:10DB0000ABFF48795B6423DB48F69CA561BEBCF99A -:10DB1000E20D768C07D699AB5BF3BA607D605E1739 -:10DB20003184BF5F88F98961BE21E9F1F4BD09360E -:10DB3000FB2844B729CA4B710131CFE0A07B79752E -:10DB4000165A3707EAA15714FADE86BE03FA3DFDDE -:10DB5000F8796DF5DE9F5A82A1E98DFC5E181C7183 -:10DB60004982263B5EF9FC0EDCA72D1C1AF1AB4462 -:10DB7000F87E53BF2377E0BD8DC2CC886D0900EFDE -:10DB800079E5EFBCFEC6886C13FA01C2D7778C44E6 -:10DB9000BFB19FE3CD7E9AEFA8FDC2F39DF8FCF3E1 -:10DBA00038D7DBFDF8BE6929D2FB9C10C6F3BD2532 -:10DBB000F9280EAABEF7B1C00EBF25B4C15E138B03 -:10DBC000C3BC06CDFDB83EEDAC8C4A77ECE5DFD7A3 -:10DBD0003F470A7D8FEB4C65FFC76095CCE8FF3966 -:10DBE000ED663BCFAFC89C56F0ABC62BFC5B62BD6D -:10DBF0003C92EC6F35B35B3081C952FD7DACBE6D9C -:10DC0000F7F6D65ECFBD3D26F33C7C754A1EBECEF0 -:10DC1000EE510A8DEFFF88FE65E0FDA9CCBFB4BCD4 -:10DC2000897C320EF80AED45560B87C72B7C52B122 -:10DC30007D2CE57B9EFBB1C98D7EC22CC51F4B722E -:10DC4000756112B4BB04F28B7AE1CC384F0AEA8FCB -:10DC50001335AC3E09145681D5E543BA34C7BF4FDE -:10DC600079D14EACAD0B43BFE72CAC27C64017E5CE -:10DC70008A7FCF2E8B9E5BD00F8EEFBB7EB986DF67 -:10DC80007EECC7EDFF99784F1CAE6FE4780BCFD7D1 -:10DC900078790FE5792E48189D8D71A4FD353BD814 -:10DCA000D1E4B6F73ABB8F32C43082A56BF625C7F4 -:10DCB000193B3EA7F1AD9A4F7303B7DF16633DE5FD -:10DCC000D1025256D712ECA4B8520CF228C687A53E -:10DCD00007085E328BD9E81E6BDB3E1DDD0755E978 -:10DCE000EFB05F1989EDC601FD51DF18AC3E23C2CC -:10DCF000CE027E3EA52F100EF5894AFF51E2238FFA -:10DD0000211DE62AF7B8E60AD51C3659E99C6BA016 -:10DD10007EC4B86631E94D796F2EFA63A02729AF2A -:10DD200082A21725F81FE545CA5967A66657CF8B0B -:10DD3000B437F73FD08F19E9FA3CE22A9D54FFAA85 -:10DD4000333AA97A12E835E87AE8A5E6299BFB2C54 -:10DD50008F77CE7D767ACC40C21B481CFA43317F48 -:10DD6000A2B8CA4C650E6C6D24F1B1698453427D32 -:10DD70003B76472C93E0D1AC1D029D6F1DB32392DF -:10DD8000E0307F0F9E5749B1F7635FEC3E02E393AB -:10DD9000275FF8621EE6BD1FF35B46F16343700820 -:10DDA000E59B104728791CC490F7F01EEB05C95875 -:10DDB0008DF6CAC9DAE50F3010FD9BF9395958E5DF -:10DDC000C99C4EFCDEDFDC7DDCCECF1DCEF7052FFF -:10DDD000E01BD0FE429148799A9E0ECE20FFADEE18 -:10DDE0000E13DD8F60B2E3135C574D52F8C112037E -:10DDF0000B4B0DBD822490570D7D1E0D7AEC3D1707 -:10DE0000F4EF857597D013FCD8B4085DBD510EFAB8 -:10DE100006F3C79A62449B1BC61F6AEFA9EBCF2982 -:10DE2000969B309EC25CDC8F56F98B89678C746F31 -:10DE30007E18CF5F71C724FD3D49D3B0F323C9DEFF -:10DE40000CD3FBDFCEABE46D5AA0F2535FD657C9BB -:10DE50004B4FF6FFC2417E3F4462CED5AABCA0FE26 -:10DE600007EFE669C4CF9DCD26E696087FAF61FD3A -:10DE700005D962C37840AB1F9E04EF45A191B4124F -:10DE80009F635E50ED3C312FA8162F9817540B63FB -:10DE90005E506D7BCC0BAAADC7BCA0DA7ACC0BAAC6 -:10DEA00085312FA8B63DE605D5C2981754DB1EF381 -:10DEB000826A61CC0BAA6D8F7941B5F59817545BD6 -:10DEC0008F7941B530E605D5B6C7BCA0DA7ACC0B60 -:10DED000AAADC7BCA05A18F3826ADB635E506D3DE1 -:10DEE000E605D5D6635E502D8C7941B5ED312FA86E -:10DEF00016C6BCA0DAF69817540B635E506D7BCC47 -:10DF00000BAAADC73CA0DA7ACCFBA98531EFA7B646 -:10DF10007D0B5B948C766C67BCAB393D1AF79DBE6C -:10DF2000257E3E742FF033CA61F3441BE52FBCCE2F -:10DF300075624BBAB26E51F8F7120B9982E7D03B7B -:10DF40007B5FE5CF97F09D6CB2074B897F59683DA9 -:10DF5000FA738F1A1D741F4A6EE0F7139991FB0133 -:10DF6000F345C5FF51F242CC1725F2033077B0518B -:10DF7000339EAE0E2B336AF0105960D3C1D1CE1848 -:10DF80005DFBEE93245D7D0F579AAE3EB6CCAE831B -:10DF90007B57E7E8DAF759E0D0C1F17281AE7DE254 -:10DFA00052A70E4EAE9FA46B9FBADAA5ABEFEB2E35 -:10DFB000D3D5F7DB54AD83FB372CD0B5BF7187AC1D -:10DFC000AB1FE059AAABCF6CAED7C1D92DAB75ED65 -:10DFD000071F72EBEA73BD9B74F543BF6DD0C13769 -:10DFE000F976E8DADFE2F7E8E0E16C9FAE7D9EF5D6 -:10DFF000631D3CCAF699AEFDAD314774F5A3A593F8 -:10E00000BAFAF2D3DCBF6775B03EC0386508CFAF4F -:10E0100051E9610DE85FDC9E765ED7DE1405EB0505 -:10E02000E09F0AD087E8F7FDD0258EF231B3EA30C1 -:10E030003BDEFB964754FF517BCF7BACFD47DDF7C2 -:10E040009F0E0EF304D1FAC24AF6F6A6FEFCBE59A4 -:10E050006B3E11F53E3BF3B198280A09F9D03F1207 -:10E06000F01796000E73F0BCD0E00791FF6403BF79 -:10E0700008FDCDD67591213E1EED72709B5FDCEBE5 -:10E080008A26CFCBD5FCE2DBF1DBD994A7D7D11F11 -:10E09000CAD90D9BF3719D358BC94B703F51CDB3E0 -:10E0A000B83F481FDF52CBD156C0AFE67BFB82EAB8 -:10E0B0007B0DFC19791F6D3D43ED5BFB55E25F0263 -:10E0C0004C76AEA6FFC760FD6704B9AEAF01F90399 -:10E0D0007FE8891A1BC1AB6A62087EAA46A27275E4 -:10E0E0004D1A95CFD4D8A97E6D4D0EC1CFD5380825 -:10E0F00076D71450B9BEC649CF37D44C22F8851A0A -:10E1000017959B6ACAA87CB9A69AEA5FAD5940F0F8 -:10E11000EB3532950D354BE9F9969A7A82B7D6AC44 -:10E1200026F8CD1A37953B6A3651F9E79A06AA6F59 -:10E1300004FF0DE15D351E823D35CD04BF53D34252 -:10E14000F0BB358708DE5BE3A5B2B9E65B2A3FA8E2 -:10E15000F151FD5F6AFC049F51F621E6F71774F751 -:10E16000F154D8C88E717F0FF356601E861CD3778A -:10E170003F971F37900EA794FE4D23C05DC23872A3 -:10E18000CF94F5759A75455D7F1EB7AC35F0FC2DC3 -:10E19000B53D99AD8EFC7607E3E7B4B8DF3E13FFDB -:10E1A00025C1D3A89ABDB8DE28ADE679CAB3911FC0 -:10E1B000D3881FFF725DEB34655DB025D1F904F2A1 -:10E1C000230B717F1A9FD5768FFE40A2EBF7F8FCE8 -:10E1D00042F57D7BB1F54C9B3D053F32D6E289C6C9 -:10E1E000FC5FBE7DA27DBDD4F9F7AA94FB0F9DD63E -:10E1F000EF3AD90BED55C14F22C5F5F79B4227E108 -:10E200003EFF8B0A3E5EEC6FD0957725395FE88F35 -:10E21000FBFBC9D52F3C20B4DDDF1F8F4B7C90EF7B -:10E220004226511E9C89CCF11EBAE077802388F0EB -:10E230005D4CA6F24482EB4F389FBB610182B06B0C -:10E240008825AEA3F9048E67A7329E9DCA38D47282 -:10E250006E927307F6772CD9A11BCF8B4A7EA171E2 -:10E26000CCF71C8EEB1F6F9F3F2E24B6E1BB359E73 -:10E27000C2AA294F4631E3F19447312F46545B5EE1 -:10E280000C75FD50BC8FFFCE11FDA1FD9C1F4FEB07 -:10E29000DBC0BC194B86EFE17930603D86F77F8BA0 -:10E2A000EFFF15E95FFC3D28BCB73BBFCB61CA332C -:10E2B000E39D05BC1A4B793578DE1B17203096F2AA -:10E2C0006A50BD7003FCBF078ECB9A66A4F175A19E -:10E2D0007C274F07EFA7BC341853B074C5BCC7F1F7 -:10E2E00034CFFDCEF3DCEF8EF2D1FDD42D89AEAF6D -:10E2F000FAF338F953991827427EC2EFD8DC747EBE -:10E300000DF8C92C008A6646013F75E06FA87C5362 -:10E31000A9DCC3519F033F9E407C7FB773701AF204 -:10E320004DD5AE5C09F15D67E0F7E9E40F947D41FE -:10E33000E5F710C4F0F47574EF009D71A46F6E28BA -:10E34000DD3B6812D982CD1DE8576B06A7F3FE1896 -:10E350009E4FB22E607F52C8E07417947663DFD967 -:10E360004779C82A9B79BC9A6579D39D1D9CCBAA15 -:10E370005AF0DBA79234F3A8DA71849FE762DE7467 -:10E38000ED392E49E957E53FD11CEA5A17A21D5F26 -:10E39000AB1C5832B2490E8EE3BDEE711629FC2E2D -:10E3A000817E1FEC3BCC2FE3FAA38DCE03AAE702BC -:10E3B0006730279533C17222DF3BE595747F7E3647 -:10E3C0006BA0E79539D3E310AE62BE9131B83E5AE7 -:10E3D0005AFB1E868326D6AF1CD503E635C13DED1C -:10E3E0003D2C0B3708C76589E42806BFEF15AA172F -:10E3F000F784EFDDF3EAF0C518B71E27723AB00FC5 -:10E40000391D8A819FC588F6F303B9E993114D72CE -:10E4100043E357E5A6782173E0F903F57E48AB1C8A -:10E42000E5CCF97B2CEEE1803F89FC5AB5CB12415B -:10E43000EB53CC3383FA4A919FC546EE5FCA98DA14 -:10E4400094F427F7374C0E259F17E3FEC81C99AFAD -:10E45000C74E99B8BC9DFA2AD48DFC3DBFCBEB7159 -:10E46000241F26553E7E9A42E77B18F81F37B7F7E0 -:10E470003F5AF3CCF462E46FB03857CCC0C4367B5B -:10E480007ECAE01E14C6F3F23B105F7B63F8FA7994 -:10E490000EE6A1C1FAAE4E09E3A5A7A2AD745F28AE -:10E4A00030CF1963769A9F49991F8C6C12FAD31654 -:10E4B00025AE561730DF1F82E268BED270D6C0D0BC -:10E4C000B130DAE4E928F70F703B31BFCB6F5CF86D -:10E4D0007D6F10B30943693E148F950DCC59C7E386 -:10E4E000B334BF0546AB0DCFE52C99267A05B213A0 -:10E4F000304E8CE74559ED3CAFAA9A7F3B70BC0E7D -:10E50000FDF8AC710CE7E710992F68281F2F8E4F8C -:10E51000067A107D009EA6191FF4EBA6FC3FC1925F -:10E520000DFDB0E67F3DC0E3CBB5DC7F84F16F220B -:10E53000FAF480F1C75E7DFC26645118FFDC0CAE56 -:10E54000A7EA700751443BDB95F4EF8420E7FDC850 -:10E550008749AEE5BDE6625C23D762C7F81DBB5CA8 -:10E56000D70BF554089328AFD63807CFAB05DD2D70 -:10E57000427E28C4BC7536F203CE68F3B0B180F891 -:10E580001A9085E2AB1330BEC6EF12BD8BF1D9896C -:10E59000CAF9E6BEEC4B157F145F13717C14AF769D -:10E5A000D1382D4859288330CE437470D33C82999A -:10E5B000478967B7907FB052E1C3218718D9892175 -:10E5C00021DC4EEC3AC2DC78EEABE9C73BF342A16A -:10E5D0007ED77923E929C013E503FCF35FB95DD940 -:10E5E00075F2782CEE07D4FEB83716FDC45D269779 -:10E5F0005885EFE75A6C0BED6D718DC643213CAE2B -:10E60000A3C4F96E52E6D9C85AEAAAA03EA787C8A1 -:10E61000300E987DD0138CF28C396A3BDA6F1C7601 -:10E62000D1ACFB5D0B934D0FE7300D1C8F21B280F9 -:10E63000DFFFBCCE75EE6B199DFCEEE799A86BFA77 -:10E64000DDCF2C651E8F6638DFCC20BB364154F001 -:10E650002E20BE400F3421BE9FA930D3EF1A34556F -:10E66000987B7835E3AB9FF50FC2EFEE7FFD83EC2F -:10E67000D6EE6C353F4E43103E37CBA114777BE688 -:10E68000B281E26E6BCABEA6F5497D0EA3DF11AB67 -:10E69000BF5C427EC0A502869B48ACF6E6FF53866F -:10E6A000F0E33759E97B81E37F1BFC790F10EA2DFA -:10E6B000F0E73DA9E0AF803F8F30DE67C5721BF801 -:10E6C000F358BAC19FC7F239F0E7B11DFAF3583ECB -:10E6D00003FE3C96ABC19FC7F229F0E7B1DD2AF0FB -:10E6E000E7B17C02FC797C0EE3CAA3711D62746FF2 -:10E6F0007F6170D832F433243994FC8D8F1C03BBB6 -:10E70000783576F6E68B061D9D879DD1FFBECD90B0 -:10E710006311BADF3FC9F9B2A7AE7ED0C1045D7DF7 -:10E72000BCACFF7D9B3E0B7EFEF76D62CB4604FCCE -:10E730003ECE6D01BF9FA3FF7D9B68E73D01BFBF3C -:10E74000A3FF7D9BC7957C992A1D53A4D782902F48 -:10E75000D6944D08671DF8176AF984420F157EF2AA -:10E760002171524771E4F01BB9BD7FE72BCBBE0D81 -:10E7700080CFDD2CDC8971F7DD0E03E9A5675687B4 -:10E78000501CD6E21D7212F967B78349C83FCF5CAF -:10E790001ED105C7331CC888CF63CBB87DEA79A3E7 -:10E7A00044FC1C5BE613F1BEE82D977D76E4C72799 -:10E7B000C3F8EF6C41BFEE85D0DF3B6307F5C5388A -:10E7C000CE3321C0CF286F1E5F7012C0E1570C0CF2 -:10E7D000F523D84ACAF32FFF2144398F7A85EEC337 -:10E7E00085A34E07BDB4BB8C7F3FC57B3958EB0F6B -:10E7F0003DFED3D5F0C288AF3AADBF6D76028EB77D -:10E800000DEFA01AA14C6165EC31C44739979FFA0E -:10E810003203C9D3259027C40FCC9AE8C25AF4F228 -:10E82000FE04CA87960EE509CB709ECFAC32D26E3D -:10E83000D928F1D57D37C22B6B0E8AB4CD2ED97C69 -:10E84000C11DF977EAB8D738F8FC22ECCC80762ED7 -:10E8500002F0E9A6FD6C7BADF6F7ACFEA0C8E7EFD1 -:10E8600015F97C5AE1075C6F233C4A5C3B3A05C7CB -:10E8700091C3F535D053C0FB58976630FA1DD1DFF0 -:10E88000172574E928CFF72A651CCF29F35A8BFD89 -:10E89000923C73B91F25160FC77ED63819E9F1359A -:10E8A0008EAF6B316E77A988F7DBE711AF80F8ED9B -:10E8B00055ED13B0FFDEF33C54BA9571F62C6BA105 -:10E8C0007AB53FC9EEE6FC5EFE356B86F9E2215B68 -:10E8D00091ECC519CA8FBAC668646887519F217CBC -:10E8E000C96AC43312ACE7AC630CEF33D78718693D -:10E8F0009F624DE5298257DA381C2657A7E3F98B2A -:10E900009DCA7CC264996077C07C52A4A9E1DADF19 -:10E91000730D2CB72B78DEA6E063A7C965B800E3BA -:10E9200018FC37917EBFA3B3F7543B9BF3A521405E -:10E93000FF74D1C93FFEC69E62171EBA11D7CFB26F -:10E9400093EC82BA6EDB3686DBD795C1533EC47535 -:10E950007F91C2474F078F7B0FEB0F8CE6BF83D3AE -:10E9600034FAD6DE5A3DB94319F77605EFB9B2E36A -:10E97000AB79D0BED069C191811973F4FE15F4E76B -:10E980001C23DA3D40B783D9AA3C388351EEDE1907 -:10E99000339D1DC2FE0BF8BED3B68289F45C62CEF5 -:10E9A000DBFBC37B9FB418C99F81E73F2B8FFB150F -:10E9B000FCFF4519C7070AFE9B153EDD8B76241523 -:10E9C000E32C6954BEA3D8118F6247762976A451EF -:10E9D000B1233BD18EA4E2BC2651B94DB12359A33A -:10E9E0009F243FE912E6C515D08E54B22530CE7C67 -:10E9F00018BFD8817D1B9F2306FC4E56B08E4EB7A4 -:10EA0000A745EAE0D1526CC0EF742506FC8E573F53 -:10EA10005D7D9E3533E077C086EADADFE21F11F0D4 -:10EA20003B627A3B32E4D804BD3FF3E53DBAFA419C -:10EA3000074B74F532FE03E69B7D8CF1FCB2C1C33B -:10EA40007E87FC927DDCA8FE3E33EDA3A9FE56A096 -:10EA5000FF93CD5AF7F10CB48F273309CF75D256F7 -:10EA60006582AE9EFCA78326672C9E3FAC2D04BE1C -:10EA7000C37388074BC730DA8707FE0579CA769ECD -:10EA8000F892F28D8AC599E4275D34EAF6D37203D1 -:10EA9000F6C59C23F5FB66D957D937FBFB8DCABE5B -:10EAA000433B7F2CE29AFC31902711C7FD74F09410 -:10EAB0003D88B79D9F713BD5F4D983B1F8FC5D6C5F -:10EAC0000AFD6CFFE641F2BBB6B7CA872B58EB6F65 -:10EAD0006DF3727BF1E6C1841DB8CEC88A16480F6B -:10EAE000661D993B99F8F1A0817E9F33A5A02A1855 -:10EAF000F1B2EDD0C260FDFD298D7E204269F48324 -:10EB000088AC1CA1AF8FD2F06102278EB6FDFF0545 -:10EB10006B92E82C00800000000000001F8B0800B2 -:10EB200000000000000BED7D0B7814D5BDF8999D19 -:10EB30007D25BB81CD03DD401226E161541E9BF78C -:10EB40002624611202460DB0101E414298243C5208 -:10EB5000AB3655ABD18FDE4C08841051A2B515AC45 -:10EB60008F958AEDEDE316AD045494E5E903840531 -:10EB70008346455D10D1DBD2BF28D0DA7EF4F37F27 -:10EB80007EBF7326D9193601FAB8ADBD37F9747254 -:10EB900066CE9C39E7F77E9D0321D790809DE0CF1C -:10EBA000D722FC3FD3D02E2081F4F076A9A17D831B -:10EBB000A1FF4C43FB2643FF3ADDF3ADA19983153A -:10EBC00027FD1B7E265E78DDDC4C48E0AABE7E3940 -:10EBD000669FE8197361BFDC6E53DFB8F4BF1D1F79 -:10EBE0002C319D4B20A4AB5BF4DB52E9F5E812A27B -:10EBF00066D371BA4D7E22E0D544E8F3AD3DAC6DED -:10EC000023AA631C7DBEB9DBECE99008D9CEBF3BDB -:10EC1000DAB770B02F869089E6D311BF2B9F37F5F6 -:10EC2000AD8FC07833079308FDB4EB4E3E6EA0D98C -:10EC30008ED76DCD2E12B0F53D176372BA7D741E5E -:10EC40005D219387DEA6F32F8D2774DDBB9C8B1D82 -:10EC5000302E9D2F214329163C49552D230991E83B -:10EC6000BC4D741D9B4326D241D7997D847D3FDBEB -:10EC700022C7BB22C09510931EFE178C477F004E03 -:10EC80004ED1DF41E1B2F38339F1E3E8F82F748B21 -:10EC900004E663551A1CBEB1B4DDC3E6A58D3BC9BD -:10ECA0002EEAE050421C3A7C149D8ED3B5B38FD12E -:10ECB00079D2F7ADD2F47880EFC5E64948B4818EB9 -:10ECC000E20CEDA1BAFEA3258AB7B1FDE3E1058E02 -:10ECD00087CD8007BAB017A23C55BE08F0DAFCA178 -:10ECE000B5C11F76FF3F3C142843E06AC26BF63182 -:10ECF000932740E173AEDBE401E0E5BB3AC5C6080B -:10ED0000E3149CD0D3676E77B40E5E44AC1E900FB4 -:10ED10009A8EB6ACDA1DD6FF1E4F4CC24907FD23B2 -:10ED20008FE4E1FA2FF2FE1F9BD555BB2D948E295F -:10ED3000C96EA2FD88AB9290C4FEFB13B29C325BFD -:10ED40001F1C892B9E2EEE52F0D489EF5D80AF7E82 -:10ED5000DEEF1B4765F0A4E0857EABC6F97EE88157 -:10ED600071423344F8FE838EDBC4109DF7238EDBA3 -:10ED700076017DEEFF935502BEDEF1A7AE24B8BF4B -:10ED80002F634B12D0FD3EFA4E10D667A658A36DE6 -:10ED9000ABBAC001F4F546F761E41F89046F1C9F0C -:10EDA0000D6D93A783767B39BD723019006EAF71FC -:10EDB0003AD9CBF97537E7D79DCD6ECEC7125E5FD6 -:10EDC000694EC7FBDB9A3DD87EB1D98BEDADCD3214 -:10EDD000B6BB9ACBF17AA8D987F70F365761FBCD2E -:10EDE0006685D161FA1D65208FCE255100D0752D25 -:10EDF000774C3347C2E7F5929ECFAE73EBF96C3296 -:10EE00008573787B927D98812F47E89E4FFCEA1AA4 -:10EE1000DDF3A2D399BAF684CF0A74FDF343A5BA01 -:10EE2000765ECF0DBAFE33CB2A75CF7D85F3F5F331 -:10EE3000139D285FB6BB0494CBD3B2EB75CFB7C399 -:10EE40001F2087ED825F4D05B8540E284F03801FA9 -:10EE50001BC091F1F1AB1C3F7B003F36C00B83FF21 -:10EE6000CB007FDA7E09E04DAF3967955D83259051 -:10EE7000030DD8B6A60F767A28FC5F768A28FFB7EE -:10EE80003437E27BFBCED59D1571BE0E09F0B29DE5 -:10EE9000CF679F45392B26405B90960B17CE2BA74B -:10EEA00047CFEFA3CB17A2DCDCDE7DDC01F4F6CA92 -:10EEB0005797A6F7B47EAF92CA49401FC5DD545795 -:10EEC000A55E5CFF697AEB62E36BFD40AF46D2174B -:10EED000C6716FF84A11095DC7CB3DEA0F62A01DEC -:10EEE000F89628D1766E8F3209F0B63B5D708902B4 -:10EEF000F69B24C3BCCF1FBE11EEBF12329B60DE57 -:10EF0000FBCFC71158C776AA776DB4DF1B64C49ACC -:10EF1000F114DE819E2FF7015FAA4E8B6714B97042 -:10EF20001E291922CA87CD636C26613CE83B330950 -:10EF30008C013E57109E5D5FA539E1BA395DE4F75B -:10EF400083C8EF5767B8F0BD97CF672640DB448290 -:10EF5000280F02674DE5FE08EBBD1ABE436548CE9B -:10EF6000F98F1C2EDA7FEFD93A07C897577AD8F86D -:10EF700039CB420E80D3BEAF3638E1FEF6F42C1CFE -:10EF800077C7D8A5685F6C3F6B42BADE3E669533A3 -:10EF9000331BD7E901D86D3F5BB72603E8BAC78CAE -:10EFA0006D89282408F496CEF4ECE6B375E4307D40 -:10EFB0007ECE23FA81CE7248E7DE4170FF8A555635 -:10EFC00092C6E06FBE82905BD9CB64924B2F074A0A -:10EFD0007BF4FAC41AAA9E3503EC08A067DA9E6A8D -:10EFE0008ED73DDFF7EEF2849980170A6FB8F7CA23 -:10EFF000D9DBF78D05F9E367EDDF1F7DDA3A985E1F -:10F000005BC6AE1A761BF4DBECF0D82478A2902F06 -:10F01000693BEFACD90FF6468E533F8F7D57572291 -:10F02000DC379F65F6D5B974B69EED9E7AF2007D09 -:10F03000EF656E7F4D3A36B202BEB79FDA4F60572A -:10F04000BCE4F94D7C16C833AFA8A3370A1FA497B8 -:10F0500073DD04C7A13F83A6523814B22E940F7DEE -:10F06000ADDFA1CFF7E5DB5CCB29AAB79FDFB9EB1A -:10F0700076DACE4B14894857F22DBF7E7EF93F7366 -:10F08000E8DAB77EA6B74B6C44E0FADC8972A03FA1 -:10F09000FE9970DAAA7B6FAAD9A61B378F843D47E9 -:10F0A0007C5AFB9EA75EDC3ED9C2E59A669F6CB196 -:10F0B00028F37D40D7C15917D1A3CBB9FE6D447950 -:10F0C000B195104F470695EB578B32F0E1B9A37617 -:10F0D0008463DE23332610D4D7CA04E00724C63065 -:10F0E0007BC07BF422F68A4B2509B9FC5304AEE6BB -:10F0F0009321DABF9DAAF9AF4187737D6E1CB73F9C -:10F10000BDFFA06310CAFDC232A6171E711C403D90 -:10F11000DFF501D5F302FB4688E27D36FC017AFF7C -:10F12000032BF67FE97A01E58866375412D94255F8 -:10F130001C99E63D6BBE9FE2CF67AF197B2BBDBE2E -:10F14000F46ED730E0DF97C03E40F9D0E860F6417A -:10F150008C1A4FA7B8ADC7867CB8E5B489D8C16F03 -:10F16000D866433AA57C7ADF58FA9D6D41662F74C4 -:10F170009DE6F6DE3607F2C98EDFB379742D733063 -:10F180003FE39455067B7CCBB21884F36829266054 -:10F1900086F19AD8F83D1CAF6F73BCEEE3FAEA75BE -:10F1A000AEAF5E057B02F517B32776813D41AF3BDD -:10F1B000B83DB11DF419BD3E7FFAB9F7812FCF6D6F -:10F1C0008B42BB733449DF04F3DAE6B4E23C8D7062 -:10F1D0009EA7E8F9606E95DE6EA818A3B71B6E189F -:10F1E000394CD72E4F1AA17B7F4AC2B5BAE765CEFC -:10F1F0002CBD3C324FD0B5E5F37ABB61BAF7463D42 -:10F200003DC9617603CA3BBDDF383BDC6F4C053C32 -:10F21000313F674BCFED88C72D47D3062B6176C2B0 -:10F22000560EE72D4799FEDC1AFA32468960477C74 -:10F23000C6FBFD96E3E314C7C77FA7C82732860045 -:10F24000BF7CC9E46F3F74ACBDAFBDF799FFE3412C -:10F25000E17A7DB828219368EDDF77BD3F1A9E5F84 -:10F260002A5F503A6D0F513CDF2DC67476D0575649 -:10F27000991B9F84B6AA9AC9C66C0447BA199F5FA6 -:10F28000E30179DC1AD3F85378BEB9C5E6DA900009 -:10F290007CF41FBF86761365051BBDFE312AC54F62 -:10F2A00028AB59334D38AF672CBE611ED09B826F9F -:10F2B000FEADB4BFBADEEAD9285D381F67A6A0311B -:10F2C000FB56D04322E7FB3F0B8A3393DE977F291F -:10F2D000A09C8E9208EA051BF105807F48833C1FA5 -:10F2E000F8839828FFD0EBBD594A1CF42732915C73 -:10F2F000741C646DFA3D21B8F74F029D978534AABE -:10F30000308EAD814A18CACF0F662889D8DF3C13EA -:10F31000C77F7E2A2120CFE872B09D7D177175C40A -:10F32000D2F911C5F4256DCFA7FE3E7CDFE4B80508 -:10F33000F5D4FBFF6DF28B11ECA55E38DF62391559 -:10F34000D2E82CED42FAE9E274B135D587F2D7F86C -:10F350007E6626F307B77C344D04FACAB60F92C115 -:10F36000AEA00B146750F9BEF5F80D8EDA08EF4D1C -:10F37000CEAECDCC1CD2D7CE0E6E126B9DE8CF8B0D -:10F38000B0AECDF46F58D78BDDA600E0F79CD38AE2 -:10F39000F2A4BF75E487F471883CB007C2F88D9081 -:10F3A0006AD7C96B01DE9DC2D7D786D3977C5F38F9 -:10F3B0007D3D7F217D219CEF7E2B1DE1DA2A30FAF5 -:10F3C00052297DC173B5B411E94B35115F6B36D24B -:10F3D0001BBEDF64B6BB6C54422ECD4C43BAE98AE7 -:10F3E000A9783F20E1F746CC447FAE86FB733528F1 -:10F3F000E75F3FC2E4BC715D3B8ECC1916027B62B5 -:10F40000D4DC61C0E75DA00086C2F473E7817DD9DA -:10F41000DBA6E8423B70328190157D9E3D4F86FE13 -:10F42000D76BED1CD6BF84F55F92F9F07A159E2F4D -:10F43000E0CF4925EBAFB5D5BC7925D0DF62C2F668 -:10F4400007BCFF431E7929D0E383197203E02F0321 -:10F450008C167AFD64BC7C33DC5F9A4970BD778D75 -:10F46000976F096FFF669C7C5B787B73AF9FDAC9EF -:10F47000FDD45BD12E7DBD6726DAB312F1DD087AAB -:10F48000E7F5208B476D1E39B01F7480DBF3FBB9A5 -:10F490009FFA06C8A3AB409F303F750FF7537771B3 -:10F4A000BDB283FBA9DBB95E7999FB492F713FE9B6 -:10F4B00005F053AF023BA48AC749989F9A3D6A5210 -:10F4C00019DA112ECD4F4D89E8A74EF7EAF5CD5444 -:10F4D0008F5EDFDC981E6FD02F7A7D332541AF6FB2 -:10F4E000CA9CD71AF44B96AEBF7C5EEFA7169F2D31 -:10F4F000D5F52F3CA5F7530B4ECCD4F55F9A2921B7 -:10F500001EBD476FD2F5CBEDAED3F5EBC39B0FF12C -:10F5100064551F77821DB779643DC71BB31734BC90 -:10F52000755D046FAF72BCEDE178DBC5F1B683E3C6 -:10F530006D3BB7075EE6787B89DB032F70BC6DE11E -:10F5400078DBCCE30B0738DEF673BCBDC1FDDDEC28 -:10F5500051BBD03F3B779A70BC3D2146C25B79924C -:10F5600068C083C380073DDE4ACDC30C784833E0D2 -:10F57000E11A5DBBF054A6010F05BAB6F768A90100 -:10F58000FE3718EC864ADD730D6F533DF30DF455CD -:10F59000AFEB77C9FCE66476DE5FCB6F7BB91DB756 -:10F5A0009BE36D27E00DE3441E1E8FF0F2B82FB3EE -:10F5B000E35EE478DBCAE3425D8037B0EF38DE5AC1 -:10F5C000479E413BFEDC790D6F0722E2ED72F9EDBB -:10F5D0003AB73E2E34D9A58F0B4DB2EBF9AD84E886 -:10F5E000EDBB895FE9F9ADE8B4DEBE9BF0999EDF23 -:10F5F000F24333756D6A0724640D013D7593EEBDCA -:10F600009C609DAE1FF59398DFE2E17ADF5F89FA97 -:10F61000A86D2AD38F940FD1FE7EE67BD40EC8E866 -:10F6200083C7F306FFE9F97EF4F7E82C66D774BDCB -:10F630005F8370CD01FD1DA15F06EF9791E5C2AB21 -:10F64000CD4CD4E84C9CE6EEA1743EE691CCEE3174 -:10F65000C7AC812003FC044DB97D7692E8F4111803 -:10F660009FDA4B195961F6A0D9D548C06E106D0FBD -:10F6700055C3BA8868F2A0DE35D847A4C125DF0E8D -:10F68000F76F1FE4E9A0B05892158BF370934D16F5 -:10F69000B033EECD920B605C711283C7E664EABBB7 -:10F6A00053786C8E626D95C26B236D8B83AB117E2C -:10F6B0005D145E62068C9F40EEA2F3AACCB2323893 -:10F6C000CC235C9F6ED4EB43301868FB9968D69EC0 -:10F6D0009DF5CC3C35A94FFFD6FCA66BBD4AC7199A -:10F6E000ED1C5A4FC6D171D7A97160678EA1F30383 -:10F6F000F968726C4B8E647FF76787A9E3E4594021 -:10F700001F7771FD3A9A42C49CD9FFFBCF44FBBEE0 -:10F710000DF8CD067884C5BDA66631FBAC12C6C90E -:10F7200041FB520EB72F49B012DB6D198CBE7EB271 -:10F730006626D29B93C24B8C85F933F8CDBF93D10B -:10F74000D7E5AE439BFF0074E20BB7A7C3E8E4AE76 -:10F750004874422A3C6EF4D7FBB3E75436DF566E4A -:10F760003F6A76B22D49B39BFD1C0E24501087577B -:10F770003299C235CE45305E53E332F9FD146451FF -:10F78000B19902CA9D3281B852617499303C564891 -:10F79000E1F2C7181FF41E8D36C8F738831E1EAA63 -:10F7A0006B179F4D33F889D70CA8E7CB9C130CFA45 -:10F7B0006992AE7F79D28D063FB6D2E0E7EAF58452 -:10F7C0009998558E2F13C62D544132E7C27D82F889 -:10F7D000097B8E7E672F9C1F93AB905FB95F63E4BC -:10F7E000D77BB32484B3E0627E8DC60FDAFB1AFCAC -:10F7F000AC6E86D7B5B99A7EF2A0DEB105BE4520C3 -:10F80000AE4A6D68795318BD6D68B6BF5F368A9091 -:10F81000A79BC9FB651479FE66175E9F6876E3F5C2 -:10F82000B16609AF8F36A763BF75CD1E6CFFA8D92F -:10F830008BD7879B65BCFF507339B63B9B7DD85EE9 -:10F84000D35C85D78E6605EF8F342BAA9DAE6B6493 -:10F850003BF1A87429A33AE9F7C2E036A29DCE2372 -:10F860000CEEA9AA4BD71EDEE4D6F54F6E9474CFEA -:10F870008735A4EB9E272A1E5DFBCA2AAFAEFF1078 -:10F880009FAC6BC79797EBFAC7CA3E5D3BC653A5C3 -:10F89000EBEF485774CF7716170C0E0DC0C70F3516 -:10F8A00007820C2EC12083D36B41069F1EBC9E0293 -:10F8B000F94BF118670EA2BC88CB7651D2A1F8B2F1 -:10F8C000B3FC5ABCD923C4868D1F5F4EC74B0F9F14 -:10F8D0002F1D4FE79FF9915E623C41DD7D477A8F96 -:10F8E000EEBDC9A2B314F211870A458C7B1D2A8C88 -:10F8F0008F01FBE53E8B6B6A36A5C7834744CF0675 -:10F90000780F5E88202F8F71BDE8186747B9307D6A -:10F9100085B04144A265EFD7758F8818F73CF87D14 -:10F920005205EB72EC7C4102BA985E581B1F15E63B -:10F93000AF4D0FFCA9CC0DF75764E446D1D1A6B763 -:10F94000A75AEBC7F4AD4BEB57B7426F5FF6D1BD8B -:10F95000DF0EEB18AD7EDF0EF2AD236903B63BD2AE -:10F9600007CE93FC96DB619F713BEC248FC39CE038 -:10F9700076D871EEF784B81DF621B7C38E72FBF905 -:10F980003D6E87F570BFE76D6E3F7773FBF930B75B -:10F99000C33AD29F9B82F2F097021123F8A9DAF5BD -:10F9A000DB3FD3DB61DFF2EBEDB0A5EBF476D8E221 -:10F9B0004EBD1D56DFAEB7C36A55BD1DB6B0496F0B -:10F9C000872D68D4CBC3F90D9374ED798A3ECE367A -:10F9D000B74A6F3F6BF899EDD3CBC5CA72BDFDDC5A -:10F9E000DF7A5F0A5C8FF91F40E2C7617AAF379F09 -:10F9F0000B7A85D245F679AA57300EEE6B85FCC995 -:10FA000056E842F56F9129F816E47DC8DB2281B8EB -:10FA1000D3CE73B915D323D05FAEAAA79BEAA3FABE -:10FA2000F8C64D77EAE13AE316BD5F622DD7C355BC -:10FA30004ED2FB2595463DE3D3C355250A01BA3482 -:10FA4000EA1B93E31609E4F7E5EA1D2BA17A85B5D5 -:10FA5000757AC70A77D274CF51EFB467B3785D2E49 -:10FA60009D07180B2D5179FB3D146E3BDF35639DCF -:10FA7000089DE0E19154FF14C3DF147E2F5B14B5A1 -:10FA800011F26C3C2F42C453BBBE43FB5B87B1BC3D -:10FA900008F9CA7C02C657E82FE02B97D076989ECB -:10FAA000CB09B2E761F3D53DFF31E06CC0F9C887FF -:10FAB00047E6FE4FCE272601EC21329E8CC77A8383 -:10FAC00050DC25C5578DF7B303CC0ECA4E62769035 -:10FAD0003779A6C8F34F04421E5E13B1633C3385E9 -:10FAE000F837429C337ABF631A6DB6C29089E0271B -:10FAF000E9F97F56C5C0F979A31F76BD34C2E0B7D6 -:10FB00005D6BF0EBF4FC6F2306FB254424B027115A -:10FB10000726DD7384D3614E472DC7DAE6C3BA5E8C -:10FB200048E6F9154E3F1338BE08D9B4AB963EF7F8 -:10FB3000BA4502FE868DA8F1E3A1BE28D82843DE8F -:10FB400021CF6B7321DEC4651EB44B4F31FC78E9C5 -:10FB50002FE0CF4BC2F005F83BAAC79FCDF0FC24A5 -:10FB6000A7A70BE7C5E8E89F372F035D39E32EA968 -:10FB70008EC578BF24288B31747E7B5C02E651F7FA -:10FB8000041B8325B47DC6CDEA865625CD34E37C9F -:10FB9000893C6832C5C314BE5E2FCF6B753513B474 -:10FBA0003B9E6FB6E395904611E4519BFBF678D0EF -:10FBB0008F5D29CA30A84FEB1A12BB02F2F39B2DBE -:10FBC000B14991EA5A7658F2509F76ED48344BF499 -:10FBD000FD12B3CB0CEF9524D589E0EF5DD743D070 -:10FBE0002E28492298CF7ABE3970887D4FC13A1CA1 -:10FBF000BA8E49609F96B96A27C524407C96DA364A -:10FC000012D8B9B1E8BFEE1E6243BCD95C4BCBBE83 -:10FC10004BD7772051248297E2C7433C01D0034958 -:10FC20004E8F1F86735B8E039C1BE8EFD7697D7A2E -:10FC300081F2F9F1707CE491B036E615F4EDA1396A -:10FC4000BC0E8AE347220AD659B4F5B0FA32128ABA -:10FC50009C67F988DB0D5A7CFF28B71BDEE371B780 -:10FC600043DC6E6833C46FDEE276C36E6E37ECE55C -:10FC700076C36BDC6E7883DB0DFBB9DDD0EB2F1028 -:10FC8000B505F28AF3883D04FEC2815A0667F70A79 -:10FC9000C15F0EF970A5D3574AEFDB5658507E0E60 -:10FCA0004F525B203E6EAB5227C33ADCD59D2D7080 -:10FCB0006D29EE4884FBF3949347C1CF067A999A55 -:10FCC000CBF99DE261AD95C179DDE218CF72A067F5 -:10FCD000654905F64B6270B3D35F8077E222550029 -:10FCE0003A702B161DBC6B0DF09D07ED30F9110D10 -:10FCF000F448E179BD06F72C92C5E0AE4601DCA3DD -:10FD00006A39DCD31322F2C93A0E770D2E3B8A6F83 -:10FD100036A9B4EB5B49AC6EE2ADC29B4D07E8FC83 -:10FD2000BB6511F3AFDD49BC4E907FD738DE3BDCBD -:10FD30009E5D5B3A70BCEE20EFD7DB6E27926D7054 -:10FD4000D838A5F75924FA7E55607532F0C5DA41E6 -:10FD50005A9ED883F6F564B1F0CD543ACF20AF83E4 -:10FD6000D4E4E51CC26163F8DE5B7C9DFDCDE7ADAC -:10FD7000D21B2D121D7756E01E02DFB3991BDDE169 -:10FD8000F5A5DD7C7EAB66DC41802F8329A71BD0E7 -:10FD90008FF7D924B0BB87277956021DB89314CBAF -:10FDA000F7E8FD69541E4A2E9856E78E04E847DFAF -:10FDB000799400BD5CB309E8E1AD643BCA9DFEE601 -:10FDC00073811EF113B447FAD32354FEA03D64ABF4 -:10FDD000F8F428F8B595A4D113A0EF05B33D4380FE -:10FDE0008F499505F5733AFD0DCFAB69D74A83FE70 -:10FDF00076782D03CAE1E1E79BDBC1EF780BF807CA -:10FE0000F3A02406EA73821577D8013ED393D37604 -:10FE1000027E48893D348AC26155E1CA0500AF556A -:10FE2000154B5D02D055D1087C1E2CB19F848A9C55 -:10FE30009E9255C95218BC57AD26C50AC03BF92E33 -:10FE4000F712BAAEB4A43F342B946F7A2CCCEF796E -:10FE5000A7F47749A961FDC7E694FC2C07F8DACD31 -:10FE6000E87CB455498B541FACD1794B7134C665CD -:10FE70008ED7B27A057A7F65137D55A1FAAAC3D3CE -:10FE8000C7C78B393D458D3ADB00FD95D53609FD59 -:10FE900033B1BAAD89B6ABC05E02FBE9610BF2A526 -:10FEA000C6CFC98D7AB9A918F8B6CAC0D71A3FED1E -:10FEB000BC908F6300AF51B58C9FB4F519D735EF67 -:10FEC0002B6AE7C41362F4EFDE5D34229AE9B130A5 -:10FED000FB763CCA26C94AD7378BD3D32C4E4F94D6 -:10FEE0002477C07C0EDE33622AE04B6DA17E00CC0D -:10FEF0006D99A5CFFE4D837592415EBAFE594D6254 -:10FF000006F8A7E44E4B1F3DA6E9BE87F50273C273 -:10FF1000DB40AFAAFC0ED81110CE848FFEF1D8A121 -:10FF20003DADF47BDD43E3498B07C73BC1E4A384CC -:10FF3000E31D2C140779E1F9BDA33220854FC2E9F6 -:10FF4000958E1F52D9F39A7B4664A2B9C9DB1F2D47 -:10FF50001B021564C45761E9EB0FFF2B3323FE67C7 -:10FF60002F133640FC6FB4F8C5E95DB4FFAC4A9B73 -:10FF7000A7958E3FFBC13A0BD8FD95AAB2A79EF676 -:10FF8000ABA474E177E13A747C72D84C2C30CE612A -:10FF900059209DB43D6B969E6F6A96E9DB467BE4E3 -:10FFA000488C9262A2EF7F2AD8C8067ADDB17EE93A -:10FFB0001330DE270FDAB0AE90C0B772410F101EBB -:10FFC0009F949FB8873EAF5B6723901799C7EDFD5D -:10FFD00041B9A938AEC9518DEFD776C4A05F7C7204 -:10FFE000FD95E300FFED718DB7413DF527B14A0D59 -:10FFF000E0B56ED5B526888FB447774E86FE9F9ABA -:020000022000DC -:10000000886B43066D4B0F59603E3DD43E8078AB04 -:1000100036CFDAF630FCC37773591C779A89289B60 -:1000200022D8350FE6F6D627A8B6B0F93F9C2BE1CB -:10003000FD6969716D3F80EF50ECBB3C1C2EB0EE4A -:10004000C92C2EDA9EE4A91942DB2704E25A9E004D -:1000500057F943E04FF57E1BD988E827D8DF3A6C83 -:10006000E8531D61FEFF383EAF8F63D9F3E3EE68BE -:100070003FACF3B8C4DAAADBE9477A362BE97362FE -:10008000D87A842B6017049BDF9118C99A86F820D0 -:10009000D273745E750F3F82F8DD4CE103FCD9E347 -:1000A00092DA76D0799CA4CA5A85E7EE4727033CBA -:1000B000EFC8A4849A78219CEECD8DC3F99C5CD7BF -:1000C0001A8375262EA258AFE883476DE796BB8545 -:1000D00071A8E755263F18FF09244CBE53FC4ECBB0 -:1000E000FFA1A50ED61B453A012FA6DD2BEC30CF84 -:1000F00079B516CC8F3989AF1CE469EDC302B6E936 -:10010000CF1AD017759CBFDAA5B8BD40C7C7C11EAE -:10011000477FEFB13D501F50CBE557D5223D9D2E77 -:10012000769B75FC32A349CF3F749DBAF6FA5C56B4 -:10013000D7D9E3FD2401F4733B5D36C0E5D336C166 -:10014000BF01E5AB2F25BCBE2E35D7A4C5E1254B9D -:1001500018FCEB28FDD581DEB093CED24458F7A829 -:100160002940EFD623D1384F237CFFD5E1F071B27F -:10017000543384CEE7634AC750FF737C7D2BDA2F5C -:10018000F023EAF8DAD506F4BD84CEF25117D2A7EF -:1001900075C6D83E7AD1E053BB2E752FF4737F1EFF -:1001A0002351E789D4BA0B96823DD94B4706F8C054 -:1001B0009ACDDA7746F4D1193E8F406793685F6E27 -:1001C0001F23BFD496F5E6F55206AA5F467C1700BA -:1001D0005EC7CF873C9426E7D616BF817470C645AC -:1001E000FC22F36BDF06B91FC3E7A61239509F004C -:1001F000CA84EA5D17DE437F399EAF37B64978AFD0 -:100200002C8B90B826F1BD327A33B62C18003D61A4 -:100210007373BDBB2DEFD7A3AF80DD0D04E3348333 -:10022000A22B3C015C8D2B11F729585C8960FF3CA7 -:1002300028085510B71F44F47655BC011E24DB7CFA -:1002400022DC2E8FE6F27EE9E41102FA3BE57AFF2A -:10025000D46CB08B7EDE4BD76CFD12FC49E1D846E6 -:10026000FD3790537181CE4EA0CF1A6AB7FA71FD57 -:100270001ECCEB58CB04F2A8D017BFFA67C52F2EBF -:100280008883F1F8457F71302D1E50C96E517F472C -:100290007143DEAFD24DFD9C416067DDEC46BFC9C6 -:1002A0007D12ED522BB74BA3462D72B1FC19E31F03 -:1002B0002D1E60A42B635CC9C87F46BBF4B7B9DCB4 -:1002C0007EBA865C7339F1012D8EBF2A9DF93DAB54 -:1002D000D2EB9643FDDA39EEF7B85413E271CE2C27 -:1002E00001F1A8D96B73BCA76701FF69F50717F384 -:1002F0007B3A0C7E48B4F729598EA03FAD792C2E5D -:10030000E42864CFE7D889D91E963FB0E5313D3760 -:1003100087EA413B5DE234BE8F683AD1E7A7E2F855 -:1003200038DA95FE04337375F5827179EC3EE64355 -:100330006D3C1F6AE7F582251967777D0DF76556D5 -:10034000076C936B1FFF1E8543F4AC188F09E957A8 -:10035000D9F843F093673950DE26A44B58F75A95E5 -:1003600064F720EDABF2DBE097A19D29C194659481 -:10037000B77329FF065C03F83BF681E3664ECDDFD9 -:10038000296474D51B5FF231F96DA2BF404FB3AB46 -:10039000F4F4325719987E32F3787C89EFE31A1D12 -:1003A0003ABFE36BA40BC6BF6B53583EFA5C05ED36 -:1003B00003F9DB7EEC71CDBF755AA85F44F112944E -:1003C0007721BD07D389251CDFBE425157DF10CCF2 -:1003D00027D12EEAF7042D24F941DA6F903CF70675 -:1003E00017F8BE25B6985AD41B7E9D7D7F908E7BD4 -:1003F000CCD9FF3C8C74BE7AD4128CFF3F703D0583 -:10040000199DFF6A483863FDDE73F3C16F7B00DA24 -:10041000585FF08BF9506FF74094D6EEFAB11C5646 -:100420006F70E796977FAC1652BFC64EF52D1DCF65 -:100430002111CC5311B209E5B308F14090CF63C24A -:10044000E08B7E831EDE463B5E2C647114D1C0F7C8 -:10045000C6EFDE9CA7DF6FD7DFBA8DEFD19FAA6B07 -:10046000F4F47F7BDE00F5B2C6F79D503F1173F9BF -:1004700075075490627E5A24260FF8CBA494E0F7B7 -:100480000417A32B9030A0072D8D833C0837DA8EFC -:1004900002BDE0776871559C7414E05F847C620053 -:1004A000F5399D4A481801FDB5FA03857CEDB8740D -:1004B000B947E5318E2395B3FCF2BB3209C1F7464B -:1004C0003FBACE970BFEFA11AA6725D0E337AB10DF -:1004D0002F3BBB8C607EC0E152B04D3F156A754129 -:1004E000DC8AB56B288C402FDBDCFAFAD71DC58F70 -:1004F0009658E9F3B632166F3DD81C787705A5B546 -:10050000B6C20294972BA063D87C833BA3AC108720 -:1005100051D4EFDAC16EFE689968856B7079AD0AC7 -:100520008B7E3751DD244810775008F8F9D665AD39 -:100530009381AFDEB5A89E3827E655314FDCBE5C0F -:10054000BD15FC1E59AA284FA57CB4A1DD8CFB8CDF -:100550008E95FE2E490AE3C3535C9E1ED811F5000A -:10056000C06195600F45C1D5A26C589D00DFB37A7C -:100570005AE814DF6DF941327C67D5E2559E9DF053 -:10058000BCC5063B50C9AAF5F62A187755F212F7F2 -:1005900092B071EDC3AC8D703F38B40DEB5A9472CC -:1005A0008F352A16D6F5450CE467DB9765C5032D14 -:1005B000B6255A53EAA1DF923FBE990778974C9827 -:1005C000B7B5BA3B2DB0EEE16E4585FCF85F72948D -:1005D00057F3E83CE7351D9B8C757365B12BE13A09 -:1005E000FCFC77DA01FEEFF2784C28B10EF3B56D22 -:1005F0008BEAED30DFE98969CBC3E3316D858BEDA3 -:10060000A3E97B696E53EDD24117D2471BC45FC685 -:10061000C3BCE87AC642BF3F342BB45F28D95A1511 -:10062000699FD6F13CE6EFD95B97A6415CA46DBD0E -:100630001DD233A44D50D6417E404D7546AC631F4C -:10064000EB65EFD528AEC95609F183FC762AAFE7F2 -:10065000C7EA48B02B19FEEC6662B784E9BFB1392E -:10066000259FE685F9D1177C37B10DF5419BC0F880 -:1006700077ECD6CF7F0CF5C2BFCAF17D0EEFAD6A25 -:1006800057D601BC886A27838AFBE793D06A9242D7 -:10069000A83C6E6BB15545AA430B2D12A7019F5084 -:1006A0000E3A3628254C2E2FAF4F83F848A8E52A5E -:1006B000E4EEDEFEEBED1F021E42EBD363411F862C -:1006C00092EBD2D2806E395D1AC7DF94C7ECC95F56 -:1006D00067F92C5EB02BC7B0BC67459ECFE645BD21 -:1006E000DDE9063BF71B40B72930DF7F22DDA29E04 -:1006F0003B9E770AE98AB82E2D1FE9232133E65362 -:100700008BFF8CF1DE8EB1DAFE27161FD4ECDEA84B -:1007100051275680DFEACBD7F25D857BC05F9FA66D -:10072000E5532B587CD0457F23C5077D86F8E03400 -:10073000435BB337A778B97DC2EDDB24A9D3570A51 -:100740007277BFE8017F229930BD32A342F0839DCA -:10075000DD521C6DC779E7F33827F7BFE6F179BFA3 -:10076000D76C27904F32390A57C2FCA715B0F93B16 -:100770001A32720212C87716E7260D3609E3268070 -:10078000FC44D2EBA7F96010BA9E790D4BD1DEEF95 -:10079000835F0B8BF310BD3FE12306FF6111B3C7ED -:1007A000347F6BBEC13E30DAFBC638755F5E609346 -:1007B0001DE8E9EC98CC8369123E56035A3E80F658 -:1007C0005BE8ED5E190A933FDD5C3F1C6E96DF5BD4 -:1007D00041D7BFD2F7133BD06987D96F077DD2517C -:1007E0007E470CD05F47B5580E7C1F6C2EC77E0726 -:1007F0009A7D786DF6327DB12F47BEDB1B1677AE42 -:100800002C2F796F4578DD837CFD7B2BC2E63FDDA5 -:100810003B43D7D6E86CBA481A3745902FBFF2321F -:10082000FE3753BD8F7586E22F3D03D5DF507FF530 -:100830006C38FCD678F5F6EC7D634A070F64B76830 -:10084000EBD3E0A2AD5B7BDEDF3CEFFA1BE7F9D434 -:1008500065CED3383F6DDEFDF59F0EC28AF2FF5D97 -:100860005B4BAAA12E765F8EF22CC8A3CA326125FB -:10087000E44B0FF378E2E1C218DCE7BE279DF97B79 -:10088000D10D8C6FA2CB6660DEEF72F17B9397D9AE -:1008900095B30A05BF4CFF9CC2F7DBBF97CEF2B9F8 -:1008A0002DC53F7F13F2D0EF145958BC97C8D3A67B -:1008B00086E5B1D65AFD01C827BDD75BA771CBCA63 -:1008C000BB683B5A932B55FABCC3AC59FAFCE17494 -:1008D000439E21DA2057821ADC7329DC47F4C1BD1C -:1008E0003F7FA23FFA20E6D3D9A0878CF0B9CD0094 -:1008F0001FA3FF327D9B811F2ED18FD9D09EBD07B4 -:10090000F26A2AB5274701FEE0117D2F5A7E16D3E1 -:100910002051F98C1E47874EAD01BDD84D5500E8DA -:1009200097B533EF5807ED7354EF035EFAFB8EE68D -:10093000BFFD2A473EE38D503FD02B47C03E180FE6 -:1009400079C1C8F641F7A2495323DA0733EBD372D2 -:10095000605E33F4F641F7FAF2C7B3E03ED807F42D -:10096000A73BBF5E671F90F2AC8BC087C9DDA85163 -:10097000D911EBF47C398A2B3F6C3D8EF446125E24 -:10098000CFF879AE1C9B4FDF9FC1E308DAF7A8FDD3 -:10099000B5DB12A17E51FB5EA697C53D49793CD3DC -:1009A0000FFC7A313C6A75D4F759643CEF458B7B78 -:1009B00069FD3CF94CCEB6A7C90DF09C38332F32F7 -:1009C0006E8B16E748CFB882D70D4BA4D71FFAB36A -:1009D00020E1F308FE1E81BC6474D2E9DD2EDAE565 -:1009E00013AF920370283AED57211F62AB10D05E0F -:1009F000B22511B46B2ED5BFBAD47EED501C00FECB -:100A0000561D8B97976498B11DAD881B402E4C3CAA -:100A10003F5800B9E153C4A760BED1F2179FFD044F -:100A2000F435D5FB1087F19146DC67EDB4F8303E24 -:100A3000D1514147CE8038CC724B1AC6D3539F8DCB -:100A400071C3D7FCED102FB779D87EA82AAFBA12A0 -:100A5000CECD985E344A20F4F9341F8BDFCC81F878 -:100A60000D8C3BEBF40E88FFCCF632F9057E1BE8CB -:100A7000CDB9F5778FFD91F4D7C46DFCEDF1D918A0 -:100A80004F92305E60880FD90AA7607C48AB53F163 -:100A9000158AB8BF9B2439F11C0A637CC718CF3173 -:100AA000C67B8CF19DEFE6B37D1A9A3DD598AF8F4A -:100AB00017DE0D7B1072C05EA2A292F275878524AC -:100AC0007752FA3C58F229B993CEC3F94313D48034 -:100AD000D37E7A3BEC52E55690CA958F6121BB5E7E -:100AE000B7807F5B2DD7627CCF48F70FE5B378DD09 -:100AF0008A7CA72E1F1C6C6EE2EF47A980E7EA9163 -:100B0000567F546ADF3897CA1F8FE6CA0FE433BF97 -:100B1000A213E89C7814DC4F5091E7D2D12D691CC8 -:100B2000423E0E8BDF18BFABCD471BFF72E7713F14 -:100B300087F7A5F2C9DAE202BB957EFF0CC5B18842 -:100B4000FA921AD461F1692D7EAEBD570379832CD8 -:100B5000B02305CC1F68F7C3E2D866A0DBE82445C4 -:100B60008E74DED4A1FCDE3C15E631B5EF104141B8 -:100B7000B950CFF335DA7866E26E413E00DAD6E658 -:100B80002546889B138FDD4649A66E8D4820FEE3DF -:100B9000247227C49FADED166C13B56A2FD8E98B6C -:100BA000385F580BA7EC85B89AC617C6BC8D554C54 -:100BB0009A02C3D677EAF357C6FC94D19ED6E2EBED -:100BC00066FA1198D7FFD3F04115B57869EB7D0A25 -:100BD000D7F30D5DAF46571559DF7643FD495B945A -:100BE000B2AE96CE4B7DDC8EF10A07CC0D6012A022 -:100BF000BF20271FF7FE04E4EF5FF2D9F9376D023B -:100C0000AB47D99DF88784F0FD0B7FE1FCFB74BEF8 -:100C1000C4E222661280FD52644C02F285567F7255 -:100C20003091D981D38B1607EEA0ED5FF07AC96BB6 -:100C30008B366AF9FE4125B9044B3F002E6BADACF3 -:100C40002EEDE0D566AC2723E2FE9D7724F4D5EDAA -:100C50005EBB49EF57DE98AEB7078DF69FD5D08EB5 -:100C60002BE072ADB7FE44B1631D5922AF23E3F30D -:100C700037F2C9CF9A595EE3E7BCEEFF977CFFE5F8 -:100C80007FF1FABD4D7CFFE5737CDFAC06F7FB2CF2 -:100C90000AC6A38F5D4F6DBAD8BE38E0DAE27BDDBD -:100CA000C0C7E30B587C68B2E8DC097AAA6F9FC51D -:100CB000C0E7845596EBF366B37DFABCD9DC2A7D98 -:100CC000DEEC0F59B2A76008ECC368580EE714CCED -:100CD000582162BE726DDB19D4B3E70AD1DABE5077 -:100CE0003EF07D18DA3E0EED7E69013BB7C8B133A8 -:100CF000D102F5F83356C44E81F83971655E92FD24 -:100D00007603C4DC613ECB5D16380F62462011E3EA -:100D1000A1B5ED9737CEEA5157609CBA37CE4FAEAA -:100D20005900EF1FD2E2FC6AFA0288F31FE271FE5B -:100D3000EA826B1F07FFE8E97C7926C06359BE5C35 -:100D4000599003F7995CA0EDD9E16DFAF35AACFE26 -:100D5000FC896A78AFBF78BA3849688C542FB2B82A -:100D6000A037CE5507EF137B6F9C6B116B77E23E7C -:100D7000BB26FEDDD6F748038CD3FA2269782E8293 -:100D8000DDFD9D02411BEF16982F716BFACD775B4D -:100D9000A4F1445B6C0AF8FDC7787D9971BCA6028A -:100DA000B61F938E7717BE9FD43BBF261C9F8FD74D -:100DB000B77FC615034CEBA8514C3D949E489B88C9 -:100DC00075278E2ED754A84B225346601DCBA1B257 -:100DD000CA7F89FD3487CA7EF36FB99FE63705A9BC -:100DE000480717DB4FE398499448718D97385DEEBB -:100DF0002CCC1A1C1A004FD6A67D41B0337ADB6684 -:100E00008540DECFDA7400EFDF17E5AA89685F70EE -:100E10003A6D2B5BE48394D0AAE42962B8FDF2BB5F -:100E20006C654F4184FD8967469EDD05AA69669918 -:100E3000601612D0DEF608547E662F9B21BA25423A -:100E4000BC8D0F4EBA923E9F9544FDBBB0751734D2 -:100E50003CBB8BB22B292C3BD49A40FBBD98AB1CDE -:100E600082F18BDDD26E68CFF26560DDFB7DB1046F -:100E7000EDBC63A3ACFE0DA917CEFB049F3795CB49 -:100E8000CBCD972197DB9AF5F9EF55C9A397C3FC12 -:100E90004797921048D834F7E912C8FF8DCD514ECC -:100EA000005FA5B9896C1B87F7651296BF318E1B51 -:100EB0003581E9DBD1A1A4FB219E7C50F3F78B2F78 -:100EC000DBDFFF221CDEC6EB31CDDF5F19D9DF3F50 -:100ED000B6283E723EA0ADBE0EF201C756EAFDFD39 -:100EE00063EBDD35B0CFEF18F7F78F4DA6FEFE9818 -:100EF000FEF301DA3AA91CB24D00B9D39B0FE0769C -:100F00003B8F6BFB72E468784EFD79075CEFCD9206 -:100F10009D13E0B9EA5A80FB9149E47DB2E4319730 -:100F20000C7E8EB6AF3DD3AB0C81F7B5FDB2A341BD -:100F3000B4C5415ED4755B247A9626307EF9EBF316 -:100F4000A4BD794C13EEA3BEC438FDA5F693BC9B9B -:100F5000583D8E99D519462596BA213F756E8C1D40 -:100F6000F57B3BFC2F4CAFA61428B91386848F6306 -:100F7000385F55BAB4EF6A75FAA0AF40BF74135228 -:100F80000EF2E681D8468C7B9471BC1AAFD74D70B7 -:100F9000713DEB4A0078A614F8A620DE9FDF24E11D -:100FA00039B0FC7E7FF5FDC6793C63F57D80FBEBB7 -:100FB0004B4589D5E511E48BABD25DA8A735FBABDA -:100FC0006E422A3B578184465AE93A5BE55DCE2C56 -:100FD000DAEFA3C7CC19F0DA4F638805E6ED4BA72B -:100FE000728EAEA3D4AD0C1F483EC28944262F5C3E -:100FF0000382C98DD778765505B87F013F3E767656 -:1010000008D8E33F7D9CE5A7AE7A7C91BD2E6CFCB1 -:10101000472670B999C4E65F230B7E2915E6731A3B -:10102000F350332493472690373E77642EC409A9A2 -:10103000FD360ADB67B01D944C5990D7FEC8FDE51C -:1010400011E87FD5F7175F81F4CFE1B17059D6333E -:1010500068E7E728DF03FC070BCFC48C188376FC16 -:101060003AA0FF8502F145B213EEE778BB416EBCB2 -:1010700009E8EC06D94660DF5AB0C48670FF699172 -:101080002081DF3A1D681EE2398F9931DE4CE17113 -:101090000B3CDFEF71E0B9D1A5F2B36668FF61AC3C -:1010A00040AE1C401F5F365C0BCF0C017EFC08E895 -:1010B0002FC2FCEB38FF6AFC44E15E8AF39259BD13 -:1010C000487F74F579BEBC0EE8B23D4D69C073111E -:1010D0005D332FE95CC4E93FF363ED9EEDE9C6A102 -:1010E0002442FDD741CE27C6FBFF3981F9054B3895 -:1010F0007F5CF5F8D9FDD7035F2FB3B800AF4FE79A -:10110000FB7E0178EBF5BBFECE7264B2588DF80B16 -:1011100056D0B9E3390E2406DAD3469A117F6A29EC -:101120003FE7E32EE26A8DC5B7B06D5F26209F3999 -:101130009C9D5560349BF31B8FCC86F74A44DCD7CB -:101140001FB6CF65C03AB210DF7FD606FBCFA82D01 -:101150001F5C216AE76E1181CAB6609999DBF79F1F -:101160003E2ED33F9FE1F5991F14894F407DE61134 -:10117000136B1F2A125396D3EF8452D83C3A1E1495 -:101180003C2D125C9F5A07F9CBFA26C1534EDB3532 -:10119000817B7A20C4B5E4611B0157E1931F2E9D2A -:1011A00002EB39E32678BEECDC44C6374A90F84DB2 -:1011B000A97DFEED87C9C4AFE54B611F9D97EB99F3 -:1011C00087601F1B9DF775EA77D5BB216F4AFD5ECF -:1011D00088ABC579583E333A68F6F809F8BBAC3E9F -:1011E000B2ED7E813C04E3886B5AC13FB7F17ADDF2 -:1011F00068B916FDC7384A9F1268D09059B78FADAD -:101200009E2848BFF1E5943332E0AAF78FB32FB29E -:101210009F6DEE8221B1C02FE726E8F765F4175FD6 -:10122000D7AE70DE0DE0A78BE757B752BB1DD6FBDC -:1012300022B5DBE1BA8DDAED701FCEA9862BEC6703 -:1012400083EB4E6AB7C315F6B3C115F6B3C115F6F5 -:10125000B3C17BB09F0DAEB09F0DF71F16A981C122 -:10126000009F926802F9A1360BA33335D98AFE4656 -:10127000A08860FE3E986CDDB01CE27502C3931A34 -:10128000CB9E0763949BB19D3A86E577CD9E14D89B -:1012900047B842182381FDD46E55B07EF9D8723319 -:1012A00081FAE5D054E103C8BB10C1E411A97DB3B4 -:1012B000FDEBDB10FE8B656282BAF4E5706E28C828 -:1012C000E3CFC806169F0B8A70BE5C6B0CE1756499 -:1012D00037F9654A7F2705ADBD57017F7422C404E5 -:1012E000907E7729F07C7193C0DBAFFAE59150D7FF -:1012F000A03D7FF349882FAE30B4BB4DBCAD0E7F0F -:1013000012C63BA27D4F1D5603E31D49D39E272ED7 -:1013100084F6C751DAFB9F2F84F783BDF33989E345 -:101320008592B5FE520DB67BFDE7050AB687B0FE85 -:10133000EB77EE7B0AFCE5BFF778AD8A8A717C75A6 -:1013400016211B6323F0FF44511F0F95055D3C548C -:101350008BBF9B1CD557E2FEB3076C28173F4E2668 -:10136000E887F417170D8BD7635CF4E713FB897FCD -:101370001285C0B855100FF4E05795F0FD69446828 -:101380002450A7EE3B1523811D694D0A8BDF71198F -:101390003050BCB0B591C507838A85A8A97D75FD7D -:1013A000D6425ED7CFE3855A1D83B5F047BABC81DC -:1013B000315E48C45B301FED5BA48F074E572E2F64 -:1013C0005E584D02962B81FE65C103FE7BB54BF93D -:1013D000F00AB4F7AF61E7334AAF61DC54DB37069C -:1013E00077E0DCA92ABEE68E5B8F7D7005EDE75FB6 -:1013F0001E25C166FCF9B794E0FBF9748510DFAADD -:101400002E4A4378E77CE6794D0279EA3679989955 -:10141000E6FB7E22D80B8B62316FB2E0CE8C0F617F -:101420009CC5AA03DFA37625A7F7AE27809E4408B4 -:101430005C86B5B35334FA9BFD04D0FFC478AD1D70 -:10144000FDA45C484889557B3F07DBF314CE7F6AD7 -:10145000FA93C07F474A357A7DA3069ECF1ED13BC3 -:101460001ED2F74487D6BE71213C6FEF1DAF1EBF61 -:10147000F70E9C6C84ED494F823E2A99A1E9ABE3BB -:101480004FC0F86DD5DAFBA3FD108F9A6FD2F887A5 -:10149000F8819F15D2DB96412FBECFF9FFC8B64D1C -:1014A0003550D77593F65CDD84EBADE6ED77B62964 -:1014B0004F023FFDDBAFEF7FF87BC6F602129C7C4C -:1014C00065761F5F18E5D56BC54C8E781B9E05723F -:1014D00025D58D4FE1F96E100F60F9ACC4593E90DF -:1014E0001776D1433983F8DC2E8C731AC7595CC444 -:1014F000ECEB4F0BF579B136435ECCC7F353FD8D62 -:10150000F3269F4F7B69643F766C4EE99785503F89 -:10151000404E8B309E8B020CCE276BC952BE82FB95 -:101520009475F1DC4D2AB23C709FFAC52AD899D344 -:101530002838210FDB52FC28C6E943F916DD792053 -:101540005A9E73AD5546F9F809AFEB985F2A4FBE26 -:1015500087B66B878A6403D6793831DF601E667D73 -:101560000AE53ACF7B6AE7714CBBC8BE08E3BE947C -:10157000CFF97ACF147658403EAB449D5C968DF2FD -:101580003A08F5C626C71ACC03DB8A2D9847D0F255 -:10159000CF0A3FFF5BCBFB4E3C3F98E9F7742DAE83 -:1015A0003B70FE5769DAE143FBA0532426E1C27C7D -:1015B000F0629F9A0CF52CD3CA6270BF4055DDEBE8 -:1015C00038FEA11482E70447CF6AC4FD41666A1F52 -:1015D000CA00179E2FD6EA63869FFF0EEE1BADD77B -:1015E000EACDC58A0360A7DA1EA17E1674E0F96011 -:1015F0002D5F3CC320EF171756A29E25D48E1F15D2 -:101600000BDF1978DFF3031359FEF84427ABE7F734 -:1016100016E9F3C0F759589CAF3D4D4F571B273281 -:101620007FF5075C9FEE2CFE7915DACFC4E481BC10 -:1016300018798C9D0B073116DC6F653C8F397D0E58 -:10164000DA758F0DA74BA4B6B6B9E97D8C2B0AEBE2 -:10165000D87B9F8D238DE0B798CDAC4D2F2AE4FF2A -:1016600033BDCAD422A8B368FA10FBB7AAACDEBB5C -:10167000BFF8CDBC226D9F088BDFCC77EFED817D6D -:10168000657F731CC7B0EFD527B1FA929585929606 -:1016900047C0730929E15AC05E4C29F0D5C3BCC9C3 -:1016A000984D12CC4393373B5EF9760DC81B224709 -:1016B000CE4B6B7CDF66C84BFBDCECFD378BEFAEB3 -:1016C00081F30DFACB433C5C2268F1B53B8A605E46 -:1016D000095ADE40BE13DABD7A1416E4D5E9D18585 -:1016E0000DFF0BF4689FDDFE760D8CF74D9B3FA53B -:1016F000ABFF42BC96B3F8D9376DFE1326C87B60AA -:10170000FEFFE8EF8C99E07B0BBEB35A90AB9C2CAC -:10171000B9E711F479BE778B06C8F35D2CFEF07F34 -:10172000F18681E30D62F1BF66BCC10A7BA87290AD -:101730008FAE2C06F95CC8F8E8DF5DEED1F5E6C0A7 -:101740007A570B9BFCD123FEFEFE7E4A8132A918FC -:10175000F5A062DA49E96775899DD9330106DFDEB4 -:101760007806CCDFAB8B673CD9F00F8867D0F55695 -:10177000227ECBF8F7BFF9F8BB15E12B337BE2DF14 -:10178000903E57E3FA36B1F5FD13BEBF1EE9E5976B -:101790008C5E7AE1C3EDA430F82C6CF8E7C0E75713 -:1017A000089FAD6C7EDF007CEE42787AD87C2FE615 -:1017B0005F1F2D1434B9FC06BE97CDE8E043B0AFEF -:1017C00099DF3DE94AA9CFEF7E34573E50CCEA631A -:1017D00082C5BAFA4FF910B407F08B8FC0F3087EB8 -:1017E000F1FBC5DF40BFD859C4E0D69777F1B3739A -:1017F0006F49D50D57D3EF7C48E10DF1B68E261118 -:10180000ED8B734904CF03D0EC8D502CABDFBB7054 -:101810003F581981FD88B67C76CE88763E8059ACDB -:101820001E1C902E84EB81418A15EABC96C8196D66 -:10183000B0BF75D29A2F70DF9555B6E1BFAB39DCDA -:10184000EDB1DC097E34F573AF83786A830BF7D191 -:1018500069FBCAB4FD1F4B02F3F6C23EDB0E4A0F12 -:1018600089F43BD3CB2CC7C3D76FB437CC86B6F142 -:10187000DF354D98A8AF07A4F047FBE7DC3A561FC9 -:10188000D761263BA1FEA35E15FD2DB4BD718D80F1 -:10189000E7712EA270027F7F52672AD6935B93D89E -:1018A0007967DABF7B4AE9A0331FECBF2322C17FEF -:1018B000C78EEF27D3CEF98E9A7A1ACFDBFA98AE7D -:1018C0001FCEEFD1CE9998C1E9448367544B3CC2F7 -:1018D000E51C850B01B8F0FD36D39A583EB8AD7AB9 -:1018E0007110C8BBA6F08B1591EA52E6B8F5E7A5D2 -:1018F0001BE319C6F3C6CDC43718F6D54D2F2C51AE -:10190000C15EB5F17ACD6822E3B9161FAFF9093B84 -:10191000D7A2CCA23B47C4F8DD68039DDA0C71075F -:10192000239D1AF1729D012F1BCDEC9CC1B66ED187 -:10193000A3D2DB6D0F2F6A877DF9EAC32656374F96 -:10194000643CF7A98D5ABCB8FF9C4E16E2F573397A -:101950003C35BC10D268017EABD6F6A19B1A57C2AB -:101960007ED2797C1FFA4D6413EE3358001604FDC5 -:10197000EE4208918B70AE8C6465CE818BC03CEAE0 -:10198000ABD83919265803E4091E3621BFB6B977FA -:10199000E2BFFB15186A893D99CEFC8948F66C6F49 -:1019A0005C8142E264581CFFFFE2577F5BFC2AB770 -:1019B000889D47D5161570E5A7B2F326A09E29B7D6 -:1019C00048423918B42829B8DF61FDA72AD081B66A -:1019D000DF81FE2CBB427F6EC2FA8903F87F45454A -:1019E00004C76B4B0D25835CFBB09FBACAEDE03892 -:1019F000303DB46122E6DFA9FD9B0D728FD9BF1582 -:101A000079BEA7F13EDFE7ACC5913EF12AFF39313F -:101A100007F6E71094C3B60AC10FFB77A63B853DD6 -:101A200082D4F77D62AC63FF5F9AB7BA93FB6DC156 -:101A30002882E720055349D57311F0F1835216A788 -:101A40000C6644C697F69CDA19EF4CCC61FED020A8 -:101A50004614A7ACFAF8C00703D18786C7F8C9F2C5 -:101A6000471373FADA0FE4299F40BB55F17D0078E4 -:101A70003DA98A12E8151250F03CBF69FF21BA0057 -:101A80008EFFE83CDCCAC2D44BCAC355039D0D503F -:101A90002F78B9D7FF0FF9613D6B0080000000007F -:101AA0001F8B080000000000000BED7D0D7854D561 -:101AB00099F0B973EFFC24998409041C24C00D0229 -:101AC000461BDC81802440E0CE4C12124860F83581 -:101AD00002E285008D5DB451791458BAB921102005 -:101AE000A260BFB4B5EAA34310DCDDFAD4D475AD6F -:101AF00088AE23A2A55DD4A8A1C6556910E4B3ADF4 -:101B0000ED870A6BEBA7F57BDFF79C3B73EF64C2B5 -:101B10009FB14B9FFDC2A337E79EBFF7BCE7FD3FD8 -:101B2000EFB939EA648C4D82FF8CC2655A01632D8E -:101B300058BE9CE18FC6A0BCB8BFA59C0B4D3B799D -:101B4000FBD1DAFF891A2319D399E82FDABF23F1E1 -:101B5000F6478303A28697B145A21ECA3A96CDFEE8 -:101B60008C29794105FAD749667997A658E7CBDAE7 -:101B7000A5C17C279CF6F19788F18AB42F69FC48AF -:101B80007CFE2FA31A948F27C17F03E3E552EDCF8C -:101B9000D47E65BCFD9F755CEF49C92C8FD2B1FF27 -:101BA0001197D9FF8A6538FF3D79BC7E6A6854D4A5 -:101BB000B804E1F9A6C7BFD0F647A7A88C0D047CEE -:101BC000D4FD2C7C19FCBAA47E97AC43BFA3CEC82D -:101BD0007B2C07C8EC5E49DD037D8A58BBCC6402D0 -:101BE000DB258F87213489B5C05C2B42F0BF09808B -:101BF00047AF83CF6304A21AD0D9E2A9269DD64469 -:101C000071DEDEE8EE9DE0771FC27527E0FEEE5242 -:101C10001BDCC6A865DA9404DCE110B487F116DF9A -:101C200072931FE15C3CC25CDF249AA739DBECD7DE -:101C30007DD6795F7BA194F0BD383E4F25B55F9C82 -:101C40006E8E37278AF326E05A48FB91806BA80DE9 -:101C50009F81D042C267C417DD3C08F013F1B38006 -:101C600001F85C54D728EB05163E32C22AF1913FA9 -:101C70005E8EDAF9A880F8A8AFE11A3629B24D8352 -:101C80007D62F9ED6A64CC37B1EE98F3325CB7212E -:101C9000D1BA4D3A5AE2B3D0BB07D6AD9AE52B97ED -:101CA000D579FB62DE8E329AF723C0374BF01333BF -:101CB000062FD3BC173E5E9377B90BE15EA5495A58 -:101CC00014DA7F853FD312CFA35324E217C0E7BFB6 -:101CD000123E8B009F99F89E111F3C5E18F9B906C1 -:101CE000F54CD51D07002E97E6612D8083AA8991BA -:101CF0007DD49EEDF423FE01001AA7F975A6209F5E -:101D0000016F051C93A1EC6435ED29E6FD61C84126 -:101D1000ED9B18AB6807F8C66FF4AD8A7813F5BE73 -:101D2000320E5796781EC9ECBE6120CCDF0D551BD4 -:101D300061FC260398179E1FD4495109D6FC416EB9 -:101D4000645631943BF21C818D307DC73AF7D03513 -:101D5000D0BE2BCF1B40E8BAB27766FA60FC0F0208 -:101D6000B2C0D74DEF235F1FC98CF39381FAA5430F -:101D7000E0F7D75A711BF2D3DB2A2F3F50FAF7EF67 -:101D80001B05486FCCC706011EB007F0AA23638A63 -:101D9000C70DF3BACA419C605F1FD35D50EFC67A8E -:101DA00058E29C1FECFEC13C95E4C6CB23AF65AC6A -:101DB00006DFABD85F31BA3D34AFF295444FE6BC95 -:101DC0003631AEABB5E9A526809FF9651642DEF245 -:101DD000F3F67ED6DDF89503C787723E43127CE1A9 -:101DE0002B58BF24CAF8F3152CD1CB2215790857EC -:101DF0003E0BB4C07C7374E789783D7F6C57AE1599 -:101E000070223CF2868A6278A6D7D9DBCDCC87B225 -:101E100027519ED15A1B42BCCFD0A0DB58C60EB76B -:101E2000D6C66A01CEC3456E9F049876E52AB6F6FB -:101E30003359FB26C43B530F1D94012F4BC57C4DDA -:101E4000BE39EF31E8B72A1F4AB0FE23FF10CC9C01 -:101E50009083FC26071CA28DC3C407A3764E079768 -:101E6000D30109DA373D63EEDBC436E4033943B20C -:101E700095832EB37E4C1BF2E191B85C1DB91CCB4F -:101E80000BAE30F926B30DF96A5A8659762D473EC6 -:101E9000EA569C429E0D6C433AD96A8E67EC20F953 -:101EA000F21633EB1D541F89CBBFF25D585EE81369 -:101EB000F018DF2779D8A4717D72D50BB16EE322BB -:101EC000DA037F5E19447E8B7079975C3FA933DA21 -:101ED00094857C07F819A5F6E4B7F54199F828A28E -:101EE0007D2CE3FE95D603CE60FFC23552E704A4F5 -:101EF0004F850D45BE6F6E009D3E0ACA2FA6B9D410 -:101F00004C94EBBE722D05FFFE3CC8F97752D09B76 -:101F100073127157C80A91EE9A1BD69AFD0DDC5FB9 -:101F20007DA42B9A96D7FB38AF851D24673A24DF12 -:101F30007CAE9F6586FA3978EF15DE629668F758B1 -:101F400098EBE5C6426D7A10E69D05E297C11E3614 -:101F50004EBD3F1282794E143B036EE233ED0DE429 -:101F6000B3B9828676B834B60EE546B1DBB71165F3 -:101F7000B75CE05C0B656508F02B962B387DEBF0C9 -:101F8000EFAB1138AE92A07F8063CE5A3B3F28CC96 -:101F900042DF50BF28989973F25B50B89A5D8DEB81 -:101FA000BFCBE95B8A726CEB08DF2D5679F6689837 -:101FB000CBB1A858EF81A9FF5283F8F994390228D0 -:101FC0003FF6A647489E1DCB62AC0D75BEC654DFDA -:101FD00020E46BBE0E297F21C3F60F0E87250C0669 -:101FE00038D6BED3515A08EFEFE3FD3EBC86D53359 -:101FF0007CAFF0323C0C632CB63B4AEDEE0C8EA06D -:1020000079D943018F07691F9AE37E7B59BB139FE0 -:102010008E8C6787EA29F6C77CB2D5CE8FE27840EE -:102020005E024D88EB9698EEF80AD72FE43FD0E990 -:1020300006DC1F90FAA447267D78CA466FE3822A01 -:10204000C1914C77D0AF89FACD37FB31A76EB1D7AC -:10205000D7077F146D1C49FA681BB5F3823ECAB1DD -:10206000E9A3BB8229F4D1C84AED6EFE9E97A1FF79 -:10207000BDBDF4FF5FA9FA43FB1FD27B8F4EF8AAC8 -:102080009AA8FD08CBE38799F2041A1681FC186020 -:10209000CA8FF41BEBA658E48F31E1619437D7EB7C -:1020A00092A8CF7F98F44EC8ECFFABA57679B4E048 -:1020B00061BB3C9A7923D627E44FED4376F9137E32 -:1020C00018E545708ED06BECFD8770FCE62566FF49 -:1020D000D1D120DA250E531EB228F2A1CEE2659BA3 -:1020E0001D79E4D9F6A5A8E74CBF8919ED0F213C6D -:1020F000A69FF1D6B3FAC3A817412EB2E3261F8CD0 -:10210000E8C9EFA61C30E9C7B40F5F7B31AA1BD02A -:102110006E6E8516B3EE4BDCCEECE6764FC2BEFC9F -:10212000DFDCFEEE7BFBF1759ABF80D3DB3730FE40 -:102130007BD6F14D7B0ADE7713FD89F7979A3F072F -:10214000F09D26F8C673F82EA2FF17B4EE00D75301 -:102150007F0578D343163FE012C4E7B04B1CBE7135 -:1021600021DCEF2ABEDF8F69CC94E31308EE1E74E6 -:1021700070DEF45F42E396F2755BC6D5ACF3F5E62C -:10218000AF43BB327BBB38FF54105C62DCB3F4AFAF -:10219000B6B78BF78F842CF4D9077CBEC8BABFDFE3 -:1021A000801C5945E38FE4E3CF4BE0F126EBFBFFC6 -:1021B0001F373B279DEF207AAAE7F4741EF6F60F2F -:1021C00010BFDBA4763D8BE2448689F7FB701C7858 -:1021D000DFED82F731B11F8F14471EC0F658F48F20 -:1021E000B3F827C6DC5D085FC23F81810A2CFA9EE6 -:1021F0005DB70BD763EAFB27428B761940277298AD -:10220000B77FF4C0CBCB70FDC965B04BFE99F63FEC -:1022100007EC92316497FC0BC275AE7101FE76C279 -:10222000C3D39C6E52D43F49E33EC6EBB7BAB81D48 -:10223000FBD6924FC98ED36E551D68C7997AFDF9AA -:1022400010B767C11EA9887A7BDA8DCF8B781A8C7C -:10225000FB3CCDDBCEF1DF199133D1DE4CD82D31F3 -:10226000F2831276D50AA2A3B85DC5BE4DE5A96278 -:102270009FDF087D679980F7571C0F623DE76EDF8F -:102280004170F879FB14F59D345E2E8793790F9D8C -:1022900040BF95E895FF8C7440799528049D0B4AC2 -:1022A00072C06E39D02AA948262BEF33F7F976E2AF -:1022B0008BB8DD26F8F07A41C79F84D6D33E5E7F87 -:1022C000DAE4FFFDD47E7CDC4F5D4FF0BF2DE213DE -:1022D000DF0BAF37E1FB90E053397CDFC0F8A70993 -:1022E0003F8CE3A786194EB4CBD0AFDCC37AEEEFB8 -:1022F00017228E03FDFE2FF5F370B86A7489ECF790 -:10230000C88A634EA4F7A59D4C4B451F72D865F64D -:1023100097C364970BFF36C0E342C9EDD3C2717A0D -:102320004AA3F63E3EDF86E2480696A7E8AF870757 -:10233000F1ADF1A03D1A2995A22D79E8DF78CB4ABD -:10234000A13CC7C1BAC9EF636C33C67DDDCF2AACEF -:102350002540AD55C512D7012EFD35FA910BC43E6F -:10236000CF61F1F88A03E33596F80DF981EEF09D1F -:10237000F9AD2AC55D286EE3F2CBE45704EF5E4168 -:10238000F191F422B7CF8DF3C8B9E4E7BA1E10F18A -:10239000A2F9DCBF74C03FB4A3D3D732F2DF666DBD -:1023A00097A22AD4BB357BFCA576C3A926F2EF56AB -:1023B000309F067EA25264AF7725F9AF8D857A00F3 -:1023C000F172F2BE5A07E22358C9FDB093F75DE1FE -:1023D00045FE4BF6A34FA21F4D52AA871F6DACC3FB -:1023E000F89AC58F5ED3877E74386CF7A38715473C -:1023F000CAC248E78A46F2EDC0D44973C95FDE2EEF -:102400003337B43FDE3AFED522281BDB9500861B0E -:102410003E706A4BB1DE007F5A1E46DBC430BE35CB -:102420005BC07FBCF85429C2AFDD3E2C80F47EFC3B -:102430006E37E1F9F8CAEC68068C97B5FDB34D69C3 -:10244000D0FFE5E8100CB2C5FDEB643F1CDC2703B0 -:10245000E9E6381BCA5A701F141FC37195FAAC8085 -:102460001148F8DBB3F37D068EA7473318EE7BECFB -:10247000974C3A99CFE8C801E9780E539D5898C710 -:102480003427E27F01D3A97C1DF09B7405CE976FA2 -:10249000101D00DF61FC6E7DA17E13E1E3414E1F44 -:1024A000EC1E65179E571C37EECD443EDB9B6E8FAE -:1024B0003798CF3522DEE0413F7F4C9FFAF9EB0899 -:1024C0001E2127CE43AE34F0FDE4FC7A1AFDDF81F5 -:1024D000A427EB90CF3B441CF89E6C1E3F690D7304 -:1024E000B992FC0486CFC1FE17AA27405FEE08DB35 -:1024F000FDF89D583E0F7DF94392334FF2753687B4 -:1025000099297F7E1CE676809A45F11410C5D7F292 -:10251000FDC59FCF25FD611C5F7B4CA2FD4A531971 -:10252000C921378BC4383119623D6CC3207BBFBDD4 -:1025300067EB776390CFFF4191FE136C57720A28C7 -:1025400014DAB9AB781C7CB6577A495213ED8E6019 -:102550001C2A55DC5FC85168167380BDB2230BF688 -:1025600000E3DB4AA01FCAEBB71AB4A368C31D6916 -:10257000A8A06797524FF2A3EB3E39DA085D5F6D72 -:10258000601DA5A37A8E5BB32478F484451ECD2EFE -:102590007BC403429135E5B71D92305EAFB9553724 -:1025A000F4EFC88CDC83F17AE37599ED017817CEEE -:1025B000AF3C7AC2221F92C785F998012CFB56982E -:1025C000C7315F0CBA63D3009E1586144579B0C23B -:1025D00038E6C478E5D2B5CB980EFBE42A3AA6E0FB -:1025E0007E96077DB4CED94532332C70DD7FADD6D3 -:1025F00011E6F19D37687F03713BEA4D2C079D5A28 -:1026000096AF20118734CF051E0BEF267BB4239B9A -:10261000D1FC113F8B36A2FCD296B9BAF19CC51FF2 -:10262000A1B8E9E1B04AF3AE6CDD45F0A44FF998EA -:10263000E001DB39E6E8DF13DF261FBC2EF0DE2CDD -:10264000F0DE1B9E3F09F3789E599E5DA664229E94 -:10265000DF50543AE7E88DBFE796DAF7C7EDAFB041 -:10266000959BB4DB1D484F275BE528EE133C5FC10B -:102670007D3B0DFBC6F212E37464B21AAB7E36F7F3 -:10268000674AA94C7099FBB3743BDF9FA5DB838439 -:1026900097A5A595AEC1FC5CAD1D689BE945CB181F -:1026A000E2C5A51D53508EF5B65FC06FEE528BFD8F -:1026B0007811F1F37EA516BBF69B8EEFC37C4369C0 -:1026C000BE243BFBAF75BE60D25327CAD582845C63 -:1026D0002D2BE5FA20F969CA558B3D49714D0B1C2C -:1026E000CBEB2E020E934F904F516E84774ACEEE75 -:1026F00002DC7FE0D731689FFD76F36539C8378CFF -:10270000E8C151CAF9C635658E0BFDA695F77DACBB -:10271000A0BE027C4E277C0A393CB694997A6806A2 -:10272000D1451DA78BFFEE731D806709C1B984C316 -:1027300079A99D3B7DA73A525F4AE7402097BC1894 -:102740008FF789FD674379DCFBC2CE373F68BD9DBB -:10275000A11D38E70F992ADA818B8AF768796ACA4E -:10276000F34D55B29D6FD68618F9158C8506B37357 -:102770009E6F269F9FF63CEF345E6ACA49D8DDC93A -:10278000E79DC9E79AAC97F3CF9EE79D2F561503B7 -:102790009C3302B24F5513E799AE2927DF65D7F472 -:1027A0003CEFFC12D623F099C32CEBED1AAAB6C766 -:1027B00000BE96C19E401B6FCEE46B1378043DE0D3 -:1027C00071C33C9BCA007EB497F3DA7E308FD9F098 -:1027D000E8223C5C201EE97C1BF1D22A4537627F4F -:1027E000A5DE4079BE92F9D4FB0389FD8C8F977FDB -:1027F0008786F2F91F6ABDCC01FCBF39E736B60CFB -:10280000DAA71F4E6332B43FACDE46FB7DF8A34C23 -:1028100015CF7BDD7ECB3E085C2A267C724F3FE9DC -:10282000AFB08F1E64B91EFBA8B695A29E3DDFFD1A -:102830007BA4387204F9D803FA5A199778DF3594D3 -:10284000E3B3FB2A166D937AEE23E05B23BF339F3D -:10285000EDDA48F5F50CE3039B24C6F19D44178E91 -:102860008C0D069E6BBB967BC98F6AAAAF277CBF77 -:102870000EF8367C9CBFF09CEA2CFC65D2059306D2 -:102880009D3F5D24EFFBE1D65AB6F6D2DED75EF867 -:10289000737729DA3DE7BBAF5593B57E6513ACFB83 -:1028A000AC65970DB4F2AD21F2520CDA47633E638A -:1028B0007BB27BDA51978BBC14186F30F61F52C66F -:1028C000441C501B82E579C3597DAABC17E774EEFE -:1028D000C72C01139CE22A463ADB331EBDAC9DEFA8 -:1028E0000D42BFCEB84AC532530F4591AE6AF912B8 -:1028F000D8911DBBBAB07E362CD69143AF54870514 -:102900003F81B23C1AB778F5B15754AA0ED0F82ED1 -:1029100010FEE8A72EC197944FC2A27B480EE86C28 -:102920002EC8FB1BD648EF61BB1A2383A15F9BC84F -:10293000AB783429AF829767E78A7AE3DFDA6CE70E -:1029400098C60B49FAEDAD36AB3FC58C63A4DF6C7E -:10295000F685459F1D79E9F7CB0DEB39A6F1318D51 -:102960007F7489395FD16EFB39E69734BE19A7664B -:10297000EC332A2F89973F27FD6AC691FF5436B161 -:1029800096C74DF5B9B8FF7258AA47FB08148C26B4 -:1029900051BCC6D786FE34D8FFF3B0FE6F7D9D6074 -:1029A00087DC5C6639FFF85B83FFB819DF370E2FD1 -:1029B000D70A2E7D7801DF0F10BE2B38BEFF06E050 -:1029C000FD59598A73804B08BE9708BEF839C47FF9 -:1029D0003B3C6F9559FCCF6F7ABEC993B513484FF6 -:1029E000DFC03A4E9559F20FCEA3FD7F517B715E49 -:1029F0009A5C7F73B98FC7B1C439F1DBF173BCAC9A -:102A00005A1CAF3B71AE47E75E8973C4E157044778 -:102A10005AE11FBE1BDB9BE78853CBF36A292FBA11 -:102A200097734C0DEB156B7F95FAB724CDE712F534 -:102A3000F3CBBF556BD8F07335B5EF486A5F23D63B -:102A4000B7BC7CDC6EC3820FF038A97D5C2EB189E7 -:102A5000B5F673C709B5D673C7D5E513779BE7FFFE -:102A6000E5881F714EFB3F1D1FC172E16F8AF37233 -:102A7000930E874DD242E5132E3D7861FF16965B8B -:102A8000E8FFAF30DF8A724BDEC585F68FF3A3D047 -:102A9000FB66FE04E0F7165CC7CDD355C27F72BE5D -:102AA00084E92746BA5914FD96C92C2AE3B944246F -:102AB000A0338C83C6F9DAD06A295E17BF1F51B1E3 -:102AC000DB7E3FA27137DA1709FDFD54AD3DCFA182 -:102AD000DC06F78E979F32D7DD546EC967E8EBF1BD -:102AE000574FB7E3255E16F8597CCB8F87DAEF5F37 -:102AF0004476D33946FCFEC5229A3791DFF1EDDDED -:102B0000F6FC8E35544EEC5743D27E7DCF06D71758 -:102B1000E50D04974BE4BDB95648BDDCAFB89EE463 -:102B20008279AE0B659B5CA0F23700D741938E048F -:102B30009FC6E1EC919FB76C37C699FA7A7E8B5CA1 -:102B40007809E9A2EFF1CEEF779878EFED7EC7F53F -:102B5000AA59FE6E6D5DC1D79F17F3FFCA53E61FDA -:102B60005DEC3AF87D1157F27D11B6AED62E7FCED0 -:102B70001BBED3A9E5CFF9F5FFB277F9F317943F60 -:102B80004D5E07DD47D1FD2CE57D949BA7F373A92E -:102B9000387F8AFB28F376A4F6A7FF7E3A8F5F9BE7 -:102BA000F1EEA0EBD40AEB79D70051EF9B1ECF1BBF -:102BB000F04DC771D772F886A13CC4F31EA6300D44 -:102BC000786AFEBCA1B9085FD37FF2F1981FFCE4DC -:102BD000CCC47893C578E63C2FCCC9ACB1E635E4DB -:102BE0009AF34C97CCF8F4B0E988CF0D7C1D72BFF6 -:102BF000D574CF2BEE571BAD24BF9A9DA69FFDE049 -:102C00006E92677139F463A28B056E93FEA3BBAD20 -:102C100071E3B25FECE67A158A788E97E8775F2DDC -:102C2000F979E7E85768E27993D82F23BE5FE3117B -:102C3000EE73F5B7F8D1312927E1473F5EA84D4142 -:102C40003C833F5D723EE3009EC2B42F6BECFE8876 -:102C5000A57EFA745B5ED2A9D567CB4B9A3BFDEC9F -:102C600079497313F43077BACDAE0F674EC038C9C7 -:102C70006047CA7B14BAD8D7447ED74F69BF9A4DF4 -:102C8000BE13E57BB279FD0DBF78BC56C07FE374FF -:102C9000CBF98579DEC20A0EC530CE63C92FD21CAE -:102CA000D6B84FF89813C75BBA5D4A993FD3835F94 -:102CB000B68AF1B7C7F7F1E6E93C1EAD63DCF17AFD -:102CC00073DC6F37D2B8352BF8B8C97C73A788533B -:102CD000DD99A0E33B691C2D9E6FB30ECB9832E0CB -:102CE0001E9718DFBCDF1374469EC3739D66435264 -:102CF00051BEEA6B97D1B922AB606C14EC5370F003 -:102D000088ED283ACCF98657F0FD825F4BB19D1FC4 -:102D100024A43118F3C497D1B9F3B51ACF5B9958ED -:102D2000D5280F5429AFA505F7AD78FEAE265CF681 -:102D3000754B7E26A7CA67E988E7B3B037460E020F -:102D4000FE16F0E1BD903530CFDBF17C96AAB23BA8 -:102D5000ACF92C91AF97CF62C6FF168700AF967D76 -:102D6000CBAEE078CDAEE0784D9C03333ABF1DCDBD -:102D70006A665C85F165BCB705AF3BC43DB733B946 -:102D80002C8AE7FF8D53D3298ED79DCDE85C15366D -:102D900024ABFA5ACC23E13F69A34A298EEB86750E -:102DA000E13AF05C3676250C2F2FE9174B41CFAF77 -:102DB00066E92CE0C5B8BFB19901DD84F57BE97CFB -:102DC0006EF88A8FEB70DEA5BA5B4512B8BECE579F -:102DD00046795CAB03CE3B300EE9979986F1EC2A3D -:102DE000E7FBFC9CC643789A5DCACB265EDC4C7937 -:102DF000DF8A1725A9BCF6DDC62D072DED5DB1B420 -:102E00004C3C177C69BAC80712F78A98EC253A3807 -:102E1000E37744F11CAA4361071480A35697E9FCA9 -:102E20007DCFF65B5FC1FB634BFD4AC001EB0CAF8E -:102E30009528FFEB7A1FC7D3670DC6968360C3A69C -:102E40000D1E41E730677C1E8AC6372FD943717B40 -:102E5000A0970E05F37AD6C90CCFBDCDFCA7398259 -:102E60005E4C3CA62DFB94F07206CFC3112F45D9C2 -:102E70009407350BF0A1FAE89C7F13E2299DD5C792 -:102E800006C0BC0BFD0E16B3C4A161FDB63C3218E2 -:102E90009BF2CE147A63AB27FCA4AF0BF37C34B95E -:102EA0002A86FB7AA688EF2B940348EFAC94D3A92B -:102EB00089FFF4243A7527E58725D36932FE4F232D -:102EC000DE2DF7B9F6282C10437AEB94C9BEE86ED4 -:102ED00055B228EFAAD54179578C45E91ED31ED6A5 -:102EE0003FD082723326D139C175026F26DE19AB0D -:102EF000DFBC1CE3DCF559018CFF3347FD66CC8F4A -:102F0000BA3E9A41F9778B583BE541DD801E32CCC1 -:102F10007B23F3B9B0BC9C05E829B102BA5FB2507B -:102F200097882F7416ABBE0AF017BBDC996DCDAB3A -:102F3000EA35AF09567ED2721ED1BF42C84B8FEE22 -:102F4000E7799EBAB8F7A3517E507659A9474F2129 -:102F50006FA715EB832B0626CA8AAF9ED1F9747131 -:102F60006448C58444FF470BB55C6C37AE481B8A88 -:102F7000CFBD68E7813E081F1AF508EA83C6424DB7 -:102F8000C5F6C9F2EA78EFF977B1B540775D28AFB9 -:102F9000288FB080F8B0AFF2EF0A2B7AE4DF4DA8AB -:102FA000B0E4DF1D75F27B65948B3C99F5BC9FB650 -:102FB000F63AAA37EFA725DF4B630FF2322CC86829 -:102FC000198BF777EB69DD26DE93F1C3C4BDB4C579 -:102FD000FE97BBA46BFA206FCD07C6DDE0B3D187A7 -:102FE000C1EF2F57DFDA954379840AE51136E7F10F -:102FF000FBCB9BB00926028DE4F6E097425F6DC9DA -:10300000AEF707A07E8B93E7C3B07C9DCD1B9318D2 -:10301000F7CB0AD93C175A8A7400761FD94BA6BD44 -:103020006AB6AB157A6195D00B8F17465612FE1310 -:10303000F9DDABB03FF3C6A20EF3DC8EFFD03990C2 -:10304000693F1C19524FF9346E2DB5BD706B455C4C -:103050009FDF4AE3B79AFA5CBB0DCBD306F8E623B1 -:103060009FB9C2326B433D36FB6692BB4F61DE288F -:10307000D83413F5C6F020D8EF860A71DE54978D48 -:10308000E8621D1ACF278D95D4FB51DF6D199CFA8C -:10309000DEF761B1CEF1C34EC938EE96658C6D1C7A -:1030A0008BF833288FCD5800B204CAE0EE1FC473EA -:1030B000190FDA01C5A817797B5F1DB4817D6C17E4 -:1030C000F80F8E06FA41FB6B943D1FC97C9AED9276 -:1030D000F3AD409467E2BA93F3DCCC7CAB2EC5C869 -:1030E0000CA4807F76D91A0FE56BE52EF7A09E6CB5 -:1030F000D6C2345E72DEDB965C3614E14ACE6B33A8 -:10310000F3A6CC7C2973DC7FAAB0E7B5B9FD5C6F70 -:10311000C193F2647E5AA1F2EF5268F6FC3633BFD7 -:1031200006DB537E4D2EE3F935FE7A86FDDC50C674 -:10313000F611917F969C570572E86744573DEC2342 -:1031400046764673B1C81B60DAE665681FE1F96D23 -:1031500020857D050201F5A00BF413D62BF2EA0AB7 -:103160004CE5F9BA76D4B4E2C8CB48972E7F5CCE52 -:103170001E22781372F697580F72F65756397BE66F -:1031800090F108E66F6E91381D6E01BC3F91823E52 -:103190008E5448828F53D3CF1F04BD361646DEC2ED -:1031A00079B41C7EBFE342EDCCE6849DC9F1D847DB -:1031B0007626E0E377840F21A7011FBF473893F1FC -:1031C000003F9B506E58F24C3FC57EBDE59926F7F7 -:1031D000BFD87BC212C80DFE1D09ED2F0857D5447C -:1031E00095EB5D218F13F76D2F4E5E773A408E027F -:1031F0003C681358DBFB2AB99C2B98ACFB2A492F5F -:10320000F3FBBEDB82FCBE2F8B69A4F78F64EA352B -:10321000C8A72C7FDC39E66B14F9B47A5D84E4FC32 -:10322000DC73B4DF48ED0B268BF5E6F727FDB14DD7 -:10323000D2EE4B9713E573ADCF53A98DAA447F53BC -:103240008FD0F712B6E43B54039676CF44FD5BB8BB -:10325000AE2DF91B69FF5A80E024909BB31CA7EEAA -:103260001E21513EF0D3523F787AC0634B41D7457F -:10327000023F60C5523D7B57F35BE31CB595F1B847 -:103280008A884BFCF323D67B4C732B7FB202E3F18D -:10329000A61EC378C91329E82224C691DDB7DAF443 -:1032A0006472BBD24A7E0F645EA5381F107A6F81AC -:1032B0009BFB51EC30C067D1AB05934315955C6E19 -:1032C0001992451F9AFA8F6A2CEFDD7E7EFF847576 -:1032D000DAC731D7B942D0A9392FD0EBFC4A1EBF8B -:1032E000585069A95F20331EEFE8B0E30BE0594462 -:1032F000F03076A217781E49094F971D9E1571BAB6 -:10330000D556E078A09757E2736B08E82E057EC784 -:103310004C08DD84F50A33B68EC83BABDD5A8FEB23 -:1033200030CB16BBF5B64ABB3CBDBD92CBD3359571 -:10333000244752CFDB50C9E5629F7D3FE03CF9FD59 -:103340002EFC3505DFB4743F99710DB09ADB6DDC4E -:103350004EFC5930EE1CFCC5F9F9C661F5A4E79E98 -:103360001376C8734EA6607E0DF0582055DE4FAC24 -:10337000D2B43BA243102FCFF46277C4DBF5925F47 -:103380007F25DB997131F647CB942319647F9C6EBE -:10339000CB403DFFCC89504AFBE3B9DC9D4352D979 -:1033A0001FFB7AB13F9EAE14F6C7072EB2274A3EE6 -:1033B000E4F647C9873B65B423FEBD52A5F5149FCB -:1033C000E8907580BB04ED0F18679FB03FB03DD902 -:1033D0001FA777CA0857F1871DD4AF04CA687F14A6 -:1033E000F7627F001432E2E1E992963771FF92D7DB -:1033F0005B355EFF85956E8BBA3B28CE63F66BC955 -:10340000DF98A1D37EDBE9675A3197BB897E9CDECA -:1034100093DBF546676572D5D66E58D73696B99365 -:10342000F23295FA87B16C180AE56BE10736906EB7 -:10343000EE9C0D306463BBFA47BB51BF186E1F7E14 -:10344000DFE0B3F4A5DCDF59C37CCEC90979444B76 -:1034500007D08C9018CFE5F13581BDF4A38C2CC238 -:10346000E35A9F19D7D9593102FADF79E548BAFFF3 -:1034700013BA170682F2E44E99EACD38D02B83199D -:10348000E5E903FFCEAA86F1278AF141DF69B74358 -:10349000FB05C21E2B97BDD4FEAE7CDE7EB271AAA8 -:1034A0000ECBC5DD2E15EF993179837C0BC66FD11C -:1034B0002E81F6773D1B29F3407DFA118004C77BEE -:1034C000D745710C0DFE21FF4EE86C277C669C7081 -:1034D000D9E21BE920E16216FBC5955466F2927EA3 -:1034E000A9E493F9EC110F9A21E211D7B0BFFB0ABE -:1034F000ECAD336CC3565CA37B54E8C5DDAC677F91 -:1035000033DEF0FBF19A7706ECE348A74EFECBBE24 -:103510000AC035ECD3BED6D699D720DE772A14DF81 -:103520003DBA3E83F669FFBDCA2E8C2B1D053EE5D4 -:10353000F1F3B52B915EF7679A6516C3F8DCFEF8D8 -:10354000F70A07F07A515667043E40DF78FF40D112 -:10355000DE68E5F56699DDB512F337F60FE6E51995 -:10356000337EBA07DB63C637F9D76B8F7B53C9CF7E -:10357000513355DB3D8F5945B7723A3E473F90F77F -:10358000D7CC18D8B35F5A35F7B3F62F0110C7223E -:103590009EF4C21930FEBEAEDBB68E81A9C64F596D -:1035A000DF41727440F79A54723F3483DBCBB1929F -:1035B00028F95DE0CB73BF972907318F751653C784 -:1035C000A17FBF63EA33FF710DCCF36AF1A871727A -:1035D0000ABEBE61C688A475BD2E2F47B9F4D1FBC3 -:1035E000F353C981E64ABDC2BE1E7E4EDAB45321F2 -:1035F000FCD7FDC7278F60FE43AC6427C5F1F6FDFD -:10360000C1C1D06FD93786DBFF78534FCEE913F8AD -:103610005A27A6A03B806F492AF846CF643C4F74D6 -:10362000BCB614EB93E15531DE0DF08299154039AB -:1036300092F6DBEF77605C735FB783822B674EB4E3 -:10364000C948822D5D234AD16C9D56754C46922AFD -:10365000F1DDBB198F80F50DB28DFF2676A5DBCA93 -:1036600037D40FB09517D70D49F023C3FB4057D877 -:10367000CA6EFFD5B6729015DACAF3AB26DBC62B3D -:10368000F3856DE5E9FE99B6F695EA3C5B7966FE51 -:10369000625BFBEA40ADAD3E523056C1AB7C409719 -:1036A000CD88AF8C4E8DF87C4BD76D3EA48B58499E -:1036B00084FCEA23991DB918B77EA597EFCB75CC8A -:1036C00090857E07D308E524E8F38DD989F6C111EA -:1036D000DDB6B8FCCF67707DFD84A0EF73DF87E3B4 -:1036E000FAF97CEFC125EBE1D957DD4672A965BE39 -:1036F0001CC57B554DF96F78F1FED82BF3793CA1B1 -:103700002517D6E9A5BC0CE2AF17175C3714CFD745 -:10371000D2F3F50128FF4DFD1DCE8FB2E3509FEE91 -:103720008BB22BF09E19946BC57DB370017F3F5A0D -:10373000BC5F854FD0DBE5167C25EBE3A067EC4B47 -:10374000E036B0A97FF2D177FCE617F0B84FE9E98F -:103750006829DEAB9EA9BD70905F9FE6F2E7D59227 -:10376000DFE5F4A2B7FFDDCE0FAF133FEC3B31F73F -:10377000ACF2FF370D3CCEFE548387C5607DEF363B -:10378000F8E8F99F0D7E7AFF7A834ACFE6867C7A45 -:10379000C61A0254FF6643113D0F3668F47CB9A186 -:1037A000829E871A22D4EE570D35F43CDCA0D3FB61 -:1037B000F76770BEBC54E0D1F2CDB842E44587440F -:1037C000789D8F29BB933ED464AB7C07BCFE76C644 -:1037D000849E78BD583D122B691F12E17A2B251F5C -:1037E00039679AF76EB99D3C4B27991F87CF857132 -:1037F000BA9C449CCE8D264D7F82F32F7D09E77EB7 -:1038000011C7D99FCD6A9EE0FED42689F48D6F2C16 -:1038100097E7F7474224CF078E4D2DCFF37AC8F3B1 -:1038200065A4B7D8218C9F627A110AE395387FEAA4 -:10383000B888D12FEFAC78A0734B130F96FD1A3ECA -:1038400033051F9C0B0FC9EB9F56AC8D9E3981DF52 -:103850004771F6EFA94746777FA1616CEAE9020E4E -:10386000EF8EF7E7F6437BC58D4129F2DFC1702B60 -:10387000C2FD66665EC19EBADC9EE3FCA6A49DF412 -:10388000FA5D713BE701B26392DBC1CF41C203EA4B -:103890002D0B1E52C881693353D04199FC6CF746F9 -:1038A000E8BFBF9B51DC4C459B1AE07F46E1DF6BD4 -:1038B000D8FFA183F07CC623917C74AFBBDD83313C -:1038C000EEA7BFC7DB19D512DD63C838B04F453B43 -:1038D00035D8AD0FC0EF8E15C52A9DF89DD0D09478 -:1038E000B181340B1D8414BB9E444B35AE77282820 -:1038F000D63FA97C79A2BD8CFB3F2251CEA3FBD73A -:103900008B705D734FD533B540C459BD29F1B45A9E -:10391000B2C4DD1416D83A318FECCE8397E3F9CDDB -:1039200028169589AE0CF2BF4D78656F84EEE79945 -:103930007EFAE792B60AE7EB317E9D46E76FCCE16F -:10394000A0F3B7F585FA2D33E99C3EE97CC6F7F282 -:103950009F25D0695B1D2C86F68591E522FC25EF1D -:10396000D7B8A2CADBB1BFFF6BFBF53B25EBF70273 -:1039700046ABD3C89F3A03FE14DE476952F83D298F -:10398000E3DDCCE81E0292E5A3DD76A77C7500F7A7 -:10399000FF4719FF48FED15A5824FA5FDB851CBE49 -:1039A00007E5303CB73BB9BFD5DCE8F6B5E5A0BFCD -:1039B00095653840717D96362CCA609DAD33B93E11 -:1039C00077B31BFA45C69C057EE19F38E3FB9EEB6F -:1039D000237F4394BD2EDDF109FA7547E428C6DD47 -:1039E000B68D7DB06639E26FAC879F7F2A31750E48 -:1039F0001A683E83E558EEF1CB4C398971DAAD6037 -:103A0000CCE039EFDDE21E6E66C061B377FA15D9FE -:103A1000EDB59FF411DC2E9444E8B7E6B8A2988F78 -:103A2000A3A2DC02B8B7FA1DC45F9B542E1F3679DF -:103A3000358F2FC5FE6E417CBB7B9F5FCEDBE4C321 -:103A4000B8F74EAF83F877ABAA6CCB83F2562F371B -:103A50006A9B544745AAFCAEEE99DCBE8226699467 -:103A60000F159C4BF64E6FF3B4887D37CBE905BA42 -:103A7000467CA60622B89E266F8E84FB62D6EF9FF8 -:103A800029097DC5E3CADB84FD949EDF1EC3B84EC1 -:103A9000F3E05585882E0FD84327E1BDA7A09DEC04 -:103AA00027EFE52E3D15BC27C478DB9C810AC4E7CF -:103AB000B64C0733007FDBF27A39DF12FAB2491DC8 -:103AC0001721FA067C8C927AB67B5EECF366E74EA1 -:103AD0003FDE5BDB366A21E5856D1BCAE5F3EAC391 -:103AE000BFDED388FE83FA5DF609F24D8E42FBA657 -:103AF000B28007F55CB34FF1615C607CCE1D9EA087 -:103B000045CE25F38973F0DC1ABC4F78A6283D809A -:103B1000482F930FD377459A032077F3306FA9DEB0 -:103B200067FD5E00D8DD9F21FF9F8B4E55A67B1061 -:103B3000BF303ED1516FFB970C8F1725D3B8B3B46C -:103B4000CFD66B527DC7645415C7AB4937CE73D0FF -:103B5000CDB9E0B7E9C5DC845E1C5875D92A3C7F35 -:103B6000BE9BF1FACB0EFF8EFCF4E4F2D7E5CF2634 -:103B70006527C9EDA6912EA2A7E4FEDBF2383CEF43 -:103B8000CC3C29E20431E2DF6C0F8F37DD53D43FA8 -:103B90002D955C2E1BAF8FA9B2D81BD9A5EDA46FB4 -:103BA0005D558CC76BD5886F248CE3ED94814601FD -:103BB000DF8E2FFE744CBD783C2A3BEB5904C6CBFC -:103BC000EA94893EF1E70B9083FD841CDC32FC8F84 -:103BD0000CF347765CA10478DECA4781B3E993AC65 -:103BE00029F678D285C68BAAAA441E431A4BE379DC -:103BF00043552185F2751C5CCF6AF0DF2021222419 -:103C0000B1FF83C451948AAF789C2C670923B919FA -:103C1000CF5FC1EFCFE0383A237B042FD062BBCB1C -:103C200057737B2B97754B781E381CB37864A47739 -:103C30002E3FCFB05C07E5EFC034987F22190ED23B -:103C40008B3F1C7E540AC2DB7B8A578D457C24AF98 -:103C5000636595887BC5D771763C9870F6359D9ADB -:103C6000FABBC9C3F5B1068A3B0D8DE5A4F8679987 -:103C7000BC81EB63C3ED437DDDA4D43F8E65E81DBD -:103C8000A1786952FCF3B3341E1F95EE603EA998EB -:103C9000E29FF9B84F6B597A00E393FD14DD83F589 -:103CA000192315FABB0C60774FC4F396845FAE7A84 -:103CB00079BEDC5ACA2B7C1EF51AB43BF0C5D9E597 -:103CC000D193E7D06B2D9D23BD145FF7D466A03F41 -:103CD000FE947FC461F46FCE7878BE97D9EE40D25F -:103CE000F74F9A859C3B5C25E2E8699FC9D87F9A8B -:103CF0005F5530AF2EE4194BF2BD494A7D5ED05975 -:103D0000C5F5C168F5354E67ABCDEF96AD26F9FF29 -:103D10004EA6A0DF3A7D31C59585BDC7344DF55D12 -:103D20009BB0F34C7DE9577CC6CD388EC8B7EAB15D -:103D3000CE033731FC1E0BF35BE2B32370FE7EF142 -:103D40003C3BE2E724FBAE377CB608FFB8C91FA2B4 -:103D50003C8D3328B3529C9F984FB0530FA29C9A2E -:103D6000D061972F19F976F9B2D5514F795FC6D541 -:103D7000CC877921AC2AE0B7DAC960AFFEB28ACE2F -:103D800077ED76E74DD58C7F673B5B55304E13F66C -:103D900004199E4B28B93AC3FD70F90367DD8FB64D -:103DA0002AAEF79BF39747D0AFD931F53B8497F113 -:103DB000153C0FD56C07FAF29D2A8B7F63E6299C90 -:103DC000F7F7947C0ECA5F3CDF3852CB9495FC7BAE -:103DD0004AFEE5F43DA5A73CFC7B4A0732F50CB44E -:103DE000BF2EF47B4ACBAB39BD863CDF7E71DA084F -:103DF0000B9EBA74CA1F71F94FD1F9CD34916F92ED -:103E00001C2F72BBEBE9BC2D5652BFD81A2F36F1CE -:103E1000D726F4F66F4A74CA0BEAEDEF4198ED101D -:103E200063B82EB788876E29594FF89F5B914DF183 -:103E30002845C4A35CA774CA038E8ED733AA2DF875 -:103E400077E71AA4EF32FE91F1FBEE9FF3FBEE1938 -:103E50001B5908EFB787BE1847E754A1581AF1D984 -:103E6000D4D301FA5E7599FCD8D611507FA053A126 -:103E7000EFC81F989A9E837AEDD34E6EDF661CB80A -:103E8000EAF0DF41B9A4B316630220770096FE3D45 -:103E9000D731F5B4E36BF99913D0CFB49C9798E37D -:103EA000FEBCE110D1C7930D1DF4DCD710A3674B06 -:103EB00043173D8B142D8CEB29EAA0B34B36E90454 -:103EC000D45BE0287A17FA5BE8C1375E1F5F4DFCD0 -:103ED000D7616B9791DF656B077E6E11B653FC1C43 -:103EE0009F2EFCCE188C3FBB8B6D96D4FF51F26A8F -:103EF0005175DFC8AB1BAB079E4D5EF1F3D45097F5 -:103F0000F8AE58123FFE5795CABF8F64F2A53857D6 -:103F100035F5F456FC15F46953D677B87C8BE76F0A -:103F2000F0FB8AE677E9EF78E5E45ECCEB697E5B4F -:103F3000D41B9FEFC5F3DCC4DFCDF8E32ABC77F2D6 -:103F4000023AB76087BEFBCAB3ABF0FB410B6BB262 -:103F5000150DE00BE3016C76E2BE8C99D7988CB717 -:103F6000DF543BCCEFD0511CBE7904FFFB06C9EDFA -:103F70005EAC167E9B6AFFBB1FE9BDDC137AAE9A6E -:103F8000CB8B5F0ABC6D75F13C85DEEE837CBFFA9E -:103F9000ECF741DE14F5E7BAFFF113D1EE0931EF8A -:103FA000B04991FB51FE987F97E349F13EFEF73807 -:103FB000FC2CE5386D42EE5E3ECB27F653A3EF9F17 -:103FC000C1788F107D88BF9F60D64FFA305EFF4F5B -:103FD000541FFF3B093AC589CCFB786DD51D7B1B6F -:103FE0002DDFFF6A8E7F5791E739FD51E02DF9698A -:103FF000DE47897F3F8A1DDEAB59BE1FF540F59B2A -:1040000027C5F7AD9EA6F58A7B38DB70BD03E9FDB9 -:104010007E7A9FF43D81A75E39B8577C47F179825B -:10402000BB3EF93B5DEFEEB57E1F615BF53BAB44FC -:10403000FB97683CF15DAF147421E8F6E85EBC1FA5 -:104040007A1EE3BD46E389EF72ADABE67CD41B3D3F -:1040500043FB23046FFC7BC5B51ED42B897BFF4734 -:10406000083FE781AFA334AF6ECECBF125BB39BF9C -:1040700098F964265DB0597C3F3656C7F3744F12E9 -:104080001C2BFA0C0FA7089EA47B48E75AC7E385B0 -:1040900091CF080E7F3C1FF94F34CED784C7BC3F69 -:1040A00096CC1FFD6649661EB46B16CE931BFF6E41 -:1040B000A77B561FCC0BE366D33889EF81F69F951B -:1040C0005AFE5CD0B84C3DBFFC12B3FCFF0015C8D3 -:1040D0004EA0007100000000000000000000000081 -:1040E0001F8B080000000000000BF3176060F85100 -:1040F0008FC09C687C5AE3BF4C0C0CFACC0C0C971C -:10410000D818189C39191884F8C833E7229ABE7B4E -:1041100040B366F030302C636560D809C47A5CD84F -:10412000F5D90822D847817E5F01C417E91C06A390 -:1041300078F0E01A11068649A208BE9E18AA7CAD46 -:104140000882AD2345995D4E40FD008850BECB806E -:1041500003000000000000001F8B080000000000AA -:10416000000BD57D0D7854D5B5E83A3367CEFC26E3 -:104170003949069884104F42C0A84007080A1675AE -:1041800012C146E5B663DA6A6CA91DAC527F61B410 -:1041900056B956CC4908C92484101015A9CAE02F75 -:1041A0005A6D53456B9FE5DE09508ABDBE277AD50F -:1041B000AAD5DE5829AD566DBC9692BE8770F75AC7 -:1041C0007B9FCC39273393A14ADB875FBBB3CFFEFC -:1041D0005B7BFDEDB5D75E7B8FE27041F509004753 -:1041E000F1DF5900F7FB01605C3A9DF9BD2F5FFDDF -:1041F000781DFBDBEF0E3FC89299BF985F119B962D -:10420000AE3F0724AAD7F08BC57F0456EFDFC1A9C4 -:10421000B9D9A79D0543FE30CBEB9213B09D1BEAA5 -:104220004BFF25C8CA871DE16E964F1D760480F5A9 -:1042300033039CD80968A006A2D3D977F9CB45608F -:10424000EADF9E9EB949865429C0AE95204759BDE4 -:10425000D505A72D1E0C00BCD092FACBFE290091EB -:10426000D449B2C6FAD9DDB297F2FFD6B2EF2FFB2E -:104270005D003128A6711AE67F242F61ED76B9A082 -:10428000B99FB56B8848AE25A6F162623EBBBCA261 -:104290005CAD97339617B072F6BD217841C6F2181F -:1042A0009B11D52B16FD0C0F3AB19E06437E9AE763 -:1042B000E1A68CF39C20DA19F9BA413EDF9D6F1D0F -:1042C0003A1FE99082A2A81BD3C3D56F22BE073C38 -:1042D0009206550CBF83E7117E53885FD6C5A1B700 -:1042E00039BE777DE208B7327C3778D44098E54113 -:1042F00066F460E50D0188105C324B191CE70BB8C1 -:104300002F166913A644178DE832E06174098C0DED -:10431000EF599B1482D798E700CE338F76065DD98C -:10432000D740B480B583CC7C301A3F6CBCD9C70E63 -:10433000A781D7E8FC81BFECF700FD3BCAFEB75070 -:104340007DEE2FFB6BD3F9B386F759F28CA3C173C3 -:104350002A8317FFD43095FF3C689457F1721C27CD -:10436000D1A2FDB986F15F5F0BFCB986F15F6F8B5F -:1043700087F23D2D2AE5BB5B42944FC8AC09A3638D -:10438000A207923A6B5F1C61F54DE315CD65ED4CCC -:10439000F01584554BDE5F1BB2D4F76A9AA53CA199 -:1043A0005DEF4832BA774D73249D12C2C164E44474 -:1043B00084C3432903F7D5109B4F0D6F026B5DDA61 -:1043C000AFAA119E179DD0C6F2855AC47129CB574A -:1043D000869C900CB3F10B8700587F8995001B5881 -:1043E0007F3D334F755CCAF2DDF3DCAA530548B25A -:1043F000FE136ED6CF9194B60AFB99AE84B11FE836 -:10440000937F8B78F2B0FF8E56034CD694B71D8500 -:1044100000553AFB6E9E9F5B0FA15C17CDB57E9F4A -:10442000AC2DBD1658FDC960FA5E95A6A731AE91B8 -:10443000B78F671FE78415B6FE6DFD566A83F5EAF0 -:10444000B474BF27C050AB1AF867EE37D220219D55 -:10445000C2A025671E3FB8032B3E2EDE3F3B8DE7F3 -:104460001E17D78376791B0407E90F90C74184C1D3 -:10447000A5698E6437EBA7BBCA41FCA3AD8624EACD -:10448000ADB593F6C531DF5DA5686D2C5F55BBA753 -:10449000599A01B066924A7CD7BDC30D6D610E4733 -:1044A00090F169A5C1A74706EBAB910F25086F6096 -:1044B000E555DA8156ACAFBEEAD35C7347CF0F56F1 -:1044C000F0F9539ECD7F08FF9833BADF5FCE5122BB -:1044D00051E45B1D926E064F574D5BA3CEC6B95794 -:1044E0009701E5A77B65FF6B88E7C4140EAF7DDEFF -:1044F000959AB204F91ACCE3B3F12A6B2EBC1AE7F1 -:104500006587C3D017DF6F51491EEF6AA9A5F4DE96 -:1045100016B51FF5C45D9F3833E2F77C89EBE7CD14 -:10452000AEA803E1D3E739920F92FE896DBE92E502 -:10453000EFF9EEF859B80E5C3FCF41FAE5CF3D1CDC -:10454000DFF7487D1703D55734AA6F93FF7BE54803 -:10455000DBB758FD7B42A5A03379AE74ED3BF74441 -:10456000EC6F45F54C9DF577CF0D1BDEC6F695F348 -:10457000A66A4ED67EF2DC036FB2451CEE3A3218C4 -:104580008A0630CFE5BA72C5F8FE1AC62713B5BE43 -:10459000EB70FCCAB98A96AC4AF3650584699C1332 -:1045A0009AFD9052C7E6CF8A6B72F3E7F1D3037F8F -:1045B0001FB92A47B92A4DC3BD59D82776BA2F92B9 -:1045C0001CC42F23723597CBD513A7733A1B727572 -:1045D000D7A4BE778B58BEF71B9C4FED7C5E35F79A -:1045E000403DD2B587C94F4908A0CCAD7D2CB17CE8 -:1045F000EF122187730F484B59FB3FBDE2D300E513 -:104600006971667D9D8D9FD3A975DC7B6F70344485 -:1046100059BD5F5E3EF58F6E1C6FB1A2A19CF5CABD -:10462000B534BEF65D45D34DF4AC5CCCE489F157AE -:10463000E50D427E6C7235D6F8899624BCC3E468D9 -:104640007D4B08228C6EEB5A3492AFB542CED01619 -:10465000853296177206B5B3289FCDFE046825B93A -:10466000F368298831FAAC677D43397E4F4522F3E0 -:10467000014A50579D4EE0A41C6C6D5F37520E11DD -:10468000C6F4D02B89BCFE473DC2C653C33CFF6C69 -:10469000EB1FF5554C08D77B797E87545BAFCF373E -:1046A000B7DF43FD1BF5593ED55063EA0FFB9F660C -:1046B00086C7518FF58DFE5E6F2DAFD7D9F8EB44CD -:1046C0005E692BE6F9E3DC7F8FD41F624C0F6B6CC5 -:1046D000FDF448024FFA7F442281F438774AEF46CE -:1046E000744BF91F228827A3FC07ADFFA1EBACFE9A -:1046F0004710BD4B627498B520560E8CEEFEC61462 -:10470000A029B5DE86EFF4FC5EA4F905A6F1FC7DD8 -:10471000AD9F4410DF46F9D352412BE21BF92630FE -:104720001E20444202B0E9E73D573E8F7FD79600F6 -:10473000CC63E3687DA0B13E1C357109F71DA1C5AE -:10474000F2018B3C08BE63F03D2EB174D6FCD8D785 -:104750007029CC009F6E86CF187F2C780D38B2F36D -:10476000271FDFCE470DE7CC7D613E932FFF3E57DD -:10477000D8ADE13C5409F5780902C5F45AF1915DD0 -:10478000442790FB436847DBFB2D59500E49D33C2F -:104790003F6B7ADE85798EB797CD7465F957CD7802 -:1047A0007C1CEBCD19CD77C6FCBC383F403B98CD87 -:1047B000AFCE3CBF279B717ED9F0669FDF3A6F5F1B -:1047C000733483FE3DD321F6BB67CEFD12F6CFC610 -:1047D00003D45F5E6D88F4AF8AE3B1AD66D1915DBD -:1047E000CDB8B5CD369E3A9F8D577BFCF039161F5C -:1047F0000798FED2583D4738371FDBE5D998B71FD9 -:10480000E72D211FF1FD807DDE008C8F0AFEFF9DCC -:10481000F7C732A7E70DAC7F9DCF8BCBC73F685E54 -:104820001F3F5F4AF28AF038393F8732F1D73B9217 -:1048300066D9E7DAF93ADBBCFE517C3A7A5EB9F127 -:104840007CBCF550BEFAB5ED551FE1B1F732BE4F55 -:10485000E8DDBB90FC0EBDCF9F3D01E1284C9C02E2 -:104860001166FF4EC5FE597FBD867DB1A96E8CFED7 -:10487000B97D71670BF4B74F0178AA7090F6C30C3D -:104880004E6ABF99D99F49A6E0EA5EBCC1BB848D40 -:10489000B7F98A0D5EF42BF50A7BB1EEC507D69FFA -:1048A000C3F039E1F292994EC60ABD5EE3FBF6E72A -:1048B000A6B2EF9B2E13DF85FF8A7D7F11EB874425 -:1048C000FD6C70952983B128C90B83CB847FA3FC31 -:1048D0004907B74B9F403BEB44DCCF703BABCCD799 -:1048E000B704E95BB859D1EE9346F7FBBF853EBDEF -:1048F00013ED3436DFBB2EEF2847BB6AE7D653777C -:104900000510AECB80F4F989C987065C1A8EAF4BCF -:1049100088E7275C60D859B4CE975F66D0B5493A2E -:10492000BB86DA093B8BE7BF3FB2AE7E9DEC968A31 -:1049300018CF3FDDF6DDFA55B2A95CFF767DA422E3 -:104940005DFE42DBB5F5B8EECEF2C4DE98CF483757 -:104950008BE9BD550C8E59B2E68C23BF6C0A66B448 -:1049600017B73DE7694E32FC6EDB3A75F2E519D6B2 -:10497000114645A2B3919FBDD72A674F20FEDC8820 -:10498000476EB7F630F462FD504C5B85F89CBD175E -:10499000C2B81FCDA6EFB2D13174B755DFCD92ADFD -:1049A000F33A5EF3F90854BEDF16FDB375FD250733 -:1049B0009F8F13E568B6CCE5FFD3CE278578E276E6 -:1049C000C46F32F5FFF79AEFAC001B27F8D98F13AD -:1049D000B28D93AD5FBBBED21B4092D11F5F0E6103 -:1049E00084A778411CD08FEF0CEC0BE9CCDE93D57B -:1049F000414A5DC1A190CEF4AE12D2CA307557843F -:104A0000CBF03BDB1F09F9E86C25BD3A92EF6A4514 -:104A10003DBA0EF3247F6BA87CC3487E2DE56F9BC7 -:104A2000C4E5F304E7ED03A887AB51D930B8D60E3F -:104A3000BCDE8C7E80D2DD81309A1AA58130A01E2A -:104A400036CA7B07DE0D79D08EDB1D002FE3F7120F -:104A50003502E6F6EB06FE1A525979409407825168 -:104A60004BF9868193CA420C453E51EE0BC5A8FC1A -:104A7000B68179651ADA31BB032A7EF757C469DC3F -:104A8000B37F718D83FCB18B1C49B7495F2516CD6F -:104A900022FDBE588A9DE464F4A8FF458F07ED8788 -:104AA000C4EE6913F03BD93CE44F92FF2FEE47313F -:104AB0007B94ECA0807AE014412F679A1E3D785ECB -:104AC000417E607E4E9110E7147A432A85E3EB85A0 -:104AD0009C4E8CA3D3FE676ABF37EDAFA6FC3E4B5E -:104AE000BE404D46701F2D07997E60EDFD113D8241 -:104AF00074572A78DE1908A7507F6CFA0684116C67 -:104B000099E113EBAF9BC7F21AD23F4AEDBBE6F037 -:104B1000BC128AE9984FCCE47977453C85F9352772 -:104B2000F1FC2683CEF088950FE04F44F7AE91BCA0 -:104B3000B70DCB1306DF80BF0DCBD79CC1F56CB989 -:104B40005CBF13F1BF69A0AB6C29EBBF08F981F51D -:104B50005FB4384CF432E872A7E6A0F5D6A0CB9D3E -:104B6000DA2C3A279859C4304113D2881E334FB8F3 -:104B7000DEA1E279C7298EE483129E4FF5780759AA -:104B8000BD4DB5B3A8BC52760AFF00F7873F28FC9D -:104B900001D5CCBA40BBE341B15EEFBC7D6A11B632 -:104BA000DBB9F97F11BDCF741653BB35B5FCFCE6FC -:104BB00019B64EA39FEEE9160FA53F62FDC598BE3C -:104BC0007EBCC543E90F5A544A1F617A1CD31E5656 -:104BD0009E42BF032B4FB17CFFA0A311E5FFF61649 -:104BE000669AB1F6B7B5783E96A7A0BF42A5FCBAC3 -:104BF0009610E5BFED685AE1E4FE14FF3436AFA726 -:104C00005EAA21FF5EF875473489F356A174515DA1 -:104C1000FABB819F6F3B1A5622BFFE7050A67140AF -:104C20001EEC3E2573BD36AC37E37599F7171CDCD7 -:104C3000707E3063BD4EACF7D87E0E377852BE2CF6 -:104C4000FDF520BCD3DE12F085522559FA5B8FF5B5 -:104C50001EDD2FE00B24BB4FCE5CEF0E1CF7E4B73C -:104C6000047C15C90DE7651EF7FBD89FA784DB2BD5 -:104C70009F437F461DAD035B25933C6F5CA24B0EAB -:104C800046674FE9601CEB4DAF8B4BD56CFCE025C4 -:104C900071C9319DDB190E96F7623F2C3DA59695A3 -:104CA000B37A1BB1BCC0548EED597AD2345E1EFC6F -:104CB000A6B57C446F378361A7A6D0D91AFA8A3586 -:104CC0003FD5C1F5E3B3CEDFD623BF4F5578F97F8B -:104CD000631EEDAE45B6FA3E9EFFAD51BF90B7776D -:104CE000C83CEF29E1F32EDCEC49A2DDB57E61473B -:104CF000E8D2407ABEC5E7246A316FCC6FFD399B9C -:104D000043979AE653FC85BB6B2F9D967D5DF16AB8 -:104D10000E8898D6DDA97DD32052FACFAF5FBE6A48 -:104D20005A37705D9920D6850973F9BAC2F0A67317 -:104D30007B95E36DDD1956BC159D69C5DBBA33ADB6 -:104D4000782B3A2B37DE7E29C6CF863F367EC43C91 -:104D5000FE8673ADE3979C671D7FC379D6F14BCE7A -:104D6000FFD4E3A7CC7CD3576F1D5F6DB08EDFD728 -:104D7000601D5F3DFBD38D6FD0A76BE02EEBBA5E5D -:104D8000170533FD12035D21CBBA1EE6EBBA51BE07 -:104D900066E0A7215CDFBDB8BEA37FA696AFEF3368 -:104DA000DFF928847EFB7567EC09E13E631DABBB30 -:104DB0006F5A7ADDD879C68D8E4759BFDF3989AFF2 -:104DC0003303673CED41FDBFA696AF3309719EDB0F -:104DD000DD923A788D2B3DAF828497F67B467EC478 -:104DE0005E82DFD5231F266A1DC25E2A6B8B305B75 -:104DF000D473926CC9774DE3E537B797B5E9E84BC3 -:104E000091F5325C87FCB5F0E76919F65BC6F806E8 -:104E10003CD9C7E7FBE2F4F8936DE34FB68C6FE43F -:104E2000BDD379B92ED734203C9BC4BEF906F9779F -:104E3000A45F8E1F7CD3DB223566F8783E0D1FCF32 -:104E40001BF0DD2ACF68D06BFE9EF09D66C3DF6944 -:104E500036FC9D66C1DF0A79EE31E1CF5EAFC7C691 -:104E60009F5743E426791CCA1190BD199755711EAE -:104E7000C4FBAB93857CE1F818B7B344494EA9E273 -:104E8000E54D6C5D5B2C8B7D98A8DF68CB1BF62B0A -:104E90002E4747C90F93D97E5580EB6D6677841FE7 -:104EA00024BD1E26794AEF3BB81F4396A39168069E -:104EB0007D7087CCCF872535DC8C70CA0185FCA836 -:104EC000D9EAF7C992B0AF75CBF94E110CA59C0881 -:104ED0004708283E090E7F59BB60FA683814391A12 -:104EE000C3719CAA02F7B171DA8B2FD4CC714C8FAD -:104EF00018F08422048FA2727814391CC9E407BE0A -:104F00004FE67E0BA31F06A1683F0468271AF0AD89 -:104F1000F6469B97A03D5FAC109EDA0BACE7E5BF71 -:104F200011F37A41A4ED59CEFD00A331307E69FC26 -:104F30005CB24357CD6DF0205F6A10F6A0BFBE3D56 -:104F400090399EC848ED766782D9A598EF6076299A -:104F5000A6ED81271A71DD39887C9CE15C7B44CF0A -:104F6000851D9032ED3FFDB53E4859FCA74982D3DF -:104F7000AB9558BEBB43E59676AEF132D9F3ED0161 -:104F80004712438DC682BF43C06FD4EB94E31E35F6 -:104F90008FFDB23B6485F7F8E18FB7F7BBFAD54CCC -:104FA000707D567833F8CADEBF52AAC4C92E96A3C4 -:104FB0002133FF3B5D9C4F95524F9CDBEBD9CA7D63 -:104FC000BC7D8095A35D1C886A78FEC2449EE2C4C5 -:104FD0003C280726FC4C14EDDA5DE23C1AE2E4AF13 -:104FE00095B47833F291A742A1F3017B3B23F58975 -:104FF000F69D9F7CE735928F711E920F4963F29365 -:10500000619CC7E4C878174B37C9910998BA8E38A4 -:105010006399E4649C8BCBB1271AD53C3CD4242300 -:10502000FCB345BF7D06FC7A9CCEBDF285BF3A4FEE -:10503000F867A7E19FE19A43F07F0ED36CF04F171A -:10504000F094427800F7EDC8A0D82FC0059AF95C1B -:10505000AE57F45B2AE003B88EE8669477093CE427 -:105060003B9FF979CEA7373D9F46319F7373CDE7BC -:105070000B623EBD2EBE5E791AA35A88F1554916C1 -:10508000BA2C15FD6F1EA1CB75C7C4575FCD731E1B -:105090004BD3F35822F8EAD25CF3880978FA9C30B3 -:1050A0006F3FC6CF4C16EB0D3459E8B2C5E02B3735 -:1050B0005F3700AEB7D0E576D14FBEF3599EE77C9F -:1050C000B6A4E7F33D41975B72CDC754BF55D46F8B -:1050D00013724576CB16D78E36B43F1E93A31DAE02 -:1050E00039E9F158BD4E73BD89ABBB8D7A6BF0BB0E -:1050F000B468A45E8F185FD845F7D37E6C35DA1894 -:10510000CCBEF9E2EA171AD01E67ED3650FF51BE49 -:105110006EB276B799FB9FBDFA8E3651EF4EACD783 -:105120007AF611A3FF4DE6FEB7B852061C77131CA2 -:105130008D23FDDD63AEB7D4D5DFC6CF092BD403F5 -:105140007E935D13CAEFDCC7158C2506D15F090578 -:105150007D687774C8F12D83C80FCCC87B907DBF64 -:10516000C91D9124B67EAA91F8C358AF4477AB4EBF -:10517000A45B43FC4798D71D10C5B8C83BFDB76E6C -:10518000C1FC0AD9A3BAC3686F697434D41B9429CB -:105190009E67B514D3715D3C24C79E7191DDC3BA7F -:1051A00064E3DC54AA25BB25F4DF82C4ED0E0ED7E0 -:1051B0007AFF250984C3CDE0C2F8E0D536B8D878A7 -:1051C000B42FEF1AC7E36D40865A19FB73FAC2D8A1 -:1051D000DFC0B81B09DE44AB5BC5F689293712BCBA -:1051E000AC2C4AF179AE38C1DBE9F2A8188F77A769 -:1051F0007FD9268CB75BA117517D8203E73FB99A0F -:10520000E0F7423CB5A40AD5575FC481F02C522880 -:105210002E3911DC40FBDBEE456C9163E376D76EF3 -:10522000D0B1DDC1453E8AAFF306FA00E3AD4ACF07 -:105230005700E380BCC13EB2334BCEF3F17C05D0C6 -:1052400038259FE7F1B22E1854AB595A9AE071C72E -:10525000DDB54DFA12B463E6F27854D0232F617CA9 -:105260005B31887FCE8A01ECDF35D109CE709ABEE2 -:10527000A57D23ED8B6219E465A45E32CF7AA9FC8B -:10528000EA9524E4FCEAF5E5592F9967BD14AFE7E8 -:10529000860B8A32C57B8CF0FD0285EC0F23BEADF8 -:1052A0009059FE23F64915B7DBCDF68A0B94B4BDB1 -:1052B000827CE65C9C138E156FB606779BEC9BA0F8 -:1052C0005210A4FDC669701AC9E518ED0FB5E8C102 -:1052D000DDAEB1E78B129632F9C9C7AABF06ED3D24 -:1052E00077F672FF8C0B43A4CFA67F4DA48B793A3F -:1052F000937D9F8669B3C87F4DE4173747328C573B -:10530000AF703D5C0BD19C74F00AF80FE0993F6BD5 -:10531000522BB3FA19CEC78D3430CD61B31BADFA21 -:10532000CE23EB0D74CE51CBE307DD288C283761FB -:1053300020FDE282945A4DE78B91C225E3D3F2E33C -:105340000A8D27F9F93F654E90E6127DC288473BEA -:105350009FD8F92260E38B4FCB27171F273EF127F9 -:105360009C79C98FBF2FCF7AC93CEBA5F2AB174808 -:1053700048F9D5EBCBB35E32CF7A295E6FCDBF282B -:10538000C2DF7AFE2AF4C3F8BFE8B1E4D77CD16764 -:105390002DFF52C092EF39D7DA3E709EB57DCF799E -:1053A000D6F681F379FB273BBE7A36FA79F29593EC -:1053B000DFFD8D7252EBC95DBF64D11872E5D16912 -:1053C0003FE99535480571FD62EB9444692499C124 -:1053D000BE7B4EC8FFF32EEEC749C83AED6BFFD92E -:1053E000E7F90385FB8D8CF98E05AFA17F7FEF1464 -:1053F000F696DDFE1AF1EB1C3E7AF454D42380C1FC -:10540000D2A06A6C6AE8C7055F184345BC357D7455 -:105410003E6DEFBF0BCFEBB8DF25D46482E33937A5 -:10542000F7ABFCBCAA2344E7B553EE08E13EBD6BE5 -:105430009294D1CF7244E1E782D5313FD9199D9A38 -:1054400087F461D7247E8FA9CBD547FEE3AE2A6BC4 -:105450007B8FB01F8E287CBCAE957140FB7FF5948E -:105460003B9A715C77EA5F4163707F77529CE247B9 -:105470003BDC7C1FE08EE880EB8247D3E9FCDD0E4D -:105480004FC2881B82BE509369DE4D6ECE373F6798 -:10549000F3C9675EEF280AD557231C7FD9F0B5E31F -:1054A00018F175B99BF7AB85BC84AF837540EB09E8 -:1054B00012D2C9E84824D6F0FF06C1CC6FF6F51821 -:1054C000C027F8ED28E535F9E29CFCD425FC30EB4B -:1054D000D00FC352EDEEAFE5E4E74EB19EBBE1EB7A -:1054E000D4AF5B8B4750DFF96AFBE052C22F4460B8 -:1054F000BCE03B82B73DE2C0F30580F0666627FA68 -:10550000C675855339FC629E5AEB7A77ACEBD96C41 -:10551000375BCFFCE9F5EC20F49013768D03AEC831 -:1055200074FFC358CFB4E0C539E7DDD5C2FD5600DE -:10553000B7403FCEE76527F1B3A306F4F58C5EEEE6 -:105540005A99E21CDC913E5CA4C15303296F61F6B9 -:1055500079BD2AF84E0BE51E77ADC0F71AA4D389A2 -:1055600039EC2C7434B37DD9AB9DF7AFC2FD5BF140 -:10557000022E07237C2FF759F87358E17E8D2EAF4A -:10558000D64AF12C55DC3F62EFB75BC06997AB445C -:1055900096FB3486DCFE55D1B81EF2F491DFC19043 -:1055A0002F4DFB57D2735D93DA3C88A784B681FCFC -:1055B000C4076B14C07B30767D300287C0FF59D0A2 -:1055C000E3C1FB4ADD2F3BE9FEABBD9E17376526E5 -:1055D000BF9EBFD6AA7FC7D227777E4A7DF21343EC -:1055E000EE47EB135A7F2FEF6CDF85F4E9F272FF81 -:1055F0007549A30E4B4CF3ED11E32F768B75A18209 -:10560000C3D1E552EBCD742A66DFEBCD7A330B7D47 -:10561000B2D1FD220C069C9386C33EBF87DCBC5EE4 -:10562000098E3F6D6C3C8CA603C7C32A77663EF893 -:10563000ACE6D3E6CE8F8FEF16F5EE167835E6356D -:10564000969C18FDF70B7C152FB0E97D59B7D0DF7C -:1056500069E0ADD156CF63AD67E04776737BC5583F -:1056600027C6EAFF2D85F387BDFF6C72F89B1139C1 -:10567000D4C92F6B8CE3861F4448EE985EEE9E09DA -:10568000501018247F01DBEBF378A76014CCE73AC5 -:1056900076FD65E8FF6CFAC8BE6F19ABBE12547296 -:1056A000DA49865D5322EE4D7A443CF00629F339FF -:1056B000CFB09023A6D8F38AEBC33011DCB74114E6 -:1056C000C4FDBFC8402BCB8F0F2B5A37FA3FE48560 -:1056D000035B597EDCCFDCD01D4697CB82810186EF -:1056E000AF35114F14CB2778AA46EE69F59D8A7E17 -:1056F0002D6E7781F396D7F01EF0F88B6440BCBA1C -:10570000611EC5691F5CC174D8CCD1F08C9701268D -:1057100096B054F807E8FC10B7945FB1AD8B8B4C92 -:1057200079F4037BACEB5EBEF3B6C393ADDD98F0CA -:10573000A4F7A1FB717C37E45ED78E757E23766D6E -:105740009EF332EEA319DFAB869DA0E1FDF66189E1 -:10575000D21386FD94560E7B299D345C0A1A235A77 -:10576000C57031A5138727D2F7F2E1324ACB8627DD -:10577000531A1AAEA2B478F8144AD5E193285D2FD3 -:10578000E4B0687836E58DFB6F85C333295F30FC64 -:10579000794A03C3F378B9384F5DBF3206E8AF5694 -:1057A000701D62F2B17AE1525A97ECF35AEFE1EBD5 -:1057B0007087B827DC61D3DBFDA2FC510F97FBF5A6 -:1057C000422E408E83D96F7E8FA8B7BE3A46F677B9 -:1057D00087B11E962DB5AC87F6FA1D59EE273F6DA1 -:1057E000940B78A0B6690CFAF0F357773046F706B9 -:1057F0000062A497408E59F46E87017F9EF708D708 -:105800002F7C9AF8D8CB0419430BBD5FB8BBF901C4 -:10581000D43BE7DC78C56E26771FB863377970DC38 -:105820002F5C454CF7FD65378750BFAD5F7807DDCE -:105830006F42F31BE39A3BCFB925FE00711DA3CB4A -:10584000746A77ABC7740EDAB5F4E6E687587F5A08 -:10585000BB033413BF56DEE203CDACBF0E97966197 -:10586000FB8A1B4A2CDFCBAF29B7B433EE49842E19 -:10587000ABB6D453179C6CA957387F96B59D382783 -:105880000FD49D6E69E70E1878E5E7888CFE96F5D3 -:10589000A353CA4CC7B887EBCB6C7C73A187AF6BA3 -:1058A000E9FE73D32D5BFFF9DE0B49F347D6799000 -:1058B000BD1B4F2C5A80F6945B8DD13D9563AF7F15 -:1058C0007CE7916F3DBBBE2A447D558AFA44A234E1 -:1058D00080FAAA14F5889752A3DEB1DEB75D8BFA81 -:1058E0002660D2377398DC67E0878037B7BE3945CA -:1058F000944FF1727DB356F0959D6F42A2DE5AD45B -:1059000037D3C6D637216F6E7D33538CF78FD6379A -:105910005DB3EE887D8BE5BCA7DDDD7C3F4B3B674F -:10592000DE4879A62F642F2BEF3CF596F8FD263D37 -:105930000287FF93F3A5E087A2B956FD61F45F10DB -:10594000B6E911431EFE46B93E22F8351B7DF67FAF -:105950004AB93E729CE4FA88A77B019E2FE62BD7BA -:10596000A3EB1FDF79E45B4F6F80D459B82F99EA1E -:105970004BAE42BF9BA32FCCEFE5C5286EA7EB39FA -:1059800097F0F370FFDF2C4FE43CE49F599EE82230 -:105990002F6B7F7D953601D76996FF227E37E5A371 -:1059A000B67C93ADFE576CF90B6DF59BCDE5094DBB -:1059B0009B80E78B89BD2E3A1F4C688EC64CFC74C9 -:1059C000AE97F3CB5E4F3486FD9D983C7902D2852D -:1059D000E52FA5FEBCBC3F96BFCC965F4AE3A7F37C -:1059E00057D8CAAFB2955F63CB2F33D7EF3A32F9AE -:1059F0004E7A7FE3972EC07B0976385F117AA273C7 -:105A0000CACDB1362E973761FBCEA9B7C42F05E2B8 -:105A10000BF2A33903B6FD1FE33333BFEC15FDFCD6 -:105A20007CD28DB46FEA64FB278A63443F5E06FC38 -:105A3000FCDA2BDEE1D2AEA4FB0F89B2EBC9CFD1E9 -:105A400059D146710A073585CE67135599DB1B7E00 -:105A5000A6CE8ACCE708BFC6205C933D0235DCFFAA -:105A6000876270D481EF0971FDBEBAAA83F4AB924C -:105A7000BA92FB37CA62E4DFB84FD04F09C4C9AF4E -:105A8000E0AE8867DCD7778EE0C3EAD7DC69E04315 -:105A9000EC234DF820396CEBFA6037AEAF096F6636 -:105AA00039FBB197CB992B94DFF8A3E7CFD7872D9C -:105AB00078A925C3BE36E1E271F2FA24EE0790D947 -:105AC0003866BF827DBC9179DAF6D9F70A3C25BCED -:105AD0003CCEDEE8CF0ECFC3A2DEC35EEE5730E68B -:105AE00025AB7C9CB1FA7F162F6BA11F40B5FB2123 -:105AF000AC7AEE1651DF15B4D6CB869F9523F8E12C -:105B0000F15806FF8EC5EFC6387B112EDACF66DE60 -:105B1000876B87E752FCC64128E8EBC67DB3ACBE75 -:105B200086711C37B16D12FA4557C93AC527E81A74 -:105B3000A80FD2F9273F7FB8C9797218F59D47C4DD -:105B40005500C655044D7189C2CF79A7FFD687B1DC -:105B50007C85EE56F17D9361EF641EB77A7805C5BA -:105B60005374B19D3A8E7BC85B99C4F7AC9C453D9C -:105B700064CF3B9D33E399E24C651FE7DBB30EAF87 -:105B8000233DDBA1F17B371D72CC53320D5DD53A3D -:105B9000C96B97963B7ED11E07E952EDF187567C83 -:105BA0004DF771FA26C4FA9BF0869BCDF149219FEF -:105BB00097CA87BD56F83A11BE00C215A778D244DD -:105BC00085C381783B5EF019E32A558E28E22508CB -:105BD000318A57F184641AD7E1E7F8CD362E68F29E -:105BE000FBE6F7638E173E47D6DF18E727197CC41C -:105BF0004FDA024FC336CC3FE7A4F5D43ECE7E5FEA -:105C0000EC349FC92F2CAB317A77C6E8EFDC713CBE -:105C1000CE5BAE00F2E32B106DAC62F35F55C1DFDB -:105C200059940363C44554D8FD15D9CEE5F8F988D5 -:105C3000719E53FF073EAE4FC40B14C020058B1658 -:105C4000A14A9F8CF1029AC4DF81084B3CAE7C3E96 -:105C5000C59107BD9F75BF8BA95F29B21E8EFA8FB4 -:105C6000A15F7990FC5C9F79BF63C0EB85BBA95FA6 -:105C70000C4D3D5A9AEE17F52F39950E1F3D8AE7C8 -:105C8000664E30FE713B5C76F07B55505E48718706 -:105C9000AB83D77BCC746DF5555BD65745EDB84ECD -:105CA0002AC47B9FD7440673F0E56A9423F42356F5 -:105CB0005C1619ACCD5ECF805366D3CFE40FED50A8 -:105CC00062C956B4172B033C5E558ED3F948A754CE -:105CD00032ABBBCEC4BF154A0AE12AA88BE818CF65 -:105CE000D859EA08631C960C3DFBE87D27E7A270B3 -:105CF0002E79952BE4F7CCF3D9ECB3C681AC1A839B -:105D0000DF570B7D9DADDCA5846399F4F0E33EB1D4 -:105D10008EF932977FEC6F78D49761DDD921F454F6 -:105D2000673153A59FE3EC837C2057EC790DF1B0EC -:105D30007ADC39B9F5936AD54FFFE58FFC04C7C902 -:105D400001C7B399E0007C4C210FBB5F5D40C18867 -:105D5000E978A020E76B8C0392C6D37928FD5B5BC2 -:105D6000775F0AED6ED7924004E9E78C6C035C47DD -:105D70008DB82067C4F7B683E8399FC707D5723F4F -:105D80006B84FD477164F373C78D396DF95FD9E991 -:105D9000DCF20CBD1761C06FC4A9DBE7F5A4BFE15D -:105DA0002DDF9C4CF8C86F1FB491F10B307ED9C029 -:105DB000D6778614E86B5129DFDB12A27C4F8B4625 -:105DC000697B4B2DA56BB0E93C8CFF8827AA703FFF -:105DD000127A207439ABB2116942712D5B17E23E21 -:105DE000B27B240FBAC4E0EEC6FBF1CC0EFDAB6F64 -:105DF000C342B443BBC5BB3BA0772C44BB2C9DBF67 -:105E00006B35DA85DD228E565D73DF42DC3F6E9C9A -:105E100064EC93239EAF9AECAF297E17F11FEDD56A -:105E2000A8FDAAD5D89F571679D8BED09A8708C2A0 -:105E3000E3F5F0FCB9FEA7081E52016CBC0BFC4F49 -:105E4000537EE314E17798D634061EB91FA3C3A787 -:105E5000713B685A09F929947018AF17C0C66201DE -:105E6000779EFDE0FE87D6BB9733AF9769B919637C -:105E70005D13708C457F860EB22F500FEB38EE2BE2 -:105E8000FCFCFC788FBBD1756C7851E60EE978F597 -:105E90006BA72F76869FB52F88F4A7AA58BE70519E -:105EA0004A27F1CD73DC32BFB84FC6E68BF26FE004 -:105EB000D9B03BAE433A8E4BF7E70A46E8BCCD2B50 -:105EC000DE13CE17DEA53ED5D20F3CD65096EBDCC6 -:105ED000655CD481414623FAA2B4D127823578BECD -:105EE000385262C917CD2DB7D42F08575BCA5DEA67 -:105EF000C996F2BF954E5FF7A916BE8EDAE6B5D009 -:105F0000569E6FBFDE154E0DDF83AC920D7B740382 -:105F1000DD4B3E883846FDD83793EEE9428D710F50 -:105F200001285EC5AB45883F7D10A6755AA9B0DA39 -:105F3000A972D06AA7869AF594D12FC6677B572895 -:105F400034EEC83A15E0F120C63919EDD727A3AAD7 -:105F5000FBDEDE2ADE2E6CBE7F6F4F65715E4677FC -:105F6000EFABC63E4FB58F13FA4AEE38357B7D084E -:105F7000C8DA0193FC656F27C301D3BB1A5B91F6A6 -:105F800073D2F88F6C5B427E0F37303B9AE17955C4 -:105F9000E84288B17976601546BF04A68CCF3B42B3 -:105FA000B3548AC3D7385D1D1E2E27DFF16B967858 -:105FB0000E6780CB89516F2CFADFE48478A6F5EC6C -:105FC000153FDF271FBA35FE27DC5FEA2F01BDE34F -:105FD000DADF324CEF5CD6A5CE75A2DFE435FF7870 -:105FE0009A4FDDEE88F36C533F75C0DFFB66FF9C74 -:105FF000667FAAE11F86C31E8A0BDE9EE271C1DBAB -:1060000053FFBDEB28E6F73AE85DD1EDFB72DB57B5 -:10601000FDC2BE32EAF5EFE5FBD57E19FC25B9ECF1 -:106020001C71FF6D66CA1677288313E97F68A5E6A1 -:10603000447BA7BFC523E1BA3F4BCCB32E1571E219 -:106040007A3AD6BC76DAE86BCC13EF1FE23CDB037E -:10605000FC3E60BBCAE64B7CCDDFCBCE06EFC8BEB4 -:106060005FCD8C0FA580BF7BA1B8626AA6798F75C2 -:106070004FD180AF03E19330E5707504391D3A428A -:10608000B9E9B04AC067D46B0F723AB433FB201F32 -:1060900078E480151E66E34968170620D9486F9A90 -:1060A000E9F012EE8348556888879DA97B105EBC95 -:1060B0007781F67C719D7439DEFB8871FBB0A02E70 -:1060C00095DA1124F3248AF7324A0707526FB1F2A6 -:1060D0003DCD7E7AEC49BD7C7F0AFB91D521929F14 -:1060E0006E1C8CECA3C91D68EFACC63F994A9FD0CB -:1060F000133A07ED0F19B85E6012A7C9E3857D92C8 -:1061000041DE4DE7FBD25177BA5D36BCD9ED4E3753 -:1061100034E5D657E2BC5F67FFA1BE516DF723ECB3 -:1061200076AE3D0EFE0CD4E7E3F2B887F129C7291D -:1061300082FB3CF81E82B3D6A1E23BCC4CA517E310 -:10614000FD1F7F448614A3675160909ECE1A0BEF0B -:106150004CFF35F2B8D17E30DF236D0A703F50B06E -:10616000A94E92F83D020DDFDD0C36ED0D67E253CE -:10617000833F47F28127483FAE866402E34EF446F0 -:1061800007AD6BDDB5D5C5E6FDD1750149EC430D15 -:10619000FA83269F9AA63F9B5FC43BE3EF47FF929B -:1061A0004556BC1F2B5D5606B85E1A8BFE9F761CAB -:1061B000836EA3E5A355D06D23E9BFAE9AFCF44AE4 -:1061C0009A6EF791BCFA6B2192CCD0AE4DD0CB7EBB -:1061D0006FDF0371C0DFA3708A7854E784539BB7E5 -:1061E000420EBA8C8AB3E2FD3803DC9FB656F285C4 -:1061F00071A8B559FCCB350592D0FF833C9E6FDE6C -:106200009E109E1FF7CC3910C2738EDE4F329F4313 -:106210009E5B20CE4522AFD33EA0770EF70BE23F28 -:10622000D43B37F13FA15A7F7713BE63B6F64DBF1B -:10623000C51EEA68C9ED6F50CAAF88A19D71E86DAF -:1062400049C3F5462A5F7122C235306F29BD3BD262 -:1062500051B793CE617AC2B9E962C4997688B8E839 -:1062600091F1B39C1B1E12F25AAD5F4DF6656FD9CA -:106270004B34CEDABADCE3E07B59B9EE45791C1039 -:10628000237FB1ED5CF70D31DE1B01713EE18A7EAB -:10629000697215FE2E874EFEB1F1B5D10107C35BC1 -:1062A0005341ECD500A36BEFBC1BCB100E7C27C673 -:1062B0004CF720F69F01BEF1050E8BDD74A83AFE67 -:1062C0005F2BEBF0F729A6D2BBF546BD9E2C71ECF7 -:1062D000271B74D6BCB4EFE9C0B87F065F4F597E68 -:1062E000F837E87C163CEF998CEDB3C4F91AA97D18 -:1062F000BD1F0BEF763CF4BA06290EAA57CA3C9F85 -:10630000730BB8DCF5AE4CF173B57907E85C2D90F2 -:106310007A9DE227BE3B671F9DAB5516707A601CC5 -:1063200025DA518573F97B80D9E4E85E413F59B5A0 -:10633000D60379D072EEB32520CECB82B9FB33E001 -:1063400004CF203FEF192D97B4FE3CD8F3C01E7A3E -:1063500037055274AED0F18A13EFA68EE061945CDB -:1063600025F8EFC2F4E2C6E3741CE7D60EF493F40A -:106370001AE76C33F9BE49AE4BD1399BA740B3D86D -:10638000EB81B0F12E627EF30CE05AC4FDC332AE55 -:10639000ABE88F47F8DA675E48FEB46C74FD8E3F59 -:1063A00036BB609CD9AFCFF75DFF6C7C7828A059D5 -:1063B000EC433B3FBAE11BC7B4AFCBE65F3E24E4FE -:1063C0003388154DFBA46F162899F1FBD64563E180 -:1063D000F79B99F17BB10FE13D747BE6DF2732D269 -:1063E000BB6CFAEE2E231E057F24A48CFAABBA20D8 -:1063F000C3BC8D75F55081F17E4FCC87EB46B53E21 -:10640000DF87E33FD473A90FC77D68536E7A1AE321 -:106410006F11E78B49F1EE88519E147CB9D5A6E740 -:106420005F16727D8F90AF873C511FFD5EC5AE8BAE -:10643000CF3B89E1AF9AF105BA14B52E28C9357E54 -:10644000956EDB971CE3BD96DE025B7C6F9EF73496 -:106450003F2D5EB622FF9C8E78F877927B67AA88E4 -:10646000E4A9FA1ACE37D5970DA5705F3B79A3231F -:10647000A9511C4B8CF052768DAC514C9BB8F77ADD -:10648000A258DFC1798BA312CBF1DEB88A6E17F563 -:106490006B140F73B7F5F73F1EF244DA14B47F1391 -:1064A00014E908D53DD6DFCB9808A6DFAB60E396AC -:1064B000BDF92EFD7E4A99ED77413E2DDE77FC83B6 -:1064C000F09E94C167D6C79A04D14C7AFF3F055F0E -:1064D0006AADBBF93B06F100BC633AE760F42B41BF -:1064E000BB608BBEA11EF1A927203C25831EFB6D3E -:1064F00081DFF81D9FDDF8CE82AB82DF3F5BBDE41C -:10650000C2C11D4C656DB9A5C1721FC0A4177E5BC9 -:1065100040EB13D70B49BD89A7879DC427537A2029 -:1065200089BF83B260637CC085A27E0D7F87BA2C51 -:10653000A14B0ACB5733F395750F93AF005E7F31B4 -:106540002423C447F06A687CFAF74E2A07AF1BC0C1 -:106550007DF11EB62FC6DF51317EAFC4E097897141 -:106560002B7F4C4958F3136CFC626F5FADC17938D7 -:106570007E4D8F03705F37AED9541FFB83A1771F09 -:1065800066E34FD98D0F33B2B42F77FF32C45C85E9 -:106590000C9F4FDD1AF8652D9BE0FD3D0DA58897FA -:1065A000873C40711107A31E7A7701A299CF9346C9 -:1065B000F1AD61F767A99FD697BC9EB1EE75BE2974 -:1065C000F1772E2AD5B7ABD0CFF92AFFDDBAF4BBCD -:1065D00015A7D3BB15218873FB11A294B60BFE54EB -:1065E000CFAEA8427F68E22DBF8AF7B3D452AB3F4B -:1065F0004D2E69A4F7C046ECEE126677B3F244B1B3 -:10660000558FD61772BB355CC8EF85AA7EDE0F7832 -:10661000F432B3DEDF582859CB037AD9974DE50D14 -:10662000A27D42BC5B7E56E1799D68CFA81359FDDF -:106630000CFCB9408C6B944330BC0FDFFFD8F48D59 -:10664000A639E6F57C63213FDF514F10E35664869F -:106650002B51C5C7BD4D8CBBB1D0FA6E1CA83C35C3 -:10666000BEDF5170A3B49FE1FB900B1A305E65D57D -:10667000384712DF4DBB69BC1117965B4F18741871 -:10668000C1B7CAE391CAAF50673933C8B1916E6ED2 -:10669000E47E2AFBF74BC43CDAAF68E8AB61704597 -:1066A0007673B9730721E3391093EF4B0AE7645807 -:1066B000F7DB1B691F77A838F7BA6FDFE7CAC2BFDD -:1066C00068AFD72AE8A4BD1CA2A7B8DB43DC9F684B -:1066D000F47FA88CFB15EDEDBA6CFD7BA1298271CE -:1066E000C678BE8AE7AA4A0D24F1BEA92FD8A756BC -:1066F00069181FB04FC7FD91060C8FE8670B03D9CF -:1067000075ED21BE1F95437DF50E8C278146D56C16 -:1067100087958BDF5534F2AE40ACB590ECA1884440 -:106720007891F979FE2157F25CC4E7AA2A07647AC6 -:10673000A7BFA790DBB99BB5A617AA32D06F7DA1E2 -:1067400066B19FCB87B9FD9DAD7EBA1E876F841F52 -:10675000433ADD3F008DF3635341E4F6C24CE7B7A3 -:10676000865E117EC84BE70A850BDA45BF66F3B833 -:1067700072AF8B62D3CF3ABC650FEA5F27D3BFDD20 -:10678000F43B727D7BD00F7919DE7F62F92BDF9CA1 -:10679000AE54B2F257CB9DE2D1F968218EFB01389D -:1067A000C85FF201BC5438DB44BF270B15BEDE24A2 -:1067B0005CA4470D7FDCE57D2E8B5EFDF6266B7EAF -:1067C00029348D473FC5D28D2E4832FC5E69D3BB3C -:1067D000F717F273A26F43BC03D7CFD5E2FCEFDA11 -:1067E0009F4C57506EAE9CAD56394DF7AE9E2DE482 -:1067F000F6DD7B8C8F34939C5D15482AB88F7B67C0 -:10680000FBEC0B3F0FD84FB2A31CFD69C599E30009 -:10681000BF95B0C239D63CEC701BE779D9E090B790 -:106820004919FD42CF154A167FFC2A0F7F0F29B266 -:106830004A06EF9918870774CF4F7FB380DEEFD6F3 -:106840001BE21457A7B7B9D555418AB3A378BA1537 -:106850008C60F8FED001C17F465C1D33284EC37D9D -:10686000DAB59E4105FDCACBE57823FE749A712EF8 -:10687000E376C5221319FCAE67EA5313C1522F9178 -:1068800067BDBD52755EF51A1D39FAFB50E8C95F48 -:106890003C76BF82EBCF078FBEFD4594C3AB9F759F -:1068A000025ECDFBF0B10248D1FE21A9A09C5FB5EC -:1068B000DD99F11D098631EAFFEA1F15905EBCEAF9 -:1068C000097772116B7FD5D3EFCC00264F1FB60D21 -:1068D000ED9988F87B54E2E785FAE00C5C9FAE9274 -:1068E000E19B99DE1DF31671797FFFA7FE66A49FD9 -:1068F000B46DE012EAB7FF2297F95D7C28E2EB0F56 -:10690000ABC7E3261F91925332E80F633FF4FE2397 -:106910003CAEE4AA675C490C09BE6ADB5625C6E0BA -:1069200058BEED23E297B37FF47821E261F9334E4C -:106930008B1D71F58F3EE9389DD1F96A270C2D42E8 -:1069400039761EA6FCC18867C84972CDE35396917B -:106950000A60F59EFCFD39BF66E5EF859C8021AE9F -:10696000EFEDFB9DF22CE6630166B961FF56BE5E5A -:10697000BEED1D857EC7C80143159FC7F30FAB9DB4 -:1069800064AF0F30A4A09E5ADEDFF59193F1DBF2E5 -:10699000ED1FBC817CB7DC261FEFE11F65A3EDF383 -:1069A000994536FB7C5B695EF6D1D58F1FBC17FD20 -:1069B00011EF3FF1C77BF11EED35473EBEF77B1867 -:1069C00017F66F5E15E57BF9A3AF148249FF9F5F51 -:1069D000C4D7CD0F1F79F8A1CD6CFE1FBEEE266C7B -:1069E0007DB8E3F795E8FFF9F0C77F1D8FFEA01B88 -:1069F000762CA4DFADB9E1A9B327E45A17915F93D0 -:106A0000E6DF5714E746DA33121A93003F13A98DD5 -:106A10001ED037A4E0BAF6170986BA8BD9F7FE4F15 -:106A200014B4CFF6446008F1B36BFB3B7B6E66F9A0 -:106A30000F187DDC19E8C3E63FD141FA99890D4B67 -:106A4000976DFFF297CEA8C3D44576F8721822BD91 -:106A5000398AAE2F33BAD6A5E96A2F3F0887153C8D -:106A60003758FE18A3E30CA427A3E38CD174FC00D1 -:106A7000FF98379A8E571559E3920EC2355B3663ED -:106A8000E1F6D28CE7BCC63EEBDAA7BE9AD37E32E3 -:106A9000F4C25878BE42E2709D5A14B9B908E5EBC9 -:106AA000891F3CB439C8E9BC8821E6C3C70F560228 -:106AB000E3933FB8862E413C0CED70ABB8BE5FB59A -:106AC000E357246F1F3EF5A2A2517C0B144AA7B2D4 -:106AD0003C8CFC7B09587E99C433D73EF0FFCE79BD -:106AE00083B5BF167F3A5525FA517E0F933FA247D3 -:106AF000F282460DF56E721CCD7B5992CBC5B2E485 -:106B0000C05730AECF8EF7278B1C86FE1FA12BC639 -:106B10008D2DDBFEF639C87FD9E869CC5FC5F99FBA -:106B2000C6CA1FB0CA6D563915F4FD70EB2105EDCC -:106B300083D4B38AEA60F6F087AE2185D6C71F3BBF -:106B4000D507C3A3E99EC6BF883F3AC67DF80FEDBF -:106B5000722EF033969C8F3DAF63C3DBDD451ADFA9 -:106B60005FD9F0F7FEE1CCFAFF39A1379641BCB10D -:106B70007CF2E8F54B86A83EB12A0DEFFB183FC624 -:106B8000E07DFF5127ED0F3BFA77911EB7EB8B6548 -:106B900059ECE8378AB83DB0EC998119A8D7DEDF07 -:106BA000F953E2CB658FBDADA0FF66CFB62795C187 -:106BB000696939C0F5C1FC3B38EFFF706006EAAF88 -:106BC000E559E2007F2FE6B3FC67D6FE973FF691CA -:106BD000A5FFABF57E85FC64638CF39E1CB908E7CA -:106BE000FBDE3E179E60C07BFDCEC64C76CEF362C8 -:106BF0007D34F0D45170EA6B4578EE55C2DF616C9C -:106C00006F8DFC8A7EBFF74597D8DF465E437B6673 -:106C100055B142F711DA0B2E247FBDD15F9F0D9F36 -:106C20006A50ADC7FD80BA205A67DE5719F0174782 -:106C30001C16F86F28689CA005F8FE4C63FB8FFFBC -:106C400001AB8A1A34008000000000001F8B08008E -:106C500000000000000BD57C0B7C54D5B5F73A73CF -:106C6000CE3CC24C2627AFC9D37892F09480431211 -:106C7000DEB40E0491226A505AA9F5AB03F28821C2 -:106C8000C9A4F8E25ABFCB8444F4029F8D95166ADA -:106C9000693B70A152217690A0B10DDC012C060554 -:106CA0006F105F78B18D5A152B246314B4575BEFC6 -:106CB0005A6B9FC3CC9C4C84DEFBFBBEDFEF0BBF4B -:106CC00076BBCFD9679FB5D7FAAFD7DEEB0C28DEFE -:106CD000DCEA5400D93D6B366461AB5AD41409E048 -:106CE0002BFABB2AD6028400C603585DD5E0776133 -:106CF000AB5A407300FF7D45FFA7785B7BF0F97BC3 -:106D0000E5D4D6B5348FB5F157D4872605B657F2FA -:106D1000B0914A25DDBFC2BBB61860A3F39F1FA781 -:106D2000FB2B8376D58E6D73EA3DBFA5FE0609AABF -:106D300065EAD3F3383E6875A8DB55BC9E0E0BC2DE -:106D400065317AF25424321BA00CE9A016FFFC3006 -:106D500001DF2B488266A8031C012959A120B5C672 -:106D6000730FAAFE62757CAC2FBBBAC18FF35E2D88 -:106D7000BB2CB4FE07732D217B31B537A641D9401A -:106D80003E18ED03ABAA213262F0FBADD98E855BD4 -:106D900080E90E5A681D9223B49D08F181A67A807D -:106DA00069030DFF873C74C4D18D037CB40E45BFCD -:106DB0006FC565D14D3B04B94D213960EB84084066 -:106DC00029D2AD96B05C52A1479F240AD563006ECC -:106DD0004CF57F93D6993BB451A2EB1EA8E6B612B0 -:106DE000FC12DDB738EBF2FC5FB33E58A09CE9190A -:106DF000A9CB175FB1C12AF8AF28A00C29273A36D2 -:106E0000ABEF8FC679E87E268D0AB21CC6557D672A -:106E1000740BC181888FE3F323336764126E8C7126 -:106E2000CD8EA29312F2DB27A7A82945D85790331D -:106E3000C4A753A9CCA71F4DC399F1FE8F4FA56ED0 -:106E400095511E8F48024F41C213E10A1A1F277C39 -:106E5000B8113F6BE9B9198DBF65BC58A0BAB952DA -:106E6000E7A487F827FE106F8CA7958A43B57B8926 -:106E7000B73E4DA1796C105A2B11BD7EE6A7035A7F -:106E8000B91D02616E5DD0CDED5DC4E76C92839754 -:106E9000FB69D0D33A149F9BA356D7AA78FDC7B3FA -:106EA00033245A9F0B549DBF8579D41F94BF3391CF -:106EB000BF8E187FEDC44FE7407E3A40653EA47B0D -:106EC000C1BB761CCF0B115CC723D321243388545C -:106ED00050112F39FA3A33C127117D841F5A5FF6BA -:106EE00002B13EF3FB72A195C7E54398DB42E8E6A9 -:106EF00036C3A14A0AD3734A97EF3BF09533468FC6 -:106F0000D1DA09C138FFB9429CBF98B9ED963CB4BB -:106F10007EE3AF9A71F887CA83BE2A1CA7F85D3E4C -:106F20003B2EE5FF54CE201082F5720548AEAE9E92 -:106F30008573C18DC3BD36888CA4D9834C5FCA4884 -:106F4000D137EC8B1D051531E8C7E7ACA73E3C45B2 -:106F5000CF59216E1CD121DF9A467C7F982E4C1E82 -:106F6000C8F795A79AB29E8B9B77AB9A9A45EB840C -:106F70008930F12B39F63C4CCA402333F0F9CF5617 -:106F800005B39EB3C6F8D0E2F867C6A50F019CF220 -:106F90004DEC138EB36238465CB29D0BAEB6ABCDF2 -:106FA000598C43C6E94A64901DDBCF528A42BC7EAD -:106FB000689C7823DA618BC3274978BD4E75878832 -:106FC0003FF5AEF02CB61326BB317DBE1AC9C77192 -:106FD0007D8DE025BE6EDC73C369E26B9F07347B59 -:106FE000BAC0856F02D909C38E8026A37CD748E337 -:106FF0001C12B6F5ED1FBFF47B1C9FD229838CF7C2 -:10700000FB70CDDDB46EC5974E4274C2FA04FD6EBE -:107010007608FD31D669D6D77F749D28799E9FE585 -:107020002093FD5DFF2FF47C3FA4B6D2F84D0ABE3D -:107030009AE6EFB286B6231F561C91196F2BDAA47D -:1070400010909C152D8DFAF7BE2883C01FF0FD7B94 -:107050007F55CA789461F48FA6E1F381CD562F5AFB -:107060004C48F725FAABCCD943408BC301047D2FA4 -:10707000E722BF16EBFCDAE87C780BD1B3A949F81C -:10708000A7ECEA8C84F19FA55C6F5B8AF36B79486F -:10709000D714C24DE7F035D85F5E20AB329A889C9A -:1070A00005F989FEB1D5FA0EE99F86FF08DF86FD56 -:1070B0005A4AF68BEC907C3FFBBF7320FC9F02C2C8 -:1070C000FF35A0BD8AE07CCB3689E78DF96A3A1F8F -:1070D000595380ED1DA1C4EBCB4189F5D9CFBA47F7 -:1070E000921D580943BC766920FE2DE9887F0289EC -:1070F0000B5C420E2E2FD997FE5764AF5DB082F520 -:1071000095F84E7644EE19B1711ACE17E8B242489E -:10711000237989FBFD9BE550B038A61FFD5D7B9868 -:107120001FCBF2901F884F7B6E22FF53B444FE3B6F -:1071300047667CAD3C52BD267ECA7399FFC86FA0DE -:10714000F9D32695243EAFF37B24FE13FCF6319D44 -:107150004B3B24784C223EAF3F5CA00DE46B43C711 -:107160002336D2FF8BF1D5CCC7D1E9BA1DD1F9783E -:107170000E3A0FE8A8AC7678D894F03A14B5753A80 -:10718000E1B410F5967062D66B837FD62CD567C3B9 -:107190007197D1385C5FBE232C94D10BCA09C2CB46 -:1071A0002261779B551FFB23C3DE3A2FD8ED77E191 -:1071B0002B6CB3E6553E4438BA534A6D952B07EA1B -:1071C000EDBA31F7B0FD2A5C8DF698FD6A629C1627 -:1071D0005EE5F02E467A9E5C05DEC5C3009E5AA58C -:1071E000726B8EDF0C7DDF8CF19B5DF8679E5741E3 -:1071F000FCAE55C9FE7855A2F3611BB09EF69541D1 -:10720000682BBE3F1CF9D4A391BD2E8F5E5F8DF11C -:1072100045600954539CF1AF1922AE7B466F6765F8 -:10722000D8B85D5B6D011FBEA7B7530E49485FAF6D -:10723000EA3B7215D99D4EABC6F1951A7DE97B7C70 -:10724000BF425D8BFCCCB3B48EA3F7E2F8D9219C8E -:10725000B7AFF35DF7ED717EB9B7E3D1511407FD18 -:10726000CC0235E124F1D0F2740BC731BD23DFF13C -:10727000E0B2A1DE11B501E2E9C19EC66A8AA7EEBD -:10728000746A4C97AD7D7AA480F1338FE3E3E7967F -:107290000E61BCED3D0321D2BB59F2ADD78EC1FECC -:1072A000E45715AF9D95CA77FDC2093C84E5BEE160 -:1072B000CB8A4DC4BF00F273355F6C3D41F27AF664 -:1072C000CF0A90DE55363EFDAE1FD7793817D13044 -:1072D0000960822F5C11C151333BD3A7937E074EC7 -:1072E00001EBEBF86E2501B720D71D2A20BBF286F3 -:1072F000080F27BE61BA0F4199E2FFC93D89D7A7A0 -:107300005E04EFFF62D80D377808EF8FADEA807723 -:10731000C92FEAFE331F17988C9F06BEF738673CCB -:10732000922EE2769970EB55928F7F2743C4F91B1A -:10733000BE9425C2655F14BCAB915F7D8BF379DD94 -:107340007D9F524086ED97F2EC709278EBD7E9364C -:1073500096DFCF6C02F73F5BEA0A35E17A0E2EAD7D -:10736000BDBC07DF77FE9FFC97AB5F1707A369B132 -:107370004C6279A511DFEF9CD722B11E426B1EF142 -:10738000CD3CDED013436F0C7DC95B3AC41F4AF27B -:107390009EE1B43EA46FC6D291928D70BB5F029203 -:1073A00063EF6AA4EB6BE2C720AC2E207A021D9F2C -:1073B000D8C85F3B3A255F28C9F8C3E96EE65FEF9E -:1073C000EA60D354E4D73D8BF059D20B5B6B71B2BA -:1073D000F983B0A1008343684BD704EE1D701BE90D -:1073E0002528AD79E4B77B3BAABE4576FD31D44371 -:1073F0008A1B7E66F532DDC17A80EDC4160A3CB187 -:107400005F783D6C591B974776A74F3F958EF39D4C -:107410004A5779DE4CBF5722BABD7FFBCC4DF3F7FC -:107420007D6E67F9E5930EC7C56D9FA60BFEACC9CF -:10743000F0BDC678A9C96263EAF5BBBD8B2B00AE6F -:10744000EC407EC7E13226B720AF3BC31F647A32DF -:10745000BA3171E2FCCBA751BC1CD08D334424500F -:1074600026C4EC73A5A3305220F287700EF237A326 -:10747000E6C76CAF53D00E53280EDD8979115B64DB -:107480007C9E749FEC42B32AE2AC967461E75A1E6C -:107490005142CDF8DECD4A4FCA306C8B7DDA0C45B7 -:1074A000237B5FC6F3E6DE05ACDF164748223BE4EC -:1074B0002CFD45FA85B86B2AC0EEBFC9CC7FB39CC2 -:1074C00046EB7AB126C3FF05F1756C57F420856F42 -:1074D000DE14C824B9CE925DBCEEC96785FD31DBF0 -:1074E0001B39F2AB9F91BDE9D3F3A724F6E676F200 -:1074F000AF86BD01B9EC10E167EA8B7A9AA9DB1976 -:10750000CC3E980F138FFA9B5D49ECCB24A84E43D9 -:10751000165FD4BE98E588C1FE857E2132A3A20BFA -:10752000F528EE79B33D2AC8D0FDAF6E8FCEC1B439 -:107530009CABB5185ECA577A0FD9E3F061D8A11891 -:107540005E428C33F37B24705CE8ABA5643F8ECA4B -:10755000696477A6A3DC71FE2E5D4FD23F0D7D8B53 -:10756000E4BFA1F39A14C2F5535D550E529B15B9B1 -:10757000B2F6678C9F9503F383A0C385EC9DF15E03 -:107580002B3834D748E28785F920ABD88F7B7F7FB3 -:10759000AB349BEC220A2D6DFE98C1EDC18A5C1BB9 -:1075A000BFE7A9AE9234C2910B30BF45F955764A78 -:1075B0001C2798716DC67133BEC0C2796335C7137D -:1075C000B214D6F71D12F3D2E2E064F65377611ECF -:1075D0004E716B7F17FA2D6C9F423F4F714AB36B10 -:1075E00016AFDB58AF41DF5DA93372A06CE0FA8DB6 -:1075F00036F0B90CA1CCB8BE12B5118E039FDB12C8 -:10760000AE1BFC1C8C0F063FA7103FA5FF3E3FA7FB -:107610006608B99AF9FA3F5D7FE18A49906C5FE0AC -:10762000FF97F54F05FFEF7B44BEF55AAE27664F37 -:107630000A57CC9697211F26503CEE8DD90707FE9E -:10764000237C8DED68657B3309ED0DC5990575616A -:10765000B62F137345BE64B61B5776C24D641F2701 -:1076600047302EBD04FBF129FD471EEFE3FC32033A -:10767000E91EF7FC82E5BBF0D2580D32E7E27BC68B -:10768000762B5EF27BD09D99745FC0EC378CB8D4BA -:107690008847CDE38C78D4F0270D3A1FFE3DC3FF19 -:1076A00064065D57D520E91BEA55F8312FC35EA368 -:1076B00078A13BBD7A37DF1F190E721E50022AEDEA -:1076C000EBA0BE721C56E97045E4B103F5D369D254 -:1076D000C330F285F609822E4B689834900E0CB7B1 -:1076E0008314F7E103FCFEA5BABF28C4312CB4060D -:1076F000E0F8BF702CF8C9EF1696638BEB3CA6C779 -:10770000232F995AA4FB79E2AB5581A0BDFC1FA79A -:1077100097482C2827FEF8FE40EB77CCF631FD0584 -:107720002A78298E2F50C29217DF9F51A74917360A -:10773000910C3F8DF315CCD5D85F160CC53E8DA7A7 -:107740007827895C7A32ACBCCE7A47CF611BF221B4 -:1077500030B771B6DB128BD3ED56BFAF80F68F3AE0 -:1077600044BC0EB4DF379EED9244EB516608FE0434 -:1077700054915FB94065BB59A9CBB1D23197F77726 -:10778000C827DA270F5CB7A4F97870FE7CD0829303 -:107790006376D5C87F701AA0F798ED6ADFBED72F41 -:1077A0000BA23EBEF5BF3F4905BCFF27259A4AFC08 -:1077B000387DFF89541FF2E3ADFB45FEF27D537C1B -:1077C000A4640AB92ECEACFE82F87ADBAABF4D883B -:1077D000B72FB0329BF5E28E904CC9F005FD59BE33 -:1077E000C3C97BCF46BF3E9C99D037F4A0DE0E8D37 -:1077F000C9E2EA6999222FBA63D7161BE5D18B3308 -:10780000FDA999D83FADC77FA7DB53793FC0A067DB -:10781000D1AE7136E2F79F3AED106103D96D157262 -:10782000F65D2F4DA0CD7BF167A6F3F0FE021BEDB8 -:107830009F2F91202AF6B5E0F0CFB1FF5EAE0C6B22 -:10784000BD03D7B1E42DD56641F92C990ED120EABC -:10785000D5A2BBA435F7E2F8457E17457003D6B92B -:10786000309898E72FD3E395DB1FB29AF2A4C6C3F2 -:10787000B45FB618E7A17C76496BE2FDFEAE3B0F24 -:10788000FF9CFC40878DFDC0B28BE44FE332F5785E -:1078900065024CFCAA94E295B21F956983DB25230F -:1078A0005E39BD0A083CF097550E6ECFAC52B9FD5B -:1078B00042B7D7CB3B0E1C665C2BDD13C8CF3ED541 -:1078C000F5AEF3162DE637BEB9E593433FC77E0507 -:1078D000ADB398EC65C44A78BC4AF71BCBF438A426 -:1078E000E273B3DF38F087DF539E8DEBDFCE19D71D -:1078F000A5C523B782F2693C1F0C3F62E6477F575C -:10790000A99370323F33713FF67FCA97C19EAB9700 -:1079100011D749EC87A14F5F64087C2FDE366F4D8D -:107920003EBEBF79DF07453DC22EBD069E185ED123 -:10793000D033DE960144D7223EFD9DFF7498F87443 -:1079400098F03689FA97F1FDDC2AC42FEAEDB2CE21 -:107950000FDF84B1AC5FB9965C6A23B9945F9A710A -:1079600068C69F196FBDD69E22B20F669CF54A89E4 -:10797000E76446BB34539C5F2CD67CB328DF45B705 -:10798000B646E5F508FB775A693DFC43D2DB6D123C -:10799000E787F5CFB43D4DF6A8F6B73F71933DFAB2 -:1079A0005069F5D0FBEAB63FE0F6915D52826E7AFF -:1079B000FEC390B04BE6F775EA7C34CE052EF8A5F1 -:1079C00087A26BEE437E9C477D26FD6D68FFEB9A98 -:1079D000FB28CFF039A294779E567A66111D772C3A -:1079E0007435367929BF4D5C77EDE33FF168BC7F94 -:1079F0001C2CD0F9C7F96AC336AB3782F336BC22E8 -:107A00007BE9350188F2FACCCF07C2EFDAC87EAB4A -:107A10001688164E1D781FC56823BD09B4AFFB58E4 -:107A200076532BE415203EC79D33D4E876D88CE3FB -:107A30005D99FABE888E5FE40FEFA706912EDA3FBC -:107A40008290B0C7CDBFD938F66DA4EFCCB617DDA4 -:107A50005259FCB9C26A96477FF8F65F392C83E326 -:107A6000B757C77B2C6E09F1735A87240E833A45AA -:107A70005B678DB8296FABDB62F506F1725D9B0C1D -:107A80000EF25F27ED1C37D4B57DC2F8AC937C5164 -:107A9000691C2FC32DC5C511CBDBDE9B45F676795E -:107AA0009E0C7351A56AF79C13E37D104DC1F1CB79 -:107AB00077BF3DEB87D447BC3B92C8AB2A7CC0263E -:107AC000F4C624AFF0DBB3281E6EFECD672C8F0FFB -:107AD000F74B90533CF0F99A2DEFD9C89F9C41C1C8 -:107AE00064A60B7E91DF0884E585B6B464F28B5CF6 -:107AF000FFBB4ABECFFB7F1793E37A3A6B1BCF786D -:107B00007FF2774847CD9B76EF5C7AEF9377BA01A7 -:107B100071F081D22870FF8B073CE4876BAC418FFA -:107B2000CAADB85EF3CBBB198FCB8EDFED11F98DEB -:107B30002F4FEC1705F3689D4B367F9BD7B914FC8C -:107B40008CC79A5FC8D5B44F734E81D9BB93E84DAB -:107B5000659688B7ECF083B1F789F300A0FCFC03CD -:107B60007DDF34F8B2CC719B1D6E4C9B17B7FF6460 -:107B7000CF12F62A08A13FD2B96A00DD2B9F831CE1 -:107B80003F378BE6B9AB5869A473225C7F50E79707 -:107B9000F415EF0B80A6C4C55955C7AFCEA17D31F2 -:107BA0003BF4DBFE5725C7D51AC53D71CF31DF3E0B -:107BB000D86A1F225D89AD27F9BEE9ED5986FEC35B -:107BC000CB1087A7C08E0F184F80FE3B2D57F41F98 -:107BD000237D5CE46A4C43BE7DFACABB363AD70AC1 -:107BE000E27A8611BDDDEF711FBCD91A8D37E60F21 -:107BF00074D863E781A4D7DBDE33E975E27DF4DF77 -:107C0000CCCF00A46994B77D608BCE227F1EC4F7D1 -:107C1000527DC1D20DF684F3C6185E4CE78BBA7E56 -:107C20001AFB9CCB4CF198D19AEDC29559897601FB -:107C30003667273D5F34E72175D6D0AF893F75277A -:107C4000ED9CBFD4B509FDC3803A3A0CF5E1A35DC4 -:107C5000875EBB05D7F151D89A3597DF96686F6B71 -:107C60009E42FDC5F132F23B85EDED671C4F19FEDA -:107C7000E823175E1C93446FF17A52BD7501DBB3A4 -:107C8000FF577676D92076F6BB5903E284347C0D13 -:107C9000FCE589E597537C61E6AF615FCD76F393B0 -:107CA0004C2DA9DD04DDCF1B7CACDD7996717B3ECC -:107CB0004F9C37356CFB2BFB31646BD48EB86D0851 -:107CC0007DCCFD07C88F71FFC07C696CB27527F24F -:107CD000D37CFF32922DE723D1EF139F658BDB2BF3 -:107CE000F6E7543ECF6F26BF49765A5381E40833F6 -:107CF000204C7187D4F9FC5FE97DE6BC223803464D -:107D000036F2B92EAC8BAFCF092B7A3D4530797D59 -:107D10004EB32D769E4BF7073BCF7D5FB7575E97EF -:107D2000CAE508D62C4D4E5657E2ADB224CD237E7F -:107D30009225CE774AB3C5BA8F650979B4C8D5FA0A -:107D400046A3C897680F95ED5FBA9BCF83AD7A7D48 -:107D500006CE9CCBE7074ECB27C812D8BDA17A8EA2 -:107D600042FBC315963B4BB1DFB5E1F6390AE2C7DA -:107D70003BD5B2A704FB2F6C582CFA575A2AAC08F3 -:107D8000FDC7834BE6CCA47D03CBDB3FA5F529AB38 -:107D900015A0FA91D296F7B87F97559C5F353CBBFA -:107DA000B786DEDF20A12090FF2DEE7023D731E4CF -:107DB00082BA9A368FB53D7EBABF260FF3799447C3 -:107DC00024CDFFDB2CF22B8E885B2BA1BCD2B7F12C -:107DD0007B785F79D94A3921AE53EC838FDE333516 -:107DE00097ECEEFF85F7FF5B56F6E0EF3FF3D4B577 -:107DF0000B68FC68195419E72B57B42AEADB31BF2A -:107E0000A6BCCD9043B922F85EE6B2713ED792EEA1 -:107E1000CB253C1D239C665F7ADBACD70FC94E8116 -:107E20000339CDD2B81BDB5774F9BFAAF383FE68C0 -:107E30005FA06F5FCE56AE5B816811C95796B7B62B -:107E4000113FA24D0A6CA5FDD77D8FB7113E5FB7DC -:107E50003978FFE8E6B4F5D62B90E47247D19D045B -:107E6000FE37A55D7753BB2FDBDF9325E68DD0BCB6 -:107E7000B77C5F16F3BA1A53C97F820FF54AECD369 -:107E800070FC0E7ED42BA2F920EAD5383205897514 -:107E90004E663AE4B45D4CC7CD7641C78250497313 -:107EA0000FD231CE1EBA8CF22B7C7F94E4700B86FD -:107EB0005B84E760217491DC5EBFEDCA2D627D8535 -:107EC000ACAFACFF7CFE7EE6499A2F80F3D3396AD3 -:107ED00040EAE1FE1EC5A1065561DF17C6EDBB3DB8 -:107EE0000BAD27CAC4FE7E33E51D53F5BCD8D87F41 -:107EF00033EA0D2676F9AB5C64B0E54E99ECCA39ED -:107F00008CD7C88E99F7DD269BECEFD48E8FD82EB8 -:107F10005FEC3CD099ADDBE37CC8A77584E93C906D -:107F2000025EDD4F7AE93C3089FEC79D0766660B2D -:107F3000397DED79E09DBABDD1A84E0ED7D18F1312 -:107F400093DCFA8F2E82F24AAE476884F4C1FD6A50 -:107F5000BBC9FE1B381FF38A7A3BD9B331AFC06D62 -:107F6000B4DEABF5F393FED3C0F580E37A1C5C1F5F -:107F700068EDB28642525C3DCA490BD7A3F4833701 -:107F8000C4F52B41BB1A647B3996EB4F5A4EEAE796 -:107F9000BD7A3D438560D93F5C0F61AE7F98E29E1C -:107FA000242FACE4F31990260DAC7F9822DF2A939E -:107FB0005D81A3429E17EA20E43299D6752E0240D5 -:107FC00029DA8457E2E48DFF9B981594B9FCE954B3 -:107FD000E2F529265C98E57F6DB61EDFE8F21FB456 -:107FE0008EE443B1AF360EC6721D89D55C47F2866A -:107FF000850B366375241521D2B7094D62DFF8620F -:10800000753CE63A1D731D4E9E3F914F0535572432 -:10801000DCBFACB13CA17FF9CA2909E38BD1A1C671 -:10802000F74B1F9A93307E58EB8D09FD119B6E49DB -:10803000183F2AB428E1FEE81DB549EB5E0C9C8C84 -:1080400009AF48B8BFD1F9E4BB84AF963C59A578D5 -:10805000FECA8EFB4C7531D31817538C7D785DFEAC -:10806000465D1D9581119FC7A3FC1F2BA6B8E9FE95 -:108070002A491B88036F24C87EFC1FC5C17A931D43 -:1080800030F4FF62FB373FD6FD849C5224519CE3C1 -:10809000C3B82A652AD5118B737B784BD4AB7C96F9 -:1080A000F2778E8B34C9ED856FD25B5589E2A07B68 -:1080B000AB348E83EE1D527480F60F7A7EE0F64A62 -:1080C000F903EB42CD75A0190EDF64E0AD11510745 -:1080D000D982869EEC7F708683E38C872D96DBAAFF -:1080E000E3E87F225BD89F27B245BEF5735B783704 -:1080F000D901C5016A539E789E8A1F802A7B502E23 -:10810000EE4C10F561F0C6DA9985E43F7B466AE9EA -:10811000543F8BFD6FE06525C4FEE4966685F3BC95 -:10812000D5CE27D99F942BC29F8C9385DF403FD219 -:1081300041F6F14DE97EAB88B38256924F810382BE -:10814000EE72F6AF7C4E9C0E59D28A32AA4FBDE039 -:10815000B7B4AF104C876AA75A884FFD8B653E0FA6 -:108160007E8948427AFB6B46719D73FF85FA3F2DED -:108170008DF2EBFEC58F9EBDBB32A697276DC9F36E -:10818000BC8BEDBBD56C793495CE514E8E8484FA80 -:108190008C37B3457EF866B62CEA0C42EF79884DF1 -:1081A0007D4BBE184E4407A4EE352E1CF2E0A61FF0 -:1081B00054935C6CEDF382B4AF69ECE35FC8033BAE -:1081C000A773FDB6912FDDFCBAD8D7BBF98BC47D60 -:1081D000EB8FB2C5B9C047F43E6CCBBBFCE3496E34 -:1081E000379042F0BEB27F3CC507D52A68E4F71746 -:1081F000F817DE7D14FBF3D64B1CEFD37D1A7F23DB -:10820000CA90EE9F00EFAB7B91BECFB3053DF3A1CB -:10821000DA4A74BEF6FDFA54C2D3EBE9627C54022A -:108220006D6BDC7C37E8F3BDFEFDE57B294FA7F7DE -:10823000D1FB891E7AFF3C154AA8FF1AF8CFBE5A17 -:108240003CF0BD3781CFAAD77B59C94F9642A8EDE4 -:1082500069B2AB472CDEB5C06D2493FD929DFD52F3 -:108260005F53F4C97B90CE3FD5FE75AF847CFDE3B0 -:10827000C2E8AF9FC6EBDFDD248386B8F838C32F92 -:108280007BE2EAB44F2EFE2495F889F1CAF69F925C -:10829000DEEDB47BA9AEE3CDDA9DC3E3E3FA54CFC0 -:1082A00074073D07932EED3CADEA89C98CBF15DB01 -:1082B00005FE56FC66440EE16C45EA05DC89FEF6D7 -:1082C000523E279D2041D2FC783FE24D1BC17535BF -:1082D000A021CEF67F2EEACAF71CCDA820FA14F012 -:1082E0005F16BF9E3D2FDD329AEB79DFC8BA243A84 -:1082F000496783687F6F665389F181AE270B3A33F4 -:108300002BF478729487E2B9DFFFE6EC7F105FF61A -:10831000EDDCFE43D6914BE3C3C03A5A7527DB2709 -:10832000230FA3BA57CAD30E59D84F5E2DDFCF798A -:1083300018D56970DE35A488C7A3C151ADC2BE8906 -:10834000EF24300E6EF672BD27EBEB4A55C42D4676 -:108350009E245BBCB98AF8C8E0C5A93C7F09D0FE61 -:10836000989B122BC35E611CE1962DBABD029F0340 -:10837000F3D3D1BA3D9BE5F15EDB22CE6B12E24F27 -:10838000EC57ED4A127756E33F8E3B37FB9B53D8B1 -:108390002F6D96CB28EEF03922E4C7CD71E7545803 -:1083A000CFFB0003E2CFE7FE7249F1E7F73CFF3D68 -:1083B000BFB3D4A3B1FD098F14762E1C19C2790E58 -:1083C000FE55907E0DA5BD003A07CD13AD4DEA1DBB -:1083D000E940FDACF594AF7B681AC265A8E00FF5E3 -:1083E00051A450AA7D72E82B8A03BB15965FFF73D8 -:1083F000577CED772495A887E4EC2387A770BD739D -:108400005F97D08FB60CEDDFA7529E8171E65624A0 -:108410003145E9B1A52759CFD3647F511FC21E91C1 -:1084200047393AC4B9A843F301D99714551D478970 -:10843000B9317EB147D8DDFAC36F16D9503E672DEA -:1084400047DD74BE52B7F729372E179A33FD0F90C8 -:10845000FE2C3FF9F20495EBDCB61451FE1D8EBCE8 -:108460003C83E3B3D9C8DA7183AF27B0A9823E4217 -:1084700080864D99DC8EA27D15BC14888875F676B1 -:10848000346724DB1F08FCDB5B0769BD3B8FA570ED -:10849000DCB233BB9BF520380F603BF2FB89CF4742 -:1084A000F37C0830A6E38A6A4D227FFF0B7D3D3BBB -:1084B000F5FCB2F77399C719F38EE9982EAB88AB28 -:1084C000B248EB41AEE3EAB46B24DF946D20F8D3FD -:1084D00099C2756181FDD788BC335D9C47B70D8912 -:1084E000FE91DE13DD67D7A84E35456D850C9CBF28 -:1084F000CD26FCEC2804FE53AED875E37D299D1BE8 -:10850000F92308C405D7E3A528ADF00D573CFF5368 -:1085100099DEFD1E11EFB40D89585CE4273057DA5F -:10852000CA74C5E8047EAF41E7288E8BDB6CD1F7B7 -:1085300069BF1DE9520917A340D0099D23348A570A -:10854000525471AE9EA26ADEA03490AEC05808614B -:1085500070000FAF860B7ACE758443627D07EA42C6 -:108560005B891EC70417AF9B392DAE4F866C52EC4A -:10857000F9139E65EB5A0A695DC20F2A4A98CFC764 -:10858000DD0B40A5F3EF14C5C77952CA7CD09A50D1 -:108590005E4E878FEF7B708EA6C9DC8F10FD2ADDC3 -:1085A000A77D9B34D53907E94EFB328D9F6BE8B62A -:1085B00072DD79DDDF6F4A2BC3F59DB11CBC6717F7 -:1085C000B61F2D0C0FA773DA0969FEB7C81E3F73DB -:1085D0006AD1BA3138FE2F6D56EF5CB24B3DC11FE8 -:1085E000D3B97DED13568DFCE2836FF447BE22F9BB -:1085F0003E2BB15DECB38AFBD8D79AF07E43E707F8 -:10860000363AD7BAA6E36D1BED7FAFCCF1BF4F7AF8 -:1086100030A9A3A98AF836195A9B699F13ED21D76F -:108620004B847385BDE87F65F8D6A6383EBB72F4EF -:108630007DEFA8FF72D29B4E5D3FF7537C84ED5EC9 -:108640003D4EDB7BE0BBA55ADCF969100EF27EE003 -:108650006A788EEB3A8DEB7D216536E168F46B8E9E -:10866000DB7C7138B3E5087DB7E9EFFB798EFF4B12 -:10867000D6DB03EFD8DCB8FEC09FC345E4AFC21819 -:10868000CF7D5D1D69C0A42F17EA8E4E03DB919D3F -:10869000AF7570FCBDF33E359DF41EE98734ECEFF9 -:1086A000C5F882F4686FB1D0BBA657CF8FA5FDE2A5 -:1086B000F3FB965F4EFCEAF5580D7CCF18427AB476 -:1086C0001BD88E197A58467A28D1F77B62BFA78CBF -:1086D000F04D7A67EB9EC37AB7D702A477886FC64E -:1086E0003BE25BA538A44C45BCF3F323588FDBBABF -:1086F0005FBE82EBD991BDC3C651DFC2F86A8BCC95 -:108700000949F87CA53572909EAFC4F7376931BD31 -:10871000AC9412EB7A167B449DAC611F7FA0EB6793 -:1087200078A496E6C5F14E594EC07F9C9F147DDD1E -:108730008FDEBBF127EB36A0BE94FA2A2C1328DE7D -:108740003926B31FD8AFC7C92BFE30E5865DE23AA4 -:10875000FBCF888E8B837ADCFCDCAA5CEE935FD047 -:10876000502EE3B1F55550BD7763156DC54D9ADDBB -:108770007A88DA29D5E12A3A2E9CB6A0FB90F8C671 -:10878000CD379AF0D67EF05BA3B94EFAA41DE83B34 -:10879000CEF6FF8CFEF1095CFF3DFB91DF90342E9D -:1087A00061BCA1C766FC0D86933EA9E7FAA968974C -:1087B000AFDBF8EB6B1574E80D04045CFF9C8DDBFC -:1087C000D605D1079EC8F15D9783F8FB22D77F5D60 -:1087D0000EF2ADEFF87F7AC89FEC7DE51D37F9E129 -:1087E000769B6F34E1AABD04F38824789C9263657C -:1087F000FF5A3948BD49638EC8B78607611DE1A598 -:10880000A15D5643E4A77DDDD793DF781F5949FB6F -:10881000DA4BA707DD942FD5EC3DC475FA463EBD73 -:1088200004F43FF9D659C4FF73B9223F5EBAC19A26 -:1088300090DF8E80888DCE91037E5763044552630E -:108840008A3BEEE8D8C2DF8DD46E4B7CAE8EE2144C -:108850008450DD45F2E3C61C7D9FA4144A294E4195 -:10886000DCF03E49F455D9BB15B8BEAA8BEAAB760D -:108870005A049F9C0E6849CB88C52B23F27C4BC8B9 -:10888000DE2D31FC875EAF146D93F87B8A513B443B -:10889000BE3CE5B4B685BF930AFAB84EAF86084031 -:1088A000BAA728415EFF94DC5208E2FA27A1792694 -:1088B0007D59DA2985989FFA772F0AFE13FB459B8D -:1088C00065FECE6FB30499C5346F94F953ABEF1FB7 -:1088D0002EDF91787E51B7E9F8610A95EAC3A6F3D5 -:1088E000209D3FE6F39DA7E83F929CEFFC24478F35 -:1088F000E78AA028E1BBBCAE4BFB2EEF238A075CC6 -:1089000074F8080971F91E1D470DFABAEB42B25806 -:10891000378A82EAA36FD76112002FF3A91E714232 -:108920003880F542DE463D632D54DBA88EACBEBDDB -:10893000E9309DBF2DD5E35A339E90A1CCAF657A27 -:10894000DD50CDE6C4FBB53A5F6A4D7C69F04B263D -:10895000FA44DC7DA9F4A1E5FA0EE1A0769795EB47 -:10896000B9CFC1AD5C7F55DFBE85E959AACB6F2079 -:10897000BD415ECF325C0FE9D3A5D26B96DF3103E8 -:10898000E757C01509F29B9D7949F22B057539AD62 -:10899000AFBF4BE4B5FD5D25BC2F61E0C5FCFC2CF1 -:1089A0003D8EBE66938837CF765439291EE83BAAA0 -:1089B0007825C47DC5B14FDDF4FD4DF93E19E89C25 -:1089C000B4AFB3625D10EDE59EAEA13769E807CAAA -:1089D0008F29EC372A8E9587528AA95FEE2CE53ACB -:1089E000132D93F2009C87FD70DFD1A127CA384E6A -:1089F0009F5949296AD3D17227C50B7B40EC6F4838 -:108A0000C72A337BE2FCCA7B3962BF614DEEBB0FE4 -:108A1000939DBA66B795F783AFB1465FA23C6C4FA2 -:108A200097E26DC27EDDB145AB5348DEBF91BC1409 -:108A3000761FEE5E9145E735F59D56D5CEF4DE7D89 -:108A400090EE077749DE61383EB0EFEAD16DB44F62 -:108A5000B4A5C24BEC35DE579EAE3D4AF5AE90E76D -:108A6000E4BCFD9ACBACEC5FCFE43BFF752EAEAB24 -:108A7000D6B76516D9E133BFDBC375157D6D12E43A -:108A80004AB48F7CE849AAF739F3F4711B9D075764 -:108A9000B51FE7BA8DC1FCC1D910E28EF3F6561BA3 -:108AA000E537F55B8C7E0F7F8F52ADC7510DDBDE56 -:108AB000E67E2DE50184C7CD7248C3FF3CB4EF19B3 -:108AC0003E1F6ED825EA3E2EDCDF26F17D03EF8BBC -:108AD00074BBB51C34C6FB7203EF7A7D9481F773C7 -:108AE0003097EBB496EF7A84F1BD44C7B7B96E0AFC -:108AF0002DB0AD2C4BE82BEDB799BFFFBB43C7F7AB -:108B00001D17C1F7A85C1DDFA36014E1FBFC7451C5 -:108B10004F77FEF81027CD7FFE08EFBE7E1DCED921 -:108B2000EF1ED5E382FE88C567BB3236AEB7E313CE -:108B3000FE0E3170B4DF467527B33A3F6679CCED4F -:108B40003C3093F87D1DF8EB887FD7753A558A83C2 -:108B5000E7F6087B36A7D3CEE713D741B885E4DC28 -:108B6000B7FFF1960CC2CDAF056E0C3BB74CE7EBEF -:108B7000B5653F9845F97BADEE0FFBBBEE9CC57626 -:108B8000671C1453BC3747FFCE7B4E58B7439B132B -:108B9000F94EE7D424B7864E3BD79B5C0B3D36F2AB -:108BA00067D7EAFED3EC27FBF29C2CE720FAAB61F7 -:108BB00038BE6E97A98E52E9617AFA3B6C7CDED59D -:108BC00060F2BFD372AD09F51783E1D32CAFDB722E -:108BD000757FA2CB6B6E54D431CC7945F6D2F94374 -:108BE00057647519C50B06DFCCF2EAD24AD3BEEE44 -:108BF000F7125ED2E37CA37F83FEFD5B586D75C5E3 -:108C0000E7EDCFE75AF473CED04F2B709D7749D064 -:108C10004D38C4FCE6867229697EB33217C73F5FC0 -:108C200078FBFA71F1F98D6FCB708AF71E44BB5255 -:108C300051C9F53BDD7C5EA8B4CEA573B0C02EABA8 -:108C400097F29A4087CCF14060973D64C179AF219B -:108C50001C215DD59DD2D58423CC1B5A72D13ECD2B -:108C6000A32D651C37AF03E3117C6EDECC8F197F1B -:108C700047868A75F72B5A4EB23CC2C81F1A3E1758 -:108C8000F1AA71BD01ED008D6FD0BF4B6B3FF8D7DE -:108C9000A2E2543AB7FDAC6821C5A9B9227F31E2FE -:108CA000D528C6AB257ABC4275174B85E860E973B9 -:108CB000F7D9C87E1DA61FB6A0FA49D5BF86F261B6 -:108CC000D50F8D3FA240436A613D6A209D221CEE74 -:108CD00095C4FECDB356AA0D81A69787705D60EF4F -:108CE0006BE21CCAACEFBD8BBAD95E9C5FE86A240C -:108CF000BC2D2FDBB206230C18BDFF75B637A37F42 -:108D000067532D6A6C5D4DF4DD1DE7692D09F17225 -:108D10006F47B38DF7A1E3BF1B2E19181FD55F64F2 -:108D20001FEB79935D41FA39DEED3B22ABB42F8422 -:108D30007CFC657E3CBFF478A8FD600AFBAFBEE317 -:108D4000AE10C5FD7FD1F17846DF976F9A24333F8F -:108D50002C93453B7AFF3325245F92871FEDFDCE90 -:108D6000FDCF5CE1E37DF490A823DE9158875D1F81 -:108D70004EACB336F81AD0F98A740DA7EF950DBA38 -:108D8000F62A3D6E6F123D92A4832C2F8B9498E7A8 -:108D9000069E95ABE3EB48713DB791DD3B69E88BEF -:108DA00012F5901F7E2B5763DC34750AF95AF68949 -:108DB00016DFFF1DB15F63E5F70FB83F235847F794 -:108DC000CF173BB9BE013E0FCEA5FE3D25E2F7030E -:108DD000EE79B97644FC3E1D48221F0F58A35CEF84 -:108DE00017386E61FA02C7FB3D435D6417B7CCA428 -:108DF0003ADA6B757B71B8C45943380FD27B736212 -:108E0000F32CC915E71B40EBCD8D7D5F69AC773541 -:108E1000DCC87C58ADE3EA3FF4BC1EF3A8F3B949C3 -:108E2000F2A8C1E2DF0B74EBF1D3F9E9DA89EF21A3 -:108E30000ECA8F2841CAD7F7BC911222FFDFB46F48 -:108E4000D99F281F0EBC69078A43EED9BF6C04D78F -:108E5000E1FBFD57923D39BFFF8E2BB98E5112DFDA -:108E6000970689BE5C8AA75EF5509C54BFEF55AE4D -:108E700073ACDF3BFE518A9F305EBA96AE631CC373 -:108E8000F82B3F56C9F8DB73B432B3940807AF939D -:108E9000E6AD3FA270DD63FD91CA17E7525C736CCB -:108EA00006C74F46BC5441F938C54F478626C44FC4 -:108EB000A979827F7D075278FF438212811F189A19 -:108EC000809FBAF63F709C5187F62E1E47C673C529 -:108ED000790ACF332C4FC74F58F2313E768BB6AE5E -:108EE000630FAF6FB935CCF26EDA6515F7DB446B03 -:108EF000D44907212348FC78912EA11CE6D842854D -:108F0000946FBE502CF20DB33C9EC813E7852F9C86 -:108F100014DF19BF30DD3F22D9F7C6419821F27026 -:108F200049E777BB7576B2EF7977E489FD09772653 -:108F3000249C4B1AEDA379425FE6D8C43E95F9BE56 -:108F40003FCFF03FB08ECE634ECCB5AAC6EFB7E4AC -:108F5000A1DDBD1E8C3FEFABF3B3E89C4BE4D50025 -:108F60003D33C91E7E9BF6F929FE9A24FCBAB1CF87 -:108F70003F6F333C20F6F96FB5925D30EA4BE6F96E -:108F8000CCF157F5D534CF8DE8DF699E9B6627DE9F -:108F9000FFF645E2AE0579BA1F1F0EC3455EE172CA -:108FA000923F38D76555655E476868B2EF0B0DFB99 -:108FB000737895383FEA42BB486DD3A8D779DFEA8A -:108FC0008503279F4C67BB9A0225C8E2ABBEFC9382 -:108FD00027D93C4D17F4757E02FE0C799DA53CA067 -:108FE0006CA0BCEECCB3E8DF259DB1F1F926343E90 -:108FF000649107FF2EA969D4672DA44F67F5EF5E32 -:1090000090BE227B9CDD3F9BF731DFBF6706448328 -:1090100078FFC0283BFBBFFA99129F1FD447843FBB -:10902000AC9F2FFCE1F0F6792C97EFA05C7C5E36CC -:1090300013AF515DAE21EFABBEEC9B69E493748E30 -:10904000D34438673B9DC56D7DFBDB2D7C5E897EFF -:1090500097E2C21B2625CA6D04F81FC8C6FB37CF8E -:1090600096BCE84106C8FDE65BE7B1DC6FD2BF8F76 -:10907000B998DC7F9BE7FF691EE97D77FF77C62003 -:109080008B5E18F54111F9D7864170BD55E72F0C5D -:109090008D3E4DE765DE0BE7E97F7F3AFE3CBDC4C0 -:1090A000E3DF924776D5F2A5FB0AA0F97A7EB942B2 -:1090B000223901EBC5607AB5439F7F479E2ADE9334 -:1090C00025CE8746E9FD17ACA142FE9EA2ECD2CE8A -:1090D000019B9E7D7E2CD9B9DE0347C6DAE2E47A95 -:1090E0006605DA07F237FB0EF1F78731DC5974DCDD -:1090F00029DC4AD28DBA1F4DC4E119C221D9E7DD5E -:1091000087AEA7FCF16CFB4D599216E767F79E708E -:109110000F8B9BF7ACFEBB1898B70DFF766A3C9D92 -:109120000F309D67C3623ED4FFE1378D89BFDF6C8E -:109130007C67C7787E7064239FD31B785640E0D944 -:10914000F83D8C0BDF55DA80BF7B0CEEB7737D45A5 -:109150009F355A941EA72F1F1A7244981566312BFB -:10916000B9DE75226CA8E273024CDED74DA6CFEFB4 -:10917000C2B2A80F6DE4BAC5698DE025DC4AB0998A -:10918000FB13668BF3F229D02D135DDF8428B73EE5 -:1091900050156A67508519B6931C6199C2ADB6F631 -:1091A000834EC257C4A3A4BFEF10A5A7C9E4175BA1 -:1091B000BF02EF1B78C5C1180425FD4E3F2B5FD8B9 -:1091C0007FAF53E863F4ACF8DD936F400FD33F55A6 -:1091D000E9667A53352D83CE4B763FB742A6FA9790 -:1091E000FDA04549CFBC998DBCFF169D0EE1ADE9B0 -:1091F000B1F54EA2F5AAB1FE940560A1F54AB04BB7 -:10920000ACBF1132E87C6C3244F83D5711C1B8DE76 -:10921000E9A029D4B7E517EB7C16F95B959EBF59F9 -:109220001C41AEFB49CD17B8762A2139AF92B7B6AB -:10923000C38FD0F94CA958E744BCCEE7388D82EEF5 -:109240000BFE3A5FD8BB29106639430DA82FF28F69 -:109250002BCC54895F52C463A1DF13BB54BEF67993 -:1092600080E977DF1EEDFD6165ECDCCBDB99C3F5B2 -:10927000D0EB254B5426BA1C85A21E3A0261FE2E65 -:109280003392F87B67C5F9375E9E4F7ECF2FBEC302 -:1092900035D775EE086DE5BA9B0541640FCD5308CF -:1092A00070DA13AB03B09684F8BE95CED955AE33C1 -:1092B000ADA07C715FB6FFF2FC6CAE371DC6932982 -:1092C000A1F1D5A931BC2365FCFB3B4E486D257B44 -:1092D000D4ACD7D30655B75ECF54C4EBD0D0CEF3C1 -:1092E0008F4828A2AEFBDE2A517F7AEF90FD5CE723 -:1092F000DB23812A15D0F9FF7EAE03A61F86B316A5 -:109300007CCDF97F96FEBB0F25FE372696EA461EDA -:109310009F6B3E95CAF5AFCA0C9F4675BCE67AF1C5 -:10932000D296F10FF5705E6AD06BAA1357BC7CFF22 -:109330005EDDBE363BC4EF0049ABEDAA348DBE7F87 -:109340005FC1BF63D54CA141257DF7BE829FA73A7F -:10935000662A02ED4DF3DF44FC32FF2E15C2ABFF4F -:10936000059A376D38EFF72593C734431E968175FC -:109370005228875B49BE46DDAD516F4B80A0753BDF -:109380007DE277F054C409FFEE1F42C94EB8F4994C -:109390007FCF43D4FFB6E8FC47BA7670DDA7437CA5 -:1093A000A76D7CCF6BE69B81DFFF02B9D77EA25011 -:1093B00053000000000000001F8B080000000000A8 -:1093C000000B9B22C3C0F0A31E81F9A551F9E8F858 -:1093D000049A3C0B0303C34F205ECC835F1F2E1CFB -:1093E000CB8260BB883330E88A3230E801F1142048 -:1093F0009E0AC49F81585B8C814107887381EC3C35 -:10940000207607626BA0DA2F1C0C0CDDC20C0CD38B -:109410008078A130AAB92F1821B41217038329101C -:10942000333263B77FAA1A03C3011D043F5D9781DE -:1094300061AB3E797E19C5430F6F7344E51FB5429A -:10944000E57FB06160B07742F08F5991667E35500C -:109450006F8D136EF9A36EA8FCBD1EA87C0B34F9AA -:109460001D61101A00FB3B7C21B8030000000000C6 -:1094700000000000000000001F8B0800000000003A -:10948000000BED7D7D7C1CC59560F5C7F4F47CAACE -:10949000471ED9235B323DD2D8964186B62DDB32AA -:1094A000B6714B06472424194CE20802B9C136AC08 -:1094B000B3E1B809770B0EC1D1E8FBC3B219192F7C -:1094C000311C81417CC4102E281F9775127219031C -:1094D000C9CF9BCB651D4238270739A1F8D87C6ED0 -:1094E00074EC19CF5D08DE7AAFAAA5E9D67CD986DF -:1094F0004DFE38F9472AD5FDAAEABD57AF5EBDF744 -:10950000EA758D22BA48EC2242CEC2DF6642DE7294 -:109510001142D6CC96A976234B5A68F934317AE9B0 -:10952000A34BB46CBB40CB15FE4951D009B92C9C60 -:109530002644242436F1301129DC509D4246A28471 -:1095400078F46D55C43FDBAFB3ECED2224BBACF82F -:109550007BE9F9E1881EA0FD3DB5B6D3A4FD0C7DE5 -:10956000A5B5D36C9E7D5F0B8352FC1A08C5A686F9 -:1095700090FEFAFB89182664908EBD8CFEA7DE93C0 -:109580002071DA4EC90E137D05C085105EFDFA0903 -:10959000F166FA7CD0453A2768A91E4D657D14EF27 -:1095A0004B9FD35649941E8F6C8ABFA5754F44CCF0 -:1095B000A4808EC841ECF734A50B867AAFE8590D2C -:1095C000F4503A365648CFC662F43C974A013D976C -:1095D0001DD557E6D3A3D6317AD4BA1E9CA7D31192 -:1095E0004A4FF442E8F90CD233C8E91974D0F34178 -:1095F0004ECF768B9EDA01A467A09ED2431FB9EFAF -:109600004991388557819E00C0D9E919007A9A0B93 -:10961000D0A3FE79E8F92B2E6F49A0674D797A9295 -:10962000404F4D05F4F8D344A3CF3D4430279AE78B -:10963000E2E5E17C5CF1F5742445FB1DFE9384F3C7 -:109640004C576464DB8A59B8498ED7F7A203914915 -:1096500090AF25F74708ED6FB85E407867BF0F10F1 -:1096600005E1B53AB31BFABFF888BDFFE17A86AFD2 -:1096700005FF7B3E8FBF2712B65BE08F0F437D78DF -:10968000C9374802C671A5231AB48BB276FD4BD6F2 -:10969000764EFA0BB567F40CEF4DA13CABD9CF2059 -:1096A000BFFEA63E4D745AF71C4910E0BF1261F888 -:1096B00058ED295E845C0E64DF699A0C3F4216D235 -:1096C000794ADD994DD1F162E9DBD538E5C7706D96 -:1096D0008F0A740FE9073B416F9D8E29448A025E11 -:1096E00085F960C9C56632AA36D0F9EC7D59324693 -:1096F000C85CB8140857CD6C5DF68B24DB44F0EFE2 -:109700002C017A1238FFFD4BEE47BA15A06B05D03D -:1097100095243A7DFE2D2E3FEEAFA708C895AAA747 -:1097200022A91573C71902FE3743AFE9C8B63CFA40 -:109730007F6ECD2F9D57C7FC225F1E206636057CAD -:10974000F1D8E7CD2AFF9EF3FDB2BA14F2B7DCF8E8 -:1097500073E967E3FF1DD1B11FA2A623F1C02C3E20 -:10976000C3AEC91E906BBA268D2728C8A5749CB6B7 -:109770003C7E3BC79BA1534EDBE4F81B9C4FC39E32 -:10978000E9E7F3FB73E2F35D0EF75DA26169D17562 -:10979000E951364EB9FE7F022CAE0178C7BA92531A -:1097A00036BEDFCDE12F7BCE0E578C3F9F9DE14F24 -:1097B0002A02F268AD47F833E713C24506FFFC6B97 -:1097C00009590EFF8736F9C3CD9377C2D27A259C0B -:1097D000380DED6F23898BBC8D74BDB8125F847218 -:1097E000AB6CBE85FD12BFF6C6255CEE24D4036CBF -:1097F0003CDA3DA1FD07787FB2D041089567772B11 -:10980000C98C50D4AE925ECD0A949F070931166878 -:1098100079FBFA14DBD7D76B992DB09F6F90292174 -:1098200074BC2AA279A004F82C850BAEF11B742419 -:10983000E2261FAF8A17901B4F0B4979AAE8F8ADB3 -:109840008A6D5D78CC0401BD108890AC2748F58DF9 -:10985000100823FEEBC83A86BF2E407FD5B2DE2D1E -:10986000D371A498688CD3A7551BC9FA1D7972A827 -:109870000B4C7EBB63A208740D50FDEFA64B325813 -:109880004FD73BAC8708B5370AC8ED8C7ECF49244B -:109890003B8FF69B13487635ADFBC9FA046D97767E -:1098A00093F5A7705C628C1790B3ED029B5721363D -:1098B0007DF62CDA0524F33EB40BD2B88E9558DA37 -:1098C000847D403583861BA6FDED7B995E938909D7 -:1098D00072128AA5B355F05E5F1A057C17C492E434 -:1098E000F566564EE5E1ABFA5311B49FA24B859E47 -:1098F000BC7DEC18959FA93C791BDACBEC80FEE887 -:1099000000D7339F44FD69BDFF04E79332499101BD -:10991000BA7425D320CC95EB21A1B09ED8C9E98596 -:10992000BF2BD7DAE5559ECFE5950EE19609CAD74C -:10993000E0532403F8524E3E7F33AD5FF2A24A4615 -:10994000A87C35931322C8CFA5641A4B8368129460 -:10995000AB8881650B8963F987362AF7B4BCCDA43F -:10996000F2DE80F2FF51818EFFFBFAC4B2207DEE61 -:1099700089A52E87FD85CAFF76784EE5440079AA31 -:109980003649C1FD3224B0F53A266B1E801B3309DF -:10999000EAC743426F0AF689216E270D79886D1D4B -:1099A0001FE0740FF132144B9049985F3A2FA0D703 -:1099B0008F456FC575EC96597D80CE0BCADD26B6F6 -:1099C0008F39F150615E569CFF3C6CFFF3CFC38032 -:1099D0005053701E06611EB60B4C7F2ABF62E39780 -:1099E000A00FF7E99DDD8F22FF9553E7066FD1BFEA -:1099F000D6A137D7713DB7814C2F96A91EB9DD9DF1 -:109A0000556401F1FE02E0FDD6CF4E7C02E82193C1 -:109A10008965B04F51BC1F16504F26C9093ABEFC8C -:109A2000B294013F45F45DA3264AF82944A3FA4CB9 -:109A3000E5FAAC01FEB74E7BC33757FF2E9DF8AB5E -:109A400093686F10353102FA69535205B9E8ADDBFE -:109A5000A6821C0DD6D13AC84D445185CB68E92762 -:109A60001D207F96FD3110D931140D83DD63AC8547 -:109A70006EADF1B7441244C0E78979EEA8FDF92F25 -:109A800061FD6B898844E95332EF5381CE7E6D9B33 -:109A90009AEF7729FE4444A1723808E3C1F8AEE496 -:109AA000F1680BE84FB2BA07F4B99624AB41BE2374 -:109AB000ED88E796BAB80AEFDD9155C4AD038BE3A4 -:109AC00068570D84EDFEDC60DD1DE456844F92374F -:109AD000FC73ED6BB73F4994BC7D02C691F2E6D9A9 -:109AE0002D27B340971429AC77FF07977F518FE359 -:109AF0007E43D29F37552AF72E2E03AE08F9997070 -:109B000069DE3C85F3F61D3A4F031EA3B3D0BAA419 -:109B10003B88BD5F4320EADACAFB9DDD6FF9BCA735 -:109B2000D70D4DE2BC07D230EFBD54EFE3BEFA6A69 -:109B300020F30425A17B53F21178EF4AC9A4278CA6 -:109B4000DD34C13E779774B101F27700F846378E65 -:109B5000D12E15CB912E0DCBA1AE08969FF77DEEA1 -:109B60008B93B4DD9E945B73831CA4EF7A16FAA3E7 -:109B70005E777C04FA0DD3FEA15F59D59ED0A0CEAE -:109B8000F61D578C95378A8C8F55A217F16D119958 -:109B90001DAE1313E525AD95F6D3AB5AED766EC029 -:109BA000F0CEAE07FA9FAFA9DA56F7E80B6DF0CE0C -:109BB000F5F26391E90D971C2746339485F5F85922 -:109BC000414238495A390DF687BC4041BBA05FB0CD -:109BD000EBED8745B6DF3D26AA4867844CBF7096FB -:109BE000F2C3A58968F704430D1359E04F8D622C29 -:109BF000A145D035A95517188F84E5DF4DE6ADF3A3 -:109C0000A7043326FE05F0690EFDDDED36B9DE272B -:109C1000B2FDEE2C5F2F92DBEC043D13A1624850A5 -:109C20003EF447810FA26FA3D144F9D01F5274F0C4 -:109C300087FABAC582FB8E930F52D58D11D08F4E05 -:109C4000BE7F97CBD1339CEF9BDFFE30EA89FD9A34 -:109C5000D891F103DF4E74809EEF6B114590F3BFF6 -:109C600018FE39E8D833C3BF193A906F7D61663763 -:109C70008F6A547E603D8799FCE824DB81EF0D4AB2 -:109C80009730972E27FFDE6BFA2CBE5785C478A637 -:109C900019F09B8E237E1BE582F8FD6BF1DDC2CBB4 -:109CA0003F835796E165FC65E0F594901887F57D54 -:109CB00080CBEB01795205BD10B3E4C6C7D6D15CA9 -:109CC000BD24D8E49DF6F325E8E75EE887C2DF2BE4 -:109CD0004FDBFAB1E002C007B62EE26C5DC87FD65A -:109CE0007561E135C2F1D64986C9755361B97EAF58 -:109CF000F1B2F6D31EDF1504F44DC81F47FB7B817C -:109D00003F9E057EF5D6283AD83FD451C2FD1A9B16 -:109D1000EA797E52CDF608C0F707B6A35DDEEF8A7A -:109D2000A39D7EBCE61BE6CD94AEDEB7AB88DBA080 -:109D3000FE80EF8AE33AE8C5E312FA6BBD6F372E77 -:109D4000481698671FC4C728FE5EC00FED6A65C637 -:109D500008077C7BFD54F1D17EDE6C2619D0A72E3E -:109D6000BF1901BBBB77856AF420549C007F7B7CC4 -:109D70009F684D34CF6DEFF30F7C5ABA74761CFA9E -:109D8000279C05DB97EEE1E0C7237D82ED7D413C1A -:109D9000CAD55DB3750DFBA7755D85AE05F36CE3A4 -:109DA0002CDF292D4D32EC9BC46BC0FCC7E21D3D5E -:109DB0007F043EFDBD847AD0C99FBF93125E69CDFA -:109DC0006CDD154EE0BC59FD5D5D23A31E95EB488F -:109DD000C62DC0A8F10EB06F7BEB448CAFC9FE6DF1 -:109DE0005525EDEEBACAEC6EC2E31E963CB4FD8A70 -:109DF0008DEB3598FE0E90490271952AC2E21A2128 -:109E0000A20B04DB1B421C83251B319E12F6BCDB1C -:109E1000FDDE88FD0AE61839EB3B877E65DA6FE3E5 -:109E20007BD06F197C3DE421EC97AA87F0D979B3F8 -:109E3000FDBA22497C48DE3E7B565A4B5813FC4BF8 -:109E4000A07CCBA281EB932C0C1A4FD0A23F7C8735 -:109E5000CD9FFA88D4608B9B2ADAC0A785202DEB92 -:109E60006E3327F3F483737E3B6120F02FEB7699FA -:109E70009315E80D30BB0BC5A5069444A61BF6EF61 -:109E8000C57E8C2312398971E141A17A15D8CF168C -:109E90009C5CA76401AF408B99027D31384F34241C -:109EA00003FA1D3D01FE0091AE311225E24B729D79 -:109EB000FC9B7C7AFEAD1408239E3CCED55B46DE2F -:109EC00007BA4A9F4F288A9128E4CFA42466BF2866 -:109ED000DEC2EFAF54DAF74A6BE6F22D0DBCA3CF2A -:109EE0000743D4E5BE8C890FC8815CF7FD93C0871A -:109EF00081DAAD9152F4128DDA39797E91A19823ED -:109F000052693C0E14C283F8A9F0AC2F310E9F5F4A -:109F1000ED4A83C53B4029C2791CB7CF28DE416199 -:109F20003ED3D3F0B7BF653C0B7134D7CD7E13E67B -:109F30004F328F1089C2FFA85622422BD4BDAF8B5F -:109F4000389F1B0DD4574DCCBF33E93FA023B851E8 -:109F5000B1ED5BA03F67F6AD28C8BFBDFEB4648F0E -:109F600067F6761D25BF5C328B3F7D64168A17CB62 -:109F70004AFB44617E5457C48F43545E08959783CF -:109F8000D46FA44C2169EA3742FD00F51B09FA930E -:109F90003A967D5D4D58EE83A6EBE1FC2C39148D8D -:109FA00042BCF4F1C82D14E410E80E3C57F1B6435E -:109FB000FC7CC4AAD32702D4F939CB0F7BFFD80687 -:109FC000F198110FAB1332DD66DAEA520FC4FB478A -:109FD00002ACFD2F257F3B9C471CE2E7484436D569 -:109FE0008FE6F9FF39C98574800DC4DAFFBE1BFA0C -:109FF000F3C8BC9EAA477C66EA948F808F4765F5BC -:10A00000BABEC5D83FAA003A5EACEF2236DE126671 -:10A01000DF93E66D65F8D883F27F3D1CC201CDCD9C -:10A02000D570A84C14C320B0DD1C0A71BC2BEC8782 -:10A03000C809B6DFF1B852F17553665FE378949BB7 -:10A040007F027E29C42FA81E4EC1B83F2DBC4FBF32 -:10A05000DBE31E729D1B5F94D6E9944C59FCB7520A -:10A060004293693D604E64A3B41EBC269BC2E55B6F -:10A07000E1B8BF93341E0F4DE0FAB7F82C6BCCEE6D -:10A08000B8D2318FAEB089E7921E3F5B7F95E2BBBD -:10A090001EC6C9EB873CD35E1B0F146F571317679F -:10A0A000ED2DFADFBC0EEFACBD46FF0B99D5B67AAD -:10A0B00055EB421B7CC068B0BD776917DBDE9FEFB4 -:10A0C0003C5DEAA0A3D1E21FAF479C74562C77B247 -:10A0D000CEF7B914B31F67EA7C3F2E577F7B99BD3B -:10A0E000CEFA75931BAA987DC3EC987F43388C13E6 -:10A0F0000F234FFF4A00C7EABA2810CBBECD36CD9A -:10A10000EDBF57FD1CC6E1CC5E9978AE981BA74BFE -:10A11000B52731CE96EA716BBD618CBB619C6D0F2A -:10A1200035E4DDB4BCCD95D80DF27BC6B33843829F -:10A13000D06F721DC4AD7B1DF104A73CC51EBABE15 -:10A14000E07999550E75B1F89F5557EB0AE701DC98 -:10A150002DB3F3FAEFBB1277031EA01B09C66909E2 -:10A16000AE0397CEF6C763D1ADE4D7E8FFB3F331C2 -:10A1700085A44E36527AD2D45F1BD1816EB64E86FC -:10A18000A25BD5187D3E1612B94D378DF653BA6DC8 -:10A190007E2DACA72A791ACFEDAA6285F1B95716A0 -:10A1A000F9BCDD54923EE77CDC048156DA6EAC5E8D -:10A1B0001091FFF562E6098847D589B8AEF79BCACA -:10A1C000A370D4BEBFA5FA7A8CA79B8A28211D59FB -:10A1D000B5D03AECE776532F8F9F1EA8637EEBB184 -:10A1E000B6375438AF3960B4633E809CFE11B61F59 -:10A1F000E4FC4EAF9CC238F96091F3971E99F9F9CF -:10A20000BD016F67A6E0FB20BE4F47DB9E7F00E8E5 -:10A21000A0FAF709F4CF48ED2E4A87666AAB80DFD3 -:10A2200063F5A6F86B90AB4D22CA5910E272129CEE -:10A230008BDAFDE7B14D229EB3A635BF01F6FB696F -:10A24000F34D821B91ACD5C2F962D5AB1B34DC2B2C -:10A25000A9BD539B67E7576D4CAE83F9B2E8729383 -:10A260006B0BCE87B0784F02F879D72AA2833FE6EE -:10A270005EDC91FD02EDF7CC7AB706AAE0CAC09584 -:10A28000D9EF803CD16D05FC6477D8CC82DDE4E960 -:10A29000F4119DBE0F4626D08E52231231C1AEFA64 -:10A2A000BF12CE17D51948977C68FD89CDB4BDB2D1 -:10A2B000495C80765933DB6F34FA0FF61B3566B78D -:10A2C000AB245716FBBB77F2513C57561C76954C86 -:10A2D000F2E0C1EEDAB4EDC38D05F481554A934145 -:10A2E0003CD725D28D25ED6CFFAB9FFC8717F3F88B -:10A2F0003E253BEC746EBF59FD14B3DFCE74EDFE0A -:10A300008717A92C275C2C0E2A2BE66F605D4EF177 -:10A31000F3C53147DE4DC2C5D6CB19BE8E6166C1CD -:10A32000DF06FF18F8D577D576E66711C3E6C7D004 -:10A33000F57E46CEF3B3ADFD2E6D96F62766F35A45 -:10A34000FC9E5889BC966BE584EC2A91D762ADD708 -:10A35000E14D2689D0F91D0D914C0FCCEF6693ECA1 -:10A3600004791588D1A331F869EB1C250A72781598 -:10A37000D905EB57970D3887EC6FFC1075148BE3FC -:10A380002B87EDF2516E1EF738E67191CB6E87BBCD -:10A3900048BC2A1B853846E47AC0637F5831603D4B -:10A3A000BAC41B77EFD0E7CE2359C7F4862B9C2580 -:10A3B00085C6B5F879BBCB5CE68238BB629C4C8025 -:10A3C000FCB72BE8F73AE16F72F13C962891C13E59 -:10A3D0004BC13A81F5DB61B2BC31414B3E6820FA9A -:10A3E00071DBB956EC2DCC677B4822C9791B09B9C2 -:10A3F000CE15657AA66D3BB37B3E40042904F00977 -:10A40000DCBF6A4D4DA07D9361CB2ED36E8E5C9BDD -:10A41000A727AFE3F239FB3E11F9A8EDBD8BE11997 -:10A42000E076B3B63372ED8A02ED4385F5E407B802 -:10A430005C5FE7E2F6446A27E605F5EB37C681CFB5 -:10A440007D9B4D6317682D9011C847F1139B7D4C80 -:10A45000E5FB3AE0A7153F92B53896963D506CFE65 -:10A460009D76802B62CF3BA9F4DC3676E8FA92E346 -:10A4700038F7672BBF0D345F3E9F5C9C0FCD7CBDD2 -:10A48000CCDA4B69BEDE0DCC079214330171494919 -:10A4900020367B6B8CCB8BE465EF9D7850FFF94EBB -:10A4A00058A752D044FF9AF85B98DD261BFAB505F1 -:10A4B000F0B7CE391FE379BCB1F48770FF1B0DB53F -:10A4C000E3BED7A795D61FD6BEBA995CA342DCAE31 -:10A4D000BFB8FE18CDD71F4A58B4AF63EEDF53FAAA -:10A4E000F5427CB6F814E1F1D2DEC0F648C9B8A056 -:10A4F000E37CC550CC07902FC5F9F685F3E1DB2846 -:10A50000CFABDBDBFFD2F33C0FC1AEAF5716D5D7D5 -:10A51000FFC9A64FB9BE7E0FF9FFDCBBC1FF4AE3FE -:10A52000309E3D927E6A1E55F1720AE919D60FA639 -:10A53000301E03EB1BEC80741BE62B901841BD080A -:10A540000D41DF797413F9E6E57126A5CEBECF483B -:10A5500061AFAD1EE94C11C857837E816ECF1E05D9 -:10A56000C7B5F84D6D16CC27B3EC4B584EE08F14A1 -:10A57000CB4FB34A2B7E03C73867719FFAEC71E06B -:10A58000EF693FC1FDA138FDF671221F8997D64FB3 -:10A590000E78E297F5370A9C0BCE6D279337F2F4CD -:10A5A000DAFF71E813F3C8CD9DA847896840FCB273 -:10A5B00037B29D2428DE0384E9932128D7433EC97E -:10A5C0002A0DFCDFEFBB74D65E67FE9DA8F238BD96 -:10A5D0005E99BF7717DD870AD93F4B15661F9FF934 -:10A5E0005CF20F9097901A1174D8DF4E75E5D07E0B -:10A5F000DA915DAE405EDA72653EC2ED381455B652 -:10A60000E4ADCF1D849DFB5344947C3D6AAD3F2552 -:10A61000ED7E1EE89C4AB3B8C654FA9FF15C7FEA0F -:10A62000B09401A64E0D5D5772FD9CE27ADB823B31 -:10A63000755832A1BFD490905942DB9F92CD60C132 -:10A640003C009261E7C1BC7E4B5AB2C9E599BD0995 -:10A6500005F4CCA92E55F8259D9B5B814E8AFF8E73 -:10A660007454019FAC1C5DF314FB7C5A74F643BE1A -:10A670004274367FA73FFC26D27B9A3E974AC4930A -:10A6800046B89EE80F17D6275E7EFEEA75650AE794 -:10A690003D38E8F535D9D7A585DF20CFA718D418E0 -:10A6A0005E831111E761B0AEB41EEBE3F360C1F558 -:10A6B00047D8796BBF1C572BC1C7A5D9F129368E56 -:10A6C000BA71A203B6F92A92E8688F227B5F8238BA -:10A6D00002860E75F09F9E3A762BC4816FF69B42E0 -:10A6E000041E4E67BF43EB0BA8BF03F6A966668442 -:10A6F000C52D90D72911881B3F947C33FB1AF8A3F2 -:10A70000D4FF817A484F86DE077A289610605DED87 -:10A7100007E58F9D7FB0B7AD99AF3F5AFFD440FB9F -:10A72000168843CA24CEE319A20EF97AB8F4C5E21A -:10A730007A02B4E759F76CBBA2743AFC2237D956B7 -:10A74000DAFFDECDE053F41FE89D050E3F2BD46900 -:10A75000B7BBAB1CEFC7B8BC16F32BDFAD71E693EC -:10A7600097543897555B442D03F0241982FD3678B1 -:10A77000A34CC08E9FAF6BDD10E22BC7F77D84E545 -:10A78000B9C11711F9EBEF4985D9B18B6E7F5C80A8 -:10A79000FDE93478D92BA19E330AC9AFD3EE1BD281 -:10A7A000A7309E38404E7434823DBF4BC4F3A4FDA5 -:10A7B0002D0743F9EDBFC7C7999D7FA2CB6BF1541D -:10A7C00016FD79A5453461DF3ADFF977FAC9E5E688 -:10A7D000BF76B7DD2E3ED779F93120BEA6FCFC5FEF -:10A7E000E838D6BCCD5D1F4C6F2EBAFD458CE38C8E -:10A7F0001AA5F5CDDC797B09E72DD842CC42719CB6 -:10A8000057F83EE6CCEB53499218909FF832DB7F25 -:10A81000A4C6B591F112FA478A39FC0FDE4FEE1645 -:10A82000424EC07E2BEB65BE879B3824D37DD3B7C9 -:10A8300067C3217935E4679998E735DC65E2F399D8 -:10A84000F9778B1C5F81886BB95ED1F1FCF3908C3A -:10A85000F68648CE421C846844B7E48E005CC7216B -:10A8600019E3313ACF23A0A0F3A11D41BDB4129248 -:10A870003D6BF09C1EFB818E581CA693D569439CB2 -:10A88000279769225E725ABD83F2739F87D7755EE0 -:10A890000FF1BAC6EB515E2707B1EE53681DE2F225 -:10A8A000AEB486752FAF4779BD9AD743BCDEC0EBF7 -:10A8B000C241ACEF53587F237286F5EFE5759DD703 -:10A8C000AB795DE3F5065E27E36C7C37ABC37E882E -:10A8D000751FAF47797D1EAF8778BD91D78571AC65 -:10A8E000179B3F6FCC44FECECE7F07E31B21DCDFFE -:10A8F0008C3BEA9DB3F079FE687F972EE49F1FBAE8 -:10A900008AC49F56B9999E996E8B639E12F5175211 -:10A9100053F9E78E91C2F26EF27633E7E6610A5799 -:10A92000307EDD5D705D548ADFD6F3C4EF23FF4ACD -:10A93000F8DDE0B6D63DF3CFA7DB0CC4D3D99FB387 -:10A940001DD85B24EF9CDE2B675210AFA13612FAA4 -:10A950003B2ED59ECF7A979B9D7376BB593E6B2F2E -:10A96000C76FBA8D9D3FF42FF166C685B971C6BF1A -:10A9700071B378C20F2C3CD509F47B7C39BA62D113 -:10A980000F627ED470ACBD4CFEBAFCFFF2FD656771 -:10A990001CE49FE11D1DC7EB2FCCA7BB66F4CD8D3A -:10A9A000A9290AAB7AE873F067B470A42E3F6F9AB6 -:10A9B000BF278228A17E799BC259F92212F6CFE2E5 -:10A9C000C5752C5E2C71781C27CABE633057C13EFA -:10A9D000439F37F17184B9FD3ADB65DDD56CBE3834 -:10A9E0003E567E8A449EC37E66F091E3C82FE7738D -:10A9F000C843D6FC17FEFC42EB2EBDC8786976FE34 -:10AA000052AEFD17B9BCCC91CF22F3FA1FDD969D53 -:10AA10003261423E902547967C9DAF1C5DB09CC044 -:10AA200086D4525C4E522489EB46069773E5B9CB27 -:10AA30004B0139C9E6C3D7A8217E9E6FA0BC507CCC -:10AA400064945B8DE153B32A8CFD09B0C697410F26 -:10AA5000BC0E7CA0F45EA286381F589CC20BE78C0B -:10AA600079ED297188AF20095CEF33B8CD2A5BE717 -:10AA70009BDAEB18FE84F7EFC097F6A7E6F727916D -:10AA80003A879C33BC3FA6B2F9A5F0F89DDF9CF154 -:10AA90006501F195483C25D2769FE2F04EFD659523 -:10AAA0007B397EC322D9CDBE938C93FCEF2A7DAA3D -:10AAB000C8BF7B64EBCCA99F5C2057ABCF5FAE2AAD -:10AAC000D5EB356AE17D87EAF92688F715DB774E05 -:10AAD000AA33FB41139FB7739AF7DF811E5A333BAA -:10AAE0009F95E27B091FF75CF13D3517DF8AE4ECA7 -:10AAF0004DAE272AC56FF379E2F79203BF774BAECD -:10AB0000DFE6FB51A5F87FEC3CE5E18773F95BD10B -:10AB10003A12D573E3EFA7CE13BF5F38F12BB26EB5 -:10AB20001595F12B45987CC8FCFCA552FCBACAE3EC -:10AB3000C7F3C5B6F69931B4D7D01FDFAF6EED4B72 -:10AB4000C9B3F89984E9F5731DFFDE8AC7FF509FEA -:10AB500029CF8EFF05F543B6F165D94061AB74DCB2 -:10AB6000872B1D37F5511BDDCF0C7DD436EEF9F266 -:10AB7000FDCB158F7F938DEEE7866EB2D3ED373028 -:10AB80009FB8D271BF739EEBFD371C5F9FAAD9F6A9 -:10AB90008162F6FBDBDCAEBD45D56C725C0CFE4D14 -:10ABA0006EAF7CB042F853BCFF460B9F32F09FE182 -:10ABB000F87FA642F8DF717CD65788CF0FF83A2C81 -:10ABC000B67F7A39DF7DA023F3FC9A0BCD5BDAE503 -:10ABD0004E081E38E7FC7A177E27F8A6AC6A10EFFD -:10ABE000241D04ED71CFAB8171965792E2FE7F2256 -:10ABF00025303D8CF12D57D8B09DC7597E972CC775 -:10AC0000CD42E76D210FD37F826674B2F5AE10C8D6 -:10AC1000432A06EFF3148EBF549169CC3F21117E75 -:10AC20008EF4F6757AC17302398E792D92A69071E1 -:10AC30003A4E5F68BB9E9FB71CB3F08998888FA27D -:10AC4000317C14D9300BE529D77BD8BC5AFD58FE8E -:10AC5000A1109926EC1E07865FBF27DE0979E2A9BD -:10AC600090827CEA0BD8CFC7AFE7FDBC9FD3D7E774 -:10AC70002A9D27D63EBF15F3957A5B59BE924E0C9E -:10AC8000CCEFECF397BED760B48BC5FF4778FED30B -:10AC9000107C3F0ADF13C3F7A3CBA0FD57F13BBCE9 -:10ACA000D3CD62C9FB7102863DCEEE6BB27FCF631E -:10ACB000C5E53DBAFDBB1E77C4FE5D8F6BBE8C79CA -:10ACC0005D7D7E763E500E7F2BEFDD821B9493AA36 -:10ACD00056904F19DBB9803B62C7F7BDE31F6BEF9E -:10ACE000734D6885F07AB7F8562CDE30436F959235 -:10ACF000CC30BD61CBCFE8E2F2E5AE5293A097A98C -:10AD0000DE2DF2DECBDAFBE3981FA246E23AC6A3C1 -:10AD1000F93EA0C27AC8E3D3E7AD75E915AD7C630F -:10AD2000CCEB107413CF1F555847C2DC7633F36A4F -:10AD3000C9FD9FB644709DD4A8B84E047D1ABFEBE0 -:10AD4000728EB3CC631EF4C0F998C7BC0F4AD73BD0 -:10AD500052A2D07A19F3303DAA5E13D7D5067455A6 -:10AD6000D1EE71E2F12C5F7F7E0BFF9489F917958C -:10AD7000E2FF7085F85BE350FC9F063D4BF1FF124C -:10AD800094C5F07F8AEBA36AA277E39EAD333D4B77 -:10AD9000C8B57A7E7CDDEB65FD56733D45489B2D3D -:10ADA000AFC7C5E9AA949EA3965E2B438F352EA507 -:10ADB000E7453E1FDF2B351F2F707ABC5EB66FA9AB -:10ADC00087E33A5D9A6469917999E278CCF7F2B8B1 -:10ADD00052AAED9CE4EAC715D231353B2FAFF17989 -:10ADE000F945293A5EE5729596C8FA53B09F365AEE -:10ADF000F90BDB6CF3B288F327EDB6E6A5DD362F51 -:10AE0000A1739C97DF5648CFA2D97939C3E725575C -:10AE10004ACEF2E0FFC4E1DFE1F068272EF2FEB196 -:10AE20000FCECB9679E2A2B766767FA3709277CDEC -:10AE30002CDCE7878F5B706E84EB988153BD79FDC6 -:10AE400091D4EB7D70FEDDCFBFFFF8C170E02ADE4C -:10AE50002E88EDAE61F4D07655F9FD3F3BFCB2D5BE -:10AE6000FF3C80EBDEF28E0517CE875BE47DC78268 -:10AE70008BC073E1F04C7FB5F9784C79FEA98FE572 -:10AE8000EB38F2BDB4CAF21D5CE104DEE7504D02BE -:10AE90006989960332BB5F21458DEA27207FD69DC5 -:10AEA000C8920AEC2E5165EDDCD4DE82F3E3791A08 -:10AEB00039E6D1C10531C861FAFE4058467FE00E3F -:10AEC0004FA2C55BC3F0C43C80D7983DD6ED6FE17F -:10AED000711486D798EF1343D09F46F182FE3FEF5F -:10AEE0000B1E03F883F50AE6F31EABBF13EDC4B1E6 -:10AEF0006E99C0FBB1AB15B413EF7B2D80FB70BF17 -:10AF00006C5C8FF90FA6A283DD7897F79D9390A7CD -:10AF10003CD95DA50957203D887F4A24F15EEC9F0E -:10AF2000D99D7B28FE900F8C5B17F4DBC1FC18C207 -:10AF3000F39CEFDAA263DE8C4ED8FD4D83AD0AE6BA -:10AF4000298DD535B4C178F7B5AA6877DC774D433C -:10AF500037E673B77A31F7ADDAAF0B90DF135CA742 -:10AF600010F810A43AAC7783DD1958EB853BBF4845 -:10AF7000751D1B2FB08CE03D7F2E928EC768191C6B -:10AF800052F01EA7FBAED996DD09764D2BCB5FA6FE -:10AF900084BD145B4B889FB392483F24808F6B1114 -:10AFA0003BCFB7E639989E695FF21C3198A9102E05 -:10AFB0005B195C6048C6FCE4B270E90AE13215C274 -:10AFC00065195CD9F37B9E4FA9D27F1087F338F3C4 -:10AFD000B1FDA5BF8B3BD77CDD31AF3DEFBA5C7BCC -:10AFE0002B4FB71CBD70983983A7541EDECAB32BF4 -:10AFF000F6DE35FFCE087C97365873372FEF616544 -:10B000002D7F5EBB2782F745D6F2F7B5F7E0FD91BD -:10B01000CE7EFE0BD7C74D245E721EAA39FE6F503E -:10B02000DC219EDD2497C90770E6FB39F49E2AA730 -:10B03000DA71DD5EC3F28B66BE9FACE3DF8D906498 -:10B040003C86F12C33B872FEECFA716DFC3EAE1FFB -:10B05000EBBB493A3FEC7B49879C38E5C2EDC84FD2 -:10B06000B9503979E53D9213D79054D1FA71A52B97 -:10B0700084CB540897AD0C4E19122AD22B4ABA42EF -:10B08000B84C85705906D7BF5EE1FBFA703FC4B774 -:10B090005C97ABB67AFFE55EFBFB0D7E5B7D608D5A -:10B0A000BDBDB2D6DE7E60ADBDBDB28EB5377C878C -:10B0B000AE4AC52A5F27FFEB3CD749935A1A3ED0C8 -:10B0C0005A665DA99A07DA57CB3A81FB85E87E95E7 -:10B0D000E1FB56C1F8CF561F5BFF577B35DBFD7494 -:10B0E0007FE97436F918BE16BDE5F0B5F4EF3F4AB6 -:10B0F000DCEE2A92771F029D538B8F17417FC78EFC -:10B10000BDB510ECCA675F5F87F79AF67ED0CA9B21 -:10B1100031301F523EE9FD38E8AD67E97E0BF93862 -:10B120001321E3F82560CF044402F63275A3F05EE4 -:10B130008F678FCA687FF43E57DAEF7FA68BE509E9 -:10B140003D0D7E3FD5FF47F8BD5B4FF27BB71EEF4D -:10B15000D2B11CEF6AC2F7992E03EB0F77B562F9F3 -:10B16000509789CF1FECEAC0FAE1AE38D6EFEFEA8C -:10B17000C4F2DEAE0496FBBB7663B9AF2B89E570F3 -:10B18000D71E2C07BB522C6FB36B887FBF96C6F2BD -:10B19000D2EF4C8D5C0276925FC4EFC08AE1BF6251 -:10B1A000C21E77B8E4883DEEB03C638F372C3B6C11 -:10B1B0008F372C4937D8DE370E5D6C7B1F4DADB213 -:10B1C000D52FDA73B90DBE3ED96EAB2FDAFD7E1BDB -:10B1D0007C6D629B3D1FACF3061BBCB67187ED7D99 -:10B1E000B0E5AF6D757FF31D36786FEC6E5B1DEECD -:10B1F0007DCE87BFD6D7C0E281E1111B9CEC3F68B2 -:10B2000083DB35DF7CC4B706F2F183685F3EFBAABF -:10B2100080F95DF3161BAF03DFC92B12CA13B99275 -:10B22000E5C3CF6B485E06F7941139B9EEBA40F921 -:10B230007BA4AD788F146C4D80BC9E795DD0C1DE4F -:10B2400015827B964D1690C7DDA7936402E2923C6F -:10B25000CFAC7121314DDACE4BF5091E2E926476BA -:10B260002FC62D45FC8EEA312181F926D46636FEA3 -:10B27000B30679F4CEFD77C3CF7787F17E04B4CBE4 -:10B28000DB0EB44E0D51F8F1150ADE7733075FC7B8 -:10B29000FD76BFF5313F78DF5E16AF6C7C7E7D8337 -:10B2A0000A76784B621EB8AA337A23FB33FC4E2908 -:10B2B000A01B6BE10A80402C4D763603DC0913E2BB -:10B2C000B614FE6BBEBCF1028F9F4879E9F3E547E7 -:10B2D000128DF0D9C4F85E162F1D1F5E2ADE4AC7F4 -:10B2E00069C82E1797A2BFF324BBD77D48176FA557 -:10B2F0007AA1E1505CDC5A806FE37F2A1C4F9DF4F9 -:10B3000049D87EBC3B83F7CB79B3DFC47B38AD79BA -:10B31000F135EB6202FA3D9C10C15E1BDFCBBED360 -:10B320001B17A20B239CCE6E079D8017A58BDC0AF2 -:10B33000E5434971AB9F3D6F0CCCF60BEF77C2FB39 -:10B340004C4ADCE2AF887FA6179E3FCEF9772423D4 -:10B3500096E49F7EC2047EAB31CA3FBD14FFEE6708 -:10B36000FCA37CBBD53F975F33F0295D5CDB9CC7BA -:10B370006FDE1EF8726B01BECEF089B64F60FBA87F -:10B38000B89A8F0B7C68A074EF2CD44E88F271327F -:10B39000F671281F6FCD8BA7C39F3F2F4FC48287A5 -:10B3A000BF8EB53C4F91D2ED9A0CED84EFAFDB9A96 -:10B3B00013780F70BF5FC4FB85FAFD5FCDE23DFDE2 -:10B3C0001A41BD29CB66CF4FC22C0EDD23145AA7DC -:10B3D000763F01BE4CC9FF9EACCF6FE5E197B197B8 -:10B3E000F8BDC212BF575891E31D51B69E8D6E3203 -:10B3F0001B5F9D3BFE41A45B8AD8F7DFBE5DF67DF7 -:10B400002FA6DD8071ECDE7065DF0DB973CCBE5404 -:10B41000383EAE9C8FDD779CF3209E666E1E969B19 -:10B4200073212CAFC82DC2F79B72B558DF986BC43F -:10B43000FA865C14CBCB7397E0F3F5B9E5586FCD82 -:10B44000ADC6725D6E253E5F9BDB80F535B9F55864 -:10B450006FC96DC17275AE0DCB55B90FE0FB95B9D3 -:10B46000ABB16EE4AEC37279EE5A2C9B721FC7F774 -:10B47000CB72D7637D696E27D697E46EC67A2CF7B8 -:10B4800029AC37E63E896543EEDF6319CD7D1ADFCF -:10B49000EBB9CF62FDA2DC67B0BE38D78BF5FA5CA2 -:10B4A00037D6EB72FBB0BE28378CE5C2DC7D58D6B0 -:10B4B000E6C6F0FD82DC0358CECF3D86CF43B947C8 -:10B4C000B1D4725FE2F7453F856530F7352C03B99B -:10B4D000AFE07B7FEEDB58F7E5BE89A537F7029634 -:10B4E0006AEE1896E5E6A9DCF74F9BC93C9B5C6CBD -:10B4F000CA2DB4D5374CDBF7EFF5BFBAD8565F3756 -:10B50000B9CA565F73F2725BFFAB4FD8F7EF95C7BE -:10B51000DF6FB71FB2F6FD7B59E606BBFD7078877B -:10B52000DD7E48FFB5AD1E1DBAC36E3FA4ECFB77B0 -:10B53000FD1EFBFEBD283962B71F761FB4C12F2048 -:10B540000F3AF2C9C76DF055E6D336F840EB571DF8 -:10B55000E72B19A6FF8D6FD99EAB4DCF173C87897E -:10B560001DBA1ABFDB3F5D27F27B86F8BDADFC7EBE -:10B5700034E77C56733D302FC7FCA7305F7735B07A -:10B58000EEF2F29EC0CE88E6D919F31AF4AFBC48A9 -:10B59000EB67162B4637AD5B7686055FF6772B1487 -:10B5A000633245F174BDEAC67BE78460A70971B5D3 -:10B5B000BBA604DCEFAB17119E1FD1D1C1E213C4AF -:10B5C000BA4F07EFF719ACB7DEEF7C1FBE8FB2FAA8 -:10B5D00071FFDEAD10471D7459EFBFF43E8C7378D8 -:10B5E00058FDBFFB770DC0FBEAAA8908ECB3FB8AC4 -:10B5F0009C6FFE4FBFC2EC7DBFF923FF9AD97BA69B -:10B600005F09275EF2D3E7B7A9898BE0CA6EB8E776 -:10B610001EEE71DE2A9B3F01B86B65F3653FEE0BB2 -:10B6200076FFE15AC87D5D83F702FE0CDE4BC1A3B5 -:10B6300098DF5FFD817BF0BEAAC100C5C75F1C9F7C -:10B64000FFE69766F61B62ED370D184F457B7020BD -:10B650004AF0DE8CC1503C05F7F9A5BEA792270C35 -:10B66000A03BCD9295787EE2E072DD920BDBFE444A -:10B67000483C0B717C5FC2AF83BDE6272730FF22B9 -:10B6800048A6B1D48826D8EEDBB6E8AF67F4C3FD90 -:10B69000FF7E3C87378F4E629C3549F8FDD56FC1E0 -:10B6A00073CA9733FE35C5F97295740FD1E8F80F58 -:10B6B000537B12E87898307CF773FF5426C97823BF -:10B6C0008FF7E4DF2321BFFA4D941B2BDE234B1BA6 -:10B6D0003BF07A177E8F4307FD07F6614DBC74BCC3 -:10B6E000C7796FC3B9C67BC20167BCC78FE7C9A75B -:10B6F0009B4B7F0767C57DF63797BEB732C3FDBE4C -:10B7000087F979EF43FCBCF741EEF71DE67EDFFDDC -:10B71000E0F7E1BD5ACCEF3B007EDF32382F366DCB -:10B72000DF978C16B9FF251A12B89CED41FBDEC7D6 -:10B73000EF2BA29E2BDAF35E6ECFF7FA7BE6C3FD0A -:10B740000CBE10C9809FB0FBEA71FC7E969262C06D -:10B75000FD00B7FFFA8DF9FF8ED6631162BBDFC91A -:10B76000DBECB82FA1DC3872C6847E7DD46F481B19 -:10B77000C5F973CEFDAA19E239AF7ED93D3FD6BDDA -:10B780006DD4034F81FCF9806E0DE4EADB38CE699D -:10B790003E0E91361EC7FB0C2F934929399833CEA4 -:10B7A00039CADFAE80E3F7291CF2A7CBA407EFA9C3 -:10B7B000E1DF43EA7EC39B1F5FB1E4B0B799C51FC9 -:10B7C000BA5FFF18FE6EC08B355B17E6FB7FD6773E -:10B7D0004ABD2D0C8E5A7DB8CEF7779FD43FA9CFA6 -:10B7E000C23D65C169A5E3194F5870A30C2ED06204 -:10B7F0008885EEEFFB22DF4FBEEC3353819AD9717F -:10B80000F59E8E1B504FAC51F17CC6D9EECBBEC419 -:10B8100050202F3FC1EA3FBF3DC85789F6E952ED9E -:10B8200017DFDDF17352BAFDE1C09AE2EDEBEEE80D -:10B8300078B00CFE99C2E3A71EC173A608FBDDB267 -:10B84000EE5AA501FCE57D6BA8BF4CE7E1C5155B91 -:10B85000F15ED9BED02B7A2139A2FD7EA9145E9467 -:10B860002F9D65E8FA5AB9F64269BABE5D86AF27E0 -:10B87000CBF0E58552ED295F0F97C1FFBF16C63F9C -:10B880007511E01DA863F1BAEE7ACA57F0D7D6B0A9 -:10B890003884B51E1E1F2BCAD757CAF0A59CBCFE04 -:10B8A000E202E5F58D52E35720AFFF5486AFE5E4A1 -:10B8B000F5AD62F28AE7A4E72FAF42F0C2E4D513F8 -:10B8C0002CCDD772F21A2AD5BE0279AD2D857F050F -:10B8D000F21A2D34BE9B508508F67E333B17DBDD14 -:10B8E000C6EE237335B17DD7F7EA17D13EEAA3FB45 -:10B8F000D3BC56D8A7A7EEBFBD65765F76EE3BCE2C -:10B90000FE9CFBE6EDFFFB49DC37037CBFB3F0F1A7 -:10B91000E8CE7E4ADF6771AEE37AE17798F27EDFA8 -:10B92000E2E2C7EDDFAD5EF878F67DDDDB42C7A76A -:10B93000EF091D7F0B9E233E83E7884B0F5DE8B820 -:10B94000A5E19B1E727C8F7B8E76C02D41BB1DDADC -:10B95000B0E76B8FE0FD23BC9F06D9C4DFED93C930 -:10B9600095ECBE9321962F24EDF9CA23A756E7DD67 -:10B970002B4574313F3F481A9A78E4541E1D39888C -:10B98000F7B0F832E62DC6B4CBD19E181C2D6DC78A -:10B990007E99EFE3CFF0F38BA7B91D7B84E72D3EB3 -:10B9A0000976EC3238C760E717E360C7629E632B05 -:10B9B000CF7334799E630796CFF1F3876F751DC6F9 -:10B9C000F747BB32587EA3EB08965FEF9AC0F75F4C -:10B9D000ED3A8AF589AE2CB38757DE897A66960EE2 -:10B9E00067DCAA341D971DB5C741564CD8CF312E00 -:10B9F00039623FC7589EB19F632C3B6C8F832C49A3 -:10BA0000DBCF311A87ECE718BE26FB398647B7C76C -:10BA100041DC91F73BCE41B639CE41ECE718F54910 -:10BA2000FB39C6A2DDF638486DC27E8EB1A0F36E3A -:10BA30001B7CC8ECB17F17DF6A8F836C9AB69F5F5F -:10BA40006CF8D583F6B8CFA43D0EB2EEA43D0EB28D -:10BA5000E6C4576DF5D5C7EDF18F0FFB122F823E6F -:10BA60005D9975C641264598BF9FFBD9F99FE55F53 -:10BA700053F81F80FEBC4AF2673750B97FEC28BBF1 -:10BA8000DFFD31C2CE3309F90FE82FC833FE8289BA -:10BA9000FA47E2FA67ECCAA957C09F91F7337FE7EC -:10BAA00076615D56CDF7775CFF28E4AF6B4973FA9A -:10BAB0000D65FA970DF473E432FEC8DC7E99DE9AC8 -:10BAC000BDDFBC25057954F28C3FF201873F523728 -:10BAD0008CBF6335AFB43F32679C73D4436F058B23 -:10BAE000F8C31111F967F923FB5AB83F42D87752CE -:10BAF000567F961E1A8B945E87D63D2D63DC6F9120 -:10BB0000FD85CFB1AD7C99B196CAF2BA7F1064E7DA -:10BB100049149AFBC3FF5F3EDE4DF9B8BCAA88BF4B -:10BB2000FA1ECB4731B873950F197406C6236F19E7 -:10BB300084EF985C50BF7CB6AEF07AF0DEDBB642A4 -:10BB40005EC81EC2CE75C8CBECBED57278C436DED8 -:10BB50005432FFC18AAFFE496379BBB1D69B306FC7 -:10BB6000F2341DA3D47DDACE3C0B299C841FDB83E9 -:10BB7000EFD80B9EF7FCB49AE593C73A3F51D26ECB -:10BB800071FE1E58CC2C7DBFEE30C7FF85D716A0A6 -:10BB9000BDBA6F88E963B973C5F3208F8F833C1AF0 -:10BBA000184F5197035D4332DEA7E6D709C6051744 -:10BBB000FB49A63B0A7C3552708F17FDC373E5190C -:10BBC000F91CB2DB51672C3EC54BF3B5ECEF19AC59 -:10BBD000D7312F4DD649520BE1FA216F84113F5CCA -:10BBE000B783AD06FBDD3B8A8FA6CD6DEFC4CBB925 -:10BBF0003EE55D57603CA941B0D6A7CF803C9DD3C0 -:10BC00007E7FC97BDEE6F47B8EEBF19939EBF19A0E -:10BC10009E9FC2B8A32C7E44F6D0BFBC734E677FF4 -:10BC2000D67AB4EA2FBC76177ED732387A07BBAF04 -:10BC3000B88EDF0B36CAF46331BCAC78D0016E1F0E -:10BC40003E71A8BD07F8DB47D74DBE3E5AF2B71F7D -:10BC5000F126D8B96235944F1E66DF6B2F7D6017D1 -:10BC60007FBE039F1F68DDD68EFECF21620259C1C1 -:10BC7000F5A754F67E4A43F8F0F471B81769299590 -:10BC8000378885DFBBB1C584DFA8AC0A89ED504A8F -:10BC9000A393A877492B3197E830AE8CBF9FB33878 -:10BCA000451E057C168F2646403E499A18F0BE2A4E -:10BCB0001CDF763585AFA282095756A7087BBF38AF -:10BCC000A9E1FCC5461307AF06F86682BFCB45DF86 -:10BCD00063BD6EB786F93FBED1C921B8F79A8EC150 -:10BCE000DFD33A7DBF30C1DA074627D35BD02F9927 -:10BCF000799FDED202F70EB2F7F228A507DE4718C9 -:10BD00003E29327D02DECF0FB3F7CA28DB1FEFDDFD -:10BD1000B803EFD3A3E3E37D532EFEFC31CEFF58EF -:10BD2000E73B27601C2B1F2345E2B67BA99CEBDE7B -:10BD3000FAFDBF5E6EC7FBD4455F3895771FC33EE3 -:10BD40007E5FB577D4BE3FFFB18AEDB3C7B89E29F9 -:10BD5000772F1B247A839CFF0B555919960080007E -:10BD6000000000001F8B080000000000000BC53D14 -:10BD70000B7854D599E7DEB9F3CA4CC29D300993CC -:10BD80009099DC840422043A814041512711111515 -:10BD90006D44DB066B7508C8FB11514BB4DADC90BF -:10BDA00004921060B0AE44E43189A2A8A08382D28C -:10BDB00096DA01B3145DBB4DAD456AD146D0A808F3 -:10BDC0003452517657D7FDFFFFDC4BE64E2689D61D -:10BDD000ED6EBE4F0FE79EF7FF3EFFF9CF19C61875 -:10BDE000FB2A17FE5795C4A2058CFE285F99CAA2AC -:10BDF000B698FCFC4C637930D7982F1F69CC7BC672 -:10BE00001ADBBB2F36947F7E1D631D4EC8487E1BF8 -:10BE100083543A7AB3AD6C3463B5EEE5943F7FBB9F -:10BE20005E1E48C27C9E7CD28EE58F5555D8582127 -:10BE300063AB3C330605E1FB57F87779EFB4A19A81 -:10BE4000B1A895B135D5214A9BAA5B286D2E6222F7 -:10BE50002B666CED6831DC96C3D8EAC219D45FBD9D -:10BE6000BBFFFEDAB0BF118C85AB6D946EAD96A9A9 -:10BE7000BFCDD51E4A6BAB154A37551750DA52ED78 -:10BE8000A77A0F554FA434541DA0745DF5342A7F52 -:10BE9000BEBA8CF2BBABCB297DB63A48DF7755CF23 -:10BEA000A7F4E9EA4A4A9FACAEA2F4896A95D2EDBA -:10BEB000D50D94AAB2C8581AACE74A7F6619CCFFD0 -:10BEC000D12B5979A4B0F7BC5559E0F56480E578D9 -:10BED000C6925828CADC882FE84B61CCDE10623647 -:10BEE0008047E662F886F9AA10B342DE3387E7D7C7 -:10BEF000E138D0AE8AB100C28D15B0F076809B4D8E -:10BF000009B159305EC0ABB21B92199BAE8D83DF75 -:10BF1000118E6A8ECA105F272C81EBE434EC8751B6 -:10BF200079FEFE8E8388D6311D91524C0B0F8744CB -:10BF300009D291532A579A201D345915B1FD2A8FE1 -:10BF4000582AC078E7AAC4B009BA568AD94113E47E -:10BF50001F2B14C34D307E73091345C46306E05193 -:10BF6000E8596FD2F9AD2C3A0EF05A3563104B00F8 -:10BF70000F3D1D3A5FECA147F82F2398D443AFF053 -:10BF8000DFEA50FFEDC7EC110DF50B77C6B52F8436 -:10BF9000F6FDD0D3C8C78CED0B362719E6B3DAD33C -:10BFA000FFF8F9E7AFA775F645B7A72C153F43B8DB -:10BFB000EBF9F4F397B1E860C6DE72CA84CFD46BB4 -:10BFC000EFF3040B69B82926A007298B859B04CCC5 -:10BFD00006D86C80AB19FED524F33CC2DD04486A58 -:10BFE000F223BB2A019682A93FC0C6601AA0FC2199 -:10BFF00073B0591E8FF932FE5D0E121D345F045D61 -:10C000005C8CFD6437042643FEFBF0CF4CC6AE0FBC -:10C010005D344D85FCE7E6A05805E3AFF5727E5C24 -:10C02000E11B9B84EB7EB4B97F7EACD5F851CF9BEE -:10C030009C0126403FB90DF258A4A3BEDA3DD8209A -:10C040004E0B27E8F729A45F987F7DC30C391F5753 -:10C05000DD8E328B31AB9311BDC5D787F53E85F0B0 -:10C0600035BBF93AD36E2AA3346FE7245B19F0C3CA -:10C07000E7C9FDE3AF316EFE76183292605E1F6A4B -:10C08000F3CA7BED17241F3F1FDD3F5DE972EF7C94 -:10C0900058641D885FA98CE469DA4D419607EB5915 -:10C0A0000DFCE244B9F7E58D0D3980577583487270 -:10C0B000409F7FFCB826A5B34484F2D5071630050F -:10C0C000C6377BCA985A88795D3E4718F6EF707676 -:10C0D0000470BD0E160A98A07F475550C5EF168F05 -:10C0E000CA90CE56675CA84FF2764D481411BEAB8D -:10C0F000B2C4301328654EE4F76246F9E48CE702D7 -:10C100002292CD17309F09D00FFEDB84F05699881C -:10C11000EBC8677E27CCCB56D01D10A17E1EDB1747 -:10C120004579602B61FE26E49F8C2301A45BF50E0C -:10C13000E6CF27320F923C6252D086F22AB7650CC6 -:10C14000F1834D8908B8EE1F5882EFC5F28BC5C345 -:10C15000E5D8EA2F4D09E5EABF6A7231A90FBC396B -:10C160005CBCFC73B3720DE91BC8B725A023B38B6D -:10C17000CBF13679C6EF0B941EBED4CBDFC2458E11 -:10C18000EFC9E79EB7D0BCF36EFAF1205C4F5F7445 -:10C19000B04AA3AFF583B8DCCD9B7C6900E17D0E8E -:10C1A000E6DA24F4AEBF609042F5F4BCE434CAC7CA -:10C1B000AF3F3F89E452DEA97B381F78FBA7577D4C -:10C1C0009E9F7B8DF6809867233D5D1F12492ED57B -:10C1D000BA459602F9AD481F3928303BED17C17AB0 -:10C1E0006C6F9818E27B6B55A9A84279728E142661 -:10C1F000FAF37447519CD9257600E903F0ABB8D225 -:10C2000010EF13087E59C51101E9FA94A617E1AFA2 -:10C21000CE0374E6E34B46FE1EE182EF819D02975A -:10C22000031E2E07CCCCAF5A717CD0881118CFF1E9 -:10C230008689BE331689DE0FF92459F4A3DC5C5BD2 -:10C24000BC321DF9CDE162A4BFE65FDD46F209E430 -:10C25000AA7F13C8D1A51F75A52F837C9E87CB5DB0 -:10C260001D1E498516835E18701C291C403DE9106F -:10C27000983FE4EF1BCEDFB85F5B98D9FFA17E410A -:10C2800061A4135F687F3B549A1FAE1BFAB5B25F7F -:10C29000D138E7B47198E9D861846FD27724664ABF -:10C2A000C01F7D8E63BAA55FFD50756CC1EFDB6367 -:10C2B000E8F73657B2BB6B14FCE3BBECBB5FA18263 -:10C2C000303989BECE813D81E32A367610F375CDB3 -:10C2D0006238117F7C5E3DFFF7ED80BCB59A5EAFA2 -:10C2E00079D75A4AF4395E0C5BA17E7BDAD4CCCE86 -:10C2F00018BED0E5706D31D70340DD0CF9616DCD0E -:10C30000516581D253EF49BD9EDCBFBED8AED76B1D -:10C31000E6F5928BFD623041FD27347E7AC611B876 -:10C32000CF35BE675C65E5B49B490E8DB73153824E -:10C33000F53DE308D6B962F858EF3FB63DD26F3FFE -:10C34000ED9B5D697DB7F7DD3BED2DD67FFB07FBF0 -:10C350006B9FB57CDAA601E6BF39F1FCD56DD82E0E -:10C36000D9636148E7351996DC06C8AF196FF15BF0 -:10C37000010FEDA3A77A106F75AE234A227A827E51 -:10C380009FE86F5E0097F201D6F5EC00702D17FA6A -:10C390005FD78BFDB507B81E1D002EBF1900AE2D4F -:10C3A00003CCFFB789DBABD938EFE42C0BE9931A48 -:10C3B0002FC0D58DFC0070653DFCF0D8863EE1FABB -:10C3C000FA40F436C0BADE1A002F03D1EBF101E0D7 -:10C3D0003A10BD9EFC96F47AB60FB86EC3797F0B07 -:10C3E0007AFDF25BD2AB39F5DBD16B726AFF72601A -:10C3F000207A4DEBAFFDD7A0576FA2F95B9923A030 -:10C40000A2FD53C8F5F8FC1291F4BAB980EB5FC7EE -:10C41000B127488FD6819E1A3C11F5F5F187961603 -:10C42000F7E8E778FD13DF5FBCFE5CFAC9E3CC8E6A -:10C4300078D4F49E3E1FBB12DFCF8FFAB5E3BEE97E -:10C44000B8491E16B58FE9693FF2318BC18EFBF6F4 -:10C45000E319F57B52318C8FFE0418FF8A89A857A7 -:10C4600077FA912E873FF86DC7EDBF7EC16663FFF7 -:10C47000DFD41E98950AF680A3C71EC8AD7A7EDB6E -:10C480007B837BFAC995024C06BA91D814B2DB586B -:10C4900003F36FC7E2AADDDBDE1BD7630F0047881B -:10C4A000B89FD0C7313544B6BD17B38EF37398B675 -:10C4B0000FABA47D4F9E7C7112D2F1EAE6FEEDE255 -:10C4C00067343DBE53F3373D85FE264877A0BF094C -:10C4D000D2C7D1DF04E963E86F1A81FE29EE6F6AE3 -:10C4E000427F9315ED0FEE6F5A85FE2648F7A31F86 -:10C4F0000CD25F6A7EB07DD5614A5FA8DE41E99EBD -:10C50000EA08953F57BD8FF291EA28E59B8B7E4262 -:10C5100072A6671DDC3ECF93757F5DFFEBF8CE3EC4 -:10C52000E33E6274C4E82719B523D590BF289C69FF -:10C53000A83FA225D7509E1F1A69281FD630D69033 -:10C5400077145C6CA86F574A8D74E5B9C6503F47A5 -:10C550009D61C86757DD6CA8EFADAC30940F9DBFEF -:10C56000D0509E115C6EC80F29BFD750DF15586997 -:10C57000281F34B1C9507E69F70386FC251F6E322F -:10C58000D49FD4D96628FFEED1A70CE5E33B9E33B8 -:10C59000E4C71DFEA5A1FEF71CC128CAC3A2E8413D -:10C5A00023BFB04E11F1D79EC268FF6387FD7B2089 -:10C5B000813DF95F83F83ED6CA4691BD7B0EE459B2 -:10C5C0005311B6AF0CE1FE3A17CA9A14DC9A8705EC -:10C5D000368CA1AF286A4F89E5876F260770A78F31 -:10C5E000F57DF0877CF95FFAFE75875DBD0CC7CFDE -:10C5F000E3F2589555D207F1ED75BF50DE8E998361 -:10C60000B0BC4E2E9513C9851396E089583D11BFD5 -:10C61000DFCD0B24B3008ED7A0FBC5B8DC33F12AE5 -:10C620002CF7D8558705F483958F49C5F5E8FE9C0E -:10C63000D51ABFD66B7C6A6597A8E8AF38A7EDFB23 -:10C640009869B2BF3F39150FAF6F2AD7BE488DDF4B -:10C65000E74C8FBE8FE33748E144FA524F75799625 -:10C66000F7C66DFDE24787AF8E4793DC1140FD6A48 -:10C67000532A5985B3379C4C599C1EFED9EB1E3A60 -:10C68000D828CFCFB1C2D240EED7586FF9ADB40E93 -:10C690001D9FF1F5D655F37D5733E295CE1164CD4C -:10C6A000DFCFF12B4E0CAC44F8A6C03E1AFD02A21F -:10C6B0003FCA3A13CC7BD044237D25FB8D72D051E9 -:10C6C00060948392D32807CDFE4A16413F2D8CC338 -:10C6D000881E830CFDB6F81FF19F3C10DF5D121021 -:10C6E00062E87020FEC321BE1A3630BFFEA3FCDD17 -:10C6F0003E279DFABF47E36FE0689EAAEC75A49FB2 -:10C700008A891A0131E5877F81792F386C263FCFDE -:10C71000E55F6C3BB405FDD113AD32FAA3190B1DD7 -:10C72000FA3594CF09D8CA30BFE0D8688B0FCA8FCA -:10C7300064021178B0BC2C05E5C069264E433FDD8C -:10C7400069F67ACAB81839B764B085FB7F1ACCC7C6 -:10C750003B6D38BC4AE753B787785E5FD7BC16633A -:10C760007E2E9B912EC138731F34A3E4630B987403 -:10C77000BC538703D0C18F07CBB49E79AC72950CA4 -:10C78000E3D69BF9F9CC9217475B100F0BC6C9395A -:10C79000A6A29E79DC3D98FB014F02BD29D69EEFF3 -:10C7A0000B9D610BCAE5137BC6FDE01286FD845725 -:10C7B00065A25FD305F688D21BBEB31B8CF31C6841 -:10C7C0001DF1F3666C25C1A3AF79483B844022FF7D -:10C7D00079ED60C180C75ADBCFB675C23C03B51294 -:10C7E000B35F0679899F1FA9C792C3DB517E975615 -:10C7F0003ED1097050575AE55A48373A7EF62CD642 -:10C80000AF0284E1F9D3CEC10AF79FDA7D613C5FC4 -:10C81000007DF3DD19C9DFBEDFDDFFA47E5FC07ED2 -:10C82000D37AF7BBC4D669C173B46552E5344144C9 -:10C83000BF22AF6735070343D19FB8AF283A5431C1 -:10C84000D46BF89AF50E0BB95FABDE34B19FFECE18 -:10C8500068F2EDB73B1FB5A0DC3AFDD4BBD7E3BE11 -:10C8600068D1AF4CCC06F5CEEC4C6651B2FBC2168B -:10C87000B45F17EE3105C2948F4EB8313996AF6B65 -:10C88000A9FF45CF26D3BE6AE173D6F07468BFF026 -:10C8900085136318C883332BBB0F0D45F83D2590D6 -:10C8A0001DCDD4CE3137C2F78512BBAD2C81DDF161 -:10C8B000678D1F4EFDC2518EF426EC38702BF51B90 -:10C8C000F9A1D91AA3C73A069B099F508FFCDBEA4E -:10C8D0009342385FE0F3BB6174ECFC6A78BD27B922 -:10C8E0003F77E13E73D88EF3DBD16A0942BD653BE9 -:10C8F0003E21FABEE2D95D29088765FB4C06B9B630 -:10C90000E8D92F575D0C785E6462DDD3498F7F4193 -:10C91000F973015BB789E450204500B9B59444161A -:10C92000D47BFE83A97F81F2931E13B3832838D969 -:10C93000F1BEE557980F3A2B991FFB37F2E1B21D74 -:10C94000272C382F5964DD59C0E8977D1AC397AC5E -:10C95000777DC6BA2D286797451A3F3101BD2DDB7B -:10C9600073FA2DA4BB6571FC7C12FF91D15B5F0A49 -:10C97000EE787DF9DA0486E7F43B601334A96F7D25 -:10C98000A9F3F7A25DE7B6AA30FEA9E73EDEAA0248 -:10C99000CA17FFF7DFB7FE14F7492FD965944BCBC1 -:10C9A0009EFA530A8B817F969B9F279D79F289C7B8 -:10C9B00037011CCEFCD94A503BF3EB0F7C0AC0FD7B -:10C9C000CCEEFF48C7F3A5BB7E7DE510A4B3BBF654 -:10C9D0005E31A4BF7D05D26DD81A8BDF30F5AFEC88 -:10C9E0008371864076BF96C6E1E5D4EECF2D784EB2 -:10C9F000F499C0BA51FE2E8D7C6941FBEC508075D4 -:10CA0000239C5EDE73E2D0BD903F0D78B226C0134A -:10CA1000AC7FA8487A253A14F5CBD23D377EEFD2C9 -:10CA2000624CCD7E05F1C4BA49DEF7C2EF1B80DF50 -:10CA3000E21EFCC6979F635F5810FECB76023EC78E -:10CA4000205E019F637AE3F334FE63526F7C5ED213 -:10CA50000B9F8BB76DC2C23D8309FF7DE173C9DEB9 -:10CA6000EFF76B67E9F2612038CF17F8BCACEEC086 -:10CA7000B56EE4B3E71CAA87E3393C1DCACEEC3A95 -:10CA8000E74367C887E6EE5B110EDDBFB6CA786E76 -:10CA9000BFF0D76F12DF9DD9FB070BE21FFE528458 -:10CAA00009906717FE5E67905FCA6D70B684754F18 -:10CAB0007DAB1853D6ADFA097F943F047C48F80843 -:10CAC000DF304D41F91B4EA3752F0D73FE581A3EF2 -:10CAD000709330A637DCEBDDA276FED3835761225C -:10CAE000E2F3DDA9487F7DE1535FBF8CEBFF2E941D -:10CAF0003F66E4DFF8FA4B815F717FD40BBFE1033F -:10CB0000FF8EE99956AB24802D7406ED04676FBC47 -:10CB1000F7C09FEBE76F6A1F57C7D187DE5E87D3E9 -:10CB200040FC3ED0FABE29FC96B815031DE9703CC6 -:10CB3000F545627DF088263F96B2CA6999C37AEBC3 -:10CB400033132B53870A3DF35D1531919C3FB5C3D9 -:10CB500044E733F1F262299EDB2618E74937B763D1 -:10CB600096EE3B3006E5DAA983BFD0E892D3FDD23A -:10CB70009DEF5A544D3F8463E5731FE7C0CF6BF3BD -:10CB80005EB63F717FCB767E92B0BF9352E087381E -:10CB9000FF931D66A642172723A684710B5BDC66F4 -:10CBA00083DDB52A79C2D141B82F48495270DDB52D -:10CBB0002B036FE2B9A8FABA99CEF999E4FFD00A2B -:10CBC000E5B5C9490AFAF36A53E63225468FD7C557 -:10CBD000C149F294D1F99DE42E2BE67BBAB0E1BCB9 -:10CBE000D70C04113B6FD0BB59A897DE29FAC08C33 -:10CBF000EBFC6B9C1DF95789AD1A02FDFD5515FC28 -:10CC0000354AA2FD81B1FFE07D26A6C4F4BFD4DA87 -:10CC1000FD0ECE87FDC6CED02E33BD6417509E2CA0 -:10CC2000DB6AA6FDD732D85621DC3ED8620FAB9026 -:10CC3000DFF87CF5ADA897FEB6D5CAF05CE2E5BD9D -:10CC40002BBAEE41B9F488C0D09FFEB75F547F86FF -:10CC50007A79C166581DC893798EEEC7B1FDBC675D -:10CC600087B25A68FFB11099809BD9AEB4E804DC52 -:10CC70008774EDCAF0ABD4CF8B4BB1DF33CF3AA87A -:10CC8000DF33BF7993C639F39B64D26BFAFCC1DE04 -:10CC90005662F538D8DBCA053E207B3B260FE32CD5 -:10CCA000C23CAF2F7CA5C93C947F8B3005BA5FB4E2 -:10CCB0006F5000FDBB31F5A89F65D6EE9FF869FF68 -:10CCC000AD668AB4778A66223F2EDA611CFF3FDCAC -:10CCD000DCAE5A66E99ECBEB873239DF76503B4BB0 -:10CCE0009A46AF5A797C7BBDBE94966BA8A7B75F76 -:10CCF0006A659589F8C0A5F5BB68C797238CFD7157 -:10CD0000BAED3D0EFF7EB7C0C87FC276DB29EE6C60 -:10CD1000B1253A3C15F8F6050B9B8FFCBB38253A3C -:10CD2000DC05E3FD4A939B8B93200FDF33B57960DD -:10CD30007DCC335BE719C4EB9217ED74AEB2E4859A -:10CD4000373F437C9E421803C64EA5757CF653A020 -:10CD500083535B4C4C057B6D8935EA7B04F5D46EBF -:10CD60002B6B43FE7EE915D25BA79FB38AFD9D53D3 -:10CD70002F890035D87AAF432D6505954E8CB709BC -:10CD800088ADB86F386C0AD7C0D8555260E5B3B8D3 -:10CD9000BEC366DA679C9DC30A705F799665FA55D3 -:10CDA000C2BFF2A604E52B5E350B89E290CCE741C9 -:10CDB000A88F033E387F2D532095CE0FA37485A5F1 -:10CDC0007204CA5D930C8B2B243F01D9ED66B79F8B -:10CDD000CD8374452A0B22FC98F39A0BFCF57B401B -:10CDE000E9F2879521D86E521A972B73D20357A672 -:10CDF000917C71CAE457D2E854DDCBE7F9B990E4ED -:10CE0000AF8179E59DBFF73684EFF2770525F6FC13 -:10CE10003C3ECEB34A52DE548A69BD248FF2E424EC -:10CE200086703D2BF3B8BEB3739441AE18B9BCA65F -:10CE30005A26F9D158EDA17475750153C8BFE6A7FC -:10CE4000BC495BBFB550A53835E469FCB33ACB02A9 -:10CE500068E7E19CF2153CEE0F121D593D95E49BED -:10CE6000B23919ED634D4E95CD83D4ECE4F03139F0 -:10CE7000CB083E162D2FB54C2778427BFA7E797A67 -:10CE80007011C2C39635D220972CEEB1867C2F78D4 -:10CE9000E9F8DFF57F053746706AACB651BABA7A61 -:10CEA00022C1ABBE3A40F9FF07B83DC0E17631C6BA -:10CEB0005AC4C0ADD490EF136E0F03DFB863F90608 -:10CEC000E0887CC392FCDB13AC3F3E7DA81A17C7F9 -:10CED000D803D52D94EADF53FBD0DB9FA4713BA090 -:10CEE0008A056BCC74BEC5FD2DCCADB2AC093DFE40 -:10CEF0004DE651998279E455C4CBD12482DDF2B755 -:10CF0000EDE43736C95257AC5C5B7E9D3204E59741 -:10CF1000A9EA517662708C1F6D7A995D21B8FA0585 -:10CF2000F4A7D66A7AB3FE02FE8C7CB0A65AA1742E -:10CF3000ADC60FEB357ED88078867CAD9F9F6F366F -:10CF40004F63A417FF05F27C1F1F65B171262E7F6A -:10CF5000246A067C938C54288D529CEF516B381FA9 -:10CF6000E3A80A19C5D1B98EDE43FE63C6221EF4BA -:10CF7000A7B934B8B1FDB9AE99C9B43C33D73BCCED -:10CF8000C4D39019EDF178B8D6FA0FDA707FDDD7F7 -:10CF90007C4ADE5920E0789FCF243431F72D91A3CD -:10CFA00015B00E67B383F46ABABF321BFD7BEC98F1 -:10CFB00095E8D3E90F0AF362F097DE875D7767FAA9 -:10CFC000D57F45FAEB4459067AE88196617684F379 -:10CFD0001A73C483F26E8D8BEB0FA51CA0F0DD9E3F -:10CFE00076AF687230A5D8C8EFBA7C95278F35D058 -:10CFF000AF2E5753A718E95C97ABCFA7717FC59C9D -:10D00000F4B24FD2201D7C7E33F1613CDDE7C917BD -:10D010009707DDA80798BF09ED35B419D18E7B5766 -:10D0200008737AE7FEA9B39D396D68E7C0AE80E466 -:10D030008A8AFC4078EA7EF92B68B74B930F2B6DF8 -:10D04000336CB8DE06A02386E77A403F08E07540DF -:10D050003F9886807E387F4CA454A74F4F7A8E210C -:10D060002ED0947748E4F1F222F99E25D8DF396179 -:10D070003CE9C0241BDA7B92D97F18E55477B218BB -:10D0800041BD59EF9C610BA0FFC6554C78FF2CB9F0 -:10D0900022BBBF3827B05BC86F2B3BFDEC388EC37B -:10D0A00018F96D4DF25886FBC45DCE8E24DCB7585E -:10D0B000D345C3BCE6A407BDE931F9D138BA862F00 -:10D0C000EC7697D64FFC7817A56B7ECB2C95056236 -:10D0D000CE2DAA74FA5654362586BF57E64F6518EA -:10D0E0007F11CFD77DCAADEDDF4E6ED56687095F64 -:10D0F000E67879E10639EEA45415659CB777CD8FB3 -:10D100008A88AE2E4DC7FDA1B3ED821D72796E02E5 -:10D11000FA3A3A7208C5675ED033B06B2E243DB33D -:10D120007122B747343DC3F5D3D96607E9A7B37376 -:10D130002A299EEA6CF31005E9EEC0BA4BC6203CE2 -:10D14000E69E6F640ACC6FDEF94994CE6FF939A57B -:10D15000152DAD40E48CD5AC9DB76E26B43BF1B037 -:10D1600089E283BAC2E3CE5441BEABD9CA4C304E39 -:10D17000D7E63BB3D12FDE05E3A07DD5B5399FE8D7 -:10D18000AB0BE046F906637D8C0B36015E2A18C7AF -:10D190000BFC2F80F5E7BE626A4D642755ACB706DD -:10D1A000129DEF5C286F496CB7D5E23F33F07F9555 -:10D1B00023105E25EFDC938DEBD5F97F452AC8233C -:10D1C00084D73B5696C81F7F79FA9573912E2F4FBF -:10D1D0000F2CE578494DE85FEBA17F3EEE0911EC9D -:10D1E0005BC24B30E506839F95FB314F68F62FB34A -:10D1F000F5519EA2B59713972F69FEF8D0FD0CEF5D -:10D2000029549621D1EBFB691383FDB480FBDF1B0E -:10D2100028FE599F0FD8A944C70CF081F2658EE60D -:10D22000EF01B87FCF02DF4FBC6212903E7AE8294F -:10D230009882768BB0E6BA95BBA0FCEF87F9FE6CBE -:10D24000C1F90D24EF8435A3374E82EF77BE6226F5 -:10D25000395FD374C9FA5B00BF9FBE66A2FCFCF3C2 -:10D2600076AAF7D1FDFE8DB740BDEEDF99C90EFF5E -:10D27000F4F09514FFF891D9E827983084F3F1F38E -:10D280001A3FCF3DBF86EC0FBD7C6EC36C8B4274E2 -:10D29000BA8EBECFC5439B4C9CFFF7FFAD44C2F393 -:10D2A0001C46F7149E7FE8866B57925E1B4BF6FE7A -:10D2B000BCB5567FA278D0E7D31583FC99D7D94C5B -:10D2C000FD32B08BDCE95A7F317264DEF9C1C407EC -:10D2D0004C5619C619CFD5E4C985F96D361BE4C97A -:10D2E00047F6C47E9097D3F93E6AEEF94B88BF7A31 -:10D2F000AFEF32FA3E571FB793F363CF7A364E4AF9 -:10D30000B49E9E754CA6FA1FB9128F7F52836F5739 -:10D31000F57C1600B95461857A4E1CFFCE55138BEF -:10D32000711DAE5421665DF35A16B140CCBAE66D5C -:10D330009E65A988E9B7070FCB0C783899BE90F0A5 -:10D3400070677AD911E49B8A35978E417A9CD7D23F -:10D3500048703E61F6FB50BE7ED072674AA238D854 -:10D3600093F1F869D1F003F66E710C7E74BCC4B70A -:10D37000EF7A7BDE6718D7D4F530376EFA82572FF5 -:10D38000BCE524869B3484E3AD0BF46D90E0A6BC31 -:10D390007014E97AADC38F74DD37FC46B1607FF05D -:10D3A000EBC37E057BE74B943B12FA68F11CB28518 -:10D3B000D3C14070EB1957A38392C4EB197B613D35 -:10D3C000554C05863D6E19880E7ECA545B3FEBB8FE -:10D3D00040073F37D0C1D88D4DD7AE847A1FA2BD4C -:10D3E00032A237FE8F5BD4948BF1DCA7C944E74AA5 -:10D3F000C793D4F49B79BE08E5F1F194D0F5784E4B -:10D40000A3E7176CCF4F991533EE070D008704F093 -:10D410001B3B4431F8A12ED04F9ECA0A27FCF3E8EB -:10D42000E78439F13DBECBD34B260C413B2594D844 -:10D430005FABA7BABC360D725ED867A2FE3CEECCDD -:10D44000FD2C0CA5F5E9C1D221E3317EF427B7A16B -:10D450003C387E5C207D5BF3F68A11A8D7E2ED04B0 -:10D46000D87F36E0B9E70A537288EC50A9721B9D49 -:10D4700083AA12DB5E8CFB94CA4DEFE5A3DFB08A72 -:10D4800052A6D9A12B4C23FD4DE497AD7C02CF4988 -:10D49000814864AC2FB14A3A3705415886F98D0E60 -:10D4A0007EEE5A25D9646B4C5CC2624D9ED757976D -:10D4B000FDFC3DF443DB5426A7637B2E3725C6EDE8 -:10D4C000AFFFC479C6E87B8B3928FB711F2AB032C5 -:10D4D000E40BB314A47B4E668FBB488DC1C3C2213D -:10D4E000DC7EB4B7B737E4407BFBEDBF93510F5AF6 -:10D4F000611CF4B3D9B2A4B3B1FE6AB33B42F7984E -:10D50000585ECC77B0AB9C859037F80160BEFDD8F3 -:10D5100085BF12FC9ECF901E6B383C26228820FDD2 -:10D52000F39C61AD2897274A75268C3B9A797B3E00 -:10D53000E537CEFE6A7867027A98B97F7507DA33E5 -:10D5400033F767CCC6F38399CEE1EF630ADB055B63 -:10D5500012B47F5960912648A7D81EA5B8C6973542 -:10D56000FF583BE663F462BB466F60E74CDB0DE9B6 -:10D570004C5BC87C47618F3F2D7EDC0D1ADFB79B6B -:10D58000236923910E601C5CC78FF787BF0FAA9F8A -:10D59000DD12095F371AF0732BEB36231C834CA680 -:10D5A000730FDDAF5BC1FC5A9ED1FEF42F8BCD6DA6 -:10D5B0004827F1FDDD12E5FDFDB81DFA83F4D6C361 -:10D5C000DDFF8A6A391891A73A584C7FFBFC871C0B -:10D5D000AC777FF170F64B36931A03574091180BD6 -:10D5E000F75EF01D547E0D1BD3379FF5C09BCF23F4 -:10D5F0001E1F9F6211F0E9234302BB906FEF1D12C3 -:10D600007806D3C5B66E9F047473C41D7C0EF34BAD -:10D610004DC1EC7480C7696F70441AC2A523F1F93B -:10D620006B3C7FE7959FDE827C736B8DC410CFAB24 -:10D63000F67EB005F9F2B419F808F6032FDFF341CE -:10D6400032D2CD1260C05879F24E553ED94F67F7AD -:10D650008CE8F7BEC93B9ABFE4558D4FF475DE8662 -:10D660000C08E3DDB6C741FB99DBAA4C17F6594815 -:10D67000EFB755F1F81026758CB9C96077D669E710 -:10D680006CBDFBC17D447C3F5DD5C16DC4F752705C -:10D6900002DADD27AAE76F43F9123F4FC5137C7BFF -:10D6A00008E9B75986B8DB39CD0BB6C5F2A15EBF24 -:10D6B000B60FF9BA7FB8B64E1B1F8F29DF29714EFE -:10D6C000A07B99F4678FDADE1562E861A0F158DE7D -:10D6D00094C005B940F7E545E64CEFDD5F7C3DBD04 -:10D6E0007F4FD515ECC4385C5FE0DC90F103CF9F31 -:10D6F000793479A6B5D3BFDB83218676A1FD8B4132 -:10D700006427EC1FCEFD0F9F6A760173C27A91C128 -:10D71000421B03FF1FEB8581E95EA67DB335615C8B -:10D72000519A47E274133954624B30BF5EFD452570 -:10D73000F675EAED1FCEA85F749391BF6B7812ED7A -:10D740006B2AAA6A699FDD08F203F541FC7C8E37DB -:10D750003DA2A01EB05B420AFA451B87A7E7AC8436 -:10D760007620D5C8EF634F0A2952EC77CD1F645F4E -:10D770001952707FDB989F49DFF5FE1A052E6775F9 -:10D78000BE68847DDF73E417F37B66605CE91BE1B0 -:10D7900069C9D0AE6D158B9A7C8C1DF4658EC27DE7 -:10D7A0006EA8DE42E77B8D0562C61CC8A7786DE4D3 -:10D7B0001F6B754567E23D5A559048BF865CCAD5D8 -:10D7C000C9E8DF5D39A403E5DFC13B2CB4DE359346 -:10D7D00044DA8F592F7E2F7405F67F17F3A35E6D01 -:10D7E0003BFF7C8B13E5F051D8CFA2DF103B0579CE -:10D7F000D436EDAC1DF773A918570774B3D91CA123 -:10D80000796DAAB152BF9B5A2DE589F0F77E864407 -:10D81000F5C34227C5070F66113BC2F58169333650 -:10D82000E641BB9C3C26E37E7E4DE1596DBF19303D -:10D83000F1F328DD8FC8ECDA79964D3BA7B2C5C667 -:10D84000173E12DA43FE43C7F4084FA789E47F8EE0 -:10D850009FC7520FF7E33926774C433DE1281699CD -:10D8600080FECD3C26E0BAE4696D748F39A780F55F -:10D87000D19EAF5B0E40FB62DE1E7D42F2D76C3F55 -:10D88000D7C3E30CD7A21F0ACAC366BF7035CC2327 -:10D890007C9D2CA84A4FBD6A0FD7AFDBA0FF28C9DB -:10D8A000D130ADCB57108922BDF9168B84A7B513A3 -:10D8B0008FD3B9C003C5BA1FD54FF3D85C73E4004A -:10D8C000DA5F9BEF6664276D46190AED365FC7C2C3 -:10D8D000FC3C8965A27CDBB4C0722D9DE71702FC7D -:10D8E000054A13CEFB4719365AB7EFBE07A2784F49 -:10D8F0003FC9CFEFDF429AB07E6D8689E6BFC91C73 -:10D90000CE40FF485F743143C387AF4AB3AB58C8BA -:10D9100083785DA7C187DD3496FB17A480121BC7EF -:10D92000D5A34FB81F03D64771AD83EB2CA48FC48A -:10D93000E9D199B8AED4020BBB2A07F98BC34D1DB0 -:10D940002DF2B833166E41FE6CBD289DE249578B0F -:10D95000610FDD132FB5D079F2C189E2CCF950BE49 -:10D96000BECE427E08C813BF8402B9ADC86F8EC94F -:10D97000A5E5F321BF41B6C808DFDA42D98E745C51 -:10D980001B106501F2EBCAF47B128CDE3128329950 -:10D99000EC0550BE2D43441F2DDB2608C4EFF58156 -:10D9A000D2D030F85E2FBB85583FC05E0DFF8BB2E2 -:10D9B000CBF67A906F020F8486291C97D20422310D -:10D9C000FA4B66D1F91873D35AFFF851BA0F556460 -:10D9D000A3FBB3DEBB42E574DFF1228B82786D3BA3 -:10D9E0003F7814ADAFCEA2203F6F10C25723DF6F38 -:10D9F000BEE3908A7E75FBFB4E8C1D66CECE4FAA91 -:10DA0000317ECC596C893BC76222CA717D5CE71BB1 -:10DA100051A2A74E21F8C764F2FF143615B8299E0B -:10DA20007902C273DDC56F15CC4D4017D0DE993E2B -:10DA300016ED65313A610CCA29AEC7982467C4E275 -:10DA4000778337F3CFE867DA5A02F3C7F1AABA6EE1 -:10DA5000A179058EFC14ED2AE7B18FBE4C3CCFD7DF -:10DA6000498F241F7344C531982E994EF6596C3D49 -:10DA700090FB8DD981BF7A00BEBB6AB8DC6FBE9DBA -:10DA8000D1BB13F8571003DFE64290D2F4000140F7 -:10DA90001EEB15CAE4475F2D2A9128C2738C8DE8CE -:10DAA00069080B925C8B5FAFE358E31D1877E4F0D5 -:10DAB0001BE77956C32FFE49E9745E819628B3644B -:10DAC000CCB1A3FCDB3D56C9C0FDF603AEC47AFE63 -:10DAD0004F197C5FB44B486C9FFF2DC3CEFB075999 -:10DAE000199D40A86214D70779319DCE6DC8C96DC4 -:10DAF00015B95C60D730D27B29459D767FCC784FB5 -:10DB00006BE3D01FF433486BC7E4EE680DACBF1570 -:10DB1000A816EFB5A578391C9D6A0F1CB1BEACAD37 -:10DB20000BF8A06644310251A6FAACCC42E72220A1 -:10DB30000DD5AFC41E38246BF5374D94041BCC2B88 -:10DB4000178021407DD7348BE11C45AE3BA262F9A2 -:10DB50004F4D4C499DD833FE9622165E09E30F0ABD -:10DB600018E19D7CD70B2BD02E8FA7039CC1857EFF -:10DB700031547C8EB15DFA2DBDF880E049F304D0BC -:10DB800034BFC1DA2C0094E61D921E1F4BF277BC05 -:10DB9000A943457F280624ED85F98F7CF28DC04E80 -:10DBA000C83707399F2517BCB002E9D291C9F1F4F3 -:10DBB00047F42D43FA0893FF8E713B6A95A8203EE7 -:10DBC000B64673498F3732A90CF1D458794444B919 -:10DBD000BE660FF30B02D2FF7F5B63E77753460EFF -:10DBE000C7BBA490FC937CFCFEE89A42D181F2F57D -:10DBF000E01D2F90DEDB724064C8FFA5BF3DF6B08C -:10DC000003E9FACF56CA37BF524972E327D04E4DC7 -:10DC1000E03F1F482FC7D7CF5BD226E0F944F6FC80 -:10DC2000C82BC3513E8724FF55888FF91D0184936B -:10DC300052CCCFD99CD3A3F44E88825A0D6C522576 -:10DC4000A4A5CDBC9CDD944AFBA8D1D6CE866B6042 -:10DC50007E8F3C2931D497266B24631EF46B7AD1D6 -:10DC6000899AA0D7FEE891E9D10C94E3499514066E -:10DC7000DD6B7E6F67703EF44D575E1D0EFDBA265C -:10DC80007358DA43430EA0BC449B19EF553854AE89 -:10DC9000E7D649E100C679AFBB2B68C1F199B67FE1 -:10DCA000695C52F138C2F984A6F758E57C7AAFC4B2 -:10DCB000A7F18BA38A9524DA673DE049E2F12DF7BD -:10DCC0008B07903F7C0146FA43AE8A4447687A1935 -:10DCD000272EDFF75C23EA17E76291D6B14EEAA858 -:10DCE000C17725D6DDC5E41AA5777FFF68FBE51966 -:10DCF000567E2E8A384EEB5907B9E440BEF9E62726 -:10DD00005E4708C71DDFB38E247D1D059D94D7E7B0 -:10DD1000B12D10F95AF3D8A0AD634D067FA7C851B5 -:10DD2000D849EFB3C4CBFB958E77E8FD9830D8EA9D -:10DD300026BA8F16B906F3CAB322E3F7B58CFCDD19 -:10DD40002BAFD155FC7785C58C938374C7F10C74C8 -:10DD5000A7D94FC077361401A2F215F93142FC9DC4 -:10DD60009C387AFCA7CBC5D87943FFC90D4CA0B825 -:10DD7000B8C54C29CDE82D179926176D4C8DA2FCFE -:10DD8000FBBF968B2007492E36C34A07C34E25B9E1 -:10DD9000BDE90ED4E3BA3C1C8F38C177A254F375A9 -:10DDA000A585B42FA27CD1C3AF36D37B43A276DE48 -:10DDB000A5C105DD500897CF3D8A419F3E84FF8075 -:10DDC00075EC6E4FBDB610C6DB589E5B84FB0B7BBB -:10DDD000E845B20F7C853C7EC557C5CFCF1D797312 -:10DDE0001F8FBD17B730C342F4B750A7BFAA900723 -:10DDF000C75987FDA27CCEB390BE7C8445B83ED483 -:10DE0000ECD3168F1647ACD1553C9FC4CBA771BF3E -:10DE10007397A27CCF10AC32EEE7503F1F4C37EA2D -:10DE20006BA4175D5FB774AC74A13F2C47F3F7E7A1 -:10DE3000D88C710E45995C5F7FA5F901568B95B41E -:10DE4000DF544B45DAC7E9F477418FC7C1311E7EF5 -:10DE500048A8AB26507C0CE5534ABA19F2EF56207D -:10DE6000D90D5066CB5034FB402638B7FE581C8B7A -:10DE7000F272777B851DFDEB82CF7635EE0FD70BE7 -:10DE80002C8A72737DC9EB1457D254053DC3A29CF2 -:10DE900005E22CCB98DE78063EA6FDAA43B576A017 -:10DEA0005F2B126DA3B885A6F0A1998CDBB10CE3B2 -:10DEB000529A0A56662E44F95E50568CF86DADB7EC -:10DEC00050DC8C5CC012FA11DED7F631DF548F398A -:10DED000F4FDE5E2C4FBCA6B32F9FE362281A8826A -:10DEE000F96415887EE4FFAC3A4BC2795CAAE1295B -:10DEF0002D93DF0F6BAD3F9441EF63899561D61F82 -:10DF0000BE60FA2BD363F031A90F7C78747C483A59 -:10DF10003E5CB3880F3B3B442E6F49AFAD63F2CDFF -:10DF2000A81FD54A0BD9B18D66BE2F6F2BD4F842EE -:10DF3000B6B522B17D53BA4E5922D23D1CEF449161 -:10DF4000F6898EC5CF515CD323ACFB1594778063E3 -:10DF50001A2FBE7D79A6A8C15111FCB49FE67804A2 -:10DF6000BCD27C36E7A7B7C6F2E9039A1DFD8087CD -:10DF7000F3E9E6FA87884FBFEE3C75B95DABD9D1BE -:10DF80000B02410BAA0355289B9A81FAF331E6470D -:10DF900038319393ECF20FB1498C5FF6CEACE0C20E -:10DFA000CC98F345395049EF165E89EF0A41FB0FD3 -:10DFB00022FC3EE80791E74BE8DDAD2023665EC01A -:10DFC0003A04627290A1DB21EF912254EE990F7313 -:10DFD00071D1ED48CADB6CA0176142A7ABF9FD8B8C -:10DFE0002EEDBDC8C7B5F7223FC6F721211DDDB212 -:10DFF000BAF4111C4F918228334EE27B9178FF795D -:10E00000E25B14177D0A646D930BE3617E5542F762 -:10E010004FEE65B23809F36B4B31EEF9CE97ACDABF -:10E020003DC98E9578EFE55111D60D6DD648A0EF1C -:10E0300087615183501943C7BB2EED48C173BED3CE -:10E04000911BFBF51FE3FD417A2F3393E369836353 -:10E0500029DD2F9BEB8CFAB0FD81DD4F3CBE09C65C -:10E06000FB78AF8DDE35D9E858EAC3F28F1F7ED337 -:10E0700087FAE2F4DE372D89CE27974891A9788F69 -:10E080006CB13A88AD84F99744665928FE64E7017B -:10E09000BA9FB6440E5AB0FFC52DBB293F65E71F96 -:10E0A0007C58FE6626D713A733823EF44BE4B5585E -:10E0B000A322E89F5DB9A18509CFD933456DDE2F35 -:10E0C00051FF1B1D2F1D42BC9C7ED84A7EB7030FFB -:10E0D000FF96FA3DB5F7459AEFC7BBDEBC15EDE9F3 -:10E0E000C58CF9519E9FB66B7E3D5B474AECFE7630 -:10E0F0009F060F3D7F3A59DB07670D504F3B8F61FD -:10E100004E803FDD1FE848C1FB851F9B831684C7F7 -:10E11000228407A425000794FB8B2202CD73514B68 -:10E120002BDDB75AB487FB071701BC082E2D0768F3 -:10E13000FE4732B9DC38B5F78F3E7A9F628F95F68D -:10E14000CFFABA1739833E848FBE5E80035FF7AE85 -:10E15000AF87A7B93A9E5AFE40F35ABC87CF6BF1FE -:10E160004E3E8FB97B004F4EC4D32CC2FFA9BD4C8D -:10E17000C17B305DBBDF3C89F6CCE9BD3605ED0ADD -:10E180007D5E59206E53C6221F717DCCF608A48F88 -:10E1900099D441E7394B6459C6F7092E94872D610C -:10E1A0002E4F3B4A8742F9D30F8AF48E25932323BF -:10E1B000D1BFFA61A67EFFA7C3877EB15D9786882F -:10E1C0003E3F4AD6E02D75F8307E66C3D0E0879991 -:10E1D000B1F878F7C591B8EE15A6CADF7A719C2719 -:10E1E000787CE8E7B9957FBD9FE63DCC70DE189F4F -:10E1F00002DC52F0FCBB406441BA97BCE7E5A4D80E -:10E2000073E82F33B9BEDAE87887EE239EC6F71C91 -:10E21000693E118AD31A1EA8F0E139DF47CC19C430 -:10E2200073D98F1F7B99E26DBA3274FF5307D53BC8 -:10E23000B5E7E5544C2BB4787816BE91E418C0B11C -:10E24000C13636917CD4EE1785F9BDB13302084C46 -:10E25000D4135B7438575A6618CE75B81CCDDA9C47 -:10E26000D34EFE9670E2FB66F1F237EFC14974AE11 -:10E270007C8E253E57665A9CDC0A5312C5DF6C74AF -:10E28000FC8CEEDF56A95619EFAF1CD7E4E27BDA1F -:10E290007B0B9F27A5A822D0CDF34383DEA169BDC8 -:10E2A000EFE156AC59E243F856E0B9076D6AB65D46 -:10E2B00087F1845D694C7B9F9445097E66BDFC5F58 -:10E2C00078B98BE78B873EB316ED13842FB7531FB6 -:10E2D000BD0EE31ABB7278791996437E566659E1F2 -:10E2E00050EE3711E81C89995D5D36AEC213C1A3AB -:10E2F000072E12EBD2ED6AA83C7B2823B8427F138D -:10E3000086D2BE1EFA1BFDEDFB03BCABB6D4FF8567 -:10E310007E6CFF5BFD44482F89417CEB0ABEF9B956 -:10E32000FE7BB494C94DAE6FDFFF3FDA7E852920B6 -:10E330007E8474384824BAD7F9BAEBE11145B8FFA6 -:10E34000B734DC1145B5D9955C6AC980EFE7147E16 -:10E350007E72FB831B0CEFA8EA69FC7BB5FA399E41 -:10E360006598F17C76D5502E8F560DEDF113E2B9FC -:10E370001C1E57D1C619FE9AD3291486DBE9AC526C -:10E38000C4F8C382761BBDD77B11034101F31FC5BF -:10E39000A222EAEFD1AC93F2DF411040BE882926D9 -:10E3A000CC8F63DD3E69189E3F4757A19D76C41D03 -:10E3B000AC43BAFDECE18E770428FF4966F0979DE7 -:10E3C000E8EF1CCAED5427988548CF32A64087A2B3 -:10E3D00063BA2791DCBF004F593A157BDE76831470 -:10E3E00058C7F9224BEE72F4C05997070BB5F7974F -:10E3F000F4F6279F7C2297DE1DEA7907BCDFFBC07D -:10E4000073AB163CF8D8B87ECA3539BBAB267C73E3 -:10E41000ACBE6FD3E0BC7DA868B00B6154B2E39E84 -:10E42000BA81DB4FBB2E0DAC7C14E56D8B89F6D326 -:10E430001FB5FC91BF8753C6C8AEEB6BDC8FE2F013 -:10E44000FED1F62732F97947D8A0DF173CFE8B9131 -:10E45000B1F1960066C53D81BFC341783FE457AD39 -:10E4600026A4D232F2C75858258F53C1F90EC3F7EC -:10E47000B822943A5907A529AC9B5299C9E49F4EFA -:10E48000657E4ADDAC8CD274562970FB2E44692619 -:10E490008B509A85F629FA7B5837A50ADEF88C89C5 -:10E4A000DFC8C513D361F8DE6E19FF1E171F2421C4 -:10E4B0001EC72590E7717141D28E2A92E7181794F2 -:10E4C000EFEEFD9E822EBF370C2DFD13CABFE787EE -:10E4D000068E20FD1C7EE6557EBF62AD40F6F50936 -:10E4E000FB748B02A87B3A3540EF80A8222BDB0E11 -:10E4F000FA7D8EEEFFC73F3D4E1881D96C3E151B4D -:10E50000BFC36CCE023C2F9EAD559DAD9D83CCD636 -:10E51000FC20F8CE19BFA7E7A7FBF6B3B5F387D960 -:10E5200071FE1716B21AFC282AFE03D6313B24D0FE -:10E53000B9C1ECA4E92F75B2BEE924A63FBAF757DA -:10E5400011E7871AD09F15979F13DFDE26305B3ABD -:10E550007EE7F4F4F4650AD975BA3F0B084EA1764C -:10E560000DD677C92F14BA32100BA7E42CBE6FB5A5 -:10E5700087AE4A49F4EE929ECE01FBCC9CDABB3DBD -:10E58000EC085DC8F7BA1CD6E93C0737B6C84705A2 -:10E590009684EFAEEAE91A4DDF37DD1F62386F7BF4 -:10E5A000F41E7A8FFA6EAF4ABE5A5B6198EE07246A -:10E5B00015843D6A82F935E13BCEC05F4DC9C67313 -:10E5C00093C5599CFF1767F1F3DD4317A597E279CF -:10E5D000F66A85BFEBBA5AE1BF47B03A6BA0F7C8FD -:10E5E0006D867BF2AB066FA57780EC5F6C63684F3E -:10E5F000DAA5C4F7526ED2E0BA41ABBF71F056F261 -:10E600009334E4F3F3FDF8FA07F21FA2F71F1B732C -:10E6100060BF8BE9FD2AF55F9FFF5039B6B7451BF8 -:10E620000DF7797F94C5E59A6D0FA747539E259CFA -:10E630008BF4208528BE40AFD7D8C779D2B42CAE92 -:10E640008F9ACC61BA27D3A4D9438BB31CEBC82FC4 -:10E6500097D57614F9F55C1EA3F3467BF4493A4747 -:10E66000B01558985DD07E0F00E33B0A23841F74D9 -:10E6700036450D741BF3EEBDA977FF755F853CB879 -:10E68000BEC69C108D3FD07A2FD5E0D9A8E9D746D9 -:10E69000BBF11C6DAE86EF2B75B8EC67244FFA8189 -:10E6A0000BD97BD336E75E8FF3B1ED1B108E86FA64 -:10E6B00039AC7C50227E8997FFCE4231EE1D2581F8 -:10E6C000E6756E8FA0BDBBC8DFB1E8B1032216ECC2 -:10E6D000F75F37571CBC1AE6B330E80C60FCE41354 -:10E6E0009BDBE89EFEA217CD149F30BC7316978368 -:10E6F0002DFC7D45FD7DA38B5AAC86F7A696B09880 -:10E70000F71761BC45C73E3AC6E89EB1F1BBFE6E45 -:10E71000C01AFC90204E2DFEDD8175597DBC3B500A -:10E7200098D84F13FFEEC0CE88487A6339C6B1D26D -:10E730003E606B29EE7BAA8E09E437E8CD87CA9646 -:10E740003C734C5EF0133DAAC94981ED09F8E94FCD -:10E750005E4E0FBBF0508DECFEFBD645B330AD6383 -:10E7600078DE547B9724E3B9766D3889EE97D4CA66 -:10E770006218E346BCC9A536F43F329728E33DB49E -:10E78000A9A6C974EFC972B7348EDE696D5BD881F2 -:10E79000F7EA6A3D12433EF6BA781C01CB10E97DD8 -:10E7A0009A3AF975D76CDCC739F93DBD6C99851576 -:10E7B00001EDBA00C3F365D8AC5446C1F4F20A8146 -:10E7C00028BE77C52659E5EDFC9D99EB8B26901F59 -:10E7D00098FE0EB44E8DFE1AC709D8CA10FF53EE2C -:10E7E00076933D18F69818C6011ECFCA21385A9262 -:10E7F0004BA36FE3FC663AC8B71B56C554C4C32B82 -:10E80000ADAB665C05DFCD6189E21D0ABEACBDF92A -:10E810002A68DFDD6AA1FB163A9C943AC9F07E8330 -:10E82000EF3E63DE12F75E85C462CA21FFC72CED9E -:10E830007C9295B3686C1CAF3BC00FDD6527BD5B58 -:10E84000D709FC49E71F5AFE4F5A7E87394478DFC3 -:10E85000F1B640FED583AD73B3495E3A966E73E070 -:10E86000BEF0283FC7EC4B3E3F9AA5E8EF7CD8B5F9 -:10E87000772AECE8F78AA7A7BA6AE6C738435BB8F5 -:10E880003D6914E2F7B0997E3FA05E938F9293CBDF -:10E89000719D6EE2D3FA38FAAB37FB0B4250BFFEE4 -:10E8A0004B93B66F3C797D7432863D28B4AF3667A2 -:10E8B000313FB287D9DD9129C33C46BD68F1E3EF12 -:10E8C000334C7DB67010CAF9512FCF24F9867042AF -:10E8D0007C4955163FDAC9D62AB75F1A87F59C449A -:10E8E00097679D16B287A42A4788ECAFD6091E25E4 -:10E8F000765F512DFB2533FE6E8D8DD2557DC8FB85 -:10E900006C9758867E578B662FBBBC5C9EBABC0E3C -:10E910007EBEA8AD739BA4CE407ADE0674837137A9 -:10E9200007EEE3F4BD3CC3467A73F92BC386F4E7E4 -:10E930001F7CBCDAE3CF03C06EBDAF82FCB625F707 -:10E94000BCD78874B73CD926231D9A52866F9C8CFD -:10E9500074FFAA99EE79D6264F5066C7F4674A9994 -:10E96000E8417898443513E979F8965DD74B939050 -:10E970004ED44D789F7F8CF75FAE9740BEEC4856E3 -:10E9800033F1BC6C82F7619E4F533709507E997703 -:10E990000BCF7BD54C11F253BDAD3C9FAF6EC2FC8B -:10E9A000F5DEED3C3F9AEBA31F789F24795E6BF672 -:10E9B00097A37FFA19987F613EBE93CAD3720D2E3A -:10E9C0007AF973F8DD8CEFAAF234BEFC05ADDDBE3A -:10E9D0003ECA7FA995EFEFA3FF97B476D13EDA1F29 -:10E9E000D4DAB5F7D1FE90D6EE701FE5AF6AE5AF89 -:10E9F000F5D1FFBF6BED3AFA68FFBAD6EE8D3EDA7D -:10EA00001FD1DA1DEDA3FC2DADFC585CFFEF68F5BE -:10EA10003BB5EFBEE486B7D05EF381BC427952903D -:10EA2000DC40FEAEAD55C544FFB5E3B9FED7E9DD28 -:10EA3000A7DD0BE8F0F2B8D20E2FB76F966B745EBD -:10EA4000724FDEFAC94887BFE3F714417F1CC57BCC -:10EA5000B8EA3D22F9F796BFC2DF95597E8F44E7A9 -:10EA60001B3A3DEAEDF5F987B579D669E9422F7F82 -:10EA70002F2347F5F8A7C7E847B36CCCDB809F305E -:10EA8000FEBFCECDF54CC13DA50D786E520B7A067A -:10EA9000D757EFB444D1FF552F4B545EE72E0DE10D -:10EAA00079BF2A4BA487EADDA9517CAFB9AEAED8B5 -:10EAB000F0DE679D2CD1FB31926B8A6DB613E5C6F3 -:10EAC0007419E5671D93534BE85C0DF669A84FAACE -:10EAD0004A65943B392E772ACAE55BB3F9BADA93D3 -:10EAE000BBEC788F42BA5FA4B70286CB12F17B5E93 -:10EAF0009D1856601EEDF272F2BF6E6FD6CE1419DD -:10EB00003F4FD4E5FC8E9F4D253D560B7A4C213D61 -:10EB1000C60615A5F7DCDF948E8DB2A0DE92334DCC -:10EB2000CC0C72F9803795C6DDFE20D75BF9A0B713 -:10EB3000F09DB56DC58CBFF3E6B1915FB742629EA3 -:10EB4000C1317ECC035E6EC733D3743FEEB3F3F1B5 -:10EB50003DC418F80E0B19F556CE007A2BBB0AE40B -:10EB6000654C7DAB4736E49FF26AEFADFA991FED35 -:10EB70009BA9CF6E267D7216F50943FDF2EF49A3DE -:10EB800050BF801EB1B2DE725097C7BADDA2CBE98A -:10EB90005A4D6FD4C6E98D81E5EEDF5F1941F42946 -:10EBA0001ADEA1E94BFE2EC73801A04B735020BDE1 -:10EBB000C2A420DDEF1F086E6673998CF6F840F052 -:10EBC00033A77DEA42396D0E4AFEF712DC931A082C -:10EBD000BE7A3D8B6DE816D46B9F1E5B51807EAF75 -:10EBE00055E68E593B916E854174BF43D1FC0E5B57 -:10EBF000ABF7B113F9F8FB3D7FD95C87BF8FC50236 -:10EC000032F94B324A156C67877DFA60B2E3F87EC1 -:10EC100093C9C1D042B4E75FB428782E70F819EDDB -:10EC2000FD06AF93E079E7EEBBA89D59A8F4F0F399 -:10EC30007E46F05E9D994A76B9B2C3A6D98D1FAFC4 -:10EC40000FE441BF62A780FAE7F7D95BD7DB501F1B -:10EC500069FB0198D9F770FF13095BB4FA78D19D6D -:10EC6000B1DDF8E334DCFF1C903CB176A8E97B53BE -:10EC7000B2F03C541E25417FEEAD96F5662F968B83 -:10EC80007AFB005E1E42F1A5E725C0C3D3ED5AB959 -:10EC9000EA5E3F05E6B3DBA28F0F06F5441C4FD4B6 -:10ECA000E829793DF6BFAB546F7F7A3DFE3E17CC25 -:10ECB000E75A13ECC1727D9EF5CE8C9EF97AB37D36 -:10ECC000EB6BA0BFD34A670A6EE396B4BE978E7A09 -:10ECD0007B7539BF3F8C0C80FE11FD1EF105BCED2C -:10ECE000B9414557ECDF0EFD674A21142D33751EDF -:10ECF0007200DC96ECABB499457CBFAB4CC5F7BB5E -:10ED0000F4764BF6CC223B67D9FE224A13B43B8CF7 -:10ED1000F767FE817636CBD718EF74F4F5A53B156F -:10ED2000BC3753D9E034517DC6FD5F89D7A7B73FC3 -:10ED3000BDF3F51FE0786794CEF46BA0F6EA28C027 -:10ED400025413BBDBE7EBFBAD81328F2C1F74F3173 -:10ED5000600CE59654E9C7FA115B88EEB1D9CDA1F4 -:10ED600032D42700FA30C629E869B12F8F9FA3C497 -:10ED70007D8FE7AF888D0D9E8EF2F22E89CEDD233A -:10ED800036D53106F2CDB04FA98129AD2C3A3216D5 -:10ED9000E3059AF73A49AED7DED5EE2944BEF25BD9 -:10EDA00018DABDCD977664E03BF875775BCA1F43F0 -:10EDB000FA8D2EF7DC1E638779B3791CB7D7152A35 -:10EDC000477EB4033FA23E6E34076DF86E8A9A21E7 -:10EDD000525CB51DCA5FA372AF56EE9F7615EDCBA0 -:10EDE0004419E7559F37675A29EA354F2AFF1DC254 -:10EDF000FC29E5F3A03C2C5B6424AF45D9153723EF -:10EE00009C9E96FC95C87F4F3B9D32C66381AC2487 -:10EE10007D20E5BB293ECBAADD77F216713D7F410F -:10EE2000FFF9B81EABF3F138FCE6E48E1B4AA05D97 -:10EE3000D2BDA2AC42FF8D773F5486F1895BEE3E96 -:10EE4000F2078C6F6D4A97E89D815D35D100D6EB56 -:10EE50001658471BFE2E52D58C0EDC8FAE658A826B -:10EE6000F6FA2E614608F573779AC4DAA07E529EB0 -:10EE7000315ED559688C97CA5A6CCC376607EFF665 -:10EE8000513C5071098E9326280A3E1D5CDCC12836 -:10EE90003E3F3D2F4FC6B8EE94E2B838D8C9C67E83 -:10EEA00052A718CBDDD3E3E2B66E32967B6E31E625 -:10EEB00033E718F3EFEBF4E8E1E70FFAEF3D6CB955 -:10EEC000FB71867ABAF18B4114CF8A7044BB3D69DD -:10EED000B8E4C77311AFA56326C6C1B19149642FC9 -:10EEE0001DF4253105F2D6A58CE4A935357200F75D -:10EEF000AB56512E534943450EBCEDC6DFEB32D124 -:10EF0000B96C3CFCBC5EEE1F7456F2DF858B485139 -:10EF1000B223ECF70C926BFCB8758CF3C32E8EC940 -:10EF2000F378EF2D3EED1CC5A3C7A9115E6165887E -:10EF3000B7498C7E3FD27BF77B6A14E6B156C9ABEA -:10EF4000443B63B5D849E3A815CE20EEBBD330CE01 -:10EF5000DB84F1DE2AA5F1F8D8A9D197C2E68410A6 -:10EF60008F9E5922C58FD41F4AAAC3C3977AEDBD7D -:10EF7000063D8E4DA7CBBD3E6E7FEE6E17C500FAE7 -:10EF8000C16FC96B437CEBF996A0BB95E2FA8B2A63 -:10EF90003B912ED975DC0E053D40F7B2F538313D79 -:10EFA000AEB0339BD3F707D9A2210E9CE28862E270 -:10EFB000C0E9E8CE8447172119CF7BBC456532CA2A -:10EFC000999FEBF72F18EF179F2FA47383E962E047 -:10EFD00022CD9F8E76DD606DBCC16E2940EFBBC334 -:10EFE0009C44A8FF20E3F507E7ED5981F7AE7623AF -:10EFF000E120FFDCCEE11C4FB719EDA1B2D1082F03 -:10F0000001F461566F3A167C2D741E587F2F4BB554 -:10F0100016F5A6EBF1266EFF742F5028CE72203A1B -:10F020003FE173713F76DA2619EDDBCCBC076BE864 -:10F030001ECCBD4C467D97D9DE7103FABDE2F921A5 -:10F04000EC4819CBE3E4BE991FDE64E2FCC18648BC -:10F0500084B7F8F8D2F878526FB64B3B87023D90F0 -:10F060008CF701E42B304EB0FB1E46EF0494BED863 -:10F070007CF3BF417F9FE55B6494D7D96F049F7099 -:10F08000C0BC3EFB45301BE5F456A9D3EE8AF17BAC -:10F090004A22BF7FD64B5E6BF4A1A0DEF0FCE3A951 -:10F0A00017E91B882B92973E4A467FD5B675BFB7A6 -:10F0B000A5FD1FDA2DAA3984768BAF5DCF67901D31 -:10F0C00096FD06CF8FDD9AB15E95106E8BC95F7489 -:10F0D000D03B97FC45D25BDC5F34DA1408639EFDBD -:10F0E000C54E71773BF6DE321FE3D5EAD3AFA1DF21 -:10F0F0003D1993CDF79D85D93A7F1BD72F590241F2 -:10F10000E49BF8EFC3B3F5F3C4B20F6701FE463FCB -:10F110006AA1B8BB02B1A22107F9A1D144F8AC3071 -:10F12000294BD7C4ECD3EAD34B2667A7D1BE8005C1 -:10F1300061C3A09C17581098CDE73E5E82F49A0DEB -:10F140006C86F2255BE506647655120BC6D0A97273 -:10F150005EA2FAF5E981C9D99ADCC3731FB3C6D29E -:10F160004FA796B159A897E11BEA5DF3CE247EDE46 -:10F17000E336DE8F349978BCC8D5DABACD78AE33B1 -:10F1800016DF7B13A3D631BDEB5FAFC149B239A304 -:10F19000A641E8277BED28DDBB8C3B07C6FD2DC5CE -:10F1A000E52C66E40745B850FE4E99BFDB5DC5E32C -:10F1B000016AEF63029E05D46AF754D45BF9EF0E3F -:10F1C000B34040C1F755688BA9E0FFA2C4BF1E1B26 -:10F1D0004BC5FA19AC83E218593B5378BC84F1DC77 -:10F1E000696B1FEF40E97E00A9CA44FB94512FDBF5 -:10F1F000F9EF4355317A279CDE6CC2FDEF7D2C2C54 -:10F20000093D7EB80EAF42EDF4F3D85D5FBE43BF5B -:10F21000C75C20B6055F23BB21596E43FD9864E4AB -:10F2200043FDFEDAFD1A1FE2EF490763CE8F7CEA49 -:10F23000718AB7CF66DD35B8CFCAAE4A35E0F982FC -:10F240005FF6FC50161C17DB6F98F3759E44EF7445 -:10F2500029E77D54BEB55A19A0FFDC3EFACF207ACB -:10F26000EABBFF2C2ADF16FDD4753D80626BF77B6D -:10F27000AE32A5C76E8D87B3EF3EA3FCFECEBEF8BF -:10F2800078720E17BB39E0BE01E066BF5FF4B7329B -:10F29000FCDD1B63BD6939E75CFCBC5CAF1F75DF3F -:10F2A00088F561DFDBAAE0EFE818EB9795BCEFE2A9 -:10F2B000E7EE7A7D3EBFCBCF1BEBC5E3277EBE30AA -:10F2C000AFB4EFC7CCEB0A9BD5505E3EABD7BCD2F8 -:10F2D0007E1833AFAB3CC6FAC19AC4F3BAB6C0DAF3 -:10F2E000EFBCF47ADF9BF8F5EAC5AFE3C669D63E1A -:10F2F000E0CEEBFFB0FCEBF5FBA3F9FDD7BBAD2AED -:10F300007E1C95E409C8CD0E944F154C5985EF84A9 -:10F31000336752C2B8E0C91A7F9C423F059E930EE4 -:10F320000DBC89F2F1A497C7FD1E7E666108CF610E -:10F3300096EFB52878DEE1D5FCD620781621FFEED1 -:10F34000B6C92E8C07147D8A763FAA2307E3F97687 -:10F35000EF387233C93D66B46760BF5682FA1A440B -:10F3600018DDCB780DDBA5C5C65104C8FEAB17FD73 -:10F370007FA47DD50FF8BE4A8FDF8FB5B3D8841E2A -:10F380003B4B8FDFDEA08D733E9BFB03C1CE570549 -:10F39000B2F3258A6FFEB9AD6303DE3FFAB9DBED48 -:10F3A000C2FDCC416DDEBADDA8DF6B18322BAFC8D1 -:10F3B00094005E17F44852CF7D098CA374E5E5D123 -:10F3C000BB1868E78D2DC47E395CFF07CA89A75634 -:10F3D00000800000000000001F8B080000000000FB -:10F3E000000BDD7D0B7C14D5B9F8999DD957B2BBC4 -:10F3F000990D4B1E3CC26EDE8100130831A095258D -:10F40000448C96D20D3E0ADAE292F094BC00ADF143 -:10F41000CAAD13121110356A44A0800B8A62AF681E -:10F42000E8450D08DE1035B5B7D886B6B6D67AF9F8 -:10F43000AFC0452A086B1FEAFD17CBFFFBBE339315 -:10F44000EC4E7655AAB7F7FEFEF187B367CECC79BE -:10F450007CE77B7FDF3973AF893156CA989A2F8555 -:10F460007609F05B666C4D19636EF8C9B2197B447E -:10F47000EE734B50FF88479255A8EFC9F232368998 -:10F48000B1BDAF994C7E0F638F7D3777A7E81B28FE -:10F490006F0A7A766079A489053B1DD888BC8CC137 -:10F4A000FDBD36D9BDBE048A529FAFDA09E5DDBF86 -:10F4B000B949703196398A517BB5CDD3D989898CB8 -:10F4C000BD6889BC7A11C7B35108ED82765EEA281F -:10F4D0009921C1FB0B4F336687476BEFBCEE9193CD -:10F4E00043189B7C529E86F76BB7BA1511EE37F422 -:10F4F00035CDC07E581353F214C6D2C569A213DAB3 -:10F5000049BFEFA8D20A437EB4C7DB158672648771 -:10F51000A0ECF462FDF292E5C5F0BCC3EF75C07CCF -:10F52000E7E350E9BE7B8619DFBBCEA2B4413B675F -:10F53000CD6C4E273C7711FFA60E5CE77FD75BCEE4 -:10F5400060FCF33BEF9C4FFDCA00B24C28DB641A11 -:10F5500087CD2BA7B640393D89D9EC13182B5B2DED -:10F56000F7DE85FD2F75CA3B01C6AE72B9F7873845 -:10F57000AFA62C5954B0F310C1416F7FA13F606119 -:10F58000D0EF98DD16688CD1DF45F837B633B63C3E -:10F59000BE2BB65CD21D5B9EF8466CF97998231B96 -:10F5A000CAD814DBF06D2701DE3D87AC0CC7BBEC7D -:10F5B0004C52C80AF03E60660CE7AFEEB1123E4C0A -:10F5C0005FE6F0237E9CF920698715CA87DF49A290 -:10F5D000E76FFD173B7FDED4F91C96D5E792193E05 -:10F5E000BF6C4867592A8CFBE5CFC45B02C57C5AC7 -:10F5F000666CFFB9A21DEBB17E6267990CF75F1CC8 -:10F60000CD581FD64BA17138CF17FF2652BB91673B -:10F61000ACA19DD0EE99FD4F3F87F03AF3CCF0546A -:10F6200001C67CB969E7C4F558DFE2F4EE84FB5308 -:10F63000CE3C9B138C5A9765BBAD31F35CE61568E5 -:10F640009ECD927FF513B83E47CC844F2B17866A28 -:10F65000BBE1FD954296A2623B16C0D3622C2BE91A -:10F660006EC0D7292E8EB72BED508EB3EEFAB5664D -:10F6700093C8821307CAC7D73D4DE3293CFD36E145 -:10F68000F501B36A4A4238AE13945D30FE0376D773 -:10F69000389682D7AC10E2CD3F794D343E98D70FE3 -:10F6A0001B102FDE14959D2C717F8519BFDF5A39F1 -:10F6B000F173EAA15FDF38C6CEFF21E9163F8CA3C4 -:10F6C0006053ECBA178562CBAB113E806F352CEAE4 -:10F6D000BE0FC793BD2683E884D1780A4FBF7B93C2 -:10F6E0000FC63BCCCA9A102EC67EEFC379403B3F73 -:10F6F000FA11B45348CD881745DE9E370DD641A385 -:10F70000AB97054E47F077DB70A0B76502E72FFA9D -:10F71000FD658671E8ED976A70F2589407C3B4FEF0 -:10F720005619D7FF83BBAB1E39691E3C9E5377FB2E -:10F73000FD9551F7176D5ADE9B09EFD5ED1D3A4146 -:10F740008C826FDD33AFA6DD0CF7CFEE96146481AB -:10F7500075739F7A600A3EF78CD889E3C57A3FCCEF -:10F76000F76CE7EB2E7C6ED156F704D13BF0FEE24E -:10F770004D57F92B0B07E079A974FA5239E773CB8F -:10F780003ACD211BD245E75B3386239E6E12943C13 -:10F79000E8A74C0A8A4877CE52BF599DCCD8D40BE3 -:10F7A000FFD63B0CEA1B0F4D2A5B0FF5EB4D81EBAF -:10F7B000BE8574B75D5476C16B2FFC7A455A306AAA -:10F7C0007D7A34FC5F7F631DB5A3026EE40153EFC5 -:10F7D00029AC998EE529C54CB0023F769D66FE9016 -:10F7E00003FB636F9B52193B7DF09E719289F8D1A8 -:10F7F000CD482767984B41BA3BE06CFA15F5B7C77F -:10F800004CFD4DED4E1190FF1E785250D63384477B -:10F810002CFD9D3EBDDA358DD3F52D01920326E6F4 -:10F8200081F6963C3196F8807EDFB87E4B43063AEF -:10F8300036E0C5096D5E889AD1F8657C6EC84CD5F6 -:10F8400082F458D70CF2228A6EEA4EB65B98637047 -:10F850003F8CF5E32F43FC05BC645E9AAF9DF80630 -:10F86000FC0936C0DB0FF0570E2F33E8FF5681A698 -:10F87000C6968DEECC473E274872455BE6007F6515 -:10F88000E521E2F367E1E77A05F942E731A47794ED -:10F89000A5BB50BEC8DDE7B660BD3ACA8FFC68188C -:10F8A00022295CD9F3C9C47FCF7AC34FD1FBCF8E55 -:10F8B0005554B87D1EE9C541EFB952A3F8534BE743 -:10F8C000ABAE3094CFEC1D5221BA106F7FE6C279F7 -:10F8D0007ED039A4C2E24ACC378C7C134646F07DF8 -:10F8E0000F7F02DE25F9FC661FC2BB0D842ECAB352 -:10F8F000214D254D71D64D7FCF63692AF122FFF846 -:10F900009E43413E9E6AAB7D1CE535FEF9E1FE1F3C -:10F91000DF18B213D7FF614DAECE17783F7A3B4365 -:10F920007D9C9FBC71383F250CFDFC917953505E46 -:10F93000ECC90964F8E07E46459F5F0478645CCBBF -:10F94000945678F584A87C5F86F558C0405EE2B591 -:10F95000346841BEC2DA86D278195366203C17CF8C -:10F9600004F897F032CAB7A5018BB21EE470ADC49B -:10F97000E15DBB5B08B5C258166C8885C7A20EEB6B -:10F98000005EE0FFB646D5433F4BA5D01A945B23FB -:10F9900040F318520EF8F064ECF3CB58378DABEE11 -:10F9A000D98BD67870FE8B06E73D39FE09383F616A -:10F9B000B68DC6B3728F40F2D563E9247D22B21CA6 -:10F9C000F8318C97FD9AAFC34D9ABED478E77CFF8F -:10F9D00002B89E6FAEF52F802A2235E4231D2984BC -:10F9E0003FCB2A3B7B89AF30F9C73767607BCC2F91 -:10F9F0006379A393EB7BECC95791AFFC85C99D88D4 -:10FA000087539608F4FE945F8B3B01C3D94DFDEB01 -:10FA1000172038D679998C707CC71CA079AB4B998C -:10FA2000BC0BF84A9D2DA0EB5FF2D5309F45AC8909 -:10FA3000E65DEDCBA6792E61ED54AE67610B1371D7 -:10FA40007DCB52105FFFC4145A5FD093983D753040 -:10FA50005E21FCFD51705BB235B6CC9E8C2A6723CB -:10FA60009CA11C05FF867D17ADFE38707FB45F1E1C -:10FA7000858AAAC746E3710BE1DF316D5D1EBD616A -:10FA80005126F2910751211EA635508EFC177E4D4E -:10FA9000A172B70DDA4F9AD85FA6FAB2D5BCDCB026 -:10FAA000E3C5C0A62B00DCE660A60C8B532B067AC0 -:10FAB0004D00D739B9C1154857B5267F9644FCC4C7 -:10FAC0009F1F8071B066BEBE8F4D682A6A8AA37F71 -:10FAD000E8E3DF2874769B908FECE7FA85B3346215 -:10FAE0008EE6FF1B7C5CBEA7F48469FD232F080C07 -:10FAF000F5DECDC24399B88E9B33BD422BCCA974A1 -:10FB00005FCB34E237C08BF2605DEBF7BDD73B1CB7 -:10FB1000CAA5557DB84C30EFC0F2D7919E2725710C -:10FB2000BD39B9698709DA4BBFA570422BE0E743BD -:10FB30003E2FF59334B1FD30B61359EE9577423B25 -:10FB400019AB55DF8A62ECBFA985F0B79AD1FDA148 -:10FB5000DF59D582CFDD378CA58AF81C6B11F0B93F -:10FB60003543055A8F35F3D99C1FC3556232E99D41 -:10FB700023E6C842CB642C374D23FCF2CAEE9F65C6 -:10FB80006299B5A5805EFDA88B919E39D424DE5282 -:10FB90000DD74727F072EA2AC1BF9388E121825727 -:10FBA000BA955509A9FC7EA89848D8BF97EA43346E -:10FBB000FEF4E94D25388EF41C7EF55882A65CE8EB -:10FBC000FFC851736835CCF388862FB7EDA8488FEE -:10FBD000E6BB47CEDA2413E8754732747DB6DB8185 -:10FBE000FAEC6D25D3D39118B373AB52705D3D59C8 -:10FBF000B1F5E7CDFE9489483F474586EBF7678727 -:10FC00003F05F5CFCB2D7CFCC6753FACAD67E3A7B8 -:10FC1000020B45C9B3C6391F939DD0F8A91473FFD1 -:10FC2000ECDD368622AE5FEE2DE99981CFD5B3BEED -:10FC3000358887F59DC92C1445179727C5EF57A719 -:10FC400087C64F45A6C6EDD7127BFFD3214C1D12A8 -:10FC5000EFB9B4D8FB308F9872D727FDF3C0FBAC57 -:10FC60003CEC0A809D3813E52894CF874CAA793C58 -:10FC7000AAF15CFE9D93C32ED4CF415E36E1BA9CBF -:10FC8000F386491E9E67AC0AEB2F37996EA9C6F51D -:10FC90009522AED9CE817EF47A7C3F7A1DCFCDB14C -:10FCA000B06E5A9F088D03E1A71630B6E5E04716FF -:10FCB0002FEA11070F13FC747C8986A31AC56FD233 -:10FCC0005AFBBA4D4057177C9FB51783C13AB447CA -:10FCD000E70B17DBFD2024D244530C9F482EEDE7A1 -:10FCE0001BC4A61E35893A9F79A872444C999E1F61 -:10FCF000785FA8AE04BE525ACCDFB7649B8EAE4686 -:10FD000059C6DA697C308F2C845F7FD966283BA086 -:10FD10003C36AA2C1BEA3D86FA0C4379047FFEACE4 -:10FD2000B33B0BED5777B6A55A023A3D9BD93D4FF1 -:10FD300080F286565B752594EB4BB9BC6E3828284B -:10FD4000246E34F835285CEF7428614B6D31C2A104 -:10FD5000AF17F94A5D97200B400F8ECEBDDD54C61C -:10FD6000F7BC51EF750AF45E5DE77BF45EC2F60BFB -:10FD70004D44E7EB0B8FF3E73ADF27BDE0DEB6E556 -:10FD800001646CBD662FF105B0E2FCC3E1C586AE2F -:10FD90006A16740CF0D77399FE5789BF1E1264A4BB -:10FDA000CF7E3CC5761D0374A13FFFFBB107DF4248 -:10FDB000B523F9B68F5A2478FE3FEADF9F847AE1B3 -:10FDC000EF3539B251081561BF5B58B008E5E0F76F -:10FDD000EAF30E9BE0B963E6F036E4BDD5D959D518 -:10FDE00012F0B563CEF04801E4FC75D945BC3C3453 -:10FDF000BC0DE1F92FD9A309BEC74686479AA0FCDE -:10FE00009D9D37F0725E781B96D59D7EFEFCD8F0E6 -:10FE10004811DECF51A755574279971C9FAEAFCE00 -:10FE2000E67AB43EBEDF4FF45764A39E57C7E5CFD2 -:10FE3000BC5BDF998BFC769E89C90CF8F4AEB327C6 -:10FE4000F6EC0278EC6A4E663B393A0624D087D34A -:10FE500039EA839C6827BE1EF1019F27E7515F584E -:10FE60008072F2249B77BD6F605DF4FED34737ED5F -:10FE7000C5F6D3E715931C117DFE67B17FFDFA76B9 -:10FE8000115CE1F967B365CEBF45939F9EBFCB1967 -:10FE9000C2E71FB4F37901FDD03A3BB475F95E3681 -:10FEA000E793DFCBE67AA4E2BB8ADABB49D7C7D7B0 -:10FEB000760E1D0DE3EA105827DA35EF98996A2778 -:10FEC0003D2689F4A10E1C3BD63F941952A19F9B5D -:10FED000051640FEA2F3930EB73F3335CAAEE928AC -:10FEE00081B263C08EEDA8F6672679F09A66421D4E -:10FEF0005FE74F1D3EFE9E2E9FD25B793FE90F16B6 -:10FF0000EDC4F9244B8CE4DDC239F93B5B483F98E2 -:10FF10004DF3677E7FA600ED9D5C9A6D4238EAEB5B -:10FF20007561A2BF99E62572BB5C5F371DBECF66C7 -:10FF300073BBB95604FD02F04EC90D527BA06F8C05 -:10FF400023C1AEE91BCF22D246C19949E14978FFCE -:10FF5000FF43786DC7FAAF0AAFFA66E023A62FC158 -:10FF60004734386E14BACDE99C8F90DD8CF7511E62 -:10FF7000DDE10BFE383B8A1EE6DD554F7AA63EAE2C -:10FF8000E43B5EAAFA0E433AFC80E86EDE3F25931E -:10FF90009D6BD40375FB4AD7571F4EE0AFECD6E6F6 -:10FFA000A7E87E596D1CC9C5E13DF703BC529953C2 -:10FFB000463E7ACC121EABC0FBC74CC1275EC27155 -:10FFC0000F1365E02183DA6BCE11A93DBB8E272C80 -:10FFD000E21AED19C093758027367CBFDA42F673BA -:10FFE000873BB47911E2C90D2314D54B7298E859B7 -:10FFF0006D4EA6FACB4DC719FA9923936519F54CA6 -:020000023000CC -:10000000C02BAAEF989B1F52B9BF40B593FF34296C -:10001000B413F1AE040080EDCD1D4DF568AF939F94 -:1000200063AE8DF73718AFB85D5DC078BD4FC3DBE9 -:10003000A5D984B769AD8CFB2924FFB8EA287D6176 -:100040004C0EE723C9A5E1177E8BFAE706BB92C7E2 -:10005000B80988FE0FD69E4EED01BE7C48F8C73821 -:100060005E2E78C0B983F33DA50CE17CAFB39DDD76 -:1000700049FE2B338D7FABBD9BF47093CDEB463F98 -:10008000F13C916DCCC7F65ACD32E28911DE2939A7 -:100090009CAF0DF667866F8FF667CEB3AAD62CACF1 -:1000A000BFDB4E7681EED79C97C2E94AF76B227D83 -:1000B000C6930BBA5FF3160DAF06D5AFFFAFBC1AF0 -:1000C00068EFFF6878A6F47C9A37DFC1E78DFE9170 -:1000D0001AFC05FDD6ACB2BF877ED01AD5DC6D7593 -:1000E000211FB9CA1F8EB2D3D8263E8FE09BE610DF -:1000F000C2A959621B9FC2F551F9FC572E0C2D8DD8 -:100100009ED7160B9F97FA4FCE98796D71B1255FE8 -:10011000CFBCFE3029765EA72769F362B634784FEC -:100120009373B7343BDF13C6C115E70557B60AE62C -:10013000553830AFABD1961B4AEBD9148F0EAF4E6A -:10014000B88EFF4BE6DBFE983FDE7C8DF3DC93E35D -:10015000AFCA994474D32D970EE0757033CCAB14AD -:10016000D77568A885D695E327632E05F9D8CA8583 -:10017000302FBCB6A4933F6B9ED5DB857E5DF6C366 -:10018000146D9E8CF8C0CACD23892E016F39DD3ED7 -:10019000C6E3412BEDDCCFB072B9ACA832CEFFC7BD -:1001A00064074780BF925ED21CCBD7BF180EF6AC57 -:1001B0009AE26838D8B2E617C75977D54AF89C68EA -:1001C000DDFF8F18B95DC849EC6763AB62FD14E8C9 -:1001D0006FEC2F8B83CB46BF07637FB3C63EAF2642 -:1001E000886F84BF178D47C7CC1A1EDD6927F9A316 -:1001F000E3D131279FAF118F1868D148C7FABC8D62 -:10020000709C87708C1387007CCA43381ED3EC33F4 -:10021000C0A73C84A34E07B734737E6084DB338968 -:10022000F9DA579B87018FBFEA3CF4FA44F3D0F523 -:10023000DB4DC2F2CD889F9B3299DC4A7A70782CD4 -:10024000DA491E4BA808C7B5C502F40BEDD668FD08 -:10025000932703E6F7A723DC2F7A5CEBD738AEAE03 -:100260001CDD2F1AEB376B7445B6A31ED298C4E57C -:10027000E1B9434EA21B961B9E87FAF7F9035686F7 -:10028000FCB54108E7E373E704FF7C7AAE25D98B20 -:100290007251F7379E7891FB1B5506F62FFAF982BB -:1002A000DC5FDAA8FE6C0DAEC3C51CA909EDCFC694 -:1002B000AE58FF1ACCCF85F33D67627DF87C83187A -:1002C0005A8A26EB460BD707369A5827AEDF805D51 -:1002D0007E3C9FEC844C99A13FA8C1F45EFE8A2825 -:1002E0003BBE41AB6FC8E2FE298C47939F1DBBF21A -:1002F0000D864BC386339F613CAD619F915E62E981 -:10030000A96EA02C5C14B0BDA87ADF003D913D8E93 -:100310007858C9427902FAD57839B9AA2F8471ED93 -:1003200046CDEF3AB4273C03F505676927433EDA2B -:10033000789ADB21530EEE7815FD6DEEAABE91A8DA -:1003400092346AF107A3FD33F9E04322FA8774FB84 -:1003500025CA1F55343BC61FB99ADE43FF16F61750 -:10036000C65BE8D796B89EBB51D373411F26BEB972 -:10037000B0BD80F461D45751EFD0FD63A887A03E93 -:100380003A27B7C2920BF3FC6B6E85903B89F74717 -:10039000763F3A5D267F0EFFD2E0A33F877EB2CF45 -:1003A0008F03707D6A8AC1FFBFE2A74309CF0F2484 -:1003B000D05387E6F6FBFFD3D1FFBF42F0A6239EC2 -:1003C0009F1283E4E75FCC54F21F2F45BF3AF1C17F -:1003D0006EF24BDFDAC494F514470FAEC172FD1212 -:1003E00026AF47BF746590EAD12FFDCDC93C4EE5DD -:1003F0008DC25F8C034597D96E28C7F0E93EF27332 -:1004000037400B5B14F423C43EDFC842D325C48BB2 -:10041000AE8BD698763A389C6ED1F065B39DFBB71B -:10042000A7ACDA21B2283F43CA04BFEF1EA4879FBE -:100430009AC9BFFA9FDAFAEAF0D89353918CEB95F8 -:10044000847E1F7CEE1E2BC9D99326B604F1E541AC -:1004500037BB6536FAB3EE66FE5C33E2859C15ED7C -:10046000EFD2AFEB0FD897209E4DCBE576807E3F45 -:100470009263A632F9AB493F4DA6F83BB0A571880F -:100480008765D9BA5ECCC6A19FFC3D8D3F35DCE8BF -:1004900008627B6113E767B372B93F6156AE85D6D8 -:1004A0004F2FF7FB8B343C837EA8BDA4892C26FEFE -:1004B0007743FFF30F697628A3F96E5C9AC4F5E8D9 -:1004C0007E7C37113F4B2E0E5882C44F2A889F45A1 -:1004D000FEE0F0225CAACED42DC579FC714E12C389 -:1004E0007C85055A7CA929D74DEDEAF1A438FAD7C5 -:1004F000CDDD9E0179A3E3A72E670E38F9BC2F3519 -:100500002FC078AD5A5F44FC5B1FC714835E92888E -:100510002E9AB57533C6C500AEC9C8670F98B8DD49 -:100520007500108BFC569D5ADC12EC64940307F6A0 -:1005300015909E3D5FF3A7829C24FB2A02F282AFB6 -:100540007770F3427CAE338FE2B9EF9943CF3C85AD -:10055000F2F610B723F4F53870607808E977CA9995 -:100560000B5908FF03A77F341CE3E407B4B8649D6C -:10057000A53B9FEC7D0BD753EB5CDDF908BF9735AE -:10058000BCA94B8232DC1F3934F830F21F3DAF007A -:10059000DF73D37CBC2EF4379CD0ECC8E36057E209 -:1005A000B8805AFA305E0AEB9D89E5C8BA74AEEF9E -:1005B000C1B8102F4E1C1A4BF3DB68E678ACEE176F -:1005C000C83F71DC1C39D50CCF1FCF9CC85A64942E -:1005D000779F3ED58BED6F179955C6BC8D4F3EEE7C -:1005E00082E7CF839D8B7EB35A53604626F28B17EA -:1005F000B9BD6E5C07947FD171BC732C92457EBDF2 -:1006000025D99D883FE70E16513E12F3C84C8572DE -:10061000E37E6EDF18E3CB27CDB1F86F6C17E7856B -:10062000FEB546FC8DF23DFAFD38ED7D51F99C3961 -:100630009C7F27C063AA37D8931B65A736BE924913 -:10064000FCF8C4FD9FD07AB2761E373D69F6CFC361 -:10065000F1B92BBB2D3551F8F83B8D3FD75AB9BCBA -:1006600006FE6B89E6377A7D59058B1BDF7F5BA31E -:1006700073671F977B83EB399EDFCE9E10915FFCE3 -:100680002ED74BED8DD2F2146E677F3A6C45FDA4E8 -:10069000B384F22046ADEA263E00E325FC3CB9399E -:1006A00085F823DBC0F175D10FADC43F1681FCE0A6 -:1006B000F636CFCB621B78FEC5A97B7C84CF65ABB9 -:1006C000BBCB881EDC4C41BDE4A5B6F75411EAE76C -:1006D000EF164A30EF6C7E9B8FEC945BF7F9687DE8 -:1006E000A7687CBDD6EAA73C33F6388FC32D78784F -:1006F00029F5539FCCDC22E97F210BCAE525BB05F8 -:10070000867435A593F3FF3AA9FB30EA91C6BC097C -:10071000168A8D2FA33C62517A26CA1F66B00B62DF -:10072000D75DBD24F96B9437E6BCF8F217EC3D4B6E -:100730001E5F572E27F60A9C6F68F2B71EE52FEA58 -:100740006A9ADCD3E5E6624D6E9E12B9DC5E647D8A -:1007500088AEC3F37C34CE5B311E4CF1CF8805F5F7 -:10076000934478315C1B978E1723304966E8005E0E -:10077000D49DEEEEB5929DA9BC8871EEBA55ACDB66 -:100780000976DA22A989E4C33099C9948F373D48A4 -:10079000E34A5F09FA39ACF3228CDD4EB874BD60D0 -:1007A000901E6090FFFAB8753C31EA7F535685443D -:1007B0008A33E533BAAF5F65D65982E3ADB671FDD2 -:1007C000BBDAE6E816D1DEAC349F8DB637AA257FBA -:1007D000791EC9CB11EE53638845306C57F1F9ABE4 -:1007E000464F1AD02B934B236BEE87F6CC6C9C09AB -:1007F000F9A4DEBFE89BB6B818E37A521FD92B2CB8 -:1008000083C9BBA0BFEB8B395C93611D76005CCDC7 -:10081000924AF033DB64778B1BD7BF8FE23291A112 -:100820008CFC74FA7A6D733215F31CAF2FE6F47DED -:100830007D31F727C3FB14FF3517C2FBD07EC501FE -:100840003BD1E5C7FB9D2194CF207746B9A13EED72 -:10085000F760A740F9DC0127E929E73479E1D1FD08 -:10086000B56C0DB5779386372AAB188EF60813AEA4 -:100870001D0E6367BA9E5CEF4E14C7D4EA7D7D37C8 -:1008800072FCB592BEF0B13BFC7D2CC37828276783 -:10089000B686578DFBA697DC85FC3BE05038D483A9 -:1008A00025A8FF58C5DB6EB401B06788AB2277225C -:1008B000DE8F74C85678A572D4BBBF990BE53FECA8 -:1008C00033332BE2CFAEEB52BAF135C99F11183B4F -:1008D000783C4B43E6E3E1283A5EB63BB65CDF1971 -:1008E0005B6E64D2F17014FF6F7E77E92F5E8BC26E -:1008F000B7BBF29C9E53C90C7D6FCA45A0A79377E6 -:1009000077B113280BC5EFA6207F5C00E41F4FAF23 -:10091000F8E4EE25BF780D9E932C15AD1C9FBC16F8 -:10092000A4AF1AD01BE2D9A125797C7DADD6A6D380 -:100930003B003ED697AD4A0BBC352B2FB801DF6F7D -:1009400030457A715DADA3CE8E437F76C5A80B94FA -:100950004FF0F13F3305E1F4B17D1AE1D3C79BEDD0 -:100960005EB4533BB21CDC0FFB8A1012B8DD326B55 -:10097000521AE68BD05C808F45D66C463E3DD92A14 -:10098000AF9669BA3613AD37586F70EDB0A86BD01B -:10099000AFDA0106648B82765E9F0B89E197B88E91 -:1009A00088DFE2B3161BFCF4B5F98B5AE0B9658118 -:1009B0002486797CD2675200F1EC5E6C2ACAEED9AB -:1009C0009DC7E54FBD2D6C9906CF355EB8AD6AA8C1 -:1009D00069C0CF6F3507FDC361DCE6AE92EEE17012 -:1009E0006B71F374B2EF80DF72BE7888F3C5C577A0 -:1009F0004EA3FBC2EC2A9AEF29982FC2E5D5CD561B -:100A00009AEFA9910EB2B74F6D13A8BC58B6501EFD -:100A100020E82743A679F0BE59B6B2C1F068DC746D -:100A2000EF9ACD50FFF34C910980FFEF6FFD09C5A0 -:100A300023DE67BC7F759F487ACFFB72A4AC1BE1B5 -:100A4000E96D7245DB938BB78901E4978BB7DDFEC7 -:100A5000F3C908B7D93795223CA6BA6F4BF33A06CB -:100A6000EA757D4F4A2D7F0AE972EA67D3FBA6A299 -:100A7000DEB50DE806C62D995810ED8FD7B65D4D41 -:100A8000FAF6E2EA2437CECFBB75D70C946FEF5756 -:100A90000F33D1BCF6084C4678B89BD3F0FE6241C8 -:100AA0000AC4C3AB45793C9E306D9443417FC3E299 -:100AB000B744C217A0B31B318E50BFCD4CFAFC6BAC -:100AC000B3DFF9CD5CCF009D09B337CD9A82CF3F1C -:100AD0006DA6E7FBF5A9AD1FBE8B7E01FC03C98E99 -:100AE0007288E067A43BEBA855F9382E23FD2D5EF4 -:100AF000DD94CFE3FB9746876C2BD021F0E3B34026 -:100B000027174D7F171DFEF952E8908D488D91DF14 -:100B100083F99E4ACFE9F1519BC2FCBB1C940FE3C1 -:100B200017805F8FCC97884E46E65BE839E9BF5661 -:100B3000EC7E13E0F4785ED0928F7A17F397A07C66 -:100B4000F646E40A74C53A34BD916DE5F9E1685F93 -:100B5000E0FA6F1CCA9E5A1FE59FC9CCD7ECC0BCF7 -:100B6000600AB673EE77177A71BD1AB2CE8E43BDA6 -:100B7000BAF1D33F535E85E320CFC7712811CA5322 -:100B8000327B02848F3ADF6F54B81C32CEAB2D9F7C -:100B9000DBAD8D9E08B5B3BF80D3BB1E8FDCD29C6E -:100BA0004471A12D9E909DFB5940DF83F667968A84 -:100BB000C4676CA5AD0CE5182B17299E33F5C22F21 -:100BC00018C6BF7E7EC57405F54A47E9ABD2109CB6 -:100BD00067B959AB7F7E6D36D4FFE28AABC83E5A07 -:100BE00091217A51AF9A599AA392FCF4F3BCDDA9F2 -:100BF0001752880E672D9D457AA53EDE00B3791DFC -:100C00008027B38158A3F39B675D61F73AA2F0EBAD -:100C10008FED4215D7ABBD29D78FE57EA1CE622ED1 -:100C2000CFA3E1B022C342FDFF3577DA6484EFD46D -:100C30002BF93A7CB0C71A5A0DFD7E608F6F47566C -:100C4000E5737F6BB6740DF1A5DBF658293E7F4640 -:100C500088FFFCAD6B45CA2B5ABA566021E8EF837A -:100C6000675ECA42BEFE875D2F65D5448D27D1FBE6 -:100C70000BF313F977BB1744DBDB332D3C2EC02677 -:100C80005863FCBB335D5A7EFE978C777C2BA19F0B -:100C9000FFA72370BC6FF6FBF9DF18111DEFE88F7B -:100CA0005B29DCCF6F8C57E596FFBB365E9E0FDD70 -:100CB0002C69E355AC3C6EB190C7C5571E1A4278FB -:100CC00037D3127980E259AF88B216D7F0DBE8FD4E -:100CD0000C5E9F605ECCEFCFF59491BF89C6237404 -:100CE00009DD4ED757981FE3710CE3FC6A0E8A7139 -:100CF000E3727F2D9079BCB3384276D5F1379EC030 -:100D0000C87B3FBEDB0FFA4CD179F4FDFAAC86DF2D -:100D1000D7217EC3FCEC6B7939115E27E25719F9B4 -:100D20009C8E75FC3EBE362705F1ED1E5B43B81761 -:100D3000E0E71753987D1894B5F8BFFA2ECF6315E6 -:100D4000A3EC1CA4836DEF3AC9CE6935373D8EFB09 -:100D50007ED41689ED82FB9EA486500B94BD662737 -:100D6000E54DDD91346B07DA7561507005287F928F -:100D7000746C07EA09CC96C2CCD08F5AA1BD6FB172 -:100D8000C9ADA05F3C96EC22FED2BC8091FC4E67C0 -:100D9000DD82000039989FCDFDB4CB5E1428FF188A -:100DA000281EF53E2527BE3EBA57A38B5F61020D74 -:100DB000C6E5A7C77FEE60BEEE179382E1283BEF42 -:100DC0005E41F112DF813FCC8F34B3BEB9C497418D -:100DD0008FFF05C883E1E28FC93F7BE2EEE0E3F1DC -:100DE000F649E8D705D3E3DBE9AF6BE32B6C174299 -:100DF0006617D1AF69470CFD6A713C679A0212060B -:100E0000E3B73C4E97CBF47CF94DE8B71F56CEC7FD -:100E1000E8F28719EA1719EDD7B0E010A4A729E97D -:100E200028DF562E8CF5A765D4ACCD24BF5ECDF758 -:100E300067A1FCDE6476AC1552F01AEB8FDB64F030 -:100E4000C77D115FC84848379333D0BFB16920FED2 -:100E500047F8D33A5F0E8902CD8245C7B5D35ABD54 -:100E6000BD41D483A6D9949DCA60FA61E54A06CEF5 -:100E7000ABBC80C34FA7E7460D35858302D9A58358 -:100E8000F9A106CFFA11044F7BFB1D64372597703B -:100E90003F76F2D29A20F29F64E03F68C7592C4D0A -:100EA00002ADFF146EB7AD147879E5345956E17987 -:100EB0008B4BCB97BD96E767AFB40783D1F1B4CB2B -:100EC0004D2BA645E7E5CA0CDE473E3C87F737D3F6 -:100ED000B68AE705074147CA1C80638506C7DCF26E -:100EE000249EA77EBB8DFC5B5BEDED345E9397DBB0 -:100EF000D935EBEDC4EF868B851437E93173FC509F -:100F00009D36A257A5E76DCA0F1B7E598657F4453B -:100F1000E1CF6DBC5EC70B66C82BB058BCBDE8BF47 -:100F20008381289897B252F0F656D0BCE488AAE0A4 -:100F3000BC35BE3C2E89CB11303733385C795CCC64 -:100F4000B05E8037DCAF3ED6C1FD462CE825BDCB78 -:100F500030DFC178B3BF10F96D4F3FDE7415C6E3C3 -:100F6000B70FBABDBD3BA3F18579D7A05FF53E139E -:100F70008BAC8F873F4AAC9D6FCC9333DAFB0DCDA2 -:100F8000D3039AFDA1DA683D2D647F34DC392DC08E -:100F9000ED8FC216F43F35AE024905EF4C3F28D81D -:100FA000B0BDC6392EB2BF1BBBF652FCBCA18A290C -:100FB000388C1ACD3FACCFF3B899C7F14066756253 -:100FC000FCBEC31DDE8EFBF23A96EA793C3CAF458F -:100FD000ED12B43C1E3DEF2B720CFD9F1D8297FC61 -:100FE000A0FDFBFB60FD79FECEA5E581398B033EBC -:100FF000B4C42FCF7BE29749932E218F563DD381E6 -:1010000079B289F3685FBF01EB6DB8165A3DA20152 -:10101000E8CB7AD96FF762FECE40BD0476A7AD4B20 -:10102000E0EFABD7DE709544FB72B4F2A147D01F5E -:10103000FEA09DC5F4173D3EC9D03E9A960EAFFE68 -:10104000FCB6D9D8DEA313B4B2FAB787FD30BE0719 -:10105000CDB1ED11CA68EF6341EFCF3BE6998E0D3C -:101060002306F476D0E3EF2E9834A0BFDFFBCECC7E -:10107000F6F1D057B2FC27DA07A5EBE18D1E9E579B -:101080006BC4F3F51A1F037B7806AAD6F7CE591E58 -:10109000C076FBF3DE0ECEF7A31DACE7BD35AE0A7E -:1010A000D07E28D0FB1F28C03CDADF9D3D7598A17B -:1010B0009DF901F9031A3F95B8DF19EC0701F0C556 -:1010C00076F021C21FB6DB1C42D74E875B65888F46 -:1010D0001D878449885F8C3565DD00B03F55E0DFB2 -:1010E00088F33897203EFE7C01B7DB1B0B2B36E7DD -:1010F00023AC9F1418EAE3EB0BFF487645C3FEAB25 -:101100002645EFDF5BDAF528DF07B6DB1C77DECF9D -:1011100017883C8F78FF0B143FF9202410CD2D91B8 -:1011200042EBD0DE5CB2C48496152B0DCDA73C59A2 -:1011300036C7C270FC8F1670B834EEBE4EC5FD8443 -:101140008DF00F48806D092C227D7BCB1C9B03E327 -:10115000D88D8535CB89DFC9497E34E58CE3ECCF6A -:101160007FBB3389F268D67799ABD04E2A03BAF8A1 -:101170005707F2D5A3BE1DC83F874C105B65CC3323 -:101180008CAF7FBF50C4F5873621A07EBB94E2228E -:101190002C3A9F795417B7BF7A0B2C31FEC9DE0267 -:1011A00089DEBB42ED9B8EB8F68A144E467BB89121 -:1011B000F93F42BF170B38BC1417629DE40FF4DCF3 -:1011C000ED25BBC9E609DF371EEBAF90C86ED2FD37 -:1011D00008E7F6A7933E36A530F82BC48B3231FCD6 -:1011E000C8B7116EF7495A7C89F395ACEB1C13D044 -:1011F000BE327BB83E63077D06F7895CB9EEE4CF6B -:10120000A6236FF504488F6020E470BFF9749BC07B -:10121000E32B06BD99C94A25BE3F43F34BE7C16A9C -:101220009DB2116AB65D1C82FE0C8F8AF07E032689 -:101230003004EAAF62FE365C97BF6A76E4460BD7AD -:10124000D7379A6CA4AFEBFA70B2A78FECC4FA4E02 -:1012500081FAA92FFC31ED1758A6E5A5F7E7874BD2 -:1012600061CA973F5790ACE96F6DDC1FC5FAC81F84 -:10127000C69EE5EB009A27E5D1EB70D7F3CAF5F6E9 -:101280002C5ABCB45EF3E702C0A8FEBF0A74BD705E -:10129000B5165FD5F3FE79BF4CF29645FB1D375668 -:1012A00033D647E3F2BA70BCF7A4054C85F0FE7163 -:1012B000C063C4B3E36B9343B8DF6BA3D0E7C7B895 -:1012C000875AC2E319467C4A2FE4FDA6F4446650CF -:1012D000DED5FE04FB8ABA62F715017F58FE3AF4A8 -:1012E000535AFA8E82F8FDA05B7BFF1A46F9E4C6DA -:1012F0007D45230ABDFF3BF71529827F275CC71672 -:10130000BAF9BE217D5F91C2D74BCFE330EE273AC9 -:1013100097D92DF1FCFFF0F65D242FAD6417BEFCCC -:10132000616F1BFA99CF975814DC479176D31B6DE8 -:10133000944F23484D188F34EA034FF8A65F563870 -:1013400009F7A5BDA850BEB0411F48E407A05869E1 -:10135000949FE89AC2AFD70F606FFFC485F87646B6 -:10136000883C8079ACEA21316E1EEB92C244FE00CB -:10137000FF9C68FDB44DCFF77227C5E43FB625C882 -:10138000F74AA4F74B09F3BCAE21FDADAD3FCFAB9F -:101390004AD7DF62F358E5A4CFB597F5FEABC2BEDE -:1013A00098B8FC3F6B74F2C5F3D4EC9804F34B642B -:1013B000B75D6A9E81110E6D09E4E83D85F1F7DFA6 -:1013C0000258648CCBB7615C1EAE92C054F29FEDA4 -:1013D000EDCF33E8267FF10B05E4F7B226CC33E0FE -:1013E000F967D2A1022F3E77AF39E0477B46DD6B2C -:1013F000D6E440E819F49BB41DCA243F1B2B0C8F84 -:1014000043FE28B96764E0B9066D1A7ED67DF93CC3 -:1014100083C791CF19F30C7684263C90CDEDE7BEBF -:1014200064D0CB76302EA7D483DCAF09E326BF5E31 -:10143000E4FE91A4AF0AB36D348F13AF58775A49C5 -:101440000F57286FA026439451BE7454979D42F9BC -:1014500075021457A4E3DA5B5791FD9A687D6AD749 -:10146000C6C671F5FB5F769D5E29E4FACE71B4EFD6 -:1014700049D0AAE42F5EB256384CF9BA8638723792 -:10148000F2109213B179011FDBA7513CF6FB0F5705 -:10149000531C56DFB7ABEFD7655ABCC5BB562239D4 -:1014A000E1DD2D84BC3E4E2626B2ED65139D1F0264 -:1014B000E26D0B8A4415A8E632B82D9804D453BDCA -:1014C0006D504E8779AD93D40C786EC7DBC9E47F3D -:1014D000BDD7E3D5F65170FB4BDD2090FE07ED92B2 -:1014E000FDACB601DE403BE1421E17F8B490FBA70D -:1014F000014542341EEDDAA6E551E8FDB53053371B -:101500005E4D02BFDE2B4B55F1F43BBDBD367393F0 -:101510000DE32D9191268A677E6CF1CFA178606AE8 -:101520003E437BB1CDD9B4B68AD7130FFDD81E097F -:1015300050FD37246E28306F2A8EF7371ADD18D702 -:1015400075617B6CD918EF379E4350CB8205993972 -:1015500083F7E5FF4693871FAFF769EBA250BCBC4A -:10156000CDECFDA50FE5E33A89E470CB080E37D347 -:10157000487ECD7657CE2139EC06FD94C6CBC79F69 -:10158000FD0D8F80F4D7E6E6F8F555C73DE81C81E0 -:10159000A27C1A6F1B1A0DD05FDB3A21C4E1C5C7CC -:1015A000FD65FDD559455FAF9C3A21284F75239EB7 -:1015B00039423F44BF5F6D8B55467E7646D0E87F0B -:1015C0009D48FC6CCB92542A1F5F9B477EA07EBA3D -:1015D0003DBD66399EAFF065F3B694228E173F3756 -:1015E000F8E16ACA85A3D88E11EE8850922E7FE06A -:1015F000D5E9D715CF40FED86062DE74D407D61A7D -:10160000F2430CF43CD51BBCB208ED0F4B5F2FE747 -:1016100053E17C89F46FBB82707BD47462EF4F100E -:101620005FF6DA29DFB06155E429F457BABDC1ABE2 -:10163000F0BDB377BE3343F05273A4279D3F5440AF -:10164000E775D4B419CE41D8109B97C2D6A6F2BC88 -:101650008F8ED8FBB85F3FE6BD41F92AED9ABE1DDB -:101660002C42FB62EA953CCFEFC3A5268678F1A118 -:101670009DE38F7ABF5393334A7EB45E5BA3D93721 -:10168000FDF871BF9DF0A356DBE7645C8F7AC40F51 -:1016900058B73A0D3F3E7CE1B27CC48FB37B2FCB71 -:1016A00047FCD8686EF7237DCDC90D2E2A82719D27 -:1016B000BC2AD06BE27C29FF52F0F676E3B8FE41FB -:1016C000FA55475122BDC3FBDDE8784B8F99FBC922 -:1016D000547BEC3EA19E4BF4AB26F68F15E5C6FA83 -:1016E000C70A73E3EA5736FBE7EA57973E0F46FB14 -:1016F000C4F4384C8F33F2C05351F05A69E7F928DB -:101700002B8B64592DC1F9D5E4D0BEB3DFD9949D9C -:10171000C2D73ACF183FE02B1772D6B4E338FCDCBF -:101720006FF98AE4EDBD1CFA7D8571BFA571DEBF3E -:101730002DE0F933BADDADDB81C6FE0F68EBFDB3FA -:1017400022FF21B4ABA75EB8487E84D3782E0FF475 -:101750006B0BFD2BD973ECA020D3BE352F8F8336B6 -:10176000EC5FF804FA5D9786B4F8E53E81ECF5A5E8 -:101770004F7E44F5E7BA6AA9DE7150E8C63868E3DF -:101780000813C96D3DFF41F7FF341E2C21BF8FEEBA -:10179000FF8171EC473F4DB2276221BE85F625BC23 -:1017A000D720F1F86E8387292AB2DAAE58BF899E16 -:1017B0001FB52560217ADF725008A13D9E6609FAA7 -:1017C00046103C47C894DFA2F18DB78BFC17905FA1 -:1017D000E9F96B7B72FCEF14F1BCB72CCA93D7D636 -:1017E00023D81F17E2FB2CFEF26BBECF229C805F3A -:1017F000FF67919E677B23E9CF7F618194F8F9E7CA -:10180000219E7FDE9FEFC6F3CCEB6632B6DECDCBFA -:1018100078CE4C3D9E33A370F9D96D909FD165CCA5 -:101820002FEB8EE29B75521FE5B1EBE7CA60BE5904 -:10183000F4F30DB84F2387E79DC5B4A3F1D37471BA -:1018400005C57FE2C45DBF1B6D7F1CD1EDAC127D71 -:101850005F4DC482FE9D952D9E08C6118E38B5FD44 -:10186000BE5A3EED4A7BE404FA3F563E934EFB4798 -:10187000FAF5FB3D56CD7FCEF1BE8EFF648D4B8ECB -:10188000939DDF88FBFA85017A9A99D02EFB692E09 -:10189000C6638EF4DB656FE4E2FE1B9DCFD6299C08 -:1018A0005FD475097C1F5667EC3E9CDCD15FAFBEF0 -:1018B000A03F97E8FD8AD189ECD92F8233E7B7475B -:1018C00012ED5FD2F8A40E47233FBA54F8E9F5FDB4 -:1018D000F003BA267E6B809FD18FA6FBC3589B4C2A -:1018E000FE32D0493A319F53F7877D5979F89DD11F -:1018F000FF33F2F0FBA313C9C3AFB63E89E4C4A51E -:10190000AECB207988EB332EB13CCC2DFF776DDC4C -:10191000C63C046DDC863C8423E6C82C7E8E05C064 -:10192000C737380F2121FE7D411EC2DF314F431ED4 -:10193000C2E7CFD39887F0F8A1C75C18AAC3FD6AA5 -:10194000E877E8D965A6F8FB0CD1E1E7F96122CF89 -:1019500027657E3A8FB3D16627FF82317F0E38D557 -:101960009A26D42FCB41EFC7FD3CDB5A492ED767CF -:101970008AE4ABC47C41D91B273F53AA4EE9F60E3B -:10198000CE13C3FC773A17E012F3C4F68EEECFD72E -:10199000F4FD9DF99AFB477F893C31258FF3A757CA -:1019A0001D7F1A127D5E66453118EAC589F3F47F02 -:1019B000A2D14DB296DF6B935416ED8F4AF4DE2F11 -:1019C00046737BE7554BE4ED4ED4ABA0198C7B6698 -:1019D00058C09A2E1DD8EF7EAA207014F394411F90 -:1019E000A1F53DB7FFB7E4EF7F3C93C99837FFB847 -:1019F00059A575568732C26B3D9F41EFE72ECDFF4B -:101A0000FD65F9CFFBFF60B9208DF9EF910B5F1BEE -:101A1000DF1994F7C4E9F1EFE037447FFDFCC4CC53 -:101A2000E341FA79175F28E7BE6E3E63C8D74834B2 -:101A3000AFBF1630C29FC23181EC31E417F3939FE0 -:101A4000F152E55F7229E843088F7D562F929A4D37 -:101A50003BD7826DC8D4FDA2FC7CC1074792DEF95A -:101A6000A19D8F573FAF439FCFE5630CF8F915ED6C -:101A7000582537F08D3130BF93D3FCB4EFF75E2794 -:101A8000D7DB22CFF0BC77E3F9134037FC3C0EEDF7 -:101A9000DC5FE33EFA6F1BC7F70F92DF0DFFDBE958 -:101AA000E812E5F7A5CF23D69E3DE2E4798503F65B -:101AB000EC7FDBBC2E495EEB79C665157D9ABF5F76 -:101AC00060E8EFD7FB69ECE3FB741ED2D653BFFF8F -:101AD0005BCDBFF7D618FFC388AFA5A5DDDB71BF0F -:101AE0004A0373318CBB3774DEB1FB4D0FDF7F4B84 -:101AF000E5421EAF640107EDCF7E3C2FB8750CC9DF -:101B0000C1F01AA4CF511E56867183F585B359AD25 -:101B100083F21042583F6A5578FB9BA59487D58481 -:101B2000F4AAE721975DFCD39AAA521A2FF97F3DB8 -:101B3000D6D8733B0E8FE1F24CBFBE3246D0E2AE38 -:101B4000FE4C1CCFD9257C3F6AA3C72FA31F598FFA -:101B50007B277BFB286FA0611F378ACAD056C4FA47 -:101B6000BB46107D35EC9B5682F150D6692FA1F310 -:101B70007E7FCFCFD93E7BE730F2374E290CBE8433 -:101B80007CC9591ABA06EDE851D00FC64DCFEEBD4B -:101B9000A62418876FA68BA92AC695D345D6F9889F -:101BA0003CC0B7C07E9E4BFEE23511F2633D3D86E0 -:101BB000DF6FF470B9DE78B09A2D740C941D9ED846 -:101BC000FD573F2BBAEA691CC7D363242D2F93E737 -:101BD00081FA400D43BFA1119F7C5A1E68B596E75C -:101BE000CC54DB407E73F617E781EAE3D3CB7A1E51 -:101BF00068F2A7DC7ECF962D9437E25CCBF92A5BA6 -:101C0000C5286E7045A46F7A0AC029B7A3FB0A8461 -:101C1000530A829DCE7F0DDF371EEE7B864857A08C -:101C20003F647BF3841ED47FA5757DDFC025F1B6AC -:101C3000CB15E8627C3C2F7082E480D454887CA968 -:101C4000E22D33DFA7B42E99F4CA8EAC3ADAA7742A -:101C5000EE1D6BDC7308F4ABCA566760DC217BEDCC -:101C6000AF282FC0B94F88BB9FADB2D8A1ED635A42 -:101C70009D81710CE7DA3EB51CDACFBE5F609A1920 -:101C80009D2964A07F5832A17CADEDE2E7DBD5B69B -:101C9000BB2B6C246FB8BF865DE1213922ADFBA65A -:101CA00009F984D4025A2CCCF3F2621E9FCEEB9039 -:101CB0004D28A7FEED33316E1CC9563CB0DF05C17F -:101CC000556F8DF466F806F27CF47D2EBABFA75FDF -:101CD000FEEC9B4FFE9E4BCFEB8EDC4C79839FA599 -:101CE000517C65A68BDB232088B4F35D62DF1F7413 -:101CF000BE8BA6B7E876B1910E8C79D2B9E5C388D0 -:101D00002E808F766E9163F85EDC7CE96689EBDD70 -:101D1000300FCB4A1CC7B40C05FD735F363FDD683E -:101D20004FF7EB399A5EA28FFBEFCDE7D6EBEB30A6 -:101D30008F3B8EFF43D76BDAF47DD09FF1F3B7462C -:101D400069F6C4F1F57F1DC7CF39D4F346427495C7 -:101D5000CCC03F097FC257AA8807FBDCA686628AEF -:101D60002F35503BEBF8F9FEA3D6E6AC2E2FC5ABD2 -:101D7000CC0480F7F103CB4651FC16E8222F0E5D10 -:101D8000BC3FC6CCDB5F974C782C3DC4280B52720D -:101D9000A7111E4B8F727C7D6F0CC72F3D6F4D8F2F -:101DA00003BE35263817F729F69FCBD19CC4CFE563 -:101DB000D0F2BF9DCDEFECC1F32EB66B71E09E5714 -:101DC000C6CCA6F8DC3A4940FBF063F7FC51E8BF0B -:101DD0005BA0E1B953EA63B2239A5E7B68FF60F6C9 -:101DE00021BEEF49D2F254A5759E1D889FA22F48AF -:101DF000FB24BFD1D62D521E947CF2912A2FDA1DDE -:101E0000110BE6AD7DD0224556BB497F8AF193196F -:101E1000FD5E4CEAA4BC9CE6E27FAC1DB2B138A1E9 -:101E2000FEF495F65FB02FF04F7D55BC4EE49FBA9F -:101E3000F47918F75D70FB84BDC2F39BE2CC2BC62E -:101E40007FF9B5CF4BF75B1AF3D506D131F77FE8B1 -:101E5000F6901E7F607E35269FBCC72C77A3DE835D -:101E6000F9B92F28A8573F6D8FCE27FB370DEFFB11 -:101E7000CFFD63213BEED73FAFED376692B216E35D -:101E8000A07788CE76B4EF5A31CF1FF54B84AF10D0 -:101E9000B5DFE15D27E53D344B7C3F0453F97E8A95 -:101EA000950B9B9EC6F757B6A4CB087FB5A2E979E0 -:101EB000DA2F61628156B87EA27DEF421F8F9EFFAE -:101EC0009F487E0ECAFFFF82FD0B9909F62FFC8703 -:101ED00086F7850B18ED5F606BFD3B705C1D2D1266 -:101EE000C3786F6A152F8F926CF4FD153BE6510F86 -:101EF000A1FDA694EF1C017862DEB61DF3A887E071 -:101F0000FE127ECEA130BB8AF02F15E0837A41AB62 -:101F1000999F6BA8DEE0207C9A5EC5E397A9010B30 -:101F2000F19FF34CA1BC7B15CF3FF3209EAD26FC67 -:101F30008C38D328FE9A9ACBF5487BC062B2F92838 -:101F40004F9AF03522E879D29CEF75CCF752FE7AA1 -:101F5000FF39870B19ADCFBABC1999F8DD8161D76C -:101F600059048CD7E872A642C38F8E1DDAFBF5FCAC -:101F70007D3C0711C7C756F2F7FBCF41FC1EAF6F80 -:101F800096C2748E10E830DA397CBC7EE5DC34A26F -:101F90001F51DBE7CA6ED2F2F4057EEED4CAB9C394 -:101FA00078BD8BF341766B9226CFB5F76F4F0D69F5 -:101FB000F1029E6FBFD4A49D1FD0CE62E2B91A9DDC -:101FC000A57EC17E8D8707F2EE899E5BAF9129AF1A -:101FD000503FC7B1C261E1FBB86CB174F542712AE0 -:101FE000C7FB72C586FDDEE2F3FBC6C6F50F87E6CA -:101FF00047F395613A5FB9D562B0CBD2395C5D9158 -:10200000ED7CBF97F592ECB2C471C5673263E38A89 -:10201000BB33A3E38AFAFA562CB1105FE9707B5FF9 -:10202000C3FCA32D005A3C17CF38EF2DFDE75B878B -:10203000ECA8971AEDC12309F28CE68FE5768F9212 -:10204000C00F317F6C22F992204E5B62FD6F8A37A0 -:1020500073FEDB93607F5F3FBC74BDC9668C7BA859 -:1020600097E4F7E9B1FD80F8A0BF5562F62BA16CAB -:10207000D88F067C90F8A2BADA2AB77A908FFE80C1 -:10208000F8623358AED628BE08E6E865C88F7BEE06 -:102090002EA4EFD9BC76B742D7F376A1531C8FD7C5 -:1020A000C83CD498163F77F8463CEFF9BC3392858C -:1020B000E743DFF3FC9BDFA1F2D0C8312CB73D270B -:1020C000CDA1725E643B9E17BDE5B935BC1E696C3F -:1020D00018633F187BD77754077D7F614D1FEAF760 -:1020E000A5863C7EC3F9B5B8DF14E793EEB050DCAB -:1020F000375DDBE7CB2A35FF10667A21DD65965028 -:102100009E9E8379F7F561FD082E77A1BE05CF4726 -:102110006DCDF3F13834E37C808DD0F238585845DA -:102120007F54ABCF4DEFF7EB77FBAC5A1E18EFFFA8 -:10213000E80BFC5C1F7DFF3263F248B41B1D5E168A -:1021400053D6CF8366923C12CF6F6DD5F0402FBF30 -:10215000941E0C8D8DB22B8F5E754731CEF3C31755 -:10216000EFCA457DEA6AED3B5046BC6A1CCFF17B65 -:1021700075F2DFE6211F7F5B7429E43F480FFE08FC -:10218000F9C6424FCB2437E04FA53C8DBE373345CF -:102190009D2B205F715FCFC7E7AE0C080B8B07BE8E -:1021A00043333428919F9E053B44D4B7879E0CC887 -:1021B000089F3A5B244B82767EE309BE80E3FC787D -:1021C000FE7BDFA7BCBC61478FE1B99247CDEDD361 -:1021D0005D884F3EED1C6126D1BE9ADEE1A3766A92 -:1021E000DFD3E1FB6BF2042D0EDB5D8972E15AC691 -:1021F000F116CB58FF4DED9CB419323F777346A9C9 -:102200008FBE8F368B4524C487196F075C0CE9E3BA -:10221000FA6069BC732BF42BCB307BA3E9E71A6F10 -:102220005419FE7DB330B6FC2D25B6FCEDF2CF0A75 -:10223000A2CBD592FF9708CF97052E7FD4C95CFE1D -:10224000C8AC7335CAC71F35C91328AEEE11542C5C -:102250008F796918E525B10C9ECF30DA951DE270B3 -:10226000C8D98AF38A809CDFE9C1EF2CF1F3AFD2A1 -:10227000DEB6ECC0F31598D7BB15E9F0457321E540 -:102280006DA6396AFEB585F41927CB233EE5DD4AF4 -:1022900078EDB479F1BB0F879D3C1FA1F52113C5E3 -:1022A0009B0497CDE487E7C49D1297FFCE25D3B159 -:1022B0005E2C83050159DDE3E6DF6D6A9DC4CCAB7E -:1022C0004B70DD94B7492F72DA28DFBFD255F85D25 -:1022D000AC175D163A0FE2B0B32CA8F5C7B0FD27D6 -:1022E0009D4BE87DE4D16630C87BECDCBF2E827D5F -:1022F000BC9AF74FDF67135730AD7F1BB360B986C9 -:1023000051FE7E8F5BE6E3BDDD44F110ACBF92C6AB -:1023100067A37AFDFCC281FDB2D3243AC75D605A3F -:102320007CAC85CA8F697CB0D52C1F463C55FFC05C -:1023300018AE47A5EB53A203D1E452E8BC1D3FCB36 -:10234000F5A431EEB380E7C534B91BF3D9C5152E1A -:10235000B29B51F3C1FAE1F893E85AF2B332CD35AA -:1023600043FDF98F231E8F125800D723388EEFA319 -:102370007DC2747413E55738025605FAB1DCC4689F -:102380007D95E4F8FB64C78FE3743A78FDCA323078 -:102390008F4370957BF1DAEA2CF7E2BE9F1EB7926D -:1023A00011882AC7599710E2CDC0BAD8BA4DE37048 -:1023B0003D142FEA175FDC1ED43B703E1A7F1DA62A -:1023C00078D10ECD75413BC0F79521F1E7111CC7BF -:1023D000FD8B9DDAB97AC6FA99E34C5FF73C0DF8AC -:1023E000F715E799163BCFAF719C61E16B18A79881 -:1023F00005E3730C8C0F7ED2395FD73A4C845FD7DC -:10240000EAE72D15C6EEBB30EEB3606CD566E4335B -:10241000576BF9A315C9FF4C7EFC6B40CF47B9D66B -:102420009BFC835CCCDF9C91D2D2C689A3E9EC42B1 -:10243000E4C73681F8CE3759F71ABC7F7E5AF0715F -:10244000770EF1FDDBC60DC5F3538305A950FED011 -:10245000DC9EBBDC477CF1F67193709C11A2BB6BD8 -:10246000F17B6C487733436D58863E9AE8DC2DA0AB -:1024700043A45B9D0E078F1FE8129E1FDEE4A2FDA2 -:1024800050DB58376D68CB60ED02F7B73491DC62F2 -:10249000DE9103F304A29D616BA279FCA44525F9AA -:1024A00070B5FB1109CB4F2AC1F538AE39E33FA215 -:1024B000F3F259C6FC02B43B61BCF7E13CFEA7C68F -:1024C0003B789FFAE7EFA3F847D9A3CF6B74ADDB56 -:1024D000A39E24D027609C5EC1A530D01FFBED5386 -:1024E000B38DF21206F6F5466A69FFB09012407994 -:1024F000A6EFEB35F2DDA95772BEFBE17297B29AF7 -:10250000CE39DC4D7669E3F50E7DDF2FE95F8D4B2B -:102510004CDABE5F81E44A03B3D1B943FDDFAB833C -:102520003F216DE0BB1E0770FF6FE9E7EDFFF5D2BD -:10253000FE6275158FD3F7DB77F532B75FF5EF43A2 -:10254000DC9EAD9FE3CFF594E5EC4BD9B771F60572 -:1025500093DEC8524C9AFDCAF5858EC95E59651442 -:102560005FE57AF85C0BD56F4C0AD1F7566AC576F1 -:102570004292E3E3DCBADFD34EDF65B228F9C82725 -:10258000F438EB9CDCE07F225E2F2CF66709309557 -:102590005A0B8F9F021D6CED83B7AA58D393F8BDD9 -:1025A000AE6B58D3AF4D3944076710DFE78CF9881D -:1025B0007FC76B800ECE623B36C6FD01D76A71A223 -:1025C000973F7CAA0DD7FDBCC0F8FEAE42E3FEAE3D -:1025D000C09FC7F17896F63D9E58BE13358E936620 -:1025E0003E0E8F28D2382EC41BC7203A6421EA1F22 -:1025F000D6B789F69F1BF0C8381EE1E01DB43F6EC8 -:10260000EBCD4C1627A31CEFB3233C472046E4E058 -:102610003C83C9E327913C0FE2B968BA5D3D68DCB1 -:10262000A283D6F5C6B9FD793AB332CB304EC4FB9E -:102630007D2CB9E151F47B34DE6C26FE5E7D702C7E -:10264000E969BDAA55C6244856C9F36B14F80FC7EB -:102650003587F9AF72433BD7C9D574CEDAF5338DE0 -:102660007939EA3D4DF0FE0D5A9ECF8DD79B8F47AD -:10267000EB9BE7CD1BCC0807B5D6D1244EC1F6A401 -:1026800081F77D83E132E89CA736CE9F18E839D8E0 -:102690007E6B7927F1A7447C6AFC787E2E14B455B2 -:1026A000F077E6FB5C36FE4BE4FB4CD0CE857ACD72 -:1026B0001CA1F33B5F1FBA78EB729867C10F8BE9DF -:1026C000FBA557A52D7DF221283FBD6534955F4FB1 -:1026D000BBF9B6A358BF3D9FCA95A68FE6213D140E -:1026E00096CDBD16BFFBFA9A9DB7939114ECA886C0 -:1026F000E732C6654FC003612A2D117AEE9BE3EBEA -:1027000027A23FA63289978F94FC760295B3B5F243 -:1027100084974763F935E1A379F1F8E29842A1BBC8 -:1027200008E46D652A7F7EE6846786A11D5F59C136 -:10273000CB639469EB72B0DEF4C779F1F4A505E3DD -:10274000F97CA75E38DF36C4836161FE3DD297FC19 -:10275000EFD1F73902206F71FF7EA09CC7E102FE26 -:102760001209BF0755E1E7E5E98E964CE483B38291 -:1027700096528CBBCA0E5F1B7E1F31A57CDA245C8F -:10278000F7E9A06E639C13E86B09C27FCE651F65F5 -:10279000B9482FD5E94B3613BD273EA7B19EAF5B95 -:1027A0002C3D407B2B906EE65C1E2B3F07D1AB018E -:1027B0000FAFB58DE0780772D15A3E985E8DFC9BC5 -:1027C000ADE914A2E9751BE2A54874BB1AC76531CF -:1027D000F579F1FE2841192D7F0EFD9E37BFEBA341 -:1027E0003810DC102F8FC337E04FD2F57C3E0A59EA -:1027F0004EA3FC659ED773F0B7F43E6E071133A964 -:10280000FF8771FE6C0D1FCF363CBF44447B2FF811 -:1028100004F289860CFE9D498CEB239D66E8FCAA98 -:102820002B76BEADE5CAAD6E71F0784D360EC7EBB6 -:10283000357DECADE6C0D01218EC8DACC98CF37DC3 -:102840002CD9A5623CB7B1869F43F92FE9C1271166 -:102850001EA2493D1486F242E6E7DFAF94FCBBC6F8 -:1028600047E95F0DDABA34D8DEA57C36FCC3F351F4 -:1028700006C1A3CBC84763E73FB02E7D9978CDC48E -:10288000F35772709ECA5A31CE7C98D4B42EDA4F68 -:10289000FFD817FAE919F7B72856ED3C95C8BC6878 -:1028A0007F5CABB3E9F1683B19CC323A07E9484B9E -:1028B0002E8B8777BA9E7444D0FC5AA0F7A23EF0C4 -:1028C00049D2DF483F018A0998B3D0AF358BF4185D -:1028D000C16293317E9D519341F8BA09F412F4B369 -:1028E000AB159D39E42FDF2E323CB760000E30125D -:1028F000DF007E7E383E9B7FF7AB1F1E2AF1518B97 -:102900004988AB5F7D38DEA49D9FCAF79736D8AC67 -:102910003CFF53FB9E859EC7D2602B5ED344F3B32E -:1029200071FA31ACD3A0BC16639E9C2D9DF40B793B -:102930000253501E0ECE8331DA092ACDE35BFDF13E -:1029400005C6F59F3B9DA4FF7C4B8B2F08B33FA58D -:10295000F54905FCB27A308EE015D05E492D3D2A4E -:10296000B1B103DF9FC4EF36A13FAB2B3BF87FC76C -:1029700047C5E3DF9CF434E5851C33F138A8113EEC -:102980006685C7816416A67CD5068D5FFD3F379CA2 -:10299000204A0080000000001F8B0800000000009B -:1029A000000BE57D09785445B67FDDBEBD25E924E1 -:1029B0009D104242583AAC4102762721806C4D80EE -:1029C000880A4C585450841B886C59059D41C73166 -:1029D0001D02880ECE84272A4F511B0444079846B7 -:1029E000D9D4C8B48088CF2D6E336E8F495C5925F9 -:1029F000864171C637FECFEFD4BDA46F13067CCBE2 -:102A0000F79FF73DF8B438B7EADEAA3AE7D4D9EA37 -:102A100054B5D8633BD19825F8CF8FDDF0FF4E49F0 -:102A20005FF61542053C02704088F642ECEE50E439 -:102A3000F052795269C847E5DF7ABB8518807A2D54 -:102A4000B3A89F1049EECC91491E027FF8F1C71F31 -:102A5000F3859882AAEE427CDA5D4BC47BD78BA2C9 -:102A600031564588E4B19A4D73093146A5FFE50911 -:102A7000D1B245093AE8F9687F8C45A4085179C874 -:102A8000160C12BCF055EA84E0858FAA4141708B88 -:102A9000F0AE6944FB80C31DA0F2A1B8FEBF1D4A81 -:102AA000E5678FDABC0EF41BF0BF9345FD96A05F7F -:102AB000827BAFB1088F539F17FDD727182B3C5946 -:102AC000AD70DFCDC926B85FA8A3A9FDE57BBA9993 -:102AD000EA7DE1CB4CF5B987724CF080862B4CED4A -:102AE000077E50608207375E6D6A3FE4C824133C5E -:102AF000ACF90653FB11676799EA4B130A0F2EA630 -:102B0000F91E4C538532488891A2D4D4BE542DB3BB -:102B10000B0BFDA3CEF66923BD57457F999EEA7442 -:102B20002BF07C668F22DA650A31778DAC37DE9B1D -:102B300057BF6A790695F383E6E7A5C2DA0AD37B25 -:102B40008B3F99FFD68188FE7AA7145B92A8BCDAE6 -:102B50001B9FF2651C262C06FEA8325DBD61D0E9E4 -:102B60003DD5EB90A4603A2FDCAA04EF253AF6128B -:102B70003D1F02DD88CE22E8015D657DCB5A351808 -:102B8000A07EBEAB9EF7D6011BC18772D73412FD63 -:102B9000E7D638DC2AD53BD2CCF48CF198E91997EA -:102BA00065A667BCD74CCFC441667A26F9CDF46CD4 -:102BB00037D64CCFF645667A76986AA667BA66A687 -:102BC00067C63C333D3B5799E9D975B1999E9981C8 -:102BD00005A6FA68FEEDBE62A1A9FEA1B8BD5F6AB6 -:102BE0008487948EAADB414BAF67DD1DA6EF097584 -:102BF0009C7D19E1AB344315AABB950F02F457AE87 -:102C0000EB2A5E5F73880F1E263A9C112B0F6678A5 -:102C1000CEE7878A3DABEC589F3F951F7E0D3EE87F -:102C2000DBCA07C47789F8CE8FF833E2FCD2A0F371 -:102C300044AB7F9597E4C806AFB61AE5D4DEDF74DF -:102C4000B192DC1045C5BD8BE2857089E619E0A71D -:102C50000A91E0BD17A5F3934CF00BFE38D2E97F43 -:102C60007ED1C34A785374BC892879A6D4FF29132E -:102C7000F35E4BCCA8A2FD849002F9D54934A4435D -:102C80003EA58B2A05659AF0AE50316E4FE756F996 -:102C900097C184B184E9FD0F4B6CCCBF4BE2FA6F56 -:102CA000015F7E502BF9F2349A0C16E20611B2E164 -:102CB0003B1FC63ED219FD1510C295C1A8ACBB0979 -:102CC000E39F8EF17B85B84934DAF0F19942D8510F -:102CD000160B0F97B385DF8EF76F16E1E598CC1FC3 -:102CE00053B45DC04785AA754D053E3A3574819C45 -:102CF00015AFB7C3A02F8857435EBF8B7F52BBE38E -:102D0000DEA2BDF8CE28A7E7D607083FFB2C625EFF -:102D100088E822C6B5E3710B6B51BF49FDDAFACEE4 -:102D20001296EF2F289A067C07D29DDE8D40725AAC -:102D3000E81985E67759B227E7DEA4D6F66F782D35 -:102D4000DC9E582FA050FBA777C432BEFA76589766 -:102D50008C79FDD47E3FF4FADFC3B88DF6179BAFB4 -:102D6000DDEE5D701BF5DBAC88AAF53488F774BA2C -:102D70006438887F68BC196A82B716748B9B71B0FF -:102D80003DE1A1A283F629F4D2D4EBAF5A0E58D973 -:102D9000D7CEB390C677AAB8311FE325FC7F89FE52 -:102DA000CB9C847F9ADAC9CE5AEF44304591C43F18 -:102DB000FDA35F519BE397E339A0E37F7707ED1411 -:102DC000FAD96769E8E2051DAD0DF94C47B79CD704 -:102DD00049BBC4CB85F05010D7793AF05FE27078E8 -:102DE00055C2678122BFFB79E2CC199534EE9B2D49 -:102DF00045A961D534EEFFE071BB8ABBA663DC3622 -:102E00007DDCCEF63ADE3DD95857171A772DBE4FE6 -:102E1000780AFC4A096ECCC4F3F05380770BB7FBF9 -:102E20005E1FAD398BD4CBCD354A703DD5BFA5E300 -:102E3000F9511BB5C3BA748AE41A1ADFCF862D5B29 -:102E40008776BFD69C3CEE8DC27BD9EA4CD043B08E -:102E5000BCCFB85B09D6123C4B7899EF4B445197E5 -:102E60001DD42EC3A7A5FA681C7F8EFBFB804C0BDC -:102E70002FE301EFD177762DE9E0BD17D0D04BE3FA -:102E8000FF2C921CE87FD278A9776ED6F1364514D4 -:102E9000F13ABD4E5471490BFE6405B59B4AFFC221 -:102EA000FA24B81FC6370DB0AF755D4F170D5CCE55 -:102EB00010EE171BE95BEFD474B8ED766A33C9D214 -:102EC000DCC5AE629DD2BACD64FCF7F311FEBF1D26 -:102ED000F3F6610578BF93E418E8BDBAFD25F1F17A -:102EE0004445E293D6ED00E081D66D9ECF12B17ECF -:102EF00046B797FC6775F7FC47EB870463427AAAED -:102F000010574A51281E3A9D2052689E0DDDD4A0CC -:102F100023137AFA4EEB0E9A6703D9130ECCDB5FBC -:102F2000DCF114D58F257D7BAF94AFF1018227F8BA -:102F300055712FF341E3D2F9F4FCF541544FED5FA5 -:102F4000A911F17904BFE2B3796B890FC79CD50E43 -:102F500024523981E47E985A5F9DB66A34EC83B17D -:102F60009D488F44E889AB7B98615A089D40A76BC8 -:102F7000747C8FCB36EB9D09D03B46FB36F40EC9F3 -:102F80005715F8BDD1A7EB9FCBC465D03FFBABF77E -:102F900088CF48BF187A6814CD30947D613D64B500 -:102FA00017CCF631DE3C76AC8F59566A0F7CBBB538 -:102FB0008E1323D6CB4BF90AE3D7438AC742F37F5C -:102FC000EB901A047EACFEF010E06FE18B0AF3E99F -:102FD000233EAD02DFFBDAD638077CD330343751DD -:102FE00050FF9F56D3407AD3FAAD760A3FAD852F76 -:102FF000ABDD0C1FA94EE3F258B587CB13D5595C56 -:10300000FF75B597E1FDBEA25FE07BB3567C63D54B -:10301000B2D17F15DB478B6AAC02F45A14BF50C2A1 -:1030200036A71B42F8EECE072D7104DF1D54BCD02D -:103030008BF3770497C34C2BADF7DB5D042FEA9C31 -:103040003CCA85F60F28CCF5730E551DC474BF7E9F -:10305000EFD3EBC68BD6F9969F5584464B2E7B80DB -:103060007F39FAFFAA7A108FEB68B59FC7E5AF6F7B -:103070003AD88EBE77BC7A2CC3FFEE2B5A09BEF528 -:103080008B6FD88E18BFA5C90A3B638C5FF183CEC6 -:10309000C3FD2218247CADB149BDB286F40AE4C058 -:1030A000C87E931EBD5540EE6B0FA29F6B93678F3A -:1030B00081BD3A615031DBAFD7FF20D87E35F8FFB4 -:1030C00062EBC8231ABECEA0FE4E06247E5A76BC02 -:1030D000CB708B95F04333DEBBA3B454907DD0729C -:1030E000F61DF99CDAB19DBA53B65B6893ED16EE06 -:1030F000FC75323F57946611A1EF8E131D05E12137 -:10310000CE99F1E8E7849FE35B7F91A645F0D7F184 -:10311000E4D0B71F414EFEBBC5BB9EF954FBEC7912 -:10312000C8D1A56E96335FDB425F3E0C39DB99F464 -:103130002AD757C54D223EABB00B8DF94E687D01A5 -:103140001F8F15338B5CB23F4F6FF91CFCD86BDBC4 -:1031500043DD7EE969ED6F73E8E68F1E061DB67DDF -:103160009C70198DB78F2A422AE62FE438021B6221 -:10317000B99FB267EE49F613FC94225A54E6F72041 -:10318000F3F3AF6D622AFACD52ACF6C5C9E457DD50 -:10319000B73B03F3EEAD8A2A95D6E5ECDF3C97F119 -:1031A0001CBDF724C92295C6FF82CDFBF51E7CF716 -:1031B000511A3FF5FBE47DE539908725FF32FF3258 -:1031C000E0E18F105A4487DFEDDECEF602F1A477FE -:1031D00014C9B57EAB5F5A924EED2F5FDB64E948B0 -:1031E000A56F83528BB274CBF6776AA8BF5CB7A584 -:1031F0000AF6EBC73E0F8F2B27B46EBD023DF0C31E -:10320000131DB12EB3577F53D0515CD8CEF85D97C4 -:103210000F5A8A3D2C17F8FD9DF593DFBD51C08EE6 -:10322000210B06E32DB67B59AFD1B46DC0CF8EEE26 -:10323000EBF0FE2E4B80F5556096B4734E1605FEEE -:1032400015F32FA7F60182CB7D0D4DB7537D795233 -:103250003711A0F91F092E9A86FA818A70033F154B -:103260003B1E28EC48F0C9A1C2AB50FFF3769E2E5E -:10327000647DD8996C757C6F476DEA0DD087D90550 -:103280000354AA2F5243DC9FA894FD55D66F7702B2 -:1032900026D427ABC46749F523F767785AE96369F1 -:1032A000FC4DA695BED79EF429C6BB2633905EE59D -:1032B0006AD5BF19BEA21F587EB9EF2FC677BEA030 -:1032C00071C13EBB547D69B754CDE7F1A409776065 -:1032D00070EB773B5BC2F3310F5A1DEE007D67A3A5 -:1032E000BB611AB723F8B7DCAFE6CA1900FB8AB096 -:1032F0009E22F57B2DFA754FEE027A5D6AFF0FC5AF -:10330000FD9DEDB44A4B82D791D76AE74C6D57FBD0 -:103310006223D1EB910E5A1AFAB959B79385D5EBBE -:1033200081DCBFA3833F3D87ED34D2C316D6BF9D5A -:103330007322ECE673769BF3D2F4EFEF3AF8BBE33B -:10334000FD4B6DEFD1E312E7E4F0991C931CAE8DB9 -:10335000B70B1F3DAF5DEDE038863860293B48FE76 -:10336000CA307CC2D2FABD45F1391DA01F6A8568FA -:10337000135F7B69FD6B84DB30E90D8DE4C0F0B336 -:10338000CDAAC672A2617F621EE4ADF0C77B103782 -:10339000B0082D423F467F87E85580F98D14714271 -:1033A0008BD0B37E9164C7BA15AEE44B9C77F80915 -:1033B000B3FED9F744E4BC87B67C1007138CF0D178 -:1033C00001E585E6F5A23EAF3F605E543E9F5F3467 -:1033D0002587BE3FEC2F6E2BE637CC3AB18BAF1B67 -:1033E0008FFB068C7BF85F2CE671FF106B822F75CC -:1033F000FCB729E4D8818FBFB107B1FEEA612BD0B9 -:103400003CEAE76707B1DE77D945C009BF67929DFF -:10341000EDE0FAF8403CE46ABDE20E21FEF482AD34 -:10342000619AF48B847BA30FFCFBE623E0FF1B5A1D -:10343000EC0AE2591D1DE24BD857424D141B532292 -:10344000BEDFDECD710E157A2397E0C1FAF36976FF -:103450007E5E6B13AC2703D362795CAB93AA5EEB01 -:1034600047F5AB6B32BC3472F18108AEE886FA3BAB -:103470005596E7432CEB373E08BF67621AEB99D5A8 -:1034800049E18C4AB49F7F993740FCB0EBEF2AEBBF -:103490008FD53E7F7AB20B7290E43CD179F5447FB0 -:1034A0007A6C0ACA540BE6DB91E43C3FCFA4765415 -:1034B0007E6493ED3ED4E946984E87BC7DB8A4A7C0 -:1034C00080FC599753703FE8840A27F1F3B59204C2 -:1034D00062DACD0F88DBD14E53836A26F0F29BFB74 -:1034E0007A117CC32CD58D38DDB5F3629A94FE54E5 -:1034F0006A6AD891402F4C19E38FF4D7D7E5F8EFDB -:10350000079DCB437DBA7F1EC1C7D36EEEF973C84A -:10351000874FC98F86DFBD2C557B84D7E91E1FB727 -:10352000DB43C6CD8FD0134E4F7FB6B74B0C3F3326 -:103530003C1BF8DDDBEC643BF642FC2084D77919B8 -:103540007DFF418B08819FBBEA7ABD160100D0390F -:1035500014C37C307692D3CFF12A97653DECE8C74F -:10356000895ED06F819D0EA617094AA6DF837B3B3B -:10357000B35E9AA9CBB1DAA9B1FC5EED765BD0025D -:103580003A2BC1A736E1BD1763587F96D905FB2BAF -:1035900065CFF7653ED865F7672E43BF7B1D526F39 -:1035A000277812B9FEDFDA09D4BFA0EBEBB2D870EE -:1035B000AF24A253E7F65A3DE8417C57C5CFEDF260 -:1035C000F9E160C13AAC4B41F64DDC7082857F1D5C -:1035D000E45580ECA08D5E493F8C4BABEDBC1EE307 -:1035E000D5681CA0B3B843E5F91CA6B58CF91DAE8F -:1035F000EACCE352268D4DBF99EA3F5B18C771D7DD -:10360000C34507CFC00E389CA6F2BA270975DF4024 -:10361000AA279DDB702FC195F33F7D73203DADA898 -:10362000FDB0CB1E4F2BDEA72F291F27880FA62FFB -:10363000B8738248B8F07A9D5EE6804FD9BABE85ED -:103640001DCE9D8449AE1FCBF17F8879DB73B54FCA -:10365000C00F95D9646F131F7D6D6F780C7195CF76 -:103660003CDA9FF1FCD4735F6DC273616DEEC5FCF3 -:10367000E16C2C445CA6CC22E34A0FE56A5FE03B98 -:1036800096C604A65F65C8C1F48BCB6E9072F1CE6E -:103690004BD307C7EA37EE52A89FD2D8FA0A2ED5E5 -:1036A000607FE8ABE34A3841E9CEF8D5B0AE4EB81A -:1036B000C309A08F6691F65EE9E6E879D25053110E -:1036C000771342FAA921FB101AD70212BD0FBBF1E2 -:1036D000DCDEDA3EB3958EF41DA6A3707D32E3974F -:1036E00068FF549F9C7B09EFA5497B7E3324F37CC4 -:1036F000FC45C3C67CCE1F8FBE4E8AC2095827C761 -:1037000015B94E4E0829BF029B63F478811CC7D7B8 -:10371000CF75E071A4EAEBE86B456FF79443B623ED -:10372000DE833D53FA7BC9770FDABCAC3703A44F75 -:10373000202F4BDB49B8D491E686BDD5510D586298 -:10374000C197D582D70B8D8DD7E5F16D19FCBE21C0 -:10375000D7449110906BA5DBD2D74BBB4EF79B3172 -:10376000016ABFE077B23FC090FFC79ECED0FB9703 -:10377000EB299AAED178C8CE9571AEDAF8FC0EFF7F -:1037800028BE9995F6F15A88A0076D725D07E2A5EB -:103790001E21BB256D623FEC4FD84DDFFD3ADE3E6A -:1037A000D3EFC23E85F9B9F1BD41B9D2EFEC1A456C -:1037B000F78E6AF34BB097C41382E544F43846E0C1 -:1037C0003DA2DBD34F9FA3B32AE94E8C64F09787C9 -:1037D000F1276CA0CF8776838EB766905C2F05AEFD -:1037E000BAB5E271974FCB801EF91A30E17B5712C0 -:1037F000C1D9B0B7A4FE3060831ED17CBAE4C3390E -:10380000198D904FB9D23FA88D49E82F12517609F2 -:10381000420ED4105E514F7A70665136FCE1B1F71A -:103820007F6E6B9DCF97D57E3FA9A073F09C353EF0 -:1038300027D6E7DCB53EE7AC087AD46ECE3DE4216E -:10384000BC9FD86C456452D45A83BFB92205CFD5EA -:10385000504070BD13F83EE1DAF726DACD599B945B -:10386000A346C8A7B96BC6F84B22E8D077B3992E08 -:10387000FD4266F8F23D66F8E7A4DB31BF9FFA9E91 -:103880002F6C86730F99E1DD839AD51FA19F5C96FB -:10389000A05341D9A2FE08F91E5483F033BADE5971 -:1038A00034793CC147D6CEF682CC73DF5F920FFAF3 -:1038B0009DDC79F7AE727AEF48B2C50BFFEAB80823 -:1038C000FD713CD1634EFD2ABBD583F99AF97C97F3 -:1038D00045E7DBA7651C707ED05C7FBE7CA8D1E38A -:1038E0004E222B92AFA2E94FFD5EE7A781952D9E58 -:1038F0007C3FEC9F79E388E1697C8343ABECC27544 -:1039000029FD0418AFD604114EA3F135DD1DCFF10A -:10391000972B168F129FD1F7CAADEEFC5FD23C6792 -:10392000391577C0DD1A576FDA9E5E017DBAD16D09 -:10393000F1928F23DC83AA0E66E4C19F1021B71792 -:1039400071FDBB96C3EF9F5795C0F8992F821C97C6 -:103950009FB5D4D12A1FE9BF929551E3591D514F0C -:10396000F398B7D6DC7EC1861F1D91B0E1975E51FA -:10397000BF4EC57C6FD6C7AD0626B05EBE428F5720 -:103980007C8EA6A46FB6762FDA9D8BF6AB47CA7AEB -:10399000AB53D7B37EF6F3CA5D760FCB33EBDBCBFD -:1039A000797F87D621F4C3A1F8393F87BC3BED145A -:1039B0006E870FED3586BF6C27FD42DEB7A0F6A7F8 -:1039C000D72AACD7CBDB49B8FC09258818703982D7 -:1039D000B6809F9471DA321D1FE0137FC47C40AF24 -:1039E0004858D419F1F130FBBF1555C20B3B4010BC -:1039F0001DFD06DE783F2A6C3F023D1B50420FFB47 -:103A000060EF99BF53B9E74747247C2EBE4CA4AB67 -:103A1000E1EF07198FAA5DF821C7D5BB62D96E27E0 -:103A200005100BFD6ED3ED6BB122D81EFA6A35F48A -:103A30001595CB743B3CB04AEAABD549FE5E6ED4DB -:103A4000AF4AF7020F3728BA7F0BBB3E09F6F53EA7 -:103A5000EEB75971BBD727A1BD08C4A4B07D2DFD19 -:103A600084BFABACEF9AC97E5F0F7BDD170A633C66 -:103A7000AB1FC8647BFD0543EFDD1723EDF9F3EDC4 -:103A80006EB6AFC4FDD27EFC4808E9F7F6D0BE039F -:103A9000DD67AB45BC1955B2C49F8EEF964CB25B47 -:103AA000400F31EFD2F645365A65FFCD345FC4EB97 -:103AB0003F578A0E5A22EC60679ED40FF905FE4DDF -:103AC0007A3B2FDA9558DE663C9458841BFEFCC680 -:103AD000B3AAB012BCB1CE115C42AF9474F3F75AE2 -:103AE000988DF7647CEAB04FCAFBB83CE10F52995D -:103AF0009427F555529EC5548AD132CEF2798CE482 -:103B0000C3E9A2A890F7073C52DE47CFA3B3FE9DBE -:103B1000127B83793C9FEC67BA90CE732F017F8F25 -:103B20009676C7E7B728ACCF693EBDDC04E7FF4B0C -:103B30000CC7173FD7F591815FE29F0188A31972E7 -:103B40002B49E797D5F7049F8A217CAFB211DF801C -:103B50006EC4371BF398EE6C17AE9E96CA74BF41C5 -:103B6000A7ABB82F9EE936C4629178BE2F9DF14C69 -:103B7000EDC55FF1DE188FB4E72FD10F23BA0FC860 -:103B80001B70BE3F66D05B588303FED1FE4DF9EE3D -:103B9000ADBB02C4FF0B7EFF4082A07647AD75A986 -:103BA0005E7ABF6CE3B2043F9547AC810437F57F82 -:103BB00034A88E0DB681EF453A3F60FF4049C5BE3F -:103BC000AB94E3C79EFEDBF23B689CDF2AA219F2AE -:103BD000B162C7F7CBEFA0F91DF43B9B214F8F5883 -:103BE0001B0B2177E717BBAA6ABC58BFE638FE82D9 -:103BF000271F48F530BE031996345EFF1978AF626F -:103C000083CD0BBFAEE23DD5EBC1BA17CDCB31BEF4 -:103C1000E8F72B439FD9817FB74534771AD246BD49 -:103C20006864395FB9E3D7DFA809288F7E04FFA253 -:103C3000326AFF609EBEBF12BD8F303BCF9CC74033 -:103C4000F8E13C86008DAB27B38B8C3BD73EF5501B -:103C5000FF26D80D1B5E4B50B25BF70F8C7D9796FD -:103C6000D0ECC79FF75C785D7EADC78D5BE926E53C -:103C700098670F0DAC83408081CB325B3801F67EB4 -:103C8000D93A1BCB91B2AD4F6C7A18FCF6A1C3DBCD -:103C9000D303F8B41DF2A04CF1372B2CDF458292F0 -:103CA000DF4AAFD2AD5F143E02FB3A5D15E3885E9A -:103CB0000B9E3D23DBFB45730CB52FDDDE5408FF67 -:103CC000A04C735539DBA0D7A8D04BF646571BF450 -:103CD0000A3515729CEAA9EF981E47F72AA243E617 -:103CE000F9EFCF5BF7855D48FFA0B95D92C417F48B -:103CF0005D65482DB6279EDF9EBE3FE1F93CAE775D -:103D0000C35FB9181D4701178813EC8E1749D0DB24 -:103D10001F3982E340DF6D8B1204F1FF57D62AC9A9 -:103D2000F78F2E4B859D37CF16487573299FCF7B14 -:103D3000EC36E6C7B94A55AA3B9BF93DDD3288E728 -:103D40009B8E79DEBCF65A9EE71CA1313FCE7B5498 -:103D50002D0A5279C62AC66E6F63DD9CD4E5944362 -:103D6000DCD21FEBE40C7D097AFC2BDDAF0FBC230A -:103D7000FD6987989418B99FB457978B01113C0C33 -:103D80003D50D960E33885FAF699427CE7D64C6B12 -:103D900015F23D68FE011D5FCA8FD27FF120EFA1B1 -:103DA00012FF227D3AEAED311D1AB3F1FD16FB4DEB -:103DB000D4EF5FE0277A4DEF31DEBE5AEF88552E03 -:103DC000A73255DAEFD1F3E8344031ECB877440448 -:103DD0003F556EFE8AF949A4A922314DC2D8BF7061 -:103DE000CF72552512DEFEF2DE6776C4BF032916B8 -:103DF000D113E36DF88261E16DEF417BE3FB957BCD -:103E00001C221CB96E377C11B5AECDF54254313E43 -:103E10002B45A207FAFB2B7B73E10BE887FADD4801 -:103E2000FDCC21FB2B6CB2AF9A0B1F813CD9637781 -:103E300073FC81ECCF7004DF9CDB1FD5F705E7EA4C -:103E4000F2201A0FD1F2E1AB28F960BC2FD6B6BD33 -:103E50001FD52A17022C4FCB6C22003BA3EC430743 -:103E6000EB8FB2AD723D0A92A73D697D1CDFB2FFB8 -:103E70008F37C09F0DD952C671AF66F93BEF992FAE -:103E8000785EB309FF315EC8DFEFECF07FD346897F -:103E90006607F68B57FAECE0FBF3D6313D6F731DE6 -:103EA000AF5458BEFD57E52EE1DB0E7BEB62EB75A0 -:103EB000EE05E46EF20073DED019919D380495EEA4 -:103EC000E2AEBC7F10855F03AFD172F4E93C4F9B3B -:103ED0007294FEFC5144E0518846E6E36F492E623D -:103EE0001FAE62C3F7ACD708ADCD0EE2E38AE03770 -:103EF0000C2F835E63F8A52988579E3F6F333EA33E -:103F0000EBDF03EFD3D08B9EB3B15D50562FF31C84 -:103F1000E93DF63B2A11AFE7D67507335222E1603F -:103F2000141C8A6AEF8F828BA2DA6B517095A97D7F -:103F3000D99EFDEC67D1B84DED1C8BAF613FE47CA1 -:103F4000BB22C878ADDCF18D3D00FEE8D46C875C07 -:103F5000B42D1181787ABFF94595EDDE539EE604C4 -:103F6000D829CB62A41D77CAADC349062C6616D3E7 -:103F7000384E05FABB9157D01C23E32DA78A9A131C -:103F80009222FCF6A67A35C143ED1B83626CDB7985 -:103F900031B58CD74671A17A69CF8D517FD826F380 -:103FA00045ADC241FD35D67CB70DF1A4CFC97F82A6 -:103FB000FD5252737D02F65F4ED577FFD954F881DA -:103FC000AFAA9CF325027E3BF226664B528A23223F -:103FD000F0E0509A9F1A9F77F005F857C428D8FF51 -:103FE0002C591965DF88A2C430FCE9D5D1F90D41FF -:103FF0003BEC9BB9A467218FE6AD35D72FA83FCE08 -:10400000EB6541D47AD1F4B871F47A596CAC179F4E -:10401000F0E9F9969CD777EA90CAFCD5B2D42696F7 -:10402000A7C8BC5AE4A3B4D4CB7C9D963D1216011C -:104030003D0F485FB706DE4E603DF5BEB0DD7262F3 -:10404000E7BFE7FF12FCB3EBE3FE8F507962D7873F -:10405000BD5E00BCFB4F5D3E16E7B71FB5F7FB1911 -:104060003CAEBD0E81719DDAFB4A17D81BA79E7727 -:10407000703EC2A9250EB6D7037BE3396E71AAB391 -:10408000B4876B5FFCAE7F23EBE3A54CC72706D854 -:10409000A55D55FF37D68F2DF50E0FE651B9378E3A -:1040A000D755E5F331BCAF76EAC5EFF223E371FFF4 -:1040B000D5F918FBF0A7E2C5D467C0BFBAFD5FF918 -:1040C000C2E0276AE02FEF78C93E1B79257FF88F81 -:1040D000FE90AFA79E7989E5EFD7B6C6C710DBDCA7 -:1040E000B6F3C0C3B674C4F5E8631D85B87297F51E -:1040F00046AC9FF3F122F1708AF08079115EE6C13F -:104100002EBF103E5EFEA7C5C73733A49C1B28B048 -:10411000EFD38A17C52F9FC773BC8AE62F9FEFFD89 -:10412000AE3FE4D0C5E6FB19E6DBFEFFCE7C95FC96 -:104130007FD6F94A7EBF678087C719CDF7E7F3F5C9 -:10414000EE9F33BC2DDECBE3BDC4F59E99FF7F8B84 -:10415000BF47FCD3CEF762F47E55A777BC1BFBA00C -:10416000A75EFC8F2EE227CC7BC6FF523E37ECF9D0 -:1041700002D57BC847ED5F13A1F7BC996C95B46974 -:104180008FFC3ADF88A7487F6A14FEE541FB9CA5B7 -:1041900021AC07B227E0C7D4BA720EBC4DF02B6435 -:1041A00027A8BC2F2BE349AFA4F98232BE5B2510B0 -:1041B000CF2AF8D36C865FF75D7900792585AA8CC4 -:1041C000C7ECAFF16E68A079EC4FB2786A091EDDDA -:1041D00069F6E7DBA9DEDD5175C33FABED94EBF487 -:1041E000448C6FB4CBEC675D13E5275DE531D78F69 -:1041F00015CFA460BF6E6CB64DE07C4E21DA47F857 -:1042000095F3F3DD3CCFAB44DD52B7EBA7E3E939DF -:104210003DAF92F0C2FB36814EAA9E1767C69B0047 -:10422000DE5280975CB6DF03C27BE06D82ADBA7D63 -:1042300025F4FDC74267FC26F8D10E51100E127C02 -:10424000C663AD427BAB207F58CE93FDE868BC09C6 -:10425000DDAFB6EA2418DD69541878C6F3AE69A656 -:10426000F779DED178FEE978DDD76911F09A16EF9B -:104270000D822F3A3D9B82386B2DE159515AF169DD -:10428000E0291AEFBFA1B14A7F5DE2BB93D567C5B4 -:104290003A1BA6DBF3A3AD4912EED4A016F1FA0B3C -:1042A0004ABEFE8BD70A7B64A42B89F349857ECE58 -:1042B00042D5F7C39161C7E320FF1479B913ADDA92 -:1042C000ABF99C8FEF1605F05B0B4408F15BA5FE84 -:1042D00095EFE11FE17C4911EF6B1EFC00706FA7A9 -:1042E0002B0C7F50ACB59E38672723EE1F75BE623E -:1042F000C2A0ED2341AF598BE919E2586ECF41AC12 -:10430000C7E2FB1D1ED0AF93B581EBC9D772D70CA6 -:10431000C66E7588E1D812B2F4D3D1EE9591DC7EE9 -:1043200091702B4948B70B29805D6E99AF46CEEB53 -:10433000B780ED4BE33DB5326E22C04F3D5076C3A2 -:10434000F765FBB4D1F43DE4BB098DEDE5D81E1C47 -:104350000912DD9422DE7FEFDA5DE645342F73B07B -:10436000BF537C77E75E904BE30ACC71EBA103650A -:104370003CC7289F1A28E5886AF1A6E13BB396F668 -:1043800061FF4B8D2D2ADF093C6E8B633E2F5E7ED5 -:10439000D3F801F4FDE26DEDBC18E6B109DBF3657D -:1043A000FB69B7BD4FCFB5CD31FCFCF581DAF7F92C -:1043B000C833503C3376D28359D7EEB7A751175A3A -:1043C00068E249C41D2704B6BF897DCE0953546EE7 -:1043D0003F41CFFF144BE378DF7C7CE01B6B1A7D01 -:1043E0006F3C3935A86F8A7177B985C65FACC79BBA -:1043F0006D03E53A546385F68C0BE3EADCAB1B3DB9 -:104400001F2F643E74F4BA1DA9B7EF3ACAEB4901F5 -:104410007E9418F7FABCD6F6F80EBE7BA58E0FF781 -:1044200040B9EF6BC084578E8B97AC7034754F409A -:10443000690BF7A6B27A7041CA40AA1FD74D14AED5 -:10444000C1776F57C57A1E6F7331C7D9E3B33CA0EC -:104450008326EA38DF48ACEEC9FB394D2305F34F1C -:10446000D3AA4C83DE9C9F64F8734D23BD0791BF94 -:10447000D53CD2E95DEF457E4B288C38CAE13572D8 -:10448000BFA66B6DB807E46CB34FEE837CB138D731 -:10449000033EB9F981C909909FB357AB6107F87D15 -:1044A000A5396F49B8BD9C373EBB6EA41DFE6B8914 -:1044B000CB6FC7BCAE1AA4790742FEEBE7222FC32D -:1044C0009870EEA7AEF875F87D6A02AD67AC3FABA9 -:1044D00027017E7574DE53A59EDF64C0CB52B5C143 -:1044E000F8DEAC44CF363E5FB9B83BC7556F1F28E6 -:1044F000E5AFB0867B003F8FD15AC0FA3C912FF9CF -:104500006F5CB2BB978BF93746605E4D36772FF004 -:1045100073D3B2180BF0346E89E4E37BAC727D0583 -:10452000FD1E4B80DE8FD1F9777A8DB5681DF5D3EE -:10453000C929ACF1C9C85BD3DC18C7F840CD61F814 -:10454000D7B3757D357BA53C3FD67594A4ABB0360B -:104550008C6E47CF8F6CCCCC415EBCC137F5830BE2 -:104560008A0646D07F5C81BFB03D7D679CC5D30283 -:10457000395C324579A9BBE4836B07B23F5FCFEB6F -:10458000BC85E4842309E7061B248C7C55C88DBABE -:1045900087FCCE08BFDD2E7670BDBD44E6A376B5A0 -:1045A000876B38FFEA16E15E42F026B223AC362173 -:1045B00036573BB97CBA9AE45D4F21B654A731BC5B -:1045C000ADDAC365A83A8B9F3F53ED657847F52078 -:1045D000867755FB19DE533D96CBE7AB8BF879B464 -:1045E000FC99ED9AC3F2C4DD8B683DF87CBE99E17D -:1045F000A17141FE3885FB6EE4D30A29EF92B2A483 -:10460000FC11BA3CEAD647F0F99BDB410FC2BB6D07 -:10461000C5480B9FF7B436A683EFC6A827B6EE466B -:10462000BC639E8BF3B25A4423AF931661F106F23A -:10463000A4FC7110DF75BD6B6C66649EFA8DF3147B -:10464000618DE0AF9BAA628435423FCD5C9C648261 -:10465000A72F7EF7E50EF4FD3EDDB47B41FFC37767 -:104660007DF9E89FE8F9E3771DEB29CFF5FEB02E41 -:1046700032EED2229A256C75F27EFCE377A4A7B6BF -:10468000EB26BF077ACDC23F3CA04FF3D127B10E36 -:1046900097A9DE25047F04FA103E3FD1E953BCAC54 -:1046A000FBF25F605DFB9D5E85BE73F88EBE858309 -:1046B000A8FDE3FA7E945841788DD43369527F7D0A -:1046C0000AFD9524F55901E46858EAAD4F7F951A23 -:1046D000B81BF5B724787102425BD1213097E09581 -:1046E0003EBB57455CAF5E2C47DC86702CED8A8064 -:1046F000CDACC71A3B25211E6C9C938ECB0B3AF98F -:104700009C167584FD985959FB443AE4529DE2C6C3 -:104710007E0DCE753A9321DF14DE1F451ED014D2D4 -:1047200097CF0E54797D9DCAB772790D92E508AF87 -:1047300031C2CBF1999295D41EF2B1CE679F13216D -:104740007F67E9CF676759B8349EEFD3BFD77185CC -:104750006F2AF8A323EAB351E64CC5F83ABA0AAD7A -:104760004AC4FE6FFD402BF7772A5FF67B0D884A1F -:10477000EFDF9BD5CD7E73369FCF62BD65F4332BC3 -:104780002B677937E8EB9523811D516BF3A6A55074 -:10479000BB97075AF579E8E7C29D323FBBEC027A36 -:1047A000C388D31DC13FE539499EEF826DBFDB86CB -:1047B00073120B3E76B0FE5A70B9D44B223B983F31 -:1047C00099039AE6B8F8E8DF9D3C78378DE724CE68 -:1047D0003121DEBFE3333BF24369D95425A60356AA -:1047E0009B90671A1D9F3DB0EDE38436E3E23BD416 -:1047F0004B8B8B2B3F24402F18F319F3E29954D89D -:104800005995CA59DE67AA7C9124751BF38E8E8B4D -:104810009F8B9F8B95DFA88833DF79A4CDF87974BF -:104820001CF0FB81D1FB11AE02C8893387D420F67E -:10483000D35B823D13451BFD1BF1F3CA35F4523B9C -:10484000AC4B4F22F6C34E5DC02E1F3E48FA2F27B9 -:10485000F578FBA92D2AFB4BA7B6C407619F566CC0 -:10486000B9FF20F6292B36286C9E978B06C617E1D8 -:10487000513823F518F2DDDAC1B8F624425E19E3A7 -:104880002BFD5D7C15F86A7E48F16FA471B4383D4C -:1048900089ED23C6D17190E4CF5247289FF1AA8FAA -:1048A000DB3D48CA41A3DDFCFAFB392E4DEDBE6667 -:1048B0007BE7F77182F30445F39B18DFF1B5B95E2E -:1048C000EC2BCE0F6DAFE0FC8E2D716EC4218EE906 -:1048D00079CEC6777AE9FDF51A24ED94E3FAFEDD88 -:1048E000F16DF27C3AC689F5744C31E70B66EBEF5B -:1048F00065EBF87A475FC746FBF9A1A6841ED4FE94 -:10490000AB3DEF72993F48AE97F9AE86FED0BB5FE4 -:10491000ED88E3FDF8AF763C528838F3C9D0C8146F -:10492000F0FF397F6D904DD261AD3A16F812419982 -:1049300067530EBCE6468EB3DDBA4066E43A93F99F -:1049400046C7773C9B60C96EA563B9B3CA89F3A11A -:10495000953B6E29021F1FB4497CDA774C0CE0D8D6 -:104960007365BD4F807F799DA573FB159688760E84 -:104970009B97ED62DB9E623FDA1B71E8853B6D7CA5 -:10498000BE70C6E59EEB6FC43A7CCDC67458D8C7DE -:10499000733DE72335A89CBFBC305384617F2CBA9C -:1049A0003D7E1DF6C38CF1CEC895EBBD6C8522FC17 -:1049B00034AFB2A02A342A3B12DD03C8514A6B1C23 -:1049C00080FCC9A6CCE03DBD52F8BC6F787D4A6B37 -:1049D0009E29ADE35E3817593E2899E7FDE0B442C1 -:1049E000D67787ED2200B9107846E6E1947593F901 -:1049F000D10F83EFD15F72B8573B9AEF099DAE6537 -:104A000093C2BD909751F64C3AE7659CB0CBFD52EE -:104A10003CC77E71590EBD4FED52F47C5EBC9F14B5 -:104A2000C14765B3BC1EB45393BD1E9F0BE3757F96 -:104A3000CD76EBCE7801BBD5B23B5ECFAF8AE13C01 -:104A400072E3BD9A41D22E4ED1E9296E90F9980FAA -:104A5000DA64BEEA831BD3F97E0CA3FD83366D1A9C -:104A6000EC27CC03F6FA7C7B5D2FECBB18E39D9F13 -:104A700050C7E33CA1F3F9FCD83A9917AE9F3B46E7 -:104A80007BC04D7A1E7BF3530ECE5F3996DEF02D40 -:104A9000C67BECA93EC88101BEE7ECE17AB21F8972 -:104AA0009E0B9E7684517FF42919B73E6A0B7E0BCC -:104AB000397CF4D1767C3EEA68FB603EE707286EDD -:104AC0000BECB3A38A0EDBDC6C5776B5134CED53BD -:104AD000628505F93B6327AD9981FC86960D0EB082 -:104AE000A738B6E9A154F66B842791F36C0EA9029E -:104AF000743BF6F4DFFA44DA2F46B9608339EFAE3F -:104B00002953DA9546FD3A7D5DAED3D7F5C64152BD -:104B10004F95C7851EECC6F393F826FAB07F470A77 -:104B20003E9EF327B6F65420371E16C19F7F9CC7C2 -:104B30005EB60779F365CF3CF526F66B8F594403D3 -:104B4000EC0FE5AECD3FC7FD1C29BF49643D24C431 -:104B5000069EDF51B73CD74A0B96E73FBF838417C9 -:104B60004CDEDC0BF041D2390AADAF051685FB5F98 -:104B7000B0AB1FE7DB113D2CBC4FB65DD5C743364C -:104B800025F0B749E62B8F4B0E6E82BDD7FC6877B8 -:104B900081F3EE63D4B5FD41BFD31BE22CE0A7F255 -:104BA000BB87240E01DEDE5205EC8FD3566F87C81B -:104BB000384234BEA2F3C0BFD5E55319AD3B9CFFCC -:104BC0002CDDF528DF2F520ABE045E9E56781FBBEF -:104BD00074F99087984FDFB4899ED4EF89D0FD098E -:104BE00091F469D4E5E2B9EFD8BDDCBE94DACBF735 -:104BF0005F4BE0716EB2715E4B345D2FF9FDA7D54E -:104C00004B7AFFDCFC436417F43F1F0FA745C3CF6B -:104C10003FA6EFFF654B0CFB83E401F039B6E3B62A -:104C2000D01CCCFBF8D618965FC793A49CF88AE4F6 -:104C300069A037C671CD6F994FDF99CCE7FDE606C5 -:104C4000CDDF35FAFD02721C7CD7CE9B08BFB3FCCA -:104C50002D290F895E3FE3F7DFB2F1FBD1F338A0D6 -:104C6000BF776E9D6E8D63BE38DE51D2E3F8B6DE3F -:104C7000AC9F9A92DC82F9E6299BACB785BAC00E4C -:104C80003EBEB5B7AF36E2BBC793425DDC11CF9BEA -:104C90006CC1E503A53C6D865F2CC2246AF3915F6D -:104CA0002458CE1BEF953A5736C04E417E6F7E0E8C -:104CB000976147F2F979BAE392A53F396CB08C0F4E -:104CC00070CE6AAA9E4FCE764FC80E39AEE9F66115 -:104CD000D996E83C5F59DFC9789FD65D8A91576CB9 -:104CE000C17843F6348E3708CF3334DED2A5B7CC43 -:104CF00047FE7869D5AA1B613F955AC5583B8DABD5 -:104D00004951791C4D3162E624D89191FD44D86F08 -:104D1000BD079F8BD30A772ADBAD6CDCF71D2CF522 -:104D20001DE03AFA5ED9526525BE6FC8170E14A66B -:104D3000B6E20979ADC8EF691AA9D75F60DE4D36D2 -:104D4000591F3D6F633C23064B39D594E9F9ED506B -:104D5000D0E50D95CF779DFE213731B90D3BAD558F -:104D6000DFDB5BF36C69FCE3605BD377DC83A5BCC2 -:104D70002BA5F1619CBDD69AF3CAB33698E1CBB6A8 -:104D800098E1EC1D66B87FBD19F61E30C3797ABF75 -:104D9000F0B3716E197E364AF8D91E87F4B301C399 -:104DA000CF46093F1BCFE16703869F0D187E366013 -:104DB00003DFF0B701C3DF46FDAF743C097F381550 -:104DC000F99A151699E74BF4F0F339A66976D3B939 -:104DD00094532FCA7329C40F52DECF77F13A791852 -:104DE0002D06432FC9F594F2BC23B884DE1BE1D114 -:104DF000E60EC67A5DF3CD1CF05D45B746CE7B6D01 -:104E00005AF64AAFFBA95DA3122F605754ACF9665E -:104E100006ECA8248F568EF695B10DCB0772DC3EBA -:104E2000CCF2A3B1C6F3D60849478EBF14ABB8295C -:104E300083EAE725B7993F149D772E569AF3CC2F36 -:104E400096771ECD07861DF8B8AD39DDCD7EFAD038 -:104E5000C710E75DA8C4BBE1A77F162396E0FEA0BC -:104E6000C0AB324FADE5904DE60DAC54D68B08FB90 -:104E7000E4D73ABE0D78F6D95CB6C7CFC12B158BF7 -:104E8000B85C881E5A7313FCEBD3F32C6C779F9E8F -:104E90005750D81EF61FF9655813B89F2B72BCB82F -:104EA0009F2B927F703F97F9DC4447537BDCCF65A3 -:104EB0003E377199A97EF2CA5C537D49D110537D6A -:104EC0000F21C7B768BE1C5F09E9077F3BC04B389D -:104ED0006F71116847764A1725B09CE5F23A85CF85 -:104EE0008D7B16AF28045E4E103B238E60F0CD6C98 -:104EF0005DBF086BC00EBE3B9322EB8F2A0D5FDEB9 -:104F00004DEF9DF4D56DC2D529272D6B1F1CEA41AD -:104F10007EFDBA2E6E5A87B72AA154889E3579DA5B -:104F2000AEC1ED919FD23891F713B7B74FAE81DD87 -:104F30007968C09B83D0DF1695F3260C7EE96293D7 -:104F400071BA75838866644FACAB93F9BCEBEADA4F -:104F5000C5F688D87F31E6D9023A08944B525338C7 -:104F60002E241A300FB2DB97C06E3B7D48DAEDC6B7 -:104F70007C7A2C0D775A44F5B76E8F61FC7CAEFBC2 -:104F80000D27FABCD4DF83F31BD57BBAA8B0072C5E -:104F90005B36C18F70A4686F82EFE7ADEBF927DC59 -:104FA000EFB5E07D55E03CCD17AB47250CA6EF1CD7 -:104FB000DB6AF38E23F8EEBA27ECF093175883766A -:104FC000CEC37C6A9D1D79C9576E5EC7CFE76C2E34 -:104FD000E6BCCBB9A28AFDC823FAB92C63DEF30A7A -:104FE00094B56EE22FEF15920FE7C5CAFD3CE2E7DC -:104FF0009731AFD39B151FECC72945DBEDC5D0CF4B -:105000003ABF7AA64E1D03FE6B09C9FB395A5E579B -:10501000E5BD63535499177381FB7C269FCD64FED5 -:105020009E72B62FFB59D786FB483F365BCA8F96D8 -:105030007A95F7E35A5EDF9F3219DFABB7F1EEDD09 -:105040003C7B833CFF6F11553847E099DA20F92A01 -:105050005354C1FE5BF4C6BB07B1EE16653A3D582A -:105060000F454355137F568E8E33F1EF54916C3AB2 -:1050700047731D924A22E029E3BA9BDA5F3FA56F8E -:10508000943CC869AD67797045D439C002135C4E51 -:10509000E59D904FE26AD37BE562526B3BF8C31B00 -:1050A000A4DD5ABE23693DF6C5E759A43F345593A4 -:1050B000CF2BF6C8E742C49E3B978EF3F8880F9833 -:1050C000CE6DEBFB7CE897E381DD1B38AED39C4EC5 -:1050D000F292305A9ED568473C8DCCE566C449CBE8 -:1050E0000304A35FBF68AEC5F911ABC4AFCBEBEE51 -:1050F000B624BD952F2A7698F3AD2A0EBDCBED8C44 -:105100007CC6E87AB2D39777C4B8C7293E3E37B990 -:10511000A5C98E78D014AD13DF4B117D5F5A59A805 -:1051200089C779ED9E5437F66D2BA2EE495B7885E1 -:1051300047EA273DFE8F7B86A49DD06097715BD7A1 -:105140003E0BAF3F792FCF39BE9C6791F70544E105 -:10515000659CEF7DEEAF63BACC43035EAC117889FA -:10516000E623E0C91A81A73942E2690E499320C1BA -:105170001DC16791F8F989F89A8B7F50FDDC3D4A93 -:1051800010F96FD1F899A33532FEE668AEAAA0FBFC -:10519000FCF954DCF9C141C8A76DE9F25EC368FCB3 -:1051A000CD150DCBE1F7CE25BD114E62BEB03BD97A -:1051B0004F53BCD0DB9E418D769B94671CE76D7985 -:1051C000FD5D5E772D5E5AD5E00B41F5D4DEE5F747 -:1051D000342F6923CF77D259193FB9EEAC95CB293B -:1051E000E3CCEBEEDAB3A9FCFCA7E2A50278069FBC -:1051F00023AE97D0C63D7B88F3259C3F5F633FC4B9 -:1052000090C3AD769D396FF942F65F749CF0AE2B7A -:10521000F47CC1016280296FF902764774DEB2A185 -:10522000C75B5C524F8E51B3DFF2D0BC8B5F55D958 -:105230004FF74C1D6BE1F3E3AFCAFBF1B465679A1E -:10524000C09F5ABC85E5E0C2F86E7CAF85A6C7ED6D -:105250008C7EBAD4B44B45FCAF38C6CDF9F8C53511 -:105260006A11F45731B5F344B45BBEB47B17E885DB -:105270004FEFE9FD5880D6CBA7B7A7A422EEFFD900 -:10528000325B0A49CE73ED3E5D36A60BF2333E5BD0 -:10529000E5981A6C033F9B747D517ED707ACB74EDF -:1052A0005A5E4F984AEF972DDB9980B4FFD265EF95 -:1052B000E6BBC9A4B8224FDB7805EFAFAEDBE4064E -:1052C000BEDCEBF83E815D242EF17EF1B2654CF739 -:1052D000058ADCAFBE55097F3982DA9D8859953041 -:1052E0003513B7A10ACED338B3215E3F8F56C379A9 -:1052F000432762C91EA0F64762243E8F6C8FF7F2E7 -:105300009D18DE4017F6DFDACBFD9D524BFD751878 -:10531000CF5529DAAE2B06601CC14D692AB7E3735D -:10532000EB5A4DCFC4B6E21FE7E6A9EB69D8DB28FC -:10533000616F235F06F63660D8DB28616FE379E59D -:105340001AB3FDD6A0EF171AF1E0AEB5CD3ED8BB2B -:1053500081029155C57A765CC1BF426FBD2AED8549 -:10536000458A774523DB4BF175F03B6BADD2CE0E12 -:105370007C22CF45D19F2CC8A75FA89779B19FFF0A -:1053800050DC5D8FA3FD62EC0FE5E1DE53B2BD2280 -:10539000F875C459A7883C773B928CB04878943311 -:1053A000DDD47E8C3BD3547F655A1F53FD551E9F21 -:1053B00009BE266BB0A9FD78EF4813FCB34157999D -:1053C000DA4FF44F34C193C74E33B5BFB6A8D854A3 -:1053D0007FFDD4F9A6FA69DA2D26F8C679B79BDAEB -:1053E000DF545563AA17A2EA49E0C71F90F7B0D56A -:1053F000C37F72E0FE17279754FF7BE4318F24515F -:10540000CFF7AEBC71DBE380F721AF9956DCD0510A -:1054100096AAB6E2F8B62132AEA80DF5FF7805FBE4 -:10542000B90D7C8F2662B7E0BB94211EDDCF96CFED -:105430003B598DB855433ADF9710D5FE42ED86C6ED -:10544000ED3BED2196BBF385C76EB20E461EC4BE82 -:10545000DCEE04EF1DD2749395E4CDD021FB9EEDDC -:1054600046F0C117FACC60F8F27DA7513FA5FE0BBC -:10547000593F59B069D230E4DE9B02C47743477488 -:105480005BE995719136CFB71B25F08473E1C013AA -:10549000CA30F13DCA7DC4F7280F10DF97905C3BFE -:1054A000487C8FF210F99978FE6FE467A27C9DFC2E -:1054B0004C946F927F89B281FC4B94EF544FE5F28C -:1054C000BD6A8DDFFB63F53C2E3FA8AEE2E71F55BA -:1054D0002FE6F293EA003FBF7C888C23B848EF4068 -:1054E000BF57200F06F902D1F72C57B9F9FE835A9E -:1054F0005D6F897A3DAF661FF9AFC067A335E94B91 -:1055000067EBFEE285FD7DABF832C26E9B68F50F5E -:1055100019C2F4EDE4E6FD21FDF90B5ECD3F84E810 -:10552000FB7EE6E49EB92AF45DD5CB8954F7BEA58F -:10553000EDFB2753747EF10DF58FC17BC39C8779FA -:105540003FDD934ED6EA108615D05FC991F1CB614D -:10555000D6865AD4D77E2F3CF09B5F8AFF23EF83F9 -:10556000D792B98CF3C7CA59E9AF0CD7F7EF6BBF25 -:1055700097FBF7C33176AA1FE696F5B53793A6F3E6 -:10558000A13EC4DF1F8ED3CEF27C9B296F67F4D976 -:1055900086515CEFB27B906F3ADC1996DF730A3765 -:1055A000E2CB2FC5EF92FD8F91FD6FF83ECCDF87E8 -:1055B000F7691B8CF1B78E67098FAF41DE4F972DCE -:1055C000DBD7EAED876BD47F12C65725C7574CED62 -:1055D000E5F859CE0DC73793E06DCBFAD834793E54 -:1055E00079F459BDDE2BE7DBC12A619C29417D4658 -:1055F0003B4DF8A9BF8C0CE145FC6D784A433AB7A6 -:10560000D7F319E2ADF27B895E791F578FBF6A72BB -:105610003F801080F11B7949C6BAED9C1C4E879DD6 -:10562000D779A19DBF97A16EF7415EE7F8B400E876 -:1056300067755A787EB57E795EFEED173D9D711FC8 -:10564000E944DD5EFF07F45F26E9BF57D21F97BC30 -:1056500065B4C2CA1CFA6F709BF497F8227EC1FC35 -:1056600089FE4C0FD053A7BF62E047A7FF397A2DC0 -:1056700089ACD7F9E37CFA8724BD757E1AEE94795C -:1056800013680FFA0FB34A7EA88D91F91E2FC51724 -:105690003E8C7BB208374588CF0F33F8A54A9E1F52 -:1056A000FEDF4AFF3CABBC47CE51E6E47BEA2EC6A8 -:1056B0000F339B4521EEE93CEBD35220278ACF7A6A -:1056C0000E029E2D4616C23C37EA959CB6EBB5BF3E -:1056D00034DB001BCFB3D06E406BBDD5F94E1CE45C -:1056E0009EF11DA3DD95E7B5CB71425F2C1A135ACD -:1056F0000BFD35B6C6CA716BB24C183E44FA4CE687 -:1057000073FA137CA991F99FDE030BF370BFA83CD9 -:10571000BF255CD2AEF6D05FC8D5C21F8A96A23F25 -:10572000A16EB1C2EF38837C5AFA4E618AD93E1F0E -:105730001BB5BF7E75F6576C8F5F7D917BAE8F0C6E -:10574000D1F7DD3345E67FF29ED1E621AC672FED40 -:105750009ED12C51CF7C30BA58E673D1FC2D3988BC -:10576000DBF84515E0425165051F8C157556E95764 -:10577000FA4F54E4B1D7CEF8B94684F9F9785228F3 -:1057800050263F23F601BC3F6EC274DC1F3C2A77D3 -:10579000540F3C8FB83FCF36B43DDF9FF76777C4D7 -:1057A000FD79FB46CBF5B6F05A196FDAE7ECDEA6C9 -:1057B0001DFA2AE9DB1E3D8117C1E5CBA48F7BD002 -:1057C000BC5F217D0CF8EAAC1A81F70A3DE6BC23E8 -:1057D000E3FD6BDCA384B5DD85F5DD35FD9FEB04D2 -:1057E0003CBF96D47B34E8F55AD2C0D188C7BF9667 -:1057F000D4C1224B879DCB7EBB7BB4353E637DB449 -:10580000F657C8FD19F7058F6E2FEF0B8EC6EBD537 -:105810002264C2EF381DBF3F01AFDEB6F09A82C3EB -:105820008EED81CF77771979538827F758DAC0F052 -:10583000AD36B90ECA778F2F405EF4C2F7657EC7CA -:10584000510C057A77F1101EFFF0C583853597F767 -:10585000A302C0779953E2F164E0A5FEB8D73CDC1F -:105860004E1B89FEBF5AABF279FB93CFC4703CEE5E -:1058700048F0D904E0D3E0E332D5B3D28B75F89A7F -:105880002AEF59FA617F17DC437A21BE267EBE7A61 -:10589000685BFCEC227EEE773E3F8B0DF21E83327E -:1058A00067619B7436FCCEA41C3FCB1FB708DF0298 -:1058B000FEAF10D23FAA70BE2EEFA92418E75EA358 -:1058C000EDAAFC586A4FF576A7CC1736E89DE19013 -:1058D000F75866C40937E22042CBBD0CE3FDB4BBE8 -:1058E000BF187821BF764B64DEDAF0705FDE771E7A -:1058F0007B48E57CF75762E5BDEF8D440F85ECD31F -:105900002BFB56B9BA111DE7E66B65785FA83FA877 -:10591000E8F7F59E8A68C7F1F35C17FBD93FD15FC2 -:10592000BF75A8EEAFF717FDFFE1EF29B497F70EAB -:105930002F7C353788712FAC21AD96C2BF8BC1F754 -:10594000C4D5C23FCF6C953BC3452FFEBD8C5129BA -:1059500036CE33FFDFF67B0A1942E3F5F79FFD5D94 -:1059600085B1F2D179BFAB9091B0E28096D2FABB0B -:105970001AD1BFAB90A1DF672D3C527F18BFA73073 -:1059800042F8392F7F4C9A59AF8C728F3CE0E6D2A7 -:105990001CEFC9B8483ED7B34375BD7231BA970BF7 -:1059A0009DEEF25C27F840FF7D9420F8D3F87D143B -:1059B00083EEC6EFA4D4B697BF93F2CFF6BB28D13F -:1059C000F489FE9D9468FA44FF6ECA702D96F134F6 -:1059D000AACCC57C6DD0692AFD657B00E77295FF76 -:1059E0007E7A1D8DA2D719B17200EE293D552CE5A6 -:1059F000FA85F4FF06AFFF14E4C58F8827E1BC8B5E -:105A000053C643FCB55611335CE07E42CE97FD454C -:105A1000ADBC07AAD62AE30101A22BEEC5FB2EF6E8 -:105A2000EFF23E47B28F6C1D1197A9E2F70376A7FC -:105A3000BBD60B7A27309F2C5E2CCF031FB6D4F138 -:105A4000EF5DCCCCAE52B07F792C535386B547BCBA -:105A5000B868FB1C8ECB570D847C9FF1074717D489 -:105A6000CFE82AEF8F14D98D0322ED911919322F27 -:105A70002B66982EC7BD320FCB354CFA09F15E3735 -:105A80009F6B28CE167A7EABE832A31FF8F813B6C8 -:105A9000E35B3CD2AE6EB4C97B2C03AFCA7C9EB52F -:105AA00055EFB0DDBF91EC5A55DA376BEEE3384372 -:105AB00082C03EEEE331CD49187FEF35C2642FF44A -:105AC000093A4D79C97D37BB4D70BF509AA9FDE5A4 -:105AD0007B3CA67A5F38CB549F7BC86B8207340C23 -:105AE00032B51FF881DF040F6E1C6B6A3FE44891EA -:105AF000091E3DAC9B8CFB8327693E3316B983F2AC -:105B00001E7D1927E96A97F654EDEDD29F30F2D742 -:105B1000357D1D44E7AF77B6CAFC757B95D46B9A8B -:105B20004BFAB7EE64E156F95C4C03C3B81B82F341 -:105B3000C603E63CF34E4EE95F59464BFFC3AEE762 -:105B400099C766C9732F465E39F9157EE0BB876831 -:105B50009CC6BF77A0DF271ACDCF453ADDA3C7DDAE -:105B6000D52ECFD3D5DE6EE7FD73CD656F5212CE45 -:105B70001FCFED0325FF6F74B67DEFD38C61328E9E -:105B800012CA2DBA6E18B57B8CD416DB5FE7F5E729 -:105B90006D84BCABFD959DF3C62FD6DF8CCBE57C29 -:105BA000A65B2C332766B33FC8E7008D7E2BF47EBF -:105BB000278D50DA9CDF8CC466BE774D24DA3DE039 -:105BC0005FCDB59C6177AC4852DBC07BEBB90C99DB -:105BD000A77FD3CAD07DBD699CD3ED753679E140EE -:105BE000D0067E18574076A40FF1D782475D448FC8 -:105BF000C7165B390E76DB8B2FCEC0D5F4E3453369 -:105C0000F3031251B09F08FB53CD691DF7B1E13288 -:105C1000EFFB415C2CCDF6CC0F3CAE163D3ED222C4 -:105C200042E7CE4F04DAE037CD7590CF21B8174A5E -:105C30007EEA1C71CE0AFEE7FFD47909811D52EA83 -:105C4000C75627E439C78BE0CF38A7E2B9C556B4A9 -:105C5000DE85F32262AC128187FF182EE3FC878673 -:105C6000497AA31DE4D185DA91DD9788FD8516E197 -:105C700049745F24AEFE3F31FF0CAB8C337471CAA4 -:105C8000F3229DAD1ACB0B7B967ECFDD79FCAECB9C -:105C90000D3D4ED6C92AD77D27AF5CD7E7CB85030C -:105CA000FC7DBB26EF4D8BC62FFF8988AB18E757CD -:105CB00062474B3962C88573E7507A4A3FD4A6CB16 -:105CC00087600F0BE71DDC1D6F5EC7DFEBF261AD78 -:105CD000A12F02E4C7E79BE484C0BE5EED3295E5E8 -:105CE00004C9C9831A8DB318F7B2B85B7F1FEEE6FB -:105CF00007A41E1BEE2F7A10FB26B356DBC43ADE38 -:105D00005790F7C3CED5E3E4C581A8FB59747BFC5B -:105D1000CC4AC58DDF8D98BDC25C3FD7F5E527F035 -:105D20001F6F8EBEA7C6D8AFBB481CE0E830DD4E63 -:105D3000F70AAF9E7FBF04E33B1394F75E9F3BAF30 -:105D4000A4C77F5A82CF4AF84E21227F47C2B00BA8 -:105D50000CD8837DB2887B5808BFB159D0EF4BADCA -:105D60006DE6371AF83D97E7A1EFD351B96419FBF7 -:105D70003332BF81E401EFCB9DA07AD8812702A7FF -:105D8000B9FD891D319C5772D2D7D01FFBB7C63ED3 -:105D90005D0F4DEE63B5EC8897F90D2E8B8437CBF4 -:105DA0007BEC17FC35D81F7E6C63E059D33907AD07 -:105DB000D1BCCF175D6A353BD9DFBC224F4B1E8E5D -:105DC000BC74ABD7E925F81ED73EBEA76B1CF98F74 -:105DD000906BC84B599622C7CFF22B705AE2AF4A4C -:105DE000E2EF6764E8417EBE2F487A228E29C8AB75 -:105DF000A5B2383C98FBFFA9FB6093CFFAE4FEEF15 -:105E0000D921FCBEB66230C359C1E6911F50BFD73D -:105E1000692E0FE248D7D6FE624C2C7DBAF15F5D49 -:105E2000CBB8EC6C3E3F6094BEE1528F34DADAAE10 -:105E30005FAFCB9F3F0C17FA7D3592DF17D628BC9A -:105E4000AFB6103C0EF83E793FA7019FAED3E131CB -:105E5000125EB44CC2504DB08367E9BF93B6498F10 -:105E6000BF60FE28317FC405B6E8F119CC1F25E6D6 -:105E70008FE790578021AF00435E0186BC420979CD -:105E800085E75F248DE27D6DECDB8D8E584FD8B7B2 -:105E90001B1DB13EB06F170963DF2EB23DF6ED2238 -:105EA000EBB16F17598F7DBB4818FB7691EDB16F41 -:105EB00017098B4157B5C2906BFE89267832F903DA -:105EC000A323D633F6ED22BF8F7D3BD3F7B45B4CD3 -:105ED000EFDF28169BDEC7BE5D64FB998B15D3BE32 -:105EE0009E10CDACD767AF69C77C94E12BAA04BFE5 -:105EF000FF39EEEFB7D9BAB17CE038C6C2F258AF7D -:105F0000A477DD58497F8B3C1FA134F3EF0B9CBE77 -:105F1000D32EE131E6FC6DA3C4BED7689BDCF7420B -:105F2000897D2F94D8F742897DAFD13DE5BE174AD0 -:105F3000EC7BE139F6BD5062DF0B25F6BD5062DF28 -:105F40000B25F6BD5062DF0BEF61DF0B25F6BDF0D0 -:105F50001CFB5E28B1EF85E787691C2511720CF6E2 -:105F60007A0F939F497C68F233DD2618F67A647BBA -:105F7000D8EB91F5B0D723EB61AF47C2B0D723DBA5 -:105F8000C35E8F8443C33CBCDE60B747BE07BB3DE6 -:105F900012EE57177819B1B5F16BBF3E80B2315E82 -:105FA000790CE70D43C3A7CCC47E66638CD22589E8 -:105FB00064BAAD66DACCD1B0C3F5FCC7FEA2D90293 -:105FC000F9A3C199CCE373869C57DAEFFB74AE6FEB -:105FD00030CEC5E10FD1DDB743F0EFCE18FBEDC6F3 -:105FE000FB5E52DBFC7B517AFB56B8ED76D1FD1B94 -:105FF000ED38B72A621C38D18CBC19DF9DAE1CF875 -:10600000219B2C0AE7996C5A22F3A2A3F9EA0B5DB3 -:106010003E6DB26CDF877330CDC58A17E73E7AD408 -:10602000697CCEACDF7461517DADF3E9FD7802E7A8 -:10603000D5BEA1CB3D63FC467C94E4059F1F1CDAD2 -:10604000DC302A91DA6B8191FC3B38E3ECD26E2094 -:106050003FF40AF8937D038A7F7D049FFF69B8D4DB -:106060006F5A408EE3C9C727C8F762E57B4F3E9E53 -:10607000C0FD4F58AA709ED9D02DC28F73CA8DFA19 -:10608000F8FB6E09ABE8AF78A9ECCFF86EF1DA2E29 -:10609000769CE736F0552C1A47E33E6991A7E04E0F -:1060A00059D1CBAAB15DDA61BADB023BE852CF41EC -:1060B0000DCB4B1A833C44512FF8DED0F1796F9B06 -:1060C000E6CBE8CAC7EFA00AF60DB5C02D16F43B23 -:1060D0008110D00EF16482311F4D13559984DFEB8E -:1060E000A61633BEB3A60B05F8EE337D9D2585DEDF -:1060F000EBABBD6481BDD6AFAE914B631EDEA14953 -:106100002AE07136F7188C7FDC1885E547741E0F7E -:10611000EC038697DA589F1BF6C3C2F873793E7F6B -:10612000429ECFE94336CEF339BDF40CD717EF8C3E -:10613000E1BC1E6D8DC272CDB01B8CBC9DB25BDE0E -:10614000CF077E8E6506372575673D9F3802F93487 -:10615000DDB627E008CE89A53BAFC3D1BDD34B77D1 -:10616000CADFABD5F7778CDF3D15D97ECE0733EC90 -:1061700040A1D6DB23F7718CDF4F23F9C9ED4EEF39 -:10618000B1BBF9F7EBF4DF3B35E23EC56FE41E042B -:106190005E8B1F95BF7F366BC5AAC2A904CFF13BAA -:1061A000C3F85DACE87CACF95176E0C57EEFB4CFC6 -:1061B000083DFED36AFF31BF9C795DDA7FC56FEC85 -:1061C000BF56DA2B36CEFB9F5E23E37562BBE0FB46 -:1061D0008FA6D78CB2E01EE9E93BFD5EC5D36A0706 -:1061E000BEA5DB2D93CE66307EDFD5ED946B917F1F -:1061F0004AF81DD718A3E7ABA57379FD59998F3AD3 -:10620000C925D77BE37382EDE9968043E611D60B6F -:106210003DBFD5CC773E41FC41F4B9CCAFEC47DA79 -:10622000F278D83DF4BDA9B083DA818F8B97215FD6 -:1062300096DE66BB339A8F2759C353F0FD495E1B28 -:10624000F3D73FE263DCCB714E2E89AA9771CE5F04 -:106250006C90BFE3305593FCDD57E7EF19717AFC82 -:10626000C925E34BE7E2011824626681AD33912F23 -:106270003C03C90B1D795A7EE4EBC567CBFAD97F85 -:10628000D83A73299C990BC425D43BEC7C7FB5E6A6 -:1062900072F2EFD05C284E80F800E4E34DB7FAECE0 -:1062A000B322E463C1C882D5FE0111E71DEF9179E5 -:1062B000500BEFE9D9A1ADF3B646399BF08BF53120 -:1062C00023B1F1369C37AF1921FCA307C9DF99E44C -:1062D00079E1C44D167E6F52C25B47BCFFE715D90A -:1062E0008C0F867F35E28599C8872977361682DD3F -:1062F0002AB3ABC622EFBA550E69FE8C4CC8215F9B -:1063000018BF1B76A1B8C3D611920ED1F187D9D987 -:10631000523E0BFDBEF04FEFD9BD0DF2DC18FFA7CA -:1063200017F87D8C8D232CFFADE73CA2CF777CD076 -:10633000477B6804E21A167F13F2E83BAA757AFEDF -:10634000ACBCD7C3A06F4CDD771CEF28D1EFC327BF -:1063500079C2FEE42CBFD35B0339922596E3BCD00F -:106360000C5534F3BEF1797497787C7CDA5FE723BF -:106370001FF7F15FC5CAF33A3AFEA6DB1B5E7666ED -:10638000B6E2EFE3C5FF6293F22BDC13FB723754E6 -:10639000C5707E5BC1C8A22D186F5CB697EFC1585F -:1063A000ED97FCE4EC56F47BC8C1F2952F3D86FBDB -:1063B000122AEB33F977658AF7F896E39C63C148B4 -:1063C0006D07DE2B76B9F9DE908AA549AC9F66741D -:1063D000D0CFBF8B66DE8733F0FE861E9FBA7FA4C8 -:1063E000FCFE29DDCF80209C686A77A1389DCCBF58 -:1063F000417E0EE28F9A6B17C709DC77C87B2AECC7 -:10640000E23D197F4C6B3B6E90A1C71BD3BD323E62 -:1064100064E0EFDEAC592CE76C463CF71CFECCE7A1 -:10642000318DD2ED97F6C2AC5B15F6574B56AB7C6F -:10643000AE7C8C3A8EEF7159B84AF1F0FA7AA03BF3 -:10644000E77B2FBC87AC310FCE97790A3BE4E1BEE6 -:1064500075C50DBB643A681111DF29593398D75BB4 -:106460004990CA36EE3535CA1B57EDEFFC9C0764E0 -:10647000F4F3FE6589DB6F4F8E58EFB3EB14D3FD59 -:106480000A062CF02316ED717F3D29481AC7F41E29 -:106490001E05FB8A6EBFC4C34DB766DAF17B24D3F9 -:1064A000E9CB969C0BF7FFFFBBFC7FC4BFEF53000B -:1064B000800000001F8B080000000000000BED7D35 -:1064C0000B7854E5B5E8BF67CF2BC94CD879910458 -:1064D00048D80904C2439C109EF5C1CE0B2610601B -:1064E00092808227840904091EF446D4126C940910 -:1064F00099C41051138D0629EA80C0A16A25564F10 -:106500008516DB017C8B8A20D6B636191E8A6D7DF6 -:10651000A470A8F67C54EF5AEBDF3B99D99904D0CC -:10652000F6DCDEFBDDF8E1CEBFFFF7FAD77BAD7F0F -:10653000A7289DBDCA2631D6DD2A48DBD318AB94E7 -:1065400014F3441B63DFE2CF0CC696B5088A6F7C58 -:106550006FB9289D2D75413952B1333699B10A4929 -:106560003627A7E15332C7C2FB65B71F30B178C6E3 -:10657000968F644CC882F6B10EB30DC75F05E30B6E -:106580008CDD20F90BB0FE86F132AB8B81F6DE2C70 -:106590003383F9DC9BF83CEEA618F31550AE304A75 -:1065A000E6142897453286ED617D3EEC5FE957CCD5 -:1065B000B1361C972D2DB1F1F5C606ADAF425D6F1A -:1065C000654B8C7945C8FB56930CE5C58C291D415C -:1065D000FBD39E331481F6B3CC5B9CDA0EEBADF4A7 -:1065E000D8259CB7D2A8981DB82E1C17FA2D6E6B13 -:1065F00037A505F5BF423150BF198A4CCFA2747F31 -:106600008680FBBD35C281EB5D2CB598109E451A86 -:106610009C1FE6705821F93370FC15560E076DBCAF -:10662000CA363E4FDFF5717857B6559865A8BFD189 -:10663000E84A6D87FE37C23A3DF05CBCF94086807F -:10664000CFEA088700E7C12477AACBDEDBFF938778 -:10665000AF4FA5FDC3FA11DE76873C3309D6B3BC34 -:10666000051623D393E62DCF66D51D4170BB5E3151 -:106670003296804F033D594BBB621D0CF060FC67A6 -:10668000B8F9480EEEA37E0C631B601F6EDBCF7360 -:10669000709FD29D8C89D361BD9BDEA3FAE5494CE6 -:1066A00012A0DECC5E10B0DE5C097DA0CC3C054AB9 -:1066B00020938FF56D3A63293832B4B701FE789292 -:1066C000195B3755A67917B3C0623602C6D9540C88 -:1066D00073C03A13F93ACB07B1EA9F8581579BBA49 -:1066E000DE1BD4F32E33B097596C6FFDDDEA79973A -:1066F000213E07F5C7F170DCD55A7DAE3FE3D6F1F8 -:10670000BDEDB579CB62793FA407C4C3D52A1E601D -:10671000FB35D49E970B44DB8606D8CF9AFB449F6B -:1067200045C0E7930D83B1FC9CE040B8FF79CD8B69 -:10673000EF5C07CF3F3DB2AD1CF7A7AD63C5D7599E -:106740004C8E83F3FDFA2A7A56FAA73339BBEF3E13 -:106750000F4F75FF48991C843F0FFD74941BE6FF93 -:10676000F3B36F65209C3F021C1001CEFFF6D327C8 -:106770004D2CBD77FDCB9ADE3355D882E12510BC78 -:106780009A338FD2F92DCFE4FD967BFF5281E7C17A -:106790006C663923ADEFF957789FE3ED6B1CD4DEBF -:1067A0006DFB809FFF102689C9173F6FED7CF5E7D1 -:1067B000FEB8C9E54F12F07C5A42E85FBFFFC7D46C -:1067C00075FB54FABB41C5E31BAA5AA9DFB2A68ADE -:1067D000274558F7628D7E2B43DF6BE773769389ED -:1067E000CEE7ECA68CC6242C77F0F3F977B163C220 -:1067F0005A68F7E7D53B6F494EC755FB525D57F0D6 -:10680000F361D9FC7CF0B912CE87C5853D9F3DC1AF -:10681000E7B3F2097E3ECB9F7DFB0FBF9009FFF8E7 -:10682000FEEEB3F890FF2EEB78EEF80FE0FDE2A657 -:1068300056531AB4FBB59246FBD2FA2FAFCE9258FC -:1068400034ECAF699B09F9C0AF15392C9E6B7065AC -:1068500046CE671E37C1D9C6503D13627BDB2F661B -:106860004A22F211E619C676C6F75DFF9F543A2A0E -:106870004A779813917F3544B1ED12AEA3E27E368C -:10688000A16F7BED792A82D3C5329807E9F3548E44 -:106890002315E9A2CC6008A137ED7942A5AFA1513B -:1068A0001D8B71BD43E398540F20FE71A4926B8041 -:1068B000797FFC03AB54EFC0FE6E19EB2D562679A1 -:1068C00000E4DB0DF244C24FC6AAEF494658062643 -:1068D00023DF1BB93AF0175C1FA253C444FEB4C3B4 -:1068E000BE2D391C4FA0CC06F3F77E7CA6183B8842 -:1068F0004F45D670FC33B3F7A96C06BE8578ABF56F -:106900001BCA8E08F83E19D682F337672EA3F333DD -:106910008DE4F4D2DFFEBEBDC4FD9D4A73FB484E3C -:106920004430697B0CED6F0D967BF697C91403F428 -:106930002FFFD115DB9A61C85375CA4133D49F5AD2 -:1069400067A3FEFFA8FDEAF7B9B8B222649F3D74C1 -:10695000D3027C2D0D9FD9A9B8CEB3569808EA4F23 -:10696000DD1A6140F89F4AE3FA0263017B099CCB80 -:10697000AEF5F0AB85B1DDEBADF47C6A3D20D368BC -:10698000C69E599F44E567D7CBF4EC589F49EFD397 -:106990007338FE95452AD12897BBEBECD2768487D5 -:1069A0009FD34D67CD088203E8099C1FAB7A41A7AE -:1069B00014B0C706F169901FF7A1BC633523D84E08 -:1069C00098A2B3E594DD301EF192AF4F6B7FBBA967 -:1069D00085ADC3768F0ABE9D306ED4EDEF1524A22F -:1069E0009C6E4BCB12A0DF929A73C40F97D806CB44 -:1069F0000CE5B8CDDD3815EB37A7491BA05B545B20 -:106A000056670DF45FE11DEDC0F6B70B7223CD5B49 -:106A10002738705EF851AC53800FE06F505E697B91 -:106A200075A4CA2F0DC82F97DFBFAE3119CA270C26 -:106A3000AC5B04D014198A6762B9684B8CA31EE55D -:106A40006D3DDF0FDB0A7CD4DACB470BA7B9AECEA6 -:106A50008173661700DF60FCB1B03626E27E3A141F -:106A60005C3F03BD6327C3F5BACCD8FF972ABFECC0 -:106A70006C3B6197D5F32946BA71779FB807CFD59C -:106A8000667034CB28DFE5776584FB1B22DB2E2381 -:106A9000FEF0FA35765E0FCF0D0D50BF669BE843D2 -:106AA000781488658303A87F6D16892FAED8563A6F -:106AB00018F58D155046F9B505A7027C6A6CCBE335 -:106AC000ED5A0B1EF1003F4D15980BF9D16963A0EB -:106AD00018E1F1E9B6C4D83AD4F76EAE1FC5A0BE2E -:106AE00072DB3DA9F8FC745BC422E4E3F952717EC9 -:106AF0000CEA3F5B63B244B997CEAA72389DDD744D -:106B0000735E22CABBD5DF1C7A5C02B9BA0270542C -:106B10008271CF7744F93CD064F5FABDA922A096E2 -:106B200025DEBD3C07F0EBDF0DFBAF9B8E7258F00E -:106B3000ED4AA6F672A2148E8E357D0AF058063CF8 -:106B4000BDF9EE0F699CCF0D87E72D86FEAB6F7EFA -:106B50003E1AC7F9F7878F4D91E0FD0F26B9FF1751 -:106B60008EFF2761DB2E0940C2366F9B80F2A33A6D -:106B70008771BE1AEBBA6E3187AF63BBDCFF7C5501 -:106B80007B0582A7565EE21B6466A897FA9959C2F4 -:106B9000A7C4480FFE54643528DF35BD447B5FAF82 -:106BA000C2E5D3412DA978FEAB76B5A7A2FCF8A328 -:106BB0009D97DD3B5E5B7127ACC3DD669018E09D61 -:106BC000DBC848EF5DEEE1FA34AB026692DC3BFFD6 -:106BD0007D3951B4FE559BB343E41EC8479AE78FF5 -:106BE00046E6C4750CAFEFCE42FDE9F746FF0A3C1E -:106BF000D7DF837EEA49C373E2F8F7FB167126BE3E -:106C0000F7DC2EB00C01CBCFDB47DA480F33105F37 -:106C1000FFA5C9B713DADB2775F891EFDDFC42CC8D -:106C200044046381383E11F167CD3ED3CCA15C9F13 -:106C30009270F6D546BF39DCB9DDA4EA513DE517BF -:106C40009E3323DEAF7E06F401A4CF17041FEA377C -:106C5000AB3B9E7B75088C77CBDE8A6C9C476B7F49 -:106C6000CB0B1C0E112C602E0DD2AB2B32631B876D -:106C7000028F7CF6C0474B1F862D55E039FD80B151 -:106C80007D333E70D78DC4A744FB64C66ED2C74126 -:106C9000BF32A3FCBFD9CBC7BB39F368633AEDABB6 -:106CA000388E059DFF9E1C13F5D3FAC3BEA95FBDA8 -:106CB000F5EE2702B05EA5DEC822AE85B2917DB4A6 -:106CC0000BE1C7A2A59DB80F233BFD2A3CD78A83C1 -:106CD00058333CB756AFF90F6A5F67914478D6DFF7 -:106CE0005CBB2700F3C9227331E8EFC9ADA6F13CC4 -:106CF000662E7FDAA39E7DF44628D72CB03900BDDE -:106D0000A11C4DF0D9FF4303F1F964D67DC800CF33 -:106D10004406540400FA539AFB30E237FDC0B86BC6 -:106D20006F937DC88F81830B88E75FBE74261BD766 -:106D30007DEDF0C039C42B53DD19773ED0FFFB3910 -:106D400012D74FC607B2B15DC24195AF198F907C83 -:106D50003425C9B1A8AFF8712C5CDFDF0C8407FBC8 -:106D600005FF9338AF06A7885CAEFF19B2DC7F4001 -:106D7000FEA708A63BFCD07EBE10EDC0FD1E891507 -:106D80003326023D7F69FA280DC7F500DA8A437B76 -:106D9000F5D85C75E9E621D336235C7200A0EC6A75 -:106DA000B065C6C7322394EF65866E0BAC23B7FB84 -:106DB00077DBEAA02C3D38888920AAEA2352592E95 -:106DC0008C2F1C848DC27E0E8E3FB81CD7796FB776 -:106DD00095219C983554CF351B92FD3F427CAE8E59 -:106DE00076B02494431D59C88FD82D364733B45FED -:106DF000722190F1BF502EFDED30E9E963D2DD5FE5 -:106E0000E17E8688CA0937D4DF2BF9473C80E3D777 -:106E10004439EAB81C61C1EBDFBFEE6FD171D0EF2E -:106E2000CBEE51C63DD0EE4BC5EA000D9675DE396E -:106E3000EEE5ABA07CB52A4FF4EBFA324936A2DD81 -:106E4000F165B7D58F7AC89736834F0090E6EE3F4D -:106E5000F4A100F23BD76AF38BD1D8CFF459B0BC80 -:106E6000614752623E194722867D0BF01CACCAA5D1 -:106E70006B0785DA8F4372B91D342497F31FA3EC97 -:106E800020389FF5185933E2218332CE6BB44ACDB6 -:106E9000B0BE5FD9762D01CA6767BF4E1F8472E30B -:106EA000ECFE1183D8F8FEF9E231D427404F583A6E -:106EB0005149CB9DDC2B5F17AA708968B9DE84F03D -:106EC000A8077834033C16DA0C7E0BEC8B2D088572 -:106ED00003ABE92E47BC61866807D20D9E2F9EBF8B -:106EE0002C18BAD9557DCF7BC605C9FF23282F8121 -:106EF000F344B8969FFDE48A07189DDB15B9097421 -:106F00008E0D57B2DEF3FB573B2F667434E139AC7C -:106F100015ED2D780EF546AEEF7900B776C650B771 -:106F20005D782E6BEB47D2390DAE073E81764A9DD8 -:106F3000916D8F47BE7294DAEF54F54196594D7CAE -:106F4000A6BCDE2221FCBE8A8CA6FE0CCED5342443 -:106F50001C9FE17CA5A692115F593ABE5AC0734F9F -:106F6000C219603F9D86801DF71988002D129EEB87 -:106F700072D389CE87224718C1CF19FB3FB6CEBE48 -:106F80001DF98D681DFAD8691045ACA93B7A2CAC67 -:106F9000AB4D601DB42F93CA3F56D9489F6B8BF100 -:106FA000117F6B5B38CC817BFD92A9F55591C45F55 -:106FB000AE3218A8DCBD7830D9636D31C05A71BCCF -:106FC000C563496FF8F93722B7D73218AFCF62A33C -:106FD00036637D71268DF74B8D5FDD67A7F1DA8A09 -:106FE00095E448AA1F6CC0FE4BD3DCB7217E0C1180 -:106FF000793B503CA8DD962D4A329EE7961233B578 -:107000007B44702D5E81E35C6123BD31B038F2D9E1 -:107010005DFC38FDE85FEAACE1FBD6E860DD54CE0C -:107020004F877B4E3C8AFCC3930B27624379F1C5A3 -:1070300012C46B458C76000AF739E7AF7AF09C757D -:107040000370597C6427D9EB72064360C3F9492C5D -:1070500017F1E410C013DA7B4C70CEF1FC9C37C4FE -:10706000E339CFDB167CCE309E672DBC17D6443B70 -:10707000846974CE99387E0D8B74A07DDD737EBFDC -:10708000F265E1533438922C008BBDE9EE8755FA56 -:1070900025F83EF607D81FC0A5DC1298DC82FAB9A5 -:1070A00081557584E1034FE472FB4062DD2694AFA5 -:1070B0004B35FCAFD5E17F6058CC27512AFE43BF4A -:1070C00017135DDBF01C3E178E4DC19787FF2E2EE8 -:1070D0000A37FE4F54F9F266BC6B37B61F693C386D -:1070E000EC36D437D65948FF65170E0DC379D7A6AD -:1070F000B99EC6FA8891DD66F44F7526779B707F3E -:107100009D8BFF94827AD6D29AD7883E2F757D1BAD -:10711000A22698506EC638B34C01E89FE8CC7A0599 -:10712000CFE5E85C8B6C09E3073930776A0AEA43FC -:10713000C70AA7A620BF3C9602244FF2D461473E5F -:107140006ADA7B851DD779CC994D6599C96AB9747E -:1071500040FEFA67E0AF7E5004FE08F61A3ECF808C -:10716000BDE6077EFB31D86BF83C05F61ABE3F0141 -:10717000F61A3EBBD63BE8FD31E788BD8817E75BD2 -:10718000B81F65B9D111562F5BFD8CC8FC1A7F83DF -:107190007F37ED880A29576D8D0B29DFD8061864D3 -:1071A000ED2D576E1A1152D6F4CF65DE7121EFDD49 -:1071B000B5D921E5FF67E0DBC4E18BFEF27F25F85E -:1071C000E2CF269077A5F80BE0F7DB9367111F3D20 -:1071D00026B0EA3878C6489CFF195D02F9DDF0A7B1 -:1071E00005E47609FE027463B4C90D58EF85F60F05 -:1071F000425BB47DD1FE60CC61AA80F70B9D111279 -:10720000CAF3EB5835D1D922D642CF1B58073DCB14 -:10721000D8117A96334E875F5604A6E0F3837877C9 -:107220005A1EAC7FB5D5FD443CDA6D29EED171C84C -:107230008F6CB16497F6774EA8613355CFB54D5139 -:10724000F7053F0B70EDD0EF68D4843BEE907BE701 -:10725000D1C687F9AECC433E63E2F3BC3D796A0AFE -:10726000F207E64A08B1A7FA9BAF559593154E0E63 -:1072700027F4D962F9F442C1B701CA075A2D66F45E -:107280002F9CDE6852F5F5BBC9CE3D719CFB654E67 -:1072900037CC4A45FCAB6B1D9D8A787EDA2437D407 -:1072A00000FC4F4F07FEED203F8E03E5C349A79D2D -:1072B000FA83A488CE82735BAEEEEFA4EC30AF838A -:1072C000F60B9345E681F66E4F5A34AE5FDBB77E20 -:1072D000DDCB365942F060FEB4D0F24266EEC5B75F -:1072E000343C6F736F3DEA4962D920F7007677CD61 -:1072F00047ABDE7D39085F6FC8B3C723DF6453D95E -:10730000D46FC5DEFEFDC1F7ABF555EFBE6CEA8567 -:10731000AF865793F25CCBF19CE0B519E916E062B9 -:1073200040797C6C2F87636BD4B5F75D0570287945 -:107330005F641CCEE59EDF233EEFE37E7DFD3C01D6 -:10734000A4EBD148AF9CAE2BBCEF91FDB6B4B6D840 -:1073500084EB2BB175A7A0DFE9C05DA353F05C8E71 -:10736000CE1D9D827CE350E1E8C76E8771BB8A44E5 -:107370008705F0E940D1B9FBB07CAC569470DEAE25 -:10738000BDE754FED2FDF65458DF174E13C9A1AE27 -:10739000BDFF1C3E53B20FF80CCC7FDEC7F9CC4AC0 -:1073A000A38B35C2BC2B012E68C7FFB3F9CDC5F83E -:1073B000CC5193AB2001E1552738D0FF56576821B7 -:1073C000FDE128D08785E353C3EDC827A781FD2BB6 -:1073D00021BEB926A34D796CEF88048417F32847A2 -:1073E00033A7F4E2FBF2DA9545E85F679B4C27513F -:1073F000EF466708CAE712663C1908C253F70BA6A6 -:10740000DE32E1B5F1642008AFF578BA4787A7E727 -:10741000D98554733AAF3F32B897EFE14F307FB917 -:1074200045F437B2B45EBCFD6BE17BE5A824005F98 -:10743000F905E2EB0F27A6BD141082F8CA25F2B1B8 -:10744000D6A86F48EEB5477D4372EF7821977B074A -:107450000AAF3FF83BC4FBBB38DE1F5B3895F0F248 -:107460009809E419C0EB686D7634964F6D2A253A79 -:10747000D3E8473F4F978AFF5ABBA5C66E93230CAC -:107480007EBA6BC590F3CC7861C920F407F4B77E5F -:107490006D5CAD9D36EE525D5C573FEE27795C4FDB -:1074A000CCD85136E0F86000F6F6437EC2227BF17C -:1074B00055443DE07AE601F87439397CBA8AAE2742 -:1074C0007A3CEED4E8D2CD301E7B7481E843FDB522 -:1074D000CB798EE8F43CD0298DD1CFBC9FAAF4F9AA -:1074E000894A9FA755FAD4EAC59D0F5F77038E5B43 -:1074F0002B129F3EBA203B01E7FBE38E0C9A17D676 -:10750000034605E8212FFFBD024C34E40F76E45F0B -:10751000C7010E6827942E2C257BBAD4E44808A70F -:1075200027E8F7AD1FEFC05C8B81F1F188DF95DCB8 -:1075300055CA1A912F001C103F8F637BA82FD9C901 -:10754000FDC087B07D7C309C4693BE727CB7E04026 -:10755000D161DAFB773B9EC32A5F28BF58B9392A2D -:10756000E4DC56B4C485944B0AF93E8ED78EA0FD58 -:107570005FEEF969FD2FF5FC6F52FBE39ABF253DE5 -:107580002536643C0452E87CE9BAFAB1BAFA89219A -:10759000E58BE1E309152F34397222425E122EBECB -:1075A000D435CF52159CA7313B9FFB5B66E773FF39 -:1075B000CBE5CAD582FCF072B5BFFE1A7F1A95E7FB -:1075C0002ACA4739EA2F35E1BE2E951F05C9E105C4 -:1075D000D43F2098B17FAB2A67AB3A38DEB547DDA0 -:1075E000FF2AE2D5E7AA9E0E7849FCFE0B95DF7FC5 -:1075F000F19F6AF9A702E1E5A17D6BA3516F3FB34B -:10760000777434DA61273BEAA391EFCBCC13FD0307 -:10761000C0C7CF5C203F61BA4F3B06969F7F54F9AD -:10762000CE193C07929B129DC729557E9E40F94971 -:10763000F23E939E47517E42FD82E7543D7DB74026 -:10764000F4BFCAD812DE3FBD23945F556D8DD2C9F9 -:10765000C950B959B96968487999774448D95D1BC7 -:107660002A370BC432E2EB677C1C8EA5CEEC90F679 -:107670006764395A22F870387C6192A311CF4EFAB0 -:10768000E2A283E945E3BF477570388D7040FCF492 -:10769000960E8827A7D4FE5A19EC4213CE5B6A7562 -:1076A000BC128F7E844D8203E3540C78CE3438C7ED -:1076B000230BB29E6C0ED233A40291F0F984F750E2 -:1076C0007932F21F30C0D0CFFB5AEDA154F4AF563F -:1076D0003C13457A937EDECAA2503EF3594371EEC5 -:1076E000EFA15FE9FBA2CF8AF0288A21FEB5E0393D -:1076F000D12742B9AB362F3A781F67543AD4E4CE3B -:107700004A6375D873ACDA1A7A8EA5457534CEB152 -:1077100087850E61103C0F4C0749DAB75FA991EFDE -:107720007FE53322F977577AFFF236C61557821E66 -:10773000886AC26B4DF5F310AF4FB84C06E2A71D37 -:1077400071F3103E9E05A22303DA1F6E1A41787E64 -:10775000B2296F30CEF772BE48747566AFC5205C33 -:10776000094F9789F9C95EF5D3797EE62D25B97160 -:1077700006E1827A905122BA78379FFB914EC03849 -:10778000586F003A417DB8CB273A7D61E8E3DD7C54 -:107790007E1EA72E3C40F8F3AAEF5034EA15273A94 -:1077A000F8F8A76AA5688C4FBDE5CDB6D3FA8A6014 -:1077B0005CD47BF75D4F72F28C97E323AE93ECC3FE -:1077C000262E3F8E7997DF3F1DE0F1F92691F4CE0A -:1077D000CF9B4AE74DC7F3DE64A2725EF1428A6F27 -:1077E0001CF371F972DC77AA1CCFEF8C174E1FCAFD -:1077F00075FBA6BE3D291ECFD944F850F94CE8B917 -:107800002CDC144A5FF0139D057A5725FE26E3FF12 -:10781000949968272D4B02F909947BA2A8D484FE81 -:10782000C9124FA83CB2B06213E21DEA97D86ED9D4 -:1078300063A593FD487F1E81E4E5D217009F603D5C -:10784000A61D5793BCAB68B184CC5B521B6A1F2D3D -:10785000D3D9437A7BE9B2E585A9BA3C9CBC1854DC -:10786000A0CA0526CD44B89F04C3BA390BE0F982FB -:10787000A860F9BC3782F867C5D2B3D7A87AE9B552 -:107880008807CCE161D3343B3D88CE9679459D9EF7 -:107890001E0A5FD09F3F41FDB8294E95A39E52F22C -:1078A000D78DCA53620A701D976A7F5FB27E5BAE46 -:1078B000EAB7E5A4DF1E5B08F202F673149B04F539 -:1078C0003FB0F07AF2EB1C9F7B3DE9B9C77BFC3AF5 -:1078D0002ED5AF730D9DDBF122C067921B0EAD3C20 -:1078E000A01EA1F18B8FD57338A5F2C9132A9FEC86 -:1078F00052EDAD46555E78557971BC48B5B7E21981 -:10790000C90BA3516197C2676E6C8BD2C987389D32 -:107910001D3554773EA1F262B7CB3DB300E0664916 -:107920001A1BF2DE244D0C2967ECD84FFEE3F3322C -:10793000CF27BA077102E3250B797E16B37690FF45 -:1079400078A143A6FAA1182784F66852611E898699 -:107950009FDA7B299EBFD7CAB1B0EB3A6C97D6416C -:10796000E5FA858C611ECC486D1C00471DE8094373 -:10797000D18F0DF324818186ED357C1FB6A095DA79 -:10798000E5563149807655056984E7494C21FE3238 -:1079900078355330DF85F99EA7764FDE0DFB00BCAE -:1079A0000FD4CF20BBBCD41ACDE3DD201F07C6B354 -:1079B0003A4E3FCE38D25B8619396AF68BB76ABB2E -:1079C0008BE16D901E7407D10533903FA2356A821A -:1079D00009F1B4C4E622BF01E0F5923BD05FF99211 -:1079E00099FB091672FFE4D1C2A98FA1BD3B618F3B -:1079F0008D7CC94757003E137FEFE676426DA9079D -:107A0000E5DE074E2EE7C6EDF9CC80F96E5D7B9979 -:107A100003CB876A9F3FFB26D2CB0281EC8C63B5F8 -:107A2000799C2F33E6C2FCCD63CEBC0D549E0686F6 -:107A30007116D283B2C188EB00B83653FDF2FB2633 -:107A4000A3BE735824FC4D52F38C243CD7E4DE7261 -:107A5000BCA296D95E2A2715F1FCC05FA8FA41871F -:107A60007A9E3F51EDA05D2ADDB4A974F3A04A3798 -:107A70001BF5FED0AD9C6E46191DF745417994C7A4 -:107A80004E72E6DDA253B46EA07F09E3B969856248 -:107A9000F32480DB384B80F8742988BD0DB09F9C9F -:107AA000A23ACA5F2C75338A57942CA8A3F50530E7 -:107AB000B67415EA4D7582A8D6237F1C17E7A7F682 -:107AC00025562661FF52E77307300F77A11B40034D -:107AD000E5FC057502C1A702C683F6076A1FA2F17D -:107AE0008E57F1751CB5F3FEC72A98E481720673B0 -:107AF0001EBC9DAFD385F1D0E3B5CF1F20782FE01A -:107B0000F0BEEA5343083D66F92343E87AEC8ED889 -:107B100090FAD19B878494135CE921EDE39CA1F456 -:107B20001E39726248FD3167A901E5ECF9055A7EFC -:107B30000FF78B69765DCE1E9B01E171DD5C51F321 -:107B4000E31AD860B4BA18F97D9B543D91B58C60A6 -:107B500098BFF1E49D06CA0FD8B8A0DE8A790FE776 -:107B60003B8C745E302EF191E3FB8D34AE35CD2B22 -:107B7000A01FF35E80B318A4FF3569F24DF5ABE3A7 -:107B80007A8C41EB899519668CF5B46F53F1E92134 -:107B9000751DC0B7734C38AF8BE3495C113398A0A7 -:107BA0007FC2022EA7F574D9A1F6FF89DA7F978AE2 -:107BB0008F5DCE273744225C1631D2470AC4D51BCD -:107BC00022701D458CE8B1C37F3032587FFC457F61 -:107BD000E32CC82EA0713C9C8F8E9D2FD447E0B91A -:107BE0006E0DFCE91D78FEF2F3C60DD1B0DEA704E0 -:107BF000D68114A5F14F4DFFBEEA8B26AA1F3B117B -:107C00004C34A8FFE517CDBCFD1426A3BFEB17AA83 -:107C1000DC6952E92763C778F22F9EDF6C26BB67C9 -:107C2000D7BC95DBDB60BDA3E7DCF5D40B882FF375 -:107C3000EEFADD0B72AF9E5F3A2FB913F3F747AD43 -:107C4000B733E40FDABC193B3ECBA5754B468678BB -:107C5000FAF4CE9F2FC3F17EB22BD2A0C0F84F6FA3 -:107C600037127F1973EF63DB37B3BEFE985267A8F4 -:107C70009DFF938DED4FEDC5F735CF3F713A284FFE -:107C8000E7D8DC7B52D06F7A747D555B7E46FFFC73 -:107C9000B3D4CCDC18BF73FEF2B39FBD05F3FFC6AF -:107CA0003D6662B01D306A26F7FF1C5D5FD3960FFC -:107CB00076EA5891E72930A36703C263EC8B8365AA -:107CC000D4DF80148C6E80A57376844181FDFDC65F -:107CD00067DC467C60F6C60C3CCFDCA78B0E7E8A48 -:107CE000E77C5CC5F77EF491A3EA39F5944D32C187 -:107CF000DDF39295DB378A9C42F6B1434E2909D2D7 -:107D0000E78EDEA5C5971C7F403E5E521645716525 -:107D10002DEE223AFFD2807C7EE9B4EAC912AD3F53 -:107D2000348E3F04E1978D715E1EAFF7788C8CF234 -:107D300082606B48276BC5B1946FF2E1AA1F52BCF9 -:107D4000DE53679132E2296EB007CB35C0772C93B2 -:107D5000288EEB43A1BD7826F7239C5B54FF9859EE -:107D6000EE1FFEDE8B9C8F493D1FFDFBC533B91E08 -:107D70005A8FE79211722E07DD93C29C4BB495F097 -:107D80004B3B1731BA89CE85596D9998F791C851F7 -:107D90000AF7F336CAA1CEE3DC5FF69BB2DBEAD684 -:107DA00042F9EC85410CE9428BAB9427F1FC033A94 -:107DB00012E05B26B57FA2AA77231F43BDBB5C8D73 -:107DC000BB742E611477D1C63B5F3348E2E3DD42DA -:107DD0007A737935D03FCA92A85F917ED13082E71D -:107DE0004794DBBA9750BEAA607060DC3C51A7D7BD -:107DF0007B5835AD37F17D91FCF986A84DD43F1104 -:107E0000C02366612B330181DAA36007A315F34910 -:107E100086E00B3948CF52F375136B5EE4FA511EBE -:107E2000F44C0E994FF896D65FFFB1887CA0C6221D -:107E300023DFC3DC2CE4DB04BF34C4A376EA2FDDEC -:107E4000C424BCC7C11426C74FE17E309C4FBF7EFF -:107E5000188FEB85A09FE17E855A3EFFD639FC1E28 -:107E600008DBCFE460BB8505AF67444859F59385CF -:107E7000964D49E61039F59B0BA583AA07F0D7E884 -:107E8000FB1B64D7C07EDFAA20BB2BBDB7BD9627E6 -:107E9000A6C179488DE58410DD7FBFDD2EE5E99927 -:107EA00080CF36E6CA7D13E0E17E5F247967883AA9 -:107EB0004CF0084470F8F4E8B38BB8BE0BDA791DC7 -:107EC000E55B83BCC3F3C33CED5180EFCC139A2731 -:107ED000A0CDABC5973A557E1C480B2C718581C748 -:107EE000C1993C7FA16BFD9714EF2E47FD167039A9 -:107EF000B0E1CF21F73F4616E71C9C497EB7D03C46 -:107F0000044D2F45394BF8EBE172B6D3934D7CE726 -:107F10003CB3B790FEAFE7374646791F6BC548477D -:107F200033F9EDEEA6BC911A8F45B2C073AE23D4DF -:107F30001F337F5AA83C2856E274F222D4DFB5D012 -:107F4000151A271AD9B68EF8D779D49B88DFF1F5A0 -:107F500018D5BC3213DE2F11D15EF7D0F3B0CA9F13 -:107F6000DF51F5CC08E4AFF03E0A13CB011FED2C36 -:107F700040E54188F22330A55DA67CC738A650397C -:107F800081B9A9ACE54126331F3DB5FC961416A076 -:107F9000F270D487442429999E23D00E19817A9EA9 -:107FA000A327DE4379937969142F2866CA1FB05D31 -:107FB00051F6E724F78AAE67944F0A9C64B9827938 -:107FC000250BB5322C14CB054C45CE7A5E5FA895B7 -:107FD000BDCB15E8DF99C3DB1B5FDBF8A4C746FC0C -:107FE0004BADBF87D7F7941B97E760D964A0B2A4C5 -:107FF000B62FCE574CB3009F936731C2835FE729FA -:1080000096E0B23B4F89082EAF2950A26625F49620 -:108010009FCF55ECC1E5AE5C655070FBA1054A0CE5 -:108020002FF33CD7F74D4A0ADABBF0B35B98C2F1A5 -:10803000107F5E35B993711CE51981E06501BEDDE5 -:108040004C7CDBC5904E816CAC9847047CC67C07A9 -:10805000D4B38966CAF73344D95207F247EAE92B09 -:1080600060627BD14F576C748FC675E9F99EE079D9 -:10807000ED6F98C703F4908B7A7E408D87046AB9C0 -:108080003F40A313EDBD7EBE8BE13D5382FCBCE9B6 -:10809000BDE3F6B77E3D1E1F51F5BDA3AABEF7BED8 -:1080A000EA97EED96FC018F389B597BEFBE79F46F4 -:1080B000F64910FFECBBDF534B4C5C7E48282F3A4F -:1080C00023D8A270F72AFB5B5F54DE4CD72CCAA7DB -:1080D0001826519C81697C9FF39B4EFC15F8E0B8F3 -:1080E000419AFDEAB0221C3258D2EC4C98B7D5C95F -:1080F000487FADCF3F5882FCE77C19483058D7A95C -:10810000DB4F23C531610FB7275A5218ADD79E26D2 -:1081100045A0BED4A0F24D0B8B291C89EB1F662411 -:1081200079AB5F7743B44FC0B8E2107F04F76FC4F8 -:10813000335F048C33C4E97052DE8A47949C582E16 -:1081400063F332A1BCAC4D949D30CEA1B65256091A -:10815000E3564E033E4719E93C9F2256C5E371168C -:1081600046F916ED09368A577B378E3EB002F9661E -:10817000B2C832A0FDF886894EF47BD6DB62632953 -:10818000E6A4AEA7DEE6781DEF61782403BF4722A0 -:108190002956CC43DF76BBD189FC3CE5B949D16295 -:1081A00010FC4F79CF46607EFB139281EA9FA8CDE9 -:1081B000B5DE68C37B847E85F20CA4938A0DE6DD70 -:1081C000026D1261BCFBAB4EB68C62FDE343B4D3CF -:1081D0001C82A7510EB3CE0F1AEAB734E9F4830715 -:1081E00066A9F1A4296C0A9EF3954F5D30A19EBB50 -:1081F000D426931F3DB749A0FC94C001472A9ED3C3 -:10820000A9FB4693DFDCDB24AA7E6B07F9AD0329CB -:108210002C15EFD754B408A4178BDEBFD461BFE18F -:108220009972328E337C527772B0BFEC89BB7E1864 -:10823000817CD45B6650FDDC8CC69165C59A06FBDB -:10824000FFD82BF0FC099324E03D66FBC36204AE2B -:10825000ABCBC4FD14CDC04FF17E6E734EC980749C -:1082600068FA1AD61964B734C4A747E2BCBDF8ABA4 -:10827000907FFD744B36C547B637E5523E887E9CED -:108280007BD7B30EB44F1AD65BE9D9A73ED595EA92 -:1082900080FE1FB7E6348290621F1F589584F783D3 -:1082A00056B4585844183C3EDD3A95E65B81F79841 -:1082B00071DE966233F2FD596D396684DBBDEB9554 -:1082C000E782E7692E76BF827C2FAAE539C2131BAD -:1082D000F37B109EBFBE464945FDE274060B9B270B -:1082E000F9EE2CAE67BC758D8BEE937C9C12BEDDD7 -:1082F000B1595CDF9F8DC43219F3D6D83B2B01CE28 -:1083000015404F75F0EA54537634E2AD89AD262618 -:10831000F59BB2520FDA73E7506F077EDE78D775A0 -:108320009B2BA15DC3DDA3DE45F67CA599EBCDECCF -:108330000391E802F4C20AA4CFFF5A6095EA83F8D9 -:108340002FEA8F4A487E1A971BA626D16F067E6EAB -:10835000DAFFC9DFD1DE41BC5582F0987EA6A8764F -:10836000819AAF913485B471FA69987D9DCFCF30F1 -:10837000EEB2DC8AE7A9D7D3FBE0499F75048D8F65 -:108380007A6E3E532282D6012CC14FFE72379FB7C0 -:10839000A79D5A6F0406F36D90FEAEAFD7F6317A03 -:1083A000B38E5E9DDCAE03F80E18AF1BE30BED97AA -:1083B000E16474CE6345E5E0272867DB45CAAB1E60 -:1083C000D7CEE3FFE78731F213F5379EC67FF1C7BB -:1083D00038588523C0B531BE84CEB3BF7E66DF1169 -:1083E000256D42AF7D382629745D5ABB8C9E7DDD9C -:1083F000C622B93ED881F699C5077C6F023E8F2808 -:1084000028BF33B7DD2E0DB46F3D3FC31F19D6BB58 -:10841000423D3219700DF9C3C79B05550F614923C1 -:10842000A7D0D545923FD85F09E27FC05778DE9E3E -:108430004F20F834B79EDA7E2FF961EC0EDE8A9F6A -:10844000D704A6C9419E07A4DD1364189A1ADC1B41 -:108450009FD2E0F8E9EE0DCF3E05AFCE3CB3E60B80 -:108460007C5A129645233CEF895F706D32B49B6055 -:10847000F625213F5DE9B3F4C13BAB862F69783F18 -:108480002FB4DE9214B47EF8D7BCEFA9CDCB504EFA -:10849000EDB33A30351CF1CB13029F407A31D05303 -:1084A000D75DFF41F7F323A5B34B28BFBDD642F7F5 -:1084B000BAF4F07D729641CBA7A4FB1A1A3D45B4DD -:1084C0008C66E85F3CA9DA4D2737819D0AE5C65ADC -:1084D000B38CDF35E872142B4961C633D79A4FE06D -:1084E000B9B2603B31BD779FDAF85D1EEE876C84D0 -:1084F000F18530FEBE8B8DF7AD4B59E904FCB21609 -:10850000BB56E1F3D4A6E5B4DF9ABDB55D6F429BDF -:1085100086C1EE9B9D09B8EE11530474441A65BAE6 -:10852000EFE7F5FE8CE449CB347807F67C4B8731D6 -:1085300002F50F8FD740F1DB968EF8C89128A76C13 -:1085400086B071D6279C1C5EBDF2C4151DAC0F35DC -:10855000E7737D48D853767F3AC0CB7B9CE7296A86 -:10856000FA87A4E2CD388B44FC59F2F23CB75E7D29 -:1085700088EBD5E751AF467D6972A5142C9F1AA2EE -:10858000F977302AF31D1EBC87996763243F86E381 -:108590006505F45BD8986F561A7E27C3C1303F3704 -:1085A00016F41F19303BB18DEB3B91369B43413C98 -:1085B00056385D59E13F846764A6C2701EA34EBF62 -:1085C00030EBF40751577ED409FAC438D6A34FC80C -:1085D000CC118D70B6DF37701E87E6CF05BD89EEF2 -:1085E000997918C01FF1D4EAA1F389064382E859AA -:1085F00051E4F8C1BD7A3FDE67E3FE1589E24582AA -:10860000D2487EFBADD9DCBF91CC78DC6B88C2ED63 -:10861000F909D33C5406FB81E250EC572C12F9F2D5 -:108620006E97FB39C48F34600368FFC58E67029173 -:10863000FB77D4CB59CDA5C5957E7C90FBFFBC863E -:1086400048C7F63078FFCE1C2E97230FC1DE50BFEF -:10865000BDDE4AF75B0AC4679A089F2619C8AFEDCA -:108660006547248AE7AB7C36A6D8F5A693E2B2AE7E -:1086700034847F92112C2A5076CDAA1F37E58EF4D0 -:108680004814F51F26FF9CE0E101D865C0BF6D3599 -:10869000F1B199F0FEF19A0D04573981FBC9B47B11 -:1086A000E77112BFDFDFEC3AEBC1FBBD1D73F8FDD4 -:1086B0009FC862E3EC74280FAF0D084877F7D89590 -:1086C00045A89734C93FA3F348CB920DE82F1B6A06 -:1086D00064AF5B2632F66C0CAF474189F58FD80743 -:1086E0006F0BCE27D9A1EEFB1121BCBEB2760ED7FF -:1086F0006B3AF7012007A17DCC54FBFBA94AB2B726 -:108700007BCA0037E8FF8087DBCFDDCEA72A3D2379 -:10871000C92EE2F59EDFF2F6182F85FAA237D6545D -:108720007AA0FDE369E1E7CD2CE2F07DFC8DEEC798 -:10873000308EF5D73A1EC7EAFF9CFDCC00BC658B96 -:108740009DA5B22B81CFAD322F0AF71D9975459C9F -:108750008F74DA3A085E0CE479F455748F5EAFAF2B -:108760005A918ECE49DBEBA6CA9C8F4C9E4257FB9A -:1087700039EEE9C6BDB8DEEA4842FDB37E5577035F -:10878000F28FFA03AB3EC47BE9E56566D25BCB8D25 -:10879000D5BF453BC87898E7BFE03726100F860065 -:1087A0003FC2FBA6B3AAF8F92D95B8BF56D8F391EE -:1087B0002B0FFDB1C946C24B4D8F1D67513CE89749 -:1087C000DDA2E6B73371581DDEF7320E15C9EF1B77 -:1087D000550B7A2DEE2F9FE7EB2AF01FF2214DCF9C -:1087E000B58D3786E4F59A7579BD465D1EF0D8C221 -:1087F000503E649F3C69407DEA576007E33AF703C7 -:108800001FC2A71FEC617C1E047B1D9F2F83BD8EA2 -:108810007EF057D767D2F3F5F50E7AFFE6FA69F4E2 -:108820009C911A30213E933F9AFC36CC2F905F4F9B -:10883000C3B36D2373A1EED91C5EBF68F6C8FFF009 -:108840005C0DF5F16A7BCF3784873D65367645EE62 -:1088500078F28353F9D5C2CC15E4275AA0E4170265 -:108860009E24185C15F89D0776A785E216FAFDBCD4 -:1088700057A8E59184B7E3197EC220D48F535238AC -:10888000B97F3FCE23025FC7DAB7D6EC40FA18545F -:108890006C74211EA7A687C60F9E2FE47429CCE610 -:1088A000CFD437DDC307BAAFAFD1477FF5F5FB00B3 -:1088B0000506F55FEFB5B36BB1BE3E263C5D95A8EE -:1088C00074D5EFF8366E4FB2D9406F43B1ACB70FE5 -:1088D00003945F72AE26CF4FE4F6BDE9AD3B05E9E8 -:1088E000AD2BC657877662D781559BF13B2122D2AB -:1088F0001B9205D21BC63F347AABE1E7B114E90DF8 -:108900007E9D55FB9E2B0FE93189D397B067FF1AE7 -:10891000CAC7B88BE7D168F416A3E6CB47491D64F4 -:108920002FD28739B01FD0DE1601EFF17CF211256E -:108930007F88450E7738BABB4C7ADBFC3DE9EDD732 -:10894000D704287FA2334D49427DC66BE27EABCB74 -:10895000A5C3ACD966FEFD8C2B7CC938CE16759CA0 -:1089600059C34E90FFAFC8EA10519E39650ED782A9 -:1089700049D9F4BDA18F0A79BF6FE62B1D445FD79B -:108980007D4A7EDE0403A7DFF7DED8417221A5E130 -:1089900068F12CC4977522E9DBFA7DC5CD53E366F7 -:1089A000029F1734AFE4E038E221952EE575C73811 -:1089B0009F8F615206AC27C9239538312E74B5813B -:1089C000BE2732A8F8680CCA676D3C38B824CC378B -:1089D00041D5D73AB12F3DC24F876970083D1F2E50 -:1089E0001CC02F7B31FE51A8D2311E3DF971D57BC1 -:1089F0009297EBB7EDD78F784578BFA44F95AFF539 -:108A0000269EFF01AD25FC2EC0CB2EF79942F2FB2E -:108A1000EAF4BFFD92DF8DFB58134D7EE52423D78A -:108A2000F792649EB732947908CE5AFC4DD31765FD -:108A300085E717DD50ECFE0BC2691B930FA03CB31A -:108A400039D8228AAF813C43BCD8ED52CED2BCDFAC -:108A5000510FCC2C56FE7B207C2ABE4EF906C7EF68 -:108A6000AF3EA7F8BF0E7D8BF45FC6FDA54BCBAA2A -:108A700029376B08D849B8DE996A7E46FD305EAF6B -:108A8000F957BD095AFC549987F993D12ABCC659A4 -:108A90005CAC02FA77A11CC6FB7B87037EBC176C1B -:108AA000C17B6412FA5119F58FA9117C32F6173F78 -:108AB0007B05E345A63CFA9C0863D3B83DA0DDBF27 -:108AC00091F22FCFDF98325BF5374E6493103EA9B9 -:108AD00006F9A1E9F03EFBD18263783C931F5B115C -:108AE00087E272EAB68652FCDED6AA9D1F6F437FEC -:108AF000E8F4DF5A189E07E88F7E63D87CAE7F9833 -:108B00001C21BA2A29FACF4A8F11F951783CED2A53 -:108B100052F54FC4D3F8103CBD7A76783C25FDE77A -:108B20007BE0E9CCD9A1785AA4C3D359B313BE17BB -:108B30009ECEC775FF37C6A9609CB30B95E2D903DB -:108B4000E065F64265E140F541F101B2FB46B169ED -:108B5000D6E0EF1E6ACF56949703E427C46E3C49D3 -:108B6000F971F535E7284FB9CB76F26DB483FEABDA -:108B7000C62207FBB3407F0FD1D75B40AE78C09EC3 -:108B8000FCA088E7411F5A67F1CF40BDB696DF478A -:108B900028AFDD2660BEF790AA6AC10DFC2D5101F9 -:108BA000D311FAC728865EFF09FCBBD27484F4D9BE -:108BB0007690C71E625FFC5E9A26FFC759AADF4007 -:108BC0003BB5FEEF46C7063C67261D407E5408F4C1 -:108BD00084F1CD6BBA41BE058DF7C6BE69E4579BE3 -:108BE000F135C8BF203F4E0E8C185CCEB32687F4FB -:108BF0002B90D242EA67258D09A9D7E8BE33468D6E -:108C0000AB4CDE918FF82356F03C8542392BA47D86 -:108C10007B592E7D0FE0CAE9FCFEDD9CCCE921E307 -:108C2000EBF582ABE13FA47751A707E8F504BD5E01 -:108C3000F0E3D9AA5EA0DE57D9680CE4127F623C4B -:108C4000AF6EF8855F131DB4CB1CCFBD6567291FC0 -:108C5000A31EEC7FF4370D0DCA2F45BA98600E9015 -:108C60007F6ECB622B9DC7967D4FD1772334FF1744 -:108C7000D00DD1D1845C89F25CC7DB1FA4FE6C15DA -:108C800097B37ABA146A5F24FD6FEB7CD81BD8EBDC -:108C9000B9F3D2B8BCDD1F203F04BBD3CC506E7AF1 -:108CA0002503E58DFD58F0470823907E15924F2C43 -:108CB00089495ECA977C8F7F4F9131C7C66434FD66 -:108CC00015CA6B04B4EF7E43CDA345BC8D7032C78B -:108CD0000628478DE7F41D3B899F8FCDC1CBD2D5A8 -:108CE000BCACD9DB3149AC05F36287E278D036BE43 -:108CF0008649F5E4D7F053FD30273B524FF3F3FE9E -:108D00008995CCD50465B15A51FDCD6E35BEDE4D89 -:108D100071EF74C11189FE8D11A28BE2DED14CA2DC -:108D2000B8F810564DCF28C1CF99C777E423570222 -:108D300000505EB09BCCF4FD8CDCA76D8CBE6FB494 -:108D4000CABC9DF2B20232F911EF39CEEFE16DB13A -:108D5000FF90E2044D6FF3FB04F7A4783EC478E67D -:108D6000905A81E13D56B18AC711C4D745C72CA896 -:108D7000176B5BE93B70895506F26B5D69AE3E404F -:108D8000E770B785BE1FD705FDD1CFD56E3730A2AE -:108D900057601E3DFE54F8E9BAC645718BAEBF0F51 -:108DA0002279C7747ECE7A37D7BFEBE3CD1CBF6C78 -:108DB00067FF807CBB313E92EEC72DBAB6FA6DE4F8 -:108DC000235BDE131D1B54FF33FAFF87E32F987FCD -:108DD0006076A5A1DE69AE0AEFA73433D7BB93D185 -:108DE0005F7AD7CAA481F4A87EE3223683DF1C7D94 -:108DF000E9719186721E07D1D6A9EDB3D1B6465856 -:108E000026E36FDF332E52D64F5C24502D20BF1F38 -:108E10008EF513103EDC6FFD5DE322CFCCE5F2F65C -:108E200072E322DABEE7AABF170162ABF91D14177D -:108E3000A07333F4AE2F088E3B707DE5F89BCCDF3A -:108E4000639C61BE5A7EFB99A39FA15FFFF0EE83F6 -:108E5000CFE073C68527CAD6005E144FB393BFF721 -:108E6000DD1FC53CCC870B8D1FCC755842FCF7F835 -:108E700083F849EB10F8BDFCE0FA62DDBA728DA10F -:108E8000F1807C5B68FB99F1A1F5CE61A16533AB04 -:108E9000263CD5EF7743D4DD9427D7781B73F00CAD -:108EA000F1A0F3102F5E360F3387DD97866FCC91DC -:108EB0004674DFFE3EA77BD74BB7BFB196EC580395 -:108EC000DD9F3FB7A8E19EB764C40F33F3D0384E9F -:108ED00005F1E8AB9F8E7F87623A92DB7323B45F24 -:108EE00096C7BF17D5279EA0FAF387D71CE8C80FEF -:108EF0008EF70E76AF9E03FC7CB8EDAC807AC8F09E -:108F00009A97A9FEBAC59307C4A38C9A431DF94149 -:108F1000DFF5CB30BA0CE8C7C8A87995DEF7A7F71C -:108F200018640FCFDF2B33CB646FA9796A192ADE5F -:108F30006494717FAB94CEE5CD1613976F1EA8167F -:108F4000AF82FFB5E9F3DD385F3F3F8DDFEB60C0F7 -:108F500085905F69E3E9E59926076C0AD72333CA50 -:108F60001EE17245CB176CD3E7C5B91F44F808550D -:108F70008DD46E6B9EDA6E3FD74FD96C26A15C867E -:108F80007D86CD137D748E1A2FEA273F8D69F6E317 -:108F900082D73FC4FCBCCBB61FFB1977466A20ECD6 -:108FA0007DDB3D85DC7EEC8C08A4201FEE3485D76C -:108FB000DF1B17CCFCE99C01F457CCAB4598F66B52 -:108FC0002F7CC7BCDA0FD57891162FD5F26B99D1CB -:108FD0003711BFF39969FBE0068A83F693577B8FBD -:108FE000DD11C07BEEDE8A08C776F6DDFDEB279C3F -:108FF0009C9FEE98C3B8FF5E175FD0AFFB83393DEF -:109000007185E373E85E58F8B842CF3E93C3FBE343 -:10901000AE98A7DDF757EF2B39B9DEA79814162EB7 -:109020000F54CB77D7BF077BE8CC9C20BF9EBB2ECD -:1090300083FC76F5268EB71E997F4F50D31F6DA8FF -:109040003F921ED542F5D1555C9FD4F42C498D6BCF -:10905000E8E909E8E3AF388F60E374ABE9893DF4F0 -:10906000711DD007D0E530C6E34A06356F74989578 -:10907000A7A07F573DAAAFFDF4B5FD3BD94F753B87 -:1090800023C87EAADAFE06EA55ED35DC4FD869AF73 -:109090007E03BF7FE0794F24BDA9BFFE9A1D95389E -:1090A0002FD48EC2B822E263A2CD27C857A01D15C7 -:1090B00030B9617DE56847D9306FD53DAC28A1AFA7 -:1090C0003DD575F79F29DF15ECCD94A27F047FD0A5 -:1090D000F9970EAA791007469E25BF8958C3ED3D22 -:1090E000B186C7438D653C6E6154B81FC50CF2084C -:1090F0005D819A1F658B23D48FD295C2FD2889F993 -:10910000D57ED4034DD32C9242F291FB55B4BCF6DC -:109110007116DF1B781FA33ECBC8300F1D1455B24C -:10912000032D6A7C83957179A5F94DF479D3369D29 -:109130009F44EF47C92F0AF59B3C2EC8F74E87790D -:109140009EDF5CF016A2ED7F6E5D11857E93177D2C -:109150000D7354BFC9A3B89E7D1F72BF49D73E6E21 -:1091600017B95181B92A1CFEF58953911F64DDE1BD -:10917000F5142FD3FC5089552A3CD4B80FC217E1FF -:10918000293A393C6374F0F40ED3E2422A3C133896 -:109190007CCB8B5CE47792109E522F3C353F95F749 -:1091A00070077D5FDBB2CE227B089E9F91BD6A4235 -:1091B0007822FCBFA71FEA9622D52E55E139F1D1BE -:1091C000EC87F03BC1931E2B3D86CF29DB6E8BBB1A -:1091D000019ED3763E548A4FF63A8F13FC752EE7E4 -:1091E0005798D91D4C8F3715CA21DF83D7E0A9E1E5 -:1091F00061AFFF8E913FB65CE2FEFC72150F33103B -:109200006EC1FE3C4728DCB6A8F992C6FC6A0FDAAC -:10921000BBC37570D3F0B01EE186FC2EC62C7BC894 -:109220007F572BA03DD41F1E0E6FBB3C3C7C588744 -:10923000873FDB9C7D2FC2EB85ADA56FE1F3E7BED9 -:10924000DBA2105E7B773C34A71FB82587F07974CA -:109250007227F485DB8962F70EE40F331C3E23F19D -:1092600059C037B47BB7374DB486C66734FEE8B40F -:1092700086931F17F72FADA1BCC2FAB235C41FBB2E -:109280007AF863B71DF3102F953FE6CDE5F7FACBDB -:109290006BBE7A6506C035AFE604D19F11E88FCE6C -:1092A000ADF68441CDC76011202F12CB981FE3C7C4 -:1092B0004398D51725507E02F14D2FE639E3074A32 -:1092C000F57E0AE9D5BF09441C4C3024011FC7DCD8 -:1092D000A92B490EBE5934B92F9F6D2F3390FF67CC -:1092E000BBEA1F2C5BE03A8CEDB4F8D66E97F276B1 -:1092F000D1F7F36B1F2F0AF21776C6B01EFF1A7E46 -:109300001F3CAF669B807928436A6F25F99058A669 -:1093100030940FB7CEE67462CC9768BF7DFD6DDDEB -:1093200079682774E28DF62CC2838F110F3A6B9EF9 -:10933000243CB87215F78F74D69C8B0B8F073511B0 -:10934000DFCDCFB83D444E7A6BF8774C3AEDCAEB9F -:1093500019978107CB543CD0E424CA1BC427635916 -:10936000E051F4630F017C88484379C9F9B108F2F0 -:109370002A0AF623F6E37FD4E8A10BD6661984F710 -:1093800084F5F900D5B4EE7365B9FEA903ACEF928C -:10939000F300D4B864BD1A975C5AC3F3573BD77D2A -:1093A0005580EB3D5706F601C0657B9983E1F9CD09 -:1093B00002C52A600B9EA74FDEEAB0B909BD71480D -:1093C0002D9E7FA2D8958AEF67004E25C5625EAFBD -:1093D0001AEF19A67E075A87FF80E7A3E6925F4E31 -:1093E00022B9A1F9D119EA8D76C46F6534D64F3010 -:1093F00057274B84DFEEF1586EDF7727E52FF4FA1D -:1094000007793EDCF7F66F459B29BF52F36F79ED84 -:10941000DCBF55C10205685F531C01F976AB85BE00 -:10942000D75029C866F2AF95B895B9A4F7B8281FE8 -:10943000D6BDC02A911F6CD5AE64E417E58D22C954 -:10944000EBFEEC92BE7476997C46A5BBEFC067AE8E -:109450009F7B697C6631EE2F88CFDC30F77BF099FB -:10946000F78B42F90BEA9D75304F9E4A4F3DFB56F4 -:10947000E3F818BF8AC80AD247D5FDEAE9A88F5E8B -:10948000FA7F1F5DDD83700D43571BF1FD65D055DD -:10949000EB45E8EA413CCF20BA6AFF17A5ABA72FFE -:1094A00085AE94B92C344F3A8E7FE7795C9C81E786 -:1094B00059FE1FCE931EA3DAD9FA3C69C6AAA95C4D -:1094C000046743E7A396E74D6232C6992CDB5EDE64 -:1094D0003456E6E305FB3B99CECFC9747E4DBD7E85 -:1094E00017C60F1AE2F73CFCD4EF0E8F855F9F7E04 -:1094F000F6BF49AF7D7BA640F7C9E78DFE6A3FEA1C -:10950000A0C51B97A9F30CECF7FC67FB39F127D832 -:10951000AFAADF5763D4DDEABD81CBF37332C7ADA9 -:10952000F47DF3F66AE640B85FCCEFD95ECBF3A6E4 -:10953000B5BC66D74B950F2F9CC4F3E9D0EFA9F7C4 -:10954000776AF9CAF5B665A4E79F54ACDC1FABF3A4 -:10955000772E8B936FA17B8C7DFD9D91F3FE01FE99 -:10956000CEDBE7C8DC4FA3F37B96CE52E2E70D904B -:10957000CFD019E360C8EFF26C3E01E3B5EC4236A0 -:10958000F97586D802F47DADF29A1CD2034716BB5A -:10959000D3701C637EF7E72F4EA27C03070EA5E76E -:1095A000CBA067A6CFA33CB67F8E9FE09FE5E7FBED -:1095B00068CEE5DD9FFF08E13D79807BF472E0B184 -:1095C0002878FF789D9DBEAFF5FC6C59CD3FE84EE5 -:1095D0006981FA77EF3A7310FD13BE3603C3FB6D52 -:1095E00097EA3F6AB8885E6CD6D9475B7AF462DF47 -:1095F0001B5383F4E286F5CE7DA7C38CA3E9C5BBDC -:1096000074FEA3721BD78BCB6DDD26B40FCAE3BFEC -:109610007E05F34E8D55AC03E5E210A59AF4E144C6 -:1096200089513EF1FF8FCBB37F685CFEFE79A1715B -:10963000F9096A3E0AF278FCFE4F97E6479DC6F5A7 -:10964000868D466EAF78157817268EAE8FCB0FBFFE -:10965000B087E2F2ED7BAD748F6FCBBE663E5E0EDF -:109660009330CF3C99A9FA5A11F797EAF58FC74D75 -:109670008A356D12E2BB81EE13E23D41F28BECB50F -:109680006E437FD3783BCFE7CE7D67F14ECAE7D6F6 -:10969000F443D043492F2E0BD07799CA250723BE18 -:1096A000133FCD4FF1F15A81F06BD93C4E6F4BF324 -:1096B0007DA41F0E2993047E4FCCC3EDF8541E7772 -:1096C0008E44FC82A662268FFB4A474407C69DEF64 -:1096D000C3A6D3F1FE2AE3DFAB986EA0BF43D12E21 -:1096E0007427215F6E1594647C82CE44F71E9F8D93 -:1096F0005106E3DF93AA4F31D0DF933A54D09884D8 -:10970000EB6BAA6B4D42BDF015D52FDE5AF009E583 -:109710003F98C6833E9846CFB07F77F4C1F982FA6E -:1097200077043B92E87B08ACE543C2AB4C33E37F64 -:10973000E7C7E15F8EF474DA46FAC203828FDF1363 -:10974000B25BE93E5ECB18737225ACA7D96E266D6D -:10975000C23B66E6913478DF9C2045631CC09B9633 -:109760002EA1FFC81BD3F83AFA419AD3D219E6FBCF -:1097700037954DA1F879D3056030D0B37EECA8774A -:1097800027C3FB8D4280BE1BE4996E60984FD8368C -:10979000666672F0BD4C51D2CB4907C9055136D02F -:1097A0003D3F518D678B7DE2D9A1F1E949EABE6564 -:1097B000D6B288EE81C69B25DC6FF998920FE99EA0 -:1097C0005BBC99F282CA4D8C7FF7630CA373D1C343 -:1097D000AF7E7D685CC1680B5DDF460C4C531EF6A6 -:1097E0009695881F0D0853CAE3BE7725F2A5869E7D -:1097F000FA465E8EE0E5AFE7D5AD44392833FEF793 -:10980000491A3279DE65794209F1E1725320EC7729 -:109810007E2FB61E99F914753CF63F39DEC631E647 -:1098200045BEF1171FAFF75C407DFE0EE36AEDF415 -:10983000E3EAFBFD4FB5EF6F9F89F3B5BC7A46793C -:1098400010A422AAF7D9504F36AAFCB03E778ACF8F -:109850002F233FF070BA883184CDB3ED9F3E82C68E -:10986000E749BDC46F697CFCF64C4DA11FF923BECE -:109870002F49EAA59B9EFC0B753CA87A15E5C3D63B -:10988000F942CFBAA5C1BDE3FEA62CDB8F761CD86A -:1098900019729C230CFDA9791AD43E8DF26D283FD4 -:1098A000868D65C447B4F646755E7DDEC66E152F9F -:1098B0002E376FE334EE6112C91AB207BDBF6DA136 -:1098C000FC25861FA342FF5C9644F7E1EED5DAD96A -:1098D00019D971DA3944B0DE1FB4D392B482CC46C0 -:1098E000E23DC38DA327D0DFA77C74F7833FC1FC83 -:1098F0008DCDCF6CF8233E23474EB87FDA24BC478A -:109900006F70A8B9D4643F69F934B67FDBFC35EADF -:10991000A9FA7C95C6F12B5AE8F882CF311DFF2EAB -:10992000B2A0A07FDF62B36DA7EFF95805B21FC4E4 -:10993000871269FD4995A1E7DE2E281FE077FF3CDD -:10994000F709C447231CA1F9377A7BA3A9E75C4335 -:10995000ED940784F071EFD7E6733923EAEE89B608 -:109960009A64FA8E6DEB46112399AC759D85F8D9F2 -:10997000EFE72F5989DF19BF03191ED4B75F63A61C -:10998000BF6BD56E97AE5B8465559E6971E607AE79 -:1099900018E50BFEFB47AFA29C85F95AAE31933C0C -:1099A00060C66ECA63D7DF0FEF6367E9F0EE6278D7 -:1099B00076C3FC5835DFC04772A5C7BE1F6DE0F700 -:1099C000A0471BFE25EE41BBE787B7EFBFEF3D6821 -:1099D0008AEB25F4A55F2DFF6F4354EA62DC7FC359 -:1099E0002C337D2FEE72EDDED6752B495E786E65D9 -:1099F0008E0C47DFBC30D74B23097FC42691FC7106 -:109A0000BDF8C5EDDA5FCC33F5FC9D166B109FD425 -:109A1000F2821E52EF153FE46AA4FC19AF93DF2BCC -:109A20008E685949F6722BE8619857A5D9C727A7C0 -:109A3000A54F1128EF47F1E0773D4EE6AA79415254 -:109A4000687E0B53F3FBB4F95AA7A5D37C5EB4C769 -:109A500007C003A353CDDFD38DD7C3AFD1EE0EB272 -:109A600097C1EEFEDB7CD8DFFD36073AE3A0FE654A -:109A7000AA6793622FE91E6817FE0AED7E50AAD0EE -:109A80009F48F9DF0A551CCD00800000000000004F -:109A90001F8B080000000000000BAD3B0D7054D57B -:109AA000B9DFFDD9BB1BB29BDC0D9BB8C1106F02A7 -:109AB000D1203F5E304913C572F303244AEDCD0F28 -:109AC00009BE01DEA26871ECD4ADB5BED03ACDC5F9 -:109AD0006C4888084BC4065F1D8D54FBDAB1D5D4A1 -:109AE000D7D7878EED5B90E7F84FDADAAA333E1BC3 -:109AF000D1F2FA3A9D37E96BB1E98C2DEFFBBE73D9 -:109B00002FD95D36809438E3E1DC73CE77CEF9FE51 -:109B10007FCEB655D53AF91180E350080AB61F85B5 -:109B2000CC35610078DF6706CC2500A7E86F1540CB -:109B30007FD20729EC836A0260BB0E263775E07C72 -:109B400058E88327B15122CBF9FBD690ADCA4180AA -:109B500012BB12A078667D1BEC57EFC2F1AB7C63A1 -:109B60002D500390D80ABA834BB684922AF5570336 -:109B700038801BAF351A031508B7F505DA086055AC -:109B800078240232C0B2E70F94C5687FC7FA7975AE -:109B90001DD054FE5BEC9FB09B717DFF1B8A791F2B -:109BA0007FD10FC770BD1A5560182148CFAC8C4EBD -:109BB000E279D4E089F7A000E0BA29809680587B4A -:109BC0008AE04F07A0A57AA6DF8890D3FBCD81D28B -:109BD0008CF9ABF58A8C71052C3325E1B9A38B3256 -:109BE000E6856A6B743A6F9BB13CE3FB0DD50D19AA -:109BF000EBA1453D3E89FD95F8DFA94A8227FA3C55 -:109C00005E01105C82FDB4F52AA4F571FC1A3B14C8 -:109C100039B1183B9F81CF9C52882EE60620BA802E -:109C20006C3E897829793E30998FF803CB32222512 -:109C3000880F1A3200BE6CE3E25AEC074FC884FF6B -:109C400047F271EF52C4B33E29139D401F97F83B72 -:109C5000C0F830223BAA5A3C0FA2A02770DEA5E034 -:109C6000483AF6435148527F3E24793EFE251F6C08 -:109C700040B60888F5051D60EEC5F1FC258E24610F -:109C8000BFA8154C05E105CD0989CEA9E37A05F9F0 -:109C9000A01452DC2F6B85897E866FDD47EB4B7BF2 -:109CA000411F2825B00E8F8F6D0487CEF33898E0C2 -:109CB00057081F36C002000DE2DC5E064611221175 -:109CC000BE0DE60AEA57C1242115A93A2651FF1212 -:109CD00018D7A90F90027B2936936AF84480A70011 -:109CE000F1A9C7AFD92DED74C2A30B4E1EBFD1DAB7 -:109CF00066237F77DF545B180BCEBE4EED7D71BCC3 -:109D0000E5EA99FEB76D83E542ED5DCBF2A2F6BEC2 -:109D1000C4E3476DFB2B36D26319C20FACF8F4F8DD -:109D20005FA6097C2624301D9C9F78EEFAE8161C5D -:109D3000779E0B985540F8457C125FD407A65E6964 -:109D400010EB891E11A407E1BB6809488483F9441C -:109D500007FCAE211D76311D930CB73C0EE60E7745 -:109D60005FEA97221D882E63A0CF21BC2AF14F47BE -:109D700007FE4338971C0A3C3E2C1176912E0B2E81 -:109D80000A5DBE752174C9A607DC3B17A0E16CFB18 -:109D90003A4CC76F49A93C69019105E983F7919055 -:109DA0003E84CF28087A680026E12917FEA99F572C -:109DB00003C67DDC17F3899E4EC30CFF1722FF8B71 -:109DC000BE90AF30D241F4059D22242FD88FDAE324 -:109DD000BCBE682BD80F94123D2C469E0F62DCFA55 -:109DE000614AA2B65232995E0B145BA67EBE9412F3 -:109DF00048464A923E28009DE9330FE2DC467C53F8 -:109E0000874F91BE0ECA634E05B5CF36D23EFDEBED -:109E100050C390CA0F8D34325FDE0E7A15F25DB9F1 -:109E200066B1FE2EBF52351D231D5FF7317C30AC6D -:109E300003646FCAE5100CD7CCEC9BF099D124D207 -:109E4000EB58E8C491187E9F53AA80DF9CC1F37140 -:109E50009FB81FC1542E257910F211ADC7B384CF1E -:109E6000D46F5155F06D701BE20FF1B19906104F90 -:109E7000D2D0BFF3F7479A85BEFBAE1DFB88F885AD -:109E8000F413E3CF029DF4936E02EB4DD9707E4341 -:109E900076F1E490DF203E85E4A815C07DB6B8FBDE -:109EA0006C19F27F2015A4DD33E18794A79F2B69FD -:109EB000BD5DC8FC6C4A10A83BFF7517CAFFD05B9C -:109EC0004CCC764EBE6D7C6665E1E492D9E76924A0 -:109ED0001F73D3D7093A6911E4A7208DBFC4E3E704 -:109EE00082E3EB3D9C21671E1C5FD46638BEDEA377 -:109EF00042DEC86E213D6F43BB358CF8FE474BD721 -:109F0000045F4EFD27D9F39BE30526D9734611CE96 -:109F1000BB25298D0D233FDE0A718DF85482850EF5 -:109F2000D16FB32399C338A572D7D602F617A045CF -:109F300027FC48A96B95538B3F051E5D3C6D4EFD7C -:109F40008FCF08115E43F0A1375E3933FEC78D0B0A -:109F50008ED51AA4B483D544DF7C97BEA8899CD73C -:109F6000F09CBE4F0A615847EECFFFC61BABF07C9A -:109F700003BF504CA582E6696021BC3920EC783ED5 -:109F8000C9E902E297F1D41DC46FBD853ADDD79BC4 -:109F900007EE3C076216DD331FF500C195F37733FA -:109FA0007FE6176886C2CC8F1A27FD1E01E4BB121C -:109FB0004635FF156BA914C9577153C0DC91095F71 -:109FC0003A45EB112694B8F790CEDC7F29F5033C97 -:109FD000D478CADDCF0AA4ED97D5F745D3FA20C6C9 -:109FE0009DF4F9A606A934BC9E961757CEBC7307FC -:109FF000835AA6BC64ADF3E8B1C427F8635E198C3C -:10A00000EDC0F30E0D1D6C247D335A0C861F8706A0 -:10A01000377F47029CDF44BA98EC4F0B8CF925DA66 -:10A02000C718AEC6BEAF2CC8FC73C96FEDD41D08EF -:10A03000E70BF57EDD409CCCFBBDA537E2F86D65F6 -:10A0400001D342FA26DCF94E0BFA5962FB5F915FAD -:10A050007AAB7B5EA605CAE1BDEDC2CF52C35D3BC4 -:10A060005FC3F9FBE629A0905E53369A649F6E5554 -:10A0700001E616617FBF8FFD3EF4EFF83EFE964C81 -:10A08000BFEFB6477C197D5F969FF8F576F403899C -:10A0900068AE1F38D00EBC2F9D67EE8ABF1F3E04EE -:10A0A00023AC3F97AA13B29EC3AE7AF8979E0932AB -:10A0B000FE7F528C78A575605B7762DF8F78247E97 -:10A0C00045455D508B78B2E89F06F9C93FBA8BE6EB -:10A0D000FB4F22FFD27C25D87227D1E152174F20A7 -:10A0E000CE65E17F74EE6C7FD89FE50F679FDBA3A1 -:10A0F000C3631E7EEAA08EF083FE39FB07DEBDB28D -:10A10000EFF3421F6A0EE4A59FF605B84DF5E9DCB2 -:10A110001EE98B727BB4CF801674AC5EEAABE6F6B8 -:10A12000E53E93BFBFDA57CFAD878FD9F44DA8581E -:10A13000667F61DFBDF2180993BA447FE50AE2DB6E -:10A14000B714561F3A1879EA02B643A0E2BCCB5ABC -:10A15000D5318BEEE2C63F97B87CB6D83F75D88F25 -:10A16000EB92A560DE470BD16E6FAD99897FAE9BF8 -:10A170009267E40428DE9933636780E29DB919FD94 -:10A18000E6C0A519F357EB0B32C63DFA3ED628E4DC -:10A19000666D7471C6FC7D2D4DA92F905FDFE0D7F1 -:10A1A000159DE29FAB33C66FA8BE36031E28EB4C4D -:10A1B000D2D3451BD3E8C6F7CFA4ABB6EDEC719074 -:10A1C00047E7F7DA33E3A1D9E89BCDB71E5E8B4EA4 -:10A1D000E355C495098A2B0DBAF712690B82DA731D -:10A1E000DA2FB1C00ECDECABD6637CB9ECE2C797E9 -:10A1F00005145F56E48A2F3FD2897FCF195FB66678 -:10A20000C6970559783B577CA97564EA95F3C5E76D -:10A21000E6F2F81BB514EFBDAEB01FA8B4C6D9FE68 -:10A22000CD9D50CCB508B7D8F5C74224F3386F732D -:10A23000ADC6FEE53E988C92DDDF2B215691FFE7FF -:10A240002E314B49DF3C1DB64A6EA238BF4D360F4A -:10A25000E292171BBF1925BF63D78EC7A36894600E -:10A260005187CCFB261B4F6C22B9520DF4E3246EB0 -:10A27000ADB11CFE8937FFAB033EB6037B37696384 -:10A2800012CEDF1BD2BB3750DFDD0711C2F676B42A -:10A29000F6F231F2FFAEEC3004BF801325FA3FB87E -:10A2A000A9AE948D948AFDA534DD643B3E1C32AD8D -:10A2B0005B887F7E1304073F3D20E90512D98B4D53 -:10A2C000B2FE24DE73B475C5BB5BB1BF2BA8992465 -:10A2D000F089705D29F197B219DD1EEC8FB48EBC48 -:10A2E0004CEBD52A99FB894D971F23F779B4586F0A -:10A2F000ABA4386F7525611A94439FF4515E231106 -:10A300003E11A5F5FDD788F5B3D147D1D3EC39700F -:10A31000FE82CFAB2C94531AC2515E38F15782A7FC -:10A32000A4DB71D6E3997EC57058A32001D6FF7CCB -:10A33000E1F71C9554B965111D4751E6094F9B374C -:10A340007514523CB5D937599CCB5E0CA07E4D5D3F -:10A3500091E66F4632FD846CF8FC5747F8C53F59CB -:10A36000748D123774C1BFC48D6BC652843748B622 -:10A370005652DC1B147679363CA8C14C3C78F01957 -:10A380001EFE4FE9CDB3F2D2F080D74A91BF73479A -:10A3900087C4F4FF22F141AD3806C51DDEB9D4569D -:10A3A00099D779FA01F978C338F1878BF7289A0C95 -:10A3B0009243EF1C5F75E1DD739AAF706A49DA3939 -:10A3C000566A2E3C93E3E2AB342157F02BC57CD286 -:10A3D000C84127D77FE3F51533E3AA7BFE2B0E6830 -:10A3E00019FA7788F6C77BBCBDB1F3ACF1F2A2B124 -:10A3F000CC75DFE9003EEF958A75E404F95257C841 -:10A40000634F22A8C557C82CCF27D1FF22BB361BCC -:10A410003C8FFE2C6225CC5D407ED9CE4807F3F9F7 -:10A420006CEBB4B109AB6219ED0BF171E4AF45D13E -:10A43000CC7379F3BE73FA5E5F8139741E74C8C938 -:10A440001EF9C75216E9693FC291B0AD7EFC6EFDA0 -:10A450006CF7F6431A7CC4E74792D0574E18F8BE03 -:10A460008977C7587EE0D0D48724DF894525C63058 -:10A47000CB0B4417D6913F22EEE5CBA2D3709E8042 -:10A4800033B25CF8A9236EDF592AE042BA9CE2FAA3 -:10A490003C37AFF242C702C6BB467A8688AC5AE563 -:10A4A000C41741F5878E8EFC3027B80FC2D8FA2327 -:10A4B0005B1C6A57951B7BEAF15C238B64B66323B4 -:10A4C000A1D8E303A487160573CAC76BAE5E1C222E -:10A4D000BEE5F8092C99E44EF284046232D26B9402 -:10A4E000391FE0FD8EB0C867E9C9FA9B118F6FBBB9 -:10A4F0007C81F7E1F5D9F0DF3D13FE13C4AF0917F6 -:10A5000038C1D982707EEDCA0590412971E33EDCE5 -:10A510002F6024EBC95F98ECD0C5B8BADCA4FB8FE0 -:10A520008473EF37E9EE67C97189E65DB251AC8794 -:10A530008058B7579ADA705CD093E589F6A7F17C1A -:10A5400033533F64C3CDABCED4575A59E6FCFF75A5 -:10A55000F92F3B1E7A40CA7DCEC24E71DF55E5C051 -:10A56000F688F8E2BE1C7C912DEF1AE53F11EEDF74 -:10A57000880EBC9FD03B4175A229BF86EC3B98FD5D -:10A580008CD8C37CDFFBF26FE43879E00691E7D02A -:10A5900054A1B7CB362018B4C7F64F5A1CEA2B7714 -:10A5A00083EE0F9F89874F1BEF91BD71D2D6873BFA -:10A5B00081CFA9A4C781788FA4CFB891F64DEE5270 -:10A5C00080FC80E476FF865C76BBB8C3E7E95D8EED -:10A5D0006B55972FC0AC0019D71F784BE1BCC081D9 -:10A5E000FA9D1C17276CCD902A284FF1086CC7F1F3 -:10A5F0003F5A32FBADBD87EEFDF5ABB8EC784B654D -:10A600009D24B31CC1AD38FF38C6C5E43793FC6543 -:10A61000E46310B181BA99FD922D95BC5F02F79366 -:10A62000CEA2E7541BE3D66567C23B6D8FB3F2231E -:10A630000325B1DA4EBCDFBEA0A8B3285E7EA42BF2 -:10A64000725E791D0392A95ED22B1B81F1106A1BE9 -:10A6500081ED944F888A38E348AD5FF0D776C98D95 -:10A66000CFA0053C3D857FEB361A0FCF25FBF28E40 -:10A670001FAA70BCE9A9D755EA8F94CA75143F5F29 -:10A68000A54DDE7F158DD7F9587F3422255319FC4F -:10A6900091F2CB513E8FE6B68A685312B5CD81FC5C -:10A6A0000C7DBD5ACF8C3FF64C1F510A893F753047 -:10A6B00025C4F39E46D32A24DD634EF6D3F73DAB83 -:10A6C0000D73D8207F38334ED9D3A6097D5A21EC9B -:10A6D000CEC861E361F2AF067BF3D8FF7CA04C16D5 -:10A6E000F75E0863C40F6D46665C33325EB96B215A -:10A6F000C959D2C7F9F2EF8F8BF95B772C1FA3B83A -:10A700005477FDD5ADA54DEC87C280987743F5E22F -:10A71000ACFB4FE8C417C9ED3E20FC0F96DD3C446E -:10A72000F9D00F12BEAB495C5EED3432E2C22D03AC -:10A73000B7729D6840839BE8FC7B3669CCFF7B8ABF -:10A740003F38700BE9E9E2398CE7D14D5A692C4D5D -:10A750001EFED6E9673918DD24FC8B621962E339E5 -:10A76000C6FFD629F4D0E76E07BE4F01DA65033F76 -:10A77000196A3CE5277C9401FC335D27FAD1437CC0 -:10A78000FF5619AAF08823918DECBF65F359B0AB41 -:10A790008AE19DB68FF572061E7D7E3BCE79EE1B5B -:10A7A000C0207DD5D28A7D8AEF376A40FCE68FDEF5 -:10A7B000CDF72CC27E1EF603AD4947C57E6061EC25 -:10A7C0006AF25B5FDCDE334479167F44D689DFFCB6 -:10A7D0001B6FB33B697E8D0FF2707C000C294AE73A -:10A7E0007424207D6D40AC95FCF591A8AC53DE66D9 -:10A7F0005D62FD36DA7F5D640E109D37B7C9BCDF40 -:10A80000494BE3A45531391A94FF2A09B2DD7DDFA3 -:10A81000177FB807E7BF8FF47260E65E873A2BF9BF -:10A820009E794666FC1C8024DBE195D6C446DA6737 -:10A8300065BD46150D38D270E200F9EBA3B57ED3A5 -:10A840008FE71A6D9018DF1FD7FAC6F0A8F0536D86 -:10A8500042A17D7FFA31F246452EF93DBBDC64CF43 -:10A86000DF53DF11207ED809135D841F675A66FB12 -:10A87000953DAFA14BD07F27E285F0ECE079AB2886 -:10A880002E9A42B942E8E169FBBBB760FBA54E9541 -:10A89000E77DB55476A82E34D8A6B19C0C866243C9 -:10A8A00015D4477EE7782812637E1E298DB01C7A66 -:10A8B000FB8C34745713BFBC519BC77EFB973B4F37 -:10A8C000DCEE2C44FDA1FCFE5F9FA1F8A94C637A4D -:10A8D0000EFAECD4ABC4D76DC25F3C3AFF1E96BBF8 -:10A8E000818D3703E10D9CF83B54B71AA86960F8D5 -:10A8F0005EBE6164BEC8270D44EE7228BF91AA17E0 -:10A90000F905ABF820E7F3BCBC52A3ABC716FBE3D9 -:10A91000AF54D1BADB55511756CA12A40FFC945745 -:10A92000A2756A66BEEBBAA9CC38785E561C9C9DAF -:10A930006782C0C4C24EB4A7BFEBCCCC2BD1155894 -:10A940008E6BFC1C2F8ED68B3828E98B97EA4BCE6A -:10A9500094E3375D3F78A22F801C00F0F33E9DFB0F -:10A9600005D61F76CC45506FF545F9FBE7573E2ECF -:10A97000A5AFDB53B33E60B0DE988C12DC6C7D91EA -:10A98000CD07BD9D7398BE18A701D177CF14307E37 -:10A99000430D2B52C4A727FF041C877EB6652208EF -:10A9A0009567AE4FD139FD94FF12E73C4AE7F45367 -:10A9B000FE4B9CEFE53E83DB57FBAAB95DD3052236 -:10A9C000CFEFE983CB501F20DE5ACA449FE49FECAF -:10A9D0007051E4669BF8CB1F557592EF40593225B4 -:10A9E000A5E983D150FC5DB2CB83C541E6BFEC73D2 -:10A9F0005DDE25BB762F7E13C1DD837009EF2F6EE0 -:10AA0000FFEF8716D03E6F29CC57451BBBB7B1DE91 -:10AA100041BD90C7FE86D087C9E220E71D46B757E3 -:10AA20004951EC6FDE211CDD73CA3DEE3386EB8E9F -:10AA3000A0BEA6FE20CA39DD67B0E1833B689F8FC8 -:10AA4000FF32872A7C48EF5FB1DCBF8101C8DC8B15 -:10AA500028F79E9CBDFE8B43DF233933C0EE39249B -:10AA6000EECF7A70343491A4FB0FFE52815C78BB38 -:10AA700050BA82757E7EC8983A75F8542447DDD066 -:10AA80001275C3FEF11F71DF59075085FD477D56D2 -:10AA900080F8E0D11DF259EB868FEE387BDD706CCB -:10AAA000BF0C7E7DE61C97C224E7592984A73AE0B3 -:10AAB000000D617B4357EC962EF623455DD168A0CF -:10AAC0009C03F5F539E43F1FB5ADAD3C1E2962BBD3 -:10AAD0001F55C75364D7A3542F37E8FD82C3754F62 -:10AAE000CACFD2FB85ECFBF7FB269BF87E3885EAC4 -:10AAF00095D9F54929F86351DF5F20EA905E7D72B0 -:10AB0000993679F07EC2D34D01C643FF73D7BC435B -:10AB1000F52FAF8E1F75EBC0FA36D077887BDCDB64 -:10AB20004571D00BA21E0AD7E03D96D3269395ED32 -:10AB30004BB9BEB983EE71AEF39F6FDD709DABDF95 -:10AB400090B9C7489E7FEDE2D39BF74D92C75AF26A -:10AB50001345DE1A0A34D6F34D4F0541217F39A43F -:10AB60001D2439D90293AB499EFAC3C26F4BECF353 -:10AB7000B1DF36DA65F03EC59AC5EF178ABF966732 -:10AB8000EE403089C37A01E591AEE9B446BBF81CCA -:10AB9000C9AE0E3AC790C2FAEEFDAAD5FC8EA94DF9 -:10ABA0002A64795475AB3C5D5F1EEACAFD1E695587 -:10ABB000F95407EF1F9281E2AD449EF9B241F8FECD -:10ABC00089CA70DB40BC5782ADBA3484F7EC0F1EE3 -:10ABD00067FAACAAF22F27FD74C8B5AF8950EEB85A -:10ABE000EE59171FFFD01EFB21D1E17A986A26FD8E -:10ABF00086A26D3AFCAE45C46B87485F8A78F75EE3 -:10AC0000B96E26AFF5922F7688EE6B7D5FF813FE56 -:10AC1000A8F0EB3152E37CD007EDD67304771DF139 -:10AC2000790D2B2A7872790E3977CF714797F51FF6 -:10AC300004EF98BBDF32DDE2BAEB3290CDFE485A2A -:10AC40005DDD38BFBABAA4FF58D4D3AF157C0C2F42 -:10AC500038820F9B40277942FE3B46E7F3DE972C74 -:10AC60007B7E5B05D75D2EB0BE9DDF61BD4DF04E96 -:10AC7000D9F6BBD4BEBFBD0718DE79BED758551E66 -:10AC80008FDA48A7C13CE1373FDD686EB0D3F23FB1 -:10AC900073D60B7B3267BD88C717233B4D88776F10 -:10ACA0006CC72F87FA00D12B1BFE401F8C531D68E9 -:10ACB000B6FDB55D7705284FDC5FD614A0F768892F -:10ACC000605321F507CBAC28ED3FD0D7FADC4755D0 -:10ACD000C44782EF9DF9221F9144FDECA4E5494F42 -:10ACE00075297CAEE63248513EDD1F147E911FE38C -:10ACF000456329F9CDF56CCFF1FB38A50EFCEB0DC2 -:10AD0000116F5B265841728340227CA18E3CBD9E10 -:10AD10004C5E73591CE85CB3C1515A703DC5A365C4 -:10AD20003AFB2157AED7196ED89267E278387F7C0C -:10AD3000ED3B07BE8ACE812F6F9E2777D978AA5C1C -:10AD4000AFF0F95E0CDFC3F7824F9A59CEFCA8F042 -:10AD5000A89E5FBD5EE8192568412CC4E1BF44F898 -:10AD600049D0039B2533F8455F91F1ABE8715EE76D -:10AD70002F3321B694F0A14B848FECFB2F7BFEBBCD -:10AD80002D84B757B608BDBA4A75F5471CEF82FC4B -:10AD9000B9D3D56FE0DAA5B63C6177D6C1CF8222B0 -:10ADA000AF2DF87419BAE381A233F5ABD73EEDE6C7 -:10ADB00095B3BFFF6E7D9EF0878C71D6EFFDAD021F -:10ADC0007E2824FCD083432BD87F58535A35275DE7 -:10ADD0003F5EEC3A61765DF05C75C019BEB10274FD -:10ADE000CE3FEA7739EDC6ECFC713FF18F8FE42658 -:10ADF000C0ED19E3E576D424B99A6F398074DB1974 -:10AE00008E47897F060E6F7F87EA24EAEB8A49FE28 -:10AE1000A6AADA40F3D614C7593ED696594075A56E -:10AE2000FBFBAC1FA6C31D6E8F6D5B4FEF84F471EF -:10AE30008BE00421E5903DBA7EAE15B773D0E16E8C -:10AE4000577F7CD06E7F693DF2E12AD29D2B007E38 -:10AE5000695B7752FF7CF5D599F2D41A20BD7FE16A -:10AE6000F2D411A0FB0D96D9FC4E6BF0670A79580D -:10AE7000A7E70DBAF23438FF1E88A5C9D5EEF559FB -:10AE80007A27E2EA9D88C57231E2EA1955B7593E40 -:10AE90007C244F4BD2F44CC4D33316CBA31AF1E429 -:10AEA000C9953F92A720BD0F9E6A263F6500C43B0F -:10AEB000C66CF9FA7E7BEC61A2C355C5FFD7596118 -:10AEC000CCBCFF340C214F83652EBFCF7F96F9FF9A -:10AED00024F23F3D16EE0F5666F0BBD7AE9C5620CF -:10AEE00085A4B86E5AE2F6B3D3F9DCAE9ACEE3D6B7 -:10AEF0009A9ECB6DE37498DBA6E94BB96D9E2EE567 -:10AF0000B6651AF9FE6AE4FFE90A6ED74C2FE676B9 -:10AF1000EDF4226E5BA7AFE6796DD3CBB9BD7EFAB7 -:10AF20005A6E6F986E10FB504DA82827FF5339EBCF -:10AF300022F0BFE9507D74E0F0EDEF107E7CBAC6E0 -:10AF4000799444B88EEB3D3E35CEFC7FB04CE8F7AB -:10AF5000B541419F6CFEFFA03DF632F16D36FF8397 -:10AF60004FBCDB52E9DD560DFB396F327F9FE1EFBD -:10AF7000BEF417CA83A2FF718CE877A1F6FFB45F15 -:10AF80005992E9570E1667FA9503F33DBFD23F4633 -:10AF900075B0AD92C1EFC4F23B621FF2FE606FA1CB -:10AFA000F1585740277F2A115E130D627FF34E053B -:10AFB00028DF87FEC56F781EEA07B21BE72BAFBFFD -:10AFC000B4851C78F397C17139FE29FC93F7E99F8A -:10AFD0000D67CAFD6CEB3CB9BF1CAAF372D9D9222C -:10AFE0005FB3907B5DC87DA2CC1EA27C4B224BEE52 -:10AFF0003D3B8A78C890FBFC6E57EE5D392E8A88FF -:10B00000771F4524F7C857E16EC3ADFF64DA51D509 -:10B010009DEF6B15F5ADE688D0AB6AABD017AA9E55 -:10B020006947916F8ABB73F8138E2AFCE3B6AA7F37 -:10B030003B6DCFC8AE1645C252216EADFF69D2A19D -:10B040003CD6617501CB77B61C25F415CCE787D5C6 -:10B0500066C825FFE72D4761CF8E586C47B2E77968 -:10B06000F23470B88DF1E2D995C3786F2BCD9EACD8 -:10B07000D5051ED09EACE8CE614F56955B313BC7DF -:10B08000399BBA855FFADA75B6F017D14F243F25A0 -:10B09000E1CBED0734750BFFA7A8D5FD7D8501F148 -:10B0A000B9A8075B5B53CD54C340796EA2FDAFB323 -:10B0B00026FB4906FB8323113A3FCA6733D1E1429D -:10B0C000E5B3BA5DF885D03B97FD16AF3D17DF7B42 -:10B0D000FE8EC7FFD9F39EAEB036E4C2CB0FBA45A1 -:10B0E0005C7370E8D90CFED8A32EB8DE3472EA5532 -:10B0F000CBBC287AF5FCFC8AC368E758AFCEEE5784 -:10B100007C25171FCCE6577CAD5BC49BE8576C27AA -:10B110003AAD5A22FC8A1F74C3C5F5171AEE627C39 -:10B120005DA8BF30D27D767FE140B7E72FC4596F6D -:10B13000F85DBDF169FD851CFEC1A3CCBF30A550F3 -:10B14000FD0F516D8A7C88D023A8670ED238C6F1D6 -:10B15000EC2F1C0C0A7EB15C3D734797FD04D16354 -:10B160004FBDF0172E961CA0DFF734C13D5F793834 -:10B17000DF79554FAC1C9A243F0742497A37DD4F9F -:10B18000EF95287E7C2F24DE11E05128EFFF4FCA77 -:10B190009526D9B9D1FC6F3C46F37B1D15E8DDE05F -:10B1A000FE3E917FDEEDE6FFF6FBE2FF328970EEB8 -:10B1B000DFE1D70FE2F89FE7143832F2D49FF3CAE9 -:10B1C000C7E85DD031570FF96153612EBE9A399FA0 -:10B1D000789F4B4F574EF1EF3ACA74CE93BBF88924 -:10B1E000683638087FE77C99EB233BDBBF7880E447 -:10B1F000C76917792E2EB4E278645E54E43BD08D93 -:10B20000A94FCB8B28A09EA07CFC10BD514FABBF9B -:10B2100016DB1847A7C51921D3CEE81B100307F783 -:10B22000D91B91393F3FB852C44583C17840CFA163 -:10B230005F76F565BE53CA6E95454F24E92DF183BF -:10B2400051D5A4F4E870754D1BE53113BA78B4A458 -:10B2500085653B571D3BDC23B9F97893EDB6FAB908 -:10B260008EC25C76C56B87FA449ED6EB07168E5B62 -:10B27000C49F5A8565F3EF75C211C949CB2FFFDE14 -:10B28000D5133B2533B50A91B63324EC44C0485A54 -:10B29000329E77A0F836AE47060C074ED0F78549A8 -:10B2A000F810DB488916CB5977EF11F1CC4E5F8C43 -:10B2B000F7DB59AA729D726745EEBCD75F5DBDACE6 -:10B2C000859B6CCEFF8755AE2767CF9B72F949D31C -:10B2D000ACA8CEF1F76D06DD2B311F389739D57349 -:10B2E000E7533B82C49F36E747F6BB79126DDE36E3 -:10B2F000C6FBEE7255A73CDC6A65DD0EDAE7415409 -:10B30000BBE49F64F3817F7E4D1ED73FD7C9FC66A7 -:10B31000339B2FE8EDDB04F9696A8AFD251FBCC366 -:10B32000798BDD3547B86FC084DB17FCE2D59B22F3 -:10B330002E3F9E61275C7A2549AE72F0CFFDE51362 -:10B340006CBF1F6898D840759B602460B6E23DF6DC -:10B350002DB739BFBDBB5666BF35DFFD3DCE83EB94 -:10B360008AC28497DDB547582F679FC777E415F6E3 -:10B370003B826A8AF317C1B28F389E7DC83DC7DA17 -:10B380007A214F05A6D0C3055D71D071DFE2B79475 -:10B390003103FBD2BC971D1FD50F6E126F8B352D5D -:10B3A000C57E467EFD1A89CEF766A90212C1505E9F -:10B3B000E0F7BA600BF9F6DE6597746919F17D184C -:10B3C000D2FA15E27704E9EFA840D978D6F766BD3E -:10B3D000EFDD7EEC681ABC9E1EF75DAF5B673BD766 -:10B3E000FA3FF76D3B761495FF83356797ABBDAE9B -:10B3F000DEDBD357CF74F2F8CBE3B7085D71C5EC51 -:10B40000EBF787C773FA25A33D82AFCFA58F0AFC60 -:10B41000E36CE7F75E379E9187FCBAAB1FBEDE2375 -:10B42000E4482F9FE2BCE55EF79DD3DE3CD8F06C8C -:10B430008E7B3DD6A309793ACDCF9E1FF0CE85F9FC -:10B4400001F3BB44FC105991477E00E2F3657AE7B3 -:10B45000F6A78866409A3C0F8432FD50CF0FF86DF6 -:10B460008FF0035E2CFE98ED786130C5763C6866FF -:10B47000E609B2EDB8E68B715CA9956A9E9EE17A09 -:10B4800057F0ED6F3CE5903E48EDE2FA513EF26F29 -:10B490009E488D3BB9E8044B32DFDD7CB107F83CB8 -:10B4A00011233ED148F6A54BE57AC87EF9BD431F6E -:10B4B00012BA9271B05DB8C3CCB7BB27F8FD8ECB82 -:10B4C000F7E7A227FD7D52E7FE6E85DE715CFB6625 -:10B4D0007DAEB8C36BE97D55E67BF84F2717CF7B70 -:10B4E00072910779422ED6C903E40FAC93F9DD0AB5 -:10B4F0003DEF55EBDC9423D5FDE964746F7A1F248E -:10B50000B9F5A40533F2029F17EF5E4E6E13EF6894 -:10B51000F877860BE877A193FCFBC1CBE895AB32BB -:10B52000A3DF4E42994CF562E788249DF6932EA541 -:10B53000278FA64CEB1682CD6DF6B92F87387FAFDB -:10B540008624B757C238B74B6082DB6530C5AD057E -:10B55000426F994745DD6305980A7DAF019BDB3A51 -:10B5600088735B0F496EBF79ED97FE70332EF9AF8C -:10B570001EB72E7F1A2F02AF39E43B458FFEBDFB6D -:10B580007B787EB0C760B93B17BD07C242DF369BF0 -:10B5900013ECDF878236EB615F44F0B707C7374BA8 -:10B5A000BEF8EFF5A3B27F67F2FF2B2134C6D03F80 -:10B5B0000000000000000000000000180000000073 -:10B5C000000000000000004000000000000000003B -:10B5D0000000002800000000000000000000001033 -:10B5E000000000000000000000000020000000003B -:10B5F000000000000000001000000000000000003B -:10B600000000000800000000000000000000000032 -:10B6100000000000000000000000003900000000F1 -:10B6200000000000000000380000000000000000E2 -:10B630000000000000000000000000000000000802 -:10B6400000000000000000000000000000000000FA -:10B65000000000000000000C0000000000000000DE -:10B660000000000E000000000000000000000004C8 -:10B6700000000000000000000000001800000000B2 -:10B68000000000000000001C00000000000000009E -:10B690000000001C0000000000000000000000137B -:10B6A00000000000000000000000003A0000000060 -:10B6B0000000000000000001000000000000000089 -:10B6C0000000000200000000000000000000000177 -:10B6D000000000000000000000000010000000005A -:10B6E000000000000000005000000000000000000A -:10B6F0000000000000000000000000000000000347 -:10B700000000000000000000000000AB000000008E -:10B710000000000000000008000000000000000021 -:10B720000000C00000100000000000080000C00879 -:10B7300000100000000000020000C0000010000027 -:10B740000000001000009FB0000000000000000892 -:10B750000000C08000100000000000040000C0884D -:10B7600000100000000000020000C0800010000077 -:10B770000000001000009120000000000000000800 -:10B780000000934000010004000000010000934805 -:10B7900000000000000000020000935000000000C4 -:10B7A00000000008000093540000000000000002A8 -:10B7B00000009418000000000000000800009358EA -:10B7C000000800000000000800009AB000400000DF -:10B7D00000000040000093980008000000000008EE -:10B7E000000093D80008000000000008000094202A -:10B7F00000C8000000000098000095B0009800000C -:10B8000000000028000095F00098000000000028CB -:10B810000000C480054000300000054000009D206D -:10B82000000800000000000100009D210008000049 -:10B8300000000001000020080010000000000010BF -:10B8400000002000000000000000000800009CD85C -:10B85000000800000000000200009D180000000029 -:10B8600000000001000000010000000000000000D6 -:10B8700000000009000000000000000000000002BD -:10B8800000000000000000000000CF2000000000C9 -:10B89000000000200000CF46000000000000000172 -:10B8A0000000600000200000000000200000730085 -:10B8B000000800000000000800009FA00000000039 -:10B8C0000000000100009FA800000000000000012F -:10B8D00000009F60000000000000001000009F6357 -:10B8E000000000000000000100009F610000000057 -:10B8F0000000000100009F66000000000000000141 -:10B9000000009F67000000000000000000009F682A -:10B91000000000000000000400009F6C0000000018 -:10B9200000000004000000520000000000000000C1 -:10B930000000000300000000000000000000000301 -:10B9400000000000000000000000000500000000F2 -:10B9500000000000000000020000000000000000E5 -:10B9600000060000000000000000002000009F70A2 -:10B97000000000000000000100009F900000000097 -:10B98000000000080000005300000000000000005C -:10B9900000009F98000000000000000200009F9C33 -:10B9A000000000000000000100009F9D000000005A -:10B9B000000000010000000900000000000000007D -:10B9C0000000000100000000000000000000004432 -:10B9D0000000000000000000000000010000000066 -:10B9E0000000000000000050000000000000000007 -:10B9F000000000890000000000000000000012C8E4 -:10BA00000080000000000080000000010000000035 -:10BA1000000000000000A000071000000000071058 -:10BA200000001AC800000000000000080000AEC0BE -:10BA300000080000000000080000AE400008000000 -:10BA4000000000080000AE800008000000000008B0 -:10BA5000000020080010000000000010000020007E -:10BA600000000000000000080000A01007100040C7 -:10BA70000000004000001BF800080000000000016A -:10BA800000001BF9000800000000000100001AD0AF -:10BA9000000000000000000100001AD800000000B3 -:10BAA0000000000200001ADA00000000000000029E -:10BAB0008000000000000000000000000000AF0057 -:10BAC000000000000000002000001B78002800009B -:10BAD000000000040000E000002000000000002042 -:10BAE0000000F300000800000000000800001AF049 -:10BAF000000000000000010800001B3700000000EB -:10BB00000000000100001B0F000000000000000109 -:10BB100000001B70000000000000000400001B7407 -:10BB200000000000000000040000005000000000C1 -:10BB30000000000000000003000000000000000002 -:10BB400000000005000000000000000000000006EA -:10BB500000000000000000000000000700000000DE -:10BB60000000000000001BC80000000000000001F1 -:10BB700000001BE800000000000000080000005169 -:10BB8000000000000000000000001BD000000000CA -:10BB90000000000400001BD40000000000000004AE -:10BBA00000001BD8000000000000000400001BDCA7 -:10BBB00000000000000000080000B00000180000B5 -:10BBC000000000180000C00000400000000000401D -:10BBD0000000C00000400002000000010000C001A1 -:10BBE00000400002000000000000E2000020000011 -:10BBF000000000200000E204000200080020000213 -:10BC00008000000000000000000000000000E200D2 -:10BC100000080020000000040000F40000280000DC -:10BC2000000000280000F540001000000000001097 -:10BC30000000F5C000200000000000200000F5C05A -:10BC400000020020000000020000F30000200000BD -:10BC5000000000200000200800100000000000107C -:10BC60000000200000000000000000080000110893 -:10BC70000008000000000008000011680008000033 -:10BC800000000008000011A80008000000000008E3 -:10BC900000001240000800000000000100001241F6 -:10BCA0000008000000000001000040000020000427 -:10BCB00000000010000059000030001800000010C3 -:10BCC0000000590800300018000000020000570072 -:10BCD00000080000000000010000570100080000FB -:10BCE00000000001000011E8000000000000000159 -:10BCF000000011F00000000000000001000011F839 -:10BD000000000000000000100000124400080000C5 -:10BD1000000000040000400000200000000000209F -:10BD20000000530000100000000000100000153853 -:10BD300000000000000000010000000300000000FF -:10BD400000000000000000000000000000000000F3 -:10BD500000000001000000000000000000000004DE -:10BD600000000000000000000000150800000000B6 -:10BD7000000000010000152800000000000000087D -:10BD800000000050000000000000000000008308D8 -:10BD900000800000000000800000000100000000A2 -:10BDA000000000000000200800100000000000104B -:10BDB00000002000000000000000000800008410C7 -:10BDC0000008000000000008000084700008000067 -:10BDD0000000000800060000046000280000046065 -:10BDE00000008520000800000000000100008521FF -:10BDF00000080000000000018000000000000000BA -:10BE000000000000000084080000000000000001A5 -:10BE1000000084F40008000000000002000084F626 -:10BE2000000800000000000200008504001000006F -:10BE300000000004000087600000000000000020F7 -:10BE400000006000002000000000002000007300DF -:10BE500000080000000000080000000300000000CF -:10BE600000000000000000050000000000000000CD -:10BE700000000006000000000000000000000007B5 -:10BE80000000000000000000000088080000000022 -:10BE900000000001000088280000000000000008E9 -:10BEA00000000050000000000000000000008810AA -:10BEB00000000000000000040000881400000000E2 -:10BEC00000000004000088180000000000000004CA -:10BED0000000881C00000000000000080000300086 -:10BEE0000040000000000008000030080040000092 -:10BEF000000000280000339001C00010000000087E -:10BF00000000320000200000000000200000372068 -:10BF1000000000000000000800001020062000388B -:10BF2000000000080000A000000000000000200049 -:10BF300000003EA9000000000000000100003EC813 -:10BF4000000000000000000280000000000000006F -:10BF50000000000000006000002000000000000859 -:10BF60000000400000080000000000010000400147 -:10BF7000000800000000000100004040000800042C -:10BF800000000002000040600008000400000004FF -:10BF90000000400000080000000000040000400411 -:10BFA0000008000000000004000040400000000005 -:10BFB00000000008000040480000000000000008E9 -:10BFC0000000800000000000000000100000504051 -:10BFD000000100040000000100005000000000000B -:10BFE00000000020000050080010000000000004C5 -:10BFF0000000500C0010000000000001000052C7BB -:10C000000000000000000001000052C60000000017 -:10C0100000000001000030000030001800000004A3 -:10C020000000300400300018000000040000300858 -:10C0300000300018000000020000300A0030001834 -:10C04000000000020000300C003000180000000169 -:10C050000000300D00300018000000010000300E1C -:10C0600000300018000000010000301000300018FF -:10C07000000000040000301400300018000000042C -:10C08000000050000100008000080004000050047F -:10C0900001000080000800040000000A0000000009 -:10C0A0000000000000005068010000800000000156 -:10C0B0000000506901000080000000010000506C89 -:10C0C00001000080000000020000506E01000080AE -:10C0D0000000000200005070010000800000000419 -:10C0E0000000507401000080000000040000506651 -:10C0F0000100008000000002000050640100008088 -:10C1000000000001000050600100008000000002FB -:10C11000000050620100008000000002000050504A -:10C120000100008000000004000050540100008065 -:10C1300000000004000050580100008000000004CE -:10C140000000505C01000080000000040000507CF2 -:10C1500001000080000000010000507D010000800F -:10C160000000000100004018001000000000000462 -:10C170000000409000100000000000040000409803 -:10C18000001000000000000400004110000000004A -:10C190000000000200004112000000000000000248 -:10C1A00000004114000000000000000200004116E1 -:10C1B00000000000000000020000604000080000D5 -:10C1C00000000002000060420008000000000002C1 -:10C1D00000006044000800000000000400006080CF -:10C1E0000008000000000008000060C000400008D7 -:10C1F00000000008000060000008000000000002CD -:10C20000000060020008000000000001000060045F -:10C210000008000000000002000063400008000069 -:10C220000000000800006380000800000000000417 -:10C23000000063840008000000000001000063C0EB -:10C240000008000000000002000063C400080000B5 -:10C25000000000020000640000080000000000046C -:10C2600000007000001000000000000400007004D6 -:10C270000010000000000004000070080010000022 -:10C280000000000400009000000800000000000210 -:10C29000000090020008000000000001000090046F -:10C2A00000080000000000020000904000080000AC -:10C2B000000000020000904400080000000000029E -:10C2C00000009046000800000000000200009648B0 -:10C2D0000008000000000008000090800008000036 -:10C2E000000000020000908400080000000000022E -:10C2F0000000968800080000000000080000804050 -:10C30000000800000000000100008041000800005B -:10C310000000000100008042000800000000000151 -:10C3200000008043000800000000000100008000C1 -:10C330000008000000000002000080020008000069 -:10C34000000000010000800400080000000000025E -:10C35000000080C00008000000000002000080C251 -:10C360000008000000000002000080C40008000077 -:10C3700000000002000080800008000000000001B2 -:10C3800000008081000800000000000100008082A1 -:10C390000008000000000001000080830008000089 -:10C3A000000000010000808400080000000000017F -:10C3B0000000808500080000000000010000808669 -:10C3C00000080000000000010000600000080000FC -:10C3D00000000002000060020008000000000001F0 -:10C3E000000060040008000000000002000060423D -:10C3F00000C00018000000020000604000C00018EB -:10C40000000000020000604C00C00018000000089E -:10C410000000604400C000180000000800006057E1 -:10C4200000C00018000000010000605400C00018A7 -:10C43000000000020000605600C00018000000016B -:10C440000000664000080000000000080000668050 -:10C450000008000000000008000066C0000800009E -:10C46000000000080000DA4200180000000000028E -:10C470000000DE4000000000000000000000E000BE -:10C4800000000000000000040000D0C00000000018 -:10C49000000000040000D0C4000000000000000400 -:10C4A0000000D0C800000000000000040000D0CC54 -:10C4B00000000000000000040000D0D000000000D8 -:10C4C000000000040000D0D40000000000000004C0 -:10C4D0000000D0D800000000000000040000D0C020 -:10C4E00000000000000000200000DB000000000051 -:10C4F000000000040000DB000000000000000068F5 -:10C500000000B94800000000000000000000D0005A -:10C5100000000000000000040000B0C000000000A7 -:10C52000000000040000B0C400000000000000048F -:10C530000000B0C800000000000000040000B0C00F -:10C5400000000000000000100000D6B00000000055 -:10C55000000000040000D6B4000000000000000449 -:10C560000000D6B800000000000000040000D6BCA7 -:10C5700000000000000000040000D6B00000000031 -:10C58000000000100000D348000000000000000878 -:10C590000000D358000000000000008000000010E0 -:10C5A00000000000000000000000D3580000000060 -:10C5B0000000000800000000060205000000000066 -:00000001FF diff --git a/firmware/bnx2x/bnx2x-e2-6.2.9.0.fw.ihex b/firmware/bnx2x/bnx2x-e2-6.2.9.0.fw.ihex new file mode 100644 index 0000000..8405e71 --- /dev/null +++ b/firmware/bnx2x/bnx2x-e2-6.2.9.0.fw.ihex @@ -0,0 +1,15473 @@ +:1000000000005310000000680000070C000053803F +:100010000000318000005A90000000B000008C18F1 +:100020000000C13400008CD0000000D800014E0850 +:100030000000F26400014EE800000074000241502C +:1000400000005250000241C8000000B40002942099 +:10005000000121EC000294D800000FFC0003B6C898 +:10006000000000040003C6C8020400480000000F9E +:1000700002040054000000450204005C0000000679 +:100080000204007000000004020400780000000078 +:100090000204007C121700000204008022170000F6 +:1000A00002040084321700000604008800000005E6 +:1000B0000204009C12150000020400A0221500009A +:1000C000020400A432150000060400A80000000489 +:1000D000020400B802100000020400BC001000007E +:1000E000020400C010100000020400C42010000030 +:1000F000020400C830100000020400CC40100000D0 +:10010000060400D000000003020400DC0010000020 +:10011000020400E012140000020400E422140000B3 +:10012000020400E832140000020400EC4214000053 +:10013000060400F000000003010401240000000098 +:1001400001040128000000000104012C000000004F +:100150000104013000000000020401D00000890603 +:1001600002040258000000360204025C000000365F +:10017000020402600810000002040264081000007B +:1001800002040004000000FF02040008000000FF59 +:100190000204000C000000FF02040010000000FF39 +:1001A000020400140000007F02040018000000FF99 +:1001B0000204001C000000FF02040020000000FFF9 +:1001C000020400240000003E020400280000000099 +:1001D0000204002C0000003F020400300000003F39 +:1001E000020400340000003F020400380000003F19 +:1001F0000204003C0000003F020400400000003FF9 +:10020000020400440000003F020404CC000000018E +:1002100002042008000002110204200C0000020069 +:10022000020420100000020402042014000002193D +:100230000204201C0000FFFF020420200000FFFF3A +:10024000020420240000FFFF020420280000FFFF1A +:1002500002042038000000200604203C0000000FAB +:1002600002042078000000210604207C0000000F1A +:10027000020420B800000001060420BC0000000FAA +:10028000020420F800000001060420FC0000003FEA +:10029000020421F800000001060421FC0000000F08 +:1002A0000204223807FFFFFF0204223C0000007F07 +:1002B0000204224007FFFFFF020422440000003F27 +:1002C00001042248000000000104224C000000004C +:1002D000010422500000000001042254000000002C +:1002E00001042258000000000104225C000000000C +:1002F00001042260000000000104226400000000EC +:1003000001042268000000000104226C00000000CB +:1003100001042270000000000104227400000000AB +:1003200001042278000000000104227C000000008B +:10033000020422C00000FFFF020422C40000FFFFED +:10034000020422C80000FFFF020422CC0000FFFFCD +:100350000C042000000003E80A0420000000000153 +:100360000B042000000000030605400000000D0003 +:100370000205004400000020020500480000003291 +:1003800002050090021500200205009402150020CD +:1003900002050098000000300205009C08100000D3 +:1003A000020500A000000036020500A40000003095 +:1003B000020500A800000031020500B000000004A2 +:1003C000020500B400000005020500C000000000A6 +:1003D000020500C400000004020500D40000000172 +:1003E00002050114000000010205011C00000001CB +:1003F00002050120000000020205020400000001C5 +:100400000205020C0000004002050210000000403E +:100410000205021C00000020020502200000001C52 +:100420000205022400000020060502400000000A28 +:1004300004050280002000000205005000000007B3 +:1004400002050054000000070205005800000000EB +:100450000205005C000000080205006000000001C9 +:100460000605006400000003020500D80000000635 +:100470000205000400000001020500080000000160 +:100480000205000C00000001020500100000000140 +:100490000205001400000001020500180000000120 +:1004A0000205001C00000001020500200000000100 +:1004B00002050024000000010205002800000001E0 +:1004C0000205002C000000010205003000000001C0 +:1004D00002050034000000010205003800000001A0 +:1004E0000205003C00000001020500400000000180 +:1004F000020500E00000000D020500E80000000019 +:10050000020500F000000000020500F800000000F5 +:10051000020500E40000002D020500EC00000020B0 +:10052000020500F400000020020500FC000000208D +:10053000020500E00000001D020500E800000010B8 +:10054000020500F000000010020500F80000001095 +:10055000020500E40000003D020500EC0000003050 +:10056000020500F400000030020500FC000000302D +:10057000020500E00000004D020500E80000004018 +:10058000020500F000000040020500F800000040F5 +:10059000020500E40000006D020500EC00000060B0 +:1005A000020500F400000060020500FC000000608D +:1005B000020500E00000005D020500E800000050B8 +:1005C000020500F000000050020500F80000005095 +:1005D000020500E40000007D020500EC0000007050 +:1005E000020500F400000070020500FC000000702D +:1005F0000406100002000020020600DC00000001DA +:100600000406020000030220020600DC00000000D5 +:100610000718040000AD0000081807D800050223E1 +:10062000071C000029920000071C8000312A0A657F +:10063000071D000034A216B0071D80002E7A23D9B2 +:10064000071E000003502F78081E07F03F02022506 +:10065000021800BC0000003001180000000000007B +:10066000011800040000000001180008000000004C +:100670000118000C0000000001180010000000002C +:100680000118001400000000021800200000000102 +:1006900002180024000000020218002800000003D5 +:1006A0000218002C000000000218003000000004B6 +:1006B0000218003400000001021800380000000099 +:1006C0000218003C00000001021800400000000475 +:1006D0000218004400000000021800480000000159 +:1006E0000218004C00000003021800500000000037 +:1006F0000218005400000001021800580000000415 +:100700000218005C000000000218006000000001F8 +:1007100002180064000000030218006800000000D6 +:100720000218006C000000010218007000000004B4 +:100730000218007400000000021800780000000495 +:100740000218007C00000003061800800000000270 +:10075000021800A400007FFF021800A8000003FF99 +:1007600002180224000000000218023400000000F9 +:100770000218024C00000000021802E4000000FF12 +:100780000618100000000400021B8BC000000001CE +:10079000021B800000000034021B80400000001893 +:1007A000021B80800000000C021B80C000000020A3 +:1007B0000C1B8300000864700A1B830000000157B3 +:1007C0000B1B83000000055F0A1B83400000000034 +:1007D0000C1B8340000002260B1B8340000000011D +:1007E000021B838000086470021B83C00000022685 +:1007F000021B1480000000010A1B1480000000008E +:10080000021B944000000001061B944800000002F7 +:10081000061A1000000002B3041A1ACC00010227C5 +:10082000061A1AD000000008061A2008000000C8A6 +:10083000061A200000000002041A1BF8009002288B +:10084000061A371800000004061A371000000002CC +:10085000061A500000000002061A500800000004AA +:10086000061A501800000004061A50280000000460 +:10087000061A503800000004061A50480000000410 +:10088000061A505800000004061A506800000004C0 +:10089000061A507800000002041A52C0000202B882 +:1008A000061A405000000006041A4068000202BA0E +:1008B000041A4040000402BC041A8000000102C077 +:1008C000061A800400000003041A8010000102C10F +:1008D000061A801400000003041A8020000102C2DE +:1008E000061A802400000003041A8030000102C3AD +:1008F000061A803400000003041A8040000102C47C +:10090000061A804400000003041A8050000102C54A +:10091000061A805400000003041A8060000102C619 +:10092000061A806400000003041A8070000102C7E8 +:10093000061A807400000003041A8080000102C8B7 +:10094000061A808400000003041A8090000102C986 +:10095000061A809400000003041A80A0000102CA55 +:10096000061A80A400000003041A80B0000102CB24 +:10097000061A80B400000003041A80C0000102CCF3 +:10098000061A80C400000003041A80D0000102CDC2 +:10099000061A80D400000003041A80E0000102CE91 +:1009A000061A80E400000003041A80F0000102CF60 +:1009B000061A80F400000003041A8100000102D02E +:1009C000061A810400000003041A8110000102D1FC +:1009D000061A811400000003041A8120000102D2CB +:1009E000061A812400000003041A8130000102D39A +:1009F000061A813400000003041A8140000102D469 +:100A0000061A814400000003041A8150000102D537 +:100A1000061A815400000003041A8160000102D606 +:100A2000061A816400000003041A8170000102D7D5 +:100A3000061A817400000003041A8180000102D8A4 +:100A4000061A818400000003041A8190000102D973 +:100A5000061A819400000003041A81A0000102DA42 +:100A6000061A81A400000003041A81B0000102DB11 +:100A7000061A81B400000003041A81C0000102DCE0 +:100A8000061A81C400000003041A81D0000102DDAF +:100A9000061A81D400000003041A81E0000102DE7E +:100AA000061A81E400000003041A81F0000102DF4D +:100AB000061A81F400000003041A8200000102E01B +:100AC000061A820400000003041A8210000102E1E9 +:100AD000061A821400000003041A8220000102E2B8 +:100AE000061A822400000003041A8230000102E387 +:100AF000061A823400000003041A8240000102E456 +:100B0000061A824400000003041A8250000102E524 +:100B1000061A825400000003041A8260000102E6F3 +:100B2000061A826400000003041A8270000102E7C2 +:100B3000061A827400000003041A8280000102E891 +:100B4000061A828400000003041A8290000102E960 +:100B5000061A829400000003041A82A0000102EA2F +:100B6000061A82A400000003041A82B0000102EBFE +:100B7000061A82B400000003041A82C0000102ECCD +:100B8000061A82C400000003041A82D0000102ED9C +:100B9000061A82D400000003041A82E0000102EE6B +:100BA000061A82E400000003041A82F0000102EF3A +:100BB000061A82F400000003041A8300000102F008 +:100BC000061A830400000003041A8310000102F1D6 +:100BD000061A831400000003041A8320000102F2A5 +:100BE000061A832400000003041A8330000102F374 +:100BF000061A833400000003041A8340000102F443 +:100C0000061A834400000003041A8350000102F511 +:100C1000061A835400000003041A8360000102F6E0 +:100C2000061A836400000003041A8370000102F7AF +:100C3000061A837400000003041A8380000102F87E +:100C4000061A838400000003041A8390000102F94D +:100C5000061A839400000003041A83A0000102FA1C +:100C6000061A83A400000003041A83B0000102FBEB +:100C7000061A83B400000003041A83C0000102FCBA +:100C8000061A83C400000003041A83D0000102FD89 +:100C9000061A83D400000003041A83E0000102FE58 +:100CA000061A83E400000003041A83F0000102FF27 +:100CB000061A83F400000003041A840000010300F4 +:100CC000061A840400000003041A841000010301C2 +:100CD000061A841400000003041A84200001030291 +:100CE000061A842400000003041A84300001030360 +:100CF000061A843400000003041A8440000103042F +:100D0000061A844400000003041A845000010305FD +:100D1000061A845400000003041A846000010306CC +:100D2000061A846400000003041A8470000103079B +:100D3000061A847400000003041A8480000103086A +:100D4000061A848400000003041A84900001030939 +:100D5000061A849400000003041A84A00001030A08 +:100D6000061A84A400000003041A84B00001030BD7 +:100D7000061A84B400000003041A84C00001030CA6 +:100D8000061A84C400000003041A84D00001030D75 +:100D9000061A84D400000003041A84E00001030E44 +:100DA000061A84E400000003041A84F00001030F13 +:100DB000061A84F400000003041A850000010310E1 +:100DC000061A850400000003041A851000010311AF +:100DD000061A851400000003041A8520000103127E +:100DE000061A852400000003041A8530000103134D +:100DF000061A853400000003041A8540000103141C +:100E0000061A854400000003041A855000010315EA +:100E1000061A855400000003041A856000010316B9 +:100E2000061A856400000003041A85700001031788 +:100E3000061A857400000003041A85800001031857 +:100E4000061A858400000003041A85900001031926 +:100E5000061A859400000003041A85A00001031AF5 +:100E6000061A85A400000003041A85B00001031BC4 +:100E7000061A85B400000003041A85C00001031C93 +:100E8000061A85C400000003041A85D00001031D62 +:100E9000061A85D400000003041A85E00001031E31 +:100EA000061A85E400000003041A85F00001031F00 +:100EB000061A85F400000003041A860000010320CE +:100EC000061A860400000003041A8610000103219C +:100ED000061A861400000003041A8620000103226B +:100EE000061A862400000003041A8630000103233A +:100EF000061A863400000003041A86400001032409 +:100F0000061A864400000003041A865000010325D7 +:100F1000061A865400000003041A866000010326A6 +:100F2000061A866400000003041A86700001032775 +:100F3000061A867400000003041A86800001032844 +:100F4000061A868400000003041A86900001032913 +:100F5000061A869400000003041A86A00001032AE2 +:100F6000061A86A400000003041A86B00001032BB1 +:100F7000061A86B400000003041A86C00001032C80 +:100F8000061A86C400000003041A86D00001032D4F +:100F9000061A86D400000003041A86E00001032E1E +:100FA000061A86E400000003041A86F00001032FED +:100FB000061A86F400000003041A870000010330BB +:100FC000061A870400000003041A87100001033189 +:100FD000061A871400000003041A87200001033258 +:100FE000061A872400000003041A87300001033327 +:100FF000061A873400000003041A874000010334F6 +:10100000061A874400000003041A875000010335C4 +:10101000061A875400000003041A87600001033693 +:10102000061A876400000003041A87700001033762 +:10103000061A877400000003041A87800001033831 +:10104000061A878400000003041A87900001033900 +:10105000061A879400000003041A87A00001033ACF +:10106000061A87A400000003041A87B00001033B9E +:10107000061A87B400000003041A87C00001033C6D +:10108000061A87C400000003041A87D00001033D3C +:10109000061A87D400000003041A87E00001033E0B +:1010A000061A87E400000003041A87F00001033FDA +:1010B000061A87F400000003041A880000010340A8 +:1010C000061A880400000003041A88100001034176 +:1010D000061A881400000003041A88200001034245 +:1010E000061A882400000003041A88300001034314 +:1010F000061A883400000003041A884000010344E3 +:10110000061A884400000003041A885000010345B1 +:10111000061A885400000003041A88600001034680 +:10112000061A886400000003041A8870000103474F +:10113000061A887400000003041A8880000103481E +:10114000061A888400000003041A889000010349ED +:10115000061A889400000003041A88A00001034ABC +:10116000061A88A400000003041A88B00001034B8B +:10117000061A88B400000003041A88C00001034C5A +:10118000061A88C400000003041A88D00001034D29 +:10119000061A88D400000003041A88E00001034EF8 +:1011A000061A88E400000003041A88F00001034FC7 +:1011B000061A88F400000003041A89000001035095 +:1011C000061A890400000003041A89100001035163 +:1011D000061A891400000003041A89200001035232 +:1011E000061A892400000003041A89300001035301 +:1011F000061A893400000003041A894000010354D0 +:10120000061A894400000003041A8950000103559E +:10121000061A895400000003041A8960000103566D +:10122000061A896400000003041A8970000103573C +:10123000061A897400000003041A8980000103580B +:10124000061A898400000003041A899000010359DA +:10125000061A899400000003041A89A00001035AA9 +:10126000061A89A400000003041A89B00001035B78 +:10127000061A89B400000003041A89C00001035C47 +:10128000061A89C400000003041A89D00001035D16 +:10129000061A89D400000003041A89E00001035EE5 +:1012A000061A89E400000003041A89F00001035FB4 +:1012B000061A89F400000003041A8A000001036082 +:1012C000061A8A0400000003041A8A100001036150 +:1012D000061A8A1400000003041A8A20000103621F +:1012E000061A8A2400000003041A8A3000010363EE +:1012F000061A8A3400000003041A8A4000010364BD +:10130000061A8A4400000003041A8A50000103658B +:10131000061A8A5400000003041A8A60000103665A +:10132000061A8A6400000003041A8A700001036729 +:10133000061A8A7400000003041A8A8000010368F8 +:10134000061A8A8400000003041A8A9000010369C7 +:10135000061A8A9400000003041A8AA00001036A96 +:10136000061A8AA400000003041A8AB00001036B65 +:10137000061A8AB400000003041A8AC00001036C34 +:10138000061A8AC400000003041A8AD00001036D03 +:10139000061A8AD400000003041A8AE00001036ED2 +:1013A000061A8AE400000003041A8AF00001036FA1 +:1013B000061A8AF400000003041A8B00000103706F +:1013C000061A8B0400000003041A8B10000103713D +:1013D000061A8B1400000003041A8B20000103720C +:1013E000061A8B2400000003041A8B3000010373DB +:1013F000061A8B3400000003041A8B4000010374AA +:10140000061A8B4400000003041A8B500001037578 +:10141000061A8B5400000003041A8B600001037647 +:10142000061A8B6400000003041A8B700001037716 +:10143000061A8B7400000003041A8B8000010378E5 +:10144000061A8B8400000003041A8B9000010379B4 +:10145000061A8B9400000003041A8BA00001037A83 +:10146000061A8BA400000003041A8BB00001037B52 +:10147000061A8BB400000003041A8BC00001037C21 +:10148000061A8BC400000003041A8BD00001037DF0 +:10149000061A8BD400000003041A8BE00001037EBF +:1014A000061A8BE400000003041A8BF00001037F8E +:1014B000061A8BF400000003041A8C00000103805C +:1014C000061A8C0400000003041A8C10000103812A +:1014D000061A8C1400000003041A8C2000010382F9 +:1014E000061A8C2400000003041A8C3000010383C8 +:1014F000061A8C3400000003041A8C400001038497 +:10150000061A8C4400000003041A8C500001038565 +:10151000061A8C5400000003041A8C600001038634 +:10152000061A8C6400000003041A8C700001038703 +:10153000061A8C7400000003041A8C8000010388D2 +:10154000061A8C8400000003041A8C9000010389A1 +:10155000061A8C9400000003041A8CA00001038A70 +:10156000061A8CA400000003041A8CB00001038B3F +:10157000061A8CB400000003041A8CC00001038C0E +:10158000061A8CC400000003041A8CD00001038DDD +:10159000061A8CD400000003041A8CE00001038EAC +:1015A000061A8CE400000003041A8CF00001038F7B +:1015B000061A8CF400000003041A8D000001039049 +:1015C000061A8D0400000003041A8D100001039117 +:1015D000061A8D1400000003041A8D2000010392E6 +:1015E000061A8D2400000003041A8D3000010393B5 +:1015F000061A8D3400000003041A8D400001039484 +:10160000061A8D4400000003041A8D500001039552 +:10161000061A8D5400000003041A8D600001039621 +:10162000061A8D6400000003041A8D7000010397F0 +:10163000061A8D7400000003041A8D8000010398BF +:10164000061A8D8400000003041A8D90000103998E +:10165000061A8D9400000003041A8DA00001039A5D +:10166000061A8DA400000003041A8DB00001039B2C +:10167000061A8DB400000003041A8DC00001039CFB +:10168000061A8DC400000003041A8DD00001039DCA +:10169000061A8DD400000003041A8DE00001039E99 +:1016A000061A8DE400000003041A8DF00001039F68 +:1016B000061A8DF400000003041A8E00000103A036 +:1016C000061A8E0400000003041A8E10000103A104 +:1016D000061A8E1400000003041A8E20000103A2D3 +:1016E000061A8E2400000003041A8E30000103A3A2 +:1016F000061A8E3400000003041A8E40000103A471 +:10170000061A8E4400000003041A8E50000103A53F +:10171000061A8E5400000003041A8E60000103A60E +:10172000061A8E6400000003041A8E70000103A7DD +:10173000061A8E7400000003041A8E80000103A8AC +:10174000061A8E8400000003041A8E90000103A97B +:10175000061A8E9400000003041A8EA0000103AA4A +:10176000061A8EA400000003041A8EB0000103AB19 +:10177000061A8EB400000003041A8EC0000103ACE8 +:10178000061A8EC400000003041A8ED0000103ADB7 +:10179000061A8ED400000003041A8EE0000103AE86 +:1017A000061A8EE400000003041A8EF0000103AF55 +:1017B000061A8EF400000003041A8F00000103B023 +:1017C000061A8F0400000003041A8F10000103B1F1 +:1017D000061A8F1400000003041A8F20000103B2C0 +:1017E000061A8F2400000003041A8F30000103B38F +:1017F000061A8F3400000003041A8F40000103B45E +:10180000061A8F4400000003041A8F50000103B52C +:10181000061A8F5400000003041A8F60000103B6FB +:10182000061A8F6400000003041A8F70000103B7CA +:10183000061A8F7400000003041A8F80000103B899 +:10184000061A8F8400000003041A8F90000103B968 +:10185000061A8F9400000003041A8FA0000103BA37 +:10186000061A8FA400000003041A8FB0000103BB06 +:10187000061A8FB400000003041A8FC0000103BCD5 +:10188000061A8FC400000003041A8FD0000103BDA4 +:10189000061A8FD400000003041A8FE0000103BE73 +:1018A000061A8FE400000007041A62C0002003BF7C +:1018B000061A1AF000000042061AAF0000000008E5 +:1018C000061AE00000000540061AD0000000007271 +:1018D000061AD24800000010061AD6B000000020F8 +:1018E000061AD47000000090061AD46800000002A6 +:1018F000061AA000000001C4061A30000000001003 +:10190000061A308000000010061A31000000001096 +:10191000061A318000000010061A33000000001281 +:10192000061A339000000070061AD4580000000216 +:10193000061AD34800000002061AD35800000020FF +:10194000061AA710000001C4061A3040000000105B +:10195000061A30C000000010061A314000000010C6 +:10196000061A31C000000010061A334800000012A9 +:10197000061A355000000070061AD46000000002FC +:10198000061AD35000000002061AD3D80000002027 +:10199000021AAE2000000000061A500000000002EB +:1019A000061A508000000012041A4000000203DFF3 +:1019B000041A63C0000203E1061A7000000000046C +:1019C000061A320000000008021AAE2400000000CF +:1019D000061A501000000002061A50C8000000123B +:1019E000041A4008000203E3041A63C8000203E576 +:1019F000061A701000000004061A322000000008C9 +:101A0000021AAE2800000000061A50200000000252 +:101A1000061A511000000012041A4010000203E7D9 +:101A2000041A63D0000203E9061A702000000004C3 +:101A3000061A324000000008021AAE2C0000000016 +:101A4000061A503000000002061A51580000001219 +:101A5000041A4018000203EB041A63D8000203EDD5 +:101A6000061A703000000004061A326000000008F8 +:101A7000021AAE3000000000061A504000000002BA +:101A8000061A51A000000012041A4020000203EFC1 +:101A9000041A63E0000203F1061A7040000000041B +:101AA000061A328000000008021AAE34000000005E +:101AB000061A505000000002061A51E800000012F9 +:101AC000041A4028000203F3041A63E8000203F535 +:101AD000061A705000000004061A32A00000000828 +:101AE000021AAE3800000000061A50600000000222 +:101AF000061A523000000012041A4030000203F7A8 +:101B0000041A63F0000203F9061A70600000000472 +:101B1000061A32C000000008021AAE3C00000000A5 +:101B2000061A507000000002061A527800000012D7 +:101B3000041A4038000203FB041A63F8000203FD94 +:101B4000061A707000000004061A32E00000000857 +:101B50000200A2A4000002090200A270000000001E +:101B60000200A274000000000200A2700000000049 +:101B70000200A274000000000200A2700000000039 +:101B80000200A274000000000200A2700000000029 +:101B90000200A27400000000020100B40000000175 +:101BA000020100B800000001020100CC00000001A9 +:101BB000020100D000000001020100DC0000000171 +:101BC0000201010000000001020101040000000107 +:101BD0000201007C003000000201008400000028A7 +:101BE0000201008C0000000002010130000000042E +:101BF0000201025C00000001020103280000000055 +:101C0000020160580000FFFF020160700000000741 +:101C10000201055400000030020100C40000000170 +:101C2000020100F800000001020100F000000001C4 +:101C3000020100800030000002010088000000283E +:101C400002010090000000000201013400000004C5 +:101C5000020102DC000000010201032C0000000070 +:101C60000201605C0000FFFF0201607400000007D9 +:101C70000201056400000030020100C800000001FC +:101C8000020100FC00000001020100F4000000015C +:101C9000020C100000000028020C200800000211B5 +:101CA000020C200C00000200020C201000000204B4 +:101CB000020C201C0000FFFF020C20200000FFFF90 +:101CC000020C20240000FFFF020C20280000FFFF70 +:101CD000020C203800000000020C203C00000037FD +:101CE000020C204000000021020C204400000020D3 +:101CF000060C20480000001D020C20BC0000000162 +:101D0000060C20C00000003F020C21BC00000001B6 +:101D1000020C21C000000001020C21C400000001DF +:101D2000060C21C80000001C020C223807FFFFFF30 +:101D3000020C223C0000007F020C224007FFFFFF44 +:101D4000020C22440000003F010C22480000000069 +:101D5000010C224C00000000010C22500000000089 +:101D6000010C225400000000010C22580000000069 +:101D7000010C225C00000000010C22600000000049 +:101D8000010C226400000000010C22680000000029 +:101D9000010C226C00000000010C22700000000009 +:101DA000010C227400000000010C227800000000E9 +:101DB000010C227C00000000020C22D80000FFFF72 +:101DC000020C22DC0000FFFF020C22E00000FFFFFB +:101DD000020C22E40000FFFF0C0C2000000003E8CE +:101DE0000A0C2000000000010B0C20000000000382 +:101DF000020C400800001011020C400C0000100002 +:101E0000020C401000001004020C401400001021CD +:101E1000020C401C0000FFFF020C40200000FFFFEE +:101E2000020C40240000FFFF020C40280000FFFFCE +:101E3000020C403800000046020C403C0000000C40 +:101E4000060C404000000002020C40480000001850 +:101E5000020C404C000000F0060C40500000001F37 +:101E6000020C40CC00000001060C40D00000003AFB +:101E7000020C41B800000001060C41BC0000000348 +:101E8000020C41C800000001020C41CC000000011E +:101E9000060C41D00000001A020C423807FFFFFF79 +:101EA000020C423C0000007F020C424007FFFFFF93 +:101EB000020C42440000003F010C424800000000B8 +:101EC000010C424C00000000010C425000000000D8 +:101ED000010C425400000000010C425800000000B8 +:101EE000010C425C00000000010C42600000000098 +:101EF000010C426400000000010C42680000000078 +:101F0000010C426C00000000010C42700000000057 +:101F1000010C427400000000010C42780000000037 +:101F2000010C427C00000000010C42800000000017 +:101F3000020C42D80000FFFF020C42DC0000FFFF51 +:101F4000020C42E00000FFFF020C42E40000FFFF31 +:101F50000C0C4000000003E80A0C400000000001E7 +:101F60000B0C400000000003060D400000000A00BA +:101F7000020D004400000032020D008C021500200A +:101F8000020D009002150020020D009408100000C0 +:101F9000020D009800000036020D00A000000000B5 +:101FA000020D00A400000004020D00A800000004BF +:101FB000060D00AC00000002020D00B80000000297 +:101FC000020D00C000000001020D00C80000000268 +:101FD000020D00CC00000002020D015C00000001B7 +:101FE000020D016400000001020D01680000000202 +:101FF000020D020400000001020D020C000000208E +:10200000020D021000000040020D0214000000400A +:10201000020D022000000003020D0224000000183F +:10202000060D028000000012040D0300001803FFDB +:10203000060D03600000000C020D004C00000001C2 +:10204000020D005000000002020D005400000000CC +:10205000020D005800000008060D005C000000049E +:10206000020D00C400000004020D00040000000185 +:10207000020D000800000001020D000C000000012C +:10208000020D001000000001020D0014000000010C +:10209000020D001800000001020D001C00000001EC +:1020A000020D002000000001020D002400000001CC +:1020B000020D002800000001020D002C00000001AC +:1020C000020D003000000001020D0034000000018C +:1020D000020D003800000001020D003C000000016C +:1020E000020D011400000009020D011C0000000A8D +:1020F000020D012400000000020D012C0000000070 +:10210000020D013400000000020D013C0000000B34 +:10211000020D014400000000020D0118000000291A +:10212000020D01200000002A020D012800000020FD +:10213000020D013000000020020D013800000020D7 +:10214000020D01400000002B020D0148000000209C +:10215000020D011400000019020D011C0000001AFC +:10216000020D012400000010020D012C00000010DF +:10217000020D013400000010020D013C0000001BA4 +:10218000020D014400000010020D0118000000398A +:10219000020D01200000003A020D0128000000306D +:1021A000020D013000000030020D01380000003047 +:1021B000020D01400000003B020D0148000000300C +:1021C000020D011400000049020D011C0000004A2C +:1021D000020D012400000040020D012C000000400F +:1021E000020D013400000040020D013C0000004BD4 +:1021F000020D014400000040020D011800000069BA +:10220000020D01200000006A020D0128000000609C +:10221000020D013000000060020D01380000006076 +:10222000020D01400000006B020D0148000000603B +:10223000020D011400000059020D011C0000005A9B +:10224000020D012400000050020D012C000000507E +:10225000020D013400000050020D013C0000005B43 +:10226000020D014400000050020D01180000007929 +:10227000020D01200000007A020D0128000000700C +:10228000020D013000000070020D013800000070E6 +:10229000020D01400000007B020D014800000070AB +:1022A000060E200000000800020E004C0000003264 +:1022B000020E009402150020020E00980215002064 +:1022C000020E009C00000030020E00A0081000006A +:1022D000020E00A400000036020E00A8000000302C +:1022E000020E00AC00000031020E00B4000000033A +:1022F000020E00B800000000020E00C40000000042 +:10230000020E00CC00000006020E00D80000000102 +:10231000020E014400000001020E014C0000000109 +:10232000020E015000000002020E02040000000133 +:10233000020E020C00000040020E021000000040DD +:10234000020E021C00000004020E02200000002009 +:10235000020E02240000000E020E02280000001BE4 +:10236000060E030000000012040E0280001B04177A +:10237000060E02EC00000005020E00540000000CE6 +:10238000020E00580000000C020E005C000000006D +:10239000020E006000000010020E00640000001039 +:1023A000060E006800000003020E00DC00000003BF +:1023B000020E000400000001020E000800000001EF +:1023C000020E000C00000001020E001000000001CF +:1023D000020E001400000001020E001800000001AF +:1023E000020E001C00000001020E0020000000018F +:1023F000020E002400000001020E0028000000016F +:10240000020E002C00000001020E0030000000014E +:10241000020E003400000001020E0038000000012E +:10242000020E003C00000001020E0040000000010E +:10243000020E004400000001020E01100000000F17 +:10244000020E011800000000020E01200000000032 +:10245000020E012800000000020E01140000002FEF +:10246000020E011C00000020020E012400000020CA +:10247000020E012C00000020020E01100000001FBF +:10248000020E011800000010020E012000000010D2 +:10249000020E012800000010020E01140000003F8F +:1024A000020E011C00000030020E0124000000306A +:1024B000020E012C00000030020E01100000004F3F +:1024C000020E011800000040020E01200000004032 +:1024D000020E012800000040020E01140000006FEF +:1024E000020E011C00000060020E012400000060CA +:1024F000020E012C00000060020E01100000005FBF +:10250000020E011800000050020E012000000050D1 +:10251000020E012800000050020E01140000007F8E +:10252000020E011C00000070020E01240000007069 +:10253000020E012C000000700730040000D60000DD +:10254000083007D80005043207340000322B0000A1 +:1025500007348000314B0C8B0735000038C518DE7E +:10256000073580002F90271007360000268F32F5A0 +:102570000836716031D40434023000BC00000030F1 +:1025800001300000000000000130000400000000E5 +:1025900001300008000000000130000C00000000C5 +:1025A00001300010000000000130001400000000A5 +:1025B0000230002000000001023000240000000270 +:1025C00002300028000000030230002C0000000050 +:1025D000023000300000000402300034000000012E +:1025E00002300038000000000230003C0000000112 +:1025F00002300040000000040230004400000000EF +:1026000002300048000000010230004C00000003CE +:1026100002300050000000000230005400000001B1 +:1026200002300058000000040230005C000000008E +:10263000023000600000000102300064000000036E +:1026400002300068000000000230006C0000000151 +:10265000023000700000000402300074000000002E +:1026600002300078000000040230007C000000030B +:102670000630008000000002023000A400007FFF4E +:10268000023000A8000003FF023002240000000016 +:1026900002300234000000000230024C0000000052 +:1026A000023002E40000FFFF0630200000000800B6 +:1026B00002338BC000000001023380000000001ACA +:1026C000023380400000004E023380800000001082 +:1026D000023380C0000000200C33830000086470C7 +:1026E0000A338300000001570B3383000000055FAD +:1026F0000A338340000000000C33834000000226B0 +:102700000B338340000000010233838000086470B3 +:10271000023383C00000022602331480000000014F +:102720000A3314800000000006328000000001021D +:1027300006322008000000C8063220000000000217 +:1027400004328520008F04360632875C00000009C1 +:1027500006323EB00000000606323ED00000000205 +:1027600006323E800000000A04323EA8000204C582 +:1027700006323E00000000200632500000000940F2 +:102780000632400000000004043294C0000204C776 +:1027900006324110000000020632D0000000007036 +:1027A0000632DB00000000D40632DEA0000000028A +:1027B0000632E00000000800063324000000011883 +:1027C0000632100000000188063250000000002090 +:1027D00006325100000000200632520000000020A6 +:1027E0000632530000000020063254000000002092 +:1027F000063255000000002006325600000000207E +:102800000632570000000020063258000000002069 +:10281000063259000000002006325A000000002055 +:1028200006325B000000002006325C000000002041 +:1028300006325D000000002006325E00000000202D +:1028400006325F0000000020063284F00000000223 +:1028500004328500000204C9063285080000000227 +:102860000632DE90000000020633286000000118E6 +:102870000632162000000188063250800000002039 +:1028800006325180000000200632528000000020F5 +:1028900006325380000000200632548000000020E1 +:1028A00006325580000000200632568000000020CD +:1028B00006325780000000200632588000000020B9 +:1028C000063259800000002006325A8000000020A5 +:1028D00006325B800000002006325C800000002091 +:1028E00006325D800000002006325E80000000207D +:1028F00006325F8000000020063284F800000002EB +:1029000004328510000204CB063285180000000254 +:102910000632DE98000000020232845000000000FF +:102920000632401000000002023284540000000011 +:1029300006324020000000020232845800000000ED +:1029400006324030000000020232845C00000000C9 +:1029500006324040000000020232846000000000A5 +:102960000632405000000002023284640000000081 +:10297000063240600000000202328468000000005D +:1029800006324070000000020232846C0000000039 +:10299000063240800000000207200400007300009F +:1029A00008200780001004CD072400002AE400005E +:1029B0000724800027670ABA0824D35063FC04CF99 +:1029C000022000BC000000300120000000000000D8 +:1029D00001200004000000000120000800000000A9 +:1029E0000120000C00000000012000100000000089 +:1029F000012000140000000002200020000000015F +:102A00000220002400000002022000280000000331 +:102A10000220002C00000000022000300000000412 +:102A200002200034000000010220003800000000F5 +:102A30000220003C000000010220004000000004D1 +:102A400002200044000000000220004800000001B5 +:102A50000220004C00000003022000500000000093 +:102A60000220005400000001022000580000000471 +:102A70000220005C00000000022000600000000155 +:102A80000220006400000003022000680000000033 +:102A90000220006C00000001022000700000000411 +:102AA00002200074000000000220007800000004F2 +:102AB0000220007C000000030620008000000002CD +:102AC000022000A400007FFF022000A8000003FFF6 +:102AD0000220022400000000022002340000000056 +:102AE0000220024C00000000022002E40000FFFF70 +:102AF000062020000000080002238BC00000000117 +:102B00000223800000000010022380400000001219 +:102B10000223808000000030022380C00000000EED +:102B20000C238300000864700A238300000001570F +:102B30000B2383000000055F0A2383400000000090 +:102B40000C238340000002260B2383400000000179 +:102B50000223838000086470022383C000000226E1 +:102B600002231480000000010A23148000000000EA +:102B7000062210000000004206222008000000C8C3 +:102B800006222000000000020622B00000000330F0 +:102B90000622F400000000530422F54C000104D189 +:102BA0000622F550000000030422F55C000104D267 +:102BB0000622F560000000030422F56C000104D336 +:102BC0000622F570000000030422F57C000104D405 +:102BD0000622F580000000030422F58C000104D5D4 +:102BE0000622F590000000030422F59C000104D6A3 +:102BF0000622F5A0000000030422F5AC000104D772 +:102C00000622F5B0000000030422F5BC000104D840 +:102C10000622F5C0000000460622E2000000044043 +:102C200004221240009004D906223000000000C0A7 +:102C30000622670000000100062290000000040048 +:102C400004226B0800200569062211F0000000062E +:102C50000422120800060589062212200000000244 +:102C600006224000000005C00622C0000000000649 +:102C70000422C0180006058F0622C0300000000A9A +:102C80000422C058000605950622C0700000000A04 +:102C90000422C0980006059B0622C0B00000000A6E +:102CA0000422C0D8000605A10622C0F00000000AD8 +:102CB0000422C118000605A70622C1300000000A40 +:102CC0000422C158000605AD0622C1700000000AAA +:102CD0000422C198000605B30622C1B00000000A14 +:102CE0000422C1D8000605B90622C1F00000000A7E +:102CF0000422C218000605BF0622C2300000000AE6 +:102D00000422C258000605C50622C2700000000A4F +:102D10000422C298000605CB0622C2B00000000AB9 +:102D20000422C2D8000605D10622C2F00000000A23 +:102D30000422C318000605D70622C3300000000A8B +:102D40000422C358000605DD0622C3700000000AF5 +:102D50000422C398000605E30622C3B00000000A5F +:102D60000422C3D8000605E90622C3F00000000AC9 +:102D70000422C418000605EF0622C4300000000A31 +:102D80000422C458000605F50622C4700000000A9B +:102D90000422C498000605FB0622C4B00000000A05 +:102DA0000422C4D8000606010622C4F00000000A6E +:102DB0000422C518000606070622C5300000000AD6 +:102DC0000422C5580006060D0622C5700000000A40 +:102DD0000422C598000606130622C5B00000000AAA +:102DE0000422C5D8000606190622C5F00000000A14 +:102DF0000422C6180006061F0622C6300000000A7C +:102E00000422C658000606250622C6700000000AE5 +:102E10000422C6980006062B0622C6B00000000A4F +:102E20000422C6D8000606310622C6F00000000AB9 +:102E30000422C718000606370622C7300000000A21 +:102E40000422C7580006063D0622C7700000000A8B +:102E50000422C798000606430622C7B00000000AF5 +:102E60000422C7D8000606490622C7F00000000A5F +:102E70000422C8180006064F0622C8300000000AC7 +:102E80000422C858000606550622C8700000000A31 +:102E90000422C8980006065B0622C8B00000000A9B +:102EA0000422C8D8000606610622C8F00000000A05 +:102EB0000422C918000606670622C9300000000A6D +:102EC0000422C9580006066D0622C9700000000AD7 +:102ED0000422C998000606730622C9B00000000A41 +:102EE0000422C9D8000606790622C9F00000000AAB +:102EF0000422CA180006067F0622CA300000000A13 +:102F00000422CA58000606850622CA700000000A7C +:102F10000422CA980006068B0622CAB00000000AE6 +:102F20000422CAD8000606910622CAF00000000A50 +:102F30000422CB18000606970622CB300000000AB8 +:102F40000422CB580006069D0622CB700000000A22 +:102F50000422CB98000606A30622CBB00000000A8C +:102F60000422CBD8000606A90622CBF00000000AF6 +:102F70000422CC18000606AF0622CC300000000A5E +:102F80000422CC58000606B50622CC700000000AC8 +:102F90000422CC98000606BB0622CCB00000000A32 +:102FA0000422CCD8000606C10622CCF00000000A9C +:102FB0000422CD18000606C70622CD300000000A04 +:102FC0000422CD58000606CD0622CD700000000A6E +:102FD0000422CD98000606D30622CDB00000000AD8 +:102FE0000422CDD8000606D90622CDF00000000A42 +:102FF0000422CE18000606DF0622CE300000000AAA +:103000000422CE58000606E50622CE700000000A13 +:103010000422CE98000606EB0622CEB00000000A7D +:103020000422CED8000606F10622CEF00000000AE7 +:103030000422CF18000606F70622CF300000000A4F +:103040000422CF58000606FD0622CF700000000AB9 +:103050000422CF98000607030622CFB00000000A22 +:103060000422CFD8000607090622CFF00000000A8C +:103070000422D0180006070F0622D0300000000AF4 +:103080000422D058000607150622D0700000000A5E +:103090000422D0980006071B0622D0B00000000AC8 +:1030A0000422D0D8000607210622D0F00000000A32 +:1030B0000422D118000607270622D1300000000A9A +:1030C0000422D1580006072D0622D1700000000A04 +:1030D0000422D198000607330622D1B00000000A6E +:1030E0000422D1D8000607390622D1F00000000AD8 +:1030F0000422D2180006073F0622D2300000000A40 +:103100000422D258000607450622D2700000000AA9 +:103110000422D2980006074B0622D2B00000000A13 +:103120000422D2D8000607510622D2F00000000A7D +:103130000422D318000607570622D3300000000AE5 +:103140000422D3580006075D0622D3700000000A4F +:103150000422D398000607630622D3B00000000AB9 +:103160000422D3D8000607690622D3F00000000A23 +:103170000422D4180006076F0622D4300000000A8B +:103180000422D458000607750622D4700000000AF5 +:103190000422D4980006077B0622D4B00000000A5F +:1031A0000422D4D8000607810622D4F00000000AC9 +:1031B0000422D518000607870622D5300000000A31 +:1031C0000422D5580006078D0622D5700000000A9B +:1031D0000422D598000607930622D5B00000000A05 +:1031E0000422D5D8000607990622D5F00000000A6F +:1031F0000422D6180006079F0622D6300000000AD7 +:103200000422D658000607A50622D6700000000A40 +:103210000422D698000607AB0622D6B00000000AAA +:103220000422D6D8000607B10622D6F00000000A14 +:103230000422D718000607B70622D7300000000A7C +:103240000422D758000607BD0622D7700000000AE6 +:103250000422D798000607C30622D7B00000000A50 +:103260000422D7D8000607C90622D7F00000000ABA +:103270000422D818000607CF0622D8300000000A22 +:103280000422D858000607D50622D8700000000A8C +:103290000422D898000607DB0622D8B00000000AF6 +:1032A0000422D8D8000607E10622D8F00000000A60 +:1032B0000422D918000607E70622D9300000000AC8 +:1032C0000422D958000607ED0622D9700000000A32 +:1032D0000422D998000607F30622D9B00000000A9C +:1032E0000422D9D8000607F90622D9F00000000A06 +:1032F0000422DA18000607FF0622DA300000000A6E +:103300000422DA58000608050622DA700000000AD6 +:103310000422DA980006080B0622DAB00000000A40 +:103320000422DAD8000608110622DAF00000000AAA +:103330000422DB18000608170622DB300000000A12 +:103340000422DB580006081D0622DB700000000A7C +:103350000422DB98000608230622DBB00000000AE6 +:103360000422DBD8000608290622DBF00000000A50 +:103370000422DC180006082F0622DC300000000AB8 +:103380000422DC58000608350622DC700000000A22 +:103390000422DC980006083B0622DCB00000000A8C +:1033A0000422DCD8000608410622DCF00000000AF6 +:1033B0000422DD18000608470622DD300000000A5E +:1033C0000422DD580006084D0622DD700000000AC8 +:1033D0000422DD98000608530622DDB00000000A32 +:1033E0000422DDD8000608590622DDF00000000A9C +:1033F0000422DE180006085F0622DE300000000A04 +:103400000422DE58000608650622DE700000000A6D +:103410000422DE980006086B0622DEB00000000AD7 +:103420000422DED8000608710622DEF00000000A41 +:103430000422DF18000608770622DF300000000AA9 +:103440000422DF580006087D0622DF700000000A13 +:103450000422DF98000608830622DFB00000000A7D +:103460000422DFD8000608890622DFF00000000AE7 +:103470000422E0180006088F0622E0300000000A4F +:103480000422E058000608950622E0700000000AB9 +:103490000422E0980006089B0622E0B00000000A23 +:1034A0000422E0D8000608A10622E0F00000000A8D +:1034B0000422E118000608A70622E1300000000AF5 +:1034C0000422E158000608AD0622E1700000000A5F +:1034D0000422E198000608B30622E1B00000000AC9 +:1034E0000422E1D8000608B90622E1F00000000439 +:1034F0000622153800000002062211E80000000232 +:103500000622F3000000000802221148000000001B +:1035100006225900000000060622330000000002C7 +:1035200006226040000000300622F3200000000860 +:103530000222114C0000000006225918000000066B +:10354000062233080000000206226100000000305D +:103550000622F34000000008022211500000000083 +:103560000622593000000006062233100000000237 +:10357000062261C0000000300622F360000000084F +:1035800002221154000000000622594800000006E3 +:10359000062233180000000206226280000000307C +:1035A0000622F380000000080222115800000000EB +:1035B00006225960000000060622332000000002A7 +:1035C00006226340000000300622F3A0000000083D +:1035D0000222115C0000000006225978000000065B +:1035E000062233280000000206226400000000309A +:1035F0000622F3C000000008022211600000000053 +:103600000622599000000006062233300000000216 +:10361000062264C0000000300622F3E0000000082B +:103620000222116400000000062259A800000006D2 +:1036300006223338000000020622658000000030B8 +:103640000216100000000028021700080000000207 +:103650000217002C000000030217003C00000004C9 +:10366000021700440000000002170048000000029A +:103670000217004C0000009002170050000000905C +:103680000217005400800090021700580810000034 +:10369000021700700000000602170078000009FF02 +:1036A0000217007C0000076C021701C4081000001C +:1036B0000217034400000001021704000000008A02 +:1036C00002170404000000800217040800000081B3 +:1036D0000217040C00000080021704100000008A8A +:1036E0000217041400000080021704180000008173 +:1036F0000217041C00000080021704300000008A3A +:103700000217043400000080021704380000008112 +:103710000217043C00000080021704400000008AE9 +:1037200002170444000000800217044800000081D2 +:103730000217044C00000080021704800000008A79 +:103740000217048400000080021704880000008132 +:103750000217048C0000008002170038007C10045F +:10376000021700040000000F021701EC0000000225 +:10377000021701F400000002021701EC0000000231 +:10378000021701F400000002021701EC0000000221 +:10379000021701F400000002021701EC0000000211 +:1037A000021701F400000002021701EC0000000201 +:1037B000021701F400000002021701EC00000002F1 +:1037C000021701F400000002021701EC00000002E1 +:1037D000021701F400000002021701EC00000002D1 +:1037E000021701F400000002061640240000000247 +:1037F000021640700000001C021642080000000182 +:1038000002164210000000010216422000000001D2 +:10381000021642280000000102164230000000019A +:103820000216423800000001021642600000000249 +:103830000C16401C0003D0900A16401C0000009C8F +:103840000B16401C000002710216403000000028D8 +:10385000021640340000002C0216403800000030F0 +:103860000216404400000020021640000000000143 +:10387000021640D8000000010216400800000001B6 +:103880000216400C0000000102164010000000016A +:1038900002164240000000000216424800000000EC +:1038A000061642700000000202164250000000009E +:1038B0000216425800000000061642800000000276 +:1038C00002166008000012140216600C00001200BC +:1038D00002166010000012040216601C0000FFFFB8 +:1038E000021660200000FFFF021660240000FFFFA8 +:1038F000021660280000FFFF02166038000000205A +:103900000216603C00000010061660400000000235 +:1039100002166048000000230216604C00000024DC +:1039200002166050000000250216605400000026B8 +:1039300002166058000000270216605C00000011AB +:103940000216606000000000021660640000002B98 +:10395000021660680000002C0216606C0000002D4A +:1039600002166070000000EC021660740000000097 +:1039700002166078000000290216607C0000002A10 +:10398000021660800000002F061660840000000D03 +:10399000021660B800000001061660BC00000008B6 +:1039A000021660DC00000001061660E00000000462 +:1039B000021660F000000001061660F4000000032B +:1039C0000216610000000001061661040000002DCF +:1039D000021661B800000001061661BC0000000874 +:1039E000021661DC00000001061661E00000000420 +:1039F000021661F000000001061661F400000003E9 +:103A00000216620000000001061662040000000DAC +:103A10000216623807FFFFFF0216623C0000007FBB +:103A20000216624007FFFFFF021662440000003FDB +:103A300001166248000000000116624C0000000000 +:103A400001166250000000000116625400000000E0 +:103A500001166258000000000116625C00000000C0 +:103A600001166260000000000116626400000000A0 +:103A700001166268000000000116626C0000000080 +:103A80000116627000000000011662740000000060 +:103A900001166278000000000116627C0000000040 +:103AA000011662D400000000021662D80000FFFF79 +:103AB000021662DC0000FFFF021662E00000FFFF5A +:103AC000021662E40000FFFF0C166000000003E82D +:103AD0000A166000000000010B16600000000003E1 +:103AE0000216804000000006021680440000000517 +:103AF000021680480000000A0216804C00000005F3 +:103B00000216805400000002021680CC000000045F +:103B1000021680D000000004021680D400000004C9 +:103B2000021680D800000004021680DC00000004A9 +:103B3000021680E000000004021680E40000000489 +:103B4000021680E800000004021688040000000647 +:103B5000021680300000007C021680340000003D18 +:103B6000021680380000003F0216803C0000009CD6 +:103B70000216E6E8000060000216E6EC00006000B5 +:103B80000216E6F0000060000216E6F40000600095 +:103B900002168234000025E40216823800008000FC +:103BA00002168094000025E3021681F400000C0840 +:103BB000021681F800000040021681FC000001009E +:103BC0000216820000000020021682040000001786 +:103BD00002168208000000800216820C000002001B +:103BE00002168210000000000216823C0000001342 +:103BF00002168220008F008F0216821C008F008F19 +:103C0000021680F0000000070216821801FF01FF73 +:103C10000216821401FF01FF061680F40000000264 +:103C20000216811C0000000502168120000000051C +:103C300002168124000000050216812800000008F9 +:103C40000216812C000000060216813000000007D9 +:103C50000616813400000004021680FC00000000FB +:103C600006168144000000020216814C0000000488 +:103C7000021681500000000102168154000000026B +:103C800002168158000000050216815C0000000544 +:103C90000216816000000005021681640000000524 +:103CA0000216816800000008021681000000000072 +:103CB0000216816C000000060216817000000007E9 +:103CC00006168174000000060216818C00000004B4 +:103CD000021681900000000102168104000000001D +:103CE000021681940000000202168198000000056F +:103CF0000216819C00000005021681A0000000054C +:103D0000021681A400000005021681A80000000828 +:103D1000021681AC00000006021681B00000000708 +:103D2000061681B40000000202168108000000009F +:103D3000061681BC00000004021681CC00000004BD +:103D4000021681D000000001021681D4000000029A +:103D5000021681D800000005021681DC0000000573 +:103D6000021681E0000000050216810C000000042C +:103D7000021681E400000005021681E80000000838 +:103D8000021681EC00000006021681F00000000718 +:103D900002168110000000010216811400000002CA +:103DA00002168118000000050216809C0000004CDD +:103DB000021680A00000004C061680C4000000021D +:103DC000021680A400000000021680A80000000077 +:103DD000021680AC0000004C061680B00000000502 +:103DE0000216E6F80000020402168240003F003F7F +:103DF00002168244003F003F061682900000000435 +:103E000002168248008000800216824C00800080EA +:103E100002168250010001000216825401000100C6 +:103E20000616825800000002021682600040004020 +:103E30000216826400400040021682681E001E00C6 +:103E40000216826C1E001E000216827040004000A6 +:103E500002168274400040000216827880008000C2 +:103E60000216827C800080000216828020002000E2 +:103E700002168284200020000616828800000002BC +:103E8000021680900000004B021680600000014086 +:103E900002168064000001400616808800000002BF +:103EA00002168068000000000216806C000000000E +:103EB00002168070000000C0061680740000000525 +:103EC0000216880C0101010102168810010120046C +:103ED000021688142008100102168818010101201A +:103EE0000216881C0101010102168820010120042C +:103EF00002168824200810010216882801010120DA +:103F00000216882C200810010216883001010120B9 +:103F100002168834010101010216883801012004CB +:103F20000216883C20081001021688400101012079 +:103F3000021688440101010102168848010120048B +:103F40000216E6BC000000000216E6C000000002F7 +:103F50000216E6C4000000040216E6C800000006CF +:103F60000216E79400000001021680EC000000FF3A +:103F700002140000000000010215C024000000002F +:103F80000215C0EC000000010215C0F000000001A5 +:103F90000615C10000000002021400040000000128 +:103FA00002140008000000010214000C00000001CF +:103FB000021400300000000102140034000000016F +:103FC0000214004000000001021400440000FFFF42 +:103FD00006140004000000030214000000000000AA +:103FE000060280000000200002020058000000329B +:103FF000020200A003150020020200A40315002005 +:10400000020200A801000030020200AC081000000B +:10401000020200B000000036020200B400000030CE +:10402000020200B800000031020200BC00000002E1 +:10403000020200C000000005020200C400000002ED +:10404000020200C800000002020200D000000007C7 +:10405000020200DC00000000020200E00000000597 +:10406000020200E400000003020200F00000000170 +:10407000020200FC00000006020201200000000015 +:104080000202013400000002020201B0000000013F +:104090000202020C000000010202021400000001F2 +:1040A00002020218000000020202040400000001E3 +:1040B0000202040C00000040020204100000004054 +:1040C0000202041C00000004020204200000002080 +:1040D0000202042400000002020204280000002062 +:1040E000060205000000001204020480002008BF40 +:1040F000020200600000000F0202006400000007DE +:1041000002020068000000000202006C0000000EC5 +:10411000020200700000000E06020074000000039E +:10412000020200F40000000402020004000000018A +:1041300002020008000000010202000C0000000161 +:104140000202001000000001020200140000000141 +:1041500002020018000000010202001C0000000121 +:104160000202002000000001020200240000000101 +:1041700002020028000000010202002C00000001E1 +:1041800002020030000000010202003400000001C1 +:1041900002020038000000010202003C00000001A1 +:1041A0000202004000000001020200440000000181 +:1041B00002020048000000010202004C0000000161 +:1041C000020200500000000102020108000000C8C5 +:1041D0000202011800000002020201C400000000F7 +:1041E000020201CC00000000020201D40000000223 +:1041F000020201DC00000002020201E4000000FFF4 +:10420000020201EC000000FF0202010000000000B9 +:104210000202010C000000C80202011C00000002A2 +:10422000020201C800000000020201D000000000EC +:10423000020201D800000002020201E000000002B8 +:10424000020201E8000000FF020201F0000000FF8E +:10425000020201040000002002020108000000C860 +:104260000202011800000002020201C40000000066 +:10427000020201CC00000000020201D40000000292 +:10428000020201DC00000002020201E4000000FF63 +:10429000020201EC000000FF020201000000001019 +:1042A0000202010C000000C80202011C0000000212 +:1042B000020201C800000000020201D0000000005C +:1042C000020201D800000002020201E00000000228 +:1042D000020201E8000000FF020201F0000000FFFE +:1042E000020201040000003002020108000000C8C0 +:1042F0000202011800000002020201C400000000D6 +:10430000020201CC00000000020201D40000000201 +:10431000020201DC00000002020201E4000000FFD2 +:10432000020201EC000000FF020201000000004058 +:104330000202010C000000C80202011C0000000281 +:10434000020201C800000000020201D000000000CB +:10435000020201D800000002020201E00000000297 +:10436000020201E8000000FF020201F0000000FF6D +:10437000020201040000006002020108000000C8FF +:104380000202011800000002020201C40000000045 +:10439000020201CC00000000020201D40000000271 +:1043A000020201DC00000002020201E4000000FF42 +:1043B000020201EC000000FF0202010000000050B8 +:1043C0000202010C000000C80202011C00000002F1 +:1043D000020201C800000000020201D0000000003B +:1043E000020201D800000002020201E00000000207 +:1043F000020201E8000000FF020201F0000000FFDD +:1044000002020104000000700728040000B300004D +:10441000082807B8000908DF072C000028CB000097 +:10442000072C8000365D0A33072D0000347017CB4F +:10443000072D80003A9424E8072E000036C7338EFB +:10444000072E80001CE94140082EC5D0274608E110 +:10445000022800BC0000003001280000000000001D +:1044600001280004000000000128000800000000EE +:104470000128000C000000000128001000000000CE +:1044800001280014000000000228002000000001A4 +:104490000228002400000002022800280000000377 +:1044A0000228002C00000000022800300000000458 +:1044B000022800340000000102280038000000003B +:1044C0000228003C00000001022800400000000417 +:1044D00002280044000000000228004800000001FB +:1044E0000228004C000000030228005000000000D9 +:1044F00002280054000000010228005800000004B7 +:104500000228005C0000000002280060000000019A +:104510000228006400000003022800680000000078 +:104520000228006C00000001022800700000000456 +:104530000228007400000000022800780000000437 +:104540000228007C00000003062800800000000212 +:10455000022800A400007FFF022800A8000003FF3B +:10456000022802240000000002280234000000009B +:104570000228024C00000000022802E40000FFFFB5 +:104580000628200000000800022B8BC0000000015C +:10459000022B800000000000022B80400000001869 +:1045A000022B80800000000C022B80C000000066FF +:1045B0000C2B8300000864700A2B83000000015755 +:1045C0000B2B83000000055F0A2B834000000000D6 +:1045D0000C2B8340000002260B2B834000000001BF +:1045E000022B838000086470022B83C00000022627 +:1045F000022B1480000000010A2B14800000000030 +:10460000022B944000000001062B94480000000299 +:10461000062A9A7000000004042A9A80000408E325 +:10462000062A9A9000000002042A9A98000208E7DD +:10463000062A900000000048062A2008000000C852 +:10464000062A200000000002062A912800000086A9 +:10465000062AC00000000120062A9348000000033B +:10466000042A9354000108E9062A9FB000000002C2 +:10467000042A9418000208EA042A9CD0000108ECDD +:10468000062A9CD400000011042A9D20008F08ED0A +:10469000062A9F5C00000005042A30000002097C05 +:1046A000062A300800000100062A404000000010E1 +:1046B000042A40000010097E042A84080002098EA2 +:1046C000042ACF4000040990042ACF600002099414 +:1046D000062A9FA000000004062A60000000054092 +:1046E000062A9D1800000002062AB00000000050B3 +:1046F000062ABB7000000070062ABB68000000029A +:10470000062AB94800000004062AD000000008006C +:10471000062AC48000000150062A942000000032BE +:10472000062A502000000002062A50300000000235 +:10473000062A500000000002062A50100000000265 +:10474000022A520800000001042A9AA000020996D9 +:10475000062A95B000000022042A96380001099824 +:10476000062A963C00000003062A96E0000000227C +:10477000042A976800010999062A976C0000000333 +:10478000062A981000000022042A98980001099A2D +:10479000062A989C00000003062A99400000002287 +:1047A000042A99C80001099B062A99CC000000033D +:1047B000062ABB5800000002062AC9C000000150AA +:1047C000062A94E800000032062A50280000000261 +:1047D000062A503800000002062A50080000000295 +:1047E000062A501800000002022A520C00000001A4 +:1047F000042A9AA80002099C062A96480000002272 +:10480000042A96D00001099E062A96D400000003CF +:10481000062A977800000022042A98000001099FC8 +:10482000062A980400000003062A98A80000002227 +:10483000042A9930000109A0062A993400000003D7 +:10484000062A99D800000022042A9A60000109A1D2 +:10485000062A9A6400000003062ABB6000000002DA +:10486000022ACF0000000000042A9AB0001009A21A +:10487000062A50480000000E022ACF040000000063 +:10488000042A9AF0001009B2062A50800000000E97 +:10489000022ACF0800000000042A9B30001009C241 +:1048A000062A50B80000000E022ACF0C00000000BB +:1048B000042A9B70001009D2062A50F00000000E56 +:1048C000022ACF1000000000042A9BB0001009E269 +:1048D000062A51280000000E022ACF140000000012 +:1048E000042A9BF0001009F2062A51600000000E15 +:1048F000022ACF1800000000042A9C3000100A028F +:10490000062A51980000000E022ACF1C0000000069 +:10491000042A9C7000100A12062A51D00000000ED2 +:1049200002101008000000010210105000000001E9 +:10493000021010000003D000021010040000003D1F +:104940000910180002000A220910110000100C22A0 +:1049500006101140000000080910116000100C3210 +:10496000061011A00000001806102400000000E04E +:104970000210201C00000000021020200000000196 +:10498000021020C0000000020210200400000001FC +:104990000210200800000001021030D800000001C1 +:1049A00009103C0000050C420910380000050C47B6 +:1049B0000910392000050C4C09103B0000050C5172 +:1049C000021040D400000030021040D80000003037 +:1049D00006104C00000001000210402800000010EA +:1049E0000210404400003FFF021040580028000021 +:1049F000021040840084924A0210405800000000D7 +:104A0000021041380000000102104138000000018E +:104A1000021041380000000102104138000000017E +:104A2000021041380000000102104138000000016E +:104A3000021041380000000102104138000000015E +:104A40000212049001F680400212051400003C108E +:104A500002120494FFFFFFFF02120498FFFFFFFF02 +:104A60000212049CFFFFFFFF021204A0FFFFFFFFE2 +:104A7000021204A4FFFFFFFF021204A8FFFFFFFFC2 +:104A8000021204ACFFFFFFFF021204B0FFFFFFFFA2 +:104A9000021204B8FFFFFFFF021204BCFFFFFFFF7A +:104AA000021204C0FFFFFFFF021204C4FFFFFFFF5A +:104AB000021204C8FFFFFFFF021204CCFFFFFFFF3A +:104AC000021204D0FFFFFFFF021204D8FFFFFFFF16 +:104AD000021204DCFFFFFFFF021204E0FFFFFFFFF2 +:104AE000021204E4FFFFFFFF021204E8FFFFFFFFD2 +:104AF000021204ECFFFFFFFF021204F0FFFFFFFFB2 +:104B0000021204F4FFFFFFFF021204F8FFFFFFFF91 +:104B1000021204FCFFFFFFFF02120500FFFFFFFF70 +:104B200002120504FFFFFFFF02120508FFFFFFFF4F +:104B30000212050CFFFFFFFF02120510FFFFFFFF2F +:104B4000021204D4F800C000021204B4F0005000B5 +:104B500002120390000000080212039C00000008EB +:104B6000021203A000000008021203A400000002C9 +:104B7000021203BC00000004021203C00000000582 +:104B8000021203C400000004021203D0000000005F +:104B90000212036C00000001021201BC0000004080 +:104BA000021201C000001808021201C4000008032C +:104BB000021201C800000803021201CC00000040EC +:104BC000021201D000000003021201D40000080309 +:104BD000021201D800000803021201DC00000803E1 +:104BE000021201E000010003021201E400000803C8 +:104BF000021201E800000803021201EC00000003A9 +:104C0000021201F000000003021201F40000000390 +:104C1000021201F800000003021201FC0000000370 +:104C2000021202000000000302120204000000034E +:104C300002120208000000030212020C000000032E +:104C4000021202100000000302120214000000030E +:104C500002120218000000030212021C00000003EE +:104C600002120220000000030212022400000003CE +:104C700002120228000024030212022C0000002F5E +:104C80000212023000000009021202340000001972 +:104C900002120238000001840212023C000001836B +:104CA0000212024000000306021202440000001932 +:104CB00002120248000000060212024C0000030625 +:104CC0000212025000000306021202540000030602 +:104CD0000212025800000C860212025C0000030659 +:104CE00002120260000003060212026400000006C5 +:104CF00002120268000000060212026C00000006A8 +:104D00000212027000000006021202740000000687 +:104D100002120278000000060212027C0000000667 +:104D20000212028000000006021202840000000647 +:104D300002120288000000060212028C0000000627 +:104D40000212029000000006021202940000000607 +:104D500002120298000000060212029C00000006E7 +:104D6000021202A000000306021202A400000013B7 +:104D7000021202A800000006021202B00000100495 +:104D8000021202B400001004021203240010644056 +:104D90000212032800106440021205B40000000152 +:104DA000021205F800000040021205FC0000001984 +:104DB00002120600000000010212066C0000000151 +:104DC000021201B000000001021207D80000000327 +:104DD000021207D800000003021207D800000003E7 +:104DE000021207D800000003021207D800000003D7 +:104DF000021207D800000003021207D800000003C7 +:104E0000021207D8000000030600A0000000000CFA +:104E10000200A050000000000200A05400000000AA +:104E20000200A0EC555400000200A0F05555555565 +:104E30000200A0F4000055550200A0F8F0000000A8 +:104E40000200A0FC555400000200A1005555555524 +:104E50000200A104000055550200A108F000000066 +:104E60000200A19C000000000200A1A000010000BF +:104E70000200A1A4000050140200A1A8000000003C +:104E80000200A6A8000000000200A6AC000000007E +:104E90000200A6D0000000000200A45C00000C008C +:104EA0000200A61C000000030200A070FFF55FFFD7 +:104EB0000200A0740000FFFF0200A078F00003E0F1 +:104EC0000200A07C000000000200A0800000A00002 +:104ED0000600A084000000050200A0980FE000007A +:104EE0000600A09C000000070200A0B8000004001B +:104EF0000600A0BC000000030200A0C800001000D3 +:104F00000600A0CC000000030200A0D80000400072 +:104F10000600A0DC000000030200A0E80001000081 +:104F20000600A22C000000040200A688000000FC7D +:104F30000600A68C000000070200A6F40000000096 +:104F40000200A10CFF5C00000200A110FFF55FFF52 +:104F50000200A1140000FFFF0200A118F00003E00E +:104F60000200A11C000000000200A1200000A0001F +:104F70000600A124000000050200A1380FE0000097 +:104F80000600A13C000000070200A1580000080034 +:104F90000600A15C000000030200A16800002000E0 +:104FA0000600A16C000000030200A1780000800050 +:104FB0000600A17C000000030200A188000200009E +:104FC0000600A23C000000040200A6B0000000FCA5 +:104FD0000600A6B4000000070200A6F800000000CA +:104FE0000200A030000000000200A0340000000019 +:104FF0000200A038000000000200A03C00000000F9 +:105000000200A040000000000200A04400000000D8 +:105010000200A048000000000200A04C00000000B8 +:10502000020090C40000E000020090CC0000F300F9 +:10503000020090D400000003020091A000000001D3 +:105040000600917000000003020090EC0000600078 +:10505000020090F400007300020090FC00000003C6 +:10506000020091A8000000010600918800000003E2 +:10507000020091000000400002009108000053006F +:105080000200911000000004020091AC0000000139 +:1050900006009194000000020200919C00000001B3 +:1050A000020090D800006000020090E00000730051 +:1050B000020090E800000003020091A4000000013B +:1050C0000200917C000000010200918000000001BC +:1050D00002009184000000000200912800000300FB +:1050E0000200916C0003F0080200912C0000030004 +:1050F0000200913000000300020091340000030020 +:1051000002009138000003000200913C00000300FF +:1051100002009140000003000200942C00000001F6 +:1051200002009430000000010200943400000001ED +:105130000200942C000000010200943000000001E5 +:1051400002009434000000010200942C00000001D1 +:1051500002009430000000010200943400000001BD +:105160000200942C000000010200943000000001B5 +:1051700002009434000000010200942C00000001A1 +:10518000020094300000000102009434000000018D +:105190000200942C00000001020094300000000185 +:1051A00002009434000000010200942C0000000171 +:1051B000020094300000000102009434000000015D +:1051C0000200942C00000001020094300000000155 +:1051D0000200943400000001021300780000003047 +:1051E0000213003C000061A8061301080000000340 +:1051F000021301040000000002130134000000004B +:10520000061301080000000302130104000000005F +:10521000021301340000000006130108000000031F +:10522000021301040000000002130134000000001A +:10523000061301080000000302130104000000002F +:1052400002130134000000000613010800000003EF +:1052500002130104000000000213013400000000EA +:1052600006130108000000030213010400000000FF +:1052700002130134000000000613010800000003BF +:1052800002130104000000000213013400000000BA +:1052900006130108000000030213010400000000CF +:1052A0000213013400000000021100B800000001E8 +:1052B0000216E6E8000020000216E6EC00002000DE +:1052C0000216E6F0000065550216E6F4000065558A +:1052D00002168150000000000216817400000001D7 +:1052E00002168178000000010216817C0000000196 +:1052F0000216818000000001021681840000000176 +:105300000216818800000001021681B4000000012D +:10531000021681B800000001021681BC00000001E5 +:10532000021681C000000001021681C400000001C5 +:10533000021681C800000001021681100000000062 +:105340000216824000BF00BF061682440000000221 +:105350000216824C00BF00BF0216E6C40000000126 +:105360000216E6C8000000030216E79400000000E1 +:10537000042ACF40000A0C56000000000000000084 +:1053800000000034000000000000000000000000E9 +:10539000000000000000000000000000000000000D +:1053A0000000000000000000000000000034003594 +:1053B00000000000000000000000000000000000ED +:1053C00000000000000000000000000000000000DD +:1053D0000000000000000000003500600000000038 +:1053E00000000000000000000000000000000000BD +:1053F00000000000000000000000000000000000AD +:1054000000000000006000910000000000000000AB +:1054100000910095009500990099009D009D00A1C4 +:1054200000A100A500A500A900A900AD00AD00B134 +:1054300000B100B500000000000000000000000006 +:10544000000000000000000000000000000000005C +:1054500000000000000000000000000000B5031183 +:105460000311031B031B03250325032C032C033308 +:105470000333033A033A0341034103480348034F0C +:10548000034F03560356035D0000000000000000B8 +:10549000000000000000000000000000000000000C +:1054A00000000000000000000000000000000000FC +:1054B00000000000000000000000000000000000EC +:1054C00000000000000000000000000000000000DC +:1054D00000000000000000000000000000000000CC +:1054E00000000000000000000000000000000000BC +:1054F00000000000000000000000000000000000AC +:10550000000000000000000000000000000000009B +:10551000000000000000000000000000000000008B +:10552000000000000000000000000000000000007B +:105530000000000000000000035D035E00000000AA +:1055400000000000035E035F035F0360036003610C +:10555000036103620362036303630364036403651B +:10556000036503660000000000000000000000006A +:10557000000000000000000000000000000000002B +:10558000000000000000000000000000000000001B +:105590000366036D036D0379037903850000000042 +:1055A00000000000000000000000000000000000FB +:1055B00000000000000000000000000000000000EB +:1055C00000000000000000000000000000000000DB +:1055D00000000000000000000000000000000000CB +:1055E00000000000000000000385038600000000AA +:1055F00000000000000000000000000000000000AB +:10560000000000000000000000000000000000009A +:1056100000000000038603B100000000000000004D +:10562000000000000000000000000000000000007A +:10563000000000000000000000000000000000006A +:1056400003B103E0000000000000000000000000C3 +:10565000000000000000000000000000000000004A +:1056600000000000000000000000000003E0040F44 +:105670000000000000000000040F04160416041DC2 +:10568000041D04240424042B042B043204320439A2 +:1056900004390440044004470447047A0000000031 +:1056A00000000000047A047E047E048204820486E2 +:1056B0000486048A048A048E048E0492049204965A +:1056C0000496049A049A04EA04EA05000500051603 +:1056D000051605180518051A051A051C051C051ED2 +:1056E000051E052005200522052205240524052682 +:1056F00005260693000000000000000006930698AF +:105700000698069D069D06A206A206A706A706AC59 +:1057100006AC06B106B106B606B606BB06BB06BCAD +:105720000000000000000000000000000000000079 +:105730000000000000000000000000000000000069 +:10574000000000000000000006BC06E000000000B1 +:105750000000000006E006E206E206E406E406E6D3 +:1057600006E606E806E806EA06EA06EC06EC06EEB9 +:1057700006EE06F006F00705070507080708070B01 +:105780000000000000000000000000000000000019 +:105790000000000000000000000000000000000009 +:1057A000070B074F00000000000000000000000091 +:1057B00000000000000000000000000000000000E9 +:1057C000000000000000000000000000074F07E19B +:1057D00000000000000000000000000000000000C9 +:1057E00000000000000000000000000000000000B9 +:1057F000000000000000000007E107EF00000000CB +:105800000000000000000000000000000000000098 +:105810000000000000000000000000000000000088 +:105820000000000007EF082C00000000000000004E +:10583000082C08350835083E083E08470847085038 +:1058400008500859085908620862086B086B087408 +:10585000087408D508D508EA08EA08FF08FF090215 +:1058600009020905090509080908090B090B090EB0 +:10587000090E09110911091409140917091709203A +:105880000000000000000000000000000000000018 +:105890000000000000000000000000000000000008 +:1058A00000000000000000000920092600000000A0 +:1058B00000000000000000000000000000000000E8 +:1058C00000000000000000000000000000000000D8 +:1058D000000000000926092B000000000000000065 +:1058E00000000000000000000000000000000000B8 +:1058F00000000000000000000000000000000000A8 +:10590000092B0933000000000000000009330934AE +:10591000093409350935093609360937093709388F +:10592000093809390939093A093A093B00000000E8 +:105930000000000000000000000000000000000067 +:105940000000000000000000000000000000000057 +:105950000000000000000000093B09AC000000004E +:105960000000000009AC09AD09AD09AE09AE09AFF0 +:1059700009AF09B009B009B109B109B209B209B357 +:1059800009B309B409B409C809C809DB09DB09EF7F +:1059900009EF09F009F009F109F109F209F209F337 +:1059A00009F309F409F409F509F509F609F609F707 +:1059B00009F70A1600000000000000000A160A1984 +:1059C0000A190A1C0A1C0A1F0A1F0A220A220A258F +:1059D0000A250A280A280A2B0A2B0A2E0A2E0A3020 +:1059E00000000000000000000A300A330A330A36C3 +:1059F0000A360A390A390A3C0A3C0A3F0A3F0A4277 +:105A00000A420A450A450A480A480A4900000000B5 +:105A10000000000000000000000000000000000086 +:105A20000000000000000000000000000000000076 +:105A3000000000000A490A610000000000000000A8 +:105A40000000000000000000000000000000000056 +:105A50000000000000000000000000000000000046 +:105A60000A610A620000000000000000000000005F +:105A70000000000000000000000000000000000026 +:105A80000000000000000000000000000000000016 +:105A9000000100000002070000030E0000041500D2 +:105AA00000051C000006230000072A000008310042 +:105AB00000093800000A3F00000B4600000C4D00B2 +:105AC000000D5400000E5B00000F62000010690022 +:105AD000001170000012770000137E000014850092 +:105AE00000158C000016930000179A000018A10002 +:105AF0000019A800001AAF00001BB600001CBD0072 +:105B0000001DC400001ECB00001FD2000000D90001 +:105B10000000200000004000000060000000800045 +:105B20000000A0000000C0000000E0000001000034 +:105B30000001200000014000000160000001800021 +:105B40000001A0000001C0000001E0000002000010 +:105B500000022000000240000002600000028000FD +:105B60000002A0000002C0000002E00000030000EC +:105B700000032000000340000003600000038000D9 +:105B80000003A0000003C0000003E00000040000C8 +:105B900000042000000440000004600000048000B5 +:105BA0000004A0000004C0000004E00000050000A4 +:105BB0000005200000054000000560000005800091 +:105BC0000005A0000005C0000005E0000006000080 +:105BD000000620000006400000066000000680006D +:105BE0000006A0000006C0000006E000000700005C +:105BF0000007200000074000000760000007800049 +:105C00000007A0000007C0000007E0000008000037 +:105C10000008200000084000000860000008800024 +:105C20000008A0000008C0000008E0000009000013 +:105C30000009200000094000000960000009800000 +:105C40000009A0000009C0000009E000000A0000EF +:105C5000000A2000000A4000000A6000000A8000DC +:105C6000000AA000000AC000000AE000000B0000CB +:105C7000000B2000000B4000000B6000000B8000B8 +:105C8000000BA000000BC000000BE000000C0000A7 +:105C9000000C2000000C4000000C6000000C800094 +:105CA000000CA000000CC000000CE000000D000083 +:105CB000000D2000000D4000000D6000000D800070 +:105CC000000DA000000DC000000DE000000E00005F +:105CD000000E2000000E4000000E6000000E80004C +:105CE000000EA000000EC000000EE000000F00003B +:105CF000000F2000000F4000000F6000000F800028 +:105D0000000FA000000FC000000FE0000010000016 +:105D10000010200000104000001060000010800003 +:105D20000010A0000010C0000010E00000110000F2 +:105D300000112000001140000011600000118000DF +:105D40000011A0000011C0000011E00000120000CE +:105D500000122000001240000012600000128000BB +:105D60000012A0000012C0000012E00000130000AA +:105D70000013200000134000001360000013800097 +:105D80000013A0000013C0000013E0000014000086 +:105D90000014200000144000001460000014800073 +:105DA0000014A0000014C0000014E0000015000062 +:105DB000001520000015400000156000001580004F +:105DC0000015A0000015C0000015E000001600003E +:105DD000001620000016400000166000001680002B +:105DE0000016A0000016C0000016E000001700001A +:105DF0000017200000174000001760000017800007 +:105E00000017A0000017C0000017E00000180000F5 +:105E100000182000001840000018600000188000E2 +:105E20000018A0000018C0000018E00000190000D1 +:105E300000192000001940000019600000198000BE +:105E40000019A0000019C0000019E000001A0000AD +:105E5000001A2000001A4000001A6000001A80009A +:105E6000001AA000001AC000001AE000001B000089 +:105E7000001B2000001B4000001B6000001B800076 +:105E8000001BA000001BC000001BE000001C000065 +:105E9000001C2000001C4000001C6000001C800052 +:105EA000001CA000001CC000001CE000001D000041 +:105EB000001D2000001D4000001D6000001D80002E +:105EC000001DA000001DC000001DE000001E00001D +:105ED000001E2000001E4000001E6000001E80000A +:105EE000001EA000001EC000001EE000001F0000F9 +:105EF000001F2000001F4000001F6000001F8000E6 +:105F0000001FA000001FC000001FE00000200000D4 +:105F100000202000002040000020600000208000C1 +:105F20000020A0000020C0000020E00000210000B0 +:105F3000002120000021400000216000002180009D +:105F40000021A0000021C0000021E000002200008C +:105F50000022200000224000002260000022800079 +:105F60000022A0000022C0000022E0000023000068 +:105F70000023200000234000002360000023800055 +:105F80000023A0000023C0000023E0000024000044 +:105F90000024200000244000002460000024800031 +:105FA0000024A0000024C0000024E0000025000020 +:105FB000002520000025400000256000002580000D +:105FC0000025A0000025C0000025E00000260000FC +:105FD00000262000002640000026600000268000E9 +:105FE0000026A0000026C0000026E00000270000D8 +:105FF00000272000002740000027600000278000C5 +:106000000027A0000027C0000027E00000280000B3 +:1060100000282000002840000028600000288000A0 +:106020000028A0000028C0000028E000002900008F +:10603000002920000029400000296000002980007C +:106040000029A0000029C0000029E000002A00006B +:10605000002A2000002A4000002A6000002A800058 +:10606000002AA000002AC000002AE000002B000047 +:10607000002B2000002B4000002B6000002B800034 +:10608000002BA000002BC000002BE000002C000023 +:10609000002C2000002C4000002C6000002C800010 +:1060A000002CA000002CC000002CE000002D0000FF +:1060B000002D2000002D4000002D6000002D8000EC +:1060C000002DA000002DC000002DE000002E0000DB +:1060D000002E2000002E4000002E6000002E8000C8 +:1060E000002EA000002EC000002EE000002F0000B7 +:1060F000002F2000002F4000002F6000002F8000A4 +:10610000002FA000002FC000002FE0000030000092 +:10611000003020000030400000306000003080007F +:106120000030A0000030C0000030E000003100006E +:10613000003120000031400000316000003180005B +:106140000031A0000031C0000031E000003200004A +:106150000032200000324000003260000032800037 +:106160000032A0000032C0000032E0000033000026 +:106170000033200000334000003360000033800013 +:106180000033A0000033C0000033E0000034000002 +:1061900000342000003440000034600000348000EF +:1061A0000034A0000034C0000034E00000350000DE +:1061B00000352000003540000035600000358000CB +:1061C0000035A0000035C0000035E00000360000BA +:1061D00000362000003640000036600000368000A7 +:1061E0000036A0000036C0000036E0000037000096 +:1061F0000037200000374000003760000037800083 +:106200000037A0000037C0000037E0000038000071 +:10621000003820000038400000386000003880005E +:106220000038A0000038C0000038E000003900004D +:10623000003920000039400000396000003980003A +:106240000039A0000039C0000039E000003A000029 +:10625000003A2000003A4000003A6000003A800016 +:10626000003AA000003AC000003AE000003B000005 +:10627000003B2000003B4000003B6000003B8000F2 +:10628000003BA000003BC000003BE000003C0000E1 +:10629000003C2000003C4000003C6000003C8000CE +:1062A000003CA000003CC000003CE000003D0000BD +:1062B000003D2000003D4000003D6000003D8000AA +:1062C000003DA000003DC000003DE000003E000099 +:1062D000003E2000003E4000003E6000003E800086 +:1062E000003EA000003EC000003EE000003F000075 +:1062F000003F2000003F4000003F6000003F800062 +:10630000003FA000003FC000003FE000003FE00170 +:1063100000000000000001FF0000020000007FF804 +:1063200000007FF800000A90000035000000000126 +:106330000000FF00000000000000FF00000000005F +:106340000000FF00000000000000FF00000000004F +:106350000000FF00000000000000FF00000000003F +:106360000000FF00000000000000FF00000000002F +:106370000000FF00000000000000FF00000000001F +:106380000000FF00000000000000FF00000000000F +:106390000000FF00000000000000FF0000000000FF +:1063A0000000FF00000000000000FF0000000000EF +:1063B0000000FF00000000000000FF0000000000DF +:1063C0000000FF00000000000000FF0000000000CF +:1063D0000000FF00000000000000FF0000000000BF +:1063E0000000FF00000000000000FF0000000000AF +:1063F0000000FF00000000000000FF00000000009F +:106400000000FF00000000000000FF00000000008E +:106410000000FF00000000000000FF00000000007E +:106420000000FF00000000000000FF00000000006E +:106430000000FF00000000000000FF00000000005E +:106440000000FF00000000000000FF00000000004E +:106450000000FF00000000000000FF00000000003E +:106460000000FF00000000000000FF00000000002E +:106470000000FF00000000000000FF00000000001E +:106480000000FF00000000000000FF00000000000E +:106490000000FF00000000000000FF0000000000FE +:1064A0000000FF00000000000000FF0000000000EE +:1064B0000000FF00000000000000FF0000000000DE +:1064C0000000FF00000000000000FF0000000000CE +:1064D0000000FF00000000000000FF0000000000BE +:1064E0000000FF00000000000000FF0000000000AE +:1064F0000000FF00000000000000FF00000000009E +:106500000000FF00000000000000FF00000000008D +:106510000000FF00000000000000FF00000000007D +:106520000000FF00000000000000FF00000000006D +:106530000000FF00000000000000FF00000000005D +:106540000000FF00000000000000FF00000000004D +:106550000000FF00000000000000FF00000000003D +:106560000000FF00000000000000FF00000000002D +:1065700000000000140AFF000000000100000000FD +:106580000020100100000000010090000000010048 +:1065900000009002000090040000900600009008A7 +:1065A0000000900A0000900C0000900E0000901077 +:1065B0000000901200009014000090160000901847 +:1065C0000000901A0000901C0000901E0000902017 +:1065D00000009022000090240000902600009028E7 +:1065E0000000902A0000902C0000902E00009030B7 +:1065F0000000903200009034000090360000903887 +:106600000000903A0000903C0000903E0000904056 +:106610000000904200009044000090460000904826 +:106620000000904A0000904C0000904E00009050F6 +:1066300000009052000090540000905600009058C6 +:106640000000905A0000905C0000905E0000906096 +:106650000000906200009064000090660000906866 +:106660000000906A0000906C0000906E0000907036 +:106670000000907200009074000090760000907806 +:106680000000907A0000907C0000907E00009080D6 +:1066900000009082000090840000908600009088A6 +:1066A0000000908A0000908C0000908E0000909076 +:1066B0000000909200009094000090960000909846 +:1066C0000000909A0000909C0000909E000090A016 +:1066D000000090A2000090A4000090A6000090A8E6 +:1066E000000090AA000090AC000090AE000090B0B6 +:1066F000000090B2000090B4000090B6000090B886 +:10670000000090BA000090BC000090BE000090C055 +:10671000000090C2000090C4000090C6000090C825 +:10672000000090CA000090CC000090CE000090D0F5 +:10673000000090D2000090D4000090D6000090D8C5 +:10674000000090DA000090DC000090DE000090E095 +:10675000000090E2000090E4000090E6000090E865 +:10676000000090EA000090EC000090EE000090F035 +:10677000000090F2000090F4000090F6000090F805 +:10678000000090FA000090FC000090FE00009100D4 +:1067900000009102000091040000910600009108A1 +:1067A0000000910A0000910C0000910E0000911071 +:1067B0000000911200009114000091160000911841 +:1067C0000000911A0000911C0000911E0000912011 +:1067D00000009122000091240000912600009128E1 +:1067E0000000912A0000912C0000912E00009130B1 +:1067F0000000913200009134000091360000913881 +:106800000000913A0000913C0000913E0000914050 +:106810000000914200009144000091460000914820 +:106820000000914A0000914C0000914E00009150F0 +:1068300000009152000091540000915600009158C0 +:106840000000915A0000915C0000915E0000916090 +:106850000000916200009164000091660000916860 +:106860000000916A0000916C0000916E0000917030 +:106870000000917200009174000091760000917800 +:106880000000917A0000917C0000917E00009180D0 +:1068900000009182000091840000918600009188A0 +:1068A0000000918A0000918C0000918E0000919070 +:1068B0000000919200009194000091960000919840 +:1068C0000000919A0000919C0000919E000091A010 +:1068D000000091A2000091A4000091A6000091A8E0 +:1068E000000091AA000091AC000091AE000091B0B0 +:1068F000000091B2000091B4000091B6000091B880 +:10690000000091BA000091BC000091BE000091C04F +:10691000000091C2000091C4000091C6000091C81F +:10692000000091CA000091CC000091CE000091D0EF +:10693000000091D2000091D4000091D6000091D8BF +:10694000000091DA000091DC000091DE000091E08F +:10695000000091E2000091E4000091E6000091E85F +:10696000000091EA000091EC000091EE000091F02F +:10697000000091F2000091F4000091F6000091F8FF +:10698000000091FA000091FC000091FEFFFFFFFF64 +:10699000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF07 +:1069A000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7 +:1069B000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE7 +:1069C000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD7 +:1069D000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC7 +:1069E000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFB7 +:1069F000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA7 +:106A0000FFFFFFFFFFFFFFFFFFFFFFFF000000038F +:106A100000BEBC20000000000000000500000003D4 +:106A200000BEBC20000000000000000500000003C4 +:106A300000BEBC20000000000000000500000003B4 +:106A400000BEBC20000000000000000500000003A4 +:106A500000BEBC2000000000000000050000000394 +:106A600000BEBC2000000000000000050000000384 +:106A700000BEBC2000000000000000050000000374 +:106A800000BEBC2000000000000000050000200047 +:106A9000000040C000006180000082400000A300B0 +:106AA0000000C3C00000E480000105400001260092 +:106AB000000146C000016780000188400001A90074 +:106AC0000001C9C00001EA8000020B4000022C0056 +:106AD00000024CC000026D8000028E400002AF0038 +:106AE0000002CFC00002F0800000114000008000D2 +:106AF000000103800001870000020A8000028E006E +:106B000000031180000395000004188000049C001D +:106B100000051F800005A300000626800006AA00CD +:106B200000072D800007B100000834800008B8007D +:106B300000093B800009BF00000A4280000AC6002D +:106B4000000B4980000BCD00000C5080000CD400DD +:106B5000000D578000005B0000007FF800007FF808 +:106B60000000022A000035000000FF0000000000C5 +:106B70000000FF00000000000000FF000000000017 +:106B80000000FF00000000000000FF000000000007 +:106B90000000FF00000000000000FF0000000000F7 +:106BA0000000FF00000000000000FF0000000000E7 +:106BB0000000FF00000000000000FF0000000000D7 +:106BC0000000FF00000000000000FF0000000000C7 +:106BD0000000FF00000000000000FF0000000000B7 +:106BE0000000FF00000000000000FF0000000000A7 +:106BF0000000FF00000000000000FF000000000097 +:106C00000000FF00000000000000FF000000000086 +:106C10000000FF00000000000000FF000000000076 +:106C20000000FF00000000000000FF000000000066 +:106C30000000FF00000000000000FF000000000056 +:106C40000000FF00000000000000FF000000000046 +:106C50000000FF00000000000000FF000000000036 +:106C60000000FF00000000000000FF000000000026 +:106C70000000FF00000000000000FF000000000016 +:106C80000000FF00000000000000FF000000000006 +:106C90000000FF00000000000000FF0000000000F6 +:106CA0000000FF00000000000000FF0000000000E6 +:106CB0000000FF00000000000000FF0000000000D6 +:106CC0000000FF00000000000000FF0000000000C6 +:106CD0000000FF00000000000000FF0000000000B6 +:106CE0000000FF00000000000000FF0000000000A6 +:106CF0000000FF00000000000000FF000000000096 +:106D00000000FF00000000000000FF000000000085 +:106D10000000FF00000000000000FF000000000075 +:106D20000000FF00000000000000FF000000000065 +:106D30000000FF00000000000000FF000000000055 +:106D40000000FF00000000000000FF000000000045 +:106D50000000FF00000000000000FF000000000035 +:106D60000000FF00000000000000FF000000000025 +:106D70000000FF00000000000000FF000000000015 +:106D80000000FF00000000000000FF000000000005 +:106D90000000FF00000000000000FF0000000000F5 +:106DA0000000FF00000019000000000000000000CB +:106DB000FFFFFFFF000000000393870000000000BA +:106DC0000393870000007FF800007FF800000BA30A +:106DD00000001500000000FF000000FF000000FFA1 +:106DE000000000FF000000FF000000FF000000FFA7 +:106DF000000000FF0000FF00000000000000FF0096 +:106E0000000000000000FF00000000000000FF0084 +:106E1000000000000000FF00000000000000FF0074 +:106E2000000000000000FF00000000000000FF0064 +:106E3000000000000000FF00000000000000FF0054 +:106E4000000000000000FF00000000000000FF0044 +:106E5000000000000000FF00000000000000FF0034 +:106E6000000000000000FF00000000000000FF0024 +:106E7000000000000000FF00000000000000FF0014 +:106E8000000000000000FF00000000000000FF0004 +:106E9000000000000000FF00000000000000FF00F4 +:106EA000000000000000FF00000000000000FF00E4 +:106EB000000000000000FF00000000000000FF00D4 +:106EC000000000000000FF00000000000000FF00C4 +:106ED000000000000000FF00000000000000FF00B4 +:106EE000000000000000FF00000000000000FF00A4 +:106EF000000000000000FF00000000000000FF0094 +:106F0000000000000000FF00000000000000FF0083 +:106F1000000000000000FF00000000000000FF0073 +:106F2000000000000000FF00000000000000FF0063 +:106F3000000000000000FF00000000000000FF0053 +:106F4000000000000000FF00000000000000FF0043 +:106F5000000000000000FF00000000000000FF0033 +:106F6000000000000000FF00000000000000FF0023 +:106F7000000000000000FF00000000000000FF0013 +:106F8000000000000000FF00000000000000FF0003 +:106F9000000000000000FF00000000000000FF00F3 +:106FA000000000000000FF00000000000000FF00E3 +:106FB000000000000000FF00000000000000FF00D3 +:106FC000000000000000FF00000000000000FF00C3 +:106FD000000000000000FF00000000000000FF00B3 +:106FE000000000000000FF00000000000000FF00A3 +:106FF000000000000000FF00000000000000FF0093 +:10700000000000000000FF00000000000000FF0082 +:10701000000000000000FF00000000000000FF0072 +:10702000000000000000FF00000000000000FF0062 +:1070300000000000FFFFFFFFFFFFFFFFFFFFFFFF5C +:10704000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF50 +:10705000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF40 +:10706000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF30 +:10707000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF20 +:10708000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF10 +:10709000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00 +:1070A000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0 +:1070B000FFFFFFFF00000000000028AD00002918BE +:1070C0000000291900000005000000070000FF0073 +:1070D0000FFFFFFF0000FF000FFFFFFF000000FF9A +:1070E0000000FF000000FF000FFFFFFF0000FF0097 +:1070F0000FFFFFFF000000FF0000FF000000FF0087 +:107100000FFFFFFF0000FF000FFFFFFF000000FF69 +:107110000000FF000000FF000FFFFFFF0000FF0066 +:107120000FFFFFFF000000FF0000FF000000FF0056 +:107130000FFFFFFF0000FF000FFFFFFF000000FF39 +:107140000000FF000000FF000FFFFFFF0000FF0036 +:107150000FFFFFFF000000FF0000FF000000FF0026 +:107160000FFFFFFF0000FF000FFFFFFF000000FF09 +:107170000000FF000000FF000FFFFFFF0000FF0006 +:107180000FFFFFFF000000FF0000FF000000FF00F6 +:107190000FFFFFFF0000FF000FFFFFFF000000FFD9 +:1071A0000000FF000000FF000FFFFFFF0000FF00D6 +:1071B0000FFFFFFF000000FF0000FF000000FF00C6 +:1071C0000FFFFFFF0000FF000FFFFFFF000000FFA9 +:1071D0000000FF000000FF000FFFFFFF0000FF00A6 +:1071E0000FFFFFFF000000FF0000FF000000FF0096 +:1071F0000FFFFFFF0000FF000FFFFFFF000000FF79 +:107200000000FF000000FF000FFFFFFF0000FF0075 +:107210000FFFFFFF000000FF0000FF000000FF0065 +:107220000FFFFFFF0000FF000FFFFFFF000000FF48 +:107230000000FF000000FF000FFFFFFF0000FF0045 +:107240000FFFFFFF000000FF0000FF000000FF0035 +:107250000FFFFFFF0000FF000FFFFFFF000000FF18 +:107260000000FF000000FF000FFFFFFF0000FF0015 +:107270000FFFFFFF000000FF0000FF000000FF0005 +:107280000FFFFFFF0000FF000FFFFFFF000000FFE8 +:107290000000FF000000FF000FFFFFFF0000FF00E5 +:1072A0000FFFFFFF000000FF0000FF000000FF00D5 +:1072B0000FFFFFFF0000FF000FFFFFFF000000FFB8 +:1072C0000000FF000000FF000FFFFFFF0000FF00B5 +:1072D0000FFFFFFF000000FF0000FF000000FF00A5 +:1072E0000FFFFFFF0000FF000FFFFFFF000000FF88 +:1072F0000000FF000000FF000FFFFFFF0000FF0085 +:107300000FFFFFFF000000FF0000FF000000FF0074 +:107310000FFFFFFF0000FF000FFFFFFF000000FF57 +:107320000000FF000000FF000FFFFFFF0000FF0054 +:107330000FFFFFFF000000FF0000FF000000FF0044 +:107340000FFFFFFF0000FF000FFFFFFF000000FF27 +:107350000000FF000000FF000FFFFFFF0000FF0024 +:107360000FFFFFFF000000FF0000FF000000FF0014 +:107370000FFFFFFF0000FF000FFFFFFF000000FFF7 +:107380000000FF000000FF000FFFFFFF0000FF00F4 +:107390000FFFFFFF000000FF0000FF000000FF00E4 +:1073A0000FFFFFFF0000FF000FFFFFFF000000FFC7 +:1073B0000000FF000000FF000FFFFFFF0000FF00C4 +:1073C0000FFFFFFF000000FF0000FF000000FF00B4 +:1073D0000FFFFFFF0000FF000FFFFFFF000000FF97 +:1073E0000000FF000000FF000FFFFFFF0000FF0094 +:1073F0000FFFFFFF000000FF0000FF000000FF0084 +:107400000FFFFFFF0000FF000FFFFFFF000000FF66 +:107410000000FF000000FF000FFFFFFF0000FF0063 +:107420000FFFFFFF000000FF0000FF000000FF0053 +:107430000FFFFFFF0000FF000FFFFFFF000000FF36 +:107440000000FF000000FF000FFFFFFF0000FF0033 +:107450000FFFFFFF000000FF0000FF000000FF0023 +:107460000FFFFFFF0000FF000FFFFFFF000000FF06 +:107470000000FF000000FF000FFFFFFF0000FF0003 +:107480000FFFFFFF000000FF0000FF000000FF00F3 +:107490000FFFFFFF0000FF000FFFFFFF000000FFD6 +:1074A0000000FF000000FF000FFFFFFF0000FF00D3 +:1074B0000FFFFFFF000000FF0000FF000000FF00C3 +:1074C0000FFFFFFF0000FF000FFFFFFF000000FFA6 +:1074D0000000FF000000FF000FFFFFFF0000FF00A3 +:1074E0000FFFFFFF000000FF0000FF000000FF0093 +:1074F0000FFFFFFF0000FF000FFFFFFF000000FF76 +:107500000000FF000000FF000FFFFFFF0000FF0072 +:107510000FFFFFFF000000FF0000FF000000FF0062 +:107520000FFFFFFF0000FF000FFFFFFF000000FF45 +:107530000000FF000000FF000FFFFFFF0000FF0042 +:107540000FFFFFFF000000FF0000FF000000FF0032 +:107550000FFFFFFF0000FF000FFFFFFF000000FF15 +:107560000000FF000000FF000FFFFFFF0000FF0012 +:107570000FFFFFFF000000FF0000FF000000FF0002 +:107580000FFFFFFF0000FF000FFFFFFF000000FFE5 +:107590000000FF000000FF000FFFFFFF0000FF00E2 +:1075A0000FFFFFFF000000FF0000FF000000FF00D2 +:1075B0000FFFFFFF0000FF000FFFFFFF000000FFB5 +:1075C0000000FF000000FF000FFFFFFF0000FF00B2 +:1075D0000FFFFFFF000000FF0000FF000000FF00A2 +:1075E0000FFFFFFF0000FF000FFFFFFF000000FF85 +:1075F0000000FF000000FF000FFFFFFF0000FF0082 +:107600000FFFFFFF000000FF0000FF000000FF0071 +:107610000FFFFFFF0000FF000FFFFFFF000000FF54 +:107620000000FF000000FF000FFFFFFF0000FF0051 +:107630000FFFFFFF000000FF0000FF000000FF0041 +:107640000FFFFFFF0000FF000FFFFFFF000000FF24 +:107650000000FF000000FF000FFFFFFF0000FF0021 +:107660000FFFFFFF000000FF0000FF000000FF0011 +:107670000FFFFFFF0000FF000FFFFFFF000000FFF4 +:107680000000FF000000FF000FFFFFFF0000FF00F1 +:107690000FFFFFFF000000FF0000FF000000FF00E1 +:1076A0000FFFFFFF0000FF000FFFFFFF000000FFC4 +:1076B0000000FF000000FF000FFFFFFF0000FF00C1 +:1076C0000FFFFFFF000000FF0000FF000000FF00B1 +:1076D0000FFFFFFF0000FF000FFFFFFF000000FF94 +:1076E0000000FF000000FF000FFFFFFF0000FF0091 +:1076F0000FFFFFFF000000FF0000FF000000FF0081 +:107700000FFFFFFF0000FF000FFFFFFF000000FF63 +:107710000000FF000000FF000FFFFFFF0000FF0060 +:107720000FFFFFFF000000FF0000FF000000FF0050 +:107730000FFFFFFF0000FF000FFFFFFF000000FF33 +:107740000000FF000000FF000FFFFFFF0000FF0030 +:107750000FFFFFFF000000FF0000FF000000FF0020 +:107760000FFFFFFF0000FF000FFFFFFF000000FF03 +:107770000000FF000000FF000FFFFFFF0000FF0000 +:107780000FFFFFFF000000FF0000FF000000FF00F0 +:107790000FFFFFFF0000FF000FFFFFFF000000FFD3 +:1077A0000000FF000000FF000FFFFFFF0000FF00D0 +:1077B0000FFFFFFF000000FF0000FF000000FF00C0 +:1077C0000FFFFFFF0000FF000FFFFFFF000000FFA3 +:1077D0000000FF000000FF000FFFFFFF0000FF00A0 +:1077E0000FFFFFFF000000FF0000FF000000FF0090 +:1077F0000FFFFFFF0000FF000FFFFFFF000000FF73 +:107800000000FF000000FF000FFFFFFF0000FF006F +:107810000FFFFFFF000000FF0000FF000000FF005F +:107820000FFFFFFF0000FF000FFFFFFF000000FF42 +:107830000000FF000000FF000FFFFFFF0000FF003F +:107840000FFFFFFF000000FF0000FF000000FF002F +:107850000FFFFFFF0000FF000FFFFFFF000000FF12 +:107860000000FF000000FF000FFFFFFF0000FF000F +:107870000FFFFFFF000000FF0000FF000000FF00FF +:107880000FFFFFFF0000FF000FFFFFFF000000FFE2 +:107890000000FF000000FF000FFFFFFF0000FF00DF +:1078A0000FFFFFFF000000FF0000FF000000FF00CF +:1078B0000FFFFFFF0000FF000FFFFFFF000000FFB2 +:1078C0000000FF000000FF000FFFFFFF0000FF00AF +:1078D0000FFFFFFF000000FF0000FF000000FF009F +:1078E0000FFFFFFF0000FF000FFFFFFF000000FF82 +:1078F0000000FF000000FF000FFFFFFF0000FF007F +:107900000FFFFFFF000000FF0000FF000000FF006E +:107910000FFFFFFF0000FF000FFFFFFF000000FF51 +:107920000000FF000000FF000FFFFFFF0000FF004E +:107930000FFFFFFF000000FF0000FF000000FF003E +:107940000FFFFFFF0000FF000FFFFFFF000000FF21 +:107950000000FF000000FF000FFFFFFF0000FF001E +:107960000FFFFFFF000000FF0000FF000000FF000E +:107970000FFFFFFF0000FF000FFFFFFF000000FFF1 +:107980000000FF000000FF000FFFFFFF0000FF00EE +:107990000FFFFFFF000000FF0000FF000000FF00DE +:1079A0000FFFFFFF0000FF000FFFFFFF000000FFC1 +:1079B0000000FF000000FF000FFFFFFF0000FF00BE +:1079C0000FFFFFFF000000FF0000FF000000FF00AE +:1079D0000FFFFFFF0000FF000FFFFFFF000000FF91 +:1079E0000000FF000000FF000FFFFFFF0000FF008E +:1079F0000FFFFFFF000000FF0000FF000000FF007E +:107A00000FFFFFFF0000FF000FFFFFFF000000FF60 +:107A10000000FF000000FF000FFFFFFF0000FF005D +:107A20000FFFFFFF000000FF0000FF000000FF004D +:107A30000FFFFFFF0000FF000FFFFFFF000000FF30 +:107A40000000FF000000FF000FFFFFFF0000FF002D +:107A50000FFFFFFF000000FF0000FF000000FF001D +:107A60000FFFFFFF0000FF000FFFFFFF000000FF00 +:107A70000000FF000000FF000FFFFFFF0000FF00FD +:107A80000FFFFFFF000000FF0000FF000000FF00ED +:107A90000FFFFFFF0000FF000FFFFFFF000000FFD0 +:107AA0000000FF000000FF000FFFFFFF0000FF00CD +:107AB0000FFFFFFF000000FF0000FF000000FF00BD +:107AC0000FFFFFFF0000FF000FFFFFFF000000FFA0 +:107AD0000000FF000000FF000FFFFFFF0000FF009D +:107AE0000FFFFFFF000000FF0000FF000000FF008D +:107AF0000FFFFFFF0000FF000FFFFFFF000000FF70 +:107B00000000FF000000FF000FFFFFFF0000FF006C +:107B10000FFFFFFF000000FF0000FF000000FF005C +:107B20000FFFFFFF0000FF000FFFFFFF000000FF3F +:107B30000000FF000000FF000FFFFFFF0000FF003C +:107B40000FFFFFFF000000FF0000FF000000FF002C +:107B50000FFFFFFF0000FF000FFFFFFF000000FF0F +:107B60000000FF000000FF000FFFFFFF0000FF000C +:107B70000FFFFFFF000000FF0000FF000000FF00FC +:107B80000FFFFFFF0000FF000FFFFFFF000000FFDF +:107B90000000FF000000FF000FFFFFFF0000FF00DC +:107BA0000FFFFFFF000000FF0000FF000000FF00CC +:107BB0000FFFFFFF0000FF000FFFFFFF000000FFAF +:107BC0000000FF000000FF000FFFFFFF0000FF00AC +:107BD0000FFFFFFF000000FF0000FF000000FF009C +:107BE0000FFFFFFF0000FF000FFFFFFF000000FF7F +:107BF0000000FF000000FF000FFFFFFF0000FF007C +:107C00000FFFFFFF000000FF0000FF000000FF006B +:107C10000FFFFFFF0000FF000FFFFFFF000000FF4E +:107C20000000FF000000FF000FFFFFFF0000FF004B +:107C30000FFFFFFF000000FF0000FF000000FF003B +:107C40000FFFFFFF0000FF000FFFFFFF000000FF1E +:107C50000000FF000000FF000FFFFFFF0000FF001B +:107C60000FFFFFFF000000FF0000FF000000FF000B +:107C70000FFFFFFF0000FF000FFFFFFF000000FFEE +:107C80000000FF000000FF000FFFFFFF0000FF00EB +:107C90000FFFFFFF000000FF0000FF000000FF00DB +:107CA0000FFFFFFF0000FF000FFFFFFF000000FFBE +:107CB0000000FF000000FF000FFFFFFF0000FF00BB +:107CC0000FFFFFFF000000FF0000FF000000FF00AB +:107CD0000FFFFFFF0000FF000FFFFFFF000000FF8E +:107CE0000000FF000000FF000FFFFFFF0000FF008B +:107CF0000FFFFFFF000000FF0000FF000000FF007B +:107D00000FFFFFFF0000FF000FFFFFFF000000FF5D +:107D10000000FF000000FF000FFFFFFF0000FF005A +:107D20000FFFFFFF000000FF0000FF000000FF004A +:107D30000FFFFFFF0000FF000FFFFFFF000000FF2D +:107D40000000FF000000FF000FFFFFFF0000FF002A +:107D50000FFFFFFF000000FF0000FF000000FF001A +:107D60000FFFFFFF0000FF000FFFFFFF000000FFFD +:107D70000000FF000000FF000FFFFFFF0000FF00FA +:107D80000FFFFFFF000000FF0000FF0000001000D9 +:107D900000002080000031000000418000005200FF +:107DA00000006280000073000000838000009400E7 +:107DB0000000A4800000B5000000C5800000D600CF +:107DC0000000E6800000F7000001078000011800B5 +:107DD00000012880000139000001498000015A009B +:107DE00000016A8000017B0000018B8000019C0083 +:107DF0000001AC800001BD000001CD800001DE006B +:107E00000001EE800001FF0000000F8000007FF8FD +:107E100000007FF8000005F60000350010000000AB +:107E2000000028AD000029180000291900000005F5 +:107E3000000000060001000100090206CCCCCCC9FC +:107E40007058103C0000FF00000000000000FF0020 +:107E5000000000000000FF00000000000000FF0024 +:107E6000000000000000FF00000000000000FF0014 +:107E7000000000000000FF00000000000000FF0004 +:107E8000000000000000FF00000000000000FF00F4 +:107E9000000000000000FF00000000000000FF00E4 +:107EA000000000000000FF00000000000000FF00D4 +:107EB000000000000000FF00000000000000FF00C4 +:107EC000000000000000FF00000000000000FF00B4 +:107ED000000000000000FF00000000000000FF00A4 +:107EE000000000000000FF00000000000000FF0094 +:107EF000000000000000FF00000000000000FF0084 +:107F0000000000000000FF00000000000000FF0073 +:107F1000000000000000FF00000000000000FF0063 +:107F2000000000000000FF00000000000000FF0053 +:107F3000000000000000FF00000000000000FF0043 +:107F4000000000000000FF00000000000000FF0033 +:107F5000000000000000FF00000000000000FF0023 +:107F6000000000000000FF00000000000000FF0013 +:107F7000000000000000FF00000000000000FF0003 +:107F8000000000000000FF00000000000000FF00F3 +:107F9000000000000000FF00000000000000FF00E3 +:107FA000000000000000FF00000000000000FF00D3 +:107FB000000000000000FF00000000000000FF00C3 +:107FC000000000000000FF00000000000000FF00B3 +:107FD000000000000000FF00000000000000FF00A3 +:107FE000000000000000FF00000000000000FF0093 +:107FF000000000000000FF00000000000000FF0083 +:10800000000000000000FF00000000000000FF0072 +:10801000000000000000FF00000000000000FF0062 +:10802000000000000000FF00000000000000FF0052 +:10803000000000000000FF00000000000000FF0042 +:10804000000000000000FF00000000000000FF0032 +:10805000000000000000FF00000000000000FF0022 +:10806000000000000000FF00000000000000FF0012 +:10807000000000000000FF00000000000000FF0002 +:108080000000000000000001CCCC0201CCCCCCCC24 +:10809000CCCC0201CCCCCCCCCCCC0201CCCCCCCC4A +:1080A000CCCC0201CCCCCCCCCCCC0201CCCCCCCC3A +:1080B000CCCC0201CCCCCCCCCCCC0201CCCCCCCC2A +:1080C000CCCC0201CCCCCCCC00000000FFFFFFFFE9 +:1080D000030303031342020250505020706080508B +:1080E0000200020006040604000E0000011600D67D +:1080F000002625A0002625A0002625A0002625A0D4 +:1081000000720000012300F3002625A0002625A010 +:10811000002625A0002625A00000FFFF000000008B +:108120000000FFFF000000000000FFFF0000000053 +:108130000000FFFF000000000000FFFF0000000043 +:108140000000FFFF000000000000FFFF0000000033 +:108150000000FFFF000000000000FFFF0000000023 +:108160000000FFFF000000000000FFFF0000000013 +:108170000000FFFF000000000000FFFF0000000003 +:108180000000FFFF000000000000FFFF00000000F3 +:108190000000FFFF000000000000FFFF00000000E3 +:1081A0000000FFFF000000000000FFFF00000000D3 +:1081B0000000FFFF000000000000FFFF00000000C3 +:1081C0000000FFFF000000000000FFFF00000000B3 +:1081D0000000FFFF000000000000FFFF00000000A3 +:1081E0000000FFFF000000000000FFFF0000000093 +:1081F0000000FFFF000000000000FFFF0000000083 +:108200000000FFFF000000000000FFFF0000000072 +:108210000000FFFF000000000000FFFF0000000062 +:108220000000FFFF000000000000FFFF0000000052 +:108230000000FFFF000000000000FFFF0000000042 +:108240000000FFFF000000000000FFFF0000000032 +:108250000000FFFF000000000000FFFF0000000022 +:108260000000FFFF000000000000FFFF0000000012 +:108270000000FFFF000000000000FFFF0000000002 +:108280000000FFFF000000000000FFFF00000000F2 +:108290000000FFFF000000000000FFFF00000000E2 +:1082A0000000FFFF000000000000FFFF00000000D2 +:1082B0000000FFFF000000000000FFFF00000000C2 +:1082C0000000FFFF000000000000FFFF00000000B2 +:1082D0000000FFFF000000000000FFFF00000000A2 +:1082E0000000FFFF000000000000FFFF0000000092 +:1082F0000000FFFF000000000000FFFF0000000082 +:108300000000FFFF000000000000FFFF0000000071 +:108310000000FFFF00000000FFFFFFF3318FFFFFB1 +:108320000C30C30CC30C30C3CF3CF300F3CF3CF391 +:108330000000CF3CCDCDCDCDFFFFFFF130EFFFFFF3 +:108340000C30C30CC30C30C3CF3CF300F3CF3CF371 +:108350000001CF3CCDCDCDCDFFFFFFF6305FFFFF5D +:108360000C30C30CC30C30C3CF3CF300F3CF3CF351 +:108370000002CF3CCDCDCDCDFFFFF4061CBFFFFFEB +:108380000C30C305C30C30C3CF300014F3CF3CF323 +:108390000004CF3CCDCDCDCDFFFFFFF2304FFFFF2E +:1083A0000C30C30CC30C30C3CF3CF300F3CF3CF311 +:1083B0000008CF3CCDCDCDCDFFFFFFFA302FFFFF22 +:1083C0000C30C30CC30C30C3CF3CF300F3CF3CF3F1 +:1083D0000010CF3CCDCDCDCDFFFFFFF731EFFFFF3C +:1083E0000C30C30CC30C30C3CF3CF300F3CF3CF3D1 +:1083F0000020CF3CCDCDCDCDFFFFFFF5302FFFFFCF +:108400000C30C30CC30C30C3CF3CF300F3CF3CF3B0 +:108410000040CF3CCDCDCDCDFFFFFFF3318FFFFF2F +:108420000C30C30CC30C30C3CF3CF300F3CF3CF390 +:108430000000CF3CCDCDCDCDFFFFFFF1310FFFFFD1 +:108440000C30C30CC30C30C3CF3CF300F3CF3CF370 +:108450000001CF3CCDCDCDCDFFFFFFF6305FFFFF5C +:108460000C30C30CC30C30C3CF3CF300F3CF3CF350 +:108470000002CF3CCDCDCDCDFFFFF4061CBFFFFFEA +:108480000C30C305C30C30C3CF300014F3CF3CF322 +:108490000004CF3CCDCDCDCDFFFFFFF2304FFFFF2D +:1084A0000C30C30CC30C30C3CF3CF300F3CF3CF310 +:1084B0000008CF3CCDCDCDCDFFFFFFFA302FFFFF21 +:1084C0000C30C30CC30C30C3CF3CF300F3CF3CF3F0 +:1084D0000010CF3CCDCDCDCDFFFFFFF730EFFFFF3C +:1084E0000C30C30CC30C30C3CF3CF300F3CF3CF3D0 +:1084F0000020CF3CCDCDCDCDFFFFFFF5304FFFFFAE +:108500000C30C30CC30C30C3CF3CF300F3CF3CF3AF +:108510000040CF3CCDCDCDCDFFFFFFFF30CFFFFFE3 +:108520000C30C30CC30C30C3CF3CF3CCF3CF3CF3C3 +:108530000000CF3CCDCDCDCDFFFFFFFF30CFFFFF03 +:108540000C30C30CC30C30C3CF3CF3CCF3CF3CF3A3 +:108550000001CF3CCDCDCDCDFFFFFFFF30CFFFFFE2 +:108560000C30C30CC30C30C3CF3CF3CCF3CF3CF383 +:108570000002CF3CCDCDCDCDFFFFFFFF30CFFFFFC1 +:108580000C30C30CC30C30C3CF3CF3CCF3CF3CF363 +:108590000004CF3CCDCDCDCDFFFFFFFF30CFFFFF9F +:1085A0000C30C30CC30C30C3CF3CF3CCF3CF3CF343 +:1085B0000008CF3CCDCDCDCDFFFFFFFF30CFFFFF7B +:1085C0000C30C30CC30C30C3CF3CF3CCF3CF3CF323 +:1085D0000010CF3CCDCDCDCDFFFFFFFF30CFFFFF53 +:1085E0000C30C30CC30C30C3CF3CF3CCF3CF3CF303 +:1085F0000020CF3CCDCDCDCDFFFFFFFF30CFFFFF23 +:108600000C30C30CC30C30C3CF3CF3CCF3CF3CF3E2 +:108610000040CF3CCDCDCDCDFFFFFFF3320FFFFFAC +:108620000C30C30CC30C30C3CF3CF300F3CF3CF38E +:108630000000CF3CCDCDCDCDFFFFFFF1310FFFFFCF +:108640000C30C30CC30C30C3CF3CF300F3CF3CF36E +:108650000001CF3CCDCDCDCDFFFFFFF6305FFFFF5A +:108660000C30C30CC30C30C3CF3CF300F3CF3CF34E +:108670000002CF3CCDCDCDCDFFFFF4061CBFFFFFE8 +:108680000C30C305C30C30C3CF300014F3CF3CF320 +:108690000004CF3CCDCDCDCDFFFFFFF2304FFFFF2B +:1086A0000C30C30CC30C30C3CF3CF300F3CF3CF30E +:1086B0000008CF3CCDCDCDCDFFFFFF8A042FFFFFBB +:1086C0000C30C30CC30C30C3CF3CC000F3CF3CF321 +:1086D0000010CF3CCDCDCDCDFFFFFF9705CFFFFFE5 +:1086E0000C30C30CC30C30C3CF3CC000F3CF3CF301 +:1086F0000020CF3CCDCDCDCDFFFFFFF5310FFFFFEB +:108700000C30C30CC30C30C3CF3CF300F3CF3CF3AD +:108710000040CF3CCDCDCDCDFFFFFFF3320FFFFFAB +:108720000C30C30CC30C30C3CF3CF300F3CF3CF38D +:108730000000CF3CCDCDCDCDFFFFFFF1302FFFFFAF +:108740000C30C30CC30C30C3CF3CF300F3CF3CF36D +:108750000001CF3CCDCDCDCDFFFFFFF6305FFFFF59 +:108760000C30C30CC30C30C3CF3CF300F3CF3CF34D +:108770000002CF3CCDCDCDCDFFFFFF061CBFFFFFDC +:108780000C30C30CC30C30C3CF3CC014F3CF3CF34C +:108790000004CF3CCDCDCDCDFFFFFFF2304FFFFF2A +:1087A0000C30C30CC30C30C3CF3CF300F3CF3CF30D +:1087B0000008CF3CCDCDCDCDFFFFFFFA302FFFFF1E +:1087C0000C30C30CC30C30C3CF3CF300F3CF3CF3ED +:1087D0000010CF3CCDCDCDCDFFFFFFF731CFFFFF58 +:1087E0000C30C30CC30C30C3CF3CF300F3CF3CF3CD +:1087F0000020CF3CCDCDCDCDFFFFFFFF30CFFFFF21 +:108800000C30C30CC30C30C3CF3CF3CCF3CF3CF3E0 +:108810000040CF3CCDCDCDCDFFFFFFFF30CFFFFFE0 +:108820000C30C30CC30C30C3CF3CF3CCF3CF3CF3C0 +:108830000000CF3CCDCDCDCDFFFFFFFF30CFFFFF00 +:108840000C30C30CC30C30C3CF3CF3CCF3CF3CF3A0 +:108850000001CF3CCDCDCDCDFFFFFFFF30CFFFFFDF +:108860000C30C30CC30C30C3CF3CF3CCF3CF3CF380 +:108870000002CF3CCDCDCDCDFFFFFFFF30CFFFFFBE +:108880000C30C30CC30C30C3CF3CF3CCF3CF3CF360 +:108890000004CF3CCDCDCDCDFFFFFFFF30CFFFFF9C +:1088A0000C30C30CC30C30C3CF3CF3CCF3CF3CF340 +:1088B0000008CF3CCDCDCDCDFFFFFFFF30CFFFFF78 +:1088C0000C30C30CC30C30C3CF3CF3CCF3CF3CF320 +:1088D0000010CF3CCDCDCDCDFFFFFFFF30CFFFFF50 +:1088E0000C30C30CC30C30C3CF3CF3CCF3CF3CF300 +:1088F0000020CF3CCDCDCDCDFFFFFFFF30CFFFFF20 +:108900000C30C30CC30C30C3CF3CF3CCF3CF3CF3DF +:108910000040CF3CCDCDCDCDFFFFFFFF30CFFFFFDF +:108920000C30C30CC30C30C3CF3CF3CCF3CF3CF3BF +:108930000000CF3CCDCDCDCDFFFFFFFF30CFFFFFFF +:108940000C30C30CC30C30C3CF3CF3CCF3CF3CF39F +:108950000001CF3CCDCDCDCDFFFFFFFF30CFFFFFDE +:108960000C30C30CC30C30C3CF3CF3CCF3CF3CF37F +:108970000002CF3CCDCDCDCDFFFFFFFF30CFFFFFBD +:108980000C30C30CC30C30C3CF3CF3CCF3CF3CF35F +:108990000004CF3CCDCDCDCDFFFFFFFF30CFFFFF9B +:1089A0000C30C30CC30C30C3CF3CF3CCF3CF3CF33F +:1089B0000008CF3CCDCDCDCDFFFFFFFF30CFFFFF77 +:1089C0000C30C30CC30C30C3CF3CF3CCF3CF3CF31F +:1089D0000010CF3CCDCDCDCDFFFFFFFF30CFFFFF4F +:1089E0000C30C30CC30C30C3CF3CF3CCF3CF3CF3FF +:1089F0000020CF3CCDCDCDCDFFFFFFFF30CFFFFF1F +:108A00000C30C30CC30C30C3CF3CF3CCF3CF3CF3DE +:108A10000040CF3CCDCDCDCDFFFFFFFF30CFFFFFDE +:108A20000C30C30CC30C30C3CF3CF3CCF3CF3CF3BE +:108A30000000CF3CCDCDCDCDFFFFFFFF30CFFFFFFE +:108A40000C30C30CC30C30C3CF3CF3CCF3CF3CF39E +:108A50000001CF3CCDCDCDCDFFFFFFFF30CFFFFFDD +:108A60000C30C30CC30C30C3CF3CF3CCF3CF3CF37E +:108A70000002CF3CCDCDCDCDFFFFFFFF30CFFFFFBC +:108A80000C30C30CC30C30C3CF3CF3CCF3CF3CF35E +:108A90000004CF3CCDCDCDCDFFFFFFFF30CFFFFF9A +:108AA0000C30C30CC30C30C3CF3CF3CCF3CF3CF33E +:108AB0000008CF3CCDCDCDCDFFFFFFFF30CFFFFF76 +:108AC0000C30C30CC30C30C3CF3CF3CCF3CF3CF31E +:108AD0000010CF3CCDCDCDCDFFFFFFFF30CFFFFF4E +:108AE0000C30C30CC30C30C3CF3CF3CCF3CF3CF3FE +:108AF0000020CF3CCDCDCDCDFFFFFFFF30CFFFFF1E +:108B00000C30C30CC30C30C3CF3CF3CCF3CF3CF3DD +:108B10000040CF3CCDCDCDCD000C0000000700C003 +:108B200000028130000B8158000202100001023067 +:108B3000000F024000010330000C0000000800C0DC +:108B400000028140000B8168000202200001024007 +:108B500000070250000202C00010000000080100DF +:108B600000028180000B81A8000202600001828067 +:108B7000000E829800080380001000000001010030 +:108B80000002811000090138000201C8000101E85B +:108B9000000E01F8000002D8CCCCCCCCCCCCCCCC94 +:108BA000CCCCCCCCCCCCCCCC00002000CCCCCCCC15 +:108BB000CCCCCCCCCCCCCCCCCCCCCCCC0000200005 +:108BC000CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCE5 +:108BD00004002000CCCCCCCCCCCCCCCCCCCCCCCCE1 +:108BE000CCCCCCCC4100200003030303034202029F +:108BF0005050502070608050131313131342121200 +:108C000050505020706080500301020000000000AE +:108C100000000000000000001F8B080000000000A2 +:108C2000000BFB51CFC0F0038A0F093230688A2055 +:108C3000F8C4E05C760686751C0C0C5BB849D3075B +:108C4000C32C0C0C0CDA4CE4E905E1FBBC0C0CAFBA +:108C50008098850F559C871342FF015AC0C7CAC030 +:108C6000A0C1865DFF3A35043B408581A11C88D9AF +:108C7000941818CC5411E2D2EA0C0C3380FC04A8EE +:108C8000D81D201DAB46BE9B47F1E0C1378D51F981 +:108C90005B0DA169012A7E0B4D7E1B54BE4A074223 +:108CA000DF36C66E6EB50E71F69FB546E5AFB4C63B +:108CB000AFFEAE3D2AFF209AFAAD503E00C5D55B0F +:108CC000A7D8030000000000000000000000000022 +:108CD0001F8B080000000000000BED7D7F7C14D589 +:108CE000B5F8999DD9D9D9CDEE6608096C20E02454 +:108CF000861AFB82DFE577A841878034B63CDF8A9D +:108D00005AD3D6F6BB506C551456BF3EE1F56933C5 +:108D1000F941122262049FDAD61F2B554BFB6C8956 +:108D2000942AAD3FDE024AF1F5C743AAD5D7A22F58 +:108D3000FE80AA455FC4D2D87E51DE3DE7DEC9CEB3 +:108D40004C76930DD01F7FBCF081E1CEDC1FE79EF7 +:108D500073EE39E79E73EE8DEA0BC2C7CE05388EEF +:108D60003FECD913028059D9A771F5BCAEBE99006A +:108D70004721D2D35D0AD0A68009AC6C1D88A41F00 +:108D800094007F6A14565E2D7F3CDE5D097067D1CA +:108D9000D7EEC3FA6B2C0502ECD9DD0C9039837D3C +:108DA0000F453743314011A4B6E277F6937890F53A +:108DB00037109C9C866876FC32F0D1B80015FAA179 +:108DC00022AA07C765F6CF81E47C18072083FDB38C +:108DD000067A593FCAF3721AC795E5C5FA8B55D979 +:108DE0007EBC4F595721A389FEF01FF9B2E26438C7 +:108DF0007FFD35072AB73E5D93AD7F06444A0FFDE0 +:108E00001DFB8F020AC123AF07C4C3D130A4E5CA3A +:108E1000FCFD0C341B5B9FF6231EBF509C989ABF31 +:108E20009E8DA7AE668D9E1DCD3A6402000C64B384 +:108E3000B7963DC3606EAE1DDA6E0148842FCDB08B +:108E4000089EF6B02F5D5489502701187EFD881FBB +:108E500009DF2FD1CC1CEDED279432FCD8F36578D7 +:108E60000C02EF0FD8FC1E64FD0571FC1CF8BA085B +:108E7000C72F63DFAB878E6FCD3CF1F1436702EC08 +:108E80000B23BE4D84017C7A0AE282DE9F9486E940 +:108E900047D05931783F23E1BDA8C6971D97FD0DF6 +:108EA0001A21179F0462256EBEF1F225E2A90CE992 +:108EB0006548AF4FC9F6AB22DD72E0EB4A81AFFEE9 +:108EC000F989A604C3C7DA66B05E73B4936360A67B +:108ED00073E069B568678FA794B27A39FA076811A9 +:108EE000EBC772D52F14BE9B4E10BE9BFF42F0DD28 +:108EF00026F89D49287AF6CF4F129CDEFE72AD2FE0 +:108F0000B68807CB21256DF990BF4B21FE207BF859 +:108F100035BECEECEFDF073FF5B303250E1BA74DA3 +:108F2000C0D73F9FCBBFB5D3D4F46689E4910BCEB5 +:108F300087517EB1769224F0A1F502F25FD1070A43 +:108F4000C05884CF844404605D7583369CFC015D09 +:108F5000F9539FCD775543F9EEE36C18842B14CE6B +:108F60008DA7EF0FCAD1CBACD7583F5A90BD3F1D4C +:108F7000FB2D8D55CC069C1DFDF8C577907CF271BC +:108F80005CB7C758BDD942CECAD43FC911A8009218 +:108F9000F7B2A84FE3B0FA01362D733A7BE2FB1A21 +:108FA000318E34B45F6FBB0128E1F811F0D8725DE7 +:108FB0008627A89F41789404E1CBFBDECFDEEBE16E +:108FC000937F7FB265BF9167BC1E89F869A4F6AF35 +:108FD000087E19C29F79E8BA5FAC33057A4D383DF7 +:108FE000CB47367F9D281F9D349FB0E1495FE4E168 +:108FF000130B52B46E5835AB7BDAE8F925079F6442 +:109000009CF5174B63F83C9438F10B834721BED590 +:10901000393C65D34BA93F09D7F819D88328231EBB +:10902000D87C97D9ED214EEB3584768EA33D9B1CE1 +:10903000C12BC99290FBBCDE0D629DCF6BA8E0F006 +:1090400083E8DF032FEB4F73F627438587CF39DCA7 +:109050001B242EDF58FD0CE1D33BBE2211BC322471 +:109060002C1F6BB7598CEF955FF673BBE86FBD048F +:109070004DBD61BE9E9638F4618324E484C6D799C1 +:10908000573EF991AF669C385F152AD7174BB9F553 +:109090000EB38A621746F2EB9D629FAD0F323141EB +:1090A000B751D1FD74A9C445F742E15D7682F04E17 +:1090B0001C0A6F417C76A6E41B959EBCE104E10B83 +:1090C0007AE03B557C3D43F059A1F0DBEB60B4F016 +:1090D000CB43F15BD03A9A3B4AF8369F207ECB7C5B +:1090E000B69D24E0CBB36EE7097A5BC0F9436176A5 +:1090F00038EE730A85EFD191E103F804FB6BBD6A8A +:10910000990AD96B0013009E6E79D5B2942C7C26F7 +:1091100070B93EDAF1F78C4C3F31FE5B96599D1DDC +:10912000FFF996B75CE32B8C7F90D90A1DF7854237 +:10913000E70DEFB9E6FDBAF49E6BDC13C5FBC18207 +:10914000C7FFA36BDEEF4B7F74CF3BCCE67D7AE1AC +:10915000E3FEFE04F9B152AC97064977E9817CF64B +:10916000FB0C41D7BBEDFA36BC79EA9F29E06A2FA8 +:10917000B0FE44D1FFE70AACDF2BFAEFC5FA652356 +:10918000D73F5DD44F15585FF2F175984F7FCE975A +:109190006CFC816BFFD1A6713F88D9A640F09CA1E1 +:1091A0007E13AB21F5ED3E467BAB35A0B79592DF44 +:1091B00084FC226B0012E837F92624EB7CAC1F6399 +:1091C000C74DF761BD238AA677EBC01724FB1E3C71 +:1091D00010D9DC5D991D6FB59C6C929097DAA2FA5C +:1091E00083E45F493549EC59668575F4DB0C5425F9 +:1091F0005A9696E23C0CDD62FDFCFA8A8B76627927 +:109200009326E9322BFFCB39736FFB0C6B35F0E102 +:10921000CE974EC37AD3C655B592BC3425C44F6998 +:109220005C35E5287B5E7C71561FE03F8B1D6566D3 +:10923000077CB6E9122EFFC5F7CF27DDE54B1A2FC5 +:1092400071B5BF34E1FE9E9D0FF07DC7B9DCFF30E4 +:109250005095FA2F0ED7C72A2DEE5FA0F9EA565483 +:10926000EF66F35CFFE1B5545EDF52ABB7B2F2E7F5 +:10927000AEF4B72C65CFB004BACC9652715CA5F9A8 +:10928000029BAF5AC7768FE73CDB35DBC8BFFF2AAE +:10929000363DF38C5F9C8593CDB3E9EADC70ABFA85 +:1092A000FB13DE60F6D2C0CEA089F084F7CAE9A035 +:1092B0004474DD3909E9621527397D40AA66CF2358 +:1092C0008D3AA07FA4A13169C8ACBC31A6C5030604 +:1092D000DAC9190DF11E411ACC65EFE3BE20DA633D +:1092E000AAFE07EA5F17DF7BE255E3D13FF2E3E630 +:1092F000351315B6DE77345BF47CB4B98B9EDB9BFB +:109300007B262ACC88DFD27C173DEDF9A12431ECF5 +:10931000F9C9B8AF365B91DF06FCCC34423CCEF7DE +:10932000D1FE7603CA113FCAE1745B14DFD7C1B422 +:109330006E40B9C4E5CBC6F8B6DDF87E633D4C435C +:10934000926D3437B745D93CAE2B87E9D8F7CE9725 +:109350001FE3DF2B607A8095773536905CED89FBD3 +:10936000D2814A82FF7CE4E79E461F3093078AEB56 +:10937000185C0EBC0662EEF2AE4626B066123ED215 +:1093800001293B7F852D33C4C746B32AE8DC57CF7C +:10939000DAE76E7F66DA5DDE88ED87F14BCDED733F +:1093A000D79FF392BBCC24DB2B837CC0F1F8AF3E7C +:1093B000260F76BF3CDE67E1BC4D3E4FF6E4FEC2B1 +:1093C000982F8DC6E716813F1BBF03112E5F3636DF +:1093D000733F603E78367EEAAAD8707E03B5B1232B +:1093E00081FE54B5B1270167E1332D9EBD09A79FCA +:1093F000D57EBE88C68FC35FD211DB58B2B4360BA0 +:109400008FB7FE785925793750C6BF77C45ED3979A +:10941000D63AFB93BCDFB5CBC3CEEFDCAF32506E98 +:109420007F3FA22D0DE7683F897DCF4197A532FF91 +:10943000FEF4CB81863B901F057E77BFFC13AD1AEF +:10944000F1FDBC0CC8671BF73590BC453E4379B1B4 +:109450008BF1455F2DD27FFD2BCE755B5CE72E3304 +:10946000BEE2FCC5FAC5A17E86F4601DFEBBF0CB52 +:10947000EE157ED93DCD317A3EDD6CD07357730D3C +:109480007DCF34C7A9FC54731D959F6836A9FCE3B2 +:10949000E6462AEF684E50F9D1E6267A6E6F4ED234 +:1094A000734BF315F464FC4BFCBCA13925FCC06B79 +:1094B0005CFCF0F7F1808BFF3E5DE32E9F6F9C918B +:1094C0005DD7ECEF2763EEF279FA275DE5059ABBED +:1094D0003C1FBEE2EAEFDC0FBEEC2ACFEBEF70D50B +:1094E0003FFB4D77796EDF439EF5E22ECFDAB7C7AB +:1094F000B31EDDE5E2BA43AEFE023177F97E1432E7 +:109500005C4E117F74C45A4B72F2CFE0F78DA12FDD +:10951000B9BECBD47E64FE59D65589FC93F6C52DD1 +:10952000943B26E7275BEE78F9C4A6DB48FC65C3CD +:10953000F197E6ABFFE5A7E1F9A9607EA85772F2C3 +:109540008397EE5EFE18226704BFFC2F1FFC6DF0B0 +:1095500001CC64C42ECFAF5773D877649F061240F6 +:10956000F69D1FED34477B75722A69E6D09F57F947 +:10957000E66F95593F8152E8C0786840C9E3E795A6 +:10958000F93E25A0F1EFC16A93ECB26230A6CB633D +:1095900000AE796C5EF932F6FEE7421F765C089603 +:1095A000C4FA1B37414DE23EA6B8DABDDF7B46E682 +:1095B000FB18FBB9E9879126FC0EA5334798378F36 +:1095C000D7C8136737FDC660CF0B666F59CBDE86F1 +:1095D000AA9319F2019596927D9A0C19D4AF5997D6 +:1095E000B67CA518478338DA8972D884241B67AE05 +:1095F000CFFC05CE9BD947FF21CFCADA3D9BC4F3F0 +:1096000047621D5EE4337F29EA3D3F5C3D7BDC1110 +:10961000E905494BE2FEA9F8830C447F69DC653F0C +:10962000D9F353948499C8616FFC4EE04BD2E34D5B +:10963000DC0FA202CA877CF50FCAB6FFC972ED071C +:109640008BA13F23231C311E6F82631719174E1DF8 +:109650000A87AA2492380EC6AB37B371DAC77CC624 +:10966000483AC6F948E67E2A2966123CAACEE1515C +:1096700095B899C8C14703021EBB1F3B6E26C5FAA9 +:10968000A12F9C856F6D30D184FB256B8C4A786A45 +:109690008FB8EDAF190AEFA75A3CDBFDB9ED438057 +:1096A00056BE1F1E57A761FF6D750D1ADAD78C1DA8 +:1096B00068BFD21E5E523C9CBDBD5ED8BFDD280F88 +:1096C00003180FD785BC8AD1B33DBCAD11D7C1D12A +:1096D0005A8687CAFCFD44E2EEB86E514DC813C7E6 +:1096E0004D139C41A3C413EF9DE06AE71FA7F8EC5C +:1096F000B8364823C3DF21E0B7EB752A294DCF895F +:10970000273EBE5D0EC4DCF0FEF9F0C7DB17F97B27 +:10971000F55C709D2ABCE58BC3DA4F75AC9A4A7331 +:109720007F4ACCB90E3E2BF84B1DABA5483E69F9DC +:10973000BE8778FB7082FC5B5A38614055361EABA1 +:10974000E17A70E0E95AD1EED78A4FACCB540CFDE8 +:109750005C92916A427ED22AD83A9286B6B39F49E9 +:10976000D1BEF3C3FFF712AD93328DD68964B075C5 +:1097700094631C4931AF56D8F31DD9BC46C1F8CC0F +:10978000477232D77A5921E0D116270CAD8A427838 +:109790003CDFC303C73A85EB834336FC568AFC564D +:1097A00085C2BFA640F8ED7118FCED02FEB5C3C13D +:1097B000DF26E02901A3857C990697B300171ACE0E +:1097C000BC8B37C4F825424E314C11DDECEFFF2540 +:1097D000FA29743E1B059C23CDE78D2C3DEEC579FF +:1097E000B0F9DC87F3CA379F7B041C6F285CCF6815 +:1097F000898411AB22559F93AF9E1070F42B228E5B +:10980000665D3B2ABEFAD702E7F144962E8F09BA6D +:10981000EC186E1E8F8A79F4C830F70DF4339E2E43 +:10982000F40E2C71D1E5A8C04F4FC0A6CB752EBA4F +:10983000FC4ECCABD0F93C53209F1DCDD2E5393145 +:109840009FFDC3CDC751FF4551FF25519FFCE74701 +:10985000952B5AAD5AFC9E38A0CCCA8EC7EABDECF7 +:10986000AC776DFB2CBBDEABC80F5223D783ACDECD +:109870006BCE7A605DD08AF6DB5A8C897E02E081FD +:10988000F6AF3688766F52BBC583FDBF25D607B5C8 +:109890005BD73EBFD50A53BD77F07DCB828FEC7A84 +:1098A000EFBAE15D61C37184E04D0CC2F1BEB3DE7D +:1098B00013CAE7A9BF217947B19282EC1F7F699251 +:1098C000F2F74A20D283FEC50E2545FE640C36A071 +:1098D0001F7275204EA92A23F9A3CB2EE6ED7445FD +:1098E000237F6A005270177BBFA154A1F8C862257C +:1098F00019F1A31D21252D0AAE827E590BF63FD604 +:10990000A0FC2F1B9EDB8ABED845FD3078B0DF3B24 +:109910008BA23B91AF364E520DE4AB9D936E20BFB0 +:10992000F96D2D3C7FF0B6F355DA676D7A3942FA5E +:1099300077AD12FF2CD6B74CD5403FFAEAD0472F6F +:109940002D67E5BE96625D3A87E641705B3E48B49E +:10995000CD74E42332B80371CAA7233FDC6D8D3C7C +:10996000AEC37ECAB1FDEA0546BCDB40F1C5E418D2 +:10997000FBDE59A792FD7A5B45D57C1C6F539D4653 +:10998000F6C6A6C5552DE4C7AB0B91BFB2246C48F3 +:10999000E8678FCE519901CECAA5460BDA9B91D9C3 +:1099A0002140BF5349051F2F7206901FCA0F3D89E2 +:1099B0006AF68C76A990198BFD2DC97C09ED99BAB0 +:1099C00000F9E1D9C4F6D78EA39437FE23FF0C101B +:1099D0001EFF441910EF367DA33D83ED87CD638CC8 +:1099E000A60BAC9729AC5EA44B81CC8C02EAF51493 +:1099F000582F5D60BD0CAF17800B87CDE78338CF44 +:109A000023D4D81F9EC7E8C82BACE4F6BBD36EF1B5 +:109A10007BBE8F362FF42ABFC80B9D0373785EE898 +:109A2000F0EDED7CD091E60BE0CBC2298F5C7F6D31 +:109A3000F3F07E63FFB81B62987FD959F655F1BCED +:109A4000913FCBC5FBF2353194779DE5E27BF98DF3 +:109A50004DB9F6AF77FAB91CAE81C4B0742811F0D5 +:109A60001F62B0637E4F8DC2EA47F2D7574B7DC36A +:109A7000E6596A8AD540EB76B18FD66D008501AE86 +:109A80009B0ABE8EFD904A54F37855B4DCB17EFC3F +:109A9000F57B68FDFCA25C06A98EE813473C7AF9C9 +:109AA000C4CB170170942B4F9E4FB6FE99F8C4DFBC +:109AB0002517B47EFC3D05D64B17582F53583DB59E +:109AC0004B2A48AEA83D05D64B17582FC3EBAD9D8A +:109AD000AB727D0E7F68C578BFFF139AABBCF613DF +:109AE00021F7F7B3C3AE72C72C777B75B6BB7DC7C2 +:109AF0006C777B750E6F1FEC800518CF2F749D1C43 +:109B00003CC17552A30D5F3F5237C2BAD2F420B6A2 +:109B10002F510CC89492BE4A0BBD95331E7E9ACA33 +:109B2000D77F959FC7CF6F53F420EE23FFD6E72949 +:109B3000A93C9FC09EEF48F0DAF2F7B7B2B0B7F297 +:109B4000E47D438C9F7FF043288E768EB1506B78F6 +:109B500085E1D1FF2CCF7BF7F6FB8A9A9CA63AF6DB +:109B6000C5CC3E83A4C30F737E99C2F36D181DD07C +:109B70001E5221D158C9FA6BABF0913DA28447D057 +:109B80001B150EB995232F2FEB970213CF53D02718 +:109B90000360FE9B7CDC501C08EE08F4D166BA180A +:109BA00053E54E07180386C493BEE212CF13ACD719 +:109BB000519E95064F75BF9751BF92791B1C2F1A66 +:109BC00045BF4A1FE5CB9CF27E478037087753BFDD +:109BD0006C97547A7C6CB65F7F2C452F314F56764C +:109BE000E4CBE1B908CA37F1C53394DF30214AFB31 +:109BF000B2B5A5D7B9F2C1FF59AD72F98754BDE32B +:109C00005A09E3BA15579B7DC3F079331357E4F72C +:109C1000AC586EF6D5E4AF3798A78FF99E39D64188 +:109C2000879A4CA3FD6E4D0EF3FDBC92227F63A775 +:109C300054321DF32DEC7A4A0593B40CAEC84CD3C4 +:109C4000C2FD5EE7585F1CED5405D6EF93CE62ED82 +:109C5000E4C571A7FFD2FB542A94B79DF3B95D65A3 +:109C60007A12E1147AB26D047E1FD1EE51E3C95C21 +:109C70007ED16FAB7C5FEB0FE5FEDE176A78409D0F +:109C800035146F8F217E717F3B06BAA4FFC3D9873D +:109C9000F2A52AF6BC8478585BB62836DC7CD90657 +:109CA000EAF0205D18897F16321F4179300C1C3F85 +:109CB000CC0507840BF37FEB0BE3C48783F65229B3 +:109CC00088FD98199518DF870457DE32737306CF25 +:109CD00043F897864DA49F6C6E01F457DB76936C26 +:109CE000865EF5113DEBB9FD54C3ED2193FDC179BD +:109CF00044EB87B7AB654FF939D56D0FB535EF003C +:109D0000679E9BF75C85FD4C871A5ECC8D8FC2F6F3 +:109D1000C3B7337EC13CFB8DCD1A22057A9A752AD2 +:109D20006F688E51797DB341CFF6E61A7ADE8C4D9D +:109D3000E7E2F9A7545725C35B57EC81D8E5ACCAD5 +:109D4000ED283B288FEFDE05682F770F96D93690E8 +:109D5000C1DD3D09785E9F7AEB02DCE7770741F8C9 +:109D600015DA16A05D9D2DDFD1361FCBC2CF10EACC +:109D7000BC6F01EEF76F17F90FA098DA250EBD77CB +:109D80005AC04FFC477B576A6FB5617F414594E1EC +:109D90009105EE3298084F50E3E505816DD43F8977 +:109DA0000036DEA7033FE0E34D11F96DB54B46C029 +:109DB00023F7EF5BAAC1FD5DB525143F52E3717433 +:109DC000BFC2ED6304DC05F6034A92EB3B718E2FB4 +:109DD000FFBA1941AF093846A23F4307F9D1EDF365 +:109DE00069CA0BB9F5F4A91EF776FFE8F0A2D6F51B +:109DF0005B7886ED09353927C0DA47CCDE4C252B58 +:109E00004717672C5ABE058E3B3660E7392669FD39 +:109E1000DB7856746E77ACF0D0D15FCAE3754171D0 +:109E2000FEA4507893AA1847F4030F37940F67AF36 +:109E300095257C68840DCA8BB18D21E19CE1E531CB +:109E40006689AB5C5C37C1553F12AF727DF7EB1F83 +:109E5000777D3F513A5DE299C7A784DD6897CFF5DA +:109E6000CEB3C07E0F1627560570DD34404D8AE113 +:109E7000F5CE2F3C44F80F0DAED385ED6605E58396 +:109E80008B753D8F9775FB7B5DBB59CFCA86FD7D7A +:109E9000062F9BF6F738AF6FD9DFA7F2EF28F759F7 +:109EA000F96B9D67B45BF81D5AC96F0B152958E211 +:109EB000A0CFD8F10DAD08DFF8CBD2318BBDEFFECE +:109EC00050E6F2007A62CE7A776ADC0FFDCC943BE2 +:109ED00062E8AF5C77E64331207927E58C07FE3CEA +:109EE000C0F3C5CA42899E00AD77B3BF98F1E1A126 +:109EF000876483EB21E535D4873E8BE7E3AB10DF46 +:109F000067A25D54C3FDD521F19DE85899AD3F4846 +:109F1000574FF9EF34AED77F87491B0CCEEF159B17 +:109F2000F7D0B890961AD97AAFB0A01FCF1F81B0E2 +:109F3000FB26F2A6509A48939F6F12C3A7CCBE4F40 +:109F4000BEB8BFC5CF706D5CA6FB7089542D8FFB6A +:109F500048C00DDA9163A5E3ECF93DA417CAE39B71 +:109F60005280FA7BED990F35215E02997F0283E1E1 +:109F7000ED1F27A5C040FF6F80C315B8AC07483E52 +:109F800057F7109EBDF85A3788F7B40BEF3F0970AA +:109F90007F7E2CC9DB0DD65358BDA943EB75077BDB +:109FA000E6AB68BF4DE178F48EF35E4012E776DDF4 +:109FB00070D8FD7AEBDF1210716D2D4DF18D67CEEB +:109FC000BC21867EEDCE298CFEB5F9E97F4B80E77A +:109FD0005B19C76E22B9DB3D6923C533D7556F26A0 +:109FE0007BF228B323F0FC747765EEF69DCD3C3F01 +:109FF000E65CB8BBB18AD1A7F37999FCB4DE7ADF0D +:10A000000954B9E28D5A857B3FC8F8AF0FE5E8489F +:10A01000FC27471EE0EB72947C8766213FCF50D629 +:10A020008EF6805F94EF0E1C6F13FA9FE47FF9F2B7 +:10A030001E70E64BBE2FF82213E0722658C1F9A31A +:10A04000DB6F494EFAC5D8FBF98E76F9E8968F1F7B +:10A050001E17EBE17D25DE44CA5F49E9B9E4B3127E +:10A06000FBF42F173ACE7BB52B694D47F86B364A78 +:10A070004EBBF61B6632A439F627A1D805BF5C8813 +:10A08000FB1F259E739FFE29D38C6A6CFC9B9B61F2 +:10A0900046359E4B50AC00D6BB59C934D2BEA2DA6D +:10A0A00047FEF27515D7EDC53C2BABD617C76A6DC9 +:10A0B00015BB1AAB0CE4976D9467FAA6BE2486FD17 +:10A0C0000462EA8CEAB194DF9DC079876B59BF0EB8 +:10A0D0007ADBE3DE2DF8F65BBA3959E3F2E034EDD2 +:10A0E0002F200FDE87788C1B590CCF39F65743F1A0 +:10A0F000CCF3043A2B86E0798EE6E0EB00E27906B9 +:10A10000C9FB9CFE0B86E7B35D780686E7A9593C40 +:10A110007757703C77D66CEEAA72E2B966D7DE4A02 +:10A1200003C7E7787E48E3E773438867079C5E3C94 +:10A1300087255BFF7CAC1DF9D6CBF70CEF7F8FF04A +:10A14000D8EF3F0AFC82ECE1B1E313176AE43F4920 +:10A15000D1FEE94E29AF5EBA442B402F758A757443 +:10A16000A7C03FEBFF0BD47FA9E8DFD6B7421FFEA5 +:10A1700083F66F0B501FB27ACBA89E9EA27DF06033 +:10A180003D0B86D5A3ACDD95C447614FFF268C4AB5 +:10A190001FB37EAEA37E34CFF8069C949E67FDDE8F +:10A1A00044FD2A9E7E4FB13DC1C6E926FC81070FC2 +:10A1B0007F663B2696F4F083D2E3927B363F942F62 +:10A1C00077D7CBAFD77AB85E1B6AD710DFFEBC73E8 +:10A1D000CF6EDC27BDA99BDF46BC8E761DD876608E +:10A1E0005928B94DE376209D83B0BE51946E636DBE +:10A1F00095E33D511E7F77EBA3F1B63D54CDF5407D +:10A2000070947A699FB0D73AC6301955CC9EFE44F7 +:10A21000532E3FC3339A9DB7E6B69B7F8373243F8B +:10A220005182FC6BEDB1CFECE863B4331B7B20971C +:10A230009C4F86923FC7F9A9BA65927A15FE917C28 +:10A24000FD9626AC9D7B6792DCEDC7BC461072186C +:10A250004D6BF4C74519DE0E69E4C288A37FADECEF +:10A26000626B3ECAB10AC62F587F5CD33E29992B38 +:10A270003E6EEF7F10881CFB97719F9B9DA47CB85E +:10A28000C53347D8DFB4D8F6EB6F715E87D49E0B29 +:10A29000A638F06ED3E90E2971E179284FE7713ABB +:10A2A000158F924E03824EB098E7A19E7BEC5C8D99 +:10A2B000FC8B115F02FDF0417F8F5EE2E0A3713EF7 +:10A2C00048F68E02FE7AE8DF7D1CF77F611FED778E +:10A2D000BBC3CBBE83F7EF58BA1A9F6264C7ED6663 +:10A2E000FABEC4A17FBCFEAAC17DF4E2C2F265A79A +:10A2F000587328DE9FBD3FC89D7FC018AB06F3860C +:10A3000056CBDC7F7E67D1D7280F618D15D003A592 +:10A31000A4C7C8FE5B27F2D93A453EDB5A91CFE687 +:10A32000B7566FC5FA9B0012E8976C9997A2787F91 +:10A3300054D1F4D638C2919A837A225A6AAFCF1F89 +:10A340002FC4F53958B6BED1DEC0E61B8DD9E58DD8 +:10A3500064BFB5B77079F3D9E00B0BAD7A64C53E35 +:10A36000A2C7A6BA25C5308C3F325CEBCE9F0B55F9 +:10A37000875C65ADA2C455564B270C1BB7F819FA7C +:10A380008966E17CFA208E70E6C9179E12E476B6E3 +:10A390002C4FEBCF60BEC1D96A7CB381E7A8DD79D1 +:10A3A0009CED416E0F3E8A0E218AE30ABEA8E3713E +:10A3B000D5A2B955BD180782319C2F304FD0C90F97 +:10A3C000F9F8E2AF8D1F5FD1E118E65DDCD21A0526 +:10A3D000CC73B965EEAFE21903E56A5F0CF333DACB +:10A3E00098246965DF37CCFD9591CB9F7C404B2E3F +:10A3F0000F22FEC209B2BF223393F4FC6BCF6B2451 +:10A400007ADE19E47A6E8AA0A782F49C99A5E7BA4D +:10A410003A46CF99D975BE4EE9D10AA1E7F9387EFF +:10A4200019CAA1FFA67DDBCD75BE46944306F45242 +:10A43000FEED865A9F0FFBFF6BE1C5862B3C97C94B +:10A4400047A25326817A61435CF1A11CF99BE3C3C7 +:10A450008FFAE87D017CF8C35C7CB85CD0432EDACF +:10A46000D7942BEF6E4A5072E1653DD28BE3A591F4 +:10A47000E3C5F757C1CBA0BED0922B916FAE88A990 +:10A48000B4EF564ABA3A285EC4F41EC61B56C8A694 +:10A4900081F126F8969FDFC7847ADBA15FFE180C56 +:10A4A00072FB445EBF88E2186C6AB82F63E58F0DBB +:10A4B0001B0F4DFBFB9DF79478F3325E0BBAE31054 +:10A4C000472A961423BDF2F5F776F35E1DCFD5DA51 +:10A4D000F919DEEF2B6448E53AB72885346167F651 +:10A4E000AA84871B99AE9D86F8F8D8423C9FD9591B +:10A4F000D13A8EEC1871AE61C5966775C501E70A51 +:10A5000085A9BFE943E763E37705AAC91247FBF4CE +:10A510005E577B6FBBC1FE447B66B7F9430C3E536D +:10A5200049EDC578B37D7E43DD323F436A330FDCAE +:10A530008C8E270577A1E7388E3CD0D681FB6DB491 +:10A54000BF3EC1F8E4B78FC8F156F6F58ABBCF58C5 +:10A5500088E75A0F01E7179B3E6F3DD0362E175FF5 +:10A56000E4A3CF79A12087E714F3D759210F7FF512 +:10A570005E549C8153CF5F8BF3F197C0CFE15E8E29 +:10A580000FB86B6C4E3AE59BCF209DEC7682CFBC2A +:10A59000EDF3B5637C95E07C95899E5D085F097855 +:10A5A0006DFA9D2CBC23F155608D6CE079AE4A2587 +:10A5B0004172B3B3F43A4BDCEB48F99E72CFB48CE2 +:10A5C000B8D74AE4B54306ED8940A949767448DC1A +:10A5D000CFA355BBE5A612739F9B8835253276BF66 +:10A5E000E8BF0CAC5169DCC1F8711832C12896790A +:10A5F0009C14C51FEE2B02F04DF27BB27639FD9E06 +:10A60000F65311F96A98CB4BF7B2C1E747C86F719F +:10A610008F13BB78F8FC1A6F7D082BC62107DEF379 +:10A62000B753E090639FB341DC2B6AE3DFDCB29465 +:10A63000F2CA83E08BD3FE20D661E1BEAF43ACE724 +:10A640004E7CCEC573BCD375DAAF55F0788B257DC3 +:10A6500099FC0CF6B9337B3CFBBC995D6F24FAAFD7 +:10A66000C6F594637DEF0A717D3AF0B5D47FE33E81 +:10A67000C4FA1318780FC5E3CD1F509CFA9CCC5B2D +:10A6800032FAF79F098DA37ECEE9EF931738D6E50E +:10A6900039E21C0740AF9CEB9C97DF0AEC427E78C6 +:10A6A000EA30DF8F3D75F808D9E14FFDDE9746BEF1 +:10A6B0007BEA83E1F31E1E17FB22BBDEE3BFE7F656 +:10A6C000D9E34A6F512EFB2E3B7E9AEF070FBBF961 +:10A6D00015945E19F965E0A67D32FA071E6FD6A4BF +:10A6E000D799FC9927E679CEE13E19F74D23CD6B3A +:10A6F000AB87BEF63CB7D6737B746BFD9110FAFF47 +:10A70000B73EC1E77BB49E9F8FCD07EFAE669EDF5D +:10A71000B1F589DCF86898C7F7C70D7EA334A75D4B +:10A72000EB3967B54093DDE7BB4E317CBBEBB9DD60 +:10A73000B55B89874F049EBCEBBBAEA711DD08510A +:10A740004836CE9708BDFB5D7E92035F6FF932E617 +:10A750006B2C0D9B12EE65A12FF3249B5789A92525 +:10A76000F0DE98E2FA1E6932E677C4781EF937AF58 +:10A770007E2DF3322BDFDC5444655D379E5B84F81D +:10A7800028D5C99F72337A5C48407F732DE627D065 +:10A790007A64E5C0CD3DE7A13F4B012E2F98C56BF4 +:10A7A00028E3E85E3F72D2E4931BEC473A1EC8B63A +:10A7B000CB3B4F4FDE6D00960C2FC796F3FA16FB7E +:10A7C0008372A8C49367A22F74E7A5443DFD4F454B +:10A7D0005BB5AC80BCF2931C670C6CD30CDC67D708 +:10A7E000FAF434D607630CE60D861B9981C4E83968 +:10A7F000460709CDE591F0BE0EA091FBBF33E03CCA +:10A80000A7D350C4E5D584AB6E97709F7134CEB892 +:10A81000621A96DFCC997FD52EE4C76059DF45F2E6 +:10A82000B4037AF7525C20E9233BFCE6DAD631CE5A +:10A83000F64B8B24DB1F28E80F86323B4B7F363FDD +:10A840003378D65F8EFEB1E56EBC8F962ED714712D +:10A85000793512FD4F761C9B6E43D7478BA0DB03E7 +:10A860001417EDAE195EEE0FA5DB36D277E1DADC18 +:10A87000F9BAD715492E796C3F3548419CF1892C9E +:10A88000EE6796C7CF6EBA7F18F9233BEF67866CE9 +:10A890003FE38C1E13E356E3A1C7C473DF8CA7E329 +:10A8A0001940FE3601ED24661E111FC99EFDDC46CF +:10A8B000C14741789EDAB35560E9A45752A03BF2F4 +:10A8C00054CE93C371F45FACD3C3742F12CA4F9E9E +:10A8D000BFC3F3FC8B39480CBFFD80F22D542E838F +:10A8E000857EBF7A01AFC4F80EF3FB0FBC7500F78D +:10A8F0002BE1996E3A29078A28AF2DE43D2772E0B3 +:10A900009A6B687FE3A1E368F3FEBF5F24ECFF224C +:10A910000893DD24DAE7CBDFB3ED7E1BBFC6B108B9 +:10A92000E5ED741C90081F659313F7E3FE0C7E257C +:10A9300003CFCB0413F3F656FF74167D1F1A574846 +:10A9400054225DDE3A50A4B75616922F9948B6B0FD +:10A95000FAC68140BCD520D5E2D3908E7D12D1516C +:10A960001AA751BED6EA7FF7DF1F18265FCB8E3FAE +:10A970000E96158BE29B5DC674CD294FCA42C95F06 +:10A980001639E3F622AEEBF5AF07C3EDB16760F41D +:10A99000F18FD2F120E2F29F5F84F64B17AE019E59 +:10A9A0001747797A5DE5BCFC46D1944518DFE98A02 +:10A9B000F07271F8C8792D246713E4FF5BC3180E99 +:10A9C000F1087BFDE21E4963FC85C3C80BEFFCD791 +:10A9D0002BFB284FFE9EF0FEF3CF40FAC47DE48FA0 +:10A9E000BBE7FA6DAEFB93DED41BDE2FA2F5AAB750 +:10A9F000637C7A62D2CED774C74526A0D660F39B1B +:10AA0000C408E3677838ED626845B6A9BCACB71CEA +:10AA1000F7C96B4BB78DE1E7FD17EA87C86E972939 +:10AA20003E9D0F5EAF9D9E6FBE76BCDDDBFEAE0829 +:10AA3000BF47D51B17F3FA831E44FC9651FE2C60CA +:10AA4000FE6CA7BF2F673CEA8D22EED76CAF5894FF +:10AA5000B81CE7A598730F327CDC5B1AA57D90FFCC +:10AA6000A2DA4B7D0E7BC3CE6753C47ECE5F9A22A3 +:10AA7000B9A86866D719182F7A5EC61505153D3B2B +:10AA800025B4E7EDFB2010AD174FE5F3C579058040 +:10AA9000DBC5785EE1B863DE1073F8C1509E88FDB7 +:10AAA000DB29A0F7B4F0ACA1F49DDFC5F3D0635768 +:10AAB000F0F34D1395DCF41E7F99EEE3F1AF534BA9 +:10AAC000E77CEDF3C53DEF8AA8B47EA6E8ABF7E2DC +:10AAD0003D771D567112E33103FE5417CAAB0DFFCB +:10AAE000E883CD34FFD1E937454FD03D7A15297D34 +:10AAF0003A2EEF7CEDEE48ED0A129E2D9ECFE0FD42 +:10AB00007E7998EB9B9E94EF36FC6E3E9DDAE9C70A +:10AB10007D678CEFABED7D783294BC3CECB0CF75AB +:10AB2000D3223E9A92BC94E4C0405961F72F0CE2C4 +:10AB30002B4F1EF31D11AE97A718AB79BF9386F765 +:10AB4000CBDA78F9A04B16BF1721134438FC8C914F +:10AB500013B82E6EE472E2EE35BBE8BD7263DF7CA3 +:10AB6000FEBDBF05F5EA1D3EB82297DFA82DC2E362 +:10AB70004193CDCC3AD41B93533E40FBF4F688412D +:10AB8000EFC75FC6F1D43509E238EC69D81FFBCFB7 +:10AB90009E4A95F4D2D852A0FB92C6AE01D2DB6396 +:10ABA0006B206DB072D7CEB93BD1BE55AB218EAE06 +:10ABB000EBDD953758680F6CAA0013F5B8FF46B661 +:10ABC000C0587DD5F0A53150BC29B58CEE6959CB64 +:10ABD000D6255263ADD140F6C3D1182F072AF839D4 +:10ABE00098AE331582C3BE7F9CEC4EA61FFCB5FD0C +:10ABF000265EFD65C015D48F7F2EA7AB71573D9D96 +:10AC000053EB1AF310DD4B635D033CDE69C7A515FA +:10AC1000C65F6C9CF62BF49CFE9523A1E4B79DFCCB +:10AC2000C0F891E44C17E613E4C0676798E3F30EAD +:10AC300021E706FCF0298A97B4F8E83E176FFD6516 +:10AC400002FF775B4BFEE10C23AB6FECEF078B0C45 +:10AC5000977FA3E20395E6B348BE1174A43BB39378 +:10AC6000E8FE17BC18F4745A9617943BCEB3DC1B5D +:10AC7000EF85C98867DB2EAAE5F68C7DEE91E12190 +:10AC8000730FFBAED705E87ED1F14DB9ED23B5408A +:10AC9000FBA8ABC8FC6918F30D443EFFD7972F21E2 +:10ACA0007D9FEFDEDABB235CCEDF2559951D489FE3 +:10ACB00049FCFE196FBD83C25E64F620F1CD268B80 +:10ACC000DFBBB5896D7D1E45BEBA9EDFF3C7DEF3DF +:10ACD000730E06D079F1D80DCBB45CEBD51B57CEF3 +:10ACE000B7EE826A5F3257BCA556D0AD24AECFF71F +:10ACF000F1E983E9B0478B6A81EEFFD2197DD0F686 +:10AD0000AD805E4ABADFD858528971A15B6F540D8D +:10AD10007C7F5F65AFB510E72D41EF839823A3F4E7 +:10AD20009A781EBD223ECEE8769CF72EAE7894CE61 +:10AD3000C3DFFE54000275783FA9E7F7D938E9234D +:10AD400067E96CEBAB7CF32BF4790BC397F3F780DB +:10AD5000308833388F220B0CBA1FD9E8253BF4A872 +:10AD60001544DD0A467D2FD72BED2178308EF7CCA8 +:10AD7000F2F2A6F054C0FB6735A597EC754DAFA273 +:10AD8000725175A29BECF369DBF55CFAE153914AD1 +:10AD900097DF24E4895369C91B9AB89F56852939DE +:10ADA000D6D9C12285DBD3AC29C573ADE1E5EDC9A8 +:10ADB000F2C79B42DFE8D97D32F107C92E468F707A +:10ADC000C5A2B764C77D9C61EFF9622F3D3DE59355 +:10ADD000A5E73AA4A723BEA0D52735A49FC1EC249C +:10ADE000B2FBEB019CF7A66FD22C7E0F8361F82C8F +:10ADF000077ECB85DDA77CA0D079DBBB9676D0FE25 +:10AE0000632CEB03F37AD933E7BDD3078B785E78F5 +:10AE10005751624984F27281EE195E27E4C679F2D5 +:10AE2000CF8298871504A6E7908F16FBE0C11C74AB +:10AE30002D8F703CA743E6E722B3F2CFF77129F7D5 +:10AE40007DA276FB83C20F50B81CE6F39D620ED044 +:10AE500079D2819B0AD3DF036C6EFBD02E57E25C64 +:10AE60004FF719D03E93EE7F4AA3DEDD145B4278A4 +:10AE7000BF0FF529DA56B55C4FFA53DC4F0C864408 +:10AE8000F7CA86C4BD1BF7A58E3C8B76CFD11A05B9 +:10AE90003D3E10AC485AA85F8BABFB2C09F56C69A2 +:10AEA0009AE2C74C8F598867E3AE4504B75FE96DF6 +:10AEB000417D99562084FA7C008D4966C73D127EFB +:10AEC000A403F35DFCB5695064DCD70338EFF737B2 +:10AED000602FD9597EA687C96E52FA5A502EB5D71F +:10AEE000EB14D739EDC63E70EEEFD8B8B7E2B81321 +:10AEF0004AD97846567F7AED8D7C7606D3B3222FD9 +:10AF0000674107EEDF6829B1F2C3E1ED1D686F7E8E +:10AF10004B37BF4EFC93679FC1F8E29E48D9E8F9D2 +:10AF2000E2B9B09B2F06FD27C2EFBAAC4E087A30CB +:10AF30002EFD0D83FBCABD7EC0F99F7BECBE3DF7A5 +:10AF4000307CC8A84FC972E9D9F324FBBE1CFDB000 +:10AF5000AC7CE581A92ACABD5F4D90F1EC30F25975 +:10AF600014F9E71DF0917FE81DD81F9DE180676708 +:10AF700084AF13E8F2BFD6E7F03F5EDEC3CBB6FC8A +:10AF8000FBCA5DEEF29761C938B4BFBE7CBB1FD26D +:10AF900012FEDE29F7BEF99108CF37FF0AA43A1056 +:10AFA000CF6BC5F9A46B1E9BAAA2FD74E50CBD1264 +:10AFB000E39F361CCF0A3DFD36E363C3210FAF0A82 +:10AFC000A755CC977A7DFB8CCF9C0DD84FBA6302E6 +:10AFD000FA0FC7404E3DFEA52E379C23CDC30BB7BD +:10AFE0007DDE281F1CCA1629A71FECC588DB0F763B +:10AFF000B2F7B31F45FB7856F6F7D7D9796627DB4A +:10B00000EF9FF2F47B8D86175103AC527A1AA5AAF2 +:10B010006CDC2BE8B7CC8968FFED989FC1DC7547E5 +:10B02000BDAE02EB35FA86A937D27C5687EE8DA2EB +:10B03000BFA84F8244AEFB77CA42C931D15943EF12 +:10B04000E101F1FB820EBD62DF63DFBF08FD7C0121 +:10B0500060FB7B7A2AC407E4FF91D05EEDC9989526 +:10B06000183F565CFC5184F11466F7AE12F6655138 +:10B070008DFBBBD71F747A94AFEB7AE823FB3FAA12 +:10B080008533329E6BAD73E73FDD59F44592BB2BA0 +:10B09000F7F9C9CE5C09C6ADF533691D921FECFA0C +:10B0A00075A7539CF8FA32236EA15C83B8496D3DB5 +:10B0B0007CB7EA0309D20E3FC12AA55FC5F5B68A5F +:10B0C000E90FE7FBEB62B2F1468EDFDF643FFDA0E4 +:10B0D00019E11AC4838F9FA7D559D931CF233D5287 +:10B0E000238FCB19C5170FB37FBF2EA6D238CBD66F +:10B0F0004D29E6FE21B7DC7C57E8A99F3CFC2D9545 +:10B10000EEA3FAEEAB17201E563C2E83C6C67DF783 +:10B11000E10864487FA555D45F576D9773EA77CCF3 +:10B1200074A2BC94ADDC7F79D5B6407A316B7FD503 +:10B13000A3AF9F050CBE775BFBF74CC475F05DEECB +:10B140005704ABEFAC8BD8FBAB14F8BFB9ECA9CF6D +:10B1500047B9BD7DF847454DB8BEA52D3BBF48FD5D +:10B16000F65EEA0F38E2734BA2FC7C2CABC7FDA065 +:10B17000DF91D25372C4EF6CBFFBE1EF481CBE1DE0 +:10B18000FE7410E1DB72BF9A6470ACDAF21EC993F0 +:10B19000055BBF17453CACDAE18ED3ADD8FA610749 +:10B1A000E6A1AC90A17F31F2B37C8CCA474DAD5F74 +:10B1B00026B9CFCF57AF2492B07A3FF8EDA2DFB0D7 +:10B1C000EF6FC7640832D1FBF6BE83EAE3584E86C0 +:10B1D00053B8C35DB5C32DF7566D799DF222741F28 +:10B1E000F4579C8DF9016EBEF6D667EB4745FB69B7 +:10B1F00055EFBAF7D0AE5CB5FD9D5FA3FC58E59165 +:10B200009F6FE37FCA87FAA9DBA29EFB69B61496FB +:10B210003FB1E27B47EFB5D8B887B7FDEE5ECCB360 +:10B22000BFFAA3F7EFFD67B4179E0AEA28FF577D20 +:10B23000F7852838F8F11EB1FEDE9D045639ABF7CC +:10B24000EE7F06D278A0F5DD277F3B19CFC9BDFB85 +:10B25000C81FC719ACFEF54F9E47F7F25FFFC30545 +:10B26000E387B3AB905FD301275C69A2ABB143E244 +:10B27000C6CB13E2E9A1C7E1470654B477FF2041EA +:10B280003FEAB995BD1FAAB83FD963423FE267F7CD +:10B29000F6D7F77C9595DF61F409E4A00F9BFF4496 +:10B2A0001FE96F2626D973E5F6D71721BCABA09FFF +:10B2B000F4E9107A3ECFE839334B4FEFF7A3704CE7 +:10B2C000C57DC1AA8719FDCE423A32FA9D35947EDA +:10B2D000EFE07FE60EA5DFE351F7BD0947E1EAFBAA +:10B2E000CA7163BA7D6CCE3C886C9C61F87B506CF3 +:10B2F0007930127EAF90385C5D51F3A728EF0F6F65 +:10B300002B1AA4EF62A4EFF78E4E46E3ED4D7FFFBC +:10B3100017110FFD4F0674FCFD12573DF922ADB316 +:10B32000777FF89C6A505C07A2D26C5686C19FFD5D +:10B33000C0CA2BB90F1CAE79E0FF2FFA356B7F0D19 +:10B34000EB02F7998C6E54DEC3D61DD1217D61A32B +:10B35000817A335D46F35E99E6EB61657AE7C578FD +:10B360001F8517EFFE62FB3ED02C3DF1BE8395DBBF +:10B370005F5D847C978F9EF6FC759CFF1CF6FD013B +:10B38000F77AF5D65FC9D627E9292F7DD33B7F8190 +:10B39000CF77EF0F28783EE35D71AFAE97EE59FCA3 +:10B3A0008B73F3A38C431DF7F0C7601C4AE0293F61 +:10B3B0007FF0753ED2FC468BBF77A2868B8F6C3CAC +:10B3C0001E3E965BFE4F2CE6726325F434A2E9EC38 +:10B3D000B55714485A132BB3F01E46FB82C17BF8B5 +:10B3E000BB32F9853A7A77931CF7CA8B9590FBF7B5 +:10B3F0006FD516737B71E58E9D67A15C3BBCEB47F7 +:10B40000C49F2B1F7E55C57DC79E2D3F50FB6AB341 +:10B41000EB01F543DA81EFC3DFDF79169707B9FD5A +:10B420005E73C57C563DE1EE7FD5C3EFB9FA5F612F +:10B43000F592BD30D2386F2BE6A538DFB7F7F9E9C2 +:10B440001EC2B77BE5C65C76F0E462BFCB0EEE7839 +:10B450006ED16FF03CECCCFD21BA7F717BAB39FE35 +:10B4600016B4DFF6FB457CD1FC1DDAA5DB9F0B9102 +:10B470009F67FBFECF503E90DDDF631E7CCE79DE02 +:10B480005A1061FDCDE94BCC948DA172A3EE00DB87 +:10B49000EF39F8E0FAE71AC7A3DCC7FDB181BF5F57 +:10B4A0004E89D3392C39BA88F2CC65DDA70773EA07 +:10B4B0006FDE9F3FCCF7937EC698CEFBDCCF3DF688 +:10B4C0001FB47FEF88FB72E2E13E817FFBF73FD93B +:10B4D000EFD74B9C6FAC67793C24DFFADAD81C8B32 +:10B4E000573354DEDA5C17C7B8CFB5C5FCBE9EB182 +:10B4F0006F18129E2D99DB674CC7F917432FE0791F +:10B50000FFDB9BF5B8333E5476D86CC17A67BF0930 +:10B5100071AC87E3E27E6DB4E35AC5FCDCF3907155 +:10B520006B7B092F858CAB9DC0B8B79E8271C327FA +:10B53000806780CD058DEBCDB3F28EAF4EE379639E +:10B54000DEF192B63E10F1055A7AC3F8DBFCA29FF9 +:10B55000A5C586EBF7958192A17BABB3791769A955 +:10B560007326C6EF06CF1B2734C77963F69DCE1B23 +:10B57000B7993C0F96B5A375D025FC1318CF5CE6A0 +:10B5800080F705219F0215A918DA5F9D79E211AFB6 +:10B59000083EEF8C346838999DFAF4E2BE61F48677 +:10B5A000B2E69B339CE792153D23B9E2C8E6EB7403 +:10B5B0007F56BEF6DEF8A20D7FE7CE7F82AAA9985D +:10B5C000379B80D61C706E17EB07EB5562BD581287 +:10B5D0005A1CF5D4189FA75DEE147EA1576E7DA569 +:10B5E00093E2F679F0B443D0F30574CC97D1F64DDD +:10B5F000C3F86F57C44772B22B98FB1EFBFF2CF6A3 +:10B60000B9E4A48AE71FC90FBB8FF68DC6B1974D69 +:10B61000BC1FE9D65A95FC6091FAFD543E6AFAC8FF +:10B62000FACF871FFB3E83C1721EFF53BDCEE9BB1D +:10B63000DBDC46F9B1D74D558DE1F22D426BA6C545 +:10B64000316F425B73761CCF6B876AF8EF61D8303D +:10B650000FE26106DF863CFCF13F58523CAB0080B4 +:10B66000000000001F8B080000000000000BED7DB3 +:10B670000B5C54D79DF0B93377EE3C813B30C0F082 +:10B68000BE8310D1623A28A2363E2E0F0D3E62468E +:10B69000C4A809D6D13C4A2218B436A11B1B2E02DD +:10B6A00082F8C2266BCDAE4D47A22D6DD31653DA6C +:10B6B000358FF61B4C74ED635B626CE2F6D30613B8 +:10B6C00037AB59D365B7CDD6ED9736DFF9FFCFBD90 +:10B6D000CCBDC30C68DAF4B7FB7D4B7EC9C9B9E7B2 +:10B6E000F53FFFF37F9FC77C4AE4089949C8EE2DD8 +:10B6F000840C151342F8B08DB808D95762B2433A9A +:10B70000284F4F1AA6E987F0B7606C6A6DFEDB1907 +:10B71000553322F9CEBC442E48FBD999F73819A6E7 +:10B72000A9F5831612A0EDAD3C91FB69EA96C960BC +:10B730009287E6E55B7C561F4D5D24C3544ADB953A +:10B74000DFC2EDF08DED7F30E711EF5BB45DBA4CF9 +:10B750003220ED2C17324C3A787ABED04402749CD9 +:10B760008E72612DC0690D7F9E480991F2274513A5 +:10B7700021A9F47B5D8F2CC3FC08C90824C03C4977 +:10B78000468DAE5E0F47D6F4178F1DFF10E087B6CB +:10B79000DFAD96EF9BF3CEA17B29FCA22C95986997 +:10B7A00037FB06AF92FC69341FBE2A73302F0F9906 +:10B7B0006E2763FB817A3E5A2FD11B241B00CEECEF +:10B7C0006112A4E327160D1398BF43229249C27E4B +:10B7D00010FEA4D92344A1F592E60E7B9569BA7EAA +:10B7E000FE608E09A719E649D7D1D15CEA2F48211E +:10B7F000C4D63CDF5F40D725811F2222ED2741625E +:10B80000F88F6EF7CF490C3F1A5E7ACA6F490AC6A5 +:10B81000E87F747D5BCEA4F1165DBEBC670DE0DFF2 +:10B82000E2092A30FFC4D90C2F5A79A2344C643A69 +:10B830006E2261F324A5443E4693845285C0387439 +:10B8400048593F9F07547A7C409D0FFCC969588F27 +:10B8500010FA29415E74D57C2BE479F256112BFF46 +:10B86000D0477041DFB2A979F3D87CBCF94C94EE93 +:10B870006A21E42DDD7C6DD974FE5ABFF4DF1E0B06 +:10B88000C900FC7E54BC09DE61A407EDFB3675FEE1 +:10B8900016CF30E2670CFE8A19FE9CC50C7FCE28BD +:10B8A000FCED55DBEFFD2F86BF513C71A63540877F +:10B8B000D178D4EA578CC2AD205DD276847C0AF26E +:10B8C000816AE0DF1E3BCB1F12EFAC06FE00BE9A82 +:10B8D000805F08C9A44D7AB82E28CF1545ECDF7AD1 +:10B8E0001F9507FA7C50930F6C5C97CF5F4D283DF6 +:10B8F000139F891CA328ED9AAB7861BDBA9153229E +:10B90000FDFFA33809EB774A8289FB244DCF2C4CED +:10B9100007B9D966EBB1C17CBB2C3DD84F5B8E49D2 +:10B92000EC8D21DF4EABF335373B671C9D111F8F2C +:10B9300066810463F1FDDBAA7C6B1B7CEA8C99D2E7 +:10B94000072F09929DC20B4CFFB6B6BEF9B43DE974 +:10B950001FF2F9609C441CC7A5C2E52A349156DF4A +:10B96000C4701E57E98A6FB68F0B270F70C69033CD +:10B970001A9CED00A7273E9CCE9C0AA453BED985F5 +:10B98000E30C8A125B0F4B936D239D9FAB35496A85 +:10B99000A5E92EBEA9AB0ED2210B5168150B91CF94 +:10B9A0005450B8F969D309A1FD745C9A659B04B43D +:10B9B000DFDC43023A391F74042F89B43F5E0C92D6 +:10B9C00020859377293280F1AC4A07DABA91A264D4 +:10B9D00042E6D0F182FC0C90A7CEA080A9D68F467B +:10B9E000274E8B4CC462E8C7248740DF416773222F +:10B9F000F5E6BB19DEDAE6860354F691EE129EEC0C +:10BA0000A09FDA8B28BD24D1BC45EEAAA3F8E87E1E +:10BA1000D5427A757CA08D9BEB66FAC74E6A93C2BD +:10BA2000D0B7F9B037388E3EB603DE68BBE60BBE42 +:10BA3000EFBCA2E115FE15133CEF38917633809FE1 +:10BA4000DF27C5AB4DA6F8FDFCAE45FACE2B3A7903 +:10BA5000D54C98FE20444A5F312D7EBBDD2D6446D7 +:10BA6000416124BF870F213EBB5DBD5DF9749E8A95 +:10BA7000DFE42FA4EB45B24B0D788A4E096965725D +:10BA800070CCBAAE96C2B47D779189B702BD1690DC +:10BA90009019F092ED41BED4D635E8607463F13070 +:10BAA000396976C998DA008F20EFCC7BBCE3C96B8B +:10BAB0001BF0490C3C16B9291E3FF1DF0F8F1E37D2 +:10BAC000C1D499509304F8232FEF22D23400C3C875 +:10BAD0007F5A3B8DDEA3E75FFDDF7CFE1A9DC4AF7E +:10BAE000AF68F6103F48AB660549A89BC37CC0967B +:10BAF000864D29E854A5D8C2ADA09A72EAFA334E11 +:10BB000011D0CFEDE23B36145DFE0F53C6EB9F27FD +:10BB1000EF68F83447C6D3E3C7047AE78C25748C02 +:10BB20008BE02941FCB47790DC089E9A6C208F3A18 +:10BB30005D5BCFF84A2378EACC7E4EDCA0A3F72BDE +:10BB40006285E2A6F8D809766D0C7972AFBBA21DAA +:10BB5000CA05536C797E48956B5480F30BE9380B1A +:10BB6000468C789AA7E2697EFA3B8FC134A994E4A7 +:10BB70000915C815017F15E0AD6A4D00C882085946 +:10BB80001F7C2288F45025025E3865B2E943E78DB8 +:10BB9000E32F1EBE5C1C09C482FB19B1E6881BF4AE +:10BBA0004931C59BCEFEA08421A27CD4D6C5E5999F +:10BBB00080AED8BABD7C31DDA4D0AA9D5E5308FC0E +:10BBC000190B69EA02BC93736602765A5A3803CBA2 +:10BBD000ADDEFC10E8BBB4B09DC8E82788213BADC2 +:10BBE0007F70ED5D7ED443D76F23614A3728CB4009 +:10BBF0008E65CB61B0A779512A374B30CEA336F092 +:10BC00006F3ABD354984D9DB24961ED8E20EFE007A +:10BC1000D68DBF3E1FFB33D998DCBBD1F97C69655B +:10BC200022013BC07E810B812E3BB0727ED77029F2 +:10BC3000C8CD841E2B4DDB78250C7A4CB96097005B +:10BC4000DF5B0B95DB4D342DFF95BD88A7DFBB383F +:10BC5000871FF0D05548979CF6F3BBA79C2142F371 +:10BC60003B572E1F49827E8E9A25287FF2C3A64F0E +:10BC7000823D65FB603FFA8736D53F247CD32C5844 +:10BC80003FFB479413BBF91EA4FF5D05D36D7AF902 +:10BC90009EEA080E035EB4BCDD4BE5DB0CA4A7B73F +:10BCA00086293D99148E7C48E9D3E6DAE63D25C124 +:10BCB0007CE9778D3E7C917A11BE35E63D14D760E4 +:10BCC0006712726431D8919D206FD06E250A07EB00 +:10BCD00096C1CADF3FB06231D8A19D76AD7CE562E6 +:10BCE000599F57FE7006F3AADDEB4FF6EC82FA9EE1 +:10BCF0002CD2C4F01320AB74F64C41328FEBD6E754 +:10BD0000967FEFD6D9CD1A5D761530BA7CF9626789 +:10BD100035C8CD4E4A975609E87097C14FD6528D17 +:10BD20000E3B0B189DC5C3BBE57A0909EBEC408BB4 +:10BD3000A707E9D1E609A01D1D5D7F450AB363345D +:10BD4000FAB77909F2834D0A3E753FF287CB0FECC3 +:10BD5000672D68221CA5138BC8FCE189E6110F3EF4 +:10BD60008DFE3B0BF215A0D7F745E227E3D4B75C75 +:10BD70002FC5F96C71CB93927578F4E451BCC798D8 +:10BD8000CF5792D97C3A027581FB69BF72BDA4205E +:10BD9000DF7889BF1BF412257FB03BA9BDF9C9E448 +:10BDA000543D9E983DA2F5AF704D8316E0730F6D24 +:10BDB00047BFB6939714587A8B2764E0EF2FA604F9 +:10BDC00067EBFBE145E61F2E34BB4CE423E0673F05 +:10BDD000F5CBC293A99FD82262BAA7C58B69578BAE +:10BDE0008469778B4CC256EAFE90EBE7EF053BDBAC +:10BDF000E540F826A28B8E163FB66F6F99CDFAE11B +:10BE0000343A9FBA0BE8C261D2F8C4BF0BE83CC910 +:10BE1000AC959761BE8763E58F242F58AC14E37C03 +:10BE200050EE754D30AE395486EB77F3FDABF25BD7 +:10BE3000C5DFFE798F54E703FDBD6126FA38C618C9 +:10BE40007A09B3F16EB4FFAE6C13CAD3FDF3769EDC +:10BE5000F1D1BCE575DAFF78F4D8C3FA8FDB9F0621 +:10BE6000EFE02E84D74AD7DB4EFBB38A4CDEC7E324 +:10BE700087E8F9D294207F7808CAE9FD836BC9CBA3 +:10BE8000C09F7458BB087C1A9021DE25B4531CFB5C +:10BE900041DF06C2CF80BEB571E418CD0B2ADF505A +:10BEA000B5AFBC4CFB11641BE9A6ED06E7DD45A070 +:10BEB0005DE72B360A13A5D3947CB417EC85B5A4A3 +:10BEC0008DD6DB596D2766FA3D69FE1A02FDEDFC41 +:10BED000991DFBF79D9982FCBA4B647C34A11CF23E +:10BEE0009A4858AFC76D8E483E1FE4E57D24300D5B +:10BEF000F9FA693D5F533DD90BFC24902A8570A067 +:10BF0000871FF0333B4451E569E05832DA81016C18 +:10BF10001FB10B9B8808FC7ACE1CEA06BFC4DC80EC +:10BF200046DF22F361DB30F2B5BC3CA38C10170373 +:10BF300081ECF287492EE025C34C6D31204B818482 +:10BF4000A9DEE8A1FF007CFC85AB17C8AD84A4AFD7 +:10BF5000110CF3E02F382F996E05F8587D4D0FF135 +:10BF6000171A1BA13E4F74F5D19FA94B1ACF2F8CE6 +:10BF7000B6E30793557FD0497240EFB5B79C206F69 +:10BF80005B22FDF05171252DD5ECF9875358DC6209 +:10BF9000949E2446DF2F503F1DE8B1E31766D21B65 +:10BFA00083BEAF27FB0CF66E46D014991FFDF795A4 +:10BFB0008BD68A8306FA1C7FFDB3EA8DED739A1C3B +:10BFC000063CE635271BF23E25D3507F5257BEA1D3 +:10BFD000BCB067AAA17CF2A1E986FC94D0A70CF5BD +:10BFE0003FD15761C84FEB5F62A8FFC91335867C0C +:10BFF00049F86E43FD1967361ACA670E3D64289FDB +:10C00000757EAB213F67F8AF0CF5BD41F1E409E067 +:10C010004F4A8F668AAF5D19CA21D09FC36DD48EF7 +:10C020009BCFEC63D0B7249BA8F631554C694057A1 +:10C03000ECAF1DF400C8F93D8F85BF807AD2E407CC +:10C04000FEE50B16C91BA15DBB68225E9D1C911607 +:10C0500011F85EB1C78DDFE5D256E40F81AA0D7BE2 +:10C0600022E86DE37A10F376D20FF0BDC1E0E3452C +:10C0700025A67C12B28DF46F25F72405C6B1FB2CE2 +:10C0800092B1FECDD2BF2F45A5FF1C4AFFE689DB4A +:10C090006B74FF90499E9CC2FCC3AA731E83DF830E +:10C0A000781DF57B6CA41DD8A9BC6E24EB14ABAE37 +:10C0B000FA3756D3879FB871FF269ABF684A714EE8 +:10C0C000D7C9CBE4B566DF8FD587330CF65974DA60 +:10C0D00096F810CA3B2A17CB530C72315005F31354 +:10C0E0007819E5A2F6DDD73715E57297C8EC944EBE +:10C0F00089F2E538F88A96CB5F4E9698BF18473E8E +:10C100000B54CE82C2DDB9F2D35D8037791B41BDBD +:10C11000447510CAD9E8FEA95D7537C2E965F4A473 +:10C12000F9439ABF65A3F203FC2B9B44105F568A28 +:10C130002F27DA478FA27D49E721817D64F550FBE7 +:10C1400013F43DB53F99BDF9E7B52FF361DE7AFBF6 +:10C150004FD5972187DC94921ABFFF17E3EC479DD8 +:10C1600049D6FCEEFF9EF427A718F1A1D1A146679E +:10C1700056203A3ADEFB125B77DA2291D3F62F246F +:10C18000F84F10E9E5D4ECB34A25AC5BD0255BA9A8 +:10C190005EDD37BB06DB0993780272266178C33215 +:10C1A000D093A494C90985FE03F4E62836CA0D5B32 +:10C1B000941E15401F278ED5BB9A7CD0FCF389E4D2 +:10C1C000CBB752D438D92C324B2F5FE2F9E19A7CAD +:10C1D000D1F0B0E0831611ED8E0F68B9664FD07EB6 +:10C1E0002C397C00E2CC829FC84762F0DFCBAA5E8C +:10C1F000EE3B6997812E5D6B04F4B332FDE172C8AA +:10C200006736113FE067F670980469FF3FF4B0F5B8 +:10C21000C8F48738B0CF332F873880F3A085C58521 +:10C2200032B785387DDCE89AEAC7FDEEE2A37E5896 +:10C23000F78A3C17F2E9671713A48F21EFC69E72A5 +:10C24000D857984BFCC03F2E0F4F32217FDE1A4249 +:10C2500079E21F51A8AF4392E944614DAFB490E930 +:10C26000F751FFFDDD161BA6D75A444C2BF38A0766 +:10C2700017D07A5B7D0E8C1774E43B709CCE5C010A +:10C28000C7F98F9C87F2C02EF8758B17EB773DDED0 +:10C290005404F184CE93FF8971CD083D53AC7901EC +:10C2A0009E30EEF710BEC90BFBBE49F20CDC27ED49 +:10C2B000B404FF7103C413D70AFE6331F837E9E50C +:10C2C0001FA19F0CF8013CB4DB195EACCE26BF1B4E +:10C2D000E2FD93C8FA15B1F854C513A530B340E98F +:10C2E0003789910611E686DA1241AFFA493F059B7C +:10C2F000583A421CEC8790074509E245D9B6D02050 +:10C300009467D78BFE36AC4F705F415B278B9D04E3 +:10C310008EBBA05E98DB42BFBFE811D9FA0D8570D5 +:10C32000DFFD37176E1FCC21F1F97B4F4BF5D92A72 +:10C330005D3CD64562EF0BFFCB6D15160FEDF77622 +:10C34000806D26ACF7AC71F5E38DF67BBB8753E3CC +:10C350001393D3C15E6EE663DB996691AD0FC47F24 +:10C36000C08FDE5A28A5BB5DFA7E183ECC279FC73A +:10C37000F57116B3F9B77DEF8DCD8F513AF977DAB4 +:10C3800010E255AF5CFC0CFA8FEF254BFBC1EF526E +:10C390007E6C26B0CEEF7D7FD669589431F36E392E +:10C3A00093CCEBE249EF7DFBD5320BEDFFBDE75EB1 +:10C3B0002DE3510885101F5A79E387AF9541FC4A58 +:10C3C00068FE4DE6650AAF52418A9A204F0D68E635 +:10C3D000876E591A1E076F07D31ED802F1C2509BF1 +:10C3E0004BE4A8BDF625E71F05A0C766809FA60FF2 +:10C3F000DB4676727489B9F4779754D1FEB6728AA7 +:10C40000E2E2006F8A15FC0A72C1EA07BAD95AC87B +:10C41000F4E5D607C59002722CDCC4C8DDF65AE6F6 +:10C42000652A87ED3F0DC11900D2CE052A13207E63 +:10C43000378D20BDDF76AD290FF695DD44C8073A6C +:10C44000B498CCD8CFC84567A817E56FD32C9043D4 +:10C45000AD171F9D0CEBF57B55BE6871B73453D3F8 +:10C46000813A1FC4DDFC1877DBCDF7639C3EDE7C90 +:10C470009D5EB6AFC0571235DEF5DBEE7076841EDA +:10C4800034FE8A6EB7B785F861BC975A6C98BED0F7 +:10C4900022627AA2C58BE9F75B244C075A8A30EDF9 +:10C4A0006BF1FB0B2C00E76C4C3B2C647D40476729 +:10C4B0005FF0B0FDC87B92CABF0074FE24EDF73276 +:10C4C0006DF745DAFE32AD3FAF366C86B8CCBC11A5 +:10C4D0002A2F2528EFC2EFFB697F506F6CB9AD049E +:10C4E000CA4BABFBC380C7D262FA9D407F7D587FA9 +:10C4F0007FCB093F2B1FAAB450FC96FE96953BE7D5 +:10C50000D27E68DEA9F643C72F61F567637F745C4E +:10C51000CCC7E8B784C173A224163CD1F5A9956FA6 +:10C5200026548F88F0BFE0EF59240EF75138123EA1 +:10C5300006F2F882B51CF4E79E12926FA2FACD9231 +:10C540005AC041FEA966229A4BA8CACBA8D9554E1B +:10C55000A09D8CDF95557CE8980FF513F6ABE9A705 +:10C56000E4EA30EA9D243FC937BB69CAD381A753A7 +:10C5700054DF4722E70D503EB13CAE076D2756937E +:10C58000C8790332717DAA5FA2CA63D3DB474D210C +:10C590003EA63FF771701EB1835F4B7DFD7E924BCF +:10C5A000F3AA7DF645B5DEFE7965491B21BFF8810A +:10C5B000A7200EFE1BE2E5603F7EB47D943D77B878 +:10C5C000E54C5A55A1AA1440DE6F138FE8EDDC6CE0 +:10C5D00085D2AB8E0F7A9AF8EA5E8C2F04336A7498 +:10C5E000FAADC312CCA0CC4BAE3FF18F8B413E8055 +:10C5F000BE06393D7784E9F751BDFE5B261F357BCA +:10C600004250D76B9FBCB12D01F7D3A83E92C0AE6C +:10C6100008920ADA3EB17CEBCBF09D9418BF270854 +:10C620008C8F32BD210EF2999EC04F3CB0DF907CC2 +:10C63000487E86CEF7B7035609E8AFEFE4DA7A888A +:10C640001B3E4C12253BED27F3A54B02C0D1611ACE +:10C65000168008473CCD4B786A0775089A9CA486DB +:10C660000F5DFF8E34552E90DF7757D1FA074DC1FD +:10C67000AB54578ED63FE8086E813CFD936D54AFA6 +:10C68000EF1D8DA36FEB96294DEC55E3E6239ECF6E +:10C69000762BD990A7F5DD2CDF4EDBEF750F794DAA +:10C6A000349FC86DE93E930379ADFE966E85B6BFA3 +:10C6B000EA61E700882BE803B9379A17693E41978A +:10C6C000E7599ED858DA77F23F05D0431D6923A772 +:10C6D000B3009F3FE4FA41BE36BEFCF541C86FAEE1 +:10C6E0002712C4E7324F1CC175F8AAB97C04F0D6F2 +:10C6F000D7724644431DFEB475A176EA142FC17863 +:10C70000B210E242F960BF15F798D07EDB4E49B017 +:10C7100004F0DD9506EB5C91C6FC812921DA8F8E51 +:10C720007FA650BEB34E0775651919D6FB5BC46F63 +:10C73000027811E5F01FE57F2F01FDD4375B714CC6 +:10C74000A5E36DDAC0FB5B25D03FA15601D6FF04FF +:10C75000877AC2772663C73768FE5A7F4A2FF81B4D +:10C76000961D8C3E37F9FAD3A6D3B4C3CEE86293B4 +:10C770005BCDBB8DF976D59EF4BA157732FDBEF947 +:10C78000C4815C3000AF1E9B857EE4660D1E720086 +:10C79000E1B93A3827E9363ADFC69FB2B866E340D6 +:10C7A000C912987FE31E13013F6EF300A5271D7F7A +:10C7B000ECA37C284FA6F3907BA6F2943E02070BD5 +:10C7C00096DAE9FA7E3D5F16015FF569B7EEB6517C +:10C7D000E7E8EB823805E8A13EAD7437D0D3A6393F +:10C7E0006F213D26A596FEA49AE2EBE8DDD54B40ED +:10C7F000ACA599185F5282433967766F43FCFF6B93 +:10C800003919B1BA119DB8CF9907FF47E19B2CCADE +:10C8100015505F5C465D22A053217012EC10A5C23A +:10C820008671D20A711996E7AE21A66E0ACF112938 +:10C8300039B99536B517C826B053F2030E8C7F9AD6 +:10C8400013AA76803F7AEC1CCB47D6E912E2C55199 +:10C8500014EAB7D17E6E71F122F8226966D906EB2F +:10C86000467979E85829F00BB303942F1663BCE797 +:10C870006022A97F8EB63B6ADAD8FD235AEF68B2F0 +:10C8800087805DD9C171EB6BF07BC5D4AD743D8EF3 +:10C89000AAEB6776FB4558AFA36E637E2FB7F141D5 +:10C8A000C0DB23A92F2E81F9A559E59E140ADFE7E5 +:10C8B000525FECF666209EF36DB4FC737FFD42B7C9 +:10C8C0008DE2FD68AB9C29EAF293FF40A536CEE3EA +:10C8D00005E453DEFDC587808F69F98F6D54FF7EB7 +:10C8E0003D59B307587941BEC6D7D4AF9D4DE168D5 +:10C8F0001DCD2BB622D8F78AD4AFA27CFED5A7CD0A +:10C9000044EB1FEC09C79C7E9BC38CF3200EB067E1 +:10C91000A6F168CF38DC6C5D1D53F2D14E3A6A67E0 +:10C92000F81AC93161F922F3B322C407AC53781362 +:10C930009EE5214D01D0CF7C364F58BCF7B03C4529 +:10C9400082B029DB1FE47A56A07F682FD2ED071250 +:10C95000F0638DFB877C54BED03A9C61A27AD87379 +:10C960006105974BFBFB6CAAEA2F7A4806C4631F4C +:10C970004D6572E6D18072BB45021A1B66E75649C7 +:10C98000603AA4E9EB0AD2C73BBF32F65C4018ED2F +:10C99000B23D2E938AB749BBC305D45E763D27824C +:10C9A0001CA16A7EC761D06F1E1EE9A610F89FE623 +:10C9B000B7B9591CDED7B7E44BB3C13E7CB5D00440 +:10C9C000FCCF8B7E11CED99527942681DDC68FD2E0 +:10C9D000E9EB4BC240378373EE043F5000FEA59F46 +:10C9E0000FDBD9F9D0910CD20F7161DE2B13FD3E14 +:10C9F000A1C6BF3B5B6C98527FFE5DD01F5FEB22F0 +:10CA0000B84F2078039897DA09077CF1F2A7EEC6B1 +:10CA1000719FE10349EB40DE9E63763D900BC63982 +:10CA2000C24F7010E778DF16488279EF771BEDBFB1 +:10CA3000B23466C776A632F9D9D9C2E2A0C2F54FA0 +:10CA4000605CA7C3A2C923D7D2F05CB0E783788E1D +:10CA5000D61ADC2683BCB21145117571725BB631F2 +:10CA6000DE255CBF95C58752D938D1E70D5C9CD6D1 +:10CA70007FC1EEF1FC032D8D3E9FD04C02288FC864 +:10CA8000103BF7B06D57657AB2AE9F6D9C9C2E8EB1 +:10CA9000431F0F5F379390EE9CCAC3FC8800F37965 +:10CAA000F8BA80DF897738B115F66528C175C33AC1 +:10CAB0003EFF5DD44B0ED213860373568853E8CEE7 +:10CAC00085122F3F324AFFF911FEC07D752E067F79 +:10CAD00048C67CF47EFAA3E03BD37F77387F2DC035 +:10CAE0003CDFAB242360871232BC08F8B7B1D28197 +:10CAF00071EA87498FCD06062EDF23EAE3C58D0351 +:10CB000097123794E23E960476F0C32F951BE254B9 +:10CB1000DAF9302DBFF9C4068C1F3E7CF49A30B58B +:10CB200014C118B2507FACD1D673C69A1FA96FB783 +:10CB300004952CA0FF975AE52CFAE95B00279CABE3 +:10CB40006A9E340BFCBFDF8AF519802727AFEA8F76 +:10CB50003536D41FED76EAAF019D5E9C8CFA9416B3 +:10CB6000F3A09FB5F15778181D8EA8FE7C023533CF +:10CB700001BF1D8EC01566B41399A7F64E47B24685 +:10CB800037CDDDA0FF0E0A11B908933DE860F9E446 +:10CB9000B4E6EE76A687B1FEC893FC6EB0873AEC99 +:10CBA0006ADE43307F50E8413F41F9BE5502380FFD +:10CBB0003A027EF007951D5324D02755E92E9C8715 +:10CBC000E5EFACBD200F333DC1AB60B7100FB38FA5 +:10CBD000DE4BBD904B5C31FB19E16EA41FAFB11F62 +:10CBE000FB5C36FE7B9C39B0A334528FB60FE3B9A1 +:10CBF000807B6C18FFD1EA1FB618ED642D9D92C69C +:10CC0000E20C204F80AFB5EF42F03EE45F2B69426B +:10CC1000FEB57A8DFB451A3F0BD7A718E297DF4A7E +:10CC2000F5E1FA687240B85E8CE59D2A9DEE847D40 +:10CC3000F471C7498E33CE0C9413F1C72953E5081C +:10CC400051E3493C9E33D3F824BEBC30C671A3E502 +:10CC50009F966AF2EF884AC7FF600F2E4CA3FFFF32 +:10CC600050A87F91035B076F85F5F9A36AF716F566 +:10CC70001D3809E47745945B5353E13C957C1CD205 +:10CC80009BE59BFA3436DE5839C6E20FDB1E945022 +:10CC90003F3FC3FB1DFE1870D75F771AE4577EAA8B +:10CCA00084FDD5F30ACAB1FAEB8958FED1FBB793DC +:10CCB000D08CF1FA7761F968FFFDACFF973FF5E39F +:10CCC00083B3A1FFE3169355E7CF6D3BBE301DE262 +:10CCD00095DBEC542E1BF95606BEE57D64D40F029D +:10CCE0003EDFAFF945CAA2DD5573C16ED5F1F96CCF +:10CCF000B0BF22ED79BACEFB1D5AFB3B77833D34A2 +:10CD0000A6BE33AA7EBED6FF6AEC3F1A1E4D8E40E9 +:10CD10001EEC2DFE0F560D3E9443074C51FD8DCA5F +:10CD2000A520F6B7690EB33392FEBAFE270A0FF4B8 +:10CD3000172ACF023BEB4122C139E768BC27A9740F +:10CD4000587F7D92615D23F8BEC5F0FD9F5BBC24DA +:10CD5000A4E3B7CF04B72D027E4BD2D689283BB1CE +:10CD6000DDE12C12D2F1DDFFC0F151E1B82D0E1C36 +:10CD7000F3FFC270F80C7C1981A3C0F0FDA3C2615F +:10CD8000B65DCFBCACCB5B4492A5CF97846D599771 +:10CD90007576CB8C33A2213F73C86BA83FEBBC6484 +:10CDA000289F335C6428BFED8ADF909F3732DB50C9 +:10CDB0007FC175D9902F278B0DF52B6D2B0CF98525 +:10CDC000E25A43FD696A9CFC76EF0643BDC5D283F7 +:10CDD000867A4273CA77C07E59F0C1021BF8173BAE +:10CDE0005DA6EA10C5CF4E3E684B8E211FCBD47E88 +:10CDF00047F59D370DDB2F149BDA411E2EA4AE7034 +:10CE00001BB5D7D2EB02EDA0F7AB45229AD16F0E3E +:10CE1000B1F8C9072BABE0FB9D8B89D8ED8EE46F91 +:10CE2000FF2B42206FCD96F15C9BBDD884E7067640 +:10CE300017D78CBBFFB04FB5DFF744E9FB51FA3190 +:10CE4000B3F393D1DF8BD3195D1D58B08FC03E81F2 +:10CE5000CD15C27B3E8353767A21FFA505DFF6828E +:10CE60009FD135E5112FD04F67CE570DE7F21C0546 +:10CE70006C7F26BADFBF55FB2DB8FEA80DF4E7EE98 +:10CE80006C86CFE87ADAF9F4DD361637FFB8E6B902 +:10CE9000F8639AE7E5746667EDB68530FEDF5DF40A +:10CEA000F1C07FAF3ACE81058F1306EFE3780EB95C +:10CEB0002B4790F47A564BE1DE28CCA7D3B7D30B9F +:10CEC0007AB7CBF788C1FEB7C27C628C63F3323C81 +:10CED000ED163FDEF93CFE27CF6767CC7D775B9C84 +:10CEE00079156BF3F2AAF7283EA6793DF5179E5700 +:10CEF000581D2F359DD9A7BB25C64749E6C0CFF39E +:10CF00007DF1F92F69B6F19C5282DFE807E417043E +:10CF1000C63D7F745EC54F3C7E5D635152018ED726 +:10CF20005BD839DB7380479A9E0F4EAA80FB0AAF0D +:10CF3000C3792D0EDAEF48186F1DD606CD063827B7 +:10CF4000920F25E9F9888FD56B8CED56059CC6F3B9 +:10CF500052EA39038AA7FD105FD6F036669DFF4C72 +:10CF6000788A476F378AA7EEA29BC3D344F49D9A71 +:10CF70002E21BD4C84278D8EE2F5F3FF2A1D2DBE98 +:10CF800071FC20FD7CDCF8F9AF463FF7A64B37C4B7 +:10CF900067FFBFE2E7F11BC4CFE8796B81D4C73AE2 +:10CFA00007D2E915900E27734D6717839FBDD88C64 +:10CFB000F1B3D70E1734927C7D3DA6075E5B36A990 +:10CFC00011CF8F553BF1ACD65953EC7E5F53F1F145 +:10CFD00090D7AD9EA7F3A782DD7BB67AE5B8F322A2 +:10CFE000CBCCC6F38BC411999F99F64BA40A8C9FA6 +:10CFF00051BC1E1B67DDB5758B37DE8DAEDBD9EA04 +:10D00000B69B5A376D3C8AA798EDEEF6E6DF10DF47 +:10D01000C309768637761EA0EF7166B7F701BE6941 +:10D02000BFBF84A20CB0FF09C6FD56AF493F02F056 +:10D03000BEE665F1F001416AC47741562EDB0DE78B +:10D0400051CEAD727310D2D0E038A6AE67595D6C88 +:10D05000BBF339B53CD29E2393A5B1F58EA876CF0C +:10D06000AA3A0EED07C2CB39FA773FFE21AA3CBAA5 +:10D07000FD4BDE442C3F17E73CE6B7D4F6AB6BC75D +:10D080006F4FEA53F0DC1F21528EFE3EFA285DA955 +:10D090007CB0C21BFCBE97D67F9D0B7EF973104FF0 +:10D0A0009DE2C2F33D84273ED8F71FED8797F1BC80 +:10D0B000C6E54686F7E87E75FD85BDA9F1FB8B8741 +:10D0C0005F6D5EDA78A524807E1DA926E27E36BEDD +:10D0D00019CE39DC59499A707C5E427852DEA4FE42 +:10D0E0009C2F421F174CD23ABC48A3F633F0FBCA20 +:10D0F000A5D0CFC05993B8C3171FEE78F2E09F5464 +:10D10000FAF198833BE05C0159CFC53CB7F72BAFF0 +:10D110001DEBEDF78EEED7E338B73C19B448B4DF1A +:10D12000BBD4736784047356E8C6DFAFCE3BBA9DA9 +:10D13000C7CCF6C7C91B66C45F5FEF4339B1F8E7D8 +:10D1400035D55EDEEF2D32F8C7B5812D16B06B6B8D +:10D1500097ADB0482E289718DDA970F409C19C122C +:10D1600057044F71E58F8A9F81F3413CB7B1BE9957 +:10D17000C373C7C5DB19FDADDF3E686AA4E911952D +:10D180000F57C03E93AE3F77069B5F5FAF2317E01C +:10D19000EFD39FBFA0707CFA10C1B89D2DE3E93D8D +:10D1A00010B71BE6881AE7332D87FD8661755FACE3 +:10D1B0009096B702BC55A9C8E7EBB7AF403FFF96C2 +:10D1C0006AE6E70F0804CF01BD392F2104EF1D10D7 +:10D1D0009B3CF828CDBFF58724D2ED8FD0C71342F2 +:10D1E000781AD0476A5BE073B1E2D35206E3F3DF0B +:10D1F000BAD83E5E3CBC9C55E5A956AF86972CB18B +:10D20000EAAFAC36CA350DFE146BF83D12239E3ED4 +:10D210004A8FA1F1F5DD2F5439FD5A94BF547B3E5E +:10D22000B6DF3237433DA71BAAD884FA4AB14A7801 +:10D23000B65885C7A3AC467C7EB8948890BFD32AE5 +:10D240003D0DF0DD556B8E92C321EC67FD32A76179 +:10D250005E4FF4FE781ADC4BCA2F60F2F7FD2217FE +:10D260009E137F80340970FEAB8E28F3912F896462 +:10D2700001FA3EA7E24F83EF1C91136682BC683629 +:10D28000C7E4AFBB543A3A17A85C85E7DFDBCD783B +:10D290001EE1526DCA72887F2B018B1F8E375D6A2B +:10D2A0005F9970BF6E5D35BDA7D935E78395E3EA19 +:10D2B000AF5501E37AF5093DB8FFA75490A66394F2 +:10D2C000CE267FF9F2DE59347F36642A61E7DCD856 +:10D2D0007CCF86B2B473F1844FA3EBAE165D350DEF +:10D2E000637DE56FD8BCD6D58516C296D83D877AC2 +:10D2F000F6CDA2F9860CB7BAEF387F1EF0EBAF9AE5 +:10D30000C7B707A2E9E996271D867CD97922E07B79 +:10D3100014DB62EB87F7B29C6C5F87F7E7C23AAC2D +:10D32000DB1EBB9E3BDB85F5AEFED15C1FCBEF3E2B +:10D3300090C5D6637D3D17539E1FC84A60E50DB169 +:10D34000FB5F95E954E59D980BEBB23E0EBC2B328A +:10D3500013118EB73B56AF83FDFB2B51F655452677 +:10D360008343CA64E72BAFF6BED09106F4B09313A3 +:10D37000E11CD95B6EFF14A0BF0DED97D0CF4F57C6 +:10D38000EB3BD2034F66D0F4EEF3CF9D82FA0375E8 +:10D39000C4CF49F1F5C0E10C4D0F68F7A2357DD837 +:10D3A00063077D04FF0BFBAB1404252919D65D79B7 +:10D3B00008CFC5F43A44760FCA3F536F577F43A551 +:10D3C000E7AB476F6EBDEFA937DA4567C1FEF3449F +:10D3D000ECBFAB82B4B7948E7B95D25B2B9D0FF9DB +:10D3E000E0895BF5FA46E38778E3DEA81D78F5E887 +:10D3F000CDD98113CDF36719BE1BB203DFAF7E62B7 +:10D400005FA904F3ECB93596BCD5E4F22F55B918F1 +:10D410004D2F5AFA4B55CE5F098D0FD7670E19E184 +:10D4200059D7648447E38F2BA13607BCAB45479F90 +:10D4300006EBACD9A5A46AE60DBD17120FCE5FAB03 +:10D4400074F2AB66338F72EF2887F1E95F353F9155 +:10D45000182B6E153DFFAB264A0F401F4FF3287F58 +:10D460000AEB379C4C9322F4F87F543CFCA974A837 +:10D47000C9574D9F44B7FFAF4A779A3E9B88EE3C11 +:10D4800071E28F07326C88BF0DBC28C0FED1810CC1 +:10D4900089E589B8C80BF6EB6C76EE9D4AA85C78F6 +:10D4A00057E26AAF03EF8329DDD650215DC72BBD5C +:10D4B000B74DD1AFE3EC4CB61EEB1BDC3B61CBFAB6 +:10D4C0008AC9BF381DD6AF86BDEF71EE7CF2A2745B +:10D4D000DAFE892113BC9045D66DDB6086F9CDCC90 +:10D4E000647A64FDF657D1EEBB59BA5EDF64D4E7C7 +:10D4F0005FCE10553DC1ECF03BA95D00E708E3E1CC +:10D50000A13093E1E19EFAE3284FEFDDCEA13CBDCF +:10D510002593E1E35E3E847299B433FB99D8283EAB +:10D52000A85CBA0493007CFC35C7CE77F30141FFB9 +:10D53000FEC6FD7B562F043B309A3FBEA7E2E92B87 +:10D5400099EA3B84E9C13B33D13F0C70D0DF5B9F4C +:10D5500067F0AEDFBE05CF275FCC50ED6B953F2F58 +:10D56000C23ACD8CCC2F459DDF05C7C836D0179465 +:10D570006F4C78BEE47533C275F5ABDF6C827AE22E +:10D580005417DEF7423B96E6FB9627845A75F13A2C +:10D59000CDAEC9F7337EA8E565835DD890E933D871 +:10D5A000E9D1F6C6FFE80396F6A878FA4BE983C3FB +:10D5B000AA5DF0A7EA834754FE8FD60BA37CBC93E9 +:10D5C000F1F1A5F3FFBE10F2D17CFCADCC8FA69794 +:10D5D000A2F9F74AEFDD48D7CA1222161AFCA39C1B +:10D5E00010F8C1A3F41FF1933838DFF644EF4FA6CB +:10D5F000419CEBD2DED5EB628DFF4416B3B33626E9 +:10D600004A267C1FF2754667D17222BADD285FC4B4 +:10D61000892FD6D6CC41FFF05CCD6DB970EF2DDAF5 +:10D620003F18539F935357817FDCAAFAC7FBACF591 +:10D63000BD31E0F566317CE6178C9C027CBFDFC013 +:10D64000E17D62F8D3DBE9779FF7FF60581A0BEFB3 +:10D65000685EF34FB6B3F1A2C779575DB751FF4487 +:10D66000A1FE09C5F370AD3911CEB16AFEC9B0F2A1 +:10D67000E7F54FDE2423FF300BD6F9686CB81CEABF +:10D68000FCAF08C17D73281C579798FD0AF08B8961 +:10D69000B6D3F925D1EDFEA8CEE7CDED37298FCE53 +:10D6A0001BE3C9F1F86D14AE3F91DFFA84911CE0E1 +:10D6B000FB378F7C70F15198CF1107BE3F16DDCF3D +:10D6C000D7B2CCAA7FE0403ED0F4EF80D0B3F905CA +:10D6D000DAEECD3B32FD3B888E2F08E50BFAFDC21A +:10D6E0001F295FF851BE211FF7F53AEB63F9298333 +:10D6F000AA3F141DB7117BBFD1047EB14CFC167D2F +:10D70000DCE90D75DD7FA1CAA5A22CA63FEFAA5DBD +:10D710002140BCE8FED1781141E7429C9A7D04FC8F +:10D72000CBD7D47B02CAC68498F1DE992A5E278AB9 +:10D730001FACA933FAF577D51AE5C73BA1FC513DDB +:10D740005238CE7E9446BFF1C6BB51FDD117BAB94F +:10D75000FD8089E6F7D9AC1BD31FAB48D33C8C7353 +:10D76000D0F581B496344D7B81C2F3CEA19509608A +:10D7700047FD82906AB4E33FF8EC34BD5D1254F18A +:10D78000FC7EED67EF00727943689A164BFF44C741 +:10D79000697E118A7D2EE32E55AEBEA1DDA7B82B82 +:10D7A000763C7F8B3AEE1B75E3F34D74DCA67699DD +:10D7B00071DE4A16B387DEA86B7304995FCDC6FD90 +:10D7C0001B362EE82DBD5DAA64FD79F4E330C4EF6D +:10D7D000619CED84403CA54F50A6EACF5DA5643323 +:10D7E0003CE4178DBF0FA5EDA768F5A2EDAC9F67D0 +:10D7F0004A867BB3B5CB8C70B569F62D11310E72AC +:10D8000015F4A527A22FEFB4FA1F043A202E09CB56 +:10D810004FA878BFBBFEDF2C307F2A3F3BF01EDBDA +:10D82000599308F2B3EC7CC8A2C7CB851BF4AB2E8E +:10D83000A8F6C2447234BF6804E5DBFB2117DE8F13 +:10D8400078F30BBFB3C4EAB7F67A96E11CF1FA405D +:10D85000ECB88A98258C8B6731CB88BFF5D773F1EC +:10D860005C703CFBFF10C8AF99608F1EE9D0DBFFF6 +:10D870004F6549AAFDAFCA339ED9FDF1E2AF432AF5 +:10D880009D4D147FD5F4B3562F7AFDB5345A5F0EF3 +:10D89000ABFC1C5DEF52D68DD1DDA81D1387EEE2E7 +:10D8A0008DABF91F5ADC37BF98B68FB12F33661C8A +:10D8B000B55EF4386F46ADCF183F224EDC2E299B63 +:10D8C000E13718276E9794CDE2766709D38B4AC863 +:10D8D000897AECCAD17BF781B9F7C0E2CF9D06F512 +:10D8E000D6A8C66BEAEA5F3D057EAAE65744ECF18E +:10D8F000601BEC935DDDC1A1BD113D4EB45DDE0842 +:10D90000EF15822055E307456619E3D4E43176BE6E +:10D91000DFD3BC1AED4B2D3EDD27047624D0EFB7C4 +:10D920006CFFB76DA05F353FFE2D8BFF411667661C +:10D93000F6EE855E17DE73DD3AEAFFF931DE38CAAE +:10D94000FF6AFC71A2F518953771D6632279132FFF +:10D950002EA2A5A3FB2C8254F80A9C4BE512FDBD18 +:10D9600034AD11080F78A859CEA19F5923C84B3167 +:10D97000DEFCAAC90479DF72DF6E3807BFB2DA2293 +:10D98000DBA5C8FE4BE96B0D85AF807F41270C7E80 +:10D99000ECC02FA57F82FBC1AF2FB64BB03F727694 +:10D9A0009E34E8A1F9B3777022D83D558BEF374FFD +:10D9B00083F15671F80E8DB399A8E7B56F5D5E5986 +:10D9C00040C8370044DDBD8F1A6D9F4659BB0FEE2E +:10D9D000CD4E4D1D30B9284ABF7B78ED3E1B85AB3F +:10D9E000A335E085FB78F76597EC83FB786969F2EE +:10D9F000D0026A471DCC9EB11CF2037FA3F557BA33 +:10DA00000FEEDFBD680AFA385AFE83EC65CB79D891 +:10DA10008F98A48DBF1ECBEF5AF2E0B16DB4FFB763 +:10DA20000F6F590E67D7CBEAB4F11F595EC953FA8D +:10DA30009FABE51F4B84BCC74922FB4CB309B144E3 +:10DA4000EEF7E179F781D1FB7C2DCBE1FCF8EBE53A +:10DA50004D95708FB3ECCB1DFB8AA710326B59B973 +:10DA600028D3FCDC9C2F2F77C2FE31A1F448F3723F +:10DA7000CE57107E8FD9A4F61FDA2767033CCA540D +:10DA800028E79467F655BBE13EC2F06920CB879B3F +:10DA90007B6C69867B098A0CA68970A23C9C85E018 +:10DAA000A8FBDAD9E169ECBE9D9A2F62718AD1BCDC +:10DAB00097E50776C4BE7FF2610E935F038ED8E5CB +:10DAC0003D2ADF6BFBAF49E789FC6C0CFEFF3CC4D1 +:10DAD000FD6746F8E914C4433CF8E45C532BECC3FF +:10DAE000DA189CF1F671F7A9E314B426E13B45CBB3 +:10DAF0009A9CF8AECE243F9337948BF89520FFCDB7 +:10DB0000268433D5CCE17B26690E123C4ED3D41447 +:10DB1000F6BEC9328A6A787764E1A4C0513CDF9BC3 +:10DB20009E51D206E7EB5A7FCE831DA6B51F0BA7E9 +:10DB3000B805E04C35D7946C29D6E1AF98C14DD7E4 +:10DB40005D6D277F13DE7B19189A9A0F767565B67F +:10DB50006488CB940DD558E05CEAE51C554E48AC82 +:10DB60007D6A25932B235BD4F72A6CFE12435C5FFE +:10DB70009D7F65E7B22F41BD86210B817388DB8EC7 +:10DB800097E33BFDF1F8BF01CEBBEBF476031FC674 +:10DB900073E60D70DE7D06F4F75301CE37423FE0A9 +:10DBA0001FC0BD0EB09B52DB62AFB716576EB8EE0A +:10DBB00026CA0CFD7786AF48FF1E2C9F685E91FE3B +:10DBC0008CF7F8C6F6A7DEE7D3F0CEAB781762C3C2 +:10DBD000F9AA469714DF261D3DAD52E98B4A3F7CDA +:10DBE000D7F7C2F2E25EFD7B0584EC60E73A78BAD3 +:10DBF0008E604F0E39F07DE0329EC9C7B2A16451EC +:10DC0000E1C6D285B6AE03C94DF83ED1C80A2EE6AC +:10DC1000EF0F9CD7E052EDA7F4BAA079830E3E8DAA +:10DC2000FE23FD0F7D41E38F75C8B77B197C606FC4 +:10DC3000C03CFCE169FA73201AFCB753D981E7496B +:10DC4000DB54FCDFE10AF57211BC8DC57FD604EB15 +:10DC5000998BE5654327059867431C3EFD650E3BA0 +:10DC600027927E3E9C08E703966633FD35D03FC37E +:10DC70007E1BF0C53213E124366FB033CB34F94A42 +:10DC8000DEFB590595AFE9A3792A5F2558875179BD +:10DC90001BB6D922F57F9AF3DEF276AA3F3C567680 +:10DCA0001F8CDA8F36A2BB8768CD61F1DBD9C1D872 +:10DCB000FBD6C3390906B9F5547325799BCE6F6538 +:10DCC00036D3E7B387157C2749E3EB68B95498C38B +:10DCD000D6D197C3ECF18F5F2E7113C8A515AA5C3E +:10DCE00062E5C4136880F234937A2F4164EBBEF18D +:10DCF00047330A210EB7D56B96E09EC34ACE9FF3F9 +:10DD00002D3A4EAD4DEA489022F4514B6C920BF0F7 +:10DD10004D47807BAF35CBEC98873FB03BFEBD874E +:10DD200063F447A4A4DA71EC5A0D9EAD5E01C7DB23 +:10DD3000B8AB3029A887930F3C8BF13DA70AA72DDC +:10DD40004A5FF1C67C5A5AB8D164D695BB98FEEAB0 +:10DD5000F6CAE539605FAAE79BA2EDA27BB23983E0 +:10DD60001CD6ECA2DF79199F50FE45FF319DFA8F3A +:10DD700004EE7BF407F03C183C605488F775D9FB3F +:10DD8000C66F1D2773C14FD2FAB92BA7D8D06FDD4C +:10DD90006ABA489FA4CC69AB942FEBE4D919F57DFE +:10DDA0007A4A0F33815F57E710633B73201BEE9570 +:10DDB0009374AB1FE4CD29217018D757246E58DF18 +:10DDC00085E62D87912ECCC4DD86E7A48E60FBEA24 +:10DDD000BA9152B4533F308741EFFC3C3703E339EB +:10DDE000A94E46B7A7EC4DD88E275232CA1155EE30 +:10DDF000FD3C770ABE7FA1C9CFC87D16AD1F567EF8 +:10DE00008A5B910DEFC49E4A9D5CD2C619ED1DB090 +:10DE10007F22F6D2F3FB6EA7FC38ABBA3F4C61A66B +:10DE200052E5A5E58FD2FA5B7298FE3BE50B0CC07C +:10DE3000B8A7DC4404F8670F079F85FC62AF13DFC7 +:10DE400071D3D623CDC47E1F264DFDFD15E01348AA +:10DE5000C55CC66F8773D93ABEA3E6D31263FF9E33 +:10DE6000CC7FA8F57AE0FE1FADD75D1EFBDEE81E75 +:10DE7000958F1B6D3DD570955E77CF13EF2DF38495 +:10DE8000DA55B4CADE1CD60FD56788AFCACE3AFCC5 +:10DE90003DB1F78756E1BBAEA3BFF301EF54D17597 +:10DEA0000F9395FB01EFC22FCC787EB3C3C2E8522B +:10DEB000700745B88794E28CEDEF7E578527C5CC77 +:10DEC000DEEBD6EE2F58D4FBFCC7547B2CD15B8BFA +:10DED000721DDE58937CF02EDB08DECFD5D631FAEA +:10DEE0003CAE45BDC77FF3F643491CFBA1D4603F60 +:10DEF00068E346DB1117E13D6E5DBC7B9DF7DC42BC +:10DF0000A2ABFF6932DC01FD7D7A5B96212E11CF39 +:10DF1000FEF8912A6FC15E5062C22518BE5FA47ED2 +:10DF2000A0A21FFF0A1B3F32AE9328BA71F7E6C8C2 +:10DF30003FCEC1F8CD5C11DFB1B0133C0F5BA6BE84 +:10DF40005F47F513BE5748F55235C86FCD2F02BE57 +:10DF5000179380AFCBCFE6A4EAF4A4DA2E5A1EDDE5 +:10DF6000A1DA0177A8FA26E9BC66373A248E8BE855 +:10DF70009DB17A8B53EDE868F918AD178C7635A50D +:10DF80005B456F078CE11715AF374F1F93E2D0C782 +:10DF90002D7F11FBB26C6ED03C0DE4663547601FDF +:10DFA00064569551DF3B7299DFE1C8751ACEE1D610 +:10DFB000D419EB25423DE0AB5CE70DF9297A7DC42D +:10DFC0009941EEB1FE36ABF4E07BF7AC00EF372EB3 +:10DFD000C965F650499E9C9A4BD3237FA8EC83DFFA +:10DFE000A11869E549AF07DAC97DC31E98974D04AA +:10DFF0003FB57C6D55D1115A6EF9A905DF9D2427D7 +:10E0000062FBF7AE664EBE8FF273BE2AE71A3C6C17 +:10E010005E0D9EB05040E1C86C60F064F70F72BCBA +:10E020004EEE65D7B37AC5B91683FEF1439EC2772B +:10E030006BAE16BF0CB5C2EFA164D7CB3CE8BBCC2E +:10E040007E8EA8EF6EE27BA9997ED6BFCB1FE2EE53 +:10E050002D8ECCBBCBB4A218F445579AD30FFAE25D +:10E060007379C1329877C3857018D036EBC2100F20 +:10E0700076DFFE3C79167CD7E62799C54CD81F770A +:10E080005E60F0F544D13F21BBD575E965F0B9027A +:10E0900025004F5AA284EF10D1BF7CD0AB69C9AA2A +:10E0A000DE482341782F88D8683DB0831CB49EFE9B +:10E0B000DE260994C23E412875DA74D0730B1DFE2A +:10E0C0009336D0AFD37DD3E15DA1170EC78EA7D70E +:10E0D000AA7A87C27FA71EFE78FC31FADEBA5ACF31 +:10E0E00012C78FD6E8DE591DDB5EA59A00CBCBD7D1 +:10E0F0007AEE86F934B40BF81B5D1ADEF7E70536C5 +:10E10000E6A6C23A1DE1805F33FBCB91AE32159E8D +:10E11000805DD1EEC80DC13BB2EDC99F4A07FCC777 +:10E1200083BBA1D92CDFA7E7E77601D7E348D4F971 +:10E1300035CDCF782C97E9A3D37981AD30FEE613A6 +:10E1400007F09CE083472F09E3BDEB73A378E3EA74 +:10E1500099FFD2B086BD9751BE96473ADCD42EE0E7 +:10E16000BBEA0DCF1E0FE37EF17682FBA00DFDC74B +:10E170004FC33BAD590DF24CFDEF126435B077E360 +:10E18000D212467F1F5400BD9DD9BFA201E95A2477 +:10E1900022413A0AA2DD956D63F6A886DFD34238A4 +:10E1A00017E267A74DC4DF46CBAF59942289E6AF8B +:10E1B000F91C7E787FE1EF8FBF213D067886B81885 +:10E1C000BC7B9017FC12E0A3BB959D27EF5E48ED4A +:10E1D0001E5A6FA1936C85FCC2361701FEB8513CE4 +:10E1E000CC8AA28B59DB199FFC283751E55782EF67 +:10E1F000291DCF4D50EDA8601DDAAF741E9D731020 +:10E200002E9C87982B7F15E9564CC671331BC29CF8 +:10E21000FEFE899646E84A7E3637F566E0ECC77D15 +:10E22000C64DAA9C295F7B947B5B47072FE69A919A +:10E230006E329F3DC2817F48CB5B177AB03EC607E6 +:10E24000339F657ED3265A7EBF41AE6CC0F97439C8 +:10E2500098FD48E5CA4980EB94690BBEEF776A3AAE +:10E26000C17766EFB8103E8DE25985F794C0D6931A +:10E27000A77868A5F99FE54A38FE6921781FACFBAD +:10E28000E94C76BFBBCBB403DF3BD5F83E9A4F7F5A +:10E2900096CBFCC9CC3547398827789CCC9ED4E0F6 +:10E2A000D3EA95E4559C05FCCEAA1E423C34AEE16F +:10E2B000D97D0D159E8542A000FCB461B5BF93AB1E +:10E2C000BF6D3E44E16B2CE6909E9FFCBB57912EA8 +:10E2D0001B7B38F6BB413DAF0AAB74FED5C1EFBD29 +:10E2E0008A7A65E9008B1F340E1CE7EF7581BE3911 +:10E2F00089F4D948E9CF5E0AEBC6ECD86B96702E4C +:10E30000E8CB68FA745633B90831D742F60E1CEEE2 +:10E31000FF86D6DAD0EED7E4AFA8C209EF08827C38 +:10E32000FD8DCAEF5AFF117FD5EE07FAF6BD3BFD12 +:10E3300024BCEBD6E8E7FC701EF93F46F50993D7FD +:10E340005222FC7660A4FF68FCE5E631F91A438F9F +:10E350007C184B8F687AD6F77405BE97ACAD1FAFAB +:10E36000E27D54BFE7B1FB578979BC0A8FEC853851 +:10E37000B644F9B9BB14DEF50B144B809F54A71FAC +:10E38000E23B7FEF7E5DDAA0C3D76981F23BCD9F90 +:10E39000CE77203C942F92F274EBD750CC7E67EA74 +:10E3A000C9EFAE40BC36C0DA51BC3604EFBB0FF14A +:10E3B000EC25E231902F4126BF1AD6DCC5DE05D709 +:10E3C000F4DF731CE2BF4171E13BD74BFB57207D6B +:10E3D000128FDD5FC8A15CC375D6F84CCCD5F61D95 +:10E3E000D8BB43D4AF6F857889E6D727D605940488 +:10E3F000692C9FA6A87EFD4CD5AFB7CCB6FD59FDC4 +:10E40000FA4DCD3F41FFE721EF8F30D5F884FA8DEB +:10E41000067EBA2D8FD92D929A56E431BEDC54DA9D +:10E420008FF4BFE97213F28FAB9AC911D705A3FC21 +:10E43000D3E260D4836374E8EC5F04FB110BBFC2CA +:10E44000892007E2C1FD19AEE967705E851C67E7A8 +:10E4500028167CF0F344FD3BA435798CBEAFF599CA +:10E460004918F0CD3709E3D9BFF1FACB0957CDF9F7 +:10E4700027BA7EFFD29784E782AE3DBBF2F3905776 +:10E480008E26E139929C702DD2C535CF1C3FD081AC +:10E49000A78DE1E95A7F25D2CFBBE99209DE096B4E +:10E4A000ED7F623EFC5E74BD0AD7BBDF3537031ECD +:10E4B000767CED3BF3E15DC94D212E05EE9B5DEBD6 +:10E4C000FBCA1F41EFD51F7D18CF7DB57DF37FA11E +:10E4D000DD6D0A1D61DFFB9244A877F59903F30116 +:10E4E000BF6DFD6D58FEEE3347307FF26BDF311F9D +:10E4F0002A8DD0F1BBDF3DF2C3DF433E9088F77237 +:10E500001A824F3E0E79529BC8EE5D055F11F4BF33 +:10E51000DF75F0F820F2A146174BFB39F5DD30012D +:10E52000CF7968F4FB56457119F01DA550BF793EAF +:10E53000CD7727D4C78A23EE51E7DB00B408E3AEDA +:10E54000E142C0075D82D287F25CECCF0579EE2C08 +:10E550000E0BF02EE9EABAE3F3D9CF10B662F94A0E +:10E560001B3B2F368DF20BBC1F457B3BFA21C4F7BA +:10E57000BA1E5C07FD1D3613D19C118177B320A113 +:10E580007FB4B986F3530E231CD9762A15F6C79AA1 +:10E59000897AAE8BD5EBA2EEA52D19F510B1D3B4C7 +:10E5A0006C5BEC38E893792E953E19BF660EACC8CB +:10E5B00006F9413C567FA12FD25FCEF9A66E78DED8 +:10E5C0003FB37E6811CC6349D18619300F0FC4FB6D +:10E5D00040BF282EECBF11E293949FBEAACAC73455 +:10E5E0003180EF8CD8E4402AFC269B640DE0396E24 +:10E5F000697DC0D20A72861FC95D858AF09861FF65 +:10E60000F0A025983113FAEB52F5D351063F6D8FE8 +:10E61000FD4995B207DAD3FEB13F5B9DCCE36FBEF7 +:10E62000D9D83AFCEB0F6E3F668C9787C6F45FEA49 +:10E6300002FDA2ACC17593049CEFBB5015F1ADDC9B +:10E64000AA8F6347C77B409EC17EEFE9BCF2C1BC85 +:10E65000D448AAC581A2F1CC4BB49CF65321C998E9 +:10E6600092BE1BBB77A6C9EDCD7B54BDFBE22594C2 +:10E670003B9B833CD3BBC1CBA877FFA545266F53FB +:10E68000C3F2E0F39790BEEF3DC1F4EEE61325022E +:10E69000D0B3F61EF2E68A6BA87F153341BADE2CA2 +:10E6A000F49FF642FFDDC44D2D7BB279FEF02D20A4 +:10E6B000FF7EFDBC7D0DB43F653221BD9DEAFDC4EA +:10E6C00091364E0F1FF303B8FA10F2E366D52E28E9 +:10E6D0005F7BDF01F0C71AEBD9EF116C1E50F98B8D +:10E6E000FA6380DFCD275E45FAD1EC5EDFD3354893 +:10E6F0006F6E4A6FF8BB095543081FFDF317D2D45C +:10E700005DC5DEC55D52545206F47672F50F778210 +:10E71000DEDE5C4544E8FF608EFC3CBEFFFB3C87D0 +:10E72000EF511EB4F454C03DC9830B2511F8637337 +:10E73000B076543FE1F9EA60ED00F28F679D1FEC7F +:10E7400087EED620DAD5DD194EB40B0E3EDF8AFAFD +:10E7500073B3E4F0C3EF992C3DC16DC5F68A8B30DD +:10E76000F839B4F397866EC3735B1A3E96560DE77D +:10E770003279C1E0FEB565E8D330EF5F7FCF0A6F35 +:10E780007E8FD2DFFF05D640AE560080000000002D +:10E790001F8B080000000000000BDD7D0B7854D5B6 +:10E7A000B5F03A73CE3C1226939327E1E9C90308EA +:10E7B00098841308EF872704102BB583F2B2220E3A +:10E7C000C823424846C48AD77E37830331526F6FCD +:10E7D000AC2FEAA576A06AD12B106DAC51030DA821 +:10E7E00014ABB5D1528A16BDA3222F918CE083DEE3 +:10E7F000D2F2AFB5F639C9CC640262EDFFF9FFE998 +:10E800005737FBECF7DAEBBDD7DE9336D9BFF18E85 +:10E8100032802BD561BAAC03A42B6DBE3B3201D242 +:10E8200000F435986FB07B9D3A9647FE430A6DCE53 +:10E83000C5EFD3C0081501E4DF23192137408A262C +:10E840000164516A335307C008C0BF0691AA811200 +:10E850006F31C027B5067C3800F84FCB0658CEFF85 +:10E860000058B1A8D5A1617F554F89FE329D46E978 +:10E870002D989EA3BFCB305F013778B13C4B966E8D +:10E8800098C1A98D53ABDC4A8799F3C87D64E1BD7B +:10E890005370FEDFA9043D0987E85D88DF310F7EF4 +:10E8A000080DC0F9F7AEF4F6D5A83C73A92E633E67 +:10E8B0002B03BE4FE591350ED82C75ED7724AD6B4B +:10E8C00004D5F39649582FAB678A1EA4A1E4725B66 +:10E8D00012B52B95F4CD1AE5AF7E14084E59BD74D0 +:10E8E000EA072064C2C15B66C37A47B353F4F5F408 +:10E8F0003DF407E56A84C7244DB5CA4BA99DE601DE +:10E90000585FDAD96E4ABE97FB9BD233490FE23C7F +:10E91000A737044A204FC0C1EBEE8443684DF2DCB8 +:10E9200050143CC6131CB07D6830CC6D2C22F87B93 +:10E93000ABA89F6C9B9EB11E3715DC81926B526811 +:10E940009C20C36B00CD03D329B83E3FF59BEF5D00 +:10E95000C5F0C84AD113C163CF25021EBBE76C9333 +:10E960003760BDEA2229E4C4F9DDFFE28C525A6720 +:10E97000F54CB70E98AFF6290B695C08B8E031CCBE +:10E98000836FD1BD53305F5DE9D5D76BBCEE455485 +:10E99000DE3733495F8FE50F3E2F1994AF0EB84332 +:10E9A0004998BFB259E04375F3D3CA8D98F620BC9D +:10E9B0007353BB40C98CE2CEF900ACE1F9544F3A35 +:10E9C000D1FF656C1F9041972762DE111EA8E3FA04 +:10E9D000AB27860712BC4E3E9F3497DABF62B30561 +:10E9E000689C57365FBA292875EDE7A4DDDB44EB58 +:10E9F0003F89EB0F60F96F9FFF7388E8612DD28329 +:10EA00009C837BB4462BA7F2F55340A57DB1F66BF2 +:10EA10008F23504878B5272F99F183E6E945381FB1 +:10EA2000A77FF602B8F5126F8D8670AEB6B5D629FF +:10EA3000D46E4B06C018CCBF70F7409FBB2B9CB167 +:10EA40003DEF8B4B01C65F57A847281885572E17F7 +:10EA5000D2DA304E036E4C7BAC16F089EFE74ECD28 +:10EA6000CDFDAC7085F7E0CE41CDEA065736E29198 +:10EA70002F59E3EF49F680D107E7E3682E6FED8366 +:10EA8000E5D9E9F81FDAB7CD3D42B46FD9D9E07BBB +:10EA90002641BFAB4C3CB3F6A5211D182FB33DA2B8 +:10EAA000FECF4DBAF98949975BCC348A2E62F1DEEC +:10EAB000EDCB253E919D0CBEC604E359ED717E5C05 +:10EAC0006ECD0B5CD84F26B5D36C8CDF717417CA32 +:10EAD0002A1E4674372559DFED227A1A963B2C08F8 +:10EAE0009DE320247267A474C5035A07D10FAD8B30 +:10EAF000E8ACBB7A0DBB047F8AC7CB674C3AA9222E +:10EB00005CC7796F93901E13EEB3E8A7DE966B7B1C +:10EB100010E7FBA3FD32F3D9F87A56BAAB16A0750D +:10EB20001040DEC66B53BDC5DDD7DB66D6FB71ADCD +:10EB30008B53B7AEAD51B0FFA12D5AA90C349E3600 +:10EB400089C60BE078B4CF2913E15319E1E319DD4D +:10EB50005078672EE179E35C5AD750256C2B25BE9F +:10EB6000EBB5416BA1E0DFE7F0FF3DE72643ABAB40 +:10EB700033DFCB971E93EF53D93BA67E3F7F5E4C8E +:10EB8000F925AB87C494E70686C5E4F3EBC7C6D482 +:10EB90001FD03029263F68C37762EA0F0E5D1D93B0 +:10EBA000BF74CBF763EA17372E8C299FF48FFCDDF7 +:10EBB0003F253CA7F527E073561AD17279FF8636B8 +:10EBC000C7AE3F7574ECFA158800D1FBA4E4BFEA28 +:10EBD00089E8D94A5341F92C6CB5233EE0D26C0F39 +:10EBE000E23CCAFF2C87D627988785CF567E922293 +:10EBF000C78C6BF1890BE1579EEFFCF8F263C217EB +:10EC0000E779E6FD0F39215DAAB9820F28E0E5F525 +:10EC1000A74E9C7BDEF5DBE3D70F1AE3BD87D69FBB +:10EC200000EFE3D79F3A3A761FACF5E7F90637874E +:10EC3000B19FCFE74A2C5FF651D198AEFDBD1BB70F +:10EC4000CED9AB52599F01EF3509EB77CEE34E9EFB +:10EC5000C7F54EF02782C374130E95B982DE2F4498 +:10EC60009FEF9BF3F81FA24F4CDD6B73991E619FC2 +:10EC70001C1A805D2DAC9776F544BC48F7B9592F26 +:10EC80005BA8B44269949CBFDFA4EF074DFADE5045 +:10EC9000AB723F0FD7E670BAB156E3EF8FD416725E +:10ECA0001AAAD5F9FBE6DAD19C3E8AFA18A58FD7C5 +:10ECB0004EE3744BAD97EB3D593B97D3A76A7DFC70 +:10ECC000DDDA9FEBCDFD016F06CBB3F8F5CC5F9598 +:10ECD000182F412EE2F6F391CEE4F3F0B52EEDE5D8 +:10ECE00079A9E7C3A3D50773B7BF1C8507D7E5A6E6 +:10ECF000641EEE81FF1805A3CEC9176EFF65ADB681 +:10ED0000FD65FB85E9C2C21738FBE18044F5AEA77B +:10ED100031C722BFC9DDDC1070770F9F4E3C8AC31C +:10ED2000572FE22B7E2D21D9DE8BCAC3BDA3C7F995 +:10ED300093B9CF567EE64C81AFF1FDDE6FE2DF2C5A +:10ED4000C24F2C9F1D47AFA77385FC3C9D2BF4F44D +:10ED5000FDDDF08B7B726DA6FC14FB3E6B9FE04BE0 +:10ED600077F6983FC197605C294F8BA1CFD9336369 +:10ED7000F771BF5DF0B7FD7F92436B12ECFF85DA50 +:10ED80005BEB896FF72773BD9FFE7F466FFBAF4D2F +:10ED9000617D7EBFDDD72F2B6A7FF65FDB636EA2BE +:10EDA0007DFFDF5CBBD8AF421548BE433A18A407CD +:10EDB000E192020ED2E5A0403D4C7482C610D145CE +:10EDC000F778A9C0618B9E64826712EBE39FCF4CFA +:10EDD000E1FD079F6A4054FFA0A8AC976EFB2EEAA6 +:10EDE0000A349E82E3A11E0ABAAD73FFF2E8BFC9DE +:10EDF0009DFC5AEE9EDE2E8407161F994D7CE43C46 +:10EE0000F2BA6BBB8BE32387888F5CFACDF3118B4F +:10EE10008EE1EC8D03BC295DCB67111FE90DF0D3AA +:10EE2000DCB7998F7C6D3859746BEA13F1FCA4DB65 +:10EE300076CD9917907F263F57FCF561C48BDBE4B4 +:10EE40009486F5D8E42EC5FF73CA07020A3C86A94A +:10EE500073F5E9DE878673B7850AD71BC2F69D5323 +:10EE6000F1FF32CCF6A053A57A0FF5F8F7ED945FD9 +:10EE70008D1CD389E99749FD4380B640699EE03FE8 +:10EE8000B2EB4CEF4351F3B3ABD0273A5FDAEAEA87 +:10EE900073286ADF86EF5563F223DA7262EA8F3AEB +:10EEA000A0C5948F0917C6948F3BAAC7E427444690 +:10EEB000C7D4BFEC8C11932F872B62EA57B866C476 +:10EEC000E4A7A8D7C6D4BF3C67414CF915DA4DB1C9 +:10EED000FD157887E7E1BA173ADCF5522ADA69B905 +:10EEE0004619E59393ABFD0BC84E5AE3516122D509 +:10EEF0000E85086E750E97BA1EF9D40792D11F10B1 +:10EF00004FEFB3A1D59D8FF5E530507AD0A697523B +:10EF10009A676CF1119D6E2F4CD6681F920702B450 +:10EF2000919C52F424407EE2E811F95D01EDCB6F33 +:10EF30006CF01826DB5554F4A97E736688ECDFACC0 +:10EF400064DF15348FF5B606CF1ADA671B781FCB4E +:10EF500064BCFAC968CC1F7E41B1119E6D6FB1DDF2 +:10EF60003316F39F61F7329637B59DF8C995981F10 +:10EF7000DA66D7A9F65090D94E5CAEC03D4A7AF712 +:10EF800078F6F10F843D15FFFD677982DF6755083C +:10EF90003B33BEFC8E3C21DF3E76242E5F6EB6AF47 +:10EFA000B86BFA43C4D7EC6D7620BFC5AA2CA32753 +:10EFB0009C4F5F3D930FA1E15179C50BAA9BBE0FFA +:10EFC000E4EF1577CD83B05BF4437EAC5549464FF3 +:10EFD000F23B7C3C29F13C6E31E7613FD3A39B7E41 +:10EFE0003DFCFDE3BCF3AFD37E2609421989DABBB1 +:10EFF000F97B563071FB7BCCF13F4E4F5C5EDFD12D +:10F000007F2F086444B7137CA7739CBE5C6E3F934C +:10F01000068184EBC8E4EF9063E410DEEC423A270B +:10F020007E519E96ED0024F1F91079C540F8CF206D +:10F030009300F1145C7A29F12950EC91B04517281E +:10F040003F1680F201D90B3644C67338B51B56DB28 +:10F050003F0847D1D10C23360F543F4ADE7C427D16 +:10F06000E37A928714A612BE9F022D554D805F56FB +:10F070003ACF257B95A8F51CEC464F6A33E178B072 +:10F080005762383E6FF2B191F320A1BED696E711D8 +:10F090007659A1DEF37C7283E0EBCB88EE377E1FDE +:10F0A00032B9FCABC219F182E57AE4BBEE10FB2960 +:10F0B000BF71785BF8DD27062F3EC98F9F777F2EC3 +:10F0C0002FE8EB7D2B8FE58A3690E4629349BF4DA4 +:10F0D0008AD163989BF8185426827F9F7C534F8D6A +:10F0E0005B771318390BC8AFA1D875E267C932F83E +:10F0F0009F4E00FFF875A79AF3C6F6735BA93D789B +:10F1000074C1E7C0EBCA463D9FFE854B280FBC6922 +:10F11000A7FEE7F93DFA7A54813ECF13FAF40208CC +:10F12000DB890F77819F3BD34E7EDB78387A419B1A +:10F130002FE55F189EE905C6E7041F9B4BCDDE8ACD +:10F14000EB9C1FF000F9696E98079E629C8FEFBBE5 +:10F15000E96F185877E155434AD6527AE9F83A9957 +:10F160005B4F66BD4F0AF491CF5DFAD5F5BE3A8F7D +:10F17000AF90E8E390A42D61384808079237BD8F1F +:10F180000F5C1005C715FDCA7F9F9F45E7036064AC +:10F1900090BF788793FD56B001580FADD9397813D9 +:10F1A000C9852FF27DAF51BD51934DFFAD11197837 +:10F1B00075CAC5C30BFFEC44271782976CD2FB417D +:10F1C0004F62BC19972FF6EBABD24B66BE8043045F +:10F1D000E1B0B9EC9BA717845F0CFF782D5FF05F5F +:10F1E0002BB5E0366A5AAC7FF735731DAFE57B3837 +:10F1F000FD22DFCB706EEFF7E9E12492FF0E5C7F1A +:10F2000002BCF7764337DDADBF3B7AF9A6F8F2C111 +:10F21000E4C4F35CFC2D99E71B344FE2F32589E746 +:10F22000F96F17894FB83F4B5CF9DFFC3CBFC8371B +:10F23000DEC8A779A6279EE74F2F129EC8EC96B48A +:10F2400062BDD9C807A9DE373D5F082C984272E835 +:10F250001A9FF0FF1723C7253E845379F4DC70D240 +:10F260006FF5751B88EFACF4E80195F9C81BF982BE +:10F270000F8281F399394D627F52FB884F97288422 +:10F28000EFD9D09A46FC6AA793FDD9F1EB0F99EB21 +:10F29000473A799CE004D32303899F1C1C98984F1C +:10F2A0003C1E5FBF3EC2F2697D7962FD749B49AF2F +:10F2B0002B5C0DD3B26DD1E72BB84099B86CC0E888 +:10F2C00043F2B64C5D4BFCC4817289E0EAE833A49A +:10F2D00027ED07E6BD12F981735E3F207918DE271E +:10F2E0003AE097D739CEF1DABD6A81BD7B7EBE5C4C +:10F2F0007E66A43FC17AB66ABE5DF95176E3F22D0F +:10F30000AFAA05D1FE7108DB800547C4E6E5F341ED +:10F31000D36FD0132ECA6F509C29E865453F2FCB81 +:10F3200007921B643FD7BD30A6943617F50F20FB1C +:10F33000209292CCF222D87B6CA11605CF0FF32D30 +:10F34000FD53EE46AF74C47C7FB7D685266567FE55 +:10F35000FAA3FBA6903E3F1FC2EBA8FEFC553DE87A +:10F3600008B2639D1DFD9D9162F4DBCEFE15FE5E2D +:10F37000EE72B7CA433175FF2EE17E6CD58CA304C3 +:10F38000CFB5FD8C63B4CE78F805EE1A9FC67E0427 +:10F3900082DF655DF7BDBB7DFEAB669CA6FE5EE8C9 +:10F3A000A75A7E1D9DCFE392ADF361453DECEA8403 +:10F3B000F757DD9764D3BF88FAC4399AB701557EF1 +:10F3C0009ACF3C8BBEE3F41C2814FE803A4FDBBA84 +:10F3D0005D517478832D9225E476781D3999FE6706 +:10F3E0004712F38FF61DBFEDE7E3F3344BEFE8214F +:10F3F0009FEBF1D5E767F917ECC989F569EB1C6359 +:10F40000B7BDA880F5123AE71D8D79495B44F6AA8D +:10F41000A2821EC4F5955F8ED884FD4D92FBB68402 +:10F42000711D9FC3D9E40998FE2788F5AF7AF3A32D +:10F4300074F2634E52ECC7A3F953BC1F684041AC51 +:10F440003FF914CC4B6D25B88C4F67B86C6F99940D +:10F450004AFD943C3FB927A5BB6AEB55C5DEE90FD1 +:10F460008A9F7F793776E9B002A177BE9E6C0C2B1C +:10F47000C0B4BC9BF58F32EB85938D5105599DFD32 +:10F4800051FD44F1106D832C3FAE80EB358105AC0E +:10F490006FD95CC857897FA2FE2AABE4272CB03312 +:10F4A000BD1BA0A9D9EC3714FB8F7C5DC1FC0433D4 +:10F4B0002FD5BF1DA4761B6FF1F03938F83420F931 +:10F4C0008080E173813AC9CF7E0717C57D60BA5E3F +:10F4D000D237902E26DB2219822E4222AE017C0AE0 +:10F4E000E57F2B85831427B0D6F5EF3F273FB81172 +:10F4F00054206922E615603F63E0600A9FCBF1CC9F +:10F50000701E4E6B5E663EC5CCB7CF9A3A6D00A6B4 +:10F51000B7253FE2213C0D4BC847B19F2F93FFBD5C +:10F5200095E9C69FACDB7B937FE93DCE4B2B937572 +:10F530002987FC4F9E42D2535743B2EEC4710C77D9 +:10F540007180C67568C0FEF86468E475B8DD9F0414 +:10F5500008282AA812DB4FC9BE65056CAF009F932F +:10F560001F7E2F6533AD3F493DD57A077ECA0083A4 +:10F57000EB65C4C9C72CF72A89E337BC4A9C5CF405 +:10F580004904FF9E73E3BFC7CA4B171C54899F48A9 +:10F59000ADDE9C73C89FDA086E659D706B53845D09 +:10F5A00067C12D30C9FF4B826BE04EA71ACCECDE51 +:10F5B000DF86001A45FA789BBA642BD547C3096CDD +:10F5C000D45F8E585FA0D229F641F16DA5F6EFD831 +:10F5D0007354B27B2C3C7B68A0C9AFBBF1773C5025 +:10F5E00020F4A3EAF4C3D524E70007B5F50738995A +:10F5F000727424F10D9497F5242F93EC06C3DB92DB +:10F600009B2B9AD600D15575F30220BEF28EE41BD7 +:10F61000F032DB23C076D99C6981576C1AF9B26647 +:10F62000AE7363FA49411EE3D7FE57A6BEC26C48CB +:10F63000761753BBD2CBBC53B270DC6031E8776233 +:10F64000BD60926FEBB3B4AE3765FD318DE2212A18 +:10F65000E0C3E12632E1F74DB333D86F9A5911A9CF +:10F66000A37881C8DDA0527C4F17FA388BEB1B09B9 +:10F67000F00B1E0BFB59A4B612FEF4427C93D4CEC1 +:10F68000F247A93C5FE42FC37C8DD852C86F29FF95 +:10F69000DE0882479B0C141655D322D968FCFC99CE +:10F6A000C359AF29A0F2CCE8F2B4E54F61BE60EED9 +:10F6B000049DC849B3F97E762B95BF01BC0E30F985 +:10F6C000F7A838FA1DD749375C5EDA91F757D07C36 +:10F6D0005FB919D88EAD31E56D0CBDD162B1CC18D2 +:10F6E00049F8D7D10F503F15667E9CA2723F7DFD31 +:10F6F00060F205EFC607F89CC0A6937FB24E6A6021 +:10F70000F840C0CFFA1EC5CD10BDF49FB76BB79DB2 +:10F7100006CB1474A7EF157457065E99E03552BDF9 +:10F720003B48E3CF9997CB7C66CC5160B830E5611C +:10F730007E429AC4FB943F209FF165BC4BAF97116A +:10F740008F64B9343F09C79B3B4FE2F38959735D1E +:10F750002109FF390BE983E3A1145FEE6CC4F7398B +:10F760003E499CFB627E5E943F1EB5613E379BED39 +:10F7700004FFD309F0397F80C077AB7DCD5A478C29 +:10F780007FE792016EE1E71830F59302E6BF22AE03 +:10F79000252BD91B117CA381F9D4611BEADFA4FFBF +:10F7A00082C1FAF63526BD5BFC6296710BDBC1B3F4 +:10F7B000BCB17AF43BB4274407D74AACE7CE997B77 +:10F7C0007E3DFB5C8164C6DDF455599E99DF35D0E2 +:10F7D000D89EBE9AF49C12FC380DF59028FD7EDE72 +:10F7E0006D67D3B87ECFC7579CBB0451A152F09729 +:10F7F0001A8427F1CBF26B15A697EAB50E8EFFAAF5 +:10F80000695E63CF267CFE21E8025FDFAFEB83F306 +:10F81000EC53658C90B528BF4D554822BACE269E34 +:10F82000C3F08F38C82F37DBA157D1BA66A7831A28 +:10F830004843BCBCF68A8DD4FF5A17A832CADBDE17 +:10F840002D6F8608AF9095EB849388391CD7D657D7 +:10F85000EDC1E70BF5B6611CB755EF49D1A3E3A4A1 +:10F86000D6AFE9C43B8AD7D29C304C35F737919D4F +:10F87000346480E0570F4AC0F22270AD8BE19C9552 +:10F880002FE295B2527547308DF88D66D5E338BBBF +:10F8900007EDBE5EC3310DA15A29F647B48BA7FB15 +:10F8A000AC0CB39F1E9A1444629CD9525A6623B87A +:10F8B000B953748A4FB4FAAD4836ECC4B72A8648B7 +:10F8C00023820CCF4DCA22D24F9362F9BEDD2EF6B1 +:10F8D00005DE157C3F5E0EA21C60BE4F7EFB6019EC +:10F8E000CBAF8A01592C0FB89FD58A4B75EAD0450A +:10F8F0009E657A2185FC5CC31064A4AFB7E5786788 +:10F9000050FC5EE07585FD6A6573F5EB1647EDEB1F +:10F91000E60E391099CFF1503FD4FB503CD4DAF2C7 +:10F92000CE3CC53D56428383F0BD324E3E2E73BF62 +:10F93000CC7AE4B247ED9DF80B1427AAE713FFA891 +:10F940007AAA8B3F88F954273F8BB32F417D89D604 +:10F950003302F931F121A3204566FF32CC13721432 +:10F960001E97C82F267B56D793DC6B97521AE4B2AA +:10F970004E3E39C2DCAFBB14EF4B141F1B407DE978 +:10F980003115BACA01F0B3FE3211E526E9D152CBE6 +:10F990001C99C6DDB814FBA6F37C255C41F9DB9607 +:10F9A0008A735208DCCCE760E3024E95E8FFCBE4B3 +:10F9B000FE6BCD71FD7664D6C7D41F727F80FB428B +:10F9C0007A8B44FC10CB7B4FC3A64807E35A8E705A +:10F9D0007F1B33045DC4EB312FDBDC219B8DF86E84 +:10F9E00080E54E128472087E4681E0B36507049F6D +:10F9F0007D2E801AB44CAAACFF9AE9B9AC0772F913 +:10FA0000D80870FCCC0EF0559BFACE5D034650B47E +:10FA1000A85FF071535FB0F4B82971FB78B9FB7E31 +:10FA200085F8D6E5395DF64BA6FEA781C4FAE21546 +:10FA3000DAF9F99661F12588E54BB97096F70FEE82 +:10FA4000DE732BF90982717A50F022F5A05EB9BEFF +:10FA50005FD0FAE2F5A1EEE2299F1A7071F194A845 +:10FA600041CC27F935D6B2B3E2F0A77ACFF1F9F756 +:10FA70004027DE75E07360D375B40E94E72AD97D14 +:10FA8000D26F1E62BA5E8BF5E4F104CD83C1FFC272 +:10FA90007CAB0DFC14AF003EF534E1A92577911342 +:10FAA000319ED42D1678374A11F9BEA8C8125E06C9 +:10FAB00047C7EBEBBE5CF2471B65C51C1F6BC9E378 +:10FAC000E13683F16404E81954CFC2939161518EF9 +:10FAD000F8F11AF19371D3105FF228CE76541FD249 +:10FAE000BBCA4163FC288F936B15EE990AD17985C7 +:10FAF0002B7EFF0D3E779C6CE2C714F5EBE1C7252A +:10FB0000841F96DC423DF9AE38FBE2AE38FBE22BB7 +:10FB1000E0C7918BC18FC845E247BBFD87EF05CA9F +:10FB2000D89EF5CBFDBBE287D472DB927B88DE8367 +:10FB30002940FBFE74925AE1C679D6548AB8F3E1A3 +:10FB4000BF2F08523E7B452EEB854FA7E92F71B999 +:10FB50005F9497B519720AE6F3576139E69FCEF5BF +:10FB60005650BE66359663FD11FB7C41CA17FC50AA +:10FB70009497DEE97F2985E47C40B47FE1589DECD1 +:10FB8000C1F2509DD9BEBCA182F235F5A2FDC803D9 +:10FB9000A120E507DF23C6B7F4CECB4CFEF9B47441 +:10FBA000EAA5DBA93FE49F9B917F8E3B61946EC3E6 +:10FBB000FC22D56623BC5D1C09D8091F0EDBAA46B2 +:10FBC00012FEC0425F0EE19993EC56B9937FD9C8FB +:10FBD000A983ED262A76D6FB5E95FC0AD59B4624A2 +:10FBE000417276B4EE22FE4EF1C89B51DE1499F2BA +:10FBF000C88ADFA57B0433A2F6AB68A090F356BD9C +:10FC0000EC748117F0B0C00B2BBEB8F52190C8DFA3 +:10FC1000426B633F449778633FCBEF50BFE2618410 +:10FC2000B797539C31965F3E56C419979E3B3D351E +:10FC3000915D347CA0B0E78F9AF722ACEF95A15C80 +:10FC40001BD1CFD3843CBD099EDA1F495F7A9AC687 +:10FC50001ACB200DC068DA47912F7FBCEF7DF57D70 +:10FC60000196DAFC0AE111F497749AFF556DFEC90A +:10FC7000BC9E2A80EFF54AB00E53DE2F093A368B30 +:10FC80003811C17F6699FB764C9DF7CAED6C3F7BBE +:10FC9000743B8E3369FC00A6FB9973258BEEBF3352 +:10FCA00090F4603AC1607FB68FE3DD6F8290830687 +:10FCB000B9298EEE97BB3F7B8FE4D2F22DB174BD94 +:10FCC000025A1DC2DF1C79E46DECBF72438A4AF20E +:10FCD0006745636CBDCA0DBF3F209574E50395165B +:10FCE0001F08C5F2015438041F7868089F7FADCC07 +:10FCF00091B54319E4FFF0B3BC4F0221EFEF52F48A +:10FD000030D35F8B53D851A67E7E9B2CF4F32470A6 +:10FD100069EE42E2C336335E55E4ADF1212ECEE505 +:10FD200054C3CDCC6FAC78180420CBFB5381CBD51A +:10FD3000683F5B079F8FA3F7D2969EAD74DFC0F23A +:10FD4000B3A07EC0F6152C424E378EF910EF9BB44F +:10FD50000CFF3F86D6E5E0753DD4A33FF3F7D548C9 +:10FD600010CE52B28B95E256EA7388A02717D111B4 +:10FD7000F1F769B1F65612083D7E789BF0E38CE806 +:10FD800094FB75B4BF4ED05D42EE3700D157B7F645 +:10FD90008A7B55427B852514F63F7B9AE0EB17B2B0 +:10FDA00057BAB3473AF63309F5364C67FA92B6D3E9 +:10FDB000BA2F3B9B9A92289E6A66B9EC25BB6CA62B +:10FDC000DDC84A4FA0E73F60EAD91DF57D6EEE4FD2 +:10FDD000F1656CA7F825ECB795F87FDBEB8E8471A5 +:10FDE000C98AD9BF6237D444FD5F454EA9287FBB7D +:10FDF000E2CBE67EBF017DE579DA977879E4D81D1C +:10FE0000774E098181D171054F0F12FC6E4281F14D +:10FE10009B81744E94D49FF99D568AF6541FCE73DD +:10FE20007F076FBE9CE3243E03E38271126BA3FC49 +:10FE3000E707D3129F8BBC61F2D7148A7DC3F47697 +:10FE4000CDF8038D7FD421CE5D8E269BA9479C5B88 +:10FE5000BDD3515FF0C788C5276DA2FC687AEC79E5 +:10FE60008D55EF94D9EE50ADCBBB36CAFFAA3DE419 +:10FE7000F4939CCECA37EF71AC02B69FDB9F4FDB89 +:10FE800014BDAF670796A70CA2F8A27CC3D18BE084 +:10FE9000F8BC907FD54AD841FBFBF025BEA334EFD8 +:10FEA0006A0D8C67A81F2DECB8A698EC06111FD21E +:10FEB0006E1776607B9248AD799D1D382365109D45 +:10FEC000CBDE1C66BED8919F1166BE7776A097C721 +:10FED0006D9F65959BF9FF10790D549DE65BEE32A1 +:10FEE000ED8742752DFB5D51EF23BF4DFCF901C03D +:10FEF00078A11F9BF19E46DFBFF3395E777E7E9B24 +:10FF0000ABED95FFC2EFF34D7FB0AFF9D357EED015 +:10FF1000187F0ED3B80B4249C071DFFFA45FBFBD8D +:10FF20005F1BAF677D79A4FFC3651C2FC07EB5152D +:10FF30002DBF65BEBEC2A2FBA658BAEF65C2F14294 +:10FF4000E76AF1E72DDF009D0D1C9440EFFB35C9FA +:10FF50006BC4AF29F274E66BA79A24F68768D05673 +:10FF600047705E29897D59F9EA8D150ECA2F0695CD +:10FF7000F97C533C3FF305494F585E0F2CEF4A2163 +:10FF80003F95E05DB357261F02DFB7D1A2F824DD0D +:10FF9000B7D1A2EC62BA6F139DA7FB36D1F5E9BECB +:10FFA0004D7439DDB7892EA7FB36D179BA6F135D51 +:10FFB0009FEEDB44E7E9BE4D747DBA6F139DA7FB4E +:10FFC00036D1F58F80FFC1F112C175E206826BD385 +:10FFD0001AA74A70C5ED7AAB289BC519E31FDDCB84 +:10FFE00089EE67B967AA6305C2614F8E0CD268BA01 +:10FFF00077B32CA6DFE57215FB0950ED6039E2C737 +:020000021000EC +:10000000FF313CE522B6933F6F962003F175E986F8 +:1000100038FDA1E5DE3AD2B76F0AC57E5F0E517E8C +:10002000F7DCAEE7404B0699F1C0BDA137E1F31410 +:10003000D9ADD33E9FDA27EB4E305D00B4CF5B8560 +:100040003FB214063D349EF7D10E218D8E4744F900 +:10005000A98D722890DB793E746AEFAF0EFBB0DE9B +:10006000D25EB24A74E7CC89DDEF242D76BF7B14D3 +:10007000C6EE778A1EBBDFA9A363F73B1ECE694697 +:10008000ECFE833C9DE1BCBC0F9A77387EC6B45829 +:100090007CB0E03B1AFF27F05563F82E41F83E2C68 +:1000A000D1B9DA3D7BFA685DE15CDD7CAF83F4D7E2 +:1000B0008B85F37D7170FE1CC657B819B830D335E7 +:1000C000B2535F2ADBEBE72081636ADF0AF35EAF9E +:1000D00038DF31E18AFA0BDB0B51E750F5B2CCFA8D +:1000E000CC26A267233385F980BEA107EFD73097CE +:1000F000E86F31F8983F2D8ED36B96BAEF77905E0C +:1001000013BF4E9A0DF95D2A5B845E13BFDE2EFE8F +:10011000A842B5B58FE0DB8D0FEBB4CC168B4FFB4F +:10012000C88F91096D0ED263BAE38333728C5F93EB +:10013000DC402E06040F610AF05F427DB2A6A35890 +:10014000F8E79D7EE1E787401ACF6314887970A3B2 +:10015000287FFF2825C47E073429D8BF64D963F1DE +:10016000F084BED2DAB7B05FF92530E1A8CB92AD0A +:10017000D37F8F56A041FAF5C8CF84FE34DAD51864 +:1001800054B4AEF6F927F9E639B762C67F5EE01CD3 +:1001900092E64F7E8E6BCCF8BB092DA35EA17CC787 +:1001A000B9E4CE57FBD07E8DDFF9FB0C4ADF92B469 +:1001B000C7EEC0F1AF96045EC4DB95C11DE334DA2F +:1001C000FFCB242FFB2BA682BFAFB047423CAF89A9 +:1001D0002E1FEBB5369761E7F328D37F09109E4AAF +:1001E0007AFA32DDC1F358AB7E3095FC31CBC1F4E5 +:1001F000C734C7EE5F177B28CE0EAAC2FDA77EE3E9 +:10020000ED9E047814170F102BEF17145AF7CA45F8 +:10021000BC8A06E2FE77A5E947AA746DF4887338B4 +:1002200094737DA18BDDA410E0C7F07985BD90EDBE +:1002300062B407F8BC5F73248AD7033593CFD56FB8 +:1002400074CF64BE7C637D17BF0EE3F5E2860BAC12 +:10025000CBD413C6D3379CFFE1419A90FBC9D3F7A7 +:100260001A545CD6D63F5A9FAD7188FBB9E0CF884F +:10027000B9B730B8509C7B97997A53A5CB8453611A +:10028000A08EF4E30EBDA98BBDF8F5EEC958F12E92 +:1002900008AFA242C6E306CF9ACCCEF31D6B1D9FDA +:1002A0008C687BBC15E125A74C76117F5CD1CF37DC +:1002B0008CEAF73B103E4C74036E8DF5F593CDC779 +:1002C000F6CB799DEB423C7B701CADA35956C5BD66 +:1002D000F940DD38ECB7BD54E05DF7F6AF8027CECE +:1002E000EBB2C2ACAEF3B2E2ECA7C845A9E128BDBF +:1002F0003DC3845FFB10EF146A57F6C7BE1E9AAF6A +:100300003DAF714F6FD28B6F157A31EE2BFB41648D +:100310003B48A4974E91CFDE42F95339A092FD9904 +:10032000D923207B48CF5B00EC2702DDAF13AAC89E +:10033000FD8AD84ECEBE15ED27ECF7DD5537A6D198 +:10034000FDFEEC944569F96E8A6FC2A90EC0BC64CB +:10035000F38AFBD9CFBCF76F65543E8FFDD2D73BF4 +:10036000C53973EE0FFEB69CE900B474E7181ACFD6 +:10037000C7EF0B44D2649E5FF9B59F0D27FDAAF726 +:1003800059F730D2CF7AD1392F8274A8491F9755A7 +:100390004486FBDD9D70CACC4F6CBF649BF03898DF +:1003A0007C72369D8758F7301EEAF1069F879F348E +:1003B000CF4FF28C69A984E707075AE75AAD59E491 +:1003C000B2AA4E3252E7D03CDF94F97EC567AA91BB +:1003D0009A86E527C1CBFA63A0CDCEE744ABEEAE5B +:1003E000E899EEEE3E6E7F4DA1B06FAAE2E2A2AABE +:1003F0009456079D6755FD9371514D6871273A0FCB +:10040000B3D65F9DA68032145309BCE7ABF7E23F39 +:10041000E48470DC629677777FE3E7E6FAACFB1959 +:10042000D5743F033FAD7ABEBC279CC70EAD3E33AB +:100430002EE61E04D96BB4BEEA3313F97BC55D27E3 +:100440001C84DFD40F3D8560DDCFE80ECED985C298 +:10045000DEA8A67B0D19D1DF051D77F69FC9E54FF4 +:100460009A707B72AF6DDAE604F37CBD50D8DD4341 +:10047000B214F6175CDA0AC6A604E35AF5ACF70D17 +:10048000BA9B57D3A4F07C9A37C505271A6FA709E2 +:10049000476BBE4DE9E1255E71CE3A90DE2FE8C88C +:1004A000AB91FE5747F1D3B3A67FA0E93BE1FEFC39 +:1004B0005EC615C28EED6E9FE7F4F3A5137F18A9F3 +:1004C000B4DEFA4A269B5D407EB49EF35A6D242723 +:1004D0003BF84F37FBDD096739E61E4C57383BB810 +:1004E000BCE3FE19181E299BE410B03EF0D01F4B50 +:1004F0001C0E1CFF980D22C477A6C87DA7BE4079AC +:10050000B41F882E8FB1ECC07483CCF7998E3D9ABE +:10051000EF20BB6C49394464E45BC7DEEA5F477196 +:1005200097DA02D424C7A1BAB336F6FCB1128C3DD7 +:1005300029D8EEC603DED456CC2FBA27568E1D7BA3 +:10054000EBC70EB207A4856E3FC515E13CA7BE8080 +:10055000F9C5CD0EBE9FB5E4FEF8FE62F5E06C5322 +:10056000DEC6EBC39F179AFAF048184972E685DA9F +:1005700066F17E8E791F11F53F23119E587A7028FF +:1005800079D2DF99EF43A34C7C699C92B8FE92220A +:10059000B10F2B1F3BEDF068DDD3D971E42705388F +:1005A000FE895A95D3ACC1866B30F63F60B02F659B +:1005B00030B697B548FF4FD8CF29CE4111DF385F0D +:1005C00043F7D448DECE157A8253BEB992F5D13EB8 +:1005D000A006597FF1FBD99F6E43FD248DE2376E53 +:1005E000913DEC6F10EF078DF968511AAD37F3BFED +:1005F000E73C4D70A53B0E40EFB0941BA5C4DFD780 +:10060000CF70F379FF265B80FBA140ADBB109EA1AC +:1006100027C7EC26F77941E3BD93C8EE535B76B567 +:1006200092BD526FFB740FC525D44F043DC8D00E48 +:10063000F138352D339EA6F6FD67BA75BA5FBA3E1E +:10064000D72855A3FAD720F21EE99927AB6CEC37CF +:100650003DD5FC0B3EAF42FB2E42CAF7A9AA3CF6A1 +:100660009B59713F7CF697C06F7802E51B44DDE72C +:100670005ED1B4C946FAF8A5B451517155D6BCAA99 +:10068000EE6CCDBE8EE4EE130ACBD1CCDF5CC1F1B3 +:1006900003B98A26113CAF9354A18F9A7AF2B560C0 +:1006A000FD35BC42FAE942D293110F3F94421CAF90 +:1006B00069839667A9FDDC1CA10F82D63882FCD71E +:1006C000E12AF37DA2E5F634D26FAC7382EEF0A19D +:1006D0003B3F0FF6B4E41D1CF7A404EC6FAAB14530 +:1006E000FAD3FC8EDB13CBD779834D3E30D01F621B +:1006F000799E0EEA6334AF025F2ED165B54D5BC9BA +:100700007EAF7D5E8E0F6997D4F498775ED4865F56 +:1007100093DE5D6353857D73C028A5F398F6194574 +:10072000FCEECB497BB83FF311E47B149775EB13D8 +:100730004D3315845B756FD4BB30BFF9895D3315BC +:100740007A87272FBCC486F95707FF45940F091FE6 +:10075000A6FC1F9FF848940F0B2FA1FD39F9C4691F +:100760009127030C11EC6F4FFCEFCC00AEEBB8E916 +:10077000FF043D3C9FE659FDC2205BB47FF1C86099 +:10078000C1378F27897AC773E186AB49FF280CF3FD +:100790007D18ABDE6B83CDFB0426FEDFF462522BAB +:1007A000C5095BED202771FF41B3DD4DE67B59485C +:1007B0007FBFA27A2FE768E9BCCF479147115C9EC3 +:1007C0001FCCE73D370D4EE7FA049FF4A2AEE32DB0 +:1007D00023394F72C01E7BFFADC1DC2F2812FD579D +:1007E000F756D3683FB2D3859D811B927617BF63BE +:1007F000B0C9D4ABC4FE64CA6A695065B9339CEC15 +:10080000E697CFF62D65BBB9A29BFB9E83851CBBEB +:100810002928C689F4D2D4CD7CEF1C0C8A4779B93B +:10082000396973F47B29274DF81E199C26E0D7B14E +:100830000F3D251E2768C2A52FC2BBB8137FACF69B +:10084000175AF7F67FD1BABBEC5399989FB51E8023 +:100850007B051C707E69A8E71F5F63B61B6DCD43E7 +:10086000637AB8E9C5DB3708FEA7A5B3DD0E3F11F3 +:10087000707059E316F1F9E40A530F96036F38C804 +:10088000DE5851DFC6EFAFAD6814EF6D75D29DB184 +:100890002A9ACE32F3C53A33652333C8F488EB6322 +:1008A0007A34CC788358FCE980773C1D77E94F4B4C +:1008B0008FED4FE3FEBADB87B08917DFD83E041314 +:1008C000C3B383BFC4C1AF831E73CD76458867654C +:1008D0005DE9F18FDDD171EED71CCFBC77B2E27646 +:1008E000335E558BC5E3154DB9B685459DF5EF6E65 +:1008F000BCD71B1D4FEB6A5A1020F957D352CE714B +:10090000B52B9EDBFAEB00B65FB6FD010F05531F5A +:10091000531AB2492FAE7A6C9DC7A0731625E021F9 +:10092000BE792C244F4B747F75D41029461FABA67B +:100930007F62FFC79FFC5BDDBFE1FCBF9050BF4201 +:10094000785737FDB58EECB73D862B4272FBA81267 +:100950009E4A72F4A6056E3FBD2F58D31CAB4F2D97 +:10096000FBE503D91A077707FAD8589F6AED43EDDC +:10097000AA1FB5EB64BF57EF93751C066A20524758 +:10098000F38B6F5FD3F8A183E0AAA23ED8775CD740 +:1009900072E4248CF7354D3FFA54F6507AEC1D285A +:1009A000A1FEA2FC1108F7CA6EF4B2C221B1F7028F +:1009B0002CF840288BF59BE0130F95BC8FF33AF190 +:1009C000E86B1EA9285A5EDE29CEA91A6FFCF90B26 +:1009D0005AF772F524E907CEAE7A80D62C0925BBEA +:1009E00045A455F6560FF905AA36D9F5007EAEDABC +:1009F000FA8BC7E95C05DE76EA74F458B5F5B48382 +:100A0000DE3FAB928C88C47A1678A4919DFBB47CAF +:100A1000EB47C25FD54B86E9B84FCB7EF5B9A86FDF +:100A2000402409EB2F7FFA7DF66F55F9DC7E578263 +:100A30007DAA68DCE508BB13EC53E3FB53490F0ABE +:100A40003EF125EFC3B19D12F4CCEDDABE72D3476F +:100A50000EA29B13B8211969025E649FD634CA0B9B +:100A60001CA989F6ADF52AD2FFB09CFD2017DA3F0C +:100A7000D7101074F1DCD66D640F54BEE3D4A7D345 +:100A8000B8DB6EF100EEFF11C52FF0FD67EBB20D84 +:100A90001CB7D21EC8563915DF2B1FB995F170E966 +:100AA0009BB766B35E07462FDB685E6F2F5AE7E29F +:100AB0008DB3789D4BC0C77858F933E1CFF85C818E +:100AC0006989EE1B6F1F22E487136E2E21FAF81C32 +:100AD0007B223FCC11078878DEB7C43B644EB83A1E +:100AE00035FA9DB93B8708391080D07BF4FE640D40 +:100AF000DAC5C417E4373F9F4AFDACCA55FC4E9592 +:100B0000D71F30E1259D13F11C9A62C59DE6E17E59 +:100B1000BD39A527D9C14E38E5B8BE8CDF69D0C82C +:100B2000FF1BD58EE17664B33359423BFF4876E232 +:100B30007B84EF99EBC0BFB7200A9F6AB61C617C2B +:100B400002B4BB527344FE61A243B48B52116E9F38 +:100B5000EDFBD0D19BFC1D99361840F36DFB88F35B +:100B6000A0676954DFEABFA6D919F32E49CDA31FA8 +:100B7000C5D1B333EEBD133FC3B3065235D2378F61 +:100B80003822535FA471705C8AD75C72BF33E6BDB4 +:100B9000B04E7C71747ECFEDA44FCBBE5A6AD27F2B +:100BA000FCFAE3F9C19371FC0036667DA5F79FAAB4 +:100BB000ECA1C7093E5548AF01A657417FA8A347FE +:100BC00006203D7CFCD44BFBBF4F7EBA467BE674CF +:100BD0001E2D96CF563E83F44BFE348477924E7C86 +:100BE000F64B07E9BD39156807E3BC3F76EB74297E +:100BF000AD2BDDE2F78474EB063ED7FABFC55F97F5 +:100C000076C35FF7C5C1F373284AA53B0CC79F5C49 +:100C10007E09FB15E2E06BD9BBF17CB37A88C67024 +:100C20008EE79BF8B71FA2E0B8ECBF3F61BCFDA206 +:100C3000973807AB7EF4AF2CBF10AC1127E26D756F +:100C4000E853CEAF23F9C5F95D33E9BCBAEBBA631B +:100C5000E1195FBEC1E4471DF7DCEE8400C5DD4548 +:100C600076C8FC0E433BCEA58EF4F3A772F99C70B8 +:100C70009DA9EFB7AB110FE9E7EBD2AC3CDC40EF3D +:100C8000C1B4074AD400B54F32E30FBC114F5A9498 +:100C90009EF47E8BEC21BD2E1C826989DF050CF24F +:100CA0003CC2D05DF91A715F4B3EBB2D6CDAF54E3C +:100CB0001C2FBCE6CB6D746E7E4871F1B9E5A23590 +:100CC000733C7CFFAF25FF3F092F16BF8A70247A43 +:100CD0000A188E5E08E71B0508D0FC08F079B09C66 +:100CE00052B6E745ACB704014CE724F1FE9465E049 +:100CF0004D6DCDEDEA374139E820F9BF14E511FB20 +:100D0000BD37C6962F6BF998F16C591C9EF908CF28 +:100D10007A75C5B3DC4B4DFF4A29949AE7BA6CCF7C +:100D2000B7EF95F93CFF940B58DFA0735EDC3138C8 +:100D3000D522F3FE9C7A4A0A71BC61204BBCDF8A43 +:100D4000F84E7A968587F1F67D7C7AE2D97747D29C +:100D50003DB1AA5FFFA5E4BF303DF1EBB707BE4848 +:100D6000F9E7FEDCFF2FD0B57EC5CEBFB21DD3BEE6 +:100D7000D3C9FED0F69DBFED4F72B9FD05A74EF861 +:100D8000DB7EA753C435EC4CE177CCDAFB09BF5DC1 +:100D900070C7972561965B6B791FA75FEAE0FD3E00 +:100DA000D5F2379623A75A9C1AADA366670FF68F24 +:100DB000D5BC901422FF40FB8E2F4746BF77F5CF5E +:100DC000AEA7DABC4FD39E0273296EA63D4DC4591F +:100DD000D6BC38E6176BC81E69DAE520FF7FC56F01 +:100DE000FE5E427CA9FD995D0EE25B68973E02883B +:100DF0001F732EFDE903F65E745F0CD8DE3E7DE9BD +:100E00003BB3E87DACAE701170684738D0BA102E95 +:100E100095A49775078FEA6F2D3C3E657BA2AA6566 +:100E200014D351275C24437C4F09B9245AFFF31E85 +:100E3000F21BB5E7A1FCD769DD5F9690FE74A17542 +:100E4000FFC7A5E27DEEFFE7D76D838B5AF753DF2F +:100E5000DA750BFC1F76A926DEA78AA383AE78FE7F +:100E6000DC0F38BF2D45E7F97E45FA7FFD5BBBFE01 +:100E7000AFBCEF25E4B7BDD87DFFF85BBBEE0BED53 +:100E8000FBABE6BEA7A874BFAE7DC7DFFBF37ABF9E +:100E9000E2BA938BBEADFCEDFCEBEED08F64AF8B72 +:100EA0009ED8BA075ADB344CD775A3A78C2AB2FC5C +:100EB00010C21E914D7D631D0C3336915D857A06FF +:100EC000D901EB3245BE1EF50799EF0F72B00AD477 +:100ED000F7D5C5BBB68A1F54CCDBFF7C23C7B3ACA8 +:100EE000CBFE0EE495D17985F06304D7E8BE5DD8DA +:100EF0003E9866D3823A3D57B5D2B709CBD5DEB21C +:100F00004AF6CD3AED6A57F43B168ADB1163A7B86F +:100F1000E3EC8DE402478C5D9204BB55F2C327E9F4 +:100F20000AC7FF3921AA3DD6CF2A12EFF42743285A +:100F3000A0BA2F1E4E8BBE3E9C5C7CAF5235E104A6 +:100F40008641EB766A0AEB610AA0FD28D621EC4EB9 +:100F500084A316054730ED50C504B9A20D6338A22D +:100F600001A14D1A4D70F5331C83BD6495E1DAD9AA +:100F70001FAF3B7E1FD6699320CFD4C725FD9B872B +:100F8000F3D822111F100F672BCDF795AF21FD77F6 +:100F9000D51A71CEF5CCEFBEC3F9263BEAC374CFA8 +:100FA00030D5B7A288FC8E5E43223A5D3543BC2F14 +:100FB0005846F7C032C9D41771B899AEBEA0B0BFB9 +:100FC00012ED0CF657AA40F69F3C091AD91FE855B6 +:100FD000E2E27A558E7B0ADE2CE29EA01034F14EBE +:100FE0004B6CFC4F601214525CC314B9AA81E675B5 +:100FF0000A521A28EED2616FEDCFFEE17E008F918A +:10100000BFA5FC8B8D549E8B7A3DD07D32A5F53DDE +:101010008A6FB84D4E058EAB8AE0A728B85D76C6BC +:10102000054A149CCB212D267FA2DFE126B213F2C4 +:10103000024E9582C72A5CBD62DA9FE87586C70BAF +:101040003A5D2AD94753D4DC98F6B267EF7B64D770 +:10105000BC916E63BBE0F29CC131EDAFFAE0C4C657 +:101060000526CED23ABEF7AEB8A78AF6D623AF632E +:10107000BB37EF0720BFF1155A694CBB66D3BF12CF +:101080009962E7F766AE2C1C13336E737837C3A5ED +:101090002A0B243A0FAEB2214960BDEFEAE531F5E3 +:1010A000BE37FA8A987E67183362F255ABBF0025C7 +:1010B0000360DCEAB340EF0796B636C6B41FBEB78E +:1010C00039A6BEE7753485302DDDA705291D75507D +:1010D000DC231D8EFB41E71BCDE1853AC5EB14D324 +:1010E00005D0323A16F0565018F2C8A3FE9728BD24 +:1010F00050FC3298EFB2269BE7AFEB6DA1C605B965 +:1011000014FFD3F0E35D12C743EE263C1D1D69A812 +:1011100048C5EA63CF34BE446953DBF87A7AC7B373 +:101120000AA08DE5AFDBC6E70253E4961289ED9F76 +:101130001EC39D51E72EDDBDD7F9A3D2F27D4548F0 +:10114000476B738C865DC4F727BD3B5FCEEB5A0FB0 +:101150005425128DE73F2AF51EA6384D2B4E2AB98D +:101160004216BF4771B98893A9B3E94926F362FDD6 +:10117000409D6AE738FE65C582BF8D6CDBDCE82EDA +:1011800023BBD3A5D1BE2667C4DEF3BE71B4B8B706 +:10119000F7459179BEA2A859D7931FBC3845B4270B +:1011A0001F1F8D37DDC6FA94E780BEC78EF9FB0A94 +:1011B000F7A9C4CE9AA67F10E0F74D0FB44D903436 +:1011C000809EF794DAC80E87BD76FE7D99A6C2C9C7 +:1011D000A70BA87CFA5B1CC3B86BC22F0B49BEAD32 +:1011E0001C3CE4BCEF8C7ACE48A045C5412C2BD6E4 +:1011F000783E1E25CCEF1279CE285CEE99A7DBFA5B +:10120000478DB77282D0FF560E4EDE4A78EB3960BA +:1012100088B8A842B73680E9239CC37C4209E75CC2 +:101220009F22E2ABB4F3BCF37F7CCB88349263198A +:10123000E57A1AF94133B6CA1DF7CE683D3FA6FFDD +:10124000D0C13AACDF3F19E7B58562D744792BF2BC +:101250002458EFB0CA9125613E43B2CAD7CF9E5CF5 +:10126000C4EF31C6D41F9AD751DF70E574F6AF15BD +:10127000AFDFBFB688E037CA467125EB7F67E777F7 +:1012800006709DAC4FAC447A06E97CF0EC710178B5 +:101290007AB8FC90A4C5BD9FDB5A4CF982BEBE4112 +:1012A000C558FF92B3A9FC0EC067F5492CFF2E3933 +:1012B000FB3D7EAFB3C961F4BF9DFD37491C6F365E +:1012C000E3E68F37AC26BABEEA7821C52858EF5737 +:1012D000D6A85F303FB0E2EC3AE187F88B78FF6345 +:1012E0005B679EF883A7139E06BDCFB53E0ABEF48A +:1012F0009B2F334C78FA8A37CE5E8BFD6B8BA6E53D +:10130000105D9E0637C7F59D561F9F4DF33DBDC529 +:10131000CE41B44D26BF0C149AEF11648673E85E7B +:101320007EF19B368E473A88F860203EE4B7BE993E +:101330005E4CED3295748A6F383DFECFFC6EC2E98B +:101340001F0207172F0B3B185E4D998B2ACA19FFF6 +:10135000B574F23F58F06D34FB79B8D4B8B298FD4B +:101360005CE67D1163EC45BD3FB96BC2977C2EB046 +:101370003617F5FC340A393E5347EF4BAECCB5B3C4 +:101380005C5A99F6C5D44CC2F7725784DE81A859CD +:10139000FD19C317BBC98DBE07A69C91418B8ADF7F +:1013A000D2868AFD571483F75F39E3E0F2AAD5A706 +:1013B000996F5BED4F98E7ABF42E23DD17AAFA8700 +:1013C000CCF746911FD64BC328DDED5819C54FA069 +:1013D000F1D30E3E3F14F7EABEE96F25939F728664 +:1013E000A4CEA2F9B56C3B339BE2056624A9B328D1 +:1013F000DEA06EDBFBB329BE60463F7516C517DC69 +:10140000573C790E97F7521FB0A1FC7AB964BEC859 +:10141000E7AA7FA2FC535BEF98C3F553C4BEDFB6C7 +:1014200075CE9C00F36337D3C1A9FA1E21E779E892 +:1014300060E9EA1721FA3DDB2EE5E6EF49C15CC120 +:10144000F73EB9BB0FBFDB09056D1C2FB6BE58F8C0 +:10145000FB3BCF5741A5F3D5CC7C30C8DF9CF95C72 +:1014600092F85DA2436DFD097E4736DEF203F2A7D6 +:10147000AE9080DFD1AF026D24D1D5425BF83D4AFA +:101480005F1CEEBBB798F5A9368E775DBA7A27CF89 +:10149000EF53DD8C5B562345DEAFF54E04F69FF02F +:1014A0009D88D838E30F6CDA40EA5731E1B2506ECC +:1014B0009BEF10F37A94E6B5227D17C7392B6A5B50 +:1014C000B64FE851856C3FE524F37BD175BDDF292C +:1014D00049F43B088DB528EF91E49EA96DE674F5BB +:1014E00050607CEBA9841D3AF6537D40C89D916DF8 +:1014F0001F38A2E319779BF04D357FEF2A3E1E7708 +:1015000037C9A5A8B88315BD5BFB927E68ED6BE774 +:10151000BEB4F635F70568BE99192F3D45EF9D50CD +:101520009CEB0FE93CE3B9A456F25B778F27D63EDC +:10153000887937250BBE11793689F5A6F8751C34E4 +:10154000E76DAD2762CADFEED61131E5EBBF6A1D4C +:101550001193BFC7AFC7A26FEBBB45DF5DDB8BF954 +:101560005F3CDE897B6D17C23B8BFF5483AF50DC41 +:101570009716FCC682B7354F0B6E4DDDC4E32AAB20 +:101580009F8F598FD236898C1E482D11EF5F298D80 +:101590005700ED87B2BA85EB75B71E39E5333EC704 +:1015A00059A6819FF4DEF875554123B7EBBAAE0812 +:1015B000F3E3159AE0C75DE3F823CC9FABD13E235C +:1015C0007DDC5A77079FC6F5137D4F4086C37C9319 +:1015D000EE124A645FF862F4E372BA31117D6EE58F +:1015E000BA39263F45BD3DA6FEE5396B62CAAFD08C +:1015F000EE8E29BFB2F0DE98FC77F59FC6E9F79B27 +:10160000E2F4FB2762CAC787DB58FF7EA3761AC7BE +:10161000A74F3C1A613DBCB556E5FCEEDA1C4E5FA7 +:10162000AED598FEF7D41672BAB756E7EFBFAB1D2A +:10163000CDE9EBB506A76DB55E4EE3F946595BB84B +:101640008CFCFBA33353F93C6AE350DFF525140708 +:10165000B92F5244F837F640E34B240AF2439FBEB9 +:1016600047F54EAB0E8E475CBB6BCC1F6EC17CC684 +:10167000EB322469E7D38B6430A2F0C7333D0C749E +:10168000FEED01F13E567CFD8525424F9E0B61F13A +:101690009EC06A3E0187B92EF5152393C54684EC9A +:1016A000F6B9E0673DD4B65ABC5333177428237B90 +:1016B000D607FE7B381E29F67D01AF3163DDAFB062 +:1016C0007C36DD3BC5F6DF7737F2BDF267F6A64F15 +:1016D0002EC5EFD77A25FE9D8F033BEFBAD5C5F611 +:1016E000AF75FFF41DDBC5E8130B4B047DB54B7ADA +:1016F0001BCD379026DE2F8A6F37CA5CE755C108AD +:10170000EB1F11D43F28DECCA2CB19EA2173FD9A3E +:101710002D750CD1C71ABEDF50D5A6E94184F798C4 +:1017200043822E46205DD0BE8D3D2AE86024D20142 +:10173000CB41D33EB4E800EDA997A8FDA983A03B17 +:10174000B17DDDC41FC9647F8DF92C14A4F4B2B33C +:10175000915DE7B07C5C9BF8DDA40BD993965EDAD3 +:10176000523B97F16867AD8FD3D6DA4A133FFD9CA1 +:101770007FB97635E7F7D40638DD5B5B6FE2670348 +:1017800097BF5EBB81F36FD4864C3CDDC2DF3592E0 +:1017900067089FBB4B4C39ED2A37ED0A917A8D359E +:1017A00076BEE78F9F889FCCA5B9127E544A21E26E +:1017B000DF75E9013BE5EB92690F68D601AE7F9DCD +:1017C0001B5A490E54E5BC28F4B0383C29CFBC86DE +:1017D000F164A619C77A20BDEE5607E2C389C6FB9D +:1017E000ECB1EF8D5E1C5E2C73AFE57B7DF17CF17F +:1017F000267A8F42EECA0F0174BDAC4CDCEFA238E2 +:10180000BDAFCAEF555B9B795F4CDC7FA9EEEBE681 +:1018100038DB7F9D9C514D39030BA87E87FD9D7C55 +:10182000703EBD8FD7052E71F6F7E141627F2DFB2B +:101830001BF54CF64BB58764B6BF2A731B3C6C7F17 +:101840008F8E78683F6FDA2103EB8B8A38EF5D4A21 +:101850001D6914D7D3BA7F1CCB99557B882F2D33A4 +:10186000CF7BE3CF6DABE9BC574A04EF30C7D52F30 +:1018700037CF7BE3D75D3DFE089FF7565FE05EE91B +:101880007B25B1BFE7137F7FB73B7CA17882E8F768 +:101890005C4F9EAD653BEDC8B63B1E0AF4FDD7ED2F +:1018A000DFADA5DECF4A441C35DF9BB3F6B3CEFCDB +:1018B0005DCEBA492EBEC7D03E42E5F76FDA25F1BC +:1018C000FE4EFB5F415FA3D1FB3AEACB24172ED338 +:1018D0001DCC574787C57B01E3E95E6282F702268C +:1018E0001C0A0553A8DDC100FBA3C6ECF305E9DE25 +:1018F000EDA8D70D99C8ABF465AF4C7860C9274BFC +:101900005E75D295796F8E6232F2BF3AFD698B4671 +:10191000E7907ED761B7BAA7F23B45A75B81A349A1 +:101920002DBFD8F083864CF712461CF20549DED64F +:101930009976E6A813013915BF4FF8CCCF76D018A9 +:10194000B453E552718FDA8882AFE5D7B2F89CC5FF +:10195000D7AC7B7BAAC3B785FCCFF04212BFFF1286 +:101960003FEF41436DD67BD6838612DF33EFE94DDF +:1019700091CFEE3A4776419B8817B8E46CFBE3645D +:10198000F7AC7AB607DF53BB907D50A39E4EA89F5D +:101990005A698D4D9CA30CABD08693BD497A2BD947 +:1019A000A1965D1A5FBFAC74D2D8A15934AFF16D66 +:1019B00006E1B76A3B2F7ED7ACFEF4BC76A1357E3C +:1019C000CD8E11EAC228BFD5EAA19219C7F2F5DE81 +:1019D000A19E10991B23C7BEED7A1FD26119E11792 +:1019E000D98624A7BE4F3B80EBB80E5A595FB9DEAB +:1019F000FC1D8B1B001CD1F7646F0483F9C39F741B +:101A00005F0DE1CD6288CCA77C8D14A97A1141F8D5 +:101A1000C9C4716AAED6555E5FAC7C4E36EFC1C6A6 +:101A2000C3FD4E136F2DFEDFEDFEC4F1FFF65295A0 +:101A3000EF41B73F3BCE46E738EDBF97F9FD54ACD9 +:101A4000C87C25384CDC3B1D3ECF7C8704F9CA009E +:101A5000BD2B5F393D7ECE64F61FD1C106C59F2ADE +:101A60007AE1F551F7CD82E6EFBA6CC194E22553E5 +:101A7000E78595E8F3B39F9AF32FBF7632903D74D4 +:101A8000952AECCE292EC84C225E78F674D12C64AF +:101A90001057913E3B9CDF617F98E0DCF10E08F12E +:101AA000A34B70DFDE17E77C7093C4FED2E626916D +:101AB0002F5E9CC6EBFAAAFB883DF728C1F52F6E76 +:101AC0005286117D0F4D8FE4115D168F793B5DC2FB +:101AD000799598F7B170DAF510F5FB56EF9AEBF8B7 +:101AE0007CA8B18DE63734BD6DFD7DA45F3E6B03F0 +:101AF000F21B1E1973FB128892CB9ED249BFA27AA9 +:101B0000DB25F39DBA1DE2F70CB04576B47FEB4FB1 +:101B10007AC5F354AFD5F433C0AAE7F91EFF0C55CC +:101B2000EC014CCE327F4F32D23FD1EF0B59E75907 +:101B3000430996C2FFC8EF8A6D37FD936F0EFD60B3 +:101B40000EF917A1359247F3389224EE517B4A7D66 +:101B5000BF233E3394FCBCB48E9F09FFC091343F39 +:101B6000DF23791BF9339D1FFFA5D6C5E9BB681F8D +:101B700051FA3F681F51FA3EDA47947E88F611A564 +:101B80008BCF60A7B87F3374E36DE6AFDDACA37B8A +:101B9000FE1230F5FBC4BFD3F49609FF92A643773B +:101BA000F6203C6896393EBAF85985F5D3932DA3B3 +:101BB000627E9714E9F530ADAFA4F98F3FA17BD6D3 +:101BC000254D8A2A69742FFB7436C71FC6CD8FE056 +:101BD00040E70D911D0EF17B4AE67CB7A7B5ADA796 +:101BE000F6DB9FCDA319D2398EC0C31DCE84BF377B +:101BF0006CC5DB3D3154E85FDF7346CAA2CF1FE3FB +:101C0000E3D3D80F3C86F0B9E00F344E60AF0C033D +:101C1000182F63FD1BFD74710FC14A8B7738384E46 +:101C200079FB8EFD575F89FDFD1F8FB61B3100804C +:101C3000000000001F8B080000000000000BCD7D9D +:101C40000B7854D5B5F09A39F34A32934CC2000957 +:101C5000123809AF00018664121212E024048A8A45 +:101C60007482D482A28EB462541E23D29ADED23FF2 +:101C700027244012830605CA558401C1C7FDFCAE66 +:101C8000D102175BF44E50A9F6B73422E2A354C731 +:101C900047552C4A8A62EBAD2DFF5A6B9F939933BF +:101CA0004C0222FC97F0E9CE3E7B9FFD58EFC73EE9 +:101CB0003BB3265E5E24C900A7E9670A80CBDB1729 +:101CC000A008604CE9D70FDCEFC1F2599BDB0400A0 +:101CD000F360DB3437F6BBCED1F1A21BEBD7BBDF11 +:101CE0009B968EF51B334D07A8BC49CE999E812546 +:101CF0004088DFFF515EC5810CACCDF456DB024E4F +:101D0000800A9000F2807F4EE37F531D29008E6889 +:101D10007D9ABB8FA1FEBDCCCB0CFD2F978718DA27 +:101D2000AFCC1B6D68D7E79DE92D34F41B97D19597 +:101D30001B74D23EBEBAA71CF70326080FA37DED85 +:101D4000FEF2EDDBB19C35719E8FF67F0CDAAE1999 +:101D50008D1BFDA4A479E3FDF4B245B165F503B88C +:101D6000857EC7F6E3103E5286ED926BF9813BF11A +:101D7000BDDB322590BC00359BADEF4762D6B10488 +:101D8000FC6961EC77DB0EE37380882DEC03B83DD2 +:101D9000E00CB62000173D81ED0E433B8FBB78AFC2 +:101DA000CD4DED4BC0126DCF01A83D9AF3E40B3140 +:101DB000E38DCBE8BCEF7E1C6FDC9E39EE065CDF6A +:101DC00093A55F0F90719FE55E97E723040D4C800C +:101DD00009A711E42039CD80FD4EBD2485245CD7B0 +:101DE00034E99BD4483E3EAF423C67E17B26F90F85 +:101DF00065D8AEBE2CC14E1CE76F75F2932F5869A3 +:101E00007CB8D19F1FA50B80950C5FBD7CAB0E7F6E +:101E10001D01F0C73A07977FAA7373F96E5D269785 +:101E2000EFD5C95C7E5097C7E5AC431068C7F1FE9B +:101E3000FCF7F1007D681C15A06FB41C67F39A07CE +:101E4000E03ABA7E2F85B6E37EBF289F9006B4CED7 +:101E50006F70FE620D0F4802D5448CA5F8DF8FB776 +:101E6000BD98E5E3E7AA0BA75AF27709141C77B9E6 +:101E7000D724C65DD4F1629627DA0ECBDF33F48720 +:101E800015A603867A638EB1DE5A7120F67D1D0E8B +:101E9000F1E52D9BEFB0055C58AE372921E799EDB0 +:101EA000FA7AA6ED4F524C389E659F3D64C7FD2DD2 +:101EB000712BA0607F0B80D29E7FE67B00F50CE744 +:101EC000791204DB138C5B47E312BDEF4F02E93C50 +:101ED000C67D0B6983D6A3FE973DB413DF7B2B4DE4 +:101EE000017FCC3C2DDAF89FA5B7FDE22BECF7D9AA +:101EF00033404FB00E73693D63777D6C3663392E86 +:101F000059D0C95877C49C81E5899A7F6C3CE261BD +:101F100032F59B26637B6ED71107A2FCBEF6AB366B +:101F200039106F6F9BCD00034020BE04FBE31854B3 +:101F30007FD07BD5DC46FCFDCAFD4961F379ECE737 +:101F400041E445A6A34AC1EF3710DD88791440511A +:101F5000B37415E8F32A241F68FF547FADDDFFE654 +:101F60007AA233E8DA48F2E13840B885D7AFA4C6A0 +:101F7000F2FFD2677FC2FCB9280BF99E04E066C16C +:101F8000BF0EFC773A97F83534DD89EBBD358CFC14 +:101F90000F179FFF9FF13AA37C3E22219F1FBA1289 +:101FA000EB4B9F91BC766C3EB96F98E0278DEF7537 +:101FB0003ED7E1B87493C47CA9D73FDF27CD08256D +:101FC00080F7368D2E86285DB369BE65CF5AA00591 +:101FD000D7B76CD288FEB1E3C7BFB7B44902396640 +:101FE000FC279FB3D710BFC8D0D5AF1AF967DCB3B1 +:101FF000A7322AF24559CFF868D3E44DD720FF180D +:1020000094D726FF9F7E8EF301E27127C2A7327319 +:102010006E36CD3FDB094ACB7806CB1C07CA89ABAD +:102020000588E0EA92EBB201E1B919D12521DDCDB5 +:1020300051AA5FBF0EF1F80373E02A92F3C7BC43C5 +:1020400078FC6B5CCBAD606672CD36E17873E7D817 +:102050000B693FB31A045DBF9EDE759C9EBF3E298F +:10206000C5D480EFBD6E8246C888EEE375AB3F9B5A +:10207000E80D37EEFE08F163524649A7537A9617EA +:1020800044C91FE97894A2F26F9AE454699E936E52 +:1020900033D3BD25ABD546EBBA154207149C7789DF +:1020A000376C23F9773BB82D5462D1D54D1F447F4F +:1020B000E5FFE8388DEF2FE9944226ECDF5ED70E7E +:1020C00016C4EFD3757BB91CFCCDE0C6CB101ECB7C +:1020D000C7DBBC2DA4B734FA32AB26389D405F9DD8 +:1020E000499F96683BAEBBC2E10C4BA9F4D87A3C41 +:1020F000761D8DD94ACA78DC8FBAA63C9DE99368D3 +:102100006170749FE36C004E92F33B5358CE1F7B7B +:10211000AED84C783AF63B6BC844F52D23DEB8D3E5 +:10212000C7752079732CC36BB6517B466E48C5F6D4 +:102130005BCCA0925C86ED426E3D3FE9AE77488E67 +:102140002DDFE932D94D828E653401A447D7BEF325 +:10215000EF38CEADC8AC766F546F2C9AF2E8C62734 +:10216000900E1699DBEE29C767A7203CD68DF0FCB0 +:102170008BA97D38E9ED8F1FB287CDF4DEC323B77D +:102180004B38FECBA98191B41FC854FAE7E0F39A0B +:10219000437DA105DF9FFAE83F0F92DEBCF5C9BE83 +:1021A000CC5F3ADD4F233EC4F59C403EA4F59CDC59 +:1021B0003784F92E8A7F0187C5280FC8246ADEB1CB +:1021C000CE4FF80C24CBFCDC02AA7219E17BEF4D58 +:1021D00040765381645288CEBB9A115EA633E9499A +:1021E000196FE6F7169951BF121D06E44282C7091E +:1021F000935CA0F105D07ADE7F6EE4F6167C7FAEAC +:10220000D63F4A774797FC86E86EB3DD6BC7251C3F +:102210004F32EA7DBD9C393E9DF9E516C79760298E +:102220008C3E5F52FBB5B19E0F0AC98D8206B9F094 +:102230000E2CEFD4E07EC548FFF7C7E3FBB7B5AF80 +:10224000DBF38A4CF36EFEE9DB34EF4B4E9E175EF8 +:1022500011F03B6112FAA55BBF3AFECAE3A3E4E1C9 +:10226000F5EACF3F7EE88DB1011CFFE3DDA38703D4 +:10227000D2DD02A9F3A307115F9FBB3ADFF93996BC +:102280004FBF74A81FC12F7EBD8B6ABF004B8C1C33 +:102290003A6E32F17E17D13EF0F96F0AFD3733BE48 +:1022A0002DA827106E0B5AC66C2779304DCA4F23C4 +:1022B000BBE9C431E3FAE2D7A98FAFAF4F1F5FEF9D +:1022C000B78CE08F709838CE2DF4ABADF373C2EFBE +:1022D000677B469B9015A3CF333AC7A6E747F1E447 +:1022E00057EAADD4EF1A12F5888AB90E81D7B935FD +:1022F000A650430EF7E3F6EBF039E1BDC2D3C0F5CB +:10230000394ED467D87F51E66F785D24E81CA8D792 +:102310007E00FA4FF5AA5F61BF3797A5B25C987B44 +:102320004B9B95ECDC6E79A6BE6D3E3DFADBCB3364 +:10233000849EECEE07CCC3A43F013767C1FA24ADFD +:102340006E2AF963C3AF483EDF99EA95D064841AD8 +:1023500019C2C4D7272144F05E6D0AB2BDE7203D03 +:1023600080658BC99B69C1523277F5019E27C47085 +:102370009A06010BD57F6B8A3400BEB7CA539949C0 +:10238000F4FF2638FD6417FD207DF51892A395EE25 +:102390009973E9F96C35D5DD82FB6DB4CA77E793A3 +:1023A000FDF303C94B76AF0E175D7FCCB578AD0456 +:1023B000DF7E41D9AB22FD16BEA2384C0C7F874A86 +:1023C000E3BE6109F6A575BDE55C3FC664263B2DFD +:1023D000E41A839B7DFBD07F14FD1EDFFF2328932F +:1023E000C81E98F35B07CBF19B40667EFF11282C3B +:1023F000C76F8600D76F8188F54B7CEFDDD2FFD9A0 +:10240000B91FA2FB7A77E257BBC9AE9F2BB5F7CDB8 +:10241000C176B512F248CFFCDAF17FB646701D4A9C +:10242000830592D0BEFA35D129D9EF475DA19DD859 +:10243000EFAEE42DA91D588F9884FDA556069FA4E4 +:10244000FEAA19FC0D58F64D0E3C4F7CF8CB14310A +:102450004EADC5E126F94806168DF3D13B2EA67781 +:10246000D2BB3761BD0CB145F03AD157D09BFA577A +:1024700060B97BC2EAED5468DC53B27727BD3AD528 +:10248000CCEFC36999D75116A75F7CA3CDFC3EFC66 +:1024900043E6F72775590CFAC537CE1C7C1AF73777 +:1024A000E5EF965EF5CECD05827F7C7DCCC144F60E +:1024B000E0FF68FC851092683D0D7B4DA116264219 +:1024C000611F94E9F40891D5446FE50041A27BD8DF +:1024D0008B7A4C9F2797F7FFB9EA233AC476B60761 +:1024E000DB9F2739690F0A3EC1FA54DA8F23085E51 +:1024F000B2D750218305EB49F8A290BB6E203BB6C2 +:10250000A502DAA93E092212E17B0A417A08F9C341 +:1025100032D3ED5450B8AED3F1F740E5F272087102 +:1025200079258485BE07B9F1299CFFAA4F40EC6745 +:102530005498E91D1D19F747686FC0E5B798C9EEB3 +:10254000F0FD30B1BF30A840870B22C473EE709904 +:102550000E814C31BF80879D9EFBA2F070C4C123C9 +:1025600089E0E18DC203E710F03803BE023E931408 +:10257000840FCAA7C9D025D13C8A66DF548297CB85 +:102580002AF073D90B5C5EA8F79C09979248C01299 +:10259000C84F009FA989E96684069F3F1600CB2F8C +:1025A0005DFE5C5B20F3735D0E217F66923D1A2F0A +:1025B0009FF4E7BE94CA2F64A487AA82AC7916D48C +:1025C00067BEC2CA3B8760FDEAA7F344BDACF257C1 +:1025D000B958FF41C128511F5759684578D59B46C6 +:1025E000CFABC2FA90806923F1E5F27AB4AB715FA8 +:1025F00081A47B8244C7A60C709BB03D505FE42D44 +:10260000C07A00E912106E7629A79EE06CFF397837 +:102610001B7015196981C905B8DEFCF99DAB053E33 +:102620002BFBCFC5FEC73BAD6CB7ACB10583842790 +:102630006477777D69747FC79FFE790D3D7F7A004F +:10264000B849BF80472EF4BBCE5C8FD9015C5F8C4C +:102650007283E21F38DF4C9A2F80EA49A6753D2528 +:102660008508FECBEBA7B13F7024CFFFFD82BE31C2 +:10267000E3E33EA4F134AFD073E0C92924B8958CCC +:10268000F45F4BFD4EB850BEA651BBC0434F6563CF +:10269000813297E68D7F6E4EF9E6862538CF52A4BB +:1026A0001192D38B0B0237D2B84BCD914185F86C88 +:1026B00065CA3B36A60B05E993E403F12BEDB7069B +:1026C000E991E87ABFE057E40077B7FD8AF8F5F8BA +:1026D000BB6E58E813224EC2FF15CF0D3E8F6635F4 +:1026E0008D7F3BAD63A9D4B590E8F2F3F4D76C7F4E +:1026F00066BE1C28E84E935B4B9FFB9AF9E7593363 +:102700000425CD3F8618BE5BFA5C9285FCC3A59F6D +:10271000422805DF2FDBF77803F93BA5E8FF939FFD +:10272000BC78D753CC6FFB485F22E896FEF7B3CF57 +:102730003F487C7A6512C7A126BD767408D94153FB +:102740008E461A106D70E2D9372E13F4AFFB257F39 +:10275000339D8F1E9F26ADB887F0BD0CF16FC7F972 +:10276000969982A26E75B855967BC24FAED1F6F19E +:1027700019746E9CCF72453D504AFBC99480E56345 +:1027800048F81332FE23FEBFFD686835AD13A46F11 +:102790006C246F4EA15F4CFBBAFDB178BFA3EB4038 +:1027A00029F9DDE417E33E17B71BDB97C6EA870478 +:1027B0007EF296022D1E960DD9B4AF5FA33FF4C1F1 +:1027C000309A777E1AD9871329AE90405EEAFE715F +:1027D00028B9F29102B697DB25E287324BE2FE0B75 +:1027E000F3855FACDBFFCB1E92D88F5BF6509F5119 +:1027F000EC276BFC0A612FF3EF93A45788CE022FCE +:1028000003D1C12DDA9E60731FA6B95B9B4CECC748 +:10281000D8A53BBCA4F7C73DD2FFB67F63BA4975C4 +:102820004326D527CC7DCCC3F655908435FA556C1C +:10283000673E99DE954BF33F992E838AF3352475D5 +:10284000E5929C559F757849EFC6AFFBED02E10F0D +:102850000C098FDF14F1083C139FE7BC54BA89F0D0 +:102860007C12F99CF0B7CC35BC3F38C96E989C19E6 +:10287000C1B241B3D3731E1B95361BE1E2A3F5C66B +:10288000D8D51DAF5E9342F6F26E8B3FC58DFD4EDF +:102890001ECE35F841F16551189153D84BFB1B33CF +:1028A000870412C05D2F7D9B2C0C2F9D6E7F5DA732 +:1028B000C00756C247B9D8876A77DB7D447FA1A994 +:1028C000E44F2EBB19DC2DD87BD9CB0F3738A8DECF +:1028D0000C4CCD27E97FD4FF137388ECF15FA68CF5 +:1028E000BDB71CEBBB8E59849FA22A87F263EC58BC +:1028F0007BA6196403BD764A8B491E13DD23BD26D2 +:10290000C9C920C7D0634A5E86A1EEF20E30BC9FD3 +:1029100056926B684F574619DA8BA13612C0F514E0 +:10292000654AEE10AEB8CF8C0243BB1DE93A4CEBC2 +:10293000FC52D85125F84FE8DB20DB4365118007B6 +:10294000900E261E37DA59259136F637930E5B0C1A +:102950007100FB59E250C9851A7F0D8481C45F481C +:10296000FF5E9263270F8BB893ACC17359B6D0CF7B +:10297000CB5E96D80E5C76CCCC7AE22478BBF14361 +:10298000F251E7BB78B8F7F51BE1DC7FAE11AE5929 +:1029900001235C2FAB31C2353B6884EBE05A235CEA +:1029A0007354231C87344D34F41FD65669A88FD82E +:1029B0007485A1FFC8D06C437DF463D71AFA8F6980 +:1029C0005F60681FB7F736437B3C5D8D0F2F33B4D4 +:1029D000DB538F305D1D40BA32A13E287CE9DFE237 +:1029E000E8C2C2702F1AE8F48662F0AFE23FC27FFD +:1029F00099969798006A03F1E385C2FF1584FF94C6 +:102A000028FE75B9DA139FEAF81D42FA9AE565794E +:102A100084F07EB22485E9E5E04B270F2B40F84F88 +:102A20008502DCEFAC29228E22C9C126A2934E700A +:102A3000B591FDB9C61264FF4545B3702729E53845 +:102A40007FF3FB25E86FC6ACB35A49024BCC7EC777 +:102A500087DB0DF5C297F61AFA1775860DF5F18723 +:102A600041227D55F0A6F7792A8B3E5438FC55FC5F +:102A700049F0792A4BBF0CDE45FA37DECFBD5AAD9F +:102A800097D2C8AFFF7BFBF368D6A07F364825BF3F +:102A9000377247AAD73400E191FC4E03F9DF807604 +:102AA000B4159511B80FB23E98EF10EFFF2D69F2F3 +:102AB0002AEA6F42FF9CF08E70C9237BAF1692BD4D +:102AC0000417B25BC80F832B843DBFDAA4B23D9AD2 +:102AD00084F628D9230D157EB697A74370203DBFF5 +:102AE000069455C4779219ED577CFE3F23028D85DD +:102AF0004562B1443F777D21B3FF3D85FC6906A661 +:102B000002A4F74ED0EFB43E78691EC5E34F902E75 +:102B1000C3F5B7B5BC304F253BC303EE08AE3B2031 +:102B200040069B0B03F7D0B8EF9BDCAB0BF1DD83CA +:102B300013FF3288EC917585C2EEB34B0829A4814E +:102B4000FEF315A0E78DD9CA7D8545D1384B4FF4EA +:102B5000A3C733F5F8E6AEBA309716B75722BA8B4B +:102B60008F3B46CCEEAAF1A4FF9699D8EFFC0B2D33 +:102B7000AE94E7496539EF804E7B3A2F99FDFFEB24 +:102B800035BC991D9DAB7E8EEFDD1014F6D60293F9 +:102B900097FDF5DB338F731CC52E99C047FE505A45 +:102BA000FE76117FD1E3259749DFC6CE3ADB7E6FF3 +:102BB000CF3C668857C1137D12C6D7A3E3ABACFFE9 +:102BC00062F6B9659347E835F2F3DF6FCEAE84D491 +:102BD00044F37CCEF1ABEB83AF1AF8E2C6DAB70C64 +:102BE0007C7093FA9EA13DE2E9B252BC32B2276BEF +:102BF0003AC5D73FDB6D2F263C20FE0F16C6C4EB2F +:102C000022CDA3AB60ECB9ECF72FBC8EA3759D8CE5 +:102C1000577DBFEFD4BDC9F5485D84CBF8FDEAF11F +:102C200011BD4471D844F6CC5D12CA0BF277495EEF +:102C30007862E405401ED9FF7749A3BC44EFB6FD96 +:102C4000C147A9BDABDEEEDEEEE3F808C74D6A91E1 +:102C50002EC86E00A7787F81CDC176E81D3EE12F9A +:102C60001EADF8EA06B25F7320D58B32107FC27FAB +:102C7000A2B8C97C531AEBFFD55907B8FE61338857 +:102C8000BC514DF821F25797A6A60ABB58C1FE5871 +:102C90003F9161E6FAA11181AF981FF3C39CDF5801 +:102CA000DA5FC4F3C01319447CF833D9FFB5E05799 +:102CB0007780DA6B32D0DF46FAFDC4AC8E35116B0B +:102CC000ED1A70AD05F1FE49B2FA395934637CFD55 +:102CD000AE253FF3139BE0DF49BB4ECF53113E1FA0 +:102CE0009A24F6CFD5674C1CAF0167C4568D7ED8A9 +:102CF000038303561F8EDF66457BD2299ECF1E13AA +:102D00008DCB9EB0624971D024513A7DC2EE75F9E7 +:102D1000449E532F4710CCB09CE4D3E57CEB708AE3 +:102D2000BF9DDC6C07925B38BF42FE96FAAC88E32D +:102D3000F7CBF02F028117F71A5CAF6788FC05F11B +:102D40009F4742BF16F721FB720CF167726053B1C7 +:102D5000FDFD3DF66D84BFEEF51E16F1B0CF9A472E +:102D600073BC5BA713D9A7C5BD7F0C20DA2FDB4648 +:102D7000ED8B5F7EFF1D8ACFFDA63030D487ED0B33 +:102D8000CC7231C9C9C5A91D1CA72BF6C93C2FAEF1 +:102D900097F78B72AB117D7158EC88705CEF6CF11A +:102DA000FB9EF6FFD9CD9D1BF3395E2D8F25B9A271 +:102DB000CF8BEB28A675E8FBD4D7111DA777FED1E2 +:102DC000E3D07AFDE387D60CD7F20837FA13E8E5AB +:102DD000AB743AB6268EFBD768F88CC74FC18860B3 +:102DE00088E3796E703760FD5A0D4E9FCDC3FD703C +:102DF0003C44194FF85D3CDBE92538EBE3F7CB8029 +:102E0000C053BDCC73C548FF1CA2BFDB82224FA0BC +:102E1000B723FD893867730AD3EBE2E7DE7AE7E789 +:102E200038CBAD8F8E2924FDA1BF1F0F6784EF70B3 +:102E30005ACF0249E4CF10BE37D1F8F1F981F385BA +:102E4000EB89EC4ED60B27B6FD2C44EB3B91056E7F +:102E500013F2E3E27DBF7DD33496E8C41996B084C3 +:102E60005DC6F857BC9E7243E03A92237694236481 +:102E7000DFD8F5F7065A0CEF55672A77F9D81F55B2 +:102E8000EE2679645785BF362450C1F5E556E1AF8B +:102E9000EDEA34CBC4DFBB2C10223DBEFCD50C9533 +:102EA000ECC7E56877B0A79317E4F54232FA41E939 +:102EB00009EC069357E6785C5A600DC14BFAD1D401 +:102EC000079FC889FAA3BABE2CD2F4BD927F6303D0 +:102ED0008DEFD3E281686772BCB314029A1DA1C55D +:102EE000E19A0F701C4297DB3698EBA0F8CF9ABEA0 +:102EF0000B1CE41FCA382CC7D73CB3D3A0173B72B6 +:102F0000551D4ADA11D1BAB5073F5E3F1FC06BECC1 +:102F100047DB0512D6D07AD5814823FEDA3AEB7723 +:102F20005D2F60D932E691C84A6AFBE6B44476A4C4 +:102F300043B303B8E847EB14EFD906AEBEC384FA37 +:102F400033D96B81F763F4A00339FFFD3C6D5EB2AA +:102F50000732BBDBFF4078EB691F17AB24F8BC6F6F +:102F6000EDA5DDE6AD49240F12C28BC8C433FD18B0 +:102F7000D16332C4EC9BED9E98BA14072F89CAEE38 +:102F800076E57482FCE577DDD7AABAF0AB1F1AECC0 +:102F90008110AFDF6AF18317E9C9E6C176C3390C46 +:102FA00055CB7F220117C7ECEF1CF64576B955DBF0 +:102FB00097F522EF8BC6F5F7BBA4D7A75EE2EB0B24 +:102FC0005FE2F885EA4B1B7E4AF5A50D3FF5125FDF +:102FD0005FF812C72FCCBEB4D7A7CCBEB4F1AB5E9E +:102FE000E2EB0B5FE2F885AB2F6DF829575FDAF063 +:102FF000532FF1F5852F6DFCAA6C073ACB81CFCD0D +:10300000A6379A4374CE46AA0A73DE3857058E4710 +:10301000A73603E72BB67B851FA5C7E947D2103239 +:10302000FA2D567716D9D1DB1BEFABFC318E732A04 +:1030300013174FF9FCEC230A8DB36D1A70FEC2D939 +:10304000F8D1518A7FE540D81BCEA1B89A04E11887 +:10305000BBF4FA600A8463FC896AA58FA15ED43947 +:10306000C0D0FF964D430CED37B78D36B4FFA8A9FD +:10307000D050BF492D33F4B7434E4B1EE55D1B2D99 +:103080005ECA8359686FA567C20D76D8F83D05FF03 +:10309000911F9383167DF7B8B88F74D56618D7192A +:1030A000D77EB67C407C3E614EB1964FE8FE7E41B5 +:1030B000BC0F6E4FC2B8A79E4FD0F139DC92C4F856 +:1030C0005AA78A7CD39A69C28F9C1A729B286FA9CF +:1030D000E36FB44672FABEB7D519FDC9F446772539 +:1030E000FBA34DC0F9DCDC2A7348C9A138C1C04A32 +:1030F00007E239B443D04708047D841A81F385A1DF +:10310000AADC95D47E2A047C0A46A78FD1550B678A +:1031100052DCB53EBB5F16C51972AA043D2CDD6BAF +:10312000A4034AE7D256D30F4BBCFEF4FA8C02CA72 +:10313000E79D819727049CF5F3E7E97170CFDB6188 +:10314000C44B3CDEBE2D5ED614C77F57F2EDF06255 +:103150009B2177A4519C540599E2322F660F373397 +:103160001C9ABC8C9F19D88DF830A70938DF134FF3 +:103170008FAD7510AE8AE1DF1C6F5821FC4C93F2C5 +:103180002B99CFF0DDFEC0A744195FDB9A44FE16F1 +:10319000CB641A1FF6CA0328AE105267F3BAB737CA +:1031A000DB92E93CDF57F566A0F3F2DB73E40194B0 +:1031B00017DBFE8C696EECF920A40ABB3993F7612A +:1031C0003797706911A5A2956011ED6189EA835660 +:1031D00098E3F0A94AD49E3E2339EEB962A2FE5B81 +:1031E0008A73193E694A86015FD61223BF23180FDE +:1031F000E5A37C1C4CBFCB4457824E42AF4BA195FC +:103200001C5FE932D510DD68E72DD257CD06CA47DD +:10321000D567FF742ECBAF7A1BC31D5608BAD0F307 +:1032200082D6264187F1F4E3F21AE9C72A0D3489E0 +:10323000FC96E01F7D1DDB146DDE2C0954967BB6D9 +:1032400001C467D6B8F1EC243C49DE78045F3A61EA +:1032500036D07BCE123BE7B1413ACAF8B74E00E810 +:1032600013734E217EBD675DE777A4F30FBF239DE7 +:10327000EBF267AD57933F45E25CE429A46B8A1FEC +:103280004DADEA04FEFE0ADC26A247A4835959C5C7 +:103290007CF4817F76911CB213BCAAD3A8DDD5A99A +:1032A0004C25FA9D2EBDA2B8709CB587059DA37EC6 +:1032B0007989EAADCD16A0732628674C3FA2794BD9 +:1032C000EDEE952479A481E369DD853E943B1447B6 +:1032D0007CC5282F8A3A8D70CB8D97EB3DC0B127E6 +:1032E0003D110F47D7040D8EC508C721DF1E8E364E +:1032F000AFD0C3E92542CEBE98FD537ED57D589C04 +:10330000AB495780E1FA852AF4F274E97898E4CB66 +:103310003A05E50BB6CFD0DADD25429EE870CED572 +:10332000E0ACCB9375F32183F8DE4DF2C44970FD18 +:1033300088F5765B9180334084F39FA98AE09335CA +:1033400056F0529CB6ADD4E9A57861AEA2C1B7499A +:103350008397094C04DF78BA9421A68EEB4B8DAB92 +:103360007F5BF8964ED0F4643F283E1FF8AE4B4981 +:1033700015FC3654C0C7EA8CF0B9E6A61C8B77253D +:10338000F275470EC21BDB9B5E17F0FEA5D67FD5FC +:1033900018E07A53DFD5990CAF9C859944CF4DD670 +:1033A0003695F2584D3AFD69E7C25C9A9C9886FCC6 +:1033B000BD00DF5F8DF289F290A92501078DD794BA +:1033C0006F0189F7BFD99B68FF0E9FCD20072FABF8 +:1033D00031C235250E8E49DF91FF7F3CE1BBF1FF05 +:1033E00076FA15FBAD1906D0C979C89083E0642B35 +:1033F00099984C74D4D2BA9DEB32849A7271FF0FB3 +:103400003B85FDD5D23ABBD7F351214D2E6CA97324 +:1034100070795F9D9BCBB6BA4C2EEFA993D97E698C +:10342000ADCBE3B2A5CECB65535D0997ABEA14EE05 +:1034300027ADCDA860395C051CCF5E99F239E7DF76 +:10344000E3E7CB518D7A6C706DB201EE7D6618F5B5 +:1034500055BA62D457748E29B6DDE51D65684FC92B +:103460002B30D493E48986FE5326047E3981E48090 +:10347000A7324E0F223F8E899EB36B6915DF4BE951 +:10348000F0D3F59353E3F33556EF00CA3B395B05B0 +:103490009F366B765E13C111CB6405F8DC8CEDB002 +:1034A000E40D01F1FF6AA6F38771EEFE488B1DD98A +:1034B000D7286427B4C8C28EB78238F76BCBF4879D +:1034C0006BF07912EA2FCAEBDAE6A6B05C78D8E3A3 +:1034D000F4D239DB96D6656E5E8F579CA771E3BF39 +:1034E000447980F8F3358EA1C67339D6B39C6FFC4E +:1034F000754FF4DA9491508E9C2167BBF32FEF6BDC +:103500007429F22FF778043CED3DC8A3D6387BD957 +:10351000A9E55F60A02F61FFA83D25F20BAD717199 +:103520007BF4C312E66FDE9A2071FF3F4F9085BF98 +:10353000660903C96B9717DF8FF53B14F17DE8B976 +:10354000CE8F3F3E4F8C7C0A2407FE3C019F2B4FC1 +:10355000083B254916DFA1D84051583E81C887D085 +:10356000591FD237A95ABEA75BCE908888A13BE7E6 +:1035700019FEAEC88BD06716443F96E8FB17C4BF50 +:10358000FDB66523F9C3C37A69A7FC5002B9E02AE6 +:10359000D1BF1F832E4F3180EEBA23FC5C2589E119 +:1035A000172678359AD6CDC8C5E7A95E8B173100A6 +:1035B0001525F25E3A5FB14A4965FDBEAA446E2701 +:1035C000FEF942717A091FADF955ACAC93867DC8FE +:1035D000A2B7B1C4C676BA8E87246D5E444F679594 +:1035E0000E67ECEFCC9B11ADE37FCD6336725EAF1F +:1035F000E5AA4738DFD732EB3F38DFB73A6B7A1EA0 +:10360000C9BDA492E9C7F82097861F660DD2237919 +:10361000C6FCDEE9D3A2CE70A0F8849607048F31F1 +:10362000CF6791FD86F92F349E60A0D0436051F89A +:103630007B8333E95BF0B5DEAF673E50F5EF4E5765 +:10364000D2F9E0268F90A34DE07D3340F55724AFAB +:103650002AD3F38237E9BCE9EA8116C6CBEACCD992 +:103660004DC28E177E53936725E76DE3F5369DD7E0 +:103670008C95DB745E3356BE37C9B37BD5CB59010D +:10368000739CDE37BE9F1D34EA1FFDBDA4CC2B5FAB +:10369000AB8A392FD56CF13B485EACF2DC678AD53A +:1036A000730F2881052531E793AC99B3F83D7BB6BC +:1036B0002FE1BAAE50948544DFB8FF5EED81F59AF4 +:1036C0005CDCA8E997B3ED7393D6FF01ADFF66D23A +:1036D000EB23A2F8193EF4F26496CFEB441C8379F5 +:1036E00020665EA524B082D615C5AB390A17A4D3CF +:1036F000E1F957B0DDD1B06E7632E169E7FADED795 +:10370000A3E7D5F57E7A1E353EBF6EF3980DF0DF48 +:10371000A3C985175C0B2B1F40D0EC6C13F4D4B0FD +:103720004EE891E14F887D9C4987C6F5EE6CEBDD54 +:103730000E8AEF4F91C56E3AE17A465C7D405CFFA0 +:10374000DCB8F65171ED0571F58971FD2BE3EA578F +:10375000C4F59F1D57BF36AEFF82B8F6DBE2DA979D +:10376000C5D5FFCD884FDFB56989E0188F3FBDDF34 +:10377000B9E2EF5D5FC57EA2A3E13083E945A7B75B +:1037800073C543D4DEF5339DD94A46B17CDF81F65B +:1037900015D9433BDB2ADDE27C4760E56E8D3E4870 +:1037A0003F58368879D0CE4AE6F89CD36390236799 +:1037B000C3B709328CEDB17668EE85C7F7D9E93326 +:1037C000A4D917BDAF5BE7E32913FC27490E414895 +:1037D000F899BA5DBB4D15FCB34D5D50B99EE46DD3 +:1037E0009359C49FB5FB50E86E1D11270F684A38E6 +:1037F000C2F18426CD4F68D3E4C95A4D9EDCADF9A1 +:10380000094943839B28EE9B7C988FE740B3AFE048 +:10381000AF0B103FF797166FA3EFC7EE1E53F2F8EA +:10382000C35877FD5D827021DAE9635B14B259DA1F +:10383000948C243A4F946272B4939FB8AAB0CD3F4F +:1038400014FBADDD7FACFD79C4B39C69F3A2CE0758 +:10385000D9D265227A837C2F7F9786EB54C9C6B272 +:103860009677D5253A77BAF60AB7898CB0F419B2AB +:1038700099CE11F79910E85B8AF018DC046605EB25 +:10388000196A98CFE25C532A0BFFEA196428DE6FAD +:103890005716C1EBAB66DB7EAAF68C0F90B438DD11 +:1038A0007995FA38698234E887E38EB245ABAB8FFD +:1038B0006CA6F3D04E49D4A73CF3F8FC95F9D1FAA5 +:1038C00098671E1FB812DB5B0B0799489EA67B52B8 +:1038D00013DE137375A9909FDB9B170E4EE48FE9DF +:1038E000A53C13383021E76B25D1D4042C876AA579 +:1038F000AC3DCF14F52B35B8C9B55ABB4794177AF0 +:103900009EF8F1E794BA753B7B809F8D6CC877F683 +:1039100033D88B5797F6622FA279CCF1DAAD56796E +:10392000009D23DCDA6C03BAFF616B3688EF905799 +:10393000D9F8DC2858DC03AE7145D71D5AD56F1E67 +:10394000D14DC80486386EA6065FFB4493768EF28E +:103950009B307DC7B755CBF36C8588DB9D1F8BE70C +:103960005FCD27BCEA78DE57FAAFCD449F1DD90B57 +:103970002B37E27BEB1ACD1C3759D798CB744EE32B +:10398000907D746AC52133D9ADF9D06E263B7F1482 +:103990007D793D84AE400A70D9AEC9E7FFD4FCF80A +:1039A00061A0F0F341D0C5C0F9B438F01382CB1058 +:1039B000126D12F18FDBE4C07996EC4BAF48A4B7DF +:1039C000EB4AF5EF7AA1C652ACF91732C3B78EF8BD +:1039D000281EBE74429FE38E8ABF9EDA9D7B5F0DD8 +:1039E0005F86D5DD6F18E993F0363B46CF6CD4E0A7 +:1039F000E7F6FA15C2E1B5C581167A7FC9A6BF1EE2 +:103A0000207354565533BDFF14E11D9F2F0C07A79B +:103A1000D33063BCE14AEA3FBA76DB7E8AA7E5058C +:103A2000EFA8EC8FEB1BAE54577A888694C0FD3418 +:103A3000CED0CE48850BEBCE4DAF86B3783D6379C3 +:103A4000BC5C7D3D480FD54C476E11C7D7F04BF895 +:103A5000A773CB0B370BF8607B16EFCFE2CE8A5DF6 +:103A6000FFB669FDF8BB8578BA68D5E0F758148EC3 +:103A70006035FA358F2582A34EA73A3C6E78A26B4B +:103A800015E53AE7873A5F2439E8DFE49EC6F2B0ED +:103A900038F024BDEF6BF337701E7057275D47D4A5 +:103AA0000D1FA7D249D7BB603FE569C2FBD615EF12 +:103AB0005772BC782F88B8589C3ED44BAB129F6786 +:103AC00010F7E58CDB6BB493915E958D9E587A353B +:103AD00073BE33A4E9935013D22FCDB742D06F48B1 +:103AE0005DE64E44678F687A658746B7FAF3A13D75 +:103AF0009CBB3C54DAED27664A46781EEA8DEFD32C +:103B0000C0CBFC807C7084FA65101F607DF00A37A2 +:103B1000D3A7CE074BF6FEF500DD67E3F4C905B188 +:103B2000F7D745343C227DBE43EF2FD9D475807C36 +:103B3000C5C12B047D7E4C77871545E90CFDC7F781 +:103B4000A89F4E3FF1FB78571B4F2EF67F4C785CB9 +:103B5000B829C8E321FF1C2BE5713AC349CC724A4E +:103B600025ED676B1BB8693FF65F1474905C3855A0 +:103B70006B62B8DE981F5E65C6F2FAA160A5EB869F +:103B8000AA33916C72298F6BCCFF0D6B33E20FE976 +:103B9000E76F344F91276013C1EBA08DE5690F7477 +:103BA00011D57BAA0EFF157172D73CB1177A3ED79B +:103BB00071D7162B8E8945DF621DE7D84F8F379D51 +:103BC000193F1DC5FE434BD36CFD9CF00CBA8F67AB +:103BD0003BC54F11AEAB9A7AB7572F58FCB4F9A436 +:103BE000889FAE008E03AD4C196B4A44379740FC5A +:103BF00074CAC444F1D3C87B063B735593900B3A07 +:103C0000FC86578D4C16792948A57C891E1FD3F751 +:103C100075B7664F3669706B21B8313C05DCDA0840 +:103C20006E0C4F1D6E33843F425F8853BCD66316C3 +:103C300079B1910B3651BEE054A6C893D767DB44E7 +:103C40007B8EC82F9C411F9931F634F2C19A667160 +:103C50009F08BECF79B517B30F3886509E33D3CCAB +:103C600071DAED9EFB6AB6733D99F9CF0A6A5B1E65 +:103C7000CE3BFCC3B9EA027A5E62E773F27A3EA7F2 +:103C8000A5AFC8E7B8F2B47C4EDC7C76B8A9B28D9B +:103C9000E6CB137E4B8F74ECD3F2115A1E2823DF30 +:103CA00098AF70C4E52BE2F3956B9A17ECDF2EE228 +:103CB0002B2C9F87FF7824FB63F1F3B8671AFDB7BD +:103CC0003523753FEA1147A2EF1852AB8CF4D8A206 +:103CD000E1BBA1AFC8479C6D7C284F36F8552D79C4 +:103CE000E71647D0FB911FEA4ED03FDE0F3D1FFF86 +:103CF000D6CDE31BEF074CE0DF6E99C8F11441DF2E +:103D00006B9AC5FEBBE3699A5FA59F3FD2C7B16AB4 +:103D10007E1CD773A2724ACF870D75DB985E876AC7 +:103D2000F74535FC7B4A68650EE5D76675513E72EE +:103D3000E80E89F3EE439D7ECE43746C98CEF9F184 +:103D4000BEC981A727C6C49F76B87E9AC9F9022D3D +:103D5000DECFF7E6A0DE53D715762A64EF8E04BED9 +:103D60006727392E1F107F3F4E7C7D4E99D0C39917 +:103D7000D741C27B4F3E9F28DACFF4DFAF6038A136 +:103D8000BF9B2CE4ADA2D7FFBFE4A976B61DE2EF3E +:103D90007D4EF94093B3FF0997A29C3D5112389E86 +:103DA00050CE5ABA58CE8627289F919E5C4E177DDA +:103DB000101E6E4C7C3F8F5C76A9E2E16981877CA6 +:103DC0001D0FF75C92F942C4437659223CA05F452F +:103DD000F06AF32983A85D29510653D98D8F1F26D8 +:103DE000E68B5965C2EEBB58F858A7E1E35EC207FF +:103DF000C769642D4E93C7CF9B357CAC39031FEF49 +:103E00000B7C94E8F878EEBCF09151956168779757 +:103E10001BF191EACB35D49DF9467C240F2D308CD3 +:103E2000B7BC4C16F7240D9C68E877263E8CFEC084 +:103E30009DF45E2FF6E8C04067057D4B34606E7BD5 +:103E400007C9E64C7F5B0595FA3E37C7F9737AB927 +:103E50005CC35FE6D4C4F85DA0F15BC644E526030D +:103E60003D7C2F317FD668FD979728B794C5F2F334 +:103E70009589FB2FD1FADF3641591CDB1F7FD64BCA +:103E800031F6784FFB0E242BCBCB78FD224FB6A317 +:103E90003E95F3663B92E476CA57ABF54EC3BD75CB +:103EA00083E937AC67FEE89B0E95CED9D13D4168DA +:103EB000596DBBA35FEE1A6CDA96317C25C1B1A9AE +:103EC0006C88B8BF7591FF6DCAEF28EA09ED1CD266 +:103ED0007CBEEFC814EE63A27BB2C09D714EF92385 +:103EE0009467E25EB7C120BE238620EB41C90FE98B +:103EF000F4DDB205FC225F4EFDC5F785BCF9140860 +:103F000073DD0511AEA7697EDE0365393C6E3AC8E4 +:103F1000260124AF89E4A8CEA70E4F90E9DF53EB2A +:103F200036AD245FCE0250467EA073207FCF0B9526 +:103F3000A0523ECB040EB6334DEB0F7CCD793AFD4B +:103F4000FBC397FB88EF0FCF717FE7DAAF91EEE508 +:103F5000F344EFE56BD4EC01FD5E3EB532C8DF976C +:103F6000AB2BEDEE06CF99DF973F3A31B08BF0FDEA +:103F7000B7A4412191640E4E98EDBAA0E3872FF2C9 +:103F8000F8AF5CE4F1DFEC6DFCBBE9D752CAEBF9AA +:103F90008F123F37B88AD9EED4CB78BC5DA12811F7 +:103FA000EA27395E1BF0619FA83DE73C6A627FA863 +:103FB000C124CE9FA9EF99D8EE827C41074E19F219 +:103FC00072C645C7717A838345DC49C45FEAFF74D2 +:103FD000D708B2BF7F99322B9286E31D7C55D87FDC +:103FE00096A991CD74BF73FF349B773BF2DD3DDA28 +:103FF0007AEDA513EEBD137FBD798A90172E8BF74E +:10400000F2023EB7343342F6A3ABD82253AEC01906 +:1040100097D76CB5B42553BCB275C77D15A3B0FB5B +:1040200063752FB91B137CEFE9D4F29A23A5C472F0 +:10403000F09F939244DCCB67BC4FD85AAE9D2B497E +:104040008554B2232DFF52D2129D07D04B7DFE2204 +:104050004FA48ABEBF8ED0256E88E7A292EAA464E0 +:104060000F9F8BE824F8567AC30EB27F1F5F10BCF7 +:1040700035F6FBD3D61270911DEF9B22CEC36E5046 +:104080002417DDAFF160C4C2F78E3FB8E8E9E6144B +:10409000ACEF3D6A76133C5AFDEF3993B1FE388E92 +:1040A0004BF2EEE00E71CE529D0FA16108BF56F2A9 +:1040B0002AB1BE5B11E7B2D9212BD6AEEA43F8FF95 +:1040C00075725F016F0856D3BD9DEB5226F37D9646 +:1040D000D973443C78BA74B483DE7FB0C4CEF81B85 +:1040E000A29DD331A9D57C9F65DFF9C6733A0F2E07 +:1040F000EF5409BFEE52BB5BE5F3974ED7587CDF18 +:10410000F5A8192456715D3CF974C929D6E5157EC8 +:10411000EEE37258A5FB8EFBE27BF56EBE35D170E7 +:104120001E68F726E19FA68D777A91D271BD71E75F +:1041300085F475B5E1BAE8DE63D7508E4764CC31BB +:10414000AE2F2DCE6F70C6D5A79677DFE3339CF0E8 +:10415000FD85FFA785AF71AB574EE47FB6D64167AB +:1041600055CCB904670F71C09AC982AE6D592F380A +:10417000C84EF9C27FC4433878E59F073EBC97CA52 +:104180007FFD6ED75284CFEFBF7E73C793B4BFDA83 +:10419000BB0F11BDEAFE189FC1C4F5BC586D63B8D2 +:1041A000F96768E7397D1D2F587DDCCEF9A5B5FB91 +:1041B00093B87D64398492B07DA445C9BA99E8AEBC +:1041C00053F2D6CB3488388FA8E37FED0D7E138C65 +:1041D000213CFA25BA0F639A76BE76C3229009FF76 +:1041E000B645ED7C5EDDB75C9C57F729D5497CDE92 +:1041F000748E99CF87D4575F73F930ACEFBA5CDC1B +:104200004F3563B9328FE75704BDA475169B9713DA +:104210005D6689FB9AF4F3A645D0C5DF7F8CF4B6C2 +:1042200077D848DECC4700D3FA5A357C69718322AF +:104230005FA74AF6A4CB6BC463461CDEE2F1BA4228 +:10424000C7E34818497894A12D99F4E14300ED742F +:10425000AFC086E54FCFA3F36C5FA8690CAF9EF8A3 +:10426000F91DB4579511740F8B83CB4EB457A9DC4D +:1042700085F62A95AE60C575CB71DD7BDE38F8D248 +:104280000F71BA594AF5957444AB48CB7B81BA7427 +:104290005025AEFF06E25E51DF4289C4777D92A1D0 +:1042A000BED66389FE3D00FCD595A5FF7D80D35B1E +:1042B00094A108964C8B968F11F559E487C4B4EFFE +:1042C0009E69EC5FB63F66FC81B8DEC5366E0FEDC9 +:1042D0005BBA45B5C4B43F87F572805735FBF1FA38 +:1042E0009D66FFF604F2EDDD7261475AFE052AC9AC +:1042F000B52FD14E23FF5E322B2CDF21D72227BAD8 +:10430000570F00E561AC5F2E1BE5EBE51A5F58FC2B +:1043100015A0E5C7E01B3DFE803F7BFE388BEF63B9 +:104320005A35C4C2F70FA13EF0F696AFB3782C9F72 +:10433000C6DEDBF5AC2EBF87C1309AFF4B28FF43AA +:1043400005F341CCBD0DC4F76DCF5FB614E7F11D89 +:104350004DE638AAE45A9FC2F731D535B13C7F40CB +:1043600009FCB63CE67C4963FAC242922FFA3999BD +:10437000E8BD47D798BFCDBDF71DD50780F4C297DC +:10438000485AF65EE8B0B16EEF115AC7EABA762E17 +:104390009D6E85858DDD12E4B8CF154AE04FB43EA1 +:1043A0007B26B6C7F089D58DEF19FC0EE37D9CB254 +:1043B0003BE224B86F28F9C049F3B71E167CBDE173 +:1043C000F0EC24E2BB56EFA124E29B2FE8E2C7EF1A +:1043D000C0273EE5559661BBDF48BD9EE8674F4369 +:1043E0001ADB150797DF7F2DF1CF8DBFF801C3BB17 +:1043F0009B6FE0E14195CE18BE818799AEBBF9462F +:10440000ABF7CC377F67BEDADDCD37A2EECB074303 +:10441000FDE04C63FF6EBEA0F1912F1EAFB073BBE9 +:104420007DD2C35BD418BE3A49F558BEF909F24DA6 +:1044300002B93F7D9246DF17986F522E32DF0C9DF6 +:10444000A4C9CFEFCE3763275D14BED9633A1FBE30 +:10445000B9EC4CBEA99AD4F7DBF34DAB3BCCE7E902 +:104460005AE79813FE7D900F347939757EA0B28D8E +:10447000EC1A45DCDF374D9A99E5F3109F497487B4 +:1044800034EA4FA1CF0F5EDFFD7D06EB67FDFEF541 +:10449000F58450B293160BBAE9AC1371DF6952F987 +:1044A000B4C5A477E93B024A3553F694EC02D4FB39 +:1044B00032D985D05EE1C179365499A04DA62D0739 +:1044C000AB87F1F861B6CF8668717FA7942FBE677E +:1044D0009A29FEEE85FE5D4CB562BC5FB6FF59ECD5 +:1044E000265C770AF931EE12F17750164D8AD7BF64 +:1044F0006887E0FA3A07DA984E362857F71A273ACB +:10450000E35CB52F98302FF9D6249376CFBEF233E3 +:10451000A2B3DD6F6C49A673127B24E0F339F383F9 +:104520004FCD23BE73A942DEB4AEF833A52361D7C5 +:10453000B41F1AF5347C6AD4D3F0A9514F6BF51E21 +:10454000E58D7AC2A8A7B57AB79ED6EADD7A5AABCE +:1045500047E5CDA7063DBD61D2A70679F31ED5CFAD +:10456000414F1F9E7471F4F4A88B2C6F9EBE70F2A5 +:1045700066DFA4BE1743DE1C392F79937DA6BC39B4 +:10458000743EF2C6B5B943A5F4CCC21EF8A056C31A +:10459000FB5B65CADB343E949C5BBC269EBE3AAA9C +:1045A00017AEA6BF2BF3A557F87F3DBDEFAAFDD5EB +:1045B00091C6183FDC65E914DF23D4EEE1E7B76C60 +:1045C0007E95E3B1675D2F5D105A74A65E45BBC84A +:1045D000C1F4EB35732EFC7CD7D13A47F0DB95CF95 +:1045E000DEC1FC945C6E9C4FB77F3BAA6D669EAFAC +:1045F00044C8E99EECA19EE6FDA05C16F7FFC5CD80 +:104600001F4FBF489FE9938B981E2D742FF8179D5D +:10461000C07FA7EABF4E6EFCBF8A7C49E9C51193F3 +:10462000CF834EA76BF84CB06FEFC5DDF705E3CF36 +:10463000E993CFC38E3E4CFBEE9B70DFDF67385EA5 +:10464000B47D5F30FFE1E6F3C1F7BBE5DDFBE6EFEC +:104650005132B47D6FF8E735EF515C63C3BFAE7D77 +:104660008AE21AF77D9DB78DE21AFABD726910FDD4 +:1046700091F5EF8F102E2EBFF89E24634ECC774518 +:10468000C0FE7DF4BB13B2377CDDEDFF2BF7CA9182 +:104690007DD2DBBD72AD36635C4F2FAF2A17F64A71 +:1046A000AB691DC72336A05F558F78EB9823E211C5 +:1046B000AD68A7B0DC9953D0AB7DB4AB4EE1B85335 +:1046C0006B9D9FCB7BEB6670B9EBB5256524777D41 +:1046D000AF2D62BDE7F3FAAF7B1881E4AEF8D049A5 +:1046E000CFEFF5E8FE90B05FD2C87EC1FAC393D792 +:1046F0006F8D8D0B8CFAEFE15BD481D178555B66C1 +:104700008CDD23C7FA51A012B944FD28AC1BEC9AEA +:1047100011EC47ED26BB06EBED934718EC1A7D9E96 +:10472000B566A821BB66ED0EF38C4476CDACF2C421 +:104730007E14D6390FE27039F8FB7F49FBFB5F51DD +:104740007EE9DDAEC99D7271ED9ADF4FBE30F18713 +:104750006E3ED6EC990714E50D4DAE7C47F9B1D10C +:104760004CF1E36F2B3F4692FCC837C88FCFCE4742 +:104770007ECC2A771BE2A20765B5CF58B2D37798D3 +:10478000A15ED6F42FD63BD1AF31219C7E5221B110 +:104790009FB3C10BFCF7FDA64BF35F267AD8BDC8CB +:1047A000CCDFBB3FA88873220FCD11E7A91E5E5E48 +:1047B000309B3E235A9772C3DD4914D72E17F70456 +:1047C0004C97CA39CEFDE00C61E7643BDB2FA7FDB7 +:1047D0001FACB000D1D5D9E2DC146EE778B5E6475E +:1047E00081B499FD0ED70F2D6E3AAF1A1FBF769682 +:1047F0007CCCDFCD83F40A7FDF7DB6F8F5B78D5B27 +:104800000F98F29DE3D6CC8F35CF0DBF41759E49F1 +:104810009F4726CBE25C620F7A2C9E9F3BAAA7A7FC +:10482000457A3917E524FB29E61E59FD7BD659E563 +:10483000621E27D94F8551BAE8A82EEEF55EDA94AC +:10484000DA678EC4E685522CED3C5E4AED3E7EBEB4 +:104850009ECE2F90CCB27859AE3E5E89F239C178A7 +:10486000FBEA8287092EBFAEAB3D4C71EA49964EFA +:1048700089FE9EEBDE3A95EB7BEA9AB8DC55D7C60B +:10488000FDD6D76DE2F2BEBA103FBFB7EE31AEDF54 +:104890005DD7CEF5C773C53C132D211E6752178E09 +:1048A0001FC30F659FE03C31782E8DA886F6096FF7 +:1048B0003619DA8B3ADB0CF5BEFE4D86FE7D66843A +:1048C0000CED6F950502538AE85CC363867ECEFCCF +:1048D0007643FD5CFD850BDD6F654AAAE51FC8AF19 +:1048E0008302484F4867E9B5B2CA79F31AC197FD08 +:1048F0006BBD61AA6F71D998BF75BAE433CB26B18D +:104900007E53CC3DB51D2E717EB2A1AF88A734FC7D +:104910004CD4B76489F391C3AB447EA461A0B8972B +:1049200044CFC36F7169F793F8C43D1A83F223FC37 +:10493000DDED20EDEFC139CB45FECC0D6ECECF378E +:10494000D481F67D6284F31D1960F68AFBD5159932 +:10495000FF9E920542F5385F43BE5BBD85E44C3057 +:10496000D56BF6F29F960D99298F48E2899330ED29 +:104970009ADED1F2F2491F009F3BE886CFE7E27B47 +:1049800084DA2EBEB7A97F6D17E7E3B6FC42DC637D +:10499000130FD78E5F7CC5F72A6DFDD95759C4D444 +:1049A0005BBBCFED7425C57E8FB6A52695EF5BD892 +:1049B0005A9BCBE728B6D688EF8D6510FBDDB2C8D1 +:1049C000C6E730B6D69ACD24274F2DB2305CF4F529 +:1049D000C7CFAB7FBFB94E3BD773AF76AE67AD766F +:1049E000CEEA6EED5C4FB376CE6A8D763E76159D3F +:1049F000EBB1133CC5B99EADB50B14ED3CAB7E2FAE +:104A000003C35742F8F2772A56D86B1A07F4870C7B +:104A1000196EF1DFC7665425C79DE7319EB74AF589 +:104A20000D30D49DF9C6F356C9434719CFA90E34AA +:104A30009EEFB1798CE77A2CCE4AE3F9D058FA444C +:104A4000609A566CAC27FC77FF7D477AD88FFF7E43 +:104A50005C37FD86F47340129D4349637ACDAC12F6 +:104A6000F499A17D0FE3864E2E53915EA874529E59 +:104A70005DA273902AD351F4FB37A5577A3ADFBF72 +:104A80000720AD4CFCF700F473087FD1ECA8A553C8 +:104A9000944FA71445E7BB7F8A723CB6AE973DC9D9 +:104AA00085FFADF2FF01C18CE32B00800000000008 +:104AB0001F8B080000000000000BB555CF4B1B41B9 +:104AC00014FEB2BBD144A35934B6865A481A520DCB +:104AD000A4B06D37A225D2D5869283C8163C78E85B +:104AE00021879CFAE358E86D635B904A24A9422F22 +:104AF00052C8C11E0A821EFC03621B7A8E680B52CA +:104B000029C18AE7405B7A11D23793AC899BC47A7A +:104B1000E940F2F266E6FDF8BEF7E6E50D68798158 +:104B200090A2DD137D40245A2A3848065468B930D3 +:104B3000305324E9A2FDB5AA94359114C0A9095CAB +:104B40009ABA1E2F4912D9C9163BFDD4CECEEF8D8D +:104B500031BB0126252EAF1F39000FB015B3E51666 +:104B6000FDC0C20E9DABC0EF315B0E7E96DC49A549 +:104B700032CA4D01917D69BDDE4BC02CFB49F17AF3 +:104B8000C73D0309F29F3180FC30BBF3D0CD745791 +:104B9000343BE5A33C427B4548E42F5284DC078646 +:104BA000AFAC81F6E7AFDE17258AFB6109B84CFB95 +:104BB0000BF652EC11DDDB1AEF945F28CCCFB4FD7D +:104BC000299DCF5C1121325DB71F962855D860AB67 +:104BD0005C237EA25255A755A1CF0334E894F70C6D +:104BE000D347EABAFB243029535ECF0FFC1B8591D3 +:104BF000BA5D805261FBB7B51ECF71376D8410AAC4 +:104C000088751C15B6EE36CB3F866FA360673821DA +:104C100030BED43D21E7A738BD5F96BB183EB1A892 +:104C20008B25B2478C508F13CE3DDD8D73FC7D6795 +:104C3000FC7502078683CBA22173B9650C72796C6F +:104C4000F8B83C3246B83C34142E4BC61897408A0C +:104C5000D7B3D3061E2F63C47763C1F6F1645B59E3 +:104C60006775C78484F7ACCE432AB76BBA17253F64 +:104C70000D7C115DBC190A3D6F2799FDBB27028F82 +:104C8000B91ADDF4EAE166FBD56753E7E24E1B7320 +:104C9000BBAFECEDCF5D1D486CB6F0FBB2D6C740A4 +:104CA00096E711880B58A43CBC0EC529D3FDF4B679 +:104CB00093F7754871E49C0CDF9A0B3F4C1CD43F72 +:104CC000CB696A19829CD524997AEAD46F8F42F90C +:104CD00034F45560FAE320AB677A223FA8138ED5EF +:104CE0009B9FE786C92EB5232288E6BC5E6B369E65 +:104CF00097892B202982DC027F3B5C8F6BF618F2B0 +:104D0000F0B960E5DF7ADFAC3BADB4345A7BA2B4D6 +:104D1000125D898C4675D2D66D9C07A70FFC7D77F6 +:104D200040CB33BC17C80FB8433CE7238994AB9EF4 +:104D30004FBB3A997974D7FACF9B2C3B12846FF909 +:104D40001F7DD8672F3A58BD9692423CD7228FF5E7 +:104D5000DA9C5B526F39D97B44B8751EFD716B9F2D +:104D600056F35991C83F9B4F2AF96FC1F737C67761 +:104D7000B59FF745AA6B46137CAC9FFB891B8D4200 +:104D8000F547904B116FD9A8A0E4E9FC97DAA17020 +:104D9000F796F9D0145F6DE8A36BCD73675B73551D +:104DA000E74D1041366F7E0ECDBAF32DEA6B4A9374 +:104DB0004773EE34F358AEE24C567122DCFA3DD71D +:104DC000EB355F1BEA488867FBE6EB797DD38E7F86 +:104DD0006B1FAC2475779EFE1FF0691FBE1B8C8F66 +:104DE000B3EFAF1D6F569E8EFF334FD6F3A23957E8 +:104DF0002E88F3A2F74CFD2FDBA790A6F00700004A +:104E000000000000000000001F8B080000000000F0 +:104E1000000BFB51CFC0F0030977F3A0F2BFA3F161 +:104E2000D7F3A3F2CBB851F99E68FC2634FDE7D145 +:104E3000E4591820B4233BAA38B158988381410E15 +:104E400088353950C5F3A1E6D6002DE807E215AC48 +:104E500084CDFA2C05748F1C03C32920DD00C4D730 +:104E6000651918D8817C216906065F204E00E2CFC3 +:104E7000320C0CB380F43B20DE2A0DD1C707143B63 +:104E800027439EFBBB85C8D3378AA9831F28A1F27D +:104E900067683330DCD66160D0D683F0AF20C9BB01 +:104EA00003C5666A43D831AA0C0C877419184E28BA +:104EB00061373716287F18281FAB87DF7E572354AA +:104EC000FE2E6B54FE4F4354FE134F547E9F372AE1 +:104ED000BFD107420300BDE0D98DD8030000000018 +:104EE00000000000000000001F8B08000000000010 +:104EF000000BCD7D0D7C15D595F8998F376FDE674A +:104F000026C90B3C20C02404891AE8000182224EE5 +:104F100042B0C14DF181546997EA93B53622C81366 +:104F2000B1A6AE6D26DFE1AB8DE85656AD3E586DAD +:104F3000A9D51A2D6D6957DB04D0C52D8548A9B5B3 +:104F40002DFB6F50575B16D9E816755D5AFEF79C1E +:104F50003B93CC3C5E3EECC7CFC6ED0E77E67E9C25 +:104F60007BEE39E79EAF7B9F220640BF1CE01CFE14 +:104F7000B1E7452200CC197C462BA0542E07D8243B +:104F8000048D70117BFE415AD91566DFC08A2F9FB0 +:104F90003ED8EE5A10A8FEF3456DF13EF6BD63EA29 +:104FA00057E350C6EA4F14A8BE53CF79DE0812402B +:104FB000014049E76A35C1FAD934AE49C5FA1DFA4C +:104FC000F695C0C63B53A28084E315656FDFD6001B +:104FD000D03D0DE072D8AA16C758F998646C866C5B +:104FE000E314D1384ED91F17A1BB14E8EF1CFBDF27 +:104FF000A62F2621C1C66D9DFAD59508B7D27D335F +:10500000E811803BC6254167EF678248F3522A2C9E +:10501000305959D5ADB835FDFC713A102F65D86BB4 +:10502000677C7964F0FD32072F0C1F197801B804F2 +:10503000408359DD16960340ED33FB35EDF1B5F8AD +:10504000E8C63F7FFE7CFC19A0131E40ED8C272292 +:1050500083F06CF2F5774B0CDF5611188FB12A39BB +:105060006C9C4A573F99E30DCC53EEF4ACFF74842B +:10507000B380E621C8AEFE32E1996BD79BCB668E3A +:105080004F675E390BF83823F57F25A2B800EB7720 +:10509000C6AD888B1E65CB83F7A05D5F33BDF586FB +:1050A000C24F08F13307F163C5911E1D3A96C27ACB +:1050B000630D9B4F8105FD522E918D096300F2F126 +:1050C0005FAC89ACE99548AF634C56977D1F1BB325 +:1050D0001A25F67EDC82B420B367041ED2DE0801F6 +:1050E0004253728E1A599CEEBB6677F431BA3D0377 +:1050F00091CECDECD92CB37E116FC723E9C71848E8 +:105100008D97A51EE963E588254353398D4B7C783F +:10511000A77491B19991F4669BFE3B1A547AB63507 +:1051200068D0ED07686988D3F3FED097BE81FDD7BC +:105130005B7ECDCF9E72D7ED4F61B9192081E345DB +:1051400062BC7F9055ED310DCB6022DE2325FCF94A +:1051500012E285C1F9558649C4CB0F6D3CE9D04DAB +:10516000FCDA6C2CCF812CF8749EA1522F9F05F491 +:10517000206B3958F6C7F33C659F36DE531FA0906D +:10518000F04665262AEA042E8F22722F180827C3BC +:105190005756B960CB15499AD9DFCDE6179EA718A7 +:1051A000BB58D36D8297BFC6099C3ECA04959E31F9 +:1051B000E8DF7F0EF16288E9CD6CACE0CCE2AEEEC8 +:1051C000188EA91853D93A067D692D2F0B7F41B946 +:1051D0007CAACF81BBF8A3C78F24F5A41259C6FDC2 +:1051E000BDBD7E979F3DA222FFAB33C544BA0CE103 +:1051F000B5126CF2B05597459CF74707F7F0EB7581 +:10520000C2E6E73650A9BE8CEB553EB85E1D065B84 +:105210002FE49F72BE5E1DB2A58E66BD1E07F0E034 +:10522000253480972E8E97B28F182FCDFB5626B23D +:10523000CCA3CD5E4F190CA394F0A0E808E7D646A6 +:105240004EB716A3DB6CF277283C4839C7E3C9B2E6 +:10525000F3F17E8DC0C75964F38983A74D865893B7 +:105260000E239E3A6B506E6D2D1145944B1F159E6B +:105270001CB8360FC095E670957EB47049A1EE95C6 +:10528000D9F8B12D831FB720DC9CEE6A38DD891F69 +:1052900029DD397005901FF83A27F83ACB7F13EBD8 +:1052A000DC36B0CE49BECEF18F669D9DFD1C5463A9 +:1052B00025AE5B9DC6F890C1718B642937E0FE1A5C +:1052C00012E03183D101C23F8EE999E1A697751DA5 +:1052D000E03E21C0F50D69554ED2056F9DCC749608 +:1052E00059F87EEB05C961E601695F7F9F0327E3FB +:1052F000DFFAE38DED075C707E5188C408CE79300B +:105300000FE17C27BC3CA71B86EEEF6483DA28FB09 +:1053100000DE6BB0DA0FF8CEFF7E8B04A96CFAE5E5 +:1053200083B65C00B54BA1F9DFCD787026E2E1824F +:105330006A88B2F508378DC17940987D9CCFFAD93B +:105340001D68945DF81D6A3E037875DA3175C79F54 +:10535000777EFBA1DA7D20241F11187E5B63623506 +:10536000C2A596401AD7C0BF7B59F778181ADED667 +:10537000D85F06DE21D7CDAEF74EB8A90D58BB6673 +:105380009F71506774D252201A4D300887432FCE38 +:10539000BA38781CEDBAFC6680BEB65E01A467829E +:1053A0002ECDFCF3E9EA20D2D5C57F7DBA7AE36F32 +:1053B00097AE4E0A057FBB74A5D44BFAEBCCCE2832 +:1053C000924D2E27B5D516AD3F8ECDE492D439B38C +:1053D0001BE525C4997DC68701919515CDE47A2FEB +:1053E0001880FAAB5AE29593BE42AF9C8CAF34BBA7 +:1053F0009D7E37EB38AE42E3A27984E3CA61E80EC2 +:1054000044B1AC503F48CEE7A6303CC18335C5BC63 +:105410009D81ED869A8F8CEDD878A87E9C2BC276E4 +:105420007F9F93C862F70ECEDF3B4E7C452227114B +:10543000197D7D08CBFA1B2EBC0FDD4E86371CBCB8 +:1054400030FA2F453F49C120FECDDDB791FF220044 +:10545000A241765D619B855FDBF1FFCDC77D9FF348 +:10546000757BE12C0DF52D60FB0DBEB784CF039647 +:105470003F1074E25B673C299C00A21BBBDE48EB3B +:105480007F27F25316FE5E25727DE3BD2FA5FE1B1E +:10549000ED416BB3A03FC6F07AB8E17D788DF1E5C0 +:1054A000EAEE0B15F47B5C2F8EA17AAB1714298BD7 +:1054B0005CFDAC066E1702F4C9CB22EE711BB91E5F +:1054C000DA25EDC379BF5A21A571FF7BB5E27F488C +:1054D0003F7FD594D288E4573BAECE194EEE1C6E7A +:1054E000E0F6AC53EFB029D1FE7E58EE0B67D3E364 +:1054F00007C74FD3F8575548DE7D5AEE9371FDDF4D +:10550000FB22F8507F3EDCA00AAF4D65C62FCE933C +:10551000D1D1EA8A2205FD0E23CD6B89ED0773F008 +:10552000EBCCB3252CD23C5BC255E4B76AD1DE216B +:10553000FBF10C7B8FF26028781DBF558BB63C2B9E +:105540003E9408D7B7145F32BBBD69CFD72967FA3D +:10555000B31CF8DAC2DC2E6A0B73B8DA62621AF98D +:10556000BF2D9E7D5CE7D96CC3E7D46B8971BDB458 +:1055700085C993D1C02387BDF030B41D457FC94490 +:105580005BD6E4D7F6367E0EEDEC64D8940C7CD373 +:105590002B4C62E5097109366B6CDC9AAA8E6AC6DF +:1055A0000279AB122F3230602C7456A21F70F217A2 +:1055B00037F67C8DCD6BC27CBF86EDF26A523DCF53 +:1055C000B176E399989358BBB1C7D7AD4339FB4F38 +:1055D0006827A220B66E6A443F560B0E7109C0C3FD +:1055E000E2AA4AF4B3C9C0E502937ABA3C06FD3395 +:1055F00040CE99A1E403FB13CEF907DB0D85B788F4 +:105600002DAF68DE24AF960F2FAF36F2FE2DF61FBA +:10561000CA9B0983E351FB71758A078F6333BE1FF1 +:10562000B0E9D20FCBFEAAE38C87E501D44F222B41 +:10563000442D8DF5A12B17FD5063D6CAD08DDFCB3D +:105640003B1B99F81811EF4CEED570BF715258E61C +:1056500082F79722F7334DBAEB9820A0DFD7602A64 +:10566000FD4C2CD7CFCC46A7DB6DFA1C28D7AC1647 +:1056700092345E62C954946BB522D9BDFFB46256B0 +:10568000AEBBFDFBF63883EB0FBA3C17CB7CFDE5D8 +:1056900015A21998F1A7AFBFFC21D73F7FA3E2D98C +:1056A0004F3FECBAC8687B148CBCFE7FEE38CEBA94 +:1056B0009DCF1F5C3E4EBAAB3A80F2EFBEC4F07293 +:1056C000E5FC755B4EEB36660598E92C72252009E2 +:1056D0009E7DD579AA900283ADB3744C22F9268DB4 +:1056E0009DBB72270C3DAE145332EC37BB3FCBDC75 +:1056F0005FC2D6FF13E0FCF5CA28876A510EA15C91 +:105700002AF7BDEEF68F308C0F9619EEDFFAC2FE47 +:1057100003288F2C268FD07F9AF9BD16CB2E7AB80E +:1057200042E2FBEFBEEFFEE202818D73C4F0EB7E3E +:10573000F6EA90D0FB06F97D2B25DA8F113E752E07 +:10574000B607524E8E989259CDEAF7960BB48FFA5F +:10575000E1A5EBFE91DA8728DED1BBE0B52F5FCA69 +:10576000DA7FE2321F720EC704B68FB37FA25E7378 +:10577000B6EFCB97B2FA872ECB1F56DFAAC5F9BA80 +:10578000E8E4AA67BDE555486F08FF7FBC59FB20D8 +:105790001BEF08E424FCF8ACE0F01D41F890EEFBB0 +:1057A0007EF506EA85874D81FC51472A7E16437BAC +:1057B000BCD214485F5CBA4048FBB3CC73E982DBCF +:1057C000264F62FD258C901660DF0F55BEBDF55249 +:1057D00006EF553F90B6E1F3F45EA920593634BC8C +:1057E000CEFBAB4CEFFB01BD189216E21D341E97A9 +:1057F000F0C58CB89B5E07F418396166F3B7AD95B8 +:10580000B8FF51D00CD2EFE4B002388FA1EADF34F8 +:1058100004FDE6407FB7847038FAF7D9AB75B73C22 +:1058200074E050E44412C791340576A19E917B8DBB +:10583000EE9E7F83C4E34242DC2478148DC3A3C868 +:105840008699CDDF546FC3E3F403D069B7EF87BE09 +:10585000F0207CAD81C44AF45B58B9DC7FD812F1EA +:10586000FA03F7D8FD3CE6F4E783AC71158026EA2D +:10587000BF6A4C858AFD3757703D490783FCE32D8D +:10588000CC6E8461F4BAADB6BCD88CF10D3FC6398C +:10589000343BCE11E7FA53F819F2939D2913C9AEA0 +:1058A00019AA9F88E1D54742A55E3BC6D15F027A1F +:1058B0005E861FC8EBF7F18D914547EF437A1D09CE +:1058C000FE013DCFAED72EA7542D2B9ED2C3EA7337 +:1058D0007F3DFCF1F6215F97960DAEBF14DE1CBA3A +:1058E000CAEC5FC95752698ADB25E21E7DC09693D8 +:1058F0004ABE9AC27D01D4A1BE0779FB30FB8EF16E +:105900008C7042477F8A043C2EA4221FB8F0F3B665 +:10591000DDEED3B268EBF3298A830A7A8AFC766AD1 +:1059200021E31FE1FC76CEB3CF6EDFFE87DB5F2184 +:10593000FE2850893F049DF14F96719A24F394C438 +:105940009EB74AE65BF8F4FD514A66E393FFB2E581 +:105950008A5A9BD0D5628A2B923D92094740E6FD38 +:10596000DEE4C06FA5284E395AF8DF1F25FCCE387B +:105970000C7E592E20F87DF81C0A7EC986270FF46C +:105980004619E59ACEE52BC032DDAD97DC28737958 +:105990009167CB2780DBE26E7BEB7ABB9FD1CE2772 +:1059A0004F1EDD7C9C71D97C26C97C3D26CBC3ACC7 +:1059B000C7441B8E1B65BEDFA9D5093DCED6257712 +:1059C00008BA5A60C39192455BAFB8ED43D1D5C5D3 +:1059D000A39CC782C1759967AF4BC570F3986BCF15 +:1059E000A35382F9AFA35E3CC5F1F72CF7ACCB1DF6 +:1059F000367E3AFDCEBA6CF0ACCB2DF6BC463B9F62 +:105A0000C5767F23CDE78EC1755966CF67F970F3F0 +:105A100071D5BFD6AEBFD2AE4F76C71D726913DA4D +:105A2000194D5262955C30381EABF71977BDB79BA4 +:105A3000CF34DAF56EC0F7420DDFFF58BDD5EE7AF0 +:105A400060459BD03FD08AB602B3634A5A2EA9B2B2 +:105A5000DBD551BBDA81FE6FB6F983DA055A8426AD +:105A60002B4CF5D661BDC6457F74EADDEA85F76249 +:105A700007DE0D046FF5001CB7BBEB2D9027507FA0 +:105A8000E7C51D46E90FF2C5921D18E7CF834827E9 +:105A9000E679B4C9A947300FC0B264780CF309FCA9 +:105AA00086803EB66845EA1B582FD762F635AE5B56 +:105AB00055EA292C5B22249ACB299F80F205EA65BE +:105AC00055F31B987F61C00E56D662721AEDF356DD +:105AD0002169E1BEF85329F96599E4ABB6AA11FB37 +:105AE000CFD7B99E0E7DB46F3970DD13BA8EF21F19 +:105AF00072195CE88F6ACD80EBFED0A41EDC6FEFDC +:105B00002D50484F66065629CA973BA5A081FDF542 +:105B1000147C9EE0DDDEC8F31BB67FE2F304EF7D6C +:105B20000250DCF63E1FCF6FB8C7A76A4D1AF617B2 +:105B30001DF759CA87C8D1FCE5361C08DFDF1513ED +:105B40007CF9A055DE2890F8EA41FBB6B542217DEC +:105B5000797B6C5625F557A1929E7A5F625623E9B0 +:105B60001D1541F2D1E7870DB25BA3F314B0B01C51 +:105B7000331A51CF8CCC0D620E0CE417022617405D +:105B8000641AA4B1EC83CECE12F68C7630BB249F7F +:105B9000EC26B811EDDE0A8677B4232CF328DA253B +:105BA00061B0FFA44326CEDB374102F47B38EB1B08 +:105BB000ED1C683FACDD154D8FB25EF7E8EA453A63 +:105BC00098DD3F7B14F53A47592F3DCA7ADDBCDE9C +:105BD00088FE0E83DB7B2AFB0FEDB640A6DD1CF6AC +:105BE000DAC3BE8CEF99F1B8CC67663CE4A4EC8DC7 +:105BF000878CD4DE89838C345F744A0CC0298D5C19 +:105C0000DFD13787FAAE8CBF266EB2F6ADE33E1D0C +:105C100027B9366E157F4EB4DF4F5C69973F6D979D +:105C200057AD34B3C8F7B13E2E874BD11F329CDF3E +:105C300001B8FEF80683FD9C80C94BC3FB4F32F5CB +:105C4000DE4C79A7CA5615F2EBF604F76BFA9119F8 +:105C5000910F0B81FCB03E487596A09C0033BA783A +:105C6000CC20FFF8CC174CE4E7C3E324102A687D6E +:105C70000CF2A767D049265DF833FC397F2E9D7C56 +:105C8000CCE78DC7FEA5E844E99046C53F4AE72822 +:105C9000EBA54759AF7B74F5FC1DC2E8EA758EB2DF +:105CA0005E7A94F5BA79BDB6F90ADFCFE17B4D662D +:105CB0000983FB12D5536EBB24E8FD7E69D8536E71 +:105CC0009FA3D0FEEF94FD73554FB99DC979CFF7CF +:105CD00079612A6F6AEDAE625BD9A8F9E43FFF44AF +:105CE0003E295547F04B578819765B065FA97A0025 +:105CF000DBE7CB3A60FE547E8CEF53EC69A6B3E051 +:105D0000F7119BFF77C93C7F73BBAC07D07EFC5B70 +:105D10009F67A38FC3EBCC7724781DF9FBA664EBB8 +:105D20005B43E57D54F3BC4C1982949759526D56F0 +:105D3000994C2EC92FF2385866BFD729C9A77D2E96 +:105D40007B58D6923CBE67F7B7A44026BD44667226 +:105D50000DF51E05123545144714C9DF278747D8AE +:105D6000370A5D72AB7818B8ED3C56FAA40354FEBE +:105D7000968F1B3480E46B04FAC898CE41AD670A55 +:105D8000EA69BA00D4DE10B8FF7C8186FB5E2CF095 +:105D900097EE7715F52B98F7C0B9D087E857EE2323 +:105DA0007FE75FBCDF11E00D607EEFC5144288B96C +:105DB000F37B7DF114BD84B3E7CE49738137A1BF76 +:105DC00024C5D765D1207F288C8F925DD61ADBA0A1 +:105DD000BAD7F5FF7CC51EBF89A2B5DD2644D9B36D +:105DE00070ADD9370C9D9FC3600CFA470A6F34FB26 +:105DF00086D94F07E29918AFCFC2076D4A328DFAA4 +:105E0000BB3529CCED7939457EC676216FD6E67251 +:105E100017FD162ADD0857A4DCB4D0DE6BCF170DB2 +:105E2000D45365D8DA2BCC60EDA45A2399458F184A +:105E30006C2F9F74CF27A678F5A9E611E8BD7504ED +:105E4000BDC7A718C96CFED0690AB76B7DC1ECDF6E +:105E5000EF12AB4A9439E7E38DA9F9DCBECD850E8C +:105E6000E1639C7C28DFA1F08557100FAD0557C476 +:105E7000879B2F68DEBCCB9B4473A6323C1C73B25D +:105E8000C131DA7C10ADDA203A1CD097629CAE5159 +:105E90004F12C660BE07FFDB56BEAB1BF3407C371C +:105EA000F0B8AC64EE06F4533B7A9364064F88B4C2 +:105EB0009E0BB8FE54CAF52193FD87F3882E185E19 +:105EC000AF9632CACB14AF3ED4DCB017303EEFC031 +:105ED000EFF8F132E7758958756D767C8CCE1EBE71 +:105EE0008FD10B4CC378948A4881CE068DCA5F6EE1 +:105EF0008853796B834ECF9686527A6EC1A6F39102 +:105F0000CF531D450C6F1DF147E39F6555EE43D9F7 +:105F100041FBFE758B504FDE3C50666620837B3321 +:105F200006BC991E71BB72D522B4DF3707C0F62BB1 +:105F30002C5A647ACAD7345762D9F6336C6EBB9E3A +:105F4000EADF3711EC7310A6FA49D7BEF788E223CF +:105F5000FEC6BD85B7379BB1BF806C97E1B645DE05 +:105F60003298084F40E5E5FDCA06EA9F44001BEF62 +:105F700027CAED7CBCA9DC8F0F65CB47C023F7EBAC +:105F800083A273F9599647F92C8A61A0FB15EECBD1 +:105F9000B5E11E6D3F7292EF77C7B2EF97837C3306 +:105FA000C2BE66C331D2FA3374D87E88245838EE24 +:105FB000CF791CF1AF3DEE7DBE0F8717A5A2DFC2E2 +:105FC000F3230B94E4F791DE23665777112B476B8D +:105FD000BB2D62DF518E7BAFA2D9F34E12FF3B780F +:105FE00076F48EFFF279D7D11733290F2910E6FC0A +:105FF000375A78FB50BF9A33D80F3C51356E387DF5 +:10600000AD2021A21236202FF26B82688C0D947382 +:10601000CD3C4F39A762BCA77EC428F67CF7691730 +:1060200079BEFFA9EBF4F38C79FCBBAD373AE51FE1 +:1060300067CE7394FD3AE59EBE4562295B87976BF8 +:1060400025D2EF5EAE7DEDBED9584E4814BF3DB3AC +:10605000B2D9878C740CCCC81CF4872525DB9F6EC5 +:106060004E447CFE1CFFC9C67B09F73D269F8ED897 +:10607000E77F989C9888E79F8E5C366F22AEEB1185 +:106080001FE76FB03A493EFDCC071E79F0335BFE47 +:1060900018ED3B9AD10F794CE065A97DC7228BE2C0 +:1060A000835BDB3ECEF496AB390A6179AD90D51EA9 +:1060B00088F815C2C7074232E267F334ABF5D61849 +:1060C000E6BFE940FAAA1F12A497D5835529A2BEBC +:1060D000C3E88FE2DC727F6136BDE367F67EEE8750 +:1060E000AB49DF5F5E9BEB4363DE5F33D3877ED4D8 +:1060F000AB6B2A7D60EBCB9A0B3E3121D0F9A91511 +:10610000B5FE5D88D715B2E9CB16D7BA3AE1F7EC00 +:106110005333190E11FE63F6B90780FE4277BC694E +:10612000A69FDB3BF192E1ED05076EA7BCAC76E6DE +:10613000F38807866D3A8F026A7FE1751177BF2178 +:10614000272E1CC17E5F5EF90F7C7F6674817EC541 +:10615000174F7CCE4771D915F91EFE5B5E2D79E095 +:106160004F2C0879CAD7D45E9D33ACFE91F467C832 +:1061700033CB3E8729921CDE7C5C20F99033A93F0B +:106180008D799AF0B2045CFF73FCAF9790FF353ABB +:10619000A15F477D017E13D21E73C9CF169B2E8748 +:1061A0001AFF393FD76BE5BC1A8A6FBF7742D071AF +:1061B000BE425EFD349CAFAC984D386E4B9198C694 +:1061C000B8F79DC5DB555CEF4D251F4E0FF4C57824 +:1061D000BC5FB7B459C8FE43B54B9BFC1C41E6FB02 +:1061E000B57E1E6F69B5966B25B88C07B44A9C7F47 +:1061F000A010B29E3365F4BFD68F7EFB98053CBEDF +:106200009E20BDBA445D4D79B8F2F8E1E3B59978C6 +:1062100093ED386066BD276D7A2CA9D845FDBE7711 +:10622000E1F0FD3A7879DF10A1D7D627B0BE0A6C2D +:106230003E0CFF5B4A791E6E4BD9338467C9AC2490 +:106240007DD6A7A54CACB7A56C35D1652BAB93CF4C +:1062500086CEADEEA2739A5BFEC0E3134FB61F6805 +:1062600046FD614BCFCD807995C1781A507E6C99EF +:106270007E938A78D8B213A017E958EE22A75CC89B +:10628000F687873448334B0A426526A05CC8D3F8AA +:1062900099CA7DF12AC075DB520E06B2667E3AD5E8 +:1062A00088A19F2D711EFF0E969A354508F73891EB +:1062B000C4800EC90E2CB7D4CA348F368DE303EDDB +:1062C000AE734E7E17E6C19470BBAB04FDFBAC7F92 +:1062D000E58B7CDEFA8E12F2136DC97DD9447DD731 +:1062E000FA04185381EBB5A427C88C8EB0FF7A2D21 +:1062F000EBBA6F1593DFF2BBE2F7B2A60B48A79992 +:10630000F879CF0757E2BC5B668AB02B8BBEB1D75A +:10631000CFE3756963F955C559C679CEAF7BF204F1 +:10632000F4F715827BA8FA83F564F2EBA3E1B1845C +:10633000CDA3A086FB4B21E31C6B0C9264DF8E0582 +:10634000AB11F9D139BF3AA13AF1CB247B4A91156F +:10635000944F37D4795627CF7375852D9041BFF66A +:10636000D76CBE371FF401E2EDF2B38FBC80F95257 +:10637000BE0ABF46F955D0F902E66FDEC8D4312C0B +:10638000DF7C7CBA82F93F2F8F97303706F9278A56 +:1063900074F81688947FF6161C8DCE76D1F9297B79 +:1063A000DF41C98A72A43997CF4B0EB7F54A515CC9 +:1063B00077D9EA73F2F74861E279ED1066EF55CAD2 +:1063C0003E6A24F9D7C1F3859CFCC8CF767AF3875F +:1063D0003EB7C35BBE09968F41BEB989297469D6A1 +:1063E000EFCDEEBC2F36FE313FD70F3E07A936DC8E +:1063F0007FDAEDFC9875DF9FAE205DDF3C5B2BC242 +:106400007318CE3C7EEFE776E849C6A7BA8BFFD774 +:10641000C4D2949F9C39BFB7F62CEA4EB2F26BBA45 +:106420009CE276B6779EEDBEDEA598EF656DF3D95A +:106430007A8337CF71CDEE4A13F3C518F6F47C6F2B +:106440007B82FF1F3ABCF31D091F99F377F4C1A1AA +:10645000E6A3EC16B2E6FB85546FBE54B3CAE38DD7 +:1064600066B30C8185E79F8FB6AA5274BED96AF2D3 +:106470006BCD318A4F52FCAF9E110EC6F7CA559DA7 +:10648000FA792F30290D740E21350FF5A33FB7DFB0 +:10649000F92AE7C3BF74BF0B8780779DDAA7207FF7 +:1064A000AE973B6B84E2C1F301019F654E60F8F645 +:1064B000EF5DD63D013CF53A4659EF201E811E4561 +:1064C000BD1A7198FE4EDBFBD6BF3DF12F0AEEDF01 +:1064D0006F3D7E6229CAB95BFE550295D53BFD44EE +:1064E00004BA69DF492B2897D7EC9168FD41EE9EED +:1064F0007BB527DFBE99E67FCB5311DA1FD63CE38D +:106500004FD7B2F66BBEF7DA0C607C7BBAA9FF8579 +:106510000988BFC7059EC760F5CDB89ABD5F23C384 +:10652000F5D9F2106E50395F9DFA416825EEEFC241 +:10653000EE9EEBA8DFAE6B7D7E97FC5DA9727B9A29 +:10654000D533F1BBF54D213D55E0F065CBCB3BF5A7 +:106550004DEE4759B3D797C63CC535BB772A495648 +:106560006FFDEEB789BE173DF56414F1B07EAFF74D +:106570003CC22D4FFDA1ED92723AEFD45F8BF24FEA +:106580003A4BE533A6DACFF3E0B93FE656E2585688 +:10659000EF3B6F5EF16BF6FD645C82001329277B95 +:1065A000FF53F9572C27C32926CA58FFBE57DD7C55 +:1065B000B87EF76B74EE481399027B299E87C8F862 +:1065C0009E519FE9B90ACAC3F55D9BDE4679B97E43 +:1065D000CF5BBF42BA5B0FF2AB6E7E3E89FF18778E +:1065E0007E3C6B93EAF5D39D814373C901B03B3F79 +:1065F000ABBDE8C4B31CFEBEE5C9330FA31E71EAF0 +:1066000099FF7A18EF6758FBC7FF7918F35AE147EB +:10661000010DE5D6FAC77F1E0517FE1FB5E5C3E9D4 +:106620006F7EE3EB0F303C9CFEA59FB076FAB93746 +:1066300027E13D1DA79FFEDF31A87F6C7C6EF158DE +:10664000A4B38DDF5D3476B873A048B769BF7B7D96 +:10665000D3FC7E83BD026E8200CFDACF8C7581437E +:10666000FD0AEABDEF0AD0BF3997BDEFFA8382FA7F +:10667000CB0B26F4239EF6EF79ED85BB58F92DB6AA +:106680004EFE2CEBC4E63F41A4FD8DB10F7BDEBA7C +:10669000E7EAAB2E2BC7A7CFC0EED7433FED1BE7F2 +:1066A000ADEF31B6BEE583EB9BF9FD0C9C5510FFB9 +:1066B000EB9F60EB3903D795ADE78CF3D7F32DFC57 +:1066C000C7FCF3D773BFEAF5C79D81B58F3C801F28 +:1066D000F7E467B56F9DF55CF7DD4F0EAB973BF2C6 +:1066E00061243CD3F95E06D75754F3672AF2ED33A1 +:1066F000DFFAFA0331BECEB50C31A79F3C33090F48 +:106700006BFCD6D77F1DE2A1FF39BF867AD49AE70A +:106710007E417C77FABB2FD1B91EF61715D87E774C +:106720001A06FE8E022BDF2AF0C23ABDFF8A5FB145 +:106730007ED7B12E2C83D6EF8A5F95E3FAA9FDB4FC +:106740001EE965353ACADF7401CDFBD634E78F5BAD +:10675000D33D2BD09F9D89F748C0C9271C5C57F4B7 +:1067600097DEBAE7C415487F43ADA7337F0DE73FF7 +:106770008F7D7FD4CBBF43F2ABBDBEA777BEA7A0B2 +:106780007ED5FDAF8A26323BFFB4AF5F198FFBCDBC +:10679000D39286E78D33D77D10FF4D59CF1D673ECD +:1067A00033E9C31FC81EBF76F03412BF8F3CBF0F42 +:1067B00087BF33F63E9C89C75367B3EF075302DCAC +:1067C0009EBB153A6B50C5CCDCCF7C90B226140D25 +:1067D000C2DBD625919C3FB59BFB6932E5C5AD4335 +:1067E000D867339D71F6F6CC40B9766ADF0F6CBA84 +:1067F000E4747FEB132714CBDE1FD22EFCAE1FC236 +:10680000DF7DA9DDDFFA67B3F7B7FE89B7B3F677A7 +:106810005236AF45F84FF6FA282FE9649794D5CE53 +:106820009D1AF079F4AEB6C8DC5772583B291AA409 +:10683000BCABE626F317E827B58EFA6C3F80F15B18 +:10684000CCB76A8E04E99C7B73F426BA2FC9E9AFF2 +:1068500025034F723C41F6931C4B94F31858DA63AE +:10686000C7F81841B8E106D92A44BDFF70D19B3260 +:10687000F67B04F548975D7F4486D6FC723C172171 +:10688000188D90C5BF91D17F628104BADB4FD83D8E +:106890004EFC3D6BEF3F26A511B5F590EAA67301BE +:1068A00085D0F55896FE1E6AD0C97E2E4A5C4FFEF2 +:1068B0001F7F2A65A2BE56B8512B16F5A1C79D9819 +:1068C000F2C6AFC733CAFF3D8E73D047FA20EC7EC5 +:1068D000FCF1C7C7F02D05F5F217F0C9E4DFE57547 +:1068E0007A21961FB2E7CD7880CE314EB41232CAEB +:1068F0003921B64C46FD62712A21AF76ADE7E298A8 +:10690000301EF7D3F410F7407D3FC0F7CFC6C66BFB +:10691000288FFDC12F8A44D70F063E5E887C7620E3 +:10692000775E18FD6B3DEBE61E9AC6E09C10960064 +:106930004DCEFDE1E1CF6D3E6CFB1776D9F70F3DF3 +:106940006AE7977FDDC6DBEE86527A3EDE60D0F7DF +:10695000271A2AA8DCD55043CF671A12F43E7A577B +:106960003089F4B9A76125BD9F006F0BB8FEDF6BBE +:106970004852F9D1402EC13FF96E1093ECFD62C42C +:10698000477870DE0E3C69DBEEFE7EE0C72DC8174F +:106990000378CCC0F7E5D02BA8E8BF8A093AAE7BD4 +:1069A0007D40E779AE19F89DE4EF17302E577F3719 +:1069B000CF877858F09E77B8DF96FFDFB1F9F4DD26 +:1069C00068F2C9007BBE53B3A294F421D0CA906E82 +:1069D0001E1612478C22C2B3E7DCC9FABCE4770268 +:1069E0002EFFF0A40E6ED7EF08D8F26D2388486F03 +:1069F0001353A023BD39F3DE57A917A25CDC270887 +:106A0000B4DE486FA52E7A1BA0DF809D971CCFBEF9 +:106A10008F0FD22FE7FFF825A5F754235E3688E4C1 +:106A20000769C64FAE761FD874C4EC16D1427AAE51 +:106A300013C99F3BF9F8096112834FD7BE15C07B7C +:106A4000BBE293C0F637750590BE1EACE3FEC5AF42 +:106A50001DE7E798CE6C2C5E368DD55FCAF083C1FA +:106A6000A8BC25251EBFA5737EE16B6A22471BC605 +:106A7000BF9599F776FFE42FBD9FC3C699703CA4DC +:106A8000E379987B26FFA84761E5F17D02F993C67B +:106A90008753D3703D2BFFDF37C7F5B9D6E181753A +:106AA000A9C9A837B64DFEB6807C30FEEC8F05DC58 +:106AB000474AB4E49BB83E1364FB9CB09C9A87762B +:106AC000C1F57989DFE1FB4461FA53484F676A36C3 +:106AD000FE1BF6EFC421EBEBF5DC692EF990799EF5 +:106AE000E2A1D4F0FE4C67FE0FE1FC87A9E7CCDF02 +:106AF00059BF3335B1B5281733F199D96FDE9215E7 +:106B0000C38EFF907D8F189BBF3FE8926B85A93E97 +:106B100019DB39ED878ABB66CE77C04F34CA386D32 +:106B2000970FF2912E9EFEBF49DF3902483A0909BC +:106B3000FD53FB02C97108CF5C4851994947CA67A8 +:106B4000377239FF3E30E6EBE388EFE47411E57D00 +:106B50008C72BC5648242A719F334423DB3E303D5F +:106B6000C8E97E01A4C83F2A86EE1E3ECE5FE88DAE +:106B7000F36F059A0458DDAA1DFF0059437FD841E1 +:106B800098857EC8FC20E7F74A99DB97B30FEA3B6C +:106B900025EEB79296455CF8B3FD763EDE3583FB75 +:106BA0006ED0743CF735B34770F1EB7BA1E4C220A3 +:106BB000ABAFC4B93FD2174BD279CBC55258247F63 +:106BC0006E2797FFF590502FE47119C079EB1017DD +:106BD00071BF7F68233FDFAE6B2182FBA1984EE53A +:106BE0007A5B4FF9B14D473FB0E5FEF76D7AF92E6C +:106BF000CA7DA49B3EF3400E83EB3BB6FC7FDA9646 +:106C0000FF4FD9F27FCEB13EF86639C96303F39ED8 +:106C1000BFBC3DDE84D37CB2C1A47ABB1AEAE8B91A +:106C20003F77ACB897D57B74A3B80BF9F9516DECED +:106C30009578DF55DA140D81357EC8DABE28CAE0B2 +:106C4000DFA90A143F7BB82145ED76AA7A938AF131 +:106C500014662D5B4806F5BD14F6A8FC6DBF56C33F +:106C6000EA7DAD33EF4A8CC3DD5B23533B878FF462 +:106C7000391BB03944F3FC4164ABBC826E750ADA4F +:106C8000E91B45EAE72B81CFA88BD873E2C4A3EABE +:106C9000C7755C8C13668A7D5FC4908CF3A8E8EBA3 +:106CA000B3B05CF27A98F2B5E7BED2074FB3725137 +:106CB0005D84CA132D2F5F4CDFD367753238269E53 +:106CC000E2DFABF37E6775B1FA391BA2D45FD5EB77 +:106CD0007D02D2B3AFDC7BFE6A87EF97FB236CFCAF +:106CE000D8A1848078DB27688B3025C4FA143F7FD5 +:106CF00033F62054E1FB787409ADC3F66011D1CFAF +:106D0000D75A8EC66F463C6D8CB5A099B37FE3060B +:106D10003A9FE0DFB891EB4129EEFF9E78C701E191 +:106D2000732EF950D82267F5DB6D0FFA799C64E376 +:106D30008AC4340EDE8130EA7B25DC5F59D45AEDFB +:106D4000C96B72E2231F08C9ED41B29B789C44D6FF +:106D500052F4FE32097545F6FA4E91EB4989DE8010 +:106D6000DB0FA3DFC1EF67CB8463575026385AACE3 +:106D7000EA3A9417DBE6287200E19866DFCF62C733 +:106D80002107F63121B9CB2DD7648DC33591A132BE +:106D9000847077F77EAA8BF5F37ECAD9C7CC20E939 +:106DA00049F788C41F5BCBF939C0FDC63BDD78CFFE +:106DB00085C34FAD8648FCBB5D16D202EB677B797D +:106DC00071EE85483F31DCBD69BE2AE2B944F6F177 +:106DD0001C0E30F7A15FDC8F7E71B6DE25C743271E +:106DE00044F2FF79F3BF8B2CEFFA8BF5DE73771348 +:106DF00099D2E3CE57064634037446FB6BF5BEFFCB +:106E0000407E5819223A03CB8C568EC1F445FB4F75 +:106E1000AAA5F3CF2519E70C1EB0EDF787ED738413 +:106E200070F63640B9F5807DFEFA81B5625067781C +:106E300079DE3A4AFBE6C4FAEE4A0ACC687E4F7E17 +:106E4000B5FF6EAD09F7D7A294374FA832232FA80C +:106E5000E4CFCCB33E1EF4DAA9FB4E060DBC0F2FD7 +:106E60007D4C32509FFDF25DB349FE596BB8DE9206 +:106E7000AECB7B00CFBBE40B60E07BA75FC77E7D22 +:106E80002798477C939ECFBEE730B912E95A5287C4 +:106E9000EB05395A530CCF43DF09DFC6FEEBF8FA96 +:106EA000571602DDAF5318033AE7CC9E9B2F40FEE6 +:106EB000DF28624C1CCEA19C4739AEF6BE88EF732A +:106EC000AF14E9FE9CA216EB429CE7BE4BC68F476F +:106ED000FAD81AE6E75E9A851468086F01E7879D7D +:106EE000916ECA07DD562342135214C3A581FDAC2F +:106EF0000EEEA23C1684770ED11DE95D18A3407EEC +:106F0000B46E08F27DE7AC7521FA95A3A1BEAEFD83 +:106F1000AC9F70BB62EC62FDECACF4DE533735C461 +:106F2000F7BB404870E2FB81107B9A5B81F216D977 +:106F30005C88BF195F5940FB8246769513DF8FEE60 +:106F40005B22164DE7CF6217FFEEB2E56CDACE5B3F +:106F500078D8DE3F1C7DE301DB6ED86AEF1B45E687 +:106F6000554D0AD26D1DCC443C95ACED125667B31D +:106F7000EF3BBC7235935F2667F24BCA7B4E75427E +:106F80005DB1E77BC4B8C8F39D4231B8EE6CFF46F3 +:106F90003CB707CA24D4FB6643C274CB95A1F6FF65 +:106FA000FCA03923F421F49F68289142FD3353FF5C +:106FB000BED45E97EB0289F9B81ED14B56521ECF54 +:106FC000BA40E252EA5F4E0B284F1760BB58567822 +:106FD00029F96B14F0567F18784136E83CD79D921A +:106FE000739FADF73C1764DC5F9B793FEDC2FFBB3D +:106FF0009BEEA76D1598A287E51CFB7E5A3FBF9FAD +:10700000B635C2EDAE563B8FEA561B0FD787F87DDB +:10701000AF6B6D3A5D18CA7EFF91E3F74AA16CC071 +:107020007A63B3DF3B861A15F6B77042F6EFA91004 +:107030008F3B2E9C3CFC381B701CD6CFDCA0B92E9D +:10704000E4F2AFCC0E99EBDDE5DB43767E919C203C +:10705000BDD294F97E5814343786E6B8F06B3FF30E +:107060009694D379BE33F6793ED66E87407895B440 +:10707000D1E0DDD1FF5B05FD1E92833F677A5F960D +:10708000F5782F18B5C49CC17894A31FED0E717BC1 +:1070900092D1DB263E8F34E5418741BF07EF8198CF +:1070A00080F770EBE85738FEF0BFA0BCBDACB70668 +:1070B000F5A7753F94E87EBBF3F0B596D19D2B1FE5 +:1070C000C5793FFEFD0964074F9692F7875CF6F19C +:1070D000F8BA7E05E91DE1AFE6F0F3FC69217D21F8 +:1070E000B70780E238AD37C73DF98499F6481EDE10 +:1070F0007340724521BD2E132EC79E70CA99E711A9 +:107100000EDB74847FFA18BC271CB8322B9B12F25A +:10711000D71C48D2731EE8F464764B17CE83F19FD8 +:107120008E703685265D8AF3F82BE2ED47A1397F14 +:107130007B7873E8B82879F9001D67BBFFFAFE5029 +:1071400094E46DFDF108E9FDD17D5F20BA96185DEC +:10715000076283F932F560E7D187A10BF5DEA264FF +:10716000039D0B3DC3E818FB95347E8E55062D819B +:10717000711B29C6F9C327976AA2867159CB8F79EB +:1071800007563118286BD11FE986B73C9C7CD38DFC +:10719000C73B8FDF43F2F6BA40F224AEE79D259657 +:1071A0001F353B971C3EE596C3028475E4BF856797 +:1071B000F97E5999D465A487458CD311EF8B214969 +:1071C000E58F8345CF2590A6E7DFE19546A4C7D993 +:1071D000E716BAAF15DDE71606F2B9CB9D7C0E1E99 +:1071E000A72AB0E9106C3BF5F995CB1B17B3F1D981 +:1071F000E29B188FFAEA4A9ECFE39F27D3F9D58204 +:10720000BE1B6A314E042BB85EE6E441E4D57AF544 +:10721000B4F3EEB73AFEBBE3D82EF39C9CA3AF6564 +:10722000EE5BCE33535FCB0B673F3F39D4BE931930 +:1072300057A8C77F72FBD5B6AB1339EE7BE3339FFC +:10724000871BFA5B0EB8F2CC8FE0FD4659F7011EA2 +:10725000EF8DEEFB5DED8A72BA5FCEC094C9DE861B +:10726000EE85AF4F1DB483130B729F477F74A23A14 +:107270007796C4F0BE34FE6ECB817C806566CFC24B +:10728000D75DF3ECD518B459F48481F14CDF07EEE7 +:10729000FDF72D85CB97567BBC881D1F6B172D3FA7 +:1072A000F1ABED7FFB7D21B7D31DFB3EDB7C5B08A3 +:1072B0005F7D61A487A1E6FB0F61BE9F8E5969D0F7 +:1072C0007DF9CDF67DF9CD139DFC2D43437DF2A6CE +:1072D000702EBFAF205C42F1D5E69EF9E44F2E3808 +:1072E000E4237FFA981549C172ED8BF73670FFEBF6 +:1072F00057987E87F9205B985E87E57D957355B436 +:10730000176E8FCCA278EDE606C3932FE23CF13ED8 +:10731000BAA4CBBFD79CA8D230DEDB523B4B45BBD7 +:1073200043FA443995E50B677556317EFECCD61984 +:107330005714605CA28CDF47763D2B3796303B3A82 +:10734000CCF7D9C3C6EB61C453555877E887D6D17B +:10735000B72269FA502EC4B52ACC9571DE834D5FF1 +:10736000EC3DE9D76F29C99BC36CFE87ED7BB1DA91 +:107370009554E986323C17CF040EFA8955EE27441E +:107380003A68993D08F7061BBF97D8E33281243E3F +:10739000ED5A3F25CED7AF5D84BA6CEB737798EB8F +:1073A000372D9AA90D4B479AFC81E7FED0F218CFF2 +:1073B000CF8F313A72F1F3F9F4CEF9A93C9C680908 +:1073C00017A05C84D214CD3F4CF287DA4983F7587A +:1073D000C6C36607D63B9A6BEB2F853C0F9ABDDF81 +:1073E0009243F34B917C77F4C17699EB73A3D50765 +:1073F000F3966C247DF01DC65A649F7D6223C9ED0F +:107400008D3E95EEFFDBB740A67856740A5CEFB66A +:107410005BA4887DFF7F84FBE5F17712D2D3B8DED1 +:1074200083E73CA221A0732EFD13797E693BECAC6F +:107430009942F04DD5DCFB59E544EE67D85615ACC2 +:1074400073FB1B16E6F278D98BB995BFC3F9978504 +:10745000D355C89A176BD087F93450C5CF8F09859B +:10746000FC9C8D0F0C95F36BB586F7860A90A4F300 +:107470006743AE1F78EF177D5C4E3705116F31EE15 +:10748000D789EC1028694FEA32BBF1EC4E7BEEF263 +:107490001F223D32B967207FF7CC0D92BDF76E8F6A +:1074A00042F6E7BB37C3AFD19FF4AE2F072CB654DB +:1074B0003F12C55F3FC5E6DBCF987517E67F69FCD5 +:1074C000FBCCAD02F99B7EF4417002D2BB110511D9 +:1074D0007FCF6229D32778922084303E1B5D04DD64 +:1074E0009763FB9E30E1CF17FFC9C2D767D3FE1366 +:1074F000122BF0BC96F820CEFF9938E461FBD9FF3F +:107500005B25A1FFCAD187BEAA258F22DEE6815561 +:10751000D7C3DA6F53387F6DCB53D218A79C552051 +:10752000921E02BE507A2AFBBEF4E0EBD598DFB97A +:10753000B46226D6C4F169BD4BB4E4719C77B5B68C +:10754000AC3A97D52F3FA693FCBD227EDB012CCF12 +:107550003DCECB3E3FD7E3518F719F0F58FAFE24AB +:107560009AD79B61AECFB6C4CD5E531896AF32EEBC +:10757000E5F59E2F70E8806DEB3AE6A5D3BF75A2C6 +:107580008BA44F1CF43F4185619F3F71E8C1143EBD +:107590000C3DEC09F37DA11DF3CD6283F966EDB6D8 +:1075A000FE36DA7CB34C7ECA5B22D33ABCC3F42DE0 +:1075B000BCCFE37C3EB98DEEFFCCE42707CECDE512 +:1075C000793194C30EDF68F3EE26B9ECBF41A1FB1D +:1075D0004C1D3E72F8E7D29C013EBA0FE5C58AB059 +:1075E000BE98A76898E0E693AB47E0ABA5D07F20B4 +:1075F000C6CA4B65B07298083A3CFFB725935C7CCD +:107600009289CFA50B0478D5230779D9856F6DE0D2 +:107610001EE02C76F250EB7254E6E71E1C3EC5DFEE +:1076200063C1F3631DA201B81FB5E7AE36226CDD5E +:10763000E4DADCB5C80F5B84440AF92132EF54E880 +:107640002686F777C7302D12FD87FAEAA788DF5F15 +:1076500009915DB66DEE1A8A4BBD7B737232EE2FC7 +:107660009B18DE5FA5FD3C3D56A45CDBBEB13C6FC4 +:10767000428FF36732CEDF83FD3D6D974DBB5E1FBA +:10768000D563EBEB919B3F8D723EF86994EF539B72 +:10769000944E15E9A1BF48D5B2E52BA722BCFEE563 +:1076A0007E28C7FB18D968941FD0AA4A353BC95910 +:1076B000C2E5C4E5534A77B9CF5739EDEE6DE822FC +:1076C000BD6653C35E7AE6D7A601F3E882A5968E1F +:1076D000FA87FAC74502EEC770118FCBE3FB4697D6 +:1076E0005EF7695BBEAB785F101B4F6DB274F7FD40 +:1076F000B4AA2864BD47E84894FB89D526A0EFEAE0 +:10770000BE7FA6FC85FC1243F82C969B3AE9F765F0 +:1077100002DDFC7DACC4146E74F51BABEDF2ECA382 +:10772000AAD82793DD540F9A8546A0DC578DFEB961 +:107730008EE5C14ECC6BCEA437FC7BD54537EA1F16 +:10774000AF26FD098E72FDB5BA58253A6FAD577652 +:10775000A2FFEFF7B12ACA67EF88089EFC02E7890B +:10776000F177A611923FCDF2F338BC358DC7E1B168 +:107770008C71787C621C1E9F1887C7EF1887C7F230 +:10778000B71B4C2A633C1ECB188FC732C6E1B18CA5 +:10779000F1777CEE6DA8A3E70F1B52F4FDD9867A32 +:1077A0002A5F6ECB5728E5BF07D6F105C5C4FCA9F3 +:1077B0006E7B7DF69BCBEB7E86FE42881AB8AF07C8 +:1077C0000E35BDF2EF7699EEC98E17E7A3FF126270 +:1077D0002260DCA12DBE9DE9A283F30BC8F7824E87 +:1077E0007177AB0EF31EBFB1ADF70A99E91F25F112 +:1077F000DBAAF258F9C96D2FB7619EE9057AE3CA91 +:107800009DAEB21E99B5E6696DB03CB96CA71C641B +:10781000DF9F89FCB20DE54520C6F5C367B7FD9A29 +:10782000F4C3EE62A600A1BC2B52D248EF37E23A75 +:107830004DC579F07CEEBF83E638E6F94DD6955913 +:10784000C8A7AC7E37E78F51D6C760CD9CF3DB0D60 +:10785000574F2C1F553D3AA73B643DF65D18A69F38 +:107860005668D67A19EC5B7C7C1FB60AB89FB8C301 +:10787000C7E54347803FA7E438F90D55CDD102CC89 +:10788000FBE17CDC11E0F713F44F17E9777BA05E96 +:10789000F87BECE7F3E341C3FCC859D38BF3D14E3B +:1078A000F8854D0F532747F8FEFE8F2AEDEF1F9FF7 +:1078B000FC644B1E2B4FFD17C3C0FD7A0B1841947F +:1078C00027D6562E4FBE553E256F19AB7EF19CEF45 +:1078D000E6A17E3CCF964F69DB8E696CBD6932DADA +:1078E00011EFBEC4E5E31BB67CD9E9EB4DD17ACEEE +:1078F00009D3790B804ED25F1AE332E58989E3F828 +:1079000053F1699FA6FB335B15BAAF49F9C33C95A8 +:10791000FCAEEFFBEDFB8A7B49AF5102492D97BDD1 +:10792000EFB444F253346BC134DE9BB5253C8B7EFF +:10793000BFC12A93296EB6A58CC77F42916BE85EC2 +:10794000ACAFF404A87E6B58A57CE174D99E835536 +:10795000317C8A1AEA07697339DD636969A246795D +:10796000C7EC5FF47D6D8CFC4174FE18BFAFE5F190 +:107970000ADFD843546EFEA446FD839DDF4F2A9A4A +:1079800088BF2791E8F1DE4BDBFF938FA1BF640D29 +:107990003FBF32435BDEF31CFBDE62AA8962C60F87 +:1079A000ADDA3BFB42585E05144F0D4D7FBD298477 +:1079B000F56FD40C9EAFC5CF4B807D0F724BD98A2B +:1079C0009EFFC0FE578660AA81F5AB55E4576881DB +:1079D00017F0DEAA428288BDCF9D25A0DED65A4B85 +:1079E000D77332F8BCE70C5AF2AE54916EA4A57965 +:1079F000344E2B982AD6B76A65DA3F0BC36A37FA3A +:107A0000170A6DFF84230FF253AEF306EC7FE3D722 +:107A1000CA9EF308636FF4960B32EEE12DB7E927A7 +:107A2000136F99F3CC8F3D938BF0E4AFA59313E7DD +:107A3000C17F6F6CD6329CD7386D9FB0B39C4C1F02 +:107A40004DC77BC821D5E8CED7F873E19D51D6D27A +:107A50008BF4304397416778F918F43761FF5B6C1A +:107A6000FAEF28F2EEE3BFB0ED1FC6A76BA37330A9 +:107A7000EE2182E5EA1FE322960B9E291D799EF2F4 +:107A8000D4CEF19EFAD376147BBE5F98BEC8F3FDC8 +:107A9000E2DDB33CE5E95D9778EA7F6C6F95A73C42 +:107AA000B3FB4A4FFDD907977BCA737A3FEDA93FD5 +:107AB000EF95D59EEFF3FBD678BE5FFADB0D9EF215 +:107AC00065FD7779EA3BFA7FE6BE795394CBA30F45 +:107AD000ABF7E3EF03B9CF1D67DA15E7DDAFF3C707 +:107AE000661DE38410E5F7E9CAB8BFB3F2862F70CC +:107AF000FB4C5D68E8286F5645B97C5D9F67DE8E5C +:107B0000F2B532AAD23E2187793D397C05E923932B +:107B1000763039359BECB681EF18AFEE68B016962B +:107B2000B8FC5A01AD13304FAC325A43F70A3AED64 +:107B300065CD04CC9F5B15D5B91EC4AC5EBA2F4091 +:107B400067ED5DF36276225D31D1CFEC48D4FF075B +:107B5000EC443987E2C3CC4E243BD20872BB11CE31 +:107B60004AF4DDF88A40F7F8333B90ECC867C2CCA2 +:107B70008E9C89765BDF169443FD3F9529DEC8FE17 +:107B8000C84E2C6776E2E65CB7BFBCAF089F69D0F1 +:107B9000C6E3B347E916C71691DDF8CF48CF9FD9A2 +:107BA000F8521DF63BBD9CDFBFD731A6368EFA7466 +:107BB000475117F1497F91CCF7213951EAF6031E5D +:107BC000B0F7AB90FA2DB257D93A905C76D6618B6C +:107BD000D097C67B0EAD2F04C92F3EE937FEA3C850 +:107BE0006F6AB13A01F3048DFD8A89E3DD6BE3B975 +:107BF000589B59853F0759125FB60F9F17E84C1FD6 +:107C000061CFD2D27BF6E1F37B51327AE122E3E914 +:107C10002A9431EA42EEDF966728E92601FDD20C6C +:107C20008E2CF689F394A23BF8BD4025F21B487FC9 +:107C3000681D9C6353A8CC5329BE1C40BA10E84968 +:107C4000F4149043B4BF04F0B02A962B843486C455 +:107C5000507FC5BCD1CABC1D44078E5E8BFA6E92A4 +:107C6000DBD10790DE62B5DEF50FA9DF263CB5D883 +:107C7000E7A23B72F543556CDC8E82E23CF4EDA248 +:107C8000DF65994BFE1CB4F7DD477344474F20F97D +:107C9000B30073190A06F522C60F3BC429086F8288 +:107CA000E2F0814312D9FD81BB3BE97758039AA5E5 +:107CB00003E9FF968EFD5617AF243FE1FFC466919E +:107CC0001E1CA8FF5156BC05FA2430670F8DCFE863 +:107CD000050F903E0063823AEEB3F5B1A0B9338B45 +:107CE0007D5017B1ED9F498EDF3341E7625BD12FA5 +:107CF00017C6AD4D15319FE7F69F1678EC9ADB0B52 +:107D0000B81F73A8F103CC1E4DBAE0DBC4FA4539A5 +:107D1000DE7A76590DDDBB8ADB4C399E1B2DDB49A3 +:107D2000FEFCB3CD3AE67DD5D9784D61320FC3DF85 +:107D3000240516ED447992C7F42386D24ADBFFE28C +:107D4000F86926E6F0F8BF6181C4FD773E67DF126F +:107D5000CFE17D353AE8CA5CFB2A005281F9BEC604 +:107D6000FEAF07CF0F4EE970ED7380FB81B73C6D1E +:107D700087B77C61DA5B665AF4CBA807AC00E0FEFB +:107D80008FDDDEEF61307D186F19EFDCB39FE0E728 +:107D900009550601D2775957BAE76B6C7E09E73E61 +:107DA000CC8C7BF5A7EF4993FE7295FDBB1F99F72D +:107DB000BD8FC7DF019941F3F2ECA3B37C12F92523 +:107DC000D09F64B8FC49259AEEB1AB1CBF50A65CAD +:107DD0000F1EBF07D817B2EB937EBC37552B43FF5E +:107DE000435BE1977E73A27CD00FD326A7DE3C4194 +:107DF0007E4EA67FC5B89F04FDD7B7FFF48EFF3E29 +:107E0000E1F267BE1B4DCE46BFC7FD93797BE75EAF +:107E100055E7DCDF3B35F2F382CEE148BAE0B8B398 +:107E2000D4FA385757D2E3D08FE4F8611C7FC3F5FA +:107E30007926E9E75B8CA3A9FDACDFAA5FFA01FB19 +:107E4000592C1D3AD880F26EA24C7925DABCB58F38 +:107E500004D1EF89DF59B9AA481F4BFCF1A28FFC6E +:107E60000EED36DF3BE7571DBF4D2287F347AD6D63 +:107E70000FB09906ED731B41D4932FDECDD6D0B34E +:107E80001F72BFA1E31F9CDEE5FD7E111E0527FFCB +:107E9000E84ECA8332E6F33CA8312BD3FB709D3FFA +:107EA00066AF33C6B72AE70EC659C7AE4AEF433DA1 +:107EB00074869DCF54F6E2F3F493BF20154A485FD1 +:107EC00017611E136B671C903DE746C68040F94062 +:107ED000638E49469AF533E359EFF73270958B106C +:107EE0003E6F39337EC5D4ADB76F10F0F7535302F0 +:107EF000CAB3ADAB988DC0CAEB72EC3CA40BE002E8 +:107F0000A4DBC552D8C0FBF536FC5CA23C64FF89FB +:107F100069BFC0382ABCC4F32EB5293C2EABFD4442 +:107F2000329804042D0433678607E35D5F3D67E004 +:107F30005DFB037EB4C7D9BAE33EF404B3FB4B7CCC +:107F400068C76B54EE62763F969F61763F3EF7308E +:107F5000BB1FDF7F8FD9FD58DECBEC7E7CFE90D936 +:107F6000FDF8FE5966F763F9C5DCCA2D397330BEDA +:107F7000554AF4149CB987F21EDB559F86F4932969 +:107F8000CF2A2B6F575730FC6E0E2FA6784BD56239 +:107F90009E77BF256731D9D303FEBC0C7FE8A07F55 +:107FA000AF4F70FC7B78043A6EDBB3037ED2A44102 +:107FB000F71B8CDC8FE9F4437ED6F3FAB1FDAD6F8D +:107FC0007DE1575F6F669FD6CDD9DE112CC6733F1A +:107FD00029FEDDCE3FCCFCDDAD757B1A291F501983 +:107FE000772C85EBBAA73C4CFA06FE2E13CAED4C53 +:107FF0003BD1B10F33F571E799B91F66E6CB446CFD +:10800000BD64A4FC8D6DBE14C5B7AD46265F70BFC0 +:1080100068482F7CDD77BE7F77B29697714E99E7DF +:1080200067F90FF2BCBD0E486AEEF93BE723C8E6DC +:108030002BE67E46B77F375892A6FB1B826193F4EE +:108040004581E991A4576A498A17B60DF1FBDAA771 +:108050006C39D138EE1ADAEFDB5EF491BE556DE77C +:10806000C9358F53A9DC3C6E6E9CF22B2373D5BEB1 +:108070002CFD6C88140FBBBF4A6CFFD787D9FF2536 +:108080003F3F17D6BC6FBE8AE7A73AC2AB7BD16E23 +:10809000EF88C7284ED0336EAEE77E72295E41F777 +:1080A000594861AE674B7195F46C19E75F3658DF3C +:1080B000A9773087D30F6373F26306C29D54CF2F25 +:1080C000274CF4B7F8633C0FD9AFF1B862B0440461 +:1080D00035CB798D1EDB2FDE5196D4D0AFD31197DF +:1080E000E9DC47873E6BA8B82CBFEF42F3FA079B49 +:1080F0006DBF43739D427A61A23E57ABCEA7730B0F +:108100006790CF3BC24D2AC669FF3F82909C4F00CB +:10811000800000001F8B080000000000000BCD7DD8 +:108120000B7C14D5B9F8999DD9577637996437C91E +:10813000E6C90402060DB8818487C6380991A222D7 +:108140002E0235B4B42C0414E415D1B6ABD5B2214B +:10815000098F2025581F282DDD50B02FBD8D96DEAC +:1081600052ABFD6F04B9A8A8A97A15FDA146B43E8B +:10817000EECF6A04BDC547FFFCBFEF3B33C9CE64F9 +:108180003604B5F77FB1653833E7F19DEF7CEFF347 +:108190009DB38EBCCA60CCC758CB3FC5862E2F3C42 +:1081A0008B18EB8127934219AC9C318F2C3096CDE4 +:1081B000D869FC73317CEF76ABAC129ECB1C717727 +:1081C0000963E168454EFD44C6166685990CF51CA9 +:1081D000BEC5720CDADB1953B13FBD9DFE0C627F48 +:1081E000558C89F26F6BDEF20FFEAE3FC5F41D2C8D +:1081F0008270944A6FF7BA18B3294C386D8332F302 +:10820000CA6F9FC7E8CF6911FFEE09867DA9FBF110 +:10821000B9FEADE6AD8983DBAD2AEF75880A639BB5 +:10822000F7748419943F131482CBCE626A01CC6B2D +:10823000F5FEEB5904E6BF55EA71C900C7D62F8495 +:1082400085E1F2C1FD2FD3F003088B219CF0C776A6 +:10825000FA7CF85B618A63126305F866243EF9775D +:1082600018A5FB34F45F91807299060FFC7FE261E0 +:1082700063B9AAC7589E7CD458662C640F8F63ECF0 +:108280008575D0E9398CCD39F6DE3196CED8DC58FB +:10829000E8F147038CE5ABAE705C666C1E0B3DFEEF +:1082A0002A940B1A3C2C1182C16D6C19AE0B4CF345 +:1082B000A55280AF8111ACAC60591A63AE81FEBF8C +:1082C0002B67123E1A7A17CD64E319FBF1CD2D8C82 +:1082D000413FB13A21BE17E09F5DBF67F62878DEC7 +:1082E0005B692BBA0F1B45EC6FE1FC5CD0D9699838 +:1082F0006FA6EDFA1123A17E789A4768817A3FBE76 +:10830000E0DCCDA550EE993E3A8478077CBDD53FA0 +:108310001FC0FFBC306FAF8FFF6CE589B9A3E0B918 +:10832000B3F2A1D9F89C935C1FFA9B35A5B3D90190 +:10833000FD5DB9529980FD85EB8DED0BAA8D6580B1 +:108340009CD609E7EBCF1A0CEF99E0318FAFF777A6 +:10835000EF3A85F0CFBE007A007C86F113B40F4B64 +:108360007D5208F09C5F2DA871A09B0255503B2DBB +:10837000F8619B463F66FC8BB10C867C56374F8C70 +:10838000B743957C979DF09F3F53882B307EFEB27C +:10839000BEC469287FD3658F8BF03D2BB34BC0EFF4 +:1083A000F7AE64ACA384C04BAF4D5ADF7B5D6DF676 +:1083B00062F83E2F4F6436A003563D8AC6233846E6 +:1083C000123E8E737CB8081F052B438FFF0CC6BF6F +:1083D0007A8A5316A1FED50DFCBB0EDF5609E80CB8 +:1083E000BE6F053A8B119D49C793F133E7D8AA5563 +:1083F000488F734CEFC7CA8CE8EAEF538F8E29067B +:10840000B856091D333C008ADBDEC4182E346010D8 +:10841000E95AE7471D4FABF635133F26F199FD3476 +:10842000F233FE3B8750437CF698EBF732CA8DBFA0 +:1084300064F6EE6440C2BF9059ACBE9AB1FF93D6C9 +:10844000779E00E5DF74346CDA74117C77F7FD9663 +:108450005530E6DCF89D19338A06CA69EDCB67CC46 +:10846000B808FBE3E3C014627CBDFBC725FAE893C0 +:10847000397C5B54B65D84B26493B7874A06DA658B +:10848000613B61887661B65DB268E7D5DB019E36F7 +:10849000C0FAA569F34AD3BEDB347892C797106F50 +:1084A000B2E215603DA4E9928CF4F255E1C839D3EB +:1084B000BC236CBB7DD4E0760076B30EBFCD1AFE34 +:1084C000387E4F1EDF3E04FC5F373ECED49F43FB19 +:1084D0007ED6F041F5F539A9E78B70D9515F298A2D +:1084E000D796D4CFB6EE4F9F3A1F88579ACF426E99 +:1084F000E843B2AB7208E8BC5CBEC3859D4B99F5FE +:108500007204F86133945578BFB9ABC3A5C0FBF2D0 +:10851000D2DB3721D19727D218CA83714CCEBC1F2A +:10852000FA1D274B2C81AB76D1419B07CAEC0A166A +:108530001A0DFD6674A7913CC92CB9E017028C9BFB +:1085400099E952B1BD2773D22F18D10753A4247CC7 +:10855000786A5FA8F3205CB35908595112E2AC164F +:10856000996C2C637BA19C79C91E560FE5097FF796 +:108570002922F2B4C4F55D3BB6473DDDCA0EA17EAB +:10858000C9D3E4CF2687BC9DF4C7751243FDE1191A +:10859000778780F0DC0B5D89C097E5E559B3EBA1E7 +:1085A0005C7EC41652149C4F87508CF3098AA4B782 +:1085B000747CEA7264C24709CEF463597C2FC0DF31 +:1085C0006A8F27505EC5A65E2DEF0578F29724C905 +:1085D0006BFCAB0F7080F03E7DD5DEF612A46FE928 +:1085E000ADE4FE323E8A27509EB1DA8630B60FCC1B +:1085F000940CF23F4D936769263DD09A65273AD196 +:10860000F50153254586790BDABCD98FC2A40F9C9E +:108610002CE47290BDB280EC1081F50AA73D307F4A +:10862000AC887017F1790C6A3F89B767C1900BED80 +:108630001C675A5313D6878F59CD805CE1BA341525 +:10864000F5B3E060AEBC09306F1B8B74019D340B39 +:108650004CC2F2C0780986E3395D9E56B4BB1E73E6 +:10866000B5D8107F2D87417FC03C36DA19B7FFE4BB +:10867000902B0BDA4735FB6D6DC5C85C2C67E4E8C1 +:1086800076615846BA5C9B5D9A8BF661BABFF7DBA0 +:108690002867676EFFE30C17CAD53AA87301E89DF7 +:1086A000CC8736C540EE3A4F153025C9CE734A4DBA +:1086B0000CED29E7A962C3FBC43A98D1390365D50B +:1086C0006BABC771D6642A84D75A26B762BB5A40AF +:1086D0008692B42ECE53794C9968D57FA1E17D0264 +:1086E000EC24C5399CFE3D4C294BEE7F548AFEC7D5 +:1086F00098FA972DFB1FE8D76FE8B74D626447C71C +:10870000025E5A77B35DB031B3EEC64CB4479DAC50 +:10871000A9CBC2EEDC906923BADB186CEA51A17DCB +:108720001D03C6073AB9F88BE322237B06560AE8F5 +:1087300085154A7DFD743C12EB71FAB5C50486724D +:10874000E962C96EE0931A662C9BEDA27361AD11CC +:108750005F365F650FD2CFDAEC34C56901BFFEEC3E +:1087600059C76A4A47C37CD3C2CB18F0F1CFB71FB1 +:1087700076B505A19CCEE9E481EDAFCE88C1FC7A47 +:10878000044E7F6D011BE1255C97DB2926F51B76E6 +:10879000B0D12817C348DF5E0E0F8EDF935DB8BBE4 +:1087A000DD627C10BB06FB61B62AD49426CDAB47B4 +:1087B000B383FBC79B56D0897CD03F9E9355D1781D +:1087C00022E03F79BC9C2F37DE5F717EE503E3CD6D +:1087D0009E6E9CDF6C874CF39BADF1AF3EDE5F710C +:1087E0007E255F623C9C5FF278DF30CE6FB653A689 +:1087F000F9CD16397DF58F97F3E5C6EB59574676D7 +:10880000F04607C827A093B48A7DAE5130EE469754 +:108810005D16948176B5B537B8E6A2EEF54E9B9E0F +:108820000DE3D45D0295F3B19769D36B4B19DB2E41 +:1088300070BAE8CBFCAF4DE8479E9CB9B68CF48982 +:10884000665F5F8955411F5F29717867157AE3CDAF +:108850004978BC17E4880A70FC14F85D057EDC05D5 +:108860007C89E5F8BA203D7783BD8ECF3D002F7E11 +:10887000BF6F5D88CABF5A37859E7A3F6553B8DDA2 +:108880003EB6DADA6E3F2F8BDBEDDBF3E4F94B50CB +:10889000AFD5A685502FB229173235D9AE664D8F88 +:1088A000B9E1FBD66FB20AD48D637670B803F5399F +:1088B00064B7A7551CEC5907E58D925D41BDBC51CD +:1088C0006133ACFCE631A867603CA793B7671772C9 +:1088D0003F2C10EE3D887A6F0EDAE980D7ECB9BDF7 +:1088E00007D1FFBB0AEC72D2CBEC8D83AFC2F71776 +:1088F000C0FF6BC7B2E865329467CDC9A6F1E14FFE +:108900007A6D0EDAEFFCCF4F669E20BF22ECE67A3E +:1089100021C0663FDE8DF0861C4A9CFA6377869103 +:108920000F54BBD24EA2206C473D9D8D7A1ABED704 +:10893000BEE1643684EF1207C9B5B9738D7EC37684 +:10894000774246FB677B45803543FF57CD347E77C2 +:108950003A39BF854D7EC32C5319AC2DAE77C50572 +:108960001968EF6FC4575307E32D7AAC79E3C1243C +:108970003A55B27C81B73DB8106C0CCAB34F58F968 +:10898000B67AFC589845C68AB9FD3FD6C5361E044E +:10899000D4BF80720FE5AD83CB8DC1FCC1E1A9D1FD +:1089A000E4E3BDEB7A6ADE1A3D005FBE1417500F98 +:1089B000142C83F749F395027101FD1D26DE5F81BA +:1089C000FE8D791EF70AF7E7318BF1F4673E93DEEF +:1089D00046BCE052A23C37CFB766D07CAB9F2D653A +:1089E00056FCA46C477B6ED66131D4AC0CE0439F3F +:1089F000FFFF345FBDABE19BA90196007A7916E8D1 +:108A0000BD9DFB310CED549D5EA102D94F575E090F +:108A1000DF912E54B508F1F9ECC8BE3DD7603B900C +:108A20001D2DE8EFEA7650E2651BDA415FB6DF2BD9 +:108A3000AF7390BDC558BDFC76D9407FA9D607FB62 +:108A40007D3B497FF6DB89F8679226FA10C6E6502F +:108A500090EC819BC03E467F3F5AFF9E94CEBF1F45 +:108A60004FB253F1CFF1A4FE5ABA7F2D280057E739 +:108A7000BAAE9AB7EC03E3962C936D6D68CF35C709 +:108A8000058A4324A01ED803239729B656C0FF1297 +:108A9000EC07E9D324D747B6423FC9764AF55CF9DB +:108AA0007EA087D6F2BA8E103C37EFE0F132BD7E61 +:108AB0007FDC2C1023FFDCCE9A9800703ADC3FFA62 +:108AC000792FCC476D9198BB06CA766EEFB0577D73 +:108AD0002417446FD32FF17B3006720BE75DD7F478 +:108AE0003B2CC76C2CDC02CFBB3DBC7D5472C94E05 +:108AF00058BF76B975064E3F272F726F168CD796E2 +:108B0000934672D0F19A6F37CA2947E6846568F7B1 +:108B10002C88FE308CF148D9CF16862DE86B816603 +:108B20003FECD5E8EC983D519409704FCFABDB9BFF +:108B30005565513FFA23EAAF46B4B6C31ED5FAD9FC +:108B400069B3960BFF9EC5E39D57AF7AE8BDFB6006 +:108B50003E9E526F08C96DF3F96C9F601B5CBF3B72 +:108B60003BF287ACA478ABBB5496280ECABAA6A237 +:108B70003DB7F9F39F76FD0E509EF5B997E46C96DC +:108B8000E88B0B2586F68F26CF436FFF974F5F0C40 +:108B9000E2FAFCC5CD48BFB2D8D397AA18D7D4CB38 +:108BA000F046C072A65EFEEDA5E86F0E94AFB9B4B4 +:108BB00016CB48BB409435FEE866D4CF5B05A611C2 +:108BC000F14DBCBE9DD72FD4BED75CF6FE2FB6A10B +:108BD0003E98E4203F74AB6607E9F0A97E91F0A3CC +:108BE000FA87C6E36B1A9E5DC3C7E36B567838906D +:108BF000A7BE8EF875B32E01E9D8FDB9EB466C7FA0 +:108C0000CF3A165E02B0EF54F6FD7A9B42EDDFB626 +:108C10005A87F3F3D477B2088EE3BFD80670F8749E +:108C20003826B31B53C0F1E150EBF9A71C2EE7BE69 +:108C300015E0CF2CCDDE74387A82B3E12957DE758A +:108C4000830CF2664349578355FCF9333FF70332EF +:108C500053C4DB037E4E7FDDB9E1D30847ABFC9004 +:108C60000BC74F135818EB6F99D2CB84A47E4301E6 +:108C70008E6780DBE987766953998A74E663BE382C +:108C8000033AF35572F8B7045F600AB4F395C1D3A1 +:108C90008BEF7B89FFD1E5E0F400820ECA0E8D3E9A +:108CA00002FEAD97A29D9F25EAF457D48EF4E2B060 +:108CB00069F563459761B9338B9727DD51D41E2B36 +:108CC000043DE380362817F21D64EF98E75718E05B +:108CD000F3DB96ADE6FBB32DF0E9ECA575DA3ACE01 +:108CE000118AC1BAD6D87A1A1AF1DB655EB2D7E01A +:108CF0007D433C69FE976BF8BADCCFEDADAD9FBA12 +:108D00001AE216EB918A4E276AEDCF824E27FA2D92 +:108D1000E803E8B412F19F44A71F336B3ABDD06F4C +:108D200041E740A7D5F8DE8C0F735964EA8E450001 +:108D3000A0F4D9F45F6D436D7579F58EDFC1B3E6AC +:108D400073AFE4873AE2184676A2CDC5E5FB80DC36 +:108D50008F5C86704B7213BD17BD61DAAF792E2B15 +:108D600045BF9327ED40B9358C7EE721DCE67E4B8D +:108D7000FD8CD6A3E6326F246E81F77FFA256E1F35 +:108D80000778BD54FC322E60A3EF29F945A7FFDC1C +:108D9000F05284E34CFC523FC02FAB86C72FFB88B8 +:108DA0005F3CE59C5F3C29F80523D1289F3794F070 +:108DB000F28FFCB9C40FFDFCC3CAE87B3FFFB0B221 +:108DC000CBB0ACF3CF658132AA6F6E9F8EF3B6C085 +:108DD0004B9B5F9F47B815D7553D4F6E15C9DEE8D1 +:108DE0006528A73A595FB713F9B05A08ED85B7B3AC +:108DF000623DF52E05BFF7B0D9607F6CD5E87E17D0 +:108E0000C283FED0242D9E25F5B0AB7C83F9D857C4 +:108E100099288B24E17FA486C76F07C277E0F89D6D +:108E2000AC772CDAA5A9D6E91E6DBC9B82EA3D562B +:108E30007C7F26BDF328EA9D6C7CF27EB23E7735BE +:108E4000A11C30F379CDEA87DFBB6F887E1ED6F098 +:108E5000F6D0D9F3FD4329F8FEF726BEAF14465AE3 +:108E6000F2FDC329F8FECF567CFF15F8FC3FACF8A5 +:108E7000BCD33F3C3CBB035CBFBBB5F5FDB2787EC9 +:108E800047C3EFEBFEB3B6035EB7C213E0B9779802 +:108E9000787EC76A9D00CFEFFA69BD6D31DC17405F +:108EA0007E47FF7DD3E4581FEE875AC0D197DC8FF1 +:108EB0004BE1FD8069FFB100745EF3D9A650C48216 +:108EC0002FA1DD3F92E1D7DBDDE397B5B8B3723D6B +:108ED000DAD53B2FF7F2FD846CF5732B7EF80AEBA5 +:108EE000EF0C58C8E31A1B9743DFF6BF4576DE57F1 +:108EF000E8DF6FD5FF331A7D9D49FF8F49D2FFD838 +:108F00008F59DE75321E4FD9961D290910BE7A2F52 +:108F100045F9B4EBE62C01FDBA423521A0FD9FAF27 +:108F20008D77BB5F21FAD2DBED92128284F59B64D0 +:108F3000212618FA3B6FA8FECC70007CE30324DFE7 +:108F4000D4F3F1798FA6CFCED61EBA30A84E0E70CC +:108F5000393D15C757CF31CA697D1EB67017EB452D +:108F6000FD02EE77DC82AEF2357D09FDD4513F9AE9 +:108F7000BCBF20206BFE29EFEF6CF50DC07739F6F2 +:108F800007FD5E61059F192F6782F3960138AF0ECA +:108F900058E825737FBA7FADAF13E9D3A4B8CE12DA +:108FA0008D5E80AF1A113E579B2DC60203FCABEBC2 +:108FB0006B904C69D8FF4E078FA3EE5C797B2DE652 +:108FC0001B74DE2257204AF297713DA7AC2CA6B83D +:108FD000EA6AAD5F33FCFDED1D5D632796D3B86B88 +:108FE00071DC8BAB5902E54606DA09147F90258CBB +:108FF0002F64393B821897DD2C74342C463D7AA9B6 +:1090000097F42D0BCEB58C4FE94F3DFEA4CF9B05B9 +:109010002BCF50BF99EACB9E8E26B493865DDFD9C5 +:10902000616957FD44B3AB607E3F1E12AFC100C5FE +:10903000B774FC0E1E87AF5F6DB849407CA795C31F +:1090400090C09269E10EDA6CB595C6592FDA4F657A +:10905000402FD4DF0B9671BF81FE36E8707522FD7C +:109060007C55B8F47AA9C7E3F570FF8CE21D5E2E3B +:10907000B7E803944F1CF65BEE1FE8CF8DEB645509 +:1090800002FD73425632305EB851D383E09905AF8A +:10909000F2FDEBEB0DCC23CEE39DA6FA51C6E99E83 +:1090A000055D64DF61183E996E8E6A74B02D27FCF1 +:1090B0007480E4482884740DE567495EBAA0ECA387 +:1090C000F25FA92CF7979FA7FA415E9FC9F2B0F013 +:1090D0000CED5EA176527F3FC7A8ECED1FF7351A65 +:1090E00027D05FEEA5EF85BCFE70C7495A573EFFFB +:1090F0001E91E6FFB1A466E0FEE837A38D14279A1F +:109100001F5D4ECF4DEBE45A8CC73DB3AEAFB515E6 +:109110009EDF9CDF28A3DD3F7FE94F68FF5EEFFF06 +:109120004AF42B90DF156906D94525B6F01EEF00ED +:10913000BF0DC0D1AAE9FBDE7AA42397CAFADA2BC5 +:10914000A0FD948F5A5B0D794E1D943FE356A4CF3A +:1091500092E3EABA1CFCBB433D1D383B3A36CD973F +:10916000B18330FEC7DED2788CE8BA4EB6E2177D06 +:10917000DEA9FAD7E79D4ACEE8F8D3DF6F2E9D200F +:10918000F3FC9FB8012FEED1F594EF73A5A0C1E9D0 +:109190007369FCC6EBCD82711E2A27FA50907E6758 +:1091A000697E9C592FE8E3FEDD1119938DEDE0CD2A +:1091B0002D132CF03B4CBC1D5DB72C5C6F4779DC4C +:1091C000E5A6FD7B26539C5FAFD79062FE75D95C08 +:1091D0008F30A74AF3D9726B461CED8E2D8BFE2083 +:1091E0006370C533EEE32ACCD7F4087D9F2C46F993 +:1091F00072AB8FF2311A167D52D59CD4FFC2037F19 +:109200007261BCB761DCFA6C8CBB2C64D2C7C9F943 +:109210000EE6711BA2AB896E63CD428395BF752CA0 +:1092200087F3F5424C9111A9BFE3C9FBC88B9409A0 +:109230000E8C4F2C8A19F77340433A903E1A379997 +:10924000DF27EDE788D83FA379C770330FF55E9B22 +:109250008DE86D27E00DFDC0625097F83C9693A510 +:10926000F1410FE1F35F0DCFB11C6E0F395D2CE6BC +:10927000C91AA09BDC480743FDE4AB14687F33E0C8 +:10928000D3F323BA484FDDE1D5CBA0B700FFE1729D +:10929000CDCE29E5DF6D5846FFC7D373D0067CDC01 +:1092A0009EFDF865C1B1D05F79246893A9FCA44400 +:1092B000F6212F33F6F89307C99E95CF1542C0FFCC +:1092C00052F793878BC89FD7ECB1EE27C91EEB2FBF +:1092D000B30483F974A6F597555710CA23FBCB3115 +:1092E0002CEFD2ECF8F6ECEE275BC93E09B7652708 +:1092F000E9EF5AC6E3CB5FB77EEC0C2EE9C07CA247 +:1093000058A98DFCBD34133F3E98EDA07A637223BB +:109310007767C373D62D7D12C61B1C792F04500EA0 +:109320008C283DA18E04FA1F51CDD36458191FB764 +:10933000B3742DD90D9DDABAC0FFD6A3DE1B589F9A +:109340001ED3FAF0F50857F6D0FAF8CA7B68BD6C60 +:1093500058A6B81FDF8FBFA292DB1BB293EF2BFC86 +:10936000269BC75DFF942D6A4FEE976694DE4EF103 +:109370001DF70C1BD5CFD09E6639FEA76CC9A05730 +:109380000EE445FE909D64B7C2FB705925CAB740F4 +:1093900016EEB3D6964A37223DFF5CF34F619DEE41 +:1093A000A0752A09A445F8BA3D62B96E65C35BB7DA +:1093B00017D745485EA55AB76FCE17C35671B76722 +:1093C000353C7CD0F0B7BB902D57B9FA1CB80FB321 +:1093D000B974BB21AFDAB56F760273A1F5BCEAF5BB +:1093E0009EF46A94DBE6715FFCE23F0288DF999F9E +:1093F0003A2DE5E37F6BF2F185750DD40E16589189 +:1094000072480E309EF7D29F27269C76D2F45EC417 +:109410003CB4EF12EB333637FC06ED572F0E8A0CB7 +:10942000F7C71732635E198BEA79C13C0FF645091D +:109430005C5340E18B31210498628BA4D9BA5C3132 +:10944000E487CD9B3BFB10EEC3376AFBF0205F0C3B +:10945000DF979AF2C6AE6E5814AED7BE9FA4BFE394 +:1094600034AFB90AB71BE77ABDA45FE785E787EB9E +:1094700093F6E35EFAA76899875E97A3E3251CAE8F +:109480001F3D182F8BC3824356CE8C1F333E6A2557 +:109490008EAF451ABECCF831E3A171EE6C5A7FF362 +:1094A000FC5F7485093F2F027E305FD88C0FC62287 +:1094B0005720DDBE345F64681F4F1767DA314FA055 +:1094C00071B6C030BF68290BA5F3FC6075D625497D +:1094D000F09AF168C657E3A32C94807E1BEFF4D179 +:1094E000FA3DA7E1474C7C48F30AC3BCDAF9BC8ECD +:1094F000F3FC5599E675955AF17800BE475A41DA62 +:109500002A567A84CF6731CCA75D1EAC4F3E61D519 +:109510004D48274B4D790B66F8CCF0CF4439387560 +:10952000F03EFEE41C5F80CE2F8C67216D1F3F83D1 +:109530008E3584B287CC5B18E0734E5F0BA3B3FB10 +:10954000C7C37E0516E92FCB80DF994FF8B7CE83CE +:109550007FAF0D8A0AE609CE9E3FAA0DE71F66E19E +:109560008C4409DAFB7D76942357313063A1DDC545 +:109570003049D4B7E17A3795F57E4F747C64273D46 +:109580001E614D7B69FF5DC9983B2EB57C591B74EC +:10959000D078663B6566C5E80C9417667CE878FA77 +:1095A000568E96DF309E8D3F1BBCF4A0EC457F1697 +:1095B000E368B08E7DCB19DB5D31B07FCC0A556E90 +:1095C0004FE630DAFF5F9D93A9D91D4D147758A05F +:1095D000E9856376D6F0A097EF234F48928F0BF37F +:1095E0006A57E724C5FBF47D642FEB25FC7DD7E5A6 +:1095F0004D88E389EEDEEFA70F925F7ABE6684F2B4 +:1096000035C58C950AC5C53CE9E35906D8C58CCF4C +:109610001BFC989B7230AEE7298EA31130F3895F53 +:109620006C9AA70CACDBE6257B3B105CF7D2DFC75E +:10963000A87385E77378B475ABD5D6ADDF8E2E836E +:10964000F749F83DD1A1D961655A1C1FFF40F94483 +:10965000A91A1FCA7FD5D7D15D06FE87218FB08397 +:10966000F0A7AF2738117DC89791A04439C336E6DB +:1096700022FF387213CFC758C8945D981FB4306A60 +:109680003F91DC4F244F2238229BDD5ADC2444FDDD +:109690002CCEE3FDB032EEE7F5D37D0CDA27E53FC3 +:1096A000DA5C604A62FB4C1642FF09FACB417DCF7F +:1096B00036258D3372F0B8A9FA33B713B5FD5BD1F7 +:1096C000190A8592E4F46F72B89E3C11ACECB28D2D +:1096D0004C8DBFC52EBF2A25E5C51ECF733558C595 +:1096E000C5F4FE74FDDD6F27C6963F956C277A376B +:1096F000343E75F8A2243B31D6F814C515F5F2595D +:10970000DA89CFDFD5F8542BCCEF1FAF7E83F2C7B9 +:109710004F3481C0043CFAA3D3D89B7E940F32E926 +:10972000AFE206F0A830F95B52C622BDBBA305AA82 +:1097300094942F7B2C4721B8FDA52AED9741D32E79 +:1097400074C5FD524840BCDDAEC5CD8070C7CEF6B5 +:1097500025B7E37E883E9ED325131C0E7D3C166AFA +:10976000A6FCFA998CF4889E07A2F3B5DECFBB392C +:10977000C678DD30F8F9DD9CAAC1FC2C8A4DAFDF3C +:109780008A72E22991FCB0EF046FA2F7E678C089F3 +:109790001C6E1F8E102327502EF4343CFF9D1F405B +:1097A000BB35FB9C2154C3ABBEFFDE8FAB14C4138F +:1097B0005FFFF94B1BEFACC2798D9664DADF28E2CC +:1097C000711847B340FEABBBC411DE07CFB703B57A +:1097D000237293E07A3B504FE59133385C27A0CF5A +:1097E0007605DB6D6F207FD1C7F7BD4F280A9DEF4F +:1097F000133D8CEC09D1C99F99B9DC2ECDCCE5780D +:10980000766B4FD729811609E9BA09F72DA418E517 +:1098100041BB4E49F4DE210896F69ADE9FEB140810 +:1098200067C497C7DCDE41EF713ED85EF433837DB9 +:10983000938FEDABF0C9E9DD75CAC3E1F09BFB493D +:10984000E7EF35FE33C37163CEB462C4CBDB017581 +:10985000442E8F6F7339EC7DF2A8307E38F298E792 +:10986000EB5F9127B928AE77AB101F0DF2A9BDECC5 +:10987000441BC9AD1257139E934AB29F047EEE86D5 +:109880009FAB18B04FFB2E995389D16BA6DC1B1AE6 +:109890006C6FBD5EF9C9BC3958D0CE4F7C5797BDAF +:1098A0003128833DF79A565CA48CDC80A1FE2BAB5B +:1098B000B97DD688F65988E496C1EE32DB675ED072 +:1098C000F773802E96062519E9C26CA7B557CE23EB +:1098D000BBA61DEC1ACCD71E6CA77179735BD4C6DE +:1098E00054A8F74CB5487EC63365BD4F5C8CFA6210 +:1098F0008A5D217D51D677DB1CFA3E91C6F16AFE66 +:109900001DD4E7E71D429EF86878F76CF59BDEC62C +:10991000A4F57E66CA9B63D12FD89522BF428FD310 +:109920001CBC99E77FBD7E87107722DE6E116DD853 +:10993000EFC20A1FE5AD5E227A699CC6AD62DC49C2 +:109940003854D32FC919B01B99589DF33CE2619B41 +:109950009DE1F9C1A21B7B0D76EEC2A8D19E8B348E +:1099600081FDA39CBD1D68B6FFCC76CCDA5CCDAE84 +:109970009BC026A0FDF2CCBAFDECCDD10376CCACD9 +:1099800014FBDFBA1D7381ADEEE65C1E17A4FD83E8 +:109990005992F5FEFE559A7FCA42DC1FBC447C9F5B +:1099A000D6EB444852107FDE9B9EA4731DDE7F8A57 +:1099B00061ABF1B6E7727F7C978391BCDD35C14323 +:1099C00079D7DD379F9BDB4BEBA5DC5D8DEBFFA4EF +:1099D0009DE4602AFDE68E8AAC1426E68B0AF4D458 +:1099E000D77344D4CD92F5C38814790ABB73B9DC1C +:1099F000CEBE85D9D0CFCE8C31D5CA2FD5EB813F05 +:109A00003A1D63D4503F9109F0AD2EB551DC5FF79C +:109A10004BDD767EDED7FEC8F531F44F47007C087B +:109A20008702F0A11C2E897AA83C32EAA7E7A86831 +:109A3000263D4BA305F47D7474143DC7444BE8FDEB +:109A400039D1F3A85C169D48CFB1D10A7A9E1BBDCF +:109A5000909EE781DEC27AE5D15A7A8E8B5E4EEF18 +:109A6000C747E7D0F3FCE86C7A86A2DFA6EF15D1F2 +:109A7000467A4E882EA2F713A32BA85C19BD81CA83 +:109A800055D1EBE93929FA437A4E8EB6D0734AB4F0 +:109A900099EA4D8D6EA1F205D19FD0F3C2E8767A96 +:109AA000564777D2779D9F3D9A3DFD74708F4CF954 +:109AB000F62C518EF231151FBEA1E9856FE4AA4F35 +:109AC000A03CD5EB1DD1CE1D98EBBD9A3B74DECDED +:109AD000D15C4E9F1F848EDF85C769F575DB1C1C2A +:109AE0003A8EC0CA0367D8B7E2F33B9CCBDBEF9258 +:109AF0003AC8DED8D5C4281FCC57D923503E43508E +:109B00009A61454799417EBE6B4C6EE45D9CA737D8 +:109B1000EFAD83B81F7565AC27300DE92514489B60 +:109B200006FD8D68B5917BAD3059C0B252CFE404CB +:109B30001B88E7807D65D06BEEA04D8BFFF4CC9C3D +:109B400088F09C5B3A81EC576D3FF9C8CD2319FA38 +:109B50001DBB1C09414279B996B1643B7CD786C5CF +:109B6000F7259FD370071D9C8F36B1C7304E56D254 +:109B7000A1D4E179C2513BD4C730C573743C52972C +:109B800006E5737E157B0C9F63BBE2751E789EB75E +:109B90003FF118BA4FE312BD755E289F7F981DC034 +:109BA000F053458F32CD07E58947D503B84D52D5DF +:109BB0001B9996AE203CF196748067D76B60684124 +:109BC00079CAFB1D22B82503EB0F76DB8349EBE254 +:109BD0002EED5145F867E18D7205CAD95D52AF3B54 +:109BE000B37CF0FA74E2BC719EA057F66AFBE8728F +:109BF000D27A5405053D1E9817AC1A880776B63EF2 +:109C000047F1C0CE34B916435D7D973079B7827481 +:109C1000CCFD84B4B691A49F74BA03FC1AEC49B786 +:109C2000D6EFAE7E7BD31ABF55FFCBF07B50A3E7B8 +:109C300054F87D1AE79177663E9E1EE47615F07122 +:109C40005D303B75BD15412E4FCD78DE25C9E7123D +:109C5000BEBCCC16AB1858B76B34FA3E135E23FF6C +:109C6000CBF07A517068BCB24A3F8F336BF969A967 +:109C7000E4CD9114E744BEA7E13149CEF178A90CB7 +:109C8000726E546A39578B70650F21BF52E43BAC3A +:109C9000D7E8BB3B3B1C0B669F39AE7F9B4DAEC5E7 +:109CA0007C97D878467E02D897AD98BF3322A64CD1 +:109CB000A06D2C14CA88C709E7919F5E02F686340E +:109CC0008161AA63029F575466DA1697635E83C662 +:109CD0006FF2A26032BFE9FA7E801F75BAC8EAA4AB +:109CE000731640AF984FD8ADE169A01F1E8FD87092 +:109CF000537E677B921CEC0C155059AF9F8A7E5F98 +:109D0000D7E9B7F539DAEFBFA2DA3ADFE4CF41514C +:109D1000CB3BEA5391CE63354CA6F3CEADC7493E5B +:109D200065827C124A787808C72F8CA6DD8771DAA5 +:109D30008783399A3F2EA77DD3F7FF8F9EB781AFD8 +:109D40004E7E66B5DC8DE72A46801E52504E560385 +:109D5000EC95A8E71CB4EE0AE3EBA854B3784220D4 +:109D6000BC25D06F8ED9F8F98C238E2E95F48E23D6 +:109D700053C6FC93EEECC813C121F842F62815B87F +:109D8000A8AF0457CDF4E6615E8E9C86E597A07C73 +:109D9000DB14CC13EA655AF936EFD42F1F7F7865B0 +:109DA000C78A23B84F7561503D8AF0005DBF827449 +:109DB000AD9E234B141F1EE6FE93CE9F03FC24573B +:109DC000E8FCB4A89CE4E15BC1A4FDAC54F6CD2E44 +:109DD0004D7E7E121CDABED1E9FEACED1B0DDE37E6 +:109DE00035B9948AFF673EF1FC8E3D6C20FEE7CBCF +:109DF0007FB14752D0DE9EC6DE9C8871AF1E4EF703 +:109E00008CC7F9548CFF011DB82B5DA6B8AD30434B +:109E10008BBB0C19AFD5E3C97ABC4F8FEBA56B7424 +:109E2000851706A01E4F9F224B8BA9BF5E7615E6B5 +:109E300037E5D90C7C8D720BF7E75D6D59D2C8F20E +:109E4000817E196B2239D5D9C0E4F64CBEFF9A0148 +:109E5000F2A5633D233F2FF68C48FD9F546DEF61C3 +:109E6000CEF7C94A4020CA059529728E760E8188A0 +:109E70005C267A7532D685FE36FB51C8E5C038F7C8 +:109E800067025301EE239F89F49430C20D8DAE0812 +:109E90005584B0716D467508F703C537A10C70D6AF +:109EA00067546760F9C89189216611BFBB3AB2C88F +:109EB000105F32E3A9BFDE77DA285F61E719F63F6A +:109EC0002FCA73E876E7E43CDCFF5CD2D7EA5006A1 +:109ED000F63FF57DBDBCD2872EC57B76F25672FB70 +:109EE000339FC59B93EDA6A4FDC5DABC2ADC4FEFDA +:109EF000DF5FEC1993BCBFB826FF163CBA7F4FFF5B +:109F0000FE62A412EBABFEAE0AA44F3D1FF688839F +:109F1000EF03B0894F05140BFA5850F17836D1A3EE +:109F2000E64F0CFAAEC5CDCC7EF09C3C631CFF64C2 +:109F3000684E46023FA688E3EBF13CDD0FC6789DF4 +:109F40006CC97746FCEBE32F10B81FCBEC02C93B82 +:109F50005D6F823C598AF88666148F569D02E56BC8 +:109F60009D0C352AE417A5902FFDFB062C31DA6AEB +:109F70009F75819677627EFFA33CAE9716D8799C39 +:109F800052B87E6904C75D90E7129C4976D28A3C3C +:109F9000AEC7F5FD1747FEA92AC4B3C31151ACE6FD +:109FA0006DDE475981B66015C753C842EFA5C2D3CD +:109FB000517B07EDCB1D5D2AD279DD9391C974EFFA +:109FC000432AB9F00AD2CF68C6E6E5733D34B08EB5 +:109FD000D678D3F364CCFB55FDDF17B9E9FC8D3996 +:109FE0005FE6210D6F4F6978F957E7CB3CA5E1EFAC +:109FF000692D3EA3C7B3AE4821EF2FB0D53D90C722 +:10A00000E38C43C665CED3F37D34FCB00363E95ED5 +:10A010008E2D3DF6B85B40786CB47FD9F09F620816 +:10A02000ED2FBD9DD7242FF4FC1DBDEC3925B07854 +:10A03000D23E8247EAA238A9E79444EFCDFC775B91 +:10A040005EFFFE22F19FBE2EA9D6595F17F3FBFBE0 +:10A05000B47539BAE84F413CEFB2C5CD2CF38958FD +:10A06000BE31FE6ECE0348B5CFFD9AD6FFC9C8D427 +:10A070005C94CB0D8ED8E8E1F0BD8E9F17BFF8A39E +:10A080000BF96CCB29E70CABF57849D34FA04F37D0 +:10A0900025EF83FAE63FDF8ABD7A24E33EA8AE4F80 +:10A0A000F57D504FA5791FCD7A1F740BB3968FA9FC +:10A0B000F64107ED7F6AFAF6B3BC14FB9FE5439FB8 +:10A0C000673F90C78695F771B5839F9735BFEFD1EE +:10A0D000F8EE646473D15DC057372C7252965262A9 +:10A0E0009193F8B071919BE2B28D153CDEDB78A7BD +:10A0F000A0EDD719E3B04F83BC5809E33FABE99D0E +:10A1000037597812DAA3B32A05C33E79B8DA6D2835 +:10A11000CF5FFA93A7F1DE8467A6D8158A3F435F25 +:10A1200031B40BAA799E2253FA6EC338B71E7FD67C +:10A13000D7FF99EA37E91EB418D8F9A343187F1658 +:10A1400089BF9E796122BF974E18D80F57C04ED84D +:10A1500072C128CAF778B9FC5B14E7DD8271719887 +:10A16000E9962FFE3883E80894720CF9757C561C2A +:10A17000E563E3B80939489707C67FE6C3B8E8EB5B +:10A18000B79CCCC675EA5DD7447907E67537C799A1 +:10A19000CDF1E5B38D2757E71BE9E169533C5997AA +:10A1A0005766F991144FAECF1F463C59975BBA9C46 +:10A1B000D0E5D7CBE5EDAFEE867FBE1C71124CAF7C +:10A1C00068F3EEE74B8D2E5FD6F9F00B27D9230706 +:10A1D000C63F4CF9567ABDD6BC4CA2AF6F95C7EDC1 +:10A1E000B43F8B790A6503EB323FB2BCBF8CDD7E96 +:10A1F0007BD9F506FAE8975367946343CB29573E1A +:10A20000B7C352E56BF6A4D43FA3C94EF5FCD51EE7 +:10A2100077957C793DD4B0E80F0AB683E70E6A3FA4 +:10A22000DE11895BE827333C9E53228B4F4C7EAF77 +:10A23000F0F7FD7AC041DF6375CAFAF5016E4FB7DA +:10A24000107FC69CB8EE52B6DA8A749097ADB6E528 +:10A2500043BBDF06D40DF949F2B4C5CEF723451B45 +:10A260008B3C688197C7F235BCB07010FB6BAB3587 +:10A270009EE7D29FBFC997B4F3189382685FB7BCBB +:10A28000511144FE39E89B44F676AA75DBA6F31318 +:10A29000CAAFD103FEC4566DBD814555DCC76DB351 +:10A2A0008783C9F1C6ADF99CAED2A73ED48376733D +:10A2B0008B6CA33CC11699E75FB77AA5197BB4767E +:10A2C00001433B493F4745F765485E637EF5636858 +:10A2D000EF54A59EE763F9DC3FB4B3C41DD5C2803B +:10A2E0005EB11FAF75D1FD0F4C95797E53C8904F6D +:10A2F0006DD7F44B9D295F4394BF9CDF569C1DE9AD +:10A30000C6F534FB6D8702EA63F83E2AC59C481FF8 +:10A31000519735DF1FD6D6B5459BAFF95E55D17441 +:10A32000EF8368BAF72156D7F4CB5EA4B7F54EB9E0 +:10A330002540F73CD0BD0F51BC72099EFF70F37CE5 +:10A3400016F0FF26F3F306A15E94AF2CE8A2785432 +:10A3500047A1AA164259F4D976AF87FE5AD43A15C6 +:10A360008FAE74786D9DB8CF979317790DE731CD87 +:10A370002791DEE9B82C8DF4107C777339C26461C3 +:10A3800012F98374690AFAE078BECC1E74503CABB3 +:10A3900025C27A9DA3F8F97FA4F75A9638525D82B8 +:10A3A000F6B6AB12F17424343123622127F4A77975 +:10A3B000FFFFD5EFBD544CF9AA62E4A37CDAF76F36 +:10A3C000DC8AFBFA6BF68B21DC47F8CEF75F1EC305 +:10A3D000CF1B19F799EFF6D4F4A23E8B7A1D54AF38 +:10A3E000DB37A903F1D422F83AD0DF6D79E3FA9F85 +:10A3F000231E5B9A799CDB8CE783BEEFD3FD1A2783 +:10A400006139B1BEF97E0DD6713D5F27A78BF62D60 +:10A4100061BEF6822ABE8E141F3CE6A37BA04E1EB0 +:10A4200039E045F8BEC2BC65EC37F5BC0B65D257C8 +:10A430001AFD3029BC09E7F503D1D7D11EC07BD264 +:10A4400060BD11EE47ECE4EFDFED49A7758D027CAE +:10A45000B8AEA2AF5E4597ECC3FD22AD73546AA2BD +:10A4600079B198C4F6E2FB473EF9F18548076A16D0 +:10A47000ED6A89454D84970F012FEB2DF002F433DF +:10A48000A600FDE5476EA07E3A1C2E192D9B16DF17 +:10A49000243AAF3CDCFB452A0A847E7F4BBB5FA499 +:10A4A00002FB1D545FF3B3D0DFC6EFB532FB38CEED +:10A4B00006F09E2A7F452D30DACFC3C85F510B2CA2 +:10A4C000FCBBAFB0AE97170C49CFC6756D71FDDF01 +:10A4D000E96867A9627AC85D0C655C27C43FAE1362 +:10A4E000AE9716B72115A4201DC88902A4831BD2DC +:10A4F00043489F67921B12E3EB6E97809EC1AE7339 +:10A50000CA91A37476518BF7E8F2C4CC672D2EA3C1 +:10A51000BC6AD1EFE53B363C7905F4B202F16096B6 +:10A520005BC3A593EF0FA693EF0F45276979E12849 +:10A530007E473C154CA078C5CD583E7244DCE718E8 +:10A5400089E3F1B8595F1E937727E565E9F06CC69A +:10A55000CD6ED2CB3C6F4A6A600CF3E0FC652141C2 +:10A560002E1F161D6DFE9AE9E88EA1E48397F5D0A3 +:10A57000798D557A7ECEBEA1F373BEAAFE81F5BC5D +:10A580000FE169F17D9FE87383DD25F37BD4CE6E07 +:10A590005D1F2C10CCF70B3D988CB7C1EB1AD987F7 +:10A5A000EBA8164CA27B8CD8944564377567ABC773 +:10A5B000305F8C4921835C1CC43F9ADCFEC1390AA0 +:10A5C000E5ABFEA5599373CD4E19EDF1C70337FCEA +:10A5D0000EEBDFCE9430C6436B6C6B094F1FC2FC91 +:10A5E000768748AE96E1BE4F94A585343DFA1F08A4 +:10A5F000CF0CA559C882F781058A8DAE2155B63397 +:10A600005BF9F0F1F0DC603C3C37141E400EFEA715 +:10A6100046CF37223DEBE7ED53C9C137B4FECF42F9 +:10A620000EBE91CC5F5F03FDBE3FB47EFBDAE5CD8D +:10A63000A7389E59DE78357EFE6E8885305E3EDC1A +:10A640007C36B03715E4AFDA7417D14FCB8302E50F +:10A650004B811D1EA1B2CF45C2E6A0CFC1F37FF74B +:10A66000F1EF621DC7B3194F42213F9FB5AAEBFA24 +:10A67000B064C8938AF1F39AEA09B954C4FCFE6A3B +:10A68000A267BF66CFE879FDE99AFCEFD7F3336D97 +:10A69000349EBF88CB773FD83B681731A997A11F5D +:10A6A000FF83029EBF0FFC40F40DA384911F32A6CE +:10A6B00048A63C2DCE2FD912B77732034C205D83AC +:10A6C0007962F0FE13B027F07E824CD5D8EE076990 +:10A6D000DF15506FF52EF23609740E3EDCFD33287F +:10A6E0006761BE17F08D7F86B17E364B2A5BF8E737 +:10A6F000B13A5686798B15855ABCCDC182A41F35D7 +:10A700003F5DBF2F503C73DED7D4C261F8E9171705 +:10A71000EA79C2467DDCE56696F1B523855C1FD5F6 +:10A72000F7D6D6A15DBDD6C7C8AE5A8BBA13CB99A2 +:10A730000EBAD726D45DE9B2BAAF2253B519EEE707 +:10A74000F5CF4833DC7B9B1DCE3294731BF20DF5A5 +:10A75000F322230DDF0B969D6BF85ED434C1501E9F +:10A7600011BDC050BF04109C5C1EB5E93243FDD141 +:10A770001D5719CAE7ECF896A1FED8F862C3F7F3A3 +:10A780007E759DE1FBB8AEB586F2F9FB6F36D46FEE +:10A7900061D6F777766878057E2739D6ECAD6BA061 +:10A7A000DFD1901D8638FF755ABDEECC4965180F74 +:10A7B00069395E5146FE70FA0543FAC366B9984A94 +:10A7C0001E9BDF6F2EE4F2F383C7DE9EB412E91CFA +:10A7D000853CC8A50FBCAF6CC0396D2EE77909FA6E +:10A7E000EF6298EFE5EFDFA794549ACF822C07B37E +:10A7F0003A1F705DA162B9BFD02A845CB857940A31 +:10A800006F478689B7EDDA3CBE2ADE8E09C638105E +:10A81000EA93072DE07A42E32BD057BF453E047DF3 +:10A820005599461E06BFC7E16CF5890E07E8937F70 +:10A830002FCC1E9C1FFE41C3F3D7DCAD60FD6B78AF +:10A840007D5BA80CD725D5BED21385E67DA5AA656C +:10A8500028E716F8D284E4FB9AF76BF5F478764B88 +:10A86000FA67B4AFD4E208950D675F697F21E3F71B +:10A87000E0E2FA6627ADAB5D0DCA96FE9DD98E610A +:10A880004FE03D1831AF4479C366FF2EAAC96DDD94 +:10A890009F930ED692BFDFE21D49791F2DEA5AD24F +:10A8A000971D29FC5CD097BDB83ED37C371AFCB904 +:10A8B0008178804AE3415BB29B5A92FC7F6CA7DEB1 +:10A8C000CDEFD5FE1AFCE08F0ACFC2FF5718F783F1 +:10A8D0004F328EA793AA8DEC84936027A0FC6D93D2 +:10A8E00018ED7BC72A05C5CA2FEE58AFD987EB39BB +:10A8F000DECCFBDD663BE38AD0F584B736A0275774 +:10A9000025CE9FDBBF6D767EFFA6EC0F0751DFF6ED +:10A91000653BD86E80F660368FCFE978F9B2F228C1 +:10A92000A76890FF93533484FF738958DE85F7B688 +:10A930009E38C5E3220A1E450CE03DE47CFDD63E70 +:10A940003127B606F55489D484F9EB225332102FFF +:10A950006B0E8B2C2EA01C33E6E7DB59D35D188FD2 +:10A960006301FE3EC65CCD6827654C31EAB14CD52B +:10A97000A8C7FC33B24C7ACDA8C7721B8C7A2C2F97 +:10A9800062D46305CB2698F49A518F8D88D699F4BA +:10A990009A518F8DDA749549AF19F5D8393B8C7A75 +:10A9A0006C6CDCA8C7CEFBD55A935E33EAB1F3F7E3 +:10A9B000AF377CAF48B41BBE4F3C7CBBA15CD573AA +:10A9C000AFA1FEE4A3BB0DDFA7F6FEC6F01D10FD90 +:10A9D0001C9E67C07B6871112F7CF721E377A63A34 +:10A9E000301F7F059ECF8475BCA8EF61437FAC8389 +:10A9F0009F5B88C17FB85EEFB008DD030072EC504A +:10AA000001B45B1D17420986FAE9C1B771DF6679A7 +:10AA100050243F6E0D065B911EEEF7C5911EAEDD14 +:10AA2000613CFFB03C6E2CC7807E148C2B00FD2057 +:10AA30007DAD30FD6E04D883446F2B14A909ED4A17 +:10AA4000337DBDA3D3574C7D0ECF73E8F3D5E767B5 +:10AA5000D7CF9F6AF4A76AF4C7C44708EE1505224A +:10AA6000FDFE8E3E5F15FEE3DFDF77E03C3ED92F33 +:10AA7000303FC0710D8B1D2AB098CFEAFDDB1DC899 +:10AA80009FE67999E761B653DB8A8CFB489788DEAD +:10AA900010F1DD0B22E9239A02F2D903FCBCDEDAC5 +:10AAA00027443A17837C88FE82186B20BCAC01BC1B +:10AAB000E0BDE1BADD7A426B77E2A7229D6F3E13DB +:10AAC0003F2A1A3E9C41233FBA9534133D19F1EBBE +:10AAD0002933F2E78AD72E75A0FC3A04F816A6307F +:10AAE000E60B19F97585B892F6F9743C2BF01F8EB8 +:10AAF0002B81A98BF35E0DF34E2883F1BBEC91ED16 +:10AB00001B0A2CE8E64CF87DB0C8B8DFAEEFCFD515 +:10AB100002761C1679A53AFEBAB3D53FA27C4CE565 +:10AB20000F1F283A6B7FF840D1D7EB0F3F5334A467 +:10AB30003FDC370BFD29274B0FB55BC4FD242627CF +:10AB4000305E6B6FE271BF81F8DDD71EE7790BE1F4 +:10AB50009464AE27DD921EE7091D8DA07D92716E73 +:10AB600008F3A2861BE7F870B01EFB70283D06F6BE +:10AB7000C5313C4FA866E4D7DB9099A45019DDEFAE +:10AB80008C20F03CA4FF46F806E5EB966669F9C711 +:10AB9000CA90F9C75768FBBB1706D57F221CD0DFC8 +:10ABA00069ECAFFF3EB6CA6CEA27FD0CFDC4EAB8FB +:10ABB000BD16B3F93A5AB8BD46FB4C5F431CC35FA0 +:10ABC0008C712D2FC77F8B83C76DCF36CE565C3CE3 +:10ABD00028BE545C3C447CE91FAFE6F273AB21B065 +:10ABE0000E2A52D3B77E0E532F6FCE34FACB1B26CC +:10ABF00070B8CE2DE6EB1ED1CEE3D668653DEF12E0 +:10AC0000F316DD13A03C939F53D2CFB5EAFDD414C5 +:10AC1000FBA8FEA7C1BA1AC4C786127EFFCE864C17 +:10AC2000E33D3C278A6A6B705E53B4FE6B8A193F22 +:10AC30003731523BB7698A177CAED5FFBCA88E9ED0 +:10AC4000788E16FD1287285AE2735AB14DBBEF86F3 +:10AC5000D173BA7E7EEE4E7EBECE7CEF02F0C98B03 +:10AC6000F8FB506FDE66277F0FF4119D9F5B5AC083 +:10AC7000CF219AEF538894C98750BC7EC2CA2DEF6A +:10AC8000E51994E770EC26CABF7B662A9385BC332E +:10AC9000E73D7CBBB85F5F85BEE439BAC6E261E4DC +:10ACA0006B2DD1CED1F5A6713DD697E78AEFB6F0E0 +:10ACB000776FD5E8F236CDAFC5FD69DC27C7FBBDA0 +:10ACC000ADF6CB6F2DE6FBC3C33D577DBB231241D1 +:10ACD000BE359FAB4E759EBAD7D1DB968BF08E6595 +:10ACE00021B4DF7317C8DDB9502FAD5EA1F38F1B00 +:10ACF0004A58FA14FC5E610BE1B98ECCB9F2063BFE +:10AD000094334B599600E5DED81C1AFFB606268B05 +:10AD100000D77DC5FC3E8485B77C44E36557C3D42A +:10AD2000143A773E1DFDB35803A37B0BCDF3BC5BF8 +:10AD3000A35F571BBF2727A3D43A0FFFEE62DDBFE7 +:10AD40000EDF85F45B5BCAF6F1F3B3FC9C025E4B4D +:10AD50004FF99BA134DA17BC12D68DEF9FF7D0FACA +:10AD6000DD149CF6536CA7F39B43CB53309F27BF56 +:10AD7000AFF8ECCE93A72DB08637A1ADF735D9E16A +:10AD8000FB918ED2CA3AF8EF977E71FAB43849FB3C +:10AD9000694705DB4722A8FFDCA0FF047C2A329D1F +:10ADA000A3652E81CEC3BA9426A22BF794901F7F61 +:10ADB000178D2DB131BCC7659AD65E6D6002FE9EBF +:10ADC00004E502929C36FDBE841A6A6D86F697E011 +:10ADD000BE5908F3BE43CBB0BF7A6F9A8CF14D7762 +:10ADE00069532DAED7E30B791FB7A7382FA19FB3B7 +:10ADF0001FB87F6ACDB3867B051CCB9F35DC2BC08B +:10AE0000963FFB55EE1578AD78F9B3FF13F70AE8D6 +:10AE1000F20DD4901DEDFAA322BF47EFC347AFB6A2 +:10AE2000E33A6CA8655D88F7D8678067D7009EED28 +:10AE300075E1C777A25DB2363DC47F4F24F61D840D +:10AE4000F3350F93B1BD9E6F28B032D2D7731B0478 +:10AE5000B21F98D4B71ACBF31FF1C8E83F7CF8E8CB +:10AE60004B4531A0CF576F3DE9C3FCD4D7A53E1F5A +:10AE7000C2F5EE2DCFFBF0FEAE576F11290F85CE38 +:10AE80007D27E5890923387D2D1A113E85F4B5709B +:10AE9000DD3F2725DB672C9A4DFA7E791C204EB6C4 +:10AEA0007B7FE531FCAEE8AA2EBFA1ACEBF9554E95 +:10AEB000EB73F35347703E5C7E7FA7A340C1F12341 +:10AEC0006923A0FEBBDA39A077F7F9C88ED7E1591C +:10AED0007C7F8503EDE1D71F71B204C5057BECCC07 +:10AEE000CBF507E65D44F8D083E03CF4970207F227 +:10AEF000D95281F53989B9D921C4F7DF34FFCF3C64 +:10AF00008FA5AFCA0E5CDFA5B5AC0FCF9D2DBE518E +:10AF1000D8F003A8BF38E225BFDF3C4FB3BEB91657 +:10AF2000EFB311ACEE816B3AF467E86709F483F68E +:10AF3000E7D20EE3F713876F38B413C6DDB7DF41EE +:10AF4000F6E2B56788F78F1FA1E9A5496CF2E951D0 +:10AF5000A4FF32C629A9ED0E5D1FBDBB8E5192CA5A +:10AF60007FE1EFFBC2F3FD75323D4F152BB41E2B75 +:10AF7000F6771FA2DF16967A26A1BC9BF944A3E7B9 +:10AF80005B6C20AF685267CB819D5455CF574D50B5 +:10AF90007C6F8A76FFCBB5DAF98FAAA3E67CD5EE73 +:10AFA000C7FF8C761BCCFF6CEEED5930CC7B7B4E13 +:10AFB0001C9EE6413A993D42F37F26035EC4AF8E64 +:10AFC0009754ED56A5F8DD169D9F4E697A66C99E89 +:10AFD000D91BF261FC9647DF29C6F8718C71FAAE75 +:10AFE000FA29FFFD9F2A6F0ED19B0BE9330F9B9827 +:10AFF000EE7988B11759127D5FFB8887E82408F63F +:10B0000090730ABEE1F45A85F776227DBFC0DBBBA0 +:10B0100034FF36F2C8ADBCFE9F1DB233487C19B474 +:10B02000D13311B44DB1B867CB7CBF5887B1FC8127 +:10B03000BDB718E5CAB5263FF403C13A3FAD71C4A8 +:10B0400048C2C712459D8E79004B5978038FDFF2B5 +:10B050007B7BDE953A0EFD10F97D8FC06280A7558F +:10B060007F7CE0DF518E5DF7BB3BD3518EBD2775F2 +:10B07000E4E0782BF7B6A5A31E78578AA563FBF703 +:10B08000E25C9E0DD29723044D0EABE902C8E4D5D5 +:10B09000446AF0FF257D1B6E8671FE1BF08C7CBF21 +:10B0A0007ADFA7543EA4BAFA5810FBED9D8E702C9F +:10B0B0005FE46D6A0EA17F69E4CFEB7E79678E4213 +:10B0C000791EB1020D7F05D86EF51E3BE5F9A21F72 +:10B0D0008FC3AC617D343F73FB355D6F3A505ECBFF +:10B0E00036D65778E1E0EF60213990DFD6ECDBF21D +:10B0F00091988ECFF75EC1DF835A63B24F9769F2A2 +:10B10000DB4CFF5D26BA07FC507C210670F19F6383 +:10B11000E272BCE5D7778F7F03E07B7FCF53E9F8FE +:10B120007B133AFDEBF73C9FE86A5CE818E21EA14E +:10B130000F343EE9D70F9A7E52F60360B9507C84F3 +:10B140003F57DA13E917C27C5776DA4348F32B1FCF +:10B1500010552FDA552F3BC91E59F9C049A2DB956E +:10B1600082DA27909E63E928C7F5F55AF1C0DFA679 +:10B17000A39C5E9127B299C08AD7FDFE135E1FE89B +:10B18000DC0DF5573CF8C6F41F6219E489CB62BDAB +:10B19000A675753B7ABD16EBD5F5C6748CCFB7FC9A +:10B1A000FA1FB41EEFFD4560B92583DB2FEBFC1BB6 +:10B1B000C5C1DE8785F167727CA1BE59D3252E7289 +:10B1C0006458AD5F62D6C395F49DF2C2CFB48E1DB4 +:10B1D0002318D78F7F7CE0DF1E063896BDE20CCDAA +:10B1E000C471FFED86740674F08ED4C4E9FE676DF9 +:10B1F00039A8BF97D96339323DF9FB65BBBE47F427 +:10B2000078ED5FBF97A3ED37E4D9481EC4F2709E76 +:10B210004B7F3A8FE6790D8B103D2EFB19BF67F1FE +:10B2200013F0B3ADFC84A90AE71B27BB7EFCCD015C +:10B23000949B78670BC0E160FCBEAEE778FEBB93E1 +:10B240005D95916CE77A146ECFC558FC35B43BD749 +:10B25000805A46B9F6FF003503B31E008000000097 +:10B260001F8B080000000000000BE5BD0B7C54C5DF +:10B27000F5383E77EFBE425E4B5E8457B8791224B4 +:10B28000C485249040D485400C0AB8404494884B2F +:10B29000C010202101AD60A5CD860002C53628551D +:10B2A00014B40B8245451B31086AC08D2886EA1705 +:10B2B000438D165BA18B2008045810EAFA2DCAEFC3 +:10B2C0009C33F766EFDD243C5ABF9F4FFF9F7FFA08 +:10B2D000A9C3B93377EECC79CF9999B3E2814BF911 +:10B2E000BF8C62ECE1787DA5C9C25805D33B3D66B1 +:10B2F000867FC215814A493F189FC35F0263790761 +:10B300004675F3A4316662178CF767327611EA9FAF +:10B31000B36ADE6357E2193BB1D1D445B819CA18F4 +:10B32000565A07EDAFE0DF6DFEB25482CEA3A9F905 +:10B330005F18F43F97BE04FD6C3991BF0EFA65B1FA +:10B34000220B8FE5F073303E4B71486578367CAF49 +:10B35000E5A8B107D43BA3742C19C7DBFC0DC1CC05 +:10B360001A2D617BA5FF8A9D26E656C603FFAFD83E +:10B37000F48D91613F3AE6ED35AC7D3D6395E9880A +:10B38000870A162EAD84F284D19BFF2E7E07BEBBAA +:10B3900019BE53B206DAA7AAFAAB3FF937968EED7B +:10B3A0008DFEE7F1F8DFC58C65412116853B42181B +:10B3B0009B8938CC693FFF855F553FFE81AABF0C52 +:10B3C0002934EA7830FC63081B7245F4BFCFD603FA +:10B3D00092BAB77FFFFB2AE7E31F18F06D27E1B1B0 +:10B3E000CCE07A09F154F6A5C9EA043C96BD76C9C9 +:10B3F000A88B422A326F7257C64E6FDDF3C57D307F +:10B400009FD37586A831F4555B9810E3C77BE9B6E6 +:10B410006FF2D7417B03E03D08E839B7FE7BA30E0E +:10B42000DAC7E631AF09C67F3ACACED800C49BE17D +:10B430006B8F0A6F79F0DC1342E3E8A98BC5D2DD8C +:10B44000934139378A59DDF0FEDC16D12A21BE98A6 +:10B45000779925A4FDFB15754703E8A2AD67CC6B72 +:10B46000B4E377EB7F735E0C53E35DFFB5478577FD +:10B4700005CF81789D8A78EDEFC7EB2596160E9F54 +:10B4800061A75E99D3C791D61EBF0A5ECF563164BD +:10B4900072FFF33E12E159DA091FEA06750D72C90F +:10B4A000D8174C85C7D9AF9E21FEFD67779189C01B +:10B4B000377337FDB00CF90AD0EA3501FFCE759D20 +:10B4C0002778A9CDEC650437160AE91DCD5B8BCF33 +:10B4D000C0FA78446AB49FFE86C5CC190AFD7A7713 +:10B4E00089AE8D30B47392372C02E6B734883D6054 +:10B4F00087F29C4586BB2A307B601A8CF39C33DD37 +:10B50000E2C4F782D8E43AA0CF39BB37AC6B887F6E +:10B51000DE471AC43009DA7B5CACA02EA43D1F3292 +:10B520005643DFF7B0CEEAAB491E4689975FF7C0B6 +:10B53000F72E38F5CC04DFF3547FFFBA07CA637ADD +:10B54000B305F134A3FA9E30A683EF3724DE351914 +:10B55000DA3DB80FF047D3B319BB037EA7F3A9B305 +:10B560006F99F3E95C989F189AB9F75D78BF04105A +:10B570002B02BFCE58A5C5CF6C660F77C7A3DC1AC8 +:10B58000FC7C42FF7519DDF0DE4C4748E54AF86E59 +:10B59000E97A6DFDEC86D3C45FB303F8CB81FCD5AB +:10B5A000BD3D7FBDA2C8ED403610F96B9418A24393 +:10B5B0007E3ED724BA4CF0CE852506B60CE00B5B58 +:10B5C0000517837E2E3440238477729839A3896FC0 +:10B5D000153E57F0D68AFCD7B73D3EDBEAB71F1AB7 +:10B5E000FC1834297BEBEFE9EBA06C7DEBCB947777 +:10B5F00011DEF1D7B8BFB3F6EDF376FF3095C6B5DF +:10B60000DBC4705CE7767F14F718C2EF98ACC8B75C +:10B61000E7169B6C0CF5DDEE505732D6F7067E0030 +:10B62000BAD7ECFA3E1DF53D634B888E9F4B462AF8 +:10B630002F34FCEBB080F3683049388F8ADD80040A +:10B6400078BFE29D2017C3F7777D3FD811F2F3CD85 +:10B6500067AE9139883F43D9E46DC8BF5D990DE766 +:10B6600053F16ECE8BD5F0FDF2FA46E374A8CF7B92 +:10B67000EFC774D447E7B6351A515F9D35785E60E1 +:10B6800056E4DFFB6B0D80E7B3A1D0590FC61EDD7A +:10B69000F0BCDD19D2115E381ECE011E705E80979F +:10B6A00052575AE7F8F8FEBF161FE7A7E2F7CB1A82 +:10B6B0008630315E8D17C1C69F87BACC02CD9F3FC1 +:10B6C000DFFD7D3A0BB9F67CA3E38D24EFFF7F9974 +:10B6D0006F46FC7F2B7D39BFBF2B4934BE40BE6F08 +:10B6E000CFD73B1E21F8F5502B8DF73AE57DE27F51 +:10B6F000EDFCFF6FE83DEFBF76BED7A2F73E99DEC7 +:10B70000A11613EAAD5D3FC6B11B9877EDFF47E781 +:10B71000DDE6FFE8ACE64C18DFDF98EBEEE10279FE +:10B72000251DFA23BBE2B5EB8E71B25F51C3BE1E7D +:10B73000390DBEEB047F02FDFD9A90AFF52D003769 +:10B74000839F80FE0543E704F0D05C38D0B512ED4E +:10B75000B6BE925900367C319DE0C9C53FE833A1A1 +:10B76000FDDDE0E761FBFDD59E19D550BFBFAB4EB7 +:10B77000AA01F82EDBC4E47A802D3D440BAE636A47 +:10B780006C19664935BEBBB2B5EB91FB02D615F715 +:10B790004CD6D64F621BA3F5D0DFA4520373C194DD +:10B7A000EE0E68BF2EDE42F8BA87552EB584DC381F +:10B7B0009E4ECB78AA61839A24C48B4DB46E66EDFD +:10B7C000F1C6106F8897D80CB6D28A5FF1E85B009B +:10B7D00036C9FE15FC913CDE1D657E09F16462F3FD +:10B7E000D923D0DF25495F89ED4D0CD68D7CDCB4A3 +:10B7F000DE0CC41B93D79F26990477D91E628867F5 +:10B800007CDE2756F33ECD3B10CF378ED7C5C94FD0 +:10B81000235E0B43AD2EE40BDB8BD17AF85E0DE09B +:10B820005910FCF854F0148877F43969FD27E35B6C +:10B8300029D398772AFA9D612CCCBA12FA0F33F7E4 +:10B84000627A3E0FAFA93B161686EB357104AB5BEF +:10B8500009EB3596AD6F6D9B5702D5BB1F83F76A19 +:10B86000E6C1FB88D75E4CB213FF1759707D2330B9 +:10B8700007BB12ECF73F3FCD06FF339E4AE2DB4F9A +:10B8800037717FF352EE9BCB0682283198B3733029 +:10B89000FAB9F29FD35384EF894C67C5F52FB3D91A +:10B8A00024CB60EC97D1BA263C5BA759FF76B575DF +:10B8B000D1E02DB220420347DB7B68DA779B9CA066 +:10B8C000A9EFEEB84953DFB3749006EE5D3954D357 +:10B8D000BECFC2111A38DE7987A67DE2F2091A3886 +:10B8E000B9F63E4DFBBE6B8B35F5FD5CB335F5FD12 +:10B8F000B7CCD7C003EA7EA9697FF3CEC59AFA8197 +:10B90000EE959AFA8CA627357056F3739AF6430E85 +:10B910006ED4D4E7785ED1D40FFB769B06BEC5FB10 +:10B920008EA6FD6DBEF735F070F6B1A67D9EF9339B +:10B930000D3CCAF2774DFBDB638F06C43B2CCE87F0 +:10B9400032518D013F819C8D964E6BDA83C75C84AA +:10B950007C6390F9E1CED4EF34F563ADFFD2F467A8 +:10B960006495400464AB5A2ABBB03A2A43583395D5 +:10B97000BF1EE0B027A05CBCE05C864CB53FE7FB97 +:10B9800038B4239FE63EE444BEBB14CB2CE24018FF +:10B990000FF3EA91AF75C1977B395471A3309FC8FB +:10B9A000DC19C0873E814A8B2F98B923810F7D41D6 +:10B9B0005446F822E979A4AF2B9551BE9EF43CDAA7 +:10B9C000D79DCA185F2295DD7CF154C6FAFA53D987 +:10B9D000DDD78FCA1EBE0C7AAFA76F2095BD7CC382 +:10B9E000E8796F5F0E9571BE3C7ADEC7379C4AC915 +:10B9F000772795F1BED15426F82652BB44DF782A2A +:10BA0000937C53E879B2EF5E2A537CD3A9ECEB9B8D +:10BA10004665AA6F0E95FD7CB3A8BCC9F710BDD7CB +:10BA2000DF378FCA34DF63F47C80EF512AD37D3552 +:10BA300054DEECABA6D2EAFB0DB51BE85B41E5207A +:10BA4000DF53F43CC3B79ACA4CDF3A7A9EE57B9643 +:10BA5000CAC1BE17A91CE2DB4065B6EF552A737C4C +:10BA60002F5339D4F726BD37CCF70695B9BE77E901 +:10BA7000F92DBEB7A9BCD5B7879EDFE66BA4D2E689 +:10BA8000FB989E0FF7EDA37284EF337A9EE73B405D +:10BA9000E548DFDFE9F928DF9754E6FB8E5279BBF2 +:10BAA000EF089505BED3548EF69DA4F20EDF77F411 +:10BAB000DE9DBEF3548EF1FD8B9E8FF5FD40655BE0 +:10BAC0003C21D710A017DBF49FEE0AC67942223A38 +:10BAD0008CB7B5BD2FEBE3D5C12F308C7B8CAB146D +:10BAE000689DFE4CF0D90F484FE69824849762D3A6 +:10BAF000EEFC3B9618C6EEC77F488C35E69868FD8D +:10BB0000BEFF57FCBD65C38F7EF510DAC779268668 +:10BB1000F63150FF2ADFFD347B4F34FA61CB0679D2 +:10BB2000CA30FEF244BCA708CB860481ECC59B72E8 +:10BB3000F94E828ECA3503B8FD2E9A971C4E71AA13 +:10BB4000A8EB9BD7FFA2DD8FF6B77F2189F7C34211 +:10BB5000BC71642FAEB39FEB6DB7D4FCEB3F605C60 +:10BB6000C756A36741B702ACE7F6DEF955A86B33B9 +:10BB70004CC939A2F28F18E7712E36596AA210CF3C +:10BB8000BFFE13B65FC898DD04E51F121C9F254059 +:10BB90003FDF07C5B9C038C25FE59009A13F6BFF21 +:10BBA000FFF83FEEFF34EAB5CEFAFF87CC476312C9 +:10BBB000EDE7701C4C6F4B473A8C58DC5D8C82F77C +:10BBC000A7AD122CC847D3970CCC47FE18C46C14F1 +:10BBD00027BD3F923D60EFC02FEB96A893FD0BC9A8 +:10BBE000780F8CE70CB81CE84F144B8CF8B2B841B6 +:10BBF0007039290E6D0B1B0BF6BB54E6DBE2E5D565 +:10BC0000C605D0AEBC3B8F9731178F9799E17F283F +:10BC100047736A37ECA570A37899E26397D0EF0574 +:10BC2000D699B3A57D3C7601C699771A2D6837CA97 +:10BC3000EB02E2B90171B3C0789925518EC75A99C8 +:10BC400095C7B9434AFE8ADF63619218756DBC28B7 +:10BC5000F1598949DD108FA3C4B4705CC75C684A90 +:10BC60000E67584A52376CE7005A344329E81D439F +:10BC7000F039E0D38974F55607BB36C2B88E803DE3 +:10BC8000913270408E21468C47FEAD375B2910D52E +:10BC9000C80FABD824925FEF59FCAF6518C79E154B +:10BCA000AFA775C0348CB9E3F8DEEEEA720AD42F80 +:10BCB000E1DDFB9A407157279B1F8B71DDC07D141E +:10BCC000FBD2E871D948A7E55D079990564EDB177E +:10BCD00049312AFA2CA921BC16C74672FAEC3490D5 +:10BCE0005F0BF4A946FACC72198EA9F17C895D36F6 +:10BCF000E27E4CF1F2F344AFD97E7A69DA95D73619 +:10BD0000125D814E9AE71595279438FAB1ABD12B85 +:10BD10003F805E183FBF072B1745927E285AEC4E96 +:10BD2000AE54F169E0BE44D28CA1E1769087821EC8 +:10BD30009C1E4C6F8D417A7EB72A8BE81548A782EE +:10BD40009FA6133DD8DF42D96618CFFD89EC810943 +:10BD5000F0FC0139FE7A7FCDE8028C974F4DE4EB81 +:10BD6000934F61FD6983F5E7812A33B3816AFEACA5 +:10BD7000CA42F0E755B104FFB54AA2F2CBAA542A51 +:10BD80008F1959699D4ABE80018C38BE192857D138 +:10BD9000582AEBC3876331EE5EF0D367593A52A954 +:10BDA0006F8E1FD51BD7178004157E261706932F7D +:10BDB000ADC01E83253F16F5C70AC1BA19E96A1F2F +:10BDC000A669CF5233FC30DA2F3DE727E08B8DC8D0 +:10BDD0007FF78E89D4B49FB4BCA7065E9428D1F8AF +:10BDE000C617246A9EDF57D45F034FF3C17A1E3E05 +:10BDF000952415E89CD0FFC54F0CC4CF172B877432 +:10BE00005BC061E2BB40FC1F333A298EE0DC68B2C4 +:10BE1000A2FEFB3688F3F7B79F8BAE1A5AF73A2982 +:10BE2000EE72C96C91709DF2C874671CD63F120CFB +:10BE30002EF940C497C8307EC05E3191FE9CBE563C +:10BE4000604E94112FA3F5F2C32F9B689E33D68AC0 +:10BE5000CC91417C1287ED1F8E96A8BFFB13A53AAB +:10BE6000E467EF66937523D44EF7C8EF0B83681F22 +:10BE7000A47CFE5F0FEB511E529AD371AD5514EFA7 +:10BE80008E463DD8BAC940FB5EE5E286921020D1CD +:10BE90009C27DE0CCB9148FC08BFA70E446FC0F96D +:10BEA000FBE7EBA2B8C8377DEC1B13419F9E2A71BC +:10BEB000A5D33A79118FC7B7C70B233DE5D4854980 +:10BEC0009B71BED31D432C696A7BC8F7FDA61BACD2 +:10BED00031D634E4FECCEEA8078EAD321460DC051A +:10BEE000F4FE38C4D3B1DA48DD4A5A546D23FE2A31 +:10BEF000D64B46F5778B5789366A0FFA7D3CDAEBDD +:10BF0000D5A2830D41B896FA772E171CB8EF94C4CA +:10BF1000B2BB21DF3E346F48379CC7D44EF619CFF1 +:10BF200082CC3854FB58B3778976177E2FD3A32F52 +:10BF30001CA01E3F8F03253996F79A8F747A23C869 +:10BF4000BA5242BD9A188EEBD4932D6037E01BB3E2 +:10BF50006A1AD32560BDB28776101D4AC7D5A5B829 +:10BF6000E1F901B3E313C4E3B7DDEB9E1E8671A2D2 +:10BF70008617E39C680717F2FDB5D9AFCCEAA3F6A4 +:10BF8000E7DBFB132C56978D853B4600BC38249687 +:10BF90008FF89DC2EAE4F8858BC627A1D2057C58AC +:10BFA000CAF8FEDB749D75EA679988FE500BD2458E +:10BFB000E9EFA881C7B9FE21CBB362877B24713F2B +:10BFC0006BBA8ECB1DDB2D109F02C1BE4852D9CB60 +:10BFD0000AB68AEC656C4F91E1BEDDD9C408592FD1 +:10BFE00070FB3707ED1FEE0B5B04928FB22D269787 +:10BFF0000BF82B3589CBE76CE36B4F0FC2E6F1955D +:10C0000046FCCEAC7A813D074D4F195C25CDB82F4B +:10C0100065D9B02482DE33585DC8A7B27E3783422B +:10C0200040BD3013FF09F5E56B04979BF8C54E76CC +:10C030006806C64D70FD8F7A5EA547DAE9F700BD48 +:10C04000FE200BD8D7AFD5DA177B70A819C7397B7C +:10C050000DF76BFDE311D915C05589C3B5771C8D5C +:10C0600057A0B848E0F767E2F870BC303EB7F5C6B5 +:10C07000C75362E5725A562BB85C1D8C4FC16B7862 +:10C080002E93D03ECFD924B8901F4745CD23FCCE68 +:10C0900006FC46225E9DF6B07B002E014672517C66 +:10C0A00085E3BF623DC73FD0F92F6ABBFB4D94D7F4 +:10C0B0008878FD06ECA713F7032BBF27BAEF05FA24 +:10C0C000A2FCCE7AC365C48DC8D3AC362C04F97EED +:10C0D000ED81BDB82CF866CD9B31B87E2D8A7027D6 +:10C0E000EB406F45B2E8270B6EF1F35FA0BD6E67C2 +:10C0F0009703F0E36476B243EDF0645ED58CFBDE2B +:10C10000EDE827C7C51EC47F017E1EDC24DA82D27B +:10C1100035EDE4F3084EC25BA9D34B7E4229CCB384 +:10C12000C6824F9DF9889707AD8CF4EE8D8E3770DF +:10C130009C4C2C22FEC4B81EFA21FFEE7803FD8F22 +:10C14000494957F73F02F548A0FFF195C1A65B8C1E +:10C150007EDF01BE2F7E51EFEE8DF27B312AC10AC8 +:10C160002DFC7A347A5037D4F38A1E2D91ED96D275 +:10C17000EF8368AF003EBEF6CD30A4BB42FF9968A6 +:10C1800027D2FC76E291E9D03F7CEF911D41D4FFAC +:10C1900099B160A7A0CFA2E73F0A632AFDF7781FF5 +:10C1A000C7FC24D4278A5D1337C45980BF147D7916 +:10C1B000AD7557A7F30A099857A8765EC538AF0C36 +:10C1C0007F7FD3E5797DBD9CCFE7E82A3EBF19ED9F +:10C1D000E6C5EDFE232F9AAC4EF20BDCD12887DFAB +:10C1E000BE21B21AA22FF71B2E99819F0662FC6610 +:10C1F00015D9F593D14CC2B84EA7F67BB589FC8210 +:10C2000059DBF97EEB29617837DAF8FFC01DF62893 +:10C21000CAF53691A11DF28FA7CD6E3F9BA4B6DB68 +:10C22000D789378CB3A23D9B0BA843BE9FDBD08D33 +:10C23000E1399755C3599D48FBF01ED263C04214A3 +:10C240009F063F5C136F3031ABD98C74EA24FEFA41 +:10C25000CFE4F353E7133EBC29887FE5FB155DDC93 +:10C26000866EE8D7BC21905F53FEF0F0B0E10CBFC2 +:10C27000C3E3663B92B89D7A07F51CCC4BB0555290 +:10C280005C0C7C1ACBEF705CEB797C98BDCFEA102C +:10C29000BF0853FC58C7E7214816563488C7E5CD78 +:10C2A00068D7427464D702F17042FE4EB9A823FFEA +:10C2B000B7CCC8FDE073023FFFF1916C1F3F4AE22B +:10C2C000EBCC4F92783CE11CFA81D0EFB95B4CAEDD +:10C2D0006A01DD563DAD93F5B92617FA337A7388B6 +:10C2E0005B4C47F4EACFB6C933E06B2A6B36203D8E +:10C2F000C765CFDB82F339DC8359C4AE546DC77D8B +:10C300008429A41918DB6FF8EA438C473AA1AD08D9 +:10C310006B8529D9277A63FBF508C3FC0F07D57D08 +:10C32000887196C3F17A86FB02CE5D26B2FF861134 +:10C330009EDE14A7ECC258CD408CC7EC598A7CB461 +:10C34000373632D502ED1FD077B18A5CFF8C3C8F37 +:10C35000E32D15F8FECD124F16D2E766B6C472DC97 +:10C360004C5B0BF55722AFC63F7A765CE10318535E +:10C37000D908F8C750C6192B9BF0A98101AF045FFB +:10C38000DEF4C88435B9B869220D403A972578F5AE +:10C39000B89FE215987723E0E1EE6CAFDE86F4B249 +:10C3A000B1BABB807FDDFB9880DF4111C0EFDEE3D7 +:10C3B0004E18857860A9120B87FABBF412C1BD0A2A +:10C3C000588428EF1B601CEBE03081E8A0334B065B +:10C3D0009CB7BD401884FBA2658BAF6F9C61C9D52B +:10C3E00034CE329D8EAF671FE5EBD929CE23A3C88B +:10C3F0004FCA6502F26145449D81D6D1202F38FE97 +:10C4000081D08D1A7F53F41E3EBE52185F0ECA456E +:10C4100012F1F17D9502F99315C68EE31A3D9295BE +:10C42000759745C2F673E05FC8D7731A7624E3F7B1 +:10C4300056099C0FE6287CB6552B97B9C9ECAA7C07 +:10C440009D93CCF93A2799F37572DBF7EAC8EECEE3 +:10C4500069F8E820AE2B3BEBBFDCC4DC84975D269B +:10C460008A1F083A6F12D1051109749882FE24B808 +:10C4700088439223B89F2EF36709FA1F8958F2B8B0 +:10C48000880E9427DAC3D2DA178D88B4C0F347E058 +:10C49000F8D039A0D99B029FABE22AA246EF50DC2C +:10C4A00053307A67E078845B83ACA88FA718EB6879 +:10C4B0005D1ED8CE50CBFD2CC372EE67D1BE1AC024 +:10C4C000A655DCCF9CD2CB3B80919EB3E40BF1AC64 +:10C4D000CD2F2EE19F86E7651ABFD88471048C7B2F +:10C4E000ADE5FEA05EF65F8B5769FD85294B54FED6 +:10C4F0002275EB2DC7F11A160553DCC584FE84CADC +:10C500000FF8876EBC13F5B033414FE72F0D2CD0D9 +:10C510009FB0331ECFE4CFF5B29F383AD9A0D97F70 +:10C52000738E60A9888722D44389A86AECCB319E98 +:10C53000778185D662DC6C94B888E27F45D5FC5C57 +:10C540005A60FCEF42E587CF637BACC7E70BBAFCD0 +:10C550001487FB9BB02CB50BB782BFD1E5F0250744 +:10C56000CA07282AC3508C03EEFF06614117CE8408 +:10C570006CFCBEFB79ECDF69345B506F3D131C46ED +:10C58000FD2C5C28507C788985CBDBA1AF4237A29B +:10C590009E52E2BDCB8667ACC5734B359B1B27987B +:10C5A0007BA37A60746E8939F7FEC506F329BC0C4B +:10C5B0007243F047136CE1C0E71F7AA79A014FCF8F +:10C5C00026374DD0839C9CFBBDF705845F4D3EC054 +:10C5D000E127BC7141086FFE9CC3D54A7F9F4FC0C5 +:10C5E000FECE3DCBE1E550EF84EF17A17EC3790F7E +:10C5F0001568DDFF8AEC7F2BF19E22DDFBBC1CC1A0 +:10C60000DC683FAFD5AE3ED9FE0AFA3B62E8B150D6 +:10C61000F42FDEEE6B7B05EDF78E44FB53C948AF7C +:10C6200016574C34C6B174AC19E90276CCD6D1BEDB +:10C63000F42B493C4EF3568A9DDE57F005FDACFFC6 +:10C6400077FA1999C2C7A5EA67F3BFD34F78DF76A7 +:10C65000E3793D39FAC6FB9917D08FE2B781032CF5 +:10C66000A19EF2A6DAF6E1F8E6FCDA36A21EF5CFD4 +:10C670007E91F8F4BBCA1D2968F7BFDB6A8A44FBC8 +:10C6800037E7F5B7E34A308E20FB45A71BBF344A96 +:10C69000F0FE5C9FC86CA0A72B7C029573EB1B8DF2 +:10C6A000F96978AEB6D198A71A57993C4EE074FD57 +:10C6B00004951FB33F5927EBCDD554CE79FDA41E69 +:10C6C000E9394757771CCF1FB3A13CEE1538BF1D82 +:10C6D000B2DE3D8CE70D3A8803B4C8FAB9777FDB48 +:10C6E0006788B7B7509F030CE6CAD111BE7AA5F090 +:10C6F000711475E17A3EABC55AF219ADFBD27522C1 +:10C7000094830F561A8BE1F9C1C41187105FEDE3D2 +:10C71000905E1E876CE071C8A288E687C198B16EF2 +:10C720002F5D7CD20CEBB83B9F91E503450FF44B9A +:10C7300081499197E0892373799C0BE1FF4D363C49 +:10C7400085E7089BBA34FFE233B40F2B42D94690F9 +:10C75000B3FB8784C66D83714C77860B603BD970C1 +:10C760005368CA3468D79A30BC5B0AE92746FE6131 +:10C770006B82FD02CED7131FAC036784398C3C9EBD +:10C78000E5F8B348F12C477AB0C3D501BEBC323EC0 +:10C79000BBA5F0FD9D261D8C73108E839FEF85BF7A +:10C7A000B86D186F5ADC4740BE53BE3F2671788C77 +:10C7B000FAFB6312ED624AB4BA7D38C3F6D73B0E7A +:10C7C00096C2C71193C2E965CF05FE52E9FD092360 +:10C7D000833570E198486653AFEF0A7B6AE0C9453C +:10C7E000899AF6F7CDE8AFA91F6B6ACEACBC017F82 +:10C7F0005F0C4B0DA7F57F165F871C6AB8F4C51454 +:10C80000F46337895601E6356BD7E62F8651EF1270 +:10C81000C5B94E3589648FC0BD35AAF74FCEB06615 +:10C820003A77ACEFBA84ECDF9C587EBE7B964BBB6C +:10C83000FFA1C4E53BDA37417B5686E7623ADA3737 +:10C84000F1C7E3AFBA7F929D22AF8707B1417C3D2C +:10C85000DCBA1766CAF2763612BD6AF6895664D516 +:10C860009ADE0213609CB7D79B5C4130EE336F1F9A +:10C87000314AAAFD930A5F35062DE0BD23463C4FA1 +:10C8800075305922FACD6D386F64C017B737CC2395 +:10C89000B96E6E744445A3FD027F757B26F2575D29 +:10C8A00026DABF269DC58EFB6173968FA63873B8B6 +:10C8B0006F0A9565B5A3A9DF72DF4482E7FA8209A2 +:10C8C000FE546CAE3F80FD3C136E417B5EAE776ED6 +:10C8D00045BA944BC119B85F35B7FEC0C55FA21DFC +:10C8E000B5F07B1D63C5BF6462FDD83E165D4D5734 +:10C8F0001C6F10F5D33CE2EF9968970A705D00CF8A +:10C90000CBB6E53850EE87D7845A50EE453C4FD62B +:10C91000019FCE48E1FE9EC1C3C73BCA379EFA5372 +:10C92000EA67A72450BD021BA237E9517F28F330E4 +:10C9300080C1C7F20E5F7F2A2BEAC7EBF15CFC9F38 +:10C94000535F8C423C41FB102C93460E233DF35D1C +:10C95000E59070D681DE524A93AC87A7A01E86FE72 +:10C96000EE4DB555A11C8E5BE4D19B518F86982D61 +:10C97000B8FF312E7BA054A29A8FF8FEBDB892006A +:10C980005FC56B40BB3D054AB5DE7EA013FBB234EC +:10C9900045D1DBD54467C50EB12D4F325C874DE5DF +:10C9A00067B5DAE46ABE2CD7CAFBCD02F7079CDB79 +:10C9B000795C7F7EAA632DEA91E6E16CF236D2A71C +:10C9C000CD71E3437FBEF187E99B89CE611649872C +:10C9D000FB0A4AFDF36DF3E0F27DAD79AC94DB7FA9 +:10C9E0002AB285C8179FDE765BB30DFA6D7C2C23C7 +:10C9F0004354D9A9D753F8F94766F15E267DB13B78 +:10CA000058423D3016F71E32FD7E3F9E87C4B84621 +:10CA1000C56ED3463C0F561106EB7CF8FEF8FE8E31 +:10CA2000D7917E8DEFE55CC47B34365C98819CDBCE +:10CA30001A865CC473F63633681B2BFA41B63F91F5 +:10CA4000BEED64BCD7D2674923E744A13FF11D0C7A +:10CA500009ED2DD8FDCC160EDB115F8EE55CFE1CBA +:10CA6000B21C4E93F9B75896C3697A2E870FAC095A +:10CA7000B760BCB378913000CFCB3129D48A2AC0BB +:10CA8000807C9981FCC9F9B2CCD75596E778B91F5B +:10CA9000CEFF81F239D71749ED1439FD53AAE310BF +:10CAA000B72BCD990B615C77805CA3DE732CEE9E77 +:10CAB0008972E2E713A305F909F824B644C50735DE +:10CAC0008D3FE8914F0CB902F18909CA3C151FD975 +:10CAD000DBFC134B7E0CFA554BE2752B99BFFEEB3A +:10CAE00014659FFCFAF8FD53B97D7108F81114FF25 +:10CAF0000963185FBB1025519C74FE0A1824A060BE +:10CB0000BEC19D8C7198F9F382280E56D252B92C71 +:10CB1000546A4FAF7B7DE9B4BF3CD19744E5C14433 +:10CB20008717E5659A6F928CC7F4EBDA9FCBB2F169 +:10CB3000B89BC165B26E88C7B89B43A4FDB8DECC74 +:10CB4000F214D929653F8EC7DD309E87F1BDC0FD47 +:10CB5000358CC3E17ADA14A5D3EC13B68BC70DD7A5 +:10CB6000EEA79535FE65B00EEA4FC5DB282EF74DD2 +:10CB70001F47505F98C7EC09AED70DEA7D36198F75 +:10CB8000757A7732DAD1BA4A8E9FBA556201ED379B +:10CB900031163C5E755EF75A7C3CDB9748F851ECE9 +:10CBA0008BA2B77754D1A1CF36FD7D2DBB532EF389 +:10CBB0007B39F2BBB5BD9D51F835909F15FD6C8852 +:10CBC0006E213D7407BC82FE83A2AF0BF286E5A204 +:10CBD0009D1FF67262FD3B30FFD854470EE2E5B66A +:10CBE000577B67AE03F80EBD4B6F09B91E7DF88306 +:10CBF00081F4E1A2F18CF421946A7D68E8C40FBF4E +:10CC0000B5EF8DF1779ADC1EFC58EE1F82BE56F709 +:10CC1000373F75C4F8BED074525F6E277FAE717710 +:10CC2000A6C727F5BD313D9E278FFF5A7A7C565FF8 +:10CC3000AEC703F5366863D2DBE776F5A338D96172 +:10CC4000067A1EED5943B0B4395E75CEBD4BB84B74 +:10CC5000ADD77BF79F3E0BE97A1D7A7D36B6FB7721 +:10CC6000F57AFEF837C8AF823FFB5DB7C2FAE3370B +:10CC7000B0BE43F85358DFC5B79787403908E47B07 +:10CC8000588FD41F80F1353DDD87E20E2007C4F7B1 +:10CC9000E5C0F728078ABCCCAD1F188EFB06EC1345 +:10CCA00091A1FE0F948382BC57F518A7423D8EF8E0 +:10CCB000DA03328F7A26D04EFCD8D7F12CF28F22AD +:10CCC0000F8A1C5C9B8FDE36E0BAD450769EEB79DF +:10CCD00028D57ABE337FE6851BE4FF55D7C93F6F61 +:10CCE000FCFCFCF3C675F2CFB6FF847F9246BE4BC8 +:10CCF000FC83FA13D76F777E6C0D5FC0F987CE2562 +:10CD0000023F6462DCB969706F2BC669EEBCC2FD7C +:10CD10007AD0E9E4D707FAD55364FDF7801C2738A9 +:10CD2000986AFFBC2F9757F2DB8727060F447B7565 +:10CD3000BDFEDE94A84A6683E70F40A9D61326A459 +:10CD40005B07FEFADF6E90BE4DD749DFD37DFF63F0 +:10CD50003FEF52DFEBF0F3926CE68988CFEFDC7A9D +:10CD60008678BAD67AC0B096E3B9CD5F77EB15BBBB +:10CD700019897613F8E39FFF097F8CCDABBB68065A +:10CD8000BA466D3116EAA1FD243C6B41F10CD31A71 +:10CD90005B12EA1BA6EC0B50BCE35351869DE69652 +:10CDA00091308E3B9F62FE7D03A81F951BDE161FF0 +:10CDB0001198BF7DE41643CB2A8A3FF0F32ACCE1D9 +:10CDC000D1F37D3219CE043854056707C0EB79FBE7 +:10CDD00030BD87F1731FF27359FF8CB3F07D01FFF3 +:10CDE0007E9E37BF2BFA7FF58205F717EECB3D67A6 +:10CDF000C478CED83CCFDE9ED02E654B7861483FBC +:10CE0000785E2FD07807A7765BE34CA2235B363C95 +:10CE10006F5896CDF74D4C758DF9B60EF87070AA17 +:10CE2000D64EE19F3E86E263F467AA13983193F7EA +:10CE300093107F7DEF23FDE8FD047ADF6D8ABAFE53 +:10CE4000F7EFC9653657077C345269877161A57F52 +:10CE5000A0C9C43AC1D651DC664C2A9797669DAEEC +:10CE60009C019E0A53FBAFC1B8D728C6F96252EAAB +:10CE70004D854E1E4762B680F95E6DBC433B98AF50 +:10CE8000A47DDF7D357CD95215B957DE97E95FAABD +:10CE9000E59370BDFD83EF601CE1518205FDD4B9BF +:10CEA000F6A0552C1CE92EF335CB2AB4E5C2FC8242 +:10CEB00098268ED7C6D76C70E1C834F9DE3ED567A8 +:10CEC000AF41FADB756DED399F37086DEFA7EA19B1 +:10CED0007E82DEAF4C1DB206E37E400FAA2738E902 +:10CEE0002A7C5E1700E706C805E330C925EA65C05D +:10CEF0004F7207FBB74FC8F83D23F0F34DCD23B871 +:10CF00003FD79CC0CBADA9DC7F5B23E371BDDCBE0A +:10CF1000B98B0A0FBDFC74863F37AE0754F3263C2D +:10CF2000DD1BA5CC7B52E118985773041B20009F92 +:10CF3000BC943A61CD92DEFEF7B7A44E223EF1F7E3 +:10CF400057D88276FC5E194F5B53EF6EC17A3C7204 +:10CF500082F2569ECDF75F4DF5073A94B705EDF98D +:10CF6000C789F915CA8991F03DC166C8E4FD2474EA +:10CF7000809F5FB57FDF16F03E3344DDC8FB327D16 +:10CF8000C604D0AF20807E2303E0222DECF783A1DE +:10CF900067F09F8A77AE5E1A83F1B32D02DDB1028E +:10CFA000FD6C14E079E396070A43703D2A4A869E99 +:10CFB000D0F6C32DD35ACCA0BFC6A3FE227D5C4CB5 +:10CFC000FA7A22CA39C1D30B6D3723DF542E8D85EF +:10CFD000F61F6F99B106EFBDDEB764B50191FEE9AA +:10CFE0009692357AE8F7DECC3FEDC5FEF4D5A52D57 +:10CFF0006384ABF0696DC03CD607C0CE80F66BAEE3 +:10D00000A1CF9704BCBF28A07E5500BC36005EAE01 +:10D010007D7FDA0CBE7F390DE88788BB96BC7C9398 +:10D02000DAE617B4D92F01EDD9C75A7EBFB386C34C +:10D0300067531F295C1EA282B72C2854F3AF41B658 +:10D040001753A2ECB68EF8F75067FC931A68D79C7A +:10D050009A73898719D3D8DF3DA2166E1495F12EE5 +:10D060006D79384DB51FC89614E23E51E7FB158B1C +:10D070000B71BFE2CEDF29F58B0B6DAAF929EDF319 +:10D080007FBC22E2F7F42F57176EA2FD3F79FF2EE7 +:10D090008297B75DBE128674C9C7F3A358DFC59DDA +:10D0A0003C5F6DE7595D0ACEAFF1317EDFD05903A9 +:10D0B000F400392F6656DAFF6E0C0F5FF812B4DFFA +:10D0C000F398B810EDD7E1859174DEA8B01FF7C7CB +:10D0D000F684F7897910E0C6E0078C18576D7C7CE0 +:10D0E0001495EF8BB6655E407EFCCBB564C71B83A1 +:10D0F000C3092FBDFBAD2AC42D59A99F44787444A0 +:10D10000586276A21FBAD2C070FF8931EB0BC427D8 +:10D110004F98C84F9D56DD9FF67B8A7F3F3EBF3BB1 +:10D12000B42B5E6AA0F83FFCD17D0CC7CA5146AC57 +:10D130009FB1442E9DB753F9DE4F6F7E9C4EFB3A54 +:10D14000229DDBD9ED8B380E92CCBE760EA0FB0A69 +:10D1500047E5FC2A6FF773A4F583797CDD9A44F9DF +:10D160005298450A9B807EDB4DB601FDA2FDEDDEA7 +:10D17000FB49A4FDAA775B8B63906E43FA717ED95D +:10D18000ED2B8E2956D9F592337AC2F37B46E961AD +:10D19000D41BEF75E92D38496EEB2231CE3A43F6B8 +:10D1A0009B814F16BED9011F26F513A9DF63A68503 +:10D1B00078169635FE263A17C7A5BC97D5E2A8C1C2 +:10D1C0007C31865ED220B57F7C6BF2883C9C879F49 +:10D1D000BFFE48FA9CFC6380C7BDFCE21A27DABC9C +:10D1E0003DE0D7E338A26CF958AF9CC763B175290D +:10D1F000EAB882DF0F5D2CCB3F6F77080F07C3F7CC +:10D200000F6D0DA2735F879C7F0F55FBC78A7CCC87 +:10D210000CFBD5E1665A17874B421CF08DBEEAF82D +:10D22000A3F05EC9F306D29B25CF472FF2623DD013 +:10D2300013B70C03BFBBA51F3F0FD0B97CD407C8E1 +:10D2400047FD55E5A3F4E5370B378574241F5531A9 +:10D25000C847F9CF1BE87C755197CA4918472CD2AB +:10D26000DDCC6A607C239EFF450CEEB3CC7CDE44B3 +:10D2700074F584861EE7F3EA138FF36AB33FFDB8B3 +:10D28000BEF254E790BD1075E09D81FE16971968B7 +:10D290003D22C61849EF8961565EDF85C52F06BB62 +:10D2A000BC34345B42FA6E4679C8A27A09F92C2F55 +:10D2B0007CF21D78AEE5F0C244DA073B99C9F7C1AC +:10D2C000663DFA6218FA9F871EE6E7BB6763BE1DDC +:10D2D0005CE7FE9BFB5E1572BE9DFFAB7DAF67FA00 +:10D2E00005EE7BF173A07B16666472BC30C984784E +:10D2F0008A1B4878B9DDCCA420C08B18C15250FFDE +:10D3000028FB5EE22FB97E127502ADD38F55392905 +:10D310007F415E98993FFF25BFB7273E3D9ED13E96 +:10D32000585425ED8345C8789D26303BCACFD1207F +:10D330006BDCBC34E4BF20A2E7CC17667DF16C2621 +:10D34000D26D6C94269E80FC17ED7FFF44F52D3442 +:10D35000BE1302B3A0BDCFFB43DF91489F46D1F17E +:10D36000F4BDA4378369FF9C593C4F0C01786635A6 +:10D37000ACB319F24DF7B884347F3F33173F968230 +:10D38000F4CEFB43901BCFDFCC5812B416CF619480 +:10D3900035F07BDED3567C47E77159BCBE12E39C67 +:10D3A0005F2F09E2E7D4EB8710FF4CD3F1732E2CEB +:10D3B000CE48F1A5B21019EE954DB0EAFE9211E9F2 +:10D3C000A1DCBFF918F50A7CFFB4820FF41B51EF02 +:10D3D0002AE7E859A584F25FA4133A3CE7F5553FE4 +:10D3E000EE9F4E8BB3D279D1F2DF9AAC8BE3399DAD +:10D3F00045559EB9729D377F2DF6AB63D2760BAE45 +:10D400001F9A4B70BDCDEAFB521E820A3DD31B23EF +:10D41000E0B9C4F599329E0A69FCEDC44F7A7650A2 +:10D420001F81786CFEA219F96371A8847191F2AE24 +:10D430005607F51B6AB6703B217F17C79E887CE0B4 +:10D440003346201F7C21E84C3CFF804D07F5E71850 +:10D45000AF6FFBCE921569346FB34537A23BF2DD57 +:10D46000F9FCB5F0DEED4C4AE88EF7C456444E9A0E +:10D470008CF5AF89A49740987E9B8DFEDE6B62068B +:10D48000AE53A7ADD843F39BF3C640BC41C0A6BD85 +:10D49000FE19D9A739327F79E4736BC500BF01A5A6 +:10D4A000FE266E271C22ABAC2358D0EC572AF5E59C +:10D4B0002B0C448FF2A526A27379F55FA9DFF2D079 +:10D4C000E618A447F97603E5EF08BD49A2F6C5D5ED +:10D4D000BD730FC2B88B0DE116011E9539C71A1125 +:10D4E0002EAB150856BE57BEE2F3185D1AEF0F4B70 +:10D4F000938EEFB3FAFB8D8E437B767A6B64DC34CC +:10D5000015DD4F2FD91186FBCE4783DCC978CED7E6 +:10D510003B2FC88AE70A9578DAE925C9FC3E90A531 +:10D520003914F7AB673C9C188176EEB0C56DC4FA30 +:10D53000C375F178648ED92C965C846DFA9B093E94 +:10D540002D9F23A13FCC1F2870BE29DBBAC79800AE +:10D55000DF1B24E3E7CC6B47F70E457C001F5950D7 +:10D56000FFC435A7A01D2ED735A7F444FABC2290DE +:10D57000BF00EB531BE61F998B7C3508F4A1CC57F9 +:10D5800073EB772C40F92C7FEB643EE2F5CC5866C8 +:10D59000C4F858B93C7F583F7EA087F6E5DB36E4F7 +:10D5A00033FEFE07C8778ABD07788901E026238706 +:10D5B000336EE2FCD364F450DEBBA6498CD1FE99F5 +:10D5C0009E8DC47640797E0F4014E5FB6995B113BA +:10D5D00078DE3DA7FAFCDC5CAC4FF3D777C6378525 +:10D5E000325F14579BC82E15CA78F1ACD81E867CC2 +:10D5F00071E6B53D7B87A25C6C132C4C2D0F8A1C09 +:10D60000C679793DE0EF49C4DFB6F3F998876276D1 +:10D610006BA8843454F0A4C89B82970AC6F1A0E09A +:10D62000A5422FE349AEBF5BC64319F3527FAC75E9 +:10D6300080B419FB7FEB07DA6F3B338D09FC9C301C +:10D64000CF8BA6CCCF11A1DDDF5F26CF6FFA4DDCEB +:10D650006E9659B85D2C8B6252F540E2339B51C9EE +:10D660002F094DCEBC714433FEE7653968A337CE30 +:10D6700003C6E9D1F17B8281FAEB51197F47AAA752 +:10D68000B851AFCC76423F99280F96A9B8CFC95E62 +:10D690001765FD0D32A9FA6EDEAB47880F41774959 +:10D6A00011B066316C8171A0FFD5DA9BE28579DD1E +:10D6B0003C34EFCD632C4C07FAE488E009DD89F6B1 +:10D6C000E05191F494324E9BF363A287AD8ECB2749 +:10D6D000F20BC60715390D1CEF3279BC269DD58398 +:10D6E000E782D96281EEAF898BCF841EE4F68E2269 +:10D6F00089FEFE6FF900F7236D17C324816AAC7AA7 +:10D700006C37F7625802DAEF2372DCE1C8D21D6190 +:10D71000C52A3AACEBEC3BCB864848FFBC90838FE4 +:10D72000A11C3D759320F3BF75E442D40797C22432 +:10D730003C2FD514E14C433FAA49C796B308CE8786 +:10D74000FA183FFE405E087F502F3D65F1CBA532B1 +:10D750006EA09B1BE906ED6D5C8EACB48F31378AF1 +:10D76000EF8B5E5B9E323CA49FAA056963A6BF9DBA +:10D77000722FEF7179DE2423317E7B80FC89F6CE17 +:10D7800024E7310ACC837A7BAFAE7188BF8A10B3AD +:10D790000E977081F581B07F3D55A9473F9F2D8938 +:10D7A000DDABBE977634C849F7CFBCDD45B611E88E +:10D7B000513DEF237E9EB781DFDB52EC34FCAD6A36 +:10D7C000E33F78AF34F37C3EEAD73FE698E85E5318 +:10D7D0004C7F7EDEE514AB330E47FBFF6D737E9806 +:10D7E000E45F9FDC72D12D8693BF10AF591F94B5B3 +:10D7F0007E40F25CCE9AE93EF6B4159F8D1D82F410 +:10D800007ED940E70766D4C6939D3BB9697A06CEB8 +:10D8100077DAD26482676D7E90C32B78FEC3694B42 +:10D82000B35E42FFEB68902D1FF9D9BB5AB0E0FA06 +:10D830006AD8E6AC45F741FDB0D03E5D71DC873675 +:10D840001D1D8B743FB45024FD64DBF4D424ACB7AD +:10D85000ED14F1C618AC672C8B30AF29D3875BD0A1 +:10D860002F50CE17D618B8BE3D2FEB87936D25E706 +:10D87000D3BC9A9A14F497BC1BC01EE1BEB7D15B0F +:10D8800042E7BB058B7523F0CBB782936066B1246A +:10D8900054E7E07D96F5941FE75CB2C9827EF2FD05 +:10D8A000266645BFF6FEF77A0FC2A5824D5E578DFC +:10D8B0008DE4DF55F0A57CDF2BF33D135795D0BEEB +:10D8C00043A49480FAAD493E377E541EEFC9252FFC +:10D8D0004F42BFE0E496E408A6C2FB49394FD32C7F +:10D8E000D083DB3A58EFFD7893127770D1774AE511 +:10D8F00078E03E436D2FCCFB1978BFEBC486203314 +:10D90000E6E70DBCE775C2C0ED47BBFB5E3BB570FB +:10D91000609EDBC0F12865BBFBFFFD433AF4E315D5 +:10D92000390B7CBFDD7DF2A4EB3B5F8579C9F0BE8E +:10D9300077D34D8CC63932F8C737515F97D49A2CBC +:10D9400078FFFE589044EB2167169336A39D314B28 +:10D95000E1B89E3FB62F83CEFF957CC548AE4AEA1C +:10D960004517A62AFE6075DFDFE502FC60BDC18AAF +:10D97000EF9F5CB37A1217336D9E856CC6E57326F4 +:10D98000AC93DC16FFBA2870BD347BED1B748FF0AE +:10D99000E75A2F2971A4407CDFDA5FCE4FDAC9FD48 +:10D9A000B9F7806DB207B5C7776B9583D64567AB7E +:10D9B0004AA9CCA9DB90D753C2FB14477E3B0CE5A8 +:10D9C00026349CE221AD5595B489777667C665BC4F +:10D9D0001FFA6E48B805F5C5D9AA85F2E502994F38 +:10D9E00064BEBCA5BE51ECC9A87DC33068BF3B2452 +:10D9F0009CEEBA24D9B2C3D1CE2B740DBCDFACCC13 +:10DA0000EFD4A39CAECA784F6D991E867E67E3BAA9 +:10DA1000C8869C283C9E1B6E417F7BA67CFEE5F859 +:10DA20005AAE6FBE3587BF3406CFCFAC9F1883EB9D +:10DA3000BA070D5EA315FAB5EE1A1F8671BC6FF416 +:10DA40009E30BC6FFC0DB477A39DD0BB44D4734310 +:10DA50000B18EDE30D75EB99144F5BE6C41739AD68 +:10DA60007A17D2F5B4FBE29E2BC847AD3A8A77010C +:10DA700066F65C81F6D6D03E14277CF06DBEDE647F +:10DA80003F76E1F501F7169FE9CFFD9613EBDF1C1A +:10DA900047EBF34D060B8EF3ECA6CF63F01CCE6C78 +:10DAA000C6CFD77FBB45A079CC067E0C8A47FDC088 +:10DAB000E3A0B341EF9B85F67C98B7A59AF8703642 +:10DAC000F021E6F59E6DE3F99867633E6689B5CB74 +:10DAD000FFD155E6BB39C077787FF7E7CEFBF13B46 +:10DAE000850F03E45EA1BB821785FE7E3E649AFC2F +:10DAF0008211750387F7647E7DA0DCEF607ACF2A00 +:10DB0000BCA7B1400CADC57C55FBF5957FA0BC2DE5 +:10DB10004E3DDB4CF69CA562BEBC05E24D568C0723 +:10DB2000D6182BDBF2BA607D605E173184BF3F1ED2 +:10DB3000F313C37CBBA6C5D3F72658ACA310DD8670 +:10DB4000280FC505C43C9D8DEEE5D59868DD1CA861 +:10DB500087EA64FADE95C6F5D0FFF4E7E7B5957B72 +:10DB60007F4A099AB137F2FBF8E0884B1234D9D5D5 +:10DB7000FFD0DDB84F3B7E58C42F12E1FB7B5F3DE9 +:10DB8000CAE18C88ED090037F5FFFA6EBCC731FE9B +:10DB9000E6882C03FA01D5C7EE1E09F0F1FEB67730 +:10DBA000FBABBEA3F40BCF77E3F37FC439DEEF4FBB +:10DBB000CFBD2548EF734218CFF796E4A538A8F2F9 +:10DBC000DE01811D7E57F0C31E038BC3BC06FF839D +:10DBD000BA3BBAF3B27B9AED63FE7DED73A4D077C6 +:10DBE000B8CE94F77F7466C988FE9FDD6AB4F2FCF4 +:10DBF0008ACC6E06BFEA2E997F8BCD974792FDADFA +:10DC0000645613263059AEBD8FD5CF7F6F6FFD8D13 +:10DC1000DCDB634E9E87AF46CEC3D7D93D4AA1E138 +:10DC2000A31FD0BF0CBC3F95F149F35BC827E3802D +:10DC3000AFD05E643673F82E994FCA778CA57CCF2F +:10DC4000F30F185CE827CC92FDB12447172641BB9F +:10DC50004B20BFA8175AC7B953507F9CA862B5493B +:10DC6000A0B00ACC8E4BFD014F4DF11F515EB41395 +:10DC7000EB6BC2D0EF3903EB8931D04599ECDFB3C0 +:10DC8000CBA2FB36F483E3FB6D5CA9E2B79F643E55 +:10DC90006B8D77C7E1FAC6196FE2F91A2FEFA13C35 +:10DCA000CF0509A3B3308EB4BF6A273B9AEC7FAF90 +:10DCB000B3FB284375230C69AA7DC971FA8ECF691D +:10DCC0009C51F2696EE2F6DBA4AFA53C5A40CACA89 +:10DCD0006A82ED14578A451EC5F8B0F410C1CB66B0 +:10DCE000310BDD63F5EFD3D17D5085FE36EB959199 +:10DCF000D86E1CD01FF58DCEECD5236C2FE0E753EA +:10DD0000FA01E1509F28F41F252EFA2DD261BE7C26 +:10DD10008F6BBE50C9618399CEB906EA478C6B16EA +:10DD200091DE74EECD417F0CF424E55590F5A2040C +:10DD3000FFA3BC48D91B8CD4ECDA7991F6E6FC073A +:10DD4000FA31234D9B475CA193E25F754627454F0F +:10DD500002BD86A5455F3FBD943C65F39FE7F1CECC +:10DD6000F9CF4F8F1D44780389437F28ED4F44C47A +:10DD700099F21CD8FA48E263C308BB84FA76ECCE69 +:10DD80009E4C8247B3760A74BE75CCCE4882C37C63 +:10DD9000DD795E25D9DE8FFD63B711189F3CF9D27E +:10DDA000DF1FC6BCF7637EC3287EAC0B0EA17C13BD +:10DDB000E208398F8318F221DE63BD20F1DFA1B0C4 +:10DDC000B376F9037444FF267E4E1656794E4E27DD +:10DDD0007EEF6FFE3E6EE7E70FE7FB8217F00D6800 +:10DDE0007FA150A43C4DCF04A793FF5673B781EE9B +:10DDF0004730A7ED2FB8AE9A2CF383291616962A32 +:10DE00007A054920AF2AFA3C1EF4DB0F1DD0BF076C +:10DE1000D65D420FC682532334F57A67D037983FD8 +:10DE2000D6102B5A5C30FE506B0F4D7F76B1CC80F4 +:10DE3000F114E6E07EB4C25F4C6CD5D3BDF95C9EB4 +:10DE4000BFE2EEC9DA7B9286DCF323C9DEE46AFD29 +:10DE50006FFB35F236FD4AE1A77EAC9F9C979EECA6 +:10DE6000FF85167E3F4462F6B58ABCA0FE07EFE64A +:10DE700019C4CFA42603734984BFD7B0FE82D364EC +:10DE8000C178409B1F9E04EF45A19134139F635EB0 +:10DE900050F53C312FA81A2F9817540D635E50751A +:10DEA0007BCC0BAAAEC7BCA0EA7ACC0BAA86312FDA +:10DEB000A8BA3DE60555C3981754DD1EF382AA6142 +:10DEC000CC0BAA6E8F7941D5F59817545D8F7941A7 +:10DED000D530E60555B7C7BCA0EA7ACC0BAAAEC7C9 +:10DEE000BCA06A18F382AADB635E50753DE6055557 +:10DEF000D7635E50358C7941D5ED312FA81AC6BC59 +:10DF0000A0EAF69817540D635E50757BCC0BAAAE51 +:10DF1000C73CA0EA7ACCFBA98631EFA7BA7D335B78 +:10DF2000928C766C77BCE37FD268DFE95BE2E783B3 +:10DF3000F7033FA31C364DB450FEC21B5C277E9EE8 +:10DF400026EFF7C8FC7B89854CC573E89DBDAFF013 +:10DF5000E7EBB2BF01F66039F12F0BAD457FEE71F3 +:10DF6000BD8DEE4339EBF8FD44A6E77EC00251F6C5 +:10DF70007FE4BC100B4489FC00CC1DAC578DA7ABD3 +:10DF8000CDCCF42A3C4416583470B43D56D3BEDB95 +:10DF9000644953DFDD91AAA9EF596AD5C0BD2BB3FF +:10DFA00035EDFB2CB469E0786781A67DE272BB0693 +:10DFB0004EAE9DAC69DF77AD4353DFCF55AAA9EFD5 +:10DFC000BFA552030FA85BA8697FF34EA7A67EA04A +:10DFD0007BB9A63EA3A956036735AFD5B41F72D04F +:10DFE000A5A9CFF16CD1D40FFBB64E03DFE2DDA9BA +:10DFF000697F9BCFAD8187B37D9AF679E6031A7866 +:10E0000094E54B4DFBDB638F68EA474B2735F5659D +:10E01000A7B97FCF6A607D8071CA109E5F63AE9B97 +:10E02000D5A17F7167EA794D7B4314AC17807FCA15 +:10E03000411FA2DFF77D9738CAC7CC2AC3AC78EF5F +:10E04000DB39A2F20FEA7BDE63AD3F68BEFF4C70A6 +:10E05000983B88D61766B2B7230624907D6CCB27F1 +:10E06000A2DC67675E161B4521212FFA4702FEC21C +:10E0700012C061369E171AFC20F29F2CE017A1BF38 +:10E08000D9B62ED2C5C7A35D0EF6FBC5BDAEA8F2AC +:10E09000BC5CCB2FA66F67519EDE5103301E5EF72E +:10E0A000463EAEB36631E732DC4F54F22CEE0FD26F +:10E0B000C6B79472B419F0ABFADEBEA0DA5E83AED6 +:10E0C00022EFA3CDADD4BEAD5F39FE25C064E7AB72 +:10E0D000FAFF2DACFFF420D7B555207FE00F3D5956 +:10E0E0006521784D552CC14F574954AEAD4AA5F224 +:10E0F000B92A2BD5AFAFCA26F8852A1BC1AEAA0212 +:10E100002A3756D9E9F9A6AAC904BF54E5A0724B2B +:10E11000552995AF545552FDD6AA8504BF5EE5A496 +:10E12000B2AE6A393DDF56554B707DD55A82DFAAB3 +:10E130007251B9B36A0B95EF54D5517D03F86F084E +:10E14000EFAE7213ECAE6A22F8FDAA66823FA83ADF +:10E1500048F0DE2A0F954D55DF52F9E72A2FD57F7B +:10E1600052E523B855DE87583440D0DCC753603DB4 +:10E170003BC6FD3DCC5B817918B20D67AF961F376A +:10E18000900EA7E4FE0D23C05DC238728F948D35CA +:10E19000AA75C5F201DC5FACD6F1FC2DD53D98A582 +:10E1A00086FC761BE3E7B4B8DF3E13FF25C1D3A896 +:10E1B000AABDB8DE28A9E479CAB3901F53891F3FCE +:10E1C000B9A1759ABC2ED891687F6600AE43425CB7 +:10E1D0005FC467FAEFD11F4C743C877C7AA1F2C10F +:10E1E000BDD87AA6C59A821F196B724763FE2FEFBE +:10E1F0003ED1BA51EAFC7B15F2FD874EEB779FECDE +:10E2000085F6AAE02791E2FAFB0DA193719F7FABFF +:10E210008C8FAD03749AB228C9FE2A8EE74472E54A +:10E220004B0F09FEFBFB77E1121FE47B3C93280FA9 +:10E23000CE4466FB105DF0BBC11144F81EE6A4B2EB +:10E2400035C1518FEFDF0B0B10841D434D711DCD78 +:10E2500027703CBBE5F1EC96C7A1940B92ECBB1088 +:10E260006FC7926D9AF16C95F3338C63DE17705C17 +:10E27000FFDC75FEB890E8C7775B3C8555529E8CF5 +:10E2800022C6E3298F635E8C287F5E0C65FD50B447 +:10E290008FFFCE11FDA1FD5C104FEBDBC0BC19CB95 +:10E2A00086EFE17930603D86F77F8BE6FD82F42FC3 +:10E2B000FE1E14DEDB5DD0E530E599F1CC025EEDAB +:10E2C00049793578DE1B0720B027E5D5A07AE1260D +:10E2D000F87F771C9739554FE3EB42F94E9E09DEE4 +:10E2E0004F796930A660EA8A798F79BC66BFFD3CB8 +:10E2F000F7BBA3BC743F7547A2E3EB013C4EFE7431 +:10E3000006C689909FF03B16179D5F037E320A80F8 +:10E31000A29951C04F1DF81B0ADFCC95EFE128CF21 +:10E32000811F5B11DF67DF1E928A7C53B13B47423E +:10E330007CD7E8F87D3AE79FE57D41F9F710C4F016 +:10E34000B40D74EF009D71A46F4E28DD3B6814D9A5 +:10E35000C2373AD0AFA1E95CDEF7C7F27C92350153 +:10E36000FB93C6744E77633AE787B1EFEFA33C6443 +:10E37000739B78BC9A657AD2EC1D9CCBAA58F89B0B +:10E38000A79354F3A8D879849FE7629E34F539AEF9 +:10E3900064F9FB0AFF89C650C78610F5F878FC01BE +:10E3A000E420243D8BE4E038DEEB1E6792C2EF11DF +:10E3B000E8F7C1CE627E19C71F2C741E503917387A +:10E3C00083D9A99C099613F9DEEE5C4DF7E767B394 +:10E3D0003A7A3E377B7A1CC215CC3B3216D747CBF4 +:10E3E000AB3FC470D0C4DAD5A3BAC3BC26B8A67DEF +:10E3F00088E5F84DC271A74472D43B1DF7B785CAB2 +:10E40000A53DE07BF76D1DBE14E3D6E3444E07F651 +:10E4100031A74311F0B318D17E7E203749E95C6EF5 +:10E4200068FC8ADC142D66363C7FA0DC0F6993A360 +:10E43000EC39FFE8897B38E04F22BF56EC3645D0F7 +:10E44000FA14F3CCA0BE92E567A99EFB974E4C6DE3 +:10E450004AFA93FB1B069B9CCF8B717F648E93AF14 +:10E46000C74E19B8BC9D3A14EA42FE5ED0E5F538B5 +:10E47000920F83221F3F4DA5F33D0CFC8F5BDBFB0E +:10E480001F6D79667A31F237589C237650A2DF9E51 +:10E490009FD2B90687F1BCFCA3105F7B63F9FA79C0 +:10E4A0000EE6A1C1FAAE7609E3A5A7A2CD745F2856 +:10E4B00030CF1963569A9F419E1F8C6C32FAD32637 +:10E4C00039AE561330DFEF83E268BED27056C7D044 +:10E4D000B1D05B9CD351EE1FE2766241975F3BF077 +:10E4E000FB9E20661186D17C281EEBD4317B0D8FDC +:10E4F000CFD2FC16EACD163C97B36C9AE811C84E01 +:10E50000C038319E1765B6F2BCAA4AFEEDC0F1DAFA +:10E51000B4E333C7319C9F4D64DEA0617CBC383EC0 +:10E5200027D083E803F034D5F8A05F17E5FF0996FC +:10E530002CE88735FDF8108F2F5773FF11C6BF8564 +:10E54000E8D31DC6DFF3DAE337208BC2F817A4C780 +:10E5500013DFD5E00EA28876B62BE9DF0941F64736 +:10E56000900F931C2B7BCDC7B8468EC98AF13B76A2 +:10E57000B9A617EAA91026515EAD71369E570BBA9F +:10E580005B82FC301EF3D659C80F6855E761630102 +:10E59000F135200BC55727607C8DDF25FA00E3B3EA +:10E5A00013E5F3CDFDD8570AFE28BE26E2F8285E13 +:10E5B000EDA0719A90B25006619C87E8E0A27904C0 +:10E5C00033B71CCF6E26FF60B5CC87430F32B21332 +:10E5D0004343B89DD87D84B9F0DC57E30F93F242F2 +:10E5E000A17EF7793DE929C013E5037CE7736E57F7 +:10E5F000769F3CDE13F703AA7FD8DB13FDC4DD064C +:10E60000875881EFE7982C8BADFEB846C3C1101E2A +:10E61000D791E37CB7C8F36C60CD3515509FDD5DB5 +:10E62000641807CC6A7107A33C638EDA8EF61B73FD +:10E630002F1A35BF6B61B068E16CA682E3F1E85137 +:10E64000C0EF7FDEE03A775BBAF6F729DB7EF7B3FF +:10E6500035EABA7EF733539EC7AA74FBBBE964D789 +:10E66000268832DE05C417E88146C4F773E546FA0A +:10E670005D83C67263778F6A7CB5B3FE49F87DEF20 +:10E68000C77F92DD7A2F4BC98F531784CF8DCE5021 +:10E690008ABB3D77594771B775A55FD3FAA4369BFE +:10E6A000D1EF88D55E2E263FE05201C34D24567D22 +:10E6B000EBFF9622FCBB5BCCF4BDC0F1EF027FDE2A +:10E6C0000D847A17FC79775FC6DE067F1E61BCCFAA +:10E6D0008AE576F0E7B174813F8FE50BE0CF633BCD +:10E6E000F4E7B17C0EFC792CD7823F8FE5D3E0CFE5 +:10E6F00063BB35E0CF63F924F8F3F81CC69547E314 +:10E700003AC8E8DEFEE2E0B015E86748CE50F237DE +:10E710003EB50DEAE251D9D95B2FEA3474CE6DD5FE +:10E72000FEBECDD063119ADF3FC9FEAA87A67E70D8 +:10E730004B82A63EDEA9FD7D9B3E0BAFFEFB363D28 +:10E740004B4704FC3ECE1D01BF9FA3FD7D9B68FB94 +:10E750007D01BFBFA3FD7D9BDFC9F932153AA648F5 +:10E76000AF05215FAC2B9D10CE3AF02F94F2499962 +:10E770001E0AFCD4A3E2E48EE2C85137737BFFFE8D +:10E7800021D3BE4D80CFF758B81DE3EEEFD974A466 +:10E79000979E5B1B4271589367E849E49FF76C4C66 +:10E7A00042FE79EEF2882E389EE140467CDEB3943C +:10E7B000DBA73E374BC4CF3D4BBD22DE17BDEDB2CC +:10E7C000D78AFCF85418FF9D2DE8D7B518FA7B7F3F +:10E7D000ECE07E18C7792E04F819E5CDED0D4E0258 +:10E7E00038FC8A8EA17E045B4979FE9DCF86C8E7FE +:10E7F00051AFD07DB870D4E9A097DE2BE5DF4FF1A3 +:10E800005C0E56FB43BFFBE95A7861C4579DD6DFC7 +:10E81000313B01C7EBC73BA84628535829FB2DE2E3 +:10E82000A38CCB4F6DA98EE4E912C813E207664DA5 +:10E830007461CD5A797F12E5434D87B2841538CF84 +:10E84000E7D6E869B76C94B875DFCDF0CABA16910F +:10E85000B6D9258B37B823FF4E19F73A1B9F5F8433 +:10E8600095E9D0CE45003E5DB49F6DAD56FF9ED577 +:10E87000B3B27CFE5E96CF67647EC0F536C2A3C499 +:10E88000F5A353701CD95C5F033D05BC8F75690609 +:10E89000A3DF11FD7D6142978EF27CAF91C7F182BB +:10E8A0003CAFF5D82FC93397FB5162D170EC679D0F +:10E8B0009D911E5F67FBBA1AE376970A79BF7D16B2 +:10E8C0007904C46FAF4AAF80FDF77ED84DA54B1ECB +:10E8D000678FD266AA57FA93AC2ECEEF655FB32648 +:10E8E000982F1EB215C95EB4527ED4757A3D433B53 +:10E8F0008CFA0CE14B663D9E91603D661D63789FEE +:10E90000B936444FFB14EBE69E2278B585C361CE41 +:10E91000CA343C7FF1B63C9F30A7936057C07C520D +:10E92000A407C2D5BFE71A58EE90F1BC5DC6C7DB9D +:10E930000687EE028C63C85F45FAFD8ECEDE53EC8F +:10E940006CF657BA00FDD34523FFF81B7BB25DF888 +:10E95000F5CDB87E76DAC92E28EBB6ED63B87D5DCD +:10E960001D3CF5635CF717CA7CF44CF0B80FB1FEA0 +:10E97000B3D1FC77701A47DFDE5BAD2777CAE3DEE1 +:10E9800021E33DC7693BF430B41F6F37E1C8C08C49 +:10E99000D97AFF02FAB38F11AD6EA05B4B96220FAE +:10E9A000F66094BBF7C74C6707B1FF02BEEFB4BD7A +:10E9B00060223D9798FDCE01F0DE5F9AF5E4CFC06E +:10E9C000F3ABCAE37E19FF9FC8E3F8B38CFF269927 +:10E9D0004FF7A21DE98B7196542ADF97ED885BB63D +:10E9E00023BB653BD220DB91B7D18EF4C5794DA610 +:10E9F00072BB6C4732473F457ED225CC8B2BA01D86 +:10EA000099CB96C138F361FC6207F6EDAE6C31E04C +:10EA100077B2823574BA333552038F967A06FC4E3C +:10EA20005762C0EF78F5D7D4E79933027E076C9828 +:10EA3000A6FD6DBE1101BF23A6B523438F4DD0FAAD +:10EA4000335FDDA7A91FDC52ACA977E23F60BE5956 +:10EA5000C718CF2F1B9CFB04F24BD671BDF2FBCC29 +:10EA6000B48FA6F85B81FE4F166BDBC7D3D13E9EF9 +:10EA7000934978AE93B6961334F5E43FB518EC3D60 +:10EA8000F1FC61F578E03B3C87D8523286D13E3CC0 +:10EA9000F02FC85396FDC457946F542CCA203FE9F9 +:10EAA000A25EB39F9613B02F661FA9DD37CBBAC6FF +:10EAB000BED9B19B3BF91DF6D688EBF2C7409E4408 +:10EAC0001CF733C153F720DEDEFE92DBA9C62F1FF1 +:10EAD000E989CF3FC0A6D0CF8E6F1E21BF6B479B69 +:10EAE0007C3882D5FED6760FB7176FB524ECC47587 +:10EAF0004666B4407A30F3C8FC29C48F2D3AFA7DBB +:10EB0000CE94828A60C4CBF6838B83B5F7A754FA80 +:10EB10008108A5D20F22B232FFBDBEFF07E9D10F97 +:10EB200034008000000000001F8B0800000000007F +:10EB3000000BED7D0B7C14D5B9F8999D7D25BB812B +:10EB40000D09B08104260960AA3C36EF4D48C22465 +:10EB5000048C1AC8427804C1304978A48A9AAAB5AC +:10EB6000D86233211062A4121F55B08A2BADDAF699 +:10EB7000F6B65425A0A22CCFAA5058306844D4052C +:10EB800014ADA5F7A284D6F6CFFFE73DDF77CE24FC +:10EB90003BC32640DB7B5B7B6FF8E9E4CC3973E653 +:10EBA0009CEFFD3A134208F94AA4FF8B1F4E0269FD +:10EBB000047FBE4A81FFA7F4B6A19F5C4D02F6F028 +:10EBC0007686A19D6F185F62685F6F183FD3D0BED5 +:10EBD000D130BE56D7BF2D3473A0E2A4BFC3CFA49B +:10EBE0008BAF5B1A09095CD53B2EDBEC133D632F21 +:10EBF0001E97D369EA9D97FEB7F3FD25A6F3F1842E +:10EC000074748A7E5B32BD1E5F42D42C3A4FA7C912 +:10EC10004F04BC9A08EDDFD6C5DA36A23AC6D3FE59 +:10EC20002D9D664F9B44C80EFEDE31BE85037D31AF +:10EC3000844C329F8DF85EF982A9777F04E69B3978 +:10EC4000904418A75D77F179038D76BC6E6F74914F +:10EC500080ADB75F8CC9EEF4D17574844C1E7A9B7D +:10EC6000AEBF248ED07DEF762E76C0BC74BD840CF2 +:10EC700023E4DACD23AA9A461122D1759BE83EB649 +:10EC8000844CA48DEE33EB287B7F96458E734580B4 +:10EC90002B21263DFC2F9A8FFE009C9CA2BF8DC28B +:10ECA00065D7FB73E2C6D3F95FEA1409ACC7AAD4EF +:10ECB0003B7CE368BB8BAD4B9B77B25DD4C1A19825 +:10ECC0003874F8283C3B48D7CE3A41D7499FB74AD9 +:10ECD000157100DF4BAD939068031D0D32B487E9C9 +:10ECE000C68F9128DEC6F58D8797381EB6001EE8C0 +:10ECF000C65E8AF254F922C06BCB07D67A7FD8FD64 +:10ED0000660F054A365C4D78CD3A61F204287CCE18 +:10ED1000779A3C00BC3C57BBD810619EFC8FF4F442 +:10ED200099D319AD83171117F4CB07CB8F37ADD912 +:10ED30001336FEFB9E98F8D3D7D05F72492EEEFFB4 +:10ED400012CFFFA9515DB3C742E99892EC663A8EA3 +:10ED5000B82A0949E87B3C212B717F1A1C892B8E2C +:10ED60006EEE72F0D48ECF5D84AF3E9EEF9D472550 +:10ED700064308527052F8C5B3BDEF7B887B6496882 +:10ED80008608EF7FD0719B18A2EB7ECC71DB6EA062 +:10ED9000CF037FB64AC0D73BFFDC9108F7F7A76FD8 +:10EDA0004D04BADF4FDF1D84FD9929D668DBAADE4A +:10EDB000E400FA7AB3F308F28F4482374CC882B683 +:10EDC000C9D34687BD9A563990F403B7D7399DEC1D +:10EDD000E3FCBA87F3EBAE4637E76309AFAF35A67E +:10EDE000E1FDED8D1E6CBFDCE8C5F6B64619DB1DF6 +:10EDF0008D65783DDCE8C3FB871AABB0FDDB46854B +:10EE0000D161DA9DA5208FCE275200D07DAD744C04 +:10EE10003747C2E775929ECFAE75EBF96C0A8573E2 +:10EE2000787BB27DB8812F5375FD93BEBC5AD75FF6 +:10EE3000783643D79EF869BE6E7C5EA844D7CEED87 +:10EE4000BA5E377E6669A5AEDF57305FBF3ED189B7 +:10EE5000F265874B40B93C3DAB4ED7BF037E0139CD +:10EE60006C17FC6A32C0A5B25F791A00FCD8008E1C +:10EE70008C8F7FC3F1B317F06303BC30F8BF0AF087 +:10EE8000A7ED5700DEF49ADDADEC1E28811CA8C763 +:10EE9000B6356DA0D343E1FFAA5344F9BFB5B10124 +:10EEA0009FDB7FBEB65BC4F53A24C0CB0EBE9EFD91 +:10EEB00016A55B8C87B620AD142E5E5776979EDF25 +:10EEC000C7942D44B9B9A3F3A403E8EDB52F2F4F90 +:10EED000EF69E37E432A27037D1475525D957C69B3 +:10EEE000FDA7E9AD4BCDAF8D03BD1A495F18E7BD56 +:10EEF000FE4B4524741FAF76A90FC7403BF04D5120 +:10EF0000A2ED9C2E6532E06D4F9AE012051C375938 +:10EF100086755F387203DC7F2D6436C1BA0F5C18CA +:10EF200044601F3BA8DEB5D1716F92D4B51328BCE5 +:10EF3000035D5FEC07BE549D16CF6872F13A52D361 +:10EF400045942B5BC6DA4CC204D0776612180B7C52 +:10EF5000AE203C3BBE4C71C2754B9AC8EF0791DFA7 +:10EF6000C7A7BBF0B9572F64C443DB4482280F0204 +:10EF7000DDA6327F84FD8E87F750B9937DE143870C +:10EF80008B8EDFD75DEB00F9F25A179B3F7B45C8AC +:10EF90000170DAFFE52627DCDF919689F3EE1CB7D6 +:10EFA00014ED8B1DDD26A4EB1D63D73833B2709FA3 +:10EFB0001E80DD8EEEDAB5E940D75D666C4B4421EC +:10EFC00041A0B734A667B774D79223B4FFBC47F407 +:10EFD000039D6593F67D03E0FE90355692C2E06F87 +:10EFE0001E42C8ADEC6132D9A59703255D7A7D62DA +:10EFF0000D2D983503EC08A067DA9E668ED3F5EFE9 +:10F000007F7765FC4CC00B8537DC7BADFB8EFDE369 +:10F0100040FEF859FB0FC77F621D48AF4DE3D60C89 +:10F02000BF0DC66D71786C12F428E40BDACEED36A4 +:10F03000FBC1DEC876EAD7B1FF1B9508F72DDDCC02 +:10F04000BE3A9FC6F6B3C353471EA0CFBDCAEDAFAD +:10F05000C9274695C3FB0E50FB09EC8A573C2FC4C9 +:10F0600065823CF38A3A7AA3F0417A39DF49701E0F +:10F07000FA33601A8543011B42F9D0D77C3BEDDFA0 +:10F080009F6773ADA4A8DE7161D7EE3B683B374143 +:10F090002422DDC937FDFAF5E5FDD4A16BDFFAA91D +:10F0A000DE2EB11181EB7327CA81BEF867E259AB3E +:10F0B000EEB969669B6EDE5C12D68FF8B4F6F62761 +:10F0C0005FDA3ED9CAE59A669F6CB528F37D40D7D2 +:10F0D000C15997D0A32BB9FE6D4079B18D104F5B0C +:10F0E0003A95EBDF1065E0C3F3C7ED08C7DCC766F0 +:10F0F0004C24A8AF9589C00F488C61F680F7F8259D +:10F10000EC15974AE273F8AB085CCDA743747C2BEF +:10F1100055F35F810EE7FADC386F5F7AFF41C70075 +:10F1200094FB05A54C2F3CE638887ABEE37DAAE720 +:10F1300005F68E10C5FB6CF805F4FEFB561CFFCAE5 +:10F140007502CA11CD6EA824B285AA3832DDDB6DF6 +:10F15000FE01C59FCF5E3DEE567A7DE5DD8EE1C0B6 +:10F16000BFAF807D80F2A1C1C1EC8318358E2E71B6 +:10F170007B970DF970EB5913B183DFB0DD86744ACC +:10F18000F9F4FE71F43DDB83CC5EE838CBEDBDEDE8 +:10F190000EE4939D7F60EBE858E1607EC619AB0CEE +:10F1A000F6F8D6153108E731524CC00CF32D67F351 +:10F1B0007771BCBECDF1BA9FEBAB37B8BEFA0DD8B4 +:10F1C00013A8BF983DB11BEC097ADDC9ED891DA0DC +:10F1D000CFE8F5C5B3CFBF077C797E7B14DA9D639A +:10F1E00048DA6658D776A715D76984F33C45CF0728 +:10F1F00073ABF47643F958BDDD70FDA8E1BA7659DA +:10F2000062AAEEF9A9F1D7E8FA4B9D997A79649E42 +:10F21000A86BCB17F4764385F7063D3DC9617603AD +:10F22000CA3BBDDF383BDC6F4C063C313F676BD7D8 +:10F230001D88C7ADC753062A6176C2360EE7ADC733 +:10F2400099FEDC16FA22468960477CCAC77DC6F162 +:10F250007186E3E33F46C8BF4B1F0CFCF20593BF2A +:10F260007DD0B1F6BCF6DCA7FE5303C2F5FA4851D7 +:10F270004226D1DA7FE8786F0CF45F2E5F503A6D4A +:10F280000D513C7F478C696FA38FAC31373C056DC6 +:10F2900055359367B2101C6966ECBFDA03F2B839D2 +:10F2A000A6E139E8DFD264736D8A073EFAFEAFA0AB +:10F2B000BD9CB2828D5EFF1435C24F28AB39324CF3 +:10F2C00038FFB316DF700FE84DC137FF563A5EDDE9 +:10F2D00060F53C235DBC9ED80C4163F66DA087446D +:10F2E000CEF77F1194D80C7A5FFE8580723A4A225D +:10F2F000A8176CC41700FE21F5F27CE00F62A2FC97 +:10F3000043AF8D99CA50184F6422B9E83CC8DAF46B +:10F310007D4270DF9F05BA2E0B6950611E5B3D95E3 +:10F3200030949F1F4D5746E078F34C9CFFC569848D +:10F33000803CA3DBC176D6DDC4D5164B286B2BA64B +:10F340002F687B3EF5F7E1FD26C732D453EFFDCEA3 +:10F35000E41723D84B3D705E6639130A8B8F18E98A +:10F36000A783D3C5B6641FCA5FE3F3B900170AC702 +:10F37000AD1F4E1781BEB2EC0364B02BE806C51971 +:10F3800054BE6F3B79BDA326C273D767D5E4660C24 +:10F39000EE6D6705378B354EF4E745D8D716FA3B47 +:10F3A000ECEBE54E5300F07BDE694579D2D73EF2B7 +:10F3B00042FA38442ED80361FC46C80217F88B0283 +:10F3C0006917BEBA269CBEE4FBC3E9EBC58BE90B0B +:10F3D000E1FC9DB7D210AECD02A32F95D217F4ABAE +:10F3E000250D485FAA89F89AB390DEF0F9E566BB6F +:10F3F000CB4625E4B28C147C4F474CF97B0109DFE6 +:10F40000973A13FDB96AEECF55A39C7FE32893F397 +:10F41000C67DED3C3A677808EC89D17387039F7706 +:10F42000800218068BCA9B27EBDA248076E0140250 +:10F43000212B80C03CB03F3BAED3DA5ED62E66E3D4 +:10F440006F79FED10D2AB46FE2FDEA6CD6AFB549F3 +:10F45000FEBC62685B4CD83E09E3E9FB1EF3C8CBF7 +:10F46000006F8FA6CBB7025DE680D142AF9F4D9073 +:10F470006F87F6B20C82FBFDDE04F95B304E6B6FDA +:10F480001B2FDF19DEDED2E3A7B6733FF556B44B70 +:10F49000DFE89A89F6AC447C3780DE7923C8E251F4 +:10F4A0005B46F5EF071DE4F6FC01EEA7BE09F2E8A6 +:10F4B0002AD027CC4FDDCBFDD4DD5CAFECE47EEA77 +:10F4C0000EAE575EE57ED22BDC4F7A09FCD4ABC082 +:10F4D0000EA9E27112E6A7668D9E5C8A76844BF3D4 +:10F4E000534744F4532BBC7A7D33CDA3D73737A48D +:10F4F000C519F48B5EDF4C8DD7EB9B52E73506FDCB +:10F5000092A91B2F5FD0FBA945DD25BAF10567F451 +:10F510007E6AFE473375E39765488847EFF11B75B0 +:10F52000E3723A6B75E37AF1E6433C59D5279D6067 +:10F53000C76D1955C7F1C6EC050D6F1D97C0DB6F80 +:10F5400038DEF672BCEDE678DBC9F1B683DB03AFDB +:10F5500072BCBDC2ED819738DEB672BC6DE1F1853B +:10F56000831C6F0738DEDEE4FE6ED6E8DDE89F9D83 +:10F570003F4B38DE368A91F05696281AF0E030E09C +:10F58000418FB712F370031E520C78B85AD72E3839 +:10F590009361C043BEAEED3D5E6280FFF506BBA148 +:10F5A00052D7AFE16D9A67BE81BEEA74E32E9BDF4E +:10F5B0009CCCCEFB6BF96D1FB7E3F670BCED02BCC3 +:10F5C000619CC8C3E3115E1EF76576DCCB1C6FDB64 +:10F5D000785CA803F006F61DC75BF3A87368C79FA5 +:10F5E000BFA0E1ED6044BC5D29BF5DEBD6C785A639 +:10F5F000B8F471A1C9763DBF1513BD7D37E94B3D08 +:10F60000BF159ED5DB77133FD5F35B5E68A6AE4D85 +:10F61000ED8084CC6CD05337EA9ECB0ED6EAC6512F +:10F620003F89F92D1EAEF7FD95A88F5AA631FD48EA +:10F63000F910EDEF67BF4DED80F45E78BC68F09F88 +:10F640005EEC437F5F93C9F477C77BD508D76CD056 +:10F65000DF91F20B7C5C4EA60BAF363351A33370B7 +:10F66000997B86D1F5984731BBC71CB316820CF045 +:10F670001334E5F4DA49A2D347607E6A2FE5648645 +:10F68000E97DB3AB8180DD20DA1E5A00FB22A2C9DE +:10F69000837AD7601F917A977C07DCBF6380A78D40 +:10F6A000C2E296CC585C879B6CB6809DD198294F5E +:10F6B00002788A93193CB62451DF9DC2634B146BC8 +:10F6C000AB145ECFD0B6387001C2AF83C24B4C874B +:10F6D000F9E3C9DD745D55995606877984E953F5D8 +:10F6E00039A65F7BF421351868FBD968D6BEF18551 +:10F6F0009FCE53137BF56F5DE64BA84FC73887D578 +:10F7000091F174DEF5EA20B033C7D2F5817C34394B +:10F71000B62745B2BFFBB2C3568F97E7C17EBEC7BF +:10F72000F5EB180A117346DFCF3F1BEDBB05F09BCD +:10F7300005F0088B7BCDCC64766B15CC3318ED4B84 +:10F7400039DCBE24C14A6CB7A433FAFAF1DA99481D +:10F750006F4E0A2F3116D6CFE037FF2E465F57BACD +:10F760000F6DFDFDD0892FDC9E0EA393EF45A213F4 +:10F7700052EE71A3BFDE973DA7B2F53673FB51B3CE +:10F78000936D899ADDECC7F558287BE40FC22B995D +:10F7900042E13AC845305E53ED32F9FD14645160E0 +:10F7A000F083DC2915882B19669709C363B9142ED9 +:10F7B0007F8CF141EFF168837C1F64D0C3C374ED8B +:10F7C000A2EE14839F7875BF7ABED439D1A09F264C +:10F7D000EBC69725DE60F0632B0D7EAE5E4F9889F9 +:10F7E00059E5F83261DC421524730EDC27889FB09E +:10F7F0007EF43B7BE0FC845C85FCCAFD1A23BF36AB +:10F80000664A0867C1C5FC1A8D1FB4E735F859DD93 +:10F810000CAFEB7234FDE441BD630B7C93405C950F +:10F82000DAD0F2E6307ADBD4687FAF7434213F69F6 +:10F8300024EF9552E4F91B5D78DDD8E8C6EB138D13 +:10F84000125E1F6F4CC371EB1B3DD87EB4D18BD7BA +:10F85000471A65BCFF506319B6DB1B7DD85EDB58C9 +:10F8600085D7B64605EF8F322BAA9DEE6B542BF150 +:10F87000A8742BA3DBE9FBC2E096DA4AD71106F79E +:10F8800064D5A56B8F5CEED68D4F6A9074FDC3EB8B +:10F89000D374FD098A47D71E5AE5D58D1FEC9375A1 +:10F8A000EDB8B232DDF858D9A76BC778AA74E31D5A +:10F8B000698AAE7F5751FEC0503F7CFC506320C820 +:10F8C000E0120C3238BD1E64F0E9C2EBE75CFE0EBC +:10F8D0003207515E0CCA7251D2A1F8B2B3FC5A9CE5 +:10F8E000D923C486CD1F5746E74B0B5F2F9D4FE7AB +:10F8F0009FF9915E623C41DD7D475A97EEB929A29E +:10F90000B304F211870B448C7B1D2E888B01FBE521 +:10F910007E8B6B5A16A5C7434745CF26780E1E88A7 +:10F92000202F4F70BDE8186F47B950B14AD8242234 +:10F93000D1B2E76B3B5323C63D0FDD4BAA605F8E10 +:10F940005D2F494017150535715161FE5A45E0CFCD +:10F95000A56EB8BF2A3D278ACE56D19A6CAD1BDB67 +:10F96000BB2F6D5CED2ABD7DD94BF77E3BEC638CE4 +:10F970007AAF1DE45B5BE2266CB7A5F59F27F98C97 +:10F98000DB619F723BEC348FC37CC4EDB093DCEF42 +:10F9900009713BEC036E871DE7F6F3316E877571D5 +:10F9A000BFE76D6E3F7772FBF908B7C3DAD29E9F4F +:10F9B0008AF2F017021123F8A9DAF5969FEAEDB062 +:10F9C0006FFAF576D8D2F57A3B6C71BBDE0EAB6B75 +:10F9D000D5DB6135AADE0E5BB85C6F87DDD4A097FE +:10F9E00087F3EB27EBDAF3147D9C6D6E95DE7ED604 +:10F9F000F033DBA7978B95657AFBB9AFFDBE12B8E4 +:10FA00000EF33F80C453617AAF279F0B7A85D245AE +:10FA1000D605AA57300EEE6B86FCC9361842F56F34 +:10FA2000A129F816E47DC8DB2281B8D3AEF339E50D +:10FA30001511E82F47D5D3CD82E3FAF8C68D77E9C3 +:10FA4000E13A6399DE2FB196E9E12A27EAFD924A6D +:10FA5000A39EF1E9E1AA1285005D1AF58DC9B14CAA +:10FA600002F97DA57AC74AA85E616D9DDEB1C29D8F +:10FA7000145D3FEA9D1F64B17A831CBA0E30169A5A +:10FA8000A2720F7828DC76BD6BC63A11BAC023A3E8 +:10FA9000A8FE2982DF29FC5EB5286A03E4D9785ED6 +:10FAA00084886776DF4EC75B87B3BC08F9D2FC1148 +:10FAB000CCAFD07F80AF1C42DB617A2E3BC8FAC34B +:10FAC000D6ABEBF703CE06F7B71EF9C8A89CFFC963 +:10FAD000F5C4C49F06A137814CC07A83D0A0CB8ADD +:10FAE000AF1AEF6705981D9495C8EC206FD24C9122 +:10FAF000E79F08843CBC2662C778E608E27F06E2FE +:10FB00009CD1071CD369B319A64C003F49CFFFB362 +:10FB1000CAFBCFCF1BFDB0EBA45483DF768DC1AF02 +:10FB2000D3F3BF8D18EC971091C09E441C9874FDC0 +:10FB300008A777381D359D68990FFB7A2989E75703 +:10FB400038FD4CE4F82264F3EE1ADAEF758B04FC0E +:10FB50000D1B51E326407D51B04186BC43AED7E634 +:10FB600042BC892B3C68979E61F8F1D27F803F2F81 +:10FB700009C317E0EFB81E7F3643FFEF393D5DBC88 +:10FB80002E4647FFB87519E8CA39E8B2EA588CF72B +:10FB90008B83B21843D7B7D725601E756FB0215835 +:10FBA0004CDBE7DCAC6E684DE24C33AE97C803A685 +:10FBB000503C4CE5FBF5F2BC56472341BBE3C54640 +:10FBC0003B5E096910411EB5B8EF8803FDD831428C +:10FBD000190EF5691D836357417E7E8B25363152A0 +:10FBE0005DCB4E4B2EEAD38E9D0966893E5F6C76C7 +:10FBF00099E1B9E2C45A11FCBD6BBB08DA05C589AD +:10FC000004F3592F36060EB3F729588743F73119F5 +:10FC1000ECD35257CDE4987888CF52DB46023B377D +:10FC200016FDD73D836D88379B6B69E9B7E8FE0EFB +:10FC3000268844F052FC788827007A20D1E9F1C365 +:10FC4000746ECB4980733DFD0778D1F402E5F393E0 +:10FC5000E1F8C825616DCC2BE8DB23B3F5F891887A +:10FC60008275162D5DACBE8C8422E7593EE4768306 +:10FC700016DF3FCEED86633CEE7698DB0D2D86F8E1 +:10FC8000CD5BDC6ED8C3ED867DDC6E789DDB0D6FC1 +:10FC900072BBE100B71B7AFC05A236415E711EB152 +:10FCA00087C05F3858C3E0EC5E25F8CB201FAEB4A8 +:10FCB000FB4AE87DDB2A0BCACF91896A13C4C76D62 +:10FCC00055EA14D8877B417B135C9B8ADA12E0FEED +:10FCD0003CE5F471F0B3815EA6E5707EA7785867C5 +:10FCE00065705EBF38C6B312E85959528EE31219D7 +:10FCF000DCECF41FC03B61912A001DB8158B0EDEB1 +:10FD00003506F8CE837698FC88067AA4F09C9ECDC2 +:10FD1000EBCF32492683BB1A05708FAAE1704F8B57 +:10FD20008FC827EB39DC35B8EC2CBAD9A4D2A16F37 +:10FD300025B2BA89B70A6E361DA4EBEF9445CCBF45 +:10FD40007626F23A41FE5EE37CEF707B765D49FFFA +:10FD5000F1BA437C5C4FBB9548B68161F394DC6F8C +:10FD600091E8F35581FB92802FD60DD0F2C41EB4DA +:10FD7000AFA78805BF4DA6EB0CF23A484D5ECE21E9 +:10FD80001C3686F7BDC5F7D9D77ADE2AB9C122D18C +:10FD9000796705EE21F03E9BB9C11D5E5FDAC9D7D8 +:10FDA000B766C69D04F83238E26C3DFAF13E9B041A +:10FDB00076F7C844CF6AA00377A262F936BD3F9DAB +:10FDC000CA43C905CB6ADF190FE3E8338F13A09745 +:10FDD000AB37033DBC956447B9D3D77A2ED2237E87 +:10FDE00082F6485F7A84CA1FB4876CE59F1C07BF00 +:10FDF000B692347802F4B960966730F031A9B2A0B7 +:10FE00007E4EA3FFC2F36ADAB5D2A0BF1D5E4BBF20 +:10FE10007278E485C656F03BDE02FEC13C2889813B +:10FE2000FA9C60F99D76804F4552CA2EC00F29B6C4 +:10FE300087465338AC29587D13C06B4DF952970053 +:10FE40007455988AFDC162FB69A8C8E92A5E9324AB +:10FE500085C17BCD7DA448017827DDED5E42F79515 +:10FE600092F8C74685F24D9785F93DEF94FC3E31F7 +:10FE7000396C7C4676F1BF67435CC7CDE87C8C5516 +:10FE80004989541FACD179535134C6654ED6B07AE6 +:10FE9000057A7FF572FAA842F5559BA7978F1773DD +:10FEA0007A8A1ADD5D0FE395FB6C12FA67E282969F +:10FEB000E5B45D05F612D84F8F58902F357E4E6A07 +:10FEC000D0CB4DC5C0B75506BED6F8E9379AFCEC85 +:10FED000E5E318C06B540DE3276D7FC67DCDFB9223 +:10FEE000DA39718418FDBB7717A546333D1666DFF6 +:10FEF0004E40D92459E9FE66717A9AC5E98992E49F +:10FF00004E58CFA17B52A701BED426EA07C0DA56CD +:10FF1000587AEDDF14D82719E0A5FB9FB55C4C0794 +:10FF2000FF94DC65E9A5C714DDFBB05E604E781B6D +:10FF3000E85595DF013B02C299F0D23F9D38BCB72E +:10FF400099BEAF73581C69F2E07C1F31F928E17C3F +:10FF5000870AC4015EE8FFEEE87448E193707AA571 +:10FF6000F38754D65F7D4F6A069A9BBCFDE18AC138 +:10FF70005041467CE596DEF1F0BF5233E27FF60A4F +:10FF80006113C4FFC6889F9FDD4DC7CFAAB4799A7D +:10FF9000E9FCB31FACB580DD5FA92A7BEBE8B84A6A +:10FFA0004A177E17EE43C72747CCC402F31C9105BE +:10FFB000D24EDBB366E9F9A67A85BE6DB4478EC62C +:10FFC00028234CF4F94F041BD944AF3B372CDD08F0 +:10FFD000F37DFCA00DEB0A09BC2B07F400E1F1490D +:10FFE00079E33DB4BF76BD8D405E641EB7F7E37222 +:10FFF00092715E9363013E5FD316837EF1E90D43F8 +:020000022000DC +:10000000C703FE5B0735DC06F5D41FC72AD580D7AA +:10001000DA35D798203ED21ADD3E05C67F6222AE81 +:100020004DE9B42D3D6481F57451FB00E2ADDA3A3F +:100030006B5AC3F00FFBCA6171DCE926A26C8E60BB +:10004000D73C9A23703D4B545BD8FA37E448787F0D +:100050007ACAA09687E13D14FB2E0F870BEC7B0A32 +:100060008B8BB6267AAA07D3F6470271AD8C87AB85 +:10007000FC01F0A7FA031B7906D14F70BC75F8B0EC +:10008000A7DBC2FCFF4CFEDE53B1ACFFA43BDA0F92 +:10009000FB3C29B1B6EA76FA919ECD4ADA9C18B6B5 +:1000A0001F61089C8260EB3B1A235953101F447A4E +:1000B0009EAEABF691C710BF5B287C803FBB5C5205 +:1000C000CB4EBA8ED35459ABD0EF7E7C0AC0F3CE60 +:1000D0000C4AA80917C3A9316710AEE7F4FAE6186D +:1000E000AC337111C53AA4171E35ED5BBF238C47A5 +:1000F0003DAF32F9C1F84F2061F29DE2777ADE0F11 +:100100002DB5B0DF28D20E7831ED59658775CEABAD +:10011000B1607ECC497C65204F6B1E11B04D7FD6FF +:1001200082BEA8E5FCD52A0DDA07747C12EC71F4C6 +:10013000F79ED80BF501355C7E552DD2D3E962B719 +:1001400059C72F3396EBF987EE53D7DE98C3EA3AB7 +:10015000BBBC1FC7837E6EA5DB06B87CD222F837F6 +:10016000A17CF58D08AFAF1B9363D2E2F092250C12 +:10017000FEB594FE6A416FD8497B09D83579A3A7AB +:1001800002BD5B8F46E33A8DF0FD6787C3A924A9C2 +:100190007A305DCF294AC750FF73724333DA2FF0AC +:1001A00023EAF8DAD502F4BD84AEF27117D2A7754E +:1001B000C6B85E7AD1E053B33E791F8C73FF678C6B +:1001C000449D2752E3CE5F0AF6640F1D19E0037BBE +:1001D000366BEF49EDA533EC8F406765742CC38B0C +:1001E0008AFC5253DA93D71BD15FFD32E23B9FE288 +:1001F000B5237D3EE4A13439B7AEE84DA483732E18 +:10020000E217995FFB36C8FD18BE3695C881BA78EB +:10021000502654EFBAF01EFACB717CBFB1CB856388 +:10022000A599840C5A2E1E2BA537634B8301D0133E +:100230003637D7BBDB737F3566089C6E2018A7194D +:10024000105DEE09E06E5C09784EC1E24A00FBE702 +:100250004141A882B8FD00A2B7ABE20CF02059E6FC +:100260008FC2EDF2682EEF974E4915D0DF29D3FBF0 +:10027000A766835DF4AB1C93E65FE055825F291CA3 +:100280005BA8FF06726A50A0BD1DE8B39ADAAD7E86 +:10029000DCBF07F33AD652813C2EF4C6AFFE51F1D3 +:1002A0008B8BE2603C7ED1571C4C8B0754B25BD4E5 +:1002B000DF51DC90F7AB74533F6700D85937BBD19F +:1002C0006F729F46BBD4CAEDD2A8D18B5C2C7FC67F +:1002D000F8478B0718E9CA185732F29FD12EFDCF85 +:1002E0001C6E3F5D4DAEBE92F88016C75F93C6FC94 +:1002F0009E3569B52BA17EED3CF77B5CAA09F138F0 +:1003000067968078D4ECB539DEB3B380FFB4FA8356 +:100310004BF93D6D063F24DAFBB42C47D09F8E5C31 +:1003200046478E02D63FC74ECCF6B0FC813397E9E4 +:10033000DF39540FDAE916A7F3734415449F9F1A67 +:100340009ACBE4AC76A53FC18C1C5DBDE0D0DCB09F +:100350007CA88DE743EDBC5EB038BD7BF757705F7E +:100360006675C036B9E6C96F533844CF8AF19890A4 +:100370007E95677E087EF22C07CADBF83409EB5EB7 +:10038000AB12ED1EA47D557E1BFC32B43325D892F2 +:100390008CF2762EE5DF80AB1F7FC7DE7FDCCCA939 +:1003A000F93B058CAE7AE24B3E26BF4DF41FD0D30D +:1003B000EC2A3DBDCC55FAA79FDC5CFD39AE31A1DE +:1003C0000B3BBF42BA60FCBB6E04CB479F2FA763B9 +:1003D000207FDB873DAEF9B74E0BF58B285E82F2AE +:1003E0006EA4F7601AB184E3DB5720EAEA1B827936 +:1003F00024DA45FD9EA085243D48C70D90E75EEFB9 +:1004000002DFB7D81653837AC3AFB3EF0FD1794F5A +:1004100038FB5E8791CEEF1BBD04E3FF0F5C4741C5 +:1004200046D77F1F249CB15E6FCB7CF0DB1E8036ED +:10043000D6DFFDFBFC62684769ED6D3F92C3EA0DB4 +:10044000EEC90DFC482DA07E8D9DEA5B3A9F4322AC +:1004500098A7226433CA6711E281209FC786C1171B +:10046000FD063DBC8D76BC58C0E228A281EF8DEF21 +:10047000BD3D97F339C7535FFB363E477FAAAED6E3 +:10048000D3FF7772FBA997353EEF84FA89982BAF9B +:100490003BA08214F3D3223179C05F262504DF27E5 +:1004A000B8185D8184013D686918E041B8D17614BF +:1004B000E805BF438BABE2A2A300FF22E41303A82D +:1004C000CFE95242422A8CD7EA0F14F295E3F2E5C3 +:1004D0001E95C7388F54C6F2CBEFCA2404EF1BF326 +:1004E000F87A5F0EF8EB47A99E95408FDFAC42BCCF +:1004F000AC7B05C1FC80C3A5609BBE2AD4EC82B84E +:10050000156B575318815EB6B9F5F5AF3B8B1E2FAF +:10051000B6D2FE9652166F3DD418787715A5B596CB +:10052000827C9497AB6060D87A83BBA2AC10875171 +:10053000D46FD9C16EFE708568856B70658D0A9B1E +:100540007E3741DD2C4810775008F8F9D615CD5389 +:1005500080AFDEB5A89E414ECCAB629EB875A57A41 +:100560002BF83DB2545E964CF96853AB19CF199DE8 +:1005700028F97DA214C6879FE732BFE1E0CEA80725 +:10058000000E6B047B280AAE1665D37DF1F03EABFE +:10059000A7892EF1DDA68793E03D6B16AFF1EC82C3 +:1005A000FE261B9C40256B36D8AB60DE35494BDC04 +:1005B0004BC2E6B50FB736C0FDE0B016AC6B51CA02 +:1005C0003CD6A858D8D7E731909F6D5D911907B4F4 +:1005D000D892601D5107E396FCE9B7B98077C984CA +:1005E000795BABBBDD02FB1EE95654C88F9B72944E +:1005F0000340AFF3969F98827573A5B1ABE13AF2D1 +:10060000C2EDAD00FF77793C2694508BF9DA964520 +:100610007576586F4542CACAF0784C4BC162FB18D8 +:10062000FA5C8ADB54B374C0C5F4D102F19709B007 +:100630002EBA9F7130EE8F8D0A1D174AB256453A79 +:10064000A7F509D747F6E6A529101769D96087F4F9 +:100650000C691194F5901F50939D11EBD833BC0C8D +:10066000EED58A6B8A5542FC20BF7DBEF5D88FD46B +:1006700051605732FCD9CDC46E09D37F19D9C567F3 +:1006800072C3FCE88BDE9BD082FAA04560FC9BE144 +:10069000FDE247502FFC7CB6AF1BE0B7A655590FC3 +:1006A000F022AA9D0C28EA9B4F42F7911184CAE3DD +:1006B00096265B55A43AB4D022713AF009E5A0130E +:1006C000034684C9E5957529101F09355D85DCDD74 +:1006D000337E83FD03C04368435A2CE8C350526DF8 +:1006E0004A0AD02DA74BE3FC5BB81DF062A62FDAB7 +:1006F0000B76E55896F79C91EB73629BB4BBC1CE29 +:10070000FD1AD06D2AACF71F48B7A8E73ED9FA1FEB +:100710004857C47579F9481F0999319F5AF4178CC5 +:10072000F7B68DD3CE3FB1F8A066F7468DFE6815BB +:10073000F8ADBE3C2DDF55B017FCF5E95A3EB59C2F +:10074000C5075DF45FA4F8A0CF101F9C6E686BF620 +:10075000E60D5EBD7D9B28B5FB4A40EE1E103DE0D8 +:100760004F2411A65766940B7EB0B39B8AA2EDB8B6 +:10077000EE3C1EE7E4FED73CBEEE638D7602F92424 +:1007800093A36035AC7F7A3E5BBFA33E3D3B2081A7 +:100790007C67716E526F93306E02C84F203D7E9A17 +:1007A0000F26A1FB9957BF14EDFD5EF835B1F81087 +:1007B000D1FB133E62F01F16317B4CF3B7E61BEC06 +:1007C00003A3BD6F8C53F7E60536DB819EBAC7667F +:1007D0001C4A91B05B0D68F9003A6EA1B773752899 +:1007E0004CFE7472FD70A4513EB68AEE7FB5EFC721 +:1007F00076A0D336B3DF0EFAA4ADECCE18A0BFB608 +:10080000056219F07DB0B10CC71D6CF4E1759597C8 +:10081000C9BB60B6BCC21B1677AE2C2B3EB62ABC39 +:10082000EE41BEEED8AAB0F5577867E8DA1A9D55C2 +:1008300088A4617304F9F2BC97D9ED66AAF7B1CE2A +:1008400050FC85A7BFFA1BEAAF7687C3EF41AFDE46 +:100850009EBD7F6CC9C0FEEC166D7F1A5CB47D6BCB +:10086000FD7DADF37B7FE33A9FF5EAEDB94BADD368 +:10087000B83E6DDD7D8DAF0061350CD659BA00EA0A +:100880006283D94A07C8A3CA526135E44B8FF07816 +:10089000E29182183CE7BE378DF97BD1F58C6FA2CF +:1008A0004B6760DEEF4AF17BA397D995B30A04BF8B +:1008B0004C7F9DCACFDB1F4B63F9DCA6A29FFF16BE +:1008C000F2D0EF145A58BC97C8D3A785E5B1D659D2 +:1008D000FD01C8271DEBA9D358B6FA6EDA8ED6E40F +:1008E0004A953EEF306B963E7F5861C833441BE417 +:1008F000CA518D3E7228DC537BE1DE973FD1177DD4 +:1009000010F3D92CD04346F8DC66808FD17FA9D86C +:100910006EE087CBF46336B566ED85BC9A4AEDC9C7 +:10092000D1803FE8A2CF45CBBFC634C8803C468FBC +:10093000634267D6825EECA42A00F4CBBA9977AE04 +:1009400087F679AAF7012F7DBD47F3DF9ECF96BFCB +:10095000F446A81FE89123601F4C80BC6064FBA094 +:1009600073D1E46911ED83997529D9B0AE197AFB79 +:10097000A07343D99399701FEC03FAD39957A7B387 +:100980000F4859E625E0C3E46ED4E8AC88757AB325 +:10099000B395C17961FB71A43590F07AC6EE1C79EC +:1009A00008F4CFE07104ED7DD4FEDA638950BFA86E +:1009B000BD2FD7CBEAF049591CD30FFC7A293C6AEA +:1009C00075D4F75B64FCDE8B16F7D2C665E731FBA6 +:1009D000B03545AE877EE2CCB8C4BC4D5A9C232DC1 +:1009E0007D08AF1B96488F3FF41741C2FE08FE1EDC +:1009F00081BC6474E2D93D2E3AE433AF929F970DE7 +:100A0000E728FC2AE4436CE502DA4BB6448276CD53 +:100A1000E5FA57973BAE158A03C0DFAA65F1F2E20B +:100A20007433B6A3157113C8854917060A20377C9D +:100A30008AF834AC375AFEFCD31F83BEA67A1FE275 +:100A4000303ED280E7AC9D161FC627DACAE9CCE952 +:100A50001087596949C1787AF2AF63DCF0367F2B91 +:100A6000C4CB6D1E761EAACAABAE86EF6654148E3A +:100A70001608ED9FEE63F19B3910BF8179679DDD0C +:100A800009F19FD95E26BFC06F03BD39B7EE3BE3C6 +:100A90001E95FE9AB88DBF352E0BE34912C60B0C7E +:100AA000F1215BC1548C0F69752ABE0211CF779377 +:100AB00044277E87C218DF31C6738CF11E637CE742 +:100AC000EE3C5627ACD953DFCED3DB532BE00CC220 +:100AD00060B097A8A8A47CDD662149ED943E0F156F +:100AE0007F42EEA2EB70FED00435E0749C21CE78FC +:100AF00099722B48E5CA29D8C8EE372CE0DF2E9032 +:100B00006B30BE67A4FBC7B8FCBA2FCFA9ABEB080C +:100B1000362EE7CF47A980E705A3ACFEA8E4DE792F +:100B20002E973F9ECA911FCE637EC50F81CE894707 +:100B3000C1F30433725D3ABA250D83C9A9B0F88DAB +:100B4000F1BDDA7AB4F9AF741D0F71785F2E9FACE6 +:100B50002BCAB75BE9FBCF511C8BA82FA9411D16EF +:100B60009FD6E2E7DA73D59037C8043B52C0FC81C8 +:100B7000763F2C8E6D06BA8D4E54E448DF9B7A3B4F +:100B8000AF276E8A794CED3D4450502ED4F17C8DC8 +:100B9000369F99B89B900F80B6B5758911E2E6C46F +:100BA00063B75192A95D2B1288FF3889DC0EF1677B +:100BB0006BAB05DB44ADDA0776FA22CE17D682A9F5 +:100BC000FB20AEA6F185316F631513A7C2B475ED96 +:100BD000FAFC95313F65B4A7B5F8BA99BE04D6754D +:100BE0000EF0C1F6EB172F6FBF4FE37EBEA6FBD50D +:100BF000E8AA3CF31637D49FB44429EB6BE8BAD487 +:100C000027ED18AF70C0DA002601FA0FE4E493DE96 +:100C10001FE379F67CF65D9A1681D5A3EC49F8635B +:100C20007CF8F905533EA39B9FE549388EEACF0037 +:100C30009C972263E3912FB4FA934309CC0EAC281E +:100C40005C1CB893B6FF8DD74B5E53F88C96EF1FA4 +:100C5000509C43B0F403E0B2CECAEAD20E7DC38CFE +:100C6000F564443CB0EBCEF8DEBADD6B36EBFDCA82 +:100C70001BD2F4F6A0D1FEB31ADA43F38D75648A61 +:100C80001DEBC812781D195FBF914F7EDAC8F21AAA +:100C90003FE775FFBFE0E72F7FC9EBF736F3F39728 +:100CA000CFF373B31ADCEFB728188F3E711DB5E987 +:100CB000627BE380EB8ABEEBC6F3FBF9CCCF9A22D2 +:100CC0003A77819EEA3D67D1FF77C22ACBF479B3A8 +:100CD000D93E7DDE6C6E953E6FF6FF32E5ECFC6C26 +:100CE000388751BF12BE5330639588F9CA752DE716 +:100CF00050CF9E2F406BFBA2F71CE6E730B4731C6D +:100D0000DAFD6BF3D9F7911CBB122C508F3F635562 +:100D1000EC54889F1357C665D96F15107387FCCFA5 +:100D20004A9705BE0731239080F1D09AD62B9BE7D6 +:100D3000BED143304EDD13E757C7DE04F2F9B016DB +:100D4000E727D7DC0471FEC33CCE5FF3F2B827C1BE +:100D50003FFA599E3C17E0D1942757C1B586AF871B +:100D6000B66FCC1FDCDBA63FAFC7EABF3F5193DFB6 +:100D70004F3C5D9C2C3444AA17B939BF27CEB5141B +:100D8000E627F69E38D737613E626FC77376F7E67F +:100D900033F9D47C8CD4C33CCD2F93FAE723D8DD30 +:100DA00077E50BDA7CDFC2E7DD9A7EF3DDC9E6D7B3 +:100DB000CF27DA624780DF7F82D79719E7BB37DF1B +:100DC0008AE3E87CDFC3F9127BD6776FF8FA7ACF33 +:100DD000CFB86280691DD58AA98BD2136911B1EE93 +:100DE000C4D1E19A067549646A2AD6B11C2EADFCBD +:100DF000A7384F73B8F4857FC9F334DBF2932FEB38 +:100E00003C8D63265122C535029C2E7715640E0C4D +:100E1000F58327EBF2FD41B0337ADA668540DECF09 +:100E2000BAFC20DEBF3FCA551DD1BEE0F2ADA574AD +:100E3000910F52426B92A68AE1F6CBD92CE5CDFCFC +:100E400008E713CF8DEADE0DAA6966A96016E2D124 +:100E5000DEF608547E66AD9821BA2542BC0D0F4ED1 +:100E60001E4AFB672552FF2E6CDFF9F5BFDE4DD918 +:100E70009514941E6E8EA7E376E4286F03FD16B9D1 +:100E8000A53DD09EE54BC7BAF7FB6309DA79274643 +:100E90005BFD9B922F5EF7EF7AE5F24AF315C8E50A +:100EA00096467DFE7B4DD29895B0FE3125240412E6 +:100EB00036C57DB618F27F19D9CAEF605D296E225A +:100EC000DBC6E37D9984E56F8CF30E98C8F0342679 +:100ED00094F80388271FD2FCFDA22BF6F7FF180E0B +:100EE0006FE3F584E6EFAF8EECEF9F581417391FD0 +:100EF000D052570BF98013ABF5FEFE890DEE6A3820 +:100F0000E77782FBFB27A6507F7F6CDFF9006D9FA0 +:100F1000540E3927EAF201DC6EE771EDD9D9F2C03F +:100F200089D9E8CFBBE0DA9829C7E278D575139E56 +:100F3000472691CFC992275C32F839DAB9F65CAF0F +:100F4000320C9ED7CECB8E01D13608F2A2AEDB2278 +:100F5000D1F368BEBEBF3E4FDA93C734E139EACB66 +:100F60008CD35FEE38C9BB99D5E398599D61544243 +:100F7000891BF253E7C7DA51BFB7C2FFC2F46A6AEE +:100F8000BE3271E2E0F0790CDF57952EEFBD5A9D2D +:100F90003EE82BD02F9D849481BC7920B601E31EBE +:100FA000D771B819AFE513395E892B1EE0999AEF16 +:100FB000BB01F0415EDC2CE17760F9FDBEEAFB8D00 +:100FC000EB78D6EA7B1FCFD7978812ABCB23C81715 +:100FD00057A5B9504F6BF6D7D2894C6EDA48689452 +:100FE00095EEB359DEEDCCA4E33E7CC29C0E8F3D62 +:100FF00017432CB06E5F1A9573741F256E65647F5E +:10100000F211BE4864F2C2352098DC788D635755E2 +:1010100080FB17F1E313DD83C11E7FEE49969FBA73 +:10102000EAC945F6DAB0F99F98C8E566225B7FB554 +:101030002CF8A56458CF59CC43CD904C1E9940DE76 +:10104000F8FCD1B91027A4F6DB686C9FC376503248 +:1010500065425EFB43F7174761FC55F72E1E82F48D +:10106000CFE1B17045E6B368E7E728DF05FC070B81 +:10107000CEC5A48E453B7E3DD0FF4281F822D909E2 +:101080000F71BC5D2F37DC087476BD6C23706E2D3C +:10109000586C43B83F572848E0B75600CD433CE76B +:1010A0000933C69B293C9641FF018F03BF1B5D227C +:1010B000FFDA0CED3F8E13C8D07EF4F115C3B5E016 +:1010C000DC60E0C70F81FE22AC7F295FBFC64F14F2 +:1010D000EE25B82E99D58BF44557DD79F2934097DC +:1010E000AD294A3D7E17D135F3B2BE8B58F1533F3F +:1010F000D6EED97ED2308C44A8FF3AC4F9C478FF2A +:101100009713997D770BE78FAB9EEC3E701DF0F542 +:101110000A8B0BF0FAB33CDF66584F8FDFF57796FA +:101120002353C40588BF60395D3B7EC781C4407BC3 +:10113000FA2833E24F2DE1DFF9B89BB89A63F12921 +:101140006CDB5708C8670E677B1518CDE6BC86A315 +:10115000B3E1B96211CFF5879D73E9B78E2CC4CF87 +:101160009FB5C0F9336ACB075789DA77B7884065EE +:101170005BB0D4CCEDFBCF9E94E9AFCFF2FACC9329 +:10118000AF5A36421DCB51136BBFFDAA65C44AFA54 +:101190009ED008B68EB607054F9304D7A7D743FE57 +:1011A000B26EB9E029A3EDEAC03D5D10E25AF288C3 +:1011B0008D80ABF0F10F974E85FD9C7313FCBEEC58 +:1011C000DC04C6374A90F84DC9BDFEED0749C4AFEF +:1011D000E54BE11C9D97EB9987E01C1B5DF7B5EA99 +:1011E000B7D4EF40DE94FABD10571BE461F9CCE8A8 +:1011F000A0D9E327E0EFB2FAC8961F08E421984788 +:101200005CDB0CFEB98DD7EB46CB35E83F0EA2F484 +:101210002981060D9975E7D8EA8882F41B5746396B +:10122000231DAE7AFF38EB12E7D9E6DE343816F824 +:10123000E52F13F5E732FA8AAF6B57F8DE0DE0A71A +:1012400083E757B751BB1DF6FB32B5DBE1BA9DDA38 +:10125000ED701FBE530D5738CF06D75DD46E872B68 +:101260009C67832B9C67832B9C6783E7E03C1B5C1C +:10127000E13C1B9E3F2C540303013EC5D104F243C5 +:101280002D1646676A9215FD8D4021C1FC7D30C93F +:10129000BA6925C4EB0486273596F50763949BB19C +:1012A0009D3C96E577CD9E11708E7095305602FB71 +:1012B000A9D5AA60FDF289956602F5CBA169C2FBAA +:1012C00090772182C92352FB66C757B721FC17CB01 +:1012D000C40475E92BE1BBA1208F3F259B587C2ED0 +:1012E00028C2F7E59A6308A7C73ABF4C65F669417B +:1012F0006B1F52C09F9D043101A4DF030AF42F5ECF +:101300002EF076D02F8F82BA06DEAF1E7A0AFCD777 +:10131000558676A7497B3EE52998EF68CFFB465472 +:10132000CB40EF295A7FE242689F8AD29EFF7C2100 +:101330009EE7D2D6A37E8AF38592B4F1A9D5D01FB9 +:10134000EAA9935B82EB0D0D66E3FF6D57E7D3E0EF +:101350002FFFBDE76B56548CE3ABB3087926F662DA +:10136000FAFA7892A88F87CA822E1EAAC5DF4D8E00 +:101370000543F1FCD90336948BA79208FA217DC569 +:1013800045C3E2F51817FDD524AD9ED910FF240AF8 +:101390008179AB201EE8C1B72AE1E7D388D040A00D +:1013A0004EDD772646023BD29A1816BFE332A0BF25 +:1013B000786173038B0F06150B51937BEBFAAD0528 +:1013C000BCAE9FC70BB53A066BC1A3BABC81315EF8 +:1013D00048C465988FF62DD2C7032B942B8B172EFC +:1013E0002001CB50A07F59F080FFBEC0A57C300407 +:1013F000EDFDABD9F719A5D7316EAA9D1B833BF044 +:10140000DDA92ABEE7B65B4FBC3F848EF3AF8C925A +:10141000E030FEFC65C5F87C1EDD21C4B76A0AF128 +:10142000F02DC9FED4F3BA04F2D46DF23033CD7787 +:101430006F02D80B8B62316F72D35DE91FC03C8B9A +:1014400055073E47ED4A4EEF2F6D047A1221701971 +:10145000D6CE1AA1D15BD546E0AF49715A3BE629F9 +:10146000E08762ABF6BC17DBF3148DFFAE790AF4AC +:10147000C7D1128DBE0F54C3F3B3537BE643FA9E1C +:10148000E4D0DAD317427F6BCF7C4B36C27CEFC0FF +:10149000978DB03DF529E0E7E2195C5FA91F6D84E7 +:1014A000F95B1668F34FF0C3771EE79BB4E7A3FC24 +:1014B000B07E85686D2ACF68FB3DCEFFC70A5EA867 +:1014C000067EB9B1A7FF05DCEF02DE3E5E50F714E1 +:1014D000F4FFCBEFEF7FF87DC6F64D2438656856F4 +:1014E0002F5F18E5D56F8B981CF1D6FF1AC8952C85 +:1014F00068781ABFEF06F10096CF4A98E503796144 +:10150000173D943388CFEDC238A7719E9B0B595C71 +:10151000FD4C813E2FD662C88BF9787EAAAF798EBA +:1015200014B1795A4B22FBB119D9257F2A80FA01CF +:10153000725684F95C1460F07DB2964CE5FFC37D71 +:10154000CABAF8DD4D2AB23C709FFAC52AD899D3A1 +:101550002938210FDB54F438C6E9437916DDF7400A +:10156000B43CE73AAB8CF2F1635ED731BF449E7274 +:101570000FF0FF30916CC23A0F27E61BCCC3AD4F82 +:10158000A35CE7794FED7B1CD32F712EC2782EA57B +:101590009BC3FF5C419B05E4B34AD429A55928AFFE +:1015A00083506F6C72ACC53CB0ADC88279042DFF1E +:1015B000ACF0EF7F6B79DF49170632FD9EA6C5754B +:1015C000FBCFFF2ACB77FAD03E68178949B8381F7E +:1015D000BCD8A726413DCBF4D2183C2F5055FB0672 +:1015E000CE7F7804C1EF0447CF6AC0F341666A1F1B +:1015F000CA00179E2FD6EA63465EB81DCF8DD66906 +:10160000F5E662F941B0536D8F513F0BD997C14553 +:10161000CB17CF30C8FBC50595A86709B5E347C709 +:10162000C27BFA3FF7FCF0A458A49B8FDA593D7FA8 +:101630006121CF97F03CF0FD1616E76B4DD1D3D565 +:10164000CF27317F65FD244677BB8A7E5E85F633E2 +:101650003179202F469E60DF8583180B9EB7327E3E +:101660008F396D0EDA754F8CA45BA4B6B679F97B11 +:10167000185714D6B3E73E1D4F1AC06F319B599BC4 +:101680005E54C8FFE77A9599855097B5FC031CDF37 +:10169000ACB27AEFBEE237D5859ABE67F19BF9EE20 +:1016A0007D5D70AEEC6F8EE318CEBDFA24565FD22E +:1016B000562069F946FC2E21255C0BD88BA9F9BE72 +:1016C000FA428C6F6D96601D9ABCD957741BCA275D +:1016D0002247CE4B6B7CDF62C84BFBDCECF923AFBF +:1016E000DD530D7F17A2AF3CC4B3C53D7983E5F848 +:1016F000FE782D6F20DF03ED5E3D4A37E4D5E9D15A +:1017000085F5FF0BF4688FDDAE76A11DFB755B3FA1 +:10171000A5AB1710AF652C7EF6755BBF3C517E13F1 +:10172000F8F9BFFB3DE9137D5D00A7FB04B9CAC909 +:10173000927B1E419FE7FBA0B09F3CDFA5E20FFF1D +:10174000176FE83FDE602FD2E7E1FF59E20D0E3858 +:10175000433518F928B108F8A880F1D1BFBADCA345 +:10176000FBCD2F827CBAB0D91F9DFAF7F7F753F360 +:1017700095B222D4838A6917A59FFB8AEDCC9E0976 +:1017800030F8F6C633E8FABDBA78C653F5FF0DF166 +:101790000CBADF2AC46F297FFFD71F7F77207C65B3 +:1017A000664FFC0BD2E703B8BFCD6C7FFF80F76FAD +:1017B000447AF905A3975EF8303B290C3E0BEBFF0A +:1017C00031F0791EE1B38DADEF6B80CFD7119E1E46 +:1017D000B6DE4BF9D7270A044D2E1FC27D66313A7B +:1017E00038C5ED6BEA774F1E2AF5FADD4FE5C86F75 +:1017F00015313BF76891AEFE537E1BEEF7E3171FE2 +:1018000083FE087E7108EE7FDDFCE2D8429647EC4D +:10181000CDBBF8D9776F49D5F5DFA0EFF980C21BB2 +:10182000E26D6DCB45B42FCE2712FC1E80666F840F +:101830006259FDDEC5E7C14A099C47B4E5B1EF8CAA +:1018400068DF07308B0B0606A48BE17A7080628517 +:101850003AAF25727A0B9C6F9DBCF6733C77659509 +:101860006DF8773547BA3D96BBC08FA67EEEB510B2 +:101870004FAD77E1393AED5C9976FE634960DE3E23 +:101880003867DB46E92181BEA7A2D472327CFF46CD +:101890007BC36C681BFFAE69C2247DDE83C21FED73 +:1018A0009FF3EB597D5C9B99EC82FA8F3A55F437A4 +:1018B000D1F6336B05FC1EE7220A27F0F727B7277E +:1018C000633DB935917DEF4CFBBBA7940EDAF3C0B5 +:1018D000FE3B2A12FC3B76FC3C99F69DEFA869671B +:1018E000F17B5BA7E8FEE1FB3DDA772666703AD133 +:1018F000E019D5148770394FE142002EFCBCCDF4BD +:10190000E52C1FDCB2607110C8BBBAE0F35591EA58 +:1019100052E6B8F5DF4B37C6338CDF1B3713DF4099 +:101920003857575150AC82BD6AE3F59AD144C6EF9F +:101930005A9C5AFB63F65D8B528BEE3B22C6F746F0 +:101940001BE8D466883B18E9D4889772035E9E3101 +:10195000B3EF0CB6748A1E95DE6E7964512B9CCB66 +:10196000571F31B1BA7922E3779F5AA8C58BE7CFC9 +:10197000E962215E3F97C353C30B210D16E0B70503 +:10198000DA397453C36A384F3A8F9F43BF916CC69C +:10199000730637810541DFBB1042E4227C5746B213 +:1019A00032E7C045601D7555EC3B1926D803E409A4 +:1019B0001E3121BFB6B877E1DFFD0A0CB3C49E4EDD +:1019C00063FE44247BB627AE4021713A2C8EFF7F04 +:1019D000F1ABBF2D7E35B17010AB9B880AB8F29287 +:1019E000D9F726A09E6962A1C4CE2758941178DE4B +:1019F00061C3272AD08176DE81FEAC18A2FF6EC2B9 +:101A0000C649FDF87F258584D54727879240AE7D5E +:101A1000D0475DE5E1E29EBACAE72661FE9DDABFE6 +:101A20005920F798FD3B23D7F7B3496817B373CE16 +:101A30005A1CE933AFF24B185F087F3F270BCFE703 +:101A4000F8E1FC4E8553D82B48BDEF27C63AF6FF88 +:101A5000A579AB7BB8DF168C22F81DA46032A97A79 +:101A60003E023E9E29617644303D32BEB47E6A67B6 +:101A70001C9FC4FDA1018C28CE58F5F18193809F55 +:101A80003EFF0E1DC7E3E829F2478877DE7E385710 +:101A90002132D4F72ABEF701AFA7555102BD420249 +:101AA0000A7ECF6FFAF74557A4BFA7F8CF7EFD2F68 +:101AB000E87FAE8400800000000000001F8B08005B +:101AC00000000000000BED7D0D7854D5B5E83E73A5 +:101AD000CEFC24998409061C24E849001B6DC0E152 +:101AE000279000813393842490C0F0A741221E08E0 +:101AF000D0DC5EB44111634B9B0381102222BE8B6C +:101B0000AFBCFEE824185AEFB37DD4CB6745D48E22 +:101B1000012D5AD4E0851A2BA54110B1CF7E8F5EDE +:101B2000E5B5CFE7FB7C6BAD7DF6CC39930920C6DC +:101B30005EFADD3B7E7E877DF6DFDA6BAFFFBDF6BA +:101B4000492D8B3AAFCD628C6952A0131EB53EFD74 +:101B5000E4502CB39B59E74478A88723F224C65657 +:101B6000B2D84F7540B986FEC558DB5DA77E3F14DD +:101B7000DA4536A6A86C3A634B5607A97F11F332B3 +:101B8000199E6DD372181BC258C1B9C06115CABA6B +:101B9000DF11906898F0778741BFF08A4CB50DC689 +:101BA00059560CAF0A183BE984E714F8DF98B64C95 +:101BB000CB87FE58BE8E3A680CCA4B065BCAD9D09A +:101BC000F4186F5FA8FD35628C82F199D9DF6CFF44 +:101BD000AEC4DB9F0F66470C2F63B79BF550D6B1A1 +:101BE0002CFA33969E1354A07FBD24CAED9A629DB1 +:101BF000EFDA766D1A63679CF6F16BCDF16669AE2C +:101C0000761C2F1C9BDFD5AE41F97402FC77305E49 +:101C1000BE557350FB95B1F60E5AEF594994C7EA79 +:101C2000583EEE12FDF39769B0DEED39BC3E1C1A4A +:101C30001B31B2AF3E78BEEAF1BF303CD354A2AB09 +:101C4000C2FA5F945C0BFFAC6D6897752FD259F8A0 +:101C5000F70CE8D17844523BA14F21DB2B3399C0DC +:101C600076C94097533489B5C15CEB4212F50F7BBE +:101C70001D7C1EA328A2019D2D992EE8745904E70E +:101C8000ED8FEEFEF4D29AC70CEB3A8D354B6D70AA +:101C90001B636D702FEA82F6505E72F73FF811CE2B +:101CA00025B9627D2511A4BF964CD1EFC38BCE7BA5 +:101CB000EAA56AA2F725B179E653FB25A962BCDB48 +:101CC000A91CC7E79D767C1A372EC3F9045CA1D006 +:101CD0009D84CFB02FB219F93DEC670103F0797BF9 +:101CE000FD0659CFB7F09151A5121FF963E5889D04 +:101CF0008F0A888F061AAE9153C23FD440CEB0BC33 +:101D0000BD6A78CC57B16E9093B86E43A2750B3A0A +:101D1000AAF559E8DD03EB564539B0ACDE3B10F3CC +:101D20007697D1BC1F01BE599C9F98919BC03F974D +:101D3000375EB377B90BE15EA5495A04DA7F8EBFEF +:101D400019F1E7E9699CDE019F2F6BF0648580CF74 +:101D5000747CCF488EEF9B107E95F0ACEA8E2E807F +:101D6000CBA579581BE060DEE4F06FA83DDBE147CE +:101D7000FC0300D4BEE5285390CF80B7028EA95053 +:101D800076B29ABD49E6FD69C841F3363356B117BC +:101D9000E09BB8D1B72AEC8DD7E79671B8547CC2D6 +:101DA000B8C7D37BEF1802F3F732E6DB08E3371B43 +:101DB000C0BCF07CBF5E8A48B0E6F7B3C3738AA0AC +:101DC000DC9DE3086C84E9BB1F708F580BED7B72C0 +:101DD000BC0184AE277347BA0FC67F3F209BF8BA79 +:101DE000E73DE4EBE3E9317E3250BF749BF83DA759 +:101DF000853A908FDF5179F967A56BDF43FE6279F1 +:101E0000CCC786021EB007F0AA236D9AC70DF3BA9D +:101E1000668238C1BE3EA6BBA0DE8DF5B0C4798F08 +:101E2000EE7E74018E61D4BC32CAA2475D4C317A19 +:101E30003D34AFF2395790CC39293EAE6B67F3CBC6 +:101E4000CDA88FFD320B216FF9797B3FEBDDF0B927 +:101E500003C787721E43127CE97358BF6496F1F77B +:101E6000392CD1CBC2153908571E0BA0BE9DA73BFC +:101E7000CFC4EAF9639B32C98413E191D75714C1E7 +:101E800033B5DEDE6E761E943DF1F2AC9D7521C455 +:101E9000FB2C0DBA8D63ECC8CEBA681DC079A4D0F6 +:101EA000ED9300D3AE6CC5D67E36DBBB09F10E7662 +:101EB000C52119F0B2D49CAFD937EFF70CFAADCAEF +:101EC0008312ACFFF87782E90559C86F72C061B61A +:101ED00071087C306AE77470391D90A07DF37362DD +:101EE000DFB40EE403394DB295832E513FA903F9B7 +:101EF000E2784CAE8E598EE5452305DF0CED403D72 +:101F000039234D94072D47BEED559CA63CBBBE031F +:101F1000E559AB18CFD8457CFD3613F5691D484708 +:101F2000E198FC9BDB8EE55B7D263CC60F491E36A7 +:101F30006B5C9F4C7DE9D55EE30ADA037F16059161 +:101F40000FC35CDE25D64F391669CE30EDBAD16AA3 +:101F50005F7EDB1694898FC2DA9F65DCBFD206C034 +:101F600019EC5F498D74AC00E953612390EF5B9AE3 +:101F700080F74743F9608A4B4D47B9EE9BA925E1AD +:101F8000DF57830E1AAF2AE8CD3AFB75683F814DC3 +:101F900040BA6B696A14FD0DDC5F7D942B9292D37D +:101FA000FF38A74AB81CE8967C0BB97E9619EAE779 +:101FB000E02323BD452CDEEEC5122E0F5A26688B7A +:101FC00083F09C03E297C11E6E98FE837008E63989 +:101FD00053E40CB889CFB4B790CFE69B34F4B04B40 +:101FE000630FA0DC2872FB36A2EC96F39D8D505651 +:101FF0008603BF62B982D3B70EFF7D9E8BE32A7141 +:10200000FA0738E635DAF9416116FA86FAD5C1746D +:10201000BEFE9BD9CDB8FE079DBEA528C75A737DCD +:10202000775BE5D9FE122EC79E36D7DB35FD9F6B59 +:10203000103F1F334700E5C79ED430C9B353198CF6 +:1020400075A0CED798EA1B8A7CCDD721E5DDCAB032 +:10205000FD8F6E80250C03381ADFED2E9D00EF7783 +:10206000F17EE7C6B20686EF155E8687618CC37681 +:1020700027A9DDD6602ECDCF1E0B783C48FBD01CA7 +:10208000F7DBCBF63AF1E9487B7E849E647FC4930C +:10209000AD767E14C303F21268425CB7C474C7E71E +:1020A000B87E53FE039D6E273AADE17A64CAB9F358 +:1020B000367A2B0DAAD42E91EEA0DFA3D46FA1E81F +:1020C000C79CBAC55EDF168C443628A48F7E48EDC7 +:1020D000BCA08FB26CFAE8C7F43E411F4DAAD41ED3 +:1020E0000F16C4CBD07F3795FBF6EF0C26D167D007 +:1020F000FEA734AE47277CCD9BAC3D89E589D70B45 +:1021000079020D0B417E5C23CAE977D64FB3CA9F93 +:10211000C2C751DE2CD625B3FEEB8F237F1F0F09DC +:1021200079736429CA93983C62358FDBE4119B7301 +:1021300027D6C7E40F5BF5188E17933F6CE6E328AC +:102140003F82F3845E3BF3188EDF522BC6BF25120D +:1021500044BBC421FAA744900F7526CA763BF27798 +:10216000D3FE65A9D56F62EC5F1ED32C7EC689694C +:10217000758F931E3486B0D3820F72FBF2BB90032F +:10218000827E847D78EAE093BA01ED5654686F59F7 +:10219000F7256667F672BB276E5F9EE7F6F7C0DB32 +:1021A0008FA769FE7C4E6F5FC1F8FFCB3ABEB0A728 +:1021B000E0FDBF59DF5F6DFE1CC0E70A21BD4FE4A3 +:1021C000F05D41FF8C10AE2FC0F5D4DF00DE6C9ABD +:1021D000CFF403AE427C064243AE6AF84A09BE2AF7 +:1021E000BEDF2F6A313A2D4F4E07974DFF73695F5F +:1021F0004AF9BA2DE3CEA7F755822FD4A4FE3AB4FC +:10220000BBCDDE2ED6FF7682CB1CF722FDEFB4B716 +:102210008BF55F6EA5CF01E0F3D5D6FDFD0AE4484E +:10222000238D3F8A8FBF328EC7EF58DFFF67DCEC0C +:102230009274DE4EFBDEC0E9E932ECED9F60FBAD4F +:10224000D25E3D83E24486C0FB3F23DEE17DAF0BDF +:10225000DEBF65EEC79345E19FE17B2CFAC75BFCCF +:10226000136309AD2FEE9FC040F9567DAFB75BF504 +:10227000FDA1505D3BC22B97F0F6FBBBDE5C86EB0D +:102280004F2C835D7280D6930576C918B24B9EC7DA +:10229000F2A5C605F8BBA8DFB39C6E92D4BF42740A +:1022A000F514AF6F75713BF6EDDA8FC98ED3D6A8F2 +:1022B0000EB4E3845E3F1AE27E00D82315116F5FEF +:1022C000BBF1684812783B4AE3EEE5F83F1696D337 +:1022D000D1DE8CD92DEC55F283E276D55DEDB88F49 +:1022E00071BBAA81CAD3CD7D3E13BA779909EF0994 +:1022F0008E07733D976EFF1EC1E1E7ED93D49FA556 +:10230000F1B2399CCC7BF80CFAAD44AFFC37CA0172 +:10231000E5556621E85C549C05764BD74E4945321D +:1023200059B94BECF3FA769BDF68F2E162938E9534 +:1023300092E665185F58FC89E0FF437CFD313FB5AC +:1023400099E07FC78C4F3C8CED397C9F12FC2A872B +:10235000EF2B18DF55427619C74F0D339C689789CC +:10236000F382C4FDCD287188FD4D2F213B99C355C3 +:10237000A34B64BF87579C7222BD2F3DC6B464F443 +:1023800031A4C425E24F43A8BFD7F46F033C2E9479 +:10239000D87E78492C5E359CE0F4F1F936148547F7 +:1023A00060FF69FAD192A17C6B3C688F864BA5488F +:1023B0005B0EFA37DEB25228CF73B05EF2FB18DB49 +:1023C0008C715FF7F30A6B0B506B55B1C475804B82 +:1023D0007F8B7EE422739FE7B1587CC581F11A4B55 +:1023E000FC86FC4077C9FD793B558ABB50DCC6E5CD +:1023F00097C9AF083EB482E223A9856E9F1BE7917F +:10240000B3C9CF75FDD08C172DE4FEA503FE433B69 +:102410003AB59191FF36679B1451A1DEADD9E32FF8 +:1024200075EBCF37937FB782F934F01395427BBDBC +:102430002BC17F6D99A087104F6777D539101FC1C9 +:102440004AEE879DDD35D28BFC97E8479F453F9A42 +:10245000A4541F3FDA7800E36B163F7AED00FAD1FF +:102460008B4AC08F465964FAD1238BC2B7113D28DD +:102470001AC9B7AEE953E693BFBC4D666E687F7A62 +:10248000E7C4370AA16C6C5302186E78DFA92DC51A +:102490007A03FC69F97ADA2686F1ADB926FCA78BB6 +:1024A000CE9722FCDABDD70790DE4F3FE4263C9F53 +:1024B0005E99194983F132B6FD65530AF47F2532DE +:1024C0001C836C31FF3AD10F672C6220DD9C6623A0 +:1024D000581BEE83E26338AED290113002717F7BDD +:1024E0006E9ECFC0F1F4481AC37D8FBECAA4B379E3 +:1024F0008C8E1C908EE731D58985054C7322FE1792 +:10250000319DCAB701BF492371BE3C83E800F80E74 +:10251000E3774D13F4EF10BDFF88D307DBAEB4E3D0 +:1025200079C569E39174E4B33DA9F6788378B698E8 +:10253000FCE9413F7FCC80FAF90F5AE5C465C895A4 +:1025400047F87E727E7595301A07F4643DF279B7CC +:102550001907DE9EC9E3277BCC3849E213183E0BEE +:10256000FB7F513D01FAB29DE08DFBF11D08CF6567 +:10257000E8CB9F12DCFBF83A7721DC5CFEFCF7121B +:102580006E07A819144F01513C89EF2FFE3E95F4B8 +:102590005FE07CDA5312ED578ACA480EB95938CA3F +:1025A0008989E3117EEB87DAFB3D7BB17E6B827C10 +:1025B000FE3F16EA2FE0FCC5E78142A19DBB8AC71A +:1025C000C1E77AA5972535DEEE38C6A192ECF779FA +:1025D000538E42B3A803EC958733600FF2717F02EC +:1025E00083505EBFDDA49D441BEE7853053D7B9474 +:1025F00006921F3DBBE4C806E8FA4613EB2E1DDD2C +:1026000077DC9ADAE0C933167934B7EC090F08455C +:10261000D69CD77158C278BDE656DDD0BF3B3DBCD5 +:102620001DE3F5C651997502BCB72EAC3C79C622A4 +:102630001F12C785F998012CFB61894C701F0CBAD9 +:10264000A333308E60481194072B8C534E8C572E39 +:102650006D5CC674D82757E12905EDC29AA08FDAC0 +:10266000CF2D94996181EBF149DA7B8867A08B3398 +:10267000B4BF81981DF53E96834E2DC3971F8F439F +:102680008A7381174B9E22FBB83B93D1FC613F8B31 +:102690006C80F94BB465AE5E3C67F187296E7AB207 +:1026A00044A57957EE6C277852A7FD99E001DB39F4 +:1026B000EA18DC17DF820F8E9A786F31F1DE1F9EE9 +:1026C00095521ECF13E5B9654A3AE2F92D45A57337 +:1026D0008EFEF87B7EA97D7FDCFE0A5BB959BBD7F5 +:1026E00081F47476A71CC17D82E7EBB86F9FC0BEF2 +:1026F000B19CF838DDE9ACC6AA9FC5FECC29B5EF80 +:10270000CFD26D7C7F966E0B125E969656BA86F18E +:1027100073B5BD40DB4C2F5CC6102F2EED9482723A +:10272000ACBFFD027E1B568AFC6BDA8F57103FCF81 +:1027300029B5D8B55F757C1FE6BBA534899DFDB76B +:102740003A5F10F4740CE56A7E5CAEDE56CAE5684A +:10275000E253C8558B3D49714D0B1CCBEBAF000EBE +:10276000C127C8A728374A7648CEDE7CDC7FE0D771 +:1027700031689F7DB819F35156F919D14356A94ACA +:1027800074ED9A36CF85F278E5AE3F2BA8AF009F67 +:102790008B4B2D72B8A494093D544BEFEB395DFC83 +:1027A0007B9FEB003C77D3BED77238AFB673A7756B +:1027B000D5E18DA5740E0472C98BF1789FD04323A7 +:1027C00078DCFB8B9D6FBEBFF35E8676E0BC3FA5D9 +:1027D000AB6807DE5ED4A9E5A849CF3755C976BEF8 +:1027E000591762E45730161AC62E79BE99787EDAE8 +:1027F000F7BCD378B9392B6E77279E77269E6BB2BC +:102800007ECE3FFB9E771EAC2A02386705649FAAE6 +:10281000C6CF335DD3CE9E6063FB9E770E32F52E1E +:1028200043ED6D596FCF08756F14F3A38679021DC0 +:10283000BC399327C5F1087AC0E38679369501FC47 +:10284000682FE7743CBA80D9F0E8223C7C413CD246 +:10285000F936E265A714D988FD950603E5F94AE63D +:10286000537F1088EF676CBCBC751ACAE7EFD47948 +:102870009903F87F73D63D6C19B44F3D92C26468DA +:102880007F44BD87F6FBC847E92A9EF7BAFD967DCF +:102890003071A908F8E4BE7ED2DF601F3DC8727DAA +:1028A000F651ED28453D7BB9FBF76451F803E4632D +:1028B0000FE86B657CFC7DCF088ECFDE9B58A44370 +:1028C000EABB8F806F8DFCCE3CD6BE91EA1B18C64A +:1028D0000736498CE33B812E1C69EB0D3CD7762DE6 +:1028E000F7921FD5DCD040F83E0AF8367C9CBFF04A +:1028F0009CEA22FC25E88249432F9F2E12F7FDC84F +:10290000CE3AD67875EF6B3FFCB9BB14ED9ECBDDAC +:10291000D77953B59CB202EB3E6B23CB8658F9D6E0 +:10292000E07E0938C0E44F2E64AC33B3AF1D956F21 +:10293000E6A5C0785FC7F1C69431330EA88DC1F209 +:10294000821B5843B2BC976BCBB93F560B2622C5AE +:10295000558C54CABBACF5EDF83DE5611A37A9D6E4 +:102960003CCC3ABE0476FCE1F61EAC9F0B8B756442 +:10297000D12BCACB14F80995E5D0B845AB4FBDAE05 +:10298000527580C67781F0473FB5165F523E098B7E +:1029900074921CD0D97C90F777AC95289FB3C64829 +:1029A00063E8D7C6F32AF626E455F0F2DC6CB3DE12 +:1029B00078B1C37E8EF9DA72DB39A6D19BA0DFFE37 +:1029C00048FACF665F58F4D9072F7FB2DC50ACE7E6 +:1029D000989FD2F8276BC57CC1DDC17CEB39A66B13 +:1029E00037C223E2D4F0DB6D3DA704C8A92CE2C8AE +:1029F000A933B53A8C87ED9BA0AFC0FD914BA406DF +:102A0000B48F40C16812C56B7C1DE84F83FDBF12B7 +:102A1000EBFFDED70976485399E5FCE3EF0DFED3D3 +:102A200022BE6F1C5F8EF05DEDF002BE7F46F8AEF9 +:102A3000E0F8FE3B80F7605952FFE4AA81EF6D8217 +:102A40002F760EF1EF0ECF876596F38BAF7A3E6D42 +:102A5000AAF6BF71FD5FC13A1C33711D66FEC165E8 +:102A6000B4F7507BF3BC34B1BE69A6E93F98E7C424 +:102A7000EFC4CEF1AEADC3F17AE3E77A74EE153F61 +:102A800047CC1B89E78871F8F3687E718E189E79B0 +:102A9000731DE545F7738E391FEB4759FBDFB41BF8 +:102AA000F9AC2D613E9759BF6AE6448237BEDE0914 +:102AB000345F7742FB1A737D6B674EDD6D58F00112 +:102AC0009DA87D4C2E31AD0EE78B9F3B4EAFB39E44 +:102AD000DF7E6FA6B65B9CFFCF443A36CF69FFA37B +:102AE000E363C14C1EDF11E7E5820E474ED116228B +:102AF0009EAE367861FFEAADF4FF37986FDD4C0B80 +:102B00003F7DD1FE317E34F5BEC89F00FC1A88DFC0 +:102B1000A6723569BE84F013C3BD2C827ECB5416D9 +:102B200091F15C221CD019C641637C6D54125FBBCD +:102B300062F723E6ED46F917BF1FD1B61BED8BB840 +:102B4000FEFE559D3DCF616E9DF57CBEFD955F8976 +:102B5000753F6AE593811EFF7BE576BCC4CA267E7D +:102B600096DCFDDF46D8EF5F2CA679DE89DDBFA8B5 +:102B7000DB6DBFC7D0B0DB9EDFF15D3B5CACD50E3B +:102B8000176BB1ED574679EB6E03CA2E33EFCDB517 +:102B900042EAE77EC572920BE25C17CA36B940E59D +:102BA000EC8187EBB7828E4C3E8DC1D9273FEF9BDE +:102BB000BBEDF9790333BF452EBC8DFC30F078E7CF +:102BC000F73B04DEFBBBDFB15815E5C6BAFAFC2FB4 +:102BD0003F2FE6FF59E5C9975F07BF2FE24ABC2F99 +:102BE000C236D6D9E5CF65C3E72A4F2A7F2EAFFF7D +:102BF000A0F27EE58F0FC76DF63AE83E8AEE674990 +:102C0000EFA33495F373A9187F9AF751163C9CDC17 +:102C10009FFEAEE94F8B7877D0757E85F5BC6B74DF +:102C2000398F6FE796C7F25072697D8D1CBE00CA5E +:102C3000433CEF610AD380A7162E18918DF035FF23 +:102C40008E8FC7FCE027A7C7C7AB36E713F3BC34AA +:102C50002FBDC69AD730D69C27109F2F40F3ADE7E3 +:102C6000EB9007ADA67B5E31BFDAF831E1B5C5293F +:102C7000FCEC4EE2EF78DCB883E4CE22B7A0FF276D +:102C8000775BFD89DB7EFD14C9370C5FE0395EBCE4 +:102C90005F7BDDE5F42B2B37F5F12673BF8CD87EF7 +:102CA000CD44B82FD5DFE24747A5ACB81FBD6F8232 +:102CB0003607FB833F3DB7BCE0D2E3009E16119E72 +:102CC000D6DAFD114BFDE2725B5ED2F9D517CB4B24 +:102CD0005A61EE7B7F79492BCA6379242BCA2DE791 +:102CE0004AC17925E905182719E6487A8FE21E734B +:102CF0005FE3F95DBFA4F5B408BE33CBDB3379FDE8 +:102D0000B77EFD6C9DC9576BCA2DE717E2BC85E500 +:102D10001F8E629CC7925FA439AC719F92534EA4E0 +:102D200087A5DBA4A4F9337DF8A5D51C7F5B6C1FB8 +:102D30009BCA797C5FC7B8E36231EE3736D0B835CD +:102D40002BF8B8897CB3D5C4DFD6389EB6129EB4B2 +:102D500058BECD8358C69401F7F8F8F8E27E4FD0FC +:102D6000197E01CF755A0C4945F9AA372EA3734530 +:102D700056013C09FB141C96BB0D4587986F5C05FA +:102D80009F0FFE598AEDFCC042C630B06B2B96D126 +:102D9000B9F3248DE7AD4CAEDA200F5129AFE547EA +:102DA000B8AEA285EDCDB8BCDB6A7F2127CB67E941 +:102DB0008EE5B3B0B7460D05FE36E1C37B216B61EE +:102DC0009E7762F92C5565EBACF92CE12F97CF2259 +:102DD000E27F4B428057CBBE8D34D739B282E33588 +:102DE0007E0ECCE8FCF6465633EB268C2FE3BD2D49 +:102DF00078DD6DDE73BB90CD2278FEBF617A2AC587 +:102E0000F17A33199DABC28664544FC23C12FE4B1B +:102E1000195D4A715C37AC0BD781E7B2D1AFC1F015 +:102E200072EDA068127A7E234367012FC6FD8DCD17 +:102E30000CCFD5F447E87CEE86157FAEC77997EACC +:102E40006E15496071BDAF8CF2B856079CEB300E21 +:102E5000E9979986F1EC2AE77BFC9CC643789A5B5C +:102E6000CACB022F6EA6BC67C58B92506E3CB16177 +:102E7000CB214B7B5734251DCF05DF2E4FB7DD2BE4 +:102E800062B297E8E082DF11C173A86E85752900F0 +:102E9000479D2ED3F97BE7B635AFE3FDB1A57E257F +:102EA000E0807596344A94FFB5D8C7F1F49726634D +:102EB000CB21B0615386E5D239CC059F87A2F12D95 +:102EC000B59D14B7077AE95630AFE70199E1B9B774 +:102ED000C87F9A67D28BC063CAB28F092F17F03CA4 +:102EE0001CF1529849795073001FAA8FCEF93721EF +:102EF0009E525943F41A98F756BF83452D7168586E +:102F0000BF2D8F0CC6A6BC3385DED8EA093FA90FBA +:102F100094F07C34B92A8AFB7AA190EF2B94034871 +:102F2000EFAC94D3A9C07F6A029DBA13F2C312E931 +:102F3000B40FFE2BEC78EF5458208AF4764C26FB25 +:102F4000A277A7924179573B1D9477C55884EE31FB +:102F500075B2C18136949B5189CE096E33F126F04A +:102F6000CE58C3E6E518E76EC80860FC9F391A36EC +:102F7000637ED4E2481AE5DFDDCEF6521ED41DE8AA +:102F800021C3BC77329F0BCBCB59809E12CBA7FBC2 +:102F900025B7EA12F185CEA2D53701FEA2D7393383 +:102FA000AD7955FDE635C1CACF5ACE23465598F2C4 +:102FB000D2A3FB799EA76EDEFBD1283F28B3ACD409 +:102FC000A32791B7A545FAD72B0A2C7918BE064638 +:102FD000E7D345E1311543E2FD9F9AA08DC5F2E4A8 +:102FE00042ED166CBF07ED3CD0078B0E8F7D02F5CE +:102FF00059CB046D3CD627CAABD3FDE7DF451B8117 +:10300000EE7A505E511E613EF1E140E5DF9555F4E8 +:10301000C9BF2BA7F598F977279DFC5E19E5224FCC +:10302000657DEFA735DE46F5E27E5AE2BD34F62334 +:103030005E8605196DE3F0FE6E03AD5BE03D113F6A +:10304000CCBC97B6C4FF4A8F347600F2D67C60DCE5 +:103050000DBB187D18FCFE72F59A9E2CCA235428CD +:103060008FB02587DF5FDE844D30116814B7070706 +:10307000557239BE25B3C11F80FA2D4E9E0FC3F283 +:1030800074B6604C7CDC4195B238176A403A00BB9C +:103090008FEC2561AF8A76F7997AA1B14212F7CE0B +:1030A000EEC7F696FCEE46DA0F6F34E210E776FCD8 +:1030B00047E740C27E383EBC81F269DC5A727BA190 +:1030C000B922A6CF9B69FC9D429F6B9B70FC19D7D0 +:1030D000F816229FB94A64D6817A6CEE5D24779FF8 +:1030E000C1BC51B06926EB1B4A86C27E3F52619E2D +:1030F00037D56722BA58B7C6F349A3C50D7ED47732 +:103100005B8625BFF77DB282DBCF13AF3F2FE3B8DD +:103110005B9681A7320EF167501E9BB1086409943B +:10312000C1DD3F84E7321EB4038A502FF2F6BE7A27 +:103130006803FBD865E22B7823D00FDACFA3EDF933 +:1031400048E229DA25E65B81284FC77527E6B98969 +:103150007CAB1EC5480F24817F6ED95A0FE56B6585 +:103160002FF7A09E6CD14A68BCC4BCB72DD96C04A3 +:10317000C29598D726F2A644BE9418F7B90A4E27EE +:10318000226FCAEDE77A0B9E942713AD50CDFBBB9F +:10319000F6FC36915F83ED29BF269BF1FC1A7F0375 +:1031A000C37E6E2863FBB0997F9698570572E8201E +:1031B000D1411FFB88919DD15264E60D306DF332F1 +:1031C000B48FF0FC3690C4BE0281807AD005FA0933 +:1031D000EB15797505A6F27C593BAAB428DC83F07F +:1031E000B9FC3139FB3B82372E67DF35E5EC09ABA3 +:1031F0009C75BFBAF509B4BBB7489C0EB700DE9FFB +:103200004E421F1F98FCB6253339FD7C6ED26BCB26 +:1032100084F08738BE96C5EF777C513BB3256E6747 +:10322000723C0E909D09F8F8CC2AA7011FFF2F19B8 +:103230001EE0B709E58625CFD45959D07F9E696233 +:10324000FF2BBD277C0DC80DE43FF0077D95E40FF3 +:10325000723A16F2387EDFF6CAE4F53107C85180BB +:10326000076D026BFBDC4A2EE7C64DD5732B492F49 +:10327000F3FBBE5B83FCBE2F8B6AA4F78FA7EB35F5 +:10328000C8A72C6FFC25E6DB60E6D3EAF56192F374 +:10329000F32FD17EA339BFB9DEBCC1A43FB64ADA51 +:1032A000AE54395EBED4FAAEABD42623FCCD7A98A8 +:1032B000BE97B025CFA11AB0B47F9AAC17E3FB2D0F +:1032C000791B69FFDA80E024909B731CE71FCA9585 +:1032D000281FF85969103C3DE0B125A1EB59959C98 +:1032E000EEC18AA57A7642F35BE31C6B4DFD16CFE7 +:1032F0000778FA09EB3DA61595FB5618163D86F1A1 +:1033000092A793D0C5C24ACE3FB27B8D4D4F26B611 +:10331000BBB5D245ED56569AF10853EF2D72733F67 +:103320008A1D01F82C7A75DCD4D0EDB4AF063324B5 +:103330008B3E14FA8F6A2CEFDD7E7EFF841DB38FE7 +:1033400023D6799F49A7625EA0D755C81FA077BF33 +:1033500081F388FA4532E3F18E6E3BBE009ED59C28 +:10336000CED88A587E96051ECDC1C78DC1D1638740 +:10337000E33E733FC64DD5EEC371401FAFC3676BCD +:1033800008E82D095EC71784BE8DF50A335A73739A +:103390002E6AAF6EC076A26CB1579B2BEDF6EA2673 +:1033A0005C2FC8D1CDF87E4F6AF2797798F81AB0C1 +:1033B000EF065C269F3F88FF4CC22F6DBDFBD2C637 +:1033C000028BB9DDC6BDC497F9E32FC1579C8FEFBF +:1033D000BCBE81F4DB0BA6FDF1829329985703BC98 +:1033E000154896EF73B452D81B91E18897E7FAB16C +:1033F0003762EDFAC9ABFF1ADB9176257647DBB46D +:10340000E36964777CD29186FAFDB933A1A476C7CB +:103410000BD93B8627B33BF6F76377BC6ADAA7077D +:10342000DF77911D517C8EDB1DC5E776C8683FBCF8 +:1034300059A9D27A8ACE74CB3AC05D8C76078CB308 +:10344000DFB43BB03DD91D9FEC9011AEA273DDD42B +:10345000AF18CA687714F56377001432E2E1D9E255 +:10346000B67FC5FD4B5CEFBC897A8F956E0B7BBB3D +:1034700029BE23FAB5E56D4CD369BFEDF4535AA4C8 +:10348000DAF2E20B7B39BD27B6EB8FCECAE4AAD6BF +:103490005E58D75696BE83F2319586C7B16C180A2E +:1034A000FF3E1E7E5F039EF7CF051832B15DC34F0E +:1034B0007A51AF186E1F7ED7E02FA94BB99FB396F4 +:1034C000F99C53E37288960EA01921733C97C7D7D5 +:1034D0000C76D2F7D332088F8D3E11CFD951910B94 +:1034E000FDEFFFDA28BAF7137A040682F2D46332CA +:1034F000D58BF8CFEBC318E5E703FFCEA986F127FC +:103500009BE3839ED3EE85F68B4C3B6CA6ECA5F635 +:103510000FE6F1F6538DF3F5582EEA75A978BF8CB6 +:10352000C9EBE5BB316E8BF608B47FF0F9709907F3 +:10353000EA538F032438DE0917C52F447CA1E0D855 +:103540005EC267DA19972DAE910A122F6AB15B5CE1 +:10355000096526D70E4A269FC433310E71ED2CD350 +:103560001F1DCB6EF91CECAC0B6C7D2BAED13D3A24 +:10357000747037EBDB5FC419CE4FD446CC827D1C10 +:10358000E5D4C96FD95F01B8867DDABF73E7ECB1C6 +:1035900088F71D0AC5754F7E3B8DF6E9C0234A3B6F +:1035A000C6934E029FF2F8ADB112E9F5403A13E727 +:1035B00040518CCB1D88DD67CE5EA959CAE35E2BD6 +:1035C0007C1FF5E08121A2FD8F79BD281BFFB4127D +:1035D000F3360E0CE3E525AF3DD369101DF72AE461 +:1035E00057379EF626939F9366DBE9784EE11A4E95 +:1035F000C797E807F27EC6AC24FD52AAB97F75A032 +:1036000016401A8778D24B67015FEFEFB9A7750CA8 +:103610004C3571DAB7BB498E5ED3BB3699DC5F306F +:103620008BDB53D1E208F95BE0C3737F97298730C6 +:103630007F750E53C7A35FFFF0F4E77E3316E6797C +:10364000A368F47839095FDF3D2B97C689C37754A7 +:103650005E8E72E9A3F716269303DFAFD417DBD78C +:10366000C3CF479B772884FF0766FFDF2730EF2112 +:103670005ABC83E277FBFFE460E8AFEC1FC3ED7E4A +:10368000BCA187DFA51C00F8764E4E427700DF5DB7 +:10369000B30AFAC2377936E3F9A113B56F617D2217 +:1036A000BC2AC6B9015E30AF022847523EFC2FDD6E +:1036B00018CFDCDFEBA0A0CA85331D3292605B4FD0 +:1036C0006E299AAB33AA4EC94852C5BE4736E3D1DC +:1036D000AFBE5EB6F1DFE49E545BF98E866B6CE59F +:1036E00025F5C3E3FCC8F01ED0485BD9EDBFD95621 +:1036F0000EB209B6F2C2AAA9B6F1CA7C25B672B951 +:103700007FB6AD7DA5BAC0569E9DB7C4D6BE3A5011 +:1037100067AB0FE78F53F00A1FD0E5F771BFD38E69 +:1037200069C4E75B7AEEF1215D448BC3E44F1F4F20 +:10373000EFCEC678F5EBFD7C57EED42CAECFEEBCC9 +:103740001E4C239493A0CF3766C6DB07737B6DF1C5 +:10375000F8C3B3B87D7A7056623CBEBF7B705C3FE5 +:103760005FEEFDB7443D3CF7A67B482EB52D942374 +:10377000789FAA39EF2D2FDE1B7B7D218F23B46527 +:10378000C33ABD948F41FC7570D16D23F05C2D352B +:103790004FBF06E5BFD0DF257911761AEA537D11B8 +:1037A0003612EF9741B9CEBC675692CFDFDF68BEC5 +:1037B0005F854FD0DB332DF84AD4C741CFB897C1CE +:1037C0005D60D3FFEAA3EFF72DCCE7F19ED24F2245 +:1037D000A5789F7AB6F6D2217E6D9ACB9F378AFF65 +:1037E00098D58FDE7ED3CEAF47891FF69F997F5144 +:1037F000F9FF87261E5F7FA6C9C3A2B0BE134D3E48 +:103800007AFEAEC94FEF8F36A9F46C69CAA367B4CC +:103810002940F5FFDA5448CF434D1A3D5F69AAA00D +:10382000E7E1A630B57BADA9869E479A747AFFF191 +:103830002CCE97570B3C5A9E8827840F3A24C2EB14 +:10384000424CD59D724E93ADF21DF0FA6932BC5ECA +:10385000A91E8916EF1D1EE67A2A291F0D9D2DEE41 +:1038600085713B798E4E323F069F0BE37359F1F819 +:103870009C1B4D9AC104E7A0D9050307E701337EDD +:10388000732093D53CCDFDBA4D12E91BDF382ECF06 +:103890007F100E913C1F322EB93CCFE923CF979178 +:1038A000DE6287316E8A6945288CD7E1FCC9E32145 +:1038B000C6A09C8BE281CE2B051E2CFB15B8123CBA +:1038C00024AEBFB4489B8CE3E03D14E7E0BE7AE44D +:1038D000C6DECF348C493D9BCFE17DF8BDF983D066 +:1038E0005E7163308AEC1570F00A71BF99698FB40C +:1038F00077D667F71DE70FC57B49AF3F18B3739EB7 +:10390000203B26B11DFC0E111E506F59F090440E45 +:103910008493ADBF4C7EBE7723F43FD0CB285EA608 +:10392000A24D0DF03FA7F0EF341C38E7203C5FF0CC +:1039300048241FDD0FDCEBC1D8F6B3DFE5ED8C6A60 +:1039400089EE2FA475ED57D14E0DF6EAD7E0F7C6F4 +:103950000AA3954EFC3E6868DAB8408A850E428A12 +:103960005D4FA2A51AD33B140C1B9C50BE2EDE5EED +:10397000C6FDCF8D9773E8DEF53FCE063A9D7FBE3C +:1039800081A9F9667C35399E564B96789BC202AD6B +:103990009373C8EE3C741D9EDB8C661199E8CA20B7 +:1039A000FF5BC02B7BC3742F4FF8E99F4ADAFDB34E +:1039B00093D80FAC5EA37337E670D0B95BD304BD68 +:1039C00069369DCF279CCBF85EF93F12E8B45607C5 +:1039D0008BA27D6164B8087F89FB35B9B07213AEE4 +:1039E000CBFFA5FDFA1D92F53B0137AA33C89FBA5C +:1039F00000FE14DE436956F8FD28E3447AA4938060 +:103A0000647968B7DD2FDF1CC0FDFF7EDAF7C83FA1 +:103A10006A047F0BFDAF6DA61CBE3F35A383818278 +:103A2000DAE66CF81F58DF22B17007FA5B29D74736 +:103A300058461CAECED95C9FBBD91D8390CFBCBE6F +:103A40009927CF4C48E6EF71FFC419DBF76C1FF9DB +:103A50001B66D9EBD2FD98F7D8326EF52EBC8F6578 +:103A60000CF1F0F34E25ACCE03FC3C64DEAB653EBE +:103A7000836559EEEFCB4C398BF1D9563066F07C2B +:103A8000F79709F038AF101E174A18F447B35C11C6 +:103A9000CCAF51511E015CAD7E07F1CD2695F3FDF3 +:103AA00026AFE6F125D9B72D884777FFFB29E76CCC +:103AB000F2611C7B87D7417CD9AA2A5B73A0DCEA20 +:103AC00055F8F75A554745B27CAD8F6673BB099AD6 +:103AD000A4507E53703ED931FDCDD366EEA728A702 +:103AE000E6EB1AF18F1A08E37A9ABD5912C63745E8 +:103AF000FDAFCDF1459C78AB6917A5E6ED8D62BCB5 +:103B0000A665D8AA09882E0FD83967E1BD277F2F6F +:103B1000D9452D433C35C9CEBFCECFE671B6ADCE2B +:103B20004005E2736BBA831980BFAD39C9F5608F68 +:103B3000B97FCDEAF830D12DE063B4D4B7DD6F4C56 +:103B40007DB9D9B9C38FF7D0B68EBE95F2BCB68E0B +:103B5000E072B7F1C889CE0DF9C80FDF62FF86FCAD +:103B600090A5D0BEA92CE041FDD5E2537CE8EF4FF3 +:103B7000CC5AE7095AE497A0FFED6887C0D3396CA7 +:103B80007E0DD2E385C2D40022BD4C3E42DF0969DE +:103B900009803CCDC13CA4069FF5FE3FD8D37215E9 +:103BA000C0951E70D8ECED4185767F4165BA87E8F7 +:103BB0007318A7A3FEF62F111E2F4A9CF117699FB9 +:103BC000A9D724FB2EC9B82A8E574137CE4BD0CD6A +:103BD000A5E0B7E9BBECB8BECBA91AB10ACF2F1E3E +:103BE00062BC7EE491F39DE8AF2796BF2C7F362B15 +:103BF0003B481E378F72113D25F6DF9AC3E1F9600D +:103C0000F647341F861570DF323D3C8EB4BD7070B0 +:103C10004A32793B6BA25E5465B18B324BF7921EF0 +:103C20001D5CC5087F5E35EC1B05E3788FC940A39A +:103C3000806FC7677F3DA55E391E951D0D2CCCC7D3 +:103C4000233983BFCF40BE6598FA64CB0D6F30CC6B +:103C50009FD93E5209C89487702470313BDA5B6863 +:103C60008F137DD138504D95998F92C252781E5046 +:103C70005548A1FC1B07D79F1AFC3FD4BCC22E9904 +:103C8000FB3FD43C5A52F1158F7F65D5325A4F2CE9 +:103C90001F05BF2783E3E88CEC0CBC108BEDAE5BFB +:103CA000CDEDA86CD62BE1F9DE0D98952323BD73DD +:103CB000F97981653B281F07A6C17C12C97090BEA7 +:103CC000FBAF379C9482F0767BD1AA71B83F89EB29 +:103CD000585365C6B362EBB8381E049C034DA74227 +:103CE0002F377BB89ED54021A7A0119C10D72C93CD +:103CF000D7535CB3C570FB500F372BA077B3A877B1 +:103D000098E2A00971CDBFA4F0B8A7B48EF9A4229F +:103D10008A6BE6E13E35B2D400C61D0729BA07EB2F +:103D2000D346298CD355C3643C3F89FBDBAA97E774 +:103D3000BF35529EE0AF50AF41BBAECF2E2E8FF6B7 +:103D40005D42AFB51D1BE5A5B8B9A72E0DFDEC670B +:103D5000FCB947D06FB9E0E1F95BA25D57C2F74CFF +:103D60005A4C39D75365C6C753FE2263FF197E5597 +:103D7000C13CB990671CC9F76629F93940AF29DF02 +:103D80006E54DFE474B65A7C876C35C9FF77D34D27 +:103D9000FAADD79750BCD8B4E398A6A9BE4971FB39 +:103DA0004DE84BBFE233EEC271CCFCA93EEBECFA1E +:103DB0000786DF57617E4BDC3517E71F14CB9BC3AB +:103DC000F913EDB6FEF0D966FABDCDFE10E55D5CE7 +:103DD000409995E45C443CC1FEEC463955D06D9762 +:103DE0002F697976F9D2EA68A03C2EE366E6C33CF7 +:103DF0000F5615F05BED5FB0438F571133DBEDC904 +:103E0000FBAAB9BCEBCA54158CBF9478820CCF1BAB +:103E1000946C9DE17EB8FC818BEEC7CFABB8DE6FB2 +:103E2000C95B1E467FE5E1E9DF24BC4CACE079A527 +:103E3000A21DE8CB0FAA2C7E8BC83BB8ECEF23F970 +:103E40001C948F78B9F1A1B6692BF9F791FCCBE9F5 +:103E5000FB48CF78F8F791BAD2F534B4BFBEE8F793 +:103E600091EEAEE6F41AF27CE3E08C5C0B9E7A7481 +:103E7000CA0771F9CFD3B9CC0C337F24310EE47665 +:103E800037D0395AB4B86189350E2CF0F77393AE38 +:103E9000FF50AC539E4F7F7FDF41B4438CE1BADCCF +:103EA000669C734BF1B709FFF32B3229CEA49871AE +:103EB00026D7799DF27A3B27EAD7565BF49D3BDB08 +:103EC000207D97F63DC6EFAF7FCAEFAFA76D6421A7 +:103ED000BCAF1EFA6C3C9D3F85A229C467D33F0945 +:103EE000D0F7A7CBE4A75A73A1BEEB9842DF85EFCA +:103EF0009A9E9A857AEDE363DCBE4DEBBAE9C82D54 +:103F0000502E3E5687BE3EC81D806570DF754CFF43 +:103F1000C4F1A5FCC702F41F2DE72062DC5F361D4B +:103F200026FAD8D7D44DCFFD4D517AB635F5D0B35A +:103F300050D14A703D85DD7426C9A69C817A0B1C40 +:103F40008527A0BF851E864CD4B56AE2BF6E5BBBD9 +:103F5000B4BC1E5B3BF05F4BAB0B308F87E3D3856C +:103F6000DF0D83F1E7F6B0CD92FA1F4A5EADAA1ECF +:103F70001879F58FD505179357FC9C34D4637E27A9 +:103F80002C811F1DD52AF90D31BE34CF4B859E6E75 +:103F9000C57F823E6DCEF826976FB17C0C7EFF50B8 +:103FA0007C677EE3EB1FEDA1BCD277CC7A83FD4426 +:103FB000B3D433F6C92ABC0FF2123AAF60879E7BA6 +:103FC000BD6B15DE9BBEB52653D100BE123C58CD4D +:103FD0008CDF7F11798A8978FB9FD59CAF8FE7FAB8 +:103FE00028BEDE92CBFF5E4162BB37ABB9BC409AC4 +:103FF000B0FE1D8FD47EEEFDBC2AC635F1D6EAE2B6 +:10400000F907FDDDEF78ACFAE2F73BFE60D65FEA38 +:104010003EC72FCD795FC4790B282F720FD285F858 +:104020003B1B51F37DECEF6BF859D2717E6ECADD0C +:104030001BE7F8CCFDD414F33BD47B893ECCBF877F +:1040400020EAA79C8BD5EFA3F9627FF740A7F88FF2 +:10405000B85FF7F3EADFEED960F99E574BEC3B8986 +:104060003C6FE95313FEC4A7B85F12FB1E147B6BB1 +:104070008F66F91ED44FAADF396B7EAFEA10C16795 +:10408000DEAB79348E875FD3FB84EF0374BDFEDA39 +:104090001EF33ECE6FA8BE21F1BB5BEFEDB1DEEFAC +:1040A00079B4FAD42AB3FD515AA7F99DAE247461AC +:1040B000D2ED993D789FF032C67B97C633BFB3B53A +:1040C000D9E4A3FEE819DA9FA2F6B1EF0FD7795031 +:1040D000AFC4EFF1BFBBC7F6FDACFEF1F5475AB771 +:1040E0002EE665667E13E717911F26E8C23B87EF31 +:1040F000C776931FF0FE1FF55F316078F88CD69578 +:1041000070AFE852EBD837212CCF4138FCB1FC62BC +:1041100085CA5F121E711F2C913F86CF91445EF3BA +:10412000609A273BF61DCE6B06625E1877048D13EE +:10413000FFBEE7F57392CB9F2F342E532F2F6F4482 +:1041400094FF3F19A999BA607100000000000000B7 +:104150001F8B080000000000000BF3176060F8518F +:104160008FC09C687C5AE3BF4C0C0CFACC0C0C97AB +:10417000D818189C39191884F8C833E7229ABE7BDE +:1041800040B366F030302C636560D809C47A5CD8DF +:10419000F5D90822D847817E5F01C417E91C06A320 +:1041A00078F0E01A11068649A208BE9E18AA7CADD6 +:1041B0000882AD2345995D4E40FD008850BECB80FE +:1041C00003000000000000001F8B0800000000003A +:1041D000000BD57D0F7C54C5B5F0DCDDBB77FF2728 +:1041E00037C9029B10E24DF863D04037103058D4E5 +:1041F0004D041A90D7AE69ABB1A576A14A151156F8 +:104200006B9567D5DCFCDF841002A202455954107F +:10421000ADB6A9A2B59FE5BD0D508A7D7E9FE8533E +:10422000AB56FB62A5B45AA5F1594AFA7D086FCE88 +:1042300099B9D97B6FEE6E962A6DBFF86B87B9F38B +:10424000EFCCF93767CE9C99956C6E52760E21A70C +:10425000E1EF12421EF21242C6A4D2CAEF7DF986E5 +:1042600027AAE8BFBDCED04E9A54FE626E71B4222A +:10427000557F1611B05EED2F96FC91D07AFF4EEC73 +:104280008A937EDAE71FF486685E15EC04DA394912 +:104290004DC1BF0468F9902DD445F3C993361FA1D1 +:1042A000FD4C2776E8842844F645A6D1EFE29773C3 +:1042B00089AE7F737AF16691240B08D97F27112389 +:1042C000B45E9BFF8225033E425E6C4CFEE5C864F3 +:1042D00042C2C9A9A242FB39D07808F3FFD678F8C8 +:1042E0002F471C8444491E8E533BF72371296DB719 +:1042F000DF411AFA68BBDAB0E058AA1B2FCAE7B34D +:10430000DFCDCBE51AD1B2DC4FCBE9F7DAC0E596C9 +:10431000E5513A23AC97C7FB191AB0433D850C7A97 +:10432000719E27EB2DE7398EB7D3F255036CBEFB98 +:10433000DE3E7119D0214972234E484F96BD05F8D3 +:10434000EE77090A29A5F81D5884F84D027E6917F1 +:1043500027DE61F8DEFF892DD444F15DEB927D21EB +:104360009A2722A5072DAFF59130C225D294C271AC +:104370001987FB2A9ED6438A7451902EFD2E4A1728 +:10438000DFE8F05EB2594278B579F6C33CB368A76E +:10439000D1957EF545FCB41DB1E68391F8A1E3CD3E +:1043A0003C733835BC46E6F6FFE5888BE0DF69FAFA +:1043B000BFF9F2F37F39529ECA5F3274D890A71CBE +:1043C0004D5CB329BCF04F0552F1CF035A79292B2C +:1043D0008771E28DCA9F2751FEEB6D247F9E44F9C1 +:1043E000AFA7D185F9EE4619F35D8D41CCC745DA0B +:1043F00084D231DE4D122A6D9F17A6F575E3E5567E +:10440000D3763AF8FC21D990F796070DF5DD8A624C +:10441000288F2B37DB1294EE9D15B6845D0038A8EB +:104420008C9C0B70B830A5E0BE16A4F399C49A908A +:10443000750EE5576500CF4B76D24CF3394AD8B6A6 +:104440008CE64B82769208D1F1730609A1FDC5EF87 +:10445000246423EDAFBB72B66D19CD77CD71CA76EA +:10446000999004ED3FEEA4FD9C4A2A2DD0CF34292B +:1044700004FD905EF1B7802717FDEF741921131525 +:10448000E91D5B0E21A52AFDAE9F9F530D825CE7BF +:10449000561BBF4F5496DF4868FD8944F7BD34452D +:1044A0004F6D5C2D6F1ECF3CCE396B4CFD9BFA2DB2 +:1044B00051066AE48A54BFE790C126D9F7CFDC6F72 +:1044C000B856003A858892A83C7B70FBD67C9C77D6 +:1044D00064660ACFDD0EA607CDF236406CA83F8891 +:1044E000388684295C8A624B74D17EBA4A6DC83F93 +:1044F0004A1B4980DE5A37E1700CF25DA592D24C1E +:10450000F3A5E5071B84E984AC9D2023DF75ED75D9 +:1045100092E610832340F9B444E3D353033565C0D6 +:104520008702096DA4E5A5CAD126A82FBFE6511CB4 +:10453000D523E747D6B0F9639ECE7F10FE316B647A +:10454000BFBF9C258523C0B72A4938293C9D939A33 +:10455000EB543ACE03AA48407EBAEEEC7B1DF01C29 +:104560009FCCE035CFBB449196025F13FDF874BC3D +:10457000924957DC00F332C3A1E98BEF37CA288F89 +:104580005B1ACB317DA051EE033DB1E513BB257E17 +:104590002F13987EDEEA88D8003E758E2DB113F574 +:1045A0004F74EBF5347FFF77C7CE8075E0E6393680 +:1045B000D42F7FEE66F8BE5FE8BD8A607D49C1FA00 +:1045C00026F97F400C377F8BD6BF3F5840542ACF07 +:1045D000258EC30BCF85FED69455AAB4BFFB6FD9E9 +:1045E000F80EB42F993345B1D3F613AB8FBE4517F0 +:1045F00071B2E5D44030E2833C93EB923563FB2605 +:10460000513E19AFF4DE04E397544B4AA234C597E8 +:10461000C52484E39CD3E025497974FE2C5E9999E6 +:104620003FCF9E1EF8FBC85511C855410AEEADDCC0 +:104630003E31D37DB160437E1996AB6A26574F5EFB +:10464000C8E8ACC9D59609BDEFE5D27CCF37189F35 +:104650009AF9BCB4FA680DD0B59BCA4F7E909042CF +:10466000A7F2B140F33D4BB91C561F1596D3F67F08 +:104670007AD5A31090A725D6FA3A1D3FA752E3B8E2 +:104680000FDC62AB8DD07ABFBC76CA1F9D30DE12C4 +:10469000490139EB11CB717CE5BB92A2EAE859B232 +:1046A00084CA13E5AF925BB8FC98E46AB4F1E38D79 +:1046B00009F22E95A30D8D4112A6745BDFA8A07C94 +:1046C000ADE37206B62829A4792E67A47C06E6D34A +:1046D000D99F8434A1DCB994248952FA6CA07D93CB +:1046E00022F89E0C87E712920FBAEA42042769A3C8 +:1046F0006BFBFAE17212A64C4F7A049E57FFA88614 +:10470000E9787288E59F6BFAA3DA428570839BE5AE +:10471000F70AE535EA5C7DFB83D8BF569FE693B583 +:104720009374FD41FF157A786C35505FEBEF8DA6E1 +:10473000A21A958EBF9EE7A5E63C963FCBFD770B70 +:104740007D41CAF464ADA99F6E81E349FD8F70D8A5 +:10475000971AE73EE1BDB06A28FF4318F0A495FF21 +:10476000A0E93F5495D6FF8844B608940E33E64539 +:104770008B08A5BBB72E49C094DA60C2776A7E2F3A +:10478000E1FC7C152CFF60D32761C0B756FE8CE09E +:104790006F027C03DFF8C6121244212164F3CFBB01 +:1047A000AF7F01FE5D9E4FC81C3A8ED24B14DA8754 +:1047B0006D524C807D47708978D4200F9CEF287C07 +:1047C0004F08349D3137FA35580A2DE053F5F0691A +:1047D000E38F06AF06477AFE64E39BF9A87641F5BE +:1047E0008B73A97C790F3B424E05E6210BA0C7F3E2 +:1047F0000128AAD7F24EED473A11B12F0876B4B985 +:10480000DFFC794524A19BE7674DCF2D9067787B2E +:10481000454F579A7F4D8FC727A0DEAC917CA7CD1F +:10482000CF0DF3236007D3F955E9E7F75403CC2FF5 +:104830001DDECCF35BEFEE6D8858E8DF8B6D7CBF3F +:104840007B71F597A07F3A1E01FDE5560651FFCA20 +:10485000301EDD6AE69EDADF005BDB74E3C973E9D4 +:1048600078E5670F9FA3F1B18FEA2F85D6B3853224 +:10487000F3B1599EB5797B61DE02F011DB0F98E749 +:104880004D08E523FFFFBFF3FE5864F4BC85F6AF87 +:10489000B27931F9F807CDEBE3170A505E011E3B00 +:1048A000E3E7A0157FBD2B28867DAE99AFD3CDEB76 +:1048B0001FC5A723E79519CF675B0F65AB5F9B5FAC +:1048C000F3201E7BAE61FB849E43F3D1EFD0F3C295 +:1048D000A5E3008E9CF8F9244CEDDF29D03FEDAF25 +:1048E00047B32F36578DD23FB32FEE6B247DAD9358 +:1048F00009793A6700F7C3144E6CBF95DA9F09AA8D +:10490000E0AA5EBAC5BD948EB7F5BA8D6EF02BF5F0 +:10491000707BB1EAA587372CA0F81C776D7EA59D2A +:10492000B2428F5BFBBEE7F929F4FBE66BF877EE4A +:10493000BFA2DF5F82FA415E3F1D5C85D2403482B8 +:10494000F242E1D2E15F2B7FCAC6ECD227C1CE3A58 +:1049500017F633CCCE2AF4F42E05FAE66C959407BC +:104960008591FDFE6FAE4FEF033B8DCE77CBB5ED5E +:10497000456057EDDB317BBF0FE0BA86A03E3F3785 +:10498000B1ABDFA1C0F8AA00787ED241343B0BD78F +:10499000F9A26B34BAD60B974EC276DCCE62F9EF31 +:1049A0000FAFAB5F47BBA538CAF2CF347FB7A64580 +:1049B000D495ABDFAE0917A7CA5F6CBEB106D6DDD2 +:1049C00019AEE89B7329E96650BDD742E198212AC8 +:1049D000F618F0CBE680A5BDB8FB79574382E277A5 +:1049E000F78E2913AFB55847281591CE5A7EE62188 +:1049F000A39C3D09F873021E99DDDA4DD10BF583B6 +:104A000051A505F039F31009C17E349DBE4B47C74F +:104A1000E036A3BE9B211AE775B6E6F31191D97E65 +:104A20009BF74FD7F5976D6C3E7690A3992293FF35 +:104A30004F3B9F24E089D911BFB1EAFFEF35DF1961 +:104A40003E3A4EE0B31F27681A275DBF667DA5D6A4 +:104A50001241047F7C1109013C79F36204FCF87671 +:104A6000DFE1A04AED3D511EC0D411180CAA54EF4D +:104A70004A41A510526771A810BED3FD11978F8EC1 +:104A800026D4ABC3F9CE26D0A3EB218FF2B716CB39 +:104A9000370EE7D761FEEE094C3ECFB1DFD30F7A78 +:104AA000B80C940D856B5DFF1B0DE0072838E00BFB +:104AB00081A951E00B11D0C35A794FFF7B4117D820 +:104AC00071077CC44DF93D5F0E137DFBF5FD7F0D35 +:104AD000CAB4DCC7CB7D8188A17C63FFD4C22045EA +:104AE0009187977B82512CBFBB7F4EA10276CC0170 +:104AF0009F0CDFBDC5311CF7D25FACB4A13F76B1CE +:104B00002DE1D4E9ABF8E219A8DF9708D1A9764ADC +:104B10008F9A5F74BBC07E881FA81807DFD1E6415B +:104B20007F92F87F613F0AD9D36807F9E4A3E7735E +:104B30007AD953F4E886F30AF403B3738A383FA7AB +:104B4000506B9349185FCD6174A21C9DF23F63FBCB +:104B500043297F35E60F1BF27E3911867DB418A0FC +:104B6000FA81B6F786D530D05D2A6679BB2F9404DA +:104B7000FDB1F91B2404608B149F507FFD1C9A57D4 +:104B800080FE116CDF398BE5A56054857CBC92E515 +:104B90009DC5B124E4D74E65F9CD1A9DC9A3463E03 +:104BA000207F42BA770EE7DDCD501ED7F886789B7E +:104BB000A17CED454CCF168935FB00FF9BFB3B0BE1 +:104BC00097D3FE73811F68FFB94B42482F8D2EF794 +:104BD00029365C6F35BADCA7CCC07382CA5C8A09FF +:104BE0009C9082F4A83CE7669B0CE71DE7DB123B38 +:104BF00005389FEA760FD07A9BCB6760798968E7A2 +:104C0000FE01E60FDFC9FD0165D4BA00BB63275F73 +:104C1000AFF7DD332517DAEDDBFABF90DE17DBF3F4 +:104C2000B0DDDA72767EF32C5DA7C14FF74CA30B93 +:104C3000D31FD1FEA2545F3FD1E8C2F4078D32A644 +:104C40008F523D0E69372D4F82DF81962769BE6FE7 +:104C5000C05607F27F4F2335CD68FBBB1B5D1F8B12 +:104C600093C15F21637E7D6310F3DFB6D5AFB133AF +:104C70007F8AB782CEEBE99727A17F2FF4862D920A +:104C80008079CBA4607155EABB869F6FDB6AEF0425 +:104C90007EFDE18088E31071A0EB7CEB7ACD506F54 +:104CA000FA1B22EB2F30B0F1B28065BD0EA8F7F8E9 +:104CB00011063771253D69FAEB06782BDEE6F00523 +:104CC00093F969FADB00F51E3BC2E1F325BACEB3D6 +:104CD000AE772F8C7BDEDB1CBEE2C4C645D6E37EFE +:104CE0001FFA73E5337BE573E0CFA8C2756087A038 +:104CF00093E74D4B55C146E9EC2A188841BD6955EB +:104D000031A18C8E1FB83A26D8A6313BC346F36E2C +:104D1000E887A6E797D3725A6F1394FB75E5D09E88 +:104D2000A6532B5879E09BC6F261BDDD40343B357C +:104D300009CED6E0578CF92936A61F9FB3FFB606D9 +:104D4000F87D8AC4CAFF1BF260772D36D5F7B0FC18 +:104D50006FB5FA39ACBD4D6479573E9B77CE565747 +:104D600002ECAE0DF3DB83CB7CA9F9E62D889743EB +:104D70005E9BDF86055B83CB74F3C9FBC2B6F2652D +:104D800015E9D715B7622361DDBA3BA5B782840B5D +:104D9000FEF9F5CB5775EB06AC2BE3F8BA30AE9ABB +:104DA000AD2B146F2AB35719DED65F64C45BEEC512 +:104DB00046BCADBFD888B7DC4B32E3ED977CFC74C2 +:104DC000F8A3E387F5E36F5C681C3F7F9171FC8D6E +:104DD0008B8CE3E75FF6A9C74FEAF9A6B7C638BEE2 +:104DE0005C6B1CBFB7D638BE7CE9A71B5FA34F67BF +:104DF000FF16E3BA5E15217AFAC5FB3B8386753D43 +:104E0000C4D675AD7C6DFF4F83B0BEBB617D07FF1F +:104E10004C395BDF2BDFFD28087EFBF5171D0CC22C +:104E20003E633DAD7BB822B56EECBBE856DB63B4A8 +:104E3000DFEF4C65EB4CFF45CFB840FFAF2D67EB84 +:104E40004C9C9FE77635268FAF74A4E6E58FBB7147 +:104E5000BFA7E587ED25F2BB1AE0C378B98DDB4B20 +:104E600085CD616A8BBAA68A867C67052BBFBDB5E6 +:104E7000B059055F8AA816C23AE42D277FAEB0D894 +:104E80006F69E36BF0A41F9FED8B53E34F348D3FAD +:104E9000D130BE96774F63E5AA38A916E0D9CCF792 +:104EA000CDB788BF43FD72F6E09BD61C9EA4878FCA +:104EB000E553F0B1BC06DF5DE2F45A75D2DF13BEF4 +:104EC0000B4CF8BBC084BF0B0CF85B23569F11FE44 +:104ED000CCF5BA4DFC790309DF268E013922686FC3 +:104EE000C644999F07B1FEAA442E5F303EC4ED2C04 +:104EF0009512934B59793D5DD796887C1FC6EBD7A9 +:104F000099F29AFD0ACBD169F4C358DBAF12617AEA +:104F10009BDA1DA19DA8D743284FA97D07F363887D +:104F200062241CB1D007F78AEC7C5890430D00A78F +:104F3000E893D08F9AAE7EAF2870FB5A359CEFE491 +:104F400092C1A41DE008128C4F2227BFAC5C3E6DBD +:104F5000241C921889C2387659220FD2715AF3AEA6 +:104F600050F4714C8F6AF004C3088F2433782431D5 +:104F700014B6F2033F2832BF85D60F8590B71F24A1 +:104F800060276AF0B5B9230D4BC19ECF93104FAD8A +:104F90007EE379F96FF8BC5EE4696B9A733F02D1E6 +:104FA0001810BF34B61AEDD096EA5A17F0A542424F +:104FB0002EF0D7B7FAACE389B4D46C77C6A95D0AF2 +:104FC000F9766A9742DAEA7BB20ED69DE3C0C7163D +:104FD000E7DAC37A2E642349DDFED35BEE214983F1 +:104FE000FF348170BA957CC37767B0C8D0CE315694 +:104FF000447BBED5674B40A8D168F0B773F8B57A4B +:105000001D62CC2567B15F76068DF09E3DFCB1F642 +:105010005E479F6C05D76785378DAFCCFD4B05523A +:105020000CED623112D4F3BFDDC1F8542A70C5987B +:10503000BD9EAEDCC3DAFB6839D8C5BE8802E72F57 +:1050400054E4314ECC0572A0C3CF78DEAED5C1CFCB +:10505000A3490CFDB582126B003E72154B783E6081 +:105060006EA7A51EDEBEE393EFBC8EF231C685F2BD +:105070002128547E2CC6795C0C8F75D074B3181E11 +:1050800007A9E3943D6A2527631C4C8E5D9188E255 +:1050900062A12696F0CFE4FDF66AF0AB313CF7CA88 +:1050A00016FEB22CE19F99827FBA6316C2FF39487F +:1050B000D3C13F8DC3534042FDB06F0706857E09C3 +:1050C000B95CD19FCBF5F07E0B387C84DC8474D343 +:1050D000CA3B391EB29DCFDC2CE7D3939A4F1D9F5C +:1050E000CFC24CF3F9029F4F8F83AD57AEBA8812EF +:1050F000A47C959F862ECB79FF5B87E972D319F14B +:10510000D557B39CC7F2D43C9672BE5A96691E51CD +:105110000E4FAF9DCC3902F13313F97A43EA0D7487 +:10512000D9AEF19593AD1B84DC6CA0CB3DBC9F6CDC +:10513000E7B33ACBF96C4FCDE77B9C2E77649A8F1F +:10514000AE7E13AFDFCCE50AED96ED8EBDCD607F70 +:105150003C2E46DA1DB352E3D17A1DFA7AE3DBBA6C +:10516000B47A6BE1BBB078B85E371F9FDB450FE1C7 +:105170007EAC0D6C0C6ADF7CB1EDC55AB0C769BB63 +:105180008DD87F84AD9BB4DDDDFAFE67B6DDDBCC68 +:10519000EBDD07F59A2E3DA5F5BF59DFFF764752A7 +:1051A00083631BC25137DCDFFDFA7ACB1D7DCDEC6A +:1051B0009CB0583EEAD5D935C1ECCE7D1C81687CC7 +:1051C00000FC95C4DF0B7647BB18DB3E00FC408D2E +:1051D000BC9DF4FB6DCEB020D0F5530EC71E817A76 +:1051E000F9AA53B603DD6A633F82BC6A2311888B38 +:1051F000BCCF7BD776C8AF115DB23304F696824739 +:10520000433D0111E379DA84A80AEBE20931FAACF3 +:1052100003ED1EDA251DE7B60225D12580FF96088D +:10522000CCEE60706DF05E1D07389C142E880F6EFA +:1052300033C145C7C37D79E718166F4344522E42E8 +:105240007F764F08FAEB1F732BC21B6F72CAD03EDA +:105250003EF95684979645303ECF1143783B1C2E3D +:1052600019E2F1EEF3AEDA0CF1766BD45CAC8F7030 +:10527000C0FC279621FC6E124B2E2D05F5D51BB6D2 +:10528000013C8B258C4B8E0736E2FEB66B315DE41C +:10529000E8B85DE51B5568777CB107E3EBDCBE5EE3 +:1052A00002F15605974904E280DC815EB433F317BE +:1052B0007958BE98E038F99F67F1B20E322097D145 +:1052C000B420CEE28EBBCAEBD5A560C754B37854E8 +:1052D000A2865F86F8B63CC2FFECC5FDD0BF63BCBA +:1052E0009DD84329FA16F40EB7CF8D5AC8CB70BD9E +:1052F0004496F592D9D5CB8F8BD9D5EBCDB25E2222 +:10530000CB7A4956CF492ECFB58AF718E6FB7912EA +:10531000DA1F5A7C5B0EB5FC87ED935266B7EBED56 +:1053200015079152F60AF0997D494638D6BCD51436 +:1053300038A0B36F02923F80FB8D0BC8052897A35E +:10534000B43FD1A8060E38469F2F485852E7271F72 +:10535000ADFE5AB0F79CE9CBBDD3AF08A23E9BF699 +:10536000359E2E616925FD5E016903CF7F8DE7972C +:1053700034842DC6AB91981E2E27918C747073F8CF +:105380008FC2993F6D522ED2FA16E7E35AEAABB0BC +:1053900099EC46A3BE73896A2D9E7394B3F8412796 +:1053A0000823C84D88A07E7190A45C86E78BE19CA1 +:1053B000A56353F2E3088E45F9F93F85762254231D +:1053C0007D428047339F98F9C267E28B4FCB2757C6 +:1053D0009D253EF1C6ED59C98FB737CB7A892CEBA5 +:1053E00025B3ABE78B0BD9D5EBCDB25E22CB7A4997 +:1053F000566FEDBF48DCDF7A590BF861BC5F74195A +:10540000F26BBFE831967FC967C8772F34B6F72DA6 +:1054100032B6EF5E646CEFBB8CB57FAAFDAB9782B2 +:105420009F275B39F9DDDF2827E5AECCF5F3178F31 +:1054300022572E15F7936E5121C900AC5F749D124F +:10544000300D272CECBBE7B9FCBFE0607E9CB8A810 +:10545000E2BEF69F7D9E3F9098DF489BEF68F06A22 +:10546000FAF7F7766E6F99EDAF61BFCEC9D3A76734 +:10547000831E21102C4D64854E8DEA1B0FF1842074 +:1054800054C4539EC0F36973FF5D705EC7FC2EC1A8 +:105490007A1D1CCF3B995FE5E7A5ED413CAF9DBA76 +:1054A0002B08FBF4AE0982A59FE594C4CE05CBA2E0 +:1054B0005EB4333A1417EAC3AE09EC1E5397238146 +:1054C000FEE3AE52637B17B71F4E496CBCAE3B6325 +:1054D00004ECFFB6A9BB1A605C67F25F8942E1FE8B +:1054E000EE8418C68FB63BD93EC0195609AC0B2EB8 +:1054F00045C5F377333C712D6E882482F5BA79D790 +:105500003B19DFFC9CCE279B79BD2B49585F0E339E +:10551000FCA5C3D7DE33C4D7B54ED6AF127423BEB5 +:105520008E57135C4F8090F6D9048FC6D9DF20D1F7 +:10553000F387793D060A337E3B8D7945BC2A233FAC +:1055400099FD30CAB6AF65E4E70EBE9E3BC9D7B140 +:105550005FA7120B83BEF35624C832C42F0993B140 +:105560009CEF14F8BF56D546E5977241682B6575D8 +:10557000EF98CE50D2227E6998FE1592515ECE7081 +:105580003D9BE9A4EB9937B59E1D27DDE884EDB678 +:1055900091EBACF0AEAD674AE0AA8CF3EE6A647EA4 +:1055A0002B42EE207D309F57EC481F5B395137501E +:1055B0007A392B443CE7704E4A10A0B3AB9C24DDF3 +:1055C00039E9E7F51AE73B259879DC1E8EEF6E4E38 +:1055D000A774F5BAF9B9E76B1D0FB5C0FE2D6F1EA4 +:1055E000938361BE171306FE1C92985FA3CBAD3464 +:1055F000613C4B29F38F8C983787D32C57F134F7C4 +:105600006934B9FDABA4303DE44AA0DF41932F4596 +:10561000F957D4735D139A5DC0D471E541F4131F3B +:105620002F9708DC8331EB032DD5ECC84B48B70B23 +:10563000EE2BAD7DC51EEAB280D70D44D0F9F5CC76 +:10564000FA7A347D72DFA7D4273FD1E47EA43E41AD +:10565000FA5CDBD1BA1FE8D3E566FEEBFC3A952C89 +:10566000D5CDB79B8FBFC4C9D7856206479743AED8 +:10567000D1D3298F7EAFD1EBCD34F44947F72B211D +:105680001870560A0EF3FC763959BD7C18BF627447 +:105690003C8CA403C3438BD39A0F3EABF9343BB38A +:1056A000E3E36DBCDE368E576D5EA3C989D67F1FDE +:1056B000C757DE3C93DE175503FDED1ADEEA4CF5C5 +:1056C0005CC67A1A7E4427B357B47562B4FEDF967F +:1056D000187F98FB4F2787BF19964315FDB2DA381C +:1056E0004EF21CFA0F8E53BDDC5549F7A3BE418C18 +:1056F0002FA07B7D8C6F82F82FBDDE35EB2F4DFF09 +:10570000A7D347E67DCB68F5A58094D14ED2EC9A1D +:105710007C7E6FD2C5E381370AD6E73C435C8EA816 +:1057200062CF2AAE0FC244001F2442F8FDBF707F33 +:1057300013CD8F0D494A17F83FC4F9FD3B687ECC65 +:10574000CF9CA42B042E9779FDFD94DFD6865D11A6 +:10575000281FE72A1DBEA7D53B1BFC5ACCEE22F61C +:105760003B5E877BC063AF1409E0D549E6609CF6D9 +:10577000F13594769523E1192B12323E9FA6DC3F3A +:1057800080E787B0A5FC8A119F64B12E0F7E6097D9 +:1057900071DDCB76DE6678D2B51B159ED43EF4085B +:1057A0008CEF2499D7B5339DDFB05D9BE5BCB4FB8E +:1057B00068DAF7D2213B51E07EFB9080E939435E05 +:1057C0004C4B86DC984E182A200A255AF1501EA60A +:1057D000E387C6E3F7A2A1424C0B8726621A1C2A74 +:1057E000C5346FE87C4CE5A1A9986EE072983B3413 +:1057F00013F3DAFDB79CA14ACCFB873E8FA96F68F3 +:105800000E2BE7E7A91BEE8C12F0574BB00E51F9A7 +:10581000689BBF1CD725F3BC36B8D83ADCCEEF095D +:10582000B79BF4761F2F7FCCC5E47E03970B22C66F +:1058300088DE6F7E3FAFB7A12C8AF677BBB61E1607 +:105840002E37AC87E6FAED69EE273FA395737848CB +:1058500079FD28F461E7AFCE4014EF0D101245BD7D +:1058600044C4A841EFB66BF067798F70C3FC6790B2 +:105870008FDD549021B4D0FD856D0D0F83DE5970FE +:10588000EB7507A8DC7DE88CDEE68271BFB002997B +:10589000EEFBAB6E0F82DF77C3FC7BF17E1398DFEC +:1058A00010D7DCB1E08ED8C3C87551B4B369BBBBA7 +:1058B0005CBA73D0CEE5B737ECA2FD29AD36A2E8CD +:1058C000F8B5E40E0F51F4FAEB644121B42FBE2574 +:1058D000DFF0BD686591A19D764F22784D99A19E1C +:1058E0003CEF3C43BD9CB9338CEDF839B9AFEA428B +:1058F000433BA74FC32B3B47A4F437AC1F1D823556 +:105900001D632EA62FD3F1CD152EB6AEA5FACF4C22 +:10591000B774FD677B2F24C51F69E781E710B1F8D5 +:10592000E279604F39E528DE5339F3FA67771ED9FB +:10593000D633EBAB1CD05705A04F044C7DA0AF0A6B +:10594000408FB831D5EA9DE97DDB75A06F7C3A7D4B +:10595000338BCABD053FF8DC99F5CDF9BC7CB29B11 +:10596000E99B759CAFCC7C13E4F5D681BEA9185D8C +:10597000DF04DD99F54D251FEF1FAD6F3A67DC1B86 +:10598000FD16CDB92FD8D6F0104D3B2A6FC53CD5AA +:1059900017A29B9677CCBE23F6904E8F9093FFC9AB +:1059A000F892F3436EB5517F68FDFB43263DA2C9D3 +:1059B000C3DF28D7A738BFA6A3CF914F29D7A7CE3B +:1059C000925C9F7275CD83F3C56CE57A64FDB33B41 +:1059D0008F6CEBA9B5247909EC4BA678122DE0BFAA +:1059E000B4F586D8BDBC28C6ED743EEFE07E1EE659 +:1059F000FF9BE10A2F02FE99E18A2C76D3F63797B6 +:105A00002AE3609DA6F92FC2775D3E62CAD79BEA62 +:105A10007FC594BFC254BF415F1E57947170BE18BA +:105A20003FE4C0F3C1B862ABB3E2A7856EC62F876F +:105A30005C9128F4776EE2BC7140179A5F86FDB9DD +:105A4000597F347F8D29BF1CC74FE5AF3395AF30E9 +:105A500095AF34E557E9EB779E9A781FBEBFF14BBF +:105A600007D969E14F7A95EB898EC9B7479B995C55 +:105A7000DE06ED3BA6DC115B46902F08C06DF79962 +:105A8000F67F94CFF4FC7288F7F3F309B7E2BEA96E +:105A900083EE9F308E11FC7816F8F9B59BBFC3A535 +:105AA0005C8FF71FE28537A39FA3A3B819E3148E79 +:105AB0002B129ECFC64BADDB7736323F5347B1F545 +:105AC00039C2AF210857678F9049CCFF076270DA5F +:105AD00006EF0931FDDE56DA8EFA554A5ECFFC1B21 +:105AE0008551F46F3CC8E927F962E8577016C72C56 +:105AF000F7F51DC3F830FA35F769F8E0FB481D3EAD +:105B0000500E9B3B3F3C00EB6BDC6D2D673F7633CB +:105B1000397304B31B7FE4FCD9FAB01D2EB558ECE1 +:105B20006BE30E1627AF4E607E00918EA3F72B9885 +:105B3000C71B9EA7699FFD00C753DCCDE2ECB5FEF5 +:105B4000CCF03CC2EB3DE2667E056D5EA2CCC61990 +:105B5000ADFFE7E0B216F80164B31FC2A8E7EEE0BC +:105B6000F51D0163BD74F8B973183F2C1E4BE3DFBC +:105B7000D1F85D1BE710C085FB59EB7DB872B21AF6 +:105B8000E3378E137F6F17EC9B45F97588E3B88D6B +:105B90006E93C0CFDF22AAE85F501522EFC4F34F07 +:105BA00076FE709BFDBC10E83B178FAB20105711A1 +:105BB000D0C525829FF35C8CB37804CAD7A84E1950 +:105BC000DE3719724F6471AB27D7603C4527DDA9DA +:105BD000C3B827DC250978CFCA9EDB8DF6BCDD5E15 +:105BE00019B38A33153D8C6F2F39B91EF56CBBC2C2 +:105BF000EEDDB48B51577E05B8AA5594D74E257368 +:105C0000FCA2390ED2219BE30F8DF89AE661F48D48 +:105C1000F3F537EE0E35E8E393821E37960FB98D14 +:105C2000F075007C3E802B86F1A4F1629B0DF0762E +:105C3000B6E0D3C6954A6D11C04B8044315EC515A0 +:105C400014715C9B97E137DDB844113FD0BF1F73DF +:105C5000B6F039BCFE46193F89C483FCA4CC73D589 +:105C6000EE86FCF3CC2F6F1EE788277A8147E71773 +:105C700016E528FAB7B4FE168E6171DE6231C1FBFB +:105C80008A1289D495D2F9B714B3771645DF2871F3 +:105C900011C5667F45BA7339763E824554446BFE22 +:105CA000C0C6F5F078013F19C060D15C50E91321FE +:105CB0005E4011D83B102181C595CFC538F280FBDD +:105CC000B3EE7709F62B843790D3DE33E8571C40C8 +:105CD0003FD767DEEF28F0BAC936EC1742534F17AB +:105CE000A4FA05FD8B4EA593A74FC3B9999D687F74 +:105CF000CC0E176DEC5E1529CAC1B8C3B6C0CD2E47 +:105D00003D5D9B3C6586F55592DB6F1272E0DEE7E8 +:105D1000CAF04006BE6C0339023F62F135E181F200 +:105D2000F4F53438453A7D2B7F68BB144D3481BD82 +:105D300058E263F1AA620CCF473A84FC195D553AE8 +:105D4000FE2D96920097BF2AAC423C6347812D04FA +:105D5000715822E93E8CEF3BD9178732C9AB582CDA +:105D6000BEAF9FCF568F310EA465147E6FE3FA3A13 +:105D70005DB9430A45ADF4F0131EBE8E79ACCB3F3E +:105D8000F6D63EE6B15877F6723DD5914755E9E72C +:105D900018FB001F88C5075F073CB48D5990593F19 +:105DA000C946FDF45FDEF04F609C0C703C67050750 +:105DB00081C714B2B0FBE579188C988A070A30BE07 +:105DC000863820612C9CD2B2BF75550F26C1EE7665 +:105DD0002CF585817EF6F06E02EBA81617640F7B1A +:105DE000DEB1213DE7B2F8A072E6670DD3FF308E39 +:105DF0006C6EE6B831BB29FF2B339D1B9FC5F72284 +:105E000034F8B53875F3BC9EF2D6BEED9965858F32 +:105E1000ECF6419B28BF10CA2F1BE9FA4E91427A3B +:105E20001B65CCF7340631DFDDA860DADA588EE97D +:105E30005A683A07E23F62F152D88F041F0E5E4B58 +:105E4000AB6C029A605CCB8EF9B08FEC1ACE135516 +:105E5000807325B81F4FEDD0BF7A36CEE7E76C3C94 +:105E60006EB67D3E9EA30DE7B7B4815DD8C5E368ED +:105E7000E5B50FCE87FDE3A609DA3E39ECFAAACEE6 +:105E8000FE9AEC75B073A652AD7D4B1BF4E7167904 +:105E90009EEC996FCC9330C0E376B1FC42EFD3080F +:105EA0000FAA003ADEE5DE6730BF6932F73B54D413 +:105EB0008F8247E6C768F728CC0EAAC8473F8514EB +:105EC0000AC1F502B2298FC39D653FB0FFC1F5EE4F +:105ED00015EBF5322537A3AC6B1C8ED1E84FD18181 +:105EE000F605E86115C67DD58EF270B6C7DDE438DB +:105EF00033BC48D5832A5CFDDAE7895EE4A5EDFD75 +:105F0000E1BE6429CDE72C4EAA28BE598E5BE8E598 +:105F1000F7C9E87C41FE353C6B76C74D40C731A9D7 +:105F2000FE1C8130BE23E1E6EF09670BEF728F6C38 +:105F3000E8873C5E5B98E9DC654CC4064146C3FAE1 +:105F4000A2A0CEC38335583E2F9C6FC8E7561719C1 +:105F5000EAFB43658672877C9EA1FC6FA5D3D73D83 +:105F6000B281AF23A679CD379567DBAF7B8D5D819D +:105F7000F7204B45CD1EDD88F7928F038E413FF60B +:105F800056E23D5D3249BB8740C210AFE256C2C8FF +:105F90009F1E12C2755A2A36DAA962C068A7061B6C +:105FA000D4A4D62FC425B8D74838EEF03AE563F12B +:105FB00020DA3919EED72782AAFBDEA152D6CE32DB +:105FC0009E414B457E5E8677EF4B473F4F358F13A3 +:105FD000FC4AE63835737DE21395A33AF94BDF4E60 +:105FE000244775EF6AEC00DACF4AE13FBC7B29FA1F +:105FF0003D9C84DAD114CF2DC12B4894CEB31DAA79 +:1060000050FAC521A57CDE1E9C21631CBEC2E86A35 +:10601000733139F98E5731C473D87D4C4EB47AA39D +:10602000D1FF363B8959AD67AF7AD93EF9C45DB12E +:106030003FC1FE527D99E03BAE7D8D43F8CE655564 +:1060400072A11DFC26AF7BC7E27CAA0E84ED97EA05 +:10605000FAA922ECBD6FFA67D7FB5335FF3039E957 +:10606000C2B8E03D491617BC27F9DFFB4F43FE904D +:106070000DDF15DD7338B37DD5C7ED2BAD5EDF21A8 +:10608000B65FED1389373F939DC3EFBF55264D7122 +:106090008722B103FD4FDCA9D8C1DEE96B7409B0DA +:1060A000EECFE0F3AC4A86EDB09E8E36AF7D26FA99 +:1060B0006AF384FB8730CF561FBB0FD82AD3F9224F +:1060C0005FB3F7B2D3C13BBCEF97ADF121F9D9BBB8 +:1060D0001792232A5BCD7BB47B8A1A7CED009F004C +:1060E0002983AB3DC0E8D01ECC4C87160E9F56AF1F +:1060F00035C0E8D04AED836CE0117D4678A88D2745 +:10610000805DE823893A7CD34C252FC33E08558512 +:106110000278D897BC1FE0857B1760CFE75509D779 +:10612000C2BD8F28B30FFD55C9E4DE009A2711B810 +:10613000975130D09F7C9B961F6CF0E2634FF2B575 +:106140004792D08F280FA2FC74C160681F4D6C0766 +:106150007BA70DFE4955FAB8EEE002B03F44C2F409 +:10616000029538451CCBED130B79D79DEF0BA79DFE +:10617000A976E9F066B63B9DA43EB3BEE2E7FD2AF0 +:10618000FD0FF48D6CBA1F61B673CD71F017813EAF +:106190001F93C53D8C4F394E2E79D005EF21D8CBBA +:1061A0006D32BCC34C557A1EDCFFF1864502718D01 +:1061B000B9BE017C3A6B34BC53FD57C7E246FB883D +:1061C000FE1E69BD8FF98102F55582C0EE1128F0DF +:1061D000EE66A0FE50C88A4F35FE1CCEFB9E44FDE5 +:1061E000D8461271883B51EB6CB8AE759597E5E9CE +:1061F000F74737F904BE0FD5E84F1471768AFE745D +:106200007E61F7F4BF1FFDF3171BF17EA674B9D3AF +:10621000C7F4D268F4FFB4E368741B291F4D9C6E69 +:106220009B50FF754ECA4EAFA4E8F620CAABB79C90 +:10623000841316ED9A39BDCCF7F65D2446E0F728B5 +:10624000ECAF307BDA3E6E76C30E92812E23E2AC49 +:10625000583F761FF3A7AD133C21186A5D1AFFF271 +:1062600024BFC0F5FF008BE79B733008E7C7DDB3A1 +:106270008E06E19CA3E713EB73C8857E7E2E127E0B +:1062800003F7013DB3985F10FE40EFDCC6FE49CA3C +:10629000D4F736C33B66EBDEF21AECA1F6C6CCFEB1 +:1062A00006A9E8BA28D81927DE1114586F84A23538 +:1062B000E7025CFD7396E3BB23ED55FBF01CA63BA8 +:1062C00094992E5A9C6FBB29DE36DDB9E1092EAFB9 +:1062D00065EA0D685FF614BE8CE3ACABCA3C0EBC3D +:1062E0009795299ED7652351F4179BCE75DFE4E37C +:1062F000BDE9E3E7138EC8972696C2EF72A8E81FA0 +:106300001B5B1EE9B751BCD5FBA3AFF9285D7BE64B +:10631000DC5A0870C03B317ABA07A07F0BF8C6FA86 +:106320006D06BBE94459ECBFEEAC82DFA79882EF63 +:10633000D66BF5BAD3C4B19FA7D15971E3BEA71DDF +:10634000E2FE297CDD85D9E15FA3F325E405D7448E +:10635000680F71BE19F8D9BCDE8F8677331E7A1CA0 +:10636000031807D52358CF67A19FC95DCF9D4976F4 +:10637000AE36E7289EABF9926F60FCC477671DC606 +:1063800073B5123FA387DF378071A539D5EC3DC0C7 +:106390007472F400A79F281BEB1171C070EEB3DD7F +:1063A000C7CFCB0299FBD3E024AE0176DE33522E69 +:1063B00071FDD9D9FDF0417C378524F15CA1FD55F3 +:1063C0003BDC4D1DC6C308B98AB3DF85E9818DC7A3 +:1063D0008530CE5DEDE027E9D1CED92AD9BE49ACD2 +:1063E0004AE2399BCBAF18E3AF43DABB88D9CDD3B0 +:1063F000076B11F30F8BB0AE823F1EE06BADBC029A +:10640000FD69E9E8FA1D6F74A67F8CDEAFCFF65DFB +:10641000FF6C7C78C2A718EC43333F3AC937CE688B +:106420005F97CEBF7C82CB67002AEAF649DFF44B48 +:10643000D6F87DFBCAD1F0FB4D6BFC5EE501784FD1 +:10644000DC63FDFB445ABAC5A4EFB668F128F0231B +:106450002185D85FE9E516F3D6D6D5137EEDFD9EEE +:10646000A807D68D3275AE07C6DFD5BDCC03E3EEE7 +:10647000DA9C999EDAF8DBF9F96282DF77D1CA13E8 +:106480009C2F7798F4FC2B5CAEEFE7F2B5CB15F1BF +:10649000E0EF55ECBF6AD1548ABF32CA17E05254BC +:1064A0003A497EA6F14B55D3BEE40CEFB5F4F84D56 +:1064B000F1BD59DED3FCB478D901FC7321E0E1DFF2 +:1064C00051EEEDC95C94A7B2958C6FCAAE194CC25F +:1064D000BE76E2265B42C1389628E2A570A5A86088 +:1064E0004C1BBFF77A2E5FDF89FD0E5B0994C3BD9D +:1064F0007119DC2EF2D7301E669BF1F73F76B9C2D8 +:10650000CD12D8BF718C742465DDC6DFCB184F74F3 +:10651000BF5741C72D7CEB3DFCFD9442D3EF827CFD +:106520005ABCEFFD07E13D21128F5E1F2B028958F7 +:10653000E9FDFFE47CA9341D60EF18C47CE45DDD57 +:106540003907A55F3ED805DBD58D35804F354E42E6 +:10655000932DF4D86FFD5EED777C0EC03B0B8E6201 +:1065600076FFAC6DE915037BA9CADA7E472DB13AF7 +:106570005FA17AE1B77E5C9F985E48A8F52C3D69E3 +:10658000473E99DC4D12F03B28F336C5FA1D20EA50 +:106590002BD93BD48571559068BE8C9AAFB47B32B1 +:1065A000F13AC2EA2F218930F211792D3836F57B84 +:1065B00027250337F5C3BEF820DD17C3EFA868BF52 +:1065C00057A2F1CBF898913F26C78DF971267E31FD +:1065D000B72F53C822187F52B78DC0BE6E4C83AE02 +:1065E0003EF44706DF7B848E3FF9003CCC48D3DE87 +:1065F000CCFD8B24EAC8A1F87CFA2EDF2FCBE9046E +:106600001FEAAE2D00BCEC721176EF22E2C27717C2 +:1066100048C4FA3C6904DF6A767F9AFA297DC9EAA0 +:1066200069EB5EC75B027BE7A2447EA714FC9CAFCC +:10663000B1DFAD4BBD5B7121BE5B112431663F9272 +:1066400008A6AD9C3FE54B8B4BC11F1A7FDB2BC3CC +:10665000FD2CB9C0E84F13F3EBF03DB061BB3B9F9D +:10666000DADDB43C9E67D4A33539CC6E0DE5B07B42 +:10667000A1B297F5435C6AA15EEF6FCA118CE53E4B +:10668000B5F0CBBAF25ADE3ECEDF2DBF24675107FC +:10669000D833F2785ADF823FE7F171B57212081DE4 +:1066A00086F73F367FA37E967E3DDF94C3CE77E4A8 +:1066B00073F8B8C5D670C54BD9B877F37137E518FC +:1066C000DF8D23324BB5EFF7FA6F158E507C9F703C +:1066D000905A88576919634BC0BB69B78DD5E2C220 +:1066E00032EB098D0EC3F896593C52D175F20CBBB2 +:1066F000851C6BE9D63AE6A7327FBF9ACFA3F5BADD +:10670000DADE4914AEF0012677CE00B13C07A2F2E2 +:106710007D75CE2C8B75BFB50EF77127F232AFFBAE +:10672000E67DAEC8FD8BE67A4D9C4ECA2B417C8A35 +:10673000BB35C8FC895AFF270A995FD1DCAED3D498 +:10674000BF9BD48721CE18CE57E15C559A4412499D +:10675000DA8F27D02B972A101F705885FD91422879 +:106760001EC1CF162268D7B506D97E540CF6D6D8EE +:10677000209E84D4C97A3BAC88FFAEA29677F8A25B +:106780004D39680F8505C48BC8CEF34F38120B0105 +:106790009F2DA53662F54E7F770EB373B72AF52F7E +:1067A000965AD06F438E62B09F8B8698FD9DAE7EC9 +:1067B000AA1E836F981F832ADE3F200AE3C77A7FD1 +:1067C000F89E1CABF35B4DAF703FE4B26AAE7089CC +:1067D00072E5AFE93CAE3FE4C0D8F44B4E6E3F08E3 +:1067E000FAD74EF56F17FE8E5CEF41F0435E03F76C +:1067F0009F68FEFAB7A64925B4FCB5223B7F743EDC +:106800009203E37E486CE82FF990BC9C335347BF5A +:10681000A77224B6DEC41DA847357FDCB5BD0E8344 +:106820005EFDF666637E39A91F0B7E8AE59B1C24FC +:1068300041F17BBD49EF3E94C3CE89BE4D62EDB0C0 +:106840007EB6F1F3BF1B7F324D02B9B97EA65C6AFA +:10685000D7DDBB7A2E87D977EF533E527472B6C21A +:106860009790601FF7EE9E99577C9E403F89F622D5 +:10687000F0A7E559C7017E2B6E8473B47998E1D6F1 +:10688000CEF3D2C121EE162CFD42CFE708067F7C65 +:106890008B8BBD87146E1189FB6288C3A3020B70BA +:1068A000BFE5C7F7BBD5DA18C6D5A9CD4EB9258047 +:1068B0007176184FB786120CDE1F3ACAF94F8BABB0 +:1068C000A306C505B04FBBD13520815F79B518ABA4 +:1068D000839F4ED3CE659C8E68783C85DFF16C4DEE +:1068E000723C31D48B6759EF90509655BD3A5B8618 +:1068F000FE8E713DF98BC71F9260FDF9F0B177BE36 +:10690000087278C373760257F38E3DEE2749DC3F59 +:10691000242490F3157BEC96EF48508C61FF37FCF4 +:10692000C88F7A71C593CEC462DA7EC533EF4E2725 +:10693000549E8E350F1E1C0FF87B4C60E785EAC015 +:1069400074589F5688E49B56EF8EB97399BC7FF0BC +:10695000536F03D04FD8DD7F35F6DB77A543FF2E8D +:106960003EC965EB0FADC7E2261F1512932DF487C4 +:10697000B61FFAE0511657B2E2594702428257EC6D +:10698000DE2145291CAB777F84FC72E98F9EC8010C +:106990003CAC7ED66EB0236EF8D127ED17523ADFAD +:1069A0006027838B418EED27317F3CEC1AB4A35CCA +:1069B000B3F89455A80268BDA77EBFE0D7B4FCFD2C +:1069C000A09D4088EBFB877F273D07F9A88F5A6E73 +:1069D000D0BF91AF57EF7E57C2DF31B291C1E2CF46 +:1069E000C3F987D14E32D7276450023DB5BAAFF311 +:1069F000233BE5B7D57B3E7C13F86EB5493EDE8779 +:106A00007F148EB4CF2B734DF6F9EE82ACECA31B42 +:106A10009E38FE00F8233E78F28F0FC03DDA95A72E +:106A20003E7EE07B1017F66F6E19E47BF563AFE6F0 +:106A3000109DFEBF2C97AD9BC71E7D64D7563AFFB5 +:106A4000636F38115BC7F6FEBE04FC3FC77EFCD700 +:106A5000B1E00FBA65EF7CFCDD9A5B9EBE745CA66C +:106A60007511F835A1FF7D457E6EA43C2B80314920 +:106A7000C8CF786AA207E91D94605DFB8B4006BB16 +:106A8000F2E8F7BE4F24B0CF0E86C920E067FF9E24 +:106A9000770FDE4EF31F52FA382DE843E73FDE86CC +:106AA000FA998A0D4D57EDF9F2972EAA82D4817684 +:106AB000F86A32887A73045D5FA174AD4AD1D55CFF +:106AC0007E9C9C94E0DC60F5E3948ED3819E948E52 +:106AD000D347D2F143F8C79C91745C916B8C4B3ACD +:106AE0004E566EDF0A857B0A2CCF79B57DD68D4F49 +:106AF0007F35A3FDA4E985D1F07C9DC0E09A9D1B64 +:106B0000BE3D17E4EBC91FECDA1A60745E4C1173DA +:106B1000EC89E32584F2C91F1C8357031E06F73A4C +:106B20006558DF57ECFD15CADBB1A75F92148C6F77 +:106B30002139C26C9A27C37F2F139A5F25B0CC8D61 +:106B40000FFFBF056FD2F637C2431E32D20FF307D5 +:106B5000A9FC213D1297D729A077136370DEAB12F1 +:106B60004C2E5625FABF02717D66BC3F956BD3F45F +:106B7000FF305D216E6CD59E771600FFA5A3A7366A +:106B80007F19E67F012D7FD828B769E594D3F7D820 +:106B90008E1312D807C9E724D946EDE1638E410967 +:106BA000D7C71FDBE59DA191744FE19FC71F9DE1F2 +:106BB0003EFC876639E7F8194DCE479FD799E16DBE +:106BC0005BAEC2F65726FC7D70D25AFF3FCFF5C6AA +:106BD0002A12AB2B9A3872FD1249441D5F9A82F734 +:106BE00003881FA3F07EF0981DF787ED7DFB518F82 +:106BF0009BF5C5AA3476F49BB9CC1E58F56CFF748E +:106C0000D06B1FECFB29F2E5AAC7DF91C07F737040 +:106C1000F753D240454A0E607DD0FF0ECE073FECC1 +:106C20009F0EFA6B759A38C0DFF3F9ACFE99B1FF8D +:106C3000D58F7F64E8FF06B54F423FD928E3BC2FCC +:106C400086AF84F9BE7FD8012718E4FD3E7B9D9571 +:106C50009DF3025F1F353CB5FB67BF9E0BE75EF9F6 +:106C6000EC1DC6D6A6F0AFF0F77B5F72F0FD6DF8B5 +:106C700075B0675AF224BC8FD0EABF02FDF55A7F87 +:106C8000BD267CCA01B906F603F2BC48957E5FA515 +:106C9000C19F17B619E0BFC55F374EF1B1FD9942EC +:106CA000F71FFF03B64D466E008000000000000095 +:106CB0001F8B080000000000000BD57C0B7C54D516 +:106CC000B5F73A73CE3CC24C2627AFC9D37892F0C1 +:106CD00094804312DEB40E0491226A505AA9F5AB97 +:106CE00003F28821C9A4F8E25ABFCB8444F4029F7E +:106CF0008D95166A693B70A152217690A0B10DDC8A +:106D0000012C06056F105F78B18D5A152B24631482 +:106D1000B4575BEF5A6B9FC3CC9C4C84DEFBFBBE2D +:106D2000DFEF0BBF76BBCFD9679FB5D7FAAFD7DE02 +:106D3000EB0C28DEDCEA5400D93D6B366461AB5ABB +:106D4000D41409E02BFABB2AD6028400C603585D8E +:106D5000D5E07761AB5A407300FF7D45FFA7785BB4 +:106D60007BF0F97BE5D4D6B5348FB5F157D48726BF +:106D700005B657F2B0914A25DDBFC2BBB61860A375 +:106D8000F39F1FA7FB2B8376D58E6D73EA3DBFA5BE +:106D9000FE0609AA65EAD3F3383E6875A8DB55BC40 +:106DA0009E0E0BC265317AF25424321BA00CE9A06E +:106DB00016FFFC3001DF2B488266A8031C0129590D +:106DC000A120B5C6730FAAFE62757CAC2FBBBAC1F9 +:106DD0008FF35E2DBB2CB4FE07732D217B31B537AD +:106DE000A641D9403E18ED03ABAA213262F0FBADBB +:106DF000D98E855B80E90E5A681D9223B49D08F1F7 +:106E000081A67A8069030DFF873C74C4D18D037C11 +:106E1000B40E45BF6FC565D14D3B04B94D213960F6 +:106E2000EB84084029D2AD96B05C52A1479F240A5A +:106E3000D563006E4CF57F93D6993BB451A2EB1EFF +:106E4000A8E6B612FC12DDB738EBF2FC5FB33E5891 +:106E5000A09CE919A9CB175FB1C12AF8AF28A00CF3 +:106E600029273A36ABEF8FC679E87E268D0AB21C09 +:106E7000C6557D67740BC181888FE3F32333676444 +:106E8000126E8C71CD8EA29312F2DB27A7A8294532 +:106E9000D8579033C4A753A9CCA71F4DC399F1FE6F +:106EA0008F4FA56E95511E8F48024F41C213E10AC4 +:106EB0001A1F277CB8113F6BE9B9198DBF65BC5803 +:106EC000A0BAB952E7A487F827FE106F8CA7958A5D +:106ED00043B57B89B73E4DA1796C105A2B11BD7E0D +:106EE000E6A7035AB91D02616E5DD0CDED5DC4E722 +:106EF0006C928397FB69D0D33A149F9BA356D7AA71 +:106F000078FDC7B333245A9F0B549DBF8579D41F96 +:106F100094BF3391BF8E187FEDC44FE7407E3A4057 +:106F2000653EA47BC1BB761CCF0B115CC723D3216C +:106F30002433885450112F39FA3A33C127117D84F4 +:106F40001F5A5FF602B13EF3FB72A195C7E5439865 +:106F5000DB42E8E636C3A14A0AD3734A97EF3BF017 +:106F60009533468FD1DA09C138FFB9429CBF98B931 +:106F7000ED963CB47EE3AF9A71F887CA83BE2A1CB3 +:106F8000A7F85D3E3B2EE5FF54CE201082F572053A +:106F900048AEAE9E8573C18DC3BD36888CA4D9839F +:106FA0004C5FCA48D137EC8B1D051531E8C7E7ACFB +:106FB000A73E3C45CF59216E1CD121DF9A467C7FEC +:106FC000982E4C1EC8F795A79AB29E8B9B77AB9ACA +:106FD0009A45EB848930F12B39F63C4CCA40233377 +:106FE000F0F9CF5605B39EB3C6F8D0E2F867C6A550 +:106FF0000F019CF24DEC138EB36238465CB29D0BD0 +:10700000AEB6ABCD598C43C6E94A64901DDBCF5276 +:107010008A42BC7E689C7823DA618BC3274978BD9D +:107020004E7587883FF5AEF02CB61326BB317DBE7A +:107030001AC9C7717D8DE025BE6EDC73C369E26B32 +:107040009F07347BBAC0856F02D909C38E8026A3FF +:107050007CD748E31C12B6F5ED1FBFF47B1C9FD212 +:1070600029838CF7FB70CDDDB46EC5974E4274C298 +:10707000FA04FD6E7608FD31D669D6D77F749D2857 +:10708000799E9FE52093FD5DFF2FF47C3FA4B6D24F +:10709000F84D0ABE9AE6EFB286B6231F561C911928 +:1070A0006F2BDAA410909C152D8DFAF7BE2883C0A3 +:1070B0001FF0FD7B7F55CA789461F48FA6E1F381C0 +:1070C000CD562F5A4C48F725FAABCCD943408BC349 +:1070D00001047D2FE722BF16EBFCDAE87C780BD1A8 +:1070E000B3A949F8A7ECEA8C84F19FA55C6F5B8A91 +:1070F000F36B7948D714C24DE7F035D85F5E20AB0B +:10710000329A889C05F989FEB1D5FA0EE99F86FF6F +:1071100008DF86FD5A4AF68BEC907C3FFBBF73205C +:10712000FC9F02C2FF35A0BD8AE07CCB3689E78D8B +:10713000F96A3A1F595380ED1DA1C4EBCB4189F583 +:10714000D9CFBA47921D580943BC766920FE2DE974 +:10715000887F02890B5C420E2E2FD997FE5764AFB1 +:107160005DB082F595F84E7644EE19B1711ACE17DE +:10717000E8B24248237989FBFD9BE550B038A61F51 +:10718000FD5D7B981FCBF2901F884F7B6E22FF53D3 +:10719000B444FE3B47667CAD3C52BD267ECA739923 +:1071A000FFC86FA0F9D32695243EAFF37B24FE13CE +:1071B000FCF6319D4B3B24784C223EAF3F5CA00D4A +:1071C000E46B43C72336D2FF8BF1D5CCC7D1E9BAE4 +:1071D0001DD1F9780E3A0FE8A8AC7678D894F03A39 +:1071E00014B5753AE1B410F5967062D66B837FD60C +:1071F0002CD567C37197D1385C5FBE232C94D10B1B +:10720000CA09C2CB2261779B551FFB23C3DE3A2FED +:10721000D8ED77E12B6CB3E6553E4438BA534A6D4E +:10722000952B07EAEDBA31F7B0FD2A5C8DF698FD93 +:107230006A629C165EE5F02E467A9E5C05DEC5C34A +:10724000009E5AA5726B8EDF0C7DDF8CF19B5DF882 +:10725000679E5741FCAE55C9FE7855A2F3611BB03D +:107260009EF69541682BBE3F1CF9D4A391BD2E8F8D +:107270005E5F8DF145600954539CF1AF1922AE7BDE +:10728000466F6765D8B85D5B6D011FBEA7B7530E2B +:1072900049485FAFEA3B7215D99D4EABC6F1951ACE +:1072A0007DE97B7CBF425D8BFCCCB3B48EA3F7E25F +:1072B000F8D9219CB7AFF35DF7ED717EB9B7E3D193 +:1072C000511407FDCC0235E124F1D0F2740BC73123 +:1072D000BD23DFF1E0B2A1DE11B501E2E9C19EC636 +:1072E0006A8AA7EE746A4C97AD7D7AA480F1338FD9 +:1072F000E3E3E7960E61BCED3D0321D2BB59F2AD4D +:10730000D78EC1FEE45715AF9D95CA77FDC2093CE3 +:1073100084E5BEE1CB8A4DC4BF00F273355F6C3D9E +:1073200041F27AF6CF0A90DE55363EFDAE1FD77990 +:107330003817D1300960822F5C11C151333BD3A77C +:10734000937E074E01EBEBF86E2501B720D71D2A7F +:1073500020BBF286080F27BE61BA0F4199E2FFC930 +:107360003D89D7A75E04EFFF62D80D377808EF8F0D +:10737000ADEA8077C92FEAFE331F17988C9F06BEAF +:10738000F738673C922EE2769970EB55928F7F2703 +:1073900043C4F91BBE9425C2655F14BCAB915F7DED +:1073A0008BF379DD7D9F524086ED97F2EC709278F9 +:1073B000EBD7E93696DFCF6C02F73F5BEA0A35E19F +:1073C0007A0E2EADBDBC07DF77FE9FFC97AB5F1733 +:1073D00007A369B14C6279A511DFEF9CD722B11EDA +:1073E000426B1EF1CD3CDED013436F0C7DC95B3A7E +:1073F000C41F4AF29EE1B43EA46FC6D291928D7032 +:10740000BB5F029263EF6AA4EB6BE2C720AC2E2055 +:107410007A021D9FD8C85F3B3A255F28C9F8C3E9A7 +:107420006EE65FEFEA60D354E4D73D8BF059D20BA0 +:107430005B6B71B2F983B0A1008343684BD704EE54 +:107440001D701BE92528AD79E4B77B3BAABE4576C4 +:10745000FD31D4438A1B7E66F532DDC17A80EDC4EE +:10746000160A3CB15F783D6C591B974776A74F3F92 +:10747000958EF39D4A5779DE4CBF5722BABD7FFBEC +:10748000CC4DF3F77D6E67F9E5930EC7C56D9FA6EA +:107490000BFEACC9F0BDC678A9C96263EAF5BBBDF5 +:1074A0008B2B00AEEC407EC7E13226B720AF3BC34A +:1074B0001F647A32BA3171E2FCCBA751BC1CD08D6B +:1074C0003344245026C4EC73A5A3305220F28770B5 +:1074D0000EF237A3E6C76CAF53D00E53280EDD89EA +:1074E00079115B647C9E749FEC42B32AE2AC967483 +:1074F00061E75A1E5142CDF8DECD4A4FCA306C8B3F +:107500007DDA0C45237B5FC6F3E6DE05ACDF16476C +:1075100048223BE42CFD45FA85B86B2AC0EEBFC972 +:10752000CC7FB39C46EB7AB126C3FF05F1756C574F +:10753000F420856FDE14C824B9CE925DBCEEC96715 +:1075400085FD31DB1B39F2AB9F91BDE9D3F3A72455 +:10755000F6E676F2AF86BD01B9EC10E167EA8B7A08 +:107560009AA9DB19CC3E980F138FFA9B5D49ECCB9F +:1075700024A84E43165FD4BE98E588C1FE857E21BF +:1075800032A3A20BF528EE79B33D2AC8D0FDAF6E29 +:107590008FCEC1B49CABB5185ECA577A0FD9E3F051 +:1075A00061D8A1185E428C33F37B24705CE8ABA5F4 +:1075B000643F8ECA696477A6A3DC71FE2E5D4FD24C +:1075C0003F0D7D8BE4BFA1F39A14C2F5535D550EB8 +:1075D000529B15B9B2F6678C9F9503F383A0C385C0 +:1075E000EC9DF15E2B3834D748E28785F920ABD883 +:1075F0008F7B7F7FAB349BEC220A2D6DFE98C1ED13 +:10760000C18A5C1BBFE7A9AE9234C2910B30BF4563 +:10761000F955764A1C2798716DC67133BEC0C27980 +:107620006335C713B214D6F71D12F3D2E2E064F645 +:107630005377611E4E716B7F17FA2D6C9F423F4F3F +:10764000714AB36B16AFDB58AF41DF5DA93372A04F +:107650006CE0FA8D36F0B90CA1CCB8BE12B5118E23 +:10766000039FDB12AE1BFC1C8C0F063FA7103FA52F +:10767000FF3E3FA76608B99AF9FA3F5D7FE18A4964 +:10768000906C5FE0FF97F54F05FFEF7B44BEF55A26 +:10769000AE27664F0A57CC9697211F26503CEE8D99 +:1076A000D90707FE237C8DED68657B3309ED0DC599 +:1076B00099057561B62F137345BE64B61B5776C224 +:1076C0004D641F2747302EBD04FBF129FD471EEFF7 +:1076D000E3FC3203E91EF7FC82E5BBF0D2580D3221 +:1076E000E7E27BC6762B5EF27BD09D99745FC0EC9F +:1076F000378CB8D48847CDE38C78D4F0270D3A1F67 +:10770000FE3DC3FF64065D57D520E91BEA55F831FD +:107710002FC35EA378A13BBD7A37DF1F190E721EFF +:1077200050022AEDEBA0BE721C56E97045E4B1038D +:10773000F5D369D2C330F285F609822E4B689834AE +:10774000900E0CB78314F7E103FCFEA5BABF28C462 +:10775000312CB406E0F8BF702CF8C9EF1696638B95 +:10776000EB3CA6C7232F995AA4FB79E2AB5581A025 +:10777000BDFC1FA797482C2827FEF8FE40EB77CCCE +:10778000F631FD052A78298E2F50C29217DF9F51BE +:10779000A7491736910C3F8DF315CCD5D85F160C41 +:1077A000C53E8DA77827895C7A32ACBCCE7A47CFAC +:1077B000611BF22130B771B6DB128BD3ED56BFAF30 +:1077C00080F68F3A44BC0EB4DF379EED9244EB5105 +:1077D0006608FE0454915FB94065BB59A9CBB1D28C +:1077E0003197F777C827DA270F5CB7A4F97870FECE +:1077F0007CD082936376D5C87F701AA0F798ED6A23 +:10780000DFBED72F0BA23EBEF5BF3F4905BCFF2709 +:10781000259A4AFC387DFF89541FF2E3ADFB45FEF3 +:10782000F27D537CA4640AB92ECEACFE82F87ADBDA +:10783000AABF4D88B72FB0329BF5E28E904CC9F0AD +:1078400005FD59BEC3C97BCF46BF3E9C99D037F4D6 +:10785000A0DE0E8DC9E2EA6999222FBA63D7161B02 +:10786000E5D18B33FDA999D83FADC77FA7DB53790D +:107870003FC0A067D1AE7136E2F79F3AED106103C9 +:10788000D96D1572F65D2F4DA0CD7BF167A6F3F093 +:10789000FE021BED9F2F91202AF6B5E0F0CFB1FF3D +:1078A0005EAE0C6BBD03D7B1E42DD56641F92C99C2 +:1078B0000ED120EAD5A2BBA435F7E2F8457E1745E4 +:1078C0007003D6B9309898E72FD3E395DB1FB29AAF +:1078D000F2A4C6C3B45FB618E7A17C76496BE2FD9B +:1078E000FEAE3B0FFF9CFC40878DFDC0B28BE44F8A +:1078F000E332F57865024CFCAA94E295B21F9569D3 +:1079000083DB25235E39BD0A083CF097550E6ECF08 +:10791000AC52B9FD42B7D7CB3B0E1C665C2BDD13D6 +:10792000C8CF3ED5F5AEF3162DE637BEB9E5934385 +:107930003FC77E05ADB398EC65C44A78BC4AF71BD7 +:10794000CBF438A4E273B3DF38F087DF539E8DEBBE +:10795000DFCE19D7A5C523B782F2693C1F0C3F6261 +:10796000E6477F57A99370323F33713FF67FCA973E +:10797000C19EAB9711D749EC87A14F5F64087C2F5C +:10798000DE366F4D3EBEBF79DF07453DC22EBD06D8 +:107990009E185ED1D033DE960144D7223EFD9DFF76 +:1079A0007498F87498F03689FA97F1FDDC2AC42FA0 +:1079B000EAEDB2CE0FDF84B1AC5FB9965C6A23B951 +:1079C000945F9A7168C69F196FBDD69E22B20F66EA +:1079D0009CF54A89E76446BB34539C5F2CD67CB344 +:1079E00028DF45B7B646E5F508FB775A693DFC4305 +:1079F000D2DB6D12E787F5CFB43D4DF6A8F6B73F61 +:107A000071933DFA5069F5D0FBEAB63FE0F6915D1F +:107A100052826E7AFEC390B04BE6F775EA7C34CEA4 +:107A2000052EF8A587A26BEE437E9C477D26FD6D53 +:107A300068FFEB9AFB28CFF039A294779E567A66BE +:107A4000111D772C7435367929BF4D5C77EDE33FF6 +:107A5000F168BC7F1C2CD0F9C7F96AC336AB3782FA +:107A6000F336BC227BE9350188F2FACCCF07C2EFAE +:107A7000DAC87EAB1688164E1D781FC56823BD096F +:107A8000B4AFFB5876532BE415203EC79D33D4E8A2 +:107A900076D88CE35D99FABE888E5FE40FEFA70677 +:107AA000912EDA3F8290B0C7CDBFD938F66DA4EFE2 +:107AB000CCB617DD5259FCB9C26A96477FF8F65F1B +:107AC000392C83E3B757C77B2C6E09F1735A87248F +:107AD0000E833A455B678DB8296FABDB62F506F123 +:107AE000725D9B0C0EF25F27ED1C37D4B57DC2F89A +:107AF000AC937C51691C2FC32DC5C511CBDBDE9B1C +:107B000045F676799E0C7351A56AF79C13E37D10B8 +:107B10004DC1F1CB77BF3DEB87D447BC3B92C8AB9F +:107B20002A7CC026F4C624AFF0DBB3281E6EFECD3F +:107B3000672C8F0FF74B90533CF0F99A2DEFD9C873 +:107B40009F9C41C164A60B7E91DF0884E585B6B495 +:107B500064F28B5CFFBB4ABECFFB7F1793E37A3A9C +:107B60006B1BCF787FF2774847CD9B76EF5C7AEF3F +:107B70009377BA0171F081D22870FF8B073CE487BC +:107B80006BAC418FCAADB85EF3CBBB198FCB8EDF28 +:107B9000ED11F98D2F4FEC1705F3689D4B367F9B48 +:107BA000D7B914FC8CC79A5FC8D5B44F734E81D92E +:107BB000BB93E84D659688B7ECF083B1F789F30085 +:107BC000A0FCFC037DDF34F8B2CC719B1D6E4C9B96 +:107BD00017B7FF64CF12F62A08A13FD2B96A00DDB9 +:107BE0002B9F831C3F378BE6B9AB5869A473225C8B +:107BF0007F50E797F415EF0B80A6C4C55955C7AF62 +:107C0000CEA17D313BF4DBFE5725C7D51AC53D71AA +:107C1000CF31DF3ED86A1F225D89AD27F9BEE9ED7D +:107C20005986FEC3CB1087A7C08E0F184F80FE3B2E +:107C30002D57F41F237D5CE46A4C43BE7DFACABB1A +:107C4000363AD70AE27A8611BDDDEF711FBCD91A28 +:107C50008D37E60F74D863E781A4D7DBDE33E9758F +:107C6000E27DF4DFCCCF00A46994B77D608BCE2297 +:107C70007F1EC4F7527DC1D20DF684F3C6185E4C48 +:107C8000E78BBA7E1AFB9CCB4CF198D19AEDC2954A +:107C9000598976013667273D5F34E72175D6D0AF25 +:107CA000893F7527ED9CBFD4B509FDC3803A3A0CD6 +:107CB000F5E1A35D875EBB05D7F151D89A3597DF13 +:107CC00096686F6B9E42FDC5F132F23B85EDED6724 +:107CD0001C4F19FEE823175E1C93446FF17A52BDC6 +:107CE0007501DBB3FF577676D92076F6BB5903E2F0 +:107CF00084347C0DFCE589E597537C61E6AF615FD8 +:107D0000CD76F3934C2DA9DD04DDCF1B7CACDD7962 +:107D100096717B3E4F9C37356CFB2BFB31646BD4EB +:107D20008EB86D087DCCFD07C88F71FFC07C696C73 +:107D3000B27527F2D37CFF32922DE723D1EF139F48 +:107D4000658BDB2BF6E7543ECF6F26BF49765A533F +:107D500081E40833204C7187D4F9FC5FE97DE6BCEF +:107D60002238034636F2B92EAC8BAFCF092B7A3DC1 +:107D70004530797D4EB32D769E4BF7073BCF7D5F27 +:107D8000B7575E97CAE508D62C4D4E5657E2ADB2AE +:107D900024CD237E9225CE774AB3C5BA8F65097963 +:107DA000B4C8D5FA46A3C897680F95ED5FBA9BCFC4 +:107DB00083AD7A7D06CE9CCBE7074ECB27C812D881 +:107DC000BDA17A8E42FBC315963B4BB1DFB5E1F600 +:107DD000390AE2C73BD5B2A704FB2F6C582CFA57DF +:107DE0005A2AAC08FDC7834BE6CCA47D03CBDB3F0E +:107DF000A5F529AB15A0FA91D296F7B87F97559CB7 +:107E00005F353CBBB786DEDF20A12090FF2DEE70F2 +:107E100023D731E482BA9A368FB53D7EBABF260F9A +:107E2000F379944724CDFFDB2CF22B8E885B2BA1BA +:107E3000BCD2B7F17B785F79D94A3921AE53EC8354 +:107E40008FDE333597ECEEFF85F7FF5B56F6E0EFFC +:107E50003FF3D4B50B68FC68195419E72B57B42AC3 +:107E6000EADB31BFA6BCCD9043B922F85EE6B27121 +:107E70003ED792EECB253C1D239C665F7ADBACD7C8 +:107E80000FC94E810339CDD2B81BDB5774F9BFAA95 +:107E9000F383FE685FA06F5FCE56AE5B816811C949 +:107EA0005796B7B6113FA24D0A6CA5FDD77D8FB787 +:107EB000113E5FB73978FFE8E6B4F5D62B90E4724F +:107EC00047D19D04FE37A55D7753BB2FDBDF93259C +:107ED000E68DD0BCB77C5F16F3BA1A53C97F820F08 +:107EE000F54AECD370FC0E7ED42BA2F920EAD538EB +:107EF000320589754E663AE4B45D4CC7CD7641C70C +:107F0000825049730FD231CE1EBA8CF22B7C7F94F3 +:107F1000E4700B865B84E760217491DC5EBFEDCA80 +:107F20002D627D85ACAFACFF7CFE7EE6499A2F804A +:107F3000F3D3396A40EAE1FE1EC5A1065561DF1799 +:107F4000C6EDBB3D0BAD27CAC4FE7E33E51D53F520 +:107F5000BCD8D87F33EA0D2676F9AB5C64B0E54E29 +:107F600099ECCA398CD7C88E99F7DD269BECEFD4F3 +:107F70008E8FD82E5FEC3CD099ADDBE37CC8A77523 +:107F800084E93C90025EDD4F7AE93C3089FEC79D72 +:107F90000766660B397DED79E09DBABDD1A84E0E1E +:107FA000D7D18F1393DCFA8F2E82F24AAE476884C2 +:107FB000F4C1FD6ABBC9FE1B381FF38A7A3BD9B3F3 +:107FC00031AFC06DB4DEABF5F393FED3C0F580E303 +:107FD0007A1C5C1F68EDB28642525C3DCA490BD7E1 +:107FE000A3F48337C4F52B41BB1A647B3996EB4F5E +:107FF0005A4EEAE7BD7A3D438560D93F5C0F61AEDA +:108000007F98E29E242FACE4F31990260DAC7F9864 +:1080100022DF2A935D81A3429E17EA20E43299D69B +:10802000752E024029DA8457E2E48DFF9B9815945F +:10803000B9FCE954E2F529265C98E57F6DB61EDFB0 +:10804000E8F21FB48EE443B1AF360EC6721D89D577 +:108050005C47F286850B366375241521D2B7094D2E +:1080600062DFF862753CE63A1D731D4E9E3F914FEC +:1080700005355724DCBFACB13CA17FF9CA2909E31F +:108080008BD1A1C6F74B1F9A93307E58EB8D09FD1B +:10809000119B6E49183F2AB428E1FEE81DB549EB53 +:1080A0005E0C9C8C09AF48B8BFD1F9E4BB84AF9695 +:1080B0003C59A578FECA8EFB4C7531D31817538CEA +:1080C0007D785DFE465D1D9581119FC7A3FC1F2B2A +:1080D000A6B8E9FE2A491B88036F24C87EFC1FC589 +:1080E000C17A931D30F4FF62FB373FD6FD849C526A +:1080F00024519CE3C3B82A652AD5118B737B784B36 +:10810000D4AB7C96F2778E8B34C9ED856FD25B55FC +:1081100089E2A07BAB348E83EE1D527480F60F7A19 +:108120007EE0F64AF903EB42CD75A0190EDF64E05C +:10813000AD115107D982869EEC7F708683E38C87D0 +:108140002D96DBAAE3E87F225BD89F27B245BEF5D8 +:10815000735B7837D901C5016A539E789E8A1F8068 +:108160002A7B502EEE4C10F561F0C6DA9985E43F7B +:108170007B466AE9543F8BFD6FE06525C4FEE496BB +:108180006685F3BCD5CE27D99F942BC29F8C93854F +:10819000DF403FD241F6F14DE97EAB88B382569283 +:1081A0004F810382EE72F6AF7C4E9C0E59D28A321A +:1081B000AA4FBDE0B7B4AF104C876AA75A884FFDED +:1081C0008B653E0F7E8948427AFB6B46719D73FF3B +:1081D00085FA3F2D8DF2EBFEC58F9EBDBB32A69773 +:1081E000276DC9F3BC8BEDBBD56C793495CE514E60 +:1081F0008E8484FA8C37B3457EF866B62CEA0C423E +:10820000EF79884D7D4BBE184E4407A4EE352E1CE9 +:10821000F2E0A61F54935C6CEDF382B4AF69ECE31B +:108220005FC8033BA773FDB6912FDDFCBAD8D7BB5F +:10823000F98BC47DEB8FB2C5B9C047F43E6CCBBBA4 +:10824000FCE3496E379042F0BEB27F3CC507D52AA9 +:1082500068E4F717F817DE7D14FBF3D64B1CEFD359 +:108260007D1A7F23CA90EE9F00EFAB7B91BECFB308 +:10827000053DF3A1DA4A74BEF6FDFA54C2D3EBE928 +:10828000627C54026D6BDC7C37E8F3BDFEFDE57B60 +:10829000294FA7F7D1FB891E7AFF3C154AA8FF1A80 +:1082A000F8CFBE5A3CF0BD3781CFAAD77B59C94F12 +:1082B0009642A8ED69B2AB472CDEB5C06D2493FDA4 +:1082C000929DFD525F53F4C97B90CE3FD5FE75AFB2 +:1082D000847CFDE3C2E8AF9FC6EBDFDD248386B874 +:1082E000F838C32F7BE2EAB44F2EFE2495F889F1CB +:1082F000CAF69F92DEEDB47BA9AEE3CDDA9DC3E36F +:10830000E3FA54CF74073D07932EED3CADEA89C9DB +:108310008CBF15DB05FE56FC66440EE16C45EA0594 +:10832000DC89FEF6523E279D2041D2FC783FE24D8B +:108330001BC17535A021CEF67F2EEACAF71CCDA849 +:1083400020FA14F05F16BF9E3D2FDD329AEB79DFE5 +:10835000C8BA243A496783687F6F665389F181AE52 +:10836000270B3A332BF478729487E2B9DFFFE6ECFF +:108370007F105FF6EDDCFE43D6914BE3C3C03A5A63 +:108380007527DB27230FA3BA57CAD30E59D84F5EE0 +:108390002DDFCF7918D56970DE35A488C7A3C15108 +:1083A000ADC2BE89EF24300E6EF672BD27EBEB4AEC +:1083B00055C42D469E245BBCB98AF8C8E0C5A93CCB +:1083C0007F09D0FE989B122BC35E611CE1962DBAEB +:1083D000BD029F03F3D3D1BA3D9BE5F15EDB22CE14 +:1083E0006B12E24FEC57ED4A127756E33F8E3B3764 +:1083F000FB9B53D82F6D96CB28EEF03922E4C7CDE6 +:1084000071E75458CFFB0003E2CFE7FE7249F1E772 +:10841000F73CFF3DBFB3D4A3B1FD098F14762E1CEA +:1084200019C2790EFE55907E0DA5BD003A07CD13F9 +:10843000AD4DEA1DE940FDACF594AF7B681AC2650D +:10844000A8E00FF551A450AA7D72E82B8A03BB1552 +:10845000965FFF73577CED772495A887E4EC23871C +:10846000A770BD735F97D08FB60CEDDFA7529E81CA +:1084700071E656243145E9B1A52759CFD3647F5120 +:108480001FC21E9147393AC4B9A843F301D99714C2 +:10849000551D4789B9317EB147D8DDFAC36F16D96A +:1084A000503E672D47DD74BE52B7F729372E179A15 +:1084B00033FD0F90FE2C3FF9F20495EBDCB614511E +:1084C000FE1D8EBC3C83E3B3D9C8DA7183AF27B0FD +:1084D000A9823E4280864D99DC8EA27D15BC14880F +:1084E0008875F676346724DB1F08FCDB5B0769BD03 +:1084F0003B8FA570DCB233BB9BF520380F603BF29D +:10850000FB89CF47F37C0830A6E38A6A4D227FFFC0 +:108510000B7D3D3BF5FCB2F77399C719F38EE998D3 +:108520002EAB88ABB248EB41AEE3EAB46B24DF94E8 +:108530006D20F8D399C2756181FDD788BC335D9CED +:1085400047B70D89FE91DE13DD67D7A84E35456D1F +:10855000850C9CBFCD26FCEC2804FE53AED875E3F9 +:108560007D299D1BF92308C405D7E3A528ADF00D8F +:10857000573CFF5399DEFD1E11EFB40D89585CE4A2 +:10858000273057DACA74C5E8047EAF41E7288E8BDE +:10859000DB6CD1F769BF1DE9520917A340D0099DD3 +:1085A00023348A57525471AE9EA26ADEA03490AE34 +:1085B000C058086170000FAF860B7ACE7584436295 +:1085C0007D07EA425B891EC70417AF9B392DAE4F6A +:1085D000866C52ECF9139E65EB5A0A695DC20F2A4C +:1085E0004A98CFC7DD0B40A5F3EF14C5C77952CA2F +:1085F0007CD09A505E4E878FEF7B708EA6C9DC8F41 +:1086000010FD2ADDA77D9B34D53907E94EFB328D5D +:108610009F6BE8B672DD79DDDF6F4A2BC3F59DB144 +:108620001CBC6717B61F2D0C0FA773DA0969FEB7BC +:10863000C81E3F736AD1BA3138FE2F6D56EF5CB257 +:108640004B3DC11FD3B97DED13568DFCE2836FF412 +:1086500047BE22F93E2BB15DECB38AFBD8D79AF026 +:108660007E43E707363AD7BAA6E36D1BED7FAFCC62 +:10867000F1BF4F7A30A9A3A98AF836195A9B699F8E +:1086800013ED21D74B847385BDE87F65F8D6A638F6 +:108690003EBB72F47DEFA8FF72D29B4E5D3FF75355 +:1086A0007C84ED5E3D4EDB7BE0BBA55ADCF96910B6 +:1086B0000EF27EE06A788EEB3A8DEB7D216536E135 +:1086C00068F46B8EDB7C7138B3E5087DB7E9EFFBAE +:1086D000798EFF4BD6DB03EFD8DCB8FEC09FC345D5 +:1086E000E4AFC218CF7D5D1D69C0A42F17EA8E4E7E +:1086F00003DB919DAF7570FCBDF33E359DF41EE923 +:108700008734ECEFC5F882F4686FB1D0BBA657CFC1 +:108710008FA5FDE2F3FB965F4EFCEAF5580D7CCF8A +:1087200018427AB41BD88E197A58467A28D1F77B2A +:1087300062BFA78CF04D7A67EB9EC37AB7D702A4CD +:1087400077886FC63BE25BA538A44C45BCF3F323A6 +:10875000588FDBBA5FBE82EBD991BDC3C651DFC271 +:10876000F86A8BCC0949F87CA53572909EAFC4F7A6 +:10877000376931BDAC9412EB7A167B449DAC611F16 +:108780007FA0EB6778A496E6C5F14E594EC07F9C5A +:108790009F147DDD8FDEBBF127EB36A0BE94FA2A55 +:1087A0002C1328DE3926B31FD8AFC7C92BFE30E5FE +:1087B000865DE23AFBCF888E8B837ADCFCDCAA5C98 +:1087C000EE935FD0502EE3B1F55550BD7763156D34 +:1087D000C54D9ADD7A88DA29D5E12A3A2E9CB6A0D1 +:1087E000FB90F8C6CD379AF0D67EF05BA3B94EFA6F +:1087F000A41DE83BCEF6FF8CFEF1095CFF3DFB912A +:10880000DF90342E61BCA1C766FC0D86933EA9E7BC +:10881000FAA96897AFDBF8EB6B1574E80D04045CFC +:10882000FF9C8DDBD605D1079EC8F15D9783F8FBD1 +:1088300022D77F5D0EF2ADEFF87F7AC89FEC7DE521 +:108840001D37F9E1769B6F34E1AABD04F3882478E3 +:108850009C926365FF5A3948BD49638EC8B7860745 +:10886000611DE1A5A15D5643E4A77DDDD793DF78C7 +:108870001F5949FBDA4BA707DD942FD5EC3DC47592 +:10888000FA463EBD04F43FF9D659C4FF73B9223FFE +:108890005EBAC19A90DF8E80888DCE91037E576339 +:1088A000044552638A3BEEE8D8C2DF8DD46E4B7C20 +:1088B000AE8EE2148450DD45F2E3C61C7D9FA41405 +:1088C0004A294E41DCF03E49F455D9BB15B8BEAA41 +:1088D0008BEAAB765A049F9C0E6849CB88C52B2344 +:1088E000F27C4BC8DE2D31FC875EAF146D93F87BB4 +:1088F0008A513B44BE3CE5B4B685BF930AFAB84EF4 +:10890000AF860840BAA728415EFF94DC5208E2FA1D +:1089100027A179267D59DA2985989FFA772F0AFEB3 +:1089200013FB459B65FECE6FB30499C5346F94F974 +:1089300053ABEF1F2EDF91787E51B7E9F8610A95AE +:10894000EAC3A6F3209D3FE6F39DA7E83F929CEF84 +:10895000FC24478FE78AA028E1BBBCAE4BFB2EEF7F +:10896000238A075C74F8080971F91E1D470DFABACD +:10897000EB42B258378A82EAA36FD76112002FF315 +:10898000A91E71423880F542DE463D632D54DBA8B6 +:108990008EACBEBDE9309DBF2DD5E35A339E90A16C +:1089A000CCAF657ADD50CDE6C4FBB53A5F6A4D7C4D +:1089B00069F04B26FA44DC7DA9F4A1E5FA0EE1A0AA +:1089C000769795EBB9CFC1AD5C7F55DFBE85E95990 +:1089D000AACB6F20BD415ECF325C0FE9D3A5D26B2D +:1089E00096DF3103E757C01509F29B9D7949F22BB9 +:1089F000057539ADAFBF4BE4B5FD5D25BC2F61E01A +:108A0000C5FCFC2C3D8EBE66938837CF7654392941 +:108A10001EE83BAA7825C47DC5B14FDDF4FD4DF9B4 +:108A20003E19E89CB4AFB3625D10EDE59EAEA13790 +:108A300069E807CA8F29EC372A8E9587528AA95F81 +:108A4000EE2CE53A132D93F2009C87FD70DFD1A147 +:108A500027CA384E9F5949296AD3D17227C50B7B43 +:108A600040EC6F48C72A337BE2FCCA7B3962BF61A6 +:108A70004DEEBB0F939DBA66B795F783AFB1465FD6 +:108A8000A23C6C4F97E26DC27EDDB145AB5348DE30 +:108A9000BF91BC14761FEE5E9145E735F59D56D526 +:108AA000CEF4DE7D90EE077749DE61383EB0EFEA26 +:108AB000D16DB44FB4A5C24BEC35DE579EAE3D4AE6 +:108AC000F5AE90E7E4BCFD9ACBACEC5FCFE43BFFA6 +:108AD000752EAEABD6B76516D9E133BFDBC37515BE +:108AE0007D6D12E44AB48F7CE849AAF739F3F4713A +:108AF0001B9D0757B51FE7BA8DC1FCC1D910E28E87 +:108B0000F3F6561BE537F55B8C7E0F7F8F52ADC7B2 +:108B1000510DDBDEE67E2DE50184C7CD7248C3FF33 +:108B20003CB4EF193E1F6ED825EA3E2EDCDF26F15D +:108B30007D03EF8B74BBB51C34C6FB7203EF7A7DEB +:108B40009481F7733097EBB496EF7A84F1BD44C704 +:108B5000B7B96E0A2DB0AD2C4BE82BEDB799BFFF1E +:108B6000BB43C7F71D17C1F7A85C1DDFA36014E165 +:108B7000FBFC74514F77FEF81027CD7FFE08EFBE47 +:108B80007E1DCED9EF1ED5E382FE88C567BB323687 +:108B9000AEB7E313FE0E3170B4DF467527B33A3F2C +:108BA0006679CCED3C3093F87D1DF8EB887FD77566 +:108BB0003A558A83E7F6087B36A7D3CEE713D74129 +:108BC000B885E4DCB7FFF1960CC2CDAF056E0C3B67 +:108BD000B74CE7EBB5653F9845F97BADEE0FFBBBB6 +:108BE000EE9CC576671C1453BC3747FFCE7B4E58AE +:108BF000B7439B13F94EE7D424B7864E3BD79B5C13 +:108C00000B3D36F267D7EAFED3EC27FBF29C2CE74C +:108C100020FAAB6138BE6E97A98E52E9617AFA3BB1 +:108C20006C7CDED560F2BFD372AD09F51783E1D35A +:108C30002CAFDB72757FA2CB6B6E54D431CC7945EF +:108C4000F6D2F94357647519C50B06DFCCF2EAD2A8 +:108C50004AD3BEEEF7125ED2E37CA37F83FEFD5BB8 +:108C6000586D75C5E7EDCFE75AF473CED04F2B7032 +:108C70009D7749D04D38C4FCE6867229697EB332AF +:108C800017C73F5F78FBFA71F1F98D6FCB708AF7E8 +:108C90001E44BB5251C9F53BDD7C5EA8B4CEA57322 +:108CA000B0C02EAB97F29A4087CCF14060973D64FC +:108CB000C179AF211C215DD59DD2D58423CC1B5A0F +:108CC00072D13ECDA32D651C37AF03E3117C6EDE60 +:108CD000CC8F197F47868A75F72B5A4EB23CC2C893 +:108CE0001F1A3E17F1AA71BD01ED008D6FD0BF4B69 +:108CF0006B3FF8D7A2E2543AB7FDAC6821C5A9B9D9 +:108D0000227F31E2D528C6AB257ABC4275174B8548 +:108D1000E860E973F7D9C87E1DA61FB6A0FA49D549 +:108D2000BF86F261D50F8D3FA240436A613D6A2044 +:108D30009D221CEE95C4FECDB356AA0D81A6978741 +:108D4000705D60EF6BE21CCAACEFBD8BBAD95E9C64 +:108D50005FE86A24BC2D2FDBB206230C18BDFF751B +:108D6000B637A37F67532D6A6C5D4DF4DD1DE7694F +:108D70002D09F1726F47B38DF7A1E3BF1B2E1918B0 +:108D80001FD55F641FEB79935D41FA39DEED3B221D +:108D9000ABB42F847CFC657E3CBFF478A8FD600AF0 +:108DA000FBAFBEE3AE10C5FD7FD1F17846DF976F14 +:108DB0009A24333F2C93453B7AFF3325245F9287D7 +:108DC0001FEDFDCEFDCF5CE1E37DF490A823DE91A5 +:108DD00058875D1F4EACB336F81AD0F98A740DA7C8 +:108DE000EF950DBAF62A3D6E6F123D92A4832C2F9B +:108DF0008B9498E7069E95ABE3EB48713DB791DD08 +:108E00003B69E88B12F5901F7E2B5763DC34750AA3 +:108E1000F95AF68916DFFF1DB15F63E5F70FB83F1A +:108E2000235847F7CF173BB9BE013E0FCEA5FE3DF5 +:108E300025E2F703EE79B97644FC3E1D48221F0F68 +:108E400058A35CEF17386E61FA02C7FB3D435D64BF +:108E500017B7CCA43ADA6B757B71B8C45943380F95 +:108E6000D27B7362F32CC915E71B40EBCD8D7D5F80 +:108E700069AC7735DCC87C58ADE3EA3FF4BC1EF33F +:108E8000A8F3B949F2A8C1E2DF0B74EBF1D3F9E919 +:108E9000DA89EF210ECA8F2841CAD7F7BC91122276 +:108EA000FFDFB46FD99F281F0EBC69078A43EED934 +:108EB000BF6C04D7E1FBFD57923D39BFFF8E2BB944 +:108EC0008E5112DF970689BE5C8AA75EF5509C54CE +:108ED000BFEF55AE73ACDF3BFE518A9F305EBA9652 +:108EE000AE631CC3F82B3F56C9F8DB73B432B3949E +:108EF0000807AF93E6AD3FA270DD63FD91CA17E7A7 +:108F0000525C736C06C74F46BC5441F938C54F4795 +:108F10008626C44FA979827F7D075278FF4382124B +:108F2000811F189A809FBAF63F709C5187F62E1EBB +:108F300047C673C5790ACF332C4FC74F58F2313E1D +:108F4000768BB6AE630FAF6FB935CCF26EDA6515BE +:108F5000F7DB446BD44907212348FC78912EA11CF0 +:108F6000E6D84285946FBE502CF20DB33C9EC813D8 +:108F7000E7852F9C14DF19BF30DD3F22D9F7C641AA +:108F80009821F27049E777BB7576B2EF7977E4897B +:108F9000FD097726249C4B1AEDA379425FE6D8C4DD +:108FA0003E95F9BE3FCFF03FB08ECE634ECCB5AA12 +:108FB000C6EFB7E4A1DDBD1E8C3FEFABF3B3E89C79 +:108FC0004BE4D5003D33C91E7E9BF6F929FE9A2459 +:108FD000FCBAB1CF3F6F333C20F6F96FB5925D30EC +:108FE000EA4BE6F9CCF157F5D534CF8DE8DF699E31 +:108FF0009B6627DEFFF645E2AE0579BA1F1F0EC35A +:10900000455EE172923F38D76555655E476868B244 +:10901000EF0B0DFB737895383FEA42BB486DD3A840 +:10902000D779DFEA8503279F4C67BB9A0225C8E200 +:10903000ABBEFC9327D93C4D17F4757E02FE0C792C +:109040009DA53CA06CA0BCEECCB3E8DF259DB1F1A2 +:10905000F926343E649107FF2EA969D4672DA44FE9 +:1090600067F5EF5E90BE227B9CDD3F9BF731DFBF53 +:109070006706448378FFC0283BFBBFFA99129F1F05 +:10908000D447843FAC9F2FFCE1F0F6792C97EFA0FA +:109090005C7C5E3613AF515DAE21EFABBEEC9B69DD +:1090A000E493748ED34438673B9DC56D7DFBDB2D07 +:1090B0007C5E897E97E2C21B2625CA6D04F81FC814 +:1090C000C6FB37CF96BCE84106C8FDE65BE7B1DCDE +:1090D0006FD2BF8FB998DC7F9BE7FF691EE97D7770 +:1090E000FF77C6208B5E18F54111F9D7864170BD18 +:1090F00055E72F0C8D3E4DE765DE0BE7E97F7F3AA4 +:10910000FE3CBDC4E3DF924776D5F2A5FB0AA0F989 +:109110007A7EB942223901EBC5607AB5439F7F4719 +:109120009E2ADE9325CE8746E9FD17ACA142FE9E1E +:10913000A2ECD2CE019B9E7D7E2CD9B9DE0347C620 +:10914000DAE2E47A6605DA07F237FB0EF1F78731E7 +:10915000DC5974DC29DC4AD28DBA1F4DC4E119C236 +:1091600021D9E7DD87AEA7FCF16CFB4D599216E7DC +:1091700067F79E700F8B9BF7ACFEBB1898B70DFF7F +:10918000766A3C9D0F309D67C3623ED4FFE1378D08 +:1091900089BFDF6C7C67C7787E7064239FD31B78A0 +:1091A0005640E0D9F83D8C0BDF55DA80BF7B0CEEE2 +:1091B000B7737D459F355A941EA72F1F1A72449886 +:1091C0001566312BB9DE75226CA8E273024CDED72E +:1091D0004DA6CFEFC2B2A80F6DE4BAC5698DE025E8 +:1091E000DC4AB099FB13668BF3F229D02D135DDFB7 +:1091F0008428B73E50156A67508519B6931C61994B +:10920000C2ADB6F6834EC257C4A3A4BFEF10A5A744 +:10921000C9E4175BBF02EF1B78C5C1180425FD4EDA +:109220003F2B5FD87FAF53E863F4ACF8DD936F401A +:109230000FD33F55E9667A53352D83CE4B763FB732 +:1092400042A6FA97FDA04549CFBC998DBCFF169D5B +:109250000EE1ADE9B1F54EA2F5AAB1FE940560A10B +:10926000F54AB04BACBF1132E87C6C3244F83D5744 +:1092700011C1B8DEE9A029D4B7E517EB7C16F95B7C +:10928000959EBF591C41AEFB49CD17B8762A2139AE +:10929000AF92B7B6C38FD0F94CA958E744BCCEE71C +:1092A000388D82EE0BFE3A5FD8BB29106639430D2C +:1092B000A82FF28F2BCC54895F52C463A1DF13BB5C +:1092C00054BEF67980E977DF1EEDFD6165ECDCCBFD +:1092D000DB99C3F5D0EB254B5426BA1C85A21E3A68 +:1092E0000261FE2E3392F87B67C5F9375E9E4F7E92 +:1092F000CF2FBEC335D775EE086DE5BA9B05416427 +:109300000FCD530870DA13AB03B09684F8BE95CE38 +:10931000D955AE33ADA07C715FB6FFF2FC6CAE37B1 +:109320001DC69329A1F1D5A931BC2365FCFB3B4E99 +:10933000486D257BD4ACD7D30655B75ECF54C4EB6C +:10934000D0D0CEF38F4828A2AEFBDE2A517F7AEF31 +:1093500090FD5CE7DB23812A15D0F9FF7EAE03A6E2 +:109360001F86B3167CCDF97F96FEBB0F25FE3726F0 +:1093700096EA461E9F6B3E95CAF5AFCA0C9F46758E +:10938000BCE67AF1D296F10FF5705E6AD06BAA1343 +:1093900057BC7CFF5EDDBE363BC4EF0049ABEDAA97 +:1093A000348DBE7F5FC1BF63D54CA141257DF7BE23 +:1093B000829FA73A662A02ED4DF3DF44FC32FF2E6E +:1093C00015C2ABFF059A376D38EFF72593C73443C5 +:1093D0001E9681755228875B49BE46DDAD516F4BA5 +:1093E00080A0753B7DE277F054C409FFEE1F42C9AF +:1093F0004EB8F4997FCF43D4FFB6E8FC47BA7670F5 +:10940000DDA7437CA76D7CCF6BE69B81DFFF02B9B4 +:10941000D77EA250530000000000000000000000B2 +:109420001F8B080000000000000B9B25C3C0F0A3A9 +:109430001E8145A551F9E8F81C9A3C0B0303C34F64 +:10944000205ECC835F1F2E1CCB82607B893330185B +:109450008B32309800F12C209E0DC43F81D8508C67 +:1094600081C108888B81EC1220F6056247A0DA2FB3 +:109470001C0C0C13851918E600F1726154735F30EF +:109480004268252E060653206664C66E3FA73AD072 +:109490005E5D04FF23906D6F409E5F46F1D0C35523 +:1094A0004EA8FC7C6B54FE2C5B0606666704BFC0AE +:1094B0009A34F3ED817A1D9C71CB77BAA3F21B3DF0 +:1094C00051F97FDC50F935E1101A008D579524B819 +:1094D00003000000000000001F8B080000000000D7 +:1094E000000BED7D7D9C14D595E8A9AEEAEAEACFA4 +:1094F000A9197AA04706A8611A19E3A0050C30281B +:1095000048CDA0384693349890D1D5BC168821090F +:10951000CFD7F1ED2A1AC9F47CCFC0800DB2067DF9 +:10952000515B0C89262621899B3559B3698DC92346 +:10953000D96C168D9B47B2B86F243C379F9B79EE50 +:1095400043FABD90B0F79C7B6BA6ABA6BF00DDE4F1 +:109550008F37FCCCCDA9BA1FE79C7BEEB9E79C7B8B +:10956000EAB6EAF1437C1EC059FC5B03F0A6170083 +:10957000964D95E94E33076DACFC1C98FDECD1A5DA +:109580007AAE5362E5A2D0B84732002E8F66003C17 +:1095900000F1C38F8287D51B695461671380DFD8C0 +:1095A0005003A1A97EDD657F0F406E61E9F7F20BE4 +:1095B000A33123CCFA7B6A79B7C5FA19F9727BB764 +:1095C000D53AF5BE010765F8CD07864D3DC0E09C54 +:1095D00007C113051866632F64FF69F72521C1DAF7 +:1095E000A9B951301661BD5AAAAF3D73D4731B7B24 +:1095F0003EEC85EEC3ACD49E4DE7820CEFCB9ED300 +:1096000097C88C1EBF62797EC5607FCC934D231DA9 +:10961000B17DD4EF2946170EF576D1B314E9617404 +:10962000ACAA929E55A5E8792E9D467A2E7FD658F3 +:109630005C488FD6C8E9D11AFB689E4EC5183D4DCF +:109640001742CF3D44CFB0A067D845CFBB043D1BE8 +:109650006D7A1A86889EA1398C1EF6C8775F1A1219 +:10966000ACBE86F484B19E939E21A4A7B5083DDAD2 +:109670001F879E0F09794B213DCB2AD393427AEA6B +:10968000ABA02794019D3DF783641D6E9D8E975F6F +:10969000F071D13399589AF53BFA7B99E699ADC8A8 +:1096A000D8864553F5C6055EDF691A8A8DA37C2DE1 +:1096B000783006ACBFD13912D577F7FB10A8547FAC +:1096C00066A3D58BFDBFE34967FFA37338BE76FD64 +:1096D000DF8879FC0DC8D46E5628318AF0E882AF55 +:1096E0004112C7F166623AB66BE2ED06172CEF1E27 +:1096F0000F156BCFE919DD912679D672F710BFFEF1 +:10970000624E060C06FB9F4C02F25F8D717CECF6FC +:109710000C2F802B90ECBB2C8BE30770119BA7F4D4 +:109720005DB9341B2F9EB9434B307E8C36F46948AB +:10973000F788B1AF1BF5D6A9B80A7213E2559C0F92 +:10974000B65CAC81316D3E9BCFFE576473274CAF46 +:109750009746E1AA9F82959007722D407F6701E9A5 +:1097600049D2FC0F2E7890E85691AE4548570A0C26 +:10977000F6FC1B427E7CCFA401E54A33D2B1F4A2B1 +:10978000E9E38C20FF5BB1D74C6C4301FD3FB5E7AB +:1097900097CDAB6B7E892F0F81954B235FFCCE79E4 +:1097A000B3CBEF09BE5FDE9826FE561A7F3AFD7CEA +:1097B000FCBF0683FA012D134B84A7F019F58EF731 +:1097C000A15CB335691E62552E63E37414F0DB3D72 +:1097D000DE249D4AC621C75F137C1AF54FBC50D8C2 +:1097E0009F1B9F6F897ADF029D4A9BAECB9EE5E36C +:1097F00054EAFF47C8E27AACEF5A574ADAC1F77B1E +:1098000045FDCB9F73D62BC59F8F4FF2271D437904 +:10981000B4D723FE59330184C8D05F6839C025F816 +:109820007F5893DFDE367E172EADE3D1E4296CBF7F +:109830000D92F302CD6CBD78939FC5729D62BD49B8 +:10984000FD42487FFD52217732E9013E1EEB1E5852 +:10985000FF61D19F2275013079F6B543762743ED3C +:109860001AF9784E62FCDC0760CED20BF6F5137C59 +:109870005F5FA967D7E27E7EA5C20861E3D580EE6F +:10988000C712EBE758BDC8B290C946021FFC594D3C +:10989000A288DCF8DB20EDAF61E3B7AB8E75E1B7F2 +:1098A00092807A211C839C3F02A04BE128E1BF02F9 +:1098B0005670FC0D09FBAB538C5E858D23C73DE6CE +:1098C00041F6B46615ACDC54208786C4E5B737EEA4 +:1098D000F1205D434CFFFBD8928CCC61EB1DD7434C +:1098E0008CD91B45E47652BFE765C8CD60FDE625FF +:1098F000C82D657008562659BB8C0F569EA471C1A1 +:109900003C5844CE364A7C5EA5F8C4D9B3641740AF +:10991000F65AB20B32B48ED578C6C27D40B322A6B9 +:109920000FA7FDCCFD5CAF2960A19CD4C633B91A4A +:109930007C6F5CDC84F8CE8AA7E0B5565E9E28C0BA +:10994000570BA563643F355D2CF515EC63CF33F9F8 +:109950003951206F233BB81D30D83424F4CC8749CB +:109960007FDAEF3F20F8A48E3364902E43CDCE975C +:10997000A6CBF588545C4F6C16F4E2DFD5CB9DF294 +:10998000AACC14F2CA86F02940F235FC1464115FA7 +:10999000C6C9176E63F0A52F6AB093C9572B1CF583 +:1099A000A0FC5C0613549AA0CB582E0193CA3648EB +:1099B00050F9DB0E26F7ACDC6631799F4FF2FF3EA3 +:1099C000898DFF9B39C98511F6DC1F4F5F81FB0B29 +:1099D00093FF8DF89CC98984F2546741D1FDB2563A +:1099E000E2EB75AFA2FBB1DE5E0B483FEE97FAD318 +:1099F000B84F8C083B69C40F8E75BC47D03D22CA56 +:109A0000DA7812C6717ED9BCA05E7FBEE9765AC7ED +:109A10003E85C3436C5E48EE56F37DCC8D8786F35E +:109A2000B2E8FCE761E31F7F1E86A4FAA2F3308C44 +:109A3000F3B051E2FA53FD391FBF0C7DB44F6FEE06 +:109A40007D9CF8AF9E3CB7FA36FDCB5D7A7385D02E +:109A50007357C2C45C85E9913B7C39559108EF4747 +:109A600010EF377F72F403480F8C2717E23EC5F0E2 +:109A70007E54223D9982A36C7CE515398B7E8A2722 +:109A80007883962CE3A780CEF49926F4D97CFCDF6A +:109A900046FDF5E074FD7BF1E10F1D237B03B4E48B +:109AA0004ED44FAB531ACA457FE3060DE568B89113 +:109AB000C128373155932E676508BA50FE6CFB6399 +:109AC00028B669A4298A768FB91CBBB5C75F1B4B22 +:109AD0008244CF93337C4DCEE73FC3F5AF2763324B +:109AE000A34FCD5EAB219D83FA06ADD0EF5243C9A3 +:109AF00098CAE47018C7C3F1BDA9234D6DA83F6192 +:109B0000691FEA733D054B51BE639D84E7DAC68445 +:109B100086EF7DB125E03390C509B2AB86A24E7FBA +:109B20006EB8F14EB89DEAA7E0F5D074FBDA174A9B +:109B3000815AB04FE03872C13CFB94540EE99263F5 +:109B4000C5F5EE3F09F9F71809DA6F20F3494B63C1 +:109B500072EF1532E08DC14FA4CB0AE6295AB0EF5F +:109B6000B0791AF29BDDC5D625DB419CFD9A1268BF +:109B7000CBABEF776ABF15F39E5931324EF31ECE51 +:109B8000E0BCF733BD4FFBEAF170F61023A1777507 +:109B9000EA317CEF4D2BD017A56E5A709FBB5B7ED0 +:109BA0008789F2B707F9C6368EB11E8DCA9D3D3A38 +:109BB00095233D312A3F19FCC467C759BBED699F06 +:109BC000EE4339C8DCFD25EC8F79DD899DD86F9493 +:109BD000F58FFD2A9A7E484798EF3BDE382F6FF1CC +:109BE000703ED67802846F9B87DBE10658242F19DC +:109BF000BDBC9F5ED3EEB473C366606A3DB0FF82A6 +:109C00002D750ED86F5CE4A8EF5E2F2F79B8DEF0CB +:109C10002A09305BB12CAEC7CF4A32D593E5C513C4 +:109C2000687F28B354B20B0625A7DE7ED4C3F7BBEA +:109C3000273C1AD11983896F9F65FCF0EA1EB27B1D +:109C400022B5F30FE7903FF5AAB9801511EFB85E82 +:109C500057643C882ABF1E2F58E74F4956DCF3272C +:109C6000C0A769F4F7763AE47A9787EF7767C57A01 +:109C7000917D5637EA9918134320F9301E473E78F4 +:109C800082ABCC16C687C15AD5407F68A0D7537423 +:109C9000DF71F341AEB92586FAD1CDF76F09397A74 +:109CA0005AF07DCD99F7909ED8AD7BBAB221E4DB16 +:109CB000D12ED4F3036D1E0FCAF99F0CFF5C746C98 +:109CC0009FE4DF241DC4B78128B79BC774263FB823 +:109CD0009EA35C7E0CC875D17B93D1254DA7CBCDBF +:109CE000BFB79B3E9BEF35B59E44B615F19B481020 +:109CF0007EAB94A2F8FD47F1DDC62B3489578EE385 +:109D000065FE69E0F594943C88EB7B8F90D73DCA63 +:109D1000B8867A216ECB4D90AFA3E97A4972C83BE1 +:109D2000EBE7F3D8CFFDD80FAB7FBF32E1E8C7AE8A +:109D300017463EF07591E0EB42F9A3AE0B1BAF9DC9 +:109D4000026F03B25CAE5B8ACBF5DB8D97BD9FF6ED +:109D500005AF02D437B5A104D9DFB342891CF2ABF9 +:109D6000BF5E35D0FE618E12EDD7D4D428F093EAD1 +:109D700037C6B0FE607823D9E583DE04D9E947EA27 +:109D8000BF66DDC6E8EA3F53033E93F903C1AB8EDD +:109D900018A8178FC8E4AFF59F699E952A32CF4166 +:109DA0008C8F31FC03881FD9D5EAA4118EF8F68771 +:109DB00098E263FDBCD10A59D4A7DE901543BBBB22 +:109DC0007F9166F651AD04207FFB821F684FB64E2F +:109DD0006F1F0C0D7D4CBE6C6A1CF6279D45DB97F2 +:109DE000EDE1E8C7137D92E37D513C2AC1DE29589D +:109DF000A7FE196C68D8B5649D6D9EE23BA3A5458E +:109E0000C17D130226CE7F3CD1D5F73BE4D3F76466 +:109E1000D2836EFEFCB59C0CC8CBA6606F3449F3B0 +:109E200066F7775DBD427A546984AC4FC251135DC9 +:109E300068DFF6377A28BEA68436D494B5BB1BAB50 +:109E4000B3BB41C43D6C79E8F8391F376072FD1D22 +:109E50008671C0B84A0DF0B8462D1812507B534A8F +:109E600050B06415C553A2FEB7BADF5BA85FC9DA6C +:109E70000B6783E7D0AFC2FA6D7E1BFAAD80AF1FD0 +:109E80003E45FD32F5103D3B63AA5F6F2C450FE167 +:109E9000CCD9B3F272E04DE82F49F2AD784C5A9F1D +:109EA0007051C43CC48AC1E89D0E7FEABDF27C4774 +:109EB000DC54D5873E264558D9B8CD1A2FD00FEEA1 +:109EC000F9EDC681D0BF6CDC628D57A137D0EC2E86 +:109ED00016971A5293D95EDCBFE786288E084A8A05 +:109EE000E2C2C352DD12B49FED7A4AA39A43BCC2C8 +:109EF0006D561AF5C5F00C8F299BD8EFD851F40791 +:109F000040BEC14C96892F298DCA2F0BE9F9CF721B +:109F1000384A788A38577F05791FEA297F3EA1AAF7 +:109F200066B2983F9396B9FDA2068ABFBF5AEDDC90 +:109F3000212F9BCEB70CF28E3D1FAE652EF7E55C50 +:109F40007C500E94C6EF1E433E0C35AC8B95A31788 +:109F50007466E714F845A66AED94CBE3B1A7181E22 +:109F60001062C2B3B2CC38627EF5AB4D1EEF40A595 +:109F700088E771C23E637847A4995C4FE3DFEEB691 +:109F800083398CA3796F0B59387FB2F524C8ACFEA6 +:109F90000F1B6490DA110EBCE6A1F95C6592BE6AF3 +:109FA000E1FE9DC5FE211D9155AA63DF42FD39B931 +:109FB0006F35A1FC3BE1CFC9CE78667FCFB3F0B35C +:109FC0000553F8B34756B178B1A2761E2ECE8FBA9C +:109FD000AAF8B19FC90B3079D9C7FC46C614C8305E +:109FE000BF11E13DCC6F04F2270D2A077A5AA8DC95 +:109FF000854D57E2F9596AA4A909E3A59F8E7D9082 +:10A0000055D98FBA83CE55029D183FDF69C3EC89BD +:10A0100084B03867F941FFEF3A301EB3D3CF618087 +:10A02000890ECB01CB7D18EFDF19E6ED7F26873A4D +:10A03000F13C62BF384702C5D2DE57E0FFE7652F2B +:10A04000D18136106FFF9B5EECCFAF08383D87F0B3 +:10A050009984191F111FBFC6E1C681B9D43FA90059 +:10A06000365E7C601E1F6F01B7EFA17543053EF69B +:10A0700091FCDF84877048736B1D1E2A836A9A8067 +:10A08000DBCDFE5A817795FD8092E4FB9D882B9570 +:10A090005E3715F6358147A5F907F44B317EC1F4DB +:10A0A000701AC7FDC7E2FBF45B3DEE7EEFB9F145E8 +:10A0B0006D9F482B8CC57F29277585C161EB70AEDC +:10A0C00089C1911B72695ABE558EFB6B5917F1D02D +:10A0D00024AD7F9BCF8ACEED8EAB5DF3E88D5A74B5 +:10A0E0002EE90FF1F5572DBE2B719C827EE0E9CE53 +:10A0F0008644B874BBFA8467CADE62FFCDE80A4CB6 +:10A10000D96BECBF5AABCE01D7B45FE4A81F36E7DA +:10A110003BDE7BF57738DE9FEF3C5DE6A2A3D9E618 +:10A120009F80636E3AAB963BC510FB5C9ADB8F93C6 +:10A13000B0D88F2BC167163A61DEAF0F6EAEE1F675 +:10A140000DB763FE13883A6E3CCC02FD2B633D0EC7 +:10A150001B1E096CFB36D732BDFF7EED131487B38F +:10A16000FA15F05F353D4E97EE4C519C2DDDE7D34F +:10A17000FBA31477A338DB7666C8FB58B9CD9BDC0C +:10A180008AF27BDA3F370B11EC37B502E3D6FDAE2E +:10A1900078825B9EE29FBAA9E879995D8EF4F0F827 +:10A1A0009F0D6B8DC5F300EE55F879FD77BDC97B2A +:10A1B000110FD48D40715AA075E035F8FEF87CD3AC +:10A1C0003AF805F9FFFC7C4C85F4B166464F86F9F8 +:10A1D0006B3B0DA49BAF9391A6755A9C3DDF5BEB47 +:10A1E0001136DD04D94F998E990DB89E6A94093ABB +:10A1F000B7AB8917C7E77EC523E6EDD6B2F4B9E75A +:10A20000E3560CB4B2767BE7481EE2FF1C4FF61013 +:10A21000C6A31A3DB4AE775BEAE378D4BEBBADEE1D +:10A22000268AA75BAA47263A725AB1753828ECA647 +:10A230007E113FDDD3C8FDD6E73B5ED7F0BC668F0D +:10A24000D949F9004AE687D47E58F03BB3F804C5F3 +:10A25000C9874B9CBFF429DCCFEF0F07BAB345DFAA +:10A2600047E87DA6A9E38587900EA67F0F917F061C +:10A270000D5B181DBAA52F417EEF9D63797E81721B +:10A28000B5DA437216C1B89C8CE7A24EFF79EF6A2B +:10A290000F9DB366F49089F6FB29EB0DA08D48D194 +:10A2A0001BF07CB1E6F8953AED95CCDE6928B0F369 +:10A2B0006B56A556E07CD974F9607DD1F990E66EB5 +:10A2C0004F223FEF5E0206FA63BEB95DB94758BF41 +:10A2D000A757FA7454055787AFCE7D13E5896D2BC8 +:10A2E000E827FBA2560EED267F77100CF63E123BB8 +:10A2F0004C76941693C142BBEAFFCA345F4C671098 +:10A300005DCAFE9547D7B0F6EA6ACF2CB2CB5AF9B0 +:10A310007EA3B37FB8DF6871A75D257B73D4DFFDB3 +:10A32000E38FD3B9B2EAB2AB1428A88F76D7EA0D7F +:10A33000EF692EA20FEC521E8FD0B92EC8B794B57C +:10A34000B343C73FFC0F2F16F0FD84E2B2D385FD67 +:10A3500066F753CA7E3BDDB3F51F5E64B29CF4F230 +:10A3600038A8A25ABFC47579429C2FEE75E5DD244A +:10A37000BD7CBD9C16EB186716FD6DF48F915F03D5 +:10A38000D76CE47E16980E3F86ADF7D34A819F6D59 +:10A39000EF7719ABBC3F3195D712F2C7CBE4B5AC20 +:10A3A00057928AB74C5E8BBD5E47575B1063F33B99 +:10A3B000560BD93E9CDF35166C467995C0ECD379A7 +:10A3C000FD09FB1CA509E5F01AD882EBD7504C3CDF +:10A3D000871C6C7E3773144BE3AB449DF251691EAE +:10A3E000B7BBE671B6D769877B2151936BC23846FC +:10A3F000EC26C463775435713D7A3DB76CDD644C0F +:10A400009F4758C1F586379A8362E3DAFCBCC36B79 +:10A410002DF4629C5D358F2551FE3B55F27BDDF5B9 +:10A420006FF58A3C962650D03E4BE33AC1F5DB658A +:10A43000F1BC31494F3D6C12FA09C7B956FC4DCAFF +:10A4400067FB940CA919AB006EF436713DD3B19142 +:10A45000DB3DD78324D762FD24ED5F0D962EB1BE80 +:10A4600061D4B6CBF4DB62EB0BF4E48D423EA7DEA5 +:10A470002763EF73BCF7723CC3C26ED637C7D62FC3 +:10A480002AD2BEB6B89EBC5EC8F58D5E614FA437B9 +:10A49000535ED0A0714B02F93CB0C632B7A0D64291 +:10A4A00019C17C941038EC6326DF37223FEDF89118 +:10A4B000A227A8B4ED8152F3EFB603BC3167DE49A1 +:10A4C000B5E7B6F1FD37951DC7BD3FDBF96DA8F9BE +:10A4D0000AF9E4157C6815EB65CA5ECA88F56E5208 +:10A4E0003E90AC5A498C4BCA1238ECADBD425EE48A +:10A4F000007FEFC683F9CF77E13A952316F9D7109D +:10A500006AE3769B621AEB8BE06F9F733E21F278D1 +:10A51000E39977D3FE3756DB49FBDE805E5E7FD85A +:10A52000FBEA1AB841C3B8DD6069FD3156A83FD4D3 +:10A53000A8C7B98E857FCFE8378AF1D9E6534CC4D6 +:10A540004BFBC31B6365E382AEF31553B51E22BEFE +:10A5500094E6DB23E7C3B7319157B763F0E51744BF +:10A560001E82535F2F2EA9AFBFE0D0A7425FBF8DE1 +:10A57000FC7FEEADE07FB57118FF76D9383983A93D +:10A5800078254DF48C1AFBD2148FC1F58D7640A638 +:10A5900083F215200EA417B121EA3BBF6111DF023F +:10A5A00022CEA4363AF719391A70C0B1EE3460BE23 +:10A5B0001AF68B74FBB7AB34AECD6F66B3503E99D1 +:10A5C0006D5FE272427FA4547E9A5DDAF11B3CC655 +:10A5D000394BFBD4C78F207F4F8580F687D2F43B61 +:10A5E000C789BD37515E3FB9EA4348315E2F722EAD +:10A5F00038BD9D02AF17E8B5FFE3D227D693B775F4 +:10A60000931E058F89F1CBFED8464832BC8780EB7C +:10A6100093112C57623EC9121DFDDFEF7A0DDEDE6D +:10A62000E0FE9D4713717AA33A7FEF6EB60F15B324 +:10A630007F2E56B97D7CFA13A9DF625E427AA76449 +:10A64000E0FE76B2274FF6D3A6DC252AE6A55DA26A +:10A65000CEA47A9BF637A96B0BD6E726E0E7FE0C73 +:10A6600011B5508FDAEB4FCDF85E403A4F64785C0D +:10A67000E344E6DFE85CFFC401398B4C3D31726393 +:10A68000D9F57352E86DBBDEC903B285FDA547A4B9 +:10A69000EC02D6FEA462458AE60140969F070BF8BD +:10A6A0008319D92197A7772455D433277B34E967B9 +:10A6B0006C6E6E473A19FE9B324D2AFA6495E89A01 +:10A6C000A13AE7D3A67310F3159AA6F27706A36F03 +:10A6D00010BDA7D873B94C3C69A7D01383D1E2FA57 +:10A6E0002420CE5F03DE6CF1BC0717BDC116E7BAAC +:10A6F000B4F11B16F914C33AC76B38E6A179186E8A +:10A700002CAFC706C43CD8F50663FCBC755049683D +:10A71000D5E0E3D59DF8941A475B75B80BB7F91AE5 +:10A7200048767536117B5FC63802850E0DF49F9E04 +:10A73000923EC4D6CB0F6F0B59520C1F4EE4BEC9CC +:10A74000E898C5FC1DB44F752B2BCD6DC3BC4E19BD +:10A75000306EFCC89FBF917B15FD51E6FF205C6BFE +:10A76000A4D65F6B601E5C52C275B51B953F75FE2B +:10A77000AEFE8E56B1FE18FCD1A1CEB5188754207E +:10A7800021E2191E03F3F568E97B4AEB09D49E67C1 +:10A790007D53ED4AD2E9F28B7CB0A1BCFFBD95D7C9 +:10A7A0004FB37FA87766B9FCACDA6EA7DD5DE37ABC +:10A7B000BF57C86B29BFF2AD1A6726BCACE1B9AC74 +:10A7C000D6E6D1B3581F52B5B8DF466E5100EDF84A +:10A7D0009986DE8B21BE4A7CDF053CCF0DBF8828E1 +:10A7E0005C7F9F51B91DDB78E7A725DC9F4EA197C1 +:10A7F000BD18E1BC594C7EDD76DF887182E2894369 +:10A8000070B4AB19EDF92D1E3A4FDADDB6AFB6B024 +:10A81000FD77C43853F30F86B29C4E65C99F57DB52 +:10A820003C16EE5BE73BFF6E3FB9D2FC376C75DA46 +:10A83000C5E73A2F2F21E2CB2ACFFF858E63CFDBEE +:10A84000F4F5C1F566E39D2F521C67CC2CAF6FA6C3 +:10A85000CFDBCB346F9136B08AC5717E2CF6317761 +:10A860005E9F062930313FF115BEFFC8CDCB63078F +:10A87000CBE81F39EEF23F443FF90F021CC5FD56ED +:10A88000312A7C0F7778BFC2F6CDE0F62BF72B4B41 +:10A89000313FCBA23CAFD11E8B9E4FCEBFCF23F01A +:10A8A00095C0B35CE81583CE3FF72B646F78E02C3E +:10A8B000C6414007C3963BC07A5DFB158AC7182284 +:10A8C0008F80559D89ED80F4D2624CF6ACA7737AE7 +:10A8D000EA073BE271986E0EB386344F5ECB22BC22 +:10A8E000948C7627E3E72EBF800D01D70A581770A6 +:10A8F0009380611FC14195C11897F7667482030266 +:10A900006E12709D806B053C5FC0D23E8277A9BC01 +:10A91000BF9D4A96F71F10B021E03A01EB029E2F2F +:10A920006038C8C7F77118F7438283026E12F00CC3 +:10A9300001D70AB859C0D241824BCD5F206E117F3A +:10A94000A7E6BF8BF30D40F89B0917DC3D55BFC050 +:10A950001F1DEC31A4C2F3436F89F8D3121FD73304 +:10A96000131D09CA5362FE42FA44E1B963ACB8BC94 +:10A970005BA2DDE4B97994D52B1ABFEE2DBA2EAACD +:10A98000C56FDD79E2F7DEFF20FC6EF6D9EB9EFBAA +:10A99000E7131D26E1E9EECFDD0EED2D2838A70FD8 +:10A9A00028D934C66B988D44FE8E5773E6B3DEED1E +:10A9B000E3E79CBD3E9ECFDA2FF09BE8E0E70F83F4 +:10A9C0000B02D983D2F438E35FF8783CE1FB369E82 +:10A9D000DA61F27B8279B662C90FE27ED468BCB3D9 +:10A9E00042FEBAF2FF0AFD65771CE4DFF01D1B276B +:10A9F000102ACEA7BB27F5CD2DE913ACAEE667CF65 +:10AA0000D19FD1A3B1C6C2BC69F11E248F4CFAE517 +:10AA10000CAB67E78BC8D43F8F1737F278B12CEABD +:10AA2000D3384DFC3B066B09EE33EC798B18479A13 +:10AA3000DEAFBB5DCE57C7E74BE063E7A7C8F01CAE +:10AA4000F533898F92207EB99F631EB21EBAF0E75C +:10AA5000170A7B8D12E365F8F94BA5F69F15F232C4 +:10AA60004D3E4BCCEB7FF3D976CA610BF3816C3949 +:10AA7000B2E5EB7CE5E882E50437A4B6D2729286B3 +:10AA800014AD1B055DCEC5E72E2F45E4245758BFF6 +:10AA90005EAB15E7F926C90BC34721B9D5393EF599 +:10AAA0004BA2D49F846B7C21F62060E403A3F75271 +:10AAB000AD56F081C7290278CE58D09E1147F84A8A +:10AAC000B224F43EAFB746E3EB7C756723C71F445F +:10AAD000FF2E7C597F5A617F3234BAE49CE3FD7EBD +:10AAE0008DCF2FAB4FDFF94D1B5F91085F191269B6 +:10AAF0000F6BF75151DFADBFEC7287C06FD4035BB2 +:10AB0000F977920928FCAE32A879C4778F7C9DB979 +:10AB1000F59317E56AE9F9CB55B57ABD5E2BBEEF23 +:10AB2000303DDF82F1BE52FBCE316D723F6811F3D2 +:10AB3000764EF3FE6BD443CBA6E6B35A7C2F15E3D7 +:10AB40009E2BBE27A7E35B959CBD21F444B5F8ADD1 +:10AB5000394FFC5E76E1F756C9F519B11F558BFFE9 +:10AB6000FBCF531E7E309DBF55AD238F766EFCFD0F +:10AB7000E879E2F7CF6EFC4AAC5B55E3FC4A0397F9 +:10AB80000F459CBF548B5F4F65FC44BED8BA012B68 +:10AB90004EF61AF9E3BBB5750369650A3F0BB85E5B +:10ABA0003FD7F1EFAF7AFC770F58CAD4F88F68EF30 +:10ABB000768CAF2826095BB5E33E5AEDB8E9F73944 +:10ABC000E87E7AE47D8E71CF97EF5FAC7AFC5B1DF7 +:10ABD000743F3772AB93EE9049F9C4D58EFBCDF339 +:10ABE0005CEFBF14F80635DDB10F94B2DFCF08BBC0 +:10ABF000F6839AEE90E352F5DF10F6CABBAAAC7F5B +:10AC000052F4DF6CE353A1FE3D02FF7BAAACFF6B65 +:10AC100081CFCA2AF1F9BE5887A5F6CF80E07B1014 +:10AC20007564815F73A1794B5B7C49C98FE79CCFC9 +:10AC3000F4D077826F289A8EF14EE802B2C7FDC732 +:10AC4000C307795E495AF8FFC9B4C4F530C5B7BC2B +:10AC500051D3711E67FB5D8A92B08A9DB7D5FAB950 +:10AC6000FE9374B39BAF7715300FA954FDA0BF7846 +:10AC7000FCA5062628FF0462E21CE9CC8D46D173B0 +:10AC8000022541792DB2AEC24136CE40ED46A33009 +:10AC90006F396EE313B3081F55E7F8A88A6915CB1F +:10ACA000539EE3E7F36AF763FB87526C02F83D0EAD +:10ACB0001CBF417FA21BF3C4D3B52AF16920EC3C31 +:10ACC0001FBF49F4F34E41DF80B77C9E58E7CC7636 +:10ACD000CA57EA6FE7F94A069894DF39102A7FAF1E +:10ACE000C1580F8FFFEF14F94F23F8FD287E4F8CCA +:10ACF000DF8F2EC4F65FA1EFF04EB57ACADE8F1358 +:10AD0000369D71F6608BF37B1E3B2EEF379CDFF593 +:10AD1000F862CEEF7ABC3315CAEB1A08F1F3814A18 +:10AD2000F8DB79EF76BD6125A5E945F994759C0BB3 +:10AD3000F8624E7CDF3EFEF1F641EF61BD185E6FBA +:10AD400015DF4AC51B26E9AD515359AE371CF91919 +:10AD50003D42BE7C355A0AF532D3BB25DE0778FB6F +:10AD60005082F243B458C2A078B4D807345C0F05BF +:10AD70007CFAA4BD2E031E3BDF98F23A24C3A2F353 +:10AD8000470DD79134BDDDE4BCDA72FFFBB5315A13 +:10AD900027F51AAD13C998A0EFBADCE32CF45BFBDE +:10ADA000FC783EE6B71EC0D2FB0739596CBDECF506 +:10ADB000733DAADD9030B4F9E4AA92DDE3C6E34B1B +:10ADC00062FD856CFCD316E55F548BFFA355E26FE3 +:10ADD0008FC3F0FF1CEA5986FFE7B12C85FF534271 +:10ADE0001FD581D14B7BB6C1F52CC07AA330BE1ED6 +:10ADF00008F07EEB849E02E870E4F578055DD5D21C +:10AE0000F3ACADD72AD0638FCBE87951CCC777CAE2 +:10AE1000CDC7B7053D8100DFB7B40309832D4DB819 +:10AE2000B8C4BC9C1078CC0C88B852BAE39CE4EA55 +:10AE3000A52AE93831352FAF8A79F9E772741C17E2 +:10AE400072959161E549DC4F9BEDFC850D8E7999FA +:10AE50002DF893F1D9F3D2E99897DA739C975F555F +:10AE600049CFECA979392DE6255F4ECE0AEAFF5E7F +:10AE7000D4FF83A84F76E2ECC0EF06F0BC6CA13F94 +:10AE8000E109D44FED6FAC9E1C583655EF93A347A4 +:10AE9000EC7A3EAAD735594F0B14F407E9D706F0E0 +:10AEA000FC7B507CFFF1FDD1F035A25D84DADDC082 +:10AEB000E961ED6A0AFBFFD2E82B76FF33B05EEF63 +:10AEC000DA3FD8F5A285F56607FE60D78BE173E916 +:10AED000C0647F0D85789CF0FFEB00CFD771E57BD8 +:10AEE000E9D5E53B78A349BACFA10EC2199995439C +:10AEF0000ABF5F21CD8CEA43983FEB4BE6A00ABB2B +:10AF0000CBA3F1763E666FE1F9F10C1D9EF71BE8CD +:10AF100082987080BDDF1355C81FB8D39F6C0BD4C7 +:10AF2000733C290FE0556E8FF586DA441C85E3B536 +:10AF300037F88111EC4F677861FF9F0C469EC7FA86 +:10AF4000FBE6A894CFFBFC9CBBC84EDCDBAB00BE91 +:10AF5000DF7B9D4A76E203AF86691F1E54CC9B2897 +:10AF6000FFC1520DB41BEF0EFCE118E6298FF7D696 +:10AF7000E8D255440FE19FF640A29FFAE776E776C4 +:10AF8000863FE603D3D685FD76713F06449EF3DD0A +:10AF90006B0DCA9B3180DFDF34DCAE529ED2DEC641 +:10AFA000F91D38DE03ED1AD91D0FDC30BF97F2B959 +:10AFB000DB0394FB56173224CCEF89AC50013F04DD +:10AFC000A98B1ABD6877869707F0CE2FA86BE4E3AC +:10AFD000851702DDF3E7854C22CECAC8884AF738C8 +:10AFE0003D70C386DC66B46BDA79FE3223ECE5F89B +:10AFF0007280906025C83F00C4C73B9B9FE7DBF38E +:10B000001CC94CB62F7B8E18C956592F575DBDF001 +:10B010008842F9C915EB65AAAC97ADB25E8ED7AB85 +:10B02000787E2FF22935F60FE3707E773E76A8FC06 +:10B030007771E79AAFBB37E0CCBBAED4DECED3ADF1 +:10B04000442F1E664EE22957AE6FE7D9957AEF9DE1 +:10B0500079570CBF4B1BAEBF5794F7F1B2413C6F11 +:10B06000D81EA3FB221BC4FB86FBE8FE48773F7F6C +:10B070002BF4710B24CACE439DC0FF75863BC6B32B +:10B080005B940AF900EE7C3F97DED3947427ADDB26 +:10B090001B787ED1E4F7938DE2BB114825E214CFF3 +:10B0A000B2228B674EAD1FEFAAEFD2FAB1BF9B64FD +:10B0B000F3C3BF9774C9895B2E7CAEFC940B959348 +:10B0C0001FBF4D72E21D91AB5A3FDE4C95F5B25554 +:10B0D000D6CB55574F1D91AAD22B6AA6CA7AD92A28 +:10B0E000EBE578BDC195AAD8D7470731BEE5BD428B +:10B0F00073C08357049CEFAF0C39E0A165CEF6EA2C +:10B100007267FBA1E5CEF6EA0ADEDE0CEEBF261D75 +:10B11000AF7E9DFCAFF35C272D5AF9FAE1F60AEBFE +:10B120004AD3FDD8BE4E3100EF1762FB5556EC5B9B +:10B1300045E33FEB827CFD5F17D01DF7D3FDA9D31C +:10B14000D912E4F8DAF456C2D7D6BFFF220BBBAB54 +:10B1500044DE3D7E564079D830DE80FD3D7FCFCC49 +:10B1600006B4E7F6BEB682EEEFE87F979D376352EE +:10B170003EA472EC9764BFECDDCEEF977EB4D6ECC4 +:10B180008AA3BD12F600DACBCC8DA27B3DF6C63C7D +:10B19000648FF45F5DFEFE924FF5F03CA187D1EF26 +:10B1A00067FAFF80B877EB4171EFD6FD3D0695BB9E +:10B1B0007B5AA8DCD5635239DAD3CEF3197B2CF154 +:10B1C000DD5917955FEA49D0F32FF47453F9F99ECE +:10B1D000243D7FAA672B959FED49D1F3433DDBA921 +:10B1E0007CA2274DCF1FEF19A1F2B19E0C3D1FBAD3 +:10B1F0007A03DD9371EA3E0F7D1D520AFF392967FC +:10B20000DC61F65667DCA121E98C37CCEA76C61BF7 +:10B21000F455F31DEF236DEF70C0A1D6258EFA8192 +:10B22000F8150E586BEC74C04AE89D0ED87C6E83FE +:10B2300003BEEC999B1D70EBD39B1CF03B3EFD11B4 +:10B2400007DCF2A93B1DF0C5FBEF75E0171FEB73A0 +:10B25000C0EB83F3F97DE0033B1DCF8DFBF639E0B6 +:10B260008FCCB41E0B623C3413E1F6EC7189F6C14D +:10B270001973CDDBF03B29F8B14CF204519E0F3F1E +:10B28000637EEA72BCA70C94D48A1BC395EF91B677 +:10B29000E33D72A43D89F27AFA35C9407B578A6C46 +:10B2A0005F58E8CFD9E5D65329388C71499167A604 +:10B2B0005F0496C5DA05983EA1C34548E57650DCA3 +:10B2C000D243DF5165A424E59B309BD9FC2B1DF3B1 +:10B2D000E8DDFB6F90ECF253519ECFDED1A9350D26 +:10B2E000B0FABB17A926A6784DC3D775BFDDAF82CC +:10B2F000DC0FDEB583C72BF517FC4D1A6B1F32939D +:10B3000033D055B5DB8572DFA3EF944286B91CFDBF +:10B310009A503C039B43588F7FD7C7EA7F3558200C +:10B32000BFA164CE5259FDD89664B387D5DF2DFAFC +:10B33000DFBDECC7748F6038F713B898FC9DCFD091 +:10B34000F8E1B6A3707B18F5D338AC2BB28E77FF3B +:10B35000BEF8F748E34199DAEFEECD82C9DA05721B +:10B360005FA77B38ED7909B61E8524F6BB6A82BEDD +:10B37000A1DDBD43A27E764B2FC56282CE5E179DB6 +:10B380008817D2753BEB27D49D94D6B5F2E7CDE173 +:10B39000A97EF1FD667C7F4B4AC23CF76AF8A72282 +:10B3A0009F928C7FB8DEB664A4B2FC337216F25B57 +:10B3B0008B57E2DF839C7F8C6FB7B74EE7D764FD76 +:10B3C000F45158DE5AC06FD11EF9727B11BE4EF295 +:10B3D00089B54F52FB97606988B7433E8419DD9B5E +:10B3E0008BB5935E12E3649DE3303EDE4ECFD322F5 +:10B3F000BEC8EFF5B4F344ECFAF8D7B55CE42932F3 +:10B40000BABDE3B59BF1FBEB8ED624DD033C18F20D +:10B41000D0FD4283A1AFE4E89E7E1DE8FB5945B113 +:10B42000FA7E14E571E83EA9D83A75FA09F8654A3A +:10B43000E1F76403213B0FBF82BD24EE1596C5BD25 +:10B44000C2AA92E86AE2EBD9EC85A9F8EAF4F1F72E +:10B4500011DD72CCB9FF0E6C71EE7B71FD668A63F3 +:10B46000F747ABFB6EC897E7F6A52AF0F1E683FC39 +:10B47000BEE3BC9FF0B4F233A85C93AFA5F2AAFC84 +:10B480006C7ABF3ADF40F0AA7C33C157E69BA8BC78 +:10B49000227F293D5F99BF84E0F6FC522A57E417CA +:10B4A000D3F3E5F92B095E965F49705B7E2D954BD2 +:10B4B000F31D542EC95F4FEF17E7AF23D8CCDF48F9 +:10B4C000E525F9F554B6E4FF8CDE2FCCDF44F0C55A +:10B4D000F9CD042FC8DF46703CFF51829BF31FA6B5 +:10B4E000727EFEBF52D994FF18BD37F21F27785ED7 +:10B4F000FE1E82E7E6FB099E93EF25B831BF8BE085 +:10B50000D9F9512A2FCA3F4065437E2FBD9F957FB1 +:10B5100088CA99F927E8796DFE712AF5FCE7C57D9F +:10B52000D14F5119C97F95CA70FECBF43E94FF1BD1 +:10B530008283F9AF5319C87F9B4A2DFF3C9595E64E +:10B54000A9D2F74F6B6086432E56E72F72C0574E35 +:10B5500038F7EF953F77EEDF2BC69738E065C79C4D +:10B56000FBF7D2A39D8EF78B8FBCD3015F9273EE56 +:10B57000DF0BB3CEFD7BC1814D8EFACD998F38E0C4 +:10B58000A611E7FE3D2FEDDCBFE76CEF73DA2FA9C4 +:10B590009D0EB861AB73DF9E050FBBF2C90F3AEA8F +:10B5A000D7589F73D40FB77FC575BE92E5FADFFCFD +:10B5B00086D38E6979A1E8394C7CFF75F4DDFEA94C +:10B5C000468FB86748DCDB2AEE4773CF679DD00310 +:10B5D00033F2DC7F8A8A75578FEBAE20EF89D91959 +:10B5E000AFA17EB0ED8C19F38D2FBFC8E0D373559A +:10B5F000B397C1B69D61D7AFF8BB15AA399E6678DF +:10B600007A8FFBE8DE3929D26D615CEDEE1312DD35 +:10B610006F57371B449EC0755D3C3E01F67D3A7402 +:10B62000BFCFF01CFBFDE66B298ED1C4E123A11D29 +:10B63000EB308E3AECB5DF7FFE5A6AEFE7F0FF0899 +:10B640006D19C2F775358763681FED2A71BEF93F22 +:10B65000432AF1B33664FD30B46CEA9EE9E3D1E4E9 +:10B66000CB21F67C9B969C875776E33DF7788FF34A +:10B670003AC5FA11D65BAF58AF84685F70FA0FEF26 +:10B68000C7DCD765742FE04FF0BD1C7996F6A3BADE +:10B69000EBEFA3FBAA86C30C9F50697CFE3E244FB0 +:10B6A000EE3760EF37F3299E4AF6E05013D0BD190C +:10B6B000C3B58934DEE797FE8E06874CA43BC3935F +:10B6C00095447EE2F025862D178EFD092091C33822 +:10B6D0007E301932D05E0BC151CABF88C004953A82 +:10B6E000E892E3BE6D9BFE399C7EBCFF3F44E7F0D1 +:10B6F000D6B3E314674D81B8BFFA4D7CCEF8723AE9 +:10B70000B4AC345FAE91EF039D8DFF28B327918ECB +:10B710004781E33B86FEA98478A6F466EAD7798F51 +:10B720008472FCEB243776BC47915769CD488FB8BB +:10B73000C7A18BFD43FBB03E513EDEE3BEB7E15CEB +:10B74000E33DD1B03BDE13A2F3E453ADE5BF83B3D9 +:10B75000E33E63ADE5CF7B9F157EDFD7C479EF3342 +:10B76000E2BCF72BC2EF3B2CFCBE2FA2DFC79E3FF3 +:10B770002DFCBECFA1DFC7E027D1EF2BF8BEE4C977 +:10B7800012F7BF2CAC95849C6D27FB3E28EE2B62F4 +:10B7900023903D1F10F6FC98D93713FD8E602D6461 +:10B7A000D14FD87ADD41FA7E969162E2FD0077FCB6 +:10B7B000E2F599FF85C1F11838EE770AB4BAEE4B7D +:10B7C000A8348E92B5B0DF20F31B326669FE9C73FD +:10B7D000BF5A16FCE7D52FBFE7C7BEB78D71328DB4 +:10B7E000F21744BA7594ABBFA1714E897140FEC186 +:10B7F00011BACFF07205CAC9C1B471CE51FEB68478 +:10B800005DBF4FE1923FC0840D46EF3CF1BDA611F4 +:10B810004A37EF61EF9FB84F757C9FED96C7DED733 +:10B820007C14871D5CCCEFE579B17EDD45E80F7EA9 +:10B830007AEF9B4D889FFDDD52BFE98C5BCCBB0F3F +:10B84000A4C27C9603623FE8D7CBCBB97DAF78FF2B +:10B8500058F97A0F8A7A5F0C5A7D61D22B13741FC4 +:10B8600064FB89AE9B11DFC77668745EE36EF7C533 +:10B8700060726778D9743C0BDBA3BC9569BFAF5C81 +:10B88000FBE53FEDFA29946FFF70B8BE74FBB697E5 +:10B89000BB1EAE80FFC1E2E3A71FC376F3623CCEBE +:10B8A000D4DB3044F3BB6B07F79F5F5CB48EEE993B +:10B8B0001DA8E5F356A4DF2F54E04B7705BAFEAA86 +:10B8C000527BA93C5DDF2CC717C6D76315F8F29DE4 +:10B8D0000A7C3D5001FFBF2FC1D77988F73CFC7D22 +:10B8E00038D6AE770EE32BFA6FC85798BE1E8AF48F +:10B8F0007BAC1C5E55C8EBF805CAEBCF2BF0B592BC +:10B90000BC4E5CA0BCE64BC92BE27D01F22A47CAC3 +:10B91000F3B592BC06231726AF33CAB5AF425E67B4 +:10B9200097C3BF0A796D2E36BE0F8216DAD5A75A95 +:10B93000F939D9D60E7E3F99B785EFC3C1E39F256C +:10B940007B6980ED5733DA71DF3EF1E01D6D53FB0B +:10B95000B47B1F72F7E7DE47EFF8DF9FA17D342449 +:10B96000F67D1B1FBFE1EEA7FCFD16E73A6E007FD8 +:10B9700097A9E0F72E1A926FF578CE7D3E60F2F12E +:10B98000818DBF96CE159FA673C59AF60B1DB77C09 +:10B99000FD59DD1766177C28E2B40B666FFFEA637A +:10B9A000741F89E867B662D1EFF8297035BFFF646C +:10B9B0001BCF1F92B77FF9B1934B0BEE9982C35205 +:10B9C00061BE90BCEDF063270BF0CA63FC87C79B98 +:10B9D000298F31AE5F11A07BEBC6CA9F67FC40EC9C +:10B9E000E3DF17E71947C479C677855DFBA2B06B23 +:10B9F0005F10766D4ED8B57F2BECDAE7845DFB0DDA +:10BA0000719EF1A0388FC8F41C20784F4F56FC4E21 +:10BA1000C993E2774A0E8B7CC967F9B9454F8EDB33 +:10BA2000C78F7FAD19F93145873B8EC5E9B0EF4728 +:10BA300077D3F12ED379DFC6F52D41C7BC5D6738CA +:10BA4000E322D7C6663BEA5FA3373BDEAFD52E7550 +:10BA5000BCEF80A5CE384BFE0A679C65C21917B9AA +:10BA6000F2E7CE738D95E3CEB8C88A63373BE32CFB +:10BA7000479DE71A4B8F38E3228B73773AE0CB9FD1 +:10BA8000BDD7517FD161E7B9C6A54F3AE322B3BA1A +:10BA9000F739E05AEB61E777F5EDCEB848D874C6D0 +:10BAA00045822D5F71C0EF61FB3DEA4FBFE18C8B9A +:10BAB000F862CEB8C84F43FC1CD0F6B359BBBF8B5D +:10BAC00090BF19CA5DC9E4FD8928BFE7FD09485246 +:10BAD0009E2CC09F93DFA04CFA0D16AD7B59E81D3C +:10BAE000B5E1E48FD1AF517673BFE70E69454E2BB8 +:10BAF000F47BBCFF2215CA87ACBBFD870AFD7B4DDA +:10BB0000F277940A7EC9F47EB9BE9ABAE7BC2D8D4D +:10BB1000F954CAA45F72BDCB2FD996A1DFB39A5155 +:10BB2000DE2F9936CE39EA9FD391127E49CC43FC61 +:10BB30003314EE97EC32855F02FC7B29BB3F5BFF41 +:10BB4000A80DE5F5887D5F8BBA88FB0D4AA8F879CA +:10BB5000B67DDFA4BAB87C7FB65FF37711714F5C16 +:10BB60000D88B8FEFF978FB7523EAEAC29113779DA +:10BB70009BE5A354BD73950F057506E5837C70188E +:10BB8000F3417C2E581370CDFDDBD6E1F74DDB8100 +:10BB90009FEFC02BFCDED552FDDBF95DF155B7966A +:10BBA000CD83B0E3AC522D3FFF8CB7DF4AF993A7AA +:10BBB000D818E5EED576E75BC8D114FEE81E7ECF37 +:10BBC0005EF4DCE79FEA785C28DEFD81B2F68AFB52 +:10BBD00077C1E256F97B764705FEDF7E7516D9A957 +:10BBE000BBB6717DAC747FF37994C74FA33C9A14B4 +:10BBF00057D12E41BAB62974AF5AC8008A0FCE0D5C +:10BC000041B6B709F96AA6F13E2FF647E7CB93F2A2 +:10BC1000B9CD79BFC9EF74BE9EE389F27CADF8BBA4 +:10BC2000062B0F77D0774206A4F45A5A3FF07A9445 +:10BC3000F023391D6E37F9EFDF317C747D7A7B3765 +:10BC40005EEEF5A96CB98AE24AB3257B7D064DCC40 +:10BC5000D739150A95BDEF6D5ABFE7B81EBF306DD5 +:10BC60003DDED0F78F38EE9888236D677F05E79D1E +:10BC7000EEFEECF568C3DF7EF56EFABE6578EC4E3D +:10BC80007E6F71A3B81F6C8CEBC752781D1272B413 +:10BC90005BD88587F677F6217F07D8BA29D4470B7A +:10BCA000FEF2BD81243F5FACC3F23307F877DB17A8 +:10BCB0003FB4453CDF44CF1744F9FD470B983C6146 +:10BCC000CC3BBCEC158DBF7F59A7FAD1F1117C7F1D +:10BCD000B178BFA7BDCDC2DFAA8CD4CEEFC4521EAF +:10BCE0003B4A7A97CDB9B5C0C07115FA1D9DB923ED +:10BCF000F038D231772CB1E13AF40FD2C07FAF2DBA +:10BD00009ADC89F21AC900F597060E1BDB759ABFFB +:10BD1000F858721FD56FE5F5D97B82E7A6F8FBE0EE +:10BD200018C317C733D97B03DF73FC1BB7E814AF05 +:10BD30000B8D1D4DAC257FC46ECFE1865B787B6596 +:10BD40008CD183ED6376FBF10CBE9F15E5EDD5310B +:10BD5000BE3FEE69DF44F7EAB1F1E9DE29AF78FED4 +:10BD600084E07FBCFB5F336BA35379196966FFAE38 +:10BD70002FB29EED756FFF0E60BFF80E49D3663F80 +:10BD800072B2E05E06FB77430363CEFDF94C0D5FB4 +:10BD900097FF1DF5CCB2CAF7B3FD3B5950D3F30062 +:10BDA000800000001F8B080000000000000BC57D14 +:10BDB0000B7854D5B5F03E67CEBC3293E4E43D79C0 +:10BDC0004D4E2040944007081810DB495444458DDF +:10BDD00068DBE0B53A04E419202296A0D89C9004D0 +:10BDE000F20206EB2F111126281A2BE86041B15AF6 +:10BDF000EF80B9147B6D9B5A2FA2A28DA05114B86D +:10BE00002915C9DF5FAFFF5A6B9F43E64C2609EA4D +:10BE1000EDBDF93ED8D967BFD77BAFBDF60E6B102D +:10BE200059C8C6E8E79B61F09F1A63CC5725B2500A +:10BE30007E58BE32C3989F3BCC58FFF64B8D79D7C6 +:10BE400078633E798AA1FDF91B18EB744246F2D85B +:10BE500018A4D2D1DB6CA56318AB4D5E4EF9DEBBE6 +:10BE6000F4726F0CE6F3E418912533B6AD400C3450 +:10BE7000E532F644D5F2C3C320BF3659A43ED7BA43 +:10BE800066C6FBA0DE37F8F3A3FE69433563212BBA +:10BE900063DBABFD946EAB6EA5B43E79F0767BB5FB +:10BEA00076CF57DB58681463C16A99F2CF56BB2826 +:10BEB000BFAB5AA1F457D5F9F4BDBDDA43F927ABAE +:10BEC0008B287DA2DA4BDFDBAAA7537E6B7529E5B1 +:10BED000B7549751BEB5DA47E9C3D50B28F5575784 +:10BEE00052BAA1BA8AEAB554AB94365537D0F7C0E6 +:10BEF000B860596941FF79D6CA00871428BFDA9320 +:10BF0000510AEB79FC6A56168C5A4FA07A1B6500D1 +:10BF1000DA44C6DCCCCF1C85F07B2B633B15C6EC2A +:10BF20009D7ED50970BD74177CC37CC8AF3A209F35 +:10BF3000FF04CF6FD2C6A962CCCBB05D150BEC0469 +:10BF40007CD8143F9B0DE379B35576732C63376926 +:10BF5000E3E07784AF9AAB32C4EF098BB7544EC19C +:10BF60007EF8F8313E9F00CB63692B588D05D28453 +:10BF70008A2E668771E21F0A796D900E6BE864BEA7 +:10BF800002C4AF586282799CF38B011374AD4C6587 +:10BF9000A208E337BB383D44AED3DDBB8D852640D8 +:10BFA000BDE42E3B8EBBAE6A663C8B020F3D1DDDB1 +:10BFB0002EF6D127FCBB2410C60FF06F9D7FF0F644 +:10BFC0006965C6F609DE88F605D01EE0102806FC75 +:10BFD00045A1B7F82263FB584F447BD7E0E3C7F491 +:10BFE000DEC8424903D3F3294B790DC25DCF8FECF4 +:10BFF000FD21D57FD729131E12AF5FED4238C3CF85 +:10C00000550867298B059A04CC7AD902C89BE1B7F9 +:10C010002699E76D90374990F7403D55F1B2B198B8 +:10C020007ABC2C0E532FE50F997D1BE589982FE5DF +:10C03000DF651FD141E012E82203E58DD2E0CD8219 +:10C04000FC8FE1F7298CDD2C8F9EAE42FEBCD927F8 +:10C050005641FFCDD9626007E075A57B7C0CAEFB35 +:10C06000F196C1F9B416F974545FDEE4F43201FAC2 +:10C07000C9AC90C79BD8C0ED1EAA10A707A2F4BBFD +:10C080005BA3DFFA8A99F2085C7507CA30C6AC4E2A +:10C090001695DE60BDBB71BDE664BECE945B4B29D8 +:10C0A000CDDB35D9560AFC703E7670FC3546CCDFC8 +:10C0B0000E4306A3E1519B57DE1B2F91BC3C3F86EC +:10C0C000D3D540FD366BF2AB3720B24EC4AF544AE5 +:10C0D000F235E5561FCB83F5AC4B17034E58CFBA5C +:10C0E000AF6F69C8057E5237892407F4F9478E6B14 +:10C0F0002AE8124C50BEEEC042A6C0F8665729533B +:10C100000B30AFCBEB20C3FE1DCE90175390980C95 +:10C11000D7EFA8F2A998B7B854E2E775E917EADBB8 +:10C12000102ECD7E91E4FBDA2C31C0044A9913E63F +:10C13000736E35A37C4EFA838C24FD57309F49D013 +:10C140000FFE6E42783355C475E4325A471E3BCC1D +:10C150004CD0CE3686799AA04A7C1E3B80EDD6A57F +:10C160007F79C08AEBBB97794628D8D847F2080870 +:10C1700094A11C595B2953FDCCD6B1C417FABA7FE0 +:10C1800062F17D1ACE3716179767EBBE364595AF2D +:10C190008735F9183300FEE21378F97973F05A9471 +:10C1A0009FCD90DF11859EEC5ABD47E5997FCA5718 +:10C1B000FAF8532F7FD7A910DFEAF9CC5E0BCD3BFD +:10C1C000EFD69FC5E3BA06A287B51A9DF9E3B9FC7D +:10C1D000CD9B7A8517E17E0EE68AFC1E597F51BC05 +:10C1E00042F3D0F392D328A72E7E7E12C9E3BC532C +:10C1F000AB383F640F4EB7FA3CCF671BED04316F8D +:10C20000818A7C5DAF007E15B417D63091EC02E6D2 +:10C21000615C45B138C83FB15A935FF95DF64B2078 +:10C220006F7BCBC410BFDBAA4A4415E09E932B055D +:10C230004C00F7F82CBF97813DE2286002CE1FF03A +:10C240003D322105E96012C1337B754810A1D31E30 +:10C25000947D29B4EC3AD7243E0EFE077C3F26019C +:10C26000D6E9DD2570F9E0E2F2C10CD3B191FCAC66 +:10C27000624118CFF19689BE033F841E807C8C2CCE +:10C280007A509EB678D6A4221F3A1218E9B505D77F +:10C29000EE20B905F2D6B30556B4F46477EA32C895 +:10C2A000E7B9F87A74F8C414580CFA61C871A4801C +:10C2B00017FB7508CCE3F70CA247BE6DBFB600B301 +:10C2C0007FA77E4191A4129F683FEDAA80E3E0BA68 +:10C2D000A15F2B7B99C639A78DC34C6F1C467E8905 +:10C2E000F981C44C51F865C0714CB70FAA37AA8EBA +:10C2F0002DFC5347183DDF95109BDC3D1A7EB98C11 +:10C300005DF60D2A0E13103CCE03EC4E13AD9FAD1F +:10C31000413CE7C8DCEE509CEAF00D50FEF86A0B99 +:10C32000C90FBDDFF3D50BFED401486C29E072BF05 +:10C33000E6436B09F6533F4E0C58A15D47CAB48CD7 +:10C340002EF8FEC4A62F73717EBA7D5AEB31F245EA +:10C35000CE6A4E977ABE55E38B5A79707DB241EF23 +:10C36000AF65F07A0F6BF59E75786B918E81D20573 +:10C37000E4CFA2E3D36FC3F96E7FC0C64C51E4C2D1 +:10C38000B30E5F73C2C4FEF30C6F8FF43648FB5FCD +:10C390000ED67ED2BBD3DF6583B77F342165E0F64E +:10C3A000856F4EDF32C4FC1F8F3EBEBA1DDBE5B881 +:10C3B0002C0CF15B93BE96F0DBFC80C563057EEF31 +:10C3C0001833CD8578AB4BE0788BD2EFB383CD0BB0 +:10C3D000E05236C4BA5E18AABD30F8BA5E1D02AE8D +:10C3E000478780CBA1C1DA035C5B8798FF1FA3CF8F +:10C3F0005FCDC179E7645948CFD464035C518E2383 +:10C400005C597F7E88D2EF3B43C065287AFDF07B84 +:10C41000D2EBC9C1C6BF087AFDDBF7A4D7FF3B103A +:10C42000BDE2BCBF07BD4A89DF8F5E9D8983C375AE +:10C43000287A4D1EACFD45D06BD660F3BF087ACD8F +:10C440008B36BE9539BC2ADA45055C9F2F281649E4 +:10C45000BF9BF3B91E761C7BCA8BEBAA037D955458 +:10C46000847AFBF8C34B0BFBF474A41E8AEC2F52A6 +:10C470008F2EFDDB93A4479D9ADED7E7635722FBFF +:10C48000F99741EDBB6F3B6E8C8B85EC63FBDAA7B4 +:10C49000FBFEBBC733EAF9180F1F9FC1F85716A15F +:10C4A0007EDDE541BA8C2FFABEE30E5E3FADECFBBC +:10C4B000D9050B12C12E70F4D9059955BFDEFE5176 +:10C4C000525F3F999297C9403712BB8AEC3756C1E9 +:10C4D0003C3BB1B86ACFF68F26F4D903007F01FD4B +:10C4E00023FA38A68AE0F68FC2E6D53B9769FBB4FB +:10C4F0004ADA17E5C95362908ED7B50C6E2FBFA1EB +:10C50000E9F1DF6B7EAAC39A9FEA10FAA920ED40F9 +:10C510003F15A407D14F05E521F45341FE55CD4FFA +:10C52000F58AE6A7FA8DE6A77A58F393F9D14F4634 +:10C53000FEA880E68F6AD7FC51414A1BAAF753BA7E +:10C54000B63A44F5DADB5E188EF0E85B07B7DBF34A +:10C5500064DDBFC7D7C158298B86AF1B3C26C3FEFD +:10C56000E2FA7C87016FD72A4986FC35AE4C43FD41 +:10C57000ABE5E186F22B6DA30DE5C56C8221FFA32F +:10C58000DE2986FA57F49418F2977F7A9DA1FEE48B +:10C59000AE9986FC65476F33D49FD8596E289F703B +:10C5A0007891A17C5C68B921FF83FDF719EA8F09B6 +:10C5B000AE31948F6E6F3294A7953D18E167DA62C1 +:10C5C000A81F5FB423C28FF42B43B923FF7943FE26 +:10C5D00026D0F728FFECCA6F0CEDACAE8386FCBF0B +:10C5E000C531DAFFD89D41AF378A3DF9553CDFAF01 +:10C5F00082DD5E4CF632C8B1A671D8BAD28FFBF19B +:10C600004CF81DED63C0AEC08643EA31CA1D5385A8 +:10C61000C538FE10FC8C1E00ACEF861FE4C7AFF4DB +:10C62000FD6CBB5DFD218E9FC7E5B02AABE47F8822 +:10C630006CAFFB8BF2DA67C563799D5C2247930789 +:10C64000272CBE93E1FA2172FF9BE78D655E1CAF3C +:10C6500042F797717967E25558E6B16B0E0BE8FF28 +:10C660002A7B3501D7A3FB79D6697C5AAFF991AD06 +:10C67000EC72F2639CD3E43F334DF50C269F22E12C +:10C68000F56DE5999814B9CF9911FA18C7AF9002D2 +:10C69000D1F4A49EEA722CEFAD3B07C58F0E5F1D4F +:10C6A0008F2639E845BD6A532A59B9B33F9C4C5986 +:10C6B000400F71FFFC75E72619E5F839F64AB177A6 +:10C6C000D845ACB7EC0E5A878ECFC87AFA7EAB0548 +:10C6D000F14AF291CBDF5A0DBF6291770DC2370E4E +:10C6E000F6D1B8FF133D21D6F51DFCC08EFC4443A6 +:10C6F0005E726618EA9B3D952C88FE5B1887113D9B +:10C70000FA18FA73F11FFA4B4C3287F3C07C773971 +:10C71000F909CE45D82103F11F0EF1CDF0A1F9F5AD +:10C72000BBF277C7DC54EAFFBE78A6F95F549EAA35 +:10C73000EC4DA49FF2228D8098F2D3F760DE0B0FB0 +:10C740009B49CEFCE8ABED871E03BE341559E526A8 +:10C75000F20CF90FFD16CAE77A6DA5985F786C8C1C +:10C76000C50DE5473280085C585E1A8772E03413C5 +:10C77000A7A3DFEE347B336E42989CBB27C942F2FD +:10C780008535988F77D9707895CEB1EEF2F3BCBE2F +:10C79000AEF9ADC6FC3C3633558271E63D646601A8 +:10C7A00000D642261DEFD2E10074302789FBDFE777 +:10C7B000B3CAB5328C5B6FE6E7364B5E1C63413C17 +:10C7C0002C9C20E79AC6F5CDE3FE2491EA7F06F47F +:10C7D000A658FBBE2F72062C28974FEC9DF093CBEA +:10C7E00019F613589B81FECE04B04394FEF09DD3FE +:10C7F000609CE750EB889C37BA41069B87D42E7823 +:10C80000A3F9D51B9304031E6B6DBFD8DE05F3F4AB +:10C81000D64ACCFE43C84BFC5C493D161BD889F276 +:10C82000BBA4F2A92E8083BAC62AD742BAD9F18B0B +:10C83000E7B07E15200CFDB9CF2729348FF376772A +:10C8400000CF1940DF5C3633F6FBF7FBE23FA9DF90 +:10C8500057B0DF94FEFD2EB17559D09FB84CAA9CFD +:10C860002E88E857E4F5AC669F3713FD89FBC78532 +:10C87000321543BD868BAC7758187651F5A68B835D +:10C88000F47746936FBFDBF5B805E5D6E95F7D78B1 +:10C8900023EE8716BF6C6236A87766572C0B91BDC6 +:10C8A00017B0A0DDBA68AFC91BA07C68D22DB1E17A +:10C8B0007C5D4BFD2F7E2E96F6538B9EB706664011 +:10C8C000FB452F9C18CB401E9C59D3732813E1F7CE +:10C8D0002B81EC67A6768DBD05BE2F92D89DD1CE5B +:10C8E0003DFF9AC4ED8E532F39CA90DE84F603774C +:10C8F00050BFC19F9AAD617AEC489299F009F5C892 +:10C90000DFAD3E2D0446087C7E378F099F5F0DAF5B +:10C91000F734F7E72EDA6F0ED8717EED6D161FD45F +:10C920005BD6FE37A2EF2B9FDB1D877058B6DF6802 +:10C93000AF2E7EEEEBB55300CF8B4DAC6706E9F121 +:10C94000AF287FCE6BEB31911CF2C60920B79692CF +:10C95000C8827ABFFE64DA7B50FE99CBC4EC200A11 +:10C960003EEBFCD8F232E67DCE4AF4682FDB6FE472 +:10C97000C365ED272C382F59643D59C0E83FFC2290 +:10C980008C2F59FFFAB00FB6A09C5D166CFC9B096A +:10C99000E86DD9DED3EF22DD2D8BE0E7CFF097F401 +:10C9A000FEFAD29A1CA92FDF9884FE72D60E9B9FA6 +:10C9B000C903EB4B9DBF17EF3EB74D85F14F3DFFD0 +:10C9C000F93615505EF15F7FDF763FEE8F5EB5CBB7 +:10C9D000289796FDEA3FE25818FC872573F970E620 +:10C9E000E9A79EDC027038F38E95A076E6B79FB873 +:10C9F0001580FB993DFF3715CF9D56FCF6EA34A410 +:10CA0000B315FBAE4C1B6C5F84741BB086E33740E0 +:10CA1000F855F6C33869907D454B23F0726ACF799B +:10CA20000B9E0B7D29B01E94BF4B835F5BD03E3BBA +:10CA3000E4653D08A7D7F69E38741FE44F039EAC0B +:10CA400051F004EBCF1449AF843251BF2CDD7BCBC6 +:10CA50004D5714626AF6288827D643F2BE1F7EDF40 +:10CA600002FC16F6E137B2FC1CFBCA82F05FB60B83 +:10CA7000F03916F10AF81CDB1F9FA7F197C9FDF1E9 +:10CA8000599C6CB4FBCEB18AED5BB0706F12E17F44 +:10CA9000207C2ED9F7E341ED2C5D3E0C05E7050225 +:10CAA0009F576CB2F7E664E4DBE71DAA8BE33930ED +:10CAB00003CACEEC3EE76640279F9A7BEE4038F4EF +:10CAC000FCD62AEF80EF8B7EFB36F1DD997D7FB6B9 +:10CAD00020FEE1274E98047976E1E74D06F9A5DCC2 +:10CAE00006674B58CFB4770B31653DAA87F047F9FD +:10CAF00043C087848FC0CDD31594BF81145AF7D219 +:10CB000000E78FA58103B70A63FBC3BD3959D4F58C +:10CB1000D605BC0A4588CF0FA721FD0D844F7DFDAA +:10CB200032AEFF32287FC2C8BF91F59702BFE2FE46 +:10CB3000A81F7E0307FE88E99936AB24802D740672 +:10CB4000ED04677FBCF7C19FEBE76F6B1FD747F022 +:10CB5000BBDE5E87D350FC3ED4FABE2DFCEE4956B8 +:10CB60000C74A4C3F1D457D1F5411BCA8F8908C7EF +:10CB7000CAE919C3FBEB33132B553385BEF9AE0D50 +:10CB80009A48CE9F6A07BB5CE82F2F96E2396E94D5 +:10CB9000719ED3E4D4D2FD07C6A25C3B75F0258D0F +:10CBA0002E39DD2FDDF5A145D5F443205C3E0F7015 +:10CBB0002EFC9236EF65AF44EF6FD9AEBF45EDEF77 +:10CBC00033C9FB539CFF679D66A642179F054D51D5 +:10CBD000E3191E4FE6FAEFC2BA63271D8DC77D41E8 +:10CBE0005C8C82EBAE5DE37D1BCF45D537CD74FE0B +:10CBF000CF24CFA75628AF8D8D51D08F571B378F9D +:10CC000029617ABC2E024E92AB94CEEFA4E4D242BC +:10CC1000BEA70B18CE7FCD4010E1F306BD9B857AF1 +:10CC2000E983719F98719D7F8DB023FF2AB1B5690B +:10CC3000D0DF5F55C153A344DB1F18FBF7AD36317E +:10CC400025ACFFA5D69E0F703EEC5FED0CED32D308 +:10CC5000AB7601E5C9B26D66DA7F2D836D15C2ED45 +:10CC600093C7EC0115F29B7F5D7D07EAA5FFDC66AB +:10CC700065781EF1DABE95DDAB502E3D2A30F4A367 +:10CC8000FFE74BD55FA25E5EB8155607F264BEA300 +:10CC9000E7496C3FFFB94C560BED3F178293703359 +:10CCA000DB9D129A84FB90EEDDE91E95FA797129DD +:10CCB000F67BE63907F57BE65FDFA671CEFC6B2CD1 +:10CCC000E9357DFE606F2BE17A1CEC6DE5021F906B +:10CCD000BD1D96877116639ED717BED1641ECABF4D +:10CCE000C59802DD2FDE1FEF45FF4A583DEA6799E0 +:10CCF000B5E7E71EDA7FAB1922ED9D4219C88F8B8D +:10CD0000DB8DE37FA3C9BB65969E79BCBE3F83F3F1 +:10CD10006D27B573A668F4AA9547B6D7EBC7A40CE0 +:10CD20008BE887B75F6A6595D1F8204DEB7771FB8B +:10CD3000D7A38CFD71BAED3F0EFF7EAFC0E340D8A4 +:10CD40001E3BC5A35558422313816F5FB0B005C881 +:10CD5000BF1571A1910930DECB9ADCAC88813C7C97 +:10CD6000CFD0E681F531CF6C5D6710AF4B5EB4D3A9 +:10CD700079CA9217DEFE12F1790A610C183B95D23E +:10CD8000F9E5FD4007A71E333115ECB525D690FB1C +:10CD900051D4537BAC6C07F2F7ABAF93DE3AFDBCDA +:10CDA000551CEC9C7A4910A8C1D67F1D6A09CBAFEF +:10CDB00074621C8E576CC37DC36153A006C6AE92CD +:10CDC000BC6B9EC3F51D36D33EE3EC5C968FFBCA6D +:10CDD000B32CC3A312FE95B725285FF97BB3102DA2 +:10CDE0003EC9DC0B427D02F041EFF54C8154EA1D57 +:10CDF0004EE94A4BE52894BB26191657407E02B2ED +:10CE0000DBCDC91E361FD29589CC87F063CEEB2EC1 +:10CE1000F0D79F00A5CB1F51D2B0DD8F52CC34EF9D +:10CE200045A9DEEB53483F3A65B22F343A55F7F146 +:10CE3000799E17623C35189FD37BDF9D08DFE51F85 +:10CE40000A4A783C43643C6895A4BCAD14D27A4944 +:10CE50001EE5C9310CE17A563B773F3B57894F08B5 +:10CE600093CBCDD532C98FC66A17A5EBAAF39942E9 +:10CE7000FE350FE54DDAFAAD052AC507214FE38FE0 +:10CE8000D559EA453B0FE784714126A78FE8C8EAE8 +:10CE9000AA24DF94CDC9681F6B72AA6C3EA46627D2 +:10CEA000878FC9594AF0B16879A97506C113DAD3D9 +:10CEB000F7AB537D77233C6C59971AE4922579BCE4 +:10CEC00021DF0F5E3AFE77FF4FC18D119C1AAB6DCB +:10CED00094AEAB2E2278D5577B29FFBF00B7D694EE +:10CEE0008908B7294CB185C3ADC4901F106E8F005F +:10CEF000DF2487F30DC011F986C5787646597F6423 +:10CF00008AF11028A81FAC6EA554FF9E3880DE3E23 +:10CF10009F2268F1B0BE1A338E23737F0B4B565994 +:10CF2000D6A43EFF2673A94CC13CF22AE2E5680C68 +:10CF3000C16EF9FB76F21B9B64A93B5CAE2DBF4131 +:10CF40004943F965AA7A9C9D088B4733CD28B52BB8 +:10CF500004570F9D53D66A7AB3FE02FE8C7CD05CD8 +:10CF6000AD50BA5EE3878D1A3F6C423C631C8987E3 +:10CF70009F6BB64C67A417FF0FE4F93E3EC4C2E3B3 +:10CF800046123CC19019F04D3252A13444F1BF47D2 +:10CF9000AD8111B9143FE545FA4838BA8AFCC78C0F +:10CFA000055DE84F4BD0E0C65E1996302B9696672C +:10CFB000E67A879978EA37A33D1E09D75ACF411BF5 +:10CFC000EEAF079A4FF1070B051CEFFC2C42134BF9 +:10CFD000BE3D78B41CCF4F5B1CA457533D9539E838 +:10CFE000DF63C7AC449F4E8F4F981F86BFD401ECC0 +:10CFF000BA55A9D77E8C7CDB8DB20CE8F0C1D6E1A6 +:10D00000768473B339E84279D79CC0F587520650CD +:10D01000B8ACAFDD9F3439185768E4775DBECA53AA +:10D02000C71BE85797AB895719E95C97AB2FA570D9 +:10D030007B6D516AE9799C4F52EF56E2C348BACFF3 +:10D0400093A794F992510F304F13DA6B6833A21DF6 +:10D05000F7A110E0F4CEFD5367BB7277A09D03BB30 +:10D0600002922B2AF203E1A9E7B56F9231DE95CB4C +:10D070008735B699365C6F03D0111B85FE6C850031 +:10D08000BC01E887D179A047E38F224A75FA74A7DB +:10D09000E61AE2044D798744C4573DD811144F0C69 +:10D0A000FB3B278C271D986C437B4F327B0EA39C48 +:10D0B000EA891583A837EB9D336D5EF4DF241412E3 +:10D0C000DEBF8C2DCF192C6E09EC16F2DBCA4E0F89 +:10D0D0003B8EE330467E5B933C9EE13E71B7B333BB +:10D0E00006F72DB1A9A2615E8B527DC353C3F263D3 +:10D0F00070740D5FD8ED6EAD9FC8F17E90AAF92DCA +:10D10000B354E60D3BB7A8D2E95B51D95561FCBDDC +:10D1100066C434867117917C3DA0DCDAF9FDE456D3 +:10D120006D4E80F0658E9417C920C79D94AAA28C7D +:10D13000F3569AFF2581E8EA4A840373EEB86087C4 +:10D14000FC685814FA3A7A691AC56B5ED033B06B32 +:10D150002E203DB3B988DB239A9EE1FAE96C8B83DC +:10D16000F4D3D9B995144775B6254D41BA3BB0E112 +:10D17000F2B1088F79BD8D4C81F9CDEF9D4CE982DC +:10D18000D65F525ADEDA0644CE58CDFAF91B664114 +:10D19000BB138F98282EA83B30E14C15E4BB5BAC49 +:10D1A0000CE38EBBB7DE93837EF16E1807EDABEE1A +:10D1B000AD2388BEBA016E946F30D6C7786113E094 +:10D1C000A59C313D68D38BF5E7BD6E6A8B662795CC +:10D1D0006FB47AA39DEF5C286F8D6EB7D5E2AFE98F +:10D1E000F85FE5288457F107AB7270BD3AFFAF4C8A +:10D1F000047984F0FAC0CAA2F9E3AF4EBDBA227531 +:10D2000022A6DE159832676254FF5A1FFDF3714F54 +:10D210008860DF125E7C71371BFCACDC8F7942B317 +:10D220007F996D80F238ADBD1CBD7C49CBE7871E70 +:10D2300060787FA1B214895EDF4F9B18ECA705DCF4 +:10D24000FFDE4CF1D0FA7CC04E253A66800F942F59 +:10D2500073357F0FC0FD260B7C3FF1BA4940FAE8D9 +:10D26000A3275F1CDA2D42F30D6B7643F9DF0FF332 +:10D27000FDD9C2DE4D24EF84E6319B27C3F77B5EE8 +:10D2800037939CAF69BA7CE3ED80DF2FDE30517EAF +:10D2900041AF9DEA9D7CC0B3F976A8D7F30733D997 +:10D2A000E15F1CBE9AE21E4F9A8D7E82A9699C8F17 +:10D2B0005FD2F8795E6F33D91F7AF9BC863916854B +:10D2C000E874037D9F878736785F8195FD7B711EAB +:10D2D0009EE730BAAFF0D2C3B75EBF86F4DA78B259 +:10D2E000F7E7AFB77AA2C54FBF94AA18E4CFFCAE58 +:10D2F00016EA97815D949CAAF5172647E6F7261152 +:10D300001F30596518673C4F932717E6B7D56C90C7 +:10D310002727EDD1FD20AFA7F27DD4BCDECB89BF9E +:10D32000FAAFEF87F47D9E3E6E17E7C7BEF56C9EA1 +:10D330001C6D3D7DEB984AF54F26441FBF471BBF30 +:10D34000BB7A01F3825C2AB7423D278E7FCFDAA2F7 +:10D35000425C4742A210B6AEF9AD8B99376C5DF3D3 +:10D36000B7CEB69487F5DB8787E5FF5E2CF5E1A1A4 +:10D37000277509E161556AE931E49BF2E62BC62283 +:10D380003DCE6F6D24389F307BDC285F3F69BD2721 +:10D39000CE17759E8AC18F30BF55C30FD8BB85612C +:10D3A000F8D1F112D9BEFBFDF95F3E80F2E7116EB4 +:10D3B000DC0C04AF7E78CB8D0EB7188D3EBB41DF01 +:10D3C000FA086ECA0B4791AED73B3C48D703C36FF0 +:10D3D00034F30D06BF01EC57B0774C69785F017DDF +:10D3E000B4780ED9CAE96028B8F58DABD14171F493 +:10D3F000F514A5E97450C55460D8E396A1E8E07E21 +:10D40000A6DA0659C7053A78D84007459BD7131DB9 +:10D410007C8AF6CAA8FEF83F6E51E3A6E0B94F93A6 +:10D4200089CE958EC7A8A9B7F1FC3894C7C7E3FC8D +:10D4300037E2398D9E5FB87344DCECB0713F690010 +:10D440003844815F51DA00F493A7B28249FF3CFA75 +:10D4500039618E7EBFEFEAD4E2A969A83FFCD1FD15 +:10D46000B57AAACB6B53BCF3C23E13F5E771E7B0B4 +:10D470002F0350DA9CEA9B8E745197F0F33B511EB8 +:10D480001C3F2E90BEAD797FE528D46B917602ECDF +:10D490003F1BF0DC73A529D64F76A854B99DCE4129 +:10D4A0005589ED2CC47D4AE5968F46A0DFB08A529F +:10D4B000A6D9A12B4D977A9AC82F5BF9149E930297 +:10D4C00091C8585F6295746E0A82B014F39B1DFC7C +:10D4D000DCB54AB2C9D6B0B884E51ABFD45797FEB6 +:10D4E000F223F443DB5426A7627B2E3725C6EDAF2B +:10D4F0007FE03CC3F4BDC5EC933DB80F155829F24D +:10D500008559F2D1FD27B32B799C1A8687CA347EC0 +:10D51000DE6EEFE868C885F6F6BBFE20A31EB4C237 +:10D5200038E867B3654967C3FDD5E6E420DD6F627F +:10D530007961DFC1AE721640DEE00780F90E621736 +:10D54000BE2C785C5F223DD67078142188207D67E0 +:10D55000EEF03694CB45529D09E38E66DD3582F2BE +:10D560009BE77C33B22B0A3DCC7A655D27DA33B377 +:10D570005E499F83E707B39C233FC614B60BB618DA +:10D5800068FF9AC0824D905E657B9CE2195FD3FC78 +:10D59000631D980FD38B1D1ABD819D337D0FA4B3DE +:10D5A0006C7EF3DD057DFEB4C871376B7CDF610EE8 +:10D5B000A65C8A7400E3E03A7EF64AE0C7A0FAD996 +:10D5C000EDC1C00D63003F77B01E33C2D1C7643ACE +:10D5D000F7D0FDBAE5CCA3E519ED4FDFAB30EF4056 +:10D5E0003A89ECEFF610EFEF671DD01FA4771CEE21 +:10D5F000F93754CBBEA03CCDC1C2FADBEF39E460B1 +:10D60000FDFB8B84B347B299D430B8028AC470B89A +:10D61000F7836F7CD9756CECC07CD6076F3E8F4862 +:10D620007C7C8145C0A76D69DE5F23BFA969DEBD33 +:10D63000C8BF15B61EB70474732CD9B71FBF2F35DA +:10D64000F97252011EA7B37DA352102E9DD1CF5F58 +:10D6500023F93BAFECF463C83777D4480CF1BC76C0 +:10D66000DF278F215F9E36031FC17EE0B5559FC423 +:10D6700022DD2C01060C97271F548D20FBE9ECDEE0 +:10D680005183DE1FF940F397746A7CA2AFF34E64B6 +:10D690004018EFCEBD0EDACFDC5965BAB0CF427A72 +:10D6A000BFB38AC78730A973ECAD06BBB36EC07E2B +:10D6B000701F11D94F77B56F3BF1BDE49B8476F7AE +:10D6C00089EA05DB51BE44CE73A4CB77228DF4DB0F +:10D6D0006C43BCEDDC9685DBC3F950AF5F3B807CCF +:10D6E000F58CD2CE016D7C3CA6FCA0D83989EE6BBE +:10D6F000D28F3D64FB5008A387A1C6637957792F69 +:10D70000C805DC7FF944E64CEDDF5F643DBD7F5723 +:10D71000D595ECC4045C9FF7FFA5A50C3D7F8B8BD2 +:10D72000CFDFAEB5D3BFDB7D7E8676A1FDAB78B211 +:10D73000133CA3B8FFE11F9A5DC09CB05E6430FF4C +:10D7400066EFFFC67A61608A17B66FB5468D2BCA41 +:10D7500074491C2FC143C5B628F3EBD75F48621745 +:10D7600053CF338AAF1FDD64E4EF1A1943FB9AF2FB +:10D77000AA5ADA673782FC407D10399FE34D8F2A21 +:10D78000A807EC16BF827ED1C691A9B96BA01D482F +:10D7900035F2FBD863FC8A14FE5DF307D9D7F81580 +:10D7A000DCDF368EC8A0EF7A7F8D0297B33A5F3404 +:10D7B000C2BEEF79F28B795C3331AEF4ADC0F45870 +:10D7C00068B7632D0B99DC8C1D74678CC67DAEBF6A +:10D7D000DE42E77B8DF962FA5CC8C765DBC83FD6DD +:10D7E00096109A85F76B554122FDEA4F50AE8D4554 +:10D7F000FFEE9AB44E947F07EFB6D07A9B27F3FBE7 +:10D800006AD6291FF9AFC4FE57300FEAD51DBDBF38 +:10D810006EC57702D4A3B09F45BF21760AF268C7D0 +:10D82000F4B376DCCFB930AE0EF0B1D51CA4796D6F +:10D83000A9B152BF5BDA2C65D1F0F779BA44EB0A93 +:10D84000085D141F9CC4827684EB83D3676ECE83FD +:10D8500076B9794CC6FD7C73C1596DBFE935F1F3DA +:10D8600028DD8FC8ECDA79964D3BA7B285C7173E05 +:10D87000EADF4BFE43C78C204FA78BE47F8E9CC70B +:10D880000A17A77BC7D4CEE9A8271C852213D0BFCF +:10D8900099C7045C973C7D075DD2C8CD6703B43758 +:10D8A000517BD90BED0B797BF409C917D9BEC2C5E1 +:10D8B000E30CD7A31F0ACA03668F702DCC23708395 +:10D8C0002CA84A5FBD7A17D7AFDBA1FF10C9D100E2 +:10D8D000ADCB9D1F0C21BDB92B44C2D3FAA2E3747A +:10D8E0002EF060A1EE47F5D03CB6D61C3980F6D7B5 +:10D8F000D67B19D9495B518642BBAD37B0003F4F4B +:10D90000621928DFB62CB45C4FE7F905007F81D29D +:10D91000A8F39E9D6E237CBB573F18C2FBFB311EB4 +:10D9200020D45C4AA3D66F4CE770DA620EA4A37FC2 +:10D930006420BA287371BFAABB4AB3AB98DF85785D +:10D94000DDA0C187DD3A9EFB1724AF121EC7D5A705 +:10D950004FB81F03D64771AD497516D247E28CD038 +:10D960002C5C5762BE855D938BFCC5E1A68E117958 +:10D97000DC190BB4227FB65D924AF1A4EBC4800B94 +:10D98000FDCD6A8985CE930F1689B3F05D848D75C0 +:10D9900016F243409EF8C5EF1DD686FCE6985A5213 +:10D9A000B6A010DFB9B0C808DFDA02D98E745CEB1C +:10D9B000156501F21B4AF5FB118CDE37186732D969 +:10D9C000F3A17C7BBA883E5AB65D1088DFEBBD259B +:10D9D000FEE1F0BD5E4E16C2FD002FBBB8DD7B77C9 +:10D9E0004EE9CB2E4803DE07FDC3158E4B6912E3CB +:10D9F000572CE02796851660CC4D5BFD934771BD93 +:10DA0000EBC7D9E8FE6CF60A7F19CE37F6128B8287 +:10DA100078DDD19B349AD6576751909F3709816B37 +:10DA200091EFB7DE7D4845BFBAFD6327C60E336769 +:10DA3000D7DFAA317ECC59688938C76222CA717D86 +:10DA40005CE75B21A2A72EC1F79758F2FF1434E5DB +:10DA500027533CF32484E78629EFE6CF8B4217D087 +:10DA6000DE993A1EED653134692CCA29AEC7982477 +:10DA7000A787E3775376C63BE867DA560CF3C7F11E +:10DA8000AABA6FA779798FDC8F7695F3D8C9AFA33F +:10DA9000CFF34DD223B1C71C21712CA64B66907DCC +:10DAA000165E0FE4FEC61CEFC72EA09BDD355CEEB4 +:10DAB000B7DCC5E83D0AFCC90F836F4B014869FE1E +:10DAC000048D42F50A64F2A3AF13956008E139D6DC +:10DAD00046F494C67C24D722D7EB38D67837C61DB7 +:10DAE000393CC679F66AFC8D3F522A9D57A025CA5B +:10DAF0002CE973ED28FFF68C57D271BFFD6042749C +:10DB00003DFF5E3A6FBF5B886E9F9F4BB7737D0989 +:10DB1000B232348950C528AE0FF2622A9DDB909351 +:10DB2000DB2A72B9C0AE63A4F7E2C675D93D61E3E2 +:10DB3000ED49EF9B27C61FC46BED98DC13AA81F556 +:10DB4000B701D5E27DEEB86C0E47A7DA0747AC2FD8 +:10DB50006BEB023EA81955884094A93E2BB5D0B96D +:10DB6000084843F51BB10F0EB15AFD2D459280EFC9 +:10DB7000900C036008503F61BAC5708E22D71D51CA +:10DB8000B1FC7E1353128BFAC67F6C1C0BAC81F177 +:10DB9000E3BD4678C7AE786125DAE591748033B885 +:10DBA000D02F868ACF35B64BBDBD1F1F103C699E56 +:10DBB000009A96B7D80E0B00A5A55DD2E36349FE87 +:10DBC0004E3475AAE80FC580A47D30FF4B9F7ECBF5 +:10DBD000BB0BF22D3ECE67B1F92FAC44BA4CC8E076 +:10DBE000787A077DCB00E74799FC778CDB51AB4413 +:10DBF00005F1B12D348CF47823934A114F8D95475C +:10DC00004494EBCD7B99471090FEFFCB1A3EBFDBCF +:10DC1000D2F9390D9314927F929BDF1B6D2E101D4C +:10DC2000285F0FDEFD02E9BDC70E880CF9BFE4775F +:10DC3000C71EC1F7815ADEB152BEE5F54A921B3FBD +:10DC400087766A14FFF9507A39B27EDE921D029E01 +:10DC50004FE42C08BE3E12E5B35FF25C83F858D067 +:10DC600049EF872885FC9CCD392344EF8728A8D528 +:10DC7000C02655FC5ADAC2CBD9AD89B48F1A63EDF0 +:10DC80006AB80EE6F7E8D312437D69B206D3E743DC +:10DC9000BFA6179DA809FAED8F1E9D114A47391E90 +:10DCA000534961D0FDE677229DCB59F70CE5F72368 +:10DCB000A1DF84A91C96767FDA0194976833E3BDCF +:10DCC0000A87CAF5DC0629E0C538EF0D2B7C161C47 +:10DCD0009F69FB97C625E54F229C4F6A7A8F552E88 +:10DCE000A0774CDC1ABF38AA5871B47D56AB2B868E +:10DCF000C7B73C201E40FE707B19E90FB92A181ADD +:10DD0000A5E9659CB8BCFAF946D42FCE0A91D6B1E4 +:10DD100041EAACC1772536AC60728DD2BFBFEFDA75 +:10DD2000BE2ADD4AF36F451CA7F4AD835C7220DF89 +:10DD3000DC0BA2AFE3611C7762DF3A62F475E47733 +:10DD4000515E9FC7766FF0A2E6B1595BC7A6749982 +:10DD5000524701681A677F79BFC6F101BD2B1300D6 +:10DD60005BDD44F7D182D7615E794E64FCBE96914B +:10DD7000BFFBE535BA8AFCAEB0B0717291EE389E49 +:10DD800081EE34FB09F8CE86224054BE213F869FA7 +:10DD9000D61F498FFF74B9183E6FE83FB68109144A +:10DDA0001757C19492F4FE72916972D1C6D410CA09 +:10DDB000BFFF69B9087290E4620BAC3409762AB1EE +:10DDC0001D4D77A31ED7E5E144C4C914645FDB0D84 +:10DDD000254EDA1751FEB247FED082F191EB44EDA9 +:10DDE000BC4B830BBAA1102E5FBB14833E7D187F02 +:10DDF0008175ECE948BCBE00C6DB5C366C1CEE2FBE +:10DE0000ECFE17C93E7017F0F81577153F3F77E421 +:10DE1000CD7B32FC5E5C653AB7D32B75FAABF2BBB7 +:10DE2000709C0DD82FCAE73C0BE9CB475990EB43C8 +:10DE3000CD3EDDE6D2FC241A5D45F249A47C9AF081 +:10DE400087E41294EFE98255C6FD1CEAE783A946F0 +:10DE50007D8DF4A2EBEBD6CE3509E80FCBD5FCFDDA +:10DE6000B936639CC365195C9E99D3F93CD68995F4 +:10DE7000B4DF544B44DAC7E9F477418F47C031121D +:10DE80007E48A86B27517C0CE5E38A7B18F2EF36BD +:10DE900020597CE32D2E5DD1E2A6658273DBCFC4D1 +:10DEA000F1282FF77494DBD1BF2EB86DD7E2FE7046 +:10DEB000A3C04228373716BF4971254D55D0332CA2 +:10DEC000CA992FCEB68CED8F67E063DAAF3A546B08 +:10DED00027FAB582A11D14B7D01438348B713B9644 +:10DEE000615C4A53FE9A8C4528DFF34B0B11BF6DE2 +:10DEF000F5168A9B91F359543FC2E7B88F213AF93E +:10DF0000767ACCA1EF2F2BA2EF2B4B33F8FE3628DD +:10DF100081A882F964E58B1EE4FFAC3A4BD4795CAE +:10DF2000A9E1293383DF0F6BAB3F944EEF668995F0 +:10DF3000013618BE60FA6B52C3F03179007CB874B8 +:10DF40007C483A3E1266131F76758A5CDE925EDB71 +:10DF5000C0E4DB503FAA9516B2631BCD7C5FBEA325 +:10DF600040E30BD9D686C4F66DE93A6E8948F7705E +:10DF7000B28B44DA273A2A9EA7B8A64759CFEB2896 +:10DF8000EFD4027E7F3EB2FD1D19DC7F159414C1D3 +:10DF900043FB698E47C02BCD67EB88D4B6703E6DCE +:10DFA000D5ECE8561787E3D6FA87894F2F769EBAC5 +:10DFB000DCAED5ECE8855E9F05D5812A944E4B47B3 +:10DFC000FDF9047F878A999C64977F8A4DC2FCB2D1 +:10DFD000ABB27C951961E743B2B752C47A57E3BB41 +:10DFE00042D0FE9320BF0FFA49F0D7C5F40E978FA9 +:10DFF00011332F649D023139C8D09D907749412A51 +:10E00000772D80B924D0ED48CADB6CA0176142A7F8 +:10E01000ABF9FD8B6E7C5F92DE9FE4EF4B7EAEBD75 +:10E020002739A6755DC9A3389E22F950667C86EF14 +:10E030004BE2FDE7A277292EFA14C8DAA6048C87F2 +:10E04000E1F7B7E5FB982C4EC6FCFA128C7BBEE7D5 +:10E0500055AB764FB2730DDE7B795C8475439B665E +:10E0600009F4FD702C6A102AC3E878F7159D7178C1 +:10E07000CE773A78CBA0FE63BC3F48F3CDE078DAA8 +:10E08000E4584AF7CBE639436E6C7F60CF534F6E4E +:10E0900081F13EDF67A3F74C363B96BAB1FCF347FC +:10E0A000DE76A3BE38BDEF6D4BB4F3C92552701AAE +:10E0B000DE23AB50E3D91A987F7170B685E24F76B4 +:10E0C0001DA0FB694B649F05FBAF68DD43F9AB7690 +:10E0D000FDD98DE5EF67703D713ADDE746BF445EDF +:10E0E000AB352482FED93DCCBF28EA397B86A8CD4A +:10E0F000FB55EA7FB3E3D5438897D38F58C9EF76B2 +:10E10000E091DF51BFA7F6BD48F3FD7CF7DB77A0B8 +:10E110003D5DC19807E5F969BBE6D7B375C685EFE4 +:10E120006F5FD5E0A1E74FC76AFBE0AC21EA69E782 +:10E1300031CC09F0A7FB039D7178BFF073B3CF8298 +:10E14000F0588CF080B418E080727F7150A0792E66 +:10E150006E6DA3FB568BF772FFE0628017C1A5F5C9 +:10E1600000CDFF5806971BA7F6FDC54DEF52ECB545 +:10E17000D2FE595FF762A7CF8DF0D1D70B70E0EBDD +:10E18000DE7D71789AA7E3A9F5CF34AF8ABD7C5EB6 +:10E1900015BBF83CE6ED053C39114FB309FFA7F676 +:10E1A0003105EFC174EF79FB33B4674EEFB32968E3 +:10E1B00057E8F3CA02711B371EF988EB63B6572084 +:10E1C0007DCCA44E3ACF5922CB32BE4F70A13C60D9 +:10E1D000097079DA599209E5CF3C24D2FB964C0EAE +:10E1E0005E8AFED53319FAF946A71BFD62BBAFF074 +:10E1F000137D9E8CD5E02D75BA317E6673A6EF4CEB +:10E2000038BF9FFEF0C54B71DD2B4D95BFCBC6715E +:10E210009EE2F1A1E78755FEF5019AF770C3796395 +:10E22000640A708BC3F3EF7C91F9E85EF2DED7628B +:10E23000C2CFA14D99DCEFB6D9F101DD473C8DEF9E +:10E240003CD27C8214A735D25BEEC673BE93CCE978 +:10E25000C373D9CF9F788DE26DBAD375FF5327D59D +:10E260003BB5F7B5444CCBB5787816B885E418C003 +:10E27000B1C1363E9A7CD4EE1705F8BDB133020821 +:10E280004CD4138FE970AEB4CC349CEB70399AB592 +:10E2900035B783FC2D81E8F7CD22E56FDE4393E9A6 +:10E2A0005CF91C8B7EAECCB438B995A6188ABFD960 +:10E2B000ECF805DDBFAD52AD32DE5F39AEC9C58FBA +:10E2C000B4F716CEC7C4A922D0CD4B99BEE199139D +:10E2D000FBDFC32D6F5EE246F896E3B9076D6A7601 +:10E2E000DC807189140F3A85B46D88E067D6CB5B0A +:10E2F000797902CF4FC9DCB31EDFC344F8723BF516 +:10E30000495E9ECBCB7FA295CFCF281D9F49FA8532 +:10E31000D13B4560912574DBB80A8F068F3EB84823 +:10E32000AC5BB7ABA1F2C24CC6E336324AA7E27A85 +:10E33000A058E07CFFFDFA03BCABB6C4FF867E6C40 +:10E34000FF5DFD04492F893E7CE30ABE79B8FE7B60 +:10E35000BC84C94D09DFBFFFEFDA7EA5C92B9E44FF +:10E360003A8C1789EE75BEEE7E64D438DCFF5B1AFA +:10E37000EE0EA1DAEC8E2DB1A4C3F7730A3F3FB9BC +:10E38000EBA14D86F755F534F21D5BFD1CCF32DC59 +:10E39000783EDB92C9E5514B669FFF0DCFE546E223 +:10E3A0002F0ACFB7A452280CB7D359A588F187F903 +:10E3B0001D367AC7F712068202E63F9A8544D4DFFB +:10E3C000635817E57F802080FC38A698303F81F5A0 +:10E3D000B8A5E178FE1C5A8B76DAB1645F13D2D906 +:10E3E000978F747E2040F9CF337CBFE982EFEB3307 +:10E3F000F93EC8096621D2B38C29D0A1E898E18AF8 +:10E4000026F72FC053964E859FB7DD2C791F223AF1 +:10E41000665972B7A30FCEBA3C58A4BDBBA4B7FFD0 +:10E42000ECE9A786D17B437DEF850F7A1F785ED517 +:10E43000C2879E983048B9266777D7046E0BD7F706 +:10E44000ED1A9C9FC9D4F5805FD70764C7FDEA66C3 +:10E450006E3FEDBEC2BBE67194B7AD26DA4F9F6C3E +:10E46000FD0BBDFB78AE94915D37D0B82723F07ECD +:10E4700072E75319FCBC2360D0EF0B9F7CE9D2F00C +:10E48000784B00B3923C89BFC341783FE451AD263D +:10E49000A4D252F2C75858258F53C1F90EC777B886 +:10E4A00082943A5927A571AC875299C9E49F4E646A +:10E4B0001E4A935929A5A9AC52E0F69D9FD20C168D +:10E4C000A4340BED53F4F7B01E4A15BCF11916BF76 +:10E4D000310C4F4C87E37BBCA5FC7B447C9084785B +:10E4E0009C10459E47C40549ED5524CF312E684404 +:10E4F00072FFF71474F9BD39B3E43D94A72F657A20 +:10E500008F617AF8D9DFF3FB15EB05B2AF4FD8670F +:10E51000581440DD33895E7A07441559E94ED0EF2F +:10E520007375FF3FFEE871C208CC16F3A9F0F81D21 +:10E530006673E6E379F11CADEA1CED1C648EE60718 +:10E54000C1F7CDF83D3D0FDDB79FA39D3FCC89F0CE +:10E55000BF30BFD5E04751F11758C71CBF40E70691 +:10E56000736266BCDAC506A693B0FEE8DE5F798406 +:10E570001F6A487F56447E6E647B9BC06CA9F89DE1 +:10E58000D3D3333F54C8AED3FD5940700AB56BB0F6 +:10E590007E487E21FFD5DE70382565F17DABDD7FBD +:10E5A0004D5CB47797F4742ED867E6C4FEED6147EE +:10E5B00098807CAFCB619DCE7371638B7C946F0927 +:10E5C0000C1697AABF77DDF4809FE1BCEDA155F44E +:10E5D0004EF5BDD92AF96A6D0501BA1F10931F7057 +:10E5E000A951E6D784EF3A037F35C51ACF4D966718 +:10E5F00071FE5F9EC5CFB50F5D925A82E7D9EB14CD +:10E6000091EE0DAF53F8DF2D589735D43BE536C367 +:10E610003DF9B549DBE81D20FB57DB19DA93762974 +:10E62000FABD94DBB4F13769F537276D233F49C351 +:10E63000087EBE1F59FFC08887E9DDC7C65CD8EFDA +:10E6400062FA804AFDD78F78B80CDBDB428D86FBFF +:10E65000BCB3B3F8BEDAB697D3A329CF121886F4A9 +:10E6600020F929BE40AFD738C079D28D595C2E36FB +:10E670009903744FA649B3879667C56D407B675D64 +:10E68000D68EA3C8AFE7F2189D37DA434FD339824D +:10E690002DDFC2EC82F6770230BEA32048F8416736 +:10E6A00053C840B7317DEF6C98FAF75FF78DDF857F +:10E6B000EB6BCCF5D3F843ADF74A8D4E1B35FDDA45 +:10E6C00068379EA35568F0BE5E5B97ED1546F26411 +:10E6D00010B890BD77E3D61137A27FCAB67F48380D +:10E6E0001AEAE7B2B2F868FC1229FF9D0562C43B42 +:10E6F0004A02CDEBDC5E417B6F91BF63D1670704BB +:10E700002DD8EFBF6D2D3F782DCC6791CFE9C5F89F +:10E71000C9A7B6EEA07BFA8B5F34537CC2C8AED9D2 +:10E720005C0EB6F27712F5F78D2E69B51ADE9B5A9C +:10E73000C2C2DE5184F1161F3B798CD13D63E37771 +:10E74000FDDD8066FC10254E2DF2DD8187B222DFD3 +:10E7500023D3DE1D2888EEA7897C7760575024BD1F +:10E76000B11CE358691FB0AD04F73D55C704F21B57 +:10E77000F4E743E5B13C73585EF0103DAAB131DED9 +:10E780009D51F8E9BD6C4E2FBBF1508DECFEEA0DAA +:10E79000A12C4CEB189E37D5AE90643CD7AE0DC47F +:10E7A000D0FD925A590C60DC48766C890DFD8F2C97 +:10E7B0004194F11EDA34D354BAF764B9579A40EF52 +:10E7C000B3EE58D489F7EA6A5D12433ECE4EE0714B +:10E7D000042C5DA4F769EAE43713E6E03ECEC9EF06 +:10E7E000E9E5C82CA00868D779199E2FC366A53221 +:10E7F00004A657B6E00DE17B576CB255DEC9DF9930 +:10E80000B971DC24F203D3CF81B669A1DFE2385EAF +:10E810005B29E2FFAA7B93C91E0CB84C0CE3003FB6 +:10E82000CDE2E78296D892D0FB38BF590EF2ED06C2 +:10E83000543111F1F07ADBDA99D7C0777340A278BE +:10E8400087FCAF6B6FBB06DAF7B459E8BE850E27BD +:10E85000A54E32BCDFE05E6DCC5B22DEAB9058583B +:10E8600039E4DFC179905D55C642E171BCC95E7E75 +:10E87000E82E3B894EBA813FE9FC43CBBF8779A0A4 +:10E88000D776B39FF0DEFEBE40FED5836DF37248AF +:10E890005E3A966EC7BF635275949F630E249F9F26 +:10E8A000CE52F47712ECDA3B1576F47B45D2535D09 +:10E8B00035F3609CA12DD011331AF17BD8ECC1B097 +:10E8C000E67A4D3E4A4E2EC775BA894CEB23E8AF27 +:10E8D000DEECC9F743FDFAAF4DDABEF1F48D485FC7 +:10E8E00092ACD0BEDA9CC53C680E9B933B336498D7 +:10E8F000C7E8172D1EFC7B07D39E2B8847393FFAAC +:10E90000B55924DF104E882FA9CAE2413BD95A9548 +:10E91000EC9126603D27D1E559A785EC21A9CAE1F4 +:10E9200027FBAB6D924B09937B6BAB658F64C6BFC6 +:10E930008F63A374ED00F23E27412C45BFAB45B376 +:10E9400097D3B475A5653B284DCDE6F273BBA4CE35 +:10E95000A4F77B816E30EEE6C06A4EDFCBD36DA4A8 +:10E960003797BF3E3C6D30FFE093D52E4F1E0076AB +:10E97000DBEA72F2DB16AFFAA811E96E79AC4D460C +:10E980003A34C58DDC3C15E9FEF766BAE7591B3B06 +:10E99000499913D69F29AEC885F030896A06D2738B +:10E9A000C163C11BA5C94827EA16BCCF5F98DD7AB1 +:10E9B000A304F2A53D56CDC0F3B2A9D95B793E457B +:10E9C000DD22209F6407783E5BCD10213F23FB09A9 +:10E9D0009E1FA16EC1FCADD9ED3C3F86EBA3DBB31E +:10E9E00077DD88FAA8D6EC2943FFF4B330FF821113 +:10E9F000F87783787A870617BDFC79FC6EC6BF333B +:10EA0000C4D3C8F217B476FB0728FF8D56FECA00A0 +:10EA1000FDBFAAB50B0DD0FEA0D6AE6380F687B4BD +:10EA200076870728FFBD56FEC600FDFF516BD7391C +:10EA300040FB37B5766F0DD0FE88D6EEE800E5EFE7 +:10EA40006AE5C722FAFF40ABDFA57D77C736BC8BEE +:10EA5000F69A1BE415CA93FCD806F2776DAB2A240C +:10EA6000FAAF9DC8F5BF4EEF6EED5EC0916C7E6E45 +:10EA700073249BDB01551A9D17AFCADB3815E9F0EB +:10EA80000FFC9E22E88FA3780F575D25927F6FF9C8 +:10EA9000EBFC5D99E5AB243ADFB8A0F7B4F6FAFCDD +:10EAA00003DA3CEBB4B4329BBF9791ABBA3C33C2B0 +:10EAB000F4A35936E66DC04F18FF5F97CCF54CFEB6 +:10EAC000AA92063C37A9053D83EBAB775A42E8FF93 +:10EAD000AA97252AAF4B2EF1E379BF2A4BA487EAE8 +:10EAE000931343F84E735D5DA1E1BDCF3A59A2F790 +:10EAF00063A484AB6C739C283766C8283FEB989C52 +:10EB0000584CE76AB04F437D525522A3DCC94D48AB +:10EB10004E44B93C3787AFAB23B6DB8EF728A4074A +:10EB2000447A2B60A42C11BFE7D5890105E6D121D9 +:10EB30002F27FFEBCE16ED4C91F1F3445DCEB7FFDE +:10EB4000621AE9B15AD0630AE931163F2EB5EFFED9 +:10EB5000A6746CB405F5969C61626690CBBFCB4EF3 +:10EB6000A471773EC4F5D608D05BF8CEDAF642C67B +:10EB7000DF7973D9C8AF5B2E315752981FF377D91D +:10EB8000DC8E67A6191EDC678FC0F710C3E03BDC84 +:10EB90006FD45BB943E8AD9C2A909761F5AD2ED94F +:10EBA000900F666BEF2A799807ED9B69CF6D257DF5 +:10EBB0007216F50943FDF2C798D1A85F408F5859E6 +:10EBC0007F39A8CB63DD6ED1E574ADA6376A23F437 +:10EBD000C6D072F7EFAF8F22FA140DEFD00C247F5E +:10EBE000AB304E00E8DFEC1348AF30C947F7FB8786 +:10EBF000829BD95C2ACBCEA1E1674EF92201E5B414 +:10EC0000D927793E8A724F6A28F8EAF52CB6CCC724 +:10EC100050AF7D716C653EFABDD69A3B67EF42BA44 +:10EC200015E2E97E87A2F91DB655EF672746603CDD +:10EC3000FC7B5BEB26E0FD71AF4CFE92F41205DB32 +:10EC4000D9619F9E44761CDF6F32D9E75F84F6FC62 +:10EC50008B1605CF050E3FABBDDF90ED2478DEB3FC +:10EC60006705B5330B952E7EDECF08DEEB3212F949 +:10EC7000DF0969B76976E3998DDE3CE857EC1250FD +:10EC8000FFFC474EDB461BEA0F6D3FC058DB4DB81B +:10EC9000FF09062C5A7DBCE8CED81E51D0FDCF5EB0 +:10ECA000C9156E875A6EBA2A0BCF43E5D112F49775 +:10ECB000B1CDBED17C05968B7A7B2F5E1E42F1A52D +:10ECC000E725C0C3331D5AB99AB6F12A98CF1E8BD7 +:10ECD0003E3E18D445389EA8D193BC11FBDF5DA2FF +:10ECE000B7EFD9E89D4AF3B9DE047BB07C77E646FE +:10ECF000677ADF7C87E7E46EAC81B59F56BAE27035 +:10ED00001BB7A4EDA354D4DBEBCAF8FD616400F497 +:10ED10008FE8F7882FE06DEFCD2ABA62FFF3D03F7E +:10ED2000E20AA06899A9EB9003E0B6647FA5CD2C18 +:10ED3000E2FB5DA52ABEDFA5B75BB27736D939CB3A +:10ED40005E194769947687F1FECC776867B35CC437 +:10ED500078A7436F2EDDA5E0BD99CA06A789EA33DF +:10ED6000EEFF8ABE3EBDFDE95D6FFE04C73BA374A6 +:10ED7000A55E07B5D785002E51DAE9F5F5FBD55329 +:10ED80005CDECBDCC07FFF70733E6452A507EB07EF +:10ED90006D7EBAC76637FB4B519F002A0318A7A0A8 +:10EDA000A753DC79FC5DEC88EF91FC15B4B1A41994 +:10EDB000282F574874EE1EB4A98EB1906F817D4AFA +:10EDC0000D4C69CDB823E3315EA0659F93E47AEDE5 +:10EDD0008A0E5701F295C7C2D0EE6DB9A2331DDF7E +:10EDE000BFAFBBD752F604D26F68B9EBAE303B6C05 +:10EDF000780E8FABCF4EF097213FDA811F511F372E +:10EE00009A7D367C37454D1729AEDA0EE56F50797D +:10EE1000B656EE997E0DEDCB4419E7559F37777ABC +:10EE200009EA355722FFFB8423AE2A9B0FE501D95F +:10EE3000222379DD9D53EE43383D23792A91FF9EAD +:10EE4000713A658CC7025949FA401A914CF15956EA +:10EE5000EDBE53F638AEE7F57936B9B9FDD0E4B674 +:10EE6000101E5A623B6F2E867631F789B20AFD3743 +:10EE7000DEFB7029C6273E76EF913F637C6B53AA79 +:10EE800044EF0CECAE0979B15E8FC03A77801DB9C2 +:10EE9000BE6A6627EE47D73345417B7DB730D38FB7 +:10EEA000FAB92745623BA07E4C9E315ED559608CF5 +:10EEB00097CAAA30E637E6F8EEC7754DF8436131D8 +:10EEC0008E9322280A3E1D5CD8C9283E3F352F4F1D +:10EED000C6B8EEB8C28838D8A9C67E12AF32962717 +:10EEE000CF8888DBBAD558EEBADD98CF986BCC7F47 +:10EEF000AED3A38B9F3FE87FE7E1B17B9F64A8A7D8 +:10EF00001BBF8AA778568423DAED3123250F9E8B09 +:10EF1000645B3A67611C1CBB3486ECA583EE18A6C3 +:10EF200040DEBA94913CB526060FE07ED52ACAA5EC +:10EF30002A69A8E081F7A1DC01FB5594BF91F0CBD1 +:10EF4000CEE6FE416725FF7B7141294476847D55DD +:10EF5000BC5CE3C1AD63841FB6222CCFE3BD1F7739 +:10EF6000F3F338BA774F477284575819E26D320B72 +:10EF7000E03B94D9F77EA486601EEB95BC4AB4337F +:10EF8000D6895D348E5AEEF4E1BE3B05E3BC4D18E4 +:10EF9000EFAD521A898FE7DDDC4E52D85C3FE2D1EB +:10EFA000355BA4F891FA43317578F852AFBDD7A01C +:10EFB000C7B1E974F9B29BFBE7F67488A217FDE0CC +:10EFC000B7E7ED407CEBF9565F721BC5F58FABECF4 +:10EFD00042BA6437703B14F400DDCBD6E3C4F4B816 +:10EFE000C2EE1C1EBF763A47BC80BF901E47141667 +:10EFF000074E4777263CBAF0CB78DE933DAE5446B9 +:10F0000039F34BFDFE05E3FDE2F385746E3043F406 +:10F010005EA2F9D3D1AE4BD2C64B4A96BCF4BE3BEE +:10F02000CC4984FA0F315E3F296FEF4ABC77B507B0 +:10F030000907F9E72E0EE748BA4DEFF0978E4178B1 +:10F0400009A00FB3FAD3B1E06EA5F3C0FAFB58A242 +:10F05000755C7FBA9E68E2F64FCF4285E22C87A2AC +:10F06000F393EE04EEC74ED922A37D9B91F7500D8A +:10F07000DD83B98FC9A8EF323A3A6F46BF57243FB4 +:10F08000041C71E3799CDCB7F3C39B4C9C3F589AFA +:10F0900044788B8C2F8D8C271D9E93A0F929400FCF +:10F0A000C4E27D00F94A8C13EC59C5E89D809217A3 +:10F0B0005B6EFB77E8EFCB111619E575CE5BBEA74B +:10F0C0001C30AF2F5FF2E5A09CDE2675D913C2FC81 +:10F0D0009E92C8EF9F45CAEBE139A246AFA0375CCC +:10F0E000DF3DCD46FA06E20AE6A58E968108876FD7 +:10F0F000DFF4275BCAFFA0DDA2DAFCF8F746DD1DCE +:10F100007A3E8BECB09CB778BE685BD6465542B869 +:10F110005590BFE860F63CF21749EF727FD1189323 +:10F12000378079F69E9DE2EEDAF7DDBE00E3D5EAA0 +:10F1300053AF53503F176AFB9FF139425478491639 +:10F14000AF0FF926F27B81065FC64A3F9D0DF81B83 +:10F15000F3B885E2EEF2C5F2865CE4874613E1B3CC +:10F16000DCA42C6D0EDBA735A71697E44CA47D011B +:10F17000F3C18641E915980FDF614A3E5E8CF49A2F +:10F18000036C86F22547E506644E550CF385D1A93C +:10F19000D22B51FDE6546F498E26F7F0DCC7ACB197 +:10F1A000F43389A56C36EA65F8867AD7BC2B869F3E +:10F1B000F7241BEF479A4C3C5EE4266DDD663CD796 +:10F1C000198FEFBD8921EBD8FEF56FD5EA49366777 +:10F1D000C8148F7EB2378ED2BDCB887360DCDF520D +:10F1E0005C4E05233F28C285F2F7C8FCDDEE2A1EDF +:10F1F0000F50BB9A09781650ABDD5351EFE07F8F6B +:10F200009879BD0ABEAF425B4C05FF0B11FFBA6C8B +:10F210002C11EBA7B34E8A63641D4CE1F112C67347 +:10F22000A76D03BC03A5FB01A42A13ED5346BF66DB +:10F23000E77F17AA8AD13BE1F46613EE7F57B380CC +:10F2400024F4F9E18E642BD44E3F8FDDFDF50719D0 +:10F250002897F3C51DBE37C86E889577A07E8C3180 +:10F26000F2A17E7FAD56A3936DD532E15B2F77ABD4 +:10F27000C729DE3E87F5D4E03E2BA72AD180E70BD5 +:10F280007ED9DE4CE69B10DE6F80BFAB9B27D13B67 +:10F290005D4AAF9BCAB7552B43F43F6C80FED389C0 +:10F2A0009E06EE3F8BCAB787BE48B81140B1ADE7A6 +:10F2B000A38452A5CF6E8D84B37BB5517EFF607F52 +:10F2C000643C39878BDDEC4DBE19E0667F40F4B4B9 +:10F2D00031FC7B3CC67AD373CF25F0F372BD7E2818 +:10F2E000F916AC0FFBDE3605FFBE8FB17E69F1C7A4 +:10F2F00009FCDC5DAFCFE7F7A35E63BD48FC44CEFD +:10F3000017E695F2E3B0795D69B31ACACB66F79B4D +:10F3100057CA4FC3E6758DCB58DF57137D5ED7E7CD +:10F320005B079D975EEFA6A28BAB17B98E5BA65BC2 +:10F3300007803BAFFFD3B28BEBF75F160C5EEFCECF +:10F34000AAC871542E272CDE2328E7CA99B216DFEB +:10F350000967CE98A871C1259A1D7316FD14180F60 +:10F3600097E97D1FE55A4F368F4B39FCEC223F9EC3 +:10F37000C32CDF6751F0BC235BF35B83E0598CFC4B +:10F38000BBC72627603CA0CDAD68FBABCE5C8CE74D +:10F39000DBD37EE436927BCC68CFC07EAD18F535EA +:10F3A0008830BA97F126B64B098FA3F092FD572FFC +:10F3B0007AFE42FBAA9FF07D951EBF1F6E67B14982 +:10F3C0007D76961EBFBD491BE7BF7286D17CC0CE3D +:10F3D000A7BF7B9B9A27517CF32F6D9D9BF0FED19D +:10F3E0002F939313703F73589BB76E37EAF71AD277 +:10F3F00066E78D334581D7FF0791B1925A008000AF +:10F40000000000001F8B080000000000000BDD7DE5 +:10F410000B7C54D599F8B973EFBC9299C99D64F2ED +:10F42000E211EEE4C5044298608801AD4C12A0A838 +:10F430002C3BC147412D0E893C227921A8A1B2F570 +:10F44000864484F8206840A0A043148A56ED6011D9 +:10F4500001C11DA2A6764B6DECF661A94B47602950 +:10F4600002C2A8BB487F7F2D7BBEEFDC9B99B99978 +:10F470005150B6DDDF9FFEECCDB9E79ED777BEF7E2 +:10F48000F79D33172FD27F93087928892C0C1413FA +:10F49000FCC7951162CFCFEFE9741232BCD42B8E2A +:10F4A000A3EFDFC9D111329E9087E983D07AB9509A +:10F4B000F06FE3E8DF22212BCBE9F7D030979027DC +:10F4C000C57EBB40EB9F7408A2CC413B09DBED7CC1 +:10F4D0004BA7F3380879EA8EFC1EDE19296FF03944 +:10F4E000B64279B88EF80216E8445C44E8FB9D26E3 +:10F4F000D1DE594A8B42BFB3C64ACB3B7E7F1B67E6 +:10F500002364C40882FDD5B55693635711B2DB104E +:10F510007EF322CC673DE7DF46FB79ADBB74AA40A2 +:10F52000DBCF3B4988997E5AB7ECA6278FA71132CB +:10F53000E1B85809EFEB36DBDD3C7DDFD4DF321577 +:10F54000C6212DC45DE0262493AFE4ADB49FCC4723 +:10F55000DE73B7D329AFEB95F6846839BC9573F7A2 +:10F560004850BFB87431C0C7E2912C74BD7361AA12 +:10F57000F8DE3E550FED6E32B83B683F67F4641617 +:10F58000C0F1A20257F539F70EA982D0F9CF0D2CA0 +:10F590009B8BE38A1464D9B46C12711E26494C6D9E +:10F5A000A3E5CC2462328F23A47C85D8F7008C5F3E +:10F5B0006F157B288C6D1562DF8F605D2D3922EF12 +:10F5C00086C1FD0807B5FF791EAF81D07147EF30C6 +:10F5D000D0CED83E5EA4FF8D09C496C7EE892D9784 +:10F5E0000663CB57BD135B7E5562F09E681ABAE581 +:10F5F000388577EF012381F92E3A9DE4375278EF71 +:10F60000D31302EB975F32223E542FB278003F4E65 +:10F610009F4ADA6AA4E5838793F0FBBB7F6266DFCB +:10F62000EB022F43597E3999C0F78BD202E5A974BA +:10F63000DEAF7FC9DFE92D66CBD243FF2F176DED1B +:10F6400084FAAB02E5227DBF7B1421FD502FF84BDD +:10F65000609DBBFFC663BFE1E78DFE1EDAEFE9BD2B +:10F660003F7E19E075FAF9A1A91C9DF335BA9EAB4E +:10F670003AA1BECD2AF5D0F7134FBF98E78BDA97A2 +:10F68000453B8C31EB5C2C71B8CE56C1B3E259D8F6 +:10F690009F437AC4A725F3FC7541DA7E0997E39668 +:10F6A000A11F03C5D36228BB33ED145F27DA18DE30 +:10F6B0002E31D3729C7D579FB51B78E2BB2A523EF8 +:10F6C000BAFAC7381FD7C9F711AFF7E9655D12C09D +:10F6D0007135E7DE46E7BFCF6C2B2129F0CCF10373 +:10F6E000DEC81225BC745CD78F9A002F7EC5BB7B09 +:10F6F00048E2F15C597FDA3CF9AAAFA8A7E33A4B9C +:10F700000839F751D29D1E3A8F911B62F7BDC81F71 +:10F710005B5EA5C0A79644BD77C27C725766219DEB +:10F72000109C8FEBE407B739E97C8718490BC0457B +:10F730003BEE5A651D2FBC40FB716137FC459EF5C1 +:10F740002765D07D51E8EA758ED111FDB77428A5E3 +:10F75000B7451CE32FEAFB459A79A8FD4F94189F03 +:10F760007218DC6B42B8FF4611F6FFD483D39E3C7F +:10F77000AE1F3C9F130F7A3C93A3DECFDFB0B82FB0 +:10F780009BB66BD8993E8E8F826FC3F36F66DC4E4B +:10F79000DF9FD921B8810536CCDEFEF844F8EE793A +:10F7A0003E00F3857A0F5DEF99C0DB36F86EFE669A +:10F7B000FB385E8AB45FB0618A67B22B02CFCBA5FB +:10F7C000D3D72A189F5B14D0FB4D401781DF4D1D06 +:10F7D0000A78BA817317D071CA051F0F74672DF3A9 +:10F7E000E8E509844CFAE25FFB86D0FAE603E3CB56 +:10F7F0003B697DA7CE7BD33F01DD3DCDBBB7015D2E +:10F80000FFF69E0C5FD4FEBC03FB4BF7A5F3D606B8 +:10F81000EC47A6B85140997AAFABB61ACA138B0918 +:10F8200067A4FCD8769278FC16188FBCAF4B25E401 +:10F83000E4FE874A041DF2A3DB814E4E139B1BE8B6 +:10F840006E9FB5E5DF71BC97F438DEA4600A07FC53 +:10F8500077DF739CBB93003C62E9EFE4C915B64ABD +:10F8600046D7777A510EE88883F6B7F0D931C807C2 +:10F87000D4F7DAFDABF7C7F6A3C58B8F9475016A91 +:10F8800046E397F6BBB4E9B201E8B1A195CA8B286B +:10F89000BA6938DE652096C1E3103280BF04F09764 +:10F8A000E2259170BD66E41BF41F67A2787B0AFE17 +:10F8B000CA636542C7BF9BC3A59145A30285C0E744 +:10F8C0003841ACEAC88EF05752E1473E7F86FED9F8 +:10F8D000E906BE103802F40EB2741BC817317876F0 +:10F8E00013D4CB233CC08F860092D227F96932F221 +:10F8F000DF3352683BB67F718C5BA6AFCF01BD583A +:10F90000B09D2D358A3FB505DEB48568F9F4CEB4D7 +:10F910002ADE0678FB4B1BACF35420ADCA604BCCFF +:10F9200037B47C93CE0CE1FB21FC49F14E747A9202 +:10F930009D00EF0E2A74419EA5B594B6C4D937B583 +:10F940009DC3D0522A01FFF8BEC5DDC3E0463CB4DA +:10F95000FCE93B693DB0EFD7E8742817E672AC7F4D +:10F96000B57D913311BF9666071D117EFD84228FF0 +:10F97000557EFD8495C1E372F9B5F639ADB328051E +:10F98000E0F7299152403EA59AEA9E013D43AD7FA2 +:10F9900022811E50EA64FCE99D838529214BA4FD48 +:10F9A0009FF3BC6500B7ACAA7E0F4FE79F7503714C +:10F9B000B7D3651DE3DDF789147FEE2254BEC3B3D0 +:10F9C000CC67003E483AD211BE84B8A7C2FE2F9839 +:10F9D0004EF1A59495411ED77B0DEE4EAA37D40962 +:10F9E0000C3FEA7670FE760AB2BB1E8DDDBFF9DDF4 +:10F9F000C6081EC3FF6D8EAAA7E3D40BFE95206731 +:10FA000087514D29AD82E2EF73B1DF2F22419C5720 +:10FA1000C38B178DF1F0E2BF15BCF8739E6706AC7F +:10FA20008F9B69C2F92C7989437DC06108A0FE13C0 +:10FA30005E4CE5079D2FF92DC39BFFE4BDB8EEE6B4 +:10FA400065733D77D17D38D75AE7B98B56216B80E6 +:10FA5000FD0E307D6FD1E4401FF24122BE727B1655 +:10FA6000F4E74578501889DB101E028EF7DFBF657A +:10FA7000F8749BA2375EA39B89EB0AD713B187F278 +:10FA8000B9892F1EC432FDD772FB4478B07EE6B729 +:10FA90001011E0BA80C8064269ED01A713F7AF9EC6 +:10FAA000F41B185DFBDB3368BB26AA6F025F8BA3D8 +:10FAB0003F7C3F1A1F0F6BF0F1F015C3C709884F49 +:10FAC0009F1137E2D36D1A7C3C9C001FDB07F0B11D +:10FAD0001CF1596D4FF550624E1DFC3DE08B276ABD +:10FAE0009F176E8E2D93E7A2CAB98017B41C852F7D +:10FAF0004DBB2E1A3D71F064DD80BCF717D58C89A3 +:10FB0000E6136D38BF230A1EADBB657E36F0E935BE +:10FB100060700C513AA800F946FFC27D234113EDF5 +:10FB20003FE9AA8132D697AF6065FFD65F7B375C2D +:10FB30004BC87ABD2F5BA4F0AAE3BD7D3A902FF9A4 +:10FB4000BEE79C6057E83C3902EEABA7D03B0636D7 +:10FB500094E1E353E35A8A5AE2C04F9DFF7A2E1094 +:10FB6000D4019FDECBF4376B59581F2D5FDF703205 +:10FB70003994D21B427C0DBFCA11B02B36726BB3C5 +:10FB800001CF36664B5C3B5D53D9AEB64AC45FCA03 +:10FB9000EB0B28DE35EEFAB06F282D974DEB07F40E +:10FBA000A3EBF62E7E1BF8E5F824669724B76CD5F8 +:10FBB000D1FE32EF748D6BA7F8F6A653C27192AEE8 +:10FBC000EA3A08FD84174B620FED276B85ECBCA762 +:10FBD00018C66F6943BCAF21F83EFD7BCBDBE0BBB1 +:10FBE000478690541EBE236D1C7CB7329DC3FD58C2 +:10FBF0003997CC7AA518A84844BD7ED82C916B9B28 +:10FC000000E5964AA41749B4FF321BA9AC2385DA54 +:10FC10002DEB6C04F975BA8EBFB3863ED78D63E5C4 +:10FC2000D4E59CA70789772DCE2FD348A671A9ECE0 +:10FC3000BDBF18598E6727D6FB71BF33AB5B4A61D6 +:10FC40001E9979ECE930F874F974FC43EFE9FD2B67 +:10FC5000E83A0F29F8B2746B5566B45C3B74C6245D +:10FC6000E8A8DE7C284BB5178216B0179696566723 +:10FC700002F3C8CD9F9602FBEAC889AD3FA7F7A45F +:10FC80005C05F2FB3D9EC0FEFD97C59302F4798DA5 +:10FC900081CD5FBBEF9F29FBD97C8123FE28BA6C05 +:10FCA0009E751EEDB0E60B42CCFB330F9A08A810F0 +:10FCB000037AC5C2DEA9F05D23E95F0978D8184848 +:10FCC00026FE28BAB82629FEB82A3D345FE0891CF2 +:10FCD000775C43ECFB0B69444E8BF75D46EC7BBADB +:10FCE0008E98F29ECF07D601EF4945C8E6A576F873 +:10FCF00074D05368F99C5F27EBC7029B63FCEBACA5 +:10FD000018B201FFA2FA480BECCB592984FAC63984 +:10FD1000CA9AA01EE4780DECAF10B6CDB446C65119 +:10FD2000EBA17DF43E9E9D652041DC9F30CE03E03B +:10FD3000278F2464D3FE4F0C12E869FB0F22FC547A +:10FD40007C8986A31CC56F32DAFB833A4A5725B9F2 +:10FD5000196B8B8BE896F5AA7C216BAD87F2810C31 +:10FD60005E17C32792CB06F806B2A9753A5EE13357 +:10FD7000D96B275F1B5D66DF47DA0FA981FAB26294 +:10FD8000D6BE2277E87B2B40F6922E9C1F5D470E55 +:10FD9000C06FA06CD2942DB43C26AA2C6AEA1D9A9E +:10FDA000FA2C4D7918FBFE8C359803FE81EADC11A4 +:10FDB0003502A5D333D9C1391C2D3FDAEEAC994CAD +:10FDC000E9B4B18CE9174DFB39374722F06B723338 +:10FDD000BDDEE20E19EA8A010EFD7DC0571AF670EB +:10FDE0002247E9C112D819C432B493A2DA05386C9B +:10FDF000D710F810DB25ECDFA5433AEF741D65DF63 +:10FE000005FE827ACCC31D8BBDC0D8FAF48C6F512D +:10FE100029E7194A1B36EDA9213E4B84BF9ECDF63A +:10FE2000BC89FCF50027027D0EE029F46B89D085A2 +:10FE3000FAFD9FC6ECFF1DA849C94B3F6913E8F7BF +:10FE4000FFD1F897F1A077FF499123EB397F118C0F +:10FE5000BB89F88A408E7FBFB1E0A08E7E77441FB9 +:10FE6000DA02BCB73DF76A84DF116B683847F59258 +:10FE70008772AB6A040ABF23E9A12D00CFFFC8AD8A +:10FE800066E5E1A1E13A5A5EDDD3C4CA05A12D5071 +:10FE90007EA567362B8F090DE769FB3CF93684FF99 +:10FEA00036313E5D2FCB65FAAC3ABF87CA3C4B7307 +:10FEB000418F6E60F267CEDD876703BF9DA323226B +:10FEC000A17C7ADB99632F6DA3F0D8D69A4C7A186F +:10FED0003A7A056A6F6432D4A772A20BF97AD8C94C +:10FEE000F41BCAED42E0D74B1E6F923A9D917D51B3 +:10FEF000C7CF1CD5B213FACF9C538C72C4ECF41C40 +:10FF000081F1D5E7F451EC79245764FC9BD779F063 +:10FF1000FB07AC7EF87E8D99AD8BD20FEEB345D941 +:10FF20009735CABAD6E4323D63BA73CA91DCF1A000 +:10FF30009F28F6CEAA40FA283AAF6E8E04C06EA46F +:10FF40007A8A6C063E5C9F84F64C37CC1DEAD766F5 +:10FF5000FB653ACEED1CF1027F51F949B7DD939D67 +:10FF60001A65377697D2B225E227E8AEF1642739D1 +:10FF7000E099A1031B4AE54FDD4ED64E954F99ED12 +:10FF80006C9CCC35453DB09E6481A0BC9B37ABB02A +:10FF9000A70DF58399386FE2F16473B4BFE3F5B947 +:10FFA0003A80A3BA5FDBCB3C2FE0BA78E6F750F794 +:10FFB0004D85EF915CE6F7A8E3A97E41F1EEF17C77 +:10FFC0001FF647F58D1214EC8ABE710490767C04FE +:10FFD000CE44088D87F7FF1FC2AB1FF0E9DBC2AB31 +:10FFE000B195F211DD25F011058EEBB9A03E93F12C +:10FFF00011F44BC07B9047CF3B7DC773A3E861CE24 +:020000023000CC +:10000000038DA867AAF34ABEFFB569DF234087A71F +:1000100090EEE6FC2019FD085A3D50B503557D359C +:10002000911DF8A9420F6ED5EFADCC23B938F4D2AB +:1000300063145EA9C42A021F3D62088D71D3F6477E +:1000400074BE675F83790FE145CA4306F5F7421E28 +:100050008FE39B553C2161DB2847044F56533C31CD +:1000600041FB1A03DA25DD76FFC6F98027B70C734A +:10007000CB12CA61A467B93519EBAFD11D25E0C712 +:100080000F4F1045D033295E617DF7EC42BFCCFCA9 +:1000900031B219FDD349FE1EC0BB520A00E86FF60B +:1000A00028AC077F08FA91669BD87883F18AF92DEE +:1000B000461256EF54F0B63E17F136A39D303F90EE +:1000C000E029A989D217BE9FC7F022B92CF4EA1FF4 +:1000D00040FF7CD4EC2E20CC6405FF12E9CAC4FE9C +:1000E00028BE8CC81BCFE438F47BD7E3D6AD8CEFA9 +:1000F000B9CB01CE0F5BBBC832F40FEA71FE9BCDCA +:1001000041D4C37526C90E7EF8393C595F08FDB548 +:10011000EB45C0132DBC2BF312F91F42F746FB8BA6 +:10012000E71865630ED43F6846BB40B5FBE6A430D4 +:10013000BA52ED3ED5CFA11D47B5FBEED4D873031F +:10014000F59D7F2DA8A5FDFD59C13377EF8582B9B7 +:1001500016B66EF03FD5C25F74DCDAE5E60FC1CFAC +:100160005C2BEB83461BF091299E50949D4636B044 +:1001700075F87EA5F7039C5A05B27E3BEC8FCCD672 +:100180004FEDD8FAE8756D32B075C93FB0C6AC6BAB +:10019000938DC591BEFDBA3E1A1FBBAE93E3957514 +:1001A0001153066DA7C8B93B5BAD1F7225F409EB6F +:1001B000A24FB29CAECB1559D7B23CC64FE7287CB4 +:1001C0006C90DCCD637A7C1CBBFDFFC67ABB9EF2D3 +:1001D000C45BAF769D7FCEF3FC202F1DE9262896C9 +:1001E00045F0DAB791AEAB0CF635DDDF86FBCAF031 +:1001F00093109B1BF8D89279745DF06CCB447FE12F +:100200001CA3B407FCE6E44729CA3A09F281251B7E +:1002100087235D52BC6574FB14F3BF2C317BD17F07 +:10022000B364B1E8964558FF2B680787297F45BD21 +:10023000A43596AF7F3D1CCC39B5C5D17030E5CC27 +:100240002D8EB3EFB211F139D1BEFF990FDFCBE59F +:1002500025F69790E5B17E0AF0E70E94F9C165ADF9 +:10026000DF8390BF1963BF9713E051E8FBD1787427 +:1002700044AFE0D13233CA1F158F8E5815BF900698 +:100280008F08D5A2818ED5756BE13807E018C72F8E +:1002900044F1A900E07844B1CF283E15001C553A3E +:1002A000B8B395F1032DDCFE9498AF7DBB7568F073 +:1002B000F8DBAE43AD4FB40E55BFDDC02DDE08F800 +:1002C000B9219B88EDA80787C6809DE430F88B6034 +:1002D0005E9B0C947E91AF303FE1678762FDCEDA82 +:1002E000F95CB8647EC1FA4DC42712E1E5E5FAF97C +:1002F0006A35703BAAC06910BEE733B9A9F5F3357A +:10030000DBC24F83DED49CC4E4F7D90356A47392B6 +:100310001F9A03F6C2B97D4602F2A0890B15C27777 +:100320006739CF5CFCAE2D590239AEFA738FED669A +:10033000FE5C99507B9D961B7CCC1FDD2CFF7225AB +:10034000C0E5629ED002F672F39E587F20DD0F1B3F +:10035000ECCF591DE987EF9B787F3D98D8EB0D4C8A +:100360007F59AF23018067C48F70B410ED9A6C91F0 +:1003700080FFAA49F761E13D517E8726A5BE298706 +:10038000F9D3203F01E32E309473305C9A1E3DFD7B +:1003900025C4579B7669E93B96FE1B2265EE220732 +:1003A000FD45D53B23F48FFE03C08BC9C45FC081DC +:1003B0001F909593A7F5FB21CFA159F13FA7F78691 +:1003C000A6827E632D0B10E0FBCD2799DD3471FFF3 +:1003D000D637C13F689FD63F1C54A866251EA5B5D9 +:1003E000D726EC5FCB833F4BB5B7A2FC67453363A1 +:1003F000FCA72BB01DF8E360BC10BC82B881C0F430 +:10040000F2F58A5E4EF577E4F3F3BA46A2FE0EFAF1 +:1004100035E849AA3F0FF426D09F77E757CDC8A704 +:10042000EB9C5D50757DFE78361EFA29C04934215B +:1004300031DEAAF051BF03BFDE57C78514FD8FB070 +:1004400078D03DBF48FF4ABA5C949F307E7F7BB432 +:10045000FF7D9FC6FFBEEFCAC5833281AEEEE1A429 +:100460004CA0AB891AF9B62F811DB0247F201E94B1 +:100470000974ADB63FC1FB30FEA1C61DEA21CE8294 +:100480007226887189BB5B88BB13F3407C2BA1DC8F +:10049000B890889D14DF1B26FB58FCA38588374E37 +:1004A000607156298ADE208E195D263B6839460E1A +:1004B000F6631CA489F6B0C90D7E9AD8EF9B89BF5C +:1004C0005A003CDE73D118D34F37DBD73B15FCDE27 +:1004D0006866F18389CBB7F224CA8F9332CEE37C6E +:1004E00008E8F7177AF45FFFA7828F2A3CFE9C5733 +:1004F0007513E05512F8D5E0BB878CA8C71CD791BF +:100500008580DF6BECE4CE99F479F641E2C9D7033C +:100510001E8B39D1FE44F5D9B9CFBC10E8E219855C +:10052000EFA9EF2BA051BA120F40FD3F19F3472856 +:10053000FB2F01BA29CF55ED0E520271880F157E9F +:10054000DA74ABC507FD85748CAFBF98CFE4C08B60 +:10055000F906DC3FB53CE08F53E8828E83FD255DD4 +:100560004562E2D73F53F055F58713254EB7BE3E9F +:1005700089D92903F4A943FE9B5CEC35F890FF551B +:1005800021FF0D7F6491002ED34E37D4C33A3E9D98 +:10059000954420DFE62E254EFA6EBE1DFB55E38BFB +:1005A000FF40BA8889935E2A5DFC3E421731715242 +:1005B0000AD764900BFB74CCAEDD47110BFD8201B2 +:1005C00025EE2E100FC8AD7DBB46A21D3357F15747 +:1005D00053BE81F66B98CA37B6DFBE8DF3E0BB40E1 +:1005E00001E6237CA8F73FBF1DF49903CC4E53F7D7 +:1005F00063DFBEA17EE03B134F7F9103F0DF77F214 +:1006000085A190E7B14F89AB37188285E84F31302B +:10061000F9DE600B1602FC5E57F0A6218996E9FB15 +:10062000BC745F18F05ACD8B8176765C8F64037F43 +:10063000CE31C54E3F4AED769817A5967E88F7D302 +:10064000FDCE8672787526D3A7E9BC002F8E1D18C3 +:1006500083EB5BAF67782CEFE5D0FF73541F3ED17F +:100660004ABF3F9A7D156913413E5FD8DE07FD3FC3 +:10067000CD13A30879479F9FDF43BF3F378417C13E +:100680002F59A7F34ECD067EB19BF943B4FB00F280 +:100690003A3AAE7B968473D06FBA303700F87376EF +:1006A0007F11E6D3118748645A6EDECBEC476D7E2E +:1006B000C4717D2CFE6BFB857581FFB219FE067D32 +:1006C00024BA7D9CFEBEAE7C561F2A5C46E13145B5 +:1006D000F24905517E80E637B2518E1C7BEC73DC0B +:1006E0004FD2C5E2E8C7F59E39303FFBE4A0A13602 +:1006F0000A1FAF2E50FC5046A65F50FE6B88E637AF +:100700006A7D7915899B9F525EC0E8DCDACFE4F4FC +:10071000E07A86E7F7926779E0175743320FED6F7B +:10072000849267732FF9ECA011F4A94029E6F18CAB +:10073000581E443E40E78BF8797C630AF247F22862 +:10074000C3D7F93F3222FF984FE507F367B0BC42A9 +:10075000F228CB1F3AF19013F1B97C45B01CE9C1E6 +:100760004EDCA047BDD6F1A1CCD3FAB93BB852C8F4 +:100770009B9CDBE1443BF0EE5D4EDCDF890A5FAF22 +:10078000337A304F923CC3E29C773D518FE334265D +:10079000133B8FFAB5DF007AC4C21D1CC6C32706FF +:1007A00018FF6F108207414FD7E6FD107F6CBE0126 +:1007B000C82312A5C783FC211ABB2B76DFE54BD2D9 +:1007C00017B472667141427DE1EFA4C77F337D614A +:1007D0005981AAC7C7EA0B60FF17303C64726D27C6 +:1007E000C7F89CA22F3482BE00BAB022A75539BFE9 +:1007F0004091F32778A667CC37AEC5E79A0296E713 +:1008000070370929790E6103E87F89F0788D322FDE +:10081000158FBB008FC747F0B8E164B0CF887E0763 +:10082000F76EC8D368584E82566AB7CF175A509E93 +:100830000D118988F9AFD53E9C57E6126AAF51BCBD +:100840009C0FB1FC7197AFC70CD25B34FA8A3A6F38 +:1008500015AFB5FAF5C4E57E1EE28BBE9104DFABA1 +:100860004F91044A61BE352666DFD4982C411EFCA8 +:100870000F93F567A2EDCF1AC1F322E33BC3EC2738 +:1008800046234B23D0EF74A7E737A3D2237A7B729A +:100890005978E563B43F3D29D1015F57C7373B2BFA +:1008A0003F298638AFD08FF62BC962F92C478A19B9 +:1008B0005C93E93E6CA570D50B32C24F6F12ED6DA3 +:1008C00076D8FF7E8CD385D309FA6DD5FDDA622503 +:1008D00032E4151F2966787FA458C4276D8FF9006C +:1008E0007A176D4FFBAFDA67463E727EAFD50FFACF +:1008F00004959323ECB43EE34FD40EA4E5B3FBACD4 +:10090000A8579D55E49B43F5DF9395B8FFEF2A78F0 +:100910002393AAA160EF11EE86A174EE44B5431AA9 +:10092000ED89E2DA4ABDB3FF5686BF46D46FCEDB0F +:1009300043F74199CE0773E0FA14BC6ADE555DFABD +:1009400000C81BAFC5CDA0EE2B057DCDC82FBDD5F2 +:1009500044813D955F1E5E06783FDC221A6993C98B +:10096000233EF8FD6C5AFE68979E18017FB6DD9411 +:100970001284668227CB3B66F07CEAFDFAA3A128AD +:10098000BEB368476CB931105B6E26C2D15094BCBF +:100990006AFDA0FED76F45E1DBB902AB03F08048EA +:1009A000C47D91D2D3F107F7906320BBF93B52800D +:1009B0009FDF45D9563C7AFFFCC185BF7E8B7E27E1 +:1009C00018AA3E2F40FD5232007DD5523D279E9DF4 +:1009D000BF4DE16B4663CBC9AD143EC6D78DEE3635 +:1009E000DAAAB7C0470AD3C13E0EF7C1BE1A479C68 +:1009F0002981F846D5882F30BFE4FCBF1037C0E905 +:100A0000BCB912F1E9FC46B3047E80EE1C0BF3CBBB +:100A1000BFC1F9396617CE184FEDE9853815E0BB2F +:100A2000E1951B41AE4C308A2B445CAE4987FB4DAF +:100A3000AD63FAEC36C82BC1CFDE4D0DF43637D896 +:100A4000D1FD362086A98512CB9FE05F3498E89FC0 +:100A5000CE0E4F511BFD6E91378940DEACF0A5E004 +:100A6000053C7B18BA8AB22B8715323ED3680A1927 +:100A70002AE977CD5F2C9D96AE8BC47D8C7A9F67DB +:100A8000289DB77E4F6970287DB5A0B51AED672AFD +:100A90001F185F3CC0F8E2826595F89E9B390DD720 +:100AA0007B82AE17E0F2E64623AEF7C4700BFA3352 +:100AB0004E6CE1B0BC403460DE2DD5A7D22A1DF0CB +:100AC0005E2F1AC96078346F7878E5465AFF6E3623 +:100AD0004F388AFF7FD9FC738C4FFD85B0F1E55DFF +:100AE0003CEA697F11C3E54180A7D4628BB6D71772 +:100AF0006CE1BDC02F176CB9F7DD0900B799B79548 +:100B0000013C26D99766489648BDAA9F0AA915DBDD +:100B1000812E277D59DD3F09F4C42D946EE8BC0574 +:100B20001DF181BDF4D696EFA27DB0A026C90EEBD3 +:100B300093366F9B0AF2F82F354374B8AE9738227C +:100B4000023CECAD19F07E012778E3E1D5E1021E0D +:100B5000F1AA7284C50DF271C1EF78C4174A67B764 +:100B6000425CA9718B1EED8FB7661EFEFD6C47843B +:100B7000CEB8991B664C84EF7FACC7EF07F4BFCDAE +:100B80001F7F007E17F84735119043083F2DDD1970 +:100B9000472C2F847969E96FC18A964296EF717963 +:100BA000744836333AF41572C8A7BF011D2E2CBC09 +:100BB0000C3A24C35263F48EC17C4F46BC55E3E526 +:100BC0002637F16CB3607E9487A3FC7A6DA180F523 +:100BD0006B0B999D29FCF59E1DBFA2704A2BF4FD5D +:100BE000A010E42BF194827C96C26215B8E62D8A9F +:100BF0009E4B36B3F318600FC1FEAF4F27DB3BA30C +:100C0000FC5F8F417FE9C817DAA19FB37FFCA20F79 +:100C1000F6AB29E74C09D801CD17FE0BF36C2CFB82 +:100C2000597E96C51DC6BC35BDC38BF8A8F2FD66BE +:100C3000379343DA755D28D4333EED08633F635C38 +:100C40008C3ED5F8F4A6D6248C136E72F8CDCC8FDA +:100C500045F553DAFFF4321EF98CA9AC9D801C23B4 +:100C6000153CC6F7267DF16B02F1D077AFAD7683E8 +:100C70001E6C297B5348837556E895FA9FAECAA52A +:100C8000F5BFBE760ADA73F764F112E853D3CBF2FC +:100C900064949F1E96273FE98B14A4C319F5335023 +:100CA0000F56E7EB2526C942F1642625D6E8F30462 +:100CB00033AE354B9628FCFAB48B9BC6EC0029E585 +:100CC000E631CCEF162866F23C1A0EF7641970FC78 +:100CD000D905952F01BE4CBA8EEDC3A9978CFE1590 +:100CE00074DC53E6F8FADDFE42E647C815AE47BEAF +:100CF000B4F42523E66B9CE6E27F7FF72A1EF3CC53 +:100D0000EA5771C44FC73BF5FC6B39C0D73FDAF6E1 +:100D10005A4E6DD47C12B5FF6361227F76F0AE68C7 +:100D2000FFC074038B139171C6187FFF749B721EF2 +:100D3000E612E35FFF9430EEF38B6130DF5F0DC4AA +:100D40007DDE19161DFF1A8863BA59DC471BBFCC1C +:100D5000AFF83765BEECFC41ABA0CCD76D6471AC8D +:100D6000792C4F62C98134C4BBE986F0E318DF7C7B +:100D70008317953897C784EDB3587D8275118F27F7 +:100D8000DF518EFE319C0FB7870B5A6DDF627D8479 +:100D9000C5B5B4EBABDDCFC78DD336BB585E48725B +:100DA0007118EDC0A3EF3C0B991803F86EDEEFD479 +:100DB000459F5B19D06715FCBE09F09BAECFBC8A7E +:100DC0009513E175227EF5A822B755FC3EBA2A2F6D +:100DD00005F0ED215353A88FC2CFC3A710F3105ACB +:100DE00056F241E40FACC88778052E4491835B3EF0 +:100DF000B0A27DD6AE6F7906CED9C96D02D946DFD5 +:100E00003B929AFC6DB42CE9AD9847777FD28CADBC +:100E1000608786A882CBD1F2E74947B6829E404CD4 +:100E200029444FC791AB94F60693D84EF58BA79201 +:100E30006DC85F5AEF2228BF334990E32840DC2376 +:100E400073991F7CD16E0EF3E729C583DEE7CE8B45 +:100E5000AF8F168C64FCFB8F905045D7EBAE8EFFA6 +:100E60009D7BA4EAF7137CA128BBF461CE2D29F960 +:100E7000E404F265F5A47F36F265AAC7FF9ACA8337 +:100E8000A1FC2BE8FF3EF6A0EF9978E792D4E75D4E +:100E9000D5F1FD0A1394715D5D9C5F6F43FAD56DCA +:100EA0008DA15F25AE6BCD70530903F17C16B7CDD4 +:100EB00027EAF9940D10171952C1E668F38408E87F +:100EC00017595DD7135F1AD0D3C44C906F4BE6C54A +:100ED000DAB959B5ABB2D10F597BDF0C90DF1BF4F7 +:100EE00096555C0A3C63FD871B34FEC3AFE30B5988 +:100EF00009E9664216F8633644E2C1883FED73455E +:100F00003FCFE12A48749E4346BBD4E7033DA8D2B5 +:100F1000E4EE710FA61F52E1CE8275BDA8EE9B4292 +:100F2000CFCD0A6A72FB39B44B07F343059E8DC3DC +:100F3000109EE6AEFBD16E4A2E657EF7E4FA5A1F8C +:100F4000F09F64CA7FC08E33185A38DCFF89CC6E9C +:100F50005BC2B1F2924A5194E9F7069B923F7D033E +:100F6000ADB7039C7CBE68BFC335BA7B2AA3F3B47C +:100F70004542DB031F9EC5C69B6E5ACEF2C47D540C +:100F800047CA8EC0B14A81637E45123B6771AF0983 +:100F9000FD719BCD5D385F9DC4ECECDA4E33F2BB46 +:100FA000A1BC0BE352BD7A861FB2D584F4EAEE7D74 +:100FB0001FF305875E9D25F1CE28FC59CAEA55BC72 +:100FC000209A3C138341EA037F239D881BF2949669 +:100FD00070525F15AE4B0CCB6E58B7C2974B9298C0 +:100FE0001CA1E66616832B8B3B6AF68BE20D8B0306 +:100FF0008CB1303F17F149A87769D63B186FF6BA24 +:1010000080DFF60EE0CD1E573C7EBBC62EF5F544C4 +:10101000E30B9156821FF8111D0977C6C31F77ACE9 +:101020009DAFCD9BD4DAFB4DADD55EC5FE904DB8DE +:101030009F06B43F9A96557A99FDE16A037F59F36A +:10104000722AA9689BEAFD9C09FA6B9E6543FBBB6B +:1010500079CF4ECCA7689A46DC308D5AC59FADAE8D +:10106000F3A89EC549A9CC0A403E47B73DF4349C3D +:1010700083EDAE57F3BA589E93BC8753F2BAD43C73 +:10108000C0F011F0D7767312FA6D07CED3D2FD6798 +:10109000F95C979717682DF63AC112FF69C17FFC7A +:1010A0002629FD32F2AAE582755F9D579D742BD4E7 +:1010B0009B602F947A4003AA2FAB658F59827CAE38 +:1010C00048BD40ED4ED31E8EB597D7DC3245C07378 +:1010D000704AF9F327E1BCEB1A3389192F7A7E8223 +:1010E000A67F302D2D92FAFD1F664EC9C73C48657C +:1010F000FE154F7A86D1FEF4B1FD21CA28EDA1A0DC +:101100008EF7C2E863DD8F0E8BE8ED548FFF6CE441 +:10111000F888FEFEF0E1E95D63E958C9E26778EE20 +:1011200050D5C39B1D2CCF5A8BE77F53E414B58752 +:10113000A7826AFDF0ACC55EE877200F72FF5C0FF6 +:10114000D8C16A1E64F3722F9E3FA47ABFCE057980 +:10115000D57F3C73E220013BF314FA039A2F08CCAD +:101160004F4EED078EE28B69FF5AC41FB243EF0763 +:10117000D74EB75D26808FDD07B8F1805F84B4E479 +:10118000DC42617F9BCB9384FD25C83FC873313F10 +:1011900077B3AB6A6321C0FA398E803EDEE9FA1478 +:1011A000ED8AA6BD53C6479F97ADDFB38E9DBBDCCE +:1011B000A18FBBEE3C17CB776CDAFB2AC67B4EF9CE +:1011C00039A4B985827F35D89B0B17EAC0B2226556 +:1011D000FEB998374D661908CCDFACD821CD3B6EEF +:1011E00092E1FC6E33FD8F9200D9E49D8FFAF6A652 +:1011F00059260BE40934BB6A1723BF13933C60CA1A +:1012000069E739900FB92C09F3AA3AF7E8A7819D4D +:10121000544EE9E26716E0ABEF39B702FF4C1BC74B +:10122000B78B90771A5FFF2E1AC5E45007E795FF3A +:10123000B90CE338243ABF7DC41E667F4D74196231 +:10124000FD932E66175E2BF75703AEBD218492C126 +:101250001E6E269E4FC0EF45BC1609E3582480FE43 +:1012600040C78312DA4D2647E891B1507FAD8076B2 +:1012700093EA4738BB3713F5B1975DBEEFC23E9690 +:10128000F3A127FF19E0F688A0C4C3185FC9B9C944 +:10129000320EEC2BBD83E93366AACFC0B9A1EB5661 +:1012A0001FFF6535F0568717F50842851CDCEF50A7 +:1012B0006DE2583C48A33713D13D19DA4F55FCD2A3 +:1012C0000574B74E9810353B2EA6813FC32103BC51 +:1012D000DFA10B48A3F55388A783ED0BDBBFF50611 +:1012E000A6AFAFD799505F57F5E164473FDA898DD4 +:1012F000010EC76974BD82E7471629E71406CE0BB5 +:1013000008213C3F51EB4A56E2B01D0C3F493FFAE1 +:10131000C3C88B6C1FA8E689E72A54B8ABE70CD486 +:10132000FE0C4A7CB751F1E75280317A74A9F1DDA5 +:1013300015CA533D07C2C62582541EED775C5F4334 +:10134000483FCE4BB2C17C1FC9F0DEE7A2DF1FA52C +:10135000780C78767455B29F708047FD1E88D3C88C +:10136000A52CFEA2C5A7475C9C72CE2C3C15F3F0C1 +:10137000F6263867B627F69C19E50F8BDFA6E394AF +:10138000951D76037EAFB12BEDAF2778BE407BCEA7 +:10139000AC4BD987FF73E7CCDC9CA7873EB7BAEC90 +:1013A000B1E7CCDC6CBFD43C19EDF9B2B3D94181C3 +:1013B0009D07093DBD0DE5A511EDC2D73FEEEB0040 +:1013C0003FF3B952831BCED564DCF64E07E62B7192 +:1013D000420BC44FB5FAC0EF9CD53F01FA5977CB09 +:1013E0006E37E68F6BF481447E008CED46F9890EF2 +:1013F000B8AEAC1FC0DCF5B90DF0ED34177E1CF2B1 +:101400009AE5037CDCBCE60F5C89E2629E59D1FA66 +:1014100069879AFF674F8AC987ED4890FF9748EF21 +:101420001712E6FD5D8FFA5BC740DEDF34557F8B18 +:10143000CD6B1693BED25E56C79F1672C6E4117C62 +:1014400072C9EB54EC9804EB4B64B75D6E5E841686 +:101450000E1D09E4E85F5D03F13F4D5E8447843C67 +:10146000820EC823A04F812332FACF760EE44504C2 +:10147000D15FFCEA48F47B1913E645B0FC3EE1C0BD +:101480004809BE7B58EFF5803D23EFD42B72C0FF97 +:101490003CF84D3A0E64A39F8DB84225C01F05FB52 +:1014A000D42CD0AB3A14FC6CB8F4BC88B4A2387914 +:1014B000115BFDE31ECF65F6737F32D5CBB61226E6 +:1014C000A7E4FDCCAF49E78D7EBDF063C3515FE576 +:1014D000669A701DC7DE30F618510F77639E436D14 +:1014E000162F827CE9AE293F01F2EB18555C818E04 +:1014F000EBEE5E8EF66BA2FDA95B151B7756DF5FE8 +:10150000EA3E8D2B62FB7414EC7B14B432FA8B1719 +:10151000AEE20E62FEB626EE5D56441439119BC74C +:1015200070DE5C89F1D8FB9EA8C138EC7CD282CFFA +:1015300085A44B89CBB2788BB44A403921EDE0FCCD +:10154000929391890E6D7B5187F7F550F1B609445E +:10155000A24CA9E66AFA9AD371A0A74A1DB49C4985 +:10156000D7B55A90B3E8775BDF4F46FFEBC30E4920 +:101570003957C3EC2FF9510EF53FDA2FDACF720746 +:10158000C51BDACFCD452C2ED050C4FCC91445FC68 +:10159000381FE5D9A1E47DA8E3B5115D109E3A8E10 +:1015A0003D1F168569F1F43BB5BF0E7D8B09E22D19 +:1015B000E1E13A8C679E377866613C30B59080BD3A +:1015C000D8616D59358DD5230F3D6F0E7BB1FE3B34 +:1015D00002331488940AF3BD41D90FEDBECEEB8AD5 +:1015E0002D6BF313B4F77ED411DFC8ECBCC1F760E8 +:1015F000DC50C4E4E1F94EA7B22F6E8C9777E8A5D2 +:10160000DF38413EAE16500EB70D6370D30D67CF75 +:101610005CFBE4592887ED543FC5F9B2F9E77EC772 +:10162000C101FD75D8197E7DDB796BE7BBB4A810CD +:10163000F7AD038C063A5EC76ACECFE0C5E67DA95A +:10164000FEEA278AAEAC9C3AC6B9B70701CF2CFE9A +:101650001F81DFAFAECD28023F3BCD29F4BF9A47B3 +:101660007EB669612A968FAE2A403FD000DD9E5C2F +:10167000B918EE33B9D47C8AE714BC7857E387AB4A +:10168000ADE0DE837EB47007841254F9439B56DFCD +:10169000543C15F863938E4899A00FACD2E4B3681C +:1016A000E8798AE47BA508EC0F437F1FE353A1424E +:1016B00001F56FB31BE0B64E776CE7CF015F769A0A +:1016C000313FB26979783BF82B3325DF5E68776666 +:1016D000D9E1A99C84DDA19E74EEC048BC1FA7B6C9 +:1016E00043738FC7A3B1793464552ACBFBE88E7D51 +:1016F0000FF737C4B41B945FC3F4D6F5065F11D857 +:101700001793AE6379891FD7EB08E0C5C766863F9C +:10171000F2635645CEB80BA3F5DADF6BF1E3313354 +:10172000E2479D72EE4DBB1F8D801F74DF1A14FCC3 +:10173000F8F8D5AB0B013FCEECBCBA10F063BDBEE0 +:10174000CB03F4B53BDF7718E0717C8AB74FC7F85D +:1017500052E1E5E0ED4757186F2F55BF328D4A141F +:101760006F91EE888EB7F4EA999F4C36C79E1BEBBB +:10177000BD4CBF6A62FF58517EAC7FCC951F57BFEE +:101780003299BF52BFBAFC75103C37A8C6617AAD1A +:10179000E1C7B747C16B8999E5A32C291245B91454 +:1017A000D6579B87E710FF6872F77057749D317E9C +:1017B000C037BEC85BD905F3F030BFE51B82D477D4 +:1017C0000D1DF70DC2FC96DA75DFA8C46154BB5B32 +:1017D000B503B5E3978C627AE6A4519E52B00B260E +:1017E0007D7111FD0827E11E2C3AAEC9FF33B4E725 +:1017F000C87E4EC4738C128B8336ED9DF72CF85D3A +:10180000EBFD4AFC721787F67AFD739F60FDD93DA8 +:1018100075586FD9CF05210EDA3C4C87725BCD7FAE +:1018200050FD3FCDFB4BD1EFA3FA7FE83CC6805D76 +:1018300099EC081B906F817D49DB35092CBEDBE4F8 +:10184000206E1958ED9E58BF899A1FB5C96B407A12 +:10185000DFB49FF3833D9E61F03987213C87892760 +:1018600092237C63FA28CF4AC87352F3EEE0FE9FBE +:1018700051E3D10F9A83E710F4EA7D2FB1F7F324F7 +:10188000C2E70509E986CC89C6B790260E11BA626F +:1018900079CCB351DFFE6FE2457DDBA7C1B75002C3 +:1018A000F9D23C4ACD63BE15F57DB5FDE0FC7E3F27 +:1018B000CBEF1FC8CF6379FC0DD309E9B4B332DC99 +:1018C000EBD408F73AB999BC0F6AE47D7419F2E1D8 +:1018D00082517CBE41E8C77302EA3D4E901F17FD5E +:1018E0007D139CDBC963797231FD28FC3F93BF07F0 +:1018F000E35571E2C47744DB4B8754BBB0543D17CA +:101900001636803F6A499B230C718F4356E5BCBA5B +:1019100092AFBCC41C3E06FE9A25CF67E279A201B5 +:101920007BE425A3E2EF6774DAC0FE24CD0B8FA21F +:101930005FA219EEA5E022FB363DA11DF98B7C8844 +:101940001F1D1AB023DFC987F363AA5C687033FEDA +:10195000D6B08763E70803B1E7C85E1E7565E58406 +:10196000FA5DA2F6874625B24BBF0ECE0CDF0F25DF +:101970003A7FA7F075158E5ABCBF5CF8A9F503F045 +:10198000A37C08E583067E5ABF9FEABF231D22FA87 +:10199000F7A80E1580FC53D57F77A9F2FB43054EBF +:1019A0007F6FF94D4627E243DF6E7F12F1A3CBDD57 +:1019B0009741F21BF6A724B1FCCEAFF83765DEDA0B +:1019C000BC0965DE9ABC8943FAF00C760F0B858F53 +:1019D0007370DE4442FCFB9ABC896FB04E4DDEC48E +:1019E00057AF539B37F1CC81A76C105A84F38BE02F +:1019F00027E9DDA6C77C81A9BCC5C3F2D97896FFCB +:101A00004A3C785F6FB3C98CFE106DBE1FE5542B46 +:101A10005B401FAEA0760A9C97DAD28E7A4463367A +:101A20008FBE55C86F14A538F9A4424D4A501A9C70 +:101A3000D706E70BF05E8BCBCC6BBB66B4D581F2DF +:101A40005722CE6F985F5A3D1AFD0F5F9DD7F65C07 +:101A500001C3FF372D9FA545DFA75B552C13885386 +:101A6000253A0751339A1BC85BC6F38A824CA2E51C +:101A700071A276B34733FBEC4D43F8FD00E881B427 +:101A80001B88D36619A8F55F16B9AFE13697F7F64C +:101A9000D1E9A83FE1FE9EDDFB078C4F3C934D440E +:101AA0003897F08C5EC67D96D309E2B59A7FA18EF9 +:101AB000734E89A35D2AFF593CFAEF2B171EFFBF17 +:101AC000CE7706E569317AFC06FC06E96F809FE86F +:101AD00059FC4ABDAFE56BE5DC95E6339AFC9244D0 +:101AE000EB6A065AA4F8F3CA68EF8B8C8E3CE817B1 +:101AF000BD5CF9975C46F52180C72EA304A466520D +:101B0000EE65218F66AB7E5C769FE79AE1A82F7F1A +:101B10006C66F355EF9B51D7F3B6163FBFA5DDFDBD +:101B200078BEF7E7405FC72B3D780EFC612BD3DB17 +:101B3000C2CFB33C7DEDFD29946ED87D32CABDE0A5 +:101B4000DA7B20FE38FA1F23BF2F8CFEDFD1AFFED9 +:101B500051F2FBF2D7116B7F1FB2B23CC888FDFD7A +:101B6000BFB6AECB92D76A5E747955BF129FE008BC +:101B7000C427D4719AFBD9B9A2A1CA7916F5FD8DF3 +:101B80008A5E7867B167189C9F292B0B3E0DE76B27 +:101B90009A880D7FD7A02970FF8E5F39D8F9662CFF +:101BA000BB587C95782D785E3FADD057588CF41B90 +:101BB0005A09F439C241CA21CED1E99A49EA2C988E +:101BC00037310AEA472C0F3DFDAB32CC1B6B017A53 +:101BD00055F3A6CB2F7EB6725A19CE17FDD50E63DC +:101BE000ECBD333716337B507D4E53E64FB73D1B6C +:101BF000E67366213BEFDBECF088E0F756E3F4C9CF +:101C0000523FE63934ED62465139D88A50FFC03030 +:101C1000A4AFA65D95A510BF25017329DE07FE2799 +:101C2000760FFF996543D03FFAB2CB5709F3B696CA +:101C3000F9AF07BB7F041D07E2BC67765E5FEA8BE6 +:101C4000C33733F95419E2E0993C093C2946F816A8 +:101C5000B5F767A37F7B6518FD6EA5C5EC7DB383E3 +:101C6000C9F5E6FD35649E2552B63862CF8B4D1A14 +:101C700035A514E6515A2C2879A42C6FD549D530B6 +:101C8000F0736AF1C9A9E4ADD62879D9443645F292 +:101C9000B173BF3E6F559D9F5A56F356932F30BF79 +:101CA00043AE68C03C17EB2AC657C97282718E6B6F +:101CB000C3FDD529144EF9DDC16B014E290076BC58 +:101CC0006F39F4C858FADE91265C0BFE9BA75BC700 +:101CD000F582FE2BACEEFF0E6C89D42556814B3479 +:101CE000ADD0DB887824B4B8802F55FD4ECFCE55CB +:101CF000AD4E46BDB23BA701CF559D3D6C8C7B2FB1 +:101D000085FA94C98A2C8893E4AEFA77CC63B0EE56 +:101D1000E2E29EBF7BB7D8A29CBB5A91057117EB3C +:101D2000AA7EB982F69FFB184714333A9BCB027FF9 +:101D3000B6A003F95AB787DDCF58D765AF32A1BC3B +:101D400061FE2572AD03E588B0FA461DF009A18D4C +:101D50006AB1749D6F17B3787A41B7A80339F5AFAC +:101D60005FF271E35E4F1447CEE700B81A8DE1BE13 +:101D70002C67242F493D97A3FAA706E4CFAEB9E814 +:101D80009FBAFC3CF4F0ED98E7F86506C683A6DB45 +:101D9000983D420591723F516CFB41F713297A8BB4 +:101DA0006A176BE9409BD79D5F3104E982F2D1C08D +:101DB000263186EFC5CDEF6E1598DE4DD7615802FE +:101DC000F3A8CC72833FF152F3E9B5F6F4809EA3F9 +:101DD000E825EABCBF69FEB95ADF0079E771FC1F4C +:101DE000AA5ED3A19E33FF92DD1F3742B1278E76C4 +:101DF000FEBF12764FA79AE7E267E754F4947F227A +:101E0000FE84AE93010F76D9754DC5180F6BC27E57 +:101E100056B3DFFF18B12A6F4545193C45C25178CA +:101E20001FDDB76804C69B295D14C4A18BC5C5EC32 +:101E3000FE06617532E2B1B09660D6A660CF403C36 +:101E400016D6317C5DA4D0BD9A67A7C62DEF2CF6BF +:101E50001D2B4E8FBAA7A53589DDD3A2E4AB5B5B02 +:101E60000FBF04F79F3CADC4AD7BDF183D13E38982 +:101E7000AB050EECC3F3F6B923C07F7756E1DF560E +:101E8000A19F8896687AEDC5F38EB907D8392D41A0 +:101E9000C9AB15563BB6027E9A9D3E3CD7F99D8E46 +:101EA000208F795BE2F127A7496077840D906777EF +:101EB000AA4D08AFB0A3FE14E327D3FABD8810C023 +:101EC0003C22DD982BAB47A9DF256A2F8D49A83F1F +:101ED0007DABF322E46BFC53DF16AF13F9A72E7F23 +:101EE0001DDA7322CC3E216FB07CAC38EB8AF15FF7 +:101EF0005EF175A97E4B6D7EDD203A66FE0FD51E24 +:101F000052E325C423C7E4BFF7EAC520E83D904F5C +:101F1000FCAA1BF4EA1F9BA3F3DFAE1FA38BBDB784 +:101F200092F8CD701F429D723E9A08EE5510B7BDD3 +:101F30009FB776817DD70EE71240BF04F87251E754 +:101F4000333EB0629E46ABC0CE6F10999DFF5832B3 +:101F5000AFE5C7D07E495BA608F097AB5A7E8AE70B +:101F60003B74C4DB4E9F9F2BBF87A3CE473DAF90F2 +:101F7000487E0E3AAFF035E72DB2139CB758A0E07B +:101F8000BDEB2E82E72DC82ACF569857779B40206D +:101F90003E9D3A8D95470826FC7D2633E47DA7E1DA +:101FA000F958CCCF0E5378429EB919F2BED3E03C1B +:101FB0000CBBA7939B390DF12F95C207F482763D98 +:101FC000BB9753BEC582F8543D8DC55B53BD06E437 +:101FD0003FE7881BCF09C8707F9F03F06C05E2675D +:101FE000D89A81F1E2D47CA6479ABD069DC9897929 +:101FF000DD88AF614ECDEB667CAF7BAE84F9F60336 +:10200000F774CE23B83FAB0BA666C3EF920CB9C9E9 +:10201000C0417C499533550A7E746F55DA37B2F664 +:10202000708F27CC8F2C61ED07EEF1FC3EAB6F1566 +:102030004278AF14D561947B2459FD92D919483F59 +:10204000BC722E97DCA69C2BE0D83D644B660F61DA +:10205000F536C607C9DD498A3C57DADF9BEA57E205 +:1020600005EC7C40BD4EB9EFA08B44C79F553AD3D9 +:10207000FE3E4784CED8F9922722E704909EDBAF3C +:1020800017310F52BD87B4CA6260E7CE4CB17435C8 +:10209000694C2AC3FB0AB709C65DEBF4FC644C5CCF +:1020A0003F8D7F6E345F19A2F295BB0D1ABB2C9346 +:1020B000C1D5167E9A9D4F335E965D96380EFA7C9A +:1020C000766C1C744776741C54DDDFAA8506E42BFD +:1020D000DD76E92DC897DA44410BF73A6AD7BD6936 +:1020E000E07E76BF19F452AD3D7828415ED4E931E7 +:1020F0004C3F7427F0439C1E93C8CF9520AE5C6A7A +:10210000FC5F8A8F33FEDB9BE03CE200BC54BDC920 +:10211000A48D7BC897E5F7E935FD10F9A0A75D20F0 +:10212000E6EB6859737E8EF241E48BF20AA3D8EE97 +:10213000003EFA43E48BADD4723546F1456A8E5EBB +:102140000DFCB8F74117FEDED55B0FBAF179CECCA6 +:1021500005F8B1F00CCF018DE993970DDF83FBCD2E +:10216000CF59C33970BF794A207516DC577E2E3D92 +:102170007C04CAB69FDEC1CA05E1A7E1BEF3FC9F9D +:10218000FEF27B58061A1B42975B12FC9E5C0CF712 +:10219000EE8756F6837E5FA63977A0B97F19CEC742 +:1021A000C27A322D068C53672AE792C964C53F0470 +:1021B00099694077D9A598576821D2AE7EA81FC6E5 +:1021C000E42EAD6F83FB7DDB0B9C2C6E4E181F2025 +:1021D000C394BC131292C11FD5EEB463FB01FD6E14 +:1021E0009751C95B63E3BFF72ABB37493D6F4D8801 +:1021F000381CEC468B4462CAEA7DE6441087C3FD76 +:10220000C3ED6ABC5A291FC8F48D2A89B25FDE9BD0 +:10221000727F31ACF3E3DD0FE4833EF55DE577E2F9 +:10222000B478F5D7B14C8EAC48FEDB1CE0E3EFF39D +:102230003637F80F9666FACAA0BF798EB6F1768A5D +:102240003F93C54AFC3DAA89F26C0EF88AFD6636BA +:102250003FFB642F37AF38F23B55E93E01FDF4C434 +:10226000D7CD83BE9D7EDC2B027C1A4CE11C81F60F +:10227000F381C33709FA3D3FF7C3FB308F70C87B4A +:1022800047E05ED4F7F45DD536C027A7720F36114C +:10229000F01C50DFD0113DCAEF6DB1F340059C1228 +:1022A000870D4E06B9700361780B65A8BF51B987D9 +:1022B0006EAAC8EE8D9D5AE6C4DF4F9C41C202E073 +:1022C000C3D4F7BD3602F471B3AF2CDE3D1BEA93E5 +:1022D00064E9A568FAB95E8A2A13C8B7882DFF9306 +:1022E0003BB6FCCF155F8E8C2ED7089E3B60DDAFD2 +:1022F000734CFEC81398FC11496005C8C7175AC42F +:102300007118577770329447BF3604F3A84816CB3C +:10231000BF1865CBF53338E46D867585A99CEF71E0 +:10232000C0EFB0B1FBC532DE376C85FB2088246D71 +:10233000063ADCAD77619E6986A5F6676DA8CF5831 +:102340004901F2296933E2B5D524C1EF961CB4B234 +:10235000FC89F6B53A8C37713693CE43BFE37B04E4 +:1023600026FFAD0BABA19E2FA71B426575AF9DFD50 +:10237000AE5BFB78A25F510AFBE67E1FF522AB093C +:10238000CF274CB6B9EE807ADE66C0FB2B0E5ACB57 +:102390007DCA7804FA7FCEBA10DB038FD653FAEDEC +:1023A0003533FF3A4FEDE3156C7CFCFD46FE1EA273 +:1023B0008C6F220628D7123C6FD06B17D97CEFD5D3 +:1023C000613C04EAAFC3F999B05EBDCF3272BEB7CB +:1023D00052C0DF21E088121F6BC3F2530A1F6CD773 +:1023E0008B07014FE58F0881FD986CBB8074C0EBB3 +:1023F0006C6EBC1FC843F21D1984F92CE8F77C866B +:102400001884FC7BFE1E1BDACDA0F940FD50F813AA +:10241000E95AF09072C53583E3798E021E8FE08809 +:1024200017F6E354492EF2A36775EF6DC0FC0A8BD3 +:10243000D7E8A6E3186E23B8BFEEE4F8E77AF7967C +:10244000303A1DBC7FE55990C7C1D92A2478B65BC4 +:102450002B2438A7D46B776779A3CA71F6C50F7898 +:1024600013D91753505702FBE19640BFF8FAFE68A4 +:10247000BD05D623E1BCF8216E09ECD07C1BED87AD +:10248000F27D775AFC759C52D61150EE2DD4D6FFB2 +:10249000BE4477A5D7A9C1BF6FB9CE8CD8755EC130 +:1024A0007986B82B304F3E87CECF12991FFD13EFA0 +:1024B00051BBC1A243FCBA41BD1FCA157B4E447B30 +:1024C0002E8490E51B81CF7C57C977AD4AFE17F467 +:1024D000E35F4FF57C906B7DC93FCC877CD3A92906 +:1024E0006D1D8C385ACECC037E6CE290EFDC4882B6 +:1024F0002BE1FDB94ADF33F63CE4FB7F2B190FF7E4 +:10250000E9FA46A6D2F2C7FAAEFCC54EE48B1781B3 +:102510002F5A4818E9EE06F8BD46A0BBE9FE0E2882 +:10252000D3315AF09E304A8740B72A1D0E9E3FA5F0 +:102530004BFAFDD0161B9EDFDA428278002F8B7497 +:1025400071CCDFD282728B48C323EBA4443BD5D439 +:1025500082EBF8799B8CF2E1BBF6270528DF5CEA79 +:10256000738CA5F39A35F613FCBD0792357724D802 +:102570009D74BEE963FF81F31D7CAEFEABF3C8FE24 +:102580005EF6E884B1B1F6A823E96F9807277136A3 +:1025900037A1FAE3807DAA37615E42E41C72B80E6F +:1025A000CF3B73295E9067EA39642DDF9D741DE38C +:1025B000BB1F2FB6B957E03D923BD02E6DBED9A2BE +:1025C0009E5346FDAB79A14E39A7CCA15C6922266A +:1025D000BC2769E0F72CE93F2E23F2BB34FBE0BCBB +:1025E00072D9579D5796F03CB4BC9CC5E907ECBB2B +:1025F0004691D9AFEAEF9BDC9BABFE0E05D3531699 +:10260000934BB26FE39C6346BD91A4E814FB95E93C +:102610000BDD13245126185F657AF86C03D6AF4F93 +:10262000F2E3EF05D5F15D88240D63EDCAFD0F7E61 +:1026300033FEAE98C15D087C428DB3EECEF7358F88 +:10264000A5FB34AFD893C3D1A5D41958FC94D2C1FB +:10265000E67EDA6A1A69790E7E6FEE7AD2F25B5DF7 +:102660001ED2C1BDF0FDACD19FB0DFA18BD0C17D2A +:10267000400726C2FC01372871A2D73FDEDE01FBEE +:102680007E8E23EC3C9A4B7B1ECDFBC3B12C9EA5CA +:10269000FC9E542CDF899AC7713D9B8783E7711E8E +:1026A0002BE3CD63101D123F8E4FF7B705CFCB6BD9 +:1026B000F0483B1F6EFFFD789E6FF3ED44E42780EA +:1026C0001CEF37033C870146E4C13A7DEB609DD99E +:1026D0009062099354ECEA41F3E62DB8AFB7CE1EF1 +:1026E000C8D399915D0E712236EE53C94DEBC0EF00 +:1026F000D17CBB1EF97BCDFE31A8A7F5C94611924E +:1027000020C964965FE3A6FF8379CD229E2976DAFD +:10271000CF4D620DDE0B77F3746D5E8EFC500B6D4A +:102720007F8B92E773EBCDFAA3D1FAE639FDA37A5A +:1027300080835C6769E127427F42A4BD73305C06F9 +:10274000DD4BD5C1F813A17A0EF4DF5E1140FE9483 +:10275000884FED1D3B709FDCC86F98EF73702CE2C3 +:10276000ED57E7FB6C57EEB17A4B1FC6FB51DF4EBE +:102770005FB079315DE7C81F15E3EF1B4FC9A87F34 +:102780006E2D2DFF78D3282CBF9D71FBD2F7A0FEB4 +:10279000E9422C4FD67D3207E8C1553EFB06F85D75 +:1027A000E8B7CCAC9FAC245F770DFD2EAB24771C33 +:1027B0005C6033D910C6EF6E1CDB7815F8632627F2 +:1027C000B1F2A1D23F8CC372AE521EF7FA2828BFD5 +:1027D000C57D32271E5F1CEDE2824554DE4E4E65FC +:1027E000DF4F1FF7FC10B0E32757B1F26877E5EA37 +:1027F0003CA8D77D3A279EBE7456E1AB93BE38D72E +:1028000091E680B030FBBDE2D73C1FE2EFCB78A968 +:10281000BC85FB06BC152C0EE7F5940AF07B6655CB +:102820001E56AEB6B465031F9CE1339441DC55B42B +:10283000383B44DA2EA5A2723CEC7B3555B721CE4D +:1028400049E9EB53A4AFAB3FC9B1A15EAAD297A8A7 +:10285000477A4F7CAFE4E76CDF62E981F6F705CA9F +:10286000CF6B62E5E7207AD5E0E1FF008B7F42C5C0 +:1028700000800000000000001F8B08000000000026 +:10288000000BED7D0B785445D2769F3973CB7D429A +:102890004248088409F74BC01912205C1D02645994 +:1028A000050C171514E1041002B98DE0EEA2EB9AA5 +:1028B0000901441777E38ACA2AE88080A0C80E0A73 +:1028C000C86A644764237EBA1AAFEBED631345E52B +:1028D0004E0CA2B89FFFFAD75B7D0E99338405BFDB +:1028E000CBF3ECF7FC3F3E3E9D3ADDE77475557542 +:1028F00055757575CF55CE4EE15FE60921FC891EF1 +:10290000473E95BD6D271A7B0BFEF74357592A6941 +:10291000427410FABF9521457413A2930870B95EF2 +:10292000D42A421562B2558BF70C12C26E6970E35D +:102930007917C5D3D745CF45BEC759D41F2F764A7F +:10294000FEA29F4053F1C395429CB67D922D5285C5 +:1029500008D00375383DF489EEA9D48F82A66ED9CC +:102960009595E04CA35FA1B85C69E857D62B757FBD +:10297000E5F7D739E8FD0CEEBF93A73DF093F8AC2F +:1029800057FC5CBA84F6B8A0F155A40BD73D5EBCE9 +:10299000DCB8324CEFA5D388EFF110B8D73CDE9A03 +:1029A0007CCFA264F5427C2DCEE65961FACE3491FB +:1029B000E851E9FDF79616B5F712B2D709BF0DE356 +:1029C0007D282E31904CCF2BE724041DF47C670723 +:1029D0006D00E8A15A022F36127CB3F0D9D16EB245 +:1029E000D577059EC70BF9BD0AFADE3D289D448FB9 +:1029F0003C898723A30D7A44E1193DFE56BE346419 +:102A0000A0CC107E86D3856795DAC67884D57F778B +:102A100023BDFF0B35A1F61E2A1FB2FA2C1BA8FFFF +:102A2000C0EBB6E06685C72380CFD24F12363AB2EC +:102A3000A9B40A8685C7C1F54B6E26FCE9BD254AB7 +:102A4000962740CF6B12FC8FE17BCDD556B1311567 +:102A5000DFF76D00FC7A757781F1458F27BDF6A70A +:102A6000424BA17AC5FF04DA05AA1DAECDD4EEDB38 +:102A7000D87FCCDDC874482AB265111C3369432362 +:102A8000C18ADDE9528869E973D2595ED7DE427C9A +:102A900020FE050A42DDE603EF475551E38AA40311 +:102AA0006192DD2A9FEB3D44B4F69063831E0105DD +:102AB0007269B728B38BE28926F877656BB9DE6354 +:102AC0001182F8D43DBFA30FE35EE2151EC80FD1FB +:102AD0004101DDC55E45A703C913EA15973FE0BA7A +:102AE000904F4B1BB36F45FD7E0BE14B6501F12B06 +:102AF00005EFC7A9F27DC5D32199FA2F4812FE1020 +:102B0000954B62DCB746D275B8C532BB28477ECF3D +:102B100049F49BADCF0603CF396B55A1E50A31C609 +:102B200039F7B1C3B9C0775887A28488FA7BFAE431 +:102B3000CCA1F75FB689E9F8BE677FEF9CE21C1E67 +:102B4000872F94C37C5C1102FEA3D33D010FF06B71 +:102B50005EE1017EAA68DEEC011E014716F089C91C +:102B6000F40404F0AC15B7E545E01F43F803BF3BA0 +:102B7000C6F922C76DE07D313CA3E97D313C2139A6 +:102B8000CEC154AFCBCD1C675C933200A51A7690B2 +:102B9000888A55D4AF33525F45C9B90830DF272E34 +:102BA0001D537498E42DD54E8F20A7B725043712F6 +:102BB000FE136F1BCDCF9529E7589EDBD17C745057 +:102BC0003966BC5B69243CDAE5BD6515FD21A78447 +:102BD00017F0B1360E9A4CF43DD6557B12FAC6C0AA +:102BE000FF2F839EF06A547FC8224A4239178E6FA6 +:102BF000B72E4F2ED16887DC5538E3C3EA800BE54A +:102C0000E562F8BFD8A1E839E88D934AC36054560D +:102C1000F676F17321B46C7C2FD9953D3A197AE29E +:102C20007BEA6F30F414FDA379D0B7BBF627BC77ED +:102C3000BD281A67A5F1B61BAFD9341AD738359E0F +:102C4000E773CB7685F5D5585F8C0574A93C680B86 +:102C500006095EFCAACA745ABC5E0D62D2B608CFE1 +:102C60005ACCC39680C305B97C286EC06F4750F913 +:102C7000D97A9BC7817E03BEB77B53BFF3743EF501 +:102C80005A6B116E832FF47F9F60AC70F76E85FBDB +:102C90006D6D6782FB873A9ADA5FB1B7ABA9DE1B2D +:102CA000EE6BAACF3D38D0040F6A18666A3FE48302 +:102CB00002133CB4F12A53FBE147A698E091CD37CB +:102CC00098DA5F796E8EA9BE34B1B07E298DB73E99 +:102CD0005D150AD9C9D1A2D4D4BE542DB30B62B1AB +:102CE000A8B57D0A79F4D37FCC4F75A615743EBB89 +:102CF000571129A48F16AC95F5C67B2575F7AD84C1 +:102D00008D5B18343F2F15D65618FAF793856F1E32 +:102D100088E8AF576AB12599CABF7B1252212F624A +:102D20008818F283CA7CF540DFB4BCAB7A1C42370A +:102D3000A5042F7E5A09DE437CEC297A3C04BE119F +:102D40009F45D00DBECAFA96756A3040FD7C5B5532 +:102D5000F2E6011BC10773D7422F2F20BD0CBDE542 +:102D60004837F333C66DE6675C6F333F133C667ECE +:102D700026E59BF999EC33F33365BC999FED8BCC39 +:102D8000FCEC30DDCCCF0CCDCCCFCC12333F3BFBB9 +:102D9000CDFCECB2D4CCCFECC022537DB4FC765B3E +:102DA000B5D854FF50DCBE2F34A2436A47D5E5A006 +:102DB000A9D7A3F676D3F7843AC1BE82E8559AA97B +:102DC0000AD5D52A0701FA4FCE6B3FCFAFF92407BA +:102DD0000F131FCE8AD5F599EE0BE5A162EF7D7634 +:102DE000CCCF1F2B0FC3BD663920B94BD2DAB06BE5 +:102DF0004669F099FC91D15ED20FD3BCDA582FE925 +:102E000093E9BDBECAB292DE1045C5BD60472EC76C +:102E10004FB10EFE117ECAA410DBE38BFA29EECE71 +:102E2000ADFA8F9DBF80057AF9C3793696DF65715B +:102E300003B6432E3FA8917279064D860A71830826 +:102E4000B11FF661EC239DD15F01115C198ACADACA +:102E50009B80FF4CE04FF6EC26D168C3C7C98EDAE1 +:102E600051160B37977375FFEC66115E89C17C9222 +:102E7000AACD075D2A54AD4B1AE8D1A9218BFDD804 +:102E8000D75380F445E96AE8EB77F027B57BC45B5C +:102E90005481EF8C71BA6F7DC00D3F80EC03F1451A +:102EA0004C4861BC85B5A8FF94FE6D7D6719DB8B2E +:102EB00017144D03BD03194E0FECAD480F3DA3D0C1 +:102EC000F8FAB6730FBC27B9B5FDAFBC867D21C734 +:102ED00086DA3FB92B96E9D5AFC3867618D78FED42 +:102EE000F76EAF6F39F036DA5F6ABC76BB67D1CF69 +:102EF000A8DF6645F8371212EFEA7CC974483F3103 +:102F0000534DF4D4806F71B3EADB131D6EEDA0FD59 +:102F10000EDF9F7EFD4F570256F6A7B817137EA708 +:102F20008B1B07035FA2FF83A82F7312FD6968271D +:102F30003B6BBD9220144592FEF447FFA236F197F9 +:102F4000F81CD0E9FF6207ED31C8F57E4B439607C8 +:102F50007CB4360C663EBAE4B84EDA255D2E468760 +:102F600082B8CE3341FF790E8747257A1628F2BB07 +:102F7000879366CFAA24BC6FB614A5855513DE4F80 +:102F8000A3BFB2F8E22E19C0DBA6E3ED6CAFD3DD30 +:102F90009D13E99F45E35D83EFC31FFE15F997D9A4 +:102FA000781EDE06F839E1E2F58BC322ED7273B5C7 +:102FB00012DC48F56FEA745E6FA37698974ED1AE37 +:102FC0009AF0BB66E48A0D68F76BCDC9786F169EE0 +:102FD000BE6BB2C10FC1FA3EF32E2558930DBFCA86 +:102FE000C3723F4F1465EDA276AF79B57AE0FFB7B3 +:102FF000B87F0CCAB6F0341EF42E7D67CFB20E9E99 +:103000007B008DB83CF9EF4D9A03FD4F9928EDCE2A +:10301000CD3ADDA689229EA7C6BA8926FCC90A6ACE +:10302000379DFEE2F59870F7077E33007B5BE7F58E +:103030004CD1C0E52CE1E2F5D4DBD51D7E761BB585 +:10304000996269CEB2AB98A7346FB399FEFF0EB9FF +:10305000F966DC5B8714D0FD0ED263E0F79AF69731 +:1030600025C79315494F9AB79FEBF3360F53EBFCE7 +:10307000FC19DB5ECA9FD5D5E39FCD1F528C891901 +:10308000E4AFFF44AA42F1D09944914AE36CE8AA24 +:1030900006B19E1AA7DE61DD45E36C207FC2817117 +:1030A000FB8A3B9EA6FAF1646FEF91FA352140F05E +:1030B000249F2AEE6139685CBE909EBF9E4FF5D476 +:1030C000FE956A919047F02B5E9BA786E470DC39F1 +:1030D000ED4012959348EF87A9F555E9F78D857F67 +:1030E00030BE13D991083B715577334C13A113F8B7 +:1030F00074B54EEF093966BB330976C768DF86DDE4 +:1031000021FDAA82BE710375FBD357F485FD79B901 +:103110006AAFF88CEC8B6187C608B9DEB8981DB22F +:10312000DA0B5206B23FEBB6637ECCC1FA04F476FA +:10313000691D2747CC97D2210AF3C94D86C742E3C0 +:103140007FF3A01A047DACBEF070D06FF18B0ACB78 +:10315000E9D503B5AC81C48753B6C6F9909B8611F7 +:10316000B94982FAFFB48A10E945F3B7CA297C3419 +:1031700017BEA872317CA42A9DCB63556E2E4F5486 +:10318000F5E6FA53551E86CB0716F5027E73567D7B +:1031900065859FEF167EF68F96D07A17FC5A92B00F +:1031A00058C236A70B4AF8AECEF5963882EF0A2AF7 +:1031B0001ED8C585BB822BE308AFD23A9F3D9EE067 +:1031C000259DDB8D8947FB071496FAF907FDF51855 +:1031D000EEA9773FBD6EA2681D6FF93985D7C9EF9B +:1031E0000FF20D46FF5F56E5335E47AB7C8C97AF21 +:1031F000AEA93E85BE77BC6A3CC3770D2C1A81719F +:10320000FBC457EC474CDCDE64859F31CEA7F8C089 +:10321000E7513E110C12BDD6DAA45D594B76057A02 +:103220006074FF29EB6F15D0FB5A21DEBFB6DDDCE1 +:1032300071F05727E517B3FF7AFDF782FD5743FE7C +:103240002F358FDCA2E15426F5773220E9D3B2EB9B +:103250001D865BAC441F1AF1BE5DA5A582FC83965A +:10326000736FCBE7D48EFDD4DDB2DD629B6CB77893 +:10327000F7AFDBF9002BA25944ACB78E131F85239F +:10328000027EFA17E95A847C1D6F17FAE623E8C913 +:103290007FB77836B29C6A9F3D0F3DBADCC57AE6AF +:1032A000942DF4C5C3D0B39DC9AE72BD3F6E0AC99B +:1032B00059855D682C7742EB07F878ACE0F800FAA6 +:1032C00073F792CF218F3D773CD4F597EED6FEB6BB +:1032D0003CFDFB96E7DDA80FF2FCDFB6637DC74738 +:1032E000082ADBB92216787D76EF7399185F2F557F +:1032F000F8559A67737FF3C7CC3F52FF4F906E41EA +:103300001CE3059BE7D45EE0B39EF0A1EF3C716F38 +:10331000F940E8B779BF5BD817EF07065A98AE4F68 +:103320003DB793ED3FC998670CE9A9FE6B5E5A96CD +:1033300041EDAF58D764E948A577935283B274FB47 +:10334000CEB7ABA9BF5C97C50F7F74C54037BF3FF1 +:1033500030B461A302BDFEFDE31D31CF72D67C55B2 +:10336000D0515CDC6F782AEB8396621E572D8F6BF1 +:1033700077DDD4776E14F04BC82301BEC5760FDB22 +:10338000291AB60DFCDED56D03DEDF6309B0FD0939 +:10339000CC917ECBC9A2C0EF31FE726A1F20B8DC8F +:1033A000DBD0741BD597277715883B1C092E998194 +:1033B0007A9ADE2ED0A762D703851D093E3942785E +:1033C00014EABF64F79942B66F9DC9F7C6F776D580 +:1033D000A4DD00FB96533048A5FA2235C4FD894A86 +:1033E000D95F65DD4EA7E0F5BC68A792224CAE1B05 +:1033F000FD7266047F2C8DBFC9B6D2F7DA937D04C7 +:10340000BE6BB30319FEF8567BFA9AB7680BEB2331 +:10341000D7FDC5F8CEE78417FCADCBB57F768B7FA3 +:1034200021E3932E5C81A1ADDFED6C092FC43848F8 +:10343000DA5D01FACE6657C30C6E47F06FB95F6D67 +:103440000FE65FA64A544F95F6BA06FDBAA6668106 +:103450005F97DBFF4371FF60BFABD292E871E4B5C9 +:10346000FA2DD3536A5E6C247E6DE8A0EDC7F88C0C +:10347000B8A4B07ADCD0E3810EBE97F1BCCC49761B +:10348000D5C2F6F415C0861F7CDE0F735E9E3DDD4F +:10349000D9C1F717A6E365B677EB7186F37AF5EC39 +:1034A00040935EAD49B00B2F3DAF59E3E0B884388F +:1034B0006029ABA7F5C7487CC2D2FABD2509033BFA +:1034C00040DFD708D126BDF6D17CD688B661B203DD +:1034D0001ACDEB51E79A558DE77DC3CB4979D09F43 +:1034E000C297E0461CC022B4087B17FD1DE2D70935 +:1034F000F06BB488135A84DDF489643BE6AD886FC1 +:103500007799E30E3F6EB627FB1F8F1CF788960F47 +:10351000E2E052113D3AA0BCD8B85ED4C7F5278C82 +:103520008BCA79438AFE01FC467EEDB2627C23ADF4 +:1035300093B3BC5D196F6B2EF53BEA6B8B19EFEF04 +:10354000634DF0E5E2FF3385166A90E3AFEC1C179C +:10355000AC83EDA771D42DCC0962BEEFB18B801383 +:10356000EB982976F66BEB1202097D51AFB84288D1 +:1035700027BD606B9821D739C2B5D90BF97DE3110E +:10358000C8FF0D2D7605F1A98E0EF105FC25A126AB +:1035900089CDA911DF6FEFE2B885EACC5C8FB86204 +:1035A000DD50FDF90C3B3FAFB109B67B8119B18C01 +:1035B000D79A64FF6BFDA97E4DB58C677E2082ABE8 +:1035C000BAA2FE0E95EDC070CBC6CD0F621D333989 +:1035D0009DEDC69AE4706625DA2FECEB09903CEC81 +:1035E000F987CAF6608DD797D12E1E7A50C605D7B7 +:1035F0004CF665C4A6A24CB360BC1D49CFF3F36C76 +:103600006A47E54736D9EE439D6F44E90CE8DB870E +:10361000E7F510D03F57E7168CCC65FF47C63BAFA8 +:10362000952C10336E7E80E3AD0F6B6A50CD065D36 +:103630007E736F4F826F98A3BA1077BBB62486E370 +:10364000A1D76A7A3C749A390E7B75AE6F642EF1FD +:10365000BF3CD4A7DBE108399E71738F9F433F7C49 +:103660002A645CFAD769DA38B4137BBDDC6E2F3973 +:103670002B3FC04E38DD03D87F9E67AC1BC3734120 +:10368000DF7DCD4EF64B2F260F42789C7DE9FB0F58 +:103690005A4408F2DC05FC4961B90DC06F0B846225 +:1036A000580EC64F71727CBD25DEC2FB0C8F11BF58 +:1036B00060DF02BBE53E03294AE6DF83FB3AB35DE8 +:1036C0009AADEBB19AE9B1FC5ECD4E5BD0023E2BD8 +:1036D000C16D5BF0DE8B316C3FCBF4386FD9F3FDFD +:1036E000580EF6D87DD92BD0EF3E07F3B92CD19DDB +:1036F000C4F5FF962250FF821E772E8B0DF7443CB7 +:10370000BB5B7B6D3EE84172C771F932BB7C7E28A2 +:1037100058C0FB1A82FC95B851040B1FEF4F04C828 +:10372000AFD9EC91FC035E5A4DE78DC057233CC0E6 +:103730006771BB8C971FA2B98CF11DF27766BC94A0 +:1037400029E3336EA6FACF16C7711CF55051FD5907 +:10375000F80187D2559EF7A4A1EE1D42F564731BB4 +:10376000EE21B872E1A76F0CA1A715351F66ED75A4 +:10377000B7D27DE6B2F20982E460E6A23B2689C4B4 +:103780008BCFD799650EAC115BE7B7B063B12661FB +:10379000D2EB6B727D3590C350AEB612E3AFCC2145 +:1037A000FF99E4E894BDE151C4498EBAB5BB517F9D +:1037B000FA8F5F6EC173616DEEC9F2E16C2C449CAF +:1037C000A5CC22E344A3F3B4DFE6B29D4D64FE55DD +:1037D000861CCCBFB89C06A917EFB83C7B70AC6EBA +:1037E000F31E85FA298DADABE0520D0E80BD3AAEC9 +:1037F0008413956E4C5F0DF3EA842B9C08FE6816CB +:10380000E9BF956E8D1EA7DC4F2CC51FBCEE0CD9F1 +:1038100087135E8B48F53EECC2737B6BFBEC563E28 +:10382000D277988F22FE9359BF44FB6D7D06DE430D +:10383000742F4DDEFB9BE1D917D22F1A36C67321A8 +:103840003EFA3C290A27629E1C57E43C3921A4FE1B +:103850000A6C8DD1D7FF128F537FECC078A4E9F3A7 +:10386000E894A2B7DBE690ED48F6E0CF94FE41CABB +:10387000DD8336CF5AB9AF66657D599A22E152474A +:10388000BA0BFE5647356089855C56099E2F841B0E +:10389000CFCBE33B32F97D43AF892221A0D74A77D2 +:1038A000646C947E9DBE0EC600A8FDA2A7647F80B6 +:1038B000A1FF8F3D99A9F72FE753345FA3E9F07E6D +:1038C000AE8C5BD5240CEEF0CFE295BDD33F5E0706 +:1038D00015F4A04DCEEB4082B423E4B7A44FEE8F95 +:1038E000FD06BBE9BBA712ECB37DF1D877303F37BB +:1038F000BEF769AE5C477689E27B47B5F925F84BA0 +:10390000E271C17A221A8FA3788FF07DF2C9F37C1D +:103910005625DF49900CF97233FD840DFCF9D06E09 +:10392000F0F1D64CD2EBA5A055D7563AEEF16A99F4 +:10393000B023A7F47DA33DC904E7C0DF92F6C3809E +:103940000D7E44CBE9B20FE767629F2A2D4FAE0F81 +:103950006A6212078824945941E8816AA22BEAC955 +:103960000EF27EDCB1AAF1F71FB6B58EE78B2A9F67 +:103970008F4CD07978FE5AAF13F373C13AAF734EC0 +:10398000043F6AB6E61E7413DD4F6CB562274BD454 +:103990005883BF19968AE76A2820B8DE097A9F887B +:1039A000DFFF06DACD5F973C508DD04F0BD68EF3FC +:1039B000CD8BE043BFAD66BEF40F99E12BF69A6163 +:1039C000377832E8C7BFE70D9BE1DC8366F8B9FCC6 +:1039D00066F507D8A7784BD0A9A06C517F807E0FE1 +:1039E000AA41AC33BADC51347522C147D6CDF5803B +:1039F000CD0BDE5B3618FC3BB9FBAE3DE5F4DE914A +:103A000076160FD657C745E8FD89C48FF975F7D9E3 +:103A1000AD6E8CD72CE77B2CBADC3E29E37A0B8386 +:103A2000E6FA0BF543B51E4712BD23E52A9AFFD4EB +:103A3000EF753E42AC6CE9D4FBE1FF944C2081274A +:103A4000FC8686EEB38BF8CBE927C072634D14E198 +:103A500074C2AFE9AE048EA70C5B3A467C46DF2BFE +:103A6000B7BA0663BF7D8E5371617FDB889337EDF4 +:103A7000CCA8803DDDECB278904CE1CAF7D767E680 +:103A8000613D21422E0FE2F477AEC43ABEC49FC816 +:103A9000F45928821C679FB3DCD1AA1FE9FF79ABD8 +:103AA000A3F05913514FE32859676EBF68D30F8EA7 +:103AB00048D858970EABDBA062BC37EB78AB0199C6 +:103AC00037304C8F3F1C4653B2377FEB56549C87A0 +:103AD000F66B46CB7AAB53B7B33E5EE795C7DBDDFB +:103AE000ACCFAC6FADE4FD1A9A87B00F0713E6FFB9 +:103AF0001CFAEE8C53B81C9C47A231FC458A5C171B +:103B0000F23E04B53FB34E61BB5E9E22E1F2C79523 +:103B10002062BAE508C2027E42C65DCB747A404E8E +:103B20007C11E301BF2261516BC4BBC3BCFEADF08D +:103B30000B0FFC00417CF499F6BDC3F623B0B30132 +:103B400025F4B017FE9EF93B957B7F7044C2E7E3F6 +:103B5000C5C4BA6AFE7E90E9A8DA850F7A5CBD33E7 +:103B600096FD763200B1B0EF36DDBF16AB82ED6167 +:103B7000AFD6C05E51B942F7C303F7497BB526D92A +:103B8000D7D385FAFB323CA0C30D8ABEBE855F9FAA +:103B90000CFF7A3FF7DBACB85C1B93D15E0462523A +:103BA000D9BF96EB847FA86CEF9AC97FC7FEFC1A39 +:103BB0006F280C7CD63C90CDFEFA0B86DDBB3746D9 +:103BC000FAF317FADDEC5F89FBA5FFF891E0BEC5BB +:103BD0009EEEDA863C92F3B96A116F2ECD5BE6CB8E +:103BE000C077E74DB15BC00F517279FB1C9BF53C70 +:103BF00098661A2FE2EF8795A27A4B841FFC4C9EA1 +:103C0000B40F830B7C5BF4761EB49B67798BE93031 +:103C1000CF225C58CF6F3EA70A2BC19B6B1DC1659D +:103C2000F4CABCAEBE9E8B73F09E8C371DF24A7DEB +:103C30001F97277C41E87FFDBB2FE4594CA5182B2B +:103C4000E32C8763A41CCE1445851CEF770B53FE31 +:103C50008551BE9227EDDE3C7B83199F4F5E66BE89 +:103C600090CD732D837C8F957EC7E15B14B6E734CE +:103C70009E9E2E8207FF2E86E38587757B64D097F4 +:103C8000E487F3220CBD95ACCBCB9ABB83DB628877 +:103C9000DEF7D9486EC037921BE4F910DFD92F5CEC +:103CA00033238DF97E83CE57716F02F36DB8C52231 +:103CB000E97C6F06D399DA8BBFE3BD716EE9CF5F04 +:103CC000E63A8CF8FE37F03D7A3D66F05B58838328 +:103CD000FED97E4CF9734FEF0990FC2FFAC303898C +:103CE00082DA1DB5D6A679E8FDB2CD2B127D541E21 +:103CF000B106125DD4FFD1A03A3ED806BD3B0F52AB +:103D0000F4F5902F11797415BA1E3FF6E47FACBC20 +:103D10009DF0FC4611CDD08F15BBBE5B793B8DAFBE +:103D2000DEE76C863E3D626D2C84DE5D581CEFAF95 +:103D3000F660FE9AE3F28B9E7820CDCDF40E645AA5 +:103D4000D279FE67E2BD8A4D360FD67515EFAA1EF1 +:103D500037E6BD685E09FCA2DFAF0C7D6607FD5D3E +:103D600016D1DC69781BF5A291F57CE5AE5F7FA5E5 +:103D700026A23CFA11D6179551FB0125FA7E49F48B +:103D8000BE40C2A084D42F10F0D6F7A3893E9C97E2 +:103D90001020BC7AB0B8C83872CDB6870634C16F6F +:103DA000D8F45AA292D3BA1F60ECA3B484E63E863C +:103DB000B8EAC5E6E5A9A838B0A1C7DC7B1599B477 +:103DC0005827CB325B3811FE7ED9061BEB91B2A788 +:103DD0001FDFF230E4ED4387A7871BF0193BF44166 +:103DE00099E26B5658BF8B4465702BBF4A9FFEBC4F +:103DF000F011F8D719AA9840FC5AF4EC59D9DE27EB +:103E00009A63A87DE9CEA642AC0FCAB478BFB30DC1 +:103E10007E8D09BD646F8C6F835FA1A6428E536D4A +:103E2000FB96F971749F223A645FF87EC986CFEDE4 +:103E300042AE0F9A539225BD60EF2A436AB13DE925 +:103E4000C2F6F4FD49CFE771BD0BEB954BF1F124C0 +:103E500068C1F29E2090C758F291233801FCDDB171 +:103E60002411F94F5F5AFD52EED7AF48839F576236 +:103E70000BA4B9B894CF4B1EFD19CBE302C59FE646 +:103E8000E2BC2DD2AFF93CDE0C8CF3E675D7F238EC +:103E9000E70B8DE5B164BD5A14A4F2AC558CDFD9A3 +:103EA000C6BC796890D4770E71CB00CC93B3F4255F +:103EB000D8F12FF5757DE06DB99E7688294991FB83 +:103EC000432583A45E0C88E021D881CA061BC7293C +:103ED000D4B7CE16E23BB7665BFDC8DFA0F107742E +:103EE0007A293FC8F58B1B790C95F88BECE998B7CC +:103EF000C67568CCC1F75BEC3751BF5F639DE83195 +:103F0000BDC774FB72A32356B982CAB4B6F3BEEA26 +:103F1000CFCF7FF1B68890A7CAAD5FB23C89745508 +:103F200024A54B18FB11AE39F1FE24A2DBD7EF7E9E +:103F30006647FC3B906A113D806FC3E70C0B4F7BDB +:103F400037DA1BDFAFDCEB10E1C879BBE9F3A87906 +:103F50006DAE17C2CFF4AC14496ED8EF2FEDCD85FE +:103F60002FA01FEA7733F5339FFCAFB0C9BF6A2E8D +:103F70007C04FA64AFDDC5F107F23FC31172737EB2 +:103F8000BF53DFE75BA0EB83683A44EB87FBA2F407 +:103F900083F1BE58D7F6FE52AB5E08303DCB6C22A3 +:103FA000003FA3EC4307DB8FB2A7E57C14A44F7B53 +:103FB000D0FC38BEFDE5F76FC07A36644B9DC0BDBE +:103FC0009AF56FC9339FF3B8E612FD633CD0BFDFAB +:103FD000DAB1FE4D1F239A1D84FFF1D55E3BE4FE4E +:103FE00082794CCFDB9CC7AB15D66FFF55BD4BF428 +:103FF000E6FCC04BCDD70517D1BB7551743D2B7274 +:1040000092905E2D5CC55D78FF208ABE065DA3F5AB +:10401000E8B441EE36F528FD7B5F44D051884696E2 +:10402000E36F482F625FAD62D3776CD788ACCDC8A1 +:1040300027AF087EC5F00AD835865F9A8678E58571 +:10404000E336D333BAFE4EC818FD5FF4471BFB05B9 +:104050006575326F91DEE3754725E2F5DCBAB63E51 +:104060003335120E46C1A1A8F6BE28B828AABD163F +:1040700005FB4DEDCBF6BECCEB2CC2DBD4CEB1F4C0 +:104080006A5E875CE85704791C95BBBEB207201FA7 +:104090009D9AEDD08BB665229040EF37BFA8B2DF76 +:1040A0007BDADD9C083F65458CF4E34EBB7438D960 +:1040B00080C5EC62C2E37460800B7902CD3132DEE0 +:1040C00072BAA839313962DDDE54A726BAA97D63F8 +:1040D000508C6F3BCFA586E753A3B858BDF4E7C615 +:1040E000A9DFEF90F99F5681FCD8C6EA6F77209E32 +:1040F0007498D64FF05FE6555F9F88FD97D375DDC6 +:10410000AE998E75E0ABAA9069D63E3BF220E64AA6 +:10411000568A2322F0E0081A9F9A9057FF02D6573A +:104120002428D8FF9CB73ACABF11454961ACA7D72C +:1041300044E72B04EDF06F16909D853E2A5967AE3B +:104140005F54779CE7CBA2A8F9A2E971E3E8F9D222 +:1041500075B09EB7E0155E3D7F92F3F44E1F545943 +:10416000BE5A96DBC4CA5499278BFC92963A997F23 +:10417000D3B257C222A0E7F5E8F3D6A0DB09CCA75B +:104180005E17F75B4EECFEF7C1BF84FCECF97800DC +:10419000F6894FECF9B0E70B809FFB6BD6C7E2C204 +:1041A000F663F67D378BF1DAE710C0EBF4BE57B259 +:1041B000E06F9C7EDEC1F905A79739D85F0FEC4B05 +:1041C000E0B8C5E9CED21FAE79F1DB018D6C8F97D7 +:1041D000331F270EB64BBFAAEE3FD83EB6D439DC0C +:1041E0001847E5BE389E5795CFC7F0BEDAE917BF2E +:1041F0001D1C198FFBAF8EC7D8573F9D20A63F03CC +:10420000F9D5FDFFCA17863E5E8DF5F2AE97EC73C9 +:104210009127F2A7FF3300FAF5F4332FB1FE3D6585 +:104220006B7C14B1CDE97B321EB10D455C8F3ED65F +:104230005188AFF6CCB811F3E742BA483A9C263A17 +:10424000605C449712F8E517A347E5BF2C3DBE9A82 +:1042500025F5DC10817D9F56BA283EF93C81E35557 +:10426000347EF97CDFB703A0872E35DE7BFF1F1B72 +:10427000EF53186FFB7FC5F14A79CF1DEC66FCA2A6 +:10428000E5FE42B97EEEE70CEF48F030BE9739DF2D +:104290005FFB971DFFFF0CBF8FFECB8EF752FC7E9E +:1042A00055E777820BFBA0A75FFC3F59E2478CDB09 +:1042B00039E45F755EFFF3711BFE7C81EA39E8A586 +:1042C000F6AF89D0BB9E6CF64ADAF447060D518CE6 +:1042D000B838AFA7C6E02F37DA0F5C8E734C01F207 +:1042E00027B08EA9891F78E02D825F213F41E57DAF +:1042F00059194F7A25DD1B94F15DBF403CABE0AF0F +:1043000073197EDDFB9303C82B2954653CE6E56AEF +:10431000CFA6061AC7CBC91637CE958DED34F7F068 +:104320004EAA7775545D589FD574CA75BA23F01B91 +:104330001B6F5E675D1DB54EFAA9DB5C3F5E3C936B +:104340008AFDBAF1393681F33685681FB1AE4C1952 +:1043500022CFF7FC54D42E77C5FF783ACDD5E94467 +:1043600074E17D9B402755CF7333D34D806EA9A058 +:104370004B2EFBEF01E139F016C156DDBF12FAFEFC +:1043800063A133610BD6D10E51100E127CD66DE5B0 +:10439000F3935641EB61394E5E4747D34DE8EB6AE4 +:1043A000ABCE82B19DC68441673CEF926E7A9FC7C7 +:1043B0001D4DE71F4FD7FD9D9680AEE9099E20E475 +:1043C000A2D3B3A988B3D6109D15A5959E069DA22C +:1043D000E99E8FCDF541ADF4EE64F55A31CF46EA52 +:1043E000FEFC586BB2843B35A8F25C5E90DB8FF923 +:1043F000DA63853F323A3E99F343857E6E42D5F7C4 +:10440000C39161C778D0FA1479B693ADDA92219C42 +:104410005FEF120558B7168810E2B74ADD2BDF614F +:104420007D84F32245BCAF59FF01E05E382F86FC46 +:104430008E75D613A6F36E51E72526E5EF1C0D7E8B +:10444000CD594ACF10C772B9EB311F8BEF77B8C186 +:10445000BF4ED606AEA7B596AB7A2876AB430CC74F +:10446000CE234F3F03ED5E19CDED970897928C74E4 +:10447000BB109F778C77C97C355ABC7E03D8BE3C75 +:10448000C15D23E32602F2D41D65577C5FB64F1F42 +:104490004BDF43BE9BD0D85F8EEDCE9120D1552906 +:1044A000E2FDF72EDD645E44F30A07AF778AEFEA98 +:1044B000DC137A694281396EFDC510B9AF69945336 +:1044C000F3DD729FC2E249C777E62CEFC3EB2F35CD +:1044D000B6A87C37E8B8238EE5BC78E54D1307D144 +:1044E000F78B77A47880E6B1493B07CBF6337EF6AD +:1044F0001E3DD7B6C6F0F39FE76B8F0F419E81E25A +:104500009EB59B1ECCB9F6657B3A75A185269F4466 +:10451000DC715260E71BD8E79C344DE5F69384CC00 +:104520002B15CBE378DF7C62E02B6B3A7D6F222D7D +:104530006A50DF14E3CABA85F02FD6E3CD7FD0E707 +:10454000A11A2BB467E28157E79E5DE9F94421F394 +:104550009BA3E7ED71BD7D97311E772AE8A3C4B810 +:10456000701ED6688FEFE0BB5FE9F4785E2F0D9880 +:10457000E8CA71F179AB1C4DDD1251DAC2BDA8EC6D +:1045800033AC601FE46D425751B816DFBD4D151BAB +:1045900019DFE6628EB327F476830F9AD0CF77AE19 +:1045A000E9C1FB394DA305CB4FD37DD906BF393FB8 +:1045B000C958CF358DF6D4237FAB79B4D3B3D1832B +:1045C000FC9650187194436BE57E4D979A7077E88E +:1045D000D966AFDC07F97C69AE1B7272F303531323 +:1045E000A13FE7AE51C30EC8FB6A73DE9270793803 +:1045F0000F7C6EED683BD6AFF3E27D768CEB4CBE64 +:10460000F611F8659C73EC0B9C708EA7B6F875AC30 +:10461000FBD4449ACF987F567722D6D5D1794F953F +:104620007A7E9301FF3A4DFB0CDF9B93E4DE01F9A8 +:10463000F87469378EAB76CBD7CF575AC3DD419F1D +:1046400047692E607E3E3844CADF8476AE9EF12CE8 +:10465000BF3102E36AB2B97A429E9B56C45840A762 +:1046600009CBA41CDF6D95F32BE8735B02F4FEB35A +:10467000789FBE3BB3DA5AB481FAE9E414D6847663 +:10468000B4CE1DA63D0FFE4C0C541FC2FA7AAE6E7E +:10469000AFE6AE96E7C1BA8C917C15D686B129F407 +:1046A000FCC8E6EC81C87337E466FEB082BF0F89B0 +:1046B000E0FF84025F617BFACE048BBB057A78DE73 +:1046C00034E5A56E520E7E18C2EBF93A9EE72DA492 +:1046D000271CC93807D82061E4AB426FD43EE4738D +:1046E00046ACDBED6217D7DBE7C97CD42EF670351C +:1046F000E75FDD225CCB08DE427E84D526C4D62A65 +:1047000027974F5691BEEB21C4F6AA74867754B909 +:10471000B90C55F5E6E7CF547918DE5595CFF09EE4 +:104720002A1FC37BABC673F97C55113F8FD63F73ED +:10473000E3E7B33E71F5245E0FBD506E66B9092FF5 +:10474000E81FA770DD85F34742EABBE4DE52FF08AD +:104750005D1F75ED23EF03E8962FF9615B35DAC233 +:10476000E737AD8D1990BB71EA89A79F43BCA3249D +:104770009EF3B25A4423CF931661E173D9D03F0E12 +:1047800092BB2E778ECF8ECC3BBFB14411D608F9A9 +:10479000BAC91F23AC11F669F6D264133C73E93B26 +:1047A0007FEE40DFBFB1AB96974F781CBAF38BF525 +:1047B0007FA5E78FDD79AC873CA7FBFD86C8B84BAA +:1047C0008B6896B0D5C9FBF18FDD9E9196A2DFD3A1 +:1047D000007E19E7A4BBD89B8F3E8179B842F52CA7 +:1047E00023F823F087E8F989CE9FE215DD56FE0213 +:1047F000F3DAE7F428F49D43B7F72BCCA7F68FE95B +:10480000FB51179CAB4E97F6EB53D8AF6469CF0AB8 +:10481000A047C3D26E7DFAABB4C05DA8BF25D183DB +:10482000130DDAAA0E810504AFF6DA3D2AE27A7595 +:1048300082EF5D201A4BBF226033DBB1C64EC988C0 +:104840005B1AE79EE3F2824E3E77451D613F664E5E +:10485000EFFD22037AA9567161BF06E7349DEDA0F2 +:10486000DF14DE1F451ED034B29737E5AB3C3F7FE7 +:104870003FC4CAE559D873A26B8CF0707C66DE6ABF +:104880006A0FFD58EBB5CF8FD0BF73F4E7737B5B36 +:10489000B8349E97E17BD83F5CE59D0EF9E888FA35 +:1048A0001C9403A703BF8EF185562562FF777EBE59 +:1048B00055EF5FF67B169392E07B7A77B5DF9CC36A +:1048C000E7ADD86E19FDCCE93D706557D8EBD5A39F +:1048D000411D5163F3A4A752BBCAF3DF71497FC4E2 +:1048E00029F3B3CB2E62378C38DD11FC29CF3DF292 +:1048F0007817ED786A07CE3D2CFAD8C1F66BD11542 +:10490000D22E899CE0E0A91CD034C7C5C73E75B241 +:10491000FE2EC2E724CE2521DEBFEB333BF24369F6 +:10492000DAF8933200AB4DC8338D8ECF1ED8F171BB +:10493000629B71F15DEAE5C5C595EF1361178CF1D6 +:104940008C7BF16C1AFCAC4AE51CEF3355BEB822E7 +:10495000ADADFCB0E8B8F8F9F8B958FD15CED757A9 +:10496000DE71A4CDF879741CF0F1FCE8FD88F80242 +:10497000E889B307D520F6D35B823D92441BFD1B2B +:10498000F1F3CAB5F4520AE6A53B09FB61A72FE291 +:10499000971FC997F6FDA41E6F3FBD5DE5F5D2E9EF +:1049A000ED0941F8A715DBEFAFC73E65C52685DDEC +:1049B000F372D1C0F4223A0A67A41D43BE5B0A9C7D +:1049C0006B7712F495815FE953097EC8D5C290E2F6 +:1049D000DB4C78B438DD49ED23F03800B96A8F3C00 +:1049E000C0D060A6AB8EF7F3BA1E34DA2DACBB9FF5 +:1049F000E3D2D4EE14FB3B7F88139C27289ADF0078 +:104A00007EC7D7E57AB0AFB830B4B382F33BB6C750 +:104A1000B9108738A6E7391BDF69D0FB6BC897FE52 +:104A2000C9717DFFEEF80E79DE1C78623E1D53CC15 +:104A3000F982EFEBEFBD9F2FF7CFEEC05EE2A0D67D +:104A4000F60B434D89DDA9FD977BDFE1B2516FBFC6 +:104A500030BE6100ECEE97BBE2783FFECB5D8F1479 +:104A600022CE7C32343A15F26F7CFF54BE8DDB9F30 +:104A70005CA78E07BD4450E6D99483AEB99178A661 +:104A80006C086447CE33996F747CD7B389969C5673 +:104A90003E963BFD4E9CF7ACDC754B11E4B8DE2630 +:104AA000E969DF35398063CC95755E01F9E5799662 +:104AB000C1ED575922DA396C1EF68B6D7B8B7D6800 +:104AC0006FC4A117EFB6F179C15957B8AFBF11F351 +:104AD000F0351BF361711FF7F59C8FD4A072FEF2C5 +:104AE000E26C1186FFB1E4B6840DD80F33F09D95CA +:104AF0002BE77BD92A45F8685C6541790F4747E287 +:104B00007B00394AE98D83903FD9941DBCBB672A4D +:104B10009FDF0DE3FE1623CF94E6714F9C73EC30BC +:104B2000B41D8FFBC119856CEF0ED945007A21F0B9 +:104B30008CCCC329EB2AF3A31F86DCA3BF76E19EAE +:104B40002934DE133A5FCBA6847B222FA3EC990C89 +:104B5000CECB386197FBA5788EFDE2B281F47E3C26 +:104B6000DFCFA119EF2747C851D91C8F1BEDD47691 +:104B70001EB7371EF8BA4EB1DFBA3B41C06FB53C25 +:104B800097A0E757C5701EB9F15EBFA152EE8C7BAE +:104B90003FC40D321FF3419BCC577D707306DF7706 +:104BA00061B47FD0A6CD80FF8471C05F5F68AFED38 +:104BB000897D1703DF8589B58CE7095DCE17C6D6D9 +:104BC000CABC70FD1C31DA036ED2F3D89BB73938FA +:104BD0007FE55846C337C0F7D8B63EC88101BDE768 +:104BE000EFE57AF21F899F8B9E7484517F749B8CB2 +:104BF0005B1FB505BF811E3EBA3E85CF471D6D1FA9 +:104C00001CCCF9018ACB02FFECA8A2C33617FB9596 +:104C10005DEC0453FBD4586141FECEF8296B67214B +:104C2000BFA1659303E2298E6D79288DD735C29D8A +:104C3000C47936075501BE1D7BF23FFA44FA2F4670 +:104C4000B9689339EFAE295B98EEC9B97AA89C97F9 +:104C500057EBF4BD66A8B453E571A107BBF2F82485 +:104C6000BD893FBCBEA3199AC0F9134FF750A037B6 +:104C70001E16C19F7F9CC7AB6C37F2E6CB9ED9F660 +:104C800006F66B8F594403FC0FE5CEAD3FC77D1B85 +:104C9000A9BF49623B24C4261EDF51973CA74A1393 +:104CA00096C7BFB08384174DDDDA13703DD91C85DC +:104CB000E6D7228BC2FD2FDAD39FF3ED881F16DED5 +:104CC00027DBA9EAF8904F09FA6D91F9CA13DA05C2 +:104CD000B7C0DF6B5EDF4DE0FCFA3875DD00F0EF4A +:104CE000CCA6380BE4A9FCAEE149C341B737550166 +:104CF000FFE38CD5D321328E104DAFE83CF0E0506D +:104D0000A99FCA700F0ECDABD23DEBF9BE9052C831 +:104D100025E8F2A4C2FBD8A52B873FC472FA864DC2 +:104D2000F4A07E4F84EE4F8CE4CF3D43A55F70FE30 +:104D30003B760FB72FA5F6F2FDD71219CF2D36CE41 +:104D40006B89E6EB65BFFFA47A59EF9F1F7F88FC54 +:104D5000820117D2E18C68F8F9C7F4FDAFB7C7F04C +:104D60007A9056007C8EEDB82D341FE33EFE740C15 +:104D7000EBAFE3C9524F7C49FA34D00B785CFD5B52 +:104D800096D3B7A7F279BF0541F3778D7E7F3B5469 +:104D9000EAF1F2144F12D69DE56F4A7D48FCBA86BF +:104DA000DF7FD3C6EF478FA3427FEFFC3C7D3A8E77 +:104DB000E5E27847C98FE33B7AB17D6A4A76099686 +:104DC0009B6D36596F0B65C10F3EFE742F6F4DC43E +:104DD000778F2787B25C11CF9B6CC19543A43E6D42 +:104DE000C6BA588449D50E467E91603D6FBC57EADD +:104DF0005CDD003F05F9BD8307721976B4BB304F07 +:104E000077423BB99EFC529F779CB39AA6E793B337 +:104E1000DF13B2438F6BBA7F58B63D3ACF57D6D720 +:104E20001BEFD3BC4B35F28A2DC037644FE7788334 +:104E3000703F43F8962EBF6521F2C74BFDF7DD08A2 +:104E4000FFA9D42AC6DB09AF2645653C9A62C4ECAB +:104E500029F02323FB89F0DFDE6AED47E0DEB6327E +:104E6000FC41F3E0BDA16E293FB0A4F4BDB2E5CA98 +:104E70006A7CDFD02F1C284C6BA513F25A91DFD32C +:104E8000345AAFBFC8B89B6CB23E7ADC063E478747 +:104E9000CABCA0A66CF76F47802F7F51F97CD799C9 +:104EA000EF7393DAB5E1A7B5DA7B7B6B9E2DE1FF5B +:104EB0000D7C6BFACEF3BABE2B25FC8067CF75E66E +:104EC000BCF2DE9BCC70DFED66386797191E506729 +:104ED000863D07CCF021BD5FACB3710E19EB6C942D +:104EE0005867BB1D729D0D18EB6C945867E339D65B +:104EF000D980B1CE068C75366083DE586F03C67AD2 +:104F00001BF5BD86497D2E7CE134E46B5658649ECA +:104F10002FF1C3C7E79866D84DE7524EBF28CFA5FB +:104F2000903C487DBF309EE7C9C36831147649CEB6 +:104F3000A7D4E71DC165F4DE38B7963C0C7662ED68 +:104F400057F32177155D1B39EFB569C52B3DEFA7E9 +:104F5000768D4A82805F51B1F6AB59F0A33AB8B56D +:104F60000EC3089FCAD8869543386E1F66FDD15878 +:104F7000ED7EF34AC9478EBF14ABB8F982EA4BDA2B +:104F8000B5993F149D772E569BF3CC2F95771E2D08 +:104F900007861FF898AD39C3C5EBF4118F22CEBB3D +:104FA000584970619DFE598C5886FB8002AFCA3CFF +:104FB000B59683369937B05AD92822FC93413ABD29 +:104FC0000D78EEB95CF6C7CFC3AB158BB84288EE4F +:104FD0005A7313D6D7674A2CEC779F2929286C0F70 +:104FE000FF8FD6659813B86F2B125FDCB715293F7A +:104FF000B86FCB7C6EA2A3A93DEEDB329F9BE86B22 +:10500000AA9FBA3AD7543FAF68B8A9BEBB90F82D53 +:105010005928F19B47F6C197027819E72D2E01EF29 +:10502000C84FC952022B592F6F50F8DCB87BE9AA40 +:1050300042D0E5048933E20886DCCCD5ED8BB0069E +:10504000EC90BBB3A9B2FEA8D2F0C55DF4DE496F07 +:10505000ED165C8572D2B2EEC1116EE4D76FC872E4 +:10506000D13CBC5509A541F5140CD234C8D9616BAB +:10507000E364DE4FDCD9BE5D35FCCE8383DEC847FA +:105080007FDB55CE9B30E425CB26E3741B689D0166 +:10509000FF6A43ADCCE7DD509B12DB3D62FFC518D4 +:1050A000670BF820502E4B4BE5B89068C038C86F9E +:1050B0005F06BFEDCC41E9B71BE3E9BE3CDC690903 +:1050C000D5DFBA3386E973585F379CE8F3D20037EF +:1050D000CE6F54EDCD52E10F58B66FC13A22215533 +:1050E0005B0AB92FD9D0E3AFB8AF6BD17BAAC07937 +:1050F0009ACFD78C491C4ADF39F6B4CD3381E0BB57 +:105100006A1FB7639DBCC81AB4731EE6B60D76E479 +:1051100025FF64EB067E3E7F6B31E75D2E107E5EE1 +:10512000471ED1CF6519E32E2950D6B948BE3E1A85 +:1051300026F56349ACDCCF2379FE33C67566ABE256 +:1051400085FF38AD68A7BD989EDFA7B7734F9F3E18 +:105150000EF2D71292F76DB4BCAECA7BC4A6A932C8 +:105160002FE622F7F34C3D97CDF23DED5C3F5E67B5 +:105170005D1BEE23D7B139527FB4D4A9BC1FD7F23F +:10518000FACBA953F1BD3A1BEFDE95D81BE4F97FAA +:105190008BF0E31C817B7A8394AB6CE187FFB7E4EF +:1051A0002FEFD463DE2DC976BA311F8A46A826F9BF +:1051B000AC1C1B6792DFE9A29DE91CCD75482A89CA +:1051C00080A74DE8666A7FFDB47E51FA60606B3D52 +:1051D000EB836151E7000B4C70399577403F89AB09 +:1051E0004CEF958B29ADEDB01EDE24FDD6F25DC9E6 +:1051F0001BB12F5E6291EBA1E99A7C5EB1573E171D +:1052000022F6FCB9749CC7477CC0746E5BDFE74331 +:10521000BF1C0FECD6C0719DE60CD29744D1F2DED4 +:105220008D76C4D3C85D6E469CB43C4030FAF58997 +:10523000E61A9C1FB14AFAC67B5C5D9765B4CA4505 +:10524000C52E73BE55C5C177B89D91CF185D4F9ED1 +:10525000EFCA8EC07B82E2E57393DB9BEC88074D3F +:10526000D33AF1BD14D1F79F95859A18CF6BF7A665 +:10527000B9B06F5B1175EF59A7E16E699FF4F83F04 +:10528000EE0D927E42835DC66DE3F75B78FEC97BCF +:1052900076CECB658945DE1710459709DEF7B8BF96 +:1052A0008E19320F0D74B146D0255A8E40276B04EB +:1052B0009DE60B49A7F9A44D820477849C45D2E76B +:1052C00047D26B01FEA0FA057B9520F2DFA2E933FD +:1052D0005F6B64FACDD7E2FD41D785E3A9B8E383DC +:1052E0007AE8A71D19F29EC268FA2D100D2BB1EEB7 +:1052F0005D4076239CCC726177F23A4DF1C06EBB73 +:10530000F31BED36A9CF38CEDBF2FA3B3CEF5A3C2B +:1053100034AB211782EAA97DBCCFDDBCAC8D3CDF6C +:1053200029E764FCE4BA73562EA74D30CFBB6BCF90 +:10533000A5F1F31F4B970AD019728EB85E621BF766 +:10534000E621CE9778E1788DFD10430FB7FA75E628 +:10535000BCE58BF97FD171C2DEC3F538E12031C8DD +:1053600094B77C11BF233A6FD9B0E32DF1D24E8EA2 +:105370005373DEC4D9C6E257555EA7BBA78FB7F0FB +:10538000F9F157E57D77DA8AB34D904F2DC1C27A96 +:1053900070714257BED742D3E376463F59D529694B +:1053A00088FF15C7B8381FBFB85A2D82FD2AA676C8 +:1053B000EE88762B9777CB825DF8F4EE5E8F0668E9 +:1053C000BE7C7A5B6A1AE2FE9FADB0A592E63CDF36 +:1053D000EED315E3B2909FF1D97D8EE9C136E85343 +:1053E000345CDA81F23B3F60BB75D2F27AE2747AC8 +:1053F000BF6CC5EE4484EA4A57BC33D8452EC5E19C +:105400003CED9AE1BCBFBA610BDF07EDDAC0F709EA +:1054100068484A6E8F7D8815CCF7458ADCAFBE554B +:10542000097F7125B53B11735FE2F46CDC6E2A389D +:105430004FE3ECA604FD3C5A35E70D9D88257F809F +:10544000DA1F8991F43CB233C1C37762780259BC48 +:105450007E6B2FF7774A2D75D7019F6B52356DF80C +:1054600020E011DC92AE723B3EB7AE55F7486A2B96 +:10547000FE61945B743B0D7F1B25FC6DE4CBC0DFAC +:10548000060C7F1B25FC6D3CAF5C6BF6DF6ED7F71F +:10549000FB8C7870979A662FFCDD4081E8ED673BC6 +:1054A0003BA1E0F7B05BAF4A7F6189E259D5C8FE06 +:1054B00052422DD69D3556E967073E91E7A22082DC +:1054C000D04FBF50FB7AB09FFF50DC9D8FA1FD52A3 +:1054D000EC0FE5E11E53F2BD22E4F5CA734E1179DB +:1054E000EE7634396191F0186786A9FD3857B6A970 +:1054F000FE27E97D4CF53F757B4DF0D5BD879ADAE7 +:105500004FF48C36C1D7E4FFD4D47EB26FB2099E7B +:105510003A7E86A9FDB545C5A6FAEBA72F34D5CFAF +:10552000D06E31C13796DC666A7F93BFDA542F8420 +:10553000FF09D0C71790F7AAD561FDE4C0FD2F4E33 +:105540002EA9FE0FC8631E4D22CDF7AEFCE5677C89 +:105550008FF57EE435D38C1B31C6E26F2B8EFF07AF +:105560005DFE6347FAB60DE7756E03DF8B89D82DB4 +:10557000E46E1FECD4A0D6E79DAC46DCAA2143DE46 +:10558000876E6E7FB17623E2F69F7193C8F5AC3BD0 +:10559000739395F4D78821FB73BB21EF79C4E0594D +:1055A00056D2372386EF7FB62BC1FEBA3B6771FD1B +:1055B00015FBCFA0FE1F75C3243C55B06B72FB8852 +:1055C000BFDD84FC941157765DED91719136CFB7B4 +:1055D0001B25E88473E1A013CA30C93DCAFD24F736 +:1055E000280F90DCCF23BD564F728FF220AD33F1E0 +:1055F000FCDF689D89F2755A67A27C83D697281BC9 +:10560000687D89F2EDAAE95CBE5BA5F17BEF579559 +:1056100070F941959F9F7F54B594CB4FAA02FCFC33 +:10562000C3E1328E108F7B9313FEC9BDC97E17DF95 +:105630007F50A3DB2D51A7E7D5ECA7F52BE8D96860 +:105640004DFEC2D9BABF78F1F5BE557C11E1B74D18 +:10565000B6FA3E97FCEDE462BDAF3F2FF56AC7A0F6 +:105660004FDECB9EDA235785BDF3FF3989EADEB3DF +:10567000B47D9FE43E5D5E3E1EE13B8DEF8D741E6A +:10568000E2FD74770679ABC31956C07F65A08C5FC5 +:105690008EB436D4A0BEE63BE1C6BAF9A584F7794C +:1056A0001FBC86DC659C3F56CEC9F5CA287DFFBE6F +:1056B000E63BB97F3F0AB853FD4897ACAFB9992C88 +:1056C0009D17F521FEFE289C7696E7DB4C793B631F +:1056D000CF358CE1FA78BB1BF9A6A39C61F93DA7F5 +:1056E0007021BEFC52C21ED9FF38D9FFA6EFC2FC02 +:1056F0007DAC3E91973DD2D98ACF32C6AF41DE37DD +:105700009723DBD7E8ED4769D47F32F0F34BFC8A6F +:10571000A9BDC49FF5DC287C3319AB6D591F9B2EA6 +:10572000CF278F3DA7D77BE4783B58258C3325A81E +:10573000CF4CD1848FFACBCC141EC4DF46A536647F +:10574000707B3D9F21C12ABF97E491F77175FFBB24 +:1057500026F7038800C0DFC84B32E66DE776E10C20 +:10576000F8799D17DBF97B99EA4E2FF4F5A75EAD2A +:10577000EF08AAB73A2D3CBE1A9F3C2FFFD68BEEFE +:10578000CEB85F74B2EEAFFF13FE5F81F7473AF712 +:1057900049FEE392B7CC5658994FFF0F6D93FF9295 +:1057A0005E242F183FF19FF9017EEAFC570CFAE8BE +:1057B000FC3FCFAF6591F5BA7C5CC8FF90E4B72E93 +:1057C0004FA39C326F02EDC1FF9156290F35313244 +:1057D000DFE3A584C287714F16D1A608F1F991863F +:1057E000BCF8E5F9E1FFADFCCFB3CA7BE41C654E24 +:1057F000BEA7EE52F230BB5914E2DECD8D03B57D6B +:1058000098D7C5E7DCF580E78AD18570CF8DFAA7F8 +:105810002E52AF7DDD6C036C3C7F1BED06B5D65B75 +:105820009D6FC741EF19DF31DA7DA57FAFB5DD4050 +:10583000FE9D8D25E342EB60BFC6575B396E4D9EE2 +:1058400009C307C99EC97C4E5FA2372D32FFD373AF +:1058500060711EEE0B95E7B744BCF4ABDDF41FF4AA +:105860006AE1F745CBD19F50B75BB1EE388B7C5ADC +:10587000FA4E61AAD93F1F1FB5BF7E55CE97EC8F58 +:105880005F75897BAB7F3742F7A7B345F67FF2DEC2 +:10589000D08747B07EBEBC7B437B8B3A9683B1C535 +:1058A000329F8BC66F1988B88D4FF801170ABF1544 +:1058B00072305ED45AE5BAD277A2228F57ED4C9F50 +:1058C000AB45989F4F24830263720D890FE097E3E5 +:1058D00026CDC47DC06372C774C7F388FBF3FE0096 +:1058E000FC2A54ED6FAE88FBF3F68F95F36DF1B59E +:1058F00032DEB4DFD9AD4D3FF455B2B7DD7B802E3B +:1059000082CB3F933DEE4EE37E85EC31E0AB7A57A0 +:105910000BBC57E836E71D19EF5FED1A23AC2917CA +:10592000B777570FF86327D0F9B5E45E63C1AFD7F7 +:1059300092878C453CFEB5E40E16593AEC5CF67F36 +:10594000AE7B5BF819F3A3B5BF42EECFB8FF776C1F +:105950007B79FF6F345DAF1221137D27E8F4FD11D1 +:1059600074FD087A349AAEFBF475C57EE73B7B8CF8 +:10597000BC29C493BB2F6F60F8569B9C07E5CF4DA5 +:105980002C405EF4E2F7647EC751A002BBBB7438C2 +:10599000E33F6AE95061CDE5FDA800E85DE6947457 +:1059A0003C19786900EE29AF4FD18E83AF5FAE53BB +:1059B000F9BCFDC96762381E7724F86C22E869C813 +:1059C0007199EA5ECDBFA7F19A2AEF59FAFEE52C4C +:1059D000DC2B7A31B92679FE7AC4A036E4399EE40C +:1059E000B9FF85F22C36C97B0CCA9C856DF2D9585B +:1059F00077BE30D0C7FAC225C2B740FE2B845C1FE9 +:105A000055385F97F754128C73AFD17ED5E0586A42 +:105A10004FF576A7CC1736F89DE990F75866C6097A +:105A200017E22042CBED0B7CFB76F7C58DE4FCC280 +:105A30009CED91796BA3C2FD78DF79FC4195F3DD94 +:105A40005F8995F7B837123F14F24F7FD2CF1FDF2F +:105A500095F8983C444B1B8971A9DFABE8F7F51E1C +:105A60008A48E1F8796E3CAFB37FE47A3D6BA4AE2F +:105A70005F068801FFF4F711DACB7B8417BF9A1B0E +:105A800004DE8BABC9AAA5F2EF5CF03D7135589FDF +:105A900067B7EA9D51A227FFFEC598541BE799FFFF +:105AA0006FFB7D844CA1F1FCFBCFFE4EC278F9E880 +:105AB00082DF49C84C5C75404B6DFD9D8CE8DF4929 +:105AC000C8D4EFA7166E693F8CDF47B852F8382F5D +:105AD0007F5CBAD9AE8C718D3EE0E2D21CEFC9BCBE +:105AE000443ED74D23F5739D97E27BB9D0F92ECF75 +:105AF00075420EF4DF3B09423E8DDF3B31F86EFC10 +:105B0000EE494D7BF9BB27FF6ABF7312CD9FE8DFDB +:105B10003D89E64FF4EFA08CD262994E63CAE259F8 +:105B2000AE0D3E4DA7FFD81FC0B95CE5BF9F5FF724 +:105B300047CDD3B362F520DC537ABA58EAF58BD956 +:105B4000FF695EDFEFA16FB6E97ABFC629E321BE28 +:105B50001AAB881925703F21E7CBFEA246DE03551C +:105B60006395F18000F115F7E27D1BFB0F799F2310 +:105B7000F947B68E88CBF8F9FD80DDE9AAF144FC3F +:105B80000ED652791EF89045FE9ED4EC1CBF82FDC5 +:105B9000CB4E5DB5A7A0AFD245D1CEF91C97F70F7C +:105BA000817E9FF5274716EA677591F7478A1CF9AA +:105BB000BB4106FEB332655ED6B323753DEE9179E7 +:105BC000587B46CAFDC0048F8BCF3514E7083DBF14 +:105BD0005564CDEA0F39FE84FDF816B7F4AB1B6DA2 +:105BE000F21ECBC0AB329F679DFF6DF6FB37935F14 +:105BF000AB4AFF66EDBD1C674814D8C77D2CA6399B +:105C000019F8F75A2B4CFE429FA0D39497DC6FAB48 +:105C1000CB04F70FA59BDA5FB1D76DAAF7867B9B04 +:105C2000EA730F7A4CF0A0867C53FB211FF84CF0EE +:105C3000D0C6F1A6F6C38F1499E05323BB4A3A416C +:105C400026693CB396B882F25E7C1927E96297FE1A +:105C500054CD6D723D61E4AF6BFA3C88CE5FEF6C62 +:105C600095F9EB76BFB46B5ABC5CDFBADA0997CA18 +:105C7000E7621A18C6DD109C371E30E7997772CAA2 +:105C8000F59565AC5C7FD8F53CF3D8DEF2DC8B9102 +:105C9000574EEB0A1FE8DD5D34CEE0DF2FD0EF1367 +:105CA0008D96E7BF8FD4EF738AC2BB8B5D9EA7AB87 +:105CB000B9CDCEFBE75ABCBD4949BC109F6E7A7E78 +:105CC000E46667DBF73E39474939BB21AF488CA210 +:105CD000768F92D962FFEB82FE3C8DD07735BFB2D2 +:105CE00073DEF8A5FA9B75851CCF4C8B65F6E41C1A +:105CF0005E0FF23940A3DF74F44BEDFAF874398F7C +:105D0000EA6F565233DFBB2692EC6EC8AF16BF92D5 +:105D10006157AC4856DBA07BEBB90C99A77FD3EA5F +:105D2000D0BDBD08CF99F65A9BBC702068833C4C0F +:105D300028203FD28BF8EB43EBE3891F8FE207EC7F +:105D4000C8CFE8B2AFDDEC4077F899CD2C0F4844CE +:105D5000C17E22FC4F75602BDE6BAE9479DFBE51A5 +:105D6000C2B8FF80F16AD1E3232D2274FEFC44A067 +:105D70000D79D3E2EBF91C826BB194A7CE11E7AC9D +:105D8000B0FEFC9F3A2F21B0434AFDD86A853CE71C +:105D90007809FA19E754DCB7D88A36C6E3BC881804 +:105DA000AF44D0E1892BA55C2E061DDACB76D04717 +:105DB000176B477E5F12F6175A843BC97589B8FA8C +:105DC000FFC4F833AD32CE90E594E7453A5B35D663 +:105DD00017F6DEFA3D7717C8BBAE37F4385927AB54 +:105DE0009CF79D3C725E5FA8170EF0F7ED9ABC37EA +:105DF0002D9ABEFC2F22AE629C5F891D2BF588A1D7 +:105E000017CE9F43E921D7A1365D3F04BB5B38EF36 +:105E1000E0AE04F33C7E7C94A46FA13E8FC9CE27F4 +:105E20007A079BF484C0BE5ECD0A95F504E9C97A71 +:105E30008DF02CC6BD2CAED6DF7BBBF90169C74601 +:105E4000F98A1EC4BEC99C3536B181F715E4FDB090 +:105E50000BF438797120EA7E16DD1F3FBB5A71E1E1 +:105E60007720E6AE32D72F88FFE213AC1F6F8EBECD +:105E7000A7C6D8AFBB441CE0FE51BAFDF7088F9E01 +:105E80007FBF0CF89D0DCA7BAFCF9F57D2E33F2D4C +:105E9000C167257C87E07851B45F60C06EEC9345A4 +:105EA000DCC342F48DED0DFBBEDCDA667EA341DF80 +:105EB000F3791EFA3E1D95CB56F07A46E637903EB2 +:105EC000E07DB913540F3FF044E00CB73FB12B868F +:105ED000F34A4E7A1B0660FFD6D8A7EBAEC97DAC5D +:105EE000965D0932BF21DE22E1ADF21EFB457F0F38 +:105EF0000EC03AB631F0ACE99C83D668DEE78B2E53 +:105F0000B5EADDBCDE3C9CA7D58D427EBDD5E3F471 +:105F1000107C77FC7EBEA76B02AD1FA1D79097B215 +:105F20002255E2CFFA2B7046D2CF2FE9770D397A7E +:105F30009C9F27487B228E2968554B65717828F7EE +:105F4000FF63F7C1A69EF3CAFDDF73C3F97D6DD56C +:105F500050867B079B477F40FD5EA7C5BB1147BAB4 +:105F6000B6E617E362E9D38DBF8F5FC16567F3F9CA +:105F700001A3FC58B7238DB6B6EB27E8FA67E19585 +:105F800086BE96F2BEB85AE17DB5C59071C0F7CA1B +:105F9000FB390DF84CAD0E8F93F092151286698285 +:105FA0001F3C47FFDDB32D7AFC05E34789F1232E23 +:105FB000B05D8FCF60FC28317E3C87BE020C7D0532 +:105FC00018FA0A30F4154AE82B3CFF3C790CEF6BC9 +:105FD00063DF6E6CC47CC2BEDDD888F9817DBB48AE +:105FE00018FB7691EDB16F17598F7DBBC87AECDB4A +:105FF00045C2D8B78B6C8F7DBB4858E4FFB415867B +:106000005EF34D36C153693D3036623E63DF2EF29A +:10601000FBD8B7337D4FBBC5F4FE8D62A9E97DEC9B +:10602000DB45B69FBD5431EDEB09D1CC767DEEDA80 +:106030001496A3D7BC451957B6E7DFA9FA99AD2B3B +:10604000EB078E632C2E8FF5487ED78E97FCB7C852 +:10605000F3114A33FFBEC0993BEC121E67CEDF3608 +:106060004AEC7B8DB5C97D2F94D8F742897D2F945A +:10607000D8F71ADB43EE7BA1C4BE179E63DF0B2566 +:10608000F6BD5062DF0B25F6BD5062DF0B25F6BD75 +:10609000F01EF6BD5062DF0BCFB1EF8512FB5E78CC +:1060A0007E88F09817A1C7E0AF7737AD33490E4D22 +:1060B000EB4C970986BF1ED91EFE7A643DFCF5C8DD +:1060C0007AF8EB9130FCF5C8F6F0D723E11B46B91E +:1060D000799EC16F8F7C0F7E7B24DCBF36F067C456 +:1060E000D626AE3B7500656382F228CE1BDE70E5D6 +:1060F000B6D9D8BF6C8C51B29249A7DBAA77CC1E17 +:106100000B7BABE73F0E10CD16E81F0D8BC93C3E55 +:1061100067C879A5FDBFCBE0FADBF5FB11F81FF1ED +:10612000DDBB4BF0EFCE18FBEDC6FB1E32DB288D3E +:10613000F6AD70DBEDA2FB37DA716E55041E38D177 +:106140008CBC19EF1DF103B10ED9A2FF8EF096653C +:10615000322F3A5AAE7EABEBA72D969DFB710EA661 +:10616000B958F1E0DC47F75A8DCF99F59F292CAA51 +:10617000B7753CBD1E4BE4BCDA5F5C29ED9181BF75 +:10618000111F257DC1E7074734378C49A2F65A60B5 +:1061900034FF0ECE04BBD07F2FD83F0CEBC97E015D +:1061A000C5B73142CEABF5EF690189C7138F4D9268 +:1061B000EFC5CAF79E782C91FB9FB45CE13CB3110C +:1061C000DB850FE794EFD1F1EFB73DACA2BFE2E57D +:1061D000B23FE3BBC5EBB2EC38CF6DD0AB58348ED9 +:1061E000C57DD2224FC19DB2A2A75563BFB4C34C97 +:1061F00097057ED0E59E831A99973C0E7988A24E2A +:10620000F0BDA113F3DE328D97C93518BF6B2A7824 +:106210006DA8056EB1A0DF49448014C49309C67807 +:10622000344DF8B389BED74D2F667AF79E2914D026 +:10623000BBCFCC0D96547AAF9FF69205FE5AFFDA8B +:10624000462E8D71784624AB8027D85CE380FF848E +:10625000710AEB8FE83C1EF8070C2FB7B13D37FCF5 +:1062600087C509E7F37CFE8A3C9F33076D9CE77383 +:1062700066F959AE2FDE1DC3793DDA5A85F59AE1EC +:106280003718793B65B7BC3718F439961DDC92DCBA +:106290008DEDFC1FAF441E4BD79D89381A7762F9EC +:1062A000EEEBE0529E59BE5BFEFEACBEBF63FC8EC1 +:1062B000A9C8F1713E98E1070AB5CE1EB98F63FCFB +:1062C0001E1AE94F6E7766AFDDC5BF47A7FF7EA9EF +:1062D00011F729FE4B6E3DE85ABC5EFE9ED99C55D7 +:1062E000F7154E2778BECF19C6EFA147E7632D8C6F +:1062F000F2032FF5FBA5C267F6FF2EE6EFFCFFF2D7 +:10630000BFB7FCBF73A5703700800000000000001D +:106310001F8B080000000000000BED7D0B58556539 +:10632000BAF0B7F6DA37606F5C080AA8E002454DAC +:10633000C936225EBA2EB9282AE206C4B441DC204E +:106340002676AC21B3911ACA8D7B4348D6C04469E6 +:106350008ED5D6D433534DD1654A27EB6CB59A2EE2 +:106360009A263975A682ED25B53BE9F1D49CC799EB +:10637000CEFBBEDF5AB2D776836633E73FFFFFFC22 +:106380007B9E66F1ADEFFE7EEFFD7DBF25136D06B2 +:10639000369EB1337B459F98C258C5BE3DA52C8E15 +:1063A000B1533526C6A05C562F322CB367992F4DBA +:1063B000C0728E2102CA657F501C82CCD877ABAAEE +:1063C000F7BF064DF7AF823616C68ABF1FCC5826D8 +:1063D000631DAB642A977E3F86B158C60A0211F44A +:1063E0007EEEF789F4BCFEFBCBE87DB10DFAC1FC73 +:1063F000811DCCB71AE63BE5B650F9D44EE6C3F999 +:10640000F1173781B111F8070C99C1A43C368CB152 +:10641000D18AB007BAB359DF5F45E3CDFB3E83C6EF +:10642000BB667C45C300E80FBD1D69D07ED6F8F77A +:1064300072FAC17A5DEE295922948B8DFE39387E2D +:10644000B1C3C4DC29F8FE564302D417325613EB0D +:1064500080F650C6FDBA5CAC468861ECCE89D06946 +:10646000009459CDEB03100E5B98632BBC9AE7AAFE +:10647000C8C67663CA9820C2D4E551ACA61DF7629F +:106480000B64155DCED80FF8BB0EDEE322AFC4C59A +:1064900027BA14A82FEF077F0EA26D29CCCA983D0A +:1064A0009DD75FA924BABCC3E1EF96758A7520CE4B +:1064B000C77F43CDD00EE611EF34FB5603FC5D36AB +:1064C000EB61612C54B8F394C028DEE68754C6868D +:1064D0004D823FB2E05C0C86854E9867C18A0C7392 +:1064E000657ACF3ACCD9D9F3A6C03EF2F0BC61BCF4 +:1064F000E56B4C3E4B0A3ED3E299ADA75DE87311C4 +:10650000C0578EC575076E17003EF314A6E4C25C33 +:10651000F399B62FE667B08E1BD4B2D7AF049A6C4E +:10652000040F2ACFF18F70B9611D375B03530193BC +:10653000D8CFD36BF2130D8CBD61E270B5985CCAF5 +:10654000605887697B867FB08CFB90E83D330612EC +:106550009D76D8C7DAF6FB46C27BAF22F3FD995B86 +:106560004C0C07623E9313E0BC289D293E84BB91EE +:10657000E3D191352F3DDD2CF4ACFF8889CD6B0F35 +:10658000B3BF3AC540F36C03BC954732F6DB5556B2 +:106590007A3EB14A6232A0E053AB12A8FC34E0313B +:1065A0003EDB578DA2F7CFAD7250F9855593A8FC0D +:1065B000E22A85CADB57E5D3F38FAB9CF4BE60B407 +:1065C000EB1605D6FB9041397C0FEC6F90D8C210CA +:1065D0006FF1DCAD137ACE37A2E5BB0A3C8F2A9B64 +:1065E00059C6755701685CB08F4AC5EAA8075000C4 +:1065F0006C1B13A05C2EB2EE6647B873E7707C6C20 +:10660000FE7F2D3540BBC7EE8A24BAD5E057663EE3 +:10661000F0BA35A5077E1FD5FEDAC40C746C69325A +:10662000CC7B434D84A33905F1C3E9C1F546A53BB5 +:10663000CC2E80D7BC298CC6BD32D5D988EF6F5EF1 +:10664000BBEBD10FF0FC76A6985D709E15DB331A7C +:106650001364ECE7BA5781761536C98C78778B3797 +:10666000C62CE3F9C7033D206EB3EEE4627B0FDC7A +:10667000B728028D7B7D361FFF1B3C1F6AD7622A1D +:10668000D2B5E3E7733E3D1C9882F0F200FB581D43 +:1066900083F4F0E2143C77E94EA091C9B01EF63EB7 +:1066A000D59B1398E489391F5E83D90101EB13014F +:1066B00096EEC93DF06B1E55497CCE043428C604C5 +:1066C000C38F113D85E2CFFBB80F804BE50A6175A2 +:1066D00003CC5FD526FA0401E9ABE00DA2AF564129 +:1066E00026FA7A70983991E84D90907F15F497A723 +:1066F000C643FBEEFB0469B38CF40A738DEB19B748 +:106700006AFD64A2B72A1F3C337BA7CB9FB5EE4935 +:10671000DA21E3312A665C6795A498FB07D1FBA2D6 +:106720001681E822B4FC9A22723A626F9A106E6562 +:10673000C365C19381FBE1F8B160458AB9D286F5A2 +:10674000CC6F807515A4B237B05D772BAC3785CF91 +:10675000332E68DC4A1C37685E68BFD009E57715C0 +:106760003BC1B54292CD8928572489D657B9629743 +:1067700009E1B308E02C64203C1C661B8EBF14C6E4 +:1067800007F8DD20F9F3B0FE867499D5C339547A41 +:1067900033CCC89F5C6BF93CAEA618F3E550AE3025 +:1067A0004AE624289745323A37589F0FFB57013C59 +:1067B000FADB705CB610654B285C2AD4F556B5C47C +:1067C0009817EBDEB79AE474E26B4A387E214EE10B +:1067D000785BE92D4A5E87E7EDB64B44B746C5ECDA +:1067E000C075A9F09DDFB6CE9412D4FF5B158FC59E +:1067F000291CCF0A52FD6902EEF7D60807AE77BE14 +:10680000D46242789E83F3831C0E8B257F1A8EBF41 +:10681000D8CAE1700E3FDAF4E7DAB33E0EEFAAB65B +:106820000AA2BF1B8DCEE475D0FF4658A71B9EF36E +:10683000D7EF4A13F009F42E207F905CC9CE207A5E +:106840003BFEE0F5C9B47F583FC2DBEE90A722DFE4 +:1068500001BC21B9ABE14F7926A76BADDFE029463A +:106860009A77F0944BA3D7AAB5EF51FD22A0579485 +:10687000B766F68280F5666084E1E837094786F6F8 +:1068800036C01F77620FFDCE6781F9C85F17AD2D47 +:1068900062AE20FE03F2B6E6B930F09A87EBCD2265 +:1068A000B945E70D74F81AEBDF539FAD9E7759AAEF +:1068B0009EFE713C1CD7A1D567FBD36E4DEF69AF2F +:1068C000CD5BD69FF7437A403C74A8F0C1F6CBA9C4 +:1068D0003D2F833C5EDD80FCE13ED16711F0F9780D +:1068E000C3402C3F0BD216B6F6C5F297DE9D0BCFF8 +:1068F000CF1FDA548EFBD3D6B118F41DE41337AA98 +:10690000F2B9CA1F9E5FFC6292EBBA295941F8F3B3 +:10691000C0EF4720FFFEE2E977D210CE1FDB39BF80 +:10692000FBD9EF1F37B1D49EF55736BD67AAB00526 +:10693000C38BF3BBE65107E9FC168DE2FD1679BF68 +:1069400025F9C5407EA5A59C7FFE15DE6779FB5A1B +:1069500007B577D9FECCCF7F1093C4C40B9FB77611 +:10696000BEA1E7FEA8C9E94F407D34B54547FFA168 +:10697000FBAF50D75D3585F3B71B543CBEA1BA952C +:10698000FA5536553C8E7AEF7C8D7EABF4EFB5F33D +:1069900039B5D644E7736A6D5A23EA8BA7DAF9F959 +:1069A000FC8BD83E7625B4FB62D9D65B1253492FB7 +:1069B0004946BD04CF07F5D21B55FD74099C0FEA6B +:1069C000A761CEE736D4CBB4F292C7F8F92C7A7A25 +:1069D000DF277F9409FFF8FEEEB3F890FF56B63F2D +:1069E0007BE84A783FBFA9D59402ED3C5352083E5C +:1069F000E7F87C4D86C4A2617F4D9B4CC8073CDA0A +:106A0000BE43F05C832B33723EF328E8F0CD315C5B +:106A10001E09FD7BDACF674A3CF211E61EC2B6C6FC +:106A20009DBFFEA7553A2A48759849AE3544B1CD69 +:106A300012AEA3E27E36B677F9753482D305485D8F +:106A400005E9F3E8144732D285A6BF86B6DFAAD29D +:106A5000D7E0A8F6F9B8DEC1B120DF01C4BF895480 +:106A6000B251EFF9CD9556C9E3C0FE2E19EB2D5664 +:106A700026A17CDF6C90C7117E827E7F4F22C232BE +:106A800090857C6FF8B2C0B7B83E44A78871FC69A6 +:106A9000877DBFA3C20B55F181FCBD1F9F49C67600 +:106AA000E25391B51CFF42F50CAD5FA87E11AA57C9 +:106AB000F4B6BF3D17B9BFA3292E1FC98908266D9B +:106AC0008EA1FD2DC7F2B9FD8D628A01FA97FFF202 +:106AD000F24DA84F1EAD57769BA1FEE81D36EAFF8A +:106AE0008FDA6FE83EE75755E8F6798E6E5A44B272 +:106AF000334EB56426935D07360F83FAA3B7461865 +:106B000010FE4753B8BE0016A01DF5C46DAA1D891E +:106B1000FA383E511F6723B93E8EE5A755BB12F5E3 +:106B2000717C7F5CC5BFB248251AE57277BD5DDA1E +:106B30008CF0F073BAE9AC1D4670003D81F36355EB +:106B40002FE89402F6FE417C1AE4C77D28EF58ED49 +:106B50003086F65D67CB51BB211DF192AF4F6BBF05 +:106B6000C2D4C2EEC0760F0BBEAD306ED48AF7F23F +:106B7000E2514EB7A56408D06F41ED69E2870B6C16 +:106B800003658672DCE66A9C88F5EB53A4D5D02DAC +:106B9000AA2DA3B316FA2FF68E24FB798520937EB7 +:106BA000CFEA05B22B996A1F2CC1BFA0BCC4F6C6A0 +:106BB00070955F1A905F2EBAFF8EC644281F36B0BC +:106BC0006E11405360289A8AE5820D310E0FCA5B20 +:106BD0000FDF0FDB087CD4DAC3474F4F72B26CA4CF +:106BE000F7B3806F30FE68581BDA512B4CED0AAEBC +:106BF0009F81DEB195E17A9DA4C7AF52F1A2B3EDBA +:106C0000B05D56CF07F5F3E1AEEEC3F7E0B9DA0CAD +:106C10008E6619E5BBBC5F46B8BF2532D4678733A3 +:106C20005EBFDCCEEBE149FAF1F24DA28F917E5CC2 +:106C3000363080FAD77A91F8E2E24D250351DF58D9 +:106C40000C65945F1B702AC0A7C6B61CDEAE35EF7C +:106C50002137F0D3648139911F1D33068A101E2716 +:106C600037C5F7AF477DEF66CF0806F5559BEE4970 +:106C7000C6E7C94D11F3908FE74A45B931A8FF6CBB +:106C80008CC940BB5FA3B3F46C2E0F6EBA39271EBC +:106C9000E5DDB2BFEF795402B9BA187054423F48EB +:106CA0007B94CF0D4D96ADDA9E2C026AD9E35C231E +:106CB000116EFF62D8397732CA61C1B72D91DACB34 +:106CC000F1521F76F371B42B014F6FBEFB431AE7ED +:106CD0002BC3DEC2F9D07FD9CDCF47E338FFF260B6 +:106CE000C70409DE1F1BEFCAC4F13F17366D93D0EE +:106CF000AE5DBF692CCA8FF1AA7D54D0DF39773ED3 +:106D000087AF63B3DCFB7CD5DB0582A7565EE0EB87 +:106D10006766A897FA9959C2A7C4480F3E29B25A84 +:106D200094EF9A5EA2BD9F96CDF9CFC97E2DC9780A +:106D3000FE4BB7AD4B46F9F1999D975D5BFEB4F8FC +:106D40004E5887ABCD2031C03B979191DEBBC8CD6B +:106D5000F569560DCC24B167FEA2EC2882F3D2F57A +:106D6000993AB9878E197CFF9991E5E33A867ABA08 +:106D700033507FFAC8E85F8CE7FA11E8A7E8974933 +:106D8000CFE6F8F7518B3815DFBB57080CFD4F1FC6 +:106D9000B53C6F1FCEFD28E4C7602F9B7C5BA1BD77 +:106DA0007D7CBB1FF9DECD2FC48C4330E689E9F131 +:106DB000883FCB7798A60EE6FA145AD36C99D16F18 +:106DC0000E776E37A97AD4B9F20BCF9A11EF973DAF +:106DD000D54A7E0550537CA8DF2C6B7FF68D413061 +:106DE000DE2DDB2B32711EADFD2D2F703844B080AF +:106DF000B92448AFAE18D5BF7130F0C8E5D9F9AEA7 +:106E000007511FC273BA12D424655245BD119F1297 +:106E1000ED9319BB491F07FD8AECEB9BBD7CBC9B26 +:106E2000471D6C4CA57D15C5B2A0F3BF2DDB44E713 +:106E3000A5F5877D533F8FF5EEC702B05EC563644D +:106E400011D742D9C83EDE86F063D1D256DC879195 +:106E50001D7B039E2BC57EAC199E1B6B96FF2BB52D +:106E6000AFB748223C3D37D73D1380F964913919BB +:106E7000F47767D7D0786E33973FEBA29E7EF846C3 +:106E800028D7CEB13900BDA11C4DF0D9F90B03F1C3 +:106E9000F944D6BDC700CF78065404001A92EA6AB6 +:106EA00021BEC3383F5E799BEC437E0C1C5C403CAA +:106EB000FFE6951399B8EE6B87064E235E99EAA715 +:106EC00057E402FDAFCF56E1921EC8C4760376ABFD +:106ED0007CCD7880E4A32941EE8FFA8A1FC7C2F5E2 +:106EE000FDD54078B053F03F8EF36A70DAA7D2FB3D +:106EF0007319AE4DD9F05404D3ED7E683F5B8876AC +:106F0000E07E0FF417D3C60D433FC4C72938AE1B2C +:106F1000D0561CDCA3C766AB4B370F9AB41EE132C8 +:106F20000500CAAE065B26BD3F3342F95E66E8B691 +:106F3000C03AB2BBFFB2A91ECAD2AFFB3111449511 +:106F400027229965C3F8C26ED828EC6777FAEE4518 +:106F5000B8CE7BBBAD0CE1C4AC7A3DD76C48F4FF36 +:106F600012F1B926DAC112500EB567203F62B7D8C8 +:106F7000C83FB3E06C20EDE72897FEBA97F4F49F82 +:106F8000A5BA5E46B80E1295C32EA8BF57F20FFBE6 +:106F9000158E5F1BE5A8E7728405AF7FE71D7F8D27 +:106FA0008E857EDF748F303E03EDBE51AC0EF4E76C +:106FB00075DE39E6B5ABA07CB52A4F42D7F54D82D8 +:106FC0006C44BBE39B6EAB1FF5906F6C06F2736471 +:106FD000EFDCF321FA21B3AD36BF188DFD4C5F060F +:106FE000CB1B762029E6F8181231EC0780E74055D4 +:106FF0002E5DDB4F6F3F7666733BA853E53F46D966 +:1070000041703EE536B266C44306659CD768959AE2 +:10701000617DAFDAB62D40FFD5A9EF53FBA1DC3877 +:10702000B573583F96DE3B5FEC407D02F484884C9C +:10703000E5533C7F4DBE96AA708968B9DE84F0F0B6 +:10704000003CD0BF566A33F82DE85F9DA38703ABA1 +:10705000ED2E47BC61866807D20D9E2F9EBF2C186F +:10706000BAD955E79FF7756725FF2FA1BC00CE134E +:10707000E15A7EEAF8E5BF62746EDFE23AE01C1B7B +:10708000AE603DE7F7BFEDBC98D1D184E7B052B414 +:10709000B7E039788C5CDF73036E6D8DA16EDBF029 +:1070A0005C567A86D3390DF4009F403B0598DAE6AA +:1070B00038E42B07A9FD56CD9F36AA86F84CB9C7F0 +:1070C0002221FCBE8B8CA6FE0CCED534281C9FE161 +:1070D0007CA5B68A115F59985E23E0B927E00CB011 +:1070E0009F4E43C08EFB0C44801609CF6B725255E5 +:1070F000FD1B3882EA67C5FE8FDC61DF8CFC46B47D +:107100000E7EE4188822D6D41D3D1AD6D526B07638 +:10711000DA9749E51F4B6DA4CFB5C5F888BFB59583 +:107120000E71E05EBF616A7D7524F197AB0C062A93 +:1071300077CF1F48F6585B0CB0561C6FFE68D21B09 +:107140005EFC3B8F9774A7315E9FC146ACC7FAA225 +:107150005134DECB1ABFBACF4EE3B515298991540D +:107160003FD080FD5B535C137388AE793B503CA8E5 +:10717000DD860D4A229EE7866233B57B4870CE5F7E +:107180008CE35C6E23BD31303FF2E96DFC38FDE8E5 +:107190005FEAACE5FBD6E840F3AB0F751F7E18F94C +:1071A000873B1B4E04ED43EBD70B10AF1531DA01D3 +:1071B000287CDE397F770ECF59370097C545769208 +:1071C000BD2EA73104369C9FC4B2114FF6003CA1DE +:1071D000BDDB04E71CC7CF79751C9E73E1A6E07385 +:1071E00086F1DC2BE1BDB03CDA214CA2731E85E3B5 +:1071F000D7B24807DAD7E7CEEF555F063E4583237F +:10720000C102B0F83CD5353F27AB478E3CF209ECC4 +:107210000FE0526E0964B5A07E6E60D5ED61F8C0D6 +:10722000A21C6E1F48ACDB84F275A186FF7521F8A5 +:107230001F1812733C4AC57FE8F74ABC73319EC3DE +:107240005742C7047CB9F76FE2BC70E3DF9CC3F917 +:10725000D68138E7325CDF70E3EE21B7A1BE7187DB +:1072600085F45F7676CF109CF77729CE9FE378116F +:10727000C3BBC9BFDE99D86DC2FD75CEFF3C09F511 +:10728000AC85B57F22FABCD8F5AD8E1A6B42B91920 +:10729000939F610A40FFF8FC8CD7F15C0ECEB2C818 +:1072A00096307E905DB32626A13ED4317D6212F2E7 +:1072B000CB8E245833C953871DF9A869FBE5765C4A +:1072C00067477E26956526ABE5923EF9EB17C05FD2 +:1072D000FDA0087C06F61A3E4F80BDE6077EFB291E +:1072E000D86BF83C0AF61ABE3F0CF61A3EBB56396C +:1072F000E87D47FEB0ED8817675AB81F6591D11138 +:10730000562F5BF694C8FC1A7F83FF6EDA12A52B0A +:10731000576F8CD5956F6C030CB2F694ABD60ED329 +:107320009535FDB3D23B46F7DE5597A92BFF3F03BA +:10733000DF260E5FF497FF6F822FFED682BC2BC133 +:107340003F00BFF7654D233EDA21B09A5878C64812 +:107350009CFF199D02F9DDF0D70272BB18FF00BA3D +:1073600031DAE406ACF742FB5F435BB47DD1FE60EB +:10737000CC61AA80F7A5F91112CAF3B9AC86E86C02 +:107380001E6BA1E70DAC9D9E65EC003DCB19A7C31C +:107390006F2A0213F0F9719CEB53A4D36556D7639F +:1073A0007168B725B946C6223FB2F527BBB4B7739B +:1073B000420D9BA97AAE6D82BA2FF8CDC1B543BFFD +:1073C0008351636FBF5DEE99471B1FE63B8D7CE3E6 +:1073D0002B139F675FD6C424E40FCC3940674FF569 +:1073E000365FAB2A272BF2399CD0678BE563A50269 +:1073F000C58B77B55ACCE85F38B6C6A4EAEB77936D +:107400009D7BF810F7CB1C6B98968CF857DF3A32BF +:1074100019F1FC98496EA805F81F9B0CFCDB417E16 +:107420001C07CA8723F976EA0F92223A03CE6D91A0 +:10743000BABF23B2C37C07B42F4D1499DB81F1F49A +:1074400094685CBFB6EFD07557AEB5E8F060F6242F +:107450007DB994997BF02D05CFDBDC538F7A925860 +:10746000D6CFD587DD5DFBF1D2FDAF05E16B72AE06 +:107470003D0EF51A36914DFC41ECE9DF1B7CB57CE5 +:10748000060DBE1A5E7D9FE31C999B45AF29DE86E3 +:10749000717494C71DDB391C5BA3AEBDEF2A80431A +:1074A000F1FB22E3702E777F84F8BC83FBF543E782 +:1074B00009205D8F447AE5745DE17D8FECB78575B9 +:1074C00045265C5FB1AD3B09FD4EBBEE1A9984E7E2 +:1074D0007270D6C824E41B7BA68F7C64058CDB55B8 +:1074E000203A2C804FBB0A4EDF87E58E3A51C27995 +:1074F000BBB69F56F94BF7BE89B0BEAFF34D24879C +:10750000BAB6FF73F84CF10EE03330FF191FE733C2 +:107510004B8C4ED608F32E01B8A01DFFCFE63717CF +:10752000E233074DCE3CCCDBE8AA171CE87FAB9FCB +:107530006E21FDE120D08785E353C30AE49393C015 +:10754000FE9510DF9C596853766C1F3600E1C5DC50 +:10755000CAC151137AF07D51DD9202F4AFB3B5A6E2 +:1075600023A877A33304E57331331E0904E1A9EBA3 +:1075700005534F99F0DA78241084D7A1787A1BE26A +:1075800069540F9E9E616793CDA9BCFEC0C01EBE0C +:1075900087BF60FE728BE86FC478BF86B7FF39FD86 +:1075A000BD72541280AFDC9D0BF8FB8B7129AF04C8 +:1075B0008420BE72917CAC35EAEF24F7D645FD9D60 +:1075C000E4DEA1E95CEEED9A7EFDEEBF20DEDFC5D4 +:1075D000F1BEA37422E1658709E419C0EB605D6622 +:1075E00034968FAE2D213AD3E827749E2E15FFB521 +:1075F000760B8DDD264718FC74D589BAF34C7B6178 +:10760000413FE7E5BDAF5F1B576BA78DBB3024AE95 +:107610001B3AEE13B9DC0E4DDB52D6E7F86000F6EC +:10762000F4A33C94C81E7C15510FB89EB9013E5D71 +:10763000F91C3E5D05D7133D1ECAD7E8D2C5301EE2 +:107640007B708EE843FDB52BFF34D1E919A0531AA6 +:10765000A397794FAAF4795CA5CF632A7D6AF5E2F6 +:10766000D607E7DE80E3D689C4A70FCEC91C80F316 +:107670007DB6258DE685F550DED15BAF2DACAC1F18 +:107680004EFCC18EFCEB10C001ED8492D212B2A769 +:107690004B4C8E01E1F484D07D878EB76B9685F2DA +:1076A000C8603CE277C57795B046E40B0007C4CFCD +:1076B00043D81EEA8BB7723FF01E6C1F170CA791C0 +:1076C000A4AF1CFAADE040D161DAFE373B9EC35255 +:1076D0009F9E5F2C591FA53BB7C52DB1BA72F1749F +:1076E000BE8F4375C30684CB6BBAD0F969FD2FF604 +:1076F000FC6F52FBE39A7F203DA5BF6E3C04927E57 +:10770000BED490FAD121F5E374E50BE1E361152FC6 +:1077100034397238425E102EBED45568A90ECED3CD +:1077200088CEE3764B749E1AB7FF917235224FCF05 +:10773000AF2ED45FE34F9FE738A53C94A3FE12CA57 +:10774000DFBA587E14248713F270BD01C18CFD5B33 +:1077500055395BDDCEF16E5DD4FD947FF395AAA71C +:10776000035E12BFFF5AE5F75FFF412DFF5E20BCAD +:10777000DCB3636534EAED27B68F8C463BEC48BB3F +:10778000271AF9BECCDCD157023E7EE904F909D3B1 +:107790009D6CEF5B7E7EA6F29D13780E2437253A12 +:1077A0008FA3AAFC3C8CF293E4FD287A1E44F909CD +:1077B000F5739E55F5F4DF0A44FF4B8D2DE1FDD3A3 +:1077C0005BF4FCAA7A6354889CD4CBCDAAB58375AC +:1077D000E54AEF305DD955A7979B796219F1F5130A +:1077E0003E0EC792FC4C5DFB13B21C2D117C381C65 +:1077F000BE36C9D18867477CB1D1C1F4A2F1DF831D +:10780000217038867040FCF496F4892747D5FE5ADB +:1078100019EC4213CE5B6275BC1E877E84B5820371 +:10782000E35498EF3709CEF1C09C8CC79B83F48C4E +:10783000F7F344C297C3DE3DE5987775060C30F444 +:10784000F3FEA96E4F32FA572B9E8A22BD2974DEB1 +:10785000AA023D9FF9B2A128FB23E857F2BEE8B384 +:10786000223C0A62887FCD7956F48950EEAACB89F2 +:107870000EDEC709950E35B9B3C45813F61CAB37E5 +:10788000EACFB1A4A09EC6E978506817FAC173D7B1 +:107890006490A4E7F72B31F2FD2F794A24FFEE1212 +:1078A000EFB7FB30AEB804F4405413FED4E42944DF +:1078B000BC3EEC3419889FB6C716227CDC7344CAE0 +:1078C00083DDDB348CF0FC4853CE409CAF4985D33C +:1078D00089ED168370053C9D26E6277BD54FE7F999 +:1078E000A5B784E4C609840BEA414689E8E2813CF5 +:1078F000EE973F0CE360BD01E804F5E12E9F98EFA1 +:107900000B431F0FA8F31C3DFB2BC29F377C7BA2B0 +:1079100051AF38DCCEC73F5A2745637CEA1D6FA6BE +:107920009DD65700E3A2DEBBE37A929327BC1C1FCF +:10793000719D641F3671F9D1E15D74FF6480C75792 +:107940006B45D23BBF6A2A299C8CE7BDD644E59C97 +:10795000A2528A6F74F8B87C39E43B5A8EE777C23A +:107960000BA70FE5FA1D13F78D8FC37336113E5425 +:107970003DA53F97D2B57AFA825F74C604CACFA4F8 +:10798000B82CA81353D14EAA4C00F909947BB8A087 +:1079900084F22A8BDD7A7964614526C43BD42FB109 +:1079A0005DE52325597EA43FB740F272E10B3CEF21 +:1079B000DAB4E56A9277152D16DDBCC5757AFBA899 +:1079C00032C41E0AB5977EB4BC30D5948793171D78 +:1079D0009A5C60D25484FB1130AC9B33E0FD0B22E7 +:1079E000E5239FF14610FFAC5878EA1A552FBD16D3 +:1079F000F18039DC6C9266A707D159A5570CD1D319 +:107A0000F5F005FDF938EAC74DB1AA1C759790BF8E +:107A1000EEF31CE510F1FB8BB5BF2F5ABF2D57F5C8 +:107A2000DB72D26F3B4A2D94AF79109B04F5DF5582 +:107A30007A3DF9750ECDBA9EF4DC43E7FC3A4ED59B +:107A4000AF730D9DDBA102C067921B0EADDCA71EBC +:107A5000A1F18B4FD57338AAF2C9C32A9FEC52ED1E +:107A6000AD46555E78557971A840B5B7E218C90B97 +:107A7000A3516117C3676E6C8B0A910FB12176D445 +:107A8000E090F3D1CB8B6545AEC8A940F79684D181 +:107A9000BAF726699CAE9CB66527F98FCFC83C9F84 +:107AA000E81EC4098C9794F2FC2C666D27FF71A91F +:107AB00043A6FAC1182784F66852611E89869FDAA8 +:107AC0007B298EBFD7CAFD61D7F5D82EA59DCA9E4A +:107AD00052C6300F66B8360E80A31EF484C1E8C7C4 +:107AE000867912C040C3F61ABE0F99D34AEDB2ABE5 +:107AF000992440BBF4A929C4CF129842FC65E03216 +:107B0000A660BE0BF33D4FED1EBF1BF601781FF0C4 +:107B10005C47767989359AC7BB413EF68D67F53C5F +:107B20007E991F4B7ACB102347CD5EF1566D77219E +:107B3000BC0DD283264F25FA34903FA2356AAC099A +:107B4000F1B4D8E624BF01E0F582DBD15FF98A9970 +:107B5000FB094AB97FF2E0F4898FA0BD3BF6191BFF +:107B6000F9920F2E067C26FEDECDED84BA1237CABE +:107B7000BD3FE7733937E6992FE97E44D776E6C0F3 +:107B8000F29EBAE74FBD8DF43247203BA3A32E8768 +:107B9000F365C69C98BFD9919FB39ACA93C030CE63 +:107BA000407A50561B711D00D766AA5F745FD67865 +:107BB000BA6F42F89BA0E6194978AE893DE5384591 +:107BC0002DB3ED544E28E0F9817F54F58376F53CD2 +:107BD0007FA7DA41DB54BA6953E9E6D72ADDAC095D +:107BE000F5876EE47433C2E8B82F0ACA23DC7692B4 +:107BF00033FB0B8ED2BA81FE258CE7A64C179BC7B0 +:107C000003DCC65802C4A74B40ECAD86FD4C29A846 +:107C1000A7FCC51217A37845F19C7A5A5F00634B05 +:107C200057A1DE542F886A3DF2C731B17E6A5F6C7E +:107C30006512F62FC97F7617E6E196BA003450CE6A +:107C40009D532F107C2A603C68BFABEE011AEF50A9 +:107C5000355FC7413BEFDF51C1243794D358FEEE67 +:107C6000157C9D4E8C871EAA7B7E17C17B0E87F7E5 +:107C700055270D3A7ACCF047EAE87AF496FEBAFA3C +:107C800091EB07E9CA039CA9BAF6B1F97A7A8F1C7D +:107C90003E4E57DF915F6240397B668E96DFC3FDB3 +:107CA000629A5D37E5199B01E1317796A8F9710D6C +:107CB0006C205A5D8CFCBE4DAA9EC85A8631CCDF22 +:107CC00078FC4E03E507AC99E3B162DEC3997623F5 +:107CD0009D178C4B7CE4D04E238D6B4DF10AE8C789 +:107CE000BC17E02C06E97F4D9A7C53FDEAB81E6371 +:107CF000D07AFACB0C33C6CEB56F53F1E901751DBE +:107D0000C0B7A798705E27C793D802663041FF01BD +:107D100073B89C0EA5CB76B5FFEFD4FEDB547CEC9C +:107D2000CA7F7C7524C2651E237D244F5CB63A024F +:107D3000D751C0881EDBFDBB2383F5C73FF636CE87 +:107D40009CCC3C1AC7CDF9E8E8D9822702CF7563ED +:107D5000E0F377E1F9F2578DABA361BD4F08AC1D9D +:107D6000294AE39F9AFE7DD5D74D543F7A1C9868E7 +:107D700050FFF2D7CDBCFD0426A3BFEB8FAADC6970 +:107D800052E9276D4B3AF917CFAC3793DDB3AD709D +:107D9000C9E63658EFC899773DF102E24BE15D7FC5 +:107DA0007941EED1F34B0A133B317F7FC42A3B4329 +:107DB000FEA0CD9BB6E5CB6C5AB7646488A74F6E26 +:107DC0007DB112C7FBDDB6488302E33FB9D948FC59 +:107DD000E5B27B1FD9BC9E9DEF8F29C9D7DBF9BFC8 +:107DE0005BB3EE89EDF8BEF6F9C78E05E5E974CC14 +:107DF000BA2709FDA6075755B7E5A6F5CE3F4BCCE8 +:107E0000CC85F1BBFC97BF7CEE1D98FF03D765E3E3 +:107E100082ED80CFA7727DE7E0AADAB65CB0534767 +:107E20008BEAFD15A37B35C263F44B0365D4DF8079 +:107E3000148C2E8065FE8C088302FBFBC067DC443B +:107E40007C60C69A343CCFEC270B769FC4733EA46B +:107E5000E27B2FFAC841F59CCE954D32C1DDFD8AFB +:107E600095DB378A9C44F6B1434E2A0ED2E70EDEEC +:107E7000A5C5971C9F201F2F2E8BA2B8B216771175 +:107E8000F3BF6D403EBF70524D9644EBD7C7F1072C +:107E900021FC3231CECBE3F56EB791515E106C0D03 +:107EA000E964A5389AF24D3E5CFA0B8AD7BBEB2DFC +:107EB000525A1CC50D9EC1722DF01DCB788AE3FA73 +:107EC0005068274DE37E84D3F33C8F98E5DEE1EFE5 +:107ED000BDC0F998D4F3097D9F348D9F8B07CF25C2 +:107EE0004D772EBBF19ED479E7126D25FCD2CE459D +:107EF0008C6EA2736156DB28CCFB88E72885FBD902 +:107F00008772A8F310F7977D50765BFD4A289F3A59 +:107F1000DB8F215D687195F2049E7F4047027CCB28 +:107F2000A4F68F57F56EE463A87797AB7197CE05EB +:107F30008CE22EDA78676AFB497CBC5B486F2EAF17 +:107F400001FA475912F52AE9170DC3787E44B9ADF5 +:107F50007B01E5AB0A0607C6CDE343F47A37ABA154 +:107F6000F5C6BF2F923FDF10B596FAC70378F0FE33 +:107F70002166E8B260BF1218AD984F42570DE52058 +:107F80003D4BCDD78DAF7D89EB4739D03351379FEE +:107F9000F003ADDFF3A9887CA0D62223DFC3DC2C5D +:107FA000E4DB04BF14C4A375D45FBA8949788F8316 +:107FB000294CC67B9A823A5FE8FA613CAE17827E12 +:107FC00086FB15EAF8FC1B67F27B206C279383ED98 +:107FD0001616BC9E61BAB2EA27D3974D09669D9CDE +:107FE000FAE06C49BF9A3EFC35A1FD0DB2B36FBFFC +:107FF0006F7590DD95DAD35ECB13D3E03CA8D672D3 +:108000005888EEBDDFB222E5E7D3804E6DCC99FDF6 +:1080100036C0C3F5BE48F2CE10B597E01188E0F047 +:1080200039A7CFCEE3FA2E68E7F5946F0DF20ECFA5 +:108030000FF3B44700BE33B73E4F409B578B2F75AD +:10804000AAFC38901258E00C038F46A4DF2CE4E71A +:10805000DF50BCBB1CF55BC0E5C0EA2F74F73F4E98 +:10806000164D69C47587E621687AA976AFB4D3CD79 +:10807000E56CA73B93F8CE19666F21FD3F94DF189E +:1080800019E57DAC14231DCDE4B7BB9BF2466ADD38 +:1080900016C902CF590EBD3F66F624BD3C28526278 +:1080A00043E485DEDF55EAD4C78986B7DD41FCEBC2 +:1080B0000CEA4DC4EFF87A8C6A5E9909EF978868EC +:1080C000AFBBE9B957E5CFEFAA7A6604F257781F3C +:1080D0008589E5808F7616A0723F44F96198D22E8B +:1080E00053BE632C53A83C80B9A8ACE54126321F8F +:1080F0003DB5FC962416A0F250D487442429999EBD +:10810000C3D00E19867A9EE35CBC87F22673522890 +:108110005E50C4944FB05D41E65724F70AAE67EA5B +:108120003DDC138B14287796B29E7BB9986792C773 +:1081300054E4FC7411DE3FEE9CAE958FF3F214DE36 +:10814000FECD3F7DF138DED305FEA5D67FC6EBCF51 +:10815000954F2E9A82659381CAEF637B280FC8538F +:10816000DE9A06E7FFC9344678E4C955DE092E0FCA +:10817000CF55F621DE68E5095395FDC1E59539CA6D +:108180007BC1E5C773948EE0FE5D79CA215ECFF3B3 +:1081900097DE37294968EFC2EFB7C2048E87F87BB4 +:1081A000C3E4FA04DB294F09042F0BF0ED66E2DB90 +:1081B0004E86740A6463C53C22E033E6DBA19E8DE3 +:1081C0003353BE9F21CA96DC973F3294BE0226B637 +:1081D0001DFD744546D717440F217C4F70FFE9AF52 +:1081E00098C703F4908D7A7E408D8704EAB83F40AB +:1081F000A313ED7DE87C17C27BA604F979537BC6F7 +:10820000ED6DFDA1787C40D5F70EAAFADEFBAA5FE2 +:10821000FADC7E03C698E3D61EFAEE9D7F1AD9F1EA +:1082200020FE79FE7E8F2E3071F921A1BCE88C08EA +:108230007F0FBBB7F5EDCF991A974FF95E43248AAC +:1082400033308DEF737ED3897F021F1CD34FB35F12 +:108250001D5684431A4B98310AE66DCD67A4BF7A48 +:10826000727717D3F70DCA4082C1BA8EAE38861422 +:10827000C78467B83DD192C468BDF6142902F5A53C +:1082800006956F5A58CCF4E1B8FE214692B7A1EB9F +:108290006E88F60918571CE48FE0FE8D38E68B8057 +:1082A0007106E53BF2296FC52D4AF9582E6385A367 +:1082B000A05CD926CAF930CE9EB6125605E3564DBB +:1082C000023E4719E93C9FA2BF8AC7632C8CF22D5E +:1082D000D60DB051BCDABB66E4AEC5C837134596BF +:1082E00006EDD31BC6E5A3DFD363EBDF9F624EEA47 +:1082F0007A3C36C79B780FC32D19F83D1249B162FD +:108300001EFAA615C67CE4E749CF8E8F1683E07F60 +:10831000D47B2A02F3DB1F930C54FF585DB6F5465D +:108320001BDE23F42B9467201D516C30EF0668137D +:108330000FE3DD5F7DA46504EB1D1FA2F3CD3A3C86 +:108340008D729843FCA07ABFA529443F28C957F3F2 +:108350003426B00978CE573C71D6847AEE429B4CD5 +:108360007EF4EC2681F25302BB1CC9784E47EF1B0A +:10837000497E736F93A8FAAD1DE4B70E24B164BCB7 +:108380005F53D122905E2C7ABFADC77E4347C98927 +:1083900038CED0F1DD89C1FEB2C7EEFA4504F25104 +:1083A0006F9941F573331A4796156B0AECFF53AF7B +:1083B000C0F3274C9280F798ED0F8A11B8AE2E13B8 +:1083C000F75334033FC5FBB9CD538AFBA443D3F71E +:1083D000B0CE20BBA5212E3512E7EDC15F85FCEBA9 +:1083E000C75A32293EB2B9299BF24142C7B9771523 +:1083F0006B47FBA46195959EE7D5273B931DD0FF66 +:10840000D3D6298D20A4D8A7BB9626E0FDA0C52DE4 +:10841000161611068F8FB54EA4F916E33D669CB76C +:10842000A5C88C72645ADB1433C2EDDE55CAB3C1E1 +:10843000F31416BBD6205D46B53C4B7862637E379D +:10844000C2F3DFAE519251BF3896C6C2E6493E90A4 +:10845000CFED8477AE71D27D924F93C2B75B97CF49 +:10846000F335A3A7CBFCFEB891BDBB04E05C01F4DF +:10847000540FAF8E36654623DE9AD83262521F946F +:1084800095B8D19E3B8D7A3BF0F3C6BBE6AEAF828A +:10849000760D778FD88FECE30A33D79BD99F45A20F +:1084A0000BD00B2B903EFF638E55F204F15FD41F6F +:1084B000155D7E1A971BA626D16F067E6EDA79FCB3 +:1084C0006F68EF20DE2A41784CBF09AA5DA0E66BF9 +:1084D000244C206D9C7E0D33E6FAFC0CE32E8BAC15 +:1084E000789EA17AFA797872DE3A82C6473D37974C +:1084F000291141EB0096E0277FB98BCF7BAE9D5AC7 +:108500006F0406F34390FE1E5AAFED63E47A3DBD5F +:10851000BE93CFF542806F9FF1BACB7CFA7E9FE588 +:10852000333AB7D1A2B2FB38CAD97522E5558F5973 +:10853000C7E3FF678630F213F5369EC67FF1671CEE +:10854000A8C211E0DA18574CE7D95B3FB3EF80922D +:1085500032B6C73EBC2C41BF2EADDD67E7F6751BBA +:108560008BE4FA603BDA67161FF0BDB1F83CA0A0BF +:10857000FC1EB56985D4D7BE43F919FE6458EF6275 +:10858000F5C864C035E40F9FAE17543D84250C9F99 +:1085900040571749FE607F2588FF015FE1797B3EE8 +:1085A00081E0D3DC7A74F3BDE487B13B782B7E5E47 +:1085B00063992607791E90764F9061686A604F7CB8 +:1085C0004A83E3C9DFAE7EFA097875E2A9E55FE385 +:1085D000D332A0321AE1794FDC9C6B13A1DD58B382 +:1085E0002F01F9E9129FE53CBCB36AF89282F7F3D8 +:1085F000F4F59684A0F5C37FCD3B9E585F89726ADF +:1086000087D581A9E1885F6E1D7C02A9F85D9CAECB +:10861000BBFE95EEE7474AA716507E7B9D85EE751B +:1086200085C27789CA07987A5F43A3A78896910C79 +:10863000FD8B4754BBE9C85AB053A1DC586796F18B +:10864000BB065D8E222521CC78E63A33FF6E4EB014 +:108650009D98DAB34F6DFC2E37F74336C2F84218B7 +:108660007FDF85C6DB53A48C990EF8BFB7C879F9B4 +:10867000F42CCC6F5A44FBADDD5ED7F536B4B97738 +:10868000A02B03EB8FAC1D36414047A451A6FB7EC7 +:108690005EEF73244F5AF03B3E60CFB7B41B2350BC +:1086A000FF707B0D14BF6D698F8B1C8E72CA6608BC +:1086B0001B675D349DC3AB479E38A383F5A1E65C81 +:1086C000AE0F09CF94DD9F0AF0F21EE2798A9AFE7E +:1086D00021A97833C622117F96BC3CCFAD471FE25B +:1086E0007AF519D4AB515FCAAA9282E5534334FF9D +:1086F0000E4655AEC38DF730736C8CE4C750BCACDE +:10870000807E0B1BF34D4BC1EF643818E6E7F6078C +:10871000FD4706CC8E6FE3FA4EA4CDE650108F15C0 +:108720004E5756F81FC2337294C2701E63887E6122 +:108730000ED11FC490F282E97A7D42668E6884B3BE +:10874000FDBEBEF338347F2EE84D74CFCCCD00FE95 +:1087500088A756379D4F34181244CF8A22C70DEC94 +:10876000D1FBF13E1BF7AF48142F129446F2DB6F9A +:10877000CCE4FE8D44C6E35E83146ECF8F9DE4A6E9 +:1087800032D80F148762AFB248E4CBCB8A5CB723F0 +:108790007EA4001B40FBAF7F3A1388DC2F512F676C +:1087A000B5171757FACD6EEEFFF31A221D9BC3E0E3 +:1087B000FDAF0BB81F2E720FEC0DF5DBEBAD74BFE8 +:1087C000254F7CAA89F069BC81FCDA5E7640427E46 +:1087D000F2ABE95CDE1F2A72DE3F9DE2B2CE14846A +:1087E0007F82112C2A5076CDAA1F37E9F6D448D4BF +:1087F0008B3F4C7C91E0E106D8A5C17F9B6AE3FAF0 +:108800008F82F78FD6AE26B8CA03B89F4CBB771EAF +:108810002BF1FBFDCDCE536EBCDFBBA22095AFAFDD +:10882000C8382315CA43EB0202D2DD3D76651EEA45 +:10883000254DF273741E2919B201FD65838DEC4D2F +:10884000CB38C69E8EE1F5DAF7A31EB20FDC149C7E +:108850004F52ADEEFB2121BCBE725501DF67E70E22 +:1088600000643FB48F996A7FDB16933D7EAE0C7037 +:1088700043B8B8B9FDFCC274DB62F770B28B78BD47 +:10888000FB2ADE1EE3A5502FBDFD7E15DAE38FA681 +:10889000849FF74B75DE47DFEA7E04E358FF59CF2C +:1088A000E358BD9FB39F1980B76CB0B3647605F0F1 +:1088B000B9A5E679E1BE2373CD2CCE473A6DED0420 +:1088C0002F06F23CFA2ABA471FAAAF5A918E4E4B96 +:1088D0009BEB27CA9C8F644DA0ABFD1CF742C6BD25 +:1088E000B0DEEA4840FDD3B3B4BB01F98767D7D205 +:1088F0000FF15E7A799999F4D67263CDBFA31D64A6 +:10890000DCCBF35FF01B13880783801FE17DD36905 +:10891000D5FCFC164ADC5F2B3CF3B13307FDB18973 +:1089200046C24B4D8F1D6351DCE897DDA0E6B7339F +:1089300071483DDEF7320E16C9EF1B55077A2DEE52 +:108940002F97E7EB2AF03FE4439A9E6B4B37EAF20E +:108950007ACD2179BDC6903CE0AFA7AB79722A1FD2 +:10896000B2678DEF539F7A15EC605CE74EE043F8F9 +:10897000F4833D8CCFDD60AFE3F335B0D7D10FFE8C +:10898000C6AA51F47C739583DEBFBD6A123DAF4B1E +:108990000E98109FC91FCDBF33E717C8AFA7E19945 +:1089A00098966DC3EF76F0FA21331BFFD57D35D451 +:1089B000C7A9EDDDAEC5F49D3AADCCD62ECE4E277F +:1089C0003F38959B67342F46BFCFE652C53A03F038 +:1089D0006480C15981DF7960775A286E11BA9F0788 +:1089E0006768723CBC1DCFF013067A3FCEC0197D7C +:1089F000F8711E12F83AAEDAFBFE16A48F7E4546D9 +:108A000027E27172AA3E7EB07206D7F35E579FC905 +:108A10006FBB86F6755F5FA38FDEEA3D3B0005FA0C +:108A2000F55EEFB5B36BB1DE13139EAE06AA74D537 +:108A3000EBF8366E4FB219406F83B11C6A1F0628DF +:108A4000BFE4746D8E9FC8ED27D35B7712D25B575E +:108A50008CAF1EEDC4AE5D4BD7E3774244A4372400 +:108A60000BA4378C7F68F456CBCF6321D21BFC3923 +:108A7000ADEE3D670ED26302A72FE1999DCB291F72 +:108A8000E32E9E47A3D15B8C9A2F1F25B593BD483B +:108A90001FE6C07E407B1B04BCC773FC634AFE100C +:108AA0000B1CAE7074F723E9AD6CC64FA3B77FBB48 +:108AB0002640F9139D294A02EA335EF5FB813F9671 +:108AC0000ECFCC3073B970B92F11C7D9A08E336DCA +:108AD000C861F2FF15581D22CAB37C99C3356F7C5B +:108AE000267D6FC8A7F6DBED5456CC80E780B9270A +:108AF000C9CF3BC0C0E9F7C1B7CD8B11EF931A0EB8 +:108B0000164D437CB943247D3B745F1F14AA713317 +:108B100081CF0B9A5762701CF11E952EE53B3A38B7 +:108B20009F8F61521AAC27C12D15E7635CE86A0379 +:108B30007D4FA45FD1C11894CFDA78707009986F17 +:108B400082AAAF75DCF9F408BF76D3401D3DB7E0CB +:108B50003E7AA3E70BF10FFB0C41E31394EFEB52CA +:108B6000EF49FE58BF6DAF7EC4CBC3FB25AB66712A +:108B7000BEE131F1FC0F682DE177019A8A5C4FE28A +:108B80007ECED3FF764A7E17EE637934F995138C47 +:108B90005CDFC36F24F2EFE5B809CE5AFC4DD31762 +:108BA0006585E7172517BBFE80E36E62F22E94679A +:108BB00036079B47F13590678817CB8A9417675023 +:108BC000FCE5D2F4C02F8B9457895FF7824F03AE38 +:108BD0005776F7856F538AFE63CF0F48FF65DC5FDA +:108BE000BAB0AC8672B306819D84EB9DAAE6677825 +:108BF00086F07ACDBFEA1DA0C54F9542CC9F8C561A +:108C0000E135C6E26415D0BF0BE530DEDFDB1BF0DB +:108C1000E3BD600BDE2393D08FCAA87F4CADE093F9 +:108C2000B1BFF8E5EB182F32E5D0E744189BC4ED4F +:108C300001EDFE8D94FBE3FC8D87353E318E8D4733 +:108C4000F8241BE40726C3FBCC87F33AF078B21E66 +:108C5000591C8BE272E2A68612FCDED6D2AD9F6E64 +:108C6000427FE8E47FB7303C0FD01FFDC6B0F95C0F +:108C7000FF303942743570563CD71353C2E3E9E3F1 +:108C8000B354FD13F1344E87A76C66783C25FDE79D +:108C900027E069E44C3D9E1684E06914CD7BE978B9 +:108CA0001A3B13F0F4559083B8AF17E72A0366F622 +:108CB0008197DF952A897DD507C507C8EE1BC12698 +:108CC0005983BF7BA83D5B515EF6919FD07FCD114C +:108CD000CA8FF3D49EA63CE52EDB917D6807FD4745 +:108CE000AD450EF66781FEAED3D75B40AEB8C19EF0 +:108CF000DC304B247EB2E70E8BFF3AD46BEBF87D71 +:108D000084F2BA4D02E67B0FAAAE115CC0DFE21519 +:108D1000301DA17F8C62E8F19FC07F57980E903E76 +:108D2000BB0EE4B19BD817BF97A6C9FF31969AB77F +:108D3000D04EF5FCCDE8588DE7CCA45DC88FA603D6 +:108D40003D617CF39A6E906F41E3BDB56312F9D536 +:108D5000AEFB1EE45F901F670A8C185CCEB126EA5A +:108D6000FAE54929BAFA690997E9EA35BAEF8C5167 +:108D7000E32A595B72117FC40A9EA7305DCED0B53D +:108D80005F57964DDF03B86232BF7F3773D464DD1F +:108D9000F8A17AC1D5F03FA47731440F08D513422A +:108DA000F5828533F5F740D71803D9C49F18CFABA8 +:108DB0001B7AF6DF880ED6C91CCFBD65A7281FC356 +:108DC00003F63FFA9B0607E597225D8C3507C83FFF +:108DD000B761BE95CE63C38E27E8BB119AFF0BE83F +:108DE00086E8686CB64479AEE9F65F537FB694CBFB +:108DF000D950BA14EA5E22FD6FE36CD81B7E6F6D0A +:108E0000760A977B3B03E48760779A19CA4DAF6473 +:108E1000A0BCB1DF08FE086118D2AF42F28925304C +:108E2000C94BF992EFF1EF2932E6589388A6BF4279 +:108E3000798D80F6DD6FA979B488B711F9CCB17A54 +:108E4000327EEF97D377FFF1FC7C6C0E5E96AEE638 +:108E500065CDDE8E49602D98173B18C783B671B576 +:108E60004CF2905FC34FF543F2D9010FCDCFFBC752 +:108E70005731671394C51A45F537BBD4F87A37C50F +:108E8000BD53054724FA3786894E8A7B473389E2EA +:108E9000E283580D3DA3043F671E97C847AE00000C +:108EA000A0BC603799E9FB19D94FDA187DDF68A9B2 +:108EB0007933E5650564F223DE7388DFC3DB60FF89 +:108EC00005C5099AF6F1FB04F724B93FC478E6A07A +:108ED0003A81BE132E56F33882F8A6E89806F5625A +:108EE0005D2B7D072EBEDA407EAD2BCC35BBE81C5A +:108EF000EEB6D0F7E3BAA03FFAB9D6D90D8CE81593 +:108F000098C7397F2AFCBAAE7152DCA2EB6FFD48DC +:108F1000DEB1103FA7C7C5F56F4F9C99E397EDD41D +:108F200027C8B71BE322E97EDCBC6B6BF6211FD997 +:108F3000F09EE858ADFA9FD1FF3F14FFC0FC03B389 +:108F40003305F54E7375783FA59939F767A1BFF4DE +:108F5000AE25097DE951BDC6456C06BF39FAE2E38D +:108F6000220DE53C0EA2AD53DB67A36DB95029E39A +:108F70005F3F312E52D64B5C24502320BF1F8AF511 +:108F800063113EDC6F7DA971919AC24B8B8B68FB9C +:108F90009EA5FE5D0088ADE677505C80CECDD0B357 +:108FA000BE20386EC1F595E35F327F8F7186D96A36 +:108FB00079DF5307BF44BFFEDEDFEE7E0A9FD79DF9 +:108FC0007DAC6C39E045D1243BF97BF7FF32E641BB +:108FD0003E9C3E7E30CB61D1F9EFF187F849EB1032 +:108FE000F8BDFCE0FAA29075651BF5F1805C9BBEB4 +:108FF000FDD4387D7DFE107DD9CC6A084F43F7BB88 +:109000003AEA6ECA936BBC8D39788678D079881726 +:109010002E9B8798C3EE4BC337E64821BA5FF73ED5 +:10902000A77BE72B2BDE5A4976AC81EECF9F9ED7EC +:1090300070CF3B32E28799B9699C7C05F1E8BBDFD0 +:10904000A7BF4B311DC9E5BE11DA57E6F0EF459DCC +:10905000174F50FDF9436B77B5E706C57BEF1DE869 +:10906000721400DE0CB59D12500F195AFB1AD5CFA1 +:109070009D9FD5271EA5D5EE69CF0DFAAE5F9AD17B +:1090800069403F465AED1BF4BE37BDC720BB79FE91 +:109090005E9959267B4BCD534B53F126AD8CFB5B30 +:1090A000A5542E6F3698B87C7343B57815FC5F5B7A +:1090B00068BE1BE7EB6726F17B1D0CB810F22B6D29 +:1090C000BC5079A6C9019BC2F5C8B4B287B85CD1BF +:1090D000F205DB42F3E25C73113E427523B5DB9887 +:1090E000A3B6DBC9F5533683492897619F61F344E2 +:1090F00017A87EDADEF2D398663FCE79F343CCCF61 +:10910000FBD1F6632FE35E971C087BDFF636D56E46 +:10911000ED8C082439B81F38ACFE3EA374EAAD05C7 +:109120007DE8AF98578B30EDD55EB8C4BCDA8D6A58 +:10913000BC488B976AF9B5CCE81B87DFF91C65FB47 +:10914000F30D1407ED25AFF61EBB2380F7DCBD152C +:10915000118ECDECD2FDEB5BA7737E5A5DC0E81992 +:109160001A5F085DF78602DEFE5091F3E1823EE26F +:109170000A5AFB0F13C3FBE3BE2DE4FB3F775F29C5 +:109180009FEB7D8A4961E1F240B57CF7D0F7600F33 +:109190003D89EBD0CAAEFA34F2DB794C1C6FDD327C +:1091A000FF9EA0A63FDA507F243DAA85EAA3ABB973 +:1091B0003EA9E959921AD708A527A08F3FE23C8221 +:1091C0008DD3ADA6279EA38FB9401F409743188F1C +:1091D0002B19D4BCD121569E827EA97AD4F9F6D31C +:1091E000F7F64BB29FEAB74690FD54BDF92DD4ABCC +:1091F000D6D5723F61A7BDE62DFCFE81FB3D91F403 +:10920000A6DEFA6B76D447857A3B0AE38A888FF12B +:10921000369F205F8E7654C0E482F595A31D65C30A +:10922000BC555700E1166A4F75DDFD05E5BB82BDF3 +:1092300079B820EB1FC01F42FC4B8DD3393EEF1A8B +:109240007E8AFC26622DB7F7C45A1E0F3596F1B8F8 +:109250008551E17E1433C82374056A7E940D0EBDDA +:109260001FA52B89FB51E2736BFCA8079A26592492 +:1092700085E423F7AB6879ED632CBEB7F03E862713 +:10928000C3C8300F1D1455B2032D6A7C03FF410B78 +:1092900094579ADF24346FDA16E22709F5A358674A +:1092A000E9FD268F0AF2BD93619EE7D7E7BD83688B +:1092B000FB878D8BA3D06FF292AF61A6EA37791846 +:1092C000D7B3E343EE37E9DAC1ED22172A305785E9 +:1092D000C3BFF3E254E407B966DFE12AF483687E92 +:1092E000A8F86A151E6ADC07E18BF014F3393C63B9 +:1092F00042E0E91DA2C58554780EE0F02D2F709252 +:10930000DF4942784A3DF0D4FC54DEBDEDF47D6D7A +:10931000CB1D16D94DF0FC92EC5513C213E1FF138F +:10932000FD50E342E039EEE1CC07F03BC1E31F29F9 +:10933000E9C0E7844DB7C5DE00CF495B1F28C127D0 +:109340007B93C709FE7316E75798D91D4C8F636747 +:10935000C8BA3883064F0D0F7BFC778CFCB1E51241 +:10936000F7E797AB789886700BF6E739F470DBA0D7 +:10937000E64B1A736BDC68EF0E0D819B86871E84AB +:109380001BF2BB18B3EC26FF5D9D80F6506F78385A +:10939000B4EDC7E1E1FC59AA3DAFC2EDB9F599F7CB +:1093A00022BC5ED858F20E3E5FF4DD1685F0DABEC0 +:1093B000E58199BDC02D3198CFEF991E1E6E5B8B54 +:1093C0005DD5B3E0FD750E9F91F82CE01BDABD9BD7 +:1093D0009BC659F5F1198D3FE65BC3C98F0BFB970F +:1093E00096535EA1A76C39F1C7AE73FCB1DB8E79E1 +:1093F0008817CB1F2D85FCBE7D79ED77AF5F077099 +:10940000CDA93D4CF46704FAA373AB3B6C50F33128 +:109410005804C88BF832E6C7F8F12066F545099480 +:109420009F407CD38B79CEF881D2503F85F4C65FC4 +:1094300005220E261812808F63EED4152407EF9FA5 +:109440001586CFAE2B3390FF67B3EA1F944B9D2D4B +:10945000D84E8B6F2D2B525A67FD347FE1C3D85FF6 +:10946000F31776C6B073FE35FC3E784EED2601F359 +:109470005006D5DD4AF221BE4C61281FB266CAFCF7 +:109480007BB3B912EDF77C7F5B770EDA099D78A389 +:109490003D83F0E077384F67EDE38407572CE5FE16 +:1094A00091CEDAD3B1E1F1A036E2D2FC8C9B757299 +:1094B000D25BCBBF63D26957DE4CFB11783042C51B +:1094C000034D4EA2BC417C3296051E463FF620C09D +:1094D00087881494979C1F8BA0FF44C17EC45EFCB8 +:1094E0008F1A3D74C1DA2CFDF09E70683E400DADC0 +:1094F000FB7459B67F621FEBBBE83C00352EE95187 +:10950000E3920B6B79FE6AE71DDFE5E17A4F978105 +:109510007D0070D95CE660787ED340B10AD882E7DE +:10952000392F6F358074ACC521B578FED662E7114E +:109530003CD7EB00A712FA635EAF1AEF19A27E07C1 +:109540003A04FF01CF3FC77130DE837240F3A3338B +:10955000D41BED88DFCA17583FD65C9328117EBB19 +:10956000BA71FC753BEEA4FC851EFF20CF87FBC9BA +:10957000FEAD6833E5576AFE2DAF9DFBB72A5880D4 +:10958000FE9D3C8A2320DF6EB5D0F71AAA04D98C41 +:10959000EFF717BB8C85A4F738291FD635C72A915A +:1095A0001F6CE9B644E417E58D22C9EBDEEC92F3BB +:1095B000E9EC47F21995EE2E81CF0C2EBC383E9384 +:1095C00054A8E733C9853F217EB67E969EBFA0DEB4 +:1095D000590FF3E4A8F4746EDF6A1C1FE3571119E6 +:1095E00041FAA8BADF503A3A4F2FFDBF8FAE66223C +:1095F0009CC3D0D5ACC21F4757A58503FAA4ABB90D +:10960000857ABAFA1996FF17D2D5CF691F17A02B02 +:109610006321D3E749C7F2EF3C8F8935F03CCBFF9C +:10962000C379D25FCDE4FE8BD03C69C66AA85C00EA +:109630006743E7A3960BC73319E34C964DAFAD1DB7 +:109640002DF3F182FD9D2CC4CFC942FC9AA1FA5D95 +:10965000183FA8CEEFB9F789BFEC1D0D7F3EF9F496 +:109660007F915EBB6FAA40F7C90B477EB71375D0D9 +:10967000A23595EA3C7DFB3DFFD97E4EFC05FB55AE +:1096800043F7D51875B77A6FE0C7F93999E356FAF9 +:10969000BEF9BA1AE640B85FC8EFB9AE8EE74D6BB7 +:1096A00079CDCE57AA1E2C1DCFF3E9D0EF19EAEFE2 +:1096B000D4F2953DB64AD2F38F2856EE8F0DF1774E +:1096C00056C6CAB7D03DC6F3FD9DEF16FE03FC9DFE +:1096D000930A64FE5DC610BF677CBEF261611F7EA7 +:1096E000B3CE1807437E9763F30918AF656733C994 +:1096F000AF33C816A0EF6B95D74E213DF06491EBC8 +:10970000535CA731B7FBAB97C653BE8103870AE50D +:10971000CBA0671E2FFC27FA09FE597E3E5F01F79A +:10972000735DECFD791FC23BAB8F7BF472E0912837 +:1097300078FF68BD9DBEAFB552D5A33B4DDD492D29 +:1097400050BFFFAE13BBD13FE16B3330BCDF76B10E +:10975000FEA3860BE8C5E610FB68C339BDD8F7D673 +:10976000C420BDB86155FE8E6361C6D1F4E29B662C +:10977000EBF5E2721BD78BCB6DDD26B40FCAE3BECF +:109780007F1DF34E8DD5AC1DE5E220A586F4E17872 +:1097900089513EF1FF8FCBB37F685CBE78B63E2E19 +:1097A0003F56CD47411E8FDFFFE9D2FCA893B8DEBC +:1097B000B0C6C8ED15AF02EFC2C4D143E3F243CF48 +:1097C0003E4371F975DBAD748F6FC38E663EDE1458 +:1097D00026619E792253F5B502EE2F0DD53F1E3539 +:1097E00029D694F188EF06BA4F88F704C92FB2DD65 +:1097F000BA09FD4DE9769ECF6DDEFFF256B73148CE +:109800003F043D94F4E2B2007D97A95C7230E23BE4 +:109810007193FC141FAF1308BF46CCE6F4B330D7E6 +:1098200047FAE1A03249E0F7C4DCDC8E4FE671E78D +:1098300048C42F682A8EE2715FE980E8C0B8F37DE2 +:10984000D87432DE5F65FC7B15930DF4EF50AC13DA +:10985000BA13902FB70A4A223E4167A27B8F4FC7A7 +:109860002803F1DF93F22419E8DF93DA93D7988085 +:10987000EB6BAA6F4D40BD70CD6C1E4769CD3B4E62 +:10988000F90FA674D00753E819F6DF1D9DEB14D429 +:10989000BCC0F604FA1E026BF990F06A9499F17F4D +:1098A000E7C7E15F84F474CC46FAC2AF041FBF2758 +:1098B00064B7D27DBC96CBCC8955B09E66BB99B4BB +:1098C00009EF65530FA4C0FBE6015234C601BC2961 +:1098D000A912FA8FBC318D6FA21FA439259561BEE4 +:1098E0007F53D9048A9F379D0506033D3DA347EC6E +:1098F000CF82F76B84007D37C83DD9C0309FB0ED73 +:10990000B2A989C1F7324529544E3A482E88B2810E +:10991000EEF9896A3C5B3C2F9EAD8F4F7F3F9BEFFA +:109920005B662DF3E81E689C59C2FD965F56FC21CC +:10993000DD738B33535E50B989F1EF7E5CC6E85C12 +:1099400042E1E759A58F2B186DFAF5ADC1C034E59A +:10995000619F5D82F8D18030A53CEEAF96205F6AB2 +:1099600038577F92D747F0F2CED94797A01C941969 +:10997000FFF7491A46F1BCCBF201C5C487CB4D8134 +:10998000B0DFF9BDD07A64E653D4F1D8FFE4786B48 +:109990002E33CFF3A55F78BC9E7301F5F912C6D5BF +:1099A000DA858E1BDAEF7FAA7D6FFBFC68F6B9FBC8 +:1099B000719407412AA27A9F0DF564A3CA0F3DD97D +:1099C000137C7E19F9819BD3458C419767FBDFA6F9 +:1099D000F2D6B800800000001F8B080000000000D5 +:1099E000000BCD3B0D545CD599DF9BF7E6CD10669F +:1099F000E00D0CC910093E082831045F1288A04907 +:109A000079046240A94EF809B825E944A346DBB3BE +:109A10009DBAD6923DD932094320989009A9256E66 +:109A20006D8BA9D9B5B547A9DBEDAA47BB9398F5CE +:109A3000F81FDA5AAB7B3C16539BDDF6B83DF42792 +:109A4000969ED336FB7DDF7D0F6626432069F69C0C +:109A50009D1C72E7BE77EF77EFFDFE7FEE9C3B87A4 +:109A60009F5A8073562B6B2A9865C09F73607DD672 +:109A7000E0736AF93FD0FD0B0114FAE6C047DD4DF3 +:109A8000F1A24AF1BC25404370BE1B4003889F935E +:109A9000F0A9050F5FBD74AE182014C4877902AC1D +:109AA000B67006EE4FBB56C7EFF4039C4538B9C6F7 +:109AB0000C1CDE47113040B0C763FF5A35FCEE9DE9 +:109AC000B4EE35601CD367C62BD6BA571F51216E32 +:109AD000CFC7BFCF5AEBFEB4AB353BE499396F6AC1 +:109AE000BB6C3479DE8774065C27E283D163F83D72 +:109AF000FA6E4CE24D3C837FB8DFE84A6D74109FEC +:109B00003F688FF3E2B822315FC7FD66C0CC47598A +:109B1000C878B05E428903E7EFBBBAE2519AFFF022 +:109B2000E3C3DFFA363E3EF29D3DBFA4764149C510 +:109B30005035C2CB341C86403B044A900E4EFA8608 +:109B400078F47CEAC814A21FFBC978DA5B7E678CC4 +:109B5000C99748471C7FC77EC9D4703D97C77354C7 +:109B6000A6FDB92593F62B1F5EC4FB0F6C4FA6FB19 +:109B70008864BE1DC0F19103121CC37E8691B00E95 +:109B8000FEA905C9E39B09BF55D44B18871B3F2885 +:109B900041E7581A7C3F1874303D886E9184FD1F50 +:109BA00072EAB7105E0FED932182200FED74012C45 +:109BB00006F846F0DFEFDE5D02F0853E27E37D64C8 +:109BC0009D3A2AE1FB11AFB6B993FA4B1CC6511D61 +:109BD0000463E2B90EAEB88ACF65AF3778ABCEEB8F +:109BE000C5D6A9F9E0A1719381A097F9E88D2AE281 +:109BF000A3B765E6A3D4FDA7F2DD5C7C5618CCB113 +:109C0000F0300AC115C89EB279E20CEE0FAE763084 +:109C1000FF2CBFDAC1FB3B5B8003A4D9F9B0AF07CF +:109C200017B87A866F548BEE7BFD2DA708FC6CF37A +:109C3000D4D171B3A882D685F05839F27320797FD8 +:109C4000F6B8926979F83B5850C9723726E3595DE6 +:109C5000A371132AA81D37256CCB1EBD5FBB90BC1A +:109C6000B820017E11C1053E7FAAFC3A21C448DC20 +:109C70009359781B9DBF6FA30AB29406DF73F40F4C +:109C8000EDBCDB24FA473E0F4629EA096720992FED +:109C9000832F9430FFC80332B8A444FE6A34895E2F +:109CA0005FBAD539AD7FDCB61E23BA1B45E0C07D57 +:109CB0001D7E4B66BE391CDCFB0B99E4BB51D525E0 +:109CC000DC7F46ECEE87DAF1FDA1D765631087777C +:109CD0003FB3EB67AF627BBABA788D544C44322302 +:109CE000DB71FCE9F56E63D010F2378D97626E4C34 +:109CF000F79A99F50E5517F37A515C4FBA001F2861 +:109D00008DEA0744875478D3FABAFBF858C3EA04BB +:109D1000B95A187A2188E71BF2E0263CF4FE24BFEA +:109D2000874AE4CBFCD9D7418C325E7E465F71DC3A +:109D30005F5ACD9304A7A9B42A9249E7826C207C8C +:109D40007CE8356EF4E190F79D86DB289F99DF1B58 +:109D50007342BC9CF080EB62DB0C135B5A88EF4BC8 +:109D60009CAC3F64FF4A7EBEDD1B541CB8AFFF0CA9 +:109D700016F37AF6FC26F8B2721FBEBFD639DA4067 +:109D8000FC11DD0E5A04A76CF3C614EA6FA00DE2B5 +:109D9000C21BF53A7711C26D7C9E1602A8F50DFB29 +:109DA000C90E553C77A42044EB47CC1F95219E7DDE +:109DB0000255B0DC351EACC7F9BD6FC8C61E7EA209 +:109DC0001D0FE17C252003D1497A6A6D6002F7A35B +:109DD00078CEBC075900EB26011A12F8A976CA0DF5 +:109DE0000D097AAE0E2127F6EBDDF949E337684518 +:109DF00049EF65308D38D277636059D2386F55A5F9 +:109E000046FB6DD257263DBFB9AC26693E3428A724 +:109E100027B0BF16FF11DD65107D5BAE3CE5D84F66 +:109E200098AF40421FDFFF25E8F59FC9C4CE75708B +:109E30001DC94F33189D241F68BC8D63889785CF3B +:109E4000B92732C9909826DB75C9E2CFAA4D454C97 +:109E50001FC973C641F87F0461C8C81715DA848327 +:109E6000E804DA98C4CF516F0C22B2038AC9E3D058 +:109E7000C069511C77056A6F0DFBDE00C4A8BF04E2 +:109E8000623C1E3FB1C335C8166E313FAB058C83B3 +:109E9000F83EB33C2249D8CF69044346781E635C40 +:109EA000A27D6A385F5E492C19E77E41238CF73228 +:109EB0007C730FCDCFEF06AD2F9FF997DF8F7641E3 +:109EC00084F6F32818E092091FA890969216097359 +:109ED0007B25E839A487BE09C62AEA97C204EB2588 +:109EE00034EF12F517C19826947D9CF5374C28BEA7 +:109EF000336EA1FFD3C9CD8CFC2870C6A60B0EBE55 +:109F0000FF56B37C13EAC1CDB7555DD0DF50BA5FC1 +:109F10004C92DFBB37E98C77A57B23CB8BD2FD122C +:109F2000BF1FD814BC6E133E2755E05E75F1F8AF25 +:109F300050053EA31218E8CB40F4D99B02DBC85F62 +:109F400079D66D94B2C8233E892FAADD93AFD48809 +:109F5000F9440F3FD283F09D530E12E16009D10105 +:109F60009FAB48877D4CC718C32D0C83B1DB5A9734 +:109F7000FAF94807A2CB28680B08AF72F8E2E8C0EC +:109F80001F84B3E81937FB470AD165E965A1CBA760 +:109F9000098F174B97547AC0AE5C809AB9F5E95790 +:109FA000A57886B494C882F4C1F348481FC26700FC +:109FB000043DD0AE1B84A774F8A77E4625E87BB885 +:109FC0002FC6133D233533FC9F8DFC2FFA42BE7CF8 +:109FD0004807D11774F293BC603F101CE3F939DBDA +:109FE0002178209FE86132F26CBBEC8249F66B8BE2 +:109FF0002583E9B55446070DFB9952DC727E46D99C +:10A00000AE6781C6F4590C616EFDCEC9E3E7485FC7 +:10A010007B1CA391226A9FAEA3757A9B51C390CA01 +:10A02000F70ED7315FDE035A29F25DA16AB2FE2E28 +:10A03000BC4631227A22BEF608BF49378F90BD292F +:10A04000747861B07266DDA8D308C4905EA7BC675F +:10A050004E84F0F9827CB4EFC60C9E4F3BC5F908E4 +:10A06000A67C05C983908F4035EEC577BE7E0B2850 +:10A07000826F3D3B107F888FADF402F1240DFC1BF5 +:10A080003F7FA45EE8BBCF6E0A3D4EFC42FA89F1E9 +:10A09000678246FA493380F5A6438FB09F7076C039 +:10A0A000A5139F426CC424BF629BB5CEB601D707EF +:10A0B0005256C239A3AE243BEED083D9CCCF86040E +:10A0C000E41FCC77DEA5F23F74E7CDCB0FA87B6A07 +:10A0D0006DF644F9ECE354928FDCC479824EAA3FCA +:10A0E000C47E874A72923B371C678AFF62C371063F +:10A0F000820CC769FB2F64B7909E77A1DD1A447C60 +:10A100007FDA448788F972F23FC89EDF1ECE62BFB5 +:10A110008B5184E3EE8849A383C88F774258253E4C +:10A1200095A02442F4DB1A91D87F2BDEB73D8BFD3E +:10A130000568D0083F52FC06F9DCF28BC0A385A766 +:10A14000ADF15F3A752FE1D50B3F4F88B7ECF7BF04 +:10A15000EB5A7AAA4A27A5ED2923FA665AF445B59F +:10A160001D790DF7E9FC53360C6AE4177FE98D5A27 +:10A17000DC5FDF8F6583E2B34C10F1D50210763CD3 +:10A1800093E47429F1CB58FC33C46FDDD91A9DD701 +:10A190001E07D6B80884D83FCE443D40701D99FBB9 +:10A1A000993F33B354DDF6B721F11C6E89FD608F02 +:10A1B000A572F3D4789CE42B0FFDD8DDC9F02511EE +:10A1C000CF03C7437C0EE9FCF55758FE3ABEAA3BC5 +:10A1D000370FFF3ED57F87C47890C663DC194FC028 +:10A1E000EBB4BC587266EFDBE35193E525659E4DF9 +:10A1F0008F72A7E08FC5187FEDC6FD0E0C1CAD2336 +:10A200007D3392073A469AD0BFF59F248AB3D693FE +:10A210002E26FBD300A3144778401F2CC3BEB3C027 +:10A22000C3FCB3E8BF83F1CF209CBBAB5D9A8E38F3 +:10A2300059FC91A9D5E1FBBB0ADC8689F48D5AE370 +:10A24000230DE86789E5DF26BFF44E6BBF4C0B9406 +:10A2500043B3A588F95DF1B5ED7D8DE2DEC532C869 +:10A26000A4D7E42E83ECD39D1830E4A2EB0E5F76E6 +:10A27000B2DF87FE1D9FC7D590ECF7DDF58833A9C7 +:10A28000EF4CF1136B5B92FDC0A616E075693FB908 +:10A29000ABFE7AF8E0F1B3FE5CA18C3BB43476D52A +:10A2A000C6BFF49487F1FF421EE295F32441F37395 +:10A2B000D877211E895F11235955882793BEEAE478 +:10A2C000277FEF3E1AEF3A8BFC4BE3654FC3E788DD +:10A2D0000E57587802B12F13FFD1BE53FD61578A34 +:10A2E0003F9CBA6F9B0E77D8F859036B083FE89FE5 +:10A2F000B37F609F2BF53CCF637CDE80BCF4831E74 +:10A3000037B7F11E8DDB133D016E4FF6E8D0808E1E +:10A31000D54B3D65DCBEDC63F0F3577BAAB9B5F1E4 +:10A32000319BBEF1E639D85F38B4CBC17902A55C68 +:10A330007BE56AE2DBB764561F1AE819CA52B643D6 +:10A34000A0E0B82B1B955193CE62C53F8B2C3E5B92 +:10A35000EE9A3CEEC279B17C30F6D044B4DBDB2B14 +:10A3600067E29F75938E1939018A771624E50BEA07 +:10A370002037A95FEFBE2269FC066D69D27B9BBEC8 +:10A38000DFA81372B331B03C69FCA186F5F1BBC9FB +:10A39000AFAF7169946F68D25727BDBFB9EC8624FF +:10A3A0007820371BA4A773BA12E8C6E74FA6ABBA4A +:10A3B000E3C271904DE7D11439988DBEA97C6BE34F +:10A3C00035671AAF22AE8C525CA9D3B9CBA56D0804 +:10A3D0006A68DA2F3181F24BF6BA4A35C69715977B +:10A3E0003FBECCA2F8B2285D7CF921E76DE68C2F48 +:10A3F0001B93E3CBAC14BCCD155FBE7A89F8DC5A55 +:10A4000028F26E39AFCBEC07CA8D61B67FB9E3B2E3 +:10A41000B191424FCB1FF392CCE3B8AD552AFB97D5 +:10A420008760220022AF984FF630B7DCC8277DF353 +:10A43000A4CF5C781BC5F94D0EE3284E79B1EE2B05 +:10A4400001F23BF6ED7E34804609FEA7C5C1FA2E27 +:10A450005677660BC995A2A31F27716B8EA6F14F85 +:10A46000ECF176BEF1E016916F3C68E51B0F5AEBFC +:10A470002042D8DE8E54897CE3AF5B742BFF17E15A +:10A48000FCE2E12D6BAC7C23F657D07083EDF8A095 +:10A49000D730EF20FEF9850722F8E880A4654964EB +:10A4A0002FB63834CA1F8F34AE7A97F249FB3CAAD4 +:10A4B00041021FF5ADC927FE92B7A2DB83FDE1C6BD +:10A4C000E19769BE52EAE07E74CB559C171CC9D354 +:10A4D0009A8A29CEDB504C9806F9993FF5505E23B5 +:10A4E000EA3B13A0F9BDD78BF9B3D12735FF2F93E2 +:10A4F00026A6F8ADC41157118EFCFC993F13BCF38E +:10A50000F2F3297EC5A04FE5BC6DFE8FF77E2B527E +:10A5100042AADCE47CF308CA3CE169EB96966C8ABB +:10A52000A7B63A27F2D2D90B3BFF39ED6FFA93FD6C +:10A530008454F8FCB1F36B0ED1D5EDBC2D7EA2B7DF +:10A54000DC381A27BC41ACB198E25E8FB0CBB3E1E6 +:10A5500041F15CB80E22776798190978B0EB1DD7E6 +:10A56000B68A3CB8D1AADB79C6A47A89D2E8E07968 +:10A57000B67EB0F3E3A975127B1F35AD224F7BFD8C +:10A580000CBCA4BA89BC56B5E0191C17A7E6B3E702 +:10A59000AAA3CC95CF6EB6CE73B175937B5B81E7E2 +:10A5A000FD7FCD7FDFDBFA7F93FF3EBF5E34CAF2D3 +:10A5B00003CF4CFE9CE43BBA6CA13E28EA4349F52C +:10A5C0009CD43ACE60868033BC52F8A9C3563FB2C1 +:10A5D00042C04DADEF6458799548EB521187812107 +:10A5E00088AC9885C4171EE5BB110DF96181E71091 +:10A5F000F8B075F9B745A8AD2DD487AA715FC3CB64 +:10A600001C6CC786BDA147FB480F2DF3A4958F8313 +:10A61000AD422F0E10DF72FC04A683E44EB2850417 +:10A62000420EA4D708733EC0D1569FC86769B1EAED +:10A63000DB118F5F25BEC8E3F3F0FC54F85F3B1FCE +:10A64000FE63C4AF510B38C1D98670BED93A5D479D +:10A650008CD07BB7B59E5B8F5593BFF058AB26F47B +:10A66000B0B2D2A0F30FFBD2AFF798B59EE9084B7A +:10A67000346E5197980F6E31EFA034D9795AD09338 +:10A68000E589D6A7F79946B27E48859B5176E17A4F +:10A69000D9D3D3FB4F8E870E48E9F7F9634B0E6B86 +:10A6A0000B81ED11F1C59E347C912AEF2AE53F1113 +:10A6B000EE098B0EB6DEF128E3EB332BC9BE83D156 +:10A6C000CB883DCEE7DD93790BC7C97D378B3C87BF +:10A6D000AA08BD5DD089606AA8BED210E1BAE1FDCA +:10A6E000A0B97CE7E3E162E33DB2379184F93FB181 +:10A6F000F823B52E18A3BA20F9B15417A4FE4E576B +:10A70000673ABBFD6E8BD3B2BFE9EB3B47A8BE8374 +:10A71000F38F545BF59DA0A8EFD43DF508ECC4F78A +:10A72000BF331DECB74ED7771A8AD7480E9623A0B1 +:10A73000FAF47CEB3BB18679D67782175DDFF9635B +:10A740002BE2E79047D459A6EB3B6DFE79E5757493 +:10A7500088C5BB49AF7401E3C1DB340C3B299F10B2 +:10A760001071C6892A97E0AF9D92159F4103D87A50 +:10A770000A3FCD5DFAC3B9645FDE714129BE5FFF58 +:10A78000C4EB0AF587F31D6B287EBE569D78F05A00 +:10A790007ABFC6C9FAA30E29194FE28FB8CBC145BB +:10A7A000F0886AB5B268E312B5F5EECC247DBD4100 +:10A7B0004B8E3F86A64EC8D9C49F1A1812E279A8BC +:10A7C000CE30B349F71813BDF47C68836E0CEAE40D +:10A7D0000F27C729434DAAD0A745C2EE0C1FD71F8C +:10A7E00026FFAABF3B83FDCF03050E71EE1218258D +:10A7F0007E68D293E39AE1B1E27D2524673127E7B1 +:10A80000CBBF3326C66FDFBD7294E252CDF257B78D +:10A81000E7AF673F14FAC4B89BCB96A79C7F5C2335 +:10A82000BE88ED7402E1BFBFE0F601CA877E1075F5 +:10A83000AE2671196AD3997F6DBA6DEBBB93EB4469 +:10A840007D2A70DD74688BCAFC3F94F7C1913B4848 +:10A850004FE72D603C8F6C51F34309F270A2CDC5D8 +:10A86000F41ED922FC8B3C0784C6D2BC3FD126F40F +:10A87000D027EF013E4F16DA651D1FE94A38EE2258 +:10A880007C1400FC231D27F0E1437CFE460794E284 +:10A890001687FD5DECBFA5F2D9785B69525CEBAA27 +:10A8A0007624E1D1E90A8639CF7D33E8A4AF1A1ABC +:10A8B000B14FF17D970AC46FAEC0FD7CCE1CEC6732 +:10A8C00060DFDD188B28D87797845693DFFAE2CEC5 +:10A8D0008E01CAB3B8FC0E8DF8CDD57557B095C6AC +:10A8E000573A2103DFF7812E05689F1109485FEB76 +:10A8F000106A247F7D38E0D0286FD31C6DDF41EBD8 +:10A9000037FB1700D1796B9383D73B6BAA9CB4CAF2 +:10A91000234783F25F0B3D6C77DF77861FEEC0F134 +:10A92000EF23BD223073AE5D6DC54CA70C3D397E63 +:10A9300076438CEDF05A73BC8BD6595BAD52450310 +:10A940004ED49C3942FEFA4895CB70E1BE466A244B +:10A95000C6F7C755CE51BAE7F003755CA6757FF010 +:10A9600031F246513AF9BDB0DCA48E1FAA6E7113C4 +:10A970003FEC458A107E22530EB65FA9E3FE6CD1F0 +:10A980007F2FE285F01CC1FD96525C34897285D020 +:10A990007D53C1C7EFC076559BC2E3BE90EF885090 +:10A9A0005DA8BF496539E9F78606E8FE4F3FF23BEF +:10A9B000C743FE10F3F370BE9FE5D05E67B86673C1 +:10A9C00019F1CB1B5519ECB757B535DE4B7EFB7A29 +:10A9D000F9A37F798AE2A70295E9D9EF0CC65F2532 +:10A9E000BE6E12FEE2C9250FB0DCF575DD0E8437B0 +:10A9F0008884DFA1BA555F650DC3B7F30DC34B441F +:10AA00003EA9CF7F5F84F21BF16A915F30F38E72B3 +:10AA10003ECFCE2BD5597A6CB92BFC4A29CDBB47FA +:10AA2000117561B9204AFAC04579259AA724E7BB78 +:10AA3000D64D26C7C18B53E2E0D43C13B8C74B5A5E +:10AA4000D19E3ED986F1F17298CE2BD111588E2B22 +:10AA50005D1C2F8E548B3828E60CE76BE5E7CBF1B5 +:10AA60009B961F3CDEE3460E00F8518FC6FD2CF38B +:10AA700037BB7311D45B3D017E7EEBDA47A5C47909 +:10AA80004395ED6E9DF5C64480E0A6EA8B543E5892 +:10AA9000DBB6C0B20F26107D872681F1EBAD5915CC +:10AAA000273E3DFB7BE038F4130DE31E283E7F7EFE +:10AAB0009CF6E9A2FC97D8E749DAA78BF25F627FA0 +:10AAC0002FF7E8DCBEDA53C6ED827610797E5B1F85 +:10AAD0005C89FA00F1D65020FA24FF648773FCB732 +:10AAE0000789BF5C014523F97617C4E252823E18FC +:10AAF000F186DF25BBDC9FE761FE4BDDD7AFDA1CBB +:10AB0000D6B9C2B711DC21844B787F71E77F3DB4A1 +:10AB100094D6794B66BECAE9DABC83F50EEA850C99 +:10AB2000F637843E8CE57938EF30B2B354A2FB504F +:10AB30005B770B47774EB9C7754671DE09D4D7D41A +:10AB4000EF4739A7F3F4D77CF0195AE7E33F2EE03B +:10AB5000FB4D235BDE66B97F030390DCCB28F7B6A1 +:10AB60009CC5DE5AFC6D117F073B9E11E7673D389F +:10AB7000E21D8FD1F9FB7F22433ABC5D2A5DC19C67 +:10AB80009F1F32AA4C1E3FE74F53373445DDB07745 +:10AB9000EC7BDC8F34039462FFEB4ED34D7CF0F5FD +:10ABA000DD8E0BD60DBFBEFBC275C3D12F3BC0A53A +:10ABB000CDECE30A98E03C2B85F05407ECA357D882 +:10ABC00066B787AE6E673F52D415F51ACA39505F23 +:10ABD0005B40FEF3C026B38CDFFB73D8EE0794B165 +:10ABE00038D9F500D5CB75BABF10E1BA27E567E9CA +:10ABF000FE42EAF97B9D13EBF97C3884EA95A9F5CE +:10AC000049C9F37D51DF5F2AEA90767DB2429D38D3 +:10AC1000FA20E1E93637E3A1F7D9EBDFA1FA975D36 +:10AC2000C70F5875606D0768BBC539CC76F2FB9FBE +:10AC300017F550B81ECFB192169928DEB482EB9B5F +:10AC40001BE81C73ED7FBE75C3664BBF2173F33DDC +:10AC5000C89F59F8B4C7FD4DBB90C76B5591B786D7 +:10AC60002C95F5FCFA273C2093BFEC558F929C6CF9 +:10AC700083890D244FBD3EE1B7450F39D96FFB5491 +:10AC8000BBCE74CD534DBEBF90F7F719C66E0413FB +:10AC90003DAE65511EE92FADE6A7DA791FB1B616B4 +:10ACA000DAC780CCFAEEFDD20D7C8FA949CA66794D +:10ACB0005434B330515FEE6A4F7F1FA9B670B2852E +:10ACC000D7F73A80E2AD6886F1B24EF87E4161B8BE +:10ACD0004D20EE2BC1764D1AC073F67A4E337D6A45 +:10ACE0004B5D2B493FED6A17715BD49B3EAE7BA059 +:10ACF0005DC49F852DA12F101D6E82C97AD26F2849 +:10AD0000DA4684EFB588786D17E94B11EFEE72AC37 +:10AD100099C96BBDE40CEDA2F39ADF11FE842B20E0 +:10AD2000FC7A8CD4381F74ACC5FC0782DB4C7C5E8B +:10AD3000C98A0A8EAD3C7F1F519B2EED662FC13B09 +:10AD40006CE9E70ACDE4BA6B05388C5E7F425D5D45 +:10AD50009F5F5D5DD2BE2FEAE937083E86E723821A +:10AD60000FD78346F284FC7798D6B3EF97543CB75D +:10AD7000A388EB2E9758DF3ED5627E95E0BDB829BB +:10AD8000F8353AF7FB3B3B80E1CDF3BE466D6138C9 +:10AD900010443AF56708BFF9C93AA3339890FF7990 +:10ADA000D3A2D79B165D97233B8D8B7B6F6CC7AF70 +:10ADB000826A37D12B157E5F0F8C511D68B6F5D591 +:10ADC0007DF7B9294FDC5BB0DE4DF7D1A29EF5D9F6 +:10ADD000D4EF2F3003B47E5F4FE3B31F96121F09E9 +:10ADE000BE8F2C11F98818EAE748429EF4C576997F +:10ADF000F7555F0071CAA7BB3CC22F7261BCA8AFF8 +:10AE000020BFB99AED393E1FA3D4C16B963CC9A6A9 +:10AE10000126DD172C0089F0853A727A3E99BCFA3A +:10AE20008230D0BE66832337E07C8A470B34F643FA +:10AE30007EDDAE313E7DA663268E87F9E3EBD01C26 +:10AE4000F8CA99035FD37C6DC95D2A9ECE109E8897 +:10AE50004F7C0FF0B9E04FF52C672E547854CFFF9C +:10AE6000C8C68BC7849097C37F89F013A50B36E5BE +:10AE700033F8455F91F12B6B619EE72A3020B48255 +:10AE8000F0A149848FD4F3573CF77803E1ED956D39 +:10AE900042AFD62A96FE08E359903F6FB2D605CB53 +:10AEA0002E356508BBD30C3FF488BCB6E0D30A74DA +:10AEB000C7DD39E7EB57BB7D72967BD74F6ECE105F +:10AEC000FE903EC6FABDB751C0F77A851F7A74600E +:10AED00015FB0F37E6972E48D48F97BB4E985A171D +:10AEE0009CAB0E38C337A69BF6F93BEDBE085D95CB +:10AEF0009B8D3F1E24FE7192DCB8B93DEF7D613021 +:10AF000060905C2D31238074DBEB0B07887FFA8E19 +:10AF1000EF7C87EA24CAEBB241FEA6A20481C6DD1B +:10AF2000981766F9D8586002D5951EEC31BF9B087A +:10AF3000F7969650F966A45BA63666121C0FC423DA +:10AF4000648F6ECA35C3C13474A8DE2CF4C7B196C1 +:10AF5000E02A9A574BBA7315C0C39BCCD5D49FAF88 +:10AF6000BE3A5F9E1ADDA4F72F5D9E5ADC74BEFECA +:10AF70008220DFD3EAFFA14C1ED6F4B87E4B9EFAA6 +:10AF8000973C00A104B90A6E4ED13B7E4BEFF84DC1 +:10AF9000968BCD9B752B0F1C64F970923C9527E81E +:10AFA00019BFAD674C9647C56FCB93257F244F1EC5 +:10AFB000BA1F3C594F7E4A1F887B8CA9F2156E0937 +:10AFC0006DD94C762CEFB7AD45FACCFD4F5D17F23D +:10AFD000D45F60F1FB92A799FFCF22FFD365E15EBA +:10AFE0004F7112BFDBEDDA2919E2488A755312B7A7 +:10AFF0009F98CAE4B6762A835B732A97DBBA291F27 +:10B00000B7EBA7AEE0B67E2A9FDB8629E4FBD5C866 +:10B01000FF5345DCDE38B59CDB8D53CBB86D9C5AB5 +:10B02000CDE39AA656727BD3D40DDCDE3C5523D6F5 +:10B03000A19A504E5AFEA772D665E07F2342F5D101 +:10B04000BEE3F7BC43F8716A2AE751A2BE355CEF54 +:10B05000712A61E6FFA30542BF6FF408FAA4F2FF6C +:10B06000B196D0FE74FC0F4E716F4BA17B5B95ECDB +:10B07000E70C337F9FE7EFBEF447CA83A2FF7198C6 +:10B08000DF5FA2FD9FF62B1726FB95FD79C97E6534 +:10B09000DF12DBAF748D521D6CBBA4F33DB1532D99 +:10B0A000A17FE6F521B88DDE87DADC1AF95351DF8E +:10B0B0008D010FF6B7EE9581F27DE85F7C8BF80C81 +:10B0C000503F90DD98AFBC3EBCC9D2EFD6F80A38ED +:10B0D000ED085F847FF23E7DAD395FEE679B67CB05 +:10B0E000FD55509691CECEE638EB85DC6B42EEA353 +:10B0F00005C101CAB74453E4DEB6A3888724B93F2B +:10B1000065CBBD25C7397E71EF2387E41EF9EA2799 +:10B110009BC579D1DF4EB2A38A35DED928EA5BF52B +:10B120007EA1579546A12F142DD98E22DFBC4B74DA +:10B130004995F78822FCE3A6D27F9DB667645773D2 +:10B14000FC3E291B97D67E3F11A13CD6716529CBC9 +:10B1500077AA1C45B555CCE7C7957A4827FFF396E3 +:10B16000239F6D474CB623A9E36C79EA3BDEC47894 +:10B17000B1EDCA713CB799604F366A020F684F3E15 +:10B1800026FE4A95A7DA4233144CB34FB543F8A5CF +:10B19000AFAD0B0A7F11FD44F253A2CEF47E80DAEC +:10B1A00021FC9F9C46EBF7153A8473510F3636C647 +:10B1B000EBA98681F2AC7620BC75E6442FC960AF5E +:10B1C00067D84FFB47F97475FC15F2F9D126E117E2 +:10B1D00042772EFB2D763B17DFDBFE8ECDFFA9E3FA +:10B1E0009E2C323BD3E1E5F3165E8E0E3C9DC41FD0 +:10B1F00043CAD29B0C3DAD5E358DCBA257E7E757D6 +:10B200001C473BC77A7576BFE2BA8E347C309B5FB1 +:10B21000F1890E91CF45BF621DCDAB2D177EC5E7DD +:10B220003BE0F2FA0B35F731BE2ED55FD86CF1DF7B +:10B230006CFE425787AD37C2AC375C96DEB8587F9C +:10B24000218D7F703BF32F4CCA54FF43541B221FA8 +:10B2500022F408EA99BBE83DC6F1EC2F1CF5087E04 +:10B26000312D3D736D7B7007E175A85AF80B974B34 +:10B270000ED0EFBBAF236FFEF230DF71A58FAD1D97 +:10B2800098203F07BC31BA37DD4BF795287E7CCF3D +:10B290002BEE11009451DEFF8BF23506D9B991CC1B +:10B2A0002F7D83C6774714A07B83433D22FFF7C5DC +:10B2B000055947017967C8197E6AC2CFBF770D1E4D +:10B2C000C5F60F1985A39070EFF6B0256F2ED8C282 +:10B2D000F774B3B45B9EFD3037DDFEC4FD5CBABAD3 +:10B2E000728E7FD751A0F13D320B3F596A10227EFA +:10B2F000922307D747D0DB83EA84BC475F4D5727AB +:10B30000C7C1F922EF25837286F2EF03B49638178E +:10B310009FB37FB1FB513A970E218677D0EFE0BC07 +:10B320007BFF5A11EFF47BC26E2D8DDED8D7937C54 +:10B33000FF28B595973D16A33BC287038A4169CF85 +:10B34000C1B2CA26CA4F4635AE0083EA7304D3D5CC +:10B35000A7C72DF9D4C1607BAC7CB2253B9DBDB0A5 +:10B36000DB010BFF76DF5D326612DFA94566907F59 +:10B3700087E3F34B9184BCF11316FCBD9211AF45EA +:10B3800064EDF50AFDEFD66326FDDEB82FEF2EAE95 +:10B3900033BAF5089CA1E72531F839E9A77C77E7AE +:10B3A000689A7DBCD521E294BDCE10AFB7375FE17E +:10B3B000FAE3DEA2F4F9ACE73B441E49F5AD0F72A7 +:10B3C0005EDFA7709D3875DC53169FF4AB6640E3D3 +:10B3D000B8FA81323A577409708E72EC9D379FD853 +:10B3E0008DFDFD3D41CE7B0C51FE0385B5BFF05E6A +:10B3F000C6FBFE6B1C1A9D6383FC11DF47385C0D96 +:10B4000006E98FEC6A1C9710471E86D101BA0F77A8 +:10B41000782D70BED46B0493DEF723038E93FFA5C3 +:10B420004CB03E734237D7010EF855BEA73354795E +:10B430009AFD231DC6394F315429E865D793FC1670 +:10B440003FFAFD773527CAC1018B6E0F52DE9CEFA4 +:10B45000318D41A2FF75A0709CEDF38175E39D5481 +:10B4600017CCF2BB0D0A45F6D70481E474A8CA9143 +:10B47000F67ED450D569DE67EA7E9C277EC9FA2F16 +:10B480004B99E0FC4456D96FD9AE3C64ED63E35A66 +:10B49000E0CD66570B3D9BDD1606FA7D58DE5BF26C +:10B4A000A88EFDDD85BF8A38493E6E0358A4D37E41 +:10B4B0002778BF879B9F8EF3FEACFBBA203FCFF768 +:10B4C000712128E4D7BE77BDB04D4D8ADFB352EE6F +:10B4D0004565A6F441EEBAE07DB2EEF7EE3975327D +:10B4E00001DEA2CEE4FBD973CDFF43CF8E5327916B +:10B4F0005F0E575E58BE0E59758D584F35D3C9E64D +:10B50000339BEFB2E88839B3CF1FF28D75A6B3C372 +:10B510001D9D420E52F93195FF34D718DBF143EBF4 +:10B5200092E1DCD029E4F8060B4E4EA19E4FEFEDE0 +:10B530007B4C747FEAE934EB7EBA53E5F1337C6DE2 +:10B54000DBF9772ECDCE2F6B1176DEBF2A83EC3C54 +:10B55000E2F365BAC7F67B940F4890EB3E6FB29F5B +:10B5600069DBF9C73B457CF062DE5512D9E91CCF97 +:10B5700004FBBF59D5C97980543BAD3A431C37AA67 +:10B58000F9AAAD6FB89EF55AC7FB4F4410CEFEF82E +:10B590003EAE0F6522FF66484CA7483A3A4179F221 +:10B5A000BD9AF24E10BF63D3855EC85AAB70BD63BF +:10B5B000C8F15EF587D82AB130042DB883CCB7FB2B +:10B5C000C7F97E8EC5F773D1933E7F5A63FD2E85F2 +:10B5D000EA88F56F56A78B2BEC96EE4F25DF77BFE9 +:10B5E00038B9F8FB4EABBE9C0119422E9A1D7D6402 +:10B5F000EF9B1D7C2F85AEEF2A6BACD201D5F56990 +:10B6000067F8DE4FF77F24AB5EB474465EE0567198 +:10B61000AFE5EC0E714F867F47B8947EF739C1BF16 +:10B620000FBC926EB1CAEC07B3DC9C850207D583D0 +:10B6300023272469DA0FBA82AE341A0E9A570241D0 +:10B640006E53F77D1584F97919C4B8BD06C6B82DB7 +:10B6500087716E2B60925B9326E07E8D93A2AEB1D4 +:10B660000A0C999E574290DB3510E6B61A62DC7ED2 +:10B67000A5FE6F7F733B4EF9DA797811784D23DFA1 +:10B6800071043A7D7E1BCFAD9D3AF3C95CF4EEF3B5 +:10B690004DB01F5F5F3DCE7EA8D71364FE76FA05DE +:10B6A0007FDB709CB3E4836D3F49253F69751AFECB +:10B6B0009DC34F4AFD1DC9FF0229F7D0B3D04500F5 +:10B6C0000000000000000000000000180000000062 +:10B6D000000000000000004000000000000000002A +:10B6E0000000002800000000000000000000001022 +:10B6F000000000000000000000000020000000002A +:10B700000000000000000010000000000000000029 +:10B710000000000800000000000000000000000021 +:10B7200000000000000000000000003900000000E0 +:10B7300000000000000000380000000000000000D1 +:10B7400000000000000000000000000000000008F1 +:10B7500000000000000000000000000000000000E9 +:10B76000000000000000000C0000000000000000CD +:10B770000000000E000000000000000000000004B7 +:10B7800000000000000000000000001800000000A1 +:10B79000000000000000001C00000000000000008D +:10B7A0000000001C0000000000000000000000136A +:10B7B00000000000000000000000003A000000004F +:10B7C0000000000000000001000000000000000078 +:10B7D0000000000200000000000000000000000166 +:10B7E0000000000000000000000000100000000049 +:10B7F00000000000000000500000000000000000F9 +:10B800000000000000000000000000000000000335 +:10B810000000000000000000000000AB000000007D +:10B820000000000000000008000000000000000010 +:10B830000000C00000100000000000080000C00868 +:10B8400000100000000000020000C0000010000016 +:10B850000000001000009FB0000000000000000881 +:10B860000000C08000100000000000040000C0883C +:10B8700000100000000000020000C0800010000066 +:10B8800000000010000091200000000000000008EF +:10B8900000009340000100040000000100009348F4 +:10B8A00000000000000000020000935000000000B3 +:10B8B0000000000800009354000000000000000297 +:10B8C00000009418000000000000000800009358D9 +:10B8D000000800000000000800009AB000400000CE +:10B8E00000000040000093980008000000000008DD +:10B8F000000093D800080000000000080000942019 +:10B9000000C8000000000098000095B000980000FA +:10B9100000000028000095F00098000000000028BA +:10B920000000C480054000300000054000009D205C +:10B93000000800000000000100009D210008000038 +:10B9400000000001000020080010000000000010AE +:10B9500000002000000000000000000800009CD84B +:10B96000000800000000000200009D180000000018 +:10B9700000000001000000010000000000000000C5 +:10B9800000000009000000000000000000000002AC +:10B9900000000000000000000000CF2000000000B8 +:10B9A000000000200000CF46000000000000000161 +:10B9B0000000600000200000000000200000730074 +:10B9C000000800000000000800009FA00000000028 +:10B9D0000000000100009FA800000000000000011E +:10B9E00000009F60000000000000001000009F6346 +:10B9F000000000000000000100009F610000000046 +:10BA00000000000100009F6600000000000000012F +:10BA100000009F67000000000000000000009F6819 +:10BA2000000000000000000400009F6C0000000007 +:10BA300000000004000000520000000000000000B0 +:10BA400000000003000000000000000000000003F0 +:10BA500000000000000000000000000500000000E1 +:10BA600000000000000000020000000000000000D4 +:10BA700000060000000000000000002000009F7091 +:10BA8000000000000000000100009F900000000086 +:10BA9000000000080000005300000000000000004B +:10BAA00000009F98000000000000000200009F9C22 +:10BAB000000000000000000100009F9D0000000049 +:10BAC000000000010000000900000000000000006C +:10BAD0000000000100000000000000000000004421 +:10BAE0000000000000000000000000010000000055 +:10BAF00000000000000000500000000000000000F6 +:10BB0000000000890000000000000000000012C8D2 +:10BB10000080000000000080000000010000000024 +:10BB2000000000000000A000071000000000071047 +:10BB300000001AC800000000000000080000AEC0AD +:10BB400000080000000000080000AE4000080000EF +:10BB5000000000080000AE8000080000000000089F +:10BB6000000020080010000000000010000020006D +:10BB700000000000000000080000A01007100040B6 +:10BB80000000004000001BF8000800000000000159 +:10BB900000001BF9000800000000000100001AD09E +:10BBA000000000000000000100001AD800000000A2 +:10BBB0000000000200001ADA00000000000000028D +:10BBC0008000000000000000000000000000AF0046 +:10BBD000000000000000002000001B78002800008A +:10BBE000000000040000E000002000000000002031 +:10BBF0000000F300000800000000000800001AF038 +:10BC0000000000000000010800001B3700000000D9 +:10BC10000000000100001B0F0000000000000001F8 +:10BC200000001B70000000000000000400001B74F6 +:10BC300000000000000000040000005000000000B0 +:10BC400000000000000000030000000000000000F1 +:10BC500000000005000000000000000000000006D9 +:10BC600000000000000000000000000700000000CD +:10BC70000000000000001BC80000000000000001E0 +:10BC800000001BE800000000000000080000005158 +:10BC9000000000000000000000001BD000000000B9 +:10BCA0000000000400001BD400000000000000049D +:10BCB00000001BD8000000000000000400001BDC96 +:10BCC00000000000000000080000B00000180000A4 +:10BCD000000000180000C00000400000000000400C +:10BCE0000000C00000400002000000010000C00190 +:10BCF00000400002000000000000E2000020000000 +:10BD0000000000200000E204000200080020000201 +:10BD10008000000000000000000000000000E200C1 +:10BD200000080020000000040000F40000280000CB +:10BD3000000000280000F540001000000000001086 +:10BD40000000F5C000200000000000200000F5C049 +:10BD500000020020000000020000F30000200000AC +:10BD6000000000200000200800100000000000106B +:10BD70000000200000000000000000080000110882 +:10BD80000008000000000008000011680008000022 +:10BD900000000008000011A80008000000000008D2 +:10BDA00000001240000800000000000100001241E5 +:10BDB0000008000000000001000040000020000416 +:10BDC00000000010000059000030001800000010B2 +:10BDD0000000590800300018000000020000570061 +:10BDE00000080000000000010000570100080000EA +:10BDF00000000001000011E8000000000000000148 +:10BE0000000011F00000000000000001000011F827 +:10BE100000000000000000100000124400080000B4 +:10BE2000000000040000400000200000000000208E +:10BE30000000530000100000000000100000153842 +:10BE400000000000000000010000000300000000EE +:10BE500000000000000000000000000000000000E2 +:10BE600000000001000000000000000000000004CD +:10BE700000000000000000000000150800000000A5 +:10BE8000000000010000152800000000000000086C +:10BE900000000050000000000000000000008308C7 +:10BEA0000080000000000080000000010000000091 +:10BEB000000000000000200800100000000000103A +:10BEC00000002000000000000000000800008410B6 +:10BED0000008000000000008000084700008000056 +:10BEE0000000000800060000046000280000046054 +:10BEF00000008520000800000000000100008521EE +:10BF000000080000000000018000000000000000A8 +:10BF10000000000000008408000000000000000194 +:10BF2000000084F40008000000000002000084F615 +:10BF3000000800000000000200008504001000005E +:10BF400000000004000087600000000000000020E6 +:10BF500000006000002000000000002000007300CE +:10BF600000080000000000080000000300000000BE +:10BF700000000000000000050000000000000000BC +:10BF800000000006000000000000000000000007A4 +:10BF90000000000000000000000088080000000011 +:10BFA00000000001000088280000000000000008D8 +:10BFB0000000005000000000000000000000881099 +:10BFC00000000000000000040000881400000000D1 +:10BFD00000000004000088180000000000000004B9 +:10BFE0000000881C00000000000000080000300075 +:10BFF0000040000000000008000030080040000081 +:10C00000000000280000339001C00010000000086C +:10C010000000320000200000000000200000372057 +:10C02000000000000000000800001020062000387A +:10C03000000000080000A000000000000000200038 +:10C0400000003EA9000000000000000100003EC802 +:10C05000000000000000000280000000000000005E +:10C060000000000000006000002000000000000848 +:10C070000000400000080000000000010000400136 +:10C08000000800000000000100004040000800041B +:10C0900000000002000040600008000400000004EE +:10C0A0000000400000080000000000040000400400 +:10C0B00000080000000000040000404000000000F4 +:10C0C00000000008000040480000000000000008D8 +:10C0D0000000800000000000000000100000504040 +:10C0E00000010004000000010000500000000000FA +:10C0F00000000020000050080010000000000004B4 +:10C100000000500C0010000000000001000052C7A9 +:10C110000000000000000001000052C60000000006 +:10C120000000000100003000003000180000000492 +:10C130000000300400300018000000040000300847 +:10C1400000300018000000020000300A0030001823 +:10C15000000000020000300C003000180000000158 +:10C160000000300D00300018000000010000300E0B +:10C1700000300018000000010000301000300018EE +:10C18000000000040000301400300018000000041B +:10C19000000050000100008000080004000050046E +:10C1A00001000080000800040000000A00000000F8 +:10C1B0000000000000005068010000800000000145 +:10C1C0000000506901000080000000010000506C78 +:10C1D00001000080000000020000506E010000809D +:10C1E0000000000200005070010000800000000408 +:10C1F0000000507401000080000000040000506640 +:10C200000100008000000002000050640100008076 +:10C2100000000001000050600100008000000002EA +:10C220000000506201000080000000020000505039 +:10C230000100008000000004000050540100008054 +:10C2400000000004000050580100008000000004BD +:10C250000000505C01000080000000040000507CE1 +:10C2600001000080000000010000507D01000080FE +:10C270000000000100004018001000000000000451 +:10C2800000004090001000000000000400004098F2 +:10C290000010000000000004000041100000000039 +:10C2A0000000000200004112000000000000000237 +:10C2B00000004114000000000000000200004116D0 +:10C2C00000000000000000020000604000080000C4 +:10C2D00000000002000060420008000000000002B0 +:10C2E00000006044000800000000000400006080BE +:10C2F0000008000000000008000060C000400008C6 +:10C3000000000008000060000008000000000002BB +:10C31000000060020008000000000001000060044E +:10C320000008000000000002000063400008000058 +:10C330000000000800006380000800000000000406 +:10C34000000063840008000000000001000063C0DA +:10C350000008000000000002000063C400080000A4 +:10C36000000000020000640000080000000000045B +:10C3700000007000001000000000000400007004C5 +:10C380000010000000000004000070080010000011 +:10C3900000000004000090000008000000000002FF +:10C3A000000090020008000000000001000090045E +:10C3B000000800000000000200009040000800009B +:10C3C000000000020000904400080000000000028D +:10C3D000000090460008000000000002000096489F +:10C3E0000008000000000008000090800008000025 +:10C3F000000000020000908400080000000000021D +:10C40000000096880008000000000008000080403E +:10C41000000800000000000100008041000800004A +:10C420000000000100008042000800000000000140 +:10C4300000008043000800000000000100008000B0 +:10C440000008000000000002000080020008000058 +:10C45000000000010000800400080000000000024D +:10C46000000080C00008000000000002000080C240 +:10C470000008000000000002000080C40008000066 +:10C4800000000002000080800008000000000001A1 +:10C490000000808100080000000000010000808290 +:10C4A0000008000000000001000080830008000078 +:10C4B000000000010000808400080000000000016E +:10C4C0000000808500080000000000010000808658 +:10C4D00000080000000000010000600000080000EB +:10C4E00000000002000060020008000000000001DF +:10C4F000000060040008000000000002000060422C +:10C5000000C00018000000020000604000C00018D9 +:10C51000000000020000604C00C00018000000088D +:10C520000000604400C000180000000800006057D0 +:10C5300000C00018000000010000605400C0001896 +:10C54000000000020000605600C00018000000015A +:10C55000000066400008000000000008000066803F +:10C560000008000000000008000066C0000800008D +:10C57000000000080000DA4200180000000000027D +:10C580000000DE4000000000000000000000E000AD +:10C5900000000000000000040000D0C00000000007 +:10C5A000000000040000D0C40000000000000004EF +:10C5B0000000D0C800000000000000040000D0CC43 +:10C5C00000000000000000040000D0D000000000C7 +:10C5D000000000040000D0D40000000000000004AF +:10C5E0000000D0D800000000000000040000D0C00F +:10C5F00000000000000000200000DB000000000040 +:10C60000000000040000DB000000000000000068E3 +:10C610000000B94800000000000000000000D00049 +:10C6200000000000000000040000B0C00000000096 +:10C63000000000040000B0C400000000000000047E +:10C640000000B0C800000000000000040000B0C0FE +:10C6500000000000000000100000D6B00000000044 +:10C66000000000040000D6B4000000000000000438 +:10C670000000D6B800000000000000040000D6BC96 +:10C6800000000000000000040000D6B00000000020 +:10C69000000000100000D348000000000000000867 +:10C6A0000000D358000000000000008000000010CF +:10C6B00000000000000000000000D358000000004F +:10C6C0000000000800000000060209000000000051 +:00000001FF -- cgit v0.10.2 From 3b7f817e47bb66ae4d82ed73689a521af70a5410 Mon Sep 17 00:00:00 2001 From: Dmitry Kravkov Date: Thu, 31 Mar 2011 17:04:01 -0700 Subject: bnx2x: don't write dcb/llfc fields in STORM memory We could get hardware attention during DCB/FCoE traffic without this fix. Signed-off-by: Dmitry Kravkov Signed-off-by: Michael Chan Signed-off-by: David S. Miller diff --git a/drivers/net/bnx2x/bnx2x_cmn.h b/drivers/net/bnx2x/bnx2x_cmn.h index ef37b98..775fef0 100644 --- a/drivers/net/bnx2x/bnx2x_cmn.h +++ b/drivers/net/bnx2x/bnx2x_cmn.h @@ -1041,12 +1041,23 @@ static inline void storm_memset_cmng(struct bnx2x *bp, struct cmng_struct_per_port *cmng, u8 port) { - size_t size = sizeof(struct cmng_struct_per_port); + size_t size = + sizeof(struct rate_shaping_vars_per_port) + + sizeof(struct fairness_vars_per_port) + + sizeof(struct safc_struct_per_port) + + sizeof(struct pfc_struct_per_port); u32 addr = BAR_XSTRORM_INTMEM + XSTORM_CMNG_PER_PORT_VARS_OFFSET(port); __storm_memset_struct(bp, addr, size, (u32 *)cmng); + + addr += size + 4 /* SKIP DCB+LLFC */; + size = sizeof(struct cmng_struct_per_port) - + size /* written */ - 4 /*skipped*/; + + __storm_memset_struct(bp, addr, size, + (u32 *)(cmng->traffic_type_to_priority_cos)); } /* HW Lock for shared dual port PHYs */ -- cgit v0.10.2 From fab0dc89f0d98459c6ce7fa27422949ac15837fa Mon Sep 17 00:00:00 2001 From: Dmitry Kravkov Date: Thu, 31 Mar 2011 17:04:22 -0700 Subject: bnx2x, cnic: Disable iSCSI if DCBX negotiation is successful With current bnx2x firmware 6.2.9, iSCSI is not supported in DCB network, so we need to disable it. Add cnic command to disconnect iSCSI connections and prevent future connections when DCBX negotiation succeeds. Signed-off-by: Dmitry Kravkov Signed-off-by: Michael Chan Signed-off-by: David S. Miller diff --git a/drivers/net/bnx2x/bnx2x_dcb.c b/drivers/net/bnx2x/bnx2x_dcb.c index 9a24d79..1214907 100644 --- a/drivers/net/bnx2x/bnx2x_dcb.c +++ b/drivers/net/bnx2x/bnx2x_dcb.c @@ -571,6 +571,28 @@ void bnx2x_dcbx_set_params(struct bnx2x *bp, u32 state) { switch (state) { case BNX2X_DCBX_STATE_NEG_RECEIVED: +#ifdef BCM_CNIC + if (bp->state != BNX2X_STATE_OPENING_WAIT4_LOAD) { + struct cnic_ops *c_ops; + struct cnic_eth_dev *cp = &bp->cnic_eth_dev; + bp->flags |= NO_ISCSI_OOO_FLAG | NO_ISCSI_FLAG; + cp->drv_state |= CNIC_DRV_STATE_NO_ISCSI_OOO; + cp->drv_state |= CNIC_DRV_STATE_NO_ISCSI; + + rcu_read_lock(); + c_ops = rcu_dereference(bp->cnic_ops); + if (c_ops) { + bnx2x_cnic_notify(bp, CNIC_CTL_STOP_ISCSI_CMD); + rcu_read_unlock(); + return; + } + rcu_read_unlock(); + } + + /* fall through if no CNIC initialized */ + case BNX2X_DCBX_STATE_ISCSI_STOPPED: +#endif + { DP(NETIF_MSG_LINK, "BNX2X_DCBX_STATE_NEG_RECEIVED\n"); #ifdef BCM_DCBNL diff --git a/drivers/net/bnx2x/bnx2x_dcb.h b/drivers/net/bnx2x/bnx2x_dcb.h index 71b8eda..1e14775 100644 --- a/drivers/net/bnx2x/bnx2x_dcb.h +++ b/drivers/net/bnx2x/bnx2x_dcb.h @@ -183,9 +183,13 @@ void bnx2x_dcbx_set_state(struct bnx2x *bp, bool dcb_on, u32 dcbx_enabled); enum { BNX2X_DCBX_STATE_NEG_RECEIVED = 0x1, - BNX2X_DCBX_STATE_TX_PAUSED = 0x2, - BNX2X_DCBX_STATE_TX_RELEASED = 0x4 +#ifdef BCM_CNIC + BNX2X_DCBX_STATE_ISCSI_STOPPED, +#endif + BNX2X_DCBX_STATE_TX_PAUSED, + BNX2X_DCBX_STATE_TX_RELEASED }; + void bnx2x_dcbx_set_params(struct bnx2x *bp, u32 state); /* DCB netlink */ diff --git a/drivers/net/bnx2x/bnx2x_main.c b/drivers/net/bnx2x/bnx2x_main.c index 32e64cc8..f3cf889 100644 --- a/drivers/net/bnx2x/bnx2x_main.c +++ b/drivers/net/bnx2x/bnx2x_main.c @@ -10342,6 +10342,11 @@ static int bnx2x_drv_ctl(struct net_device *dev, struct drv_ctl_info *ctl) break; } + case DRV_CTL_ISCSI_STOPPED_CMD: { + bnx2x_dcbx_set_params(bp, BNX2X_DCBX_STATE_ISCSI_STOPPED); + break; + } + default: BNX2X_ERR("unknown command %x\n", ctl->cmd); rc = -EINVAL; diff --git a/drivers/net/cnic.c b/drivers/net/cnic.c index 8cca60e..5dfbff0 100644 --- a/drivers/net/cnic.c +++ b/drivers/net/cnic.c @@ -2966,31 +2966,36 @@ static int cnic_service_bnx2x(void *data, void *status_blk) return 0; } -static void cnic_ulp_stop(struct cnic_dev *dev) +static void cnic_ulp_stop_one(struct cnic_local *cp, int if_type) { - struct cnic_local *cp = dev->cnic_priv; - int if_type; - - cnic_send_nlmsg(cp, ISCSI_KEVENT_IF_DOWN, NULL); + struct cnic_ulp_ops *ulp_ops; - for (if_type = 0; if_type < MAX_CNIC_ULP_TYPE; if_type++) { - struct cnic_ulp_ops *ulp_ops; + if (if_type == CNIC_ULP_ISCSI) + cnic_send_nlmsg(cp, ISCSI_KEVENT_IF_DOWN, NULL); - mutex_lock(&cnic_lock); - ulp_ops = rcu_dereference_protected(cp->ulp_ops[if_type], - lockdep_is_held(&cnic_lock)); - if (!ulp_ops) { - mutex_unlock(&cnic_lock); - continue; - } - set_bit(ULP_F_CALL_PENDING, &cp->ulp_flags[if_type]); + mutex_lock(&cnic_lock); + ulp_ops = rcu_dereference_protected(cp->ulp_ops[if_type], + lockdep_is_held(&cnic_lock)); + if (!ulp_ops) { mutex_unlock(&cnic_lock); + return; + } + set_bit(ULP_F_CALL_PENDING, &cp->ulp_flags[if_type]); + mutex_unlock(&cnic_lock); - if (test_and_clear_bit(ULP_F_START, &cp->ulp_flags[if_type])) - ulp_ops->cnic_stop(cp->ulp_handle[if_type]); + if (test_and_clear_bit(ULP_F_START, &cp->ulp_flags[if_type])) + ulp_ops->cnic_stop(cp->ulp_handle[if_type]); - clear_bit(ULP_F_CALL_PENDING, &cp->ulp_flags[if_type]); - } + clear_bit(ULP_F_CALL_PENDING, &cp->ulp_flags[if_type]); +} + +static void cnic_ulp_stop(struct cnic_dev *dev) +{ + struct cnic_local *cp = dev->cnic_priv; + int if_type; + + for (if_type = 0; if_type < MAX_CNIC_ULP_TYPE; if_type++) + cnic_ulp_stop_one(cp, if_type); } static void cnic_ulp_start(struct cnic_dev *dev) @@ -3039,6 +3044,12 @@ static int cnic_ctl(void *data, struct cnic_ctl_info *info) cnic_put(dev); break; + case CNIC_CTL_STOP_ISCSI_CMD: { + struct cnic_local *cp = dev->cnic_priv; + set_bit(CNIC_LCL_FL_STOP_ISCSI, &cp->cnic_local_flags); + queue_delayed_work(cnic_wq, &cp->delete_task, 0); + break; + } case CNIC_CTL_COMPLETION_CMD: { u32 cid = BNX2X_SW_CID(info->data.comp.cid); u32 l5_cid; @@ -3562,8 +3573,12 @@ static void cnic_init_csk_state(struct cnic_sock *csk) static int cnic_cm_connect(struct cnic_sock *csk, struct cnic_sockaddr *saddr) { + struct cnic_local *cp = csk->dev->cnic_priv; int err = 0; + if (cp->ethdev->drv_state & CNIC_DRV_STATE_NO_ISCSI) + return -EOPNOTSUPP; + if (!cnic_in_use(csk)) return -EINVAL; @@ -3965,6 +3980,17 @@ static void cnic_delete_task(struct work_struct *work) cp = container_of(work, struct cnic_local, delete_task.work); dev = cp->dev; + if (test_and_clear_bit(CNIC_LCL_FL_STOP_ISCSI, &cp->cnic_local_flags)) { + struct drv_ctl_info info; + + rtnl_lock(); + cnic_ulp_stop_one(cp, CNIC_ULP_ISCSI); + rtnl_unlock(); + + info.cmd = DRV_CTL_ISCSI_STOPPED_CMD; + cp->ethdev->drv_ctl(dev->netdev, &info); + } + for (i = 0; i < cp->max_cid_space; i++) { struct cnic_context *ctx = &cp->ctx_tbl[i]; diff --git a/drivers/net/cnic.h b/drivers/net/cnic.h index 4456260..3367a6d3 100644 --- a/drivers/net/cnic.h +++ b/drivers/net/cnic.h @@ -226,6 +226,7 @@ struct cnic_local { #define CNIC_LCL_FL_KWQ_INIT 0x0 #define CNIC_LCL_FL_L2_WAIT 0x1 #define CNIC_LCL_FL_RINGS_INITED 0x2 +#define CNIC_LCL_FL_STOP_ISCSI 0x4 struct cnic_dev *dev; diff --git a/drivers/net/cnic_if.h b/drivers/net/cnic_if.h index e01b49e..fdd8e46 100644 --- a/drivers/net/cnic_if.h +++ b/drivers/net/cnic_if.h @@ -12,8 +12,8 @@ #ifndef CNIC_IF_H #define CNIC_IF_H -#define CNIC_MODULE_VERSION "2.2.13" -#define CNIC_MODULE_RELDATE "Jan 31, 2011" +#define CNIC_MODULE_VERSION "2.2.14" +#define CNIC_MODULE_RELDATE "Mar 30, 2011" #define CNIC_ULP_RDMA 0 #define CNIC_ULP_ISCSI 1 @@ -85,6 +85,7 @@ struct kcqe { #define CNIC_CTL_STOP_CMD 1 #define CNIC_CTL_START_CMD 2 #define CNIC_CTL_COMPLETION_CMD 3 +#define CNIC_CTL_STOP_ISCSI_CMD 4 #define DRV_CTL_IO_WR_CMD 0x101 #define DRV_CTL_IO_RD_CMD 0x102 @@ -94,6 +95,7 @@ struct kcqe { #define DRV_CTL_START_L2_CMD 0x106 #define DRV_CTL_STOP_L2_CMD 0x107 #define DRV_CTL_RET_L2_SPQ_CREDIT_CMD 0x10c +#define DRV_CTL_ISCSI_STOPPED_CMD 0x10d struct cnic_ctl_completion { u32 cid; -- cgit v0.10.2 From 9b12c75bf4d58dd85c987ee7b6a4356fdc7c1222 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Thu, 31 Mar 2011 18:03:35 -0700 Subject: net: Order ports in same order as addresses in flow objects. For consistency. Signed-off-by: David S. Miller diff --git a/include/net/flow.h b/include/net/flow.h index 37e77d6..c6d5fe5 100644 --- a/include/net/flow.h +++ b/include/net/flow.h @@ -26,8 +26,8 @@ struct flowi_common { union flowi_uli { struct { - __be16 sport; __be16 dport; + __be16 sport; } ports; struct { @@ -36,8 +36,8 @@ union flowi_uli { } icmpt; struct { - __le16 sport; __le16 dport; + __le16 sport; } dnports; __be32 spi; @@ -86,8 +86,8 @@ static inline void flowi4_init_output(struct flowi4 *fl4, int oif, fl4->flowi4_secid = 0; fl4->daddr = daddr; fl4->saddr = saddr; - fl4->fl4_sport = sport; fl4->fl4_dport = dport; + fl4->fl4_sport = sport; } -- cgit v0.10.2 From 052936080c8fb2f791103995b21bd4018c8df886 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Fri, 1 Apr 2011 11:15:12 +0200 Subject: x86-64, NUMA: Remove custom phys_to_nid() implementation phys_to_nid() maps physical address to NUMA node id. This is implemented by building perfect hash in compute_hash_shift() during initialization. However, with SPARSE memory model, the nid is encoded in page flags. The perfect hash implementation was for DISCONTIG memory model which got removed years ago by b263295dbf (x86: 64-bit, make sparsemem vmemmap the only memory model). So, the perfect hash ends up being used only during initialization when the core SPARSE code already provides perfectly acceptable generic early_pfn_to_nid() implementation. Drop phys_to_nid() and use the generic ealry_pfn_to_nid() instead. Signed-off-by: Tejun Heo Reviewed-by: Christoph Lameter Acked-by: Yinghai Lu Cc: Ingo Molnar Cc: "H. Peter Anvin" Cc: Thomas Gleixner diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig index cc6c53a..b034814 100644 --- a/arch/x86/Kconfig +++ b/arch/x86/Kconfig @@ -1703,10 +1703,6 @@ config ARCH_ENABLE_MEMORY_HOTREMOVE def_bool y depends on MEMORY_HOTPLUG -config HAVE_ARCH_EARLY_PFN_TO_NID - def_bool X86_64 - depends on NUMA - config USE_PERCPU_NUMA_NODE_ID def_bool y depends on NUMA diff --git a/arch/x86/include/asm/mmzone_64.h b/arch/x86/include/asm/mmzone_64.h index 288b96f..b3f88d7 100644 --- a/arch/x86/include/asm/mmzone_64.h +++ b/arch/x86/include/asm/mmzone_64.h @@ -4,36 +4,13 @@ #ifndef _ASM_X86_MMZONE_64_H #define _ASM_X86_MMZONE_64_H - #ifdef CONFIG_NUMA #include - #include -/* Simple perfect hash to map physical addresses to node numbers */ -struct memnode { - int shift; - unsigned int mapsize; - s16 *map; - s16 embedded_map[64 - 8]; -} ____cacheline_aligned; /* total size = 128 bytes */ -extern struct memnode memnode; -#define memnode_shift memnode.shift -#define memnodemap memnode.map -#define memnodemapsize memnode.mapsize - extern struct pglist_data *node_data[]; -static inline __attribute__((pure)) int phys_to_nid(unsigned long addr) -{ - unsigned nid; - VIRTUAL_BUG_ON(!memnodemap); - nid = memnodemap[addr >> memnode_shift]; - VIRTUAL_BUG_ON(nid >= MAX_NUMNODES || !node_data[nid]); - return nid; -} - #define NODE_DATA(nid) (node_data[nid]) #define node_start_pfn(nid) (NODE_DATA(nid)->node_start_pfn) diff --git a/arch/x86/mm/numa_64.c b/arch/x86/mm/numa_64.c index e8c00cc..3951ee6 100644 --- a/arch/x86/mm/numa_64.c +++ b/arch/x86/mm/numa_64.c @@ -28,125 +28,10 @@ EXPORT_SYMBOL(node_data); nodemask_t numa_nodes_parsed __initdata; -struct memnode memnode; - -static unsigned long __initdata nodemap_addr; -static unsigned long __initdata nodemap_size; - static struct numa_meminfo numa_meminfo __initdata; - static int numa_distance_cnt; static u8 *numa_distance; -/* - * Given a shift value, try to populate memnodemap[] - * Returns : - * 1 if OK - * 0 if memnodmap[] too small (of shift too small) - * -1 if node overlap or lost ram (shift too big) - */ -static int __init populate_memnodemap(const struct numa_meminfo *mi, int shift) -{ - unsigned long addr, end; - int i, res = -1; - - memset(memnodemap, 0xff, sizeof(s16)*memnodemapsize); - for (i = 0; i < mi->nr_blks; i++) { - addr = mi->blk[i].start; - end = mi->blk[i].end; - if (addr >= end) - continue; - if ((end >> shift) >= memnodemapsize) - return 0; - do { - if (memnodemap[addr >> shift] != NUMA_NO_NODE) - return -1; - memnodemap[addr >> shift] = mi->blk[i].nid; - addr += (1UL << shift); - } while (addr < end); - res = 1; - } - return res; -} - -static int __init allocate_cachealigned_memnodemap(void) -{ - unsigned long addr; - - memnodemap = memnode.embedded_map; - if (memnodemapsize <= ARRAY_SIZE(memnode.embedded_map)) - return 0; - - addr = 0x8000; - nodemap_size = roundup(sizeof(s16) * memnodemapsize, L1_CACHE_BYTES); - nodemap_addr = memblock_find_in_range(addr, get_max_mapped(), - nodemap_size, L1_CACHE_BYTES); - if (nodemap_addr == MEMBLOCK_ERROR) { - printk(KERN_ERR - "NUMA: Unable to allocate Memory to Node hash map\n"); - nodemap_addr = nodemap_size = 0; - return -1; - } - memnodemap = phys_to_virt(nodemap_addr); - memblock_x86_reserve_range(nodemap_addr, nodemap_addr + nodemap_size, "MEMNODEMAP"); - - printk(KERN_DEBUG "NUMA: Allocated memnodemap from %lx - %lx\n", - nodemap_addr, nodemap_addr + nodemap_size); - return 0; -} - -/* - * The LSB of all start and end addresses in the node map is the value of the - * maximum possible shift. - */ -static int __init extract_lsb_from_nodes(const struct numa_meminfo *mi) -{ - int i, nodes_used = 0; - unsigned long start, end; - unsigned long bitfield = 0, memtop = 0; - - for (i = 0; i < mi->nr_blks; i++) { - start = mi->blk[i].start; - end = mi->blk[i].end; - if (start >= end) - continue; - bitfield |= start; - nodes_used++; - if (end > memtop) - memtop = end; - } - if (nodes_used <= 1) - i = 63; - else - i = find_first_bit(&bitfield, sizeof(unsigned long)*8); - memnodemapsize = (memtop >> i)+1; - return i; -} - -static int __init compute_hash_shift(const struct numa_meminfo *mi) -{ - int shift; - - shift = extract_lsb_from_nodes(mi); - if (allocate_cachealigned_memnodemap()) - return -1; - printk(KERN_DEBUG "NUMA: Using %d for the hash shift.\n", - shift); - - if (populate_memnodemap(mi, shift) != 1) { - printk(KERN_INFO "Your memory is not aligned you need to " - "rebuild your kernel with a bigger NODEMAPSIZE " - "shift=%d\n", shift); - return -1; - } - return shift; -} - -int __meminit __early_pfn_to_nid(unsigned long pfn) -{ - return phys_to_nid(pfn << PAGE_SHIFT); -} - static void * __init early_node_mem(int nodeid, unsigned long start, unsigned long end, unsigned long size, unsigned long align) @@ -270,7 +155,7 @@ setup_node_bootmem(int nodeid, unsigned long start, unsigned long end) memblock_x86_reserve_range(nodedata_phys, nodedata_phys + pgdat_size, "NODE_DATA"); printk(KERN_INFO " NODE_DATA [%016lx - %016lx]\n", nodedata_phys, nodedata_phys + pgdat_size - 1); - nid = phys_to_nid(nodedata_phys); + nid = early_pfn_to_nid(nodedata_phys >> PAGE_SHIFT); if (nid != nodeid) printk(KERN_INFO " NODE_DATA(%d) on node %d\n", nodeid, nid); @@ -527,12 +412,6 @@ static int __init numa_register_memblks(struct numa_meminfo *mi) if (WARN_ON(nodes_empty(node_possible_map))) return -EINVAL; - memnode_shift = compute_hash_shift(mi); - if (memnode_shift < 0) { - printk(KERN_ERR "NUMA: No NUMA node hash function found. Contact maintainer\n"); - return -EINVAL; - } - for (i = 0; i < mi->nr_blks; i++) memblock_x86_register_active_regions(mi->blk[i].nid, mi->blk[i].start >> PAGE_SHIFT, -- cgit v0.10.2 From 3b16651f806d35b5c404f2525fbce76afa3c9297 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Fri, 1 Apr 2011 11:15:12 +0200 Subject: x86: Clean up memory model related configs in arch/x86/Kconfig * Remove bogus dependency on ARCH_SELECT_MEMORY_MODEL from ARCH_FLATMEM_ENABLE. ENABLE configs don't interfere with SELECT_MEMORY_MODEL. They just need to indicate whether the specific memory model is supported. * Relocate HAVE_ARCH_ALLOC_REMAP, ARCH_PROC_KCORE_TEXT and ARCH_SPARSEMEM_DEFAULT so that memory model related configs are together in consistent order. Signed-off-by: Tejun Heo Reviewed-by: Christoph Lameter Cc: Ingo Molnar Cc: Yinghai Lu Cc: "H. Peter Anvin" Cc: Thomas Gleixner diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig index b034814..8db4fbf 100644 --- a/arch/x86/Kconfig +++ b/arch/x86/Kconfig @@ -1223,6 +1223,10 @@ config HAVE_ARCH_BOOTMEM def_bool y depends on X86_32 && NUMA +config HAVE_ARCH_ALLOC_REMAP + def_bool y + depends on X86_32 && NUMA + config ARCH_HAVE_MEMORY_PRESENT def_bool y depends on X86_32 && DISCONTIGMEM @@ -1231,13 +1235,9 @@ config NEED_NODE_MEMMAP_SIZE def_bool y depends on X86_32 && (DISCONTIGMEM || SPARSEMEM) -config HAVE_ARCH_ALLOC_REMAP - def_bool y - depends on X86_32 && NUMA - config ARCH_FLATMEM_ENABLE def_bool y - depends on X86_32 && ARCH_SELECT_MEMORY_MODEL && !NUMA + depends on X86_32 && !NUMA config ARCH_DISCONTIGMEM_ENABLE def_bool y @@ -1247,20 +1247,16 @@ config ARCH_DISCONTIGMEM_DEFAULT def_bool y depends on NUMA && X86_32 -config ARCH_PROC_KCORE_TEXT - def_bool y - depends on X86_64 && PROC_KCORE - -config ARCH_SPARSEMEM_DEFAULT - def_bool y - depends on X86_64 - config ARCH_SPARSEMEM_ENABLE def_bool y depends on X86_64 || NUMA || (EXPERIMENTAL && X86_32) || X86_32_NON_STANDARD select SPARSEMEM_STATIC if X86_32 select SPARSEMEM_VMEMMAP_ENABLE if X86_64 +config ARCH_SPARSEMEM_DEFAULT + def_bool y + depends on X86_64 + config ARCH_SELECT_MEMORY_MODEL def_bool y depends on ARCH_SPARSEMEM_ENABLE @@ -1269,6 +1265,10 @@ config ARCH_MEMORY_PROBE def_bool X86_64 depends on MEMORY_HOTPLUG +config ARCH_PROC_KCORE_TEXT + def_bool y + depends on X86_64 && PROC_KCORE + config ILLEGAL_POINTER_VALUE hex default 0 if X86_32 -- cgit v0.10.2 From 4d9fd0b72cd80624f9f5c6a4c69c503615bec370 Mon Sep 17 00:00:00 2001 From: Florian Tobias Schandinat Date: Sat, 26 Mar 2011 03:17:42 +0000 Subject: viafb: delete clock and PLL initialization We do this also in the real program code so there is no reason to do it here too (and here it's hardly readable). Signed-off-by: Florian Tobias Schandinat diff --git a/drivers/video/via/viamode.c b/drivers/video/via/viamode.c index 8c5bc41..e550063 100644 --- a/drivers/video/via/viamode.c +++ b/drivers/video/via/viamode.c @@ -41,7 +41,6 @@ struct io_reg CN400_ModeXregs[] = { {VIASR, SR10, 0xFF, 0x01}, {VIACR, CR69, 0xFF, 0x00}, {VIACR, CR6A, 0xFF, 0x40}, {VIACR, CR6B, 0xFF, 0x00}, -{VIACR, CR6C, 0xFF, 0x00}, {VIACR, CR88, 0xFF, 0x40}, /* LCD Panel Type */ {VIACR, CR89, 0xFF, 0x00}, /* LCD Timing Control 0 */ {VIACR, CR8A, 0xFF, 0x88}, /* LCD Timing Control 1 */ @@ -87,7 +86,6 @@ struct io_reg CN700_ModeXregs[] = { {VIASR, SR10, 0xFF, 0x01}, {VIACR, CR69, 0xFF, 0x00}, {VIACR, CR6A, 0xFD, 0x40}, {VIACR, CR6B, 0xFF, 0x00}, -{VIACR, CR6C, 0xFF, 0x00}, {VIACR, CR77, 0xFF, 0x00}, /* LCD scaling Factor */ {VIACR, CR78, 0xFF, 0x00}, /* LCD scaling Factor */ {VIACR, CR79, 0xFF, 0x00}, /* LCD scaling Factor */ @@ -161,7 +159,7 @@ struct io_reg CX700_ModeXregs[] = { {VIASR, SR10, 0xFF, 0x01}, {VIASR, SR1B, 0xFF, 0xF0}, {VIASR, SR1E, 0xFF, 0x01}, {VIASR, SR2A, 0xFF, 0x00}, -{VIASR, SR2D, 0xFF, 0xFF}, /* VCK and LCK PLL power on. */ +{VIASR, SR2D, 0xC0, 0xC0}, /* delayed E3_ECK */ {VIACR, CR0A, 0xFF, 0x1E}, /* Cursor Start */ {VIACR, CR0B, 0xFF, 0x00}, /* Cursor End */ {VIACR, CR0E, 0xFF, 0x00}, /* Cursor Location High */ @@ -174,7 +172,6 @@ struct io_reg CX700_ModeXregs[] = { {VIASR, SR10, 0xFF, 0x01}, {VIACR, CR69, 0xFF, 0x00}, {VIACR, CR6A, 0xFF, 0x40}, {VIACR, CR6B, 0xFF, 0x00}, -{VIACR, CR6C, 0xFF, 0x00}, {VIACR, CR88, 0xFF, 0x40}, /* LCD Panel Type */ {VIACR, CR89, 0xFF, 0x00}, /* LCD Timing Control 0 */ {VIACR, CR8A, 0xFF, 0x88}, /* LCD Timing Control 1 */ @@ -204,7 +201,7 @@ struct io_reg VX855_ModeXregs[] = { {VIASR, SR2A, 0xF0, 0x00}, {VIASR, SR58, 0xFF, 0x00}, {VIASR, SR59, 0xFF, 0x00}, -{VIASR, SR2D, 0xFF, 0xFF}, /* VCK and LCK PLL power on. */ +{VIASR, SR2D, 0xC0, 0xC0}, /* delayed E3_ECK */ {VIACR, CR09, 0xFF, 0x00}, /* Initial CR09=0*/ {VIACR, CR11, 0x8F, 0x00}, /* IGA1 initial Vertical end */ {VIACR, CR17, 0x7F, 0x00}, /* IGA1 CRT Mode control init */ @@ -219,7 +216,6 @@ struct io_reg VX855_ModeXregs[] = { {VIACR, CR69, 0xFF, 0x00}, {VIACR, CR6A, 0xFD, 0x60}, {VIACR, CR6B, 0xFF, 0x00}, -{VIACR, CR6C, 0xFF, 0x00}, {VIACR, CR88, 0xFF, 0x40}, /* LCD Panel Type */ {VIACR, CR89, 0xFF, 0x00}, /* LCD Timing Control 0 */ {VIACR, CR8A, 0xFF, 0x88}, /* LCD Timing Control 1 */ -- cgit v0.10.2 From ab3cf6d0f3d2daeef2101a2a97b6c0beee6b70cf Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Fri, 1 Apr 2011 22:20:06 +0100 Subject: sfc: Move test of rx_checksum_enabled from nic.c to rx.c This is preparation for using the generic netdev features interface, and should have no effect in itself. Signed-off-by: Ben Hutchings diff --git a/drivers/net/sfc/nic.c b/drivers/net/sfc/nic.c index e839661..2594f39 100644 --- a/drivers/net/sfc/nic.c +++ b/drivers/net/sfc/nic.c @@ -850,7 +850,6 @@ efx_handle_rx_event(struct efx_channel *channel, const efx_qword_t *event) unsigned expected_ptr; bool rx_ev_pkt_ok, discard = false, checksummed; struct efx_rx_queue *rx_queue; - struct efx_nic *efx = channel->efx; /* Basic packet information */ rx_ev_byte_cnt = EFX_QWORD_FIELD(*event, FSF_AZ_RX_EV_BYTE_CNT); @@ -873,9 +872,8 @@ efx_handle_rx_event(struct efx_channel *channel, const efx_qword_t *event) * UDP/IP, then we can rely on the hardware checksum. */ checksummed = - likely(efx->rx_checksum_enabled) && - (rx_ev_hdr_type == FSE_CZ_RX_EV_HDR_TYPE_IPV4V6_TCP || - rx_ev_hdr_type == FSE_CZ_RX_EV_HDR_TYPE_IPV4V6_UDP); + rx_ev_hdr_type == FSE_CZ_RX_EV_HDR_TYPE_IPV4V6_TCP || + rx_ev_hdr_type == FSE_CZ_RX_EV_HDR_TYPE_IPV4V6_UDP; } else { efx_handle_rx_not_ok(rx_queue, event, &rx_ev_pkt_ok, &discard); checksummed = false; diff --git a/drivers/net/sfc/rx.c b/drivers/net/sfc/rx.c index c0fdb59..fb402c5 100644 --- a/drivers/net/sfc/rx.c +++ b/drivers/net/sfc/rx.c @@ -605,6 +605,9 @@ void __efx_rx_packet(struct efx_channel *channel, skb_record_rx_queue(skb, channel->channel); } + if (unlikely(!efx->rx_checksum_enabled)) + checksummed = false; + if (likely(checksummed || rx_buf->is_page)) { efx_rx_packet_gro(channel, rx_buf, eh, checksummed); return; -- cgit v0.10.2 From 98e778c9aa4f4f75550fa3a31358304e4ce67b96 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Miros=C5=82aw?= Date: Thu, 31 Mar 2011 01:01:35 +0000 Subject: virtio_net: convert to hw_features MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: MichaÅ‚ MirosÅ‚aw Signed-off-by: David S. Miller diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c index 82dba5a..0cb0b06 100644 --- a/drivers/net/virtio_net.c +++ b/drivers/net/virtio_net.c @@ -710,17 +710,6 @@ static int virtnet_close(struct net_device *dev) return 0; } -static int virtnet_set_tx_csum(struct net_device *dev, u32 data) -{ - struct virtnet_info *vi = netdev_priv(dev); - struct virtio_device *vdev = vi->vdev; - - if (data && !virtio_has_feature(vdev, VIRTIO_NET_F_CSUM)) - return -ENOSYS; - - return ethtool_op_set_tx_hw_csum(dev, data); -} - static void virtnet_set_rx_mode(struct net_device *dev) { struct virtnet_info *vi = netdev_priv(dev); @@ -822,10 +811,6 @@ static void virtnet_vlan_rx_kill_vid(struct net_device *dev, u16 vid) } static const struct ethtool_ops virtnet_ethtool_ops = { - .set_tx_csum = virtnet_set_tx_csum, - .set_sg = ethtool_op_set_sg, - .set_tso = ethtool_op_set_tso, - .set_ufo = ethtool_op_set_ufo, .get_link = ethtool_op_get_link, }; @@ -912,22 +897,29 @@ static int virtnet_probe(struct virtio_device *vdev) SET_NETDEV_DEV(dev, &vdev->dev); /* Do we support "hardware" checksums? */ - if (csum && virtio_has_feature(vdev, VIRTIO_NET_F_CSUM)) { + if (virtio_has_feature(vdev, VIRTIO_NET_F_CSUM)) { /* This opens up the world of extra features. */ - dev->features |= NETIF_F_HW_CSUM|NETIF_F_SG|NETIF_F_FRAGLIST; - if (gso && virtio_has_feature(vdev, VIRTIO_NET_F_GSO)) { - dev->features |= NETIF_F_TSO | NETIF_F_UFO + dev->hw_features |= NETIF_F_HW_CSUM|NETIF_F_SG|NETIF_F_FRAGLIST; + if (csum) + dev->features |= NETIF_F_HW_CSUM|NETIF_F_SG|NETIF_F_FRAGLIST; + + if (virtio_has_feature(vdev, VIRTIO_NET_F_GSO)) { + dev->hw_features |= NETIF_F_TSO | NETIF_F_UFO | NETIF_F_TSO_ECN | NETIF_F_TSO6; } /* Individual feature bits: what can host handle? */ - if (gso && virtio_has_feature(vdev, VIRTIO_NET_F_HOST_TSO4)) - dev->features |= NETIF_F_TSO; - if (gso && virtio_has_feature(vdev, VIRTIO_NET_F_HOST_TSO6)) - dev->features |= NETIF_F_TSO6; - if (gso && virtio_has_feature(vdev, VIRTIO_NET_F_HOST_ECN)) - dev->features |= NETIF_F_TSO_ECN; - if (gso && virtio_has_feature(vdev, VIRTIO_NET_F_HOST_UFO)) - dev->features |= NETIF_F_UFO; + if (virtio_has_feature(vdev, VIRTIO_NET_F_HOST_TSO4)) + dev->hw_features |= NETIF_F_TSO; + if (virtio_has_feature(vdev, VIRTIO_NET_F_HOST_TSO6)) + dev->hw_features |= NETIF_F_TSO6; + if (virtio_has_feature(vdev, VIRTIO_NET_F_HOST_ECN)) + dev->hw_features |= NETIF_F_TSO_ECN; + if (virtio_has_feature(vdev, VIRTIO_NET_F_HOST_UFO)) + dev->hw_features |= NETIF_F_UFO; + + if (gso) + dev->features |= dev->hw_features & (NETIF_F_ALL_TSO|NETIF_F_UFO); + /* (!csum && gso) case will be fixed by register_netdev() */ } /* Configuration may specify what MAC to use. Otherwise random. */ -- cgit v0.10.2 From 78e47fe4194ca7fac2cc29d25f1327db86922724 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Miros=C5=82aw?= Date: Fri, 1 Apr 2011 20:56:23 -0700 Subject: net: convert SMSC USB net drivers to hw_features MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit There's a race (not fixed here) in smsc75xx in setting RFE_CTL that's not properly handled via rfe_ctl_lock. Spinlock is not a good tool here, as this has to wait for URB completion (or maybe just submission) after issuing register write request. Otherwise, the rfe_ctl might be changed just after spin_unlock() and device left programmed with other value. smsc95xx has increased hard_header_len for the case of TX checksumming. smsc75xx is fixed to advertise IP+IPV6_CSUM instead of HW_CSUM as it does not use csum_start/csum_offset. Signed-off-by: MichaÅ‚ MirosÅ‚aw Signed-off-by: David S. Miller diff --git a/drivers/net/usb/smsc75xx.c b/drivers/net/usb/smsc75xx.c index 753ee6e..860a20c 100644 --- a/drivers/net/usb/smsc75xx.c +++ b/drivers/net/usb/smsc75xx.c @@ -65,7 +65,6 @@ struct smsc75xx_priv { struct usbnet *dev; u32 rfe_ctl; u32 multicast_hash_table[DP_SEL_VHF_HASH_LEN]; - bool use_rx_csum; struct mutex dataport_mutex; spinlock_t rfe_ctl_lock; struct work_struct set_multicast; @@ -548,28 +547,6 @@ static void smsc75xx_status(struct usbnet *dev, struct urb *urb) "unexpected interrupt, intdata=0x%08X", intdata); } -/* Enable or disable Rx checksum offload engine */ -static int smsc75xx_set_rx_csum_offload(struct usbnet *dev) -{ - struct smsc75xx_priv *pdata = (struct smsc75xx_priv *)(dev->data[0]); - unsigned long flags; - int ret; - - spin_lock_irqsave(&pdata->rfe_ctl_lock, flags); - - if (pdata->use_rx_csum) - pdata->rfe_ctl |= RFE_CTL_TCPUDP_CKM | RFE_CTL_IP_CKM; - else - pdata->rfe_ctl &= ~(RFE_CTL_TCPUDP_CKM | RFE_CTL_IP_CKM); - - spin_unlock_irqrestore(&pdata->rfe_ctl_lock, flags); - - ret = smsc75xx_write_reg(dev, RFE_CTL, pdata->rfe_ctl); - check_warn_return(ret, "Error writing RFE_CTL"); - - return 0; -} - static int smsc75xx_ethtool_get_eeprom_len(struct net_device *net) { return MAX_EEPROM_SIZE; @@ -599,34 +576,6 @@ static int smsc75xx_ethtool_set_eeprom(struct net_device *netdev, return smsc75xx_write_eeprom(dev, ee->offset, ee->len, data); } -static u32 smsc75xx_ethtool_get_rx_csum(struct net_device *netdev) -{ - struct usbnet *dev = netdev_priv(netdev); - struct smsc75xx_priv *pdata = (struct smsc75xx_priv *)(dev->data[0]); - - return pdata->use_rx_csum; -} - -static int smsc75xx_ethtool_set_rx_csum(struct net_device *netdev, u32 val) -{ - struct usbnet *dev = netdev_priv(netdev); - struct smsc75xx_priv *pdata = (struct smsc75xx_priv *)(dev->data[0]); - - pdata->use_rx_csum = !!val; - - return smsc75xx_set_rx_csum_offload(dev); -} - -static int smsc75xx_ethtool_set_tso(struct net_device *netdev, u32 data) -{ - if (data) - netdev->features |= NETIF_F_TSO | NETIF_F_TSO6; - else - netdev->features &= ~(NETIF_F_TSO | NETIF_F_TSO6); - - return 0; -} - static const struct ethtool_ops smsc75xx_ethtool_ops = { .get_link = usbnet_get_link, .nway_reset = usbnet_nway_reset, @@ -638,12 +587,6 @@ static const struct ethtool_ops smsc75xx_ethtool_ops = { .get_eeprom_len = smsc75xx_ethtool_get_eeprom_len, .get_eeprom = smsc75xx_ethtool_get_eeprom, .set_eeprom = smsc75xx_ethtool_set_eeprom, - .get_tx_csum = ethtool_op_get_tx_csum, - .set_tx_csum = ethtool_op_set_tx_hw_csum, - .get_rx_csum = smsc75xx_ethtool_get_rx_csum, - .set_rx_csum = smsc75xx_ethtool_set_rx_csum, - .get_tso = ethtool_op_get_tso, - .set_tso = smsc75xx_ethtool_set_tso, }; static int smsc75xx_ioctl(struct net_device *netdev, struct ifreq *rq, int cmd) @@ -782,6 +725,30 @@ static int smsc75xx_change_mtu(struct net_device *netdev, int new_mtu) return usbnet_change_mtu(netdev, new_mtu); } +/* Enable or disable Rx checksum offload engine */ +static int smsc75xx_set_features(struct net_device *netdev, u32 features) +{ + struct usbnet *dev = netdev_priv(netdev); + struct smsc75xx_priv *pdata = (struct smsc75xx_priv *)(dev->data[0]); + unsigned long flags; + int ret; + + spin_lock_irqsave(&pdata->rfe_ctl_lock, flags); + + if (features & NETIF_F_RXCSUM) + pdata->rfe_ctl |= RFE_CTL_TCPUDP_CKM | RFE_CTL_IP_CKM; + else + pdata->rfe_ctl &= ~(RFE_CTL_TCPUDP_CKM | RFE_CTL_IP_CKM); + + spin_unlock_irqrestore(&pdata->rfe_ctl_lock, flags); + /* it's racing here! */ + + ret = smsc75xx_write_reg(dev, RFE_CTL, pdata->rfe_ctl); + check_warn_return(ret, "Error writing RFE_CTL"); + + return 0; +} + static int smsc75xx_reset(struct usbnet *dev) { struct smsc75xx_priv *pdata = (struct smsc75xx_priv *)(dev->data[0]); @@ -960,11 +927,7 @@ static int smsc75xx_reset(struct usbnet *dev) netif_dbg(dev, ifup, dev->net, "RFE_CTL set to 0x%08x", pdata->rfe_ctl); /* Enable or disable checksum offload engines */ - ethtool_op_set_tx_hw_csum(dev->net, DEFAULT_TX_CSUM_ENABLE); - ret = smsc75xx_set_rx_csum_offload(dev); - check_warn_return(ret, "Failed to set rx csum offload: %d", ret); - - smsc75xx_ethtool_set_tso(dev->net, DEFAULT_TSO_ENABLE); + smsc75xx_set_features(dev->net, dev->net->features); smsc75xx_set_multicast(dev->net); @@ -1037,6 +1000,7 @@ static const struct net_device_ops smsc75xx_netdev_ops = { .ndo_validate_addr = eth_validate_addr, .ndo_do_ioctl = smsc75xx_ioctl, .ndo_set_multicast_list = smsc75xx_set_multicast, + .ndo_set_features = smsc75xx_set_features, }; static int smsc75xx_bind(struct usbnet *dev, struct usb_interface *intf) @@ -1065,10 +1029,17 @@ static int smsc75xx_bind(struct usbnet *dev, struct usb_interface *intf) INIT_WORK(&pdata->set_multicast, smsc75xx_deferred_multicast_write); - pdata->use_rx_csum = DEFAULT_RX_CSUM_ENABLE; + if (DEFAULT_TX_CSUM_ENABLE) { + dev->net->features |= NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM; + if (DEFAULT_TSO_ENABLE) + dev->net->features |= NETIF_F_SG | + NETIF_F_TSO | NETIF_F_TSO6; + } + if (DEFAULT_RX_CSUM_ENABLE) + dev->net->features |= NETIF_F_RXCSUM; - /* We have to advertise SG otherwise TSO cannot be enabled */ - dev->net->features |= NETIF_F_SG; + dev->net->hw_features = NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM | + NETIF_F_SG | NETIF_F_TSO | NETIF_F_TSO6 | NETIF_F_RXCSUM; /* Init all registers */ ret = smsc75xx_reset(dev); @@ -1091,10 +1062,11 @@ static void smsc75xx_unbind(struct usbnet *dev, struct usb_interface *intf) } } -static void smsc75xx_rx_csum_offload(struct sk_buff *skb, u32 rx_cmd_a, - u32 rx_cmd_b) +static void smsc75xx_rx_csum_offload(struct usbnet *dev, struct sk_buff *skb, + u32 rx_cmd_a, u32 rx_cmd_b) { - if (unlikely(rx_cmd_a & RX_CMD_A_LCSM)) { + if (!(dev->net->features & NETIF_F_RXCSUM) || + unlikely(rx_cmd_a & RX_CMD_A_LCSM)) { skb->ip_summed = CHECKSUM_NONE; } else { skb->csum = ntohs((u16)(rx_cmd_b >> RX_CMD_B_CSUM_SHIFT)); @@ -1104,8 +1076,6 @@ static void smsc75xx_rx_csum_offload(struct sk_buff *skb, u32 rx_cmd_a, static int smsc75xx_rx_fixup(struct usbnet *dev, struct sk_buff *skb) { - struct smsc75xx_priv *pdata = (struct smsc75xx_priv *)(dev->data[0]); - while (skb->len > 0) { u32 rx_cmd_a, rx_cmd_b, align_count, size; struct sk_buff *ax_skb; @@ -1145,11 +1115,8 @@ static int smsc75xx_rx_fixup(struct usbnet *dev, struct sk_buff *skb) /* last frame in this batch */ if (skb->len == size) { - if (pdata->use_rx_csum) - smsc75xx_rx_csum_offload(skb, rx_cmd_a, - rx_cmd_b); - else - skb->ip_summed = CHECKSUM_NONE; + smsc75xx_rx_csum_offload(dev, skb, rx_cmd_a, + rx_cmd_b); skb_trim(skb, skb->len - 4); /* remove fcs */ skb->truesize = size + sizeof(struct sk_buff); @@ -1167,11 +1134,8 @@ static int smsc75xx_rx_fixup(struct usbnet *dev, struct sk_buff *skb) ax_skb->data = packet; skb_set_tail_pointer(ax_skb, size); - if (pdata->use_rx_csum) - smsc75xx_rx_csum_offload(ax_skb, rx_cmd_a, - rx_cmd_b); - else - ax_skb->ip_summed = CHECKSUM_NONE; + smsc75xx_rx_csum_offload(dev, ax_skb, rx_cmd_a, + rx_cmd_b); skb_trim(ax_skb, ax_skb->len - 4); /* remove fcs */ ax_skb->truesize = size + sizeof(struct sk_buff); diff --git a/drivers/net/usb/smsc95xx.c b/drivers/net/usb/smsc95xx.c index 727874d..708f208 100644 --- a/drivers/net/usb/smsc95xx.c +++ b/drivers/net/usb/smsc95xx.c @@ -52,8 +52,6 @@ struct smsc95xx_priv { u32 hash_hi; u32 hash_lo; spinlock_t mac_cr_lock; - bool use_tx_csum; - bool use_rx_csum; }; struct usb_context { @@ -517,22 +515,24 @@ static void smsc95xx_status(struct usbnet *dev, struct urb *urb) } /* Enable or disable Tx & Rx checksum offload engines */ -static int smsc95xx_set_csums(struct usbnet *dev) +static int smsc95xx_set_features(struct net_device *netdev, u32 features) { - struct smsc95xx_priv *pdata = (struct smsc95xx_priv *)(dev->data[0]); + struct usbnet *dev = netdev_priv(netdev); u32 read_buf; - int ret = smsc95xx_read_reg(dev, COE_CR, &read_buf); + int ret; + + ret = smsc95xx_read_reg(dev, COE_CR, &read_buf); if (ret < 0) { netdev_warn(dev->net, "Failed to read COE_CR: %d\n", ret); return ret; } - if (pdata->use_tx_csum) + if (features & NETIF_F_HW_CSUM) read_buf |= Tx_COE_EN_; else read_buf &= ~Tx_COE_EN_; - if (pdata->use_rx_csum) + if (features & NETIF_F_RXCSUM) read_buf |= Rx_COE_EN_; else read_buf &= ~Rx_COE_EN_; @@ -576,43 +576,6 @@ static int smsc95xx_ethtool_set_eeprom(struct net_device *netdev, return smsc95xx_write_eeprom(dev, ee->offset, ee->len, data); } -static u32 smsc95xx_ethtool_get_rx_csum(struct net_device *netdev) -{ - struct usbnet *dev = netdev_priv(netdev); - struct smsc95xx_priv *pdata = (struct smsc95xx_priv *)(dev->data[0]); - - return pdata->use_rx_csum; -} - -static int smsc95xx_ethtool_set_rx_csum(struct net_device *netdev, u32 val) -{ - struct usbnet *dev = netdev_priv(netdev); - struct smsc95xx_priv *pdata = (struct smsc95xx_priv *)(dev->data[0]); - - pdata->use_rx_csum = !!val; - - return smsc95xx_set_csums(dev); -} - -static u32 smsc95xx_ethtool_get_tx_csum(struct net_device *netdev) -{ - struct usbnet *dev = netdev_priv(netdev); - struct smsc95xx_priv *pdata = (struct smsc95xx_priv *)(dev->data[0]); - - return pdata->use_tx_csum; -} - -static int smsc95xx_ethtool_set_tx_csum(struct net_device *netdev, u32 val) -{ - struct usbnet *dev = netdev_priv(netdev); - struct smsc95xx_priv *pdata = (struct smsc95xx_priv *)(dev->data[0]); - - pdata->use_tx_csum = !!val; - - ethtool_op_set_tx_hw_csum(netdev, pdata->use_tx_csum); - return smsc95xx_set_csums(dev); -} - static const struct ethtool_ops smsc95xx_ethtool_ops = { .get_link = usbnet_get_link, .nway_reset = usbnet_nway_reset, @@ -624,10 +587,6 @@ static const struct ethtool_ops smsc95xx_ethtool_ops = { .get_eeprom_len = smsc95xx_ethtool_get_eeprom_len, .get_eeprom = smsc95xx_ethtool_get_eeprom, .set_eeprom = smsc95xx_ethtool_set_eeprom, - .get_tx_csum = smsc95xx_ethtool_get_tx_csum, - .set_tx_csum = smsc95xx_ethtool_set_tx_csum, - .get_rx_csum = smsc95xx_ethtool_get_rx_csum, - .set_rx_csum = smsc95xx_ethtool_set_rx_csum, }; static int smsc95xx_ioctl(struct net_device *netdev, struct ifreq *rq, int cmd) @@ -755,7 +714,6 @@ static int smsc95xx_phy_initialize(struct usbnet *dev) static int smsc95xx_reset(struct usbnet *dev) { struct smsc95xx_priv *pdata = (struct smsc95xx_priv *)(dev->data[0]); - struct net_device *netdev = dev->net; u32 read_buf, write_buf, burst_cap; int ret = 0, timeout; @@ -975,12 +933,7 @@ static int smsc95xx_reset(struct usbnet *dev) } /* Enable or disable checksum offload engines */ - ethtool_op_set_tx_hw_csum(netdev, pdata->use_tx_csum); - ret = smsc95xx_set_csums(dev); - if (ret < 0) { - netdev_warn(dev->net, "Failed to set csum offload: %d\n", ret); - return ret; - } + smsc95xx_set_features(dev->net, dev->net->features); smsc95xx_set_multicast(dev->net); @@ -1019,6 +972,7 @@ static const struct net_device_ops smsc95xx_netdev_ops = { .ndo_validate_addr = eth_validate_addr, .ndo_do_ioctl = smsc95xx_ioctl, .ndo_set_multicast_list = smsc95xx_set_multicast, + .ndo_set_features = smsc95xx_set_features, }; static int smsc95xx_bind(struct usbnet *dev, struct usb_interface *intf) @@ -1045,8 +999,12 @@ static int smsc95xx_bind(struct usbnet *dev, struct usb_interface *intf) spin_lock_init(&pdata->mac_cr_lock); - pdata->use_tx_csum = DEFAULT_TX_CSUM_ENABLE; - pdata->use_rx_csum = DEFAULT_RX_CSUM_ENABLE; + if (DEFAULT_TX_CSUM_ENABLE) + dev->net->features |= NETIF_F_HW_CSUM; + if (DEFAULT_RX_CSUM_ENABLE) + dev->net->features |= NETIF_F_RXCSUM; + + dev->net->hw_features = NETIF_F_HW_CSUM | NETIF_F_RXCSUM; smsc95xx_init_mac_address(dev); @@ -1056,7 +1014,7 @@ static int smsc95xx_bind(struct usbnet *dev, struct usb_interface *intf) dev->net->netdev_ops = &smsc95xx_netdev_ops; dev->net->ethtool_ops = &smsc95xx_ethtool_ops; dev->net->flags |= IFF_MULTICAST; - dev->net->hard_header_len += SMSC95XX_TX_OVERHEAD; + dev->net->hard_header_len += SMSC95XX_TX_OVERHEAD_CSUM; return 0; } @@ -1080,8 +1038,6 @@ static void smsc95xx_rx_csum_offload(struct sk_buff *skb) static int smsc95xx_rx_fixup(struct usbnet *dev, struct sk_buff *skb) { - struct smsc95xx_priv *pdata = (struct smsc95xx_priv *)(dev->data[0]); - while (skb->len > 0) { u32 header, align_count; struct sk_buff *ax_skb; @@ -1123,7 +1079,7 @@ static int smsc95xx_rx_fixup(struct usbnet *dev, struct sk_buff *skb) /* last frame in this batch */ if (skb->len == size) { - if (pdata->use_rx_csum) + if (dev->net->features & NETIF_F_RXCSUM) smsc95xx_rx_csum_offload(skb); skb_trim(skb, skb->len - 4); /* remove fcs */ skb->truesize = size + sizeof(struct sk_buff); @@ -1141,7 +1097,7 @@ static int smsc95xx_rx_fixup(struct usbnet *dev, struct sk_buff *skb) ax_skb->data = packet; skb_set_tail_pointer(ax_skb, size); - if (pdata->use_rx_csum) + if (dev->net->features & NETIF_F_RXCSUM) smsc95xx_rx_csum_offload(ax_skb); skb_trim(ax_skb, ax_skb->len - 4); /* remove fcs */ ax_skb->truesize = size + sizeof(struct sk_buff); @@ -1174,8 +1130,7 @@ static u32 smsc95xx_calc_csum_preamble(struct sk_buff *skb) static struct sk_buff *smsc95xx_tx_fixup(struct usbnet *dev, struct sk_buff *skb, gfp_t flags) { - struct smsc95xx_priv *pdata = (struct smsc95xx_priv *)(dev->data[0]); - bool csum = pdata->use_tx_csum && (skb->ip_summed == CHECKSUM_PARTIAL); + bool csum = skb->ip_summed == CHECKSUM_PARTIAL; int overhead = csum ? SMSC95XX_TX_OVERHEAD_CSUM : SMSC95XX_TX_OVERHEAD; u32 tx_cmd_a, tx_cmd_b; -- cgit v0.10.2 From fb507934fd6faa00b3d833facb53b90c71ddc307 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Miros=C5=82aw?= Date: Thu, 31 Mar 2011 01:01:35 +0000 Subject: net: convert xen-netfront to hw_features MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Not tested in any way. The original code for offload setting seems broken as it resets the features on every netback reconnect. This will set GSO_ROBUST at device creation time (earlier than connect time). RX checksum offload is forced on - so advertise as it is. Signed-off-by: MichaÅ‚ MirosÅ‚aw Signed-off-by: David S. Miller diff --git a/drivers/net/xen-netfront.c b/drivers/net/xen-netfront.c index c06f5a0..f6e7e27 100644 --- a/drivers/net/xen-netfront.c +++ b/drivers/net/xen-netfront.c @@ -1148,6 +1148,8 @@ static const struct net_device_ops xennet_netdev_ops = { .ndo_change_mtu = xennet_change_mtu, .ndo_set_mac_address = eth_mac_addr, .ndo_validate_addr = eth_validate_addr, + .ndo_fix_features = xennet_fix_features, + .ndo_set_features = xennet_set_features, }; static struct net_device * __devinit xennet_create_dev(struct xenbus_device *dev) @@ -1209,7 +1211,9 @@ static struct net_device * __devinit xennet_create_dev(struct xenbus_device *dev netdev->netdev_ops = &xennet_netdev_ops; netif_napi_add(netdev, &np->napi, xennet_poll, 64); - netdev->features = NETIF_F_IP_CSUM; + netdev->features = NETIF_F_IP_CSUM | NETIF_F_RXCSUM | + NETIF_F_GSO_ROBUST; + netdev->hw_features = NETIF_F_IP_CSUM | NETIF_F_SG | NETIF_F_TSO; SET_ETHTOOL_OPS(netdev, &xennet_ethtool_ops); SET_NETDEV_DEV(netdev, &dev->dev); @@ -1509,52 +1513,40 @@ again: return err; } -static int xennet_set_sg(struct net_device *dev, u32 data) +static u32 xennet_fix_features(struct net_device *dev, u32 features) { - if (data) { - struct netfront_info *np = netdev_priv(dev); - int val; + struct netfront_info *np = netdev_priv(dev); + int val; + if (features & NETIF_F_SG) { if (xenbus_scanf(XBT_NIL, np->xbdev->otherend, "feature-sg", "%d", &val) < 0) val = 0; - if (!val) - return -ENOSYS; - } else if (dev->mtu > ETH_DATA_LEN) - dev->mtu = ETH_DATA_LEN; - return ethtool_op_set_sg(dev, data); -} - -static int xennet_set_tso(struct net_device *dev, u32 data) -{ - if (data) { - struct netfront_info *np = netdev_priv(dev); - int val; + if (!val) + features &= ~NETIF_F_SG; + } + if (features & NETIF_F_TSO) { if (xenbus_scanf(XBT_NIL, np->xbdev->otherend, "feature-gso-tcpv4", "%d", &val) < 0) val = 0; + if (!val) - return -ENOSYS; + features &= ~NETIF_F_TSO; } - return ethtool_op_set_tso(dev, data); + return features; } -static void xennet_set_features(struct net_device *dev) +static int xennet_set_features(struct net_device *dev, u32 features) { - /* Turn off all GSO bits except ROBUST. */ - dev->features &= ~NETIF_F_GSO_MASK; - dev->features |= NETIF_F_GSO_ROBUST; - xennet_set_sg(dev, 0); - - /* We need checksum offload to enable scatter/gather and TSO. */ - if (!(dev->features & NETIF_F_IP_CSUM)) - return; + if (!(features & NETIF_F_SG) && dev->mtu > ETH_DATA_LEN) { + netdev_info(dev, "Reducing MTU because no SG offload"); + dev->mtu = ETH_DATA_LEN; + } - if (!xennet_set_sg(dev, 1)) - xennet_set_tso(dev, 1); + return 0; } static int xennet_connect(struct net_device *dev) @@ -1581,7 +1573,7 @@ static int xennet_connect(struct net_device *dev) if (err) return err; - xennet_set_features(dev); + netdev_update_features(dev); spin_lock_bh(&np->rx_lock); spin_lock_irq(&np->tx_lock); @@ -1709,9 +1701,6 @@ static void xennet_get_strings(struct net_device *dev, u32 stringset, u8 * data) static const struct ethtool_ops xennet_ethtool_ops = { - .set_tx_csum = ethtool_op_set_tx_csum, - .set_sg = xennet_set_sg, - .set_tso = xennet_set_tso, .get_link = ethtool_op_get_link, .get_sset_count = xennet_get_sset_count, -- cgit v0.10.2 From d7b576545648e487b2958c220542e111f5ac46f0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Miros=C5=82aw?= Date: Thu, 31 Mar 2011 01:01:35 +0000 Subject: jme: convert offload constraints to ndo_fix_features MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: MichaÅ‚ MirosÅ‚aw Signed-off-by: David S. Miller diff --git a/drivers/net/jme.c b/drivers/net/jme.c index 994c809..be4773f 100644 --- a/drivers/net/jme.c +++ b/drivers/net/jme.c @@ -2230,17 +2230,9 @@ jme_change_mtu(struct net_device *netdev, int new_mtu) jme_restart_rx_engine(jme); } - if (new_mtu > 1900) { - netdev->features &= ~(NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM | - NETIF_F_TSO | NETIF_F_TSO6); - } else { - if (test_bit(JME_FLAG_TXCSUM, &jme->flags)) - netdev->features |= NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM; - if (test_bit(JME_FLAG_TSO, &jme->flags)) - netdev->features |= NETIF_F_TSO | NETIF_F_TSO6; - } - netdev->mtu = new_mtu; + netdev_update_features(netdev); + jme_reset_link(jme); return 0; @@ -2640,19 +2632,20 @@ jme_set_msglevel(struct net_device *netdev, u32 value) } static u32 -jme_get_rx_csum(struct net_device *netdev) +jme_fix_features(struct net_device *netdev, u32 features) { - struct jme_adapter *jme = netdev_priv(netdev); - return jme->reg_rxmcs & RXMCS_CHECKSUM; + if (netdev->mtu > 1900) + features &= ~(NETIF_F_ALL_TSO | NETIF_F_ALL_CSUM); + return features; } static int -jme_set_rx_csum(struct net_device *netdev, u32 on) +jme_set_features(struct net_device *netdev, u32 features) { struct jme_adapter *jme = netdev_priv(netdev); spin_lock_bh(&jme->rxmcs_lock); - if (on) + if (features & NETIF_F_RXCSUM) jme->reg_rxmcs |= RXMCS_CHECKSUM; else jme->reg_rxmcs &= ~RXMCS_CHECKSUM; @@ -2663,42 +2656,6 @@ jme_set_rx_csum(struct net_device *netdev, u32 on) } static int -jme_set_tx_csum(struct net_device *netdev, u32 on) -{ - struct jme_adapter *jme = netdev_priv(netdev); - - if (on) { - set_bit(JME_FLAG_TXCSUM, &jme->flags); - if (netdev->mtu <= 1900) - netdev->features |= - NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM; - } else { - clear_bit(JME_FLAG_TXCSUM, &jme->flags); - netdev->features &= - ~(NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM); - } - - return 0; -} - -static int -jme_set_tso(struct net_device *netdev, u32 on) -{ - struct jme_adapter *jme = netdev_priv(netdev); - - if (on) { - set_bit(JME_FLAG_TSO, &jme->flags); - if (netdev->mtu <= 1900) - netdev->features |= NETIF_F_TSO | NETIF_F_TSO6; - } else { - clear_bit(JME_FLAG_TSO, &jme->flags); - netdev->features &= ~(NETIF_F_TSO | NETIF_F_TSO6); - } - - return 0; -} - -static int jme_nway_reset(struct net_device *netdev) { struct jme_adapter *jme = netdev_priv(netdev); @@ -2839,11 +2796,6 @@ static const struct ethtool_ops jme_ethtool_ops = { .get_link = jme_get_link, .get_msglevel = jme_get_msglevel, .set_msglevel = jme_set_msglevel, - .get_rx_csum = jme_get_rx_csum, - .set_rx_csum = jme_set_rx_csum, - .set_tx_csum = jme_set_tx_csum, - .set_tso = jme_set_tso, - .set_sg = ethtool_op_set_sg, .nway_reset = jme_nway_reset, .get_eeprom_len = jme_get_eeprom_len, .get_eeprom = jme_get_eeprom, @@ -2903,6 +2855,8 @@ static const struct net_device_ops jme_netdev_ops = { .ndo_change_mtu = jme_change_mtu, .ndo_tx_timeout = jme_tx_timeout, .ndo_vlan_rx_register = jme_vlan_rx_register, + .ndo_fix_features = jme_fix_features, + .ndo_set_features = jme_set_features, }; static int __devinit @@ -2957,6 +2911,12 @@ jme_init_one(struct pci_dev *pdev, netdev->netdev_ops = &jme_netdev_ops; netdev->ethtool_ops = &jme_ethtool_ops; netdev->watchdog_timeo = TX_TIMEOUT; + netdev->hw_features = NETIF_F_IP_CSUM | + NETIF_F_IPV6_CSUM | + NETIF_F_SG | + NETIF_F_TSO | + NETIF_F_TSO6 | + NETIF_F_RXCSUM; netdev->features = NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM | NETIF_F_SG | @@ -3040,8 +3000,9 @@ jme_init_one(struct pci_dev *pdev, jme->reg_txpfc = 0; jme->reg_pmcs = PMCS_MFEN; jme->reg_gpreg1 = GPREG1_DEFAULT; - set_bit(JME_FLAG_TXCSUM, &jme->flags); - set_bit(JME_FLAG_TSO, &jme->flags); + + if (jme->reg_rxmcs & RXMCS_CHECKSUM) + netdev->features |= NETIF_F_RXCSUM; /* * Get Max Read Req Size from PCI Config Space diff --git a/drivers/net/jme.h b/drivers/net/jme.h index 8bf3045..e9aaeca 100644 --- a/drivers/net/jme.h +++ b/drivers/net/jme.h @@ -468,8 +468,6 @@ struct jme_adapter { enum jme_flags_bits { JME_FLAG_MSI = 1, JME_FLAG_SSET = 2, - JME_FLAG_TXCSUM = 3, - JME_FLAG_TSO = 4, JME_FLAG_POLL = 5, JME_FLAG_SHUTDOWN = 6, }; -- cgit v0.10.2 From a2c725fa39b79fcc3f09151e847cc006ff0d4389 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Miros=C5=82aw?= Date: Thu, 31 Mar 2011 01:01:35 +0000 Subject: veth: convert to hw_features MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This should probably get TSO available as it's basically a loopback device. Offloads are left disabled by default - as before. Signed-off-by: MichaÅ‚ MirosÅ‚aw Signed-off-by: David S. Miller diff --git a/drivers/net/veth.c b/drivers/net/veth.c index 2de9b90..6542288 100644 --- a/drivers/net/veth.c +++ b/drivers/net/veth.c @@ -36,7 +36,6 @@ struct veth_net_stats { struct veth_priv { struct net_device *peer; struct veth_net_stats __percpu *stats; - unsigned ip_summed; }; /* @@ -99,47 +98,10 @@ static void veth_get_ethtool_stats(struct net_device *dev, data[0] = priv->peer->ifindex; } -static u32 veth_get_rx_csum(struct net_device *dev) -{ - struct veth_priv *priv; - - priv = netdev_priv(dev); - return priv->ip_summed == CHECKSUM_UNNECESSARY; -} - -static int veth_set_rx_csum(struct net_device *dev, u32 data) -{ - struct veth_priv *priv; - - priv = netdev_priv(dev); - priv->ip_summed = data ? CHECKSUM_UNNECESSARY : CHECKSUM_NONE; - return 0; -} - -static u32 veth_get_tx_csum(struct net_device *dev) -{ - return (dev->features & NETIF_F_NO_CSUM) != 0; -} - -static int veth_set_tx_csum(struct net_device *dev, u32 data) -{ - if (data) - dev->features |= NETIF_F_NO_CSUM; - else - dev->features &= ~NETIF_F_NO_CSUM; - return 0; -} - static const struct ethtool_ops veth_ethtool_ops = { .get_settings = veth_get_settings, .get_drvinfo = veth_get_drvinfo, .get_link = ethtool_op_get_link, - .get_rx_csum = veth_get_rx_csum, - .set_rx_csum = veth_set_rx_csum, - .get_tx_csum = veth_get_tx_csum, - .set_tx_csum = veth_set_tx_csum, - .get_sg = ethtool_op_get_sg, - .set_sg = ethtool_op_set_sg, .get_strings = veth_get_strings, .get_sset_count = veth_get_sset_count, .get_ethtool_stats = veth_get_ethtool_stats, @@ -168,8 +130,9 @@ static netdev_tx_t veth_xmit(struct sk_buff *skb, struct net_device *dev) /* don't change ip_summed == CHECKSUM_PARTIAL, as that will cause bad checksum on forwarded packets */ - if (skb->ip_summed == CHECKSUM_NONE) - skb->ip_summed = rcv_priv->ip_summed; + if (skb->ip_summed == CHECKSUM_NONE && + rcv->features & NETIF_F_RXCSUM) + skb->ip_summed = CHECKSUM_UNNECESSARY; length = skb->len; if (dev_forward_skb(rcv, skb) != NET_RX_SUCCESS) @@ -304,6 +267,8 @@ static void veth_setup(struct net_device *dev) dev->ethtool_ops = &veth_ethtool_ops; dev->features |= NETIF_F_LLTX; dev->destructor = veth_dev_free; + + dev->hw_features = NETIF_F_NO_CSUM | NETIF_F_SG | NETIF_F_RXCSUM; } /* -- cgit v0.10.2 From e9403c8437cf3721e7901c1a8fcb06bb642a7e55 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Miros=C5=82aw?= Date: Fri, 1 Apr 2011 20:58:37 -0700 Subject: net: convert sunhme/sungem network drivers to hw_features MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Side effects: - TX offloads (HW csum, scatter-gather) can be toggled now - RX checksum is reported correctly now (it's always active) Signed-off-by: MichaÅ‚ MirosÅ‚aw Signed-off-by: David S. Miller diff --git a/drivers/net/sungem.c b/drivers/net/sungem.c index c1a3448..a935426 100644 --- a/drivers/net/sungem.c +++ b/drivers/net/sungem.c @@ -3146,7 +3146,8 @@ static int __devinit gem_init_one(struct pci_dev *pdev, gp->phy_mii.def ? gp->phy_mii.def->name : "no"); /* GEM can do it all... */ - dev->features |= NETIF_F_SG | NETIF_F_HW_CSUM | NETIF_F_LLTX; + dev->hw_features = NETIF_F_SG | NETIF_F_HW_CSUM; + dev->features |= dev->hw_features | NETIF_F_RXCSUM | NETIF_F_LLTX; if (pci_using_dac) dev->features |= NETIF_F_HIGHDMA; diff --git a/drivers/net/sunhme.c b/drivers/net/sunhme.c index eb4f59f..80e907d 100644 --- a/drivers/net/sunhme.c +++ b/drivers/net/sunhme.c @@ -2788,7 +2788,8 @@ static int __devinit happy_meal_sbus_probe_one(struct platform_device *op, int i dev->ethtool_ops = &hme_ethtool_ops; /* Happy Meal can do it all... */ - dev->features |= NETIF_F_SG | NETIF_F_HW_CSUM; + dev->hw_features = NETIF_F_SG | NETIF_F_HW_CSUM; + dev->features |= dev->hw_features | NETIF_F_RXCSUM; dev->irq = op->archdata.irqs[0]; @@ -3113,7 +3114,8 @@ static int __devinit happy_meal_pci_probe(struct pci_dev *pdev, dev->dma = 0; /* Happy Meal can do it all... */ - dev->features |= NETIF_F_SG | NETIF_F_HW_CSUM; + dev->hw_features = NETIF_F_SG | NETIF_F_HW_CSUM; + dev->features |= dev->hw_features | NETIF_F_RXCSUM; #if defined(CONFIG_SBUS) && defined(CONFIG_PCI) /* Hook up PCI register/descriptor accessors. */ -- cgit v0.10.2 From 6cb6a27c45cec9184302c2e350b3593c64bc7f6c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Miros=C5=82aw?= Date: Sat, 2 Apr 2011 22:48:47 -0700 Subject: net: Call netdev_features_change() from netdev_update_features() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Issue FEAT_CHANGE notification when features are changed by netdev_update_features(). This will allow changes made by extra constraints on e.g. MTU change to be properly propagated like changes via ethtool. Signed-off-by: MichaÅ‚ MirosÅ‚aw Signed-off-by: David S. Miller diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index 5eeb2cd..423a544 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -2550,6 +2550,7 @@ static inline u32 netdev_get_wanted_features(struct net_device *dev) } u32 netdev_increment_features(u32 all, u32 one, u32 mask); u32 netdev_fix_features(struct net_device *dev, u32 features); +int __netdev_update_features(struct net_device *dev); void netdev_update_features(struct net_device *dev); void netif_stacked_transfer_operstate(const struct net_device *rootdev, diff --git a/net/core/dev.c b/net/core/dev.c index 3da9fb0..02f5637 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -5236,7 +5236,7 @@ u32 netdev_fix_features(struct net_device *dev, u32 features) } EXPORT_SYMBOL(netdev_fix_features); -void netdev_update_features(struct net_device *dev) +int __netdev_update_features(struct net_device *dev) { u32 features; int err = 0; @@ -5250,7 +5250,7 @@ void netdev_update_features(struct net_device *dev) features = netdev_fix_features(dev, features); if (dev->features == features) - return; + return 0; netdev_info(dev, "Features changed: 0x%08x -> 0x%08x\n", dev->features, features); @@ -5258,12 +5258,23 @@ void netdev_update_features(struct net_device *dev) if (dev->netdev_ops->ndo_set_features) err = dev->netdev_ops->ndo_set_features(dev, features); - if (!err) - dev->features = features; - else if (err < 0) + if (unlikely(err < 0)) { netdev_err(dev, "set_features() failed (%d); wanted 0x%08x, left 0x%08x\n", err, features, dev->features); + return -1; + } + + if (!err) + dev->features = features; + + return 1; +} + +void netdev_update_features(struct net_device *dev) +{ + if (__netdev_update_features(dev)) + netdev_features_change(dev); } EXPORT_SYMBOL(netdev_update_features); @@ -5430,7 +5441,7 @@ int register_netdevice(struct net_device *dev) goto err_uninit; dev->reg_state = NETREG_REGISTERED; - netdev_update_features(dev); + __netdev_update_features(dev); /* * Default initial state at registry is that the diff --git a/net/core/ethtool.c b/net/core/ethtool.c index 74ead9e..439e4b0 100644 --- a/net/core/ethtool.c +++ b/net/core/ethtool.c @@ -317,7 +317,7 @@ static int ethtool_set_features(struct net_device *dev, void __user *useraddr) dev->wanted_features &= ~features[0].valid; dev->wanted_features |= features[0].valid & features[0].requested; - netdev_update_features(dev); + __netdev_update_features(dev); if ((dev->wanted_features ^ dev->features) & features[0].valid) ret |= ETHTOOL_F_WISH; @@ -499,7 +499,7 @@ static int ethtool_set_one_feature(struct net_device *dev, else dev->wanted_features &= ~mask; - netdev_update_features(dev); + __netdev_update_features(dev); return 0; } @@ -551,7 +551,7 @@ int __ethtool_set_flags(struct net_device *dev, u32 data) dev->wanted_features = (dev->wanted_features & ~changed) | data; - netdev_update_features(dev); + __netdev_update_features(dev); return 0; } -- cgit v0.10.2 From 8a0427bb688eae86a8bb939b6a74e5aa00aa035a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Miros=C5=82aw?= Date: Sat, 2 Apr 2011 22:49:12 -0700 Subject: vlan: convert VLAN devices to use ndo_fix_features() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Note: get_flags was actually broken, because it should return the flags capped with vlan_features. This is now done implicitly by limiting netdev->hw_features. RX checksumming offload control is (and was) broken, as there was no way before to say whether it's done for tagged packets. Signed-off-by: MichaÅ‚ MirosÅ‚aw Signed-off-by: David S. Miller diff --git a/net/8021q/vlan.c b/net/8021q/vlan.c index 7850412..e47600b 100644 --- a/net/8021q/vlan.c +++ b/net/8021q/vlan.c @@ -327,10 +327,6 @@ static void vlan_sync_address(struct net_device *dev, static void vlan_transfer_features(struct net_device *dev, struct net_device *vlandev) { - u32 old_features = vlandev->features; - - vlandev->features &= ~dev->vlan_features; - vlandev->features |= dev->features & dev->vlan_features; vlandev->gso_max_size = dev->gso_max_size; if (dev->features & NETIF_F_HW_VLAN_TX) @@ -341,8 +337,8 @@ static void vlan_transfer_features(struct net_device *dev, #if defined(CONFIG_FCOE) || defined(CONFIG_FCOE_MODULE) vlandev->fcoe_ddp_xid = dev->fcoe_ddp_xid; #endif - if (old_features != vlandev->features) - netdev_features_change(vlandev); + + netdev_update_features(vlandev); } static void __vlan_device_event(struct net_device *dev, unsigned long event) diff --git a/net/8021q/vlan_dev.c b/net/8021q/vlan_dev.c index e34ea9e..b84a46b 100644 --- a/net/8021q/vlan_dev.c +++ b/net/8021q/vlan_dev.c @@ -704,8 +704,8 @@ static int vlan_dev_init(struct net_device *dev) (1<<__LINK_STATE_DORMANT))) | (1<<__LINK_STATE_PRESENT); - dev->features |= real_dev->features & real_dev->vlan_features; - dev->features |= NETIF_F_LLTX; + dev->hw_features = real_dev->vlan_features & NETIF_F_ALL_TX_OFFLOADS; + dev->features |= real_dev->vlan_features | NETIF_F_LLTX; dev->gso_max_size = real_dev->gso_max_size; /* ipv6 shared card related stuff */ @@ -759,6 +759,17 @@ static void vlan_dev_uninit(struct net_device *dev) } } +static u32 vlan_dev_fix_features(struct net_device *dev, u32 features) +{ + struct net_device *real_dev = vlan_dev_info(dev)->real_dev; + + features &= (real_dev->features | NETIF_F_LLTX); + if (dev_ethtool_get_rx_csum(real_dev)) + features |= NETIF_F_RXCSUM; + + return features; +} + static int vlan_ethtool_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) { @@ -774,18 +785,6 @@ static void vlan_ethtool_get_drvinfo(struct net_device *dev, strcpy(info->fw_version, "N/A"); } -static u32 vlan_ethtool_get_rx_csum(struct net_device *dev) -{ - const struct vlan_dev_info *vlan = vlan_dev_info(dev); - return dev_ethtool_get_rx_csum(vlan->real_dev); -} - -static u32 vlan_ethtool_get_flags(struct net_device *dev) -{ - const struct vlan_dev_info *vlan = vlan_dev_info(dev); - return dev_ethtool_get_flags(vlan->real_dev); -} - static struct rtnl_link_stats64 *vlan_dev_get_stats64(struct net_device *dev, struct rtnl_link_stats64 *stats) { @@ -823,32 +822,10 @@ static struct rtnl_link_stats64 *vlan_dev_get_stats64(struct net_device *dev, st return stats; } -static int vlan_ethtool_set_tso(struct net_device *dev, u32 data) -{ - if (data) { - struct net_device *real_dev = vlan_dev_info(dev)->real_dev; - - /* Underlying device must support TSO for VLAN-tagged packets - * and must have TSO enabled now. - */ - if (!(real_dev->vlan_features & NETIF_F_TSO)) - return -EOPNOTSUPP; - if (!(real_dev->features & NETIF_F_TSO)) - return -EINVAL; - dev->features |= NETIF_F_TSO; - } else { - dev->features &= ~NETIF_F_TSO; - } - return 0; -} - static const struct ethtool_ops vlan_ethtool_ops = { .get_settings = vlan_ethtool_get_settings, .get_drvinfo = vlan_ethtool_get_drvinfo, .get_link = ethtool_op_get_link, - .get_rx_csum = vlan_ethtool_get_rx_csum, - .get_flags = vlan_ethtool_get_flags, - .set_tso = vlan_ethtool_set_tso, }; static const struct net_device_ops vlan_netdev_ops = { @@ -874,6 +851,7 @@ static const struct net_device_ops vlan_netdev_ops = { .ndo_fcoe_get_wwn = vlan_dev_fcoe_get_wwn, .ndo_fcoe_ddp_target = vlan_dev_fcoe_ddp_target, #endif + .ndo_fix_features = vlan_dev_fix_features, }; void vlan_setup(struct net_device *dev) -- cgit v0.10.2 From 711b8c87a5fe6de78e90411cb67b506babfef74a Mon Sep 17 00:00:00 2001 From: Florian Mickler Date: Mon, 4 Apr 2011 01:17:40 +0200 Subject: x86-64, NUMA: Remove unused variable In case !CONFIG_ACPI_NUMA and !CONFIG_AMD_NUMA gcc emits a warning about the unused variable ret. As that variable is in fact not needed I choose to remove it. Signed-off-by: Florian Mickler LKML-Reference: <1301843624-22364-1-git-send-email-florian@mickler.org> Signed-off-by: Tejun Heo diff --git a/arch/x86/mm/numa_64.c b/arch/x86/mm/numa_64.c index 3951ee6..13f5b06 100644 --- a/arch/x86/mm/numa_64.c +++ b/arch/x86/mm/numa_64.c @@ -505,17 +505,13 @@ static int __init numa_init(int (*init_func)(void)) void __init initmem_init(void) { - int ret; - if (!numa_off) { #ifdef CONFIG_ACPI_NUMA - ret = numa_init(x86_acpi_numa_init); - if (!ret) + if (!numa_init(x86_acpi_numa_init)) return; #endif #ifdef CONFIG_AMD_NUMA - ret = numa_init(amd_numa_init); - if (!ret) + if (!numa_init(amd_numa_init)) return; #endif } -- cgit v0.10.2 From 1deac632fc3dcff33a6df3e82ef10c738ac13fe6 Mon Sep 17 00:00:00 2001 From: Oleg Nesterov Date: Fri, 1 Apr 2011 20:11:50 +0200 Subject: signal: prepare_signal(SIGCONT) shouldn't play with TIF_SIGPENDING prepare_signal(SIGCONT) should never set TIF_SIGPENDING or wake up the TASK_INTERRUPTIBLE threads. We are going to call complete_signal() which should pick the right thread correctly. All we need is to wake up the TASK_STOPPED threads. If the task was stopped, it can't return to usermode without taking ->siglock. Otherwise we don't care, and the spurious TIF_SIGPENDING can't be useful. The comment says: * If there is a handler for SIGCONT, we must make * sure that no thread returns to user mode before * we post the signal It is not clear what this means. Probably, "when there's only a single thread" and this continues to be true. Otherwise, even if this SIGCONT is not private, with or without this change only one thread can dequeue SIGCONT, other threads can happily return to user mode before before that thread handles this signal. Note also that wake_up_state(t, __TASK_STOPPED) can't race with the task which changes its state, TASK_STOPPED state is protected by ->siglock as well. In short: when it comes to signal delivery, SIGCONT is the normal signal and does not need any special support. Signed-off-by: Oleg Nesterov Signed-off-by: Tejun Heo diff --git a/kernel/signal.c b/kernel/signal.c index f799a05..38ea9e2 100644 --- a/kernel/signal.c +++ b/kernel/signal.c @@ -788,37 +788,14 @@ static int prepare_signal(int sig, struct task_struct *p, int from_ancestor_ns) } else if (sig == SIGCONT) { unsigned int why; /* - * Remove all stop signals from all queues, - * and wake all threads. + * Remove all stop signals from all queues, wake all threads. */ rm_from_queue(SIG_KERNEL_STOP_MASK, &signal->shared_pending); t = p; do { - unsigned int state; - task_clear_group_stop_pending(t); - rm_from_queue(SIG_KERNEL_STOP_MASK, &t->pending); - /* - * If there is a handler for SIGCONT, we must make - * sure that no thread returns to user mode before - * we post the signal, in case it was the only - * thread eligible to run the signal handler--then - * it must not do anything between resuming and - * running the handler. With the TIF_SIGPENDING - * flag set, the thread will pause and acquire the - * siglock that we hold now and until we've queued - * the pending signal. - * - * Wake up the stopped thread _after_ setting - * TIF_SIGPENDING - */ - state = __TASK_STOPPED; - if (sig_user_defined(t, SIGCONT) && !sigismember(&t->blocked, SIGCONT)) { - set_tsk_thread_flag(t, TIF_SIGPENDING); - state |= TASK_INTERRUPTIBLE; - } - wake_up_state(t, state); + wake_up_state(t, __TASK_STOPPED); } while_each_thread(p, t); /* -- cgit v0.10.2 From 780006eac2fe7f4d2582da16a096e5a44c4767ff Mon Sep 17 00:00:00 2001 From: Oleg Nesterov Date: Fri, 1 Apr 2011 20:12:16 +0200 Subject: signal: do_signal_stop: Remove the unneeded task_clear_group_stop_pending() PF_EXITING or TASK_STOPPED has already called task_participate_group_stop() and cleared its ->group_stop. No need to do task_clear_group_stop_pending() when we start the new group stop. Add a small comment to explain the !task_is_stopped() check. Note that this check is not exactly right and it can lead to unnecessary stop later if the thread is TASK_PTRACED. What we need is task_participated_in_group_stop(), this will be solved later. Signed-off-by: Oleg Nesterov Signed-off-by: Tejun Heo diff --git a/kernel/signal.c b/kernel/signal.c index 38ea9e2..e9abc69 100644 --- a/kernel/signal.c +++ b/kernel/signal.c @@ -1866,7 +1866,8 @@ static int do_signal_stop(int signr) * still in effect and then receive a stop signal and * initiate another group stop. This deviates from the * usual behavior as two consecutive stop signals can't - * cause two group stops when !ptraced. + * cause two group stops when !ptraced. That is why we + * also check !task_is_stopped(t) below. * * The condition can be distinguished by testing whether * SIGNAL_STOP_STOPPED is already set. Don't generate @@ -1896,8 +1897,6 @@ static int do_signal_stop(int signr) t->group_stop |= signr | gstop; sig->group_stop_count++; signal_wake_up(t, 0); - } else { - task_clear_group_stop_pending(t); } } } -- cgit v0.10.2 From ee77f075921730b2b465880f9fd4367003bdab39 Mon Sep 17 00:00:00 2001 From: Oleg Nesterov Date: Fri, 1 Apr 2011 20:12:38 +0200 Subject: signal: Turn SIGNAL_STOP_DEQUEUED into GROUP_STOP_DEQUEUED This patch moves SIGNAL_STOP_DEQUEUED from signal_struct->flags to task_struct->group_stop, and thus makes it per-thread. Like SIGNAL_STOP_DEQUEUED, GROUP_STOP_DEQUEUED can be false-positive after return from get_signal_to_deliver(), this is fine. The only purpose of this bit is: we can drop ->siglock after __dequeue_signal() returns the sig_kernel_stop() signal and before we call do_signal_stop(), in this case we must not miss SIGCONT if it comes in between. But, unlike SIGNAL_STOP_DEQUEUED, GROUP_STOP_DEQUEUED can not be false-positive in do_signal_stop() if multiple threads dequeue the sig_kernel_stop() signal at the same time. Consider two threads T1 and T2, SIGTTIN has a hanlder. - T1 dequeues SIGTSTP and sets SIGNAL_STOP_DEQUEUED, then it drops ->siglock - SIGCONT comes and clears SIGNAL_STOP_DEQUEUED, SIGTSTP should be cancelled. - T2 dequeues SIGTTIN and sets SIGNAL_STOP_DEQUEUED again. Since we have a handler we should not stop, T2 returns to usermode to run the handler. - T1 continues, calls do_signal_stop() and wrongly starts the group stop because SIGNAL_STOP_DEQUEUED was restored in between. With or without this change: - we need to do something with ptrace_signal() which can return SIGSTOP, but this needs another discussion - SIGSTOP can be lost if it races with the mt exec, will be fixed later. Signed-off-by: Oleg Nesterov Signed-off-by: Tejun Heo diff --git a/include/linux/sched.h b/include/linux/sched.h index 456d80e..8cef82d 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h @@ -652,9 +652,8 @@ struct signal_struct { * Bits in flags field of signal_struct. */ #define SIGNAL_STOP_STOPPED 0x00000001 /* job control stop in effect */ -#define SIGNAL_STOP_DEQUEUED 0x00000002 /* stop signal dequeued */ -#define SIGNAL_STOP_CONTINUED 0x00000004 /* SIGCONT since WCONTINUED reap */ -#define SIGNAL_GROUP_EXIT 0x00000008 /* group exit in progress */ +#define SIGNAL_STOP_CONTINUED 0x00000002 /* SIGCONT since WCONTINUED reap */ +#define SIGNAL_GROUP_EXIT 0x00000004 /* group exit in progress */ /* * Pending notifications to parent. */ @@ -1779,6 +1778,7 @@ extern void thread_group_times(struct task_struct *p, cputime_t *ut, cputime_t * #define GROUP_STOP_PENDING (1 << 16) /* task should stop for group stop */ #define GROUP_STOP_CONSUME (1 << 17) /* consume group stop count */ #define GROUP_STOP_TRAPPING (1 << 18) /* switching from STOPPED to TRACED */ +#define GROUP_STOP_DEQUEUED (1 << 19) /* stop signal dequeued */ extern void task_clear_group_stop_pending(struct task_struct *task); diff --git a/kernel/signal.c b/kernel/signal.c index e9abc69..4f7312b 100644 --- a/kernel/signal.c +++ b/kernel/signal.c @@ -254,7 +254,8 @@ static void task_clear_group_stop_trapping(struct task_struct *task) */ void task_clear_group_stop_pending(struct task_struct *task) { - task->group_stop &= ~(GROUP_STOP_PENDING | GROUP_STOP_CONSUME); + task->group_stop &= ~(GROUP_STOP_PENDING | GROUP_STOP_CONSUME | + GROUP_STOP_DEQUEUED); } /** @@ -602,7 +603,7 @@ int dequeue_signal(struct task_struct *tsk, sigset_t *mask, siginfo_t *info) * is to alert stop-signal processing code when another * processor has come along and cleared the flag. */ - tsk->signal->flags |= SIGNAL_STOP_DEQUEUED; + current->group_stop |= GROUP_STOP_DEQUEUED; } if ((info->si_code & __SI_MASK) == __SI_TIMER && info->si_sys_private) { /* @@ -821,13 +822,6 @@ static int prepare_signal(int sig, struct task_struct *p, int from_ancestor_ns) signal->flags = why | SIGNAL_STOP_CONTINUED; signal->group_stop_count = 0; signal->group_exit_code = 0; - } else { - /* - * We are not stopped, but there could be a stop - * signal in the middle of being processed after - * being removed from the queue. Clear that too. - */ - signal->flags &= ~SIGNAL_STOP_DEQUEUED; } } @@ -1855,7 +1849,7 @@ static int do_signal_stop(int signr) /* signr will be recorded in task->group_stop for retries */ WARN_ON_ONCE(signr & ~GROUP_STOP_SIGMASK); - if (!likely(sig->flags & SIGNAL_STOP_DEQUEUED) || + if (!likely(current->group_stop & GROUP_STOP_DEQUEUED) || unlikely(signal_group_exit(sig))) return 0; /* -- cgit v0.10.2 From 321fb561971ba0f10ce18c0f8a4b9fbfc7cef4b9 Mon Sep 17 00:00:00 2001 From: Oleg Nesterov Date: Fri, 1 Apr 2011 20:13:01 +0200 Subject: ptrace: ptrace_check_attach() should not do s/STOPPED/TRACED/ After "ptrace: Clean transitions between TASK_STOPPED and TRACED" d79fdd6d96f46fabb779d86332e3677c6f5c2a4f, ptrace_check_attach() should never see a TASK_STOPPED tracee and s/STOPPED/TRACED/ is no longer legal. Add the warning. Note: ptrace_check_attach() can be greatly simplified, in particular it doesn't need tasklist. But I'd prefer another patch for that. Signed-off-by: Oleg Nesterov Signed-off-by: Tejun Heo diff --git a/kernel/ptrace.c b/kernel/ptrace.c index 4348586..20d5efd 100644 --- a/kernel/ptrace.c +++ b/kernel/ptrace.c @@ -112,16 +112,14 @@ int ptrace_check_attach(struct task_struct *child, int kill) */ read_lock(&tasklist_lock); if ((child->ptrace & PT_PTRACED) && child->parent == current) { - ret = 0; /* * child->sighand can't be NULL, release_task() * does ptrace_unlink() before __exit_signal(). */ spin_lock_irq(&child->sighand->siglock); - if (task_is_stopped(child)) - child->state = TASK_TRACED; - else if (!task_is_traced(child) && !kill) - ret = -ESRCH; + WARN_ON_ONCE(task_is_stopped(child)); + if (task_is_traced(child) || kill) + ret = 0; spin_unlock_irq(&child->sighand->siglock); } read_unlock(&tasklist_lock); -- cgit v0.10.2 From 8f7b01a178b8e6a7b663a1bbaa1710756d67b69b Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Sun, 3 Apr 2011 17:21:00 -0700 Subject: xen: netfront: fix declaration order Must declare xennet_fix_features() and xennet_set_features() before using them. Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller diff --git a/drivers/net/xen-netfront.c b/drivers/net/xen-netfront.c index f6e7e27..0cfe4cc 100644 --- a/drivers/net/xen-netfront.c +++ b/drivers/net/xen-netfront.c @@ -1140,6 +1140,42 @@ static void xennet_uninit(struct net_device *dev) gnttab_free_grant_references(np->gref_rx_head); } +static u32 xennet_fix_features(struct net_device *dev, u32 features) +{ + struct netfront_info *np = netdev_priv(dev); + int val; + + if (features & NETIF_F_SG) { + if (xenbus_scanf(XBT_NIL, np->xbdev->otherend, "feature-sg", + "%d", &val) < 0) + val = 0; + + if (!val) + features &= ~NETIF_F_SG; + } + + if (features & NETIF_F_TSO) { + if (xenbus_scanf(XBT_NIL, np->xbdev->otherend, + "feature-gso-tcpv4", "%d", &val) < 0) + val = 0; + + if (!val) + features &= ~NETIF_F_TSO; + } + + return features; +} + +static int xennet_set_features(struct net_device *dev, u32 features) +{ + if (!(features & NETIF_F_SG) && dev->mtu > ETH_DATA_LEN) { + netdev_info(dev, "Reducing MTU because no SG offload"); + dev->mtu = ETH_DATA_LEN; + } + + return 0; +} + static const struct net_device_ops xennet_netdev_ops = { .ndo_open = xennet_open, .ndo_uninit = xennet_uninit, @@ -1513,42 +1549,6 @@ again: return err; } -static u32 xennet_fix_features(struct net_device *dev, u32 features) -{ - struct netfront_info *np = netdev_priv(dev); - int val; - - if (features & NETIF_F_SG) { - if (xenbus_scanf(XBT_NIL, np->xbdev->otherend, "feature-sg", - "%d", &val) < 0) - val = 0; - - if (!val) - features &= ~NETIF_F_SG; - } - - if (features & NETIF_F_TSO) { - if (xenbus_scanf(XBT_NIL, np->xbdev->otherend, - "feature-gso-tcpv4", "%d", &val) < 0) - val = 0; - - if (!val) - features &= ~NETIF_F_TSO; - } - - return features; -} - -static int xennet_set_features(struct net_device *dev, u32 features) -{ - if (!(features & NETIF_F_SG) && dev->mtu > ETH_DATA_LEN) { - netdev_info(dev, "Reducing MTU because no SG offload"); - dev->mtu = ETH_DATA_LEN; - } - - return 0; -} - static int xennet_connect(struct net_device *dev) { struct netfront_info *np = netdev_priv(dev); -- cgit v0.10.2 From 95b8fbada76d978ce13a26785f8b85ff54478bb2 Mon Sep 17 00:00:00 2001 From: Jan Engelhardt Date: Sun, 3 Apr 2011 13:31:06 +0000 Subject: mISDN: fix "persistant" typo Signed-off-by: Jan Engelhardt Signed-off-by: David S. Miller diff --git a/drivers/isdn/mISDN/layer2.c b/drivers/isdn/mISDN/layer2.c index 4ae7505..9e1610f 100644 --- a/drivers/isdn/mISDN/layer2.c +++ b/drivers/isdn/mISDN/layer2.c @@ -1640,7 +1640,7 @@ l2_tei_remove(struct FsmInst *fi, int event, void *arg) } static void -l2_st14_persistant_da(struct FsmInst *fi, int event, void *arg) +l2_st14_persistent_da(struct FsmInst *fi, int event, void *arg) { struct layer2 *l2 = fi->userdata; struct sk_buff *skb = arg; @@ -1654,7 +1654,7 @@ l2_st14_persistant_da(struct FsmInst *fi, int event, void *arg) } static void -l2_st5_persistant_da(struct FsmInst *fi, int event, void *arg) +l2_st5_persistent_da(struct FsmInst *fi, int event, void *arg) { struct layer2 *l2 = fi->userdata; struct sk_buff *skb = arg; @@ -1671,7 +1671,7 @@ l2_st5_persistant_da(struct FsmInst *fi, int event, void *arg) } static void -l2_st6_persistant_da(struct FsmInst *fi, int event, void *arg) +l2_st6_persistent_da(struct FsmInst *fi, int event, void *arg) { struct layer2 *l2 = fi->userdata; struct sk_buff *skb = arg; @@ -1685,7 +1685,7 @@ l2_st6_persistant_da(struct FsmInst *fi, int event, void *arg) } static void -l2_persistant_da(struct FsmInst *fi, int event, void *arg) +l2_persistent_da(struct FsmInst *fi, int event, void *arg) { struct layer2 *l2 = fi->userdata; struct sk_buff *skb = arg; @@ -1829,14 +1829,14 @@ static struct FsmNode L2FnList[] = {ST_L2_6, EV_L2_FRAME_ERROR, l2_frame_error}, {ST_L2_7, EV_L2_FRAME_ERROR, l2_frame_error_reest}, {ST_L2_8, EV_L2_FRAME_ERROR, l2_frame_error_reest}, - {ST_L2_1, EV_L1_DEACTIVATE, l2_st14_persistant_da}, + {ST_L2_1, EV_L1_DEACTIVATE, l2_st14_persistent_da}, {ST_L2_2, EV_L1_DEACTIVATE, l2_st24_tei_remove}, {ST_L2_3, EV_L1_DEACTIVATE, l2_st3_tei_remove}, - {ST_L2_4, EV_L1_DEACTIVATE, l2_st14_persistant_da}, - {ST_L2_5, EV_L1_DEACTIVATE, l2_st5_persistant_da}, - {ST_L2_6, EV_L1_DEACTIVATE, l2_st6_persistant_da}, - {ST_L2_7, EV_L1_DEACTIVATE, l2_persistant_da}, - {ST_L2_8, EV_L1_DEACTIVATE, l2_persistant_da}, + {ST_L2_4, EV_L1_DEACTIVATE, l2_st14_persistent_da}, + {ST_L2_5, EV_L1_DEACTIVATE, l2_st5_persistent_da}, + {ST_L2_6, EV_L1_DEACTIVATE, l2_st6_persistent_da}, + {ST_L2_7, EV_L1_DEACTIVATE, l2_persistent_da}, + {ST_L2_8, EV_L1_DEACTIVATE, l2_persistent_da}, }; static int -- cgit v0.10.2 From 7f5c6d4f665bb57a19a34ce1fb16cc708c04f219 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Mon, 4 Apr 2011 17:04:03 +0200 Subject: netfilter: get rid of atomic ops in fast path We currently use a percpu spinlock to 'protect' rule bytes/packets counters, after various attempts to use RCU instead. Lately we added a seqlock so that get_counters() can run without blocking BH or 'writers'. But we really only need the seqcount in it. Spinlock itself is only locked by the current/owner cpu, so we can remove it completely. This cleanups api, using correct 'writer' vs 'reader' semantic. At replace time, the get_counters() call makes sure all cpus are done using the old table. Signed-off-by: Eric Dumazet Cc: Jan Engelhardt Signed-off-by: Patrick McHardy diff --git a/include/linux/netfilter/x_tables.h b/include/linux/netfilter/x_tables.h index 3721952..32cddf7 100644 --- a/include/linux/netfilter/x_tables.h +++ b/include/linux/netfilter/x_tables.h @@ -456,72 +456,60 @@ extern void xt_proto_fini(struct net *net, u_int8_t af); extern struct xt_table_info *xt_alloc_table_info(unsigned int size); extern void xt_free_table_info(struct xt_table_info *info); -/* - * Per-CPU spinlock associated with per-cpu table entries, and - * with a counter for the "reading" side that allows a recursive - * reader to avoid taking the lock and deadlocking. - * - * "reading" is used by ip/arp/ip6 tables rule processing which runs per-cpu. - * It needs to ensure that the rules are not being changed while the packet - * is being processed. In some cases, the read lock will be acquired - * twice on the same CPU; this is okay because of the count. - * - * "writing" is used when reading counters. - * During replace any readers that are using the old tables have to complete - * before freeing the old table. This is handled by the write locking - * necessary for reading the counters. +/** + * xt_recseq - recursive seqcount for netfilter use + * + * Packet processing changes the seqcount only if no recursion happened + * get_counters() can use read_seqcount_begin()/read_seqcount_retry(), + * because we use the normal seqcount convention : + * Low order bit set to 1 if a writer is active. */ -struct xt_info_lock { - seqlock_t lock; - unsigned char readers; -}; -DECLARE_PER_CPU(struct xt_info_lock, xt_info_locks); +DECLARE_PER_CPU(seqcount_t, xt_recseq); -/* - * Note: we need to ensure that preemption is disabled before acquiring - * the per-cpu-variable, so we do it as a two step process rather than - * using "spin_lock_bh()". - * - * We _also_ need to disable bottom half processing before updating our - * nesting count, to make sure that the only kind of re-entrancy is this - * code being called by itself: since the count+lock is not an atomic - * operation, we can allow no races. +/** + * xt_write_recseq_begin - start of a write section * - * _Only_ that special combination of being per-cpu and never getting - * re-entered asynchronously means that the count is safe. + * Begin packet processing : all readers must wait the end + * 1) Must be called with preemption disabled + * 2) softirqs must be disabled too (or we should use irqsafe_cpu_add()) + * Returns : + * 1 if no recursion on this cpu + * 0 if recursion detected */ -static inline void xt_info_rdlock_bh(void) +static inline unsigned int xt_write_recseq_begin(void) { - struct xt_info_lock *lock; + unsigned int addend; - local_bh_disable(); - lock = &__get_cpu_var(xt_info_locks); - if (likely(!lock->readers++)) - write_seqlock(&lock->lock); -} + /* + * Low order bit of sequence is set if we already + * called xt_write_recseq_begin(). + */ + addend = (__this_cpu_read(xt_recseq.sequence) + 1) & 1; -static inline void xt_info_rdunlock_bh(void) -{ - struct xt_info_lock *lock = &__get_cpu_var(xt_info_locks); + /* + * This is kind of a write_seqcount_begin(), but addend is 0 or 1 + * We dont check addend value to avoid a test and conditional jump, + * since addend is most likely 1 + */ + __this_cpu_add(xt_recseq.sequence, addend); + smp_wmb(); - if (likely(!--lock->readers)) - write_sequnlock(&lock->lock); - local_bh_enable(); + return addend; } -/* - * The "writer" side needs to get exclusive access to the lock, - * regardless of readers. This must be called with bottom half - * processing (and thus also preemption) disabled. +/** + * xt_write_recseq_end - end of a write section + * @addend: return value from previous xt_write_recseq_begin() + * + * End packet processing : all readers can proceed + * 1) Must be called with preemption disabled + * 2) softirqs must be disabled too (or we should use irqsafe_cpu_add()) */ -static inline void xt_info_wrlock(unsigned int cpu) -{ - write_seqlock(&per_cpu(xt_info_locks, cpu).lock); -} - -static inline void xt_info_wrunlock(unsigned int cpu) +static inline void xt_write_recseq_end(unsigned int addend) { - write_sequnlock(&per_cpu(xt_info_locks, cpu).lock); + /* this is kind of a write_seqcount_end(), but addend is 0 or 1 */ + smp_wmb(); + __this_cpu_add(xt_recseq.sequence, addend); } /* diff --git a/net/ipv4/netfilter/arp_tables.c b/net/ipv4/netfilter/arp_tables.c index 4b5d457..2ea7433 100644 --- a/net/ipv4/netfilter/arp_tables.c +++ b/net/ipv4/netfilter/arp_tables.c @@ -260,6 +260,7 @@ unsigned int arpt_do_table(struct sk_buff *skb, void *table_base; const struct xt_table_info *private; struct xt_action_param acpar; + unsigned int addend; if (!pskb_may_pull(skb, arp_hdr_len(skb->dev))) return NF_DROP; @@ -267,7 +268,8 @@ unsigned int arpt_do_table(struct sk_buff *skb, indev = in ? in->name : nulldevname; outdev = out ? out->name : nulldevname; - xt_info_rdlock_bh(); + local_bh_disable(); + addend = xt_write_recseq_begin(); private = table->private; table_base = private->entries[smp_processor_id()]; @@ -338,7 +340,8 @@ unsigned int arpt_do_table(struct sk_buff *skb, /* Verdict */ break; } while (!acpar.hotdrop); - xt_info_rdunlock_bh(); + xt_write_recseq_end(addend); + local_bh_enable(); if (acpar.hotdrop) return NF_DROP; @@ -712,7 +715,7 @@ static void get_counters(const struct xt_table_info *t, unsigned int i; for_each_possible_cpu(cpu) { - seqlock_t *lock = &per_cpu(xt_info_locks, cpu).lock; + seqcount_t *s = &per_cpu(xt_recseq, cpu); i = 0; xt_entry_foreach(iter, t->entries[cpu], t->size) { @@ -720,10 +723,10 @@ static void get_counters(const struct xt_table_info *t, unsigned int start; do { - start = read_seqbegin(lock); + start = read_seqcount_begin(s); bcnt = iter->counters.bcnt; pcnt = iter->counters.pcnt; - } while (read_seqretry(lock, start)); + } while (read_seqcount_retry(s, start)); ADD_COUNTER(counters[i], bcnt, pcnt); ++i; @@ -1115,6 +1118,7 @@ static int do_add_counters(struct net *net, const void __user *user, int ret = 0; void *loc_cpu_entry; struct arpt_entry *iter; + unsigned int addend; #ifdef CONFIG_COMPAT struct compat_xt_counters_info compat_tmp; @@ -1171,12 +1175,12 @@ static int do_add_counters(struct net *net, const void __user *user, /* Choose the copy that is on our node */ curcpu = smp_processor_id(); loc_cpu_entry = private->entries[curcpu]; - xt_info_wrlock(curcpu); + addend = xt_write_recseq_begin(); xt_entry_foreach(iter, loc_cpu_entry, private->size) { ADD_COUNTER(iter->counters, paddc[i].bcnt, paddc[i].pcnt); ++i; } - xt_info_wrunlock(curcpu); + xt_write_recseq_end(addend); unlock_up_free: local_bh_enable(); xt_table_unlock(t); diff --git a/net/ipv4/netfilter/ip_tables.c b/net/ipv4/netfilter/ip_tables.c index ffcea0d..2b6b700 100644 --- a/net/ipv4/netfilter/ip_tables.c +++ b/net/ipv4/netfilter/ip_tables.c @@ -68,15 +68,6 @@ void *ipt_alloc_initial_table(const struct xt_table *info) } EXPORT_SYMBOL_GPL(ipt_alloc_initial_table); -/* - We keep a set of rules for each CPU, so we can avoid write-locking - them in the softirq when updating the counters and therefore - only need to read-lock in the softirq; doing a write_lock_bh() in user - context stops packets coming through and allows user context to read - the counters or update the rules. - - Hence the start of any table is given by get_table() below. */ - /* Returns whether matches rule or not. */ /* Performance critical - called for every packet */ static inline bool @@ -311,6 +302,7 @@ ipt_do_table(struct sk_buff *skb, unsigned int *stackptr, origptr, cpu; const struct xt_table_info *private; struct xt_action_param acpar; + unsigned int addend; /* Initialization */ ip = ip_hdr(skb); @@ -331,7 +323,8 @@ ipt_do_table(struct sk_buff *skb, acpar.hooknum = hook; IP_NF_ASSERT(table->valid_hooks & (1 << hook)); - xt_info_rdlock_bh(); + local_bh_disable(); + addend = xt_write_recseq_begin(); private = table->private; cpu = smp_processor_id(); table_base = private->entries[cpu]; @@ -430,7 +423,9 @@ ipt_do_table(struct sk_buff *skb, pr_debug("Exiting %s; resetting sp from %u to %u\n", __func__, *stackptr, origptr); *stackptr = origptr; - xt_info_rdunlock_bh(); + xt_write_recseq_end(addend); + local_bh_enable(); + #ifdef DEBUG_ALLOW_ALL return NF_ACCEPT; #else @@ -886,7 +881,7 @@ get_counters(const struct xt_table_info *t, unsigned int i; for_each_possible_cpu(cpu) { - seqlock_t *lock = &per_cpu(xt_info_locks, cpu).lock; + seqcount_t *s = &per_cpu(xt_recseq, cpu); i = 0; xt_entry_foreach(iter, t->entries[cpu], t->size) { @@ -894,10 +889,10 @@ get_counters(const struct xt_table_info *t, unsigned int start; do { - start = read_seqbegin(lock); + start = read_seqcount_begin(s); bcnt = iter->counters.bcnt; pcnt = iter->counters.pcnt; - } while (read_seqretry(lock, start)); + } while (read_seqcount_retry(s, start)); ADD_COUNTER(counters[i], bcnt, pcnt); ++i; /* macro does multi eval of i */ @@ -1312,6 +1307,7 @@ do_add_counters(struct net *net, const void __user *user, int ret = 0; void *loc_cpu_entry; struct ipt_entry *iter; + unsigned int addend; #ifdef CONFIG_COMPAT struct compat_xt_counters_info compat_tmp; @@ -1368,12 +1364,12 @@ do_add_counters(struct net *net, const void __user *user, /* Choose the copy that is on our node */ curcpu = smp_processor_id(); loc_cpu_entry = private->entries[curcpu]; - xt_info_wrlock(curcpu); + addend = xt_write_recseq_begin(); xt_entry_foreach(iter, loc_cpu_entry, private->size) { ADD_COUNTER(iter->counters, paddc[i].bcnt, paddc[i].pcnt); ++i; } - xt_info_wrunlock(curcpu); + xt_write_recseq_end(addend); unlock_up_free: local_bh_enable(); xt_table_unlock(t); diff --git a/net/ipv6/netfilter/ip6_tables.c b/net/ipv6/netfilter/ip6_tables.c index 0b2af9b..ec7cf57 100644 --- a/net/ipv6/netfilter/ip6_tables.c +++ b/net/ipv6/netfilter/ip6_tables.c @@ -340,6 +340,7 @@ ip6t_do_table(struct sk_buff *skb, unsigned int *stackptr, origptr, cpu; const struct xt_table_info *private; struct xt_action_param acpar; + unsigned int addend; /* Initialization */ indev = in ? in->name : nulldevname; @@ -358,7 +359,8 @@ ip6t_do_table(struct sk_buff *skb, IP_NF_ASSERT(table->valid_hooks & (1 << hook)); - xt_info_rdlock_bh(); + local_bh_disable(); + addend = xt_write_recseq_begin(); private = table->private; cpu = smp_processor_id(); table_base = private->entries[cpu]; @@ -442,7 +444,9 @@ ip6t_do_table(struct sk_buff *skb, } while (!acpar.hotdrop); *stackptr = origptr; - xt_info_rdunlock_bh(); + + xt_write_recseq_end(addend); + local_bh_enable(); #ifdef DEBUG_ALLOW_ALL return NF_ACCEPT; @@ -899,7 +903,7 @@ get_counters(const struct xt_table_info *t, unsigned int i; for_each_possible_cpu(cpu) { - seqlock_t *lock = &per_cpu(xt_info_locks, cpu).lock; + seqcount_t *s = &per_cpu(xt_recseq, cpu); i = 0; xt_entry_foreach(iter, t->entries[cpu], t->size) { @@ -907,10 +911,10 @@ get_counters(const struct xt_table_info *t, unsigned int start; do { - start = read_seqbegin(lock); + start = read_seqcount_begin(s); bcnt = iter->counters.bcnt; pcnt = iter->counters.pcnt; - } while (read_seqretry(lock, start)); + } while (read_seqcount_retry(s, start)); ADD_COUNTER(counters[i], bcnt, pcnt); ++i; @@ -1325,6 +1329,7 @@ do_add_counters(struct net *net, const void __user *user, unsigned int len, int ret = 0; const void *loc_cpu_entry; struct ip6t_entry *iter; + unsigned int addend; #ifdef CONFIG_COMPAT struct compat_xt_counters_info compat_tmp; @@ -1381,13 +1386,13 @@ do_add_counters(struct net *net, const void __user *user, unsigned int len, i = 0; /* Choose the copy that is on our node */ curcpu = smp_processor_id(); - xt_info_wrlock(curcpu); + addend = xt_write_recseq_begin(); loc_cpu_entry = private->entries[curcpu]; xt_entry_foreach(iter, loc_cpu_entry, private->size) { ADD_COUNTER(iter->counters, paddc[i].bcnt, paddc[i].pcnt); ++i; } - xt_info_wrunlock(curcpu); + xt_write_recseq_end(addend); unlock_up_free: local_bh_enable(); diff --git a/net/netfilter/x_tables.c b/net/netfilter/x_tables.c index a9adf4c..52959ef 100644 --- a/net/netfilter/x_tables.c +++ b/net/netfilter/x_tables.c @@ -762,8 +762,8 @@ void xt_compat_unlock(u_int8_t af) EXPORT_SYMBOL_GPL(xt_compat_unlock); #endif -DEFINE_PER_CPU(struct xt_info_lock, xt_info_locks); -EXPORT_PER_CPU_SYMBOL_GPL(xt_info_locks); +DEFINE_PER_CPU(seqcount_t, xt_recseq); +EXPORT_PER_CPU_SYMBOL_GPL(xt_recseq); static int xt_jumpstack_alloc(struct xt_table_info *i) { @@ -1362,10 +1362,7 @@ static int __init xt_init(void) int rv; for_each_possible_cpu(i) { - struct xt_info_lock *lock = &per_cpu(xt_info_locks, i); - - seqlock_init(&lock->lock); - lock->readers = 0; + seqcount_init(&per_cpu(xt_recseq, i)); } xt = kmalloc(sizeof(struct xt_af) * NFPROTO_NUMPROTO, GFP_KERNEL); -- cgit v0.10.2 From 64d21fc194e12bdf7347019bf10325a4b3d77e7b Mon Sep 17 00:00:00 2001 From: Rakib Mullick Date: Sat, 2 Apr 2011 13:17:48 +0600 Subject: x86, mpparse: Put check_slot() into .init section check_slot() is only called from replace_intsrc_all() - which is in the .init section. So, put check_slot into the .init section as well, so it can be freed after system boot. Signed-off-by: Rakib Mullick LKML-Reference: Signed-off-by: Ingo Molnar diff --git a/arch/x86/kernel/mpparse.c b/arch/x86/kernel/mpparse.c index 5a532ce..f1b2718 100644 --- a/arch/x86/kernel/mpparse.c +++ b/arch/x86/kernel/mpparse.c @@ -715,7 +715,7 @@ static void __init check_irq_src(struct mpc_intsrc *m, int *nr_m_spare) } } -static int +static int __init check_slot(unsigned long mpc_new_phys, unsigned long mpc_new_length, int count) { int ret = 0; -- cgit v0.10.2 From 0588fa30db44fd2d4032b36a061c87478a43fbee Mon Sep 17 00:00:00 2001 From: Steven Rostedt Date: Mon, 21 Mar 2011 22:59:21 -0400 Subject: tracing: Convert trace_printk() formats for module to const char * The trace_printk() formats for modules do not show up in the debugfs/tracing/printk_formats file. Only the formats that are for trace_printk()s that are in the kernel core. To facilitate the change to add trace_printk() formats from modules into that file as well, we need to convert the structure that holds the formats from char fmt[], into const char *fmt, and allocate them separately. Signed-off-by: Steven Rostedt diff --git a/kernel/trace/trace_printk.c b/kernel/trace/trace_printk.c index 2547d88..b8b2681 100644 --- a/kernel/trace/trace_printk.c +++ b/kernel/trace/trace_printk.c @@ -32,7 +32,7 @@ static DEFINE_MUTEX(btrace_mutex); struct trace_bprintk_fmt { struct list_head list; - char fmt[0]; + const char *fmt; }; static inline struct trace_bprintk_fmt *lookup_format(const char *fmt) @@ -49,6 +49,7 @@ static void hold_module_trace_bprintk_format(const char **start, const char **end) { const char **iter; + char *fmt; mutex_lock(&btrace_mutex); for (iter = start; iter < end; iter++) { @@ -58,14 +59,18 @@ void hold_module_trace_bprintk_format(const char **start, const char **end) continue; } - tb_fmt = kmalloc(offsetof(struct trace_bprintk_fmt, fmt) - + strlen(*iter) + 1, GFP_KERNEL); - if (tb_fmt) { + tb_fmt = kmalloc(sizeof(*tb_fmt), GFP_KERNEL); + if (tb_fmt) + fmt = kmalloc(strlen(*iter) + 1, GFP_KERNEL); + if (tb_fmt && fmt) { list_add_tail(&tb_fmt->list, &trace_bprintk_fmt_list); - strcpy(tb_fmt->fmt, *iter); + strcpy(fmt, *iter); + tb_fmt->fmt = fmt; *iter = tb_fmt->fmt; - } else + } else { + kfree(tb_fmt); *iter = NULL; + } } mutex_unlock(&btrace_mutex); } -- cgit v0.10.2 From 1813dc3776c22ad4b0294a6df8434b9a02c98109 Mon Sep 17 00:00:00 2001 From: Steven Rostedt Date: Mon, 21 Mar 2011 23:36:31 -0400 Subject: tracing: Print trace_bprintk() formats for modules too The file debugfs/tracing/printk_formats maps the addresses to the formats that are used by trace_bprintk() so that userspace tools can read the buffer and be able to decode trace_bprintk events to get the format saved when reading the ring buffer directly. This is because trace_bprintk() does not store the format into the buffer, but just the address of the format, which is hidden in the kernel memory. But currently it only exports trace_bprintk()s from the kernel core and not for modules. The modules need their formats exported as well. Signed-off-by: Steven Rostedt diff --git a/kernel/trace/trace_printk.c b/kernel/trace/trace_printk.c index b8b2681..dff763b 100644 --- a/kernel/trace/trace_printk.c +++ b/kernel/trace/trace_printk.c @@ -89,6 +89,76 @@ static int module_trace_bprintk_format_notify(struct notifier_block *self, return 0; } +/* + * The debugfs/tracing/printk_formats file maps the addresses with + * the ASCII formats that are used in the bprintk events in the + * buffer. For userspace tools to be able to decode the events from + * the buffer, they need to be able to map the address with the format. + * + * The addresses of the bprintk formats are in their own section + * __trace_printk_fmt. But for modules we copy them into a link list. + * The code to print the formats and their addresses passes around the + * address of the fmt string. If the fmt address passed into the seq + * functions is within the kernel core __trace_printk_fmt section, then + * it simply uses the next pointer in the list. + * + * When the fmt pointer is outside the kernel core __trace_printk_fmt + * section, then we need to read the link list pointers. The trick is + * we pass the address of the string to the seq function just like + * we do for the kernel core formats. To get back the structure that + * holds the format, we simply use containerof() and then go to the + * next format in the list. + */ +static const char ** +find_next_mod_format(int start_index, void *v, const char **fmt, loff_t *pos) +{ + struct trace_bprintk_fmt *mod_fmt; + + if (list_empty(&trace_bprintk_fmt_list)) + return NULL; + + /* + * v will point to the address of the fmt record from t_next + * v will be NULL from t_start. + * If this is the first pointer or called from start + * then we need to walk the list. + */ + if (!v || start_index == *pos) { + struct trace_bprintk_fmt *p; + + /* search the module list */ + list_for_each_entry(p, &trace_bprintk_fmt_list, list) { + if (start_index == *pos) + return &p->fmt; + start_index++; + } + /* pos > index */ + return NULL; + } + + /* + * v points to the address of the fmt field in the mod list + * structure that holds the module print format. + */ + mod_fmt = container_of(v, typeof(*mod_fmt), fmt); + if (mod_fmt->list.next == &trace_bprintk_fmt_list) + return NULL; + + mod_fmt = container_of(mod_fmt->list.next, typeof(*mod_fmt), list); + + return &mod_fmt->fmt; +} + +static void format_mod_start(void) +{ + mutex_lock(&btrace_mutex); +} + +static void format_mod_stop(void) +{ + mutex_unlock(&btrace_mutex); +} + #else /* !CONFIG_MODULES */ __init static int module_trace_bprintk_format_notify(struct notifier_block *self, @@ -96,6 +166,13 @@ module_trace_bprintk_format_notify(struct notifier_block *self, { return 0; } +static inline const char ** +find_next_mod_format(int start_index, void *v, const char **fmt, loff_t *pos) +{ + return NULL; +} +static inline void format_mod_start(void) { } +static inline void format_mod_stop(void) { } #endif /* CONFIG_MODULES */ @@ -158,20 +235,33 @@ int __ftrace_vprintk(unsigned long ip, const char *fmt, va_list ap) } EXPORT_SYMBOL_GPL(__ftrace_vprintk); +static const char **find_next(void *v, loff_t *pos) +{ + const char **fmt = v; + int start_index; + + if (!fmt) + fmt = __start___trace_bprintk_fmt + *pos; + + start_index = __stop___trace_bprintk_fmt - __start___trace_bprintk_fmt; + + if (*pos < start_index) + return fmt; + + return find_next_mod_format(start_index, v, fmt, pos); +} + static void * t_start(struct seq_file *m, loff_t *pos) { - const char **fmt = __start___trace_bprintk_fmt + *pos; - - if ((unsigned long)fmt >= (unsigned long)__stop___trace_bprintk_fmt) - return NULL; - return fmt; + format_mod_start(); + return find_next(NULL, pos); } static void *t_next(struct seq_file *m, void * v, loff_t *pos) { (*pos)++; - return t_start(m, pos); + return find_next(v, pos); } static int t_show(struct seq_file *m, void *v) @@ -210,6 +300,7 @@ static int t_show(struct seq_file *m, void *v) static void t_stop(struct seq_file *m, void *p) { + format_mod_stop(); } static const struct seq_operations show_format_seq_ops = { -- cgit v0.10.2 From ee5e51f51be755830f57445e268ba50e88ccbdbb Mon Sep 17 00:00:00 2001 From: Jiri Olsa Date: Fri, 25 Mar 2011 12:05:18 +0100 Subject: tracing: Avoid soft lockup in trace_pipe running following commands: # enable the binary option echo 1 > ./options/bin # disable context info option echo 0 > ./options/context-info # tracing only events echo 1 > ./events/enable cat trace_pipe plus forcing system to generate many tracing events, is causing lockup (in NON preemptive kernels) inside tracing_read_pipe function. The issue is also easily reproduced by running ltp stress test. (ftrace_stress_test.sh) The reasons are: - bin/hex/raw output functions for events are set to trace_nop_print function, which prints nothing and returns TRACE_TYPE_HANDLED value - LOST EVENT trace do not handle trace_seq overflow These reasons force the while loop in tracing_read_pipe function never to break. The attached patch fixies handling of lost event trace, and changes trace_nop_print to print minimal info, which is needed for the correct tracing_read_pipe processing. v2 changes: - omit the cond_resched changes by trace_nop_print changes - WARN changed to WARN_ONCE and added info to be able to find out the culprit v3 changes: - make more accurate patch comment Signed-off-by: Jiri Olsa LKML-Reference: <20110325110518.GC1922@jolsa.brq.redhat.com> Signed-off-by: Steven Rostedt diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c index 9541c27..5af42f4 100644 --- a/kernel/trace/trace.c +++ b/kernel/trace/trace.c @@ -2013,9 +2013,10 @@ enum print_line_t print_trace_line(struct trace_iterator *iter) { enum print_line_t ret; - if (iter->lost_events) - trace_seq_printf(&iter->seq, "CPU:%d [LOST %lu EVENTS]\n", - iter->cpu, iter->lost_events); + if (iter->lost_events && + !trace_seq_printf(&iter->seq, "CPU:%d [LOST %lu EVENTS]\n", + iter->cpu, iter->lost_events)) + return TRACE_TYPE_PARTIAL_LINE; if (iter->trace && iter->trace->print_line) { ret = iter->trace->print_line(iter); @@ -3229,6 +3230,14 @@ waitagain: if (iter->seq.len >= cnt) break; + + /* + * Setting the full flag means we reached the trace_seq buffer + * size and we should leave by partial output condition above. + * One of the trace_seq_* functions is not used properly. + */ + WARN_ONCE(iter->seq.full, "full flag set for trace type %d", + iter->ent->type); } trace_access_unlock(iter->cpu_file); trace_event_read_unlock(); diff --git a/kernel/trace/trace_output.c b/kernel/trace/trace_output.c index 456be90..cf535cc 100644 --- a/kernel/trace/trace_output.c +++ b/kernel/trace/trace_output.c @@ -830,6 +830,9 @@ EXPORT_SYMBOL_GPL(unregister_ftrace_event); enum print_line_t trace_nop_print(struct trace_iterator *iter, int flags, struct trace_event *event) { + if (!trace_seq_printf(&iter->seq, "type: %d\n", iter->ent->type)) + return TRACE_TYPE_PARTIAL_LINE; + return TRACE_TYPE_HANDLED; } -- cgit v0.10.2 From d430d3d7e646eb1eac2bb4aa244a644312e67c76 Mon Sep 17 00:00:00 2001 From: Jason Baron Date: Wed, 16 Mar 2011 17:29:47 -0400 Subject: jump label: Introduce static_branch() interface Introduce: static __always_inline bool static_branch(struct jump_label_key *key); instead of the old JUMP_LABEL(key, label) macro. In this way, jump labels become really easy to use: Define: struct jump_label_key jump_key; Can be used as: if (static_branch(&jump_key)) do unlikely code enable/disale via: jump_label_inc(&jump_key); jump_label_dec(&jump_key); that's it! For the jump labels disabled case, the static_branch() becomes an atomic_read(), and jump_label_inc()/dec() are simply atomic_inc(), atomic_dec() operations. We show testing results for this change below. Thanks to H. Peter Anvin for suggesting the 'static_branch()' construct. Since we now require a 'struct jump_label_key *key', we can store a pointer into the jump table addresses. In this way, we can enable/disable jump labels, in basically constant time. This change allows us to completely remove the previous hashtable scheme. Thanks to Peter Zijlstra for this re-write. Testing: I ran a series of 'tbench 20' runs 5 times (with reboots) for 3 configurations, where tracepoints were disabled. jump label configured in avg: 815.6 jump label *not* configured in (using atomic reads) avg: 800.1 jump label *not* configured in (regular reads) avg: 803.4 Signed-off-by: Peter Zijlstra LKML-Reference: <20110316212947.GA8792@redhat.com> Signed-off-by: Jason Baron Suggested-by: H. Peter Anvin Tested-by: David Daney Acked-by: Ralf Baechle Acked-by: David S. Miller Acked-by: Mathieu Desnoyers Signed-off-by: Steven Rostedt diff --git a/arch/mips/include/asm/jump_label.h b/arch/mips/include/asm/jump_label.h index 7622ccf..1881b31 100644 --- a/arch/mips/include/asm/jump_label.h +++ b/arch/mips/include/asm/jump_label.h @@ -20,16 +20,18 @@ #define WORD_INSN ".word" #endif -#define JUMP_LABEL(key, label) \ - do { \ - asm goto("1:\tnop\n\t" \ - "nop\n\t" \ - ".pushsection __jump_table, \"a\"\n\t" \ - WORD_INSN " 1b, %l[" #label "], %0\n\t" \ - ".popsection\n\t" \ - : : "i" (key) : : label); \ - } while (0) - +static __always_inline bool arch_static_branch(struct jump_label_key *key) +{ + asm goto("1:\tnop\n\t" + "nop\n\t" + ".pushsection __jump_table, \"aw\"\n\t" + WORD_INSN " 1b, %l[l_yes], %0\n\t" + ".popsection\n\t" + : : "i" (key) : : l_yes); + return false; +l_yes: + return true; +} #endif /* __KERNEL__ */ diff --git a/arch/sparc/include/asm/jump_label.h b/arch/sparc/include/asm/jump_label.h index 427d468..fc73a82 100644 --- a/arch/sparc/include/asm/jump_label.h +++ b/arch/sparc/include/asm/jump_label.h @@ -7,17 +7,20 @@ #define JUMP_LABEL_NOP_SIZE 4 -#define JUMP_LABEL(key, label) \ - do { \ - asm goto("1:\n\t" \ - "nop\n\t" \ - "nop\n\t" \ - ".pushsection __jump_table, \"a\"\n\t"\ - ".align 4\n\t" \ - ".word 1b, %l[" #label "], %c0\n\t" \ - ".popsection \n\t" \ - : : "i" (key) : : label);\ - } while (0) +static __always_inline bool arch_static_branch(struct jump_label_key *key) +{ + asm goto("1:\n\t" + "nop\n\t" + "nop\n\t" + ".pushsection __jump_table, \"aw\"\n\t" + ".align 4\n\t" + ".word 1b, %l[l_yes], %c0\n\t" + ".popsection \n\t" + : : "i" (key) : : l_yes); + return false; +l_yes: + return true; +} #endif /* __KERNEL__ */ diff --git a/arch/x86/include/asm/alternative.h b/arch/x86/include/asm/alternative.h index 13009d1..8cdd1e2 100644 --- a/arch/x86/include/asm/alternative.h +++ b/arch/x86/include/asm/alternative.h @@ -4,7 +4,6 @@ #include #include #include -#include #include /* @@ -191,7 +190,7 @@ extern void *text_poke(void *addr, const void *opcode, size_t len); extern void *text_poke_smp(void *addr, const void *opcode, size_t len); extern void text_poke_smp_batch(struct text_poke_param *params, int n); -#if defined(CONFIG_DYNAMIC_FTRACE) || defined(HAVE_JUMP_LABEL) +#if defined(CONFIG_DYNAMIC_FTRACE) || defined(CONFIG_JUMP_LABEL) #define IDEAL_NOP_SIZE_5 5 extern unsigned char ideal_nop5[IDEAL_NOP_SIZE_5]; extern void arch_init_ideal_nop5(void); diff --git a/arch/x86/include/asm/jump_label.h b/arch/x86/include/asm/jump_label.h index 574dbc2..f217cee 100644 --- a/arch/x86/include/asm/jump_label.h +++ b/arch/x86/include/asm/jump_label.h @@ -5,20 +5,24 @@ #include #include +#include #define JUMP_LABEL_NOP_SIZE 5 -# define JUMP_LABEL_INITIAL_NOP ".byte 0xe9 \n\t .long 0\n\t" - -# define JUMP_LABEL(key, label) \ - do { \ - asm goto("1:" \ - JUMP_LABEL_INITIAL_NOP \ - ".pushsection __jump_table, \"aw\" \n\t"\ - _ASM_PTR "1b, %l[" #label "], %c0 \n\t" \ - ".popsection \n\t" \ - : : "i" (key) : : label); \ - } while (0) +#define JUMP_LABEL_INITIAL_NOP ".byte 0xe9 \n\t .long 0\n\t" + +static __always_inline bool arch_static_branch(struct jump_label_key *key) +{ + asm goto("1:" + JUMP_LABEL_INITIAL_NOP + ".pushsection __jump_table, \"aw\" \n\t" + _ASM_PTR "1b, %l[l_yes], %c0 \n\t" + ".popsection \n\t" + : : "i" (key) : : l_yes); + return false; +l_yes: + return true; +} #endif /* __KERNEL__ */ diff --git a/arch/x86/kernel/alternative.c b/arch/x86/kernel/alternative.c index 4a23467..651454b 100644 --- a/arch/x86/kernel/alternative.c +++ b/arch/x86/kernel/alternative.c @@ -679,7 +679,7 @@ void __kprobes text_poke_smp_batch(struct text_poke_param *params, int n) __stop_machine(stop_machine_text_poke, (void *)&tpp, NULL); } -#if defined(CONFIG_DYNAMIC_FTRACE) || defined(HAVE_JUMP_LABEL) +#if defined(CONFIG_DYNAMIC_FTRACE) || defined(CONFIG_JUMP_LABEL) #ifdef CONFIG_X86_64 unsigned char ideal_nop5[5] = { 0x66, 0x66, 0x66, 0x66, 0x90 }; diff --git a/arch/x86/kernel/module.c b/arch/x86/kernel/module.c index ab23f1a..52f256f 100644 --- a/arch/x86/kernel/module.c +++ b/arch/x86/kernel/module.c @@ -24,6 +24,7 @@ #include #include #include +#include #include #include diff --git a/include/asm-generic/vmlinux.lds.h b/include/asm-generic/vmlinux.lds.h index 32c45e5..7952216 100644 --- a/include/asm-generic/vmlinux.lds.h +++ b/include/asm-generic/vmlinux.lds.h @@ -170,6 +170,10 @@ STRUCT_ALIGN(); \ *(__tracepoints) \ /* implement dynamic printk debug */ \ + . = ALIGN(8); \ + VMLINUX_SYMBOL(__start___jump_table) = .; \ + *(__jump_table) \ + VMLINUX_SYMBOL(__stop___jump_table) = .; \ . = ALIGN(8); \ VMLINUX_SYMBOL(__start___verbose) = .; \ *(__verbose) \ @@ -228,8 +232,6 @@ \ BUG_TABLE \ \ - JUMP_TABLE \ - \ /* PCI quirks */ \ .pci_fixup : AT(ADDR(.pci_fixup) - LOAD_OFFSET) { \ VMLINUX_SYMBOL(__start_pci_fixups_early) = .; \ @@ -589,14 +591,6 @@ #define BUG_TABLE #endif -#define JUMP_TABLE \ - . = ALIGN(8); \ - __jump_table : AT(ADDR(__jump_table) - LOAD_OFFSET) { \ - VMLINUX_SYMBOL(__start___jump_table) = .; \ - *(__jump_table) \ - VMLINUX_SYMBOL(__stop___jump_table) = .; \ - } - #ifdef CONFIG_PM_TRACE #define TRACEDATA \ . = ALIGN(4); \ diff --git a/include/linux/dynamic_debug.h b/include/linux/dynamic_debug.h index 0c9653f..e747ecd 100644 --- a/include/linux/dynamic_debug.h +++ b/include/linux/dynamic_debug.h @@ -1,8 +1,6 @@ #ifndef _DYNAMIC_DEBUG_H #define _DYNAMIC_DEBUG_H -#include - /* dynamic_printk_enabled, and dynamic_printk_enabled2 are bitmasks in which * bit n is set to 1 if any modname hashes into the bucket n, 0 otherwise. They * use independent hash functions, to reduce the chance of false positives. diff --git a/include/linux/jump_label.h b/include/linux/jump_label.h index 7880f18..83e745f 100644 --- a/include/linux/jump_label.h +++ b/include/linux/jump_label.h @@ -1,20 +1,43 @@ #ifndef _LINUX_JUMP_LABEL_H #define _LINUX_JUMP_LABEL_H +#include +#include + #if defined(CC_HAVE_ASM_GOTO) && defined(CONFIG_JUMP_LABEL) + +struct jump_label_key { + atomic_t enabled; + struct jump_entry *entries; +#ifdef CONFIG_MODULES + struct jump_label_mod *next; +#endif +}; + # include # define HAVE_JUMP_LABEL #endif enum jump_label_type { + JUMP_LABEL_DISABLE = 0, JUMP_LABEL_ENABLE, - JUMP_LABEL_DISABLE }; struct module; #ifdef HAVE_JUMP_LABEL +#ifdef CONFIG_MODULES +#define JUMP_LABEL_INIT {{ 0 }, NULL, NULL} +#else +#define JUMP_LABEL_INIT {{ 0 }, NULL} +#endif + +static __always_inline bool static_branch(struct jump_label_key *key) +{ + return arch_static_branch(key); +} + extern struct jump_entry __start___jump_table[]; extern struct jump_entry __stop___jump_table[]; @@ -23,37 +46,37 @@ extern void jump_label_unlock(void); extern void arch_jump_label_transform(struct jump_entry *entry, enum jump_label_type type); extern void arch_jump_label_text_poke_early(jump_label_t addr); -extern void jump_label_update(unsigned long key, enum jump_label_type type); -extern void jump_label_apply_nops(struct module *mod); extern int jump_label_text_reserved(void *start, void *end); +extern void jump_label_inc(struct jump_label_key *key); +extern void jump_label_dec(struct jump_label_key *key); +extern bool jump_label_enabled(struct jump_label_key *key); +extern void jump_label_apply_nops(struct module *mod); -#define jump_label_enable(key) \ - jump_label_update((unsigned long)key, JUMP_LABEL_ENABLE); +#else -#define jump_label_disable(key) \ - jump_label_update((unsigned long)key, JUMP_LABEL_DISABLE); +#include -#else +#define JUMP_LABEL_INIT {ATOMIC_INIT(0)} -#define JUMP_LABEL(key, label) \ -do { \ - if (unlikely(*key)) \ - goto label; \ -} while (0) +struct jump_label_key { + atomic_t enabled; +}; -#define jump_label_enable(cond_var) \ -do { \ - *(cond_var) = 1; \ -} while (0) +static __always_inline bool static_branch(struct jump_label_key *key) +{ + if (unlikely(atomic_read(&key->enabled))) + return true; + return false; +} -#define jump_label_disable(cond_var) \ -do { \ - *(cond_var) = 0; \ -} while (0) +static inline void jump_label_inc(struct jump_label_key *key) +{ + atomic_inc(&key->enabled); +} -static inline int jump_label_apply_nops(struct module *mod) +static inline void jump_label_dec(struct jump_label_key *key) { - return 0; + atomic_dec(&key->enabled); } static inline int jump_label_text_reserved(void *start, void *end) @@ -64,16 +87,16 @@ static inline int jump_label_text_reserved(void *start, void *end) static inline void jump_label_lock(void) {} static inline void jump_label_unlock(void) {} -#endif +static inline bool jump_label_enabled(struct jump_label_key *key) +{ + return !!atomic_read(&key->enabled); +} -#define COND_STMT(key, stmt) \ -do { \ - __label__ jl_enabled; \ - JUMP_LABEL(key, jl_enabled); \ - if (0) { \ -jl_enabled: \ - stmt; \ - } \ -} while (0) +static inline int jump_label_apply_nops(struct module *mod) +{ + return 0; +} + +#endif #endif diff --git a/include/linux/jump_label_ref.h b/include/linux/jump_label_ref.h deleted file mode 100644 index e5d012a..0000000 --- a/include/linux/jump_label_ref.h +++ /dev/null @@ -1,44 +0,0 @@ -#ifndef _LINUX_JUMP_LABEL_REF_H -#define _LINUX_JUMP_LABEL_REF_H - -#include -#include - -#ifdef HAVE_JUMP_LABEL - -static inline void jump_label_inc(atomic_t *key) -{ - if (atomic_add_return(1, key) == 1) - jump_label_enable(key); -} - -static inline void jump_label_dec(atomic_t *key) -{ - if (atomic_dec_and_test(key)) - jump_label_disable(key); -} - -#else /* !HAVE_JUMP_LABEL */ - -static inline void jump_label_inc(atomic_t *key) -{ - atomic_inc(key); -} - -static inline void jump_label_dec(atomic_t *key) -{ - atomic_dec(key); -} - -#undef JUMP_LABEL -#define JUMP_LABEL(key, label) \ -do { \ - if (unlikely(__builtin_choose_expr( \ - __builtin_types_compatible_p(typeof(key), atomic_t *), \ - atomic_read((atomic_t *)(key)), *(key)))) \ - goto label; \ -} while (0) - -#endif /* HAVE_JUMP_LABEL */ - -#endif /* _LINUX_JUMP_LABEL_REF_H */ diff --git a/include/linux/perf_event.h b/include/linux/perf_event.h index 311b4dc..730b782 100644 --- a/include/linux/perf_event.h +++ b/include/linux/perf_event.h @@ -505,7 +505,7 @@ struct perf_guest_info_callbacks { #include #include #include -#include +#include #include #include @@ -1034,7 +1034,7 @@ static inline int is_software_event(struct perf_event *event) return event->pmu->task_ctx_nr == perf_sw_context; } -extern atomic_t perf_swevent_enabled[PERF_COUNT_SW_MAX]; +extern struct jump_label_key perf_swevent_enabled[PERF_COUNT_SW_MAX]; extern void __perf_sw_event(u32, u64, int, struct pt_regs *, u64); @@ -1063,22 +1063,21 @@ perf_sw_event(u32 event_id, u64 nr, int nmi, struct pt_regs *regs, u64 addr) { struct pt_regs hot_regs; - JUMP_LABEL(&perf_swevent_enabled[event_id], have_event); - return; - -have_event: - if (!regs) { - perf_fetch_caller_regs(&hot_regs); - regs = &hot_regs; + if (static_branch(&perf_swevent_enabled[event_id])) { + if (!regs) { + perf_fetch_caller_regs(&hot_regs); + regs = &hot_regs; + } + __perf_sw_event(event_id, nr, nmi, regs, addr); } - __perf_sw_event(event_id, nr, nmi, regs, addr); } -extern atomic_t perf_sched_events; +extern struct jump_label_key perf_sched_events; static inline void perf_event_task_sched_in(struct task_struct *task) { - COND_STMT(&perf_sched_events, __perf_event_task_sched_in(task)); + if (static_branch(&perf_sched_events)) + __perf_event_task_sched_in(task); } static inline @@ -1086,7 +1085,8 @@ void perf_event_task_sched_out(struct task_struct *task, struct task_struct *nex { perf_sw_event(PERF_COUNT_SW_CONTEXT_SWITCHES, 1, 1, NULL, 0); - COND_STMT(&perf_sched_events, __perf_event_task_sched_out(task, next)); + if (static_branch(&perf_sched_events)) + __perf_event_task_sched_out(task, next); } extern void perf_event_mmap(struct vm_area_struct *vma); diff --git a/include/linux/tracepoint.h b/include/linux/tracepoint.h index 97c84a5..d530a44 100644 --- a/include/linux/tracepoint.h +++ b/include/linux/tracepoint.h @@ -29,7 +29,7 @@ struct tracepoint_func { struct tracepoint { const char *name; /* Tracepoint name */ - int state; /* State. */ + struct jump_label_key key; void (*regfunc)(void); void (*unregfunc)(void); struct tracepoint_func __rcu *funcs; @@ -146,9 +146,7 @@ void tracepoint_update_probe_range(struct tracepoint * const *begin, extern struct tracepoint __tracepoint_##name; \ static inline void trace_##name(proto) \ { \ - JUMP_LABEL(&__tracepoint_##name.state, do_trace); \ - return; \ -do_trace: \ + if (static_branch(&__tracepoint_##name.key)) \ __DO_TRACE(&__tracepoint_##name, \ TP_PROTO(data_proto), \ TP_ARGS(data_args), \ @@ -176,14 +174,14 @@ do_trace: \ * structures, so we create an array of pointers that will be used for iteration * on the tracepoints. */ -#define DEFINE_TRACE_FN(name, reg, unreg) \ - static const char __tpstrtab_##name[] \ - __attribute__((section("__tracepoints_strings"))) = #name; \ - struct tracepoint __tracepoint_##name \ - __attribute__((section("__tracepoints"))) = \ - { __tpstrtab_##name, 0, reg, unreg, NULL }; \ - static struct tracepoint * const __tracepoint_ptr_##name __used \ - __attribute__((section("__tracepoints_ptrs"))) = \ +#define DEFINE_TRACE_FN(name, reg, unreg) \ + static const char __tpstrtab_##name[] \ + __attribute__((section("__tracepoints_strings"))) = #name; \ + struct tracepoint __tracepoint_##name \ + __attribute__((section("__tracepoints"))) = \ + { __tpstrtab_##name, JUMP_LABEL_INIT, reg, unreg, NULL };\ + static struct tracepoint * const __tracepoint_ptr_##name __used \ + __attribute__((section("__tracepoints_ptrs"))) = \ &__tracepoint_##name; #define DEFINE_TRACE(name) \ diff --git a/kernel/jump_label.c b/kernel/jump_label.c index 3b79bd9..74d1c09 100644 --- a/kernel/jump_label.c +++ b/kernel/jump_label.c @@ -2,43 +2,23 @@ * jump label support * * Copyright (C) 2009 Jason Baron + * Copyright (C) 2011 Peter Zijlstra * */ -#include #include #include #include #include -#include #include #include #include +#include #ifdef HAVE_JUMP_LABEL -#define JUMP_LABEL_HASH_BITS 6 -#define JUMP_LABEL_TABLE_SIZE (1 << JUMP_LABEL_HASH_BITS) -static struct hlist_head jump_label_table[JUMP_LABEL_TABLE_SIZE]; - /* mutex to protect coming/going of the the jump_label table */ static DEFINE_MUTEX(jump_label_mutex); -struct jump_label_entry { - struct hlist_node hlist; - struct jump_entry *table; - int nr_entries; - /* hang modules off here */ - struct hlist_head modules; - unsigned long key; -}; - -struct jump_label_module_entry { - struct hlist_node hlist; - struct jump_entry *table; - int nr_entries; - struct module *mod; -}; - void jump_label_lock(void) { mutex_lock(&jump_label_mutex); @@ -49,6 +29,11 @@ void jump_label_unlock(void) mutex_unlock(&jump_label_mutex); } +bool jump_label_enabled(struct jump_label_key *key) +{ + return !!atomic_read(&key->enabled); +} + static int jump_label_cmp(const void *a, const void *b) { const struct jump_entry *jea = a; @@ -64,7 +49,7 @@ static int jump_label_cmp(const void *a, const void *b) } static void -sort_jump_label_entries(struct jump_entry *start, struct jump_entry *stop) +jump_label_sort_entries(struct jump_entry *start, struct jump_entry *stop) { unsigned long size; @@ -73,118 +58,25 @@ sort_jump_label_entries(struct jump_entry *start, struct jump_entry *stop) sort(start, size, sizeof(struct jump_entry), jump_label_cmp, NULL); } -static struct jump_label_entry *get_jump_label_entry(jump_label_t key) -{ - struct hlist_head *head; - struct hlist_node *node; - struct jump_label_entry *e; - u32 hash = jhash((void *)&key, sizeof(jump_label_t), 0); - - head = &jump_label_table[hash & (JUMP_LABEL_TABLE_SIZE - 1)]; - hlist_for_each_entry(e, node, head, hlist) { - if (key == e->key) - return e; - } - return NULL; -} +static void jump_label_update(struct jump_label_key *key, int enable); -static struct jump_label_entry * -add_jump_label_entry(jump_label_t key, int nr_entries, struct jump_entry *table) +void jump_label_inc(struct jump_label_key *key) { - struct hlist_head *head; - struct jump_label_entry *e; - u32 hash; - - e = get_jump_label_entry(key); - if (e) - return ERR_PTR(-EEXIST); - - e = kmalloc(sizeof(struct jump_label_entry), GFP_KERNEL); - if (!e) - return ERR_PTR(-ENOMEM); - - hash = jhash((void *)&key, sizeof(jump_label_t), 0); - head = &jump_label_table[hash & (JUMP_LABEL_TABLE_SIZE - 1)]; - e->key = key; - e->table = table; - e->nr_entries = nr_entries; - INIT_HLIST_HEAD(&(e->modules)); - hlist_add_head(&e->hlist, head); - return e; -} + if (atomic_inc_not_zero(&key->enabled)) + return; -static int -build_jump_label_hashtable(struct jump_entry *start, struct jump_entry *stop) -{ - struct jump_entry *iter, *iter_begin; - struct jump_label_entry *entry; - int count; - - sort_jump_label_entries(start, stop); - iter = start; - while (iter < stop) { - entry = get_jump_label_entry(iter->key); - if (!entry) { - iter_begin = iter; - count = 0; - while ((iter < stop) && - (iter->key == iter_begin->key)) { - iter++; - count++; - } - entry = add_jump_label_entry(iter_begin->key, - count, iter_begin); - if (IS_ERR(entry)) - return PTR_ERR(entry); - } else { - WARN_ONCE(1, KERN_ERR "build_jump_hashtable: unexpected entry!\n"); - return -1; - } - } - return 0; + jump_label_lock(); + if (atomic_add_return(1, &key->enabled) == 1) + jump_label_update(key, JUMP_LABEL_ENABLE); + jump_label_unlock(); } -/*** - * jump_label_update - update jump label text - * @key - key value associated with a a jump label - * @type - enum set to JUMP_LABEL_ENABLE or JUMP_LABEL_DISABLE - * - * Will enable/disable the jump for jump label @key, depending on the - * value of @type. - * - */ - -void jump_label_update(unsigned long key, enum jump_label_type type) +void jump_label_dec(struct jump_label_key *key) { - struct jump_entry *iter; - struct jump_label_entry *entry; - struct hlist_node *module_node; - struct jump_label_module_entry *e_module; - int count; + if (!atomic_dec_and_mutex_lock(&key->enabled, &jump_label_mutex)) + return; - jump_label_lock(); - entry = get_jump_label_entry((jump_label_t)key); - if (entry) { - count = entry->nr_entries; - iter = entry->table; - while (count--) { - if (kernel_text_address(iter->code)) - arch_jump_label_transform(iter, type); - iter++; - } - /* eanble/disable jump labels in modules */ - hlist_for_each_entry(e_module, module_node, &(entry->modules), - hlist) { - count = e_module->nr_entries; - iter = e_module->table; - while (count--) { - if (iter->key && - kernel_text_address(iter->code)) - arch_jump_label_transform(iter, type); - iter++; - } - } - } + jump_label_update(key, JUMP_LABEL_DISABLE); jump_label_unlock(); } @@ -197,77 +89,33 @@ static int addr_conflict(struct jump_entry *entry, void *start, void *end) return 0; } -#ifdef CONFIG_MODULES - -static int module_conflict(void *start, void *end) +static int __jump_label_text_reserved(struct jump_entry *iter_start, + struct jump_entry *iter_stop, void *start, void *end) { - struct hlist_head *head; - struct hlist_node *node, *node_next, *module_node, *module_node_next; - struct jump_label_entry *e; - struct jump_label_module_entry *e_module; struct jump_entry *iter; - int i, count; - int conflict = 0; - - for (i = 0; i < JUMP_LABEL_TABLE_SIZE; i++) { - head = &jump_label_table[i]; - hlist_for_each_entry_safe(e, node, node_next, head, hlist) { - hlist_for_each_entry_safe(e_module, module_node, - module_node_next, - &(e->modules), hlist) { - count = e_module->nr_entries; - iter = e_module->table; - while (count--) { - if (addr_conflict(iter, start, end)) { - conflict = 1; - goto out; - } - iter++; - } - } - } - } -out: - return conflict; -} - -#endif - -/*** - * jump_label_text_reserved - check if addr range is reserved - * @start: start text addr - * @end: end text addr - * - * checks if the text addr located between @start and @end - * overlaps with any of the jump label patch addresses. Code - * that wants to modify kernel text should first verify that - * it does not overlap with any of the jump label addresses. - * Caller must hold jump_label_mutex. - * - * returns 1 if there is an overlap, 0 otherwise - */ -int jump_label_text_reserved(void *start, void *end) -{ - struct jump_entry *iter; - struct jump_entry *iter_start = __start___jump_table; - struct jump_entry *iter_stop = __start___jump_table; - int conflict = 0; iter = iter_start; while (iter < iter_stop) { - if (addr_conflict(iter, start, end)) { - conflict = 1; - goto out; - } + if (addr_conflict(iter, start, end)) + return 1; iter++; } - /* now check modules */ -#ifdef CONFIG_MODULES - conflict = module_conflict(start, end); -#endif -out: - return conflict; + return 0; +} + +static void __jump_label_update(struct jump_label_key *key, + struct jump_entry *entry, int enable) +{ + for (; entry->key == (jump_label_t)(unsigned long)key; entry++) { + /* + * entry->code set to 0 invalidates module init text sections + * kernel_text_address() verifies we are not in core kernel + * init code, see jump_label_invalidate_module_init(). + */ + if (entry->code && kernel_text_address(entry->code)) + arch_jump_label_transform(entry, enable); + } } /* @@ -277,142 +125,173 @@ void __weak arch_jump_label_text_poke_early(jump_label_t addr) { } -static __init int init_jump_label(void) +static __init int jump_label_init(void) { - int ret; struct jump_entry *iter_start = __start___jump_table; struct jump_entry *iter_stop = __stop___jump_table; + struct jump_label_key *key = NULL; struct jump_entry *iter; jump_label_lock(); - ret = build_jump_label_hashtable(__start___jump_table, - __stop___jump_table); - iter = iter_start; - while (iter < iter_stop) { + jump_label_sort_entries(iter_start, iter_stop); + + for (iter = iter_start; iter < iter_stop; iter++) { arch_jump_label_text_poke_early(iter->code); - iter++; + if (iter->key == (jump_label_t)(unsigned long)key) + continue; + + key = (struct jump_label_key *)(unsigned long)iter->key; + atomic_set(&key->enabled, 0); + key->entries = iter; +#ifdef CONFIG_MODULES + key->next = NULL; +#endif } jump_label_unlock(); - return ret; + + return 0; } -early_initcall(init_jump_label); +early_initcall(jump_label_init); #ifdef CONFIG_MODULES -static struct jump_label_module_entry * -add_jump_label_module_entry(struct jump_label_entry *entry, - struct jump_entry *iter_begin, - int count, struct module *mod) +struct jump_label_mod { + struct jump_label_mod *next; + struct jump_entry *entries; + struct module *mod; +}; + +static int __jump_label_mod_text_reserved(void *start, void *end) +{ + struct module *mod; + + mod = __module_text_address((unsigned long)start); + if (!mod) + return 0; + + WARN_ON_ONCE(__module_text_address((unsigned long)end) != mod); + + return __jump_label_text_reserved(mod->jump_entries, + mod->jump_entries + mod->num_jump_entries, + start, end); +} + +static void __jump_label_mod_update(struct jump_label_key *key, int enable) +{ + struct jump_label_mod *mod = key->next; + + while (mod) { + __jump_label_update(key, mod->entries, enable); + mod = mod->next; + } +} + +/*** + * apply_jump_label_nops - patch module jump labels with arch_get_jump_label_nop() + * @mod: module to patch + * + * Allow for run-time selection of the optimal nops. Before the module + * loads patch these with arch_get_jump_label_nop(), which is specified by + * the arch specific jump label code. + */ +void jump_label_apply_nops(struct module *mod) { - struct jump_label_module_entry *e; - - e = kmalloc(sizeof(struct jump_label_module_entry), GFP_KERNEL); - if (!e) - return ERR_PTR(-ENOMEM); - e->mod = mod; - e->nr_entries = count; - e->table = iter_begin; - hlist_add_head(&e->hlist, &entry->modules); - return e; + struct jump_entry *iter_start = mod->jump_entries; + struct jump_entry *iter_stop = iter_start + mod->num_jump_entries; + struct jump_entry *iter; + + /* if the module doesn't have jump label entries, just return */ + if (iter_start == iter_stop) + return; + + for (iter = iter_start; iter < iter_stop; iter++) + arch_jump_label_text_poke_early(iter->code); } -static int add_jump_label_module(struct module *mod) +static int jump_label_add_module(struct module *mod) { - struct jump_entry *iter, *iter_begin; - struct jump_label_entry *entry; - struct jump_label_module_entry *module_entry; - int count; + struct jump_entry *iter_start = mod->jump_entries; + struct jump_entry *iter_stop = iter_start + mod->num_jump_entries; + struct jump_entry *iter; + struct jump_label_key *key = NULL; + struct jump_label_mod *jlm; /* if the module doesn't have jump label entries, just return */ - if (!mod->num_jump_entries) + if (iter_start == iter_stop) return 0; - sort_jump_label_entries(mod->jump_entries, - mod->jump_entries + mod->num_jump_entries); - iter = mod->jump_entries; - while (iter < mod->jump_entries + mod->num_jump_entries) { - entry = get_jump_label_entry(iter->key); - iter_begin = iter; - count = 0; - while ((iter < mod->jump_entries + mod->num_jump_entries) && - (iter->key == iter_begin->key)) { - iter++; - count++; - } - if (!entry) { - entry = add_jump_label_entry(iter_begin->key, 0, NULL); - if (IS_ERR(entry)) - return PTR_ERR(entry); + jump_label_sort_entries(iter_start, iter_stop); + + for (iter = iter_start; iter < iter_stop; iter++) { + if (iter->key == (jump_label_t)(unsigned long)key) + continue; + + key = (struct jump_label_key *)(unsigned long)iter->key; + + if (__module_address(iter->key) == mod) { + atomic_set(&key->enabled, 0); + key->entries = iter; + key->next = NULL; + continue; } - module_entry = add_jump_label_module_entry(entry, iter_begin, - count, mod); - if (IS_ERR(module_entry)) - return PTR_ERR(module_entry); + + jlm = kzalloc(sizeof(struct jump_label_mod), GFP_KERNEL); + if (!jlm) + return -ENOMEM; + + jlm->mod = mod; + jlm->entries = iter; + jlm->next = key->next; + key->next = jlm; + + if (jump_label_enabled(key)) + __jump_label_update(key, iter, JUMP_LABEL_ENABLE); } + return 0; } -static void remove_jump_label_module(struct module *mod) +static void jump_label_del_module(struct module *mod) { - struct hlist_head *head; - struct hlist_node *node, *node_next, *module_node, *module_node_next; - struct jump_label_entry *e; - struct jump_label_module_entry *e_module; - int i; + struct jump_entry *iter_start = mod->jump_entries; + struct jump_entry *iter_stop = iter_start + mod->num_jump_entries; + struct jump_entry *iter; + struct jump_label_key *key = NULL; + struct jump_label_mod *jlm, **prev; - /* if the module doesn't have jump label entries, just return */ - if (!mod->num_jump_entries) - return; + for (iter = iter_start; iter < iter_stop; iter++) { + if (iter->key == (jump_label_t)(unsigned long)key) + continue; + + key = (struct jump_label_key *)(unsigned long)iter->key; + + if (__module_address(iter->key) == mod) + continue; + + prev = &key->next; + jlm = key->next; - for (i = 0; i < JUMP_LABEL_TABLE_SIZE; i++) { - head = &jump_label_table[i]; - hlist_for_each_entry_safe(e, node, node_next, head, hlist) { - hlist_for_each_entry_safe(e_module, module_node, - module_node_next, - &(e->modules), hlist) { - if (e_module->mod == mod) { - hlist_del(&e_module->hlist); - kfree(e_module); - } - } - if (hlist_empty(&e->modules) && (e->nr_entries == 0)) { - hlist_del(&e->hlist); - kfree(e); - } + while (jlm && jlm->mod != mod) { + prev = &jlm->next; + jlm = jlm->next; + } + + if (jlm) { + *prev = jlm->next; + kfree(jlm); } } } -static void remove_jump_label_module_init(struct module *mod) +static void jump_label_invalidate_module_init(struct module *mod) { - struct hlist_head *head; - struct hlist_node *node, *node_next, *module_node, *module_node_next; - struct jump_label_entry *e; - struct jump_label_module_entry *e_module; + struct jump_entry *iter_start = mod->jump_entries; + struct jump_entry *iter_stop = iter_start + mod->num_jump_entries; struct jump_entry *iter; - int i, count; - - /* if the module doesn't have jump label entries, just return */ - if (!mod->num_jump_entries) - return; - for (i = 0; i < JUMP_LABEL_TABLE_SIZE; i++) { - head = &jump_label_table[i]; - hlist_for_each_entry_safe(e, node, node_next, head, hlist) { - hlist_for_each_entry_safe(e_module, module_node, - module_node_next, - &(e->modules), hlist) { - if (e_module->mod != mod) - continue; - count = e_module->nr_entries; - iter = e_module->table; - while (count--) { - if (within_module_init(iter->code, mod)) - iter->key = 0; - iter++; - } - } - } + for (iter = iter_start; iter < iter_stop; iter++) { + if (within_module_init(iter->code, mod)) + iter->code = 0; } } @@ -426,59 +305,77 @@ jump_label_module_notify(struct notifier_block *self, unsigned long val, switch (val) { case MODULE_STATE_COMING: jump_label_lock(); - ret = add_jump_label_module(mod); + ret = jump_label_add_module(mod); if (ret) - remove_jump_label_module(mod); + jump_label_del_module(mod); jump_label_unlock(); break; case MODULE_STATE_GOING: jump_label_lock(); - remove_jump_label_module(mod); + jump_label_del_module(mod); jump_label_unlock(); break; case MODULE_STATE_LIVE: jump_label_lock(); - remove_jump_label_module_init(mod); + jump_label_invalidate_module_init(mod); jump_label_unlock(); break; } - return ret; -} -/*** - * apply_jump_label_nops - patch module jump labels with arch_get_jump_label_nop() - * @mod: module to patch - * - * Allow for run-time selection of the optimal nops. Before the module - * loads patch these with arch_get_jump_label_nop(), which is specified by - * the arch specific jump label code. - */ -void jump_label_apply_nops(struct module *mod) -{ - struct jump_entry *iter; - - /* if the module doesn't have jump label entries, just return */ - if (!mod->num_jump_entries) - return; - - iter = mod->jump_entries; - while (iter < mod->jump_entries + mod->num_jump_entries) { - arch_jump_label_text_poke_early(iter->code); - iter++; - } + return notifier_from_errno(ret); } struct notifier_block jump_label_module_nb = { .notifier_call = jump_label_module_notify, - .priority = 0, + .priority = 1, /* higher than tracepoints */ }; -static __init int init_jump_label_module(void) +static __init int jump_label_init_module(void) { return register_module_notifier(&jump_label_module_nb); } -early_initcall(init_jump_label_module); +early_initcall(jump_label_init_module); #endif /* CONFIG_MODULES */ +/*** + * jump_label_text_reserved - check if addr range is reserved + * @start: start text addr + * @end: end text addr + * + * checks if the text addr located between @start and @end + * overlaps with any of the jump label patch addresses. Code + * that wants to modify kernel text should first verify that + * it does not overlap with any of the jump label addresses. + * Caller must hold jump_label_mutex. + * + * returns 1 if there is an overlap, 0 otherwise + */ +int jump_label_text_reserved(void *start, void *end) +{ + int ret = __jump_label_text_reserved(__start___jump_table, + __stop___jump_table, start, end); + + if (ret) + return ret; + +#ifdef CONFIG_MODULES + ret = __jump_label_mod_text_reserved(start, end); +#endif + return ret; +} + +static void jump_label_update(struct jump_label_key *key, int enable) +{ + struct jump_entry *entry = key->entries; + + /* if there are no users, entry can be NULL */ + if (entry) + __jump_label_update(key, entry, enable); + +#ifdef CONFIG_MODULES + __jump_label_mod_update(key, enable); +#endif +} + #endif diff --git a/kernel/perf_event.c b/kernel/perf_event.c index c75925c..d665e92 100644 --- a/kernel/perf_event.c +++ b/kernel/perf_event.c @@ -125,7 +125,7 @@ enum event_type_t { * perf_sched_events : >0 events exist * perf_cgroup_events: >0 per-cpu cgroup events exist on this cpu */ -atomic_t perf_sched_events __read_mostly; +struct jump_label_key perf_sched_events __read_mostly; static DEFINE_PER_CPU(atomic_t, perf_cgroup_events); static atomic_t nr_mmap_events __read_mostly; @@ -5417,7 +5417,7 @@ fail: return err; } -atomic_t perf_swevent_enabled[PERF_COUNT_SW_MAX]; +struct jump_label_key perf_swevent_enabled[PERF_COUNT_SW_MAX]; static void sw_perf_event_destroy(struct perf_event *event) { diff --git a/kernel/tracepoint.c b/kernel/tracepoint.c index 68187af..b219f14 100644 --- a/kernel/tracepoint.c +++ b/kernel/tracepoint.c @@ -251,9 +251,9 @@ static void set_tracepoint(struct tracepoint_entry **entry, { WARN_ON(strcmp((*entry)->name, elem->name) != 0); - if (elem->regfunc && !elem->state && active) + if (elem->regfunc && !jump_label_enabled(&elem->key) && active) elem->regfunc(); - else if (elem->unregfunc && elem->state && !active) + else if (elem->unregfunc && jump_label_enabled(&elem->key) && !active) elem->unregfunc(); /* @@ -264,13 +264,10 @@ static void set_tracepoint(struct tracepoint_entry **entry, * is used. */ rcu_assign_pointer(elem->funcs, (*entry)->funcs); - if (!elem->state && active) { - jump_label_enable(&elem->state); - elem->state = active; - } else if (elem->state && !active) { - jump_label_disable(&elem->state); - elem->state = active; - } + if (active && !jump_label_enabled(&elem->key)) + jump_label_inc(&elem->key); + else if (!active && jump_label_enabled(&elem->key)) + jump_label_dec(&elem->key); } /* @@ -281,13 +278,11 @@ static void set_tracepoint(struct tracepoint_entry **entry, */ static void disable_tracepoint(struct tracepoint *elem) { - if (elem->unregfunc && elem->state) + if (elem->unregfunc && jump_label_enabled(&elem->key)) elem->unregfunc(); - if (elem->state) { - jump_label_disable(&elem->state); - elem->state = 0; - } + if (jump_label_enabled(&elem->key)) + jump_label_dec(&elem->key); rcu_assign_pointer(elem->funcs, NULL); } -- cgit v0.10.2 From ef64789413c73f32faa5e5f1bc393e5843b0aa51 Mon Sep 17 00:00:00 2001 From: Jason Baron Date: Wed, 16 Mar 2011 15:58:27 -0400 Subject: jump label: Add _ASM_ALIGN for x86 and x86_64 The linker should not be adding holes to word size aligned pointers, but out of paranoia we are explicitly specifying that alignment. I have not seen any holes in the jump label section in practice. Signed-off-by: Jason Baron LKML-Reference: Acked-by: Peter Zijlstra Acked-by: Mathieu Desnoyers Signed-off-by: Steven Rostedt diff --git a/arch/x86/include/asm/jump_label.h b/arch/x86/include/asm/jump_label.h index f217cee..a32b18c 100644 --- a/arch/x86/include/asm/jump_label.h +++ b/arch/x86/include/asm/jump_label.h @@ -16,6 +16,7 @@ static __always_inline bool arch_static_branch(struct jump_label_key *key) asm goto("1:" JUMP_LABEL_INITIAL_NOP ".pushsection __jump_table, \"aw\" \n\t" + _ASM_ALIGN "\n\t" _ASM_PTR "1b, %l[l_yes], %c0 \n\t" ".popsection \n\t" : : "i" (key) : : l_yes); -- cgit v0.10.2 From 5373db886b791b2bc7811e2c115377916c409a5d Mon Sep 17 00:00:00 2001 From: Jan Glauber Date: Wed, 16 Mar 2011 15:58:30 -0400 Subject: jump label: Add s390 support Implement the architecture backend for jump label support on s390. For a shared kernel booted from a NSS silently disable jump labels because the NSS is read-only. Therefore jump labels will be disabled in a shared kernel and can't be activated. Signed-off-by: Jan Glauber LKML-Reference: <6935d2c41ce111e1719176ed4bbd3dbe4de80855.1300299760.git.jbaron@redhat.com> Acked-by: Peter Zijlstra Signed-off-by: Martin Schwidefsky Signed-off-by: Steven Rostedt diff --git a/arch/s390/Kconfig b/arch/s390/Kconfig index 2508a6f..4a7f140 100644 --- a/arch/s390/Kconfig +++ b/arch/s390/Kconfig @@ -88,6 +88,7 @@ config S390 select HAVE_KERNEL_XZ select HAVE_GET_USER_PAGES_FAST select HAVE_ARCH_MUTEX_CPU_RELAX + select HAVE_ARCH_JUMP_LABEL if !MARCH_G5 select ARCH_INLINE_SPIN_TRYLOCK select ARCH_INLINE_SPIN_TRYLOCK_BH select ARCH_INLINE_SPIN_LOCK diff --git a/arch/s390/include/asm/jump_label.h b/arch/s390/include/asm/jump_label.h new file mode 100644 index 0000000..95a6cf2 --- /dev/null +++ b/arch/s390/include/asm/jump_label.h @@ -0,0 +1,37 @@ +#ifndef _ASM_S390_JUMP_LABEL_H +#define _ASM_S390_JUMP_LABEL_H + +#include + +#define JUMP_LABEL_NOP_SIZE 6 + +#ifdef CONFIG_64BIT +#define ASM_PTR ".quad" +#define ASM_ALIGN ".balign 8" +#else +#define ASM_PTR ".long" +#define ASM_ALIGN ".balign 4" +#endif + +static __always_inline bool arch_static_branch(struct jump_label_key *key) +{ + asm goto("0: brcl 0,0\n" + ".pushsection __jump_table, \"aw\"\n" + ASM_ALIGN "\n" + ASM_PTR " 0b, %l[label], %0\n" + ".popsection\n" + : : "X" (key) : : label); + return false; +label: + return true; +} + +typedef unsigned long jump_label_t; + +struct jump_entry { + jump_label_t code; + jump_label_t target; + jump_label_t key; +}; + +#endif diff --git a/arch/s390/kernel/Makefile b/arch/s390/kernel/Makefile index 64230bc..5ff15da 100644 --- a/arch/s390/kernel/Makefile +++ b/arch/s390/kernel/Makefile @@ -23,7 +23,7 @@ CFLAGS_sysinfo.o += -Iinclude/math-emu -Iarch/s390/math-emu -w obj-y := bitmap.o traps.o time.o process.o base.o early.o setup.o \ processor.o sys_s390.o ptrace.o signal.o cpcmd.o ebcdic.o \ s390_ext.o debug.o irq.o ipl.o dis.o diag.o mem_detect.o \ - vdso.o vtime.o sysinfo.o nmi.o sclp.o + vdso.o vtime.o sysinfo.o nmi.o sclp.o jump_label.o obj-y += $(if $(CONFIG_64BIT),entry64.o,entry.o) obj-y += $(if $(CONFIG_64BIT),reipl64.o,reipl.o) diff --git a/arch/s390/kernel/jump_label.c b/arch/s390/kernel/jump_label.c new file mode 100644 index 0000000..44cc06b --- /dev/null +++ b/arch/s390/kernel/jump_label.c @@ -0,0 +1,59 @@ +/* + * Jump label s390 support + * + * Copyright IBM Corp. 2011 + * Author(s): Jan Glauber + */ +#include +#include +#include +#include +#include + +#ifdef HAVE_JUMP_LABEL + +struct insn { + u16 opcode; + s32 offset; +} __packed; + +struct insn_args { + unsigned long *target; + struct insn *insn; + ssize_t size; +}; + +static int __arch_jump_label_transform(void *data) +{ + struct insn_args *args = data; + int rc; + + rc = probe_kernel_write(args->target, args->insn, args->size); + WARN_ON_ONCE(rc < 0); + return 0; +} + +void arch_jump_label_transform(struct jump_entry *entry, + enum jump_label_type type) +{ + struct insn_args args; + struct insn insn; + + if (type == JUMP_LABEL_ENABLE) { + /* brcl 15,offset */ + insn.opcode = 0xc0f4; + insn.offset = (entry->target - entry->code) >> 1; + } else { + /* brcl 0,0 */ + insn.opcode = 0xc004; + insn.offset = 0; + } + + args.target = (void *) entry->code; + args.insn = &insn; + args.size = JUMP_LABEL_NOP_SIZE; + + stop_machine(__arch_jump_label_transform, &args, NULL); +} + +#endif -- cgit v0.10.2 From fc3e5941248be00996150965a469d38c92913ac2 Mon Sep 17 00:00:00 2001 From: Ian Campbell Date: Mon, 4 Apr 2011 11:07:57 -0700 Subject: xen: netfront: assume all hw features are available until backend connection setup We need to assume that all features will be available when registering the netdev otherwise they are ommitted from the initial set of dev->wanted_features. When we connect to the backed we reduce the set as necessary due to the call to netdev_update_features() in xennet_connect(). Signed-off-by: Ian Campbell Signed-off-by: David S. Miller diff --git a/drivers/net/xen-netfront.c b/drivers/net/xen-netfront.c index 0cfe4cc..db9a763 100644 --- a/drivers/net/xen-netfront.c +++ b/drivers/net/xen-netfront.c @@ -1251,6 +1251,14 @@ static struct net_device * __devinit xennet_create_dev(struct xenbus_device *dev NETIF_F_GSO_ROBUST; netdev->hw_features = NETIF_F_IP_CSUM | NETIF_F_SG | NETIF_F_TSO; + /* + * Assume that all hw features are available for now. This set + * will be adjusted by the call to netdev_update_features() in + * xennet_connect() which is the earliest point where we can + * negotiate with the backend regarding supported features. + */ + netdev->features |= netdev->hw_features; + SET_ETHTOOL_OPS(netdev, &xennet_ethtool_ops); SET_NETDEV_DEV(netdev, &dev->dev); -- cgit v0.10.2 From 0545a3037773512d3448557ba048cebb73b3e4af Mon Sep 17 00:00:00 2001 From: stephen hemminger Date: Mon, 4 Apr 2011 05:30:58 +0000 Subject: pkt_sched: QFQ - quick fair queue scheduler This is an implementation of the Quick Fair Queue scheduler developed by Fabio Checconi. The same algorithm is already implemented in ipfw in FreeBSD. Fabio had an earlier version developed on Linux, I just cleaned it up. Thanks to Eric Dumazet for testing this under load. Signed-off-by: Stephen Hemminger Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller diff --git a/include/linux/pkt_sched.h b/include/linux/pkt_sched.h index b1032a3..8062e0a 100644 --- a/include/linux/pkt_sched.h +++ b/include/linux/pkt_sched.h @@ -588,4 +588,19 @@ struct tc_sfb_xstats { #define SFB_MAX_PROB 0xFFFF +/* QFQ */ +enum { + TCA_QFQ_UNSPEC, + TCA_QFQ_WEIGHT, + TCA_QFQ_LMAX, + __TCA_QFQ_MAX +}; + +#define TCA_QFQ_MAX (__TCA_QFQ_MAX - 1) + +struct tc_qfq_stats { + __u32 weight; + __u32 lmax; +}; + #endif diff --git a/net/sched/Kconfig b/net/sched/Kconfig index a7a5583d..aeaa211 100644 --- a/net/sched/Kconfig +++ b/net/sched/Kconfig @@ -239,6 +239,17 @@ config NET_SCH_CHOKE To compile this code as a module, choose M here: the module will be called sch_choke. +config NET_SCH_QFQ + tristate "Quick Fair Queueing scheduler (QFQ)" + help + Say Y here if you want to use the Quick Fair Queueing Scheduler (QFQ) + packet scheduling algorithm. + + To compile this driver as a module, choose M here: the module + will be called sch_qfq. + + If unsure, say N. + config NET_SCH_INGRESS tristate "Ingress Qdisc" depends on NET_CLS_ACT diff --git a/net/sched/Makefile b/net/sched/Makefile index 2e77b8d..dc5889c 100644 --- a/net/sched/Makefile +++ b/net/sched/Makefile @@ -35,6 +35,7 @@ obj-$(CONFIG_NET_SCH_NETEM) += sch_netem.o obj-$(CONFIG_NET_SCH_DRR) += sch_drr.o obj-$(CONFIG_NET_SCH_MQPRIO) += sch_mqprio.o obj-$(CONFIG_NET_SCH_CHOKE) += sch_choke.o +obj-$(CONFIG_NET_SCH_QFQ) += sch_qfq.o obj-$(CONFIG_NET_CLS_U32) += cls_u32.o obj-$(CONFIG_NET_CLS_ROUTE4) += cls_route.o diff --git a/net/sched/sch_qfq.c b/net/sched/sch_qfq.c new file mode 100644 index 0000000..1033434 --- /dev/null +++ b/net/sched/sch_qfq.c @@ -0,0 +1,1137 @@ +/* + * net/sched/sch_qfq.c Quick Fair Queueing Scheduler. + * + * Copyright (c) 2009 Fabio Checconi, Luigi Rizzo, and Paolo Valente. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +/* Quick Fair Queueing + =================== + + Sources: + + Fabio Checconi, Luigi Rizzo, and Paolo Valente: "QFQ: Efficient + Packet Scheduling with Tight Bandwidth Distribution Guarantees." + + See also: + http://retis.sssup.it/~fabio/linux/qfq/ + */ + +/* + + Virtual time computations. + + S, F and V are all computed in fixed point arithmetic with + FRAC_BITS decimal bits. + + QFQ_MAX_INDEX is the maximum index allowed for a group. We need + one bit per index. + QFQ_MAX_WSHIFT is the maximum power of two supported as a weight. + + The layout of the bits is as below: + + [ MTU_SHIFT ][ FRAC_BITS ] + [ MAX_INDEX ][ MIN_SLOT_SHIFT ] + ^.__grp->index = 0 + *.__grp->slot_shift + + where MIN_SLOT_SHIFT is derived by difference from the others. + + The max group index corresponds to Lmax/w_min, where + Lmax=1<group mapping. We allow class weights that are + * in the range [1, 2^MAX_WSHIFT], and we try to map each class i to the + * group with the smallest index that can support the L_i / r_i configured + * for the class. + * + * grp->index is the index of the group; and grp->slot_shift + * is the shift for the corresponding (scaled) sigma_i. + */ +#define QFQ_MAX_INDEX 19 +#define QFQ_MAX_WSHIFT 16 + +#define QFQ_MAX_WEIGHT (1<clhash, classid); + if (clc == NULL) + return NULL; + return container_of(clc, struct qfq_class, common); +} + +static void qfq_purge_queue(struct qfq_class *cl) +{ + unsigned int len = cl->qdisc->q.qlen; + + qdisc_reset(cl->qdisc); + qdisc_tree_decrease_qlen(cl->qdisc, len); +} + +static const struct nla_policy qfq_policy[TCA_QFQ_MAX + 1] = { + [TCA_QFQ_WEIGHT] = { .type = NLA_U32 }, + [TCA_QFQ_LMAX] = { .type = NLA_U32 }, +}; + +/* + * Calculate a flow index, given its weight and maximum packet length. + * index = log_2(maxlen/weight) but we need to apply the scaling. + * This is used only once at flow creation. + */ +static int qfq_calc_index(u32 inv_w, unsigned int maxlen) +{ + u64 slot_size = (u64)maxlen * inv_w; + unsigned long size_map; + int index = 0; + + size_map = slot_size >> QFQ_MIN_SLOT_SHIFT; + if (!size_map) + goto out; + + index = __fls(size_map) + 1; /* basically a log_2 */ + index -= !(slot_size - (1ULL << (index + QFQ_MIN_SLOT_SHIFT - 1))); + + if (index < 0) + index = 0; +out: + pr_debug("qfq calc_index: W = %lu, L = %u, I = %d\n", + (unsigned long) ONE_FP/inv_w, maxlen, index); + + return index; +} + +static int qfq_change_class(struct Qdisc *sch, u32 classid, u32 parentid, + struct nlattr **tca, unsigned long *arg) +{ + struct qfq_sched *q = qdisc_priv(sch); + struct qfq_class *cl = (struct qfq_class *)*arg; + struct nlattr *tb[TCA_QFQ_MAX + 1]; + u32 weight, lmax, inv_w; + int i, err; + + if (tca[TCA_OPTIONS] == NULL) { + pr_notice("qfq: no options\n"); + return -EINVAL; + } + + err = nla_parse_nested(tb, TCA_QFQ_MAX, tca[TCA_OPTIONS], qfq_policy); + if (err < 0) + return err; + + if (tb[TCA_QFQ_WEIGHT]) { + weight = nla_get_u32(tb[TCA_QFQ_WEIGHT]); + if (!weight || weight > (1UL << QFQ_MAX_WSHIFT)) { + pr_notice("qfq: invalid weight %u\n", weight); + return -EINVAL; + } + } else + weight = 1; + + inv_w = ONE_FP / weight; + weight = ONE_FP / inv_w; + if (q->wsum + weight > QFQ_MAX_WSUM) { + pr_notice("qfq: total weight out of range (%u + %u)\n", + weight, q->wsum); + return -EINVAL; + } + + if (tb[TCA_QFQ_LMAX]) { + lmax = nla_get_u32(tb[TCA_QFQ_LMAX]); + if (!lmax || lmax > (1UL << QFQ_MTU_SHIFT)) { + pr_notice("qfq: invalid max length %u\n", lmax); + return -EINVAL; + } + } else + lmax = 1UL << QFQ_MTU_SHIFT; + + if (cl != NULL) { + if (tca[TCA_RATE]) { + err = gen_replace_estimator(&cl->bstats, &cl->rate_est, + qdisc_root_sleeping_lock(sch), + tca[TCA_RATE]); + if (err) + return err; + } + + sch_tree_lock(sch); + if (tb[TCA_QFQ_WEIGHT]) { + q->wsum = weight - ONE_FP / cl->inv_w; + cl->inv_w = inv_w; + } + sch_tree_unlock(sch); + + return 0; + } + + cl = kzalloc(sizeof(struct qfq_class), GFP_KERNEL); + if (cl == NULL) + return -ENOBUFS; + + cl->refcnt = 1; + cl->common.classid = classid; + cl->lmax = lmax; + cl->inv_w = inv_w; + i = qfq_calc_index(cl->inv_w, cl->lmax); + + cl->grp = &q->groups[i]; + q->wsum += weight; + + cl->qdisc = qdisc_create_dflt(sch->dev_queue, + &pfifo_qdisc_ops, classid); + if (cl->qdisc == NULL) + cl->qdisc = &noop_qdisc; + + if (tca[TCA_RATE]) { + err = gen_new_estimator(&cl->bstats, &cl->rate_est, + qdisc_root_sleeping_lock(sch), + tca[TCA_RATE]); + if (err) { + qdisc_destroy(cl->qdisc); + kfree(cl); + return err; + } + } + + sch_tree_lock(sch); + qdisc_class_hash_insert(&q->clhash, &cl->common); + sch_tree_unlock(sch); + + qdisc_class_hash_grow(sch, &q->clhash); + + *arg = (unsigned long)cl; + return 0; +} + +static void qfq_destroy_class(struct Qdisc *sch, struct qfq_class *cl) +{ + struct qfq_sched *q = qdisc_priv(sch); + + if (cl->inv_w) { + q->wsum -= ONE_FP / cl->inv_w; + cl->inv_w = 0; + } + + gen_kill_estimator(&cl->bstats, &cl->rate_est); + qdisc_destroy(cl->qdisc); + kfree(cl); +} + +static int qfq_delete_class(struct Qdisc *sch, unsigned long arg) +{ + struct qfq_sched *q = qdisc_priv(sch); + struct qfq_class *cl = (struct qfq_class *)arg; + + if (cl->filter_cnt > 0) + return -EBUSY; + + sch_tree_lock(sch); + + qfq_purge_queue(cl); + qdisc_class_hash_remove(&q->clhash, &cl->common); + + BUG_ON(--cl->refcnt == 0); + /* + * This shouldn't happen: we "hold" one cops->get() when called + * from tc_ctl_tclass; the destroy method is done from cops->put(). + */ + + sch_tree_unlock(sch); + return 0; +} + +static unsigned long qfq_get_class(struct Qdisc *sch, u32 classid) +{ + struct qfq_class *cl = qfq_find_class(sch, classid); + + if (cl != NULL) + cl->refcnt++; + + return (unsigned long)cl; +} + +static void qfq_put_class(struct Qdisc *sch, unsigned long arg) +{ + struct qfq_class *cl = (struct qfq_class *)arg; + + if (--cl->refcnt == 0) + qfq_destroy_class(sch, cl); +} + +static struct tcf_proto **qfq_tcf_chain(struct Qdisc *sch, unsigned long cl) +{ + struct qfq_sched *q = qdisc_priv(sch); + + if (cl) + return NULL; + + return &q->filter_list; +} + +static unsigned long qfq_bind_tcf(struct Qdisc *sch, unsigned long parent, + u32 classid) +{ + struct qfq_class *cl = qfq_find_class(sch, classid); + + if (cl != NULL) + cl->filter_cnt++; + + return (unsigned long)cl; +} + +static void qfq_unbind_tcf(struct Qdisc *sch, unsigned long arg) +{ + struct qfq_class *cl = (struct qfq_class *)arg; + + cl->filter_cnt--; +} + +static int qfq_graft_class(struct Qdisc *sch, unsigned long arg, + struct Qdisc *new, struct Qdisc **old) +{ + struct qfq_class *cl = (struct qfq_class *)arg; + + if (new == NULL) { + new = qdisc_create_dflt(sch->dev_queue, + &pfifo_qdisc_ops, cl->common.classid); + if (new == NULL) + new = &noop_qdisc; + } + + sch_tree_lock(sch); + qfq_purge_queue(cl); + *old = cl->qdisc; + cl->qdisc = new; + sch_tree_unlock(sch); + return 0; +} + +static struct Qdisc *qfq_class_leaf(struct Qdisc *sch, unsigned long arg) +{ + struct qfq_class *cl = (struct qfq_class *)arg; + + return cl->qdisc; +} + +static int qfq_dump_class(struct Qdisc *sch, unsigned long arg, + struct sk_buff *skb, struct tcmsg *tcm) +{ + struct qfq_class *cl = (struct qfq_class *)arg; + struct nlattr *nest; + + tcm->tcm_parent = TC_H_ROOT; + tcm->tcm_handle = cl->common.classid; + tcm->tcm_info = cl->qdisc->handle; + + nest = nla_nest_start(skb, TCA_OPTIONS); + if (nest == NULL) + goto nla_put_failure; + NLA_PUT_U32(skb, TCA_QFQ_WEIGHT, ONE_FP/cl->inv_w); + NLA_PUT_U32(skb, TCA_QFQ_LMAX, cl->lmax); + return nla_nest_end(skb, nest); + +nla_put_failure: + nla_nest_cancel(skb, nest); + return -EMSGSIZE; +} + +static int qfq_dump_class_stats(struct Qdisc *sch, unsigned long arg, + struct gnet_dump *d) +{ + struct qfq_class *cl = (struct qfq_class *)arg; + struct tc_qfq_stats xstats; + + memset(&xstats, 0, sizeof(xstats)); + cl->qdisc->qstats.qlen = cl->qdisc->q.qlen; + + xstats.weight = ONE_FP/cl->inv_w; + xstats.lmax = cl->lmax; + + if (gnet_stats_copy_basic(d, &cl->bstats) < 0 || + gnet_stats_copy_rate_est(d, &cl->bstats, &cl->rate_est) < 0 || + gnet_stats_copy_queue(d, &cl->qdisc->qstats) < 0) + return -1; + + return gnet_stats_copy_app(d, &xstats, sizeof(xstats)); +} + +static void qfq_walk(struct Qdisc *sch, struct qdisc_walker *arg) +{ + struct qfq_sched *q = qdisc_priv(sch); + struct qfq_class *cl; + struct hlist_node *n; + unsigned int i; + + if (arg->stop) + return; + + for (i = 0; i < q->clhash.hashsize; i++) { + hlist_for_each_entry(cl, n, &q->clhash.hash[i], common.hnode) { + if (arg->count < arg->skip) { + arg->count++; + continue; + } + if (arg->fn(sch, (unsigned long)cl, arg) < 0) { + arg->stop = 1; + return; + } + arg->count++; + } + } +} + +static struct qfq_class *qfq_classify(struct sk_buff *skb, struct Qdisc *sch, + int *qerr) +{ + struct qfq_sched *q = qdisc_priv(sch); + struct qfq_class *cl; + struct tcf_result res; + int result; + + if (TC_H_MAJ(skb->priority ^ sch->handle) == 0) { + pr_debug("qfq_classify: found %d\n", skb->priority); + cl = qfq_find_class(sch, skb->priority); + if (cl != NULL) + return cl; + } + + *qerr = NET_XMIT_SUCCESS | __NET_XMIT_BYPASS; + result = tc_classify(skb, q->filter_list, &res); + if (result >= 0) { +#ifdef CONFIG_NET_CLS_ACT + switch (result) { + case TC_ACT_QUEUED: + case TC_ACT_STOLEN: + *qerr = NET_XMIT_SUCCESS | __NET_XMIT_STOLEN; + case TC_ACT_SHOT: + return NULL; + } +#endif + cl = (struct qfq_class *)res.class; + if (cl == NULL) + cl = qfq_find_class(sch, res.classid); + return cl; + } + + return NULL; +} + +/* Generic comparison function, handling wraparound. */ +static inline int qfq_gt(u64 a, u64 b) +{ + return (s64)(a - b) > 0; +} + +/* Round a precise timestamp to its slotted value. */ +static inline u64 qfq_round_down(u64 ts, unsigned int shift) +{ + return ts & ~((1ULL << shift) - 1); +} + +/* return the pointer to the group with lowest index in the bitmap */ +static inline struct qfq_group *qfq_ffs(struct qfq_sched *q, + unsigned long bitmap) +{ + int index = __ffs(bitmap); + return &q->groups[index]; +} +/* Calculate a mask to mimic what would be ffs_from(). */ +static inline unsigned long mask_from(unsigned long bitmap, int from) +{ + return bitmap & ~((1UL << from) - 1); +} + +/* + * The state computation relies on ER=0, IR=1, EB=2, IB=3 + * First compute eligibility comparing grp->S, q->V, + * then check if someone is blocking us and possibly add EB + */ +static int qfq_calc_state(struct qfq_sched *q, const struct qfq_group *grp) +{ + /* if S > V we are not eligible */ + unsigned int state = qfq_gt(grp->S, q->V); + unsigned long mask = mask_from(q->bitmaps[ER], grp->index); + struct qfq_group *next; + + if (mask) { + next = qfq_ffs(q, mask); + if (qfq_gt(grp->F, next->F)) + state |= EB; + } + + return state; +} + + +/* + * In principle + * q->bitmaps[dst] |= q->bitmaps[src] & mask; + * q->bitmaps[src] &= ~mask; + * but we should make sure that src != dst + */ +static inline void qfq_move_groups(struct qfq_sched *q, unsigned long mask, + int src, int dst) +{ + q->bitmaps[dst] |= q->bitmaps[src] & mask; + q->bitmaps[src] &= ~mask; +} + +static void qfq_unblock_groups(struct qfq_sched *q, int index, u64 old_F) +{ + unsigned long mask = mask_from(q->bitmaps[ER], index + 1); + struct qfq_group *next; + + if (mask) { + next = qfq_ffs(q, mask); + if (!qfq_gt(next->F, old_F)) + return; + } + + mask = (1UL << index) - 1; + qfq_move_groups(q, mask, EB, ER); + qfq_move_groups(q, mask, IB, IR); +} + +/* + * perhaps + * + old_V ^= q->V; + old_V >>= QFQ_MIN_SLOT_SHIFT; + if (old_V) { + ... + } + * + */ +static void qfq_make_eligible(struct qfq_sched *q, u64 old_V) +{ + unsigned long vslot = q->V >> QFQ_MIN_SLOT_SHIFT; + unsigned long old_vslot = old_V >> QFQ_MIN_SLOT_SHIFT; + + if (vslot != old_vslot) { + unsigned long mask = (1UL << fls(vslot ^ old_vslot)) - 1; + qfq_move_groups(q, mask, IR, ER); + qfq_move_groups(q, mask, IB, EB); + } +} + + +/* + * XXX we should make sure that slot becomes less than 32. + * This is guaranteed by the input values. + * roundedS is always cl->S rounded on grp->slot_shift bits. + */ +static void qfq_slot_insert(struct qfq_group *grp, struct qfq_class *cl, + u64 roundedS) +{ + u64 slot = (roundedS - grp->S) >> grp->slot_shift; + unsigned int i = (grp->front + slot) % QFQ_MAX_SLOTS; + + hlist_add_head(&cl->next, &grp->slots[i]); + __set_bit(slot, &grp->full_slots); +} + +/* Maybe introduce hlist_first_entry?? */ +static struct qfq_class *qfq_slot_head(struct qfq_group *grp) +{ + return hlist_entry(grp->slots[grp->front].first, + struct qfq_class, next); +} + +/* + * remove the entry from the slot + */ +static void qfq_front_slot_remove(struct qfq_group *grp) +{ + struct qfq_class *cl = qfq_slot_head(grp); + + BUG_ON(!cl); + hlist_del(&cl->next); + if (hlist_empty(&grp->slots[grp->front])) + __clear_bit(0, &grp->full_slots); +} + +/* + * Returns the first full queue in a group. As a side effect, + * adjust the bucket list so the first non-empty bucket is at + * position 0 in full_slots. + */ +static struct qfq_class *qfq_slot_scan(struct qfq_group *grp) +{ + unsigned int i; + + pr_debug("qfq slot_scan: grp %u full %#lx\n", + grp->index, grp->full_slots); + + if (grp->full_slots == 0) + return NULL; + + i = __ffs(grp->full_slots); /* zero based */ + if (i > 0) { + grp->front = (grp->front + i) % QFQ_MAX_SLOTS; + grp->full_slots >>= i; + } + + return qfq_slot_head(grp); +} + +/* + * adjust the bucket list. When the start time of a group decreases, + * we move the index down (modulo QFQ_MAX_SLOTS) so we don't need to + * move the objects. The mask of occupied slots must be shifted + * because we use ffs() to find the first non-empty slot. + * This covers decreases in the group's start time, but what about + * increases of the start time ? + * Here too we should make sure that i is less than 32 + */ +static void qfq_slot_rotate(struct qfq_group *grp, u64 roundedS) +{ + unsigned int i = (grp->S - roundedS) >> grp->slot_shift; + + grp->full_slots <<= i; + grp->front = (grp->front - i) % QFQ_MAX_SLOTS; +} + +static void qfq_update_eligible(struct qfq_sched *q, u64 old_V) +{ + struct qfq_group *grp; + unsigned long ineligible; + + ineligible = q->bitmaps[IR] | q->bitmaps[IB]; + if (ineligible) { + if (!q->bitmaps[ER]) { + grp = qfq_ffs(q, ineligible); + if (qfq_gt(grp->S, q->V)) + q->V = grp->S; + } + qfq_make_eligible(q, old_V); + } +} + +/* What is length of next packet in queue (0 if queue is empty) */ +static unsigned int qdisc_peek_len(struct Qdisc *sch) +{ + struct sk_buff *skb; + + skb = sch->ops->peek(sch); + return skb ? qdisc_pkt_len(skb) : 0; +} + +/* + * Updates the class, returns true if also the group needs to be updated. + */ +static bool qfq_update_class(struct qfq_group *grp, struct qfq_class *cl) +{ + unsigned int len = qdisc_peek_len(cl->qdisc); + + cl->S = cl->F; + if (!len) + qfq_front_slot_remove(grp); /* queue is empty */ + else { + u64 roundedS; + + cl->F = cl->S + (u64)len * cl->inv_w; + roundedS = qfq_round_down(cl->S, grp->slot_shift); + if (roundedS == grp->S) + return false; + + qfq_front_slot_remove(grp); + qfq_slot_insert(grp, cl, roundedS); + } + + return true; +} + +static struct sk_buff *qfq_dequeue(struct Qdisc *sch) +{ + struct qfq_sched *q = qdisc_priv(sch); + struct qfq_group *grp; + struct qfq_class *cl; + struct sk_buff *skb; + unsigned int len; + u64 old_V; + + if (!q->bitmaps[ER]) + return NULL; + + grp = qfq_ffs(q, q->bitmaps[ER]); + + cl = qfq_slot_head(grp); + skb = qdisc_dequeue_peeked(cl->qdisc); + if (!skb) { + WARN_ONCE(1, "qfq_dequeue: non-workconserving leaf\n"); + return NULL; + } + + sch->q.qlen--; + qdisc_bstats_update(sch, skb); + + old_V = q->V; + len = qdisc_pkt_len(skb); + q->V += (u64)len * IWSUM; + pr_debug("qfq dequeue: len %u F %lld now %lld\n", + len, (unsigned long long) cl->F, (unsigned long long) q->V); + + if (qfq_update_class(grp, cl)) { + u64 old_F = grp->F; + + cl = qfq_slot_scan(grp); + if (!cl) + __clear_bit(grp->index, &q->bitmaps[ER]); + else { + u64 roundedS = qfq_round_down(cl->S, grp->slot_shift); + unsigned int s; + + if (grp->S == roundedS) + goto skip_unblock; + grp->S = roundedS; + grp->F = roundedS + (2ULL << grp->slot_shift); + __clear_bit(grp->index, &q->bitmaps[ER]); + s = qfq_calc_state(q, grp); + __set_bit(grp->index, &q->bitmaps[s]); + } + + qfq_unblock_groups(q, grp->index, old_F); + } + +skip_unblock: + qfq_update_eligible(q, old_V); + + return skb; +} + +/* + * Assign a reasonable start time for a new flow k in group i. + * Admissible values for \hat(F) are multiples of \sigma_i + * no greater than V+\sigma_i . Larger values mean that + * we had a wraparound so we consider the timestamp to be stale. + * + * If F is not stale and F >= V then we set S = F. + * Otherwise we should assign S = V, but this may violate + * the ordering in ER. So, if we have groups in ER, set S to + * the F_j of the first group j which would be blocking us. + * We are guaranteed not to move S backward because + * otherwise our group i would still be blocked. + */ +static void qfq_update_start(struct qfq_sched *q, struct qfq_class *cl) +{ + unsigned long mask; + uint32_t limit, roundedF; + int slot_shift = cl->grp->slot_shift; + + roundedF = qfq_round_down(cl->F, slot_shift); + limit = qfq_round_down(q->V, slot_shift) + (1UL << slot_shift); + + if (!qfq_gt(cl->F, q->V) || qfq_gt(roundedF, limit)) { + /* timestamp was stale */ + mask = mask_from(q->bitmaps[ER], cl->grp->index); + if (mask) { + struct qfq_group *next = qfq_ffs(q, mask); + if (qfq_gt(roundedF, next->F)) { + cl->S = next->F; + return; + } + } + cl->S = q->V; + } else /* timestamp is not stale */ + cl->S = cl->F; +} + +static int qfq_enqueue(struct sk_buff *skb, struct Qdisc *sch) +{ + struct qfq_sched *q = qdisc_priv(sch); + struct qfq_group *grp; + struct qfq_class *cl; + int err; + u64 roundedS; + int s; + + cl = qfq_classify(skb, sch, &err); + if (cl == NULL) { + if (err & __NET_XMIT_BYPASS) + sch->qstats.drops++; + kfree_skb(skb); + return err; + } + pr_debug("qfq_enqueue: cl = %x\n", cl->common.classid); + + err = qdisc_enqueue(skb, cl->qdisc); + if (unlikely(err != NET_XMIT_SUCCESS)) { + pr_debug("qfq_enqueue: enqueue failed %d\n", err); + if (net_xmit_drop_count(err)) { + cl->qstats.drops++; + sch->qstats.drops++; + } + return err; + } + + bstats_update(&cl->bstats, skb); + ++sch->q.qlen; + + /* If the new skb is not the head of queue, then done here. */ + if (cl->qdisc->q.qlen != 1) + return err; + + /* If reach this point, queue q was idle */ + grp = cl->grp; + qfq_update_start(q, cl); + + /* compute new finish time and rounded start. */ + cl->F = cl->S + (u64)qdisc_pkt_len(skb) * cl->inv_w; + roundedS = qfq_round_down(cl->S, grp->slot_shift); + + /* + * insert cl in the correct bucket. + * If cl->S >= grp->S we don't need to adjust the + * bucket list and simply go to the insertion phase. + * Otherwise grp->S is decreasing, we must make room + * in the bucket list, and also recompute the group state. + * Finally, if there were no flows in this group and nobody + * was in ER make sure to adjust V. + */ + if (grp->full_slots) { + if (!qfq_gt(grp->S, cl->S)) + goto skip_update; + + /* create a slot for this cl->S */ + qfq_slot_rotate(grp, roundedS); + /* group was surely ineligible, remove */ + __clear_bit(grp->index, &q->bitmaps[IR]); + __clear_bit(grp->index, &q->bitmaps[IB]); + } else if (!q->bitmaps[ER] && qfq_gt(roundedS, q->V)) + q->V = roundedS; + + grp->S = roundedS; + grp->F = roundedS + (2ULL << grp->slot_shift); + s = qfq_calc_state(q, grp); + __set_bit(grp->index, &q->bitmaps[s]); + + pr_debug("qfq enqueue: new state %d %#lx S %lld F %lld V %lld\n", + s, q->bitmaps[s], + (unsigned long long) cl->S, + (unsigned long long) cl->F, + (unsigned long long) q->V); + +skip_update: + qfq_slot_insert(grp, cl, roundedS); + + return err; +} + + +static void qfq_slot_remove(struct qfq_sched *q, struct qfq_group *grp, + struct qfq_class *cl) +{ + unsigned int i, offset; + u64 roundedS; + + roundedS = qfq_round_down(cl->S, grp->slot_shift); + offset = (roundedS - grp->S) >> grp->slot_shift; + i = (grp->front + offset) % QFQ_MAX_SLOTS; + + hlist_del(&cl->next); + if (hlist_empty(&grp->slots[i])) + __clear_bit(offset, &grp->full_slots); +} + +/* + * called to forcibly destroy a queue. + * If the queue is not in the front bucket, or if it has + * other queues in the front bucket, we can simply remove + * the queue with no other side effects. + * Otherwise we must propagate the event up. + */ +static void qfq_deactivate_class(struct qfq_sched *q, struct qfq_class *cl) +{ + struct qfq_group *grp = cl->grp; + unsigned long mask; + u64 roundedS; + int s; + + cl->F = cl->S; + qfq_slot_remove(q, grp, cl); + + if (!grp->full_slots) { + __clear_bit(grp->index, &q->bitmaps[IR]); + __clear_bit(grp->index, &q->bitmaps[EB]); + __clear_bit(grp->index, &q->bitmaps[IB]); + + if (test_bit(grp->index, &q->bitmaps[ER]) && + !(q->bitmaps[ER] & ~((1UL << grp->index) - 1))) { + mask = q->bitmaps[ER] & ((1UL << grp->index) - 1); + if (mask) + mask = ~((1UL << __fls(mask)) - 1); + else + mask = ~0UL; + qfq_move_groups(q, mask, EB, ER); + qfq_move_groups(q, mask, IB, IR); + } + __clear_bit(grp->index, &q->bitmaps[ER]); + } else if (hlist_empty(&grp->slots[grp->front])) { + cl = qfq_slot_scan(grp); + roundedS = qfq_round_down(cl->S, grp->slot_shift); + if (grp->S != roundedS) { + __clear_bit(grp->index, &q->bitmaps[ER]); + __clear_bit(grp->index, &q->bitmaps[IR]); + __clear_bit(grp->index, &q->bitmaps[EB]); + __clear_bit(grp->index, &q->bitmaps[IB]); + grp->S = roundedS; + grp->F = roundedS + (2ULL << grp->slot_shift); + s = qfq_calc_state(q, grp); + __set_bit(grp->index, &q->bitmaps[s]); + } + } + + qfq_update_eligible(q, q->V); +} + +static void qfq_qlen_notify(struct Qdisc *sch, unsigned long arg) +{ + struct qfq_sched *q = qdisc_priv(sch); + struct qfq_class *cl = (struct qfq_class *)arg; + + if (cl->qdisc->q.qlen == 0) + qfq_deactivate_class(q, cl); +} + +static unsigned int qfq_drop(struct Qdisc *sch) +{ + struct qfq_sched *q = qdisc_priv(sch); + struct qfq_group *grp; + unsigned int i, j, len; + + for (i = 0; i <= QFQ_MAX_INDEX; i++) { + grp = &q->groups[i]; + for (j = 0; j < QFQ_MAX_SLOTS; j++) { + struct qfq_class *cl; + struct hlist_node *n; + + hlist_for_each_entry(cl, n, &grp->slots[j], next) { + + if (!cl->qdisc->ops->drop) + continue; + + len = cl->qdisc->ops->drop(cl->qdisc); + if (len > 0) { + sch->q.qlen--; + if (!cl->qdisc->q.qlen) + qfq_deactivate_class(q, cl); + + return len; + } + } + } + } + + return 0; +} + +static int qfq_init_qdisc(struct Qdisc *sch, struct nlattr *opt) +{ + struct qfq_sched *q = qdisc_priv(sch); + struct qfq_group *grp; + int i, j, err; + + err = qdisc_class_hash_init(&q->clhash); + if (err < 0) + return err; + + for (i = 0; i <= QFQ_MAX_INDEX; i++) { + grp = &q->groups[i]; + grp->index = i; + grp->slot_shift = QFQ_MTU_SHIFT + FRAC_BITS + - (QFQ_MAX_INDEX - i); + for (j = 0; j < QFQ_MAX_SLOTS; j++) + INIT_HLIST_HEAD(&grp->slots[j]); + } + + return 0; +} + +static void qfq_reset_qdisc(struct Qdisc *sch) +{ + struct qfq_sched *q = qdisc_priv(sch); + struct qfq_group *grp; + struct qfq_class *cl; + struct hlist_node *n, *tmp; + unsigned int i, j; + + for (i = 0; i <= QFQ_MAX_INDEX; i++) { + grp = &q->groups[i]; + for (j = 0; j < QFQ_MAX_SLOTS; j++) { + hlist_for_each_entry_safe(cl, n, tmp, + &grp->slots[j], next) { + qfq_deactivate_class(q, cl); + } + } + } + + for (i = 0; i < q->clhash.hashsize; i++) { + hlist_for_each_entry(cl, n, &q->clhash.hash[i], common.hnode) + qdisc_reset(cl->qdisc); + } + sch->q.qlen = 0; +} + +static void qfq_destroy_qdisc(struct Qdisc *sch) +{ + struct qfq_sched *q = qdisc_priv(sch); + struct qfq_class *cl; + struct hlist_node *n, *next; + unsigned int i; + + tcf_destroy_chain(&q->filter_list); + + for (i = 0; i < q->clhash.hashsize; i++) { + hlist_for_each_entry_safe(cl, n, next, &q->clhash.hash[i], + common.hnode) { + qfq_destroy_class(sch, cl); + } + } + qdisc_class_hash_destroy(&q->clhash); +} + +static const struct Qdisc_class_ops qfq_class_ops = { + .change = qfq_change_class, + .delete = qfq_delete_class, + .get = qfq_get_class, + .put = qfq_put_class, + .tcf_chain = qfq_tcf_chain, + .bind_tcf = qfq_bind_tcf, + .unbind_tcf = qfq_unbind_tcf, + .graft = qfq_graft_class, + .leaf = qfq_class_leaf, + .qlen_notify = qfq_qlen_notify, + .dump = qfq_dump_class, + .dump_stats = qfq_dump_class_stats, + .walk = qfq_walk, +}; + +static struct Qdisc_ops qfq_qdisc_ops __read_mostly = { + .cl_ops = &qfq_class_ops, + .id = "qfq", + .priv_size = sizeof(struct qfq_sched), + .enqueue = qfq_enqueue, + .dequeue = qfq_dequeue, + .peek = qdisc_peek_dequeued, + .drop = qfq_drop, + .init = qfq_init_qdisc, + .reset = qfq_reset_qdisc, + .destroy = qfq_destroy_qdisc, + .owner = THIS_MODULE, +}; + +static int __init qfq_init(void) +{ + return register_qdisc(&qfq_qdisc_ops); +} + +static void __exit qfq_exit(void) +{ + unregister_qdisc(&qfq_qdisc_ops); +} + +module_init(qfq_init); +module_exit(qfq_exit); +MODULE_LICENSE("GPL"); -- cgit v0.10.2 From 7f4d527f0bf3ddc8c257b21fb9bbada5e49f0ef0 Mon Sep 17 00:00:00 2001 From: Patrick Boettcher Date: Sun, 3 Apr 2011 12:28:08 -0300 Subject: [media] DIB0700: fix typo in dib0700_devices.c Fix typo introduced in b4d6046e841955be9cc49164b03b91c9524f9c2e. Spotted by Dr. David Alan Gilbert. Thanks for that. Signed-off-by: Patrick Boettcher Cc: Dr. David Alan Gilbert Cc: stable@kernel.org Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/dvb/dvb-usb/dib0700_devices.c b/drivers/media/dvb/dvb-usb/dib0700_devices.c index 97af266..72e2370 100644 --- a/drivers/media/dvb/dvb-usb/dib0700_devices.c +++ b/drivers/media/dvb/dvb-usb/dib0700_devices.c @@ -2162,7 +2162,7 @@ struct dibx000_agc_config dib7090_agc_config[2] = { .agc1_pt3 = 98, .agc1_slope1 = 0, .agc1_slope2 = 167, - .agc1_pt1 = 98, + .agc2_pt1 = 98, .agc2_pt2 = 255, .agc2_slope1 = 104, .agc2_slope2 = 0, -- cgit v0.10.2 From b934c20de1398d4a82d2ecfeb588a214a910f13f Mon Sep 17 00:00:00 2001 From: Patrick Boettcher Date: Sun, 3 Apr 2011 12:40:24 -0300 Subject: [media] FLEXCOP-PCI: fix __xlate_proc_name-warning for flexcop-pci This patch fixes the warning about bad names for sys-fs and other kernel-things. The flexcop-pci driver was using '/'-characters in it, which is not good. This has been fixed in several attempts by several people, but obviously never made it into the kernel. Signed-off-by: Patrick Boettcher Cc: Steffen Barszus Cc: Boris Cuber Cc: stable@kernel.org Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/dvb/b2c2/flexcop-pci.c b/drivers/media/dvb/b2c2/flexcop-pci.c index 227c020..4f3e3ce 100644 --- a/drivers/media/dvb/b2c2/flexcop-pci.c +++ b/drivers/media/dvb/b2c2/flexcop-pci.c @@ -38,7 +38,7 @@ MODULE_PARM_DESC(debug, DEBSTATUS); #define DRIVER_VERSION "0.1" -#define DRIVER_NAME "Technisat/B2C2 FlexCop II/IIb/III Digital TV PCI Driver" +#define DRIVER_NAME "flexcop-pci" #define DRIVER_AUTHOR "Patrick Boettcher " struct flexcop_pci { -- cgit v0.10.2 From 71682520b33abef3f6c3fb618cb530826f472476 Mon Sep 17 00:00:00 2001 From: Patrick Boettcher Date: Sun, 3 Apr 2011 12:44:25 -0300 Subject: [media] dib0700: fix possible NULL pointer dereference Seems like 'adap->fe' test for NULL was meant to be before we dereference that pointer. Signed-off-by: Mariusz Kozlowski Signed-off-by: Patrick Boettcher Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/dvb/dvb-usb/dib0700_devices.c b/drivers/media/dvb/dvb-usb/dib0700_devices.c index 72e2370..65214af 100644 --- a/drivers/media/dvb/dvb-usb/dib0700_devices.c +++ b/drivers/media/dvb/dvb-usb/dib0700_devices.c @@ -2440,11 +2440,11 @@ static int tfe7090pvr_frontend0_attach(struct dvb_usb_adapter *adap) dib0700_set_i2c_speed(adap->dev, 340); adap->fe = dvb_attach(dib7000p_attach, &adap->dev->i2c_adap, 0x90, &tfe7090pvr_dib7000p_config[0]); - dib7090_slave_reset(adap->fe); - if (adap->fe == NULL) return -ENODEV; + dib7090_slave_reset(adap->fe); + return 0; } -- cgit v0.10.2 From 974ceab8fd76d795cb6d77b7573a383d2e733ee6 Mon Sep 17 00:00:00 2001 From: Patrick Boettcher Date: Sun, 3 Apr 2011 12:46:02 -0300 Subject: [media] Fix dependencies for Technisat USB2.0 DVB-S/S2 Device is based on STV0903 demod and STV6110x tuner Signed-off-by: Oleg Roitburd Signed-off-by: Patrick Boettcher Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/dvb/dvb-usb/Kconfig b/drivers/media/dvb/dvb-usb/Kconfig index fe4f894..ccbd39a 100644 --- a/drivers/media/dvb/dvb-usb/Kconfig +++ b/drivers/media/dvb/dvb-usb/Kconfig @@ -362,7 +362,7 @@ config DVB_USB_LME2510 config DVB_USB_TECHNISAT_USB2 tristate "Technisat DVB-S/S2 USB2.0 support" depends on DVB_USB - select DVB_STB0899 if !DVB_FE_CUSTOMISE - select DVB_STB6100 if !DVB_FE_CUSTOMISE + select DVB_STV090x if !DVB_FE_CUSTOMISE + select DVB_STV6110x if !DVB_FE_CUSTOMISE help Say Y here to support the Technisat USB2 DVB-S/S2 device -- cgit v0.10.2 From 1c0ce89c87b310e8022f50bb75c1b693ee9d7158 Mon Sep 17 00:00:00 2001 From: Stanislaw Gruszka Date: Fri, 25 Mar 2011 17:59:39 +0100 Subject: iwlegacy: MAINTAINERS Add iwlegacy driver to MAINTAINERS. Signed-off-by: Stanislaw Gruszka Signed-off-by: John W. Linville diff --git a/MAINTAINERS b/MAINTAINERS index 09d3fc0..5dd948b 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -3355,14 +3355,10 @@ F: Documentation/wimax/README.i2400m F: drivers/net/wimax/i2400m/ F: include/linux/wimax/i2400m.h -INTEL PRO/WIRELESS 3945ABG/BG NETWORK CONNECTION SUPPORT +INTEL WIRELESS 3945ABG/BG, 4965AGN (iwlegacy) +M: Stanislaw Gruszka L: linux-wireless@vger.kernel.org -S: Orphan -F: drivers/net/wireless/iwlegacy/ - -INTEL WIRELESS WIFI 4965AGN NETWORK CONNECTION SUPPORT -L: linux-wireless@vger.kernel.org -S: Orphan +S: Supported F: drivers/net/wireless/iwlegacy/ INTEL WIRELESS WIFI LINK (iwlwifi) -- cgit v0.10.2 From 279daf64c01e391379060a6d30e9827cc0c56612 Mon Sep 17 00:00:00 2001 From: Ben Greear Date: Wed, 23 Mar 2011 14:04:31 -0700 Subject: wifi: Add hwflags to debugfs. Aids debugging wifi behaviour. Signed-off-by: Ben Greear Signed-off-by: John W. Linville diff --git a/net/mac80211/debugfs.c b/net/mac80211/debugfs.c index 51f0d78..0a602db 100644 --- a/net/mac80211/debugfs.c +++ b/net/mac80211/debugfs.c @@ -37,7 +37,7 @@ int mac80211_format_buffer(char __user *userbuf, size_t count, return simple_read_from_buffer(userbuf, count, ppos, buf, res); } -#define DEBUGFS_READONLY_FILE(name, fmt, value...) \ +#define DEBUGFS_READONLY_FILE_FN(name, fmt, value...) \ static ssize_t name## _read(struct file *file, char __user *userbuf, \ size_t count, loff_t *ppos) \ { \ @@ -45,14 +45,19 @@ static ssize_t name## _read(struct file *file, char __user *userbuf, \ \ return mac80211_format_buffer(userbuf, count, ppos, \ fmt "\n", ##value); \ -} \ - \ +} + +#define DEBUGFS_READONLY_FILE_OPS(name) \ static const struct file_operations name## _ops = { \ .read = name## _read, \ .open = mac80211_open_file_generic, \ .llseek = generic_file_llseek, \ }; +#define DEBUGFS_READONLY_FILE(name, fmt, value...) \ + DEBUGFS_READONLY_FILE_FN(name, fmt, value) \ + DEBUGFS_READONLY_FILE_OPS(name) + #define DEBUGFS_ADD(name) \ debugfs_create_file(#name, 0400, phyd, local, &name## _ops); @@ -291,11 +296,70 @@ static ssize_t channel_type_read(struct file *file, char __user *user_buf, return simple_read_from_buffer(user_buf, count, ppos, buf, strlen(buf)); } -static const struct file_operations channel_type_ops = { - .read = channel_type_read, - .open = mac80211_open_file_generic, - .llseek = default_llseek, -}; +static ssize_t hwflags_read(struct file *file, char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct ieee80211_local *local = file->private_data; + int mxln = 500; + ssize_t rv; + char *buf = kzalloc(mxln, GFP_KERNEL); + int sf = 0; /* how many written so far */ + + sf += snprintf(buf, mxln - sf, "0x%x\n", local->hw.flags); + if (local->hw.flags & IEEE80211_HW_HAS_RATE_CONTROL) + sf += snprintf(buf + sf, mxln - sf, "HAS_RATE_CONTROL\n"); + if (local->hw.flags & IEEE80211_HW_RX_INCLUDES_FCS) + sf += snprintf(buf + sf, mxln - sf, "RX_INCLUDES_FCS\n"); + if (local->hw.flags & IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING) + sf += snprintf(buf + sf, mxln - sf, + "HOST_BCAST_PS_BUFFERING\n"); + if (local->hw.flags & IEEE80211_HW_2GHZ_SHORT_SLOT_INCAPABLE) + sf += snprintf(buf + sf, mxln - sf, + "2GHZ_SHORT_SLOT_INCAPABLE\n"); + if (local->hw.flags & IEEE80211_HW_2GHZ_SHORT_PREAMBLE_INCAPABLE) + sf += snprintf(buf + sf, mxln - sf, + "2GHZ_SHORT_PREAMBLE_INCAPABLE\n"); + if (local->hw.flags & IEEE80211_HW_SIGNAL_UNSPEC) + sf += snprintf(buf + sf, mxln - sf, "SIGNAL_UNSPEC\n"); + if (local->hw.flags & IEEE80211_HW_SIGNAL_DBM) + sf += snprintf(buf + sf, mxln - sf, "SIGNAL_DBM\n"); + if (local->hw.flags & IEEE80211_HW_NEED_DTIM_PERIOD) + sf += snprintf(buf + sf, mxln - sf, "NEED_DTIM_PERIOD\n"); + if (local->hw.flags & IEEE80211_HW_SPECTRUM_MGMT) + sf += snprintf(buf + sf, mxln - sf, "SPECTRUM_MGMT\n"); + if (local->hw.flags & IEEE80211_HW_AMPDU_AGGREGATION) + sf += snprintf(buf + sf, mxln - sf, "AMPDU_AGGREGATION\n"); + if (local->hw.flags & IEEE80211_HW_SUPPORTS_PS) + sf += snprintf(buf + sf, mxln - sf, "SUPPORTS_PS\n"); + if (local->hw.flags & IEEE80211_HW_PS_NULLFUNC_STACK) + sf += snprintf(buf + sf, mxln - sf, "PS_NULLFUNC_STACK\n"); + if (local->hw.flags & IEEE80211_HW_SUPPORTS_DYNAMIC_PS) + sf += snprintf(buf + sf, mxln - sf, "SUPPORTS_DYNAMIC_PS\n"); + if (local->hw.flags & IEEE80211_HW_MFP_CAPABLE) + sf += snprintf(buf + sf, mxln - sf, "MFP_CAPABLE\n"); + if (local->hw.flags & IEEE80211_HW_BEACON_FILTER) + sf += snprintf(buf + sf, mxln - sf, "BEACON_FILTER\n"); + if (local->hw.flags & IEEE80211_HW_SUPPORTS_STATIC_SMPS) + sf += snprintf(buf + sf, mxln - sf, "SUPPORTS_STATIC_SMPS\n"); + if (local->hw.flags & IEEE80211_HW_SUPPORTS_DYNAMIC_SMPS) + sf += snprintf(buf + sf, mxln - sf, "SUPPORTS_DYNAMIC_SMPS\n"); + if (local->hw.flags & IEEE80211_HW_SUPPORTS_UAPSD) + sf += snprintf(buf + sf, mxln - sf, "SUPPORTS_UAPSD\n"); + if (local->hw.flags & IEEE80211_HW_REPORTS_TX_ACK_STATUS) + sf += snprintf(buf + sf, mxln - sf, "REPORTS_TX_ACK_STATUS\n"); + if (local->hw.flags & IEEE80211_HW_CONNECTION_MONITOR) + sf += snprintf(buf + sf, mxln - sf, "CONNECTION_MONITOR\n"); + if (local->hw.flags & IEEE80211_HW_SUPPORTS_CQM_RSSI) + sf += snprintf(buf + sf, mxln - sf, "SUPPORTS_CQM_RSSI\n"); + if (local->hw.flags & IEEE80211_HW_SUPPORTS_PER_STA_GTK) + sf += snprintf(buf + sf, mxln - sf, "SUPPORTS_PER_STA_GTK\n"); + if (local->hw.flags & IEEE80211_HW_AP_LINK_PS) + sf += snprintf(buf + sf, mxln - sf, "AP_LINK_PS\n"); + + rv = simple_read_from_buffer(user_buf, count, ppos, buf, strlen(buf)); + kfree(buf); + return rv; +} static ssize_t queues_read(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) @@ -315,11 +379,9 @@ static ssize_t queues_read(struct file *file, char __user *user_buf, return simple_read_from_buffer(user_buf, count, ppos, buf, res); } -static const struct file_operations queues_ops = { - .read = queues_read, - .open = mac80211_open_file_generic, - .llseek = default_llseek, -}; +DEBUGFS_READONLY_FILE_OPS(hwflags); +DEBUGFS_READONLY_FILE_OPS(channel_type); +DEBUGFS_READONLY_FILE_OPS(queues); /* statistics stuff */ @@ -395,6 +457,7 @@ void debugfs_hw_add(struct ieee80211_local *local) DEBUGFS_ADD(uapsd_queues); DEBUGFS_ADD(uapsd_max_sp_len); DEBUGFS_ADD(channel_type); + DEBUGFS_ADD(hwflags); DEBUGFS_ADD(user_power); DEBUGFS_ADD(power); -- cgit v0.10.2 From b64c6a3d1ab1bab9396e6efd2fd03479be4d0a63 Mon Sep 17 00:00:00 2001 From: Mohammed Shafi Shajakhan Date: Thu, 24 Mar 2011 14:36:16 +0530 Subject: ath9k: cleanup few redundant macros Signed-off-by: Mohammed Shafi Shajakhan Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h index 7c91ba4..a43f059 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h @@ -120,13 +120,11 @@ void ath_descdma_cleanup(struct ath_softc *sc, struct ath_descdma *dd, /* RX / TX */ /***********/ -#define ATH_MAX_ANTENNA 3 #define ATH_RXBUF 512 #define ATH_TXBUF 512 #define ATH_TXBUF_RESERVE 5 #define ATH_MAX_QDEPTH (ATH_TXBUF / 4 - ATH_TXBUF_RESERVE) #define ATH_TXMAXTRY 13 -#define ATH_MGT_TXMAXTRY 4 #define TID_TO_WME_AC(_tid) \ ((((_tid) == 0) || ((_tid) == 3)) ? WME_AC_BE : \ @@ -688,8 +686,6 @@ void ath9k_ps_restore(struct ath_softc *sc); u8 ath_txchainmask_reduction(struct ath_softc *sc, u8 chainmask, u32 rate); -void ath9k_set_bssid_mask(struct ieee80211_hw *hw, struct ieee80211_vif *vif); - void ath_start_rfkill_poll(struct ath_softc *sc); extern void ath9k_rfkill_poll_state(struct ieee80211_hw *hw); void ath9k_calculate_iter_data(struct ieee80211_hw *hw, diff --git a/drivers/net/wireless/ath/ath9k/common.c b/drivers/net/wireless/ath/ath9k/common.c index 615e682..16ba8c6 100644 --- a/drivers/net/wireless/ath/ath9k/common.c +++ b/drivers/net/wireless/ath/ath9k/common.c @@ -116,7 +116,7 @@ void ath9k_cmn_update_ichannel(struct ath9k_channel *ichan, if (chan->band == IEEE80211_BAND_2GHZ) { ichan->chanmode = CHANNEL_G; - ichan->channelFlags = CHANNEL_2GHZ | CHANNEL_OFDM | CHANNEL_G; + ichan->channelFlags = CHANNEL_2GHZ | CHANNEL_OFDM; } else { ichan->chanmode = CHANNEL_A; ichan->channelFlags = CHANNEL_5GHZ | CHANNEL_OFDM; diff --git a/drivers/net/wireless/ath/ath9k/mac.c b/drivers/net/wireless/ath/ath9k/mac.c index 05efcfb..6f431cb 100644 --- a/drivers/net/wireless/ath/ath9k/mac.c +++ b/drivers/net/wireless/ath/ath9k/mac.c @@ -713,7 +713,6 @@ EXPORT_SYMBOL(ath9k_hw_abortpcurecv); bool ath9k_hw_stopdmarecv(struct ath_hw *ah) { #define AH_RX_STOP_DMA_TIMEOUT 10000 /* usec */ -#define AH_RX_TIME_QUANTUM 100 /* usec */ struct ath_common *common = ath9k_hw_common(ah); int i; @@ -737,7 +736,6 @@ bool ath9k_hw_stopdmarecv(struct ath_hw *ah) return true; } -#undef AH_RX_TIME_QUANTUM #undef AH_RX_STOP_DMA_TIMEOUT } EXPORT_SYMBOL(ath9k_hw_stopdmarecv); -- cgit v0.10.2 From 468b0d4482cadd174298e2fe9bde6a20044f90f5 Mon Sep 17 00:00:00 2001 From: Mohammed Shafi Shajakhan Date: Thu, 24 Mar 2011 15:49:54 +0530 Subject: ath9k: remove set11n_virtualmorefrag This does not seems to be used anywhere so remove it. Signed-off-by: Mohammed Shafi Shajakhan Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/ar9002_mac.c b/drivers/net/wireless/ath/ath9k/ar9002_mac.c index 399ab3b..8dd8f63 100644 --- a/drivers/net/wireless/ath/ath9k/ar9002_mac.c +++ b/drivers/net/wireless/ath/ath9k/ar9002_mac.c @@ -415,17 +415,6 @@ static void ar9002_hw_set11n_burstduration(struct ath_hw *ah, void *ds, ads->ds_ctl2 |= SM(burstDuration, AR_BurstDur); } -static void ar9002_hw_set11n_virtualmorefrag(struct ath_hw *ah, void *ds, - u32 vmf) -{ - struct ar5416_desc *ads = AR5416DESC(ds); - - if (vmf) - ads->ds_ctl0 |= AR_VirtMoreFrag; - else - ads->ds_ctl0 &= ~AR_VirtMoreFrag; -} - void ath9k_hw_setuprxdesc(struct ath_hw *ah, struct ath_desc *ds, u32 size, u32 flags) { @@ -459,5 +448,4 @@ void ar9002_hw_attach_mac_ops(struct ath_hw *ah) ops->set11n_aggr_last = ar9002_hw_set11n_aggr_last; ops->clr11n_aggr = ar9002_hw_clr11n_aggr; ops->set11n_burstduration = ar9002_hw_set11n_burstduration; - ops->set11n_virtualmorefrag = ar9002_hw_set11n_virtualmorefrag; } diff --git a/drivers/net/wireless/ath/ath9k/ar9003_mac.c b/drivers/net/wireless/ath/ath9k/ar9003_mac.c index 038a0cb..724ac24 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_mac.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_mac.c @@ -485,17 +485,6 @@ static void ar9003_hw_set11n_burstduration(struct ath_hw *ah, void *ds, } -static void ar9003_hw_set11n_virtualmorefrag(struct ath_hw *ah, void *ds, - u32 vmf) -{ - struct ar9003_txc *ads = (struct ar9003_txc *) ds; - - if (vmf) - ads->ctl11 |= AR_VirtMoreFrag; - else - ads->ctl11 &= ~AR_VirtMoreFrag; -} - void ar9003_hw_set_paprd_txdesc(struct ath_hw *ah, void *ds, u8 chains) { struct ar9003_txc *ads = ds; @@ -521,7 +510,6 @@ void ar9003_hw_attach_mac_ops(struct ath_hw *hw) ops->set11n_aggr_last = ar9003_hw_set11n_aggr_last; ops->clr11n_aggr = ar9003_hw_clr11n_aggr; ops->set11n_burstduration = ar9003_hw_set11n_burstduration; - ops->set11n_virtualmorefrag = ar9003_hw_set11n_virtualmorefrag; } void ath9k_hw_set_rx_bufsize(struct ath_hw *ah, u16 buf_size) diff --git a/drivers/net/wireless/ath/ath9k/hw-ops.h b/drivers/net/wireless/ath/ath9k/hw-ops.h index c8f254f..22ee888 100644 --- a/drivers/net/wireless/ath/ath9k/hw-ops.h +++ b/drivers/net/wireless/ath/ath9k/hw-ops.h @@ -122,12 +122,6 @@ static inline void ath9k_hw_set11n_burstduration(struct ath_hw *ah, void *ds, ath9k_hw_ops(ah)->set11n_burstduration(ah, ds, burstDuration); } -static inline void ath9k_hw_set11n_virtualmorefrag(struct ath_hw *ah, void *ds, - u32 vmf) -{ - ath9k_hw_ops(ah)->set11n_virtualmorefrag(ah, ds, vmf); -} - /* Private hardware call ops */ /* PHY ops */ diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h index 4cc320b..031b1bf 100644 --- a/drivers/net/wireless/ath/ath9k/hw.h +++ b/drivers/net/wireless/ath/ath9k/hw.h @@ -628,8 +628,6 @@ struct ath_hw_ops { void (*clr11n_aggr)(struct ath_hw *ah, void *ds); void (*set11n_burstduration)(struct ath_hw *ah, void *ds, u32 burstDuration); - void (*set11n_virtualmorefrag)(struct ath_hw *ah, void *ds, - u32 vmf); }; struct ath_nf_limits { -- cgit v0.10.2 From 2638126a7c7cce87d51ae5d3bfaca9350503c0b4 Mon Sep 17 00:00:00 2001 From: Mohammed Shafi Shajakhan Date: Thu, 24 Mar 2011 19:06:40 +0530 Subject: ath9k_hw: remove ath9k_get_channel_edges This function is nowhere used. Signed-off-by: Mohammed Shafi Shajakhan Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index 298f4d6..be7baf0 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c @@ -156,25 +156,6 @@ u32 ath9k_hw_reverse_bits(u32 val, u32 n) return retval; } -bool ath9k_get_channel_edges(struct ath_hw *ah, - u16 flags, u16 *low, - u16 *high) -{ - struct ath9k_hw_capabilities *pCap = &ah->caps; - - if (flags & CHANNEL_5GHZ) { - *low = pCap->low_5ghz_chan; - *high = pCap->high_5ghz_chan; - return true; - } - if ((flags & CHANNEL_2GHZ)) { - *low = pCap->low_2ghz_chan; - *high = pCap->high_2ghz_chan; - return true; - } - return false; -} - u16 ath9k_hw_computetxtime(struct ath_hw *ah, u8 phy, int kbps, u32 frameLen, u16 rateix, @@ -1867,12 +1848,6 @@ int ath9k_hw_fill_cap_info(struct ath_hw *ah) if (AR_SREV_9300_20_OR_LATER(ah)) ah->misc_mode |= AR_PCU_ALWAYS_PERFORM_KEYSEARCH; - pCap->low_2ghz_chan = 2312; - pCap->high_2ghz_chan = 2732; - - pCap->low_5ghz_chan = 4920; - pCap->high_5ghz_chan = 6100; - common->crypt_caps |= ATH_CRYPT_CAP_CIPHER_AESCCM; if (ah->hw_version.devid != AR2427_DEVID_PCIE) diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h index 031b1bf..a778b66 100644 --- a/drivers/net/wireless/ath/ath9k/hw.h +++ b/drivers/net/wireless/ath/ath9k/hw.h @@ -190,8 +190,6 @@ enum ath9k_hw_caps { struct ath9k_hw_capabilities { u32 hw_caps; /* ATH9K_HW_CAP_* from ath9k_hw_caps */ - u16 low_5ghz_chan, high_5ghz_chan; - u16 low_2ghz_chan, high_2ghz_chan; u16 rts_aggr_limit; u8 tx_chainmask; u8 rx_chainmask; @@ -900,7 +898,6 @@ bool ath9k_hw_wait(struct ath_hw *ah, u32 reg, u32 mask, u32 val, u32 timeout); void ath9k_hw_write_array(struct ath_hw *ah, struct ar5416IniArray *array, int column, unsigned int *writecnt); u32 ath9k_hw_reverse_bits(u32 val, u32 n); -bool ath9k_get_channel_edges(struct ath_hw *ah, u16 flags, u16 *low, u16 *high); u16 ath9k_hw_computetxtime(struct ath_hw *ah, u8 phy, int kbps, u32 frameLen, u16 rateix, bool shortPreamble); -- cgit v0.10.2 From 1ed76487ce115110171480deabd3cd4656f9803e Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Thu, 24 Mar 2011 19:46:18 +0100 Subject: mac80211: fix suppressing probe responses in ad-hoc mode The commit "mac80211: reply to directed probes in IBSS" changed ad-hoc specific code to respond to unicast probe requests, even if drv_tx_last_beacon returns false, however due to confusion over the meaning of the IEEE80211_RX_RA_MATCH flag, it also unconditionally enabled responding to multicast probe requests. Fix this by explicitly checking for a multicast destination address instead. Signed-off-by: Felix Fietkau Signed-off-by: John W. Linville diff --git a/net/mac80211/ibss.c b/net/mac80211/ibss.c index 3e81af1..1488396 100644 --- a/net/mac80211/ibss.c +++ b/net/mac80211/ibss.c @@ -661,7 +661,6 @@ static void ieee80211_sta_find_ibss(struct ieee80211_sub_if_data *sdata) static void ieee80211_rx_mgmt_probe_req(struct ieee80211_sub_if_data *sdata, struct sk_buff *req) { - struct ieee80211_rx_status *rx_status = IEEE80211_SKB_RXCB(req); struct ieee80211_mgmt *mgmt = (void *)req->data; struct ieee80211_if_ibss *ifibss = &sdata->u.ibss; struct ieee80211_local *local = sdata->local; @@ -685,7 +684,7 @@ static void ieee80211_rx_mgmt_probe_req(struct ieee80211_sub_if_data *sdata, mgmt->bssid, tx_last_beacon); #endif /* CONFIG_MAC80211_IBSS_DEBUG */ - if (!tx_last_beacon && !(rx_status->rx_flags & IEEE80211_RX_RA_MATCH)) + if (!tx_last_beacon && is_multicast_ether_addr(mgmt->da)) return; if (memcmp(mgmt->bssid, ifibss->bssid, ETH_ALEN) != 0 && -- cgit v0.10.2 From 0022801c893e953ebff8e0ad00cc22716055babf Mon Sep 17 00:00:00 2001 From: Yogesh Ashok Powar Date: Thu, 24 Mar 2011 20:49:38 -0700 Subject: mwifiex: remove helper functions for displaying 11n capabilities 'iw list' is sufficient to retrieve the information which was displayed by these functions. Signed-off-by: Yogesh Ashok Powar Signed-off-by: Bing Zhao Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/mwifiex/11n.c b/drivers/net/wireless/mwifiex/11n.c index 0e04a21..7b7b86d 100644 --- a/drivers/net/wireless/mwifiex/11n.c +++ b/drivers/net/wireless/mwifiex/11n.c @@ -140,102 +140,6 @@ mwifiex_fill_cap_info(struct mwifiex_private *priv, } /* - * Shows HT capability information fields. - * - * The following HT capability information fields are supported. - * - Maximum AMSDU length (3839 bytes or 7935 bytes) - * - Beam forming support - * - Greenfield preamble support - * - AMPDU support - * - MIMO Power Save support - * - Rx STBC support - * - Tx STBC support - * - Short GI for 20 MHz support - * - Short GI for 40 MHz support - * - LDPC coded packets receive support - * - Number of delayed BA streams - * - Number of immediate BA streams - * - 10 MHz channel width support - * - 20 MHz channel width support - * - 40 MHz channel width support - * - Presence of Tx antenna A/B/C/D - * - Presence of Rx antenna A/B/C/D - */ -void -mwifiex_show_dot_11n_dev_cap(struct mwifiex_adapter *adapter, u32 cap) -{ - dev_dbg(adapter->dev, "info: GET_HW_SPEC: Max MSDU len = %s octets\n", - (ISSUPP_MAXAMSDU(cap) ? "7935" : "3839")); - dev_dbg(adapter->dev, "info: GET_HW_SPEC: Beam forming %s\n", - (ISSUPP_BEAMFORMING(cap) ? "supported" : "not supported")); - dev_dbg(adapter->dev, "info: GET_HW_SPEC: Greenfield preamble %s\n", - (ISSUPP_GREENFIELD(cap) ? "supported" : "not supported")); - dev_dbg(adapter->dev, "info: GET_HW_SPEC: AMPDU %s\n", - (ISSUPP_AMPDU(cap) ? "supported" : "not supported")); - dev_dbg(adapter->dev, "info: GET_HW_SPEC: MIMO Power Save %s\n", - (ISSUPP_MIMOPS(cap) ? "supported" : "not supported")); - dev_dbg(adapter->dev, "info: GET_HW_SPEC: Rx STBC %s\n", - (ISSUPP_RXSTBC(cap) ? "supported" : "not supported")); - dev_dbg(adapter->dev, "info: GET_HW_SPEC: Tx STBC %s\n", - (ISSUPP_TXSTBC(cap) ? "supported" : "not supported")); - dev_dbg(adapter->dev, "info: GET_HW_SPEC: Short GI for 40 Mhz %s\n", - (ISSUPP_SHORTGI40(cap) ? "supported" : "not supported")); - dev_dbg(adapter->dev, "info: GET_HW_SPEC: Short GI for 20 Mhz %s\n", - (ISSUPP_SHORTGI20(cap) ? "supported" : "not supported")); - dev_dbg(adapter->dev, "info: GET_HW_SPEC: LDPC coded packet receive %s\n", - (ISSUPP_RXLDPC(cap) ? "supported" : "not supported")); - dev_dbg(adapter->dev, - "info: GET_HW_SPEC: Number of Delayed Block Ack streams = %d\n", - GET_DELAYEDBACK(cap)); - dev_dbg(adapter->dev, - "info: GET_HW_SPEC: Number of Immediate Block Ack streams = %d\n", - GET_IMMEDIATEBACK(cap)); - dev_dbg(adapter->dev, "info: GET_HW_SPEC: 40 Mhz channel width %s\n", - (ISSUPP_CHANWIDTH40(cap) ? "supported" : "not supported")); - dev_dbg(adapter->dev, "info: GET_HW_SPEC: 20 Mhz channel width %s\n", - (ISSUPP_CHANWIDTH20(cap) ? "supported" : "not supported")); - dev_dbg(adapter->dev, "info: GET_HW_SPEC: 10 Mhz channel width %s\n", - (ISSUPP_CHANWIDTH10(cap) ? "supported" : "not supported")); - - if (ISSUPP_RXANTENNAA(cap)) - dev_dbg(adapter->dev, "info: GET_HW_SPEC: Prescence of Rx antennea A\n"); - - if (ISSUPP_RXANTENNAB(cap)) - dev_dbg(adapter->dev, "info: GET_HW_SPEC: Prescence of Rx antennea B\n"); - - if (ISSUPP_RXANTENNAC(cap)) - dev_dbg(adapter->dev, "info: GET_HW_SPEC: Prescence of Rx antennea C\n"); - - if (ISSUPP_RXANTENNAD(cap)) - dev_dbg(adapter->dev, "info: GET_HW_SPEC: Prescence of Rx antennea D\n"); - - if (ISSUPP_TXANTENNAA(cap)) - dev_dbg(adapter->dev, "info: GET_HW_SPEC: Prescence of Tx antennea A\n"); - - if (ISSUPP_TXANTENNAB(cap)) - dev_dbg(adapter->dev, "info: GET_HW_SPEC: Prescence of Tx antennea B\n"); - - if (ISSUPP_TXANTENNAC(cap)) - dev_dbg(adapter->dev, "info: GET_HW_SPEC: Prescence of Tx antennea C\n"); - - if (ISSUPP_TXANTENNAD(cap)) - dev_dbg(adapter->dev, "info: GET_HW_SPEC: Prescence of Tx antennea D\n"); - - return; -} - -/* - * Shows HT MCS support field. - */ -void -mwifiex_show_dev_mcs_support(struct mwifiex_adapter *adapter, u8 support) -{ - dev_dbg(adapter->dev, "info: GET_HW_SPEC: MCSs for %dx%d MIMO\n", - GET_RXMCSSUPP(support), GET_TXMCSSUPP(support)); - return; -} - -/* * This function returns the pointer to an entry in BA Stream * table which matches the requested BA status. */ diff --git a/drivers/net/wireless/mwifiex/11n.h b/drivers/net/wireless/mwifiex/11n.h index 769a27f..71a853e 100644 --- a/drivers/net/wireless/mwifiex/11n.h +++ b/drivers/net/wireless/mwifiex/11n.h @@ -24,8 +24,6 @@ #include "11n_rxreorder.h" #include "wmm.h" -void mwifiex_show_dot_11n_dev_cap(struct mwifiex_adapter *adapter, u32 cap); -void mwifiex_show_dev_mcs_support(struct mwifiex_adapter *adapter, u8 support); int mwifiex_ret_11n_delba(struct mwifiex_private *priv, struct host_cmd_ds_command *resp); int mwifiex_ret_11n_addba_req(struct mwifiex_private *priv, diff --git a/drivers/net/wireless/mwifiex/cmdevt.c b/drivers/net/wireless/mwifiex/cmdevt.c index 3a8fe1e..24a3b6b 100644 --- a/drivers/net/wireless/mwifiex/cmdevt.c +++ b/drivers/net/wireless/mwifiex/cmdevt.c @@ -1452,8 +1452,6 @@ int mwifiex_ret_get_hw_spec(struct mwifiex_private *priv, DEFAULT_11N_CAP_MASK; adapter->hw_dev_mcs_support = hw_spec->dev_mcs_support; adapter->usr_dev_mcs_support = adapter->hw_dev_mcs_support; - mwifiex_show_dot_11n_dev_cap(adapter, adapter->hw_dot_11n_dev_cap); - mwifiex_show_dev_mcs_support(adapter, adapter->hw_dev_mcs_support); if (adapter->if_ops.update_mp_end_port) adapter->if_ops.update_mp_end_port(adapter, diff --git a/drivers/net/wireless/mwifiex/fw.h b/drivers/net/wireless/mwifiex/fw.h index e5dae45..d1a5a10 100644 --- a/drivers/net/wireless/mwifiex/fw.h +++ b/drivers/net/wireless/mwifiex/fw.h @@ -196,30 +196,14 @@ enum MWIFIEX_802_11_WEP_STATUS { #define DEFAULT_11N_CAP_MASK (HWSPEC_SHORTGI20_SUPP | HWSPEC_RXSTBC_SUPP) #define ISSUPP_11NENABLED(FwCapInfo) (FwCapInfo & BIT(11)) -#define ISSUPP_MAXAMSDU(Dot11nDevCap) (Dot11nDevCap & BIT(31)) -#define ISSUPP_BEAMFORMING(Dot11nDevCap) (Dot11nDevCap & BIT(30)) #define ISSUPP_GREENFIELD(Dot11nDevCap) (Dot11nDevCap & BIT(29)) -#define ISSUPP_AMPDU(Dot11nDevCap) (Dot11nDevCap & BIT(28)) -#define ISSUPP_MIMOPS(Dot11nDevCap) (Dot11nDevCap & BIT(27)) #define ISSUPP_RXSTBC(Dot11nDevCap) (Dot11nDevCap & BIT(26)) #define ISSUPP_TXSTBC(Dot11nDevCap) (Dot11nDevCap & BIT(25)) #define ISSUPP_SHORTGI40(Dot11nDevCap) (Dot11nDevCap & BIT(24)) #define ISSUPP_SHORTGI20(Dot11nDevCap) (Dot11nDevCap & BIT(23)) -#define ISSUPP_RXLDPC(Dot11nDevCap) (Dot11nDevCap & BIT(22)) #define GET_DELAYEDBACK(Dot11nDevCap) (((Dot11nDevCap >> 20) & 0x03)) -#define GET_IMMEDIATEBACK(Dot11nDevCap) (((Dot11nDevCap >> 18) & 0x03)) #define ISSUPP_CHANWIDTH40(Dot11nDevCap) (Dot11nDevCap & BIT(17)) -#define ISSUPP_CHANWIDTH20(Dot11nDevCap) (Dot11nDevCap & BIT(16)) -#define ISSUPP_CHANWIDTH10(Dot11nDevCap) (Dot11nDevCap & BIT(15)) #define ISENABLED_40MHZ_INTOLARENT(Dot11nDevCap) (Dot11nDevCap & BIT(8)) -#define ISSUPP_RXANTENNAD(Dot11nDevCap) (Dot11nDevCap & BIT(7)) -#define ISSUPP_RXANTENNAC(Dot11nDevCap) (Dot11nDevCap & BIT(6)) -#define ISSUPP_RXANTENNAB(Dot11nDevCap) (Dot11nDevCap & BIT(5)) -#define ISSUPP_RXANTENNAA(Dot11nDevCap) (Dot11nDevCap & BIT(4)) -#define ISSUPP_TXANTENNAD(Dot11nDevCap) (Dot11nDevCap & BIT(3)) -#define ISSUPP_TXANTENNAC(Dot11nDevCap) (Dot11nDevCap & BIT(2)) -#define ISSUPP_TXANTENNAB(Dot11nDevCap) (Dot11nDevCap & BIT(1)) -#define ISSUPP_TXANTENNAA(Dot11nDevCap) (Dot11nDevCap & BIT(0)) #define SETSUPP_CHANWIDTH40(Dot11nDevCap) (Dot11nDevCap |= BIT(17)) #define RESETSUPP_CHANWIDTH40(Dot11nDevCap) (Dot11nDevCap &= ~BIT(17)) #define GET_TXMCSSUPP(DevMCSSupported) (DevMCSSupported >> 4) -- cgit v0.10.2 From 203afecaa320fa8c541ce130aed449ff53f5b4aa Mon Sep 17 00:00:00 2001 From: Marc Yang Date: Thu, 24 Mar 2011 20:49:39 -0700 Subject: mwifiex: remove unnecessary _set_auth functions mwifiex_set_encrypt_mode() mwifiex_set_auth_mode() mwifiex_set_auth() These functions are confusing and misleading. And they are really not needed at all. Some unused definitions are also removed. Signed-off-by: Marc Yang Signed-off-by: Bing Zhao Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/mwifiex/cfg80211.c b/drivers/net/wireless/mwifiex/cfg80211.c index 80f367f..84e33f1 100644 --- a/drivers/net/wireless/mwifiex/cfg80211.c +++ b/drivers/net/wireless/mwifiex/cfg80211.c @@ -1055,11 +1055,10 @@ mwifiex_cfg80211_assoc(struct mwifiex_private *priv, size_t ssid_len, u8 *ssid, * scan. The cfg80211 does not give us the encryption * mode at this stage so just setting it to WEP here. */ - wpa_enabled = 0; - auth_type = MWIFIEX_AUTH_MODE_OPEN; - ret = mwifiex_set_auth(priv, - MWIFIEX_ENCRYPTION_MODE_WEP104, - auth_type, wpa_enabled); + priv->sec_info.encryption_mode = + MWIFIEX_ENCRYPTION_MODE_WEP104; + priv->sec_info.authentication_mode = + MWIFIEX_AUTH_MODE_OPEN; } goto done; @@ -1075,15 +1074,15 @@ mwifiex_cfg80211_assoc(struct mwifiex_private *priv, size_t ssid_len, u8 *ssid, if (sme->crypto.n_ciphers_pairwise) { pairwise_encrypt_mode = mwifiex_get_mwifiex_cipher(sme->crypto. ciphers_pairwise[0], &wpa_enabled); - ret = mwifiex_set_auth(priv, pairwise_encrypt_mode, auth_type, - wpa_enabled); + priv->sec_info.encryption_mode = pairwise_encrypt_mode; + priv->sec_info.authentication_mode = auth_type; } if (sme->crypto.cipher_group) { group_encrypt_mode = mwifiex_get_mwifiex_cipher(sme->crypto. cipher_group, &wpa_enabled); - ret = mwifiex_set_auth(priv, group_encrypt_mode, auth_type, - wpa_enabled); + priv->sec_info.encryption_mode = group_encrypt_mode; + priv->sec_info.authentication_mode = auth_type; } if (sme->ie) ret = mwifiex_set_gen_ie(priv, sme->ie, sme->ie_len); diff --git a/drivers/net/wireless/mwifiex/ioctl.h b/drivers/net/wireless/mwifiex/ioctl.h index d6babfb..b7e4571 100644 --- a/drivers/net/wireless/mwifiex/ioctl.h +++ b/drivers/net/wireless/mwifiex/ioctl.h @@ -277,8 +277,6 @@ struct mwifiex_debug_info { enum { MWIFIEX_AUTH_MODE_OPEN = 0x00, MWIFIEX_AUTH_MODE_SHARED = 0x01, - MWIFIEX_AUTH_MODE_NETWORKEAP = 0x80, - MWIFIEX_AUTH_MODE_AUTO = 0xFF, }; enum { diff --git a/drivers/net/wireless/mwifiex/join.c b/drivers/net/wireless/mwifiex/join.c index d06f4c2..98d76d8 100644 --- a/drivers/net/wireless/mwifiex/join.c +++ b/drivers/net/wireless/mwifiex/join.c @@ -441,20 +441,17 @@ int mwifiex_cmd_802_11_associate(struct mwifiex_private *priv, dev_dbg(priv->adapter->dev, "info: ASSOC_CMD: rates size = %d\n", rates_size); - /* Add the Authentication type to be used for Auth frames if needed */ - if (priv->sec_info.authentication_mode != MWIFIEX_AUTH_MODE_AUTO) { - auth_tlv = (struct mwifiex_ie_types_auth_type *) pos; - auth_tlv->header.type = cpu_to_le16(TLV_TYPE_AUTH_TYPE); - auth_tlv->header.len = cpu_to_le16(sizeof(auth_tlv->auth_type)); - if (priv->sec_info.wep_status == MWIFIEX_802_11_WEP_ENABLED) - auth_tlv->auth_type = cpu_to_le16((u16) priv->sec_info. - authentication_mode); - else - auth_tlv->auth_type = - cpu_to_le16(MWIFIEX_AUTH_MODE_OPEN); - pos += sizeof(auth_tlv->header) + - le16_to_cpu(auth_tlv->header.len); - } + /* Add the Authentication type to be used for Auth frames */ + auth_tlv = (struct mwifiex_ie_types_auth_type *) pos; + auth_tlv->header.type = cpu_to_le16(TLV_TYPE_AUTH_TYPE); + auth_tlv->header.len = cpu_to_le16(sizeof(auth_tlv->auth_type)); + if (priv->sec_info.wep_status == MWIFIEX_802_11_WEP_ENABLED) + auth_tlv->auth_type = cpu_to_le16( + (u16) priv->sec_info.authentication_mode); + else + auth_tlv->auth_type = cpu_to_le16(MWIFIEX_AUTH_MODE_OPEN); + + pos += sizeof(auth_tlv->header) + le16_to_cpu(auth_tlv->header.len); if (IS_SUPPORT_MULTI_BANDS(priv->adapter) && !(ISSUPP_11NENABLED(priv->adapter->fw_cap_info) diff --git a/drivers/net/wireless/mwifiex/main.h b/drivers/net/wireless/mwifiex/main.h index 2b0ad8e..f6fe105 100644 --- a/drivers/net/wireless/mwifiex/main.h +++ b/drivers/net/wireless/mwifiex/main.h @@ -994,11 +994,6 @@ int mwifiex_get_channel_list(struct mwifiex_private *priv, int mwifiex_get_scan_table(struct mwifiex_private *priv, u8 wait_option, struct mwifiex_scan_resp *scanresp); -int mwifiex_get_auth_mode(struct mwifiex_private *priv, - u8 wait_option, u32 *auth_mode); -int mwifiex_get_encrypt_mode(struct mwifiex_private *priv, - u8 wait_option, - u32 *encrypt_mode); int mwifiex_enable_wep_key(struct mwifiex_private *priv, u8 wait_option); int mwifiex_find_best_bss(struct mwifiex_private *priv, u8 wait_option, struct mwifiex_ssid_bssid *ssid_bssid); @@ -1014,9 +1009,6 @@ int mwifiex_drv_get_mode(struct mwifiex_private *priv, u8 wait_option); int mwifiex_drv_change_adhoc_chan(struct mwifiex_private *priv, int channel); -int mwifiex_set_auth(struct mwifiex_private *priv, int encrypt_mode, - int auth_mode, int wpa_enabled); - int mwifiex_set_encode(struct mwifiex_private *priv, const u8 *key, int key_len, u8 key_index, int disable); diff --git a/drivers/net/wireless/mwifiex/sta_ioctl.c b/drivers/net/wireless/mwifiex/sta_ioctl.c index 665a519..362301f 100644 --- a/drivers/net/wireless/mwifiex/sta_ioctl.c +++ b/drivers/net/wireless/mwifiex/sta_ioctl.c @@ -1691,20 +1691,6 @@ static int mwifiex_sec_ioctl_set_wapi_key(struct mwifiex_adapter *adapter, } /* - * IOCTL request handler to set/get authentication mode. - */ -static int mwifiex_set_auth_mode(struct mwifiex_private *priv, u32 auth_mode) -{ - int ret = 0; - - priv->sec_info.authentication_mode = auth_mode; - if (priv->sec_info.authentication_mode == MWIFIEX_AUTH_MODE_NETWORKEAP) - ret = mwifiex_set_wpa_ie_helper(priv, NULL, 0); - - return ret; -} - -/* * IOCTL request handler to set WEP network key. * * This function prepares the correct firmware command and @@ -1999,36 +1985,6 @@ int mwifiex_get_signal_info(struct mwifiex_private *priv, u8 wait_option, } /* - * Sends IOCTL request to set encryption mode. - * - * This function allocates the IOCTL request buffer, fills it - * with requisite parameters and calls the IOCTL handler. - */ -static int mwifiex_set_encrypt_mode(struct mwifiex_private *priv, - u8 wait_option, u32 encrypt_mode) -{ - priv->sec_info.encryption_mode = encrypt_mode; - return 0; -} - -/* - * This function set the authentication parameters. It sets both encryption - * mode and authentication mode, and also enables WPA if required. - */ -int -mwifiex_set_auth(struct mwifiex_private *priv, int encrypt_mode, - int auth_mode, int wpa_enabled) -{ - if (mwifiex_set_encrypt_mode(priv, MWIFIEX_IOCTL_WAIT, encrypt_mode)) - return -EFAULT; - - if (mwifiex_set_auth_mode(priv, auth_mode)) - return -EFAULT; - - return 0; -} - -/* * Sends IOCTL request to set encoding parameters. * * This function allocates the IOCTL request buffer, fills it -- cgit v0.10.2 From 5f9f1812b68a2979bc97399cd4954f1c191986af Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Fri, 25 Mar 2011 21:39:19 +0100 Subject: mac80211: remove the dependency on crypto_blkcipher The only thing that using crypto_blkcipher with ecb does over just using arc4 directly is wrapping the encrypt/decrypt function into a for loop, looping over each individual character. To be able to do this, it pulls in around 40 kb worth of unnecessary kernel modules (at least on a MIPS embedded device). Using arc4 directly not only eliminates those dependencies, it also makes the code smaller. Signed-off-by: Felix Fietkau Signed-off-by: John W. Linville diff --git a/net/mac80211/Kconfig b/net/mac80211/Kconfig index 513f85c..f5fdfcbf 100644 --- a/net/mac80211/Kconfig +++ b/net/mac80211/Kconfig @@ -2,7 +2,6 @@ config MAC80211 tristate "Generic IEEE 802.11 Networking Stack (mac80211)" depends on CFG80211 select CRYPTO - select CRYPTO_ECB select CRYPTO_ARC4 select CRYPTO_AES select CRC32 diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index a404017..6eb2c852 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -809,8 +809,8 @@ struct ieee80211_local { struct rate_control_ref *rate_ctrl; - struct crypto_blkcipher *wep_tx_tfm; - struct crypto_blkcipher *wep_rx_tfm; + struct crypto_cipher *wep_tx_tfm; + struct crypto_cipher *wep_rx_tfm; u32 wep_iv; /* see iface.c */ diff --git a/net/mac80211/tkip.c b/net/mac80211/tkip.c index e840c9c..757e4eb 100644 --- a/net/mac80211/tkip.c +++ b/net/mac80211/tkip.c @@ -202,7 +202,7 @@ EXPORT_SYMBOL(ieee80211_get_tkip_key); * @payload_len is the length of payload (_not_ including IV/ICV length). * @ta is the transmitter addresses. */ -int ieee80211_tkip_encrypt_data(struct crypto_blkcipher *tfm, +int ieee80211_tkip_encrypt_data(struct crypto_cipher *tfm, struct ieee80211_key *key, u8 *pos, size_t payload_len, u8 *ta) { @@ -223,7 +223,7 @@ int ieee80211_tkip_encrypt_data(struct crypto_blkcipher *tfm, * beginning of the buffer containing IEEE 802.11 header payload, i.e., * including IV, Ext. IV, real data, Michael MIC, ICV. @payload_len is the * length of payload, including IV, Ext. IV, MIC, ICV. */ -int ieee80211_tkip_decrypt_data(struct crypto_blkcipher *tfm, +int ieee80211_tkip_decrypt_data(struct crypto_cipher *tfm, struct ieee80211_key *key, u8 *payload, size_t payload_len, u8 *ta, u8 *ra, int only_iv, int queue, diff --git a/net/mac80211/tkip.h b/net/mac80211/tkip.h index 7e83dee..1cab9c8 100644 --- a/net/mac80211/tkip.h +++ b/net/mac80211/tkip.h @@ -15,7 +15,7 @@ u8 *ieee80211_tkip_add_iv(u8 *pos, struct ieee80211_key *key, u16 iv16); -int ieee80211_tkip_encrypt_data(struct crypto_blkcipher *tfm, +int ieee80211_tkip_encrypt_data(struct crypto_cipher *tfm, struct ieee80211_key *key, u8 *pos, size_t payload_len, u8 *ta); enum { @@ -24,7 +24,7 @@ enum { TKIP_DECRYPT_INVALID_KEYIDX = -2, TKIP_DECRYPT_REPLAY = -3, }; -int ieee80211_tkip_decrypt_data(struct crypto_blkcipher *tfm, +int ieee80211_tkip_decrypt_data(struct crypto_cipher *tfm, struct ieee80211_key *key, u8 *payload, size_t payload_len, u8 *ta, u8 *ra, int only_iv, int queue, diff --git a/net/mac80211/wep.c b/net/mac80211/wep.c index 2ff6d1e..a1c6bfd 100644 --- a/net/mac80211/wep.c +++ b/net/mac80211/wep.c @@ -30,17 +30,15 @@ int ieee80211_wep_init(struct ieee80211_local *local) /* start WEP IV from a random value */ get_random_bytes(&local->wep_iv, WEP_IV_LEN); - local->wep_tx_tfm = crypto_alloc_blkcipher("ecb(arc4)", 0, - CRYPTO_ALG_ASYNC); + local->wep_tx_tfm = crypto_alloc_cipher("arc4", 0, CRYPTO_ALG_ASYNC); if (IS_ERR(local->wep_tx_tfm)) { local->wep_rx_tfm = ERR_PTR(-EINVAL); return PTR_ERR(local->wep_tx_tfm); } - local->wep_rx_tfm = crypto_alloc_blkcipher("ecb(arc4)", 0, - CRYPTO_ALG_ASYNC); + local->wep_rx_tfm = crypto_alloc_cipher("arc4", 0, CRYPTO_ALG_ASYNC); if (IS_ERR(local->wep_rx_tfm)) { - crypto_free_blkcipher(local->wep_tx_tfm); + crypto_free_cipher(local->wep_tx_tfm); local->wep_tx_tfm = ERR_PTR(-EINVAL); return PTR_ERR(local->wep_rx_tfm); } @@ -51,9 +49,9 @@ int ieee80211_wep_init(struct ieee80211_local *local) void ieee80211_wep_free(struct ieee80211_local *local) { if (!IS_ERR(local->wep_tx_tfm)) - crypto_free_blkcipher(local->wep_tx_tfm); + crypto_free_cipher(local->wep_tx_tfm); if (!IS_ERR(local->wep_rx_tfm)) - crypto_free_blkcipher(local->wep_rx_tfm); + crypto_free_cipher(local->wep_rx_tfm); } static inline bool ieee80211_wep_weak_iv(u32 iv, int keylen) @@ -127,12 +125,11 @@ static void ieee80211_wep_remove_iv(struct ieee80211_local *local, /* Perform WEP encryption using given key. data buffer must have tailroom * for 4-byte ICV. data_len must not include this ICV. Note: this function * does _not_ add IV. data = RC4(data | CRC32(data)) */ -int ieee80211_wep_encrypt_data(struct crypto_blkcipher *tfm, u8 *rc4key, +int ieee80211_wep_encrypt_data(struct crypto_cipher *tfm, u8 *rc4key, size_t klen, u8 *data, size_t data_len) { - struct blkcipher_desc desc = { .tfm = tfm }; - struct scatterlist sg; __le32 icv; + int i; if (IS_ERR(tfm)) return -1; @@ -140,9 +137,9 @@ int ieee80211_wep_encrypt_data(struct crypto_blkcipher *tfm, u8 *rc4key, icv = cpu_to_le32(~crc32_le(~0, data, data_len)); put_unaligned(icv, (__le32 *)(data + data_len)); - crypto_blkcipher_setkey(tfm, rc4key, klen); - sg_init_one(&sg, data, data_len + WEP_ICV_LEN); - crypto_blkcipher_encrypt(&desc, &sg, &sg, sg.length); + crypto_cipher_setkey(tfm, rc4key, klen); + for (i = 0; i < data_len + WEP_ICV_LEN; i++) + crypto_cipher_encrypt_one(tfm, data + i, data + i); return 0; } @@ -186,19 +183,18 @@ int ieee80211_wep_encrypt(struct ieee80211_local *local, /* Perform WEP decryption using given key. data buffer includes encrypted * payload, including 4-byte ICV, but _not_ IV. data_len must not include ICV. * Return 0 on success and -1 on ICV mismatch. */ -int ieee80211_wep_decrypt_data(struct crypto_blkcipher *tfm, u8 *rc4key, +int ieee80211_wep_decrypt_data(struct crypto_cipher *tfm, u8 *rc4key, size_t klen, u8 *data, size_t data_len) { - struct blkcipher_desc desc = { .tfm = tfm }; - struct scatterlist sg; __le32 crc; + int i; if (IS_ERR(tfm)) return -1; - crypto_blkcipher_setkey(tfm, rc4key, klen); - sg_init_one(&sg, data, data_len + WEP_ICV_LEN); - crypto_blkcipher_decrypt(&desc, &sg, &sg, sg.length); + crypto_cipher_setkey(tfm, rc4key, klen); + for (i = 0; i < data_len + WEP_ICV_LEN; i++) + crypto_cipher_decrypt_one(tfm, data + i, data + i); crc = cpu_to_le32(~crc32_le(~0, data, data_len)); if (memcmp(&crc, data + data_len, WEP_ICV_LEN) != 0) diff --git a/net/mac80211/wep.h b/net/mac80211/wep.h index 58654ee..01e5484 100644 --- a/net/mac80211/wep.h +++ b/net/mac80211/wep.h @@ -18,12 +18,12 @@ int ieee80211_wep_init(struct ieee80211_local *local); void ieee80211_wep_free(struct ieee80211_local *local); -int ieee80211_wep_encrypt_data(struct crypto_blkcipher *tfm, u8 *rc4key, +int ieee80211_wep_encrypt_data(struct crypto_cipher *tfm, u8 *rc4key, size_t klen, u8 *data, size_t data_len); int ieee80211_wep_encrypt(struct ieee80211_local *local, struct sk_buff *skb, const u8 *key, int keylen, int keyidx); -int ieee80211_wep_decrypt_data(struct crypto_blkcipher *tfm, u8 *rc4key, +int ieee80211_wep_decrypt_data(struct crypto_cipher *tfm, u8 *rc4key, size_t klen, u8 *data, size_t data_len); bool ieee80211_wep_is_weak_iv(struct sk_buff *skb, struct ieee80211_key *key); -- cgit v0.10.2 From b93f85f0fb019f527b68569aafb836c94b89a47e Mon Sep 17 00:00:00 2001 From: Bing Zhao Date: Fri, 25 Mar 2011 19:47:01 -0700 Subject: mwifiex: remove macro SHORT_SLOT_TIME_DISABLED and SHORT_SLOT_TIME_ENABLED. Use WLAN_CAPABILITY_SHORT_SLOT_TIME instead. Signed-off-by: Bing Zhao Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/mwifiex/fw.h b/drivers/net/wireless/mwifiex/fw.h index d1a5a10..410be69 100644 --- a/drivers/net/wireless/mwifiex/fw.h +++ b/drivers/net/wireless/mwifiex/fw.h @@ -57,9 +57,6 @@ struct tx_packet_hdr { #define GET_FW_DEFAULT_BANDS(adapter) \ ((adapter->fw_cap_info >> 8) & ALL_802_11_BANDS) -#define SHORT_SLOT_TIME_DISABLED(CapInfo) (CapInfo &= ~BIT(10)) -#define SHORT_SLOT_TIME_ENABLED(CapInfo) (CapInfo |= BIT(10)) - extern u8 supported_rates_b[B_SUPPORTED_RATES]; extern u8 supported_rates_g[G_SUPPORTED_RATES]; extern u8 supported_rates_bg[BG_SUPPORTED_RATES]; diff --git a/drivers/net/wireless/mwifiex/join.c b/drivers/net/wireless/mwifiex/join.c index 98d76d8..8ffb6a8 100644 --- a/drivers/net/wireless/mwifiex/join.c +++ b/drivers/net/wireless/mwifiex/join.c @@ -517,7 +517,7 @@ int mwifiex_cmd_802_11_associate(struct mwifiex_private *priv, tmp_cap = bss_desc->cap_info_bitmap; if (priv->adapter->config_bands == BAND_B) - SHORT_SLOT_TIME_DISABLED(tmp_cap); + tmp_cap &= ~WLAN_CAPABILITY_SHORT_SLOT_TIME; tmp_cap &= CAPINFO_MASK; dev_dbg(priv->adapter->dev, "info: ASSOC_CMD: tmp_cap=%4X CAPINFO_MASK=%4lX\n", @@ -1015,9 +1015,9 @@ mwifiex_cmd_802_11_ad_hoc_start(struct mwifiex_private *priv, + S_DS_GEN + cmd_append_size)); if (adapter->adhoc_start_band == BAND_B) - SHORT_SLOT_TIME_DISABLED(tmp_cap); + tmp_cap &= ~WLAN_CAPABILITY_SHORT_SLOT_TIME; else - SHORT_SLOT_TIME_ENABLED(tmp_cap); + tmp_cap |= WLAN_CAPABILITY_SHORT_SLOT_TIME; adhoc_start->cap_info_bitmap = cpu_to_le16(tmp_cap); -- cgit v0.10.2 From 6d2bd916afe6950b50f750cd82bbb9c6ff58611f Mon Sep 17 00:00:00 2001 From: Marc Yang Date: Fri, 25 Mar 2011 19:47:02 -0700 Subject: mwifiex: use IEEE80211_HT_CAP_ macros for 11n cap_info The hw_dot_11n_dev_cap reported by firmware hw_spec has different format than the 11n capabilities. Hence a lot of SET_ and RESET_ bit operation macros were used to convert the dev_cap format to 11n capability format. However the locally defined 11n ht_cap macros are not necessary as we can use IEEE80211_HT_CAP_ macros directly. The 32-bit dev_cap bitmap is added as comment to explain the mapping between firmware and 11n spec. Some unused macros and unnecessary adapter variables are also removed. Signed-off-by: Marc Yang Signed-off-by: Yogesh Ashok Powar Signed-off-by: Bing Zhao Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/mwifiex/11n.c b/drivers/net/wireless/mwifiex/11n.c index 7b7b86d..ce6421f 100644 --- a/drivers/net/wireless/mwifiex/11n.c +++ b/drivers/net/wireless/mwifiex/11n.c @@ -61,59 +61,42 @@ mwifiex_fill_cap_info(struct mwifiex_private *priv, uint16_t ht_cap_info = le16_to_cpu(ht_cap->ht_cap.cap_info); uint16_t ht_ext_cap = le16_to_cpu(ht_cap->ht_cap.extended_ht_cap_info); - if (ISSUPP_CHANWIDTH40(adapter->hw_dot_11n_dev_cap) && - ISSUPP_CHANWIDTH40(adapter->usr_dot_11n_dev_cap)) - SETHT_SUPPCHANWIDTH(ht_cap_info); + /* Convert dev_cap to IEEE80211_HT_CAP */ + if (ISSUPP_CHANWIDTH40(adapter->hw_dot_11n_dev_cap)) + ht_cap_info |= IEEE80211_HT_CAP_SUP_WIDTH_20_40; else - RESETHT_SUPPCHANWIDTH(ht_cap_info); + ht_cap_info &= ~IEEE80211_HT_CAP_SUP_WIDTH_20_40; - if (ISSUPP_GREENFIELD(adapter->hw_dot_11n_dev_cap) && - ISSUPP_GREENFIELD(adapter->usr_dot_11n_dev_cap)) - SETHT_GREENFIELD(ht_cap_info); + if (ISSUPP_SHORTGI20(adapter->hw_dot_11n_dev_cap)) + ht_cap_info |= IEEE80211_HT_CAP_SGI_20; else - RESETHT_GREENFIELD(ht_cap_info); + ht_cap_info &= ~IEEE80211_HT_CAP_SGI_20; - if (ISSUPP_SHORTGI20(adapter->hw_dot_11n_dev_cap) && - ISSUPP_SHORTGI20(adapter->usr_dot_11n_dev_cap)) - SETHT_SHORTGI20(ht_cap_info); + if (ISSUPP_SHORTGI40(adapter->hw_dot_11n_dev_cap)) + ht_cap_info |= IEEE80211_HT_CAP_SGI_40; else - RESETHT_SHORTGI20(ht_cap_info); + ht_cap_info &= ~IEEE80211_HT_CAP_SGI_40; - if (ISSUPP_SHORTGI40(adapter->hw_dot_11n_dev_cap) && - ISSUPP_SHORTGI40(adapter->usr_dot_11n_dev_cap)) - SETHT_SHORTGI40(ht_cap_info); - else - RESETHT_SHORTGI40(ht_cap_info); - - /* No user config for RX STBC yet */ - if (ISSUPP_RXSTBC(adapter->hw_dot_11n_dev_cap) - && ISSUPP_RXSTBC(adapter->usr_dot_11n_dev_cap)) - SETHT_RXSTBC(ht_cap_info, 1); - else - RESETHT_RXSTBC(ht_cap_info); - - /* No user config for TX STBC yet */ if (ISSUPP_TXSTBC(adapter->hw_dot_11n_dev_cap)) - SETHT_TXSTBC(ht_cap_info); + ht_cap_info |= IEEE80211_HT_CAP_TX_STBC; else - RESETHT_TXSTBC(ht_cap_info); + ht_cap_info &= ~IEEE80211_HT_CAP_TX_STBC; - /* No user config for Delayed BACK yet */ - if (GET_DELAYEDBACK(adapter->hw_dot_11n_dev_cap)) - SETHT_DELAYEDBACK(ht_cap_info); + if (ISSUPP_RXSTBC(adapter->hw_dot_11n_dev_cap)) + ht_cap_info |= 1 << IEEE80211_HT_CAP_RX_STBC_SHIFT; else - RESETHT_DELAYEDBACK(ht_cap_info); + ht_cap_info &= ~(3 << IEEE80211_HT_CAP_RX_STBC_SHIFT); - if (ISENABLED_40MHZ_INTOLARENT(adapter->usr_dot_11n_dev_cap)) - SETHT_40MHZ_INTOLARANT(ht_cap_info); + if (ISSUPP_GREENFIELD(adapter->hw_dot_11n_dev_cap)) + ht_cap_info |= IEEE80211_HT_CAP_GRN_FLD; else - RESETHT_40MHZ_INTOLARANT(ht_cap_info); + ht_cap_info &= ~IEEE80211_HT_CAP_GRN_FLD; - SETAMPDU_SIZE(ht_cap->ht_cap.ampdu_params_info, AMPDU_FACTOR_64K); - SETAMPDU_SPACING(ht_cap->ht_cap.ampdu_params_info, 0); + ht_cap_info &= ~IEEE80211_HT_CAP_MAX_AMSDU; + ht_cap_info |= IEEE80211_HT_CAP_SM_PS; - /* Need change to support 8k AMSDU receive */ - RESETHT_MAXAMSDU(ht_cap_info); + ht_cap->ht_cap.ampdu_params_info |= IEEE80211_HT_AMPDU_PARM_FACTOR; + ht_cap->ht_cap.ampdu_params_info &= ~IEEE80211_HT_AMPDU_PARM_DENSITY; rx_mcs_supp = GET_RXMCSSUPP(adapter->hw_dev_mcs_support); @@ -127,8 +110,7 @@ mwifiex_fill_cap_info(struct mwifiex_private *priv, sizeof(struct ieee80211_mcs_info) - rx_mcs_supp); if (priv->bss_mode == MWIFIEX_BSS_MODE_INFRA || - (ISSUPP_CHANWIDTH40(adapter->hw_dot_11n_dev_cap) && - ISSUPP_CHANWIDTH40(adapter->usr_dot_11n_dev_cap))) + (ht_cap_info & IEEE80211_HT_CAP_SUP_WIDTH_20_40)) /* Set MCS32 for infra mode or ad-hoc mode with 40MHz support */ SETHT_MCS32(ht_cap->ht_cap.mcs.rx_mask); @@ -452,10 +434,10 @@ mwifiex_cmd_append_11n_tlv(struct mwifiex_private *priv, le16_to_cpu(ht_info->header.len)); if (!ISSUPP_CHANWIDTH40 - (priv->adapter->hw_dot_11n_dev_cap) - || !ISSUPP_CHANWIDTH40(priv->adapter-> - usr_dot_11n_dev_cap)) - RESET_CHANWIDTH40(ht_info->ht_info.ht_param); + (priv->adapter->hw_dot_11n_dev_cap)) + ht_info->ht_info.ht_param &= + ~(IEEE80211_HT_PARAM_CHAN_WIDTH_ANY | + IEEE80211_HT_PARAM_CHA_SEC_OFFSET); *buffer += sizeof(struct mwifiex_ie_types_htinfo); ret_len += sizeof(struct mwifiex_ie_types_htinfo); @@ -474,13 +456,13 @@ mwifiex_cmd_append_11n_tlv(struct mwifiex_private *priv, chan_list->chan_scan_param[0].radio_type = mwifiex_band_to_radio_type((u8) bss_desc->bss_band); - if ((ISSUPP_CHANWIDTH40(priv->adapter->hw_dot_11n_dev_cap) && - ISSUPP_CHANWIDTH40(priv->adapter->usr_dot_11n_dev_cap)) - && ISALLOWED_CHANWIDTH40(bss_desc->bcn_ht_info->ht_param)) + if (ISSUPP_CHANWIDTH40(priv->adapter->hw_dot_11n_dev_cap) + && (bss_desc->bcn_ht_info->ht_param & + IEEE80211_HT_PARAM_CHAN_WIDTH_ANY)) SET_SECONDARYCHAN(chan_list->chan_scan_param[0]. radio_type, - GET_SECONDARYCHAN(bss_desc-> - bcn_ht_info->ht_param)); + (bss_desc->bcn_ht_info->ht_param & + IEEE80211_HT_PARAM_CHA_SEC_OFFSET)); *buffer += sizeof(struct mwifiex_ie_types_chan_list_param_set); ret_len += sizeof(struct mwifiex_ie_types_chan_list_param_set); @@ -540,7 +522,8 @@ mwifiex_cfg_tx_buf(struct mwifiex_private *priv, u16 curr_tx_buf_size = 0; if (bss_desc->bcn_ht_cap) { - if (GETHT_MAXAMSDU(le16_to_cpu(bss_desc->bcn_ht_cap->cap_info))) + if (le16_to_cpu(bss_desc->bcn_ht_cap->cap_info) & + IEEE80211_HT_CAP_MAX_AMSDU) max_amsdu = MWIFIEX_TX_DATA_BUF_SIZE_8K; else max_amsdu = MWIFIEX_TX_DATA_BUF_SIZE_4K; diff --git a/drivers/net/wireless/mwifiex/cfg80211.c b/drivers/net/wireless/mwifiex/cfg80211.c index 84e33f1..de86ef8 100644 --- a/drivers/net/wireless/mwifiex/cfg80211.c +++ b/drivers/net/wireless/mwifiex/cfg80211.c @@ -1302,8 +1302,7 @@ mwifiex_setup_ht_caps(struct ieee80211_sta_ht_cap *ht_info, memset(&mcs[rx_mcs_supp], 0, sizeof(struct ieee80211_mcs_info) - rx_mcs_supp); if (priv->bss_mode == MWIFIEX_BSS_MODE_INFRA || - (ISSUPP_CHANWIDTH40(adapter->hw_dot_11n_dev_cap) && - ISSUPP_CHANWIDTH40(adapter->usr_dot_11n_dev_cap))) + ISSUPP_CHANWIDTH40(adapter->hw_dot_11n_dev_cap)) /* Set MCS32 for infra mode or ad-hoc mode with 40MHz support */ SETHT_MCS32(mcs_set.rx_mask); diff --git a/drivers/net/wireless/mwifiex/cmdevt.c b/drivers/net/wireless/mwifiex/cmdevt.c index 24a3b6b..3865dd1 100644 --- a/drivers/net/wireless/mwifiex/cmdevt.c +++ b/drivers/net/wireless/mwifiex/cmdevt.c @@ -1448,10 +1448,7 @@ int mwifiex_ret_get_hw_spec(struct mwifiex_private *priv, } adapter->hw_dot_11n_dev_cap = le32_to_cpu(hw_spec->dot_11n_dev_cap); - adapter->usr_dot_11n_dev_cap = adapter->hw_dot_11n_dev_cap & - DEFAULT_11N_CAP_MASK; adapter->hw_dev_mcs_support = hw_spec->dev_mcs_support; - adapter->usr_dev_mcs_support = adapter->hw_dev_mcs_support; if (adapter->if_ops.update_mp_end_port) adapter->if_ops.update_mp_end_port(adapter, diff --git a/drivers/net/wireless/mwifiex/fw.h b/drivers/net/wireless/mwifiex/fw.h index 410be69..6593e07 100644 --- a/drivers/net/wireless/mwifiex/fw.h +++ b/drivers/net/wireless/mwifiex/fw.h @@ -182,76 +182,34 @@ enum MWIFIEX_802_11_WEP_STATUS { #define MWIFIEX_TX_DATA_BUF_SIZE_4K 4096 #define MWIFIEX_TX_DATA_BUF_SIZE_8K 8192 -#define MAX_RX_AMPDU_SIZE_64K 0x03 #define NON_GREENFIELD_STAS 0x04 -#define HWSPEC_GREENFIELD_SUPP BIT(29) -#define HWSPEC_RXSTBC_SUPP BIT(26) -#define HWSPEC_SHORTGI40_SUPP BIT(24) -#define HWSPEC_SHORTGI20_SUPP BIT(23) -#define HWSPEC_CHANBW40_SUPP BIT(17) - -#define DEFAULT_11N_CAP_MASK (HWSPEC_SHORTGI20_SUPP | HWSPEC_RXSTBC_SUPP) #define ISSUPP_11NENABLED(FwCapInfo) (FwCapInfo & BIT(11)) -#define ISSUPP_GREENFIELD(Dot11nDevCap) (Dot11nDevCap & BIT(29)) -#define ISSUPP_RXSTBC(Dot11nDevCap) (Dot11nDevCap & BIT(26)) -#define ISSUPP_TXSTBC(Dot11nDevCap) (Dot11nDevCap & BIT(25)) -#define ISSUPP_SHORTGI40(Dot11nDevCap) (Dot11nDevCap & BIT(24)) -#define ISSUPP_SHORTGI20(Dot11nDevCap) (Dot11nDevCap & BIT(23)) -#define GET_DELAYEDBACK(Dot11nDevCap) (((Dot11nDevCap >> 20) & 0x03)) + +/* dev_cap bitmap + * BIT + * 0-16 reserved + * 17 IEEE80211_HT_CAP_SUP_WIDTH_20_40 + * 18-22 reserved + * 23 IEEE80211_HT_CAP_SGI_20 + * 24 IEEE80211_HT_CAP_SGI_40 + * 25 IEEE80211_HT_CAP_TX_STBC + * 26 IEEE80211_HT_CAP_RX_STBC + * 27-28 reserved + * 29 IEEE80211_HT_CAP_GRN_FLD + * 30-31 reserved + */ #define ISSUPP_CHANWIDTH40(Dot11nDevCap) (Dot11nDevCap & BIT(17)) -#define ISENABLED_40MHZ_INTOLARENT(Dot11nDevCap) (Dot11nDevCap & BIT(8)) -#define SETSUPP_CHANWIDTH40(Dot11nDevCap) (Dot11nDevCap |= BIT(17)) -#define RESETSUPP_CHANWIDTH40(Dot11nDevCap) (Dot11nDevCap &= ~BIT(17)) -#define GET_TXMCSSUPP(DevMCSSupported) (DevMCSSupported >> 4) +#define ISSUPP_SHORTGI20(Dot11nDevCap) (Dot11nDevCap & BIT(23)) +#define ISSUPP_SHORTGI40(Dot11nDevCap) (Dot11nDevCap & BIT(24)) +#define ISSUPP_TXSTBC(Dot11nDevCap) (Dot11nDevCap & BIT(25)) +#define ISSUPP_RXSTBC(Dot11nDevCap) (Dot11nDevCap & BIT(26)) +#define ISSUPP_GREENFIELD(Dot11nDevCap) (Dot11nDevCap & BIT(29)) + #define GET_RXMCSSUPP(DevMCSSupported) (DevMCSSupported & 0x0f) -#define GETHT_SUPPCHANWIDTH(HTCapInfo) (HTCapInfo & BIT(1)) -#define GETHT_GREENFIELD(HTCapInfo) (HTCapInfo & BIT(4)) -#define GETHT_SHORTGI20(HTCapInfo) (HTCapInfo & BIT(5)) -#define GETHT_SHORTGI40(HTCapInfo) (HTCapInfo & BIT(6)) -#define GETHT_TXSTBC(HTCapInfo) (HTCapInfo & BIT(7)) -#define GETHT_RXSTBC(HTCapInfo) ((HTCapInfo >> 8) & 0x03) -#define GETHT_DELAYEDBACK(HTCapInfo) (HTCapInfo & BIT(10)) -#define GETHT_MAXAMSDU(HTCapInfo) (HTCapInfo & BIT(11)) -#define SETHT_SUPPCHANWIDTH(HTCapInfo) (HTCapInfo |= BIT(1)) -#define SETHT_GREENFIELD(HTCapInfo) (HTCapInfo |= BIT(4)) -#define SETHT_SHORTGI20(HTCapInfo) (HTCapInfo |= BIT(5)) -#define SETHT_SHORTGI40(HTCapInfo) (HTCapInfo |= BIT(6)) -#define SETHT_TXSTBC(HTCapInfo) (HTCapInfo |= BIT(7)) -#define SETHT_RXSTBC(HTCapInfo, value) (HTCapInfo |= (value << 8)) -#define SETHT_DELAYEDBACK(HTCapInfo) (HTCapInfo |= BIT(10)) -#define SETHT_MAXAMSDU(HTCapInfo) (HTCapInfo |= BIT(11)) -#define SETHT_DSSSCCK40(HTCapInfo) (HTCapInfo |= BIT(12)) -#define SETHT_40MHZ_INTOLARANT(HTCapInfo) (HTCapInfo |= BIT(14)) -#define RESETHT_SUPPCHANWIDTH(HTCapInfo) (HTCapInfo &= ~BIT(1)) -#define RESETHT_GREENFIELD(HTCapInfo) (HTCapInfo &= ~BIT(4)) -#define RESETHT_SHORTGI20(HTCapInfo) (HTCapInfo &= ~BIT(5)) -#define RESETHT_SHORTGI40(HTCapInfo) (HTCapInfo &= ~BIT(6)) -#define RESETHT_TXSTBC(HTCapInfo) (HTCapInfo &= ~BIT(7)) -#define RESETHT_RXSTBC(HTCapInfo) (HTCapInfo &= ~(0x03 << 8)) -#define RESETHT_DELAYEDBACK(HTCapInfo) (HTCapInfo &= ~BIT(10)) -#define RESETHT_MAXAMSDU(HTCapInfo) (HTCapInfo &= ~BIT(11)) -#define RESETHT_40MHZ_INTOLARANT(HTCapInfo) (HTCapInfo &= ~BIT(14)) #define RESETHT_EXTCAP_RDG(HTExtCap) (HTExtCap &= ~BIT(11)) #define SETHT_MCS32(x) (x[4] |= 1) -#define SETHT_MCS_SET_DEFINED(x) (x[12] |= 1) -#define SETHT_RX_HIGHEST_DT_SUPP(x, y) ((*(u16 *) (x + 10)) = y) -#define AMPDU_FACTOR_64K 0x03 -#define SETAMPDU_SIZE(x, y) do { \ - x = x & ~0x03; \ - x |= y & 0x03; \ -} while (0) \ - -#define SETAMPDU_SPACING(x, y) do { \ - x = x & ~0x1c; \ - x |= (y & 0x07) << 2; \ -} while (0) \ - -#define ISSUPP_BANDA(FwCapInfo) (FwCapInfo & BIT(10)) -#define ISALLOWED_CHANWIDTH40(Field2) (Field2 & BIT(2)) -#define SET_CHANWIDTH40(Field2) (Field2 |= BIT(2)) -#define RESET_CHANWIDTH40(Field2) (Field2 &= ~(BIT(0) | BIT(1) | BIT(2))) -#define GET_SECONDARYCHAN(Field2) (Field2 & (BIT(0) | BIT(1))) + #define SET_SECONDARYCHAN(RadioType, SECCHAN) (RadioType |= (SECCHAN << 4)) #define LLC_SNAP_LEN 8 diff --git a/drivers/net/wireless/mwifiex/init.c b/drivers/net/wireless/mwifiex/init.c index 07ebc97..1c9315d 100644 --- a/drivers/net/wireless/mwifiex/init.c +++ b/drivers/net/wireless/mwifiex/init.c @@ -267,8 +267,6 @@ static void mwifiex_init_adapter(struct mwifiex_adapter *adapter) memset(adapter->event_body, 0, sizeof(adapter->event_body)); adapter->hw_dot_11n_dev_cap = 0; adapter->hw_dev_mcs_support = 0; - adapter->usr_dot_11n_dev_cap = 0; - adapter->usr_dev_mcs_support = 0; adapter->chan_offset = 0; adapter->adhoc_11n_enabled = false; diff --git a/drivers/net/wireless/mwifiex/join.c b/drivers/net/wireless/mwifiex/join.c index 8ffb6a8..08fa721 100644 --- a/drivers/net/wireless/mwifiex/join.c +++ b/drivers/net/wireless/mwifiex/join.c @@ -970,16 +970,16 @@ mwifiex_cmd_802_11_ad_hoc_start(struct mwifiex_private *priv, cpu_to_le16(sizeof(struct ieee80211_ht_cap)); ht_cap_info = le16_to_cpu(ht_cap->ht_cap.cap_info); - SETHT_SHORTGI20(ht_cap_info); + ht_cap_info |= IEEE80211_HT_CAP_SGI_20; if (adapter->chan_offset) { - SETHT_SHORTGI40(ht_cap_info); - SETHT_DSSSCCK40(ht_cap_info); - SETHT_SUPPCHANWIDTH(ht_cap_info); + ht_cap_info |= IEEE80211_HT_CAP_SGI_40; + ht_cap_info |= IEEE80211_HT_CAP_DSSSCCK40; + ht_cap_info |= IEEE80211_HT_CAP_SUP_WIDTH_20_40; SETHT_MCS32(ht_cap->ht_cap.mcs.rx_mask); } ht_cap->ht_cap.ampdu_params_info - = MAX_RX_AMPDU_SIZE_64K; + = IEEE80211_HT_MAX_AMPDU_64K; ht_cap->ht_cap.mcs.rx_mask[0] = 0xff; pos += sizeof(struct mwifiex_ie_types_htcap); cmd_append_size += @@ -999,7 +999,8 @@ mwifiex_cmd_802_11_ad_hoc_start(struct mwifiex_private *priv, if (adapter->chan_offset) { ht_info->ht_info.ht_param = adapter->chan_offset; - SET_CHANWIDTH40(ht_info->ht_info.ht_param); + ht_info->ht_info.ht_param |= + IEEE80211_HT_PARAM_CHAN_WIDTH_ANY; } ht_info->ht_info.operation_mode = cpu_to_le16(NON_GREENFIELD_STAS); diff --git a/drivers/net/wireless/mwifiex/main.h b/drivers/net/wireless/mwifiex/main.h index f6fe105..7bcb2e9 100644 --- a/drivers/net/wireless/mwifiex/main.h +++ b/drivers/net/wireless/mwifiex/main.h @@ -687,8 +687,6 @@ struct mwifiex_adapter { u8 event_body[MAX_EVENT_SIZE]; u32 hw_dot_11n_dev_cap; u8 hw_dev_mcs_support; - u32 usr_dot_11n_dev_cap; - u8 usr_dev_mcs_support; u8 adhoc_11n_enabled; u8 chan_offset; struct mwifiex_dbg dbg; -- cgit v0.10.2 From 324732848c42bf79988479ee1b4359e15f08154b Mon Sep 17 00:00:00 2001 From: Larry Finger Date: Sun, 27 Mar 2011 16:19:57 -0500 Subject: rtlwifi: Remove unused/unneeded variables Remove some unused variables and correct spelling errors. Signed-off-by: Larry Finger Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/rtlwifi/base.c b/drivers/net/wireless/rtlwifi/base.c index bb0c781..dd5318e 100644 --- a/drivers/net/wireless/rtlwifi/base.c +++ b/drivers/net/wireless/rtlwifi/base.c @@ -432,7 +432,7 @@ static void _rtl_txrate_selectmode(struct ieee80211_hw *hw, } if (rtlpriv->dm.useramask) { - /* TODO we will differentiate adhoc and station futrue */ + /* TODO adhoc and station handled differently in the future */ tcb_desc->mac_id = 0; if ((mac->mode == WIRELESS_MODE_N_24G) || @@ -630,7 +630,7 @@ u8 rtl_is_special_data(struct ieee80211_hw *hw, struct sk_buff *skb, u8 is_tx) const struct iphdr *ip; if (!ieee80211_is_data(fc)) - goto end; + return false; if (ieee80211_is_nullfunc(fc)) return true; @@ -686,7 +686,6 @@ u8 rtl_is_special_data(struct ieee80211_hw *hw, struct sk_buff *skb, u8 is_tx) return true; } -end: return false; } diff --git a/drivers/net/wireless/rtlwifi/core.c b/drivers/net/wireless/rtlwifi/core.c index e4f4aee..8fed3c6 100644 --- a/drivers/net/wireless/rtlwifi/core.c +++ b/drivers/net/wireless/rtlwifi/core.c @@ -35,7 +35,7 @@ /*mutex for start & stop is must here. */ static int rtl_op_start(struct ieee80211_hw *hw) { - int err = 0; + int err; struct rtl_priv *rtlpriv = rtl_priv(hw); struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); @@ -45,10 +45,8 @@ static int rtl_op_start(struct ieee80211_hw *hw) return 0; mutex_lock(&rtlpriv->locks.conf_mutex); err = rtlpriv->intf_ops->adapter_start(hw); - if (err) - goto out; - rtl_watch_dog_timer_callback((unsigned long)hw); -out: + if (!err) + rtl_watch_dog_timer_callback((unsigned long)hw); mutex_unlock(&rtlpriv->locks.conf_mutex); return err; } diff --git a/drivers/net/wireless/rtlwifi/efuse.c b/drivers/net/wireless/rtlwifi/efuse.c index f74a870..5d73c0f 100644 --- a/drivers/net/wireless/rtlwifi/efuse.c +++ b/drivers/net/wireless/rtlwifi/efuse.c @@ -338,11 +338,11 @@ bool efuse_shadow_update_chk(struct ieee80211_hw *hw) struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw)); u8 section_idx, i, Base; u16 words_need = 0, hdr_num = 0, totalbytes, efuse_used; - bool bwordchanged, bresult = true; + bool wordchanged, result = true; for (section_idx = 0; section_idx < 16; section_idx++) { Base = section_idx * 8; - bwordchanged = false; + wordchanged = false; for (i = 0; i < 8; i = i + 2) { if ((rtlefuse->efuse_map[EFUSE_INIT_MAP][Base + i] != @@ -351,11 +351,11 @@ bool efuse_shadow_update_chk(struct ieee80211_hw *hw) rtlefuse->efuse_map[EFUSE_MODIFY_MAP][Base + i + 1])) { words_need++; - bwordchanged = true; + wordchanged = true; } } - if (bwordchanged == true) + if (wordchanged == true) hdr_num++; } @@ -364,14 +364,14 @@ bool efuse_shadow_update_chk(struct ieee80211_hw *hw) if ((totalbytes + efuse_used) >= (EFUSE_MAX_SIZE - EFUSE_OOB_PROTECT_BYTES)) - bresult = false; + result = false; RT_TRACE(rtlpriv, COMP_EFUSE, DBG_LOUD, ("efuse_shadow_update_chk(): totalbytes(%#x), " "hdr_num(%#x), words_need(%#x), efuse_used(%d)\n", totalbytes, hdr_num, words_need, efuse_used)); - return bresult; + return result; } void efuse_shadow_read(struct ieee80211_hw *hw, u8 type, @@ -394,7 +394,7 @@ void efuse_shadow_write(struct ieee80211_hw *hw, u8 type, u16 offset, else if (type == 2) efuse_shadow_write_2byte(hw, offset, (u16) value); else if (type == 4) - efuse_shadow_write_4byte(hw, offset, (u32) value); + efuse_shadow_write_4byte(hw, offset, value); } @@ -572,7 +572,7 @@ static int efuse_one_byte_read(struct ieee80211_hw *hw, u16 addr, u8 *data) { struct rtl_priv *rtlpriv = rtl_priv(hw); u8 tmpidx = 0; - int bresult; + int result; rtl_write_byte(rtlpriv, rtlpriv->cfg->maps[EFUSE_CTRL] + 1, (u8) (addr & 0xff)); @@ -592,19 +592,18 @@ static int efuse_one_byte_read(struct ieee80211_hw *hw, u16 addr, u8 *data) if (tmpidx < 100) { *data = rtl_read_byte(rtlpriv, rtlpriv->cfg->maps[EFUSE_CTRL]); - bresult = true; + result = true; } else { *data = 0xff; - bresult = false; + result = false; } - return bresult; + return result; } static int efuse_one_byte_write(struct ieee80211_hw *hw, u16 addr, u8 data) { struct rtl_priv *rtlpriv = rtl_priv(hw); u8 tmpidx = 0; - bool bresult; RT_TRACE(rtlpriv, COMP_EFUSE, DBG_LOUD, ("Addr = %x Data=%x\n", addr, data)); @@ -626,11 +625,9 @@ static int efuse_one_byte_write(struct ieee80211_hw *hw, u16 addr, u8 data) } if (tmpidx < 100) - bresult = true; - else - bresult = false; + return true; - return bresult; + return false; } static void efuse_read_all_map(struct ieee80211_hw *hw, u8 * efuse) @@ -681,11 +678,10 @@ static int efuse_pg_packet_read(struct ieee80211_hw *hw, u8 offset, u8 *data) { u8 readstate = PG_STATE_HEADER; - bool bcontinual = true; + bool continual = true; u8 efuse_data, word_cnts = 0; u16 efuse_addr = 0; - u8 hworden; u8 tmpdata[8]; if (data == NULL) @@ -696,7 +692,7 @@ static int efuse_pg_packet_read(struct ieee80211_hw *hw, u8 offset, u8 *data) memset(data, 0xff, PGPKT_DATA_SIZE * sizeof(u8)); memset(tmpdata, 0xff, PGPKT_DATA_SIZE * sizeof(u8)); - while (bcontinual && (efuse_addr < EFUSE_MAX_SIZE)) { + while (continual && (efuse_addr < EFUSE_MAX_SIZE)) { if (readstate & PG_STATE_HEADER) { if (efuse_one_byte_read(hw, efuse_addr, &efuse_data) && (efuse_data != 0xFF)) @@ -705,9 +701,9 @@ static int efuse_pg_packet_read(struct ieee80211_hw *hw, u8 offset, u8 *data) offset, tmpdata, &readstate); else - bcontinual = false; + continual = false; } else if (readstate & PG_STATE_DATA) { - efuse_word_enable_data_read(hworden, tmpdata, data); + efuse_word_enable_data_read(0, tmpdata, data); efuse_addr = efuse_addr + (word_cnts * 2) + 1; readstate = PG_STATE_HEADER; } @@ -725,13 +721,13 @@ static int efuse_pg_packet_read(struct ieee80211_hw *hw, u8 offset, u8 *data) } static void efuse_write_data_case1(struct ieee80211_hw *hw, u16 *efuse_addr, - u8 efuse_data, u8 offset, int *bcontinual, + u8 efuse_data, u8 offset, int *continual, u8 *write_state, struct pgpkt_struct *target_pkt, - int *repeat_times, int *bresult, u8 word_en) + int *repeat_times, int *result, u8 word_en) { struct rtl_priv *rtlpriv = rtl_priv(hw); struct pgpkt_struct tmp_pkt; - int bdataempty = true; + bool dataempty = true; u8 originaldata[8 * sizeof(u8)]; u8 badworden = 0x0F; u8 match_word_en, tmp_word_en; @@ -751,10 +747,10 @@ static void efuse_write_data_case1(struct ieee80211_hw *hw, u16 *efuse_addr, u16 address = *efuse_addr + 1 + tmpindex; if (efuse_one_byte_read(hw, address, &efuse_data) && (efuse_data != 0xFF)) - bdataempty = false; + dataempty = false; } - if (bdataempty == false) { + if (dataempty == false) { *efuse_addr = *efuse_addr + (tmp_word_cnts * 2) + 1; *write_state = PG_STATE_HEADER; } else { @@ -811,12 +807,12 @@ static void efuse_write_data_case1(struct ieee80211_hw *hw, u16 *efuse_addr, target_pkt->offset = offset; target_pkt->word_en = tmp_word_en; } else - *bcontinual = false; + *continual = false; *write_state = PG_STATE_HEADER; *repeat_times += 1; if (*repeat_times > EFUSE_REPEAT_THRESHOLD_) { - *bcontinual = false; - *bresult = false; + *continual = false; + *result = false; } } else { *efuse_addr += (2 * tmp_word_cnts) + 1; @@ -830,9 +826,9 @@ static void efuse_write_data_case1(struct ieee80211_hw *hw, u16 *efuse_addr, } static void efuse_write_data_case2(struct ieee80211_hw *hw, u16 *efuse_addr, - int *bcontinual, u8 *write_state, + int *continual, u8 *write_state, struct pgpkt_struct target_pkt, - int *repeat_times, int *bresult) + int *repeat_times, int *result) { struct rtl_priv *rtlpriv = rtl_priv(hw); struct pgpkt_struct tmp_pkt; @@ -852,8 +848,8 @@ static void efuse_write_data_case2(struct ieee80211_hw *hw, u16 *efuse_addr, *write_state = PG_STATE_HEADER; *repeat_times += 1; if (*repeat_times > EFUSE_REPEAT_THRESHOLD_) { - *bcontinual = false; - *bresult = false; + *continual = false; + *result = false; } } else { tmp_pkt.offset = (tmp_header >> 4) & 0x0F; @@ -884,8 +880,8 @@ static void efuse_write_data_case2(struct ieee80211_hw *hw, u16 *efuse_addr, *write_state = PG_STATE_HEADER; *repeat_times += 1; if (*repeat_times > EFUSE_REPEAT_THRESHOLD_) { - *bcontinual = false; - *bresult = false; + *continual = false; + *result = false; } RTPRINT(rtlpriv, FEEPROM, EFUSE_PG, @@ -899,7 +895,7 @@ static int efuse_pg_packet_write(struct ieee80211_hw *hw, struct rtl_priv *rtlpriv = rtl_priv(hw); struct pgpkt_struct target_pkt; u8 write_state = PG_STATE_HEADER; - int bcontinual = true, bdataempty = true, bresult = true; + int continual = true, dataempty = true, result = true; u16 efuse_addr = 0; u8 efuse_data; u8 target_word_cnts = 0; @@ -923,11 +919,11 @@ static int efuse_pg_packet_write(struct ieee80211_hw *hw, RTPRINT(rtlpriv, FEEPROM, EFUSE_PG, ("efuse Power ON\n")); - while (bcontinual && (efuse_addr < + while (continual && (efuse_addr < (EFUSE_MAX_SIZE - EFUSE_OOB_PROTECT_BYTES))) { if (write_state == PG_STATE_HEADER) { - bdataempty = true; + dataempty = true; badworden = 0x0F; RTPRINT(rtlpriv, FEEPROM, EFUSE_PG, ("efuse PG_STATE_HEADER\n")); @@ -936,32 +932,30 @@ static int efuse_pg_packet_write(struct ieee80211_hw *hw, (efuse_data != 0xFF)) efuse_write_data_case1(hw, &efuse_addr, efuse_data, offset, - &bcontinual, + &continual, &write_state, &target_pkt, - &repeat_times, &bresult, + &repeat_times, &result, word_en); else efuse_write_data_case2(hw, &efuse_addr, - &bcontinual, + &continual, &write_state, target_pkt, &repeat_times, - &bresult); + &result); } else if (write_state == PG_STATE_DATA) { RTPRINT(rtlpriv, FEEPROM, EFUSE_PG, ("efuse PG_STATE_DATA\n")); - badworden = 0x0f; badworden = efuse_word_enable_data_write(hw, efuse_addr + 1, target_pkt.word_en, target_pkt.data); if ((badworden & 0x0F) == 0x0F) { - bcontinual = false; + continual = false; } else { - efuse_addr = - efuse_addr + (2 * target_word_cnts) + 1; + efuse_addr += (2 * target_word_cnts) + 1; target_pkt.offset = offset; target_pkt.word_en = badworden; @@ -971,8 +965,8 @@ static int efuse_pg_packet_write(struct ieee80211_hw *hw, write_state = PG_STATE_HEADER; repeat_times++; if (repeat_times > EFUSE_REPEAT_THRESHOLD_) { - bcontinual = false; - bresult = false; + continual = false; + result = false; } RTPRINT(rtlpriv, FEEPROM, EFUSE_PG, ("efuse PG_STATE_HEADER-3\n")); @@ -1072,13 +1066,13 @@ static u8 efuse_word_enable_data_write(struct ieee80211_hw *hw, return badworden; } -static void efuse_power_switch(struct ieee80211_hw *hw, u8 bwrite, u8 pwrstate) +static void efuse_power_switch(struct ieee80211_hw *hw, u8 write, u8 pwrstate) { struct rtl_priv *rtlpriv = rtl_priv(hw); u8 tempval; u16 tmpV16; - if (pwrstate == true) { + if (pwrstate) { tmpV16 = rtl_read_word(rtlpriv, rtlpriv->cfg->maps[SYS_ISO_CTRL]); if (!(tmpV16 & rtlpriv->cfg->maps[EFUSE_PWC_EV12V])) { @@ -1106,8 +1100,8 @@ static void efuse_power_switch(struct ieee80211_hw *hw, u8 bwrite, u8 pwrstate) } } - if (pwrstate == true) { - if (bwrite == true) { + if (pwrstate) { + if (write) { tempval = rtl_read_byte(rtlpriv, rtlpriv->cfg->maps[EFUSE_TEST] + 3); @@ -1119,7 +1113,7 @@ static void efuse_power_switch(struct ieee80211_hw *hw, u8 bwrite, u8 pwrstate) } } else { - if (bwrite == true) { + if (write) { tempval = rtl_read_byte(rtlpriv, rtlpriv->cfg->maps[EFUSE_TEST] + 3); @@ -1134,12 +1128,12 @@ static void efuse_power_switch(struct ieee80211_hw *hw, u8 bwrite, u8 pwrstate) static u16 efuse_get_current_size(struct ieee80211_hw *hw) { - int bcontinual = true; + int continual = true; u16 efuse_addr = 0; u8 hoffset, hworden; u8 efuse_data, word_cnts; - while (bcontinual && efuse_one_byte_read(hw, efuse_addr, &efuse_data) + while (continual && efuse_one_byte_read(hw, efuse_addr, &efuse_data) && (efuse_addr < EFUSE_MAX_SIZE)) { if (efuse_data != 0xFF) { hoffset = (efuse_data >> 4) & 0x0F; @@ -1147,7 +1141,7 @@ static u16 efuse_get_current_size(struct ieee80211_hw *hw) word_cnts = efuse_calculate_word_cnts(hworden); efuse_addr = efuse_addr + (word_cnts * 2) + 1; } else { - bcontinual = false; + continual = false; } } diff --git a/drivers/net/wireless/rtlwifi/pci.c b/drivers/net/wireless/rtlwifi/pci.c index 9cd7703..efded43 100644 --- a/drivers/net/wireless/rtlwifi/pci.c +++ b/drivers/net/wireless/rtlwifi/pci.c @@ -113,32 +113,19 @@ static void _rtl_pci_update_default_setting(struct ieee80211_hw *hw) /*Set HW definition to determine if it supports ASPM. */ switch (rtlpci->const_support_pciaspm) { - case 0:{ - /*Not support ASPM. */ - bool support_aspm = false; - ppsc->support_aspm = support_aspm; - break; - } - case 1:{ - /*Support ASPM. */ - bool support_aspm = true; - bool support_backdoor = true; - ppsc->support_aspm = support_aspm; - - /*if(priv->oem_id == RT_CID_TOSHIBA && - !priv->ndis_adapter.amd_l1_patch) - support_backdoor = false; */ - - ppsc->support_backdoor = support_backdoor; - - break; - } + case 0: + /*Not support ASPM. */ + ppsc->support_aspm = false; + break; + case 1: + /*Support ASPM. */ + ppsc->support_aspm = true; + ppsc->support_backdoor = true; + break; case 2: /*ASPM value set by chipset. */ - if (pcibridge_vendor == PCI_BRIDGE_VENDOR_INTEL) { - bool support_aspm = true; - ppsc->support_aspm = support_aspm; - } + if (pcibridge_vendor == PCI_BRIDGE_VENDOR_INTEL) + ppsc->support_aspm = true; break; default: RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, @@ -152,13 +139,11 @@ static bool _rtl_pci_platform_switch_device_pci_aspm( u8 value) { struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); - bool bresult = false; value |= 0x40; - pci_write_config_byte(rtlpci->pdev, 0x80, value); - return bresult; + return false; } /*When we set 0x01 to enable clk request. Set 0x0 to disable clk req.*/ @@ -166,14 +151,11 @@ static bool _rtl_pci_switch_clk_req(struct ieee80211_hw *hw, u8 value) { struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); u8 buffer; - bool bresult = false; buffer = value; - pci_write_config_byte(rtlpci->pdev, 0x81, value); - bresult = true; - return bresult; + return true; } /*Disable RTL8192SE ASPM & Disable Pci Bridge ASPM*/ @@ -191,6 +173,7 @@ static void rtl_pci_disable_aspm(struct ieee80211_hw *hw) u16 pcibridge_linkctrlreg = pcipriv->ndis_adapter. pcibridge_linkctrlreg; u16 aspmlevel = 0; + u8 tmp_u1b = 0; if (pcibridge_vendor == PCI_BRIDGE_VENDOR_UNKNOWN) { RT_TRACE(rtlpriv, COMP_POWER, DBG_TRACE, @@ -204,11 +187,8 @@ static void rtl_pci_disable_aspm(struct ieee80211_hw *hw) _rtl_pci_switch_clk_req(hw, 0x0); } - if (1) { - /*for promising device will in L0 state after an I/O. */ - u8 tmp_u1b; - pci_read_config_byte(rtlpci->pdev, 0x80, &tmp_u1b); - } + /*for promising device will in L0 state after an I/O. */ + pci_read_config_byte(rtlpci->pdev, 0x80, &tmp_u1b); /*Set corresponding value. */ aspmlevel |= BIT(0) | BIT(1); @@ -224,7 +204,6 @@ static void rtl_pci_disable_aspm(struct ieee80211_hw *hw) rtl_pci_raw_write_port_uchar(PCI_CONF_DATA, pcibridge_linkctrlreg); udelay(50); - } /* diff --git a/drivers/net/wireless/rtlwifi/pci.h b/drivers/net/wireless/rtlwifi/pci.h index 0caa814..12747b9 100644 --- a/drivers/net/wireless/rtlwifi/pci.h +++ b/drivers/net/wireless/rtlwifi/pci.h @@ -192,8 +192,8 @@ struct rtl_pci { u8 const_devicepci_aspm_setting; /*If it supports ASPM, Offset[560h] = 0x40, otherwise Offset[560h] = 0x00. */ - bool b_support_aspm; - bool b_support_backdoor; + bool support_aspm; + bool support_backdoor; /*QOS & EDCA */ enum acm_method acm_method; diff --git a/drivers/net/wireless/rtlwifi/ps.c b/drivers/net/wireless/rtlwifi/ps.c index 6b7e217..c8395fb 100644 --- a/drivers/net/wireless/rtlwifi/ps.c +++ b/drivers/net/wireless/rtlwifi/ps.c @@ -63,7 +63,6 @@ EXPORT_SYMBOL(rtl_ps_enable_nic); bool rtl_ps_disable_nic(struct ieee80211_hw *hw) { - bool status = true; struct rtl_priv *rtlpriv = rtl_priv(hw); /*<1> Stop all timer */ @@ -75,7 +74,7 @@ bool rtl_ps_disable_nic(struct ieee80211_hw *hw) /*<3> Disable Adapter */ rtlpriv->cfg->ops->hw_disable(hw); - return status; + return true; } EXPORT_SYMBOL(rtl_ps_disable_nic); diff --git a/drivers/net/wireless/rtlwifi/rtl8192c/fw_common.c b/drivers/net/wireless/rtlwifi/rtl8192c/fw_common.c index 5ef9137..f107660 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192c/fw_common.c +++ b/drivers/net/wireless/rtlwifi/rtl8192c/fw_common.c @@ -171,7 +171,6 @@ static void _rtl92c_write_fw(struct ieee80211_hw *hw, static int _rtl92c_fw_free_to_go(struct ieee80211_hw *hw) { struct rtl_priv *rtlpriv = rtl_priv(hw); - int err = -EIO; u32 counter = 0; u32 value32; @@ -184,7 +183,7 @@ static int _rtl92c_fw_free_to_go(struct ieee80211_hw *hw) RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, ("chksum report faill ! REG_MCUFWDL:0x%08x .\n", value32)); - goto exit; + return -EIO; } RT_TRACE(rtlpriv, COMP_FW, DBG_TRACE, @@ -204,8 +203,7 @@ static int _rtl92c_fw_free_to_go(struct ieee80211_hw *hw) ("Polling FW ready success!!" " REG_MCUFWDL:0x%08x .\n", value32)); - err = 0; - goto exit; + return 0; } mdelay(FW_8192C_POLLING_DELAY); @@ -214,9 +212,7 @@ static int _rtl92c_fw_free_to_go(struct ieee80211_hw *hw) RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, ("Polling FW ready fail!! REG_MCUFWDL:0x%08x .\n", value32)); - -exit: - return err; + return -EIO; } int rtl92c_download_fw(struct ieee80211_hw *hw) @@ -226,16 +222,14 @@ int rtl92c_download_fw(struct ieee80211_hw *hw) struct rtl92c_firmware_header *pfwheader; u8 *pfwdata; u32 fwsize; - int err; enum version_8192c version = rtlhal->version; const struct firmware *firmware; - printk(KERN_INFO "rtl8192cu: Loading firmware file %s\n", + printk(KERN_INFO "rtl8192c: Loading firmware file %s\n", rtlpriv->cfg->fw_name); - err = request_firmware(&firmware, rtlpriv->cfg->fw_name, - rtlpriv->io.dev); - if (err) { - printk(KERN_ERR "rtl8192cu: Firmware loading failed\n"); + if (request_firmware(&firmware, rtlpriv->cfg->fw_name, + rtlpriv->io.dev)) { + printk(KERN_ERR "rtl8192c: Firmware loading failed\n"); return 1; } @@ -267,8 +261,7 @@ int rtl92c_download_fw(struct ieee80211_hw *hw) _rtl92c_write_fw(hw, version, pfwdata, fwsize); _rtl92c_enable_fw_download(hw, false); - err = _rtl92c_fw_free_to_go(hw); - if (err) { + if (_rtl92c_fw_free_to_go(hw)) { RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, ("Firmware is not ready to run!\n")); } else { @@ -303,7 +296,6 @@ static void _rtl92c_fill_h2c_command(struct ieee80211_hw *hw, u16 box_reg, box_extreg; u8 u1b_tmp; bool isfw_read = false; - u8 buf_index; bool bwrite_sucess = false; u8 wait_h2c_limmit = 100; u8 wait_writeh2c_limmit = 100; @@ -414,7 +406,7 @@ static void _rtl92c_fill_h2c_command(struct ieee80211_hw *hw, case 1: boxcontent[0] &= ~(BIT(7)); memcpy((u8 *) (boxcontent) + 1, - p_cmdbuffer + buf_index, 1); + p_cmdbuffer, 1); for (idx = 0; idx < 4; idx++) { rtl_write_byte(rtlpriv, box_reg + idx, @@ -424,7 +416,7 @@ static void _rtl92c_fill_h2c_command(struct ieee80211_hw *hw, case 2: boxcontent[0] &= ~(BIT(7)); memcpy((u8 *) (boxcontent) + 1, - p_cmdbuffer + buf_index, 2); + p_cmdbuffer, 2); for (idx = 0; idx < 4; idx++) { rtl_write_byte(rtlpriv, box_reg + idx, @@ -434,7 +426,7 @@ static void _rtl92c_fill_h2c_command(struct ieee80211_hw *hw, case 3: boxcontent[0] &= ~(BIT(7)); memcpy((u8 *) (boxcontent) + 1, - p_cmdbuffer + buf_index, 3); + p_cmdbuffer, 3); for (idx = 0; idx < 4; idx++) { rtl_write_byte(rtlpriv, box_reg + idx, @@ -444,9 +436,9 @@ static void _rtl92c_fill_h2c_command(struct ieee80211_hw *hw, case 4: boxcontent[0] |= (BIT(7)); memcpy((u8 *) (boxextcontent), - p_cmdbuffer + buf_index, 2); + p_cmdbuffer, 2); memcpy((u8 *) (boxcontent) + 1, - p_cmdbuffer + buf_index + 2, 2); + p_cmdbuffer + 2, 2); for (idx = 0; idx < 2; idx++) { rtl_write_byte(rtlpriv, box_extreg + idx, @@ -461,9 +453,9 @@ static void _rtl92c_fill_h2c_command(struct ieee80211_hw *hw, case 5: boxcontent[0] |= (BIT(7)); memcpy((u8 *) (boxextcontent), - p_cmdbuffer + buf_index, 2); + p_cmdbuffer, 2); memcpy((u8 *) (boxcontent) + 1, - p_cmdbuffer + buf_index + 2, 3); + p_cmdbuffer + 2, 3); for (idx = 0; idx < 2; idx++) { rtl_write_byte(rtlpriv, box_extreg + idx, diff --git a/drivers/net/wireless/rtlwifi/wifi.h b/drivers/net/wireless/rtlwifi/wifi.h index 01226f8..4ce4853 100644 --- a/drivers/net/wireless/rtlwifi/wifi.h +++ b/drivers/net/wireless/rtlwifi/wifi.h @@ -766,7 +766,7 @@ struct rtl_rfkill { #define IQK_MATRIX_REG_NUM 8 #define IQK_MATRIX_SETTINGS_NUM (1 + 24 + 21) struct iqk_matrix_regs { - bool b_iqk_done; + bool iqk_done; long value[1][IQK_MATRIX_REG_NUM]; }; @@ -1621,19 +1621,19 @@ struct bt_coexist_info { u32 bt_edca_ul; u32 bt_edca_dl; - bool b_init_set; - bool b_bt_busy_traffic; - bool b_bt_traffic_mode_set; - bool b_bt_non_traffic_mode_set; + bool init_set; + bool bt_busy_traffic; + bool bt_traffic_mode_set; + bool bt_non_traffic_mode_set; - bool b_fw_coexist_all_off; - bool b_sw_coexist_all_off; + bool fw_coexist_all_off; + bool sw_coexist_all_off; u32 current_state; u32 previous_state; u8 bt_pre_rssi_state; - u8 b_reg_bt_iso; - u8 b_reg_bt_sco; + u8 reg_bt_iso; + u8 reg_bt_sco; }; -- cgit v0.10.2 From 166389375d5a3894aa00a9c2e490ac4b9af2a891 Mon Sep 17 00:00:00 2001 From: Helmut Schaa Date: Mon, 28 Mar 2011 13:29:44 +0200 Subject: rt2x00: Limit rt2x00pci rxdone processing to 16 entries at once Instead of receiving an unlimited number of frames, stop after 16 entries and reschedule the rxdone tasklet. This allows other tasklets to be run inbetween. Signed-off-by: Helmut Schaa Acked-by: Gertjan van Wingerde Signed-off-by: Ivo van Doorn Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/rt2x00/rt2400pci.c b/drivers/net/wireless/rt2x00/rt2400pci.c index 329f328..137a24e 100644 --- a/drivers/net/wireless/rt2x00/rt2400pci.c +++ b/drivers/net/wireless/rt2x00/rt2400pci.c @@ -1368,8 +1368,10 @@ static void rt2400pci_tbtt_tasklet(unsigned long data) static void rt2400pci_rxdone_tasklet(unsigned long data) { struct rt2x00_dev *rt2x00dev = (struct rt2x00_dev *)data; - rt2x00pci_rxdone(rt2x00dev); - rt2400pci_enable_interrupt(rt2x00dev, CSR8_RXDONE); + if (rt2x00pci_rxdone(rt2x00dev)) + tasklet_schedule(&rt2x00dev->rxdone_tasklet); + else + rt2400pci_enable_interrupt(rt2x00dev, CSR8_RXDONE); } static irqreturn_t rt2400pci_interrupt(int irq, void *dev_instance) diff --git a/drivers/net/wireless/rt2x00/rt2500pci.c b/drivers/net/wireless/rt2x00/rt2500pci.c index 5827787..198fc0a 100644 --- a/drivers/net/wireless/rt2x00/rt2500pci.c +++ b/drivers/net/wireless/rt2x00/rt2500pci.c @@ -1500,8 +1500,10 @@ static void rt2500pci_tbtt_tasklet(unsigned long data) static void rt2500pci_rxdone_tasklet(unsigned long data) { struct rt2x00_dev *rt2x00dev = (struct rt2x00_dev *)data; - rt2x00pci_rxdone(rt2x00dev); - rt2500pci_enable_interrupt(rt2x00dev, CSR8_RXDONE); + if (rt2x00pci_rxdone(rt2x00dev)) + tasklet_schedule(&rt2x00dev->rxdone_tasklet); + else + rt2500pci_enable_interrupt(rt2x00dev, CSR8_RXDONE); } static irqreturn_t rt2500pci_interrupt(int irq, void *dev_instance) diff --git a/drivers/net/wireless/rt2x00/rt2800pci.c b/drivers/net/wireless/rt2x00/rt2800pci.c index 808073a..4672dc9 100644 --- a/drivers/net/wireless/rt2x00/rt2800pci.c +++ b/drivers/net/wireless/rt2x00/rt2800pci.c @@ -806,8 +806,10 @@ static void rt2800pci_tbtt_tasklet(unsigned long data) static void rt2800pci_rxdone_tasklet(unsigned long data) { struct rt2x00_dev *rt2x00dev = (struct rt2x00_dev *)data; - rt2x00pci_rxdone(rt2x00dev); - rt2800pci_enable_interrupt(rt2x00dev, INT_MASK_CSR_RX_DONE); + if (rt2x00pci_rxdone(rt2x00dev)) + tasklet_schedule(&rt2x00dev->rxdone_tasklet); + else + rt2800pci_enable_interrupt(rt2x00dev, INT_MASK_CSR_RX_DONE); } static void rt2800pci_autowake_tasklet(unsigned long data) diff --git a/drivers/net/wireless/rt2x00/rt2x00pci.c b/drivers/net/wireless/rt2x00/rt2x00pci.c index 4dd82b0..9649bd0 100644 --- a/drivers/net/wireless/rt2x00/rt2x00pci.c +++ b/drivers/net/wireless/rt2x00/rt2x00pci.c @@ -60,14 +60,15 @@ int rt2x00pci_regbusy_read(struct rt2x00_dev *rt2x00dev, } EXPORT_SYMBOL_GPL(rt2x00pci_regbusy_read); -void rt2x00pci_rxdone(struct rt2x00_dev *rt2x00dev) +bool rt2x00pci_rxdone(struct rt2x00_dev *rt2x00dev) { struct data_queue *queue = rt2x00dev->rx; struct queue_entry *entry; struct queue_entry_priv_pci *entry_priv; struct skb_frame_desc *skbdesc; + int max_rx = 16; - while (1) { + while (--max_rx) { entry = rt2x00queue_get_entry(queue, Q_INDEX); entry_priv = entry->priv_data; @@ -93,6 +94,8 @@ void rt2x00pci_rxdone(struct rt2x00_dev *rt2x00dev) */ rt2x00lib_rxdone(entry); } + + return !max_rx; } EXPORT_SYMBOL_GPL(rt2x00pci_rxdone); diff --git a/drivers/net/wireless/rt2x00/rt2x00pci.h b/drivers/net/wireless/rt2x00/rt2x00pci.h index 746ce8f..07961b8 100644 --- a/drivers/net/wireless/rt2x00/rt2x00pci.h +++ b/drivers/net/wireless/rt2x00/rt2x00pci.h @@ -101,8 +101,11 @@ struct queue_entry_priv_pci { /** * rt2x00pci_rxdone - Handle RX done events * @rt2x00dev: Device pointer, see &struct rt2x00_dev. + * + * Returns true if there are still rx frames pending and false if all + * pending rx frames were processed. */ -void rt2x00pci_rxdone(struct rt2x00_dev *rt2x00dev); +bool rt2x00pci_rxdone(struct rt2x00_dev *rt2x00dev); /* * Device initialization handlers. diff --git a/drivers/net/wireless/rt2x00/rt61pci.c b/drivers/net/wireless/rt2x00/rt61pci.c index 77e8113..8ee1514 100644 --- a/drivers/net/wireless/rt2x00/rt61pci.c +++ b/drivers/net/wireless/rt2x00/rt61pci.c @@ -2313,8 +2313,10 @@ static void rt61pci_tbtt_tasklet(unsigned long data) static void rt61pci_rxdone_tasklet(unsigned long data) { struct rt2x00_dev *rt2x00dev = (struct rt2x00_dev *)data; - rt2x00pci_rxdone(rt2x00dev); - rt61pci_enable_interrupt(rt2x00dev, INT_MASK_CSR_RXDONE); + if (rt2x00pci_rxdone(rt2x00dev)) + rt2x00pci_rxdone(rt2x00dev); + else + rt61pci_enable_interrupt(rt2x00dev, INT_MASK_CSR_RXDONE); } static void rt61pci_autowake_tasklet(unsigned long data) -- cgit v0.10.2 From 2e7798b7c12bdaab4a4aee76d6d1ab7c986234ac Mon Sep 17 00:00:00 2001 From: Helmut Schaa Date: Mon, 28 Mar 2011 13:30:09 +0200 Subject: rt2x00: Limit rt2800pci txdone processing to 16 entries at once Instead of reporting an unlimited number of tx status reports to mac80211 stop after 16 frames and reschedule the tx status tasklet. This allows other tasklets to be run inbetween. Signed-off-by: Helmut Schaa Acked-by: Gertjan van Wingerde Signed-off-by: Ivo van Doorn Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/rt2x00/rt2800pci.c b/drivers/net/wireless/rt2x00/rt2800pci.c index 4672dc9..d305514 100644 --- a/drivers/net/wireless/rt2x00/rt2800pci.c +++ b/drivers/net/wireless/rt2x00/rt2800pci.c @@ -717,12 +717,13 @@ static void rt2800pci_wakeup(struct rt2x00_dev *rt2x00dev) rt2800_config(rt2x00dev, &libconf, IEEE80211_CONF_CHANGE_PS); } -static void rt2800pci_txdone(struct rt2x00_dev *rt2x00dev) +static bool rt2800pci_txdone(struct rt2x00_dev *rt2x00dev) { struct data_queue *queue; struct queue_entry *entry; u32 status; u8 qid; + int max_tx_done = 16; while (kfifo_get(&rt2x00dev->txstatus_fifo, &status)) { qid = rt2x00_get_field32(status, TX_STA_FIFO_PID_QUEUE); @@ -759,7 +760,12 @@ static void rt2800pci_txdone(struct rt2x00_dev *rt2x00dev) entry = rt2x00queue_get_entry(queue, Q_INDEX_DONE); rt2800_txdone_entry(entry, status); + + if (--max_tx_done == 0) + break; } + + return !max_tx_done; } static void rt2800pci_enable_interrupt(struct rt2x00_dev *rt2x00dev, @@ -780,7 +786,9 @@ static void rt2800pci_enable_interrupt(struct rt2x00_dev *rt2x00dev, static void rt2800pci_txstatus_tasklet(unsigned long data) { - rt2800pci_txdone((struct rt2x00_dev *)data); + struct rt2x00_dev *rt2x00dev = (struct rt2x00_dev *)data; + if (rt2800pci_txdone(rt2x00dev)) + tasklet_schedule(&rt2x00dev->txstatus_tasklet); /* * No need to enable the tx status interrupt here as we always -- cgit v0.10.2 From f78987cf8bb740b7a3636c08e003f1976f860cfc Mon Sep 17 00:00:00 2001 From: Helmut Schaa Date: Mon, 28 Mar 2011 13:30:36 +0200 Subject: rt2x00: Calculate tx status fifo size instead of hardcoding it Instead of hardcoding the tx status fifo size as 512 calculate it based on the number of tx queues and the number of entries per queue. Also round the size up to a power of 2 as kfifo would otherwise round it down. On rt2800pci this will increase the kfifo size from 512 bytes to 1024 bytes which is then able to hold the tx status for all entries in all tx queues. Furthermore, if the number of tx queues or tx entries changes in the future (use of the MGMT queue for example) the kfifo size doesn't need to be updated. Signed-off-by: Helmut Schaa Acked-by: Gertjan van Wingerde Signed-off-by: Ivo van Doorn Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/rt2x00/rt2x00dev.c b/drivers/net/wireless/rt2x00/rt2x00dev.c index 9de9dbe..d63b582 100644 --- a/drivers/net/wireless/rt2x00/rt2x00dev.c +++ b/drivers/net/wireless/rt2x00/rt2x00dev.c @@ -27,6 +27,7 @@ #include #include #include +#include #include "rt2x00.h" #include "rt2x00lib.h" @@ -811,13 +812,18 @@ static int rt2x00lib_probe_hw(struct rt2x00_dev *rt2x00dev) */ if (test_bit(DRIVER_REQUIRE_TXSTATUS_FIFO, &rt2x00dev->flags)) { /* - * Allocate txstatus fifo and tasklet, we use a size of 512 - * for the kfifo which is big enough to store 512/4=128 tx - * status reports. In the worst case (tx status for all tx - * queues gets reported before we've got a chance to handle - * them) 24*4=384 tx status reports need to be cached. + * Allocate the txstatus fifo. In the worst case the tx + * status fifo has to hold the tx status of all entries + * in all tx queues. Hence, calculate the kfifo size as + * tx_queues * entry_num and round up to the nearest + * power of 2. */ - status = kfifo_alloc(&rt2x00dev->txstatus_fifo, 512, + int kfifo_size = + roundup_pow_of_two(rt2x00dev->ops->tx_queues * + rt2x00dev->ops->tx->entry_num * + sizeof(u32)); + + status = kfifo_alloc(&rt2x00dev->txstatus_fifo, kfifo_size, GFP_KERNEL); if (status) return status; -- cgit v0.10.2 From aca7305be5cd9e07f042e6bf6547e7c5635f0041 Mon Sep 17 00:00:00 2001 From: Helmut Schaa Date: Mon, 28 Mar 2011 13:30:59 +0200 Subject: rt2x00: Remove DRIVER_SUPPORT_WATCHDOG flag We can simply check if the driver registered the watchdog callback. There's no need to have an additional flag for that. Signed-off-by: Helmut Schaa Signed-off-by: Ivo van Doorn Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/rt2x00/rt2500usb.c b/drivers/net/wireless/rt2x00/rt2500usb.c index 979fe65..d9e6cec 100644 --- a/drivers/net/wireless/rt2x00/rt2500usb.c +++ b/drivers/net/wireless/rt2x00/rt2500usb.c @@ -1796,7 +1796,6 @@ static int rt2500usb_probe_hw(struct rt2x00_dev *rt2x00dev) __set_bit(CONFIG_SUPPORT_HW_CRYPTO, &rt2x00dev->flags); __set_bit(DRIVER_REQUIRE_COPY_IV, &rt2x00dev->flags); } - __set_bit(DRIVER_SUPPORT_WATCHDOG, &rt2x00dev->flags); __set_bit(DRIVER_REQUIRE_SW_SEQNO, &rt2x00dev->flags); /* diff --git a/drivers/net/wireless/rt2x00/rt2800usb.c b/drivers/net/wireless/rt2x00/rt2800usb.c index 4e36865..1c99a4f 100644 --- a/drivers/net/wireless/rt2x00/rt2800usb.c +++ b/drivers/net/wireless/rt2x00/rt2800usb.c @@ -564,7 +564,6 @@ static int rt2800usb_probe_hw(struct rt2x00_dev *rt2x00dev) if (!modparam_nohwcrypt) __set_bit(CONFIG_SUPPORT_HW_CRYPTO, &rt2x00dev->flags); __set_bit(DRIVER_SUPPORT_LINK_TUNING, &rt2x00dev->flags); - __set_bit(DRIVER_SUPPORT_WATCHDOG, &rt2x00dev->flags); __set_bit(DRIVER_REQUIRE_HT_TX_DESC, &rt2x00dev->flags); /* diff --git a/drivers/net/wireless/rt2x00/rt2x00.h b/drivers/net/wireless/rt2x00/rt2x00.h index a3940d7..60b1cb0 100644 --- a/drivers/net/wireless/rt2x00/rt2x00.h +++ b/drivers/net/wireless/rt2x00/rt2x00.h @@ -674,7 +674,6 @@ enum rt2x00_flags { DRIVER_SUPPORT_CONTROL_FILTER_PSPOLL, DRIVER_SUPPORT_PRE_TBTT_INTERRUPT, DRIVER_SUPPORT_LINK_TUNING, - DRIVER_SUPPORT_WATCHDOG, /* * Driver configuration diff --git a/drivers/net/wireless/rt2x00/rt2x00link.c b/drivers/net/wireless/rt2x00/rt2x00link.c index c975b0a..fc8cee9 100644 --- a/drivers/net/wireless/rt2x00/rt2x00link.c +++ b/drivers/net/wireless/rt2x00/rt2x00link.c @@ -413,12 +413,11 @@ void rt2x00link_start_watchdog(struct rt2x00_dev *rt2x00dev) { struct link *link = &rt2x00dev->link; - if (!test_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags) || - !test_bit(DRIVER_SUPPORT_WATCHDOG, &rt2x00dev->flags)) - return; - - ieee80211_queue_delayed_work(rt2x00dev->hw, - &link->watchdog_work, WATCHDOG_INTERVAL); + if (test_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags) && + rt2x00dev->ops->lib->watchdog) + ieee80211_queue_delayed_work(rt2x00dev->hw, + &link->watchdog_work, + WATCHDOG_INTERVAL); } void rt2x00link_stop_watchdog(struct rt2x00_dev *rt2x00dev) diff --git a/drivers/net/wireless/rt2x00/rt73usb.c b/drivers/net/wireless/rt2x00/rt73usb.c index 02f1148..149e4f9 100644 --- a/drivers/net/wireless/rt2x00/rt73usb.c +++ b/drivers/net/wireless/rt2x00/rt73usb.c @@ -2209,7 +2209,6 @@ static int rt73usb_probe_hw(struct rt2x00_dev *rt2x00dev) if (!modparam_nohwcrypt) __set_bit(CONFIG_SUPPORT_HW_CRYPTO, &rt2x00dev->flags); __set_bit(DRIVER_SUPPORT_LINK_TUNING, &rt2x00dev->flags); - __set_bit(DRIVER_SUPPORT_WATCHDOG, &rt2x00dev->flags); /* * Set the rssi offset. -- cgit v0.10.2 From 75faae8b80171b447bfc4bac448308676fb8a663 Mon Sep 17 00:00:00 2001 From: Helmut Schaa Date: Mon, 28 Mar 2011 13:31:30 +0200 Subject: rt2x00: Restructure bw_comp calculation Move the HT40 check inside the calculation function to make it easier for a later cleanup. Signed-off-by: Helmut Schaa Signed-off-by: Ivo van Doorn Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/rt2x00/rt2800lib.c b/drivers/net/wireless/rt2x00/rt2800lib.c index 2ee6ceb..2f8af7a 100644 --- a/drivers/net/wireless/rt2x00/rt2800lib.c +++ b/drivers/net/wireless/rt2x00/rt2800lib.c @@ -1819,11 +1819,15 @@ static int rt2800_get_txpower_bw_comp(struct rt2x00_dev *rt2x00dev, u16 eeprom; u8 comp_en; u8 comp_type; - int comp_value; + int comp_value = 0; rt2x00_eeprom_read(rt2x00dev, EEPROM_TXPOWER_DELTA, &eeprom); - if (eeprom == 0xffff) + /* + * HT40 compensation not required. + */ + if (eeprom == 0xffff || + !test_bit(CONFIG_CHANNEL_HT40, &rt2x00dev->flags)) return 0; if (band == IEEE80211_BAND_2GHZ) { @@ -1865,13 +1869,12 @@ static u8 rt2800_compesate_txpower(struct rt2x00_dev *rt2x00dev, u8 eirp_txpower; u8 eirp_txpower_criterion; u8 reg_limit; - int bw_comp = 0; + int bw_comp; if (!((band == IEEE80211_BAND_5GHZ) && is_rate_b)) return txpower; - if (test_bit(CONFIG_CHANNEL_HT40, &rt2x00dev->flags)) - bw_comp = rt2800_get_txpower_bw_comp(rt2x00dev, band); + bw_comp = rt2800_get_txpower_bw_comp(rt2x00dev, band); if (test_bit(CONFIG_SUPPORT_POWER_LIMIT, &rt2x00dev->flags)) { /* -- cgit v0.10.2 From 2af242e19f06cfaade7ac8608c9df8af1e0fbb34 Mon Sep 17 00:00:00 2001 From: Helmut Schaa Date: Mon, 28 Mar 2011 13:32:01 +0200 Subject: rt2x00: Don't recalculate HT40 compensation for each rate Previously the HT40 tx power compensation value was calculated for each rate. However, the calculation is independent of the tx rate and as such can be precalculated and just passed in for each rate. Signed-off-by: Helmut Schaa Signed-off-by: Ivo van Doorn Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/rt2x00/rt2800lib.c b/drivers/net/wireless/rt2x00/rt2800lib.c index 2f8af7a..26ac892 100644 --- a/drivers/net/wireless/rt2x00/rt2800lib.c +++ b/drivers/net/wireless/rt2x00/rt2800lib.c @@ -1861,7 +1861,8 @@ static u8 rt2800_compesate_txpower(struct rt2x00_dev *rt2x00dev, int is_rate_b, enum ieee80211_band band, int power_level, - u8 txpower) + u8 txpower, + int delta) { u32 reg; u16 eeprom; @@ -1869,13 +1870,10 @@ static u8 rt2800_compesate_txpower(struct rt2x00_dev *rt2x00dev, u8 eirp_txpower; u8 eirp_txpower_criterion; u8 reg_limit; - int bw_comp; if (!((band == IEEE80211_BAND_5GHZ) && is_rate_b)) return txpower; - bw_comp = rt2800_get_txpower_bw_comp(rt2x00dev, band); - if (test_bit(CONFIG_SUPPORT_POWER_LIMIT, &rt2x00dev->flags)) { /* * Check if eirp txpower exceed txpower_limit. @@ -1898,14 +1896,14 @@ static u8 rt2800_compesate_txpower(struct rt2x00_dev *rt2x00dev, EEPROM_EIRP_MAX_TX_POWER_5GHZ); eirp_txpower = eirp_txpower_criterion + (txpower - criterion) + - (is_rate_b ? 4 : 0) + bw_comp; + (is_rate_b ? 4 : 0) + delta; reg_limit = (eirp_txpower > power_level) ? (eirp_txpower - power_level) : 0; } else reg_limit = 0; - return txpower + bw_comp - reg_limit; + return txpower + delta - reg_limit; } static void rt2800_config_txpower(struct rt2x00_dev *rt2x00dev, @@ -1919,6 +1917,12 @@ static void rt2800_config_txpower(struct rt2x00_dev *rt2x00dev, u32 offset; enum ieee80211_band band = conf->channel->band; int power_level = conf->power_level; + int delta; + + /* + * Calculate HT40 compensation delta + */ + delta = rt2800_get_txpower_bw_comp(rt2x00dev, band); /* * set to normal bbp tx power control mode: +/- 0dBm @@ -1948,7 +1952,7 @@ static void rt2800_config_txpower(struct rt2x00_dev *rt2x00dev, txpower = rt2x00_get_field16(eeprom, EEPROM_TXPOWER_BYRATE_RATE0); txpower = rt2800_compesate_txpower(rt2x00dev, is_rate_b, band, - power_level, txpower); + power_level, txpower, delta); rt2x00_set_field32(®, TX_PWR_CFG_RATE0, txpower); /* @@ -1959,7 +1963,7 @@ static void rt2800_config_txpower(struct rt2x00_dev *rt2x00dev, txpower = rt2x00_get_field16(eeprom, EEPROM_TXPOWER_BYRATE_RATE1); txpower = rt2800_compesate_txpower(rt2x00dev, is_rate_b, band, - power_level, txpower); + power_level, txpower, delta); rt2x00_set_field32(®, TX_PWR_CFG_RATE1, txpower); /* @@ -1970,7 +1974,7 @@ static void rt2800_config_txpower(struct rt2x00_dev *rt2x00dev, txpower = rt2x00_get_field16(eeprom, EEPROM_TXPOWER_BYRATE_RATE2); txpower = rt2800_compesate_txpower(rt2x00dev, is_rate_b, band, - power_level, txpower); + power_level, txpower, delta); rt2x00_set_field32(®, TX_PWR_CFG_RATE2, txpower); /* @@ -1981,7 +1985,7 @@ static void rt2800_config_txpower(struct rt2x00_dev *rt2x00dev, txpower = rt2x00_get_field16(eeprom, EEPROM_TXPOWER_BYRATE_RATE3); txpower = rt2800_compesate_txpower(rt2x00dev, is_rate_b, band, - power_level, txpower); + power_level, txpower, delta); rt2x00_set_field32(®, TX_PWR_CFG_RATE3, txpower); /* read the next four txpower values */ @@ -1997,7 +2001,7 @@ static void rt2800_config_txpower(struct rt2x00_dev *rt2x00dev, txpower = rt2x00_get_field16(eeprom, EEPROM_TXPOWER_BYRATE_RATE0); txpower = rt2800_compesate_txpower(rt2x00dev, is_rate_b, band, - power_level, txpower); + power_level, txpower, delta); rt2x00_set_field32(®, TX_PWR_CFG_RATE4, txpower); /* @@ -2008,7 +2012,7 @@ static void rt2800_config_txpower(struct rt2x00_dev *rt2x00dev, txpower = rt2x00_get_field16(eeprom, EEPROM_TXPOWER_BYRATE_RATE1); txpower = rt2800_compesate_txpower(rt2x00dev, is_rate_b, band, - power_level, txpower); + power_level, txpower, delta); rt2x00_set_field32(®, TX_PWR_CFG_RATE5, txpower); /* @@ -2019,7 +2023,7 @@ static void rt2800_config_txpower(struct rt2x00_dev *rt2x00dev, txpower = rt2x00_get_field16(eeprom, EEPROM_TXPOWER_BYRATE_RATE2); txpower = rt2800_compesate_txpower(rt2x00dev, is_rate_b, band, - power_level, txpower); + power_level, txpower, delta); rt2x00_set_field32(®, TX_PWR_CFG_RATE6, txpower); /* @@ -2030,7 +2034,7 @@ static void rt2800_config_txpower(struct rt2x00_dev *rt2x00dev, txpower = rt2x00_get_field16(eeprom, EEPROM_TXPOWER_BYRATE_RATE3); txpower = rt2800_compesate_txpower(rt2x00dev, is_rate_b, band, - power_level, txpower); + power_level, txpower, delta); rt2x00_set_field32(®, TX_PWR_CFG_RATE7, txpower); rt2800_register_write(rt2x00dev, offset, reg); -- cgit v0.10.2 From fa71a160272c0eec9c04102ab2a82befb7cb107f Mon Sep 17 00:00:00 2001 From: Helmut Schaa Date: Mon, 28 Mar 2011 13:32:32 +0200 Subject: rt2x00: Indention cleanup in rt2800lib Fix the indention in rt2800_compesate_txpower and also fix a typo in the function name rt2800_compesate_txpower -> rt2800_compensate_txpower. Signed-off-by: Helmut Schaa Signed-off-by: Ivo van Doorn Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/rt2x00/rt2800lib.c b/drivers/net/wireless/rt2x00/rt2800lib.c index 26ac892..0265133 100644 --- a/drivers/net/wireless/rt2x00/rt2800lib.c +++ b/drivers/net/wireless/rt2x00/rt2800lib.c @@ -1857,12 +1857,9 @@ static int rt2800_get_txpower_bw_comp(struct rt2x00_dev *rt2x00dev, return comp_value; } -static u8 rt2800_compesate_txpower(struct rt2x00_dev *rt2x00dev, - int is_rate_b, - enum ieee80211_band band, - int power_level, - u8 txpower, - int delta) +static u8 rt2800_compensate_txpower(struct rt2x00_dev *rt2x00dev, int is_rate_b, + enum ieee80211_band band, int power_level, + u8 txpower, int delta) { u32 reg; u16 eeprom; @@ -1951,7 +1948,7 @@ static void rt2800_config_txpower(struct rt2x00_dev *rt2x00dev, */ txpower = rt2x00_get_field16(eeprom, EEPROM_TXPOWER_BYRATE_RATE0); - txpower = rt2800_compesate_txpower(rt2x00dev, is_rate_b, band, + txpower = rt2800_compensate_txpower(rt2x00dev, is_rate_b, band, power_level, txpower, delta); rt2x00_set_field32(®, TX_PWR_CFG_RATE0, txpower); @@ -1962,7 +1959,7 @@ static void rt2800_config_txpower(struct rt2x00_dev *rt2x00dev, */ txpower = rt2x00_get_field16(eeprom, EEPROM_TXPOWER_BYRATE_RATE1); - txpower = rt2800_compesate_txpower(rt2x00dev, is_rate_b, band, + txpower = rt2800_compensate_txpower(rt2x00dev, is_rate_b, band, power_level, txpower, delta); rt2x00_set_field32(®, TX_PWR_CFG_RATE1, txpower); @@ -1973,7 +1970,7 @@ static void rt2800_config_txpower(struct rt2x00_dev *rt2x00dev, */ txpower = rt2x00_get_field16(eeprom, EEPROM_TXPOWER_BYRATE_RATE2); - txpower = rt2800_compesate_txpower(rt2x00dev, is_rate_b, band, + txpower = rt2800_compensate_txpower(rt2x00dev, is_rate_b, band, power_level, txpower, delta); rt2x00_set_field32(®, TX_PWR_CFG_RATE2, txpower); @@ -1984,7 +1981,7 @@ static void rt2800_config_txpower(struct rt2x00_dev *rt2x00dev, */ txpower = rt2x00_get_field16(eeprom, EEPROM_TXPOWER_BYRATE_RATE3); - txpower = rt2800_compesate_txpower(rt2x00dev, is_rate_b, band, + txpower = rt2800_compensate_txpower(rt2x00dev, is_rate_b, band, power_level, txpower, delta); rt2x00_set_field32(®, TX_PWR_CFG_RATE3, txpower); @@ -2000,7 +1997,7 @@ static void rt2800_config_txpower(struct rt2x00_dev *rt2x00dev, */ txpower = rt2x00_get_field16(eeprom, EEPROM_TXPOWER_BYRATE_RATE0); - txpower = rt2800_compesate_txpower(rt2x00dev, is_rate_b, band, + txpower = rt2800_compensate_txpower(rt2x00dev, is_rate_b, band, power_level, txpower, delta); rt2x00_set_field32(®, TX_PWR_CFG_RATE4, txpower); @@ -2011,7 +2008,7 @@ static void rt2800_config_txpower(struct rt2x00_dev *rt2x00dev, */ txpower = rt2x00_get_field16(eeprom, EEPROM_TXPOWER_BYRATE_RATE1); - txpower = rt2800_compesate_txpower(rt2x00dev, is_rate_b, band, + txpower = rt2800_compensate_txpower(rt2x00dev, is_rate_b, band, power_level, txpower, delta); rt2x00_set_field32(®, TX_PWR_CFG_RATE5, txpower); @@ -2022,7 +2019,7 @@ static void rt2800_config_txpower(struct rt2x00_dev *rt2x00dev, */ txpower = rt2x00_get_field16(eeprom, EEPROM_TXPOWER_BYRATE_RATE2); - txpower = rt2800_compesate_txpower(rt2x00dev, is_rate_b, band, + txpower = rt2800_compensate_txpower(rt2x00dev, is_rate_b, band, power_level, txpower, delta); rt2x00_set_field32(®, TX_PWR_CFG_RATE6, txpower); @@ -2033,7 +2030,7 @@ static void rt2800_config_txpower(struct rt2x00_dev *rt2x00dev, */ txpower = rt2x00_get_field16(eeprom, EEPROM_TXPOWER_BYRATE_RATE3); - txpower = rt2800_compesate_txpower(rt2x00dev, is_rate_b, band, + txpower = rt2800_compensate_txpower(rt2x00dev, is_rate_b, band, power_level, txpower, delta); rt2x00_set_field32(®, TX_PWR_CFG_RATE7, txpower); -- cgit v0.10.2 From 2f2bb7e8bdc977c94cdaaf84328526555eba89b1 Mon Sep 17 00:00:00 2001 From: Helmut Schaa Date: Mon, 28 Mar 2011 13:33:04 +0200 Subject: rt2x00: Remove obsolete rt2x00queue_align_payload Since commit d1c3a37ceeb1a5ea02991a0476355f1a1d3b3e83 ("mac80211: clarify alignment docs, fix up alignment") removed the requirement for a 4-byte aligned payload rt2x00queue_align_payload is obsolete as mac80211 will align the payload when it passes the frame to the net stack. As a result we can remove the call to rt2x00queue_align_payload in the rx path and since that's the last user we can remove rt2x00queue_align_payload altogether. One advantage is that we save some alignment operations for frames that don't need to be aligned (for example beause they are not passed to the net stack). Signed-off-by: Helmut Schaa Signed-off-by: Ivo van Doorn Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/rt2x00/rt2x00dev.c b/drivers/net/wireless/rt2x00/rt2x00dev.c index d63b582..55c1d03 100644 --- a/drivers/net/wireless/rt2x00/rt2x00dev.c +++ b/drivers/net/wireless/rt2x00/rt2x00dev.c @@ -512,8 +512,6 @@ void rt2x00lib_rxdone(struct queue_entry *entry) (rxdesc.size > header_length) && (rxdesc.dev_flags & RXDONE_L2PAD)) rt2x00queue_remove_l2pad(entry->skb, header_length); - else - rt2x00queue_align_payload(entry->skb, header_length); /* Trim buffer to correct size */ skb_trim(entry->skb, rxdesc.size); diff --git a/drivers/net/wireless/rt2x00/rt2x00lib.h b/drivers/net/wireless/rt2x00/rt2x00lib.h index 2d94cba..63c40d4 100644 --- a/drivers/net/wireless/rt2x00/rt2x00lib.h +++ b/drivers/net/wireless/rt2x00/rt2x00lib.h @@ -119,16 +119,6 @@ void rt2x00queue_free_skb(struct queue_entry *entry); void rt2x00queue_align_frame(struct sk_buff *skb); /** - * rt2x00queue_align_payload - Align 802.11 payload to 4-byte boundary - * @skb: The skb to align - * @header_length: Length of 802.11 header - * - * Align the 802.11 payload to a 4-byte boundary, this could - * mean the header is not aligned properly though. - */ -void rt2x00queue_align_payload(struct sk_buff *skb, unsigned int header_length); - -/** * rt2x00queue_insert_l2pad - Align 802.11 header & payload to 4-byte boundary * @skb: The skb to align * @header_length: Length of 802.11 header diff --git a/drivers/net/wireless/rt2x00/rt2x00queue.c b/drivers/net/wireless/rt2x00/rt2x00queue.c index 4b3c70e..5d89259 100644 --- a/drivers/net/wireless/rt2x00/rt2x00queue.c +++ b/drivers/net/wireless/rt2x00/rt2x00queue.c @@ -148,19 +148,6 @@ void rt2x00queue_align_frame(struct sk_buff *skb) skb_trim(skb, frame_length); } -void rt2x00queue_align_payload(struct sk_buff *skb, unsigned int header_length) -{ - unsigned int frame_length = skb->len; - unsigned int align = ALIGN_SIZE(skb, header_length); - - if (!align) - return; - - skb_push(skb, align); - memmove(skb->data, skb->data + align, frame_length); - skb_trim(skb, frame_length); -} - void rt2x00queue_insert_l2pad(struct sk_buff *skb, unsigned int header_length) { unsigned int payload_length = skb->len - header_length; -- cgit v0.10.2 From 9e33a3553821418b2c4f53d09311476c55176b13 Mon Sep 17 00:00:00 2001 From: Helmut Schaa Date: Mon, 28 Mar 2011 13:33:40 +0200 Subject: rt2x00: Implement tx power temperature compensation rt2800 devices should adjust their tx power in accordance with the eeproms temperature calibration values. Add a new driver callback gain_calibration that is called every 4 seconds. The rt2800 gain calibration routine simply runs the tx power configuration that takes care of calculating the temperature compensation delta. We don't need to synchronize the calls to rt2800_config_txpower as they should all happen from mac80211's single threaded workqueue. Signed-off-by: Helmut Schaa Signed-off-by: Ivo van Doorn Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/rt2x00/rt2800.h b/drivers/net/wireless/rt2x00/rt2800.h index 70b9abb..3b3d851 100644 --- a/drivers/net/wireless/rt2x00/rt2800.h +++ b/drivers/net/wireless/rt2x00/rt2800.h @@ -2104,6 +2104,59 @@ struct mac_iveiv_entry { #define EEPROM_TXPOWER_BG_2 FIELD16(0xff00) /* + * EEPROM temperature compensation boundaries 802.11BG + * MINUS4: If the actual TSSI is below this boundary, tx power needs to be + * reduced by (agc_step * -4) + * MINUS3: If the actual TSSI is below this boundary, tx power needs to be + * reduced by (agc_step * -3) + */ +#define EEPROM_TSSI_BOUND_BG1 0x0037 +#define EEPROM_TSSI_BOUND_BG1_MINUS4 FIELD16(0x00ff) +#define EEPROM_TSSI_BOUND_BG1_MINUS3 FIELD16(0xff00) + +/* + * EEPROM temperature compensation boundaries 802.11BG + * MINUS2: If the actual TSSI is below this boundary, tx power needs to be + * reduced by (agc_step * -2) + * MINUS1: If the actual TSSI is below this boundary, tx power needs to be + * reduced by (agc_step * -1) + */ +#define EEPROM_TSSI_BOUND_BG2 0x0038 +#define EEPROM_TSSI_BOUND_BG2_MINUS2 FIELD16(0x00ff) +#define EEPROM_TSSI_BOUND_BG2_MINUS1 FIELD16(0xff00) + +/* + * EEPROM temperature compensation boundaries 802.11BG + * REF: Reference TSSI value, no tx power changes needed + * PLUS1: If the actual TSSI is above this boundary, tx power needs to be + * increased by (agc_step * 1) + */ +#define EEPROM_TSSI_BOUND_BG3 0x0039 +#define EEPROM_TSSI_BOUND_BG3_REF FIELD16(0x00ff) +#define EEPROM_TSSI_BOUND_BG3_PLUS1 FIELD16(0xff00) + +/* + * EEPROM temperature compensation boundaries 802.11BG + * PLUS2: If the actual TSSI is above this boundary, tx power needs to be + * increased by (agc_step * 2) + * PLUS3: If the actual TSSI is above this boundary, tx power needs to be + * increased by (agc_step * 3) + */ +#define EEPROM_TSSI_BOUND_BG4 0x003a +#define EEPROM_TSSI_BOUND_BG4_PLUS2 FIELD16(0x00ff) +#define EEPROM_TSSI_BOUND_BG4_PLUS3 FIELD16(0xff00) + +/* + * EEPROM temperature compensation boundaries 802.11BG + * PLUS4: If the actual TSSI is above this boundary, tx power needs to be + * increased by (agc_step * 4) + * AGC_STEP: Temperature compensation step. + */ +#define EEPROM_TSSI_BOUND_BG5 0x003b +#define EEPROM_TSSI_BOUND_BG5_PLUS4 FIELD16(0x00ff) +#define EEPROM_TSSI_BOUND_BG5_AGC_STEP FIELD16(0xff00) + +/* * EEPROM TXPOWER 802.11A */ #define EEPROM_TXPOWER_A1 0x003c @@ -2113,6 +2166,59 @@ struct mac_iveiv_entry { #define EEPROM_TXPOWER_A_2 FIELD16(0xff00) /* + * EEPROM temperature compensation boundaries 802.11A + * MINUS4: If the actual TSSI is below this boundary, tx power needs to be + * reduced by (agc_step * -4) + * MINUS3: If the actual TSSI is below this boundary, tx power needs to be + * reduced by (agc_step * -3) + */ +#define EEPROM_TSSI_BOUND_A1 0x006a +#define EEPROM_TSSI_BOUND_A1_MINUS4 FIELD16(0x00ff) +#define EEPROM_TSSI_BOUND_A1_MINUS3 FIELD16(0xff00) + +/* + * EEPROM temperature compensation boundaries 802.11A + * MINUS2: If the actual TSSI is below this boundary, tx power needs to be + * reduced by (agc_step * -2) + * MINUS1: If the actual TSSI is below this boundary, tx power needs to be + * reduced by (agc_step * -1) + */ +#define EEPROM_TSSI_BOUND_A2 0x006b +#define EEPROM_TSSI_BOUND_A2_MINUS2 FIELD16(0x00ff) +#define EEPROM_TSSI_BOUND_A2_MINUS1 FIELD16(0xff00) + +/* + * EEPROM temperature compensation boundaries 802.11A + * REF: Reference TSSI value, no tx power changes needed + * PLUS1: If the actual TSSI is above this boundary, tx power needs to be + * increased by (agc_step * 1) + */ +#define EEPROM_TSSI_BOUND_A3 0x006c +#define EEPROM_TSSI_BOUND_A3_REF FIELD16(0x00ff) +#define EEPROM_TSSI_BOUND_A3_PLUS1 FIELD16(0xff00) + +/* + * EEPROM temperature compensation boundaries 802.11A + * PLUS2: If the actual TSSI is above this boundary, tx power needs to be + * increased by (agc_step * 2) + * PLUS3: If the actual TSSI is above this boundary, tx power needs to be + * increased by (agc_step * 3) + */ +#define EEPROM_TSSI_BOUND_A4 0x006d +#define EEPROM_TSSI_BOUND_A4_PLUS2 FIELD16(0x00ff) +#define EEPROM_TSSI_BOUND_A4_PLUS3 FIELD16(0xff00) + +/* + * EEPROM temperature compensation boundaries 802.11A + * PLUS4: If the actual TSSI is above this boundary, tx power needs to be + * increased by (agc_step * 4) + * AGC_STEP: Temperature compensation step. + */ +#define EEPROM_TSSI_BOUND_A5 0x006e +#define EEPROM_TSSI_BOUND_A5_PLUS4 FIELD16(0x00ff) +#define EEPROM_TSSI_BOUND_A5_AGC_STEP FIELD16(0xff00) + +/* * EEPROM TXPOWER by rate: tx power per tx rate for HT20 mode */ #define EEPROM_TXPOWER_BYRATE 0x006f diff --git a/drivers/net/wireless/rt2x00/rt2800lib.c b/drivers/net/wireless/rt2x00/rt2800lib.c index 0265133..59302fa 100644 --- a/drivers/net/wireless/rt2x00/rt2800lib.c +++ b/drivers/net/wireless/rt2x00/rt2800lib.c @@ -1813,6 +1813,116 @@ static void rt2800_config_channel(struct rt2x00_dev *rt2x00dev, rt2800_register_read(rt2x00dev, CH_BUSY_STA_SEC, ®); } +static int rt2800_get_gain_calibration_delta(struct rt2x00_dev *rt2x00dev) +{ + u8 tssi_bounds[9]; + u8 current_tssi; + u16 eeprom; + u8 step; + int i; + + /* + * Read TSSI boundaries for temperature compensation from + * the EEPROM. + * + * Array idx 0 1 2 3 4 5 6 7 8 + * Matching Delta value -4 -3 -2 -1 0 +1 +2 +3 +4 + * Example TSSI bounds 0xF0 0xD0 0xB5 0xA0 0x88 0x45 0x25 0x15 0x00 + */ + if (rt2x00dev->curr_band == IEEE80211_BAND_2GHZ) { + rt2x00_eeprom_read(rt2x00dev, EEPROM_TSSI_BOUND_BG1, &eeprom); + tssi_bounds[0] = rt2x00_get_field16(eeprom, + EEPROM_TSSI_BOUND_BG1_MINUS4); + tssi_bounds[1] = rt2x00_get_field16(eeprom, + EEPROM_TSSI_BOUND_BG1_MINUS3); + + rt2x00_eeprom_read(rt2x00dev, EEPROM_TSSI_BOUND_BG2, &eeprom); + tssi_bounds[2] = rt2x00_get_field16(eeprom, + EEPROM_TSSI_BOUND_BG2_MINUS2); + tssi_bounds[3] = rt2x00_get_field16(eeprom, + EEPROM_TSSI_BOUND_BG2_MINUS1); + + rt2x00_eeprom_read(rt2x00dev, EEPROM_TSSI_BOUND_BG3, &eeprom); + tssi_bounds[4] = rt2x00_get_field16(eeprom, + EEPROM_TSSI_BOUND_BG3_REF); + tssi_bounds[5] = rt2x00_get_field16(eeprom, + EEPROM_TSSI_BOUND_BG3_PLUS1); + + rt2x00_eeprom_read(rt2x00dev, EEPROM_TSSI_BOUND_BG4, &eeprom); + tssi_bounds[6] = rt2x00_get_field16(eeprom, + EEPROM_TSSI_BOUND_BG4_PLUS2); + tssi_bounds[7] = rt2x00_get_field16(eeprom, + EEPROM_TSSI_BOUND_BG4_PLUS3); + + rt2x00_eeprom_read(rt2x00dev, EEPROM_TSSI_BOUND_BG5, &eeprom); + tssi_bounds[8] = rt2x00_get_field16(eeprom, + EEPROM_TSSI_BOUND_BG5_PLUS4); + + step = rt2x00_get_field16(eeprom, + EEPROM_TSSI_BOUND_BG5_AGC_STEP); + } else { + rt2x00_eeprom_read(rt2x00dev, EEPROM_TSSI_BOUND_A1, &eeprom); + tssi_bounds[0] = rt2x00_get_field16(eeprom, + EEPROM_TSSI_BOUND_A1_MINUS4); + tssi_bounds[1] = rt2x00_get_field16(eeprom, + EEPROM_TSSI_BOUND_A1_MINUS3); + + rt2x00_eeprom_read(rt2x00dev, EEPROM_TSSI_BOUND_A2, &eeprom); + tssi_bounds[2] = rt2x00_get_field16(eeprom, + EEPROM_TSSI_BOUND_A2_MINUS2); + tssi_bounds[3] = rt2x00_get_field16(eeprom, + EEPROM_TSSI_BOUND_A2_MINUS1); + + rt2x00_eeprom_read(rt2x00dev, EEPROM_TSSI_BOUND_A3, &eeprom); + tssi_bounds[4] = rt2x00_get_field16(eeprom, + EEPROM_TSSI_BOUND_A3_REF); + tssi_bounds[5] = rt2x00_get_field16(eeprom, + EEPROM_TSSI_BOUND_A3_PLUS1); + + rt2x00_eeprom_read(rt2x00dev, EEPROM_TSSI_BOUND_A4, &eeprom); + tssi_bounds[6] = rt2x00_get_field16(eeprom, + EEPROM_TSSI_BOUND_A4_PLUS2); + tssi_bounds[7] = rt2x00_get_field16(eeprom, + EEPROM_TSSI_BOUND_A4_PLUS3); + + rt2x00_eeprom_read(rt2x00dev, EEPROM_TSSI_BOUND_A5, &eeprom); + tssi_bounds[8] = rt2x00_get_field16(eeprom, + EEPROM_TSSI_BOUND_A5_PLUS4); + + step = rt2x00_get_field16(eeprom, + EEPROM_TSSI_BOUND_A5_AGC_STEP); + } + + /* + * Check if temperature compensation is supported. + */ + if (tssi_bounds[4] == 0xff) + return 0; + + /* + * Read current TSSI (BBP 49). + */ + rt2800_bbp_read(rt2x00dev, 49, ¤t_tssi); + + /* + * Compare TSSI value (BBP49) with the compensation boundaries + * from the EEPROM and increase or decrease tx power. + */ + for (i = 0; i <= 3; i++) { + if (current_tssi > tssi_bounds[i]) + break; + } + + if (i == 4) { + for (i = 8; i >= 5; i--) { + if (current_tssi < tssi_bounds[i]) + break; + } + } + + return (i - 4) * step; +} + static int rt2800_get_txpower_bw_comp(struct rt2x00_dev *rt2x00dev, enum ieee80211_band band) { @@ -1904,7 +2014,8 @@ static u8 rt2800_compensate_txpower(struct rt2x00_dev *rt2x00dev, int is_rate_b, } static void rt2800_config_txpower(struct rt2x00_dev *rt2x00dev, - struct ieee80211_conf *conf) + enum ieee80211_band band, + int power_level) { u8 txpower; u16 eeprom; @@ -1912,8 +2023,6 @@ static void rt2800_config_txpower(struct rt2x00_dev *rt2x00dev, u32 reg; u8 r1; u32 offset; - enum ieee80211_band band = conf->channel->band; - int power_level = conf->power_level; int delta; /* @@ -1922,6 +2031,11 @@ static void rt2800_config_txpower(struct rt2x00_dev *rt2x00dev, delta = rt2800_get_txpower_bw_comp(rt2x00dev, band); /* + * calculate temperature compensation delta + */ + delta += rt2800_get_gain_calibration_delta(rt2x00dev); + + /* * set to normal bbp tx power control mode: +/- 0dBm */ rt2800_bbp_read(rt2x00dev, 1, &r1); @@ -2041,6 +2155,13 @@ static void rt2800_config_txpower(struct rt2x00_dev *rt2x00dev, } } +void rt2800_gain_calibration(struct rt2x00_dev *rt2x00dev) +{ + rt2800_config_txpower(rt2x00dev, rt2x00dev->curr_band, + rt2x00dev->tx_power); +} +EXPORT_SYMBOL_GPL(rt2800_gain_calibration); + static void rt2800_config_retry_limit(struct rt2x00_dev *rt2x00dev, struct rt2x00lib_conf *libconf) { @@ -2094,10 +2215,12 @@ void rt2800_config(struct rt2x00_dev *rt2x00dev, if (flags & IEEE80211_CONF_CHANGE_CHANNEL) { rt2800_config_channel(rt2x00dev, libconf->conf, &libconf->rf, &libconf->channel); - rt2800_config_txpower(rt2x00dev, libconf->conf); + rt2800_config_txpower(rt2x00dev, libconf->conf->channel->band, + libconf->conf->power_level); } if (flags & IEEE80211_CONF_CHANGE_POWER) - rt2800_config_txpower(rt2x00dev, libconf->conf); + rt2800_config_txpower(rt2x00dev, libconf->conf->channel->band, + libconf->conf->power_level); if (flags & IEEE80211_CONF_CHANGE_RETRY_LIMITS) rt2800_config_retry_limit(rt2x00dev, libconf); if (flags & IEEE80211_CONF_CHANGE_PS) diff --git a/drivers/net/wireless/rt2x00/rt2800lib.h b/drivers/net/wireless/rt2x00/rt2800lib.h index 0c92d86..f2d1594 100644 --- a/drivers/net/wireless/rt2x00/rt2800lib.h +++ b/drivers/net/wireless/rt2x00/rt2800lib.h @@ -181,6 +181,7 @@ void rt2800_link_stats(struct rt2x00_dev *rt2x00dev, struct link_qual *qual); void rt2800_reset_tuner(struct rt2x00_dev *rt2x00dev, struct link_qual *qual); void rt2800_link_tuner(struct rt2x00_dev *rt2x00dev, struct link_qual *qual, const u32 count); +void rt2800_gain_calibration(struct rt2x00_dev *rt2x00dev); int rt2800_enable_radio(struct rt2x00_dev *rt2x00dev); void rt2800_disable_radio(struct rt2x00_dev *rt2x00dev); diff --git a/drivers/net/wireless/rt2x00/rt2800pci.c b/drivers/net/wireless/rt2x00/rt2800pci.c index d305514..adc3534 100644 --- a/drivers/net/wireless/rt2x00/rt2800pci.c +++ b/drivers/net/wireless/rt2x00/rt2800pci.c @@ -1053,6 +1053,7 @@ static const struct rt2x00lib_ops rt2800pci_rt2x00_ops = { .link_stats = rt2800_link_stats, .reset_tuner = rt2800_reset_tuner, .link_tuner = rt2800_link_tuner, + .gain_calibration = rt2800_gain_calibration, .start_queue = rt2800pci_start_queue, .kick_queue = rt2800pci_kick_queue, .stop_queue = rt2800pci_stop_queue, diff --git a/drivers/net/wireless/rt2x00/rt2800usb.c b/drivers/net/wireless/rt2x00/rt2800usb.c index 1c99a4f..8b3ab3f 100644 --- a/drivers/net/wireless/rt2x00/rt2800usb.c +++ b/drivers/net/wireless/rt2x00/rt2800usb.c @@ -629,6 +629,7 @@ static const struct rt2x00lib_ops rt2800usb_rt2x00_ops = { .link_stats = rt2800_link_stats, .reset_tuner = rt2800_reset_tuner, .link_tuner = rt2800_link_tuner, + .gain_calibration = rt2800_gain_calibration, .watchdog = rt2800usb_watchdog, .start_queue = rt2800usb_start_queue, .kick_queue = rt2x00usb_kick_queue, diff --git a/drivers/net/wireless/rt2x00/rt2x00.h b/drivers/net/wireless/rt2x00/rt2x00.h index 60b1cb0..dd0f66a 100644 --- a/drivers/net/wireless/rt2x00/rt2x00.h +++ b/drivers/net/wireless/rt2x00/rt2x00.h @@ -348,6 +348,11 @@ struct link { * to bring the device/driver back into the desired state. */ struct delayed_work watchdog_work; + + /* + * Work structure for scheduling periodic AGC adjustments. + */ + struct delayed_work agc_work; }; enum rt2x00_delayed_flags { @@ -556,6 +561,7 @@ struct rt2x00lib_ops { struct link_qual *qual); void (*link_tuner) (struct rt2x00_dev *rt2x00dev, struct link_qual *qual, const u32 count); + void (*gain_calibration) (struct rt2x00_dev *rt2x00dev); /* * Data queue handlers. diff --git a/drivers/net/wireless/rt2x00/rt2x00dev.c b/drivers/net/wireless/rt2x00/rt2x00dev.c index 55c1d03..a98c434 100644 --- a/drivers/net/wireless/rt2x00/rt2x00dev.c +++ b/drivers/net/wireless/rt2x00/rt2x00dev.c @@ -71,6 +71,7 @@ int rt2x00lib_enable_radio(struct rt2x00_dev *rt2x00dev) */ rt2x00queue_start_queues(rt2x00dev); rt2x00link_start_tuner(rt2x00dev); + rt2x00link_start_agc(rt2x00dev); /* * Start watchdog monitoring. @@ -93,6 +94,7 @@ void rt2x00lib_disable_radio(struct rt2x00_dev *rt2x00dev) /* * Stop all queues */ + rt2x00link_stop_agc(rt2x00dev); rt2x00link_stop_tuner(rt2x00dev); rt2x00queue_stop_queues(rt2x00dev); rt2x00queue_flush_queues(rt2x00dev, true); diff --git a/drivers/net/wireless/rt2x00/rt2x00lib.h b/drivers/net/wireless/rt2x00/rt2x00lib.h index 63c40d4..88f2f92 100644 --- a/drivers/net/wireless/rt2x00/rt2x00lib.h +++ b/drivers/net/wireless/rt2x00/rt2x00lib.h @@ -32,6 +32,7 @@ */ #define WATCHDOG_INTERVAL round_jiffies_relative(HZ) #define LINK_TUNE_INTERVAL round_jiffies_relative(HZ) +#define AGC_INTERVAL round_jiffies_relative(4 * HZ) /* * rt2x00_rate: Per rate device information @@ -271,6 +272,18 @@ void rt2x00link_start_watchdog(struct rt2x00_dev *rt2x00dev); void rt2x00link_stop_watchdog(struct rt2x00_dev *rt2x00dev); /** + * rt2x00link_start_agc - Start periodic gain calibration + * @rt2x00dev: Pointer to &struct rt2x00_dev. + */ +void rt2x00link_start_agc(struct rt2x00_dev *rt2x00dev); + +/** + * rt2x00link_stop_agc - Stop periodic gain calibration + * @rt2x00dev: Pointer to &struct rt2x00_dev. + */ +void rt2x00link_stop_agc(struct rt2x00_dev *rt2x00dev); + +/** * rt2x00link_register - Initialize link tuning & watchdog functionality * @rt2x00dev: Pointer to &struct rt2x00_dev. * diff --git a/drivers/net/wireless/rt2x00/rt2x00link.c b/drivers/net/wireless/rt2x00/rt2x00link.c index fc8cee9..128b361 100644 --- a/drivers/net/wireless/rt2x00/rt2x00link.c +++ b/drivers/net/wireless/rt2x00/rt2x00link.c @@ -446,8 +446,46 @@ static void rt2x00link_watchdog(struct work_struct *work) WATCHDOG_INTERVAL); } +void rt2x00link_start_agc(struct rt2x00_dev *rt2x00dev) +{ + struct link *link = &rt2x00dev->link; + + if (test_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags) && + rt2x00dev->ops->lib->gain_calibration) + ieee80211_queue_delayed_work(rt2x00dev->hw, + &link->agc_work, + AGC_INTERVAL); +} + +void rt2x00link_stop_agc(struct rt2x00_dev *rt2x00dev) +{ + cancel_delayed_work_sync(&rt2x00dev->link.agc_work); +} + +static void rt2x00link_agc(struct work_struct *work) +{ + struct rt2x00_dev *rt2x00dev = + container_of(work, struct rt2x00_dev, link.agc_work.work); + struct link *link = &rt2x00dev->link; + + /* + * When the radio is shutting down we should + * immediately cease the watchdog monitoring. + */ + if (!test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags)) + return; + + rt2x00dev->ops->lib->gain_calibration(rt2x00dev); + + if (test_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags)) + ieee80211_queue_delayed_work(rt2x00dev->hw, + &link->agc_work, + AGC_INTERVAL); +} + void rt2x00link_register(struct rt2x00_dev *rt2x00dev) { + INIT_DELAYED_WORK(&rt2x00dev->link.agc_work, rt2x00link_agc); INIT_DELAYED_WORK(&rt2x00dev->link.watchdog_work, rt2x00link_watchdog); INIT_DELAYED_WORK(&rt2x00dev->link.work, rt2x00link_tuner); } -- cgit v0.10.2 From 351151e8ace033fe3b1977516b32a6c76e9a3f6d Mon Sep 17 00:00:00 2001 From: Helmut Schaa Date: Mon, 28 Mar 2011 13:34:15 +0200 Subject: rt2x00: Fix STBC transmissions to STAs with Rx STBC > 1 For STBC transmissions rt2x00 used the number of RxSTBC streams the destination STA indicates in its HT capabilities as STBC value in the TXWI. However, the legacy drivers and our own comment in rt2800.h suggest that the STBC field in the TXWI only allows a value of 0 or 1. The values 2 and 3 are reserved (probably for future devices). And indeed, STBC transmissions to STAs indicating more then 1 RxSTBC stream fail when the STBC field is set to something >1. Fix this by only setting the STBC field to 1 when STBC should be used. Signed-off-by: Helmut Schaa Acked-by: Gertjan van Wingerde Signed-off-by: Ivo van Doorn Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/rt2x00/rt2x00ht.c b/drivers/net/wireless/rt2x00/rt2x00ht.c index ae1219d..e8c0c3e 100644 --- a/drivers/net/wireless/rt2x00/rt2x00ht.c +++ b/drivers/net/wireless/rt2x00/rt2x00ht.c @@ -43,8 +43,11 @@ void rt2x00ht_create_tx_descriptor(struct queue_entry *entry, txdesc->u.ht.ba_size = 7; /* FIXME: What value is needed? */ - txdesc->u.ht.stbc = - (tx_info->flags & IEEE80211_TX_CTL_STBC) >> IEEE80211_TX_CTL_STBC_SHIFT; + /* + * Only one STBC stream is supported for now. + */ + if (tx_info->flags & IEEE80211_TX_CTL_STBC) + txdesc->u.ht.stbc = 1; /* * If IEEE80211_TX_RC_MCS is set txrate->idx just contains the -- cgit v0.10.2 From b35e77cf84137bbb4b6888dc90616eb0b452ea36 Mon Sep 17 00:00:00 2001 From: Ivo van Doorn Date: Mon, 28 Mar 2011 13:34:50 +0200 Subject: rt2x00: Add support for the ZyXEL NWD-211AN USB Add new USB ID Signed-off-by: Ivo van Doorn Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/rt2x00/rt2800usb.c b/drivers/net/wireless/rt2x00/rt2800usb.c index 8b3ab3f..262bf66 100644 --- a/drivers/net/wireless/rt2x00/rt2800usb.c +++ b/drivers/net/wireless/rt2x00/rt2800usb.c @@ -877,6 +877,7 @@ static struct usb_device_id rt2800usb_device_table[] = { { USB_DEVICE(0x5a57, 0x5257), USB_DEVICE_DATA(&rt2800usb_ops) }, /* Zyxel */ { USB_DEVICE(0x0586, 0x3416), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x0586, 0x3418), USB_DEVICE_DATA(&rt2800usb_ops) }, #ifdef CONFIG_RT2800USB_RT33XX /* Ralink */ { USB_DEVICE(0x148f, 0x3370), USB_DEVICE_DATA(&rt2800usb_ops) }, -- cgit v0.10.2 From f16d2db704b873d34cec54f992637f3579e10e08 Mon Sep 17 00:00:00 2001 From: Helmut Schaa Date: Mon, 28 Mar 2011 13:35:21 +0200 Subject: rt2x00: Fix tx aggregation problems with some clients Some clients seem to rely upon the reception of BlockAckReqs to flush their rx reorder buffer. In order to fix aggregation for these clients rt2x00 should send a BlockAckReq if the transmission of an AMPDU subframe fails. Introduce a new flag TXDONE_AMPDU to indicate that this is an AMPDU subframe and pass IEEE80211_TX_STAT_AMPDU_NO_BACK to mac80211 if an AMPDU subframe failed during transmission. This fixes aggregation problems with Intel 5100 Windows STAs (and maybe others as well). Signed-off-by: Helmut Schaa Signed-off-by: Ivo van Doorn Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/rt2x00/rt2800lib.c b/drivers/net/wireless/rt2x00/rt2800lib.c index 59302fa..769c05c 100644 --- a/drivers/net/wireless/rt2x00/rt2800lib.c +++ b/drivers/net/wireless/rt2x00/rt2800lib.c @@ -687,6 +687,9 @@ void rt2800_txdone_entry(struct queue_entry *entry, u32 status) mcs = real_mcs; } + if (aggr == 1 || ampdu == 1) + __set_bit(TXDONE_AMPDU, &txdesc.flags); + /* * Ralink has a retry mechanism using a global fallback * table. We setup this fallback table to try the immediate diff --git a/drivers/net/wireless/rt2x00/rt2x00dev.c b/drivers/net/wireless/rt2x00/rt2x00dev.c index a98c434..83252d94 100644 --- a/drivers/net/wireless/rt2x00/rt2x00dev.c +++ b/drivers/net/wireless/rt2x00/rt2x00dev.c @@ -353,10 +353,14 @@ void rt2x00lib_txdone(struct queue_entry *entry, * which would allow the rc algorithm to better decide on * which rates are suitable. */ - if (tx_info->flags & IEEE80211_TX_CTL_AMPDU) { + if (test_bit(TXDONE_AMPDU, &txdesc->flags) || + tx_info->flags & IEEE80211_TX_CTL_AMPDU) { tx_info->flags |= IEEE80211_TX_STAT_AMPDU; tx_info->status.ampdu_len = 1; tx_info->status.ampdu_ack_len = success ? 1 : 0; + + if (!success) + tx_info->flags |= IEEE80211_TX_STAT_AMPDU_NO_BACK; } if (rate_flags & IEEE80211_TX_RC_USE_RTS_CTS) { diff --git a/drivers/net/wireless/rt2x00/rt2x00queue.h b/drivers/net/wireless/rt2x00/rt2x00queue.h index 0c8b0c6..6ae8200 100644 --- a/drivers/net/wireless/rt2x00/rt2x00queue.h +++ b/drivers/net/wireless/rt2x00/rt2x00queue.h @@ -217,6 +217,7 @@ enum txdone_entry_desc_flags { TXDONE_FALLBACK, TXDONE_FAILURE, TXDONE_EXCESSIVE_RETRY, + TXDONE_AMPDU, }; /** -- cgit v0.10.2 From 6a4c499e86f54ed9316a87e7ddc6b7d33adb4976 Mon Sep 17 00:00:00 2001 From: Helmut Schaa Date: Mon, 28 Mar 2011 13:35:51 +0200 Subject: rt2x00: Add an error message when trying to send on a full queue We already tell mac80211 to stop the queue when we hit a certain threshold. Hence, it shouldn't happen at all that a frame gets queued for tx on a full queue. Add an error message for this case. Signed-off-by: Helmut Schaa Acked-by: Gertjan van Wingerde Signed-off-by: Ivo van Doorn Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/rt2x00/rt2x00queue.c b/drivers/net/wireless/rt2x00/rt2x00queue.c index 5d89259..9fc4a1e 100644 --- a/drivers/net/wireless/rt2x00/rt2x00queue.c +++ b/drivers/net/wireless/rt2x00/rt2x00queue.c @@ -482,8 +482,11 @@ int rt2x00queue_write_tx_frame(struct data_queue *queue, struct sk_buff *skb, struct skb_frame_desc *skbdesc; u8 rate_idx, rate_flags; - if (unlikely(rt2x00queue_full(queue))) + if (unlikely(rt2x00queue_full(queue))) { + ERROR(queue->rt2x00dev, + "Dropping frame due to full tx queue %d.\n", queue->qid); return -ENOBUFS; + } if (unlikely(test_and_set_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags))) { -- cgit v0.10.2 From eecd8250e492ffc4e7b72953cda9c2f3ba0e6ccc Mon Sep 17 00:00:00 2001 From: Bing Zhao Date: Mon, 28 Mar 2011 17:55:41 -0700 Subject: mwifiex: remove MWIFIEX_BSS_MODE_ macros replace them with NL80211_IFTYPE_ macros Also remove redundant functions mwifiex_drv_get_mode() and mwifiex_bss_ioctl_mode(). Signed-off-by: Bing Zhao Signed-off-by: Amitkumar Karwar Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/mwifiex/11n.c b/drivers/net/wireless/mwifiex/11n.c index ce6421f..73a6e62 100644 --- a/drivers/net/wireless/mwifiex/11n.c +++ b/drivers/net/wireless/mwifiex/11n.c @@ -109,7 +109,7 @@ mwifiex_fill_cap_info(struct mwifiex_private *priv, memset(&mcs[rx_mcs_supp], 0, sizeof(struct ieee80211_mcs_info) - rx_mcs_supp); - if (priv->bss_mode == MWIFIEX_BSS_MODE_INFRA || + if (priv->bss_mode == NL80211_IFTYPE_STATION || (ht_cap_info & IEEE80211_HT_CAP_SUP_WIDTH_20_40)) /* Set MCS32 for infra mode or ad-hoc mode with 40MHz support */ SETHT_MCS32(ht_cap->ht_cap.mcs.rx_mask); @@ -418,7 +418,7 @@ mwifiex_cmd_append_11n_tlv(struct mwifiex_private *priv, } if (bss_desc->bcn_ht_info) { - if (priv->bss_mode == MWIFIEX_BSS_MODE_IBSS) { + if (priv->bss_mode == NL80211_IFTYPE_ADHOC) { ht_info = (struct mwifiex_ie_types_htinfo *) *buffer; memset(ht_info, 0, sizeof(struct mwifiex_ie_types_htinfo)); diff --git a/drivers/net/wireless/mwifiex/cfg80211.c b/drivers/net/wireless/mwifiex/cfg80211.c index de86ef8..701c179 100644 --- a/drivers/net/wireless/mwifiex/cfg80211.c +++ b/drivers/net/wireless/mwifiex/cfg80211.c @@ -398,13 +398,9 @@ mwifiex_set_rf_channel(struct mwifiex_private *priv, int ret = 0; int status = 0; struct mwifiex_ds_band_cfg band_cfg; - int mode; - u8 wait_option = MWIFIEX_IOCTL_WAIT; u32 config_bands = 0; struct wiphy *wiphy = priv->wdev->wiphy; - mode = mwifiex_drv_get_mode(priv, wait_option); - if (chan) { memset(&band_cfg, 0, sizeof(band_cfg)); /* Set appropriate bands */ @@ -412,10 +408,10 @@ mwifiex_set_rf_channel(struct mwifiex_private *priv, config_bands = BAND_B | BAND_G | BAND_GN; else config_bands = BAND_AN | BAND_A; - if (mode == MWIFIEX_BSS_MODE_INFRA - || mode == MWIFIEX_BSS_MODE_AUTO) { + if (priv->bss_mode == NL80211_IFTYPE_STATION + || priv->bss_mode == NL80211_IFTYPE_UNSPECIFIED) { band_cfg.config_bands = config_bands; - } else if (mode == MWIFIEX_BSS_MODE_IBSS) { + } else if (priv->bss_mode == NL80211_IFTYPE_ADHOC) { band_cfg.config_bands = config_bands; band_cfg.adhoc_start_band = config_bands; } @@ -432,7 +428,8 @@ mwifiex_set_rf_channel(struct mwifiex_private *priv, } wiphy_dbg(wiphy, "info: setting band %d, channel offset %d and " - "mode %d\n", config_bands, band_cfg.sec_chan_offset, mode); + "mode %d\n", config_bands, band_cfg.sec_chan_offset, + priv->bss_mode); if (!chan) return ret; @@ -561,14 +558,6 @@ mwifiex_cfg80211_set_wiphy_params(struct wiphy *wiphy, u32 changed) /* * CFG802.11 operation handler to change interface type. - * - * This function creates an IOCTL request, populates it accordingly - * and issues an IOCTL. - * - * The function also maps the CFG802.11 mode type into driver mode type. - * NL80211_IFTYPE_ADHOC -> MWIFIEX_BSS_MODE_IBSS - * NL80211_IFTYPE_STATION -> MWIFIEX_BSS_MODE_INFRA - * NL80211_IFTYPE_UNSPECIFIED -> MWIFIEX_BSS_MODE_AUTO */ static int mwifiex_cfg80211_change_virtual_intf(struct wiphy *wiphy, @@ -578,41 +567,50 @@ mwifiex_cfg80211_change_virtual_intf(struct wiphy *wiphy, { int ret = 0; struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev); - int mode = -1; struct mwifiex_wait_queue *wait = NULL; - int status = 0; - wait = mwifiex_alloc_fill_wait_queue(priv, MWIFIEX_IOCTL_WAIT); - if (!wait) - return -ENOMEM; + if (priv->bss_mode == type) { + wiphy_warn(wiphy, "already set to required type\n"); + return 0; + } + + priv->bss_mode = type; switch (type) { case NL80211_IFTYPE_ADHOC: - mode = MWIFIEX_BSS_MODE_IBSS; dev->ieee80211_ptr->iftype = NL80211_IFTYPE_ADHOC; wiphy_dbg(wiphy, "info: setting interface type to adhoc\n"); break; case NL80211_IFTYPE_STATION: - mode = MWIFIEX_BSS_MODE_INFRA; dev->ieee80211_ptr->iftype = NL80211_IFTYPE_STATION; - wiphy_dbg(wiphy, "info: Setting interface type to managed\n"); + wiphy_dbg(wiphy, "info: setting interface type to managed\n"); break; case NL80211_IFTYPE_UNSPECIFIED: - mode = MWIFIEX_BSS_MODE_AUTO; dev->ieee80211_ptr->iftype = NL80211_IFTYPE_STATION; wiphy_dbg(wiphy, "info: setting interface type to auto\n"); - break; + return 0; default: - ret = -EINVAL; + wiphy_err(wiphy, "unknown interface type: %d\n", type); + return -EINVAL; } - if (ret) - goto done; - status = mwifiex_bss_ioctl_mode(priv, wait, HostCmd_ACT_GEN_SET, &mode); - if (mwifiex_request_ioctl(priv, wait, status, MWIFIEX_IOCTL_WAIT)) + wait = mwifiex_alloc_fill_wait_queue(priv, MWIFIEX_IOCTL_WAIT); + if (!wait) + return -ENOMEM; + + mwifiex_deauthenticate(priv, wait, NULL); + + priv->sec_info.authentication_mode = MWIFIEX_AUTH_MODE_OPEN; + + ret = mwifiex_prepare_cmd(priv, HostCmd_CMD_SET_BSS_MODE, + HostCmd_ACT_GEN_SET, 0, wait, NULL); + if (!ret) + ret = -EINPROGRESS; + + ret = mwifiex_request_ioctl(priv, wait, ret, MWIFIEX_IOCTL_WAIT); + if (ret) ret = -EFAULT; -done: kfree(wait); return ret; } @@ -1046,7 +1044,7 @@ mwifiex_cfg80211_assoc(struct mwifiex_private *priv, size_t ssid_len, u8 *ssid, ret = mwifiex_set_encode(priv, NULL, 0, 0, 1); /* Disable keys */ - if (mode == MWIFIEX_BSS_MODE_IBSS) { + if (mode == NL80211_IFTYPE_ADHOC) { /* "privacy" is set only for ad-hoc mode */ if (privacy) { /* @@ -1108,7 +1106,7 @@ done: memcpy(&ssid_bssid.ssid, &req_ssid, sizeof(struct mwifiex_802_11_ssid)); - if (mode != MWIFIEX_BSS_MODE_IBSS) { + if (mode != NL80211_IFTYPE_ADHOC) { if (mwifiex_find_best_bss(priv, MWIFIEX_IOCTL_WAIT, &ssid_bssid)) return -EFAULT; @@ -1129,7 +1127,7 @@ done: if (mwifiex_bss_start(priv, MWIFIEX_IOCTL_WAIT, &ssid_bssid)) return -EFAULT; - if (mode == MWIFIEX_BSS_MODE_IBSS) { + if (mode == NL80211_IFTYPE_ADHOC) { /* Inform the BSS information to kernel, otherwise * kernel will give a panic after successful assoc */ if (mwifiex_cfg80211_inform_ibss_bss(priv)) @@ -1152,14 +1150,11 @@ mwifiex_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev, { struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev); int ret = 0; - int mode = 0; if (priv->assoc_request) return -EBUSY; - mode = mwifiex_drv_get_mode(priv, MWIFIEX_IOCTL_WAIT); - - if (mode == MWIFIEX_BSS_MODE_IBSS) { + if (priv->bss_mode == NL80211_IFTYPE_ADHOC) { wiphy_err(wiphy, "received infra assoc request " "when station is in ibss mode\n"); goto done; @@ -1171,7 +1166,7 @@ mwifiex_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev, (char *) sme->ssid, sme->bssid); ret = mwifiex_cfg80211_assoc(priv, sme->ssid_len, sme->ssid, sme->bssid, - mode, sme->channel, sme, 0); + priv->bss_mode, sme->channel, sme, 0); done: priv->assoc_result = ret; @@ -1191,13 +1186,11 @@ mwifiex_cfg80211_join_ibss(struct wiphy *wiphy, struct net_device *dev, { struct mwifiex_private *priv = mwifiex_cfg80211_get_priv(wiphy); int ret = 0; - int mode = 0; if (priv->ibss_join_request) return -EBUSY; - mode = mwifiex_drv_get_mode(priv, MWIFIEX_IOCTL_WAIT); - if (mode != MWIFIEX_BSS_MODE_IBSS) { + if (priv->bss_mode != NL80211_IFTYPE_ADHOC) { wiphy_err(wiphy, "request to join ibss received " "when station is not in ibss mode\n"); goto done; @@ -1209,8 +1202,8 @@ mwifiex_cfg80211_join_ibss(struct wiphy *wiphy, struct net_device *dev, (char *) params->ssid, params->bssid); ret = mwifiex_cfg80211_assoc(priv, params->ssid_len, params->ssid, - params->bssid, mode, params->channel, NULL, - params->privacy); + params->bssid, priv->bss_mode, + params->channel, NULL, params->privacy); done: priv->ibss_join_result = ret; queue_work(priv->workqueue, &priv->cfg_workqueue); @@ -1301,7 +1294,7 @@ mwifiex_setup_ht_caps(struct ieee80211_sta_ht_cap *ht_info, /* Clear all the other values */ memset(&mcs[rx_mcs_supp], 0, sizeof(struct ieee80211_mcs_info) - rx_mcs_supp); - if (priv->bss_mode == MWIFIEX_BSS_MODE_INFRA || + if (priv->bss_mode == NL80211_IFTYPE_STATION || ISSUPP_CHANWIDTH40(adapter->hw_dot_11n_dev_cap)) /* Set MCS32 for infra mode or ad-hoc mode with 40MHz support */ SETHT_MCS32(mcs_set.rx_mask); diff --git a/drivers/net/wireless/mwifiex/cfp.c b/drivers/net/wireless/mwifiex/cfp.c index 999ed81..07187a4 100644 --- a/drivers/net/wireless/mwifiex/cfp.c +++ b/drivers/net/wireless/mwifiex/cfp.c @@ -288,8 +288,7 @@ u32 mwifiex_get_supported_rates(struct mwifiex_private *priv, u8 *rates) { u32 k = 0; struct mwifiex_adapter *adapter = priv->adapter; - if (priv->bss_mode == MWIFIEX_BSS_MODE_INFRA) { - /* Infra. mode */ + if (priv->bss_mode == NL80211_IFTYPE_STATION) { switch (adapter->config_bands) { case BAND_B: dev_dbg(adapter->dev, "info: infra band=%d " diff --git a/drivers/net/wireless/mwifiex/init.c b/drivers/net/wireless/mwifiex/init.c index 1c9315d..00e73ea 100644 --- a/drivers/net/wireless/mwifiex/init.c +++ b/drivers/net/wireless/mwifiex/init.c @@ -78,7 +78,7 @@ static int mwifiex_init_priv(struct mwifiex_private *priv) memset(priv->curr_addr, 0xff, ETH_ALEN); priv->pkt_tx_ctrl = 0; - priv->bss_mode = MWIFIEX_BSS_MODE_INFRA; + priv->bss_mode = NL80211_IFTYPE_STATION; priv->data_rate = 0; /* Initially indicate the rate as auto */ priv->is_data_rate_auto = true; priv->bcn_avg_factor = DEFAULT_BCN_AVG_FACTOR; diff --git a/drivers/net/wireless/mwifiex/ioctl.h b/drivers/net/wireless/mwifiex/ioctl.h index b7e4571..7fb81df 100644 --- a/drivers/net/wireless/mwifiex/ioctl.h +++ b/drivers/net/wireless/mwifiex/ioctl.h @@ -66,12 +66,6 @@ struct mwifiex_scan_resp { u8 *scan_table; }; -enum { - MWIFIEX_BSS_MODE_INFRA = 1, - MWIFIEX_BSS_MODE_IBSS, - MWIFIEX_BSS_MODE_AUTO -}; - #define MWIFIEX_PROMISC_MODE 1 #define MWIFIEX_MULTICAST_MODE 2 #define MWIFIEX_ALL_MULTI_MODE 4 diff --git a/drivers/net/wireless/mwifiex/join.c b/drivers/net/wireless/mwifiex/join.c index 08fa721..d8c7c5f 100644 --- a/drivers/net/wireless/mwifiex/join.c +++ b/drivers/net/wireless/mwifiex/join.c @@ -808,7 +808,7 @@ mwifiex_cmd_802_11_ad_hoc_start(struct mwifiex_private *priv, /* Set the BSS mode */ adhoc_start->bss_mode = HostCmd_BSS_MODE_IBSS; - bss_desc->bss_mode = MWIFIEX_BSS_MODE_IBSS; + bss_desc->bss_mode = NL80211_IFTYPE_ADHOC; adhoc_start->beacon_period = cpu_to_le16(priv->beacon_period); bss_desc->beacon_period = priv->beacon_period; @@ -1289,8 +1289,8 @@ int mwifiex_associate(struct mwifiex_private *priv, u8 current_bssid[ETH_ALEN]; /* Return error if the adapter or table entry is not marked as infra */ - if ((priv->bss_mode != MWIFIEX_BSS_MODE_INFRA) || - (bss_desc->bss_mode != MWIFIEX_BSS_MODE_INFRA)) + if ((priv->bss_mode != NL80211_IFTYPE_STATION) || + (bss_desc->bss_mode != NL80211_IFTYPE_STATION)) return -1; memcpy(¤t_bssid, @@ -1358,7 +1358,7 @@ int mwifiex_adhoc_join(struct mwifiex_private *priv, !mwifiex_ssid_cmp(&bss_desc->ssid, &priv->curr_bss_params.bss_descriptor.ssid) && (priv->curr_bss_params.bss_descriptor.bss_mode == - MWIFIEX_BSS_MODE_IBSS)) { + NL80211_IFTYPE_ADHOC)) { dev_dbg(priv->adapter->dev, "info: ADHOC_J_CMD: new ad-hoc SSID" " is the same as current; not attempting to re-join\n"); return -1; @@ -1421,9 +1421,9 @@ int mwifiex_deauthenticate(struct mwifiex_private *priv, int ret = 0; if (priv->media_connected) { - if (priv->bss_mode == MWIFIEX_BSS_MODE_INFRA) { + if (priv->bss_mode == NL80211_IFTYPE_STATION) { ret = mwifiex_deauthenticate_infra(priv, wait, mac); - } else if (priv->bss_mode == MWIFIEX_BSS_MODE_IBSS) { + } else if (priv->bss_mode == NL80211_IFTYPE_ADHOC) { ret = mwifiex_prepare_cmd(priv, HostCmd_CMD_802_11_AD_HOC_STOP, HostCmd_ACT_GEN_SET, 0, wait, NULL); diff --git a/drivers/net/wireless/mwifiex/main.h b/drivers/net/wireless/mwifiex/main.h index 7bcb2e9..12b9a36 100644 --- a/drivers/net/wireless/mwifiex/main.h +++ b/drivers/net/wireless/mwifiex/main.h @@ -877,7 +877,7 @@ mwifiex_queuing_ra_based(struct mwifiex_private *priv) * Currently we assume if we are in Infra, then DA=RA. This might not be * true in the future */ - if ((priv->bss_mode == MWIFIEX_BSS_MODE_INFRA) && + if ((priv->bss_mode == NL80211_IFTYPE_STATION) && (GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_STA)) return false; @@ -1003,8 +1003,6 @@ int mwifiex_set_user_scan_ioctl(struct mwifiex_private *priv, int mwifiex_change_adhoc_chan(struct mwifiex_private *priv, int channel); int mwifiex_set_radio(struct mwifiex_private *priv, u8 option); -int mwifiex_drv_get_mode(struct mwifiex_private *priv, u8 wait_option); - int mwifiex_drv_change_adhoc_chan(struct mwifiex_private *priv, int channel); int mwifiex_set_encode(struct mwifiex_private *priv, const u8 *key, @@ -1043,9 +1041,6 @@ int mwifiex_set_tx_power(struct mwifiex_private *priv, int type, int dbm); int mwifiex_main_process(struct mwifiex_adapter *); -int mwifiex_bss_ioctl_mode(struct mwifiex_private *, - struct mwifiex_wait_queue *, - u16 action, int *mode); int mwifiex_bss_ioctl_channel(struct mwifiex_private *, u16 action, struct mwifiex_chan_freq_power *cfp); diff --git a/drivers/net/wireless/mwifiex/scan.c b/drivers/net/wireless/mwifiex/scan.c index 1152beb..69ea32f 100644 --- a/drivers/net/wireless/mwifiex/scan.c +++ b/drivers/net/wireless/mwifiex/scan.c @@ -455,8 +455,8 @@ mwifiex_is_network_compatible(struct mwifiex_private *priv, u32 index, u32 mode) bss_desc->disable_11n = false; /* Don't check for compatibility if roaming */ - if (priv->media_connected && (priv->bss_mode == MWIFIEX_BSS_MODE_INFRA) - && (bss_desc->bss_mode == MWIFIEX_BSS_MODE_INFRA)) + if (priv->media_connected && (priv->bss_mode == NL80211_IFTYPE_STATION) + && (bss_desc->bss_mode == NL80211_IFTYPE_STATION)) return index; if (priv->wps.session_enable) { @@ -573,8 +573,8 @@ mwifiex_find_best_network_in_list(struct mwifiex_private *priv) for (i = 0; i < adapter->num_in_scan_table; i++) { switch (mode) { - case MWIFIEX_BSS_MODE_INFRA: - case MWIFIEX_BSS_MODE_IBSS: + case NL80211_IFTYPE_STATION: + case NL80211_IFTYPE_ADHOC: if (mwifiex_is_network_compatible(priv, i, mode) >= 0) { if (SCAN_RSSI(adapter->scan_table[i].rssi) > best_rssi) { @@ -584,7 +584,7 @@ mwifiex_find_best_network_in_list(struct mwifiex_private *priv) } } break; - case MWIFIEX_BSS_MODE_AUTO: + case NL80211_IFTYPE_UNSPECIFIED: default: if (SCAN_RSSI(adapter->scan_table[i].rssi) > best_rssi) { @@ -1314,9 +1314,9 @@ mwifiex_interpret_bss_desc_with_ie(struct mwifiex_adapter *adapter, } if (bss_entry->cap_info_bitmap & WLAN_CAPABILITY_IBSS) - bss_entry->bss_mode = MWIFIEX_BSS_MODE_IBSS; + bss_entry->bss_mode = NL80211_IFTYPE_ADHOC; else - bss_entry->bss_mode = MWIFIEX_BSS_MODE_INFRA; + bss_entry->bss_mode = NL80211_IFTYPE_STATION; /* Process variable IE */ @@ -2251,8 +2251,7 @@ mwifiex_scan_delete_ssid_table_entry(struct mwifiex_private *priv, searching the table for multiple entires for the SSID until no more are found */ while ((table_idx = mwifiex_find_ssid_in_list(priv, del_ssid, NULL, - MWIFIEX_BSS_MODE_AUTO)) >= - 0) { + NL80211_IFTYPE_UNSPECIFIED)) >= 0) { dev_dbg(priv->adapter->dev, "info: Scan: Delete SSID Entry: Found Idx = %d\n", table_idx); @@ -2746,8 +2745,8 @@ mwifiex_find_ssid_in_list(struct mwifiex_private *priv, (priv, (u8) adapter->scan_table[i].bss_band, (u16) adapter->scan_table[i].channel))) { switch (mode) { - case MWIFIEX_BSS_MODE_INFRA: - case MWIFIEX_BSS_MODE_IBSS: + case NL80211_IFTYPE_STATION: + case NL80211_IFTYPE_ADHOC: j = mwifiex_is_network_compatible(priv, i, mode); @@ -2765,7 +2764,7 @@ mwifiex_find_ssid_in_list(struct mwifiex_private *priv, net = j; } break; - case MWIFIEX_BSS_MODE_AUTO: + case NL80211_IFTYPE_UNSPECIFIED: default: /* * Do not check compatibility if the mode @@ -2829,8 +2828,8 @@ mwifiex_find_bssid_in_list(struct mwifiex_private *priv, u8 *bssid, scan_table[i]. channel)) { switch (mode) { - case MWIFIEX_BSS_MODE_INFRA: - case MWIFIEX_BSS_MODE_IBSS: + case NL80211_IFTYPE_STATION: + case NL80211_IFTYPE_ADHOC: net = mwifiex_is_network_compatible(priv, i, mode); break; @@ -2881,7 +2880,7 @@ int mwifiex_find_best_network(struct mwifiex_private *priv, (u8 *) &req_bss->mac_address, ETH_ALEN); /* Make sure we are in the right mode */ - if (priv->bss_mode == MWIFIEX_BSS_MODE_AUTO) + if (priv->bss_mode == NL80211_IFTYPE_UNSPECIFIED) priv->bss_mode = req_bss->bss_mode; } diff --git a/drivers/net/wireless/mwifiex/sta_cmd.c b/drivers/net/wireless/mwifiex/sta_cmd.c index 795b1ea..6fff261 100644 --- a/drivers/net/wireless/mwifiex/sta_cmd.c +++ b/drivers/net/wireless/mwifiex/sta_cmd.c @@ -1089,10 +1089,10 @@ int mwifiex_sta_prepare_cmd(struct mwifiex_private *priv, uint16_t cmd_no, break; case HostCmd_CMD_SET_BSS_MODE: cmd_ptr->command = cpu_to_le16(cmd_no); - if (priv->bss_mode == MWIFIEX_BSS_MODE_IBSS) + if (priv->bss_mode == NL80211_IFTYPE_ADHOC) cmd_ptr->params.bss_mode.con_type = CONNECTION_TYPE_ADHOC; - else if (priv->bss_mode == MWIFIEX_BSS_MODE_INFRA) + else if (priv->bss_mode == NL80211_IFTYPE_STATION) cmd_ptr->params.bss_mode.con_type = CONNECTION_TYPE_INFRA; cmd_ptr->size = cpu_to_le16(sizeof(struct diff --git a/drivers/net/wireless/mwifiex/sta_cmdresp.c b/drivers/net/wireless/mwifiex/sta_cmdresp.c index ae960dd..b220b8b 100644 --- a/drivers/net/wireless/mwifiex/sta_cmdresp.c +++ b/drivers/net/wireless/mwifiex/sta_cmdresp.c @@ -65,7 +65,7 @@ mwifiex_process_cmdresp_error(struct mwifiex_private *priv, if (le16_to_cpu(pm->action) == EN_AUTO_PS && (le16_to_cpu(pm->params.auto_ps.ps_bitmap) & BITMAP_STA_PS) - && priv->bss_mode == MWIFIEX_BSS_MODE_IBSS) + && priv->bss_mode == NL80211_IFTYPE_ADHOC) adapter->ps_mode = MWIFIEX_802_11_POWER_MODE_CAM; } diff --git a/drivers/net/wireless/mwifiex/sta_event.c b/drivers/net/wireless/mwifiex/sta_event.c index d4a5c1f..0187185 100644 --- a/drivers/net/wireless/mwifiex/sta_event.c +++ b/drivers/net/wireless/mwifiex/sta_event.c @@ -82,7 +82,7 @@ mwifiex_reset_connect_state(struct mwifiex_private *priv) priv->is_data_rate_auto = true; priv->data_rate = 0; - if (priv->bss_mode == MWIFIEX_BSS_MODE_IBSS) { + if (priv->bss_mode == NL80211_IFTYPE_ADHOC) { priv->adhoc_state = ADHOC_IDLE; priv->adhoc_is_link_sensed = false; } diff --git a/drivers/net/wireless/mwifiex/sta_ioctl.c b/drivers/net/wireless/mwifiex/sta_ioctl.c index 362301f..abad07e 100644 --- a/drivers/net/wireless/mwifiex/sta_ioctl.c +++ b/drivers/net/wireless/mwifiex/sta_ioctl.c @@ -404,7 +404,7 @@ static int mwifiex_bss_ioctl_start(struct mwifiex_private *priv, if (!ssid_bssid) return -1; - if (priv->bss_mode == MWIFIEX_BSS_MODE_INFRA) { + if (priv->bss_mode == NL80211_IFTYPE_STATION) { /* Infra mode */ ret = mwifiex_deauthenticate(priv, NULL, NULL); if (ret) @@ -413,11 +413,11 @@ static int mwifiex_bss_ioctl_start(struct mwifiex_private *priv, /* Search for the requested SSID in the scan table */ if (ssid_bssid->ssid.ssid_len) i = mwifiex_find_ssid_in_list(priv, &ssid_bssid->ssid, - NULL, MWIFIEX_BSS_MODE_INFRA); + NULL, NL80211_IFTYPE_STATION); else i = mwifiex_find_bssid_in_list(priv, (u8 *) &ssid_bssid->bssid, - MWIFIEX_BSS_MODE_INFRA); + NL80211_IFTYPE_STATION); if (i < 0) return -1; @@ -451,11 +451,11 @@ static int mwifiex_bss_ioctl_start(struct mwifiex_private *priv, if (ssid_bssid->ssid.ssid_len) i = mwifiex_find_ssid_in_list(priv, &ssid_bssid->ssid, NULL, - MWIFIEX_BSS_MODE_IBSS); + NL80211_IFTYPE_ADHOC); else i = mwifiex_find_bssid_in_list(priv, (u8 *)&ssid_bssid->bssid, - MWIFIEX_BSS_MODE_IBSS); + NL80211_IFTYPE_ADHOC); if (i >= 0) { dev_dbg(adapter->dev, "info: network found in scan" @@ -1021,50 +1021,6 @@ int mwifiex_bss_ioctl_channel(struct mwifiex_private *priv, u16 action, } /* - * IOCTL request handler to set/get BSS mode. - * - * This function prepares the correct firmware command and - * issues it to set or get the BSS mode. - * - * In case the mode is changed, a deauthentication is performed - * first by the function automatically. - */ -int mwifiex_bss_ioctl_mode(struct mwifiex_private *priv, - struct mwifiex_wait_queue *wait, - u16 action, int *mode) -{ - int ret = 0; - - if (!mode) - return -1; - - if (action == HostCmd_ACT_GEN_GET) { - *mode = priv->bss_mode; - return 0; - } - - if ((priv->bss_mode == *mode) || (*mode == MWIFIEX_BSS_MODE_AUTO)) { - dev_dbg(priv->adapter->dev, - "info: Already set to required mode! No change!\n"); - priv->bss_mode = *mode; - return 0; - } - - ret = mwifiex_deauthenticate(priv, wait, NULL); - - priv->sec_info.authentication_mode = MWIFIEX_AUTH_MODE_OPEN; - priv->bss_mode = *mode; - if (priv->bss_mode != MWIFIEX_BSS_MODE_AUTO) { - ret = mwifiex_prepare_cmd(priv, HostCmd_CMD_SET_BSS_MODE, - HostCmd_ACT_GEN_SET, 0, wait, NULL); - if (!ret) - ret = -EINPROGRESS; - } - - return ret; -} - -/* * IOCTL request handler to set/get Ad-Hoc channel. * * This function prepares the correct firmware command and @@ -1237,33 +1193,6 @@ done: } /* - * IOCTL request handler to get current driver mode. - * - * This function allocates the IOCTL request buffer, fills it - * with requisite parameters and calls the IOCTL handler. - */ -int -mwifiex_drv_get_mode(struct mwifiex_private *priv, u8 wait_option) -{ - struct mwifiex_wait_queue *wait = NULL; - int status = 0; - int mode = -1; - - /* Allocate wait buffer */ - wait = mwifiex_alloc_fill_wait_queue(priv, wait_option); - if (!wait) - return -1; - - status = mwifiex_bss_ioctl_mode(priv, wait, HostCmd_ACT_GEN_GET, &mode); - - status = mwifiex_request_ioctl(priv, wait, status, wait_option); - - if (wait && (status != -EINPROGRESS)) - kfree(wait); - return mode; -} - -/* * IOCTL request handler to get rate. * * This function prepares the correct firmware command and @@ -1780,7 +1709,7 @@ static int mwifiex_sec_ioctl_set_wpa_key(struct mwifiex_adapter *adapter, return -1; } - if (priv->bss_mode == MWIFIEX_BSS_MODE_IBSS) { + if (priv->bss_mode == NL80211_IFTYPE_ADHOC) { /* * IBSS/WPA-None uses only one key (Group) for both receiving * and sending unicast and multicast packets. -- cgit v0.10.2 From f986b6d538c9351c99108b51be9f77ac1b300b16 Mon Sep 17 00:00:00 2001 From: Marc Yang Date: Mon, 28 Mar 2011 17:55:42 -0700 Subject: mwifiex: remove MWIFIEX_AUTH_MODE_ macros replace them with NL80211_AUTHTYPE_ macros Signed-off-by: Marc Yang Signed-off-by: Bing Zhao Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/mwifiex/cfg80211.c b/drivers/net/wireless/mwifiex/cfg80211.c index 701c179..2d96800 100644 --- a/drivers/net/wireless/mwifiex/cfg80211.c +++ b/drivers/net/wireless/mwifiex/cfg80211.c @@ -600,7 +600,7 @@ mwifiex_cfg80211_change_virtual_intf(struct wiphy *wiphy, mwifiex_deauthenticate(priv, wait, NULL); - priv->sec_info.authentication_mode = MWIFIEX_AUTH_MODE_OPEN; + priv->sec_info.authentication_mode = NL80211_AUTHTYPE_OPEN_SYSTEM; ret = mwifiex_prepare_cmd(priv, HostCmd_CMD_SET_BSS_MODE, HostCmd_ACT_GEN_SET, 0, wait, NULL); @@ -1056,7 +1056,7 @@ mwifiex_cfg80211_assoc(struct mwifiex_private *priv, size_t ssid_len, u8 *ssid, priv->sec_info.encryption_mode = MWIFIEX_ENCRYPTION_MODE_WEP104; priv->sec_info.authentication_mode = - MWIFIEX_AUTH_MODE_OPEN; + NL80211_AUTHTYPE_OPEN_SYSTEM; } goto done; @@ -1065,9 +1065,9 @@ mwifiex_cfg80211_assoc(struct mwifiex_private *priv, size_t ssid_len, u8 *ssid, /* Now handle infra mode. "sme" is valid for infra mode only */ if (sme->auth_type == NL80211_AUTHTYPE_AUTOMATIC || sme->auth_type == NL80211_AUTHTYPE_OPEN_SYSTEM) - auth_type = MWIFIEX_AUTH_MODE_OPEN; + auth_type = NL80211_AUTHTYPE_OPEN_SYSTEM; else if (sme->auth_type == NL80211_AUTHTYPE_SHARED_KEY) - auth_type = MWIFIEX_AUTH_MODE_SHARED; + auth_type = NL80211_AUTHTYPE_SHARED_KEY; if (sme->crypto.n_ciphers_pairwise) { pairwise_encrypt_mode = mwifiex_get_mwifiex_cipher(sme->crypto. diff --git a/drivers/net/wireless/mwifiex/init.c b/drivers/net/wireless/mwifiex/init.c index 00e73ea..bad436d6 100644 --- a/drivers/net/wireless/mwifiex/init.c +++ b/drivers/net/wireless/mwifiex/init.c @@ -85,7 +85,7 @@ static int mwifiex_init_priv(struct mwifiex_private *priv) priv->data_avg_factor = DEFAULT_DATA_AVG_FACTOR; priv->sec_info.wep_status = MWIFIEX_802_11_WEP_DISABLED; - priv->sec_info.authentication_mode = MWIFIEX_AUTH_MODE_OPEN; + priv->sec_info.authentication_mode = NL80211_AUTHTYPE_OPEN_SYSTEM; priv->sec_info.encryption_mode = MWIFIEX_ENCRYPTION_MODE_NONE; for (i = 0; i < ARRAY_SIZE(priv->wep_key); i++) memset(&priv->wep_key[i], 0, sizeof(struct mwifiex_wep_key)); diff --git a/drivers/net/wireless/mwifiex/ioctl.h b/drivers/net/wireless/mwifiex/ioctl.h index 7fb81df..7e0d316 100644 --- a/drivers/net/wireless/mwifiex/ioctl.h +++ b/drivers/net/wireless/mwifiex/ioctl.h @@ -269,11 +269,6 @@ struct mwifiex_debug_info { }; enum { - MWIFIEX_AUTH_MODE_OPEN = 0x00, - MWIFIEX_AUTH_MODE_SHARED = 0x01, -}; - -enum { MWIFIEX_ENCRYPTION_MODE_NONE = 0, MWIFIEX_ENCRYPTION_MODE_WEP40 = 1, MWIFIEX_ENCRYPTION_MODE_TKIP = 2, diff --git a/drivers/net/wireless/mwifiex/join.c b/drivers/net/wireless/mwifiex/join.c index d8c7c5f..8a1eb2a 100644 --- a/drivers/net/wireless/mwifiex/join.c +++ b/drivers/net/wireless/mwifiex/join.c @@ -449,7 +449,7 @@ int mwifiex_cmd_802_11_associate(struct mwifiex_private *priv, auth_tlv->auth_type = cpu_to_le16( (u16) priv->sec_info.authentication_mode); else - auth_tlv->auth_type = cpu_to_le16(MWIFIEX_AUTH_MODE_OPEN); + auth_tlv->auth_type = cpu_to_le16(NL80211_AUTHTYPE_OPEN_SYSTEM); pos += sizeof(auth_tlv->header) + le16_to_cpu(auth_tlv->header.len); -- cgit v0.10.2 From fd2e401a35500c9af63dc7ffbc545d2e3c478702 Mon Sep 17 00:00:00 2001 From: Marc Yang Date: Mon, 28 Mar 2011 17:55:43 -0700 Subject: mwifiex: remove unused radio_on variable and macros The radio_on variable is defined but never used. Signed-off-by: Marc Yang Signed-off-by: Bing Zhao Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/mwifiex/fw.h b/drivers/net/wireless/mwifiex/fw.h index 6593e07..2d93391 100644 --- a/drivers/net/wireless/mwifiex/fw.h +++ b/drivers/net/wireless/mwifiex/fw.h @@ -875,9 +875,6 @@ struct host_cmd_ds_802_11_snmp_mib { u8 value[1]; } __packed; -#define RADIO_ON 0x01 -#define RADIO_OFF 0x00 - struct mwifiex_rate_scope { __le16 type; __le16 length; diff --git a/drivers/net/wireless/mwifiex/init.c b/drivers/net/wireless/mwifiex/init.c index bad436d6..6fcdaa9 100644 --- a/drivers/net/wireless/mwifiex/init.c +++ b/drivers/net/wireless/mwifiex/init.c @@ -234,7 +234,6 @@ static void mwifiex_init_adapter(struct mwifiex_adapter *adapter) memset(adapter->bcn_buf, 0, sizeof(adapter->bcn_buf)); adapter->bcn_buf_end = adapter->bcn_buf; - adapter->radio_on = RADIO_ON; adapter->multiple_dtim = 1; adapter->local_listen_interval = 0; /* default value in firmware diff --git a/drivers/net/wireless/mwifiex/ioctl.h b/drivers/net/wireless/mwifiex/ioctl.h index 7e0d316..d01160a 100644 --- a/drivers/net/wireless/mwifiex/ioctl.h +++ b/drivers/net/wireless/mwifiex/ioctl.h @@ -193,7 +193,6 @@ struct mwifiex_bss_info { u32 bss_chan; u32 region_code; u32 media_connected; - u32 radio_on; u32 max_power_level; u32 min_power_level; u32 adhoc_state; diff --git a/drivers/net/wireless/mwifiex/main.h b/drivers/net/wireless/mwifiex/main.h index 12b9a36..c26f704 100644 --- a/drivers/net/wireless/mwifiex/main.h +++ b/drivers/net/wireless/mwifiex/main.h @@ -611,7 +611,6 @@ struct mwifiex_adapter { u16 curr_tx_buf_size; u32 ioport; enum MWIFIEX_HARDWARE_STATUS hw_status; - u16 radio_on; u16 number_of_antenna; u32 fw_cap_info; /* spin lock for interrupt handling */ diff --git a/drivers/net/wireless/mwifiex/sta_ioctl.c b/drivers/net/wireless/mwifiex/sta_ioctl.c index abad07e..b163507 100644 --- a/drivers/net/wireless/mwifiex/sta_ioctl.c +++ b/drivers/net/wireless/mwifiex/sta_ioctl.c @@ -790,9 +790,6 @@ int mwifiex_get_bss_info(struct mwifiex_private *priv, /* Connection status */ info->media_connected = priv->media_connected; - /* Radio status */ - info->radio_on = adapter->radio_on; - /* Tx power information */ info->max_power_level = priv->max_tx_power_level; info->min_power_level = priv->min_tx_power_level; -- cgit v0.10.2 From 4f3f1ee9f373abfdc09bb3bed87969b7fe0fba06 Mon Sep 17 00:00:00 2001 From: Marc Yang Date: Mon, 28 Mar 2011 17:55:44 -0700 Subject: mwifiex: remove unused macros in fw.h These definitions are no longer used after previous cleanups. Signed-off-by: Marc Yang Signed-off-by: Bing Zhao Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/mwifiex/fw.h b/drivers/net/wireless/mwifiex/fw.h index 2d93391..b4e4991 100644 --- a/drivers/net/wireless/mwifiex/fw.h +++ b/drivers/net/wireless/mwifiex/fw.h @@ -107,8 +107,6 @@ enum KEY_INFO_WAPI { #define FIRMWARE_READY 0xfedc -#define FIRMWARE_TRANSFER_NBLOCK 2 - enum MWIFIEX_802_11_PRIVACY_FILTER { MWIFIEX_802_11_PRIV_FILTER_ACCEPT_ALL, MWIFIEX_802_11_PRIV_FILTER_8021X_WEP @@ -125,50 +123,22 @@ enum MWIFIEX_802_11_WEP_STATUS { #define TLV_TYPE_KEY_MATERIAL (PROPRIETARY_TLV_BASE_ID + 0) #define TLV_TYPE_CHANLIST (PROPRIETARY_TLV_BASE_ID + 1) #define TLV_TYPE_NUMPROBES (PROPRIETARY_TLV_BASE_ID + 2) -#define TLV_TYPE_RSSI_LOW (PROPRIETARY_TLV_BASE_ID + 4) -#define TLV_TYPE_SNR_LOW (PROPRIETARY_TLV_BASE_ID + 5) -#define TLV_TYPE_FAILCOUNT (PROPRIETARY_TLV_BASE_ID + 6) -#define TLV_TYPE_BCNMISS (PROPRIETARY_TLV_BASE_ID + 7) -#define TLV_TYPE_LEDBEHAVIOR (PROPRIETARY_TLV_BASE_ID + 9) #define TLV_TYPE_PASSTHROUGH (PROPRIETARY_TLV_BASE_ID + 10) -#define TLV_TYPE_POWER_TBL_2_4GHZ (PROPRIETARY_TLV_BASE_ID + 12) -#define TLV_TYPE_POWER_TBL_5GHZ (PROPRIETARY_TLV_BASE_ID + 13) #define TLV_TYPE_WMMQSTATUS (PROPRIETARY_TLV_BASE_ID + 16) #define TLV_TYPE_WILDCARDSSID (PROPRIETARY_TLV_BASE_ID + 18) #define TLV_TYPE_TSFTIMESTAMP (PROPRIETARY_TLV_BASE_ID + 19) -#define TLV_TYPE_RSSI_HIGH (PROPRIETARY_TLV_BASE_ID + 22) -#define TLV_TYPE_SNR_HIGH (PROPRIETARY_TLV_BASE_ID + 23) -#define TLV_TYPE_STARTBGSCANLATER (PROPRIETARY_TLV_BASE_ID + 30) #define TLV_TYPE_AUTH_TYPE (PROPRIETARY_TLV_BASE_ID + 31) -#define TLV_TYPE_LINK_QUALITY (PROPRIETARY_TLV_BASE_ID + 36) -#define TLV_TYPE_RSSI_LOW_DATA (PROPRIETARY_TLV_BASE_ID + 38) -#define TLV_TYPE_SNR_LOW_DATA (PROPRIETARY_TLV_BASE_ID + 39) -#define TLV_TYPE_RSSI_HIGH_DATA (PROPRIETARY_TLV_BASE_ID + 40) -#define TLV_TYPE_SNR_HIGH_DATA (PROPRIETARY_TLV_BASE_ID + 41) #define TLV_TYPE_CHANNELBANDLIST (PROPRIETARY_TLV_BASE_ID + 42) #define TLV_TYPE_WAPI_IE (PROPRIETARY_TLV_BASE_ID + 94) -#define TLV_TYPE_BSSID (PROPRIETARY_TLV_BASE_ID + 35) #define MWIFIEX_TX_DATA_BUF_SIZE_2K 2048 -#define TLV_TYPE_HT_CAP (PROPRIETARY_TLV_BASE_ID + 74) -#define TLV_TYPE_HT_INFO (PROPRIETARY_TLV_BASE_ID + 75) -#define TLV_SECONDARY_CHANNEL_OFFSET (PROPRIETARY_TLV_BASE_ID + 76) -#define TLV_TYPE_2040BSS_COEXISTENCE (PROPRIETARY_TLV_BASE_ID + 77) -#define TLV_TYPE_OVERLAP_BSS_SCAN_PARAM (PROPRIETARY_TLV_BASE_ID + 78) -#define TLV_TYPE_EXTCAP (PROPRIETARY_TLV_BASE_ID + 79) -#define TLV_TYPE_HT_OPERATIONAL_MCS_SET (PROPRIETARY_TLV_BASE_ID + 80) - -#define ADDBA_TID_MASK (BIT(2) | BIT(3) | BIT(4) | BIT(5)) -#define DELBA_TID_MASK (BIT(12) | BIT(13) | BIT(14) | BIT(15)) #define SSN_MASK 0xfff0 #define BA_RESULT_SUCCESS 0x0 -#define BA_RESULT_FAILURE 0x1 #define BA_RESULT_TIMEOUT 0x2 -#define BA_RESULT_DATA_INVALID 0x3 #define IS_BASTREAM_SETUP(ptr) (ptr->ba_status) @@ -214,7 +184,6 @@ enum MWIFIEX_802_11_WEP_STATUS { #define LLC_SNAP_LEN 8 -#define TLV_TYPE_RATE_DROP_PATTERN (PROPRIETARY_TLV_BASE_ID + 81) #define TLV_TYPE_RATE_DROP_CONTROL (PROPRIETARY_TLV_BASE_ID + 82) #define TLV_TYPE_RATE_SCOPE (PROPRIETARY_TLV_BASE_ID + 83) @@ -282,15 +251,7 @@ enum ENH_PS_MODES { #define HostCmd_RET_BIT 0x8000 #define HostCmd_ACT_GEN_GET 0x0000 #define HostCmd_ACT_GEN_SET 0x0001 -#define HostCmd_ACT_GEN_REMOVE 0x0004 -#define HostCmd_ACT_SET_BOTH 0x0003 -#define HostCmd_ACT_GET_BOTH 0x000c #define HostCmd_RESULT_OK 0x0000 -#define HostCmd_RESULT_ERROR 0x0001 -#define HostCmd_RESULT_NOT_SUPPORT 0x0002 -#define HostCmd_RESULT_PENDING 0x0003 -#define HostCmd_RESULT_BUSY 0x0004 -#define HostCmd_RESULT_PARTIAL_DATA 0x0005 #define HostCmd_ACT_MAC_RX_ON 0x0001 #define HostCmd_ACT_MAC_TX_ON 0x0002 @@ -298,11 +259,8 @@ enum ENH_PS_MODES { #define HostCmd_ACT_MAC_ETHERNETII_ENABLE 0x0010 #define HostCmd_ACT_MAC_PROMISCUOUS_ENABLE 0x0080 #define HostCmd_ACT_MAC_ALL_MULTICAST_ENABLE 0x0100 -#define HostCmd_ACT_MAC_RTS_CTS_ENABLE 0x0200 -#define HostCmd_ACT_MAC_STRICT_PROTECTION_ENABLE 0x0400 #define HostCmd_ACT_MAC_ADHOC_G_PROTECTION_ON 0x2000 -#define HostCmd_BSS_MODE_BSS 0x0001 #define HostCmd_BSS_MODE_IBSS 0x0002 #define HostCmd_BSS_MODE_ANY 0x0003 -- cgit v0.10.2 From 4dd365fd55991b4e54a1d1c255081e6370b9da29 Mon Sep 17 00:00:00 2001 From: Bing Zhao Date: Wed, 30 Mar 2011 18:01:15 -0700 Subject: ieee80211: add HT extended capabilities masks IEEE Std 802.11n, Oct. 29, 2009: 7.3.2.56.5 HT Extended Capabilities field Signed-off-by: Bing Zhao Signed-off-by: John W. Linville diff --git a/include/linux/ieee80211.h b/include/linux/ieee80211.h index 2d1c611..79690b7 100644 --- a/include/linux/ieee80211.h +++ b/include/linux/ieee80211.h @@ -884,6 +884,15 @@ struct ieee80211_ht_cap { #define IEEE80211_HT_CAP_40MHZ_INTOLERANT 0x4000 #define IEEE80211_HT_CAP_LSIG_TXOP_PROT 0x8000 +/* 802.11n HT extended capabilities masks (for extended_ht_cap_info) */ +#define IEEE80211_HT_EXT_CAP_PCO 0x0001 +#define IEEE80211_HT_EXT_CAP_PCO_TIME 0x0006 +#define IEEE80211_HT_EXT_CAP_PCO_TIME_SHIFT 1 +#define IEEE80211_HT_EXT_CAP_MCS_FB 0x0300 +#define IEEE80211_HT_EXT_CAP_MCS_FB_SHIFT 8 +#define IEEE80211_HT_EXT_CAP_HTC_SUP 0x0400 +#define IEEE80211_HT_EXT_CAP_RD_RESPONDER 0x0800 + /* 802.11n HT capability AMPDU settings (for ampdu_params_info) */ #define IEEE80211_HT_AMPDU_PARM_FACTOR 0x03 #define IEEE80211_HT_AMPDU_PARM_DENSITY 0x1C -- cgit v0.10.2 From 2b06bdbe073f8dff93eb476f07352df43dcdba44 Mon Sep 17 00:00:00 2001 From: Marc Yang Date: Wed, 30 Mar 2011 18:12:44 -0700 Subject: mwifiex: cleanup power save related struct and macros remove redundant structures and unused macros Signed-off-by: Marc Yang Signed-off-by: Bing Zhao Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/mwifiex/cmdevt.c b/drivers/net/wireless/mwifiex/cmdevt.c index 3865dd1..a9aeb31 100644 --- a/drivers/net/wireless/mwifiex/cmdevt.c +++ b/drivers/net/wireless/mwifiex/cmdevt.c @@ -275,14 +275,14 @@ static int mwifiex_dnld_sleep_confirm_cmd(struct mwifiex_adapter *adapter) } if (GET_BSS_ROLE(mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_ANY)) == MWIFIEX_BSS_ROLE_STA) { - if (!sleep_cfm_buf->ps_cfm_sleep.sleep_cfm.resp_ctrl) + if (!sleep_cfm_buf->ps_cfm_sleep.resp_ctrl) /* Response is not needed for sleep confirm command */ adapter->ps_state = PS_STATE_SLEEP; else adapter->ps_state = PS_STATE_SLEEP_CFM; - if (!sleep_cfm_buf->ps_cfm_sleep.sleep_cfm.resp_ctrl + if (!sleep_cfm_buf->ps_cfm_sleep.resp_ctrl && (adapter->is_hs_configured && !adapter->sleep_period.period)) { adapter->pm_wakeup_card_req = true; @@ -1211,15 +1211,18 @@ int mwifiex_cmd_enh_power_mode(struct mwifiex_private *priv, if (cmd_action == DIS_AUTO_PS) { psmode_enh->action = cpu_to_le16(DIS_AUTO_PS); psmode_enh->params.ps_bitmap = cpu_to_le16(ps_bitmap); - cmd->size = cpu_to_le16(S_DS_GEN + AUTO_PS_FIX_SIZE); + cmd->size = cpu_to_le16(S_DS_GEN + sizeof(psmode_enh->action) + + sizeof(psmode_enh->params.ps_bitmap)); } else if (cmd_action == GET_PS) { psmode_enh->action = cpu_to_le16(GET_PS); psmode_enh->params.ps_bitmap = cpu_to_le16(ps_bitmap); - cmd->size = cpu_to_le16(S_DS_GEN + AUTO_PS_FIX_SIZE); + cmd->size = cpu_to_le16(S_DS_GEN + sizeof(psmode_enh->action) + + sizeof(psmode_enh->params.ps_bitmap)); } else if (cmd_action == EN_AUTO_PS) { psmode_enh->action = cpu_to_le16(EN_AUTO_PS); - psmode_enh->params.auto_ps.ps_bitmap = cpu_to_le16(ps_bitmap); - cmd_size = S_DS_GEN + AUTO_PS_FIX_SIZE; + psmode_enh->params.ps_bitmap = cpu_to_le16(ps_bitmap); + cmd_size = S_DS_GEN + sizeof(psmode_enh->action) + + sizeof(psmode_enh->params.ps_bitmap); tlv = (u8 *) cmd + cmd_size; if (ps_bitmap & BITMAP_STA_PS) { struct mwifiex_adapter *adapter = priv->adapter; @@ -1249,24 +1252,23 @@ int mwifiex_cmd_enh_power_mode(struct mwifiex_private *priv, } if (ps_bitmap & BITMAP_AUTO_DS) { - struct mwifiex_ie_types_auto_ds_param *auto_ps_tlv = + struct mwifiex_ie_types_auto_ds_param *auto_ds_tlv = (struct mwifiex_ie_types_auto_ds_param *) tlv; - struct mwifiex_auto_ds_param *auto_ds = - &auto_ps_tlv->param; u16 idletime = 0; - auto_ps_tlv->header.type = + + auto_ds_tlv->header.type = cpu_to_le16(TLV_TYPE_AUTO_DS_PARAM); - auto_ps_tlv->header.len = - cpu_to_le16(sizeof(*auto_ps_tlv) - + auto_ds_tlv->header.len = + cpu_to_le16(sizeof(*auto_ds_tlv) - sizeof(struct mwifiex_ie_types_header)); - cmd_size += sizeof(*auto_ps_tlv); - tlv += sizeof(*auto_ps_tlv); + cmd_size += sizeof(*auto_ds_tlv); + tlv += sizeof(*auto_ds_tlv); if (data_buf) idletime = ((struct mwifiex_ds_auto_ds *) data_buf)->idle_time; dev_dbg(priv->adapter->dev, "cmd: PS Command: Enter Auto Deep Sleep\n"); - auto_ds->deep_sleep_timeout = cpu_to_le16(idletime); + auto_ds_tlv->deep_sleep_timeout = cpu_to_le16(idletime); } cmd->size = cpu_to_le16(cmd_size); } @@ -1290,7 +1292,7 @@ int mwifiex_ret_enh_power_mode(struct mwifiex_private *priv, uint16_t action = le16_to_cpu(ps_mode->action); uint16_t ps_bitmap = le16_to_cpu(ps_mode->params.ps_bitmap); uint16_t auto_ps_bitmap = - le16_to_cpu(ps_mode->params.auto_ps.ps_bitmap); + le16_to_cpu(ps_mode->params.ps_bitmap); dev_dbg(adapter->dev, "info: %s: PS_MODE cmd reply result=%#x action=%#X\n", __func__, resp->result, action); @@ -1318,8 +1320,7 @@ int mwifiex_ret_enh_power_mode(struct mwifiex_private *priv, } } } else if (action == GET_PS) { - if (ps_bitmap & (BITMAP_STA_PS | BITMAP_UAP_INACT_PS - | BITMAP_UAP_DTIM_PS)) + if (ps_bitmap & BITMAP_STA_PS) adapter->ps_mode = MWIFIEX_802_11_POWER_MODE_PSP; else adapter->ps_mode = MWIFIEX_802_11_POWER_MODE_CAM; diff --git a/drivers/net/wireless/mwifiex/fw.h b/drivers/net/wireless/mwifiex/fw.h index b4e4991..d981265 100644 --- a/drivers/net/wireless/mwifiex/fw.h +++ b/drivers/net/wireless/mwifiex/fw.h @@ -127,11 +127,14 @@ enum MWIFIEX_802_11_WEP_STATUS { #define TLV_TYPE_WMMQSTATUS (PROPRIETARY_TLV_BASE_ID + 16) #define TLV_TYPE_WILDCARDSSID (PROPRIETARY_TLV_BASE_ID + 18) #define TLV_TYPE_TSFTIMESTAMP (PROPRIETARY_TLV_BASE_ID + 19) - #define TLV_TYPE_AUTH_TYPE (PROPRIETARY_TLV_BASE_ID + 31) - #define TLV_TYPE_CHANNELBANDLIST (PROPRIETARY_TLV_BASE_ID + 42) +#define TLV_TYPE_RATE_DROP_CONTROL (PROPRIETARY_TLV_BASE_ID + 82) +#define TLV_TYPE_RATE_SCOPE (PROPRIETARY_TLV_BASE_ID + 83) +#define TLV_TYPE_POWER_GROUP (PROPRIETARY_TLV_BASE_ID + 84) #define TLV_TYPE_WAPI_IE (PROPRIETARY_TLV_BASE_ID + 94) +#define TLV_TYPE_AUTO_DS_PARAM (PROPRIETARY_TLV_BASE_ID + 113) +#define TLV_TYPE_PS_PARAM (PROPRIETARY_TLV_BASE_ID + 114) #define MWIFIEX_TX_DATA_BUF_SIZE_2K 2048 @@ -184,11 +187,6 @@ enum MWIFIEX_802_11_WEP_STATUS { #define LLC_SNAP_LEN 8 -#define TLV_TYPE_RATE_DROP_CONTROL (PROPRIETARY_TLV_BASE_ID + 82) -#define TLV_TYPE_RATE_SCOPE (PROPRIETARY_TLV_BASE_ID + 83) - -#define TLV_TYPE_POWER_GROUP (PROPRIETARY_TLV_BASE_ID + 84) - #define MOD_CLASS_HR_DSSS 0x03 #define MOD_CLASS_OFDM 0x07 #define MOD_CLASS_HT 0x08 @@ -553,34 +551,12 @@ struct mwifiex_ps_param { __le16 delay_to_ps; }; -struct mwifiex_auto_ds_param { - __le16 deep_sleep_timeout; -}; - -struct sleep_confirm_param { - __le16 resp_ctrl; -}; - #define BITMAP_AUTO_DS 0x01 #define BITMAP_STA_PS 0x10 -#define BITMAP_UAP_INACT_PS 0x100 -#define BITMAP_UAP_DTIM_PS 0x200 -struct auto_ps_param { - __le16 ps_bitmap; - /* auto deep sleep parameter, - * sta power save parameter - * uap inactivity parameter - * uap DTIM parameter */ -}; - -#define AUTO_PS_FIX_SIZE 4 - -#define TLV_TYPE_AUTO_DS_PARAM (PROPRIETARY_TLV_BASE_ID + 113) -#define TLV_TYPE_PS_PARAM (PROPRIETARY_TLV_BASE_ID + 114) struct mwifiex_ie_types_auto_ds_param { struct mwifiex_ie_types_header header; - struct mwifiex_auto_ds_param param; + __le16 deep_sleep_timeout; } __packed; struct mwifiex_ie_types_ps_param { @@ -593,10 +569,7 @@ struct host_cmd_ds_802_11_ps_mode_enh { union { struct mwifiex_ps_param opt_ps; - struct mwifiex_auto_ds_param auto_ds; - struct sleep_confirm_param sleep_cfm; __le16 ps_bitmap; - struct auto_ps_param auto_ps; } params; } __packed; @@ -1260,7 +1233,7 @@ struct mwifiex_opt_sleep_confirm { __le16 seq_num; __le16 result; __le16 action; - struct sleep_confirm_param sleep_cfm; + __le16 resp_ctrl; } __packed; struct mwifiex_opt_sleep_confirm_buffer { diff --git a/drivers/net/wireless/mwifiex/init.c b/drivers/net/wireless/mwifiex/init.c index 6fcdaa9..43ea87d 100644 --- a/drivers/net/wireless/mwifiex/init.c +++ b/drivers/net/wireless/mwifiex/init.c @@ -280,7 +280,7 @@ static void mwifiex_init_adapter(struct mwifiex_adapter *adapter) cpu_to_le16(adapter->sleep_cfm->len); sleep_cfm_buf->ps_cfm_sleep.result = 0; sleep_cfm_buf->ps_cfm_sleep.action = cpu_to_le16(SLEEP_CONFIRM); - sleep_cfm_buf->ps_cfm_sleep.sleep_cfm.resp_ctrl = + sleep_cfm_buf->ps_cfm_sleep.resp_ctrl = cpu_to_le16(RESP_NEEDED); } memset(&adapter->sleep_params, 0, sizeof(adapter->sleep_params)); diff --git a/drivers/net/wireless/mwifiex/sta_cmdresp.c b/drivers/net/wireless/mwifiex/sta_cmdresp.c index b220b8b..74add45 100644 --- a/drivers/net/wireless/mwifiex/sta_cmdresp.c +++ b/drivers/net/wireless/mwifiex/sta_cmdresp.c @@ -46,6 +46,7 @@ mwifiex_process_cmdresp_error(struct mwifiex_private *priv, { struct cmd_ctrl_node *cmd_node = NULL, *tmp_node = NULL; struct mwifiex_adapter *adapter = priv->adapter; + struct host_cmd_ds_802_11_ps_mode_enh *pm; unsigned long flags; dev_err(adapter->dev, "CMD_RESP: cmd %#x error, result=%#x\n", @@ -55,20 +56,16 @@ mwifiex_process_cmdresp_error(struct mwifiex_private *priv, switch (le16_to_cpu(resp->command)) { case HostCmd_CMD_802_11_PS_MODE_ENH: - { - struct host_cmd_ds_802_11_ps_mode_enh *pm = - &resp->params.psmode_enh; - dev_err(adapter->dev, "PS_MODE_ENH cmd failed: " - "result=0x%x action=0x%X\n", + pm = &resp->params.psmode_enh; + dev_err(adapter->dev, "PS_MODE_ENH cmd failed: " + "result=0x%x action=0x%X\n", resp->result, le16_to_cpu(pm->action)); - /* We do not re-try enter-ps command in ad-hoc mode. */ - if (le16_to_cpu(pm->action) == EN_AUTO_PS && - (le16_to_cpu(pm->params.auto_ps.ps_bitmap) & - BITMAP_STA_PS) - && priv->bss_mode == NL80211_IFTYPE_ADHOC) - adapter->ps_mode = - MWIFIEX_802_11_POWER_MODE_CAM; - } + /* We do not re-try enter-ps command in ad-hoc mode. */ + if (le16_to_cpu(pm->action) == EN_AUTO_PS && + (le16_to_cpu(pm->params.ps_bitmap) & BITMAP_STA_PS) && + priv->bss_mode == NL80211_IFTYPE_ADHOC) + adapter->ps_mode = MWIFIEX_802_11_POWER_MODE_CAM; + break; case HostCmd_CMD_802_11_SCAN: /* Cancel all pending scan command */ -- cgit v0.10.2 From 7327890a1f42046c50030c8723bdbd9266d781bc Mon Sep 17 00:00:00 2001 From: Bing Zhao Date: Wed, 30 Mar 2011 18:12:45 -0700 Subject: mwifiex: remove struct mwifiex_802_11_fixed_ies struct mwifiex_802_11_fixed_ies is not necessary. struct mwifiex_event_wep_icv_err is not used any more. Signed-off-by: Bing Zhao Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/mwifiex/fw.h b/drivers/net/wireless/mwifiex/fw.h index d981265..2b93811 100644 --- a/drivers/net/wireless/mwifiex/fw.h +++ b/drivers/net/wireless/mwifiex/fw.h @@ -343,20 +343,6 @@ enum ENH_PS_MODES { #define EVENT_GET_BSS_TYPE(event_cause) \ (((event_cause) >> 24) & 0x00ff) -struct mwifiex_event_wep_icv_err { - u16 reason_code; - u8 src_mac_addr[ETH_ALEN]; - u8 wep_key_index; - u8 wep_key_length; - u8 key[WLAN_KEY_LEN_WEP104]; -}; - -struct mwifiex_802_11_fixed_ies { - u8 time_stamp[8]; - __le16 beacon_interval; - __le16 capabilities; -}; - struct mwifiex_ie_types_header { __le16 type; __le16 len; diff --git a/drivers/net/wireless/mwifiex/scan.c b/drivers/net/wireless/mwifiex/scan.c index 69ea32f..64ed60a 100644 --- a/drivers/net/wireless/mwifiex/scan.c +++ b/drivers/net/wireless/mwifiex/scan.c @@ -1210,7 +1210,8 @@ mwifiex_interpret_bss_desc_with_ie(struct mwifiex_adapter *adapter, struct ieee_types_ds_param_set *ds_param_set; struct ieee_types_cf_param_set *cf_param_set; struct ieee_types_ibss_param_set *ibss_param_set; - struct mwifiex_802_11_fixed_ies fixed_ie; + __le16 beacon_interval; + __le16 capabilities; u8 *current_ptr; u8 *rate; u8 element_len; @@ -1283,22 +1284,21 @@ mwifiex_interpret_bss_desc_with_ie(struct mwifiex_adapter *adapter, bss_entry->beacon_buf_size = bytes_left_for_current_beacon; /* Time stamp is 8 bytes long */ - memcpy(fixed_ie.time_stamp, current_ptr, 8); memcpy(bss_entry->time_stamp, current_ptr, 8); current_ptr += 8; bytes_left_for_current_beacon -= 8; /* Beacon interval is 2 bytes long */ - memcpy(&fixed_ie.beacon_interval, current_ptr, 2); - bss_entry->beacon_period = le16_to_cpu(fixed_ie.beacon_interval); + memcpy(&beacon_interval, current_ptr, 2); + bss_entry->beacon_period = le16_to_cpu(beacon_interval); current_ptr += 2; bytes_left_for_current_beacon -= 2; /* Capability information is 2 bytes long */ - memcpy(&fixed_ie.capabilities, current_ptr, 2); - dev_dbg(adapter->dev, "info: InterpretIE: fixed_ie.capabilities=0x%X\n", - fixed_ie.capabilities); - bss_entry->cap_info_bitmap = le16_to_cpu(fixed_ie.capabilities); + memcpy(&capabilities, current_ptr, 2); + dev_dbg(adapter->dev, "info: InterpretIE: capabilities=0x%X\n", + capabilities); + bss_entry->cap_info_bitmap = le16_to_cpu(capabilities); current_ptr += 2; bytes_left_for_current_beacon -= 2; -- cgit v0.10.2 From 8120347de30f98982b8c75243e3b17dd1ee75740 Mon Sep 17 00:00:00 2001 From: Bing Zhao Date: Thu, 31 Mar 2011 19:50:14 -0700 Subject: mwifiex: remove unused macros in decl.h and main.h These macros are leftover of previous cleanup patches. Signed-off-by: Bing Zhao Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/mwifiex/decl.h b/drivers/net/wireless/mwifiex/decl.h index 4e1f115..c3c15f9 100644 --- a/drivers/net/wireless/mwifiex/decl.h +++ b/drivers/net/wireless/mwifiex/decl.h @@ -51,7 +51,6 @@ #define MWIFIEX_RATE_BITMAP_MCS127 159 #define MWIFIEX_RX_DATA_BUF_SIZE (4 * 1024) -#define MWIFIEX_RX_CMD_BUF_SIZE (2 * 1024) #define MWIFIEX_RTS_MIN_VALUE (0) #define MWIFIEX_RTS_MAX_VALUE (2347) @@ -141,13 +140,6 @@ struct mwifiex_bss_attr { u32 bss_num; }; -enum mwifiex_cmd_result_e { - MWIFIEX_CMD_RESULT_SUCCESS = 0, - MWIFIEX_CMD_RESULT_FAILURE = 1, - MWIFIEX_CMD_RESULT_TIMEOUT = 2, - MWIFIEX_CMD_RESULT_INVALID_DATA = 3 -} __packed; - enum mwifiex_wmm_ac_e { WMM_AC_BK, WMM_AC_BE, @@ -155,22 +147,6 @@ enum mwifiex_wmm_ac_e { WMM_AC_VO } __packed; -enum mwifiex_wmm_queue_config_action_e { - MWIFIEX_WMM_QUEUE_CONFIG_ACTION_GET = 0, - MWIFIEX_WMM_QUEUE_CONFIG_ACTION_SET = 1, - MWIFIEX_WMM_QUEUE_CONFIG_ACTION_DEFAULT = 2, - MWIFIEX_WMM_QUEUE_CONFIG_ACTION_MAX -} __packed; - -enum mwifiex_wmm_queue_stats_action_e { - MWIFIEX_WMM_STATS_ACTION_START = 0, - MWIFIEX_WMM_STATS_ACTION_STOP = 1, - MWIFIEX_WMM_STATS_ACTION_GET_CLR = 2, - MWIFIEX_WMM_STATS_ACTION_SET_CFG = 3, /* Not currently used */ - MWIFIEX_WMM_STATS_ACTION_GET_CFG = 4, /* Not currently used */ - MWIFIEX_WMM_STATS_ACTION_MAX -} __packed; - struct mwifiex_device { struct mwifiex_bss_attr bss_attr[MWIFIEX_MAX_BSS_NUM]; }; diff --git a/drivers/net/wireless/mwifiex/main.h b/drivers/net/wireless/mwifiex/main.h index c26f704..43ff149 100644 --- a/drivers/net/wireless/mwifiex/main.h +++ b/drivers/net/wireless/mwifiex/main.h @@ -50,8 +50,6 @@ enum { }; #define DRV_MODE_STA 0x1 -#define DRV_MODE_UAP 0x2 -#define DRV_MODE_UAP_STA 0x3 #define SD8787_W0 0x30 #define SD8787_W1 0x31 @@ -74,13 +72,8 @@ struct mwifiex_drv_mode { #define MWIFIEX_TIMER_10S 10000 #define MWIFIEX_TIMER_1S 1000 -#define NL_MAX_PAYLOAD 1024 -#define NL_MULTICAST_GROUP 1 - #define MAX_TX_PENDING 60 -#define HEADER_ALIGNMENT 8 - #define MWIFIEX_UPLD_SIZE (2312) #define MAX_EVENT_SIZE 1024 -- cgit v0.10.2 From 832fd35a545ecde11082d2dab74dd0aef8e0505e Mon Sep 17 00:00:00 2001 From: Vasanthakumar Thiagarajan Date: Fri, 1 Apr 2011 15:32:16 +0530 Subject: ath9k_hw: Use appropriate rx gain table for AR9485 Signed-off-by: Vasanthakumar Thiagarajan Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/ar9003_hw.c b/drivers/net/wireless/ath/ath9k/ar9003_hw.c index 3daf3df..aebaad9 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_hw.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_hw.c @@ -66,8 +66,8 @@ static void ar9003_hw_init_mode_regs(struct ath_hw *ah) /* rx/tx gain */ INIT_INI_ARRAY(&ah->iniModesRxGain, - ar9485_common_rx_gain_1_1, - ARRAY_SIZE(ar9485_common_rx_gain_1_1), 2); + ar9485Common_wo_xlna_rx_gain_1_1, + ARRAY_SIZE(ar9485Common_wo_xlna_rx_gain_1_1), 2); INIT_INI_ARRAY(&ah->iniModesTxGain, ar9485_modes_lowest_ob_db_tx_gain_1_1, ARRAY_SIZE(ar9485_modes_lowest_ob_db_tx_gain_1_1), @@ -220,8 +220,8 @@ static void ar9003_rx_gain_table_apply(struct ath_hw *ah) default: if (AR_SREV_9485_11(ah)) INIT_INI_ARRAY(&ah->iniModesRxGain, - ar9485_common_rx_gain_1_1, - ARRAY_SIZE(ar9485_common_rx_gain_1_1), + ar9485Common_wo_xlna_rx_gain_1_1, + ARRAY_SIZE(ar9485Common_wo_xlna_rx_gain_1_1), 2); else INIT_INI_ARRAY(&ah->iniModesRxGain, -- cgit v0.10.2 From ce57d9e694d98e421e329fbac5d6f5dc5e9e101e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= Date: Fri, 1 Apr 2011 12:06:48 +0200 Subject: ssb: trivial: use u8 for chip_rev (it's mask is 0xF) 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 diff --git a/drivers/ssb/scan.c b/drivers/ssb/scan.c index 29884c0..7dca719 100644 --- a/drivers/ssb/scan.c +++ b/drivers/ssb/scan.c @@ -307,7 +307,7 @@ int ssb_bus_scan(struct ssb_bus *bus, } else { if (bus->bustype == SSB_BUSTYPE_PCI) { bus->chip_id = pcidev_to_chipid(bus->host_pci); - pci_read_config_word(bus->host_pci, PCI_REVISION_ID, + pci_read_config_byte(bus->host_pci, PCI_REVISION_ID, &bus->chip_rev); bus->chip_package = 0; } else { diff --git a/include/linux/ssb/ssb.h b/include/linux/ssb/ssb.h index 9659eff..7e99b34 100644 --- a/include/linux/ssb/ssb.h +++ b/include/linux/ssb/ssb.h @@ -308,7 +308,7 @@ struct ssb_bus { /* ID information about the Chip. */ u16 chip_id; - u16 chip_rev; + u8 chip_rev; u16 sprom_offset; u16 sprom_size; /* number of words in sprom */ u8 chip_package; -- cgit v0.10.2 From 6c74608bd479bbe02ce330f83df43c3f535ed200 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= Date: Fri, 1 Apr 2011 12:07:32 +0200 Subject: ssb: pci: trivial: drop useless pointer 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 diff --git a/drivers/ssb/driver_pcicore.c b/drivers/ssb/driver_pcicore.c index 0e8d352..e0cf29e 100644 --- a/drivers/ssb/driver_pcicore.c +++ b/drivers/ssb/driver_pcicore.c @@ -417,11 +417,9 @@ static void ssb_pcicore_init_clientmode(struct ssb_pcicore *pc) void ssb_pcicore_init(struct ssb_pcicore *pc) { struct ssb_device *dev = pc->dev; - struct ssb_bus *bus; if (!dev) return; - bus = dev->bus; if (!ssb_device_is_enabled(dev)) ssb_device_enable(dev, 0); -- cgit v0.10.2 From 1b1c7acd9709e545399d1b6b89888f025911c0a2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= Date: Fri, 1 Apr 2011 12:07:33 +0200 Subject: ssb: pci: fix mdio writes on newer cores (rev 10+) 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 diff --git a/drivers/ssb/driver_pcicore.c b/drivers/ssb/driver_pcicore.c index e0cf29e..08fa6fd 100644 --- a/drivers/ssb/driver_pcicore.c +++ b/drivers/ssb/driver_pcicore.c @@ -444,11 +444,35 @@ static void ssb_pcie_write(struct ssb_pcicore *pc, u32 address, u32 data) pcicore_write32(pc, 0x134, data); } +static void ssb_pcie_mdio_set_phy(struct ssb_pcicore *pc, u8 phy) +{ + const u16 mdio_control = 0x128; + const u16 mdio_data = 0x12C; + u32 v; + int i; + + v = (1 << 30); /* Start of Transaction */ + v |= (1 << 28); /* Write Transaction */ + v |= (1 << 17); /* Turnaround */ + v |= (0x1F << 18); + v |= (phy << 4); + pcicore_write32(pc, mdio_data, v); + + udelay(10); + for (i = 0; i < 200; i++) { + v = pcicore_read32(pc, mdio_control); + if (v & 0x100 /* Trans complete */) + break; + msleep(1); + } +} + static void ssb_pcie_mdio_write(struct ssb_pcicore *pc, u8 device, u8 address, u16 data) { const u16 mdio_control = 0x128; const u16 mdio_data = 0x12C; + int max_retries = 10; u32 v; int i; @@ -456,16 +480,22 @@ static void ssb_pcie_mdio_write(struct ssb_pcicore *pc, u8 device, v |= 0x2; /* MDIO Clock Divisor */ pcicore_write32(pc, mdio_control, v); + if (pc->dev->id.revision >= 10) { + max_retries = 200; + ssb_pcie_mdio_set_phy(pc, device); + } + v = (1 << 30); /* Start of Transaction */ v |= (1 << 28); /* Write Transaction */ v |= (1 << 17); /* Turnaround */ - v |= (u32)device << 22; + if (pc->dev->id.revision < 10) + v |= (u32)device << 22; v |= (u32)address << 18; v |= data; pcicore_write32(pc, mdio_data, v); /* Wait for the device to complete the transaction */ udelay(10); - for (i = 0; i < 10; i++) { + for (i = 0; i < max_retries; i++) { v = pcicore_read32(pc, mdio_control); if (v & 0x100 /* Trans complete */) break; -- cgit v0.10.2 From ba91d1a1bcccd90247b5b9703c1a236cc2e95698 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= Date: Fri, 1 Apr 2011 12:07:34 +0200 Subject: ssb: pci: implement mdio reading 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 diff --git a/drivers/ssb/driver_pcicore.c b/drivers/ssb/driver_pcicore.c index 08fa6fd..76cbf96 100644 --- a/drivers/ssb/driver_pcicore.c +++ b/drivers/ssb/driver_pcicore.c @@ -467,6 +467,49 @@ static void ssb_pcie_mdio_set_phy(struct ssb_pcicore *pc, u8 phy) } } +#if 0 +//done but not used yet +static u16 ssb_pcie_mdio_read(struct ssb_pcicore *pc, u8 device, u8 address) +{ + const u16 mdio_control = 0x128; + const u16 mdio_data = 0x12C; + int max_retries = 10; + u16 ret = 0; + u32 v; + int i; + + v = 0x80; /* Enable Preamble Sequence */ + v |= 0x2; /* MDIO Clock Divisor */ + pcicore_write32(pc, mdio_control, v); + + if (pc->dev->id.revision >= 10) { + max_retries = 200; + ssb_pcie_mdio_set_phy(pc, device); + } + + v = (1 << 30); /* Start of Transaction */ + v |= (1 << 29); /* Read Transaction */ + v |= (1 << 17); /* Turnaround */ + if (pc->dev->id.revision < 10) + v |= (u32)device << 22; + v |= (u32)address << 18; + pcicore_write32(pc, mdio_data, v); + /* Wait for the device to complete the transaction */ + udelay(10); + for (i = 0; i < 200; i++) { + v = pcicore_read32(pc, mdio_control); + if (v & 0x100 /* Trans complete */) { + udelay(10); + ret = pcicore_read32(pc, mdio_data); + break; + } + msleep(1); + } + pcicore_write32(pc, mdio_control, 0); + return ret; +} +#endif + static void ssb_pcie_mdio_write(struct ssb_pcicore *pc, u8 device, u8 address, u16 data) { -- cgit v0.10.2 From ccc7c28af205888798b51b6cbc0b557ac1170a49 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= Date: Fri, 1 Apr 2011 13:26:52 +0200 Subject: ssb: pci: implement serdes workaround 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 diff --git a/drivers/ssb/driver_pcicore.c b/drivers/ssb/driver_pcicore.c index 76cbf96..1ba9f0e 100644 --- a/drivers/ssb/driver_pcicore.c +++ b/drivers/ssb/driver_pcicore.c @@ -15,6 +15,11 @@ #include "ssb_private.h" +static u32 ssb_pcie_read(struct ssb_pcicore *pc, u32 address); +static void ssb_pcie_write(struct ssb_pcicore *pc, u32 address, u32 data); +static u16 ssb_pcie_mdio_read(struct ssb_pcicore *pc, u8 device, u8 address); +static void ssb_pcie_mdio_write(struct ssb_pcicore *pc, u8 device, + u8 address, u16 data); static inline u32 pcicore_read32(struct ssb_pcicore *pc, u16 offset) @@ -403,6 +408,27 @@ static int pcicore_is_in_hostmode(struct ssb_pcicore *pc) } #endif /* CONFIG_SSB_PCICORE_HOSTMODE */ +/************************************************** + * Workarounds. + **************************************************/ + +static u8 ssb_pcicore_polarity_workaround(struct ssb_pcicore *pc) +{ + return (ssb_pcie_read(pc, 0x204) & 0x10) ? 0xC0 : 0x80; +} + +static void ssb_pcicore_serdes_workaround(struct ssb_pcicore *pc) +{ + const u8 serdes_pll_device = 0x1D; + const u8 serdes_rx_device = 0x1F; + u16 tmp; + + ssb_pcie_mdio_write(pc, serdes_rx_device, 1 /* Control */, + ssb_pcicore_polarity_workaround(pc)); + tmp = ssb_pcie_mdio_read(pc, serdes_pll_device, 1 /* Control */); + if (tmp & 0x4000) + ssb_pcie_mdio_write(pc, serdes_pll_device, 1, tmp & ~0x4000); +} /************************************************** * Generic and Clientmode operation code. @@ -430,6 +456,8 @@ void ssb_pcicore_init(struct ssb_pcicore *pc) #endif /* CONFIG_SSB_PCICORE_HOSTMODE */ if (!pc->hostmode) ssb_pcicore_init_clientmode(pc); + + ssb_pcicore_serdes_workaround(pc); } static u32 ssb_pcie_read(struct ssb_pcicore *pc, u32 address) @@ -467,8 +495,6 @@ static void ssb_pcie_mdio_set_phy(struct ssb_pcicore *pc, u8 phy) } } -#if 0 -//done but not used yet static u16 ssb_pcie_mdio_read(struct ssb_pcicore *pc, u8 device, u8 address) { const u16 mdio_control = 0x128; @@ -508,7 +534,6 @@ static u16 ssb_pcie_mdio_read(struct ssb_pcicore *pc, u8 device, u8 address) pcicore_write32(pc, mdio_control, 0); return ret; } -#endif static void ssb_pcie_mdio_write(struct ssb_pcicore *pc, u8 device, u8 address, u16 data) -- cgit v0.10.2 From 26d59535aa08386b97ece58a27bb16fca4f066db Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 1 Apr 2011 13:52:48 +0200 Subject: mac80211: clean up station cleanup timer We currently run this timer exactly once when a new mac80211 device is registered, but that is completely pointless since it will have no work to do at all. Therefore, remove that and also simplify some code using the timer. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville diff --git a/net/mac80211/main.c b/net/mac80211/main.c index 562d298..dc50fc31 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c @@ -879,10 +879,6 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) local->dynamic_ps_forced_timeout = -1; - result = sta_info_start(local); - if (result < 0) - goto fail_sta_info; - result = ieee80211_wep_init(local); if (result < 0) wiphy_debug(local->hw.wiphy, "Failed to initialize wep: %d\n", @@ -945,7 +941,6 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) rtnl_unlock(); ieee80211_wep_free(local); sta_info_stop(local); - fail_sta_info: destroy_workqueue(local->workqueue); fail_workqueue: wiphy_unregister(local->hw.wiphy); diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c index 5ec0a7c..999f8fb 100644 --- a/net/mac80211/sta_info.c +++ b/net/mac80211/sta_info.c @@ -768,9 +768,8 @@ static void sta_info_cleanup(unsigned long data) if (!timer_needed) return; - local->sta_cleanup.expires = - round_jiffies(jiffies + STA_INFO_CLEANUP_INTERVAL); - add_timer(&local->sta_cleanup); + mod_timer(&local->sta_cleanup, + round_jiffies(jiffies + STA_INFO_CLEANUP_INTERVAL)); } void sta_info_init(struct ieee80211_local *local) @@ -783,14 +782,6 @@ void sta_info_init(struct ieee80211_local *local) setup_timer(&local->sta_cleanup, sta_info_cleanup, (unsigned long)local); - local->sta_cleanup.expires = - round_jiffies(jiffies + STA_INFO_CLEANUP_INTERVAL); -} - -int sta_info_start(struct ieee80211_local *local) -{ - add_timer(&local->sta_cleanup); - return 0; } void sta_info_stop(struct ieee80211_local *local) diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h index 5768114..43238e9 100644 --- a/net/mac80211/sta_info.h +++ b/net/mac80211/sta_info.h @@ -497,7 +497,6 @@ void sta_info_set_tim_bit(struct sta_info *sta); void sta_info_clear_tim_bit(struct sta_info *sta); void sta_info_init(struct ieee80211_local *local); -int sta_info_start(struct ieee80211_local *local); void sta_info_stop(struct ieee80211_local *local); int sta_info_flush(struct ieee80211_local *local, struct ieee80211_sub_if_data *sdata); diff --git a/net/mac80211/util.c b/net/mac80211/util.c index 556647a..ef0560a 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c @@ -1290,7 +1290,7 @@ int ieee80211_reconfig(struct ieee80211_local *local) } } - add_timer(&local->sta_cleanup); + mod_timer(&local->sta_cleanup, jiffies + 1); mutex_lock(&local->sta_mtx); list_for_each_entry(sta, &local->sta_list, list) -- cgit v0.10.2 From 1e429f3842b5c9b5967a250f4daf78f92436268c Mon Sep 17 00:00:00 2001 From: "Gustavo F. Padovan" Date: Mon, 4 Apr 2011 18:25:14 -0300 Subject: Bluetooth: Remove gfp_mask param from hci_reassembly() It is unnecessary, once we are always in interrupt context. Signed-off-by: Gustavo F. Padovan diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index decd601..a80bc1c 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -1341,7 +1341,7 @@ int hci_recv_frame(struct sk_buff *skb) EXPORT_SYMBOL(hci_recv_frame); static int hci_reassembly(struct hci_dev *hdev, int type, void *data, - int count, __u8 index, gfp_t gfp_mask) + int count, __u8 index) { int len = 0; int hlen = 0; @@ -1371,7 +1371,7 @@ static int hci_reassembly(struct hci_dev *hdev, int type, void *data, break; } - skb = bt_skb_alloc(len, gfp_mask); + skb = bt_skb_alloc(len, GFP_ATOMIC); if (!skb) return -ENOMEM; @@ -1457,8 +1457,7 @@ int hci_recv_fragment(struct hci_dev *hdev, int type, void *data, int count) return -EILSEQ; while (count) { - rem = hci_reassembly(hdev, type, data, count, - type - 1, GFP_ATOMIC); + rem = hci_reassembly(hdev, type, data, count, type - 1); if (rem < 0) return rem; @@ -1492,8 +1491,8 @@ int hci_recv_stream_fragment(struct hci_dev *hdev, void *data, int count) } else type = bt_cb(skb)->pkt_type; - rem = hci_reassembly(hdev, type, data, - count, STREAM_REASSEMBLY, GFP_ATOMIC); + rem = hci_reassembly(hdev, type, data, count, + STREAM_REASSEMBLY); if (rem < 0) return rem; -- cgit v0.10.2 From e17acd40f6006d0a0e0b1b3f7359ba4d543011c6 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Wed, 30 Mar 2011 23:57:16 +0300 Subject: Bluetooth: Add mgmt_device_found event This patch adds a device_found event to the Management interface. For now the event only maps to BR/EDR inquiry result HCI events, but in the future the plan is to also use it for the LE device discovery process. Signed-off-by: Johan Hedberg Signed-off-by: Gustavo F. Padovan diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index 3b2f09d..2a88fc8 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -787,6 +787,8 @@ int mgmt_auth_failed(u16 index, bdaddr_t *bdaddr, u8 status); int mgmt_set_local_name_complete(u16 index, u8 *name, u8 status); int mgmt_read_local_oob_data_reply_complete(u16 index, u8 *hash, u8 *randomizer, u8 status); +int mgmt_device_found(u16 index, bdaddr_t *bdaddr, u8 *dev_class, s8 rssi, + u8 *eir); /* HCI info for socket */ #define hci_pi(sk) ((struct hci_pinfo *) sk) diff --git a/include/net/bluetooth/mgmt.h b/include/net/bluetooth/mgmt.h index 1a6283f..864d0cb 100644 --- a/include/net/bluetooth/mgmt.h +++ b/include/net/bluetooth/mgmt.h @@ -267,3 +267,11 @@ struct mgmt_ev_auth_failed { struct mgmt_ev_local_name_changed { __u8 name[MGMT_MAX_NAME_LENGTH]; } __packed; + +#define MGMT_EV_DEVICE_FOUND 0x0012 +struct mgmt_ev_device_found { + bdaddr_t bdaddr; + __u8 dev_class[3]; + __s8 rssi; + __u8 eir[HCI_MAX_EIR_LENGTH]; +} __packed; diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index 833797e..d04011c 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -1228,7 +1228,7 @@ static inline void hci_inquiry_result_evt(struct hci_dev *hdev, struct sk_buff * hci_dev_lock(hdev); - for (; num_rsp; num_rsp--) { + for (; num_rsp; num_rsp--, info++) { bacpy(&data.bdaddr, &info->bdaddr); data.pscan_rep_mode = info->pscan_rep_mode; data.pscan_period_mode = info->pscan_period_mode; @@ -1237,8 +1237,9 @@ static inline void hci_inquiry_result_evt(struct hci_dev *hdev, struct sk_buff * data.clock_offset = info->clock_offset; data.rssi = 0x00; data.ssp_mode = 0x00; - info++; hci_inquiry_cache_update(hdev, &data); + mgmt_device_found(hdev->id, &info->bdaddr, info->dev_class, 0, + NULL); } hci_dev_unlock(hdev); @@ -2158,7 +2159,7 @@ static inline void hci_inquiry_result_with_rssi_evt(struct hci_dev *hdev, struct struct inquiry_info_with_rssi_and_pscan_mode *info; info = (void *) (skb->data + 1); - for (; num_rsp; num_rsp--) { + for (; num_rsp; num_rsp--, info++) { bacpy(&data.bdaddr, &info->bdaddr); data.pscan_rep_mode = info->pscan_rep_mode; data.pscan_period_mode = info->pscan_period_mode; @@ -2167,13 +2168,15 @@ static inline void hci_inquiry_result_with_rssi_evt(struct hci_dev *hdev, struct data.clock_offset = info->clock_offset; data.rssi = info->rssi; data.ssp_mode = 0x00; - info++; hci_inquiry_cache_update(hdev, &data); + mgmt_device_found(hdev->id, &info->bdaddr, + info->dev_class, info->rssi, + NULL); } } else { struct inquiry_info_with_rssi *info = (void *) (skb->data + 1); - for (; num_rsp; num_rsp--) { + for (; num_rsp; num_rsp--, info++) { bacpy(&data.bdaddr, &info->bdaddr); data.pscan_rep_mode = info->pscan_rep_mode; data.pscan_period_mode = info->pscan_period_mode; @@ -2182,8 +2185,10 @@ static inline void hci_inquiry_result_with_rssi_evt(struct hci_dev *hdev, struct data.clock_offset = info->clock_offset; data.rssi = info->rssi; data.ssp_mode = 0x00; - info++; hci_inquiry_cache_update(hdev, &data); + mgmt_device_found(hdev->id, &info->bdaddr, + info->dev_class, info->rssi, + NULL); } } @@ -2314,7 +2319,7 @@ static inline void hci_extended_inquiry_result_evt(struct hci_dev *hdev, struct hci_dev_lock(hdev); - for (; num_rsp; num_rsp--) { + for (; num_rsp; num_rsp--, info++) { bacpy(&data.bdaddr, &info->bdaddr); data.pscan_rep_mode = info->pscan_rep_mode; data.pscan_period_mode = info->pscan_period_mode; @@ -2323,8 +2328,9 @@ static inline void hci_extended_inquiry_result_evt(struct hci_dev *hdev, struct data.clock_offset = info->clock_offset; data.rssi = info->rssi; data.ssp_mode = 0x01; - info++; hci_inquiry_cache_update(hdev, &data); + mgmt_device_found(hdev->id, &info->bdaddr, info->dev_class, + info->rssi, info->data); } hci_dev_unlock(hdev); diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index f87691e..86fb502 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -2046,3 +2046,20 @@ int mgmt_read_local_oob_data_reply_complete(u16 index, u8 *hash, u8 *randomizer, return err; } + +int mgmt_device_found(u16 index, bdaddr_t *bdaddr, u8 *dev_class, s8 rssi, + u8 *eir) +{ + struct mgmt_ev_device_found ev; + + memset(&ev, 0, sizeof(ev)); + + bacpy(&ev.bdaddr, bdaddr); + memcpy(ev.dev_class, dev_class, sizeof(ev.dev_class)); + ev.rssi = rssi; + + if (eir) + memcpy(ev.eir, eir, sizeof(ev.eir)); + + return mgmt_event(MGMT_EV_DEVICE_FOUND, index, &ev, sizeof(ev), NULL); +} -- cgit v0.10.2 From a88a9652d25a63ce10b6a5fe680d0ad8f33b9c9b Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Wed, 30 Mar 2011 13:18:12 +0300 Subject: Bluetooth: Add mgmt_remote_name event This patch adds a new remote_name event to the Management interface which is sent every time the name of a remote device is resolved (over BR/EDR). Signed-off-by: Johan Hedberg Signed-off-by: Gustavo F. Padovan diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index 2a88fc8..4093133 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -789,6 +789,7 @@ int mgmt_read_local_oob_data_reply_complete(u16 index, u8 *hash, u8 *randomizer, u8 status); int mgmt_device_found(u16 index, bdaddr_t *bdaddr, u8 *dev_class, s8 rssi, u8 *eir); +int mgmt_remote_name(u16 index, bdaddr_t *bdaddr, u8 *name); /* HCI info for socket */ #define hci_pi(sk) ((struct hci_pinfo *) sk) diff --git a/include/net/bluetooth/mgmt.h b/include/net/bluetooth/mgmt.h index 864d0cb..6b6ff92 100644 --- a/include/net/bluetooth/mgmt.h +++ b/include/net/bluetooth/mgmt.h @@ -275,3 +275,9 @@ struct mgmt_ev_device_found { __s8 rssi; __u8 eir[HCI_MAX_EIR_LENGTH]; } __packed; + +#define MGMT_EV_REMOTE_NAME 0x0013 +struct mgmt_ev_remote_name { + bdaddr_t bdaddr; + __u8 name[MGMT_MAX_NAME_LENGTH]; +} __packed; diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index d04011c..7a3398d 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -1497,6 +1497,9 @@ static inline void hci_remote_name_evt(struct hci_dev *hdev, struct sk_buff *skb hci_dev_lock(hdev); + if (ev->status == 0 && test_bit(HCI_MGMT, &hdev->flags)) + mgmt_remote_name(hdev->id, &ev->bdaddr, ev->name); + conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &ev->bdaddr); if (conn && hci_outgoing_auth_needed(hdev, conn)) { struct hci_cp_auth_requested cp; diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 86fb502..9a61320 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -2063,3 +2063,15 @@ int mgmt_device_found(u16 index, bdaddr_t *bdaddr, u8 *dev_class, s8 rssi, return mgmt_event(MGMT_EV_DEVICE_FOUND, index, &ev, sizeof(ev), NULL); } + +int mgmt_remote_name(u16 index, bdaddr_t *bdaddr, u8 *name) +{ + struct mgmt_ev_remote_name ev; + + memset(&ev, 0, sizeof(ev)); + + bacpy(&ev.bdaddr, bdaddr); + memcpy(ev.name, name, HCI_MAX_NAME_LENGTH); + + return mgmt_event(MGMT_EV_REMOTE_NAME, index, &ev, sizeof(ev), NULL); +} -- cgit v0.10.2 From 03e9b64b89243ccc6f8f48f5955a5a78a8ca1431 Mon Sep 17 00:00:00 2001 From: stephen hemminger Date: Mon, 4 Apr 2011 14:03:27 +0000 Subject: bridge: change arguments to fdb_create Later patch provides ability to create non-local static entry. To make this easier move the updating of the flag values to after the code that creates entry. Signed-off-by: Stephen Hemminger Signed-off-by: David S. Miller diff --git a/net/bridge/br_fdb.c b/net/bridge/br_fdb.c index 88485cc..70bd0bf 100644 --- a/net/bridge/br_fdb.c +++ b/net/bridge/br_fdb.c @@ -320,8 +320,7 @@ static inline struct net_bridge_fdb_entry *fdb_find(struct hlist_head *head, static struct net_bridge_fdb_entry *fdb_create(struct hlist_head *head, struct net_bridge_port *source, - const unsigned char *addr, - int is_local) + const unsigned char *addr) { struct net_bridge_fdb_entry *fdb; @@ -329,10 +328,9 @@ static struct net_bridge_fdb_entry *fdb_create(struct hlist_head *head, if (fdb) { memcpy(fdb->addr.addr, addr, ETH_ALEN); fdb->dst = source; - fdb->is_local = is_local; - fdb->is_static = is_local; + fdb->is_local = 0; + fdb->is_static = 0; fdb->ageing_timer = jiffies; - hlist_add_head_rcu(&fdb->hlist, head); } return fdb; @@ -360,12 +358,15 @@ static int fdb_insert(struct net_bridge *br, struct net_bridge_port *source, fdb_delete(fdb); } - if (!fdb_create(head, source, addr, 1)) + fdb = fdb_create(head, source, addr); + if (!fdb) return -ENOMEM; + fdb->is_local = fdb->is_static = 1; return 0; } +/* Add entry for local address of interface */ int br_fdb_insert(struct net_bridge *br, struct net_bridge_port *source, const unsigned char *addr) { @@ -407,8 +408,9 @@ void br_fdb_update(struct net_bridge *br, struct net_bridge_port *source, } } else { spin_lock(&br->hash_lock); - if (!fdb_find(head, addr)) - fdb_create(head, source, addr, 0); + if (likely(!fdb_find(head, addr))) + fdb_create(head, source, addr); + /* else we lose race and someone else inserts * it first, don't bother updating */ -- cgit v0.10.2 From 7cd8861ab0d907430bbea0af93bc41aee0437efc Mon Sep 17 00:00:00 2001 From: stephen hemminger Date: Mon, 4 Apr 2011 14:03:28 +0000 Subject: bridge: track last used time in forwarding table Adds tracking the last used time in forwarding table. Rename ageing_timer to updated to better describe it. Signed-off-by: Stephen Hemminger Signed-off-by: David S. Miller diff --git a/net/bridge/br_fdb.c b/net/bridge/br_fdb.c index 70bd0bf..b391352 100644 --- a/net/bridge/br_fdb.c +++ b/net/bridge/br_fdb.c @@ -62,7 +62,7 @@ static inline int has_expired(const struct net_bridge *br, const struct net_bridge_fdb_entry *fdb) { return !fdb->is_static && - time_before_eq(fdb->ageing_timer + hold_time(br), jiffies); + time_before_eq(fdb->updated + hold_time(br), jiffies); } static inline int br_mac_hash(const unsigned char *mac) @@ -140,7 +140,7 @@ void br_fdb_cleanup(unsigned long _data) unsigned long this_timer; if (f->is_static) continue; - this_timer = f->ageing_timer + delay; + this_timer = f->updated + delay; if (time_before_eq(this_timer, jiffies)) fdb_delete(f); else if (time_before(this_timer, next_timer)) @@ -293,7 +293,7 @@ int br_fdb_fillbuf(struct net_bridge *br, void *buf, fe->is_local = f->is_local; if (!f->is_static) - fe->ageing_timer_value = jiffies_to_clock_t(jiffies - f->ageing_timer); + fe->ageing_timer_value = jiffies_to_clock_t(jiffies - f->updated); ++fe; ++num; } @@ -330,7 +330,7 @@ static struct net_bridge_fdb_entry *fdb_create(struct hlist_head *head, fdb->dst = source; fdb->is_local = 0; fdb->is_static = 0; - fdb->ageing_timer = jiffies; + fdb->updated = fdb->used = jiffies; hlist_add_head_rcu(&fdb->hlist, head); } return fdb; @@ -404,7 +404,7 @@ void br_fdb_update(struct net_bridge *br, struct net_bridge_port *source, } else { /* fastpath: update of existing entry */ fdb->dst = source; - fdb->ageing_timer = jiffies; + fdb->updated = jiffies; } } else { spin_lock(&br->hash_lock); diff --git a/net/bridge/br_input.c b/net/bridge/br_input.c index e216079..785932d 100644 --- a/net/bridge/br_input.c +++ b/net/bridge/br_input.c @@ -98,9 +98,10 @@ int br_handle_frame_finish(struct sk_buff *skb) } if (skb) { - if (dst) + if (dst) { + dst->used = jiffies; br_forward(dst->dst, skb, skb2); - else + } else br_flood_forward(br, skb, skb2); } diff --git a/net/bridge/br_private.h b/net/bridge/br_private.h index 387013d..a0e6b94 100644 --- a/net/bridge/br_private.h +++ b/net/bridge/br_private.h @@ -64,7 +64,8 @@ struct net_bridge_fdb_entry struct net_bridge_port *dst; struct rcu_head rcu; - unsigned long ageing_timer; + unsigned long updated; + unsigned long used; mac_addr addr; unsigned char is_local; unsigned char is_static; -- cgit v0.10.2 From 664de48bb6c4e167fcdf92a4bddf880030fbfbb3 Mon Sep 17 00:00:00 2001 From: stephen hemminger Date: Mon, 4 Apr 2011 14:03:29 +0000 Subject: bridge: split rcu and no-rcu cases of fdb lookup In some cases, look up of forward database entry is done with RCU; and for others no RCU is needed because of locking. Split the two cases into two differnt loops (and take off inline). Signed-off-by: Stephen Hemminger Signed-off-by: David S. Miller diff --git a/net/bridge/br_fdb.c b/net/bridge/br_fdb.c index b391352..a839a5d 100644 --- a/net/bridge/br_fdb.c +++ b/net/bridge/br_fdb.c @@ -305,8 +305,21 @@ int br_fdb_fillbuf(struct net_bridge *br, void *buf, return num; } -static inline struct net_bridge_fdb_entry *fdb_find(struct hlist_head *head, - const unsigned char *addr) +static struct net_bridge_fdb_entry *fdb_find(struct hlist_head *head, + const unsigned char *addr) +{ + struct hlist_node *h; + struct net_bridge_fdb_entry *fdb; + + hlist_for_each_entry(fdb, h, head, hlist) { + if (!compare_ether_addr(fdb->addr.addr, addr)) + return fdb; + } + return NULL; +} + +static struct net_bridge_fdb_entry *fdb_find_rcu(struct hlist_head *head, + const unsigned char *addr) { struct hlist_node *h; struct net_bridge_fdb_entry *fdb; @@ -393,7 +406,7 @@ void br_fdb_update(struct net_bridge *br, struct net_bridge_port *source, source->state == BR_STATE_FORWARDING)) return; - fdb = fdb_find(head, addr); + fdb = fdb_find_rcu(head, addr); if (likely(fdb)) { /* attempt to update an entry for a local interface */ if (unlikely(fdb->is_local)) { -- cgit v0.10.2 From b078f0df676233fc7ebc1ab270bd11ef5824bb64 Mon Sep 17 00:00:00 2001 From: stephen hemminger Date: Mon, 4 Apr 2011 14:03:30 +0000 Subject: bridge: add netlink notification on forward entry changes This allows applications to query and monitor bridge forwarding table in the same method used for neighbor table. The forward table entries are returned in same structure format as used by the ioctl. If more information is desired in future, the netlink method is extensible. Example (using bridge extensions to iproute2) # br monitor Signed-off-by: Stephen Hemminger Signed-off-by: David S. Miller diff --git a/net/bridge/br_fdb.c b/net/bridge/br_fdb.c index a839a5d..5e19e61 100644 --- a/net/bridge/br_fdb.c +++ b/net/bridge/br_fdb.c @@ -28,6 +28,7 @@ static struct kmem_cache *br_fdb_cache __read_mostly; static int fdb_insert(struct net_bridge *br, struct net_bridge_port *source, const unsigned char *addr); +static void fdb_notify(const struct net_bridge_fdb_entry *, int); static u32 fdb_salt __read_mostly; @@ -81,6 +82,7 @@ static void fdb_rcu_free(struct rcu_head *head) static inline void fdb_delete(struct net_bridge_fdb_entry *f) { + fdb_notify(f, RTM_DELNEIGH); hlist_del_rcu(&f->hlist); call_rcu(&f->rcu, fdb_rcu_free); } @@ -345,6 +347,7 @@ static struct net_bridge_fdb_entry *fdb_create(struct hlist_head *head, fdb->is_static = 0; fdb->updated = fdb->used = jiffies; hlist_add_head_rcu(&fdb->hlist, head); + fdb_notify(fdb, RTM_NEWNEIGH); } return fdb; } @@ -430,3 +433,125 @@ void br_fdb_update(struct net_bridge *br, struct net_bridge_port *source, spin_unlock(&br->hash_lock); } } + +static int fdb_to_nud(const struct net_bridge_fdb_entry *fdb) +{ + if (fdb->is_local) + return NUD_PERMANENT; + else if (fdb->is_static) + return NUD_NOARP; + else if (has_expired(fdb->dst->br, fdb)) + return NUD_STALE; + else + return NUD_REACHABLE; +} + +static int fdb_fill_info(struct sk_buff *skb, + const struct net_bridge_fdb_entry *fdb, + u32 pid, u32 seq, int type, unsigned int flags) +{ + unsigned long now = jiffies; + struct nda_cacheinfo ci; + struct nlmsghdr *nlh; + struct ndmsg *ndm; + + nlh = nlmsg_put(skb, pid, seq, type, sizeof(*ndm), flags); + if (nlh == NULL) + return -EMSGSIZE; + + + ndm = nlmsg_data(nlh); + ndm->ndm_family = AF_BRIDGE; + ndm->ndm_pad1 = 0; + ndm->ndm_pad2 = 0; + ndm->ndm_flags = 0; + ndm->ndm_type = 0; + ndm->ndm_ifindex = fdb->dst->dev->ifindex; + ndm->ndm_state = fdb_to_nud(fdb); + + NLA_PUT(skb, NDA_LLADDR, ETH_ALEN, &fdb->addr); + + ci.ndm_used = jiffies_to_clock_t(now - fdb->used); + ci.ndm_confirmed = 0; + ci.ndm_updated = jiffies_to_clock_t(now - fdb->updated); + ci.ndm_refcnt = 0; + NLA_PUT(skb, NDA_CACHEINFO, sizeof(ci), &ci); + + return nlmsg_end(skb, nlh); + +nla_put_failure: + nlmsg_cancel(skb, nlh); + return -EMSGSIZE; +} + +static inline size_t fdb_nlmsg_size(void) +{ + return NLMSG_ALIGN(sizeof(struct ndmsg)) + + nla_total_size(ETH_ALEN) /* NDA_LLADDR */ + + nla_total_size(sizeof(struct nda_cacheinfo)); +} + +static void fdb_notify(const struct net_bridge_fdb_entry *fdb, int type) +{ + struct net *net = dev_net(fdb->dst->dev); + struct sk_buff *skb; + int err = -ENOBUFS; + + skb = nlmsg_new(fdb_nlmsg_size(), GFP_ATOMIC); + if (skb == NULL) + goto errout; + + err = fdb_fill_info(skb, fdb, 0, 0, type, 0); + if (err < 0) { + /* -EMSGSIZE implies BUG in fdb_nlmsg_size() */ + WARN_ON(err == -EMSGSIZE); + kfree_skb(skb); + goto errout; + } + rtnl_notify(skb, net, 0, RTNLGRP_NEIGH, NULL, GFP_ATOMIC); + return; +errout: + if (err < 0) + rtnl_set_sk_err(net, RTNLGRP_NEIGH, err); +} + +/* Dump information about entries, in response to GETNEIGH */ +int br_fdb_dump(struct sk_buff *skb, struct netlink_callback *cb) +{ + struct net *net = sock_net(skb->sk); + struct net_device *dev; + int idx = 0; + + rcu_read_lock(); + for_each_netdev_rcu(net, dev) { + struct net_bridge *br = netdev_priv(dev); + int i; + + if (!(dev->priv_flags & IFF_EBRIDGE)) + continue; + + for (i = 0; i < BR_HASH_SIZE; i++) { + struct hlist_node *h; + struct net_bridge_fdb_entry *f; + + hlist_for_each_entry_rcu(f, h, &br->hash[i], hlist) { + if (idx < cb->args[0]) + goto skip; + + if (fdb_fill_info(skb, f, + NETLINK_CB(cb->skb).pid, + cb->nlh->nlmsg_seq, + RTM_NEWNEIGH, + NLM_F_MULTI) < 0) + break; +skip: + ++idx; + } + } + } + rcu_read_unlock(); + + cb->args[0] = idx; + + return skb->len; +} diff --git a/net/bridge/br_netlink.c b/net/bridge/br_netlink.c index f8bf4c7..cedcafd 100644 --- a/net/bridge/br_netlink.c +++ b/net/bridge/br_netlink.c @@ -196,6 +196,7 @@ int __init br_netlink_init(void) /* Only the first call to __rtnl_register can fail */ __rtnl_register(PF_BRIDGE, RTM_SETLINK, br_rtm_setlink, NULL); + __rtnl_register(PF_BRIDGE, RTM_GETNEIGH, NULL, br_fdb_dump); return 0; } diff --git a/net/bridge/br_private.h b/net/bridge/br_private.h index a0e6b94..884d245 100644 --- a/net/bridge/br_private.h +++ b/net/bridge/br_private.h @@ -354,6 +354,7 @@ extern int br_fdb_insert(struct net_bridge *br, extern void br_fdb_update(struct net_bridge *br, struct net_bridge_port *source, const unsigned char *addr); +extern int br_fdb_dump(struct sk_buff *skb, struct netlink_callback *cb); /* br_forward.c */ extern void br_deliver(const struct net_bridge_port *to, -- cgit v0.10.2 From 36fd2b63e3b4336744cf3f6a6c9543ecbec334a7 Mon Sep 17 00:00:00 2001 From: stephen hemminger Date: Mon, 4 Apr 2011 14:03:31 +0000 Subject: bridge: allow creating/deleting fdb entries via netlink Use RTM_NEWNEIGH and RTM_DELNEIGH to allow updating of entries in bridge forwarding table. This allows manipulating static entries which is not possible with existing tools. Example (using bridge extensions to iproute2) # br fdb add 00:02:03:04:05:06 dev eth0 Signed-off-by: Stephen Hemminger Signed-off-by: David S. Miller diff --git a/net/bridge/br_fdb.c b/net/bridge/br_fdb.c index 5e19e61..498f47c 100644 --- a/net/bridge/br_fdb.c +++ b/net/bridge/br_fdb.c @@ -555,3 +555,142 @@ skip: return skb->len; } + +/* Create new static fdb entry */ +static int fdb_add_entry(struct net_bridge_port *source, const __u8 *addr, + __u16 state) +{ + struct net_bridge *br = source->br; + struct hlist_head *head = &br->hash[br_mac_hash(addr)]; + struct net_bridge_fdb_entry *fdb; + + fdb = fdb_find(head, addr); + if (fdb) + return -EEXIST; + + fdb = fdb_create(head, source, addr); + if (!fdb) + return -ENOMEM; + + if (state & NUD_PERMANENT) + fdb->is_local = fdb->is_static = 1; + else if (state & NUD_NOARP) + fdb->is_static = 1; + return 0; +} + +/* Add new permanent fdb entry with RTM_NEWNEIGH */ +int br_fdb_add(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg) +{ + struct net *net = sock_net(skb->sk); + struct ndmsg *ndm; + struct nlattr *tb[NDA_MAX+1]; + struct net_device *dev; + struct net_bridge_port *p; + const __u8 *addr; + int err; + + ASSERT_RTNL(); + err = nlmsg_parse(nlh, sizeof(*ndm), tb, NDA_MAX, NULL); + if (err < 0) + return err; + + ndm = nlmsg_data(nlh); + if (ndm->ndm_ifindex == 0) { + pr_info("bridge: RTM_NEWNEIGH with invalid ifindex\n"); + return -EINVAL; + } + + dev = __dev_get_by_index(net, ndm->ndm_ifindex); + if (dev == NULL) { + pr_info("bridge: RTM_NEWNEIGH with unknown ifindex\n"); + return -ENODEV; + } + + if (!tb[NDA_LLADDR] || nla_len(tb[NDA_LLADDR]) != ETH_ALEN) { + pr_info("bridge: RTM_NEWNEIGH with invalid address\n"); + return -EINVAL; + } + + addr = nla_data(tb[NDA_LLADDR]); + if (!is_valid_ether_addr(addr)) { + pr_info("bridge: RTM_NEWNEIGH with invalid ether address\n"); + return -EINVAL; + } + + p = br_port_get_rtnl(dev); + if (p == NULL) { + pr_info("bridge: RTM_NEWNEIGH %s not a bridge port\n", + dev->name); + return -EINVAL; + } + + spin_lock_bh(&p->br->hash_lock); + err = fdb_add_entry(p, addr, ndm->ndm_state); + spin_unlock_bh(&p->br->hash_lock); + + return err; +} + +static int fdb_delete_by_addr(struct net_bridge_port *p, const u8 *addr) +{ + struct net_bridge *br = p->br; + struct hlist_head *head = &br->hash[br_mac_hash(addr)]; + struct net_bridge_fdb_entry *fdb; + + fdb = fdb_find(head, addr); + if (!fdb) + return -ENOENT; + + fdb_delete(fdb); + return 0; +} + +/* Remove neighbor entry with RTM_DELNEIGH */ +int br_fdb_delete(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg) +{ + struct net *net = sock_net(skb->sk); + struct ndmsg *ndm; + struct net_bridge_port *p; + struct nlattr *llattr; + const __u8 *addr; + struct net_device *dev; + int err; + + ASSERT_RTNL(); + if (nlmsg_len(nlh) < sizeof(*ndm)) + return -EINVAL; + + ndm = nlmsg_data(nlh); + if (ndm->ndm_ifindex == 0) { + pr_info("bridge: RTM_DELNEIGH with invalid ifindex\n"); + return -EINVAL; + } + + dev = __dev_get_by_index(net, ndm->ndm_ifindex); + if (dev == NULL) { + pr_info("bridge: RTM_DELNEIGH with unknown ifindex\n"); + return -ENODEV; + } + + llattr = nlmsg_find_attr(nlh, sizeof(*ndm), NDA_LLADDR); + if (llattr == NULL || nla_len(llattr) != ETH_ALEN) { + pr_info("bridge: RTM_DELNEIGH with invalid address\n"); + return -EINVAL; + } + + addr = nla_data(llattr); + + p = br_port_get_rtnl(dev); + if (p == NULL) { + pr_info("bridge: RTM_DELNEIGH %s not a bridge port\n", + dev->name); + return -EINVAL; + } + + spin_lock_bh(&p->br->hash_lock); + err = fdb_delete_by_addr(p, addr); + spin_unlock_bh(&p->br->hash_lock); + + return err; +} diff --git a/net/bridge/br_netlink.c b/net/bridge/br_netlink.c index cedcafd..fb7d5a7 100644 --- a/net/bridge/br_netlink.c +++ b/net/bridge/br_netlink.c @@ -196,6 +196,9 @@ int __init br_netlink_init(void) /* Only the first call to __rtnl_register can fail */ __rtnl_register(PF_BRIDGE, RTM_SETLINK, br_rtm_setlink, NULL); + + __rtnl_register(PF_BRIDGE, RTM_NEWNEIGH, br_fdb_add, NULL); + __rtnl_register(PF_BRIDGE, RTM_DELNEIGH, br_fdb_delete, NULL); __rtnl_register(PF_BRIDGE, RTM_GETNEIGH, NULL, br_fdb_dump); return 0; diff --git a/net/bridge/br_private.h b/net/bridge/br_private.h index 884d245..4bbe0d1 100644 --- a/net/bridge/br_private.h +++ b/net/bridge/br_private.h @@ -355,6 +355,8 @@ extern void br_fdb_update(struct net_bridge *br, struct net_bridge_port *source, const unsigned char *addr); extern int br_fdb_dump(struct sk_buff *skb, struct netlink_callback *cb); +extern int br_fdb_add(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg); +extern int br_fdb_delete(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg); /* br_forward.c */ extern void br_deliver(const struct net_bridge_port *to, -- cgit v0.10.2 From bb900b27a2f49b37bc38c08e656ea13048fee13b Mon Sep 17 00:00:00 2001 From: stephen hemminger Date: Mon, 4 Apr 2011 14:03:32 +0000 Subject: bridge: allow creating bridge devices with netlink Add netlink device ops to allow creating bridge device via netlink. This works in a manner similar to vlan, macvlan and bonding. Example: # ip link add link dev br0 type bridge # ip link del dev br0 The change required rearranging initializtion code to deal with being called by create link. Most of the initialization happens in br_dev_setup, but allocation of stats is done in ndo_init callback to deal with allocation failure. Sysfs setup has to wait until after the network device kobject is registered. Signed-off-by: Stephen Hemminger Signed-off-by: David S. Miller diff --git a/net/bridge/br.c b/net/bridge/br.c index 84bbb82..f20c4fd 100644 --- a/net/bridge/br.c +++ b/net/bridge/br.c @@ -104,3 +104,4 @@ module_init(br_init) module_exit(br_deinit) MODULE_LICENSE("GPL"); MODULE_VERSION(BR_VERSION); +MODULE_ALIAS_RTNL_LINK("bridge"); diff --git a/net/bridge/br_device.c b/net/bridge/br_device.c index 21e5901..45cfd54 100644 --- a/net/bridge/br_device.c +++ b/net/bridge/br_device.c @@ -74,6 +74,17 @@ out: return NETDEV_TX_OK; } +static int br_dev_init(struct net_device *dev) +{ + struct net_bridge *br = netdev_priv(dev); + + br->stats = alloc_percpu(struct br_cpu_netstats); + if (!br->stats) + return -ENOMEM; + + return 0; +} + static int br_dev_open(struct net_device *dev) { struct net_bridge *br = netdev_priv(dev); @@ -334,6 +345,7 @@ static const struct ethtool_ops br_ethtool_ops = { static const struct net_device_ops br_netdev_ops = { .ndo_open = br_dev_open, .ndo_stop = br_dev_stop, + .ndo_init = br_dev_init, .ndo_start_xmit = br_dev_xmit, .ndo_get_stats64 = br_get_stats64, .ndo_set_mac_address = br_set_mac_address, @@ -357,18 +369,47 @@ static void br_dev_free(struct net_device *dev) free_netdev(dev); } +static struct device_type br_type = { + .name = "bridge", +}; + void br_dev_setup(struct net_device *dev) { + struct net_bridge *br = netdev_priv(dev); + random_ether_addr(dev->dev_addr); ether_setup(dev); dev->netdev_ops = &br_netdev_ops; dev->destructor = br_dev_free; SET_ETHTOOL_OPS(dev, &br_ethtool_ops); + SET_NETDEV_DEVTYPE(dev, &br_type); dev->tx_queue_len = 0; dev->priv_flags = IFF_EBRIDGE; dev->features = NETIF_F_SG | NETIF_F_FRAGLIST | NETIF_F_HIGHDMA | NETIF_F_GSO_MASK | NETIF_F_NO_CSUM | NETIF_F_LLTX | NETIF_F_NETNS_LOCAL | NETIF_F_GSO | NETIF_F_HW_VLAN_TX; + + br->dev = dev; + spin_lock_init(&br->lock); + INIT_LIST_HEAD(&br->port_list); + spin_lock_init(&br->hash_lock); + + br->bridge_id.prio[0] = 0x80; + br->bridge_id.prio[1] = 0x00; + + memcpy(br->group_addr, br_group_address, ETH_ALEN); + + br->feature_mask = dev->features; + br->stp_enabled = BR_NO_STP; + br->designated_root = br->bridge_id; + br->bridge_max_age = br->max_age = 20 * HZ; + br->bridge_hello_time = br->hello_time = 2 * HZ; + br->bridge_forward_delay = br->forward_delay = 15 * HZ; + br->ageing_time = 300 * HZ; + + br_netfilter_rtable_init(br); + br_stp_timer_init(br); + br_multicast_init(br); } diff --git a/net/bridge/br_if.c b/net/bridge/br_if.c index 718b603..7f5379c 100644 --- a/net/bridge/br_if.c +++ b/net/bridge/br_if.c @@ -175,56 +175,6 @@ static void del_br(struct net_bridge *br, struct list_head *head) unregister_netdevice_queue(br->dev, head); } -static struct net_device *new_bridge_dev(struct net *net, const char *name) -{ - struct net_bridge *br; - struct net_device *dev; - - dev = alloc_netdev(sizeof(struct net_bridge), name, - br_dev_setup); - - if (!dev) - return NULL; - dev_net_set(dev, net); - - br = netdev_priv(dev); - br->dev = dev; - - br->stats = alloc_percpu(struct br_cpu_netstats); - if (!br->stats) { - free_netdev(dev); - return NULL; - } - - spin_lock_init(&br->lock); - INIT_LIST_HEAD(&br->port_list); - spin_lock_init(&br->hash_lock); - - br->bridge_id.prio[0] = 0x80; - br->bridge_id.prio[1] = 0x00; - - memcpy(br->group_addr, br_group_address, ETH_ALEN); - - br->feature_mask = dev->features; - br->stp_enabled = BR_NO_STP; - br->designated_root = br->bridge_id; - br->root_path_cost = 0; - br->root_port = 0; - br->bridge_max_age = br->max_age = 20 * HZ; - br->bridge_hello_time = br->hello_time = 2 * HZ; - br->bridge_forward_delay = br->forward_delay = 15 * HZ; - br->topology_change = 0; - br->topology_change_detected = 0; - br->ageing_time = 300 * HZ; - - br_netfilter_rtable_init(br); - - br_stp_timer_init(br); - br_multicast_init(br); - - return dev; -} - /* find an available port number */ static int find_portno(struct net_bridge *br) { @@ -277,42 +227,19 @@ static struct net_bridge_port *new_nbp(struct net_bridge *br, return p; } -static struct device_type br_type = { - .name = "bridge", -}; - int br_add_bridge(struct net *net, const char *name) { struct net_device *dev; - int ret; - dev = new_bridge_dev(net, name); + dev = alloc_netdev(sizeof(struct net_bridge), name, + br_dev_setup); + if (!dev) return -ENOMEM; - rtnl_lock(); - if (strchr(dev->name, '%')) { - ret = dev_alloc_name(dev, dev->name); - if (ret < 0) - goto out_free; - } - - SET_NETDEV_DEVTYPE(dev, &br_type); - - ret = register_netdevice(dev); - if (ret) - goto out_free; - - ret = br_sysfs_addbr(dev); - if (ret) - unregister_netdevice(dev); - out: - rtnl_unlock(); - return ret; + dev_net_set(dev, net); -out_free: - free_netdev(dev); - goto out; + return register_netdev(dev); } int br_del_bridge(struct net *net, const char *name) diff --git a/net/bridge/br_netlink.c b/net/bridge/br_netlink.c index fb7d5a7..134a2ff 100644 --- a/net/bridge/br_netlink.c +++ b/net/bridge/br_netlink.c @@ -12,9 +12,11 @@ #include #include +#include #include #include #include + #include "br_private.h" static inline size_t br_nlmsg_size(void) @@ -188,24 +190,61 @@ static int br_rtm_setlink(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg) return 0; } +static int br_validate(struct nlattr *tb[], struct nlattr *data[]) +{ + if (tb[IFLA_ADDRESS]) { + if (nla_len(tb[IFLA_ADDRESS]) != ETH_ALEN) + return -EINVAL; + if (!is_valid_ether_addr(nla_data(tb[IFLA_ADDRESS]))) + return -EADDRNOTAVAIL; + } + + return 0; +} + +static struct rtnl_link_ops br_link_ops __read_mostly = { + .kind = "bridge", + .priv_size = sizeof(struct net_bridge), + .setup = br_dev_setup, + .validate = br_validate, +}; int __init br_netlink_init(void) { - if (__rtnl_register(PF_BRIDGE, RTM_GETLINK, NULL, br_dump_ifinfo)) - return -ENOBUFS; - - /* Only the first call to __rtnl_register can fail */ - __rtnl_register(PF_BRIDGE, RTM_SETLINK, br_rtm_setlink, NULL); + int err; - __rtnl_register(PF_BRIDGE, RTM_NEWNEIGH, br_fdb_add, NULL); - __rtnl_register(PF_BRIDGE, RTM_DELNEIGH, br_fdb_delete, NULL); - __rtnl_register(PF_BRIDGE, RTM_GETNEIGH, NULL, br_fdb_dump); + err = rtnl_link_register(&br_link_ops); + if (err < 0) + goto err1; + + err = __rtnl_register(PF_BRIDGE, RTM_GETLINK, NULL, br_dump_ifinfo); + if (err) + goto err2; + err = __rtnl_register(PF_BRIDGE, RTM_SETLINK, br_rtm_setlink, NULL); + if (err) + goto err3; + err = __rtnl_register(PF_BRIDGE, RTM_NEWNEIGH, br_fdb_add, NULL); + if (err) + goto err3; + err = __rtnl_register(PF_BRIDGE, RTM_DELNEIGH, br_fdb_delete, NULL); + if (err) + goto err3; + err = __rtnl_register(PF_BRIDGE, RTM_GETNEIGH, NULL, br_fdb_dump); + if (err) + goto err3; return 0; + +err3: + rtnl_unregister_all(PF_BRIDGE); +err2: + rtnl_link_unregister(&br_link_ops); +err1: + return err; } void __exit br_netlink_fini(void) { + rtnl_link_unregister(&br_link_ops); rtnl_unregister_all(PF_BRIDGE); } - diff --git a/net/bridge/br_notify.c b/net/bridge/br_notify.c index 7d337c9..7a03bb9 100644 --- a/net/bridge/br_notify.c +++ b/net/bridge/br_notify.c @@ -36,6 +36,12 @@ static int br_device_event(struct notifier_block *unused, unsigned long event, v struct net_bridge *br; int err; + /* register of bridge completed, add sysfs entries */ + if ((dev->priv_flags && IFF_EBRIDGE) && event == NETDEV_REGISTER) { + br_sysfs_addbr(dev); + return NOTIFY_DONE; + } + /* not a port of a bridge */ p = br_port_get_rtnl(dev); if (!p) -- cgit v0.10.2 From 14f98f258f1936e0dba77474bd7eda63f61a9826 Mon Sep 17 00:00:00 2001 From: stephen hemminger Date: Mon, 4 Apr 2011 14:03:33 +0000 Subject: bridge: range check STP parameters Apply restrictions on STP parameters based 802.1D 1998 standard. * Fixes missing locking in set path cost ioctl * Uses common code for both ioctl and sysfs This is based on an earlier patch Sasikanth V but with overhaul. Note: 1. It does NOT enforce the restriction on the relationship max_age and forward delay or hello time because in existing implementation these are set as independant operations. 2. If STP is disabled, there is no restriction on forward delay 3. No restriction on holding time because users use Linux code to act as hub or be sticky. 4. Although standard allow 0-255, Linux only allows 0-63 for port priority because more bits are reserved for port number. Signed-off-by: Stephen Hemminger Signed-off-by: David S. Miller diff --git a/net/bridge/br_ioctl.c b/net/bridge/br_ioctl.c index cb43312..0459890 100644 --- a/net/bridge/br_ioctl.c +++ b/net/bridge/br_ioctl.c @@ -181,40 +181,19 @@ static int old_dev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) if (!capable(CAP_NET_ADMIN)) return -EPERM; - spin_lock_bh(&br->lock); - br->bridge_forward_delay = clock_t_to_jiffies(args[1]); - if (br_is_root_bridge(br)) - br->forward_delay = br->bridge_forward_delay; - spin_unlock_bh(&br->lock); - return 0; + return br_set_forward_delay(br, args[1]); case BRCTL_SET_BRIDGE_HELLO_TIME: - { - unsigned long t = clock_t_to_jiffies(args[1]); if (!capable(CAP_NET_ADMIN)) return -EPERM; - if (t < HZ) - return -EINVAL; - - spin_lock_bh(&br->lock); - br->bridge_hello_time = t; - if (br_is_root_bridge(br)) - br->hello_time = br->bridge_hello_time; - spin_unlock_bh(&br->lock); - return 0; - } + return br_set_hello_time(br, args[1]); case BRCTL_SET_BRIDGE_MAX_AGE: if (!capable(CAP_NET_ADMIN)) return -EPERM; - spin_lock_bh(&br->lock); - br->bridge_max_age = clock_t_to_jiffies(args[1]); - if (br_is_root_bridge(br)) - br->max_age = br->bridge_max_age; - spin_unlock_bh(&br->lock); - return 0; + return br_set_max_age(br, args[1]); case BRCTL_SET_AGEING_TIME: if (!capable(CAP_NET_ADMIN)) @@ -275,19 +254,16 @@ static int old_dev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) case BRCTL_SET_PORT_PRIORITY: { struct net_bridge_port *p; - int ret = 0; + int ret; if (!capable(CAP_NET_ADMIN)) return -EPERM; - if (args[2] >= (1<<(16-BR_PORT_BITS))) - return -ERANGE; - spin_lock_bh(&br->lock); if ((p = br_get_port(br, args[1])) == NULL) ret = -EINVAL; else - br_stp_set_port_priority(p, args[2]); + ret = br_stp_set_port_priority(p, args[2]); spin_unlock_bh(&br->lock); return ret; } @@ -295,15 +271,17 @@ static int old_dev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) case BRCTL_SET_PATH_COST: { struct net_bridge_port *p; - int ret = 0; + int ret; if (!capable(CAP_NET_ADMIN)) return -EPERM; + spin_lock_bh(&br->lock); if ((p = br_get_port(br, args[1])) == NULL) ret = -EINVAL; else - br_stp_set_path_cost(p, args[2]); + ret = br_stp_set_path_cost(p, args[2]); + spin_unlock_bh(&br->lock); return ret; } diff --git a/net/bridge/br_private.h b/net/bridge/br_private.h index 4bbe0d1..e2a4034 100644 --- a/net/bridge/br_private.h +++ b/net/bridge/br_private.h @@ -495,6 +495,11 @@ extern struct net_bridge_port *br_get_port(struct net_bridge *br, extern void br_init_port(struct net_bridge_port *p); extern void br_become_designated_port(struct net_bridge_port *p); +extern int br_set_forward_delay(struct net_bridge *br, unsigned long x); +extern int br_set_hello_time(struct net_bridge *br, unsigned long x); +extern int br_set_max_age(struct net_bridge *br, unsigned long x); + + /* br_stp_if.c */ extern void br_stp_enable_bridge(struct net_bridge *br); extern void br_stp_disable_bridge(struct net_bridge *br); @@ -505,10 +510,10 @@ extern bool br_stp_recalculate_bridge_id(struct net_bridge *br); extern void br_stp_change_bridge_id(struct net_bridge *br, const unsigned char *a); extern void br_stp_set_bridge_priority(struct net_bridge *br, u16 newprio); -extern void br_stp_set_port_priority(struct net_bridge_port *p, - u8 newprio); -extern void br_stp_set_path_cost(struct net_bridge_port *p, - u32 path_cost); +extern int br_stp_set_port_priority(struct net_bridge_port *p, + unsigned long newprio); +extern int br_stp_set_path_cost(struct net_bridge_port *p, + unsigned long path_cost); extern ssize_t br_show_bridge_id(char *buf, const struct bridge_id *id); /* br_stp_bpdu.c */ diff --git a/net/bridge/br_private_stp.h b/net/bridge/br_private_stp.h index 8b650f7..642ef47 100644 --- a/net/bridge/br_private_stp.h +++ b/net/bridge/br_private_stp.h @@ -16,6 +16,19 @@ #define BPDU_TYPE_CONFIG 0 #define BPDU_TYPE_TCN 0x80 +/* IEEE 802.1D-1998 timer values */ +#define BR_MIN_HELLO_TIME (1*HZ) +#define BR_MAX_HELLO_TIME (10*HZ) + +#define BR_MIN_FORWARD_DELAY (2*HZ) +#define BR_MAX_FORWARD_DELAY (30*HZ) + +#define BR_MIN_MAX_AGE (6*HZ) +#define BR_MAX_MAX_AGE (40*HZ) + +#define BR_MIN_PATH_COST 1 +#define BR_MAX_PATH_COST 65535 + struct br_config_bpdu { unsigned topology_change:1; diff --git a/net/bridge/br_stp.c b/net/bridge/br_stp.c index 7370d14..bb4383e 100644 --- a/net/bridge/br_stp.c +++ b/net/bridge/br_stp.c @@ -484,3 +484,51 @@ void br_received_tcn_bpdu(struct net_bridge_port *p) br_topology_change_acknowledge(p); } } + +/* Change bridge STP parameter */ +int br_set_hello_time(struct net_bridge *br, unsigned long val) +{ + unsigned long t = clock_t_to_jiffies(val); + + if (t < BR_MIN_HELLO_TIME || t > BR_MAX_HELLO_TIME) + return -ERANGE; + + spin_lock_bh(&br->lock); + br->bridge_hello_time = t; + if (br_is_root_bridge(br)) + br->hello_time = br->bridge_hello_time; + spin_unlock_bh(&br->lock); + return 0; +} + +int br_set_max_age(struct net_bridge *br, unsigned long val) +{ + unsigned long t = clock_t_to_jiffies(val); + + if (t < BR_MIN_MAX_AGE || t > BR_MAX_MAX_AGE) + return -ERANGE; + + spin_lock_bh(&br->lock); + br->bridge_max_age = t; + if (br_is_root_bridge(br)) + br->max_age = br->bridge_max_age; + spin_unlock_bh(&br->lock); + return 0; + +} + +int br_set_forward_delay(struct net_bridge *br, unsigned long val) +{ + unsigned long t = clock_t_to_jiffies(val); + + if (br->stp_enabled != BR_NO_STP && + (t < BR_MIN_FORWARD_DELAY || t > BR_MAX_FORWARD_DELAY)) + return -ERANGE; + + spin_lock_bh(&br->lock); + br->bridge_forward_delay = t; + if (br_is_root_bridge(br)) + br->forward_delay = br->bridge_forward_delay; + spin_unlock_bh(&br->lock); + return 0; +} diff --git a/net/bridge/br_stp_if.c b/net/bridge/br_stp_if.c index 9b61d09..6f615b8 100644 --- a/net/bridge/br_stp_if.c +++ b/net/bridge/br_stp_if.c @@ -20,7 +20,7 @@ /* Port id is composed of priority and port number. - * NB: least significant bits of priority are dropped to + * NB: some bits of priority are dropped to * make room for more ports. */ static inline port_id br_make_port_id(__u8 priority, __u16 port_no) @@ -29,6 +29,8 @@ static inline port_id br_make_port_id(__u8 priority, __u16 port_no) | (port_no & ((1<> BR_PORT_BITS) + /* called under bridge lock */ void br_init_port(struct net_bridge_port *p) { @@ -255,10 +257,14 @@ void br_stp_set_bridge_priority(struct net_bridge *br, u16 newprio) } /* called under bridge lock */ -void br_stp_set_port_priority(struct net_bridge_port *p, u8 newprio) +int br_stp_set_port_priority(struct net_bridge_port *p, unsigned long newprio) { - port_id new_port_id = br_make_port_id(newprio, p->port_no); + port_id new_port_id; + + if (newprio > BR_MAX_PORT_PRIORITY) + return -ERANGE; + new_port_id = br_make_port_id(newprio, p->port_no); if (br_is_designated_port(p)) p->designated_port = new_port_id; @@ -269,14 +275,21 @@ void br_stp_set_port_priority(struct net_bridge_port *p, u8 newprio) br_become_designated_port(p); br_port_state_selection(p->br); } + + return 0; } /* called under bridge lock */ -void br_stp_set_path_cost(struct net_bridge_port *p, u32 path_cost) +int br_stp_set_path_cost(struct net_bridge_port *p, unsigned long path_cost) { + if (path_cost < BR_MIN_PATH_COST || + path_cost > BR_MAX_PATH_COST) + return -ERANGE; + p->path_cost = path_cost; br_configuration_update(p->br); br_port_state_selection(p->br); + return 0; } ssize_t br_show_bridge_id(char *buf, const struct bridge_id *id) diff --git a/net/bridge/br_sysfs_br.c b/net/bridge/br_sysfs_br.c index 5c1e555..68b893e 100644 --- a/net/bridge/br_sysfs_br.c +++ b/net/bridge/br_sysfs_br.c @@ -43,9 +43,7 @@ static ssize_t store_bridge_parm(struct device *d, if (endp == buf) return -EINVAL; - spin_lock_bh(&br->lock); err = (*set)(br, val); - spin_unlock_bh(&br->lock); return err ? err : len; } @@ -57,20 +55,11 @@ static ssize_t show_forward_delay(struct device *d, return sprintf(buf, "%lu\n", jiffies_to_clock_t(br->forward_delay)); } -static int set_forward_delay(struct net_bridge *br, unsigned long val) -{ - unsigned long delay = clock_t_to_jiffies(val); - br->forward_delay = delay; - if (br_is_root_bridge(br)) - br->bridge_forward_delay = delay; - return 0; -} - static ssize_t store_forward_delay(struct device *d, struct device_attribute *attr, const char *buf, size_t len) { - return store_bridge_parm(d, buf, len, set_forward_delay); + return store_bridge_parm(d, buf, len, br_set_forward_delay); } static DEVICE_ATTR(forward_delay, S_IRUGO | S_IWUSR, show_forward_delay, store_forward_delay); @@ -82,24 +71,11 @@ static ssize_t show_hello_time(struct device *d, struct device_attribute *attr, jiffies_to_clock_t(to_bridge(d)->hello_time)); } -static int set_hello_time(struct net_bridge *br, unsigned long val) -{ - unsigned long t = clock_t_to_jiffies(val); - - if (t < HZ) - return -EINVAL; - - br->hello_time = t; - if (br_is_root_bridge(br)) - br->bridge_hello_time = t; - return 0; -} - static ssize_t store_hello_time(struct device *d, struct device_attribute *attr, const char *buf, size_t len) { - return store_bridge_parm(d, buf, len, set_hello_time); + return store_bridge_parm(d, buf, len, br_set_hello_time); } static DEVICE_ATTR(hello_time, S_IRUGO | S_IWUSR, show_hello_time, store_hello_time); @@ -111,19 +87,10 @@ static ssize_t show_max_age(struct device *d, struct device_attribute *attr, jiffies_to_clock_t(to_bridge(d)->max_age)); } -static int set_max_age(struct net_bridge *br, unsigned long val) -{ - unsigned long t = clock_t_to_jiffies(val); - br->max_age = t; - if (br_is_root_bridge(br)) - br->bridge_max_age = t; - return 0; -} - static ssize_t store_max_age(struct device *d, struct device_attribute *attr, const char *buf, size_t len) { - return store_bridge_parm(d, buf, len, set_max_age); + return store_bridge_parm(d, buf, len, br_set_max_age); } static DEVICE_ATTR(max_age, S_IRUGO | S_IWUSR, show_max_age, store_max_age); diff --git a/net/bridge/br_sysfs_if.c b/net/bridge/br_sysfs_if.c index fd5799c..6229b62 100644 --- a/net/bridge/br_sysfs_if.c +++ b/net/bridge/br_sysfs_if.c @@ -23,7 +23,7 @@ struct brport_attribute { struct attribute attr; ssize_t (*show)(struct net_bridge_port *, char *); - ssize_t (*store)(struct net_bridge_port *, unsigned long); + int (*store)(struct net_bridge_port *, unsigned long); }; #define BRPORT_ATTR(_name,_mode,_show,_store) \ @@ -38,27 +38,17 @@ static ssize_t show_path_cost(struct net_bridge_port *p, char *buf) { return sprintf(buf, "%d\n", p->path_cost); } -static ssize_t store_path_cost(struct net_bridge_port *p, unsigned long v) -{ - br_stp_set_path_cost(p, v); - return 0; -} + static BRPORT_ATTR(path_cost, S_IRUGO | S_IWUSR, - show_path_cost, store_path_cost); + show_path_cost, br_stp_set_path_cost); static ssize_t show_priority(struct net_bridge_port *p, char *buf) { return sprintf(buf, "%d\n", p->priority); } -static ssize_t store_priority(struct net_bridge_port *p, unsigned long v) -{ - if (v >= (1<<(16-BR_PORT_BITS))) - return -ERANGE; - br_stp_set_port_priority(p, v); - return 0; -} + static BRPORT_ATTR(priority, S_IRUGO | S_IWUSR, - show_priority, store_priority); + show_priority, br_stp_set_port_priority); static ssize_t show_designated_root(struct net_bridge_port *p, char *buf) { @@ -136,7 +126,7 @@ static ssize_t show_hold_timer(struct net_bridge_port *p, } static BRPORT_ATTR(hold_timer, S_IRUGO, show_hold_timer, NULL); -static ssize_t store_flush(struct net_bridge_port *p, unsigned long v) +static int store_flush(struct net_bridge_port *p, unsigned long v) { br_fdb_delete_by_port(p->br, p, 0); // Don't delete local entry return 0; @@ -148,7 +138,7 @@ static ssize_t show_hairpin_mode(struct net_bridge_port *p, char *buf) int hairpin_mode = (p->flags & BR_HAIRPIN_MODE) ? 1 : 0; return sprintf(buf, "%d\n", hairpin_mode); } -static ssize_t store_hairpin_mode(struct net_bridge_port *p, unsigned long v) +static int store_hairpin_mode(struct net_bridge_port *p, unsigned long v) { if (v) p->flags |= BR_HAIRPIN_MODE; @@ -165,7 +155,7 @@ static ssize_t show_multicast_router(struct net_bridge_port *p, char *buf) return sprintf(buf, "%d\n", p->multicast_router); } -static ssize_t store_multicast_router(struct net_bridge_port *p, +static int store_multicast_router(struct net_bridge_port *p, unsigned long v) { return br_multicast_set_port_router(p, v); -- cgit v0.10.2 From e3f6a652fd0e828de586a3a87b56c07f7a32259a Mon Sep 17 00:00:00 2001 From: Simon Horman Date: Tue, 5 Apr 2011 11:25:03 +0900 Subject: IPVS: combine consecutive #ifdef CONFIG_PROC_FS blocks Signed-off-by: Simon Horman diff --git a/net/netfilter/ipvs/ip_vs_ctl.c b/net/netfilter/ipvs/ip_vs_ctl.c index 33733c8..36f4495 100644 --- a/net/netfilter/ipvs/ip_vs_ctl.c +++ b/net/netfilter/ipvs/ip_vs_ctl.c @@ -1984,9 +1984,6 @@ static const struct file_operations ip_vs_info_fops = { .release = seq_release_private, }; -#endif - -#ifdef CONFIG_PROC_FS static int ip_vs_stats_show(struct seq_file *seq, void *v) { struct net *net = seq_file_single_net(seq); -- cgit v0.10.2 From c6e1a0d12ca7b4f22c58e55a16beacfb7d3d8462 Mon Sep 17 00:00:00 2001 From: Tom Herbert Date: Mon, 4 Apr 2011 22:30:30 -0700 Subject: net: Allow no-cache copy from user on transmit This patch uses __copy_from_user_nocache on transmit to bypass data cache for a performance improvement. skb_add_data_nocache and skb_copy_to_page_nocache can be called by sendmsg functions to use this feature, initial support is in tcp_sendmsg. This functionality is configurable per device using ethtool. Presumably, this feature would only be useful when the driver does not touch the data. The feature is turned on by default if a device indicates that it does some form of checksum offload; it is off by default for devices that do no checksum offload or indicate no checksum is necessary. For the former case copy-checksum is probably done anyway, in the latter case the device is likely loopback in which case the no cache copy is probably not beneficial. This patch was tested using 200 instances of netperf TCP_RR with 1400 byte request and one byte reply. Platform is 16 core AMD x86. No-cache copy disabled: 672703 tps, 97.13% utilization 50/90/99% latency:244.31 484.205 1028.41 No-cache copy enabled: 702113 tps, 96.16% utilization, 50/90/99% latency 238.56 467.56 956.955 Using 14000 byte request and response sizes demonstrate the effects more dramatically: No-cache copy disabled: 79571 tps, 34.34 %utlization 50/90/95% latency 1584.46 2319.59 5001.76 No-cache copy enabled: 83856 tps, 34.81% utilization 50/90/95% latency 2508.42 2622.62 2735.88 Note especially the effect on latency tail (95th percentile). This seems to provide a nice performance improvement and is consistent in the tests I ran. Presumably, this would provide the greatest benfits in the presence of an application workload stressing the cache and a lot of transmit data happening. Signed-off-by: Tom Herbert Signed-off-by: David S. Miller diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index 16d6fe9..b51e021 100644 --- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c @@ -1407,7 +1407,7 @@ static int bond_compute_features(struct bonding *bond) int i; features &= ~(NETIF_F_ALL_CSUM | BOND_VLAN_FEATURES); - features |= NETIF_F_GSO_MASK | NETIF_F_NO_CSUM; + features |= NETIF_F_GSO_MASK | NETIF_F_NO_CSUM | NETIF_F_NOCACHE_COPY; if (!bond->first_slave) goto done; diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index a4664cc6..09d2624 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -1066,6 +1066,7 @@ struct net_device { #define NETIF_F_NTUPLE (1 << 27) /* N-tuple filters supported */ #define NETIF_F_RXHASH (1 << 28) /* Receive hashing offload */ #define NETIF_F_RXCSUM (1 << 29) /* Receive checksumming offload */ +#define NETIF_F_NOCACHE_COPY (1 << 30) /* Use no-cache copyfromuser */ /* Segmentation offload features */ #define NETIF_F_GSO_SHIFT 16 @@ -1081,7 +1082,7 @@ struct net_device { /* = all defined minus driver/device-class-related */ #define NETIF_F_NEVER_CHANGE (NETIF_F_HIGHDMA | NETIF_F_VLAN_CHALLENGED | \ NETIF_F_LLTX | NETIF_F_NETNS_LOCAL) -#define NETIF_F_ETHTOOL_BITS (0x3f3fffff & ~NETIF_F_NEVER_CHANGE) +#define NETIF_F_ETHTOOL_BITS (0x7f3fffff & ~NETIF_F_NEVER_CHANGE) /* List of features with software fallbacks. */ #define NETIF_F_GSO_SOFTWARE (NETIF_F_TSO | NETIF_F_TSO_ECN | \ diff --git a/include/net/sock.h b/include/net/sock.h index da0534d..43bd515 100644 --- a/include/net/sock.h +++ b/include/net/sock.h @@ -52,6 +52,7 @@ #include #include #include +#include #include #include @@ -1389,6 +1390,58 @@ static inline void sk_nocaps_add(struct sock *sk, int flags) sk->sk_route_caps &= ~flags; } +static inline int skb_do_copy_data_nocache(struct sock *sk, struct sk_buff *skb, + char __user *from, char *to, + int copy) +{ + if (skb->ip_summed == CHECKSUM_NONE) { + int err = 0; + __wsum csum = csum_and_copy_from_user(from, to, copy, 0, &err); + if (err) + return err; + skb->csum = csum_block_add(skb->csum, csum, skb->len); + } else if (sk->sk_route_caps & NETIF_F_NOCACHE_COPY) { + if (!access_ok(VERIFY_READ, from, copy) || + __copy_from_user_nocache(to, from, copy)) + return -EFAULT; + } else if (copy_from_user(to, from, copy)) + return -EFAULT; + + return 0; +} + +static inline int skb_add_data_nocache(struct sock *sk, struct sk_buff *skb, + char __user *from, int copy) +{ + int err; + + err = skb_do_copy_data_nocache(sk, skb, from, skb_put(skb, copy), copy); + if (err) + __skb_trim(skb, skb->len); + + return err; +} + +static inline int skb_copy_to_page_nocache(struct sock *sk, char __user *from, + struct sk_buff *skb, + struct page *page, + int off, int copy) +{ + int err; + + err = skb_do_copy_data_nocache(sk, skb, from, + page_address(page) + off, copy); + if (err) + return err; + + skb->len += copy; + skb->data_len += copy; + skb->truesize += copy; + sk->sk_wmem_queued += copy; + sk_mem_charge(sk, copy); + return 0; +} + static inline int skb_copy_to_page(struct sock *sk, char __user *from, struct sk_buff *skb, struct page *page, int off, int copy) diff --git a/net/core/dev.c b/net/core/dev.c index 02f5637..5d0b4f6 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -5425,6 +5425,14 @@ int register_netdevice(struct net_device *dev) dev->features &= ~NETIF_F_GSO; } + /* Turn on no cache copy if HW is doing checksum */ + dev->hw_features |= NETIF_F_NOCACHE_COPY; + if ((dev->features & NETIF_F_ALL_CSUM) && + !(dev->features & NETIF_F_NO_CSUM)) { + dev->wanted_features |= NETIF_F_NOCACHE_COPY; + dev->features |= NETIF_F_NOCACHE_COPY; + } + /* Enable GRO and NETIF_F_HIGHDMA for vlans by default, * vlan_dev_init() will do the dev->features check, so these features * are enabled only if supported by underlying device. @@ -6182,6 +6190,10 @@ u32 netdev_increment_features(u32 all, u32 one, u32 mask) } } + /* If device can't no cache copy, don't do for all */ + if (!(one & NETIF_F_NOCACHE_COPY)) + all &= ~NETIF_F_NOCACHE_COPY; + one |= NETIF_F_ALL_CSUM; one |= all & NETIF_F_ONE_FOR_ALL; diff --git a/net/core/ethtool.c b/net/core/ethtool.c index 439e4b0..719670a 100644 --- a/net/core/ethtool.c +++ b/net/core/ethtool.c @@ -359,7 +359,7 @@ static const char netdev_features_strings[ETHTOOL_DEV_FEATURE_WORDS * 32][ETH_GS /* NETIF_F_NTUPLE */ "rx-ntuple-filter", /* NETIF_F_RXHASH */ "rx-hashing", /* NETIF_F_RXCSUM */ "rx-checksum", - "", + /* NETIF_F_NOCACHE_COPY */ "tx-nocache-copy" "", }; diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c index b22d450..054a59d 100644 --- a/net/ipv4/tcp.c +++ b/net/ipv4/tcp.c @@ -999,7 +999,8 @@ new_segment: /* We have some space in skb head. Superb! */ if (copy > skb_tailroom(skb)) copy = skb_tailroom(skb); - if ((err = skb_add_data(skb, from, copy)) != 0) + err = skb_add_data_nocache(sk, skb, from, copy); + if (err) goto do_fault; } else { int merge = 0; @@ -1042,8 +1043,8 @@ new_segment: /* Time to copy data. We are close to * the end! */ - err = skb_copy_to_page(sk, from, skb, page, - off, copy); + err = skb_copy_to_page_nocache(sk, from, skb, + page, off, copy); if (err) { /* If this page was new, give it to the * socket so it does not get leaked. -- cgit v0.10.2 From f82d9a67fbcdfd8af6be7a7c9e381864ec9a271a Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Tue, 5 Apr 2011 13:36:09 +0100 Subject: sfc: Enable all TSO features on VLANs The TSO code already supports IPv6 on VLAN, so enable it. Signed-off-by: Ben Hutchings diff --git a/drivers/net/sfc/efx.c b/drivers/net/sfc/efx.c index d890679..542f32d 100644 --- a/drivers/net/sfc/efx.c +++ b/drivers/net/sfc/efx.c @@ -2457,7 +2457,7 @@ static int __devinit efx_pci_probe(struct pci_dev *pci_dev, net_dev->features |= NETIF_F_TSO6; /* Mask for features that also apply to VLAN devices */ net_dev->vlan_features |= (NETIF_F_ALL_CSUM | NETIF_F_SG | - NETIF_F_HIGHDMA | NETIF_F_TSO); + NETIF_F_HIGHDMA | NETIF_F_ALL_TSO); efx = netdev_priv(net_dev); pci_set_drvdata(pci_dev, efx); SET_NETDEV_DEV(net_dev, &pci_dev->dev); -- cgit v0.10.2 From abfe903980161b11f3594e3dcbab8b5c5a67168b Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Tue, 5 Apr 2011 15:00:02 +0100 Subject: sfc: Implement generic features interface Signed-off-by: Ben Hutchings diff --git a/drivers/net/sfc/efx.c b/drivers/net/sfc/efx.c index 542f32d..db72a6e 100644 --- a/drivers/net/sfc/efx.c +++ b/drivers/net/sfc/efx.c @@ -1874,6 +1874,17 @@ static void efx_set_multicast_list(struct net_device *net_dev) /* Otherwise efx_start_port() will do this */ } +static int efx_set_features(struct net_device *net_dev, u32 data) +{ + struct efx_nic *efx = netdev_priv(net_dev); + + /* If disabling RX n-tuple filtering, clear existing filters */ + if (net_dev->features & ~data & NETIF_F_NTUPLE) + efx_filter_clear_rx(efx, EFX_FILTER_PRI_MANUAL); + + return 0; +} + static const struct net_device_ops efx_netdev_ops = { .ndo_open = efx_net_open, .ndo_stop = efx_net_stop, @@ -1885,6 +1896,7 @@ static const struct net_device_ops efx_netdev_ops = { .ndo_change_mtu = efx_change_mtu, .ndo_set_mac_address = efx_set_mac_address, .ndo_set_multicast_list = efx_set_multicast_list, + .ndo_set_features = efx_set_features, #ifdef CONFIG_NET_POLL_CONTROLLER .ndo_poll_controller = efx_netpoll, #endif @@ -2269,7 +2281,6 @@ static int efx_init_struct(struct efx_nic *efx, struct efx_nic_type *type, strlcpy(efx->name, pci_name(pci_dev), sizeof(efx->name)); efx->net_dev = net_dev; - efx->rx_checksum_enabled = true; spin_lock_init(&efx->stats_lock); mutex_init(&efx->mac_lock); efx->mac_op = type->default_mac_ops; @@ -2452,12 +2463,15 @@ static int __devinit efx_pci_probe(struct pci_dev *pci_dev, return -ENOMEM; net_dev->features |= (type->offload_features | NETIF_F_SG | NETIF_F_HIGHDMA | NETIF_F_TSO | - NETIF_F_GRO); + NETIF_F_RXCSUM); if (type->offload_features & NETIF_F_V6_CSUM) net_dev->features |= NETIF_F_TSO6; /* Mask for features that also apply to VLAN devices */ net_dev->vlan_features |= (NETIF_F_ALL_CSUM | NETIF_F_SG | - NETIF_F_HIGHDMA | NETIF_F_ALL_TSO); + NETIF_F_HIGHDMA | NETIF_F_ALL_TSO | + NETIF_F_RXCSUM); + /* All offloads can be toggled */ + net_dev->hw_features = net_dev->features & ~NETIF_F_HIGHDMA; efx = netdev_priv(net_dev); pci_set_drvdata(pci_dev, efx); SET_NETDEV_DEV(net_dev, &pci_dev->dev); diff --git a/drivers/net/sfc/ethtool.c b/drivers/net/sfc/ethtool.c index 807178e..0d55439 100644 --- a/drivers/net/sfc/ethtool.c +++ b/drivers/net/sfc/ethtool.c @@ -518,72 +518,6 @@ static void efx_ethtool_get_stats(struct net_device *net_dev, } } -static int efx_ethtool_set_tso(struct net_device *net_dev, u32 enable) -{ - struct efx_nic *efx __attribute__ ((unused)) = netdev_priv(net_dev); - u32 features; - - features = NETIF_F_TSO; - if (efx->type->offload_features & NETIF_F_V6_CSUM) - features |= NETIF_F_TSO6; - - if (enable) - net_dev->features |= features; - else - net_dev->features &= ~features; - - return 0; -} - -static int efx_ethtool_set_tx_csum(struct net_device *net_dev, u32 enable) -{ - struct efx_nic *efx = netdev_priv(net_dev); - u32 features = efx->type->offload_features & NETIF_F_ALL_CSUM; - - if (enable) - net_dev->features |= features; - else - net_dev->features &= ~features; - - return 0; -} - -static int efx_ethtool_set_rx_csum(struct net_device *net_dev, u32 enable) -{ - struct efx_nic *efx = netdev_priv(net_dev); - - /* No way to stop the hardware doing the checks; we just - * ignore the result. - */ - efx->rx_checksum_enabled = !!enable; - - return 0; -} - -static u32 efx_ethtool_get_rx_csum(struct net_device *net_dev) -{ - struct efx_nic *efx = netdev_priv(net_dev); - - return efx->rx_checksum_enabled; -} - -static int efx_ethtool_set_flags(struct net_device *net_dev, u32 data) -{ - struct efx_nic *efx = netdev_priv(net_dev); - u32 supported = (efx->type->offload_features & - (ETH_FLAG_RXHASH | ETH_FLAG_NTUPLE)); - int rc; - - rc = ethtool_op_set_flags(net_dev, data, supported); - if (rc) - return rc; - - if (!(data & ETH_FLAG_NTUPLE)) - efx_filter_clear_rx(efx, EFX_FILTER_PRI_MANUAL); - - return 0; -} - static void efx_ethtool_self_test(struct net_device *net_dev, struct ethtool_test *test, u64 *data) { @@ -1070,18 +1004,6 @@ const struct ethtool_ops efx_ethtool_ops = { .set_ringparam = efx_ethtool_set_ringparam, .get_pauseparam = efx_ethtool_get_pauseparam, .set_pauseparam = efx_ethtool_set_pauseparam, - .get_rx_csum = efx_ethtool_get_rx_csum, - .set_rx_csum = efx_ethtool_set_rx_csum, - .get_tx_csum = ethtool_op_get_tx_csum, - /* Need to enable/disable IPv6 too */ - .set_tx_csum = efx_ethtool_set_tx_csum, - .get_sg = ethtool_op_get_sg, - .set_sg = ethtool_op_set_sg, - .get_tso = ethtool_op_get_tso, - /* Need to enable/disable TSO-IPv6 too */ - .set_tso = efx_ethtool_set_tso, - .get_flags = ethtool_op_get_flags, - .set_flags = efx_ethtool_set_flags, .get_sset_count = efx_ethtool_get_sset_count, .self_test = efx_ethtool_self_test, .get_strings = efx_ethtool_get_strings, diff --git a/drivers/net/sfc/net_driver.h b/drivers/net/sfc/net_driver.h index 215d5c5..f0f8ca5 100644 --- a/drivers/net/sfc/net_driver.h +++ b/drivers/net/sfc/net_driver.h @@ -681,7 +681,6 @@ struct efx_filter_state; * @port_inhibited: If set, the netif_carrier is always off. Hold the mac_lock * @port_initialized: Port initialized? * @net_dev: Operating system network device. Consider holding the rtnl lock - * @rx_checksum_enabled: RX checksumming enabled * @stats_buffer: DMA buffer for statistics * @mac_op: MAC interface * @phy_type: PHY type @@ -771,7 +770,6 @@ struct efx_nic { bool port_initialized; struct net_device *net_dev; - bool rx_checksum_enabled; struct efx_buffer stats_buffer; diff --git a/drivers/net/sfc/rx.c b/drivers/net/sfc/rx.c index fb402c5..b7dc891 100644 --- a/drivers/net/sfc/rx.c +++ b/drivers/net/sfc/rx.c @@ -605,7 +605,7 @@ void __efx_rx_packet(struct efx_channel *channel, skb_record_rx_queue(skb, channel->channel); } - if (unlikely(!efx->rx_checksum_enabled)) + if (unlikely(!(efx->net_dev->features & NETIF_F_RXCSUM))) checksummed = false; if (likely(checksummed || rx_buf->is_page)) { -- cgit v0.10.2 From e20b5b61a36bd5b80eea064c0f2e73285dbe0d3b Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Fri, 1 Apr 2011 22:52:34 +0100 Subject: ethtool: Convert struct ethtool_ops comment to kernel-doc format Signed-off-by: Ben Hutchings diff --git a/include/linux/ethtool.h b/include/linux/ethtool.h index c8fcbdd..ab12f84 100644 --- a/include/linux/ethtool.h +++ b/include/linux/ethtool.h @@ -683,63 +683,53 @@ void ethtool_ntuple_flush(struct net_device *dev); bool ethtool_invalid_flags(struct net_device *dev, u32 data, u32 supported); /** - * ðtool_ops - Alter and report network device settings - * get_settings: Get device-specific settings - * set_settings: Set device-specific settings - * get_drvinfo: Report driver information - * get_regs: Get device registers - * get_wol: Report whether Wake-on-Lan is enabled - * set_wol: Turn Wake-on-Lan on or off - * get_msglevel: Report driver message level - * set_msglevel: Set driver message level - * nway_reset: Restart autonegotiation - * get_link: Get link status - * get_eeprom: Read data from the device EEPROM - * set_eeprom: Write data to the device EEPROM - * get_coalesce: Get interrupt coalescing parameters - * set_coalesce: Set interrupt coalescing parameters - * get_ringparam: Report ring sizes - * set_ringparam: Set ring sizes - * get_pauseparam: Report pause parameters - * set_pauseparam: Set pause parameters - * get_rx_csum: Report whether receive checksums are turned on or off - * set_rx_csum: Turn receive checksum on or off - * get_tx_csum: Report whether transmit checksums are turned on or off - * set_tx_csum: Turn transmit checksums on or off - * get_sg: Report whether scatter-gather is enabled - * set_sg: Turn scatter-gather on or off - * get_tso: Report whether TCP segmentation offload is enabled - * set_tso: Turn TCP segmentation offload on or off - * get_ufo: Report whether UDP fragmentation offload is enabled - * set_ufo: Turn UDP fragmentation offload on or off - * self_test: Run specified self-tests - * get_strings: Return a set of strings that describe the requested objects - * phys_id: Identify the device - * get_stats: Return statistics about the device - * get_flags: get 32-bit flags bitmap - * set_flags: set 32-bit flags bitmap - * - * Description: - * - * get_settings: + * struct ethtool_ops - Alter and report network device settings + * @get_settings: Get device-specific settings. * @get_settings is passed an ðtool_cmd to fill in. It returns * an negative errno or zero. - * - * set_settings: + * @set_settings: Set device-specific settings. * @set_settings is passed an ðtool_cmd and should attempt to set * all the settings this device supports. It may return an error value * if something goes wrong (otherwise 0). - * - * get_eeprom: + * @get_drvinfo: Report driver information + * @get_regs: Get device registers + * @get_wol: Report whether Wake-on-Lan is enabled + * @set_wol: Turn Wake-on-Lan on or off + * @get_msglevel: Report driver message level + * @set_msglevel: Set driver message level + * @nway_reset: Restart autonegotiation + * @get_link: Get link status + * @get_eeprom: Read data from the device EEPROM. * Should fill in the magic field. Don't need to check len for zero * or wraparound. Fill in the data argument with the eeprom values * from offset to offset + len. Update len to the amount read. * Returns an error or zero. - * - * set_eeprom: + * @set_eeprom: Write data to the device EEPROM. * Should validate the magic field. Don't need to check len for zero * or wraparound. Update len to the amount written. Returns an error * or zero. + * @get_coalesce: Get interrupt coalescing parameters + * @set_coalesce: Set interrupt coalescing parameters + * @get_ringparam: Report ring sizes + * @set_ringparam: Set ring sizes + * @get_pauseparam: Report pause parameters + * @set_pauseparam: Set pause parameters + * @get_rx_csum: Report whether receive checksums are turned on or off + * @set_rx_csum: Turn receive checksum on or off + * @get_tx_csum: Report whether transmit checksums are turned on or off + * @set_tx_csum: Turn transmit checksums on or off + * @get_sg: Report whether scatter-gather is enabled + * @set_sg: Turn scatter-gather on or off + * @get_tso: Report whether TCP segmentation offload is enabled + * @set_tso: Turn TCP segmentation offload on or off + * @get_ufo: Report whether UDP fragmentation offload is enabled + * @set_ufo: Turn UDP fragmentation offload on or off + * @self_test: Run specified self-tests + * @get_strings: Return a set of strings that describe the requested objects + * @phys_id: Identify the device + * @get_stats: Return statistics about the device + * @get_flags: get 32-bit flags bitmap + * @set_flags: set 32-bit flags bitmap */ struct ethtool_ops { int (*get_settings)(struct net_device *, struct ethtool_cmd *); -- cgit v0.10.2 From 8717d07b1143e0f150921f5bd7cfe7af579a995a Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Fri, 1 Apr 2011 23:57:41 +0100 Subject: ethtool: Fill out and update comment for struct ethtool_ops Briefly document all operations (except get_rx_ntuple), including whether they may return an error code and whether they are deprecated. Also mention some things that should be handled by the ethtool core rather than by drivers. Briefly document general requirements for callers. Signed-off-by: Ben Hutchings diff --git a/include/linux/ethtool.h b/include/linux/ethtool.h index ab12f84..ead7dcb 100644 --- a/include/linux/ethtool.h +++ b/include/linux/ethtool.h @@ -683,22 +683,28 @@ void ethtool_ntuple_flush(struct net_device *dev); bool ethtool_invalid_flags(struct net_device *dev, u32 data, u32 supported); /** - * struct ethtool_ops - Alter and report network device settings - * @get_settings: Get device-specific settings. - * @get_settings is passed an ðtool_cmd to fill in. It returns - * an negative errno or zero. - * @set_settings: Set device-specific settings. - * @set_settings is passed an ðtool_cmd and should attempt to set - * all the settings this device supports. It may return an error value - * if something goes wrong (otherwise 0). - * @get_drvinfo: Report driver information + * struct ethtool_ops - optional netdev operations + * @get_settings: Get various device settings including Ethernet link + * settings. Returns a negative error code or zero. + * @set_settings: Set various device settings including Ethernet link + * settings. Returns a negative error code or zero. + * @get_drvinfo: Report driver/device information. Should only set the + * @driver, @version, @fw_version and @bus_info fields. If not + * implemented, the @driver and @bus_info fields will be filled in + * according to the netdev's parent device. + * @get_regs_len: Get buffer length required for @get_regs * @get_regs: Get device registers * @get_wol: Report whether Wake-on-Lan is enabled - * @set_wol: Turn Wake-on-Lan on or off - * @get_msglevel: Report driver message level + * @set_wol: Turn Wake-on-Lan on or off. Returns a negative error code + * or zero. + * @get_msglevel: Report driver message level. This should be the value + * of the @msg_enable field used by netif logging functions. * @set_msglevel: Set driver message level - * @nway_reset: Restart autonegotiation - * @get_link: Get link status + * @nway_reset: Restart autonegotiation. Returns a negative error code + * or zero. + * @get_link: Report whether physical link is up. Will only be called if + * the netdev is up. Should usually be set to ethtool_op_get_link(), + * which uses netif_carrier_ok(). * @get_eeprom: Read data from the device EEPROM. * Should fill in the magic field. Don't need to check len for zero * or wraparound. Fill in the data argument with the eeprom values @@ -708,28 +714,84 @@ bool ethtool_invalid_flags(struct net_device *dev, u32 data, u32 supported); * Should validate the magic field. Don't need to check len for zero * or wraparound. Update len to the amount written. Returns an error * or zero. - * @get_coalesce: Get interrupt coalescing parameters - * @set_coalesce: Set interrupt coalescing parameters + * @get_coalesce: Get interrupt coalescing parameters. Returns a negative + * error code or zero. + * @set_coalesce: Set interrupt coalescing parameters. Returns a negative + * error code or zero. * @get_ringparam: Report ring sizes - * @set_ringparam: Set ring sizes + * @set_ringparam: Set ring sizes. Returns a negative error code or zero. * @get_pauseparam: Report pause parameters - * @set_pauseparam: Set pause parameters - * @get_rx_csum: Report whether receive checksums are turned on or off - * @set_rx_csum: Turn receive checksum on or off - * @get_tx_csum: Report whether transmit checksums are turned on or off - * @set_tx_csum: Turn transmit checksums on or off - * @get_sg: Report whether scatter-gather is enabled - * @set_sg: Turn scatter-gather on or off - * @get_tso: Report whether TCP segmentation offload is enabled - * @set_tso: Turn TCP segmentation offload on or off - * @get_ufo: Report whether UDP fragmentation offload is enabled - * @set_ufo: Turn UDP fragmentation offload on or off + * @set_pauseparam: Set pause parameters. Returns a negative error code + * or zero. + * @get_rx_csum: Deprecated in favour of the netdev feature %NETIF_F_RXCSUM. + * Report whether receive checksums are turned on or off. + * @set_rx_csum: Deprecated in favour of generic netdev features. Turn + * receive checksum on or off. Returns a negative error code or zero. + * @get_tx_csum: Deprecated as redundant. Report whether transmit checksums + * are turned on or off. + * @set_tx_csum: Deprecated in favour of generic netdev features. Turn + * transmit checksums on or off. Returns a egative error code or zero. + * @get_sg: Deprecated as redundant. Report whether scatter-gather is + * enabled. + * @set_sg: Deprecated in favour of generic netdev features. Turn + * scatter-gather on or off. Returns a negative error code or zero. + * @get_tso: Deprecated as redundant. Report whether TCP segmentation + * offload is enabled. + * @set_tso: Deprecated in favour of generic netdev features. Turn TCP + * segmentation offload on or off. Returns a negative error code or zero. * @self_test: Run specified self-tests * @get_strings: Return a set of strings that describe the requested objects - * @phys_id: Identify the device - * @get_stats: Return statistics about the device - * @get_flags: get 32-bit flags bitmap - * @set_flags: set 32-bit flags bitmap + * @phys_id: Identify the physical device, e.g. by flashing an LED + * attached to it until interrupted by a signal or the given time + * (in seconds) elapses. If the given time is zero, use a default + * time limit. Returns a negative error code or zero. Being + * interrupted by a signal is not an error. + * @get_ethtool_stats: Return extended statistics about the device. + * This is only useful if the device maintains statistics not + * included in &struct rtnl_link_stats64. + * @begin: Function to be called before any other operation. Returns a + * negative error code or zero. + * @complete: Function to be called after any other operation except + * @begin. Will be called even if the other operation failed. + * @get_ufo: Deprecated as redundant. Report whether UDP fragmentation + * offload is enabled. + * @set_ufo: Deprecated in favour of generic netdev features. Turn UDP + * fragmentation offload on or off. Returns a negative error code or zero. + * @get_flags: Deprecated as redundant. Report features included in + * &enum ethtool_flags that are enabled. + * @set_flags: Deprecated in favour of generic netdev features. Turn + * features included in &enum ethtool_flags on or off. Returns a + * negative error code or zero. + * @get_priv_flags: Report driver-specific feature flags. + * @set_priv_flags: Set driver-specific feature flags. Returns a negative + * error code or zero. + * @get_sset_count: Get number of strings that @get_strings will write. + * @get_rxnfc: Get RX flow classification rules. Returns a negative + * error code or zero. + * @set_rxnfc: Set RX flow classification rules. Returns a negative + * error code or zero. + * @flash_device: Write a firmware image to device's flash memory. + * Returns a negative error code or zero. + * @reset: Reset (part of) the device, as specified by a bitmask of + * flags from &enum ethtool_reset_flags. Returns a negative + * error code or zero. + * @set_rx_ntuple: Set an RX n-tuple rule. Returns a negative error code + * or zero. + * @get_rx_ntuple: Deprecated. + * @get_rxfh_indir: Get the contents of the RX flow hash indirection table. + * Returns a negative error code or zero. + * @set_rxfh_indir: Set the contents of the RX flow hash indirection table. + * Returns a negative error code or zero. + * + * All operations are optional (i.e. the function pointer may be set + * to %NULL) and callers must take this into account. Callers must + * hold the RTNL, except that for @get_drvinfo the caller may or may + * not hold the RTNL. + * + * See the structures used by these operations for further documentation. + * + * See &struct net_device and &struct net_device_ops for documentation + * of the generic netdev features interface. */ struct ethtool_ops { int (*get_settings)(struct net_device *, struct ethtool_cmd *); -- cgit v0.10.2 From 68f512f21a64c9b264df6c61a9333e7890faf74b Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Sat, 2 Apr 2011 00:35:15 +0100 Subject: ethtool: Change ETHTOOL_PHYS_ID implementation to allow dropping RTNL The ethtool ETHTOOL_PHYS_ID command runs for an arbitrarily long period of time, holding the RTNL lock. This blocks routing updates, device enumeration, and various important operations that one might want to keep running while hunting for the flashing LED. We need to drop the RTNL lock during this operation, but currently the core implementation is a thin wrapper around a driver operation and drivers may well depend upon holding the lock. Define a new driver operation 'set_phys_id' with an argument that sets the ID indicator on/off/inactive/active (the last optional, for any driver or firmware that prefers to handle blinking asynchronously). When this is defined, the ethtool core drops the lock while waiting and only acquires it around calls to this operation. Deprecate the 'phys_id' operation in favour of this. It can be removed once all in-tree drivers are converted. Signed-off-by: Ben Hutchings diff --git a/include/linux/ethtool.h b/include/linux/ethtool.h index ead7dcb..c04d131 100644 --- a/include/linux/ethtool.h +++ b/include/linux/ethtool.h @@ -663,6 +663,22 @@ struct ethtool_rx_ntuple_list { unsigned int count; }; +/** + * enum ethtool_phys_id_state - indicator state for physical identification + * @ETHTOOL_ID_INACTIVE: Physical ID indicator should be deactivated + * @ETHTOOL_ID_ACTIVE: Physical ID indicator should be activated + * @ETHTOOL_ID_ON: LED should be turned on (used iff %ETHTOOL_ID_ACTIVE + * is not supported) + * @ETHTOOL_ID_OFF: LED should be turned off (used iff %ETHTOOL_ID_ACTIVE + * is not supported) + */ +enum ethtool_phys_id_state { + ETHTOOL_ID_INACTIVE, + ETHTOOL_ID_ACTIVE, + ETHTOOL_ID_ON, + ETHTOOL_ID_OFF +}; + struct net_device; /* Some generic methods drivers may use in their ethtool_ops */ @@ -741,7 +757,18 @@ bool ethtool_invalid_flags(struct net_device *dev, u32 data, u32 supported); * segmentation offload on or off. Returns a negative error code or zero. * @self_test: Run specified self-tests * @get_strings: Return a set of strings that describe the requested objects - * @phys_id: Identify the physical device, e.g. by flashing an LED + * @set_phys_id: Identify the physical devices, e.g. by flashing an LED + * attached to it. The implementation may update the indicator + * asynchronously or synchronously, but in either case it must return + * quickly. It is initially called with the argument %ETHTOOL_ID_ACTIVE, + * and must either activate asynchronous updates or return -%EINVAL. + * If it returns -%EINVAL then it will be called again at intervals with + * argument %ETHTOOL_ID_ON or %ETHTOOL_ID_OFF and should set the state of + * the indicator accordingly. Finally, it is called with the argument + * %ETHTOOL_ID_INACTIVE and must deactivate the indicator. Returns a + * negative error code or zero. + * @phys_id: Deprecated in favour of @set_phys_id. + * Identify the physical device, e.g. by flashing an LED * attached to it until interrupted by a signal or the given time * (in seconds) elapses. If the given time is zero, use a default * time limit. Returns a negative error code or zero. Being @@ -830,6 +857,7 @@ struct ethtool_ops { int (*set_tso)(struct net_device *, u32); void (*self_test)(struct net_device *, struct ethtool_test *, u64 *); void (*get_strings)(struct net_device *, u32 stringset, u8 *); + int (*set_phys_id)(struct net_device *, enum ethtool_phys_id_state); int (*phys_id)(struct net_device *, u32); void (*get_ethtool_stats)(struct net_device *, struct ethtool_stats *, u64 *); diff --git a/net/core/ethtool.c b/net/core/ethtool.c index 74ead9e..1c95f0f 100644 --- a/net/core/ethtool.c +++ b/net/core/ethtool.c @@ -21,6 +21,8 @@ #include #include #include +#include +#include /* * Some useful ethtool_ops methods that're device independent. @@ -1618,14 +1620,63 @@ out: static int ethtool_phys_id(struct net_device *dev, void __user *useraddr) { struct ethtool_value id; + static bool busy; + int rc; - if (!dev->ethtool_ops->phys_id) + if (!dev->ethtool_ops->set_phys_id && !dev->ethtool_ops->phys_id) return -EOPNOTSUPP; + if (busy) + return -EBUSY; + if (copy_from_user(&id, useraddr, sizeof(id))) return -EFAULT; - return dev->ethtool_ops->phys_id(dev, id.data); + if (!dev->ethtool_ops->set_phys_id) + /* Do it the old way */ + return dev->ethtool_ops->phys_id(dev, id.data); + + rc = dev->ethtool_ops->set_phys_id(dev, ETHTOOL_ID_ACTIVE); + if (rc && rc != -EINVAL) + return rc; + + /* Drop the RTNL lock while waiting, but prevent reentry or + * removal of the device. + */ + busy = true; + dev_hold(dev); + rtnl_unlock(); + + if (rc == 0) { + /* Driver will handle this itself */ + schedule_timeout_interruptible( + id.data ? id.data : MAX_SCHEDULE_TIMEOUT); + } else { + /* Driver expects to be called periodically */ + do { + rtnl_lock(); + rc = dev->ethtool_ops->set_phys_id(dev, ETHTOOL_ID_ON); + rtnl_unlock(); + if (rc) + break; + schedule_timeout_interruptible(HZ / 2); + + rtnl_lock(); + rc = dev->ethtool_ops->set_phys_id(dev, ETHTOOL_ID_OFF); + rtnl_unlock(); + if (rc) + break; + schedule_timeout_interruptible(HZ / 2); + } while (!signal_pending(current) && + (id.data == 0 || --id.data != 0)); + } + + rtnl_lock(); + dev_put(dev); + busy = false; + + (void)dev->ethtool_ops->set_phys_id(dev, ETHTOOL_ID_INACTIVE); + return rc; } static int ethtool_get_stats(struct net_device *dev, void __user *useraddr) -- cgit v0.10.2 From c5e129ac2fc72c119b85db79a629de66332f136d Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Sat, 2 Apr 2011 00:43:46 +0100 Subject: sfc: Implement ethtool_ops::set_phys_id instead of ethtool_ops::phys_id Signed-off-by: Ben Hutchings diff --git a/drivers/net/sfc/ethtool.c b/drivers/net/sfc/ethtool.c index 0d55439..644f7c1 100644 --- a/drivers/net/sfc/ethtool.c +++ b/drivers/net/sfc/ethtool.c @@ -178,19 +178,27 @@ static struct efx_ethtool_stat efx_ethtool_stats[] = { */ /* Identify device by flashing LEDs */ -static int efx_ethtool_phys_id(struct net_device *net_dev, u32 count) +static int efx_ethtool_phys_id(struct net_device *net_dev, + enum ethtool_phys_id_state state) { struct efx_nic *efx = netdev_priv(net_dev); + enum efx_led_mode mode; - do { - efx->type->set_id_led(efx, EFX_LED_ON); - schedule_timeout_interruptible(HZ / 2); - - efx->type->set_id_led(efx, EFX_LED_OFF); - schedule_timeout_interruptible(HZ / 2); - } while (!signal_pending(current) && --count != 0); + switch (state) { + case ETHTOOL_ID_ON: + mode = EFX_LED_ON; + break; + case ETHTOOL_ID_OFF: + mode = EFX_LED_OFF; + break; + case ETHTOOL_ID_INACTIVE: + mode = EFX_LED_DEFAULT; + break; + default: + return -EINVAL; + } - efx->type->set_id_led(efx, EFX_LED_DEFAULT); + efx->type->set_id_led(efx, mode); return 0; } @@ -1007,7 +1015,7 @@ const struct ethtool_ops efx_ethtool_ops = { .get_sset_count = efx_ethtool_get_sset_count, .self_test = efx_ethtool_self_test, .get_strings = efx_ethtool_get_strings, - .phys_id = efx_ethtool_phys_id, + .set_phys_id = efx_ethtool_phys_id, .get_ethtool_stats = efx_ethtool_get_stats, .get_wol = efx_ethtool_get_wol, .set_wol = efx_ethtool_set_wol, -- cgit v0.10.2 From aabf6f897e44bdf3e237ada04aa8f88d77d75cac Mon Sep 17 00:00:00 2001 From: Szymon Janc Date: Tue, 5 Apr 2011 15:37:45 +0200 Subject: Bluetooth: Use kthread API in hidp kernel_thread() is a low-level implementation detail and EXPORT_SYMBOL(kernel_thread) is scheduled for removal. Use the API instead. Signed-off-by: Szymon Janc Signed-off-by: Gustavo F. Padovan diff --git a/net/bluetooth/hidp/core.c b/net/bluetooth/hidp/core.c index a1472b7..ae6ebc6 100644 --- a/net/bluetooth/hidp/core.c +++ b/net/bluetooth/hidp/core.c @@ -37,6 +37,7 @@ #include #include #include +#include #include #include @@ -463,8 +464,7 @@ static void hidp_idle_timeout(unsigned long arg) { struct hidp_session *session = (struct hidp_session *) arg; - atomic_inc(&session->terminate); - hidp_schedule(session); + kthread_stop(session->task); } static void hidp_set_timer(struct hidp_session *session) @@ -535,9 +535,7 @@ static void hidp_process_hid_control(struct hidp_session *session, skb_queue_purge(&session->ctrl_transmit); skb_queue_purge(&session->intr_transmit); - /* Kill session thread */ - atomic_inc(&session->terminate); - hidp_schedule(session); + kthread_stop(session->task); } } @@ -696,22 +694,10 @@ static int hidp_session(void *arg) struct sock *ctrl_sk = session->ctrl_sock->sk; struct sock *intr_sk = session->intr_sock->sk; struct sk_buff *skb; - int vendor = 0x0000, product = 0x0000; wait_queue_t ctrl_wait, intr_wait; BT_DBG("session %p", session); - if (session->input) { - vendor = session->input->id.vendor; - product = session->input->id.product; - } - - if (session->hid) { - vendor = session->hid->vendor; - product = session->hid->product; - } - - daemonize("khidpd_%04x%04x", vendor, product); set_user_nice(current, -15); init_waitqueue_entry(&ctrl_wait, current); @@ -720,7 +706,7 @@ static int hidp_session(void *arg) add_wait_queue(sk_sleep(intr_sk), &intr_wait); session->waiting_for_startup = 0; wake_up_interruptible(&session->startup_queue); - while (!atomic_read(&session->terminate)) { + while (!kthread_should_stop()) { set_current_state(TASK_INTERRUPTIBLE); if (ctrl_sk->sk_state != BT_CONNECTED || @@ -968,6 +954,7 @@ fault: int hidp_add_connection(struct hidp_connadd_req *req, struct socket *ctrl_sock, struct socket *intr_sock) { struct hidp_session *session, *s; + int vendor, product; int err; BT_DBG(""); @@ -1029,9 +1016,24 @@ int hidp_add_connection(struct hidp_connadd_req *req, struct socket *ctrl_sock, hidp_set_timer(session); - err = kernel_thread(hidp_session, session, CLONE_KERNEL); - if (err < 0) + if (session->hid) { + vendor = session->hid->vendor; + product = session->hid->product; + } else if (session->input) { + vendor = session->input->id.vendor; + product = session->input->id.product; + } else { + vendor = 0x0000; + product = 0x0000; + } + + session->task = kthread_run(hidp_session, session, "khidpd_%04x%04x", + vendor, product); + if (IS_ERR(session->task)) { + err = PTR_ERR(session->task); goto unlink; + } + while (session->waiting_for_startup) { wait_event_interruptible(session->startup_queue, !session->waiting_for_startup); @@ -1056,8 +1058,7 @@ int hidp_add_connection(struct hidp_connadd_req *req, struct socket *ctrl_sock, err_add_device: hid_destroy_device(session->hid); session->hid = NULL; - atomic_inc(&session->terminate); - hidp_schedule(session); + kthread_stop(session->task); unlink: hidp_del_timer(session); @@ -1108,13 +1109,7 @@ int hidp_del_connection(struct hidp_conndel_req *req) skb_queue_purge(&session->ctrl_transmit); skb_queue_purge(&session->intr_transmit); - /* Wakeup user-space polling for socket errors */ - session->intr_sock->sk->sk_err = EUNATCH; - session->ctrl_sock->sk->sk_err = EUNATCH; - - /* Kill session thread */ - atomic_inc(&session->terminate); - hidp_schedule(session); + kthread_stop(session->task); } } else err = -ENOENT; diff --git a/net/bluetooth/hidp/hidp.h b/net/bluetooth/hidp/hidp.h index b412e71..12822cd 100644 --- a/net/bluetooth/hidp/hidp.h +++ b/net/bluetooth/hidp/hidp.h @@ -142,7 +142,7 @@ struct hidp_session { uint ctrl_mtu; uint intr_mtu; - atomic_t terminate; + struct task_struct *task; unsigned char keys[8]; unsigned char leds; -- cgit v0.10.2 From f4d7cd4a4c25cb4a5c30a675d4cc0052c93b925a Mon Sep 17 00:00:00 2001 From: Szymon Janc Date: Mon, 21 Mar 2011 14:20:00 +0100 Subject: Bluetooth: Use kthread API in bnep kernel_thread() is a low-level implementation detail and EXPORT_SYMBOL(kernel_thread) is scheduled for removal. Use the API instead. Signed-off-by: Szymon Janc Signed-off-by: Gustavo F. Padovan diff --git a/net/bluetooth/bnep/bnep.h b/net/bluetooth/bnep/bnep.h index d768e04..8e6c061 100644 --- a/net/bluetooth/bnep/bnep.h +++ b/net/bluetooth/bnep/bnep.h @@ -155,7 +155,7 @@ struct bnep_session { unsigned int role; unsigned long state; unsigned long flags; - atomic_t killed; + struct task_struct *task; struct ethhdr eh; struct msghdr msg; diff --git a/net/bluetooth/bnep/core.c b/net/bluetooth/bnep/core.c index 0a2e76b..ca39fcf 100644 --- a/net/bluetooth/bnep/core.c +++ b/net/bluetooth/bnep/core.c @@ -36,6 +36,7 @@ #include #include #include +#include #include #include @@ -479,12 +480,11 @@ static int bnep_session(void *arg) BT_DBG(""); - daemonize("kbnepd %s", dev->name); set_user_nice(current, -15); init_waitqueue_entry(&wait, current); add_wait_queue(sk_sleep(sk), &wait); - while (!atomic_read(&s->killed)) { + while (!kthread_should_stop()) { set_current_state(TASK_INTERRUPTIBLE); /* RX */ @@ -611,11 +611,12 @@ int bnep_add_connection(struct bnep_connadd_req *req, struct socket *sock) __bnep_link_session(s); - err = kernel_thread(bnep_session, s, CLONE_KERNEL); - if (err < 0) { + s->task = kthread_run(bnep_session, s, "kbnepd %s", dev->name); + if (IS_ERR(s->task)) { /* Session thread start failed, gotta cleanup. */ unregister_netdev(dev); __bnep_unlink_session(s); + err = PTR_ERR(s->task); goto failed; } @@ -639,15 +640,9 @@ int bnep_del_connection(struct bnep_conndel_req *req) down_read(&bnep_session_sem); s = __bnep_get_session(req->dst); - if (s) { - /* Wakeup user-space which is polling for socket errors. - * This is temporary hack until we have shutdown in L2CAP */ - s->sock->sk->sk_err = EUNATCH; - - /* Kill session thread */ - atomic_inc(&s->killed); - wake_up_interruptible(sk_sleep(s->sock->sk)); - } else + if (s) + kthread_stop(s->task); + else err = -ENOENT; up_read(&bnep_session_sem); -- cgit v0.10.2 From fada4ac33992b1f953d95584e36f6ca7860aea40 Mon Sep 17 00:00:00 2001 From: Szymon Janc Date: Mon, 21 Mar 2011 14:20:06 +0100 Subject: Bluetooth: Use kthread API in cmtp kernel_thread() is a low-level implementation detail and EXPORT_SYMBOL(kernel_thread) is scheduled for removal. Use the API instead. Signed-off-by: Szymon Janc Signed-off-by: Gustavo F. Padovan diff --git a/net/bluetooth/cmtp/capi.c b/net/bluetooth/cmtp/capi.c index 67cff810..744233c 100644 --- a/net/bluetooth/cmtp/capi.c +++ b/net/bluetooth/cmtp/capi.c @@ -35,6 +35,7 @@ #include #include #include +#include #include #include @@ -143,7 +144,7 @@ static void cmtp_send_capimsg(struct cmtp_session *session, struct sk_buff *skb) skb_queue_tail(&session->transmit, skb); - cmtp_schedule(session); + wake_up_interruptible(sk_sleep(session->sock->sk)); } static void cmtp_send_interopmsg(struct cmtp_session *session, @@ -386,8 +387,7 @@ static void cmtp_reset_ctr(struct capi_ctr *ctrl) capi_ctr_down(ctrl); - atomic_inc(&session->terminate); - cmtp_schedule(session); + kthread_stop(session->task); } static void cmtp_register_appl(struct capi_ctr *ctrl, __u16 appl, capi_register_params *rp) diff --git a/net/bluetooth/cmtp/cmtp.h b/net/bluetooth/cmtp/cmtp.h index c6f78f8..db43b54 100644 --- a/net/bluetooth/cmtp/cmtp.h +++ b/net/bluetooth/cmtp/cmtp.h @@ -81,7 +81,7 @@ struct cmtp_session { char name[BTNAMSIZ]; - atomic_t terminate; + struct task_struct *task; wait_queue_head_t wait; @@ -121,13 +121,6 @@ void cmtp_detach_device(struct cmtp_session *session); void cmtp_recv_capimsg(struct cmtp_session *session, struct sk_buff *skb); -static inline void cmtp_schedule(struct cmtp_session *session) -{ - struct sock *sk = session->sock->sk; - - wake_up_interruptible(sk_sleep(sk)); -} - /* CMTP init defines */ int cmtp_init_sockets(void); void cmtp_cleanup_sockets(void); diff --git a/net/bluetooth/cmtp/core.c b/net/bluetooth/cmtp/core.c index 16aa6bd..cce99b0 100644 --- a/net/bluetooth/cmtp/core.c +++ b/net/bluetooth/cmtp/core.c @@ -35,6 +35,7 @@ #include #include #include +#include #include #include @@ -287,12 +288,11 @@ static int cmtp_session(void *arg) BT_DBG("session %p", session); - daemonize("kcmtpd_ctr_%d", session->num); set_user_nice(current, -15); init_waitqueue_entry(&wait, current); add_wait_queue(sk_sleep(sk), &wait); - while (!atomic_read(&session->terminate)) { + while (!kthread_should_stop()) { set_current_state(TASK_INTERRUPTIBLE); if (sk->sk_state != BT_CONNECTED) @@ -370,9 +370,12 @@ int cmtp_add_connection(struct cmtp_connadd_req *req, struct socket *sock) __cmtp_link_session(session); - err = kernel_thread(cmtp_session, session, CLONE_KERNEL); - if (err < 0) + session->task = kthread_run(cmtp_session, session, "kcmtpd_ctr_%d", + session->num); + if (IS_ERR(session->task)) { + err = PTR_ERR(session->task); goto unlink; + } if (!(session->flags & (1 << CMTP_LOOPBACK))) { err = cmtp_attach_device(session); @@ -409,9 +412,8 @@ int cmtp_del_connection(struct cmtp_conndel_req *req) /* Flush the transmit queue */ skb_queue_purge(&session->transmit); - /* Kill session thread */ - atomic_inc(&session->terminate); - cmtp_schedule(session); + /* Stop session thread */ + kthread_stop(session->task); } else err = -ENOENT; -- cgit v0.10.2 From 1322901da5094cecd9826ec3aaade83f6452cc45 Mon Sep 17 00:00:00 2001 From: "Gustavo F. Padovan" Date: Mon, 4 Apr 2011 19:06:05 -0300 Subject: Bluetooth: Don't use spin_lock_bh in user context spin_lock() and spin_unlock() are more apropiated for user context. Signed-off-by: Gustavo F. Padovan diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 9a61320..c322381 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -179,7 +179,7 @@ static int read_controller_info(struct sock *sk, u16 index) hci_del_off_timer(hdev); - hci_dev_lock_bh(hdev); + hci_dev_lock(hdev); set_bit(HCI_MGMT, &hdev->flags); @@ -208,7 +208,7 @@ static int read_controller_info(struct sock *sk, u16 index) memcpy(rp.name, hdev->dev_name, sizeof(hdev->dev_name)); - hci_dev_unlock_bh(hdev); + hci_dev_unlock(hdev); hci_dev_put(hdev); return cmd_complete(sk, index, MGMT_OP_READ_INFO, &rp, sizeof(rp)); @@ -316,7 +316,7 @@ static int set_powered(struct sock *sk, u16 index, unsigned char *data, u16 len) if (!hdev) return cmd_status(sk, index, MGMT_OP_SET_POWERED, ENODEV); - hci_dev_lock_bh(hdev); + hci_dev_lock(hdev); up = test_bit(HCI_UP, &hdev->flags); if ((cp->val && up) || (!cp->val && !up)) { @@ -343,7 +343,7 @@ static int set_powered(struct sock *sk, u16 index, unsigned char *data, u16 len) err = 0; failed: - hci_dev_unlock_bh(hdev); + hci_dev_unlock(hdev); hci_dev_put(hdev); return err; } @@ -368,7 +368,7 @@ static int set_discoverable(struct sock *sk, u16 index, unsigned char *data, if (!hdev) return cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE, ENODEV); - hci_dev_lock_bh(hdev); + hci_dev_lock(hdev); if (!test_bit(HCI_UP, &hdev->flags)) { err = cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE, ENETDOWN); @@ -403,7 +403,7 @@ static int set_discoverable(struct sock *sk, u16 index, unsigned char *data, mgmt_pending_remove(cmd); failed: - hci_dev_unlock_bh(hdev); + hci_dev_unlock(hdev); hci_dev_put(hdev); return err; @@ -429,7 +429,7 @@ static int set_connectable(struct sock *sk, u16 index, unsigned char *data, if (!hdev) return cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE, ENODEV); - hci_dev_lock_bh(hdev); + hci_dev_lock(hdev); if (!test_bit(HCI_UP, &hdev->flags)) { err = cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE, ENETDOWN); @@ -463,7 +463,7 @@ static int set_connectable(struct sock *sk, u16 index, unsigned char *data, mgmt_pending_remove(cmd); failed: - hci_dev_unlock_bh(hdev); + hci_dev_unlock(hdev); hci_dev_put(hdev); return err; @@ -522,7 +522,7 @@ static int set_pairable(struct sock *sk, u16 index, unsigned char *data, if (!hdev) return cmd_status(sk, index, MGMT_OP_SET_PAIRABLE, ENODEV); - hci_dev_lock_bh(hdev); + hci_dev_lock(hdev); if (cp->val) set_bit(HCI_PAIRABLE, &hdev->flags); @@ -538,7 +538,7 @@ static int set_pairable(struct sock *sk, u16 index, unsigned char *data, err = mgmt_event(MGMT_EV_PAIRABLE, index, &ev, sizeof(ev), sk); failed: - hci_dev_unlock_bh(hdev); + hci_dev_unlock(hdev); hci_dev_put(hdev); return err; @@ -739,7 +739,7 @@ static int add_uuid(struct sock *sk, u16 index, unsigned char *data, u16 len) if (!hdev) return cmd_status(sk, index, MGMT_OP_ADD_UUID, ENODEV); - hci_dev_lock_bh(hdev); + hci_dev_lock(hdev); uuid = kmalloc(sizeof(*uuid), GFP_ATOMIC); if (!uuid) { @@ -763,7 +763,7 @@ static int add_uuid(struct sock *sk, u16 index, unsigned char *data, u16 len) err = cmd_complete(sk, index, MGMT_OP_ADD_UUID, NULL, 0); failed: - hci_dev_unlock_bh(hdev); + hci_dev_unlock(hdev); hci_dev_put(hdev); return err; @@ -788,7 +788,7 @@ static int remove_uuid(struct sock *sk, u16 index, unsigned char *data, u16 len) if (!hdev) return cmd_status(sk, index, MGMT_OP_REMOVE_UUID, ENODEV); - hci_dev_lock_bh(hdev); + hci_dev_lock(hdev); if (memcmp(cp->uuid, bt_uuid_any, 16) == 0) { err = hci_uuids_clear(hdev); @@ -823,7 +823,7 @@ static int remove_uuid(struct sock *sk, u16 index, unsigned char *data, u16 len) err = cmd_complete(sk, index, MGMT_OP_REMOVE_UUID, NULL, 0); unlock: - hci_dev_unlock_bh(hdev); + hci_dev_unlock(hdev); hci_dev_put(hdev); return err; @@ -847,7 +847,7 @@ static int set_dev_class(struct sock *sk, u16 index, unsigned char *data, if (!hdev) return cmd_status(sk, index, MGMT_OP_SET_DEV_CLASS, ENODEV); - hci_dev_lock_bh(hdev); + hci_dev_lock(hdev); hdev->major_class = cp->major; hdev->minor_class = cp->minor; @@ -857,7 +857,7 @@ static int set_dev_class(struct sock *sk, u16 index, unsigned char *data, if (err == 0) err = cmd_complete(sk, index, MGMT_OP_SET_DEV_CLASS, NULL, 0); - hci_dev_unlock_bh(hdev); + hci_dev_unlock(hdev); hci_dev_put(hdev); return err; @@ -879,7 +879,7 @@ static int set_service_cache(struct sock *sk, u16 index, unsigned char *data, if (!hdev) return cmd_status(sk, index, MGMT_OP_SET_SERVICE_CACHE, ENODEV); - hci_dev_lock_bh(hdev); + hci_dev_lock(hdev); BT_DBG("hci%u enable %d", index, cp->enable); @@ -897,7 +897,7 @@ static int set_service_cache(struct sock *sk, u16 index, unsigned char *data, err = cmd_complete(sk, index, MGMT_OP_SET_SERVICE_CACHE, NULL, 0); - hci_dev_unlock_bh(hdev); + hci_dev_unlock(hdev); hci_dev_put(hdev); return err; @@ -931,7 +931,7 @@ static int load_keys(struct sock *sk, u16 index, unsigned char *data, u16 len) BT_DBG("hci%u debug_keys %u key_count %u", index, cp->debug_keys, key_count); - hci_dev_lock_bh(hdev); + hci_dev_lock(hdev); hci_link_keys_clear(hdev); @@ -949,7 +949,7 @@ static int load_keys(struct sock *sk, u16 index, unsigned char *data, u16 len) key->pin_len); } - hci_dev_unlock_bh(hdev); + hci_dev_unlock(hdev); hci_dev_put(hdev); return 0; @@ -971,7 +971,7 @@ static int remove_key(struct sock *sk, u16 index, unsigned char *data, u16 len) if (!hdev) return cmd_status(sk, index, MGMT_OP_REMOVE_KEY, ENODEV); - hci_dev_lock_bh(hdev); + hci_dev_lock(hdev); err = hci_remove_link_key(hdev, &cp->bdaddr); if (err < 0) { @@ -994,7 +994,7 @@ static int remove_key(struct sock *sk, u16 index, unsigned char *data, u16 len) } unlock: - hci_dev_unlock_bh(hdev); + hci_dev_unlock(hdev); hci_dev_put(hdev); return err; @@ -1020,7 +1020,7 @@ static int disconnect(struct sock *sk, u16 index, unsigned char *data, u16 len) if (!hdev) return cmd_status(sk, index, MGMT_OP_DISCONNECT, ENODEV); - hci_dev_lock_bh(hdev); + hci_dev_lock(hdev); if (!test_bit(HCI_UP, &hdev->flags)) { err = cmd_status(sk, index, MGMT_OP_DISCONNECT, ENETDOWN); @@ -1052,7 +1052,7 @@ static int disconnect(struct sock *sk, u16 index, unsigned char *data, u16 len) mgmt_pending_remove(cmd); failed: - hci_dev_unlock_bh(hdev); + hci_dev_unlock(hdev); hci_dev_put(hdev); return err; @@ -1073,7 +1073,7 @@ static int get_connections(struct sock *sk, u16 index) if (!hdev) return cmd_status(sk, index, MGMT_OP_GET_CONNECTIONS, ENODEV); - hci_dev_lock_bh(hdev); + hci_dev_lock(hdev); count = 0; list_for_each(p, &hdev->conn_hash.list) { @@ -1104,7 +1104,7 @@ static int get_connections(struct sock *sk, u16 index) unlock: kfree(rp); - hci_dev_unlock_bh(hdev); + hci_dev_unlock(hdev); hci_dev_put(hdev); return err; } @@ -1129,7 +1129,7 @@ static int pin_code_reply(struct sock *sk, u16 index, unsigned char *data, if (!hdev) return cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY, ENODEV); - hci_dev_lock_bh(hdev); + hci_dev_lock(hdev); if (!test_bit(HCI_UP, &hdev->flags)) { err = cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY, ENETDOWN); @@ -1151,7 +1151,7 @@ static int pin_code_reply(struct sock *sk, u16 index, unsigned char *data, mgmt_pending_remove(cmd); failed: - hci_dev_unlock_bh(hdev); + hci_dev_unlock(hdev); hci_dev_put(hdev); return err; @@ -1178,7 +1178,7 @@ static int pin_code_neg_reply(struct sock *sk, u16 index, unsigned char *data, return cmd_status(sk, index, MGMT_OP_PIN_CODE_NEG_REPLY, ENODEV); - hci_dev_lock_bh(hdev); + hci_dev_lock(hdev); if (!test_bit(HCI_UP, &hdev->flags)) { err = cmd_status(sk, index, MGMT_OP_PIN_CODE_NEG_REPLY, @@ -1199,7 +1199,7 @@ static int pin_code_neg_reply(struct sock *sk, u16 index, unsigned char *data, mgmt_pending_remove(cmd); failed: - hci_dev_unlock_bh(hdev); + hci_dev_unlock(hdev); hci_dev_put(hdev); return err; @@ -1222,14 +1222,14 @@ static int set_io_capability(struct sock *sk, u16 index, unsigned char *data, if (!hdev) return cmd_status(sk, index, MGMT_OP_SET_IO_CAPABILITY, ENODEV); - hci_dev_lock_bh(hdev); + hci_dev_lock(hdev); hdev->io_capability = cp->io_capability; BT_DBG("%s IO capability set to 0x%02x", hdev->name, hdev->io_capability); - hci_dev_unlock_bh(hdev); + hci_dev_unlock(hdev); hci_dev_put(hdev); return cmd_complete(sk, index, MGMT_OP_SET_IO_CAPABILITY, NULL, 0); @@ -1315,7 +1315,7 @@ static int pair_device(struct sock *sk, u16 index, unsigned char *data, u16 len) if (!hdev) return cmd_status(sk, index, MGMT_OP_PAIR_DEVICE, ENODEV); - hci_dev_lock_bh(hdev); + hci_dev_lock(hdev); if (cp->io_cap == 0x03) { sec_level = BT_SECURITY_MEDIUM; @@ -1357,7 +1357,7 @@ static int pair_device(struct sock *sk, u16 index, unsigned char *data, u16 len) err = 0; unlock: - hci_dev_unlock_bh(hdev); + hci_dev_unlock(hdev); hci_dev_put(hdev); return err; @@ -1389,7 +1389,7 @@ static int user_confirm_reply(struct sock *sk, u16 index, unsigned char *data, if (!hdev) return cmd_status(sk, index, mgmt_op, ENODEV); - hci_dev_lock_bh(hdev); + hci_dev_lock(hdev); if (!test_bit(HCI_UP, &hdev->flags)) { err = cmd_status(sk, index, mgmt_op, ENETDOWN); @@ -1407,7 +1407,7 @@ static int user_confirm_reply(struct sock *sk, u16 index, unsigned char *data, mgmt_pending_remove(cmd); failed: - hci_dev_unlock_bh(hdev); + hci_dev_unlock(hdev); hci_dev_put(hdev); return err; @@ -1431,7 +1431,7 @@ static int set_local_name(struct sock *sk, u16 index, unsigned char *data, if (!hdev) return cmd_status(sk, index, MGMT_OP_SET_LOCAL_NAME, ENODEV); - hci_dev_lock_bh(hdev); + hci_dev_lock(hdev); cmd = mgmt_pending_add(sk, MGMT_OP_SET_LOCAL_NAME, index, data, len); if (!cmd) { @@ -1446,7 +1446,7 @@ static int set_local_name(struct sock *sk, u16 index, unsigned char *data, mgmt_pending_remove(cmd); failed: - hci_dev_unlock_bh(hdev); + hci_dev_unlock(hdev); hci_dev_put(hdev); return err; @@ -1465,7 +1465,7 @@ static int read_local_oob_data(struct sock *sk, u16 index) return cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA, ENODEV); - hci_dev_lock_bh(hdev); + hci_dev_lock(hdev); if (!test_bit(HCI_UP, &hdev->flags)) { err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA, @@ -1495,7 +1495,7 @@ static int read_local_oob_data(struct sock *sk, u16 index) mgmt_pending_remove(cmd); unlock: - hci_dev_unlock_bh(hdev); + hci_dev_unlock(hdev); hci_dev_put(hdev); return err; @@ -1519,7 +1519,7 @@ static int add_remote_oob_data(struct sock *sk, u16 index, unsigned char *data, return cmd_status(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA, ENODEV); - hci_dev_lock_bh(hdev); + hci_dev_lock(hdev); err = hci_add_remote_oob_data(hdev, &cp->bdaddr, cp->hash, cp->randomizer); @@ -1529,7 +1529,7 @@ static int add_remote_oob_data(struct sock *sk, u16 index, unsigned char *data, err = cmd_complete(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA, NULL, 0); - hci_dev_unlock_bh(hdev); + hci_dev_unlock(hdev); hci_dev_put(hdev); return err; @@ -1553,7 +1553,7 @@ static int remove_remote_oob_data(struct sock *sk, u16 index, return cmd_status(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA, ENODEV); - hci_dev_lock_bh(hdev); + hci_dev_lock(hdev); err = hci_remove_remote_oob_data(hdev, &cp->bdaddr); if (err < 0) @@ -1563,7 +1563,7 @@ static int remove_remote_oob_data(struct sock *sk, u16 index, err = cmd_complete(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA, NULL, 0); - hci_dev_unlock_bh(hdev); + hci_dev_unlock(hdev); hci_dev_put(hdev); return err; -- cgit v0.10.2 From e63a15ec0f25c0f97e8f6247b97ac9b30968b6b3 Mon Sep 17 00:00:00 2001 From: "Gustavo F. Padovan" Date: Mon, 4 Apr 2011 18:56:53 -0300 Subject: Bluetooth: Use GFP_KERNEL in user context The allocation in mgmt_control() code are in user context and not locked by any spinlock, so it's not recommended the use of GFP_ATOMIC there. Signed-off-by: Gustavo F. Padovan diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index c322381..c304688 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -1581,7 +1581,7 @@ int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen) if (msglen < sizeof(*hdr)) return -EINVAL; - buf = kmalloc(msglen, GFP_ATOMIC); + buf = kmalloc(msglen, GFP_KERNEL); if (!buf) return -ENOMEM; -- cgit v0.10.2 From db940cb0db7c69a217661ecd49e1e6b0d680a6cc Mon Sep 17 00:00:00 2001 From: Alexey Dobriyan Date: Sat, 2 Apr 2011 14:19:41 +0300 Subject: Bluetooth: convert net/bluetooth/ to kstrtox Convert from strict_strto*() interfaces to kstrto*() interfaces. Signed-off-by: Alexey Dobriyan Signed-off-by: Gustavo F. Padovan diff --git a/net/bluetooth/hci_sysfs.c b/net/bluetooth/hci_sysfs.c index e544216..8775933 100644 --- a/net/bluetooth/hci_sysfs.c +++ b/net/bluetooth/hci_sysfs.c @@ -277,10 +277,12 @@ static ssize_t show_idle_timeout(struct device *dev, struct device_attribute *at static ssize_t store_idle_timeout(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct hci_dev *hdev = dev_get_drvdata(dev); - unsigned long val; + unsigned int val; + int rv; - if (strict_strtoul(buf, 0, &val) < 0) - return -EINVAL; + rv = kstrtouint(buf, 0, &val); + if (rv < 0) + return rv; if (val != 0 && (val < 500 || val > 3600000)) return -EINVAL; @@ -299,15 +301,14 @@ static ssize_t show_sniff_max_interval(struct device *dev, struct device_attribu static ssize_t store_sniff_max_interval(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct hci_dev *hdev = dev_get_drvdata(dev); - unsigned long val; - - if (strict_strtoul(buf, 0, &val) < 0) - return -EINVAL; + u16 val; + int rv; - if (val < 0x0002 || val > 0xFFFE || val % 2) - return -EINVAL; + rv = kstrtou16(buf, 0, &val); + if (rv < 0) + return rv; - if (val < hdev->sniff_min_interval) + if (val == 0 || val % 2 || val < hdev->sniff_min_interval) return -EINVAL; hdev->sniff_max_interval = val; @@ -324,15 +325,14 @@ static ssize_t show_sniff_min_interval(struct device *dev, struct device_attribu static ssize_t store_sniff_min_interval(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct hci_dev *hdev = dev_get_drvdata(dev); - unsigned long val; + u16 val; + int rv; - if (strict_strtoul(buf, 0, &val) < 0) - return -EINVAL; - - if (val < 0x0002 || val > 0xFFFE || val % 2) - return -EINVAL; + rv = kstrtou16(buf, 0, &val); + if (rv < 0) + return rv; - if (val > hdev->sniff_max_interval) + if (val == 0 || val % 2 || val > hdev->sniff_max_interval) return -EINVAL; hdev->sniff_min_interval = val; -- cgit v0.10.2 From 660e34cebf0a11d54f2d5dd8838607452355f321 Mon Sep 17 00:00:00 2001 From: Matthew Garrett Date: Mon, 4 Apr 2011 13:55:05 -0400 Subject: x86: Reorder reboot method preferences We have a never ending stream of 'reboot quirks' for new boxes that will not reboot properly under Linux (they will hang on reboot). The reason is widespread 'Windows compatible' assumption of modern x86 hardware, which expects the following reboot sequence: - hitting the ACPI reboot vector (if available) - trying the keyboard controller - hitting the ACPI reboot vector again - then giving the keyboard controller one last go This sequence expectation gets more and more embedded in modern hardware, which often lacks a keyboard controller and may even lock up if the legacy io ports are hit - and which hardware is often not tested with Linux during development. The end result is that reboot works under Windows-alike OSs but not under Linux. Rework our reboot process to meet this hardware externality a little better and match this assumption of newer x86 hardware. In addition to the ACPI,kbd,ACPI,kbd sequence we'll still fall through to attempting a legacy triple fault if nothing else works - and keep trying that and the kbd reset. Signed-off-by: Matthew Garrett [ this commit will also save special casing Oaktrail boards ] Acked-by: Alan Cox Cc: Linus Torvalds Cc: Andrew Morton Cc: Leann Ogasawara Cc: Dave Jones Cc: Len Brown LKML-Reference: <1301939705-2404-1-git-send-email-mjg@redhat.com> Signed-off-by: Ingo Molnar diff --git a/arch/x86/kernel/reboot.c b/arch/x86/kernel/reboot.c index 08c44b0..0c016f7 100644 --- a/arch/x86/kernel/reboot.c +++ b/arch/x86/kernel/reboot.c @@ -36,7 +36,7 @@ EXPORT_SYMBOL(pm_power_off); static const struct desc_ptr no_idt = {}; static int reboot_mode; -enum reboot_type reboot_type = BOOT_KBD; +enum reboot_type reboot_type = BOOT_ACPI; int reboot_force; #if defined(CONFIG_X86_32) && defined(CONFIG_SMP) @@ -478,9 +478,24 @@ void __attribute__((weak)) mach_reboot_fixups(void) { } +/* + * Windows compatible x86 hardware expects the following on reboot: + * + * 1) If the FADT has the ACPI reboot register flag set, try it + * 2) If still alive, write to the keyboard controller + * 3) If still alive, write to the ACPI reboot register again + * 4) If still alive, write to the keyboard controller again + * + * If the machine is still alive at this stage, it gives up. We default to + * following the same pattern, except that if we're still alive after (4) we'll + * try to force a triple fault and then cycle between hitting the keyboard + * controller and doing that + */ static void native_machine_emergency_restart(void) { int i; + int attempt = 0; + int orig_reboot_type = reboot_type; if (reboot_emergency) emergency_vmx_disable_all(); @@ -502,6 +517,13 @@ static void native_machine_emergency_restart(void) outb(0xfe, 0x64); /* pulse reset low */ udelay(50); } + if (attempt == 0 && orig_reboot_type == BOOT_ACPI) { + attempt = 1; + reboot_type = BOOT_ACPI; + } else { + reboot_type = BOOT_TRIPLE; + } + break; case BOOT_TRIPLE: load_idt(&no_idt); -- cgit v0.10.2 From ded467374a34eb80020c2213456b1d9ca946b88c Mon Sep 17 00:00:00 2001 From: Joerg Roedel Date: Wed, 6 Apr 2011 10:53:48 +0200 Subject: x86/amd-iommu: Move compl-wait command building to own function This patch introduces a seperate function for building completion-wait commands. Signed-off-by: Joerg Roedel diff --git a/arch/x86/kernel/amd_iommu.c b/arch/x86/kernel/amd_iommu.c index 57ca777..eebd504 100644 --- a/arch/x86/kernel/amd_iommu.c +++ b/arch/x86/kernel/amd_iommu.c @@ -383,6 +383,13 @@ irqreturn_t amd_iommu_int_handler(int irq, void *data) * ****************************************************************************/ +static void build_completion_wait(struct iommu_cmd *cmd) +{ + memset(cmd, 0, sizeof(*cmd)); + cmd->data[0] = CMD_COMPL_WAIT_INT_MASK; + CMD_SET_TYPE(cmd, CMD_COMPL_WAIT); +} + /* * Writes the command to the IOMMUs command buffer and informs the * hardware about the new command. Must be called with iommu->lock held. @@ -458,9 +465,7 @@ static int __iommu_completion_wait(struct amd_iommu *iommu) { struct iommu_cmd cmd; - memset(&cmd, 0, sizeof(cmd)); - cmd.data[0] = CMD_COMPL_WAIT_INT_MASK; - CMD_SET_TYPE(&cmd, CMD_COMPL_WAIT); + build_completion_wait(&cmd); return __iommu_queue_command(iommu, &cmd); } -- cgit v0.10.2 From 94fe79e2f100bfcd8e7689cbf8838634779b80a2 Mon Sep 17 00:00:00 2001 From: Joerg Roedel Date: Wed, 6 Apr 2011 11:07:21 +0200 Subject: x86/amd-iommu: Move inv-dte command building to own function This patch moves command building for the invalidate-dte command into its own function. Signed-off-by: Joerg Roedel diff --git a/arch/x86/kernel/amd_iommu.c b/arch/x86/kernel/amd_iommu.c index eebd504..4e5631a 100644 --- a/arch/x86/kernel/amd_iommu.c +++ b/arch/x86/kernel/amd_iommu.c @@ -390,6 +390,13 @@ static void build_completion_wait(struct iommu_cmd *cmd) CMD_SET_TYPE(cmd, CMD_COMPL_WAIT); } +static void build_inv_dte(struct iommu_cmd *cmd, u16 devid) +{ + memset(cmd, 0, sizeof(*cmd)); + cmd->data[0] = devid; + CMD_SET_TYPE(cmd, CMD_INV_DEV_ENTRY); +} + /* * Writes the command to the IOMMUs command buffer and informs the * hardware about the new command. Must be called with iommu->lock held. @@ -533,10 +540,7 @@ static int iommu_flush_device(struct device *dev) devid = get_device_id(dev); iommu = amd_iommu_rlookup_table[devid]; - /* Build command */ - memset(&cmd, 0, sizeof(cmd)); - CMD_SET_TYPE(&cmd, CMD_INV_DEV_ENTRY); - cmd.data[0] = devid; + build_inv_dte(&cmd, devid); return iommu_queue_command(iommu, &cmd); } -- cgit v0.10.2 From 11b6402c6673b530fac9920c5640c75e99fee956 Mon Sep 17 00:00:00 2001 From: Joerg Roedel Date: Wed, 6 Apr 2011 11:49:28 +0200 Subject: x86/amd-iommu: Cleanup inv_pages command handling This patch reworks the processing of invalidate-pages commands to the IOMMU. The function building the the command is extended so we can get rid of another function. It was also renamed to match with the other function names. Signed-off-by: Joerg Roedel diff --git a/arch/x86/kernel/amd_iommu.c b/arch/x86/kernel/amd_iommu.c index 4e5631a..f8ec28e 100644 --- a/arch/x86/kernel/amd_iommu.c +++ b/arch/x86/kernel/amd_iommu.c @@ -397,6 +397,37 @@ static void build_inv_dte(struct iommu_cmd *cmd, u16 devid) CMD_SET_TYPE(cmd, CMD_INV_DEV_ENTRY); } +static void build_inv_iommu_pages(struct iommu_cmd *cmd, u64 address, + size_t size, u16 domid, int pde) +{ + u64 pages; + int s; + + pages = iommu_num_pages(address, size, PAGE_SIZE); + s = 0; + + if (pages > 1) { + /* + * If we have to flush more than one page, flush all + * TLB entries for this domain + */ + address = CMD_INV_IOMMU_ALL_PAGES_ADDRESS; + s = 1; + } + + address &= PAGE_MASK; + + memset(cmd, 0, sizeof(*cmd)); + cmd->data[1] |= domid; + cmd->data[2] = lower_32_bits(address); + cmd->data[3] = upper_32_bits(address); + CMD_SET_TYPE(cmd, CMD_INV_IOMMU_PAGES); + if (s) /* size bit - we flush more than one 4kb page */ + cmd->data[2] |= CMD_INV_IOMMU_PAGES_SIZE_MASK; + if (pde) /* PDE bit - we wan't flush everything not only the PTEs */ + cmd->data[2] |= CMD_INV_IOMMU_PAGES_PDE_MASK; +} + /* * Writes the command to the IOMMUs command buffer and informs the * hardware about the new command. Must be called with iommu->lock held. @@ -545,37 +576,6 @@ static int iommu_flush_device(struct device *dev) return iommu_queue_command(iommu, &cmd); } -static void __iommu_build_inv_iommu_pages(struct iommu_cmd *cmd, u64 address, - u16 domid, int pde, int s) -{ - memset(cmd, 0, sizeof(*cmd)); - address &= PAGE_MASK; - CMD_SET_TYPE(cmd, CMD_INV_IOMMU_PAGES); - cmd->data[1] |= domid; - cmd->data[2] = lower_32_bits(address); - cmd->data[3] = upper_32_bits(address); - if (s) /* size bit - we flush more than one 4kb page */ - cmd->data[2] |= CMD_INV_IOMMU_PAGES_SIZE_MASK; - if (pde) /* PDE bit - we wan't flush everything not only the PTEs */ - cmd->data[2] |= CMD_INV_IOMMU_PAGES_PDE_MASK; -} - -/* - * Generic command send function for invalidaing TLB entries - */ -static int iommu_queue_inv_iommu_pages(struct amd_iommu *iommu, - u64 address, u16 domid, int pde, int s) -{ - struct iommu_cmd cmd; - int ret; - - __iommu_build_inv_iommu_pages(&cmd, address, domid, pde, s); - - ret = iommu_queue_command(iommu, &cmd); - - return ret; -} - /* * TLB invalidation function which is called from the mapping functions. * It invalidates a single PTE if the range to flush is within a single @@ -584,20 +584,10 @@ static int iommu_queue_inv_iommu_pages(struct amd_iommu *iommu, static void __iommu_flush_pages(struct protection_domain *domain, u64 address, size_t size, int pde) { - int s = 0, i; - unsigned long pages = iommu_num_pages(address, size, PAGE_SIZE); - - address &= PAGE_MASK; - - if (pages > 1) { - /* - * If we have to flush more than one page, flush all - * TLB entries for this domain - */ - address = CMD_INV_IOMMU_ALL_PAGES_ADDRESS; - s = 1; - } + struct iommu_cmd cmd; + int ret = 0, i; + build_inv_iommu_pages(&cmd, address, size, domain->id, pde); for (i = 0; i < amd_iommus_present; ++i) { if (!domain->dev_iommu[i]) @@ -607,11 +597,10 @@ static void __iommu_flush_pages(struct protection_domain *domain, * Devices of this domain are behind this IOMMU * We need a TLB flush */ - iommu_queue_inv_iommu_pages(amd_iommus[i], address, - domain->id, pde, s); + ret |= iommu_queue_command(amd_iommus[i], &cmd); } - return; + WARN_ON(ret); } static void iommu_flush_pages(struct protection_domain *domain, -- cgit v0.10.2 From deb2607e6c3d75c7185bb8aba658d9cd57e6e54a Mon Sep 17 00:00:00 2001 From: Stephen Warren Date: Tue, 5 Apr 2011 19:35:30 -0600 Subject: ASoC: Tegra: Suspend/resume support ASoC machine drivers that are their own platform_driver (as opposed to those using the soc-audio platform_driver) need to explicitly set up power-management operation callbacks. To avoid cut/paste, snd_soc_pm_ops also needs to be exported. Signed-off-by: Stephen Warren Signed-off-by: Mark Brown diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index b76b74d..960718b 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -2060,6 +2060,7 @@ const struct dev_pm_ops snd_soc_pm_ops = { .resume = snd_soc_resume, .poweroff = snd_soc_poweroff, }; +EXPORT_SYMBOL_GPL(snd_soc_pm_ops); /* ASoC platform driver */ static struct platform_driver soc_driver = { diff --git a/sound/soc/tegra/harmony.c b/sound/soc/tegra/harmony.c index 8585957..556a571 100644 --- a/sound/soc/tegra/harmony.c +++ b/sound/soc/tegra/harmony.c @@ -370,6 +370,7 @@ static struct platform_driver tegra_snd_harmony_driver = { .driver = { .name = DRV_NAME, .owner = THIS_MODULE, + .pm = &snd_soc_pm_ops, }, .probe = tegra_snd_harmony_probe, .remove = __devexit_p(tegra_snd_harmony_remove), -- cgit v0.10.2 From de9f52300d03915846c2baab27332ec462f7f6b0 Mon Sep 17 00:00:00 2001 From: Matt Carlson Date: Tue, 5 Apr 2011 14:22:43 +0000 Subject: tg3: Cleanup extended rx ring size code Hardcoded values are used in multiple places to describe the maximum rx ring sizes. This patch replaces those values with preprocessor constants. This patch also introduces a new TG3_FLG3_LRG_PROD_RING_CAP to determine if the device is capable of supporting larger ring sizes. Signed-off-by: Matt Carlson Signed-off-by: David S. Miller diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index b7e03a6..8ffa5af 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -97,14 +97,12 @@ * them in the NIC onboard memory. */ #define TG3_RX_STD_RING_SIZE(tp) \ - ((GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5717 || \ - GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5719) ? \ - RX_STD_MAX_SIZE_5717 : 512) + ((tp->tg3_flags3 & TG3_FLG3_LRG_PROD_RING_CAP) ? \ + TG3_RX_STD_MAX_SIZE_5717 : TG3_RX_STD_MAX_SIZE_5700) #define TG3_DEF_RX_RING_PENDING 200 #define TG3_RX_JMB_RING_SIZE(tp) \ - ((GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5717 || \ - GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5719) ? \ - 1024 : 256) + ((tp->tg3_flags3 & TG3_FLG3_LRG_PROD_RING_CAP) ? \ + TG3_RX_JMB_MAX_SIZE_5717 : TG3_RX_JMB_MAX_SIZE_5700) #define TG3_DEF_RX_JUMBO_RING_PENDING 100 #define TG3_RSS_INDIR_TBL_SIZE 128 @@ -8115,9 +8113,10 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy) ((u64) tpr->rx_jmb_mapping >> 32)); tw32(RCVDBDI_JUMBO_BD + TG3_BDINFO_HOST_ADDR + TG3_64BIT_REG_LOW, ((u64) tpr->rx_jmb_mapping & 0xffffffff)); + val = TG3_RX_JMB_RING_SIZE(tp) << + BDINFO_FLAGS_MAXLEN_SHIFT; tw32(RCVDBDI_JUMBO_BD + TG3_BDINFO_MAXLEN_FLAGS, - (RX_JUMBO_MAX_SIZE << BDINFO_FLAGS_MAXLEN_SHIFT) | - BDINFO_FLAGS_USE_EXT_RECV); + val | BDINFO_FLAGS_USE_EXT_RECV); if (!(tp->tg3_flags3 & TG3_FLG3_USE_JUMBO_BDFLAG) || GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57765) tw32(RCVDBDI_JUMBO_BD + TG3_BDINFO_NIC_ADDR, @@ -8129,15 +8128,15 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy) if (tp->tg3_flags3 & TG3_FLG3_5717_PLUS) { if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57765) - val = RX_STD_MAX_SIZE_5705; + val = TG3_RX_STD_MAX_SIZE_5700; else - val = RX_STD_MAX_SIZE_5717; + val = TG3_RX_STD_MAX_SIZE_5717; val <<= BDINFO_FLAGS_MAXLEN_SHIFT; val |= (TG3_RX_STD_DMA_SZ << 2); } else val = TG3_RX_STD_DMA_SZ << BDINFO_FLAGS_MAXLEN_SHIFT; } else - val = RX_STD_MAX_SIZE_5705 << BDINFO_FLAGS_MAXLEN_SHIFT; + val = TG3_RX_STD_MAX_SIZE_5700 << BDINFO_FLAGS_MAXLEN_SHIFT; tw32(RCVDBDI_STD_BD + TG3_BDINFO_MAXLEN_FLAGS, val); @@ -8421,8 +8420,7 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy) tw32(SNDBDC_MODE, SNDBDC_MODE_ENABLE | SNDBDC_MODE_ATTN_ENABLE); tw32(RCVBDI_MODE, RCVBDI_MODE_ENABLE | RCVBDI_MODE_RCB_ATTN_ENAB); val = RCVDBDI_MODE_ENABLE | RCVDBDI_MODE_INV_RING_SZ; - if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5717 || - GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5719) + if (tp->tg3_flags3 & TG3_FLG3_LRG_PROD_RING_CAP) val |= RCVDBDI_MODE_LRG_RING_SZ; tw32(RCVDBDI_MODE, val); tw32(SNDDATAI_MODE, SNDDATAI_MODE_ENABLE); @@ -13125,14 +13123,13 @@ static inline void vlan_features_add(struct net_device *dev, unsigned long flags static inline u32 tg3_rx_ret_ring_size(struct tg3 *tp) { - if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5717 || - GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5719) - return 4096; + if (tp->tg3_flags3 & TG3_FLG3_LRG_PROD_RING_CAP) + return TG3_RX_RET_MAX_SIZE_5717; else if ((tp->tg3_flags & TG3_FLAG_JUMBO_CAPABLE) && !(tp->tg3_flags2 & TG3_FLG2_5780_CLASS)) - return 1024; + return TG3_RX_RET_MAX_SIZE_5700; else - return 512; + return TG3_RX_RET_MAX_SIZE_5705; } static DEFINE_PCI_DEVICE_TABLE(tg3_write_reorder_chipsets) = { @@ -13430,6 +13427,10 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) tp->tg3_flags3 |= TG3_FLG3_40BIT_DMA_LIMIT_BUG; } + if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5717 || + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5719) + tp->tg3_flags3 |= TG3_FLG3_LRG_PROD_RING_CAP; + if ((tp->tg3_flags3 & TG3_FLG3_5717_PLUS) && GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5719) tp->tg3_flags3 |= TG3_FLG3_USE_JUMBO_BDFLAG; diff --git a/drivers/net/tg3.h b/drivers/net/tg3.h index 73884b6..4c498ed 100644 --- a/drivers/net/tg3.h +++ b/drivers/net/tg3.h @@ -25,9 +25,13 @@ #define TG3_RX_INTERNAL_RING_SZ_5906 32 -#define RX_STD_MAX_SIZE_5705 512 -#define RX_STD_MAX_SIZE_5717 2048 -#define RX_JUMBO_MAX_SIZE 0xdeadbeef /* XXX */ +#define TG3_RX_STD_MAX_SIZE_5700 512 +#define TG3_RX_STD_MAX_SIZE_5717 2048 +#define TG3_RX_JMB_MAX_SIZE_5700 256 +#define TG3_RX_JMB_MAX_SIZE_5717 1024 +#define TG3_RX_RET_MAX_SIZE_5700 1024 +#define TG3_RX_RET_MAX_SIZE_5705 512 +#define TG3_RX_RET_MAX_SIZE_5717 4096 /* First 256 bytes are a mirror of PCI config space. */ #define TG3PCI_VENDOR 0x00000000 @@ -2897,6 +2901,7 @@ struct tg3 { #define TG3_FLG3_5701_DMA_BUG 0x00000008 #define TG3_FLG3_USE_PHYLIB 0x00000010 #define TG3_FLG3_MDIOBUS_INITED 0x00000020 +#define TG3_FLG3_LRG_PROD_RING_CAP 0x00000080 #define TG3_FLG3_RGMII_INBAND_DISABLE 0x00000100 #define TG3_FLG3_RGMII_EXT_IBND_RX_EN 0x00000200 #define TG3_FLG3_RGMII_EXT_IBND_TX_EN 0x00000400 -- cgit v0.10.2 From 1407deb1a99f7ec7ed5b09798b02abea5aa44128 Mon Sep 17 00:00:00 2001 From: Matt Carlson Date: Tue, 5 Apr 2011 14:22:44 +0000 Subject: tg3: 5717_PLUS => 57765_PLUS The 57765 arrived before the 5717 and has a subset of the features supported by the 5717. This patch renames the 5717_PLUS flag so that it can be reintroduced to designate only 5717 and later devices. Signed-off-by: Matt Carlson Signed-off-by: David S. Miller diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index 8ffa5af..4f8976b 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -7095,7 +7095,7 @@ static int tg3_chip_reset(struct tg3 *tp) if (tp->tg3_flags2 & TG3_FLG2_PCI_EXPRESS) { /* Force PCIe 1.0a mode */ if (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5785 && - !(tp->tg3_flags3 & TG3_FLG3_5717_PLUS) && + !(tp->tg3_flags3 & TG3_FLG3_57765_PLUS) && tr32(TG3_PCIE_PHY_TSTCTL) == (TG3_PCIE_PHY_TSTCTL_PCIE10 | TG3_PCIE_PHY_TSTCTL_PSCRAM)) tw32(TG3_PCIE_PHY_TSTCTL, TG3_PCIE_PHY_TSTCTL_PSCRAM); @@ -7248,7 +7248,7 @@ static int tg3_chip_reset(struct tg3 *tp) if ((tp->tg3_flags2 & TG3_FLG2_PCI_EXPRESS) && tp->pci_chip_rev_id != CHIPREV_ID_5750_A0 && GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5785 && - !(tp->tg3_flags3 & TG3_FLG3_5717_PLUS)) { + !(tp->tg3_flags3 & TG3_FLG3_57765_PLUS)) { val = tr32(0x7c00); tw32(0x7c00, val | (1 << 25)); @@ -7958,7 +7958,7 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy) if (err) return err; - if (tp->tg3_flags3 & TG3_FLG3_5717_PLUS) { + if (tp->tg3_flags3 & TG3_FLG3_57765_PLUS) { val = tr32(TG3PCI_DMA_RW_CTRL) & ~DMA_RWCTRL_DIS_CACHE_ALIGNMENT; if (tp->pci_chip_rev_id == CHIPREV_ID_57765_A0) @@ -8126,7 +8126,7 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy) BDINFO_FLAGS_DISABLED); } - if (tp->tg3_flags3 & TG3_FLG3_5717_PLUS) { + if (tp->tg3_flags3 & TG3_FLG3_57765_PLUS) { if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57765) val = TG3_RX_STD_MAX_SIZE_5700; else @@ -8147,7 +8147,7 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy) tp->rx_jumbo_pending : 0; tw32_rx_mbox(TG3_RX_JMB_PROD_IDX_REG, tpr->rx_jmb_prod_idx); - if (tp->tg3_flags3 & TG3_FLG3_5717_PLUS) { + if (tp->tg3_flags3 & TG3_FLG3_57765_PLUS) { tw32(STD_REPLENISH_LWM, 32); tw32(JMB_REPLENISH_LWM, 16); } @@ -8218,7 +8218,7 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy) GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784 || GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5785 || GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57780 || - (tp->tg3_flags3 & TG3_FLG3_5717_PLUS)) { + (tp->tg3_flags3 & TG3_FLG3_57765_PLUS)) { val = tr32(TG3_RDMA_RSRVCTRL_REG); if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5719) { val &= ~(TG3_RDMA_RSRVCTRL_TXMRGN_MASK | @@ -8866,7 +8866,7 @@ static int tg3_test_interrupt(struct tg3 *tp) * Turn off MSI one shot mode. Otherwise this test has no * observable way to know whether the interrupt was delivered. */ - if ((tp->tg3_flags3 & TG3_FLG3_5717_PLUS) && + if ((tp->tg3_flags3 & TG3_FLG3_57765_PLUS) && (tp->tg3_flags2 & TG3_FLG2_USING_MSI)) { val = tr32(MSGINT_MODE) | MSGINT_MODE_ONE_SHOT_DISABLE; tw32(MSGINT_MODE, val); @@ -8909,7 +8909,7 @@ static int tg3_test_interrupt(struct tg3 *tp) if (intr_ok) { /* Reenable MSI one shot mode. */ - if ((tp->tg3_flags3 & TG3_FLG3_5717_PLUS) && + if ((tp->tg3_flags3 & TG3_FLG3_57765_PLUS) && (tp->tg3_flags2 & TG3_FLG2_USING_MSI)) { val = tr32(MSGINT_MODE) & ~MSGINT_MODE_ONE_SHOT_DISABLE; tw32(MSGINT_MODE, val); @@ -9212,7 +9212,7 @@ static int tg3_open(struct net_device *dev) goto err_out2; } - if (!(tp->tg3_flags3 & TG3_FLG3_5717_PLUS) && + if (!(tp->tg3_flags3 & TG3_FLG3_57765_PLUS) && (tp->tg3_flags2 & TG3_FLG2_USING_MSI)) { u32 val = tr32(PCIE_TRANSACTION_CFG); @@ -12470,7 +12470,7 @@ static void __devinit tg3_get_eeprom_hw_cfg(struct tg3 *tp) if (cfg2 & (1 << 18)) tp->phy_flags |= TG3_PHYFLG_SERDES_PREEMPHASIS; - if (((tp->tg3_flags3 & TG3_FLG3_5717_PLUS) || + if (((tp->tg3_flags3 & TG3_FLG3_57765_PLUS) || ((GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784 && GET_CHIP_REV(tp->pci_chip_rev_id) != CHIPREV_5784_AX))) && (cfg2 & NIC_SRAM_DATA_CFG_2_APD_EN)) @@ -12478,7 +12478,7 @@ static void __devinit tg3_get_eeprom_hw_cfg(struct tg3 *tp) if ((tp->tg3_flags2 & TG3_FLG2_PCI_EXPRESS) && GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5785 && - !(tp->tg3_flags3 & TG3_FLG3_5717_PLUS)) { + !(tp->tg3_flags3 & TG3_FLG3_57765_PLUS)) { u32 cfg3; tg3_read_mem(tp, NIC_SRAM_DATA_CFG_3, &cfg3); @@ -13335,7 +13335,7 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5717 || GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5719 || GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57765) - tp->tg3_flags3 |= TG3_FLG3_5717_PLUS; + tp->tg3_flags3 |= TG3_FLG3_57765_PLUS; /* Intentionally exclude ASIC_REV_5906 */ if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5755 || @@ -13344,7 +13344,7 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761 || GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5785 || GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57780 || - (tp->tg3_flags3 & TG3_FLG3_5717_PLUS)) + (tp->tg3_flags3 & TG3_FLG3_57765_PLUS)) tp->tg3_flags3 |= TG3_FLG3_5755_PLUS; if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5750 || @@ -13376,7 +13376,7 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) /* Determine TSO capabilities */ if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5719) ; /* Do nothing. HW bug. */ - else if (tp->tg3_flags3 & TG3_FLG3_5717_PLUS) + else if (tp->tg3_flags3 & TG3_FLG3_57765_PLUS) tp->tg3_flags2 |= TG3_FLG2_HW_TSO_3; else if ((tp->tg3_flags3 & TG3_FLG3_5755_PLUS) || GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906) @@ -13412,7 +13412,7 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) tp->tg3_flags2 |= TG3_FLG2_1SHOT_MSI; } - if (tp->tg3_flags3 & TG3_FLG3_5717_PLUS) { + if (tp->tg3_flags3 & TG3_FLG3_57765_PLUS) { tp->tg3_flags |= TG3_FLAG_SUPPORT_MSIX; tp->irq_max = TG3_IRQ_MAX_VECS; } @@ -13431,7 +13431,7 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5719) tp->tg3_flags3 |= TG3_FLG3_LRG_PROD_RING_CAP; - if ((tp->tg3_flags3 & TG3_FLG3_5717_PLUS) && + if ((tp->tg3_flags3 & TG3_FLG3_57765_PLUS) && GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5719) tp->tg3_flags3 |= TG3_FLG3_USE_JUMBO_BDFLAG; @@ -13637,7 +13637,7 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761 || GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5785 || GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57780 || - (tp->tg3_flags3 & TG3_FLG3_5717_PLUS)) + (tp->tg3_flags3 & TG3_FLG3_57765_PLUS)) tp->tg3_flags |= TG3_FLAG_CPMU_PRESENT; /* Set up tp->grc_local_ctrl before calling tg_power_up(). @@ -13716,7 +13716,7 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) !(tp->phy_flags & TG3_PHYFLG_IS_FET) && GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5785 && GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_57780 && - !(tp->tg3_flags3 & TG3_FLG3_5717_PLUS)) { + !(tp->tg3_flags3 & TG3_FLG3_57765_PLUS)) { if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5755 || GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5787 || GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784 || @@ -14052,7 +14052,7 @@ static u32 __devinit tg3_calc_dma_bndry(struct tg3 *tp, u32 val) #endif #endif - if (tp->tg3_flags3 & TG3_FLG3_5717_PLUS) { + if (tp->tg3_flags3 & TG3_FLG3_57765_PLUS) { val = goal ? 0 : DMA_RWCTRL_DIS_CACHE_ALIGNMENT; goto out; } @@ -14269,7 +14269,7 @@ static int __devinit tg3_test_dma(struct tg3 *tp) tp->dma_rwctrl = tg3_calc_dma_bndry(tp, tp->dma_rwctrl); - if (tp->tg3_flags3 & TG3_FLG3_5717_PLUS) + if (tp->tg3_flags3 & TG3_FLG3_57765_PLUS) goto out; if (tp->tg3_flags2 & TG3_FLG2_PCI_EXPRESS) { @@ -14444,7 +14444,7 @@ out_nofree: static void __devinit tg3_init_bufmgr_config(struct tg3 *tp) { - if (tp->tg3_flags3 & TG3_FLG3_5717_PLUS) { + if (tp->tg3_flags3 & TG3_FLG3_57765_PLUS) { tp->bufmgr_config.mbuf_read_dma_low_water = DEFAULT_MB_RDMA_LOW_WATER_5705; tp->bufmgr_config.mbuf_mac_rx_low_water = diff --git a/drivers/net/tg3.h b/drivers/net/tg3.h index 4c498ed..6f34db5 100644 --- a/drivers/net/tg3.h +++ b/drivers/net/tg3.h @@ -2915,7 +2915,7 @@ struct tg3 { #define TG3_FLG3_SHORT_DMA_BUG 0x00200000 #define TG3_FLG3_USE_JUMBO_BDFLAG 0x00400000 #define TG3_FLG3_L1PLLPD_EN 0x00800000 -#define TG3_FLG3_5717_PLUS 0x01000000 +#define TG3_FLG3_57765_PLUS 0x01000000 #define TG3_FLG3_APE_HAS_NCSI 0x02000000 struct timer_list timer; -- cgit v0.10.2 From 0a58d6689bb7c0d49addbf6992aa97234bcfc96c Mon Sep 17 00:00:00 2001 From: Matt Carlson Date: Tue, 5 Apr 2011 14:22:45 +0000 Subject: tg3: Reintroduce 5717_PLUS This patch reintroduces the TG3_FLG3_5717_PLUS to identify 5717 and later devices. Signed-off-by: Matt Carlson Signed-off-by: David S. Miller diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index 4f8976b..dc6b60b 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -1042,8 +1042,7 @@ static int tg3_mdio_init(struct tg3 *tp) u32 reg; struct phy_device *phydev; - if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5717 || - GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5719) { + if (tp->tg3_flags3 & TG3_FLG3_5717_PLUS) { u32 is_serdes; tp->phy_addr = PCI_FUNC(tp->pdev->devfn) + 1; @@ -1621,8 +1620,7 @@ static void tg3_phy_toggle_apd(struct tg3 *tp, bool enable) u32 reg; if (!(tp->tg3_flags2 & TG3_FLG2_5705_PLUS) || - ((GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5717 || - GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5719) && + ((tp->tg3_flags3 & TG3_FLG3_5717_PLUS) && (tp->phy_flags & TG3_PHYFLG_MII_SERDES))) return; @@ -2045,8 +2043,7 @@ static int tg3_phy_reset(struct tg3 *tp) } } - if ((GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5717 || - GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5719) && + if ((tp->tg3_flags3 & TG3_FLG3_5717_PLUS) && (tp->phy_flags & TG3_PHYFLG_MII_SERDES)) return 0; @@ -7671,8 +7668,7 @@ static void tg3_rings_reset(struct tg3 *tp) /* Disable all transmit rings but the first. */ if (!(tp->tg3_flags2 & TG3_FLG2_5705_PLUS)) limit = NIC_SRAM_SEND_RCB + TG3_BDINFO_SIZE * 16; - else if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5717 || - GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5719) + else if (tp->tg3_flags3 & TG3_FLG3_5717_PLUS) limit = NIC_SRAM_SEND_RCB + TG3_BDINFO_SIZE * 4; else if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57765) limit = NIC_SRAM_SEND_RCB + TG3_BDINFO_SIZE * 2; @@ -7686,8 +7682,7 @@ static void tg3_rings_reset(struct tg3 *tp) /* Disable all receive return rings but the first. */ - if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5717 || - GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5719) + if (tp->tg3_flags3 & TG3_FLG3_5717_PLUS) limit = NIC_SRAM_RCV_RET_RCB + TG3_BDINFO_SIZE * 17; else if (!(tp->tg3_flags2 & TG3_FLG2_5705_PLUS)) limit = NIC_SRAM_RCV_RET_RCB + TG3_BDINFO_SIZE * 16; @@ -8089,8 +8084,7 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy) ((u64) tpr->rx_std_mapping >> 32)); tw32(RCVDBDI_STD_BD + TG3_BDINFO_HOST_ADDR + TG3_64BIT_REG_LOW, ((u64) tpr->rx_std_mapping & 0xffffffff)); - if (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5717 && - GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5719) + if (!(tp->tg3_flags3 & TG3_FLG3_5717_PLUS)) tw32(RCVDBDI_STD_BD + TG3_BDINFO_NIC_ADDR, NIC_SRAM_RX_BUFFER_DESC); @@ -10848,8 +10842,7 @@ static int tg3_test_memory(struct tg3 *tp) int err = 0; int i; - if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5717 || - GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5719) + if (tp->tg3_flags3 & TG3_FLG3_5717_PLUS) mem_tbl = mem_tbl_5717; else if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57765) mem_tbl = mem_tbl_57765; @@ -11930,8 +11923,7 @@ static void __devinit tg3_nvram_init(struct tg3 *tp) else if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57780 || GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57765) tg3_get_57780_nvram_info(tp); - else if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5717 || - GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5719) + else if (tp->tg3_flags3 & TG3_FLG3_5717_PLUS) tg3_get_5717_nvram_info(tp); else tg3_get_nvram_info(tp); @@ -13333,8 +13325,11 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) tp->pdev_peer = tg3_find_peer(tp); if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5717 || - GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5719 || - GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57765) + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5719) + tp->tg3_flags3 |= TG3_FLG3_5717_PLUS; + + if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57765 || + (tp->tg3_flags3 & TG3_FLG3_5717_PLUS)) tp->tg3_flags3 |= TG3_FLG3_57765_PLUS; /* Intentionally exclude ASIC_REV_5906 */ @@ -13427,8 +13422,7 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) tp->tg3_flags3 |= TG3_FLG3_40BIT_DMA_LIMIT_BUG; } - if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5717 || - GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5719) + if (tp->tg3_flags3 & TG3_FLG3_5717_PLUS) tp->tg3_flags3 |= TG3_FLG3_LRG_PROD_RING_CAP; if ((tp->tg3_flags3 & TG3_FLG3_57765_PLUS) && @@ -13962,8 +13956,7 @@ static int __devinit tg3_get_device_address(struct tg3 *tp) tw32_f(NVRAM_CMD, NVRAM_CMD_RESET); else tg3_nvram_unlock(tp); - } else if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5717 || - GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5719) { + } else if (tp->tg3_flags3 & TG3_FLG3_5717_PLUS) { if (PCI_FUNC(tp->pdev->devfn) & 1) mac_offset = 0xcc; if (PCI_FUNC(tp->pdev->devfn) > 1) @@ -14760,8 +14753,7 @@ static int __devinit tg3_init_one(struct pci_dev *pdev, } if ((tp->tg3_flags3 & TG3_FLG3_5755_PLUS) && - GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5717 && - GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5719) + !(tp->tg3_flags3 & TG3_FLG3_5717_PLUS)) dev->netdev_ops = &tg3_netdev_ops; else dev->netdev_ops = &tg3_netdev_ops_dma_bug; diff --git a/drivers/net/tg3.h b/drivers/net/tg3.h index 6f34db5..b8e6acc 100644 --- a/drivers/net/tg3.h +++ b/drivers/net/tg3.h @@ -2917,6 +2917,7 @@ struct tg3 { #define TG3_FLG3_L1PLLPD_EN 0x00800000 #define TG3_FLG3_57765_PLUS 0x01000000 #define TG3_FLG3_APE_HAS_NCSI 0x02000000 +#define TG3_FLG3_5717_PLUS 0x04000000 struct timer_list timer; u16 timer_counter; -- cgit v0.10.2 From d78b59f5d18bf064abae2fa5bc87f00545e2160a Mon Sep 17 00:00:00 2001 From: Matt Carlson Date: Tue, 5 Apr 2011 14:22:46 +0000 Subject: tg3: Add 5720 ASIC rev This patch adds support for the 5720 ASIC rev. Signed-off-by: Matt Carlson Reviewed-by: Michael Chan Signed-off-by: David S. Miller diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index dc6b60b..53a1209 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -2125,7 +2125,8 @@ static void tg3_frob_aux_power(struct tg3 *tp) if ((GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5704 || GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5714 || - GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5717) && + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5717 || + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5720) && tp->pdev_peer != tp->pdev) { struct net_device *dev_peer; @@ -7251,6 +7252,11 @@ static int tg3_chip_reset(struct tg3 *tp) tw32(0x7c00, val | (1 << 25)); } + if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5720) { + val = tr32(TG3_CPMU_CLCK_ORIDE); + tw32(TG3_CPMU_CLCK_ORIDE, val & ~CPMU_CLCK_ORIDE_MAC_ORIDE_EN); + } + /* Reprobe ASF enable state. */ tp->tg3_flags &= ~TG3_FLAG_ENABLE_ASF; tp->tg3_flags2 &= ~TG3_FLG2_ASF_NEW_HANDSHAKE; @@ -8214,7 +8220,8 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy) GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57780 || (tp->tg3_flags3 & TG3_FLG3_57765_PLUS)) { val = tr32(TG3_RDMA_RSRVCTRL_REG); - if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5719) { + if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5719 || + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5720) { val &= ~(TG3_RDMA_RSRVCTRL_TXMRGN_MASK | TG3_RDMA_RSRVCTRL_FIFO_LWM_MASK | TG3_RDMA_RSRVCTRL_FIFO_HWM_MASK); @@ -8226,7 +8233,8 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy) val | TG3_RDMA_RSRVCTRL_FIFO_OFLW_FIX); } - if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5719) { + if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5719 || + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5720) { val = tr32(TG3_LSO_RD_DMA_CRPTEN_CTRL); tw32(TG3_LSO_RD_DMA_CRPTEN_CTRL, val | TG3_LSO_RD_DMA_CRPTEN_CTRL_BLEN_BD_4K | @@ -9050,7 +9058,9 @@ static bool tg3_enable_msix(struct tg3 *tp) if (tp->irq_cnt > 1) { tp->tg3_flags3 |= TG3_FLG3_ENABLE_RSS; - if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5719) { + + if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5719 || + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5720) { tp->tg3_flags3 |= TG3_FLG3_ENABLE_TSS; netif_set_real_num_tx_queues(tp->dev, tp->irq_cnt - 1); } @@ -13166,7 +13176,8 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) if (tp->pdev->device == TG3PCI_DEVICE_TIGON3_5717 || tp->pdev->device == TG3PCI_DEVICE_TIGON3_5718 || - tp->pdev->device == TG3PCI_DEVICE_TIGON3_5719) + tp->pdev->device == TG3PCI_DEVICE_TIGON3_5719 || + tp->pdev->device == TG3PCI_DEVICE_TIGON3_5720) pci_read_config_dword(tp->pdev, TG3PCI_GEN2_PRODID_ASICREV, &prod_id_asic_rev); @@ -13321,11 +13332,13 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5704 || GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5714 || - GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5717) + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5717 || + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5720) tp->pdev_peer = tg3_find_peer(tp); if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5717 || - GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5719) + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5719 || + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5720) tp->tg3_flags3 |= TG3_FLG3_5717_PLUS; if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57765 || @@ -13444,7 +13457,8 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) tp->tg3_flags2 |= TG3_FLG2_PCI_EXPRESS; tp->pcie_readrq = 4096; - if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5719) + if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5719 || + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5720) tp->pcie_readrq = 2048; pcie_set_readrq(tp->pdev, tp->pcie_readrq); diff --git a/drivers/net/tg3.h b/drivers/net/tg3.h index b8e6acc..45605f2 100644 --- a/drivers/net/tg3.h +++ b/drivers/net/tg3.h @@ -58,6 +58,7 @@ #define TG3PCI_DEVICE_TIGON3_57791 0x16b2 #define TG3PCI_DEVICE_TIGON3_57795 0x16b6 #define TG3PCI_DEVICE_TIGON3_5719 0x1657 +#define TG3PCI_DEVICE_TIGON3_5720 0x165f /* 0x04 --> 0x2c unused */ #define TG3PCI_SUBVENDOR_ID_BROADCOM PCI_VENDOR_ID_BROADCOM #define TG3PCI_SUBDEVICE_ID_BROADCOM_95700A6 0x1644 @@ -167,6 +168,7 @@ #define ASIC_REV_5717 0x5717 #define ASIC_REV_57765 0x57785 #define ASIC_REV_5719 0x5719 +#define ASIC_REV_5720 0x5720 #define GET_CHIP_REV(CHIP_REV_ID) ((CHIP_REV_ID) >> 8) #define CHIPREV_5700_AX 0x70 #define CHIPREV_5700_BX 0x71 @@ -1083,6 +1085,9 @@ #define CPMU_HST_ACC_MACCLK_6_25 0x00130000 /* 0x3620 --> 0x3630 unused */ +#define TG3_CPMU_CLCK_ORIDE 0x00003624 +#define CPMU_CLCK_ORIDE_MAC_ORIDE_EN 0x80000000 + #define TG3_CPMU_CLCK_STAT 0x00003630 #define CPMU_CLCK_STAT_MAC_CLCK_MASK 0x001f0000 #define CPMU_CLCK_STAT_MAC_CLCK_62_5 0x00000000 -- cgit v0.10.2 From 9b91b5f178605dd0d4debcbc184a3e97fcb4f591 Mon Sep 17 00:00:00 2001 From: Matt Carlson Date: Tue, 5 Apr 2011 14:22:47 +0000 Subject: tg3: Add 5720 NVRAM decoding The 5720 implements its own NVRAM pin strapping scheme. This patch adds the required support. Signed-off-by: Matt Carlson Reviewed-by: Michael Chan Signed-off-by: David S. Miller diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index 53a1209..a079e74 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -11889,6 +11889,118 @@ static void __devinit tg3_get_5717_nvram_info(struct tg3 *tp) tp->tg3_flags3 |= TG3_FLG3_NO_NVRAM_ADDR_TRANS; } +static void __devinit tg3_get_5720_nvram_info(struct tg3 *tp) +{ + u32 nvcfg1, nvmpinstrp; + + nvcfg1 = tr32(NVRAM_CFG1); + nvmpinstrp = nvcfg1 & NVRAM_CFG1_5752VENDOR_MASK; + + switch (nvmpinstrp) { + case FLASH_5720_EEPROM_HD: + case FLASH_5720_EEPROM_LD: + tp->nvram_jedecnum = JEDEC_ATMEL; + tp->tg3_flags |= TG3_FLAG_NVRAM_BUFFERED; + + nvcfg1 &= ~NVRAM_CFG1_COMPAT_BYPASS; + tw32(NVRAM_CFG1, nvcfg1); + if (nvmpinstrp == FLASH_5720_EEPROM_HD) + tp->nvram_pagesize = ATMEL_AT24C512_CHIP_SIZE; + else + tp->nvram_pagesize = ATMEL_AT24C02_CHIP_SIZE; + return; + case FLASH_5720VENDOR_M_ATMEL_DB011D: + case FLASH_5720VENDOR_A_ATMEL_DB011B: + case FLASH_5720VENDOR_A_ATMEL_DB011D: + case FLASH_5720VENDOR_M_ATMEL_DB021D: + case FLASH_5720VENDOR_A_ATMEL_DB021B: + case FLASH_5720VENDOR_A_ATMEL_DB021D: + case FLASH_5720VENDOR_M_ATMEL_DB041D: + case FLASH_5720VENDOR_A_ATMEL_DB041B: + case FLASH_5720VENDOR_A_ATMEL_DB041D: + case FLASH_5720VENDOR_M_ATMEL_DB081D: + case FLASH_5720VENDOR_A_ATMEL_DB081D: + case FLASH_5720VENDOR_ATMEL_45USPT: + tp->nvram_jedecnum = JEDEC_ATMEL; + tp->tg3_flags |= TG3_FLAG_NVRAM_BUFFERED; + tp->tg3_flags2 |= TG3_FLG2_FLASH; + + switch (nvmpinstrp) { + case FLASH_5720VENDOR_M_ATMEL_DB021D: + case FLASH_5720VENDOR_A_ATMEL_DB021B: + case FLASH_5720VENDOR_A_ATMEL_DB021D: + tp->nvram_size = TG3_NVRAM_SIZE_256KB; + break; + case FLASH_5720VENDOR_M_ATMEL_DB041D: + case FLASH_5720VENDOR_A_ATMEL_DB041B: + case FLASH_5720VENDOR_A_ATMEL_DB041D: + tp->nvram_size = TG3_NVRAM_SIZE_512KB; + break; + case FLASH_5720VENDOR_M_ATMEL_DB081D: + case FLASH_5720VENDOR_A_ATMEL_DB081D: + tp->nvram_size = TG3_NVRAM_SIZE_1MB; + break; + default: + tp->nvram_size = TG3_NVRAM_SIZE_128KB; + break; + } + break; + case FLASH_5720VENDOR_M_ST_M25PE10: + case FLASH_5720VENDOR_M_ST_M45PE10: + case FLASH_5720VENDOR_A_ST_M25PE10: + case FLASH_5720VENDOR_A_ST_M45PE10: + case FLASH_5720VENDOR_M_ST_M25PE20: + case FLASH_5720VENDOR_M_ST_M45PE20: + case FLASH_5720VENDOR_A_ST_M25PE20: + case FLASH_5720VENDOR_A_ST_M45PE20: + case FLASH_5720VENDOR_M_ST_M25PE40: + case FLASH_5720VENDOR_M_ST_M45PE40: + case FLASH_5720VENDOR_A_ST_M25PE40: + case FLASH_5720VENDOR_A_ST_M45PE40: + case FLASH_5720VENDOR_M_ST_M25PE80: + case FLASH_5720VENDOR_M_ST_M45PE80: + case FLASH_5720VENDOR_A_ST_M25PE80: + case FLASH_5720VENDOR_A_ST_M45PE80: + case FLASH_5720VENDOR_ST_25USPT: + case FLASH_5720VENDOR_ST_45USPT: + tp->nvram_jedecnum = JEDEC_ST; + tp->tg3_flags |= TG3_FLAG_NVRAM_BUFFERED; + tp->tg3_flags2 |= TG3_FLG2_FLASH; + + switch (nvmpinstrp) { + case FLASH_5720VENDOR_M_ST_M25PE20: + case FLASH_5720VENDOR_M_ST_M45PE20: + case FLASH_5720VENDOR_A_ST_M25PE20: + case FLASH_5720VENDOR_A_ST_M45PE20: + tp->nvram_size = TG3_NVRAM_SIZE_256KB; + break; + case FLASH_5720VENDOR_M_ST_M25PE40: + case FLASH_5720VENDOR_M_ST_M45PE40: + case FLASH_5720VENDOR_A_ST_M25PE40: + case FLASH_5720VENDOR_A_ST_M45PE40: + tp->nvram_size = TG3_NVRAM_SIZE_512KB; + break; + case FLASH_5720VENDOR_M_ST_M25PE80: + case FLASH_5720VENDOR_M_ST_M45PE80: + case FLASH_5720VENDOR_A_ST_M25PE80: + case FLASH_5720VENDOR_A_ST_M45PE80: + tp->nvram_size = TG3_NVRAM_SIZE_1MB; + break; + default: + tp->nvram_size = TG3_NVRAM_SIZE_128KB; + break; + } + break; + default: + tp->tg3_flags3 |= TG3_FLG3_NO_NVRAM; + return; + } + + tg3_nvram_get_pagesize(tp, nvcfg1); + if (tp->nvram_pagesize != 264 && tp->nvram_pagesize != 528) + tp->tg3_flags3 |= TG3_FLG3_NO_NVRAM_ADDR_TRANS; +} + /* Chips other than 5700/5701 use the NVRAM for fetching info. */ static void __devinit tg3_nvram_init(struct tg3 *tp) { @@ -11933,8 +12045,11 @@ static void __devinit tg3_nvram_init(struct tg3 *tp) else if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57780 || GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57765) tg3_get_57780_nvram_info(tp); - else if (tp->tg3_flags3 & TG3_FLG3_5717_PLUS) + else if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5717 || + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5719) tg3_get_5717_nvram_info(tp); + else if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5720) + tg3_get_5720_nvram_info(tp); else tg3_get_nvram_info(tp); diff --git a/drivers/net/tg3.h b/drivers/net/tg3.h index 45605f2..169a6ce 100644 --- a/drivers/net/tg3.h +++ b/drivers/net/tg3.h @@ -1827,6 +1827,38 @@ #define FLASH_5717VENDOR_ATMEL_45USPT 0x03400000 #define FLASH_5717VENDOR_ST_25USPT 0x03400002 #define FLASH_5717VENDOR_ST_45USPT 0x03400001 +#define FLASH_5720_EEPROM_HD 0x00000001 +#define FLASH_5720_EEPROM_LD 0x00000003 +#define FLASH_5720VENDOR_M_ATMEL_DB011D 0x01000000 +#define FLASH_5720VENDOR_M_ATMEL_DB021D 0x01000002 +#define FLASH_5720VENDOR_M_ATMEL_DB041D 0x01000001 +#define FLASH_5720VENDOR_M_ATMEL_DB081D 0x01000003 +#define FLASH_5720VENDOR_M_ST_M25PE10 0x02000000 +#define FLASH_5720VENDOR_M_ST_M25PE20 0x02000002 +#define FLASH_5720VENDOR_M_ST_M25PE40 0x02000001 +#define FLASH_5720VENDOR_M_ST_M25PE80 0x02000003 +#define FLASH_5720VENDOR_M_ST_M45PE10 0x03000000 +#define FLASH_5720VENDOR_M_ST_M45PE20 0x03000002 +#define FLASH_5720VENDOR_M_ST_M45PE40 0x03000001 +#define FLASH_5720VENDOR_M_ST_M45PE80 0x03000003 +#define FLASH_5720VENDOR_A_ATMEL_DB011B 0x01800000 +#define FLASH_5720VENDOR_A_ATMEL_DB021B 0x01800002 +#define FLASH_5720VENDOR_A_ATMEL_DB041B 0x01800001 +#define FLASH_5720VENDOR_A_ATMEL_DB011D 0x01c00000 +#define FLASH_5720VENDOR_A_ATMEL_DB021D 0x01c00002 +#define FLASH_5720VENDOR_A_ATMEL_DB041D 0x01c00001 +#define FLASH_5720VENDOR_A_ATMEL_DB081D 0x01c00003 +#define FLASH_5720VENDOR_A_ST_M25PE10 0x02800000 +#define FLASH_5720VENDOR_A_ST_M25PE20 0x02800002 +#define FLASH_5720VENDOR_A_ST_M25PE40 0x02800001 +#define FLASH_5720VENDOR_A_ST_M25PE80 0x02800003 +#define FLASH_5720VENDOR_A_ST_M45PE10 0x02c00000 +#define FLASH_5720VENDOR_A_ST_M45PE20 0x02c00002 +#define FLASH_5720VENDOR_A_ST_M45PE40 0x02c00001 +#define FLASH_5720VENDOR_A_ST_M45PE80 0x02c00003 +#define FLASH_5720VENDOR_ATMEL_45USPT 0x03c00000 +#define FLASH_5720VENDOR_ST_25USPT 0x03c00002 +#define FLASH_5720VENDOR_ST_45USPT 0x03c00001 #define NVRAM_CFG1_5752PAGE_SIZE_MASK 0x70000000 #define FLASH_5752PAGE_SIZE_256 0x00000000 #define FLASH_5752PAGE_SIZE_512 0x10000000 @@ -3060,6 +3092,7 @@ struct tg3 { int nvram_lock_cnt; u32 nvram_size; +#define TG3_NVRAM_SIZE_2KB 0x00000800 #define TG3_NVRAM_SIZE_64KB 0x00010000 #define TG3_NVRAM_SIZE_128KB 0x00020000 #define TG3_NVRAM_SIZE_256KB 0x00040000 @@ -3075,6 +3108,9 @@ struct tg3 { #define JEDEC_SAIFUN 0x4f #define JEDEC_SST 0xbf +#define ATMEL_AT24C02_CHIP_SIZE TG3_NVRAM_SIZE_2KB +#define ATMEL_AT24C02_PAGE_SIZE (8) + #define ATMEL_AT24C64_CHIP_SIZE TG3_NVRAM_SIZE_64KB #define ATMEL_AT24C64_PAGE_SIZE (32) -- cgit v0.10.2 From f2096f94b514d88593355995d5dd276961e88af1 Mon Sep 17 00:00:00 2001 From: Matt Carlson Date: Tue, 5 Apr 2011 14:22:48 +0000 Subject: tg3: Add 5720 H2BMC support This patch adds support for the new Host to BMC feature. Signed-off-by: Matt Carlson Reviewed-by: Michael Chan Signed-off-by: David S. Miller diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index a079e74..263f151 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -4390,6 +4390,7 @@ static void tg3_serdes_parallel_detect(struct tg3 *tp) static int tg3_setup_phy(struct tg3 *tp, int force_reset) { + u32 val; int err; if (tp->phy_flags & TG3_PHYFLG_PHY_SERDES) @@ -4400,7 +4401,7 @@ static int tg3_setup_phy(struct tg3 *tp, int force_reset) err = tg3_setup_copper_phy(tp, force_reset); if (GET_CHIP_REV(tp->pci_chip_rev_id) == CHIPREV_5784_AX) { - u32 val, scale; + u32 scale; val = tr32(TG3_CPMU_CLCK_STAT) & CPMU_CLCK_STAT_MAC_CLCK_MASK; if (val == CPMU_CLCK_STAT_MAC_CLCK_62_5) @@ -4415,17 +4416,20 @@ static int tg3_setup_phy(struct tg3 *tp, int force_reset) tw32(GRC_MISC_CFG, val); } + val = (2 << TX_LENGTHS_IPG_CRS_SHIFT) | + (6 << TX_LENGTHS_IPG_SHIFT); + if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5720) + val |= tr32(MAC_TX_LENGTHS) & + (TX_LENGTHS_JMB_FRM_LEN_MSK | + TX_LENGTHS_CNT_DWN_VAL_MSK); + if (tp->link_config.active_speed == SPEED_1000 && tp->link_config.active_duplex == DUPLEX_HALF) - tw32(MAC_TX_LENGTHS, - ((2 << TX_LENGTHS_IPG_CRS_SHIFT) | - (6 << TX_LENGTHS_IPG_SHIFT) | - (0xff << TX_LENGTHS_SLOT_TIME_SHIFT))); + tw32(MAC_TX_LENGTHS, val | + (0xff << TX_LENGTHS_SLOT_TIME_SHIFT)); else - tw32(MAC_TX_LENGTHS, - ((2 << TX_LENGTHS_IPG_CRS_SHIFT) | - (6 << TX_LENGTHS_IPG_SHIFT) | - (32 << TX_LENGTHS_SLOT_TIME_SHIFT))); + tw32(MAC_TX_LENGTHS, val | + (32 << TX_LENGTHS_SLOT_TIME_SHIFT)); if (!(tp->tg3_flags2 & TG3_FLG2_5705_PLUS)) { if (netif_carrier_ok(tp->dev)) { @@ -4437,7 +4441,7 @@ static int tg3_setup_phy(struct tg3 *tp, int force_reset) } if (tp->tg3_flags & TG3_FLAG_ASPM_WORKAROUND) { - u32 val = tr32(PCIE_PWR_MGMT_THRESH); + val = tr32(PCIE_PWR_MGMT_THRESH); if (!netif_carrier_ok(tp->dev)) val = (val & ~PCIE_PWR_MGMT_L1_THRESH_MSK) | tp->pwrmgmt_thresh; @@ -8164,10 +8168,16 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy) /* The slot time is changed by tg3_setup_phy if we * run at gigabit with half duplex. */ - tw32(MAC_TX_LENGTHS, - (2 << TX_LENGTHS_IPG_CRS_SHIFT) | - (6 << TX_LENGTHS_IPG_SHIFT) | - (32 << TX_LENGTHS_SLOT_TIME_SHIFT)); + val = (2 << TX_LENGTHS_IPG_CRS_SHIFT) | + (6 << TX_LENGTHS_IPG_SHIFT) | + (32 << TX_LENGTHS_SLOT_TIME_SHIFT); + + if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5720) + val |= tr32(MAC_TX_LENGTHS) & + (TX_LENGTHS_JMB_FRM_LEN_MSK | + TX_LENGTHS_CNT_DWN_VAL_MSK); + + tw32(MAC_TX_LENGTHS, val); /* Receive rules. */ tw32(MAC_RCV_RULE_CFG, RCV_RULE_CFG_DEFAULT_CLASS); @@ -8214,6 +8224,9 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy) GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57780) rdmac_mode |= RDMAC_MODE_IPV6_LSO_EN; + if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5720) + rdmac_mode |= tr32(RDMAC_MODE) & RDMAC_MODE_H2BNC_VLAN_DET; + if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761 || GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784 || GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5785 || @@ -8447,9 +8460,17 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy) } tp->tx_mode = TX_MODE_ENABLE; + if ((tp->tg3_flags3 & TG3_FLG3_5755_PLUS) || GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906) tp->tx_mode |= TX_MODE_MBUF_LOCKUP_FIX; + + if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5720) { + val = TX_MODE_JMB_FRM_LEN | TX_MODE_CNT_DN_MODE; + tp->tx_mode &= ~val; + tp->tx_mode |= tr32(MAC_TX_MODE) & val; + } + tw32_f(MAC_TX_MODE, tp->tx_mode); udelay(100); @@ -13880,7 +13901,15 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) /* Initialize data/descriptor byte/word swapping. */ val = tr32(GRC_MODE); - val &= GRC_MODE_HOST_STACKUP; + if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5720) + val &= (GRC_MODE_BYTE_SWAP_B2HRX_DATA | + GRC_MODE_WORD_SWAP_B2HRX_DATA | + GRC_MODE_B2HRX_ENABLE | + GRC_MODE_HTX2B_ENABLE | + GRC_MODE_HOST_STACKUP); + else + val &= GRC_MODE_HOST_STACKUP; + tw32(GRC_MODE, val | tp->grc_mode); tg3_switch_clocks(tp); diff --git a/drivers/net/tg3.h b/drivers/net/tg3.h index 169a6ce..a936727 100644 --- a/drivers/net/tg3.h +++ b/drivers/net/tg3.h @@ -479,6 +479,8 @@ #define TX_MODE_BIG_BCKOFF_ENABLE 0x00000020 #define TX_MODE_LONG_PAUSE_ENABLE 0x00000040 #define TX_MODE_MBUF_LOCKUP_FIX 0x00000100 +#define TX_MODE_JMB_FRM_LEN 0x00400000 +#define TX_MODE_CNT_DN_MODE 0x00800000 #define MAC_TX_STATUS 0x00000460 #define TX_STATUS_XOFFED 0x00000001 #define TX_STATUS_SENT_XOFF 0x00000002 @@ -493,6 +495,8 @@ #define TX_LENGTHS_IPG_SHIFT 8 #define TX_LENGTHS_IPG_CRS_MASK 0x00003000 #define TX_LENGTHS_IPG_CRS_SHIFT 12 +#define TX_LENGTHS_JMB_FRM_LEN_MSK 0x00ff0000 +#define TX_LENGTHS_CNT_DWN_VAL_MSK 0xff000000 #define MAC_RX_MODE 0x00000468 #define RX_MODE_RESET 0x00000001 #define RX_MODE_ENABLE 0x00000002 @@ -1330,6 +1334,7 @@ #define RDMAC_MODE_MULT_DMA_RD_DIS 0x01000000 #define RDMAC_MODE_IPV4_LSO_EN 0x08000000 #define RDMAC_MODE_IPV6_LSO_EN 0x10000000 +#define RDMAC_MODE_H2BNC_VLAN_DET 0x20000000 #define RDMAC_STATUS 0x00004804 #define RDMAC_STATUS_TGTABORT 0x00000004 #define RDMAC_STATUS_MSTABORT 0x00000008 @@ -1622,6 +1627,8 @@ #define GRC_MODE_WSWAP_NONFRM_DATA 0x00000004 #define GRC_MODE_BSWAP_DATA 0x00000010 #define GRC_MODE_WSWAP_DATA 0x00000020 +#define GRC_MODE_BYTE_SWAP_B2HRX_DATA 0x00000040 +#define GRC_MODE_WORD_SWAP_B2HRX_DATA 0x00000080 #define GRC_MODE_SPLITHDR 0x00000100 #define GRC_MODE_NOFRM_CRACKING 0x00000200 #define GRC_MODE_INCL_CRC 0x00000400 @@ -1629,8 +1636,10 @@ #define GRC_MODE_NOIRQ_ON_SENDS 0x00002000 #define GRC_MODE_NOIRQ_ON_RCV 0x00004000 #define GRC_MODE_FORCE_PCI32BIT 0x00008000 +#define GRC_MODE_B2HRX_ENABLE 0x00008000 #define GRC_MODE_HOST_STACKUP 0x00010000 #define GRC_MODE_HOST_SENDBDS 0x00020000 +#define GRC_MODE_HTX2B_ENABLE 0x00040000 #define GRC_MODE_NO_TX_PHDR_CSUM 0x00100000 #define GRC_MODE_NVRAM_WR_ENABLE 0x00200000 #define GRC_MODE_PCIE_TL_SEL 0x00000000 -- cgit v0.10.2 From 6418f2c1b57f9a5d4e7380f698635e5a445c2a50 Mon Sep 17 00:00:00 2001 From: Matt Carlson Date: Tue, 5 Apr 2011 14:22:49 +0000 Subject: tg3: Add 5720 PHY ID This patch adds the 5720 PHY ID. Signed-off-by: Matt Carlson Reviewed-by: Michael Chan Signed-off-by: David S. Miller diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index 263f151..886174d 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -14673,6 +14673,7 @@ static char * __devinit tg3_phy_string(struct tg3 *tp) case TG3_PHY_ID_BCM5718S: return "5718S"; case TG3_PHY_ID_BCM57765: return "57765"; case TG3_PHY_ID_BCM5719C: return "5719C"; + case TG3_PHY_ID_BCM5720C: return "5720C"; case TG3_PHY_ID_BCM8002: return "8002/serdes"; case 0: return "serdes"; default: return "unknown"; diff --git a/drivers/net/tg3.h b/drivers/net/tg3.h index a936727..e7880d5 100644 --- a/drivers/net/tg3.h +++ b/drivers/net/tg3.h @@ -3035,6 +3035,7 @@ struct tg3 { #define TG3_PHY_ID_BCM5718S 0xbc050ff0 #define TG3_PHY_ID_BCM57765 0x5c0d8a40 #define TG3_PHY_ID_BCM5719C 0x5c0d8a20 +#define TG3_PHY_ID_BCM5720C 0x5c0d8b60 #define TG3_PHY_ID_BCM5906 0xdc00ac40 #define TG3_PHY_ID_BCM8002 0x60010140 #define TG3_PHY_ID_INVALID 0xffffffff -- cgit v0.10.2 From ba1f3c76d7607a0af58834b79a055326619cbf2a Mon Sep 17 00:00:00 2001 From: Matt Carlson Date: Tue, 5 Apr 2011 14:22:50 +0000 Subject: tg3: Enable 5720 support This patch adds the 5720 device ID to the PCI table, thus enabling 5720 support. Signed-off-by: Matt Carlson Reviewed-by: Michael Chan Signed-off-by: David S. Miller diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index 886174d..a065beb 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -264,6 +264,7 @@ static DEFINE_PCI_DEVICE_TABLE(tg3_pci_tbl) = { {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, TG3PCI_DEVICE_TIGON3_57791)}, {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, TG3PCI_DEVICE_TIGON3_57795)}, {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, TG3PCI_DEVICE_TIGON3_5719)}, + {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, TG3PCI_DEVICE_TIGON3_5720)}, {PCI_DEVICE(PCI_VENDOR_ID_SYSKONNECT, PCI_DEVICE_ID_SYSKONNECT_9DXX)}, {PCI_DEVICE(PCI_VENDOR_ID_SYSKONNECT, PCI_DEVICE_ID_SYSKONNECT_9MXX)}, {PCI_DEVICE(PCI_VENDOR_ID_ALTIMA, PCI_DEVICE_ID_ALTIMA_AC1000)}, -- cgit v0.10.2 From 66ee33bfda6237b009b6fb0e48690e31800ff334 Mon Sep 17 00:00:00 2001 From: Matt Carlson Date: Tue, 5 Apr 2011 14:22:51 +0000 Subject: tg3: Support 4mb flash sizes for 5717 and 5719 If a 5717 or 5719 NVRAM part is manually strapped and is 2mb in size, the driver needs to look at the NVRAM size field rather than infer it from the strapping itself. Signed-off-by: Matt Carlson Reviewed-by: Michael Chan Signed-off-by: David S. Miller diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index a065beb..f944c6b 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -11866,6 +11866,8 @@ static void __devinit tg3_get_5717_nvram_info(struct tg3 *tp) switch (nvcfg1 & NVRAM_CFG1_5752VENDOR_MASK) { case FLASH_5717VENDOR_ATMEL_MDB021D: + /* Detect size with tg3_nvram_get_size() */ + break; case FLASH_5717VENDOR_ATMEL_ADB021B: case FLASH_5717VENDOR_ATMEL_ADB021D: tp->nvram_size = TG3_NVRAM_SIZE_256KB; @@ -11891,8 +11893,10 @@ static void __devinit tg3_get_5717_nvram_info(struct tg3 *tp) switch (nvcfg1 & NVRAM_CFG1_5752VENDOR_MASK) { case FLASH_5717VENDOR_ST_M_M25PE20: - case FLASH_5717VENDOR_ST_A_M25PE20: case FLASH_5717VENDOR_ST_M_M45PE20: + /* Detect size with tg3_nvram_get_size() */ + break; + case FLASH_5717VENDOR_ST_A_M25PE20: case FLASH_5717VENDOR_ST_A_M45PE20: tp->nvram_size = TG3_NVRAM_SIZE_256KB; break; -- cgit v0.10.2 From 1ca050d909add6825224c015d8cec2425b3edf27 Mon Sep 17 00:00:00 2001 From: Oliver Hartkopp Date: Tue, 5 Apr 2011 08:01:16 +0000 Subject: can: convert protocol handling to RCU This patch removes spin_locks at CAN socket creation time by using RCU. Inspired by the discussion with Kurt van Dijck and Eric Dumazet the RCU code was partly derived from af_phonet.c Signed-off-by: Oliver Hartkopp Reviewed-by: Eric Dumazet Acked-by: Kurt Van Dijck Signed-off-by: David S. Miller diff --git a/net/can/af_can.c b/net/can/af_can.c index 733d66f..a8dcaa4 100644 --- a/net/can/af_can.c +++ b/net/can/af_can.c @@ -85,7 +85,7 @@ static struct kmem_cache *rcv_cache __read_mostly; /* table of registered CAN protocols */ static struct can_proto *proto_tab[CAN_NPROTO] __read_mostly; -static DEFINE_SPINLOCK(proto_tab_lock); +static DEFINE_MUTEX(proto_tab_lock); struct timer_list can_stattimer; /* timer for statistics update */ struct s_stats can_stats; /* packet statistics */ @@ -115,6 +115,19 @@ static void can_sock_destruct(struct sock *sk) skb_queue_purge(&sk->sk_receive_queue); } +static struct can_proto *can_try_module_get(int protocol) +{ + struct can_proto *cp; + + rcu_read_lock(); + cp = rcu_dereference(proto_tab[protocol]); + if (cp && !try_module_get(cp->prot->owner)) + cp = NULL; + rcu_read_unlock(); + + return cp; +} + static int can_create(struct net *net, struct socket *sock, int protocol, int kern) { @@ -130,9 +143,12 @@ static int can_create(struct net *net, struct socket *sock, int protocol, if (!net_eq(net, &init_net)) return -EAFNOSUPPORT; + cp = can_try_module_get(protocol); + #ifdef CONFIG_MODULES - /* try to load protocol module kernel is modular */ - if (!proto_tab[protocol]) { + if (!cp) { + /* try to load protocol module if kernel is modular */ + err = request_module("can-proto-%d", protocol); /* @@ -143,22 +159,18 @@ static int can_create(struct net *net, struct socket *sock, int protocol, if (err && printk_ratelimit()) printk(KERN_ERR "can: request_module " "(can-proto-%d) failed.\n", protocol); + + cp = can_try_module_get(protocol); } #endif - spin_lock(&proto_tab_lock); - cp = proto_tab[protocol]; - if (cp && !try_module_get(cp->prot->owner)) - cp = NULL; - spin_unlock(&proto_tab_lock); - /* check for available protocol and correct usage */ if (!cp) return -EPROTONOSUPPORT; if (cp->type != sock->type) { - err = -EPROTONOSUPPORT; + err = -EPROTOTYPE; goto errout; } @@ -694,15 +706,16 @@ int can_proto_register(struct can_proto *cp) if (err < 0) return err; - spin_lock(&proto_tab_lock); + mutex_lock(&proto_tab_lock); + if (proto_tab[proto]) { printk(KERN_ERR "can: protocol %d already registered\n", proto); err = -EBUSY; } else - proto_tab[proto] = cp; + rcu_assign_pointer(proto_tab[proto], cp); - spin_unlock(&proto_tab_lock); + mutex_unlock(&proto_tab_lock); if (err < 0) proto_unregister(cp->prot); @@ -719,13 +732,12 @@ void can_proto_unregister(struct can_proto *cp) { int proto = cp->protocol; - spin_lock(&proto_tab_lock); - if (!proto_tab[proto]) { - printk(KERN_ERR "BUG: can: protocol %d is not registered\n", - proto); - } - proto_tab[proto] = NULL; - spin_unlock(&proto_tab_lock); + mutex_lock(&proto_tab_lock); + BUG_ON(proto_tab[proto] != cp); + rcu_assign_pointer(proto_tab[proto], NULL); + mutex_unlock(&proto_tab_lock); + + synchronize_rcu(); proto_unregister(cp->prot); } -- cgit v0.10.2 From 53478fef7490c90564dd328b395f238952d95c77 Mon Sep 17 00:00:00 2001 From: Sony Chacko Date: Fri, 1 Apr 2011 14:27:47 +0000 Subject: qlcnic: Make PCI info available in all modes Before this fix, PCI info was available only when multiple NIC functions are present on the same port. Signed-off-by: Sony Chacko Signed-off-by: Anirban Chakraborty Signed-off-by: David S. Miller diff --git a/drivers/net/qlcnic/qlcnic_main.c b/drivers/net/qlcnic/qlcnic_main.c index cd88c7e..d230fdd 100644 --- a/drivers/net/qlcnic/qlcnic_main.c +++ b/drivers/net/qlcnic/qlcnic_main.c @@ -3954,14 +3954,14 @@ qlcnic_create_diag_entries(struct qlcnic_adapter *adapter) dev_info(dev, "failed to create crb sysfs entry\n"); if (device_create_bin_file(dev, &bin_attr_mem)) dev_info(dev, "failed to create mem sysfs entry\n"); + if (device_create_bin_file(dev, &bin_attr_pci_config)) + dev_info(dev, "failed to create pci config sysfs entry"); if (!(adapter->flags & QLCNIC_ESWITCH_ENABLED)) return; if (device_create_bin_file(dev, &bin_attr_esw_config)) dev_info(dev, "failed to create esw config sysfs entry"); if (adapter->op_mode != QLCNIC_MGMT_FUNC) return; - if (device_create_bin_file(dev, &bin_attr_pci_config)) - dev_info(dev, "failed to create pci config sysfs entry"); if (device_create_bin_file(dev, &bin_attr_npar_config)) dev_info(dev, "failed to create npar config sysfs entry"); if (device_create_bin_file(dev, &bin_attr_pm_config)) @@ -3982,12 +3982,12 @@ qlcnic_remove_diag_entries(struct qlcnic_adapter *adapter) device_remove_file(dev, &dev_attr_diag_mode); device_remove_bin_file(dev, &bin_attr_crb); device_remove_bin_file(dev, &bin_attr_mem); + device_remove_bin_file(dev, &bin_attr_pci_config); if (!(adapter->flags & QLCNIC_ESWITCH_ENABLED)) return; device_remove_bin_file(dev, &bin_attr_esw_config); if (adapter->op_mode != QLCNIC_MGMT_FUNC) return; - device_remove_bin_file(dev, &bin_attr_pci_config); device_remove_bin_file(dev, &bin_attr_npar_config); device_remove_bin_file(dev, &bin_attr_pm_config); device_remove_bin_file(dev, &bin_attr_esw_stats); -- cgit v0.10.2 From f848d6dd10e8e27d5dd61a8ab7174a7dde3a3db5 Mon Sep 17 00:00:00 2001 From: Sony Chacko Date: Fri, 1 Apr 2011 14:27:59 +0000 Subject: qlcnic: Memory leak fix Fix a memory leak in error path of pci info. Signed-off-by: Sony Chacko Signed-off-by: Anirban Chakraborty Signed-off-by: David S. Miller diff --git a/drivers/net/qlcnic/qlcnic_main.c b/drivers/net/qlcnic/qlcnic_main.c index d230fdd..de6f866 100644 --- a/drivers/net/qlcnic/qlcnic_main.c +++ b/drivers/net/qlcnic/qlcnic_main.c @@ -464,8 +464,10 @@ qlcnic_init_pci_info(struct qlcnic_adapter *adapter) for (i = 0; i < QLCNIC_MAX_PCI_FUNC; i++) { pfn = pci_info[i].id; - if (pfn > QLCNIC_MAX_PCI_FUNC) - return QL_STATUS_INVALID_PARAM; + if (pfn > QLCNIC_MAX_PCI_FUNC) { + ret = QL_STATUS_INVALID_PARAM; + goto err_eswitch; + } adapter->npars[pfn].active = (u8)pci_info[i].active; adapter->npars[pfn].type = (u8)pci_info[i].type; adapter->npars[pfn].phy_port = (u8)pci_info[i].default_port; -- cgit v0.10.2 From b1fc6d3cfaff6fefd838b84532cb356f8a80da7b Mon Sep 17 00:00:00 2001 From: Anirban Chakraborty Date: Fri, 1 Apr 2011 14:28:05 +0000 Subject: qlcnic: Cleanup patch 1. Changed adapter structure to move away from embedding hardware and receive context structs and use pointers to those objects 2. Packed all the structs that interface with FW 3. Removed unused code and structs Signed-off-by: Anirban Chakraborty Signed-off-by: David S. Miller diff --git a/drivers/net/qlcnic/qlcnic.h b/drivers/net/qlcnic/qlcnic.h index dc44564..15d950a 100644 --- a/drivers/net/qlcnic/qlcnic.h +++ b/drivers/net/qlcnic/qlcnic.h @@ -93,8 +93,6 @@ #define TX_IP_PKT 0x04 #define TX_TCP_LSO 0x05 #define TX_TCP_LSO6 0x06 -#define TX_IPSEC 0x07 -#define TX_IPSEC_CMD 0x0a #define TX_TCPV6_PKT 0x0b #define TX_UDPV6_PKT 0x0c @@ -200,7 +198,7 @@ struct rcv_desc { __le16 reserved; __le32 buffer_length; /* allocated buffer length (usually 2K) */ __le64 addr_buffer; -}; +} __packed; /* opcode field in status_desc */ #define QLCNIC_SYN_OFFLOAD 0x03 @@ -365,12 +363,6 @@ struct qlcnic_skb_frag { u64 length; }; -struct qlcnic_recv_crb { - u32 crb_rcv_producer[NUM_RCV_DESC_RINGS]; - u32 crb_sts_consumer[NUM_STS_DESC_RINGS]; - u32 sw_int_mask[NUM_STS_DESC_RINGS]; -}; - /* Following defines are for the state of the buffers */ #define QLCNIC_BUFFER_FREE 0 #define QLCNIC_BUFFER_BUSY 1 @@ -387,10 +379,10 @@ struct qlcnic_cmd_buffer { /* In rx_buffer, we do not need multiple fragments as is a single buffer */ struct qlcnic_rx_buffer { - struct list_head list; + u16 ref_handle; struct sk_buff *skb; + struct list_head list; u64 dma; - u16 ref_handle; }; /* Board types */ @@ -494,12 +486,12 @@ struct qlcnic_host_tx_ring { * present elsewhere. */ struct qlcnic_recv_context { + struct qlcnic_host_rds_ring *rds_rings; + struct qlcnic_host_sds_ring *sds_rings; u32 state; u16 context_id; u16 virt_port; - struct qlcnic_host_rds_ring *rds_rings; - struct qlcnic_host_sds_ring *sds_rings; }; /* HW context creation */ @@ -538,9 +530,6 @@ struct qlcnic_recv_context { #define QLCNIC_CDRP_CMD_DESTROY_RX_CTX 0x00000008 #define QLCNIC_CDRP_CMD_CREATE_TX_CTX 0x00000009 #define QLCNIC_CDRP_CMD_DESTROY_TX_CTX 0x0000000a -#define QLCNIC_CDRP_CMD_SETUP_STATISTICS 0x0000000e -#define QLCNIC_CDRP_CMD_GET_STATISTICS 0x0000000f -#define QLCNIC_CDRP_CMD_DELETE_STATISTICS 0x00000010 #define QLCNIC_CDRP_CMD_SET_MTU 0x00000012 #define QLCNIC_CDRP_CMD_READ_PHY 0x00000013 #define QLCNIC_CDRP_CMD_WRITE_PHY 0x00000014 @@ -549,17 +538,11 @@ struct qlcnic_recv_context { #define QLCNIC_CDRP_CMD_SET_FLOW_CTL 0x00000017 #define QLCNIC_CDRP_CMD_READ_MAX_MTU 0x00000018 #define QLCNIC_CDRP_CMD_READ_MAX_LRO 0x00000019 -#define QLCNIC_CDRP_CMD_CONFIGURE_TOE 0x0000001a -#define QLCNIC_CDRP_CMD_FUNC_ATTRIB 0x0000001b -#define QLCNIC_CDRP_CMD_READ_PEXQ_PARAMETERS 0x0000001c -#define QLCNIC_CDRP_CMD_GET_LIC_CAPABILITIES 0x0000001d -#define QLCNIC_CDRP_CMD_READ_MAX_LRO_PER_BOARD 0x0000001e #define QLCNIC_CDRP_CMD_MAC_ADDRESS 0x0000001f #define QLCNIC_CDRP_CMD_GET_PCI_INFO 0x00000020 #define QLCNIC_CDRP_CMD_GET_NIC_INFO 0x00000021 #define QLCNIC_CDRP_CMD_SET_NIC_INFO 0x00000022 -#define QLCNIC_CDRP_CMD_RESET_NPAR 0x00000023 #define QLCNIC_CDRP_CMD_GET_ESWITCH_CAPABILITY 0x00000024 #define QLCNIC_CDRP_CMD_TOGGLE_ESWITCH 0x00000025 #define QLCNIC_CDRP_CMD_GET_ESWITCH_STATUS 0x00000026 @@ -597,14 +580,14 @@ struct qlcnic_hostrq_sds_ring { __le32 ring_size; /* Ring entries */ __le16 msi_index; __le16 rsvd; /* Padding */ -}; +} __packed; struct qlcnic_hostrq_rds_ring { __le64 host_phys_addr; /* Ring base addr */ __le64 buff_size; /* Packet buffer size */ __le32 ring_size; /* Ring entries */ __le32 ring_kind; /* Class of ring */ -}; +} __packed; struct qlcnic_hostrq_rx_ctx { __le64 host_rsp_dma_addr; /* Response dma'd here */ @@ -625,17 +608,17 @@ struct qlcnic_hostrq_rx_ctx { - N hostrq_rds_rings - N hostrq_sds_rings */ char data[0]; -}; +} __packed; struct qlcnic_cardrsp_rds_ring{ __le32 host_producer_crb; /* Crb to use */ __le32 rsvd1; /* Padding */ -}; +} __packed; struct qlcnic_cardrsp_sds_ring { __le32 host_consumer_crb; /* Crb to use */ __le32 interrupt_crb; /* Crb to use */ -}; +} __packed; struct qlcnic_cardrsp_rx_ctx { /* These ring offsets are relative to data[0] below */ @@ -654,7 +637,7 @@ struct qlcnic_cardrsp_rx_ctx { - N cardrsp_rds_rings - N cardrs_sds_rings */ char data[0]; -}; +} __packed; #define SIZEOF_HOSTRQ_RX(HOSTRQ_RX, rds_rings, sds_rings) \ (sizeof(HOSTRQ_RX) + \ @@ -674,7 +657,7 @@ struct qlcnic_hostrq_cds_ring { __le64 host_phys_addr; /* Ring base addr */ __le32 ring_size; /* Ring entries */ __le32 rsvd; /* Padding */ -}; +} __packed; struct qlcnic_hostrq_tx_ctx { __le64 host_rsp_dma_addr; /* Response dma'd here */ @@ -689,12 +672,12 @@ struct qlcnic_hostrq_tx_ctx { __le16 rsvd3; /* Padding */ struct qlcnic_hostrq_cds_ring cds_ring; /* Desc of cds ring */ u8 reserved[128]; /* future expansion */ -}; +} __packed; struct qlcnic_cardrsp_cds_ring { __le32 host_producer_crb; /* Crb to use */ __le32 interrupt_crb; /* Crb to use */ -}; +} __packed; struct qlcnic_cardrsp_tx_ctx { __le32 host_ctx_state; /* Starting state */ @@ -703,7 +686,7 @@ struct qlcnic_cardrsp_tx_ctx { u8 virt_port; /* Virtual/Logical id of port */ struct qlcnic_cardrsp_cds_ring cds_ring; /* Card cds settings */ u8 reserved[128]; /* future expansion */ -}; +} __packed; #define SIZEOF_HOSTRQ_TX(HOSTRQ_TX) (sizeof(HOSTRQ_TX)) #define SIZEOF_CARDRSP_TX(CARDRSP_TX) (sizeof(CARDRSP_TX)) @@ -782,50 +765,20 @@ struct qlcnic_nic_intr_coalesce { /* * Driver --> Firmware */ -#define QLCNIC_H2C_OPCODE_START 0 -#define QLCNIC_H2C_OPCODE_CONFIG_RSS 1 -#define QLCNIC_H2C_OPCODE_CONFIG_RSS_TBL 2 -#define QLCNIC_H2C_OPCODE_CONFIG_INTR_COALESCE 3 -#define QLCNIC_H2C_OPCODE_CONFIG_LED 4 -#define QLCNIC_H2C_OPCODE_CONFIG_PROMISCUOUS 5 -#define QLCNIC_H2C_OPCODE_CONFIG_L2_MAC 6 -#define QLCNIC_H2C_OPCODE_LRO_REQUEST 7 -#define QLCNIC_H2C_OPCODE_GET_SNMP_STATS 8 -#define QLCNIC_H2C_OPCODE_PROXY_START_REQUEST 9 -#define QLCNIC_H2C_OPCODE_PROXY_STOP_REQUEST 10 -#define QLCNIC_H2C_OPCODE_PROXY_SET_MTU 11 -#define QLCNIC_H2C_OPCODE_PROXY_SET_VPORT_MISS_MODE 12 -#define QLCNIC_H2C_OPCODE_GET_FINGER_PRINT_REQUEST 13 -#define QLCNIC_H2C_OPCODE_INSTALL_LICENSE_REQUEST 14 -#define QLCNIC_H2C_OPCODE_GET_LICENSE_CAPABILITY_REQUEST 15 -#define QLCNIC_H2C_OPCODE_GET_NET_STATS 16 -#define QLCNIC_H2C_OPCODE_PROXY_UPDATE_P2V 17 -#define QLCNIC_H2C_OPCODE_CONFIG_IPADDR 18 -#define QLCNIC_H2C_OPCODE_PROXY_STOP_DONE 20 -#define QLCNIC_H2C_OPCODE_GET_LINKEVENT 21 -#define QLCNIC_C2C_OPCODE 22 -#define QLCNIC_H2C_OPCODE_CONFIG_BRIDGING 23 -#define QLCNIC_H2C_OPCODE_CONFIG_HW_LRO 24 -#define QLCNIC_H2C_OPCODE_LAST 25 +#define QLCNIC_H2C_OPCODE_CONFIG_RSS 0x1 +#define QLCNIC_H2C_OPCODE_CONFIG_INTR_COALESCE 0x3 +#define QLCNIC_H2C_OPCODE_CONFIG_LED 0x4 +#define QLCNIC_H2C_OPCODE_LRO_REQUEST 0x7 +#define QLCNIC_H2C_OPCODE_SET_MAC_RECEIVE_MODE 0xc +#define QLCNIC_H2C_OPCODE_CONFIG_IPADDR 0x12 +#define QLCNIC_H2C_OPCODE_GET_LINKEVENT 0x15 +#define QLCNIC_H2C_OPCODE_CONFIG_BRIDGING 0x17 +#define QLCNIC_H2C_OPCODE_CONFIG_HW_LRO 0x18 /* * Firmware --> Driver */ -#define QLCNIC_C2H_OPCODE_START 128 -#define QLCNIC_C2H_OPCODE_CONFIG_RSS_RESPONSE 129 -#define QLCNIC_C2H_OPCODE_CONFIG_RSS_TBL_RESPONSE 130 -#define QLCNIC_C2H_OPCODE_CONFIG_MAC_RESPONSE 131 -#define QLCNIC_C2H_OPCODE_CONFIG_PROMISCUOUS_RESPONSE 132 -#define QLCNIC_C2H_OPCODE_CONFIG_L2_MAC_RESPONSE 133 -#define QLCNIC_C2H_OPCODE_LRO_DELETE_RESPONSE 134 -#define QLCNIC_C2H_OPCODE_LRO_ADD_FAILURE_RESPONSE 135 -#define QLCNIC_C2H_OPCODE_GET_SNMP_STATS 136 -#define QLCNIC_C2H_OPCODE_GET_FINGER_PRINT_REPLY 137 -#define QLCNIC_C2H_OPCODE_INSTALL_LICENSE_REPLY 138 -#define QLCNIC_C2H_OPCODE_GET_LICENSE_CAPABILITIES_REPLY 139 -#define QLCNIC_C2H_OPCODE_GET_NET_STATS_RESPONSE 140 #define QLCNIC_C2H_OPCODE_GET_LINKEVENT_RESPONSE 141 -#define QLCNIC_C2H_OPCODE_LAST 142 #define VPORT_MISS_MODE_DROP 0 /* drop all unmatched */ #define VPORT_MISS_MODE_ACCEPT_ALL 1 /* accept all packets */ @@ -894,7 +847,7 @@ struct qlcnic_nic_req { __le64 qhdr; __le64 req_hdr; __le64 words[6]; -}; +} __packed; struct qlcnic_mac_req { u8 op; @@ -905,7 +858,7 @@ struct qlcnic_mac_req { struct qlcnic_vlan_req { __le16 vlan_id; __le16 rsvd[3]; -}; +} __packed; struct qlcnic_ipaddr { __be32 ipv4; @@ -964,14 +917,14 @@ struct qlcnic_filter_hash { }; struct qlcnic_adapter { - struct qlcnic_hardware_context ahw; - + struct qlcnic_hardware_context *ahw; + struct qlcnic_recv_context *recv_ctx; + struct qlcnic_host_tx_ring *tx_ring; struct net_device *netdev; struct pci_dev *pdev; - struct list_head mac_list; - spinlock_t tx_clean_lock; - spinlock_t mac_learn_lock; + unsigned long state; + u32 flags; u16 num_txd; u16 num_rxd; @@ -989,7 +942,6 @@ struct qlcnic_adapter { u8 mc_enabled; u8 max_mc_count; - u8 rss_supported; u8 fw_wait_cnt; u8 fw_fail_cnt; u8 tx_timeo_cnt; @@ -1014,7 +966,6 @@ struct qlcnic_adapter { u32 fw_hal_version; u32 capabilities; - u32 flags; u32 irq; u32 temp; @@ -1039,9 +990,7 @@ struct qlcnic_adapter { struct qlcnic_nic_template *nic_ops; struct qlcnic_adapter_stats stats; - - struct qlcnic_recv_context recv_ctx; - struct qlcnic_host_tx_ring *tx_ring; + struct list_head mac_list; void __iomem *tgt_mask_reg; void __iomem *tgt_status_reg; @@ -1056,7 +1005,8 @@ struct qlcnic_adapter { struct qlcnic_filter_hash fhash; - unsigned long state; + spinlock_t tx_clean_lock; + spinlock_t mac_learn_lock; __le32 file_prd_off; /*File fw product offset*/ u32 fw_version; const struct firmware *fw; @@ -1078,7 +1028,7 @@ struct qlcnic_info { __le16 min_tx_bw; __le16 max_tx_bw; u8 reserved2[104]; -}; +} __packed; struct qlcnic_pci_info { __le16 id; /* pci function id */ @@ -1092,7 +1042,7 @@ struct qlcnic_pci_info { u8 mac[ETH_ALEN]; u8 reserved2[106]; -}; +} __packed; struct qlcnic_npar_info { u16 pvid; @@ -1209,7 +1159,7 @@ struct __qlcnic_esw_statistics { __le64 local_frames; __le64 numbytes; __le64 rsvd[3]; -}; +} __packed; struct qlcnic_esw_statistics { struct __qlcnic_esw_statistics rx; @@ -1293,7 +1243,7 @@ void qlcnic_release_tx_buffers(struct qlcnic_adapter *adapter); int qlcnic_check_fw_status(struct qlcnic_adapter *adapter); void qlcnic_watchdog_task(struct work_struct *work); -void qlcnic_post_rx_buffers(struct qlcnic_adapter *adapter, u32 ringid, +void qlcnic_post_rx_buffers(struct qlcnic_adapter *adapter, struct qlcnic_host_rds_ring *rds_ring); int qlcnic_process_rcv_ring(struct qlcnic_host_sds_ring *sds_ring, int max); void qlcnic_set_multi(struct net_device *netdev); diff --git a/drivers/net/qlcnic/qlcnic_ctx.c b/drivers/net/qlcnic/qlcnic_ctx.c index 27631f2..050fa5a 100644 --- a/drivers/net/qlcnic/qlcnic_ctx.c +++ b/drivers/net/qlcnic/qlcnic_ctx.c @@ -67,11 +67,11 @@ qlcnic_issue_cmd(struct qlcnic_adapter *adapter, int qlcnic_fw_cmd_set_mtu(struct qlcnic_adapter *adapter, int mtu) { - struct qlcnic_recv_context *recv_ctx = &adapter->recv_ctx; + struct qlcnic_recv_context *recv_ctx = adapter->recv_ctx; if (recv_ctx->state == QLCNIC_HOST_CTX_STATE_ACTIVE) { if (qlcnic_issue_cmd(adapter, - adapter->ahw.pci_func, + adapter->ahw->pci_func, adapter->fw_hal_version, recv_ctx->context_id, mtu, @@ -102,12 +102,12 @@ qlcnic_fw_cmd_create_rx_ctx(struct qlcnic_adapter *adapter) dma_addr_t hostrq_phys_addr, cardrsp_phys_addr; u64 phys_addr; - int i, nrds_rings, nsds_rings; + u8 i, nrds_rings, nsds_rings; size_t rq_size, rsp_size; u32 cap, reg, val, reg2; int err; - struct qlcnic_recv_context *recv_ctx = &adapter->recv_ctx; + struct qlcnic_recv_context *recv_ctx = adapter->recv_ctx; nrds_rings = adapter->max_rds_rings; nsds_rings = adapter->max_sds_rings; @@ -119,14 +119,14 @@ qlcnic_fw_cmd_create_rx_ctx(struct qlcnic_adapter *adapter) SIZEOF_CARDRSP_RX(struct qlcnic_cardrsp_rx_ctx, nrds_rings, nsds_rings); - addr = pci_alloc_consistent(adapter->pdev, - rq_size, &hostrq_phys_addr); + addr = dma_alloc_coherent(&adapter->pdev->dev, rq_size, + &hostrq_phys_addr, GFP_KERNEL); if (addr == NULL) return -ENOMEM; prq = (struct qlcnic_hostrq_rx_ctx *)addr; - addr = pci_alloc_consistent(adapter->pdev, - rsp_size, &cardrsp_phys_addr); + addr = dma_alloc_coherent(&adapter->pdev->dev, rsp_size, + &cardrsp_phys_addr, GFP_KERNEL); if (addr == NULL) { err = -ENOMEM; goto out_free_rq; @@ -151,7 +151,7 @@ qlcnic_fw_cmd_create_rx_ctx(struct qlcnic_adapter *adapter) prq->num_rds_rings = cpu_to_le16(nrds_rings); prq->num_sds_rings = cpu_to_le16(nsds_rings); - prq->rds_ring_offset = cpu_to_le32(0); + prq->rds_ring_offset = 0; val = le32_to_cpu(prq->rds_ring_offset) + (sizeof(struct qlcnic_hostrq_rds_ring) * nrds_rings); @@ -187,7 +187,7 @@ qlcnic_fw_cmd_create_rx_ctx(struct qlcnic_adapter *adapter) phys_addr = hostrq_phys_addr; err = qlcnic_issue_cmd(adapter, - adapter->ahw.pci_func, + adapter->ahw->pci_func, adapter->fw_hal_version, (u32)(phys_addr >> 32), (u32)(phys_addr & 0xffffffff), @@ -207,7 +207,7 @@ qlcnic_fw_cmd_create_rx_ctx(struct qlcnic_adapter *adapter) rds_ring = &recv_ctx->rds_rings[i]; reg = le32_to_cpu(prsp_rds[i].host_producer_crb); - rds_ring->crb_rcv_producer = adapter->ahw.pci_base0 + reg; + rds_ring->crb_rcv_producer = adapter->ahw->pci_base0 + reg; } prsp_sds = ((struct qlcnic_cardrsp_sds_ring *) @@ -219,8 +219,8 @@ qlcnic_fw_cmd_create_rx_ctx(struct qlcnic_adapter *adapter) reg = le32_to_cpu(prsp_sds[i].host_consumer_crb); reg2 = le32_to_cpu(prsp_sds[i].interrupt_crb); - sds_ring->crb_sts_consumer = adapter->ahw.pci_base0 + reg; - sds_ring->crb_intr_mask = adapter->ahw.pci_base0 + reg2; + sds_ring->crb_sts_consumer = adapter->ahw->pci_base0 + reg; + sds_ring->crb_intr_mask = adapter->ahw->pci_base0 + reg2; } recv_ctx->state = le32_to_cpu(prsp->host_ctx_state); @@ -228,19 +228,20 @@ qlcnic_fw_cmd_create_rx_ctx(struct qlcnic_adapter *adapter) recv_ctx->virt_port = prsp->virt_port; out_free_rsp: - pci_free_consistent(adapter->pdev, rsp_size, prsp, cardrsp_phys_addr); + dma_free_coherent(&adapter->pdev->dev, rsp_size, prsp, + cardrsp_phys_addr); out_free_rq: - pci_free_consistent(adapter->pdev, rq_size, prq, hostrq_phys_addr); + dma_free_coherent(&adapter->pdev->dev, rq_size, prq, hostrq_phys_addr); return err; } static void qlcnic_fw_cmd_destroy_rx_ctx(struct qlcnic_adapter *adapter) { - struct qlcnic_recv_context *recv_ctx = &adapter->recv_ctx; + struct qlcnic_recv_context *recv_ctx = adapter->recv_ctx; if (qlcnic_issue_cmd(adapter, - adapter->ahw.pci_func, + adapter->ahw->pci_func, adapter->fw_hal_version, recv_ctx->context_id, QLCNIC_DESTROY_CTX_RESET, @@ -274,14 +275,14 @@ qlcnic_fw_cmd_create_tx_ctx(struct qlcnic_adapter *adapter) *(tx_ring->hw_consumer) = 0; rq_size = SIZEOF_HOSTRQ_TX(struct qlcnic_hostrq_tx_ctx); - rq_addr = pci_alloc_consistent(adapter->pdev, - rq_size, &rq_phys_addr); + rq_addr = dma_alloc_coherent(&adapter->pdev->dev, rq_size, + &rq_phys_addr, GFP_KERNEL); if (!rq_addr) return -ENOMEM; rsp_size = SIZEOF_CARDRSP_TX(struct qlcnic_cardrsp_tx_ctx); - rsp_addr = pci_alloc_consistent(adapter->pdev, - rsp_size, &rsp_phys_addr); + rsp_addr = dma_alloc_coherent(&adapter->pdev->dev, rsp_size, + &rsp_phys_addr, GFP_KERNEL); if (!rsp_addr) { err = -ENOMEM; goto out_free_rq; @@ -313,7 +314,7 @@ qlcnic_fw_cmd_create_tx_ctx(struct qlcnic_adapter *adapter) phys_addr = rq_phys_addr; err = qlcnic_issue_cmd(adapter, - adapter->ahw.pci_func, + adapter->ahw->pci_func, adapter->fw_hal_version, (u32)(phys_addr >> 32), ((u32)phys_addr & 0xffffffff), @@ -322,7 +323,7 @@ qlcnic_fw_cmd_create_tx_ctx(struct qlcnic_adapter *adapter) if (err == QLCNIC_RCODE_SUCCESS) { temp = le32_to_cpu(prsp->cds_ring.host_producer_crb); - tx_ring->crb_cmd_producer = adapter->ahw.pci_base0 + temp; + tx_ring->crb_cmd_producer = adapter->ahw->pci_base0 + temp; adapter->tx_context_id = le16_to_cpu(prsp->context_id); @@ -332,10 +333,11 @@ qlcnic_fw_cmd_create_tx_ctx(struct qlcnic_adapter *adapter) err = -EIO; } - pci_free_consistent(adapter->pdev, rsp_size, rsp_addr, rsp_phys_addr); + dma_free_coherent(&adapter->pdev->dev, rsp_size, rsp_addr, + rsp_phys_addr); out_free_rq: - pci_free_consistent(adapter->pdev, rq_size, rq_addr, rq_phys_addr); + dma_free_coherent(&adapter->pdev->dev, rq_size, rq_addr, rq_phys_addr); return err; } @@ -344,7 +346,7 @@ static void qlcnic_fw_cmd_destroy_tx_ctx(struct qlcnic_adapter *adapter) { if (qlcnic_issue_cmd(adapter, - adapter->ahw.pci_func, + adapter->ahw->pci_func, adapter->fw_hal_version, adapter->tx_context_id, QLCNIC_DESTROY_CTX_RESET, @@ -361,7 +363,7 @@ qlcnic_fw_cmd_query_phy(struct qlcnic_adapter *adapter, u32 reg, u32 *val) { if (qlcnic_issue_cmd(adapter, - adapter->ahw.pci_func, + adapter->ahw->pci_func, adapter->fw_hal_version, reg, 0, @@ -378,7 +380,7 @@ int qlcnic_fw_cmd_set_phy(struct qlcnic_adapter *adapter, u32 reg, u32 val) { return qlcnic_issue_cmd(adapter, - adapter->ahw.pci_func, + adapter->ahw->pci_func, adapter->fw_hal_version, reg, val, @@ -398,20 +400,19 @@ int qlcnic_alloc_hw_resources(struct qlcnic_adapter *adapter) struct pci_dev *pdev = adapter->pdev; - recv_ctx = &adapter->recv_ctx; + recv_ctx = adapter->recv_ctx; tx_ring = adapter->tx_ring; - tx_ring->hw_consumer = (__le32 *)pci_alloc_consistent(pdev, sizeof(u32), - &tx_ring->hw_cons_phys_addr); + tx_ring->hw_consumer = (__le32 *) dma_alloc_coherent(&pdev->dev, + sizeof(u32), &tx_ring->hw_cons_phys_addr, GFP_KERNEL); if (tx_ring->hw_consumer == NULL) { dev_err(&pdev->dev, "failed to allocate tx consumer\n"); return -ENOMEM; } - *(tx_ring->hw_consumer) = 0; /* cmd desc ring */ - addr = pci_alloc_consistent(pdev, TX_DESC_RINGSIZE(tx_ring), - &tx_ring->phys_addr); + addr = dma_alloc_coherent(&pdev->dev, TX_DESC_RINGSIZE(tx_ring), + &tx_ring->phys_addr, GFP_KERNEL); if (addr == NULL) { dev_err(&pdev->dev, "failed to allocate tx desc ring\n"); @@ -423,9 +424,9 @@ int qlcnic_alloc_hw_resources(struct qlcnic_adapter *adapter) for (ring = 0; ring < adapter->max_rds_rings; ring++) { rds_ring = &recv_ctx->rds_rings[ring]; - addr = pci_alloc_consistent(adapter->pdev, + addr = dma_alloc_coherent(&adapter->pdev->dev, RCV_DESC_RINGSIZE(rds_ring), - &rds_ring->phys_addr); + &rds_ring->phys_addr, GFP_KERNEL); if (addr == NULL) { dev_err(&pdev->dev, "failed to allocate rds ring [%d]\n", ring); @@ -439,9 +440,9 @@ int qlcnic_alloc_hw_resources(struct qlcnic_adapter *adapter) for (ring = 0; ring < adapter->max_sds_rings; ring++) { sds_ring = &recv_ctx->sds_rings[ring]; - addr = pci_alloc_consistent(adapter->pdev, + addr = dma_alloc_coherent(&adapter->pdev->dev, STATUS_DESC_RINGSIZE(sds_ring), - &sds_ring->phys_addr); + &sds_ring->phys_addr, GFP_KERNEL); if (addr == NULL) { dev_err(&pdev->dev, "failed to allocate sds ring [%d]\n", ring); @@ -501,11 +502,11 @@ void qlcnic_free_hw_resources(struct qlcnic_adapter *adapter) struct qlcnic_host_tx_ring *tx_ring; int ring; - recv_ctx = &adapter->recv_ctx; + recv_ctx = adapter->recv_ctx; tx_ring = adapter->tx_ring; if (tx_ring->hw_consumer != NULL) { - pci_free_consistent(adapter->pdev, + dma_free_coherent(&adapter->pdev->dev, sizeof(u32), tx_ring->hw_consumer, tx_ring->hw_cons_phys_addr); @@ -513,7 +514,7 @@ void qlcnic_free_hw_resources(struct qlcnic_adapter *adapter) } if (tx_ring->desc_head != NULL) { - pci_free_consistent(adapter->pdev, + dma_free_coherent(&adapter->pdev->dev, TX_DESC_RINGSIZE(tx_ring), tx_ring->desc_head, tx_ring->phys_addr); tx_ring->desc_head = NULL; @@ -523,7 +524,7 @@ void qlcnic_free_hw_resources(struct qlcnic_adapter *adapter) rds_ring = &recv_ctx->rds_rings[ring]; if (rds_ring->desc_head != NULL) { - pci_free_consistent(adapter->pdev, + dma_free_coherent(&adapter->pdev->dev, RCV_DESC_RINGSIZE(rds_ring), rds_ring->desc_head, rds_ring->phys_addr); @@ -535,7 +536,7 @@ void qlcnic_free_hw_resources(struct qlcnic_adapter *adapter) sds_ring = &recv_ctx->sds_rings[ring]; if (sds_ring->desc_head != NULL) { - pci_free_consistent(adapter->pdev, + dma_free_coherent(&adapter->pdev->dev, STATUS_DESC_RINGSIZE(sds_ring), sds_ring->desc_head, sds_ring->phys_addr); @@ -551,9 +552,9 @@ int qlcnic_get_mac_address(struct qlcnic_adapter *adapter, u8 *mac) int err; u32 arg1; - arg1 = adapter->ahw.pci_func | BIT_8; + arg1 = adapter->ahw->pci_func | BIT_8; err = qlcnic_issue_cmd(adapter, - adapter->ahw.pci_func, + adapter->ahw->pci_func, adapter->fw_hal_version, arg1, 0, @@ -582,15 +583,15 @@ int qlcnic_get_nic_info(struct qlcnic_adapter *adapter, void *nic_info_addr; size_t nic_size = sizeof(struct qlcnic_info); - nic_info_addr = pci_alloc_consistent(adapter->pdev, - nic_size, &nic_dma_t); + nic_info_addr = dma_alloc_coherent(&adapter->pdev->dev, nic_size, + &nic_dma_t, GFP_KERNEL); if (!nic_info_addr) return -ENOMEM; memset(nic_info_addr, 0, nic_size); nic_info = (struct qlcnic_info *) nic_info_addr; err = qlcnic_issue_cmd(adapter, - adapter->ahw.pci_func, + adapter->ahw->pci_func, adapter->fw_hal_version, MSD(nic_dma_t), LSD(nic_dma_t), @@ -623,7 +624,8 @@ int qlcnic_get_nic_info(struct qlcnic_adapter *adapter, err = -EIO; } - pci_free_consistent(adapter->pdev, nic_size, nic_info_addr, nic_dma_t); + dma_free_coherent(&adapter->pdev->dev, nic_size, nic_info_addr, + nic_dma_t); return err; } @@ -639,8 +641,8 @@ int qlcnic_set_nic_info(struct qlcnic_adapter *adapter, struct qlcnic_info *nic) if (adapter->op_mode != QLCNIC_MGMT_FUNC) return err; - nic_info_addr = pci_alloc_consistent(adapter->pdev, nic_size, - &nic_dma_t); + nic_info_addr = dma_alloc_coherent(&adapter->pdev->dev, nic_size, + &nic_dma_t, GFP_KERNEL); if (!nic_info_addr) return -ENOMEM; @@ -659,7 +661,7 @@ int qlcnic_set_nic_info(struct qlcnic_adapter *adapter, struct qlcnic_info *nic) nic_info->max_tx_bw = cpu_to_le16(nic->max_tx_bw); err = qlcnic_issue_cmd(adapter, - adapter->ahw.pci_func, + adapter->ahw->pci_func, adapter->fw_hal_version, MSD(nic_dma_t), LSD(nic_dma_t), @@ -672,7 +674,8 @@ int qlcnic_set_nic_info(struct qlcnic_adapter *adapter, struct qlcnic_info *nic) err = -EIO; } - pci_free_consistent(adapter->pdev, nic_size, nic_info_addr, nic_dma_t); + dma_free_coherent(&adapter->pdev->dev, nic_size, nic_info_addr, + nic_dma_t); return err; } @@ -687,15 +690,15 @@ int qlcnic_get_pci_info(struct qlcnic_adapter *adapter, size_t npar_size = sizeof(struct qlcnic_pci_info); size_t pci_size = npar_size * QLCNIC_MAX_PCI_FUNC; - pci_info_addr = pci_alloc_consistent(adapter->pdev, pci_size, - &pci_info_dma_t); + pci_info_addr = dma_alloc_coherent(&adapter->pdev->dev, pci_size, + &pci_info_dma_t, GFP_KERNEL); if (!pci_info_addr) return -ENOMEM; memset(pci_info_addr, 0, pci_size); npar = (struct qlcnic_pci_info *) pci_info_addr; err = qlcnic_issue_cmd(adapter, - adapter->ahw.pci_func, + adapter->ahw->pci_func, adapter->fw_hal_version, MSD(pci_info_dma_t), LSD(pci_info_dma_t), @@ -721,7 +724,7 @@ int qlcnic_get_pci_info(struct qlcnic_adapter *adapter, err = -EIO; } - pci_free_consistent(adapter->pdev, pci_size, pci_info_addr, + dma_free_coherent(&adapter->pdev->dev, pci_size, pci_info_addr, pci_info_dma_t); return err; } @@ -741,7 +744,7 @@ int qlcnic_config_port_mirroring(struct qlcnic_adapter *adapter, u8 id, arg1 |= pci_func << 8; err = qlcnic_issue_cmd(adapter, - adapter->ahw.pci_func, + adapter->ahw->pci_func, adapter->fw_hal_version, arg1, 0, @@ -775,14 +778,14 @@ int qlcnic_get_port_stats(struct qlcnic_adapter *adapter, const u8 func, return -ENOMEM; if (adapter->op_mode != QLCNIC_MGMT_FUNC && - func != adapter->ahw.pci_func) { + func != adapter->ahw->pci_func) { dev_err(&adapter->pdev->dev, "Not privilege to query stats for func=%d", func); return -EIO; } - stats_addr = pci_alloc_consistent(adapter->pdev, stats_size, - &stats_dma_t); + stats_addr = dma_alloc_coherent(&adapter->pdev->dev, stats_size, + &stats_dma_t, GFP_KERNEL); if (!stats_addr) { dev_err(&adapter->pdev->dev, "Unable to allocate memory\n"); return -ENOMEM; @@ -793,7 +796,7 @@ int qlcnic_get_port_stats(struct qlcnic_adapter *adapter, const u8 func, arg1 |= rx_tx << 15 | stats_size << 16; err = qlcnic_issue_cmd(adapter, - adapter->ahw.pci_func, + adapter->ahw->pci_func, adapter->fw_hal_version, arg1, MSD(stats_dma_t), @@ -816,7 +819,7 @@ int qlcnic_get_port_stats(struct qlcnic_adapter *adapter, const u8 func, esw_stats->numbytes = le64_to_cpu(stats->numbytes); } - pci_free_consistent(adapter->pdev, stats_size, stats_addr, + dma_free_coherent(&adapter->pdev->dev, stats_size, stats_addr, stats_dma_t); return err; } @@ -900,7 +903,7 @@ int qlcnic_clear_esw_stats(struct qlcnic_adapter *adapter, const u8 func_esw, arg1 |= BIT_14 | rx_tx << 15; return qlcnic_issue_cmd(adapter, - adapter->ahw.pci_func, + adapter->ahw->pci_func, adapter->fw_hal_version, arg1, 0, @@ -921,7 +924,7 @@ __qlcnic_get_eswitch_port_config(struct qlcnic_adapter *adapter, u8 pci_func; pci_func = (*arg1 >> 8); err = qlcnic_issue_cmd(adapter, - adapter->ahw.pci_func, + adapter->ahw->pci_func, adapter->fw_hal_version, *arg1, 0, @@ -999,7 +1002,7 @@ int qlcnic_config_switch_port(struct qlcnic_adapter *adapter, } err = qlcnic_issue_cmd(adapter, - adapter->ahw.pci_func, + adapter->ahw->pci_func, adapter->fw_hal_version, arg1, arg2, diff --git a/drivers/net/qlcnic/qlcnic_ethtool.c b/drivers/net/qlcnic/qlcnic_ethtool.c index 45b2755..7e53cad 100644 --- a/drivers/net/qlcnic/qlcnic_ethtool.c +++ b/drivers/net/qlcnic/qlcnic_ethtool.c @@ -150,10 +150,10 @@ qlcnic_get_settings(struct net_device *dev, struct ethtool_cmd *ecmd) { struct qlcnic_adapter *adapter = netdev_priv(dev); int check_sfp_module = 0; - u16 pcifn = adapter->ahw.pci_func; + u16 pcifn = adapter->ahw->pci_func; /* read which mode */ - if (adapter->ahw.port_type == QLCNIC_GBE) { + if (adapter->ahw->port_type == QLCNIC_GBE) { ecmd->supported = (SUPPORTED_10baseT_Half | SUPPORTED_10baseT_Full | SUPPORTED_100baseT_Half | @@ -170,7 +170,7 @@ qlcnic_get_settings(struct net_device *dev, struct ethtool_cmd *ecmd) ecmd->duplex = adapter->link_duplex; ecmd->autoneg = adapter->link_autoneg; - } else if (adapter->ahw.port_type == QLCNIC_XGBE) { + } else if (adapter->ahw->port_type == QLCNIC_XGBE) { u32 val; val = QLCRD32(adapter, QLCNIC_PORT_MODE_ADDR); @@ -201,7 +201,7 @@ skip: ecmd->phy_address = adapter->physical_port; ecmd->transceiver = XCVR_EXTERNAL; - switch (adapter->ahw.board_type) { + switch (adapter->ahw->board_type) { case QLCNIC_BRDTYPE_P3P_REF_QG: case QLCNIC_BRDTYPE_P3P_4_GB: case QLCNIC_BRDTYPE_P3P_4_GB_MM: @@ -238,7 +238,7 @@ skip: ecmd->autoneg = AUTONEG_DISABLE; break; case QLCNIC_BRDTYPE_P3P_10G_TP: - if (adapter->ahw.port_type == QLCNIC_XGBE) { + if (adapter->ahw->port_type == QLCNIC_XGBE) { ecmd->autoneg = AUTONEG_DISABLE; ecmd->supported |= (SUPPORTED_FIBRE | SUPPORTED_TP); ecmd->advertising |= @@ -256,7 +256,7 @@ skip: break; default: dev_err(&adapter->pdev->dev, "Unsupported board model %d\n", - adapter->ahw.board_type); + adapter->ahw->board_type); return -EIO; } @@ -288,7 +288,7 @@ qlcnic_set_settings(struct net_device *dev, struct ethtool_cmd *ecmd) __u32 status; /* read which mode */ - if (adapter->ahw.port_type == QLCNIC_GBE) { + if (adapter->ahw->port_type == QLCNIC_GBE) { /* autonegotiation */ if (qlcnic_fw_cmd_set_phy(adapter, QLCNIC_NIU_GB_MII_MGMT_ADDR_AUTONEG, @@ -340,14 +340,14 @@ static void qlcnic_get_regs(struct net_device *dev, struct ethtool_regs *regs, void *p) { struct qlcnic_adapter *adapter = netdev_priv(dev); - struct qlcnic_recv_context *recv_ctx = &adapter->recv_ctx; + struct qlcnic_recv_context *recv_ctx = adapter->recv_ctx; struct qlcnic_host_sds_ring *sds_ring; u32 *regs_buff = p; int ring, i = 0, j = 0; memset(p, 0, qlcnic_get_regs_len(dev)); regs->version = (QLCNIC_ETHTOOL_REGS_VER << 24) | - (adapter->ahw.revision_id << 16) | (adapter->pdev)->device; + (adapter->ahw->revision_id << 16) | (adapter->pdev)->device; regs_buff[0] = (0xcafe0000 | (QLCNIC_DEV_INFO_SIZE & 0xffff)); regs_buff[1] = QLCNIC_MGMT_API_VERSION; @@ -382,7 +382,7 @@ static u32 qlcnic_test_link(struct net_device *dev) u32 val; val = QLCRD32(adapter, CRB_XG_STATE_P3P); - val = XG_LINK_STATE_P3P(adapter->ahw.pci_func, val); + val = XG_LINK_STATE_P3P(adapter->ahw->pci_func, val); return (val == XG_LINK_UP_P3P) ? 0 : 1; } @@ -482,7 +482,7 @@ qlcnic_get_pauseparam(struct net_device *netdev, int port = adapter->physical_port; __u32 val; - if (adapter->ahw.port_type == QLCNIC_GBE) { + if (adapter->ahw->port_type == QLCNIC_GBE) { if ((port < 0) || (port > QLCNIC_NIU_MAX_GBE_PORTS)) return; /* get flow control settings */ @@ -504,7 +504,7 @@ qlcnic_get_pauseparam(struct net_device *netdev, pause->tx_pause = !(qlcnic_gb_get_gb3_mask(val)); break; } - } else if (adapter->ahw.port_type == QLCNIC_XGBE) { + } else if (adapter->ahw->port_type == QLCNIC_XGBE) { if ((port < 0) || (port > QLCNIC_NIU_MAX_XG_PORTS)) return; pause->rx_pause = 1; @@ -515,7 +515,7 @@ qlcnic_get_pauseparam(struct net_device *netdev, pause->tx_pause = !(qlcnic_xg_get_xg1_mask(val)); } else { dev_err(&netdev->dev, "Unknown board type: %x\n", - adapter->ahw.port_type); + adapter->ahw->port_type); } } @@ -528,7 +528,7 @@ qlcnic_set_pauseparam(struct net_device *netdev, __u32 val; /* read mode */ - if (adapter->ahw.port_type == QLCNIC_GBE) { + if (adapter->ahw->port_type == QLCNIC_GBE) { if ((port < 0) || (port > QLCNIC_NIU_MAX_GBE_PORTS)) return -EIO; /* set flow control */ @@ -571,7 +571,7 @@ qlcnic_set_pauseparam(struct net_device *netdev, break; } QLCWR32(adapter, QLCNIC_NIU_GB_PAUSE_CTL, val); - } else if (adapter->ahw.port_type == QLCNIC_XGBE) { + } else if (adapter->ahw->port_type == QLCNIC_XGBE) { if (!pause->rx_pause || pause->autoneg) return -EOPNOTSUPP; @@ -593,7 +593,7 @@ qlcnic_set_pauseparam(struct net_device *netdev, QLCWR32(adapter, QLCNIC_NIU_XG_PAUSE_CTL, val); } else { dev_err(&netdev->dev, "Unknown board type: %x\n", - adapter->ahw.port_type); + adapter->ahw->port_type); } return 0; } @@ -639,8 +639,8 @@ static int qlcnic_irq_test(struct net_device *netdev) goto clear_it; adapter->diag_cnt = 0; - ret = qlcnic_issue_cmd(adapter, adapter->ahw.pci_func, - adapter->fw_hal_version, adapter->portnum, + ret = qlcnic_issue_cmd(adapter, adapter->ahw->pci_func, + adapter->fw_hal_version, adapter->ahw->pci_func, 0, 0, 0x00000011); if (ret) goto done; @@ -749,14 +749,14 @@ qlcnic_get_ethtool_stats(struct net_device *dev, return; memset(&port_stats, 0, sizeof(struct qlcnic_esw_statistics)); - ret = qlcnic_get_port_stats(adapter, adapter->ahw.pci_func, + ret = qlcnic_get_port_stats(adapter, adapter->ahw->pci_func, QLCNIC_QUERY_RX_COUNTER, &port_stats.rx); if (ret) return; qlcnic_fill_device_stats(&index, data, &port_stats.rx); - ret = qlcnic_get_port_stats(adapter, adapter->ahw.pci_func, + ret = qlcnic_get_port_stats(adapter, adapter->ahw->pci_func, QLCNIC_QUERY_TX_COUNTER, &port_stats.tx); if (ret) return; diff --git a/drivers/net/qlcnic/qlcnic_hw.c b/drivers/net/qlcnic/qlcnic_hw.c index 616940f..7e3f526 100644 --- a/drivers/net/qlcnic/qlcnic_hw.c +++ b/drivers/net/qlcnic/qlcnic_hw.c @@ -457,7 +457,7 @@ int qlcnic_nic_set_promisc(struct qlcnic_adapter *adapter, u32 mode) req.qhdr = cpu_to_le64(QLCNIC_HOST_REQUEST << 23); - word = QLCNIC_H2C_OPCODE_PROXY_SET_VPORT_MISS_MODE | + word = QLCNIC_H2C_OPCODE_SET_MAC_RECEIVE_MODE | ((u64)adapter->portnum << 16); req.req_hdr = cpu_to_le64(word); @@ -780,7 +780,7 @@ qlcnic_pci_get_crb_addr_2M(struct qlcnic_adapter *adapter, m = &crb_128M_2M_map[CRB_BLK(off)].sub_block[CRB_SUBBLK(off)]; if (m->valid && (m->start_128M <= off) && (m->end_128M > off)) { - *addr = adapter->ahw.pci_base0 + m->start_2M + + *addr = adapter->ahw->pci_base0 + m->start_2M + (off - m->start_128M); return 0; } @@ -788,7 +788,7 @@ qlcnic_pci_get_crb_addr_2M(struct qlcnic_adapter *adapter, /* * Not in direct map, use crb window */ - *addr = adapter->ahw.pci_base0 + CRB_INDIRECT_2M + (off & MASK(16)); + *addr = adapter->ahw->pci_base0 + CRB_INDIRECT_2M + (off & MASK(16)); return 1; } @@ -801,7 +801,7 @@ static int qlcnic_pci_set_crbwindow_2M(struct qlcnic_adapter *adapter, ulong off) { u32 window; - void __iomem *addr = adapter->ahw.pci_base0 + CRB_WINDOW_2M; + void __iomem *addr = adapter->ahw->pci_base0 + CRB_WINDOW_2M; off -= QLCNIC_PCI_CRBSPACE; @@ -838,13 +838,13 @@ qlcnic_hw_write_wx_2M(struct qlcnic_adapter *adapter, ulong off, u32 data) if (rv > 0) { /* indirect access */ - write_lock_irqsave(&adapter->ahw.crb_lock, flags); + write_lock_irqsave(&adapter->ahw->crb_lock, flags); crb_win_lock(adapter); rv = qlcnic_pci_set_crbwindow_2M(adapter, off); if (!rv) writel(data, addr); crb_win_unlock(adapter); - write_unlock_irqrestore(&adapter->ahw.crb_lock, flags); + write_unlock_irqrestore(&adapter->ahw->crb_lock, flags); return rv; } @@ -869,12 +869,12 @@ qlcnic_hw_read_wx_2M(struct qlcnic_adapter *adapter, ulong off) if (rv > 0) { /* indirect access */ - write_lock_irqsave(&adapter->ahw.crb_lock, flags); + write_lock_irqsave(&adapter->ahw->crb_lock, flags); crb_win_lock(adapter); if (!qlcnic_pci_set_crbwindow_2M(adapter, off)) data = readl(addr); crb_win_unlock(adapter); - write_unlock_irqrestore(&adapter->ahw.crb_lock, flags); + write_unlock_irqrestore(&adapter->ahw->crb_lock, flags); return data; } @@ -904,9 +904,9 @@ qlcnic_pci_set_window_2M(struct qlcnic_adapter *adapter, window = OCM_WIN_P3P(addr); - writel(window, adapter->ahw.ocm_win_crb); + writel(window, adapter->ahw->ocm_win_crb); /* read back to flush */ - readl(adapter->ahw.ocm_win_crb); + readl(adapter->ahw->ocm_win_crb); *start = QLCNIC_PCI_OCM0_2M + GET_MEM_OFFS_2M(addr); return 0; @@ -920,13 +920,13 @@ qlcnic_pci_mem_access_direct(struct qlcnic_adapter *adapter, u64 off, int ret; u32 start; - mutex_lock(&adapter->ahw.mem_lock); + mutex_lock(&adapter->ahw->mem_lock); ret = qlcnic_pci_set_window_2M(adapter, off, &start); if (ret != 0) goto unlock; - addr = adapter->ahw.pci_base0 + start; + addr = adapter->ahw->pci_base0 + start; if (op == 0) /* read */ *data = readq(addr); @@ -934,7 +934,7 @@ qlcnic_pci_mem_access_direct(struct qlcnic_adapter *adapter, u64 off, writeq(*data, addr); unlock: - mutex_unlock(&adapter->ahw.mem_lock); + mutex_unlock(&adapter->ahw->mem_lock); return ret; } @@ -942,23 +942,23 @@ unlock: void qlcnic_pci_camqm_read_2M(struct qlcnic_adapter *adapter, u64 off, u64 *data) { - void __iomem *addr = adapter->ahw.pci_base0 + + void __iomem *addr = adapter->ahw->pci_base0 + QLCNIC_PCI_CAMQM_2M_BASE + (off - QLCNIC_PCI_CAMQM); - mutex_lock(&adapter->ahw.mem_lock); + mutex_lock(&adapter->ahw->mem_lock); *data = readq(addr); - mutex_unlock(&adapter->ahw.mem_lock); + mutex_unlock(&adapter->ahw->mem_lock); } void qlcnic_pci_camqm_write_2M(struct qlcnic_adapter *adapter, u64 off, u64 data) { - void __iomem *addr = adapter->ahw.pci_base0 + + void __iomem *addr = adapter->ahw->pci_base0 + QLCNIC_PCI_CAMQM_2M_BASE + (off - QLCNIC_PCI_CAMQM); - mutex_lock(&adapter->ahw.mem_lock); + mutex_lock(&adapter->ahw->mem_lock); writeq(data, addr); - mutex_unlock(&adapter->ahw.mem_lock); + mutex_unlock(&adapter->ahw->mem_lock); } #define MAX_CTL_CHECK 1000 @@ -997,7 +997,7 @@ qlcnic_pci_mem_write_2M(struct qlcnic_adapter *adapter, correct: off8 = off & ~0xf; - mutex_lock(&adapter->ahw.mem_lock); + mutex_lock(&adapter->ahw->mem_lock); writel(off8, (mem_crb + MIU_TEST_AGT_ADDR_LO)); writel(0, (mem_crb + MIU_TEST_AGT_ADDR_HI)); @@ -1049,7 +1049,7 @@ correct: ret = 0; done: - mutex_unlock(&adapter->ahw.mem_lock); + mutex_unlock(&adapter->ahw->mem_lock); return ret; } @@ -1091,7 +1091,7 @@ qlcnic_pci_mem_read_2M(struct qlcnic_adapter *adapter, correct: off8 = off & ~0xf; - mutex_lock(&adapter->ahw.mem_lock); + mutex_lock(&adapter->ahw->mem_lock); writel(off8, (mem_crb + MIU_TEST_AGT_ADDR_LO)); writel(0, (mem_crb + MIU_TEST_AGT_ADDR_HI)); @@ -1121,7 +1121,7 @@ correct: ret = 0; } - mutex_unlock(&adapter->ahw.mem_lock); + mutex_unlock(&adapter->ahw->mem_lock); return ret; } @@ -1145,7 +1145,7 @@ int qlcnic_get_board_info(struct qlcnic_adapter *adapter) if (qlcnic_rom_fast_read(adapter, offset, &board_type)) return -EIO; - adapter->ahw.board_type = board_type; + adapter->ahw->board_type = board_type; if (board_type == QLCNIC_BRDTYPE_P3P_4_GB_MM) { u32 gpio = QLCRD32(adapter, QLCNIC_ROMUSB_GLB_PAD_GPIO_I); @@ -1164,20 +1164,20 @@ int qlcnic_get_board_info(struct qlcnic_adapter *adapter) case QLCNIC_BRDTYPE_P3P_10G_SFP_QT: case QLCNIC_BRDTYPE_P3P_10G_XFP: case QLCNIC_BRDTYPE_P3P_10000_BASE_T: - adapter->ahw.port_type = QLCNIC_XGBE; + adapter->ahw->port_type = QLCNIC_XGBE; break; case QLCNIC_BRDTYPE_P3P_REF_QG: case QLCNIC_BRDTYPE_P3P_4_GB: case QLCNIC_BRDTYPE_P3P_4_GB_MM: - adapter->ahw.port_type = QLCNIC_GBE; + adapter->ahw->port_type = QLCNIC_GBE; break; case QLCNIC_BRDTYPE_P3P_10G_TP: - adapter->ahw.port_type = (adapter->portnum < 2) ? + adapter->ahw->port_type = (adapter->portnum < 2) ? QLCNIC_XGBE : QLCNIC_GBE; break; default: dev_err(&pdev->dev, "unknown board type %x\n", board_type); - adapter->ahw.port_type = QLCNIC_XGBE; + adapter->ahw->port_type = QLCNIC_XGBE; break; } diff --git a/drivers/net/qlcnic/qlcnic_init.c b/drivers/net/qlcnic/qlcnic_init.c index a7f1d5b..476ea14 100644 --- a/drivers/net/qlcnic/qlcnic_init.c +++ b/drivers/net/qlcnic/qlcnic_init.c @@ -94,7 +94,7 @@ void qlcnic_release_rx_buffers(struct qlcnic_adapter *adapter) struct qlcnic_rx_buffer *rx_buf; int i, ring; - recv_ctx = &adapter->recv_ctx; + recv_ctx = adapter->recv_ctx; for (ring = 0; ring < adapter->max_rds_rings; ring++) { rds_ring = &recv_ctx->rds_rings[ring]; for (i = 0; i < rds_ring->num_desc; ++i) { @@ -119,7 +119,7 @@ void qlcnic_reset_rx_buffers_list(struct qlcnic_adapter *adapter) struct qlcnic_rx_buffer *rx_buf; int i, ring; - recv_ctx = &adapter->recv_ctx; + recv_ctx = adapter->recv_ctx; for (ring = 0; ring < adapter->max_rds_rings; ring++) { rds_ring = &recv_ctx->rds_rings[ring]; @@ -173,7 +173,7 @@ void qlcnic_free_sw_resources(struct qlcnic_adapter *adapter) struct qlcnic_host_tx_ring *tx_ring; int ring; - recv_ctx = &adapter->recv_ctx; + recv_ctx = adapter->recv_ctx; if (recv_ctx->rds_rings == NULL) goto skip_rds; @@ -226,7 +226,7 @@ int qlcnic_alloc_sw_resources(struct qlcnic_adapter *adapter) } tx_ring->cmd_buf_arr = cmd_buf_arr; - recv_ctx = &adapter->recv_ctx; + recv_ctx = adapter->recv_ctx; size = adapter->max_rds_rings * sizeof(struct qlcnic_host_rds_ring); rds_ring = kzalloc(size, GFP_KERNEL); @@ -864,7 +864,7 @@ nomn: for (i = 0; i < entries; i++) { __le32 flags, file_chiprev, offs; - u8 chiprev = adapter->ahw.revision_id; + u8 chiprev = adapter->ahw->revision_id; u32 flagbit; offs = cpu_to_le32(ptab_descr->findex) + @@ -1394,7 +1394,7 @@ static struct sk_buff *qlcnic_process_rxbuf(struct qlcnic_adapter *adapter, return skb; } -static int +static inline int qlcnic_check_rx_tagging(struct qlcnic_adapter *adapter, struct sk_buff *skb, u16 *vlan_tag) { @@ -1425,7 +1425,7 @@ qlcnic_process_rcv(struct qlcnic_adapter *adapter, int ring, u64 sts_data0) { struct net_device *netdev = adapter->netdev; - struct qlcnic_recv_context *recv_ctx = &adapter->recv_ctx; + struct qlcnic_recv_context *recv_ctx = adapter->recv_ctx; struct qlcnic_rx_buffer *buffer; struct sk_buff *skb; struct qlcnic_host_rds_ring *rds_ring; @@ -1488,7 +1488,7 @@ qlcnic_process_lro(struct qlcnic_adapter *adapter, int ring, u64 sts_data0, u64 sts_data1) { struct net_device *netdev = adapter->netdev; - struct qlcnic_recv_context *recv_ctx = &adapter->recv_ctx; + struct qlcnic_recv_context *recv_ctx = adapter->recv_ctx; struct qlcnic_rx_buffer *buffer; struct sk_buff *skb; struct qlcnic_host_rds_ring *rds_ring; @@ -1625,7 +1625,7 @@ skip: for (ring = 0; ring < adapter->max_rds_rings; ring++) { struct qlcnic_host_rds_ring *rds_ring = - &adapter->recv_ctx.rds_rings[ring]; + &adapter->recv_ctx->rds_rings[ring]; if (!list_empty(&sds_ring->free_list[ring])) { list_for_each(cur, &sds_ring->free_list[ring]) { @@ -1651,12 +1651,13 @@ skip: } void -qlcnic_post_rx_buffers(struct qlcnic_adapter *adapter, u32 ringid, +qlcnic_post_rx_buffers(struct qlcnic_adapter *adapter, struct qlcnic_host_rds_ring *rds_ring) { struct rcv_desc *pdesc; struct qlcnic_rx_buffer *buffer; - int producer, count = 0; + int count = 0; + u32 producer; struct list_head *head; producer = rds_ring->producer; @@ -1696,7 +1697,8 @@ qlcnic_post_rx_buffers_nodb(struct qlcnic_adapter *adapter, { struct rcv_desc *pdesc; struct qlcnic_rx_buffer *buffer; - int producer, count = 0; + int count = 0; + uint32_t producer; struct list_head *head; if (!spin_trylock(&rds_ring->lock)) diff --git a/drivers/net/qlcnic/qlcnic_main.c b/drivers/net/qlcnic/qlcnic_main.c index de6f866..dde7e44 100644 --- a/drivers/net/qlcnic/qlcnic_main.c +++ b/drivers/net/qlcnic/qlcnic_main.c @@ -113,7 +113,7 @@ static DEFINE_PCI_DEVICE_TABLE(qlcnic_pci_tbl) = { MODULE_DEVICE_TABLE(pci, qlcnic_pci_tbl); -void +inline void qlcnic_update_cmd_producer(struct qlcnic_adapter *adapter, struct qlcnic_host_tx_ring *tx_ring) { @@ -169,7 +169,7 @@ qlcnic_napi_add(struct qlcnic_adapter *adapter, struct net_device *netdev) { int ring; struct qlcnic_host_sds_ring *sds_ring; - struct qlcnic_recv_context *recv_ctx = &adapter->recv_ctx; + struct qlcnic_recv_context *recv_ctx = adapter->recv_ctx; if (qlcnic_alloc_sds_rings(recv_ctx, adapter->max_sds_rings)) return -ENOMEM; @@ -193,14 +193,14 @@ qlcnic_napi_del(struct qlcnic_adapter *adapter) { int ring; struct qlcnic_host_sds_ring *sds_ring; - struct qlcnic_recv_context *recv_ctx = &adapter->recv_ctx; + struct qlcnic_recv_context *recv_ctx = adapter->recv_ctx; for (ring = 0; ring < adapter->max_sds_rings; ring++) { sds_ring = &recv_ctx->sds_rings[ring]; netif_napi_del(&sds_ring->napi); } - qlcnic_free_sds_rings(&adapter->recv_ctx); + qlcnic_free_sds_rings(adapter->recv_ctx); } static void @@ -208,7 +208,7 @@ qlcnic_napi_enable(struct qlcnic_adapter *adapter) { int ring; struct qlcnic_host_sds_ring *sds_ring; - struct qlcnic_recv_context *recv_ctx = &adapter->recv_ctx; + struct qlcnic_recv_context *recv_ctx = adapter->recv_ctx; if (adapter->is_up != QLCNIC_ADAPTER_UP_MAGIC) return; @@ -225,7 +225,7 @@ qlcnic_napi_disable(struct qlcnic_adapter *adapter) { int ring; struct qlcnic_host_sds_ring *sds_ring; - struct qlcnic_recv_context *recv_ctx = &adapter->recv_ctx; + struct qlcnic_recv_context *recv_ctx = adapter->recv_ctx; if (adapter->is_up != QLCNIC_ADAPTER_UP_MAGIC) return; @@ -359,7 +359,7 @@ qlcnic_setup_intr(struct qlcnic_adapter *adapter) struct pci_dev *pdev = adapter->pdev; int err, num_msix; - if (adapter->rss_supported) { + if (adapter->msix_supported) { num_msix = (num_online_cpus() >= MSIX_ENTRIES_PER_ADAPTER) ? MSIX_ENTRIES_PER_ADAPTER : 2; } else @@ -369,7 +369,7 @@ qlcnic_setup_intr(struct qlcnic_adapter *adapter) adapter->flags &= ~(QLCNIC_MSI_ENABLED | QLCNIC_MSIX_ENABLED); - legacy_intrp = &legacy_intr[adapter->ahw.pci_func]; + legacy_intrp = &legacy_intr[adapter->ahw->pci_func]; adapter->int_vec_bit = legacy_intrp->int_vec_bit; adapter->tgt_status_reg = qlcnic_get_ioaddr(adapter, @@ -391,8 +391,7 @@ qlcnic_setup_intr(struct qlcnic_adapter *adapter) adapter->flags |= QLCNIC_MSIX_ENABLED; qlcnic_set_msix_bit(pdev, 1); - if (adapter->rss_supported) - adapter->max_sds_rings = num_msix; + adapter->max_sds_rings = num_msix; dev_info(&pdev->dev, "using msi-x interrupts\n"); return; @@ -407,7 +406,7 @@ qlcnic_setup_intr(struct qlcnic_adapter *adapter) if (use_msi && !pci_enable_msi(pdev)) { adapter->flags |= QLCNIC_MSI_ENABLED; adapter->tgt_status_reg = qlcnic_get_ioaddr(adapter, - msi_tgt_status[adapter->ahw.pci_func]); + msi_tgt_status[adapter->ahw->pci_func]); dev_info(&pdev->dev, "using msi interrupts\n"); adapter->msix_entries[0].vector = pdev->irq; return; @@ -429,8 +428,8 @@ qlcnic_teardown_intr(struct qlcnic_adapter *adapter) static void qlcnic_cleanup_pci_map(struct qlcnic_adapter *adapter) { - if (adapter->ahw.pci_base0 != NULL) - iounmap(adapter->ahw.pci_base0); + if (adapter->ahw->pci_base0 != NULL) + iounmap(adapter->ahw->pci_base0); } static int @@ -500,7 +499,7 @@ qlcnic_set_function_modes(struct qlcnic_adapter *adapter) u32 ref_count; int i, ret = 1; u32 data = QLCNIC_MGMT_FUNC; - void __iomem *priv_op = adapter->ahw.pci_base0 + QLCNIC_DRV_OP_MODE; + void __iomem *priv_op = adapter->ahw->pci_base0 + QLCNIC_DRV_OP_MODE; /* If other drivers are not in use set their privilege level */ ref_count = QLCRD32(adapter, QLCNIC_CRB_DRV_ACTIVE); @@ -512,16 +511,16 @@ qlcnic_set_function_modes(struct qlcnic_adapter *adapter) for (i = 0; i < QLCNIC_MAX_PCI_FUNC; i++) { id = i; if (adapter->npars[i].type != QLCNIC_TYPE_NIC || - id == adapter->ahw.pci_func) + id == adapter->ahw->pci_func) continue; data |= (qlcnic_config_npars & QLC_DEV_SET_DRV(0xf, id)); } } else { data = readl(priv_op); - data = (data & ~QLC_DEV_SET_DRV(0xf, adapter->ahw.pci_func)) | + data = (data & ~QLC_DEV_SET_DRV(0xf, adapter->ahw->pci_func)) | (QLC_DEV_SET_DRV(QLCNIC_MGMT_FUNC, - adapter->ahw.pci_func)); + adapter->ahw->pci_func)); } writel(data, priv_op); qlcnic_api_unlock(adapter); @@ -539,22 +538,23 @@ qlcnic_check_vf(struct qlcnic_adapter *adapter) u32 op_mode, priv_level; /* Determine FW API version */ - adapter->fw_hal_version = readl(adapter->ahw.pci_base0 + QLCNIC_FW_API); + adapter->fw_hal_version = readl(adapter->ahw->pci_base0 + + QLCNIC_FW_API); /* Find PCI function number */ pci_read_config_dword(adapter->pdev, QLCNIC_MSIX_TABLE_OFFSET, &func); - msix_base_addr = adapter->ahw.pci_base0 + QLCNIC_MSIX_BASE; + msix_base_addr = adapter->ahw->pci_base0 + QLCNIC_MSIX_BASE; msix_base = readl(msix_base_addr); func = (func - msix_base)/QLCNIC_MSIX_TBL_PGSIZE; - adapter->ahw.pci_func = func; + adapter->ahw->pci_func = func; /* Determine function privilege level */ - priv_op = adapter->ahw.pci_base0 + QLCNIC_DRV_OP_MODE; + priv_op = adapter->ahw->pci_base0 + QLCNIC_DRV_OP_MODE; op_mode = readl(priv_op); if (op_mode == QLC_DEV_DRV_DEFAULT) priv_level = QLCNIC_MGMT_FUNC; else - priv_level = QLC_DEV_GET_DRV(op_mode, adapter->ahw.pci_func); + priv_level = QLC_DEV_GET_DRV(op_mode, adapter->ahw->pci_func); if (priv_level == QLCNIC_NON_PRIV_FUNC) { adapter->op_mode = QLCNIC_NON_PRIV_FUNC; @@ -593,13 +593,14 @@ qlcnic_setup_pci_map(struct qlcnic_adapter *adapter) dev_info(&pdev->dev, "%dMB memory map\n", (int)(mem_len>>20)); - adapter->ahw.pci_base0 = mem_ptr0; - adapter->ahw.pci_len0 = pci_len0; + adapter->ahw->pci_base0 = mem_ptr0; + adapter->ahw->pci_len0 = pci_len0; qlcnic_check_vf(adapter); - adapter->ahw.ocm_win_crb = qlcnic_get_ioaddr(adapter, - QLCNIC_PCIX_PS_REG(PCIX_OCM_WINDOW_REG(adapter->ahw.pci_func))); + adapter->ahw->ocm_win_crb = qlcnic_get_ioaddr(adapter, + QLCNIC_PCIX_PS_REG(PCIX_OCM_WINDOW_REG( + adapter->ahw->pci_func))); return 0; } @@ -641,7 +642,7 @@ qlcnic_check_options(struct qlcnic_adapter *adapter) dev_info(&pdev->dev, "firmware v%d.%d.%d\n", fw_major, fw_minor, fw_build); - if (adapter->ahw.port_type == QLCNIC_XGBE) { + if (adapter->ahw->port_type == QLCNIC_XGBE) { if (adapter->flags & QLCNIC_ESWITCH_ENABLED) { adapter->num_rxd = DEFAULT_RCV_DESCRIPTORS_VF; adapter->max_rxd = MAX_RCV_DESCRIPTORS_VF; @@ -653,7 +654,7 @@ qlcnic_check_options(struct qlcnic_adapter *adapter) adapter->num_jumbo_rxd = MAX_JUMBO_RCV_DESCRIPTORS_10G; adapter->max_jumbo_rxd = MAX_JUMBO_RCV_DESCRIPTORS_10G; - } else if (adapter->ahw.port_type == QLCNIC_GBE) { + } else if (adapter->ahw->port_type == QLCNIC_GBE) { adapter->num_rxd = DEFAULT_RCV_DESCRIPTORS_1G; adapter->num_jumbo_rxd = MAX_JUMBO_RCV_DESCRIPTORS_1G; adapter->max_jumbo_rxd = MAX_JUMBO_RCV_DESCRIPTORS_1G; @@ -661,7 +662,6 @@ qlcnic_check_options(struct qlcnic_adapter *adapter) } adapter->msix_supported = !!use_msi_x; - adapter->rss_supported = !!use_msi_x; adapter->num_txd = MAX_CMD_DESCRIPTORS; @@ -674,7 +674,7 @@ qlcnic_initialize_nic(struct qlcnic_adapter *adapter) int err; struct qlcnic_info nic_info; - err = qlcnic_get_nic_info(adapter, &nic_info, adapter->ahw.pci_func); + err = qlcnic_get_nic_info(adapter, &nic_info, adapter->ahw->pci_func); if (err) return err; @@ -736,7 +736,7 @@ qlcnic_set_eswitch_port_config(struct qlcnic_adapter *adapter) if (!(adapter->flags & QLCNIC_ESWITCH_ENABLED)) return 0; - esw_cfg.pci_func = adapter->ahw.pci_func; + esw_cfg.pci_func = adapter->ahw->pci_func; if (qlcnic_get_eswitch_port_config(adapter, &esw_cfg)) return -EIO; qlcnic_set_vlan_config(adapter, &esw_cfg); @@ -793,14 +793,14 @@ qlcnic_check_eswitch_mode(struct qlcnic_adapter *adapter) if (adapter->flags & QLCNIC_ADAPTER_INITIALIZED) return 0; - priv_op = adapter->ahw.pci_base0 + QLCNIC_DRV_OP_MODE; + priv_op = adapter->ahw->pci_base0 + QLCNIC_DRV_OP_MODE; op_mode = readl(priv_op); - priv_level = QLC_DEV_GET_DRV(op_mode, adapter->ahw.pci_func); + priv_level = QLC_DEV_GET_DRV(op_mode, adapter->ahw->pci_func); if (op_mode == QLC_DEV_DRV_DEFAULT) priv_level = QLCNIC_MGMT_FUNC; else - priv_level = QLC_DEV_GET_DRV(op_mode, adapter->ahw.pci_func); + priv_level = QLC_DEV_GET_DRV(op_mode, adapter->ahw->pci_func); if (adapter->flags & QLCNIC_ESWITCH_ENABLED) { if (priv_level == QLCNIC_MGMT_FUNC) { @@ -1040,7 +1040,7 @@ qlcnic_request_irq(struct qlcnic_adapter *adapter) unsigned long flags = 0; struct net_device *netdev = adapter->netdev; - struct qlcnic_recv_context *recv_ctx = &adapter->recv_ctx; + struct qlcnic_recv_context *recv_ctx = adapter->recv_ctx; if (adapter->diag_test == QLCNIC_INTERRUPT_TEST) { handler = qlcnic_tmp_intr; @@ -1077,7 +1077,7 @@ qlcnic_free_irq(struct qlcnic_adapter *adapter) int ring; struct qlcnic_host_sds_ring *sds_ring; - struct qlcnic_recv_context *recv_ctx = &adapter->recv_ctx; + struct qlcnic_recv_context *recv_ctx = adapter->recv_ctx; for (ring = 0; ring < adapter->max_sds_rings; ring++) { sds_ring = &recv_ctx->sds_rings[ring]; @@ -1117,14 +1117,14 @@ __qlcnic_up(struct qlcnic_adapter *adapter, struct net_device *netdev) return -EIO; for (ring = 0; ring < adapter->max_rds_rings; ring++) { - rds_ring = &adapter->recv_ctx.rds_rings[ring]; - qlcnic_post_rx_buffers(adapter, ring, rds_ring); + rds_ring = &adapter->recv_ctx->rds_rings[ring]; + qlcnic_post_rx_buffers(adapter, rds_ring); } qlcnic_set_multi(netdev); qlcnic_fw_cmd_set_mtu(adapter, netdev->mtu); - adapter->ahw.linkup = 0; + adapter->ahw->linkup = 0; if (adapter->max_sds_rings > 1) qlcnic_config_rss(adapter, 1); @@ -1274,7 +1274,7 @@ void qlcnic_diag_free_res(struct net_device *netdev, int max_sds_rings) clear_bit(__QLCNIC_DEV_UP, &adapter->state); if (adapter->diag_test == QLCNIC_INTERRUPT_TEST) { for (ring = 0; ring < adapter->max_sds_rings; ring++) { - sds_ring = &adapter->recv_ctx.sds_rings[ring]; + sds_ring = &adapter->recv_ctx->sds_rings[ring]; qlcnic_disable_int(sds_ring); } } @@ -1295,6 +1295,39 @@ out: netif_device_attach(netdev); } +static int qlcnic_alloc_adapter_resources(struct qlcnic_adapter *adapter) +{ + int err = 0; + adapter->ahw = kzalloc(sizeof(struct qlcnic_hardware_context), + GFP_KERNEL); + if (!adapter->ahw) { + dev_err(&adapter->pdev->dev, + "Failed to allocate recv ctx resources for adapter\n"); + err = -ENOMEM; + goto err_out; + } + adapter->recv_ctx = kzalloc(sizeof(struct qlcnic_recv_context), + GFP_KERNEL); + if (!adapter->recv_ctx) { + dev_err(&adapter->pdev->dev, + "Failed to allocate recv ctx resources for adapter\n"); + kfree(adapter->ahw); + adapter->ahw = NULL; + err = -ENOMEM; + } +err_out: + return err; +} + +static void qlcnic_free_adapter_resources(struct qlcnic_adapter *adapter) +{ + kfree(adapter->recv_ctx); + adapter->recv_ctx = NULL; + + kfree(adapter->ahw); + adapter->ahw = NULL; +} + int qlcnic_diag_alloc_res(struct net_device *netdev, int test) { struct qlcnic_adapter *adapter = netdev_priv(netdev); @@ -1327,13 +1360,13 @@ int qlcnic_diag_alloc_res(struct net_device *netdev, int test) } for (ring = 0; ring < adapter->max_rds_rings; ring++) { - rds_ring = &adapter->recv_ctx.rds_rings[ring]; - qlcnic_post_rx_buffers(adapter, ring, rds_ring); + rds_ring = &adapter->recv_ctx->rds_rings[ring]; + qlcnic_post_rx_buffers(adapter, rds_ring); } if (adapter->diag_test == QLCNIC_INTERRUPT_TEST) { for (ring = 0; ring < adapter->max_sds_rings; ring++) { - sds_ring = &adapter->recv_ctx.sds_rings[ring]; + sds_ring = &adapter->recv_ctx->sds_rings[ring]; qlcnic_enable_int(sds_ring); } } @@ -1503,23 +1536,26 @@ qlcnic_probe(struct pci_dev *pdev, const struct pci_device_id *ent) adapter = netdev_priv(netdev); adapter->netdev = netdev; adapter->pdev = pdev; - adapter->dev_rst_time = jiffies; + if (qlcnic_alloc_adapter_resources(adapter)) + goto err_out_free_netdev; + + adapter->dev_rst_time = jiffies; revision_id = pdev->revision; - adapter->ahw.revision_id = revision_id; + adapter->ahw->revision_id = revision_id; - rwlock_init(&adapter->ahw.crb_lock); - mutex_init(&adapter->ahw.mem_lock); + rwlock_init(&adapter->ahw->crb_lock); + mutex_init(&adapter->ahw->mem_lock); spin_lock_init(&adapter->tx_clean_lock); INIT_LIST_HEAD(&adapter->mac_list); err = qlcnic_setup_pci_map(adapter); if (err) - goto err_out_free_netdev; + goto err_out_free_hw; /* This will be reset for mezz cards */ - adapter->portnum = adapter->ahw.pci_func; + adapter->portnum = adapter->ahw->pci_func; err = qlcnic_get_board_info(adapter); if (err) { @@ -1547,7 +1583,7 @@ qlcnic_probe(struct pci_dev *pdev, const struct pci_device_id *ent) pr_info("%s: %s Board Chip rev 0x%x\n", module_name(THIS_MODULE), - brd_name, adapter->ahw.revision_id); + brd_name, adapter->ahw->revision_id); } qlcnic_clear_stats(adapter); @@ -1562,7 +1598,7 @@ qlcnic_probe(struct pci_dev *pdev, const struct pci_device_id *ent) qlcnic_schedule_work(adapter, qlcnic_fw_poll_work, FW_POLL_DELAY); - switch (adapter->ahw.port_type) { + switch (adapter->ahw->port_type) { case QLCNIC_GBE: dev_info(&adapter->pdev->dev, "%s: GbE port initialized\n", adapter->netdev->name); @@ -1587,6 +1623,9 @@ err_out_decr_ref: err_out_iounmap: qlcnic_cleanup_pci_map(adapter); +err_out_free_hw: + qlcnic_free_adapter_resources(adapter); + err_out_free_netdev: free_netdev(netdev); @@ -1640,6 +1679,7 @@ static void __devexit qlcnic_remove(struct pci_dev *pdev) pci_disable_device(pdev); pci_set_drvdata(pdev, NULL); + qlcnic_free_adapter_resources(adapter); free_netdev(netdev); } static int __qlcnic_shutdown(struct pci_dev *pdev) @@ -2248,16 +2288,16 @@ void qlcnic_advert_link_change(struct qlcnic_adapter *adapter, int linkup) { struct net_device *netdev = adapter->netdev; - if (adapter->ahw.linkup && !linkup) { + if (adapter->ahw->linkup && !linkup) { netdev_info(netdev, "NIC Link is down\n"); - adapter->ahw.linkup = 0; + adapter->ahw->linkup = 0; if (netif_running(netdev)) { netif_carrier_off(netdev); netif_stop_queue(netdev); } - } else if (!adapter->ahw.linkup && linkup) { + } else if (!adapter->ahw->linkup && linkup) { netdev_info(netdev, "NIC Link is up\n"); - adapter->ahw.linkup = 1; + adapter->ahw->linkup = 1; if (netif_running(netdev)) { netif_carrier_on(netdev); netif_wake_queue(netdev); @@ -2493,7 +2533,7 @@ static void qlcnic_poll_controller(struct net_device *netdev) int ring; struct qlcnic_host_sds_ring *sds_ring; struct qlcnic_adapter *adapter = netdev_priv(netdev); - struct qlcnic_recv_context *recv_ctx = &adapter->recv_ctx; + struct qlcnic_recv_context *recv_ctx = adapter->recv_ctx; disable_irq(adapter->irq); for (ring = 0; ring < adapter->max_sds_rings; ring++) { @@ -3503,7 +3543,7 @@ validate_esw_config(struct qlcnic_adapter *adapter, u8 pci_func; int i; - op_mode = readl(adapter->ahw.pci_base0 + QLCNIC_DRV_OP_MODE); + op_mode = readl(adapter->ahw->pci_base0 + QLCNIC_DRV_OP_MODE); for (i = 0; i < count; i++) { pci_func = esw_cfg[i].pci_func; @@ -3569,13 +3609,13 @@ qlcnic_sysfs_write_esw_config(struct file *file, struct kobject *kobj, if (qlcnic_config_switch_port(adapter, &esw_cfg[i])) return QL_STATUS_INVALID_PARAM; - if (adapter->ahw.pci_func != esw_cfg[i].pci_func) + if (adapter->ahw->pci_func != esw_cfg[i].pci_func) continue; op_mode = esw_cfg[i].op_mode; qlcnic_get_eswitch_port_config(adapter, &esw_cfg[i]); esw_cfg[i].op_mode = op_mode; - esw_cfg[i].pci_func = adapter->ahw.pci_func; + esw_cfg[i].pci_func = adapter->ahw->pci_func; switch (esw_cfg[i].op_mode) { case QLCNIC_PORT_DEFAULTS: -- cgit v0.10.2 From 036d61f05189c9c02de22dd19a1c64a4fd74a914 Mon Sep 17 00:00:00 2001 From: Anirban Chakraborty Date: Fri, 1 Apr 2011 14:28:11 +0000 Subject: qlcnic: Code optimization patch Optimized code resulted in achieving lower CPU utilization on transmit path and higher throughput for small packet sizes (64 bytes). Signed-off-by: Anirban Chakraborty Signed-off-by: David S. Miller diff --git a/drivers/net/qlcnic/qlcnic.h b/drivers/net/qlcnic/qlcnic.h index 15d950a..a5b28d1 100644 --- a/drivers/net/qlcnic/qlcnic.h +++ b/drivers/net/qlcnic/qlcnic.h @@ -434,50 +434,49 @@ struct qlcnic_adapter_stats { * be one Rcv Descriptor for normal packets, one for jumbo and may be others. */ struct qlcnic_host_rds_ring { - u32 producer; + void __iomem *crb_rcv_producer; + struct rcv_desc *desc_head; + struct qlcnic_rx_buffer *rx_buf_arr; u32 num_desc; + u32 producer; u32 dma_size; u32 skb_size; u32 flags; - void __iomem *crb_rcv_producer; - struct rcv_desc *desc_head; - struct qlcnic_rx_buffer *rx_buf_arr; struct list_head free_list; spinlock_t lock; dma_addr_t phys_addr; -}; +} ____cacheline_internodealigned_in_smp; struct qlcnic_host_sds_ring { u32 consumer; u32 num_desc; void __iomem *crb_sts_consumer; - void __iomem *crb_intr_mask; struct status_desc *desc_head; struct qlcnic_adapter *adapter; struct napi_struct napi; struct list_head free_list[NUM_RCV_DESC_RINGS]; + void __iomem *crb_intr_mask; int irq; dma_addr_t phys_addr; char name[IFNAMSIZ+4]; -}; +} ____cacheline_internodealigned_in_smp; struct qlcnic_host_tx_ring { u32 producer; - __le32 *hw_consumer; u32 sw_consumer; - void __iomem *crb_cmd_producer; u32 num_desc; - - struct netdev_queue *txq; - - struct qlcnic_cmd_buffer *cmd_buf_arr; + void __iomem *crb_cmd_producer; struct cmd_desc_type0 *desc_head; + struct qlcnic_cmd_buffer *cmd_buf_arr; + __le32 *hw_consumer; + dma_addr_t phys_addr; dma_addr_t hw_cons_phys_addr; -}; + struct netdev_queue *txq; +} ____cacheline_internodealigned_in_smp; /* * Receive context. There is one such structure per instance of the @@ -1328,8 +1327,7 @@ static const struct qlcnic_brdinfo qlcnic_boards[] = { static inline u32 qlcnic_tx_avail(struct qlcnic_host_tx_ring *tx_ring) { - smp_mb(); - if (tx_ring->producer < tx_ring->sw_consumer) + if (likely(tx_ring->producer < tx_ring->sw_consumer)) return tx_ring->sw_consumer - tx_ring->producer; else return tx_ring->sw_consumer + tx_ring->num_desc - diff --git a/drivers/net/qlcnic/qlcnic_main.c b/drivers/net/qlcnic/qlcnic_main.c index dde7e44..3b740f55 100644 --- a/drivers/net/qlcnic/qlcnic_main.c +++ b/drivers/net/qlcnic/qlcnic_main.c @@ -1861,6 +1861,7 @@ static void qlcnic_change_filter(struct qlcnic_adapter *adapter, vlan_req->vlan_id = vlan_id; tx_ring->producer = get_next_index(producer, tx_ring->num_desc); + smp_mb(); } #define QLCNIC_MAC_HASH(MAC)\ @@ -1921,58 +1922,122 @@ qlcnic_send_filter(struct qlcnic_adapter *adapter, spin_unlock(&adapter->mac_learn_lock); } -static void -qlcnic_tso_check(struct net_device *netdev, - struct qlcnic_host_tx_ring *tx_ring, +static int +qlcnic_tx_pkt(struct qlcnic_adapter *adapter, struct cmd_desc_type0 *first_desc, struct sk_buff *skb) { - u8 opcode = TX_ETHER_PKT; - __be16 protocol = skb->protocol; - u16 flags = 0; - int copied, offset, copy_len, hdr_len = 0, tso = 0; + u8 opcode = 0, hdr_len = 0; + u16 flags = 0, vlan_tci = 0; + int copied, offset, copy_len; struct cmd_desc_type0 *hwdesc; struct vlan_ethhdr *vh; - struct qlcnic_adapter *adapter = netdev_priv(netdev); + struct qlcnic_host_tx_ring *tx_ring = adapter->tx_ring; + u16 protocol = ntohs(skb->protocol); u32 producer = tx_ring->producer; - __le16 vlan_oob = first_desc->flags_opcode & - cpu_to_le16(FLAGS_VLAN_OOB); + + if (protocol == ETH_P_8021Q) { + vh = (struct vlan_ethhdr *)skb->data; + flags = FLAGS_VLAN_TAGGED; + vlan_tci = vh->h_vlan_TCI; + } else if (vlan_tx_tag_present(skb)) { + flags = FLAGS_VLAN_OOB; + vlan_tci = vlan_tx_tag_get(skb); + } + if (unlikely(adapter->pvid)) { + if (vlan_tci && !(adapter->flags & QLCNIC_TAGGING_ENABLED)) + return -EIO; + if (vlan_tci && (adapter->flags & QLCNIC_TAGGING_ENABLED)) + goto set_flags; + + flags = FLAGS_VLAN_OOB; + vlan_tci = adapter->pvid; + } +set_flags: + qlcnic_set_tx_vlan_tci(first_desc, vlan_tci); + qlcnic_set_tx_flags_opcode(first_desc, flags, opcode); if (*(skb->data) & BIT_0) { flags |= BIT_0; memcpy(&first_desc->eth_addr, skb->data, ETH_ALEN); } - - if ((netdev->features & (NETIF_F_TSO | NETIF_F_TSO6)) && + opcode = TX_ETHER_PKT; + if ((adapter->netdev->features & (NETIF_F_TSO | NETIF_F_TSO6)) && skb_shinfo(skb)->gso_size > 0) { hdr_len = skb_transport_offset(skb) + tcp_hdrlen(skb); first_desc->mss = cpu_to_le16(skb_shinfo(skb)->gso_size); first_desc->total_hdr_length = hdr_len; - if (vlan_oob) { + + opcode = (protocol == ETH_P_IPV6) ? TX_TCP_LSO6 : TX_TCP_LSO; + + /* For LSO, we need to copy the MAC/IP/TCP headers into + * the descriptor ring */ + copied = 0; + offset = 2; + + if (flags & FLAGS_VLAN_OOB) { first_desc->total_hdr_length += VLAN_HLEN; first_desc->tcp_hdr_offset = VLAN_HLEN; first_desc->ip_hdr_offset = VLAN_HLEN; /* Only in case of TSO on vlan device */ flags |= FLAGS_VLAN_TAGGED; + + /* Create a TSO vlan header template for firmware */ + + hwdesc = &tx_ring->desc_head[producer]; + tx_ring->cmd_buf_arr[producer].skb = NULL; + + copy_len = min((int)sizeof(struct cmd_desc_type0) - + offset, hdr_len + VLAN_HLEN); + + vh = (struct vlan_ethhdr *)((char *) hwdesc + 2); + skb_copy_from_linear_data(skb, vh, 12); + vh->h_vlan_proto = htons(ETH_P_8021Q); + vh->h_vlan_TCI = htons(vlan_tci); + + skb_copy_from_linear_data_offset(skb, 12, + (char *)vh + 16, copy_len - 16); + + copied = copy_len - VLAN_HLEN; + offset = 0; + + producer = get_next_index(producer, tx_ring->num_desc); } - opcode = (protocol == cpu_to_be16(ETH_P_IPV6)) ? - TX_TCP_LSO6 : TX_TCP_LSO; - tso = 1; + while (copied < hdr_len) { + + copy_len = min((int)sizeof(struct cmd_desc_type0) - + offset, (hdr_len - copied)); + + hwdesc = &tx_ring->desc_head[producer]; + tx_ring->cmd_buf_arr[producer].skb = NULL; + + skb_copy_from_linear_data_offset(skb, copied, + (char *) hwdesc + offset, copy_len); + + copied += copy_len; + offset = 0; + + producer = get_next_index(producer, tx_ring->num_desc); + } + + tx_ring->producer = producer; + smp_mb(); + adapter->stats.lso_frames++; } else if (skb->ip_summed == CHECKSUM_PARTIAL) { u8 l4proto; - if (protocol == cpu_to_be16(ETH_P_IP)) { + if (protocol == ETH_P_IP) { l4proto = ip_hdr(skb)->protocol; if (l4proto == IPPROTO_TCP) opcode = TX_TCP_PKT; else if (l4proto == IPPROTO_UDP) opcode = TX_UDP_PKT; - } else if (protocol == cpu_to_be16(ETH_P_IPV6)) { + } else if (protocol == ETH_P_IPV6) { l4proto = ipv6_hdr(skb)->nexthdr; if (l4proto == IPPROTO_TCP) @@ -1981,63 +2046,11 @@ qlcnic_tso_check(struct net_device *netdev, opcode = TX_UDPV6_PKT; } } - first_desc->tcp_hdr_offset += skb_transport_offset(skb); first_desc->ip_hdr_offset += skb_network_offset(skb); qlcnic_set_tx_flags_opcode(first_desc, flags, opcode); - if (!tso) - return; - - /* For LSO, we need to copy the MAC/IP/TCP headers into - * the descriptor ring - */ - copied = 0; - offset = 2; - - if (vlan_oob) { - /* Create a TSO vlan header template for firmware */ - - hwdesc = &tx_ring->desc_head[producer]; - tx_ring->cmd_buf_arr[producer].skb = NULL; - - copy_len = min((int)sizeof(struct cmd_desc_type0) - offset, - hdr_len + VLAN_HLEN); - - vh = (struct vlan_ethhdr *)((char *)hwdesc + 2); - skb_copy_from_linear_data(skb, vh, 12); - vh->h_vlan_proto = htons(ETH_P_8021Q); - vh->h_vlan_TCI = (__be16)swab16((u16)first_desc->vlan_TCI); - - skb_copy_from_linear_data_offset(skb, 12, - (char *)vh + 16, copy_len - 16); - - copied = copy_len - VLAN_HLEN; - offset = 0; - - producer = get_next_index(producer, tx_ring->num_desc); - } - - while (copied < hdr_len) { - - copy_len = min((int)sizeof(struct cmd_desc_type0) - offset, - (hdr_len - copied)); - - hwdesc = &tx_ring->desc_head[producer]; - tx_ring->cmd_buf_arr[producer].skb = NULL; - - skb_copy_from_linear_data_offset(skb, copied, - (char *)hwdesc + offset, copy_len); - - copied += copy_len; - offset = 0; - - producer = get_next_index(producer, tx_ring->num_desc); - } - - tx_ring->producer = producer; - barrier(); - adapter->stats.lso_frames++; + return 0; } static int @@ -2088,39 +2101,21 @@ out_err: return -ENOMEM; } -static int -qlcnic_check_tx_tagging(struct qlcnic_adapter *adapter, - struct sk_buff *skb, - struct cmd_desc_type0 *first_desc) +static void +qlcnic_unmap_buffers(struct pci_dev *pdev, struct sk_buff *skb, + struct qlcnic_cmd_buffer *pbuf) { - u8 opcode = 0; - u16 flags = 0; - __be16 protocol = skb->protocol; - struct vlan_ethhdr *vh; + struct qlcnic_skb_frag *nf = &pbuf->frag_array[0]; + int nr_frags = skb_shinfo(skb)->nr_frags; + int i; - if (protocol == cpu_to_be16(ETH_P_8021Q)) { - vh = (struct vlan_ethhdr *)skb->data; - protocol = vh->h_vlan_encapsulated_proto; - flags = FLAGS_VLAN_TAGGED; - qlcnic_set_tx_vlan_tci(first_desc, ntohs(vh->h_vlan_TCI)); - } else if (vlan_tx_tag_present(skb)) { - flags = FLAGS_VLAN_OOB; - qlcnic_set_tx_vlan_tci(first_desc, vlan_tx_tag_get(skb)); + for (i = 0; i < nr_frags; i++) { + nf = &pbuf->frag_array[i+1]; + pci_unmap_page(pdev, nf->dma, nf->length, PCI_DMA_TODEVICE); } - if (unlikely(adapter->pvid)) { - if (first_desc->vlan_TCI && - !(adapter->flags & QLCNIC_TAGGING_ENABLED)) - return -EIO; - if (first_desc->vlan_TCI && - (adapter->flags & QLCNIC_TAGGING_ENABLED)) - goto set_flags; - flags = FLAGS_VLAN_OOB; - qlcnic_set_tx_vlan_tci(first_desc, adapter->pvid); - } -set_flags: - qlcnic_set_tx_flags_opcode(first_desc, flags, opcode); - return 0; + nf = &pbuf->frag_array[0]; + pci_unmap_single(pdev, nf->dma, skb_headlen(skb), PCI_DMA_TODEVICE); } static inline void @@ -2144,7 +2139,7 @@ qlcnic_xmit_frame(struct sk_buff *skb, struct net_device *netdev) int i, k; u32 producer; - int frag_count, no_of_desc; + int frag_count; u32 num_txd = tx_ring->num_desc; if (!test_bit(__QLCNIC_DEV_UP, &adapter->state)) { @@ -2161,12 +2156,8 @@ qlcnic_xmit_frame(struct sk_buff *skb, struct net_device *netdev) frag_count = skb_shinfo(skb)->nr_frags + 1; - /* 4 fragments per cmd des */ - no_of_desc = (frag_count + 3) >> 2; - if (unlikely(qlcnic_tx_avail(tx_ring) <= TX_STOP_THRESH)) { netif_stop_queue(netdev); - smp_mb(); if (qlcnic_tx_avail(tx_ring) > TX_STOP_THRESH) netif_start_queue(netdev); else { @@ -2183,9 +2174,6 @@ qlcnic_xmit_frame(struct sk_buff *skb, struct net_device *netdev) first_desc = hwdesc = &tx_ring->desc_head[producer]; qlcnic_clear_cmddesc((u64 *)hwdesc); - if (qlcnic_check_tx_tagging(adapter, skb, first_desc)) - goto drop_packet; - if (qlcnic_map_tx_skb(pdev, skb, pbuf)) { adapter->stats.tx_dma_map_error++; goto drop_packet; @@ -2229,8 +2217,10 @@ qlcnic_xmit_frame(struct sk_buff *skb, struct net_device *netdev) } tx_ring->producer = get_next_index(producer, num_txd); + smp_mb(); - qlcnic_tso_check(netdev, tx_ring, first_desc, skb); + if (unlikely(qlcnic_tx_pkt(adapter, first_desc, skb))) + goto unwind_buff; if (qlcnic_mac_learn) qlcnic_send_filter(adapter, tx_ring, first_desc, skb); @@ -2242,6 +2232,8 @@ qlcnic_xmit_frame(struct sk_buff *skb, struct net_device *netdev) return NETDEV_TX_OK; +unwind_buff: + qlcnic_unmap_buffers(pdev, skb, pbuf); drop_packet: adapter->stats.txdropped++; dev_kfree_skb_any(skb); -- cgit v0.10.2 From b9796a14d9705c4be4a080a4fe39379a51681374 Mon Sep 17 00:00:00 2001 From: Anirban Chakraborty Date: Fri, 1 Apr 2011 14:28:15 +0000 Subject: qlcnic: Changes to VLAN code Made changes to VLAN code comply with new VLAN infrastructure in kernel Signed-off-by: Anirban Chakraborty Signed-off-by: David S. Miller diff --git a/drivers/net/qlcnic/qlcnic.h b/drivers/net/qlcnic/qlcnic.h index a5b28d1..be9c329 100644 --- a/drivers/net/qlcnic/qlcnic.h +++ b/drivers/net/qlcnic/qlcnic.h @@ -29,6 +29,8 @@ #include #include +#include +#include #include "qlcnic_hdr.h" @@ -982,8 +984,8 @@ struct qlcnic_adapter { u8 mac_addr[ETH_ALEN]; u64 dev_rst_time; + unsigned long vlans[BITS_TO_LONGS(VLAN_N_VID)]; - struct vlan_group *vlgrp; struct qlcnic_npar_info *npars; struct qlcnic_eswitch *eswitch; struct qlcnic_nic_template *nic_ops; diff --git a/drivers/net/qlcnic/qlcnic_init.c b/drivers/net/qlcnic/qlcnic_init.c index 476ea14..74ec96d 100644 --- a/drivers/net/qlcnic/qlcnic_init.c +++ b/drivers/net/qlcnic/qlcnic_init.c @@ -1467,10 +1467,10 @@ qlcnic_process_rcv(struct qlcnic_adapter *adapter, skb->protocol = eth_type_trans(skb, netdev); - if ((vid != 0xffff) && adapter->vlgrp) - vlan_gro_receive(&sds_ring->napi, adapter->vlgrp, vid, skb); - else - napi_gro_receive(&sds_ring->napi, skb); + if (vid != 0xffff) + __vlan_hwaccel_put_tag(skb, vid); + + napi_gro_receive(&sds_ring->napi, skb); adapter->stats.rx_pkts++; adapter->stats.rxbytes += length; @@ -1552,10 +1552,9 @@ qlcnic_process_lro(struct qlcnic_adapter *adapter, length = skb->len; - if ((vid != 0xffff) && adapter->vlgrp) - vlan_hwaccel_receive_skb(skb, adapter->vlgrp, vid); - else - netif_receive_skb(skb); + if (vid != 0xffff) + __vlan_hwaccel_put_tag(skb, vid); + netif_receive_skb(skb); adapter->stats.lro_pkts++; adapter->stats.lrobytes += length; diff --git a/drivers/net/qlcnic/qlcnic_main.c b/drivers/net/qlcnic/qlcnic_main.c index 3b740f55..b75aef0 100644 --- a/drivers/net/qlcnic/qlcnic_main.c +++ b/drivers/net/qlcnic/qlcnic_main.c @@ -13,7 +13,6 @@ #include #include -#include #include #include #include @@ -98,6 +97,9 @@ static int qlcnicvf_config_bridged_mode(struct qlcnic_adapter *, u32); static int qlcnicvf_start_firmware(struct qlcnic_adapter *); static void qlcnic_set_netdev_features(struct qlcnic_adapter *, struct qlcnic_esw_func_cfg *); +static void qlcnic_vlan_rx_add(struct net_device *, u16); +static void qlcnic_vlan_rx_del(struct net_device *, u16); + /* PCI Device ID Table */ #define ENTRY(device) \ {PCI_DEVICE(PCI_VENDOR_ID_QLOGIC, (device)), \ @@ -317,13 +319,6 @@ static int qlcnic_set_mac(struct net_device *netdev, void *p) return 0; } -static void qlcnic_vlan_rx_register(struct net_device *netdev, - struct vlan_group *grp) -{ - struct qlcnic_adapter *adapter = netdev_priv(netdev); - adapter->vlgrp = grp; -} - static const struct net_device_ops qlcnic_netdev_ops = { .ndo_open = qlcnic_open, .ndo_stop = qlcnic_close, @@ -334,7 +329,8 @@ static const struct net_device_ops qlcnic_netdev_ops = { .ndo_set_mac_address = qlcnic_set_mac, .ndo_change_mtu = qlcnic_change_mtu, .ndo_tx_timeout = qlcnic_tx_timeout, - .ndo_vlan_rx_register = qlcnic_vlan_rx_register, + .ndo_vlan_rx_add_vid = qlcnic_vlan_rx_add, + .ndo_vlan_rx_kill_vid = qlcnic_vlan_rx_del, #ifdef CONFIG_NET_POLL_CONTROLLER .ndo_poll_controller = qlcnic_poll_controller, #endif @@ -710,6 +706,22 @@ qlcnic_set_vlan_config(struct qlcnic_adapter *adapter, } static void +qlcnic_vlan_rx_add(struct net_device *netdev, u16 vid) +{ + struct qlcnic_adapter *adapter = netdev_priv(netdev); + set_bit(vid, adapter->vlans); +} + +static void +qlcnic_vlan_rx_del(struct net_device *netdev, u16 vid) +{ + struct qlcnic_adapter *adapter = netdev_priv(netdev); + + qlcnic_restore_indev_addr(netdev, NETDEV_DOWN); + clear_bit(vid, adapter->vlans); +} + +static void qlcnic_set_eswitch_port_features(struct qlcnic_adapter *adapter, struct qlcnic_esw_func_cfg *esw_cfg) { @@ -755,7 +767,7 @@ qlcnic_set_netdev_features(struct qlcnic_adapter *adapter, features = (NETIF_F_SG | NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM | NETIF_F_GRO); vlan_features = (NETIF_F_SG | NETIF_F_IP_CSUM | - NETIF_F_IPV6_CSUM); + NETIF_F_IPV6_CSUM | NETIF_F_HW_VLAN_FILTER); if (adapter->capabilities & QLCNIC_FW_CAPABILITY_TSO) { features |= (NETIF_F_TSO | NETIF_F_TSO6); @@ -1448,7 +1460,7 @@ qlcnic_setup_netdev(struct qlcnic_adapter *adapter, netdev->features |= (NETIF_F_SG | NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM | NETIF_F_GRO | NETIF_F_HW_VLAN_RX); netdev->vlan_features |= (NETIF_F_SG | NETIF_F_IP_CSUM | - NETIF_F_IPV6_CSUM); + NETIF_F_IPV6_CSUM | NETIF_F_HW_VLAN_FILTER); if (adapter->capabilities & QLCNIC_FW_CAPABILITY_TSO) { netdev->features |= (NETIF_F_TSO | NETIF_F_TSO6); @@ -4068,14 +4080,10 @@ qlcnic_restore_indev_addr(struct net_device *netdev, unsigned long event) qlcnic_config_indev_addr(adapter, netdev, event); - if (!adapter->vlgrp) - return; - - for (vid = 0; vid < VLAN_N_VID; vid++) { - dev = vlan_group_get_device(adapter->vlgrp, vid); + for_each_set_bit(vid, adapter->vlans, VLAN_N_VID) { + dev = vlan_find_dev(netdev, vid); if (!dev) continue; - qlcnic_config_indev_addr(adapter, dev, event); } } -- cgit v0.10.2 From 8816d0099b9c0f48452b69471c2f54037f7e0e3b Mon Sep 17 00:00:00 2001 From: Anirban Chakraborty Date: Fri, 1 Apr 2011 14:28:21 +0000 Subject: qlcnic: Remove unused code Cleaned up unused codes for interrupt coalescence settings Signed-off-by: Anirban Chakraborty Signed-off-by: David S. Miller diff --git a/drivers/net/qlcnic/qlcnic.h b/drivers/net/qlcnic/qlcnic.h index be9c329..9d2e630 100644 --- a/drivers/net/qlcnic/qlcnic.h +++ b/drivers/net/qlcnic/qlcnic.h @@ -392,6 +392,25 @@ struct qlcnic_rx_buffer { #define QLCNIC_XGBE 0x02 /* + * Interrupt coalescing defaults. The defaults are for 1500 MTU. It is + * adjusted based on configured MTU. + */ +#define QLCNIC_DEFAULT_INTR_COALESCE_RX_TIME_US 3 +#define QLCNIC_DEFAULT_INTR_COALESCE_RX_PACKETS 256 + +#define QLCNIC_INTR_DEFAULT 0x04 +#define QLCNIC_CONFIG_INTR_COALESCE 3 + +struct qlcnic_nic_intr_coalesce { + u8 type; + u8 sts_ring_mask; + u16 rx_packets; + u16 rx_time_us; + u16 flag; + u32 timer_out; +}; + +/* * One hardware_context{} per adapter * contains interrupt info as well shared hardware info. */ @@ -409,6 +428,8 @@ struct qlcnic_hardware_context { u8 linkup; u16 port_type; u16 board_type; + + struct qlcnic_nic_intr_coalesce coal; }; struct qlcnic_adapter_stats { @@ -721,40 +742,6 @@ struct qlcnic_mac_list_s { uint8_t mac_addr[ETH_ALEN+2]; }; -/* - * Interrupt coalescing defaults. The defaults are for 1500 MTU. It is - * adjusted based on configured MTU. - */ -#define QLCNIC_DEFAULT_INTR_COALESCE_RX_TIME_US 3 -#define QLCNIC_DEFAULT_INTR_COALESCE_RX_PACKETS 256 -#define QLCNIC_DEFAULT_INTR_COALESCE_TX_PACKETS 64 -#define QLCNIC_DEFAULT_INTR_COALESCE_TX_TIME_US 4 - -#define QLCNIC_INTR_DEFAULT 0x04 - -union qlcnic_nic_intr_coalesce_data { - struct { - u16 rx_packets; - u16 rx_time_us; - u16 tx_packets; - u16 tx_time_us; - } data; - u64 word; -}; - -struct qlcnic_nic_intr_coalesce { - u16 stats_time_us; - u16 rate_sample_time; - u16 flags; - u16 rsvd_1; - u32 low_threshold; - u32 high_threshold; - union qlcnic_nic_intr_coalesce_data normal; - union qlcnic_nic_intr_coalesce_data low; - union qlcnic_nic_intr_coalesce_data high; - union qlcnic_nic_intr_coalesce_data irq; -}; - #define QLCNIC_HOST_REQUEST 0x13 #define QLCNIC_REQUEST 0x14 @@ -1002,7 +989,6 @@ struct qlcnic_adapter { struct delayed_work fw_work; - struct qlcnic_nic_intr_coalesce coal; struct qlcnic_filter_hash fhash; diff --git a/drivers/net/qlcnic/qlcnic_ethtool.c b/drivers/net/qlcnic/qlcnic_ethtool.c index 7e53cad..24a79a6 100644 --- a/drivers/net/qlcnic/qlcnic_ethtool.c +++ b/drivers/net/qlcnic/qlcnic_ethtool.c @@ -936,8 +936,8 @@ static int qlcnic_set_intr_coalesce(struct net_device *netdev, */ if (ethcoal->rx_coalesce_usecs > 0xffff || ethcoal->rx_max_coalesced_frames > 0xffff || - ethcoal->tx_coalesce_usecs > 0xffff || - ethcoal->tx_max_coalesced_frames > 0xffff || + ethcoal->tx_coalesce_usecs || + ethcoal->tx_max_coalesced_frames || ethcoal->rx_coalesce_usecs_irq || ethcoal->rx_max_coalesced_frames_irq || ethcoal->tx_coalesce_usecs_irq || @@ -959,21 +959,17 @@ static int qlcnic_set_intr_coalesce(struct net_device *netdev, if (!ethcoal->rx_coalesce_usecs || !ethcoal->rx_max_coalesced_frames) { - adapter->coal.flags = QLCNIC_INTR_DEFAULT; - adapter->coal.normal.data.rx_time_us = + adapter->ahw->coal.flag = QLCNIC_INTR_DEFAULT; + adapter->ahw->coal.rx_time_us = QLCNIC_DEFAULT_INTR_COALESCE_RX_TIME_US; - adapter->coal.normal.data.rx_packets = + adapter->ahw->coal.rx_packets = QLCNIC_DEFAULT_INTR_COALESCE_RX_PACKETS; } else { - adapter->coal.flags = 0; - adapter->coal.normal.data.rx_time_us = - ethcoal->rx_coalesce_usecs; - adapter->coal.normal.data.rx_packets = - ethcoal->rx_max_coalesced_frames; + adapter->ahw->coal.flag = 0; + adapter->ahw->coal.rx_time_us = ethcoal->rx_coalesce_usecs; + adapter->ahw->coal.rx_packets = + ethcoal->rx_max_coalesced_frames; } - adapter->coal.normal.data.tx_time_us = ethcoal->tx_coalesce_usecs; - adapter->coal.normal.data.tx_packets = - ethcoal->tx_max_coalesced_frames; qlcnic_config_intr_coalesce(adapter); @@ -988,12 +984,8 @@ static int qlcnic_get_intr_coalesce(struct net_device *netdev, if (adapter->is_up != QLCNIC_ADAPTER_UP_MAGIC) return -EINVAL; - ethcoal->rx_coalesce_usecs = adapter->coal.normal.data.rx_time_us; - ethcoal->tx_coalesce_usecs = adapter->coal.normal.data.tx_time_us; - ethcoal->rx_max_coalesced_frames = - adapter->coal.normal.data.rx_packets; - ethcoal->tx_max_coalesced_frames = - adapter->coal.normal.data.tx_packets; + ethcoal->rx_coalesce_usecs = adapter->ahw->coal.rx_time_us; + ethcoal->rx_max_coalesced_frames = adapter->ahw->coal.rx_packets; return 0; } diff --git a/drivers/net/qlcnic/qlcnic_hw.c b/drivers/net/qlcnic/qlcnic_hw.c index 7e3f526..3901be8 100644 --- a/drivers/net/qlcnic/qlcnic_hw.c +++ b/drivers/net/qlcnic/qlcnic_hw.c @@ -532,33 +532,31 @@ void qlcnic_delete_lb_filters(struct qlcnic_adapter *adapter) } } -#define QLCNIC_CONFIG_INTR_COALESCE 3 - /* * Send the interrupt coalescing parameter set by ethtool to the card. */ int qlcnic_config_intr_coalesce(struct qlcnic_adapter *adapter) { struct qlcnic_nic_req req; - u64 word[6]; - int rv, i; + int rv; memset(&req, 0, sizeof(struct qlcnic_nic_req)); req.qhdr = cpu_to_le64(QLCNIC_HOST_REQUEST << 23); - word[0] = QLCNIC_CONFIG_INTR_COALESCE | ((u64)adapter->portnum << 16); - req.req_hdr = cpu_to_le64(word[0]); - - memcpy(&word[0], &adapter->coal, sizeof(adapter->coal)); - for (i = 0; i < 6; i++) - req.words[i] = cpu_to_le64(word[i]); + req.req_hdr = cpu_to_le64(QLCNIC_CONFIG_INTR_COALESCE | + ((u64) adapter->portnum << 16)); + req.words[0] = cpu_to_le64(((u64) adapter->ahw->coal.flag) << 32); + req.words[2] = cpu_to_le64(adapter->ahw->coal.rx_packets | + ((u64) adapter->ahw->coal.rx_time_us) << 16); + req.words[5] = cpu_to_le64(adapter->ahw->coal.timer_out | + ((u64) adapter->ahw->coal.type) << 32 | + ((u64) adapter->ahw->coal.sts_ring_mask) << 40); rv = qlcnic_send_cmd_descs(adapter, (struct cmd_desc_type0 *)&req, 1); if (rv != 0) dev_err(&adapter->netdev->dev, "Could not send interrupt coalescing parameters\n"); - return rv; } diff --git a/drivers/net/qlcnic/qlcnic_main.c b/drivers/net/qlcnic/qlcnic_main.c index b75aef0..8bf9a96 100644 --- a/drivers/net/qlcnic/qlcnic_main.c +++ b/drivers/net/qlcnic/qlcnic_main.c @@ -1097,20 +1097,6 @@ qlcnic_free_irq(struct qlcnic_adapter *adapter) } } -static void -qlcnic_init_coalesce_defaults(struct qlcnic_adapter *adapter) -{ - adapter->coal.flags = QLCNIC_INTR_DEFAULT; - adapter->coal.normal.data.rx_time_us = - QLCNIC_DEFAULT_INTR_COALESCE_RX_TIME_US; - adapter->coal.normal.data.rx_packets = - QLCNIC_DEFAULT_INTR_COALESCE_RX_PACKETS; - adapter->coal.normal.data.tx_time_us = - QLCNIC_DEFAULT_INTR_COALESCE_TX_TIME_US; - adapter->coal.normal.data.tx_packets = - QLCNIC_DEFAULT_INTR_COALESCE_TX_PACKETS; -} - static int __qlcnic_up(struct qlcnic_adapter *adapter, struct net_device *netdev) { @@ -1244,8 +1230,6 @@ qlcnic_attach(struct qlcnic_adapter *adapter) goto err_out_free_hw; } - qlcnic_init_coalesce_defaults(adapter); - qlcnic_create_sysfs_entries(adapter); adapter->is_up = QLCNIC_ADAPTER_UP_MAGIC; @@ -1326,7 +1310,12 @@ static int qlcnic_alloc_adapter_resources(struct qlcnic_adapter *adapter) kfree(adapter->ahw); adapter->ahw = NULL; err = -ENOMEM; + goto err_out; } + /* Initialize interrupt coalesce parameters */ + adapter->ahw->coal.flag = QLCNIC_INTR_DEFAULT; + adapter->ahw->coal.rx_time_us = QLCNIC_DEFAULT_INTR_COALESCE_RX_TIME_US; + adapter->ahw->coal.rx_packets = QLCNIC_DEFAULT_INTR_COALESCE_RX_PACKETS; err_out: return err; } -- cgit v0.10.2 From f8d54811cb125094769704722e4eda6610339b92 Mon Sep 17 00:00:00 2001 From: Sritej Velaga Date: Fri, 1 Apr 2011 14:28:26 +0000 Subject: qlcnic: Use flt method to determine flash fw region Use flash layout table to get flash fw starting address and its size. If that fails, use legacy method. Signed-off-by: Sritej Velaga Signed-off-by: Anirban Chakraborty Signed-off-by: David S. Miller diff --git a/drivers/net/qlcnic/qlcnic.h b/drivers/net/qlcnic/qlcnic.h index 9d2e630..d9dd2c4 100644 --- a/drivers/net/qlcnic/qlcnic.h +++ b/drivers/net/qlcnic/qlcnic.h @@ -292,6 +292,7 @@ struct uni_data_desc{ /* Flash Defines and Structures */ #define QLCNIC_FLT_LOCATION 0x3F1000 #define QLCNIC_FW_IMAGE_REGION 0x74 +#define QLCNIC_BOOTLD_REGION 0X72 struct qlcnic_flt_header { u16 version; u16 len; @@ -306,7 +307,7 @@ struct qlcnic_flt_entry { u8 reserved1; u32 size; u32 start_addr; - u32 end_add; + u32 end_addr; }; /* Magic number to let user know flash is programmed */ diff --git a/drivers/net/qlcnic/qlcnic_init.c b/drivers/net/qlcnic/qlcnic_init.c index 74ec96d..4ec0eeb 100644 --- a/drivers/net/qlcnic/qlcnic_init.c +++ b/drivers/net/qlcnic/qlcnic_init.c @@ -1130,9 +1130,20 @@ qlcnic_load_firmware(struct qlcnic_adapter *adapter) } else { u64 data; u32 hi, lo; - - size = (QLCNIC_IMAGE_START - QLCNIC_BOOTLD_START) / 8; - flashaddr = QLCNIC_BOOTLD_START; + int ret; + struct qlcnic_flt_entry bootld_entry; + + ret = qlcnic_get_flt_entry(adapter, QLCNIC_BOOTLD_REGION, + &bootld_entry); + if (!ret) { + size = bootld_entry.size / 8; + flashaddr = bootld_entry.start_addr; + } else { + size = (QLCNIC_IMAGE_START - QLCNIC_BOOTLD_START) / 8; + flashaddr = QLCNIC_BOOTLD_START; + dev_info(&pdev->dev, + "using legacy method to get flash fw region"); + } for (i = 0; i < size; i++) { if (qlcnic_rom_fast_read(adapter, -- cgit v0.10.2 From b56421d0b7527f8ecea3de030cf508468fdc9ba1 Mon Sep 17 00:00:00 2001 From: Rajesh Borundia Date: Fri, 1 Apr 2011 14:28:31 +0000 Subject: qlcnic: Fix LRO disable o In dev->open LRO was enabled by default, enable it depending upon netdev->features , kernel may have disabled it. o Configure LRO when interface is up. Signed-off-by: Rajesh Borundia Signed-off-by: Anirban Chakraborty Signed-off-by: David S. Miller diff --git a/drivers/net/qlcnic/qlcnic_ethtool.c b/drivers/net/qlcnic/qlcnic_ethtool.c index 24a79a6..6be4d5a 100644 --- a/drivers/net/qlcnic/qlcnic_ethtool.c +++ b/drivers/net/qlcnic/qlcnic_ethtool.c @@ -998,22 +998,28 @@ static int qlcnic_set_flags(struct net_device *netdev, u32 data) if (ethtool_invalid_flags(netdev, data, ETH_FLAG_LRO)) return -EINVAL; - if (!(adapter->capabilities & QLCNIC_FW_CAPABILITY_HW_LRO)) - return -EINVAL; + if (data & ETH_FLAG_LRO) { - if (!adapter->rx_csum) { - dev_info(&adapter->pdev->dev, "rx csum is off, " - "cannot toggle lro\n"); - return -EINVAL; - } + if (netdev->features & NETIF_F_LRO) + return 0; - if ((data & ETH_FLAG_LRO) && (netdev->features & NETIF_F_LRO)) - return 0; + if (!(adapter->capabilities & QLCNIC_FW_CAPABILITY_HW_LRO)) + return -EINVAL; + + if (!adapter->rx_csum) { + dev_info(&adapter->pdev->dev, "rx csum is off, " + "cannot toggle lro\n"); + return -EINVAL; + } - if (data & ETH_FLAG_LRO) { hw_lro = QLCNIC_LRO_ENABLED; netdev->features |= NETIF_F_LRO; + } else { + + if (!(netdev->features & NETIF_F_LRO)) + return 0; + hw_lro = 0; netdev->features &= ~NETIF_F_LRO; } diff --git a/drivers/net/qlcnic/qlcnic_hw.c b/drivers/net/qlcnic/qlcnic_hw.c index 3901be8..498cca9 100644 --- a/drivers/net/qlcnic/qlcnic_hw.c +++ b/drivers/net/qlcnic/qlcnic_hw.c @@ -566,6 +566,9 @@ int qlcnic_config_hw_lro(struct qlcnic_adapter *adapter, int enable) u64 word; int rv; + if (!test_bit(__QLCNIC_FW_ATTACHED, &adapter->state)) + return 0; + memset(&req, 0, sizeof(struct qlcnic_nic_req)); req.qhdr = cpu_to_le64(QLCNIC_HOST_REQUEST << 23); @@ -711,6 +714,9 @@ int qlcnic_send_lro_cleanup(struct qlcnic_adapter *adapter) u64 word; int rv; + if (!test_bit(__QLCNIC_FW_ATTACHED, &adapter->state)) + return 0; + memset(&req, 0, sizeof(struct qlcnic_nic_req)); req.qhdr = cpu_to_le64(QLCNIC_HOST_REQUEST << 23); diff --git a/drivers/net/qlcnic/qlcnic_main.c b/drivers/net/qlcnic/qlcnic_main.c index 8bf9a96..7f9edb2 100644 --- a/drivers/net/qlcnic/qlcnic_main.c +++ b/drivers/net/qlcnic/qlcnic_main.c @@ -773,7 +773,8 @@ qlcnic_set_netdev_features(struct qlcnic_adapter *adapter, features |= (NETIF_F_TSO | NETIF_F_TSO6); vlan_features |= (NETIF_F_TSO | NETIF_F_TSO6); } - if (adapter->capabilities & QLCNIC_FW_CAPABILITY_HW_LRO) + + if (netdev->features & NETIF_F_LRO) features |= NETIF_F_LRO; if (esw_cfg->offload_flags & BIT_0) { -- cgit v0.10.2 From 191350e7887aa6d843f1097fc1de06cb59eb6ac1 Mon Sep 17 00:00:00 2001 From: Anirban Chakraborty Date: Fri, 1 Apr 2011 14:28:36 +0000 Subject: qlcnic: Update version number to 5.0.16 Bumped up version number to 5.0.16 Signed-off-by: Anirban Chakraborty Signed-off-by: David S. Miller diff --git a/drivers/net/qlcnic/qlcnic.h b/drivers/net/qlcnic/qlcnic.h index d9dd2c4..dc6f7c6 100644 --- a/drivers/net/qlcnic/qlcnic.h +++ b/drivers/net/qlcnic/qlcnic.h @@ -36,8 +36,8 @@ #define _QLCNIC_LINUX_MAJOR 5 #define _QLCNIC_LINUX_MINOR 0 -#define _QLCNIC_LINUX_SUBVERSION 15 -#define QLCNIC_LINUX_VERSIONID "5.0.15" +#define _QLCNIC_LINUX_SUBVERSION 16 +#define QLCNIC_LINUX_VERSIONID "5.0.16" #define QLCNIC_DRV_IDC_VER 0x01 #define QLCNIC_DRIVER_VERSION ((_QLCNIC_LINUX_MAJOR << 16) |\ (_QLCNIC_LINUX_MINOR << 8) | (_QLCNIC_LINUX_SUBVERSION)) -- cgit v0.10.2 From 74e532ff3c634f20ee2eefe3f8f0083ea547c74c Mon Sep 17 00:00:00 2001 From: stephen hemminger Date: Mon, 4 Apr 2011 08:43:41 +0000 Subject: sky2: support ethtool set_phys_id Use ethtool set_phys_id to control LED. Fixes issues with RTNL being held for extended periods. Signed-off-by: Stephen Hemminger Signed-off-by: David S. Miller diff --git a/drivers/net/sky2.c b/drivers/net/sky2.c index 2a91868..afc925a 100644 --- a/drivers/net/sky2.c +++ b/drivers/net/sky2.c @@ -3826,23 +3826,24 @@ static void sky2_led(struct sky2_port *sky2, enum led_mode mode) } /* blink LED's for finding board */ -static int sky2_phys_id(struct net_device *dev, u32 data) +static int sky2_set_phys_id(struct net_device *dev, + enum ethtool_phys_id_state state) { struct sky2_port *sky2 = netdev_priv(dev); - unsigned int i; - - if (data == 0) - data = UINT_MAX; - for (i = 0; i < data; i++) { + switch (state) { + case ETHTOOL_ID_ACTIVE: + return -EINVAL; + case ETHTOOL_ID_INACTIVE: + sky2_led(sky2, MO_LED_NORM); + break; + case ETHTOOL_ID_ON: sky2_led(sky2, MO_LED_ON); - if (msleep_interruptible(500)) - break; + break; + case ETHTOOL_ID_OFF: sky2_led(sky2, MO_LED_OFF); - if (msleep_interruptible(500)) - break; + break; } - sky2_led(sky2, MO_LED_NORM); return 0; } @@ -4269,7 +4270,7 @@ static const struct ethtool_ops sky2_ethtool_ops = { .set_ringparam = sky2_set_ringparam, .get_pauseparam = sky2_get_pauseparam, .set_pauseparam = sky2_set_pauseparam, - .phys_id = sky2_phys_id, + .set_phys_id = sky2_set_phys_id, .get_sset_count = sky2_get_sset_count, .get_ethtool_stats = sky2_get_ethtool_stats, .set_flags = sky2_set_flags, -- cgit v0.10.2 From a5b9f41c228f93d368ab0f292d890ea7143ca5aa Mon Sep 17 00:00:00 2001 From: stephen hemminger Date: Mon, 4 Apr 2011 08:43:42 +0000 Subject: skge: implement set_phys_id Implement set_phys_id led control on SysKonnect board. Signed-off-by: Stephen Hemminger Signed-off-by: David S. Miller diff --git a/drivers/net/skge.c b/drivers/net/skge.c index 35b28f4..e579ff7 100644 --- a/drivers/net/skge.c +++ b/drivers/net/skge.c @@ -786,28 +786,27 @@ static void skge_led(struct skge_port *skge, enum led_mode mode) } /* blink LED's for finding board */ -static int skge_phys_id(struct net_device *dev, u32 data) +static int skge_set_phys_id(struct net_device *dev, + enum ethtool_phys_id_state state) { struct skge_port *skge = netdev_priv(dev); - unsigned long ms; - enum led_mode mode = LED_MODE_TST; - if (!data || data > (u32)(MAX_SCHEDULE_TIMEOUT / HZ)) - ms = jiffies_to_msecs(MAX_SCHEDULE_TIMEOUT / HZ) * 1000; - else - ms = data * 1000; + switch (state) { + case ETHTOOL_ID_ACTIVE: + return -EINVAL; - while (ms > 0) { - skge_led(skge, mode); - mode ^= LED_MODE_TST; + case ETHTOOL_ID_ON: + skge_led(skge, LED_MODE_TST); + break; - if (msleep_interruptible(BLINK_MS)) - break; - ms -= BLINK_MS; - } + case ETHTOOL_ID_OFF: + skge_led(skge, LED_MODE_OFF); + break; - /* back to regular LED state */ - skge_led(skge, netif_running(dev) ? LED_MODE_ON : LED_MODE_OFF); + case ETHTOOL_ID_INACTIVE: + /* back to regular LED state */ + skge_led(skge, netif_running(dev) ? LED_MODE_ON : LED_MODE_OFF); + } return 0; } @@ -930,7 +929,7 @@ static const struct ethtool_ops skge_ethtool_ops = { .get_rx_csum = skge_get_rx_csum, .set_rx_csum = skge_set_rx_csum, .get_strings = skge_get_strings, - .phys_id = skge_phys_id, + .set_phys_id = skge_set_phys_id, .get_sset_count = skge_get_sset_count, .get_ethtool_stats = skge_get_ethtool_stats, }; -- cgit v0.10.2 From 81b8709c25e8c8f56224a24d860de7b77a772e83 Mon Sep 17 00:00:00 2001 From: stephen hemminger Date: Mon, 4 Apr 2011 08:43:50 +0000 Subject: tg3: implement ethtool set_phys_id Implement control of LED via set_phys_id. Note: since PHY is powered off if device is down, this board only allows blinking if device is up. Signed-off-by: Stephen Hemminger Signed-off-by: David S. Miller diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index f944c6b..d37ae87 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -10341,35 +10341,38 @@ static void tg3_get_strings(struct net_device *dev, u32 stringset, u8 *buf) } } -static int tg3_phys_id(struct net_device *dev, u32 data) +static int tg3_set_phys_id(struct net_device *dev, + enum ethtool_phys_id_state state) { struct tg3 *tp = netdev_priv(dev); - int i; if (!netif_running(tp->dev)) return -EAGAIN; - if (data == 0) - data = UINT_MAX / 2; + switch (state) { + case ETHTOOL_ID_ACTIVE: + return -EINVAL; - for (i = 0; i < (data * 2); i++) { - if ((i % 2) == 0) - tw32(MAC_LED_CTRL, LED_CTRL_LNKLED_OVERRIDE | - LED_CTRL_1000MBPS_ON | - LED_CTRL_100MBPS_ON | - LED_CTRL_10MBPS_ON | - LED_CTRL_TRAFFIC_OVERRIDE | - LED_CTRL_TRAFFIC_BLINK | - LED_CTRL_TRAFFIC_LED); + case ETHTOOL_ID_ON: + tw32(MAC_LED_CTRL, LED_CTRL_LNKLED_OVERRIDE | + LED_CTRL_1000MBPS_ON | + LED_CTRL_100MBPS_ON | + LED_CTRL_10MBPS_ON | + LED_CTRL_TRAFFIC_OVERRIDE | + LED_CTRL_TRAFFIC_BLINK | + LED_CTRL_TRAFFIC_LED); + break; - else - tw32(MAC_LED_CTRL, LED_CTRL_LNKLED_OVERRIDE | - LED_CTRL_TRAFFIC_OVERRIDE); + case ETHTOOL_ID_OFF: + tw32(MAC_LED_CTRL, LED_CTRL_LNKLED_OVERRIDE | + LED_CTRL_TRAFFIC_OVERRIDE); + break; - if (msleep_interruptible(500)) - break; + case ETHTOOL_ID_INACTIVE: + tw32(MAC_LED_CTRL, tp->led_ctrl); + break; } - tw32(MAC_LED_CTRL, tp->led_ctrl); + return 0; } @@ -11394,7 +11397,7 @@ static const struct ethtool_ops tg3_ethtool_ops = { .set_tso = tg3_set_tso, .self_test = tg3_self_test, .get_strings = tg3_get_strings, - .phys_id = tg3_phys_id, + .set_phys_id = tg3_set_phys_id, .get_ethtool_stats = tg3_get_ethtool_stats, .get_coalesce = tg3_get_coalesce, .set_coalesce = tg3_set_coalesce, -- cgit v0.10.2 From 12fcf941674fd781117a56f998d2bb28b4bc4cf1 Mon Sep 17 00:00:00 2001 From: stephen hemminger Date: Mon, 4 Apr 2011 08:43:51 +0000 Subject: cxgb3: implement set_phys_id Implement new ethtool set_phys_id on Chelsio cxgb3 board. Signed-off-by: Stephen Hemminger Signed-off-by: David S. Miller diff --git a/drivers/net/cxgb3/cxgb3_main.c b/drivers/net/cxgb3/cxgb3_main.c index 9108931..802c7a7 100644 --- a/drivers/net/cxgb3/cxgb3_main.c +++ b/drivers/net/cxgb3/cxgb3_main.c @@ -1749,23 +1749,26 @@ static int restart_autoneg(struct net_device *dev) return 0; } -static int cxgb3_phys_id(struct net_device *dev, u32 data) +static int set_phys_id(struct net_device *dev, + enum ethtool_phys_id_state state) { struct port_info *pi = netdev_priv(dev); struct adapter *adapter = pi->adapter; - int i; - if (data == 0) - data = 2; + switch (state) { + case ETHTOOL_ID_ACTIVE: + return -EINVAL; + + case ETHTOOL_ID_OFF: + t3_set_reg_field(adapter, A_T3DBG_GPIO_EN, F_GPIO0_OUT_VAL, 0); + break; - for (i = 0; i < data * 2; i++) { + case ETHTOOL_ID_ON: + case ETHTOOL_ID_INACTIVE: t3_set_reg_field(adapter, A_T3DBG_GPIO_EN, F_GPIO0_OUT_VAL, - (i & 1) ? F_GPIO0_OUT_VAL : 0); - if (msleep_interruptible(500)) - break; - } - t3_set_reg_field(adapter, A_T3DBG_GPIO_EN, F_GPIO0_OUT_VAL, F_GPIO0_OUT_VAL); + } + return 0; } @@ -2107,7 +2110,7 @@ static const struct ethtool_ops cxgb_ethtool_ops = { .set_sg = ethtool_op_set_sg, .get_link = ethtool_op_get_link, .get_strings = get_strings, - .phys_id = cxgb3_phys_id, + .set_phys_id = set_phys_id, .nway_reset = restart_autoneg, .get_sset_count = get_sset_count, .get_ethtool_stats = get_stats, -- cgit v0.10.2 From 6d8a7e6f52b0bf646739f2d4bad4643c64977b2a Mon Sep 17 00:00:00 2001 From: stephen hemminger Date: Mon, 4 Apr 2011 11:06:35 +0000 Subject: vxge: convert to set_phys_id Also fix up incorrect docbook comment Signed-off-by: Stephen Hemminger Signed-off-by: David S. Miller diff --git a/drivers/net/vxge/vxge-ethtool.c b/drivers/net/vxge/vxge-ethtool.c index c5eb034..43c4583 100644 --- a/drivers/net/vxge/vxge-ethtool.c +++ b/drivers/net/vxge/vxge-ethtool.c @@ -134,22 +134,29 @@ static void vxge_ethtool_gregs(struct net_device *dev, /** * vxge_ethtool_idnic - To physically identify the nic on the system. * @dev : device pointer. - * @id : pointer to the structure with identification parameters given by - * ethtool. + * @state : requested LED state * * Used to physically identify the NIC on the system. - * The Link LED will blink for a time specified by the user. - * Return value: * 0 on success */ -static int vxge_ethtool_idnic(struct net_device *dev, u32 data) +static int vxge_ethtool_idnic(struct net_device *dev, + enum ethtool_phys_id_state state) { struct vxgedev *vdev = netdev_priv(dev); struct __vxge_hw_device *hldev = vdev->devh; - vxge_hw_device_flick_link_led(hldev, VXGE_FLICKER_ON); - msleep_interruptible(data ? (data * HZ) : VXGE_MAX_FLICKER_TIME); - vxge_hw_device_flick_link_led(hldev, VXGE_FLICKER_OFF); + switch (state) { + case ETHTOOL_ID_ACTIVE: + vxge_hw_device_flick_link_led(hldev, VXGE_FLICKER_ON); + break; + + case ETHTOOL_ID_INACTIVE: + vxge_hw_device_flick_link_led(hldev, VXGE_FLICKER_OFF); + break; + + default: + return -EINVAL; + } return 0; } @@ -1183,7 +1190,7 @@ static const struct ethtool_ops vxge_ethtool_ops = { .get_tso = ethtool_op_get_tso, .set_tso = vxge_ethtool_op_set_tso, .get_strings = vxge_ethtool_get_strings, - .phys_id = vxge_ethtool_idnic, + .set_phys_id = vxge_ethtool_idnic, .get_sset_count = vxge_ethtool_get_sset_count, .get_ethtool_stats = vxge_get_ethtool_stats, .set_flags = vxge_set_flags, -- cgit v0.10.2 From 2e17e1aa80e914acd8a31a41b9bf1173186a976a Mon Sep 17 00:00:00 2001 From: stephen hemminger Date: Mon, 4 Apr 2011 11:06:36 +0000 Subject: bnx2: convert to set_phys_id In this case, need to add element to device private to hold original led state. Signed-off-by: Stephen Hemminger Signed-off-by: David S. Miller diff --git a/drivers/net/bnx2.c b/drivers/net/bnx2.c index 8e6d618..05ddfb1 100644 --- a/drivers/net/bnx2.c +++ b/drivers/net/bnx2.c @@ -7495,41 +7495,39 @@ bnx2_get_ethtool_stats(struct net_device *dev, } static int -bnx2_phys_id(struct net_device *dev, u32 data) +bnx2_set_phys_id(struct net_device *dev, enum ethtool_phys_id_state state) { struct bnx2 *bp = netdev_priv(dev); - int i; - u32 save; - bnx2_set_power_state(bp, PCI_D0); + switch (state) { + case ETHTOOL_ID_ACTIVE: + bnx2_set_power_state(bp, PCI_D0); - if (data == 0) - data = 2; + bp->leds_save = REG_RD(bp, BNX2_MISC_CFG); + REG_WR(bp, BNX2_MISC_CFG, BNX2_MISC_CFG_LEDMODE_MAC); + return -EINVAL; - save = REG_RD(bp, BNX2_MISC_CFG); - REG_WR(bp, BNX2_MISC_CFG, BNX2_MISC_CFG_LEDMODE_MAC); + case ETHTOOL_ID_ON: + REG_WR(bp, BNX2_EMAC_LED, BNX2_EMAC_LED_OVERRIDE | + BNX2_EMAC_LED_1000MB_OVERRIDE | + BNX2_EMAC_LED_100MB_OVERRIDE | + BNX2_EMAC_LED_10MB_OVERRIDE | + BNX2_EMAC_LED_TRAFFIC_OVERRIDE | + BNX2_EMAC_LED_TRAFFIC); + break; - for (i = 0; i < (data * 2); i++) { - if ((i % 2) == 0) { - REG_WR(bp, BNX2_EMAC_LED, BNX2_EMAC_LED_OVERRIDE); - } - else { - REG_WR(bp, BNX2_EMAC_LED, BNX2_EMAC_LED_OVERRIDE | - BNX2_EMAC_LED_1000MB_OVERRIDE | - BNX2_EMAC_LED_100MB_OVERRIDE | - BNX2_EMAC_LED_10MB_OVERRIDE | - BNX2_EMAC_LED_TRAFFIC_OVERRIDE | - BNX2_EMAC_LED_TRAFFIC); - } - msleep_interruptible(500); - if (signal_pending(current)) - break; - } - REG_WR(bp, BNX2_EMAC_LED, 0); - REG_WR(bp, BNX2_MISC_CFG, save); + case ETHTOOL_ID_OFF: + REG_WR(bp, BNX2_EMAC_LED, BNX2_EMAC_LED_OVERRIDE); + break; - if (!netif_running(dev)) - bnx2_set_power_state(bp, PCI_D3hot); + case ETHTOOL_ID_INACTIVE: + REG_WR(bp, BNX2_EMAC_LED, 0); + REG_WR(bp, BNX2_MISC_CFG, bp->leds_save); + + if (!netif_running(dev)) + bnx2_set_power_state(bp, PCI_D3hot); + break; + } return 0; } @@ -7602,7 +7600,7 @@ static const struct ethtool_ops bnx2_ethtool_ops = { .set_tso = bnx2_set_tso, .self_test = bnx2_self_test, .get_strings = bnx2_get_strings, - .phys_id = bnx2_phys_id, + .set_phys_id = bnx2_set_phys_id, .get_ethtool_stats = bnx2_get_ethtool_stats, .get_sset_count = bnx2_get_sset_count, .set_flags = bnx2_set_flags, diff --git a/drivers/net/bnx2.h b/drivers/net/bnx2.h index 6802045..91e8356 100644 --- a/drivers/net/bnx2.h +++ b/drivers/net/bnx2.h @@ -6922,6 +6922,7 @@ struct bnx2 { u8 num_tx_rings; u8 num_rx_rings; + u32 leds_save; u32 idle_chk_status_idx; #ifdef BCM_CNIC -- cgit v0.10.2 From 32d3613475d8c7d2170313b9105499dece6a3735 Mon Sep 17 00:00:00 2001 From: stephen hemminger Date: Mon, 4 Apr 2011 11:06:37 +0000 Subject: bnx2x: convert to set_phys_id Also cleanup error codes to no lie about things that driver doesn't support. If device is down report -EAGAIN (same as Broadcom), and if port doesn't blink then error as well. Signed-off-by: Stephen Hemminger Signed-off-by: David S. Miller diff --git a/drivers/net/bnx2x/bnx2x_ethtool.c b/drivers/net/bnx2x/bnx2x_ethtool.c index f505015..1479994 100644 --- a/drivers/net/bnx2x/bnx2x_ethtool.c +++ b/drivers/net/bnx2x/bnx2x_ethtool.c @@ -2097,36 +2097,38 @@ static void bnx2x_get_ethtool_stats(struct net_device *dev, } } -static int bnx2x_phys_id(struct net_device *dev, u32 data) +static int bnx2x_set_phys_id(struct net_device *dev, + enum ethtool_phys_id_state state) { struct bnx2x *bp = netdev_priv(dev); - int i; if (!netif_running(dev)) - return 0; + return -EAGAIN; if (!bp->port.pmf) - return 0; + return -EOPNOTSUPP; - if (data == 0) - data = 2; + switch (state) { + case ETHTOOL_ID_ACTIVE: + return -EINVAL; - for (i = 0; i < (data * 2); i++) { - if ((i % 2) == 0) - bnx2x_set_led(&bp->link_params, &bp->link_vars, - LED_MODE_OPER, SPEED_1000); - else - bnx2x_set_led(&bp->link_params, &bp->link_vars, - LED_MODE_OFF, 0); + case ETHTOOL_ID_ON: + bnx2x_set_led(&bp->link_params, &bp->link_vars, + LED_MODE_OPER, SPEED_1000); + break; - msleep_interruptible(500); - if (signal_pending(current)) - break; - } + case ETHTOOL_ID_OFF: + bnx2x_set_led(&bp->link_params, &bp->link_vars, + LED_MODE_OFF, 0); - if (bp->link_vars.link_up) - bnx2x_set_led(&bp->link_params, &bp->link_vars, LED_MODE_OPER, - bp->link_vars.line_speed); + break; + + case ETHTOOL_ID_INACTIVE: + if (bp->link_vars.link_up) + bnx2x_set_led(&bp->link_params, &bp->link_vars, + LED_MODE_OPER, + bp->link_vars.line_speed); + } return 0; } @@ -2218,7 +2220,7 @@ static const struct ethtool_ops bnx2x_ethtool_ops = { .self_test = bnx2x_self_test, .get_sset_count = bnx2x_get_sset_count, .get_strings = bnx2x_get_strings, - .phys_id = bnx2x_phys_id, + .set_phys_id = bnx2x_set_phys_id, .get_ethtool_stats = bnx2x_get_ethtool_stats, .get_rxnfc = bnx2x_get_rxnfc, .get_rxfh_indir = bnx2x_get_rxfh_indir, -- cgit v0.10.2 From 1a64246913849b0cef0be88c23381468ce169ab6 Mon Sep 17 00:00:00 2001 From: stephen hemminger Date: Mon, 4 Apr 2011 11:06:40 +0000 Subject: benet: convert to set_phys_id Signed-off-by: Stephen Hemminger Signed-off-by: David S. Miller diff --git a/drivers/net/benet/be.h b/drivers/net/benet/be.h index 3937bca..0899d91 100644 --- a/drivers/net/benet/be.h +++ b/drivers/net/benet/be.h @@ -313,6 +313,7 @@ struct be_adapter { char fw_ver[FW_VER_LEN]; u32 if_handle; /* Used to configure filtering */ u32 pmac_id; /* MAC addr handle used by BE card */ + u32 beacon_state; /* for set_phys_id */ bool eeh_err; bool link_up; diff --git a/drivers/net/benet/be_ethtool.c b/drivers/net/benet/be_ethtool.c index 575ac659..a665697 100644 --- a/drivers/net/benet/be_ethtool.c +++ b/drivers/net/benet/be_ethtool.c @@ -526,29 +526,33 @@ be_set_pauseparam(struct net_device *netdev, struct ethtool_pauseparam *ecmd) } static int -be_phys_id(struct net_device *netdev, u32 data) +be_set_phys_id(struct net_device *netdev, + enum ethtool_phys_id_state state) { struct be_adapter *adapter = netdev_priv(netdev); - int status; - u32 cur; - - be_cmd_get_beacon_state(adapter, adapter->hba_port_num, &cur); - if (cur == BEACON_STATE_ENABLED) - return 0; + switch (state) { + case ETHTOOL_ID_ACTIVE: + be_cmd_get_beacon_state(adapter, adapter->hba_port_num, + &adapter->beacon_state); + return -EINVAL; - if (data < 2) - data = 2; + case ETHTOOL_ID_ON: + be_cmd_set_beacon_state(adapter, adapter->hba_port_num, 0, 0, + BEACON_STATE_ENABLED); + break; - status = be_cmd_set_beacon_state(adapter, adapter->hba_port_num, 0, 0, - BEACON_STATE_ENABLED); - set_current_state(TASK_INTERRUPTIBLE); - schedule_timeout(data*HZ); + case ETHTOOL_ID_OFF: + be_cmd_set_beacon_state(adapter, adapter->hba_port_num, 0, 0, + BEACON_STATE_DISABLED); + break; - status = be_cmd_set_beacon_state(adapter, adapter->hba_port_num, 0, 0, - BEACON_STATE_DISABLED); + case ETHTOOL_ID_INACTIVE: + be_cmd_set_beacon_state(adapter, adapter->hba_port_num, 0, 0, + adapter->beacon_state); + } - return status; + return 0; } static bool @@ -753,7 +757,7 @@ const struct ethtool_ops be_ethtool_ops = { .get_tso = ethtool_op_get_tso, .set_tso = ethtool_op_set_tso, .get_strings = be_get_stat_strings, - .phys_id = be_phys_id, + .set_phys_id = be_set_phys_id, .get_sset_count = be_get_sset_count, .get_ethtool_stats = be_get_ethtool_stats, .get_regs_len = be_get_reg_len, -- cgit v0.10.2 From 9871acf67c9af89c1e17aee907a3f36e88ccfb67 Mon Sep 17 00:00:00 2001 From: stephen hemminger Date: Mon, 4 Apr 2011 11:06:41 +0000 Subject: pcnet32: convert to set_phys_id Signed-off-by: Stephen Hemminger Signed-off-by: David S. Miller diff --git a/drivers/net/pcnet32.c b/drivers/net/pcnet32.c index aee3bb0..eb7ac4e 100644 --- a/drivers/net/pcnet32.c +++ b/drivers/net/pcnet32.c @@ -295,12 +295,14 @@ struct pcnet32_private { struct net_device *next; struct mii_if_info mii_if; struct timer_list watchdog_timer; - struct timer_list blink_timer; u32 msg_enable; /* debug message level */ /* each bit indicates an available PHY */ u32 phymask; unsigned short chip_version; /* which variant this is */ + + /* saved registers during ethtool blink */ + u16 save_regs[4]; }; static int pcnet32_probe_pci(struct pci_dev *, const struct pci_device_id *); @@ -324,8 +326,6 @@ static void pcnet32_restart(struct net_device *dev, unsigned int csr0_bits); static void pcnet32_ethtool_test(struct net_device *dev, struct ethtool_test *eth_test, u64 * data); static int pcnet32_loopback_test(struct net_device *dev, uint64_t * data1); -static int pcnet32_phys_id(struct net_device *dev, u32 data); -static void pcnet32_led_blink_callback(struct net_device *dev); static int pcnet32_get_regs_len(struct net_device *dev); static void pcnet32_get_regs(struct net_device *dev, struct ethtool_regs *regs, void *ptr); @@ -1022,7 +1022,8 @@ clean_up: return rc; } /* end pcnet32_loopback_test */ -static void pcnet32_led_blink_callback(struct net_device *dev) +static int pcnet32_set_phys_id(struct net_device *dev, + enum ethtool_phys_id_state state) { struct pcnet32_private *lp = netdev_priv(dev); struct pcnet32_access *a = &lp->a; @@ -1030,50 +1031,31 @@ static void pcnet32_led_blink_callback(struct net_device *dev) unsigned long flags; int i; - spin_lock_irqsave(&lp->lock, flags); - for (i = 4; i < 8; i++) - a->write_bcr(ioaddr, i, a->read_bcr(ioaddr, i) ^ 0x4000); - spin_unlock_irqrestore(&lp->lock, flags); - - mod_timer(&lp->blink_timer, PCNET32_BLINK_TIMEOUT); -} + switch (state) { + case ETHTOOL_ID_ACTIVE: + /* Save the current value of the bcrs */ + spin_lock_irqsave(&lp->lock, flags); + for (i = 4; i < 8; i++) + lp->save_regs[i - 4] = a->read_bcr(ioaddr, i); + spin_unlock_irqrestore(&lp->lock, flags); + return -EINVAL; -static int pcnet32_phys_id(struct net_device *dev, u32 data) -{ - struct pcnet32_private *lp = netdev_priv(dev); - struct pcnet32_access *a = &lp->a; - ulong ioaddr = dev->base_addr; - unsigned long flags; - int i, regs[4]; + case ETHTOOL_ID_ON: + case ETHTOOL_ID_OFF: + /* Blink the led */ + spin_lock_irqsave(&lp->lock, flags); + for (i = 4; i < 8; i++) + a->write_bcr(ioaddr, i, a->read_bcr(ioaddr, i) ^ 0x4000); + spin_unlock_irqrestore(&lp->lock, flags); + break; - if (!lp->blink_timer.function) { - init_timer(&lp->blink_timer); - lp->blink_timer.function = (void *)pcnet32_led_blink_callback; - lp->blink_timer.data = (unsigned long)dev; + case ETHTOOL_ID_INACTIVE: + /* Restore the original value of the bcrs */ + spin_lock_irqsave(&lp->lock, flags); + for (i = 4; i < 8; i++) + a->write_bcr(ioaddr, i, lp->save_regs[i - 4]); + spin_unlock_irqrestore(&lp->lock, flags); } - - /* Save the current value of the bcrs */ - spin_lock_irqsave(&lp->lock, flags); - for (i = 4; i < 8; i++) - regs[i - 4] = a->read_bcr(ioaddr, i); - spin_unlock_irqrestore(&lp->lock, flags); - - mod_timer(&lp->blink_timer, jiffies); - set_current_state(TASK_INTERRUPTIBLE); - - /* AV: the limit here makes no sense whatsoever */ - if ((!data) || (data > (u32) (MAX_SCHEDULE_TIMEOUT / HZ))) - data = (u32) (MAX_SCHEDULE_TIMEOUT / HZ); - - msleep_interruptible(data * 1000); - del_timer_sync(&lp->blink_timer); - - /* Restore the original value of the bcrs */ - spin_lock_irqsave(&lp->lock, flags); - for (i = 4; i < 8; i++) - a->write_bcr(ioaddr, i, regs[i - 4]); - spin_unlock_irqrestore(&lp->lock, flags); - return 0; } @@ -1450,7 +1432,7 @@ static const struct ethtool_ops pcnet32_ethtool_ops = { .set_ringparam = pcnet32_set_ringparam, .get_strings = pcnet32_get_strings, .self_test = pcnet32_ethtool_test, - .phys_id = pcnet32_phys_id, + .set_phys_id = pcnet32_set_phys_id, .get_regs_len = pcnet32_get_regs_len, .get_regs = pcnet32_get_regs, .get_sset_count = pcnet32_get_sset_count, -- cgit v0.10.2 From 7bc93714042418cbc4ca89c51d3ab448ea3ef2fe Mon Sep 17 00:00:00 2001 From: stephen hemminger Date: Mon, 4 Apr 2011 12:31:19 +0000 Subject: niu: convert to new ethtool set_phys_id Signed-off-by: Stephen Hemminger Signed-off-by: David S. Miller diff --git a/drivers/net/niu.c b/drivers/net/niu.c index 681a42c..ab4e7dd 100644 --- a/drivers/net/niu.c +++ b/drivers/net/niu.c @@ -7888,28 +7888,31 @@ static void niu_force_led(struct niu *np, int on) nw64_mac(reg, val); } -static int niu_phys_id(struct net_device *dev, u32 data) +static int niu_set_phys_id(struct net_device *dev, + enum ethtool_phys_id_state state) + { struct niu *np = netdev_priv(dev); - u64 orig_led_state; - int i; if (!netif_running(dev)) return -EAGAIN; - if (data == 0) - data = 2; + switch (state) { + case ETHTOOL_ID_ACTIVE: + np->orig_led_state = niu_led_state_save(np); + return -EINVAL; - orig_led_state = niu_led_state_save(np); - for (i = 0; i < (data * 2); i++) { - int on = ((i % 2) == 0); + case ETHTOOL_ID_ON: + niu_force_led(np, 1); + break; - niu_force_led(np, on); + case ETHTOOL_ID_OFF: + niu_force_led(np, 0); + break; - if (msleep_interruptible(500)) - break; + case ETHTOOL_ID_INACTIVE: + niu_led_state_restore(np, np->orig_led_state); } - niu_led_state_restore(np, orig_led_state); return 0; } @@ -7932,7 +7935,7 @@ static const struct ethtool_ops niu_ethtool_ops = { .get_strings = niu_get_strings, .get_sset_count = niu_get_sset_count, .get_ethtool_stats = niu_get_ethtool_stats, - .phys_id = niu_phys_id, + .set_phys_id = niu_set_phys_id, .get_rxnfc = niu_get_nfc, .set_rxnfc = niu_set_nfc, .set_flags = niu_set_flags, diff --git a/drivers/net/niu.h b/drivers/net/niu.h index a41fa8e..51e177e 100644 --- a/drivers/net/niu.h +++ b/drivers/net/niu.h @@ -3279,6 +3279,7 @@ struct niu { unsigned long xpcs_off; struct timer_list timer; + u64 orig_led_state; const struct niu_phy_ops *phy_ops; int phy_addr; -- cgit v0.10.2 From 034e345081cfb442abeb0e00fa26edeedb5ba96a Mon Sep 17 00:00:00 2001 From: stephen hemminger Date: Mon, 4 Apr 2011 15:09:25 +0000 Subject: s2io: convert to set_phys_id (v2) Convert to new ethtool set physical id model. Remove no longer used timer, and fix docbook comment. Signed-off-by: Stephen Hemminger Signed-off-by: David S. Miller diff --git a/drivers/net/s2io.c b/drivers/net/s2io.c index 356e74d..cae08ed 100644 --- a/drivers/net/s2io.c +++ b/drivers/net/s2io.c @@ -5484,83 +5484,79 @@ static void s2io_ethtool_gregs(struct net_device *dev, } } -/** - * s2io_phy_id - timer function that alternates adapter LED. - * @data : address of the private member of the device structure, which - * is a pointer to the s2io_nic structure, provided as an u32. - * Description: This is actually the timer function that alternates the - * adapter LED bit of the adapter control bit to set/reset every time on - * invocation. The timer is set for 1/2 a second, hence tha NIC blinks - * once every second. +/* + * s2io_set_led - control NIC led */ -static void s2io_phy_id(unsigned long data) +static void s2io_set_led(struct s2io_nic *sp, bool on) { - struct s2io_nic *sp = (struct s2io_nic *)data; struct XENA_dev_config __iomem *bar0 = sp->bar0; - u64 val64 = 0; - u16 subid; + u16 subid = sp->pdev->subsystem_device; + u64 val64; - subid = sp->pdev->subsystem_device; if ((sp->device_type == XFRAME_II_DEVICE) || ((subid & 0xFF) >= 0x07)) { val64 = readq(&bar0->gpio_control); - val64 ^= GPIO_CTRL_GPIO_0; + if (on) + val64 |= GPIO_CTRL_GPIO_0; + else + val64 &= ~GPIO_CTRL_GPIO_0; + writeq(val64, &bar0->gpio_control); } else { val64 = readq(&bar0->adapter_control); - val64 ^= ADAPTER_LED_ON; + if (on) + val64 |= ADAPTER_LED_ON; + else + val64 &= ~ADAPTER_LED_ON; + writeq(val64, &bar0->adapter_control); } - mod_timer(&sp->id_timer, jiffies + HZ / 2); } /** - * s2io_ethtool_idnic - To physically identify the nic on the system. - * @sp : private member of the device structure, which is a pointer to the - * s2io_nic structure. - * @id : pointer to the structure with identification parameters given by - * ethtool. + * s2io_ethtool_set_led - To physically identify the nic on the system. + * @dev : network device + * @state: led setting + * * Description: Used to physically identify the NIC on the system. * The Link LED will blink for a time specified by the user for * identification. * NOTE: The Link has to be Up to be able to blink the LED. Hence * identification is possible only if it's link is up. - * Return value: - * int , returns 0 on success */ -static int s2io_ethtool_idnic(struct net_device *dev, u32 data) +static int s2io_ethtool_set_led(struct net_device *dev, + enum ethtool_phys_id_state state) { - u64 val64 = 0, last_gpio_ctrl_val; struct s2io_nic *sp = netdev_priv(dev); struct XENA_dev_config __iomem *bar0 = sp->bar0; - u16 subid; + u16 subid = sp->pdev->subsystem_device; - subid = sp->pdev->subsystem_device; - last_gpio_ctrl_val = readq(&bar0->gpio_control); if ((sp->device_type == XFRAME_I_DEVICE) && ((subid & 0xFF) < 0x07)) { - val64 = readq(&bar0->adapter_control); + u64 val64 = readq(&bar0->adapter_control); if (!(val64 & ADAPTER_CNTL_EN)) { pr_err("Adapter Link down, cannot blink LED\n"); - return -EFAULT; + return -EAGAIN; } } - if (sp->id_timer.function == NULL) { - init_timer(&sp->id_timer); - sp->id_timer.function = s2io_phy_id; - sp->id_timer.data = (unsigned long)sp; - } - mod_timer(&sp->id_timer, jiffies); - if (data) - msleep_interruptible(data * HZ); - else - msleep_interruptible(MAX_FLICKER_TIME); - del_timer_sync(&sp->id_timer); - if (CARDS_WITH_FAULTY_LINK_INDICATORS(sp->device_type, subid)) { - writeq(last_gpio_ctrl_val, &bar0->gpio_control); - last_gpio_ctrl_val = readq(&bar0->gpio_control); + switch (state) { + case ETHTOOL_ID_ACTIVE: + sp->adapt_ctrl_org = readq(&bar0->gpio_control); + return -EINVAL; + + case ETHTOOL_ID_ON: + s2io_set_led(sp, true); + break; + + case ETHTOOL_ID_OFF: + s2io_set_led(sp, false); + break; + + case ETHTOOL_ID_INACTIVE: + if (CARDS_WITH_FAULTY_LINK_INDICATORS(sp->device_type, subid)) + writeq(sp->adapt_ctrl_org, &bar0->gpio_control); } return 0; @@ -6776,7 +6772,7 @@ static const struct ethtool_ops netdev_ethtool_ops = { .set_ufo = ethtool_op_set_ufo, .self_test = s2io_ethtool_test, .get_strings = s2io_ethtool_get_strings, - .phys_id = s2io_ethtool_idnic, + .set_phys_id = s2io_ethtool_set_led, .get_ethtool_stats = s2io_get_ethtool_stats, .get_sset_count = s2io_get_sset_count, }; diff --git a/drivers/net/s2io.h b/drivers/net/s2io.h index 7d16030..6b5c023 100644 --- a/drivers/net/s2io.h +++ b/drivers/net/s2io.h @@ -893,9 +893,6 @@ struct s2io_nic { u16 all_multi_pos; u16 promisc_flg; - /* Id timer, used to blink NIC to physically identify NIC. */ - struct timer_list id_timer; - /* Restart timer, used to restart NIC if the device is stuck and * a schedule task that will set the correct Link state once the * NIC's PHY has stabilized after a state change. -- cgit v0.10.2 From 17938a6983d634a909d9779143a8dc2922720de5 Mon Sep 17 00:00:00 2001 From: Ian Campbell Date: Sun, 3 Apr 2011 22:26:24 +0000 Subject: Signed bit field; int have_hotplug_status_watch:1 Fixes error from sparse: CHECK drivers/net/xen-netback/xenbus.c drivers/net/xen-netback/xenbus.c:29:40: error: dubious one-bit signed bitfield int have_hotplug_status_watch:1; Reported-by: Dr. David Alan Gilbert Signed-off-by: Ian Campbell Signed-off-by: David S. Miller diff --git a/drivers/net/xen-netback/xenbus.c b/drivers/net/xen-netback/xenbus.c index 22b8c35..1ce729d 100644 --- a/drivers/net/xen-netback/xenbus.c +++ b/drivers/net/xen-netback/xenbus.c @@ -26,7 +26,7 @@ struct backend_info { struct xenvif *vif; enum xenbus_state frontend_state; struct xenbus_watch hotplug_status_watch; - int have_hotplug_status_watch:1; + u8 have_hotplug_status_watch:1; }; static int connect_rings(struct backend_info *); -- cgit v0.10.2 From 1f90d6657c1ce2eaa4c7fbd1fb36738542f2b650 Mon Sep 17 00:00:00 2001 From: Jan Kiszka Date: Wed, 6 Apr 2011 10:58:37 +0000 Subject: capi: Perform scheduled capifs removal udev fully replaces this special file system that only contains CAPI NCCI TTY device nodes. User space (pppdcapiplugin) works without noticing the difference. Signed-off-by: Jan Kiszka Signed-off-by: David S. Miller diff --git a/Documentation/feature-removal-schedule.txt b/Documentation/feature-removal-schedule.txt index 274b32d..e38ccae 100644 --- a/Documentation/feature-removal-schedule.txt +++ b/Documentation/feature-removal-schedule.txt @@ -425,16 +425,6 @@ Who: anybody or Florian Mickler ---------------------------- -What: capifs -When: February 2011 -Files: drivers/isdn/capi/capifs.* -Why: udev fully replaces this special file system that only contains CAPI - NCCI TTY device nodes. User space (pppdcapiplugin) works without - noticing the difference. -Who: Jan Kiszka - ----------------------------- - What: KVM paravirt mmu host support When: January 2011 Why: The paravirt mmu host support is slower than non-paravirt mmu, both diff --git a/drivers/isdn/capi/Kconfig b/drivers/isdn/capi/Kconfig index a168e8a..15c3ffd 100644 --- a/drivers/isdn/capi/Kconfig +++ b/drivers/isdn/capi/Kconfig @@ -33,21 +33,6 @@ config ISDN_CAPI_CAPI20 standardized libcapi20 to access this functionality. You should say Y/M here. -config ISDN_CAPI_CAPIFS_BOOL - bool "CAPI2.0 filesystem support (DEPRECATED)" - depends on ISDN_CAPI_MIDDLEWARE && ISDN_CAPI_CAPI20 - help - This option provides a special file system, similar to /dev/pts with - device nodes for the special ttys established by using the - middleware extension above. - You no longer need this, udev fully replaces it. This feature is - scheduled for removal. - -config ISDN_CAPI_CAPIFS - tristate - depends on ISDN_CAPI_CAPIFS_BOOL - default ISDN_CAPI_CAPI20 - config ISDN_CAPI_CAPIDRV tristate "CAPI2.0 capidrv interface support" depends on ISDN_I4L diff --git a/drivers/isdn/capi/Makefile b/drivers/isdn/capi/Makefile index 57123e3..4d5b4b7 100644 --- a/drivers/isdn/capi/Makefile +++ b/drivers/isdn/capi/Makefile @@ -7,7 +7,6 @@ obj-$(CONFIG_ISDN_CAPI) += kernelcapi.o obj-$(CONFIG_ISDN_CAPI_CAPI20) += capi.o obj-$(CONFIG_ISDN_CAPI_CAPIDRV) += capidrv.o -obj-$(CONFIG_ISDN_CAPI_CAPIFS) += capifs.o # Multipart objects. diff --git a/drivers/isdn/capi/capi.c b/drivers/isdn/capi/capi.c index 0d70883..bea1009 100644 --- a/drivers/isdn/capi/capi.c +++ b/drivers/isdn/capi/capi.c @@ -38,8 +38,6 @@ #include #include -#include "capifs.h" - MODULE_DESCRIPTION("CAPI4Linux: Userspace /dev/capi20 interface"); MODULE_AUTHOR("Carsten Paeth"); MODULE_LICENSE("GPL"); @@ -85,7 +83,6 @@ struct capiminor { struct kref kref; unsigned int minor; - struct dentry *capifs_dentry; struct capi20_appl *ap; u32 ncci; @@ -300,17 +297,8 @@ static void capiminor_free(struct capiminor *mp) static void capincci_alloc_minor(struct capidev *cdev, struct capincci *np) { - struct capiminor *mp; - dev_t device; - - if (!(cdev->userflags & CAPIFLAG_HIGHJACKING)) - return; - - mp = np->minorp = capiminor_alloc(&cdev->ap, np->ncci); - if (mp) { - device = MKDEV(capinc_tty_driver->major, mp->minor); - mp->capifs_dentry = capifs_new_ncci(mp->minor, device); - } + if (cdev->userflags & CAPIFLAG_HIGHJACKING) + np->minorp = capiminor_alloc(&cdev->ap, np->ncci); } static void capincci_free_minor(struct capincci *np) @@ -319,8 +307,6 @@ static void capincci_free_minor(struct capincci *np) struct tty_struct *tty; if (mp) { - capifs_free_ncci(mp->capifs_dentry); - tty = tty_port_tty_get(&mp->port); if (tty) { tty_vhangup(tty); @@ -1514,10 +1500,8 @@ static int __init capi_init(void) proc_init(); -#if defined(CONFIG_ISDN_CAPI_CAPIFS) || defined(CONFIG_ISDN_CAPI_CAPIFS_MODULE) - compileinfo = " (middleware+capifs)"; -#elif defined(CONFIG_ISDN_CAPI_MIDDLEWARE) - compileinfo = " (no capifs)"; +#ifdef CONFIG_ISDN_CAPI_MIDDLEWARE + compileinfo = " (middleware)"; #else compileinfo = " (no middleware)"; #endif diff --git a/drivers/isdn/capi/capifs.c b/drivers/isdn/capi/capifs.c deleted file mode 100644 index b4faed7..0000000 --- a/drivers/isdn/capi/capifs.c +++ /dev/null @@ -1,239 +0,0 @@ -/* $Id: capifs.c,v 1.1.2.3 2004/01/16 21:09:26 keil Exp $ - * - * Copyright 2000 by Carsten Paeth - * - * Heavily based on devpts filesystem from H. Peter Anvin - * - * This software may be used and distributed according to the terms - * of the GNU General Public License, incorporated herein by reference. - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include /* current */ - -#include "capifs.h" - -MODULE_DESCRIPTION("CAPI4Linux: /dev/capi/ filesystem"); -MODULE_AUTHOR("Carsten Paeth"); -MODULE_LICENSE("GPL"); - -/* ------------------------------------------------------------------ */ - -#define CAPIFS_SUPER_MAGIC (('C'<<8)|'N') - -static struct vfsmount *capifs_mnt; -static int capifs_mnt_count; - -static struct { - int setuid; - int setgid; - uid_t uid; - gid_t gid; - umode_t mode; -} config = {.mode = 0600}; - -/* ------------------------------------------------------------------ */ - -static int capifs_remount(struct super_block *s, int *flags, char *data) -{ - int setuid = 0; - int setgid = 0; - uid_t uid = 0; - gid_t gid = 0; - umode_t mode = 0600; - char *this_char; - char *new_opt = kstrdup(data, GFP_KERNEL); - - this_char = NULL; - while ((this_char = strsep(&data, ",")) != NULL) { - int n; - char dummy; - if (!*this_char) - continue; - if (sscanf(this_char, "uid=%i%c", &n, &dummy) == 1) { - setuid = 1; - uid = n; - } else if (sscanf(this_char, "gid=%i%c", &n, &dummy) == 1) { - setgid = 1; - gid = n; - } else if (sscanf(this_char, "mode=%o%c", &n, &dummy) == 1) - mode = n & ~S_IFMT; - else { - kfree(new_opt); - printk("capifs: called with bogus options\n"); - return -EINVAL; - } - } - - mutex_lock(&s->s_root->d_inode->i_mutex); - - replace_mount_options(s, new_opt); - config.setuid = setuid; - config.setgid = setgid; - config.uid = uid; - config.gid = gid; - config.mode = mode; - - mutex_unlock(&s->s_root->d_inode->i_mutex); - - return 0; -} - -static const struct super_operations capifs_sops = -{ - .statfs = simple_statfs, - .remount_fs = capifs_remount, - .show_options = generic_show_options, -}; - - -static int -capifs_fill_super(struct super_block *s, void *data, int silent) -{ - struct inode * inode; - - s->s_blocksize = 1024; - s->s_blocksize_bits = 10; - s->s_magic = CAPIFS_SUPER_MAGIC; - s->s_op = &capifs_sops; - s->s_time_gran = 1; - - inode = new_inode(s); - if (!inode) - goto fail; - inode->i_ino = 1; - inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME; - inode->i_mode = S_IFDIR | S_IRUGO | S_IXUGO | S_IWUSR; - inode->i_op = &simple_dir_inode_operations; - inode->i_fop = &simple_dir_operations; - inode->i_nlink = 2; - - s->s_root = d_alloc_root(inode); - if (s->s_root) - return 0; - - printk("capifs: get root dentry failed\n"); - iput(inode); -fail: - return -ENOMEM; -} - -static struct dentry *capifs_mount(struct file_system_type *fs_type, - int flags, const char *dev_name, void *data) -{ - return mount_single(fs_type, flags, data, capifs_fill_super); -} - -static struct file_system_type capifs_fs_type = { - .owner = THIS_MODULE, - .name = "capifs", - .mount = capifs_mount, - .kill_sb = kill_anon_super, -}; - -static struct dentry *new_ncci(unsigned int number, dev_t device) -{ - struct super_block *s = capifs_mnt->mnt_sb; - struct dentry *root = s->s_root; - struct dentry *dentry; - struct inode *inode; - char name[10]; - int namelen; - - mutex_lock(&root->d_inode->i_mutex); - - namelen = sprintf(name, "%d", number); - dentry = lookup_one_len(name, root, namelen); - if (IS_ERR(dentry)) { - dentry = NULL; - goto unlock_out; - } - - if (dentry->d_inode) { - dput(dentry); - dentry = NULL; - goto unlock_out; - } - - inode = new_inode(s); - if (!inode) { - dput(dentry); - dentry = NULL; - goto unlock_out; - } - - /* config contents is protected by root's i_mutex */ - inode->i_uid = config.setuid ? config.uid : current_fsuid(); - inode->i_gid = config.setgid ? config.gid : current_fsgid(); - inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME; - inode->i_ino = number + 2; - init_special_inode(inode, S_IFCHR|config.mode, device); - - d_instantiate(dentry, inode); - dget(dentry); - -unlock_out: - mutex_unlock(&root->d_inode->i_mutex); - - return dentry; -} - -struct dentry *capifs_new_ncci(unsigned int number, dev_t device) -{ - struct dentry *dentry; - - if (simple_pin_fs(&capifs_fs_type, &capifs_mnt, &capifs_mnt_count) < 0) - return NULL; - - dentry = new_ncci(number, device); - if (!dentry) - simple_release_fs(&capifs_mnt, &capifs_mnt_count); - - return dentry; -} - -void capifs_free_ncci(struct dentry *dentry) -{ - struct dentry *root = capifs_mnt->mnt_sb->s_root; - struct inode *inode; - - if (!dentry) - return; - - mutex_lock(&root->d_inode->i_mutex); - - inode = dentry->d_inode; - if (inode) { - drop_nlink(inode); - d_delete(dentry); - dput(dentry); - } - dput(dentry); - - mutex_unlock(&root->d_inode->i_mutex); - - simple_release_fs(&capifs_mnt, &capifs_mnt_count); -} - -static int __init capifs_init(void) -{ - return register_filesystem(&capifs_fs_type); -} - -static void __exit capifs_exit(void) -{ - unregister_filesystem(&capifs_fs_type); -} - -EXPORT_SYMBOL(capifs_new_ncci); -EXPORT_SYMBOL(capifs_free_ncci); - -module_init(capifs_init); -module_exit(capifs_exit); diff --git a/drivers/isdn/capi/capifs.h b/drivers/isdn/capi/capifs.h deleted file mode 100644 index e193d11..0000000 --- a/drivers/isdn/capi/capifs.h +++ /dev/null @@ -1,28 +0,0 @@ -/* $Id: capifs.h,v 1.1.2.2 2004/01/16 21:09:26 keil Exp $ - * - * Copyright 2000 by Carsten Paeth - * - * This software may be used and distributed according to the terms - * of the GNU General Public License, incorporated herein by reference. - * - */ - -#include - -#if defined(CONFIG_ISDN_CAPI_CAPIFS) || defined(CONFIG_ISDN_CAPI_CAPIFS_MODULE) - -struct dentry *capifs_new_ncci(unsigned int num, dev_t device); -void capifs_free_ncci(struct dentry *dentry); - -#else - -static inline struct dentry *capifs_new_ncci(unsigned int num, dev_t device) -{ - return NULL; -} - -static inline void capifs_free_ncci(struct dentry *dentry) -{ -} - -#endif -- cgit v0.10.2 From 066413dac420c8225e3ef7f0f76c3255448782d3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Miros=C5=82aw?= Date: Tue, 5 Apr 2011 01:36:58 +0000 Subject: net: netxen: convert to hw_features MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Rather simple conversion to hw_features. Signed-off-by: MichaÅ‚ MirosÅ‚aw Signed-off-by: David S. Miller diff --git a/drivers/net/netxen/netxen_nic.h b/drivers/net/netxen/netxen_nic.h index d7299f1..15595b3 100644 --- a/drivers/net/netxen/netxen_nic.h +++ b/drivers/net/netxen/netxen_nic.h @@ -1177,7 +1177,7 @@ struct netxen_adapter { u8 max_sds_rings; u8 driver_mismatch; u8 msix_supported; - u8 rx_csum; + u8 __pad; u8 pci_using_dac; u8 portnum; u8 physical_port; diff --git a/drivers/net/netxen/netxen_nic_ethtool.c b/drivers/net/netxen/netxen_nic_ethtool.c index 3bdcc80..29f90ba 100644 --- a/drivers/net/netxen/netxen_nic_ethtool.c +++ b/drivers/net/netxen/netxen_nic_ethtool.c @@ -676,62 +676,6 @@ netxen_nic_get_ethtool_stats(struct net_device *dev, } } -static u32 netxen_nic_get_tx_csum(struct net_device *dev) -{ - return dev->features & NETIF_F_IP_CSUM; -} - -static u32 netxen_nic_get_rx_csum(struct net_device *dev) -{ - struct netxen_adapter *adapter = netdev_priv(dev); - return adapter->rx_csum; -} - -static int netxen_nic_set_rx_csum(struct net_device *dev, u32 data) -{ - struct netxen_adapter *adapter = netdev_priv(dev); - - if (data) { - adapter->rx_csum = data; - return 0; - } - - if (dev->features & NETIF_F_LRO) { - if (netxen_config_hw_lro(adapter, NETXEN_NIC_LRO_DISABLED)) - return -EIO; - - dev->features &= ~NETIF_F_LRO; - netxen_send_lro_cleanup(adapter); - netdev_info(dev, "disabling LRO as rx_csum is off\n"); - } - adapter->rx_csum = data; - return 0; -} - -static u32 netxen_nic_get_tso(struct net_device *dev) -{ - struct netxen_adapter *adapter = netdev_priv(dev); - - if (NX_IS_REVISION_P3(adapter->ahw.revision_id)) - return (dev->features & (NETIF_F_TSO | NETIF_F_TSO6)) != 0; - - return (dev->features & NETIF_F_TSO) != 0; -} - -static int netxen_nic_set_tso(struct net_device *dev, u32 data) -{ - if (data) { - struct netxen_adapter *adapter = netdev_priv(dev); - - dev->features |= NETIF_F_TSO; - if (NX_IS_REVISION_P3(adapter->ahw.revision_id)) - dev->features |= NETIF_F_TSO6; - } else - dev->features &= ~(NETIF_F_TSO | NETIF_F_TSO6); - - return 0; -} - static void netxen_nic_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol) { @@ -866,43 +810,6 @@ static int netxen_get_intr_coalesce(struct net_device *netdev, return 0; } -static int netxen_nic_set_flags(struct net_device *netdev, u32 data) -{ - struct netxen_adapter *adapter = netdev_priv(netdev); - int hw_lro; - - if (ethtool_invalid_flags(netdev, data, ETH_FLAG_LRO)) - return -EINVAL; - - if (!(adapter->capabilities & NX_FW_CAPABILITY_HW_LRO)) - return -EINVAL; - - if (!adapter->rx_csum) { - netdev_info(netdev, "rx csum is off, cannot toggle LRO\n"); - return -EINVAL; - } - - if (!!(data & ETH_FLAG_LRO) == !!(netdev->features & NETIF_F_LRO)) - return 0; - - if (data & ETH_FLAG_LRO) { - hw_lro = NETXEN_NIC_LRO_ENABLED; - netdev->features |= NETIF_F_LRO; - } else { - hw_lro = NETXEN_NIC_LRO_DISABLED; - netdev->features &= ~NETIF_F_LRO; - } - - if (netxen_config_hw_lro(adapter, hw_lro)) - return -EIO; - - if ((hw_lro == 0) && netxen_send_lro_cleanup(adapter)) - return -EIO; - - - return 0; -} - const struct ethtool_ops netxen_nic_ethtool_ops = { .get_settings = netxen_nic_get_settings, .set_settings = netxen_nic_set_settings, @@ -916,21 +823,12 @@ const struct ethtool_ops netxen_nic_ethtool_ops = { .set_ringparam = netxen_nic_set_ringparam, .get_pauseparam = netxen_nic_get_pauseparam, .set_pauseparam = netxen_nic_set_pauseparam, - .get_tx_csum = netxen_nic_get_tx_csum, - .set_tx_csum = ethtool_op_set_tx_csum, - .set_sg = ethtool_op_set_sg, - .get_tso = netxen_nic_get_tso, - .set_tso = netxen_nic_set_tso, .get_wol = netxen_nic_get_wol, .set_wol = netxen_nic_set_wol, .self_test = netxen_nic_diag_test, .get_strings = netxen_nic_get_strings, .get_ethtool_stats = netxen_nic_get_ethtool_stats, .get_sset_count = netxen_get_sset_count, - .get_rx_csum = netxen_nic_get_rx_csum, - .set_rx_csum = netxen_nic_set_rx_csum, .get_coalesce = netxen_get_intr_coalesce, .set_coalesce = netxen_set_intr_coalesce, - .get_flags = ethtool_op_get_flags, - .set_flags = netxen_nic_set_flags, }; diff --git a/drivers/net/netxen/netxen_nic_init.c b/drivers/net/netxen/netxen_nic_init.c index 731077d..7f99967 100644 --- a/drivers/net/netxen/netxen_nic_init.c +++ b/drivers/net/netxen/netxen_nic_init.c @@ -1483,7 +1483,8 @@ static struct sk_buff *netxen_process_rxbuf(struct netxen_adapter *adapter, if (!skb) goto no_skb; - if (likely(adapter->rx_csum && cksum == STATUS_CKSUM_OK)) { + if (likely((adapter->netdev->features & NETIF_F_RXCSUM) + && cksum == STATUS_CKSUM_OK)) { adapter->stats.csummed++; skb->ip_summed = CHECKSUM_UNNECESSARY; } else diff --git a/drivers/net/netxen/netxen_nic_main.c b/drivers/net/netxen/netxen_nic_main.c index 9336715..201b944 100644 --- a/drivers/net/netxen/netxen_nic_main.c +++ b/drivers/net/netxen/netxen_nic_main.c @@ -485,6 +485,37 @@ static void netxen_set_multicast_list(struct net_device *dev) adapter->set_multi(dev); } +static u32 netxen_fix_features(struct net_device *dev, u32 features) +{ + if (!(features & NETIF_F_RXCSUM)) { + netdev_info(dev, "disabling LRO as RXCSUM is off\n"); + + features &= ~NETIF_F_LRO; + } + + return features; +} + +static int netxen_set_features(struct net_device *dev, u32 features) +{ + struct netxen_adapter *adapter = netdev_priv(dev); + int hw_lro; + + if (!((dev->features ^ features) & NETIF_F_LRO)) + return 0; + + hw_lro = (features & NETIF_F_LRO) ? NETXEN_NIC_LRO_ENABLED + : NETXEN_NIC_LRO_DISABLED; + + if (netxen_config_hw_lro(adapter, hw_lro)) + return -EIO; + + if (!(features & NETIF_F_LRO) && netxen_send_lro_cleanup(adapter)) + return -EIO; + + return 0; +} + static const struct net_device_ops netxen_netdev_ops = { .ndo_open = netxen_nic_open, .ndo_stop = netxen_nic_close, @@ -495,6 +526,8 @@ static const struct net_device_ops netxen_netdev_ops = { .ndo_set_mac_address = netxen_nic_set_mac, .ndo_change_mtu = netxen_nic_change_mtu, .ndo_tx_timeout = netxen_tx_timeout, + .ndo_fix_features = netxen_fix_features, + .ndo_set_features = netxen_set_features, #ifdef CONFIG_NET_POLL_CONTROLLER .ndo_poll_controller = netxen_nic_poll_controller, #endif @@ -1196,7 +1229,6 @@ netxen_setup_netdev(struct netxen_adapter *adapter, int err = 0; struct pci_dev *pdev = adapter->pdev; - adapter->rx_csum = 1; adapter->mc_enabled = 0; if (NX_IS_REVISION_P3(adapter->ahw.revision_id)) adapter->max_mc_count = 38; @@ -1210,14 +1242,13 @@ netxen_setup_netdev(struct netxen_adapter *adapter, SET_ETHTOOL_OPS(netdev, &netxen_nic_ethtool_ops); - netdev->features |= (NETIF_F_SG | NETIF_F_IP_CSUM | NETIF_F_TSO); - netdev->features |= (NETIF_F_GRO); - netdev->vlan_features |= (NETIF_F_SG | NETIF_F_IP_CSUM | NETIF_F_TSO); + netdev->hw_features = NETIF_F_SG | NETIF_F_IP_CSUM | NETIF_F_TSO | + NETIF_F_RXCSUM; - if (NX_IS_REVISION_P3(adapter->ahw.revision_id)) { - netdev->features |= (NETIF_F_IPV6_CSUM | NETIF_F_TSO6); - netdev->vlan_features |= (NETIF_F_IPV6_CSUM | NETIF_F_TSO6); - } + if (NX_IS_REVISION_P3(adapter->ahw.revision_id)) + netdev->hw_features |= NETIF_F_IPV6_CSUM | NETIF_F_TSO6; + + netdev->vlan_features |= netdev->hw_features; if (adapter->pci_using_dac) { netdev->features |= NETIF_F_HIGHDMA; @@ -1225,10 +1256,12 @@ netxen_setup_netdev(struct netxen_adapter *adapter, } if (adapter->capabilities & NX_FW_CAPABILITY_FVLANTX) - netdev->features |= (NETIF_F_HW_VLAN_TX); + netdev->hw_features |= NETIF_F_HW_VLAN_TX; if (adapter->capabilities & NX_FW_CAPABILITY_HW_LRO) - netdev->features |= NETIF_F_LRO; + netdev->hw_features |= NETIF_F_LRO; + + netdev->features |= netdev->hw_features; netdev->irq = adapter->msix_entries[0].vector; -- cgit v0.10.2 From 94469f75321d13a42056514e2883590b91d84cba Mon Sep 17 00:00:00 2001 From: stephen hemminger Date: Wed, 6 Apr 2011 11:47:23 +0000 Subject: qlcnic: convert to set_phys_id Convert driver to use new ethtool set_phys_id. Not completely sure that this is correct for all cases of device up/down and doing operation. Compile tested only. Signed-off-by: Stephen Hemminger Signed-off-by: David S. Miller diff --git a/drivers/net/qlcnic/qlcnic.h b/drivers/net/qlcnic/qlcnic.h index dc6f7c6..b6e0fc3 100644 --- a/drivers/net/qlcnic/qlcnic.h +++ b/drivers/net/qlcnic/qlcnic.h @@ -912,6 +912,7 @@ struct qlcnic_adapter { struct net_device *netdev; struct pci_dev *pdev; + bool blink_was_down; unsigned long state; u32 flags; diff --git a/drivers/net/qlcnic/qlcnic_ethtool.c b/drivers/net/qlcnic/qlcnic_ethtool.c index 6be4d5a..3cd8a16 100644 --- a/drivers/net/qlcnic/qlcnic_ethtool.c +++ b/drivers/net/qlcnic/qlcnic_ethtool.c @@ -831,48 +831,51 @@ static int qlcnic_set_tso(struct net_device *dev, u32 data) return 0; } -static int qlcnic_blink_led(struct net_device *dev, u32 val) +static int qlcnic_set_led(struct net_device *dev, + enum ethtool_phys_id_state state) { struct qlcnic_adapter *adapter = netdev_priv(dev); int max_sds_rings = adapter->max_sds_rings; - int dev_down = 0; - int ret; - - if (!test_bit(__QLCNIC_DEV_UP, &adapter->state)) { - dev_down = 1; - if (test_and_set_bit(__QLCNIC_RESETTING, &adapter->state)) - return -EIO; - ret = qlcnic_diag_alloc_res(dev, QLCNIC_LED_TEST); - if (ret) { - clear_bit(__QLCNIC_RESETTING, &adapter->state); - return ret; + switch (state) { + case ETHTOOL_ID_ACTIVE: + adapter->blink_was_down = false; + if (!test_bit(__QLCNIC_DEV_UP, &adapter->state)) { + if (test_and_set_bit(__QLCNIC_RESETTING, &adapter->state)) + return -EIO; + + if (qlcnic_diag_alloc_res(dev, QLCNIC_LED_TEST)) { + clear_bit(__QLCNIC_RESETTING, &adapter->state); + return -EIO; + } + adapter->blink_was_down = true; } - } - ret = adapter->nic_ops->config_led(adapter, 1, 0xf); - if (ret) { + if (adapter->nic_ops->config_led(adapter, 1, 0xf) == 0) + return 0; + dev_err(&adapter->pdev->dev, "Failed to set LED blink state.\n"); - goto done; - } + break; - msleep_interruptible(val * 1000); + case ETHTOOL_ID_INACTIVE: + if (adapter->nic_ops->config_led(adapter, 0, 0xf) == 0) + return 0; - ret = adapter->nic_ops->config_led(adapter, 0, 0xf); - if (ret) { dev_err(&adapter->pdev->dev, "Failed to reset LED blink state.\n"); - goto done; + break; + + default: + return -EINVAL; } -done: - if (dev_down) { + if (adapter->blink_was_down) { qlcnic_diag_free_res(dev, max_sds_rings); clear_bit(__QLCNIC_RESETTING, &adapter->state); } - return ret; + return -EIO; } static void @@ -1078,7 +1081,7 @@ const struct ethtool_ops qlcnic_ethtool_ops = { .set_coalesce = qlcnic_set_intr_coalesce, .get_flags = ethtool_op_get_flags, .set_flags = qlcnic_set_flags, - .phys_id = qlcnic_blink_led, + .set_phys_id = qlcnic_set_led, .set_msglevel = qlcnic_set_msglevel, .get_msglevel = qlcnic_get_msglevel, }; -- cgit v0.10.2 From 7b1b3afadf33627e707c5038af991ae2ce9b5ac5 Mon Sep 17 00:00:00 2001 From: stephen hemminger Date: Wed, 6 Apr 2011 11:58:36 +0000 Subject: ewrk3: convert to set_phys_id Use ethtool infrastructure for blinking, which is now does locking at higher level. Signed-off-by: Stephen Hemminger Signed-off-by: David S. Miller diff --git a/drivers/net/ewrk3.c b/drivers/net/ewrk3.c index 380d061..c7ce443 100644 --- a/drivers/net/ewrk3.c +++ b/drivers/net/ewrk3.c @@ -1604,55 +1604,47 @@ static u32 ewrk3_get_link(struct net_device *dev) return !(cmr & CMR_LINK); } -static int ewrk3_phys_id(struct net_device *dev, u32 data) +static int ewrk3_set_phys_id(struct net_device *dev, + enum ethtool_phys_id_state state) { struct ewrk3_private *lp = netdev_priv(dev); unsigned long iobase = dev->base_addr; - unsigned long flags; u8 cr; - int count; - - /* Toggle LED 4x per second */ - count = data << 2; - spin_lock_irqsave(&lp->hw_lock, flags); - - /* Bail if a PHYS_ID is already in progress */ - if (lp->led_mask == 0) { - spin_unlock_irqrestore(&lp->hw_lock, flags); - return -EBUSY; - } + spin_lock_irq(&lp->hw_lock); - /* Prevent ISR from twiddling the LED */ - lp->led_mask = 0; + switch (state) { + case ETHTOOL_ID_ACTIVE: + /* Prevent ISR from twiddling the LED */ + lp->led_mask = 0; + spin_unlock_irq(&lp->hw_lock); + return -EINVAL; - while (count--) { - /* Toggle the LED */ + case ETHTOOL_ID_ON: cr = inb(EWRK3_CR); - outb(cr ^ CR_LED, EWRK3_CR); + outb(cr | CR_LED, EWRK3_CR); + break; - /* Wait a little while */ - spin_unlock_irqrestore(&lp->hw_lock, flags); - msleep(250); - spin_lock_irqsave(&lp->hw_lock, flags); + case ETHTOOL_ID_OFF: + cr = inb(EWRK3_CR); + outb(cr & ~CR_LED, EWRK3_CR); + break; - /* Exit if we got a signal */ - if (signal_pending(current)) - break; + case ETHTOOL_ID_INACTIVE: + lp->led_mask = CR_LED; + cr = inb(EWRK3_CR); + outb(cr & ~CR_LED, EWRK3_CR); } + spin_unlock_irq(&lp->hw_lock); - lp->led_mask = CR_LED; - cr = inb(EWRK3_CR); - outb(cr & ~CR_LED, EWRK3_CR); - spin_unlock_irqrestore(&lp->hw_lock, flags); - return signal_pending(current) ? -ERESTARTSYS : 0; + return 0; } static const struct ethtool_ops ethtool_ops_203 = { .get_drvinfo = ewrk3_get_drvinfo, .get_settings = ewrk3_get_settings, .set_settings = ewrk3_set_settings, - .phys_id = ewrk3_phys_id, + .set_phys_id = ewrk3_set_phys_id, }; static const struct ethtool_ops ethtool_ops = { @@ -1660,7 +1652,7 @@ static const struct ethtool_ops ethtool_ops = { .get_settings = ewrk3_get_settings, .set_settings = ewrk3_set_settings, .get_link = ewrk3_get_link, - .phys_id = ewrk3_phys_id, + .set_phys_id = ewrk3_set_phys_id, }; /* -- cgit v0.10.2 From 8f74c0661c42104b3e3d2c032bc61efde15360ad Mon Sep 17 00:00:00 2001 From: Shubhrajyoti D Date: Wed, 6 Apr 2011 15:31:22 -0700 Subject: Input: twl4030_keypad - avoid potential NULL-pointer dereference Signed-off-by: Shubhrajyoti D Acked-by: Axel Lin Signed-off-by: Dmitry Torokhov diff --git a/drivers/input/keyboard/twl4030_keypad.c b/drivers/input/keyboard/twl4030_keypad.c index 09bef79..cc06c4b 100644 --- a/drivers/input/keyboard/twl4030_keypad.c +++ b/drivers/input/keyboard/twl4030_keypad.c @@ -338,7 +338,7 @@ static int __devinit twl4030_kp_probe(struct platform_device *pdev) u8 reg; int error; - if (!pdata || !pdata->rows || !pdata->cols || + if (!pdata || !pdata->rows || !pdata->cols || !pdata->keymap_data || pdata->rows > TWL4030_MAX_ROWS || pdata->cols > TWL4030_MAX_COLS) { dev_err(&pdev->dev, "Invalid platform_data\n"); return -EINVAL; -- cgit v0.10.2 From 908433833cac977563e9bef8b206990d846876b4 Mon Sep 17 00:00:00 2001 From: Christoph Fritz Date: Wed, 6 Apr 2011 15:33:16 -0700 Subject: Input: h3600_ts - fix error handling at connect In case of an error in h3600ts_connect(), deconstruct in correct order and with the right calls. Signed-off-by: Christoph Fritz Signed-off-by: Dmitry Torokhov diff --git a/drivers/input/touchscreen/h3600_ts_input.c b/drivers/input/touchscreen/h3600_ts_input.c index efa0688..45f93d0 100644 --- a/drivers/input/touchscreen/h3600_ts_input.c +++ b/drivers/input/touchscreen/h3600_ts_input.c @@ -399,31 +399,34 @@ static int h3600ts_connect(struct serio *serio, struct serio_driver *drv) IRQF_SHARED | IRQF_DISABLED, "h3600_action", &ts->dev)) { printk(KERN_ERR "h3600ts.c: Could not allocate Action Button IRQ!\n"); err = -EBUSY; - goto fail2; + goto fail1; } if (request_irq(IRQ_GPIO_BITSY_NPOWER_BUTTON, npower_button_handler, IRQF_SHARED | IRQF_DISABLED, "h3600_suspend", &ts->dev)) { printk(KERN_ERR "h3600ts.c: Could not allocate Power Button IRQ!\n"); err = -EBUSY; - goto fail3; + goto fail2; } serio_set_drvdata(serio, ts); err = serio_open(serio, drv); if (err) - return err; + goto fail3; //h3600_flite_control(1, 25); /* default brightness */ - input_register_device(ts->dev); + err = input_register_device(ts->dev); + if (err) + goto fail4; return 0; -fail3: free_irq(IRQ_GPIO_BITSY_NPOWER_BUTTON, ts->dev); +fail4: serio_close(serio); +fail3: serio_set_drvdata(serio, NULL); + free_irq(IRQ_GPIO_BITSY_NPOWER_BUTTON, ts->dev); fail2: free_irq(IRQ_GPIO_BITSY_ACTION_BUTTON, ts->dev); -fail1: serio_set_drvdata(serio, NULL); - input_free_device(input_dev); +fail1: input_free_device(input_dev); kfree(ts); return err; } -- cgit v0.10.2 From b04cfcf70b35e032071a6b482273cc642675c8e4 Mon Sep 17 00:00:00 2001 From: Lu Guanqun Date: Wed, 6 Apr 2011 23:25:11 +0800 Subject: ASoC: check channel mismatch between cpu_dai and codec_dai Suppose we have: cpu_dai channels_min = 1 channels_max = 1 codec_dai channels_min = 2 channels_max = 2 This is a mismatch that should not happen, however according to the current code, the result of runtime->hw will be: channels_min = 2 channels_max = 1 We better spot it early. This patch checks this mismatch. Signed-off-by: Lu Guanqun Signed-off-by: Mark Brown diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 960718b..4f42fef 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -640,7 +640,8 @@ static int soc_pcm_open(struct snd_pcm_substream *substream) codec_dai->name, cpu_dai->name); goto config_err; } - if (!runtime->hw.channels_min || !runtime->hw.channels_max) { + if (!runtime->hw.channels_min || !runtime->hw.channels_max || + runtime->hw.channels_min > runtime->hw.channels_max) { printk(KERN_ERR "asoc: %s <-> %s No matching channels\n", codec_dai->name, cpu_dai->name); goto config_err; -- cgit v0.10.2 From c51def659870d25c735a9e06648e560ab39dbbb6 Mon Sep 17 00:00:00 2001 From: Lu Guanqun Date: Wed, 6 Apr 2011 23:25:21 +0800 Subject: ASoC: fix config error path initialize ret to invalid value so that when we reach the config error path in soc_pcm_open, it will return the correct error code. without this patch, though config error path is executed, soc_pcm_open will return 0 in snd_pcm_open_substream and then cause double release of substream. Signed-off-by: Lu Guanqun Signed-off-by: Mark Brown diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 4f42fef..d8562ce 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -629,6 +629,7 @@ static int soc_pcm_open(struct snd_pcm_substream *substream) runtime->hw.rates |= codec_dai_drv->capture.rates; } + ret = -EINVAL; snd_pcm_limit_hw_rates(runtime); if (!runtime->hw.rates) { printk(KERN_ERR "asoc: %s <-> %s No matching rates\n", -- cgit v0.10.2 From baa8160382e2818179d025063697ce0a471ec48f Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Wed, 6 Apr 2011 10:52:42 +0900 Subject: ASoC: Set left channel volume update bits for WM8994 Ensures that we apply volume updates that don't affect the right channel. Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/wm8994.c b/sound/soc/codecs/wm8994.c index 3dc64c8..24857d5 100644 --- a/sound/soc/codecs/wm8994.c +++ b/sound/soc/codecs/wm8994.c @@ -3261,20 +3261,36 @@ static int wm8994_codec_probe(struct snd_soc_codec *codec) wm8994_set_bias_level(codec, SND_SOC_BIAS_STANDBY); /* Latch volume updates (right only; we always do left then right). */ + snd_soc_update_bits(codec, WM8994_AIF1_DAC1_LEFT_VOLUME, + WM8994_AIF1DAC1_VU, WM8994_AIF1DAC1_VU); snd_soc_update_bits(codec, WM8994_AIF1_DAC1_RIGHT_VOLUME, WM8994_AIF1DAC1_VU, WM8994_AIF1DAC1_VU); + snd_soc_update_bits(codec, WM8994_AIF1_DAC2_LEFT_VOLUME, + WM8994_AIF1DAC2_VU, WM8994_AIF1DAC2_VU); snd_soc_update_bits(codec, WM8994_AIF1_DAC2_RIGHT_VOLUME, WM8994_AIF1DAC2_VU, WM8994_AIF1DAC2_VU); + snd_soc_update_bits(codec, WM8994_AIF2_DAC_LEFT_VOLUME, + WM8994_AIF2DAC_VU, WM8994_AIF2DAC_VU); snd_soc_update_bits(codec, WM8994_AIF2_DAC_RIGHT_VOLUME, WM8994_AIF2DAC_VU, WM8994_AIF2DAC_VU); + snd_soc_update_bits(codec, WM8994_AIF1_ADC1_LEFT_VOLUME, + WM8994_AIF1ADC1_VU, WM8994_AIF1ADC1_VU); snd_soc_update_bits(codec, WM8994_AIF1_ADC1_RIGHT_VOLUME, WM8994_AIF1ADC1_VU, WM8994_AIF1ADC1_VU); + snd_soc_update_bits(codec, WM8994_AIF1_ADC2_LEFT_VOLUME, + WM8994_AIF1ADC2_VU, WM8994_AIF1ADC2_VU); snd_soc_update_bits(codec, WM8994_AIF1_ADC2_RIGHT_VOLUME, WM8994_AIF1ADC2_VU, WM8994_AIF1ADC2_VU); + snd_soc_update_bits(codec, WM8994_AIF2_ADC_LEFT_VOLUME, + WM8994_AIF2ADC_VU, WM8994_AIF1ADC2_VU); snd_soc_update_bits(codec, WM8994_AIF2_ADC_RIGHT_VOLUME, WM8994_AIF2ADC_VU, WM8994_AIF1ADC2_VU); + snd_soc_update_bits(codec, WM8994_DAC1_LEFT_VOLUME, + WM8994_DAC1_VU, WM8994_DAC1_VU); snd_soc_update_bits(codec, WM8994_DAC1_RIGHT_VOLUME, WM8994_DAC1_VU, WM8994_DAC1_VU); + snd_soc_update_bits(codec, WM8994_DAC2_LEFT_VOLUME, + WM8994_DAC2_VU, WM8994_DAC2_VU); snd_soc_update_bits(codec, WM8994_DAC2_RIGHT_VOLUME, WM8994_DAC2_VU, WM8994_DAC2_VU); -- cgit v0.10.2 From 3fe14ab541cd9b0d1f243afb7556046f12c8743c Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Tue, 5 Apr 2011 00:23:47 +0200 Subject: x86-32, numa: Fix failure condition check in alloc_remap() node_remap_{start|end}_vaddr[] describe [start, end) ranges; however, alloc_remap() incorrectly failed when the current allocation + size equaled the end but it should fail only when it goes over. Fix it. Signed-off-by: Tejun Heo Link: http://lkml.kernel.org/r/1301955840-7246-2-git-send-email-tj@kernel.org Acked-by: Yinghai Lu Cc: David Rientjes Signed-off-by: H. Peter Anvin diff --git a/arch/x86/mm/numa_32.c b/arch/x86/mm/numa_32.c index bde3906..84aac47 100644 --- a/arch/x86/mm/numa_32.c +++ b/arch/x86/mm/numa_32.c @@ -200,7 +200,7 @@ void *alloc_remap(int nid, unsigned long size) size = ALIGN(size, L1_CACHE_BYTES); - if (!allocation || (allocation + size) >= node_remap_end_vaddr[nid]) + if (!allocation || (allocation + size) > node_remap_end_vaddr[nid]) return NULL; node_remap_alloc_vaddr[nid] += size; -- cgit v0.10.2 From a6c24f7a705d939ddd2fcaa443fa3d8e852b933d Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Tue, 5 Apr 2011 00:23:48 +0200 Subject: x86-32, numa: Align pgdat size while initializing alloc_remap When pgdat is reserved in init_remap_allocator(), PAGE_SIZE aligned size will be used. Match the size alignment in initialization to avoid allocation failure down the road. Signed-off-by: Tejun Heo Link: http://lkml.kernel.org/r/1301955840-7246-3-git-send-email-tj@kernel.org Acked-by: Yinghai Lu Cc: David Rientjes Signed-off-by: H. Peter Anvin diff --git a/arch/x86/mm/numa_32.c b/arch/x86/mm/numa_32.c index 84aac47..50e8250 100644 --- a/arch/x86/mm/numa_32.c +++ b/arch/x86/mm/numa_32.c @@ -287,7 +287,8 @@ static __init unsigned long calculate_numa_remap_pages(void) node_end_pfn[nid] = max_pfn; /* ensure the remap includes space for the pgdat. */ - size = node_remap_size[nid] + sizeof(pg_data_t); + size = node_remap_size[nid]; + size += ALIGN(sizeof(pg_data_t), PAGE_SIZE); /* convert size to large (pmd size) pages, rounding up */ size = (size + LARGE_PAGE_BYTES - 1) / LARGE_PAGE_BYTES; -- cgit v0.10.2 From 5b8443b25c0f323ec190d094e4b441957b02664e Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Tue, 5 Apr 2011 00:23:49 +0200 Subject: x86-32, numa: Remove redundant top-down alloc code from remap initialization memblock_find_in_range() now does top-down allocation by default, so there's no reason for its callers to explicitly implement it by gradually lowering the start address. Remove redundant top-down allocation logic from init_meminit() and calculate_numa_remap_pages(). Signed-off-by: Tejun Heo Link: http://lkml.kernel.org/r/1301955840-7246-4-git-send-email-tj@kernel.org Acked-by: Yinghai Lu Cc: David Rientjes Signed-off-by: H. Peter Anvin diff --git a/arch/x86/mm/numa_32.c b/arch/x86/mm/numa_32.c index 50e8250..60701a5 100644 --- a/arch/x86/mm/numa_32.c +++ b/arch/x86/mm/numa_32.c @@ -270,8 +270,7 @@ static __init unsigned long calculate_numa_remap_pages(void) unsigned long size, reserve_pages = 0; for_each_online_node(nid) { - u64 node_kva_target; - u64 node_kva_final; + u64 node_kva; /* * The acpi/srat node info can show hot-add memroy zones @@ -295,19 +294,11 @@ static __init unsigned long calculate_numa_remap_pages(void) /* now the roundup is correct, convert to PAGE_SIZE pages */ size = size * PTRS_PER_PTE; - node_kva_target = round_down(node_end_pfn[nid] - size, - PTRS_PER_PTE); - node_kva_target <<= PAGE_SHIFT; - do { - node_kva_final = memblock_find_in_range(node_kva_target, + node_kva = memblock_find_in_range(node_start_pfn[nid] << PAGE_SHIFT, ((u64)node_end_pfn[nid])<>PAGE_SHIFT) > (node_start_pfn[nid])); - - if (node_kva_final == MEMBLOCK_ERROR) + ((u64)size)<>PAGE_SHIFT); + size, nid, node_kva >> PAGE_SHIFT); /* * prevent kva address below max_low_pfn want it on system @@ -328,11 +319,11 @@ static __init unsigned long calculate_numa_remap_pages(void) * to use it as free. * So memblock_x86_reserve_range here, hope we don't run out of that array */ - memblock_x86_reserve_range(node_kva_final, - node_kva_final+(((u64)size)<>PAGE_SHIFT; + node_remap_start_pfn[nid] = node_kva >> PAGE_SHIFT; } printk(KERN_INFO "Reserving total of %lx pages for numa KVA remap\n", reserve_pages); @@ -356,7 +347,6 @@ static void init_remap_allocator(int nid) void __init initmem_init(void) { int nid; - long kva_target_pfn; /* * When mapping a NUMA machine we allocate the node_mem_map arrays @@ -371,15 +361,10 @@ void __init initmem_init(void) kva_pages = roundup(calculate_numa_remap_pages(), PTRS_PER_PTE); - kva_target_pfn = round_down(max_low_pfn - kva_pages, PTRS_PER_PTE); - do { - kva_start_pfn = memblock_find_in_range(kva_target_pfn<> PAGE_SHIFT; - kva_target_pfn -= PTRS_PER_PTE; - } while (kva_start_pfn == MEMBLOCK_ERROR && kva_target_pfn > min_low_pfn); - + kva_start_pfn = memblock_find_in_range(min_low_pfn << PAGE_SHIFT, + max_low_pfn << PAGE_SHIFT, + kva_pages << PAGE_SHIFT, + PTRS_PER_PTE << PAGE_SHIFT) >> PAGE_SHIFT; if (kva_start_pfn == MEMBLOCK_ERROR) panic("Can not get kva space\n"); -- cgit v0.10.2 From 5510db9c1be111528ce46c57f0bec1c9dce258f4 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Tue, 5 Apr 2011 00:23:50 +0200 Subject: x86-32, numa: Reorganize calculate_numa_remap_page() Separate the outer node walking loop and per-node logic from calculate_numa_remap_pages(). The outer loop is collapsed into initmem_init() and the per-node logic is moved into a new function - init_alloc_remap(). The new function name is confusing with the existing init_remap_allocator() and the behavior is the function isn't very clean either at this point, but this is to prepare for further cleanups and it will become prettier. This function doesn't introduce any behavior change. Signed-off-by: Tejun Heo Link: http://lkml.kernel.org/r/1301955840-7246-5-git-send-email-tj@kernel.org Acked-by: Yinghai Lu Cc: David Rientjes Signed-off-by: H. Peter Anvin diff --git a/arch/x86/mm/numa_32.c b/arch/x86/mm/numa_32.c index 60701a5..5039e9b 100644 --- a/arch/x86/mm/numa_32.c +++ b/arch/x86/mm/numa_32.c @@ -264,70 +264,64 @@ void resume_map_numa_kva(pgd_t *pgd_base) } #endif -static __init unsigned long calculate_numa_remap_pages(void) +static __init unsigned long init_alloc_remap(int nid, unsigned long offset) { - int nid; - unsigned long size, reserve_pages = 0; + unsigned long size; + u64 node_kva; - for_each_online_node(nid) { - u64 node_kva; - - /* - * The acpi/srat node info can show hot-add memroy zones - * where memory could be added but not currently present. - */ - printk(KERN_DEBUG "node %d pfn: [%lx - %lx]\n", - nid, node_start_pfn[nid], node_end_pfn[nid]); - if (node_start_pfn[nid] > max_pfn) - continue; - if (!node_end_pfn[nid]) - continue; - if (node_end_pfn[nid] > max_pfn) - node_end_pfn[nid] = max_pfn; - - /* ensure the remap includes space for the pgdat. */ - size = node_remap_size[nid]; - size += ALIGN(sizeof(pg_data_t), PAGE_SIZE); - - /* convert size to large (pmd size) pages, rounding up */ - size = (size + LARGE_PAGE_BYTES - 1) / LARGE_PAGE_BYTES; - /* now the roundup is correct, convert to PAGE_SIZE pages */ - size = size * PTRS_PER_PTE; - - node_kva = memblock_find_in_range(node_start_pfn[nid] << PAGE_SHIFT, - ((u64)node_end_pfn[nid])<> PAGE_SHIFT); - - /* - * prevent kva address below max_low_pfn want it on system - * with less memory later. - * layout will be: KVA address , KVA RAM - * - * we are supposed to only record the one less then max_low_pfn - * but we could have some hole in high memory, and it will only - * check page_is_ram(pfn) && !page_is_reserved_early(pfn) to decide - * to use it as free. - * So memblock_x86_reserve_range here, hope we don't run out of that array - */ - memblock_x86_reserve_range(node_kva, - node_kva + (((u64)size)<> PAGE_SHIFT; - } - printk(KERN_INFO "Reserving total of %lx pages for numa KVA remap\n", - reserve_pages); - return reserve_pages; + /* + * The acpi/srat node info can show hot-add memroy zones where + * memory could be added but not currently present. + */ + printk(KERN_DEBUG "node %d pfn: [%lx - %lx]\n", + nid, node_start_pfn[nid], node_end_pfn[nid]); + if (node_start_pfn[nid] > max_pfn) + return 0; + if (!node_end_pfn[nid]) + return 0; + if (node_end_pfn[nid] > max_pfn) + node_end_pfn[nid] = max_pfn; + + /* ensure the remap includes space for the pgdat. */ + size = node_remap_size[nid]; + size += ALIGN(sizeof(pg_data_t), PAGE_SIZE); + + /* convert size to large (pmd size) pages, rounding up */ + size = (size + LARGE_PAGE_BYTES - 1) / LARGE_PAGE_BYTES; + /* now the roundup is correct, convert to PAGE_SIZE pages */ + size = size * PTRS_PER_PTE; + + node_kva = memblock_find_in_range(node_start_pfn[nid] << PAGE_SHIFT, + (u64)node_end_pfn[nid] << PAGE_SHIFT, + (u64)size << PAGE_SHIFT, + LARGE_PAGE_BYTES); + if (node_kva == MEMBLOCK_ERROR) + panic("Can not get kva ram\n"); + + node_remap_size[nid] = size; + node_remap_offset[nid] = offset; + printk(KERN_DEBUG "Reserving %ld pages of KVA for lmem_map of node %d at %llx\n", + size, nid, node_kva >> PAGE_SHIFT); + + /* + * prevent kva address below max_low_pfn want it on system + * with less memory later. + * layout will be: KVA address , KVA RAM + * + * we are supposed to only record the one less then + * max_low_pfn but we could have some hole in high memory, + * and it will only check page_is_ram(pfn) && + * !page_is_reserved_early(pfn) to decide to use it as free. + * So memblock_x86_reserve_range here, hope we don't run out + * of that array + */ + memblock_x86_reserve_range(node_kva, + node_kva + ((u64)size << PAGE_SHIFT), + "KVA RAM"); + + node_remap_start_pfn[nid] = node_kva >> PAGE_SHIFT; + + return size; } static void init_remap_allocator(int nid) @@ -346,6 +340,7 @@ static void init_remap_allocator(int nid) void __init initmem_init(void) { + unsigned long reserve_pages = 0; int nid; /* @@ -359,7 +354,11 @@ void __init initmem_init(void) get_memcfg_numa(); numa_init_array(); - kva_pages = roundup(calculate_numa_remap_pages(), PTRS_PER_PTE); + for_each_online_node(nid) + reserve_pages += init_alloc_remap(nid, reserve_pages); + kva_pages = roundup(reserve_pages, PTRS_PER_PTE); + printk(KERN_INFO "Reserving total of %lx pages for numa KVA remap\n", + reserve_pages); kva_start_pfn = memblock_find_in_range(min_low_pfn << PAGE_SHIFT, max_low_pfn << PAGE_SHIFT, -- cgit v0.10.2 From c4d4f577d49c441ab4f1bb6068247dafb366e635 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Tue, 5 Apr 2011 00:23:51 +0200 Subject: x86-32, numa: Rename @node_kva to @node_pa in init_alloc_remap() init_alloc_remap() is about to do more and using _kva suffix for physical address becomes confusing because the function will be handling both physical and virtual addresses. Rename @node_kva to @node_pa. This is trivial rename and doesn't cause any behavior difference. Signed-off-by: Tejun Heo Link: http://lkml.kernel.org/r/1301955840-7246-6-git-send-email-tj@kernel.org Signed-off-by: H. Peter Anvin diff --git a/arch/x86/mm/numa_32.c b/arch/x86/mm/numa_32.c index 5039e9b..30933fe 100644 --- a/arch/x86/mm/numa_32.c +++ b/arch/x86/mm/numa_32.c @@ -267,7 +267,7 @@ void resume_map_numa_kva(pgd_t *pgd_base) static __init unsigned long init_alloc_remap(int nid, unsigned long offset) { unsigned long size; - u64 node_kva; + u64 node_pa; /* * The acpi/srat node info can show hot-add memroy zones where @@ -291,17 +291,17 @@ static __init unsigned long init_alloc_remap(int nid, unsigned long offset) /* now the roundup is correct, convert to PAGE_SIZE pages */ size = size * PTRS_PER_PTE; - node_kva = memblock_find_in_range(node_start_pfn[nid] << PAGE_SHIFT, - (u64)node_end_pfn[nid] << PAGE_SHIFT, - (u64)size << PAGE_SHIFT, - LARGE_PAGE_BYTES); - if (node_kva == MEMBLOCK_ERROR) + node_pa = memblock_find_in_range(node_start_pfn[nid] << PAGE_SHIFT, + (u64)node_end_pfn[nid] << PAGE_SHIFT, + (u64)size << PAGE_SHIFT, + LARGE_PAGE_BYTES); + if (node_pa == MEMBLOCK_ERROR) panic("Can not get kva ram\n"); node_remap_size[nid] = size; node_remap_offset[nid] = offset; printk(KERN_DEBUG "Reserving %ld pages of KVA for lmem_map of node %d at %llx\n", - size, nid, node_kva >> PAGE_SHIFT); + size, nid, node_pa >> PAGE_SHIFT); /* * prevent kva address below max_low_pfn want it on system @@ -315,11 +315,10 @@ static __init unsigned long init_alloc_remap(int nid, unsigned long offset) * So memblock_x86_reserve_range here, hope we don't run out * of that array */ - memblock_x86_reserve_range(node_kva, - node_kva + ((u64)size << PAGE_SHIFT), + memblock_x86_reserve_range(node_pa, node_pa + ((u64)size << PAGE_SHIFT), "KVA RAM"); - node_remap_start_pfn[nid] = node_kva >> PAGE_SHIFT; + node_remap_start_pfn[nid] = node_pa >> PAGE_SHIFT; return size; } -- cgit v0.10.2 From af7c1a6e8374e05aab4a98ce4d2fb07b66506a02 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Tue, 5 Apr 2011 00:23:52 +0200 Subject: x86-32, numa: Make @size in init_aloc_remap() represent bytes @size variable in init_alloc_remap() is confusing in that it starts as number of bytes as its name implies and then becomes number of pages. Make it consistently represent bytes. Signed-off-by: Tejun Heo Link: http://lkml.kernel.org/r/1301955840-7246-7-git-send-email-tj@kernel.org Acked-by: Yinghai Lu Cc: David Rientjes Signed-off-by: H. Peter Anvin diff --git a/arch/x86/mm/numa_32.c b/arch/x86/mm/numa_32.c index 30933fe..99310d2 100644 --- a/arch/x86/mm/numa_32.c +++ b/arch/x86/mm/numa_32.c @@ -286,22 +286,19 @@ static __init unsigned long init_alloc_remap(int nid, unsigned long offset) size = node_remap_size[nid]; size += ALIGN(sizeof(pg_data_t), PAGE_SIZE); - /* convert size to large (pmd size) pages, rounding up */ - size = (size + LARGE_PAGE_BYTES - 1) / LARGE_PAGE_BYTES; - /* now the roundup is correct, convert to PAGE_SIZE pages */ - size = size * PTRS_PER_PTE; + /* align to large page */ + size = ALIGN(size, LARGE_PAGE_BYTES); node_pa = memblock_find_in_range(node_start_pfn[nid] << PAGE_SHIFT, (u64)node_end_pfn[nid] << PAGE_SHIFT, - (u64)size << PAGE_SHIFT, - LARGE_PAGE_BYTES); + size, LARGE_PAGE_BYTES); if (node_pa == MEMBLOCK_ERROR) panic("Can not get kva ram\n"); - node_remap_size[nid] = size; + node_remap_size[nid] = size >> PAGE_SHIFT; node_remap_offset[nid] = offset; printk(KERN_DEBUG "Reserving %ld pages of KVA for lmem_map of node %d at %llx\n", - size, nid, node_pa >> PAGE_SHIFT); + size >> PAGE_SHIFT, nid, node_pa >> PAGE_SHIFT); /* * prevent kva address below max_low_pfn want it on system @@ -315,12 +312,11 @@ static __init unsigned long init_alloc_remap(int nid, unsigned long offset) * So memblock_x86_reserve_range here, hope we don't run out * of that array */ - memblock_x86_reserve_range(node_pa, node_pa + ((u64)size << PAGE_SHIFT), - "KVA RAM"); + memblock_x86_reserve_range(node_pa, node_pa + size, "KVA RAM"); node_remap_start_pfn[nid] = node_pa >> PAGE_SHIFT; - return size; + return size >> PAGE_SHIFT; } static void init_remap_allocator(int nid) -- cgit v0.10.2 From 7210cf9217937e470a9acbc113a590f476b9c047 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Tue, 5 Apr 2011 00:23:53 +0200 Subject: x86-32, numa: Calculate remap size in common code Only pgdat and memmap use remap area and there isn't much benefit in allowing per-node override. In addition, the use of node_remap_size[] is confusing in that it contains number of bytes before remap initialization and then number of pages afterwards. Move remap size calculation for memap from specific NUMA config implementations to init_alloc_remap() and make node_remap_size[] static. The only behavior difference is that, before this patch, numaq_32 didn't consider max_pfn when calculating the memmap size but it's enforced after this patch, which is the right thing to do. Signed-off-by: Tejun Heo Link: http://lkml.kernel.org/r/1301955840-7246-8-git-send-email-tj@kernel.org Acked-by: Yinghai Lu Cc: David Rientjes Signed-off-by: H. Peter Anvin diff --git a/arch/x86/include/asm/topology.h b/arch/x86/include/asm/topology.h index 910a708..8dba769 100644 --- a/arch/x86/include/asm/topology.h +++ b/arch/x86/include/asm/topology.h @@ -95,7 +95,6 @@ extern void setup_node_to_cpumask_map(void); #ifdef CONFIG_X86_32 extern unsigned long node_start_pfn[]; extern unsigned long node_end_pfn[]; -extern unsigned long node_remap_size[]; #define node_has_online_mem(nid) (node_start_pfn[nid] != node_end_pfn[nid]) # define SD_CACHE_NICE_TRIES 1 diff --git a/arch/x86/kernel/apic/numaq_32.c b/arch/x86/kernel/apic/numaq_32.c index 6273eee..0aced70 100644 --- a/arch/x86/kernel/apic/numaq_32.c +++ b/arch/x86/kernel/apic/numaq_32.c @@ -93,10 +93,6 @@ static inline void numaq_register_node(int node, struct sys_cfg_data *scd) node_end_pfn[node]); memory_present(node, node_start_pfn[node], node_end_pfn[node]); - - node_remap_size[node] = node_memmap_size_bytes(node, - node_start_pfn[node], - node_end_pfn[node]); } /* diff --git a/arch/x86/mm/numa_32.c b/arch/x86/mm/numa_32.c index 99310d2..9a73365 100644 --- a/arch/x86/mm/numa_32.c +++ b/arch/x86/mm/numa_32.c @@ -104,7 +104,7 @@ extern unsigned long highend_pfn, highstart_pfn; #define LARGE_PAGE_BYTES (PTRS_PER_PTE * PAGE_SIZE) -unsigned long node_remap_size[MAX_NUMNODES]; +static unsigned long node_remap_size[MAX_NUMNODES]; static void *node_remap_start_vaddr[MAX_NUMNODES]; void set_pmd_pfn(unsigned long vaddr, unsigned long pfn, pgprot_t flags); @@ -129,7 +129,6 @@ int __init get_memcfg_numa_flat(void) node_end_pfn[0] = max_pfn; memblock_x86_register_active_regions(0, 0, max_pfn); memory_present(0, 0, max_pfn); - node_remap_size[0] = node_memmap_size_bytes(0, 0, max_pfn); /* Indicate there is one node available. */ nodes_clear(node_online_map); @@ -282,11 +281,10 @@ static __init unsigned long init_alloc_remap(int nid, unsigned long offset) if (node_end_pfn[nid] > max_pfn) node_end_pfn[nid] = max_pfn; - /* ensure the remap includes space for the pgdat. */ - size = node_remap_size[nid]; + /* calculate the necessary space aligned to large page size */ + size = node_memmap_size_bytes(nid, node_start_pfn[nid], + min(node_end_pfn[nid], max_pfn)); size += ALIGN(sizeof(pg_data_t), PAGE_SIZE); - - /* align to large page */ size = ALIGN(size, LARGE_PAGE_BYTES); node_pa = memblock_find_in_range(node_start_pfn[nid] << PAGE_SHIFT, diff --git a/arch/x86/mm/srat_32.c b/arch/x86/mm/srat_32.c index 48651c6..1b9e82c 100644 --- a/arch/x86/mm/srat_32.c +++ b/arch/x86/mm/srat_32.c @@ -276,7 +276,6 @@ int __init get_memcfg_from_srat(void) unsigned long end = min(node_end_pfn[nid], max_pfn); memory_present(nid, start, end); - node_remap_size[nid] = node_memmap_size_bytes(nid, start, end); } return 1; out_fail: -- cgit v0.10.2 From 82044c328d6f6b22882c2a936e487e6d2240817a Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Tue, 5 Apr 2011 00:23:54 +0200 Subject: x86-32, numa: Make init_alloc_remap() less panicky Remap allocator failure isn't fatal. The callers are required to fall back to regular early memory allocation mechanisms on failure anyway, so there's no reason to panic on remap init failure. Whining and returning are enough. Signed-off-by: Tejun Heo Link: http://lkml.kernel.org/r/1301955840-7246-9-git-send-email-tj@kernel.org Acked-by: Yinghai Lu Cc: David Rientjes Signed-off-by: H. Peter Anvin diff --git a/arch/x86/mm/numa_32.c b/arch/x86/mm/numa_32.c index 9a73365..c127543 100644 --- a/arch/x86/mm/numa_32.c +++ b/arch/x86/mm/numa_32.c @@ -290,8 +290,11 @@ static __init unsigned long init_alloc_remap(int nid, unsigned long offset) node_pa = memblock_find_in_range(node_start_pfn[nid] << PAGE_SHIFT, (u64)node_end_pfn[nid] << PAGE_SHIFT, size, LARGE_PAGE_BYTES); - if (node_pa == MEMBLOCK_ERROR) - panic("Can not get kva ram\n"); + if (node_pa == MEMBLOCK_ERROR) { + pr_warning("remap_alloc: failed to allocate %lu bytes for node %d\n", + size, nid); + return 0; + } node_remap_size[nid] = size >> PAGE_SHIFT; node_remap_offset[nid] = offset; -- cgit v0.10.2 From 0e9f93c1c04c8ab10cc564df54a7ad0f83c67796 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Tue, 5 Apr 2011 00:23:55 +0200 Subject: x86-32, numa: Move lowmem address space reservation to init_alloc_remap() Remap alloc init is done in the following stages. 1. init_alloc_remap() calculates how much memory is necessary for each node and reserves node local memory. 2. initmem_init() collects how much each node needs and reserves a single contiguous lowmem area which can contain all. 3. init_remap_allocator() initializes allocator parameters from the determined lowmem address and per-node offsets. 4. Actual remap happens. There is no reason for the lowmem remap area to be reserved as a single contiguous area at one go. They don't interact with each other and the memblock allocator will put them side-by-side anyway. This patch breaks up the single lowmem address reservation and put per-node lowmem address reservation into init_alloc_remap() and initializes allocator parameters directly in the function as all the addresses are determined there. This merges steps 2 and 3 into 1. While at it, remove now largely irrelevant comments in init_alloc_remap(). This change causes the following behavior changes. * Remap lowmem areas are allocated in smaller per-node chunks. * Remap lowmem area reservation failure fail future remap allocations instead of panicking. * Remap allocator initialization is less verbose. Signed-off-by: Tejun Heo Link: http://lkml.kernel.org/r/1301955840-7246-10-git-send-email-tj@kernel.org Acked-by: Yinghai Lu Cc: David Rientjes Signed-off-by: H. Peter Anvin diff --git a/arch/x86/mm/numa_32.c b/arch/x86/mm/numa_32.c index c127543..12bb34c 100644 --- a/arch/x86/mm/numa_32.c +++ b/arch/x86/mm/numa_32.c @@ -108,9 +108,6 @@ static unsigned long node_remap_size[MAX_NUMNODES]; static void *node_remap_start_vaddr[MAX_NUMNODES]; void set_pmd_pfn(unsigned long vaddr, unsigned long pfn, pgprot_t flags); -static unsigned long kva_start_pfn; -static unsigned long kva_pages; - int __cpuinit numa_cpu_node(int cpu) { return apic->x86_32_numa_cpu_node(cpu); @@ -266,7 +263,8 @@ void resume_map_numa_kva(pgd_t *pgd_base) static __init unsigned long init_alloc_remap(int nid, unsigned long offset) { unsigned long size; - u64 node_pa; + u64 node_pa, remap_pa; + void *remap_va; /* * The acpi/srat node info can show hot-add memroy zones where @@ -287,6 +285,7 @@ static __init unsigned long init_alloc_remap(int nid, unsigned long offset) size += ALIGN(sizeof(pg_data_t), PAGE_SIZE); size = ALIGN(size, LARGE_PAGE_BYTES); + /* allocate node memory and the lowmem remap area */ node_pa = memblock_find_in_range(node_start_pfn[nid] << PAGE_SHIFT, (u64)node_end_pfn[nid] << PAGE_SHIFT, size, LARGE_PAGE_BYTES); @@ -295,45 +294,35 @@ static __init unsigned long init_alloc_remap(int nid, unsigned long offset) size, nid); return 0; } + memblock_x86_reserve_range(node_pa, node_pa + size, "KVA RAM"); + + remap_pa = memblock_find_in_range(min_low_pfn << PAGE_SHIFT, + max_low_pfn << PAGE_SHIFT, + size, LARGE_PAGE_BYTES); + if (remap_pa == MEMBLOCK_ERROR) { + pr_warning("remap_alloc: failed to allocate %lu bytes remap area for node %d\n", + size, nid); + memblock_x86_free_range(node_pa, node_pa + size); + return 0; + } + memblock_x86_reserve_range(remap_pa, remap_pa + size, "KVA PG"); + remap_va = phys_to_virt(remap_pa); + /* initialize remap allocator parameters */ + node_remap_start_pfn[nid] = node_pa >> PAGE_SHIFT; node_remap_size[nid] = size >> PAGE_SHIFT; node_remap_offset[nid] = offset; - printk(KERN_DEBUG "Reserving %ld pages of KVA for lmem_map of node %d at %llx\n", - size >> PAGE_SHIFT, nid, node_pa >> PAGE_SHIFT); - /* - * prevent kva address below max_low_pfn want it on system - * with less memory later. - * layout will be: KVA address , KVA RAM - * - * we are supposed to only record the one less then - * max_low_pfn but we could have some hole in high memory, - * and it will only check page_is_ram(pfn) && - * !page_is_reserved_early(pfn) to decide to use it as free. - * So memblock_x86_reserve_range here, hope we don't run out - * of that array - */ - memblock_x86_reserve_range(node_pa, node_pa + size, "KVA RAM"); + node_remap_start_vaddr[nid] = remap_va; + node_remap_end_vaddr[nid] = remap_va + size; + node_remap_alloc_vaddr[nid] = remap_va + ALIGN(sizeof(pg_data_t), PAGE_SIZE); - node_remap_start_pfn[nid] = node_pa >> PAGE_SHIFT; + printk(KERN_DEBUG "remap_alloc: node %d [%08llx-%08llx) -> [%p-%p)\n", + nid, node_pa, node_pa + size, remap_va, remap_va + size); return size >> PAGE_SHIFT; } -static void init_remap_allocator(int nid) -{ - node_remap_start_vaddr[nid] = pfn_to_kaddr( - kva_start_pfn + node_remap_offset[nid]); - node_remap_end_vaddr[nid] = node_remap_start_vaddr[nid] + - (node_remap_size[nid] * PAGE_SIZE); - node_remap_alloc_vaddr[nid] = node_remap_start_vaddr[nid] + - ALIGN(sizeof(pg_data_t), PAGE_SIZE); - - printk(KERN_DEBUG "node %d will remap to vaddr %08lx - %08lx\n", nid, - (ulong) node_remap_start_vaddr[nid], - (ulong) node_remap_end_vaddr[nid]); -} - void __init initmem_init(void) { unsigned long reserve_pages = 0; @@ -352,25 +341,7 @@ void __init initmem_init(void) for_each_online_node(nid) reserve_pages += init_alloc_remap(nid, reserve_pages); - kva_pages = roundup(reserve_pages, PTRS_PER_PTE); - printk(KERN_INFO "Reserving total of %lx pages for numa KVA remap\n", - reserve_pages); - - kva_start_pfn = memblock_find_in_range(min_low_pfn << PAGE_SHIFT, - max_low_pfn << PAGE_SHIFT, - kva_pages << PAGE_SHIFT, - PTRS_PER_PTE << PAGE_SHIFT) >> PAGE_SHIFT; - if (kva_start_pfn == MEMBLOCK_ERROR) - panic("Can not get kva space\n"); - - printk(KERN_INFO "kva_start_pfn ~ %lx max_low_pfn ~ %lx\n", - kva_start_pfn, max_low_pfn); - printk(KERN_INFO "max_pfn = %lx\n", max_pfn); - - /* avoid clash with initrd */ - memblock_x86_reserve_range(kva_start_pfn< max_low_pfn) @@ -390,11 +361,8 @@ void __init initmem_init(void) printk(KERN_DEBUG "Low memory ends at vaddr %08lx\n", (ulong) pfn_to_kaddr(max_low_pfn)); - for_each_online_node(nid) { - init_remap_allocator(nid); - + for_each_online_node(nid) allocate_pgdat(nid); - } remap_numa_kva(); printk(KERN_DEBUG "High memory starts at vaddr %08lx\n", -- cgit v0.10.2 From 2a286344f06d6341740b284494379373e87648f7 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Tue, 5 Apr 2011 00:23:56 +0200 Subject: x86-32, numa: Move remapping for remap allocator into init_alloc_remap() There's no reason to perform the actual remapping separately. Collapse remap_numa_kva() into init_alloc_remap() and, while at it, make it less verbose. Signed-off-by: Tejun Heo Link: http://lkml.kernel.org/r/1301955840-7246-11-git-send-email-tj@kernel.org Acked-by: Yinghai Lu Cc: David Rientjes Signed-off-by: H. Peter Anvin diff --git a/arch/x86/mm/numa_32.c b/arch/x86/mm/numa_32.c index 12bb34c..53ec13a 100644 --- a/arch/x86/mm/numa_32.c +++ b/arch/x86/mm/numa_32.c @@ -205,26 +205,6 @@ void *alloc_remap(int nid, unsigned long size) return allocation; } -static void __init remap_numa_kva(void) -{ - void *vaddr; - unsigned long pfn; - int node; - - for_each_online_node(node) { - printk(KERN_DEBUG "remap_numa_kva: node %d\n", node); - for (pfn=0; pfn < node_remap_size[node]; pfn += PTRS_PER_PTE) { - vaddr = node_remap_start_vaddr[node]+(pfn<> PAGE_SHIFT; pfn += PTRS_PER_PTE) + set_pmd_pfn((unsigned long)remap_va + (pfn << PAGE_SHIFT), + (node_pa >> PAGE_SHIFT) + pfn, + PAGE_KERNEL_LARGE); + /* initialize remap allocator parameters */ node_remap_start_pfn[nid] = node_pa >> PAGE_SHIFT; node_remap_size[nid] = size >> PAGE_SHIFT; @@ -363,7 +349,6 @@ void __init initmem_init(void) (ulong) pfn_to_kaddr(max_low_pfn)); for_each_online_node(nid) allocate_pgdat(nid); - remap_numa_kva(); printk(KERN_DEBUG "High memory starts at vaddr %08lx\n", (ulong) pfn_to_kaddr(highstart_pfn)); -- cgit v0.10.2 From b2e3e4fa3eee752b893687783f2a427106c93423 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Tue, 5 Apr 2011 00:23:57 +0200 Subject: x86-32, numa: Make pgdat allocation use alloc_remap() pgdat allocation is handled differnetly from other remap allocations - it's reserved during initialization. There's no reason to handle this any differnetly. Remap allocator is initialized for every node and if init failed the allocation will fail and pgdat allocation can fall back to generic code like anyone else. Remove special init-time pgdat reservation and make allocate_pgdat() use alloc_remap() like everyone else. Signed-off-by: Tejun Heo Link: http://lkml.kernel.org/r/1301955840-7246-12-git-send-email-tj@kernel.org Acked-by: Yinghai Lu Cc: David Rientjes Signed-off-by: H. Peter Anvin diff --git a/arch/x86/mm/numa_32.c b/arch/x86/mm/numa_32.c index 53ec13a..0184a9f 100644 --- a/arch/x86/mm/numa_32.c +++ b/arch/x86/mm/numa_32.c @@ -160,9 +160,8 @@ static void __init allocate_pgdat(int nid) { char buf[16]; - if (node_has_online_mem(nid) && node_remap_start_vaddr[nid]) - NODE_DATA(nid) = (pg_data_t *)node_remap_start_vaddr[nid]; - else { + NODE_DATA(nid) = alloc_remap(nid, ALIGN(sizeof(pg_data_t), PAGE_SIZE)); + if (!NODE_DATA(nid)) { unsigned long pgdat_phys; pgdat_phys = memblock_find_in_range(min_low_pfn< [%p-%p)\n", nid, node_pa, node_pa + size, remap_va, remap_va + size); -- cgit v0.10.2 From 1d85b61baf0334dd6bb88261bec42b808204d694 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Tue, 5 Apr 2011 00:23:58 +0200 Subject: x86-32, numa: Remove now useless node_remap_offset[] With lowmem address reservation moved into init_alloc_remap(), node_remap_offset[] is no longer useful. Remove it and related offset handling code. Signed-off-by: Tejun Heo Link: http://lkml.kernel.org/r/1301955840-7246-13-git-send-email-tj@kernel.org Acked-by: Yinghai Lu Cc: David Rientjes Signed-off-by: H. Peter Anvin diff --git a/arch/x86/mm/numa_32.c b/arch/x86/mm/numa_32.c index 0184a9f..960ea7b 100644 --- a/arch/x86/mm/numa_32.c +++ b/arch/x86/mm/numa_32.c @@ -187,7 +187,6 @@ static void __init allocate_pgdat(int nid) static unsigned long node_remap_start_pfn[MAX_NUMNODES]; static void *node_remap_end_vaddr[MAX_NUMNODES]; static void *node_remap_alloc_vaddr[MAX_NUMNODES]; -static unsigned long node_remap_offset[MAX_NUMNODES]; void *alloc_remap(int nid, unsigned long size) { @@ -239,7 +238,7 @@ void resume_map_numa_kva(pgd_t *pgd_base) } #endif -static __init unsigned long init_alloc_remap(int nid, unsigned long offset) +static __init void init_alloc_remap(int nid) { unsigned long size, pfn; u64 node_pa, remap_pa; @@ -252,9 +251,9 @@ static __init unsigned long init_alloc_remap(int nid, unsigned long offset) printk(KERN_DEBUG "node %d pfn: [%lx - %lx]\n", nid, node_start_pfn[nid], node_end_pfn[nid]); if (node_start_pfn[nid] > max_pfn) - return 0; + return; if (!node_end_pfn[nid]) - return 0; + return; if (node_end_pfn[nid] > max_pfn) node_end_pfn[nid] = max_pfn; @@ -271,7 +270,7 @@ static __init unsigned long init_alloc_remap(int nid, unsigned long offset) if (node_pa == MEMBLOCK_ERROR) { pr_warning("remap_alloc: failed to allocate %lu bytes for node %d\n", size, nid); - return 0; + return; } memblock_x86_reserve_range(node_pa, node_pa + size, "KVA RAM"); @@ -282,7 +281,7 @@ static __init unsigned long init_alloc_remap(int nid, unsigned long offset) pr_warning("remap_alloc: failed to allocate %lu bytes remap area for node %d\n", size, nid); memblock_x86_free_range(node_pa, node_pa + size); - return 0; + return; } memblock_x86_reserve_range(remap_pa, remap_pa + size, "KVA PG"); remap_va = phys_to_virt(remap_pa); @@ -296,7 +295,6 @@ static __init unsigned long init_alloc_remap(int nid, unsigned long offset) /* initialize remap allocator parameters */ node_remap_start_pfn[nid] = node_pa >> PAGE_SHIFT; node_remap_size[nid] = size >> PAGE_SHIFT; - node_remap_offset[nid] = offset; node_remap_start_vaddr[nid] = remap_va; node_remap_end_vaddr[nid] = remap_va + size; @@ -304,13 +302,10 @@ static __init unsigned long init_alloc_remap(int nid, unsigned long offset) printk(KERN_DEBUG "remap_alloc: node %d [%08llx-%08llx) -> [%p-%p)\n", nid, node_pa, node_pa + size, remap_va, remap_va + size); - - return size >> PAGE_SHIFT; } void __init initmem_init(void) { - unsigned long reserve_pages = 0; int nid; /* @@ -325,7 +320,7 @@ void __init initmem_init(void) numa_init_array(); for_each_online_node(nid) - reserve_pages += init_alloc_remap(nid, reserve_pages); + init_alloc_remap(nid); #ifdef CONFIG_HIGHMEM highstart_pfn = highend_pfn = max_pfn; -- cgit v0.10.2 From 198bd06bbfde2984027e91f64c55eb19a7034a27 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Tue, 5 Apr 2011 00:23:59 +0200 Subject: x86-32, numa: Remove redundant node_remap_size[] Remap area size can be determined from node_remap_start_vaddr[] and node_remap_end_vaddr[] making node_remap_size[] redundant. Remove it. While at it, make resume_map_numa_kva() use @nr_pages for number of pages instead of @size. Signed-off-by: Tejun Heo Link: http://lkml.kernel.org/r/1301955840-7246-14-git-send-email-tj@kernel.org Acked-by: Yinghai Lu Cc: David Rientjes Signed-off-by: H. Peter Anvin diff --git a/arch/x86/mm/numa_32.c b/arch/x86/mm/numa_32.c index 960ea7b..f325e6f 100644 --- a/arch/x86/mm/numa_32.c +++ b/arch/x86/mm/numa_32.c @@ -104,7 +104,6 @@ extern unsigned long highend_pfn, highstart_pfn; #define LARGE_PAGE_BYTES (PTRS_PER_PTE * PAGE_SIZE) -static unsigned long node_remap_size[MAX_NUMNODES]; static void *node_remap_start_vaddr[MAX_NUMNODES]; void set_pmd_pfn(unsigned long vaddr, unsigned long pfn, pgprot_t flags); @@ -214,15 +213,16 @@ void resume_map_numa_kva(pgd_t *pgd_base) int node; for_each_online_node(node) { - unsigned long start_va, start_pfn, size, pfn; + unsigned long start_va, start_pfn, nr_pages, pfn; start_va = (unsigned long)node_remap_start_vaddr[node]; start_pfn = node_remap_start_pfn[node]; - size = node_remap_size[node]; + nr_pages = (node_remap_end_vaddr[node] - + node_remap_start_vaddr[node]) >> PAGE_SHIFT; printk(KERN_DEBUG "%s: node %d\n", __func__, node); - for (pfn = 0; pfn < size; pfn += PTRS_PER_PTE) { + for (pfn = 0; pfn < nr_pages; pfn += PTRS_PER_PTE) { unsigned long vaddr = start_va + (pfn << PAGE_SHIFT); pgd_t *pgd = pgd_base + pgd_index(vaddr); pud_t *pud = pud_offset(pgd, vaddr); @@ -294,8 +294,6 @@ static __init void init_alloc_remap(int nid) /* initialize remap allocator parameters */ node_remap_start_pfn[nid] = node_pa >> PAGE_SHIFT; - node_remap_size[nid] = size >> PAGE_SHIFT; - node_remap_start_vaddr[nid] = remap_va; node_remap_end_vaddr[nid] = remap_va + size; node_remap_alloc_vaddr[nid] = remap_va; -- cgit v0.10.2 From 993ba1585cbb03fab012e41d1a5d24330a283b31 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Tue, 5 Apr 2011 00:24:00 +0200 Subject: x86-32, numa: Update remap allocator comments Now that remap allocator is cleaned up, update comments such that they are in docbook function description format and reflect the actual implementation. Signed-off-by: Tejun Heo Link: http://lkml.kernel.org/r/1301955840-7246-15-git-send-email-tj@kernel.org Acked-by: Yinghai Lu Cc: David Rientjes Signed-off-by: H. Peter Anvin diff --git a/arch/x86/mm/numa_32.c b/arch/x86/mm/numa_32.c index f325e6f..c757c0a 100644 --- a/arch/x86/mm/numa_32.c +++ b/arch/x86/mm/numa_32.c @@ -176,17 +176,31 @@ static void __init allocate_pgdat(int nid) } /* - * In the DISCONTIGMEM and SPARSEMEM memory model, a portion of the kernel - * virtual address space (KVA) is reserved and portions of nodes are mapped - * using it. This is to allow node-local memory to be allocated for - * structures that would normally require ZONE_NORMAL. The memory is - * allocated with alloc_remap() and callers should be prepared to allocate - * from the bootmem allocator instead. + * Remap memory allocator */ static unsigned long node_remap_start_pfn[MAX_NUMNODES]; static void *node_remap_end_vaddr[MAX_NUMNODES]; static void *node_remap_alloc_vaddr[MAX_NUMNODES]; +/** + * alloc_remap - Allocate remapped memory + * @nid: NUMA node to allocate memory from + * @size: The size of allocation + * + * Allocate @size bytes from the remap area of NUMA node @nid. The + * size of the remap area is predetermined by init_alloc_remap() and + * only the callers considered there should call this function. For + * more info, please read the comment on top of init_alloc_remap(). + * + * The caller must be ready to handle allocation failure from this + * function and fall back to regular memory allocator in such cases. + * + * CONTEXT: + * Single CPU early boot context. + * + * RETURNS: + * Pointer to the allocated memory on success, %NULL on failure. + */ void *alloc_remap(int nid, unsigned long size) { void *allocation = node_remap_alloc_vaddr[nid]; @@ -238,6 +252,28 @@ void resume_map_numa_kva(pgd_t *pgd_base) } #endif +/** + * init_alloc_remap - Initialize remap allocator for a NUMA node + * @nid: NUMA node to initizlie remap allocator for + * + * NUMA nodes may end up without any lowmem. As allocating pgdat and + * memmap on a different node with lowmem is inefficient, a special + * remap allocator is implemented which can be used by alloc_remap(). + * + * For each node, the amount of memory which will be necessary for + * pgdat and memmap is calculated and two memory areas of the size are + * allocated - one in the node and the other in lowmem; then, the area + * in the node is remapped to the lowmem area. + * + * As pgdat and memmap must be allocated in lowmem anyway, this + * doesn't waste lowmem address space; however, the actual lowmem + * which gets remapped over is wasted. The amount shouldn't be + * problematic on machines this feature will be used. + * + * Initialization failure isn't fatal. alloc_remap() is used + * opportunistically and the callers will fall back to other memory + * allocation mechanisms on failure. + */ static __init void init_alloc_remap(int nid) { unsigned long size, pfn; @@ -306,14 +342,6 @@ void __init initmem_init(void) { int nid; - /* - * When mapping a NUMA machine we allocate the node_mem_map arrays - * from node local memory. They are then mapped directly into KVA - * between zone normal and vmalloc space. Calculate the size of - * this space and use it to adjust the boundary between ZONE_NORMAL - * and ZONE_HIGHMEM. - */ - get_memcfg_numa(); numa_init_array(); -- cgit v0.10.2 From 912d398d28b4359c2fb1f3763f1ce4f86de8350e Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Wed, 6 Apr 2011 18:40:12 +0000 Subject: net: fix skb_add_data_nocache() to calc csum correctly commit c6e1a0d12ca7b4f22c58e55a16beacfb7d3d8462 broken the calc (net: Allow no-cache copy from user on transmit) of checksum, which may cause some tcp packets be dropped because incorrect checksum. ssh does not work under today's net-next-2.6 tree. Signed-off-by: Wei Yongjun Acked-by: Tom Herbert Signed-off-by: David S. Miller diff --git a/include/net/sock.h b/include/net/sock.h index 43bd515..9cbf23c 100644 --- a/include/net/sock.h +++ b/include/net/sock.h @@ -1392,14 +1392,14 @@ static inline void sk_nocaps_add(struct sock *sk, int flags) static inline int skb_do_copy_data_nocache(struct sock *sk, struct sk_buff *skb, char __user *from, char *to, - int copy) + int copy, int offset) { if (skb->ip_summed == CHECKSUM_NONE) { int err = 0; __wsum csum = csum_and_copy_from_user(from, to, copy, 0, &err); if (err) return err; - skb->csum = csum_block_add(skb->csum, csum, skb->len); + skb->csum = csum_block_add(skb->csum, csum, offset); } else if (sk->sk_route_caps & NETIF_F_NOCACHE_COPY) { if (!access_ok(VERIFY_READ, from, copy) || __copy_from_user_nocache(to, from, copy)) @@ -1413,11 +1413,12 @@ static inline int skb_do_copy_data_nocache(struct sock *sk, struct sk_buff *skb, static inline int skb_add_data_nocache(struct sock *sk, struct sk_buff *skb, char __user *from, int copy) { - int err; + int err, offset = skb->len; - err = skb_do_copy_data_nocache(sk, skb, from, skb_put(skb, copy), copy); + err = skb_do_copy_data_nocache(sk, skb, from, skb_put(skb, copy), + copy, offset); if (err) - __skb_trim(skb, skb->len); + __skb_trim(skb, offset); return err; } @@ -1429,8 +1430,8 @@ static inline int skb_copy_to_page_nocache(struct sock *sk, char __user *from, { int err; - err = skb_do_copy_data_nocache(sk, skb, from, - page_address(page) + off, copy); + err = skb_do_copy_data_nocache(sk, skb, from, page_address(page) + off, + copy, skb->len); if (err) return err; -- cgit v0.10.2 From 815b33fdc279d34ab40a8bfe1866623a4cc5669b Mon Sep 17 00:00:00 2001 From: Joerg Roedel Date: Wed, 6 Apr 2011 17:26:49 +0200 Subject: x86/amd-iommu: Cleanup completion-wait handling This patch cleans up the implementation of completion-wait command sending. It also switches the completion indicator from the MMIO bit to a memory store which can be checked without IOMMU locking. As a side effect this patch makes the __iommu_queue_command function obsolete and so it is removed too. Signed-off-by: Joerg Roedel diff --git a/arch/x86/kernel/amd_iommu.c b/arch/x86/kernel/amd_iommu.c index f8ec28e..073c64b 100644 --- a/arch/x86/kernel/amd_iommu.c +++ b/arch/x86/kernel/amd_iommu.c @@ -25,6 +25,7 @@ #include #include #include +#include #include #include #include @@ -34,7 +35,7 @@ #define CMD_SET_TYPE(cmd, t) ((cmd)->data[1] |= ((t) << 28)) -#define EXIT_LOOP_COUNT 10000000 +#define LOOP_TIMEOUT 100000 static DEFINE_RWLOCK(amd_iommu_devtable_lock); @@ -383,10 +384,14 @@ irqreturn_t amd_iommu_int_handler(int irq, void *data) * ****************************************************************************/ -static void build_completion_wait(struct iommu_cmd *cmd) +static void build_completion_wait(struct iommu_cmd *cmd, u64 address) { + WARN_ON(address & 0x7ULL); + memset(cmd, 0, sizeof(*cmd)); - cmd->data[0] = CMD_COMPL_WAIT_INT_MASK; + cmd->data[0] = lower_32_bits(__pa(address)) | CMD_COMPL_WAIT_STORE_MASK; + cmd->data[1] = upper_32_bits(__pa(address)); + cmd->data[2] = 1; CMD_SET_TYPE(cmd, CMD_COMPL_WAIT); } @@ -432,12 +437,14 @@ static void build_inv_iommu_pages(struct iommu_cmd *cmd, u64 address, * Writes the command to the IOMMUs command buffer and informs the * hardware about the new command. Must be called with iommu->lock held. */ -static int __iommu_queue_command(struct amd_iommu *iommu, struct iommu_cmd *cmd) +static int iommu_queue_command(struct amd_iommu *iommu, struct iommu_cmd *cmd) { + unsigned long flags; u32 tail, head; u8 *target; WARN_ON(iommu->cmd_buf_size & CMD_BUFFER_UNINITIALIZED); + spin_lock_irqsave(&iommu->lock, flags); tail = readl(iommu->mmio_base + MMIO_CMD_TAIL_OFFSET); target = iommu->cmd_buf + tail; memcpy_toio(target, cmd, sizeof(*cmd)); @@ -446,99 +453,41 @@ static int __iommu_queue_command(struct amd_iommu *iommu, struct iommu_cmd *cmd) if (tail == head) return -ENOMEM; writel(tail, iommu->mmio_base + MMIO_CMD_TAIL_OFFSET); - - return 0; -} - -/* - * General queuing function for commands. Takes iommu->lock and calls - * __iommu_queue_command(). - */ -static int iommu_queue_command(struct amd_iommu *iommu, struct iommu_cmd *cmd) -{ - unsigned long flags; - int ret; - - spin_lock_irqsave(&iommu->lock, flags); - ret = __iommu_queue_command(iommu, cmd); - if (!ret) - iommu->need_sync = true; + iommu->need_sync = true; spin_unlock_irqrestore(&iommu->lock, flags); - return ret; -} - -/* - * This function waits until an IOMMU has completed a completion - * wait command - */ -static void __iommu_wait_for_completion(struct amd_iommu *iommu) -{ - int ready = 0; - unsigned status = 0; - unsigned long i = 0; - - INC_STATS_COUNTER(compl_wait); - - while (!ready && (i < EXIT_LOOP_COUNT)) { - ++i; - /* wait for the bit to become one */ - status = readl(iommu->mmio_base + MMIO_STATUS_OFFSET); - ready = status & MMIO_STATUS_COM_WAIT_INT_MASK; - } - - /* set bit back to zero */ - status &= ~MMIO_STATUS_COM_WAIT_INT_MASK; - writel(status, iommu->mmio_base + MMIO_STATUS_OFFSET); - - if (unlikely(i == EXIT_LOOP_COUNT)) - iommu->reset_in_progress = true; + return 0; } /* * This function queues a completion wait command into the command * buffer of an IOMMU */ -static int __iommu_completion_wait(struct amd_iommu *iommu) -{ - struct iommu_cmd cmd; - - build_completion_wait(&cmd); - - return __iommu_queue_command(iommu, &cmd); -} - -/* - * This function is called whenever we need to ensure that the IOMMU has - * completed execution of all commands we sent. It sends a - * COMPLETION_WAIT command and waits for it to finish. The IOMMU informs - * us about that by writing a value to a physical address we pass with - * the command. - */ static int iommu_completion_wait(struct amd_iommu *iommu) { - int ret = 0; - unsigned long flags; - - spin_lock_irqsave(&iommu->lock, flags); + struct iommu_cmd cmd; + volatile u64 sem = 0; + int ret, i = 0; if (!iommu->need_sync) - goto out; - - ret = __iommu_completion_wait(iommu); + return 0; - iommu->need_sync = false; + build_completion_wait(&cmd, (u64)&sem); + ret = iommu_queue_command(iommu, &cmd); if (ret) - goto out; - - __iommu_wait_for_completion(iommu); + return ret; -out: - spin_unlock_irqrestore(&iommu->lock, flags); + while (sem == 0 && i < LOOP_TIMEOUT) { + udelay(1); + i += 1; + } - if (iommu->reset_in_progress) + if (i == LOOP_TIMEOUT) { + pr_alert("AMD-Vi: Completion-Wait loop timed out\n"); + iommu->reset_in_progress = true; reset_iommu_command_buffer(iommu); + } return 0; } -- cgit v0.10.2 From 61985a040f17c03b09a2772508ee02729571365b Mon Sep 17 00:00:00 2001 From: Joerg Roedel Date: Wed, 6 Apr 2011 17:46:49 +0200 Subject: x86/amd-iommu: Remove command buffer resetting logic The logic to reset the command buffer caused more problems than it actually helped. The logic jumped in when the IOMMU hardware doesn't execute commands anymore but the reasons for this are usually not fixed by just resetting the command buffer. So the code can be removed to reduce complexity. Signed-off-by: Joerg Roedel diff --git a/arch/x86/include/asm/amd_iommu_types.h b/arch/x86/include/asm/amd_iommu_types.h index e3509fc..878ae00 100644 --- a/arch/x86/include/asm/amd_iommu_types.h +++ b/arch/x86/include/asm/amd_iommu_types.h @@ -409,9 +409,6 @@ struct amd_iommu { /* if one, we need to send a completion wait command */ bool need_sync; - /* becomes true if a command buffer reset is running */ - bool reset_in_progress; - /* default dma_ops domain for that IOMMU */ struct dma_ops_domain *default_dom; diff --git a/arch/x86/kernel/amd_iommu.c b/arch/x86/kernel/amd_iommu.c index 073c64b..0147c5c 100644 --- a/arch/x86/kernel/amd_iommu.c +++ b/arch/x86/kernel/amd_iommu.c @@ -58,7 +58,6 @@ struct iommu_cmd { u32 data[4]; }; -static void reset_iommu_command_buffer(struct amd_iommu *iommu); static void update_domain(struct protection_domain *domain); /**************************************************************************** @@ -323,8 +322,6 @@ static void iommu_print_event(struct amd_iommu *iommu, void *__evt) break; case EVENT_TYPE_ILL_CMD: printk("ILLEGAL_COMMAND_ERROR address=0x%016llx]\n", address); - iommu->reset_in_progress = true; - reset_iommu_command_buffer(iommu); dump_command(address); break; case EVENT_TYPE_CMD_HARD_ERR: @@ -485,8 +482,7 @@ static int iommu_completion_wait(struct amd_iommu *iommu) if (i == LOOP_TIMEOUT) { pr_alert("AMD-Vi: Completion-Wait loop timed out\n"); - iommu->reset_in_progress = true; - reset_iommu_command_buffer(iommu); + ret = -EIO; } return 0; @@ -628,20 +624,6 @@ void amd_iommu_flush_all_domains(void) spin_unlock_irqrestore(&amd_iommu_pd_lock, flags); } -static void reset_iommu_command_buffer(struct amd_iommu *iommu) -{ - pr_err("AMD-Vi: Resetting IOMMU command buffer\n"); - - if (iommu->reset_in_progress) - panic("AMD-Vi: ILLEGAL_COMMAND_ERROR while resetting command buffer\n"); - - amd_iommu_reset_cmd_buffer(iommu); - amd_iommu_flush_all_devices(); - amd_iommu_flush_all_domains(); - - iommu->reset_in_progress = false; -} - /**************************************************************************** * * The functions below are used the create the page table mappings for -- cgit v0.10.2 From 17b124bf1463582005d662d4dd95f037ad863c57 Mon Sep 17 00:00:00 2001 From: Joerg Roedel Date: Wed, 6 Apr 2011 18:01:35 +0200 Subject: x86/amd-iommu: Rename iommu_flush* to domain_flush* These functions all operate on protection domains and not on singe IOMMUs. Represent that in their name. Signed-off-by: Joerg Roedel diff --git a/arch/x86/kernel/amd_iommu.c b/arch/x86/kernel/amd_iommu.c index 0147c5c..9d66b20 100644 --- a/arch/x86/kernel/amd_iommu.c +++ b/arch/x86/kernel/amd_iommu.c @@ -488,22 +488,6 @@ static int iommu_completion_wait(struct amd_iommu *iommu) return 0; } -static void iommu_flush_complete(struct protection_domain *domain) -{ - int i; - - for (i = 0; i < amd_iommus_present; ++i) { - if (!domain->dev_iommu[i]) - continue; - - /* - * Devices of this domain are behind this IOMMU - * We need to wait for completion of all commands. - */ - iommu_completion_wait(amd_iommus[i]); - } -} - /* * Command send function for invalidating a device table entry */ @@ -526,8 +510,8 @@ static int iommu_flush_device(struct device *dev) * It invalidates a single PTE if the range to flush is within a single * page. Otherwise it flushes the whole TLB of the IOMMU. */ -static void __iommu_flush_pages(struct protection_domain *domain, - u64 address, size_t size, int pde) +static void __domain_flush_pages(struct protection_domain *domain, + u64 address, size_t size, int pde) { struct iommu_cmd cmd; int ret = 0, i; @@ -548,29 +532,45 @@ static void __iommu_flush_pages(struct protection_domain *domain, WARN_ON(ret); } -static void iommu_flush_pages(struct protection_domain *domain, - u64 address, size_t size) +static void domain_flush_pages(struct protection_domain *domain, + u64 address, size_t size) { - __iommu_flush_pages(domain, address, size, 0); + __domain_flush_pages(domain, address, size, 0); } /* Flush the whole IO/TLB for a given protection domain */ -static void iommu_flush_tlb(struct protection_domain *domain) +static void domain_flush_tlb(struct protection_domain *domain) { - __iommu_flush_pages(domain, 0, CMD_INV_IOMMU_ALL_PAGES_ADDRESS, 0); + __domain_flush_pages(domain, 0, CMD_INV_IOMMU_ALL_PAGES_ADDRESS, 0); } /* Flush the whole IO/TLB for a given protection domain - including PDE */ -static void iommu_flush_tlb_pde(struct protection_domain *domain) +static void domain_flush_tlb_pde(struct protection_domain *domain) { - __iommu_flush_pages(domain, 0, CMD_INV_IOMMU_ALL_PAGES_ADDRESS, 1); + __domain_flush_pages(domain, 0, CMD_INV_IOMMU_ALL_PAGES_ADDRESS, 1); +} + +static void domain_flush_complete(struct protection_domain *domain) +{ + int i; + + for (i = 0; i < amd_iommus_present; ++i) { + if (!domain->dev_iommu[i]) + continue; + + /* + * Devices of this domain are behind this IOMMU + * We need to wait for completion of all commands. + */ + iommu_completion_wait(amd_iommus[i]); + } } /* * This function flushes the DTEs for all devices in domain */ -static void iommu_flush_domain_devices(struct protection_domain *domain) +static void domain_flush_devices(struct protection_domain *domain) { struct iommu_dev_data *dev_data; unsigned long flags; @@ -591,8 +591,8 @@ static void iommu_flush_all_domain_devices(void) spin_lock_irqsave(&amd_iommu_pd_lock, flags); list_for_each_entry(domain, &amd_iommu_pd_list, list) { - iommu_flush_domain_devices(domain); - iommu_flush_complete(domain); + domain_flush_devices(domain); + domain_flush_complete(domain); } spin_unlock_irqrestore(&amd_iommu_pd_lock, flags); @@ -616,8 +616,8 @@ void amd_iommu_flush_all_domains(void) list_for_each_entry(domain, &amd_iommu_pd_list, list) { spin_lock(&domain->lock); - iommu_flush_tlb_pde(domain); - iommu_flush_complete(domain); + domain_flush_tlb_pde(domain); + domain_flush_complete(domain); spin_unlock(&domain->lock); } @@ -1480,7 +1480,7 @@ static int attach_device(struct device *dev, * left the caches in the IOMMU dirty. So we have to flush * here to evict all dirty stuff. */ - iommu_flush_tlb_pde(domain); + domain_flush_tlb_pde(domain); return ret; } @@ -1693,8 +1693,9 @@ static void update_domain(struct protection_domain *domain) return; update_device_table(domain); - iommu_flush_domain_devices(domain); - iommu_flush_tlb_pde(domain); + + domain_flush_devices(domain); + domain_flush_tlb_pde(domain); domain->updated = false; } @@ -1853,10 +1854,10 @@ retry: ADD_STATS_COUNTER(alloced_io_mem, size); if (unlikely(dma_dom->need_flush && !amd_iommu_unmap_flush)) { - iommu_flush_tlb(&dma_dom->domain); + domain_flush_tlb(&dma_dom->domain); dma_dom->need_flush = false; } else if (unlikely(amd_iommu_np_cache)) - iommu_flush_pages(&dma_dom->domain, address, size); + domain_flush_pages(&dma_dom->domain, address, size); out: return address; @@ -1905,7 +1906,7 @@ static void __unmap_single(struct dma_ops_domain *dma_dom, dma_ops_free_addresses(dma_dom, dma_addr, pages); if (amd_iommu_unmap_flush || dma_dom->need_flush) { - iommu_flush_pages(&dma_dom->domain, flush_addr, size); + domain_flush_pages(&dma_dom->domain, flush_addr, size); dma_dom->need_flush = false; } } @@ -1941,7 +1942,7 @@ static dma_addr_t map_page(struct device *dev, struct page *page, if (addr == DMA_ERROR_CODE) goto out; - iommu_flush_complete(domain); + domain_flush_complete(domain); out: spin_unlock_irqrestore(&domain->lock, flags); @@ -1968,7 +1969,7 @@ static void unmap_page(struct device *dev, dma_addr_t dma_addr, size_t size, __unmap_single(domain->priv, dma_addr, size, dir); - iommu_flush_complete(domain); + domain_flush_complete(domain); spin_unlock_irqrestore(&domain->lock, flags); } @@ -2033,7 +2034,7 @@ static int map_sg(struct device *dev, struct scatterlist *sglist, goto unmap; } - iommu_flush_complete(domain); + domain_flush_complete(domain); out: spin_unlock_irqrestore(&domain->lock, flags); @@ -2079,7 +2080,7 @@ static void unmap_sg(struct device *dev, struct scatterlist *sglist, s->dma_address = s->dma_length = 0; } - iommu_flush_complete(domain); + domain_flush_complete(domain); spin_unlock_irqrestore(&domain->lock, flags); } @@ -2129,7 +2130,7 @@ static void *alloc_coherent(struct device *dev, size_t size, goto out_free; } - iommu_flush_complete(domain); + domain_flush_complete(domain); spin_unlock_irqrestore(&domain->lock, flags); @@ -2161,7 +2162,7 @@ static void free_coherent(struct device *dev, size_t size, __unmap_single(domain->priv, dma_addr, size, DMA_BIDIRECTIONAL); - iommu_flush_complete(domain); + domain_flush_complete(domain); spin_unlock_irqrestore(&domain->lock, flags); @@ -2471,7 +2472,7 @@ static int amd_iommu_unmap(struct iommu_domain *dom, unsigned long iova, unmap_size = iommu_unmap_page(domain, iova, page_size); mutex_unlock(&domain->api_lock); - iommu_flush_tlb_pde(domain); + domain_flush_tlb_pde(domain); return get_order(unmap_size); } -- cgit v0.10.2 From ac0ea6e92b2227c86fe4f7f9eb429071d617a25d Mon Sep 17 00:00:00 2001 From: Joerg Roedel Date: Wed, 6 Apr 2011 18:38:20 +0200 Subject: x86/amd-iommu: Improve handling of full command buffer This patch improved the handling of commands when the IOMMU command buffer is nearly full. In this case it issues an completion wait command and waits until the IOMMU has processed it before continuing queuing new commands. Signed-off-by: Joerg Roedel diff --git a/arch/x86/kernel/amd_iommu.c b/arch/x86/kernel/amd_iommu.c index 9d66b20..75c7f8c 100644 --- a/arch/x86/kernel/amd_iommu.c +++ b/arch/x86/kernel/amd_iommu.c @@ -381,6 +381,39 @@ irqreturn_t amd_iommu_int_handler(int irq, void *data) * ****************************************************************************/ +static int wait_on_sem(volatile u64 *sem) +{ + int i = 0; + + while (*sem == 0 && i < LOOP_TIMEOUT) { + udelay(1); + i += 1; + } + + if (i == LOOP_TIMEOUT) { + pr_alert("AMD-Vi: Completion-Wait loop timed out\n"); + return -EIO; + } + + return 0; +} + +static void copy_cmd_to_buffer(struct amd_iommu *iommu, + struct iommu_cmd *cmd, + u32 tail) +{ + u8 *target; + + target = iommu->cmd_buf + tail; + tail = (tail + sizeof(*cmd)) % iommu->cmd_buf_size; + + /* Copy command to buffer */ + memcpy(target, cmd, sizeof(*cmd)); + + /* Tell the IOMMU about it */ + writel(tail, iommu->mmio_base + MMIO_CMD_TAIL_OFFSET); +} + static void build_completion_wait(struct iommu_cmd *cmd, u64 address) { WARN_ON(address & 0x7ULL); @@ -432,25 +465,44 @@ static void build_inv_iommu_pages(struct iommu_cmd *cmd, u64 address, /* * Writes the command to the IOMMUs command buffer and informs the - * hardware about the new command. Must be called with iommu->lock held. + * hardware about the new command. */ static int iommu_queue_command(struct amd_iommu *iommu, struct iommu_cmd *cmd) { + u32 left, tail, head, next_tail; unsigned long flags; - u32 tail, head; - u8 *target; WARN_ON(iommu->cmd_buf_size & CMD_BUFFER_UNINITIALIZED); + +again: spin_lock_irqsave(&iommu->lock, flags); - tail = readl(iommu->mmio_base + MMIO_CMD_TAIL_OFFSET); - target = iommu->cmd_buf + tail; - memcpy_toio(target, cmd, sizeof(*cmd)); - tail = (tail + sizeof(*cmd)) % iommu->cmd_buf_size; - head = readl(iommu->mmio_base + MMIO_CMD_HEAD_OFFSET); - if (tail == head) - return -ENOMEM; - writel(tail, iommu->mmio_base + MMIO_CMD_TAIL_OFFSET); + + head = readl(iommu->mmio_base + MMIO_CMD_HEAD_OFFSET); + tail = readl(iommu->mmio_base + MMIO_CMD_TAIL_OFFSET); + next_tail = (tail + sizeof(*cmd)) % iommu->cmd_buf_size; + left = (head - next_tail) % iommu->cmd_buf_size; + + if (left <= 2) { + struct iommu_cmd sync_cmd; + volatile u64 sem = 0; + int ret; + + build_completion_wait(&sync_cmd, (u64)&sem); + copy_cmd_to_buffer(iommu, &sync_cmd, tail); + + spin_unlock_irqrestore(&iommu->lock, flags); + + if ((ret = wait_on_sem(&sem)) != 0) + return ret; + + goto again; + } + + copy_cmd_to_buffer(iommu, cmd, tail); + + /* We need to sync now to make sure all commands are processed */ iommu->need_sync = true; + spin_unlock_irqrestore(&iommu->lock, flags); return 0; @@ -464,7 +516,7 @@ static int iommu_completion_wait(struct amd_iommu *iommu) { struct iommu_cmd cmd; volatile u64 sem = 0; - int ret, i = 0; + int ret; if (!iommu->need_sync) return 0; @@ -475,17 +527,7 @@ static int iommu_completion_wait(struct amd_iommu *iommu) if (ret) return ret; - while (sem == 0 && i < LOOP_TIMEOUT) { - udelay(1); - i += 1; - } - - if (i == LOOP_TIMEOUT) { - pr_alert("AMD-Vi: Completion-Wait loop timed out\n"); - ret = -EIO; - } - - return 0; + return wait_on_sem(&sem); } /* -- cgit v0.10.2 From d8c13085775c72e2d46edc54ed0c803c3a944ddb Mon Sep 17 00:00:00 2001 From: Joerg Roedel Date: Wed, 6 Apr 2011 18:51:26 +0200 Subject: x86/amd-iommu: Rename iommu_flush_device This function operates on a struct device, so give it a name that represents that. As a side effect a new function is introduced which operates on am iommu and a device-id. It will be used again in a later patch. Signed-off-by: Joerg Roedel diff --git a/arch/x86/kernel/amd_iommu.c b/arch/x86/kernel/amd_iommu.c index 75c7f8c..3557f22 100644 --- a/arch/x86/kernel/amd_iommu.c +++ b/arch/x86/kernel/amd_iommu.c @@ -530,21 +530,27 @@ static int iommu_completion_wait(struct amd_iommu *iommu) return wait_on_sem(&sem); } +static int iommu_flush_dte(struct amd_iommu *iommu, u16 devid) +{ + struct iommu_cmd cmd; + + build_inv_dte(&cmd, devid); + + return iommu_queue_command(iommu, &cmd); +} + /* * Command send function for invalidating a device table entry */ -static int iommu_flush_device(struct device *dev) +static int device_flush_dte(struct device *dev) { struct amd_iommu *iommu; - struct iommu_cmd cmd; u16 devid; devid = get_device_id(dev); iommu = amd_iommu_rlookup_table[devid]; - build_inv_dte(&cmd, devid); - - return iommu_queue_command(iommu, &cmd); + return iommu_flush_dte(iommu, devid); } /* @@ -620,7 +626,7 @@ static void domain_flush_devices(struct protection_domain *domain) spin_lock_irqsave(&domain->lock, flags); list_for_each_entry(dev_data, &domain->dev_list, list) - iommu_flush_device(dev_data->dev); + device_flush_dte(dev_data->dev); spin_unlock_irqrestore(&domain->lock, flags); } @@ -1424,7 +1430,7 @@ static void do_attach(struct device *dev, struct protection_domain *domain) domain->dev_cnt += 1; /* Flush the DTE entry */ - iommu_flush_device(dev); + device_flush_dte(dev); } static void do_detach(struct device *dev) @@ -1447,7 +1453,7 @@ static void do_detach(struct device *dev) clear_dte_entry(devid); /* Flush the DTE entry */ - iommu_flush_device(dev); + device_flush_dte(dev); } /* @@ -1663,7 +1669,7 @@ static int device_change_notifier(struct notifier_block *nb, goto out; } - iommu_flush_device(dev); + device_flush_dte(dev); iommu_completion_wait(iommu); out: @@ -2448,7 +2454,7 @@ static void amd_iommu_detach_device(struct iommu_domain *dom, if (!iommu) return; - iommu_flush_device(dev); + device_flush_dte(dev); iommu_completion_wait(iommu); } -- cgit v0.10.2 From 7d0c5cc5be73f7ce26fdcca7b8ec2203f661eb93 Mon Sep 17 00:00:00 2001 From: Joerg Roedel Date: Thu, 7 Apr 2011 08:16:10 +0200 Subject: x86/amd-iommu: Flush all internal TLBs when IOMMUs are enabled The old code only flushed a DTE or a domain TLB before it is actually used by the IOMMU driver. While this is efficient and works when done right it is more likely to introduce new bugs when changing code (which happened in the past). This patch adds code to flush all DTEs and all domain TLBs in each IOMMU right after it is enabled (at boot and after resume). This reduces the complexity of the driver and makes it less likely to introduce stale-TLB bugs in the future. Signed-off-by: Joerg Roedel diff --git a/arch/x86/include/asm/amd_iommu_proto.h b/arch/x86/include/asm/amd_iommu_proto.h index 916bc81..1223c0f 100644 --- a/arch/x86/include/asm/amd_iommu_proto.h +++ b/arch/x86/include/asm/amd_iommu_proto.h @@ -24,8 +24,6 @@ struct amd_iommu; extern int amd_iommu_init_dma_ops(void); extern int amd_iommu_init_passthrough(void); extern irqreturn_t amd_iommu_int_handler(int irq, void *data); -extern void amd_iommu_flush_all_domains(void); -extern void amd_iommu_flush_all_devices(void); extern void amd_iommu_apply_erratum_63(u16 devid); extern void amd_iommu_reset_cmd_buffer(struct amd_iommu *iommu); extern int amd_iommu_init_devices(void); diff --git a/arch/x86/kernel/amd_iommu.c b/arch/x86/kernel/amd_iommu.c index 3557f22..bcf58ea 100644 --- a/arch/x86/kernel/amd_iommu.c +++ b/arch/x86/kernel/amd_iommu.c @@ -539,6 +539,40 @@ static int iommu_flush_dte(struct amd_iommu *iommu, u16 devid) return iommu_queue_command(iommu, &cmd); } +static void iommu_flush_dte_all(struct amd_iommu *iommu) +{ + u32 devid; + + for (devid = 0; devid <= 0xffff; ++devid) + iommu_flush_dte(iommu, devid); + + iommu_completion_wait(iommu); +} + +/* + * This function uses heavy locking and may disable irqs for some time. But + * this is no issue because it is only called during resume. + */ +static void iommu_flush_tlb_all(struct amd_iommu *iommu) +{ + u32 dom_id; + + for (dom_id = 0; dom_id <= 0xffff; ++dom_id) { + struct iommu_cmd cmd; + build_inv_iommu_pages(&cmd, 0, CMD_INV_IOMMU_ALL_PAGES_ADDRESS, + dom_id, 1); + iommu_queue_command(iommu, &cmd); + } + + iommu_completion_wait(iommu); +} + +void iommu_flush_all_caches(struct amd_iommu *iommu) +{ + iommu_flush_dte_all(iommu); + iommu_flush_tlb_all(iommu); +} + /* * Command send function for invalidating a device table entry */ @@ -631,47 +665,6 @@ static void domain_flush_devices(struct protection_domain *domain) spin_unlock_irqrestore(&domain->lock, flags); } -static void iommu_flush_all_domain_devices(void) -{ - struct protection_domain *domain; - unsigned long flags; - - spin_lock_irqsave(&amd_iommu_pd_lock, flags); - - list_for_each_entry(domain, &amd_iommu_pd_list, list) { - domain_flush_devices(domain); - domain_flush_complete(domain); - } - - spin_unlock_irqrestore(&amd_iommu_pd_lock, flags); -} - -void amd_iommu_flush_all_devices(void) -{ - iommu_flush_all_domain_devices(); -} - -/* - * This function uses heavy locking and may disable irqs for some time. But - * this is no issue because it is only called during resume. - */ -void amd_iommu_flush_all_domains(void) -{ - struct protection_domain *domain; - unsigned long flags; - - spin_lock_irqsave(&amd_iommu_pd_lock, flags); - - list_for_each_entry(domain, &amd_iommu_pd_list, list) { - spin_lock(&domain->lock); - domain_flush_tlb_pde(domain); - domain_flush_complete(domain); - spin_unlock(&domain->lock); - } - - spin_unlock_irqrestore(&amd_iommu_pd_lock, flags); -} - /**************************************************************************** * * The functions below are used the create the page table mappings for diff --git a/arch/x86/kernel/amd_iommu_init.c b/arch/x86/kernel/amd_iommu_init.c index 246d727..8848dda 100644 --- a/arch/x86/kernel/amd_iommu_init.c +++ b/arch/x86/kernel/amd_iommu_init.c @@ -180,6 +180,12 @@ static u32 dev_table_size; /* size of the device table */ static u32 alias_table_size; /* size of the alias table */ static u32 rlookup_table_size; /* size if the rlookup table */ +/* + * This function flushes all internal caches of + * the IOMMU used by this driver. + */ +extern void iommu_flush_all_caches(struct amd_iommu *iommu); + static inline void update_last_devid(u16 devid) { if (devid > amd_iommu_last_bdf) @@ -1244,6 +1250,7 @@ static void enable_iommus(void) iommu_set_exclusion_range(iommu); iommu_init_msi(iommu); iommu_enable(iommu); + iommu_flush_all_caches(iommu); } } @@ -1274,8 +1281,8 @@ static void amd_iommu_resume(void) * we have to flush after the IOMMUs are enabled because a * disabled IOMMU will never execute the commands we send */ - amd_iommu_flush_all_devices(); - amd_iommu_flush_all_domains(); + for_each_iommu(iommu) + iommu_flush_all_caches(iommu); } static int amd_iommu_suspend(void) -- cgit v0.10.2 From ba4b87ad5497cba555954885db99c99627f93748 Mon Sep 17 00:00:00 2001 From: Stanislaw Gruszka Date: Thu, 31 Mar 2011 08:08:09 -0400 Subject: dma-debug: print information about leaked entry When driver leak dma mapping, print additional information about one of leaked entries, to to help investigate problem. Patch should be useful for debugging drivers, which maps many different class of buffers. Signed-off-by: Stanislaw Gruszka Signed-off-by: Joerg Roedel diff --git a/lib/dma-debug.c b/lib/dma-debug.c index 4bfb047..db07bfd 100644 --- a/lib/dma-debug.c +++ b/lib/dma-debug.c @@ -649,7 +649,7 @@ out_err: return -ENOMEM; } -static int device_dma_allocations(struct device *dev) +static int device_dma_allocations(struct device *dev, struct dma_debug_entry **out_entry) { struct dma_debug_entry *entry; unsigned long flags; @@ -660,8 +660,10 @@ static int device_dma_allocations(struct device *dev) for (i = 0; i < HASH_SIZE; ++i) { spin_lock(&dma_entry_hash[i].lock); list_for_each_entry(entry, &dma_entry_hash[i].list, list) { - if (entry->dev == dev) + if (entry->dev == dev) { count += 1; + *out_entry = entry; + } } spin_unlock(&dma_entry_hash[i].lock); } @@ -674,6 +676,7 @@ static int device_dma_allocations(struct device *dev) static int dma_debug_device_change(struct notifier_block *nb, unsigned long action, void *data) { struct device *dev = data; + struct dma_debug_entry *uninitialized_var(entry); int count; if (global_disable) @@ -681,12 +684,17 @@ static int dma_debug_device_change(struct notifier_block *nb, unsigned long acti switch (action) { case BUS_NOTIFY_UNBOUND_DRIVER: - count = device_dma_allocations(dev); + count = device_dma_allocations(dev, &entry); if (count == 0) break; - err_printk(dev, NULL, "DMA-API: device driver has pending " + err_printk(dev, entry, "DMA-API: device driver has pending " "DMA allocations while released from device " - "[count=%d]\n", count); + "[count=%d]\n" + "One of leaked entries details: " + "[device address=0x%016llx] [size=%llu bytes] " + "[mapped with %s] [mapped as %s]\n", + count, entry->dev_addr, entry->size, + dir2name[entry->direction], type2name[entry->type]); break; default: break; -- cgit v0.10.2 From ff00c2a5b2308219ab952d01e5bb17b9ea772d7e Mon Sep 17 00:00:00 2001 From: Tony Luck Date: Thu, 7 Apr 2011 11:05:56 -0700 Subject: [IA64] fix build warning in arch/ia64/oprofile/backtrace.c arch/ia64/oprofile/backtrace.c:63: warning: comparison of distinct pointer types lacks a cast Comparing a "u64 *" with an "unsigned long *". Make them match. Signed-off-by: Tony Luck diff --git a/arch/ia64/oprofile/backtrace.c b/arch/ia64/oprofile/backtrace.c index 5cdd7e4..f7b7989 100644 --- a/arch/ia64/oprofile/backtrace.c +++ b/arch/ia64/oprofile/backtrace.c @@ -29,7 +29,7 @@ typedef struct unsigned int depth; struct pt_regs *regs; struct unw_frame_info frame; - u64 *prev_pfs_loc; /* state for WAR for old spinlock ool code */ + unsigned long *prev_pfs_loc; /* state for WAR for old spinlock ool code */ } ia64_backtrace_t; /* Returns non-zero if the PC is in the Interrupt Vector Table */ -- cgit v0.10.2 From 2845fd858c55c8a05674a071384a12a19cc17dbf Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 5 Apr 2011 08:55:05 -0700 Subject: iwlagn: override 5300 EEPROM # of chains At least EEPROM version 0x11A has the wrong number of chains programmed into it for some reason, so we need to override in the driver. Signed-off-by: Johannes Berg Signed-off-by: Wey-Yi Guy Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwlwifi/iwl-5000.c b/drivers/net/wireless/iwlwifi/iwl-5000.c index 3ea31b6..22e045b 100644 --- a/drivers/net/wireless/iwlwifi/iwl-5000.c +++ b/drivers/net/wireless/iwlwifi/iwl-5000.c @@ -530,6 +530,9 @@ static struct iwl_ht_params iwl5000_ht_params = { struct iwl_cfg iwl5300_agn_cfg = { .name = "Intel(R) Ultimate N WiFi Link 5300 AGN", IWL_DEVICE_5000, + /* at least EEPROM 0x11A has wrong info */ + .valid_tx_ant = ANT_ABC, /* .cfg overwrite */ + .valid_rx_ant = ANT_ABC, /* .cfg overwrite */ .ht_params = &iwl5000_ht_params, }; -- cgit v0.10.2 From bf3ca7f752d8f5009c9a83db56035566f3e313de Mon Sep 17 00:00:00 2001 From: Brian Cavagnolo Date: Wed, 6 Apr 2011 14:18:46 +0530 Subject: mwl8k: do not free unrequested irq When the mwl8k driver attempts and fails to switch from sta to ap firmware (or vice-versa) in the mwl8k_add_interface routine, the mwl8k_stop routine will be called. This routine must not attempt to free the irq if it was not requested. Signed-off-by: Brian Cavagnolo Signed-off-by: Nishant Sarmukadam Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c index 3695227..c1ceb4b 100644 --- a/drivers/net/wireless/mwl8k.c +++ b/drivers/net/wireless/mwl8k.c @@ -137,6 +137,7 @@ struct mwl8k_tx_queue { struct mwl8k_priv { struct ieee80211_hw *hw; struct pci_dev *pdev; + int irq; struct mwl8k_device_info *device_info; @@ -3761,9 +3762,11 @@ static int mwl8k_start(struct ieee80211_hw *hw) rc = request_irq(priv->pdev->irq, mwl8k_interrupt, IRQF_SHARED, MWL8K_NAME, hw); if (rc) { + priv->irq = -1; wiphy_err(hw->wiphy, "failed to register IRQ handler\n"); return -EIO; } + priv->irq = priv->pdev->irq; /* Enable TX reclaim and RX tasklets. */ tasklet_enable(&priv->poll_tx_task); @@ -3800,6 +3803,7 @@ static int mwl8k_start(struct ieee80211_hw *hw) if (rc) { iowrite32(0, priv->regs + MWL8K_HIU_A2H_INTERRUPT_MASK); free_irq(priv->pdev->irq, hw); + priv->irq = -1; tasklet_disable(&priv->poll_tx_task); tasklet_disable(&priv->poll_rx_task); } @@ -3818,7 +3822,10 @@ static void mwl8k_stop(struct ieee80211_hw *hw) /* Disable interrupts */ iowrite32(0, priv->regs + MWL8K_HIU_A2H_INTERRUPT_MASK); - free_irq(priv->pdev->irq, hw); + if (priv->irq != -1) { + free_irq(priv->pdev->irq, hw); + priv->irq = -1; + } /* Stop finalize join worker */ cancel_work_sync(&priv->finalize_join_worker); -- cgit v0.10.2 From bd39a274fb7b43374c797bafdb7f506598f36f77 Mon Sep 17 00:00:00 2001 From: Christian Lamparter Date: Wed, 6 Apr 2011 20:40:31 +0200 Subject: ath: add missing regdomain pair 0x5c mapping Joe Culler reported a problem with his AR9170 device: > ath: EEPROM regdomain: 0x5c > ath: EEPROM indicates we should expect a direct regpair map > ath: invalid regulatory domain/country code 0x5c > ath: Invalid EEPROM contents It turned out that the regdomain 'APL7_FCCA' was not mapped yet. According to Luis R. Rodriguez [Atheros' engineer] APL7 maps to FCC_CTL and FCCA maps to FCC_CTL as well, so the attached patch should be correct. Cc: Reported-by: Joe Culler Acked-by: Luis R. Rodriguez Signed-off-by: Christian Lamparter Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/regd_common.h b/drivers/net/wireless/ath/regd_common.h index 248c670..5c2cfe6 100644 --- a/drivers/net/wireless/ath/regd_common.h +++ b/drivers/net/wireless/ath/regd_common.h @@ -195,6 +195,7 @@ static struct reg_dmn_pair_mapping regDomainPairs[] = { {APL9_WORLD, CTL_ETSI, CTL_ETSI}, {APL3_FCCA, CTL_FCC, CTL_FCC}, + {APL7_FCCA, CTL_FCC, CTL_FCC}, {APL1_ETSIC, CTL_FCC, CTL_ETSI}, {APL2_ETSIC, CTL_FCC, CTL_ETSI}, {APL2_APLD, CTL_FCC, NO_CTL}, -- cgit v0.10.2 From b0006e69615868f3dfdfe2bd64eb11973f1208fc Mon Sep 17 00:00:00 2001 From: Christian Lamparter Date: Fri, 25 Mar 2011 20:21:55 +0100 Subject: ar9170usb: purge obsolete driver Signed-off-by: Christian Lamparter Signed-off-by: John W. Linville diff --git a/Documentation/feature-removal-schedule.txt b/Documentation/feature-removal-schedule.txt index 274b32d..05ed6f3 100644 --- a/Documentation/feature-removal-schedule.txt +++ b/Documentation/feature-removal-schedule.txt @@ -35,17 +35,6 @@ Who: Luis R. Rodriguez --------------------------- -What: AR9170USB -When: 2.6.40 - -Why: This driver is deprecated and the firmware is no longer - maintained. The replacement driver "carl9170" has been - around for a while, so the devices are still supported. - -Who: Christian Lamparter - ---------------------------- - What: IRQF_SAMPLE_RANDOM Check: IRQF_SAMPLE_RANDOM When: July 2009 diff --git a/MAINTAINERS b/MAINTAINERS index 5dd948b..9f91049 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1224,13 +1224,6 @@ W: http://wireless.kernel.org/en/users/Drivers/ath9k S: Supported F: drivers/net/wireless/ath/ath9k/ -ATHEROS AR9170 WIRELESS DRIVER -M: Christian Lamparter -L: linux-wireless@vger.kernel.org -W: http://wireless.kernel.org/en/users/Drivers/ar9170 -S: Obsolete -F: drivers/net/wireless/ath/ar9170/ - CARL9170 LINUX COMMUNITY WIRELESS DRIVER M: Christian Lamparter L: linux-wireless@vger.kernel.org diff --git a/drivers/net/wireless/ath/Kconfig b/drivers/net/wireless/ath/Kconfig index 92c2162..d1b2306 100644 --- a/drivers/net/wireless/ath/Kconfig +++ b/drivers/net/wireless/ath/Kconfig @@ -24,7 +24,6 @@ config ATH_DEBUG source "drivers/net/wireless/ath/ath5k/Kconfig" source "drivers/net/wireless/ath/ath9k/Kconfig" -source "drivers/net/wireless/ath/ar9170/Kconfig" source "drivers/net/wireless/ath/carl9170/Kconfig" endif diff --git a/drivers/net/wireless/ath/Makefile b/drivers/net/wireless/ath/Makefile index 6d711ec..0e8f528 100644 --- a/drivers/net/wireless/ath/Makefile +++ b/drivers/net/wireless/ath/Makefile @@ -1,6 +1,5 @@ obj-$(CONFIG_ATH5K) += ath5k/ obj-$(CONFIG_ATH9K_HW) += ath9k/ -obj-$(CONFIG_AR9170_USB) += ar9170/ obj-$(CONFIG_CARL9170) += carl9170/ obj-$(CONFIG_ATH_COMMON) += ath.o diff --git a/drivers/net/wireless/ath/ar9170/Kconfig b/drivers/net/wireless/ath/ar9170/Kconfig deleted file mode 100644 index 7b9672b..0000000 --- a/drivers/net/wireless/ath/ar9170/Kconfig +++ /dev/null @@ -1,20 +0,0 @@ -config AR9170_USB - tristate "Atheros AR9170 802.11n USB support (OBSOLETE)" - depends on USB && MAC80211 - select FW_LOADER - help - This driver is going to get replaced by carl9170. - - This is a driver for the Atheros "otus" 802.11n USB devices. - - These devices require additional firmware (2 files). - For now, these files can be downloaded from here: - - http://wireless.kernel.org/en/users/Drivers/ar9170 - - If you choose to build a module, it'll be called ar9170usb. - -config AR9170_LEDS - bool - depends on AR9170_USB && MAC80211_LEDS && (LEDS_CLASS = y || LEDS_CLASS = AR9170_USB) - default y diff --git a/drivers/net/wireless/ath/ar9170/Makefile b/drivers/net/wireless/ath/ar9170/Makefile deleted file mode 100644 index 8d91c7e..0000000 --- a/drivers/net/wireless/ath/ar9170/Makefile +++ /dev/null @@ -1,3 +0,0 @@ -ar9170usb-objs := usb.o main.o cmd.o mac.o phy.o led.o - -obj-$(CONFIG_AR9170_USB) += ar9170usb.o diff --git a/drivers/net/wireless/ath/ar9170/ar9170.h b/drivers/net/wireless/ath/ar9170/ar9170.h deleted file mode 100644 index 371e4ce..0000000 --- a/drivers/net/wireless/ath/ar9170/ar9170.h +++ /dev/null @@ -1,258 +0,0 @@ -/* - * Atheros AR9170 driver - * - * Driver specific definitions - * - * Copyright 2008, Johannes Berg - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; see the file COPYING. If not, see - * http://www.gnu.org/licenses/. - * - * This file incorporates work covered by the following copyright and - * permission notice: - * Copyright (c) 2007-2008 Atheros Communications, Inc. - * - * 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. - */ -#ifndef __AR9170_H -#define __AR9170_H - -#include -#include -#include -#include -#ifdef CONFIG_AR9170_LEDS -#include -#endif /* CONFIG_AR9170_LEDS */ -#include "eeprom.h" -#include "hw.h" - -#include "../regd.h" - -#define PAYLOAD_MAX (AR9170_MAX_CMD_LEN/4 - 1) - -enum ar9170_bw { - AR9170_BW_20, - AR9170_BW_40_BELOW, - AR9170_BW_40_ABOVE, - - __AR9170_NUM_BW, -}; - -static inline enum ar9170_bw nl80211_to_ar9170(enum nl80211_channel_type type) -{ - switch (type) { - case NL80211_CHAN_NO_HT: - case NL80211_CHAN_HT20: - return AR9170_BW_20; - case NL80211_CHAN_HT40MINUS: - return AR9170_BW_40_BELOW; - case NL80211_CHAN_HT40PLUS: - return AR9170_BW_40_ABOVE; - default: - BUG(); - } -} - -enum ar9170_rf_init_mode { - AR9170_RFI_NONE, - AR9170_RFI_WARM, - AR9170_RFI_COLD, -}; - -#define AR9170_MAX_RX_BUFFER_SIZE 8192 - -#ifdef CONFIG_AR9170_LEDS -struct ar9170; - -struct ar9170_led { - struct ar9170 *ar; - struct led_classdev l; - char name[32]; - unsigned int toggled; - bool last_state; - bool registered; -}; - -#endif /* CONFIG_AR9170_LEDS */ - -enum ar9170_device_state { - AR9170_UNKNOWN_STATE, - AR9170_STOPPED, - AR9170_IDLE, - AR9170_STARTED, -}; - -struct ar9170_rxstream_mpdu_merge { - struct ar9170_rx_head plcp; - bool has_plcp; -}; - -struct ar9170_tx_queue_stats { - unsigned int len; - unsigned int limit; - unsigned int count; -}; - -#define AR9170_QUEUE_TIMEOUT 64 -#define AR9170_TX_TIMEOUT 8 -#define AR9170_JANITOR_DELAY 128 -#define AR9170_TX_INVALID_RATE 0xffffffff - -#define AR9170_NUM_TX_LIMIT_HARD AR9170_TXQ_DEPTH -#define AR9170_NUM_TX_LIMIT_SOFT (AR9170_TXQ_DEPTH - 10) - -struct ar9170 { - struct ieee80211_hw *hw; - struct ath_common common; - struct mutex mutex; - enum ar9170_device_state state; - bool registered; - unsigned long bad_hw_nagger; - - int (*open)(struct ar9170 *); - void (*stop)(struct ar9170 *); - int (*tx)(struct ar9170 *, struct sk_buff *); - int (*exec_cmd)(struct ar9170 *, enum ar9170_cmd, u32 , - void *, u32 , void *); - void (*callback_cmd)(struct ar9170 *, u32 , void *); - int (*flush)(struct ar9170 *); - - /* interface mode settings */ - struct ieee80211_vif *vif; - - /* beaconing */ - struct sk_buff *beacon; - struct work_struct beacon_work; - bool enable_beacon; - - /* cryptographic engine */ - u64 usedkeys; - bool rx_software_decryption; - bool disable_offload; - - /* filter settings */ - u64 cur_mc_hash; - u32 cur_filter; - unsigned int filter_state; - bool sniffer_enabled; - - /* PHY */ - struct ieee80211_channel *channel; - int noise[4]; - - /* power calibration data */ - u8 power_5G_leg[4]; - u8 power_2G_cck[4]; - u8 power_2G_ofdm[4]; - u8 power_5G_ht20[8]; - u8 power_5G_ht40[8]; - u8 power_2G_ht20[8]; - u8 power_2G_ht40[8]; - - u8 phy_heavy_clip; - -#ifdef CONFIG_AR9170_LEDS - struct delayed_work led_work; - struct ar9170_led leds[AR9170_NUM_LEDS]; -#endif /* CONFIG_AR9170_LEDS */ - - /* qos queue settings */ - spinlock_t tx_stats_lock; - struct ar9170_tx_queue_stats tx_stats[5]; - struct ieee80211_tx_queue_params edcf[5]; - - spinlock_t cmdlock; - __le32 cmdbuf[PAYLOAD_MAX + 1]; - - /* MAC statistics */ - struct ieee80211_low_level_stats stats; - - /* EEPROM */ - struct ar9170_eeprom eeprom; - - /* tx queues - as seen by hw - */ - struct sk_buff_head tx_pending[__AR9170_NUM_TXQ]; - struct sk_buff_head tx_status[__AR9170_NUM_TXQ]; - struct delayed_work tx_janitor; - - /* rxstream mpdu merge */ - struct ar9170_rxstream_mpdu_merge rx_mpdu; - struct sk_buff *rx_failover; - int rx_failover_missing; - - /* (cached) HW A-MPDU settings */ - u8 global_ampdu_density; - u8 global_ampdu_factor; -}; - -struct ar9170_tx_info { - unsigned long timeout; -}; - -#define IS_STARTED(a) (((struct ar9170 *)a)->state >= AR9170_STARTED) -#define IS_ACCEPTING_CMD(a) (((struct ar9170 *)a)->state >= AR9170_IDLE) - -/* exported interface */ -void *ar9170_alloc(size_t priv_size); -int ar9170_register(struct ar9170 *ar, struct device *pdev); -void ar9170_rx(struct ar9170 *ar, struct sk_buff *skb); -void ar9170_unregister(struct ar9170 *ar); -void ar9170_tx_callback(struct ar9170 *ar, struct sk_buff *skb); -void ar9170_handle_command_response(struct ar9170 *ar, void *buf, u32 len); -int ar9170_nag_limiter(struct ar9170 *ar); - -/* MAC */ -void ar9170_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb); -int ar9170_init_mac(struct ar9170 *ar); -int ar9170_set_qos(struct ar9170 *ar); -int ar9170_update_multicast(struct ar9170 *ar, const u64 mc_hast); -int ar9170_update_frame_filter(struct ar9170 *ar, const u32 filter); -int ar9170_set_operating_mode(struct ar9170 *ar); -int ar9170_set_beacon_timers(struct ar9170 *ar); -int ar9170_set_dyn_sifs_ack(struct ar9170 *ar); -int ar9170_set_slot_time(struct ar9170 *ar); -int ar9170_set_basic_rates(struct ar9170 *ar); -int ar9170_set_hwretry_limit(struct ar9170 *ar, u32 max_retry); -int ar9170_update_beacon(struct ar9170 *ar); -void ar9170_new_beacon(struct work_struct *work); -int ar9170_upload_key(struct ar9170 *ar, u8 id, const u8 *mac, u8 ktype, - u8 keyidx, u8 *keydata, int keylen); -int ar9170_disable_key(struct ar9170 *ar, u8 id); - -/* LEDs */ -#ifdef CONFIG_AR9170_LEDS -int ar9170_register_leds(struct ar9170 *ar); -void ar9170_unregister_leds(struct ar9170 *ar); -#endif /* CONFIG_AR9170_LEDS */ -int ar9170_init_leds(struct ar9170 *ar); -int ar9170_set_leds_state(struct ar9170 *ar, u32 led_state); - -/* PHY / RF */ -int ar9170_init_phy(struct ar9170 *ar, enum ieee80211_band band); -int ar9170_init_rf(struct ar9170 *ar); -int ar9170_set_channel(struct ar9170 *ar, struct ieee80211_channel *channel, - enum ar9170_rf_init_mode rfi, enum ar9170_bw bw); - -#endif /* __AR9170_H */ diff --git a/drivers/net/wireless/ath/ar9170/cmd.c b/drivers/net/wireless/ath/ar9170/cmd.c deleted file mode 100644 index 6452c50..0000000 --- a/drivers/net/wireless/ath/ar9170/cmd.c +++ /dev/null @@ -1,127 +0,0 @@ -/* - * Atheros AR9170 driver - * - * Basic HW register/memory/command access functions - * - * Copyright 2008, Johannes Berg - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; see the file COPYING. If not, see - * http://www.gnu.org/licenses/. - * - * This file incorporates work covered by the following copyright and - * permission notice: - * Copyright (c) 2007-2008 Atheros Communications, Inc. - * - * 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 "ar9170.h" -#include "cmd.h" - -int ar9170_write_mem(struct ar9170 *ar, const __le32 *data, size_t len) -{ - int err; - - if (unlikely(!IS_ACCEPTING_CMD(ar))) - return 0; - - err = ar->exec_cmd(ar, AR9170_CMD_WMEM, len, (u8 *) data, 0, NULL); - if (err) - wiphy_debug(ar->hw->wiphy, "writing memory failed\n"); - return err; -} - -int ar9170_write_reg(struct ar9170 *ar, const u32 reg, const u32 val) -{ - const __le32 buf[2] = { - cpu_to_le32(reg), - cpu_to_le32(val), - }; - int err; - - if (unlikely(!IS_ACCEPTING_CMD(ar))) - return 0; - - err = ar->exec_cmd(ar, AR9170_CMD_WREG, sizeof(buf), - (u8 *) buf, 0, NULL); - if (err) - wiphy_debug(ar->hw->wiphy, "writing reg %#x (val %#x) failed\n", - reg, val); - return err; -} - -int ar9170_read_mreg(struct ar9170 *ar, int nregs, const u32 *regs, u32 *out) -{ - int i, err; - __le32 *offs, *res; - - if (unlikely(!IS_ACCEPTING_CMD(ar))) - return 0; - - /* abuse "out" for the register offsets, must be same length */ - offs = (__le32 *)out; - for (i = 0; i < nregs; i++) - offs[i] = cpu_to_le32(regs[i]); - - /* also use the same buffer for the input */ - res = (__le32 *)out; - - err = ar->exec_cmd(ar, AR9170_CMD_RREG, - 4 * nregs, (u8 *)offs, - 4 * nregs, (u8 *)res); - if (err) - return err; - - /* convert result to cpu endian */ - for (i = 0; i < nregs; i++) - out[i] = le32_to_cpu(res[i]); - - return 0; -} - -int ar9170_read_reg(struct ar9170 *ar, u32 reg, u32 *val) -{ - return ar9170_read_mreg(ar, 1, ®, val); -} - -int ar9170_echo_test(struct ar9170 *ar, u32 v) -{ - __le32 echobuf = cpu_to_le32(v); - __le32 echores; - int err; - - if (unlikely(!IS_ACCEPTING_CMD(ar))) - return -ENODEV; - - err = ar->exec_cmd(ar, AR9170_CMD_ECHO, - 4, (u8 *)&echobuf, - 4, (u8 *)&echores); - if (err) - return err; - - if (echobuf != echores) - return -EINVAL; - - return 0; -} diff --git a/drivers/net/wireless/ath/ar9170/cmd.h b/drivers/net/wireless/ath/ar9170/cmd.h deleted file mode 100644 index ec8134b4..0000000 --- a/drivers/net/wireless/ath/ar9170/cmd.h +++ /dev/null @@ -1,92 +0,0 @@ -/* - * Atheros AR9170 driver - * - * Basic HW register/memory/command access functions - * - * Copyright 2008, Johannes Berg - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; see the file COPYING. If not, see - * http://www.gnu.org/licenses/. - * - * This file incorporates work covered by the following copyright and - * permission notice: - * Copyright (c) 2007-2008 Atheros Communications, Inc. - * - * 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. - */ -#ifndef __CMD_H -#define __CMD_H - -#include "ar9170.h" - -/* basic HW access */ -int ar9170_write_mem(struct ar9170 *ar, const __le32 *data, size_t len); -int ar9170_write_reg(struct ar9170 *ar, const u32 reg, const u32 val); -int ar9170_read_reg(struct ar9170 *ar, u32 reg, u32 *val); -int ar9170_read_mreg(struct ar9170 *ar, int nregs, const u32 *regs, u32 *out); -int ar9170_echo_test(struct ar9170 *ar, u32 v); - -/* - * Macros to facilitate writing multiple registers in a single - * write-combining USB command. Note that when the first group - * fails the whole thing will fail without any others attempted, - * but you won't know which write in the group failed. - */ -#define ar9170_regwrite_begin(ar) \ -do { \ - int __nreg = 0, __err = 0; \ - struct ar9170 *__ar = ar; - -#define ar9170_regwrite(r, v) do { \ - __ar->cmdbuf[2 * __nreg + 1] = cpu_to_le32(r); \ - __ar->cmdbuf[2 * __nreg + 2] = cpu_to_le32(v); \ - __nreg++; \ - if ((__nreg >= PAYLOAD_MAX/2)) { \ - if (IS_ACCEPTING_CMD(__ar)) \ - __err = ar->exec_cmd(__ar, AR9170_CMD_WREG, \ - 8 * __nreg, \ - (u8 *) &__ar->cmdbuf[1], \ - 0, NULL); \ - __nreg = 0; \ - if (__err) \ - goto __regwrite_out; \ - } \ -} while (0) - -#define ar9170_regwrite_finish() \ -__regwrite_out : \ - if (__nreg) { \ - if (IS_ACCEPTING_CMD(__ar)) \ - __err = ar->exec_cmd(__ar, AR9170_CMD_WREG, \ - 8 * __nreg, \ - (u8 *) &__ar->cmdbuf[1], \ - 0, NULL); \ - __nreg = 0; \ - } - -#define ar9170_regwrite_result() \ - __err; \ -} while (0); - -#endif /* __CMD_H */ diff --git a/drivers/net/wireless/ath/ar9170/eeprom.h b/drivers/net/wireless/ath/ar9170/eeprom.h deleted file mode 100644 index 6c46638..0000000 --- a/drivers/net/wireless/ath/ar9170/eeprom.h +++ /dev/null @@ -1,179 +0,0 @@ -/* - * Atheros AR9170 driver - * - * EEPROM layout - * - * Copyright 2008, Johannes Berg - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; see the file COPYING. If not, see - * http://www.gnu.org/licenses/. - * - * This file incorporates work covered by the following copyright and - * permission notice: - * Copyright (c) 2007-2008 Atheros Communications, Inc. - * - * 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. - */ -#ifndef __AR9170_EEPROM_H -#define __AR9170_EEPROM_H - -#define AR5416_MAX_CHAINS 2 -#define AR5416_MODAL_SPURS 5 - -struct ar9170_eeprom_modal { - __le32 antCtrlChain[AR5416_MAX_CHAINS]; - __le32 antCtrlCommon; - s8 antennaGainCh[AR5416_MAX_CHAINS]; - u8 switchSettling; - u8 txRxAttenCh[AR5416_MAX_CHAINS]; - u8 rxTxMarginCh[AR5416_MAX_CHAINS]; - s8 adcDesiredSize; - s8 pgaDesiredSize; - u8 xlnaGainCh[AR5416_MAX_CHAINS]; - u8 txEndToXpaOff; - u8 txEndToRxOn; - u8 txFrameToXpaOn; - u8 thresh62; - s8 noiseFloorThreshCh[AR5416_MAX_CHAINS]; - u8 xpdGain; - u8 xpd; - s8 iqCalICh[AR5416_MAX_CHAINS]; - s8 iqCalQCh[AR5416_MAX_CHAINS]; - u8 pdGainOverlap; - u8 ob; - u8 db; - u8 xpaBiasLvl; - u8 pwrDecreaseFor2Chain; - u8 pwrDecreaseFor3Chain; - u8 txFrameToDataStart; - u8 txFrameToPaOn; - u8 ht40PowerIncForPdadc; - u8 bswAtten[AR5416_MAX_CHAINS]; - u8 bswMargin[AR5416_MAX_CHAINS]; - u8 swSettleHt40; - u8 reserved[22]; - struct spur_channel { - __le16 spurChan; - u8 spurRangeLow; - u8 spurRangeHigh; - } __packed spur_channels[AR5416_MODAL_SPURS]; -} __packed; - -#define AR5416_NUM_PD_GAINS 4 -#define AR5416_PD_GAIN_ICEPTS 5 - -struct ar9170_calibration_data_per_freq { - u8 pwr_pdg[AR5416_NUM_PD_GAINS][AR5416_PD_GAIN_ICEPTS]; - u8 vpd_pdg[AR5416_NUM_PD_GAINS][AR5416_PD_GAIN_ICEPTS]; -} __packed; - -#define AR5416_NUM_5G_CAL_PIERS 8 -#define AR5416_NUM_2G_CAL_PIERS 4 - -#define AR5416_NUM_5G_TARGET_PWRS 8 -#define AR5416_NUM_2G_CCK_TARGET_PWRS 3 -#define AR5416_NUM_2G_OFDM_TARGET_PWRS 4 -#define AR5416_MAX_NUM_TGT_PWRS 8 - -struct ar9170_calibration_target_power_legacy { - u8 freq; - u8 power[4]; -} __packed; - -struct ar9170_calibration_target_power_ht { - u8 freq; - u8 power[8]; -} __packed; - -#define AR5416_NUM_CTLS 24 - -struct ar9170_calctl_edges { - u8 channel; -#define AR9170_CALCTL_EDGE_FLAGS 0xC0 - u8 power_flags; -} __packed; - -#define AR5416_NUM_BAND_EDGES 8 - -struct ar9170_calctl_data { - struct ar9170_calctl_edges - control_edges[AR5416_MAX_CHAINS][AR5416_NUM_BAND_EDGES]; -} __packed; - - -struct ar9170_eeprom { - __le16 length; - __le16 checksum; - __le16 version; - u8 operating_flags; -#define AR9170_OPFLAG_5GHZ 1 -#define AR9170_OPFLAG_2GHZ 2 - u8 misc; - __le16 reg_domain[2]; - u8 mac_address[6]; - u8 rx_mask; - u8 tx_mask; - __le16 rf_silent; - __le16 bluetooth_options; - __le16 device_capabilities; - __le32 build_number; - u8 deviceType; - u8 reserved[33]; - - u8 customer_data[64]; - - struct ar9170_eeprom_modal - modal_header[2]; - - u8 cal_freq_pier_5G[AR5416_NUM_5G_CAL_PIERS]; - u8 cal_freq_pier_2G[AR5416_NUM_2G_CAL_PIERS]; - - struct ar9170_calibration_data_per_freq - cal_pier_data_5G[AR5416_MAX_CHAINS][AR5416_NUM_5G_CAL_PIERS], - cal_pier_data_2G[AR5416_MAX_CHAINS][AR5416_NUM_2G_CAL_PIERS]; - - /* power calibration data */ - struct ar9170_calibration_target_power_legacy - cal_tgt_pwr_5G[AR5416_NUM_5G_TARGET_PWRS]; - struct ar9170_calibration_target_power_ht - cal_tgt_pwr_5G_ht20[AR5416_NUM_5G_TARGET_PWRS], - cal_tgt_pwr_5G_ht40[AR5416_NUM_5G_TARGET_PWRS]; - - struct ar9170_calibration_target_power_legacy - cal_tgt_pwr_2G_cck[AR5416_NUM_2G_CCK_TARGET_PWRS], - cal_tgt_pwr_2G_ofdm[AR5416_NUM_2G_OFDM_TARGET_PWRS]; - struct ar9170_calibration_target_power_ht - cal_tgt_pwr_2G_ht20[AR5416_NUM_2G_OFDM_TARGET_PWRS], - cal_tgt_pwr_2G_ht40[AR5416_NUM_2G_OFDM_TARGET_PWRS]; - - /* conformance testing limits */ - u8 ctl_index[AR5416_NUM_CTLS]; - struct ar9170_calctl_data - ctl_data[AR5416_NUM_CTLS]; - - u8 pad; - __le16 subsystem_id; -} __packed; - -#endif /* __AR9170_EEPROM_H */ diff --git a/drivers/net/wireless/ath/ar9170/hw.h b/drivers/net/wireless/ath/ar9170/hw.h deleted file mode 100644 index 06f1f3c..0000000 --- a/drivers/net/wireless/ath/ar9170/hw.h +++ /dev/null @@ -1,430 +0,0 @@ -/* - * Atheros AR9170 driver - * - * Hardware-specific definitions - * - * Copyright 2008, Johannes Berg - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; see the file COPYING. If not, see - * http://www.gnu.org/licenses/. - * - * This file incorporates work covered by the following copyright and - * permission notice: - * Copyright (c) 2007-2008 Atheros Communications, Inc. - * - * 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. - */ -#ifndef __AR9170_HW_H -#define __AR9170_HW_H - -#define AR9170_MAX_CMD_LEN 64 - -enum ar9170_cmd { - AR9170_CMD_RREG = 0x00, - AR9170_CMD_WREG = 0x01, - AR9170_CMD_RMEM = 0x02, - AR9170_CMD_WMEM = 0x03, - AR9170_CMD_BITAND = 0x04, - AR9170_CMD_BITOR = 0x05, - AR9170_CMD_EKEY = 0x28, - AR9170_CMD_DKEY = 0x29, - AR9170_CMD_FREQUENCY = 0x30, - AR9170_CMD_RF_INIT = 0x31, - AR9170_CMD_SYNTH = 0x32, - AR9170_CMD_FREQ_START = 0x33, - AR9170_CMD_ECHO = 0x80, - AR9170_CMD_TALLY = 0x81, - AR9170_CMD_TALLY_APD = 0x82, - AR9170_CMD_CONFIG = 0x83, - AR9170_CMD_RESET = 0x90, - AR9170_CMD_DKRESET = 0x91, - AR9170_CMD_DKTX_STATUS = 0x92, - AR9170_CMD_FDC = 0xA0, - AR9170_CMD_WREEPROM = 0xB0, - AR9170_CMD_WFLASH = 0xB0, - AR9170_CMD_FLASH_ERASE = 0xB1, - AR9170_CMD_FLASH_PROG = 0xB2, - AR9170_CMD_FLASH_CHKSUM = 0xB3, - AR9170_CMD_FLASH_READ = 0xB4, - AR9170_CMD_FW_DL_INIT = 0xB5, - AR9170_CMD_MEM_WREEPROM = 0xBB, -}; - -/* endpoints */ -#define AR9170_EP_TX 1 -#define AR9170_EP_RX 2 -#define AR9170_EP_IRQ 3 -#define AR9170_EP_CMD 4 - -#define AR9170_EEPROM_START 0x1600 - -#define AR9170_GPIO_REG_BASE 0x1d0100 -#define AR9170_GPIO_REG_PORT_TYPE AR9170_GPIO_REG_BASE -#define AR9170_GPIO_REG_DATA (AR9170_GPIO_REG_BASE + 4) -#define AR9170_NUM_LEDS 2 - - -#define AR9170_USB_REG_BASE 0x1e1000 -#define AR9170_USB_REG_DMA_CTL (AR9170_USB_REG_BASE + 0x108) -#define AR9170_DMA_CTL_ENABLE_TO_DEVICE 0x1 -#define AR9170_DMA_CTL_ENABLE_FROM_DEVICE 0x2 -#define AR9170_DMA_CTL_HIGH_SPEED 0x4 -#define AR9170_DMA_CTL_PACKET_MODE 0x8 - -#define AR9170_USB_REG_MAX_AGG_UPLOAD (AR9170_USB_REG_BASE + 0x110) -#define AR9170_USB_REG_UPLOAD_TIME_CTL (AR9170_USB_REG_BASE + 0x114) - - - -#define AR9170_MAC_REG_BASE 0x1c3000 - -#define AR9170_MAC_REG_TSF_L (AR9170_MAC_REG_BASE + 0x514) -#define AR9170_MAC_REG_TSF_H (AR9170_MAC_REG_BASE + 0x518) - -#define AR9170_MAC_REG_ATIM_WINDOW (AR9170_MAC_REG_BASE + 0x51C) -#define AR9170_MAC_REG_BCN_PERIOD (AR9170_MAC_REG_BASE + 0x520) -#define AR9170_MAC_REG_PRETBTT (AR9170_MAC_REG_BASE + 0x524) - -#define AR9170_MAC_REG_MAC_ADDR_L (AR9170_MAC_REG_BASE + 0x610) -#define AR9170_MAC_REG_MAC_ADDR_H (AR9170_MAC_REG_BASE + 0x614) -#define AR9170_MAC_REG_BSSID_L (AR9170_MAC_REG_BASE + 0x618) -#define AR9170_MAC_REG_BSSID_H (AR9170_MAC_REG_BASE + 0x61c) - -#define AR9170_MAC_REG_GROUP_HASH_TBL_L (AR9170_MAC_REG_BASE + 0x624) -#define AR9170_MAC_REG_GROUP_HASH_TBL_H (AR9170_MAC_REG_BASE + 0x628) - -#define AR9170_MAC_REG_RX_TIMEOUT (AR9170_MAC_REG_BASE + 0x62C) - -#define AR9170_MAC_REG_BASIC_RATE (AR9170_MAC_REG_BASE + 0x630) -#define AR9170_MAC_REG_MANDATORY_RATE (AR9170_MAC_REG_BASE + 0x634) -#define AR9170_MAC_REG_RTS_CTS_RATE (AR9170_MAC_REG_BASE + 0x638) -#define AR9170_MAC_REG_BACKOFF_PROTECT (AR9170_MAC_REG_BASE + 0x63c) -#define AR9170_MAC_REG_RX_THRESHOLD (AR9170_MAC_REG_BASE + 0x640) -#define AR9170_MAC_REG_RX_PE_DELAY (AR9170_MAC_REG_BASE + 0x64C) - -#define AR9170_MAC_REG_DYNAMIC_SIFS_ACK (AR9170_MAC_REG_BASE + 0x658) -#define AR9170_MAC_REG_SNIFFER (AR9170_MAC_REG_BASE + 0x674) -#define AR9170_MAC_REG_SNIFFER_ENABLE_PROMISC BIT(0) -#define AR9170_MAC_REG_SNIFFER_DEFAULTS 0x02000000 -#define AR9170_MAC_REG_ENCRYPTION (AR9170_MAC_REG_BASE + 0x678) -#define AR9170_MAC_REG_ENCRYPTION_RX_SOFTWARE BIT(3) -#define AR9170_MAC_REG_ENCRYPTION_DEFAULTS 0x70 - -#define AR9170_MAC_REG_MISC_680 (AR9170_MAC_REG_BASE + 0x680) -#define AR9170_MAC_REG_TX_UNDERRUN (AR9170_MAC_REG_BASE + 0x688) - -#define AR9170_MAC_REG_FRAMETYPE_FILTER (AR9170_MAC_REG_BASE + 0x68c) -#define AR9170_MAC_REG_FTF_ASSOC_REQ BIT(0) -#define AR9170_MAC_REG_FTF_ASSOC_RESP BIT(1) -#define AR9170_MAC_REG_FTF_REASSOC_REQ BIT(2) -#define AR9170_MAC_REG_FTF_REASSOC_RESP BIT(3) -#define AR9170_MAC_REG_FTF_PRB_REQ BIT(4) -#define AR9170_MAC_REG_FTF_PRB_RESP BIT(5) -#define AR9170_MAC_REG_FTF_BIT6 BIT(6) -#define AR9170_MAC_REG_FTF_BIT7 BIT(7) -#define AR9170_MAC_REG_FTF_BEACON BIT(8) -#define AR9170_MAC_REG_FTF_ATIM BIT(9) -#define AR9170_MAC_REG_FTF_DEASSOC BIT(10) -#define AR9170_MAC_REG_FTF_AUTH BIT(11) -#define AR9170_MAC_REG_FTF_DEAUTH BIT(12) -#define AR9170_MAC_REG_FTF_BIT13 BIT(13) -#define AR9170_MAC_REG_FTF_BIT14 BIT(14) -#define AR9170_MAC_REG_FTF_BIT15 BIT(15) -#define AR9170_MAC_REG_FTF_BAR BIT(24) -#define AR9170_MAC_REG_FTF_BA BIT(25) -#define AR9170_MAC_REG_FTF_PSPOLL BIT(26) -#define AR9170_MAC_REG_FTF_RTS BIT(27) -#define AR9170_MAC_REG_FTF_CTS BIT(28) -#define AR9170_MAC_REG_FTF_ACK BIT(29) -#define AR9170_MAC_REG_FTF_CFE BIT(30) -#define AR9170_MAC_REG_FTF_CFE_ACK BIT(31) -#define AR9170_MAC_REG_FTF_DEFAULTS 0x0700ffff -#define AR9170_MAC_REG_FTF_MONITOR 0xfd00ffff - -#define AR9170_MAC_REG_RX_TOTAL (AR9170_MAC_REG_BASE + 0x6A0) -#define AR9170_MAC_REG_RX_CRC32 (AR9170_MAC_REG_BASE + 0x6A4) -#define AR9170_MAC_REG_RX_CRC16 (AR9170_MAC_REG_BASE + 0x6A8) -#define AR9170_MAC_REG_RX_ERR_DECRYPTION_UNI (AR9170_MAC_REG_BASE + 0x6AC) -#define AR9170_MAC_REG_RX_OVERRUN (AR9170_MAC_REG_BASE + 0x6B0) -#define AR9170_MAC_REG_RX_ERR_DECRYPTION_MUL (AR9170_MAC_REG_BASE + 0x6BC) -#define AR9170_MAC_REG_TX_RETRY (AR9170_MAC_REG_BASE + 0x6CC) -#define AR9170_MAC_REG_TX_TOTAL (AR9170_MAC_REG_BASE + 0x6F4) - - -#define AR9170_MAC_REG_ACK_EXTENSION (AR9170_MAC_REG_BASE + 0x690) -#define AR9170_MAC_REG_EIFS_AND_SIFS (AR9170_MAC_REG_BASE + 0x698) - -#define AR9170_MAC_REG_SLOT_TIME (AR9170_MAC_REG_BASE + 0x6F0) - -#define AR9170_MAC_REG_POWERMANAGEMENT (AR9170_MAC_REG_BASE + 0x700) -#define AR9170_MAC_REG_POWERMGT_IBSS 0xe0 -#define AR9170_MAC_REG_POWERMGT_AP 0xa1 -#define AR9170_MAC_REG_POWERMGT_STA 0x2 -#define AR9170_MAC_REG_POWERMGT_AP_WDS 0x3 -#define AR9170_MAC_REG_POWERMGT_DEFAULTS (0xf << 24) - -#define AR9170_MAC_REG_ROLL_CALL_TBL_L (AR9170_MAC_REG_BASE + 0x704) -#define AR9170_MAC_REG_ROLL_CALL_TBL_H (AR9170_MAC_REG_BASE + 0x708) - -#define AR9170_MAC_REG_AC0_CW (AR9170_MAC_REG_BASE + 0xB00) -#define AR9170_MAC_REG_AC1_CW (AR9170_MAC_REG_BASE + 0xB04) -#define AR9170_MAC_REG_AC2_CW (AR9170_MAC_REG_BASE + 0xB08) -#define AR9170_MAC_REG_AC3_CW (AR9170_MAC_REG_BASE + 0xB0C) -#define AR9170_MAC_REG_AC4_CW (AR9170_MAC_REG_BASE + 0xB10) -#define AR9170_MAC_REG_AC1_AC0_AIFS (AR9170_MAC_REG_BASE + 0xB14) -#define AR9170_MAC_REG_AC3_AC2_AIFS (AR9170_MAC_REG_BASE + 0xB18) - -#define AR9170_MAC_REG_RETRY_MAX (AR9170_MAC_REG_BASE + 0xB28) - -#define AR9170_MAC_REG_FCS_SELECT (AR9170_MAC_REG_BASE + 0xBB0) -#define AR9170_MAC_FCS_SWFCS 0x1 -#define AR9170_MAC_FCS_FIFO_PROT 0x4 - - -#define AR9170_MAC_REG_TXOP_NOT_ENOUGH_IND (AR9170_MAC_REG_BASE + 0xB30) - -#define AR9170_MAC_REG_AC1_AC0_TXOP (AR9170_MAC_REG_BASE + 0xB44) -#define AR9170_MAC_REG_AC3_AC2_TXOP (AR9170_MAC_REG_BASE + 0xB48) - -#define AR9170_MAC_REG_AMPDU_FACTOR (AR9170_MAC_REG_BASE + 0xB9C) -#define AR9170_MAC_REG_AMPDU_DENSITY (AR9170_MAC_REG_BASE + 0xBA0) - -#define AR9170_MAC_REG_ACK_TABLE (AR9170_MAC_REG_BASE + 0xC00) -#define AR9170_MAC_REG_AMPDU_RX_THRESH (AR9170_MAC_REG_BASE + 0xC50) - -#define AR9170_MAC_REG_TXRX_MPI (AR9170_MAC_REG_BASE + 0xD7C) -#define AR9170_MAC_TXRX_MPI_TX_MPI_MASK 0x0000000f -#define AR9170_MAC_TXRX_MPI_TX_TO_MASK 0x0000fff0 -#define AR9170_MAC_TXRX_MPI_RX_MPI_MASK 0x000f0000 -#define AR9170_MAC_TXRX_MPI_RX_TO_MASK 0xfff00000 - -#define AR9170_MAC_REG_BCN_ADDR (AR9170_MAC_REG_BASE + 0xD84) -#define AR9170_MAC_REG_BCN_LENGTH (AR9170_MAC_REG_BASE + 0xD88) -#define AR9170_MAC_REG_BCN_PLCP (AR9170_MAC_REG_BASE + 0xD90) -#define AR9170_MAC_REG_BCN_CTRL (AR9170_MAC_REG_BASE + 0xD94) -#define AR9170_MAC_REG_BCN_HT1 (AR9170_MAC_REG_BASE + 0xDA0) -#define AR9170_MAC_REG_BCN_HT2 (AR9170_MAC_REG_BASE + 0xDA4) - - -#define AR9170_PWR_REG_BASE 0x1D4000 - -#define AR9170_PWR_REG_CLOCK_SEL (AR9170_PWR_REG_BASE + 0x008) -#define AR9170_PWR_CLK_AHB_40MHZ 0 -#define AR9170_PWR_CLK_AHB_20_22MHZ 1 -#define AR9170_PWR_CLK_AHB_40_44MHZ 2 -#define AR9170_PWR_CLK_AHB_80_88MHZ 3 -#define AR9170_PWR_CLK_DAC_160_INV_DLY 0x70 - - -/* put beacon here in memory */ -#define AR9170_BEACON_BUFFER_ADDRESS 0x117900 - - -struct ar9170_tx_control { - __le16 length; - __le16 mac_control; - __le32 phy_control; - u8 frame_data[0]; -} __packed; - -/* these are either-or */ -#define AR9170_TX_MAC_PROT_RTS 0x0001 -#define AR9170_TX_MAC_PROT_CTS 0x0002 - -#define AR9170_TX_MAC_NO_ACK 0x0004 -/* if unset, MAC will only do SIFS space before frame */ -#define AR9170_TX_MAC_BACKOFF 0x0008 -#define AR9170_TX_MAC_BURST 0x0010 -#define AR9170_TX_MAC_AGGR 0x0020 - -/* encryption is a two-bit field */ -#define AR9170_TX_MAC_ENCR_NONE 0x0000 -#define AR9170_TX_MAC_ENCR_RC4 0x0040 -#define AR9170_TX_MAC_ENCR_CENC 0x0080 -#define AR9170_TX_MAC_ENCR_AES 0x00c0 - -#define AR9170_TX_MAC_MMIC 0x0100 -#define AR9170_TX_MAC_HW_DURATION 0x0200 -#define AR9170_TX_MAC_QOS_SHIFT 10 -#define AR9170_TX_MAC_QOS_MASK (3 << AR9170_TX_MAC_QOS_SHIFT) -#define AR9170_TX_MAC_AGGR_QOS_BIT1 0x0400 -#define AR9170_TX_MAC_AGGR_QOS_BIT2 0x0800 -#define AR9170_TX_MAC_DISABLE_TXOP 0x1000 -#define AR9170_TX_MAC_TXOP_RIFS 0x2000 -#define AR9170_TX_MAC_IMM_AMPDU 0x4000 -#define AR9170_TX_MAC_RATE_PROBE 0x8000 - -/* either-or */ -#define AR9170_TX_PHY_MOD_MASK 0x00000003 -#define AR9170_TX_PHY_MOD_CCK 0x00000000 -#define AR9170_TX_PHY_MOD_OFDM 0x00000001 -#define AR9170_TX_PHY_MOD_HT 0x00000002 - -/* depends on modulation */ -#define AR9170_TX_PHY_SHORT_PREAMBLE 0x00000004 -#define AR9170_TX_PHY_GREENFIELD 0x00000004 - -#define AR9170_TX_PHY_BW_SHIFT 3 -#define AR9170_TX_PHY_BW_MASK (3 << AR9170_TX_PHY_BW_SHIFT) -#define AR9170_TX_PHY_BW_20MHZ 0 -#define AR9170_TX_PHY_BW_40MHZ 2 -#define AR9170_TX_PHY_BW_40MHZ_DUP 3 - -#define AR9170_TX_PHY_TX_HEAVY_CLIP_SHIFT 6 -#define AR9170_TX_PHY_TX_HEAVY_CLIP_MASK (7 << AR9170_TX_PHY_TX_HEAVY_CLIP_SHIFT) - -#define AR9170_TX_PHY_TX_PWR_SHIFT 9 -#define AR9170_TX_PHY_TX_PWR_MASK (0x3f << AR9170_TX_PHY_TX_PWR_SHIFT) - -/* not part of the hw-spec */ -#define AR9170_TX_PHY_QOS_SHIFT 25 -#define AR9170_TX_PHY_QOS_MASK (3 << AR9170_TX_PHY_QOS_SHIFT) - -#define AR9170_TX_PHY_TXCHAIN_SHIFT 15 -#define AR9170_TX_PHY_TXCHAIN_MASK (7 << AR9170_TX_PHY_TXCHAIN_SHIFT) -#define AR9170_TX_PHY_TXCHAIN_1 1 -/* use for cck, ofdm 6/9/12/18/24 and HT if capable */ -#define AR9170_TX_PHY_TXCHAIN_2 5 - -#define AR9170_TX_PHY_MCS_SHIFT 18 -#define AR9170_TX_PHY_MCS_MASK (0x7f << AR9170_TX_PHY_MCS_SHIFT) - -#define AR9170_TX_PHY_SHORT_GI 0x80000000 - -#define AR5416_MAX_RATE_POWER 63 - -struct ar9170_rx_head { - u8 plcp[12]; -} __packed; - -struct ar9170_rx_phystatus { - union { - struct { - u8 rssi_ant0, rssi_ant1, rssi_ant2, - rssi_ant0x, rssi_ant1x, rssi_ant2x, - rssi_combined; - } __packed; - u8 rssi[7]; - } __packed; - - u8 evm_stream0[6], evm_stream1[6]; - u8 phy_err; -} __packed; - -struct ar9170_rx_macstatus { - u8 SAidx, DAidx; - u8 error; - u8 status; -} __packed; - -#define AR9170_ENC_ALG_NONE 0x0 -#define AR9170_ENC_ALG_WEP64 0x1 -#define AR9170_ENC_ALG_TKIP 0x2 -#define AR9170_ENC_ALG_AESCCMP 0x4 -#define AR9170_ENC_ALG_WEP128 0x5 -#define AR9170_ENC_ALG_WEP256 0x6 -#define AR9170_ENC_ALG_CENC 0x7 - -#define AR9170_RX_ENC_SOFTWARE 0x8 - -static inline u8 ar9170_get_decrypt_type(struct ar9170_rx_macstatus *t) -{ - return (t->SAidx & 0xc0) >> 4 | - (t->DAidx & 0xc0) >> 6; -} - -#define AR9170_RX_STATUS_MODULATION_MASK 0x03 -#define AR9170_RX_STATUS_MODULATION_CCK 0x00 -#define AR9170_RX_STATUS_MODULATION_OFDM 0x01 -#define AR9170_RX_STATUS_MODULATION_HT 0x02 -#define AR9170_RX_STATUS_MODULATION_DUPOFDM 0x03 - -/* depends on modulation */ -#define AR9170_RX_STATUS_SHORT_PREAMBLE 0x08 -#define AR9170_RX_STATUS_GREENFIELD 0x08 - -#define AR9170_RX_STATUS_MPDU_MASK 0x30 -#define AR9170_RX_STATUS_MPDU_SINGLE 0x00 -#define AR9170_RX_STATUS_MPDU_FIRST 0x20 -#define AR9170_RX_STATUS_MPDU_MIDDLE 0x30 -#define AR9170_RX_STATUS_MPDU_LAST 0x10 - -#define AR9170_RX_ERROR_RXTO 0x01 -#define AR9170_RX_ERROR_OVERRUN 0x02 -#define AR9170_RX_ERROR_DECRYPT 0x04 -#define AR9170_RX_ERROR_FCS 0x08 -#define AR9170_RX_ERROR_WRONG_RA 0x10 -#define AR9170_RX_ERROR_PLCP 0x20 -#define AR9170_RX_ERROR_MMIC 0x40 -#define AR9170_RX_ERROR_FATAL 0x80 - -struct ar9170_cmd_tx_status { - u8 dst[ETH_ALEN]; - __le32 rate; - __le16 status; -} __packed; - -#define AR9170_TX_STATUS_COMPLETE 0x00 -#define AR9170_TX_STATUS_RETRY 0x01 -#define AR9170_TX_STATUS_FAILED 0x02 - -struct ar9170_cmd_ba_failed_count { - __le16 failed; - __le16 rate; -} __packed; - -struct ar9170_cmd_response { - u8 flag; - u8 type; - __le16 padding; - - union { - struct ar9170_cmd_tx_status tx_status; - struct ar9170_cmd_ba_failed_count ba_fail_cnt; - u8 data[0]; - }; -} __packed; - -/* QoS */ - -/* mac80211 queue to HW/FW map */ -static const u8 ar9170_qos_hwmap[4] = { 3, 2, 0, 1 }; - -/* HW/FW queue to mac80211 map */ -static const u8 ar9170_qos_mac80211map[4] = { 2, 3, 1, 0 }; - -enum ar9170_txq { - AR9170_TXQ_BE, - AR9170_TXQ_BK, - AR9170_TXQ_VI, - AR9170_TXQ_VO, - - __AR9170_NUM_TXQ, -}; - -#define AR9170_TXQ_DEPTH 32 -#define AR9170_TX_MAX_PENDING 128 -#define AR9170_RX_STREAM_MAX_SIZE 65535 - -#endif /* __AR9170_HW_H */ diff --git a/drivers/net/wireless/ath/ar9170/led.c b/drivers/net/wireless/ath/ar9170/led.c deleted file mode 100644 index 832d900..0000000 --- a/drivers/net/wireless/ath/ar9170/led.c +++ /dev/null @@ -1,181 +0,0 @@ -/* - * Atheros AR9170 driver - * - * LED handling - * - * Copyright 2008, Johannes Berg - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; see the file COPYING. If not, see - * http://www.gnu.org/licenses/. - * - * This file incorporates work covered by the following copyright and - * permission notice: - * Copyright (c) 2007-2008 Atheros Communications, Inc. - * - * 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 "ar9170.h" -#include "cmd.h" - -int ar9170_set_leds_state(struct ar9170 *ar, u32 led_state) -{ - return ar9170_write_reg(ar, AR9170_GPIO_REG_DATA, led_state); -} - -int ar9170_init_leds(struct ar9170 *ar) -{ - int err; - - /* disable LEDs */ - /* GPIO [0/1 mode: output, 2/3: input] */ - err = ar9170_write_reg(ar, AR9170_GPIO_REG_PORT_TYPE, 3); - if (err) - goto out; - - /* GPIO 0/1 value: off */ - err = ar9170_set_leds_state(ar, 0); - -out: - return err; -} - -#ifdef CONFIG_AR9170_LEDS -static void ar9170_update_leds(struct work_struct *work) -{ - struct ar9170 *ar = container_of(work, struct ar9170, led_work.work); - int i, tmp, blink_delay = 1000; - u32 led_val = 0; - bool rerun = false; - - if (unlikely(!IS_ACCEPTING_CMD(ar))) - return ; - - mutex_lock(&ar->mutex); - for (i = 0; i < AR9170_NUM_LEDS; i++) - if (ar->leds[i].registered && ar->leds[i].toggled) { - led_val |= 1 << i; - - tmp = 70 + 200 / (ar->leds[i].toggled); - if (tmp < blink_delay) - blink_delay = tmp; - - if (ar->leds[i].toggled > 1) - ar->leds[i].toggled = 0; - - rerun = true; - } - - ar9170_set_leds_state(ar, led_val); - mutex_unlock(&ar->mutex); - - if (!rerun) - return; - - ieee80211_queue_delayed_work(ar->hw, - &ar->led_work, - msecs_to_jiffies(blink_delay)); -} - -static void ar9170_led_brightness_set(struct led_classdev *led, - enum led_brightness brightness) -{ - struct ar9170_led *arl = container_of(led, struct ar9170_led, l); - struct ar9170 *ar = arl->ar; - - if (unlikely(!arl->registered)) - return ; - - if (arl->last_state != !!brightness) { - arl->toggled++; - arl->last_state = !!brightness; - } - - if (likely(IS_ACCEPTING_CMD(ar) && arl->toggled)) - ieee80211_queue_delayed_work(ar->hw, &ar->led_work, HZ/10); -} - -static int ar9170_register_led(struct ar9170 *ar, int i, char *name, - char *trigger) -{ - int err; - - snprintf(ar->leds[i].name, sizeof(ar->leds[i].name), - "ar9170-%s::%s", wiphy_name(ar->hw->wiphy), name); - - ar->leds[i].ar = ar; - ar->leds[i].l.name = ar->leds[i].name; - ar->leds[i].l.brightness_set = ar9170_led_brightness_set; - ar->leds[i].l.brightness = 0; - ar->leds[i].l.default_trigger = trigger; - - err = led_classdev_register(wiphy_dev(ar->hw->wiphy), - &ar->leds[i].l); - if (err) - wiphy_err(ar->hw->wiphy, "failed to register %s LED (%d).\n", - ar->leds[i].name, err); - else - ar->leds[i].registered = true; - - return err; -} - -void ar9170_unregister_leds(struct ar9170 *ar) -{ - int i; - - for (i = 0; i < AR9170_NUM_LEDS; i++) - if (ar->leds[i].registered) { - led_classdev_unregister(&ar->leds[i].l); - ar->leds[i].registered = false; - ar->leds[i].toggled = 0; - } - - cancel_delayed_work_sync(&ar->led_work); -} - -int ar9170_register_leds(struct ar9170 *ar) -{ - int err; - - INIT_DELAYED_WORK(&ar->led_work, ar9170_update_leds); - - err = ar9170_register_led(ar, 0, "tx", - ieee80211_get_tx_led_name(ar->hw)); - if (err) - goto fail; - - err = ar9170_register_led(ar, 1, "assoc", - ieee80211_get_assoc_led_name(ar->hw)); - if (err) - goto fail; - - return 0; - -fail: - ar9170_unregister_leds(ar); - return err; -} - -#endif /* CONFIG_AR9170_LEDS */ diff --git a/drivers/net/wireless/ath/ar9170/mac.c b/drivers/net/wireless/ath/ar9170/mac.c deleted file mode 100644 index 857e861..0000000 --- a/drivers/net/wireless/ath/ar9170/mac.c +++ /dev/null @@ -1,519 +0,0 @@ -/* - * Atheros AR9170 driver - * - * MAC programming - * - * Copyright 2008, Johannes Berg - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; see the file COPYING. If not, see - * http://www.gnu.org/licenses/. - * - * This file incorporates work covered by the following copyright and - * permission notice: - * Copyright (c) 2007-2008 Atheros Communications, Inc. - * - * 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 "ar9170.h" -#include "cmd.h" - -int ar9170_set_dyn_sifs_ack(struct ar9170 *ar) -{ - u32 val; - - if (conf_is_ht40(&ar->hw->conf)) - val = 0x010a; - else { - if (ar->hw->conf.channel->band == IEEE80211_BAND_2GHZ) - val = 0x105; - else - val = 0x104; - } - - return ar9170_write_reg(ar, AR9170_MAC_REG_DYNAMIC_SIFS_ACK, val); -} - -int ar9170_set_slot_time(struct ar9170 *ar) -{ - u32 slottime = 20; - - if (!ar->vif) - return 0; - - if ((ar->hw->conf.channel->band == IEEE80211_BAND_5GHZ) || - ar->vif->bss_conf.use_short_slot) - slottime = 9; - - return ar9170_write_reg(ar, AR9170_MAC_REG_SLOT_TIME, slottime << 10); -} - -int ar9170_set_basic_rates(struct ar9170 *ar) -{ - u8 cck, ofdm; - - if (!ar->vif) - return 0; - - ofdm = ar->vif->bss_conf.basic_rates >> 4; - - /* FIXME: is still necessary? */ - if (ar->hw->conf.channel->band == IEEE80211_BAND_5GHZ) - cck = 0; - else - cck = ar->vif->bss_conf.basic_rates & 0xf; - - return ar9170_write_reg(ar, AR9170_MAC_REG_BASIC_RATE, - ofdm << 8 | cck); -} - -int ar9170_set_qos(struct ar9170 *ar) -{ - ar9170_regwrite_begin(ar); - - ar9170_regwrite(AR9170_MAC_REG_AC0_CW, ar->edcf[0].cw_min | - (ar->edcf[0].cw_max << 16)); - ar9170_regwrite(AR9170_MAC_REG_AC1_CW, ar->edcf[1].cw_min | - (ar->edcf[1].cw_max << 16)); - ar9170_regwrite(AR9170_MAC_REG_AC2_CW, ar->edcf[2].cw_min | - (ar->edcf[2].cw_max << 16)); - ar9170_regwrite(AR9170_MAC_REG_AC3_CW, ar->edcf[3].cw_min | - (ar->edcf[3].cw_max << 16)); - ar9170_regwrite(AR9170_MAC_REG_AC4_CW, ar->edcf[4].cw_min | - (ar->edcf[4].cw_max << 16)); - - ar9170_regwrite(AR9170_MAC_REG_AC1_AC0_AIFS, - ((ar->edcf[0].aifs * 9 + 10)) | - ((ar->edcf[1].aifs * 9 + 10) << 12) | - ((ar->edcf[2].aifs * 9 + 10) << 24)); - ar9170_regwrite(AR9170_MAC_REG_AC3_AC2_AIFS, - ((ar->edcf[2].aifs * 9 + 10) >> 8) | - ((ar->edcf[3].aifs * 9 + 10) << 4) | - ((ar->edcf[4].aifs * 9 + 10) << 16)); - - ar9170_regwrite(AR9170_MAC_REG_AC1_AC0_TXOP, - ar->edcf[0].txop | ar->edcf[1].txop << 16); - ar9170_regwrite(AR9170_MAC_REG_AC3_AC2_TXOP, - ar->edcf[2].txop | ar->edcf[3].txop << 16); - - ar9170_regwrite_finish(); - - return ar9170_regwrite_result(); -} - -static int ar9170_set_ampdu_density(struct ar9170 *ar, u8 mpdudensity) -{ - u32 val; - - /* don't allow AMPDU density > 8us */ - if (mpdudensity > 6) - return -EINVAL; - - /* Watch out! Otus uses slightly different density values. */ - val = 0x140a00 | (mpdudensity ? (mpdudensity + 1) : 0); - - ar9170_regwrite_begin(ar); - ar9170_regwrite(AR9170_MAC_REG_AMPDU_DENSITY, val); - ar9170_regwrite_finish(); - - return ar9170_regwrite_result(); -} - -int ar9170_init_mac(struct ar9170 *ar) -{ - ar9170_regwrite_begin(ar); - - ar9170_regwrite(AR9170_MAC_REG_ACK_EXTENSION, 0x40); - - ar9170_regwrite(AR9170_MAC_REG_RETRY_MAX, 0); - - /* enable MMIC */ - ar9170_regwrite(AR9170_MAC_REG_SNIFFER, - AR9170_MAC_REG_SNIFFER_DEFAULTS); - - ar9170_regwrite(AR9170_MAC_REG_RX_THRESHOLD, 0xc1f80); - - ar9170_regwrite(AR9170_MAC_REG_RX_PE_DELAY, 0x70); - ar9170_regwrite(AR9170_MAC_REG_EIFS_AND_SIFS, 0xa144000); - ar9170_regwrite(AR9170_MAC_REG_SLOT_TIME, 9 << 10); - - /* CF-END mode */ - ar9170_regwrite(0x1c3b2c, 0x19000000); - - /* NAV protects ACK only (in TXOP) */ - ar9170_regwrite(0x1c3b38, 0x201); - - /* Set Beacon PHY CTRL's TPC to 0x7, TA1=1 */ - /* OTUS set AM to 0x1 */ - ar9170_regwrite(AR9170_MAC_REG_BCN_HT1, 0x8000170); - - ar9170_regwrite(AR9170_MAC_REG_BACKOFF_PROTECT, 0x105); - - /* AGG test code*/ - /* Aggregation MAX number and timeout */ - ar9170_regwrite(0x1c3b9c, 0x10000a); - - ar9170_regwrite(AR9170_MAC_REG_FRAMETYPE_FILTER, - AR9170_MAC_REG_FTF_DEFAULTS); - - /* Enable deaggregator, response in sniffer mode */ - ar9170_regwrite(0x1c3c40, 0x1 | 1<<30); - - /* rate sets */ - ar9170_regwrite(AR9170_MAC_REG_BASIC_RATE, 0x150f); - ar9170_regwrite(AR9170_MAC_REG_MANDATORY_RATE, 0x150f); - ar9170_regwrite(AR9170_MAC_REG_RTS_CTS_RATE, 0x10b01bb); - - /* MIMO response control */ - ar9170_regwrite(0x1c3694, 0x4003C1E);/* bit 26~28 otus-AM */ - - /* switch MAC to OTUS interface */ - ar9170_regwrite(0x1c3600, 0x3); - - ar9170_regwrite(AR9170_MAC_REG_AMPDU_RX_THRESH, 0xffff); - - /* set PHY register read timeout (??) */ - ar9170_regwrite(AR9170_MAC_REG_MISC_680, 0xf00008); - - /* Disable Rx TimeOut, workaround for BB. */ - ar9170_regwrite(AR9170_MAC_REG_RX_TIMEOUT, 0x0); - - /* Set CPU clock frequency to 88/80MHz */ - ar9170_regwrite(AR9170_PWR_REG_CLOCK_SEL, - AR9170_PWR_CLK_AHB_80_88MHZ | - AR9170_PWR_CLK_DAC_160_INV_DLY); - - /* Set WLAN DMA interrupt mode: generate int per packet */ - ar9170_regwrite(AR9170_MAC_REG_TXRX_MPI, 0x110011); - - ar9170_regwrite(AR9170_MAC_REG_FCS_SELECT, - AR9170_MAC_FCS_FIFO_PROT); - - /* Disables the CF_END frame, undocumented register */ - ar9170_regwrite(AR9170_MAC_REG_TXOP_NOT_ENOUGH_IND, - 0x141E0F48); - - ar9170_regwrite_finish(); - - return ar9170_regwrite_result(); -} - -static int ar9170_set_mac_reg(struct ar9170 *ar, const u32 reg, const u8 *mac) -{ - static const u8 zero[ETH_ALEN] = { 0 }; - - if (!mac) - mac = zero; - - ar9170_regwrite_begin(ar); - - ar9170_regwrite(reg, get_unaligned_le32(mac)); - ar9170_regwrite(reg + 4, get_unaligned_le16(mac + 4)); - - ar9170_regwrite_finish(); - - return ar9170_regwrite_result(); -} - -int ar9170_update_multicast(struct ar9170 *ar, const u64 mc_hash) -{ - int err; - - ar9170_regwrite_begin(ar); - ar9170_regwrite(AR9170_MAC_REG_GROUP_HASH_TBL_H, mc_hash >> 32); - ar9170_regwrite(AR9170_MAC_REG_GROUP_HASH_TBL_L, mc_hash); - ar9170_regwrite_finish(); - err = ar9170_regwrite_result(); - if (err) - return err; - - ar->cur_mc_hash = mc_hash; - return 0; -} - -int ar9170_update_frame_filter(struct ar9170 *ar, const u32 filter) -{ - int err; - - err = ar9170_write_reg(ar, AR9170_MAC_REG_FRAMETYPE_FILTER, filter); - if (err) - return err; - - ar->cur_filter = filter; - return 0; -} - -static int ar9170_set_promiscouous(struct ar9170 *ar) -{ - u32 encr_mode, sniffer; - int err; - - err = ar9170_read_reg(ar, AR9170_MAC_REG_SNIFFER, &sniffer); - if (err) - return err; - - err = ar9170_read_reg(ar, AR9170_MAC_REG_ENCRYPTION, &encr_mode); - if (err) - return err; - - if (ar->sniffer_enabled) { - sniffer |= AR9170_MAC_REG_SNIFFER_ENABLE_PROMISC; - - /* - * Rx decryption works in place. - * - * If we don't disable it, the hardware will render all - * encrypted frames which are encrypted with an unknown - * key useless. - */ - - encr_mode |= AR9170_MAC_REG_ENCRYPTION_RX_SOFTWARE; - ar->sniffer_enabled = true; - } else { - sniffer &= ~AR9170_MAC_REG_SNIFFER_ENABLE_PROMISC; - - if (ar->rx_software_decryption) - encr_mode |= AR9170_MAC_REG_ENCRYPTION_RX_SOFTWARE; - else - encr_mode &= ~AR9170_MAC_REG_ENCRYPTION_RX_SOFTWARE; - } - - ar9170_regwrite_begin(ar); - ar9170_regwrite(AR9170_MAC_REG_ENCRYPTION, encr_mode); - ar9170_regwrite(AR9170_MAC_REG_SNIFFER, sniffer); - ar9170_regwrite_finish(); - - return ar9170_regwrite_result(); -} - -int ar9170_set_operating_mode(struct ar9170 *ar) -{ - struct ath_common *common = &ar->common; - u32 pm_mode = AR9170_MAC_REG_POWERMGT_DEFAULTS; - u8 *mac_addr, *bssid; - int err; - - if (ar->vif) { - mac_addr = common->macaddr; - bssid = common->curbssid; - - switch (ar->vif->type) { - case NL80211_IFTYPE_MESH_POINT: - case NL80211_IFTYPE_ADHOC: - pm_mode |= AR9170_MAC_REG_POWERMGT_IBSS; - break; - case NL80211_IFTYPE_AP: - pm_mode |= AR9170_MAC_REG_POWERMGT_AP; - break; - case NL80211_IFTYPE_WDS: - pm_mode |= AR9170_MAC_REG_POWERMGT_AP_WDS; - break; - case NL80211_IFTYPE_MONITOR: - ar->sniffer_enabled = true; - ar->rx_software_decryption = true; - break; - default: - pm_mode |= AR9170_MAC_REG_POWERMGT_STA; - break; - } - } else { - mac_addr = NULL; - bssid = NULL; - } - - err = ar9170_set_mac_reg(ar, AR9170_MAC_REG_MAC_ADDR_L, mac_addr); - if (err) - return err; - - err = ar9170_set_mac_reg(ar, AR9170_MAC_REG_BSSID_L, bssid); - if (err) - return err; - - err = ar9170_set_promiscouous(ar); - if (err) - return err; - - /* set AMPDU density to 8us. */ - err = ar9170_set_ampdu_density(ar, 6); - if (err) - return err; - - ar9170_regwrite_begin(ar); - - ar9170_regwrite(AR9170_MAC_REG_POWERMANAGEMENT, pm_mode); - ar9170_regwrite_finish(); - - return ar9170_regwrite_result(); -} - -int ar9170_set_hwretry_limit(struct ar9170 *ar, unsigned int max_retry) -{ - u32 tmp = min_t(u32, 0x33333, max_retry * 0x11111); - - return ar9170_write_reg(ar, AR9170_MAC_REG_RETRY_MAX, tmp); -} - -int ar9170_set_beacon_timers(struct ar9170 *ar) -{ - u32 v = 0; - u32 pretbtt = 0; - - if (ar->vif) { - v |= ar->vif->bss_conf.beacon_int; - - if (ar->enable_beacon) { - switch (ar->vif->type) { - case NL80211_IFTYPE_MESH_POINT: - case NL80211_IFTYPE_ADHOC: - v |= BIT(25); - break; - case NL80211_IFTYPE_AP: - v |= BIT(24); - pretbtt = (ar->vif->bss_conf.beacon_int - 6) << - 16; - break; - default: - break; - } - } - - v |= ar->vif->bss_conf.dtim_period << 16; - } - - ar9170_regwrite_begin(ar); - ar9170_regwrite(AR9170_MAC_REG_PRETBTT, pretbtt); - ar9170_regwrite(AR9170_MAC_REG_BCN_PERIOD, v); - ar9170_regwrite_finish(); - return ar9170_regwrite_result(); -} - -int ar9170_update_beacon(struct ar9170 *ar) -{ - struct sk_buff *skb; - __le32 *data, *old = NULL; - u32 word; - int i; - - skb = ieee80211_beacon_get(ar->hw, ar->vif); - if (!skb) - return -ENOMEM; - - data = (__le32 *)skb->data; - if (ar->beacon) - old = (__le32 *)ar->beacon->data; - - ar9170_regwrite_begin(ar); - for (i = 0; i < DIV_ROUND_UP(skb->len, 4); i++) { - /* - * XXX: This accesses beyond skb data for up - * to the last 3 bytes!! - */ - - if (old && (data[i] == old[i])) - continue; - - word = le32_to_cpu(data[i]); - ar9170_regwrite(AR9170_BEACON_BUFFER_ADDRESS + 4 * i, word); - } - - /* XXX: use skb->cb info */ - if (ar->hw->conf.channel->band == IEEE80211_BAND_2GHZ) - ar9170_regwrite(AR9170_MAC_REG_BCN_PLCP, - ((skb->len + 4) << (3 + 16)) + 0x0400); - else - ar9170_regwrite(AR9170_MAC_REG_BCN_PLCP, - ((skb->len + 4) << 16) + 0x001b); - - ar9170_regwrite(AR9170_MAC_REG_BCN_LENGTH, skb->len + 4); - ar9170_regwrite(AR9170_MAC_REG_BCN_ADDR, AR9170_BEACON_BUFFER_ADDRESS); - ar9170_regwrite(AR9170_MAC_REG_BCN_CTRL, 1); - - ar9170_regwrite_finish(); - - dev_kfree_skb(ar->beacon); - ar->beacon = skb; - - return ar9170_regwrite_result(); -} - -void ar9170_new_beacon(struct work_struct *work) -{ - struct ar9170 *ar = container_of(work, struct ar9170, - beacon_work); - struct sk_buff *skb; - - if (unlikely(!IS_STARTED(ar))) - return ; - - mutex_lock(&ar->mutex); - - if (!ar->vif) - goto out; - - ar9170_update_beacon(ar); - - rcu_read_lock(); - while ((skb = ieee80211_get_buffered_bc(ar->hw, ar->vif))) - ar9170_op_tx(ar->hw, skb); - - rcu_read_unlock(); - - out: - mutex_unlock(&ar->mutex); -} - -int ar9170_upload_key(struct ar9170 *ar, u8 id, const u8 *mac, u8 ktype, - u8 keyidx, u8 *keydata, int keylen) -{ - __le32 vals[7]; - static const u8 bcast[ETH_ALEN] = - { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; - u8 dummy; - - mac = mac ? : bcast; - - vals[0] = cpu_to_le32((keyidx << 16) + id); - vals[1] = cpu_to_le32(mac[1] << 24 | mac[0] << 16 | ktype); - vals[2] = cpu_to_le32(mac[5] << 24 | mac[4] << 16 | - mac[3] << 8 | mac[2]); - memset(&vals[3], 0, 16); - if (keydata) - memcpy(&vals[3], keydata, keylen); - - return ar->exec_cmd(ar, AR9170_CMD_EKEY, - sizeof(vals), (u8 *)vals, - 1, &dummy); -} - -int ar9170_disable_key(struct ar9170 *ar, u8 id) -{ - __le32 val = cpu_to_le32(id); - u8 dummy; - - return ar->exec_cmd(ar, AR9170_CMD_EKEY, - sizeof(val), (u8 *)&val, - 1, &dummy); -} diff --git a/drivers/net/wireless/ath/ar9170/main.c b/drivers/net/wireless/ath/ar9170/main.c deleted file mode 100644 index b761fec..0000000 --- a/drivers/net/wireless/ath/ar9170/main.c +++ /dev/null @@ -1,2190 +0,0 @@ -/* - * Atheros AR9170 driver - * - * mac80211 interaction code - * - * Copyright 2008, Johannes Berg - * Copyright 2009, Christian Lamparter - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; see the file COPYING. If not, see - * http://www.gnu.org/licenses/. - * - * This file incorporates work covered by the following copyright and - * permission notice: - * Copyright (c) 2007-2008 Atheros Communications, Inc. - * - * 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 -#include -#include -#include "ar9170.h" -#include "hw.h" -#include "cmd.h" - -static int modparam_nohwcrypt; -module_param_named(nohwcrypt, modparam_nohwcrypt, bool, S_IRUGO); -MODULE_PARM_DESC(nohwcrypt, "Disable hardware encryption."); - -#define RATE(_bitrate, _hw_rate, _txpidx, _flags) { \ - .bitrate = (_bitrate), \ - .flags = (_flags), \ - .hw_value = (_hw_rate) | (_txpidx) << 4, \ -} - -static struct ieee80211_rate __ar9170_ratetable[] = { - RATE(10, 0, 0, 0), - RATE(20, 1, 1, IEEE80211_RATE_SHORT_PREAMBLE), - RATE(55, 2, 2, IEEE80211_RATE_SHORT_PREAMBLE), - RATE(110, 3, 3, IEEE80211_RATE_SHORT_PREAMBLE), - RATE(60, 0xb, 0, 0), - RATE(90, 0xf, 0, 0), - RATE(120, 0xa, 0, 0), - RATE(180, 0xe, 0, 0), - RATE(240, 0x9, 0, 0), - RATE(360, 0xd, 1, 0), - RATE(480, 0x8, 2, 0), - RATE(540, 0xc, 3, 0), -}; -#undef RATE - -#define ar9170_g_ratetable (__ar9170_ratetable + 0) -#define ar9170_g_ratetable_size 12 -#define ar9170_a_ratetable (__ar9170_ratetable + 4) -#define ar9170_a_ratetable_size 8 - -/* - * NB: The hw_value is used as an index into the ar9170_phy_freq_params - * array in phy.c so that we don't have to do frequency lookups! - */ -#define CHAN(_freq, _idx) { \ - .center_freq = (_freq), \ - .hw_value = (_idx), \ - .max_power = 18, /* XXX */ \ -} - -static struct ieee80211_channel ar9170_2ghz_chantable[] = { - CHAN(2412, 0), - CHAN(2417, 1), - CHAN(2422, 2), - CHAN(2427, 3), - CHAN(2432, 4), - CHAN(2437, 5), - CHAN(2442, 6), - CHAN(2447, 7), - CHAN(2452, 8), - CHAN(2457, 9), - CHAN(2462, 10), - CHAN(2467, 11), - CHAN(2472, 12), - CHAN(2484, 13), -}; - -static struct ieee80211_channel ar9170_5ghz_chantable[] = { - CHAN(4920, 14), - CHAN(4940, 15), - CHAN(4960, 16), - CHAN(4980, 17), - CHAN(5040, 18), - CHAN(5060, 19), - CHAN(5080, 20), - CHAN(5180, 21), - CHAN(5200, 22), - CHAN(5220, 23), - CHAN(5240, 24), - CHAN(5260, 25), - CHAN(5280, 26), - CHAN(5300, 27), - CHAN(5320, 28), - CHAN(5500, 29), - CHAN(5520, 30), - CHAN(5540, 31), - CHAN(5560, 32), - CHAN(5580, 33), - CHAN(5600, 34), - CHAN(5620, 35), - CHAN(5640, 36), - CHAN(5660, 37), - CHAN(5680, 38), - CHAN(5700, 39), - CHAN(5745, 40), - CHAN(5765, 41), - CHAN(5785, 42), - CHAN(5805, 43), - CHAN(5825, 44), - CHAN(5170, 45), - CHAN(5190, 46), - CHAN(5210, 47), - CHAN(5230, 48), -}; -#undef CHAN - -#define AR9170_HT_CAP \ -{ \ - .ht_supported = true, \ - .cap = IEEE80211_HT_CAP_MAX_AMSDU | \ - IEEE80211_HT_CAP_SUP_WIDTH_20_40 | \ - IEEE80211_HT_CAP_SGI_40 | \ - IEEE80211_HT_CAP_GRN_FLD | \ - IEEE80211_HT_CAP_DSSSCCK40 | \ - IEEE80211_HT_CAP_SM_PS, \ - .ampdu_factor = 3, \ - .ampdu_density = 6, \ - .mcs = { \ - .rx_mask = { 0xff, 0xff, 0, 0, 0x1, 0, 0, 0, 0, 0, }, \ - .rx_highest = cpu_to_le16(300), \ - .tx_params = IEEE80211_HT_MCS_TX_DEFINED, \ - }, \ -} - -static struct ieee80211_supported_band ar9170_band_2GHz = { - .channels = ar9170_2ghz_chantable, - .n_channels = ARRAY_SIZE(ar9170_2ghz_chantable), - .bitrates = ar9170_g_ratetable, - .n_bitrates = ar9170_g_ratetable_size, - .ht_cap = AR9170_HT_CAP, -}; - -static struct ieee80211_supported_band ar9170_band_5GHz = { - .channels = ar9170_5ghz_chantable, - .n_channels = ARRAY_SIZE(ar9170_5ghz_chantable), - .bitrates = ar9170_a_ratetable, - .n_bitrates = ar9170_a_ratetable_size, - .ht_cap = AR9170_HT_CAP, -}; - -static void ar9170_tx(struct ar9170 *ar); - -static inline u16 ar9170_get_seq_h(struct ieee80211_hdr *hdr) -{ - return le16_to_cpu(hdr->seq_ctrl) >> 4; -} - -static inline u16 ar9170_get_seq(struct sk_buff *skb) -{ - struct ar9170_tx_control *txc = (void *) skb->data; - return ar9170_get_seq_h((void *) txc->frame_data); -} - -#ifdef AR9170_QUEUE_DEBUG -static void ar9170_print_txheader(struct ar9170 *ar, struct sk_buff *skb) -{ - struct ar9170_tx_control *txc = (void *) skb->data; - struct ieee80211_tx_info *txinfo = IEEE80211_SKB_CB(skb); - struct ar9170_tx_info *arinfo = (void *) txinfo->rate_driver_data; - struct ieee80211_hdr *hdr = (void *) txc->frame_data; - - wiphy_debug(ar->hw->wiphy, - "=> FRAME [skb:%p, q:%d, DA:[%pM] s:%d " - "mac_ctrl:%04x, phy_ctrl:%08x, timeout:[%d ms]]\n", - skb, skb_get_queue_mapping(skb), - ieee80211_get_DA(hdr), ar9170_get_seq_h(hdr), - le16_to_cpu(txc->mac_control), le32_to_cpu(txc->phy_control), - jiffies_to_msecs(arinfo->timeout - jiffies)); -} - -static void __ar9170_dump_txqueue(struct ar9170 *ar, - struct sk_buff_head *queue) -{ - struct sk_buff *skb; - int i = 0; - - printk(KERN_DEBUG "---[ cut here ]---\n"); - wiphy_debug(ar->hw->wiphy, "%d entries in queue.\n", - skb_queue_len(queue)); - - skb_queue_walk(queue, skb) { - printk(KERN_DEBUG "index:%d =>\n", i++); - ar9170_print_txheader(ar, skb); - } - if (i != skb_queue_len(queue)) - printk(KERN_DEBUG "WARNING: queue frame counter " - "mismatch %d != %d\n", skb_queue_len(queue), i); - printk(KERN_DEBUG "---[ end ]---\n"); -} -#endif /* AR9170_QUEUE_DEBUG */ - -#ifdef AR9170_QUEUE_DEBUG -static void ar9170_dump_txqueue(struct ar9170 *ar, - struct sk_buff_head *queue) -{ - unsigned long flags; - - spin_lock_irqsave(&queue->lock, flags); - __ar9170_dump_txqueue(ar, queue); - spin_unlock_irqrestore(&queue->lock, flags); -} -#endif /* AR9170_QUEUE_DEBUG */ - -#ifdef AR9170_QUEUE_STOP_DEBUG -static void __ar9170_dump_txstats(struct ar9170 *ar) -{ - int i; - - wiphy_debug(ar->hw->wiphy, "QoS queue stats\n"); - - for (i = 0; i < __AR9170_NUM_TXQ; i++) - wiphy_debug(ar->hw->wiphy, - "queue:%d limit:%d len:%d waitack:%d stopped:%d\n", - i, ar->tx_stats[i].limit, ar->tx_stats[i].len, - skb_queue_len(&ar->tx_status[i]), - ieee80211_queue_stopped(ar->hw, i)); -} -#endif /* AR9170_QUEUE_STOP_DEBUG */ - -/* caller must guarantee exclusive access for _bin_ queue. */ -static void ar9170_recycle_expired(struct ar9170 *ar, - struct sk_buff_head *queue, - struct sk_buff_head *bin) -{ - struct sk_buff *skb, *old = NULL; - unsigned long flags; - - spin_lock_irqsave(&queue->lock, flags); - while ((skb = skb_peek(queue))) { - struct ieee80211_tx_info *txinfo; - struct ar9170_tx_info *arinfo; - - txinfo = IEEE80211_SKB_CB(skb); - arinfo = (void *) txinfo->rate_driver_data; - - if (time_is_before_jiffies(arinfo->timeout)) { -#ifdef AR9170_QUEUE_DEBUG - wiphy_debug(ar->hw->wiphy, - "[%ld > %ld] frame expired => recycle\n", - jiffies, arinfo->timeout); - ar9170_print_txheader(ar, skb); -#endif /* AR9170_QUEUE_DEBUG */ - __skb_unlink(skb, queue); - __skb_queue_tail(bin, skb); - } else { - break; - } - - if (unlikely(old == skb)) { - /* bail out - queue is shot. */ - - WARN_ON(1); - break; - } - old = skb; - } - spin_unlock_irqrestore(&queue->lock, flags); -} - -static void ar9170_tx_status(struct ar9170 *ar, struct sk_buff *skb, - u16 tx_status) -{ - struct ieee80211_tx_info *txinfo; - unsigned int retries = 0; - - txinfo = IEEE80211_SKB_CB(skb); - ieee80211_tx_info_clear_status(txinfo); - - switch (tx_status) { - case AR9170_TX_STATUS_RETRY: - retries = 2; - case AR9170_TX_STATUS_COMPLETE: - txinfo->flags |= IEEE80211_TX_STAT_ACK; - break; - - case AR9170_TX_STATUS_FAILED: - retries = ar->hw->conf.long_frame_max_tx_count; - break; - - default: - wiphy_err(ar->hw->wiphy, - "invalid tx_status response (%x)\n", tx_status); - break; - } - - txinfo->status.rates[0].count = retries + 1; - skb_pull(skb, sizeof(struct ar9170_tx_control)); - ieee80211_tx_status_irqsafe(ar->hw, skb); -} - -void ar9170_tx_callback(struct ar9170 *ar, struct sk_buff *skb) -{ - struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); - struct ar9170_tx_info *arinfo = (void *) info->rate_driver_data; - unsigned int queue = skb_get_queue_mapping(skb); - unsigned long flags; - - spin_lock_irqsave(&ar->tx_stats_lock, flags); - ar->tx_stats[queue].len--; - - if (ar->tx_stats[queue].len < AR9170_NUM_TX_LIMIT_SOFT) { -#ifdef AR9170_QUEUE_STOP_DEBUG - wiphy_debug(ar->hw->wiphy, "wake queue %d\n", queue); - __ar9170_dump_txstats(ar); -#endif /* AR9170_QUEUE_STOP_DEBUG */ - ieee80211_wake_queue(ar->hw, queue); - } - spin_unlock_irqrestore(&ar->tx_stats_lock, flags); - - if (info->flags & IEEE80211_TX_CTL_NO_ACK) { - ar9170_tx_status(ar, skb, AR9170_TX_STATUS_FAILED); - } else { - arinfo->timeout = jiffies + - msecs_to_jiffies(AR9170_TX_TIMEOUT); - - skb_queue_tail(&ar->tx_status[queue], skb); - } - - if (!ar->tx_stats[queue].len && - !skb_queue_empty(&ar->tx_pending[queue])) { - ar9170_tx(ar); - } -} - -static struct sk_buff *ar9170_get_queued_skb(struct ar9170 *ar, - const u8 *mac, - struct sk_buff_head *queue, - const u32 rate) -{ - unsigned long flags; - struct sk_buff *skb; - - /* - * Unfortunately, the firmware does not tell to which (queued) frame - * this transmission status report belongs to. - * - * So we have to make risky guesses - with the scarce information - * the firmware provided (-> destination MAC, and phy_control) - - * and hope that we picked the right one... - */ - - spin_lock_irqsave(&queue->lock, flags); - skb_queue_walk(queue, skb) { - struct ar9170_tx_control *txc = (void *) skb->data; - struct ieee80211_hdr *hdr = (void *) txc->frame_data; - u32 r; - - if (mac && compare_ether_addr(ieee80211_get_DA(hdr), mac)) { -#ifdef AR9170_QUEUE_DEBUG - wiphy_debug(ar->hw->wiphy, - "skip frame => DA %pM != %pM\n", - mac, ieee80211_get_DA(hdr)); - ar9170_print_txheader(ar, skb); -#endif /* AR9170_QUEUE_DEBUG */ - continue; - } - - r = (le32_to_cpu(txc->phy_control) & AR9170_TX_PHY_MCS_MASK) >> - AR9170_TX_PHY_MCS_SHIFT; - - if ((rate != AR9170_TX_INVALID_RATE) && (r != rate)) { -#ifdef AR9170_QUEUE_DEBUG - wiphy_debug(ar->hw->wiphy, - "skip frame => rate %d != %d\n", rate, r); - ar9170_print_txheader(ar, skb); -#endif /* AR9170_QUEUE_DEBUG */ - continue; - } - - __skb_unlink(skb, queue); - spin_unlock_irqrestore(&queue->lock, flags); - return skb; - } - -#ifdef AR9170_QUEUE_DEBUG - wiphy_err(ar->hw->wiphy, - "ESS:[%pM] does not have any outstanding frames in queue.\n", - mac); - __ar9170_dump_txqueue(ar, queue); -#endif /* AR9170_QUEUE_DEBUG */ - spin_unlock_irqrestore(&queue->lock, flags); - - return NULL; -} - -/* - * This worker tries to keeps an maintain tx_status queues. - * So we can guarantee that incoming tx_status reports are - * actually for a pending frame. - */ - -static void ar9170_tx_janitor(struct work_struct *work) -{ - struct ar9170 *ar = container_of(work, struct ar9170, - tx_janitor.work); - struct sk_buff_head waste; - unsigned int i; - bool resched = false; - - if (unlikely(!IS_STARTED(ar))) - return ; - - skb_queue_head_init(&waste); - - for (i = 0; i < __AR9170_NUM_TXQ; i++) { -#ifdef AR9170_QUEUE_DEBUG - wiphy_debug(ar->hw->wiphy, "garbage collector scans queue:%d\n", - i); - ar9170_dump_txqueue(ar, &ar->tx_pending[i]); - ar9170_dump_txqueue(ar, &ar->tx_status[i]); -#endif /* AR9170_QUEUE_DEBUG */ - - ar9170_recycle_expired(ar, &ar->tx_status[i], &waste); - ar9170_recycle_expired(ar, &ar->tx_pending[i], &waste); - skb_queue_purge(&waste); - - if (!skb_queue_empty(&ar->tx_status[i]) || - !skb_queue_empty(&ar->tx_pending[i])) - resched = true; - } - - if (!resched) - return; - - ieee80211_queue_delayed_work(ar->hw, - &ar->tx_janitor, - msecs_to_jiffies(AR9170_JANITOR_DELAY)); -} - -void ar9170_handle_command_response(struct ar9170 *ar, void *buf, u32 len) -{ - struct ar9170_cmd_response *cmd = (void *) buf; - - if ((cmd->type & 0xc0) != 0xc0) { - ar->callback_cmd(ar, len, buf); - return; - } - - /* hardware event handlers */ - switch (cmd->type) { - case 0xc1: { - /* - * TX status notification: - * bytes: 0c c1 XX YY M1 M2 M3 M4 M5 M6 R4 R3 R2 R1 S2 S1 - * - * XX always 81 - * YY always 00 - * M1-M6 is the MAC address - * R1-R4 is the transmit rate - * S1-S2 is the transmit status - */ - - struct sk_buff *skb; - u32 phy = le32_to_cpu(cmd->tx_status.rate); - u32 q = (phy & AR9170_TX_PHY_QOS_MASK) >> - AR9170_TX_PHY_QOS_SHIFT; -#ifdef AR9170_QUEUE_DEBUG - wiphy_debug(ar->hw->wiphy, - "recv tx_status for %pm, p:%08x, q:%d\n", - cmd->tx_status.dst, phy, q); -#endif /* AR9170_QUEUE_DEBUG */ - - skb = ar9170_get_queued_skb(ar, cmd->tx_status.dst, - &ar->tx_status[q], - AR9170_TX_INVALID_RATE); - if (unlikely(!skb)) - return ; - - ar9170_tx_status(ar, skb, le16_to_cpu(cmd->tx_status.status)); - break; - } - - case 0xc0: - /* - * pre-TBTT event - */ - if (ar->vif && ar->vif->type == NL80211_IFTYPE_AP) - ieee80211_queue_work(ar->hw, &ar->beacon_work); - break; - - case 0xc2: - /* - * (IBSS) beacon send notification - * bytes: 04 c2 XX YY B4 B3 B2 B1 - * - * XX always 80 - * YY always 00 - * B1-B4 "should" be the number of send out beacons. - */ - break; - - case 0xc3: - /* End of Atim Window */ - break; - - case 0xc4: - /* BlockACK bitmap */ - break; - - case 0xc5: - /* BlockACK events */ - break; - - case 0xc6: - /* Watchdog Interrupt */ - break; - - case 0xc9: - /* retransmission issue / SIFS/EIFS collision ?! */ - break; - - /* firmware debug */ - case 0xca: - printk(KERN_DEBUG "ar9170 FW: %.*s\n", len - 4, - (char *)buf + 4); - break; - case 0xcb: - len -= 4; - - switch (len) { - case 1: - printk(KERN_DEBUG "ar9170 FW: u8: %#.2x\n", - *((char *)buf + 4)); - break; - case 2: - printk(KERN_DEBUG "ar9170 FW: u8: %#.4x\n", - le16_to_cpup((__le16 *)((char *)buf + 4))); - break; - case 4: - printk(KERN_DEBUG "ar9170 FW: u8: %#.8x\n", - le32_to_cpup((__le32 *)((char *)buf + 4))); - break; - case 8: - printk(KERN_DEBUG "ar9170 FW: u8: %#.16lx\n", - (unsigned long)le64_to_cpup( - (__le64 *)((char *)buf + 4))); - break; - } - break; - case 0xcc: - print_hex_dump_bytes("ar9170 FW:", DUMP_PREFIX_NONE, - (char *)buf + 4, len - 4); - break; - - default: - pr_info("received unhandled event %x\n", cmd->type); - print_hex_dump_bytes("dump:", DUMP_PREFIX_NONE, buf, len); - break; - } -} - -static void ar9170_rx_reset_rx_mpdu(struct ar9170 *ar) -{ - memset(&ar->rx_mpdu.plcp, 0, sizeof(struct ar9170_rx_head)); - ar->rx_mpdu.has_plcp = false; -} - -int ar9170_nag_limiter(struct ar9170 *ar) -{ - bool print_message; - - /* - * we expect all sorts of errors in promiscuous mode. - * don't bother with it, it's OK! - */ - if (ar->sniffer_enabled) - return false; - - /* - * only go for frequent errors! The hardware tends to - * do some stupid thing once in a while under load, in - * noisy environments or just for fun! - */ - if (time_before(jiffies, ar->bad_hw_nagger) && net_ratelimit()) - print_message = true; - else - print_message = false; - - /* reset threshold for "once in a while" */ - ar->bad_hw_nagger = jiffies + HZ / 4; - return print_message; -} - -static int ar9170_rx_mac_status(struct ar9170 *ar, - struct ar9170_rx_head *head, - struct ar9170_rx_macstatus *mac, - struct ieee80211_rx_status *status) -{ - u8 error, decrypt; - - BUILD_BUG_ON(sizeof(struct ar9170_rx_head) != 12); - BUILD_BUG_ON(sizeof(struct ar9170_rx_macstatus) != 4); - - error = mac->error; - if (error & AR9170_RX_ERROR_MMIC) { - status->flag |= RX_FLAG_MMIC_ERROR; - error &= ~AR9170_RX_ERROR_MMIC; - } - - if (error & AR9170_RX_ERROR_PLCP) { - status->flag |= RX_FLAG_FAILED_PLCP_CRC; - error &= ~AR9170_RX_ERROR_PLCP; - - if (!(ar->filter_state & FIF_PLCPFAIL)) - return -EINVAL; - } - - if (error & AR9170_RX_ERROR_FCS) { - status->flag |= RX_FLAG_FAILED_FCS_CRC; - error &= ~AR9170_RX_ERROR_FCS; - - if (!(ar->filter_state & FIF_FCSFAIL)) - return -EINVAL; - } - - decrypt = ar9170_get_decrypt_type(mac); - if (!(decrypt & AR9170_RX_ENC_SOFTWARE) && - decrypt != AR9170_ENC_ALG_NONE) - status->flag |= RX_FLAG_DECRYPTED; - - /* ignore wrong RA errors */ - error &= ~AR9170_RX_ERROR_WRONG_RA; - - if (error & AR9170_RX_ERROR_DECRYPT) { - error &= ~AR9170_RX_ERROR_DECRYPT; - /* - * Rx decryption is done in place, - * the original data is lost anyway. - */ - - return -EINVAL; - } - - /* drop any other error frames */ - if (unlikely(error)) { - /* TODO: update netdevice's RX dropped/errors statistics */ - - if (ar9170_nag_limiter(ar)) - wiphy_debug(ar->hw->wiphy, - "received frame with suspicious error code (%#x).\n", - error); - - return -EINVAL; - } - - status->band = ar->channel->band; - status->freq = ar->channel->center_freq; - - switch (mac->status & AR9170_RX_STATUS_MODULATION_MASK) { - case AR9170_RX_STATUS_MODULATION_CCK: - if (mac->status & AR9170_RX_STATUS_SHORT_PREAMBLE) - status->flag |= RX_FLAG_SHORTPRE; - switch (head->plcp[0]) { - case 0x0a: - status->rate_idx = 0; - break; - case 0x14: - status->rate_idx = 1; - break; - case 0x37: - status->rate_idx = 2; - break; - case 0x6e: - status->rate_idx = 3; - break; - default: - if (ar9170_nag_limiter(ar)) - wiphy_err(ar->hw->wiphy, - "invalid plcp cck rate (%x).\n", - head->plcp[0]); - return -EINVAL; - } - break; - - case AR9170_RX_STATUS_MODULATION_DUPOFDM: - case AR9170_RX_STATUS_MODULATION_OFDM: - switch (head->plcp[0] & 0xf) { - case 0xb: - status->rate_idx = 0; - break; - case 0xf: - status->rate_idx = 1; - break; - case 0xa: - status->rate_idx = 2; - break; - case 0xe: - status->rate_idx = 3; - break; - case 0x9: - status->rate_idx = 4; - break; - case 0xd: - status->rate_idx = 5; - break; - case 0x8: - status->rate_idx = 6; - break; - case 0xc: - status->rate_idx = 7; - break; - default: - if (ar9170_nag_limiter(ar)) - wiphy_err(ar->hw->wiphy, - "invalid plcp ofdm rate (%x).\n", - head->plcp[0]); - return -EINVAL; - } - if (status->band == IEEE80211_BAND_2GHZ) - status->rate_idx += 4; - break; - - case AR9170_RX_STATUS_MODULATION_HT: - if (head->plcp[3] & 0x80) - status->flag |= RX_FLAG_40MHZ; - if (head->plcp[6] & 0x80) - status->flag |= RX_FLAG_SHORT_GI; - - status->rate_idx = clamp(0, 75, head->plcp[6] & 0x7f); - status->flag |= RX_FLAG_HT; - break; - - default: - if (ar9170_nag_limiter(ar)) - wiphy_err(ar->hw->wiphy, "invalid modulation\n"); - return -EINVAL; - } - - return 0; -} - -static void ar9170_rx_phy_status(struct ar9170 *ar, - struct ar9170_rx_phystatus *phy, - struct ieee80211_rx_status *status) -{ - int i; - - BUILD_BUG_ON(sizeof(struct ar9170_rx_phystatus) != 20); - - for (i = 0; i < 3; i++) - if (phy->rssi[i] != 0x80) - status->antenna |= BIT(i); - - /* post-process RSSI */ - for (i = 0; i < 7; i++) - if (phy->rssi[i] & 0x80) - phy->rssi[i] = ((phy->rssi[i] & 0x7f) + 1) & 0x7f; - - /* TODO: we could do something with phy_errors */ - status->signal = ar->noise[0] + phy->rssi_combined; -} - -static struct sk_buff *ar9170_rx_copy_data(u8 *buf, int len) -{ - struct sk_buff *skb; - int reserved = 0; - struct ieee80211_hdr *hdr = (void *) buf; - - if (ieee80211_is_data_qos(hdr->frame_control)) { - u8 *qc = ieee80211_get_qos_ctl(hdr); - reserved += NET_IP_ALIGN; - - if (*qc & IEEE80211_QOS_CONTROL_A_MSDU_PRESENT) - reserved += NET_IP_ALIGN; - } - - if (ieee80211_has_a4(hdr->frame_control)) - reserved += NET_IP_ALIGN; - - reserved = 32 + (reserved & NET_IP_ALIGN); - - skb = dev_alloc_skb(len + reserved); - if (likely(skb)) { - skb_reserve(skb, reserved); - memcpy(skb_put(skb, len), buf, len); - } - - return skb; -} - -/* - * If the frame alignment is right (or the kernel has - * CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS), and there - * is only a single MPDU in the USB frame, then we could - * submit to mac80211 the SKB directly. However, since - * there may be multiple packets in one SKB in stream - * mode, and we need to observe the proper ordering, - * this is non-trivial. - */ - -static void ar9170_handle_mpdu(struct ar9170 *ar, u8 *buf, int len) -{ - struct ar9170_rx_head *head; - struct ar9170_rx_macstatus *mac; - struct ar9170_rx_phystatus *phy = NULL; - struct ieee80211_rx_status status; - struct sk_buff *skb; - int mpdu_len; - - if (unlikely(!IS_STARTED(ar) || len < (sizeof(*mac)))) - return ; - - /* Received MPDU */ - mpdu_len = len - sizeof(*mac); - - mac = (void *)(buf + mpdu_len); - if (unlikely(mac->error & AR9170_RX_ERROR_FATAL)) { - /* this frame is too damaged and can't be used - drop it */ - - return ; - } - - switch (mac->status & AR9170_RX_STATUS_MPDU_MASK) { - case AR9170_RX_STATUS_MPDU_FIRST: - /* first mpdu packet has the plcp header */ - if (likely(mpdu_len >= sizeof(struct ar9170_rx_head))) { - head = (void *) buf; - memcpy(&ar->rx_mpdu.plcp, (void *) buf, - sizeof(struct ar9170_rx_head)); - - mpdu_len -= sizeof(struct ar9170_rx_head); - buf += sizeof(struct ar9170_rx_head); - ar->rx_mpdu.has_plcp = true; - } else { - if (ar9170_nag_limiter(ar)) - wiphy_err(ar->hw->wiphy, - "plcp info is clipped.\n"); - return ; - } - break; - - case AR9170_RX_STATUS_MPDU_LAST: - /* last mpdu has a extra tail with phy status information */ - - if (likely(mpdu_len >= sizeof(struct ar9170_rx_phystatus))) { - mpdu_len -= sizeof(struct ar9170_rx_phystatus); - phy = (void *)(buf + mpdu_len); - } else { - if (ar9170_nag_limiter(ar)) - wiphy_err(ar->hw->wiphy, - "frame tail is clipped.\n"); - return ; - } - - case AR9170_RX_STATUS_MPDU_MIDDLE: - /* middle mpdus are just data */ - if (unlikely(!ar->rx_mpdu.has_plcp)) { - if (!ar9170_nag_limiter(ar)) - return ; - - wiphy_err(ar->hw->wiphy, - "rx stream did not start with a first_mpdu frame tag.\n"); - - return ; - } - - head = &ar->rx_mpdu.plcp; - break; - - case AR9170_RX_STATUS_MPDU_SINGLE: - /* single mpdu - has plcp (head) and phy status (tail) */ - head = (void *) buf; - - mpdu_len -= sizeof(struct ar9170_rx_head); - mpdu_len -= sizeof(struct ar9170_rx_phystatus); - - buf += sizeof(struct ar9170_rx_head); - phy = (void *)(buf + mpdu_len); - break; - - default: - BUG_ON(1); - break; - } - - if (unlikely(mpdu_len < FCS_LEN)) - return ; - - memset(&status, 0, sizeof(status)); - if (unlikely(ar9170_rx_mac_status(ar, head, mac, &status))) - return ; - - if (phy) - ar9170_rx_phy_status(ar, phy, &status); - - skb = ar9170_rx_copy_data(buf, mpdu_len); - if (likely(skb)) { - memcpy(IEEE80211_SKB_RXCB(skb), &status, sizeof(status)); - ieee80211_rx_irqsafe(ar->hw, skb); - } -} - -void ar9170_rx(struct ar9170 *ar, struct sk_buff *skb) -{ - unsigned int i, tlen, resplen, wlen = 0, clen = 0; - u8 *tbuf, *respbuf; - - tbuf = skb->data; - tlen = skb->len; - - while (tlen >= 4) { - clen = tbuf[1] << 8 | tbuf[0]; - wlen = ALIGN(clen, 4); - - /* check if this is stream has a valid tag.*/ - if (tbuf[2] != 0 || tbuf[3] != 0x4e) { - /* - * TODO: handle the highly unlikely event that the - * corrupted stream has the TAG at the right position. - */ - - /* check if the frame can be repaired. */ - if (!ar->rx_failover_missing) { - /* this is no "short read". */ - if (ar9170_nag_limiter(ar)) { - wiphy_err(ar->hw->wiphy, - "missing tag!\n"); - goto err_telluser; - } else - goto err_silent; - } - - if (ar->rx_failover_missing > tlen) { - if (ar9170_nag_limiter(ar)) { - wiphy_err(ar->hw->wiphy, - "possible multi stream corruption!\n"); - goto err_telluser; - } else - goto err_silent; - } - - memcpy(skb_put(ar->rx_failover, tlen), tbuf, tlen); - ar->rx_failover_missing -= tlen; - - if (ar->rx_failover_missing <= 0) { - /* - * nested ar9170_rx call! - * termination is guranteed, even when the - * combined frame also have a element with - * a bad tag. - */ - - ar->rx_failover_missing = 0; - ar9170_rx(ar, ar->rx_failover); - - skb_reset_tail_pointer(ar->rx_failover); - skb_trim(ar->rx_failover, 0); - } - - return ; - } - - /* check if stream is clipped */ - if (wlen > tlen - 4) { - if (ar->rx_failover_missing) { - /* TODO: handle double stream corruption. */ - if (ar9170_nag_limiter(ar)) { - wiphy_err(ar->hw->wiphy, - "double rx stream corruption!\n"); - goto err_telluser; - } else - goto err_silent; - } - - /* - * save incomplete data set. - * the firmware will resend the missing bits when - * the rx - descriptor comes round again. - */ - - memcpy(skb_put(ar->rx_failover, tlen), tbuf, tlen); - ar->rx_failover_missing = clen - tlen; - return ; - } - resplen = clen; - respbuf = tbuf + 4; - tbuf += wlen + 4; - tlen -= wlen + 4; - - i = 0; - - /* weird thing, but this is the same in the original driver */ - while (resplen > 2 && i < 12 && - respbuf[0] == 0xff && respbuf[1] == 0xff) { - i += 2; - resplen -= 2; - respbuf += 2; - } - - if (resplen < 4) - continue; - - /* found the 6 * 0xffff marker? */ - if (i == 12) - ar9170_handle_command_response(ar, respbuf, resplen); - else - ar9170_handle_mpdu(ar, respbuf, clen); - } - - if (tlen) { - if (net_ratelimit()) - wiphy_err(ar->hw->wiphy, - "%d bytes of unprocessed data left in rx stream!\n", - tlen); - - goto err_telluser; - } - - return ; - -err_telluser: - wiphy_err(ar->hw->wiphy, - "damaged RX stream data [want:%d, data:%d, rx:%d, pending:%d ]\n", - clen, wlen, tlen, ar->rx_failover_missing); - - if (ar->rx_failover_missing) - print_hex_dump_bytes("rxbuf:", DUMP_PREFIX_OFFSET, - ar->rx_failover->data, - ar->rx_failover->len); - - print_hex_dump_bytes("stream:", DUMP_PREFIX_OFFSET, - skb->data, skb->len); - - wiphy_err(ar->hw->wiphy, - "If you see this message frequently, please check your hardware and cables.\n"); - -err_silent: - if (ar->rx_failover_missing) { - skb_reset_tail_pointer(ar->rx_failover); - skb_trim(ar->rx_failover, 0); - ar->rx_failover_missing = 0; - } -} - -#define AR9170_FILL_QUEUE(queue, ai_fs, cwmin, cwmax, _txop) \ -do { \ - queue.aifs = ai_fs; \ - queue.cw_min = cwmin; \ - queue.cw_max = cwmax; \ - queue.txop = _txop; \ -} while (0) - -static int ar9170_op_start(struct ieee80211_hw *hw) -{ - struct ar9170 *ar = hw->priv; - int err, i; - - mutex_lock(&ar->mutex); - - /* reinitialize queues statistics */ - memset(&ar->tx_stats, 0, sizeof(ar->tx_stats)); - for (i = 0; i < __AR9170_NUM_TXQ; i++) - ar->tx_stats[i].limit = AR9170_TXQ_DEPTH; - - /* reset QoS defaults */ - AR9170_FILL_QUEUE(ar->edcf[0], 3, 15, 1023, 0); /* BEST EFFORT*/ - AR9170_FILL_QUEUE(ar->edcf[1], 7, 15, 1023, 0); /* BACKGROUND */ - AR9170_FILL_QUEUE(ar->edcf[2], 2, 7, 15, 94); /* VIDEO */ - AR9170_FILL_QUEUE(ar->edcf[3], 2, 3, 7, 47); /* VOICE */ - AR9170_FILL_QUEUE(ar->edcf[4], 2, 3, 7, 0); /* SPECIAL */ - - /* set sane AMPDU defaults */ - ar->global_ampdu_density = 6; - ar->global_ampdu_factor = 3; - - ar->bad_hw_nagger = jiffies; - - err = ar->open(ar); - if (err) - goto out; - - err = ar9170_init_mac(ar); - if (err) - goto out; - - err = ar9170_set_qos(ar); - if (err) - goto out; - - err = ar9170_init_phy(ar, IEEE80211_BAND_2GHZ); - if (err) - goto out; - - err = ar9170_init_rf(ar); - if (err) - goto out; - - /* start DMA */ - err = ar9170_write_reg(ar, 0x1c3d30, 0x100); - if (err) - goto out; - - ar->state = AR9170_STARTED; - -out: - mutex_unlock(&ar->mutex); - return err; -} - -static void ar9170_op_stop(struct ieee80211_hw *hw) -{ - struct ar9170 *ar = hw->priv; - unsigned int i; - - if (IS_STARTED(ar)) - ar->state = AR9170_IDLE; - - cancel_delayed_work_sync(&ar->tx_janitor); -#ifdef CONFIG_AR9170_LEDS - cancel_delayed_work_sync(&ar->led_work); -#endif - cancel_work_sync(&ar->beacon_work); - - mutex_lock(&ar->mutex); - - if (IS_ACCEPTING_CMD(ar)) { - ar9170_set_leds_state(ar, 0); - - /* stop DMA */ - ar9170_write_reg(ar, 0x1c3d30, 0); - ar->stop(ar); - } - - for (i = 0; i < __AR9170_NUM_TXQ; i++) { - skb_queue_purge(&ar->tx_pending[i]); - skb_queue_purge(&ar->tx_status[i]); - } - - mutex_unlock(&ar->mutex); -} - -static int ar9170_tx_prepare(struct ar9170 *ar, struct sk_buff *skb) -{ - struct ieee80211_hdr *hdr; - struct ar9170_tx_control *txc; - struct ieee80211_tx_info *info; - struct ieee80211_tx_rate *txrate; - struct ar9170_tx_info *arinfo; - unsigned int queue = skb_get_queue_mapping(skb); - u16 keytype = 0; - u16 len, icv = 0; - - BUILD_BUG_ON(sizeof(*arinfo) > sizeof(info->rate_driver_data)); - - hdr = (void *)skb->data; - info = IEEE80211_SKB_CB(skb); - len = skb->len; - - txc = (void *)skb_push(skb, sizeof(*txc)); - - if (info->control.hw_key) { - icv = info->control.hw_key->icv_len; - - switch (info->control.hw_key->cipher) { - case WLAN_CIPHER_SUITE_WEP40: - case WLAN_CIPHER_SUITE_WEP104: - case WLAN_CIPHER_SUITE_TKIP: - keytype = AR9170_TX_MAC_ENCR_RC4; - break; - case WLAN_CIPHER_SUITE_CCMP: - keytype = AR9170_TX_MAC_ENCR_AES; - break; - default: - WARN_ON(1); - goto err_out; - } - } - - /* Length */ - txc->length = cpu_to_le16(len + icv + 4); - - txc->mac_control = cpu_to_le16(AR9170_TX_MAC_HW_DURATION | - AR9170_TX_MAC_BACKOFF); - txc->mac_control |= cpu_to_le16(ar9170_qos_hwmap[queue] << - AR9170_TX_MAC_QOS_SHIFT); - txc->mac_control |= cpu_to_le16(keytype); - txc->phy_control = cpu_to_le32(0); - - if (info->flags & IEEE80211_TX_CTL_NO_ACK) - txc->mac_control |= cpu_to_le16(AR9170_TX_MAC_NO_ACK); - - txrate = &info->control.rates[0]; - if (txrate->flags & IEEE80211_TX_RC_USE_CTS_PROTECT) - txc->mac_control |= cpu_to_le16(AR9170_TX_MAC_PROT_CTS); - else if (txrate->flags & IEEE80211_TX_RC_USE_RTS_CTS) - txc->mac_control |= cpu_to_le16(AR9170_TX_MAC_PROT_RTS); - - arinfo = (void *)info->rate_driver_data; - arinfo->timeout = jiffies + msecs_to_jiffies(AR9170_QUEUE_TIMEOUT); - - if (!(info->flags & IEEE80211_TX_CTL_NO_ACK) && - (is_valid_ether_addr(ieee80211_get_DA(hdr)))) { - /* - * WARNING: - * Putting the QoS queue bits into an unexplored territory is - * certainly not elegant. - * - * In my defense: This idea provides a reasonable way to - * smuggle valuable information to the tx_status callback. - * Also, the idea behind this bit-abuse came straight from - * the original driver code. - */ - - txc->phy_control |= - cpu_to_le32(queue << AR9170_TX_PHY_QOS_SHIFT); - - txc->mac_control |= cpu_to_le16(AR9170_TX_MAC_RATE_PROBE); - } - - return 0; - -err_out: - skb_pull(skb, sizeof(*txc)); - return -EINVAL; -} - -static void ar9170_tx_prepare_phy(struct ar9170 *ar, struct sk_buff *skb) -{ - struct ar9170_tx_control *txc; - struct ieee80211_tx_info *info; - struct ieee80211_rate *rate = NULL; - struct ieee80211_tx_rate *txrate; - u32 power, chains; - - txc = (void *) skb->data; - info = IEEE80211_SKB_CB(skb); - txrate = &info->control.rates[0]; - - if (txrate->flags & IEEE80211_TX_RC_GREEN_FIELD) - txc->phy_control |= cpu_to_le32(AR9170_TX_PHY_GREENFIELD); - - if (txrate->flags & IEEE80211_TX_RC_USE_SHORT_PREAMBLE) - txc->phy_control |= cpu_to_le32(AR9170_TX_PHY_SHORT_PREAMBLE); - - if (txrate->flags & IEEE80211_TX_RC_40_MHZ_WIDTH) - txc->phy_control |= cpu_to_le32(AR9170_TX_PHY_BW_40MHZ); - /* this works because 40 MHz is 2 and dup is 3 */ - if (txrate->flags & IEEE80211_TX_RC_DUP_DATA) - txc->phy_control |= cpu_to_le32(AR9170_TX_PHY_BW_40MHZ_DUP); - - if (txrate->flags & IEEE80211_TX_RC_SHORT_GI) - txc->phy_control |= cpu_to_le32(AR9170_TX_PHY_SHORT_GI); - - if (txrate->flags & IEEE80211_TX_RC_MCS) { - u32 r = txrate->idx; - u8 *txpower; - - /* heavy clip control */ - txc->phy_control |= cpu_to_le32((r & 0x7) << 7); - - r <<= AR9170_TX_PHY_MCS_SHIFT; - BUG_ON(r & ~AR9170_TX_PHY_MCS_MASK); - - txc->phy_control |= cpu_to_le32(r & AR9170_TX_PHY_MCS_MASK); - txc->phy_control |= cpu_to_le32(AR9170_TX_PHY_MOD_HT); - - if (txrate->flags & IEEE80211_TX_RC_40_MHZ_WIDTH) { - if (info->band == IEEE80211_BAND_5GHZ) - txpower = ar->power_5G_ht40; - else - txpower = ar->power_2G_ht40; - } else { - if (info->band == IEEE80211_BAND_5GHZ) - txpower = ar->power_5G_ht20; - else - txpower = ar->power_2G_ht20; - } - - power = txpower[(txrate->idx) & 7]; - } else { - u8 *txpower; - u32 mod; - u32 phyrate; - u8 idx = txrate->idx; - - if (info->band != IEEE80211_BAND_2GHZ) { - idx += 4; - txpower = ar->power_5G_leg; - mod = AR9170_TX_PHY_MOD_OFDM; - } else { - if (idx < 4) { - txpower = ar->power_2G_cck; - mod = AR9170_TX_PHY_MOD_CCK; - } else { - mod = AR9170_TX_PHY_MOD_OFDM; - txpower = ar->power_2G_ofdm; - } - } - - rate = &__ar9170_ratetable[idx]; - - phyrate = rate->hw_value & 0xF; - power = txpower[(rate->hw_value & 0x30) >> 4]; - phyrate <<= AR9170_TX_PHY_MCS_SHIFT; - - txc->phy_control |= cpu_to_le32(mod); - txc->phy_control |= cpu_to_le32(phyrate); - } - - power <<= AR9170_TX_PHY_TX_PWR_SHIFT; - power &= AR9170_TX_PHY_TX_PWR_MASK; - txc->phy_control |= cpu_to_le32(power); - - /* set TX chains */ - if (ar->eeprom.tx_mask == 1) { - chains = AR9170_TX_PHY_TXCHAIN_1; - } else { - chains = AR9170_TX_PHY_TXCHAIN_2; - - /* >= 36M legacy OFDM - use only one chain */ - if (rate && rate->bitrate >= 360) - chains = AR9170_TX_PHY_TXCHAIN_1; - } - txc->phy_control |= cpu_to_le32(chains << AR9170_TX_PHY_TXCHAIN_SHIFT); -} - -static void ar9170_tx(struct ar9170 *ar) -{ - struct sk_buff *skb; - unsigned long flags; - struct ieee80211_tx_info *info; - struct ar9170_tx_info *arinfo; - unsigned int i, frames, frames_failed, remaining_space; - int err; - bool schedule_garbagecollector = false; - - BUILD_BUG_ON(sizeof(*arinfo) > sizeof(info->rate_driver_data)); - - if (unlikely(!IS_STARTED(ar))) - return ; - - remaining_space = AR9170_TX_MAX_PENDING; - - for (i = 0; i < __AR9170_NUM_TXQ; i++) { - spin_lock_irqsave(&ar->tx_stats_lock, flags); - frames = min(ar->tx_stats[i].limit - ar->tx_stats[i].len, - skb_queue_len(&ar->tx_pending[i])); - - if (remaining_space < frames) { -#ifdef AR9170_QUEUE_DEBUG - wiphy_debug(ar->hw->wiphy, - "tx quota reached queue:%d, " - "remaining slots:%d, needed:%d\n", - i, remaining_space, frames); -#endif /* AR9170_QUEUE_DEBUG */ - frames = remaining_space; - } - - ar->tx_stats[i].len += frames; - ar->tx_stats[i].count += frames; - if (ar->tx_stats[i].len >= ar->tx_stats[i].limit) { -#ifdef AR9170_QUEUE_DEBUG - wiphy_debug(ar->hw->wiphy, "queue %d full\n", i); - wiphy_debug(ar->hw->wiphy, "stuck frames: ===>\n"); - ar9170_dump_txqueue(ar, &ar->tx_pending[i]); - ar9170_dump_txqueue(ar, &ar->tx_status[i]); -#endif /* AR9170_QUEUE_DEBUG */ - -#ifdef AR9170_QUEUE_STOP_DEBUG - wiphy_debug(ar->hw->wiphy, "stop queue %d\n", i); - __ar9170_dump_txstats(ar); -#endif /* AR9170_QUEUE_STOP_DEBUG */ - ieee80211_stop_queue(ar->hw, i); - } - - spin_unlock_irqrestore(&ar->tx_stats_lock, flags); - - if (!frames) - continue; - - frames_failed = 0; - while (frames) { - skb = skb_dequeue(&ar->tx_pending[i]); - if (unlikely(!skb)) { - frames_failed += frames; - frames = 0; - break; - } - - info = IEEE80211_SKB_CB(skb); - arinfo = (void *) info->rate_driver_data; - - /* TODO: cancel stuck frames */ - arinfo->timeout = jiffies + - msecs_to_jiffies(AR9170_TX_TIMEOUT); - -#ifdef AR9170_QUEUE_DEBUG - wiphy_debug(ar->hw->wiphy, "send frame q:%d =>\n", i); - ar9170_print_txheader(ar, skb); -#endif /* AR9170_QUEUE_DEBUG */ - - err = ar->tx(ar, skb); - if (unlikely(err)) { - frames_failed++; - dev_kfree_skb_any(skb); - } else { - remaining_space--; - schedule_garbagecollector = true; - } - - frames--; - } - -#ifdef AR9170_QUEUE_DEBUG - wiphy_debug(ar->hw->wiphy, - "ar9170_tx report for queue %d\n", i); - - wiphy_debug(ar->hw->wiphy, - "unprocessed pending frames left:\n"); - ar9170_dump_txqueue(ar, &ar->tx_pending[i]); -#endif /* AR9170_QUEUE_DEBUG */ - - if (unlikely(frames_failed)) { -#ifdef AR9170_QUEUE_DEBUG - wiphy_debug(ar->hw->wiphy, - "frames failed %d =>\n", frames_failed); -#endif /* AR9170_QUEUE_DEBUG */ - - spin_lock_irqsave(&ar->tx_stats_lock, flags); - ar->tx_stats[i].len -= frames_failed; - ar->tx_stats[i].count -= frames_failed; -#ifdef AR9170_QUEUE_STOP_DEBUG - wiphy_debug(ar->hw->wiphy, "wake queue %d\n", i); - __ar9170_dump_txstats(ar); -#endif /* AR9170_QUEUE_STOP_DEBUG */ - ieee80211_wake_queue(ar->hw, i); - spin_unlock_irqrestore(&ar->tx_stats_lock, flags); - } - } - - if (!schedule_garbagecollector) - return; - - ieee80211_queue_delayed_work(ar->hw, - &ar->tx_janitor, - msecs_to_jiffies(AR9170_JANITOR_DELAY)); -} - -void ar9170_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb) -{ - struct ar9170 *ar = hw->priv; - struct ieee80211_tx_info *info; - unsigned int queue; - - if (unlikely(!IS_STARTED(ar))) - goto err_free; - - if (unlikely(ar9170_tx_prepare(ar, skb))) - goto err_free; - - queue = skb_get_queue_mapping(skb); - info = IEEE80211_SKB_CB(skb); - ar9170_tx_prepare_phy(ar, skb); - skb_queue_tail(&ar->tx_pending[queue], skb); - - ar9170_tx(ar); - return; - -err_free: - dev_kfree_skb_any(skb); -} - -static int ar9170_op_add_interface(struct ieee80211_hw *hw, - struct ieee80211_vif *vif) -{ - struct ar9170 *ar = hw->priv; - struct ath_common *common = &ar->common; - int err = 0; - - mutex_lock(&ar->mutex); - - if (ar->vif) { - err = -EBUSY; - goto unlock; - } - - ar->vif = vif; - memcpy(common->macaddr, vif->addr, ETH_ALEN); - - if (modparam_nohwcrypt || (ar->vif->type != NL80211_IFTYPE_STATION)) { - ar->rx_software_decryption = true; - ar->disable_offload = true; - } - - ar->cur_filter = 0; - err = ar9170_update_frame_filter(ar, AR9170_MAC_REG_FTF_DEFAULTS); - if (err) - goto unlock; - - err = ar9170_set_operating_mode(ar); - -unlock: - mutex_unlock(&ar->mutex); - return err; -} - -static void ar9170_op_remove_interface(struct ieee80211_hw *hw, - struct ieee80211_vif *vif) -{ - struct ar9170 *ar = hw->priv; - - mutex_lock(&ar->mutex); - ar->vif = NULL; - ar9170_update_frame_filter(ar, 0); - ar9170_set_beacon_timers(ar); - dev_kfree_skb(ar->beacon); - ar->beacon = NULL; - ar->sniffer_enabled = false; - ar->rx_software_decryption = false; - ar9170_set_operating_mode(ar); - mutex_unlock(&ar->mutex); -} - -static int ar9170_op_config(struct ieee80211_hw *hw, u32 changed) -{ - struct ar9170 *ar = hw->priv; - int err = 0; - - mutex_lock(&ar->mutex); - - if (changed & IEEE80211_CONF_CHANGE_LISTEN_INTERVAL) { - /* TODO */ - err = 0; - } - - if (changed & IEEE80211_CONF_CHANGE_PS) { - /* TODO */ - err = 0; - } - - if (changed & IEEE80211_CONF_CHANGE_POWER) { - /* TODO */ - err = 0; - } - - if (changed & IEEE80211_CONF_CHANGE_RETRY_LIMITS) { - /* - * is it long_frame_max_tx_count or short_frame_max_tx_count? - */ - - err = ar9170_set_hwretry_limit(ar, - ar->hw->conf.long_frame_max_tx_count); - if (err) - goto out; - } - - if (changed & IEEE80211_CONF_CHANGE_CHANNEL) { - - /* adjust slot time for 5 GHz */ - err = ar9170_set_slot_time(ar); - if (err) - goto out; - - err = ar9170_set_dyn_sifs_ack(ar); - if (err) - goto out; - - err = ar9170_set_channel(ar, hw->conf.channel, - AR9170_RFI_NONE, - nl80211_to_ar9170(hw->conf.channel_type)); - if (err) - goto out; - } - -out: - mutex_unlock(&ar->mutex); - return err; -} - -static u64 ar9170_op_prepare_multicast(struct ieee80211_hw *hw, - struct netdev_hw_addr_list *mc_list) -{ - u64 mchash; - struct netdev_hw_addr *ha; - - /* always get broadcast frames */ - mchash = 1ULL << (0xff >> 2); - - netdev_hw_addr_list_for_each(ha, mc_list) - mchash |= 1ULL << (ha->addr[5] >> 2); - - return mchash; -} - -static void ar9170_op_configure_filter(struct ieee80211_hw *hw, - unsigned int changed_flags, - unsigned int *new_flags, - u64 multicast) -{ - struct ar9170 *ar = hw->priv; - - if (unlikely(!IS_ACCEPTING_CMD(ar))) - return ; - - mutex_lock(&ar->mutex); - - /* mask supported flags */ - *new_flags &= FIF_ALLMULTI | FIF_CONTROL | FIF_BCN_PRBRESP_PROMISC | - FIF_PROMISC_IN_BSS | FIF_FCSFAIL | FIF_PLCPFAIL; - ar->filter_state = *new_flags; - /* - * We can support more by setting the sniffer bit and - * then checking the error flags, later. - */ - - if (changed_flags & FIF_ALLMULTI && *new_flags & FIF_ALLMULTI) - multicast = ~0ULL; - - if (multicast != ar->cur_mc_hash) - ar9170_update_multicast(ar, multicast); - - if (changed_flags & FIF_CONTROL) { - u32 filter = AR9170_MAC_REG_FTF_PSPOLL | - AR9170_MAC_REG_FTF_RTS | - AR9170_MAC_REG_FTF_CTS | - AR9170_MAC_REG_FTF_ACK | - AR9170_MAC_REG_FTF_CFE | - AR9170_MAC_REG_FTF_CFE_ACK; - - if (*new_flags & FIF_CONTROL) - filter |= ar->cur_filter; - else - filter &= (~ar->cur_filter); - - ar9170_update_frame_filter(ar, filter); - } - - if (changed_flags & FIF_PROMISC_IN_BSS) { - ar->sniffer_enabled = ((*new_flags) & FIF_PROMISC_IN_BSS) != 0; - ar9170_set_operating_mode(ar); - } - - mutex_unlock(&ar->mutex); -} - - -static void ar9170_op_bss_info_changed(struct ieee80211_hw *hw, - struct ieee80211_vif *vif, - struct ieee80211_bss_conf *bss_conf, - u32 changed) -{ - struct ar9170 *ar = hw->priv; - struct ath_common *common = &ar->common; - int err = 0; - - mutex_lock(&ar->mutex); - - if (changed & BSS_CHANGED_BSSID) { - memcpy(common->curbssid, bss_conf->bssid, ETH_ALEN); - err = ar9170_set_operating_mode(ar); - if (err) - goto out; - } - - if (changed & BSS_CHANGED_BEACON_ENABLED) - ar->enable_beacon = bss_conf->enable_beacon; - - if (changed & BSS_CHANGED_BEACON) { - err = ar9170_update_beacon(ar); - if (err) - goto out; - } - - if (changed & (BSS_CHANGED_BEACON_ENABLED | BSS_CHANGED_BEACON | - BSS_CHANGED_BEACON_INT)) { - err = ar9170_set_beacon_timers(ar); - if (err) - goto out; - } - - if (changed & BSS_CHANGED_ASSOC) { -#ifndef CONFIG_AR9170_LEDS - /* enable assoc LED. */ - err = ar9170_set_leds_state(ar, bss_conf->assoc ? 2 : 0); -#endif /* CONFIG_AR9170_LEDS */ - } - - if (changed & BSS_CHANGED_HT) { - /* TODO */ - err = 0; - } - - if (changed & BSS_CHANGED_ERP_SLOT) { - err = ar9170_set_slot_time(ar); - if (err) - goto out; - } - - if (changed & BSS_CHANGED_BASIC_RATES) { - err = ar9170_set_basic_rates(ar); - if (err) - goto out; - } - -out: - mutex_unlock(&ar->mutex); -} - -static u64 ar9170_op_get_tsf(struct ieee80211_hw *hw) -{ - struct ar9170 *ar = hw->priv; - int err; - u64 tsf; -#define NR 3 - static const u32 addr[NR] = { AR9170_MAC_REG_TSF_H, - AR9170_MAC_REG_TSF_L, - AR9170_MAC_REG_TSF_H }; - u32 val[NR]; - int loops = 0; - - mutex_lock(&ar->mutex); - - while (loops++ < 10) { - err = ar9170_read_mreg(ar, NR, addr, val); - if (err || val[0] == val[2]) - break; - } - - mutex_unlock(&ar->mutex); - - if (WARN_ON(err)) - return 0; - tsf = val[0]; - tsf = (tsf << 32) | val[1]; - return tsf; -#undef NR -} - -static int ar9170_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, - struct ieee80211_vif *vif, struct ieee80211_sta *sta, - struct ieee80211_key_conf *key) -{ - struct ar9170 *ar = hw->priv; - int err = 0, i; - u8 ktype; - - if ((!ar->vif) || (ar->disable_offload)) - return -EOPNOTSUPP; - - switch (key->cipher) { - case WLAN_CIPHER_SUITE_WEP40: - ktype = AR9170_ENC_ALG_WEP64; - break; - case WLAN_CIPHER_SUITE_WEP104: - ktype = AR9170_ENC_ALG_WEP128; - break; - case WLAN_CIPHER_SUITE_TKIP: - ktype = AR9170_ENC_ALG_TKIP; - break; - case WLAN_CIPHER_SUITE_CCMP: - ktype = AR9170_ENC_ALG_AESCCMP; - break; - default: - return -EOPNOTSUPP; - } - - mutex_lock(&ar->mutex); - if (cmd == SET_KEY) { - if (unlikely(!IS_STARTED(ar))) { - err = -EOPNOTSUPP; - goto out; - } - - /* group keys need all-zeroes address */ - if (!(key->flags & IEEE80211_KEY_FLAG_PAIRWISE)) - sta = NULL; - - if (key->flags & IEEE80211_KEY_FLAG_PAIRWISE) { - for (i = 0; i < 64; i++) - if (!(ar->usedkeys & BIT(i))) - break; - if (i == 64) { - ar->rx_software_decryption = true; - ar9170_set_operating_mode(ar); - err = -ENOSPC; - goto out; - } - } else { - i = 64 + key->keyidx; - } - - key->hw_key_idx = i; - - err = ar9170_upload_key(ar, i, sta ? sta->addr : NULL, ktype, 0, - key->key, min_t(u8, 16, key->keylen)); - if (err) - goto out; - - if (key->cipher == WLAN_CIPHER_SUITE_TKIP) { - err = ar9170_upload_key(ar, i, sta ? sta->addr : NULL, - ktype, 1, key->key + 16, 16); - if (err) - goto out; - - /* - * hardware is not capable generating the MMIC - * for fragmented frames! - */ - key->flags |= IEEE80211_KEY_FLAG_GENERATE_MMIC; - } - - if (i < 64) - ar->usedkeys |= BIT(i); - - key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV; - } else { - if (unlikely(!IS_STARTED(ar))) { - /* The device is gone... together with the key ;-) */ - err = 0; - goto out; - } - - err = ar9170_disable_key(ar, key->hw_key_idx); - if (err) - goto out; - - if (key->hw_key_idx < 64) { - ar->usedkeys &= ~BIT(key->hw_key_idx); - } else { - err = ar9170_upload_key(ar, key->hw_key_idx, NULL, - AR9170_ENC_ALG_NONE, 0, - NULL, 0); - if (err) - goto out; - - if (key->cipher == WLAN_CIPHER_SUITE_TKIP) { - err = ar9170_upload_key(ar, key->hw_key_idx, - NULL, - AR9170_ENC_ALG_NONE, 1, - NULL, 0); - if (err) - goto out; - } - - } - } - - ar9170_regwrite_begin(ar); - ar9170_regwrite(AR9170_MAC_REG_ROLL_CALL_TBL_L, ar->usedkeys); - ar9170_regwrite(AR9170_MAC_REG_ROLL_CALL_TBL_H, ar->usedkeys >> 32); - ar9170_regwrite_finish(); - err = ar9170_regwrite_result(); - -out: - mutex_unlock(&ar->mutex); - - return err; -} - -static int ar9170_get_stats(struct ieee80211_hw *hw, - struct ieee80211_low_level_stats *stats) -{ - struct ar9170 *ar = hw->priv; - u32 val; - int err; - - mutex_lock(&ar->mutex); - err = ar9170_read_reg(ar, AR9170_MAC_REG_TX_RETRY, &val); - ar->stats.dot11ACKFailureCount += val; - - memcpy(stats, &ar->stats, sizeof(*stats)); - mutex_unlock(&ar->mutex); - - return 0; -} - -static int ar9170_get_survey(struct ieee80211_hw *hw, int idx, - struct survey_info *survey) -{ - struct ar9170 *ar = hw->priv; - struct ieee80211_conf *conf = &hw->conf; - - if (idx != 0) - return -ENOENT; - - /* TODO: update noise value, e.g. call ar9170_set_channel */ - - survey->channel = conf->channel; - survey->filled = SURVEY_INFO_NOISE_DBM; - survey->noise = ar->noise[0]; - - return 0; -} - -static int ar9170_conf_tx(struct ieee80211_hw *hw, u16 queue, - const struct ieee80211_tx_queue_params *param) -{ - struct ar9170 *ar = hw->priv; - int ret; - - mutex_lock(&ar->mutex); - if (queue < __AR9170_NUM_TXQ) { - memcpy(&ar->edcf[ar9170_qos_hwmap[queue]], - param, sizeof(*param)); - - ret = ar9170_set_qos(ar); - } else { - ret = -EINVAL; - } - - mutex_unlock(&ar->mutex); - return ret; -} - -static int ar9170_ampdu_action(struct ieee80211_hw *hw, - struct ieee80211_vif *vif, - enum ieee80211_ampdu_mlme_action action, - struct ieee80211_sta *sta, u16 tid, u16 *ssn, - u8 buf_size) -{ - switch (action) { - case IEEE80211_AMPDU_RX_START: - case IEEE80211_AMPDU_RX_STOP: - /* Handled by firmware */ - break; - - default: - return -EOPNOTSUPP; - } - - return 0; -} - -static const struct ieee80211_ops ar9170_ops = { - .start = ar9170_op_start, - .stop = ar9170_op_stop, - .tx = ar9170_op_tx, - .add_interface = ar9170_op_add_interface, - .remove_interface = ar9170_op_remove_interface, - .config = ar9170_op_config, - .prepare_multicast = ar9170_op_prepare_multicast, - .configure_filter = ar9170_op_configure_filter, - .conf_tx = ar9170_conf_tx, - .bss_info_changed = ar9170_op_bss_info_changed, - .get_tsf = ar9170_op_get_tsf, - .set_key = ar9170_set_key, - .get_stats = ar9170_get_stats, - .get_survey = ar9170_get_survey, - .ampdu_action = ar9170_ampdu_action, -}; - -void *ar9170_alloc(size_t priv_size) -{ - struct ieee80211_hw *hw; - struct ar9170 *ar; - struct sk_buff *skb; - int i; - - /* - * this buffer is used for rx stream reconstruction. - * Under heavy load this device (or the transport layer?) - * tends to split the streams into separate rx descriptors. - */ - - skb = __dev_alloc_skb(AR9170_RX_STREAM_MAX_SIZE, GFP_KERNEL); - if (!skb) - goto err_nomem; - - hw = ieee80211_alloc_hw(priv_size, &ar9170_ops); - if (!hw) - goto err_nomem; - - ar = hw->priv; - ar->hw = hw; - ar->rx_failover = skb; - - mutex_init(&ar->mutex); - spin_lock_init(&ar->cmdlock); - spin_lock_init(&ar->tx_stats_lock); - for (i = 0; i < __AR9170_NUM_TXQ; i++) { - skb_queue_head_init(&ar->tx_status[i]); - skb_queue_head_init(&ar->tx_pending[i]); - } - ar9170_rx_reset_rx_mpdu(ar); - INIT_WORK(&ar->beacon_work, ar9170_new_beacon); - INIT_DELAYED_WORK(&ar->tx_janitor, ar9170_tx_janitor); - - /* all hw supports 2.4 GHz, so set channel to 1 by default */ - ar->channel = &ar9170_2ghz_chantable[0]; - - /* first part of wiphy init */ - ar->hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) | - BIT(NL80211_IFTYPE_WDS) | - BIT(NL80211_IFTYPE_ADHOC); - ar->hw->flags |= IEEE80211_HW_RX_INCLUDES_FCS | - IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING | - IEEE80211_HW_SIGNAL_DBM; - - ar->hw->queues = __AR9170_NUM_TXQ; - ar->hw->extra_tx_headroom = 8; - - ar->hw->max_rates = 1; - ar->hw->max_rate_tries = 3; - - for (i = 0; i < ARRAY_SIZE(ar->noise); i++) - ar->noise[i] = -95; /* ATH_DEFAULT_NOISE_FLOOR */ - - return ar; - -err_nomem: - kfree_skb(skb); - return ERR_PTR(-ENOMEM); -} - -static int ar9170_read_eeprom(struct ar9170 *ar) -{ -#define RW 8 /* number of words to read at once */ -#define RB (sizeof(u32) * RW) - struct ath_regulatory *regulatory = &ar->common.regulatory; - u8 *eeprom = (void *)&ar->eeprom; - u8 *addr = ar->eeprom.mac_address; - __le32 offsets[RW]; - unsigned int rx_streams, tx_streams, tx_params = 0; - int i, j, err, bands = 0; - - BUILD_BUG_ON(sizeof(ar->eeprom) & 3); - - BUILD_BUG_ON(RB > AR9170_MAX_CMD_LEN - 4); -#ifndef __CHECKER__ - /* don't want to handle trailing remains */ - BUILD_BUG_ON(sizeof(ar->eeprom) % RB); -#endif - - for (i = 0; i < sizeof(ar->eeprom)/RB; i++) { - for (j = 0; j < RW; j++) - offsets[j] = cpu_to_le32(AR9170_EEPROM_START + - RB * i + 4 * j); - - err = ar->exec_cmd(ar, AR9170_CMD_RREG, - RB, (u8 *) &offsets, - RB, eeprom + RB * i); - if (err) - return err; - } - -#undef RW -#undef RB - - if (ar->eeprom.length == cpu_to_le16(0xFFFF)) - return -ENODATA; - - if (ar->eeprom.operating_flags & AR9170_OPFLAG_2GHZ) { - ar->hw->wiphy->bands[IEEE80211_BAND_2GHZ] = &ar9170_band_2GHz; - bands++; - } - if (ar->eeprom.operating_flags & AR9170_OPFLAG_5GHZ) { - ar->hw->wiphy->bands[IEEE80211_BAND_5GHZ] = &ar9170_band_5GHz; - bands++; - } - - rx_streams = hweight8(ar->eeprom.rx_mask); - tx_streams = hweight8(ar->eeprom.tx_mask); - - if (rx_streams != tx_streams) - tx_params = IEEE80211_HT_MCS_TX_RX_DIFF; - - if (tx_streams >= 1 && tx_streams <= IEEE80211_HT_MCS_TX_MAX_STREAMS) - tx_params = (tx_streams - 1) << - IEEE80211_HT_MCS_TX_MAX_STREAMS_SHIFT; - - ar9170_band_2GHz.ht_cap.mcs.tx_params |= tx_params; - ar9170_band_5GHz.ht_cap.mcs.tx_params |= tx_params; - - /* - * I measured this, a bandswitch takes roughly - * 135 ms and a frequency switch about 80. - * - * FIXME: measure these values again once EEPROM settings - * are used, that will influence them! - */ - if (bands == 2) - ar->hw->channel_change_time = 135 * 1000; - else - ar->hw->channel_change_time = 80 * 1000; - - regulatory->current_rd = le16_to_cpu(ar->eeprom.reg_domain[0]); - regulatory->current_rd_ext = le16_to_cpu(ar->eeprom.reg_domain[1]); - - /* second part of wiphy init */ - SET_IEEE80211_PERM_ADDR(ar->hw, addr); - - return bands ? 0 : -EINVAL; -} - -static int ar9170_reg_notifier(struct wiphy *wiphy, - struct regulatory_request *request) -{ - struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy); - struct ar9170 *ar = hw->priv; - - return ath_reg_notifier_apply(wiphy, request, &ar->common.regulatory); -} - -int ar9170_register(struct ar9170 *ar, struct device *pdev) -{ - struct ath_regulatory *regulatory = &ar->common.regulatory; - int err; - - /* try to read EEPROM, init MAC addr */ - err = ar9170_read_eeprom(ar); - if (err) - goto err_out; - - err = ath_regd_init(regulatory, ar->hw->wiphy, - ar9170_reg_notifier); - if (err) - goto err_out; - - err = ieee80211_register_hw(ar->hw); - if (err) - goto err_out; - - if (!ath_is_world_regd(regulatory)) - regulatory_hint(ar->hw->wiphy, regulatory->alpha2); - - err = ar9170_init_leds(ar); - if (err) - goto err_unreg; - -#ifdef CONFIG_AR9170_LEDS - err = ar9170_register_leds(ar); - if (err) - goto err_unreg; -#endif /* CONFIG_AR9170_LEDS */ - - dev_info(pdev, "Atheros AR9170 is registered as '%s'\n", - wiphy_name(ar->hw->wiphy)); - - ar->registered = true; - return 0; - -err_unreg: - ieee80211_unregister_hw(ar->hw); - -err_out: - return err; -} - -void ar9170_unregister(struct ar9170 *ar) -{ - if (ar->registered) { -#ifdef CONFIG_AR9170_LEDS - ar9170_unregister_leds(ar); -#endif /* CONFIG_AR9170_LEDS */ - - ieee80211_unregister_hw(ar->hw); - } - - kfree_skb(ar->rx_failover); - mutex_destroy(&ar->mutex); -} diff --git a/drivers/net/wireless/ath/ar9170/phy.c b/drivers/net/wireless/ath/ar9170/phy.c deleted file mode 100644 index 0dbfcf7..0000000 --- a/drivers/net/wireless/ath/ar9170/phy.c +++ /dev/null @@ -1,1719 +0,0 @@ -/* - * Atheros AR9170 driver - * - * PHY and RF code - * - * Copyright 2008, Johannes Berg - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; see the file COPYING. If not, see - * http://www.gnu.org/licenses/. - * - * This file incorporates work covered by the following copyright and - * permission notice: - * Copyright (c) 2007-2008 Atheros Communications, Inc. - * - * 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 "ar9170.h" -#include "cmd.h" - -static int ar9170_init_power_cal(struct ar9170 *ar) -{ - ar9170_regwrite_begin(ar); - - ar9170_regwrite(0x1bc000 + 0x993c, 0x7f); - ar9170_regwrite(0x1bc000 + 0x9934, 0x3f3f3f3f); - ar9170_regwrite(0x1bc000 + 0x9938, 0x3f3f3f3f); - ar9170_regwrite(0x1bc000 + 0xa234, 0x3f3f3f3f); - ar9170_regwrite(0x1bc000 + 0xa238, 0x3f3f3f3f); - ar9170_regwrite(0x1bc000 + 0xa38c, 0x3f3f3f3f); - ar9170_regwrite(0x1bc000 + 0xa390, 0x3f3f3f3f); - ar9170_regwrite(0x1bc000 + 0xa3cc, 0x3f3f3f3f); - ar9170_regwrite(0x1bc000 + 0xa3d0, 0x3f3f3f3f); - ar9170_regwrite(0x1bc000 + 0xa3d4, 0x3f3f3f3f); - - ar9170_regwrite_finish(); - return ar9170_regwrite_result(); -} - -struct ar9170_phy_init { - u32 reg, _5ghz_20, _5ghz_40, _2ghz_40, _2ghz_20; -}; - -static struct ar9170_phy_init ar5416_phy_init[] = { - { 0x1c5800, 0x00000007, 0x00000007, 0x00000007, 0x00000007, }, - { 0x1c5804, 0x00000300, 0x000003c4, 0x000003c4, 0x00000300, }, - { 0x1c5808, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, - { 0x1c580c, 0xad848e19, 0xad848e19, 0xad848e19, 0xad848e19, }, - { 0x1c5810, 0x7d14e000, 0x7d14e000, 0x7d14e000, 0x7d14e000, }, - { 0x1c5814, 0x9c0a9f6b, 0x9c0a9f6b, 0x9c0a9f6b, 0x9c0a9f6b, }, - { 0x1c5818, 0x00000090, 0x00000090, 0x00000090, 0x00000090, }, - { 0x1c581c, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, - { 0x1c5820, 0x02020200, 0x02020200, 0x02020200, 0x02020200, }, - { 0x1c5824, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e, }, - { 0x1c5828, 0x0a020001, 0x0a020001, 0x0a020001, 0x0a020001, }, - { 0x1c582c, 0x0000a000, 0x0000a000, 0x0000a000, 0x0000a000, }, - { 0x1c5830, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, - { 0x1c5834, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e, }, - { 0x1c5838, 0x00000007, 0x00000007, 0x00000007, 0x00000007, }, - { 0x1c583c, 0x00200400, 0x00200400, 0x00200400, 0x00200400, }, - { 0x1c5840, 0x206a002e, 0x206a002e, 0x206a002e, 0x206a002e, }, - { 0x1c5844, 0x1372161e, 0x13721c1e, 0x13721c24, 0x137216a4, }, - { 0x1c5848, 0x001a6a65, 0x001a6a65, 0x00197a68, 0x00197a68, }, - { 0x1c584c, 0x1284233c, 0x1284233c, 0x1284233c, 0x1284233c, }, - { 0x1c5850, 0x6c48b4e4, 0x6c48b4e4, 0x6c48b0e4, 0x6c48b0e4, }, - { 0x1c5854, 0x00000859, 0x00000859, 0x00000859, 0x00000859, }, - { 0x1c5858, 0x7ec80d2e, 0x7ec80d2e, 0x7ec80d2e, 0x7ec80d2e, }, - { 0x1c585c, 0x31395c5e, 0x31395c5e, 0x31395c5e, 0x31395c5e, }, - { 0x1c5860, 0x0004dd10, 0x0004dd10, 0x0004dd20, 0x0004dd20, }, - { 0x1c5868, 0x409a4190, 0x409a4190, 0x409a4190, 0x409a4190, }, - { 0x1c586c, 0x050cb081, 0x050cb081, 0x050cb081, 0x050cb081, }, - { 0x1c5900, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, - { 0x1c5904, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, - { 0x1c5908, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, - { 0x1c590c, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, - { 0x1c5914, 0x000007d0, 0x000007d0, 0x00000898, 0x00000898, }, - { 0x1c5918, 0x00000118, 0x00000230, 0x00000268, 0x00000134, }, - { 0x1c591c, 0x10000fff, 0x10000fff, 0x10000fff, 0x10000fff, }, - { 0x1c5920, 0x0510081c, 0x0510081c, 0x0510001c, 0x0510001c, }, - { 0x1c5924, 0xd0058a15, 0xd0058a15, 0xd0058a15, 0xd0058a15, }, - { 0x1c5928, 0x00000001, 0x00000001, 0x00000001, 0x00000001, }, - { 0x1c592c, 0x00000004, 0x00000004, 0x00000004, 0x00000004, }, - { 0x1c5934, 0x3f3f3f3f, 0x3f3f3f3f, 0x3f3f3f3f, 0x3f3f3f3f, }, - { 0x1c5938, 0x3f3f3f3f, 0x3f3f3f3f, 0x3f3f3f3f, 0x3f3f3f3f, }, - { 0x1c593c, 0x0000007f, 0x0000007f, 0x0000007f, 0x0000007f, }, - { 0x1c5944, 0xdfb81020, 0xdfb81020, 0xdfb81020, 0xdfb81020, }, - { 0x1c5948, 0x9280b212, 0x9280b212, 0x9280b212, 0x9280b212, }, - { 0x1c594c, 0x00020028, 0x00020028, 0x00020028, 0x00020028, }, - { 0x1c5954, 0x5d50e188, 0x5d50e188, 0x5d50e188, 0x5d50e188, }, - { 0x1c5958, 0x00081fff, 0x00081fff, 0x00081fff, 0x00081fff, }, - { 0x1c5960, 0x00009b40, 0x00009b40, 0x00009b40, 0x00009b40, }, - { 0x1c5964, 0x00001120, 0x00001120, 0x00001120, 0x00001120, }, - { 0x1c5970, 0x190fb515, 0x190fb515, 0x190fb515, 0x190fb515, }, - { 0x1c5974, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, - { 0x1c5978, 0x00000001, 0x00000001, 0x00000001, 0x00000001, }, - { 0x1c597c, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, - { 0x1c5980, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, - { 0x1c5984, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, - { 0x1c5988, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, - { 0x1c598c, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, - { 0x1c5990, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, - { 0x1c5994, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, - { 0x1c5998, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, - { 0x1c599c, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, - { 0x1c59a0, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, - { 0x1c59a4, 0x00000007, 0x00000007, 0x00000007, 0x00000007, }, - { 0x1c59a8, 0x001fff00, 0x001fff00, 0x001fff00, 0x001fff00, }, - { 0x1c59ac, 0x006f00c4, 0x006f00c4, 0x006f00c4, 0x006f00c4, }, - { 0x1c59b0, 0x03051000, 0x03051000, 0x03051000, 0x03051000, }, - { 0x1c59b4, 0x00000820, 0x00000820, 0x00000820, 0x00000820, }, - { 0x1c59c0, 0x038919be, 0x038919be, 0x038919be, 0x038919be, }, - { 0x1c59c4, 0x06336f77, 0x06336f77, 0x06336f77, 0x06336f77, }, - { 0x1c59c8, 0x60f6532c, 0x60f6532c, 0x60f6532c, 0x60f6532c, }, - { 0x1c59cc, 0x08f186c8, 0x08f186c8, 0x08f186c8, 0x08f186c8, }, - { 0x1c59d0, 0x00046384, 0x00046384, 0x00046384, 0x00046384, }, - { 0x1c59d4, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, - { 0x1c59d8, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, - { 0x1c59dc, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, - { 0x1c59e0, 0x00000200, 0x00000200, 0x00000200, 0x00000200, }, - { 0x1c59e4, 0x64646464, 0x64646464, 0x64646464, 0x64646464, }, - { 0x1c59e8, 0x3c787878, 0x3c787878, 0x3c787878, 0x3c787878, }, - { 0x1c59ec, 0x000000aa, 0x000000aa, 0x000000aa, 0x000000aa, }, - { 0x1c59f0, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, - { 0x1c59fc, 0x00001042, 0x00001042, 0x00001042, 0x00001042, }, - { 0x1c5a00, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, - { 0x1c5a04, 0x00000040, 0x00000040, 0x00000040, 0x00000040, }, - { 0x1c5a08, 0x00000080, 0x00000080, 0x00000080, 0x00000080, }, - { 0x1c5a0c, 0x000001a1, 0x000001a1, 0x00000141, 0x00000141, }, - { 0x1c5a10, 0x000001e1, 0x000001e1, 0x00000181, 0x00000181, }, - { 0x1c5a14, 0x00000021, 0x00000021, 0x000001c1, 0x000001c1, }, - { 0x1c5a18, 0x00000061, 0x00000061, 0x00000001, 0x00000001, }, - { 0x1c5a1c, 0x00000168, 0x00000168, 0x00000041, 0x00000041, }, - { 0x1c5a20, 0x000001a8, 0x000001a8, 0x000001a8, 0x000001a8, }, - { 0x1c5a24, 0x000001e8, 0x000001e8, 0x000001e8, 0x000001e8, }, - { 0x1c5a28, 0x00000028, 0x00000028, 0x00000028, 0x00000028, }, - { 0x1c5a2c, 0x00000068, 0x00000068, 0x00000068, 0x00000068, }, - { 0x1c5a30, 0x00000189, 0x00000189, 0x000000a8, 0x000000a8, }, - { 0x1c5a34, 0x000001c9, 0x000001c9, 0x00000169, 0x00000169, }, - { 0x1c5a38, 0x00000009, 0x00000009, 0x000001a9, 0x000001a9, }, - { 0x1c5a3c, 0x00000049, 0x00000049, 0x000001e9, 0x000001e9, }, - { 0x1c5a40, 0x00000089, 0x00000089, 0x00000029, 0x00000029, }, - { 0x1c5a44, 0x00000170, 0x00000170, 0x00000069, 0x00000069, }, - { 0x1c5a48, 0x000001b0, 0x000001b0, 0x00000190, 0x00000190, }, - { 0x1c5a4c, 0x000001f0, 0x000001f0, 0x000001d0, 0x000001d0, }, - { 0x1c5a50, 0x00000030, 0x00000030, 0x00000010, 0x00000010, }, - { 0x1c5a54, 0x00000070, 0x00000070, 0x00000050, 0x00000050, }, - { 0x1c5a58, 0x00000191, 0x00000191, 0x00000090, 0x00000090, }, - { 0x1c5a5c, 0x000001d1, 0x000001d1, 0x00000151, 0x00000151, }, - { 0x1c5a60, 0x00000011, 0x00000011, 0x00000191, 0x00000191, }, - { 0x1c5a64, 0x00000051, 0x00000051, 0x000001d1, 0x000001d1, }, - { 0x1c5a68, 0x00000091, 0x00000091, 0x00000011, 0x00000011, }, - { 0x1c5a6c, 0x000001b8, 0x000001b8, 0x00000051, 0x00000051, }, - { 0x1c5a70, 0x000001f8, 0x000001f8, 0x00000198, 0x00000198, }, - { 0x1c5a74, 0x00000038, 0x00000038, 0x000001d8, 0x000001d8, }, - { 0x1c5a78, 0x00000078, 0x00000078, 0x00000018, 0x00000018, }, - { 0x1c5a7c, 0x00000199, 0x00000199, 0x00000058, 0x00000058, }, - { 0x1c5a80, 0x000001d9, 0x000001d9, 0x00000098, 0x00000098, }, - { 0x1c5a84, 0x00000019, 0x00000019, 0x00000159, 0x00000159, }, - { 0x1c5a88, 0x00000059, 0x00000059, 0x00000199, 0x00000199, }, - { 0x1c5a8c, 0x00000099, 0x00000099, 0x000001d9, 0x000001d9, }, - { 0x1c5a90, 0x000000d9, 0x000000d9, 0x00000019, 0x00000019, }, - { 0x1c5a94, 0x000000f9, 0x000000f9, 0x00000059, 0x00000059, }, - { 0x1c5a98, 0x000000f9, 0x000000f9, 0x00000099, 0x00000099, }, - { 0x1c5a9c, 0x000000f9, 0x000000f9, 0x000000d9, 0x000000d9, }, - { 0x1c5aa0, 0x000000f9, 0x000000f9, 0x000000f9, 0x000000f9, }, - { 0x1c5aa4, 0x000000f9, 0x000000f9, 0x000000f9, 0x000000f9, }, - { 0x1c5aa8, 0x000000f9, 0x000000f9, 0x000000f9, 0x000000f9, }, - { 0x1c5aac, 0x000000f9, 0x000000f9, 0x000000f9, 0x000000f9, }, - { 0x1c5ab0, 0x000000f9, 0x000000f9, 0x000000f9, 0x000000f9, }, - { 0x1c5ab4, 0x000000f9, 0x000000f9, 0x000000f9, 0x000000f9, }, - { 0x1c5ab8, 0x000000f9, 0x000000f9, 0x000000f9, 0x000000f9, }, - { 0x1c5abc, 0x000000f9, 0x000000f9, 0x000000f9, 0x000000f9, }, - { 0x1c5ac0, 0x000000f9, 0x000000f9, 0x000000f9, 0x000000f9, }, - { 0x1c5ac4, 0x000000f9, 0x000000f9, 0x000000f9, 0x000000f9, }, - { 0x1c5ac8, 0x000000f9, 0x000000f9, 0x000000f9, 0x000000f9, }, - { 0x1c5acc, 0x000000f9, 0x000000f9, 0x000000f9, 0x000000f9, }, - { 0x1c5ad0, 0x000000f9, 0x000000f9, 0x000000f9, 0x000000f9, }, - { 0x1c5ad4, 0x000000f9, 0x000000f9, 0x000000f9, 0x000000f9, }, - { 0x1c5ad8, 0x000000f9, 0x000000f9, 0x000000f9, 0x000000f9, }, - { 0x1c5adc, 0x000000f9, 0x000000f9, 0x000000f9, 0x000000f9, }, - { 0x1c5ae0, 0x000000f9, 0x000000f9, 0x000000f9, 0x000000f9, }, - { 0x1c5ae4, 0x000000f9, 0x000000f9, 0x000000f9, 0x000000f9, }, - { 0x1c5ae8, 0x000000f9, 0x000000f9, 0x000000f9, 0x000000f9, }, - { 0x1c5aec, 0x000000f9, 0x000000f9, 0x000000f9, 0x000000f9, }, - { 0x1c5af0, 0x000000f9, 0x000000f9, 0x000000f9, 0x000000f9, }, - { 0x1c5af4, 0x000000f9, 0x000000f9, 0x000000f9, 0x000000f9, }, - { 0x1c5af8, 0x000000f9, 0x000000f9, 0x000000f9, 0x000000f9, }, - { 0x1c5afc, 0x000000f9, 0x000000f9, 0x000000f9, 0x000000f9, }, - { 0x1c5b00, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, - { 0x1c5b04, 0x00000001, 0x00000001, 0x00000001, 0x00000001, }, - { 0x1c5b08, 0x00000002, 0x00000002, 0x00000002, 0x00000002, }, - { 0x1c5b0c, 0x00000003, 0x00000003, 0x00000003, 0x00000003, }, - { 0x1c5b10, 0x00000004, 0x00000004, 0x00000004, 0x00000004, }, - { 0x1c5b14, 0x00000005, 0x00000005, 0x00000005, 0x00000005, }, - { 0x1c5b18, 0x00000008, 0x00000008, 0x00000008, 0x00000008, }, - { 0x1c5b1c, 0x00000009, 0x00000009, 0x00000009, 0x00000009, }, - { 0x1c5b20, 0x0000000a, 0x0000000a, 0x0000000a, 0x0000000a, }, - { 0x1c5b24, 0x0000000b, 0x0000000b, 0x0000000b, 0x0000000b, }, - { 0x1c5b28, 0x0000000c, 0x0000000c, 0x0000000c, 0x0000000c, }, - { 0x1c5b2c, 0x0000000d, 0x0000000d, 0x0000000d, 0x0000000d, }, - { 0x1c5b30, 0x00000010, 0x00000010, 0x00000010, 0x00000010, }, - { 0x1c5b34, 0x00000011, 0x00000011, 0x00000011, 0x00000011, }, - { 0x1c5b38, 0x00000012, 0x00000012, 0x00000012, 0x00000012, }, - { 0x1c5b3c, 0x00000013, 0x00000013, 0x00000013, 0x00000013, }, - { 0x1c5b40, 0x00000014, 0x00000014, 0x00000014, 0x00000014, }, - { 0x1c5b44, 0x00000015, 0x00000015, 0x00000015, 0x00000015, }, - { 0x1c5b48, 0x00000018, 0x00000018, 0x00000018, 0x00000018, }, - { 0x1c5b4c, 0x00000019, 0x00000019, 0x00000019, 0x00000019, }, - { 0x1c5b50, 0x0000001a, 0x0000001a, 0x0000001a, 0x0000001a, }, - { 0x1c5b54, 0x0000001b, 0x0000001b, 0x0000001b, 0x0000001b, }, - { 0x1c5b58, 0x0000001c, 0x0000001c, 0x0000001c, 0x0000001c, }, - { 0x1c5b5c, 0x0000001d, 0x0000001d, 0x0000001d, 0x0000001d, }, - { 0x1c5b60, 0x00000020, 0x00000020, 0x00000020, 0x00000020, }, - { 0x1c5b64, 0x00000021, 0x00000021, 0x00000021, 0x00000021, }, - { 0x1c5b68, 0x00000022, 0x00000022, 0x00000022, 0x00000022, }, - { 0x1c5b6c, 0x00000023, 0x00000023, 0x00000023, 0x00000023, }, - { 0x1c5b70, 0x00000024, 0x00000024, 0x00000024, 0x00000024, }, - { 0x1c5b74, 0x00000025, 0x00000025, 0x00000025, 0x00000025, }, - { 0x1c5b78, 0x00000028, 0x00000028, 0x00000028, 0x00000028, }, - { 0x1c5b7c, 0x00000029, 0x00000029, 0x00000029, 0x00000029, }, - { 0x1c5b80, 0x0000002a, 0x0000002a, 0x0000002a, 0x0000002a, }, - { 0x1c5b84, 0x0000002b, 0x0000002b, 0x0000002b, 0x0000002b, }, - { 0x1c5b88, 0x0000002c, 0x0000002c, 0x0000002c, 0x0000002c, }, - { 0x1c5b8c, 0x0000002d, 0x0000002d, 0x0000002d, 0x0000002d, }, - { 0x1c5b90, 0x00000030, 0x00000030, 0x00000030, 0x00000030, }, - { 0x1c5b94, 0x00000031, 0x00000031, 0x00000031, 0x00000031, }, - { 0x1c5b98, 0x00000032, 0x00000032, 0x00000032, 0x00000032, }, - { 0x1c5b9c, 0x00000033, 0x00000033, 0x00000033, 0x00000033, }, - { 0x1c5ba0, 0x00000034, 0x00000034, 0x00000034, 0x00000034, }, - { 0x1c5ba4, 0x00000035, 0x00000035, 0x00000035, 0x00000035, }, - { 0x1c5ba8, 0x00000035, 0x00000035, 0x00000035, 0x00000035, }, - { 0x1c5bac, 0x00000035, 0x00000035, 0x00000035, 0x00000035, }, - { 0x1c5bb0, 0x00000035, 0x00000035, 0x00000035, 0x00000035, }, - { 0x1c5bb4, 0x00000035, 0x00000035, 0x00000035, 0x00000035, }, - { 0x1c5bb8, 0x00000035, 0x00000035, 0x00000035, 0x00000035, }, - { 0x1c5bbc, 0x00000035, 0x00000035, 0x00000035, 0x00000035, }, - { 0x1c5bc0, 0x00000035, 0x00000035, 0x00000035, 0x00000035, }, - { 0x1c5bc4, 0x00000035, 0x00000035, 0x00000035, 0x00000035, }, - { 0x1c5bc8, 0x00000035, 0x00000035, 0x00000035, 0x00000035, }, - { 0x1c5bcc, 0x00000035, 0x00000035, 0x00000035, 0x00000035, }, - { 0x1c5bd0, 0x00000035, 0x00000035, 0x00000035, 0x00000035, }, - { 0x1c5bd4, 0x00000035, 0x00000035, 0x00000035, 0x00000035, }, - { 0x1c5bd8, 0x00000035, 0x00000035, 0x00000035, 0x00000035, }, - { 0x1c5bdc, 0x00000035, 0x00000035, 0x00000035, 0x00000035, }, - { 0x1c5be0, 0x00000035, 0x00000035, 0x00000035, 0x00000035, }, - { 0x1c5be4, 0x00000035, 0x00000035, 0x00000035, 0x00000035, }, - { 0x1c5be8, 0x00000035, 0x00000035, 0x00000035, 0x00000035, }, - { 0x1c5bec, 0x00000035, 0x00000035, 0x00000035, 0x00000035, }, - { 0x1c5bf0, 0x00000035, 0x00000035, 0x00000035, 0x00000035, }, - { 0x1c5bf4, 0x00000035, 0x00000035, 0x00000035, 0x00000035, }, - { 0x1c5bf8, 0x00000010, 0x00000010, 0x00000010, 0x00000010, }, - { 0x1c5bfc, 0x0000001a, 0x0000001a, 0x0000001a, 0x0000001a, }, - { 0x1c5c00, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, - { 0x1c5c0c, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, - { 0x1c5c10, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, - { 0x1c5c14, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, - { 0x1c5c18, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, - { 0x1c5c1c, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, - { 0x1c5c20, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, - { 0x1c5c24, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, - { 0x1c5c28, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, - { 0x1c5c2c, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, - { 0x1c5c30, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, - { 0x1c5c34, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, - { 0x1c5c38, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, - { 0x1c5c3c, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, - { 0x1c5cf0, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, - { 0x1c5cf4, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, - { 0x1c5cf8, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, - { 0x1c5cfc, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, - { 0x1c6200, 0x00000008, 0x00000008, 0x0000000e, 0x0000000e, }, - { 0x1c6204, 0x00000440, 0x00000440, 0x00000440, 0x00000440, }, - { 0x1c6208, 0xd6be4788, 0xd6be4788, 0xd03e4788, 0xd03e4788, }, - { 0x1c620c, 0x012e8160, 0x012e8160, 0x012a8160, 0x012a8160, }, - { 0x1c6210, 0x40806333, 0x40806333, 0x40806333, 0x40806333, }, - { 0x1c6214, 0x00106c10, 0x00106c10, 0x00106c10, 0x00106c10, }, - { 0x1c6218, 0x009c4060, 0x009c4060, 0x009c4060, 0x009c4060, }, - { 0x1c621c, 0x1883800a, 0x1883800a, 0x1883800a, 0x1883800a, }, - { 0x1c6220, 0x018830c6, 0x018830c6, 0x018830c6, 0x018830c6, }, - { 0x1c6224, 0x00000400, 0x00000400, 0x00000400, 0x00000400, }, - { 0x1c6228, 0x000009b5, 0x000009b5, 0x000009b5, 0x000009b5, }, - { 0x1c622c, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, - { 0x1c6230, 0x00000108, 0x00000210, 0x00000210, 0x00000108, }, - { 0x1c6234, 0x3f3f3f3f, 0x3f3f3f3f, 0x3f3f3f3f, 0x3f3f3f3f, }, - { 0x1c6238, 0x3f3f3f3f, 0x3f3f3f3f, 0x3f3f3f3f, 0x3f3f3f3f, }, - { 0x1c623c, 0x13c889af, 0x13c889af, 0x13c889af, 0x13c889af, }, - { 0x1c6240, 0x38490a20, 0x38490a20, 0x38490a20, 0x38490a20, }, - { 0x1c6244, 0x00007bb6, 0x00007bb6, 0x00007bb6, 0x00007bb6, }, - { 0x1c6248, 0x0fff3ffc, 0x0fff3ffc, 0x0fff3ffc, 0x0fff3ffc, }, - { 0x1c624c, 0x00000001, 0x00000001, 0x00000001, 0x00000001, }, - { 0x1c6250, 0x0000a000, 0x0000a000, 0x0000a000, 0x0000a000, }, - { 0x1c6254, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, - { 0x1c6258, 0x0cc75380, 0x0cc75380, 0x0cc75380, 0x0cc75380, }, - { 0x1c625c, 0x0f0f0f01, 0x0f0f0f01, 0x0f0f0f01, 0x0f0f0f01, }, - { 0x1c6260, 0xdfa91f01, 0xdfa91f01, 0xdfa91f01, 0xdfa91f01, }, - { 0x1c6264, 0x00418a11, 0x00418a11, 0x00418a11, 0x00418a11, }, - { 0x1c6268, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, - { 0x1c626c, 0x09249126, 0x09249126, 0x09249126, 0x09249126, }, - { 0x1c6274, 0x0a1a9caa, 0x0a1a9caa, 0x0a1a7caa, 0x0a1a7caa, }, - { 0x1c6278, 0x1ce739ce, 0x1ce739ce, 0x1ce739ce, 0x1ce739ce, }, - { 0x1c627c, 0x051701ce, 0x051701ce, 0x051701ce, 0x051701ce, }, - { 0x1c6300, 0x18010000, 0x18010000, 0x18010000, 0x18010000, }, - { 0x1c6304, 0x30032602, 0x30032602, 0x2e032402, 0x2e032402, }, - { 0x1c6308, 0x48073e06, 0x48073e06, 0x4a0a3c06, 0x4a0a3c06, }, - { 0x1c630c, 0x560b4c0a, 0x560b4c0a, 0x621a540b, 0x621a540b, }, - { 0x1c6310, 0x641a600f, 0x641a600f, 0x764f6c1b, 0x764f6c1b, }, - { 0x1c6314, 0x7a4f6e1b, 0x7a4f6e1b, 0x845b7a5a, 0x845b7a5a, }, - { 0x1c6318, 0x8c5b7e5a, 0x8c5b7e5a, 0x950f8ccf, 0x950f8ccf, }, - { 0x1c631c, 0x9d0f96cf, 0x9d0f96cf, 0xa5cf9b4f, 0xa5cf9b4f, }, - { 0x1c6320, 0xb51fa69f, 0xb51fa69f, 0xbddfaf1f, 0xbddfaf1f, }, - { 0x1c6324, 0xcb3fbd07, 0xcb3fbcbf, 0xd1ffc93f, 0xd1ffc93f, }, - { 0x1c6328, 0x0000d7bf, 0x0000d7bf, 0x00000000, 0x00000000, }, - { 0x1c632c, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, - { 0x1c6330, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, - { 0x1c6334, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, - { 0x1c6338, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, - { 0x1c633c, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, - { 0x1c6340, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, - { 0x1c6344, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, - { 0x1c6348, 0x3fffffff, 0x3fffffff, 0x3fffffff, 0x3fffffff, }, - { 0x1c634c, 0x3fffffff, 0x3fffffff, 0x3fffffff, 0x3fffffff, }, - { 0x1c6350, 0x3fffffff, 0x3fffffff, 0x3fffffff, 0x3fffffff, }, - { 0x1c6354, 0x0003ffff, 0x0003ffff, 0x0003ffff, 0x0003ffff, }, - { 0x1c6358, 0x79a8aa1f, 0x79a8aa1f, 0x79a8aa1f, 0x79a8aa1f, }, - { 0x1c6388, 0x08000000, 0x08000000, 0x08000000, 0x08000000, }, - { 0x1c638c, 0x3f3f3f3f, 0x3f3f3f3f, 0x3f3f3f3f, 0x3f3f3f3f, }, - { 0x1c6390, 0x3f3f3f3f, 0x3f3f3f3f, 0x3f3f3f3f, 0x3f3f3f3f, }, - { 0x1c6394, 0x1ce739ce, 0x1ce739ce, 0x1ce739ce, 0x1ce739ce, }, - { 0x1c6398, 0x000001ce, 0x000001ce, 0x000001ce, 0x000001ce, }, - { 0x1c639c, 0x00000007, 0x00000007, 0x00000007, 0x00000007, }, - { 0x1c63a0, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, - { 0x1c63a4, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, - { 0x1c63a8, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, - { 0x1c63ac, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, - { 0x1c63b0, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, - { 0x1c63b4, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, - { 0x1c63b8, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, - { 0x1c63bc, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, - { 0x1c63c0, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, - { 0x1c63c4, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, - { 0x1c63c8, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, - { 0x1c63cc, 0x3f3f3f3f, 0x3f3f3f3f, 0x3f3f3f3f, 0x3f3f3f3f, }, - { 0x1c63d0, 0x3f3f3f3f, 0x3f3f3f3f, 0x3f3f3f3f, 0x3f3f3f3f, }, - { 0x1c63d4, 0x3f3f3f3f, 0x3f3f3f3f, 0x3f3f3f3f, 0x3f3f3f3f, }, - { 0x1c63d8, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, - { 0x1c63dc, 0x1ce739ce, 0x1ce739ce, 0x1ce739ce, 0x1ce739ce, }, - { 0x1c63e0, 0x000000c0, 0x000000c0, 0x000000c0, 0x000000c0, }, - { 0x1c6848, 0x00180a65, 0x00180a65, 0x00180a68, 0x00180a68, }, - { 0x1c6920, 0x0510001c, 0x0510001c, 0x0510001c, 0x0510001c, }, - { 0x1c6960, 0x00009b40, 0x00009b40, 0x00009b40, 0x00009b40, }, - { 0x1c720c, 0x012e8160, 0x012e8160, 0x012a8160, 0x012a8160, }, - { 0x1c726c, 0x09249126, 0x09249126, 0x09249126, 0x09249126, }, - { 0x1c7848, 0x00180a65, 0x00180a65, 0x00180a68, 0x00180a68, }, - { 0x1c7920, 0x0510001c, 0x0510001c, 0x0510001c, 0x0510001c, }, - { 0x1c7960, 0x00009b40, 0x00009b40, 0x00009b40, 0x00009b40, }, - { 0x1c820c, 0x012e8160, 0x012e8160, 0x012a8160, 0x012a8160, }, - { 0x1c826c, 0x09249126, 0x09249126, 0x09249126, 0x09249126, }, -/* { 0x1c8864, 0x0001ce00, 0x0001ce00, 0x0001ce00, 0x0001ce00, }, */ - { 0x1c8864, 0x0001c600, 0x0001c600, 0x0001c600, 0x0001c600, }, - { 0x1c895c, 0x004b6a8e, 0x004b6a8e, 0x004b6a8e, 0x004b6a8e, }, - { 0x1c8968, 0x000003ce, 0x000003ce, 0x000003ce, 0x000003ce, }, - { 0x1c89bc, 0x00181400, 0x00181400, 0x00181400, 0x00181400, }, - { 0x1c9270, 0x00820820, 0x00820820, 0x00820820, 0x00820820, }, - { 0x1c935c, 0x066c420f, 0x066c420f, 0x066c420f, 0x066c420f, }, - { 0x1c9360, 0x0f282207, 0x0f282207, 0x0f282207, 0x0f282207, }, - { 0x1c9364, 0x17601685, 0x17601685, 0x17601685, 0x17601685, }, - { 0x1c9368, 0x1f801104, 0x1f801104, 0x1f801104, 0x1f801104, }, - { 0x1c936c, 0x37a00c03, 0x37a00c03, 0x37a00c03, 0x37a00c03, }, - { 0x1c9370, 0x3fc40883, 0x3fc40883, 0x3fc40883, 0x3fc40883, }, - { 0x1c9374, 0x57c00803, 0x57c00803, 0x57c00803, 0x57c00803, }, - { 0x1c9378, 0x5fd80682, 0x5fd80682, 0x5fd80682, 0x5fd80682, }, - { 0x1c937c, 0x7fe00482, 0x7fe00482, 0x7fe00482, 0x7fe00482, }, - { 0x1c9380, 0x7f3c7bba, 0x7f3c7bba, 0x7f3c7bba, 0x7f3c7bba, }, - { 0x1c9384, 0xf3307ff0, 0xf3307ff0, 0xf3307ff0, 0xf3307ff0, } -}; - -/* - * look up a certain register in ar5416_phy_init[] and return the init. value - * for the band and bandwidth given. Return 0 if register address not found. - */ -static u32 ar9170_get_default_phy_reg_val(u32 reg, bool is_2ghz, bool is_40mhz) -{ - unsigned int i; - for (i = 0; i < ARRAY_SIZE(ar5416_phy_init); i++) { - if (ar5416_phy_init[i].reg != reg) - continue; - - if (is_2ghz) { - if (is_40mhz) - return ar5416_phy_init[i]._2ghz_40; - else - return ar5416_phy_init[i]._2ghz_20; - } else { - if (is_40mhz) - return ar5416_phy_init[i]._5ghz_40; - else - return ar5416_phy_init[i]._5ghz_20; - } - } - return 0; -} - -/* - * initialize some phy regs from eeprom values in modal_header[] - * acc. to band and bandwith - */ -static int ar9170_init_phy_from_eeprom(struct ar9170 *ar, - bool is_2ghz, bool is_40mhz) -{ - static const u8 xpd2pd[16] = { - 0x2, 0x2, 0x2, 0x1, 0x2, 0x2, 0x6, 0x2, - 0x2, 0x3, 0x7, 0x2, 0xB, 0x2, 0x2, 0x2 - }; - u32 defval, newval; - /* pointer to the modal_header acc. to band */ - struct ar9170_eeprom_modal *m = &ar->eeprom.modal_header[is_2ghz]; - - ar9170_regwrite_begin(ar); - - /* ant common control (index 0) */ - newval = le32_to_cpu(m->antCtrlCommon); - ar9170_regwrite(0x1c5964, newval); - - /* ant control chain 0 (index 1) */ - newval = le32_to_cpu(m->antCtrlChain[0]); - ar9170_regwrite(0x1c5960, newval); - - /* ant control chain 2 (index 2) */ - newval = le32_to_cpu(m->antCtrlChain[1]); - ar9170_regwrite(0x1c7960, newval); - - /* SwSettle (index 3) */ - if (!is_40mhz) { - defval = ar9170_get_default_phy_reg_val(0x1c5844, - is_2ghz, is_40mhz); - newval = (defval & ~0x3f80) | - ((m->switchSettling & 0x7f) << 7); - ar9170_regwrite(0x1c5844, newval); - } - - /* adcDesired, pdaDesired (index 4) */ - defval = ar9170_get_default_phy_reg_val(0x1c5850, is_2ghz, is_40mhz); - newval = (defval & ~0xffff) | ((u8)m->pgaDesiredSize << 8) | - ((u8)m->adcDesiredSize); - ar9170_regwrite(0x1c5850, newval); - - /* TxEndToXpaOff, TxFrameToXpaOn (index 5) */ - defval = ar9170_get_default_phy_reg_val(0x1c5834, is_2ghz, is_40mhz); - newval = (m->txEndToXpaOff << 24) | (m->txEndToXpaOff << 16) | - (m->txFrameToXpaOn << 8) | m->txFrameToXpaOn; - ar9170_regwrite(0x1c5834, newval); - - /* TxEndToRxOn (index 6) */ - defval = ar9170_get_default_phy_reg_val(0x1c5828, is_2ghz, is_40mhz); - newval = (defval & ~0xff0000) | (m->txEndToRxOn << 16); - ar9170_regwrite(0x1c5828, newval); - - /* thresh62 (index 7) */ - defval = ar9170_get_default_phy_reg_val(0x1c8864, is_2ghz, is_40mhz); - newval = (defval & ~0x7f000) | (m->thresh62 << 12); - ar9170_regwrite(0x1c8864, newval); - - /* tx/rx attenuation chain 0 (index 8) */ - defval = ar9170_get_default_phy_reg_val(0x1c5848, is_2ghz, is_40mhz); - newval = (defval & ~0x3f000) | ((m->txRxAttenCh[0] & 0x3f) << 12); - ar9170_regwrite(0x1c5848, newval); - - /* tx/rx attenuation chain 2 (index 9) */ - defval = ar9170_get_default_phy_reg_val(0x1c7848, is_2ghz, is_40mhz); - newval = (defval & ~0x3f000) | ((m->txRxAttenCh[1] & 0x3f) << 12); - ar9170_regwrite(0x1c7848, newval); - - /* tx/rx margin chain 0 (index 10) */ - defval = ar9170_get_default_phy_reg_val(0x1c620c, is_2ghz, is_40mhz); - newval = (defval & ~0xfc0000) | ((m->rxTxMarginCh[0] & 0x3f) << 18); - /* bsw margin chain 0 for 5GHz only */ - if (!is_2ghz) - newval = (newval & ~0x3c00) | ((m->bswMargin[0] & 0xf) << 10); - ar9170_regwrite(0x1c620c, newval); - - /* tx/rx margin chain 2 (index 11) */ - defval = ar9170_get_default_phy_reg_val(0x1c820c, is_2ghz, is_40mhz); - newval = (defval & ~0xfc0000) | ((m->rxTxMarginCh[1] & 0x3f) << 18); - ar9170_regwrite(0x1c820c, newval); - - /* iqCall, iqCallq chain 0 (index 12) */ - defval = ar9170_get_default_phy_reg_val(0x1c5920, is_2ghz, is_40mhz); - newval = (defval & ~0x7ff) | (((u8)m->iqCalICh[0] & 0x3f) << 5) | - ((u8)m->iqCalQCh[0] & 0x1f); - ar9170_regwrite(0x1c5920, newval); - - /* iqCall, iqCallq chain 2 (index 13) */ - defval = ar9170_get_default_phy_reg_val(0x1c7920, is_2ghz, is_40mhz); - newval = (defval & ~0x7ff) | (((u8)m->iqCalICh[1] & 0x3f) << 5) | - ((u8)m->iqCalQCh[1] & 0x1f); - ar9170_regwrite(0x1c7920, newval); - - /* xpd gain mask (index 14) */ - defval = ar9170_get_default_phy_reg_val(0x1c6258, is_2ghz, is_40mhz); - newval = (defval & ~0xf0000) | (xpd2pd[m->xpdGain & 0xf] << 16); - ar9170_regwrite(0x1c6258, newval); - ar9170_regwrite_finish(); - - return ar9170_regwrite_result(); -} - -int ar9170_init_phy(struct ar9170 *ar, enum ieee80211_band band) -{ - int i, err; - u32 val; - bool is_2ghz = band == IEEE80211_BAND_2GHZ; - bool is_40mhz = conf_is_ht40(&ar->hw->conf); - - ar9170_regwrite_begin(ar); - - for (i = 0; i < ARRAY_SIZE(ar5416_phy_init); i++) { - if (is_40mhz) { - if (is_2ghz) - val = ar5416_phy_init[i]._2ghz_40; - else - val = ar5416_phy_init[i]._5ghz_40; - } else { - if (is_2ghz) - val = ar5416_phy_init[i]._2ghz_20; - else - val = ar5416_phy_init[i]._5ghz_20; - } - - ar9170_regwrite(ar5416_phy_init[i].reg, val); - } - - ar9170_regwrite_finish(); - err = ar9170_regwrite_result(); - if (err) - return err; - - err = ar9170_init_phy_from_eeprom(ar, is_2ghz, is_40mhz); - if (err) - return err; - - err = ar9170_init_power_cal(ar); - if (err) - return err; - - /* XXX: remove magic! */ - if (is_2ghz) - err = ar9170_write_reg(ar, 0x1d4014, 0x5163); - else - err = ar9170_write_reg(ar, 0x1d4014, 0x5143); - - return err; -} - -struct ar9170_rf_init { - u32 reg, _5ghz, _2ghz; -}; - -static struct ar9170_rf_init ar9170_rf_init[] = { - /* bank 0 */ - { 0x1c58b0, 0x1e5795e5, 0x1e5795e5}, - { 0x1c58e0, 0x02008020, 0x02008020}, - /* bank 1 */ - { 0x1c58b0, 0x02108421, 0x02108421}, - { 0x1c58ec, 0x00000008, 0x00000008}, - /* bank 2 */ - { 0x1c58b0, 0x0e73ff17, 0x0e73ff17}, - { 0x1c58e0, 0x00000420, 0x00000420}, - /* bank 3 */ - { 0x1c58f0, 0x01400018, 0x01c00018}, - /* bank 4 */ - { 0x1c58b0, 0x000001a1, 0x000001a1}, - { 0x1c58e8, 0x00000001, 0x00000001}, - /* bank 5 */ - { 0x1c58b0, 0x00000013, 0x00000013}, - { 0x1c58e4, 0x00000002, 0x00000002}, - /* bank 6 */ - { 0x1c58b0, 0x00000000, 0x00000000}, - { 0x1c58b0, 0x00000000, 0x00000000}, - { 0x1c58b0, 0x00000000, 0x00000000}, - { 0x1c58b0, 0x00000000, 0x00000000}, - { 0x1c58b0, 0x00000000, 0x00000000}, - { 0x1c58b0, 0x00004000, 0x00004000}, - { 0x1c58b0, 0x00006c00, 0x00006c00}, - { 0x1c58b0, 0x00002c00, 0x00002c00}, - { 0x1c58b0, 0x00004800, 0x00004800}, - { 0x1c58b0, 0x00004000, 0x00004000}, - { 0x1c58b0, 0x00006000, 0x00006000}, - { 0x1c58b0, 0x00001000, 0x00001000}, - { 0x1c58b0, 0x00004000, 0x00004000}, - { 0x1c58b0, 0x00007c00, 0x00007c00}, - { 0x1c58b0, 0x00007c00, 0x00007c00}, - { 0x1c58b0, 0x00007c00, 0x00007c00}, - { 0x1c58b0, 0x00007c00, 0x00007c00}, - { 0x1c58b0, 0x00007c00, 0x00007c00}, - { 0x1c58b0, 0x00087c00, 0x00087c00}, - { 0x1c58b0, 0x00007c00, 0x00007c00}, - { 0x1c58b0, 0x00005400, 0x00005400}, - { 0x1c58b0, 0x00000c00, 0x00000c00}, - { 0x1c58b0, 0x00001800, 0x00001800}, - { 0x1c58b0, 0x00007c00, 0x00007c00}, - { 0x1c58b0, 0x00006c00, 0x00006c00}, - { 0x1c58b0, 0x00006c00, 0x00006c00}, - { 0x1c58b0, 0x00007c00, 0x00007c00}, - { 0x1c58b0, 0x00002c00, 0x00002c00}, - { 0x1c58b0, 0x00003c00, 0x00003c00}, - { 0x1c58b0, 0x00003800, 0x00003800}, - { 0x1c58b0, 0x00001c00, 0x00001c00}, - { 0x1c58b0, 0x00000800, 0x00000800}, - { 0x1c58b0, 0x00000408, 0x00000408}, - { 0x1c58b0, 0x00004c15, 0x00004c15}, - { 0x1c58b0, 0x00004188, 0x00004188}, - { 0x1c58b0, 0x0000201e, 0x0000201e}, - { 0x1c58b0, 0x00010408, 0x00010408}, - { 0x1c58b0, 0x00000801, 0x00000801}, - { 0x1c58b0, 0x00000c08, 0x00000c08}, - { 0x1c58b0, 0x0000181e, 0x0000181e}, - { 0x1c58b0, 0x00001016, 0x00001016}, - { 0x1c58b0, 0x00002800, 0x00002800}, - { 0x1c58b0, 0x00004010, 0x00004010}, - { 0x1c58b0, 0x0000081c, 0x0000081c}, - { 0x1c58b0, 0x00000115, 0x00000115}, - { 0x1c58b0, 0x00000015, 0x00000015}, - { 0x1c58b0, 0x00000066, 0x00000066}, - { 0x1c58b0, 0x0000001c, 0x0000001c}, - { 0x1c58b0, 0x00000000, 0x00000000}, - { 0x1c58b0, 0x00000004, 0x00000004}, - { 0x1c58b0, 0x00000015, 0x00000015}, - { 0x1c58b0, 0x0000001f, 0x0000001f}, - { 0x1c58e0, 0x00000000, 0x00000400}, - /* bank 7 */ - { 0x1c58b0, 0x000000a0, 0x000000a0}, - { 0x1c58b0, 0x00000000, 0x00000000}, - { 0x1c58b0, 0x00000040, 0x00000040}, - { 0x1c58f0, 0x0000001c, 0x0000001c}, -}; - -static int ar9170_init_rf_banks_0_7(struct ar9170 *ar, bool band5ghz) -{ - int err, i; - - ar9170_regwrite_begin(ar); - - for (i = 0; i < ARRAY_SIZE(ar9170_rf_init); i++) - ar9170_regwrite(ar9170_rf_init[i].reg, - band5ghz ? ar9170_rf_init[i]._5ghz - : ar9170_rf_init[i]._2ghz); - - ar9170_regwrite_finish(); - err = ar9170_regwrite_result(); - if (err) - wiphy_err(ar->hw->wiphy, "rf init failed\n"); - return err; -} - -static int ar9170_init_rf_bank4_pwr(struct ar9170 *ar, bool band5ghz, - u32 freq, enum ar9170_bw bw) -{ - int err; - u32 d0, d1, td0, td1, fd0, fd1; - u8 chansel; - u8 refsel0 = 1, refsel1 = 0; - u8 lf_synth = 0; - - switch (bw) { - case AR9170_BW_40_ABOVE: - freq += 10; - break; - case AR9170_BW_40_BELOW: - freq -= 10; - break; - case AR9170_BW_20: - break; - case __AR9170_NUM_BW: - BUG(); - } - - if (band5ghz) { - if (freq % 10) { - chansel = (freq - 4800) / 5; - } else { - chansel = ((freq - 4800) / 10) * 2; - refsel0 = 0; - refsel1 = 1; - } - chansel = byte_rev_table[chansel]; - } else { - if (freq == 2484) { - chansel = 10 + (freq - 2274) / 5; - lf_synth = 1; - } else - chansel = 16 + (freq - 2272) / 5; - chansel *= 4; - chansel = byte_rev_table[chansel]; - } - - d1 = chansel; - d0 = 0x21 | - refsel0 << 3 | - refsel1 << 2 | - lf_synth << 1; - td0 = d0 & 0x1f; - td1 = d1 & 0x1f; - fd0 = td1 << 5 | td0; - - td0 = (d0 >> 5) & 0x7; - td1 = (d1 >> 5) & 0x7; - fd1 = td1 << 5 | td0; - - ar9170_regwrite_begin(ar); - - ar9170_regwrite(0x1c58b0, fd0); - ar9170_regwrite(0x1c58e8, fd1); - - ar9170_regwrite_finish(); - err = ar9170_regwrite_result(); - if (err) - return err; - - msleep(10); - - return 0; -} - -struct ar9170_phy_freq_params { - u8 coeff_exp; - u16 coeff_man; - u8 coeff_exp_shgi; - u16 coeff_man_shgi; -}; - -struct ar9170_phy_freq_entry { - u16 freq; - struct ar9170_phy_freq_params params[__AR9170_NUM_BW]; -}; - -/* NB: must be in sync with channel tables in main! */ -static const struct ar9170_phy_freq_entry ar9170_phy_freq_params[] = { -/* - * freq, - * 20MHz, - * 40MHz (below), - * 40Mhz (above), - */ - { 2412, { - { 3, 21737, 3, 19563, }, - { 3, 21827, 3, 19644, }, - { 3, 21647, 3, 19482, }, - } }, - { 2417, { - { 3, 21692, 3, 19523, }, - { 3, 21782, 3, 19604, }, - { 3, 21602, 3, 19442, }, - } }, - { 2422, { - { 3, 21647, 3, 19482, }, - { 3, 21737, 3, 19563, }, - { 3, 21558, 3, 19402, }, - } }, - { 2427, { - { 3, 21602, 3, 19442, }, - { 3, 21692, 3, 19523, }, - { 3, 21514, 3, 19362, }, - } }, - { 2432, { - { 3, 21558, 3, 19402, }, - { 3, 21647, 3, 19482, }, - { 3, 21470, 3, 19323, }, - } }, - { 2437, { - { 3, 21514, 3, 19362, }, - { 3, 21602, 3, 19442, }, - { 3, 21426, 3, 19283, }, - } }, - { 2442, { - { 3, 21470, 3, 19323, }, - { 3, 21558, 3, 19402, }, - { 3, 21382, 3, 19244, }, - } }, - { 2447, { - { 3, 21426, 3, 19283, }, - { 3, 21514, 3, 19362, }, - { 3, 21339, 3, 19205, }, - } }, - { 2452, { - { 3, 21382, 3, 19244, }, - { 3, 21470, 3, 19323, }, - { 3, 21295, 3, 19166, }, - } }, - { 2457, { - { 3, 21339, 3, 19205, }, - { 3, 21426, 3, 19283, }, - { 3, 21252, 3, 19127, }, - } }, - { 2462, { - { 3, 21295, 3, 19166, }, - { 3, 21382, 3, 19244, }, - { 3, 21209, 3, 19088, }, - } }, - { 2467, { - { 3, 21252, 3, 19127, }, - { 3, 21339, 3, 19205, }, - { 3, 21166, 3, 19050, }, - } }, - { 2472, { - { 3, 21209, 3, 19088, }, - { 3, 21295, 3, 19166, }, - { 3, 21124, 3, 19011, }, - } }, - { 2484, { - { 3, 21107, 3, 18996, }, - { 3, 21192, 3, 19073, }, - { 3, 21022, 3, 18920, }, - } }, - { 4920, { - { 4, 21313, 4, 19181, }, - { 4, 21356, 4, 19220, }, - { 4, 21269, 4, 19142, }, - } }, - { 4940, { - { 4, 21226, 4, 19104, }, - { 4, 21269, 4, 19142, }, - { 4, 21183, 4, 19065, }, - } }, - { 4960, { - { 4, 21141, 4, 19027, }, - { 4, 21183, 4, 19065, }, - { 4, 21098, 4, 18988, }, - } }, - { 4980, { - { 4, 21056, 4, 18950, }, - { 4, 21098, 4, 18988, }, - { 4, 21014, 4, 18912, }, - } }, - { 5040, { - { 4, 20805, 4, 18725, }, - { 4, 20846, 4, 18762, }, - { 4, 20764, 4, 18687, }, - } }, - { 5060, { - { 4, 20723, 4, 18651, }, - { 4, 20764, 4, 18687, }, - { 4, 20682, 4, 18614, }, - } }, - { 5080, { - { 4, 20641, 4, 18577, }, - { 4, 20682, 4, 18614, }, - { 4, 20601, 4, 18541, }, - } }, - { 5180, { - { 4, 20243, 4, 18219, }, - { 4, 20282, 4, 18254, }, - { 4, 20204, 4, 18183, }, - } }, - { 5200, { - { 4, 20165, 4, 18148, }, - { 4, 20204, 4, 18183, }, - { 4, 20126, 4, 18114, }, - } }, - { 5220, { - { 4, 20088, 4, 18079, }, - { 4, 20126, 4, 18114, }, - { 4, 20049, 4, 18044, }, - } }, - { 5240, { - { 4, 20011, 4, 18010, }, - { 4, 20049, 4, 18044, }, - { 4, 19973, 4, 17976, }, - } }, - { 5260, { - { 4, 19935, 4, 17941, }, - { 4, 19973, 4, 17976, }, - { 4, 19897, 4, 17907, }, - } }, - { 5280, { - { 4, 19859, 4, 17873, }, - { 4, 19897, 4, 17907, }, - { 4, 19822, 4, 17840, }, - } }, - { 5300, { - { 4, 19784, 4, 17806, }, - { 4, 19822, 4, 17840, }, - { 4, 19747, 4, 17772, }, - } }, - { 5320, { - { 4, 19710, 4, 17739, }, - { 4, 19747, 4, 17772, }, - { 4, 19673, 4, 17706, }, - } }, - { 5500, { - { 4, 19065, 4, 17159, }, - { 4, 19100, 4, 17190, }, - { 4, 19030, 4, 17127, }, - } }, - { 5520, { - { 4, 18996, 4, 17096, }, - { 4, 19030, 4, 17127, }, - { 4, 18962, 4, 17065, }, - } }, - { 5540, { - { 4, 18927, 4, 17035, }, - { 4, 18962, 4, 17065, }, - { 4, 18893, 4, 17004, }, - } }, - { 5560, { - { 4, 18859, 4, 16973, }, - { 4, 18893, 4, 17004, }, - { 4, 18825, 4, 16943, }, - } }, - { 5580, { - { 4, 18792, 4, 16913, }, - { 4, 18825, 4, 16943, }, - { 4, 18758, 4, 16882, }, - } }, - { 5600, { - { 4, 18725, 4, 16852, }, - { 4, 18758, 4, 16882, }, - { 4, 18691, 4, 16822, }, - } }, - { 5620, { - { 4, 18658, 4, 16792, }, - { 4, 18691, 4, 16822, }, - { 4, 18625, 4, 16762, }, - } }, - { 5640, { - { 4, 18592, 4, 16733, }, - { 4, 18625, 4, 16762, }, - { 4, 18559, 4, 16703, }, - } }, - { 5660, { - { 4, 18526, 4, 16673, }, - { 4, 18559, 4, 16703, }, - { 4, 18493, 4, 16644, }, - } }, - { 5680, { - { 4, 18461, 4, 16615, }, - { 4, 18493, 4, 16644, }, - { 4, 18428, 4, 16586, }, - } }, - { 5700, { - { 4, 18396, 4, 16556, }, - { 4, 18428, 4, 16586, }, - { 4, 18364, 4, 16527, }, - } }, - { 5745, { - { 4, 18252, 4, 16427, }, - { 4, 18284, 4, 16455, }, - { 4, 18220, 4, 16398, }, - } }, - { 5765, { - { 4, 18189, 5, 32740, }, - { 4, 18220, 4, 16398, }, - { 4, 18157, 5, 32683, }, - } }, - { 5785, { - { 4, 18126, 5, 32626, }, - { 4, 18157, 5, 32683, }, - { 4, 18094, 5, 32570, }, - } }, - { 5805, { - { 4, 18063, 5, 32514, }, - { 4, 18094, 5, 32570, }, - { 4, 18032, 5, 32458, }, - } }, - { 5825, { - { 4, 18001, 5, 32402, }, - { 4, 18032, 5, 32458, }, - { 4, 17970, 5, 32347, }, - } }, - { 5170, { - { 4, 20282, 4, 18254, }, - { 4, 20321, 4, 18289, }, - { 4, 20243, 4, 18219, }, - } }, - { 5190, { - { 4, 20204, 4, 18183, }, - { 4, 20243, 4, 18219, }, - { 4, 20165, 4, 18148, }, - } }, - { 5210, { - { 4, 20126, 4, 18114, }, - { 4, 20165, 4, 18148, }, - { 4, 20088, 4, 18079, }, - } }, - { 5230, { - { 4, 20049, 4, 18044, }, - { 4, 20088, 4, 18079, }, - { 4, 20011, 4, 18010, }, - } }, -}; - -static const struct ar9170_phy_freq_params * -ar9170_get_hw_dyn_params(struct ieee80211_channel *channel, - enum ar9170_bw bw) -{ - unsigned int chanidx = 0; - u16 freq = 2412; - - if (channel) { - chanidx = channel->hw_value; - freq = channel->center_freq; - } - - BUG_ON(chanidx >= ARRAY_SIZE(ar9170_phy_freq_params)); - - BUILD_BUG_ON(__AR9170_NUM_BW != 3); - - WARN_ON(ar9170_phy_freq_params[chanidx].freq != freq); - - return &ar9170_phy_freq_params[chanidx].params[bw]; -} - - -int ar9170_init_rf(struct ar9170 *ar) -{ - const struct ar9170_phy_freq_params *freqpar; - __le32 cmd[7]; - int err; - - err = ar9170_init_rf_banks_0_7(ar, false); - if (err) - return err; - - err = ar9170_init_rf_bank4_pwr(ar, false, 2412, AR9170_BW_20); - if (err) - return err; - - freqpar = ar9170_get_hw_dyn_params(NULL, AR9170_BW_20); - - cmd[0] = cpu_to_le32(2412 * 1000); - cmd[1] = cpu_to_le32(0); - cmd[2] = cpu_to_le32(1); - cmd[3] = cpu_to_le32(freqpar->coeff_exp); - cmd[4] = cpu_to_le32(freqpar->coeff_man); - cmd[5] = cpu_to_le32(freqpar->coeff_exp_shgi); - cmd[6] = cpu_to_le32(freqpar->coeff_man_shgi); - - /* RF_INIT echoes the command back to us */ - err = ar->exec_cmd(ar, AR9170_CMD_RF_INIT, - sizeof(cmd), (u8 *)cmd, - sizeof(cmd), (u8 *)cmd); - if (err) - return err; - - msleep(1000); - - return ar9170_echo_test(ar, 0xaabbccdd); -} - -static int ar9170_find_freq_idx(int nfreqs, u8 *freqs, u8 f) -{ - int idx = nfreqs - 2; - - while (idx >= 0) { - if (f >= freqs[idx]) - return idx; - idx--; - } - - return 0; -} - -static s32 ar9170_interpolate_s32(s32 x, s32 x1, s32 y1, s32 x2, s32 y2) -{ - /* nothing to interpolate, it's horizontal */ - if (y2 == y1) - return y1; - - /* check if we hit one of the edges */ - if (x == x1) - return y1; - if (x == x2) - return y2; - - /* x1 == x2 is bad, hopefully == x */ - if (x2 == x1) - return y1; - - return y1 + (((y2 - y1) * (x - x1)) / (x2 - x1)); -} - -static u8 ar9170_interpolate_u8(u8 x, u8 x1, u8 y1, u8 x2, u8 y2) -{ -#define SHIFT 8 - s32 y; - - y = ar9170_interpolate_s32(x << SHIFT, - x1 << SHIFT, y1 << SHIFT, - x2 << SHIFT, y2 << SHIFT); - - /* - * XXX: unwrap this expression - * Isn't it just DIV_ROUND_UP(y, 1<> SHIFT) + ((y & (1<<(SHIFT-1))) >> (SHIFT - 1)); -#undef SHIFT -} - -static u8 ar9170_interpolate_val(u8 x, u8 *x_array, u8 *y_array) -{ - int i; - - for (i = 0; i < 3; i++) - if (x <= x_array[i + 1]) - break; - - return ar9170_interpolate_u8(x, - x_array[i], - y_array[i], - x_array[i + 1], - y_array[i + 1]); -} - -static int ar9170_set_freq_cal_data(struct ar9170 *ar, - struct ieee80211_channel *channel) -{ - u8 *cal_freq_pier; - u8 vpds[2][AR5416_PD_GAIN_ICEPTS]; - u8 pwrs[2][AR5416_PD_GAIN_ICEPTS]; - int chain, idx, i; - u32 phy_data = 0; - u8 f, tmp; - - switch (channel->band) { - case IEEE80211_BAND_2GHZ: - f = channel->center_freq - 2300; - cal_freq_pier = ar->eeprom.cal_freq_pier_2G; - i = AR5416_NUM_2G_CAL_PIERS - 1; - break; - - case IEEE80211_BAND_5GHZ: - f = (channel->center_freq - 4800) / 5; - cal_freq_pier = ar->eeprom.cal_freq_pier_5G; - i = AR5416_NUM_5G_CAL_PIERS - 1; - break; - - default: - return -EINVAL; - break; - } - - for (; i >= 0; i--) { - if (cal_freq_pier[i] != 0xff) - break; - } - if (i < 0) - return -EINVAL; - - idx = ar9170_find_freq_idx(i, cal_freq_pier, f); - - ar9170_regwrite_begin(ar); - - for (chain = 0; chain < AR5416_MAX_CHAINS; chain++) { - for (i = 0; i < AR5416_PD_GAIN_ICEPTS; i++) { - struct ar9170_calibration_data_per_freq *cal_pier_data; - int j; - - switch (channel->band) { - case IEEE80211_BAND_2GHZ: - cal_pier_data = &ar->eeprom. - cal_pier_data_2G[chain][idx]; - break; - - case IEEE80211_BAND_5GHZ: - cal_pier_data = &ar->eeprom. - cal_pier_data_5G[chain][idx]; - break; - - default: - return -EINVAL; - } - - for (j = 0; j < 2; j++) { - vpds[j][i] = ar9170_interpolate_u8(f, - cal_freq_pier[idx], - cal_pier_data->vpd_pdg[j][i], - cal_freq_pier[idx + 1], - cal_pier_data[1].vpd_pdg[j][i]); - - pwrs[j][i] = ar9170_interpolate_u8(f, - cal_freq_pier[idx], - cal_pier_data->pwr_pdg[j][i], - cal_freq_pier[idx + 1], - cal_pier_data[1].pwr_pdg[j][i]) / 2; - } - } - - for (i = 0; i < 76; i++) { - if (i < 25) { - tmp = ar9170_interpolate_val(i, &pwrs[0][0], - &vpds[0][0]); - } else { - tmp = ar9170_interpolate_val(i - 12, - &pwrs[1][0], - &vpds[1][0]); - } - - phy_data |= tmp << ((i & 3) << 3); - if ((i & 3) == 3) { - ar9170_regwrite(0x1c6280 + chain * 0x1000 + - (i & ~3), phy_data); - phy_data = 0; - } - } - - for (i = 19; i < 32; i++) - ar9170_regwrite(0x1c6280 + chain * 0x1000 + (i << 2), - 0x0); - } - - ar9170_regwrite_finish(); - return ar9170_regwrite_result(); -} - -static u8 ar9170_get_max_edge_power(struct ar9170 *ar, - struct ar9170_calctl_edges edges[], - u32 freq) -{ - int i; - u8 rc = AR5416_MAX_RATE_POWER; - u8 f; - if (freq < 3000) - f = freq - 2300; - else - f = (freq - 4800) / 5; - - for (i = 0; i < AR5416_NUM_BAND_EDGES; i++) { - if (edges[i].channel == 0xff) - break; - if (f == edges[i].channel) { - /* exact freq match */ - rc = edges[i].power_flags & ~AR9170_CALCTL_EDGE_FLAGS; - break; - } - if (i > 0 && f < edges[i].channel) { - if (f > edges[i - 1].channel && - edges[i - 1].power_flags & - AR9170_CALCTL_EDGE_FLAGS) { - /* lower channel has the inband flag set */ - rc = edges[i - 1].power_flags & - ~AR9170_CALCTL_EDGE_FLAGS; - } - break; - } - } - - if (i == AR5416_NUM_BAND_EDGES) { - if (f > edges[i - 1].channel && - edges[i - 1].power_flags & AR9170_CALCTL_EDGE_FLAGS) { - /* lower channel has the inband flag set */ - rc = edges[i - 1].power_flags & - ~AR9170_CALCTL_EDGE_FLAGS; - } - } - return rc; -} - -static u8 ar9170_get_heavy_clip(struct ar9170 *ar, - struct ar9170_calctl_edges edges[], - u32 freq, enum ar9170_bw bw) -{ - u8 f; - int i; - u8 rc = 0; - - if (freq < 3000) - f = freq - 2300; - else - f = (freq - 4800) / 5; - - if (bw == AR9170_BW_40_BELOW || bw == AR9170_BW_40_ABOVE) - rc |= 0xf0; - - for (i = 0; i < AR5416_NUM_BAND_EDGES; i++) { - if (edges[i].channel == 0xff) - break; - if (f == edges[i].channel) { - if (!(edges[i].power_flags & AR9170_CALCTL_EDGE_FLAGS)) - rc |= 0x0f; - break; - } - } - - return rc; -} - -/* - * calculate the conformance test limits and the heavy clip parameter - * and apply them to ar->power* (derived from otus hal/hpmain.c, line 3706) - */ -static void ar9170_calc_ctl(struct ar9170 *ar, u32 freq, enum ar9170_bw bw) -{ - u8 ctl_grp; /* CTL group */ - u8 ctl_idx; /* CTL index */ - int i, j; - struct ctl_modes { - u8 ctl_mode; - u8 max_power; - u8 *pwr_cal_data; - int pwr_cal_len; - } *modes; - - /* - * order is relevant in the mode_list_*: we fall back to the - * lower indices if any mode is missed in the EEPROM. - */ - struct ctl_modes mode_list_2ghz[] = { - { CTL_11B, 0, ar->power_2G_cck, 4 }, - { CTL_11G, 0, ar->power_2G_ofdm, 4 }, - { CTL_2GHT20, 0, ar->power_2G_ht20, 8 }, - { CTL_2GHT40, 0, ar->power_2G_ht40, 8 }, - }; - struct ctl_modes mode_list_5ghz[] = { - { CTL_11A, 0, ar->power_5G_leg, 4 }, - { CTL_5GHT20, 0, ar->power_5G_ht20, 8 }, - { CTL_5GHT40, 0, ar->power_5G_ht40, 8 }, - }; - int nr_modes; - -#define EDGES(c, n) (ar->eeprom.ctl_data[c].control_edges[n]) - - ar->phy_heavy_clip = 0; - - /* - * TODO: investigate the differences between OTUS' - * hpreg.c::zfHpGetRegulatoryDomain() and - * ath/regd.c::ath_regd_get_band_ctl() - - * e.g. for FCC3_WORLD the OTUS procedure - * always returns CTL_FCC, while the one in ath/ delivers - * CTL_ETSI for 2GHz and CTL_FCC for 5GHz. - */ - ctl_grp = ath_regd_get_band_ctl(&ar->common.regulatory, - ar->hw->conf.channel->band); - - /* ctl group not found - either invalid band (NO_CTL) or ww roaming */ - if (ctl_grp == NO_CTL || ctl_grp == SD_NO_CTL) - ctl_grp = CTL_FCC; - - if (ctl_grp != CTL_FCC) - /* skip CTL and heavy clip for CTL_MKK and CTL_ETSI */ - return; - - if (ar->hw->conf.channel->band == IEEE80211_BAND_2GHZ) { - modes = mode_list_2ghz; - nr_modes = ARRAY_SIZE(mode_list_2ghz); - } else { - modes = mode_list_5ghz; - nr_modes = ARRAY_SIZE(mode_list_5ghz); - } - - for (i = 0; i < nr_modes; i++) { - u8 c = ctl_grp | modes[i].ctl_mode; - for (ctl_idx = 0; ctl_idx < AR5416_NUM_CTLS; ctl_idx++) - if (c == ar->eeprom.ctl_index[ctl_idx]) - break; - if (ctl_idx < AR5416_NUM_CTLS) { - int f_off = 0; - - /* determine heav clip parameter from - the 11G edges array */ - if (modes[i].ctl_mode == CTL_11G) { - ar->phy_heavy_clip = - ar9170_get_heavy_clip(ar, - EDGES(ctl_idx, 1), - freq, bw); - } - - /* adjust freq for 40MHz */ - if (modes[i].ctl_mode == CTL_2GHT40 || - modes[i].ctl_mode == CTL_5GHT40) { - if (bw == AR9170_BW_40_BELOW) - f_off = -10; - else - f_off = 10; - } - - modes[i].max_power = - ar9170_get_max_edge_power(ar, EDGES(ctl_idx, 1), - freq+f_off); - - /* - * TODO: check if the regulatory max. power is - * controlled by cfg80211 for DFS - * (hpmain applies it to max_power itself for DFS freq) - */ - - } else { - /* - * Workaround in otus driver, hpmain.c, line 3906: - * if no data for 5GHT20 are found, take the - * legacy 5G value. - * We extend this here to fallback from any other *HT or - * 11G, too. - */ - int k = i; - - modes[i].max_power = AR5416_MAX_RATE_POWER; - while (k-- > 0) { - if (modes[k].max_power != - AR5416_MAX_RATE_POWER) { - modes[i].max_power = modes[k].max_power; - break; - } - } - } - - /* apply max power to pwr_cal_data (ar->power_*) */ - for (j = 0; j < modes[i].pwr_cal_len; j++) { - modes[i].pwr_cal_data[j] = min(modes[i].pwr_cal_data[j], - modes[i].max_power); - } - } - - if (ar->phy_heavy_clip & 0xf0) { - ar->power_2G_ht40[0]--; - ar->power_2G_ht40[1]--; - ar->power_2G_ht40[2]--; - } - if (ar->phy_heavy_clip & 0xf) { - ar->power_2G_ht20[0]++; - ar->power_2G_ht20[1]++; - ar->power_2G_ht20[2]++; - } - - -#undef EDGES -} - -static int ar9170_set_power_cal(struct ar9170 *ar, u32 freq, enum ar9170_bw bw) -{ - struct ar9170_calibration_target_power_legacy *ctpl; - struct ar9170_calibration_target_power_ht *ctph; - u8 *ctpres; - int ntargets; - int idx, i, n; - u8 ackpower, ackchains, f; - u8 pwr_freqs[AR5416_MAX_NUM_TGT_PWRS]; - - if (freq < 3000) - f = freq - 2300; - else - f = (freq - 4800)/5; - - /* - * cycle through the various modes - * - * legacy modes first: 5G, 2G CCK, 2G OFDM - */ - for (i = 0; i < 3; i++) { - switch (i) { - case 0: /* 5 GHz legacy */ - ctpl = &ar->eeprom.cal_tgt_pwr_5G[0]; - ntargets = AR5416_NUM_5G_TARGET_PWRS; - ctpres = ar->power_5G_leg; - break; - case 1: /* 2.4 GHz CCK */ - ctpl = &ar->eeprom.cal_tgt_pwr_2G_cck[0]; - ntargets = AR5416_NUM_2G_CCK_TARGET_PWRS; - ctpres = ar->power_2G_cck; - break; - case 2: /* 2.4 GHz OFDM */ - ctpl = &ar->eeprom.cal_tgt_pwr_2G_ofdm[0]; - ntargets = AR5416_NUM_2G_OFDM_TARGET_PWRS; - ctpres = ar->power_2G_ofdm; - break; - default: - BUG(); - } - - for (n = 0; n < ntargets; n++) { - if (ctpl[n].freq == 0xff) - break; - pwr_freqs[n] = ctpl[n].freq; - } - ntargets = n; - idx = ar9170_find_freq_idx(ntargets, pwr_freqs, f); - for (n = 0; n < 4; n++) - ctpres[n] = ar9170_interpolate_u8( - f, - ctpl[idx + 0].freq, - ctpl[idx + 0].power[n], - ctpl[idx + 1].freq, - ctpl[idx + 1].power[n]); - } - - /* - * HT modes now: 5G HT20, 5G HT40, 2G CCK, 2G OFDM, 2G HT20, 2G HT40 - */ - for (i = 0; i < 4; i++) { - switch (i) { - case 0: /* 5 GHz HT 20 */ - ctph = &ar->eeprom.cal_tgt_pwr_5G_ht20[0]; - ntargets = AR5416_NUM_5G_TARGET_PWRS; - ctpres = ar->power_5G_ht20; - break; - case 1: /* 5 GHz HT 40 */ - ctph = &ar->eeprom.cal_tgt_pwr_5G_ht40[0]; - ntargets = AR5416_NUM_5G_TARGET_PWRS; - ctpres = ar->power_5G_ht40; - break; - case 2: /* 2.4 GHz HT 20 */ - ctph = &ar->eeprom.cal_tgt_pwr_2G_ht20[0]; - ntargets = AR5416_NUM_2G_OFDM_TARGET_PWRS; - ctpres = ar->power_2G_ht20; - break; - case 3: /* 2.4 GHz HT 40 */ - ctph = &ar->eeprom.cal_tgt_pwr_2G_ht40[0]; - ntargets = AR5416_NUM_2G_OFDM_TARGET_PWRS; - ctpres = ar->power_2G_ht40; - break; - default: - BUG(); - } - - for (n = 0; n < ntargets; n++) { - if (ctph[n].freq == 0xff) - break; - pwr_freqs[n] = ctph[n].freq; - } - ntargets = n; - idx = ar9170_find_freq_idx(ntargets, pwr_freqs, f); - for (n = 0; n < 8; n++) - ctpres[n] = ar9170_interpolate_u8( - f, - ctph[idx + 0].freq, - ctph[idx + 0].power[n], - ctph[idx + 1].freq, - ctph[idx + 1].power[n]); - } - - - /* calc. conformance test limits and apply to ar->power*[] */ - ar9170_calc_ctl(ar, freq, bw); - - /* set ACK/CTS TX power */ - ar9170_regwrite_begin(ar); - - if (ar->eeprom.tx_mask != 1) - ackchains = AR9170_TX_PHY_TXCHAIN_2; - else - ackchains = AR9170_TX_PHY_TXCHAIN_1; - - if (freq < 3000) - ackpower = ar->power_2G_ofdm[0] & 0x3f; - else - ackpower = ar->power_5G_leg[0] & 0x3f; - - ar9170_regwrite(0x1c3694, ackpower << 20 | ackchains << 26); - ar9170_regwrite(0x1c3bb4, ackpower << 5 | ackchains << 11 | - ackpower << 21 | ackchains << 27); - - ar9170_regwrite_finish(); - return ar9170_regwrite_result(); -} - -static int ar9170_calc_noise_dbm(u32 raw_noise) -{ - if (raw_noise & 0x100) - return ~((raw_noise & 0x0ff) >> 1); - else - return (raw_noise & 0xff) >> 1; -} - -int ar9170_set_channel(struct ar9170 *ar, struct ieee80211_channel *channel, - enum ar9170_rf_init_mode rfi, enum ar9170_bw bw) -{ - const struct ar9170_phy_freq_params *freqpar; - u32 cmd, tmp, offs; - __le32 vals[8]; - int i, err; - bool bandswitch; - - /* clear BB heavy clip enable */ - err = ar9170_write_reg(ar, 0x1c59e0, 0x200); - if (err) - return err; - - /* may be NULL at first setup */ - if (ar->channel) - bandswitch = ar->channel->band != channel->band; - else - bandswitch = true; - - /* HW workaround */ - if (!ar->hw->wiphy->bands[IEEE80211_BAND_5GHZ] && - channel->center_freq <= 2417) - bandswitch = true; - - err = ar->exec_cmd(ar, AR9170_CMD_FREQ_START, 0, NULL, 0, NULL); - if (err) - return err; - - if (rfi != AR9170_RFI_NONE || bandswitch) { - u32 val = 0x400; - - if (rfi == AR9170_RFI_COLD) - val = 0x800; - - /* warm/cold reset BB/ADDA */ - err = ar9170_write_reg(ar, 0x1d4004, val); - if (err) - return err; - - err = ar9170_write_reg(ar, 0x1d4004, 0x0); - if (err) - return err; - - err = ar9170_init_phy(ar, channel->band); - if (err) - return err; - - err = ar9170_init_rf_banks_0_7(ar, - channel->band == IEEE80211_BAND_5GHZ); - if (err) - return err; - - cmd = AR9170_CMD_RF_INIT; - } else { - cmd = AR9170_CMD_FREQUENCY; - } - - err = ar9170_init_rf_bank4_pwr(ar, - channel->band == IEEE80211_BAND_5GHZ, - channel->center_freq, bw); - if (err) - return err; - - switch (bw) { - case AR9170_BW_20: - tmp = 0x240; - offs = 0; - break; - case AR9170_BW_40_BELOW: - tmp = 0x2c4; - offs = 3; - break; - case AR9170_BW_40_ABOVE: - tmp = 0x2d4; - offs = 1; - break; - default: - BUG(); - return -ENOSYS; - } - - if (ar->eeprom.tx_mask != 1) - tmp |= 0x100; - - err = ar9170_write_reg(ar, 0x1c5804, tmp); - if (err) - return err; - - err = ar9170_set_freq_cal_data(ar, channel); - if (err) - return err; - - err = ar9170_set_power_cal(ar, channel->center_freq, bw); - if (err) - return err; - - freqpar = ar9170_get_hw_dyn_params(channel, bw); - - vals[0] = cpu_to_le32(channel->center_freq * 1000); - vals[1] = cpu_to_le32(conf_is_ht40(&ar->hw->conf)); - vals[2] = cpu_to_le32(offs << 2 | 1); - vals[3] = cpu_to_le32(freqpar->coeff_exp); - vals[4] = cpu_to_le32(freqpar->coeff_man); - vals[5] = cpu_to_le32(freqpar->coeff_exp_shgi); - vals[6] = cpu_to_le32(freqpar->coeff_man_shgi); - vals[7] = cpu_to_le32(1000); - - err = ar->exec_cmd(ar, cmd, sizeof(vals), (u8 *)vals, - sizeof(vals), (u8 *)vals); - if (err) - return err; - - if (ar->phy_heavy_clip) { - err = ar9170_write_reg(ar, 0x1c59e0, - 0x200 | ar->phy_heavy_clip); - if (err) { - if (ar9170_nag_limiter(ar)) - wiphy_err(ar->hw->wiphy, - "failed to set heavy clip\n"); - } - } - - for (i = 0; i < 2; i++) { - ar->noise[i] = ar9170_calc_noise_dbm( - (le32_to_cpu(vals[2 + i]) >> 19) & 0x1ff); - - ar->noise[i + 2] = ar9170_calc_noise_dbm( - (le32_to_cpu(vals[5 + i]) >> 23) & 0x1ff); - } - - ar->channel = channel; - return 0; -} diff --git a/drivers/net/wireless/ath/ar9170/usb.c b/drivers/net/wireless/ath/ar9170/usb.c deleted file mode 100644 index d3be6f9..0000000 --- a/drivers/net/wireless/ath/ar9170/usb.c +++ /dev/null @@ -1,1008 +0,0 @@ -/* - * Atheros AR9170 driver - * - * USB - frontend - * - * Copyright 2008, Johannes Berg - * Copyright 2009, Christian Lamparter - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; see the file COPYING. If not, see - * http://www.gnu.org/licenses/. - * - * This file incorporates work covered by the following copyright and - * permission notice: - * Copyright (c) 2007-2008 Atheros Communications, Inc. - * - * 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 -#include -#include -#include -#include -#include "ar9170.h" -#include "cmd.h" -#include "hw.h" -#include "usb.h" - -MODULE_AUTHOR("Johannes Berg "); -MODULE_AUTHOR("Christian Lamparter "); -MODULE_LICENSE("GPL"); -MODULE_DESCRIPTION("Atheros AR9170 802.11n USB wireless"); -MODULE_FIRMWARE("ar9170.fw"); - -enum ar9170_requirements { - AR9170_REQ_FW1_ONLY = 1, -}; - -static struct usb_device_id ar9170_usb_ids[] = { - /* Atheros 9170 */ - { USB_DEVICE(0x0cf3, 0x9170) }, - /* Atheros TG121N */ - { USB_DEVICE(0x0cf3, 0x1001) }, - /* TP-Link TL-WN821N v2 */ - { USB_DEVICE(0x0cf3, 0x1002) }, - /* 3Com Dual Band 802.11n USB Adapter */ - { USB_DEVICE(0x0cf3, 0x1010) }, - /* H3C Dual Band 802.11n USB Adapter */ - { USB_DEVICE(0x0cf3, 0x1011) }, - /* Cace Airpcap NX */ - { USB_DEVICE(0xcace, 0x0300) }, - /* D-Link DWA 160 A1 */ - { USB_DEVICE(0x07d1, 0x3c10) }, - /* D-Link DWA 160 A2 */ - { USB_DEVICE(0x07d1, 0x3a09) }, - /* Netgear WNA1000 */ - { USB_DEVICE(0x0846, 0x9040) }, - /* Netgear WNDA3100 */ - { USB_DEVICE(0x0846, 0x9010) }, - /* Netgear WN111 v2 */ - { USB_DEVICE(0x0846, 0x9001) }, - /* Zydas ZD1221 */ - { USB_DEVICE(0x0ace, 0x1221) }, - /* Proxim ORiNOCO 802.11n USB */ - { USB_DEVICE(0x1435, 0x0804) }, - /* WNC Generic 11n USB Dongle */ - { USB_DEVICE(0x1435, 0x0326) }, - /* ZyXEL NWD271N */ - { USB_DEVICE(0x0586, 0x3417) }, - /* Z-Com UB81 BG */ - { USB_DEVICE(0x0cde, 0x0023) }, - /* Z-Com UB82 ABG */ - { USB_DEVICE(0x0cde, 0x0026) }, - /* Sphairon Homelink 1202 */ - { USB_DEVICE(0x0cde, 0x0027) }, - /* Arcadyan WN7512 */ - { USB_DEVICE(0x083a, 0xf522) }, - /* Planex GWUS300 */ - { USB_DEVICE(0x2019, 0x5304) }, - /* IO-Data WNGDNUS2 */ - { USB_DEVICE(0x04bb, 0x093f) }, - /* AVM FRITZ!WLAN USB Stick N */ - { USB_DEVICE(0x057C, 0x8401) }, - /* NEC WL300NU-G */ - { USB_DEVICE(0x0409, 0x0249) }, - /* AVM FRITZ!WLAN USB Stick N 2.4 */ - { USB_DEVICE(0x057C, 0x8402), .driver_info = AR9170_REQ_FW1_ONLY }, - /* Qwest/Actiontec 802AIN Wireless N USB Network Adapter */ - { USB_DEVICE(0x1668, 0x1200) }, - - /* terminate */ - {} -}; -MODULE_DEVICE_TABLE(usb, ar9170_usb_ids); - -static void ar9170_usb_submit_urb(struct ar9170_usb *aru) -{ - struct urb *urb; - unsigned long flags; - int err; - - if (unlikely(!IS_STARTED(&aru->common))) - return ; - - spin_lock_irqsave(&aru->tx_urb_lock, flags); - if (atomic_read(&aru->tx_submitted_urbs) >= AR9170_NUM_TX_URBS) { - spin_unlock_irqrestore(&aru->tx_urb_lock, flags); - return ; - } - atomic_inc(&aru->tx_submitted_urbs); - - urb = usb_get_from_anchor(&aru->tx_pending); - if (!urb) { - atomic_dec(&aru->tx_submitted_urbs); - spin_unlock_irqrestore(&aru->tx_urb_lock, flags); - - return ; - } - spin_unlock_irqrestore(&aru->tx_urb_lock, flags); - - aru->tx_pending_urbs--; - usb_anchor_urb(urb, &aru->tx_submitted); - - err = usb_submit_urb(urb, GFP_ATOMIC); - if (unlikely(err)) { - if (ar9170_nag_limiter(&aru->common)) - dev_err(&aru->udev->dev, "submit_urb failed (%d).\n", - err); - - usb_unanchor_urb(urb); - atomic_dec(&aru->tx_submitted_urbs); - ar9170_tx_callback(&aru->common, urb->context); - } - - usb_free_urb(urb); -} - -static void ar9170_usb_tx_urb_complete_frame(struct urb *urb) -{ - struct sk_buff *skb = urb->context; - struct ar9170_usb *aru = usb_get_intfdata(usb_ifnum_to_if(urb->dev, 0)); - - if (unlikely(!aru)) { - dev_kfree_skb_irq(skb); - return ; - } - - atomic_dec(&aru->tx_submitted_urbs); - - ar9170_tx_callback(&aru->common, skb); - - ar9170_usb_submit_urb(aru); -} - -static void ar9170_usb_tx_urb_complete(struct urb *urb) -{ -} - -static void ar9170_usb_irq_completed(struct urb *urb) -{ - struct ar9170_usb *aru = urb->context; - - switch (urb->status) { - /* everything is fine */ - case 0: - break; - - /* disconnect */ - case -ENOENT: - case -ECONNRESET: - case -ENODEV: - case -ESHUTDOWN: - goto free; - - default: - goto resubmit; - } - - ar9170_handle_command_response(&aru->common, urb->transfer_buffer, - urb->actual_length); - -resubmit: - usb_anchor_urb(urb, &aru->rx_submitted); - if (usb_submit_urb(urb, GFP_ATOMIC)) { - usb_unanchor_urb(urb); - goto free; - } - - return; - -free: - usb_free_coherent(aru->udev, 64, urb->transfer_buffer, urb->transfer_dma); -} - -static void ar9170_usb_rx_completed(struct urb *urb) -{ - struct sk_buff *skb = urb->context; - struct ar9170_usb *aru = usb_get_intfdata(usb_ifnum_to_if(urb->dev, 0)); - int err; - - if (!aru) - goto free; - - switch (urb->status) { - /* everything is fine */ - case 0: - break; - - /* disconnect */ - case -ENOENT: - case -ECONNRESET: - case -ENODEV: - case -ESHUTDOWN: - goto free; - - default: - goto resubmit; - } - - skb_put(skb, urb->actual_length); - ar9170_rx(&aru->common, skb); - -resubmit: - skb_reset_tail_pointer(skb); - skb_trim(skb, 0); - - usb_anchor_urb(urb, &aru->rx_submitted); - err = usb_submit_urb(urb, GFP_ATOMIC); - if (unlikely(err)) { - usb_unanchor_urb(urb); - goto free; - } - - return ; - -free: - dev_kfree_skb_irq(skb); -} - -static int ar9170_usb_prep_rx_urb(struct ar9170_usb *aru, - struct urb *urb, gfp_t gfp) -{ - struct sk_buff *skb; - - skb = __dev_alloc_skb(AR9170_MAX_RX_BUFFER_SIZE + 32, gfp); - if (!skb) - return -ENOMEM; - - /* reserve some space for mac80211's radiotap */ - skb_reserve(skb, 32); - - usb_fill_bulk_urb(urb, aru->udev, - usb_rcvbulkpipe(aru->udev, AR9170_EP_RX), - skb->data, min(skb_tailroom(skb), - AR9170_MAX_RX_BUFFER_SIZE), - ar9170_usb_rx_completed, skb); - - return 0; -} - -static int ar9170_usb_alloc_rx_irq_urb(struct ar9170_usb *aru) -{ - struct urb *urb = NULL; - void *ibuf; - int err = -ENOMEM; - - /* initialize interrupt endpoint */ - urb = usb_alloc_urb(0, GFP_KERNEL); - if (!urb) - goto out; - - ibuf = usb_alloc_coherent(aru->udev, 64, GFP_KERNEL, &urb->transfer_dma); - if (!ibuf) - goto out; - - usb_fill_int_urb(urb, aru->udev, - usb_rcvintpipe(aru->udev, AR9170_EP_IRQ), ibuf, - 64, ar9170_usb_irq_completed, aru, 1); - urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; - - usb_anchor_urb(urb, &aru->rx_submitted); - err = usb_submit_urb(urb, GFP_KERNEL); - if (err) { - usb_unanchor_urb(urb); - usb_free_coherent(aru->udev, 64, urb->transfer_buffer, - urb->transfer_dma); - } - -out: - usb_free_urb(urb); - return err; -} - -static int ar9170_usb_alloc_rx_bulk_urbs(struct ar9170_usb *aru) -{ - struct urb *urb; - int i; - int err = -EINVAL; - - for (i = 0; i < AR9170_NUM_RX_URBS; i++) { - err = -ENOMEM; - urb = usb_alloc_urb(0, GFP_KERNEL); - if (!urb) - goto err_out; - - err = ar9170_usb_prep_rx_urb(aru, urb, GFP_KERNEL); - if (err) { - usb_free_urb(urb); - goto err_out; - } - - usb_anchor_urb(urb, &aru->rx_submitted); - err = usb_submit_urb(urb, GFP_KERNEL); - if (err) { - usb_unanchor_urb(urb); - dev_kfree_skb_any((void *) urb->transfer_buffer); - usb_free_urb(urb); - goto err_out; - } - usb_free_urb(urb); - } - - /* the device now waiting for a firmware. */ - aru->common.state = AR9170_IDLE; - return 0; - -err_out: - - usb_kill_anchored_urbs(&aru->rx_submitted); - return err; -} - -static int ar9170_usb_flush(struct ar9170 *ar) -{ - struct ar9170_usb *aru = (void *) ar; - struct urb *urb; - int ret, err = 0; - - if (IS_STARTED(ar)) - aru->common.state = AR9170_IDLE; - - usb_wait_anchor_empty_timeout(&aru->tx_pending, - msecs_to_jiffies(800)); - while ((urb = usb_get_from_anchor(&aru->tx_pending))) { - ar9170_tx_callback(&aru->common, (void *) urb->context); - usb_free_urb(urb); - } - - /* lets wait a while until the tx - queues are dried out */ - ret = usb_wait_anchor_empty_timeout(&aru->tx_submitted, - msecs_to_jiffies(100)); - if (ret == 0) - err = -ETIMEDOUT; - - usb_kill_anchored_urbs(&aru->tx_submitted); - - if (IS_ACCEPTING_CMD(ar)) - aru->common.state = AR9170_STARTED; - - return err; -} - -static void ar9170_usb_cancel_urbs(struct ar9170_usb *aru) -{ - int err; - - aru->common.state = AR9170_UNKNOWN_STATE; - - err = ar9170_usb_flush(&aru->common); - if (err) - dev_err(&aru->udev->dev, "stuck tx urbs!\n"); - - usb_poison_anchored_urbs(&aru->tx_submitted); - usb_poison_anchored_urbs(&aru->rx_submitted); -} - -static int ar9170_usb_exec_cmd(struct ar9170 *ar, enum ar9170_cmd cmd, - unsigned int plen, void *payload, - unsigned int outlen, void *out) -{ - struct ar9170_usb *aru = (void *) ar; - struct urb *urb = NULL; - unsigned long flags; - int err = -ENOMEM; - - if (unlikely(!IS_ACCEPTING_CMD(ar))) - return -EPERM; - - if (WARN_ON(plen > AR9170_MAX_CMD_LEN - 4)) - return -EINVAL; - - urb = usb_alloc_urb(0, GFP_ATOMIC); - if (unlikely(!urb)) - goto err_free; - - ar->cmdbuf[0] = cpu_to_le32(plen); - ar->cmdbuf[0] |= cpu_to_le32(cmd << 8); - /* writing multiple regs fills this buffer already */ - if (plen && payload != (u8 *)(&ar->cmdbuf[1])) - memcpy(&ar->cmdbuf[1], payload, plen); - - spin_lock_irqsave(&aru->common.cmdlock, flags); - aru->readbuf = (u8 *)out; - aru->readlen = outlen; - spin_unlock_irqrestore(&aru->common.cmdlock, flags); - - usb_fill_int_urb(urb, aru->udev, - usb_sndintpipe(aru->udev, AR9170_EP_CMD), - aru->common.cmdbuf, plen + 4, - ar9170_usb_tx_urb_complete, NULL, 1); - - usb_anchor_urb(urb, &aru->tx_submitted); - err = usb_submit_urb(urb, GFP_ATOMIC); - if (unlikely(err)) { - usb_unanchor_urb(urb); - usb_free_urb(urb); - goto err_unbuf; - } - usb_free_urb(urb); - - err = wait_for_completion_timeout(&aru->cmd_wait, HZ); - if (err == 0) { - err = -ETIMEDOUT; - goto err_unbuf; - } - - if (aru->readlen != outlen) { - err = -EMSGSIZE; - goto err_unbuf; - } - - return 0; - -err_unbuf: - /* Maybe the device was removed in the second we were waiting? */ - if (IS_STARTED(ar)) { - dev_err(&aru->udev->dev, "no command feedback " - "received (%d).\n", err); - - /* provide some maybe useful debug information */ - print_hex_dump_bytes("ar9170 cmd: ", DUMP_PREFIX_NONE, - aru->common.cmdbuf, plen + 4); - dump_stack(); - } - - /* invalidate to avoid completing the next prematurely */ - spin_lock_irqsave(&aru->common.cmdlock, flags); - aru->readbuf = NULL; - aru->readlen = 0; - spin_unlock_irqrestore(&aru->common.cmdlock, flags); - -err_free: - - return err; -} - -static int ar9170_usb_tx(struct ar9170 *ar, struct sk_buff *skb) -{ - struct ar9170_usb *aru = (struct ar9170_usb *) ar; - struct urb *urb; - - if (unlikely(!IS_STARTED(ar))) { - /* Seriously, what were you drink... err... thinking!? */ - return -EPERM; - } - - urb = usb_alloc_urb(0, GFP_ATOMIC); - if (unlikely(!urb)) - return -ENOMEM; - - usb_fill_bulk_urb(urb, aru->udev, - usb_sndbulkpipe(aru->udev, AR9170_EP_TX), - skb->data, skb->len, - ar9170_usb_tx_urb_complete_frame, skb); - urb->transfer_flags |= URB_ZERO_PACKET; - - usb_anchor_urb(urb, &aru->tx_pending); - aru->tx_pending_urbs++; - - usb_free_urb(urb); - - ar9170_usb_submit_urb(aru); - return 0; -} - -static void ar9170_usb_callback_cmd(struct ar9170 *ar, u32 len , void *buffer) -{ - struct ar9170_usb *aru = (void *) ar; - unsigned long flags; - u32 in, out; - - if (unlikely(!buffer)) - return ; - - in = le32_to_cpup((__le32 *)buffer); - out = le32_to_cpu(ar->cmdbuf[0]); - - /* mask off length byte */ - out &= ~0xFF; - - if (aru->readlen >= 0) { - /* add expected length */ - out |= aru->readlen; - } else { - /* add obtained length */ - out |= in & 0xFF; - } - - /* - * Some commands (e.g: AR9170_CMD_FREQUENCY) have a variable response - * length and we cannot predict the correct length in advance. - * So we only check if we provided enough space for the data. - */ - if (unlikely(out < in)) { - dev_warn(&aru->udev->dev, "received invalid command response " - "got %d bytes, instead of %d bytes " - "and the resp length is %d bytes\n", - in, out, len); - print_hex_dump_bytes("ar9170 invalid resp: ", - DUMP_PREFIX_OFFSET, buffer, len); - /* - * Do not complete, then the command times out, - * and we get a stack trace from there. - */ - return ; - } - - spin_lock_irqsave(&aru->common.cmdlock, flags); - if (aru->readbuf && len > 0) { - memcpy(aru->readbuf, buffer + 4, len - 4); - aru->readbuf = NULL; - } - complete(&aru->cmd_wait); - spin_unlock_irqrestore(&aru->common.cmdlock, flags); -} - -static int ar9170_usb_upload(struct ar9170_usb *aru, const void *data, - size_t len, u32 addr, bool complete) -{ - int transfer, err; - u8 *buf = kmalloc(4096, GFP_KERNEL); - - if (!buf) - return -ENOMEM; - - while (len) { - transfer = min_t(int, len, 4096); - memcpy(buf, data, transfer); - - err = usb_control_msg(aru->udev, usb_sndctrlpipe(aru->udev, 0), - 0x30 /* FW DL */, 0x40 | USB_DIR_OUT, - addr >> 8, 0, buf, transfer, 1000); - - if (err < 0) { - kfree(buf); - return err; - } - - len -= transfer; - data += transfer; - addr += transfer; - } - kfree(buf); - - if (complete) { - err = usb_control_msg(aru->udev, usb_sndctrlpipe(aru->udev, 0), - 0x31 /* FW DL COMPLETE */, - 0x40 | USB_DIR_OUT, 0, 0, NULL, 0, 5000); - } - - return 0; -} - -static int ar9170_usb_reset(struct ar9170_usb *aru) -{ - int ret, lock = (aru->intf->condition != USB_INTERFACE_BINDING); - - if (lock) { - ret = usb_lock_device_for_reset(aru->udev, aru->intf); - if (ret < 0) { - dev_err(&aru->udev->dev, "unable to lock device " - "for reset (%d).\n", ret); - return ret; - } - } - - ret = usb_reset_device(aru->udev); - if (lock) - usb_unlock_device(aru->udev); - - /* let it rest - for a second - */ - msleep(1000); - - return ret; -} - -static int ar9170_usb_upload_firmware(struct ar9170_usb *aru) -{ - int err; - - if (!aru->init_values) - goto upload_fw_start; - - /* First, upload initial values to device RAM */ - err = ar9170_usb_upload(aru, aru->init_values->data, - aru->init_values->size, 0x102800, false); - if (err) { - dev_err(&aru->udev->dev, "firmware part 1 " - "upload failed (%d).\n", err); - return err; - } - -upload_fw_start: - - /* Then, upload the firmware itself and start it */ - return ar9170_usb_upload(aru, aru->firmware->data, aru->firmware->size, - 0x200000, true); -} - -static int ar9170_usb_init_transport(struct ar9170_usb *aru) -{ - struct ar9170 *ar = (void *) &aru->common; - int err; - - ar9170_regwrite_begin(ar); - - /* Set USB Rx stream mode MAX packet number to 2 */ - ar9170_regwrite(AR9170_USB_REG_MAX_AGG_UPLOAD, 0x4); - - /* Set USB Rx stream mode timeout to 10us */ - ar9170_regwrite(AR9170_USB_REG_UPLOAD_TIME_CTL, 0x80); - - ar9170_regwrite_finish(); - - err = ar9170_regwrite_result(); - if (err) - dev_err(&aru->udev->dev, "USB setup failed (%d).\n", err); - - return err; -} - -static void ar9170_usb_stop(struct ar9170 *ar) -{ - struct ar9170_usb *aru = (void *) ar; - int ret; - - if (IS_ACCEPTING_CMD(ar)) - aru->common.state = AR9170_STOPPED; - - ret = ar9170_usb_flush(ar); - if (ret) - dev_err(&aru->udev->dev, "kill pending tx urbs.\n"); - - usb_poison_anchored_urbs(&aru->tx_submitted); - - /* - * Note: - * So far we freed all tx urbs, but we won't dare to touch any rx urbs. - * Else we would end up with a unresponsive device... - */ -} - -static int ar9170_usb_open(struct ar9170 *ar) -{ - struct ar9170_usb *aru = (void *) ar; - int err; - - usb_unpoison_anchored_urbs(&aru->tx_submitted); - err = ar9170_usb_init_transport(aru); - if (err) { - usb_poison_anchored_urbs(&aru->tx_submitted); - return err; - } - - aru->common.state = AR9170_IDLE; - return 0; -} - -static int ar9170_usb_init_device(struct ar9170_usb *aru) -{ - int err; - - err = ar9170_usb_alloc_rx_irq_urb(aru); - if (err) - goto err_out; - - err = ar9170_usb_alloc_rx_bulk_urbs(aru); - if (err) - goto err_unrx; - - err = ar9170_usb_upload_firmware(aru); - if (err) { - err = ar9170_echo_test(&aru->common, 0x60d43110); - if (err) { - /* force user invention, by disabling the device */ - err = usb_driver_set_configuration(aru->udev, -1); - dev_err(&aru->udev->dev, "device is in a bad state. " - "please reconnect it!\n"); - goto err_unrx; - } - } - - return 0; - -err_unrx: - ar9170_usb_cancel_urbs(aru); - -err_out: - return err; -} - -static void ar9170_usb_firmware_failed(struct ar9170_usb *aru) -{ - struct device *parent = aru->udev->dev.parent; - struct usb_device *udev; - - /* - * Store a copy of the usb_device pointer locally. - * This is because device_release_driver initiates - * ar9170_usb_disconnect, which in turn frees our - * driver context (aru). - */ - udev = aru->udev; - - complete(&aru->firmware_loading_complete); - - /* unbind anything failed */ - if (parent) - device_lock(parent); - - device_release_driver(&udev->dev); - if (parent) - device_unlock(parent); - - usb_put_dev(udev); -} - -static void ar9170_usb_firmware_finish(const struct firmware *fw, void *context) -{ - struct ar9170_usb *aru = context; - int err; - - aru->firmware = fw; - - if (!fw) { - dev_err(&aru->udev->dev, "firmware file not found.\n"); - goto err_freefw; - } - - err = ar9170_usb_init_device(aru); - if (err) - goto err_freefw; - - err = ar9170_usb_open(&aru->common); - if (err) - goto err_unrx; - - err = ar9170_register(&aru->common, &aru->udev->dev); - - ar9170_usb_stop(&aru->common); - if (err) - goto err_unrx; - - complete(&aru->firmware_loading_complete); - usb_put_dev(aru->udev); - return; - - err_unrx: - ar9170_usb_cancel_urbs(aru); - - err_freefw: - ar9170_usb_firmware_failed(aru); -} - -static void ar9170_usb_firmware_inits(const struct firmware *fw, - void *context) -{ - struct ar9170_usb *aru = context; - int err; - - if (!fw) { - dev_err(&aru->udev->dev, "file with init values not found.\n"); - ar9170_usb_firmware_failed(aru); - return; - } - - aru->init_values = fw; - - /* ok so we have the init values -- get code for two-stage */ - - err = request_firmware_nowait(THIS_MODULE, 1, "ar9170-2.fw", - &aru->udev->dev, GFP_KERNEL, aru, - ar9170_usb_firmware_finish); - if (err) - ar9170_usb_firmware_failed(aru); -} - -static void ar9170_usb_firmware_step2(const struct firmware *fw, void *context) -{ - struct ar9170_usb *aru = context; - int err; - - if (fw) { - ar9170_usb_firmware_finish(fw, context); - return; - } - - if (aru->req_one_stage_fw) { - dev_err(&aru->udev->dev, "ar9170.fw firmware file " - "not found and is required for this device\n"); - ar9170_usb_firmware_failed(aru); - return; - } - - dev_err(&aru->udev->dev, "ar9170.fw firmware file " - "not found, trying old firmware...\n"); - - err = request_firmware_nowait(THIS_MODULE, 1, "ar9170-1.fw", - &aru->udev->dev, GFP_KERNEL, aru, - ar9170_usb_firmware_inits); - if (err) - ar9170_usb_firmware_failed(aru); -} - -static bool ar9170_requires_one_stage(const struct usb_device_id *id) -{ - if (!id->driver_info) - return false; - if (id->driver_info == AR9170_REQ_FW1_ONLY) - return true; - return false; -} - -static int ar9170_usb_probe(struct usb_interface *intf, - const struct usb_device_id *id) -{ - struct ar9170_usb *aru; - struct ar9170 *ar; - struct usb_device *udev; - int err; - - aru = ar9170_alloc(sizeof(*aru)); - if (IS_ERR(aru)) { - err = PTR_ERR(aru); - goto out; - } - - udev = interface_to_usbdev(intf); - usb_get_dev(udev); - aru->udev = udev; - aru->intf = intf; - ar = &aru->common; - - aru->req_one_stage_fw = ar9170_requires_one_stage(id); - - usb_set_intfdata(intf, aru); - SET_IEEE80211_DEV(ar->hw, &intf->dev); - - init_usb_anchor(&aru->rx_submitted); - init_usb_anchor(&aru->tx_pending); - init_usb_anchor(&aru->tx_submitted); - init_completion(&aru->cmd_wait); - init_completion(&aru->firmware_loading_complete); - spin_lock_init(&aru->tx_urb_lock); - - aru->tx_pending_urbs = 0; - atomic_set(&aru->tx_submitted_urbs, 0); - - aru->common.stop = ar9170_usb_stop; - aru->common.flush = ar9170_usb_flush; - aru->common.open = ar9170_usb_open; - aru->common.tx = ar9170_usb_tx; - aru->common.exec_cmd = ar9170_usb_exec_cmd; - aru->common.callback_cmd = ar9170_usb_callback_cmd; - -#ifdef CONFIG_PM - udev->reset_resume = 1; -#endif /* CONFIG_PM */ - err = ar9170_usb_reset(aru); - if (err) - goto err_freehw; - - usb_get_dev(aru->udev); - return request_firmware_nowait(THIS_MODULE, 1, "ar9170.fw", - &aru->udev->dev, GFP_KERNEL, aru, - ar9170_usb_firmware_step2); -err_freehw: - usb_set_intfdata(intf, NULL); - usb_put_dev(udev); - ieee80211_free_hw(ar->hw); -out: - return err; -} - -static void ar9170_usb_disconnect(struct usb_interface *intf) -{ - struct ar9170_usb *aru = usb_get_intfdata(intf); - - if (!aru) - return; - - aru->common.state = AR9170_IDLE; - - wait_for_completion(&aru->firmware_loading_complete); - - ar9170_unregister(&aru->common); - ar9170_usb_cancel_urbs(aru); - - usb_put_dev(aru->udev); - usb_set_intfdata(intf, NULL); - ieee80211_free_hw(aru->common.hw); - - release_firmware(aru->init_values); - release_firmware(aru->firmware); -} - -#ifdef CONFIG_PM -static int ar9170_suspend(struct usb_interface *intf, - pm_message_t message) -{ - struct ar9170_usb *aru = usb_get_intfdata(intf); - - if (!aru) - return -ENODEV; - - aru->common.state = AR9170_IDLE; - ar9170_usb_cancel_urbs(aru); - - return 0; -} - -static int ar9170_resume(struct usb_interface *intf) -{ - struct ar9170_usb *aru = usb_get_intfdata(intf); - int err; - - if (!aru) - return -ENODEV; - - usb_unpoison_anchored_urbs(&aru->rx_submitted); - usb_unpoison_anchored_urbs(&aru->tx_submitted); - - err = ar9170_usb_init_device(aru); - if (err) - goto err_unrx; - - err = ar9170_usb_open(&aru->common); - if (err) - goto err_unrx; - - return 0; - -err_unrx: - aru->common.state = AR9170_IDLE; - ar9170_usb_cancel_urbs(aru); - - return err; -} -#endif /* CONFIG_PM */ - -static struct usb_driver ar9170_driver = { - .name = "ar9170usb", - .probe = ar9170_usb_probe, - .disconnect = ar9170_usb_disconnect, - .id_table = ar9170_usb_ids, - .soft_unbind = 1, -#ifdef CONFIG_PM - .suspend = ar9170_suspend, - .resume = ar9170_resume, - .reset_resume = ar9170_resume, -#endif /* CONFIG_PM */ -}; - -static int __init ar9170_init(void) -{ - return usb_register(&ar9170_driver); -} - -static void __exit ar9170_exit(void) -{ - usb_deregister(&ar9170_driver); -} - -module_init(ar9170_init); -module_exit(ar9170_exit); diff --git a/drivers/net/wireless/ath/ar9170/usb.h b/drivers/net/wireless/ath/ar9170/usb.h deleted file mode 100644 index 919b060..0000000 --- a/drivers/net/wireless/ath/ar9170/usb.h +++ /dev/null @@ -1,82 +0,0 @@ -/* - * Atheros AR9170 USB driver - * - * Driver specific definitions - * - * Copyright 2008, Johannes Berg - * Copyright 2009, Christian Lamparter - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; see the file COPYING. If not, see - * http://www.gnu.org/licenses/. - * - * This file incorporates work covered by the following copyright and - * permission notice: - * Copyright (c) 2007-2008 Atheros Communications, Inc. - * - * 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. - */ -#ifndef __USB_H -#define __USB_H - -#include -#include -#include -#include -#include -#include -#include -#include "eeprom.h" -#include "hw.h" -#include "ar9170.h" - -#define AR9170_NUM_RX_URBS 16 -#define AR9170_NUM_TX_URBS 8 - -struct firmware; - -struct ar9170_usb { - struct ar9170 common; - struct usb_device *udev; - struct usb_interface *intf; - - struct usb_anchor rx_submitted; - struct usb_anchor tx_pending; - struct usb_anchor tx_submitted; - - bool req_one_stage_fw; - - spinlock_t tx_urb_lock; - atomic_t tx_submitted_urbs; - unsigned int tx_pending_urbs; - - struct completion cmd_wait; - struct completion firmware_loading_complete; - int readlen; - u8 *readbuf; - - const struct firmware *init_values; - const struct firmware *firmware; -}; - -#endif /* __USB_H */ -- cgit v0.10.2 From 08b8099c128d601fd675b212ef8b10397706b633 Mon Sep 17 00:00:00 2001 From: Xose Vazquez Perez Date: Sun, 27 Mar 2011 01:15:53 +0100 Subject: wireless: rt2x00: rt{2500,73}usb.c fix duplicate ids based on the Ralink drivers: W = Windows_ralink_driver L = Linux_ralink_driver USB_IDs W_73 W_2500 L_73 L_2500 ============= ==== ====== ==== ====== 0x050d,0x7050 - - - YES 0x050d,0x705a - - YES - 0x1371,0x9022 - YES YES - 0x148f,0x2573 YES - YES - Signed-off-by: Xose Vazquez Perez Acked-by: Ivo van Doorn Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/rt2x00/rt2500usb.c b/drivers/net/wireless/rt2x00/rt2500usb.c index d9e6cec..eac7881 100644 --- a/drivers/net/wireless/rt2x00/rt2500usb.c +++ b/drivers/net/wireless/rt2x00/rt2500usb.c @@ -1909,13 +1909,10 @@ static struct usb_device_id rt2500usb_device_table[] = { /* Belkin */ { USB_DEVICE(0x050d, 0x7050), USB_DEVICE_DATA(&rt2500usb_ops) }, { USB_DEVICE(0x050d, 0x7051), USB_DEVICE_DATA(&rt2500usb_ops) }, - { USB_DEVICE(0x050d, 0x705a), USB_DEVICE_DATA(&rt2500usb_ops) }, /* Cisco Systems */ { USB_DEVICE(0x13b1, 0x000d), USB_DEVICE_DATA(&rt2500usb_ops) }, { USB_DEVICE(0x13b1, 0x0011), USB_DEVICE_DATA(&rt2500usb_ops) }, { USB_DEVICE(0x13b1, 0x001a), USB_DEVICE_DATA(&rt2500usb_ops) }, - /* CNet */ - { USB_DEVICE(0x1371, 0x9022), USB_DEVICE_DATA(&rt2500usb_ops) }, /* Conceptronic */ { USB_DEVICE(0x14b2, 0x3c02), USB_DEVICE_DATA(&rt2500usb_ops) }, /* D-LINK */ @@ -1938,7 +1935,6 @@ static struct usb_device_id rt2500usb_device_table[] = { /* Ralink */ { USB_DEVICE(0x148f, 0x1706), USB_DEVICE_DATA(&rt2500usb_ops) }, { USB_DEVICE(0x148f, 0x2570), USB_DEVICE_DATA(&rt2500usb_ops) }, - { USB_DEVICE(0x148f, 0x2573), USB_DEVICE_DATA(&rt2500usb_ops) }, { USB_DEVICE(0x148f, 0x9020), USB_DEVICE_DATA(&rt2500usb_ops) }, /* Sagem */ { USB_DEVICE(0x079b, 0x004b), USB_DEVICE_DATA(&rt2500usb_ops) }, diff --git a/drivers/net/wireless/rt2x00/rt73usb.c b/drivers/net/wireless/rt2x00/rt73usb.c index 149e4f9..6593059 100644 --- a/drivers/net/wireless/rt2x00/rt73usb.c +++ b/drivers/net/wireless/rt2x00/rt73usb.c @@ -2406,7 +2406,6 @@ static struct usb_device_id rt73usb_device_table[] = { { USB_DEVICE(0x0b05, 0x1723), USB_DEVICE_DATA(&rt73usb_ops) }, { USB_DEVICE(0x0b05, 0x1724), USB_DEVICE_DATA(&rt73usb_ops) }, /* Belkin */ - { USB_DEVICE(0x050d, 0x7050), USB_DEVICE_DATA(&rt73usb_ops) }, { USB_DEVICE(0x050d, 0x705a), USB_DEVICE_DATA(&rt73usb_ops) }, { USB_DEVICE(0x050d, 0x905b), USB_DEVICE_DATA(&rt73usb_ops) }, { USB_DEVICE(0x050d, 0x905c), USB_DEVICE_DATA(&rt73usb_ops) }, -- cgit v0.10.2 From 3598e1774c94e55c71b585340e7dc4538f310e3f Mon Sep 17 00:00:00 2001 From: Stanislaw Gruszka Date: Thu, 31 Mar 2011 17:36:26 +0200 Subject: iwlwifi: fix enqueue hcmd race conditions We mark command as huge by using meta->flags from other (non huge) command, but flags can be possibly overridden, when non huge command is enqueued, what can lead to: WARNING: at lib/dma-debug.c:696 dma_debug_device_change+0x1a3/0x1f0() DMA-API: device driver has pending DMA allocations while released from device [count=1] To fix introduce additional CMD_MAPPED to mark command as mapped and serialize iwl_enqueue_hcmd() with iwl_tx_cmd_complete() using hcmd_lock. Serialization will also fix possible race conditions, because q->read_ptr, q->write_ptr are modified/used in parallel. On the way fix whitespace. Signed-off-by: Stanislaw Gruszka Acked-by: Wey-Yi Guy Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index a5d438d..7465875 100644 --- a/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h @@ -309,6 +309,7 @@ enum { CMD_SIZE_HUGE = (1 << 0), CMD_ASYNC = (1 << 1), CMD_WANT_SKB = (1 << 2), + CMD_MAPPED = (1 << 3), }; #define DEF_CMD_PAYLOAD_SIZE 320 diff --git a/drivers/net/wireless/iwlwifi/iwl-tx.c b/drivers/net/wireless/iwlwifi/iwl-tx.c index 277c917..39a4180 100644 --- a/drivers/net/wireless/iwlwifi/iwl-tx.c +++ b/drivers/net/wireless/iwlwifi/iwl-tx.c @@ -149,32 +149,31 @@ void iwl_cmd_queue_unmap(struct iwl_priv *priv) struct iwl_tx_queue *txq = &priv->txq[priv->cmd_queue]; struct iwl_queue *q = &txq->q; int i; - bool huge = false; if (q->n_bd == 0) return; while (q->read_ptr != q->write_ptr) { - /* we have no way to tell if it is a huge cmd ATM */ i = get_cmd_index(q, q->read_ptr, 0); - if (txq->meta[i].flags & CMD_SIZE_HUGE) - huge = true; - else + if (txq->meta[i].flags & CMD_MAPPED) { pci_unmap_single(priv->pci_dev, dma_unmap_addr(&txq->meta[i], mapping), dma_unmap_len(&txq->meta[i], len), PCI_DMA_BIDIRECTIONAL); + txq->meta[i].flags = 0; + } - q->read_ptr = iwl_queue_inc_wrap(q->read_ptr, q->n_bd); + q->read_ptr = iwl_queue_inc_wrap(q->read_ptr, q->n_bd); } - if (huge) { - i = q->n_window; + i = q->n_window; + if (txq->meta[i].flags & CMD_MAPPED) { pci_unmap_single(priv->pci_dev, dma_unmap_addr(&txq->meta[i], mapping), dma_unmap_len(&txq->meta[i], len), PCI_DMA_BIDIRECTIONAL); + txq->meta[i].flags = 0; } } @@ -463,7 +462,11 @@ int iwl_enqueue_hcmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd) return -EIO; } + spin_lock_irqsave(&priv->hcmd_lock, flags); + if (iwl_queue_space(q) < ((cmd->flags & CMD_ASYNC) ? 2 : 1)) { + spin_unlock_irqrestore(&priv->hcmd_lock, flags); + IWL_ERR(priv, "No space in command queue\n"); if (priv->cfg->ops->lib->tt_ops.ct_kill_check) { is_ct_kill = @@ -476,22 +479,17 @@ int iwl_enqueue_hcmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd) return -ENOSPC; } - spin_lock_irqsave(&priv->hcmd_lock, flags); - - /* If this is a huge cmd, mark the huge flag also on the meta.flags - * of the _original_ cmd. This is used for DMA mapping clean up. - */ - if (cmd->flags & CMD_SIZE_HUGE) { - idx = get_cmd_index(q, q->write_ptr, 0); - txq->meta[idx].flags = CMD_SIZE_HUGE; - } - idx = get_cmd_index(q, q->write_ptr, cmd->flags & CMD_SIZE_HUGE); out_cmd = txq->cmd[idx]; out_meta = &txq->meta[idx]; + if (WARN_ON(out_meta->flags & CMD_MAPPED)) { + spin_unlock_irqrestore(&priv->hcmd_lock, flags); + return -ENOSPC; + } + memset(out_meta, 0, sizeof(*out_meta)); /* re-initialize to NULL */ - out_meta->flags = cmd->flags; + out_meta->flags = cmd->flags | CMD_MAPPED; if (cmd->flags & CMD_WANT_SKB) out_meta->source = cmd; if (cmd->flags & CMD_ASYNC) @@ -609,6 +607,10 @@ void iwl_tx_cmd_complete(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb) struct iwl_device_cmd *cmd; struct iwl_cmd_meta *meta; struct iwl_tx_queue *txq = &priv->txq[priv->cmd_queue]; + unsigned long flags; + void (*callback) (struct iwl_priv *priv, struct iwl_device_cmd *cmd, + struct iwl_rx_packet *pkt); + /* If a Tx command is being handled and it isn't in the actual * command queue then there a command routing bug has been introduced @@ -622,14 +624,8 @@ void iwl_tx_cmd_complete(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb) return; } - /* If this is a huge cmd, clear the huge flag on the meta.flags - * of the _original_ cmd. So that iwl_cmd_queue_free won't unmap - * the DMA buffer for the scan (huge) command. - */ - if (huge) { - cmd_index = get_cmd_index(&txq->q, index, 0); - txq->meta[cmd_index].flags = 0; - } + spin_lock_irqsave(&priv->hcmd_lock, flags); + cmd_index = get_cmd_index(&txq->q, index, huge); cmd = txq->cmd[cmd_index]; meta = &txq->meta[cmd_index]; @@ -639,12 +635,13 @@ void iwl_tx_cmd_complete(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb) dma_unmap_len(meta, len), PCI_DMA_BIDIRECTIONAL); + callback = NULL; /* Input error checking is done when commands are added to queue. */ if (meta->flags & CMD_WANT_SKB) { meta->source->reply_page = (unsigned long)rxb_addr(rxb); rxb->page = NULL; - } else if (meta->callback) - meta->callback(priv, cmd, pkt); + } else + callback = meta->callback; iwl_hcmd_queue_reclaim(priv, txq_id, index, cmd_index); @@ -654,5 +651,12 @@ void iwl_tx_cmd_complete(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb) get_cmd_string(cmd->hdr.cmd)); wake_up_interruptible(&priv->wait_command_queue); } + + /* Mark as unmapped */ meta->flags = 0; + + spin_unlock_irqrestore(&priv->hcmd_lock, flags); + + if (callback) + callback(priv, cmd, pkt); } -- cgit v0.10.2 From dc1a4068fce2657991c5c3b1f6849f7fc466c69f Mon Sep 17 00:00:00 2001 From: Stanislaw Gruszka Date: Thu, 31 Mar 2011 17:36:27 +0200 Subject: iwlwifi: more priv->mutex serialization Check status bits with mutex taken, because when we wait for mutex unlock, status can change. Patch should also make remaining sync commands be send with priv->mutex taken. That will prevent execute these commands when we are currently reset firmware, what could possibly cause troubles. Signed-off-by: Stanislaw Gruszka Acked-by: Wey-Yi Guy Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index 28ac0d4..70428e9 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -483,12 +483,14 @@ static void iwl_bg_bt_full_concurrency(struct work_struct *work) container_of(work, struct iwl_priv, bt_full_concurrency); struct iwl_rxon_context *ctx; + mutex_lock(&priv->mutex); + if (test_bit(STATUS_EXIT_PENDING, &priv->status)) - return; + goto out; /* dont send host command if rf-kill is on */ if (!iwl_is_ready_rf(priv)) - return; + goto out; IWL_DEBUG_INFO(priv, "BT coex in %s mode\n", priv->bt_full_concurrent ? @@ -498,15 +500,15 @@ static void iwl_bg_bt_full_concurrency(struct work_struct *work) * LQ & RXON updated cmds must be sent before BT Config cmd * to avoid 3-wire collisions */ - mutex_lock(&priv->mutex); for_each_context(priv, ctx) { if (priv->cfg->ops->hcmd->set_rxon_chain) priv->cfg->ops->hcmd->set_rxon_chain(priv, ctx); iwlcore_commit_rxon(priv, ctx); } - mutex_unlock(&priv->mutex); priv->cfg->ops->hcmd->send_bt_config(priv); +out: + mutex_unlock(&priv->mutex); } /** @@ -2620,10 +2622,13 @@ static void iwl_bg_init_alive_start(struct work_struct *data) struct iwl_priv *priv = container_of(data, struct iwl_priv, init_alive_start.work); - if (test_bit(STATUS_EXIT_PENDING, &priv->status)) + mutex_lock(&priv->mutex); + + if (test_bit(STATUS_EXIT_PENDING, &priv->status)) { + mutex_unlock(&priv->mutex); return; + } - mutex_lock(&priv->mutex); priv->cfg->ops->lib->init_alive_start(priv); mutex_unlock(&priv->mutex); } @@ -2633,15 +2638,16 @@ static void iwl_bg_alive_start(struct work_struct *data) struct iwl_priv *priv = container_of(data, struct iwl_priv, alive_start.work); + mutex_lock(&priv->mutex); if (test_bit(STATUS_EXIT_PENDING, &priv->status)) - return; + goto unlock; /* enable dram interrupt */ if (priv->cfg->ops->lib->isr_ops.reset) priv->cfg->ops->lib->isr_ops.reset(priv); - mutex_lock(&priv->mutex); iwl_alive_start(priv); +unlock: mutex_unlock(&priv->mutex); } @@ -3267,21 +3273,22 @@ void iwlagn_mac_channel_switch(struct ieee80211_hw *hw, IWL_DEBUG_MAC80211(priv, "enter\n"); + mutex_lock(&priv->mutex); + if (iwl_is_rfkill(priv)) - goto out_exit; + goto out; if (test_bit(STATUS_EXIT_PENDING, &priv->status) || test_bit(STATUS_SCANNING, &priv->status)) - goto out_exit; + goto out; if (!iwl_is_associated_ctx(ctx)) - goto out_exit; + goto out; /* channel switch in progress */ if (priv->switch_rxon.switch_in_progress == true) - goto out_exit; + goto out; - mutex_lock(&priv->mutex); if (priv->cfg->ops->lib->set_channel_switch) { ch = channel->hw_value; @@ -3337,7 +3344,6 @@ void iwlagn_mac_channel_switch(struct ieee80211_hw *hw, } out: mutex_unlock(&priv->mutex); -out_exit: if (!priv->switch_rxon.switch_in_progress) ieee80211_chswitch_done(ctx->vif, false); IWL_DEBUG_MAC80211(priv, "leave\n"); -- cgit v0.10.2 From 8447c163afeaa7e9f6f015088177b1c8511e0877 Mon Sep 17 00:00:00 2001 From: Stanislaw Gruszka Date: Thu, 31 Mar 2011 17:36:28 +0200 Subject: iwlwifi: remove sync_cmd_mutex We now use priv->mutex to serialize sync command, remove old priv->sync_cmd_mutex and add assertion that priv->mutex must be locked. Signed-off-by: Stanislaw Gruszka Acked-by: Wey-Yi Guy Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index 70428e9..42fad62 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -2371,9 +2371,6 @@ static void __iwl_down(struct iwl_priv *priv) priv->bt_full_concurrent = false; priv->bt_ci_compliance = 0; - /* Unblock any waiting calls */ - wake_up_interruptible_all(&priv->wait_command_queue); - /* Wipe out the EXIT_PENDING status bit if we are not actually * exiting the module */ if (!exit_pending) @@ -3620,7 +3617,6 @@ static int iwl_init_drv(struct iwl_priv *priv) INIT_LIST_HEAD(&priv->free_frames); mutex_init(&priv->mutex); - mutex_init(&priv->sync_cmd_mutex); priv->ieee_channels = NULL; priv->ieee_rates = NULL; diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index 7465875..1c9d2dd 100644 --- a/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h @@ -1307,7 +1307,6 @@ struct iwl_priv { spinlock_t hcmd_lock; /* protect hcmd */ spinlock_t reg_lock; /* protect hw register access */ struct mutex mutex; - struct mutex sync_cmd_mutex; /* enable serialization of sync commands */ /* basic pci-network driver stuff */ struct pci_dev *pci_dev; diff --git a/drivers/net/wireless/iwlwifi/iwl-hcmd.c b/drivers/net/wireless/iwlwifi/iwl-hcmd.c index 02499f6..c71c0a4 100644 --- a/drivers/net/wireless/iwlwifi/iwl-hcmd.c +++ b/drivers/net/wireless/iwlwifi/iwl-hcmd.c @@ -171,14 +171,13 @@ int iwl_send_cmd_sync(struct iwl_priv *priv, struct iwl_host_cmd *cmd) int cmd_idx; int ret; - BUG_ON(cmd->flags & CMD_ASYNC); + lockdep_assert_held(&priv->mutex); /* A synchronous command can not have a callback set. */ - BUG_ON(cmd->callback); + BUG_ON((cmd->flags & CMD_ASYNC) || cmd->callback); IWL_DEBUG_INFO(priv, "Attempting to send sync command %s\n", get_cmd_string(cmd->id)); - mutex_lock(&priv->sync_cmd_mutex); set_bit(STATUS_HCMD_ACTIVE, &priv->status); IWL_DEBUG_INFO(priv, "Setting HCMD_ACTIVE for command %s\n", @@ -189,7 +188,7 @@ int iwl_send_cmd_sync(struct iwl_priv *priv, struct iwl_host_cmd *cmd) ret = cmd_idx; IWL_ERR(priv, "Error sending %s: enqueue_hcmd failed: %d\n", get_cmd_string(cmd->id), ret); - goto out; + return ret; } ret = wait_event_interruptible_timeout(priv->wait_command_queue, @@ -229,8 +228,7 @@ int iwl_send_cmd_sync(struct iwl_priv *priv, struct iwl_host_cmd *cmd) goto cancel; } - ret = 0; - goto out; + return 0; cancel: if (cmd->flags & CMD_WANT_SKB) { @@ -248,8 +246,7 @@ fail: iwl_free_pages(priv, cmd->reply_page); cmd->reply_page = 0; } -out: - mutex_unlock(&priv->sync_cmd_mutex); + return ret; } -- cgit v0.10.2 From f4263c9857e6411ef2388868cc6c79a1602a654e Mon Sep 17 00:00:00 2001 From: Paul Stewart Date: Thu, 31 Mar 2011 09:25:41 -0700 Subject: nl80211: Add BSS parameters to station This allows user-space monitoring of BSS parameters for the associated station. This is useful for debugging and verifying that the paramaters are as expected. [Exactly the same as before but bundled into a single message] Signed-off-by: Paul Stewart Cc: Johannes Berg Signed-off-by: John W. Linville diff --git a/include/linux/nl80211.h b/include/linux/nl80211.h index 3002218..16eea72 100644 --- a/include/linux/nl80211.h +++ b/include/linux/nl80211.h @@ -1222,6 +1222,36 @@ enum nl80211_rate_info { }; /** + * enum nl80211_sta_bss_param - BSS information collected by STA + * + * These attribute types are used with %NL80211_STA_INFO_BSS_PARAM + * when getting information about the bitrate of a station. + * + * @__NL80211_STA_BSS_PARAM_INVALID: attribute number 0 is reserved + * @NL80211_STA_BSS_PARAM_CTS_PROT: whether CTS protection is enabled (flag) + * @NL80211_STA_BSS_PARAM_SHORT_PREAMBLE: whether short preamble is enabled + * (flag) + * @NL80211_STA_BSS_PARAM_SHORT_SLOT_TIME: whether short slot time is enabled + * (flag) + * @NL80211_STA_BSS_PARAM_DTIM_PERIOD: DTIM period for beaconing (u8) + * @NL80211_STA_BSS_PARAM_BEACON_INTERVAL: Beacon interval (u16) + * @NL80211_STA_BSS_PARAM_MAX: highest sta_bss_param number currently defined + * @__NL80211_STA_BSS_PARAM_AFTER_LAST: internal use + */ +enum nl80211_sta_bss_param { + __NL80211_STA_BSS_PARAM_INVALID, + NL80211_STA_BSS_PARAM_CTS_PROT, + NL80211_STA_BSS_PARAM_SHORT_PREAMBLE, + NL80211_STA_BSS_PARAM_SHORT_SLOT_TIME, + NL80211_STA_BSS_PARAM_DTIM_PERIOD, + NL80211_STA_BSS_PARAM_BEACON_INTERVAL, + + /* keep last */ + __NL80211_STA_BSS_PARAM_AFTER_LAST, + NL80211_STA_BSS_PARAM_MAX = __NL80211_STA_BSS_PARAM_AFTER_LAST - 1 +}; + +/** * enum nl80211_sta_info - station information * * These attribute types are used with %NL80211_ATTR_STA_INFO @@ -1233,7 +1263,7 @@ enum nl80211_rate_info { * @NL80211_STA_INFO_TX_BYTES: total transmitted bytes (u32, to this station) * @NL80211_STA_INFO_SIGNAL: signal strength of last received PPDU (u8, dBm) * @NL80211_STA_INFO_TX_BITRATE: current unicast tx rate, nested attribute - * containing info as possible, see &enum nl80211_sta_info_txrate. + * containing info as possible, see &enum nl80211_rate_info * @NL80211_STA_INFO_RX_PACKETS: total received packet (u32, from this station) * @NL80211_STA_INFO_TX_PACKETS: total transmitted packets (u32, to this * station) @@ -1245,6 +1275,8 @@ enum nl80211_rate_info { * @NL80211_STA_INFO_PLINK_STATE: peer link state for the station * @NL80211_STA_INFO_RX_BITRATE: last unicast data frame rx rate, nested * attribute, like NL80211_STA_INFO_TX_BITRATE. + * @NL80211_STA_INFO_BSS_PARAM: current station's view of BSS, nested attribute + * containing info as possible, see &enum nl80211_sta_bss_param * @__NL80211_STA_INFO_AFTER_LAST: internal * @NL80211_STA_INFO_MAX: highest possible station info attribute */ @@ -1264,6 +1296,7 @@ enum nl80211_sta_info { NL80211_STA_INFO_TX_FAILED, NL80211_STA_INFO_SIGNAL_AVG, NL80211_STA_INFO_RX_BITRATE, + NL80211_STA_INFO_BSS_PARAM, /* keep last */ __NL80211_STA_INFO_AFTER_LAST, diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index 2c45304..ba7384a 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -422,6 +422,7 @@ struct station_parameters { * @STATION_INFO_RX_DROP_MISC: @rx_dropped_misc filled * @STATION_INFO_SIGNAL_AVG: @signal_avg filled * @STATION_INFO_RX_BITRATE: @rxrate fields are filled + * @STATION_INFO_BSS_PARAM: @bss_param filled */ enum station_info_flags { STATION_INFO_INACTIVE_TIME = 1<<0, @@ -439,6 +440,7 @@ enum station_info_flags { STATION_INFO_RX_DROP_MISC = 1<<12, STATION_INFO_SIGNAL_AVG = 1<<13, STATION_INFO_RX_BITRATE = 1<<14, + STATION_INFO_BSS_PARAM = 1<<15, }; /** @@ -473,6 +475,37 @@ struct rate_info { }; /** + * enum station_info_rate_flags - bitrate info flags + * + * Used by the driver to indicate the specific rate transmission + * type for 802.11n transmissions. + * + * @BSS_PARAM_FLAGS_CTS_PROT: whether CTS protection is enabled + * @BSS_PARAM_FLAGS_SHORT_PREAMBLE: whether short preamble is enabled + * @BSS_PARAM_FLAGS_SHORT_SLOT_TIME: whether short slot time is enabled + */ +enum bss_param_flags { + BSS_PARAM_FLAGS_CTS_PROT = 1<<0, + BSS_PARAM_FLAGS_SHORT_PREAMBLE = 1<<1, + BSS_PARAM_FLAGS_SHORT_SLOT_TIME = 1<<2, +}; + +/** + * struct sta_bss_parameters - BSS parameters for the attached station + * + * Information about the currently associated BSS + * + * @flags: bitflag of flags from &enum bss_param_flags + * @dtim_period: DTIM period for the BSS + * @beacon_interval: beacon interval + */ +struct sta_bss_parameters { + u8 flags; + u8 dtim_period; + u16 beacon_interval; +}; + +/** * struct station_info - station information * * Station information filled by driver for get_station() and dump_station. @@ -515,6 +548,7 @@ struct station_info { u32 tx_retries; u32 tx_failed; u32 rx_dropped_misc; + struct sta_bss_parameters bss_param; int generation; }; diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index 3342135..bf5d28d 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -342,7 +342,8 @@ static void sta_set_sinfo(struct sta_info *sta, struct station_info *sinfo) STATION_INFO_TX_FAILED | STATION_INFO_TX_BITRATE | STATION_INFO_RX_BITRATE | - STATION_INFO_RX_DROP_MISC; + STATION_INFO_RX_DROP_MISC | + STATION_INFO_BSS_PARAM; sinfo->inactive_time = jiffies_to_msecs(jiffies - sta->last_rx); sinfo->rx_bytes = sta->rx_bytes; @@ -389,6 +390,16 @@ static void sta_set_sinfo(struct sta_info *sta, struct station_info *sinfo) sinfo->plink_state = sta->plink_state; #endif } + + sinfo->bss_param.flags = 0; + if (sdata->vif.bss_conf.use_cts_prot) + sinfo->bss_param.flags |= BSS_PARAM_FLAGS_CTS_PROT; + if (sdata->vif.bss_conf.use_short_preamble) + sinfo->bss_param.flags |= BSS_PARAM_FLAGS_SHORT_PREAMBLE; + if (sdata->vif.bss_conf.use_short_slot) + sinfo->bss_param.flags |= BSS_PARAM_FLAGS_SHORT_SLOT_TIME; + sinfo->bss_param.dtim_period = sdata->local->hw.conf.ps_dtim_period; + sinfo->bss_param.beacon_interval = sdata->vif.bss_conf.beacon_int; } diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 40c90fb..297d7ce 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -2002,7 +2002,7 @@ static int nl80211_send_station(struct sk_buff *msg, u32 pid, u32 seq, const u8 *mac_addr, struct station_info *sinfo) { void *hdr; - struct nlattr *sinfoattr; + struct nlattr *sinfoattr, *bss_param; hdr = nl80211hdr_put(msg, pid, seq, flags, NL80211_CMD_NEW_STATION); if (!hdr) @@ -2062,6 +2062,25 @@ static int nl80211_send_station(struct sk_buff *msg, u32 pid, u32 seq, if (sinfo->filled & STATION_INFO_TX_FAILED) NLA_PUT_U32(msg, NL80211_STA_INFO_TX_FAILED, sinfo->tx_failed); + if (sinfo->filled & STATION_INFO_BSS_PARAM) { + bss_param = nla_nest_start(msg, NL80211_STA_INFO_BSS_PARAM); + if (!bss_param) + goto nla_put_failure; + + if (sinfo->bss_param.flags & BSS_PARAM_FLAGS_CTS_PROT) + NLA_PUT_FLAG(msg, NL80211_STA_BSS_PARAM_CTS_PROT); + if (sinfo->bss_param.flags & BSS_PARAM_FLAGS_SHORT_PREAMBLE) + NLA_PUT_FLAG(msg, NL80211_STA_BSS_PARAM_SHORT_PREAMBLE); + if (sinfo->bss_param.flags & BSS_PARAM_FLAGS_SHORT_SLOT_TIME) + NLA_PUT_FLAG(msg, + NL80211_STA_BSS_PARAM_SHORT_SLOT_TIME); + NLA_PUT_U8(msg, NL80211_STA_BSS_PARAM_DTIM_PERIOD, + sinfo->bss_param.dtim_period); + NLA_PUT_U16(msg, NL80211_STA_BSS_PARAM_BEACON_INTERVAL, + sinfo->bss_param.beacon_interval); + + nla_nest_end(msg, bss_param); + } nla_nest_end(msg, sinfoattr); return genlmsg_end(msg, hdr); -- cgit v0.10.2 From 2d3d0a88bd136f8e6f39bc53242712852e5d0bb2 Mon Sep 17 00:00:00 2001 From: Amitkumar Karwar Date: Fri, 1 Apr 2011 18:36:46 -0700 Subject: mwifiex: return success in set_default_key for WPA/WPA2 When testing wpa_supplicant with 'nl80211' driver to connect to an AP with WPA/WPA2 security, we notice the followings: 1) add_key is called firstly with the key from cfg80211 2) set_defaut_key is called next set_default_key() is specific to WEP keys and should not be called in case of WPA/WPA2 security. The set_default_key() won't be called if wpa_supplicant uses "-Dwext" option, but it's been called if "-Dnl80211" option is specified. We can fix this issue by adding a check to return from set_default_key() if WEP key is not configured. Signed-off-by: Amitkumar Karwar Signed-off-by: Yogesh Ashok Powar Signed-off-by: Marc Yang Signed-off-by: Bing Zhao Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/mwifiex/cfg80211.c b/drivers/net/wireless/mwifiex/cfg80211.c index 2d96800..4ac4f5a 100644 --- a/drivers/net/wireless/mwifiex/cfg80211.c +++ b/drivers/net/wireless/mwifiex/cfg80211.c @@ -228,6 +228,10 @@ mwifiex_cfg80211_set_default_key(struct wiphy *wiphy, struct net_device *netdev, struct mwifiex_private *priv = mwifiex_cfg80211_get_priv(wiphy); int ret; + /* Return if WEP key not configured */ + if (priv->sec_info.wep_status == MWIFIEX_802_11_WEP_DISABLED) + return 0; + ret = mwifiex_set_encode(priv, NULL, 0, key_index, 0); wiphy_dbg(wiphy, "info: set default Tx key index\n"); -- cgit v0.10.2 From 2be50b8df53f2f329b7ddcc8be286ef6a7469fd2 Mon Sep 17 00:00:00 2001 From: Yogesh Ashok Powar Date: Fri, 1 Apr 2011 18:36:47 -0700 Subject: mwifiex: remove redundant encryption_mode mapping remove MWIFIEX_ENCRYPTION_MODE_ and use WLAN_CIPHER_SUITE_ macros directly Signed-off-by: Yogesh Ashok Powar Signed-off-by: Bing Zhao Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/mwifiex/cfg80211.c b/drivers/net/wireless/mwifiex/cfg80211.c index 4ac4f5a..ec0895f 100644 --- a/drivers/net/wireless/mwifiex/cfg80211.c +++ b/drivers/net/wireless/mwifiex/cfg80211.c @@ -90,8 +90,8 @@ mwifiex_is_alg_wep(u32 cipher) int alg = 0; switch (cipher) { - case MWIFIEX_ENCRYPTION_MODE_WEP40: - case MWIFIEX_ENCRYPTION_MODE_WEP104: + case WLAN_CIPHER_SUITE_WEP40: + case WLAN_CIPHER_SUITE_WEP104: alg = 1; break; default: @@ -102,55 +102,6 @@ mwifiex_is_alg_wep(u32 cipher) } /* - * This function maps the given cipher type into driver specific type. - * - * It also sets a flag to indicate whether WPA is enabled or not. - * - * The mapping table is - - * Input cipher Driver cipher type WPA enabled? - * ------------ ------------------ ------------ - * IW_AUTH_CIPHER_NONE MWIFIEX_ENCRYPTION_MODE_NONE No - * WLAN_CIPHER_SUITE_WEP40 MWIFIEX_ENCRYPTION_MODE_WEP40 No - * WLAN_CIPHER_SUITE_WEP104 MWIFIEX_ENCRYPTION_MODE_WEP104 No - * WLAN_CIPHER_SUITE_TKIP MWIFIEX_ENCRYPTION_MODE_TKIP Yes - * WLAN_CIPHER_SUITE_CCMP MWIFIEX_ENCRYPTION_MODE_CCMP Yes - * Others -1 No - */ -static int -mwifiex_get_mwifiex_cipher(u32 cipher, int *wpa_enabled) -{ - int encrypt_mode; - - if (wpa_enabled) - *wpa_enabled = 0; - switch (cipher) { - case IW_AUTH_CIPHER_NONE: - encrypt_mode = MWIFIEX_ENCRYPTION_MODE_NONE; - break; - case WLAN_CIPHER_SUITE_WEP40: - encrypt_mode = MWIFIEX_ENCRYPTION_MODE_WEP40; - break; - case WLAN_CIPHER_SUITE_WEP104: - encrypt_mode = MWIFIEX_ENCRYPTION_MODE_WEP104; - break; - case WLAN_CIPHER_SUITE_TKIP: - encrypt_mode = MWIFIEX_ENCRYPTION_MODE_TKIP; - if (wpa_enabled) - *wpa_enabled = 1; - break; - case WLAN_CIPHER_SUITE_CCMP: - encrypt_mode = MWIFIEX_ENCRYPTION_MODE_CCMP; - if (wpa_enabled) - *wpa_enabled = 1; - break; - default: - encrypt_mode = -1; - } - - return encrypt_mode; -} - -/* * This function retrieves the private structure from kernel wiphy structure. */ static void *mwifiex_cfg80211_get_priv(struct wiphy *wiphy) @@ -252,13 +203,9 @@ mwifiex_cfg80211_add_key(struct wiphy *wiphy, struct net_device *netdev, { struct mwifiex_private *priv = mwifiex_cfg80211_get_priv(wiphy); int ret = 0; - int encrypt_mode; - - encrypt_mode = mwifiex_get_mwifiex_cipher(params->cipher, NULL); - if (encrypt_mode != -1) - ret = mwifiex_set_encode(priv, params->key, params->key_len, - key_index, 0); + ret = mwifiex_set_encode(priv, params->key, params->key_len, + key_index, 0); wiphy_dbg(wiphy, "info: crypto keys added\n"); @@ -1019,7 +966,7 @@ mwifiex_cfg80211_assoc(struct mwifiex_private *priv, size_t ssid_len, u8 *ssid, struct mwifiex_802_11_ssid req_ssid; struct mwifiex_ssid_bssid ssid_bssid; int ret = 0; - int auth_type = 0, pairwise_encrypt_mode = 0, wpa_enabled = 0; + int auth_type = 0, pairwise_encrypt_mode = 0; int group_encrypt_mode = 0; int alg_is_wep = 0; @@ -1052,13 +999,13 @@ mwifiex_cfg80211_assoc(struct mwifiex_private *priv, size_t ssid_len, u8 *ssid, /* "privacy" is set only for ad-hoc mode */ if (privacy) { /* - * Keep MWIFIEX_ENCRYPTION_MODE_WEP104 for now so that + * Keep WLAN_CIPHER_SUITE_WEP104 for now so that * the firmware can find a matching network from the * scan. The cfg80211 does not give us the encryption * mode at this stage so just setting it to WEP here. */ priv->sec_info.encryption_mode = - MWIFIEX_ENCRYPTION_MODE_WEP104; + WLAN_CIPHER_SUITE_WEP104; priv->sec_info.authentication_mode = NL80211_AUTHTYPE_OPEN_SYSTEM; } @@ -1074,16 +1021,13 @@ mwifiex_cfg80211_assoc(struct mwifiex_private *priv, size_t ssid_len, u8 *ssid, auth_type = NL80211_AUTHTYPE_SHARED_KEY; if (sme->crypto.n_ciphers_pairwise) { - pairwise_encrypt_mode = mwifiex_get_mwifiex_cipher(sme->crypto. - ciphers_pairwise[0], &wpa_enabled); - priv->sec_info.encryption_mode = pairwise_encrypt_mode; + priv->sec_info.encryption_mode = + sme->crypto.ciphers_pairwise[0]; priv->sec_info.authentication_mode = auth_type; } if (sme->crypto.cipher_group) { - group_encrypt_mode = mwifiex_get_mwifiex_cipher(sme->crypto. - cipher_group, &wpa_enabled); - priv->sec_info.encryption_mode = group_encrypt_mode; + priv->sec_info.encryption_mode = sme->crypto.cipher_group; priv->sec_info.authentication_mode = auth_type; } if (sme->ie) diff --git a/drivers/net/wireless/mwifiex/init.c b/drivers/net/wireless/mwifiex/init.c index 43ea87d..8189862 100644 --- a/drivers/net/wireless/mwifiex/init.c +++ b/drivers/net/wireless/mwifiex/init.c @@ -86,7 +86,7 @@ static int mwifiex_init_priv(struct mwifiex_private *priv) priv->sec_info.wep_status = MWIFIEX_802_11_WEP_DISABLED; priv->sec_info.authentication_mode = NL80211_AUTHTYPE_OPEN_SYSTEM; - priv->sec_info.encryption_mode = MWIFIEX_ENCRYPTION_MODE_NONE; + priv->sec_info.encryption_mode = 0; for (i = 0; i < ARRAY_SIZE(priv->wep_key); i++) memset(&priv->wep_key[i], 0, sizeof(struct mwifiex_wep_key)); priv->wep_key_curr_index = 0; diff --git a/drivers/net/wireless/mwifiex/ioctl.h b/drivers/net/wireless/mwifiex/ioctl.h index d01160a..703a6d1 100644 --- a/drivers/net/wireless/mwifiex/ioctl.h +++ b/drivers/net/wireless/mwifiex/ioctl.h @@ -267,14 +267,6 @@ struct mwifiex_debug_info { u8 event_received; }; -enum { - MWIFIEX_ENCRYPTION_MODE_NONE = 0, - MWIFIEX_ENCRYPTION_MODE_WEP40 = 1, - MWIFIEX_ENCRYPTION_MODE_TKIP = 2, - MWIFIEX_ENCRYPTION_MODE_CCMP = 3, - MWIFIEX_ENCRYPTION_MODE_WEP104 = 4, -}; - #define MWIFIEX_KEY_INDEX_UNICAST 0x40000000 #define MWIFIEX_MAX_KEY_LENGTH 32 #define WAPI_RXPN_LEN 16 diff --git a/drivers/net/wireless/mwifiex/join.c b/drivers/net/wireless/mwifiex/join.c index 8a1eb2a..7a9e0b5 100644 --- a/drivers/net/wireless/mwifiex/join.c +++ b/drivers/net/wireless/mwifiex/join.c @@ -869,7 +869,7 @@ mwifiex_cmd_802_11_ad_hoc_start(struct mwifiex_private *priv, tmp_cap |= WLAN_CAPABILITY_IBSS; /* Set up privacy in bss_desc */ - if (priv->sec_info.encryption_mode != MWIFIEX_ENCRYPTION_MODE_NONE) { + if (priv->sec_info.encryption_mode) { /* Ad-Hoc capability privacy on */ dev_dbg(adapter->dev, "info: ADHOC_S_CMD: wep_status set privacy to WEP\n"); diff --git a/drivers/net/wireless/mwifiex/scan.c b/drivers/net/wireless/mwifiex/scan.c index 64ed60a..6bb52d0 100644 --- a/drivers/net/wireless/mwifiex/scan.c +++ b/drivers/net/wireless/mwifiex/scan.c @@ -273,8 +273,8 @@ mwifiex_is_network_compatible_for_no_sec(struct mwifiex_private *priv, && ((!bss_desc->bcn_rsn_ie) || ((*(bss_desc->bcn_rsn_ie)).ieee_hdr.element_id != WLAN_EID_RSN)) - && priv->sec_info.encryption_mode == - MWIFIEX_ENCRYPTION_MODE_NONE && !bss_desc->privacy) { + && !priv->sec_info.encryption_mode + && !bss_desc->privacy) { return true; } return false; @@ -386,8 +386,8 @@ mwifiex_is_network_compatible_for_adhoc_aes(struct mwifiex_private *priv, element_id != WLAN_EID_WPA)) && ((!bss_desc->bcn_rsn_ie) || ((*(bss_desc->bcn_rsn_ie)).ieee_hdr. element_id != WLAN_EID_RSN)) - && priv->sec_info.encryption_mode == - MWIFIEX_ENCRYPTION_MODE_NONE && bss_desc->privacy) { + && !priv->sec_info.encryption_mode + && bss_desc->privacy) { return true; } return false; @@ -408,8 +408,8 @@ mwifiex_is_network_compatible_for_dynamic_wep(struct mwifiex_private *priv, element_id != WLAN_EID_WPA)) && ((!bss_desc->bcn_rsn_ie) || ((*(bss_desc->bcn_rsn_ie)).ieee_hdr. element_id != WLAN_EID_RSN)) - && priv->sec_info.encryption_mode != - MWIFIEX_ENCRYPTION_MODE_NONE && bss_desc->privacy) { + && priv->sec_info.encryption_mode + && bss_desc->privacy) { dev_dbg(priv->adapter->dev, "info: %s: dynamic " "WEP: index=%d wpa_ie=%#x wpa2_ie=%#x " "EncMode=%#x privacy=%#x\n", diff --git a/drivers/net/wireless/mwifiex/sta_event.c b/drivers/net/wireless/mwifiex/sta_event.c index 0187185..936d7c1 100644 --- a/drivers/net/wireless/mwifiex/sta_event.c +++ b/drivers/net/wireless/mwifiex/sta_event.c @@ -76,7 +76,7 @@ mwifiex_reset_connect_state(struct mwifiex_private *priv) priv->wapi_ie_len = 0; priv->sec_info.wapi_key_on = false; - priv->sec_info.encryption_mode = MWIFIEX_ENCRYPTION_MODE_NONE; + priv->sec_info.encryption_mode = 0; /* Enable auto data rate */ priv->is_data_rate_auto = true; -- cgit v0.10.2 From 5e65968a10bb628b87024161c9adc8dbd886b47a Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Sat, 2 Apr 2011 03:39:47 +0200 Subject: ath9k: fix beacon slot processing in ad-hoc mode The recent cleanups in the beacon code fixed SWBA backoff calculation, however it did not remove a line of code that worked around the issues from the earlier version of the code. After the cleanup, the initial TSF based slot calculation now always returns 0 instead of ATH_BCBUF-1, so the previous hack that reversed the slot order needs to be removed, as ad-hoc mode does not use staggered beacons. Signed-off-by: Felix Fietkau Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/beacon.c b/drivers/net/wireless/ath/ath9k/beacon.c index 74f33bc..24861b2 100644 --- a/drivers/net/wireless/ath/ath9k/beacon.c +++ b/drivers/net/wireless/ath/ath9k/beacon.c @@ -392,14 +392,6 @@ void ath_beacon_tasklet(unsigned long data) tsf += TU_TO_USEC(ah->config.sw_beacon_response_time); tsftu = TSF_TO_TU((tsf * ATH_BCBUF) >>32, tsf * ATH_BCBUF); slot = (tsftu % (intval * ATH_BCBUF)) / intval; - /* - * Reverse the slot order to get slot 0 on the TBTT offset that does - * not require TSF adjustment and other slots adding - * slot/ATH_BCBUF * beacon_int to timestamp. For example, with - * ATH_BCBUF = 4, we process beacon slots as follows: 3 2 1 0 3 2 1 .. - * and slot 0 is at correct offset to TBTT. - */ - slot = ATH_BCBUF - slot - 1; vif = sc->beacon.bslot[slot]; ath_dbg(common, ATH_DBG_BEACON, -- cgit v0.10.2 From 26cd322bacd3d65fffef6f8418c2fdad5b42e4b5 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Sat, 2 Apr 2011 03:39:48 +0200 Subject: ath9k: use the hw opmode to select the beacon timer mode Since the beacon timers are global, the individual vif type should not be used to determine the beacon timer configuration mode, use the global opmode instead. Signed-off-by: Felix Fietkau Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/beacon.c b/drivers/net/wireless/ath/ath9k/beacon.c index 24861b2..f688527 100644 --- a/drivers/net/wireless/ath/ath9k/beacon.c +++ b/drivers/net/wireless/ath/ath9k/beacon.c @@ -700,7 +700,7 @@ void ath_beacon_config(struct ath_softc *sc, struct ieee80211_vif *vif) if (cur_conf->dtim_period == 0) cur_conf->dtim_period = 1; - switch (iftype) { + switch (sc->sc_ah->opmode) { case NL80211_IFTYPE_AP: ath_beacon_config_ap(sc, cur_conf); break; -- cgit v0.10.2 From fbd5d17b8e2b418b495599c554f9c4754b7f93c9 Mon Sep 17 00:00:00 2001 From: Jussi Kivilinna Date: Sat, 2 Apr 2011 11:25:54 +0300 Subject: zd1211rw: rename CR* macros to ZD_CR* With compat-wireless CR* macros in zd_usb.h conflict with CR macros in include/asm-generic/termbits.h. So rename CR* macros to ZD_CR*. Conversion was done with using sed and then 'over 80 character line' checkpatch.pl warnings and comment indents were fixed. Reported-by: Walter Goldens Signed-off-by: Jussi Kivilinna Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/zd1211rw/zd_chip.c b/drivers/net/wireless/zd1211rw/zd_chip.c index a73a305..ff306d7 100644 --- a/drivers/net/wireless/zd1211rw/zd_chip.c +++ b/drivers/net/wireless/zd1211rw/zd_chip.c @@ -557,7 +557,7 @@ int zd_chip_unlock_phy_regs(struct zd_chip *chip) return r; } -/* CR157 can be optionally patched by the EEPROM for original ZD1211 */ +/* ZD_CR157 can be optionally patched by the EEPROM for original ZD1211 */ static int patch_cr157(struct zd_chip *chip) { int r; @@ -571,7 +571,7 @@ static int patch_cr157(struct zd_chip *chip) return r; dev_dbg_f(zd_chip_dev(chip), "patching value %x\n", value >> 8); - return zd_iowrite32_locked(chip, value >> 8, CR157); + return zd_iowrite32_locked(chip, value >> 8, ZD_CR157); } /* @@ -593,8 +593,8 @@ static int patch_6m_band_edge(struct zd_chip *chip, u8 channel) int zd_chip_generic_patch_6m_band(struct zd_chip *chip, int channel) { struct zd_ioreq16 ioreqs[] = { - { CR128, 0x14 }, { CR129, 0x12 }, { CR130, 0x10 }, - { CR47, 0x1e }, + { ZD_CR128, 0x14 }, { ZD_CR129, 0x12 }, { ZD_CR130, 0x10 }, + { ZD_CR47, 0x1e }, }; /* FIXME: Channel 11 is not the edge for all regulatory domains. */ @@ -608,69 +608,69 @@ int zd_chip_generic_patch_6m_band(struct zd_chip *chip, int channel) static int zd1211_hw_reset_phy(struct zd_chip *chip) { static const struct zd_ioreq16 ioreqs[] = { - { CR0, 0x0a }, { CR1, 0x06 }, { CR2, 0x26 }, - { CR3, 0x38 }, { CR4, 0x80 }, { CR9, 0xa0 }, - { CR10, 0x81 }, { CR11, 0x00 }, { CR12, 0x7f }, - { CR13, 0x8c }, { CR14, 0x80 }, { CR15, 0x3d }, - { CR16, 0x20 }, { CR17, 0x1e }, { CR18, 0x0a }, - { CR19, 0x48 }, { CR20, 0x0c }, { CR21, 0x0c }, - { CR22, 0x23 }, { CR23, 0x90 }, { CR24, 0x14 }, - { CR25, 0x40 }, { CR26, 0x10 }, { CR27, 0x19 }, - { CR28, 0x7f }, { CR29, 0x80 }, { CR30, 0x4b }, - { CR31, 0x60 }, { CR32, 0x43 }, { CR33, 0x08 }, - { CR34, 0x06 }, { CR35, 0x0a }, { CR36, 0x00 }, - { CR37, 0x00 }, { CR38, 0x38 }, { CR39, 0x0c }, - { CR40, 0x84 }, { CR41, 0x2a }, { CR42, 0x80 }, - { CR43, 0x10 }, { CR44, 0x12 }, { CR46, 0xff }, - { CR47, 0x1E }, { CR48, 0x26 }, { CR49, 0x5b }, - { CR64, 0xd0 }, { CR65, 0x04 }, { CR66, 0x58 }, - { CR67, 0xc9 }, { CR68, 0x88 }, { CR69, 0x41 }, - { CR70, 0x23 }, { CR71, 0x10 }, { CR72, 0xff }, - { CR73, 0x32 }, { CR74, 0x30 }, { CR75, 0x65 }, - { CR76, 0x41 }, { CR77, 0x1b }, { CR78, 0x30 }, - { CR79, 0x68 }, { CR80, 0x64 }, { CR81, 0x64 }, - { CR82, 0x00 }, { CR83, 0x00 }, { CR84, 0x00 }, - { CR85, 0x02 }, { CR86, 0x00 }, { CR87, 0x00 }, - { CR88, 0xff }, { CR89, 0xfc }, { CR90, 0x00 }, - { CR91, 0x00 }, { CR92, 0x00 }, { CR93, 0x08 }, - { CR94, 0x00 }, { CR95, 0x00 }, { CR96, 0xff }, - { CR97, 0xe7 }, { CR98, 0x00 }, { CR99, 0x00 }, - { CR100, 0x00 }, { CR101, 0xae }, { CR102, 0x02 }, - { CR103, 0x00 }, { CR104, 0x03 }, { CR105, 0x65 }, - { CR106, 0x04 }, { CR107, 0x00 }, { CR108, 0x0a }, - { CR109, 0xaa }, { CR110, 0xaa }, { CR111, 0x25 }, - { CR112, 0x25 }, { CR113, 0x00 }, { CR119, 0x1e }, - { CR125, 0x90 }, { CR126, 0x00 }, { CR127, 0x00 }, + { ZD_CR0, 0x0a }, { ZD_CR1, 0x06 }, { ZD_CR2, 0x26 }, + { ZD_CR3, 0x38 }, { ZD_CR4, 0x80 }, { ZD_CR9, 0xa0 }, + { ZD_CR10, 0x81 }, { ZD_CR11, 0x00 }, { ZD_CR12, 0x7f }, + { ZD_CR13, 0x8c }, { ZD_CR14, 0x80 }, { ZD_CR15, 0x3d }, + { ZD_CR16, 0x20 }, { ZD_CR17, 0x1e }, { ZD_CR18, 0x0a }, + { ZD_CR19, 0x48 }, { ZD_CR20, 0x0c }, { ZD_CR21, 0x0c }, + { ZD_CR22, 0x23 }, { ZD_CR23, 0x90 }, { ZD_CR24, 0x14 }, + { ZD_CR25, 0x40 }, { ZD_CR26, 0x10 }, { ZD_CR27, 0x19 }, + { ZD_CR28, 0x7f }, { ZD_CR29, 0x80 }, { ZD_CR30, 0x4b }, + { ZD_CR31, 0x60 }, { ZD_CR32, 0x43 }, { ZD_CR33, 0x08 }, + { ZD_CR34, 0x06 }, { ZD_CR35, 0x0a }, { ZD_CR36, 0x00 }, + { ZD_CR37, 0x00 }, { ZD_CR38, 0x38 }, { ZD_CR39, 0x0c }, + { ZD_CR40, 0x84 }, { ZD_CR41, 0x2a }, { ZD_CR42, 0x80 }, + { ZD_CR43, 0x10 }, { ZD_CR44, 0x12 }, { ZD_CR46, 0xff }, + { ZD_CR47, 0x1E }, { ZD_CR48, 0x26 }, { ZD_CR49, 0x5b }, + { ZD_CR64, 0xd0 }, { ZD_CR65, 0x04 }, { ZD_CR66, 0x58 }, + { ZD_CR67, 0xc9 }, { ZD_CR68, 0x88 }, { ZD_CR69, 0x41 }, + { ZD_CR70, 0x23 }, { ZD_CR71, 0x10 }, { ZD_CR72, 0xff }, + { ZD_CR73, 0x32 }, { ZD_CR74, 0x30 }, { ZD_CR75, 0x65 }, + { ZD_CR76, 0x41 }, { ZD_CR77, 0x1b }, { ZD_CR78, 0x30 }, + { ZD_CR79, 0x68 }, { ZD_CR80, 0x64 }, { ZD_CR81, 0x64 }, + { ZD_CR82, 0x00 }, { ZD_CR83, 0x00 }, { ZD_CR84, 0x00 }, + { ZD_CR85, 0x02 }, { ZD_CR86, 0x00 }, { ZD_CR87, 0x00 }, + { ZD_CR88, 0xff }, { ZD_CR89, 0xfc }, { ZD_CR90, 0x00 }, + { ZD_CR91, 0x00 }, { ZD_CR92, 0x00 }, { ZD_CR93, 0x08 }, + { ZD_CR94, 0x00 }, { ZD_CR95, 0x00 }, { ZD_CR96, 0xff }, + { ZD_CR97, 0xe7 }, { ZD_CR98, 0x00 }, { ZD_CR99, 0x00 }, + { ZD_CR100, 0x00 }, { ZD_CR101, 0xae }, { ZD_CR102, 0x02 }, + { ZD_CR103, 0x00 }, { ZD_CR104, 0x03 }, { ZD_CR105, 0x65 }, + { ZD_CR106, 0x04 }, { ZD_CR107, 0x00 }, { ZD_CR108, 0x0a }, + { ZD_CR109, 0xaa }, { ZD_CR110, 0xaa }, { ZD_CR111, 0x25 }, + { ZD_CR112, 0x25 }, { ZD_CR113, 0x00 }, { ZD_CR119, 0x1e }, + { ZD_CR125, 0x90 }, { ZD_CR126, 0x00 }, { ZD_CR127, 0x00 }, { }, - { CR5, 0x00 }, { CR6, 0x00 }, { CR7, 0x00 }, - { CR8, 0x00 }, { CR9, 0x20 }, { CR12, 0xf0 }, - { CR20, 0x0e }, { CR21, 0x0e }, { CR27, 0x10 }, - { CR44, 0x33 }, { CR47, 0x1E }, { CR83, 0x24 }, - { CR84, 0x04 }, { CR85, 0x00 }, { CR86, 0x0C }, - { CR87, 0x12 }, { CR88, 0x0C }, { CR89, 0x00 }, - { CR90, 0x10 }, { CR91, 0x08 }, { CR93, 0x00 }, - { CR94, 0x01 }, { CR95, 0x00 }, { CR96, 0x50 }, - { CR97, 0x37 }, { CR98, 0x35 }, { CR101, 0x13 }, - { CR102, 0x27 }, { CR103, 0x27 }, { CR104, 0x18 }, - { CR105, 0x12 }, { CR109, 0x27 }, { CR110, 0x27 }, - { CR111, 0x27 }, { CR112, 0x27 }, { CR113, 0x27 }, - { CR114, 0x27 }, { CR115, 0x26 }, { CR116, 0x24 }, - { CR117, 0xfc }, { CR118, 0xfa }, { CR120, 0x4f }, - { CR125, 0xaa }, { CR127, 0x03 }, { CR128, 0x14 }, - { CR129, 0x12 }, { CR130, 0x10 }, { CR131, 0x0C }, - { CR136, 0xdf }, { CR137, 0x40 }, { CR138, 0xa0 }, - { CR139, 0xb0 }, { CR140, 0x99 }, { CR141, 0x82 }, - { CR142, 0x54 }, { CR143, 0x1c }, { CR144, 0x6c }, - { CR147, 0x07 }, { CR148, 0x4c }, { CR149, 0x50 }, - { CR150, 0x0e }, { CR151, 0x18 }, { CR160, 0xfe }, - { CR161, 0xee }, { CR162, 0xaa }, { CR163, 0xfa }, - { CR164, 0xfa }, { CR165, 0xea }, { CR166, 0xbe }, - { CR167, 0xbe }, { CR168, 0x6a }, { CR169, 0xba }, - { CR170, 0xba }, { CR171, 0xba }, - /* Note: CR204 must lead the CR203 */ - { CR204, 0x7d }, + { ZD_CR5, 0x00 }, { ZD_CR6, 0x00 }, { ZD_CR7, 0x00 }, + { ZD_CR8, 0x00 }, { ZD_CR9, 0x20 }, { ZD_CR12, 0xf0 }, + { ZD_CR20, 0x0e }, { ZD_CR21, 0x0e }, { ZD_CR27, 0x10 }, + { ZD_CR44, 0x33 }, { ZD_CR47, 0x1E }, { ZD_CR83, 0x24 }, + { ZD_CR84, 0x04 }, { ZD_CR85, 0x00 }, { ZD_CR86, 0x0C }, + { ZD_CR87, 0x12 }, { ZD_CR88, 0x0C }, { ZD_CR89, 0x00 }, + { ZD_CR90, 0x10 }, { ZD_CR91, 0x08 }, { ZD_CR93, 0x00 }, + { ZD_CR94, 0x01 }, { ZD_CR95, 0x00 }, { ZD_CR96, 0x50 }, + { ZD_CR97, 0x37 }, { ZD_CR98, 0x35 }, { ZD_CR101, 0x13 }, + { ZD_CR102, 0x27 }, { ZD_CR103, 0x27 }, { ZD_CR104, 0x18 }, + { ZD_CR105, 0x12 }, { ZD_CR109, 0x27 }, { ZD_CR110, 0x27 }, + { ZD_CR111, 0x27 }, { ZD_CR112, 0x27 }, { ZD_CR113, 0x27 }, + { ZD_CR114, 0x27 }, { ZD_CR115, 0x26 }, { ZD_CR116, 0x24 }, + { ZD_CR117, 0xfc }, { ZD_CR118, 0xfa }, { ZD_CR120, 0x4f }, + { ZD_CR125, 0xaa }, { ZD_CR127, 0x03 }, { ZD_CR128, 0x14 }, + { ZD_CR129, 0x12 }, { ZD_CR130, 0x10 }, { ZD_CR131, 0x0C }, + { ZD_CR136, 0xdf }, { ZD_CR137, 0x40 }, { ZD_CR138, 0xa0 }, + { ZD_CR139, 0xb0 }, { ZD_CR140, 0x99 }, { ZD_CR141, 0x82 }, + { ZD_CR142, 0x54 }, { ZD_CR143, 0x1c }, { ZD_CR144, 0x6c }, + { ZD_CR147, 0x07 }, { ZD_CR148, 0x4c }, { ZD_CR149, 0x50 }, + { ZD_CR150, 0x0e }, { ZD_CR151, 0x18 }, { ZD_CR160, 0xfe }, + { ZD_CR161, 0xee }, { ZD_CR162, 0xaa }, { ZD_CR163, 0xfa }, + { ZD_CR164, 0xfa }, { ZD_CR165, 0xea }, { ZD_CR166, 0xbe }, + { ZD_CR167, 0xbe }, { ZD_CR168, 0x6a }, { ZD_CR169, 0xba }, + { ZD_CR170, 0xba }, { ZD_CR171, 0xba }, + /* Note: ZD_CR204 must lead the ZD_CR203 */ + { ZD_CR204, 0x7d }, { }, - { CR203, 0x30 }, + { ZD_CR203, 0x30 }, }; int r, t; @@ -697,62 +697,62 @@ out: static int zd1211b_hw_reset_phy(struct zd_chip *chip) { static const struct zd_ioreq16 ioreqs[] = { - { CR0, 0x14 }, { CR1, 0x06 }, { CR2, 0x26 }, - { CR3, 0x38 }, { CR4, 0x80 }, { CR9, 0xe0 }, - { CR10, 0x81 }, - /* power control { { CR11, 1 << 6 }, */ - { CR11, 0x00 }, - { CR12, 0xf0 }, { CR13, 0x8c }, { CR14, 0x80 }, - { CR15, 0x3d }, { CR16, 0x20 }, { CR17, 0x1e }, - { CR18, 0x0a }, { CR19, 0x48 }, - { CR20, 0x10 }, /* Org:0x0E, ComTrend:RalLink AP */ - { CR21, 0x0e }, { CR22, 0x23 }, { CR23, 0x90 }, - { CR24, 0x14 }, { CR25, 0x40 }, { CR26, 0x10 }, - { CR27, 0x10 }, { CR28, 0x7f }, { CR29, 0x80 }, - { CR30, 0x4b }, /* ASIC/FWT, no jointly decoder */ - { CR31, 0x60 }, { CR32, 0x43 }, { CR33, 0x08 }, - { CR34, 0x06 }, { CR35, 0x0a }, { CR36, 0x00 }, - { CR37, 0x00 }, { CR38, 0x38 }, { CR39, 0x0c }, - { CR40, 0x84 }, { CR41, 0x2a }, { CR42, 0x80 }, - { CR43, 0x10 }, { CR44, 0x33 }, { CR46, 0xff }, - { CR47, 0x1E }, { CR48, 0x26 }, { CR49, 0x5b }, - { CR64, 0xd0 }, { CR65, 0x04 }, { CR66, 0x58 }, - { CR67, 0xc9 }, { CR68, 0x88 }, { CR69, 0x41 }, - { CR70, 0x23 }, { CR71, 0x10 }, { CR72, 0xff }, - { CR73, 0x32 }, { CR74, 0x30 }, { CR75, 0x65 }, - { CR76, 0x41 }, { CR77, 0x1b }, { CR78, 0x30 }, - { CR79, 0xf0 }, { CR80, 0x64 }, { CR81, 0x64 }, - { CR82, 0x00 }, { CR83, 0x24 }, { CR84, 0x04 }, - { CR85, 0x00 }, { CR86, 0x0c }, { CR87, 0x12 }, - { CR88, 0x0c }, { CR89, 0x00 }, { CR90, 0x58 }, - { CR91, 0x04 }, { CR92, 0x00 }, { CR93, 0x00 }, - { CR94, 0x01 }, - { CR95, 0x20 }, /* ZD1211B */ - { CR96, 0x50 }, { CR97, 0x37 }, { CR98, 0x35 }, - { CR99, 0x00 }, { CR100, 0x01 }, { CR101, 0x13 }, - { CR102, 0x27 }, { CR103, 0x27 }, { CR104, 0x18 }, - { CR105, 0x12 }, { CR106, 0x04 }, { CR107, 0x00 }, - { CR108, 0x0a }, { CR109, 0x27 }, { CR110, 0x27 }, - { CR111, 0x27 }, { CR112, 0x27 }, { CR113, 0x27 }, - { CR114, 0x27 }, { CR115, 0x26 }, { CR116, 0x24 }, - { CR117, 0xfc }, { CR118, 0xfa }, { CR119, 0x1e }, - { CR125, 0x90 }, { CR126, 0x00 }, { CR127, 0x00 }, - { CR128, 0x14 }, { CR129, 0x12 }, { CR130, 0x10 }, - { CR131, 0x0c }, { CR136, 0xdf }, { CR137, 0xa0 }, - { CR138, 0xa8 }, { CR139, 0xb4 }, { CR140, 0x98 }, - { CR141, 0x82 }, { CR142, 0x53 }, { CR143, 0x1c }, - { CR144, 0x6c }, { CR147, 0x07 }, { CR148, 0x40 }, - { CR149, 0x40 }, /* Org:0x50 ComTrend:RalLink AP */ - { CR150, 0x14 }, /* Org:0x0E ComTrend:RalLink AP */ - { CR151, 0x18 }, { CR159, 0x70 }, { CR160, 0xfe }, - { CR161, 0xee }, { CR162, 0xaa }, { CR163, 0xfa }, - { CR164, 0xfa }, { CR165, 0xea }, { CR166, 0xbe }, - { CR167, 0xbe }, { CR168, 0x6a }, { CR169, 0xba }, - { CR170, 0xba }, { CR171, 0xba }, - /* Note: CR204 must lead the CR203 */ - { CR204, 0x7d }, + { ZD_CR0, 0x14 }, { ZD_CR1, 0x06 }, { ZD_CR2, 0x26 }, + { ZD_CR3, 0x38 }, { ZD_CR4, 0x80 }, { ZD_CR9, 0xe0 }, + { ZD_CR10, 0x81 }, + /* power control { { ZD_CR11, 1 << 6 }, */ + { ZD_CR11, 0x00 }, + { ZD_CR12, 0xf0 }, { ZD_CR13, 0x8c }, { ZD_CR14, 0x80 }, + { ZD_CR15, 0x3d }, { ZD_CR16, 0x20 }, { ZD_CR17, 0x1e }, + { ZD_CR18, 0x0a }, { ZD_CR19, 0x48 }, + { ZD_CR20, 0x10 }, /* Org:0x0E, ComTrend:RalLink AP */ + { ZD_CR21, 0x0e }, { ZD_CR22, 0x23 }, { ZD_CR23, 0x90 }, + { ZD_CR24, 0x14 }, { ZD_CR25, 0x40 }, { ZD_CR26, 0x10 }, + { ZD_CR27, 0x10 }, { ZD_CR28, 0x7f }, { ZD_CR29, 0x80 }, + { ZD_CR30, 0x4b }, /* ASIC/FWT, no jointly decoder */ + { ZD_CR31, 0x60 }, { ZD_CR32, 0x43 }, { ZD_CR33, 0x08 }, + { ZD_CR34, 0x06 }, { ZD_CR35, 0x0a }, { ZD_CR36, 0x00 }, + { ZD_CR37, 0x00 }, { ZD_CR38, 0x38 }, { ZD_CR39, 0x0c }, + { ZD_CR40, 0x84 }, { ZD_CR41, 0x2a }, { ZD_CR42, 0x80 }, + { ZD_CR43, 0x10 }, { ZD_CR44, 0x33 }, { ZD_CR46, 0xff }, + { ZD_CR47, 0x1E }, { ZD_CR48, 0x26 }, { ZD_CR49, 0x5b }, + { ZD_CR64, 0xd0 }, { ZD_CR65, 0x04 }, { ZD_CR66, 0x58 }, + { ZD_CR67, 0xc9 }, { ZD_CR68, 0x88 }, { ZD_CR69, 0x41 }, + { ZD_CR70, 0x23 }, { ZD_CR71, 0x10 }, { ZD_CR72, 0xff }, + { ZD_CR73, 0x32 }, { ZD_CR74, 0x30 }, { ZD_CR75, 0x65 }, + { ZD_CR76, 0x41 }, { ZD_CR77, 0x1b }, { ZD_CR78, 0x30 }, + { ZD_CR79, 0xf0 }, { ZD_CR80, 0x64 }, { ZD_CR81, 0x64 }, + { ZD_CR82, 0x00 }, { ZD_CR83, 0x24 }, { ZD_CR84, 0x04 }, + { ZD_CR85, 0x00 }, { ZD_CR86, 0x0c }, { ZD_CR87, 0x12 }, + { ZD_CR88, 0x0c }, { ZD_CR89, 0x00 }, { ZD_CR90, 0x58 }, + { ZD_CR91, 0x04 }, { ZD_CR92, 0x00 }, { ZD_CR93, 0x00 }, + { ZD_CR94, 0x01 }, + { ZD_CR95, 0x20 }, /* ZD1211B */ + { ZD_CR96, 0x50 }, { ZD_CR97, 0x37 }, { ZD_CR98, 0x35 }, + { ZD_CR99, 0x00 }, { ZD_CR100, 0x01 }, { ZD_CR101, 0x13 }, + { ZD_CR102, 0x27 }, { ZD_CR103, 0x27 }, { ZD_CR104, 0x18 }, + { ZD_CR105, 0x12 }, { ZD_CR106, 0x04 }, { ZD_CR107, 0x00 }, + { ZD_CR108, 0x0a }, { ZD_CR109, 0x27 }, { ZD_CR110, 0x27 }, + { ZD_CR111, 0x27 }, { ZD_CR112, 0x27 }, { ZD_CR113, 0x27 }, + { ZD_CR114, 0x27 }, { ZD_CR115, 0x26 }, { ZD_CR116, 0x24 }, + { ZD_CR117, 0xfc }, { ZD_CR118, 0xfa }, { ZD_CR119, 0x1e }, + { ZD_CR125, 0x90 }, { ZD_CR126, 0x00 }, { ZD_CR127, 0x00 }, + { ZD_CR128, 0x14 }, { ZD_CR129, 0x12 }, { ZD_CR130, 0x10 }, + { ZD_CR131, 0x0c }, { ZD_CR136, 0xdf }, { ZD_CR137, 0xa0 }, + { ZD_CR138, 0xa8 }, { ZD_CR139, 0xb4 }, { ZD_CR140, 0x98 }, + { ZD_CR141, 0x82 }, { ZD_CR142, 0x53 }, { ZD_CR143, 0x1c }, + { ZD_CR144, 0x6c }, { ZD_CR147, 0x07 }, { ZD_CR148, 0x40 }, + { ZD_CR149, 0x40 }, /* Org:0x50 ComTrend:RalLink AP */ + { ZD_CR150, 0x14 }, /* Org:0x0E ComTrend:RalLink AP */ + { ZD_CR151, 0x18 }, { ZD_CR159, 0x70 }, { ZD_CR160, 0xfe }, + { ZD_CR161, 0xee }, { ZD_CR162, 0xaa }, { ZD_CR163, 0xfa }, + { ZD_CR164, 0xfa }, { ZD_CR165, 0xea }, { ZD_CR166, 0xbe }, + { ZD_CR167, 0xbe }, { ZD_CR168, 0x6a }, { ZD_CR169, 0xba }, + { ZD_CR170, 0xba }, { ZD_CR171, 0xba }, + /* Note: ZD_CR204 must lead the ZD_CR203 */ + { ZD_CR204, 0x7d }, {}, - { CR203, 0x30 }, + { ZD_CR203, 0x30 }, }; int r, t; @@ -1200,24 +1200,24 @@ out: static int update_pwr_int(struct zd_chip *chip, u8 channel) { u8 value = chip->pwr_int_values[channel - 1]; - return zd_iowrite16_locked(chip, value, CR31); + return zd_iowrite16_locked(chip, value, ZD_CR31); } static int update_pwr_cal(struct zd_chip *chip, u8 channel) { u8 value = chip->pwr_cal_values[channel-1]; - return zd_iowrite16_locked(chip, value, CR68); + return zd_iowrite16_locked(chip, value, ZD_CR68); } static int update_ofdm_cal(struct zd_chip *chip, u8 channel) { struct zd_ioreq16 ioreqs[3]; - ioreqs[0].addr = CR67; + ioreqs[0].addr = ZD_CR67; ioreqs[0].value = chip->ofdm_cal_values[OFDM_36M_INDEX][channel-1]; - ioreqs[1].addr = CR66; + ioreqs[1].addr = ZD_CR66; ioreqs[1].value = chip->ofdm_cal_values[OFDM_48M_INDEX][channel-1]; - ioreqs[2].addr = CR65; + ioreqs[2].addr = ZD_CR65; ioreqs[2].value = chip->ofdm_cal_values[OFDM_54M_INDEX][channel-1]; return zd_iowrite16a_locked(chip, ioreqs, ARRAY_SIZE(ioreqs)); @@ -1236,9 +1236,9 @@ static int update_channel_integration_and_calibration(struct zd_chip *chip, return r; if (zd_chip_is_zd1211b(chip)) { static const struct zd_ioreq16 ioreqs[] = { - { CR69, 0x28 }, + { ZD_CR69, 0x28 }, {}, - { CR69, 0x2a }, + { ZD_CR69, 0x2a }, }; r = update_ofdm_cal(chip, channel); @@ -1269,7 +1269,7 @@ static int patch_cck_gain(struct zd_chip *chip) if (r) return r; dev_dbg_f(zd_chip_dev(chip), "patching value %x\n", value & 0xff); - return zd_iowrite16_locked(chip, value & 0xff, CR47); + return zd_iowrite16_locked(chip, value & 0xff, ZD_CR47); } int zd_chip_set_channel(struct zd_chip *chip, u8 channel) @@ -1505,9 +1505,9 @@ int zd_rfwritev_locked(struct zd_chip *chip, int zd_rfwrite_cr_locked(struct zd_chip *chip, u32 value) { const struct zd_ioreq16 ioreqs[] = { - { CR244, (value >> 16) & 0xff }, - { CR243, (value >> 8) & 0xff }, - { CR242, value & 0xff }, + { ZD_CR244, (value >> 16) & 0xff }, + { ZD_CR243, (value >> 8) & 0xff }, + { ZD_CR242, value & 0xff }, }; ZD_ASSERT(mutex_is_locked(&chip->mutex)); return zd_iowrite16a_locked(chip, ioreqs, ARRAY_SIZE(ioreqs)); diff --git a/drivers/net/wireless/zd1211rw/zd_chip.h b/drivers/net/wireless/zd1211rw/zd_chip.h index 14e4402..4be7c3b 100644 --- a/drivers/net/wireless/zd1211rw/zd_chip.h +++ b/drivers/net/wireless/zd1211rw/zd_chip.h @@ -61,277 +61,288 @@ enum { #define FWRAW_DATA(offset) ((zd_addr_t)(FW_START + (offset))) /* 8-bit hardware registers */ -#define CR0 CTL_REG(0x0000) -#define CR1 CTL_REG(0x0004) -#define CR2 CTL_REG(0x0008) -#define CR3 CTL_REG(0x000C) +#define ZD_CR0 CTL_REG(0x0000) +#define ZD_CR1 CTL_REG(0x0004) +#define ZD_CR2 CTL_REG(0x0008) +#define ZD_CR3 CTL_REG(0x000C) -#define CR5 CTL_REG(0x0010) +#define ZD_CR5 CTL_REG(0x0010) /* bit 5: if set short preamble used * bit 6: filter band - Japan channel 14 on, else off */ -#define CR6 CTL_REG(0x0014) -#define CR7 CTL_REG(0x0018) -#define CR8 CTL_REG(0x001C) +#define ZD_CR6 CTL_REG(0x0014) +#define ZD_CR7 CTL_REG(0x0018) +#define ZD_CR8 CTL_REG(0x001C) -#define CR4 CTL_REG(0x0020) +#define ZD_CR4 CTL_REG(0x0020) -#define CR9 CTL_REG(0x0024) -/* bit 2: antenna switch (together with CR10) */ -#define CR10 CTL_REG(0x0028) -/* bit 1: antenna switch (together with CR9) - * RF2959 controls with CR11 radion on and off +#define ZD_CR9 CTL_REG(0x0024) +/* bit 2: antenna switch (together with ZD_CR10) */ +#define ZD_CR10 CTL_REG(0x0028) +/* bit 1: antenna switch (together with ZD_CR9) + * RF2959 controls with ZD_CR11 radion on and off */ -#define CR11 CTL_REG(0x002C) +#define ZD_CR11 CTL_REG(0x002C) /* bit 6: TX power control for OFDM - * RF2959 controls with CR10 radio on and off + * RF2959 controls with ZD_CR10 radio on and off */ -#define CR12 CTL_REG(0x0030) -#define CR13 CTL_REG(0x0034) -#define CR14 CTL_REG(0x0038) -#define CR15 CTL_REG(0x003C) -#define CR16 CTL_REG(0x0040) -#define CR17 CTL_REG(0x0044) -#define CR18 CTL_REG(0x0048) -#define CR19 CTL_REG(0x004C) -#define CR20 CTL_REG(0x0050) -#define CR21 CTL_REG(0x0054) -#define CR22 CTL_REG(0x0058) -#define CR23 CTL_REG(0x005C) -#define CR24 CTL_REG(0x0060) /* CCA threshold */ -#define CR25 CTL_REG(0x0064) -#define CR26 CTL_REG(0x0068) -#define CR27 CTL_REG(0x006C) -#define CR28 CTL_REG(0x0070) -#define CR29 CTL_REG(0x0074) -#define CR30 CTL_REG(0x0078) -#define CR31 CTL_REG(0x007C) /* TX power control for RF in CCK mode */ -#define CR32 CTL_REG(0x0080) -#define CR33 CTL_REG(0x0084) -#define CR34 CTL_REG(0x0088) -#define CR35 CTL_REG(0x008C) -#define CR36 CTL_REG(0x0090) -#define CR37 CTL_REG(0x0094) -#define CR38 CTL_REG(0x0098) -#define CR39 CTL_REG(0x009C) -#define CR40 CTL_REG(0x00A0) -#define CR41 CTL_REG(0x00A4) -#define CR42 CTL_REG(0x00A8) -#define CR43 CTL_REG(0x00AC) -#define CR44 CTL_REG(0x00B0) -#define CR45 CTL_REG(0x00B4) -#define CR46 CTL_REG(0x00B8) -#define CR47 CTL_REG(0x00BC) /* CCK baseband gain - * (patch value might be in EEPROM) - */ -#define CR48 CTL_REG(0x00C0) -#define CR49 CTL_REG(0x00C4) -#define CR50 CTL_REG(0x00C8) -#define CR51 CTL_REG(0x00CC) /* TX power control for RF in 6-36M modes */ -#define CR52 CTL_REG(0x00D0) /* TX power control for RF in 48M mode */ -#define CR53 CTL_REG(0x00D4) /* TX power control for RF in 54M mode */ -#define CR54 CTL_REG(0x00D8) -#define CR55 CTL_REG(0x00DC) -#define CR56 CTL_REG(0x00E0) -#define CR57 CTL_REG(0x00E4) -#define CR58 CTL_REG(0x00E8) -#define CR59 CTL_REG(0x00EC) -#define CR60 CTL_REG(0x00F0) -#define CR61 CTL_REG(0x00F4) -#define CR62 CTL_REG(0x00F8) -#define CR63 CTL_REG(0x00FC) -#define CR64 CTL_REG(0x0100) -#define CR65 CTL_REG(0x0104) /* OFDM 54M calibration */ -#define CR66 CTL_REG(0x0108) /* OFDM 48M calibration */ -#define CR67 CTL_REG(0x010C) /* OFDM 36M calibration */ -#define CR68 CTL_REG(0x0110) /* CCK calibration */ -#define CR69 CTL_REG(0x0114) -#define CR70 CTL_REG(0x0118) -#define CR71 CTL_REG(0x011C) -#define CR72 CTL_REG(0x0120) -#define CR73 CTL_REG(0x0124) -#define CR74 CTL_REG(0x0128) -#define CR75 CTL_REG(0x012C) -#define CR76 CTL_REG(0x0130) -#define CR77 CTL_REG(0x0134) -#define CR78 CTL_REG(0x0138) -#define CR79 CTL_REG(0x013C) -#define CR80 CTL_REG(0x0140) -#define CR81 CTL_REG(0x0144) -#define CR82 CTL_REG(0x0148) -#define CR83 CTL_REG(0x014C) -#define CR84 CTL_REG(0x0150) -#define CR85 CTL_REG(0x0154) -#define CR86 CTL_REG(0x0158) -#define CR87 CTL_REG(0x015C) -#define CR88 CTL_REG(0x0160) -#define CR89 CTL_REG(0x0164) -#define CR90 CTL_REG(0x0168) -#define CR91 CTL_REG(0x016C) -#define CR92 CTL_REG(0x0170) -#define CR93 CTL_REG(0x0174) -#define CR94 CTL_REG(0x0178) -#define CR95 CTL_REG(0x017C) -#define CR96 CTL_REG(0x0180) -#define CR97 CTL_REG(0x0184) -#define CR98 CTL_REG(0x0188) -#define CR99 CTL_REG(0x018C) -#define CR100 CTL_REG(0x0190) -#define CR101 CTL_REG(0x0194) -#define CR102 CTL_REG(0x0198) -#define CR103 CTL_REG(0x019C) -#define CR104 CTL_REG(0x01A0) -#define CR105 CTL_REG(0x01A4) -#define CR106 CTL_REG(0x01A8) -#define CR107 CTL_REG(0x01AC) -#define CR108 CTL_REG(0x01B0) -#define CR109 CTL_REG(0x01B4) -#define CR110 CTL_REG(0x01B8) -#define CR111 CTL_REG(0x01BC) -#define CR112 CTL_REG(0x01C0) -#define CR113 CTL_REG(0x01C4) -#define CR114 CTL_REG(0x01C8) -#define CR115 CTL_REG(0x01CC) -#define CR116 CTL_REG(0x01D0) -#define CR117 CTL_REG(0x01D4) -#define CR118 CTL_REG(0x01D8) -#define CR119 CTL_REG(0x01DC) -#define CR120 CTL_REG(0x01E0) -#define CR121 CTL_REG(0x01E4) -#define CR122 CTL_REG(0x01E8) -#define CR123 CTL_REG(0x01EC) -#define CR124 CTL_REG(0x01F0) -#define CR125 CTL_REG(0x01F4) -#define CR126 CTL_REG(0x01F8) -#define CR127 CTL_REG(0x01FC) -#define CR128 CTL_REG(0x0200) -#define CR129 CTL_REG(0x0204) -#define CR130 CTL_REG(0x0208) -#define CR131 CTL_REG(0x020C) -#define CR132 CTL_REG(0x0210) -#define CR133 CTL_REG(0x0214) -#define CR134 CTL_REG(0x0218) -#define CR135 CTL_REG(0x021C) -#define CR136 CTL_REG(0x0220) -#define CR137 CTL_REG(0x0224) -#define CR138 CTL_REG(0x0228) -#define CR139 CTL_REG(0x022C) -#define CR140 CTL_REG(0x0230) -#define CR141 CTL_REG(0x0234) -#define CR142 CTL_REG(0x0238) -#define CR143 CTL_REG(0x023C) -#define CR144 CTL_REG(0x0240) -#define CR145 CTL_REG(0x0244) -#define CR146 CTL_REG(0x0248) -#define CR147 CTL_REG(0x024C) -#define CR148 CTL_REG(0x0250) -#define CR149 CTL_REG(0x0254) -#define CR150 CTL_REG(0x0258) -#define CR151 CTL_REG(0x025C) -#define CR152 CTL_REG(0x0260) -#define CR153 CTL_REG(0x0264) -#define CR154 CTL_REG(0x0268) -#define CR155 CTL_REG(0x026C) -#define CR156 CTL_REG(0x0270) -#define CR157 CTL_REG(0x0274) -#define CR158 CTL_REG(0x0278) -#define CR159 CTL_REG(0x027C) -#define CR160 CTL_REG(0x0280) -#define CR161 CTL_REG(0x0284) -#define CR162 CTL_REG(0x0288) -#define CR163 CTL_REG(0x028C) -#define CR164 CTL_REG(0x0290) -#define CR165 CTL_REG(0x0294) -#define CR166 CTL_REG(0x0298) -#define CR167 CTL_REG(0x029C) -#define CR168 CTL_REG(0x02A0) -#define CR169 CTL_REG(0x02A4) -#define CR170 CTL_REG(0x02A8) -#define CR171 CTL_REG(0x02AC) -#define CR172 CTL_REG(0x02B0) -#define CR173 CTL_REG(0x02B4) -#define CR174 CTL_REG(0x02B8) -#define CR175 CTL_REG(0x02BC) -#define CR176 CTL_REG(0x02C0) -#define CR177 CTL_REG(0x02C4) -#define CR178 CTL_REG(0x02C8) -#define CR179 CTL_REG(0x02CC) -#define CR180 CTL_REG(0x02D0) -#define CR181 CTL_REG(0x02D4) -#define CR182 CTL_REG(0x02D8) -#define CR183 CTL_REG(0x02DC) -#define CR184 CTL_REG(0x02E0) -#define CR185 CTL_REG(0x02E4) -#define CR186 CTL_REG(0x02E8) -#define CR187 CTL_REG(0x02EC) -#define CR188 CTL_REG(0x02F0) -#define CR189 CTL_REG(0x02F4) -#define CR190 CTL_REG(0x02F8) -#define CR191 CTL_REG(0x02FC) -#define CR192 CTL_REG(0x0300) -#define CR193 CTL_REG(0x0304) -#define CR194 CTL_REG(0x0308) -#define CR195 CTL_REG(0x030C) -#define CR196 CTL_REG(0x0310) -#define CR197 CTL_REG(0x0314) -#define CR198 CTL_REG(0x0318) -#define CR199 CTL_REG(0x031C) -#define CR200 CTL_REG(0x0320) -#define CR201 CTL_REG(0x0324) -#define CR202 CTL_REG(0x0328) -#define CR203 CTL_REG(0x032C) /* I2C bus template value & flash control */ -#define CR204 CTL_REG(0x0330) -#define CR205 CTL_REG(0x0334) -#define CR206 CTL_REG(0x0338) -#define CR207 CTL_REG(0x033C) -#define CR208 CTL_REG(0x0340) -#define CR209 CTL_REG(0x0344) -#define CR210 CTL_REG(0x0348) -#define CR211 CTL_REG(0x034C) -#define CR212 CTL_REG(0x0350) -#define CR213 CTL_REG(0x0354) -#define CR214 CTL_REG(0x0358) -#define CR215 CTL_REG(0x035C) -#define CR216 CTL_REG(0x0360) -#define CR217 CTL_REG(0x0364) -#define CR218 CTL_REG(0x0368) -#define CR219 CTL_REG(0x036C) -#define CR220 CTL_REG(0x0370) -#define CR221 CTL_REG(0x0374) -#define CR222 CTL_REG(0x0378) -#define CR223 CTL_REG(0x037C) -#define CR224 CTL_REG(0x0380) -#define CR225 CTL_REG(0x0384) -#define CR226 CTL_REG(0x0388) -#define CR227 CTL_REG(0x038C) -#define CR228 CTL_REG(0x0390) -#define CR229 CTL_REG(0x0394) -#define CR230 CTL_REG(0x0398) -#define CR231 CTL_REG(0x039C) -#define CR232 CTL_REG(0x03A0) -#define CR233 CTL_REG(0x03A4) -#define CR234 CTL_REG(0x03A8) -#define CR235 CTL_REG(0x03AC) -#define CR236 CTL_REG(0x03B0) - -#define CR240 CTL_REG(0x03C0) -/* bit 7: host-controlled RF register writes - * CR241-CR245: for hardware controlled writing of RF bits, not needed for - * USB +#define ZD_CR12 CTL_REG(0x0030) +#define ZD_CR13 CTL_REG(0x0034) +#define ZD_CR14 CTL_REG(0x0038) +#define ZD_CR15 CTL_REG(0x003C) +#define ZD_CR16 CTL_REG(0x0040) +#define ZD_CR17 CTL_REG(0x0044) +#define ZD_CR18 CTL_REG(0x0048) +#define ZD_CR19 CTL_REG(0x004C) +#define ZD_CR20 CTL_REG(0x0050) +#define ZD_CR21 CTL_REG(0x0054) +#define ZD_CR22 CTL_REG(0x0058) +#define ZD_CR23 CTL_REG(0x005C) +#define ZD_CR24 CTL_REG(0x0060) /* CCA threshold */ +#define ZD_CR25 CTL_REG(0x0064) +#define ZD_CR26 CTL_REG(0x0068) +#define ZD_CR27 CTL_REG(0x006C) +#define ZD_CR28 CTL_REG(0x0070) +#define ZD_CR29 CTL_REG(0x0074) +#define ZD_CR30 CTL_REG(0x0078) +#define ZD_CR31 CTL_REG(0x007C) /* TX power control for RF in + * CCK mode + */ +#define ZD_CR32 CTL_REG(0x0080) +#define ZD_CR33 CTL_REG(0x0084) +#define ZD_CR34 CTL_REG(0x0088) +#define ZD_CR35 CTL_REG(0x008C) +#define ZD_CR36 CTL_REG(0x0090) +#define ZD_CR37 CTL_REG(0x0094) +#define ZD_CR38 CTL_REG(0x0098) +#define ZD_CR39 CTL_REG(0x009C) +#define ZD_CR40 CTL_REG(0x00A0) +#define ZD_CR41 CTL_REG(0x00A4) +#define ZD_CR42 CTL_REG(0x00A8) +#define ZD_CR43 CTL_REG(0x00AC) +#define ZD_CR44 CTL_REG(0x00B0) +#define ZD_CR45 CTL_REG(0x00B4) +#define ZD_CR46 CTL_REG(0x00B8) +#define ZD_CR47 CTL_REG(0x00BC) /* CCK baseband gain + * (patch value might be in EEPROM) + */ +#define ZD_CR48 CTL_REG(0x00C0) +#define ZD_CR49 CTL_REG(0x00C4) +#define ZD_CR50 CTL_REG(0x00C8) +#define ZD_CR51 CTL_REG(0x00CC) /* TX power control for RF in + * 6-36M modes + */ +#define ZD_CR52 CTL_REG(0x00D0) /* TX power control for RF in + * 48M mode + */ +#define ZD_CR53 CTL_REG(0x00D4) /* TX power control for RF in + * 54M mode + */ +#define ZD_CR54 CTL_REG(0x00D8) +#define ZD_CR55 CTL_REG(0x00DC) +#define ZD_CR56 CTL_REG(0x00E0) +#define ZD_CR57 CTL_REG(0x00E4) +#define ZD_CR58 CTL_REG(0x00E8) +#define ZD_CR59 CTL_REG(0x00EC) +#define ZD_CR60 CTL_REG(0x00F0) +#define ZD_CR61 CTL_REG(0x00F4) +#define ZD_CR62 CTL_REG(0x00F8) +#define ZD_CR63 CTL_REG(0x00FC) +#define ZD_CR64 CTL_REG(0x0100) +#define ZD_CR65 CTL_REG(0x0104) /* OFDM 54M calibration */ +#define ZD_CR66 CTL_REG(0x0108) /* OFDM 48M calibration */ +#define ZD_CR67 CTL_REG(0x010C) /* OFDM 36M calibration */ +#define ZD_CR68 CTL_REG(0x0110) /* CCK calibration */ +#define ZD_CR69 CTL_REG(0x0114) +#define ZD_CR70 CTL_REG(0x0118) +#define ZD_CR71 CTL_REG(0x011C) +#define ZD_CR72 CTL_REG(0x0120) +#define ZD_CR73 CTL_REG(0x0124) +#define ZD_CR74 CTL_REG(0x0128) +#define ZD_CR75 CTL_REG(0x012C) +#define ZD_CR76 CTL_REG(0x0130) +#define ZD_CR77 CTL_REG(0x0134) +#define ZD_CR78 CTL_REG(0x0138) +#define ZD_CR79 CTL_REG(0x013C) +#define ZD_CR80 CTL_REG(0x0140) +#define ZD_CR81 CTL_REG(0x0144) +#define ZD_CR82 CTL_REG(0x0148) +#define ZD_CR83 CTL_REG(0x014C) +#define ZD_CR84 CTL_REG(0x0150) +#define ZD_CR85 CTL_REG(0x0154) +#define ZD_CR86 CTL_REG(0x0158) +#define ZD_CR87 CTL_REG(0x015C) +#define ZD_CR88 CTL_REG(0x0160) +#define ZD_CR89 CTL_REG(0x0164) +#define ZD_CR90 CTL_REG(0x0168) +#define ZD_CR91 CTL_REG(0x016C) +#define ZD_CR92 CTL_REG(0x0170) +#define ZD_CR93 CTL_REG(0x0174) +#define ZD_CR94 CTL_REG(0x0178) +#define ZD_CR95 CTL_REG(0x017C) +#define ZD_CR96 CTL_REG(0x0180) +#define ZD_CR97 CTL_REG(0x0184) +#define ZD_CR98 CTL_REG(0x0188) +#define ZD_CR99 CTL_REG(0x018C) +#define ZD_CR100 CTL_REG(0x0190) +#define ZD_CR101 CTL_REG(0x0194) +#define ZD_CR102 CTL_REG(0x0198) +#define ZD_CR103 CTL_REG(0x019C) +#define ZD_CR104 CTL_REG(0x01A0) +#define ZD_CR105 CTL_REG(0x01A4) +#define ZD_CR106 CTL_REG(0x01A8) +#define ZD_CR107 CTL_REG(0x01AC) +#define ZD_CR108 CTL_REG(0x01B0) +#define ZD_CR109 CTL_REG(0x01B4) +#define ZD_CR110 CTL_REG(0x01B8) +#define ZD_CR111 CTL_REG(0x01BC) +#define ZD_CR112 CTL_REG(0x01C0) +#define ZD_CR113 CTL_REG(0x01C4) +#define ZD_CR114 CTL_REG(0x01C8) +#define ZD_CR115 CTL_REG(0x01CC) +#define ZD_CR116 CTL_REG(0x01D0) +#define ZD_CR117 CTL_REG(0x01D4) +#define ZD_CR118 CTL_REG(0x01D8) +#define ZD_CR119 CTL_REG(0x01DC) +#define ZD_CR120 CTL_REG(0x01E0) +#define ZD_CR121 CTL_REG(0x01E4) +#define ZD_CR122 CTL_REG(0x01E8) +#define ZD_CR123 CTL_REG(0x01EC) +#define ZD_CR124 CTL_REG(0x01F0) +#define ZD_CR125 CTL_REG(0x01F4) +#define ZD_CR126 CTL_REG(0x01F8) +#define ZD_CR127 CTL_REG(0x01FC) +#define ZD_CR128 CTL_REG(0x0200) +#define ZD_CR129 CTL_REG(0x0204) +#define ZD_CR130 CTL_REG(0x0208) +#define ZD_CR131 CTL_REG(0x020C) +#define ZD_CR132 CTL_REG(0x0210) +#define ZD_CR133 CTL_REG(0x0214) +#define ZD_CR134 CTL_REG(0x0218) +#define ZD_CR135 CTL_REG(0x021C) +#define ZD_CR136 CTL_REG(0x0220) +#define ZD_CR137 CTL_REG(0x0224) +#define ZD_CR138 CTL_REG(0x0228) +#define ZD_CR139 CTL_REG(0x022C) +#define ZD_CR140 CTL_REG(0x0230) +#define ZD_CR141 CTL_REG(0x0234) +#define ZD_CR142 CTL_REG(0x0238) +#define ZD_CR143 CTL_REG(0x023C) +#define ZD_CR144 CTL_REG(0x0240) +#define ZD_CR145 CTL_REG(0x0244) +#define ZD_CR146 CTL_REG(0x0248) +#define ZD_CR147 CTL_REG(0x024C) +#define ZD_CR148 CTL_REG(0x0250) +#define ZD_CR149 CTL_REG(0x0254) +#define ZD_CR150 CTL_REG(0x0258) +#define ZD_CR151 CTL_REG(0x025C) +#define ZD_CR152 CTL_REG(0x0260) +#define ZD_CR153 CTL_REG(0x0264) +#define ZD_CR154 CTL_REG(0x0268) +#define ZD_CR155 CTL_REG(0x026C) +#define ZD_CR156 CTL_REG(0x0270) +#define ZD_CR157 CTL_REG(0x0274) +#define ZD_CR158 CTL_REG(0x0278) +#define ZD_CR159 CTL_REG(0x027C) +#define ZD_CR160 CTL_REG(0x0280) +#define ZD_CR161 CTL_REG(0x0284) +#define ZD_CR162 CTL_REG(0x0288) +#define ZD_CR163 CTL_REG(0x028C) +#define ZD_CR164 CTL_REG(0x0290) +#define ZD_CR165 CTL_REG(0x0294) +#define ZD_CR166 CTL_REG(0x0298) +#define ZD_CR167 CTL_REG(0x029C) +#define ZD_CR168 CTL_REG(0x02A0) +#define ZD_CR169 CTL_REG(0x02A4) +#define ZD_CR170 CTL_REG(0x02A8) +#define ZD_CR171 CTL_REG(0x02AC) +#define ZD_CR172 CTL_REG(0x02B0) +#define ZD_CR173 CTL_REG(0x02B4) +#define ZD_CR174 CTL_REG(0x02B8) +#define ZD_CR175 CTL_REG(0x02BC) +#define ZD_CR176 CTL_REG(0x02C0) +#define ZD_CR177 CTL_REG(0x02C4) +#define ZD_CR178 CTL_REG(0x02C8) +#define ZD_CR179 CTL_REG(0x02CC) +#define ZD_CR180 CTL_REG(0x02D0) +#define ZD_CR181 CTL_REG(0x02D4) +#define ZD_CR182 CTL_REG(0x02D8) +#define ZD_CR183 CTL_REG(0x02DC) +#define ZD_CR184 CTL_REG(0x02E0) +#define ZD_CR185 CTL_REG(0x02E4) +#define ZD_CR186 CTL_REG(0x02E8) +#define ZD_CR187 CTL_REG(0x02EC) +#define ZD_CR188 CTL_REG(0x02F0) +#define ZD_CR189 CTL_REG(0x02F4) +#define ZD_CR190 CTL_REG(0x02F8) +#define ZD_CR191 CTL_REG(0x02FC) +#define ZD_CR192 CTL_REG(0x0300) +#define ZD_CR193 CTL_REG(0x0304) +#define ZD_CR194 CTL_REG(0x0308) +#define ZD_CR195 CTL_REG(0x030C) +#define ZD_CR196 CTL_REG(0x0310) +#define ZD_CR197 CTL_REG(0x0314) +#define ZD_CR198 CTL_REG(0x0318) +#define ZD_CR199 CTL_REG(0x031C) +#define ZD_CR200 CTL_REG(0x0320) +#define ZD_CR201 CTL_REG(0x0324) +#define ZD_CR202 CTL_REG(0x0328) +#define ZD_CR203 CTL_REG(0x032C) /* I2C bus template value & flash + * control + */ +#define ZD_CR204 CTL_REG(0x0330) +#define ZD_CR205 CTL_REG(0x0334) +#define ZD_CR206 CTL_REG(0x0338) +#define ZD_CR207 CTL_REG(0x033C) +#define ZD_CR208 CTL_REG(0x0340) +#define ZD_CR209 CTL_REG(0x0344) +#define ZD_CR210 CTL_REG(0x0348) +#define ZD_CR211 CTL_REG(0x034C) +#define ZD_CR212 CTL_REG(0x0350) +#define ZD_CR213 CTL_REG(0x0354) +#define ZD_CR214 CTL_REG(0x0358) +#define ZD_CR215 CTL_REG(0x035C) +#define ZD_CR216 CTL_REG(0x0360) +#define ZD_CR217 CTL_REG(0x0364) +#define ZD_CR218 CTL_REG(0x0368) +#define ZD_CR219 CTL_REG(0x036C) +#define ZD_CR220 CTL_REG(0x0370) +#define ZD_CR221 CTL_REG(0x0374) +#define ZD_CR222 CTL_REG(0x0378) +#define ZD_CR223 CTL_REG(0x037C) +#define ZD_CR224 CTL_REG(0x0380) +#define ZD_CR225 CTL_REG(0x0384) +#define ZD_CR226 CTL_REG(0x0388) +#define ZD_CR227 CTL_REG(0x038C) +#define ZD_CR228 CTL_REG(0x0390) +#define ZD_CR229 CTL_REG(0x0394) +#define ZD_CR230 CTL_REG(0x0398) +#define ZD_CR231 CTL_REG(0x039C) +#define ZD_CR232 CTL_REG(0x03A0) +#define ZD_CR233 CTL_REG(0x03A4) +#define ZD_CR234 CTL_REG(0x03A8) +#define ZD_CR235 CTL_REG(0x03AC) +#define ZD_CR236 CTL_REG(0x03B0) + +#define ZD_CR240 CTL_REG(0x03C0) +/* bit 7: host-controlled RF register writes + * ZD_CR241-ZD_CR245: for hardware controlled writing of RF bits, not needed for + * USB */ -#define CR241 CTL_REG(0x03C4) -#define CR242 CTL_REG(0x03C8) -#define CR243 CTL_REG(0x03CC) -#define CR244 CTL_REG(0x03D0) -#define CR245 CTL_REG(0x03D4) - -#define CR251 CTL_REG(0x03EC) /* only used for activation and deactivation of - * Airoha RFs AL2230 and AL7230B - */ -#define CR252 CTL_REG(0x03F0) -#define CR253 CTL_REG(0x03F4) -#define CR254 CTL_REG(0x03F8) -#define CR255 CTL_REG(0x03FC) +#define ZD_CR241 CTL_REG(0x03C4) +#define ZD_CR242 CTL_REG(0x03C8) +#define ZD_CR243 CTL_REG(0x03CC) +#define ZD_CR244 CTL_REG(0x03D0) +#define ZD_CR245 CTL_REG(0x03D4) + +#define ZD_CR251 CTL_REG(0x03EC) /* only used for activation and + * deactivation of Airoha RFs AL2230 + * and AL7230B + */ +#define ZD_CR252 CTL_REG(0x03F0) +#define ZD_CR253 CTL_REG(0x03F4) +#define ZD_CR254 CTL_REG(0x03F8) +#define ZD_CR255 CTL_REG(0x03FC) #define CR_MAX_PHY_REG 255 diff --git a/drivers/net/wireless/zd1211rw/zd_rf.h b/drivers/net/wireless/zd1211rw/zd_rf.h index 79dc103..725b7c9 100644 --- a/drivers/net/wireless/zd1211rw/zd_rf.h +++ b/drivers/net/wireless/zd1211rw/zd_rf.h @@ -55,7 +55,7 @@ struct zd_rf { * defaults to 1 (yes) */ u8 update_channel_int:1; - /* whether CR47 should be patched from the EEPROM, if the appropriate + /* whether ZD_CR47 should be patched from the EEPROM, if the appropriate * flag is set in the POD. The vendor driver suggests that this should * be done for all RF's, but a bug in their code prevents but their * HW_OverWritePhyRegFromE2P() routine from ever taking effect. */ diff --git a/drivers/net/wireless/zd1211rw/zd_rf_al2230.c b/drivers/net/wireless/zd1211rw/zd_rf_al2230.c index 74a8f7a..12babcb 100644 --- a/drivers/net/wireless/zd1211rw/zd_rf_al2230.c +++ b/drivers/net/wireless/zd1211rw/zd_rf_al2230.c @@ -61,31 +61,31 @@ static const u32 zd1211b_al2230_table[][3] = { }; static const struct zd_ioreq16 zd1211b_ioreqs_shared_1[] = { - { CR240, 0x57 }, { CR9, 0xe0 }, + { ZD_CR240, 0x57 }, { ZD_CR9, 0xe0 }, }; static const struct zd_ioreq16 ioreqs_init_al2230s[] = { - { CR47, 0x1e }, /* MARK_002 */ - { CR106, 0x22 }, - { CR107, 0x2a }, /* MARK_002 */ - { CR109, 0x13 }, /* MARK_002 */ - { CR118, 0xf8 }, /* MARK_002 */ - { CR119, 0x12 }, { CR122, 0xe0 }, - { CR128, 0x10 }, /* MARK_001 from 0xe->0x10 */ - { CR129, 0x0e }, /* MARK_001 from 0xd->0x0e */ - { CR130, 0x10 }, /* MARK_001 from 0xb->0x0d */ + { ZD_CR47, 0x1e }, /* MARK_002 */ + { ZD_CR106, 0x22 }, + { ZD_CR107, 0x2a }, /* MARK_002 */ + { ZD_CR109, 0x13 }, /* MARK_002 */ + { ZD_CR118, 0xf8 }, /* MARK_002 */ + { ZD_CR119, 0x12 }, { ZD_CR122, 0xe0 }, + { ZD_CR128, 0x10 }, /* MARK_001 from 0xe->0x10 */ + { ZD_CR129, 0x0e }, /* MARK_001 from 0xd->0x0e */ + { ZD_CR130, 0x10 }, /* MARK_001 from 0xb->0x0d */ }; static int zd1211b_al2230_finalize_rf(struct zd_chip *chip) { int r; static const struct zd_ioreq16 ioreqs[] = { - { CR80, 0x30 }, { CR81, 0x30 }, { CR79, 0x58 }, - { CR12, 0xf0 }, { CR77, 0x1b }, { CR78, 0x58 }, - { CR203, 0x06 }, + { ZD_CR80, 0x30 }, { ZD_CR81, 0x30 }, { ZD_CR79, 0x58 }, + { ZD_CR12, 0xf0 }, { ZD_CR77, 0x1b }, { ZD_CR78, 0x58 }, + { ZD_CR203, 0x06 }, { }, - { CR240, 0x80 }, + { ZD_CR240, 0x80 }, }; r = zd_iowrite16a_locked(chip, ioreqs, ARRAY_SIZE(ioreqs)); @@ -94,12 +94,12 @@ static int zd1211b_al2230_finalize_rf(struct zd_chip *chip) /* related to antenna selection? */ if (chip->new_phy_layout) { - r = zd_iowrite16_locked(chip, 0xe1, CR9); + r = zd_iowrite16_locked(chip, 0xe1, ZD_CR9); if (r) return r; } - return zd_iowrite16_locked(chip, 0x06, CR203); + return zd_iowrite16_locked(chip, 0x06, ZD_CR203); } static int zd1211_al2230_init_hw(struct zd_rf *rf) @@ -108,40 +108,40 @@ static int zd1211_al2230_init_hw(struct zd_rf *rf) struct zd_chip *chip = zd_rf_to_chip(rf); static const struct zd_ioreq16 ioreqs_init[] = { - { CR15, 0x20 }, { CR23, 0x40 }, { CR24, 0x20 }, - { CR26, 0x11 }, { CR28, 0x3e }, { CR29, 0x00 }, - { CR44, 0x33 }, { CR106, 0x2a }, { CR107, 0x1a }, - { CR109, 0x09 }, { CR110, 0x27 }, { CR111, 0x2b }, - { CR112, 0x2b }, { CR119, 0x0a }, { CR10, 0x89 }, + { ZD_CR15, 0x20 }, { ZD_CR23, 0x40 }, { ZD_CR24, 0x20 }, + { ZD_CR26, 0x11 }, { ZD_CR28, 0x3e }, { ZD_CR29, 0x00 }, + { ZD_CR44, 0x33 }, { ZD_CR106, 0x2a }, { ZD_CR107, 0x1a }, + { ZD_CR109, 0x09 }, { ZD_CR110, 0x27 }, { ZD_CR111, 0x2b }, + { ZD_CR112, 0x2b }, { ZD_CR119, 0x0a }, { ZD_CR10, 0x89 }, /* for newest (3rd cut) AL2300 */ - { CR17, 0x28 }, - { CR26, 0x93 }, { CR34, 0x30 }, + { ZD_CR17, 0x28 }, + { ZD_CR26, 0x93 }, { ZD_CR34, 0x30 }, /* for newest (3rd cut) AL2300 */ - { CR35, 0x3e }, - { CR41, 0x24 }, { CR44, 0x32 }, + { ZD_CR35, 0x3e }, + { ZD_CR41, 0x24 }, { ZD_CR44, 0x32 }, /* for newest (3rd cut) AL2300 */ - { CR46, 0x96 }, - { CR47, 0x1e }, { CR79, 0x58 }, { CR80, 0x30 }, - { CR81, 0x30 }, { CR87, 0x0a }, { CR89, 0x04 }, - { CR92, 0x0a }, { CR99, 0x28 }, { CR100, 0x00 }, - { CR101, 0x13 }, { CR102, 0x27 }, { CR106, 0x24 }, - { CR107, 0x2a }, { CR109, 0x09 }, { CR110, 0x13 }, - { CR111, 0x1f }, { CR112, 0x1f }, { CR113, 0x27 }, - { CR114, 0x27 }, + { ZD_CR46, 0x96 }, + { ZD_CR47, 0x1e }, { ZD_CR79, 0x58 }, { ZD_CR80, 0x30 }, + { ZD_CR81, 0x30 }, { ZD_CR87, 0x0a }, { ZD_CR89, 0x04 }, + { ZD_CR92, 0x0a }, { ZD_CR99, 0x28 }, { ZD_CR100, 0x00 }, + { ZD_CR101, 0x13 }, { ZD_CR102, 0x27 }, { ZD_CR106, 0x24 }, + { ZD_CR107, 0x2a }, { ZD_CR109, 0x09 }, { ZD_CR110, 0x13 }, + { ZD_CR111, 0x1f }, { ZD_CR112, 0x1f }, { ZD_CR113, 0x27 }, + { ZD_CR114, 0x27 }, /* for newest (3rd cut) AL2300 */ - { CR115, 0x24 }, - { CR116, 0x24 }, { CR117, 0xf4 }, { CR118, 0xfc }, - { CR119, 0x10 }, { CR120, 0x4f }, { CR121, 0x77 }, - { CR122, 0xe0 }, { CR137, 0x88 }, { CR252, 0xff }, - { CR253, 0xff }, + { ZD_CR115, 0x24 }, + { ZD_CR116, 0x24 }, { ZD_CR117, 0xf4 }, { ZD_CR118, 0xfc }, + { ZD_CR119, 0x10 }, { ZD_CR120, 0x4f }, { ZD_CR121, 0x77 }, + { ZD_CR122, 0xe0 }, { ZD_CR137, 0x88 }, { ZD_CR252, 0xff }, + { ZD_CR253, 0xff }, }; static const struct zd_ioreq16 ioreqs_pll[] = { /* shdnb(PLL_ON)=0 */ - { CR251, 0x2f }, + { ZD_CR251, 0x2f }, /* shdnb(PLL_ON)=1 */ - { CR251, 0x3f }, - { CR138, 0x28 }, { CR203, 0x06 }, + { ZD_CR251, 0x3f }, + { ZD_CR138, 0x28 }, { ZD_CR203, 0x06 }, }; static const u32 rv1[] = { @@ -161,7 +161,7 @@ static int zd1211_al2230_init_hw(struct zd_rf *rf) 0x0805b6, 0x011687, 0x000688, - 0x0403b9, /* external control TX power (CR31) */ + 0x0403b9, /* external control TX power (ZD_CR31) */ 0x00dbba, 0x00099b, 0x0bdffc, @@ -221,52 +221,54 @@ static int zd1211b_al2230_init_hw(struct zd_rf *rf) struct zd_chip *chip = zd_rf_to_chip(rf); static const struct zd_ioreq16 ioreqs1[] = { - { CR10, 0x89 }, { CR15, 0x20 }, - { CR17, 0x2B }, /* for newest(3rd cut) AL2230 */ - { CR23, 0x40 }, { CR24, 0x20 }, { CR26, 0x93 }, - { CR28, 0x3e }, { CR29, 0x00 }, - { CR33, 0x28 }, /* 5621 */ - { CR34, 0x30 }, - { CR35, 0x3e }, /* for newest(3rd cut) AL2230 */ - { CR41, 0x24 }, { CR44, 0x32 }, - { CR46, 0x99 }, /* for newest(3rd cut) AL2230 */ - { CR47, 0x1e }, + { ZD_CR10, 0x89 }, { ZD_CR15, 0x20 }, + { ZD_CR17, 0x2B }, /* for newest(3rd cut) AL2230 */ + { ZD_CR23, 0x40 }, { ZD_CR24, 0x20 }, { ZD_CR26, 0x93 }, + { ZD_CR28, 0x3e }, { ZD_CR29, 0x00 }, + { ZD_CR33, 0x28 }, /* 5621 */ + { ZD_CR34, 0x30 }, + { ZD_CR35, 0x3e }, /* for newest(3rd cut) AL2230 */ + { ZD_CR41, 0x24 }, { ZD_CR44, 0x32 }, + { ZD_CR46, 0x99 }, /* for newest(3rd cut) AL2230 */ + { ZD_CR47, 0x1e }, /* ZD1211B 05.06.10 */ - { CR48, 0x06 }, { CR49, 0xf9 }, { CR51, 0x01 }, - { CR52, 0x80 }, { CR53, 0x7e }, { CR65, 0x00 }, - { CR66, 0x00 }, { CR67, 0x00 }, { CR68, 0x00 }, - { CR69, 0x28 }, - - { CR79, 0x58 }, { CR80, 0x30 }, { CR81, 0x30 }, - { CR87, 0x0a }, { CR89, 0x04 }, - { CR91, 0x00 }, /* 5621 */ - { CR92, 0x0a }, - { CR98, 0x8d }, /* 4804, for 1212 new algorithm */ - { CR99, 0x00 }, /* 5621 */ - { CR101, 0x13 }, { CR102, 0x27 }, - { CR106, 0x24 }, /* for newest(3rd cut) AL2230 */ - { CR107, 0x2a }, - { CR109, 0x13 }, /* 4804, for 1212 new algorithm */ - { CR110, 0x1f }, /* 4804, for 1212 new algorithm */ - { CR111, 0x1f }, { CR112, 0x1f }, { CR113, 0x27 }, - { CR114, 0x27 }, - { CR115, 0x26 }, /* 24->26 at 4902 for newest(3rd cut) AL2230 */ - { CR116, 0x24 }, - { CR117, 0xfa }, /* for 1211b */ - { CR118, 0xfa }, /* for 1211b */ - { CR119, 0x10 }, - { CR120, 0x4f }, - { CR121, 0x6c }, /* for 1211b */ - { CR122, 0xfc }, /* E0->FC at 4902 */ - { CR123, 0x57 }, /* 5623 */ - { CR125, 0xad }, /* 4804, for 1212 new algorithm */ - { CR126, 0x6c }, /* 5614 */ - { CR127, 0x03 }, /* 4804, for 1212 new algorithm */ - { CR137, 0x50 }, /* 5614 */ - { CR138, 0xa8 }, - { CR144, 0xac }, /* 5621 */ - { CR150, 0x0d }, { CR252, 0x34 }, { CR253, 0x34 }, + { ZD_CR48, 0x06 }, { ZD_CR49, 0xf9 }, { ZD_CR51, 0x01 }, + { ZD_CR52, 0x80 }, { ZD_CR53, 0x7e }, { ZD_CR65, 0x00 }, + { ZD_CR66, 0x00 }, { ZD_CR67, 0x00 }, { ZD_CR68, 0x00 }, + { ZD_CR69, 0x28 }, + + { ZD_CR79, 0x58 }, { ZD_CR80, 0x30 }, { ZD_CR81, 0x30 }, + { ZD_CR87, 0x0a }, { ZD_CR89, 0x04 }, + { ZD_CR91, 0x00 }, /* 5621 */ + { ZD_CR92, 0x0a }, + { ZD_CR98, 0x8d }, /* 4804, for 1212 new algorithm */ + { ZD_CR99, 0x00 }, /* 5621 */ + { ZD_CR101, 0x13 }, { ZD_CR102, 0x27 }, + { ZD_CR106, 0x24 }, /* for newest(3rd cut) AL2230 */ + { ZD_CR107, 0x2a }, + { ZD_CR109, 0x13 }, /* 4804, for 1212 new algorithm */ + { ZD_CR110, 0x1f }, /* 4804, for 1212 new algorithm */ + { ZD_CR111, 0x1f }, { ZD_CR112, 0x1f }, { ZD_CR113, 0x27 }, + { ZD_CR114, 0x27 }, + { ZD_CR115, 0x26 }, /* 24->26 at 4902 for newest(3rd cut) + * AL2230 + */ + { ZD_CR116, 0x24 }, + { ZD_CR117, 0xfa }, /* for 1211b */ + { ZD_CR118, 0xfa }, /* for 1211b */ + { ZD_CR119, 0x10 }, + { ZD_CR120, 0x4f }, + { ZD_CR121, 0x6c }, /* for 1211b */ + { ZD_CR122, 0xfc }, /* E0->FC at 4902 */ + { ZD_CR123, 0x57 }, /* 5623 */ + { ZD_CR125, 0xad }, /* 4804, for 1212 new algorithm */ + { ZD_CR126, 0x6c }, /* 5614 */ + { ZD_CR127, 0x03 }, /* 4804, for 1212 new algorithm */ + { ZD_CR137, 0x50 }, /* 5614 */ + { ZD_CR138, 0xa8 }, + { ZD_CR144, 0xac }, /* 5621 */ + { ZD_CR150, 0x0d }, { ZD_CR252, 0x34 }, { ZD_CR253, 0x34 }, }; static const u32 rv1[] = { @@ -284,7 +286,7 @@ static int zd1211b_al2230_init_hw(struct zd_rf *rf) 0x6da010, /* Reg6 update for MP versio */ 0xe36280, /* Modified by jxiao for Bor-Chin on 2004/08/02 */ 0x116000, - 0x9dc020, /* External control TX power (CR31) */ + 0x9dc020, /* External control TX power (ZD_CR31) */ 0x5ddb00, /* RegA update for MP version */ 0xd99000, /* RegB update for MP version */ 0x3ffbd0, /* RegC update for MP version */ @@ -295,8 +297,8 @@ static int zd1211b_al2230_init_hw(struct zd_rf *rf) }; static const struct zd_ioreq16 ioreqs2[] = { - { CR251, 0x2f }, /* shdnb(PLL_ON)=0 */ - { CR251, 0x7f }, /* shdnb(PLL_ON)=1 */ + { ZD_CR251, 0x2f }, /* shdnb(PLL_ON)=0 */ + { ZD_CR251, 0x7f }, /* shdnb(PLL_ON)=1 */ }; static const u32 rv3[] = { @@ -308,7 +310,7 @@ static int zd1211b_al2230_init_hw(struct zd_rf *rf) static const struct zd_ioreq16 ioreqs3[] = { /* related to 6M band edge patching, happens unconditionally */ - { CR128, 0x14 }, { CR129, 0x12 }, { CR130, 0x10 }, + { ZD_CR128, 0x14 }, { ZD_CR129, 0x12 }, { ZD_CR130, 0x10 }, }; r = zd_iowrite16a_locked(chip, zd1211b_ioreqs_shared_1, @@ -361,8 +363,8 @@ static int zd1211_al2230_set_channel(struct zd_rf *rf, u8 channel) const u32 *rv = zd1211_al2230_table[channel-1]; struct zd_chip *chip = zd_rf_to_chip(rf); static const struct zd_ioreq16 ioreqs[] = { - { CR138, 0x28 }, - { CR203, 0x06 }, + { ZD_CR138, 0x28 }, + { ZD_CR203, 0x06 }, }; r = zd_rfwritev_locked(chip, rv, 3, RF_RV_BITS); @@ -393,8 +395,8 @@ static int zd1211_al2230_switch_radio_on(struct zd_rf *rf) { struct zd_chip *chip = zd_rf_to_chip(rf); static const struct zd_ioreq16 ioreqs[] = { - { CR11, 0x00 }, - { CR251, 0x3f }, + { ZD_CR11, 0x00 }, + { ZD_CR251, 0x3f }, }; return zd_iowrite16a_locked(chip, ioreqs, ARRAY_SIZE(ioreqs)); @@ -404,8 +406,8 @@ static int zd1211b_al2230_switch_radio_on(struct zd_rf *rf) { struct zd_chip *chip = zd_rf_to_chip(rf); static const struct zd_ioreq16 ioreqs[] = { - { CR11, 0x00 }, - { CR251, 0x7f }, + { ZD_CR11, 0x00 }, + { ZD_CR251, 0x7f }, }; return zd_iowrite16a_locked(chip, ioreqs, ARRAY_SIZE(ioreqs)); @@ -415,8 +417,8 @@ static int al2230_switch_radio_off(struct zd_rf *rf) { struct zd_chip *chip = zd_rf_to_chip(rf); static const struct zd_ioreq16 ioreqs[] = { - { CR11, 0x04 }, - { CR251, 0x2f }, + { ZD_CR11, 0x04 }, + { ZD_CR251, 0x2f }, }; return zd_iowrite16a_locked(chip, ioreqs, ARRAY_SIZE(ioreqs)); diff --git a/drivers/net/wireless/zd1211rw/zd_rf_al7230b.c b/drivers/net/wireless/zd1211rw/zd_rf_al7230b.c index 65095d6..385c670 100644 --- a/drivers/net/wireless/zd1211rw/zd_rf_al7230b.c +++ b/drivers/net/wireless/zd1211rw/zd_rf_al7230b.c @@ -68,19 +68,19 @@ static const u32 rv_init2[] = { }; static const struct zd_ioreq16 ioreqs_sw[] = { - { CR128, 0x14 }, { CR129, 0x12 }, { CR130, 0x10 }, - { CR38, 0x38 }, { CR136, 0xdf }, + { ZD_CR128, 0x14 }, { ZD_CR129, 0x12 }, { ZD_CR130, 0x10 }, + { ZD_CR38, 0x38 }, { ZD_CR136, 0xdf }, }; static int zd1211b_al7230b_finalize(struct zd_chip *chip) { int r; static const struct zd_ioreq16 ioreqs[] = { - { CR80, 0x30 }, { CR81, 0x30 }, { CR79, 0x58 }, - { CR12, 0xf0 }, { CR77, 0x1b }, { CR78, 0x58 }, - { CR203, 0x04 }, + { ZD_CR80, 0x30 }, { ZD_CR81, 0x30 }, { ZD_CR79, 0x58 }, + { ZD_CR12, 0xf0 }, { ZD_CR77, 0x1b }, { ZD_CR78, 0x58 }, + { ZD_CR203, 0x04 }, { }, - { CR240, 0x80 }, + { ZD_CR240, 0x80 }, }; r = zd_iowrite16a_locked(chip, ioreqs, ARRAY_SIZE(ioreqs)); @@ -89,12 +89,12 @@ static int zd1211b_al7230b_finalize(struct zd_chip *chip) if (chip->new_phy_layout) { /* antenna selection? */ - r = zd_iowrite16_locked(chip, 0xe5, CR9); + r = zd_iowrite16_locked(chip, 0xe5, ZD_CR9); if (r) return r; } - return zd_iowrite16_locked(chip, 0x04, CR203); + return zd_iowrite16_locked(chip, 0x04, ZD_CR203); } static int zd1211_al7230b_init_hw(struct zd_rf *rf) @@ -106,66 +106,66 @@ static int zd1211_al7230b_init_hw(struct zd_rf *rf) * specified */ static const struct zd_ioreq16 ioreqs_1[] = { /* This one is 7230-specific, and happens before the rest */ - { CR240, 0x57 }, + { ZD_CR240, 0x57 }, { }, - { CR15, 0x20 }, { CR23, 0x40 }, { CR24, 0x20 }, - { CR26, 0x11 }, { CR28, 0x3e }, { CR29, 0x00 }, - { CR44, 0x33 }, + { ZD_CR15, 0x20 }, { ZD_CR23, 0x40 }, { ZD_CR24, 0x20 }, + { ZD_CR26, 0x11 }, { ZD_CR28, 0x3e }, { ZD_CR29, 0x00 }, + { ZD_CR44, 0x33 }, /* This value is different for 7230 (was: 0x2a) */ - { CR106, 0x22 }, - { CR107, 0x1a }, { CR109, 0x09 }, { CR110, 0x27 }, - { CR111, 0x2b }, { CR112, 0x2b }, { CR119, 0x0a }, + { ZD_CR106, 0x22 }, + { ZD_CR107, 0x1a }, { ZD_CR109, 0x09 }, { ZD_CR110, 0x27 }, + { ZD_CR111, 0x2b }, { ZD_CR112, 0x2b }, { ZD_CR119, 0x0a }, /* This happened further down in AL2230, * and the value changed (was: 0xe0) */ - { CR122, 0xfc }, - { CR10, 0x89 }, + { ZD_CR122, 0xfc }, + { ZD_CR10, 0x89 }, /* for newest (3rd cut) AL2300 */ - { CR17, 0x28 }, - { CR26, 0x93 }, { CR34, 0x30 }, + { ZD_CR17, 0x28 }, + { ZD_CR26, 0x93 }, { ZD_CR34, 0x30 }, /* for newest (3rd cut) AL2300 */ - { CR35, 0x3e }, - { CR41, 0x24 }, { CR44, 0x32 }, + { ZD_CR35, 0x3e }, + { ZD_CR41, 0x24 }, { ZD_CR44, 0x32 }, /* for newest (3rd cut) AL2300 */ - { CR46, 0x96 }, - { CR47, 0x1e }, { CR79, 0x58 }, { CR80, 0x30 }, - { CR81, 0x30 }, { CR87, 0x0a }, { CR89, 0x04 }, - { CR92, 0x0a }, { CR99, 0x28 }, + { ZD_CR46, 0x96 }, + { ZD_CR47, 0x1e }, { ZD_CR79, 0x58 }, { ZD_CR80, 0x30 }, + { ZD_CR81, 0x30 }, { ZD_CR87, 0x0a }, { ZD_CR89, 0x04 }, + { ZD_CR92, 0x0a }, { ZD_CR99, 0x28 }, /* This value is different for 7230 (was: 0x00) */ - { CR100, 0x02 }, - { CR101, 0x13 }, { CR102, 0x27 }, + { ZD_CR100, 0x02 }, + { ZD_CR101, 0x13 }, { ZD_CR102, 0x27 }, /* This value is different for 7230 (was: 0x24) */ - { CR106, 0x22 }, + { ZD_CR106, 0x22 }, /* This value is different for 7230 (was: 0x2a) */ - { CR107, 0x3f }, - { CR109, 0x09 }, + { ZD_CR107, 0x3f }, + { ZD_CR109, 0x09 }, /* This value is different for 7230 (was: 0x13) */ - { CR110, 0x1f }, - { CR111, 0x1f }, { CR112, 0x1f }, { CR113, 0x27 }, - { CR114, 0x27 }, + { ZD_CR110, 0x1f }, + { ZD_CR111, 0x1f }, { ZD_CR112, 0x1f }, { ZD_CR113, 0x27 }, + { ZD_CR114, 0x27 }, /* for newest (3rd cut) AL2300 */ - { CR115, 0x24 }, + { ZD_CR115, 0x24 }, /* This value is different for 7230 (was: 0x24) */ - { CR116, 0x3f }, + { ZD_CR116, 0x3f }, /* This value is different for 7230 (was: 0xf4) */ - { CR117, 0xfa }, - { CR118, 0xfc }, { CR119, 0x10 }, { CR120, 0x4f }, - { CR121, 0x77 }, { CR137, 0x88 }, + { ZD_CR117, 0xfa }, + { ZD_CR118, 0xfc }, { ZD_CR119, 0x10 }, { ZD_CR120, 0x4f }, + { ZD_CR121, 0x77 }, { ZD_CR137, 0x88 }, /* This one is 7230-specific */ - { CR138, 0xa8 }, + { ZD_CR138, 0xa8 }, /* This value is different for 7230 (was: 0xff) */ - { CR252, 0x34 }, + { ZD_CR252, 0x34 }, /* This value is different for 7230 (was: 0xff) */ - { CR253, 0x34 }, + { ZD_CR253, 0x34 }, /* PLL_OFF */ - { CR251, 0x2f }, + { ZD_CR251, 0x2f }, }; static const struct zd_ioreq16 ioreqs_2[] = { - { CR251, 0x3f }, /* PLL_ON */ - { CR128, 0x14 }, { CR129, 0x12 }, { CR130, 0x10 }, - { CR38, 0x38 }, { CR136, 0xdf }, + { ZD_CR251, 0x3f }, /* PLL_ON */ + { ZD_CR128, 0x14 }, { ZD_CR129, 0x12 }, { ZD_CR130, 0x10 }, + { ZD_CR38, 0x38 }, { ZD_CR136, 0xdf }, }; r = zd_iowrite16a_locked(chip, ioreqs_1, ARRAY_SIZE(ioreqs_1)); @@ -192,10 +192,10 @@ static int zd1211_al7230b_init_hw(struct zd_rf *rf) if (r) return r; - r = zd_iowrite16_locked(chip, 0x06, CR203); + r = zd_iowrite16_locked(chip, 0x06, ZD_CR203); if (r) return r; - r = zd_iowrite16_locked(chip, 0x80, CR240); + r = zd_iowrite16_locked(chip, 0x80, ZD_CR240); if (r) return r; @@ -208,79 +208,79 @@ static int zd1211b_al7230b_init_hw(struct zd_rf *rf) struct zd_chip *chip = zd_rf_to_chip(rf); static const struct zd_ioreq16 ioreqs_1[] = { - { CR240, 0x57 }, { CR9, 0x9 }, + { ZD_CR240, 0x57 }, { ZD_CR9, 0x9 }, { }, - { CR10, 0x8b }, { CR15, 0x20 }, - { CR17, 0x2B }, /* for newest (3rd cut) AL2230 */ - { CR20, 0x10 }, /* 4N25->Stone Request */ - { CR23, 0x40 }, { CR24, 0x20 }, { CR26, 0x93 }, - { CR28, 0x3e }, { CR29, 0x00 }, - { CR33, 0x28 }, /* 5613 */ - { CR34, 0x30 }, - { CR35, 0x3e }, /* for newest (3rd cut) AL2230 */ - { CR41, 0x24 }, { CR44, 0x32 }, - { CR46, 0x99 }, /* for newest (3rd cut) AL2230 */ - { CR47, 0x1e }, + { ZD_CR10, 0x8b }, { ZD_CR15, 0x20 }, + { ZD_CR17, 0x2B }, /* for newest (3rd cut) AL2230 */ + { ZD_CR20, 0x10 }, /* 4N25->Stone Request */ + { ZD_CR23, 0x40 }, { ZD_CR24, 0x20 }, { ZD_CR26, 0x93 }, + { ZD_CR28, 0x3e }, { ZD_CR29, 0x00 }, + { ZD_CR33, 0x28 }, /* 5613 */ + { ZD_CR34, 0x30 }, + { ZD_CR35, 0x3e }, /* for newest (3rd cut) AL2230 */ + { ZD_CR41, 0x24 }, { ZD_CR44, 0x32 }, + { ZD_CR46, 0x99 }, /* for newest (3rd cut) AL2230 */ + { ZD_CR47, 0x1e }, /* ZD1215 5610 */ - { CR48, 0x00 }, { CR49, 0x00 }, { CR51, 0x01 }, - { CR52, 0x80 }, { CR53, 0x7e }, { CR65, 0x00 }, - { CR66, 0x00 }, { CR67, 0x00 }, { CR68, 0x00 }, - { CR69, 0x28 }, - - { CR79, 0x58 }, { CR80, 0x30 }, { CR81, 0x30 }, - { CR87, 0x0A }, { CR89, 0x04 }, - { CR90, 0x58 }, /* 5112 */ - { CR91, 0x00 }, /* 5613 */ - { CR92, 0x0a }, - { CR98, 0x8d }, /* 4804, for 1212 new algorithm */ - { CR99, 0x00 }, { CR100, 0x02 }, { CR101, 0x13 }, - { CR102, 0x27 }, - { CR106, 0x20 }, /* change to 0x24 for AL7230B */ - { CR109, 0x13 }, /* 4804, for 1212 new algorithm */ - { CR112, 0x1f }, + { ZD_CR48, 0x00 }, { ZD_CR49, 0x00 }, { ZD_CR51, 0x01 }, + { ZD_CR52, 0x80 }, { ZD_CR53, 0x7e }, { ZD_CR65, 0x00 }, + { ZD_CR66, 0x00 }, { ZD_CR67, 0x00 }, { ZD_CR68, 0x00 }, + { ZD_CR69, 0x28 }, + + { ZD_CR79, 0x58 }, { ZD_CR80, 0x30 }, { ZD_CR81, 0x30 }, + { ZD_CR87, 0x0A }, { ZD_CR89, 0x04 }, + { ZD_CR90, 0x58 }, /* 5112 */ + { ZD_CR91, 0x00 }, /* 5613 */ + { ZD_CR92, 0x0a }, + { ZD_CR98, 0x8d }, /* 4804, for 1212 new algorithm */ + { ZD_CR99, 0x00 }, { ZD_CR100, 0x02 }, { ZD_CR101, 0x13 }, + { ZD_CR102, 0x27 }, + { ZD_CR106, 0x20 }, /* change to 0x24 for AL7230B */ + { ZD_CR109, 0x13 }, /* 4804, for 1212 new algorithm */ + { ZD_CR112, 0x1f }, }; static const struct zd_ioreq16 ioreqs_new_phy[] = { - { CR107, 0x28 }, - { CR110, 0x1f }, /* 5127, 0x13->0x1f */ - { CR111, 0x1f }, /* 0x13 to 0x1f for AL7230B */ - { CR116, 0x2a }, { CR118, 0xfa }, { CR119, 0x12 }, - { CR121, 0x6c }, /* 5613 */ + { ZD_CR107, 0x28 }, + { ZD_CR110, 0x1f }, /* 5127, 0x13->0x1f */ + { ZD_CR111, 0x1f }, /* 0x13 to 0x1f for AL7230B */ + { ZD_CR116, 0x2a }, { ZD_CR118, 0xfa }, { ZD_CR119, 0x12 }, + { ZD_CR121, 0x6c }, /* 5613 */ }; static const struct zd_ioreq16 ioreqs_old_phy[] = { - { CR107, 0x24 }, - { CR110, 0x13 }, /* 5127, 0x13->0x1f */ - { CR111, 0x13 }, /* 0x13 to 0x1f for AL7230B */ - { CR116, 0x24 }, { CR118, 0xfc }, { CR119, 0x11 }, - { CR121, 0x6a }, /* 5613 */ + { ZD_CR107, 0x24 }, + { ZD_CR110, 0x13 }, /* 5127, 0x13->0x1f */ + { ZD_CR111, 0x13 }, /* 0x13 to 0x1f for AL7230B */ + { ZD_CR116, 0x24 }, { ZD_CR118, 0xfc }, { ZD_CR119, 0x11 }, + { ZD_CR121, 0x6a }, /* 5613 */ }; static const struct zd_ioreq16 ioreqs_2[] = { - { CR113, 0x27 }, { CR114, 0x27 }, { CR115, 0x24 }, - { CR117, 0xfa }, { CR120, 0x4f }, - { CR122, 0xfc }, /* E0->FCh at 4901 */ - { CR123, 0x57 }, /* 5613 */ - { CR125, 0xad }, /* 4804, for 1212 new algorithm */ - { CR126, 0x6c }, /* 5613 */ - { CR127, 0x03 }, /* 4804, for 1212 new algorithm */ - { CR130, 0x10 }, - { CR131, 0x00 }, /* 5112 */ - { CR137, 0x50 }, /* 5613 */ - { CR138, 0xa8 }, /* 5112 */ - { CR144, 0xac }, /* 5613 */ - { CR148, 0x40 }, /* 5112 */ - { CR149, 0x40 }, /* 4O07, 50->40 */ - { CR150, 0x1a }, /* 5112, 0C->1A */ - { CR252, 0x34 }, { CR253, 0x34 }, - { CR251, 0x2f }, /* PLL_OFF */ + { ZD_CR113, 0x27 }, { ZD_CR114, 0x27 }, { ZD_CR115, 0x24 }, + { ZD_CR117, 0xfa }, { ZD_CR120, 0x4f }, + { ZD_CR122, 0xfc }, /* E0->FCh at 4901 */ + { ZD_CR123, 0x57 }, /* 5613 */ + { ZD_CR125, 0xad }, /* 4804, for 1212 new algorithm */ + { ZD_CR126, 0x6c }, /* 5613 */ + { ZD_CR127, 0x03 }, /* 4804, for 1212 new algorithm */ + { ZD_CR130, 0x10 }, + { ZD_CR131, 0x00 }, /* 5112 */ + { ZD_CR137, 0x50 }, /* 5613 */ + { ZD_CR138, 0xa8 }, /* 5112 */ + { ZD_CR144, 0xac }, /* 5613 */ + { ZD_CR148, 0x40 }, /* 5112 */ + { ZD_CR149, 0x40 }, /* 4O07, 50->40 */ + { ZD_CR150, 0x1a }, /* 5112, 0C->1A */ + { ZD_CR252, 0x34 }, { ZD_CR253, 0x34 }, + { ZD_CR251, 0x2f }, /* PLL_OFF */ }; static const struct zd_ioreq16 ioreqs_3[] = { - { CR251, 0x7f }, /* PLL_ON */ - { CR128, 0x14 }, { CR129, 0x12 }, { CR130, 0x10 }, - { CR38, 0x38 }, { CR136, 0xdf }, + { ZD_CR251, 0x7f }, /* PLL_ON */ + { ZD_CR128, 0x14 }, { ZD_CR129, 0x12 }, { ZD_CR130, 0x10 }, + { ZD_CR38, 0x38 }, { ZD_CR136, 0xdf }, }; r = zd_iowrite16a_locked(chip, ioreqs_1, ARRAY_SIZE(ioreqs_1)); @@ -331,16 +331,16 @@ static int zd1211_al7230b_set_channel(struct zd_rf *rf, u8 channel) static const struct zd_ioreq16 ioreqs[] = { /* PLL_ON */ - { CR251, 0x3f }, - { CR203, 0x06 }, { CR240, 0x08 }, + { ZD_CR251, 0x3f }, + { ZD_CR203, 0x06 }, { ZD_CR240, 0x08 }, }; - r = zd_iowrite16_locked(chip, 0x57, CR240); + r = zd_iowrite16_locked(chip, 0x57, ZD_CR240); if (r) return r; /* PLL_OFF */ - r = zd_iowrite16_locked(chip, 0x2f, CR251); + r = zd_iowrite16_locked(chip, 0x2f, ZD_CR251); if (r) return r; @@ -376,15 +376,15 @@ static int zd1211b_al7230b_set_channel(struct zd_rf *rf, u8 channel) const u32 *rv = chan_rv[channel-1]; struct zd_chip *chip = zd_rf_to_chip(rf); - r = zd_iowrite16_locked(chip, 0x57, CR240); + r = zd_iowrite16_locked(chip, 0x57, ZD_CR240); if (r) return r; - r = zd_iowrite16_locked(chip, 0xe4, CR9); + r = zd_iowrite16_locked(chip, 0xe4, ZD_CR9); if (r) return r; /* PLL_OFF */ - r = zd_iowrite16_locked(chip, 0x2f, CR251); + r = zd_iowrite16_locked(chip, 0x2f, ZD_CR251); if (r) return r; r = zd_rfwritev_cr_locked(chip, std_rv, ARRAY_SIZE(std_rv)); @@ -410,7 +410,7 @@ static int zd1211b_al7230b_set_channel(struct zd_rf *rf, u8 channel) if (r) return r; - r = zd_iowrite16_locked(chip, 0x7f, CR251); + r = zd_iowrite16_locked(chip, 0x7f, ZD_CR251); if (r) return r; @@ -421,8 +421,8 @@ static int zd1211_al7230b_switch_radio_on(struct zd_rf *rf) { struct zd_chip *chip = zd_rf_to_chip(rf); static const struct zd_ioreq16 ioreqs[] = { - { CR11, 0x00 }, - { CR251, 0x3f }, + { ZD_CR11, 0x00 }, + { ZD_CR251, 0x3f }, }; return zd_iowrite16a_locked(chip, ioreqs, ARRAY_SIZE(ioreqs)); @@ -432,8 +432,8 @@ static int zd1211b_al7230b_switch_radio_on(struct zd_rf *rf) { struct zd_chip *chip = zd_rf_to_chip(rf); static const struct zd_ioreq16 ioreqs[] = { - { CR11, 0x00 }, - { CR251, 0x7f }, + { ZD_CR11, 0x00 }, + { ZD_CR251, 0x7f }, }; return zd_iowrite16a_locked(chip, ioreqs, ARRAY_SIZE(ioreqs)); @@ -443,8 +443,8 @@ static int al7230b_switch_radio_off(struct zd_rf *rf) { struct zd_chip *chip = zd_rf_to_chip(rf); static const struct zd_ioreq16 ioreqs[] = { - { CR11, 0x04 }, - { CR251, 0x2f }, + { ZD_CR11, 0x04 }, + { ZD_CR251, 0x2f }, }; return zd_iowrite16a_locked(chip, ioreqs, ARRAY_SIZE(ioreqs)); @@ -456,7 +456,7 @@ static int zd1211b_al7230b_patch_6m(struct zd_rf *rf, u8 channel) { struct zd_chip *chip = zd_rf_to_chip(rf); struct zd_ioreq16 ioreqs[] = { - { CR128, 0x14 }, { CR129, 0x12 }, + { ZD_CR128, 0x14 }, { ZD_CR129, 0x12 }, }; /* FIXME: Channel 11 is not the edge for all regulatory domains. */ diff --git a/drivers/net/wireless/zd1211rw/zd_rf_rf2959.c b/drivers/net/wireless/zd1211rw/zd_rf_rf2959.c index 0597d86..03254261 100644 --- a/drivers/net/wireless/zd1211rw/zd_rf_rf2959.c +++ b/drivers/net/wireless/zd1211rw/zd_rf_rf2959.c @@ -152,44 +152,44 @@ static int rf2959_init_hw(struct zd_rf *rf) struct zd_chip *chip = zd_rf_to_chip(rf); static const struct zd_ioreq16 ioreqs[] = { - { CR2, 0x1E }, { CR9, 0x20 }, { CR10, 0x89 }, - { CR11, 0x00 }, { CR15, 0xD0 }, { CR17, 0x68 }, - { CR19, 0x4a }, { CR20, 0x0c }, { CR21, 0x0E }, - { CR23, 0x48 }, + { ZD_CR2, 0x1E }, { ZD_CR9, 0x20 }, { ZD_CR10, 0x89 }, + { ZD_CR11, 0x00 }, { ZD_CR15, 0xD0 }, { ZD_CR17, 0x68 }, + { ZD_CR19, 0x4a }, { ZD_CR20, 0x0c }, { ZD_CR21, 0x0E }, + { ZD_CR23, 0x48 }, /* normal size for cca threshold */ - { CR24, 0x14 }, - /* { CR24, 0x20 }, */ - { CR26, 0x90 }, { CR27, 0x30 }, { CR29, 0x20 }, - { CR31, 0xb2 }, { CR32, 0x43 }, { CR33, 0x28 }, - { CR38, 0x30 }, { CR34, 0x0f }, { CR35, 0xF0 }, - { CR41, 0x2a }, { CR46, 0x7F }, { CR47, 0x1E }, - { CR51, 0xc5 }, { CR52, 0xc5 }, { CR53, 0xc5 }, - { CR79, 0x58 }, { CR80, 0x30 }, { CR81, 0x30 }, - { CR82, 0x00 }, { CR83, 0x24 }, { CR84, 0x04 }, - { CR85, 0x00 }, { CR86, 0x10 }, { CR87, 0x2A }, - { CR88, 0x10 }, { CR89, 0x24 }, { CR90, 0x18 }, - /* { CR91, 0x18 }, */ + { ZD_CR24, 0x14 }, + /* { ZD_CR24, 0x20 }, */ + { ZD_CR26, 0x90 }, { ZD_CR27, 0x30 }, { ZD_CR29, 0x20 }, + { ZD_CR31, 0xb2 }, { ZD_CR32, 0x43 }, { ZD_CR33, 0x28 }, + { ZD_CR38, 0x30 }, { ZD_CR34, 0x0f }, { ZD_CR35, 0xF0 }, + { ZD_CR41, 0x2a }, { ZD_CR46, 0x7F }, { ZD_CR47, 0x1E }, + { ZD_CR51, 0xc5 }, { ZD_CR52, 0xc5 }, { ZD_CR53, 0xc5 }, + { ZD_CR79, 0x58 }, { ZD_CR80, 0x30 }, { ZD_CR81, 0x30 }, + { ZD_CR82, 0x00 }, { ZD_CR83, 0x24 }, { ZD_CR84, 0x04 }, + { ZD_CR85, 0x00 }, { ZD_CR86, 0x10 }, { ZD_CR87, 0x2A }, + { ZD_CR88, 0x10 }, { ZD_CR89, 0x24 }, { ZD_CR90, 0x18 }, + /* { ZD_CR91, 0x18 }, */ /* should solve continous CTS frame problems */ - { CR91, 0x00 }, - { CR92, 0x0a }, { CR93, 0x00 }, { CR94, 0x01 }, - { CR95, 0x00 }, { CR96, 0x40 }, { CR97, 0x37 }, - { CR98, 0x05 }, { CR99, 0x28 }, { CR100, 0x00 }, - { CR101, 0x13 }, { CR102, 0x27 }, { CR103, 0x27 }, - { CR104, 0x18 }, { CR105, 0x12 }, + { ZD_CR91, 0x00 }, + { ZD_CR92, 0x0a }, { ZD_CR93, 0x00 }, { ZD_CR94, 0x01 }, + { ZD_CR95, 0x00 }, { ZD_CR96, 0x40 }, { ZD_CR97, 0x37 }, + { ZD_CR98, 0x05 }, { ZD_CR99, 0x28 }, { ZD_CR100, 0x00 }, + { ZD_CR101, 0x13 }, { ZD_CR102, 0x27 }, { ZD_CR103, 0x27 }, + { ZD_CR104, 0x18 }, { ZD_CR105, 0x12 }, /* normal size */ - { CR106, 0x1a }, - /* { CR106, 0x22 }, */ - { CR107, 0x24 }, { CR108, 0x0a }, { CR109, 0x13 }, - { CR110, 0x2F }, { CR111, 0x27 }, { CR112, 0x27 }, - { CR113, 0x27 }, { CR114, 0x27 }, { CR115, 0x40 }, - { CR116, 0x40 }, { CR117, 0xF0 }, { CR118, 0xF0 }, - { CR119, 0x16 }, + { ZD_CR106, 0x1a }, + /* { ZD_CR106, 0x22 }, */ + { ZD_CR107, 0x24 }, { ZD_CR108, 0x0a }, { ZD_CR109, 0x13 }, + { ZD_CR110, 0x2F }, { ZD_CR111, 0x27 }, { ZD_CR112, 0x27 }, + { ZD_CR113, 0x27 }, { ZD_CR114, 0x27 }, { ZD_CR115, 0x40 }, + { ZD_CR116, 0x40 }, { ZD_CR117, 0xF0 }, { ZD_CR118, 0xF0 }, + { ZD_CR119, 0x16 }, /* no TX continuation */ - { CR122, 0x00 }, - /* { CR122, 0xff }, */ - { CR127, 0x03 }, { CR131, 0x08 }, { CR138, 0x28 }, - { CR148, 0x44 }, { CR150, 0x10 }, { CR169, 0xBB }, - { CR170, 0xBB }, + { ZD_CR122, 0x00 }, + /* { ZD_CR122, 0xff }, */ + { ZD_CR127, 0x03 }, { ZD_CR131, 0x08 }, { ZD_CR138, 0x28 }, + { ZD_CR148, 0x44 }, { ZD_CR150, 0x10 }, { ZD_CR169, 0xBB }, + { ZD_CR170, 0xBB }, }; static const u32 rv[] = { @@ -210,7 +210,7 @@ static int rf2959_init_hw(struct zd_rf *rf) */ 0x294128, /* internal power */ /* 0x28252c, */ /* External control TX power */ - /* CR31_CCK, CR51_6-36M, CR52_48M, CR53_54M */ + /* ZD_CR31_CCK, ZD_CR51_6-36M, ZD_CR52_48M, ZD_CR53_54M */ 0x2c0000, 0x300000, 0x340000, /* REG13(0xD) */ @@ -245,8 +245,8 @@ static int rf2959_set_channel(struct zd_rf *rf, u8 channel) static int rf2959_switch_radio_on(struct zd_rf *rf) { static const struct zd_ioreq16 ioreqs[] = { - { CR10, 0x89 }, - { CR11, 0x00 }, + { ZD_CR10, 0x89 }, + { ZD_CR11, 0x00 }, }; struct zd_chip *chip = zd_rf_to_chip(rf); @@ -256,8 +256,8 @@ static int rf2959_switch_radio_on(struct zd_rf *rf) static int rf2959_switch_radio_off(struct zd_rf *rf) { static const struct zd_ioreq16 ioreqs[] = { - { CR10, 0x15 }, - { CR11, 0x81 }, + { ZD_CR10, 0x15 }, + { ZD_CR11, 0x81 }, }; struct zd_chip *chip = zd_rf_to_chip(rf); diff --git a/drivers/net/wireless/zd1211rw/zd_rf_uw2453.c b/drivers/net/wireless/zd1211rw/zd_rf_uw2453.c index 9e74eb1..860b0af 100644 --- a/drivers/net/wireless/zd1211rw/zd_rf_uw2453.c +++ b/drivers/net/wireless/zd1211rw/zd_rf_uw2453.c @@ -314,42 +314,44 @@ static int uw2453_init_hw(struct zd_rf *rf) struct zd_chip *chip = zd_rf_to_chip(rf); static const struct zd_ioreq16 ioreqs[] = { - { CR10, 0x89 }, { CR15, 0x20 }, - { CR17, 0x28 }, /* 6112 no change */ - { CR23, 0x38 }, { CR24, 0x20 }, { CR26, 0x93 }, - { CR27, 0x15 }, { CR28, 0x3e }, { CR29, 0x00 }, - { CR33, 0x28 }, { CR34, 0x30 }, - { CR35, 0x43 }, /* 6112 3e->43 */ - { CR41, 0x24 }, { CR44, 0x32 }, - { CR46, 0x92 }, /* 6112 96->92 */ - { CR47, 0x1e }, - { CR48, 0x04 }, /* 5602 Roger */ - { CR49, 0xfa }, { CR79, 0x58 }, { CR80, 0x30 }, - { CR81, 0x30 }, { CR87, 0x0a }, { CR89, 0x04 }, - { CR91, 0x00 }, { CR92, 0x0a }, { CR98, 0x8d }, - { CR99, 0x28 }, { CR100, 0x02 }, - { CR101, 0x09 }, /* 6112 13->1f 6220 1f->13 6407 13->9 */ - { CR102, 0x27 }, - { CR106, 0x1c }, /* 5d07 5112 1f->1c 6220 1c->1f 6221 1f->1c */ - { CR107, 0x1c }, /* 6220 1c->1a 5221 1a->1c */ - { CR109, 0x13 }, - { CR110, 0x1f }, /* 6112 13->1f 6221 1f->13 6407 13->0x09 */ - { CR111, 0x13 }, { CR112, 0x1f }, { CR113, 0x27 }, - { CR114, 0x23 }, /* 6221 27->23 */ - { CR115, 0x24 }, /* 6112 24->1c 6220 1c->24 */ - { CR116, 0x24 }, /* 6220 1c->24 */ - { CR117, 0xfa }, /* 6112 fa->f8 6220 f8->f4 6220 f4->fa */ - { CR118, 0xf0 }, /* 5d07 6112 f0->f2 6220 f2->f0 */ - { CR119, 0x1a }, /* 6112 1a->10 6220 10->14 6220 14->1a */ - { CR120, 0x4f }, - { CR121, 0x1f }, /* 6220 4f->1f */ - { CR122, 0xf0 }, { CR123, 0x57 }, { CR125, 0xad }, - { CR126, 0x6c }, { CR127, 0x03 }, - { CR128, 0x14 }, /* 6302 12->11 */ - { CR129, 0x12 }, /* 6301 10->0f */ - { CR130, 0x10 }, { CR137, 0x50 }, { CR138, 0xa8 }, - { CR144, 0xac }, { CR146, 0x20 }, { CR252, 0xff }, - { CR253, 0xff }, + { ZD_CR10, 0x89 }, { ZD_CR15, 0x20 }, + { ZD_CR17, 0x28 }, /* 6112 no change */ + { ZD_CR23, 0x38 }, { ZD_CR24, 0x20 }, { ZD_CR26, 0x93 }, + { ZD_CR27, 0x15 }, { ZD_CR28, 0x3e }, { ZD_CR29, 0x00 }, + { ZD_CR33, 0x28 }, { ZD_CR34, 0x30 }, + { ZD_CR35, 0x43 }, /* 6112 3e->43 */ + { ZD_CR41, 0x24 }, { ZD_CR44, 0x32 }, + { ZD_CR46, 0x92 }, /* 6112 96->92 */ + { ZD_CR47, 0x1e }, + { ZD_CR48, 0x04 }, /* 5602 Roger */ + { ZD_CR49, 0xfa }, { ZD_CR79, 0x58 }, { ZD_CR80, 0x30 }, + { ZD_CR81, 0x30 }, { ZD_CR87, 0x0a }, { ZD_CR89, 0x04 }, + { ZD_CR91, 0x00 }, { ZD_CR92, 0x0a }, { ZD_CR98, 0x8d }, + { ZD_CR99, 0x28 }, { ZD_CR100, 0x02 }, + { ZD_CR101, 0x09 }, /* 6112 13->1f 6220 1f->13 6407 13->9 */ + { ZD_CR102, 0x27 }, + { ZD_CR106, 0x1c }, /* 5d07 5112 1f->1c 6220 1c->1f + * 6221 1f->1c + */ + { ZD_CR107, 0x1c }, /* 6220 1c->1a 5221 1a->1c */ + { ZD_CR109, 0x13 }, + { ZD_CR110, 0x1f }, /* 6112 13->1f 6221 1f->13 6407 13->0x09 */ + { ZD_CR111, 0x13 }, { ZD_CR112, 0x1f }, { ZD_CR113, 0x27 }, + { ZD_CR114, 0x23 }, /* 6221 27->23 */ + { ZD_CR115, 0x24 }, /* 6112 24->1c 6220 1c->24 */ + { ZD_CR116, 0x24 }, /* 6220 1c->24 */ + { ZD_CR117, 0xfa }, /* 6112 fa->f8 6220 f8->f4 6220 f4->fa */ + { ZD_CR118, 0xf0 }, /* 5d07 6112 f0->f2 6220 f2->f0 */ + { ZD_CR119, 0x1a }, /* 6112 1a->10 6220 10->14 6220 14->1a */ + { ZD_CR120, 0x4f }, + { ZD_CR121, 0x1f }, /* 6220 4f->1f */ + { ZD_CR122, 0xf0 }, { ZD_CR123, 0x57 }, { ZD_CR125, 0xad }, + { ZD_CR126, 0x6c }, { ZD_CR127, 0x03 }, + { ZD_CR128, 0x14 }, /* 6302 12->11 */ + { ZD_CR129, 0x12 }, /* 6301 10->0f */ + { ZD_CR130, 0x10 }, { ZD_CR137, 0x50 }, { ZD_CR138, 0xa8 }, + { ZD_CR144, 0xac }, { ZD_CR146, 0x20 }, { ZD_CR252, 0xff }, + { ZD_CR253, 0xff }, }; static const u32 rv[] = { @@ -433,7 +435,7 @@ static int uw2453_init_hw(struct zd_rf *rf) * the one that produced a lock. */ UW2453_PRIV(rf)->config = found_config + 1; - return zd_iowrite16_locked(chip, 0x06, CR203); + return zd_iowrite16_locked(chip, 0x06, ZD_CR203); } static int uw2453_set_channel(struct zd_rf *rf, u8 channel) @@ -445,8 +447,8 @@ static int uw2453_set_channel(struct zd_rf *rf, u8 channel) struct zd_chip *chip = zd_rf_to_chip(rf); static const struct zd_ioreq16 ioreqs[] = { - { CR80, 0x30 }, { CR81, 0x30 }, { CR79, 0x58 }, - { CR12, 0xf0 }, { CR77, 0x1b }, { CR78, 0x58 }, + { ZD_CR80, 0x30 }, { ZD_CR81, 0x30 }, { ZD_CR79, 0x58 }, + { ZD_CR12, 0xf0 }, { ZD_CR77, 0x1b }, { ZD_CR78, 0x58 }, }; r = uw2453_synth_set_channel(chip, channel, autocal); @@ -474,7 +476,7 @@ static int uw2453_set_channel(struct zd_rf *rf, u8 channel) if (r) return r; - return zd_iowrite16_locked(chip, 0x06, CR203); + return zd_iowrite16_locked(chip, 0x06, ZD_CR203); } static int uw2453_switch_radio_on(struct zd_rf *rf) @@ -482,7 +484,7 @@ static int uw2453_switch_radio_on(struct zd_rf *rf) int r; struct zd_chip *chip = zd_rf_to_chip(rf); struct zd_ioreq16 ioreqs[] = { - { CR11, 0x00 }, { CR251, 0x3f }, + { ZD_CR11, 0x00 }, { ZD_CR251, 0x3f }, }; /* enter RXTX mode */ @@ -501,7 +503,7 @@ static int uw2453_switch_radio_off(struct zd_rf *rf) int r; struct zd_chip *chip = zd_rf_to_chip(rf); static const struct zd_ioreq16 ioreqs[] = { - { CR11, 0x04 }, { CR251, 0x2f }, + { ZD_CR11, 0x04 }, { ZD_CR251, 0x2f }, }; /* enter IDLE mode */ diff --git a/drivers/net/wireless/zd1211rw/zd_usb.c b/drivers/net/wireless/zd1211rw/zd_usb.c index 58236e6..c9c1362 100644 --- a/drivers/net/wireless/zd1211rw/zd_usb.c +++ b/drivers/net/wireless/zd1211rw/zd_usb.c @@ -1877,10 +1877,10 @@ int zd_usb_rfwrite(struct zd_usb *usb, u32 value, u8 bits) dev_dbg_f(zd_usb_dev(usb), "value %#09x bits %d\n", value, bits); - r = zd_usb_ioread16(usb, &bit_value_template, CR203); + r = zd_usb_ioread16(usb, &bit_value_template, ZD_CR203); if (r) { dev_dbg_f(zd_usb_dev(usb), - "error %d: Couldn't read CR203\n", r); + "error %d: Couldn't read ZD_CR203\n", r); return r; } bit_value_template &= ~(RF_IF_LE|RF_CLK|RF_DATA); diff --git a/drivers/net/wireless/zd1211rw/zd_usb.h b/drivers/net/wireless/zd1211rw/zd_usb.h index b3df2c8..3924258 100644 --- a/drivers/net/wireless/zd1211rw/zd_usb.h +++ b/drivers/net/wireless/zd1211rw/zd_usb.h @@ -109,7 +109,7 @@ struct usb_req_rfwrite { __le16 bits; /* RF2595: 24 */ __le16 bit_values[0]; - /* (CR203 & ~(RF_IF_LE | RF_CLK | RF_DATA)) | (bit ? RF_DATA : 0) */ + /* (ZD_CR203 & ~(RF_IF_LE | RF_CLK | RF_DATA)) | (bit ? RF_DATA : 0) */ } __packed; /* USB interrupt */ -- cgit v0.10.2 From ffbd308dce898a857de76d17cc05748505cf4ece Mon Sep 17 00:00:00 2001 From: Mohammed Shafi Shajakhan Date: Sun, 3 Apr 2011 19:05:28 +0530 Subject: mac80211: remove few obsolete flags Signed-off-by: Mohammed Shafi Shajakhan Signed-off-by: John W. Linville diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 64d92d5..865fed4 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -90,20 +90,11 @@ enum rx_mgmt_action { /* no action required */ RX_MGMT_NONE, - /* caller must call cfg80211_send_rx_auth() */ - RX_MGMT_CFG80211_AUTH, - - /* caller must call cfg80211_send_rx_assoc() */ - RX_MGMT_CFG80211_ASSOC, - /* caller must call cfg80211_send_deauth() */ RX_MGMT_CFG80211_DEAUTH, /* caller must call cfg80211_send_disassoc() */ RX_MGMT_CFG80211_DISASSOC, - - /* caller must tell cfg80211 about internal error */ - RX_MGMT_CFG80211_ASSOC_ERROR, }; /* utils */ -- cgit v0.10.2 From a0bbb58bcb70295ff05f870c93d34f9fbe614204 Mon Sep 17 00:00:00 2001 From: Jarkko Nikula Date: Mon, 4 Apr 2011 11:04:57 +0300 Subject: wl1251: Prepare for idle mode support RFC for WL1251 idle mode support brought a few issues that are worth to update before adding the idle mode support. Since the idle mode can reuse the code that is now used in Power Save Mode (PSM), the flag psm in struct wl1251 is changed to variable station_mode to be able to distinguish between PSM and idle modes. As the station mode is different than the power power save mode command that is sent to chip, the enum wl1251_cmd_ps_mod values are used only when communicating with the chip and new enum wl1251_station_mode values are used inside the driver. Confusing comment about psm and elp relation is removed since the PSM is actually activated by putting the chip into Entreme Low Power (ELP) mode. Signed-off-by: Jarkko Nikula Acked-by: Kalle Valo Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/wl1251/cmd.h b/drivers/net/wireless/wl1251/cmd.h index e5c74c6..79ca527 100644 --- a/drivers/net/wireless/wl1251/cmd.h +++ b/drivers/net/wireless/wl1251/cmd.h @@ -313,8 +313,8 @@ struct wl1251_cmd_vbm_update { } __packed; enum wl1251_cmd_ps_mode { - STATION_ACTIVE_MODE, - STATION_POWER_SAVE_MODE + CHIP_ACTIVE_MODE, + CHIP_POWER_SAVE_MODE }; struct wl1251_cmd_ps_params { diff --git a/drivers/net/wireless/wl1251/event.c b/drivers/net/wireless/wl1251/event.c index dfc4579..9f15cca 100644 --- a/drivers/net/wireless/wl1251/event.c +++ b/drivers/net/wireless/wl1251/event.c @@ -68,14 +68,16 @@ static int wl1251_event_process(struct wl1251 *wl, struct event_mailbox *mbox) if (vector & BSS_LOSE_EVENT_ID) { wl1251_debug(DEBUG_EVENT, "BSS_LOSE_EVENT"); - if (wl->psm_requested && wl->psm) { + if (wl->psm_requested && + wl->station_mode != STATION_ACTIVE_MODE) { ret = wl1251_ps_set_mode(wl, STATION_ACTIVE_MODE); if (ret < 0) return ret; } } - if (vector & SYNCHRONIZATION_TIMEOUT_EVENT_ID && wl->psm) { + if (vector & SYNCHRONIZATION_TIMEOUT_EVENT_ID && + wl->station_mode != STATION_ACTIVE_MODE) { wl1251_debug(DEBUG_EVENT, "SYNCHRONIZATION_TIMEOUT_EVENT"); /* indicate to the stack, that beacons have been lost */ diff --git a/drivers/net/wireless/wl1251/main.c b/drivers/net/wireless/wl1251/main.c index 12c9e63..04a0549 100644 --- a/drivers/net/wireless/wl1251/main.c +++ b/drivers/net/wireless/wl1251/main.c @@ -497,7 +497,7 @@ static void wl1251_op_stop(struct ieee80211_hw *hw) wl->rx_last_id = 0; wl->next_tx_complete = 0; wl->elp = false; - wl->psm = 0; + wl->station_mode = STATION_ACTIVE_MODE; wl->tx_queue_stopped = false; wl->power_level = WL1251_DEFAULT_POWER_LEVEL; wl->rssi_thold = 0; @@ -632,7 +632,7 @@ static int wl1251_op_config(struct ieee80211_hw *hw, u32 changed) wl->psm_requested = false; - if (wl->psm) { + if (wl->station_mode != STATION_ACTIVE_MODE) { ret = wl1251_ps_set_mode(wl, STATION_ACTIVE_MODE); if (ret < 0) goto out_sleep; @@ -1384,7 +1384,7 @@ struct ieee80211_hw *wl1251_alloc_hw(void) wl->rx_config = WL1251_DEFAULT_RX_CONFIG; wl->rx_filter = WL1251_DEFAULT_RX_FILTER; wl->elp = false; - wl->psm = 0; + wl->station_mode = STATION_ACTIVE_MODE; wl->psm_requested = false; wl->tx_queue_stopped = false; wl->power_level = WL1251_DEFAULT_POWER_LEVEL; diff --git a/drivers/net/wireless/wl1251/ps.c b/drivers/net/wireless/wl1251/ps.c index 9cc5147..97a5b8c 100644 --- a/drivers/net/wireless/wl1251/ps.c +++ b/drivers/net/wireless/wl1251/ps.c @@ -39,7 +39,7 @@ void wl1251_elp_work(struct work_struct *work) mutex_lock(&wl->mutex); - if (wl->elp || !wl->psm) + if (wl->elp || wl->station_mode == STATION_ACTIVE_MODE) goto out; wl1251_debug(DEBUG_PSM, "chip to elp"); @@ -57,7 +57,7 @@ void wl1251_ps_elp_sleep(struct wl1251 *wl) { unsigned long delay; - if (wl->psm) { + if (wl->station_mode != STATION_ACTIVE_MODE) { delay = msecs_to_jiffies(ELP_ENTRY_DELAY); ieee80211_queue_delayed_work(wl->hw, &wl->elp_work, delay); } @@ -104,7 +104,7 @@ int wl1251_ps_elp_wakeup(struct wl1251 *wl) return 0; } -int wl1251_ps_set_mode(struct wl1251 *wl, enum wl1251_cmd_ps_mode mode) +int wl1251_ps_set_mode(struct wl1251 *wl, enum wl1251_station_mode mode) { int ret; @@ -128,15 +128,13 @@ int wl1251_ps_set_mode(struct wl1251 *wl, enum wl1251_cmd_ps_mode mode) if (ret < 0) return ret; - ret = wl1251_cmd_ps_mode(wl, STATION_POWER_SAVE_MODE); + ret = wl1251_cmd_ps_mode(wl, CHIP_POWER_SAVE_MODE); if (ret < 0) return ret; ret = wl1251_acx_sleep_auth(wl, WL1251_PSM_ELP); if (ret < 0) return ret; - - wl->psm = 1; break; case STATION_ACTIVE_MODE: default: @@ -163,13 +161,13 @@ int wl1251_ps_set_mode(struct wl1251 *wl, enum wl1251_cmd_ps_mode mode) if (ret < 0) return ret; - ret = wl1251_cmd_ps_mode(wl, STATION_ACTIVE_MODE); + ret = wl1251_cmd_ps_mode(wl, CHIP_ACTIVE_MODE); if (ret < 0) return ret; - wl->psm = 0; break; } + wl->station_mode = mode; return ret; } diff --git a/drivers/net/wireless/wl1251/ps.h b/drivers/net/wireless/wl1251/ps.h index 55c3dda..75efad2 100644 --- a/drivers/net/wireless/wl1251/ps.h +++ b/drivers/net/wireless/wl1251/ps.h @@ -26,7 +26,7 @@ #include "wl1251.h" #include "acx.h" -int wl1251_ps_set_mode(struct wl1251 *wl, enum wl1251_cmd_ps_mode mode); +int wl1251_ps_set_mode(struct wl1251 *wl, enum wl1251_station_mode mode); void wl1251_ps_elp_sleep(struct wl1251 *wl); int wl1251_ps_elp_wakeup(struct wl1251 *wl); void wl1251_elp_work(struct work_struct *work); diff --git a/drivers/net/wireless/wl1251/wl1251.h b/drivers/net/wireless/wl1251/wl1251.h index bb23cd5..bf245a8 100644 --- a/drivers/net/wireless/wl1251/wl1251.h +++ b/drivers/net/wireless/wl1251/wl1251.h @@ -129,6 +129,11 @@ enum wl1251_partition_type { PART_TABLE_LEN }; +enum wl1251_station_mode { + STATION_ACTIVE_MODE, + STATION_POWER_SAVE_MODE, +}; + struct wl1251_partition { u32 size; u32 start; @@ -358,8 +363,7 @@ struct wl1251 { struct delayed_work elp_work; - /* we can be in psm, but not in elp, we have to differentiate */ - bool psm; + enum wl1251_station_mode station_mode; /* PSM mode requested */ bool psm_requested; -- cgit v0.10.2 From 1e5f52de216a32986a5c3cbc358dbb2620a03047 Mon Sep 17 00:00:00 2001 From: Jarkko Nikula Date: Mon, 4 Apr 2011 11:04:58 +0300 Subject: wl1251: Add support for idle mode On Nokia N900 the wl1251 consumes the most power when the interface is up but not associated to access point (that supports PSM). In terms of battery current consumption, the consumption is ~180 mA higher when the interface is up but not associated and only ~5 mA higher when associated compared to interface down and driver not loaded cases. This patch adds support for the mac80211 idle notifications. Chip is put into idle very much the same way when entering into PSM by utilizing the Extreme Low Power (ELP) mode. I.e. idle is entered by setting necessary conditions in wl1251_ps_set_mode followed by a call to wl1251_ps_elp_sleep. It seems it is just enough the authorize ELP mode followed by CMD_DISCONNECT (thanks to Kalle Valo about the idea to use it). Without disconnect command the chip remains somewhat active and stays consuming ~20 mA. Idle mode is left by same way than PSM. The wl1251_join call is used to revert the CMD_DISCONNECT. Without it association to AP doesn't work when trying second time. With this patch the interface up but not associated case the battery current consumption is less than 1 mA higher compared to interface down case. Signed-off-by: Jarkko Nikula Acked-by: Kalle Valo Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/wl1251/main.c b/drivers/net/wireless/wl1251/main.c index 04a0549..a14a48c 100644 --- a/drivers/net/wireless/wl1251/main.c +++ b/drivers/net/wireless/wl1251/main.c @@ -639,6 +639,22 @@ static int wl1251_op_config(struct ieee80211_hw *hw, u32 changed) } } + if (changed & IEEE80211_CONF_CHANGE_IDLE) { + if (conf->flags & IEEE80211_CONF_IDLE) { + ret = wl1251_ps_set_mode(wl, STATION_IDLE); + if (ret < 0) + goto out_sleep; + } else { + ret = wl1251_ps_set_mode(wl, STATION_ACTIVE_MODE); + if (ret < 0) + goto out_sleep; + ret = wl1251_join(wl, wl->bss_type, wl->channel, + wl->beacon_int, wl->dtim_period); + if (ret < 0) + goto out_sleep; + } + } + if (conf->power_level != wl->power_level) { ret = wl1251_acx_tx_power(wl, conf->power_level); if (ret < 0) diff --git a/drivers/net/wireless/wl1251/ps.c b/drivers/net/wireless/wl1251/ps.c index 97a5b8c..db719f7 100644 --- a/drivers/net/wireless/wl1251/ps.c +++ b/drivers/net/wireless/wl1251/ps.c @@ -136,6 +136,17 @@ int wl1251_ps_set_mode(struct wl1251 *wl, enum wl1251_station_mode mode) if (ret < 0) return ret; break; + case STATION_IDLE: + wl1251_debug(DEBUG_PSM, "entering idle"); + + ret = wl1251_acx_sleep_auth(wl, WL1251_PSM_ELP); + if (ret < 0) + return ret; + + ret = wl1251_cmd_template_set(wl, CMD_DISCONNECT, NULL, 0); + if (ret < 0) + return ret; + break; case STATION_ACTIVE_MODE: default: wl1251_debug(DEBUG_PSM, "leaving psm"); diff --git a/drivers/net/wireless/wl1251/wl1251.h b/drivers/net/wireless/wl1251/wl1251.h index bf245a8..a77f1bb 100644 --- a/drivers/net/wireless/wl1251/wl1251.h +++ b/drivers/net/wireless/wl1251/wl1251.h @@ -132,6 +132,7 @@ enum wl1251_partition_type { enum wl1251_station_mode { STATION_ACTIVE_MODE, STATION_POWER_SAVE_MODE, + STATION_IDLE, }; struct wl1251_partition { -- cgit v0.10.2 From 59575d1c717815d62f1b5aeac74e5e60a1b27428 Mon Sep 17 00:00:00 2001 From: Rajkumar Manoharan Date: Mon, 4 Apr 2011 22:56:16 +0530 Subject: ath9k: deny new interface addtion on IBSS mode The present check denies the IBSS interface addtion if we already have any other vifs. But it fails to deny interface addition if IBSS was already present. Signed-off-by: Rajkumar Manoharan Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index 3c5de73..88073f4 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -1479,8 +1479,9 @@ static int ath9k_add_interface(struct ieee80211_hw *hw, } } - if ((vif->type == NL80211_IFTYPE_ADHOC) && - sc->nvifs > 0) { + if ((ah->opmode == NL80211_IFTYPE_ADHOC) || + ((vif->type == NL80211_IFTYPE_ADHOC) && + sc->nvifs > 0)) { ath_err(common, "Cannot create ADHOC interface when other" " interfaces already exist.\n"); ret = -EINVAL; -- cgit v0.10.2 From 66da424177db4f4f2fa7a462db5912655aad966f Mon Sep 17 00:00:00 2001 From: Rajkumar Manoharan Date: Mon, 4 Apr 2011 22:56:17 +0530 Subject: ath9k: Cleanup ath_vif struct Remove unused bssid from ath_vif and set av_bslot on beacon alloc/return. Signed-off-by: Rajkumar Manoharan Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h index a43f059..f3a7530 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h @@ -346,9 +346,7 @@ struct ath_vif { int av_bslot; bool is_bslot_active; __le64 tsf_adjust; /* TSF adjustment for staggered beacons */ - enum nl80211_iftype av_opmode; struct ath_buf *av_bcbuf; - u8 bssid[ETH_ALEN]; /* current BSSID from config_interface */ }; /*******************/ diff --git a/drivers/net/wireless/ath/ath9k/beacon.c b/drivers/net/wireless/ath/ath9k/beacon.c index f688527..dfd1b98 100644 --- a/drivers/net/wireless/ath/ath9k/beacon.c +++ b/drivers/net/wireless/ath/ath9k/beacon.c @@ -323,6 +323,7 @@ void ath_beacon_return(struct ath_softc *sc, struct ath_vif *avp) if (avp->av_bslot != -1) { sc->beacon.bslot[avp->av_bslot] = NULL; sc->nbcnvifs--; + avp->av_bslot = -1; } bf = avp->av_bcbuf; diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index 88073f4..6f300d7 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -1450,7 +1450,6 @@ static int ath9k_add_interface(struct ieee80211_hw *hw, struct ath_softc *sc = hw->priv; struct ath_hw *ah = sc->sc_ah; struct ath_common *common = ath9k_hw_common(ah); - struct ath_vif *avp = (void *)vif->drv_priv; int ret = 0; mutex_lock(&sc->mutex); @@ -1491,10 +1490,6 @@ static int ath9k_add_interface(struct ieee80211_hw *hw, ath_dbg(common, ATH_DBG_CONFIG, "Attach a VIF of type: %d\n", vif->type); - /* Set the VIF opmode */ - avp->av_opmode = vif->type; - avp->av_bslot = -1; - sc->nvifs++; ath9k_do_vif_add_setup(hw, vif); @@ -1910,7 +1905,6 @@ static void ath9k_bss_info_changed(struct ieee80211_hw *hw, if (changed & BSS_CHANGED_BSSID) { /* Set BSSID */ memcpy(common->curbssid, bss_conf->bssid, ETH_ALEN); - memcpy(avp->bssid, bss_conf->bssid, ETH_ALEN); common->curaid = 0; ath9k_hw_write_associd(ah); -- cgit v0.10.2 From 4f5ef75b155955bf92adc772c6660787151fc78c Mon Sep 17 00:00:00 2001 From: Rajkumar Manoharan Date: Mon, 4 Apr 2011 22:56:18 +0530 Subject: ath9k: Handle BSSID/AID for multiple interfaces As of now bssid/aid is overridden with recently changed vif's bss config. This may cause improper beacon updation due to bssid/aid mismatch. On station mode, select an associated sta vif as primary vif and configure that vif's bss into hw. Update the primary vif on interface change and bss info change. Signed-off-by: Rajkumar Manoharan Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h index f3a7530..a972396 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h @@ -344,7 +344,7 @@ void ath_tx_aggr_resume(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid struct ath_vif { int av_bslot; - bool is_bslot_active; + bool is_bslot_active, primary_sta_vif; __le64 tsf_adjust; /* TSF adjustment for staggered beacons */ struct ath_buf *av_bcbuf; }; @@ -546,6 +546,7 @@ struct ath_ant_comb { #define SC_OP_BT_SCAN BIT(13) #define SC_OP_ANI_RUN BIT(14) #define SC_OP_ENABLE_APM BIT(15) +#define SC_OP_PRIM_STA_VIF BIT(16) /* Powersave flags */ #define PS_WAIT_FOR_BEACON BIT(0) diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index 6f300d7..3181211 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -841,10 +841,6 @@ static void ath9k_bss_assoc_info(struct ath_softc *sc, "Bss Info ASSOC %d, bssid: %pM\n", bss_conf->aid, common->curbssid); - /* New association, store aid */ - common->curaid = bss_conf->aid; - ath9k_hw_write_associd(ah); - /* * Request a re-configuration of Beacon related timers * on the receipt of the first Beacon frame (i.e., @@ -863,7 +859,6 @@ static void ath9k_bss_assoc_info(struct ath_softc *sc, ath_start_ani(common); } else { ath_dbg(common, ATH_DBG_CONFIG, "Bss Info DISASSOC\n"); - common->curaid = 0; /* Stop ANI */ sc->sc_flags &= ~SC_OP_ANI_RUN; del_timer_sync(&common->ani.timer); @@ -1886,6 +1881,66 @@ static int ath9k_set_key(struct ieee80211_hw *hw, return ret; } +static void ath9k_bss_iter(void *data, u8 *mac, struct ieee80211_vif *vif) +{ + struct ath_softc *sc = data; + struct ath_common *common = ath9k_hw_common(sc->sc_ah); + struct ieee80211_bss_conf *bss_conf = &vif->bss_conf; + struct ath_vif *avp = (void *)vif->drv_priv; + + switch (sc->sc_ah->opmode) { + case NL80211_IFTYPE_ADHOC: + /* There can be only one vif available */ + memcpy(common->curbssid, bss_conf->bssid, ETH_ALEN); + common->curaid = bss_conf->aid; + ath9k_hw_write_associd(sc->sc_ah); + break; + case NL80211_IFTYPE_STATION: + /* + * Skip iteration if primary station vif's bss info + * was not changed + */ + if (sc->sc_flags & SC_OP_PRIM_STA_VIF) + break; + + if (bss_conf->assoc) { + sc->sc_flags |= SC_OP_PRIM_STA_VIF; + avp->primary_sta_vif = true; + memcpy(common->curbssid, bss_conf->bssid, ETH_ALEN); + common->curaid = bss_conf->aid; + ath9k_hw_write_associd(sc->sc_ah); + } + break; + default: + break; + } +} + +static void ath9k_config_bss(struct ath_softc *sc, struct ieee80211_vif *vif) +{ + struct ath_common *common = ath9k_hw_common(sc->sc_ah); + struct ieee80211_bss_conf *bss_conf = &vif->bss_conf; + struct ath_vif *avp = (void *)vif->drv_priv; + + /* Reconfigure bss info */ + if (avp->primary_sta_vif && !bss_conf->assoc) { + sc->sc_flags &= ~SC_OP_PRIM_STA_VIF; + avp->primary_sta_vif = false; + memset(common->curbssid, 0, ETH_ALEN); + common->curaid = 0; + } + + ieee80211_iterate_active_interfaces_atomic( + sc->hw, ath9k_bss_iter, sc); + + /* + * None of station vifs are associated. + * Clear bssid & aid + */ + if ((sc->sc_ah->opmode == NL80211_IFTYPE_STATION) && + !(sc->sc_flags & SC_OP_PRIM_STA_VIF)) + ath9k_hw_write_associd(sc->sc_ah); +} static void ath9k_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif, @@ -1903,10 +1958,7 @@ static void ath9k_bss_info_changed(struct ieee80211_hw *hw, mutex_lock(&sc->mutex); if (changed & BSS_CHANGED_BSSID) { - /* Set BSSID */ - memcpy(common->curbssid, bss_conf->bssid, ETH_ALEN); - common->curaid = 0; - ath9k_hw_write_associd(ah); + ath9k_config_bss(sc, vif); /* Set aggregation protection mode parameters */ sc->config.ath_aggr_prot = 0; -- cgit v0.10.2 From 99e4d43ad5ff5778f92ee3bc40a29ac7cd8a28f4 Mon Sep 17 00:00:00 2001 From: Rajkumar Manoharan Date: Mon, 4 Apr 2011 22:56:19 +0530 Subject: ath9k: configure beacons based on hw opmode Current ath9k code does not handle beacon timers on opmode specific. One such example is that a STA beacon config overwrites already configured AP vif's beacon timers during scan. On multi station vif case, configure beacon timers beased on primary vif selected. This also helps while moving back to single STA vif from multi STA vifs, where the power save is enabled and hw has to be reconfigured with proper beacon and bssid/aid. Otherwise connection poll will be triggered so frequently due to beacon loss. Signed-off-by: Rajkumar Manoharan Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h index a972396..38835bc 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h @@ -397,6 +397,7 @@ void ath_beacon_config(struct ath_softc *sc, struct ieee80211_vif *vif); int ath_beacon_alloc(struct ath_softc *sc, struct ieee80211_vif *vif); void ath_beacon_return(struct ath_softc *sc, struct ath_vif *avp); int ath_beaconq_config(struct ath_softc *sc); +void ath_set_beacon(struct ath_softc *sc); void ath9k_set_beaconing_status(struct ath_softc *sc, bool status); /*******/ diff --git a/drivers/net/wireless/ath/ath9k/beacon.c b/drivers/net/wireless/ath/ath9k/beacon.c index dfd1b98..eccb0ec 100644 --- a/drivers/net/wireless/ath/ath9k/beacon.c +++ b/drivers/net/wireless/ath/ath9k/beacon.c @@ -663,22 +663,63 @@ static void ath_beacon_config_adhoc(struct ath_softc *sc, ath9k_hw_set_interrupts(ah, ah->imask); } -void ath_beacon_config(struct ath_softc *sc, struct ieee80211_vif *vif) +static bool ath9k_allow_beacon_config(struct ath_softc *sc, + struct ieee80211_vif *vif) { struct ath_beacon_config *cur_conf = &sc->cur_beacon_conf; struct ath_common *common = ath9k_hw_common(sc->sc_ah); - enum nl80211_iftype iftype; + struct ieee80211_bss_conf *bss_conf = &vif->bss_conf; + struct ath_vif *avp = (void *)vif->drv_priv; - /* Setup the beacon configuration parameters */ - if (vif) { - struct ieee80211_bss_conf *bss_conf = &vif->bss_conf; - iftype = vif->type; - cur_conf->beacon_interval = bss_conf->beacon_int; - cur_conf->dtim_period = bss_conf->dtim_period; - } else { - iftype = sc->sc_ah->opmode; + /* + * Can not have different beacon interval on multiple + * AP interface case + */ + if ((sc->sc_ah->opmode == NL80211_IFTYPE_AP) && + (sc->nbcnvifs > 1) && + (vif->type == NL80211_IFTYPE_AP) && + (cur_conf->beacon_interval != bss_conf->beacon_int)) { + ath_dbg(common, ATH_DBG_CONFIG, + "Changing beacon interval of multiple \ + AP interfaces !\n"); + return false; + } + /* + * Can not configure station vif's beacon config + * while on AP opmode + */ + if ((sc->sc_ah->opmode == NL80211_IFTYPE_AP) && + (vif->type != NL80211_IFTYPE_AP)) { + ath_dbg(common, ATH_DBG_CONFIG, + "STA vif's beacon not allowed on AP mode\n"); + return false; + } + /* + * Do not allow beacon config if HW was already configured + * with another STA vif + */ + if ((sc->sc_ah->opmode == NL80211_IFTYPE_STATION) && + (vif->type == NL80211_IFTYPE_STATION) && + (sc->sc_flags & SC_OP_BEACONS) && + !avp->primary_sta_vif) { + ath_dbg(common, ATH_DBG_CONFIG, + "Beacon already configured for a station interface\n"); + return false; } + return true; +} + +void ath_beacon_config(struct ath_softc *sc, struct ieee80211_vif *vif) +{ + struct ath_beacon_config *cur_conf = &sc->cur_beacon_conf; + struct ieee80211_bss_conf *bss_conf = &vif->bss_conf; + if (!ath9k_allow_beacon_config(sc, vif)) + return; + + /* Setup the beacon configuration parameters */ + cur_conf->beacon_interval = bss_conf->beacon_int; + cur_conf->dtim_period = bss_conf->dtim_period; cur_conf->listen_interval = 1; cur_conf->dtim_count = 1; cur_conf->bmiss_timeout = @@ -701,6 +742,15 @@ void ath_beacon_config(struct ath_softc *sc, struct ieee80211_vif *vif) if (cur_conf->dtim_period == 0) cur_conf->dtim_period = 1; + ath_set_beacon(sc); + sc->ps_flags |= PS_BEACON_SYNC | PS_WAIT_FOR_BEACON; +} + +void ath_set_beacon(struct ath_softc *sc) +{ + struct ath_common *common = ath9k_hw_common(sc->sc_ah); + struct ath_beacon_config *cur_conf = &sc->cur_beacon_conf; + switch (sc->sc_ah->opmode) { case NL80211_IFTYPE_AP: ath_beacon_config_ap(sc, cur_conf); @@ -728,22 +778,23 @@ void ath9k_set_beaconing_status(struct ath_softc *sc, bool status) int slot; bool found = false; - ath9k_ps_wakeup(sc); - if (status) { - for (slot = 0; slot < ATH_BCBUF; slot++) { - if (sc->beacon.bslot[slot]) { - avp = (void *)sc->beacon.bslot[slot]->drv_priv; - if (avp->is_bslot_active) { - found = true; - break; - } + for (slot = 0; slot < ATH_BCBUF; slot++) { + if (sc->beacon.bslot[slot]) { + avp = (void *)sc->beacon.bslot[slot]->drv_priv; + if (avp->is_bslot_active) { + found = true; + break; } } - if (found) { - /* Re-enable beaconing */ - ah->imask |= ATH9K_INT_SWBA; - ath9k_hw_set_interrupts(ah, ah->imask); - } + } + if (!found) + return; + + ath9k_ps_wakeup(sc); + if (status) { + /* Re-enable beaconing */ + ah->imask |= ATH9K_INT_SWBA; + ath9k_hw_set_interrupts(ah, ah->imask); } else { /* Disable SWBA interrupt */ ah->imask &= ~ATH9K_INT_SWBA; diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index 3181211..ddd5413 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -299,7 +299,7 @@ int ath_set_channel(struct ath_softc *sc, struct ieee80211_hw *hw, if (!(sc->sc_flags & (SC_OP_OFFCHANNEL))) { if (sc->sc_flags & SC_OP_BEACONS) - ath_beacon_config(sc, NULL); + ath_set_beacon(sc); ieee80211_queue_delayed_work(sc->hw, &sc->tx_complete_work, 0); ieee80211_queue_delayed_work(sc->hw, &sc->hw_pll_work, HZ/2); ath_start_ani(common); @@ -828,43 +828,6 @@ chip_reset: #undef SCHED_INTR } -static void ath9k_bss_assoc_info(struct ath_softc *sc, - struct ieee80211_hw *hw, - struct ieee80211_vif *vif, - struct ieee80211_bss_conf *bss_conf) -{ - struct ath_hw *ah = sc->sc_ah; - struct ath_common *common = ath9k_hw_common(ah); - - if (bss_conf->assoc) { - ath_dbg(common, ATH_DBG_CONFIG, - "Bss Info ASSOC %d, bssid: %pM\n", - bss_conf->aid, common->curbssid); - - /* - * Request a re-configuration of Beacon related timers - * on the receipt of the first Beacon frame (i.e., - * after time sync with the AP). - */ - sc->ps_flags |= PS_BEACON_SYNC; - - /* Configure the beacon */ - ath_beacon_config(sc, vif); - - /* Reset rssi stats */ - sc->last_rssi = ATH_RSSI_DUMMY_MARKER; - sc->sc_ah->stats.avgbrssi = ATH_RSSI_DUMMY_MARKER; - - sc->sc_flags |= SC_OP_ANI_RUN; - ath_start_ani(common); - } else { - ath_dbg(common, ATH_DBG_CONFIG, "Bss Info DISASSOC\n"); - /* Stop ANI */ - sc->sc_flags &= ~SC_OP_ANI_RUN; - del_timer_sync(&common->ani.timer); - } -} - void ath_radio_enable(struct ath_softc *sc, struct ieee80211_hw *hw) { struct ath_hw *ah = sc->sc_ah; @@ -894,7 +857,7 @@ void ath_radio_enable(struct ath_softc *sc, struct ieee80211_hw *hw) goto out; } if (sc->sc_flags & SC_OP_BEACONS) - ath_beacon_config(sc, NULL); /* restart beacons */ + ath_set_beacon(sc); /* restart beacons */ /* Re-Enable interrupts */ ath9k_hw_set_interrupts(ah, ah->imask); @@ -1001,7 +964,7 @@ int ath_reset(struct ath_softc *sc, bool retry_tx) sc->config.txpowlimit, &sc->curtxpow); if ((sc->sc_flags & SC_OP_BEACONS) || !(sc->sc_flags & (SC_OP_OFFCHANNEL))) - ath_beacon_config(sc, NULL); /* restart beacons */ + ath_set_beacon(sc); /* restart beacons */ ath9k_hw_set_interrupts(ah, ah->imask); @@ -1408,9 +1371,6 @@ static void ath9k_calculate_summary_state(struct ieee80211_hw *hw, if ((iter_data.naps + iter_data.nadhocs) > 0) { sc->sc_flags |= SC_OP_ANI_RUN; ath_start_ani(common); - } else { - sc->sc_flags &= ~SC_OP_ANI_RUN; - del_timer_sync(&common->ani.timer); } } @@ -1894,6 +1854,9 @@ static void ath9k_bss_iter(void *data, u8 *mac, struct ieee80211_vif *vif) memcpy(common->curbssid, bss_conf->bssid, ETH_ALEN); common->curaid = bss_conf->aid; ath9k_hw_write_associd(sc->sc_ah); + /* configure beacon */ + if (bss_conf->enable_beacon) + ath_beacon_config(sc, vif); break; case NL80211_IFTYPE_STATION: /* @@ -1909,6 +1872,16 @@ static void ath9k_bss_iter(void *data, u8 *mac, struct ieee80211_vif *vif) memcpy(common->curbssid, bss_conf->bssid, ETH_ALEN); common->curaid = bss_conf->aid; ath9k_hw_write_associd(sc->sc_ah); + ath_dbg(common, ATH_DBG_CONFIG, + "Bss Info ASSOC %d, bssid: %pM\n", + bss_conf->aid, common->curbssid); + ath_beacon_config(sc, vif); + /* Reset rssi stats */ + sc->last_rssi = ATH_RSSI_DUMMY_MARKER; + sc->sc_ah->stats.avgbrssi = ATH_RSSI_DUMMY_MARKER; + + sc->sc_flags |= SC_OP_ANI_RUN; + ath_start_ani(common); } break; default: @@ -1924,7 +1897,10 @@ static void ath9k_config_bss(struct ath_softc *sc, struct ieee80211_vif *vif) /* Reconfigure bss info */ if (avp->primary_sta_vif && !bss_conf->assoc) { - sc->sc_flags &= ~SC_OP_PRIM_STA_VIF; + ath_dbg(common, ATH_DBG_CONFIG, + "Bss Info DISASSOC %d, bssid %pM\n", + common->curaid, common->curbssid); + sc->sc_flags &= ~(SC_OP_PRIM_STA_VIF | SC_OP_BEACONS); avp->primary_sta_vif = false; memset(common->curbssid, 0, ETH_ALEN); common->curaid = 0; @@ -1938,8 +1914,12 @@ static void ath9k_config_bss(struct ath_softc *sc, struct ieee80211_vif *vif) * Clear bssid & aid */ if ((sc->sc_ah->opmode == NL80211_IFTYPE_STATION) && - !(sc->sc_flags & SC_OP_PRIM_STA_VIF)) + !(sc->sc_flags & SC_OP_PRIM_STA_VIF)) { ath9k_hw_write_associd(sc->sc_ah); + /* Stop ANI */ + sc->sc_flags &= ~SC_OP_ANI_RUN; + del_timer_sync(&common->ani.timer); + } } static void ath9k_bss_info_changed(struct ieee80211_hw *hw, @@ -1948,7 +1928,6 @@ static void ath9k_bss_info_changed(struct ieee80211_hw *hw, u32 changed) { struct ath_softc *sc = hw->priv; - struct ath_beacon_config *cur_conf = &sc->cur_beacon_conf; struct ath_hw *ah = sc->sc_ah; struct ath_common *common = ath9k_hw_common(ah); struct ath_vif *avp = (void *)vif->drv_priv; @@ -1965,9 +1944,6 @@ static void ath9k_bss_info_changed(struct ieee80211_hw *hw, ath_dbg(common, ATH_DBG_CONFIG, "BSSID: %pM aid: 0x%x\n", common->curbssid, common->curaid); - - /* need to reconfigure the beacon */ - sc->sc_flags &= ~SC_OP_BEACONS ; } /* Enable transmission of beacons (AP, IBSS, MESH) */ @@ -2008,7 +1984,6 @@ static void ath9k_bss_info_changed(struct ieee80211_hw *hw, } if (changed & BSS_CHANGED_BEACON_INT) { - cur_conf->beacon_interval = bss_conf->beacon_int; /* * In case of AP mode, the HW TSF has to be reset * when the beacon interval changes. @@ -2020,9 +1995,8 @@ static void ath9k_bss_info_changed(struct ieee80211_hw *hw, if (!error) ath_beacon_config(sc, vif); ath9k_set_beaconing_status(sc, true); - } else { + } else ath_beacon_config(sc, vif); - } } if (changed & BSS_CHANGED_ERP_PREAMBLE) { @@ -2044,12 +2018,6 @@ static void ath9k_bss_info_changed(struct ieee80211_hw *hw, sc->sc_flags &= ~SC_OP_PROTECT_ENABLE; } - if (changed & BSS_CHANGED_ASSOC) { - ath_dbg(common, ATH_DBG_CONFIG, "BSS Changed ASSOC %d\n", - bss_conf->assoc); - ath9k_bss_assoc_info(sc, hw, vif, bss_conf); - } - mutex_unlock(&sc->mutex); } diff --git a/drivers/net/wireless/ath/ath9k/recv.c b/drivers/net/wireless/ath/ath9k/recv.c index a9c3f46..3842b75 100644 --- a/drivers/net/wireless/ath/ath9k/recv.c +++ b/drivers/net/wireless/ath/ath9k/recv.c @@ -574,7 +574,7 @@ static void ath_rx_ps_beacon(struct ath_softc *sc, struct sk_buff *skb) sc->ps_flags &= ~PS_BEACON_SYNC; ath_dbg(common, ATH_DBG_PS, "Reconfigure Beacon timers based on timestamp from the AP\n"); - ath_beacon_config(sc, NULL); + ath_set_beacon(sc); } if (ath_beacon_dtim_pending_cab(skb)) { -- cgit v0.10.2 From 0321708748d8f2ecfffa4a9feafb332312e4e57f Mon Sep 17 00:00:00 2001 From: Nishant Sarmukadam Date: Tue, 5 Apr 2011 14:18:09 +0530 Subject: mwl8k: Do not configure tx power unconditionally Instead of configuring tx power unconditionally, check for IEEE80211_CONF_CHANGE_POWER and configure it only when stack sets this flag Signed-off-by: Nishant Sarmukadam Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c index ae56d2f3..d5e0479 100644 --- a/drivers/net/wireless/mwl8k.c +++ b/drivers/net/wireless/mwl8k.c @@ -4463,9 +4463,12 @@ static int mwl8k_config(struct ieee80211_hw *hw, u32 changed) conf->power_level = 18; if (priv->ap_fw) { - rc = mwl8k_cmd_tx_power(hw, conf, conf->power_level); - if (rc) - goto out; + + if (conf->flags & IEEE80211_CONF_CHANGE_POWER) { + rc = mwl8k_cmd_tx_power(hw, conf, conf->power_level); + if (rc) + goto out; + } rc = mwl8k_cmd_rf_antenna(hw, MWL8K_RF_ANTENNA_RX, 0x3); if (rc) -- cgit v0.10.2 From cebb28ba1ebb00edee4606547d81acf8db0f0532 Mon Sep 17 00:00:00 2001 From: Michal Marek Date: Tue, 5 Apr 2011 16:59:06 +0200 Subject: rt2x00: Drop __TIME__ usage The kernel already prints its build timestamp during boot, no need to repeat it in random drivers and produce different object files each time. Signed-off-by: Michal Marek Acked-by: Ivo van Doorn Acked-by: Gertjan van Wingerde Cc: linux-wireless@vger.kernel.org Cc: netdev@vger.kernel.org Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/rt2x00/rt2x00debug.c b/drivers/net/wireless/rt2x00/rt2x00debug.c index c92db32..66166ef 100644 --- a/drivers/net/wireless/rt2x00/rt2x00debug.c +++ b/drivers/net/wireless/rt2x00/rt2x00debug.c @@ -568,7 +568,6 @@ static struct dentry *rt2x00debug_create_file_driver(const char *name, blob->data = data; data += sprintf(data, "driver:\t%s\n", intf->rt2x00dev->ops->name); data += sprintf(data, "version:\t%s\n", DRV_VERSION); - data += sprintf(data, "compiled:\t%s %s\n", __DATE__, __TIME__); blob->size = strlen(blob->data); return debugfs_create_blob(name, S_IRUSR, intf->driver_folder, blob); -- cgit v0.10.2 From 68e022dfeb548b48635888d1392f983977293573 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 5 Apr 2011 09:41:48 -0700 Subject: iwlagn: remove unused variable Some code was removed, but a variable it used and that is now unused stayed around, kill it. Signed-off-by: Johannes Berg Signed-off-by: Wey-Yi Guy Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwlwifi/iwl-sta.c b/drivers/net/wireless/iwlwifi/iwl-sta.c index b0dcca0..6ded017 100644 --- a/drivers/net/wireless/iwlwifi/iwl-sta.c +++ b/drivers/net/wireless/iwlwifi/iwl-sta.c @@ -233,7 +233,6 @@ u8 iwl_prep_station(struct iwl_priv *priv, struct iwl_rxon_context *ctx, struct iwl_station_entry *station; int i; u8 sta_id = IWL_INVALID_STATION; - u16 rate; if (is_ap) sta_id = ctx->ap_sta_id; -- cgit v0.10.2 From 3240cab3ddfb2637cfca3a078078cdeda44d0a99 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 5 Apr 2011 09:41:49 -0700 Subject: iwlagn: clean up some 3945/4965 remnants When the driver was split, a bunch of definitions for the 3945 and 4965 devices stayed around, but they're now useless so remove (some of) them. Signed-off-by: Johannes Berg Signed-off-by: Wey-Yi Guy Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-rs.h b/drivers/net/wireless/iwlwifi/iwl-agn-rs.h index 184828c..b356a39 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-rs.h +++ b/drivers/net/wireless/iwlwifi/iwl-agn-rs.h @@ -41,20 +41,6 @@ struct iwl_rate_info { u8 next_rs_tgg; /* next rate used in TGG rs algo */ }; -struct iwl3945_rate_info { - u8 plcp; /* uCode API: IWL_RATE_6M_PLCP, etc. */ - u8 ieee; /* MAC header: IWL_RATE_6M_IEEE, etc. */ - u8 prev_ieee; /* previous rate in IEEE speeds */ - u8 next_ieee; /* next rate in IEEE speeds */ - u8 prev_rs; /* previous rate used in rs algo */ - u8 next_rs; /* next rate used in rs algo */ - u8 prev_rs_tgg; /* previous rate used in TGG rs algo */ - u8 next_rs_tgg; /* next rate used in TGG rs algo */ - u8 table_rs_index; /* index in rate scale table cmd */ - u8 prev_table_rs; /* prev in rate table cmd */ -}; - - /* * These serve as indexes into * struct iwl_rate_info iwl_rates[IWL_RATE_COUNT]; @@ -75,7 +61,6 @@ enum { IWL_RATE_60M_INDEX, IWL_RATE_COUNT, /*FIXME:RS:change to IWL_RATE_INDEX_COUNT,*/ IWL_RATE_COUNT_LEGACY = IWL_RATE_COUNT - 1, /* Excluding 60M */ - IWL_RATE_COUNT_3945 = IWL_RATE_COUNT - 1, IWL_RATE_INVM_INDEX = IWL_RATE_COUNT, IWL_RATE_INVALID = IWL_RATE_COUNT, }; @@ -213,7 +198,6 @@ enum { IWL_CCK_BASIC_RATES_MASK) #define IWL_RATES_MASK ((1 << IWL_RATE_COUNT) - 1) -#define IWL_RATES_MASK_3945 ((1 << IWL_RATE_COUNT_3945) - 1) #define IWL_INVALID_VALUE -1 @@ -453,19 +437,9 @@ static inline u8 first_antenna(u8 mask) } -/** - * iwl3945_rate_scale_init - Initialize the rate scale table based on assoc info - * - * The specific throughput table used is based on the type of network - * the associated with, including A, B, G, and G w/ TGG protection - */ -extern void iwl3945_rate_scale_init(struct ieee80211_hw *hw, s32 sta_id); - /* Initialize station's rate scaling information after adding station */ extern void iwl_rs_rate_init(struct iwl_priv *priv, struct ieee80211_sta *sta, u8 sta_id); -extern void iwl3945_rs_rate_init(struct iwl_priv *priv, - struct ieee80211_sta *sta, u8 sta_id); /** * iwl_rate_control_register - Register the rate control algorithm callbacks @@ -478,7 +452,6 @@ extern void iwl3945_rs_rate_init(struct iwl_priv *priv, * */ extern int iwlagn_rate_control_register(void); -extern int iwl3945_rate_control_register(void); /** * iwl_rate_control_unregister - Unregister the rate control callbacks @@ -487,6 +460,5 @@ extern int iwl3945_rate_control_register(void); * the driver is unloaded. */ extern void iwlagn_rate_control_unregister(void); -extern void iwl3945_rate_control_unregister(void); #endif /* __iwl_agn__rs__ */ diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-sta.c b/drivers/net/wireless/iwlwifi/iwl-agn-sta.c index 35f085a..3782fe8 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-sta.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-sta.c @@ -474,7 +474,7 @@ int iwl_remove_dynamic_key(struct iwl_priv *priv, memset(&priv->stations[sta_id].keyinfo, 0, sizeof(struct iwl_hw_key)); memset(&priv->stations[sta_id].sta.key, 0, - sizeof(struct iwl4965_keyinfo)); + sizeof(struct iwl_keyinfo)); priv->stations[sta_id].sta.key.key_flags = STA_KEY_FLG_NO_ENC | STA_KEY_FLG_INVALID; priv->stations[sta_id].sta.key.key_offset = WEP_INVALID_OFFSET; diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.h b/drivers/net/wireless/iwlwifi/iwl-agn.h index 39313ac..80de8a1 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.h +++ b/drivers/net/wireless/iwlwifi/iwl-agn.h @@ -66,7 +66,6 @@ #include "iwl-dev.h" /* configuration for the _agn devices */ -extern struct iwl_cfg iwl4965_agn_cfg; extern struct iwl_cfg iwl5300_agn_cfg; extern struct iwl_cfg iwl5100_agn_cfg; extern struct iwl_cfg iwl5350_agn_cfg; @@ -114,7 +113,6 @@ extern struct iwl_hcmd_ops iwlagn_bt_hcmd; extern struct iwl_hcmd_utils_ops iwlagn_hcmd_utils; extern struct ieee80211_ops iwlagn_hw_ops; -extern struct ieee80211_ops iwl4965_hw_ops; int iwl_reset_ict(struct iwl_priv *priv); void iwl_disable_ict(struct iwl_priv *priv); diff --git a/drivers/net/wireless/iwlwifi/iwl-commands.h b/drivers/net/wireless/iwlwifi/iwl-commands.h index cc21514..e6058436 100644 --- a/drivers/net/wireless/iwlwifi/iwl-commands.h +++ b/drivers/net/wireless/iwlwifi/iwl-commands.h @@ -103,9 +103,7 @@ enum { REPLY_WEPKEY = 0x20, /* RX, TX, LEDs */ - REPLY_3945_RX = 0x1b, /* 3945 only */ REPLY_TX = 0x1c, - REPLY_RATE_SCALE = 0x47, /* 3945 only */ REPLY_LEDS_CMD = 0x48, REPLY_TX_LINK_QUALITY_CMD = 0x4e, /* for 4965 and up */ @@ -229,7 +227,7 @@ struct iwl_cmd_header { * There is one exception: uCode sets bit 15 when it originates * the response/notification, i.e. when the response/notification * is not a direct response to a command sent by the driver. For - * example, uCode issues REPLY_3945_RX when it sends a received frame + * example, uCode issues REPLY_RX when it sends a received frame * to the driver; it is not a direct response to any driver command. * * The Linux driver uses the following format: @@ -249,36 +247,6 @@ struct iwl_cmd_header { /** - * struct iwl3945_tx_power - * - * Used in REPLY_TX_PWR_TABLE_CMD, REPLY_SCAN_CMD, REPLY_CHANNEL_SWITCH - * - * Each entry contains two values: - * 1) DSP gain (or sometimes called DSP attenuation). This is a fine-grained - * linear value that multiplies the output of the digital signal processor, - * before being sent to the analog radio. - * 2) Radio gain. This sets the analog gain of the radio Tx path. - * It is a coarser setting, and behaves in a logarithmic (dB) fashion. - * - * Driver obtains values from struct iwl3945_tx_power power_gain_table[][]. - */ -struct iwl3945_tx_power { - u8 tx_gain; /* gain for analog radio */ - u8 dsp_atten; /* gain for DSP */ -} __packed; - -/** - * struct iwl3945_power_per_rate - * - * Used in REPLY_TX_PWR_TABLE_CMD, REPLY_CHANNEL_SWITCH - */ -struct iwl3945_power_per_rate { - u8 rate; /* plcp */ - struct iwl3945_tx_power tpc; - u8 reserved; -} __packed; - -/** * iwlagn rate_n_flags bit fields * * rate_n_flags format is used in following iwlagn commands: @@ -377,30 +345,6 @@ struct iwl3945_power_per_rate { #define IWL_PWR_CCK_ENTRIES 2 /** - * union iwl4965_tx_power_dual_stream - * - * Host format used for REPLY_TX_PWR_TABLE_CMD, REPLY_CHANNEL_SWITCH - * Use __le32 version (struct tx_power_dual_stream) when building command. - * - * Driver provides radio gain and DSP attenuation settings to device in pairs, - * one value for each transmitter chain. The first value is for transmitter A, - * second for transmitter B. - * - * For SISO bit rates, both values in a pair should be identical. - * For MIMO rates, one value may be different from the other, - * in order to balance the Tx output between the two transmitters. - * - * See more details in doc for TXPOWER in iwl-4965-hw.h. - */ -union iwl4965_tx_power_dual_stream { - struct { - u8 radio_tx_gain[2]; - u8 dsp_predis_atten[2]; - } s; - u32 dw; -}; - -/** * struct tx_power_dual_stream * * Table entries in REPLY_TX_PWR_TABLE_CMD, REPLY_CHANNEL_SWITCH @@ -412,15 +356,6 @@ struct tx_power_dual_stream { } __packed; /** - * struct iwl4965_tx_power_db - * - * Entire table within REPLY_TX_PWR_TABLE_CMD, REPLY_CHANNEL_SWITCH - */ -struct iwl4965_tx_power_db { - struct tx_power_dual_stream power_tbl[POWER_TABLE_NUM_ENTRIES]; -} __packed; - -/** * Command REPLY_TX_POWER_DBM_CMD = 0x98 * struct iwlagn_tx_power_dbm_cmd */ @@ -724,46 +659,6 @@ enum { * regardless of whether RXON_FILTER_ASSOC_MSK is set. */ -struct iwl3945_rxon_cmd { - u8 node_addr[6]; - __le16 reserved1; - u8 bssid_addr[6]; - __le16 reserved2; - u8 wlap_bssid_addr[6]; - __le16 reserved3; - u8 dev_type; - u8 air_propagation; - __le16 reserved4; - u8 ofdm_basic_rates; - u8 cck_basic_rates; - __le16 assoc_id; - __le32 flags; - __le32 filter_flags; - __le16 channel; - __le16 reserved5; -} __packed; - -struct iwl4965_rxon_cmd { - u8 node_addr[6]; - __le16 reserved1; - u8 bssid_addr[6]; - __le16 reserved2; - u8 wlap_bssid_addr[6]; - __le16 reserved3; - u8 dev_type; - u8 air_propagation; - __le16 rx_chain; - u8 ofdm_basic_rates; - u8 cck_basic_rates; - __le16 assoc_id; - __le32 flags; - __le32 filter_flags; - __le16 channel; - u8 ofdm_ht_single_stream_basic_rates; - u8 ofdm_ht_dual_stream_basic_rates; -} __packed; - -/* 5000 HW just extend this command */ struct iwl_rxon_cmd { u8 node_addr[6]; __le16 reserved1; @@ -791,25 +686,6 @@ struct iwl_rxon_cmd { /* * REPLY_RXON_ASSOC = 0x11 (command, has simple generic response) */ -struct iwl3945_rxon_assoc_cmd { - __le32 flags; - __le32 filter_flags; - u8 ofdm_basic_rates; - u8 cck_basic_rates; - __le16 reserved; -} __packed; - -struct iwl4965_rxon_assoc_cmd { - __le32 flags; - __le32 filter_flags; - u8 ofdm_basic_rates; - u8 cck_basic_rates; - u8 ofdm_ht_single_stream_basic_rates; - u8 ofdm_ht_dual_stream_basic_rates; - __le16 rx_chain_select_flags; - __le16 reserved; -} __packed; - struct iwl5000_rxon_assoc_cmd { __le32 flags; __le32 filter_flags; @@ -845,26 +721,6 @@ struct iwl_rxon_time_cmd { /* * REPLY_CHANNEL_SWITCH = 0x72 (command, has simple generic response) */ -struct iwl3945_channel_switch_cmd { - u8 band; - u8 expect_beacon; - __le16 channel; - __le32 rxon_flags; - __le32 rxon_filter_flags; - __le32 switch_time; - struct iwl3945_power_per_rate power[IWL_MAX_RATES]; -} __packed; - -struct iwl4965_channel_switch_cmd { - u8 band; - u8 expect_beacon; - __le16 channel; - __le32 rxon_flags; - __le32 rxon_filter_flags; - __le32 switch_time; - struct iwl4965_tx_power_db tx_power; -} __packed; - /** * struct iwl5000_channel_switch_cmd * @band: 0- 5.2GHz, 1- 2.4GHz @@ -978,15 +834,10 @@ struct iwl_qosparam_cmd { #define IWL_AP_ID 0 #define IWL_AP_ID_PAN 1 #define IWL_STA_ID 2 -#define IWL3945_BROADCAST_ID 24 -#define IWL3945_STATION_COUNT 25 -#define IWL4965_BROADCAST_ID 31 -#define IWL4965_STATION_COUNT 32 #define IWLAGN_PAN_BCAST_ID 14 #define IWLAGN_BROADCAST_ID 15 #define IWLAGN_STATION_COUNT 16 -#define IWL_STATION_COUNT 32 /* MAX(3945,4965)*/ #define IWL_INVALID_STATION 255 #define STA_FLG_TX_RATE_MSK cpu_to_le32(1 << 2) @@ -1034,16 +885,6 @@ struct iwl_qosparam_cmd { * combined with Traffic ID (QOS priority), in format used by Tx Scheduler */ #define BUILD_RAxTID(sta_id, tid) (((sta_id) << 4) + (tid)) -struct iwl4965_keyinfo { - __le16 key_flags; - u8 tkip_rx_tsc_byte2; /* TSC[2] for key mix ph1 detection */ - u8 reserved1; - __le16 tkip_rx_ttak[5]; /* 10-byte unicast TKIP TTAK */ - u8 key_offset; - u8 reserved2; - u8 key[16]; /* 16-byte unicast decryption key */ -} __packed; - /* agn */ struct iwl_keyinfo { __le16 key_flags; @@ -1085,7 +926,6 @@ struct sta_id_modify { * with info on security keys, aggregation parameters, and Tx rates for * initial Tx attempt and any retries (agn devices uses * REPLY_TX_LINK_QUALITY_CMD, - * 3945 uses REPLY_RATE_SCALE to set up rate tables). * * REPLY_ADD_STA sets up the table entry for one station, either creating * a new entry, or modifying a pre-existing one. @@ -1105,72 +945,6 @@ struct sta_id_modify { * entries for all STAs in network, starting with index IWL_STA_ID. */ -struct iwl3945_addsta_cmd { - u8 mode; /* 1: modify existing, 0: add new station */ - u8 reserved[3]; - struct sta_id_modify sta; - struct iwl4965_keyinfo key; - __le32 station_flags; /* STA_FLG_* */ - __le32 station_flags_msk; /* STA_FLG_* */ - - /* bit field to disable (1) or enable (0) Tx for Traffic ID (TID) - * corresponding to bit (e.g. bit 5 controls TID 5). - * Set modify_mask bit STA_MODIFY_TID_DISABLE_TX to use this field. */ - __le16 tid_disable_tx; - - __le16 rate_n_flags; - - /* TID for which to add block-ack support. - * Set modify_mask bit STA_MODIFY_ADDBA_TID_MSK to use this field. */ - u8 add_immediate_ba_tid; - - /* TID for which to remove block-ack support. - * Set modify_mask bit STA_MODIFY_DELBA_TID_MSK to use this field. */ - u8 remove_immediate_ba_tid; - - /* Starting Sequence Number for added block-ack support. - * Set modify_mask bit STA_MODIFY_ADDBA_TID_MSK to use this field. */ - __le16 add_immediate_ba_ssn; -} __packed; - -struct iwl4965_addsta_cmd { - u8 mode; /* 1: modify existing, 0: add new station */ - u8 reserved[3]; - struct sta_id_modify sta; - struct iwl4965_keyinfo key; - __le32 station_flags; /* STA_FLG_* */ - __le32 station_flags_msk; /* STA_FLG_* */ - - /* bit field to disable (1) or enable (0) Tx for Traffic ID (TID) - * corresponding to bit (e.g. bit 5 controls TID 5). - * Set modify_mask bit STA_MODIFY_TID_DISABLE_TX to use this field. */ - __le16 tid_disable_tx; - - __le16 reserved1; - - /* TID for which to add block-ack support. - * Set modify_mask bit STA_MODIFY_ADDBA_TID_MSK to use this field. */ - u8 add_immediate_ba_tid; - - /* TID for which to remove block-ack support. - * Set modify_mask bit STA_MODIFY_DELBA_TID_MSK to use this field. */ - u8 remove_immediate_ba_tid; - - /* Starting Sequence Number for added block-ack support. - * Set modify_mask bit STA_MODIFY_ADDBA_TID_MSK to use this field. */ - __le16 add_immediate_ba_ssn; - - /* - * Number of packets OK to transmit to station even though - * it is asleep -- used to synchronise PS-poll and u-APSD - * responses while ucode keeps track of STA sleep state. - */ - __le16 sleep_tx_count; - - __le16 reserved2; -} __packed; - -/* agn */ struct iwl_addsta_cmd { u8 mode; /* 1: modify existing, 0: add new station */ u8 reserved[3]; @@ -1339,62 +1113,6 @@ struct iwl_wep_cmd { #define RX_MPDU_RES_STATUS_DEC_DONE_MSK (0x800) -struct iwl3945_rx_frame_stats { - u8 phy_count; - u8 id; - u8 rssi; - u8 agc; - __le16 sig_avg; - __le16 noise_diff; - u8 payload[0]; -} __packed; - -struct iwl3945_rx_frame_hdr { - __le16 channel; - __le16 phy_flags; - u8 reserved1; - u8 rate; - __le16 len; - u8 payload[0]; -} __packed; - -struct iwl3945_rx_frame_end { - __le32 status; - __le64 timestamp; - __le32 beacon_timestamp; -} __packed; - -/* - * REPLY_3945_RX = 0x1b (response only, not a command) - * - * NOTE: DO NOT dereference from casts to this structure - * It is provided only for calculating minimum data set size. - * The actual offsets of the hdr and end are dynamic based on - * stats.phy_count - */ -struct iwl3945_rx_frame { - struct iwl3945_rx_frame_stats stats; - struct iwl3945_rx_frame_hdr hdr; - struct iwl3945_rx_frame_end end; -} __packed; - -#define IWL39_RX_FRAME_SIZE (4 + sizeof(struct iwl3945_rx_frame)) - -/* Fixed (non-configurable) rx data from phy */ - -#define IWL49_RX_RES_PHY_CNT 14 -#define IWL49_RX_PHY_FLAGS_ANTENNAE_OFFSET (4) -#define IWL49_RX_PHY_FLAGS_ANTENNAE_MASK (0x70) -#define IWL49_AGC_DB_MASK (0x3f80) /* MASK(7,13) */ -#define IWL49_AGC_DB_POS (7) -struct iwl4965_rx_non_cfg_phy { - __le16 ant_selection; /* ant A bit 4, ant B bit 5, ant C bit 6 */ - __le16 agc_info; /* agc code 0:6, agc dB 7:13, reserved 14:15 */ - u8 rssi_info[6]; /* we use even entries, 0/2/4 for A/B/C rssi */ - u8 pad[0]; -} __packed; - - #define IWLAGN_RX_RES_PHY_CNT 8 #define IWLAGN_RX_RES_AGC_IDX 1 #define IWLAGN_RX_RES_RSSI_AB_IDX 2 @@ -1578,80 +1296,6 @@ struct iwl_rx_mpdu_res_start { * REPLY_TX = 0x1c (command) */ -struct iwl3945_tx_cmd { - /* - * MPDU byte count: - * MAC header (24/26/30/32 bytes) + 2 bytes pad if 26/30 header size, - * + 8 byte IV for CCM or TKIP (not used for WEP) - * + Data payload - * + 8-byte MIC (not used for CCM/WEP) - * NOTE: Does not include Tx command bytes, post-MAC pad bytes, - * MIC (CCM) 8 bytes, ICV (WEP/TKIP/CKIP) 4 bytes, CRC 4 bytes.i - * Range: 14-2342 bytes. - */ - __le16 len; - - /* - * MPDU or MSDU byte count for next frame. - * Used for fragmentation and bursting, but not 11n aggregation. - * Same as "len", but for next frame. Set to 0 if not applicable. - */ - __le16 next_frame_len; - - __le32 tx_flags; /* TX_CMD_FLG_* */ - - u8 rate; - - /* Index of recipient station in uCode's station table */ - u8 sta_id; - u8 tid_tspec; - u8 sec_ctl; - u8 key[16]; - union { - u8 byte[8]; - __le16 word[4]; - __le32 dw[2]; - } tkip_mic; - __le32 next_frame_info; - union { - __le32 life_time; - __le32 attempt; - } stop_time; - u8 supp_rates[2]; - u8 rts_retry_limit; /*byte 50 */ - u8 data_retry_limit; /*byte 51 */ - union { - __le16 pm_frame_timeout; - __le16 attempt_duration; - } timeout; - - /* - * Duration of EDCA burst Tx Opportunity, in 32-usec units. - * Set this if txop time is not specified by HCCA protocol (e.g. by AP). - */ - __le16 driver_txop; - - /* - * MAC header goes here, followed by 2 bytes padding if MAC header - * length is 26 or 30 bytes, followed by payload data - */ - u8 payload[0]; - struct ieee80211_hdr hdr[0]; -} __packed; - -/* - * REPLY_TX = 0x1c (response) - */ -struct iwl3945_tx_resp { - u8 failure_rts; - u8 failure_frame; - u8 bt_kill_count; - u8 rate; - __le32 wireless_media_time; - __le32 status; /* TX status */ -} __packed; - - /* * 4965 uCode updates these Tx attempt count values in host DRAM. * Used for managing Tx retries when expecting block-acks. @@ -1742,54 +1386,6 @@ struct iwl_tx_cmd { struct ieee80211_hdr hdr[0]; } __packed; -/* TX command response is sent after *3945* transmission attempts. - * - * NOTES: - * - * TX_STATUS_FAIL_NEXT_FRAG - * - * If the fragment flag in the MAC header for the frame being transmitted - * is set and there is insufficient time to transmit the next frame, the - * TX status will be returned with 'TX_STATUS_FAIL_NEXT_FRAG'. - * - * TX_STATUS_FIFO_UNDERRUN - * - * Indicates the host did not provide bytes to the FIFO fast enough while - * a TX was in progress. - * - * TX_STATUS_FAIL_MGMNT_ABORT - * - * This status is only possible if the ABORT ON MGMT RX parameter was - * set to true with the TX command. - * - * If the MSB of the status parameter is set then an abort sequence is - * required. This sequence consists of the host activating the TX Abort - * control line, and then waiting for the TX Abort command response. This - * indicates that a the device is no longer in a transmit state, and that the - * command FIFO has been cleared. The host must then deactivate the TX Abort - * control line. Receiving is still allowed in this case. - */ -enum { - TX_3945_STATUS_SUCCESS = 0x01, - TX_3945_STATUS_DIRECT_DONE = 0x02, - TX_3945_STATUS_FAIL_SHORT_LIMIT = 0x82, - TX_3945_STATUS_FAIL_LONG_LIMIT = 0x83, - TX_3945_STATUS_FAIL_FIFO_UNDERRUN = 0x84, - TX_3945_STATUS_FAIL_MGMNT_ABORT = 0x85, - TX_3945_STATUS_FAIL_NEXT_FRAG = 0x86, - TX_3945_STATUS_FAIL_LIFE_EXPIRE = 0x87, - TX_3945_STATUS_FAIL_DEST_PS = 0x88, - TX_3945_STATUS_FAIL_ABORTED = 0x89, - TX_3945_STATUS_FAIL_BT_RETRY = 0x8a, - TX_3945_STATUS_FAIL_STA_INVALID = 0x8b, - TX_3945_STATUS_FAIL_FRAG_DROPPED = 0x8c, - TX_3945_STATUS_FAIL_TID_DISABLE = 0x8d, - TX_3945_STATUS_FAIL_FRAME_FLUSHED = 0x8e, - TX_3945_STATUS_FAIL_INSUFFICIENT_CF_POLL = 0x8f, - TX_3945_STATUS_FAIL_TX_LOCKED = 0x90, - TX_3945_STATUS_FAIL_NO_BEACON_ON_RADAR = 0x91, -}; - /* * TX command response is sent after *agn* transmission attempts. * @@ -1907,43 +1503,6 @@ struct agg_tx_status { __le16 sequence; } __packed; -struct iwl4965_tx_resp { - u8 frame_count; /* 1 no aggregation, >1 aggregation */ - u8 bt_kill_count; /* # blocked by bluetooth (unused for agg) */ - u8 failure_rts; /* # failures due to unsuccessful RTS */ - u8 failure_frame; /* # failures due to no ACK (unused for agg) */ - - /* For non-agg: Rate at which frame was successful. - * For agg: Rate at which all frames were transmitted. */ - __le32 rate_n_flags; /* RATE_MCS_* */ - - /* For non-agg: RTS + CTS + frame tx attempts time + ACK. - * For agg: RTS + CTS + aggregation tx time + block-ack time. */ - __le16 wireless_media_time; /* uSecs */ - - __le16 reserved; - __le32 pa_power1; /* RF power amplifier measurement (not used) */ - __le32 pa_power2; - - /* - * For non-agg: frame status TX_STATUS_* - * For agg: status of 1st frame, AGG_TX_STATE_*; other frame status - * fields follow this one, up to frame_count. - * Bit fields: - * 11- 0: AGG_TX_STATE_* status code - * 15-12: Retry count for 1st frame in aggregation (retries - * occur if tx failed for this frame when it was a - * member of a previous aggregation block). If rate - * scaling is used, retry count indicates the rate - * table entry used for all frames in the new agg. - * 31-16: Sequence # for this frame's Tx cmd (not SSN!) - */ - union { - __le32 status; - struct agg_tx_status agg_status[0]; /* for each agg frame */ - } u; -} __packed; - /* * definitions for initial rate index field * bits [3:0] initial rate index @@ -2032,52 +1591,8 @@ struct iwl_compressed_ba_resp { /* * REPLY_TX_PWR_TABLE_CMD = 0x97 (command, has simple generic response) * - * See details under "TXPOWER" in iwl-4965-hw.h. */ -struct iwl3945_txpowertable_cmd { - u8 band; /* 0: 5 GHz, 1: 2.4 GHz */ - u8 reserved; - __le16 channel; - struct iwl3945_power_per_rate power[IWL_MAX_RATES]; -} __packed; - -struct iwl4965_txpowertable_cmd { - u8 band; /* 0: 5 GHz, 1: 2.4 GHz */ - u8 reserved; - __le16 channel; - struct iwl4965_tx_power_db tx_power; -} __packed; - - -/** - * struct iwl3945_rate_scaling_cmd - Rate Scaling Command & Response - * - * REPLY_RATE_SCALE = 0x47 (command, has simple generic response) - * - * NOTE: The table of rates passed to the uCode via the - * RATE_SCALE command sets up the corresponding order of - * rates used for all related commands, including rate - * masks, etc. - * - * For example, if you set 9MB (PLCP 0x0f) as the first - * rate in the rate table, the bit mask for that rate - * when passed through ofdm_basic_rates on the REPLY_RXON - * command would be bit 0 (1 << 0) - */ -struct iwl3945_rate_scaling_info { - __le16 rate_n_flags; - u8 try_cnt; - u8 next_rate_index; -} __packed; - -struct iwl3945_rate_scaling_cmd { - u8 table_id; - u8 reserved[3]; - struct iwl3945_rate_scaling_info table[IWL_MAX_RATES]; -} __packed; - - /*RS_NEW_API: only TLC_RTS remains and moved to bit 0 */ #define LINK_QUAL_FLAGS_SET_STA_TLC_RTS_MSK (1 << 0) @@ -2698,14 +2213,6 @@ struct iwl_spectrum_notification { #define IWL_POWER_BT_SCO_ENA cpu_to_le16(BIT(8)) #define IWL_POWER_ADVANCE_PM_ENA_MSK cpu_to_le16(BIT(9)) -struct iwl3945_powertable_cmd { - __le16 flags; - u8 reserved[2]; - __le32 rx_data_timeout; - __le32 tx_data_timeout; - __le32 sleep_interval[IWL_POWER_VEC_SIZE]; -} __packed; - struct iwl_powertable_cmd { __le16 flags; u8 keep_alive_seconds; /* 3945 reserved */ @@ -2808,25 +2315,6 @@ struct iwl_ct_kill_throttling_config { * active_dwell < max_out_time */ -/* FIXME: rename to AP1, remove tpc */ -struct iwl3945_scan_channel { - /* - * type is defined as: - * 0:0 1 = active, 0 = passive - * 1:4 SSID direct bit map; if a bit is set, then corresponding - * SSID IE is transmitted in probe request. - * 5:7 reserved - */ - u8 type; - u8 channel; /* band is selected by iwl3945_scan_cmd "flags" field */ - struct iwl3945_tx_power tpc; - __le16 active_dwell; /* in 1024-uSec TU (time units), typ 5-50 */ - __le16 passive_dwell; /* in 1024-uSec TU (time units), typ 20-500 */ -} __packed; - -/* set number of direct probes u8 type */ -#define IWL39_SCAN_PROBE_MASK(n) ((BIT(n) | (BIT(n) - BIT(1)))) - struct iwl_scan_channel { /* * type is defined as: @@ -2922,50 +2410,6 @@ struct iwl_ssid_ie { * struct iwl_scan_channel. */ -struct iwl3945_scan_cmd { - __le16 len; - u8 reserved0; - u8 channel_count; /* # channels in channel list */ - __le16 quiet_time; /* dwell only this # millisecs on quiet channel - * (only for active scan) */ - __le16 quiet_plcp_th; /* quiet chnl is < this # pkts (typ. 1) */ - __le16 good_CRC_th; /* passive -> active promotion threshold */ - __le16 reserved1; - __le32 max_out_time; /* max usec to be away from associated (service) - * channel */ - __le32 suspend_time; /* pause scan this long (in "extended beacon - * format") when returning to service channel: - * 3945; 31:24 # beacons, 19:0 additional usec, - * 4965; 31:22 # beacons, 21:0 additional usec. - */ - __le32 flags; /* RXON_FLG_* */ - __le32 filter_flags; /* RXON_FILTER_* */ - - /* For active scans (set to all-0s for passive scans). - * Does not include payload. Must specify Tx rate; no rate scaling. */ - struct iwl3945_tx_cmd tx_cmd; - - /* For directed active scans (set to all-0s otherwise) */ - struct iwl_ssid_ie direct_scan[PROBE_OPTION_MAX_3945]; - - /* - * Probe request frame, followed by channel list. - * - * Size of probe request frame is specified by byte count in tx_cmd. - * Channel list follows immediately after probe request frame. - * Number of channels in list is specified by channel_count. - * Each channel in list is of type: - * - * struct iwl3945_scan_channel channels[0]; - * - * NOTE: Only one band of channels can be scanned per pass. You - * must not mix 2.4GHz channels and 5.2GHz channels, and you must wait - * for one scan to complete (i.e. receive SCAN_COMPLETE_NOTIFICATION) - * before requesting another scan. - */ - u8 data[0]; -} __packed; - enum iwl_scan_flags { /* BIT(0) currently unused */ IWL_SCAN_FLAGS_ACTION_FRAME_TX = BIT(1), @@ -3092,20 +2536,6 @@ enum iwl_ibss_manager { * BEACON_NOTIFICATION = 0x90 (notification only, not a command) */ -struct iwl3945_beacon_notif { - struct iwl3945_tx_resp beacon_notify_hdr; - __le32 low_tsf; - __le32 high_tsf; - __le32 ibss_mgr_status; -} __packed; - -struct iwl4965_beacon_notif { - struct iwl4965_tx_resp beacon_notify_hdr; - __le32 low_tsf; - __le32 high_tsf; - __le32 ibss_mgr_status; -} __packed; - struct iwlagn_beacon_notif { struct iwlagn_tx_resp beacon_notify_hdr; __le32 low_tsf; @@ -3117,14 +2547,6 @@ struct iwlagn_beacon_notif { * REPLY_TX_BEACON = 0x91 (command, has simple generic response) */ -struct iwl3945_tx_beacon_cmd { - struct iwl3945_tx_cmd tx; - __le16 tim_idx; - u8 tim_size; - u8 reserved1; - struct ieee80211_hdr frame[0]; /* beacon frame */ -} __packed; - struct iwl_tx_beacon_cmd { struct iwl_tx_cmd tx; __le16 tim_idx; @@ -3473,13 +2895,6 @@ struct iwl_statistics_cmd { #define STATISTICS_REPLY_FLG_BAND_24G_MSK cpu_to_le32(0x2) #define STATISTICS_REPLY_FLG_HT40_MODE_MSK cpu_to_le32(0x8) -struct iwl3945_notif_statistics { - __le32 flag; - struct iwl39_statistics_rx rx; - struct iwl39_statistics_tx tx; - struct iwl39_statistics_general general; -} __packed; - struct iwl_notif_statistics { __le32 flag; struct statistics_rx rx; @@ -4453,10 +3868,6 @@ struct iwl_rx_packet { __le32 len_n_flags; struct iwl_cmd_header hdr; union { - struct iwl3945_rx_frame rx_frame; - struct iwl3945_tx_resp tx_resp; - struct iwl3945_beacon_notif beacon_status; - struct iwl_alive_resp alive_frame; struct iwl_spectrum_notification spectrum_notif; struct iwl_csa_notification csa_notif; diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index 6c30fa6..d778f52 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -1430,7 +1430,6 @@ void iwl_mac_remove_interface(struct ieee80211_hw *hw, iwl_teardown_interface(priv, vif, false); - memset(priv->bssid, 0, ETH_ALEN); mutex_unlock(&priv->mutex); IWL_DEBUG_MAC80211(priv, "leave\n"); diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index 1c9d2dd..8dc209a 100644 --- a/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h @@ -26,7 +26,6 @@ /* * Please use this file (iwl-dev.h) for driver implementation definitions. * Please use iwl-commands.h for uCode API definitions. - * Please use iwl-4965-hw.h for hardware-related definitions. */ #ifndef __iwl_dev_h__ @@ -179,53 +178,12 @@ struct iwl_tx_queue { #define IWL_NUM_SCAN_RATES (2) -struct iwl4965_channel_tgd_info { - u8 type; - s8 max_power; -}; - -struct iwl4965_channel_tgh_info { - s64 last_radar_time; -}; - -#define IWL4965_MAX_RATE (33) - -struct iwl3945_clip_group { - /* maximum power level to prevent clipping for each rate, derived by - * us from this band's saturation power in EEPROM */ - const s8 clip_powers[IWL_MAX_RATES]; -}; - -/* current Tx power values to use, one for each rate for each channel. - * requested power is limited by: - * -- regulatory EEPROM limits for this channel - * -- hardware capabilities (clip-powers) - * -- spectrum management - * -- user preference (e.g. iwconfig) - * when requested power is set, base power index must also be set. */ -struct iwl3945_channel_power_info { - struct iwl3945_tx_power tpc; /* actual radio and DSP gain settings */ - s8 power_table_index; /* actual (compenst'd) index into gain table */ - s8 base_power_index; /* gain index for power at factory temp. */ - s8 requested_power; /* power (dBm) requested for this chnl/rate */ -}; - -/* current scan Tx power values to use, one for each scan rate for each - * channel. */ -struct iwl3945_scan_power_info { - struct iwl3945_tx_power tpc; /* actual radio and DSP gain settings */ - s8 power_table_index; /* actual (compenst'd) index into gain table */ - s8 requested_power; /* scan pwr (dBm) requested for chnl/rate */ -}; - /* * One for each channel, holds all channel setup data * Some of the fields (e.g. eeprom and flags/max_power_avg) are redundant * with one another! */ struct iwl_channel_info { - struct iwl4965_channel_tgd_info tgd; - struct iwl4965_channel_tgh_info tgh; struct iwl_eeprom_channel eeprom; /* EEPROM regulatory limit */ struct iwl_eeprom_channel ht40_eeprom; /* EEPROM regulatory limit for * HT40 channel */ @@ -245,14 +203,6 @@ struct iwl_channel_info { s8 ht40_max_power_avg; /* (dBm) regul. eeprom, normal Tx, any rate */ u8 ht40_flags; /* flags copied from EEPROM */ u8 ht40_extension_channel; /* HT_IE_EXT_CHANNEL_* */ - - /* Radio/DSP gain settings for each "normal" data Tx rate. - * These include, in addition to RF and DSP gain, a few fields for - * remembering/modifying gain settings (indexes). */ - struct iwl3945_channel_power_info power_info[IWL4965_MAX_RATE]; - - /* Radio/DSP gain settings for each scan rate, for directed scans. */ - struct iwl3945_scan_power_info scan_pwr_info[IWL_NUM_SCAN_RATES]; }; #define IWL_TX_FIFO_BK 0 /* shared */ @@ -501,9 +451,6 @@ struct iwl_station_priv_common { * When mac80211 creates a station it reserves some space (hw->sta_data_size) * in the structure for use by driver. This structure is places in that * space. - * - * The common struct MUST be first because it is shared between - * 3945 and agn! */ struct iwl_station_priv { struct iwl_station_priv_common common; @@ -621,14 +568,6 @@ struct iwl_tlv_ucode_header { u8 data[0]; }; -struct iwl4965_ibss_seq { - u8 mac[ETH_ALEN]; - u16 seq_num; - u16 frag_num; - unsigned long packet_time; - struct list_head list; -}; - struct iwl_sensitivity_ranges { u16 min_nrg_cck; u16 max_nrg_cck; @@ -724,8 +663,6 @@ struct iwl_hw_params { * Naming convention -- * iwl_ <-- Is part of iwlwifi * iwlXXXX_ <-- Hardware specific (implemented in iwl-XXXX.c for XXXX) - * iwl4965_bg_ <-- Called from work queue context - * iwl4965_mac_ <-- mac80211 callback * ****************************************************************************/ extern void iwl_update_chain_flags(struct iwl_priv *priv); @@ -774,7 +711,6 @@ struct iwl_dma_ptr { /* Sensitivity and chain noise calibration */ #define INITIALIZATION_VALUE 0xFFFF -#define IWL4965_CAL_NUM_BEACONS 20 #define IWL_CAL_NUM_BEACONS 16 #define MAXIMUM_ALLOWED_PATHLOSS 15 @@ -808,24 +744,19 @@ struct iwl_dma_ptr { #define NRG_NUM_PREV_STAT_L 20 #define NUM_RX_CHAINS 3 -enum iwl4965_false_alarm_state { +enum iwlagn_false_alarm_state { IWL_FA_TOO_MANY = 0, IWL_FA_TOO_FEW = 1, IWL_FA_GOOD_RANGE = 2, }; -enum iwl4965_chain_noise_state { +enum iwlagn_chain_noise_state { IWL_CHAIN_NOISE_ALIVE = 0, /* must be 0 */ IWL_CHAIN_NOISE_ACCUMULATE, IWL_CHAIN_NOISE_CALIBRATED, IWL_CHAIN_NOISE_DONE, }; -enum iwl4965_calib_enabled_state { - IWL_CALIB_DISABLED = 0, /* must be 0 */ - IWL_CALIB_ENABLED = 1, -}; - /* * enum iwl_calib @@ -1133,12 +1064,6 @@ struct iwl_force_reset { /* extend beacon time format bit shifting */ /* - * for _3945 devices - * bits 31:24 - extended - * bits 23:0 - interval - */ -#define IWL3945_EXT_BEACON_TIME_POS 24 -/* * for _agn devices * bits 31:22 - extended * bits 21:0 - interval @@ -1391,15 +1316,12 @@ struct iwl_priv { struct iwl_power_mgr power_data; struct iwl_tt_mgmt thermal_throttle; - /* context information */ - u8 bssid[ETH_ALEN]; /* used only on 3945 but filled by core */ - /* station table variables */ /* Note: if lock and sta_lock are needed, lock must be acquired first */ spinlock_t sta_lock; int num_stations; - struct iwl_station_entry stations[IWL_STATION_COUNT]; + struct iwl_station_entry stations[IWLAGN_STATION_COUNT]; unsigned long ucode_key_table; /* queue refcounts */ @@ -1423,101 +1345,66 @@ struct iwl_priv { /* Last Rx'd beacon timestamp */ u64 timestamp; - union { -#if defined(CONFIG_IWL3945) || defined(CONFIG_IWL3945_MODULE) - struct { - void *shared_virt; - dma_addr_t shared_phys; - - struct delayed_work thermal_periodic; - struct delayed_work rfkill_poll; - - struct iwl3945_notif_statistics statistics; -#ifdef CONFIG_IWLWIFI_DEBUGFS - struct iwl3945_notif_statistics accum_statistics; - struct iwl3945_notif_statistics delta_statistics; - struct iwl3945_notif_statistics max_delta; -#endif - - u32 sta_supp_rates; - int last_rx_rssi; /* From Rx packet statistics */ - - /* Rx'd packet timing information */ - u32 last_beacon_time; - u64 last_tsf; - - /* - * each calibration channel group in the - * EEPROM has a derived clip setting for - * each rate. - */ - const struct iwl3945_clip_group clip_groups[5]; - - } _3945; -#endif -#if defined(CONFIG_IWLAGN) || defined(CONFIG_IWLAGN_MODULE) - struct { - /* INT ICT Table */ - __le32 *ict_tbl; - void *ict_tbl_vir; - dma_addr_t ict_tbl_dma; - dma_addr_t aligned_ict_tbl_dma; - int ict_index; - u32 inta; - bool use_ict; - /* - * reporting the number of tids has AGG on. 0 means - * no AGGREGATION - */ - u8 agg_tids_count; - - struct iwl_rx_phy_res last_phy_res; - bool last_phy_res_valid; - - struct completion firmware_loading_complete; - - u32 init_evtlog_ptr, init_evtlog_size, init_errlog_ptr; - u32 inst_evtlog_ptr, inst_evtlog_size, inst_errlog_ptr; - - /* - * chain noise reset and gain commands are the - * two extra calibration commands follows the standard - * phy calibration commands - */ - u8 phy_calib_chain_noise_reset_cmd; - u8 phy_calib_chain_noise_gain_cmd; - - struct iwl_notif_statistics statistics; - struct iwl_bt_notif_statistics statistics_bt; - /* counts reply_tx error */ - struct reply_tx_error_statistics reply_tx_stats; - struct reply_agg_tx_error_statistics reply_agg_tx_stats; + struct { + /* INT ICT Table */ + __le32 *ict_tbl; + void *ict_tbl_vir; + dma_addr_t ict_tbl_dma; + dma_addr_t aligned_ict_tbl_dma; + int ict_index; + u32 inta; + bool use_ict; + /* + * reporting the number of tids has AGG on. 0 means + * no AGGREGATION + */ + u8 agg_tids_count; + + struct iwl_rx_phy_res last_phy_res; + bool last_phy_res_valid; + + struct completion firmware_loading_complete; + + u32 init_evtlog_ptr, init_evtlog_size, init_errlog_ptr; + u32 inst_evtlog_ptr, inst_evtlog_size, inst_errlog_ptr; + + /* + * chain noise reset and gain commands are the + * two extra calibration commands follows the standard + * phy calibration commands + */ + u8 phy_calib_chain_noise_reset_cmd; + u8 phy_calib_chain_noise_gain_cmd; + + struct iwl_notif_statistics statistics; + struct iwl_bt_notif_statistics statistics_bt; + /* counts reply_tx error */ + struct reply_tx_error_statistics reply_tx_stats; + struct reply_agg_tx_error_statistics reply_agg_tx_stats; #ifdef CONFIG_IWLWIFI_DEBUGFS - struct iwl_notif_statistics accum_statistics; - struct iwl_notif_statistics delta_statistics; - struct iwl_notif_statistics max_delta; - struct iwl_bt_notif_statistics accum_statistics_bt; - struct iwl_bt_notif_statistics delta_statistics_bt; - struct iwl_bt_notif_statistics max_delta_bt; -#endif - - /* notification wait support */ - struct list_head notif_waits; - spinlock_t notif_wait_lock; - wait_queue_head_t notif_waitq; - - /* remain-on-channel offload support */ - struct ieee80211_channel *hw_roc_channel; - struct delayed_work hw_roc_work; - enum nl80211_channel_type hw_roc_chantype; - int hw_roc_duration; - - struct sk_buff *offchan_tx_skb; - int offchan_tx_timeout; - struct ieee80211_channel *offchan_tx_chan; - } _agn; + struct iwl_notif_statistics accum_statistics; + struct iwl_notif_statistics delta_statistics; + struct iwl_notif_statistics max_delta; + struct iwl_bt_notif_statistics accum_statistics_bt; + struct iwl_bt_notif_statistics delta_statistics_bt; + struct iwl_bt_notif_statistics max_delta_bt; #endif - }; + /* notification wait support */ + struct list_head notif_waits; + spinlock_t notif_wait_lock; + wait_queue_head_t notif_waitq; + + /* remain-on-channel offload support */ + struct ieee80211_channel *hw_roc_channel; + struct delayed_work hw_roc_work; + enum nl80211_channel_type hw_roc_chantype; + int hw_roc_duration; + bool hw_roc_setup; + + struct sk_buff *offchan_tx_skb; + int offchan_tx_timeout; + struct ieee80211_channel *offchan_tx_chan; + } _agn; /* bt coex */ u8 bt_enable_flag; diff --git a/drivers/net/wireless/iwlwifi/iwl-eeprom.h b/drivers/net/wireless/iwlwifi/iwl-eeprom.h index 98aa8af..d0f858a 100644 --- a/drivers/net/wireless/iwlwifi/iwl-eeprom.h +++ b/drivers/net/wireless/iwlwifi/iwl-eeprom.h @@ -110,10 +110,6 @@ enum { }; /* SKU Capabilities */ -/* 3945 only */ -#define EEPROM_SKU_CAP_SW_RF_KILL_ENABLE (1 << 0) -#define EEPROM_SKU_CAP_HW_RF_KILL_ENABLE (1 << 1) - /* 5000 and up */ #define EEPROM_SKU_CAP_BAND_POS (4) #define EEPROM_SKU_CAP_BAND_SELECTION \ @@ -168,28 +164,6 @@ struct iwl_eeprom_enhanced_txpwr { s8 mimo3_max; } __packed; -/* 3945 Specific */ -#define EEPROM_3945_EEPROM_VERSION (0x2f) - -/* 4965 has two radio transmitters (and 3 radio receivers) */ -#define EEPROM_TX_POWER_TX_CHAINS (2) - -/* 4965 has room for up to 8 sets of txpower calibration data */ -#define EEPROM_TX_POWER_BANDS (8) - -/* 4965 factory calibration measures txpower gain settings for - * each of 3 target output levels */ -#define EEPROM_TX_POWER_MEASUREMENTS (3) - -/* 4965 Specific */ -/* 4965 driver does not work with txpower calibration version < 5 */ -#define EEPROM_4965_TX_POWER_VERSION (5) -#define EEPROM_4965_EEPROM_VERSION (0x2f) -#define EEPROM_4965_CALIB_VERSION_OFFSET (2*0xB6) /* 2 bytes */ -#define EEPROM_4965_CALIB_TXPOWER_OFFSET (2*0xE8) /* 48 bytes */ -#define EEPROM_4965_BOARD_REVISION (2*0x4F) /* 2 bytes */ -#define EEPROM_4965_BOARD_PBA (2*0x56+1) /* 9 bytes */ - /* 5000 Specific */ #define EEPROM_5000_TX_POWER_VERSION (4) #define EEPROM_5000_EEPROM_VERSION (0x11A) @@ -282,90 +256,6 @@ struct iwl_eeprom_enhanced_txpwr { /* 2.4 GHz */ extern const u8 iwl_eeprom_band_1[14]; -/* - * factory calibration data for one txpower level, on one channel, - * measured on one of the 2 tx chains (radio transmitter and associated - * antenna). EEPROM contains: - * - * 1) Temperature (degrees Celsius) of device when measurement was made. - * - * 2) Gain table index used to achieve the target measurement power. - * This refers to the "well-known" gain tables (see iwl-4965-hw.h). - * - * 3) Actual measured output power, in half-dBm ("34" = 17 dBm). - * - * 4) RF power amplifier detector level measurement (not used). - */ -struct iwl_eeprom_calib_measure { - u8 temperature; /* Device temperature (Celsius) */ - u8 gain_idx; /* Index into gain table */ - u8 actual_pow; /* Measured RF output power, half-dBm */ - s8 pa_det; /* Power amp detector level (not used) */ -} __packed; - - -/* - * measurement set for one channel. EEPROM contains: - * - * 1) Channel number measured - * - * 2) Measurements for each of 3 power levels for each of 2 radio transmitters - * (a.k.a. "tx chains") (6 measurements altogether) - */ -struct iwl_eeprom_calib_ch_info { - u8 ch_num; - struct iwl_eeprom_calib_measure - measurements[EEPROM_TX_POWER_TX_CHAINS] - [EEPROM_TX_POWER_MEASUREMENTS]; -} __packed; - -/* - * txpower subband info. - * - * For each frequency subband, EEPROM contains the following: - * - * 1) First and last channels within range of the subband. "0" values - * indicate that this sample set is not being used. - * - * 2) Sample measurement sets for 2 channels close to the range endpoints. - */ -struct iwl_eeprom_calib_subband_info { - u8 ch_from; /* channel number of lowest channel in subband */ - u8 ch_to; /* channel number of highest channel in subband */ - struct iwl_eeprom_calib_ch_info ch1; - struct iwl_eeprom_calib_ch_info ch2; -} __packed; - - -/* - * txpower calibration info. EEPROM contains: - * - * 1) Factory-measured saturation power levels (maximum levels at which - * tx power amplifier can output a signal without too much distortion). - * There is one level for 2.4 GHz band and one for 5 GHz band. These - * values apply to all channels within each of the bands. - * - * 2) Factory-measured power supply voltage level. This is assumed to be - * constant (i.e. same value applies to all channels/bands) while the - * factory measurements are being made. - * - * 3) Up to 8 sets of factory-measured txpower calibration values. - * These are for different frequency ranges, since txpower gain - * characteristics of the analog radio circuitry vary with frequency. - * - * Not all sets need to be filled with data; - * struct iwl_eeprom_calib_subband_info contains range of channels - * (0 if unused) for each set of data. - */ -struct iwl_eeprom_calib_info { - u8 saturation_power24; /* half-dBm (e.g. "34" = 17 dBm) */ - u8 saturation_power52; /* half-dBm */ - __le16 voltage; /* signed */ - struct iwl_eeprom_calib_subband_info - band_info[EEPROM_TX_POWER_BANDS]; -} __packed; - - #define ADDRESS_MSK 0x0000FFFF #define INDIRECT_TYPE_MSK 0x000F0000 #define INDIRECT_HOST 0x00010000 @@ -398,83 +288,8 @@ struct iwl_eeprom_calib_info { #define EEPROM_RF_CFG_TX_ANT_MSK(x) ((x >> 8) & 0xF) /* bits 8-11 */ #define EEPROM_RF_CFG_RX_ANT_MSK(x) ((x >> 12) & 0xF) /* bits 12-15 */ -#define EEPROM_3945_RF_CFG_TYPE_MAX 0x0 -#define EEPROM_4965_RF_CFG_TYPE_MAX 0x1 - -/* Radio Config for 5000 and up */ -#define EEPROM_RF_CONFIG_TYPE_R3x3 0x0 -#define EEPROM_RF_CONFIG_TYPE_R2x2 0x1 -#define EEPROM_RF_CONFIG_TYPE_R1x2 0x2 #define EEPROM_RF_CONFIG_TYPE_MAX 0x3 -/* - * Per-channel regulatory data. - * - * Each channel that *might* be supported by iwl has a fixed location - * in EEPROM containing EEPROM_CHANNEL_* usage flags (LSB) and max regulatory - * txpower (MSB). - * - * Entries immediately below are for 20 MHz channel width. HT40 (40 MHz) - * channels (only for 4965, not supported by 3945) appear later in the EEPROM. - * - * 2.4 GHz channels 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14 - */ -#define EEPROM_REGULATORY_SKU_ID (2*0x60) /* 4 bytes */ -#define EEPROM_REGULATORY_BAND_1 (2*0x62) /* 2 bytes */ -#define EEPROM_REGULATORY_BAND_1_CHANNELS (2*0x63) /* 28 bytes */ - -/* - * 4.9 GHz channels 183, 184, 185, 187, 188, 189, 192, 196, - * 5.0 GHz channels 7, 8, 11, 12, 16 - * (4915-5080MHz) (none of these is ever supported) - */ -#define EEPROM_REGULATORY_BAND_2 (2*0x71) /* 2 bytes */ -#define EEPROM_REGULATORY_BAND_2_CHANNELS (2*0x72) /* 26 bytes */ - -/* - * 5.2 GHz channels 34, 36, 38, 40, 42, 44, 46, 48, 52, 56, 60, 64 - * (5170-5320MHz) - */ -#define EEPROM_REGULATORY_BAND_3 (2*0x7F) /* 2 bytes */ -#define EEPROM_REGULATORY_BAND_3_CHANNELS (2*0x80) /* 24 bytes */ - -/* - * 5.5 GHz channels 100, 104, 108, 112, 116, 120, 124, 128, 132, 136, 140 - * (5500-5700MHz) - */ -#define EEPROM_REGULATORY_BAND_4 (2*0x8C) /* 2 bytes */ -#define EEPROM_REGULATORY_BAND_4_CHANNELS (2*0x8D) /* 22 bytes */ - -/* - * 5.7 GHz channels 145, 149, 153, 157, 161, 165 - * (5725-5825MHz) - */ -#define EEPROM_REGULATORY_BAND_5 (2*0x98) /* 2 bytes */ -#define EEPROM_REGULATORY_BAND_5_CHANNELS (2*0x99) /* 12 bytes */ - -/* - * 2.4 GHz HT40 channels 1 (5), 2 (6), 3 (7), 4 (8), 5 (9), 6 (10), 7 (11) - * - * The channel listed is the center of the lower 20 MHz half of the channel. - * The overall center frequency is actually 2 channels (10 MHz) above that, - * and the upper half of each HT40 channel is centered 4 channels (20 MHz) away - * from the lower half; e.g. the upper half of HT40 channel 1 is channel 5, - * and the overall HT40 channel width centers on channel 3. - * - * NOTE: The RXON command uses 20 MHz channel numbers to specify the - * control channel to which to tune. RXON also specifies whether the - * control channel is the upper or lower half of a HT40 channel. - * - * NOTE: 4965 does not support HT40 channels on 2.4 GHz. - */ -#define EEPROM_4965_REGULATORY_BAND_24_HT40_CHANNELS (2*0xA0) /* 14 bytes */ - -/* - * 5.2 GHz HT40 channels 36 (40), 44 (48), 52 (56), 60 (64), - * 100 (104), 108 (112), 116 (120), 124 (128), 132 (136), 149 (153), 157 (161) - */ -#define EEPROM_4965_REGULATORY_BAND_52_HT40_CHANNELS (2*0xA8) /* 22 bytes */ - #define EEPROM_REGULATORY_BAND_NO_HT40 (0) struct iwl_eeprom_ops { diff --git a/drivers/net/wireless/iwlwifi/iwl-hcmd.c b/drivers/net/wireless/iwlwifi/iwl-hcmd.c index c71c0a4..165e756 100644 --- a/drivers/net/wireless/iwlwifi/iwl-hcmd.c +++ b/drivers/net/wireless/iwlwifi/iwl-hcmd.c @@ -51,9 +51,7 @@ const char *get_cmd_string(u8 cmd) IWL_CMD(REPLY_REMOVE_ALL_STA); IWL_CMD(REPLY_TXFIFO_FLUSH); IWL_CMD(REPLY_WEPKEY); - IWL_CMD(REPLY_3945_RX); IWL_CMD(REPLY_TX); - IWL_CMD(REPLY_RATE_SCALE); IWL_CMD(REPLY_LEDS_CMD); IWL_CMD(REPLY_TX_LINK_QUALITY_CMD); IWL_CMD(COEX_PRIORITY_TABLE_CMD); diff --git a/drivers/net/wireless/iwlwifi/iwl-prph.h b/drivers/net/wireless/iwlwifi/iwl-prph.h index 86f5123..81c4647 100644 --- a/drivers/net/wireless/iwlwifi/iwl-prph.h +++ b/drivers/net/wireless/iwlwifi/iwl-prph.h @@ -91,7 +91,6 @@ #define APMG_PS_CTRL_VAL_RESET_REQ (0x04000000) #define APMG_PS_CTRL_MSK_PWR_SRC (0x03000000) #define APMG_PS_CTRL_VAL_PWR_SRC_VMAIN (0x00000000) -#define APMG_PS_CTRL_VAL_PWR_SRC_MAX (0x01000000) /* 3945 only */ #define APMG_PS_CTRL_VAL_PWR_SRC_VAUX (0x02000000) #define APMG_SVR_VOLTAGE_CONFIG_BIT_MSK (0x000001E0) /* bit 8:5 */ #define APMG_SVR_DIGITAL_VOLTAGE_1_32 (0x00000060) @@ -234,16 +233,6 @@ #define BSM_SRAM_SIZE (1024) /* bytes */ -/* 3945 Tx scheduler registers */ -#define ALM_SCD_BASE (PRPH_BASE + 0x2E00) -#define ALM_SCD_MODE_REG (ALM_SCD_BASE + 0x000) -#define ALM_SCD_ARASTAT_REG (ALM_SCD_BASE + 0x004) -#define ALM_SCD_TXFACT_REG (ALM_SCD_BASE + 0x010) -#define ALM_SCD_TXF4MF_REG (ALM_SCD_BASE + 0x014) -#define ALM_SCD_TXF5MF_REG (ALM_SCD_BASE + 0x020) -#define ALM_SCD_SBYP_MODE_1_REG (ALM_SCD_BASE + 0x02C) -#define ALM_SCD_SBYP_MODE_2_REG (ALM_SCD_BASE + 0x030) - /** * Tx Scheduler * -- cgit v0.10.2 From 2dedbf58b2edbe940d370845dbf4210f1ddd2b31 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 5 Apr 2011 09:41:50 -0700 Subject: iwlagn: make mac80211 handlers static Now that these handlers are no longer shared between 4965 and agn, they can be static. Signed-off-by: Johannes Berg Signed-off-by: Wey-Yi Guy Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index 42fad62..b701a03 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -2921,7 +2921,7 @@ static int iwl_mac_setup_register(struct iwl_priv *priv, } -int iwlagn_mac_start(struct ieee80211_hw *hw) +static int iwlagn_mac_start(struct ieee80211_hw *hw) { struct iwl_priv *priv = hw->priv; int ret; @@ -2962,7 +2962,7 @@ out: return 0; } -void iwlagn_mac_stop(struct ieee80211_hw *hw) +static void iwlagn_mac_stop(struct ieee80211_hw *hw) { struct iwl_priv *priv = hw->priv; @@ -2985,7 +2985,7 @@ void iwlagn_mac_stop(struct ieee80211_hw *hw) IWL_DEBUG_MAC80211(priv, "leave\n"); } -void iwlagn_mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb) +static void iwlagn_mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb) { struct iwl_priv *priv = hw->priv; @@ -3000,11 +3000,11 @@ void iwlagn_mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb) IWL_DEBUG_MACDUMP(priv, "leave\n"); } -void iwlagn_mac_update_tkip_key(struct ieee80211_hw *hw, - struct ieee80211_vif *vif, - struct ieee80211_key_conf *keyconf, - struct ieee80211_sta *sta, - u32 iv32, u16 *phase1key) +static void iwlagn_mac_update_tkip_key(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct ieee80211_key_conf *keyconf, + struct ieee80211_sta *sta, + u32 iv32, u16 *phase1key) { struct iwl_priv *priv = hw->priv; struct iwl_vif_priv *vif_priv = (void *)vif->drv_priv; @@ -3017,9 +3017,10 @@ void iwlagn_mac_update_tkip_key(struct ieee80211_hw *hw, IWL_DEBUG_MAC80211(priv, "leave\n"); } -int iwlagn_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, - struct ieee80211_vif *vif, struct ieee80211_sta *sta, - struct ieee80211_key_conf *key) +static int iwlagn_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, + struct ieee80211_vif *vif, + struct ieee80211_sta *sta, + struct ieee80211_key_conf *key) { struct iwl_priv *priv = hw->priv; struct iwl_vif_priv *vif_priv = (void *)vif->drv_priv; @@ -3094,11 +3095,11 @@ int iwlagn_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, return ret; } -int iwlagn_mac_ampdu_action(struct ieee80211_hw *hw, - struct ieee80211_vif *vif, - enum ieee80211_ampdu_mlme_action action, - struct ieee80211_sta *sta, u16 tid, u16 *ssn, - u8 buf_size) +static int iwlagn_mac_ampdu_action(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + enum ieee80211_ampdu_mlme_action action, + struct ieee80211_sta *sta, u16 tid, u16 *ssn, + u8 buf_size) { struct iwl_priv *priv = hw->priv; int ret = -EINVAL; @@ -3205,9 +3206,9 @@ int iwlagn_mac_ampdu_action(struct ieee80211_hw *hw, return ret; } -int iwlagn_mac_sta_add(struct ieee80211_hw *hw, - struct ieee80211_vif *vif, - struct ieee80211_sta *sta) +static int iwlagn_mac_sta_add(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct ieee80211_sta *sta) { struct iwl_priv *priv = hw->priv; struct iwl_station_priv *sta_priv = (void *)sta->drv_priv; @@ -3248,8 +3249,8 @@ int iwlagn_mac_sta_add(struct ieee80211_hw *hw, return 0; } -void iwlagn_mac_channel_switch(struct ieee80211_hw *hw, - struct ieee80211_channel_switch *ch_switch) +static void iwlagn_mac_channel_switch(struct ieee80211_hw *hw, + struct ieee80211_channel_switch *ch_switch) { struct iwl_priv *priv = hw->priv; const struct iwl_channel_info *ch_info; @@ -3346,10 +3347,10 @@ out: IWL_DEBUG_MAC80211(priv, "leave\n"); } -void iwlagn_configure_filter(struct ieee80211_hw *hw, - unsigned int changed_flags, - unsigned int *total_flags, - u64 multicast) +static void iwlagn_configure_filter(struct ieee80211_hw *hw, + unsigned int changed_flags, + unsigned int *total_flags, + u64 multicast) { struct iwl_priv *priv = hw->priv; __le32 filter_or = 0, filter_nand = 0; @@ -3396,7 +3397,7 @@ void iwlagn_configure_filter(struct ieee80211_hw *hw, FIF_BCN_PRBRESP_PROMISC | FIF_CONTROL; } -void iwlagn_mac_flush(struct ieee80211_hw *hw, bool drop) +static void iwlagn_mac_flush(struct ieee80211_hw *hw, bool drop) { struct iwl_priv *priv = hw->priv; diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.h b/drivers/net/wireless/iwlwifi/iwl-agn.h index 80de8a1..4a0a46e 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.h +++ b/drivers/net/wireless/iwlwifi/iwl-agn.h @@ -337,32 +337,4 @@ void __releases(wait_entry) iwlagn_remove_notification(struct iwl_priv *priv, struct iwl_notification_wait *wait_entry); -/* mac80211 handlers (for 4965) */ -void iwlagn_mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb); -int iwlagn_mac_start(struct ieee80211_hw *hw); -void iwlagn_mac_stop(struct ieee80211_hw *hw); -void iwlagn_configure_filter(struct ieee80211_hw *hw, - unsigned int changed_flags, - unsigned int *total_flags, - u64 multicast); -int iwlagn_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, - struct ieee80211_vif *vif, struct ieee80211_sta *sta, - struct ieee80211_key_conf *key); -void iwlagn_mac_update_tkip_key(struct ieee80211_hw *hw, - struct ieee80211_vif *vif, - struct ieee80211_key_conf *keyconf, - struct ieee80211_sta *sta, - u32 iv32, u16 *phase1key); -int iwlagn_mac_ampdu_action(struct ieee80211_hw *hw, - struct ieee80211_vif *vif, - enum ieee80211_ampdu_mlme_action action, - struct ieee80211_sta *sta, u16 tid, u16 *ssn, - u8 buf_size); -int iwlagn_mac_sta_add(struct ieee80211_hw *hw, - struct ieee80211_vif *vif, - struct ieee80211_sta *sta); -void iwlagn_mac_channel_switch(struct ieee80211_hw *hw, - struct ieee80211_channel_switch *ch_switch); -void iwlagn_mac_flush(struct ieee80211_hw *hw, bool drop); - #endif /* __iwl_agn_h__ */ -- cgit v0.10.2 From 7102762ef0ef330ab0601b6c3bc92bf9be5b1317 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 5 Apr 2011 09:41:51 -0700 Subject: iwlagn: clean up ucode loading All agn devices behave the same, so there's no need to go through function pointers for any of the ucode loading functionality. Signed-off-by: Johannes Berg Signed-off-by: Wey-Yi Guy Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwlwifi/iwl-1000.c b/drivers/net/wireless/iwlwifi/iwl-1000.c index 2601b55..ad50063 100644 --- a/drivers/net/wireless/iwlwifi/iwl-1000.c +++ b/drivers/net/wireless/iwlwifi/iwl-1000.c @@ -185,13 +185,10 @@ static struct iwl_lib_ops iwl1000_lib = { .rx_handler_setup = iwlagn_rx_handler_setup, .setup_deferred_work = iwlagn_setup_deferred_work, .is_valid_rtc_data_addr = iwlagn_hw_valid_rtc_data_addr, - .load_ucode = iwlagn_load_ucode, .dump_nic_event_log = iwl_dump_nic_event_log, .dump_nic_error_log = iwl_dump_nic_error_log, .dump_csr = iwl_dump_csr, .dump_fh = iwl_dump_fh, - .init_alive_start = iwlagn_init_alive_start, - .alive_notify = iwlagn_alive_notify, .send_tx_power = iwlagn_send_tx_power, .update_chain_flags = iwl_update_chain_flags, .apm_ops = { diff --git a/drivers/net/wireless/iwlwifi/iwl-2000.c b/drivers/net/wireless/iwlwifi/iwl-2000.c index 55274a1..5e375d8 100644 --- a/drivers/net/wireless/iwlwifi/iwl-2000.c +++ b/drivers/net/wireless/iwlwifi/iwl-2000.c @@ -266,13 +266,10 @@ static struct iwl_lib_ops iwl2000_lib = { .setup_deferred_work = iwlagn_bt_setup_deferred_work, .cancel_deferred_work = iwlagn_bt_cancel_deferred_work, .is_valid_rtc_data_addr = iwlagn_hw_valid_rtc_data_addr, - .load_ucode = iwlagn_load_ucode, .dump_nic_event_log = iwl_dump_nic_event_log, .dump_nic_error_log = iwl_dump_nic_error_log, .dump_csr = iwl_dump_csr, .dump_fh = iwl_dump_fh, - .init_alive_start = iwlagn_init_alive_start, - .alive_notify = iwlagn_alive_notify, .send_tx_power = iwlagn_send_tx_power, .update_chain_flags = iwl_update_chain_flags, .set_channel_switch = iwl2030_hw_channel_switch, diff --git a/drivers/net/wireless/iwlwifi/iwl-5000.c b/drivers/net/wireless/iwlwifi/iwl-5000.c index 8cab357..0e1f0b5 100644 --- a/drivers/net/wireless/iwlwifi/iwl-5000.c +++ b/drivers/net/wireless/iwlwifi/iwl-5000.c @@ -358,9 +358,6 @@ static struct iwl_lib_ops iwl5000_lib = { .dump_nic_error_log = iwl_dump_nic_error_log, .dump_csr = iwl_dump_csr, .dump_fh = iwl_dump_fh, - .load_ucode = iwlagn_load_ucode, - .init_alive_start = iwlagn_init_alive_start, - .alive_notify = iwlagn_alive_notify, .send_tx_power = iwlagn_send_tx_power, .update_chain_flags = iwl_update_chain_flags, .set_channel_switch = iwl5000_hw_channel_switch, @@ -423,9 +420,6 @@ static struct iwl_lib_ops iwl5150_lib = { .dump_nic_event_log = iwl_dump_nic_event_log, .dump_nic_error_log = iwl_dump_nic_error_log, .dump_csr = iwl_dump_csr, - .load_ucode = iwlagn_load_ucode, - .init_alive_start = iwlagn_init_alive_start, - .alive_notify = iwlagn_alive_notify, .send_tx_power = iwlagn_send_tx_power, .update_chain_flags = iwl_update_chain_flags, .set_channel_switch = iwl5000_hw_channel_switch, diff --git a/drivers/net/wireless/iwlwifi/iwl-6000.c b/drivers/net/wireless/iwlwifi/iwl-6000.c index 7ecfbbc..4d545e6 100644 --- a/drivers/net/wireless/iwlwifi/iwl-6000.c +++ b/drivers/net/wireless/iwlwifi/iwl-6000.c @@ -294,13 +294,10 @@ static struct iwl_lib_ops iwl6000_lib = { .rx_handler_setup = iwlagn_rx_handler_setup, .setup_deferred_work = iwlagn_setup_deferred_work, .is_valid_rtc_data_addr = iwlagn_hw_valid_rtc_data_addr, - .load_ucode = iwlagn_load_ucode, .dump_nic_event_log = iwl_dump_nic_event_log, .dump_nic_error_log = iwl_dump_nic_error_log, .dump_csr = iwl_dump_csr, .dump_fh = iwl_dump_fh, - .init_alive_start = iwlagn_init_alive_start, - .alive_notify = iwlagn_alive_notify, .send_tx_power = iwlagn_send_tx_power, .update_chain_flags = iwl_update_chain_flags, .set_channel_switch = iwl6000_hw_channel_switch, @@ -362,13 +359,10 @@ static struct iwl_lib_ops iwl6030_lib = { .setup_deferred_work = iwlagn_bt_setup_deferred_work, .cancel_deferred_work = iwlagn_bt_cancel_deferred_work, .is_valid_rtc_data_addr = iwlagn_hw_valid_rtc_data_addr, - .load_ucode = iwlagn_load_ucode, .dump_nic_event_log = iwl_dump_nic_event_log, .dump_nic_error_log = iwl_dump_nic_error_log, .dump_csr = iwl_dump_csr, .dump_fh = iwl_dump_fh, - .init_alive_start = iwlagn_init_alive_start, - .alive_notify = iwlagn_alive_notify, .send_tx_power = iwlagn_send_tx_power, .update_chain_flags = iwl_update_chain_flags, .set_channel_switch = iwl6000_hw_channel_switch, diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-ucode.c b/drivers/net/wireless/iwlwifi/iwl-agn-ucode.c index d807e5e..5d35e35 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-ucode.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-ucode.c @@ -318,7 +318,7 @@ void iwlagn_init_alive_start(struct iwl_priv *priv) goto restart; } - ret = priv->cfg->ops->lib->alive_notify(priv); + ret = iwlagn_alive_notify(priv); if (ret) { IWL_WARN(priv, "Could not complete ALIVE transition: %d\n", ret); diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index b701a03..c8cd333 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -2248,7 +2248,7 @@ static void iwl_alive_start(struct iwl_priv *priv) goto restart; } - ret = priv->cfg->ops->lib->alive_notify(priv); + ret = iwlagn_alive_notify(priv); if (ret) { IWL_WARN(priv, "Could not complete ALIVE transition [ntf]: %d\n", ret); @@ -2581,7 +2581,7 @@ static int __iwl_up(struct iwl_priv *priv) /* load bootstrap state machine, * load bootstrap program into processor's memory, * prepare to load the "initialize" uCode */ - ret = priv->cfg->ops->lib->load_ucode(priv); + ret = iwlagn_load_ucode(priv); if (ret) { IWL_ERR(priv, "Unable to set up bootstrap uCode: %d\n", @@ -2626,7 +2626,7 @@ static void iwl_bg_init_alive_start(struct work_struct *data) return; } - priv->cfg->ops->lib->init_alive_start(priv); + iwlagn_init_alive_start(priv); mutex_unlock(&priv->mutex); } diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h index 967b4c0..46c90b3 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.h +++ b/drivers/net/wireless/iwlwifi/iwl-core.h @@ -177,14 +177,9 @@ struct iwl_lib_ops { void (*setup_deferred_work)(struct iwl_priv *priv); /* cancel deferred work */ void (*cancel_deferred_work)(struct iwl_priv *priv); - /* alive notification after init uCode load */ - void (*init_alive_start)(struct iwl_priv *priv); - /* alive notification */ - int (*alive_notify)(struct iwl_priv *priv); /* check validity of rtc data address */ int (*is_valid_rtc_data_addr)(u32 addr); - /* 1st ucode load */ - int (*load_ucode)(struct iwl_priv *priv); + int (*dump_nic_event_log)(struct iwl_priv *priv, bool full_log, char **buf, bool display); void (*dump_nic_error_log)(struct iwl_priv *priv); -- cgit v0.10.2 From 4de10b188070b1b96743b1b912843af729ebe50f Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Tue, 5 Apr 2011 09:41:52 -0700 Subject: iwlagn: remove more 3945/4965 related defines After driver split, remove unused #defines Signed-off-by: Wey-Yi Guy Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwlwifi/iwl-prph.h b/drivers/net/wireless/iwlwifi/iwl-prph.h index 81c4647..448b0ea 100644 --- a/drivers/net/wireless/iwlwifi/iwl-prph.h +++ b/drivers/net/wireless/iwlwifi/iwl-prph.h @@ -98,142 +98,6 @@ #define APMG_PCIDEV_STT_VAL_L1_ACT_DIS (0x00000800) /** - * BSM (Bootstrap State Machine) - * - * The Bootstrap State Machine (BSM) stores a short bootstrap uCode program - * in special SRAM that does not power down when the embedded control - * processor is sleeping (e.g. for periodic power-saving shutdowns of radio). - * - * When powering back up after sleeps (or during initial uCode load), the BSM - * internally loads the short bootstrap program from the special SRAM into the - * embedded processor's instruction SRAM, and starts the processor so it runs - * the bootstrap program. - * - * This bootstrap program loads (via PCI busmaster DMA) instructions and data - * images for a uCode program from host DRAM locations. The host driver - * indicates DRAM locations and sizes for instruction and data images via the - * four BSM_DRAM_* registers. Once the bootstrap program loads the new program, - * the new program starts automatically. - * - * The uCode used for open-source drivers includes two programs: - * - * 1) Initialization -- performs hardware calibration and sets up some - * internal data, then notifies host via "initialize alive" notification - * (struct iwl_init_alive_resp) that it has completed all of its work. - * After signal from host, it then loads and starts the runtime program. - * The initialization program must be used when initially setting up the - * NIC after loading the driver. - * - * 2) Runtime/Protocol -- performs all normal runtime operations. This - * notifies host via "alive" notification (struct iwl_alive_resp) that it - * is ready to be used. - * - * When initializing the NIC, the host driver does the following procedure: - * - * 1) Load bootstrap program (instructions only, no data image for bootstrap) - * into bootstrap memory. Use dword writes starting at BSM_SRAM_LOWER_BOUND - * - * 2) Point (via BSM_DRAM_*) to the "initialize" uCode data and instruction - * images in host DRAM. - * - * 3) Set up BSM to copy from BSM SRAM into uCode instruction SRAM when asked: - * BSM_WR_MEM_SRC_REG = 0 - * BSM_WR_MEM_DST_REG = RTC_INST_LOWER_BOUND - * BSM_WR_MEM_DWCOUNT_REG = # dwords in bootstrap instruction image - * - * 4) Load bootstrap into instruction SRAM: - * BSM_WR_CTRL_REG = BSM_WR_CTRL_REG_BIT_START - * - * 5) Wait for load completion: - * Poll BSM_WR_CTRL_REG for BSM_WR_CTRL_REG_BIT_START = 0 - * - * 6) Enable future boot loads whenever NIC's power management triggers it: - * BSM_WR_CTRL_REG = BSM_WR_CTRL_REG_BIT_START_EN - * - * 7) Start the NIC by removing all reset bits: - * CSR_RESET = 0 - * - * The bootstrap uCode (already in instruction SRAM) loads initialization - * uCode. Initialization uCode performs data initialization, sends - * "initialize alive" notification to host, and waits for a signal from - * host to load runtime code. - * - * 4) Point (via BSM_DRAM_*) to the "runtime" uCode data and instruction - * images in host DRAM. The last register loaded must be the instruction - * byte count register ("1" in MSbit tells initialization uCode to load - * the runtime uCode): - * BSM_DRAM_INST_BYTECOUNT_REG = byte count | BSM_DRAM_INST_LOAD - * - * 5) Wait for "alive" notification, then issue normal runtime commands. - * - * Data caching during power-downs: - * - * Just before the embedded controller powers down (e.g for automatic - * power-saving modes, or for RFKILL), uCode stores (via PCI busmaster DMA) - * a current snapshot of the embedded processor's data SRAM into host DRAM. - * This caches the data while the embedded processor's memory is powered down. - * Location and size are controlled by BSM_DRAM_DATA_* registers. - * - * NOTE: Instruction SRAM does not need to be saved, since that doesn't - * change during operation; the original image (from uCode distribution - * file) can be used for reload. - * - * When powering back up, the BSM loads the bootstrap program. Bootstrap looks - * at the BSM_DRAM_* registers, which now point to the runtime instruction - * image and the cached (modified) runtime data (*not* the initialization - * uCode). Bootstrap reloads these runtime images into SRAM, and restarts the - * uCode from where it left off before the power-down. - * - * NOTE: Initialization uCode does *not* run as part of the save/restore - * procedure. - * - * This save/restore method is mostly for autonomous power management during - * normal operation (result of POWER_TABLE_CMD). Platform suspend/resume and - * RFKILL should use complete restarts (with total re-initialization) of uCode, - * allowing total shutdown (including BSM memory). - * - * Note that, during normal operation, the host DRAM that held the initial - * startup data for the runtime code is now being used as a backup data cache - * for modified data! If you need to completely re-initialize the NIC, make - * sure that you use the runtime data image from the uCode distribution file, - * not the modified/saved runtime data. You may want to store a separate - * "clean" runtime data image in DRAM to avoid disk reads of distribution file. - */ - -/* BSM bit fields */ -#define BSM_WR_CTRL_REG_BIT_START (0x80000000) /* start boot load now */ -#define BSM_WR_CTRL_REG_BIT_START_EN (0x40000000) /* enable boot after pwrup*/ -#define BSM_DRAM_INST_LOAD (0x80000000) /* start program load now */ - -/* BSM addresses */ -#define BSM_BASE (PRPH_BASE + 0x3400) -#define BSM_END (PRPH_BASE + 0x3800) - -#define BSM_WR_CTRL_REG (BSM_BASE + 0x000) /* ctl and status */ -#define BSM_WR_MEM_SRC_REG (BSM_BASE + 0x004) /* source in BSM mem */ -#define BSM_WR_MEM_DST_REG (BSM_BASE + 0x008) /* dest in SRAM mem */ -#define BSM_WR_DWCOUNT_REG (BSM_BASE + 0x00C) /* bytes */ -#define BSM_WR_STATUS_REG (BSM_BASE + 0x010) /* bit 0: 1 == done */ - -/* - * Pointers and size regs for bootstrap load and data SRAM save/restore. - * NOTE: 3945 pointers use bits 31:0 of DRAM address. - * 4965 pointers use bits 35:4 of DRAM address. - */ -#define BSM_DRAM_INST_PTR_REG (BSM_BASE + 0x090) -#define BSM_DRAM_INST_BYTECOUNT_REG (BSM_BASE + 0x094) -#define BSM_DRAM_DATA_PTR_REG (BSM_BASE + 0x098) -#define BSM_DRAM_DATA_BYTECOUNT_REG (BSM_BASE + 0x09C) - -/* - * BSM special memory, stays powered on during power-save sleeps. - * Read/write, address range from LOWER_BOUND to (LOWER_BOUND + SIZE -1) - */ -#define BSM_SRAM_LOWER_BOUND (PRPH_BASE + 0x3800) -#define BSM_SRAM_SIZE (1024) /* bytes */ - - -/** * Tx Scheduler * * The Tx Scheduler selects the next frame to be transmitted, choosing TFDs @@ -319,201 +183,10 @@ * Max Tx window size is the max number of contiguous TFDs that the scheduler * can keep track of at one time when creating block-ack chains of frames. * Note that "64" matches the number of ack bits in a block-ack packet. - * Driver should use SCD_WIN_SIZE and SCD_FRAME_LIMIT values to initialize - * IWL49_SCD_CONTEXT_QUEUE_OFFSET(x) values. */ #define SCD_WIN_SIZE 64 #define SCD_FRAME_LIMIT 64 -/* SCD registers are internal, must be accessed via HBUS_TARG_PRPH regs */ -#define IWL49_SCD_START_OFFSET 0xa02c00 - -/* - * 4965 tells driver SRAM address for internal scheduler structs via this reg. - * Value is valid only after "Alive" response from uCode. - */ -#define IWL49_SCD_SRAM_BASE_ADDR (IWL49_SCD_START_OFFSET + 0x0) - -/* - * Driver may need to update queue-empty bits after changing queue's - * write and read pointers (indexes) during (re-)initialization (i.e. when - * scheduler is not tracking what's happening). - * Bit fields: - * 31-16: Write mask -- 1: update empty bit, 0: don't change empty bit - * 15-00: Empty state, one for each queue -- 1: empty, 0: non-empty - * NOTE: This register is not used by Linux driver. - */ -#define IWL49_SCD_EMPTY_BITS (IWL49_SCD_START_OFFSET + 0x4) - -/* - * Physical base address of array of byte count (BC) circular buffers (CBs). - * Each Tx queue has a BC CB in host DRAM to support Scheduler-ACK mode. - * This register points to BC CB for queue 0, must be on 1024-byte boundary. - * Others are spaced by 1024 bytes. - * Each BC CB is 2 bytes * (256 + 64) = 740 bytes, followed by 384 bytes pad. - * (Index into a queue's BC CB) = (index into queue's TFD CB) = (SSN & 0xff). - * Bit fields: - * 25-00: Byte Count CB physical address [35:10], must be 1024-byte aligned. - */ -#define IWL49_SCD_DRAM_BASE_ADDR (IWL49_SCD_START_OFFSET + 0x10) - -/* - * Enables any/all Tx DMA/FIFO channels. - * Scheduler generates requests for only the active channels. - * Set this to 0xff to enable all 8 channels (normal usage). - * Bit fields: - * 7- 0: Enable (1), disable (0), one bit for each channel 0-7 - */ -#define IWL49_SCD_TXFACT (IWL49_SCD_START_OFFSET + 0x1c) -/* - * Queue (x) Write Pointers (indexes, really!), one for each Tx queue. - * Initialized and updated by driver as new TFDs are added to queue. - * NOTE: If using Block Ack, index must correspond to frame's - * Start Sequence Number; index = (SSN & 0xff) - * NOTE: Alternative to HBUS_TARG_WRPTR, which is what Linux driver uses? - */ -#define IWL49_SCD_QUEUE_WRPTR(x) (IWL49_SCD_START_OFFSET + 0x24 + (x) * 4) - -/* - * Queue (x) Read Pointers (indexes, really!), one for each Tx queue. - * For FIFO mode, index indicates next frame to transmit. - * For Scheduler-ACK mode, index indicates first frame in Tx window. - * Initialized by driver, updated by scheduler. - */ -#define IWL49_SCD_QUEUE_RDPTR(x) (IWL49_SCD_START_OFFSET + 0x64 + (x) * 4) - -/* - * Select which queues work in chain mode (1) vs. not (0). - * Use chain mode to build chains of aggregated frames. - * Bit fields: - * 31-16: Reserved - * 15-00: Mode, one bit for each queue -- 1: Chain mode, 0: one-at-a-time - * NOTE: If driver sets up queue for chain mode, it should be also set up - * Scheduler-ACK mode as well, via SCD_QUEUE_STATUS_BITS(x). - */ -#define IWL49_SCD_QUEUECHAIN_SEL (IWL49_SCD_START_OFFSET + 0xd0) - -/* - * Select which queues interrupt driver when scheduler increments - * a queue's read pointer (index). - * Bit fields: - * 31-16: Reserved - * 15-00: Interrupt enable, one bit for each queue -- 1: enabled, 0: disabled - * NOTE: This functionality is apparently a no-op; driver relies on interrupts - * from Rx queue to read Tx command responses and update Tx queues. - */ -#define IWL49_SCD_INTERRUPT_MASK (IWL49_SCD_START_OFFSET + 0xe4) - -/* - * Queue search status registers. One for each queue. - * Sets up queue mode and assigns queue to Tx DMA channel. - * Bit fields: - * 19-10: Write mask/enable bits for bits 0-9 - * 9: Driver should init to "0" - * 8: Scheduler-ACK mode (1), non-Scheduler-ACK (i.e. FIFO) mode (0). - * Driver should init to "1" for aggregation mode, or "0" otherwise. - * 7-6: Driver should init to "0" - * 5: Window Size Left; indicates whether scheduler can request - * another TFD, based on window size, etc. Driver should init - * this bit to "1" for aggregation mode, or "0" for non-agg. - * 4-1: Tx FIFO to use (range 0-7). - * 0: Queue is active (1), not active (0). - * Other bits should be written as "0" - * - * NOTE: If enabling Scheduler-ACK mode, chain mode should also be enabled - * via SCD_QUEUECHAIN_SEL. - */ -#define IWL49_SCD_QUEUE_STATUS_BITS(x)\ - (IWL49_SCD_START_OFFSET + 0x104 + (x) * 4) - -/* Bit field positions */ -#define IWL49_SCD_QUEUE_STTS_REG_POS_ACTIVE (0) -#define IWL49_SCD_QUEUE_STTS_REG_POS_TXF (1) -#define IWL49_SCD_QUEUE_STTS_REG_POS_WSL (5) -#define IWL49_SCD_QUEUE_STTS_REG_POS_SCD_ACK (8) - -/* Write masks */ -#define IWL49_SCD_QUEUE_STTS_REG_POS_SCD_ACT_EN (10) -#define IWL49_SCD_QUEUE_STTS_REG_MSK (0x0007FC00) - -/** - * 4965 internal SRAM structures for scheduler, shared with driver ... - * - * Driver should clear and initialize the following areas after receiving - * "Alive" response from 4965 uCode, i.e. after initial - * uCode load, or after a uCode load done for error recovery: - * - * SCD_CONTEXT_DATA_OFFSET (size 128 bytes) - * SCD_TX_STTS_BITMAP_OFFSET (size 256 bytes) - * SCD_TRANSLATE_TBL_OFFSET (size 32 bytes) - * - * Driver accesses SRAM via HBUS_TARG_MEM_* registers. - * Driver reads base address of this scheduler area from SCD_SRAM_BASE_ADDR. - * All OFFSET values must be added to this base address. - */ - -/* - * Queue context. One 8-byte entry for each of 16 queues. - * - * Driver should clear this entire area (size 0x80) to 0 after receiving - * "Alive" notification from uCode. Additionally, driver should init - * each queue's entry as follows: - * - * LS Dword bit fields: - * 0-06: Max Tx window size for Scheduler-ACK. Driver should init to 64. - * - * MS Dword bit fields: - * 16-22: Frame limit. Driver should init to 10 (0xa). - * - * Driver should init all other bits to 0. - * - * Init must be done after driver receives "Alive" response from 4965 uCode, - * and when setting up queue for aggregation. - */ -#define IWL49_SCD_CONTEXT_DATA_OFFSET 0x380 -#define IWL49_SCD_CONTEXT_QUEUE_OFFSET(x) \ - (IWL49_SCD_CONTEXT_DATA_OFFSET + ((x) * 8)) - -#define IWL49_SCD_QUEUE_CTX_REG1_WIN_SIZE_POS (0) -#define IWL49_SCD_QUEUE_CTX_REG1_WIN_SIZE_MSK (0x0000007F) -#define IWL49_SCD_QUEUE_CTX_REG2_FRAME_LIMIT_POS (16) -#define IWL49_SCD_QUEUE_CTX_REG2_FRAME_LIMIT_MSK (0x007F0000) - -/* - * Tx Status Bitmap - * - * Driver should clear this entire area (size 0x100) to 0 after receiving - * "Alive" notification from uCode. Area is used only by device itself; - * no other support (besides clearing) is required from driver. - */ -#define IWL49_SCD_TX_STTS_BITMAP_OFFSET 0x400 - -/* - * RAxTID to queue translation mapping. - * - * When queue is in Scheduler-ACK mode, frames placed in a that queue must be - * for only one combination of receiver address (RA) and traffic ID (TID), i.e. - * one QOS priority level destined for one station (for this wireless link, - * not final destination). The SCD_TRANSLATE_TABLE area provides 16 16-bit - * mappings, one for each of the 16 queues. If queue is not in Scheduler-ACK - * mode, the device ignores the mapping value. - * - * Bit fields, for each 16-bit map: - * 15-9: Reserved, set to 0 - * 8-4: Index into device's station table for recipient station - * 3-0: Traffic ID (tid), range 0-15 - * - * Driver should clear this entire area (size 32 bytes) to 0 after receiving - * "Alive" notification from uCode. To update a 16-bit map value, driver - * must read a dword-aligned value from device SRAM, replace the 16-bit map - * value of interest, and write the dword value back into device SRAM. - */ -#define IWL49_SCD_TRANSLATE_TBL_OFFSET 0x500 - -/* Find translation table dword to read/write for given queue */ -#define IWL49_SCD_TRANSLATE_TBL_OFFSET_QUEUE(x) \ - ((IWL49_SCD_TRANSLATE_TBL_OFFSET + ((x) * 2)) & 0xfffffffc) - #define IWL_SCD_TXFIFO_POS_TID (0) #define IWL_SCD_TXFIFO_POS_RA (4) #define IWL_SCD_QUEUE_RA_TID_MAP_RATID_MSK (0x01FF) -- cgit v0.10.2 From 08960dea6c736280a03cb947f445fdb94fdaa2ee Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 5 Apr 2011 09:41:53 -0700 Subject: iwlagn: remove pointless return variables A number of places just use a variable to return it right away, which is useless, so let's remove the variables there. Signed-off-by: Johannes Berg Signed-off-by: Wey-Yi Guy Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c index e394e49..97abc10 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c @@ -2771,16 +2771,13 @@ static void rs_get_rate(void *priv_r, struct ieee80211_sta *sta, void *priv_sta, static void *rs_alloc_sta(void *priv_rate, struct ieee80211_sta *sta, gfp_t gfp) { - struct iwl_lq_sta *lq_sta; struct iwl_station_priv *sta_priv = (struct iwl_station_priv *) sta->drv_priv; struct iwl_priv *priv; priv = (struct iwl_priv *)priv_rate; IWL_DEBUG_RATE(priv, "create station rate scale window\n"); - lq_sta = &sta_priv->lq_sta; - - return lq_sta; + return &sta_priv->lq_sta; } /* @@ -3259,7 +3256,6 @@ static ssize_t rs_sta_dbgfs_rate_scale_data_read(struct file *file, { char buff[120]; int desc = 0; - ssize_t ret; struct iwl_lq_sta *lq_sta = file->private_data; struct iwl_priv *priv; @@ -3276,8 +3272,7 @@ static ssize_t rs_sta_dbgfs_rate_scale_data_read(struct file *file, "Bit Rate= %d Mb/s\n", iwl_rates[lq_sta->last_txrate_idx].ieee >> 1); - ret = simple_read_from_buffer(user_buf, count, ppos, buff, desc); - return ret; + return simple_read_from_buffer(user_buf, count, ppos, buff, desc); } static const struct file_operations rs_sta_dbgfs_rate_scale_data_ops = { diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-ucode.c b/drivers/net/wireless/iwlwifi/iwl-agn-ucode.c index 5d35e35..bb262a6 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-ucode.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-ucode.c @@ -653,7 +653,5 @@ int iwl_verify_ucode(struct iwl_priv *priv) * Selection of bootstrap image (vs. other images) is arbitrary. */ image = (__le32 *)priv->ucode_boot.v_addr; len = priv->ucode_boot.len; - ret = iwl_verify_inst_full(priv, image, len); - - return ret; + return iwl_verify_inst_full(priv, image, len); } diff --git a/drivers/net/wireless/iwlwifi/iwl-debugfs.c b/drivers/net/wireless/iwlwifi/iwl-debugfs.c index 8842411..90f2b64 100644 --- a/drivers/net/wireless/iwlwifi/iwl-debugfs.c +++ b/drivers/net/wireless/iwlwifi/iwl-debugfs.c @@ -1572,12 +1572,10 @@ static ssize_t iwl_dbgfs_bt_traffic_read(struct file *file, int pos = 0; char buf[200]; const size_t bufsz = sizeof(buf); - ssize_t ret; if (!priv->bt_enable_flag) { pos += scnprintf(buf + pos, bufsz - pos, "BT coex disabled\n"); - ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos); - return ret; + return simple_read_from_buffer(user_buf, count, ppos, buf, pos); } pos += scnprintf(buf + pos, bufsz - pos, "BT enable flag: 0x%x\n", priv->bt_enable_flag); @@ -1608,8 +1606,7 @@ static ssize_t iwl_dbgfs_bt_traffic_read(struct file *file, break; } - ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos); - return ret; + return simple_read_from_buffer(user_buf, count, ppos, buf, pos); } static ssize_t iwl_dbgfs_protection_mode_read(struct file *file, -- cgit v0.10.2 From 36127db02ec17828c1582bb6bc1f12160fd35d64 Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Tue, 5 Apr 2011 09:41:54 -0700 Subject: iwlagn: return send calibration result In alive notification call, return the status from iwl_send_calib_results() Signed-off-by: Wey-Yi Guy Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-ucode.c b/drivers/net/wireless/iwlwifi/iwl-agn-ucode.c index bb262a6..127c842 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-ucode.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-ucode.c @@ -530,9 +530,7 @@ int iwlagn_alive_notify(struct iwl_priv *priv) iwlagn_send_wimax_coex(priv); iwlagn_set_Xtal_calib(priv); - iwl_send_calib_results(priv); - - return 0; + return iwl_send_calib_results(priv); } -- cgit v0.10.2 From fb66216f9ebb146ad457829fcb62ae8f4348cda2 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 5 Apr 2011 09:41:55 -0700 Subject: iwlagn: simplify ucode check code The code in iwlcore_verify_inst_sparse really doesn't need to keep track of the number of errors it encountered since a single one is fatal. Also, the code in iwl_verify_inst_full is just used to print out some things, so rename it to iwl_print_inst and don't give it a return code and just make it print out the values. Signed-off-by: Johannes Berg Signed-off-by: Wey-Yi Guy Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-ucode.c b/drivers/net/wireless/iwlwifi/iwl-agn-ucode.c index 127c842..2205b60 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-ucode.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-ucode.c @@ -542,8 +542,6 @@ int iwlagn_alive_notify(struct iwl_priv *priv) static int iwlcore_verify_inst_sparse(struct iwl_priv *priv, __le32 *image, u32 len) { u32 val; - int ret = 0; - u32 errcnt = 0; u32 i; IWL_DEBUG_INFO(priv, "ucode inst image size is %u\n", len); @@ -555,56 +553,39 @@ static int iwlcore_verify_inst_sparse(struct iwl_priv *priv, __le32 *image, u32 iwl_write_direct32(priv, HBUS_TARG_MEM_RADDR, i + IWLAGN_RTC_INST_LOWER_BOUND); val = _iwl_read_direct32(priv, HBUS_TARG_MEM_RDAT); - if (val != le32_to_cpu(*image)) { - ret = -EIO; - errcnt++; - if (errcnt >= 3) - break; - } + if (val != le32_to_cpu(*image)) + return -EIO; } - return ret; + return 0; } -/** - * iwlcore_verify_inst_full - verify runtime uCode image in card vs. host, - * looking at all data. - */ -static int iwl_verify_inst_full(struct iwl_priv *priv, __le32 *image, - u32 len) +static void iwl_print_mismatch_inst(struct iwl_priv *priv, + __le32 *image, u32 len) { u32 val; - u32 save_len = len; - int ret = 0; - u32 errcnt; + u32 offs; + int errors = 0; IWL_DEBUG_INFO(priv, "ucode inst image size is %u\n", len); iwl_write_direct32(priv, HBUS_TARG_MEM_RADDR, IWLAGN_RTC_INST_LOWER_BOUND); - errcnt = 0; - for (; len > 0; len -= sizeof(u32), image++) { + for (offs = 0; + offs < len && errors < 20; + offs += sizeof(u32), image++) { /* read data comes through single port, auto-incr addr */ /* NOTE: Use the debugless read so we don't flood kernel log * if IWL_DL_IO is set */ val = _iwl_read_direct32(priv, HBUS_TARG_MEM_RDAT); if (val != le32_to_cpu(*image)) { - IWL_ERR(priv, "uCode INST section is invalid at " - "offset 0x%x, is 0x%x, s/b 0x%x\n", - save_len - len, val, le32_to_cpu(*image)); - ret = -EIO; - errcnt++; - if (errcnt >= 20) - break; + IWL_ERR(priv, "uCode INST section at " + "offset 0x%x, is 0x%x, s/b 0x%x\n", + offs, val, le32_to_cpu(*image)); + errors++; } } - - if (!errcnt) - IWL_DEBUG_INFO(priv, - "ucode image in INSTRUCTION memory is good\n"); - - return ret; } /** @@ -651,5 +632,7 @@ int iwl_verify_ucode(struct iwl_priv *priv) * Selection of bootstrap image (vs. other images) is arbitrary. */ image = (__le32 *)priv->ucode_boot.v_addr; len = priv->ucode_boot.len; - return iwl_verify_inst_full(priv, image, len); + iwl_print_mismatch_inst(priv, image, len); + + return -EIO; } -- cgit v0.10.2 From 35b1d92dfb361d24664381a0e4ae8ed47c771a66 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 5 Apr 2011 09:41:56 -0700 Subject: iwlagn: verify specific ucode When we loaded a ucode, there's no point in checking any one that is present, we know which one is supposed to be present so also verify that it is exactly the right one. That also simplifies the code and makes it faster since it doesn't have to check all. Signed-off-by: Johannes Berg Signed-off-by: Wey-Yi Guy Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-ucode.c b/drivers/net/wireless/iwlwifi/iwl-agn-ucode.c index 2205b60..c7b9b83 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-ucode.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-ucode.c @@ -311,7 +311,7 @@ void iwlagn_init_alive_start(struct iwl_priv *priv) /* initialize uCode was loaded... verify inst image. * This is a paranoid check, because we would not have gotten the * "initialize" alive if code weren't properly loaded. */ - if (iwl_verify_ucode(priv)) { + if (iwl_verify_ucode(priv, &priv->ucode_init)) { /* Runtime instruction load was bad; * take it all the way back down so we can try again */ IWL_DEBUG_INFO(priv, "Bad \"initialize\" uCode load.\n"); @@ -539,8 +539,11 @@ int iwlagn_alive_notify(struct iwl_priv *priv) * using sample data 100 bytes apart. If these sample points are good, * it's a pretty good bet that everything between them is good, too. */ -static int iwlcore_verify_inst_sparse(struct iwl_priv *priv, __le32 *image, u32 len) +static int iwlcore_verify_inst_sparse(struct iwl_priv *priv, + struct fw_desc *fw_desc) { + __le32 *image = (__le32 *)fw_desc->v_addr; + u32 len = fw_desc->len; u32 val; u32 i; @@ -561,8 +564,10 @@ static int iwlcore_verify_inst_sparse(struct iwl_priv *priv, __le32 *image, u32 } static void iwl_print_mismatch_inst(struct iwl_priv *priv, - __le32 *image, u32 len) + struct fw_desc *fw_desc) { + __le32 *image = (__le32 *)fw_desc->v_addr; + u32 len = fw_desc->len; u32 val; u32 offs; int errors = 0; @@ -592,47 +597,15 @@ static void iwl_print_mismatch_inst(struct iwl_priv *priv, * iwl_verify_ucode - determine which instruction image is in SRAM, * and verify its contents */ -int iwl_verify_ucode(struct iwl_priv *priv) +int iwl_verify_ucode(struct iwl_priv *priv, struct fw_desc *fw_desc) { - __le32 *image; - u32 len; - int ret; - - /* Try bootstrap */ - image = (__le32 *)priv->ucode_boot.v_addr; - len = priv->ucode_boot.len; - ret = iwlcore_verify_inst_sparse(priv, image, len); - if (!ret) { + if (!iwlcore_verify_inst_sparse(priv, fw_desc)) { IWL_DEBUG_INFO(priv, "Bootstrap uCode is good in inst SRAM\n"); return 0; } - /* Try initialize */ - image = (__le32 *)priv->ucode_init.v_addr; - len = priv->ucode_init.len; - ret = iwlcore_verify_inst_sparse(priv, image, len); - if (!ret) { - IWL_DEBUG_INFO(priv, "Initialize uCode is good in inst SRAM\n"); - return 0; - } - - /* Try runtime/protocol */ - image = (__le32 *)priv->ucode_code.v_addr; - len = priv->ucode_code.len; - ret = iwlcore_verify_inst_sparse(priv, image, len); - if (!ret) { - IWL_DEBUG_INFO(priv, "Runtime uCode is good in inst SRAM\n"); - return 0; - } - - IWL_ERR(priv, "NO VALID UCODE IMAGE IN INSTRUCTION SRAM!!\n"); - - /* Since nothing seems to match, show first several data entries in - * instruction SRAM, so maybe visual inspection will give a clue. - * Selection of bootstrap image (vs. other images) is arbitrary. */ - image = (__le32 *)priv->ucode_boot.v_addr; - len = priv->ucode_boot.len; - iwl_print_mismatch_inst(priv, image, len); + IWL_ERR(priv, "UCODE IMAGE IN INSTRUCTION SRAM NOT VALID!!\n"); + iwl_print_mismatch_inst(priv, fw_desc); return -EIO; } diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index c8cd333..c66fcea 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -2241,7 +2241,7 @@ static void iwl_alive_start(struct iwl_priv *priv) /* Initialize uCode has loaded Runtime uCode ... verify inst image. * This is a paranoid check, because we would not have gotten the * "runtime" alive if code weren't properly loaded. */ - if (iwl_verify_ucode(priv)) { + if (iwl_verify_ucode(priv, &priv->ucode_code)) { /* Runtime instruction load was bad; * take it all the way back down so we can try again */ IWL_DEBUG_INFO(priv, "Bad runtime uCode load.\n"); diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.h b/drivers/net/wireless/iwlwifi/iwl-agn.h index 4a0a46e..d2953bc 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.h +++ b/drivers/net/wireless/iwlwifi/iwl-agn.h @@ -152,7 +152,7 @@ void iwlagn_rx_calib_complete(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb); void iwlagn_init_alive_start(struct iwl_priv *priv); int iwlagn_alive_notify(struct iwl_priv *priv); -int iwl_verify_ucode(struct iwl_priv *priv); +int iwl_verify_ucode(struct iwl_priv *priv, struct fw_desc *fw_desc); void iwlagn_send_bt_env(struct iwl_priv *priv, u8 action, u8 type); void iwlagn_send_prio_tbl(struct iwl_priv *priv); -- cgit v0.10.2 From 1fc352765fb461e4afafff4d650624df8ab6b6d6 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 5 Apr 2011 09:41:57 -0700 Subject: iwlagn: remove bootstrap code Only 4965 had a bootstrap microcode image, so the agn driver can completely ignore that and we can remove some code from it. Signed-off-by: Johannes Berg Signed-off-by: Wey-Yi Guy Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwlwifi/iwl-1000.c b/drivers/net/wireless/iwlwifi/iwl-1000.c index ad50063..53a6702 100644 --- a/drivers/net/wireless/iwlwifi/iwl-1000.c +++ b/drivers/net/wireless/iwlwifi/iwl-1000.c @@ -141,7 +141,6 @@ static int iwl1000_hw_set_hw_params(struct iwl_priv *priv) priv->hw_params.max_data_size = IWLAGN_RTC_DATA_SIZE; priv->hw_params.max_inst_size = IWLAGN_RTC_INST_SIZE; - priv->hw_params.max_bsm_size = 0; priv->hw_params.ht40_channel = BIT(IEEE80211_BAND_2GHZ) | BIT(IEEE80211_BAND_5GHZ); priv->hw_params.rx_wrt_ptr_reg = FH_RSCSR_CHNL0_WPTR; diff --git a/drivers/net/wireless/iwlwifi/iwl-2000.c b/drivers/net/wireless/iwlwifi/iwl-2000.c index 5e375d8..9f97389 100644 --- a/drivers/net/wireless/iwlwifi/iwl-2000.c +++ b/drivers/net/wireless/iwlwifi/iwl-2000.c @@ -147,7 +147,6 @@ static int iwl2000_hw_set_hw_params(struct iwl_priv *priv) priv->hw_params.max_data_size = IWL60_RTC_DATA_SIZE; priv->hw_params.max_inst_size = IWL60_RTC_INST_SIZE; - priv->hw_params.max_bsm_size = 0; priv->hw_params.ht40_channel = BIT(IEEE80211_BAND_2GHZ) | BIT(IEEE80211_BAND_5GHZ); priv->hw_params.rx_wrt_ptr_reg = FH_RSCSR_CHNL0_WPTR; diff --git a/drivers/net/wireless/iwlwifi/iwl-5000.c b/drivers/net/wireless/iwlwifi/iwl-5000.c index 0e1f0b5..653bb8e 100644 --- a/drivers/net/wireless/iwlwifi/iwl-5000.c +++ b/drivers/net/wireless/iwlwifi/iwl-5000.c @@ -185,7 +185,6 @@ static int iwl5000_hw_set_hw_params(struct iwl_priv *priv) priv->hw_params.max_data_size = IWLAGN_RTC_DATA_SIZE; priv->hw_params.max_inst_size = IWLAGN_RTC_INST_SIZE; - priv->hw_params.max_bsm_size = 0; priv->hw_params.ht40_channel = BIT(IEEE80211_BAND_2GHZ) | BIT(IEEE80211_BAND_5GHZ); priv->hw_params.rx_wrt_ptr_reg = FH_RSCSR_CHNL0_WPTR; @@ -231,7 +230,6 @@ static int iwl5150_hw_set_hw_params(struct iwl_priv *priv) priv->hw_params.max_data_size = IWLAGN_RTC_DATA_SIZE; priv->hw_params.max_inst_size = IWLAGN_RTC_INST_SIZE; - priv->hw_params.max_bsm_size = 0; priv->hw_params.ht40_channel = BIT(IEEE80211_BAND_2GHZ) | BIT(IEEE80211_BAND_5GHZ); priv->hw_params.rx_wrt_ptr_reg = FH_RSCSR_CHNL0_WPTR; diff --git a/drivers/net/wireless/iwlwifi/iwl-6000.c b/drivers/net/wireless/iwlwifi/iwl-6000.c index 4d545e6..1e55f81 100644 --- a/drivers/net/wireless/iwlwifi/iwl-6000.c +++ b/drivers/net/wireless/iwlwifi/iwl-6000.c @@ -176,7 +176,6 @@ static int iwl6000_hw_set_hw_params(struct iwl_priv *priv) priv->hw_params.max_data_size = IWL60_RTC_DATA_SIZE; priv->hw_params.max_inst_size = IWL60_RTC_INST_SIZE; - priv->hw_params.max_bsm_size = 0; priv->hw_params.ht40_channel = BIT(IEEE80211_BAND_2GHZ) | BIT(IEEE80211_BAND_5GHZ); priv->hw_params.rx_wrt_ptr_reg = FH_RSCSR_CHNL0_WPTR; diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index c66fcea..5e74eb0 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -1181,7 +1181,6 @@ static void iwl_dealloc_ucode_pci(struct iwl_priv *priv) iwl_free_fw_desc(priv->pci_dev, &priv->ucode_data_backup); iwl_free_fw_desc(priv->pci_dev, &priv->ucode_init); iwl_free_fw_desc(priv->pci_dev, &priv->ucode_init_data); - iwl_free_fw_desc(priv->pci_dev, &priv->ucode_boot); } static void iwl_nic_start(struct iwl_priv *priv) @@ -1239,8 +1238,8 @@ static int __must_check iwl_request_firmware(struct iwl_priv *priv, bool first) } struct iwlagn_firmware_pieces { - const void *inst, *data, *init, *init_data, *boot; - size_t inst_size, data_size, init_size, init_data_size, boot_size; + const void *inst, *data, *init, *init_data; + size_t inst_size, data_size, init_size, init_data_size; u32 build; @@ -1271,7 +1270,6 @@ static int iwlagn_load_legacy_firmware(struct iwl_priv *priv, pieces->data_size = le32_to_cpu(ucode->u.v2.data_size); pieces->init_size = le32_to_cpu(ucode->u.v2.init_size); pieces->init_data_size = le32_to_cpu(ucode->u.v2.init_data_size); - pieces->boot_size = le32_to_cpu(ucode->u.v2.boot_size); src = ucode->u.v2.data; break; case 0: @@ -1287,7 +1285,6 @@ static int iwlagn_load_legacy_firmware(struct iwl_priv *priv, pieces->data_size = le32_to_cpu(ucode->u.v1.data_size); pieces->init_size = le32_to_cpu(ucode->u.v1.init_size); pieces->init_data_size = le32_to_cpu(ucode->u.v1.init_data_size); - pieces->boot_size = le32_to_cpu(ucode->u.v1.boot_size); src = ucode->u.v1.data; break; } @@ -1295,7 +1292,7 @@ static int iwlagn_load_legacy_firmware(struct iwl_priv *priv, /* Verify size of file vs. image size info in file's header */ if (ucode_raw->size != hdr_size + pieces->inst_size + pieces->data_size + pieces->init_size + - pieces->init_data_size + pieces->boot_size) { + pieces->init_data_size) { IWL_ERR(priv, "uCode file size %d does not match expected size\n", @@ -1311,8 +1308,6 @@ static int iwlagn_load_legacy_firmware(struct iwl_priv *priv, src += pieces->init_size; pieces->init_data = src; src += pieces->init_data_size; - pieces->boot = src; - src += pieces->boot_size; return 0; } @@ -1413,8 +1408,7 @@ static int iwlagn_load_firmware(struct iwl_priv *priv, pieces->init_data_size = tlv_len; break; case IWL_UCODE_TLV_BOOT: - pieces->boot = tlv_data; - pieces->boot_size = tlv_len; + IWL_ERR(priv, "Found unexpected BOOT ucode\n"); break; case IWL_UCODE_TLV_PROBE_MAX_LEN: if (tlv_len != sizeof(u32)) @@ -1614,8 +1608,6 @@ static void iwl_ucode_callback(const struct firmware *ucode_raw, void *context) pieces.init_size); IWL_DEBUG_INFO(priv, "f/w package hdr init data size = %Zd\n", pieces.init_data_size); - IWL_DEBUG_INFO(priv, "f/w package hdr boot inst size = %Zd\n", - pieces.boot_size); /* Verify that uCode images will fit in card's SRAM */ if (pieces.inst_size > priv->hw_params.max_inst_size) { @@ -1642,12 +1634,6 @@ static void iwl_ucode_callback(const struct firmware *ucode_raw, void *context) goto try_again; } - if (pieces.boot_size > priv->hw_params.max_bsm_size) { - IWL_ERR(priv, "uCode boot instr len %Zd too large to fit in\n", - pieces.boot_size); - goto try_again; - } - /* Allocate ucode buffers for card's bus-master loading ... */ /* Runtime instructions and 2 copies of data: @@ -1678,15 +1664,6 @@ static void iwl_ucode_callback(const struct firmware *ucode_raw, void *context) goto err_pci_alloc; } - /* Bootstrap (instructions only, no data) */ - if (pieces.boot_size) { - priv->ucode_boot.len = pieces.boot_size; - iwl_alloc_fw_desc(priv->pci_dev, &priv->ucode_boot); - - if (!priv->ucode_boot.v_addr) - goto err_pci_alloc; - } - /* Now that we can no longer fail, copy information */ /* @@ -1749,11 +1726,6 @@ static void iwl_ucode_callback(const struct firmware *ucode_raw, void *context) pieces.init_data_size); } - /* Bootstrap instructions */ - IWL_DEBUG_INFO(priv, "Copying (but not loading) boot instr len %Zd\n", - pieces.boot_size); - memcpy(priv->ucode_boot.v_addr, pieces.boot, pieces.boot_size); - /* * figure out the offset of chain noise reset and gain commands * base on the size of standard phy calibration commands table size diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index 8dc209a..b3af2e8 100644 --- a/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h @@ -641,7 +641,6 @@ struct iwl_hw_params { u8 max_beacon_itrvl; /* in 1024 ms */ u32 max_inst_size; u32 max_data_size; - u32 max_bsm_size; u32 ct_kill_threshold; /* value in hw-dependent units */ u32 ct_kill_exit_threshold; /* value in hw-dependent units */ /* for 1000, 6000 series and up */ @@ -1263,7 +1262,6 @@ struct iwl_priv { struct fw_desc ucode_data_backup; /* runtime data save/restore */ struct fw_desc ucode_init; /* initialization inst */ struct fw_desc ucode_init_data; /* initialization data */ - struct fw_desc ucode_boot; /* bootstrap inst */ enum ucode_type ucode_type; u8 ucode_write_complete; /* the image write is complete */ char firmware_name[25]; -- cgit v0.10.2 From e649437fd6e2bae6f7b8a36a302a1ec4faa5d906 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 5 Apr 2011 09:41:58 -0700 Subject: iwlagn: centralize and fix ucode restart The ucode restart has to take into account a number of things, like clearing the HCMD_ACTIVE and other status bits, and waking up the wait_command_queue. Currently, however, there are a number of places that neither do that, nor actually set the FW error bit that leads to proper restart handling, which means that in those cases things will probably just hang completely. To clean this up, make all ucode restart go through a single function, except for the cases where it's called during firmware loading. Also fix a bug in wimax coexist restart avoidance, it needs to first clear the status bits (and it has to clear the HCMD_ACTIVE one as well) and then wake up anything waiting on wait_command_queue. Signed-off-by: Johannes Berg Signed-off-by: Wey-Yi Guy Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index d778f52..64b28b0 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -890,10 +890,8 @@ void iwl_print_rx_config_cmd(struct iwl_priv *priv, IWL_DEBUG_RADIO(priv, "u16 assoc_id: 0x%x\n", le16_to_cpu(rxon->assoc_id)); } #endif -/** - * iwl_irq_handle_error - called for HW or SW error interrupt from card - */ -void iwl_irq_handle_error(struct iwl_priv *priv) + +void iwlagn_fw_error(struct iwl_priv *priv, bool ondemand) { unsigned int reload_msec; unsigned long reload_jiffies; @@ -904,18 +902,62 @@ void iwl_irq_handle_error(struct iwl_priv *priv) /* Cancel currently queued command. */ clear_bit(STATUS_HCMD_ACTIVE, &priv->status); + /* Keep the restart process from trying to send host + * commands by clearing the ready bit */ + clear_bit(STATUS_READY, &priv->status); + + wake_up_interruptible(&priv->wait_command_queue); + + if (!ondemand) { + /* + * If firmware keep reloading, then it indicate something + * serious wrong and firmware having problem to recover + * from it. Instead of keep trying which will fill the syslog + * and hang the system, let's just stop it + */ + reload_jiffies = jiffies; + reload_msec = jiffies_to_msecs((long) reload_jiffies - + (long) priv->reload_jiffies); + priv->reload_jiffies = reload_jiffies; + if (reload_msec <= IWL_MIN_RELOAD_DURATION) { + priv->reload_count++; + if (priv->reload_count >= IWL_MAX_CONTINUE_RELOAD_CNT) { + IWL_ERR(priv, "BUG_ON, Stop restarting\n"); + return; + } + } else + priv->reload_count = 0; + } + + if (!test_bit(STATUS_EXIT_PENDING, &priv->status)) { + if (priv->cfg->mod_params->restart_fw) { + IWL_DEBUG(priv, IWL_DL_FW_ERRORS, + "Restarting adapter due to uCode error.\n"); + queue_work(priv->workqueue, &priv->restart); + } else + IWL_DEBUG(priv, IWL_DL_FW_ERRORS, + "Detected FW error, but not restarting\n"); + } +} + +/** + * iwl_irq_handle_error - called for HW or SW error interrupt from card + */ +void iwl_irq_handle_error(struct iwl_priv *priv) +{ /* W/A for WiFi/WiMAX coex and WiMAX own the RF */ if (priv->cfg->internal_wimax_coex && (!(iwl_read_prph(priv, APMG_CLK_CTRL_REG) & APMS_CLK_VAL_MRB_FUNC_MODE) || (iwl_read_prph(priv, APMG_PS_CTRL_REG) & APMG_PS_CTRL_VAL_RESET_REQ))) { - wake_up_interruptible(&priv->wait_command_queue); /* - *Keep the restart process from trying to send host - * commands by clearing the INIT status bit + * Keep the restart process from trying to send host + * commands by clearing the ready bit. */ clear_bit(STATUS_READY, &priv->status); + clear_bit(STATUS_HCMD_ACTIVE, &priv->status); + wake_up_interruptible(&priv->wait_command_queue); IWL_ERR(priv, "RF is used by WiMAX\n"); return; } @@ -935,38 +977,7 @@ void iwl_irq_handle_error(struct iwl_priv *priv) &priv->contexts[IWL_RXON_CTX_BSS]); #endif - wake_up_interruptible(&priv->wait_command_queue); - - /* Keep the restart process from trying to send host - * commands by clearing the INIT status bit */ - clear_bit(STATUS_READY, &priv->status); - - /* - * If firmware keep reloading, then it indicate something - * serious wrong and firmware having problem to recover - * from it. Instead of keep trying which will fill the syslog - * and hang the system, let's just stop it - */ - reload_jiffies = jiffies; - reload_msec = jiffies_to_msecs((long) reload_jiffies - - (long) priv->reload_jiffies); - priv->reload_jiffies = reload_jiffies; - if (reload_msec <= IWL_MIN_RELOAD_DURATION) { - priv->reload_count++; - if (priv->reload_count >= IWL_MAX_CONTINUE_RELOAD_CNT) { - IWL_ERR(priv, "BUG_ON, Stop restarting\n"); - return; - } - } else - priv->reload_count = 0; - - if (!test_bit(STATUS_EXIT_PENDING, &priv->status)) { - IWL_DEBUG(priv, IWL_DL_FW_ERRORS, - "Restarting adapter due to uCode error.\n"); - - if (priv->cfg->mod_params->restart_fw) - queue_work(priv->workqueue, &priv->restart); - } + iwlagn_fw_error(priv, false); } static int iwl_apm_stop_master(struct iwl_priv *priv) @@ -1755,15 +1766,7 @@ int iwl_force_reset(struct iwl_priv *priv, int mode, bool external) break; } IWL_ERR(priv, "On demand firmware reload\n"); - /* Set the FW error flag -- cleared on iwl_down */ - set_bit(STATUS_FW_ERROR, &priv->status); - wake_up_interruptible(&priv->wait_command_queue); - /* - * Keep the restart process from trying to send host - * commands by clearing the INIT status bit - */ - clear_bit(STATUS_READY, &priv->status); - queue_work(priv->workqueue, &priv->restart); + iwlagn_fw_error(priv, true); break; } return 0; diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h index 46c90b3..8bc2346 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.h +++ b/drivers/net/wireless/iwlwifi/iwl-core.h @@ -729,4 +729,7 @@ static inline bool iwl_bt_statistics(struct iwl_priv *priv) extern bool bt_coex_active; extern bool bt_siso_mode; + +void iwlagn_fw_error(struct iwl_priv *priv, bool ondemand); + #endif /* __iwl_core_h__ */ diff --git a/drivers/net/wireless/iwlwifi/iwl-tx.c b/drivers/net/wireless/iwlwifi/iwl-tx.c index 39a4180..fa81df2 100644 --- a/drivers/net/wireless/iwlwifi/iwl-tx.c +++ b/drivers/net/wireless/iwlwifi/iwl-tx.c @@ -474,7 +474,7 @@ int iwl_enqueue_hcmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd) } if (!is_ct_kill) { IWL_ERR(priv, "Restarting adapter due to queue full\n"); - queue_work(priv->workqueue, &priv->restart); + iwlagn_fw_error(priv, false); } return -ENOSPC; } @@ -582,7 +582,7 @@ static void iwl_hcmd_queue_reclaim(struct iwl_priv *priv, int txq_id, if (nfreed++ > 0) { IWL_ERR(priv, "HCMD skipped: index (%d) %d %d\n", idx, q->write_ptr, q->read_ptr); - queue_work(priv->workqueue, &priv->restart); + iwlagn_fw_error(priv, false); } } -- cgit v0.10.2 From 6009c39c6fc1cb988bdc90a395d9cce273afc7d5 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 5 Apr 2011 09:41:59 -0700 Subject: iwlagn: remove ucode_data_backup This was used only on 4965 in conjunction with the bootstrap ucode. Signed-off-by: Johannes Berg Signed-off-by: Wey-Yi Guy Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index 5e74eb0..e3095af 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -1178,7 +1178,6 @@ static void iwl_dealloc_ucode_pci(struct iwl_priv *priv) { iwl_free_fw_desc(priv->pci_dev, &priv->ucode_code); iwl_free_fw_desc(priv->pci_dev, &priv->ucode_data); - iwl_free_fw_desc(priv->pci_dev, &priv->ucode_data_backup); iwl_free_fw_desc(priv->pci_dev, &priv->ucode_init); iwl_free_fw_desc(priv->pci_dev, &priv->ucode_init_data); } @@ -1645,11 +1644,7 @@ static void iwl_ucode_callback(const struct firmware *ucode_raw, void *context) priv->ucode_data.len = pieces.data_size; iwl_alloc_fw_desc(priv->pci_dev, &priv->ucode_data); - priv->ucode_data_backup.len = pieces.data_size; - iwl_alloc_fw_desc(priv->pci_dev, &priv->ucode_data_backup); - - if (!priv->ucode_code.v_addr || !priv->ucode_data.v_addr || - !priv->ucode_data_backup.v_addr) + if (!priv->ucode_code.v_addr || !priv->ucode_data.v_addr) goto err_pci_alloc; /* Initialization instructions and data */ @@ -1709,7 +1704,6 @@ static void iwl_ucode_callback(const struct firmware *ucode_raw, void *context) IWL_DEBUG_INFO(priv, "Copying (but not loading) uCode data len %Zd\n", pieces.data_size); memcpy(priv->ucode_data.v_addr, pieces.data, pieces.data_size); - memcpy(priv->ucode_data_backup.v_addr, pieces.data, pieces.data_size); /* Initialization instructions */ if (pieces.init_size) { @@ -2481,11 +2475,6 @@ static int __iwl_up(struct iwl_priv *priv) return -EIO; } - if (!priv->ucode_data_backup.v_addr || !priv->ucode_data.v_addr) { - IWL_ERR(priv, "ucode not available for device bringup\n"); - return -EIO; - } - for_each_context(priv, ctx) { ret = iwlagn_alloc_bcast_station(priv, ctx); if (ret) { @@ -2542,12 +2531,6 @@ static int __iwl_up(struct iwl_priv *priv) iwl_write32(priv, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL); iwl_write32(priv, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL); - /* Copy original ucode data image from disk into backup cache. - * This will be used to initialize the on-board processor's - * data SRAM for a clean start when the runtime program first loads. */ - memcpy(priv->ucode_data_backup.v_addr, priv->ucode_data.v_addr, - priv->ucode_data.len); - for (i = 0; i < MAX_HW_RESTARTS; i++) { /* load bootstrap state machine, diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index b3af2e8..7619cee 100644 --- a/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h @@ -1259,7 +1259,6 @@ struct iwl_priv { iwl_ucode.ver */ struct fw_desc ucode_code; /* runtime inst */ struct fw_desc ucode_data; /* runtime data original */ - struct fw_desc ucode_data_backup; /* runtime data save/restore */ struct fw_desc ucode_init; /* initialization inst */ struct fw_desc ucode_init_data; /* initialization data */ enum ucode_type ucode_type; -- cgit v0.10.2 From 901069c71415a76d731857ccda814e18ded062f7 Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Tue, 5 Apr 2011 09:42:00 -0700 Subject: iwlagn: change Copyright to 2011 Signed-off-by: Wey-Yi Guy Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwlwifi/iwl-1000.c b/drivers/net/wireless/iwlwifi/iwl-1000.c index 53a6702..5c3bb47 100644 --- a/drivers/net/wireless/iwlwifi/iwl-1000.c +++ b/drivers/net/wireless/iwlwifi/iwl-1000.c @@ -1,6 +1,6 @@ /****************************************************************************** * - * Copyright(c) 2008 - 2010 Intel Corporation. All rights reserved. + * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of version 2 of the GNU General Public License as diff --git a/drivers/net/wireless/iwlwifi/iwl-2000.c b/drivers/net/wireless/iwlwifi/iwl-2000.c index 9f97389..f87adbf 100644 --- a/drivers/net/wireless/iwlwifi/iwl-2000.c +++ b/drivers/net/wireless/iwlwifi/iwl-2000.c @@ -1,6 +1,6 @@ /****************************************************************************** * - * Copyright(c) 2008 - 2010 Intel Corporation. All rights reserved. + * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of version 2 of the GNU General Public License as diff --git a/drivers/net/wireless/iwlwifi/iwl-5000-hw.h b/drivers/net/wireless/iwlwifi/iwl-5000-hw.h index 3975e45..05ad476 100644 --- a/drivers/net/wireless/iwlwifi/iwl-5000-hw.h +++ b/drivers/net/wireless/iwlwifi/iwl-5000-hw.h @@ -5,7 +5,7 @@ * * GPL LICENSE SUMMARY * - * Copyright(c) 2007 - 2010 Intel Corporation. All rights reserved. + * Copyright(c) 2007 - 2011 Intel Corporation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -30,7 +30,7 @@ * * BSD LICENSE * - * Copyright(c) 2005 - 2010 Intel Corporation. All rights reserved. + * Copyright(c) 2005 - 2011 Intel Corporation. All rights reserved. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/net/wireless/iwlwifi/iwl-5000.c b/drivers/net/wireless/iwlwifi/iwl-5000.c index 653bb8e..d2f4eb3 100644 --- a/drivers/net/wireless/iwlwifi/iwl-5000.c +++ b/drivers/net/wireless/iwlwifi/iwl-5000.c @@ -1,6 +1,6 @@ /****************************************************************************** * - * Copyright(c) 2007 - 2010 Intel Corporation. All rights reserved. + * Copyright(c) 2007 - 2011 Intel Corporation. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of version 2 of the GNU General Public License as diff --git a/drivers/net/wireless/iwlwifi/iwl-6000-hw.h b/drivers/net/wireless/iwlwifi/iwl-6000-hw.h index 47891e1..b27986e 100644 --- a/drivers/net/wireless/iwlwifi/iwl-6000-hw.h +++ b/drivers/net/wireless/iwlwifi/iwl-6000-hw.h @@ -5,7 +5,7 @@ * * GPL LICENSE SUMMARY * - * Copyright(c) 2007 - 2010 Intel Corporation. All rights reserved. + * Copyright(c) 2007 - 2011 Intel Corporation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -30,7 +30,7 @@ * * BSD LICENSE * - * Copyright(c) 2005 - 2010 Intel Corporation. All rights reserved. + * Copyright(c) 2005 - 2011 Intel Corporation. All rights reserved. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/net/wireless/iwlwifi/iwl-6000.c b/drivers/net/wireless/iwlwifi/iwl-6000.c index 1e55f81..c1f8d1d 100644 --- a/drivers/net/wireless/iwlwifi/iwl-6000.c +++ b/drivers/net/wireless/iwlwifi/iwl-6000.c @@ -1,6 +1,6 @@ /****************************************************************************** * - * Copyright(c) 2008 - 2010 Intel Corporation. All rights reserved. + * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of version 2 of the GNU General Public License as diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-calib.c b/drivers/net/wireless/iwlwifi/iwl-agn-calib.c index 9006293..7b761de 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-calib.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-calib.c @@ -5,7 +5,7 @@ * * GPL LICENSE SUMMARY * - * Copyright(c) 2008 - 2010 Intel Corporation. All rights reserved. + * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -30,7 +30,7 @@ * * BSD LICENSE * - * Copyright(c) 2005 - 2010 Intel Corporation. All rights reserved. + * Copyright(c) 2005 - 2011 Intel Corporation. All rights reserved. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-calib.h b/drivers/net/wireless/iwlwifi/iwl-agn-calib.h index e37ae726..ef4d507 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-calib.h +++ b/drivers/net/wireless/iwlwifi/iwl-agn-calib.h @@ -5,7 +5,7 @@ * * GPL LICENSE SUMMARY * - * Copyright(c) 2008 - 2010 Intel Corporation. All rights reserved. + * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -30,7 +30,7 @@ * * BSD LICENSE * - * Copyright(c) 2005 - 2010 Intel Corporation. All rights reserved. + * Copyright(c) 2005 - 2011 Intel Corporation. All rights reserved. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-debugfs.c b/drivers/net/wireless/iwlwifi/iwl-agn-debugfs.c index b500aaa..d1834aa 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-debugfs.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-debugfs.c @@ -1,30 +1,30 @@ /****************************************************************************** -* -* GPL LICENSE SUMMARY -* -* Copyright(c) 2008 - 2010 Intel Corporation. All rights reserved. -* -* This program is free software; you can redistribute it and/or modify -* it under the terms of version 2 of the GNU General Public License as -* published by the Free Software Foundation. -* -* This program is distributed in the hope that it will be useful, but -* WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -* General Public License for more details. -* -* You should have received a copy of the GNU General Public License -* along with this program; if not, write to the Free Software -* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, -* USA -* -* The full GNU General Public License is included in this distribution -* in the file called LICENSE.GPL. -* -* Contact Information: -* Intel Linux Wireless -* Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 -*****************************************************************************/ + * + * GPL LICENSE SUMMARY + * + * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, + * USA + * + * The full GNU General Public License is included in this distribution + * in the file called LICENSE.GPL. + * + * Contact Information: + * Intel Linux Wireless + * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + *****************************************************************************/ #include "iwl-agn.h" #include "iwl-agn-debugfs.h" diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-debugfs.h b/drivers/net/wireless/iwlwifi/iwl-agn-debugfs.h index f2573b5..9a3f329 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-debugfs.h +++ b/drivers/net/wireless/iwlwifi/iwl-agn-debugfs.h @@ -2,7 +2,7 @@ * * GPL LICENSE SUMMARY * - * Copyright(c) 2008 - 2010 Intel Corporation. All rights reserved. + * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-eeprom.c b/drivers/net/wireless/iwlwifi/iwl-agn-eeprom.c index 27b5a3e..c6dd9b7 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-eeprom.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-eeprom.c @@ -5,7 +5,7 @@ * * GPL LICENSE SUMMARY * - * Copyright(c) 2008 - 2010 Intel Corporation. All rights reserved. + * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -30,7 +30,7 @@ * * BSD LICENSE * - * Copyright(c) 2005 - 2010 Intel Corporation. All rights reserved. + * Copyright(c) 2005 - 2011 Intel Corporation. All rights reserved. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-hcmd.c b/drivers/net/wireless/iwlwifi/iwl-agn-hcmd.c index 41543ad..861cc93 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-hcmd.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-hcmd.c @@ -2,7 +2,7 @@ * * GPL LICENSE SUMMARY * - * Copyright(c) 2008 - 2010 Intel Corporation. All rights reserved. + * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-hw.h b/drivers/net/wireless/iwlwifi/iwl-agn-hw.h index a52b82c..7bd19f4 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-hw.h +++ b/drivers/net/wireless/iwlwifi/iwl-agn-hw.h @@ -5,7 +5,7 @@ * * GPL LICENSE SUMMARY * - * Copyright(c) 2007 - 2010 Intel Corporation. All rights reserved. + * Copyright(c) 2007 - 2011 Intel Corporation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -30,7 +30,7 @@ * * BSD LICENSE * - * Copyright(c) 2005 - 2010 Intel Corporation. All rights reserved. + * Copyright(c) 2005 - 2011 Intel Corporation. All rights reserved. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-ict.c b/drivers/net/wireless/iwlwifi/iwl-agn-ict.c index 47e1fa4..34d77d2 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-ict.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-ict.c @@ -2,7 +2,7 @@ * * GPL LICENSE SUMMARY * - * Copyright(c) 2008 - 2010 Intel Corporation. All rights reserved. + * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-led.c b/drivers/net/wireless/iwlwifi/iwl-agn-led.c index c1190d9..4bb877e 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-led.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-led.c @@ -1,6 +1,6 @@ /****************************************************************************** * - * Copyright(c) 2003 - 2010 Intel Corporation. All rights reserved. + * Copyright(c) 2003 - 2011 Intel Corporation. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of version 2 of the GNU General Public License as diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-led.h b/drivers/net/wireless/iwlwifi/iwl-agn-led.h index 96f323d..c0b7611 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-led.h +++ b/drivers/net/wireless/iwlwifi/iwl-agn-led.h @@ -1,6 +1,6 @@ /****************************************************************************** * - * Copyright(c) 2003 - 2010 Intel Corporation. All rights reserved. + * Copyright(c) 2003 - 2011 Intel Corporation. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of version 2 of the GNU General Public License as diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-lib.c b/drivers/net/wireless/iwlwifi/iwl-agn-lib.c index 3a02bea..9a3d69d 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-lib.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-lib.c @@ -2,7 +2,7 @@ * * GPL LICENSE SUMMARY * - * Copyright(c) 2008 - 2010 Intel Corporation. All rights reserved. + * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c index 97abc10..dbe6295 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c @@ -1,6 +1,6 @@ /****************************************************************************** * - * Copyright(c) 2005 - 2010 Intel Corporation. All rights reserved. + * Copyright(c) 2005 - 2011 Intel Corporation. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of version 2 of the GNU General Public License as diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-rs.h b/drivers/net/wireless/iwlwifi/iwl-agn-rs.h index b356a39..69a2993 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-rs.h +++ b/drivers/net/wireless/iwlwifi/iwl-agn-rs.h @@ -1,6 +1,6 @@ /****************************************************************************** * - * Copyright(c) 2003 - 2010 Intel Corporation. All rights reserved. + * Copyright(c) 2003 - 2011 Intel Corporation. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of version 2 of the GNU General Public License as diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-rxon.c b/drivers/net/wireless/iwlwifi/iwl-agn-rxon.c index dfdbea6..c335ee6 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-rxon.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-rxon.c @@ -1,6 +1,6 @@ /****************************************************************************** * - * Copyright(c) 2003 - 2010 Intel Corporation. All rights reserved. + * Copyright(c) 2003 - 2011 Intel Corporation. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of version 2 of the GNU General Public License as diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-sta.c b/drivers/net/wireless/iwlwifi/iwl-agn-sta.c index 3782fe8..079275f 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-sta.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-sta.c @@ -1,6 +1,6 @@ /****************************************************************************** * - * Copyright(c) 2003 - 2010 Intel Corporation. All rights reserved. + * Copyright(c) 2003 - 2011 Intel Corporation. All rights reserved. * * Portions of this file are derived from the ipw3945 project, as well * as portions of the ieee80211 subsystem header files. diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-tt.c b/drivers/net/wireless/iwlwifi/iwl-agn-tt.c index e3a8216..348f74f 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-tt.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-tt.c @@ -1,6 +1,6 @@ /****************************************************************************** * - * Copyright(c) 2007 - 2010 Intel Corporation. All rights reserved. + * Copyright(c) 2007 - 2011 Intel Corporation. All rights reserved. * * Portions of this file are derived from the ipw3945 project, as well * as portions of the ieee80211 subsystem header files. diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-tt.h b/drivers/net/wireless/iwlwifi/iwl-agn-tt.h index d550604..d118ed2 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-tt.h +++ b/drivers/net/wireless/iwlwifi/iwl-agn-tt.h @@ -1,6 +1,6 @@ /****************************************************************************** * - * Copyright(c) 2007 - 2010 Intel Corporation. All rights reserved. + * Copyright(c) 2007 - 2011 Intel Corporation. All rights reserved. * * Portions of this file are derived from the ipw3945 project, as well * as portions of the ieee80211 subsystem header files. diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-tx.c b/drivers/net/wireless/iwlwifi/iwl-agn-tx.c index cb8eacd..2816b43 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-tx.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-tx.c @@ -2,7 +2,7 @@ * * GPL LICENSE SUMMARY * - * Copyright(c) 2008 - 2010 Intel Corporation. All rights reserved. + * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-ucode.c b/drivers/net/wireless/iwlwifi/iwl-agn-ucode.c index c7b9b83..a7c9131 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-ucode.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-ucode.c @@ -2,7 +2,7 @@ * * GPL LICENSE SUMMARY * - * Copyright(c) 2008 - 2010 Intel Corporation. All rights reserved. + * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index e3095af..2f4fe16 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -1,6 +1,6 @@ /****************************************************************************** * - * Copyright(c) 2003 - 2010 Intel Corporation. All rights reserved. + * Copyright(c) 2003 - 2011 Intel Corporation. All rights reserved. * * Portions of this file are derived from the ipw3945 project, as well * as portions of the ieee80211 subsystem header files. diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.h b/drivers/net/wireless/iwlwifi/iwl-agn.h index d2953bc..016b79e 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.h +++ b/drivers/net/wireless/iwlwifi/iwl-agn.h @@ -5,7 +5,7 @@ * * GPL LICENSE SUMMARY * - * Copyright(c) 2008 - 2010 Intel Corporation. All rights reserved. + * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -30,7 +30,7 @@ * * BSD LICENSE * - * Copyright(c) 2005 - 2010 Intel Corporation. All rights reserved. + * Copyright(c) 2005 - 2011 Intel Corporation. All rights reserved. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/net/wireless/iwlwifi/iwl-commands.h b/drivers/net/wireless/iwlwifi/iwl-commands.h index e6058436..a2348ee 100644 --- a/drivers/net/wireless/iwlwifi/iwl-commands.h +++ b/drivers/net/wireless/iwlwifi/iwl-commands.h @@ -5,7 +5,7 @@ * * GPL LICENSE SUMMARY * - * Copyright(c) 2005 - 2010 Intel Corporation. All rights reserved. + * Copyright(c) 2005 - 2011 Intel Corporation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -30,7 +30,7 @@ * * BSD LICENSE * - * Copyright(c) 2005 - 2010 Intel Corporation. All rights reserved. + * Copyright(c) 2005 - 2011 Intel Corporation. All rights reserved. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index 64b28b0..6e9829f 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -2,7 +2,7 @@ * * GPL LICENSE SUMMARY * - * Copyright(c) 2008 - 2010 Intel Corporation. All rights reserved. + * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h index 8bc2346..696b056 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.h +++ b/drivers/net/wireless/iwlwifi/iwl-core.h @@ -5,7 +5,7 @@ * * GPL LICENSE SUMMARY * - * Copyright(c) 2008 - 2010 Intel Corporation. All rights reserved. + * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -30,7 +30,7 @@ * * BSD LICENSE * - * Copyright(c) 2005 - 2010 Intel Corporation. All rights reserved. + * Copyright(c) 2005 - 2011 Intel Corporation. All rights reserved. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -73,7 +73,7 @@ struct iwl_cmd; #define IWLWIFI_VERSION "in-tree:" -#define DRV_COPYRIGHT "Copyright(c) 2003-2010 Intel Corporation" +#define DRV_COPYRIGHT "Copyright(c) 2003-2011 Intel Corporation" #define DRV_AUTHOR "" #define IWL_PCI_DEVICE(dev, subdev, cfg) \ diff --git a/drivers/net/wireless/iwlwifi/iwl-csr.h b/drivers/net/wireless/iwlwifi/iwl-csr.h index 1123319..5ab90ba 100644 --- a/drivers/net/wireless/iwlwifi/iwl-csr.h +++ b/drivers/net/wireless/iwlwifi/iwl-csr.h @@ -5,7 +5,7 @@ * * GPL LICENSE SUMMARY * - * Copyright(c) 2005 - 2010 Intel Corporation. All rights reserved. + * Copyright(c) 2005 - 2011 Intel Corporation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -30,7 +30,7 @@ * * BSD LICENSE * - * Copyright(c) 2005 - 2010 Intel Corporation. All rights reserved. + * Copyright(c) 2005 - 2011 Intel Corporation. All rights reserved. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/net/wireless/iwlwifi/iwl-debug.h b/drivers/net/wireless/iwlwifi/iwl-debug.h index ebdea3b..8489431 100644 --- a/drivers/net/wireless/iwlwifi/iwl-debug.h +++ b/drivers/net/wireless/iwlwifi/iwl-debug.h @@ -1,6 +1,6 @@ /****************************************************************************** * - * Copyright(c) 2003 - 2010 Intel Corporation. All rights reserved. + * Copyright(c) 2003 - 2011 Intel Corporation. All rights reserved. * * Portions of this file are derived from the ipw3945 project. * diff --git a/drivers/net/wireless/iwlwifi/iwl-debugfs.c b/drivers/net/wireless/iwlwifi/iwl-debugfs.c index 90f2b64..92f6efd 100644 --- a/drivers/net/wireless/iwlwifi/iwl-debugfs.c +++ b/drivers/net/wireless/iwlwifi/iwl-debugfs.c @@ -2,7 +2,7 @@ * * GPL LICENSE SUMMARY * - * Copyright(c) 2008 - 2010 Intel Corporation. All rights reserved. + * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index 7619cee..0696e7f 100644 --- a/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h @@ -1,6 +1,6 @@ /****************************************************************************** * - * Copyright(c) 2003 - 2010 Intel Corporation. All rights reserved. + * Copyright(c) 2003 - 2011 Intel Corporation. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of version 2 of the GNU General Public License as diff --git a/drivers/net/wireless/iwlwifi/iwl-devtrace.c b/drivers/net/wireless/iwlwifi/iwl-devtrace.c index 4a48763..a635a7e 100644 --- a/drivers/net/wireless/iwlwifi/iwl-devtrace.c +++ b/drivers/net/wireless/iwlwifi/iwl-devtrace.c @@ -1,6 +1,6 @@ /****************************************************************************** * - * Copyright(c) 2009 - 2010 Intel Corporation. All rights reserved. + * Copyright(c) 2009 - 2011 Intel Corporation. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of version 2 of the GNU General Public License as diff --git a/drivers/net/wireless/iwlwifi/iwl-devtrace.h b/drivers/net/wireless/iwlwifi/iwl-devtrace.h index 4cf864c..f00172c 100644 --- a/drivers/net/wireless/iwlwifi/iwl-devtrace.h +++ b/drivers/net/wireless/iwlwifi/iwl-devtrace.h @@ -1,6 +1,6 @@ /****************************************************************************** * - * Copyright(c) 2009 - 2010 Intel Corporation. All rights reserved. + * Copyright(c) 2009 - 2011 Intel Corporation. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of version 2 of the GNU General Public License as diff --git a/drivers/net/wireless/iwlwifi/iwl-eeprom.c b/drivers/net/wireless/iwlwifi/iwl-eeprom.c index c831a0f..f70d871 100644 --- a/drivers/net/wireless/iwlwifi/iwl-eeprom.c +++ b/drivers/net/wireless/iwlwifi/iwl-eeprom.c @@ -5,7 +5,7 @@ * * GPL LICENSE SUMMARY * - * Copyright(c) 2008 - 2010 Intel Corporation. All rights reserved. + * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -30,7 +30,7 @@ * * BSD LICENSE * - * Copyright(c) 2005 - 2010 Intel Corporation. All rights reserved. + * Copyright(c) 2005 - 2011 Intel Corporation. All rights reserved. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/net/wireless/iwlwifi/iwl-eeprom.h b/drivers/net/wireless/iwlwifi/iwl-eeprom.h index d0f858a..35bf54b 100644 --- a/drivers/net/wireless/iwlwifi/iwl-eeprom.h +++ b/drivers/net/wireless/iwlwifi/iwl-eeprom.h @@ -5,7 +5,7 @@ * * GPL LICENSE SUMMARY * - * Copyright(c) 2008 - 2010 Intel Corporation. All rights reserved. + * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -30,7 +30,7 @@ * * BSD LICENSE * - * Copyright(c) 2005 - 2010 Intel Corporation. All rights reserved. + * Copyright(c) 2005 - 2011 Intel Corporation. All rights reserved. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/net/wireless/iwlwifi/iwl-fh.h b/drivers/net/wireless/iwlwifi/iwl-fh.h index 55b8370..da06d13 100644 --- a/drivers/net/wireless/iwlwifi/iwl-fh.h +++ b/drivers/net/wireless/iwlwifi/iwl-fh.h @@ -5,7 +5,7 @@ * * GPL LICENSE SUMMARY * - * Copyright(c) 2005 - 2010 Intel Corporation. All rights reserved. + * Copyright(c) 2005 - 2011 Intel Corporation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -30,7 +30,7 @@ * * BSD LICENSE * - * Copyright(c) 2005 - 2010 Intel Corporation. All rights reserved. + * Copyright(c) 2005 - 2011 Intel Corporation. All rights reserved. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/net/wireless/iwlwifi/iwl-hcmd.c b/drivers/net/wireless/iwlwifi/iwl-hcmd.c index 165e756..9177b55 100644 --- a/drivers/net/wireless/iwlwifi/iwl-hcmd.c +++ b/drivers/net/wireless/iwlwifi/iwl-hcmd.c @@ -2,7 +2,7 @@ * * GPL LICENSE SUMMARY * - * Copyright(c) 2008 - 2010 Intel Corporation. All rights reserved. + * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as diff --git a/drivers/net/wireless/iwlwifi/iwl-helpers.h b/drivers/net/wireless/iwlwifi/iwl-helpers.h index 8821f08..5da5761 100644 --- a/drivers/net/wireless/iwlwifi/iwl-helpers.h +++ b/drivers/net/wireless/iwlwifi/iwl-helpers.h @@ -1,6 +1,6 @@ /****************************************************************************** * - * Copyright(c) 2003 - 2010 Intel Corporation. All rights reserved. + * Copyright(c) 2003 - 2011 Intel Corporation. All rights reserved. * * Portions of this file are derived from the ipw3945 project, as well * as portions of the ieee80211 subsystem header files. diff --git a/drivers/net/wireless/iwlwifi/iwl-io.h b/drivers/net/wireless/iwlwifi/iwl-io.h index 0203a3b..3ddb2fb 100644 --- a/drivers/net/wireless/iwlwifi/iwl-io.h +++ b/drivers/net/wireless/iwlwifi/iwl-io.h @@ -1,6 +1,6 @@ /****************************************************************************** * - * Copyright(c) 2003 - 2010 Intel Corporation. All rights reserved. + * Copyright(c) 2003 - 2011 Intel Corporation. All rights reserved. * * Portions of this file are derived from the ipw3945 project. * diff --git a/drivers/net/wireless/iwlwifi/iwl-led.c b/drivers/net/wireless/iwlwifi/iwl-led.c index d7f2a0b..c2862d4 100644 --- a/drivers/net/wireless/iwlwifi/iwl-led.c +++ b/drivers/net/wireless/iwlwifi/iwl-led.c @@ -1,6 +1,6 @@ /****************************************************************************** * - * Copyright(c) 2003 - 2010 Intel Corporation. All rights reserved. + * Copyright(c) 2003 - 2011 Intel Corporation. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of version 2 of the GNU General Public License as diff --git a/drivers/net/wireless/iwlwifi/iwl-led.h b/drivers/net/wireless/iwlwifi/iwl-led.h index 101eef1..05b8e8f 100644 --- a/drivers/net/wireless/iwlwifi/iwl-led.h +++ b/drivers/net/wireless/iwlwifi/iwl-led.h @@ -1,6 +1,6 @@ /****************************************************************************** * - * Copyright(c) 2003 - 2010 Intel Corporation. All rights reserved. + * Copyright(c) 2003 - 2011 Intel Corporation. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of version 2 of the GNU General Public License as diff --git a/drivers/net/wireless/iwlwifi/iwl-power.c b/drivers/net/wireless/iwlwifi/iwl-power.c index 576795e..c43c8e6 100644 --- a/drivers/net/wireless/iwlwifi/iwl-power.c +++ b/drivers/net/wireless/iwlwifi/iwl-power.c @@ -1,6 +1,6 @@ /****************************************************************************** * - * Copyright(c) 2007 - 2010 Intel Corporation. All rights reserved. + * Copyright(c) 2007 - 2011 Intel Corporation. All rights reserved. * * Portions of this file are derived from the ipw3945 project, as well * as portions of the ieee80211 subsystem header files. diff --git a/drivers/net/wireless/iwlwifi/iwl-power.h b/drivers/net/wireless/iwlwifi/iwl-power.h index fe01203..59635d7 100644 --- a/drivers/net/wireless/iwlwifi/iwl-power.h +++ b/drivers/net/wireless/iwlwifi/iwl-power.h @@ -1,6 +1,6 @@ /****************************************************************************** * - * Copyright(c) 2007 - 2010 Intel Corporation. All rights reserved. + * Copyright(c) 2007 - 2011 Intel Corporation. All rights reserved. * * Portions of this file are derived from the ipw3945 project, as well * as portions of the ieee80211 subsystem header files. diff --git a/drivers/net/wireless/iwlwifi/iwl-prph.h b/drivers/net/wireless/iwlwifi/iwl-prph.h index 448b0ea..c960195 100644 --- a/drivers/net/wireless/iwlwifi/iwl-prph.h +++ b/drivers/net/wireless/iwlwifi/iwl-prph.h @@ -5,7 +5,7 @@ * * GPL LICENSE SUMMARY * - * Copyright(c) 2005 - 2010 Intel Corporation. All rights reserved. + * Copyright(c) 2005 - 2011 Intel Corporation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -30,7 +30,7 @@ * * BSD LICENSE * - * Copyright(c) 2005 - 2010 Intel Corporation. All rights reserved. + * Copyright(c) 2005 - 2011 Intel Corporation. All rights reserved. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/net/wireless/iwlwifi/iwl-rx.c b/drivers/net/wireless/iwlwifi/iwl-rx.c index 6f9a2fa..984a42c 100644 --- a/drivers/net/wireless/iwlwifi/iwl-rx.c +++ b/drivers/net/wireless/iwlwifi/iwl-rx.c @@ -1,6 +1,6 @@ /****************************************************************************** * - * Copyright(c) 2003 - 2010 Intel Corporation. All rights reserved. + * Copyright(c) 2003 - 2011 Intel Corporation. All rights reserved. * * Portions of this file are derived from the ipw3945 project, as well * as portions of the ieee80211 subsystem header files. diff --git a/drivers/net/wireless/iwlwifi/iwl-scan.c b/drivers/net/wireless/iwlwifi/iwl-scan.c index 3a4d9e6..c517f6d 100644 --- a/drivers/net/wireless/iwlwifi/iwl-scan.c +++ b/drivers/net/wireless/iwlwifi/iwl-scan.c @@ -2,7 +2,7 @@ * * GPL LICENSE SUMMARY * - * Copyright(c) 2008 - 2010 Intel Corporation. All rights reserved. + * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as diff --git a/drivers/net/wireless/iwlwifi/iwl-spectrum.h b/drivers/net/wireless/iwlwifi/iwl-spectrum.h index c4ca0b5..cb80bb4 100644 --- a/drivers/net/wireless/iwlwifi/iwl-spectrum.h +++ b/drivers/net/wireless/iwlwifi/iwl-spectrum.h @@ -1,6 +1,6 @@ /****************************************************************************** * - * Copyright(c) 2003 - 2010 Intel Corporation. All rights reserved. + * Copyright(c) 2003 - 2011 Intel Corporation. All rights reserved. * * Portions of this file are derived from the ieee80211 subsystem header files. * diff --git a/drivers/net/wireless/iwlwifi/iwl-sta.c b/drivers/net/wireless/iwlwifi/iwl-sta.c index 6ded017..c215156 100644 --- a/drivers/net/wireless/iwlwifi/iwl-sta.c +++ b/drivers/net/wireless/iwlwifi/iwl-sta.c @@ -1,6 +1,6 @@ /****************************************************************************** * - * Copyright(c) 2003 - 2010 Intel Corporation. All rights reserved. + * Copyright(c) 2003 - 2011 Intel Corporation. All rights reserved. * * Portions of this file are derived from the ipw3945 project, as well * as portions of the ieee80211 subsystem header files. diff --git a/drivers/net/wireless/iwlwifi/iwl-sta.h b/drivers/net/wireless/iwlwifi/iwl-sta.h index 206f1e1..ff64027 100644 --- a/drivers/net/wireless/iwlwifi/iwl-sta.h +++ b/drivers/net/wireless/iwlwifi/iwl-sta.h @@ -1,6 +1,6 @@ /****************************************************************************** * - * Copyright(c) 2003 - 2010 Intel Corporation. All rights reserved. + * Copyright(c) 2003 - 2011 Intel Corporation. All rights reserved. * * Portions of this file are derived from the ipw3945 project, as well * as portions of the ieee80211 subsystem header files. diff --git a/drivers/net/wireless/iwlwifi/iwl-tx.c b/drivers/net/wireless/iwlwifi/iwl-tx.c index fa81df2..565980f 100644 --- a/drivers/net/wireless/iwlwifi/iwl-tx.c +++ b/drivers/net/wireless/iwlwifi/iwl-tx.c @@ -1,6 +1,6 @@ /****************************************************************************** * - * Copyright(c) 2003 - 2010 Intel Corporation. All rights reserved. + * Copyright(c) 2003 - 2011 Intel Corporation. All rights reserved. * * Portions of this file are derived from the ipw3945 project, as well * as portions of the ieee80211 subsystem header files. -- cgit v0.10.2 From 7415952ff789b1c1878119662d4dc011ac9d261e Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Tue, 5 Apr 2011 09:42:01 -0700 Subject: iwlagn: check more error return code In alive notify, we should check return code instead of assume everything ok Signed-off-by: Wey-Yi Guy Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-ucode.c b/drivers/net/wireless/iwlwifi/iwl-agn-ucode.c index a7c9131..9c5abff 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-ucode.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-ucode.c @@ -432,6 +432,7 @@ int iwlagn_alive_notify(struct iwl_priv *priv) unsigned long flags; int i, chan; u32 reg_val; + int ret; spin_lock_irqsave(&priv->lock, flags); @@ -527,9 +528,14 @@ int iwlagn_alive_notify(struct iwl_priv *priv) iwl_clear_bits_prph(priv, APMG_PCIDEV_STT_REG, APMG_PCIDEV_STT_VAL_L1_ACT_DIS); - iwlagn_send_wimax_coex(priv); + ret = iwlagn_send_wimax_coex(priv); + if (ret) + return ret; + + ret = iwlagn_set_Xtal_calib(priv); + if (ret) + return ret; - iwlagn_set_Xtal_calib(priv); return iwl_send_calib_results(priv); } -- cgit v0.10.2 From 3997ff39faa184a2ff670a6792cdb89ff51cf78f Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 5 Apr 2011 09:42:02 -0700 Subject: iwlagn: add feature flags Some new devices and microcode files will a greater variety of features, so the TLV-per-feature approach we took before will quickly make things harder to manage and increase the file size. Add a new TLV that has feature flags. Currently, it will contain: 1) a PAN feature flag, which moves from a separate TLV 2) a new BT stats bit that indicates whether the microcode image uses bluetooth statistics 3) a new MFP flag for management frame protection which can be enabled once the device/microcode supports it Signed-off-by: Johannes Berg Signed-off-by: Wey-Yi Guy Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index 2f4fe16..30b8b9e 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -1191,7 +1191,7 @@ static void iwl_nic_start(struct iwl_priv *priv) struct iwlagn_ucode_capabilities { u32 max_probe_length; u32 standard_phy_calibration_size; - bool pan; + u32 flags; }; static void iwl_ucode_callback(const struct firmware *ucode_raw, void *context); @@ -1418,7 +1418,23 @@ static int iwlagn_load_firmware(struct iwl_priv *priv, case IWL_UCODE_TLV_PAN: if (tlv_len) goto invalid_tlv_len; - capa->pan = true; + capa->flags |= IWL_UCODE_TLV_FLAGS_PAN; + break; + case IWL_UCODE_TLV_FLAGS: + /* must be at least one u32 */ + if (tlv_len < sizeof(u32)) + goto invalid_tlv_len; + /* and a proper number of u32s */ + if (tlv_len % sizeof(u32)) + goto invalid_tlv_len; + /* + * This driver only reads the first u32 as + * right now no more features are defined, + * if that changes then either the driver + * will not work with the new firmware, or + * it'll not take advantage of new features. + */ + capa->flags = le32_to_cpup((__le32 *)tlv_data); break; case IWL_UCODE_TLV_INIT_EVTLOG_PTR: if (tlv_len != sizeof(u32)) @@ -1681,12 +1697,16 @@ static void iwl_ucode_callback(const struct firmware *ucode_raw, void *context) priv->cfg->base_params->max_event_log_size; priv->_agn.inst_errlog_ptr = pieces.inst_errlog_ptr; - if (ucode_capa.pan) { + if (ucode_capa.flags & IWL_UCODE_TLV_FLAGS_PAN) { priv->valid_contexts |= BIT(IWL_RXON_CTX_PAN); priv->sta_key_max_num = STA_KEY_MAX_NUM_PAN; } else priv->sta_key_max_num = STA_KEY_MAX_NUM; + if (ucode_capa.flags & IWL_UCODE_TLV_FLAGS_BTSTATS || + (priv->cfg->bt_params && priv->cfg->bt_params->bt_statistics)) + priv->bt_statistics = true; + /* Copy images into buffers for card's bus-master reads ... */ /* Runtime instructions (first block of data in file) */ @@ -2827,6 +2847,9 @@ static int iwl_mac_setup_register(struct iwl_priv *priv, hw->flags |= IEEE80211_HW_SUPPORTS_DYNAMIC_SMPS | IEEE80211_HW_SUPPORTS_STATIC_SMPS; + if (capa->flags & IWL_UCODE_TLV_FLAGS_MFP) + hw->flags |= IEEE80211_HW_MFP_CAPABLE; + hw->sta_data_size = sizeof(struct iwl_station_priv); hw->vif_data_size = sizeof(struct iwl_vif_priv); diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h index 696b056..7b9f64ea 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.h +++ b/drivers/net/wireless/iwlwifi/iwl-core.h @@ -723,7 +723,7 @@ static inline bool iwl_advanced_bt_coexist(struct iwl_priv *priv) static inline bool iwl_bt_statistics(struct iwl_priv *priv) { - return priv->cfg->bt_params && priv->cfg->bt_params->bt_statistics; + return priv->bt_statistics; } extern bool bt_coex_active; diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index 0696e7f..2f7458d 100644 --- a/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h @@ -535,6 +535,22 @@ enum iwl_ucode_tlv_type { IWL_UCODE_TLV_INIT_ERRLOG_PTR = 13, IWL_UCODE_TLV_ENHANCE_SENS_TBL = 14, IWL_UCODE_TLV_PHY_CALIBRATION_SIZE = 15, + /* 16 and 17 reserved for future use */ + IWL_UCODE_TLV_FLAGS = 18, +}; + +/** + * enum iwl_ucode_tlv_flag - ucode API flags + * @IWL_UCODE_TLV_FLAGS_PAN: This is PAN capable microcode; this previously + * was a separate TLV but moved here to save space. + * @IWL_UCODE_TLV_FLAGS_BTSTATS: This uCode image uses BT statistics, which + * may be true even if the device doesn't have BT. + * @IWL_UCODE_TLV_FLAGS_MFP: This uCode image supports MFP (802.11w). + */ +enum iwl_ucode_tlv_flag { + IWL_UCODE_TLV_FLAGS_PAN = BIT(0), + IWL_UCODE_TLV_FLAGS_BTSTATS = BIT(1), + IWL_UCODE_TLV_FLAGS_MFP = BIT(2), }; struct iwl_ucode_tlv { @@ -1410,6 +1426,7 @@ struct iwl_priv { bool bt_ch_announce; bool bt_full_concurrent; bool bt_ant_couple_ok; + bool bt_statistics; __le32 kill_ack_mask; __le32 kill_cts_mask; __le16 bt_valid; -- cgit v0.10.2 From 3d09cdff233b5a37ce9993c533e8da1403e2da30 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 5 Apr 2011 09:42:03 -0700 Subject: iwlagn: fix ucode verify message My previous patch left a message talking about bootstrap, but that's clearly bogus. Signed-off-by: Johannes Berg Signed-off-by: Wey-Yi Guy Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-ucode.c b/drivers/net/wireless/iwlwifi/iwl-agn-ucode.c index 9c5abff..5187a2c 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-ucode.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-ucode.c @@ -606,7 +606,7 @@ static void iwl_print_mismatch_inst(struct iwl_priv *priv, int iwl_verify_ucode(struct iwl_priv *priv, struct fw_desc *fw_desc) { if (!iwlcore_verify_inst_sparse(priv, fw_desc)) { - IWL_DEBUG_INFO(priv, "Bootstrap uCode is good in inst SRAM\n"); + IWL_DEBUG_INFO(priv, "uCode is good in inst SRAM\n"); return 0; } -- cgit v0.10.2 From d7d5783c6668b54111cc77005755799e94261497 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 5 Apr 2011 09:42:04 -0700 Subject: iwlagn: clean up alive handling Devices newer than 4965 don't actually send two different versions of the ALIVE command, so we always had a bug here since before this patch we copy more data than we got. Remove the iwl_init_alive_resp struct and don't use it. Since we also really don't need to track all the data received in ALIVE as we only use the error and log event tables later, we can also save space by just keeping those and not more data around in memory. Signed-off-by: Johannes Berg Signed-off-by: Wey-Yi Guy Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index 30b8b9e..b3b1e84 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -590,10 +590,7 @@ static void iwl_continuous_event_trace(struct iwl_priv *priv) u32 num_wraps; /* # times uCode wrapped to top of log */ u32 next_entry; /* index of next entry to be written by uCode */ - if (priv->ucode_type == UCODE_INIT) - base = le32_to_cpu(priv->card_alive_init.error_event_table_ptr); - else - base = le32_to_cpu(priv->card_alive.log_event_table_ptr); + base = priv->device_pointers.error_event_table; if (priv->cfg->ops->lib->is_valid_rtc_data_addr(base)) { capacity = iwl_read_targ_mem(priv, base); num_wraps = iwl_read_targ_mem(priv, base + (2 * sizeof(u32))); @@ -1871,12 +1868,11 @@ void iwl_dump_nic_error_log(struct iwl_priv *priv) u32 blink1, blink2, ilink1, ilink2; u32 pc, hcmd; + base = priv->device_pointers.error_event_table; if (priv->ucode_type == UCODE_INIT) { - base = le32_to_cpu(priv->card_alive_init.error_event_table_ptr); if (!base) base = priv->_agn.init_errlog_ptr; } else { - base = le32_to_cpu(priv->card_alive.error_event_table_ptr); if (!base) base = priv->_agn.inst_errlog_ptr; } @@ -1941,12 +1937,11 @@ static int iwl_print_event_log(struct iwl_priv *priv, u32 start_idx, if (num_events == 0) return pos; + base = priv->device_pointers.log_event_table; if (priv->ucode_type == UCODE_INIT) { - base = le32_to_cpu(priv->card_alive_init.log_event_table_ptr); if (!base) base = priv->_agn.init_evtlog_ptr; } else { - base = le32_to_cpu(priv->card_alive.log_event_table_ptr); if (!base) base = priv->_agn.inst_evtlog_ptr; } @@ -2055,13 +2050,12 @@ int iwl_dump_nic_event_log(struct iwl_priv *priv, bool full_log, int pos = 0; size_t bufsz = 0; + base = priv->device_pointers.log_event_table; if (priv->ucode_type == UCODE_INIT) { - base = le32_to_cpu(priv->card_alive_init.log_event_table_ptr); logsize = priv->_agn.init_evtlog_size; if (!base) base = priv->_agn.init_evtlog_ptr; } else { - base = le32_to_cpu(priv->card_alive.log_event_table_ptr); logsize = priv->_agn.inst_evtlog_size; if (!base) base = priv->_agn.inst_evtlog_ptr; @@ -2415,8 +2409,6 @@ static void __iwl_down(struct iwl_priv *priv) iwl_apm_stop(priv); exit: - memset(&priv->card_alive, 0, sizeof(struct iwl_alive_resp)); - dev_kfree_skb(priv->beacon_skb); priv->beacon_skb = NULL; diff --git a/drivers/net/wireless/iwlwifi/iwl-commands.h b/drivers/net/wireless/iwlwifi/iwl-commands.h index a2348ee..a1a5c1b 100644 --- a/drivers/net/wireless/iwlwifi/iwl-commands.h +++ b/drivers/net/wireless/iwlwifi/iwl-commands.h @@ -388,54 +388,6 @@ struct iwl_tx_ant_config_cmd { #define UCODE_VALID_OK cpu_to_le32(0x1) #define INITIALIZE_SUBTYPE (9) -/* - * ("Initialize") REPLY_ALIVE = 0x1 (response only, not a command) - * - * uCode issues this "initialize alive" notification once the initialization - * uCode image has completed its work, and is ready to load the runtime image. - * This is the *first* "alive" notification that the driver will receive after - * rebooting uCode; the "initialize" alive is indicated by subtype field == 9. - * - * See comments documenting "BSM" (bootstrap state machine). - * - * For 4965, this notification contains important calibration data for - * calculating txpower settings: - * - * 1) Power supply voltage indication. The voltage sensor outputs higher - * values for lower voltage, and vice verse. - * - * 2) Temperature measurement parameters, for each of two channel widths - * (20 MHz and 40 MHz) supported by the radios. Temperature sensing - * is done via one of the receiver chains, and channel width influences - * the results. - * - * 3) Tx gain compensation to balance 4965's 2 Tx chains for MIMO operation, - * for each of 5 frequency ranges. - */ -struct iwl_init_alive_resp { - u8 ucode_minor; - u8 ucode_major; - __le16 reserved1; - u8 sw_rev[8]; - u8 ver_type; - u8 ver_subtype; /* "9" for initialize alive */ - __le16 reserved2; - __le32 log_event_table_ptr; - __le32 error_event_table_ptr; - __le32 timestamp; - __le32 is_valid; - - /* calibration values from "initialize" uCode */ - __le32 voltage; /* signed, higher value is lower voltage */ - __le32 therm_r1[2]; /* signed, 1st for normal, 2nd for HT40 */ - __le32 therm_r2[2]; /* signed */ - __le32 therm_r3[2]; /* signed */ - __le32 therm_r4[2]; /* signed */ - __le32 tx_atten[5][2]; /* signed MIMO gain comp, 5 freq groups, - * 2 Tx chains */ -} __packed; - - /** * REPLY_ALIVE = 0x1 (response only, not a command) * diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index 2f7458d..b4bfcab 100644 --- a/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h @@ -1285,10 +1285,10 @@ struct iwl_priv { struct iwl_switch_rxon switch_rxon; - /* 1st responses from initialize and runtime uCode images. - * _agn's initialize alive response contains some calibration data. */ - struct iwl_init_alive_resp card_alive_init; - struct iwl_alive_resp card_alive; + struct { + u32 error_event_table; + u32 log_event_table; + } device_pointers; u16 active_rate; diff --git a/drivers/net/wireless/iwlwifi/iwl-rx.c b/drivers/net/wireless/iwlwifi/iwl-rx.c index 984a42c..b5124de 100644 --- a/drivers/net/wireless/iwlwifi/iwl-rx.c +++ b/drivers/net/wireless/iwlwifi/iwl-rx.c @@ -239,16 +239,16 @@ static void iwl_rx_reply_alive(struct iwl_priv *priv, palive->is_valid, palive->ver_type, palive->ver_subtype); + priv->device_pointers.log_event_table = + le32_to_cpu(palive->log_event_table_ptr); + priv->device_pointers.error_event_table = + le32_to_cpu(palive->error_event_table_ptr); + if (palive->ver_subtype == INITIALIZE_SUBTYPE) { IWL_DEBUG_INFO(priv, "Initialization Alive received.\n"); - memcpy(&priv->card_alive_init, - &pkt->u.alive_frame, - sizeof(struct iwl_init_alive_resp)); pwork = &priv->init_alive_start; } else { IWL_DEBUG_INFO(priv, "Runtime Alive received.\n"); - memcpy(&priv->card_alive, &pkt->u.alive_frame, - sizeof(struct iwl_alive_resp)); pwork = &priv->alive_start; } -- cgit v0.10.2 From 17445b8c443bb1aaf7f85bcf60676d04be1c467c Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 5 Apr 2011 09:42:05 -0700 Subject: iwlagn: init cmd_queue earlier We know after loading the ucode whether it will support PAN or not, so we can also initialise the cmd_queue variable much earlier. Signed-off-by: Johannes Berg Signed-off-by: Wey-Yi Guy Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index b3b1e84..d700860 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -1700,6 +1700,11 @@ static void iwl_ucode_callback(const struct firmware *ucode_raw, void *context) } else priv->sta_key_max_num = STA_KEY_MAX_NUM; + if (priv->valid_contexts != BIT(IWL_RXON_CTX_BSS)) + priv->cmd_queue = IWL_IPAN_CMD_QUEUE_NUM; + else + priv->cmd_queue = IWL_DEFAULT_CMD_QUEUE_NUM; + if (ucode_capa.flags & IWL_UCODE_TLV_FLAGS_BTSTATS || (priv->cfg->bt_params && priv->cfg->bt_params->bt_statistics)) priv->bt_statistics = true; @@ -2518,12 +2523,6 @@ static int __iwl_up(struct iwl_priv *priv) iwl_write32(priv, CSR_INT, 0xFFFFFFFF); - /* must be initialised before iwl_hw_nic_init */ - if (priv->valid_contexts != BIT(IWL_RXON_CTX_BSS)) - priv->cmd_queue = IWL_IPAN_CMD_QUEUE_NUM; - else - priv->cmd_queue = IWL_DEFAULT_CMD_QUEUE_NUM; - ret = iwlagn_hw_nic_init(priv); if (ret) { IWL_ERR(priv, "Unable to init nic\n"); -- cgit v0.10.2 From 917b6777b45ac49c436570e36eb09d9b8b84c434 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 5 Apr 2011 09:42:06 -0700 Subject: iwlagn: remove BSM clock setting Again, a 4965 specific code path that we no longer need in iwlagn. Signed-off-by: Johannes Berg Signed-off-by: Wey-Yi Guy Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwlwifi/iwl-1000.c b/drivers/net/wireless/iwlwifi/iwl-1000.c index 5c3bb47..de5b287 100644 --- a/drivers/net/wireless/iwlwifi/iwl-1000.c +++ b/drivers/net/wireless/iwlwifi/iwl-1000.c @@ -249,7 +249,6 @@ static struct iwl_base_params iwl1000_base_params = { .eeprom_size = OTP_LOW_IMAGE_SIZE, .pll_cfg_val = CSR50_ANA_PLL_CFG_VAL, .set_l0s = true, - .use_bsm = false, .max_ll_items = OTP_MAX_LL_ITEMS_1000, .shadow_ram_support = false, .led_compensation = 51, diff --git a/drivers/net/wireless/iwlwifi/iwl-2000.c b/drivers/net/wireless/iwlwifi/iwl-2000.c index f87adbf..d22e006 100644 --- a/drivers/net/wireless/iwlwifi/iwl-2000.c +++ b/drivers/net/wireless/iwlwifi/iwl-2000.c @@ -356,7 +356,6 @@ static struct iwl_base_params iwl2000_base_params = { .num_of_ampdu_queues = IWLAGN_NUM_AMPDU_QUEUES, .pll_cfg_val = 0, .set_l0s = true, - .use_bsm = false, .max_ll_items = OTP_MAX_LL_ITEMS_2x00, .shadow_ram_support = true, .led_compensation = 51, @@ -380,7 +379,6 @@ static struct iwl_base_params iwl2030_base_params = { .num_of_ampdu_queues = IWLAGN_NUM_AMPDU_QUEUES, .pll_cfg_val = 0, .set_l0s = true, - .use_bsm = false, .max_ll_items = OTP_MAX_LL_ITEMS_2x00, .shadow_ram_support = true, .led_compensation = 57, diff --git a/drivers/net/wireless/iwlwifi/iwl-5000.c b/drivers/net/wireless/iwlwifi/iwl-5000.c index d2f4eb3..de0e86a 100644 --- a/drivers/net/wireless/iwlwifi/iwl-5000.c +++ b/drivers/net/wireless/iwlwifi/iwl-5000.c @@ -488,7 +488,6 @@ static struct iwl_base_params iwl5000_base_params = { .num_of_ampdu_queues = IWLAGN_NUM_AMPDU_QUEUES, .pll_cfg_val = CSR50_ANA_PLL_CFG_VAL, .set_l0s = true, - .use_bsm = false, .led_compensation = 51, .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS, .plcp_delta_threshold = IWL_MAX_PLCP_ERR_LONG_THRESHOLD_DEF, diff --git a/drivers/net/wireless/iwlwifi/iwl-6000.c b/drivers/net/wireless/iwlwifi/iwl-6000.c index c1f8d1d..be2dbf7 100644 --- a/drivers/net/wireless/iwlwifi/iwl-6000.c +++ b/drivers/net/wireless/iwlwifi/iwl-6000.c @@ -459,7 +459,6 @@ static struct iwl_base_params iwl6000_base_params = { .num_of_ampdu_queues = IWLAGN_NUM_AMPDU_QUEUES, .pll_cfg_val = 0, .set_l0s = true, - .use_bsm = false, .max_ll_items = OTP_MAX_LL_ITEMS_6x00, .shadow_ram_support = true, .led_compensation = 51, @@ -482,7 +481,6 @@ static struct iwl_base_params iwl6050_base_params = { .num_of_ampdu_queues = IWLAGN_NUM_AMPDU_QUEUES, .pll_cfg_val = 0, .set_l0s = true, - .use_bsm = false, .max_ll_items = OTP_MAX_LL_ITEMS_6x50, .shadow_ram_support = true, .led_compensation = 51, @@ -504,7 +502,6 @@ static struct iwl_base_params iwl6000_g2_base_params = { .num_of_ampdu_queues = IWLAGN_NUM_AMPDU_QUEUES, .pll_cfg_val = 0, .set_l0s = true, - .use_bsm = false, .max_ll_items = OTP_MAX_LL_ITEMS_6x00, .shadow_ram_support = true, .led_compensation = 57, diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index 6e9829f..c46be36 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -1105,21 +1105,13 @@ int iwl_apm_init(struct iwl_priv *priv) } /* - * Enable DMA and BSM (if used) clocks, wait for them to stabilize. - * BSM (Boostrap State Machine) is only in 3945 and 4965; - * later devices (i.e. 5000 and later) have non-volatile SRAM, - * and don't need BSM to restore data after power-saving sleep. + * Enable DMA clock and wait for it to stabilize. * * Write to "CLK_EN_REG"; "1" bits enable clocks, while "0" bits * do not disable clocks. This preserves any hardware bits already * set by default in "CLK_CTRL_REG" after reset. */ - if (priv->cfg->base_params->use_bsm) - iwl_write_prph(priv, APMG_CLK_EN_REG, - APMG_CLK_VAL_DMA_CLK_RQT | APMG_CLK_VAL_BSM_CLK_RQT); - else - iwl_write_prph(priv, APMG_CLK_EN_REG, - APMG_CLK_VAL_DMA_CLK_RQT); + iwl_write_prph(priv, APMG_CLK_EN_REG, APMG_CLK_VAL_DMA_CLK_RQT); udelay(20); /* Disable L1-Active */ diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h index 7b9f64ea..ada76af 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.h +++ b/drivers/net/wireless/iwlwifi/iwl-core.h @@ -283,7 +283,6 @@ struct iwl_base_params { /* for iwl_apm_init() */ u32 pll_cfg_val; bool set_l0s; - bool use_bsm; const u16 max_ll_items; const bool shadow_ram_support; -- cgit v0.10.2 From bc255930639122d788d1b6ce10d3c01cc2946398 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 5 Apr 2011 09:42:07 -0700 Subject: iwlagn: remove hw_wa_rev The variable is never used. Signed-off-by: Johannes Berg Signed-off-by: Wey-Yi Guy Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index d700860..55a1d65 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -3688,7 +3688,6 @@ struct ieee80211_ops iwlagn_hw_ops = { static void iwl_hw_detect(struct iwl_priv *priv) { priv->hw_rev = _iwl_read32(priv, CSR_HW_REV); - priv->hw_wa_rev = _iwl_read32(priv, CSR_HW_REV_WA_REG); priv->rev_id = priv->pci_dev->revision; IWL_DEBUG_INFO(priv, "HW Revision ID = 0x%X\n", priv->rev_id); } diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index b4bfcab..2c2d5b0 100644 --- a/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h @@ -1254,7 +1254,6 @@ struct iwl_priv { /* pci hardware address support */ void __iomem *hw_base; u32 hw_rev; - u32 hw_wa_rev; u8 rev_id; /* microcode/device supports multiple contexts */ -- cgit v0.10.2 From e98a130259ed6f88bc2833fa525b10453c92c047 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 5 Apr 2011 09:42:08 -0700 Subject: iwlagn: remove hw_rev The hw_rev variable is used only during init, so there's no need to keep it around. Signed-off-by: Johannes Berg Signed-off-by: Wey-Yi Guy Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index 55a1d65..c3306ba 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -3685,11 +3685,11 @@ struct ieee80211_ops iwlagn_hw_ops = { .offchannel_tx_cancel_wait = iwl_mac_offchannel_tx_cancel_wait, }; -static void iwl_hw_detect(struct iwl_priv *priv) +static u32 iwl_hw_detect(struct iwl_priv *priv) { - priv->hw_rev = _iwl_read32(priv, CSR_HW_REV); priv->rev_id = priv->pci_dev->revision; IWL_DEBUG_INFO(priv, "HW Revision ID = 0x%X\n", priv->rev_id); + return _iwl_read32(priv, CSR_HW_REV); } static int iwl_set_hw_params(struct iwl_priv *priv) @@ -3740,6 +3740,7 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) struct iwl_cfg *cfg = (struct iwl_cfg *)(ent->driver_data); unsigned long flags; u16 pci_cmd, num_mac; + u32 hw_rev; /************************ * 1. Allocating HW data @@ -3885,9 +3886,9 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) */ iwl_write32(priv, CSR_RESET, CSR_RESET_REG_FLAG_NEVO_RESET); - iwl_hw_detect(priv); + hw_rev = iwl_hw_detect(priv); IWL_INFO(priv, "Detected %s, REV=0x%X\n", - priv->cfg->name, priv->hw_rev); + priv->cfg->name, hw_rev); /* We disable the RETRY_TIMEOUT register (0x41) to keep * PCI Tx retries from interfering with C3 CPU state */ @@ -3903,7 +3904,7 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) * 4. Read EEPROM *****************/ /* Read the EEPROM */ - err = iwl_eeprom_init(priv); + err = iwl_eeprom_init(priv, hw_rev); if (err) { IWL_ERR(priv, "Unable to init EEPROM\n"); goto out_iounmap; diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index 2c2d5b0..1779d60 100644 --- a/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h @@ -1253,7 +1253,6 @@ struct iwl_priv { /* pci hardware address support */ void __iomem *hw_base; - u32 hw_rev; u8 rev_id; /* microcode/device supports multiple contexts */ diff --git a/drivers/net/wireless/iwlwifi/iwl-eeprom.c b/drivers/net/wireless/iwlwifi/iwl-eeprom.c index f70d871..4f8c13e 100644 --- a/drivers/net/wireless/iwlwifi/iwl-eeprom.c +++ b/drivers/net/wireless/iwlwifi/iwl-eeprom.c @@ -188,13 +188,13 @@ static void iwl_set_otp_access(struct iwl_priv *priv, enum iwl_access_mode mode) CSR_OTP_GP_REG_OTP_ACCESS_MODE); } -static int iwlcore_get_nvm_type(struct iwl_priv *priv) +static int iwlcore_get_nvm_type(struct iwl_priv *priv, u32 hw_rev) { u32 otpgp; int nvm_type; /* OTP only valid for CP/PP and after */ - switch (priv->hw_rev & CSR_HW_REV_TYPE_MSK) { + switch (hw_rev & CSR_HW_REV_TYPE_MSK) { case CSR_HW_REV_TYPE_NONE: IWL_ERR(priv, "Unknown hardware type\n"); return -ENOENT; @@ -394,7 +394,7 @@ u16 iwl_eeprom_query16(const struct iwl_priv *priv, size_t offset) * * NOTE: This routine uses the non-debug IO access functions. */ -int iwl_eeprom_init(struct iwl_priv *priv) +int iwl_eeprom_init(struct iwl_priv *priv, u32 hw_rev) { __le16 *e; u32 gp = iwl_read32(priv, CSR_EEPROM_GP); @@ -404,7 +404,7 @@ int iwl_eeprom_init(struct iwl_priv *priv) u16 validblockaddr = 0; u16 cache_addr = 0; - priv->nvm_device_type = iwlcore_get_nvm_type(priv); + priv->nvm_device_type = iwlcore_get_nvm_type(priv, hw_rev); if (priv->nvm_device_type == -ENOENT) return -ENOENT; /* allocate eeprom */ diff --git a/drivers/net/wireless/iwlwifi/iwl-eeprom.h b/drivers/net/wireless/iwlwifi/iwl-eeprom.h index 35bf54b..6b4343b 100644 --- a/drivers/net/wireless/iwlwifi/iwl-eeprom.h +++ b/drivers/net/wireless/iwlwifi/iwl-eeprom.h @@ -302,7 +302,7 @@ struct iwl_eeprom_ops { }; -int iwl_eeprom_init(struct iwl_priv *priv); +int iwl_eeprom_init(struct iwl_priv *priv, u32 hw_rev); void iwl_eeprom_free(struct iwl_priv *priv); int iwl_eeprom_check_version(struct iwl_priv *priv); int iwl_eeprom_check_sku(struct iwl_priv *priv); -- cgit v0.10.2 From c2974a1d18832a9fffb2eb389c3878f5c4ed92f1 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 5 Apr 2011 09:42:09 -0700 Subject: iwlagn: remove rev_id The rev_id variable is only printed, we don't need to store it. Signed-off-by: Johannes Berg Signed-off-by: Wey-Yi Guy Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index c3306ba..08bad17c 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -3687,8 +3687,10 @@ struct ieee80211_ops iwlagn_hw_ops = { static u32 iwl_hw_detect(struct iwl_priv *priv) { - priv->rev_id = priv->pci_dev->revision; - IWL_DEBUG_INFO(priv, "HW Revision ID = 0x%X\n", priv->rev_id); + u8 rev_id; + + pci_read_config_byte(priv->pci_dev, PCI_REVISION_ID, &rev_id); + IWL_DEBUG_INFO(priv, "HW Revision ID = 0x%X\n", rev_id); return _iwl_read32(priv, CSR_HW_REV); } diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index 1779d60..54b20d8 100644 --- a/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h @@ -1253,7 +1253,6 @@ struct iwl_priv { /* pci hardware address support */ void __iomem *hw_base; - u8 rev_id; /* microcode/device supports multiple contexts */ u8 valid_contexts; -- cgit v0.10.2 From 0e5884458eeadbb48ab3eb1d5f63b4a53a044a95 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 5 Apr 2011 09:42:10 -0700 Subject: iwlagn: remove rxb page bookkeeping We never use the value in alloc_rxb_page, so there's no point in keeping it either. Signed-off-by: Johannes Berg Signed-off-by: Wey-Yi Guy Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-lib.c b/drivers/net/wireless/iwlwifi/iwl-agn-lib.c index 9a3d69d..9e47be6 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-lib.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-lib.c @@ -912,7 +912,6 @@ void iwlagn_rx_allocate(struct iwl_priv *priv, gfp_t priority) list_add_tail(&rxb->list, &rxq->rx_free); rxq->free_count++; - priv->alloc_rxb_page++; spin_unlock_irqrestore(&rxq->lock, flags); } diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index 54b20d8..7213336 100644 --- a/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h @@ -1191,7 +1191,6 @@ struct iwl_priv { int frames_count; enum ieee80211_band band; - int alloc_rxb_page; void (*rx_handlers[REPLY_MAX])(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb); @@ -1609,12 +1608,10 @@ static inline int is_channel_ibss(const struct iwl_channel_info *ch) static inline void __iwl_free_pages(struct iwl_priv *priv, struct page *page) { __free_pages(page, priv->hw_params.rx_page_order); - priv->alloc_rxb_page--; } static inline void iwl_free_pages(struct iwl_priv *priv, unsigned long page) { free_pages(page, priv->hw_params.rx_page_order); - priv->alloc_rxb_page--; } #endif /* __iwl_dev_h__ */ diff --git a/drivers/net/wireless/iwlwifi/iwl-rx.c b/drivers/net/wireless/iwlwifi/iwl-rx.c index b5124de..c421f56 100644 --- a/drivers/net/wireless/iwlwifi/iwl-rx.c +++ b/drivers/net/wireless/iwlwifi/iwl-rx.c @@ -898,7 +898,6 @@ static void iwl_pass_packet_to_mac80211(struct iwl_priv *priv, memcpy(IEEE80211_SKB_RXCB(skb), stats, sizeof(*stats)); ieee80211_rx(priv->hw, skb); - priv->alloc_rxb_page--; rxb->page = NULL; } -- cgit v0.10.2 From 519d8abd358afad825a1b919a2421d76779f23cd Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 5 Apr 2011 09:42:11 -0700 Subject: iwlagn: remove ISR ops The ISR (interrupt service routine) ops are now no longer necessary since they are the same for all devices this driver now handles. Signed-off-by: Johannes Berg Signed-off-by: Wey-Yi Guy Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwlwifi/iwl-1000.c b/drivers/net/wireless/iwlwifi/iwl-1000.c index de5b287..1b27992 100644 --- a/drivers/net/wireless/iwlwifi/iwl-1000.c +++ b/drivers/net/wireless/iwlwifi/iwl-1000.c @@ -209,13 +209,6 @@ static struct iwl_lib_ops iwl1000_lib = { .calib_version = iwlagn_eeprom_calib_version, .query_addr = iwlagn_eeprom_query_addr, }, - .isr_ops = { - .isr = iwl_isr_ict, - .free = iwl_free_isr_ict, - .alloc = iwl_alloc_isr_ict, - .reset = iwl_reset_ict, - .disable = iwl_disable_ict, - }, .temp_ops = { .temperature = iwlagn_temperature, }, diff --git a/drivers/net/wireless/iwlwifi/iwl-2000.c b/drivers/net/wireless/iwlwifi/iwl-2000.c index d22e006..f602af4 100644 --- a/drivers/net/wireless/iwlwifi/iwl-2000.c +++ b/drivers/net/wireless/iwlwifi/iwl-2000.c @@ -292,13 +292,6 @@ static struct iwl_lib_ops iwl2000_lib = { .query_addr = iwlagn_eeprom_query_addr, .update_enhanced_txpower = iwlcore_eeprom_enhanced_txpower, }, - .isr_ops = { - .isr = iwl_isr_ict, - .free = iwl_free_isr_ict, - .alloc = iwl_alloc_isr_ict, - .reset = iwl_reset_ict, - .disable = iwl_disable_ict, - }, .temp_ops = { .temperature = iwlagn_temperature, }, diff --git a/drivers/net/wireless/iwlwifi/iwl-5000.c b/drivers/net/wireless/iwlwifi/iwl-5000.c index de0e86a..fb00464 100644 --- a/drivers/net/wireless/iwlwifi/iwl-5000.c +++ b/drivers/net/wireless/iwlwifi/iwl-5000.c @@ -378,13 +378,6 @@ static struct iwl_lib_ops iwl5000_lib = { .calib_version = iwlagn_eeprom_calib_version, .query_addr = iwlagn_eeprom_query_addr, }, - .isr_ops = { - .isr = iwl_isr_ict, - .free = iwl_free_isr_ict, - .alloc = iwl_alloc_isr_ict, - .reset = iwl_reset_ict, - .disable = iwl_disable_ict, - }, .temp_ops = { .temperature = iwlagn_temperature, }, @@ -440,13 +433,6 @@ static struct iwl_lib_ops iwl5150_lib = { .calib_version = iwlagn_eeprom_calib_version, .query_addr = iwlagn_eeprom_query_addr, }, - .isr_ops = { - .isr = iwl_isr_ict, - .free = iwl_free_isr_ict, - .alloc = iwl_alloc_isr_ict, - .reset = iwl_reset_ict, - .disable = iwl_disable_ict, - }, .temp_ops = { .temperature = iwl5150_temperature, }, diff --git a/drivers/net/wireless/iwlwifi/iwl-6000.c b/drivers/net/wireless/iwlwifi/iwl-6000.c index be2dbf7..24d105b 100644 --- a/drivers/net/wireless/iwlwifi/iwl-6000.c +++ b/drivers/net/wireless/iwlwifi/iwl-6000.c @@ -320,13 +320,6 @@ static struct iwl_lib_ops iwl6000_lib = { .query_addr = iwlagn_eeprom_query_addr, .update_enhanced_txpower = iwlcore_eeprom_enhanced_txpower, }, - .isr_ops = { - .isr = iwl_isr_ict, - .free = iwl_free_isr_ict, - .alloc = iwl_alloc_isr_ict, - .reset = iwl_reset_ict, - .disable = iwl_disable_ict, - }, .temp_ops = { .temperature = iwlagn_temperature, }, @@ -385,13 +378,6 @@ static struct iwl_lib_ops iwl6030_lib = { .query_addr = iwlagn_eeprom_query_addr, .update_enhanced_txpower = iwlcore_eeprom_enhanced_txpower, }, - .isr_ops = { - .isr = iwl_isr_ict, - .free = iwl_free_isr_ict, - .alloc = iwl_alloc_isr_ict, - .reset = iwl_reset_ict, - .disable = iwl_disable_ict, - }, .temp_ops = { .temperature = iwlagn_temperature, }, diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index 08bad17c..fd3aed8 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -2397,8 +2397,7 @@ static void __iwl_down(struct iwl_priv *priv) STATUS_EXIT_PENDING; /* device going down, Stop using ICT table */ - if (priv->cfg->ops->lib->isr_ops.disable) - priv->cfg->ops->lib->isr_ops.disable(priv); + iwl_disable_ict(priv); iwlagn_txq_ctx_stop(priv); iwlagn_rxq_stop(priv); @@ -2606,8 +2605,7 @@ static void iwl_bg_alive_start(struct work_struct *data) goto unlock; /* enable dram interrupt */ - if (priv->cfg->ops->lib->isr_ops.reset) - priv->cfg->ops->lib->isr_ops.reset(priv); + iwl_reset_ict(priv); iwl_alive_start(priv); unlock: @@ -3958,10 +3956,9 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) pci_enable_msi(priv->pci_dev); - if (priv->cfg->ops->lib->isr_ops.alloc) - priv->cfg->ops->lib->isr_ops.alloc(priv); + iwl_alloc_isr_ict(priv); - err = request_irq(priv->pci_dev->irq, priv->cfg->ops->lib->isr_ops.isr, + err = request_irq(priv->pci_dev->irq, iwl_isr_ict, IRQF_SHARED, DRV_NAME, priv); if (err) { IWL_ERR(priv, "Error allocating IRQ %d\n", priv->pci_dev->irq); @@ -4008,8 +4005,7 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) destroy_workqueue(priv->workqueue); priv->workqueue = NULL; free_irq(priv->pci_dev->irq, priv); - if (priv->cfg->ops->lib->isr_ops.free) - priv->cfg->ops->lib->isr_ops.free(priv); + iwl_free_isr_ict(priv); out_disable_msi: pci_disable_msi(priv->pci_dev); iwl_uninit_drv(priv); @@ -4107,8 +4103,7 @@ static void __devexit iwl_pci_remove(struct pci_dev *pdev) iwl_uninit_drv(priv); - if (priv->cfg->ops->lib->isr_ops.free) - priv->cfg->ops->lib->isr_ops.free(priv); + iwl_free_isr_ict(priv); dev_kfree_skb(priv->beacon_skb); diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h index ada76af..82939f8 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.h +++ b/drivers/net/wireless/iwlwifi/iwl-core.h @@ -122,14 +122,6 @@ struct iwl_apm_ops { void (*config)(struct iwl_priv *priv); }; -struct iwl_isr_ops { - irqreturn_t (*isr) (int irq, void *data); - void (*free)(struct iwl_priv *priv); - int (*alloc)(struct iwl_priv *priv); - int (*reset)(struct iwl_priv *priv); - void (*disable)(struct iwl_priv *priv); -}; - struct iwl_debugfs_ops { ssize_t (*rx_stats_read)(struct file *file, char __user *user_buf, size_t count, loff_t *ppos); @@ -194,9 +186,6 @@ struct iwl_lib_ops { int (*send_tx_power) (struct iwl_priv *priv); void (*update_chain_flags)(struct iwl_priv *priv); - /* isr */ - struct iwl_isr_ops isr_ops; - /* eeprom operations (as defined in iwl-eeprom.h) */ struct iwl_eeprom_ops eeprom_ops; -- cgit v0.10.2 From 02a7fa00a6d145037d549c779ad7692deb504acc Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 5 Apr 2011 09:42:12 -0700 Subject: iwlagn: move IO functions out of line This generates a massive reduction in module size: with debug: text data bss dec hex filename 670300 13136 420 683856 a6f50 iwlagn.ko (before) 388347 13136 408 401891 621e3 iwlagn.ko (after) without debug: text data bss dec hex filename 528575 13072 420 542067 84573 iwlagn.ko (before) 294192 13072 408 307672 4b1d8 iwlagn.ko (after) This also removes all the IO debug functionality since it can easily be replaced by tracing, and makes the code unnecessarily complex. I haven't done any CPU utilisation measurements, but given that the hotpaths don't use much IO it is not likely to have a negative impact; in fact, the size reduction will reduce cache pressure which possibly improves performance. Finally, an unused function or two were removed. Signed-off-by: Johannes Berg Signed-off-by: Wey-Yi Guy Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwlwifi/Makefile b/drivers/net/wireless/iwlwifi/Makefile index 9d6ee83..3652931 100644 --- a/drivers/net/wireless/iwlwifi/Makefile +++ b/drivers/net/wireless/iwlwifi/Makefile @@ -2,7 +2,7 @@ obj-$(CONFIG_IWLAGN) += iwlagn.o iwlagn-objs := iwl-agn.o iwl-agn-rs.o iwl-agn-led.o iwlagn-objs += iwl-agn-ucode.o iwl-agn-tx.o -iwlagn-objs += iwl-agn-lib.o iwl-agn-calib.o +iwlagn-objs += iwl-agn-lib.o iwl-agn-calib.o iwl-io.o iwlagn-objs += iwl-agn-tt.o iwl-agn-sta.o iwl-agn-eeprom.o iwlagn-objs += iwl-core.o iwl-eeprom.o iwl-hcmd.o iwl-power.o diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-eeprom.c b/drivers/net/wireless/iwlwifi/iwl-agn-eeprom.c index c6dd9b7..3bcaa10 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-eeprom.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-eeprom.c @@ -103,7 +103,7 @@ int iwlcore_eeprom_acquire_semaphore(struct iwl_priv *priv) CSR_HW_IF_CONFIG_REG_BIT_EEPROM_OWN_SEM, EEPROM_SEM_TIMEOUT); if (ret >= 0) { - IWL_DEBUG_IO(priv, + IWL_DEBUG_EEPROM(priv, "Acquired semaphore after %d tries.\n", count+1); return ret; diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-ucode.c b/drivers/net/wireless/iwlwifi/iwl-agn-ucode.c index 5187a2c..01a6d2f 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-ucode.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-ucode.c @@ -561,7 +561,7 @@ static int iwlcore_verify_inst_sparse(struct iwl_priv *priv, * if IWL_DL_IO is set */ iwl_write_direct32(priv, HBUS_TARG_MEM_RADDR, i + IWLAGN_RTC_INST_LOWER_BOUND); - val = _iwl_read_direct32(priv, HBUS_TARG_MEM_RDAT); + val = iwl_read32(priv, HBUS_TARG_MEM_RDAT); if (val != le32_to_cpu(*image)) return -EIO; } @@ -587,9 +587,7 @@ static void iwl_print_mismatch_inst(struct iwl_priv *priv, offs < len && errors < 20; offs += sizeof(u32), image++) { /* read data comes through single port, auto-incr addr */ - /* NOTE: Use the debugless read so we don't flood kernel log - * if IWL_DL_IO is set */ - val = _iwl_read_direct32(priv, HBUS_TARG_MEM_RDAT); + val = iwl_read32(priv, HBUS_TARG_MEM_RDAT); if (val != le32_to_cpu(*image)) { IWL_ERR(priv, "uCode INST section at " "offset 0x%x, is 0x%x, s/b 0x%x\n", diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index fd3aed8..60bfde7 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -558,7 +558,7 @@ static void iwl_print_cont_event_trace(struct iwl_priv *priv, u32 base, } /* Set starting address; reads will auto-increment */ - _iwl_write_direct32(priv, HBUS_TARG_MEM_RADDR, ptr); + iwl_write32(priv, HBUS_TARG_MEM_RADDR, ptr); rmb(); /* @@ -566,13 +566,13 @@ static void iwl_print_cont_event_trace(struct iwl_priv *priv, u32 base, * place event id # at far right for easier visual parsing. */ for (i = 0; i < num_events; i++) { - ev = _iwl_read_direct32(priv, HBUS_TARG_MEM_RDAT); - time = _iwl_read_direct32(priv, HBUS_TARG_MEM_RDAT); + ev = iwl_read32(priv, HBUS_TARG_MEM_RDAT); + time = iwl_read32(priv, HBUS_TARG_MEM_RDAT); if (mode == 0) { trace_iwlwifi_dev_ucode_cont_event(priv, 0, time, ev); } else { - data = _iwl_read_direct32(priv, HBUS_TARG_MEM_RDAT); + data = iwl_read32(priv, HBUS_TARG_MEM_RDAT); trace_iwlwifi_dev_ucode_cont_event(priv, time, data, ev); } @@ -1963,14 +1963,14 @@ static int iwl_print_event_log(struct iwl_priv *priv, u32 start_idx, iwl_grab_nic_access(priv); /* Set starting address; reads will auto-increment */ - _iwl_write_direct32(priv, HBUS_TARG_MEM_RADDR, ptr); + iwl_write32(priv, HBUS_TARG_MEM_RADDR, ptr); rmb(); /* "time" is actually "data" for mode 0 (no timestamp). * place event id # at far right for easier visual parsing. */ for (i = 0; i < num_events; i++) { - ev = _iwl_read_direct32(priv, HBUS_TARG_MEM_RDAT); - time = _iwl_read_direct32(priv, HBUS_TARG_MEM_RDAT); + ev = iwl_read32(priv, HBUS_TARG_MEM_RDAT); + time = iwl_read32(priv, HBUS_TARG_MEM_RDAT); if (mode == 0) { /* data, ev */ if (bufsz) { @@ -1984,7 +1984,7 @@ static int iwl_print_event_log(struct iwl_priv *priv, u32 start_idx, time, ev); } } else { - data = _iwl_read_direct32(priv, HBUS_TARG_MEM_RDAT); + data = iwl_read32(priv, HBUS_TARG_MEM_RDAT); if (bufsz) { pos += scnprintf(*buf + pos, bufsz - pos, "EVT_LOGT:%010u:0x%08x:%04u\n", @@ -3689,7 +3689,7 @@ static u32 iwl_hw_detect(struct iwl_priv *priv) pci_read_config_byte(priv->pci_dev, PCI_REVISION_ID, &rev_id); IWL_DEBUG_INFO(priv, "HW Revision ID = 0x%X\n", rev_id); - return _iwl_read32(priv, CSR_HW_REV); + return iwl_read32(priv, CSR_HW_REV); } static int iwl_set_hw_params(struct iwl_priv *priv) diff --git a/drivers/net/wireless/iwlwifi/iwl-debug.h b/drivers/net/wireless/iwlwifi/iwl-debug.h index 8489431..2824ccb 100644 --- a/drivers/net/wireless/iwlwifi/iwl-debug.h +++ b/drivers/net/wireless/iwlwifi/iwl-debug.h @@ -146,7 +146,6 @@ static inline void iwl_dbgfs_unregister(struct iwl_priv *priv) #define IWL_DL_RX (1 << 24) #define IWL_DL_ISR (1 << 25) #define IWL_DL_HT (1 << 26) -#define IWL_DL_IO (1 << 27) /* 0xF0000000 - 0x10000000 */ #define IWL_DL_11H (1 << 28) #define IWL_DL_STATS (1 << 29) @@ -174,7 +173,6 @@ static inline void iwl_dbgfs_unregister(struct iwl_priv *priv) IWL_DEBUG_LIMIT(p, IWL_DL_DROP, f, ## a) #define IWL_DEBUG_AP(p, f, a...) IWL_DEBUG(p, IWL_DL_AP, f, ## a) #define IWL_DEBUG_TXPOWER(p, f, a...) IWL_DEBUG(p, IWL_DL_TXPOWER, f, ## a) -#define IWL_DEBUG_IO(p, f, a...) IWL_DEBUG(p, IWL_DL_IO, f, ## a) #define IWL_DEBUG_RATE(p, f, a...) IWL_DEBUG(p, IWL_DL_RATE, f, ## a) #define IWL_DEBUG_RATE_LIMIT(p, f, a...) \ IWL_DEBUG_LIMIT(p, IWL_DL_RATE, f, ## a) diff --git a/drivers/net/wireless/iwlwifi/iwl-eeprom.c b/drivers/net/wireless/iwlwifi/iwl-eeprom.c index 4f8c13e..859b94a 100644 --- a/drivers/net/wireless/iwlwifi/iwl-eeprom.c +++ b/drivers/net/wireless/iwlwifi/iwl-eeprom.c @@ -226,15 +226,15 @@ static int iwl_init_otp_access(struct iwl_priv *priv) int ret; /* Enable 40MHz radio clock */ - _iwl_write32(priv, CSR_GP_CNTRL, - _iwl_read32(priv, CSR_GP_CNTRL) | - CSR_GP_CNTRL_REG_FLAG_INIT_DONE); + iwl_write32(priv, CSR_GP_CNTRL, + iwl_read32(priv, CSR_GP_CNTRL) | + CSR_GP_CNTRL_REG_FLAG_INIT_DONE); /* wait for clock to be ready */ ret = iwl_poll_bit(priv, CSR_GP_CNTRL, - CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, - CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, - 25000); + CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, + CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, + 25000); if (ret < 0) IWL_ERR(priv, "Time out access OTP\n"); else { @@ -261,17 +261,17 @@ static int iwl_read_otp_word(struct iwl_priv *priv, u16 addr, __le16 *eeprom_dat u32 r; u32 otpgp; - _iwl_write32(priv, CSR_EEPROM_REG, - CSR_EEPROM_REG_MSK_ADDR & (addr << 1)); + iwl_write32(priv, CSR_EEPROM_REG, + CSR_EEPROM_REG_MSK_ADDR & (addr << 1)); ret = iwl_poll_bit(priv, CSR_EEPROM_REG, - CSR_EEPROM_REG_READ_VALID_MSK, - CSR_EEPROM_REG_READ_VALID_MSK, - IWL_EEPROM_ACCESS_TIMEOUT); + CSR_EEPROM_REG_READ_VALID_MSK, + CSR_EEPROM_REG_READ_VALID_MSK, + IWL_EEPROM_ACCESS_TIMEOUT); if (ret < 0) { IWL_ERR(priv, "Time out reading OTP[%d]\n", addr); return ret; } - r = _iwl_read_direct32(priv, CSR_EEPROM_REG); + r = iwl_read32(priv, CSR_EEPROM_REG); /* check for ECC errors: */ otpgp = iwl_read32(priv, CSR_OTP_GP_REG); if (otpgp & CSR_OTP_GP_REG_ECC_UNCORR_STATUS_MSK) { @@ -442,9 +442,9 @@ int iwl_eeprom_init(struct iwl_priv *priv, u32 hw_rev) ret = -ENOENT; goto done; } - _iwl_write32(priv, CSR_EEPROM_GP, - iwl_read32(priv, CSR_EEPROM_GP) & - ~CSR_EEPROM_GP_IF_OWNER_MSK); + iwl_write32(priv, CSR_EEPROM_GP, + iwl_read32(priv, CSR_EEPROM_GP) & + ~CSR_EEPROM_GP_IF_OWNER_MSK); iwl_set_bit(priv, CSR_OTP_GP_REG, CSR_OTP_GP_REG_ECC_CORR_STATUS_MSK | @@ -471,8 +471,8 @@ int iwl_eeprom_init(struct iwl_priv *priv, u32 hw_rev) for (addr = 0; addr < sz; addr += sizeof(u16)) { u32 r; - _iwl_write32(priv, CSR_EEPROM_REG, - CSR_EEPROM_REG_MSK_ADDR & (addr << 1)); + iwl_write32(priv, CSR_EEPROM_REG, + CSR_EEPROM_REG_MSK_ADDR & (addr << 1)); ret = iwl_poll_bit(priv, CSR_EEPROM_REG, CSR_EEPROM_REG_READ_VALID_MSK, @@ -482,7 +482,7 @@ int iwl_eeprom_init(struct iwl_priv *priv, u32 hw_rev) IWL_ERR(priv, "Time out reading EEPROM[%d]\n", addr); goto done; } - r = _iwl_read_direct32(priv, CSR_EEPROM_REG); + r = iwl_read32(priv, CSR_EEPROM_REG); e[addr / 2] = cpu_to_le16(r >> 16); } } diff --git a/drivers/net/wireless/iwlwifi/iwl-io.c b/drivers/net/wireless/iwlwifi/iwl-io.c new file mode 100644 index 0000000..5133741 --- /dev/null +++ b/drivers/net/wireless/iwlwifi/iwl-io.c @@ -0,0 +1,274 @@ +/****************************************************************************** + * + * Copyright(c) 2003 - 2011 Intel Corporation. All rights reserved. + * + * Portions of this file are derived from the ipw3945 project. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * Intel Linux Wireless + * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + * + *****************************************************************************/ + +#include "iwl-io.h" + +#define IWL_POLL_INTERVAL 10 /* microseconds */ + +static inline void __iwl_set_bit(struct iwl_priv *priv, u32 reg, u32 mask) +{ + iwl_write32(priv, reg, iwl_read32(priv, reg) | mask); +} + +static inline void __iwl_clear_bit(struct iwl_priv *priv, u32 reg, u32 mask) +{ + iwl_write32(priv, reg, iwl_read32(priv, reg) & ~mask); +} + +void iwl_set_bit(struct iwl_priv *priv, u32 reg, u32 mask) +{ + unsigned long flags; + + spin_lock_irqsave(&priv->reg_lock, flags); + __iwl_set_bit(priv, reg, mask); + spin_unlock_irqrestore(&priv->reg_lock, flags); +} + +void iwl_clear_bit(struct iwl_priv *priv, u32 reg, u32 mask) +{ + unsigned long flags; + + spin_lock_irqsave(&priv->reg_lock, flags); + __iwl_clear_bit(priv, reg, mask); + spin_unlock_irqrestore(&priv->reg_lock, flags); +} + +int iwl_poll_bit(struct iwl_priv *priv, u32 addr, + u32 bits, u32 mask, int timeout) +{ + int t = 0; + + do { + if ((iwl_read32(priv, addr) & mask) == (bits & mask)) + return t; + udelay(IWL_POLL_INTERVAL); + t += IWL_POLL_INTERVAL; + } while (t < timeout); + + return -ETIMEDOUT; +} + +int iwl_grab_nic_access(struct iwl_priv *priv) +{ + int ret; + u32 val; + + lockdep_assert_held(&priv->reg_lock); + + /* this bit wakes up the NIC */ + __iwl_set_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ); + + /* + * These bits say the device is running, and should keep running for + * at least a short while (at least as long as MAC_ACCESS_REQ stays 1), + * but they do not indicate that embedded SRAM is restored yet; + * 3945 and 4965 have volatile SRAM, and must save/restore contents + * to/from host DRAM when sleeping/waking for power-saving. + * Each direction takes approximately 1/4 millisecond; with this + * overhead, it's a good idea to grab and hold MAC_ACCESS_REQUEST if a + * series of register accesses are expected (e.g. reading Event Log), + * to keep device from sleeping. + * + * CSR_UCODE_DRV_GP1 register bit MAC_SLEEP == 0 indicates that + * SRAM is okay/restored. We don't check that here because this call + * is just for hardware register access; but GP1 MAC_SLEEP check is a + * good idea before accessing 3945/4965 SRAM (e.g. reading Event Log). + * + * 5000 series and later (including 1000 series) have non-volatile SRAM, + * and do not save/restore SRAM when power cycling. + */ + ret = iwl_poll_bit(priv, CSR_GP_CNTRL, + CSR_GP_CNTRL_REG_VAL_MAC_ACCESS_EN, + (CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY | + CSR_GP_CNTRL_REG_FLAG_GOING_TO_SLEEP), 15000); + if (ret < 0) { + val = iwl_read32(priv, CSR_GP_CNTRL); + IWL_ERR(priv, + "MAC is in deep sleep!. CSR_GP_CNTRL = 0x%08X\n", val); + iwl_write32(priv, CSR_RESET, CSR_RESET_REG_FLAG_FORCE_NMI); + return -EIO; + } + + return 0; +} + +void iwl_release_nic_access(struct iwl_priv *priv) +{ + lockdep_assert_held(&priv->reg_lock); + __iwl_clear_bit(priv, CSR_GP_CNTRL, + CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ); +} + +u32 iwl_read_direct32(struct iwl_priv *priv, u32 reg) +{ + u32 value; + unsigned long flags; + + spin_lock_irqsave(&priv->reg_lock, flags); + iwl_grab_nic_access(priv); + value = iwl_read32(priv, reg); + iwl_release_nic_access(priv); + spin_unlock_irqrestore(&priv->reg_lock, flags); + + return value; +} + +void iwl_write_direct32(struct iwl_priv *priv, u32 reg, u32 value) +{ + unsigned long flags; + + spin_lock_irqsave(&priv->reg_lock, flags); + if (!iwl_grab_nic_access(priv)) { + iwl_write32(priv, reg, value); + iwl_release_nic_access(priv); + } + spin_unlock_irqrestore(&priv->reg_lock, flags); +} + +int iwl_poll_direct_bit(struct iwl_priv *priv, u32 addr, u32 mask, + int timeout) +{ + int t = 0; + + do { + if ((iwl_read_direct32(priv, addr) & mask) == mask) + return t; + udelay(IWL_POLL_INTERVAL); + t += IWL_POLL_INTERVAL; + } while (t < timeout); + + return -ETIMEDOUT; +} + +static inline u32 __iwl_read_prph(struct iwl_priv *priv, u32 reg) +{ + iwl_write32(priv, HBUS_TARG_PRPH_RADDR, reg | (3 << 24)); + rmb(); + return iwl_read32(priv, HBUS_TARG_PRPH_RDAT); +} + +static inline void __iwl_write_prph(struct iwl_priv *priv, u32 addr, u32 val) +{ + iwl_write32(priv, HBUS_TARG_PRPH_WADDR, + ((addr & 0x0000FFFF) | (3 << 24))); + wmb(); + iwl_write32(priv, HBUS_TARG_PRPH_WDAT, val); +} + +u32 iwl_read_prph(struct iwl_priv *priv, u32 reg) +{ + unsigned long flags; + u32 val; + + spin_lock_irqsave(&priv->reg_lock, flags); + iwl_grab_nic_access(priv); + val = __iwl_read_prph(priv, reg); + iwl_release_nic_access(priv); + spin_unlock_irqrestore(&priv->reg_lock, flags); + return val; +} + +void iwl_write_prph(struct iwl_priv *priv, u32 addr, u32 val) +{ + unsigned long flags; + + spin_lock_irqsave(&priv->reg_lock, flags); + if (!iwl_grab_nic_access(priv)) { + __iwl_write_prph(priv, addr, val); + iwl_release_nic_access(priv); + } + spin_unlock_irqrestore(&priv->reg_lock, flags); +} + +void iwl_set_bits_prph(struct iwl_priv *priv, u32 reg, u32 mask) +{ + unsigned long flags; + + spin_lock_irqsave(&priv->reg_lock, flags); + iwl_grab_nic_access(priv); + __iwl_write_prph(priv, reg, __iwl_read_prph(priv, reg) | mask); + iwl_release_nic_access(priv); + spin_unlock_irqrestore(&priv->reg_lock, flags); +} + +void iwl_set_bits_mask_prph(struct iwl_priv *priv, u32 reg, + u32 bits, u32 mask) +{ + unsigned long flags; + + spin_lock_irqsave(&priv->reg_lock, flags); + iwl_grab_nic_access(priv); + __iwl_write_prph(priv, reg, + (__iwl_read_prph(priv, reg) & mask) | bits); + iwl_release_nic_access(priv); + spin_unlock_irqrestore(&priv->reg_lock, flags); +} + +void iwl_clear_bits_prph(struct iwl_priv *priv, u32 reg, u32 mask) +{ + unsigned long flags; + u32 val; + + spin_lock_irqsave(&priv->reg_lock, flags); + iwl_grab_nic_access(priv); + val = __iwl_read_prph(priv, reg); + __iwl_write_prph(priv, reg, (val & ~mask)); + iwl_release_nic_access(priv); + spin_unlock_irqrestore(&priv->reg_lock, flags); +} + +u32 iwl_read_targ_mem(struct iwl_priv *priv, u32 addr) +{ + unsigned long flags; + u32 value; + + spin_lock_irqsave(&priv->reg_lock, flags); + iwl_grab_nic_access(priv); + + iwl_write32(priv, HBUS_TARG_MEM_RADDR, addr); + rmb(); + value = iwl_read32(priv, HBUS_TARG_MEM_RDAT); + + iwl_release_nic_access(priv); + spin_unlock_irqrestore(&priv->reg_lock, flags); + return value; +} + +void iwl_write_targ_mem(struct iwl_priv *priv, u32 addr, u32 val) +{ + unsigned long flags; + + spin_lock_irqsave(&priv->reg_lock, flags); + if (!iwl_grab_nic_access(priv)) { + iwl_write32(priv, HBUS_TARG_MEM_WADDR, addr); + wmb(); + iwl_write32(priv, HBUS_TARG_MEM_WDAT, val); + iwl_release_nic_access(priv); + } + spin_unlock_irqrestore(&priv->reg_lock, flags); +} diff --git a/drivers/net/wireless/iwlwifi/iwl-io.h b/drivers/net/wireless/iwlwifi/iwl-io.h index 3ddb2fb..ab632ba 100644 --- a/drivers/net/wireless/iwlwifi/iwl-io.h +++ b/drivers/net/wireless/iwlwifi/iwl-io.h @@ -35,494 +35,47 @@ #include "iwl-debug.h" #include "iwl-devtrace.h" -/* - * IO, register, and NIC memory access functions - * - * NOTE on naming convention and macro usage for these - * - * A single _ prefix before a an access function means that no state - * check or debug information is printed when that function is called. - * - * A double __ prefix before an access function means that state is checked - * and the current line number and caller function name are printed in addition - * to any other debug output. - * - * The non-prefixed name is the #define that maps the caller into a - * #define that provides the caller's name and __LINE__ to the double - * prefix version. - * - * If you wish to call the function without any debug or state checking, - * you should use the single _ prefix version (as is used by dependent IO - * routines, for example _iwl_read_direct32 calls the non-check version of - * _iwl_read32.) - * - * These declarations are *extremely* useful in quickly isolating code deltas - * which result in misconfiguration of the hardware I/O. In combination with - * git-bisect and the IO debug level you can quickly determine the specific - * commit which breaks the IO sequence to the hardware. - * - */ - -static inline void _iwl_write8(struct iwl_priv *priv, u32 ofs, u8 val) +static inline void iwl_write8(struct iwl_priv *priv, u32 ofs, u8 val) { trace_iwlwifi_dev_iowrite8(priv, ofs, val); iowrite8(val, priv->hw_base + ofs); } -#ifdef CONFIG_IWLWIFI_DEBUG -static inline void __iwl_write8(const char *f, u32 l, struct iwl_priv *priv, - u32 ofs, u8 val) -{ - IWL_DEBUG_IO(priv, "write8(0x%08X, 0x%02X) - %s %d\n", ofs, val, f, l); - _iwl_write8(priv, ofs, val); -} -#define iwl_write8(priv, ofs, val) \ - __iwl_write8(__FILE__, __LINE__, priv, ofs, val) -#else -#define iwl_write8(priv, ofs, val) _iwl_write8(priv, ofs, val) -#endif - - -static inline void _iwl_write32(struct iwl_priv *priv, u32 ofs, u32 val) +static inline void iwl_write32(struct iwl_priv *priv, u32 ofs, u32 val) { trace_iwlwifi_dev_iowrite32(priv, ofs, val); iowrite32(val, priv->hw_base + ofs); } -#ifdef CONFIG_IWLWIFI_DEBUG -static inline void __iwl_write32(const char *f, u32 l, struct iwl_priv *priv, - u32 ofs, u32 val) -{ - IWL_DEBUG_IO(priv, "write32(0x%08X, 0x%08X) - %s %d\n", ofs, val, f, l); - _iwl_write32(priv, ofs, val); -} -#define iwl_write32(priv, ofs, val) \ - __iwl_write32(__FILE__, __LINE__, priv, ofs, val) -#else -#define iwl_write32(priv, ofs, val) _iwl_write32(priv, ofs, val) -#endif - -static inline u32 _iwl_read32(struct iwl_priv *priv, u32 ofs) +static inline u32 iwl_read32(struct iwl_priv *priv, u32 ofs) { u32 val = ioread32(priv->hw_base + ofs); trace_iwlwifi_dev_ioread32(priv, ofs, val); return val; } -#ifdef CONFIG_IWLWIFI_DEBUG -static inline u32 __iwl_read32(char *f, u32 l, struct iwl_priv *priv, u32 ofs) -{ - IWL_DEBUG_IO(priv, "read_direct32(0x%08X) - %s %d\n", ofs, f, l); - return _iwl_read32(priv, ofs); -} -#define iwl_read32(priv, ofs) __iwl_read32(__FILE__, __LINE__, priv, ofs) -#else -#define iwl_read32(p, o) _iwl_read32(p, o) -#endif - -#define IWL_POLL_INTERVAL 10 /* microseconds */ -static inline int _iwl_poll_bit(struct iwl_priv *priv, u32 addr, - u32 bits, u32 mask, int timeout) -{ - int t = 0; - - do { - if ((_iwl_read32(priv, addr) & mask) == (bits & mask)) - return t; - udelay(IWL_POLL_INTERVAL); - t += IWL_POLL_INTERVAL; - } while (t < timeout); - - return -ETIMEDOUT; -} -#ifdef CONFIG_IWLWIFI_DEBUG -static inline int __iwl_poll_bit(const char *f, u32 l, - struct iwl_priv *priv, u32 addr, - u32 bits, u32 mask, int timeout) -{ - int ret = _iwl_poll_bit(priv, addr, bits, mask, timeout); - IWL_DEBUG_IO(priv, "poll_bit(0x%08X, 0x%08X, 0x%08X) - %s- %s %d\n", - addr, bits, mask, - unlikely(ret == -ETIMEDOUT) ? "timeout" : "", f, l); - return ret; -} -#define iwl_poll_bit(priv, addr, bits, mask, timeout) \ - __iwl_poll_bit(__FILE__, __LINE__, priv, addr, bits, mask, timeout) -#else -#define iwl_poll_bit(p, a, b, m, t) _iwl_poll_bit(p, a, b, m, t) -#endif - -static inline void _iwl_set_bit(struct iwl_priv *priv, u32 reg, u32 mask) -{ - _iwl_write32(priv, reg, _iwl_read32(priv, reg) | mask); -} -#ifdef CONFIG_IWLWIFI_DEBUG -static inline void __iwl_set_bit(const char *f, u32 l, - struct iwl_priv *priv, u32 reg, u32 mask) -{ - u32 val = _iwl_read32(priv, reg) | mask; - IWL_DEBUG_IO(priv, "set_bit(0x%08X, 0x%08X) = 0x%08X\n", reg, mask, val); - _iwl_write32(priv, reg, val); -} -static inline void iwl_set_bit(struct iwl_priv *p, u32 r, u32 m) -{ - unsigned long reg_flags; - - spin_lock_irqsave(&p->reg_lock, reg_flags); - __iwl_set_bit(__FILE__, __LINE__, p, r, m); - spin_unlock_irqrestore(&p->reg_lock, reg_flags); -} -#else -static inline void iwl_set_bit(struct iwl_priv *p, u32 r, u32 m) -{ - unsigned long reg_flags; - - spin_lock_irqsave(&p->reg_lock, reg_flags); - _iwl_set_bit(p, r, m); - spin_unlock_irqrestore(&p->reg_lock, reg_flags); -} -#endif - -static inline void _iwl_clear_bit(struct iwl_priv *priv, u32 reg, u32 mask) -{ - _iwl_write32(priv, reg, _iwl_read32(priv, reg) & ~mask); -} -#ifdef CONFIG_IWLWIFI_DEBUG -static inline void __iwl_clear_bit(const char *f, u32 l, - struct iwl_priv *priv, u32 reg, u32 mask) -{ - u32 val = _iwl_read32(priv, reg) & ~mask; - IWL_DEBUG_IO(priv, "clear_bit(0x%08X, 0x%08X) = 0x%08X\n", reg, mask, val); - _iwl_write32(priv, reg, val); -} -static inline void iwl_clear_bit(struct iwl_priv *p, u32 r, u32 m) -{ - unsigned long reg_flags; - - spin_lock_irqsave(&p->reg_lock, reg_flags); - __iwl_clear_bit(__FILE__, __LINE__, p, r, m); - spin_unlock_irqrestore(&p->reg_lock, reg_flags); -} -#else -static inline void iwl_clear_bit(struct iwl_priv *p, u32 r, u32 m) -{ - unsigned long reg_flags; - - spin_lock_irqsave(&p->reg_lock, reg_flags); - _iwl_clear_bit(p, r, m); - spin_unlock_irqrestore(&p->reg_lock, reg_flags); -} -#endif - -static inline int _iwl_grab_nic_access(struct iwl_priv *priv) -{ - int ret; - u32 val; - - /* this bit wakes up the NIC */ - _iwl_set_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ); - - /* - * These bits say the device is running, and should keep running for - * at least a short while (at least as long as MAC_ACCESS_REQ stays 1), - * but they do not indicate that embedded SRAM is restored yet; - * 3945 and 4965 have volatile SRAM, and must save/restore contents - * to/from host DRAM when sleeping/waking for power-saving. - * Each direction takes approximately 1/4 millisecond; with this - * overhead, it's a good idea to grab and hold MAC_ACCESS_REQUEST if a - * series of register accesses are expected (e.g. reading Event Log), - * to keep device from sleeping. - * - * CSR_UCODE_DRV_GP1 register bit MAC_SLEEP == 0 indicates that - * SRAM is okay/restored. We don't check that here because this call - * is just for hardware register access; but GP1 MAC_SLEEP check is a - * good idea before accessing 3945/4965 SRAM (e.g. reading Event Log). - * - * 5000 series and later (including 1000 series) have non-volatile SRAM, - * and do not save/restore SRAM when power cycling. - */ - ret = _iwl_poll_bit(priv, CSR_GP_CNTRL, - CSR_GP_CNTRL_REG_VAL_MAC_ACCESS_EN, - (CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY | - CSR_GP_CNTRL_REG_FLAG_GOING_TO_SLEEP), 15000); - if (ret < 0) { - val = _iwl_read32(priv, CSR_GP_CNTRL); - IWL_ERR(priv, "MAC is in deep sleep!. CSR_GP_CNTRL = 0x%08X\n", val); - _iwl_write32(priv, CSR_RESET, CSR_RESET_REG_FLAG_FORCE_NMI); - return -EIO; - } - - return 0; -} - -#ifdef CONFIG_IWLWIFI_DEBUG -static inline int __iwl_grab_nic_access(const char *f, u32 l, - struct iwl_priv *priv) -{ - IWL_DEBUG_IO(priv, "grabbing nic access - %s %d\n", f, l); - return _iwl_grab_nic_access(priv); -} -#define iwl_grab_nic_access(priv) \ - __iwl_grab_nic_access(__FILE__, __LINE__, priv) -#else -#define iwl_grab_nic_access(priv) \ - _iwl_grab_nic_access(priv) -#endif - -static inline void _iwl_release_nic_access(struct iwl_priv *priv) -{ - _iwl_clear_bit(priv, CSR_GP_CNTRL, - CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ); -} -#ifdef CONFIG_IWLWIFI_DEBUG -static inline void __iwl_release_nic_access(const char *f, u32 l, - struct iwl_priv *priv) -{ - - IWL_DEBUG_IO(priv, "releasing nic access - %s %d\n", f, l); - _iwl_release_nic_access(priv); -} -#define iwl_release_nic_access(priv) \ - __iwl_release_nic_access(__FILE__, __LINE__, priv) -#else -#define iwl_release_nic_access(priv) \ - _iwl_release_nic_access(priv) -#endif - -static inline u32 _iwl_read_direct32(struct iwl_priv *priv, u32 reg) -{ - return _iwl_read32(priv, reg); -} -#ifdef CONFIG_IWLWIFI_DEBUG -static inline u32 __iwl_read_direct32(const char *f, u32 l, - struct iwl_priv *priv, u32 reg) -{ - u32 value = _iwl_read_direct32(priv, reg); - IWL_DEBUG_IO(priv, "read_direct32(0x%4X) = 0x%08x - %s %d\n", reg, value, - f, l); - return value; -} -static inline u32 iwl_read_direct32(struct iwl_priv *priv, u32 reg) -{ - u32 value; - unsigned long reg_flags; - - spin_lock_irqsave(&priv->reg_lock, reg_flags); - iwl_grab_nic_access(priv); - value = __iwl_read_direct32(__FILE__, __LINE__, priv, reg); - iwl_release_nic_access(priv); - spin_unlock_irqrestore(&priv->reg_lock, reg_flags); - return value; -} - -#else -static inline u32 iwl_read_direct32(struct iwl_priv *priv, u32 reg) -{ - u32 value; - unsigned long reg_flags; - - spin_lock_irqsave(&priv->reg_lock, reg_flags); - iwl_grab_nic_access(priv); - value = _iwl_read_direct32(priv, reg); - iwl_release_nic_access(priv); - spin_unlock_irqrestore(&priv->reg_lock, reg_flags); - return value; - -} -#endif - -static inline void _iwl_write_direct32(struct iwl_priv *priv, - u32 reg, u32 value) -{ - _iwl_write32(priv, reg, value); -} -static inline void iwl_write_direct32(struct iwl_priv *priv, u32 reg, u32 value) -{ - unsigned long reg_flags; - - spin_lock_irqsave(&priv->reg_lock, reg_flags); - if (!iwl_grab_nic_access(priv)) { - _iwl_write_direct32(priv, reg, value); - iwl_release_nic_access(priv); - } - spin_unlock_irqrestore(&priv->reg_lock, reg_flags); -} - -static inline void iwl_write_reg_buf(struct iwl_priv *priv, - u32 reg, u32 len, u32 *values) -{ - u32 count = sizeof(u32); - - if ((priv != NULL) && (values != NULL)) { - for (; 0 < len; len -= count, reg += count, values++) - iwl_write_direct32(priv, reg, *values); - } -} - -static inline int _iwl_poll_direct_bit(struct iwl_priv *priv, u32 addr, - u32 mask, int timeout) -{ - int t = 0; - - do { - if ((iwl_read_direct32(priv, addr) & mask) == mask) - return t; - udelay(IWL_POLL_INTERVAL); - t += IWL_POLL_INTERVAL; - } while (t < timeout); - - return -ETIMEDOUT; -} - -#ifdef CONFIG_IWLWIFI_DEBUG -static inline int __iwl_poll_direct_bit(const char *f, u32 l, - struct iwl_priv *priv, - u32 addr, u32 mask, int timeout) -{ - int ret = _iwl_poll_direct_bit(priv, addr, mask, timeout); - - if (unlikely(ret == -ETIMEDOUT)) - IWL_DEBUG_IO(priv, "poll_direct_bit(0x%08X, 0x%08X) - " - "timedout - %s %d\n", addr, mask, f, l); - else - IWL_DEBUG_IO(priv, "poll_direct_bit(0x%08X, 0x%08X) = 0x%08X " - "- %s %d\n", addr, mask, ret, f, l); - return ret; -} -#define iwl_poll_direct_bit(priv, addr, mask, timeout) \ - __iwl_poll_direct_bit(__FILE__, __LINE__, priv, addr, mask, timeout) -#else -#define iwl_poll_direct_bit _iwl_poll_direct_bit -#endif - -static inline u32 _iwl_read_prph(struct iwl_priv *priv, u32 reg) -{ - _iwl_write_direct32(priv, HBUS_TARG_PRPH_RADDR, reg | (3 << 24)); - rmb(); - return _iwl_read_direct32(priv, HBUS_TARG_PRPH_RDAT); -} -static inline u32 iwl_read_prph(struct iwl_priv *priv, u32 reg) -{ - unsigned long reg_flags; - u32 val; - - spin_lock_irqsave(&priv->reg_lock, reg_flags); - iwl_grab_nic_access(priv); - val = _iwl_read_prph(priv, reg); - iwl_release_nic_access(priv); - spin_unlock_irqrestore(&priv->reg_lock, reg_flags); - return val; -} - -static inline void _iwl_write_prph(struct iwl_priv *priv, - u32 addr, u32 val) -{ - _iwl_write_direct32(priv, HBUS_TARG_PRPH_WADDR, - ((addr & 0x0000FFFF) | (3 << 24))); - wmb(); - _iwl_write_direct32(priv, HBUS_TARG_PRPH_WDAT, val); -} - -static inline void iwl_write_prph(struct iwl_priv *priv, u32 addr, u32 val) -{ - unsigned long reg_flags; +void iwl_set_bit(struct iwl_priv *priv, u32 reg, u32 mask); +void iwl_clear_bit(struct iwl_priv *priv, u32 reg, u32 mask); - spin_lock_irqsave(&priv->reg_lock, reg_flags); - if (!iwl_grab_nic_access(priv)) { - _iwl_write_prph(priv, addr, val); - iwl_release_nic_access(priv); - } - spin_unlock_irqrestore(&priv->reg_lock, reg_flags); -} +int iwl_poll_bit(struct iwl_priv *priv, u32 addr, + u32 bits, u32 mask, int timeout); +int iwl_poll_direct_bit(struct iwl_priv *priv, u32 addr, u32 mask, + int timeout); -#define _iwl_set_bits_prph(priv, reg, mask) \ - _iwl_write_prph(priv, reg, (_iwl_read_prph(priv, reg) | mask)) +int iwl_grab_nic_access(struct iwl_priv *priv); +void iwl_release_nic_access(struct iwl_priv *priv); -static inline void iwl_set_bits_prph(struct iwl_priv *priv, u32 reg, u32 mask) -{ - unsigned long reg_flags; +u32 iwl_read_direct32(struct iwl_priv *priv, u32 reg); +void iwl_write_direct32(struct iwl_priv *priv, u32 reg, u32 value); - spin_lock_irqsave(&priv->reg_lock, reg_flags); - iwl_grab_nic_access(priv); - _iwl_set_bits_prph(priv, reg, mask); - iwl_release_nic_access(priv); - spin_unlock_irqrestore(&priv->reg_lock, reg_flags); -} -#define _iwl_set_bits_mask_prph(priv, reg, bits, mask) \ - _iwl_write_prph(priv, reg, ((_iwl_read_prph(priv, reg) & mask) | bits)) +u32 iwl_read_prph(struct iwl_priv *priv, u32 reg); +void iwl_write_prph(struct iwl_priv *priv, u32 addr, u32 val); +void iwl_set_bits_prph(struct iwl_priv *priv, u32 reg, u32 mask); +void iwl_set_bits_mask_prph(struct iwl_priv *priv, u32 reg, + u32 bits, u32 mask); +void iwl_clear_bits_prph(struct iwl_priv *priv, u32 reg, u32 mask); -static inline void iwl_set_bits_mask_prph(struct iwl_priv *priv, u32 reg, - u32 bits, u32 mask) -{ - unsigned long reg_flags; - - spin_lock_irqsave(&priv->reg_lock, reg_flags); - iwl_grab_nic_access(priv); - _iwl_set_bits_mask_prph(priv, reg, bits, mask); - iwl_release_nic_access(priv); - spin_unlock_irqrestore(&priv->reg_lock, reg_flags); -} - -static inline void iwl_clear_bits_prph(struct iwl_priv - *priv, u32 reg, u32 mask) -{ - unsigned long reg_flags; - u32 val; - - spin_lock_irqsave(&priv->reg_lock, reg_flags); - iwl_grab_nic_access(priv); - val = _iwl_read_prph(priv, reg); - _iwl_write_prph(priv, reg, (val & ~mask)); - iwl_release_nic_access(priv); - spin_unlock_irqrestore(&priv->reg_lock, reg_flags); -} - -static inline u32 iwl_read_targ_mem(struct iwl_priv *priv, u32 addr) -{ - unsigned long reg_flags; - u32 value; - - spin_lock_irqsave(&priv->reg_lock, reg_flags); - iwl_grab_nic_access(priv); - - _iwl_write_direct32(priv, HBUS_TARG_MEM_RADDR, addr); - rmb(); - value = _iwl_read_direct32(priv, HBUS_TARG_MEM_RDAT); - - iwl_release_nic_access(priv); - spin_unlock_irqrestore(&priv->reg_lock, reg_flags); - return value; -} - -static inline void iwl_write_targ_mem(struct iwl_priv *priv, u32 addr, u32 val) -{ - unsigned long reg_flags; - - spin_lock_irqsave(&priv->reg_lock, reg_flags); - if (!iwl_grab_nic_access(priv)) { - _iwl_write_direct32(priv, HBUS_TARG_MEM_WADDR, addr); - wmb(); - _iwl_write_direct32(priv, HBUS_TARG_MEM_WDAT, val); - iwl_release_nic_access(priv); - } - spin_unlock_irqrestore(&priv->reg_lock, reg_flags); -} - -static inline void iwl_write_targ_mem_buf(struct iwl_priv *priv, u32 addr, - u32 len, u32 *values) -{ - unsigned long reg_flags; - - spin_lock_irqsave(&priv->reg_lock, reg_flags); - if (!iwl_grab_nic_access(priv)) { - _iwl_write_direct32(priv, HBUS_TARG_MEM_WADDR, addr); - wmb(); - for (; 0 < len; len -= sizeof(u32), values++) - _iwl_write_direct32(priv, HBUS_TARG_MEM_WDAT, *values); - - iwl_release_nic_access(priv); - } - spin_unlock_irqrestore(&priv->reg_lock, reg_flags); -} +u32 iwl_read_targ_mem(struct iwl_priv *priv, u32 addr); +void iwl_write_targ_mem(struct iwl_priv *priv, u32 addr, u32 val); #endif -- cgit v0.10.2 From 146095557b01cf5ff5d66554d96cbb8133d94eb9 Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Tue, 5 Apr 2011 10:49:03 -0700 Subject: cfg80211: fix regulatory restore upon user hints When we restore regulatory settings its possible CRDA will not reply because of a bogus user entry. In this case the bogus entry will prevent any further processing on cfg80211 for regulatory domains even if we restore regulatory settings. To prevent this we suck out all pending requests when restoring regulatory settings and add them back into the queue after we have queued up the reset work. The impact of not having this applied is that a user with privileges can issue a userspace regulatory hint while we are disasocciating and this would prevent any further processing of regulatory domains. Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville diff --git a/net/wireless/reg.c b/net/wireless/reg.c index 3332d5b..7b1a89b 100644 --- a/net/wireless/reg.c +++ b/net/wireless/reg.c @@ -1744,6 +1744,8 @@ static void restore_regulatory_settings(bool reset_user) { char alpha2[2]; struct reg_beacon *reg_beacon, *btmp; + struct regulatory_request *reg_request, *tmp; + LIST_HEAD(tmp_reg_req_list); mutex_lock(&cfg80211_mutex); mutex_lock(®_mutex); @@ -1751,6 +1753,25 @@ static void restore_regulatory_settings(bool reset_user) reset_regdomains(); restore_alpha2(alpha2, reset_user); + /* + * If there's any pending requests we simply + * stash them to a temporary pending queue and + * add then after we've restored regulatory + * settings. + */ + spin_lock(®_requests_lock); + if (!list_empty(®_requests_list)) { + list_for_each_entry_safe(reg_request, tmp, + ®_requests_list, list) { + if (reg_request->initiator != + NL80211_REGDOM_SET_BY_USER) + continue; + list_del(®_request->list); + list_add_tail(®_request->list, &tmp_reg_req_list); + } + } + spin_unlock(®_requests_lock); + /* Clear beacon hints */ spin_lock_bh(®_pending_beacons_lock); if (!list_empty(®_pending_beacons)) { @@ -1785,8 +1806,31 @@ static void restore_regulatory_settings(bool reset_user) */ if (is_an_alpha2(alpha2)) regulatory_hint_user(user_alpha2); -} + if (list_empty(&tmp_reg_req_list)) + return; + + mutex_lock(&cfg80211_mutex); + mutex_lock(®_mutex); + + spin_lock(®_requests_lock); + list_for_each_entry_safe(reg_request, tmp, &tmp_reg_req_list, list) { + REG_DBG_PRINT("Adding request for country %c%c back " + "into the queue\n", + reg_request->alpha2[0], + reg_request->alpha2[1]); + list_del(®_request->list); + list_add_tail(®_request->list, ®_requests_list); + } + spin_unlock(®_requests_lock); + + mutex_unlock(®_mutex); + mutex_unlock(&cfg80211_mutex); + + REG_DBG_PRINT("Kicking the queue\n"); + + schedule_work(®_work); +} void regulatory_hint_disconnect(void) { -- cgit v0.10.2 From a90c7a313a1c5b4fc99f987a2ae8f92ab0ae35c7 Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Tue, 5 Apr 2011 10:49:04 -0700 Subject: cfg80211: add a timer for invalid user reg hints We have no other option but to inform userspace that we have queued up their regulatory hint request when we are given one given that nl80211 operates atomically on user requests. The best we can do is accept the request, and add a delayed work item for processing failure and cancel it if we succeeed. Upon failure we restore the regulatory settings and ignore the user input. This fixes this reported bug: https://bugzilla.kernel.org/show_bug.cgi?id=28112 Reported-by: gregoryx.alagnou@intel.com Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville diff --git a/net/wireless/reg.c b/net/wireless/reg.c index 7b1a89b..2714379 100644 --- a/net/wireless/reg.c +++ b/net/wireless/reg.c @@ -106,6 +106,9 @@ struct reg_beacon { static void reg_todo(struct work_struct *work); static DECLARE_WORK(reg_work, reg_todo); +static void reg_timeout_work(struct work_struct *work); +static DECLARE_DELAYED_WORK(reg_timeout, reg_timeout_work); + /* We keep a static world regulatory domain in case of the absence of CRDA */ static const struct ieee80211_regdomain world_regdom = { .n_reg_rules = 5, @@ -1330,6 +1333,9 @@ static void reg_set_request_processed(void) need_more_processing = true; spin_unlock(®_requests_lock); + if (last_request->initiator == NL80211_REGDOM_SET_BY_USER) + cancel_delayed_work_sync(®_timeout); + if (need_more_processing) schedule_work(®_work); } @@ -1440,8 +1446,17 @@ static void reg_process_hint(struct regulatory_request *reg_request) r = __regulatory_hint(wiphy, reg_request); /* This is required so that the orig_* parameters are saved */ if (r == -EALREADY && wiphy && - wiphy->flags & WIPHY_FLAG_STRICT_REGULATORY) + wiphy->flags & WIPHY_FLAG_STRICT_REGULATORY) { wiphy_update_regulatory(wiphy, initiator); + return; + } + + /* + * We only time out user hints, given that they should be the only + * source of bogus requests. + */ + if (reg_request->initiator == NL80211_REGDOM_SET_BY_USER) + schedule_delayed_work(®_timeout, msecs_to_jiffies(3142)); } /* @@ -2169,6 +2184,13 @@ out: mutex_unlock(®_mutex); } +static void reg_timeout_work(struct work_struct *work) +{ + REG_DBG_PRINT("Timeout while waiting for CRDA to reply, " + "restoring regulatory settings"); + restore_regulatory_settings(true); +} + int __init regulatory_init(void) { int err = 0; @@ -2222,6 +2244,7 @@ void /* __init_or_exit */ regulatory_exit(void) struct reg_beacon *reg_beacon, *btmp; cancel_work_sync(®_work); + cancel_delayed_work_sync(®_timeout); mutex_lock(&cfg80211_mutex); mutex_lock(®_mutex); -- cgit v0.10.2 From 48454079c2d4b9ee65c570a22c5fdfe1827996a4 Mon Sep 17 00:00:00 2001 From: "Gustavo F. Padovan" Date: Fri, 25 Mar 2011 00:22:30 -0300 Subject: Bluetooth: Create struct l2cap_chan struct l2cap_chan cames to create a clear separation between what properties and data belongs to the L2CAP channel and what belongs to the socket. By now we just fold the struct sock * in struct l2cap_chan as all the channel info is struct l2cap_pinfo today. In the next commits we will see a move of channel stuff to struct l2cap_chan. Signed-off-by: Gustavo F. Padovan diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h index 2b9ca0d..6378bcc 100644 --- a/include/net/bluetooth/l2cap.h +++ b/include/net/bluetooth/l2cap.h @@ -276,9 +276,16 @@ struct l2cap_conn_param_update_rsp { #define L2CAP_CONN_PARAM_ACCEPTED 0x0000 #define L2CAP_CONN_PARAM_REJECTED 0x0001 -/* ----- L2CAP connections ----- */ +/* ----- L2CAP channels and connections ----- */ + +struct l2cap_chan { + struct sock *sk; + struct l2cap_chan *next_c; + struct l2cap_chan *prev_c; +}; + struct l2cap_chan_list { - struct sock *head; + struct l2cap_chan *head; rwlock_t lock; }; @@ -317,7 +324,7 @@ struct sock_del_list { #define L2CAP_INFO_FEAT_MASK_REQ_SENT 0x04 #define L2CAP_INFO_FEAT_MASK_REQ_DONE 0x08 -/* ----- L2CAP channel and socket info ----- */ +/* ----- L2CAP socket info ----- */ #define l2cap_pi(sk) ((struct l2cap_pinfo *) sk) #define TX_QUEUE(sk) (&l2cap_pi(sk)->tx_queue) #define SREJ_QUEUE(sk) (&l2cap_pi(sk)->srej_queue) @@ -389,8 +396,7 @@ struct l2cap_pinfo { struct work_struct busy_work; struct srej_list srej_l; struct l2cap_conn *conn; - struct sock *next_c; - struct sock *prev_c; + struct l2cap_chan *chan; }; #define L2CAP_CONF_REQ_SENT 0x01 @@ -471,7 +477,7 @@ void l2cap_sock_init(struct sock *sk, struct sock *parent); struct sock *l2cap_sock_alloc(struct net *net, struct socket *sock, int proto, gfp_t prio); void l2cap_send_disconn_req(struct l2cap_conn *conn, struct sock *sk, int err); -void l2cap_chan_del(struct sock *sk, int err); +void l2cap_chan_del(struct l2cap_chan *chan, int err); int l2cap_do_connect(struct sock *sk); #endif /* __L2CAP_H */ diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index c3cebed..e49d8f7 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -74,58 +74,58 @@ static struct sk_buff *l2cap_build_cmd(struct l2cap_conn *conn, static int l2cap_ertm_data_rcv(struct sock *sk, struct sk_buff *skb); /* ---- L2CAP channels ---- */ -static struct sock *__l2cap_get_chan_by_dcid(struct l2cap_chan_list *l, u16 cid) +static struct l2cap_chan *__l2cap_get_chan_by_dcid(struct l2cap_chan_list *l, u16 cid) { - struct sock *s; - for (s = l->head; s; s = l2cap_pi(s)->next_c) { - if (l2cap_pi(s)->dcid == cid) + struct l2cap_chan *c; + for (c = l->head; c; c = c->next_c) { + if (l2cap_pi(c->sk)->dcid == cid) break; } - return s; + return c; } -static struct sock *__l2cap_get_chan_by_scid(struct l2cap_chan_list *l, u16 cid) +static struct l2cap_chan *__l2cap_get_chan_by_scid(struct l2cap_chan_list *l, u16 cid) { - struct sock *s; - for (s = l->head; s; s = l2cap_pi(s)->next_c) { - if (l2cap_pi(s)->scid == cid) + struct l2cap_chan *c; + for (c = l->head; c; c = c->next_c) { + if (l2cap_pi(c->sk)->scid == cid) break; } - return s; + return c; } /* Find channel with given SCID. * Returns locked socket */ -static inline struct sock *l2cap_get_chan_by_scid(struct l2cap_chan_list *l, u16 cid) +static inline struct l2cap_chan *l2cap_get_chan_by_scid(struct l2cap_chan_list *l, u16 cid) { - struct sock *s; + struct l2cap_chan *c; read_lock(&l->lock); - s = __l2cap_get_chan_by_scid(l, cid); - if (s) - bh_lock_sock(s); + c = __l2cap_get_chan_by_scid(l, cid); + if (c) + bh_lock_sock(c->sk); read_unlock(&l->lock); - return s; + return c; } -static struct sock *__l2cap_get_chan_by_ident(struct l2cap_chan_list *l, u8 ident) +static struct l2cap_chan *__l2cap_get_chan_by_ident(struct l2cap_chan_list *l, u8 ident) { - struct sock *s; - for (s = l->head; s; s = l2cap_pi(s)->next_c) { - if (l2cap_pi(s)->ident == ident) + struct l2cap_chan *c; + for (c = l->head; c; c = c->next_c) { + if (l2cap_pi(c->sk)->ident == ident) break; } - return s; + return c; } -static inline struct sock *l2cap_get_chan_by_ident(struct l2cap_chan_list *l, u8 ident) +static inline struct l2cap_chan *l2cap_get_chan_by_ident(struct l2cap_chan_list *l, u8 ident) { - struct sock *s; + struct l2cap_chan *c; read_lock(&l->lock); - s = __l2cap_get_chan_by_ident(l, ident); - if (s) - bh_lock_sock(s); + c = __l2cap_get_chan_by_ident(l, ident); + if (c) + bh_lock_sock(c->sk); read_unlock(&l->lock); - return s; + return c; } static u16 l2cap_alloc_cid(struct l2cap_chan_list *l) @@ -140,38 +140,52 @@ static u16 l2cap_alloc_cid(struct l2cap_chan_list *l) return 0; } -static inline void __l2cap_chan_link(struct l2cap_chan_list *l, struct sock *sk) +static struct l2cap_chan *l2cap_chan_alloc(struct sock *sk) +{ + struct l2cap_chan *chan; + + chan = kzalloc(sizeof(*chan), GFP_ATOMIC); + if (!chan) + return NULL; + + chan->sk = sk; + + return chan; +} + +static inline void __l2cap_chan_link(struct l2cap_chan_list *l, struct l2cap_chan *chan) { - sock_hold(sk); + sock_hold(chan->sk); if (l->head) - l2cap_pi(l->head)->prev_c = sk; + l->head->prev_c = chan; - l2cap_pi(sk)->next_c = l->head; - l2cap_pi(sk)->prev_c = NULL; - l->head = sk; + chan->next_c = l->head; + chan->prev_c = NULL; + l->head = chan; } -static inline void l2cap_chan_unlink(struct l2cap_chan_list *l, struct sock *sk) +static inline void l2cap_chan_unlink(struct l2cap_chan_list *l, struct l2cap_chan *chan) { - struct sock *next = l2cap_pi(sk)->next_c, *prev = l2cap_pi(sk)->prev_c; + struct l2cap_chan *next = chan->next_c, *prev = chan->prev_c; write_lock_bh(&l->lock); - if (sk == l->head) + if (chan == l->head) l->head = next; if (next) - l2cap_pi(next)->prev_c = prev; + next->prev_c = prev; if (prev) - l2cap_pi(prev)->next_c = next; + prev->next_c = next; write_unlock_bh(&l->lock); - __sock_put(sk); + __sock_put(chan->sk); } -static void __l2cap_chan_add(struct l2cap_conn *conn, struct sock *sk) +static void __l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan) { struct l2cap_chan_list *l = &conn->chan_list; + struct sock *sk = chan->sk; BT_DBG("conn %p, psm 0x%2.2x, dcid 0x%4.4x", conn, l2cap_pi(sk)->psm, l2cap_pi(sk)->dcid); @@ -203,13 +217,14 @@ static void __l2cap_chan_add(struct l2cap_conn *conn, struct sock *sk) l2cap_pi(sk)->omtu = L2CAP_DEFAULT_MTU; } - __l2cap_chan_link(l, sk); + __l2cap_chan_link(l, chan); } /* Delete channel. * Must be called on the locked socket. */ -void l2cap_chan_del(struct sock *sk, int err) +void l2cap_chan_del(struct l2cap_chan *chan, int err) { + struct sock *sk = chan->sk; struct l2cap_conn *conn = l2cap_pi(sk)->conn; struct sock *parent = bt_sk(sk)->parent; @@ -219,7 +234,7 @@ void l2cap_chan_del(struct sock *sk, int err) if (conn) { /* Unlink from channel list */ - l2cap_chan_unlink(&conn->chan_list, sk); + l2cap_chan_unlink(&conn->chan_list, chan); l2cap_pi(sk)->conn = NULL; hci_conn_put(conn->hcon); } @@ -253,6 +268,8 @@ void l2cap_chan_del(struct sock *sk, int err) kfree(l); } } + + kfree(chan); } static inline u8 l2cap_get_auth_type(struct sock *sk) @@ -487,7 +504,7 @@ static void l2cap_conn_start(struct l2cap_conn *conn) { struct l2cap_chan_list *l = &conn->chan_list; struct sock_del_list del, *tmp1, *tmp2; - struct sock *sk; + struct l2cap_chan *chan; BT_DBG("conn %p", conn); @@ -495,7 +512,8 @@ static void l2cap_conn_start(struct l2cap_conn *conn) read_lock(&l->lock); - for (sk = l->head; sk; sk = l2cap_pi(sk)->next_c) { + for (chan = l->head; chan; chan = chan->next_c) { + struct sock *sk = chan->sk; bh_lock_sock(sk); if (sk->sk_type != SOCK_SEQPACKET && @@ -622,6 +640,7 @@ static void l2cap_le_conn_ready(struct l2cap_conn *conn) { struct l2cap_chan_list *list = &conn->chan_list; struct sock *parent, *uninitialized_var(sk); + struct l2cap_chan *chan; BT_DBG(""); @@ -641,6 +660,12 @@ static void l2cap_le_conn_ready(struct l2cap_conn *conn) if (!sk) goto clean; + chan = l2cap_chan_alloc(sk); + if (!chan) { + l2cap_sock_kill(sk); + goto clean; + } + write_lock_bh(&list->lock); hci_conn_hold(conn->hcon); @@ -651,7 +676,9 @@ static void l2cap_le_conn_ready(struct l2cap_conn *conn) bt_accept_enqueue(parent, sk); - __l2cap_chan_add(conn, sk); + __l2cap_chan_add(conn, chan); + + l2cap_pi(sk)->chan = chan; l2cap_sock_set_timer(sk, sk->sk_sndtimeo); @@ -667,7 +694,7 @@ clean: static void l2cap_conn_ready(struct l2cap_conn *conn) { struct l2cap_chan_list *l = &conn->chan_list; - struct sock *sk; + struct l2cap_chan *chan; BT_DBG("conn %p", conn); @@ -676,7 +703,8 @@ static void l2cap_conn_ready(struct l2cap_conn *conn) read_lock(&l->lock); - for (sk = l->head; sk; sk = l2cap_pi(sk)->next_c) { + for (chan = l->head; chan; chan = chan->next_c) { + struct sock *sk = chan->sk; bh_lock_sock(sk); if (conn->hcon->type == LE_LINK) { @@ -703,13 +731,14 @@ static void l2cap_conn_ready(struct l2cap_conn *conn) static void l2cap_conn_unreliable(struct l2cap_conn *conn, int err) { struct l2cap_chan_list *l = &conn->chan_list; - struct sock *sk; + struct l2cap_chan *chan; BT_DBG("conn %p", conn); read_lock(&l->lock); - for (sk = l->head; sk; sk = l2cap_pi(sk)->next_c) { + for (chan = l->head; chan; chan = chan->next_c) { + struct sock *sk = chan->sk; if (l2cap_pi(sk)->force_reliable) sk->sk_err = err; } @@ -768,6 +797,7 @@ static struct l2cap_conn *l2cap_conn_add(struct hci_conn *hcon, u8 status) static void l2cap_conn_del(struct hci_conn *hcon, int err) { struct l2cap_conn *conn = hcon->l2cap_data; + struct l2cap_chan *chan; struct sock *sk; if (!conn) @@ -778,9 +808,10 @@ static void l2cap_conn_del(struct hci_conn *hcon, int err) kfree_skb(conn->rx_skb); /* Kill channels */ - while ((sk = conn->chan_list.head)) { + while ((chan = conn->chan_list.head)) { + sk = chan->sk; bh_lock_sock(sk); - l2cap_chan_del(sk, err); + l2cap_chan_del(chan, err); bh_unlock_sock(sk); l2cap_sock_kill(sk); } @@ -792,11 +823,11 @@ static void l2cap_conn_del(struct hci_conn *hcon, int err) kfree(conn); } -static inline void l2cap_chan_add(struct l2cap_conn *conn, struct sock *sk) +static inline void l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan) { struct l2cap_chan_list *l = &conn->chan_list; write_lock_bh(&l->lock); - __l2cap_chan_add(conn, sk); + __l2cap_chan_add(conn, chan); write_unlock_bh(&l->lock); } @@ -837,6 +868,7 @@ int l2cap_do_connect(struct sock *sk) bdaddr_t *src = &bt_sk(sk)->src; bdaddr_t *dst = &bt_sk(sk)->dst; struct l2cap_conn *conn; + struct l2cap_chan *chan; struct hci_conn *hcon; struct hci_dev *hdev; __u8 auth_type; @@ -872,10 +904,19 @@ int l2cap_do_connect(struct sock *sk) goto done; } + chan = l2cap_chan_alloc(sk); + if (!chan) { + hci_conn_put(hcon); + err = -ENOMEM; + goto done; + } + /* Update source addr of the socket */ bacpy(src, conn->src); - l2cap_chan_add(conn, sk); + l2cap_chan_add(conn, chan); + + l2cap_pi(sk)->chan = chan; sk->sk_state = BT_CONNECT; l2cap_sock_set_timer(sk, sk->sk_sndtimeo); @@ -1387,12 +1428,13 @@ static void l2cap_raw_recv(struct l2cap_conn *conn, struct sk_buff *skb) { struct l2cap_chan_list *l = &conn->chan_list; struct sk_buff *nskb; - struct sock *sk; + struct l2cap_chan *chan; BT_DBG("conn %p", conn); read_lock(&l->lock); - for (sk = l->head; sk; sk = l2cap_pi(sk)->next_c) { + for (chan = l->head; chan; chan = chan->next_c) { + struct sock *sk = chan->sk; if (sk->sk_type != SOCK_RAW) continue; @@ -1976,6 +2018,7 @@ static inline int l2cap_connect_req(struct l2cap_conn *conn, struct l2cap_cmd_hd struct l2cap_chan_list *list = &conn->chan_list; struct l2cap_conn_req *req = (struct l2cap_conn_req *) data; struct l2cap_conn_rsp rsp; + struct l2cap_chan *chan; struct sock *parent, *sk = NULL; int result, status = L2CAP_CS_NO_INFO; @@ -2013,6 +2056,12 @@ static inline int l2cap_connect_req(struct l2cap_conn *conn, struct l2cap_cmd_hd if (!sk) goto response; + chan = l2cap_chan_alloc(sk); + if (!chan) { + l2cap_sock_kill(sk); + goto response; + } + write_lock_bh(&list->lock); /* Check if we already have channel with that dcid */ @@ -2033,7 +2082,10 @@ static inline int l2cap_connect_req(struct l2cap_conn *conn, struct l2cap_cmd_hd bt_accept_enqueue(parent, sk); - __l2cap_chan_add(conn, sk); + __l2cap_chan_add(conn, chan); + + l2cap_pi(sk)->chan = chan; + dcid = l2cap_pi(sk)->scid; l2cap_sock_set_timer(sk, sk->sk_sndtimeo); @@ -2105,6 +2157,7 @@ static inline int l2cap_connect_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hd { struct l2cap_conn_rsp *rsp = (struct l2cap_conn_rsp *) data; u16 scid, dcid, result, status; + struct l2cap_chan *chan; struct sock *sk; u8 req[128]; @@ -2116,15 +2169,17 @@ static inline int l2cap_connect_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hd BT_DBG("dcid 0x%4.4x scid 0x%4.4x result 0x%2.2x status 0x%2.2x", dcid, scid, result, status); if (scid) { - sk = l2cap_get_chan_by_scid(&conn->chan_list, scid); - if (!sk) + chan = l2cap_get_chan_by_scid(&conn->chan_list, scid); + if (!chan) return -EFAULT; } else { - sk = l2cap_get_chan_by_ident(&conn->chan_list, cmd->ident); - if (!sk) + chan = l2cap_get_chan_by_ident(&conn->chan_list, cmd->ident); + if (!chan) return -EFAULT; } + sk = chan->sk; + switch (result) { case L2CAP_CR_SUCCESS: sk->sk_state = BT_CONFIG; @@ -2155,7 +2210,7 @@ static inline int l2cap_connect_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hd break; } - l2cap_chan_del(sk, ECONNREFUSED); + l2cap_chan_del(chan, ECONNREFUSED); break; } @@ -2179,6 +2234,7 @@ static inline int l2cap_config_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr struct l2cap_conf_req *req = (struct l2cap_conf_req *) data; u16 dcid, flags; u8 rsp[64]; + struct l2cap_chan *chan; struct sock *sk; int len; @@ -2187,10 +2243,12 @@ static inline int l2cap_config_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr BT_DBG("dcid 0x%4.4x flags 0x%2.2x", dcid, flags); - sk = l2cap_get_chan_by_scid(&conn->chan_list, dcid); - if (!sk) + chan = l2cap_get_chan_by_scid(&conn->chan_list, dcid); + if (!chan) return -ENOENT; + sk = chan->sk; + if (sk->sk_state != BT_CONFIG) { struct l2cap_cmd_rej rej; @@ -2269,6 +2327,7 @@ static inline int l2cap_config_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hdr { struct l2cap_conf_rsp *rsp = (struct l2cap_conf_rsp *)data; u16 scid, flags, result; + struct l2cap_chan *chan; struct sock *sk; int len = cmd->len - sizeof(*rsp); @@ -2279,10 +2338,12 @@ static inline int l2cap_config_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hdr BT_DBG("scid 0x%4.4x flags 0x%2.2x result 0x%2.2x", scid, flags, result); - sk = l2cap_get_chan_by_scid(&conn->chan_list, scid); - if (!sk) + chan = l2cap_get_chan_by_scid(&conn->chan_list, scid); + if (!chan) return 0; + sk = chan->sk; + switch (result) { case L2CAP_CONF_SUCCESS: l2cap_conf_rfc_get(sk, rsp->data, len); @@ -2349,6 +2410,7 @@ static inline int l2cap_disconnect_req(struct l2cap_conn *conn, struct l2cap_cmd struct l2cap_disconn_req *req = (struct l2cap_disconn_req *) data; struct l2cap_disconn_rsp rsp; u16 dcid, scid; + struct l2cap_chan *chan; struct sock *sk; scid = __le16_to_cpu(req->scid); @@ -2356,10 +2418,12 @@ static inline int l2cap_disconnect_req(struct l2cap_conn *conn, struct l2cap_cmd BT_DBG("scid 0x%4.4x dcid 0x%4.4x", scid, dcid); - sk = l2cap_get_chan_by_scid(&conn->chan_list, dcid); - if (!sk) + chan = l2cap_get_chan_by_scid(&conn->chan_list, dcid); + if (!chan) return 0; + sk = chan->sk; + rsp.dcid = cpu_to_le16(l2cap_pi(sk)->scid); rsp.scid = cpu_to_le16(l2cap_pi(sk)->dcid); l2cap_send_cmd(conn, cmd->ident, L2CAP_DISCONN_RSP, sizeof(rsp), &rsp); @@ -2375,7 +2439,7 @@ static inline int l2cap_disconnect_req(struct l2cap_conn *conn, struct l2cap_cmd return 0; } - l2cap_chan_del(sk, ECONNRESET); + l2cap_chan_del(chan, ECONNRESET); bh_unlock_sock(sk); l2cap_sock_kill(sk); @@ -2386,6 +2450,7 @@ static inline int l2cap_disconnect_rsp(struct l2cap_conn *conn, struct l2cap_cmd { struct l2cap_disconn_rsp *rsp = (struct l2cap_disconn_rsp *) data; u16 dcid, scid; + struct l2cap_chan *chan; struct sock *sk; scid = __le16_to_cpu(rsp->scid); @@ -2393,10 +2458,12 @@ static inline int l2cap_disconnect_rsp(struct l2cap_conn *conn, struct l2cap_cmd BT_DBG("dcid 0x%4.4x scid 0x%4.4x", dcid, scid); - sk = l2cap_get_chan_by_scid(&conn->chan_list, scid); - if (!sk) + chan = l2cap_get_chan_by_scid(&conn->chan_list, scid); + if (!chan) return 0; + sk = chan->sk; + /* don't delete l2cap channel if sk is owned by user */ if (sock_owned_by_user(sk)) { sk->sk_state = BT_DISCONN; @@ -2406,7 +2473,7 @@ static inline int l2cap_disconnect_rsp(struct l2cap_conn *conn, struct l2cap_cmd return 0; } - l2cap_chan_del(sk, 0); + l2cap_chan_del(chan, 0); bh_unlock_sock(sk); l2cap_sock_kill(sk); @@ -3538,18 +3605,20 @@ drop: static inline int l2cap_data_channel(struct l2cap_conn *conn, u16 cid, struct sk_buff *skb) { + struct l2cap_chan *chan; struct sock *sk; struct l2cap_pinfo *pi; u16 control; u8 tx_seq; int len; - sk = l2cap_get_chan_by_scid(&conn->chan_list, cid); - if (!sk) { + chan = l2cap_get_chan_by_scid(&conn->chan_list, cid); + if (!chan) { BT_DBG("unknown cid 0x%4.4x", cid); goto drop; } + sk = chan->sk; pi = l2cap_pi(sk); BT_DBG("sk %p, len %d", sk, skb->len); @@ -3788,7 +3857,7 @@ static int l2cap_security_cfm(struct hci_conn *hcon, u8 status, u8 encrypt) { struct l2cap_chan_list *l; struct l2cap_conn *conn = hcon->l2cap_data; - struct sock *sk; + struct l2cap_chan *chan; if (!conn) return 0; @@ -3799,7 +3868,8 @@ static int l2cap_security_cfm(struct hci_conn *hcon, u8 status, u8 encrypt) read_lock(&l->lock); - for (sk = l->head; sk; sk = l2cap_pi(sk)->next_c) { + for (chan = l->head; chan; chan = chan->next_c) { + struct sock *sk = chan->sk; bh_lock_sock(sk); if (l2cap_pi(sk)->conf_state & L2CAP_CONF_CONNECT_PEND) { @@ -3872,7 +3942,7 @@ static int l2cap_recv_acldata(struct hci_conn *hcon, struct sk_buff *skb, u16 fl if (!(flags & ACL_CONT)) { struct l2cap_hdr *hdr; - struct sock *sk; + struct l2cap_chan *chan; u16 cid; int len; @@ -3910,18 +3980,21 @@ static int l2cap_recv_acldata(struct hci_conn *hcon, struct sk_buff *skb, u16 fl goto drop; } - sk = l2cap_get_chan_by_scid(&conn->chan_list, cid); + chan = l2cap_get_chan_by_scid(&conn->chan_list, cid); - if (sk && l2cap_pi(sk)->imtu < len - L2CAP_HDR_SIZE) { - BT_ERR("Frame exceeding recv MTU (len %d, MTU %d)", - len, l2cap_pi(sk)->imtu); - bh_unlock_sock(sk); - l2cap_conn_unreliable(conn, ECOMM); - goto drop; - } + if (chan && chan->sk) { + struct sock *sk = chan->sk; - if (sk) + if (l2cap_pi(sk)->imtu < len - L2CAP_HDR_SIZE) { + BT_ERR("Frame exceeding recv MTU (len %d, " + "MTU %d)", len, + l2cap_pi(sk)->imtu); + bh_unlock_sock(sk); + l2cap_conn_unreliable(conn, ECOMM); + goto drop; + } bh_unlock_sock(sk); + } /* Allocate skb for the complete frame (with header) */ conn->rx_skb = bt_skb_alloc(len, GFP_ATOMIC); diff --git a/net/bluetooth/l2cap_sock.c b/net/bluetooth/l2cap_sock.c index f77308e..7df8118 100644 --- a/net/bluetooth/l2cap_sock.c +++ b/net/bluetooth/l2cap_sock.c @@ -902,7 +902,7 @@ void __l2cap_sock_close(struct sock *sk, int reason) l2cap_sock_set_timer(sk, sk->sk_sndtimeo); l2cap_send_disconn_req(conn, sk, reason); } else - l2cap_chan_del(sk, reason); + l2cap_chan_del(l2cap_pi(sk)->chan, reason); break; case BT_CONNECT2: @@ -925,12 +925,12 @@ void __l2cap_sock_close(struct sock *sk, int reason) L2CAP_CONN_RSP, sizeof(rsp), &rsp); } - l2cap_chan_del(sk, reason); + l2cap_chan_del(l2cap_pi(sk)->chan, reason); break; case BT_CONNECT: case BT_DISCONN: - l2cap_chan_del(sk, reason); + l2cap_chan_del(l2cap_pi(sk)->chan, reason); break; default: -- cgit v0.10.2 From baa7e1fa6d2870462bd744df1c6ddbd497fe86d6 Mon Sep 17 00:00:00 2001 From: "Gustavo F. Padovan" Date: Thu, 31 Mar 2011 16:17:41 -0300 Subject: Bluetooth: Use struct list_head for L2CAP channels list Use a well known Kernel API is always a good idea than implement your own list. In the future we might use RCU on this list. Signed-off-by: Gustavo F. Padovan diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h index 6378bcc..ddf4bc5 100644 --- a/include/net/bluetooth/l2cap.h +++ b/include/net/bluetooth/l2cap.h @@ -277,16 +277,9 @@ struct l2cap_conn_param_update_rsp { #define L2CAP_CONN_PARAM_REJECTED 0x0001 /* ----- L2CAP channels and connections ----- */ - struct l2cap_chan { struct sock *sk; - struct l2cap_chan *next_c; - struct l2cap_chan *prev_c; -}; - -struct l2cap_chan_list { - struct l2cap_chan *head; - rwlock_t lock; + struct list_head list; }; struct l2cap_conn { @@ -312,7 +305,8 @@ struct l2cap_conn { __u8 disc_reason; - struct l2cap_chan_list chan_list; + struct list_head chan_l; + rwlock_t chan_lock; }; struct sock_del_list { diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index e49d8f7..0dbbaf3 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -74,66 +74,75 @@ static struct sk_buff *l2cap_build_cmd(struct l2cap_conn *conn, static int l2cap_ertm_data_rcv(struct sock *sk, struct sk_buff *skb); /* ---- L2CAP channels ---- */ -static struct l2cap_chan *__l2cap_get_chan_by_dcid(struct l2cap_chan_list *l, u16 cid) +static struct l2cap_chan *__l2cap_get_chan_by_dcid(struct l2cap_conn *conn, u16 cid) { struct l2cap_chan *c; - for (c = l->head; c; c = c->next_c) { - if (l2cap_pi(c->sk)->dcid == cid) - break; + + list_for_each_entry(c, &conn->chan_l, list) { + struct sock *s = c->sk; + if (l2cap_pi(s)->dcid == cid) + return c; } - return c; + return NULL; + } -static struct l2cap_chan *__l2cap_get_chan_by_scid(struct l2cap_chan_list *l, u16 cid) +static struct l2cap_chan *__l2cap_get_chan_by_scid(struct l2cap_conn *conn, u16 cid) { struct l2cap_chan *c; - for (c = l->head; c; c = c->next_c) { - if (l2cap_pi(c->sk)->scid == cid) - break; + + list_for_each_entry(c, &conn->chan_l, list) { + struct sock *s = c->sk; + if (l2cap_pi(s)->scid == cid) + return c; } - return c; + return NULL; } /* Find channel with given SCID. * Returns locked socket */ -static inline struct l2cap_chan *l2cap_get_chan_by_scid(struct l2cap_chan_list *l, u16 cid) +static struct l2cap_chan *l2cap_get_chan_by_scid(struct l2cap_conn *conn, u16 cid) { struct l2cap_chan *c; - read_lock(&l->lock); - c = __l2cap_get_chan_by_scid(l, cid); + + read_lock(&conn->chan_lock); + c = __l2cap_get_chan_by_scid(conn, cid); if (c) bh_lock_sock(c->sk); - read_unlock(&l->lock); + read_unlock(&conn->chan_lock); return c; } -static struct l2cap_chan *__l2cap_get_chan_by_ident(struct l2cap_chan_list *l, u8 ident) +static struct l2cap_chan *__l2cap_get_chan_by_ident(struct l2cap_conn *conn, u8 ident) { struct l2cap_chan *c; - for (c = l->head; c; c = c->next_c) { - if (l2cap_pi(c->sk)->ident == ident) - break; + + list_for_each_entry(c, &conn->chan_l, list) { + struct sock *s = c->sk; + if (l2cap_pi(s)->ident == ident) + return c; } - return c; + return NULL; } -static inline struct l2cap_chan *l2cap_get_chan_by_ident(struct l2cap_chan_list *l, u8 ident) +static inline struct l2cap_chan *l2cap_get_chan_by_ident(struct l2cap_conn *conn, u8 ident) { struct l2cap_chan *c; - read_lock(&l->lock); - c = __l2cap_get_chan_by_ident(l, ident); + + read_lock(&conn->chan_lock); + c = __l2cap_get_chan_by_ident(conn, ident); if (c) bh_lock_sock(c->sk); - read_unlock(&l->lock); + read_unlock(&conn->chan_lock); return c; } -static u16 l2cap_alloc_cid(struct l2cap_chan_list *l) +static u16 l2cap_alloc_cid(struct l2cap_conn *conn) { u16 cid = L2CAP_CID_DYN_START; for (; cid < L2CAP_CID_DYN_END; cid++) { - if (!__l2cap_get_chan_by_scid(l, cid)) + if (!__l2cap_get_chan_by_scid(conn, cid)) return cid; } @@ -153,38 +162,8 @@ static struct l2cap_chan *l2cap_chan_alloc(struct sock *sk) return chan; } -static inline void __l2cap_chan_link(struct l2cap_chan_list *l, struct l2cap_chan *chan) -{ - sock_hold(chan->sk); - - if (l->head) - l->head->prev_c = chan; - - chan->next_c = l->head; - chan->prev_c = NULL; - l->head = chan; -} - -static inline void l2cap_chan_unlink(struct l2cap_chan_list *l, struct l2cap_chan *chan) -{ - struct l2cap_chan *next = chan->next_c, *prev = chan->prev_c; - - write_lock_bh(&l->lock); - if (chan == l->head) - l->head = next; - - if (next) - next->prev_c = prev; - if (prev) - prev->next_c = next; - write_unlock_bh(&l->lock); - - __sock_put(chan->sk); -} - static void __l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan) { - struct l2cap_chan_list *l = &conn->chan_list; struct sock *sk = chan->sk; BT_DBG("conn %p, psm 0x%2.2x, dcid 0x%4.4x", conn, @@ -202,7 +181,7 @@ static void __l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan) l2cap_pi(sk)->dcid = L2CAP_CID_LE_DATA; } else { /* Alloc CID for connection-oriented socket */ - l2cap_pi(sk)->scid = l2cap_alloc_cid(l); + l2cap_pi(sk)->scid = l2cap_alloc_cid(conn); l2cap_pi(sk)->omtu = L2CAP_DEFAULT_MTU; } } else if (sk->sk_type == SOCK_DGRAM) { @@ -217,7 +196,9 @@ static void __l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan) l2cap_pi(sk)->omtu = L2CAP_DEFAULT_MTU; } - __l2cap_chan_link(l, chan); + sock_hold(sk); + + list_add(&chan->list, &conn->chan_l); } /* Delete channel. @@ -233,8 +214,12 @@ void l2cap_chan_del(struct l2cap_chan *chan, int err) BT_DBG("sk %p, conn %p, err %d", sk, conn, err); if (conn) { - /* Unlink from channel list */ - l2cap_chan_unlink(&conn->chan_list, chan); + /* Delete from channel list */ + write_lock_bh(&conn->chan_lock); + list_del(&chan->list); + write_unlock_bh(&conn->chan_lock); + __sock_put(sk); + l2cap_pi(sk)->conn = NULL; hci_conn_put(conn->hcon); } @@ -502,7 +487,6 @@ void l2cap_send_disconn_req(struct l2cap_conn *conn, struct sock *sk, int err) /* ---- L2CAP connections ---- */ static void l2cap_conn_start(struct l2cap_conn *conn) { - struct l2cap_chan_list *l = &conn->chan_list; struct sock_del_list del, *tmp1, *tmp2; struct l2cap_chan *chan; @@ -510,10 +494,11 @@ static void l2cap_conn_start(struct l2cap_conn *conn) INIT_LIST_HEAD(&del.list); - read_lock(&l->lock); + read_lock(&conn->chan_lock); - for (chan = l->head; chan; chan = chan->next_c) { + list_for_each_entry(chan, &conn->chan_l, list) { struct sock *sk = chan->sk; + bh_lock_sock(sk); if (sk->sk_type != SOCK_SEQPACKET && @@ -593,7 +578,7 @@ static void l2cap_conn_start(struct l2cap_conn *conn) bh_unlock_sock(sk); } - read_unlock(&l->lock); + read_unlock(&conn->chan_lock); list_for_each_entry_safe(tmp1, tmp2, &del.list, list) { bh_lock_sock(tmp1->sk); @@ -638,7 +623,6 @@ static struct sock *l2cap_get_sock_by_scid(int state, __le16 cid, bdaddr_t *src) static void l2cap_le_conn_ready(struct l2cap_conn *conn) { - struct l2cap_chan_list *list = &conn->chan_list; struct sock *parent, *uninitialized_var(sk); struct l2cap_chan *chan; @@ -666,11 +650,12 @@ static void l2cap_le_conn_ready(struct l2cap_conn *conn) goto clean; } - write_lock_bh(&list->lock); + write_lock_bh(&conn->chan_lock); hci_conn_hold(conn->hcon); l2cap_sock_init(sk, parent); + bacpy(&bt_sk(sk)->src, conn->src); bacpy(&bt_sk(sk)->dst, conn->dst); @@ -685,7 +670,7 @@ static void l2cap_le_conn_ready(struct l2cap_conn *conn) sk->sk_state = BT_CONNECTED; parent->sk_data_ready(parent, 0); - write_unlock_bh(&list->lock); + write_unlock_bh(&conn->chan_lock); clean: bh_unlock_sock(parent); @@ -693,7 +678,6 @@ clean: static void l2cap_conn_ready(struct l2cap_conn *conn) { - struct l2cap_chan_list *l = &conn->chan_list; struct l2cap_chan *chan; BT_DBG("conn %p", conn); @@ -701,10 +685,11 @@ static void l2cap_conn_ready(struct l2cap_conn *conn) if (!conn->hcon->out && conn->hcon->type == LE_LINK) l2cap_le_conn_ready(conn); - read_lock(&l->lock); + read_lock(&conn->chan_lock); - for (chan = l->head; chan; chan = chan->next_c) { + list_for_each_entry(chan, &conn->chan_l, list) { struct sock *sk = chan->sk; + bh_lock_sock(sk); if (conn->hcon->type == LE_LINK) { @@ -724,26 +709,26 @@ static void l2cap_conn_ready(struct l2cap_conn *conn) bh_unlock_sock(sk); } - read_unlock(&l->lock); + read_unlock(&conn->chan_lock); } /* Notify sockets that we cannot guaranty reliability anymore */ static void l2cap_conn_unreliable(struct l2cap_conn *conn, int err) { - struct l2cap_chan_list *l = &conn->chan_list; struct l2cap_chan *chan; BT_DBG("conn %p", conn); - read_lock(&l->lock); + read_lock(&conn->chan_lock); - for (chan = l->head; chan; chan = chan->next_c) { + list_for_each_entry(chan, &conn->chan_l, list) { struct sock *sk = chan->sk; + if (l2cap_pi(sk)->force_reliable) sk->sk_err = err; } - read_unlock(&l->lock); + read_unlock(&conn->chan_lock); } static void l2cap_info_timeout(unsigned long arg) @@ -783,7 +768,9 @@ static struct l2cap_conn *l2cap_conn_add(struct hci_conn *hcon, u8 status) conn->feat_mask = 0; spin_lock_init(&conn->lock); - rwlock_init(&conn->chan_list.lock); + rwlock_init(&conn->chan_lock); + + INIT_LIST_HEAD(&conn->chan_l); if (hcon->type != LE_LINK) setup_timer(&conn->info_timer, l2cap_info_timeout, @@ -797,7 +784,7 @@ static struct l2cap_conn *l2cap_conn_add(struct hci_conn *hcon, u8 status) static void l2cap_conn_del(struct hci_conn *hcon, int err) { struct l2cap_conn *conn = hcon->l2cap_data; - struct l2cap_chan *chan; + struct l2cap_chan *chan, *l; struct sock *sk; if (!conn) @@ -808,7 +795,7 @@ static void l2cap_conn_del(struct hci_conn *hcon, int err) kfree_skb(conn->rx_skb); /* Kill channels */ - while ((chan = conn->chan_list.head)) { + list_for_each_entry_safe(chan, l, &conn->chan_l, list) { sk = chan->sk; bh_lock_sock(sk); l2cap_chan_del(chan, err); @@ -825,10 +812,9 @@ static void l2cap_conn_del(struct hci_conn *hcon, int err) static inline void l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan) { - struct l2cap_chan_list *l = &conn->chan_list; - write_lock_bh(&l->lock); + write_lock_bh(&conn->chan_lock); __l2cap_chan_add(conn, chan); - write_unlock_bh(&l->lock); + write_unlock_bh(&conn->chan_lock); } /* ---- Socket interface ---- */ @@ -1426,14 +1412,13 @@ static void l2cap_chan_ready(struct sock *sk) /* Copy frame to all raw sockets on that connection */ static void l2cap_raw_recv(struct l2cap_conn *conn, struct sk_buff *skb) { - struct l2cap_chan_list *l = &conn->chan_list; struct sk_buff *nskb; struct l2cap_chan *chan; BT_DBG("conn %p", conn); - read_lock(&l->lock); - for (chan = l->head; chan; chan = chan->next_c) { + read_lock(&conn->chan_lock); + list_for_each_entry(chan, &conn->chan_l, list) { struct sock *sk = chan->sk; if (sk->sk_type != SOCK_RAW) continue; @@ -1448,7 +1433,7 @@ static void l2cap_raw_recv(struct l2cap_conn *conn, struct sk_buff *skb) if (sock_queue_rcv_skb(sk, nskb)) kfree_skb(nskb); } - read_unlock(&l->lock); + read_unlock(&conn->chan_lock); } /* ---- L2CAP signalling commands ---- */ @@ -2015,7 +2000,6 @@ static inline int l2cap_command_rej(struct l2cap_conn *conn, struct l2cap_cmd_hd static inline int l2cap_connect_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u8 *data) { - struct l2cap_chan_list *list = &conn->chan_list; struct l2cap_conn_req *req = (struct l2cap_conn_req *) data; struct l2cap_conn_rsp rsp; struct l2cap_chan *chan; @@ -2062,11 +2046,11 @@ static inline int l2cap_connect_req(struct l2cap_conn *conn, struct l2cap_cmd_hd goto response; } - write_lock_bh(&list->lock); + write_lock_bh(&conn->chan_lock); /* Check if we already have channel with that dcid */ - if (__l2cap_get_chan_by_dcid(list, scid)) { - write_unlock_bh(&list->lock); + if (__l2cap_get_chan_by_dcid(conn, scid)) { + write_unlock_bh(&conn->chan_lock); sock_set_flag(sk, SOCK_ZAPPED); l2cap_sock_kill(sk); goto response; @@ -2115,7 +2099,7 @@ static inline int l2cap_connect_req(struct l2cap_conn *conn, struct l2cap_cmd_hd status = L2CAP_CS_NO_INFO; } - write_unlock_bh(&list->lock); + write_unlock_bh(&conn->chan_lock); response: bh_unlock_sock(parent); @@ -2169,11 +2153,11 @@ static inline int l2cap_connect_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hd BT_DBG("dcid 0x%4.4x scid 0x%4.4x result 0x%2.2x status 0x%2.2x", dcid, scid, result, status); if (scid) { - chan = l2cap_get_chan_by_scid(&conn->chan_list, scid); + chan = l2cap_get_chan_by_scid(conn, scid); if (!chan) return -EFAULT; } else { - chan = l2cap_get_chan_by_ident(&conn->chan_list, cmd->ident); + chan = l2cap_get_chan_by_ident(conn, cmd->ident); if (!chan) return -EFAULT; } @@ -2243,7 +2227,7 @@ static inline int l2cap_config_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr BT_DBG("dcid 0x%4.4x flags 0x%2.2x", dcid, flags); - chan = l2cap_get_chan_by_scid(&conn->chan_list, dcid); + chan = l2cap_get_chan_by_scid(conn, dcid); if (!chan) return -ENOENT; @@ -2338,7 +2322,7 @@ static inline int l2cap_config_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hdr BT_DBG("scid 0x%4.4x flags 0x%2.2x result 0x%2.2x", scid, flags, result); - chan = l2cap_get_chan_by_scid(&conn->chan_list, scid); + chan = l2cap_get_chan_by_scid(conn, scid); if (!chan) return 0; @@ -2418,7 +2402,7 @@ static inline int l2cap_disconnect_req(struct l2cap_conn *conn, struct l2cap_cmd BT_DBG("scid 0x%4.4x dcid 0x%4.4x", scid, dcid); - chan = l2cap_get_chan_by_scid(&conn->chan_list, dcid); + chan = l2cap_get_chan_by_scid(conn, dcid); if (!chan) return 0; @@ -2458,7 +2442,7 @@ static inline int l2cap_disconnect_rsp(struct l2cap_conn *conn, struct l2cap_cmd BT_DBG("dcid 0x%4.4x scid 0x%4.4x", dcid, scid); - chan = l2cap_get_chan_by_scid(&conn->chan_list, scid); + chan = l2cap_get_chan_by_scid(conn, scid); if (!chan) return 0; @@ -3612,7 +3596,7 @@ static inline int l2cap_data_channel(struct l2cap_conn *conn, u16 cid, struct sk u8 tx_seq; int len; - chan = l2cap_get_chan_by_scid(&conn->chan_list, cid); + chan = l2cap_get_chan_by_scid(conn, cid); if (!chan) { BT_DBG("unknown cid 0x%4.4x", cid); goto drop; @@ -3855,21 +3839,19 @@ static inline void l2cap_check_encryption(struct sock *sk, u8 encrypt) static int l2cap_security_cfm(struct hci_conn *hcon, u8 status, u8 encrypt) { - struct l2cap_chan_list *l; struct l2cap_conn *conn = hcon->l2cap_data; struct l2cap_chan *chan; if (!conn) return 0; - l = &conn->chan_list; - BT_DBG("conn %p", conn); - read_lock(&l->lock); + read_lock(&conn->chan_lock); - for (chan = l->head; chan; chan = chan->next_c) { + list_for_each_entry(chan, &conn->chan_l, list) { struct sock *sk = chan->sk; + bh_lock_sock(sk); if (l2cap_pi(sk)->conf_state & L2CAP_CONF_CONNECT_PEND) { @@ -3923,7 +3905,7 @@ static int l2cap_security_cfm(struct hci_conn *hcon, u8 status, u8 encrypt) bh_unlock_sock(sk); } - read_unlock(&l->lock); + read_unlock(&conn->chan_lock); return 0; } @@ -3980,7 +3962,7 @@ static int l2cap_recv_acldata(struct hci_conn *hcon, struct sk_buff *skb, u16 fl goto drop; } - chan = l2cap_get_chan_by_scid(&conn->chan_list, cid); + chan = l2cap_get_chan_by_scid(conn, cid); if (chan && chan->sk) { struct sock *sk = chan->sk; -- cgit v0.10.2 From 820ffdb3d25f74fbd553453f461709d52dfa72a2 Mon Sep 17 00:00:00 2001 From: "Gustavo F. Padovan" Date: Fri, 1 Apr 2011 00:35:21 -0300 Subject: Bluetooth: Remove struct del_list As we use struct list_head to keep L2CAP channels list the workaround with del_list is not needed anymore. Signed-off-by: Gustavo F. Padovan diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h index ddf4bc5..d24b51c 100644 --- a/include/net/bluetooth/l2cap.h +++ b/include/net/bluetooth/l2cap.h @@ -309,11 +309,6 @@ struct l2cap_conn { rwlock_t chan_lock; }; -struct sock_del_list { - struct sock *sk; - struct list_head list; -}; - #define L2CAP_INFO_CL_MTU_REQ_SENT 0x01 #define L2CAP_INFO_FEAT_MASK_REQ_SENT 0x04 #define L2CAP_INFO_FEAT_MASK_REQ_DONE 0x08 diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index 0dbbaf3..b0aaaa9 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -487,16 +487,13 @@ void l2cap_send_disconn_req(struct l2cap_conn *conn, struct sock *sk, int err) /* ---- L2CAP connections ---- */ static void l2cap_conn_start(struct l2cap_conn *conn) { - struct sock_del_list del, *tmp1, *tmp2; - struct l2cap_chan *chan; + struct l2cap_chan *chan, *tmp; BT_DBG("conn %p", conn); - INIT_LIST_HEAD(&del.list); - read_lock(&conn->chan_lock); - list_for_each_entry(chan, &conn->chan_l, list) { + list_for_each_entry_safe(chan, tmp, &conn->chan_l, list) { struct sock *sk = chan->sk; bh_lock_sock(sk); @@ -520,10 +517,11 @@ static void l2cap_conn_start(struct l2cap_conn *conn) conn->feat_mask) && l2cap_pi(sk)->conf_state & L2CAP_CONF_STATE2_DEVICE) { - tmp1 = kzalloc(sizeof(struct sock_del_list), - GFP_ATOMIC); - tmp1->sk = sk; - list_add_tail(&tmp1->list, &del.list); + /* __l2cap_sock_close() calls list_del(chan) + * so release the lock */ + read_unlock_bh(&conn->chan_lock); + __l2cap_sock_close(sk, ECONNRESET); + read_lock_bh(&conn->chan_lock); bh_unlock_sock(sk); continue; } @@ -579,14 +577,6 @@ static void l2cap_conn_start(struct l2cap_conn *conn) } read_unlock(&conn->chan_lock); - - list_for_each_entry_safe(tmp1, tmp2, &del.list, list) { - bh_lock_sock(tmp1->sk); - __l2cap_sock_close(tmp1->sk, ECONNRESET); - bh_unlock_sock(tmp1->sk); - list_del(&tmp1->list); - kfree(tmp1); - } } /* Find socket with cid and source bdaddr. -- cgit v0.10.2 From fc7f8a7ed4543853a99852ca405ea71fabe78946 Mon Sep 17 00:00:00 2001 From: "Gustavo F. Padovan" Date: Fri, 25 Mar 2011 13:59:37 -0300 Subject: Bluetooth: Move ident to struct l2cap_chan ident is chan property, no need to reside on socket. Signed-off-by: Gustavo F. Padovan diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h index d24b51c..81829e5 100644 --- a/include/net/bluetooth/l2cap.h +++ b/include/net/bluetooth/l2cap.h @@ -279,6 +279,8 @@ struct l2cap_conn_param_update_rsp { /* ----- L2CAP channels and connections ----- */ struct l2cap_chan { struct sock *sk; + __u8 ident; + struct list_head list; }; @@ -363,8 +365,6 @@ struct l2cap_pinfo { __u16 partial_sdu_len; struct sk_buff *sdu; - __u8 ident; - __u8 tx_win; __u8 max_tx; __u8 remote_tx_win; diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index b0aaaa9..6020e1e 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -118,8 +118,7 @@ static struct l2cap_chan *__l2cap_get_chan_by_ident(struct l2cap_conn *conn, u8 struct l2cap_chan *c; list_for_each_entry(c, &conn->chan_l, list) { - struct sock *s = c->sk; - if (l2cap_pi(s)->ident == ident) + if (c->ident == ident) return c; } return NULL; @@ -410,8 +409,9 @@ static inline int __l2cap_no_conn_pending(struct sock *sk) return !(l2cap_pi(sk)->conf_state & L2CAP_CONF_CONNECT_PEND); } -static void l2cap_do_start(struct sock *sk) +static void l2cap_do_start(struct l2cap_chan *chan) { + struct sock *sk = chan->sk; struct l2cap_conn *conn = l2cap_pi(sk)->conn; if (conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_SENT) { @@ -423,11 +423,11 @@ static void l2cap_do_start(struct sock *sk) req.scid = cpu_to_le16(l2cap_pi(sk)->scid); req.psm = l2cap_pi(sk)->psm; - l2cap_pi(sk)->ident = l2cap_get_ident(conn); + chan->ident = l2cap_get_ident(conn); l2cap_pi(sk)->conf_state |= L2CAP_CONF_CONNECT_PEND; - l2cap_send_cmd(conn, l2cap_pi(sk)->ident, - L2CAP_CONN_REQ, sizeof(req), &req); + l2cap_send_cmd(conn, chan->ident, L2CAP_CONN_REQ, + sizeof(req), &req); } } else { struct l2cap_info_req req; @@ -529,11 +529,11 @@ static void l2cap_conn_start(struct l2cap_conn *conn) req.scid = cpu_to_le16(l2cap_pi(sk)->scid); req.psm = l2cap_pi(sk)->psm; - l2cap_pi(sk)->ident = l2cap_get_ident(conn); + chan->ident = l2cap_get_ident(conn); l2cap_pi(sk)->conf_state |= L2CAP_CONF_CONNECT_PEND; - l2cap_send_cmd(conn, l2cap_pi(sk)->ident, - L2CAP_CONN_REQ, sizeof(req), &req); + l2cap_send_cmd(conn, chan->ident, L2CAP_CONN_REQ, + sizeof(req), &req); } else if (sk->sk_state == BT_CONNECT2) { struct l2cap_conn_rsp rsp; @@ -558,8 +558,8 @@ static void l2cap_conn_start(struct l2cap_conn *conn) rsp.status = cpu_to_le16(L2CAP_CS_AUTHEN_PEND); } - l2cap_send_cmd(conn, l2cap_pi(sk)->ident, - L2CAP_CONN_RSP, sizeof(rsp), &rsp); + l2cap_send_cmd(conn, chan->ident, L2CAP_CONN_RSP, + sizeof(rsp), &rsp); if (l2cap_pi(sk)->conf_state & L2CAP_CONF_REQ_SENT || rsp.result != L2CAP_CR_SUCCESS) { @@ -694,7 +694,7 @@ static void l2cap_conn_ready(struct l2cap_conn *conn) sk->sk_state = BT_CONNECTED; sk->sk_state_change(sk); } else if (sk->sk_state == BT_CONNECT) - l2cap_do_start(sk); + l2cap_do_start(chan); bh_unlock_sock(sk); } @@ -904,7 +904,7 @@ int l2cap_do_connect(struct sock *sk) if (l2cap_check_security(sk)) sk->sk_state = BT_CONNECTED; } else - l2cap_do_start(sk); + l2cap_do_start(chan); } err = 0; @@ -2064,7 +2064,7 @@ static inline int l2cap_connect_req(struct l2cap_conn *conn, struct l2cap_cmd_hd l2cap_sock_set_timer(sk, sk->sk_sndtimeo); - l2cap_pi(sk)->ident = cmd->ident; + chan->ident = cmd->ident; if (conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_DONE) { if (l2cap_check_security(sk)) { @@ -2157,7 +2157,7 @@ static inline int l2cap_connect_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hd switch (result) { case L2CAP_CR_SUCCESS: sk->sk_state = BT_CONFIG; - l2cap_pi(sk)->ident = 0; + chan->ident = 0; l2cap_pi(sk)->dcid = dcid; l2cap_pi(sk)->conf_state &= ~L2CAP_CONF_CONNECT_PEND; @@ -3862,10 +3862,10 @@ static int l2cap_security_cfm(struct hci_conn *hcon, u8 status, u8 encrypt) req.scid = cpu_to_le16(l2cap_pi(sk)->scid); req.psm = l2cap_pi(sk)->psm; - l2cap_pi(sk)->ident = l2cap_get_ident(conn); + chan->ident = l2cap_get_ident(conn); l2cap_pi(sk)->conf_state |= L2CAP_CONF_CONNECT_PEND; - l2cap_send_cmd(conn, l2cap_pi(sk)->ident, + l2cap_send_cmd(conn, chan->ident, L2CAP_CONN_REQ, sizeof(req), &req); } else { l2cap_sock_clear_timer(sk); @@ -3888,8 +3888,8 @@ static int l2cap_security_cfm(struct hci_conn *hcon, u8 status, u8 encrypt) rsp.dcid = cpu_to_le16(l2cap_pi(sk)->scid); rsp.result = cpu_to_le16(result); rsp.status = cpu_to_le16(L2CAP_CS_NO_INFO); - l2cap_send_cmd(conn, l2cap_pi(sk)->ident, - L2CAP_CONN_RSP, sizeof(rsp), &rsp); + l2cap_send_cmd(conn, chan->ident, L2CAP_CONN_RSP, + sizeof(rsp), &rsp); } bh_unlock_sock(sk); diff --git a/net/bluetooth/l2cap_sock.c b/net/bluetooth/l2cap_sock.c index 7df8118..cad4bc7 100644 --- a/net/bluetooth/l2cap_sock.c +++ b/net/bluetooth/l2cap_sock.c @@ -818,7 +818,7 @@ static int l2cap_sock_recvmsg(struct kiocb *iocb, struct socket *sock, struct ms rsp.dcid = cpu_to_le16(l2cap_pi(sk)->scid); rsp.result = cpu_to_le16(L2CAP_CR_SUCCESS); rsp.status = cpu_to_le16(L2CAP_CS_NO_INFO); - l2cap_send_cmd(l2cap_pi(sk)->conn, l2cap_pi(sk)->ident, + l2cap_send_cmd(l2cap_pi(sk)->conn, l2cap_pi(sk)->chan->ident, L2CAP_CONN_RSP, sizeof(rsp), &rsp); if (l2cap_pi(sk)->conf_state & L2CAP_CONF_REQ_SENT) { @@ -921,7 +921,7 @@ void __l2cap_sock_close(struct sock *sk, int reason) rsp.dcid = cpu_to_le16(l2cap_pi(sk)->scid); rsp.result = cpu_to_le16(result); rsp.status = cpu_to_le16(L2CAP_CS_NO_INFO); - l2cap_send_cmd(conn, l2cap_pi(sk)->ident, + l2cap_send_cmd(conn, l2cap_pi(sk)->chan->ident, L2CAP_CONN_RSP, sizeof(rsp), &rsp); } -- cgit v0.10.2 From 73ffa904b78287f6acf8797e040150aa26a4af4a Mon Sep 17 00:00:00 2001 From: "Gustavo F. Padovan" Date: Fri, 25 Mar 2011 14:16:54 -0300 Subject: Bluetooth: Move conf_{req,rsp} stuff to struct l2cap_chan They are also l2cap_chan specific. Signed-off-by: Gustavo F. Padovan diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h index 81829e5..bf91828 100644 --- a/include/net/bluetooth/l2cap.h +++ b/include/net/bluetooth/l2cap.h @@ -281,6 +281,11 @@ struct l2cap_chan { struct sock *sk; __u8 ident; + __u8 conf_req[64]; + __u8 conf_len; + __u8 num_conf_req; + __u8 num_conf_rsp; + struct list_head list; }; @@ -337,8 +342,6 @@ struct l2cap_pinfo { __u16 omtu; __u16 flush_to; __u8 mode; - __u8 num_conf_req; - __u8 num_conf_rsp; __u8 fcs; __u8 sec_level; @@ -346,8 +349,6 @@ struct l2cap_pinfo { __u8 force_reliable; __u8 flushable; - __u8 conf_req[64]; - __u8 conf_len; __u8 conf_state; __u16 conn_state; @@ -447,7 +448,7 @@ void l2cap_cleanup_sockets(void); u8 l2cap_get_ident(struct l2cap_conn *conn); void l2cap_send_cmd(struct l2cap_conn *conn, u8 ident, u8 code, u16 len, void *data); -int l2cap_build_conf_req(struct sock *sk, void *data); +int l2cap_build_conf_req(struct l2cap_chan *chan, void *data); int __l2cap_wait_ack(struct sock *sk); struct sk_buff *l2cap_create_connless_pdu(struct sock *sk, struct msghdr *msg, size_t len); diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index 6020e1e..cb849b5 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -569,8 +569,8 @@ static void l2cap_conn_start(struct l2cap_conn *conn) l2cap_pi(sk)->conf_state |= L2CAP_CONF_REQ_SENT; l2cap_send_cmd(conn, l2cap_get_ident(conn), L2CAP_CONF_REQ, - l2cap_build_conf_req(sk, buf), buf); - l2cap_pi(sk)->num_conf_req++; + l2cap_build_conf_req(chan, buf), buf); + chan->num_conf_req++; } bh_unlock_sock(sk); @@ -1598,8 +1598,9 @@ static inline __u8 l2cap_select_mode(__u8 mode, __u16 remote_feat_mask) } } -int l2cap_build_conf_req(struct sock *sk, void *data) +int l2cap_build_conf_req(struct l2cap_chan *chan, void *data) { + struct sock *sk = chan->sk; struct l2cap_pinfo *pi = l2cap_pi(sk); struct l2cap_conf_req *req = data; struct l2cap_conf_rfc rfc = { .mode = pi->mode }; @@ -1607,7 +1608,7 @@ int l2cap_build_conf_req(struct sock *sk, void *data) BT_DBG("sk %p", sk); - if (pi->num_conf_req || pi->num_conf_rsp) + if (chan->num_conf_req || chan->num_conf_rsp) goto done; switch (pi->mode) { @@ -1696,20 +1697,20 @@ done: return ptr - data; } -static int l2cap_parse_conf_req(struct sock *sk, void *data) +static int l2cap_parse_conf_req(struct l2cap_chan *chan, void *data) { - struct l2cap_pinfo *pi = l2cap_pi(sk); + struct l2cap_pinfo *pi = l2cap_pi(chan->sk); struct l2cap_conf_rsp *rsp = data; void *ptr = rsp->data; - void *req = pi->conf_req; - int len = pi->conf_len; + void *req = chan->conf_req; + int len = chan->conf_len; int type, hint, olen; unsigned long val; struct l2cap_conf_rfc rfc = { .mode = L2CAP_MODE_BASIC }; u16 mtu = L2CAP_DEFAULT_MTU; u16 result = L2CAP_CONF_SUCCESS; - BT_DBG("sk %p", sk); + BT_DBG("chan %p", chan); while (len >= L2CAP_CONF_OPT_SIZE) { len -= l2cap_get_conf_opt(&req, &type, &olen, &val); @@ -1750,7 +1751,7 @@ static int l2cap_parse_conf_req(struct sock *sk, void *data) } } - if (pi->num_conf_rsp || pi->num_conf_req > 1) + if (chan->num_conf_rsp || chan->num_conf_req > 1) goto done; switch (pi->mode) { @@ -1773,7 +1774,7 @@ done: result = L2CAP_CONF_UNACCEPT; rfc.mode = pi->mode; - if (pi->num_conf_rsp == 1) + if (chan->num_conf_rsp == 1) return -ECONNREFUSED; l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC, @@ -1992,7 +1993,7 @@ static inline int l2cap_connect_req(struct l2cap_conn *conn, struct l2cap_cmd_hd { struct l2cap_conn_req *req = (struct l2cap_conn_req *) data; struct l2cap_conn_rsp rsp; - struct l2cap_chan *chan; + struct l2cap_chan *chan = NULL; struct sock *parent, *sk = NULL; int result, status = L2CAP_CS_NO_INFO; @@ -2115,13 +2116,13 @@ sendresp: L2CAP_INFO_REQ, sizeof(info), &info); } - if (sk && !(l2cap_pi(sk)->conf_state & L2CAP_CONF_REQ_SENT) && + if (chan && !(l2cap_pi(sk)->conf_state & L2CAP_CONF_REQ_SENT) && result == L2CAP_CR_SUCCESS) { u8 buf[128]; l2cap_pi(sk)->conf_state |= L2CAP_CONF_REQ_SENT; l2cap_send_cmd(conn, l2cap_get_ident(conn), L2CAP_CONF_REQ, - l2cap_build_conf_req(sk, buf), buf); - l2cap_pi(sk)->num_conf_req++; + l2cap_build_conf_req(chan, buf), buf); + chan->num_conf_req++; } return 0; @@ -2167,8 +2168,8 @@ static inline int l2cap_connect_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hd l2cap_pi(sk)->conf_state |= L2CAP_CONF_REQ_SENT; l2cap_send_cmd(conn, l2cap_get_ident(conn), L2CAP_CONF_REQ, - l2cap_build_conf_req(sk, req), req); - l2cap_pi(sk)->num_conf_req++; + l2cap_build_conf_req(chan, req), req); + chan->num_conf_req++; break; case L2CAP_CR_PEND: @@ -2234,7 +2235,7 @@ static inline int l2cap_config_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr /* Reject if config buffer is too small. */ len = cmd_len - sizeof(*req); - if (l2cap_pi(sk)->conf_len + len > sizeof(l2cap_pi(sk)->conf_req)) { + if (chan->conf_len + len > sizeof(chan->conf_req)) { l2cap_send_cmd(conn, cmd->ident, L2CAP_CONF_RSP, l2cap_build_conf_rsp(sk, rsp, L2CAP_CONF_REJECT, flags), rsp); @@ -2242,8 +2243,8 @@ static inline int l2cap_config_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr } /* Store config. */ - memcpy(l2cap_pi(sk)->conf_req + l2cap_pi(sk)->conf_len, req->data, len); - l2cap_pi(sk)->conf_len += len; + memcpy(chan->conf_req + chan->conf_len, req->data, len); + chan->conf_len += len; if (flags & 0x0001) { /* Incomplete config. Send empty response. */ @@ -2254,17 +2255,17 @@ static inline int l2cap_config_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr } /* Complete config. */ - len = l2cap_parse_conf_req(sk, rsp); + len = l2cap_parse_conf_req(chan, rsp); if (len < 0) { l2cap_send_disconn_req(conn, sk, ECONNRESET); goto unlock; } l2cap_send_cmd(conn, cmd->ident, L2CAP_CONF_RSP, len, rsp); - l2cap_pi(sk)->num_conf_rsp++; + chan->num_conf_rsp++; /* Reset config buffer. */ - l2cap_pi(sk)->conf_len = 0; + chan->conf_len = 0; if (!(l2cap_pi(sk)->conf_state & L2CAP_CONF_OUTPUT_DONE)) goto unlock; @@ -2288,8 +2289,8 @@ static inline int l2cap_config_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr u8 buf[64]; l2cap_pi(sk)->conf_state |= L2CAP_CONF_REQ_SENT; l2cap_send_cmd(conn, l2cap_get_ident(conn), L2CAP_CONF_REQ, - l2cap_build_conf_req(sk, buf), buf); - l2cap_pi(sk)->num_conf_req++; + l2cap_build_conf_req(chan, buf), buf); + chan->num_conf_req++; } unlock: @@ -2324,7 +2325,7 @@ static inline int l2cap_config_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hdr break; case L2CAP_CONF_UNACCEPT: - if (l2cap_pi(sk)->num_conf_rsp <= L2CAP_CONF_MAX_CONF_RSP) { + if (chan->num_conf_rsp <= L2CAP_CONF_MAX_CONF_RSP) { char req[64]; if (len > sizeof(req) - sizeof(struct l2cap_conf_req)) { @@ -2343,7 +2344,7 @@ static inline int l2cap_config_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hdr l2cap_send_cmd(conn, l2cap_get_ident(conn), L2CAP_CONF_REQ, len, req); - l2cap_pi(sk)->num_conf_req++; + chan->num_conf_req++; if (result != L2CAP_CONF_SUCCESS) goto done; break; diff --git a/net/bluetooth/l2cap_sock.c b/net/bluetooth/l2cap_sock.c index cad4bc7..244475e 100644 --- a/net/bluetooth/l2cap_sock.c +++ b/net/bluetooth/l2cap_sock.c @@ -810,6 +810,7 @@ static int l2cap_sock_recvmsg(struct kiocb *iocb, struct socket *sock, struct ms if (sk->sk_state == BT_CONNECT2 && bt_sk(sk)->defer_setup) { struct l2cap_conn_rsp rsp; struct l2cap_conn *conn = l2cap_pi(sk)->conn; + struct l2cap_chan *chan = l2cap_pi(sk)->chan; u8 buf[128]; sk->sk_state = BT_CONFIG; @@ -818,7 +819,7 @@ static int l2cap_sock_recvmsg(struct kiocb *iocb, struct socket *sock, struct ms rsp.dcid = cpu_to_le16(l2cap_pi(sk)->scid); rsp.result = cpu_to_le16(L2CAP_CR_SUCCESS); rsp.status = cpu_to_le16(L2CAP_CS_NO_INFO); - l2cap_send_cmd(l2cap_pi(sk)->conn, l2cap_pi(sk)->chan->ident, + l2cap_send_cmd(l2cap_pi(sk)->conn, chan->ident, L2CAP_CONN_RSP, sizeof(rsp), &rsp); if (l2cap_pi(sk)->conf_state & L2CAP_CONF_REQ_SENT) { @@ -828,8 +829,8 @@ static int l2cap_sock_recvmsg(struct kiocb *iocb, struct socket *sock, struct ms l2cap_pi(sk)->conf_state |= L2CAP_CONF_REQ_SENT; l2cap_send_cmd(conn, l2cap_get_ident(conn), L2CAP_CONF_REQ, - l2cap_build_conf_req(sk, buf), buf); - l2cap_pi(sk)->num_conf_req++; + l2cap_build_conf_req(chan, buf), buf); + chan->num_conf_req++; release_sock(sk); return 0; @@ -1035,7 +1036,6 @@ void l2cap_sock_init(struct sock *sk, struct sock *parent) } /* Default config options */ - pi->conf_len = 0; pi->flush_to = L2CAP_DEFAULT_FLUSH_TO; skb_queue_head_init(TX_QUEUE(sk)); skb_queue_head_init(SREJ_QUEUE(sk)); -- cgit v0.10.2 From 710f9b0a423cad155144742f6497efe5163ed750 Mon Sep 17 00:00:00 2001 From: "Gustavo F. Padovan" Date: Fri, 25 Mar 2011 14:30:37 -0300 Subject: Bluetooth: clean up l2cap_sock_recvmsg() Move some channel specific stuff to l2cap_core.c, this will make things more clear. Signed-off-by: Gustavo F. Padovan diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h index bf91828..4692413 100644 --- a/include/net/bluetooth/l2cap.h +++ b/include/net/bluetooth/l2cap.h @@ -446,9 +446,8 @@ extern struct bt_sock_list l2cap_sk_list; int l2cap_init_sockets(void); void l2cap_cleanup_sockets(void); -u8 l2cap_get_ident(struct l2cap_conn *conn); void l2cap_send_cmd(struct l2cap_conn *conn, u8 ident, u8 code, u16 len, void *data); -int l2cap_build_conf_req(struct l2cap_chan *chan, void *data); +void __l2cap_connect_rsp_defer(struct sock *sk); int __l2cap_wait_ack(struct sock *sk); struct sk_buff *l2cap_create_connless_pdu(struct sock *sk, struct msghdr *msg, size_t len); diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index cb849b5..b41e21f 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -70,6 +70,7 @@ static void l2cap_busy_work(struct work_struct *work); static struct sk_buff *l2cap_build_cmd(struct l2cap_conn *conn, u8 code, u8 ident, u16 dlen, void *data); +static int l2cap_build_conf_req(struct l2cap_chan *chan, void *data); static int l2cap_ertm_data_rcv(struct sock *sk, struct sk_buff *skb); @@ -1598,7 +1599,7 @@ static inline __u8 l2cap_select_mode(__u8 mode, __u16 remote_feat_mask) } } -int l2cap_build_conf_req(struct l2cap_chan *chan, void *data) +static int l2cap_build_conf_req(struct l2cap_chan *chan, void *data) { struct sock *sk = chan->sk; struct l2cap_pinfo *pi = l2cap_pi(sk); @@ -1934,6 +1935,31 @@ static int l2cap_build_conf_rsp(struct sock *sk, void *data, u16 result, u16 fla return ptr - data; } +void __l2cap_connect_rsp_defer(struct sock *sk) +{ + struct l2cap_conn_rsp rsp; + struct l2cap_conn *conn = l2cap_pi(sk)->conn; + struct l2cap_chan *chan = l2cap_pi(sk)->chan; + u8 buf[128]; + + sk->sk_state = BT_CONFIG; + + rsp.scid = cpu_to_le16(l2cap_pi(sk)->dcid); + rsp.dcid = cpu_to_le16(l2cap_pi(sk)->scid); + rsp.result = cpu_to_le16(L2CAP_CR_SUCCESS); + rsp.status = cpu_to_le16(L2CAP_CS_NO_INFO); + l2cap_send_cmd(conn, chan->ident, + L2CAP_CONN_RSP, sizeof(rsp), &rsp); + + if (l2cap_pi(sk)->conf_state & L2CAP_CONF_REQ_SENT) + return; + + l2cap_pi(sk)->conf_state |= L2CAP_CONF_REQ_SENT; + l2cap_send_cmd(conn, l2cap_get_ident(conn), L2CAP_CONF_REQ, + l2cap_build_conf_req(chan, buf), buf); + chan->num_conf_req++; +} + static void l2cap_conf_rfc_get(struct sock *sk, void *rsp, int len) { struct l2cap_pinfo *pi = l2cap_pi(sk); diff --git a/net/bluetooth/l2cap_sock.c b/net/bluetooth/l2cap_sock.c index 244475e..450f57b 100644 --- a/net/bluetooth/l2cap_sock.c +++ b/net/bluetooth/l2cap_sock.c @@ -808,30 +808,7 @@ static int l2cap_sock_recvmsg(struct kiocb *iocb, struct socket *sock, struct ms lock_sock(sk); if (sk->sk_state == BT_CONNECT2 && bt_sk(sk)->defer_setup) { - struct l2cap_conn_rsp rsp; - struct l2cap_conn *conn = l2cap_pi(sk)->conn; - struct l2cap_chan *chan = l2cap_pi(sk)->chan; - u8 buf[128]; - - sk->sk_state = BT_CONFIG; - - rsp.scid = cpu_to_le16(l2cap_pi(sk)->dcid); - rsp.dcid = cpu_to_le16(l2cap_pi(sk)->scid); - rsp.result = cpu_to_le16(L2CAP_CR_SUCCESS); - rsp.status = cpu_to_le16(L2CAP_CS_NO_INFO); - l2cap_send_cmd(l2cap_pi(sk)->conn, chan->ident, - L2CAP_CONN_RSP, sizeof(rsp), &rsp); - - if (l2cap_pi(sk)->conf_state & L2CAP_CONF_REQ_SENT) { - release_sock(sk); - return 0; - } - - l2cap_pi(sk)->conf_state |= L2CAP_CONF_REQ_SENT; - l2cap_send_cmd(conn, l2cap_get_ident(conn), L2CAP_CONF_REQ, - l2cap_build_conf_req(chan, buf), buf); - chan->num_conf_req++; - + __l2cap_connect_rsp_defer(sk); release_sock(sk); return 0; } -- cgit v0.10.2 From 525cd1851b9faaadf5ea33e05192b8d22f42487e Mon Sep 17 00:00:00 2001 From: "Gustavo F. Padovan" Date: Fri, 25 Mar 2011 19:43:39 -0300 Subject: Bluetooth: Move conn_state to struct l2cap_chan This is part of "moving things to l2cap_chan". As one the first move it triggered a big number of changes in the funcions parameters, basically changing the struct sock param to struct l2cap_chan. Signed-off-by: Gustavo F. Padovan diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h index 4692413..82d5b81 100644 --- a/include/net/bluetooth/l2cap.h +++ b/include/net/bluetooth/l2cap.h @@ -286,6 +286,8 @@ struct l2cap_chan { __u8 num_conf_req; __u8 num_conf_rsp; + __u16 conn_state; + struct list_head list; }; @@ -350,7 +352,6 @@ struct l2cap_pinfo { __u8 flushable; __u8 conf_state; - __u16 conn_state; __u8 next_tx_seq; __u8 expected_ack_seq; @@ -456,7 +457,7 @@ struct sk_buff *l2cap_create_iframe_pdu(struct sock *sk, struct msghdr *msg, siz int l2cap_sar_segment_sdu(struct sock *sk, struct msghdr *msg, size_t len); void l2cap_do_send(struct sock *sk, struct sk_buff *skb); void l2cap_streaming_send(struct sock *sk); -int l2cap_ertm_send(struct sock *sk); +int l2cap_ertm_send(struct l2cap_chan *chan); void l2cap_sock_set_timer(struct sock *sk, long timeout); void l2cap_sock_clear_timer(struct sock *sk); diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index b41e21f..b5435cd 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -340,10 +340,11 @@ void l2cap_send_cmd(struct l2cap_conn *conn, u8 ident, u8 code, u16 len, void *d hci_send_acl(conn->hcon, skb, flags); } -static inline void l2cap_send_sframe(struct l2cap_pinfo *pi, u16 control) +static inline void l2cap_send_sframe(struct l2cap_chan *chan, u16 control) { struct sk_buff *skb; struct l2cap_hdr *lh; + struct l2cap_pinfo *pi = l2cap_pi(chan->sk); struct l2cap_conn *conn = pi->conn; struct sock *sk = (struct sock *)pi; int count, hlen = L2CAP_HDR_SIZE + 2; @@ -360,14 +361,14 @@ static inline void l2cap_send_sframe(struct l2cap_pinfo *pi, u16 control) count = min_t(unsigned int, conn->mtu, hlen); control |= L2CAP_CTRL_FRAME_TYPE; - if (pi->conn_state & L2CAP_CONN_SEND_FBIT) { + if (chan->conn_state & L2CAP_CONN_SEND_FBIT) { control |= L2CAP_CTRL_FINAL; - pi->conn_state &= ~L2CAP_CONN_SEND_FBIT; + chan->conn_state &= ~L2CAP_CONN_SEND_FBIT; } - if (pi->conn_state & L2CAP_CONN_SEND_PBIT) { + if (chan->conn_state & L2CAP_CONN_SEND_PBIT) { control |= L2CAP_CTRL_POLL; - pi->conn_state &= ~L2CAP_CONN_SEND_PBIT; + chan->conn_state &= ~L2CAP_CONN_SEND_PBIT; } skb = bt_skb_alloc(count, GFP_ATOMIC); @@ -392,17 +393,19 @@ static inline void l2cap_send_sframe(struct l2cap_pinfo *pi, u16 control) hci_send_acl(pi->conn->hcon, skb, flags); } -static inline void l2cap_send_rr_or_rnr(struct l2cap_pinfo *pi, u16 control) +static inline void l2cap_send_rr_or_rnr(struct l2cap_chan *chan, u16 control) { - if (pi->conn_state & L2CAP_CONN_LOCAL_BUSY) { + struct l2cap_pinfo *pi = l2cap_pi(chan->sk); + + if (chan->conn_state & L2CAP_CONN_LOCAL_BUSY) { control |= L2CAP_SUPER_RCV_NOT_READY; - pi->conn_state |= L2CAP_CONN_RNR_SENT; + chan->conn_state |= L2CAP_CONN_RNR_SENT; } else control |= L2CAP_SUPER_RCV_READY; control |= pi->buffer_seq << L2CAP_CTRL_REQSEQ_SHIFT; - l2cap_send_sframe(pi, control); + l2cap_send_sframe(chan, control); } static inline int __l2cap_no_conn_pending(struct sock *sk) @@ -949,9 +952,10 @@ int __l2cap_wait_ack(struct sock *sk) static void l2cap_monitor_timeout(unsigned long arg) { - struct sock *sk = (void *) arg; + struct l2cap_chan *chan = (void *) arg; + struct sock *sk = chan->sk; - BT_DBG("sk %p", sk); + BT_DBG("chan %p", chan); bh_lock_sock(sk); if (l2cap_pi(sk)->retry_count >= l2cap_pi(sk)->remote_max_tx) { @@ -963,13 +967,14 @@ static void l2cap_monitor_timeout(unsigned long arg) l2cap_pi(sk)->retry_count++; __mod_monitor_timer(); - l2cap_send_rr_or_rnr(l2cap_pi(sk), L2CAP_CTRL_POLL); + l2cap_send_rr_or_rnr(chan, L2CAP_CTRL_POLL); bh_unlock_sock(sk); } static void l2cap_retrans_timeout(unsigned long arg) { - struct sock *sk = (void *) arg; + struct l2cap_chan *chan = (void *) arg; + struct sock *sk = chan->sk; BT_DBG("sk %p", sk); @@ -977,9 +982,9 @@ static void l2cap_retrans_timeout(unsigned long arg) l2cap_pi(sk)->retry_count = 1; __mod_monitor_timer(); - l2cap_pi(sk)->conn_state |= L2CAP_CONN_WAIT_F; + chan->conn_state |= L2CAP_CONN_WAIT_F; - l2cap_send_rr_or_rnr(l2cap_pi(sk), L2CAP_CTRL_POLL); + l2cap_send_rr_or_rnr(chan, L2CAP_CTRL_POLL); bh_unlock_sock(sk); } @@ -1040,8 +1045,9 @@ void l2cap_streaming_send(struct sock *sk) } } -static void l2cap_retransmit_one_frame(struct sock *sk, u8 tx_seq) +static void l2cap_retransmit_one_frame(struct l2cap_chan *chan, u8 tx_seq) { + struct sock *sk = chan->sk; struct l2cap_pinfo *pi = l2cap_pi(sk); struct sk_buff *skb, *tx_skb; u16 control, fcs; @@ -1069,9 +1075,9 @@ static void l2cap_retransmit_one_frame(struct sock *sk, u8 tx_seq) bt_cb(skb)->retries++; control = get_unaligned_le16(tx_skb->data + L2CAP_HDR_SIZE); - if (pi->conn_state & L2CAP_CONN_SEND_FBIT) { + if (chan->conn_state & L2CAP_CONN_SEND_FBIT) { control |= L2CAP_CTRL_FINAL; - pi->conn_state &= ~L2CAP_CONN_SEND_FBIT; + chan->conn_state &= ~L2CAP_CONN_SEND_FBIT; } control |= (pi->buffer_seq << L2CAP_CTRL_REQSEQ_SHIFT) @@ -1087,9 +1093,10 @@ static void l2cap_retransmit_one_frame(struct sock *sk, u8 tx_seq) l2cap_do_send(sk, tx_skb); } -int l2cap_ertm_send(struct sock *sk) +int l2cap_ertm_send(struct l2cap_chan *chan) { struct sk_buff *skb, *tx_skb; + struct sock *sk = chan->sk; struct l2cap_pinfo *pi = l2cap_pi(sk); u16 control, fcs; int nsent = 0; @@ -1112,9 +1119,9 @@ int l2cap_ertm_send(struct sock *sk) control = get_unaligned_le16(tx_skb->data + L2CAP_HDR_SIZE); control &= L2CAP_CTRL_SAR; - if (pi->conn_state & L2CAP_CONN_SEND_FBIT) { + if (chan->conn_state & L2CAP_CONN_SEND_FBIT) { control |= L2CAP_CTRL_FINAL; - pi->conn_state &= ~L2CAP_CONN_SEND_FBIT; + chan->conn_state &= ~L2CAP_CONN_SEND_FBIT; } control |= (pi->buffer_seq << L2CAP_CTRL_REQSEQ_SHIFT) | (pi->next_tx_seq << L2CAP_CTRL_TXSEQ_SHIFT); @@ -1149,8 +1156,9 @@ int l2cap_ertm_send(struct sock *sk) return nsent; } -static int l2cap_retransmit_frames(struct sock *sk) +static int l2cap_retransmit_frames(struct l2cap_chan *chan) { + struct sock *sk = chan->sk; struct l2cap_pinfo *pi = l2cap_pi(sk); int ret; @@ -1158,32 +1166,32 @@ static int l2cap_retransmit_frames(struct sock *sk) sk->sk_send_head = TX_QUEUE(sk)->next; pi->next_tx_seq = pi->expected_ack_seq; - ret = l2cap_ertm_send(sk); + ret = l2cap_ertm_send(chan); return ret; } -static void l2cap_send_ack(struct l2cap_pinfo *pi) +static void l2cap_send_ack(struct l2cap_chan *chan) { - struct sock *sk = (struct sock *)pi; + struct sock *sk = chan->sk; u16 control = 0; - control |= pi->buffer_seq << L2CAP_CTRL_REQSEQ_SHIFT; + control |= l2cap_pi(sk)->buffer_seq << L2CAP_CTRL_REQSEQ_SHIFT; - if (pi->conn_state & L2CAP_CONN_LOCAL_BUSY) { + if (chan->conn_state & L2CAP_CONN_LOCAL_BUSY) { control |= L2CAP_SUPER_RCV_NOT_READY; - pi->conn_state |= L2CAP_CONN_RNR_SENT; - l2cap_send_sframe(pi, control); + chan->conn_state |= L2CAP_CONN_RNR_SENT; + l2cap_send_sframe(chan, control); return; } - if (l2cap_ertm_send(sk) > 0) + if (l2cap_ertm_send(chan) > 0) return; control |= L2CAP_SUPER_RCV_READY; - l2cap_send_sframe(pi, control); + l2cap_send_sframe(chan, control); } -static void l2cap_send_srejtail(struct sock *sk) +static void l2cap_send_srejtail(struct l2cap_chan *chan) { struct srej_list *tail; u16 control; @@ -1191,10 +1199,10 @@ static void l2cap_send_srejtail(struct sock *sk) control = L2CAP_SUPER_SELECT_REJECT; control |= L2CAP_CTRL_FINAL; - tail = list_entry(SREJ_LIST(sk)->prev, struct srej_list, list); + tail = list_entry(SREJ_LIST(chan->sk)->prev, struct srej_list, list); control |= tail->tx_seq << L2CAP_CTRL_REQSEQ_SHIFT; - l2cap_send_sframe(l2cap_pi(sk), control); + l2cap_send_sframe(chan, control); } static inline int l2cap_skbuff_fromiovec(struct sock *sk, struct msghdr *msg, int len, int count, struct sk_buff *skb) @@ -1556,15 +1564,17 @@ static void l2cap_add_conf_opt(void **ptr, u8 type, u8 len, unsigned long val) static void l2cap_ack_timeout(unsigned long arg) { - struct sock *sk = (void *) arg; + struct l2cap_chan *chan = (void *) arg; - bh_lock_sock(sk); - l2cap_send_ack(l2cap_pi(sk)); - bh_unlock_sock(sk); + bh_lock_sock(chan->sk); + l2cap_send_ack(chan); + bh_unlock_sock(chan->sk); } -static inline void l2cap_ertm_init(struct sock *sk) +static inline void l2cap_ertm_init(struct l2cap_chan *chan) { + struct sock *sk = chan->sk; + l2cap_pi(sk)->expected_ack_seq = 0; l2cap_pi(sk)->unacked_frames = 0; l2cap_pi(sk)->buffer_seq = 0; @@ -1572,11 +1582,11 @@ static inline void l2cap_ertm_init(struct sock *sk) l2cap_pi(sk)->frames_sent = 0; setup_timer(&l2cap_pi(sk)->retrans_timer, - l2cap_retrans_timeout, (unsigned long) sk); + l2cap_retrans_timeout, (unsigned long) chan); setup_timer(&l2cap_pi(sk)->monitor_timer, - l2cap_monitor_timeout, (unsigned long) sk); + l2cap_monitor_timeout, (unsigned long) chan); setup_timer(&l2cap_pi(sk)->ack_timer, - l2cap_ack_timeout, (unsigned long) sk); + l2cap_ack_timeout, (unsigned long) chan); __skb_queue_head_init(SREJ_QUEUE(sk)); __skb_queue_head_init(BUSY_QUEUE(sk)); @@ -2305,7 +2315,7 @@ static inline int l2cap_config_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr l2cap_pi(sk)->expected_tx_seq = 0; __skb_queue_head_init(TX_QUEUE(sk)); if (l2cap_pi(sk)->mode == L2CAP_MODE_ERTM) - l2cap_ertm_init(sk); + l2cap_ertm_init(chan); l2cap_chan_ready(sk); goto unlock; @@ -2396,7 +2406,7 @@ static inline int l2cap_config_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hdr l2cap_pi(sk)->expected_tx_seq = 0; __skb_queue_head_init(TX_QUEUE(sk)); if (l2cap_pi(sk)->mode == L2CAP_MODE_ERTM) - l2cap_ertm_init(sk); + l2cap_ertm_init(chan); l2cap_chan_ready(sk); } @@ -2777,30 +2787,30 @@ static int l2cap_check_fcs(struct l2cap_pinfo *pi, struct sk_buff *skb) return 0; } -static inline void l2cap_send_i_or_rr_or_rnr(struct sock *sk) +static inline void l2cap_send_i_or_rr_or_rnr(struct l2cap_chan *chan) { - struct l2cap_pinfo *pi = l2cap_pi(sk); + struct l2cap_pinfo *pi = l2cap_pi(chan->sk); u16 control = 0; pi->frames_sent = 0; control |= pi->buffer_seq << L2CAP_CTRL_REQSEQ_SHIFT; - if (pi->conn_state & L2CAP_CONN_LOCAL_BUSY) { + if (chan->conn_state & L2CAP_CONN_LOCAL_BUSY) { control |= L2CAP_SUPER_RCV_NOT_READY; - l2cap_send_sframe(pi, control); - pi->conn_state |= L2CAP_CONN_RNR_SENT; + l2cap_send_sframe(chan, control); + chan->conn_state |= L2CAP_CONN_RNR_SENT; } - if (pi->conn_state & L2CAP_CONN_REMOTE_BUSY) - l2cap_retransmit_frames(sk); + if (chan->conn_state & L2CAP_CONN_REMOTE_BUSY) + l2cap_retransmit_frames(chan); - l2cap_ertm_send(sk); + l2cap_ertm_send(chan); - if (!(pi->conn_state & L2CAP_CONN_LOCAL_BUSY) && + if (!(chan->conn_state & L2CAP_CONN_LOCAL_BUSY) && pi->frames_sent == 0) { control |= L2CAP_SUPER_RCV_READY; - l2cap_send_sframe(pi, control); + l2cap_send_sframe(chan, control); } } @@ -2847,25 +2857,25 @@ static int l2cap_add_to_srej_queue(struct sock *sk, struct sk_buff *skb, u8 tx_s return 0; } -static int l2cap_ertm_reassembly_sdu(struct sock *sk, struct sk_buff *skb, u16 control) +static int l2cap_ertm_reassembly_sdu(struct l2cap_chan *chan, struct sk_buff *skb, u16 control) { - struct l2cap_pinfo *pi = l2cap_pi(sk); + struct l2cap_pinfo *pi = l2cap_pi(chan->sk); struct sk_buff *_skb; int err; switch (control & L2CAP_CTRL_SAR) { case L2CAP_SDU_UNSEGMENTED: - if (pi->conn_state & L2CAP_CONN_SAR_SDU) + if (chan->conn_state & L2CAP_CONN_SAR_SDU) goto drop; - err = sock_queue_rcv_skb(sk, skb); + err = sock_queue_rcv_skb(chan->sk, skb); if (!err) return err; break; case L2CAP_SDU_START: - if (pi->conn_state & L2CAP_CONN_SAR_SDU) + if (chan->conn_state & L2CAP_CONN_SAR_SDU) goto drop; pi->sdu_len = get_unaligned_le16(skb->data); @@ -2884,12 +2894,12 @@ static int l2cap_ertm_reassembly_sdu(struct sock *sk, struct sk_buff *skb, u16 c memcpy(skb_put(pi->sdu, skb->len), skb->data, skb->len); - pi->conn_state |= L2CAP_CONN_SAR_SDU; + chan->conn_state |= L2CAP_CONN_SAR_SDU; pi->partial_sdu_len = skb->len; break; case L2CAP_SDU_CONTINUE: - if (!(pi->conn_state & L2CAP_CONN_SAR_SDU)) + if (!(chan->conn_state & L2CAP_CONN_SAR_SDU)) goto disconnect; if (!pi->sdu) @@ -2904,13 +2914,13 @@ static int l2cap_ertm_reassembly_sdu(struct sock *sk, struct sk_buff *skb, u16 c break; case L2CAP_SDU_END: - if (!(pi->conn_state & L2CAP_CONN_SAR_SDU)) + if (!(chan->conn_state & L2CAP_CONN_SAR_SDU)) goto disconnect; if (!pi->sdu) goto disconnect; - if (!(pi->conn_state & L2CAP_CONN_SAR_RETRY)) { + if (!(chan->conn_state & L2CAP_CONN_SAR_RETRY)) { pi->partial_sdu_len += skb->len; if (pi->partial_sdu_len > pi->imtu) @@ -2924,19 +2934,19 @@ static int l2cap_ertm_reassembly_sdu(struct sock *sk, struct sk_buff *skb, u16 c _skb = skb_clone(pi->sdu, GFP_ATOMIC); if (!_skb) { - pi->conn_state |= L2CAP_CONN_SAR_RETRY; + chan->conn_state |= L2CAP_CONN_SAR_RETRY; return -ENOMEM; } - err = sock_queue_rcv_skb(sk, _skb); + err = sock_queue_rcv_skb(chan->sk, _skb); if (err < 0) { kfree_skb(_skb); - pi->conn_state |= L2CAP_CONN_SAR_RETRY; + chan->conn_state |= L2CAP_CONN_SAR_RETRY; return err; } - pi->conn_state &= ~L2CAP_CONN_SAR_RETRY; - pi->conn_state &= ~L2CAP_CONN_SAR_SDU; + chan->conn_state &= ~L2CAP_CONN_SAR_RETRY; + chan->conn_state &= ~L2CAP_CONN_SAR_SDU; kfree_skb(pi->sdu); break; @@ -2950,13 +2960,14 @@ drop: pi->sdu = NULL; disconnect: - l2cap_send_disconn_req(pi->conn, sk, ECONNRESET); + l2cap_send_disconn_req(pi->conn, chan->sk, ECONNRESET); kfree_skb(skb); return 0; } -static int l2cap_try_push_rx_skb(struct sock *sk) +static int l2cap_try_push_rx_skb(struct l2cap_chan *chan) { + struct sock *sk = chan->sk; struct l2cap_pinfo *pi = l2cap_pi(sk); struct sk_buff *skb; u16 control; @@ -2964,7 +2975,7 @@ static int l2cap_try_push_rx_skb(struct sock *sk) while ((skb = skb_dequeue(BUSY_QUEUE(sk)))) { control = bt_cb(skb)->sar << L2CAP_CTRL_SAR_SHIFT; - err = l2cap_ertm_reassembly_sdu(sk, skb, control); + err = l2cap_ertm_reassembly_sdu(chan, skb, control); if (err < 0) { skb_queue_head(BUSY_QUEUE(sk), skb); return -EBUSY; @@ -2973,22 +2984,22 @@ static int l2cap_try_push_rx_skb(struct sock *sk) pi->buffer_seq = (pi->buffer_seq + 1) % 64; } - if (!(pi->conn_state & L2CAP_CONN_RNR_SENT)) + if (!(chan->conn_state & L2CAP_CONN_RNR_SENT)) goto done; control = pi->buffer_seq << L2CAP_CTRL_REQSEQ_SHIFT; control |= L2CAP_SUPER_RCV_READY | L2CAP_CTRL_POLL; - l2cap_send_sframe(pi, control); + l2cap_send_sframe(chan, control); l2cap_pi(sk)->retry_count = 1; del_timer(&pi->retrans_timer); __mod_monitor_timer(); - l2cap_pi(sk)->conn_state |= L2CAP_CONN_WAIT_F; + chan->conn_state |= L2CAP_CONN_WAIT_F; done: - pi->conn_state &= ~L2CAP_CONN_LOCAL_BUSY; - pi->conn_state &= ~L2CAP_CONN_RNR_SENT; + chan->conn_state &= ~L2CAP_CONN_LOCAL_BUSY; + chan->conn_state &= ~L2CAP_CONN_RNR_SENT; BT_DBG("sk %p, Exit local busy", sk); @@ -3032,7 +3043,7 @@ static void l2cap_busy_work(struct work_struct *work) if (err) break; - if (l2cap_try_push_rx_skb(sk) == 0) + if (l2cap_try_push_rx_skb(l2cap_pi(sk)->chan) == 0) break; } @@ -3042,20 +3053,21 @@ static void l2cap_busy_work(struct work_struct *work) release_sock(sk); } -static int l2cap_push_rx_skb(struct sock *sk, struct sk_buff *skb, u16 control) +static int l2cap_push_rx_skb(struct l2cap_chan *chan, struct sk_buff *skb, u16 control) { + struct sock *sk = chan->sk; struct l2cap_pinfo *pi = l2cap_pi(sk); int sctrl, err; - if (pi->conn_state & L2CAP_CONN_LOCAL_BUSY) { + if (chan->conn_state & L2CAP_CONN_LOCAL_BUSY) { bt_cb(skb)->sar = control >> L2CAP_CTRL_SAR_SHIFT; __skb_queue_tail(BUSY_QUEUE(sk), skb); - return l2cap_try_push_rx_skb(sk); + return l2cap_try_push_rx_skb(chan); } - err = l2cap_ertm_reassembly_sdu(sk, skb, control); + err = l2cap_ertm_reassembly_sdu(chan, skb, control); if (err >= 0) { pi->buffer_seq = (pi->buffer_seq + 1) % 64; return err; @@ -3064,15 +3076,15 @@ static int l2cap_push_rx_skb(struct sock *sk, struct sk_buff *skb, u16 control) /* Busy Condition */ BT_DBG("sk %p, Enter local busy", sk); - pi->conn_state |= L2CAP_CONN_LOCAL_BUSY; + chan->conn_state |= L2CAP_CONN_LOCAL_BUSY; bt_cb(skb)->sar = control >> L2CAP_CTRL_SAR_SHIFT; __skb_queue_tail(BUSY_QUEUE(sk), skb); sctrl = pi->buffer_seq << L2CAP_CTRL_REQSEQ_SHIFT; sctrl |= L2CAP_SUPER_RCV_NOT_READY; - l2cap_send_sframe(pi, sctrl); + l2cap_send_sframe(chan, sctrl); - pi->conn_state |= L2CAP_CONN_RNR_SENT; + chan->conn_state |= L2CAP_CONN_RNR_SENT; del_timer(&pi->ack_timer); @@ -3081,9 +3093,9 @@ static int l2cap_push_rx_skb(struct sock *sk, struct sk_buff *skb, u16 control) return err; } -static int l2cap_streaming_reassembly_sdu(struct sock *sk, struct sk_buff *skb, u16 control) +static int l2cap_streaming_reassembly_sdu(struct l2cap_chan *chan, struct sk_buff *skb, u16 control) { - struct l2cap_pinfo *pi = l2cap_pi(sk); + struct l2cap_pinfo *pi = l2cap_pi(chan->sk); struct sk_buff *_skb; int err = -EINVAL; @@ -3094,19 +3106,19 @@ static int l2cap_streaming_reassembly_sdu(struct sock *sk, struct sk_buff *skb, switch (control & L2CAP_CTRL_SAR) { case L2CAP_SDU_UNSEGMENTED: - if (pi->conn_state & L2CAP_CONN_SAR_SDU) { + if (chan->conn_state & L2CAP_CONN_SAR_SDU) { kfree_skb(pi->sdu); break; } - err = sock_queue_rcv_skb(sk, skb); + err = sock_queue_rcv_skb(chan->sk, skb); if (!err) return 0; break; case L2CAP_SDU_START: - if (pi->conn_state & L2CAP_CONN_SAR_SDU) { + if (chan->conn_state & L2CAP_CONN_SAR_SDU) { kfree_skb(pi->sdu); break; } @@ -3127,13 +3139,13 @@ static int l2cap_streaming_reassembly_sdu(struct sock *sk, struct sk_buff *skb, memcpy(skb_put(pi->sdu, skb->len), skb->data, skb->len); - pi->conn_state |= L2CAP_CONN_SAR_SDU; + chan->conn_state |= L2CAP_CONN_SAR_SDU; pi->partial_sdu_len = skb->len; err = 0; break; case L2CAP_SDU_CONTINUE: - if (!(pi->conn_state & L2CAP_CONN_SAR_SDU)) + if (!(chan->conn_state & L2CAP_CONN_SAR_SDU)) break; memcpy(skb_put(pi->sdu, skb->len), skb->data, skb->len); @@ -3147,12 +3159,12 @@ static int l2cap_streaming_reassembly_sdu(struct sock *sk, struct sk_buff *skb, break; case L2CAP_SDU_END: - if (!(pi->conn_state & L2CAP_CONN_SAR_SDU)) + if (!(chan->conn_state & L2CAP_CONN_SAR_SDU)) break; memcpy(skb_put(pi->sdu, skb->len), skb->data, skb->len); - pi->conn_state &= ~L2CAP_CONN_SAR_SDU; + chan->conn_state &= ~L2CAP_CONN_SAR_SDU; pi->partial_sdu_len += skb->len; if (pi->partial_sdu_len > pi->imtu) @@ -3160,7 +3172,7 @@ static int l2cap_streaming_reassembly_sdu(struct sock *sk, struct sk_buff *skb, if (pi->partial_sdu_len == pi->sdu_len) { _skb = skb_clone(pi->sdu, GFP_ATOMIC); - err = sock_queue_rcv_skb(sk, _skb); + err = sock_queue_rcv_skb(chan->sk, _skb); if (err < 0) kfree_skb(_skb); } @@ -3175,8 +3187,9 @@ drop: return err; } -static void l2cap_check_srej_gap(struct sock *sk, u8 tx_seq) +static void l2cap_check_srej_gap(struct l2cap_chan *chan, u8 tx_seq) { + struct sock *sk = chan->sk; struct sk_buff *skb; u16 control; @@ -3186,16 +3199,16 @@ static void l2cap_check_srej_gap(struct sock *sk, u8 tx_seq) skb = skb_dequeue(SREJ_QUEUE(sk)); control = bt_cb(skb)->sar << L2CAP_CTRL_SAR_SHIFT; - l2cap_ertm_reassembly_sdu(sk, skb, control); + l2cap_ertm_reassembly_sdu(chan, skb, control); l2cap_pi(sk)->buffer_seq_srej = (l2cap_pi(sk)->buffer_seq_srej + 1) % 64; tx_seq = (tx_seq + 1) % 64; } } -static void l2cap_resend_srejframe(struct sock *sk, u8 tx_seq) +static void l2cap_resend_srejframe(struct l2cap_chan *chan, u8 tx_seq) { - struct l2cap_pinfo *pi = l2cap_pi(sk); + struct sock *sk = chan->sk; struct srej_list *l, *tmp; u16 control; @@ -3207,14 +3220,15 @@ static void l2cap_resend_srejframe(struct sock *sk, u8 tx_seq) } control = L2CAP_SUPER_SELECT_REJECT; control |= l->tx_seq << L2CAP_CTRL_REQSEQ_SHIFT; - l2cap_send_sframe(pi, control); + l2cap_send_sframe(chan, control); list_del(&l->list); list_add_tail(&l->list, SREJ_LIST(sk)); } } -static void l2cap_send_srejframe(struct sock *sk, u8 tx_seq) +static void l2cap_send_srejframe(struct l2cap_chan *chan, u8 tx_seq) { + struct sock *sk = chan->sk; struct l2cap_pinfo *pi = l2cap_pi(sk); struct srej_list *new; u16 control; @@ -3222,7 +3236,7 @@ static void l2cap_send_srejframe(struct sock *sk, u8 tx_seq) while (tx_seq != pi->expected_tx_seq) { control = L2CAP_SUPER_SELECT_REJECT; control |= pi->expected_tx_seq << L2CAP_CTRL_REQSEQ_SHIFT; - l2cap_send_sframe(pi, control); + l2cap_send_sframe(chan, control); new = kzalloc(sizeof(struct srej_list), GFP_ATOMIC); new->tx_seq = pi->expected_tx_seq; @@ -3232,8 +3246,9 @@ static void l2cap_send_srejframe(struct sock *sk, u8 tx_seq) pi->expected_tx_seq = (pi->expected_tx_seq + 1) % 64; } -static inline int l2cap_data_channel_iframe(struct sock *sk, u16 rx_control, struct sk_buff *skb) +static inline int l2cap_data_channel_iframe(struct l2cap_chan *chan, u16 rx_control, struct sk_buff *skb) { + struct sock *sk = chan->sk; struct l2cap_pinfo *pi = l2cap_pi(sk); u8 tx_seq = __get_txseq(rx_control); u8 req_seq = __get_reqseq(rx_control); @@ -3242,15 +3257,15 @@ static inline int l2cap_data_channel_iframe(struct sock *sk, u16 rx_control, str int num_to_ack = (pi->tx_win/6) + 1; int err = 0; - BT_DBG("sk %p len %d tx_seq %d rx_control 0x%4.4x", sk, skb->len, tx_seq, - rx_control); + BT_DBG("chan %p len %d tx_seq %d rx_control 0x%4.4x", chan, skb->len, + tx_seq, rx_control); if (L2CAP_CTRL_FINAL & rx_control && - l2cap_pi(sk)->conn_state & L2CAP_CONN_WAIT_F) { + chan->conn_state & L2CAP_CONN_WAIT_F) { del_timer(&pi->monitor_timer); if (pi->unacked_frames > 0) __mod_retrans_timer(); - pi->conn_state &= ~L2CAP_CONN_WAIT_F; + chan->conn_state &= ~L2CAP_CONN_WAIT_F; } pi->expected_ack_seq = req_seq; @@ -3269,25 +3284,25 @@ static inline int l2cap_data_channel_iframe(struct sock *sk, u16 rx_control, str goto drop; } - if (pi->conn_state == L2CAP_CONN_LOCAL_BUSY) + if (chan->conn_state == L2CAP_CONN_LOCAL_BUSY) goto drop; - if (pi->conn_state & L2CAP_CONN_SREJ_SENT) { + if (chan->conn_state & L2CAP_CONN_SREJ_SENT) { struct srej_list *first; first = list_first_entry(SREJ_LIST(sk), struct srej_list, list); if (tx_seq == first->tx_seq) { l2cap_add_to_srej_queue(sk, skb, tx_seq, sar); - l2cap_check_srej_gap(sk, tx_seq); + l2cap_check_srej_gap(chan, tx_seq); list_del(&first->list); kfree(first); if (list_empty(SREJ_LIST(sk))) { pi->buffer_seq = pi->buffer_seq_srej; - pi->conn_state &= ~L2CAP_CONN_SREJ_SENT; - l2cap_send_ack(pi); + chan->conn_state &= ~L2CAP_CONN_SREJ_SENT; + l2cap_send_ack(chan); BT_DBG("sk %p, Exit SREJ_SENT", sk); } } else { @@ -3299,11 +3314,11 @@ static inline int l2cap_data_channel_iframe(struct sock *sk, u16 rx_control, str list_for_each_entry(l, SREJ_LIST(sk), list) { if (l->tx_seq == tx_seq) { - l2cap_resend_srejframe(sk, tx_seq); + l2cap_resend_srejframe(chan, tx_seq); return 0; } } - l2cap_send_srejframe(sk, tx_seq); + l2cap_send_srejframe(chan, tx_seq); } } else { expected_tx_seq_offset = @@ -3315,7 +3330,7 @@ static inline int l2cap_data_channel_iframe(struct sock *sk, u16 rx_control, str if (tx_seq_offset < expected_tx_seq_offset) goto drop; - pi->conn_state |= L2CAP_CONN_SREJ_SENT; + chan->conn_state |= L2CAP_CONN_SREJ_SENT; BT_DBG("sk %p, Enter SREJ", sk); @@ -3326,9 +3341,9 @@ static inline int l2cap_data_channel_iframe(struct sock *sk, u16 rx_control, str __skb_queue_head_init(BUSY_QUEUE(sk)); l2cap_add_to_srej_queue(sk, skb, tx_seq, sar); - pi->conn_state |= L2CAP_CONN_SEND_PBIT; + chan->conn_state |= L2CAP_CONN_SEND_PBIT; - l2cap_send_srejframe(sk, tx_seq); + l2cap_send_srejframe(chan, tx_seq); del_timer(&pi->ack_timer); } @@ -3337,29 +3352,29 @@ static inline int l2cap_data_channel_iframe(struct sock *sk, u16 rx_control, str expected: pi->expected_tx_seq = (pi->expected_tx_seq + 1) % 64; - if (pi->conn_state & L2CAP_CONN_SREJ_SENT) { + if (chan->conn_state & L2CAP_CONN_SREJ_SENT) { bt_cb(skb)->tx_seq = tx_seq; bt_cb(skb)->sar = sar; __skb_queue_tail(SREJ_QUEUE(sk), skb); return 0; } - err = l2cap_push_rx_skb(sk, skb, rx_control); + err = l2cap_push_rx_skb(chan, skb, rx_control); if (err < 0) return 0; if (rx_control & L2CAP_CTRL_FINAL) { - if (pi->conn_state & L2CAP_CONN_REJ_ACT) - pi->conn_state &= ~L2CAP_CONN_REJ_ACT; + if (chan->conn_state & L2CAP_CONN_REJ_ACT) + chan->conn_state &= ~L2CAP_CONN_REJ_ACT; else - l2cap_retransmit_frames(sk); + l2cap_retransmit_frames(chan); } __mod_ack_timer(); pi->num_acked = (pi->num_acked + 1) % num_to_ack; if (pi->num_acked == num_to_ack - 1) - l2cap_send_ack(pi); + l2cap_send_ack(chan); return 0; @@ -3368,8 +3383,9 @@ drop: return 0; } -static inline void l2cap_data_channel_rrframe(struct sock *sk, u16 rx_control) +static inline void l2cap_data_channel_rrframe(struct l2cap_chan *chan, u16 rx_control) { + struct sock *sk = chan->sk; struct l2cap_pinfo *pi = l2cap_pi(sk); BT_DBG("sk %p, req_seq %d ctrl 0x%4.4x", sk, __get_reqseq(rx_control), @@ -3379,154 +3395,156 @@ static inline void l2cap_data_channel_rrframe(struct sock *sk, u16 rx_control) l2cap_drop_acked_frames(sk); if (rx_control & L2CAP_CTRL_POLL) { - pi->conn_state |= L2CAP_CONN_SEND_FBIT; - if (pi->conn_state & L2CAP_CONN_SREJ_SENT) { - if ((pi->conn_state & L2CAP_CONN_REMOTE_BUSY) && + chan->conn_state |= L2CAP_CONN_SEND_FBIT; + if (chan->conn_state & L2CAP_CONN_SREJ_SENT) { + if ((chan->conn_state & L2CAP_CONN_REMOTE_BUSY) && (pi->unacked_frames > 0)) __mod_retrans_timer(); - pi->conn_state &= ~L2CAP_CONN_REMOTE_BUSY; - l2cap_send_srejtail(sk); + chan->conn_state &= ~L2CAP_CONN_REMOTE_BUSY; + l2cap_send_srejtail(chan); } else { - l2cap_send_i_or_rr_or_rnr(sk); + l2cap_send_i_or_rr_or_rnr(chan); } } else if (rx_control & L2CAP_CTRL_FINAL) { - pi->conn_state &= ~L2CAP_CONN_REMOTE_BUSY; + chan->conn_state &= ~L2CAP_CONN_REMOTE_BUSY; - if (pi->conn_state & L2CAP_CONN_REJ_ACT) - pi->conn_state &= ~L2CAP_CONN_REJ_ACT; + if (chan->conn_state & L2CAP_CONN_REJ_ACT) + chan->conn_state &= ~L2CAP_CONN_REJ_ACT; else - l2cap_retransmit_frames(sk); + l2cap_retransmit_frames(chan); } else { - if ((pi->conn_state & L2CAP_CONN_REMOTE_BUSY) && + if ((chan->conn_state & L2CAP_CONN_REMOTE_BUSY) && (pi->unacked_frames > 0)) __mod_retrans_timer(); - pi->conn_state &= ~L2CAP_CONN_REMOTE_BUSY; - if (pi->conn_state & L2CAP_CONN_SREJ_SENT) - l2cap_send_ack(pi); + chan->conn_state &= ~L2CAP_CONN_REMOTE_BUSY; + if (chan->conn_state & L2CAP_CONN_SREJ_SENT) + l2cap_send_ack(chan); else - l2cap_ertm_send(sk); + l2cap_ertm_send(chan); } } -static inline void l2cap_data_channel_rejframe(struct sock *sk, u16 rx_control) +static inline void l2cap_data_channel_rejframe(struct l2cap_chan *chan, u16 rx_control) { - struct l2cap_pinfo *pi = l2cap_pi(sk); + struct l2cap_pinfo *pi = l2cap_pi(chan->sk); u8 tx_seq = __get_reqseq(rx_control); - BT_DBG("sk %p, req_seq %d ctrl 0x%4.4x", sk, tx_seq, rx_control); + BT_DBG("chan %p, req_seq %d ctrl 0x%4.4x", chan, tx_seq, rx_control); - pi->conn_state &= ~L2CAP_CONN_REMOTE_BUSY; + chan->conn_state &= ~L2CAP_CONN_REMOTE_BUSY; pi->expected_ack_seq = tx_seq; - l2cap_drop_acked_frames(sk); + l2cap_drop_acked_frames(chan->sk); if (rx_control & L2CAP_CTRL_FINAL) { - if (pi->conn_state & L2CAP_CONN_REJ_ACT) - pi->conn_state &= ~L2CAP_CONN_REJ_ACT; + if (chan->conn_state & L2CAP_CONN_REJ_ACT) + chan->conn_state &= ~L2CAP_CONN_REJ_ACT; else - l2cap_retransmit_frames(sk); + l2cap_retransmit_frames(chan); } else { - l2cap_retransmit_frames(sk); + l2cap_retransmit_frames(chan); - if (pi->conn_state & L2CAP_CONN_WAIT_F) - pi->conn_state |= L2CAP_CONN_REJ_ACT; + if (chan->conn_state & L2CAP_CONN_WAIT_F) + chan->conn_state |= L2CAP_CONN_REJ_ACT; } } -static inline void l2cap_data_channel_srejframe(struct sock *sk, u16 rx_control) +static inline void l2cap_data_channel_srejframe(struct l2cap_chan *chan, u16 rx_control) { - struct l2cap_pinfo *pi = l2cap_pi(sk); + struct l2cap_pinfo *pi = l2cap_pi(chan->sk); u8 tx_seq = __get_reqseq(rx_control); - BT_DBG("sk %p, req_seq %d ctrl 0x%4.4x", sk, tx_seq, rx_control); + BT_DBG("chan %p, req_seq %d ctrl 0x%4.4x", chan, tx_seq, rx_control); - pi->conn_state &= ~L2CAP_CONN_REMOTE_BUSY; + chan->conn_state &= ~L2CAP_CONN_REMOTE_BUSY; if (rx_control & L2CAP_CTRL_POLL) { pi->expected_ack_seq = tx_seq; - l2cap_drop_acked_frames(sk); + l2cap_drop_acked_frames(chan->sk); - pi->conn_state |= L2CAP_CONN_SEND_FBIT; - l2cap_retransmit_one_frame(sk, tx_seq); + chan->conn_state |= L2CAP_CONN_SEND_FBIT; + l2cap_retransmit_one_frame(chan, tx_seq); - l2cap_ertm_send(sk); + l2cap_ertm_send(chan); - if (pi->conn_state & L2CAP_CONN_WAIT_F) { + if (chan->conn_state & L2CAP_CONN_WAIT_F) { pi->srej_save_reqseq = tx_seq; - pi->conn_state |= L2CAP_CONN_SREJ_ACT; + chan->conn_state |= L2CAP_CONN_SREJ_ACT; } } else if (rx_control & L2CAP_CTRL_FINAL) { - if ((pi->conn_state & L2CAP_CONN_SREJ_ACT) && + if ((chan->conn_state & L2CAP_CONN_SREJ_ACT) && pi->srej_save_reqseq == tx_seq) - pi->conn_state &= ~L2CAP_CONN_SREJ_ACT; + chan->conn_state &= ~L2CAP_CONN_SREJ_ACT; else - l2cap_retransmit_one_frame(sk, tx_seq); + l2cap_retransmit_one_frame(chan, tx_seq); } else { - l2cap_retransmit_one_frame(sk, tx_seq); - if (pi->conn_state & L2CAP_CONN_WAIT_F) { + l2cap_retransmit_one_frame(chan, tx_seq); + if (chan->conn_state & L2CAP_CONN_WAIT_F) { pi->srej_save_reqseq = tx_seq; - pi->conn_state |= L2CAP_CONN_SREJ_ACT; + chan->conn_state |= L2CAP_CONN_SREJ_ACT; } } } -static inline void l2cap_data_channel_rnrframe(struct sock *sk, u16 rx_control) +static inline void l2cap_data_channel_rnrframe(struct l2cap_chan *chan, u16 rx_control) { - struct l2cap_pinfo *pi = l2cap_pi(sk); + struct l2cap_pinfo *pi = l2cap_pi(chan->sk); u8 tx_seq = __get_reqseq(rx_control); - BT_DBG("sk %p, req_seq %d ctrl 0x%4.4x", sk, tx_seq, rx_control); + BT_DBG("chan %p, req_seq %d ctrl 0x%4.4x", chan, tx_seq, rx_control); - pi->conn_state |= L2CAP_CONN_REMOTE_BUSY; + chan->conn_state |= L2CAP_CONN_REMOTE_BUSY; pi->expected_ack_seq = tx_seq; - l2cap_drop_acked_frames(sk); + l2cap_drop_acked_frames(chan->sk); if (rx_control & L2CAP_CTRL_POLL) - pi->conn_state |= L2CAP_CONN_SEND_FBIT; + chan->conn_state |= L2CAP_CONN_SEND_FBIT; - if (!(pi->conn_state & L2CAP_CONN_SREJ_SENT)) { + if (!(chan->conn_state & L2CAP_CONN_SREJ_SENT)) { del_timer(&pi->retrans_timer); if (rx_control & L2CAP_CTRL_POLL) - l2cap_send_rr_or_rnr(pi, L2CAP_CTRL_FINAL); + l2cap_send_rr_or_rnr(chan, L2CAP_CTRL_FINAL); return; } if (rx_control & L2CAP_CTRL_POLL) - l2cap_send_srejtail(sk); + l2cap_send_srejtail(chan); else - l2cap_send_sframe(pi, L2CAP_SUPER_RCV_READY); + l2cap_send_sframe(chan, L2CAP_SUPER_RCV_READY); } -static inline int l2cap_data_channel_sframe(struct sock *sk, u16 rx_control, struct sk_buff *skb) +static inline int l2cap_data_channel_sframe(struct l2cap_chan *chan, u16 rx_control, struct sk_buff *skb) { - BT_DBG("sk %p rx_control 0x%4.4x len %d", sk, rx_control, skb->len); + struct sock *sk = chan->sk; + + BT_DBG("chan %p rx_control 0x%4.4x len %d", chan, rx_control, skb->len); if (L2CAP_CTRL_FINAL & rx_control && - l2cap_pi(sk)->conn_state & L2CAP_CONN_WAIT_F) { + chan->conn_state & L2CAP_CONN_WAIT_F) { del_timer(&l2cap_pi(sk)->monitor_timer); if (l2cap_pi(sk)->unacked_frames > 0) __mod_retrans_timer(); - l2cap_pi(sk)->conn_state &= ~L2CAP_CONN_WAIT_F; + chan->conn_state &= ~L2CAP_CONN_WAIT_F; } switch (rx_control & L2CAP_CTRL_SUPERVISE) { case L2CAP_SUPER_RCV_READY: - l2cap_data_channel_rrframe(sk, rx_control); + l2cap_data_channel_rrframe(chan, rx_control); break; case L2CAP_SUPER_REJECT: - l2cap_data_channel_rejframe(sk, rx_control); + l2cap_data_channel_rejframe(chan, rx_control); break; case L2CAP_SUPER_SELECT_REJECT: - l2cap_data_channel_srejframe(sk, rx_control); + l2cap_data_channel_srejframe(chan, rx_control); break; case L2CAP_SUPER_RCV_NOT_READY: - l2cap_data_channel_rnrframe(sk, rx_control); + l2cap_data_channel_rnrframe(chan, rx_control); break; } @@ -3536,6 +3554,7 @@ static inline int l2cap_data_channel_sframe(struct sock *sk, u16 rx_control, str static int l2cap_ertm_data_rcv(struct sock *sk, struct sk_buff *skb) { + struct l2cap_chan *chan = l2cap_pi(sk)->chan; struct l2cap_pinfo *pi = l2cap_pi(sk); u16 control; u8 req_seq; @@ -3586,7 +3605,7 @@ static int l2cap_ertm_data_rcv(struct sock *sk, struct sk_buff *skb) goto drop; } - l2cap_data_channel_iframe(sk, control, skb); + l2cap_data_channel_iframe(chan, control, skb); } else { if (len != 0) { BT_ERR("%d", len); @@ -3594,7 +3613,7 @@ static int l2cap_ertm_data_rcv(struct sock *sk, struct sk_buff *skb) goto drop; } - l2cap_data_channel_sframe(sk, control, skb); + l2cap_data_channel_sframe(chan, control, skb); } return 0; @@ -3675,7 +3694,7 @@ static inline int l2cap_data_channel(struct l2cap_conn *conn, u16 cid, struct sk else pi->expected_tx_seq = (tx_seq + 1) % 64; - l2cap_streaming_reassembly_sdu(sk, skb, control); + l2cap_streaming_reassembly_sdu(chan, skb, control); goto done; diff --git a/net/bluetooth/l2cap_sock.c b/net/bluetooth/l2cap_sock.c index 450f57b..66ec966 100644 --- a/net/bluetooth/l2cap_sock.c +++ b/net/bluetooth/l2cap_sock.c @@ -778,14 +778,16 @@ static int l2cap_sock_sendmsg(struct kiocb *iocb, struct socket *sock, struct ms if (pi->mode == L2CAP_MODE_STREAMING) { l2cap_streaming_send(sk); - } else { - if ((pi->conn_state & L2CAP_CONN_REMOTE_BUSY) && - (pi->conn_state & L2CAP_CONN_WAIT_F)) { - err = len; - break; - } - err = l2cap_ertm_send(sk); + err = len; + break; + } + + if ((pi->chan->conn_state & L2CAP_CONN_REMOTE_BUSY) && + (pi->chan->conn_state & L2CAP_CONN_WAIT_F)) { + err = len; + break; } + err = l2cap_ertm_send(pi->chan); if (err >= 0) err = len; -- cgit v0.10.2 From 42e5c8027bad6f1591032941f0ebf4fc079405c8 Mon Sep 17 00:00:00 2001 From: "Gustavo F. Padovan" Date: Fri, 25 Mar 2011 19:58:34 -0300 Subject: Bluetooth: Move of ERTM *_seq vars to struct l2cap_chan As part of the moving channel to stuff to struct l2cap_chan. Signed-off-by: Gustavo F. Padovan diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h index 82d5b81..9b43874 100644 --- a/include/net/bluetooth/l2cap.h +++ b/include/net/bluetooth/l2cap.h @@ -288,6 +288,12 @@ struct l2cap_chan { __u16 conn_state; + __u8 next_tx_seq; + __u8 expected_ack_seq; + __u8 expected_tx_seq; + __u8 buffer_seq; + __u8 buffer_seq_srej; + struct list_head list; }; @@ -353,11 +359,6 @@ struct l2cap_pinfo { __u8 conf_state; - __u8 next_tx_seq; - __u8 expected_ack_seq; - __u8 expected_tx_seq; - __u8 buffer_seq; - __u8 buffer_seq_srej; __u8 srej_save_reqseq; __u8 frames_sent; __u8 unacked_frames; @@ -421,17 +422,16 @@ struct l2cap_pinfo { #define __mod_ack_timer() mod_timer(&l2cap_pi(sk)->ack_timer, \ jiffies + msecs_to_jiffies(L2CAP_DEFAULT_ACK_TO)); -static inline int l2cap_tx_window_full(struct sock *sk) +static inline int l2cap_tx_window_full(struct l2cap_chan *ch) { - struct l2cap_pinfo *pi = l2cap_pi(sk); int sub; - sub = (pi->next_tx_seq - pi->expected_ack_seq) % 64; + sub = (ch->next_tx_seq - ch->expected_ack_seq) % 64; if (sub < 0) sub += 64; - return sub == pi->remote_tx_win; + return sub == l2cap_pi(ch->sk)->remote_tx_win; } #define __get_txseq(ctrl) (((ctrl) & L2CAP_CTRL_TXSEQ) >> 1) @@ -456,7 +456,7 @@ struct sk_buff *l2cap_create_basic_pdu(struct sock *sk, struct msghdr *msg, size struct sk_buff *l2cap_create_iframe_pdu(struct sock *sk, struct msghdr *msg, size_t len, u16 control, u16 sdulen); int l2cap_sar_segment_sdu(struct sock *sk, struct msghdr *msg, size_t len); void l2cap_do_send(struct sock *sk, struct sk_buff *skb); -void l2cap_streaming_send(struct sock *sk); +void l2cap_streaming_send(struct l2cap_chan *chan); int l2cap_ertm_send(struct l2cap_chan *chan); void l2cap_sock_set_timer(struct sock *sk, long timeout); diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index b5435cd..d975092 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -395,15 +395,13 @@ static inline void l2cap_send_sframe(struct l2cap_chan *chan, u16 control) static inline void l2cap_send_rr_or_rnr(struct l2cap_chan *chan, u16 control) { - struct l2cap_pinfo *pi = l2cap_pi(chan->sk); - if (chan->conn_state & L2CAP_CONN_LOCAL_BUSY) { control |= L2CAP_SUPER_RCV_NOT_READY; chan->conn_state |= L2CAP_CONN_RNR_SENT; } else control |= L2CAP_SUPER_RCV_READY; - control |= pi->buffer_seq << L2CAP_CTRL_REQSEQ_SHIFT; + control |= chan->buffer_seq << L2CAP_CTRL_REQSEQ_SHIFT; l2cap_send_sframe(chan, control); } @@ -988,13 +986,14 @@ static void l2cap_retrans_timeout(unsigned long arg) bh_unlock_sock(sk); } -static void l2cap_drop_acked_frames(struct sock *sk) +static void l2cap_drop_acked_frames(struct l2cap_chan *chan) { + struct sock *sk = chan->sk; struct sk_buff *skb; while ((skb = skb_peek(TX_QUEUE(sk))) && l2cap_pi(sk)->unacked_frames) { - if (bt_cb(skb)->tx_seq == l2cap_pi(sk)->expected_ack_seq) + if (bt_cb(skb)->tx_seq == chan->expected_ack_seq) break; skb = skb_dequeue(TX_QUEUE(sk)); @@ -1023,15 +1022,16 @@ void l2cap_do_send(struct sock *sk, struct sk_buff *skb) hci_send_acl(hcon, skb, flags); } -void l2cap_streaming_send(struct sock *sk) +void l2cap_streaming_send(struct l2cap_chan *chan) { + struct sock *sk = chan->sk; struct sk_buff *skb; struct l2cap_pinfo *pi = l2cap_pi(sk); u16 control, fcs; while ((skb = skb_dequeue(TX_QUEUE(sk)))) { control = get_unaligned_le16(skb->data + L2CAP_HDR_SIZE); - control |= pi->next_tx_seq << L2CAP_CTRL_TXSEQ_SHIFT; + control |= chan->next_tx_seq << L2CAP_CTRL_TXSEQ_SHIFT; put_unaligned_le16(control, skb->data + L2CAP_HDR_SIZE); if (pi->fcs == L2CAP_FCS_CRC16) { @@ -1041,7 +1041,7 @@ void l2cap_streaming_send(struct sock *sk) l2cap_do_send(sk, skb); - pi->next_tx_seq = (pi->next_tx_seq + 1) % 64; + chan->next_tx_seq = (chan->next_tx_seq + 1) % 64; } } @@ -1080,7 +1080,7 @@ static void l2cap_retransmit_one_frame(struct l2cap_chan *chan, u8 tx_seq) chan->conn_state &= ~L2CAP_CONN_SEND_FBIT; } - control |= (pi->buffer_seq << L2CAP_CTRL_REQSEQ_SHIFT) + control |= (chan->buffer_seq << L2CAP_CTRL_REQSEQ_SHIFT) | (tx_seq << L2CAP_CTRL_TXSEQ_SHIFT); put_unaligned_le16(control, tx_skb->data + L2CAP_HDR_SIZE); @@ -1104,7 +1104,7 @@ int l2cap_ertm_send(struct l2cap_chan *chan) if (sk->sk_state != BT_CONNECTED) return -ENOTCONN; - while ((skb = sk->sk_send_head) && (!l2cap_tx_window_full(sk))) { + while ((skb = sk->sk_send_head) && (!l2cap_tx_window_full(chan))) { if (pi->remote_max_tx && bt_cb(skb)->retries == pi->remote_max_tx) { @@ -1123,8 +1123,8 @@ int l2cap_ertm_send(struct l2cap_chan *chan) control |= L2CAP_CTRL_FINAL; chan->conn_state &= ~L2CAP_CONN_SEND_FBIT; } - control |= (pi->buffer_seq << L2CAP_CTRL_REQSEQ_SHIFT) - | (pi->next_tx_seq << L2CAP_CTRL_TXSEQ_SHIFT); + control |= (chan->buffer_seq << L2CAP_CTRL_REQSEQ_SHIFT) + | (chan->next_tx_seq << L2CAP_CTRL_TXSEQ_SHIFT); put_unaligned_le16(control, tx_skb->data + L2CAP_HDR_SIZE); @@ -1137,8 +1137,8 @@ int l2cap_ertm_send(struct l2cap_chan *chan) __mod_retrans_timer(); - bt_cb(skb)->tx_seq = pi->next_tx_seq; - pi->next_tx_seq = (pi->next_tx_seq + 1) % 64; + bt_cb(skb)->tx_seq = chan->next_tx_seq; + chan->next_tx_seq = (chan->next_tx_seq + 1) % 64; if (bt_cb(skb)->retries == 1) pi->unacked_frames++; @@ -1159,23 +1159,21 @@ int l2cap_ertm_send(struct l2cap_chan *chan) static int l2cap_retransmit_frames(struct l2cap_chan *chan) { struct sock *sk = chan->sk; - struct l2cap_pinfo *pi = l2cap_pi(sk); int ret; if (!skb_queue_empty(TX_QUEUE(sk))) sk->sk_send_head = TX_QUEUE(sk)->next; - pi->next_tx_seq = pi->expected_ack_seq; + chan->next_tx_seq = chan->expected_ack_seq; ret = l2cap_ertm_send(chan); return ret; } static void l2cap_send_ack(struct l2cap_chan *chan) { - struct sock *sk = chan->sk; u16 control = 0; - control |= l2cap_pi(sk)->buffer_seq << L2CAP_CTRL_REQSEQ_SHIFT; + control |= chan->buffer_seq << L2CAP_CTRL_REQSEQ_SHIFT; if (chan->conn_state & L2CAP_CONN_LOCAL_BUSY) { control |= L2CAP_SUPER_RCV_NOT_READY; @@ -1575,9 +1573,9 @@ static inline void l2cap_ertm_init(struct l2cap_chan *chan) { struct sock *sk = chan->sk; - l2cap_pi(sk)->expected_ack_seq = 0; + chan->expected_ack_seq = 0; l2cap_pi(sk)->unacked_frames = 0; - l2cap_pi(sk)->buffer_seq = 0; + chan->buffer_seq = 0; l2cap_pi(sk)->num_acked = 0; l2cap_pi(sk)->frames_sent = 0; @@ -2311,8 +2309,8 @@ static inline int l2cap_config_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr sk->sk_state = BT_CONNECTED; - l2cap_pi(sk)->next_tx_seq = 0; - l2cap_pi(sk)->expected_tx_seq = 0; + chan->next_tx_seq = 0; + chan->expected_tx_seq = 0; __skb_queue_head_init(TX_QUEUE(sk)); if (l2cap_pi(sk)->mode == L2CAP_MODE_ERTM) l2cap_ertm_init(chan); @@ -2402,8 +2400,8 @@ static inline int l2cap_config_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hdr set_default_fcs(l2cap_pi(sk)); sk->sk_state = BT_CONNECTED; - l2cap_pi(sk)->next_tx_seq = 0; - l2cap_pi(sk)->expected_tx_seq = 0; + chan->next_tx_seq = 0; + chan->expected_tx_seq = 0; __skb_queue_head_init(TX_QUEUE(sk)); if (l2cap_pi(sk)->mode == L2CAP_MODE_ERTM) l2cap_ertm_init(chan); @@ -2794,7 +2792,7 @@ static inline void l2cap_send_i_or_rr_or_rnr(struct l2cap_chan *chan) pi->frames_sent = 0; - control |= pi->buffer_seq << L2CAP_CTRL_REQSEQ_SHIFT; + control |= chan->buffer_seq << L2CAP_CTRL_REQSEQ_SHIFT; if (chan->conn_state & L2CAP_CONN_LOCAL_BUSY) { control |= L2CAP_SUPER_RCV_NOT_READY; @@ -2814,10 +2812,10 @@ static inline void l2cap_send_i_or_rr_or_rnr(struct l2cap_chan *chan) } } -static int l2cap_add_to_srej_queue(struct sock *sk, struct sk_buff *skb, u8 tx_seq, u8 sar) +static int l2cap_add_to_srej_queue(struct l2cap_chan *chan, struct sk_buff *skb, u8 tx_seq, u8 sar) { + struct sock *sk = chan->sk; struct sk_buff *next_skb; - struct l2cap_pinfo *pi = l2cap_pi(sk); int tx_seq_offset, next_tx_seq_offset; bt_cb(skb)->tx_seq = tx_seq; @@ -2829,7 +2827,7 @@ static int l2cap_add_to_srej_queue(struct sock *sk, struct sk_buff *skb, u8 tx_s return 0; } - tx_seq_offset = (tx_seq - pi->buffer_seq) % 64; + tx_seq_offset = (tx_seq - chan->buffer_seq) % 64; if (tx_seq_offset < 0) tx_seq_offset += 64; @@ -2838,7 +2836,7 @@ static int l2cap_add_to_srej_queue(struct sock *sk, struct sk_buff *skb, u8 tx_s return -EINVAL; next_tx_seq_offset = (bt_cb(next_skb)->tx_seq - - pi->buffer_seq) % 64; + chan->buffer_seq) % 64; if (next_tx_seq_offset < 0) next_tx_seq_offset += 64; @@ -2981,13 +2979,13 @@ static int l2cap_try_push_rx_skb(struct l2cap_chan *chan) return -EBUSY; } - pi->buffer_seq = (pi->buffer_seq + 1) % 64; + chan->buffer_seq = (chan->buffer_seq + 1) % 64; } if (!(chan->conn_state & L2CAP_CONN_RNR_SENT)) goto done; - control = pi->buffer_seq << L2CAP_CTRL_REQSEQ_SHIFT; + control = chan->buffer_seq << L2CAP_CTRL_REQSEQ_SHIFT; control |= L2CAP_SUPER_RCV_READY | L2CAP_CTRL_POLL; l2cap_send_sframe(chan, control); l2cap_pi(sk)->retry_count = 1; @@ -3069,7 +3067,7 @@ static int l2cap_push_rx_skb(struct l2cap_chan *chan, struct sk_buff *skb, u16 c err = l2cap_ertm_reassembly_sdu(chan, skb, control); if (err >= 0) { - pi->buffer_seq = (pi->buffer_seq + 1) % 64; + chan->buffer_seq = (chan->buffer_seq + 1) % 64; return err; } @@ -3080,7 +3078,7 @@ static int l2cap_push_rx_skb(struct l2cap_chan *chan, struct sk_buff *skb, u16 c bt_cb(skb)->sar = control >> L2CAP_CTRL_SAR_SHIFT; __skb_queue_tail(BUSY_QUEUE(sk), skb); - sctrl = pi->buffer_seq << L2CAP_CTRL_REQSEQ_SHIFT; + sctrl = chan->buffer_seq << L2CAP_CTRL_REQSEQ_SHIFT; sctrl |= L2CAP_SUPER_RCV_NOT_READY; l2cap_send_sframe(chan, sctrl); @@ -3200,8 +3198,8 @@ static void l2cap_check_srej_gap(struct l2cap_chan *chan, u8 tx_seq) skb = skb_dequeue(SREJ_QUEUE(sk)); control = bt_cb(skb)->sar << L2CAP_CTRL_SAR_SHIFT; l2cap_ertm_reassembly_sdu(chan, skb, control); - l2cap_pi(sk)->buffer_seq_srej = - (l2cap_pi(sk)->buffer_seq_srej + 1) % 64; + chan->buffer_seq_srej = + (chan->buffer_seq_srej + 1) % 64; tx_seq = (tx_seq + 1) % 64; } } @@ -3229,21 +3227,20 @@ static void l2cap_resend_srejframe(struct l2cap_chan *chan, u8 tx_seq) static void l2cap_send_srejframe(struct l2cap_chan *chan, u8 tx_seq) { struct sock *sk = chan->sk; - struct l2cap_pinfo *pi = l2cap_pi(sk); struct srej_list *new; u16 control; - while (tx_seq != pi->expected_tx_seq) { + while (tx_seq != chan->expected_tx_seq) { control = L2CAP_SUPER_SELECT_REJECT; - control |= pi->expected_tx_seq << L2CAP_CTRL_REQSEQ_SHIFT; + control |= chan->expected_tx_seq << L2CAP_CTRL_REQSEQ_SHIFT; l2cap_send_sframe(chan, control); new = kzalloc(sizeof(struct srej_list), GFP_ATOMIC); - new->tx_seq = pi->expected_tx_seq; - pi->expected_tx_seq = (pi->expected_tx_seq + 1) % 64; + new->tx_seq = chan->expected_tx_seq; + chan->expected_tx_seq = (chan->expected_tx_seq + 1) % 64; list_add_tail(&new->list, SREJ_LIST(sk)); } - pi->expected_tx_seq = (pi->expected_tx_seq + 1) % 64; + chan->expected_tx_seq = (chan->expected_tx_seq + 1) % 64; } static inline int l2cap_data_channel_iframe(struct l2cap_chan *chan, u16 rx_control, struct sk_buff *skb) @@ -3268,13 +3265,13 @@ static inline int l2cap_data_channel_iframe(struct l2cap_chan *chan, u16 rx_cont chan->conn_state &= ~L2CAP_CONN_WAIT_F; } - pi->expected_ack_seq = req_seq; - l2cap_drop_acked_frames(sk); + chan->expected_ack_seq = req_seq; + l2cap_drop_acked_frames(chan); - if (tx_seq == pi->expected_tx_seq) + if (tx_seq == chan->expected_tx_seq) goto expected; - tx_seq_offset = (tx_seq - pi->buffer_seq) % 64; + tx_seq_offset = (tx_seq - chan->buffer_seq) % 64; if (tx_seq_offset < 0) tx_seq_offset += 64; @@ -3293,14 +3290,14 @@ static inline int l2cap_data_channel_iframe(struct l2cap_chan *chan, u16 rx_cont first = list_first_entry(SREJ_LIST(sk), struct srej_list, list); if (tx_seq == first->tx_seq) { - l2cap_add_to_srej_queue(sk, skb, tx_seq, sar); + l2cap_add_to_srej_queue(chan, skb, tx_seq, sar); l2cap_check_srej_gap(chan, tx_seq); list_del(&first->list); kfree(first); if (list_empty(SREJ_LIST(sk))) { - pi->buffer_seq = pi->buffer_seq_srej; + chan->buffer_seq = chan->buffer_seq_srej; chan->conn_state &= ~L2CAP_CONN_SREJ_SENT; l2cap_send_ack(chan); BT_DBG("sk %p, Exit SREJ_SENT", sk); @@ -3309,7 +3306,7 @@ static inline int l2cap_data_channel_iframe(struct l2cap_chan *chan, u16 rx_cont struct srej_list *l; /* duplicated tx_seq */ - if (l2cap_add_to_srej_queue(sk, skb, tx_seq, sar) < 0) + if (l2cap_add_to_srej_queue(chan, skb, tx_seq, sar) < 0) goto drop; list_for_each_entry(l, SREJ_LIST(sk), list) { @@ -3322,7 +3319,7 @@ static inline int l2cap_data_channel_iframe(struct l2cap_chan *chan, u16 rx_cont } } else { expected_tx_seq_offset = - (pi->expected_tx_seq - pi->buffer_seq) % 64; + (chan->expected_tx_seq - chan->buffer_seq) % 64; if (expected_tx_seq_offset < 0) expected_tx_seq_offset += 64; @@ -3335,11 +3332,11 @@ static inline int l2cap_data_channel_iframe(struct l2cap_chan *chan, u16 rx_cont BT_DBG("sk %p, Enter SREJ", sk); INIT_LIST_HEAD(SREJ_LIST(sk)); - pi->buffer_seq_srej = pi->buffer_seq; + chan->buffer_seq_srej = chan->buffer_seq; __skb_queue_head_init(SREJ_QUEUE(sk)); __skb_queue_head_init(BUSY_QUEUE(sk)); - l2cap_add_to_srej_queue(sk, skb, tx_seq, sar); + l2cap_add_to_srej_queue(chan, skb, tx_seq, sar); chan->conn_state |= L2CAP_CONN_SEND_PBIT; @@ -3350,7 +3347,7 @@ static inline int l2cap_data_channel_iframe(struct l2cap_chan *chan, u16 rx_cont return 0; expected: - pi->expected_tx_seq = (pi->expected_tx_seq + 1) % 64; + chan->expected_tx_seq = (chan->expected_tx_seq + 1) % 64; if (chan->conn_state & L2CAP_CONN_SREJ_SENT) { bt_cb(skb)->tx_seq = tx_seq; @@ -3391,8 +3388,8 @@ static inline void l2cap_data_channel_rrframe(struct l2cap_chan *chan, u16 rx_co BT_DBG("sk %p, req_seq %d ctrl 0x%4.4x", sk, __get_reqseq(rx_control), rx_control); - pi->expected_ack_seq = __get_reqseq(rx_control); - l2cap_drop_acked_frames(sk); + chan->expected_ack_seq = __get_reqseq(rx_control); + l2cap_drop_acked_frames(chan); if (rx_control & L2CAP_CTRL_POLL) { chan->conn_state |= L2CAP_CONN_SEND_FBIT; @@ -3430,15 +3427,14 @@ static inline void l2cap_data_channel_rrframe(struct l2cap_chan *chan, u16 rx_co static inline void l2cap_data_channel_rejframe(struct l2cap_chan *chan, u16 rx_control) { - struct l2cap_pinfo *pi = l2cap_pi(chan->sk); u8 tx_seq = __get_reqseq(rx_control); BT_DBG("chan %p, req_seq %d ctrl 0x%4.4x", chan, tx_seq, rx_control); chan->conn_state &= ~L2CAP_CONN_REMOTE_BUSY; - pi->expected_ack_seq = tx_seq; - l2cap_drop_acked_frames(chan->sk); + chan->expected_ack_seq = tx_seq; + l2cap_drop_acked_frames(chan); if (rx_control & L2CAP_CTRL_FINAL) { if (chan->conn_state & L2CAP_CONN_REJ_ACT) @@ -3462,8 +3458,8 @@ static inline void l2cap_data_channel_srejframe(struct l2cap_chan *chan, u16 rx_ chan->conn_state &= ~L2CAP_CONN_REMOTE_BUSY; if (rx_control & L2CAP_CTRL_POLL) { - pi->expected_ack_seq = tx_seq; - l2cap_drop_acked_frames(chan->sk); + chan->expected_ack_seq = tx_seq; + l2cap_drop_acked_frames(chan); chan->conn_state |= L2CAP_CONN_SEND_FBIT; l2cap_retransmit_one_frame(chan, tx_seq); @@ -3497,8 +3493,8 @@ static inline void l2cap_data_channel_rnrframe(struct l2cap_chan *chan, u16 rx_c BT_DBG("chan %p, req_seq %d ctrl 0x%4.4x", chan, tx_seq, rx_control); chan->conn_state |= L2CAP_CONN_REMOTE_BUSY; - pi->expected_ack_seq = tx_seq; - l2cap_drop_acked_frames(chan->sk); + chan->expected_ack_seq = tx_seq; + l2cap_drop_acked_frames(chan); if (rx_control & L2CAP_CTRL_POLL) chan->conn_state |= L2CAP_CONN_SEND_FBIT; @@ -3584,12 +3580,12 @@ static int l2cap_ertm_data_rcv(struct sock *sk, struct sk_buff *skb) } req_seq = __get_reqseq(control); - req_seq_offset = (req_seq - pi->expected_ack_seq) % 64; + req_seq_offset = (req_seq - chan->expected_ack_seq) % 64; if (req_seq_offset < 0) req_seq_offset += 64; next_tx_seq_offset = - (pi->next_tx_seq - pi->expected_ack_seq) % 64; + (chan->next_tx_seq - chan->expected_ack_seq) % 64; if (next_tx_seq_offset < 0) next_tx_seq_offset += 64; @@ -3689,10 +3685,10 @@ static inline int l2cap_data_channel(struct l2cap_conn *conn, u16 cid, struct sk tx_seq = __get_txseq(control); - if (pi->expected_tx_seq == tx_seq) - pi->expected_tx_seq = (pi->expected_tx_seq + 1) % 64; + if (chan->expected_tx_seq == tx_seq) + chan->expected_tx_seq = (chan->expected_tx_seq + 1) % 64; else - pi->expected_tx_seq = (tx_seq + 1) % 64; + chan->expected_tx_seq = (tx_seq + 1) % 64; l2cap_streaming_reassembly_sdu(chan, skb, control); diff --git a/net/bluetooth/l2cap_sock.c b/net/bluetooth/l2cap_sock.c index 66ec966..19574e4 100644 --- a/net/bluetooth/l2cap_sock.c +++ b/net/bluetooth/l2cap_sock.c @@ -777,7 +777,7 @@ static int l2cap_sock_sendmsg(struct kiocb *iocb, struct socket *sock, struct ms } if (pi->mode == L2CAP_MODE_STREAMING) { - l2cap_streaming_send(sk); + l2cap_streaming_send(pi->chan); err = len; break; } -- cgit v0.10.2 From 6a026610eee2c53ff59598905fcbaa979aec68d1 Mon Sep 17 00:00:00 2001 From: "Gustavo F. Padovan" Date: Fri, 1 Apr 2011 00:38:50 -0300 Subject: Bluetooth: Move more ERTM stuff to struct l2cap_chan As part of the moving channel stuff to l2cap_chan. Signed-off-by: Gustavo F. Padovan diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h index 9b43874..041213b 100644 --- a/include/net/bluetooth/l2cap.h +++ b/include/net/bluetooth/l2cap.h @@ -293,6 +293,11 @@ struct l2cap_chan { __u8 expected_tx_seq; __u8 buffer_seq; __u8 buffer_seq_srej; + __u8 srej_save_reqseq; + __u8 frames_sent; + __u8 unacked_frames; + __u8 retry_count; + __u8 num_acked; struct list_head list; }; @@ -359,11 +364,6 @@ struct l2cap_pinfo { __u8 conf_state; - __u8 srej_save_reqseq; - __u8 frames_sent; - __u8 unacked_frames; - __u8 retry_count; - __u8 num_acked; __u16 sdu_len; __u16 partial_sdu_len; struct sk_buff *sdu; diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index d975092..3f601d1 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -924,7 +924,7 @@ int __l2cap_wait_ack(struct sock *sk) int timeo = HZ/5; add_wait_queue(sk_sleep(sk), &wait); - while ((l2cap_pi(sk)->unacked_frames > 0 && l2cap_pi(sk)->conn)) { + while ((l2cap_pi(sk)->chan->unacked_frames > 0 && l2cap_pi(sk)->conn)) { set_current_state(TASK_INTERRUPTIBLE); if (!timeo) @@ -956,13 +956,13 @@ static void l2cap_monitor_timeout(unsigned long arg) BT_DBG("chan %p", chan); bh_lock_sock(sk); - if (l2cap_pi(sk)->retry_count >= l2cap_pi(sk)->remote_max_tx) { + if (chan->retry_count >= l2cap_pi(sk)->remote_max_tx) { l2cap_send_disconn_req(l2cap_pi(sk)->conn, sk, ECONNABORTED); bh_unlock_sock(sk); return; } - l2cap_pi(sk)->retry_count++; + chan->retry_count++; __mod_monitor_timer(); l2cap_send_rr_or_rnr(chan, L2CAP_CTRL_POLL); @@ -977,7 +977,7 @@ static void l2cap_retrans_timeout(unsigned long arg) BT_DBG("sk %p", sk); bh_lock_sock(sk); - l2cap_pi(sk)->retry_count = 1; + chan->retry_count = 1; __mod_monitor_timer(); chan->conn_state |= L2CAP_CONN_WAIT_F; @@ -992,17 +992,17 @@ static void l2cap_drop_acked_frames(struct l2cap_chan *chan) struct sk_buff *skb; while ((skb = skb_peek(TX_QUEUE(sk))) && - l2cap_pi(sk)->unacked_frames) { + chan->unacked_frames) { if (bt_cb(skb)->tx_seq == chan->expected_ack_seq) break; skb = skb_dequeue(TX_QUEUE(sk)); kfree_skb(skb); - l2cap_pi(sk)->unacked_frames--; + chan->unacked_frames--; } - if (!l2cap_pi(sk)->unacked_frames) + if (!chan->unacked_frames) del_timer(&l2cap_pi(sk)->retrans_timer); } @@ -1141,9 +1141,9 @@ int l2cap_ertm_send(struct l2cap_chan *chan) chan->next_tx_seq = (chan->next_tx_seq + 1) % 64; if (bt_cb(skb)->retries == 1) - pi->unacked_frames++; + chan->unacked_frames++; - pi->frames_sent++; + chan->frames_sent++; if (skb_queue_is_last(TX_QUEUE(sk), skb)) sk->sk_send_head = NULL; @@ -1574,10 +1574,10 @@ static inline void l2cap_ertm_init(struct l2cap_chan *chan) struct sock *sk = chan->sk; chan->expected_ack_seq = 0; - l2cap_pi(sk)->unacked_frames = 0; + chan->unacked_frames = 0; chan->buffer_seq = 0; - l2cap_pi(sk)->num_acked = 0; - l2cap_pi(sk)->frames_sent = 0; + chan->num_acked = 0; + chan->frames_sent = 0; setup_timer(&l2cap_pi(sk)->retrans_timer, l2cap_retrans_timeout, (unsigned long) chan); @@ -2787,10 +2787,9 @@ static int l2cap_check_fcs(struct l2cap_pinfo *pi, struct sk_buff *skb) static inline void l2cap_send_i_or_rr_or_rnr(struct l2cap_chan *chan) { - struct l2cap_pinfo *pi = l2cap_pi(chan->sk); u16 control = 0; - pi->frames_sent = 0; + chan->frames_sent = 0; control |= chan->buffer_seq << L2CAP_CTRL_REQSEQ_SHIFT; @@ -2806,7 +2805,7 @@ static inline void l2cap_send_i_or_rr_or_rnr(struct l2cap_chan *chan) l2cap_ertm_send(chan); if (!(chan->conn_state & L2CAP_CONN_LOCAL_BUSY) && - pi->frames_sent == 0) { + chan->frames_sent == 0) { control |= L2CAP_SUPER_RCV_READY; l2cap_send_sframe(chan, control); } @@ -2988,7 +2987,7 @@ static int l2cap_try_push_rx_skb(struct l2cap_chan *chan) control = chan->buffer_seq << L2CAP_CTRL_REQSEQ_SHIFT; control |= L2CAP_SUPER_RCV_READY | L2CAP_CTRL_POLL; l2cap_send_sframe(chan, control); - l2cap_pi(sk)->retry_count = 1; + chan->retry_count = 1; del_timer(&pi->retrans_timer); __mod_monitor_timer(); @@ -3260,7 +3259,7 @@ static inline int l2cap_data_channel_iframe(struct l2cap_chan *chan, u16 rx_cont if (L2CAP_CTRL_FINAL & rx_control && chan->conn_state & L2CAP_CONN_WAIT_F) { del_timer(&pi->monitor_timer); - if (pi->unacked_frames > 0) + if (chan->unacked_frames > 0) __mod_retrans_timer(); chan->conn_state &= ~L2CAP_CONN_WAIT_F; } @@ -3369,8 +3368,8 @@ expected: __mod_ack_timer(); - pi->num_acked = (pi->num_acked + 1) % num_to_ack; - if (pi->num_acked == num_to_ack - 1) + chan->num_acked = (chan->num_acked + 1) % num_to_ack; + if (chan->num_acked == num_to_ack - 1) l2cap_send_ack(chan); return 0; @@ -3383,7 +3382,6 @@ drop: static inline void l2cap_data_channel_rrframe(struct l2cap_chan *chan, u16 rx_control) { struct sock *sk = chan->sk; - struct l2cap_pinfo *pi = l2cap_pi(sk); BT_DBG("sk %p, req_seq %d ctrl 0x%4.4x", sk, __get_reqseq(rx_control), rx_control); @@ -3395,7 +3393,7 @@ static inline void l2cap_data_channel_rrframe(struct l2cap_chan *chan, u16 rx_co chan->conn_state |= L2CAP_CONN_SEND_FBIT; if (chan->conn_state & L2CAP_CONN_SREJ_SENT) { if ((chan->conn_state & L2CAP_CONN_REMOTE_BUSY) && - (pi->unacked_frames > 0)) + (chan->unacked_frames > 0)) __mod_retrans_timer(); chan->conn_state &= ~L2CAP_CONN_REMOTE_BUSY; @@ -3414,7 +3412,7 @@ static inline void l2cap_data_channel_rrframe(struct l2cap_chan *chan, u16 rx_co } else { if ((chan->conn_state & L2CAP_CONN_REMOTE_BUSY) && - (pi->unacked_frames > 0)) + (chan->unacked_frames > 0)) __mod_retrans_timer(); chan->conn_state &= ~L2CAP_CONN_REMOTE_BUSY; @@ -3450,7 +3448,6 @@ static inline void l2cap_data_channel_rejframe(struct l2cap_chan *chan, u16 rx_c } static inline void l2cap_data_channel_srejframe(struct l2cap_chan *chan, u16 rx_control) { - struct l2cap_pinfo *pi = l2cap_pi(chan->sk); u8 tx_seq = __get_reqseq(rx_control); BT_DBG("chan %p, req_seq %d ctrl 0x%4.4x", chan, tx_seq, rx_control); @@ -3467,19 +3464,19 @@ static inline void l2cap_data_channel_srejframe(struct l2cap_chan *chan, u16 rx_ l2cap_ertm_send(chan); if (chan->conn_state & L2CAP_CONN_WAIT_F) { - pi->srej_save_reqseq = tx_seq; + chan->srej_save_reqseq = tx_seq; chan->conn_state |= L2CAP_CONN_SREJ_ACT; } } else if (rx_control & L2CAP_CTRL_FINAL) { if ((chan->conn_state & L2CAP_CONN_SREJ_ACT) && - pi->srej_save_reqseq == tx_seq) + chan->srej_save_reqseq == tx_seq) chan->conn_state &= ~L2CAP_CONN_SREJ_ACT; else l2cap_retransmit_one_frame(chan, tx_seq); } else { l2cap_retransmit_one_frame(chan, tx_seq); if (chan->conn_state & L2CAP_CONN_WAIT_F) { - pi->srej_save_reqseq = tx_seq; + chan->srej_save_reqseq = tx_seq; chan->conn_state |= L2CAP_CONN_SREJ_ACT; } } @@ -3521,7 +3518,7 @@ static inline int l2cap_data_channel_sframe(struct l2cap_chan *chan, u16 rx_cont if (L2CAP_CTRL_FINAL & rx_control && chan->conn_state & L2CAP_CONN_WAIT_F) { del_timer(&l2cap_pi(sk)->monitor_timer); - if (l2cap_pi(sk)->unacked_frames > 0) + if (chan->unacked_frames > 0) __mod_retrans_timer(); chan->conn_state &= ~L2CAP_CONN_WAIT_F; } -- cgit v0.10.2 From 6f61fd475907bf0a1470cb969ee993a31d305513 Mon Sep 17 00:00:00 2001 From: "Gustavo F. Padovan" Date: Fri, 25 Mar 2011 20:09:37 -0300 Subject: Bluetooth: Move SDU related vars to struct l2cap_chan As part of the moving channel stuff to l2cap_chan. Signed-off-by: Gustavo F. Padovan diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h index 041213b..19d613b 100644 --- a/include/net/bluetooth/l2cap.h +++ b/include/net/bluetooth/l2cap.h @@ -298,6 +298,10 @@ struct l2cap_chan { __u8 unacked_frames; __u8 retry_count; __u8 num_acked; + __u16 sdu_len; + __u16 partial_sdu_len; + struct sk_buff *sdu; + struct list_head list; }; @@ -364,10 +368,6 @@ struct l2cap_pinfo { __u8 conf_state; - __u16 sdu_len; - __u16 partial_sdu_len; - struct sk_buff *sdu; - __u8 tx_win; __u8 max_tx; __u8 remote_tx_win; diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index 3f601d1..8ccfcdf 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -2875,13 +2875,13 @@ static int l2cap_ertm_reassembly_sdu(struct l2cap_chan *chan, struct sk_buff *sk if (chan->conn_state & L2CAP_CONN_SAR_SDU) goto drop; - pi->sdu_len = get_unaligned_le16(skb->data); + chan->sdu_len = get_unaligned_le16(skb->data); - if (pi->sdu_len > pi->imtu) + if (chan->sdu_len > pi->imtu) goto disconnect; - pi->sdu = bt_skb_alloc(pi->sdu_len, GFP_ATOMIC); - if (!pi->sdu) + chan->sdu = bt_skb_alloc(chan->sdu_len, GFP_ATOMIC); + if (!chan->sdu) return -ENOMEM; /* pull sdu_len bytes only after alloc, because of Local Busy @@ -2889,24 +2889,24 @@ static int l2cap_ertm_reassembly_sdu(struct l2cap_chan *chan, struct sk_buff *sk * only once, i.e., when alloc does not fail */ skb_pull(skb, 2); - memcpy(skb_put(pi->sdu, skb->len), skb->data, skb->len); + memcpy(skb_put(chan->sdu, skb->len), skb->data, skb->len); chan->conn_state |= L2CAP_CONN_SAR_SDU; - pi->partial_sdu_len = skb->len; + chan->partial_sdu_len = skb->len; break; case L2CAP_SDU_CONTINUE: if (!(chan->conn_state & L2CAP_CONN_SAR_SDU)) goto disconnect; - if (!pi->sdu) + if (!chan->sdu) goto disconnect; - pi->partial_sdu_len += skb->len; - if (pi->partial_sdu_len > pi->sdu_len) + chan->partial_sdu_len += skb->len; + if (chan->partial_sdu_len > chan->sdu_len) goto drop; - memcpy(skb_put(pi->sdu, skb->len), skb->data, skb->len); + memcpy(skb_put(chan->sdu, skb->len), skb->data, skb->len); break; @@ -2914,22 +2914,22 @@ static int l2cap_ertm_reassembly_sdu(struct l2cap_chan *chan, struct sk_buff *sk if (!(chan->conn_state & L2CAP_CONN_SAR_SDU)) goto disconnect; - if (!pi->sdu) + if (!chan->sdu) goto disconnect; if (!(chan->conn_state & L2CAP_CONN_SAR_RETRY)) { - pi->partial_sdu_len += skb->len; + chan->partial_sdu_len += skb->len; - if (pi->partial_sdu_len > pi->imtu) + if (chan->partial_sdu_len > pi->imtu) goto drop; - if (pi->partial_sdu_len != pi->sdu_len) + if (chan->partial_sdu_len != chan->sdu_len) goto drop; - memcpy(skb_put(pi->sdu, skb->len), skb->data, skb->len); + memcpy(skb_put(chan->sdu, skb->len), skb->data, skb->len); } - _skb = skb_clone(pi->sdu, GFP_ATOMIC); + _skb = skb_clone(chan->sdu, GFP_ATOMIC); if (!_skb) { chan->conn_state |= L2CAP_CONN_SAR_RETRY; return -ENOMEM; @@ -2945,7 +2945,7 @@ static int l2cap_ertm_reassembly_sdu(struct l2cap_chan *chan, struct sk_buff *sk chan->conn_state &= ~L2CAP_CONN_SAR_RETRY; chan->conn_state &= ~L2CAP_CONN_SAR_SDU; - kfree_skb(pi->sdu); + kfree_skb(chan->sdu); break; } @@ -2953,8 +2953,8 @@ static int l2cap_ertm_reassembly_sdu(struct l2cap_chan *chan, struct sk_buff *sk return 0; drop: - kfree_skb(pi->sdu); - pi->sdu = NULL; + kfree_skb(chan->sdu); + chan->sdu = NULL; disconnect: l2cap_send_disconn_req(pi->conn, chan->sk, ECONNRESET); @@ -3104,7 +3104,7 @@ static int l2cap_streaming_reassembly_sdu(struct l2cap_chan *chan, struct sk_buf switch (control & L2CAP_CTRL_SAR) { case L2CAP_SDU_UNSEGMENTED: if (chan->conn_state & L2CAP_CONN_SAR_SDU) { - kfree_skb(pi->sdu); + kfree_skb(chan->sdu); break; } @@ -3116,28 +3116,28 @@ static int l2cap_streaming_reassembly_sdu(struct l2cap_chan *chan, struct sk_buf case L2CAP_SDU_START: if (chan->conn_state & L2CAP_CONN_SAR_SDU) { - kfree_skb(pi->sdu); + kfree_skb(chan->sdu); break; } - pi->sdu_len = get_unaligned_le16(skb->data); + chan->sdu_len = get_unaligned_le16(skb->data); skb_pull(skb, 2); - if (pi->sdu_len > pi->imtu) { + if (chan->sdu_len > pi->imtu) { err = -EMSGSIZE; break; } - pi->sdu = bt_skb_alloc(pi->sdu_len, GFP_ATOMIC); - if (!pi->sdu) { + chan->sdu = bt_skb_alloc(chan->sdu_len, GFP_ATOMIC); + if (!chan->sdu) { err = -ENOMEM; break; } - memcpy(skb_put(pi->sdu, skb->len), skb->data, skb->len); + memcpy(skb_put(chan->sdu, skb->len), skb->data, skb->len); chan->conn_state |= L2CAP_CONN_SAR_SDU; - pi->partial_sdu_len = skb->len; + chan->partial_sdu_len = skb->len; err = 0; break; @@ -3145,11 +3145,11 @@ static int l2cap_streaming_reassembly_sdu(struct l2cap_chan *chan, struct sk_buf if (!(chan->conn_state & L2CAP_CONN_SAR_SDU)) break; - memcpy(skb_put(pi->sdu, skb->len), skb->data, skb->len); + memcpy(skb_put(chan->sdu, skb->len), skb->data, skb->len); - pi->partial_sdu_len += skb->len; - if (pi->partial_sdu_len > pi->sdu_len) - kfree_skb(pi->sdu); + chan->partial_sdu_len += skb->len; + if (chan->partial_sdu_len > chan->sdu_len) + kfree_skb(chan->sdu); else err = 0; @@ -3159,16 +3159,16 @@ static int l2cap_streaming_reassembly_sdu(struct l2cap_chan *chan, struct sk_buf if (!(chan->conn_state & L2CAP_CONN_SAR_SDU)) break; - memcpy(skb_put(pi->sdu, skb->len), skb->data, skb->len); + memcpy(skb_put(chan->sdu, skb->len), skb->data, skb->len); chan->conn_state &= ~L2CAP_CONN_SAR_SDU; - pi->partial_sdu_len += skb->len; + chan->partial_sdu_len += skb->len; - if (pi->partial_sdu_len > pi->imtu) + if (chan->partial_sdu_len > pi->imtu) goto drop; - if (pi->partial_sdu_len == pi->sdu_len) { - _skb = skb_clone(pi->sdu, GFP_ATOMIC); + if (chan->partial_sdu_len == chan->sdu_len) { + _skb = skb_clone(chan->sdu, GFP_ATOMIC); err = sock_queue_rcv_skb(chan->sk, _skb); if (err < 0) kfree_skb(_skb); @@ -3176,7 +3176,7 @@ static int l2cap_streaming_reassembly_sdu(struct l2cap_chan *chan, struct sk_buf err = 0; drop: - kfree_skb(pi->sdu); + kfree_skb(chan->sdu); break; } -- cgit v0.10.2 From 2c03a7a49e0831646bd35d0877ec7d051d8f174b Mon Sep 17 00:00:00 2001 From: "Gustavo F. Padovan" Date: Fri, 25 Mar 2011 20:15:28 -0300 Subject: Bluetooth: Move remote info to struct l2cap_chan As part of the moving channel stuff to l2cap_chan. Signed-off-by: Gustavo F. Padovan diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h index 19d613b..11c53cb 100644 --- a/include/net/bluetooth/l2cap.h +++ b/include/net/bluetooth/l2cap.h @@ -302,6 +302,9 @@ struct l2cap_chan { __u16 partial_sdu_len; struct sk_buff *sdu; + __u8 remote_tx_win; + __u8 remote_max_tx; + __u16 remote_mps; struct list_head list; }; @@ -370,11 +373,8 @@ struct l2cap_pinfo { __u8 tx_win; __u8 max_tx; - __u8 remote_tx_win; - __u8 remote_max_tx; __u16 retrans_timeout; __u16 monitor_timeout; - __u16 remote_mps; __u16 mps; __le16 sport; @@ -431,7 +431,7 @@ static inline int l2cap_tx_window_full(struct l2cap_chan *ch) if (sub < 0) sub += 64; - return sub == l2cap_pi(ch->sk)->remote_tx_win; + return sub == ch->remote_tx_win; } #define __get_txseq(ctrl) (((ctrl) & L2CAP_CTRL_TXSEQ) >> 1) @@ -454,7 +454,7 @@ int __l2cap_wait_ack(struct sock *sk); struct sk_buff *l2cap_create_connless_pdu(struct sock *sk, struct msghdr *msg, size_t len); struct sk_buff *l2cap_create_basic_pdu(struct sock *sk, struct msghdr *msg, size_t len); struct sk_buff *l2cap_create_iframe_pdu(struct sock *sk, struct msghdr *msg, size_t len, u16 control, u16 sdulen); -int l2cap_sar_segment_sdu(struct sock *sk, struct msghdr *msg, size_t len); +int l2cap_sar_segment_sdu(struct l2cap_chan *chan, struct msghdr *msg, size_t len); void l2cap_do_send(struct sock *sk, struct sk_buff *skb); void l2cap_streaming_send(struct l2cap_chan *chan); int l2cap_ertm_send(struct l2cap_chan *chan); diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index 8ccfcdf..2176a00 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -956,7 +956,7 @@ static void l2cap_monitor_timeout(unsigned long arg) BT_DBG("chan %p", chan); bh_lock_sock(sk); - if (chan->retry_count >= l2cap_pi(sk)->remote_max_tx) { + if (chan->retry_count >= chan->remote_max_tx) { l2cap_send_disconn_req(l2cap_pi(sk)->conn, sk, ECONNABORTED); bh_unlock_sock(sk); return; @@ -1065,8 +1065,8 @@ static void l2cap_retransmit_one_frame(struct l2cap_chan *chan, u8 tx_seq) } while ((skb = skb_queue_next(TX_QUEUE(sk), skb))); - if (pi->remote_max_tx && - bt_cb(skb)->retries == pi->remote_max_tx) { + if (chan->remote_max_tx && + bt_cb(skb)->retries == chan->remote_max_tx) { l2cap_send_disconn_req(pi->conn, sk, ECONNABORTED); return; } @@ -1106,8 +1106,8 @@ int l2cap_ertm_send(struct l2cap_chan *chan) while ((skb = sk->sk_send_head) && (!l2cap_tx_window_full(chan))) { - if (pi->remote_max_tx && - bt_cb(skb)->retries == pi->remote_max_tx) { + if (chan->remote_max_tx && + bt_cb(skb)->retries == chan->remote_max_tx) { l2cap_send_disconn_req(pi->conn, sk, ECONNABORTED); break; } @@ -1337,9 +1337,9 @@ struct sk_buff *l2cap_create_iframe_pdu(struct sock *sk, struct msghdr *msg, siz return skb; } -int l2cap_sar_segment_sdu(struct sock *sk, struct msghdr *msg, size_t len) +int l2cap_sar_segment_sdu(struct l2cap_chan *chan, struct msghdr *msg, size_t len) { - struct l2cap_pinfo *pi = l2cap_pi(sk); + struct sock *sk = chan->sk; struct sk_buff *skb; struct sk_buff_head sar_queue; u16 control; @@ -1347,20 +1347,20 @@ int l2cap_sar_segment_sdu(struct sock *sk, struct msghdr *msg, size_t len) skb_queue_head_init(&sar_queue); control = L2CAP_SDU_START; - skb = l2cap_create_iframe_pdu(sk, msg, pi->remote_mps, control, len); + skb = l2cap_create_iframe_pdu(sk, msg, chan->remote_mps, control, len); if (IS_ERR(skb)) return PTR_ERR(skb); __skb_queue_tail(&sar_queue, skb); - len -= pi->remote_mps; - size += pi->remote_mps; + len -= chan->remote_mps; + size += chan->remote_mps; while (len > 0) { size_t buflen; - if (len > pi->remote_mps) { + if (len > chan->remote_mps) { control = L2CAP_SDU_CONTINUE; - buflen = pi->remote_mps; + buflen = chan->remote_mps; } else { control = L2CAP_SDU_END; buflen = len; @@ -1810,13 +1810,13 @@ done: break; case L2CAP_MODE_ERTM: - pi->remote_tx_win = rfc.txwin_size; - pi->remote_max_tx = rfc.max_transmit; + chan->remote_tx_win = rfc.txwin_size; + chan->remote_max_tx = rfc.max_transmit; if (le16_to_cpu(rfc.max_pdu_size) > pi->conn->mtu - 10) rfc.max_pdu_size = cpu_to_le16(pi->conn->mtu - 10); - pi->remote_mps = le16_to_cpu(rfc.max_pdu_size); + chan->remote_mps = le16_to_cpu(rfc.max_pdu_size); rfc.retrans_timeout = le16_to_cpu(L2CAP_DEFAULT_RETRANS_TO); @@ -1834,7 +1834,7 @@ done: if (le16_to_cpu(rfc.max_pdu_size) > pi->conn->mtu - 10) rfc.max_pdu_size = cpu_to_le16(pi->conn->mtu - 10); - pi->remote_mps = le16_to_cpu(rfc.max_pdu_size); + chan->remote_mps = le16_to_cpu(rfc.max_pdu_size); pi->conf_state |= L2CAP_CONF_MODE_DONE; diff --git a/net/bluetooth/l2cap_sock.c b/net/bluetooth/l2cap_sock.c index 19574e4..f90ca25 100644 --- a/net/bluetooth/l2cap_sock.c +++ b/net/bluetooth/l2cap_sock.c @@ -757,7 +757,7 @@ static int l2cap_sock_sendmsg(struct kiocb *iocb, struct socket *sock, struct ms case L2CAP_MODE_ERTM: case L2CAP_MODE_STREAMING: /* Entire SDU fits into one PDU */ - if (len <= pi->remote_mps) { + if (len <= pi->chan->remote_mps) { control = L2CAP_SDU_UNSEGMENTED; skb = l2cap_create_iframe_pdu(sk, msg, len, control, 0); if (IS_ERR(skb)) { @@ -771,7 +771,7 @@ static int l2cap_sock_sendmsg(struct kiocb *iocb, struct socket *sock, struct ms } else { /* Segment SDU into multiples PDUs */ - err = l2cap_sar_segment_sdu(sk, msg, len); + err = l2cap_sar_segment_sdu(pi->chan, msg, len); if (err < 0) goto done; } -- cgit v0.10.2 From e92c8e70faf5e3cc22979daba2a895359aa1eab2 Mon Sep 17 00:00:00 2001 From: "Gustavo F. Padovan" Date: Fri, 1 Apr 2011 00:53:45 -0300 Subject: Bluetooth: Move ERTM timers to struct l2cap_chan This also triggered a change in l2cap_send_disconn_req() parameters. Signed-off-by: Gustavo F. Padovan diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h index 11c53cb..5f4abea 100644 --- a/include/net/bluetooth/l2cap.h +++ b/include/net/bluetooth/l2cap.h @@ -306,6 +306,10 @@ struct l2cap_chan { __u8 remote_max_tx; __u16 remote_mps; + struct timer_list retrans_timer; + struct timer_list monitor_timer; + struct timer_list ack_timer; + struct list_head list; }; @@ -379,9 +383,6 @@ struct l2cap_pinfo { __le16 sport; - struct timer_list retrans_timer; - struct timer_list monitor_timer; - struct timer_list ack_timer; struct sk_buff_head tx_queue; struct sk_buff_head srej_queue; struct sk_buff_head busy_queue; @@ -415,11 +416,11 @@ struct l2cap_pinfo { #define L2CAP_CONN_RNR_SENT 0x0200 #define L2CAP_CONN_SAR_RETRY 0x0400 -#define __mod_retrans_timer() mod_timer(&l2cap_pi(sk)->retrans_timer, \ +#define __mod_retrans_timer() mod_timer(&chan->retrans_timer, \ jiffies + msecs_to_jiffies(L2CAP_DEFAULT_RETRANS_TO)); -#define __mod_monitor_timer() mod_timer(&l2cap_pi(sk)->monitor_timer, \ +#define __mod_monitor_timer() mod_timer(&chan->monitor_timer, \ jiffies + msecs_to_jiffies(L2CAP_DEFAULT_MONITOR_TO)); -#define __mod_ack_timer() mod_timer(&l2cap_pi(sk)->ack_timer, \ +#define __mod_ack_timer() mod_timer(&chan->ack_timer, \ jiffies + msecs_to_jiffies(L2CAP_DEFAULT_ACK_TO)); static inline int l2cap_tx_window_full(struct l2cap_chan *ch) @@ -466,7 +467,7 @@ void l2cap_sock_kill(struct sock *sk); void l2cap_sock_init(struct sock *sk, struct sock *parent); struct sock *l2cap_sock_alloc(struct net *net, struct socket *sock, int proto, gfp_t prio); -void l2cap_send_disconn_req(struct l2cap_conn *conn, struct sock *sk, int err); +void l2cap_send_disconn_req(struct l2cap_conn *conn, struct l2cap_chan *chan, int err); void l2cap_chan_del(struct l2cap_chan *chan, int err); int l2cap_do_connect(struct sock *sk); diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index 2176a00..eaac13cb 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -241,9 +241,9 @@ void l2cap_chan_del(struct l2cap_chan *chan, int err) if (l2cap_pi(sk)->mode == L2CAP_MODE_ERTM) { struct srej_list *l, *tmp; - del_timer(&l2cap_pi(sk)->retrans_timer); - del_timer(&l2cap_pi(sk)->monitor_timer); - del_timer(&l2cap_pi(sk)->ack_timer); + del_timer(&chan->retrans_timer); + del_timer(&chan->monitor_timer); + del_timer(&chan->ack_timer); skb_queue_purge(SREJ_QUEUE(sk)); skb_queue_purge(BUSY_QUEUE(sk)); @@ -462,19 +462,22 @@ static inline int l2cap_mode_supported(__u8 mode, __u32 feat_mask) } } -void l2cap_send_disconn_req(struct l2cap_conn *conn, struct sock *sk, int err) +void l2cap_send_disconn_req(struct l2cap_conn *conn, struct l2cap_chan *chan, int err) { + struct sock *sk; struct l2cap_disconn_req req; if (!conn) return; + sk = chan->sk; + skb_queue_purge(TX_QUEUE(sk)); if (l2cap_pi(sk)->mode == L2CAP_MODE_ERTM) { - del_timer(&l2cap_pi(sk)->retrans_timer); - del_timer(&l2cap_pi(sk)->monitor_timer); - del_timer(&l2cap_pi(sk)->ack_timer); + del_timer(&chan->retrans_timer); + del_timer(&chan->monitor_timer); + del_timer(&chan->ack_timer); } req.dcid = cpu_to_le16(l2cap_pi(sk)->dcid); @@ -957,7 +960,7 @@ static void l2cap_monitor_timeout(unsigned long arg) bh_lock_sock(sk); if (chan->retry_count >= chan->remote_max_tx) { - l2cap_send_disconn_req(l2cap_pi(sk)->conn, sk, ECONNABORTED); + l2cap_send_disconn_req(l2cap_pi(sk)->conn, chan, ECONNABORTED); bh_unlock_sock(sk); return; } @@ -1003,7 +1006,7 @@ static void l2cap_drop_acked_frames(struct l2cap_chan *chan) } if (!chan->unacked_frames) - del_timer(&l2cap_pi(sk)->retrans_timer); + del_timer(&chan->retrans_timer); } void l2cap_do_send(struct sock *sk, struct sk_buff *skb) @@ -1067,7 +1070,7 @@ static void l2cap_retransmit_one_frame(struct l2cap_chan *chan, u8 tx_seq) if (chan->remote_max_tx && bt_cb(skb)->retries == chan->remote_max_tx) { - l2cap_send_disconn_req(pi->conn, sk, ECONNABORTED); + l2cap_send_disconn_req(pi->conn, chan, ECONNABORTED); return; } @@ -1108,7 +1111,7 @@ int l2cap_ertm_send(struct l2cap_chan *chan) if (chan->remote_max_tx && bt_cb(skb)->retries == chan->remote_max_tx) { - l2cap_send_disconn_req(pi->conn, sk, ECONNABORTED); + l2cap_send_disconn_req(pi->conn, chan, ECONNABORTED); break; } @@ -1579,12 +1582,11 @@ static inline void l2cap_ertm_init(struct l2cap_chan *chan) chan->num_acked = 0; chan->frames_sent = 0; - setup_timer(&l2cap_pi(sk)->retrans_timer, - l2cap_retrans_timeout, (unsigned long) chan); - setup_timer(&l2cap_pi(sk)->monitor_timer, - l2cap_monitor_timeout, (unsigned long) chan); - setup_timer(&l2cap_pi(sk)->ack_timer, - l2cap_ack_timeout, (unsigned long) chan); + setup_timer(&chan->retrans_timer, l2cap_retrans_timeout, + (unsigned long) chan); + setup_timer(&chan->monitor_timer, l2cap_monitor_timeout, + (unsigned long) chan); + setup_timer(&chan->ack_timer, l2cap_ack_timeout, (unsigned long) chan); __skb_queue_head_init(SREJ_QUEUE(sk)); __skb_queue_head_init(BUSY_QUEUE(sk)); @@ -2291,7 +2293,7 @@ static inline int l2cap_config_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr /* Complete config. */ len = l2cap_parse_conf_req(chan, rsp); if (len < 0) { - l2cap_send_disconn_req(conn, sk, ECONNRESET); + l2cap_send_disconn_req(conn, chan, ECONNRESET); goto unlock; } @@ -2363,7 +2365,7 @@ static inline int l2cap_config_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hdr char req[64]; if (len > sizeof(req) - sizeof(struct l2cap_conf_req)) { - l2cap_send_disconn_req(conn, sk, ECONNRESET); + l2cap_send_disconn_req(conn, chan, ECONNRESET); goto done; } @@ -2372,7 +2374,7 @@ static inline int l2cap_config_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hdr len = l2cap_parse_conf_rsp(sk, rsp->data, len, req, &result); if (len < 0) { - l2cap_send_disconn_req(conn, sk, ECONNRESET); + l2cap_send_disconn_req(conn, chan, ECONNRESET); goto done; } @@ -2387,7 +2389,7 @@ static inline int l2cap_config_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hdr default: sk->sk_err = ECONNRESET; l2cap_sock_set_timer(sk, HZ * 5); - l2cap_send_disconn_req(conn, sk, ECONNRESET); + l2cap_send_disconn_req(conn, chan, ECONNRESET); goto done; } @@ -2957,7 +2959,7 @@ drop: chan->sdu = NULL; disconnect: - l2cap_send_disconn_req(pi->conn, chan->sk, ECONNRESET); + l2cap_send_disconn_req(pi->conn, chan, ECONNRESET); kfree_skb(skb); return 0; } @@ -2965,7 +2967,6 @@ disconnect: static int l2cap_try_push_rx_skb(struct l2cap_chan *chan) { struct sock *sk = chan->sk; - struct l2cap_pinfo *pi = l2cap_pi(sk); struct sk_buff *skb; u16 control; int err; @@ -2989,7 +2990,7 @@ static int l2cap_try_push_rx_skb(struct l2cap_chan *chan) l2cap_send_sframe(chan, control); chan->retry_count = 1; - del_timer(&pi->retrans_timer); + del_timer(&chan->retrans_timer); __mod_monitor_timer(); chan->conn_state |= L2CAP_CONN_WAIT_F; @@ -3020,7 +3021,7 @@ static void l2cap_busy_work(struct work_struct *work) if (n_tries++ > L2CAP_LOCAL_BUSY_TRIES) { err = -EBUSY; - l2cap_send_disconn_req(pi->conn, sk, EBUSY); + l2cap_send_disconn_req(pi->conn, pi->chan, EBUSY); break; } @@ -3083,7 +3084,7 @@ static int l2cap_push_rx_skb(struct l2cap_chan *chan, struct sk_buff *skb, u16 c chan->conn_state |= L2CAP_CONN_RNR_SENT; - del_timer(&pi->ack_timer); + del_timer(&chan->ack_timer); queue_work(_busy_wq, &pi->busy_work); @@ -3258,7 +3259,7 @@ static inline int l2cap_data_channel_iframe(struct l2cap_chan *chan, u16 rx_cont if (L2CAP_CTRL_FINAL & rx_control && chan->conn_state & L2CAP_CONN_WAIT_F) { - del_timer(&pi->monitor_timer); + del_timer(&chan->monitor_timer); if (chan->unacked_frames > 0) __mod_retrans_timer(); chan->conn_state &= ~L2CAP_CONN_WAIT_F; @@ -3276,7 +3277,7 @@ static inline int l2cap_data_channel_iframe(struct l2cap_chan *chan, u16 rx_cont /* invalid tx_seq */ if (tx_seq_offset >= pi->tx_win) { - l2cap_send_disconn_req(pi->conn, sk, ECONNRESET); + l2cap_send_disconn_req(pi->conn, chan, ECONNRESET); goto drop; } @@ -3341,7 +3342,7 @@ static inline int l2cap_data_channel_iframe(struct l2cap_chan *chan, u16 rx_cont l2cap_send_srejframe(chan, tx_seq); - del_timer(&pi->ack_timer); + del_timer(&chan->ack_timer); } return 0; @@ -3484,7 +3485,6 @@ static inline void l2cap_data_channel_srejframe(struct l2cap_chan *chan, u16 rx_ static inline void l2cap_data_channel_rnrframe(struct l2cap_chan *chan, u16 rx_control) { - struct l2cap_pinfo *pi = l2cap_pi(chan->sk); u8 tx_seq = __get_reqseq(rx_control); BT_DBG("chan %p, req_seq %d ctrl 0x%4.4x", chan, tx_seq, rx_control); @@ -3497,7 +3497,7 @@ static inline void l2cap_data_channel_rnrframe(struct l2cap_chan *chan, u16 rx_c chan->conn_state |= L2CAP_CONN_SEND_FBIT; if (!(chan->conn_state & L2CAP_CONN_SREJ_SENT)) { - del_timer(&pi->retrans_timer); + del_timer(&chan->retrans_timer); if (rx_control & L2CAP_CTRL_POLL) l2cap_send_rr_or_rnr(chan, L2CAP_CTRL_FINAL); return; @@ -3511,13 +3511,11 @@ static inline void l2cap_data_channel_rnrframe(struct l2cap_chan *chan, u16 rx_c static inline int l2cap_data_channel_sframe(struct l2cap_chan *chan, u16 rx_control, struct sk_buff *skb) { - struct sock *sk = chan->sk; - BT_DBG("chan %p rx_control 0x%4.4x len %d", chan, rx_control, skb->len); if (L2CAP_CTRL_FINAL & rx_control && chan->conn_state & L2CAP_CONN_WAIT_F) { - del_timer(&l2cap_pi(sk)->monitor_timer); + del_timer(&chan->monitor_timer); if (chan->unacked_frames > 0) __mod_retrans_timer(); chan->conn_state &= ~L2CAP_CONN_WAIT_F; @@ -3572,7 +3570,7 @@ static int l2cap_ertm_data_rcv(struct sock *sk, struct sk_buff *skb) len -= 2; if (len > pi->mps) { - l2cap_send_disconn_req(pi->conn, sk, ECONNRESET); + l2cap_send_disconn_req(pi->conn, chan, ECONNRESET); goto drop; } @@ -3588,13 +3586,13 @@ static int l2cap_ertm_data_rcv(struct sock *sk, struct sk_buff *skb) /* check for invalid req-seq */ if (req_seq_offset > next_tx_seq_offset) { - l2cap_send_disconn_req(pi->conn, sk, ECONNRESET); + l2cap_send_disconn_req(pi->conn, chan, ECONNRESET); goto drop; } if (__is_iframe(control)) { if (len < 0) { - l2cap_send_disconn_req(pi->conn, sk, ECONNRESET); + l2cap_send_disconn_req(pi->conn, chan, ECONNRESET); goto drop; } @@ -3602,7 +3600,7 @@ static int l2cap_ertm_data_rcv(struct sock *sk, struct sk_buff *skb) } else { if (len != 0) { BT_ERR("%d", len); - l2cap_send_disconn_req(pi->conn, sk, ECONNRESET); + l2cap_send_disconn_req(pi->conn, chan, ECONNRESET); goto drop; } diff --git a/net/bluetooth/l2cap_sock.c b/net/bluetooth/l2cap_sock.c index f90ca25..d66886f 100644 --- a/net/bluetooth/l2cap_sock.c +++ b/net/bluetooth/l2cap_sock.c @@ -866,6 +866,7 @@ static void l2cap_sock_cleanup_listen(struct sock *parent) void __l2cap_sock_close(struct sock *sk, int reason) { struct l2cap_conn *conn = l2cap_pi(sk)->conn; + struct l2cap_chan *chan = l2cap_pi(sk)->chan; BT_DBG("sk %p state %d socket %p", sk, sk->sk_state, sk->sk_socket); @@ -880,9 +881,9 @@ void __l2cap_sock_close(struct sock *sk, int reason) sk->sk_type == SOCK_STREAM) && conn->hcon->type == ACL_LINK) { l2cap_sock_set_timer(sk, sk->sk_sndtimeo); - l2cap_send_disconn_req(conn, sk, reason); + l2cap_send_disconn_req(conn, chan, reason); } else - l2cap_chan_del(l2cap_pi(sk)->chan, reason); + l2cap_chan_del(chan, reason); break; case BT_CONNECT2: @@ -901,16 +902,16 @@ void __l2cap_sock_close(struct sock *sk, int reason) rsp.dcid = cpu_to_le16(l2cap_pi(sk)->scid); rsp.result = cpu_to_le16(result); rsp.status = cpu_to_le16(L2CAP_CS_NO_INFO); - l2cap_send_cmd(conn, l2cap_pi(sk)->chan->ident, - L2CAP_CONN_RSP, sizeof(rsp), &rsp); + l2cap_send_cmd(conn, chan->ident, L2CAP_CONN_RSP, + sizeof(rsp), &rsp); } - l2cap_chan_del(l2cap_pi(sk)->chan, reason); + l2cap_chan_del(chan, reason); break; case BT_CONNECT: case BT_DISCONN: - l2cap_chan_del(l2cap_pi(sk)->chan, reason); + l2cap_chan_del(chan, reason); break; default: -- cgit v0.10.2 From f1c6775be6fc944e32e0150305d9753b9a846519 Mon Sep 17 00:00:00 2001 From: "Gustavo F. Padovan" Date: Fri, 25 Mar 2011 20:36:10 -0300 Subject: Bluetooth: Move srej and busy queues to struct l2cap_chan As part of the moving channel stuff to l2cap_chan. Signed-off-by: Gustavo F. Padovan diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h index 5f4abea..09f4a2f 100644 --- a/include/net/bluetooth/l2cap.h +++ b/include/net/bluetooth/l2cap.h @@ -309,6 +309,8 @@ struct l2cap_chan { struct timer_list retrans_timer; struct timer_list monitor_timer; struct timer_list ack_timer; + struct sk_buff_head srej_q; + struct sk_buff_head busy_q; struct list_head list; }; @@ -347,8 +349,6 @@ struct l2cap_conn { /* ----- L2CAP socket info ----- */ #define l2cap_pi(sk) ((struct l2cap_pinfo *) sk) #define TX_QUEUE(sk) (&l2cap_pi(sk)->tx_queue) -#define SREJ_QUEUE(sk) (&l2cap_pi(sk)->srej_queue) -#define BUSY_QUEUE(sk) (&l2cap_pi(sk)->busy_queue) #define SREJ_LIST(sk) (&l2cap_pi(sk)->srej_l.list) struct srej_list { @@ -384,8 +384,6 @@ struct l2cap_pinfo { __le16 sport; struct sk_buff_head tx_queue; - struct sk_buff_head srej_queue; - struct sk_buff_head busy_queue; struct work_struct busy_work; struct srej_list srej_l; struct l2cap_conn *conn; diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index eaac13cb..06c505b 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -245,8 +245,8 @@ void l2cap_chan_del(struct l2cap_chan *chan, int err) del_timer(&chan->monitor_timer); del_timer(&chan->ack_timer); - skb_queue_purge(SREJ_QUEUE(sk)); - skb_queue_purge(BUSY_QUEUE(sk)); + skb_queue_purge(&chan->srej_q); + skb_queue_purge(&chan->busy_q); list_for_each_entry_safe(l, tmp, SREJ_LIST(sk), list) { list_del(&l->list); @@ -1588,8 +1588,8 @@ static inline void l2cap_ertm_init(struct l2cap_chan *chan) (unsigned long) chan); setup_timer(&chan->ack_timer, l2cap_ack_timeout, (unsigned long) chan); - __skb_queue_head_init(SREJ_QUEUE(sk)); - __skb_queue_head_init(BUSY_QUEUE(sk)); + skb_queue_head_init(&chan->srej_q); + skb_queue_head_init(&chan->busy_q); INIT_WORK(&l2cap_pi(sk)->busy_work, l2cap_busy_work); @@ -2815,16 +2815,15 @@ static inline void l2cap_send_i_or_rr_or_rnr(struct l2cap_chan *chan) static int l2cap_add_to_srej_queue(struct l2cap_chan *chan, struct sk_buff *skb, u8 tx_seq, u8 sar) { - struct sock *sk = chan->sk; struct sk_buff *next_skb; int tx_seq_offset, next_tx_seq_offset; bt_cb(skb)->tx_seq = tx_seq; bt_cb(skb)->sar = sar; - next_skb = skb_peek(SREJ_QUEUE(sk)); + next_skb = skb_peek(&chan->srej_q); if (!next_skb) { - __skb_queue_tail(SREJ_QUEUE(sk), skb); + __skb_queue_tail(&chan->srej_q, skb); return 0; } @@ -2842,16 +2841,16 @@ static int l2cap_add_to_srej_queue(struct l2cap_chan *chan, struct sk_buff *skb, next_tx_seq_offset += 64; if (next_tx_seq_offset > tx_seq_offset) { - __skb_queue_before(SREJ_QUEUE(sk), next_skb, skb); + __skb_queue_before(&chan->srej_q, next_skb, skb); return 0; } - if (skb_queue_is_last(SREJ_QUEUE(sk), next_skb)) + if (skb_queue_is_last(&chan->srej_q, next_skb)) break; - } while ((next_skb = skb_queue_next(SREJ_QUEUE(sk), next_skb))); + } while ((next_skb = skb_queue_next(&chan->srej_q, next_skb))); - __skb_queue_tail(SREJ_QUEUE(sk), skb); + __skb_queue_tail(&chan->srej_q, skb); return 0; } @@ -2971,11 +2970,11 @@ static int l2cap_try_push_rx_skb(struct l2cap_chan *chan) u16 control; int err; - while ((skb = skb_dequeue(BUSY_QUEUE(sk)))) { + while ((skb = skb_dequeue(&chan->busy_q))) { control = bt_cb(skb)->sar << L2CAP_CTRL_SAR_SHIFT; err = l2cap_ertm_reassembly_sdu(chan, skb, control); if (err < 0) { - skb_queue_head(BUSY_QUEUE(sk), skb); + skb_queue_head(&chan->busy_q, skb); return -EBUSY; } @@ -3016,7 +3015,7 @@ static void l2cap_busy_work(struct work_struct *work) lock_sock(sk); add_wait_queue(sk_sleep(sk), &wait); - while ((skb = skb_peek(BUSY_QUEUE(sk)))) { + while ((skb = skb_peek(&pi->chan->busy_q))) { set_current_state(TASK_INTERRUPTIBLE); if (n_tries++ > L2CAP_LOCAL_BUSY_TRIES) { @@ -3059,7 +3058,7 @@ static int l2cap_push_rx_skb(struct l2cap_chan *chan, struct sk_buff *skb, u16 c if (chan->conn_state & L2CAP_CONN_LOCAL_BUSY) { bt_cb(skb)->sar = control >> L2CAP_CTRL_SAR_SHIFT; - __skb_queue_tail(BUSY_QUEUE(sk), skb); + __skb_queue_tail(&chan->busy_q, skb); return l2cap_try_push_rx_skb(chan); @@ -3076,7 +3075,7 @@ static int l2cap_push_rx_skb(struct l2cap_chan *chan, struct sk_buff *skb, u16 c chan->conn_state |= L2CAP_CONN_LOCAL_BUSY; bt_cb(skb)->sar = control >> L2CAP_CTRL_SAR_SHIFT; - __skb_queue_tail(BUSY_QUEUE(sk), skb); + __skb_queue_tail(&chan->busy_q, skb); sctrl = chan->buffer_seq << L2CAP_CTRL_REQSEQ_SHIFT; sctrl |= L2CAP_SUPER_RCV_NOT_READY; @@ -3187,15 +3186,14 @@ drop: static void l2cap_check_srej_gap(struct l2cap_chan *chan, u8 tx_seq) { - struct sock *sk = chan->sk; struct sk_buff *skb; u16 control; - while ((skb = skb_peek(SREJ_QUEUE(sk)))) { + while ((skb = skb_peek(&chan->srej_q))) { if (bt_cb(skb)->tx_seq != tx_seq) break; - skb = skb_dequeue(SREJ_QUEUE(sk)); + skb = skb_dequeue(&chan->srej_q); control = bt_cb(skb)->sar << L2CAP_CTRL_SAR_SHIFT; l2cap_ertm_reassembly_sdu(chan, skb, control); chan->buffer_seq_srej = @@ -3334,8 +3332,8 @@ static inline int l2cap_data_channel_iframe(struct l2cap_chan *chan, u16 rx_cont INIT_LIST_HEAD(SREJ_LIST(sk)); chan->buffer_seq_srej = chan->buffer_seq; - __skb_queue_head_init(SREJ_QUEUE(sk)); - __skb_queue_head_init(BUSY_QUEUE(sk)); + __skb_queue_head_init(&chan->srej_q); + __skb_queue_head_init(&chan->busy_q); l2cap_add_to_srej_queue(chan, skb, tx_seq, sar); chan->conn_state |= L2CAP_CONN_SEND_PBIT; @@ -3352,7 +3350,7 @@ expected: if (chan->conn_state & L2CAP_CONN_SREJ_SENT) { bt_cb(skb)->tx_seq = tx_seq; bt_cb(skb)->sar = sar; - __skb_queue_tail(SREJ_QUEUE(sk), skb); + __skb_queue_tail(&chan->srej_q, skb); return 0; } diff --git a/net/bluetooth/l2cap_sock.c b/net/bluetooth/l2cap_sock.c index d66886f..55dee99 100644 --- a/net/bluetooth/l2cap_sock.c +++ b/net/bluetooth/l2cap_sock.c @@ -1018,8 +1018,6 @@ void l2cap_sock_init(struct sock *sk, struct sock *parent) /* Default config options */ pi->flush_to = L2CAP_DEFAULT_FLUSH_TO; skb_queue_head_init(TX_QUEUE(sk)); - skb_queue_head_init(SREJ_QUEUE(sk)); - skb_queue_head_init(BUSY_QUEUE(sk)); INIT_LIST_HEAD(SREJ_LIST(sk)); } -- cgit v0.10.2 From 311bb895e325e5f4d708c1ed2206da8a3885c83a Mon Sep 17 00:00:00 2001 From: "Gustavo F. Padovan" Date: Fri, 25 Mar 2011 20:41:00 -0300 Subject: Bluetooth: Move busy workqueue to struct l2cap_chan As part of the moving channel stuff to l2cap_chan. Signed-off-by: Gustavo F. Padovan diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h index 09f4a2f..d05d91f 100644 --- a/include/net/bluetooth/l2cap.h +++ b/include/net/bluetooth/l2cap.h @@ -311,6 +311,7 @@ struct l2cap_chan { struct timer_list ack_timer; struct sk_buff_head srej_q; struct sk_buff_head busy_q; + struct work_struct busy_work; struct list_head list; }; @@ -384,7 +385,6 @@ struct l2cap_pinfo { __le16 sport; struct sk_buff_head tx_queue; - struct work_struct busy_work; struct srej_list srej_l; struct l2cap_conn *conn; struct l2cap_chan *chan; diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index 06c505b..d3b5d64 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -1591,7 +1591,7 @@ static inline void l2cap_ertm_init(struct l2cap_chan *chan) skb_queue_head_init(&chan->srej_q); skb_queue_head_init(&chan->busy_q); - INIT_WORK(&l2cap_pi(sk)->busy_work, l2cap_busy_work); + INIT_WORK(&chan->busy_work, l2cap_busy_work); sk->sk_backlog_rcv = l2cap_ertm_data_rcv; } @@ -3006,21 +3006,21 @@ done: static void l2cap_busy_work(struct work_struct *work) { DECLARE_WAITQUEUE(wait, current); - struct l2cap_pinfo *pi = - container_of(work, struct l2cap_pinfo, busy_work); - struct sock *sk = (struct sock *)pi; + struct l2cap_chan *chan = + container_of(work, struct l2cap_chan, busy_work); + struct sock *sk = chan->sk; int n_tries = 0, timeo = HZ/5, err; struct sk_buff *skb; lock_sock(sk); add_wait_queue(sk_sleep(sk), &wait); - while ((skb = skb_peek(&pi->chan->busy_q))) { + while ((skb = skb_peek(&chan->busy_q))) { set_current_state(TASK_INTERRUPTIBLE); if (n_tries++ > L2CAP_LOCAL_BUSY_TRIES) { err = -EBUSY; - l2cap_send_disconn_req(pi->conn, pi->chan, EBUSY); + l2cap_send_disconn_req(l2cap_pi(sk)->conn, chan, EBUSY); break; } @@ -3040,7 +3040,7 @@ static void l2cap_busy_work(struct work_struct *work) if (err) break; - if (l2cap_try_push_rx_skb(l2cap_pi(sk)->chan) == 0) + if (l2cap_try_push_rx_skb(chan) == 0) break; } @@ -3052,8 +3052,6 @@ static void l2cap_busy_work(struct work_struct *work) static int l2cap_push_rx_skb(struct l2cap_chan *chan, struct sk_buff *skb, u16 control) { - struct sock *sk = chan->sk; - struct l2cap_pinfo *pi = l2cap_pi(sk); int sctrl, err; if (chan->conn_state & L2CAP_CONN_LOCAL_BUSY) { @@ -3071,7 +3069,7 @@ static int l2cap_push_rx_skb(struct l2cap_chan *chan, struct sk_buff *skb, u16 c } /* Busy Condition */ - BT_DBG("sk %p, Enter local busy", sk); + BT_DBG("chan %p, Enter local busy", chan); chan->conn_state |= L2CAP_CONN_LOCAL_BUSY; bt_cb(skb)->sar = control >> L2CAP_CTRL_SAR_SHIFT; @@ -3085,7 +3083,7 @@ static int l2cap_push_rx_skb(struct l2cap_chan *chan, struct sk_buff *skb, u16 c del_timer(&chan->ack_timer); - queue_work(_busy_wq, &pi->busy_work); + queue_work(_busy_wq, &chan->busy_work); return err; } -- cgit v0.10.2 From 2ead70b8390d199ca04cd35311b51f5f3676079e Mon Sep 17 00:00:00 2001 From: "Gustavo F. Padovan" Date: Fri, 1 Apr 2011 15:13:36 -0300 Subject: Bluetooth: Fix lockdep warning with skb list lock This is a regression acctually, caused by the first patch series for creating a formal strcut l2cap_chan. Signed-off-by: Gustavo F. Padovan diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index d3b5d64..7264119 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -236,6 +236,10 @@ void l2cap_chan_del(struct l2cap_chan *chan, int err) } else sk->sk_state_change(sk); + if (!(l2cap_pi(sk)->conf_state & L2CAP_CONF_OUTPUT_DONE && + l2cap_pi(sk)->conf_state & L2CAP_CONF_INPUT_DONE)) + goto free; + skb_queue_purge(TX_QUEUE(sk)); if (l2cap_pi(sk)->mode == L2CAP_MODE_ERTM) { @@ -254,6 +258,7 @@ void l2cap_chan_del(struct l2cap_chan *chan, int err) } } +free: kfree(chan); } -- cgit v0.10.2 From 4b97291429bf59c09a969184a7d2ebde7287e7eb Mon Sep 17 00:00:00 2001 From: Ajit Khaparde Date: Wed, 6 Apr 2011 18:07:43 +0000 Subject: be2net: add rxhash support Add rxhash support, Based on initial work by Eric Dumazet. Cc: Eric Dumazet Signed-off-by: Ajit Khaparde Signed-off-by: David S. Miller diff --git a/drivers/net/benet/be.h b/drivers/net/benet/be.h index ea1ea82..ab5be05 100644 --- a/drivers/net/benet/be.h +++ b/drivers/net/benet/be.h @@ -485,6 +485,11 @@ static inline void be_vf_eth_addr_generate(struct be_adapter *adapter, u8 *mac) memcpy(mac, adapter->netdev->dev_addr, 3); } +static inline bool be_multi_rxq(const struct be_adapter *adapter) +{ + return adapter->num_rx_qs > 1; +} + extern void be_cq_notify(struct be_adapter *adapter, u16 qid, bool arm, u16 num_popped); extern void be_link_status_update(struct be_adapter *adapter, bool link_up); diff --git a/drivers/net/benet/be_ethtool.c b/drivers/net/benet/be_ethtool.c index a665697..1565c81 100644 --- a/drivers/net/benet/be_ethtool.c +++ b/drivers/net/benet/be_ethtool.c @@ -735,6 +735,18 @@ be_read_eeprom(struct net_device *netdev, struct ethtool_eeprom *eeprom, return status; } +static int be_set_flags(struct net_device *netdev, u32 data) +{ + struct be_adapter *adapter = netdev_priv(netdev); + int rc = -1; + + if (be_multi_rxq(adapter)) + rc = ethtool_op_set_flags(netdev, data, ETH_FLAG_RXHASH | + ETH_FLAG_TXVLAN | ETH_FLAG_RXVLAN); + + return rc; +} + const struct ethtool_ops be_ethtool_ops = { .get_settings = be_get_settings, .get_drvinfo = be_get_drvinfo, @@ -764,4 +776,5 @@ const struct ethtool_ops be_ethtool_ops = { .get_regs = be_get_regs, .flash_device = be_do_flash, .self_test = be_self_test, + .set_flags = be_set_flags, }; diff --git a/drivers/net/benet/be_main.c b/drivers/net/benet/be_main.c index 2c36853..d762c2a 100644 --- a/drivers/net/benet/be_main.c +++ b/drivers/net/benet/be_main.c @@ -116,11 +116,6 @@ static char *ue_status_hi_desc[] = { "Unknown" }; -static inline bool be_multi_rxq(struct be_adapter *adapter) -{ - return (adapter->num_rx_qs > 1); -} - static void be_queue_free(struct be_adapter *adapter, struct be_queue_info *q) { struct be_dma_mem *mem = &q->dma_mem; @@ -1012,6 +1007,9 @@ static void be_rx_compl_process(struct be_adapter *adapter, skb->truesize = skb->len + sizeof(struct sk_buff); skb->protocol = eth_type_trans(skb, adapter->netdev); + if (adapter->netdev->features & NETIF_F_RXHASH) + skb->rxhash = rxcp->rss_hash; + if (unlikely(rxcp->vlanf)) { if (!adapter->vlan_grp || adapter->vlans_added == 0) { @@ -1072,6 +1070,8 @@ static void be_rx_compl_process_gro(struct be_adapter *adapter, skb->data_len = rxcp->pkt_size; skb->truesize += rxcp->pkt_size; skb->ip_summed = CHECKSUM_UNNECESSARY; + if (adapter->netdev->features & NETIF_F_RXHASH) + skb->rxhash = rxcp->rss_hash; if (likely(!rxcp->vlanf)) napi_gro_frags(&eq_obj->napi); @@ -1101,6 +1101,8 @@ static void be_parse_rx_compl_v1(struct be_adapter *adapter, AMAP_GET_BITS(struct amap_eth_rx_compl_v1, numfrags, compl); rxcp->pkt_type = AMAP_GET_BITS(struct amap_eth_rx_compl_v1, cast_enc, compl); + rxcp->rss_hash = + AMAP_GET_BITS(struct amap_eth_rx_compl_v1, rsshash, rxcp); if (rxcp->vlanf) { rxcp->vtm = AMAP_GET_BITS(struct amap_eth_rx_compl_v1, vtm, compl); @@ -1131,6 +1133,8 @@ static void be_parse_rx_compl_v0(struct be_adapter *adapter, AMAP_GET_BITS(struct amap_eth_rx_compl_v0, numfrags, compl); rxcp->pkt_type = AMAP_GET_BITS(struct amap_eth_rx_compl_v0, cast_enc, compl); + rxcp->rss_hash = + AMAP_GET_BITS(struct amap_eth_rx_compl_v0, rsshash, rxcp); if (rxcp->vlanf) { rxcp->vtm = AMAP_GET_BITS(struct amap_eth_rx_compl_v0, vtm, compl); @@ -2615,6 +2619,9 @@ static void be_netdev_init(struct net_device *netdev) NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM | NETIF_F_GRO | NETIF_F_TSO6; + if (be_multi_rxq(adapter)) + netdev->features |= NETIF_F_RXHASH; + netdev->vlan_features |= NETIF_F_SG | NETIF_F_TSO | NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM; -- cgit v0.10.2 From b0060586d23968d66325d775651d92ee830c032f Mon Sep 17 00:00:00 2001 From: Ajit Khaparde Date: Wed, 6 Apr 2011 18:08:01 +0000 Subject: be2net: use common method to check for sriov function type Lancer and BE can both use SLI_INTF_REG to check a VF or a PF. Signed-off-by: Ajit Khaparde Signed-off-by: David S. Miller diff --git a/drivers/net/benet/be.h b/drivers/net/benet/be.h index ab5be05..7e20400 100644 --- a/drivers/net/benet/be.h +++ b/drivers/net/benet/be.h @@ -458,18 +458,10 @@ static inline u8 is_udp_pkt(struct sk_buff *skb) static inline void be_check_sriov_fn_type(struct be_adapter *adapter) { - u8 data; u32 sli_intf; - if (lancer_chip(adapter)) { - pci_read_config_dword(adapter->pdev, SLI_INTF_REG_OFFSET, - &sli_intf); - adapter->is_virtfn = (sli_intf & SLI_INTF_FT_MASK) ? 1 : 0; - } else { - pci_write_config_byte(adapter->pdev, 0xFE, 0xAA); - pci_read_config_byte(adapter->pdev, 0xFE, &data); - adapter->is_virtfn = (data != 0xAA); - } + pci_read_config_dword(adapter->pdev, SLI_INTF_REG_OFFSET, &sli_intf); + adapter->is_virtfn = (sli_intf & SLI_INTF_FT_MASK) ? 1 : 0; } static inline void be_vf_eth_addr_generate(struct be_adapter *adapter, u8 *mac) -- cgit v0.10.2 From 81be8f0ab47db1171dac0eb8b062291603b57dd4 Mon Sep 17 00:00:00 2001 From: Ajit Khaparde Date: Wed, 6 Apr 2011 18:08:17 +0000 Subject: be2net: fix to get max VFs supported from adapter The user supplied num_vfs value need not be compared against a static BE_MAX_VF, but can be checked against the actual VFs that the device can support. Signed-off-by: Ajit Khaparde Signed-off-by: David S. Miller diff --git a/drivers/net/benet/be_main.c b/drivers/net/benet/be_main.c index d762c2a..bc11078 100644 --- a/drivers/net/benet/be_main.c +++ b/drivers/net/benet/be_main.c @@ -1947,7 +1947,20 @@ static void be_sriov_enable(struct be_adapter *adapter) be_check_sriov_fn_type(adapter); #ifdef CONFIG_PCI_IOV if (be_physfn(adapter) && num_vfs) { - int status; + int status, pos; + u16 nvfs; + + pos = pci_find_ext_capability(adapter->pdev, + PCI_EXT_CAP_ID_SRIOV); + pci_read_config_word(adapter->pdev, + pos + PCI_SRIOV_TOTAL_VF, &nvfs); + + if (num_vfs > nvfs) { + dev_info(&adapter->pdev->dev, + "Device supports %d VFs and not %d\n", + nvfs, num_vfs); + num_vfs = nvfs; + } status = pci_enable_sriov(adapter->pdev, num_vfs); adapter->sriov_enabled = status ? false : true; @@ -3284,13 +3297,6 @@ static int __init be_init_module(void) rx_frag_size = 2048; } - if (num_vfs > 32) { - printk(KERN_WARNING DRV_NAME - " : Module param num_vfs must not be greater than 32." - "Using 32\n"); - num_vfs = 32; - } - return pci_register_driver(&be_driver); } module_init(be_init_module); -- cgit v0.10.2 From 48f5a19168c228e6533401c563d9fcbc152bc33f Mon Sep 17 00:00:00 2001 From: Ajit Khaparde Date: Wed, 6 Apr 2011 18:08:30 +0000 Subject: be2net: dynamically allocate adapter->vf_cfg Instead of a fixed sized array for vf_cfg, allocate the size dynamically depending on number of VFs the device supports. Signed-off-by: Ajit Khaparde Signed-off-by: David S. Miller diff --git a/drivers/net/benet/be.h b/drivers/net/benet/be.h index 7e20400..d2c42f5 100644 --- a/drivers/net/benet/be.h +++ b/drivers/net/benet/be.h @@ -92,8 +92,6 @@ static inline char *nic_name(struct pci_dev *pdev) #define FW_VER_LEN 32 -#define BE_MAX_VF 32 - struct be_dma_mem { void *va; dma_addr_t dma; @@ -336,7 +334,7 @@ struct be_adapter { bool be3_native; bool sriov_enabled; - struct be_vf_cfg vf_cfg[BE_MAX_VF]; + struct be_vf_cfg *vf_cfg; u8 is_virtfn; u32 sli_family; u8 hba_port_num; diff --git a/drivers/net/benet/be_main.c b/drivers/net/benet/be_main.c index bc11078..6e7df0d 100644 --- a/drivers/net/benet/be_main.c +++ b/drivers/net/benet/be_main.c @@ -2838,6 +2838,7 @@ static void __devexit be_remove(struct pci_dev *pdev) be_ctrl_cleanup(adapter); + kfree(adapter->vf_cfg); be_sriov_disable(adapter); be_msix_disable(adapter); @@ -3022,16 +3023,23 @@ static int __devinit be_probe(struct pci_dev *pdev, } be_sriov_enable(adapter); + if (adapter->sriov_enabled) { + adapter->vf_cfg = kcalloc(num_vfs, + sizeof(struct be_vf_cfg), GFP_KERNEL); + + if (!adapter->vf_cfg) + goto free_netdev; + } status = be_ctrl_init(adapter); if (status) - goto free_netdev; + goto free_vf_cfg; if (lancer_chip(adapter)) { status = lancer_test_and_set_rdy_state(adapter); if (status) { dev_err(&pdev->dev, "Adapter in non recoverable error\n"); - goto free_netdev; + goto ctrl_clean; } } @@ -3093,6 +3101,8 @@ stats_clean: be_stats_cleanup(adapter); ctrl_clean: be_ctrl_cleanup(adapter); +free_vf_cfg: + kfree(adapter->vf_cfg); free_netdev: be_sriov_disable(adapter); free_netdev(netdev); -- cgit v0.10.2 From 57841869197831542f25c739beaeab4465977878 Mon Sep 17 00:00:00 2001 From: Ajit Khaparde Date: Wed, 6 Apr 2011 18:08:43 +0000 Subject: be2net: call FLR after setup wol in be_shutdown Calling setup_wol after a reset is inconsequential. The WOL setting should be programmed before FLR. And yes, FLR does not erase wol information. Signed-off-by: Ajit Khaparde Signed-off-by: David S. Miller diff --git a/drivers/net/benet/be_main.c b/drivers/net/benet/be_main.c index 6e7df0d..b883140 100644 --- a/drivers/net/benet/be_main.c +++ b/drivers/net/benet/be_main.c @@ -3191,11 +3191,11 @@ static void be_shutdown(struct pci_dev *pdev) netif_device_detach(adapter->netdev); - be_cmd_reset_function(adapter); - if (adapter->wol) be_setup_wol(adapter, true); + be_cmd_reset_function(adapter); + pci_disable_device(pdev); } -- cgit v0.10.2 From 1b877cb57a8e329e571cd41b60ed51ba8f8c9edd Mon Sep 17 00:00:00 2001 From: Dilan Lee Date: Thu, 7 Apr 2011 11:08:38 -0600 Subject: ASoC: WM8903: HP and Line out PGA/mixer DAPM fixes Update the headphone and line out mixers and PGAs use the same logical set of register bits and sequencing as the speaker mixer/PGA. This allows ALSA controls for mute and volume on headphone and line out to operate correctly. Per conversation on alsa-devel, earlier datasheets indicated that the POWER_MANAGEMENT_* register bits 0 and 1 were aliases to ANALOG_* register bits 0 and 4, and hence only one copy of those bits was programmed. However, later datasheets corrected this. From: Dilan Lee [swarren: Applied same change to headphone widgets] Signed-off-by: Stephen Warren Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/wm8903.c b/sound/soc/codecs/wm8903.c index ae1cadf..f52b623 100644 --- a/sound/soc/codecs/wm8903.c +++ b/sound/soc/codecs/wm8903.c @@ -247,8 +247,6 @@ static int wm8903_volatile_register(struct snd_soc_codec *codec, unsigned int re case WM8903_REVISION_NUMBER: case WM8903_INTERRUPT_STATUS_1: case WM8903_WRITE_SEQUENCER_4: - case WM8903_POWER_MANAGEMENT_3: - case WM8903_POWER_MANAGEMENT_2: case WM8903_DC_SERVO_READBACK_1: case WM8903_DC_SERVO_READBACK_2: case WM8903_DC_SERVO_READBACK_3: @@ -875,34 +873,40 @@ SND_SOC_DAPM_MIXER("Left Speaker Mixer", WM8903_POWER_MANAGEMENT_4, 1, 0, SND_SOC_DAPM_MIXER("Right Speaker Mixer", WM8903_POWER_MANAGEMENT_4, 0, 0, right_speaker_mixer, ARRAY_SIZE(right_speaker_mixer)), -SND_SOC_DAPM_PGA_S("Left Headphone Output PGA", 0, WM8903_ANALOGUE_HP_0, - 4, 0, NULL, 0), -SND_SOC_DAPM_PGA_S("Right Headphone Output PGA", 0, WM8903_ANALOGUE_HP_0, +SND_SOC_DAPM_PGA_S("Left Headphone Output PGA", 0, WM8903_POWER_MANAGEMENT_2, + 1, 0, NULL, 0), +SND_SOC_DAPM_PGA_S("Right Headphone Output PGA", 0, WM8903_POWER_MANAGEMENT_2, 0, 0, NULL, 0), -SND_SOC_DAPM_PGA_S("Left Line Output PGA", 0, WM8903_ANALOGUE_LINEOUT_0, 4, 0, +SND_SOC_DAPM_PGA_S("Left Line Output PGA", 0, WM8903_POWER_MANAGEMENT_3, 1, 0, NULL, 0), -SND_SOC_DAPM_PGA_S("Right Line Output PGA", 0, WM8903_ANALOGUE_LINEOUT_0, 0, 0, +SND_SOC_DAPM_PGA_S("Right Line Output PGA", 0, WM8903_POWER_MANAGEMENT_3, 0, 0, NULL, 0), SND_SOC_DAPM_PGA_S("HPL_RMV_SHORT", 4, WM8903_ANALOGUE_HP_0, 7, 0, NULL, 0), SND_SOC_DAPM_PGA_S("HPL_ENA_OUTP", 3, WM8903_ANALOGUE_HP_0, 6, 0, NULL, 0), -SND_SOC_DAPM_PGA_S("HPL_ENA_DLY", 1, WM8903_ANALOGUE_HP_0, 5, 0, NULL, 0), +SND_SOC_DAPM_PGA_S("HPL_ENA_DLY", 2, WM8903_ANALOGUE_HP_0, 5, 0, NULL, 0), +SND_SOC_DAPM_PGA_S("HPL_ENA", 1, WM8903_ANALOGUE_HP_0, 4, 0, NULL, 0), SND_SOC_DAPM_PGA_S("HPR_RMV_SHORT", 4, WM8903_ANALOGUE_HP_0, 3, 0, NULL, 0), SND_SOC_DAPM_PGA_S("HPR_ENA_OUTP", 3, WM8903_ANALOGUE_HP_0, 2, 0, NULL, 0), -SND_SOC_DAPM_PGA_S("HPR_ENA_DLY", 1, WM8903_ANALOGUE_HP_0, 1, 0, NULL, 0), +SND_SOC_DAPM_PGA_S("HPR_ENA_DLY", 2, WM8903_ANALOGUE_HP_0, 1, 0, NULL, 0), +SND_SOC_DAPM_PGA_S("HPR_ENA", 1, WM8903_ANALOGUE_HP_0, 0, 0, NULL, 0), SND_SOC_DAPM_PGA_S("LINEOUTL_RMV_SHORT", 4, WM8903_ANALOGUE_LINEOUT_0, 7, 0, NULL, 0), SND_SOC_DAPM_PGA_S("LINEOUTL_ENA_OUTP", 3, WM8903_ANALOGUE_LINEOUT_0, 6, 0, NULL, 0), -SND_SOC_DAPM_PGA_S("LINEOUTL_ENA_DLY", 1, WM8903_ANALOGUE_LINEOUT_0, 5, 0, +SND_SOC_DAPM_PGA_S("LINEOUTL_ENA_DLY", 2, WM8903_ANALOGUE_LINEOUT_0, 5, 0, + NULL, 0), +SND_SOC_DAPM_PGA_S("LINEOUTL_ENA", 1, WM8903_ANALOGUE_LINEOUT_0, 4, 0, NULL, 0), SND_SOC_DAPM_PGA_S("LINEOUTR_RMV_SHORT", 4, WM8903_ANALOGUE_LINEOUT_0, 3, 0, NULL, 0), SND_SOC_DAPM_PGA_S("LINEOUTR_ENA_OUTP", 3, WM8903_ANALOGUE_LINEOUT_0, 2, 0, NULL, 0), -SND_SOC_DAPM_PGA_S("LINEOUTR_ENA_DLY", 1, WM8903_ANALOGUE_LINEOUT_0, 1, 0, +SND_SOC_DAPM_PGA_S("LINEOUTR_ENA_DLY", 2, WM8903_ANALOGUE_LINEOUT_0, 1, 0, + NULL, 0), +SND_SOC_DAPM_PGA_S("LINEOUTR_ENA", 1, WM8903_ANALOGUE_LINEOUT_0, 0, 0, NULL, 0), SND_SOC_DAPM_SUPPLY("DCS Master", WM8903_DC_SERVO_0, 4, 0, NULL, 0), @@ -1037,10 +1041,14 @@ static const struct snd_soc_dapm_route intercon[] = { { "Left Speaker PGA", NULL, "Left Speaker Mixer" }, { "Right Speaker PGA", NULL, "Right Speaker Mixer" }, - { "HPL_ENA_DLY", NULL, "Left Headphone Output PGA" }, - { "HPR_ENA_DLY", NULL, "Right Headphone Output PGA" }, - { "LINEOUTL_ENA_DLY", NULL, "Left Line Output PGA" }, - { "LINEOUTR_ENA_DLY", NULL, "Right Line Output PGA" }, + { "HPL_ENA", NULL, "Left Headphone Output PGA" }, + { "HPR_ENA", NULL, "Right Headphone Output PGA" }, + { "HPL_ENA_DLY", NULL, "HPL_ENA" }, + { "HPR_ENA_DLY", NULL, "HPR_ENA" }, + { "LINEOUTL_ENA", NULL, "Left Line Output PGA" }, + { "LINEOUTR_ENA", NULL, "Right Line Output PGA" }, + { "LINEOUTL_ENA_DLY", NULL, "LINEOUTL_ENA" }, + { "LINEOUTR_ENA_DLY", NULL, "LINEOUTR_ENA" }, { "HPL_DCS", NULL, "DCS Master" }, { "HPR_DCS", NULL, "DCS Master" }, -- cgit v0.10.2 From e92702b1046a418a562878b22f92433517760921 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Miros=C5=82aw?= Date: Thu, 31 Mar 2011 01:01:35 +0000 Subject: skge: convert to hw_features MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit just IP_CSUM. This needs testing and so is not changed here. Signed-off-by: MichaÅ‚ MirosÅ‚aw Signed-off-by: David S. Miller diff --git a/drivers/net/skge.c b/drivers/net/skge.c index e579ff7..310dcbc 100644 --- a/drivers/net/skge.c +++ b/drivers/net/skge.c @@ -537,46 +537,6 @@ static int skge_nway_reset(struct net_device *dev) return 0; } -static int skge_set_sg(struct net_device *dev, u32 data) -{ - struct skge_port *skge = netdev_priv(dev); - struct skge_hw *hw = skge->hw; - - if (hw->chip_id == CHIP_ID_GENESIS && data) - return -EOPNOTSUPP; - return ethtool_op_set_sg(dev, data); -} - -static int skge_set_tx_csum(struct net_device *dev, u32 data) -{ - struct skge_port *skge = netdev_priv(dev); - struct skge_hw *hw = skge->hw; - - if (hw->chip_id == CHIP_ID_GENESIS && data) - return -EOPNOTSUPP; - - return ethtool_op_set_tx_csum(dev, data); -} - -static u32 skge_get_rx_csum(struct net_device *dev) -{ - struct skge_port *skge = netdev_priv(dev); - - return skge->rx_csum; -} - -/* Only Yukon supports checksum offload. */ -static int skge_set_rx_csum(struct net_device *dev, u32 data) -{ - struct skge_port *skge = netdev_priv(dev); - - if (skge->hw->chip_id == CHIP_ID_GENESIS && data) - return -EOPNOTSUPP; - - skge->rx_csum = data; - return 0; -} - static void skge_get_pauseparam(struct net_device *dev, struct ethtool_pauseparam *ecmd) { @@ -924,10 +884,6 @@ static const struct ethtool_ops skge_ethtool_ops = { .set_pauseparam = skge_set_pauseparam, .get_coalesce = skge_get_coalesce, .set_coalesce = skge_set_coalesce, - .set_sg = skge_set_sg, - .set_tx_csum = skge_set_tx_csum, - .get_rx_csum = skge_get_rx_csum, - .set_rx_csum = skge_set_rx_csum, .get_strings = skge_get_strings, .set_phys_id = skge_set_phys_id, .get_sset_count = skge_get_sset_count, @@ -3084,7 +3040,8 @@ static struct sk_buff *skge_rx_get(struct net_device *dev, } skb_put(skb, len); - if (skge->rx_csum) { + + if (dev->features & NETIF_F_RXCSUM) { skb->csum = csum; skb->ip_summed = CHECKSUM_COMPLETE; } @@ -3846,10 +3803,10 @@ static struct net_device *skge_devinit(struct skge_hw *hw, int port, setup_timer(&skge->link_timer, xm_link_timer, (unsigned long) skge); if (hw->chip_id != CHIP_ID_GENESIS) { - dev->features |= NETIF_F_IP_CSUM | NETIF_F_SG; - skge->rx_csum = 1; + dev->hw_features = NETIF_F_IP_CSUM | NETIF_F_SG | + NETIF_F_RXCSUM; + dev->features |= dev->hw_features; } - dev->features |= NETIF_F_GRO; /* read the mac address */ memcpy_fromio(dev->dev_addr, hw->regs + B2_MAC_1 + port*8, ETH_ALEN); diff --git a/drivers/net/skge.h b/drivers/net/skge.h index 507addc..f055c47 100644 --- a/drivers/net/skge.h +++ b/drivers/net/skge.h @@ -2460,7 +2460,6 @@ struct skge_port { struct timer_list link_timer; enum pause_control flow_control; enum pause_status flow_status; - u8 rx_csum; u8 blink_on; u8 wol; u8 autoneg; /* AUTONEG_ENABLE, AUTONEG_DISABLE */ -- cgit v0.10.2 From 6332c8d3a5e352fae854cbcac764622e083461e5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Miros=C5=82aw?= Date: Thu, 7 Apr 2011 02:43:48 +0000 Subject: net: benet: convert to hw_features MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Simple conversion. This also fixes a bug in TX checksum toggling --- driver was changing NETIF_F_HW_CSUM instead of NETIF_F_IP_CSUM+NETIF_F_IPV6_CSUM. Signed-off-by: MichaÅ‚ MirosÅ‚aw Signed-off-by: David S. Miller diff --git a/drivers/net/benet/be.h b/drivers/net/benet/be.h index d2c42f5..a0b4743 100644 --- a/drivers/net/benet/be.h +++ b/drivers/net/benet/be.h @@ -307,7 +307,6 @@ struct be_adapter { u16 work_counter; /* Ethtool knobs and info */ - bool rx_csum; /* BE card must perform rx-checksumming */ char fw_ver[FW_VER_LEN]; u32 if_handle; /* Used to configure filtering */ u32 pmac_id; /* MAC addr handle used by BE card */ diff --git a/drivers/net/benet/be_ethtool.c b/drivers/net/benet/be_ethtool.c index 1565c81..96f5502 100644 --- a/drivers/net/benet/be_ethtool.c +++ b/drivers/net/benet/be_ethtool.c @@ -261,25 +261,6 @@ be_set_coalesce(struct net_device *netdev, struct ethtool_coalesce *coalesce) return 0; } -static u32 be_get_rx_csum(struct net_device *netdev) -{ - struct be_adapter *adapter = netdev_priv(netdev); - - return adapter->rx_csum; -} - -static int be_set_rx_csum(struct net_device *netdev, uint32_t data) -{ - struct be_adapter *adapter = netdev_priv(netdev); - - if (data) - adapter->rx_csum = true; - else - adapter->rx_csum = false; - - return 0; -} - static void be_get_ethtool_stats(struct net_device *netdev, struct ethtool_stats *stats, uint64_t *data) @@ -760,14 +741,6 @@ const struct ethtool_ops be_ethtool_ops = { .get_ringparam = be_get_ringparam, .get_pauseparam = be_get_pauseparam, .set_pauseparam = be_set_pauseparam, - .get_rx_csum = be_get_rx_csum, - .set_rx_csum = be_set_rx_csum, - .get_tx_csum = ethtool_op_get_tx_csum, - .set_tx_csum = ethtool_op_set_tx_hw_csum, - .get_sg = ethtool_op_get_sg, - .set_sg = ethtool_op_set_sg, - .get_tso = ethtool_op_get_tso, - .set_tso = ethtool_op_set_tso, .get_strings = be_get_stat_strings, .set_phys_id = be_set_phys_id, .get_sset_count = be_get_sset_count, diff --git a/drivers/net/benet/be_main.c b/drivers/net/benet/be_main.c index b883140..58a652f 100644 --- a/drivers/net/benet/be_main.c +++ b/drivers/net/benet/be_main.c @@ -988,9 +988,10 @@ static void be_rx_compl_process(struct be_adapter *adapter, struct be_rx_obj *rxo, struct be_rx_compl_info *rxcp) { + struct net_device *netdev = adapter->netdev; struct sk_buff *skb; - skb = netdev_alloc_skb_ip_align(adapter->netdev, BE_HDR_LEN); + skb = netdev_alloc_skb_ip_align(netdev, BE_HDR_LEN); if (unlikely(!skb)) { if (net_ratelimit()) dev_warn(&adapter->pdev->dev, "skb alloc failed\n"); @@ -1000,13 +1001,13 @@ static void be_rx_compl_process(struct be_adapter *adapter, skb_fill_rx_data(adapter, rxo, skb, rxcp); - if (likely(adapter->rx_csum && csum_passed(rxcp))) + if (likely((netdev->features & NETIF_F_RXCSUM) && csum_passed(rxcp))) skb->ip_summed = CHECKSUM_UNNECESSARY; else skb_checksum_none_assert(skb); skb->truesize = skb->len + sizeof(struct sk_buff); - skb->protocol = eth_type_trans(skb, adapter->netdev); + skb->protocol = eth_type_trans(skb, netdev); if (adapter->netdev->features & NETIF_F_RXHASH) skb->rxhash = rxcp->rss_hash; @@ -2627,10 +2628,12 @@ static void be_netdev_init(struct net_device *netdev) struct be_rx_obj *rxo; int i; - netdev->features |= NETIF_F_SG | NETIF_F_HW_VLAN_RX | NETIF_F_TSO | - NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_FILTER | - NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM | - NETIF_F_GRO | NETIF_F_TSO6; + netdev->hw_features |= NETIF_F_SG | NETIF_F_TSO | NETIF_F_TSO6 | + NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM | NETIF_F_RXCSUM; + + netdev->features |= netdev->hw_features | + NETIF_F_HW_VLAN_RX | NETIF_F_HW_VLAN_TX | + NETIF_F_HW_VLAN_FILTER; if (be_multi_rxq(adapter)) netdev->features |= NETIF_F_RXHASH; @@ -2643,8 +2646,6 @@ static void be_netdev_init(struct net_device *netdev) netdev->flags |= IFF_MULTICAST; - adapter->rx_csum = true; - /* Default settings for Rx and Tx flow control */ adapter->rx_fc = true; adapter->tx_fc = true; -- cgit v0.10.2 From 5ec8f9b8e6d87faa9d3a4b079b83e3c0d9c39921 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Miros=C5=82aw?= Date: Thu, 7 Apr 2011 02:43:48 +0000 Subject: net: enic: convert to hw_features MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit As the driver uses GRO and not LRO, LRO settings are ignored anyway and are removed here to avoid confusion. Signed-off-by: MichaÅ‚ MirosÅ‚aw Signed-off-by: David S. Miller diff --git a/drivers/net/enic/enic.h b/drivers/net/enic/enic.h index 178b94d..38b351c 100644 --- a/drivers/net/enic/enic.h +++ b/drivers/net/enic/enic.h @@ -84,7 +84,6 @@ struct enic { unsigned int flags; unsigned int mc_count; unsigned int uc_count; - int csum_rx_enabled; u32 port_mtu; u32 rx_coalesce_usecs; u32 tx_coalesce_usecs; diff --git a/drivers/net/enic/enic_main.c b/drivers/net/enic/enic_main.c index 9a3a027..b224551 100644 --- a/drivers/net/enic/enic_main.c +++ b/drivers/net/enic/enic_main.c @@ -251,56 +251,6 @@ static void enic_get_ethtool_stats(struct net_device *netdev, *(data++) = ((u64 *)&vstats->rx)[enic_rx_stats[i].offset]; } -static u32 enic_get_rx_csum(struct net_device *netdev) -{ - struct enic *enic = netdev_priv(netdev); - return enic->csum_rx_enabled; -} - -static int enic_set_rx_csum(struct net_device *netdev, u32 data) -{ - struct enic *enic = netdev_priv(netdev); - - if (data && !ENIC_SETTING(enic, RXCSUM)) - return -EINVAL; - - enic->csum_rx_enabled = !!data; - - return 0; -} - -static int enic_set_tx_csum(struct net_device *netdev, u32 data) -{ - struct enic *enic = netdev_priv(netdev); - - if (data && !ENIC_SETTING(enic, TXCSUM)) - return -EINVAL; - - if (data) - netdev->features |= NETIF_F_HW_CSUM; - else - netdev->features &= ~NETIF_F_HW_CSUM; - - return 0; -} - -static int enic_set_tso(struct net_device *netdev, u32 data) -{ - struct enic *enic = netdev_priv(netdev); - - if (data && !ENIC_SETTING(enic, TSO)) - return -EINVAL; - - if (data) - netdev->features |= - NETIF_F_TSO | NETIF_F_TSO6 | NETIF_F_TSO_ECN; - else - netdev->features &= - ~(NETIF_F_TSO | NETIF_F_TSO6 | NETIF_F_TSO_ECN); - - return 0; -} - static u32 enic_get_msglevel(struct net_device *netdev) { struct enic *enic = netdev_priv(netdev); @@ -388,17 +338,8 @@ static const struct ethtool_ops enic_ethtool_ops = { .get_strings = enic_get_strings, .get_sset_count = enic_get_sset_count, .get_ethtool_stats = enic_get_ethtool_stats, - .get_rx_csum = enic_get_rx_csum, - .set_rx_csum = enic_set_rx_csum, - .get_tx_csum = ethtool_op_get_tx_csum, - .set_tx_csum = enic_set_tx_csum, - .get_sg = ethtool_op_get_sg, - .set_sg = ethtool_op_set_sg, - .get_tso = ethtool_op_get_tso, - .set_tso = enic_set_tso, .get_coalesce = enic_get_coalesce, .set_coalesce = enic_set_coalesce, - .get_flags = ethtool_op_get_flags, }; static void enic_free_wq_buf(struct vnic_wq *wq, struct vnic_wq_buf *buf) @@ -1309,7 +1250,7 @@ static void enic_rq_indicate_buf(struct vnic_rq *rq, skb_put(skb, bytes_written); skb->protocol = eth_type_trans(skb, netdev); - if (enic->csum_rx_enabled && !csum_not_calc) { + if ((netdev->features & NETIF_F_RXCSUM) && !csum_not_calc) { skb->csum = htons(checksum); skb->ip_summed = CHECKSUM_COMPLETE; } @@ -2438,17 +2379,18 @@ static int __devinit enic_probe(struct pci_dev *pdev, dev_info(dev, "loopback tag=0x%04x\n", enic->loop_tag); } if (ENIC_SETTING(enic, TXCSUM)) - netdev->features |= NETIF_F_SG | NETIF_F_HW_CSUM; + netdev->hw_features |= NETIF_F_SG | NETIF_F_HW_CSUM; if (ENIC_SETTING(enic, TSO)) - netdev->features |= NETIF_F_TSO | + netdev->hw_features |= NETIF_F_TSO | NETIF_F_TSO6 | NETIF_F_TSO_ECN; - if (ENIC_SETTING(enic, LRO)) - netdev->features |= NETIF_F_GRO; + if (ENIC_SETTING(enic, RXCSUM)) + netdev->hw_features |= NETIF_F_RXCSUM; + + netdev->features |= netdev->hw_features; + if (using_dac) netdev->features |= NETIF_F_HIGHDMA; - enic->csum_rx_enabled = ENIC_SETTING(enic, RXCSUM); - err = register_netdev(netdev); if (err) { dev_err(dev, "Cannot register net device, aborting\n"); diff --git a/drivers/net/enic/enic_res.c b/drivers/net/enic/enic_res.c index f111a37..6e5c635 100644 --- a/drivers/net/enic/enic_res.c +++ b/drivers/net/enic/enic_res.c @@ -98,9 +98,9 @@ int enic_get_vnic_config(struct enic *enic) "vNIC MAC addr %pM wq/rq %d/%d mtu %d\n", enic->mac_addr, c->wq_desc_count, c->rq_desc_count, c->mtu); dev_info(enic_get_dev(enic), "vNIC csum tx/rx %d/%d " - "tso/lro %d/%d intr timer %d usec rss %d\n", + "tso %d intr timer %d usec rss %d\n", ENIC_SETTING(enic, TXCSUM), ENIC_SETTING(enic, RXCSUM), - ENIC_SETTING(enic, TSO), ENIC_SETTING(enic, LRO), + ENIC_SETTING(enic, TSO), c->intr_timer_usec, ENIC_SETTING(enic, RSS)); return 0; -- cgit v0.10.2 From dc668910f4eaa233c241d43d96ed6b0b9258cc43 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Miros=C5=82aw?= Date: Thu, 7 Apr 2011 03:35:07 +0000 Subject: net: tg3: convert to hw_features MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Cleanup hint: Some features are calculated in tg3_get_invariants() and the rest in its caller --- tg3_init_one(). This is not changed here. Signed-off-by: MichaÅ‚ MirosÅ‚aw Acked-by: Matt Carlson Signed-off-by: David S. Miller diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index d37ae87..38962af 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -4816,7 +4816,7 @@ static int tg3_rx(struct tg3_napi *tnapi, int budget) skb = copy_skb; } - if ((tp->tg3_flags & TG3_FLAG_RX_CHECKSUMS) && + if ((tp->dev->features & NETIF_F_RXCSUM) && (desc->type_flags & RXD_FLAG_TCPUDP_CSUM) && (((desc->ip_tcp_csum & RXD_TCPCSUM_MASK) >> RXD_TCPCSUM_SHIFT) == 0xffff)) @@ -6127,6 +6127,16 @@ dma_error: return NETDEV_TX_OK; } +static u32 tg3_fix_features(struct net_device *dev, u32 features) +{ + struct tg3 *tp = netdev_priv(dev); + + if (dev->mtu > ETH_DATA_LEN && (tp->tg3_flags2 & TG3_FLG2_5780_CLASS)) + features &= ~NETIF_F_ALL_TSO; + + return features; +} + static inline void tg3_set_mtu(struct net_device *dev, struct tg3 *tp, int new_mtu) { @@ -6134,14 +6144,16 @@ static inline void tg3_set_mtu(struct net_device *dev, struct tg3 *tp, if (new_mtu > ETH_DATA_LEN) { if (tp->tg3_flags2 & TG3_FLG2_5780_CLASS) { + netdev_update_features(dev); tp->tg3_flags2 &= ~TG3_FLG2_TSO_CAPABLE; - ethtool_op_set_tso(dev, 0); } else { tp->tg3_flags |= TG3_FLAG_JUMBO_RING_ENABLE; } } else { - if (tp->tg3_flags2 & TG3_FLG2_5780_CLASS) + if (tp->tg3_flags2 & TG3_FLG2_5780_CLASS) { tp->tg3_flags2 |= TG3_FLG2_TSO_CAPABLE; + netdev_update_features(dev); + } tp->tg3_flags &= ~TG3_FLAG_JUMBO_RING_ENABLE; } } @@ -10021,33 +10033,6 @@ static void tg3_set_msglevel(struct net_device *dev, u32 value) tp->msg_enable = value; } -static int tg3_set_tso(struct net_device *dev, u32 value) -{ - struct tg3 *tp = netdev_priv(dev); - - if (!(tp->tg3_flags2 & TG3_FLG2_TSO_CAPABLE)) { - if (value) - return -EINVAL; - return 0; - } - if ((dev->features & NETIF_F_IPV6_CSUM) && - ((tp->tg3_flags2 & TG3_FLG2_HW_TSO_2) || - (tp->tg3_flags2 & TG3_FLG2_HW_TSO_3))) { - if (value) { - dev->features |= NETIF_F_TSO6; - if ((tp->tg3_flags2 & TG3_FLG2_HW_TSO_3) || - GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761 || - (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784 && - GET_CHIP_REV(tp->pci_chip_rev_id) != CHIPREV_5784_AX) || - GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5785 || - GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57780) - dev->features |= NETIF_F_TSO_ECN; - } else - dev->features &= ~(NETIF_F_TSO6 | NETIF_F_TSO_ECN); - } - return ethtool_op_set_tso(dev, value); -} - static int tg3_nway_reset(struct net_device *dev) { struct tg3 *tp = netdev_priv(dev); @@ -10270,50 +10255,6 @@ static int tg3_set_pauseparam(struct net_device *dev, struct ethtool_pauseparam return err; } -static u32 tg3_get_rx_csum(struct net_device *dev) -{ - struct tg3 *tp = netdev_priv(dev); - return (tp->tg3_flags & TG3_FLAG_RX_CHECKSUMS) != 0; -} - -static int tg3_set_rx_csum(struct net_device *dev, u32 data) -{ - struct tg3 *tp = netdev_priv(dev); - - if (tp->tg3_flags & TG3_FLAG_BROKEN_CHECKSUMS) { - if (data != 0) - return -EINVAL; - return 0; - } - - spin_lock_bh(&tp->lock); - if (data) - tp->tg3_flags |= TG3_FLAG_RX_CHECKSUMS; - else - tp->tg3_flags &= ~TG3_FLAG_RX_CHECKSUMS; - spin_unlock_bh(&tp->lock); - - return 0; -} - -static int tg3_set_tx_csum(struct net_device *dev, u32 data) -{ - struct tg3 *tp = netdev_priv(dev); - - if (tp->tg3_flags & TG3_FLAG_BROKEN_CHECKSUMS) { - if (data != 0) - return -EINVAL; - return 0; - } - - if (tp->tg3_flags3 & TG3_FLG3_5755_PLUS) - ethtool_op_set_tx_ipv6_csum(dev, data); - else - ethtool_op_set_tx_csum(dev, data); - - return 0; -} - static int tg3_get_sset_count(struct net_device *dev, int sset) { switch (sset) { @@ -11390,11 +11331,6 @@ static const struct ethtool_ops tg3_ethtool_ops = { .set_ringparam = tg3_set_ringparam, .get_pauseparam = tg3_get_pauseparam, .set_pauseparam = tg3_set_pauseparam, - .get_rx_csum = tg3_get_rx_csum, - .set_rx_csum = tg3_set_rx_csum, - .set_tx_csum = tg3_set_tx_csum, - .set_sg = ethtool_op_set_sg, - .set_tso = tg3_set_tso, .self_test = tg3_self_test, .get_strings = tg3_get_strings, .set_phys_id = tg3_set_phys_id, @@ -13262,11 +13198,6 @@ done: static struct pci_dev * __devinit tg3_find_peer(struct tg3 *); -static inline void vlan_features_add(struct net_device *dev, unsigned long flags) -{ - dev->vlan_features |= flags; -} - static inline u32 tg3_rx_ret_ring_size(struct tg3 *tp) { if (tp->tg3_flags3 & TG3_FLG3_LRG_PROD_RING_CAP) @@ -13513,16 +13444,14 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) /* 5700 B0 chips do not support checksumming correctly due * to hardware bugs. */ - if (tp->pci_chip_rev_id == CHIPREV_ID_5700_B0) - tp->tg3_flags |= TG3_FLAG_BROKEN_CHECKSUMS; - else { - unsigned long features = NETIF_F_IP_CSUM | NETIF_F_SG | NETIF_F_GRO; + if (tp->pci_chip_rev_id != CHIPREV_ID_5700_B0) { + u32 features = NETIF_F_SG | NETIF_F_IP_CSUM | NETIF_F_RXCSUM; - tp->tg3_flags |= TG3_FLAG_RX_CHECKSUMS; if (tp->tg3_flags3 & TG3_FLG3_5755_PLUS) features |= NETIF_F_IPV6_CSUM; tp->dev->features |= features; - vlan_features_add(tp->dev, features); + tp->dev->hw_features |= features; + tp->dev->vlan_features |= features; } /* Determine TSO capabilities */ @@ -14794,6 +14723,7 @@ static const struct net_device_ops tg3_netdev_ops = { .ndo_do_ioctl = tg3_ioctl, .ndo_tx_timeout = tg3_tx_timeout, .ndo_change_mtu = tg3_change_mtu, + .ndo_fix_features = tg3_fix_features, #ifdef CONFIG_NET_POLL_CONTROLLER .ndo_poll_controller = tg3_poll_controller, #endif @@ -14824,6 +14754,7 @@ static int __devinit tg3_init_one(struct pci_dev *pdev, u32 sndmbx, rcvmbx, intmbx; char str[40]; u64 dma_mask, persist_dma_mask; + u32 hw_features = 0; printk_once(KERN_INFO "%s\n", version); @@ -14984,27 +14915,25 @@ static int __devinit tg3_init_one(struct pci_dev *pdev, * is off by default, but can be enabled using ethtool. */ if ((tp->tg3_flags2 & TG3_FLG2_HW_TSO) && - (dev->features & NETIF_F_IP_CSUM)) { - dev->features |= NETIF_F_TSO; - vlan_features_add(dev, NETIF_F_TSO); - } + (dev->features & NETIF_F_IP_CSUM)) + hw_features |= NETIF_F_TSO; if ((tp->tg3_flags2 & TG3_FLG2_HW_TSO_2) || (tp->tg3_flags2 & TG3_FLG2_HW_TSO_3)) { - if (dev->features & NETIF_F_IPV6_CSUM) { - dev->features |= NETIF_F_TSO6; - vlan_features_add(dev, NETIF_F_TSO6); - } + if (dev->features & NETIF_F_IPV6_CSUM) + hw_features |= NETIF_F_TSO6; if ((tp->tg3_flags2 & TG3_FLG2_HW_TSO_3) || GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761 || (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784 && GET_CHIP_REV(tp->pci_chip_rev_id) != CHIPREV_5784_AX) || GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5785 || - GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57780) { - dev->features |= NETIF_F_TSO_ECN; - vlan_features_add(dev, NETIF_F_TSO_ECN); - } + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57780) + hw_features |= NETIF_F_TSO_ECN; } + dev->hw_features |= hw_features; + dev->features |= hw_features; + dev->vlan_features |= hw_features; + if (tp->pci_chip_rev_id == CHIPREV_ID_5705_A1 && !(tp->tg3_flags2 & TG3_FLG2_TSO_CAPABLE) && !(tr32(TG3PCI_PCISTATE) & PCISTATE_BUS_SPEED_HIGH)) { @@ -15133,7 +15062,7 @@ static int __devinit tg3_init_one(struct pci_dev *pdev, } netdev_info(dev, "RXcsums[%d] LinkChgREG[%d] MIirq[%d] ASF[%d] TSOcap[%d]\n", - (tp->tg3_flags & TG3_FLAG_RX_CHECKSUMS) != 0, + (dev->features & NETIF_F_RXCSUM) != 0, (tp->tg3_flags & TG3_FLAG_USE_LINKCHG_REG) != 0, (tp->phy_flags & TG3_PHYFLG_USE_MI_INTERRUPT) != 0, (tp->tg3_flags & TG3_FLAG_ENABLE_ASF) != 0, diff --git a/drivers/net/tg3.h b/drivers/net/tg3.h index e7880d5..73dda27 100644 --- a/drivers/net/tg3.h +++ b/drivers/net/tg3.h @@ -2883,7 +2883,6 @@ struct tg3 { u32 tg3_flags; #define TG3_FLAG_TAGGED_STATUS 0x00000001 #define TG3_FLAG_TXD_MBOX_HWBUG 0x00000002 -#define TG3_FLAG_RX_CHECKSUMS 0x00000004 #define TG3_FLAG_USE_LINKCHG_REG 0x00000008 #define TG3_FLAG_ENABLE_ASF 0x00000020 #define TG3_FLAG_ASPM_WORKAROUND 0x00000040 @@ -2909,7 +2908,6 @@ struct tg3 { #define TG3_FLAG_PAUSE_AUTONEG 0x02000000 #define TG3_FLAG_CPMU_PRESENT 0x04000000 #define TG3_FLAG_40BIT_DMA_BUG 0x08000000 -#define TG3_FLAG_BROKEN_CHECKSUMS 0x10000000 #define TG3_FLAG_JUMBO_CAPABLE 0x20000000 #define TG3_FLAG_CHIP_RESETTING 0x40000000 #define TG3_FLAG_INIT_COMPLETE 0x80000000 -- cgit v0.10.2 From 782d640afd15af7a1faf01cfe566ca4ac511319d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Miros=C5=82aw?= Date: Thu, 7 Apr 2011 07:32:18 +0000 Subject: net: atl*: convert to hw_features MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Things left as they were: - atl1: is RX checksum really enabled? - atl2: copy-paste from atl1, with-errors-on-modify I presume - atl1c: there's a bug: MTU can't be changed if device is not up Signed-off-by: MichaÅ‚ MirosÅ‚aw Signed-off-by: David S. Miller diff --git a/drivers/net/atl1c/atl1c_ethtool.c b/drivers/net/atl1c/atl1c_ethtool.c index 7c52150..3af5a33 100644 --- a/drivers/net/atl1c/atl1c_ethtool.c +++ b/drivers/net/atl1c/atl1c_ethtool.c @@ -113,11 +113,6 @@ static int atl1c_set_settings(struct net_device *netdev, return 0; } -static u32 atl1c_get_tx_csum(struct net_device *netdev) -{ - return (netdev->features & NETIF_F_HW_CSUM) != 0; -} - static u32 atl1c_get_msglevel(struct net_device *netdev) { struct atl1c_adapter *adapter = netdev_priv(netdev); @@ -307,9 +302,6 @@ static const struct ethtool_ops atl1c_ethtool_ops = { .get_link = ethtool_op_get_link, .get_eeprom_len = atl1c_get_eeprom_len, .get_eeprom = atl1c_get_eeprom, - .get_tx_csum = atl1c_get_tx_csum, - .get_sg = ethtool_op_get_sg, - .set_sg = ethtool_op_set_sg, }; void atl1c_set_ethtool_ops(struct net_device *netdev) diff --git a/drivers/net/atl1c/atl1c_main.c b/drivers/net/atl1c/atl1c_main.c index 7d9d506..894d485 100644 --- a/drivers/net/atl1c/atl1c_main.c +++ b/drivers/net/atl1c/atl1c_main.c @@ -484,6 +484,15 @@ static void atl1c_set_rxbufsize(struct atl1c_adapter *adapter, adapter->rx_buffer_len = mtu > AT_RX_BUF_SIZE ? roundup(mtu + ETH_HLEN + ETH_FCS_LEN + VLAN_HLEN, 8) : AT_RX_BUF_SIZE; } + +static u32 atl1c_fix_features(struct net_device *netdev, u32 features) +{ + if (netdev->mtu > MAX_TSO_FRAME_SIZE) + features &= ~(NETIF_F_TSO | NETIF_F_TSO6); + + return features; +} + /* * atl1c_change_mtu - Change the Maximum Transfer Unit * @netdev: network interface device structure @@ -510,14 +519,8 @@ static int atl1c_change_mtu(struct net_device *netdev, int new_mtu) netdev->mtu = new_mtu; adapter->hw.max_frame_size = new_mtu; atl1c_set_rxbufsize(adapter, netdev); - if (new_mtu > MAX_TSO_FRAME_SIZE) { - adapter->netdev->features &= ~NETIF_F_TSO; - adapter->netdev->features &= ~NETIF_F_TSO6; - } else { - adapter->netdev->features |= NETIF_F_TSO; - adapter->netdev->features |= NETIF_F_TSO6; - } atl1c_down(adapter); + netdev_update_features(netdev); atl1c_up(adapter); clear_bit(__AT_RESETTING, &adapter->flags); if (adapter->hw.ctrl_flags & ATL1C_FPGA_VERSION) { @@ -2585,6 +2588,7 @@ static const struct net_device_ops atl1c_netdev_ops = { .ndo_set_mac_address = atl1c_set_mac_addr, .ndo_set_multicast_list = atl1c_set_multi, .ndo_change_mtu = atl1c_change_mtu, + .ndo_fix_features = atl1c_fix_features, .ndo_do_ioctl = atl1c_ioctl, .ndo_tx_timeout = atl1c_tx_timeout, .ndo_get_stats = atl1c_get_stats, @@ -2605,12 +2609,13 @@ static int atl1c_init_netdev(struct net_device *netdev, struct pci_dev *pdev) atl1c_set_ethtool_ops(netdev); /* TODO: add when ready */ - netdev->features = NETIF_F_SG | + netdev->hw_features = NETIF_F_SG | NETIF_F_HW_CSUM | NETIF_F_HW_VLAN_TX | - NETIF_F_HW_VLAN_RX | NETIF_F_TSO | NETIF_F_TSO6; + netdev->features = netdev->hw_features | + NETIF_F_HW_VLAN_RX; return 0; } diff --git a/drivers/net/atl1e/atl1e_ethtool.c b/drivers/net/atl1e/atl1e_ethtool.c index 1209297..4778374 100644 --- a/drivers/net/atl1e/atl1e_ethtool.c +++ b/drivers/net/atl1e/atl1e_ethtool.c @@ -382,9 +382,6 @@ static const struct ethtool_ops atl1e_ethtool_ops = { .get_eeprom_len = atl1e_get_eeprom_len, .get_eeprom = atl1e_get_eeprom, .set_eeprom = atl1e_set_eeprom, - .set_tx_csum = ethtool_op_set_tx_hw_csum, - .set_sg = ethtool_op_set_sg, - .set_tso = ethtool_op_set_tso, }; void atl1e_set_ethtool_ops(struct net_device *netdev) diff --git a/drivers/net/atl1e/atl1e_main.c b/drivers/net/atl1e/atl1e_main.c index 1ff001a..c05b2e7 100644 --- a/drivers/net/atl1e/atl1e_main.c +++ b/drivers/net/atl1e/atl1e_main.c @@ -1927,11 +1927,7 @@ void atl1e_down(struct atl1e_adapter *adapter) * reschedule our watchdog timer */ set_bit(__AT_DOWN, &adapter->flags); -#ifdef NETIF_F_LLTX netif_stop_queue(netdev); -#else - netif_tx_disable(netdev); -#endif /* reset MAC to disable all RX/TX */ atl1e_reset_hw(&adapter->hw); @@ -2223,10 +2219,10 @@ static int atl1e_init_netdev(struct net_device *netdev, struct pci_dev *pdev) netdev->watchdog_timeo = AT_TX_WATCHDOG; atl1e_set_ethtool_ops(netdev); - netdev->features = NETIF_F_SG | NETIF_F_HW_CSUM | - NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX; - netdev->features |= NETIF_F_LLTX; - netdev->features |= NETIF_F_TSO; + netdev->hw_features = NETIF_F_SG | NETIF_F_HW_CSUM | NETIF_F_TSO | + NETIF_F_HW_VLAN_TX; + netdev->features = netdev->hw_features | + NETIF_F_HW_VLAN_RX | NETIF_F_LLTX; return 0; } diff --git a/drivers/net/atlx/atl1.c b/drivers/net/atlx/atl1.c index e973d05..98334a1 100644 --- a/drivers/net/atlx/atl1.c +++ b/drivers/net/atlx/atl1.c @@ -2986,6 +2986,11 @@ static int __devinit atl1_probe(struct pci_dev *pdev, netdev->features |= NETIF_F_SG; netdev->features |= (NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX); + netdev->hw_features = NETIF_F_HW_CSUM | NETIF_F_SG | NETIF_F_TSO; + + /* is this valid? see atl1_setup_mac_ctrl() */ + netdev->features |= NETIF_F_RXCSUM; + /* * patch for some L1 of old version, * the final version of L1 may not need these @@ -3595,12 +3600,6 @@ static int atl1_set_pauseparam(struct net_device *netdev, return 0; } -/* FIXME: is this right? -- CHS */ -static u32 atl1_get_rx_csum(struct net_device *netdev) -{ - return 1; -} - static void atl1_get_strings(struct net_device *netdev, u32 stringset, u8 *data) { @@ -3668,13 +3667,9 @@ static const struct ethtool_ops atl1_ethtool_ops = { .set_ringparam = atl1_set_ringparam, .get_pauseparam = atl1_get_pauseparam, .set_pauseparam = atl1_set_pauseparam, - .get_rx_csum = atl1_get_rx_csum, - .set_tx_csum = ethtool_op_set_tx_hw_csum, .get_link = ethtool_op_get_link, - .set_sg = ethtool_op_set_sg, .get_strings = atl1_get_strings, .nway_reset = atl1_nway_reset, .get_ethtool_stats = atl1_get_ethtool_stats, .get_sset_count = atl1_get_sset_count, - .set_tso = ethtool_op_set_tso, }; diff --git a/drivers/net/atlx/atl2.c b/drivers/net/atlx/atl2.c index 937ef1a..02761dd 100644 --- a/drivers/net/atlx/atl2.c +++ b/drivers/net/atlx/atl2.c @@ -1411,9 +1411,8 @@ static int __devinit atl2_probe(struct pci_dev *pdev, err = -EIO; -#ifdef NETIF_F_HW_VLAN_TX + netdev->hw_features = NETIF_F_SG; netdev->features |= (NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX); -#endif /* Init PHY as early as possible due to power saving issue */ atl2_phy_init(&adapter->hw); @@ -1840,11 +1839,6 @@ static int atl2_set_settings(struct net_device *netdev, return 0; } -static u32 atl2_get_tx_csum(struct net_device *netdev) -{ - return (netdev->features & NETIF_F_HW_CSUM) != 0; -} - static u32 atl2_get_msglevel(struct net_device *netdev) { return 0; @@ -2112,12 +2106,6 @@ static const struct ethtool_ops atl2_ethtool_ops = { .get_eeprom_len = atl2_get_eeprom_len, .get_eeprom = atl2_get_eeprom, .set_eeprom = atl2_set_eeprom, - .get_tx_csum = atl2_get_tx_csum, - .get_sg = ethtool_op_get_sg, - .set_sg = ethtool_op_set_sg, -#ifdef NETIF_F_TSO - .get_tso = ethtool_op_get_tso, -#endif }; static void atl2_set_ethtool_ops(struct net_device *netdev) -- cgit v0.10.2 From b3b7f0550f84e06ae60df0a13c2992792fbd1af9 Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Fri, 8 Apr 2011 20:39:23 +0800 Subject: crypto: caam - introduce missing kfree Error handling code following a kmalloc should free the allocated data. The semantic match that finds the problem is as follows: (http://www.emn.fr/x-info/coccinelle/) // @r exists@ local idexpression x; statement S; expression E; identifier f,f1,l; position p1,p2; expression *ptr != NULL; @@ x@p1 = \(kmalloc\|kzalloc\|kcalloc\)(...); ... if (x == NULL) S <... when != x when != if (...) { <+...x...+> } ( x->f1 = E | (x->f1 == NULL || ...) | f(...,x->f1,...) ) ...> ( return \(0\|<+...x...+>\|ptr\); | return@p2 ...; ) @script:python@ p1 << r.p1; p2 << r.p2; @@ print "* file: %s kmalloc %s return %s" % (p1[0].file,p1[0].line,p2[0].line) // Signed-off-by: Julia Lawall Acked-by: Kim Phillips Signed-off-by: Herbert Xu diff --git a/drivers/crypto/caam/caamalg.c b/drivers/crypto/caam/caamalg.c index dce44b2..20e1215 100644 --- a/drivers/crypto/caam/caamalg.c +++ b/drivers/crypto/caam/caamalg.c @@ -1120,6 +1120,7 @@ static int __init caam_algapi_init(void) if (err < 0 && i == 0) { dev_err(ctrldev, "algapi error in job ring registration: %d\n", err); + kfree(jrdev); return err; } -- cgit v0.10.2 From a49e490c7a8a5c6c9474b1936ad8048f3e4440fc Mon Sep 17 00:00:00 2001 From: Vladimir Zapolskiy Date: Fri, 8 Apr 2011 20:40:51 +0800 Subject: crypto: s5p-sss - add S5PV210 advanced crypto engine support This change adds support for AES encrypting and decrypting using advanced crypto engine found on Samsung S5PV210 and S5PC110 SoCs. Signed-off-by: Vladimir Zapolskiy Signed-off-by: Herbert Xu diff --git a/drivers/crypto/Kconfig b/drivers/crypto/Kconfig index a27224a..7957acb 100644 --- a/drivers/crypto/Kconfig +++ b/drivers/crypto/Kconfig @@ -271,4 +271,15 @@ config CRYPTO_DEV_PICOXCELL Saying m here will build a module named pipcoxcell_crypto. +config CRYPTO_DEV_S5P + tristate "Support for Samsung S5PV210 crypto accelerator" + depends on ARCH_S5PV210 + select CRYPTO_AES + select CRYPTO_ALGAPI + select CRYPTO_BLKCIPHER + help + This option allows you to have support for S5P crypto acceleration. + Select this to offload Samsung S5PV210 or S5PC110 from AES + algorithms execution. + endif # CRYPTO_HW diff --git a/drivers/crypto/Makefile b/drivers/crypto/Makefile index 663c5ef..53ea501 100644 --- a/drivers/crypto/Makefile +++ b/drivers/crypto/Makefile @@ -12,3 +12,4 @@ obj-$(CONFIG_CRYPTO_DEV_PPC4XX) += amcc/ obj-$(CONFIG_CRYPTO_DEV_OMAP_SHAM) += omap-sham.o obj-$(CONFIG_CRYPTO_DEV_OMAP_AES) += omap-aes.o obj-$(CONFIG_CRYPTO_DEV_PICOXCELL) += picoxcell_crypto.o +obj-$(CONFIG_CRYPTO_DEV_S5P) += s5p-sss.o diff --git a/drivers/crypto/s5p-sss.c b/drivers/crypto/s5p-sss.c new file mode 100644 index 0000000..8115417 --- /dev/null +++ b/drivers/crypto/s5p-sss.c @@ -0,0 +1,701 @@ +/* + * Cryptographic API. + * + * Support for Samsung S5PV210 HW acceleration. + * + * Copyright (C) 2011 NetUP Inc. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as published + * by the Free Software Foundation. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + +#define _SBF(s, v) ((v) << (s)) +#define _BIT(b) _SBF(b, 1) + +/* Feed control registers */ +#define SSS_REG_FCINTSTAT 0x0000 +#define SSS_FCINTSTAT_BRDMAINT _BIT(3) +#define SSS_FCINTSTAT_BTDMAINT _BIT(2) +#define SSS_FCINTSTAT_HRDMAINT _BIT(1) +#define SSS_FCINTSTAT_PKDMAINT _BIT(0) + +#define SSS_REG_FCINTENSET 0x0004 +#define SSS_FCINTENSET_BRDMAINTENSET _BIT(3) +#define SSS_FCINTENSET_BTDMAINTENSET _BIT(2) +#define SSS_FCINTENSET_HRDMAINTENSET _BIT(1) +#define SSS_FCINTENSET_PKDMAINTENSET _BIT(0) + +#define SSS_REG_FCINTENCLR 0x0008 +#define SSS_FCINTENCLR_BRDMAINTENCLR _BIT(3) +#define SSS_FCINTENCLR_BTDMAINTENCLR _BIT(2) +#define SSS_FCINTENCLR_HRDMAINTENCLR _BIT(1) +#define SSS_FCINTENCLR_PKDMAINTENCLR _BIT(0) + +#define SSS_REG_FCINTPEND 0x000C +#define SSS_FCINTPEND_BRDMAINTP _BIT(3) +#define SSS_FCINTPEND_BTDMAINTP _BIT(2) +#define SSS_FCINTPEND_HRDMAINTP _BIT(1) +#define SSS_FCINTPEND_PKDMAINTP _BIT(0) + +#define SSS_REG_FCFIFOSTAT 0x0010 +#define SSS_FCFIFOSTAT_BRFIFOFUL _BIT(7) +#define SSS_FCFIFOSTAT_BRFIFOEMP _BIT(6) +#define SSS_FCFIFOSTAT_BTFIFOFUL _BIT(5) +#define SSS_FCFIFOSTAT_BTFIFOEMP _BIT(4) +#define SSS_FCFIFOSTAT_HRFIFOFUL _BIT(3) +#define SSS_FCFIFOSTAT_HRFIFOEMP _BIT(2) +#define SSS_FCFIFOSTAT_PKFIFOFUL _BIT(1) +#define SSS_FCFIFOSTAT_PKFIFOEMP _BIT(0) + +#define SSS_REG_FCFIFOCTRL 0x0014 +#define SSS_FCFIFOCTRL_DESSEL _BIT(2) +#define SSS_HASHIN_INDEPENDENT _SBF(0, 0x00) +#define SSS_HASHIN_CIPHER_INPUT _SBF(0, 0x01) +#define SSS_HASHIN_CIPHER_OUTPUT _SBF(0, 0x02) + +#define SSS_REG_FCBRDMAS 0x0020 +#define SSS_REG_FCBRDMAL 0x0024 +#define SSS_REG_FCBRDMAC 0x0028 +#define SSS_FCBRDMAC_BYTESWAP _BIT(1) +#define SSS_FCBRDMAC_FLUSH _BIT(0) + +#define SSS_REG_FCBTDMAS 0x0030 +#define SSS_REG_FCBTDMAL 0x0034 +#define SSS_REG_FCBTDMAC 0x0038 +#define SSS_FCBTDMAC_BYTESWAP _BIT(1) +#define SSS_FCBTDMAC_FLUSH _BIT(0) + +#define SSS_REG_FCHRDMAS 0x0040 +#define SSS_REG_FCHRDMAL 0x0044 +#define SSS_REG_FCHRDMAC 0x0048 +#define SSS_FCHRDMAC_BYTESWAP _BIT(1) +#define SSS_FCHRDMAC_FLUSH _BIT(0) + +#define SSS_REG_FCPKDMAS 0x0050 +#define SSS_REG_FCPKDMAL 0x0054 +#define SSS_REG_FCPKDMAC 0x0058 +#define SSS_FCPKDMAC_BYTESWAP _BIT(3) +#define SSS_FCPKDMAC_DESCEND _BIT(2) +#define SSS_FCPKDMAC_TRANSMIT _BIT(1) +#define SSS_FCPKDMAC_FLUSH _BIT(0) + +#define SSS_REG_FCPKDMAO 0x005C + +/* AES registers */ +#define SSS_REG_AES_CONTROL 0x4000 +#define SSS_AES_BYTESWAP_DI _BIT(11) +#define SSS_AES_BYTESWAP_DO _BIT(10) +#define SSS_AES_BYTESWAP_IV _BIT(9) +#define SSS_AES_BYTESWAP_CNT _BIT(8) +#define SSS_AES_BYTESWAP_KEY _BIT(7) +#define SSS_AES_KEY_CHANGE_MODE _BIT(6) +#define SSS_AES_KEY_SIZE_128 _SBF(4, 0x00) +#define SSS_AES_KEY_SIZE_192 _SBF(4, 0x01) +#define SSS_AES_KEY_SIZE_256 _SBF(4, 0x02) +#define SSS_AES_FIFO_MODE _BIT(3) +#define SSS_AES_CHAIN_MODE_ECB _SBF(1, 0x00) +#define SSS_AES_CHAIN_MODE_CBC _SBF(1, 0x01) +#define SSS_AES_CHAIN_MODE_CTR _SBF(1, 0x02) +#define SSS_AES_MODE_DECRYPT _BIT(0) + +#define SSS_REG_AES_STATUS 0x4004 +#define SSS_AES_BUSY _BIT(2) +#define SSS_AES_INPUT_READY _BIT(1) +#define SSS_AES_OUTPUT_READY _BIT(0) + +#define SSS_REG_AES_IN_DATA(s) (0x4010 + (s << 2)) +#define SSS_REG_AES_OUT_DATA(s) (0x4020 + (s << 2)) +#define SSS_REG_AES_IV_DATA(s) (0x4030 + (s << 2)) +#define SSS_REG_AES_CNT_DATA(s) (0x4040 + (s << 2)) +#define SSS_REG_AES_KEY_DATA(s) (0x4080 + (s << 2)) + +#define SSS_REG(dev, reg) ((dev)->ioaddr + (SSS_REG_##reg)) +#define SSS_READ(dev, reg) __raw_readl(SSS_REG(dev, reg)) +#define SSS_WRITE(dev, reg, val) __raw_writel((val), SSS_REG(dev, reg)) + +/* HW engine modes */ +#define FLAGS_AES_DECRYPT _BIT(0) +#define FLAGS_AES_MODE_MASK _SBF(1, 0x03) +#define FLAGS_AES_CBC _SBF(1, 0x01) +#define FLAGS_AES_CTR _SBF(1, 0x02) + +#define AES_KEY_LEN 16 +#define CRYPTO_QUEUE_LEN 1 + +struct s5p_aes_reqctx { + unsigned long mode; +}; + +struct s5p_aes_ctx { + struct s5p_aes_dev *dev; + + uint8_t aes_key[AES_MAX_KEY_SIZE]; + uint8_t nonce[CTR_RFC3686_NONCE_SIZE]; + int keylen; +}; + +struct s5p_aes_dev { + struct device *dev; + struct clk *clk; + void __iomem *ioaddr; + int irq_hash; + int irq_fc; + + struct ablkcipher_request *req; + struct s5p_aes_ctx *ctx; + struct scatterlist *sg_src; + struct scatterlist *sg_dst; + + struct tasklet_struct tasklet; + struct crypto_queue queue; + bool busy; + spinlock_t lock; +}; + +static struct s5p_aes_dev *s5p_dev; + +static void s5p_set_dma_indata(struct s5p_aes_dev *dev, struct scatterlist *sg) +{ + SSS_WRITE(dev, FCBRDMAS, sg_dma_address(sg)); + SSS_WRITE(dev, FCBRDMAL, sg_dma_len(sg)); +} + +static void s5p_set_dma_outdata(struct s5p_aes_dev *dev, struct scatterlist *sg) +{ + SSS_WRITE(dev, FCBTDMAS, sg_dma_address(sg)); + SSS_WRITE(dev, FCBTDMAL, sg_dma_len(sg)); +} + +static void s5p_aes_complete(struct s5p_aes_dev *dev, int err) +{ + /* holding a lock outside */ + dev->req->base.complete(&dev->req->base, err); + dev->busy = false; +} + +static void s5p_unset_outdata(struct s5p_aes_dev *dev) +{ + dma_unmap_sg(dev->dev, dev->sg_dst, 1, DMA_FROM_DEVICE); +} + +static void s5p_unset_indata(struct s5p_aes_dev *dev) +{ + dma_unmap_sg(dev->dev, dev->sg_src, 1, DMA_TO_DEVICE); +} + +static int s5p_set_outdata(struct s5p_aes_dev *dev, struct scatterlist *sg) +{ + int err; + + if (!IS_ALIGNED(sg_dma_len(sg), AES_BLOCK_SIZE)) { + err = -EINVAL; + goto exit; + } + if (!sg_dma_len(sg)) { + err = -EINVAL; + goto exit; + } + + err = dma_map_sg(dev->dev, sg, 1, DMA_FROM_DEVICE); + if (!err) { + err = -ENOMEM; + goto exit; + } + + dev->sg_dst = sg; + err = 0; + + exit: + return err; +} + +static int s5p_set_indata(struct s5p_aes_dev *dev, struct scatterlist *sg) +{ + int err; + + if (!IS_ALIGNED(sg_dma_len(sg), AES_BLOCK_SIZE)) { + err = -EINVAL; + goto exit; + } + if (!sg_dma_len(sg)) { + err = -EINVAL; + goto exit; + } + + err = dma_map_sg(dev->dev, sg, 1, DMA_TO_DEVICE); + if (!err) { + err = -ENOMEM; + goto exit; + } + + dev->sg_src = sg; + err = 0; + + exit: + return err; +} + +static void s5p_aes_tx(struct s5p_aes_dev *dev) +{ + int err = 0; + + s5p_unset_outdata(dev); + + if (!sg_is_last(dev->sg_dst)) { + err = s5p_set_outdata(dev, sg_next(dev->sg_dst)); + if (err) { + s5p_aes_complete(dev, err); + return; + } + + s5p_set_dma_outdata(dev, dev->sg_dst); + } else + s5p_aes_complete(dev, err); +} + +static void s5p_aes_rx(struct s5p_aes_dev *dev) +{ + int err; + + s5p_unset_indata(dev); + + if (!sg_is_last(dev->sg_src)) { + err = s5p_set_indata(dev, sg_next(dev->sg_src)); + if (err) { + s5p_aes_complete(dev, err); + return; + } + + s5p_set_dma_indata(dev, dev->sg_src); + } +} + +static irqreturn_t s5p_aes_interrupt(int irq, void *dev_id) +{ + struct platform_device *pdev = dev_id; + struct s5p_aes_dev *dev = platform_get_drvdata(pdev); + uint32_t status; + unsigned long flags; + + spin_lock_irqsave(&dev->lock, flags); + + if (irq == dev->irq_fc) { + status = SSS_READ(dev, FCINTSTAT); + if (status & SSS_FCINTSTAT_BRDMAINT) + s5p_aes_rx(dev); + if (status & SSS_FCINTSTAT_BTDMAINT) + s5p_aes_tx(dev); + + SSS_WRITE(dev, FCINTPEND, status); + } + + spin_unlock_irqrestore(&dev->lock, flags); + + return IRQ_HANDLED; +} + +static void s5p_set_aes(struct s5p_aes_dev *dev, + uint8_t *key, uint8_t *iv, unsigned int keylen) +{ + void __iomem *keystart; + + memcpy(dev->ioaddr + SSS_REG_AES_IV_DATA(0), iv, 0x10); + + if (keylen == AES_KEYSIZE_256) + keystart = dev->ioaddr + SSS_REG_AES_KEY_DATA(0); + else if (keylen == AES_KEYSIZE_192) + keystart = dev->ioaddr + SSS_REG_AES_KEY_DATA(2); + else + keystart = dev->ioaddr + SSS_REG_AES_KEY_DATA(4); + + memcpy(keystart, key, keylen); +} + +static void s5p_aes_crypt_start(struct s5p_aes_dev *dev, unsigned long mode) +{ + struct ablkcipher_request *req = dev->req; + + uint32_t aes_control; + int err; + unsigned long flags; + + aes_control = SSS_AES_KEY_CHANGE_MODE; + if (mode & FLAGS_AES_DECRYPT) + aes_control |= SSS_AES_MODE_DECRYPT; + + if ((mode & FLAGS_AES_MODE_MASK) == FLAGS_AES_CBC) + aes_control |= SSS_AES_CHAIN_MODE_CBC; + else if ((mode & FLAGS_AES_MODE_MASK) == FLAGS_AES_CTR) + aes_control |= SSS_AES_CHAIN_MODE_CTR; + + if (dev->ctx->keylen == AES_KEYSIZE_192) + aes_control |= SSS_AES_KEY_SIZE_192; + else if (dev->ctx->keylen == AES_KEYSIZE_256) + aes_control |= SSS_AES_KEY_SIZE_256; + + aes_control |= SSS_AES_FIFO_MODE; + + /* as a variant it is possible to use byte swapping on DMA side */ + aes_control |= SSS_AES_BYTESWAP_DI + | SSS_AES_BYTESWAP_DO + | SSS_AES_BYTESWAP_IV + | SSS_AES_BYTESWAP_KEY + | SSS_AES_BYTESWAP_CNT; + + spin_lock_irqsave(&dev->lock, flags); + + SSS_WRITE(dev, FCINTENCLR, + SSS_FCINTENCLR_BTDMAINTENCLR | SSS_FCINTENCLR_BRDMAINTENCLR); + SSS_WRITE(dev, FCFIFOCTRL, 0x00); + + err = s5p_set_indata(dev, req->src); + if (err) + goto indata_error; + + err = s5p_set_outdata(dev, req->dst); + if (err) + goto outdata_error; + + SSS_WRITE(dev, AES_CONTROL, aes_control); + s5p_set_aes(dev, dev->ctx->aes_key, req->info, dev->ctx->keylen); + + s5p_set_dma_indata(dev, req->src); + s5p_set_dma_outdata(dev, req->dst); + + SSS_WRITE(dev, FCINTENSET, + SSS_FCINTENSET_BTDMAINTENSET | SSS_FCINTENSET_BRDMAINTENSET); + + spin_unlock_irqrestore(&dev->lock, flags); + + return; + + outdata_error: + s5p_unset_indata(dev); + + indata_error: + s5p_aes_complete(dev, err); + spin_unlock_irqrestore(&dev->lock, flags); +} + +static void s5p_tasklet_cb(unsigned long data) +{ + struct s5p_aes_dev *dev = (struct s5p_aes_dev *)data; + struct crypto_async_request *async_req, *backlog; + struct s5p_aes_reqctx *reqctx; + unsigned long flags; + + spin_lock_irqsave(&dev->lock, flags); + backlog = crypto_get_backlog(&dev->queue); + async_req = crypto_dequeue_request(&dev->queue); + spin_unlock_irqrestore(&dev->lock, flags); + + if (!async_req) + return; + + if (backlog) + backlog->complete(backlog, -EINPROGRESS); + + dev->req = ablkcipher_request_cast(async_req); + dev->ctx = crypto_tfm_ctx(dev->req->base.tfm); + reqctx = ablkcipher_request_ctx(dev->req); + + s5p_aes_crypt_start(dev, reqctx->mode); +} + +static int s5p_aes_handle_req(struct s5p_aes_dev *dev, + struct ablkcipher_request *req) +{ + unsigned long flags; + int err; + + spin_lock_irqsave(&dev->lock, flags); + if (dev->busy) { + err = -EAGAIN; + spin_unlock_irqrestore(&dev->lock, flags); + goto exit; + } + dev->busy = true; + + err = ablkcipher_enqueue_request(&dev->queue, req); + spin_unlock_irqrestore(&dev->lock, flags); + + tasklet_schedule(&dev->tasklet); + + exit: + return err; +} + +static int s5p_aes_crypt(struct ablkcipher_request *req, unsigned long mode) +{ + struct crypto_ablkcipher *tfm = crypto_ablkcipher_reqtfm(req); + struct s5p_aes_ctx *ctx = crypto_ablkcipher_ctx(tfm); + struct s5p_aes_reqctx *reqctx = ablkcipher_request_ctx(req); + struct s5p_aes_dev *dev = ctx->dev; + + if (!IS_ALIGNED(req->nbytes, AES_BLOCK_SIZE)) { + pr_err("request size is not exact amount of AES blocks\n"); + return -EINVAL; + } + + reqctx->mode = mode; + + return s5p_aes_handle_req(dev, req); +} + +static int s5p_aes_setkey(struct crypto_ablkcipher *cipher, + const uint8_t *key, unsigned int keylen) +{ + struct crypto_tfm *tfm = crypto_ablkcipher_tfm(cipher); + struct s5p_aes_ctx *ctx = crypto_tfm_ctx(tfm); + + if (keylen != AES_KEYSIZE_128 && + keylen != AES_KEYSIZE_192 && + keylen != AES_KEYSIZE_256) + return -EINVAL; + + memcpy(ctx->aes_key, key, keylen); + ctx->keylen = keylen; + + return 0; +} + +static int s5p_aes_ecb_encrypt(struct ablkcipher_request *req) +{ + return s5p_aes_crypt(req, 0); +} + +static int s5p_aes_ecb_decrypt(struct ablkcipher_request *req) +{ + return s5p_aes_crypt(req, FLAGS_AES_DECRYPT); +} + +static int s5p_aes_cbc_encrypt(struct ablkcipher_request *req) +{ + return s5p_aes_crypt(req, FLAGS_AES_CBC); +} + +static int s5p_aes_cbc_decrypt(struct ablkcipher_request *req) +{ + return s5p_aes_crypt(req, FLAGS_AES_DECRYPT | FLAGS_AES_CBC); +} + +static int s5p_aes_cra_init(struct crypto_tfm *tfm) +{ + struct s5p_aes_ctx *ctx = crypto_tfm_ctx(tfm); + + ctx->dev = s5p_dev; + tfm->crt_ablkcipher.reqsize = sizeof(struct s5p_aes_reqctx); + + return 0; +} + +static struct crypto_alg algs[] = { + { + .cra_name = "ecb(aes)", + .cra_driver_name = "ecb-aes-s5p", + .cra_priority = 100, + .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | + CRYPTO_ALG_ASYNC, + .cra_blocksize = AES_BLOCK_SIZE, + .cra_ctxsize = sizeof(struct s5p_aes_ctx), + .cra_alignmask = 0x0f, + .cra_type = &crypto_ablkcipher_type, + .cra_module = THIS_MODULE, + .cra_init = s5p_aes_cra_init, + .cra_u.ablkcipher = { + .min_keysize = AES_MIN_KEY_SIZE, + .max_keysize = AES_MAX_KEY_SIZE, + .setkey = s5p_aes_setkey, + .encrypt = s5p_aes_ecb_encrypt, + .decrypt = s5p_aes_ecb_decrypt, + } + }, + { + .cra_name = "cbc(aes)", + .cra_driver_name = "cbc-aes-s5p", + .cra_priority = 100, + .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | + CRYPTO_ALG_ASYNC, + .cra_blocksize = AES_BLOCK_SIZE, + .cra_ctxsize = sizeof(struct s5p_aes_ctx), + .cra_alignmask = 0x0f, + .cra_type = &crypto_ablkcipher_type, + .cra_module = THIS_MODULE, + .cra_init = s5p_aes_cra_init, + .cra_u.ablkcipher = { + .min_keysize = AES_MIN_KEY_SIZE, + .max_keysize = AES_MAX_KEY_SIZE, + .ivsize = AES_BLOCK_SIZE, + .setkey = s5p_aes_setkey, + .encrypt = s5p_aes_cbc_encrypt, + .decrypt = s5p_aes_cbc_decrypt, + } + }, +}; + +static int s5p_aes_probe(struct platform_device *pdev) +{ + int i, j, err = -ENODEV; + struct s5p_aes_dev *pdata; + struct device *dev = &pdev->dev; + struct resource *res; + + if (s5p_dev) + return -EEXIST; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) + return -ENODEV; + + pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL); + if (!pdata) + return -ENOMEM; + + if (!devm_request_mem_region(dev, res->start, + resource_size(res), pdev->name)) + return -EBUSY; + + pdata->clk = clk_get(dev, "secss"); + if (IS_ERR(pdata->clk)) { + dev_err(dev, "failed to find secss clock source\n"); + return -ENOENT; + } + + clk_enable(pdata->clk); + + spin_lock_init(&pdata->lock); + pdata->ioaddr = devm_ioremap(dev, res->start, + resource_size(res)); + + pdata->irq_hash = platform_get_irq_byname(pdev, "hash"); + if (pdata->irq_hash < 0) { + err = pdata->irq_hash; + dev_warn(dev, "hash interrupt is not available.\n"); + goto err_irq; + } + err = devm_request_irq(dev, pdata->irq_hash, s5p_aes_interrupt, + IRQF_SHARED, pdev->name, pdev); + if (err < 0) { + dev_warn(dev, "hash interrupt is not available.\n"); + goto err_irq; + } + + pdata->irq_fc = platform_get_irq_byname(pdev, "feed control"); + if (pdata->irq_fc < 0) { + err = pdata->irq_fc; + dev_warn(dev, "feed control interrupt is not available.\n"); + goto err_irq; + } + err = devm_request_irq(dev, pdata->irq_fc, s5p_aes_interrupt, + IRQF_SHARED, pdev->name, pdev); + if (err < 0) { + dev_warn(dev, "feed control interrupt is not available.\n"); + goto err_irq; + } + + pdata->dev = dev; + platform_set_drvdata(pdev, pdata); + s5p_dev = pdata; + + tasklet_init(&pdata->tasklet, s5p_tasklet_cb, (unsigned long)pdata); + crypto_init_queue(&pdata->queue, CRYPTO_QUEUE_LEN); + + for (i = 0; i < ARRAY_SIZE(algs); i++) { + INIT_LIST_HEAD(&algs[i].cra_list); + err = crypto_register_alg(&algs[i]); + if (err) + goto err_algs; + } + + pr_info("s5p-sss driver registered\n"); + + return 0; + + err_algs: + dev_err(dev, "can't register '%s': %d\n", algs[i].cra_name, err); + + for (j = 0; j < i; j++) + crypto_unregister_alg(&algs[j]); + + tasklet_kill(&pdata->tasklet); + + err_irq: + clk_disable(pdata->clk); + clk_put(pdata->clk); + + s5p_dev = NULL; + platform_set_drvdata(pdev, NULL); + + return err; +} + +static int s5p_aes_remove(struct platform_device *pdev) +{ + struct s5p_aes_dev *pdata = platform_get_drvdata(pdev); + int i; + + if (!pdata) + return -ENODEV; + + for (i = 0; i < ARRAY_SIZE(algs); i++) + crypto_unregister_alg(&algs[i]); + + tasklet_kill(&pdata->tasklet); + + clk_disable(pdata->clk); + clk_put(pdata->clk); + + s5p_dev = NULL; + platform_set_drvdata(pdev, NULL); + + return 0; +} + +static struct platform_driver s5p_aes_crypto = { + .probe = s5p_aes_probe, + .remove = s5p_aes_remove, + .driver = { + .owner = THIS_MODULE, + .name = "s5p-secss", + }, +}; + +static int __init s5p_aes_mod_init(void) +{ + return platform_driver_register(&s5p_aes_crypto); +} + +static void __exit s5p_aes_mod_exit(void) +{ + platform_driver_unregister(&s5p_aes_crypto); +} + +module_init(s5p_aes_mod_init); +module_exit(s5p_aes_mod_exit); + +MODULE_DESCRIPTION("S5PV210 AES hw acceleration support."); +MODULE_LICENSE("GPL v2"); +MODULE_AUTHOR("Vladimir Zapolskiy "); -- cgit v0.10.2 From 1d5cc5559aaf5273cc1f9aac9b428e3a99d41de6 Mon Sep 17 00:00:00 2001 From: root Date: Mon, 28 Mar 2011 16:12:43 -0700 Subject: iwlwifi: remove extranious macro from firmware define define of firmware filenames use extra macro to build the files name. Signed-off-by: Jay Sternberg Signed-off-by: Wey-Yi Guy diff --git a/drivers/net/wireless/iwlwifi/iwl-1000.c b/drivers/net/wireless/iwlwifi/iwl-1000.c index 1b27992..4323d27 100644 --- a/drivers/net/wireless/iwlwifi/iwl-1000.c +++ b/drivers/net/wireless/iwlwifi/iwl-1000.c @@ -57,12 +57,10 @@ #define IWL100_UCODE_API_MIN 5 #define IWL1000_FW_PRE "iwlwifi-1000-" -#define _IWL1000_MODULE_FIRMWARE(api) IWL1000_FW_PRE #api ".ucode" -#define IWL1000_MODULE_FIRMWARE(api) _IWL1000_MODULE_FIRMWARE(api) +#define IWL1000_MODULE_FIRMWARE(api) IWL1000_FW_PRE #api ".ucode" #define IWL100_FW_PRE "iwlwifi-100-" -#define _IWL100_MODULE_FIRMWARE(api) IWL100_FW_PRE #api ".ucode" -#define IWL100_MODULE_FIRMWARE(api) _IWL100_MODULE_FIRMWARE(api) +#define IWL100_MODULE_FIRMWARE(api) IWL100_FW_PRE #api ".ucode" /* diff --git a/drivers/net/wireless/iwlwifi/iwl-2000.c b/drivers/net/wireless/iwlwifi/iwl-2000.c index f602af4..564477d 100644 --- a/drivers/net/wireless/iwlwifi/iwl-2000.c +++ b/drivers/net/wireless/iwlwifi/iwl-2000.c @@ -60,16 +60,13 @@ #define IWL200_UCODE_API_MIN 5 #define IWL2030_FW_PRE "iwlwifi-2030-" -#define _IWL2030_MODULE_FIRMWARE(api) IWL2030_FW_PRE #api ".ucode" -#define IWL2030_MODULE_FIRMWARE(api) _IWL2030_MODULE_FIRMWARE(api) +#define IWL2030_MODULE_FIRMWARE(api) IWL2030_FW_PRE #api ".ucode" #define IWL2000_FW_PRE "iwlwifi-2000-" -#define _IWL2000_MODULE_FIRMWARE(api) IWL2000_FW_PRE #api ".ucode" -#define IWL2000_MODULE_FIRMWARE(api) _IWL2000_MODULE_FIRMWARE(api) +#define IWL2000_MODULE_FIRMWARE(api) IWL2000_FW_PRE #api ".ucode" #define IWL200_FW_PRE "iwlwifi-200-" -#define _IWL200_MODULE_FIRMWARE(api) IWL200_FW_PRE #api ".ucode" -#define IWL200_MODULE_FIRMWARE(api) _IWL200_MODULE_FIRMWARE(api) +#define IWL200_MODULE_FIRMWARE(api) IWL200_FW_PRE #api ".ucode" static void iwl2000_set_ct_threshold(struct iwl_priv *priv) { diff --git a/drivers/net/wireless/iwlwifi/iwl-5000.c b/drivers/net/wireless/iwlwifi/iwl-5000.c index 66f5fe8..4dafc58 100644 --- a/drivers/net/wireless/iwlwifi/iwl-5000.c +++ b/drivers/net/wireless/iwlwifi/iwl-5000.c @@ -59,12 +59,10 @@ #define IWL5150_UCODE_API_MIN 1 #define IWL5000_FW_PRE "iwlwifi-5000-" -#define _IWL5000_MODULE_FIRMWARE(api) IWL5000_FW_PRE #api ".ucode" -#define IWL5000_MODULE_FIRMWARE(api) _IWL5000_MODULE_FIRMWARE(api) +#define IWL5000_MODULE_FIRMWARE(api) IWL5000_FW_PRE #api ".ucode" #define IWL5150_FW_PRE "iwlwifi-5150-" -#define _IWL5150_MODULE_FIRMWARE(api) IWL5150_FW_PRE #api ".ucode" -#define IWL5150_MODULE_FIRMWARE(api) _IWL5150_MODULE_FIRMWARE(api) +#define IWL5150_MODULE_FIRMWARE(api) IWL5150_FW_PRE #api ".ucode" /* NIC configuration for 5000 series */ static void iwl5000_nic_config(struct iwl_priv *priv) diff --git a/drivers/net/wireless/iwlwifi/iwl-6000.c b/drivers/net/wireless/iwlwifi/iwl-6000.c index 24d105b..9fb2a42 100644 --- a/drivers/net/wireless/iwlwifi/iwl-6000.c +++ b/drivers/net/wireless/iwlwifi/iwl-6000.c @@ -60,20 +60,16 @@ #define IWL6000G2_UCODE_API_MIN 4 #define IWL6000_FW_PRE "iwlwifi-6000-" -#define _IWL6000_MODULE_FIRMWARE(api) IWL6000_FW_PRE #api ".ucode" -#define IWL6000_MODULE_FIRMWARE(api) _IWL6000_MODULE_FIRMWARE(api) +#define IWL6000_MODULE_FIRMWARE(api) IWL6000_FW_PRE #api ".ucode" #define IWL6050_FW_PRE "iwlwifi-6050-" -#define _IWL6050_MODULE_FIRMWARE(api) IWL6050_FW_PRE #api ".ucode" -#define IWL6050_MODULE_FIRMWARE(api) _IWL6050_MODULE_FIRMWARE(api) +#define IWL6050_MODULE_FIRMWARE(api) IWL6050_FW_PRE #api ".ucode" #define IWL6005_FW_PRE "iwlwifi-6000g2a-" -#define _IWL6005_MODULE_FIRMWARE(api) IWL6005_FW_PRE #api ".ucode" -#define IWL6005_MODULE_FIRMWARE(api) _IWL6005_MODULE_FIRMWARE(api) +#define IWL6005_MODULE_FIRMWARE(api) IWL6005_FW_PRE #api ".ucode" #define IWL6030_FW_PRE "iwlwifi-6000g2b-" -#define _IWL6030_MODULE_FIRMWARE(api) IWL6030_FW_PRE #api ".ucode" -#define IWL6030_MODULE_FIRMWARE(api) _IWL6030_MODULE_FIRMWARE(api) +#define IWL6030_MODULE_FIRMWARE(api) IWL6030_FW_PRE #api ".ucode" static void iwl6000_set_ct_threshold(struct iwl_priv *priv) { -- cgit v0.10.2 From 3ecccbcd3c67374aeee447c08fcb9e39a99f7ee5 Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Tue, 29 Mar 2011 17:53:15 -0700 Subject: iwlagn: remove un-necessary function pointer After driver split, no need to use function pointer for those event and register dump function. Signed-off-by: Wey-Yi Guy diff --git a/drivers/net/wireless/iwlwifi/iwl-1000.c b/drivers/net/wireless/iwlwifi/iwl-1000.c index 4323d27..cb2f871 100644 --- a/drivers/net/wireless/iwlwifi/iwl-1000.c +++ b/drivers/net/wireless/iwlwifi/iwl-1000.c @@ -182,10 +182,6 @@ static struct iwl_lib_ops iwl1000_lib = { .rx_handler_setup = iwlagn_rx_handler_setup, .setup_deferred_work = iwlagn_setup_deferred_work, .is_valid_rtc_data_addr = iwlagn_hw_valid_rtc_data_addr, - .dump_nic_event_log = iwl_dump_nic_event_log, - .dump_nic_error_log = iwl_dump_nic_error_log, - .dump_csr = iwl_dump_csr, - .dump_fh = iwl_dump_fh, .send_tx_power = iwlagn_send_tx_power, .update_chain_flags = iwl_update_chain_flags, .apm_ops = { diff --git a/drivers/net/wireless/iwlwifi/iwl-2000.c b/drivers/net/wireless/iwlwifi/iwl-2000.c index 564477d..e73ac80 100644 --- a/drivers/net/wireless/iwlwifi/iwl-2000.c +++ b/drivers/net/wireless/iwlwifi/iwl-2000.c @@ -262,10 +262,6 @@ static struct iwl_lib_ops iwl2000_lib = { .setup_deferred_work = iwlagn_bt_setup_deferred_work, .cancel_deferred_work = iwlagn_bt_cancel_deferred_work, .is_valid_rtc_data_addr = iwlagn_hw_valid_rtc_data_addr, - .dump_nic_event_log = iwl_dump_nic_event_log, - .dump_nic_error_log = iwl_dump_nic_error_log, - .dump_csr = iwl_dump_csr, - .dump_fh = iwl_dump_fh, .send_tx_power = iwlagn_send_tx_power, .update_chain_flags = iwl_update_chain_flags, .set_channel_switch = iwl2030_hw_channel_switch, diff --git a/drivers/net/wireless/iwlwifi/iwl-5000.c b/drivers/net/wireless/iwlwifi/iwl-5000.c index 4dafc58..4c8f72a 100644 --- a/drivers/net/wireless/iwlwifi/iwl-5000.c +++ b/drivers/net/wireless/iwlwifi/iwl-5000.c @@ -350,10 +350,6 @@ static struct iwl_lib_ops iwl5000_lib = { .rx_handler_setup = iwlagn_rx_handler_setup, .setup_deferred_work = iwlagn_setup_deferred_work, .is_valid_rtc_data_addr = iwlagn_hw_valid_rtc_data_addr, - .dump_nic_event_log = iwl_dump_nic_event_log, - .dump_nic_error_log = iwl_dump_nic_error_log, - .dump_csr = iwl_dump_csr, - .dump_fh = iwl_dump_fh, .send_tx_power = iwlagn_send_tx_power, .update_chain_flags = iwl_update_chain_flags, .set_channel_switch = iwl5000_hw_channel_switch, @@ -406,9 +402,6 @@ static struct iwl_lib_ops iwl5150_lib = { .rx_handler_setup = iwlagn_rx_handler_setup, .setup_deferred_work = iwlagn_setup_deferred_work, .is_valid_rtc_data_addr = iwlagn_hw_valid_rtc_data_addr, - .dump_nic_event_log = iwl_dump_nic_event_log, - .dump_nic_error_log = iwl_dump_nic_error_log, - .dump_csr = iwl_dump_csr, .send_tx_power = iwlagn_send_tx_power, .update_chain_flags = iwl_update_chain_flags, .set_channel_switch = iwl5000_hw_channel_switch, diff --git a/drivers/net/wireless/iwlwifi/iwl-6000.c b/drivers/net/wireless/iwlwifi/iwl-6000.c index 9fb2a42..80a335f 100644 --- a/drivers/net/wireless/iwlwifi/iwl-6000.c +++ b/drivers/net/wireless/iwlwifi/iwl-6000.c @@ -289,10 +289,6 @@ static struct iwl_lib_ops iwl6000_lib = { .rx_handler_setup = iwlagn_rx_handler_setup, .setup_deferred_work = iwlagn_setup_deferred_work, .is_valid_rtc_data_addr = iwlagn_hw_valid_rtc_data_addr, - .dump_nic_event_log = iwl_dump_nic_event_log, - .dump_nic_error_log = iwl_dump_nic_error_log, - .dump_csr = iwl_dump_csr, - .dump_fh = iwl_dump_fh, .send_tx_power = iwlagn_send_tx_power, .update_chain_flags = iwl_update_chain_flags, .set_channel_switch = iwl6000_hw_channel_switch, @@ -347,10 +343,6 @@ static struct iwl_lib_ops iwl6030_lib = { .setup_deferred_work = iwlagn_bt_setup_deferred_work, .cancel_deferred_work = iwlagn_bt_cancel_deferred_work, .is_valid_rtc_data_addr = iwlagn_hw_valid_rtc_data_addr, - .dump_nic_event_log = iwl_dump_nic_event_log, - .dump_nic_error_log = iwl_dump_nic_error_log, - .dump_csr = iwl_dump_csr, - .dump_fh = iwl_dump_fh, .send_tx_power = iwlagn_send_tx_power, .update_chain_flags = iwl_update_chain_flags, .set_channel_switch = iwl6000_hw_channel_switch, diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.h b/drivers/net/wireless/iwlwifi/iwl-agn.h index 016b79e..290a208 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.h +++ b/drivers/net/wireless/iwlwifi/iwl-agn.h @@ -173,8 +173,6 @@ int iwlagn_hw_nic_init(struct iwl_priv *priv); int iwlagn_wait_tx_queue_empty(struct iwl_priv *priv); int iwlagn_txfifo_flush(struct iwl_priv *priv, u16 flush_control); void iwlagn_dev_txfifo_flush(struct iwl_priv *priv, u16 flush_control); -void iwl_dump_csr(struct iwl_priv *priv); -int iwl_dump_fh(struct iwl_priv *priv, char **buf, bool display); /* rx */ void iwlagn_rx_queue_restock(struct iwl_priv *priv); diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index c46be36..5e7281c 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -965,12 +965,10 @@ void iwl_irq_handle_error(struct iwl_priv *priv) IWL_ERR(priv, "Loaded firmware version: %s\n", priv->hw->wiphy->fw_version); - priv->cfg->ops->lib->dump_nic_error_log(priv); - if (priv->cfg->ops->lib->dump_csr) - priv->cfg->ops->lib->dump_csr(priv); - if (priv->cfg->ops->lib->dump_fh) - priv->cfg->ops->lib->dump_fh(priv, NULL, false); - priv->cfg->ops->lib->dump_nic_event_log(priv, false, NULL, false); + iwl_dump_nic_error_log(priv); + iwl_dump_csr(priv); + iwl_dump_fh(priv, NULL, false); + iwl_dump_nic_event_log(priv, false, NULL, false); #ifdef CONFIG_IWLWIFI_DEBUG if (iwl_get_debug_level(priv) & IWL_DL_FW_ERRORS) iwl_print_rx_config_cmd(priv, diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h index 82939f8..43d4c92 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.h +++ b/drivers/net/wireless/iwlwifi/iwl-core.h @@ -171,12 +171,6 @@ struct iwl_lib_ops { void (*cancel_deferred_work)(struct iwl_priv *priv); /* check validity of rtc data address */ int (*is_valid_rtc_data_addr)(u32 addr); - - int (*dump_nic_event_log)(struct iwl_priv *priv, - bool full_log, char **buf, bool display); - void (*dump_nic_error_log)(struct iwl_priv *priv); - void (*dump_csr)(struct iwl_priv *priv); - int (*dump_fh)(struct iwl_priv *priv, char **buf, bool display); int (*set_channel_switch)(struct iwl_priv *priv, struct ieee80211_channel_switch *ch_switch); /* power management */ @@ -598,6 +592,8 @@ extern const struct dev_pm_ops iwl_pm_ops; void iwl_dump_nic_error_log(struct iwl_priv *priv); int iwl_dump_nic_event_log(struct iwl_priv *priv, bool full_log, char **buf, bool display); +void iwl_dump_csr(struct iwl_priv *priv); +int iwl_dump_fh(struct iwl_priv *priv, char **buf, bool display); #ifdef CONFIG_IWLWIFI_DEBUG void iwl_print_rx_config_cmd(struct iwl_priv *priv, struct iwl_rxon_context *ctx); diff --git a/drivers/net/wireless/iwlwifi/iwl-debugfs.c b/drivers/net/wireless/iwlwifi/iwl-debugfs.c index 92f6efd..93a8699 100644 --- a/drivers/net/wireless/iwlwifi/iwl-debugfs.c +++ b/drivers/net/wireless/iwlwifi/iwl-debugfs.c @@ -437,8 +437,7 @@ static ssize_t iwl_dbgfs_log_event_read(struct file *file, int pos = 0; ssize_t ret = -ENOMEM; - ret = pos = priv->cfg->ops->lib->dump_nic_event_log( - priv, true, &buf, true); + ret = pos = iwl_dump_nic_event_log(priv, true, &buf, true); if (buf) { ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos); kfree(buf); @@ -462,8 +461,7 @@ static ssize_t iwl_dbgfs_log_event_write(struct file *file, if (sscanf(buf, "%d", &event_log_flag) != 1) return -EFAULT; if (event_log_flag == 1) - priv->cfg->ops->lib->dump_nic_event_log(priv, true, - NULL, false); + iwl_dump_nic_event_log(priv, true, NULL, false); return count; } @@ -1268,8 +1266,7 @@ static ssize_t iwl_dbgfs_csr_write(struct file *file, if (sscanf(buf, "%d", &csr) != 1) return -EFAULT; - if (priv->cfg->ops->lib->dump_csr) - priv->cfg->ops->lib->dump_csr(priv); + iwl_dump_csr(priv); return count; } @@ -1359,13 +1356,11 @@ static ssize_t iwl_dbgfs_fh_reg_read(struct file *file, int pos = 0; ssize_t ret = -EFAULT; - if (priv->cfg->ops->lib->dump_fh) { - ret = pos = priv->cfg->ops->lib->dump_fh(priv, &buf, true); - if (buf) { - ret = simple_read_from_buffer(user_buf, - count, ppos, buf, pos); - kfree(buf); - } + ret = pos = iwl_dump_fh(priv, &buf, true); + if (buf) { + ret = simple_read_from_buffer(user_buf, + count, ppos, buf, pos); + kfree(buf); } return ret; -- cgit v0.10.2 From 68b993118f715cc631b62b6a50574e4701fe9ace Mon Sep 17 00:00:00 2001 From: Garen Tamrazian Date: Wed, 30 Mar 2011 02:29:32 -0700 Subject: iwlagn: fix radar frame rejection The microcode may sometimes reject TX frames when on a radar channel even after we associated as it clears information during association and needs to receive a new beacon before allowing that channel again. This manifests itself as a TX status value of TX_STATUS_FAIL_PASSIVE_NO_RX. So in this case, stop the corresponding queue and give the frame back to mac80211 for retransmission. We start the queue again when a beacon from the AP is received which will make the regulatory enforcement in the device allow transmitting again. Signed-off-by: Garen Tamrazian Signed-off-by: Johannes Berg Signed-off-by: Wey-Yi Guy diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-lib.c b/drivers/net/wireless/iwlwifi/iwl-agn-lib.c index 9e47be6..cccf747 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-lib.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-lib.c @@ -172,6 +172,7 @@ static void iwlagn_count_agg_tx_err_status(struct iwl_priv *priv, u16 status) static void iwlagn_set_tx_status(struct iwl_priv *priv, struct ieee80211_tx_info *info, + struct iwl_rxon_context *ctx, struct iwlagn_tx_resp *tx_resp, int txq_id, bool is_agg) { @@ -186,6 +187,13 @@ static void iwlagn_set_tx_status(struct iwl_priv *priv, if (!iwl_is_tx_success(status)) iwlagn_count_tx_err_status(priv, status); + if (status == TX_STATUS_FAIL_PASSIVE_NO_RX && + iwl_is_associated_ctx(ctx) && ctx->vif && + ctx->vif->type == NL80211_IFTYPE_STATION) { + ctx->last_tx_rejected = true; + iwl_stop_queue(priv, &priv->txq[txq_id]); + } + IWL_DEBUG_TX_REPLY(priv, "TXQ %d status %s (0x%08x) rate_n_flags " "0x%x retries %d\n", txq_id, @@ -242,15 +250,16 @@ static int iwlagn_tx_status_reply_tx(struct iwl_priv *priv, /* # frames attempted by Tx command */ if (agg->frame_count == 1) { + struct iwl_tx_info *txb; + /* Only one frame was attempted; no block-ack will arrive */ idx = start_idx; IWL_DEBUG_TX_REPLY(priv, "FrameCnt = %d, StartIdx=%d idx=%d\n", agg->frame_count, agg->start_idx, idx); - iwlagn_set_tx_status(priv, - IEEE80211_SKB_CB( - priv->txq[txq_id].txb[idx].skb), - tx_resp, txq_id, true); + txb = &priv->txq[txq_id].txb[idx]; + iwlagn_set_tx_status(priv, IEEE80211_SKB_CB(txb->skb), + txb->ctx, tx_resp, txq_id, true); agg->wait_for_ba = 0; } else { /* Two or more frames were attempted; expect block-ack */ @@ -391,7 +400,8 @@ static void iwlagn_rx_reply_tx(struct iwl_priv *priv, struct iwl_tx_queue *txq = &priv->txq[txq_id]; struct ieee80211_tx_info *info; struct iwlagn_tx_resp *tx_resp = (void *)&pkt->u.raw[0]; - u32 status = le16_to_cpu(tx_resp->status.status); + struct iwl_tx_info *txb; + u32 status = le16_to_cpu(tx_resp->status.status); int tid; int sta_id; int freed; @@ -406,7 +416,8 @@ static void iwlagn_rx_reply_tx(struct iwl_priv *priv, } txq->time_stamp = jiffies; - info = IEEE80211_SKB_CB(txq->txb[txq->q.read_ptr].skb); + txb = &txq->txb[txq->q.read_ptr]; + info = IEEE80211_SKB_CB(txb->skb); memset(&info->status, 0, sizeof(info->status)); tid = (tx_resp->ra_tid & IWLAGN_TX_RES_TID_MSK) >> @@ -450,12 +461,14 @@ static void iwlagn_rx_reply_tx(struct iwl_priv *priv, iwl_wake_queue(priv, txq); } } else { - iwlagn_set_tx_status(priv, info, tx_resp, txq_id, false); + iwlagn_set_tx_status(priv, info, txb->ctx, tx_resp, + txq_id, false); freed = iwlagn_tx_queue_reclaim(priv, txq_id, index); iwl_free_tfds_in_queue(priv, sta_id, tid, freed); if (priv->mac80211_registered && - (iwl_queue_space(&txq->q) > txq->q.low_mark)) + iwl_queue_space(&txq->q) > txq->q.low_mark && + status != TX_STATUS_FAIL_PASSIVE_NO_RX) iwl_wake_queue(priv, txq); } diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-rxon.c b/drivers/net/wireless/iwlwifi/iwl-agn-rxon.c index c335ee6..56f46ee 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-rxon.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-rxon.c @@ -29,6 +29,7 @@ #include "iwl-sta.h" #include "iwl-core.h" #include "iwl-agn-calib.h" +#include "iwl-helpers.h" static int iwlagn_disable_bss(struct iwl_priv *priv, struct iwl_rxon_context *ctx, @@ -600,6 +601,18 @@ void iwlagn_bss_info_changed(struct ieee80211_hw *hw, priv->timestamp = bss_conf->timestamp; ctx->staging.filter_flags |= RXON_FILTER_ASSOC_MSK; } else { + /* + * If we disassociate while there are pending + * frames, just wake up the queues and let the + * frames "escape" ... This shouldn't really + * be happening to start with, but we should + * not get stuck in this case either since it + * can happen if userspace gets confused. + */ + if (ctx->last_tx_rejected) { + ctx->last_tx_rejected = false; + iwl_wake_any_queue(priv, ctx); + } ctx->staging.filter_flags &= ~RXON_FILTER_ASSOC_MSK; } } diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-ucode.c b/drivers/net/wireless/iwlwifi/iwl-agn-ucode.c index 01a6d2f..5c30f6b 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-ucode.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-ucode.c @@ -428,6 +428,7 @@ void iwlagn_send_bt_env(struct iwl_priv *priv, u8 action, u8 type) int iwlagn_alive_notify(struct iwl_priv *priv) { const struct queue_to_fifo_ac *queue_to_fifo; + struct iwl_rxon_context *ctx; u32 a; unsigned long flags; int i, chan; @@ -501,6 +502,8 @@ int iwlagn_alive_notify(struct iwl_priv *priv) memset(&priv->queue_stopped[0], 0, sizeof(priv->queue_stopped)); for (i = 0; i < 4; i++) atomic_set(&priv->queue_stop_count[i], 0); + for_each_context(priv, ctx) + ctx->last_tx_rejected = false; /* reset to 0 to enable all the queue first */ priv->txq_ctx_active_msk = 0; diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.h b/drivers/net/wireless/iwlwifi/iwl-agn.h index 290a208..078a23e 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.h +++ b/drivers/net/wireless/iwlwifi/iwl-agn.h @@ -220,6 +220,7 @@ static inline u32 iwl_tx_status_to_mac80211(u32 status) case TX_STATUS_DIRECT_DONE: return IEEE80211_TX_STAT_ACK; case TX_STATUS_FAIL_DEST_PS: + case TX_STATUS_FAIL_PASSIVE_NO_RX: return IEEE80211_TX_STAT_TX_FILTERED; default: return 0; diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index 7213336..14f7d8f 100644 --- a/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h @@ -1170,6 +1170,8 @@ struct iwl_rxon_context { bool enabled, is_40mhz; u8 extension_chan_offset; } ht; + + bool last_tx_rejected; }; enum iwl_scan_type { diff --git a/drivers/net/wireless/iwlwifi/iwl-helpers.h b/drivers/net/wireless/iwlwifi/iwl-helpers.h index 5da5761..9309ff2 100644 --- a/drivers/net/wireless/iwlwifi/iwl-helpers.h +++ b/drivers/net/wireless/iwlwifi/iwl-helpers.h @@ -131,6 +131,19 @@ static inline void iwl_stop_queue(struct iwl_priv *priv, ieee80211_stop_queue(priv->hw, ac); } +static inline void iwl_wake_any_queue(struct iwl_priv *priv, + struct iwl_rxon_context *ctx) +{ + u8 ac; + + for (ac = 0; ac < AC_NUM; ac++) { + IWL_DEBUG_INFO(priv, "Queue Status: Q[%d] %s\n", + ac, (atomic_read(&priv->queue_stop_count[ac]) > 0) + ? "stopped" : "awake"); + iwl_wake_queue(priv, &priv->txq[ctx->ac_to_queue[ac]]); + } +} + #define ieee80211_stop_queue DO_NOT_USE_ieee80211_stop_queue #define ieee80211_wake_queue DO_NOT_USE_ieee80211_wake_queue diff --git a/drivers/net/wireless/iwlwifi/iwl-rx.c b/drivers/net/wireless/iwlwifi/iwl-rx.c index c421f56..4472761 100644 --- a/drivers/net/wireless/iwlwifi/iwl-rx.c +++ b/drivers/net/wireless/iwlwifi/iwl-rx.c @@ -873,6 +873,7 @@ static void iwl_pass_packet_to_mac80211(struct iwl_priv *priv, { struct sk_buff *skb; __le16 fc = hdr->frame_control; + struct iwl_rxon_context *ctx; /* We only process data packets if the interface is open */ if (unlikely(!priv->is_open)) { @@ -895,6 +896,26 @@ static void iwl_pass_packet_to_mac80211(struct iwl_priv *priv, skb_add_rx_frag(skb, 0, rxb->page, (void *)hdr - rxb_addr(rxb), len); iwl_update_stats(priv, false, fc, len); + + /* + * Wake any queues that were stopped due to a passive channel tx + * failure. This can happen because the regulatory enforcement in + * the device waits for a beacon before allowing transmission, + * sometimes even after already having transmitted frames for the + * association because the new RXON may reset the information. + */ + if (unlikely(ieee80211_is_beacon(fc))) { + for_each_context(priv, ctx) { + if (!ctx->last_tx_rejected) + continue; + if (compare_ether_addr(hdr->addr3, + ctx->active.bssid_addr)) + continue; + ctx->last_tx_rejected = false; + iwl_wake_any_queue(priv, ctx); + } + } + memcpy(IEEE80211_SKB_RXCB(skb), stats, sizeof(*stats)); ieee80211_rx(priv->hw, skb); -- cgit v0.10.2 From a2b76b3b31568da9d281a393845f17689594ccdf Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 29 Mar 2011 06:29:37 -0700 Subject: iwlwifi: fix bugs in change_interface If change_interface gets invoked during a firmware restart, it may crash; prevent that from happening by checking if ctx->vif is assigned. Additionally, in my initial commit I forgot to set the vif->p2p variable correctly, so fix that too. Cc: stable@kernel.org [2.6.38+] Signed-off-by: Johannes Berg Signed-off-by: Wey-Yi Guy diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index 5e7281c..b5a0654 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -1775,6 +1775,15 @@ int iwl_mac_change_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif, mutex_lock(&priv->mutex); + if (!ctx->vif || !iwl_is_ready_rf(priv)) { + /* + * Huh? But wait ... this can maybe happen when + * we're in the middle of a firmware restart! + */ + err = -EBUSY; + goto out; + } + interface_modes = ctx->interface_modes | ctx->exclusive_interface_modes; if (!(interface_modes & BIT(newtype))) { @@ -1802,6 +1811,7 @@ int iwl_mac_change_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif, /* success */ iwl_teardown_interface(priv, vif, true); vif->type = newtype; + vif->p2p = newp2p; err = iwl_setup_interface(priv, ctx); WARN_ON(err); /* -- cgit v0.10.2 From dcf6640f0f58affa93f158d8573b6868136e3d62 Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Fri, 1 Apr 2011 13:20:44 -0700 Subject: iwlagn: PAPD read for 2000 series devices For 2000 series NICs, disable OTP refresh in order to read correct PAPD table from high OTP block Signed-off-by: Wey-Yi Guy diff --git a/drivers/net/wireless/iwlwifi/iwl-2000.c b/drivers/net/wireless/iwlwifi/iwl-2000.c index e73ac80..86d7ffd6 100644 --- a/drivers/net/wireless/iwlwifi/iwl-2000.c +++ b/drivers/net/wireless/iwlwifi/iwl-2000.c @@ -98,6 +98,8 @@ static void iwl2000_nic_config(struct iwl_priv *priv) iwl_set_bit(priv, CSR_GP_DRIVER_REG, CSR_GP_DRIVER_REG_BIT_RADIO_IQ_INVER); + if (priv->cfg->disable_otp_refresh) + iwl_write_prph(priv, APMG_ANALOG_SVR_REG, 0x80000010); } static struct iwl_sensitivity_ranges iwl2000_sensitivity = { @@ -409,7 +411,8 @@ static struct iwl_bt_params iwl2030_bt_params = { .need_dc_calib = true, \ .need_temp_offset_calib = true, \ .led_mode = IWL_LED_RF_STATE, \ - .iq_invert = true \ + .iq_invert = true, \ + .disable_otp_refresh = true \ struct iwl_cfg iwl2000_2bgn_cfg = { .name = "2000 Series 2x2 BGN", diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h index 43d4c92..10a6f85 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.h +++ b/drivers/net/wireless/iwlwifi/iwl-core.h @@ -331,6 +331,7 @@ struct iwl_ht_params { * @rx_with_siso_diversity: 1x1 device with rx antenna diversity * @internal_wimax_coex: internal wifi/wimax combo device * @iq_invert: I/Q inversion + * @disable_otp_refresh: disable OTP refresh current limit * * We enable the driver to be backward compatible wrt API version. The * driver specifies which APIs it supports (with @ucode_api_max being the @@ -381,6 +382,7 @@ struct iwl_cfg { const bool rx_with_siso_diversity; const bool internal_wimax_coex; const bool iq_invert; + const bool disable_otp_refresh; }; /*************************** -- cgit v0.10.2 From ece3cd2e8fb119a4394dcdc6ef921e85cdd4cc69 Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Fri, 1 Apr 2011 16:29:47 -0700 Subject: iwlagn: no 3945 define needed Remove 3945 define Signed-off-by: Wey-Yi Guy diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-rs.h b/drivers/net/wireless/iwlwifi/iwl-agn-rs.h index 69a2993..bdae82e 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-rs.h +++ b/drivers/net/wireless/iwlwifi/iwl-agn-rs.h @@ -83,7 +83,6 @@ enum { enum { IWL_FIRST_OFDM_RATE = IWL_RATE_6M_INDEX, - IWL39_LAST_OFDM_RATE = IWL_RATE_54M_INDEX, IWL_LAST_OFDM_RATE = IWL_RATE_60M_INDEX, IWL_FIRST_CCK_RATE = IWL_RATE_1M_INDEX, IWL_LAST_CCK_RATE = IWL_RATE_11M_INDEX, -- cgit v0.10.2 From ab4bf5ef5afce9d31cf5cf05ac80b3b01cbb24a3 Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Fri, 1 Apr 2011 16:35:09 -0700 Subject: iwlagn: remove unused 3945 define 3945 no longer apply Signed-off-by: Wey-Yi Guy diff --git a/drivers/net/wireless/iwlwifi/iwl-fh.h b/drivers/net/wireless/iwlwifi/iwl-fh.h index da06d13..0f1052f 100644 --- a/drivers/net/wireless/iwlwifi/iwl-fh.h +++ b/drivers/net/wireless/iwlwifi/iwl-fh.h @@ -424,7 +424,6 @@ #define RX_LOW_WATERMARK 8 /* Size of one Rx buffer in host DRAM */ -#define IWL_RX_BUF_SIZE_3K (3 * 1000) /* 3945 only */ #define IWL_RX_BUF_SIZE_4K (4 * 1024) #define IWL_RX_BUF_SIZE_8K (8 * 1024) @@ -443,7 +442,7 @@ struct iwl_rb_status { __le16 closed_fr_num; __le16 finished_rb_num; __le16 finished_fr_nam; - __le32 __unused; /* 3945 only */ + __le32 __unused; } __packed; -- cgit v0.10.2 From ee3cd7e04ca08ff0ec1ebb96be7e64aef928f511 Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Fri, 1 Apr 2011 16:35:10 -0700 Subject: iwlagn: cleanup to remove the reference for 3945 More clean up after driver split Signed-off-by: Wey-Yi Guy diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index b5a0654..4c76499 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -1049,7 +1049,6 @@ int iwl_apm_init(struct iwl_priv *priv) /* * Enable HAP INTA (interrupt from management bus) to * wake device's PCI Express link L1a -> L0s - * NOTE: This is no-op for 3945 (non-existant bit) */ iwl_set_bit(priv, CSR_HW_IF_CONFIG_REG, CSR_HW_IF_CONFIG_REG_BIT_HAP_WAKE_L1A); -- cgit v0.10.2 From 6bb64697ed58909985487e885c269dafd09583f1 Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Fri, 1 Apr 2011 16:29:50 -0700 Subject: iwlagn: remove more reference to legacy devices Remove the reference to both 3945 and 4965 in LED code Signed-off-by: Wey-Yi Guy diff --git a/drivers/net/wireless/iwlwifi/iwl-led.c b/drivers/net/wireless/iwlwifi/iwl-led.c index c2862d4..0d90004 100644 --- a/drivers/net/wireless/iwlwifi/iwl-led.c +++ b/drivers/net/wireless/iwlwifi/iwl-led.c @@ -63,8 +63,8 @@ static const struct ieee80211_tpt_blink iwl_blink[] = { /* * Adjust led blink rate to compensate on a MAC Clock difference on every HW - * Led blink rate analysis showed an average deviation of 0% on 3945, - * 5% on 4965 HW and 20% on 5000 series and up. + * Led blink rate analysis showed an average deviation of 20% on 5000 series + * and up. * Need to compensate on the led on/off time per HW according to the deviation * to achieve the desired led frequency * The calculation is: (100-averageDeviation)/100 * blinkTime -- cgit v0.10.2 From 15ade3ca647d95611814333cfe0885fd0184481e Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Fri, 1 Apr 2011 16:29:51 -0700 Subject: iwlagn: remove un-needed configuration After driver split, set_l0s config is no longer needed, remove it Signed-off-by: Wey-Yi Guy diff --git a/drivers/net/wireless/iwlwifi/iwl-1000.c b/drivers/net/wireless/iwlwifi/iwl-1000.c index cb2f871..5a72810 100644 --- a/drivers/net/wireless/iwlwifi/iwl-1000.c +++ b/drivers/net/wireless/iwlwifi/iwl-1000.c @@ -235,7 +235,6 @@ static struct iwl_base_params iwl1000_base_params = { .num_of_ampdu_queues = IWLAGN_NUM_AMPDU_QUEUES, .eeprom_size = OTP_LOW_IMAGE_SIZE, .pll_cfg_val = CSR50_ANA_PLL_CFG_VAL, - .set_l0s = true, .max_ll_items = OTP_MAX_LL_ITEMS_1000, .shadow_ram_support = false, .led_compensation = 51, diff --git a/drivers/net/wireless/iwlwifi/iwl-2000.c b/drivers/net/wireless/iwlwifi/iwl-2000.c index 86d7ffd6..9daf888 100644 --- a/drivers/net/wireless/iwlwifi/iwl-2000.c +++ b/drivers/net/wireless/iwlwifi/iwl-2000.c @@ -343,7 +343,6 @@ static struct iwl_base_params iwl2000_base_params = { .num_of_queues = IWLAGN_NUM_QUEUES, .num_of_ampdu_queues = IWLAGN_NUM_AMPDU_QUEUES, .pll_cfg_val = 0, - .set_l0s = true, .max_ll_items = OTP_MAX_LL_ITEMS_2x00, .shadow_ram_support = true, .led_compensation = 51, @@ -366,7 +365,6 @@ static struct iwl_base_params iwl2030_base_params = { .num_of_queues = IWLAGN_NUM_QUEUES, .num_of_ampdu_queues = IWLAGN_NUM_AMPDU_QUEUES, .pll_cfg_val = 0, - .set_l0s = true, .max_ll_items = OTP_MAX_LL_ITEMS_2x00, .shadow_ram_support = true, .led_compensation = 57, diff --git a/drivers/net/wireless/iwlwifi/iwl-5000.c b/drivers/net/wireless/iwlwifi/iwl-5000.c index 4c8f72a..8106423 100644 --- a/drivers/net/wireless/iwlwifi/iwl-5000.c +++ b/drivers/net/wireless/iwlwifi/iwl-5000.c @@ -464,7 +464,6 @@ static struct iwl_base_params iwl5000_base_params = { .num_of_queues = IWLAGN_NUM_QUEUES, .num_of_ampdu_queues = IWLAGN_NUM_AMPDU_QUEUES, .pll_cfg_val = CSR50_ANA_PLL_CFG_VAL, - .set_l0s = true, .led_compensation = 51, .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS, .plcp_delta_threshold = IWL_MAX_PLCP_ERR_LONG_THRESHOLD_DEF, diff --git a/drivers/net/wireless/iwlwifi/iwl-6000.c b/drivers/net/wireless/iwlwifi/iwl-6000.c index 80a335f..7f0715e 100644 --- a/drivers/net/wireless/iwlwifi/iwl-6000.c +++ b/drivers/net/wireless/iwlwifi/iwl-6000.c @@ -432,7 +432,6 @@ static struct iwl_base_params iwl6000_base_params = { .num_of_queues = IWLAGN_NUM_QUEUES, .num_of_ampdu_queues = IWLAGN_NUM_AMPDU_QUEUES, .pll_cfg_val = 0, - .set_l0s = true, .max_ll_items = OTP_MAX_LL_ITEMS_6x00, .shadow_ram_support = true, .led_compensation = 51, @@ -454,7 +453,6 @@ static struct iwl_base_params iwl6050_base_params = { .num_of_queues = IWLAGN_NUM_QUEUES, .num_of_ampdu_queues = IWLAGN_NUM_AMPDU_QUEUES, .pll_cfg_val = 0, - .set_l0s = true, .max_ll_items = OTP_MAX_LL_ITEMS_6x50, .shadow_ram_support = true, .led_compensation = 51, @@ -475,7 +473,6 @@ static struct iwl_base_params iwl6000_g2_base_params = { .num_of_queues = IWLAGN_NUM_QUEUES, .num_of_ampdu_queues = IWLAGN_NUM_AMPDU_QUEUES, .pll_cfg_val = 0, - .set_l0s = true, .max_ll_items = OTP_MAX_LL_ITEMS_6x00, .shadow_ram_support = true, .led_compensation = 57, diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index 4c76499..0e98a87 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -1061,20 +1061,18 @@ int iwl_apm_init(struct iwl_priv *priv) * If not (unlikely), enable L0S, so there is at least some * power savings, even without L1. */ - if (priv->cfg->base_params->set_l0s) { - lctl = iwl_pcie_link_ctl(priv); - if ((lctl & PCI_CFG_LINK_CTRL_VAL_L1_EN) == - PCI_CFG_LINK_CTRL_VAL_L1_EN) { - /* L1-ASPM enabled; disable(!) L0S */ - iwl_set_bit(priv, CSR_GIO_REG, - CSR_GIO_REG_VAL_L0S_ENABLED); - IWL_DEBUG_POWER(priv, "L1 Enabled; Disabling L0S\n"); - } else { - /* L1-ASPM disabled; enable(!) L0S */ - iwl_clear_bit(priv, CSR_GIO_REG, - CSR_GIO_REG_VAL_L0S_ENABLED); - IWL_DEBUG_POWER(priv, "L1 Disabled; Enabling L0S\n"); - } + lctl = iwl_pcie_link_ctl(priv); + if ((lctl & PCI_CFG_LINK_CTRL_VAL_L1_EN) == + PCI_CFG_LINK_CTRL_VAL_L1_EN) { + /* L1-ASPM enabled; disable(!) L0S */ + iwl_set_bit(priv, CSR_GIO_REG, + CSR_GIO_REG_VAL_L0S_ENABLED); + IWL_DEBUG_POWER(priv, "L1 Enabled; Disabling L0S\n"); + } else { + /* L1-ASPM disabled; enable(!) L0S */ + iwl_clear_bit(priv, CSR_GIO_REG, + CSR_GIO_REG_VAL_L0S_ENABLED); + IWL_DEBUG_POWER(priv, "L1 Disabled; Enabling L0S\n"); } /* Configure analog phase-lock-loop before activating to D0A */ diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h index 10a6f85..7d303acc 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.h +++ b/drivers/net/wireless/iwlwifi/iwl-core.h @@ -265,7 +265,6 @@ struct iwl_base_params { int num_of_ampdu_queues;/* def: HW dependent */ /* for iwl_apm_init() */ u32 pll_cfg_val; - bool set_l0s; const u16 max_ll_items; const bool shadow_ram_support; -- cgit v0.10.2 From 8ff84a2c99bc7f5f22d9d2b5365d821ce4f7a8f9 Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Fri, 1 Apr 2011 16:29:52 -0700 Subject: iwlagn: more cleanup to remove unused reference More cleanup code, no functional changes Signed-off-by: Wey-Yi Guy diff --git a/drivers/net/wireless/iwlwifi/iwl-fh.h b/drivers/net/wireless/iwlwifi/iwl-fh.h index 0f1052f..b90924e 100644 --- a/drivers/net/wireless/iwlwifi/iwl-fh.h +++ b/drivers/net/wireless/iwlwifi/iwl-fh.h @@ -77,14 +77,14 @@ /** * Keep-Warm (KW) buffer base address. * - * Driver must allocate a 4KByte buffer that is used by 4965 for keeping the + * Driver must allocate a 4KByte buffer that is for keeping the * host DRAM powered on (via dummy accesses to DRAM) to maintain low-latency - * DRAM access when 4965 is Txing or Rxing. The dummy accesses prevent host + * DRAM access when doing Txing or Rxing. The dummy accesses prevent host * from going into a power-savings mode that would cause higher DRAM latency, * and possible data over/under-runs, before all Tx/Rx is complete. * * Driver loads FH_KW_MEM_ADDR_REG with the physical address (bits 35:4) - * of the buffer, which must be 4K aligned. Once this is set up, the 4965 + * of the buffer, which must be 4K aligned. Once this is set up, the device * automatically invokes keep-warm accesses when normal accesses might not * be sufficient to maintain fast DRAM response. * @@ -97,7 +97,7 @@ /** * TFD Circular Buffers Base (CBBC) addresses * - * 4965 has 16 base pointer registers, one for each of 16 host-DRAM-resident + * Device has 16 base pointer registers, one for each of 16 host-DRAM-resident * circular buffers (CBs/queues) containing Transmit Frame Descriptors (TFDs) * (see struct iwl_tfd_frame). These 16 pointer registers are offset by 0x04 * bytes from one another. Each TFD circular buffer in DRAM must be 256-byte @@ -116,16 +116,16 @@ /** * Rx SRAM Control and Status Registers (RSCSR) * - * These registers provide handshake between driver and 4965 for the Rx queue + * These registers provide handshake between driver and device for the Rx queue * (this queue handles *all* command responses, notifications, Rx data, etc. - * sent from 4965 uCode to host driver). Unlike Tx, there is only one Rx + * sent from uCode to host driver). Unlike Tx, there is only one Rx * queue, and only one Rx DMA/FIFO channel. Also unlike Tx, which can * concatenate up to 20 DRAM buffers to form a Tx frame, each Receive Buffer * Descriptor (RBD) points to only one Rx Buffer (RB); there is a 1:1 * mapping between RBDs and RBs. * * Driver must allocate host DRAM memory for the following, and set the - * physical address of each into 4965 registers: + * physical address of each into device registers: * * 1) Receive Buffer Descriptor (RBD) circular buffer (CB), typically with 256 * entries (although any power of 2, up to 4096, is selectable by driver). @@ -140,20 +140,20 @@ * Driver sets physical address [35:8] of base of RBD circular buffer * into FH_RSCSR_CHNL0_RBDCB_BASE_REG [27:0]. * - * 2) Rx status buffer, 8 bytes, in which 4965 indicates which Rx Buffers + * 2) Rx status buffer, 8 bytes, in which uCode indicates which Rx Buffers * (RBs) have been filled, via a "write pointer", actually the index of * the RB's corresponding RBD within the circular buffer. Driver sets * physical address [35:4] into FH_RSCSR_CHNL0_STTS_WPTR_REG [31:0]. * * Bit fields in lower dword of Rx status buffer (upper dword not used - * by driver; see struct iwl4965_shared, val0): + * by driver: * 31-12: Not used by driver * 11- 0: Index of last filled Rx buffer descriptor - * (4965 writes, driver reads this value) + * (device writes, driver reads this value) * - * As the driver prepares Receive Buffers (RBs) for 4965 to fill, driver must + * As the driver prepares Receive Buffers (RBs) for device to fill, driver must * enter pointers to these RBs into contiguous RBD circular buffer entries, - * and update the 4965's "write" index register, + * and update the device's "write" index register, * FH_RSCSR_CHNL0_RBDCB_WPTR_REG. * * This "write" index corresponds to the *next* RBD that the driver will make @@ -162,12 +162,12 @@ * RBs), should be 8 after preparing the first 8 RBs (for example), and must * wrap back to 0 at the end of the circular buffer (but don't wrap before * "read" index has advanced past 1! See below). - * NOTE: 4965 EXPECTS THE WRITE INDEX TO BE INCREMENTED IN MULTIPLES OF 8. + * NOTE: DEVICE EXPECTS THE WRITE INDEX TO BE INCREMENTED IN MULTIPLES OF 8. * - * As the 4965 fills RBs (referenced from contiguous RBDs within the circular + * As the device fills RBs (referenced from contiguous RBDs within the circular * buffer), it updates the Rx status buffer in host DRAM, 2) described above, * to tell the driver the index of the latest filled RBD. The driver must - * read this "read" index from DRAM after receiving an Rx interrupt from 4965. + * read this "read" index from DRAM after receiving an Rx interrupt from device * * The driver must also internally keep track of a third index, which is the * next RBD to process. When receiving an Rx interrupt, driver should process @@ -176,7 +176,7 @@ * driver may process the RB pointed to by RBD 0. Depending on volume of * traffic, there may be many RBs to process. * - * If read index == write index, 4965 thinks there is no room to put new data. + * If read index == write index, device thinks there is no room to put new data. * Due to this, the maximum number of filled RBs is 255, instead of 256. To * be safe, make sure that there is a gap of at least 2 RBDs between "write" * and "read" indexes; that is, make sure that there are no more than 254 @@ -303,7 +303,7 @@ /** * Transmit DMA Channel Control/Status Registers (TCSR) * - * 4965 has one configuration register for each of 8 Tx DMA/FIFO channels + * Device has one configuration register for each of 8 Tx DMA/FIFO channels * supported in hardware (don't confuse these with the 16 Tx queues in DRAM, * which feed the DMA/FIFO channels); config regs are separated by 0x20 bytes. * @@ -326,7 +326,6 @@ #define FH_TCSR_UPPER_BOUND (FH_MEM_LOWER_BOUND + 0xE60) /* Find Control/Status reg for given Tx DMA/FIFO channel */ -#define FH49_TCSR_CHNL_NUM (7) #define FH50_TCSR_CHNL_NUM (8) /* TCSR: tx_config register values */ diff --git a/drivers/net/wireless/iwlwifi/iwl-prph.h b/drivers/net/wireless/iwlwifi/iwl-prph.h index c960195..f00d188 100644 --- a/drivers/net/wireless/iwlwifi/iwl-prph.h +++ b/drivers/net/wireless/iwlwifi/iwl-prph.h @@ -107,17 +107,7 @@ * device. A queue maps to only one (selectable by driver) Tx DMA channel, * but one DMA channel may take input from several queues. * - * Tx DMA FIFOs have dedicated purposes. For 4965, they are used as follows - * (cf. default_queue_to_tx_fifo in iwl-4965.c): - * - * 0 -- EDCA BK (background) frames, lowest priority - * 1 -- EDCA BE (best effort) frames, normal priority - * 2 -- EDCA VI (video) frames, higher priority - * 3 -- EDCA VO (voice) and management frames, highest priority - * 4 -- Commands (e.g. RXON, etc.) - * 5 -- unused (HCCA) - * 6 -- unused (HCCA) - * 7 -- not used by driver (device-internal only) + * Tx DMA FIFOs have dedicated purposes. * * For 5000 series and up, they are used differently * (cf. iwl5000_default_queue_to_tx_fifo in iwl-5000.c): @@ -151,7 +141,7 @@ * Tx completion may end up being out-of-order). * * The driver must maintain the queue's Byte Count table in host DRAM - * (struct iwl4965_sched_queue_byte_cnt_tbl) for this mode. + * for this mode. * This mode does not support fragmentation. * * 2) FIFO (a.k.a. non-Scheduler-ACK), in which each TFD is processed in order. @@ -164,7 +154,7 @@ * * Driver controls scheduler operation via 3 means: * 1) Scheduler registers - * 2) Shared scheduler data base in internal 4956 SRAM + * 2) Shared scheduler data base in internal SRAM * 3) Shared data in host DRAM * * Initialization: diff --git a/drivers/net/wireless/iwlwifi/iwl-tx.c b/drivers/net/wireless/iwlwifi/iwl-tx.c index 565980f..3732380 100644 --- a/drivers/net/wireless/iwlwifi/iwl-tx.c +++ b/drivers/net/wireless/iwlwifi/iwl-tx.c @@ -232,7 +232,6 @@ void iwl_cmd_queue_free(struct iwl_priv *priv) * reclaiming packets (on 'tx done IRQ), if free space become > high mark, * Tx queue resumed. * - * See more detailed info in iwl-4965-hw.h. ***************************************************/ int iwl_queue_space(const struct iwl_queue *q) -- cgit v0.10.2 From 23c0fcc66b4345ea97ae588c2e01f10c994652ba Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Fri, 1 Apr 2011 16:29:53 -0700 Subject: iwlagn: all _agn devices support power save mode Remove broken_power_save checking Signed-off-by: Wey-Yi Guy diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index 60bfde7..23b89c2 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -2828,9 +2828,8 @@ static int iwl_mac_setup_register(struct iwl_priv *priv, hw->max_tx_aggregation_subframes = LINK_QUAL_AGG_FRAME_LIMIT_DEF; - if (!priv->cfg->base_params->broken_powersave) - hw->flags |= IEEE80211_HW_SUPPORTS_PS | - IEEE80211_HW_SUPPORTS_DYNAMIC_PS; + hw->flags |= IEEE80211_HW_SUPPORTS_PS | + IEEE80211_HW_SUPPORTS_DYNAMIC_PS; if (priv->cfg->sku & IWL_SKU_N) hw->flags |= IEEE80211_HW_SUPPORTS_DYNAMIC_SMPS | diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h index 7d303acc..a0530d0 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.h +++ b/drivers/net/wireless/iwlwifi/iwl-core.h @@ -269,7 +269,6 @@ struct iwl_base_params { const u16 max_ll_items; const bool shadow_ram_support; u16 led_compensation; - const bool broken_powersave; int chain_noise_num_beacons; bool adv_thermal_throttle; bool support_ct_kill_exit; diff --git a/drivers/net/wireless/iwlwifi/iwl-debugfs.c b/drivers/net/wireless/iwlwifi/iwl-debugfs.c index 93a8699..2c58980 100644 --- a/drivers/net/wireless/iwlwifi/iwl-debugfs.c +++ b/drivers/net/wireless/iwlwifi/iwl-debugfs.c @@ -1723,11 +1723,8 @@ int iwl_dbgfs_register(struct iwl_priv *priv, const char *name) DEBUGFS_ADD_FILE(status, dir_data, S_IRUSR); DEBUGFS_ADD_FILE(interrupt, dir_data, S_IWUSR | S_IRUSR); DEBUGFS_ADD_FILE(qos, dir_data, S_IRUSR); - if (!priv->cfg->base_params->broken_powersave) { - DEBUGFS_ADD_FILE(sleep_level_override, dir_data, - S_IWUSR | S_IRUSR); - DEBUGFS_ADD_FILE(current_sleep_command, dir_data, S_IRUSR); - } + DEBUGFS_ADD_FILE(sleep_level_override, dir_data, S_IWUSR | S_IRUSR); + DEBUGFS_ADD_FILE(current_sleep_command, dir_data, S_IRUSR); DEBUGFS_ADD_FILE(thermal_throttling, dir_data, S_IRUSR); DEBUGFS_ADD_FILE(disable_ht40, dir_data, S_IWUSR | S_IRUSR); DEBUGFS_ADD_FILE(rx_statistics, dir_debug, S_IRUSR); diff --git a/drivers/net/wireless/iwlwifi/iwl-power.c b/drivers/net/wireless/iwlwifi/iwl-power.c index c43c8e6..ae176d8 100644 --- a/drivers/net/wireless/iwlwifi/iwl-power.c +++ b/drivers/net/wireless/iwlwifi/iwl-power.c @@ -354,9 +354,7 @@ static void iwl_power_build_cmd(struct iwl_priv *priv, dtimper = priv->hw->conf.ps_dtim_period ?: 1; - if (priv->cfg->base_params->broken_powersave) - iwl_power_sleep_cam_cmd(priv, cmd); - else if (priv->hw->conf.flags & IEEE80211_CONF_IDLE) + if (priv->hw->conf.flags & IEEE80211_CONF_IDLE) iwl_static_sleep_cmd(priv, cmd, IWL_POWER_INDEX_5, 20); else if (priv->cfg->ops->lib->tt_ops.lower_power_detection && priv->cfg->ops->lib->tt_ops.tt_power_mode && -- cgit v0.10.2 From ae89726a02049e8f61bb3c8bf5dbf1fc06527a07 Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Fri, 1 Apr 2011 16:29:54 -0700 Subject: iwlagn: tx power calib always done in firmware Remove the config flag for tx power calib Signed-off-by: Wey-Yi Guy diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-lib.c b/drivers/net/wireless/iwlwifi/iwl-agn-lib.c index cccf747..bc5dfe2 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-lib.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-lib.c @@ -495,8 +495,10 @@ void iwlagn_rx_handler_setup(struct iwl_priv *priv) void iwlagn_setup_deferred_work(struct iwl_priv *priv) { - /* in agn, the tx power calibration is done in uCode */ - priv->disable_tx_power_cal = 1; + /* + * nothing need to be done here anymore + * still keep for future use if needed + */ } int iwlagn_hw_valid_rtc_data_addr(u32 addr) diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h index a0530d0..98dc544 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.h +++ b/drivers/net/wireless/iwlwifi/iwl-core.h @@ -250,8 +250,6 @@ struct iwl_mod_params { * @wd_timeout: TX queues watchdog timeout * @temperature_kelvin: temperature report by uCode in kelvin * @max_event_log_size: size of event log buffer size for ucode event logging - * @tx_power_by_driver: tx power calibration performed by driver - * instead of uCode * @ucode_tracing: support ucode continuous tracing * @sensitivity_calib_by_driver: driver has the capability to perform * sensitivity calibration operation @@ -278,7 +276,6 @@ struct iwl_base_params { unsigned int wd_timeout; bool temperature_kelvin; u32 max_event_log_size; - const bool tx_power_by_driver; const bool ucode_tracing; const bool sensitivity_calib_by_driver; const bool chain_noise_calib_by_driver; diff --git a/drivers/net/wireless/iwlwifi/iwl-debugfs.c b/drivers/net/wireless/iwlwifi/iwl-debugfs.c index 2c58980..9b1f962 100644 --- a/drivers/net/wireless/iwlwifi/iwl-debugfs.c +++ b/drivers/net/wireless/iwlwifi/iwl-debugfs.c @@ -1767,9 +1767,6 @@ int iwl_dbgfs_register(struct iwl_priv *priv, const char *name) if (priv->cfg->base_params->chain_noise_calib_by_driver) DEBUGFS_ADD_BOOL(disable_chain_noise, dir_rf, &priv->disable_chain_noise_cal); - if (priv->cfg->base_params->tx_power_by_driver) - DEBUGFS_ADD_BOOL(disable_tx_power, dir_rf, - &priv->disable_tx_power_cal); return 0; err: diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index 14f7d8f..7fe68f8 100644 --- a/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h @@ -1489,7 +1489,6 @@ struct iwl_priv { struct work_struct txpower_work; u32 disable_sens_cal; u32 disable_chain_noise_cal; - u32 disable_tx_power_cal; struct work_struct run_time_calib_work; struct timer_list statistics_periodic; struct timer_list ucode_trace; -- cgit v0.10.2 From 703bc583cb98a24eeedd297ee59dfa12852897d1 Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Sun, 3 Apr 2011 08:14:41 -0700 Subject: iwlagn: sensitivity and chain noise done by driver _agn driver should perform both sensitivity and chain noise calib. Signed-off-by: Wey-Yi Guy diff --git a/drivers/net/wireless/iwlwifi/iwl-1000.c b/drivers/net/wireless/iwlwifi/iwl-1000.c index 5a72810..d1d7852 100644 --- a/drivers/net/wireless/iwlwifi/iwl-1000.c +++ b/drivers/net/wireless/iwlwifi/iwl-1000.c @@ -245,8 +245,6 @@ static struct iwl_base_params iwl1000_base_params = { .wd_timeout = IWL_DEF_WD_TIMEOUT, .max_event_log_size = 128, .ucode_tracing = true, - .sensitivity_calib_by_driver = true, - .chain_noise_calib_by_driver = true, }; static struct iwl_ht_params iwl1000_ht_params = { .ht_greenfield_support = true, diff --git a/drivers/net/wireless/iwlwifi/iwl-2000.c b/drivers/net/wireless/iwlwifi/iwl-2000.c index 9daf888..805b039 100644 --- a/drivers/net/wireless/iwlwifi/iwl-2000.c +++ b/drivers/net/wireless/iwlwifi/iwl-2000.c @@ -354,8 +354,6 @@ static struct iwl_base_params iwl2000_base_params = { .wd_timeout = IWL_DEF_WD_TIMEOUT, .max_event_log_size = 512, .ucode_tracing = true, - .sensitivity_calib_by_driver = true, - .chain_noise_calib_by_driver = true, .shadow_reg_enable = true, }; @@ -376,8 +374,6 @@ static struct iwl_base_params iwl2030_base_params = { .wd_timeout = IWL_LONG_WD_TIMEOUT, .max_event_log_size = 512, .ucode_tracing = true, - .sensitivity_calib_by_driver = true, - .chain_noise_calib_by_driver = true, .shadow_reg_enable = true, }; diff --git a/drivers/net/wireless/iwlwifi/iwl-5000.c b/drivers/net/wireless/iwlwifi/iwl-5000.c index 8106423..357137f 100644 --- a/drivers/net/wireless/iwlwifi/iwl-5000.c +++ b/drivers/net/wireless/iwlwifi/iwl-5000.c @@ -471,8 +471,6 @@ static struct iwl_base_params iwl5000_base_params = { .wd_timeout = IWL_LONG_WD_TIMEOUT, .max_event_log_size = 512, .ucode_tracing = true, - .sensitivity_calib_by_driver = true, - .chain_noise_calib_by_driver = true, }; static struct iwl_ht_params iwl5000_ht_params = { .ht_greenfield_support = true, diff --git a/drivers/net/wireless/iwlwifi/iwl-6000.c b/drivers/net/wireless/iwlwifi/iwl-6000.c index 7f0715e..8847b21 100644 --- a/drivers/net/wireless/iwlwifi/iwl-6000.c +++ b/drivers/net/wireless/iwlwifi/iwl-6000.c @@ -443,8 +443,6 @@ static struct iwl_base_params iwl6000_base_params = { .wd_timeout = IWL_DEF_WD_TIMEOUT, .max_event_log_size = 512, .ucode_tracing = true, - .sensitivity_calib_by_driver = true, - .chain_noise_calib_by_driver = true, .shadow_reg_enable = true, }; @@ -464,8 +462,6 @@ static struct iwl_base_params iwl6050_base_params = { .wd_timeout = IWL_DEF_WD_TIMEOUT, .max_event_log_size = 1024, .ucode_tracing = true, - .sensitivity_calib_by_driver = true, - .chain_noise_calib_by_driver = true, .shadow_reg_enable = true, }; static struct iwl_base_params iwl6000_g2_base_params = { @@ -484,8 +480,6 @@ static struct iwl_base_params iwl6000_g2_base_params = { .wd_timeout = IWL_LONG_WD_TIMEOUT, .max_event_log_size = 512, .ucode_tracing = true, - .sensitivity_calib_by_driver = true, - .chain_noise_calib_by_driver = true, .shadow_reg_enable = true, }; diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h index 98dc544..57763c0 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.h +++ b/drivers/net/wireless/iwlwifi/iwl-core.h @@ -251,10 +251,6 @@ struct iwl_mod_params { * @temperature_kelvin: temperature report by uCode in kelvin * @max_event_log_size: size of event log buffer size for ucode event logging * @ucode_tracing: support ucode continuous tracing - * @sensitivity_calib_by_driver: driver has the capability to perform - * sensitivity calibration operation - * @chain_noise_calib_by_driver: driver has the capability to perform - * chain noise calibration operation * @shadow_reg_enable: HW shadhow register bit */ struct iwl_base_params { @@ -277,8 +273,6 @@ struct iwl_base_params { bool temperature_kelvin; u32 max_event_log_size; const bool ucode_tracing; - const bool sensitivity_calib_by_driver; - const bool chain_noise_calib_by_driver; const bool shadow_reg_enable; }; /* diff --git a/drivers/net/wireless/iwlwifi/iwl-debugfs.c b/drivers/net/wireless/iwlwifi/iwl-debugfs.c index 9b1f962..c02f069 100644 --- a/drivers/net/wireless/iwlwifi/iwl-debugfs.c +++ b/drivers/net/wireless/iwlwifi/iwl-debugfs.c @@ -1747,10 +1747,8 @@ int iwl_dbgfs_register(struct iwl_priv *priv, const char *name) DEBUGFS_ADD_FILE(txfifo_flush, dir_debug, S_IWUSR); DEBUGFS_ADD_FILE(protection_mode, dir_debug, S_IWUSR | S_IRUSR); - if (priv->cfg->base_params->sensitivity_calib_by_driver) - DEBUGFS_ADD_FILE(sensitivity, dir_debug, S_IRUSR); - if (priv->cfg->base_params->chain_noise_calib_by_driver) - DEBUGFS_ADD_FILE(chain_noise, dir_debug, S_IRUSR); + DEBUGFS_ADD_FILE(sensitivity, dir_debug, S_IRUSR); + DEBUGFS_ADD_FILE(chain_noise, dir_debug, S_IRUSR); if (priv->cfg->base_params->ucode_tracing) DEBUGFS_ADD_FILE(ucode_tracing, dir_debug, S_IWUSR | S_IRUSR); if (iwl_bt_statistics(priv)) @@ -1761,12 +1759,10 @@ int iwl_dbgfs_register(struct iwl_priv *priv, const char *name) DEBUGFS_ADD_FILE(wd_timeout, dir_debug, S_IWUSR); if (iwl_advanced_bt_coexist(priv)) DEBUGFS_ADD_FILE(bt_traffic, dir_debug, S_IRUSR); - if (priv->cfg->base_params->sensitivity_calib_by_driver) - DEBUGFS_ADD_BOOL(disable_sensitivity, dir_rf, - &priv->disable_sens_cal); - if (priv->cfg->base_params->chain_noise_calib_by_driver) - DEBUGFS_ADD_BOOL(disable_chain_noise, dir_rf, - &priv->disable_chain_noise_cal); + DEBUGFS_ADD_BOOL(disable_sensitivity, dir_rf, + &priv->disable_sens_cal); + DEBUGFS_ADD_BOOL(disable_chain_noise, dir_rf, + &priv->disable_chain_noise_cal); return 0; err: -- cgit v0.10.2 From 0da0e5bf1522d75d446f5124e17016628d0a149e Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 8 Apr 2011 08:14:56 -0700 Subject: iwlagn: clean up & autodetect statistics There's no need to keep both normal and BT statistics versions around all the time in memory when we only use a subset of both. So keep only the subsets that we need in memory, depending on the debug config). Also, in doing so, we can remove all the calls to iwl_bt_statistics() in the driver as we'll just access the copied statistics now. Finally, also remove this call from the one place where it might still be needed and automatically detect what kind of statistics the device is sending based on their size. This way, we don't need to keep track of which devices do what any more, which is good since this is subject to change based on the ucode version (as some ucode even for non-BT devices will in fact use BT statistics). Warn upon encountering a statistics command from the ucode that isn't known, so we will find such issues earlier in the future. Signed-off-by: Johannes Berg Tested-by: Don Fry Signed-off-by: Wey-Yi Guy diff --git a/drivers/net/wireless/iwlwifi/iwl-2000.c b/drivers/net/wireless/iwlwifi/iwl-2000.c index 805b039..a31314f 100644 --- a/drivers/net/wireless/iwlwifi/iwl-2000.c +++ b/drivers/net/wireless/iwlwifi/iwl-2000.c @@ -383,7 +383,6 @@ static struct iwl_ht_params iwl2000_ht_params = { }; static struct iwl_bt_params iwl2030_bt_params = { - .bt_statistics = true, /* Due to bluetooth, we transmit 2.4 GHz probes only on antenna A */ .advanced_bt_coexist = true, .agg_time_limit = BT_AGG_THRESHOLD_DEF, diff --git a/drivers/net/wireless/iwlwifi/iwl-5000.c b/drivers/net/wireless/iwlwifi/iwl-5000.c index 357137f..7c28666 100644 --- a/drivers/net/wireless/iwlwifi/iwl-5000.c +++ b/drivers/net/wireless/iwlwifi/iwl-5000.c @@ -259,7 +259,7 @@ static void iwl5150_temperature(struct iwl_priv *priv) u32 vt = 0; s32 offset = iwl_temp_calib_to_offset(priv); - vt = le32_to_cpu(priv->_agn.statistics.general.common.temperature); + vt = le32_to_cpu(priv->statistics.common.temperature); vt = vt / IWL_5150_VOLTAGE_TO_TEMPERATURE_COEFF + offset; /* now vt hold the temperature in Kelvin */ priv->temperature = KELVIN_TO_CELSIUS(vt); diff --git a/drivers/net/wireless/iwlwifi/iwl-6000.c b/drivers/net/wireless/iwlwifi/iwl-6000.c index 8847b21..0649813 100644 --- a/drivers/net/wireless/iwlwifi/iwl-6000.c +++ b/drivers/net/wireless/iwlwifi/iwl-6000.c @@ -489,7 +489,6 @@ static struct iwl_ht_params iwl6000_ht_params = { }; static struct iwl_bt_params iwl6000_bt_params = { - .bt_statistics = true, /* Due to bluetooth, we transmit 2.4 GHz probes only on antenna A */ .advanced_bt_coexist = true, .agg_time_limit = BT_AGG_THRESHOLD_DEF, diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-calib.c b/drivers/net/wireless/iwlwifi/iwl-agn-calib.c index 7b761de..0f6bb9b 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-calib.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-calib.c @@ -605,7 +605,7 @@ void iwl_init_sensitivity(struct iwl_priv *priv) IWL_DEBUG_CALIB(priv, "<lock, flags); - if (iwl_bt_statistics(priv)) { - rx_info = &(((struct iwl_bt_notif_statistics *)resp)-> - rx.general.common); - ofdm = &(((struct iwl_bt_notif_statistics *)resp)->rx.ofdm); - cck = &(((struct iwl_bt_notif_statistics *)resp)->rx.cck); - } else { - rx_info = &(((struct iwl_notif_statistics *)resp)->rx.general); - ofdm = &(((struct iwl_notif_statistics *)resp)->rx.ofdm); - cck = &(((struct iwl_notif_statistics *)resp)->rx.cck); - } + rx_info = &priv->statistics.rx_non_phy; + ofdm = &priv->statistics.rx_ofdm; + cck = &priv->statistics.rx_cck; if (rx_info->interference_data_flag != INTERFERENCE_DATA_AVAILABLE) { IWL_DEBUG_CALIB(priv, "<< invalid data.\n"); spin_unlock_irqrestore(&priv->lock, flags); @@ -851,7 +844,7 @@ static void iwl_find_disconn_antenna(struct iwl_priv *priv, u32* average_sig, * 1) Which antennas are connected. * 2) Differential rx gain settings to balance the 3 receivers. */ -void iwl_chain_noise_calibration(struct iwl_priv *priv, void *stat_resp) +void iwl_chain_noise_calibration(struct iwl_priv *priv) { struct iwl_chain_noise_data *data = NULL; @@ -896,13 +889,9 @@ void iwl_chain_noise_calibration(struct iwl_priv *priv, void *stat_resp) } spin_lock_irqsave(&priv->lock, flags); - if (iwl_bt_statistics(priv)) { - rx_info = &(((struct iwl_bt_notif_statistics *)stat_resp)-> - rx.general.common); - } else { - rx_info = &(((struct iwl_notif_statistics *)stat_resp)-> - rx.general); - } + + rx_info = &priv->statistics.rx_non_phy; + if (rx_info->interference_data_flag != INTERFERENCE_DATA_AVAILABLE) { IWL_DEBUG_CALIB(priv, " << Interference data unavailable\n"); spin_unlock_irqrestore(&priv->lock, flags); @@ -911,19 +900,9 @@ void iwl_chain_noise_calibration(struct iwl_priv *priv, void *stat_resp) rxon_band24 = !!(ctx->staging.flags & RXON_FLG_BAND_24G_MSK); rxon_chnum = le16_to_cpu(ctx->staging.channel); - if (iwl_bt_statistics(priv)) { - stat_band24 = !!(((struct iwl_bt_notif_statistics *) - stat_resp)->flag & - STATISTICS_REPLY_FLG_BAND_24G_MSK); - stat_chnum = le32_to_cpu(((struct iwl_bt_notif_statistics *) - stat_resp)->flag) >> 16; - } else { - stat_band24 = !!(((struct iwl_notif_statistics *) - stat_resp)->flag & - STATISTICS_REPLY_FLG_BAND_24G_MSK); - stat_chnum = le32_to_cpu(((struct iwl_notif_statistics *) - stat_resp)->flag) >> 16; - } + stat_band24 = + !!(priv->statistics.flag & STATISTICS_REPLY_FLG_BAND_24G_MSK); + stat_chnum = le32_to_cpu(priv->statistics.flag) >> 16; /* Make sure we accumulate data for just the associated channel * (even if scanning). */ diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-calib.h b/drivers/net/wireless/iwlwifi/iwl-agn-calib.h index ef4d507..4ef4dd9 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-calib.h +++ b/drivers/net/wireless/iwlwifi/iwl-agn-calib.h @@ -66,8 +66,8 @@ #include "iwl-core.h" #include "iwl-commands.h" -void iwl_chain_noise_calibration(struct iwl_priv *priv, void *stat_resp); -void iwl_sensitivity_calibration(struct iwl_priv *priv, void *resp); +void iwl_chain_noise_calibration(struct iwl_priv *priv); +void iwl_sensitivity_calibration(struct iwl_priv *priv); void iwl_init_sensitivity(struct iwl_priv *priv); void iwl_reset_run_time_calib(struct iwl_priv *priv); diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-debugfs.c b/drivers/net/wireless/iwlwifi/iwl-agn-debugfs.c index d1834aa..71a5f31 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-debugfs.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-debugfs.c @@ -39,10 +39,7 @@ static int iwl_statistics_flag(struct iwl_priv *priv, char *buf, int bufsz) int p = 0; u32 flag; - if (iwl_bt_statistics(priv)) - flag = le32_to_cpu(priv->_agn.statistics_bt.flag); - else - flag = le32_to_cpu(priv->_agn.statistics.flag); + flag = le32_to_cpu(priv->statistics.flag); p += scnprintf(buf + p, bufsz - p, "Statistics Flag(0x%X):\n", flag); if (flag & UCODE_STATISTICS_CLEAR_MSK) @@ -88,43 +85,22 @@ ssize_t iwl_ucode_rx_stats_read(struct file *file, char __user *user_buf, * the last statistics notification from uCode * might not reflect the current uCode activity */ - if (iwl_bt_statistics(priv)) { - ofdm = &priv->_agn.statistics_bt.rx.ofdm; - cck = &priv->_agn.statistics_bt.rx.cck; - general = &priv->_agn.statistics_bt.rx.general.common; - ht = &priv->_agn.statistics_bt.rx.ofdm_ht; - accum_ofdm = &priv->_agn.accum_statistics_bt.rx.ofdm; - accum_cck = &priv->_agn.accum_statistics_bt.rx.cck; - accum_general = - &priv->_agn.accum_statistics_bt.rx.general.common; - accum_ht = &priv->_agn.accum_statistics_bt.rx.ofdm_ht; - delta_ofdm = &priv->_agn.delta_statistics_bt.rx.ofdm; - delta_cck = &priv->_agn.delta_statistics_bt.rx.cck; - delta_general = - &priv->_agn.delta_statistics_bt.rx.general.common; - delta_ht = &priv->_agn.delta_statistics_bt.rx.ofdm_ht; - max_ofdm = &priv->_agn.max_delta_bt.rx.ofdm; - max_cck = &priv->_agn.max_delta_bt.rx.cck; - max_general = &priv->_agn.max_delta_bt.rx.general.common; - max_ht = &priv->_agn.max_delta_bt.rx.ofdm_ht; - } else { - ofdm = &priv->_agn.statistics.rx.ofdm; - cck = &priv->_agn.statistics.rx.cck; - general = &priv->_agn.statistics.rx.general; - ht = &priv->_agn.statistics.rx.ofdm_ht; - accum_ofdm = &priv->_agn.accum_statistics.rx.ofdm; - accum_cck = &priv->_agn.accum_statistics.rx.cck; - accum_general = &priv->_agn.accum_statistics.rx.general; - accum_ht = &priv->_agn.accum_statistics.rx.ofdm_ht; - delta_ofdm = &priv->_agn.delta_statistics.rx.ofdm; - delta_cck = &priv->_agn.delta_statistics.rx.cck; - delta_general = &priv->_agn.delta_statistics.rx.general; - delta_ht = &priv->_agn.delta_statistics.rx.ofdm_ht; - max_ofdm = &priv->_agn.max_delta.rx.ofdm; - max_cck = &priv->_agn.max_delta.rx.cck; - max_general = &priv->_agn.max_delta.rx.general; - max_ht = &priv->_agn.max_delta.rx.ofdm_ht; - } + ofdm = &priv->statistics.rx_ofdm; + cck = &priv->statistics.rx_cck; + general = &priv->statistics.rx_non_phy; + ht = &priv->statistics.rx_ofdm_ht; + accum_ofdm = &priv->accum_stats.rx_ofdm; + accum_cck = &priv->accum_stats.rx_cck; + accum_general = &priv->accum_stats.rx_non_phy; + accum_ht = &priv->accum_stats.rx_ofdm_ht; + delta_ofdm = &priv->delta_stats.rx_ofdm; + delta_cck = &priv->delta_stats.rx_cck; + delta_general = &priv->delta_stats.rx_non_phy; + delta_ht = &priv->delta_stats.rx_ofdm_ht; + max_ofdm = &priv->max_delta_stats.rx_ofdm; + max_cck = &priv->max_delta_stats.rx_cck; + max_general = &priv->max_delta_stats.rx_non_phy; + max_ht = &priv->max_delta_stats.rx_ofdm_ht; pos += iwl_statistics_flag(priv, buf, bufsz); pos += scnprintf(buf + pos, bufsz - pos, @@ -531,20 +507,13 @@ ssize_t iwl_ucode_tx_stats_read(struct file *file, } /* the statistic information display here is based on - * the last statistics notification from uCode - * might not reflect the current uCode activity - */ - if (iwl_bt_statistics(priv)) { - tx = &priv->_agn.statistics_bt.tx; - accum_tx = &priv->_agn.accum_statistics_bt.tx; - delta_tx = &priv->_agn.delta_statistics_bt.tx; - max_tx = &priv->_agn.max_delta_bt.tx; - } else { - tx = &priv->_agn.statistics.tx; - accum_tx = &priv->_agn.accum_statistics.tx; - delta_tx = &priv->_agn.delta_statistics.tx; - max_tx = &priv->_agn.max_delta.tx; - } + * the last statistics notification from uCode + * might not reflect the current uCode activity + */ + tx = &priv->statistics.tx; + accum_tx = &priv->accum_stats.tx; + delta_tx = &priv->delta_stats.tx; + max_tx = &priv->max_delta_stats.tx; pos += iwl_statistics_flag(priv, buf, bufsz); pos += scnprintf(buf + pos, bufsz - pos, @@ -731,36 +700,21 @@ ssize_t iwl_ucode_general_stats_read(struct file *file, char __user *user_buf, } /* the statistic information display here is based on - * the last statistics notification from uCode - * might not reflect the current uCode activity - */ - if (iwl_bt_statistics(priv)) { - general = &priv->_agn.statistics_bt.general.common; - dbg = &priv->_agn.statistics_bt.general.common.dbg; - div = &priv->_agn.statistics_bt.general.common.div; - accum_general = &priv->_agn.accum_statistics_bt.general.common; - accum_dbg = &priv->_agn.accum_statistics_bt.general.common.dbg; - accum_div = &priv->_agn.accum_statistics_bt.general.common.div; - delta_general = &priv->_agn.delta_statistics_bt.general.common; - max_general = &priv->_agn.max_delta_bt.general.common; - delta_dbg = &priv->_agn.delta_statistics_bt.general.common.dbg; - max_dbg = &priv->_agn.max_delta_bt.general.common.dbg; - delta_div = &priv->_agn.delta_statistics_bt.general.common.div; - max_div = &priv->_agn.max_delta_bt.general.common.div; - } else { - general = &priv->_agn.statistics.general.common; - dbg = &priv->_agn.statistics.general.common.dbg; - div = &priv->_agn.statistics.general.common.div; - accum_general = &priv->_agn.accum_statistics.general.common; - accum_dbg = &priv->_agn.accum_statistics.general.common.dbg; - accum_div = &priv->_agn.accum_statistics.general.common.div; - delta_general = &priv->_agn.delta_statistics.general.common; - max_general = &priv->_agn.max_delta.general.common; - delta_dbg = &priv->_agn.delta_statistics.general.common.dbg; - max_dbg = &priv->_agn.max_delta.general.common.dbg; - delta_div = &priv->_agn.delta_statistics.general.common.div; - max_div = &priv->_agn.max_delta.general.common.div; - } + * the last statistics notification from uCode + * might not reflect the current uCode activity + */ + general = &priv->statistics.common; + dbg = &priv->statistics.common.dbg; + div = &priv->statistics.common.div; + accum_general = &priv->accum_stats.common; + accum_dbg = &priv->accum_stats.common.dbg; + accum_div = &priv->accum_stats.common.div; + delta_general = &priv->delta_stats.common; + max_general = &priv->max_delta_stats.common; + delta_dbg = &priv->delta_stats.common.dbg; + max_dbg = &priv->max_delta_stats.common.dbg; + delta_div = &priv->delta_stats.common.div; + max_div = &priv->max_delta_stats.common.div; pos += iwl_statistics_flag(priv, buf, bufsz); pos += scnprintf(buf + pos, bufsz - pos, @@ -876,8 +830,8 @@ ssize_t iwl_ucode_bt_stats_read(struct file *file, * the last statistics notification from uCode * might not reflect the current uCode activity */ - bt = &priv->_agn.statistics_bt.general.activity; - accum_bt = &priv->_agn.accum_statistics_bt.general.activity; + bt = &priv->statistics.bt_activity; + accum_bt = &priv->accum_stats.bt_activity; pos += iwl_statistics_flag(priv, buf, bufsz); pos += scnprintf(buf + pos, bufsz - pos, "Statistics_BT:\n"); @@ -918,10 +872,8 @@ ssize_t iwl_ucode_bt_stats_read(struct file *file, pos += scnprintf(buf + pos, bufsz - pos, "(rx)num_bt_kills:\t\t%u\t\t\t%u\n", - le32_to_cpu(priv->_agn.statistics_bt.rx. - general.num_bt_kills), - priv->_agn.accum_statistics_bt.rx. - general.num_bt_kills); + le32_to_cpu(priv->statistics.num_bt_kills), + priv->statistics.accum_num_bt_kills); ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos); kfree(buf); diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-lib.c b/drivers/net/wireless/iwlwifi/iwl-agn-lib.c index bc5dfe2..e741128 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-lib.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-lib.c @@ -549,9 +549,7 @@ int iwlagn_send_tx_power(struct iwl_priv *priv) void iwlagn_temperature(struct iwl_priv *priv) { /* store temperature from correct statistics (in Celsius) */ - priv->temperature = le32_to_cpu((iwl_bt_statistics(priv)) ? - priv->_agn.statistics_bt.general.common.temperature : - priv->_agn.statistics.general.common.temperature); + priv->temperature = le32_to_cpu(priv->statistics.common.temperature); iwl_tt_handler(priv); } diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index 23b89c2..20499b7 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -1705,10 +1705,6 @@ static void iwl_ucode_callback(const struct firmware *ucode_raw, void *context) else priv->cmd_queue = IWL_DEFAULT_CMD_QUEUE_NUM; - if (ucode_capa.flags & IWL_UCODE_TLV_FLAGS_BTSTATS || - (priv->cfg->bt_params && priv->cfg->bt_params->bt_statistics)) - priv->bt_statistics = true; - /* Copy images into buffers for card's bus-master reads ... */ /* Runtime instructions (first block of data in file) */ @@ -2626,17 +2622,8 @@ static void iwl_bg_run_time_calib_work(struct work_struct *work) } if (priv->start_calib) { - if (iwl_bt_statistics(priv)) { - iwl_chain_noise_calibration(priv, - (void *)&priv->_agn.statistics_bt); - iwl_sensitivity_calibration(priv, - (void *)&priv->_agn.statistics_bt); - } else { - iwl_chain_noise_calibration(priv, - (void *)&priv->_agn.statistics); - iwl_sensitivity_calibration(priv, - (void *)&priv->_agn.statistics); - } + iwl_chain_noise_calibration(priv); + iwl_sensitivity_calibration(priv); } mutex_unlock(&priv->mutex); diff --git a/drivers/net/wireless/iwlwifi/iwl-commands.h b/drivers/net/wireless/iwlwifi/iwl-commands.h index a1a5c1b..0edba8a 100644 --- a/drivers/net/wireless/iwlwifi/iwl-commands.h +++ b/drivers/net/wireless/iwlwifi/iwl-commands.h @@ -2535,53 +2535,6 @@ struct rate_histogram { /* statistics command response */ -struct iwl39_statistics_rx_phy { - __le32 ina_cnt; - __le32 fina_cnt; - __le32 plcp_err; - __le32 crc32_err; - __le32 overrun_err; - __le32 early_overrun_err; - __le32 crc32_good; - __le32 false_alarm_cnt; - __le32 fina_sync_err_cnt; - __le32 sfd_timeout; - __le32 fina_timeout; - __le32 unresponded_rts; - __le32 rxe_frame_limit_overrun; - __le32 sent_ack_cnt; - __le32 sent_cts_cnt; -} __packed; - -struct iwl39_statistics_rx_non_phy { - __le32 bogus_cts; /* CTS received when not expecting CTS */ - __le32 bogus_ack; /* ACK received when not expecting ACK */ - __le32 non_bssid_frames; /* number of frames with BSSID that - * doesn't belong to the STA BSSID */ - __le32 filtered_frames; /* count frames that were dumped in the - * filtering process */ - __le32 non_channel_beacons; /* beacons with our bss id but not on - * our serving channel */ -} __packed; - -struct iwl39_statistics_rx { - struct iwl39_statistics_rx_phy ofdm; - struct iwl39_statistics_rx_phy cck; - struct iwl39_statistics_rx_non_phy general; -} __packed; - -struct iwl39_statistics_tx { - __le32 preamble_cnt; - __le32 rx_detected_cnt; - __le32 bt_prio_defer_cnt; - __le32 bt_prio_kill_cnt; - __le32 few_bytes_cnt; - __le32 cts_timeout; - __le32 ack_timeout; - __le32 expected_ack_cnt; - __le32 actual_ack_cnt; -} __packed; - struct statistics_dbg { __le32 burst_check; __le32 burst_count; @@ -2589,23 +2542,6 @@ struct statistics_dbg { __le32 reserved[3]; } __packed; -struct iwl39_statistics_div { - __le32 tx_on_a; - __le32 tx_on_b; - __le32 exec_time; - __le32 probe_time; -} __packed; - -struct iwl39_statistics_general { - __le32 temperature; - struct statistics_dbg dbg; - __le32 sleep_time; - __le32 slots_out; - __le32 slots_idle; - __le32 ttl_timestamp; - struct iwl39_statistics_div div; -} __packed; - struct statistics_rx_phy { __le32 ina_cnt; __le32 fina_cnt; diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h index 57763c0..6988335 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.h +++ b/drivers/net/wireless/iwlwifi/iwl-core.h @@ -279,7 +279,6 @@ struct iwl_base_params { * @advanced_bt_coexist: support advanced bt coexist * @bt_init_traffic_load: specify initial bt traffic load * @bt_prio_boost: default bt priority boost value - * @bt_statistics: use BT version of statistics notification * @agg_time_limit: maximum number of uSec in aggregation * @ampdu_factor: Maximum A-MPDU length factor * @ampdu_density: Minimum A-MPDU spacing @@ -289,7 +288,6 @@ struct iwl_bt_params { bool advanced_bt_coexist; u8 bt_init_traffic_load; u8 bt_prio_boost; - const bool bt_statistics; u16 agg_time_limit; u8 ampdu_factor; u8 ampdu_density; @@ -696,11 +694,6 @@ static inline bool iwl_advanced_bt_coexist(struct iwl_priv *priv) priv->cfg->bt_params->advanced_bt_coexist; } -static inline bool iwl_bt_statistics(struct iwl_priv *priv) -{ - return priv->bt_statistics; -} - extern bool bt_coex_active; extern bool bt_siso_mode; diff --git a/drivers/net/wireless/iwlwifi/iwl-debugfs.c b/drivers/net/wireless/iwlwifi/iwl-debugfs.c index c02f069..897efac 100644 --- a/drivers/net/wireless/iwlwifi/iwl-debugfs.c +++ b/drivers/net/wireless/iwlwifi/iwl-debugfs.c @@ -1751,8 +1751,7 @@ int iwl_dbgfs_register(struct iwl_priv *priv, const char *name) DEBUGFS_ADD_FILE(chain_noise, dir_debug, S_IRUSR); if (priv->cfg->base_params->ucode_tracing) DEBUGFS_ADD_FILE(ucode_tracing, dir_debug, S_IWUSR | S_IRUSR); - if (iwl_bt_statistics(priv)) - DEBUGFS_ADD_FILE(ucode_bt_stats, dir_debug, S_IRUSR); + DEBUGFS_ADD_FILE(ucode_bt_stats, dir_debug, S_IRUSR); DEBUGFS_ADD_FILE(reply_tx_error, dir_debug, S_IRUSR); DEBUGFS_ADD_FILE(rxon_flags, dir_debug, S_IWUSR); DEBUGFS_ADD_FILE(rxon_filter_flags, dir_debug, S_IWUSR); diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index 7fe68f8..e84534c 100644 --- a/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h @@ -543,13 +543,12 @@ enum iwl_ucode_tlv_type { * enum iwl_ucode_tlv_flag - ucode API flags * @IWL_UCODE_TLV_FLAGS_PAN: This is PAN capable microcode; this previously * was a separate TLV but moved here to save space. - * @IWL_UCODE_TLV_FLAGS_BTSTATS: This uCode image uses BT statistics, which - * may be true even if the device doesn't have BT. + * @IWL_UCODE_TLV_FLAGS_RESERVED_1: reserved * @IWL_UCODE_TLV_FLAGS_MFP: This uCode image supports MFP (802.11w). */ enum iwl_ucode_tlv_flag { IWL_UCODE_TLV_FLAGS_PAN = BIT(0), - IWL_UCODE_TLV_FLAGS_BTSTATS = BIT(1), + IWL_UCODE_TLV_FLAGS_RESERVED_1 = BIT(1), IWL_UCODE_TLV_FLAGS_MFP = BIT(2), }; @@ -1357,6 +1356,31 @@ struct iwl_priv { u64 timestamp; struct { + __le32 flag; + struct statistics_general_common common; + struct statistics_rx_non_phy rx_non_phy; + struct statistics_rx_phy rx_ofdm; + struct statistics_rx_ht_phy rx_ofdm_ht; + struct statistics_rx_phy rx_cck; + struct statistics_tx tx; +#ifdef CONFIG_IWLWIFI_DEBUGFS + struct statistics_bt_activity bt_activity; + __le32 num_bt_kills, accum_num_bt_kills; +#endif + } statistics; +#ifdef CONFIG_IWLWIFI_DEBUGFS + struct { + struct statistics_general_common common; + struct statistics_rx_non_phy rx_non_phy; + struct statistics_rx_phy rx_ofdm; + struct statistics_rx_ht_phy rx_ofdm_ht; + struct statistics_rx_phy rx_cck; + struct statistics_tx tx; + struct statistics_bt_activity bt_activity; + } accum_stats, delta_stats, max_delta_stats; +#endif + + struct { /* INT ICT Table */ __le32 *ict_tbl; void *ict_tbl_vir; @@ -1387,19 +1411,9 @@ struct iwl_priv { u8 phy_calib_chain_noise_reset_cmd; u8 phy_calib_chain_noise_gain_cmd; - struct iwl_notif_statistics statistics; - struct iwl_bt_notif_statistics statistics_bt; /* counts reply_tx error */ struct reply_tx_error_statistics reply_tx_stats; struct reply_agg_tx_error_statistics reply_agg_tx_stats; -#ifdef CONFIG_IWLWIFI_DEBUGFS - struct iwl_notif_statistics accum_statistics; - struct iwl_notif_statistics delta_statistics; - struct iwl_notif_statistics max_delta; - struct iwl_bt_notif_statistics accum_statistics_bt; - struct iwl_bt_notif_statistics delta_statistics_bt; - struct iwl_bt_notif_statistics max_delta_bt; -#endif /* notification wait support */ struct list_head notif_waits; spinlock_t notif_wait_lock; @@ -1424,7 +1438,6 @@ struct iwl_priv { bool bt_ch_announce; bool bt_full_concurrent; bool bt_ant_couple_ok; - bool bt_statistics; __le32 kill_ack_mask; __le32 kill_cts_mask; __le16 bt_valid; diff --git a/drivers/net/wireless/iwlwifi/iwl-rx.c b/drivers/net/wireless/iwlwifi/iwl-rx.c index 4472761..b49819c 100644 --- a/drivers/net/wireless/iwlwifi/iwl-rx.c +++ b/drivers/net/wireless/iwlwifi/iwl-rx.c @@ -390,21 +390,16 @@ static void iwl_rx_beacon_notif(struct iwl_priv *priv, * the BA_TIMEOUT_MAX, reload firmware and bring system back to normal * operation state. */ -static bool iwl_good_ack_health(struct iwl_priv *priv, struct iwl_rx_packet *pkt) +static bool iwl_good_ack_health(struct iwl_priv *priv, + struct statistics_tx *cur) { int actual_delta, expected_delta, ba_timeout_delta; - struct statistics_tx *cur, *old; + struct statistics_tx *old; if (priv->_agn.agg_tids_count) return true; - if (iwl_bt_statistics(priv)) { - cur = &pkt->u.stats_bt.tx; - old = &priv->_agn.statistics_bt.tx; - } else { - cur = &pkt->u.stats.tx; - old = &priv->_agn.statistics.tx; - } + old = &priv->statistics.tx; actual_delta = le32_to_cpu(cur->actual_ack_cnt) - le32_to_cpu(old->actual_ack_cnt); @@ -430,10 +425,10 @@ static bool iwl_good_ack_health(struct iwl_priv *priv, struct iwl_rx_packet *pkt * DEBUG is not, these will just compile out. */ IWL_DEBUG_RADIO(priv, "rx_detected_cnt delta %d\n", - priv->_agn.delta_statistics.tx.rx_detected_cnt); + priv->delta_stats.tx.rx_detected_cnt); IWL_DEBUG_RADIO(priv, "ack_or_ba_timeout_collision delta %d\n", - priv->_agn.delta_statistics.tx.ack_or_ba_timeout_collision); + priv->delta_stats.tx.ack_or_ba_timeout_collision); #endif if (ba_timeout_delta >= BA_TIMEOUT_MAX) @@ -450,7 +445,9 @@ static bool iwl_good_ack_health(struct iwl_priv *priv, struct iwl_rx_packet *pkt * to improve the throughput. */ static bool iwl_good_plcp_health(struct iwl_priv *priv, - struct iwl_rx_packet *pkt, unsigned int msecs) + struct statistics_rx_phy *cur_ofdm, + struct statistics_rx_ht_phy *cur_ofdm_ht, + unsigned int msecs) { int delta; int threshold = priv->cfg->base_params->plcp_delta_threshold; @@ -460,29 +457,12 @@ static bool iwl_good_plcp_health(struct iwl_priv *priv, return true; } - if (iwl_bt_statistics(priv)) { - struct statistics_rx_bt *cur, *old; - - cur = &pkt->u.stats_bt.rx; - old = &priv->_agn.statistics_bt.rx; - - delta = le32_to_cpu(cur->ofdm.plcp_err) - - le32_to_cpu(old->ofdm.plcp_err) + - le32_to_cpu(cur->ofdm_ht.plcp_err) - - le32_to_cpu(old->ofdm_ht.plcp_err); - } else { - struct statistics_rx *cur, *old; - - cur = &pkt->u.stats.rx; - old = &priv->_agn.statistics.rx; - - delta = le32_to_cpu(cur->ofdm.plcp_err) - - le32_to_cpu(old->ofdm.plcp_err) + - le32_to_cpu(cur->ofdm_ht.plcp_err) - - le32_to_cpu(old->ofdm_ht.plcp_err); - } + delta = le32_to_cpu(cur_ofdm->plcp_err) - + le32_to_cpu(priv->statistics.rx_ofdm.plcp_err) + + le32_to_cpu(cur_ofdm_ht->plcp_err) - + le32_to_cpu(priv->statistics.rx_ofdm_ht.plcp_err); - /* Can be negative if firmware reseted statistics */ + /* Can be negative if firmware reset statistics */ if (delta <= 0) return true; @@ -497,44 +477,36 @@ static bool iwl_good_plcp_health(struct iwl_priv *priv, } static void iwl_recover_from_statistics(struct iwl_priv *priv, - struct iwl_rx_packet *pkt) + struct statistics_rx_phy *cur_ofdm, + struct statistics_rx_ht_phy *cur_ofdm_ht, + struct statistics_tx *tx, + unsigned long stamp) { const struct iwl_mod_params *mod_params = priv->cfg->mod_params; unsigned int msecs; - unsigned long stamp; if (test_bit(STATUS_EXIT_PENDING, &priv->status)) return; - stamp = jiffies; msecs = jiffies_to_msecs(stamp - priv->rx_statistics_jiffies); /* Only gather statistics and update time stamp when not associated */ if (!iwl_is_any_associated(priv)) - goto out; + return; /* Do not check/recover when do not have enough statistics data */ if (msecs < 99) return; - if (mod_params->ack_check && !iwl_good_ack_health(priv, pkt)) { + if (mod_params->ack_check && !iwl_good_ack_health(priv, tx)) { IWL_ERR(priv, "low ack count detected, restart firmware\n"); if (!iwl_force_reset(priv, IWL_FW_RESET, false)) return; } - if (mod_params->plcp_check && !iwl_good_plcp_health(priv, pkt, msecs)) + if (mod_params->plcp_check && + !iwl_good_plcp_health(priv, cur_ofdm, cur_ofdm_ht, msecs)) iwl_force_reset(priv, IWL_RF_RESET, false); - -out: - if (iwl_bt_statistics(priv)) - memcpy(&priv->_agn.statistics_bt, &pkt->u.stats_bt, - sizeof(priv->_agn.statistics_bt)); - else - memcpy(&priv->_agn.statistics, &pkt->u.stats, - sizeof(priv->_agn.statistics)); - - priv->rx_statistics_jiffies = stamp; } /* Calculate noise level, based on measurements during network silence just @@ -548,10 +520,8 @@ static void iwl_rx_calc_noise(struct iwl_priv *priv) int bcn_silence_a, bcn_silence_b, bcn_silence_c; int last_rx_noise; - if (iwl_bt_statistics(priv)) - rx_info = &(priv->_agn.statistics_bt.rx.general.common); - else - rx_info = &(priv->_agn.statistics.rx.general); + rx_info = &priv->statistics.rx_non_phy; + bcn_silence_a = le32_to_cpu(rx_info->beacon_silence_rssi_a) & IN_BAND_FILTER; bcn_silence_b = @@ -583,105 +553,153 @@ static void iwl_rx_calc_noise(struct iwl_priv *priv) last_rx_noise); } +#ifdef CONFIG_IWLWIFI_DEBUGFS /* * based on the assumption of all statistics counter are in DWORD * FIXME: This function is for debugging, do not deal with * the case of counters roll-over. */ -static void iwl_accumulative_statistics(struct iwl_priv *priv, - __le32 *stats) +static void accum_stats(__le32 *prev, __le32 *cur, __le32 *delta, + __le32 *max_delta, __le32 *accum, int size) { -#ifdef CONFIG_IWLWIFI_DEBUGFS - int i, size; - __le32 *prev_stats; - u32 *accum_stats; - u32 *delta, *max_delta; - struct statistics_general_common *general, *accum_general; - struct statistics_tx *tx, *accum_tx; - - if (iwl_bt_statistics(priv)) { - prev_stats = (__le32 *)&priv->_agn.statistics_bt; - accum_stats = (u32 *)&priv->_agn.accum_statistics_bt; - size = sizeof(struct iwl_bt_notif_statistics); - general = &priv->_agn.statistics_bt.general.common; - accum_general = &priv->_agn.accum_statistics_bt.general.common; - tx = &priv->_agn.statistics_bt.tx; - accum_tx = &priv->_agn.accum_statistics_bt.tx; - delta = (u32 *)&priv->_agn.delta_statistics_bt; - max_delta = (u32 *)&priv->_agn.max_delta_bt; - } else { - prev_stats = (__le32 *)&priv->_agn.statistics; - accum_stats = (u32 *)&priv->_agn.accum_statistics; - size = sizeof(struct iwl_notif_statistics); - general = &priv->_agn.statistics.general.common; - accum_general = &priv->_agn.accum_statistics.general.common; - tx = &priv->_agn.statistics.tx; - accum_tx = &priv->_agn.accum_statistics.tx; - delta = (u32 *)&priv->_agn.delta_statistics; - max_delta = (u32 *)&priv->_agn.max_delta; - } - for (i = sizeof(__le32); i < size; - i += sizeof(__le32), stats++, prev_stats++, delta++, - max_delta++, accum_stats++) { - if (le32_to_cpu(*stats) > le32_to_cpu(*prev_stats)) { - *delta = (le32_to_cpu(*stats) - - le32_to_cpu(*prev_stats)); - *accum_stats += *delta; - if (*delta > *max_delta) + int i; + + for (i = 0; + i < size / sizeof(__le32); + i++, prev++, cur++, delta++, max_delta++, accum++) { + if (le32_to_cpu(*cur) > le32_to_cpu(*prev)) { + *delta = cpu_to_le32( + le32_to_cpu(*cur) - le32_to_cpu(*prev)); + le32_add_cpu(accum, le32_to_cpu(*delta)); + if (le32_to_cpu(*delta) > le32_to_cpu(*max_delta)) *max_delta = *delta; } } +} - /* reset accumulative statistics for "no-counter" type statistics */ - accum_general->temperature = general->temperature; - accum_general->temperature_m = general->temperature_m; - accum_general->ttl_timestamp = general->ttl_timestamp; - accum_tx->tx_power.ant_a = tx->tx_power.ant_a; - accum_tx->tx_power.ant_b = tx->tx_power.ant_b; - accum_tx->tx_power.ant_c = tx->tx_power.ant_c; -#endif +static void +iwl_accumulative_statistics(struct iwl_priv *priv, + struct statistics_general_common *common, + struct statistics_rx_non_phy *rx_non_phy, + struct statistics_rx_phy *rx_ofdm, + struct statistics_rx_ht_phy *rx_ofdm_ht, + struct statistics_rx_phy *rx_cck, + struct statistics_tx *tx, + struct statistics_bt_activity *bt_activity) +{ +#define ACCUM(_name) \ + accum_stats((__le32 *)&priv->statistics._name, \ + (__le32 *)_name, \ + (__le32 *)&priv->delta_stats._name, \ + (__le32 *)&priv->max_delta_stats._name, \ + (__le32 *)&priv->accum_stats._name, \ + sizeof(*_name)); + + ACCUM(common); + ACCUM(rx_non_phy); + ACCUM(rx_ofdm); + ACCUM(rx_ofdm_ht); + ACCUM(rx_cck); + ACCUM(tx); + if (bt_activity) + ACCUM(bt_activity); +#undef ACCUM } +#else +static inline void +iwl_accumulative_statistics(struct iwl_priv *priv, + struct statistics_general_common *common, + struct statistics_rx_non_phy *rx_non_phy, + struct statistics_rx_phy *rx_ofdm, + struct statistics_rx_ht_phy *rx_ofdm_ht, + struct statistics_rx_phy *rx_cck, + struct statistics_tx *tx, + struct statistics_bt_activity *bt_activity) +{ +} +#endif static void iwl_rx_statistics(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb) { + unsigned long stamp = jiffies; const int reg_recalib_period = 60; int change; struct iwl_rx_packet *pkt = rxb_addr(rxb); + u32 len = le32_to_cpu(pkt->len_n_flags) & FH_RSCSR_FRAME_SIZE_MSK; + __le32 *flag; + struct statistics_general_common *common; + struct statistics_rx_non_phy *rx_non_phy; + struct statistics_rx_phy *rx_ofdm; + struct statistics_rx_ht_phy *rx_ofdm_ht; + struct statistics_rx_phy *rx_cck; + struct statistics_tx *tx; + struct statistics_bt_activity *bt_activity; + + len -= sizeof(struct iwl_cmd_header); /* skip header */ + + IWL_DEBUG_RX(priv, "Statistics notification received (%d bytes).\n", + len); + + if (len == sizeof(struct iwl_bt_notif_statistics)) { + struct iwl_bt_notif_statistics *stats; + stats = &pkt->u.stats_bt; + flag = &stats->flag; + common = &stats->general.common; + rx_non_phy = &stats->rx.general.common; + rx_ofdm = &stats->rx.ofdm; + rx_ofdm_ht = &stats->rx.ofdm_ht; + rx_cck = &stats->rx.cck; + tx = &stats->tx; + bt_activity = &stats->general.activity; - if (iwl_bt_statistics(priv)) { - IWL_DEBUG_RX(priv, - "Statistics notification received (%d vs %d).\n", - (int)sizeof(struct iwl_bt_notif_statistics), - le32_to_cpu(pkt->len_n_flags) & - FH_RSCSR_FRAME_SIZE_MSK); - - change = ((priv->_agn.statistics_bt.general.common.temperature != - pkt->u.stats_bt.general.common.temperature) || - ((priv->_agn.statistics_bt.flag & - STATISTICS_REPLY_FLG_HT40_MODE_MSK) != - (pkt->u.stats_bt.flag & - STATISTICS_REPLY_FLG_HT40_MODE_MSK))); - - iwl_accumulative_statistics(priv, (__le32 *)&pkt->u.stats_bt); +#ifdef CONFIG_IWLWIFI_DEBUGFS + /* handle this exception directly */ + priv->statistics.num_bt_kills = stats->rx.general.num_bt_kills; + le32_add_cpu(&priv->statistics.accum_num_bt_kills, + le32_to_cpu(stats->rx.general.num_bt_kills)); +#endif + } else if (len == sizeof(struct iwl_notif_statistics)) { + struct iwl_notif_statistics *stats; + stats = &pkt->u.stats; + flag = &stats->flag; + common = &stats->general.common; + rx_non_phy = &stats->rx.general; + rx_ofdm = &stats->rx.ofdm; + rx_ofdm_ht = &stats->rx.ofdm_ht; + rx_cck = &stats->rx.cck; + tx = &stats->tx; + bt_activity = NULL; } else { - IWL_DEBUG_RX(priv, - "Statistics notification received (%d vs %d).\n", - (int)sizeof(struct iwl_notif_statistics), - le32_to_cpu(pkt->len_n_flags) & - FH_RSCSR_FRAME_SIZE_MSK); - - change = ((priv->_agn.statistics.general.common.temperature != - pkt->u.stats.general.common.temperature) || - ((priv->_agn.statistics.flag & - STATISTICS_REPLY_FLG_HT40_MODE_MSK) != - (pkt->u.stats.flag & - STATISTICS_REPLY_FLG_HT40_MODE_MSK))); - - iwl_accumulative_statistics(priv, (__le32 *)&pkt->u.stats); + WARN_ONCE(1, "len %d doesn't match BT (%zu) or normal (%zu)\n", + len, sizeof(struct iwl_bt_notif_statistics), + sizeof(struct iwl_notif_statistics)); + return; } - iwl_recover_from_statistics(priv, pkt); + change = common->temperature != priv->statistics.common.temperature || + (*flag & STATISTICS_REPLY_FLG_HT40_MODE_MSK) != + (priv->statistics.flag & STATISTICS_REPLY_FLG_HT40_MODE_MSK); + + iwl_accumulative_statistics(priv, common, rx_non_phy, rx_ofdm, + rx_ofdm_ht, rx_cck, tx, bt_activity); + + iwl_recover_from_statistics(priv, rx_ofdm, rx_ofdm_ht, tx, stamp); + + priv->statistics.flag = *flag; + memcpy(&priv->statistics.common, common, sizeof(*common)); + memcpy(&priv->statistics.rx_non_phy, rx_non_phy, sizeof(*rx_non_phy)); + memcpy(&priv->statistics.rx_ofdm, rx_ofdm, sizeof(*rx_ofdm)); + memcpy(&priv->statistics.rx_ofdm_ht, rx_ofdm_ht, sizeof(*rx_ofdm_ht)); + memcpy(&priv->statistics.rx_cck, rx_cck, sizeof(*rx_cck)); + memcpy(&priv->statistics.tx, tx, sizeof(*tx)); +#ifdef CONFIG_IWLWIFI_DEBUGFS + if (bt_activity) + memcpy(&priv->statistics.bt_activity, bt_activity, + sizeof(*bt_activity)); +#endif + + priv->rx_statistics_jiffies = stamp; set_bit(STATUS_STATISTICS, &priv->status); @@ -708,18 +726,12 @@ static void iwl_rx_reply_statistics(struct iwl_priv *priv, if (le32_to_cpu(pkt->u.stats.flag) & UCODE_STATISTICS_CLEAR_MSK) { #ifdef CONFIG_IWLWIFI_DEBUGFS - memset(&priv->_agn.accum_statistics, 0, - sizeof(struct iwl_notif_statistics)); - memset(&priv->_agn.delta_statistics, 0, - sizeof(struct iwl_notif_statistics)); - memset(&priv->_agn.max_delta, 0, - sizeof(struct iwl_notif_statistics)); - memset(&priv->_agn.accum_statistics_bt, 0, - sizeof(struct iwl_bt_notif_statistics)); - memset(&priv->_agn.delta_statistics_bt, 0, - sizeof(struct iwl_bt_notif_statistics)); - memset(&priv->_agn.max_delta_bt, 0, - sizeof(struct iwl_bt_notif_statistics)); + memset(&priv->accum_stats, 0, + sizeof(priv->accum_stats)); + memset(&priv->delta_stats, 0, + sizeof(priv->delta_stats)); + memset(&priv->max_delta_stats, 0, + sizeof(priv->max_delta_stats)); #endif IWL_DEBUG_RX(priv, "Statistics have been cleared\n"); } -- cgit v0.10.2 From 6fc3ba999994b675c4e6af77ac4e1a6bfd8e6128 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 4 Apr 2011 06:16:29 -0700 Subject: iwlagn: downgrade warning on unknown TLV If we maintain API properly, then there isn't really a reason to warn about this since we'll just be adding things that are safe to ignore, so downgrade the warning to debug info level. Signed-off-by: Johannes Berg Signed-off-by: Wey-Yi Guy diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index 20499b7..47a4cda 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -1481,7 +1481,7 @@ static int iwlagn_load_firmware(struct iwl_priv *priv, le32_to_cpup((__le32 *)tlv_data); break; default: - IWL_WARN(priv, "unknown TLV: %d\n", tlv_type); + IWL_DEBUG_INFO(priv, "unknown TLV: %d\n", tlv_type); break; } } -- cgit v0.10.2 From be1a12a0dfed06cf1e62e35bf91620dc610a451a Mon Sep 17 00:00:00 2001 From: Josef Bacik Date: Wed, 6 Apr 2011 13:05:22 -0400 Subject: Btrfs: deal with the case that we run out of space in the cache Currently we don't handle running out of space in the cache, so to fix this we keep track of how far in the cache we are. Then we only dirty the pages if we successfully modify all of them, otherwise if we have an error or run out of space we can just drop them and not worry about the vm writing them out. Thanks, Tested-by Johannes Hirte Signed-off-by: Josef Bacik diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h index 3458b57..0d00a07 100644 --- a/fs/btrfs/ctree.h +++ b/fs/btrfs/ctree.h @@ -2576,6 +2576,11 @@ int btrfs_drop_extents(struct btrfs_trans_handle *trans, struct inode *inode, int btrfs_mark_extent_written(struct btrfs_trans_handle *trans, struct inode *inode, u64 start, u64 end); int btrfs_release_file(struct inode *inode, struct file *file); +void btrfs_drop_pages(struct page **pages, size_t num_pages); +int btrfs_dirty_pages(struct btrfs_root *root, struct inode *inode, + struct page **pages, size_t num_pages, + loff_t pos, size_t write_bytes, + struct extent_state **cached); /* tree-defrag.c */ int btrfs_defrag_leaves(struct btrfs_trans_handle *trans, diff --git a/fs/btrfs/file.c b/fs/btrfs/file.c index e621ea5..75899a0 100644 --- a/fs/btrfs/file.c +++ b/fs/btrfs/file.c @@ -104,7 +104,7 @@ static noinline int btrfs_copy_from_user(loff_t pos, int num_pages, /* * unlocks pages after btrfs_file_write is done with them */ -static noinline void btrfs_drop_pages(struct page **pages, size_t num_pages) +void btrfs_drop_pages(struct page **pages, size_t num_pages) { size_t i; for (i = 0; i < num_pages; i++) { @@ -127,16 +127,13 @@ static noinline void btrfs_drop_pages(struct page **pages, size_t num_pages) * this also makes the decision about creating an inline extent vs * doing real data extents, marking pages dirty and delalloc as required. */ -static noinline int dirty_and_release_pages(struct btrfs_root *root, - struct file *file, - struct page **pages, - size_t num_pages, - loff_t pos, - size_t write_bytes) +int btrfs_dirty_pages(struct btrfs_root *root, struct inode *inode, + struct page **pages, size_t num_pages, + loff_t pos, size_t write_bytes, + struct extent_state **cached) { int err = 0; int i; - struct inode *inode = fdentry(file)->d_inode; u64 num_bytes; u64 start_pos; u64 end_of_last_block; @@ -149,7 +146,7 @@ static noinline int dirty_and_release_pages(struct btrfs_root *root, end_of_last_block = start_pos + num_bytes - 1; err = btrfs_set_extent_delalloc(inode, start_pos, end_of_last_block, - NULL); + cached); if (err) return err; @@ -992,9 +989,9 @@ static noinline ssize_t __btrfs_buffered_write(struct file *file, } if (copied > 0) { - ret = dirty_and_release_pages(root, file, pages, - dirty_pages, pos, - copied); + ret = btrfs_dirty_pages(root, inode, pages, + dirty_pages, pos, copied, + NULL); if (ret) { btrfs_delalloc_release_space(inode, dirty_pages << PAGE_CACHE_SHIFT); diff --git a/fs/btrfs/free-space-cache.c b/fs/btrfs/free-space-cache.c index f561c95..a3f420d 100644 --- a/fs/btrfs/free-space-cache.c +++ b/fs/btrfs/free-space-cache.c @@ -508,6 +508,7 @@ int btrfs_write_out_cache(struct btrfs_root *root, struct inode *inode; struct rb_node *node; struct list_head *pos, *n; + struct page **pages; struct page *page; struct extent_state *cached_state = NULL; struct btrfs_free_cluster *cluster = NULL; @@ -517,13 +518,13 @@ int btrfs_write_out_cache(struct btrfs_root *root, u64 start, end, len; u64 bytes = 0; u32 *crc, *checksums; - pgoff_t index = 0, last_index = 0; unsigned long first_page_offset; - int num_checksums; + int index = 0, num_pages = 0; int entries = 0; int bitmaps = 0; int ret = 0; bool next_page = false; + bool out_of_space = false; root = root->fs_info->tree_root; @@ -551,24 +552,31 @@ int btrfs_write_out_cache(struct btrfs_root *root, return 0; } - last_index = (i_size_read(inode) - 1) >> PAGE_CACHE_SHIFT; + num_pages = (i_size_read(inode) + PAGE_CACHE_SIZE - 1) >> + PAGE_CACHE_SHIFT; filemap_write_and_wait(inode->i_mapping); btrfs_wait_ordered_range(inode, inode->i_size & ~(root->sectorsize - 1), (u64)-1); /* We need a checksum per page. */ - num_checksums = i_size_read(inode) / PAGE_CACHE_SIZE; - crc = checksums = kzalloc(sizeof(u32) * num_checksums, GFP_NOFS); + crc = checksums = kzalloc(sizeof(u32) * num_pages, GFP_NOFS); if (!crc) { iput(inode); return 0; } + pages = kzalloc(sizeof(struct page *) * num_pages, GFP_NOFS); + if (!pages) { + kfree(crc); + iput(inode); + return 0; + } + /* Since the first page has all of our checksums and our generation we * need to calculate the offset into the page that we can start writing * our entries. */ - first_page_offset = (sizeof(u32) * num_checksums) + sizeof(u64); + first_page_offset = (sizeof(u32) * num_pages) + sizeof(u64); /* Get the cluster for this block_group if it exists */ if (!list_empty(&block_group->cluster_list)) @@ -590,20 +598,18 @@ int btrfs_write_out_cache(struct btrfs_root *root, * after find_get_page at this point. Just putting this here so people * know and don't freak out. */ - while (index <= last_index) { + while (index < num_pages) { page = grab_cache_page(inode->i_mapping, index); if (!page) { - pgoff_t i = 0; + int i; - while (i < index) { - page = find_get_page(inode->i_mapping, i); - unlock_page(page); - page_cache_release(page); - page_cache_release(page); - i++; + for (i = 0; i < num_pages; i++) { + unlock_page(pages[i]); + page_cache_release(pages[i]); } goto out_free; } + pages[index] = page; index++; } @@ -631,7 +637,12 @@ int btrfs_write_out_cache(struct btrfs_root *root, offset = start_offset; } - page = find_get_page(inode->i_mapping, index); + if (index >= num_pages) { + out_of_space = true; + break; + } + + page = pages[index]; addr = kmap(page); entry = addr + start_offset; @@ -708,23 +719,6 @@ int btrfs_write_out_cache(struct btrfs_root *root, bytes += PAGE_CACHE_SIZE; - ClearPageChecked(page); - set_page_extent_mapped(page); - SetPageUptodate(page); - set_page_dirty(page); - - /* - * We need to release our reference we got for grab_cache_page, - * except for the first page which will hold our checksums, we - * do that below. - */ - if (index != 0) { - unlock_page(page); - page_cache_release(page); - } - - page_cache_release(page); - index++; } while (node || next_page); @@ -734,6 +728,10 @@ int btrfs_write_out_cache(struct btrfs_root *root, struct btrfs_free_space *entry = list_entry(pos, struct btrfs_free_space, list); + if (index >= num_pages) { + out_of_space = true; + break; + } page = find_get_page(inode->i_mapping, index); addr = kmap(page); @@ -745,64 +743,58 @@ int btrfs_write_out_cache(struct btrfs_root *root, crc++; bytes += PAGE_CACHE_SIZE; - ClearPageChecked(page); - set_page_extent_mapped(page); - SetPageUptodate(page); - set_page_dirty(page); - unlock_page(page); - page_cache_release(page); - page_cache_release(page); list_del_init(&entry->list); index++; } + if (out_of_space) { + btrfs_drop_pages(pages, num_pages); + unlock_extent_cached(&BTRFS_I(inode)->io_tree, 0, + i_size_read(inode) - 1, &cached_state, + GFP_NOFS); + ret = 0; + goto out_free; + } + /* Zero out the rest of the pages just to make sure */ - while (index <= last_index) { + while (index < num_pages) { void *addr; - page = find_get_page(inode->i_mapping, index); - + page = pages[index]; addr = kmap(page); memset(addr, 0, PAGE_CACHE_SIZE); kunmap(page); - ClearPageChecked(page); - set_page_extent_mapped(page); - SetPageUptodate(page); - set_page_dirty(page); - unlock_page(page); - page_cache_release(page); - page_cache_release(page); bytes += PAGE_CACHE_SIZE; index++; } - btrfs_set_extent_delalloc(inode, 0, bytes - 1, &cached_state); - /* Write the checksums and trans id to the first page */ { void *addr; u64 *gen; - page = find_get_page(inode->i_mapping, 0); + page = pages[0]; addr = kmap(page); - memcpy(addr, checksums, sizeof(u32) * num_checksums); - gen = addr + (sizeof(u32) * num_checksums); + memcpy(addr, checksums, sizeof(u32) * num_pages); + gen = addr + (sizeof(u32) * num_pages); *gen = trans->transid; kunmap(page); - ClearPageChecked(page); - set_page_extent_mapped(page); - SetPageUptodate(page); - set_page_dirty(page); - unlock_page(page); - page_cache_release(page); - page_cache_release(page); } - BTRFS_I(inode)->generation = trans->transid; + ret = btrfs_dirty_pages(root, inode, pages, num_pages, 0, + bytes, &cached_state); + btrfs_drop_pages(pages, num_pages); unlock_extent_cached(&BTRFS_I(inode)->io_tree, 0, i_size_read(inode) - 1, &cached_state, GFP_NOFS); + if (ret) { + ret = 0; + goto out_free; + } + + BTRFS_I(inode)->generation = trans->transid; + filemap_write_and_wait(inode->i_mapping); key.objectid = BTRFS_FREE_SPACE_OBJECTID; @@ -853,6 +845,7 @@ out_free: BTRFS_I(inode)->generation = 0; } kfree(checksums); + kfree(pages); btrfs_update_inode(trans, root, inode); iput(inode); return ret; -- cgit v0.10.2 From 06d5a5899d6d3ac401d2359b5eac6d2a3a0fe331 Mon Sep 17 00:00:00 2001 From: Josef Bacik Date: Tue, 5 Apr 2011 11:57:27 -0400 Subject: Btrfs: only retry transaction reservation once I saw a lockup where we kept getting into this start transaction->commit transaction loop because of enospce. The fact is if we fail to make our reservation, we've tried _everything_ several times, so we only need to try and commit the transaction once, and if that doesn't work then we really are out of space and need to just exit. Thanks, Signed-off-by: Josef Bacik diff --git a/fs/btrfs/transaction.c b/fs/btrfs/transaction.c index 5b158da..4583008 100644 --- a/fs/btrfs/transaction.c +++ b/fs/btrfs/transaction.c @@ -181,6 +181,7 @@ static struct btrfs_trans_handle *start_transaction(struct btrfs_root *root, { struct btrfs_trans_handle *h; struct btrfs_transaction *cur_trans; + int retries = 0; int ret; if (root->fs_info->fs_state & BTRFS_SUPER_FLAG_ERROR) @@ -224,10 +225,18 @@ again: if (num_items > 0) { ret = btrfs_trans_reserve_metadata(h, root, num_items); - if (ret == -EAGAIN) { + if (ret == -EAGAIN && !retries) { + retries++; btrfs_commit_transaction(h, root); goto again; + } else if (ret == -EAGAIN) { + /* + * We have already retried and got EAGAIN, so really we + * don't have space, so set ret to -ENOSPC. + */ + ret = -ENOSPC; } + if (ret < 0) { btrfs_end_transaction(h, root); return ERR_PTR(ret); -- cgit v0.10.2 From 12ddb96cb6752218d8a1aeb696ec9b0ca7adb42f Mon Sep 17 00:00:00 2001 From: Josef Bacik Date: Tue, 5 Apr 2011 13:02:27 -0400 Subject: Btrfs: map the inode item when doing fill_inode_item Instead of calling kmap_atomic for every thing we set in the inode item, map the entire inode item at the start and unmap it at the end. This makes a sequential dd of 400mb O_DIRECT something like 1% faster. Thanks, Signed-off-by: Josef Bacik diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c index cc60228..da26802 100644 --- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c @@ -2589,6 +2589,13 @@ static void fill_inode_item(struct btrfs_trans_handle *trans, struct btrfs_inode_item *item, struct inode *inode) { + if (!leaf->map_token) + map_private_extent_buffer(leaf, (unsigned long)item, + sizeof(struct btrfs_inode_item), + &leaf->map_token, &leaf->kaddr, + &leaf->map_start, &leaf->map_len, + KM_USER1); + btrfs_set_inode_uid(leaf, item, inode->i_uid); btrfs_set_inode_gid(leaf, item, inode->i_gid); btrfs_set_inode_size(leaf, item, BTRFS_I(inode)->disk_i_size); @@ -2617,6 +2624,11 @@ static void fill_inode_item(struct btrfs_trans_handle *trans, btrfs_set_inode_rdev(leaf, item, inode->i_rdev); btrfs_set_inode_flags(leaf, item, BTRFS_I(inode)->flags); btrfs_set_inode_block_group(leaf, item, BTRFS_I(inode)->block_group); + + if (leaf->map_token) { + unmap_extent_buffer(leaf, leaf->map_token, KM_USER1); + leaf->map_token = NULL; + } } /* -- cgit v0.10.2 From 1ef30be142d2cc60e2687ef267de864cf31be995 Mon Sep 17 00:00:00 2001 From: Josef Bacik Date: Tue, 5 Apr 2011 19:25:36 -0400 Subject: Btrfs: do not call btrfs_update_inode in endio if nothing changed In the DIO code we often don't update the i_disk_size because the i_size isn't updated until after the DIO is completed, so basically we are allocating a path, doing a search, and updating the inode item for no reason since nothing changed. btrfs_ordered_update_i_size will return 1 if it didn't update i_disk_size, so only run btrfs_update_inode if btrfs_ordered_update_i_size returns 0. Thanks, Signed-off-by: Josef Bacik diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c index da26802..4a238d6 100644 --- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c @@ -1769,9 +1769,12 @@ static int btrfs_finish_ordered_io(struct inode *inode, u64 start, u64 end) add_pending_csums(trans, inode, ordered_extent->file_offset, &ordered_extent->list); - btrfs_ordered_update_i_size(inode, 0, ordered_extent); - ret = btrfs_update_inode(trans, root, inode); - BUG_ON(ret); + ret = btrfs_ordered_update_i_size(inode, 0, ordered_extent); + if (!ret) { + ret = btrfs_update_inode(trans, root, inode); + BUG_ON(ret); + } + ret = 0; out: if (nolock) { if (trans) @@ -5865,8 +5868,10 @@ again: } add_pending_csums(trans, inode, ordered->file_offset, &ordered->list); - btrfs_ordered_update_i_size(inode, 0, ordered); - btrfs_update_inode(trans, root, inode); + ret = btrfs_ordered_update_i_size(inode, 0, ordered); + if (!ret) + btrfs_update_inode(trans, root, inode); + ret = 0; out_unlock: unlock_extent_cached(&BTRFS_I(inode)->io_tree, ordered->file_offset, ordered->file_offset + ordered->len - 1, -- cgit v0.10.2 From 02f57c7aedef1a537f4b16db7061cdd8efa3bb4e Mon Sep 17 00:00:00 2001 From: Josef Bacik Date: Wed, 6 Apr 2011 14:25:44 -0400 Subject: Btrfs: don't split dio bios if we don't have to We have been unconditionally allocating a new bio and re-adding all pages from our original bio to the new bio. This is needed if our original bio is larger than our stripe size, but if it is smaller than the stripe size then there is no need to do this. So check the map length and if we are under that then go ahead and submit the original bio. Thanks, Signed-off-by: Josef Bacik diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c index 4a238d6..149c77f 100644 --- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c @@ -6006,13 +6006,6 @@ static int btrfs_submit_direct_hook(int rw, struct btrfs_dio_private *dip, int ret = 0; int write = rw & REQ_WRITE; - bio = btrfs_dio_bio_alloc(orig_bio->bi_bdev, start_sector, GFP_NOFS); - if (!bio) - return -ENOMEM; - bio->bi_private = dip; - bio->bi_end_io = btrfs_end_dio_bio; - atomic_inc(&dip->pending_bios); - map_length = orig_bio->bi_size; ret = btrfs_map_block(map_tree, READ, start_sector << 9, &map_length, NULL, 0); @@ -6021,6 +6014,18 @@ static int btrfs_submit_direct_hook(int rw, struct btrfs_dio_private *dip, return -EIO; } + if (map_length >= orig_bio->bi_size) { + bio = orig_bio; + goto submit; + } + + bio = btrfs_dio_bio_alloc(orig_bio->bi_bdev, start_sector, GFP_NOFS); + if (!bio) + return -ENOMEM; + bio->bi_private = dip; + bio->bi_end_io = btrfs_end_dio_bio; + atomic_inc(&dip->pending_bios); + while (bvec <= (orig_bio->bi_io_vec + orig_bio->bi_vcnt - 1)) { if (unlikely(map_length < submit_len + bvec->bv_len || bio_add_page(bio, bvec->bv_page, bvec->bv_len, @@ -6071,6 +6076,7 @@ static int btrfs_submit_direct_hook(int rw, struct btrfs_dio_private *dip, } } +submit: ret = __btrfs_submit_dio_bio(bio, inode, rw, file_offset, skip_sum, csums); if (!ret) -- cgit v0.10.2 From 1ae399382512b3e4d6c923e53da9e45935577040 Mon Sep 17 00:00:00 2001 From: Josef Bacik Date: Wed, 6 Apr 2011 14:41:34 -0400 Subject: Btrfs: do not use async submit for small DIO io's When looking at our DIO performance Chris said that for small IO's doing the async submit stuff tends to be more overhead than it's worth. With this on top of my other fixes I get about a 17-20% speedup doing a sequential dd with 4k IO's. Basically if we don't have to split the bio for the map length it's small enough to be directly submitted, otherwise go back to the async submit. Thanks, Signed-off-by: Josef Bacik diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c index 149c77f..2bb76c6 100644 --- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c @@ -5957,7 +5957,7 @@ static struct bio *btrfs_dio_bio_alloc(struct block_device *bdev, static inline int __btrfs_submit_dio_bio(struct bio *bio, struct inode *inode, int rw, u64 file_offset, int skip_sum, - u32 *csums) + u32 *csums, int async_submit) { int write = rw & REQ_WRITE; struct btrfs_root *root = BTRFS_I(inode)->root; @@ -5968,13 +5968,24 @@ static inline int __btrfs_submit_dio_bio(struct bio *bio, struct inode *inode, if (ret) goto err; - if (write && !skip_sum) { + if (skip_sum) + goto map; + + if (write && async_submit) { ret = btrfs_wq_submit_bio(root->fs_info, inode, rw, bio, 0, 0, file_offset, __btrfs_submit_bio_start_direct_io, __btrfs_submit_bio_done); goto err; + } else if (write) { + /* + * If we aren't doing async submit, calculate the csum of the + * bio now. + */ + ret = btrfs_csum_one_bio(root, inode, bio, file_offset, 1); + if (ret) + goto err; } else if (!skip_sum) { ret = btrfs_lookup_bio_sums_dio(root, inode, bio, file_offset, csums); @@ -5982,7 +5993,8 @@ static inline int __btrfs_submit_dio_bio(struct bio *bio, struct inode *inode, goto err; } - ret = btrfs_map_bio(root, rw, bio, 0, 1); +map: + ret = btrfs_map_bio(root, rw, bio, 0, async_submit); err: bio_put(bio); return ret; @@ -6004,6 +6016,7 @@ static int btrfs_submit_direct_hook(int rw, struct btrfs_dio_private *dip, int nr_pages = 0; u32 *csums = dip->csums; int ret = 0; + int async_submit = 0; int write = rw & REQ_WRITE; map_length = orig_bio->bi_size; @@ -6019,6 +6032,7 @@ static int btrfs_submit_direct_hook(int rw, struct btrfs_dio_private *dip, goto submit; } + async_submit = 1; bio = btrfs_dio_bio_alloc(orig_bio->bi_bdev, start_sector, GFP_NOFS); if (!bio) return -ENOMEM; @@ -6039,7 +6053,7 @@ static int btrfs_submit_direct_hook(int rw, struct btrfs_dio_private *dip, atomic_inc(&dip->pending_bios); ret = __btrfs_submit_dio_bio(bio, inode, rw, file_offset, skip_sum, - csums); + csums, async_submit); if (ret) { bio_put(bio); atomic_dec(&dip->pending_bios); @@ -6078,7 +6092,7 @@ static int btrfs_submit_direct_hook(int rw, struct btrfs_dio_private *dip, submit: ret = __btrfs_submit_dio_bio(bio, inode, rw, file_offset, skip_sum, - csums); + csums, async_submit); if (!ret) return 0; -- cgit v0.10.2 From 16d299ac7446b5a75c5683a9ae11d7907d444c86 Mon Sep 17 00:00:00 2001 From: Josef Bacik Date: Wed, 6 Apr 2011 14:53:07 -0400 Subject: Btrfs: reuse the extent_map we found when calling btrfs_get_extent In btrfs_get_block_direct we call btrfs_get_extent to lookup the extent for the range that we are looking for. If we don't find an extent, btrfs_get_extent will insert a extent_map for that area and mark it as a hole. So it does the job of allocating a new extent map and inserting it into the io tree. But if we're creating a new extent we free it up and redo all of that work. So instead pass the em to btrfs_new_extent_direct(), and if it will work just allocate the disk space and set it up properly and bypass the freeing/allocating of a new extent map and the expensive operation of inserting the thing into the io_tree. Thanks, Signed-off-by: Josef Bacik diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c index 2bb76c6..24310c9 100644 --- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c @@ -5445,17 +5445,30 @@ out: } static struct extent_map *btrfs_new_extent_direct(struct inode *inode, + struct extent_map *em, u64 start, u64 len) { struct btrfs_root *root = BTRFS_I(inode)->root; struct btrfs_trans_handle *trans; - struct extent_map *em; struct extent_map_tree *em_tree = &BTRFS_I(inode)->extent_tree; struct btrfs_key ins; u64 alloc_hint; int ret; + bool insert = false; - btrfs_drop_extent_cache(inode, start, start + len - 1, 0); + /* + * Ok if the extent map we looked up is a hole and is for the exact + * range we want, there is no reason to allocate a new one, however if + * it is not right then we need to free this one and drop the cache for + * our range. + */ + if (em->block_start != EXTENT_MAP_HOLE || em->start != start || + em->len != len) { + free_extent_map(em); + em = NULL; + insert = true; + btrfs_drop_extent_cache(inode, start, start + len - 1, 0); + } trans = btrfs_join_transaction(root, 0); if (IS_ERR(trans)) @@ -5471,10 +5484,12 @@ static struct extent_map *btrfs_new_extent_direct(struct inode *inode, goto out; } - em = alloc_extent_map(GFP_NOFS); if (!em) { - em = ERR_PTR(-ENOMEM); - goto out; + em = alloc_extent_map(GFP_NOFS); + if (!em) { + em = ERR_PTR(-ENOMEM); + goto out; + } } em->start = start; @@ -5484,9 +5499,15 @@ static struct extent_map *btrfs_new_extent_direct(struct inode *inode, em->block_start = ins.objectid; em->block_len = ins.offset; em->bdev = root->fs_info->fs_devices->latest_bdev; + + /* + * We need to do this because if we're using the original em we searched + * for, we could have EXTENT_FLAG_VACANCY set, and we don't want that. + */ + em->flags = 0; set_bit(EXTENT_FLAG_PINNED, &em->flags); - while (1) { + while (insert) { write_lock(&em_tree->lock); ret = add_extent_mapping(em_tree, em); write_unlock(&em_tree->lock); @@ -5704,8 +5725,7 @@ must_cow: * it above */ len = bh_result->b_size; - free_extent_map(em); - em = btrfs_new_extent_direct(inode, start, len); + em = btrfs_new_extent_direct(inode, em, start, len); if (IS_ERR(em)) return PTR_ERR(em); len = min(len, em->len - (start - em->start)); -- cgit v0.10.2 From 93a54bc4c28a125978cddbe2db9e347391e3522d Mon Sep 17 00:00:00 2001 From: Josef Bacik Date: Wed, 6 Apr 2011 15:11:44 -0400 Subject: Btrfs: check for duplicate iov_base's when doing dio reads Apparently it is ok to submit a read to an IDE device with the same target page for different offsets. This is what Windows does under qemu. The problem is under DIO we expect them to be different buffers for checksumming reasons, and so this sort of thing will result in checksum errors, when in reality the file is fine. So when reading, check to make sure that all iov bases are different, and if they aren't fall back to buffered mode, since that will work out right. Thanks, Signed-off-by: Josef Bacik diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c index 24310c9..00d59c6 100644 --- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c @@ -6207,6 +6207,7 @@ static ssize_t check_direct_IO(struct btrfs_root *root, int rw, struct kiocb *io unsigned long nr_segs) { int seg; + int i; size_t size; unsigned long addr; unsigned blocksize_mask = root->sectorsize - 1; @@ -6221,8 +6222,22 @@ static ssize_t check_direct_IO(struct btrfs_root *root, int rw, struct kiocb *io addr = (unsigned long)iov[seg].iov_base; size = iov[seg].iov_len; end += size; - if ((addr & blocksize_mask) || (size & blocksize_mask)) + if ((addr & blocksize_mask) || (size & blocksize_mask)) goto out; + + /* If this is a write we don't need to check anymore */ + if (rw & WRITE) + continue; + + /* + * Check to make sure we don't have duplicate iov_base's in this + * iovec, if so return EINVAL, otherwise we'll get csum errors + * when reading back. + */ + for (i = seg + 1; i < nr_segs; i++) { + if (iov[seg].iov_base == iov[i].iov_base) + goto out; + } } retval = 0; out: -- cgit v0.10.2 From 96f372c95d32f76fa2b0e035e0a6269234bfda09 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Thu, 7 Apr 2011 19:07:17 +0200 Subject: ath9k: fix missing ath9k_ps_wakeup/ath9k_ps_restore calls These missing chip wakeups mainly cause crashes on AR5416 cards in MIPS boards, but have also been reported to cause radio stability issues on AR9285. Signed-off-by: Felix Fietkau Cc: stable@kernel.org Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index dddb85d..17d04ff 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -1376,7 +1376,6 @@ static void ath9k_calculate_summary_state(struct ieee80211_hw *hw, ath9k_calculate_iter_data(hw, vif, &iter_data); - ath9k_ps_wakeup(sc); /* Set BSSID mask. */ memcpy(common->bssidmask, iter_data.mask, ETH_ALEN); ath_hw_setbssidmask(common); @@ -1411,7 +1410,6 @@ static void ath9k_calculate_summary_state(struct ieee80211_hw *hw, } ath9k_hw_set_interrupts(ah, ah->imask); - ath9k_ps_restore(sc); /* Set up ANI */ if ((iter_data.naps + iter_data.nadhocs) > 0) { @@ -1457,6 +1455,7 @@ static int ath9k_add_interface(struct ieee80211_hw *hw, struct ath_vif *avp = (void *)vif->drv_priv; int ret = 0; + ath9k_ps_wakeup(sc); mutex_lock(&sc->mutex); switch (vif->type) { @@ -1503,6 +1502,7 @@ static int ath9k_add_interface(struct ieee80211_hw *hw, ath9k_do_vif_add_setup(hw, vif); out: mutex_unlock(&sc->mutex); + ath9k_ps_restore(sc); return ret; } @@ -1517,6 +1517,7 @@ static int ath9k_change_interface(struct ieee80211_hw *hw, ath_dbg(common, ATH_DBG_CONFIG, "Change Interface\n"); mutex_lock(&sc->mutex); + ath9k_ps_wakeup(sc); /* See if new interface type is valid. */ if ((new_type == NL80211_IFTYPE_ADHOC) && @@ -1546,6 +1547,7 @@ static int ath9k_change_interface(struct ieee80211_hw *hw, ath9k_do_vif_add_setup(hw, vif); out: + ath9k_ps_restore(sc); mutex_unlock(&sc->mutex); return ret; } @@ -1558,6 +1560,7 @@ static void ath9k_remove_interface(struct ieee80211_hw *hw, ath_dbg(common, ATH_DBG_CONFIG, "Detach Interface\n"); + ath9k_ps_wakeup(sc); mutex_lock(&sc->mutex); sc->nvifs--; @@ -1569,6 +1572,7 @@ static void ath9k_remove_interface(struct ieee80211_hw *hw, ath9k_calculate_summary_state(hw, NULL); mutex_unlock(&sc->mutex); + ath9k_ps_restore(sc); } static void ath9k_enable_ps(struct ath_softc *sc) @@ -1809,6 +1813,7 @@ static int ath9k_conf_tx(struct ieee80211_hw *hw, u16 queue, txq = sc->tx.txq_map[queue]; + ath9k_ps_wakeup(sc); mutex_lock(&sc->mutex); memset(&qi, 0, sizeof(struct ath9k_tx_queue_info)); @@ -1832,6 +1837,7 @@ static int ath9k_conf_tx(struct ieee80211_hw *hw, u16 queue, ath_beaconq_config(sc); mutex_unlock(&sc->mutex); + ath9k_ps_restore(sc); return ret; } @@ -1894,6 +1900,7 @@ static void ath9k_bss_info_changed(struct ieee80211_hw *hw, int slottime; int error; + ath9k_ps_wakeup(sc); mutex_lock(&sc->mutex); if (changed & BSS_CHANGED_BSSID) { @@ -1994,6 +2001,7 @@ static void ath9k_bss_info_changed(struct ieee80211_hw *hw, } mutex_unlock(&sc->mutex); + ath9k_ps_restore(sc); } static u64 ath9k_get_tsf(struct ieee80211_hw *hw) -- cgit v0.10.2 From a6756da9eace8b4af73e9dea43f1fc2889224c94 Mon Sep 17 00:00:00 2001 From: Jason Conti Date: Thu, 7 Apr 2011 21:09:57 +0200 Subject: p54: Initialize extra_len in p54_tx_80211 This patch fixes a very serious off-by-one bug in the driver, which could leave the device in an unresponsive state. The problem was that the extra_len variable [used to reserve extra scratch buffer space for the firmware] was left uninitialized. Because p54_assign_address later needs the value to reserve additional space, the resulting frame could be to big for the small device's memory window and everything would immediately come to a grinding halt. Reference: https://bugs.launchpad.net/bugs/722185 Cc: Acked-by: Christian Lamparter Signed-off-by: Jason Conti Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/p54/txrx.c b/drivers/net/wireless/p54/txrx.c index 7834c26..042842e 100644 --- a/drivers/net/wireless/p54/txrx.c +++ b/drivers/net/wireless/p54/txrx.c @@ -703,7 +703,7 @@ void p54_tx_80211(struct ieee80211_hw *dev, struct sk_buff *skb) struct p54_tx_info *p54info; struct p54_hdr *hdr; struct p54_tx_data *txhdr; - unsigned int padding, len, extra_len; + unsigned int padding, len, extra_len = 0; int i, j, ridx; u16 hdr_flags = 0, aid = 0; u8 rate, queue = 0, crypt_offset = 0; -- cgit v0.10.2 From ce9c99af8d4b3b0b9463654fd252d8640d804dc3 Mon Sep 17 00:00:00 2001 From: Ian Campbell Date: Fri, 8 Apr 2011 07:42:29 +0100 Subject: x86, cpu: Move AMD Elan Kconfig under "Processor family" Currently the option resides under X86_EXTENDED_PLATFORM due to historical nonstandard A20M# handling. However that is no longer the case and so Elan can be treated as part of the standard processor choice Kconfig option. Signed-off-by: Ian Campbell Link: http://lkml.kernel.org/r/1302245177.31620.47.camel@localhost.localdomain Cc: H. Peter Anvin Signed-off-by: H. Peter Anvin diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig index cc6c53a..f00a3f3 100644 --- a/arch/x86/Kconfig +++ b/arch/x86/Kconfig @@ -365,17 +365,6 @@ config X86_UV # Following is an alphabetically sorted list of 32 bit extended platforms # Please maintain the alphabetic order if and when there are additions -config X86_ELAN - bool "AMD Elan" - depends on X86_32 - depends on X86_EXTENDED_PLATFORM - ---help--- - Select this for an AMD Elan processor. - - Do not use this option for K6/Athlon/Opteron processors! - - If unsure, choose "PC-compatible" instead. - config X86_INTEL_CE bool "CE4100 TV platform" depends on PCI diff --git a/arch/x86/Kconfig.cpu b/arch/x86/Kconfig.cpu index d161e93..6a7cfdf 100644 --- a/arch/x86/Kconfig.cpu +++ b/arch/x86/Kconfig.cpu @@ -1,6 +1,4 @@ # Put here option for CPU selection and depending optimization -if !X86_ELAN - choice prompt "Processor family" default M686 if X86_32 @@ -203,6 +201,14 @@ config MWINCHIP3D stores for this CPU, which can increase performance of some operations. +config MELAN + bool "AMD Elan" + depends on X86_32 + ---help--- + Select this for an AMD Elan processor. + + Do not use this option for K6/Athlon/Opteron processors! + config MGEODEGX1 bool "GeodeGX1" depends on X86_32 @@ -292,8 +298,6 @@ config X86_GENERIC This is really intended for distributors who need more generic optimizations. -endif - # # Define implied options from the CPU selection here config X86_INTERNODE_CACHE_SHIFT @@ -312,7 +316,7 @@ config X86_L1_CACHE_SHIFT int default "7" if MPENTIUM4 || MPSC default "6" if MK7 || MK8 || MPENTIUMM || MCORE2 || MATOM || MVIAC7 || X86_GENERIC || GENERIC_CPU - default "4" if X86_ELAN || M486 || M386 || MGEODEGX1 + default "4" if MELAN || M486 || M386 || MGEODEGX1 default "5" if MWINCHIP3D || MWINCHIPC6 || MCRUSOE || MEFFICEON || MCYRIXIII || MK6 || MPENTIUMIII || MPENTIUMII || M686 || M586MMX || M586TSC || M586 || MVIAC3_2 || MGEODE_LX config X86_XADD @@ -358,7 +362,7 @@ config X86_POPAD_OK config X86_ALIGNMENT_16 def_bool y - depends on MWINCHIP3D || MWINCHIPC6 || MCYRIXIII || X86_ELAN || MK6 || M586MMX || M586TSC || M586 || M486 || MVIAC3_2 || MGEODEGX1 + depends on MWINCHIP3D || MWINCHIPC6 || MCYRIXIII || MELAN || MK6 || M586MMX || M586TSC || M586 || M486 || MVIAC3_2 || MGEODEGX1 config X86_INTEL_USERCOPY def_bool y diff --git a/arch/x86/Makefile_32.cpu b/arch/x86/Makefile_32.cpu index f2ee1ab..86cee7b 100644 --- a/arch/x86/Makefile_32.cpu +++ b/arch/x86/Makefile_32.cpu @@ -37,7 +37,7 @@ cflags-$(CONFIG_MATOM) += $(call cc-option,-march=atom,$(call cc-option,-march= $(call cc-option,-mtune=atom,$(call cc-option,-mtune=generic)) # AMD Elan support -cflags-$(CONFIG_X86_ELAN) += -march=i486 +cflags-$(CONFIG_MELAN) += -march=i486 # Geode GX1 support cflags-$(CONFIG_MGEODEGX1) += -march=pentium-mmx diff --git a/arch/x86/include/asm/module.h b/arch/x86/include/asm/module.h index 67763c5..9eae775 100644 --- a/arch/x86/include/asm/module.h +++ b/arch/x86/include/asm/module.h @@ -35,7 +35,7 @@ #define MODULE_PROC_FAMILY "K7 " #elif defined CONFIG_MK8 #define MODULE_PROC_FAMILY "K8 " -#elif defined CONFIG_X86_ELAN +#elif defined CONFIG_MELAN #define MODULE_PROC_FAMILY "ELAN " #elif defined CONFIG_MCRUSOE #define MODULE_PROC_FAMILY "CRUSOE " diff --git a/arch/x86/kernel/cpu/cpufreq/Kconfig b/arch/x86/kernel/cpu/cpufreq/Kconfig index 870e6cc..0ab9b22 100644 --- a/arch/x86/kernel/cpu/cpufreq/Kconfig +++ b/arch/x86/kernel/cpu/cpufreq/Kconfig @@ -43,7 +43,7 @@ config X86_ACPI_CPUFREQ config ELAN_CPUFREQ tristate "AMD Elan SC400 and SC410" select CPU_FREQ_TABLE - depends on X86_ELAN + depends on MELAN ---help--- This adds the CPUFreq driver for AMD Elan SC400 and SC410 processors. @@ -59,7 +59,7 @@ config ELAN_CPUFREQ config SC520_CPUFREQ tristate "AMD Elan SC520" select CPU_FREQ_TABLE - depends on X86_ELAN + depends on MELAN ---help--- This adds the CPUFreq driver for AMD Elan SC520 processor. -- cgit v0.10.2 From 93ae653491f0a413d5f4d9aa4df45d09ecb55d62 Mon Sep 17 00:00:00 2001 From: Michael Chan Date: Fri, 8 Apr 2011 13:03:02 -0700 Subject: cnic: Fix rtnl deadlock When cnic_stop_hw() -> cnic_cm_stop_bnx2x_hw() is called under rtnl_lock() from NETDEV_DOWN event, it waits for cnic_delete_task() to complete. It will deadlock when cnic_delete_task() takes rtnl_lock() before calling cnic_ulp_stop_one(). We fix it by removing the rtnl_lock() in cnic_delete_task(). cnic_ulp_stop_one() has mutex and atomic bit ops to prevent important operations from being done more than once, so it is not necessary to take rtnl_lock(). Signed-off-by: Michael Chan Signed-off-by: David S. Miller diff --git a/drivers/net/cnic.c b/drivers/net/cnic.c index 5dfbff0..cde59b4 100644 --- a/drivers/net/cnic.c +++ b/drivers/net/cnic.c @@ -3983,9 +3983,7 @@ static void cnic_delete_task(struct work_struct *work) if (test_and_clear_bit(CNIC_LCL_FL_STOP_ISCSI, &cp->cnic_local_flags)) { struct drv_ctl_info info; - rtnl_lock(); cnic_ulp_stop_one(cp, CNIC_ULP_ISCSI); - rtnl_unlock(); info.cmd = DRV_CTL_ISCSI_STOPPED_CMD; cp->ethdev->drv_ctl(dev->netdev, &info); -- cgit v0.10.2 From c5e06360317d9c7a91de983749d136c4089e5379 Mon Sep 17 00:00:00 2001 From: Dimitris Michailidis Date: Fri, 8 Apr 2011 13:06:25 -0700 Subject: cxgb4: drop phys_id interface and implement the newer set_phys_id Signed-off-by: Dimitris Michailidis Signed-off-by: David S. Miller diff --git a/drivers/net/cxgb4/cxgb4_main.c b/drivers/net/cxgb4/cxgb4_main.c index 5352c8a..0af9c9f 100644 --- a/drivers/net/cxgb4/cxgb4_main.c +++ b/drivers/net/cxgb4/cxgb4_main.c @@ -1336,15 +1336,20 @@ static int restart_autoneg(struct net_device *dev) return 0; } -static int identify_port(struct net_device *dev, u32 data) +static int identify_port(struct net_device *dev, + enum ethtool_phys_id_state state) { + unsigned int val; struct adapter *adap = netdev2adap(dev); - if (data == 0) - data = 2; /* default to 2 seconds */ + if (state == ETHTOOL_ID_ACTIVE) + val = 0xffff; + else if (state == ETHTOOL_ID_INACTIVE) + val = 0; + else + return -EINVAL; - return t4_identify_port(adap, adap->fn, netdev2pinfo(dev)->viid, - data * 5); + return t4_identify_port(adap, adap->fn, netdev2pinfo(dev)->viid, val); } static unsigned int from_fw_linkcaps(unsigned int type, unsigned int caps) @@ -2011,7 +2016,7 @@ static struct ethtool_ops cxgb_ethtool_ops = { .set_sg = ethtool_op_set_sg, .get_link = ethtool_op_get_link, .get_strings = get_strings, - .phys_id = identify_port, + .set_phys_id = identify_port, .nway_reset = restart_autoneg, .get_sset_count = get_sset_count, .get_ethtool_stats = get_stats, -- cgit v0.10.2 From 857a3d0fb648b450de4a87cc2df9055774cafd2d Mon Sep 17 00:00:00 2001 From: Dimitris Michailidis Date: Fri, 8 Apr 2011 13:07:08 -0700 Subject: cxgb4vf: drop phys_id interface and implement the newer set_phys_id Signed-off-by: Dimitris Michailidis Signed-off-by: David S. Miller diff --git a/drivers/net/cxgb4vf/cxgb4vf_main.c b/drivers/net/cxgb4vf/cxgb4vf_main.c index 6aad64d..b0d037e 100644 --- a/drivers/net/cxgb4vf/cxgb4vf_main.c +++ b/drivers/net/cxgb4vf/cxgb4vf_main.c @@ -1352,11 +1352,20 @@ static int cxgb4vf_set_rx_csum(struct net_device *dev, u32 csum) /* * Identify the port by blinking the port's LED. */ -static int cxgb4vf_phys_id(struct net_device *dev, u32 id) +static int cxgb4vf_phys_id(struct net_device *dev, + enum ethtool_phys_id_state state) { + unsigned int val; struct port_info *pi = netdev_priv(dev); - return t4vf_identify_port(pi->adapter, pi->viid, 5); + if (state == ETHTOOL_ID_ACTIVE) + val = 0xffff; + else if (state == ETHTOOL_ID_INACTIVE) + val = 0; + else + return -EINVAL; + + return t4vf_identify_port(pi->adapter, pi->viid, val); } /* @@ -1588,7 +1597,7 @@ static struct ethtool_ops cxgb4vf_ethtool_ops = { .set_sg = ethtool_op_set_sg, .get_link = ethtool_op_get_link, .get_strings = cxgb4vf_get_strings, - .phys_id = cxgb4vf_phys_id, + .set_phys_id = cxgb4vf_phys_id, .get_sset_count = cxgb4vf_get_sset_count, .get_ethtool_stats = cxgb4vf_get_ethtool_stats, .get_regs_len = cxgb4vf_get_regs_len, -- cgit v0.10.2 From b9cbfcbe260c43bac3a6d941b095cc4dcf70e614 Mon Sep 17 00:00:00 2001 From: Jassi Brar Date: Fri, 8 Apr 2011 11:29:42 +0530 Subject: MAINTAINERS: Update Samsung ASoC maintainer's id Signed-off-by: Jassi Brar Acked-by: Liam Girdwood Signed-off-by: Mark Brown diff --git a/MAINTAINERS b/MAINTAINERS index 6b4b9cd..c4fb13f 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -5390,7 +5390,7 @@ F: drivers/media/video/*7146* F: include/media/*7146* SAMSUNG AUDIO (ASoC) DRIVERS -M: Jassi Brar +M: Jassi Brar L: alsa-devel@alsa-project.org (moderated for non-subscribers) S: Supported F: sound/soc/samsung -- cgit v0.10.2 From 6e4d2d9eb22dc9e9f0abfb1a464405b97a461cde Mon Sep 17 00:00:00 2001 From: simon Date: Wed, 6 Apr 2011 21:40:13 +0000 Subject: usb: plusb: Whitespace This patch cleans up a couple of instances of incorrect whitespace Signed-off-by: Simon Wood Signed-off-by: David S. Miller diff --git a/drivers/net/usb/plusb.c b/drivers/net/usb/plusb.c index 823c537..2fe1bb5 100644 --- a/drivers/net/usb/plusb.c +++ b/drivers/net/usb/plusb.c @@ -134,13 +134,13 @@ static struct usb_driver plusb_driver = { static int __init plusb_init(void) { - return usb_register(&plusb_driver); + return usb_register(&plusb_driver); } module_init(plusb_init); static void __exit plusb_exit(void) { - usb_deregister(&plusb_driver); + usb_deregister(&plusb_driver); } module_exit(plusb_exit); -- cgit v0.10.2 From 647da406e5e6cef87d17ee4d3c65c7b496883a3f Mon Sep 17 00:00:00 2001 From: simon Date: Wed, 6 Apr 2011 21:40:14 +0000 Subject: usb: plusb: Add support for PL-25A1 This patch adds support for the PL-25A1 by adding the appropriate USB ID's. This chip is used in the Belkin 'Windows Easy Transfer' Cables. Signed-off-by: Simon Wood Signed-off-by: David S. Miller diff --git a/drivers/net/usb/Kconfig b/drivers/net/usb/Kconfig index 3ec22c3..9d4f911 100644 --- a/drivers/net/usb/Kconfig +++ b/drivers/net/usb/Kconfig @@ -258,7 +258,7 @@ config USB_NET_NET1080 optionally with LEDs that indicate traffic config USB_NET_PLUSB - tristate "Prolific PL-2301/2302 based cables" + tristate "Prolific PL-2301/2302/25A1 based cables" # if the handshake/init/reset problems, from original 'plusb', # are ever resolved ... then remove "experimental" depends on USB_USBNET && EXPERIMENTAL diff --git a/drivers/net/usb/plusb.c b/drivers/net/usb/plusb.c index 2fe1bb5..f46aa07 100644 --- a/drivers/net/usb/plusb.c +++ b/drivers/net/usb/plusb.c @@ -45,6 +45,14 @@ * seems to get wedged under load. Prolific docs are weak, and * don't identify differences between PL2301 and PL2302, much less * anything to explain the different PL2302 versions observed. + * + * NOTE: pl2501 has several modes, including pl2301 and pl2302 + * compatibility. Some docs suggest the difference between 2301 + * and 2302 is only to make MS-Windows use a different driver... + * + * pl25a1 glue based on patch from Tony Gibbs. Prolific "docs" on + * this chip are as usual incomplete about what control messages + * are supported. */ /* @@ -95,7 +103,7 @@ static int pl_reset(struct usbnet *dev) } static const struct driver_info prolific_info = { - .description = "Prolific PL-2301/PL-2302", + .description = "Prolific PL-2301/PL-2302/PL-25A1", .flags = FLAG_POINTTOPOINT | FLAG_NO_SETINT, /* some PL-2302 versions seem to fail usb_set_interface() */ .reset = pl_reset, @@ -111,6 +119,7 @@ static const struct driver_info prolific_info = { static const struct usb_device_id products [] = { +/* full speed cables */ { USB_DEVICE(0x067b, 0x0000), // PL-2301 .driver_info = (unsigned long) &prolific_info, @@ -119,6 +128,15 @@ static const struct usb_device_id products [] = { .driver_info = (unsigned long) &prolific_info, }, +/* high speed cables */ +{ + USB_DEVICE(0x067b, 0x25a1), /* PL-25A1, no eeprom */ + .driver_info = (unsigned long) &prolific_info, +}, { + USB_DEVICE(0x050d, 0x258a), /* Belkin F5U258/F5U279 (PL-25A1) */ + .driver_info = (unsigned long) &prolific_info, +}, + { }, // END }; MODULE_DEVICE_TABLE(usb, products); @@ -145,5 +163,5 @@ static void __exit plusb_exit(void) module_exit(plusb_exit); MODULE_AUTHOR("David Brownell"); -MODULE_DESCRIPTION("Prolific PL-2301/2302 USB Host to Host Link Driver"); +MODULE_DESCRIPTION("Prolific PL-2301/2302/25A1 USB Host to Host Link Driver"); MODULE_LICENSE("GPL"); -- cgit v0.10.2 From 5325e92f33eef5fb54e2e63185d965b4be59a4b3 Mon Sep 17 00:00:00 2001 From: simon Date: Wed, 6 Apr 2011 21:40:15 +0000 Subject: usb: plusb: Add debug to reset function This patch adds some debug to the reset function to print out the reason why it fails. Signed-off-by: Simon Wood Signed-off-by: David S. Miller diff --git a/drivers/net/usb/plusb.c b/drivers/net/usb/plusb.c index f46aa07..217aec8 100644 --- a/drivers/net/usb/plusb.c +++ b/drivers/net/usb/plusb.c @@ -94,11 +94,15 @@ pl_set_QuickLink_features(struct usbnet *dev, int val) static int pl_reset(struct usbnet *dev) { + int status; + /* some units seem to need this reset, others reject it utterly. * FIXME be more like "naplink" or windows drivers. */ - (void) pl_set_QuickLink_features(dev, + status = pl_set_QuickLink_features(dev, PL_S_EN|PL_RESET_OUT|PL_RESET_IN|PL_PEER_E); + if (status != 0 && netif_msg_probe(dev)) + netif_dbg(dev, link, dev->net, "pl_reset --> %d\n", status); return 0; } -- cgit v0.10.2 From 5c04c819a20af40adb7d282199f4e34e14fa05c5 Mon Sep 17 00:00:00 2001 From: Michael Smith Date: Thu, 7 Apr 2011 04:51:50 +0000 Subject: fib_validate_source(): pass sk_buff instead of mark This makes sk_buff available for other use in fib_validate_source(). Signed-off-by: Michael Smith Signed-off-by: David S. Miller diff --git a/include/net/ip_fib.h b/include/net/ip_fib.h index e5d66ec..514627f 100644 --- a/include/net/ip_fib.h +++ b/include/net/ip_fib.h @@ -227,9 +227,9 @@ extern struct fib_table *fib_get_table(struct net *net, u32 id); /* Exported by fib_frontend.c */ extern const struct nla_policy rtm_ipv4_policy[]; extern void ip_fib_init(void); -extern int fib_validate_source(__be32 src, __be32 dst, u8 tos, int oif, - struct net_device *dev, __be32 *spec_dst, - u32 *itag, u32 mark); +extern int fib_validate_source(struct sk_buff *skb, __be32 src, __be32 dst, + u8 tos, int oif, struct net_device *dev, + __be32 *spec_dst, u32 *itag); extern void fib_select_default(struct fib_result *res); /* Exported by fib_semantics.c */ diff --git a/net/ipv4/fib_frontend.c b/net/ipv4/fib_frontend.c index 4510883..f162f84 100644 --- a/net/ipv4/fib_frontend.c +++ b/net/ipv4/fib_frontend.c @@ -188,9 +188,9 @@ EXPORT_SYMBOL(inet_dev_addr_type); * - check, that packet arrived from expected physical interface. * called with rcu_read_lock() */ -int fib_validate_source(__be32 src, __be32 dst, u8 tos, int oif, - struct net_device *dev, __be32 *spec_dst, - u32 *itag, u32 mark) +int fib_validate_source(struct sk_buff *skb, __be32 src, __be32 dst, u8 tos, + int oif, struct net_device *dev, __be32 *spec_dst, + u32 *itag) { struct in_device *in_dev; struct flowi4 fl4; @@ -202,7 +202,6 @@ int fib_validate_source(__be32 src, __be32 dst, u8 tos, int oif, fl4.flowi4_oif = 0; fl4.flowi4_iif = oif; - fl4.flowi4_mark = mark; fl4.daddr = src; fl4.saddr = dst; fl4.flowi4_tos = tos; @@ -214,8 +213,7 @@ int fib_validate_source(__be32 src, __be32 dst, u8 tos, int oif, no_addr = in_dev->ifa_list == NULL; rpf = IN_DEV_RPFILTER(in_dev); accept_local = IN_DEV_ACCEPT_LOCAL(in_dev); - if (mark && !IN_DEV_SRC_VMARK(in_dev)) - fl4.flowi4_mark = 0; + fl4.flowi4_mark = IN_DEV_SRC_VMARK(in_dev) ? skb->mark : 0; } if (in_dev == NULL) diff --git a/net/ipv4/route.c b/net/ipv4/route.c index 1628be5..052c912 100644 --- a/net/ipv4/route.c +++ b/net/ipv4/route.c @@ -1871,8 +1871,8 @@ static int ip_route_input_mc(struct sk_buff *skb, __be32 daddr, __be32 saddr, goto e_inval; spec_dst = inet_select_addr(dev, 0, RT_SCOPE_LINK); } else { - err = fib_validate_source(saddr, 0, tos, 0, dev, &spec_dst, - &itag, 0); + err = fib_validate_source(skb, saddr, 0, tos, 0, dev, &spec_dst, + &itag); if (err < 0) goto e_err; } @@ -1981,8 +1981,8 @@ static int __mkroute_input(struct sk_buff *skb, } - err = fib_validate_source(saddr, daddr, tos, FIB_RES_OIF(*res), - in_dev->dev, &spec_dst, &itag, skb->mark); + err = fib_validate_source(skb, saddr, daddr, tos, FIB_RES_OIF(*res), + in_dev->dev, &spec_dst, &itag); if (err < 0) { ip_handle_martian_source(in_dev->dev, in_dev, skb, daddr, saddr); @@ -2150,9 +2150,9 @@ static int ip_route_input_slow(struct sk_buff *skb, __be32 daddr, __be32 saddr, goto brd_input; if (res.type == RTN_LOCAL) { - err = fib_validate_source(saddr, daddr, tos, + err = fib_validate_source(skb, saddr, daddr, tos, net->loopback_dev->ifindex, - dev, &spec_dst, &itag, skb->mark); + dev, &spec_dst, &itag); if (err < 0) goto martian_source_keep_err; if (err) @@ -2176,8 +2176,8 @@ brd_input: if (ipv4_is_zeronet(saddr)) spec_dst = inet_select_addr(dev, 0, RT_SCOPE_LINK); else { - err = fib_validate_source(saddr, 0, tos, 0, dev, &spec_dst, - &itag, skb->mark); + err = fib_validate_source(skb, saddr, 0, tos, 0, dev, &spec_dst, + &itag); if (err < 0) goto martian_source_keep_err; if (err) -- cgit v0.10.2 From 990078afbf90e0175e71da2df04595b99153514c Mon Sep 17 00:00:00 2001 From: Michael Smith Date: Thu, 7 Apr 2011 04:51:51 +0000 Subject: Disable rp_filter for IPsec packets The reverse path filter interferes with IPsec subnet-to-subnet tunnels, especially when the link to the IPsec peer is on an interface other than the one hosting the default route. With dynamic routing, where the peer might be reachable through eth0 today and eth1 tomorrow, it's difficult to keep rp_filter enabled unless fake routes to the remote subnets are configured on the interface currently used to reach the peer. IPsec provides a much stronger anti-spoofing policy than rp_filter, so this patch disables the rp_filter for packets with a security path. Signed-off-by: Michael Smith Signed-off-by: David S. Miller diff --git a/include/net/xfrm.h b/include/net/xfrm.h index 6ae4bc5..65ea313 100644 --- a/include/net/xfrm.h +++ b/include/net/xfrm.h @@ -957,6 +957,15 @@ struct sec_path { struct xfrm_state *xvec[XFRM_MAX_DEPTH]; }; +static inline int secpath_exists(struct sk_buff *skb) +{ +#ifdef CONFIG_XFRM + return skb->sp != NULL; +#else + return 0; +#endif +} + static inline struct sec_path * secpath_get(struct sec_path *sp) { diff --git a/net/ipv4/fib_frontend.c b/net/ipv4/fib_frontend.c index f162f84..2252471 100644 --- a/net/ipv4/fib_frontend.c +++ b/net/ipv4/fib_frontend.c @@ -44,6 +44,7 @@ #include #include #include +#include #ifndef CONFIG_IP_MULTIPLE_TABLES @@ -211,7 +212,10 @@ int fib_validate_source(struct sk_buff *skb, __be32 src, __be32 dst, u8 tos, in_dev = __in_dev_get_rcu(dev); if (in_dev) { no_addr = in_dev->ifa_list == NULL; - rpf = IN_DEV_RPFILTER(in_dev); + + /* Ignore rp_filter for packets protected by IPsec. */ + rpf = secpath_exists(skb) ? 0 : IN_DEV_RPFILTER(in_dev); + accept_local = IN_DEV_ACCEPT_LOCAL(in_dev); fl4.flowi4_mark = IN_DEV_SRC_VMARK(in_dev) ? skb->mark : 0; } -- cgit v0.10.2 From 4e01d2d1cac683477b539b40b7b4662d6a9c436f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Miros=C5=82aw?= Date: Fri, 8 Apr 2011 02:38:46 +0000 Subject: net: Remove invalid offloads MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Remove offload changing ethtool ops which drivers don't really support: - fs_enet - ucc_geth Signed-off-by: MichaÅ‚ MirosÅ‚aw Signed-off-by: David S. Miller diff --git a/drivers/net/fs_enet/fs_enet-main.c b/drivers/net/fs_enet/fs_enet-main.c index 24cb953..a938894 100644 --- a/drivers/net/fs_enet/fs_enet-main.c +++ b/drivers/net/fs_enet/fs_enet-main.c @@ -956,8 +956,6 @@ static const struct ethtool_ops fs_ethtool_ops = { .get_link = ethtool_op_get_link, .get_msglevel = fs_get_msglevel, .set_msglevel = fs_set_msglevel, - .set_tx_csum = ethtool_op_set_tx_csum, /* local! */ - .set_sg = ethtool_op_set_sg, .get_regs = fs_get_regs, }; diff --git a/drivers/net/ucc_geth_ethtool.c b/drivers/net/ucc_geth_ethtool.c index 6f92e48..537fbc0a 100644 --- a/drivers/net/ucc_geth_ethtool.c +++ b/drivers/net/ucc_geth_ethtool.c @@ -410,7 +410,6 @@ static const struct ethtool_ops uec_ethtool_ops = { .set_ringparam = uec_set_ringparam, .get_pauseparam = uec_get_pauseparam, .set_pauseparam = uec_set_pauseparam, - .set_sg = ethtool_op_set_sg, .get_sset_count = uec_get_sset_count, .get_strings = uec_get_strings, .get_ethtool_stats = uec_get_ethtool_stats, -- cgit v0.10.2 From 8b8ddc68df13032a5666438b48dfb7a86de3a610 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Miros=C5=82aw?= Date: Fri, 8 Apr 2011 02:38:47 +0000 Subject: net: benet: convert to hw_features - fixup MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fix up after merge with NETIF_F_RXHASH implementation. This allows to toggle NETIF_F_RXHASH and NETIF_F_HW_VLAN_TX. Signed-off-by: MichaÅ‚ MirosÅ‚aw Signed-off-by: David S. Miller diff --git a/drivers/net/benet/be_main.c b/drivers/net/benet/be_main.c index 58a652f..289c73a 100644 --- a/drivers/net/benet/be_main.c +++ b/drivers/net/benet/be_main.c @@ -2629,14 +2629,13 @@ static void be_netdev_init(struct net_device *netdev) int i; netdev->hw_features |= NETIF_F_SG | NETIF_F_TSO | NETIF_F_TSO6 | - NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM | NETIF_F_RXCSUM; + NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM | NETIF_F_RXCSUM | + NETIF_F_HW_VLAN_TX; + if (be_multi_rxq(adapter)) + netdev->hw_features |= NETIF_F_RXHASH; netdev->features |= netdev->hw_features | - NETIF_F_HW_VLAN_RX | NETIF_F_HW_VLAN_TX | - NETIF_F_HW_VLAN_FILTER; - - if (be_multi_rxq(adapter)) - netdev->features |= NETIF_F_RXHASH; + NETIF_F_HW_VLAN_RX | NETIF_F_HW_VLAN_FILTER; netdev->vlan_features |= NETIF_F_SG | NETIF_F_TSO | NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM; -- cgit v0.10.2 From 350fb32ae45ec74ea9cc117c728c48b8e840f0f9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Miros=C5=82aw?= Date: Fri, 8 Apr 2011 06:35:56 +0000 Subject: net: r8169: convert to hw_features MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Simple conversion with a bit of needed cleanup. This also fixes: - confusion around vlan_features in rtl8169_vlan_mode(), - problem with broken TSO for too big MTU (the limit is set at 0xFFF --- max MSS field value). SG+IP_CSUM+TSO is left disabled by default, based on suggestion by David Dillow. Signed-off-by: MichaÅ‚ MirosÅ‚aw Signed-off-by: David S. Miller diff --git a/drivers/net/r8169.c b/drivers/net/r8169.c index caa99cd..058524f 100644 --- a/drivers/net/r8169.c +++ b/drivers/net/r8169.c @@ -1286,14 +1286,15 @@ static int rtl8169_set_settings(struct net_device *dev, struct ethtool_cmd *cmd) return ret; } -static u32 rtl8169_get_rx_csum(struct net_device *dev) +static u32 rtl8169_fix_features(struct net_device *dev, u32 features) { - struct rtl8169_private *tp = netdev_priv(dev); + if (dev->mtu > MSSMask) + features &= ~NETIF_F_ALL_TSO; - return tp->cp_cmd & RxChkSum; + return features; } -static int rtl8169_set_rx_csum(struct net_device *dev, u32 data) +static int rtl8169_set_features(struct net_device *dev, u32 features) { struct rtl8169_private *tp = netdev_priv(dev); void __iomem *ioaddr = tp->mmio_addr; @@ -1301,11 +1302,16 @@ static int rtl8169_set_rx_csum(struct net_device *dev, u32 data) spin_lock_irqsave(&tp->lock, flags); - if (data) + if (features & NETIF_F_RXCSUM) tp->cp_cmd |= RxChkSum; else tp->cp_cmd &= ~RxChkSum; + if (dev->features & NETIF_F_HW_VLAN_RX) + tp->cp_cmd |= RxVlan; + else + tp->cp_cmd &= ~RxVlan; + RTL_W16(CPlusCmd, tp->cp_cmd); RTL_R16(CPlusCmd); @@ -1321,27 +1327,6 @@ static inline u32 rtl8169_tx_vlan_tag(struct rtl8169_private *tp, TxVlanTag | swab16(vlan_tx_tag_get(skb)) : 0x00; } -#define NETIF_F_HW_VLAN_TX_RX (NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX) - -static void rtl8169_vlan_mode(struct net_device *dev) -{ - struct rtl8169_private *tp = netdev_priv(dev); - void __iomem *ioaddr = tp->mmio_addr; - unsigned long flags; - - spin_lock_irqsave(&tp->lock, flags); - if (dev->features & NETIF_F_HW_VLAN_RX) - tp->cp_cmd |= RxVlan; - else - tp->cp_cmd &= ~RxVlan; - RTL_W16(CPlusCmd, tp->cp_cmd); - /* PCI commit */ - RTL_R16(CPlusCmd); - spin_unlock_irqrestore(&tp->lock, flags); - - dev->vlan_features = dev->features &~ NETIF_F_HW_VLAN_TX_RX; -} - static void rtl8169_rx_vlan_tag(struct RxDesc *desc, struct sk_buff *skb) { u32 opts2 = le32_to_cpu(desc->opts2); @@ -1522,28 +1507,6 @@ static void rtl8169_get_strings(struct net_device *dev, u32 stringset, u8 *data) } } -static int rtl8169_set_flags(struct net_device *dev, u32 data) -{ - struct rtl8169_private *tp = netdev_priv(dev); - unsigned long old_feat = dev->features; - int rc; - - if ((tp->mac_version == RTL_GIGA_MAC_VER_05) && - !(data & ETH_FLAG_RXVLAN)) { - netif_info(tp, drv, dev, "8110SCd requires hardware Rx VLAN\n"); - return -EINVAL; - } - - rc = ethtool_op_set_flags(dev, data, ETH_FLAG_TXVLAN | ETH_FLAG_RXVLAN); - if (rc) - return rc; - - if ((old_feat ^ dev->features) & NETIF_F_HW_VLAN_RX) - rtl8169_vlan_mode(dev); - - return 0; -} - static const struct ethtool_ops rtl8169_ethtool_ops = { .get_drvinfo = rtl8169_get_drvinfo, .get_regs_len = rtl8169_get_regs_len, @@ -1552,19 +1515,12 @@ static const struct ethtool_ops rtl8169_ethtool_ops = { .set_settings = rtl8169_set_settings, .get_msglevel = rtl8169_get_msglevel, .set_msglevel = rtl8169_set_msglevel, - .get_rx_csum = rtl8169_get_rx_csum, - .set_rx_csum = rtl8169_set_rx_csum, - .set_tx_csum = ethtool_op_set_tx_csum, - .set_sg = ethtool_op_set_sg, - .set_tso = ethtool_op_set_tso, .get_regs = rtl8169_get_regs, .get_wol = rtl8169_get_wol, .set_wol = rtl8169_set_wol, .get_strings = rtl8169_get_strings, .get_sset_count = rtl8169_get_sset_count, .get_ethtool_stats = rtl8169_get_ethtool_stats, - .set_flags = rtl8169_set_flags, - .get_flags = ethtool_op_get_flags, }; static void rtl8169_get_mac_version(struct rtl8169_private *tp, @@ -2979,6 +2935,8 @@ static const struct net_device_ops rtl8169_netdev_ops = { .ndo_tx_timeout = rtl8169_tx_timeout, .ndo_validate_addr = eth_validate_addr, .ndo_change_mtu = rtl8169_change_mtu, + .ndo_fix_features = rtl8169_fix_features, + .ndo_set_features = rtl8169_set_features, .ndo_set_mac_address = rtl_set_mac_address, .ndo_do_ioctl = rtl8169_ioctl, .ndo_set_multicast_list = rtl_set_rx_mode, @@ -3425,7 +3383,19 @@ rtl8169_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) netif_napi_add(dev, &tp->napi, rtl8169_poll, R8169_NAPI_WEIGHT); - dev->features |= NETIF_F_HW_VLAN_TX_RX | NETIF_F_GRO; + /* don't enable SG, IP_CSUM and TSO by default - it might not work + * properly for all devices */ + dev->features |= NETIF_F_RXCSUM | + NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX; + + dev->hw_features = NETIF_F_SG | NETIF_F_IP_CSUM | NETIF_F_TSO | + NETIF_F_RXCSUM | NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX; + dev->vlan_features = NETIF_F_SG | NETIF_F_IP_CSUM | NETIF_F_TSO | + NETIF_F_HIGHDMA; + + if (tp->mac_version == RTL_GIGA_MAC_VER_05) + /* 8110SCd requires hardware Rx VLAN - disallow toggling */ + dev->hw_features &= ~NETIF_F_HW_VLAN_RX; tp->intr_mask = 0xffff; tp->hw_start = cfg->hw_start; @@ -3545,7 +3515,7 @@ static int rtl8169_open(struct net_device *dev) rtl8169_init_phy(dev, tp); - rtl8169_vlan_mode(dev); + rtl8169_set_features(dev, dev->features); rtl_pll_power_up(tp); @@ -4318,6 +4288,8 @@ static int rtl8169_change_mtu(struct net_device *dev, int new_mtu) return -EINVAL; dev->mtu = new_mtu; + netdev_update_features(dev); + return 0; } @@ -4642,12 +4614,11 @@ err_out: static inline u32 rtl8169_tso_csum(struct sk_buff *skb, struct net_device *dev) { - if (dev->features & NETIF_F_TSO) { - u32 mss = skb_shinfo(skb)->gso_size; + u32 mss = skb_shinfo(skb)->gso_size; + + if (mss) + return LargeSend | ((mss & MSSMask) << MSSShift); - if (mss) - return LargeSend | ((mss & MSSMask) << MSSShift); - } if (skb->ip_summed == CHECKSUM_PARTIAL) { const struct iphdr *ip = ip_hdr(skb); -- cgit v0.10.2 From 044a890c5a0fb7ac60c70bbb4e1b79e59272e504 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Miros=C5=82aw?= Date: Sat, 9 Apr 2011 00:58:18 +0000 Subject: net: 8139cp: convert to hw_features MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: MichaÅ‚ MirosÅ‚aw Signed-off-by: David S. Miller diff --git a/drivers/net/8139cp.c b/drivers/net/8139cp.c index dd16e83..10c4505 100644 --- a/drivers/net/8139cp.c +++ b/drivers/net/8139cp.c @@ -758,8 +758,7 @@ static netdev_tx_t cp_start_xmit (struct sk_buff *skb, entry = cp->tx_head; eor = (entry == (CP_TX_RING_SIZE - 1)) ? RingEnd : 0; - if (dev->features & NETIF_F_TSO) - mss = skb_shinfo(skb)->gso_size; + mss = skb_shinfo(skb)->gso_size; if (skb_shinfo(skb)->nr_frags == 0) { struct cp_desc *txd = &cp->tx_ring[entry]; @@ -1416,32 +1415,23 @@ static void cp_set_msglevel(struct net_device *dev, u32 value) cp->msg_enable = value; } -static u32 cp_get_rx_csum(struct net_device *dev) +static int cp_set_features(struct net_device *dev, u32 features) { struct cp_private *cp = netdev_priv(dev); - return (cpr16(CpCmd) & RxChkSum) ? 1 : 0; -} + unsigned long flags; -static int cp_set_rx_csum(struct net_device *dev, u32 data) -{ - struct cp_private *cp = netdev_priv(dev); - u16 cmd = cp->cpcmd, newcmd; + if (!((dev->features ^ features) & NETIF_F_RXCSUM)) + return 0; - newcmd = cmd; + spin_lock_irqsave(&cp->lock, flags); - if (data) - newcmd |= RxChkSum; + if (features & NETIF_F_RXCSUM) + cp->cpcmd |= RxChkSum; else - newcmd &= ~RxChkSum; - - if (newcmd != cmd) { - unsigned long flags; + cp->cpcmd &= ~RxChkSum; - spin_lock_irqsave(&cp->lock, flags); - cp->cpcmd = newcmd; - cpw16_f(CpCmd, newcmd); - spin_unlock_irqrestore(&cp->lock, flags); - } + cpw16_f(CpCmd, cp->cpcmd); + spin_unlock_irqrestore(&cp->lock, flags); return 0; } @@ -1554,11 +1544,6 @@ static const struct ethtool_ops cp_ethtool_ops = { .get_link = ethtool_op_get_link, .get_msglevel = cp_get_msglevel, .set_msglevel = cp_set_msglevel, - .get_rx_csum = cp_get_rx_csum, - .set_rx_csum = cp_set_rx_csum, - .set_tx_csum = ethtool_op_set_tx_csum, /* local! */ - .set_sg = ethtool_op_set_sg, - .set_tso = ethtool_op_set_tso, .get_regs = cp_get_regs, .get_wol = cp_get_wol, .set_wol = cp_set_wol, @@ -1831,6 +1816,7 @@ static const struct net_device_ops cp_netdev_ops = { .ndo_do_ioctl = cp_ioctl, .ndo_start_xmit = cp_start_xmit, .ndo_tx_timeout = cp_tx_timeout, + .ndo_set_features = cp_set_features, #if CP_VLAN_TAG_USED .ndo_vlan_rx_register = cp_vlan_rx_register, #endif @@ -1934,6 +1920,9 @@ static int cp_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) cp->cpcmd = (pci_using_dac ? PCIDAC : 0) | PCIMulRW | RxChkSum | CpRxOn | CpTxOn; + dev->features |= NETIF_F_RXCSUM; + dev->hw_features |= NETIF_F_RXCSUM; + regs = ioremap(pciaddr, CP_REGS_SIZE); if (!regs) { rc = -EIO; @@ -1966,9 +1955,8 @@ static int cp_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) if (pci_using_dac) dev->features |= NETIF_F_HIGHDMA; -#if 0 /* disabled by default until verified */ - dev->features |= NETIF_F_TSO; -#endif + /* disabled by default until verified */ + dev->hw_features |= NETIF_F_SG | NETIF_F_IP_CSUM | NETIF_F_TSO; dev->irq = pdev->irq; -- cgit v0.10.2 From 5e982f3bfdd5d063f8806a26c87843496a35d26b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Miros=C5=82aw?= Date: Sat, 9 Apr 2011 02:46:55 +0000 Subject: net: stmmac: convert to hw_features MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This also removes TSO as it's made fully in software --- better to leave this to networking core. If the MAC features can be detected at probe time and not at open, then stmmac_fix_features could be simplified by limiting hw_features. That's also better for users as they don't see offloads being togglable but never turned on. Redundant fallbacks for TX csum are removed as it's already handled by network core. Signed-off-by: MichaÅ‚ MirosÅ‚aw Signed-off-by: David S. Miller diff --git a/drivers/net/stmmac/stmmac_ethtool.c b/drivers/net/stmmac/stmmac_ethtool.c index fd719ed..156a805 100644 --- a/drivers/net/stmmac/stmmac_ethtool.c +++ b/drivers/net/stmmac/stmmac_ethtool.c @@ -197,13 +197,6 @@ static void stmmac_ethtool_gregs(struct net_device *dev, } } -static u32 stmmac_ethtool_get_rx_csum(struct net_device *dev) -{ - struct stmmac_priv *priv = netdev_priv(dev); - - return priv->rx_coe; -} - static void stmmac_get_pauseparam(struct net_device *netdev, struct ethtool_pauseparam *pause) @@ -358,11 +351,6 @@ static struct ethtool_ops stmmac_ethtool_ops = { .get_regs = stmmac_ethtool_gregs, .get_regs_len = stmmac_ethtool_get_regs_len, .get_link = ethtool_op_get_link, - .get_rx_csum = stmmac_ethtool_get_rx_csum, - .get_tx_csum = ethtool_op_get_tx_csum, - .set_tx_csum = ethtool_op_set_tx_ipv6_csum, - .get_sg = ethtool_op_get_sg, - .set_sg = ethtool_op_set_sg, .get_pauseparam = stmmac_get_pauseparam, .set_pauseparam = stmmac_set_pauseparam, .get_ethtool_stats = stmmac_get_ethtool_stats, @@ -370,8 +358,6 @@ static struct ethtool_ops stmmac_ethtool_ops = { .get_wol = stmmac_get_wol, .set_wol = stmmac_set_wol, .get_sset_count = stmmac_get_sset_count, - .get_tso = ethtool_op_get_tso, - .set_tso = ethtool_op_set_tso, }; void stmmac_set_ethtool_ops(struct net_device *netdev) diff --git a/drivers/net/stmmac/stmmac_main.c b/drivers/net/stmmac/stmmac_main.c index 0e5f031..62fa51e 100644 --- a/drivers/net/stmmac/stmmac_main.c +++ b/drivers/net/stmmac/stmmac_main.c @@ -139,7 +139,6 @@ static const u32 default_msg_level = (NETIF_MSG_DRV | NETIF_MSG_PROBE | NETIF_MSG_IFDOWN | NETIF_MSG_TIMER); static irqreturn_t stmmac_interrupt(int irq, void *dev_id); -static netdev_tx_t stmmac_xmit(struct sk_buff *skb, struct net_device *dev); /** * stmmac_verify_args - verify the driver parameters. @@ -843,6 +842,7 @@ static int stmmac_open(struct net_device *dev) pr_info("stmmac: Rx Checksum Offload Engine supported\n"); if (priv->plat->tx_coe) pr_info("\tTX Checksum insertion supported\n"); + netdev_update_features(dev); /* Initialise the MMC (if present) to disable all interrupts. */ writel(0xffffffff, priv->ioaddr + MMC_HIGH_INTR_MASK); @@ -927,46 +927,6 @@ static int stmmac_release(struct net_device *dev) return 0; } -/* - * To perform emulated hardware segmentation on skb. - */ -static int stmmac_sw_tso(struct stmmac_priv *priv, struct sk_buff *skb) -{ - struct sk_buff *segs, *curr_skb; - int gso_segs = skb_shinfo(skb)->gso_segs; - - /* Estimate the number of fragments in the worst case */ - if (unlikely(stmmac_tx_avail(priv) < gso_segs)) { - netif_stop_queue(priv->dev); - TX_DBG(KERN_ERR "%s: TSO BUG! Tx Ring full when queue awake\n", - __func__); - if (stmmac_tx_avail(priv) < gso_segs) - return NETDEV_TX_BUSY; - - netif_wake_queue(priv->dev); - } - TX_DBG("\tstmmac_sw_tso: segmenting: skb %p (len %d)\n", - skb, skb->len); - - segs = skb_gso_segment(skb, priv->dev->features & ~NETIF_F_TSO); - if (IS_ERR(segs)) - goto sw_tso_end; - - do { - curr_skb = segs; - segs = segs->next; - TX_DBG("\t\tcurrent skb->len: %d, *curr %p," - "*next %p\n", curr_skb->len, curr_skb, segs); - curr_skb->next = NULL; - stmmac_xmit(curr_skb, priv->dev); - } while (segs); - -sw_tso_end: - dev_kfree_skb(skb); - - return NETDEV_TX_OK; -} - static unsigned int stmmac_handle_jumbo_frames(struct sk_buff *skb, struct net_device *dev, int csum_insertion) @@ -1044,16 +1004,7 @@ static netdev_tx_t stmmac_xmit(struct sk_buff *skb, struct net_device *dev) !skb_is_gso(skb) ? "isn't" : "is"); #endif - if (unlikely(skb_is_gso(skb))) - return stmmac_sw_tso(priv, skb); - - if (likely((skb->ip_summed == CHECKSUM_PARTIAL))) { - if (unlikely((!priv->plat->tx_coe) || - (priv->no_csum_insertion))) - skb_checksum_help(skb); - else - csum_insertion = 1; - } + csum_insertion = (skb->ip_summed == CHECKSUM_PARTIAL); desc = priv->dma_tx + entry; first = desc; @@ -1373,18 +1324,29 @@ static int stmmac_change_mtu(struct net_device *dev, int new_mtu) return -EINVAL; } + dev->mtu = new_mtu; + netdev_update_features(dev); + + return 0; +} + +static u32 stmmac_fix_features(struct net_device *dev, u32 features) +{ + struct stmmac_priv *priv = netdev_priv(dev); + + if (!priv->rx_coe) + features &= ~NETIF_F_RXCSUM; + if (!priv->plat->tx_coe) + features &= ~NETIF_F_ALL_CSUM; + /* Some GMAC devices have a bugged Jumbo frame support that * needs to have the Tx COE disabled for oversized frames * (due to limited buffer sizes). In this case we disable * the TX csum insertionin the TDES and not use SF. */ - if ((priv->plat->bugged_jumbo) && (priv->dev->mtu > ETH_DATA_LEN)) - priv->no_csum_insertion = 1; - else - priv->no_csum_insertion = 0; + if (priv->plat->bugged_jumbo && (dev->mtu > ETH_DATA_LEN)) + features &= ~NETIF_F_ALL_CSUM; - dev->mtu = new_mtu; - - return 0; + return features; } static irqreturn_t stmmac_interrupt(int irq, void *dev_id) @@ -1464,6 +1426,7 @@ static const struct net_device_ops stmmac_netdev_ops = { .ndo_start_xmit = stmmac_xmit, .ndo_stop = stmmac_release, .ndo_change_mtu = stmmac_change_mtu, + .ndo_fix_features = stmmac_fix_features, .ndo_set_multicast_list = stmmac_multicast_list, .ndo_tx_timeout = stmmac_tx_timeout, .ndo_do_ioctl = stmmac_ioctl, @@ -1494,8 +1457,8 @@ static int stmmac_probe(struct net_device *dev) dev->netdev_ops = &stmmac_netdev_ops; stmmac_set_ethtool_ops(dev); - dev->features |= NETIF_F_SG | NETIF_F_HIGHDMA | - NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM; + dev->hw_features = NETIF_F_SG | NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM; + dev->features |= dev->hw_features | NETIF_F_HIGHDMA; dev->watchdog_timeo = msecs_to_jiffies(watchdog); #ifdef STMMAC_VLAN_TAG_USED /* Both mac100 and gmac support receive VLAN tag detection */ -- cgit v0.10.2 From e6a46416d4233c99a041ca35c1f692ecae9f942d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Miros=C5=82aw?= Date: Sun, 10 Apr 2011 03:13:21 +0000 Subject: net: ksz884x: convert to hw_features MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This also fixes possible race when changing receive checksum state and removes IPV6_CSUM_GEN_HACK as it's always set. BTW, The claim about fake IPV6 checksum looks dubious. If that were true, then there's a problem in networking core and should be fixed there and not in random drivers. BTW#2, there's no MAINTAINERS entry for this driver. I assume this driver is supported by Micrel? Signed-off-by: MichaÅ‚ MirosÅ‚aw Signed-off-by: David S. Miller diff --git a/drivers/net/ksz884x.c b/drivers/net/ksz884x.c index 7f7d570..2c37a38 100644 --- a/drivers/net/ksz884x.c +++ b/drivers/net/ksz884x.c @@ -1221,7 +1221,6 @@ struct ksz_port_info { #define LINK_INT_WORKING (1 << 0) #define SMALL_PACKET_TX_BUG (1 << 1) #define HALF_DUPLEX_SIGNAL_BUG (1 << 2) -#define IPV6_CSUM_GEN_HACK (1 << 3) #define RX_HUGE_FRAME (1 << 4) #define STP_SUPPORT (1 << 8) @@ -3748,7 +3747,6 @@ static int hw_init(struct ksz_hw *hw) if (1 == rc) hw->features |= HALF_DUPLEX_SIGNAL_BUG; } - hw->features |= IPV6_CSUM_GEN_HACK; return rc; } @@ -4887,8 +4885,7 @@ static netdev_tx_t netdev_tx(struct sk_buff *skb, struct net_device *dev) left = hw_alloc_pkt(hw, skb->len, num); if (left) { if (left < num || - ((hw->features & IPV6_CSUM_GEN_HACK) && - (CHECKSUM_PARTIAL == skb->ip_summed) && + ((CHECKSUM_PARTIAL == skb->ip_summed) && (ETH_P_IPV6 == htons(skb->protocol)))) { struct sk_buff *org_skb = skb; @@ -6583,57 +6580,33 @@ static void netdev_get_ethtool_stats(struct net_device *dev, } /** - * netdev_get_rx_csum - get receive checksum support + * netdev_set_features - set receive checksum support * @dev: Network device. - * - * This function gets receive checksum support setting. - * - * Return true if receive checksum is enabled; false otherwise. - */ -static u32 netdev_get_rx_csum(struct net_device *dev) -{ - struct dev_priv *priv = netdev_priv(dev); - struct dev_info *hw_priv = priv->adapter; - struct ksz_hw *hw = &hw_priv->hw; - - return hw->rx_cfg & - (DMA_RX_CSUM_UDP | - DMA_RX_CSUM_TCP | - DMA_RX_CSUM_IP); -} - -/** - * netdev_set_rx_csum - set receive checksum support - * @dev: Network device. - * @data: Zero to disable receive checksum support. + * @features: New device features (offloads). * * This function sets receive checksum support setting. * * Return 0 if successful; otherwise an error code. */ -static int netdev_set_rx_csum(struct net_device *dev, u32 data) +static int netdev_set_features(struct net_device *dev, u32 features) { struct dev_priv *priv = netdev_priv(dev); struct dev_info *hw_priv = priv->adapter; struct ksz_hw *hw = &hw_priv->hw; - u32 new_setting = hw->rx_cfg; - if (data) - new_setting |= - (DMA_RX_CSUM_UDP | DMA_RX_CSUM_TCP | - DMA_RX_CSUM_IP); - else - new_setting &= - ~(DMA_RX_CSUM_UDP | DMA_RX_CSUM_TCP | - DMA_RX_CSUM_IP); - new_setting &= ~DMA_RX_CSUM_UDP; mutex_lock(&hw_priv->lock); - if (new_setting != hw->rx_cfg) { - hw->rx_cfg = new_setting; - if (hw->enabled) - writel(hw->rx_cfg, hw->io + KS_DMA_RX_CTRL); - } + + /* see note in hw_setup() */ + if (features & NETIF_F_RXCSUM) + hw->rx_cfg |= DMA_RX_CSUM_TCP | DMA_RX_CSUM_IP; + else + hw->rx_cfg &= ~(DMA_RX_CSUM_TCP | DMA_RX_CSUM_IP); + + if (hw->enabled) + writel(hw->rx_cfg, hw->io + KS_DMA_RX_CTRL); + mutex_unlock(&hw_priv->lock); + return 0; } @@ -6658,12 +6631,6 @@ static struct ethtool_ops netdev_ethtool_ops = { .get_strings = netdev_get_strings, .get_sset_count = netdev_get_sset_count, .get_ethtool_stats = netdev_get_ethtool_stats, - .get_rx_csum = netdev_get_rx_csum, - .set_rx_csum = netdev_set_rx_csum, - .get_tx_csum = ethtool_op_get_tx_csum, - .set_tx_csum = ethtool_op_set_tx_csum, - .get_sg = ethtool_op_get_sg, - .set_sg = ethtool_op_set_sg, }; /* @@ -6828,14 +6795,15 @@ static int __init netdev_init(struct net_device *dev) /* 500 ms timeout */ dev->watchdog_timeo = HZ / 2; - dev->features |= NETIF_F_IP_CSUM; + dev->hw_features = NETIF_F_IP_CSUM | NETIF_F_SG | NETIF_F_RXCSUM; /* * Hardware does not really support IPv6 checksum generation, but - * driver actually runs faster with this on. Refer IPV6_CSUM_GEN_HACK. + * driver actually runs faster with this on. */ - dev->features |= NETIF_F_IPV6_CSUM; - dev->features |= NETIF_F_SG; + dev->hw_features |= NETIF_F_IPV6_CSUM; + + dev->features |= dev->hw_features; sema_init(&priv->proc_sem, 1); @@ -6860,6 +6828,7 @@ static const struct net_device_ops netdev_ops = { .ndo_start_xmit = netdev_tx, .ndo_tx_timeout = netdev_tx_timeout, .ndo_change_mtu = netdev_change_mtu, + .ndo_set_features = netdev_set_features, .ndo_set_mac_address = netdev_set_mac_address, .ndo_validate_addr = eth_validate_addr, .ndo_do_ioctl = netdev_ioctl, -- cgit v0.10.2 From f593fe363268e7354b3a7f3907170de1ac4de7e7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Miros=C5=82aw?= Date: Sun, 10 Apr 2011 03:13:21 +0000 Subject: net: via-velocity: convert to hw_features MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Trivial conversion. This also enables toggling TX VLAN offload and fixes TX checksumming race with offload changes. Signed-off-by: MichaÅ‚ MirosÅ‚aw Signed-off-by: David S. Miller diff --git a/drivers/net/via-velocity.c b/drivers/net/via-velocity.c index 0d6fec6..77315ad 100644 --- a/drivers/net/via-velocity.c +++ b/drivers/net/via-velocity.c @@ -2600,8 +2600,7 @@ static netdev_tx_t velocity_xmit(struct sk_buff *skb, /* * Handle hardware checksum */ - if ((dev->features & NETIF_F_IP_CSUM) && - (skb->ip_summed == CHECKSUM_PARTIAL)) { + if (skb->ip_summed == CHECKSUM_PARTIAL) { const struct iphdr *ip = ip_hdr(skb); if (ip->protocol == IPPROTO_TCP) td_ptr->tdesc1.TCR |= TCR0_TCPCK; @@ -2841,6 +2840,7 @@ static int __devinit velocity_found1(struct pci_dev *pdev, const struct pci_devi dev->ethtool_ops = &velocity_ethtool_ops; netif_napi_add(dev, &vptr->napi, velocity_poll, VELOCITY_NAPI_WEIGHT); + dev->hw_features = NETIF_F_IP_CSUM | NETIF_F_SG | NETIF_F_HW_VLAN_TX; dev->features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_FILTER | NETIF_F_HW_VLAN_RX | NETIF_F_IP_CSUM; @@ -3457,13 +3457,10 @@ static const struct ethtool_ops velocity_ethtool_ops = { .get_settings = velocity_get_settings, .set_settings = velocity_set_settings, .get_drvinfo = velocity_get_drvinfo, - .set_tx_csum = ethtool_op_set_tx_csum, - .get_tx_csum = ethtool_op_get_tx_csum, .get_wol = velocity_ethtool_get_wol, .set_wol = velocity_ethtool_set_wol, .get_msglevel = velocity_get_msglevel, .set_msglevel = velocity_set_msglevel, - .set_sg = ethtool_op_set_sg, .get_link = velocity_get_link, .get_coalesce = velocity_get_coalesce, .set_coalesce = velocity_set_coalesce, -- cgit v0.10.2 From 8d7dfc2b57bb2cad0731dedd58ec1d70bcca1ccf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Miros=C5=82aw?= Date: Sun, 10 Apr 2011 04:47:46 +0000 Subject: net: bnx2: convert to hw_features MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: MichaÅ‚ MirosÅ‚aw Signed-off-by: David S. Miller diff --git a/drivers/net/bnx2.c b/drivers/net/bnx2.c index 05ddfb1..0a52079 100644 --- a/drivers/net/bnx2.c +++ b/drivers/net/bnx2.c @@ -3174,7 +3174,7 @@ bnx2_rx_int(struct bnx2 *bp, struct bnx2_napi *bnapi, int budget) } skb_checksum_none_assert(skb); - if (bp->rx_csum && + if ((bp->dev->features & NETIF_F_RXCSUM) && (status & (L2_FHDR_STATUS_TCP_SEGMENT | L2_FHDR_STATUS_UDP_DATAGRAM))) { @@ -7189,38 +7189,6 @@ bnx2_set_pauseparam(struct net_device *dev, struct ethtool_pauseparam *epause) return 0; } -static u32 -bnx2_get_rx_csum(struct net_device *dev) -{ - struct bnx2 *bp = netdev_priv(dev); - - return bp->rx_csum; -} - -static int -bnx2_set_rx_csum(struct net_device *dev, u32 data) -{ - struct bnx2 *bp = netdev_priv(dev); - - bp->rx_csum = data; - return 0; -} - -static int -bnx2_set_tso(struct net_device *dev, u32 data) -{ - struct bnx2 *bp = netdev_priv(dev); - - if (data) { - dev->features |= NETIF_F_TSO | NETIF_F_TSO_ECN; - if (CHIP_NUM(bp) == CHIP_NUM_5709) - dev->features |= NETIF_F_TSO6; - } else - dev->features &= ~(NETIF_F_TSO | NETIF_F_TSO6 | - NETIF_F_TSO_ECN); - return 0; -} - static struct { char string[ETH_GSTRING_LEN]; } bnx2_stats_str_arr[] = { @@ -7532,43 +7500,37 @@ bnx2_set_phys_id(struct net_device *dev, enum ethtool_phys_id_state state) return 0; } -static int -bnx2_set_tx_csum(struct net_device *dev, u32 data) +static u32 +bnx2_fix_features(struct net_device *dev, u32 features) { struct bnx2 *bp = netdev_priv(dev); - if (CHIP_NUM(bp) == CHIP_NUM_5709) - return ethtool_op_set_tx_ipv6_csum(dev, data); - else - return ethtool_op_set_tx_csum(dev, data); + if (!(bp->flags & BNX2_FLAG_CAN_KEEP_VLAN)) + features |= NETIF_F_HW_VLAN_RX; + + return features; } static int -bnx2_set_flags(struct net_device *dev, u32 data) +bnx2_set_features(struct net_device *dev, u32 features) { struct bnx2 *bp = netdev_priv(dev); - int rc; - - if (!(bp->flags & BNX2_FLAG_CAN_KEEP_VLAN) && - !(data & ETH_FLAG_RXVLAN)) - return -EINVAL; /* TSO with VLAN tag won't work with current firmware */ - if (!(data & ETH_FLAG_TXVLAN)) - return -EINVAL; - - rc = ethtool_op_set_flags(dev, data, ETH_FLAG_RXHASH | ETH_FLAG_RXVLAN | - ETH_FLAG_TXVLAN); - if (rc) - return rc; + if (features & NETIF_F_HW_VLAN_TX) + dev->vlan_features |= (dev->hw_features & NETIF_F_ALL_TSO); + else + dev->vlan_features &= ~NETIF_F_ALL_TSO; - if ((!!(data & ETH_FLAG_RXVLAN) != + if ((!!(features & NETIF_F_HW_VLAN_RX) != !!(bp->rx_mode & BNX2_EMAC_RX_MODE_KEEP_VLAN_TAG)) && netif_running(dev)) { bnx2_netif_stop(bp, false); + dev->features = features; bnx2_set_rx_mode(dev); bnx2_fw_sync(bp, BNX2_DRV_MSG_CODE_KEEP_VLAN_UPDATE, 0, 1); bnx2_netif_start(bp, false); + return 1; } return 0; @@ -7593,18 +7555,11 @@ static const struct ethtool_ops bnx2_ethtool_ops = { .set_ringparam = bnx2_set_ringparam, .get_pauseparam = bnx2_get_pauseparam, .set_pauseparam = bnx2_set_pauseparam, - .get_rx_csum = bnx2_get_rx_csum, - .set_rx_csum = bnx2_set_rx_csum, - .set_tx_csum = bnx2_set_tx_csum, - .set_sg = ethtool_op_set_sg, - .set_tso = bnx2_set_tso, .self_test = bnx2_self_test, .get_strings = bnx2_get_strings, .set_phys_id = bnx2_set_phys_id, .get_ethtool_stats = bnx2_get_ethtool_stats, .get_sset_count = bnx2_get_sset_count, - .set_flags = bnx2_set_flags, - .get_flags = ethtool_op_get_flags, }; /* Called with rtnl_lock */ @@ -8116,8 +8071,6 @@ bnx2_init_board(struct pci_dev *pdev, struct net_device *dev) bp->tx_ring_size = MAX_TX_DESC_CNT; bnx2_set_rx_ring_size(bp, 255); - bp->rx_csum = 1; - bp->tx_quick_cons_trip_int = 2; bp->tx_quick_cons_trip = 20; bp->tx_ticks_int = 18; @@ -8309,17 +8262,14 @@ static const struct net_device_ops bnx2_netdev_ops = { .ndo_validate_addr = eth_validate_addr, .ndo_set_mac_address = bnx2_change_mac_addr, .ndo_change_mtu = bnx2_change_mtu, + .ndo_fix_features = bnx2_fix_features, + .ndo_set_features = bnx2_set_features, .ndo_tx_timeout = bnx2_tx_timeout, #ifdef CONFIG_NET_POLL_CONTROLLER .ndo_poll_controller = poll_bnx2, #endif }; -static inline void vlan_features_add(struct net_device *dev, u32 flags) -{ - dev->vlan_features |= flags; -} - static int __devinit bnx2_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) { @@ -8359,20 +8309,17 @@ bnx2_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) memcpy(dev->dev_addr, bp->mac_addr, 6); memcpy(dev->perm_addr, bp->mac_addr, 6); - dev->features |= NETIF_F_IP_CSUM | NETIF_F_SG | NETIF_F_GRO | - NETIF_F_RXHASH; - vlan_features_add(dev, NETIF_F_IP_CSUM | NETIF_F_SG); - if (CHIP_NUM(bp) == CHIP_NUM_5709) { - dev->features |= NETIF_F_IPV6_CSUM; - vlan_features_add(dev, NETIF_F_IPV6_CSUM); - } - dev->features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX; - dev->features |= NETIF_F_TSO | NETIF_F_TSO_ECN; - vlan_features_add(dev, NETIF_F_TSO | NETIF_F_TSO_ECN); - if (CHIP_NUM(bp) == CHIP_NUM_5709) { - dev->features |= NETIF_F_TSO6; - vlan_features_add(dev, NETIF_F_TSO6); - } + dev->hw_features = NETIF_F_IP_CSUM | NETIF_F_SG | + NETIF_F_TSO | NETIF_F_TSO_ECN | + NETIF_F_RXHASH | NETIF_F_RXCSUM; + + if (CHIP_NUM(bp) == CHIP_NUM_5709) + dev->hw_features |= NETIF_F_IPV6_CSUM | NETIF_F_TSO6; + + dev->vlan_features = dev->hw_features; + dev->hw_features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX; + dev->features |= dev->hw_features; + if ((rc = register_netdev(dev))) { dev_err(&pdev->dev, "Cannot register net device\n"); goto error; diff --git a/drivers/net/bnx2.h b/drivers/net/bnx2.h index 91e8356..bf371f6 100644 --- a/drivers/net/bnx2.h +++ b/drivers/net/bnx2.h @@ -6754,8 +6754,6 @@ struct bnx2 { u32 rx_max_ring_idx; u32 rx_max_pg_ring_idx; - u32 rx_csum; - /* TX constants */ int tx_ring_size; u32 tx_wake_thresh; -- cgit v0.10.2 From 5cdede2408e80f190c5595e592c24e77c1bf44b2 Mon Sep 17 00:00:00 2001 From: Joerg Roedel Date: Mon, 4 Apr 2011 15:55:18 +0200 Subject: PCI: Move ATS declarations in seperate header file This patch moves the relevant declarations from the local header file in drivers/pci to a more accessible locations so that it can be used by the AMD IOMMU driver too. The file is named pci-ats.h because support for the PCI PRI capability will also be added there in a later patch-set. Signed-off-by: Joerg Roedel Acked-by: Jesse Barnes diff --git a/drivers/pci/intel-iommu.c b/drivers/pci/intel-iommu.c index 7da3bef..fdb2cef 100644 --- a/drivers/pci/intel-iommu.c +++ b/drivers/pci/intel-iommu.c @@ -39,6 +39,7 @@ #include #include #include +#include #include #include #include "pci.h" diff --git a/drivers/pci/iov.c b/drivers/pci/iov.c index 553d8ee..42fae47 100644 --- a/drivers/pci/iov.c +++ b/drivers/pci/iov.c @@ -13,6 +13,7 @@ #include #include #include +#include #include "pci.h" #define VIRTFN_ID_LEN 16 diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h index a6ec200..4020025 100644 --- a/drivers/pci/pci.h +++ b/drivers/pci/pci.h @@ -250,15 +250,6 @@ struct pci_sriov { u8 __iomem *mstate; /* VF Migration State Array */ }; -/* Address Translation Service */ -struct pci_ats { - int pos; /* capability position */ - int stu; /* Smallest Translation Unit */ - int qdep; /* Invalidate Queue Depth */ - int ref_cnt; /* Physical Function reference count */ - unsigned int is_enabled:1; /* Enable bit is set */ -}; - #ifdef CONFIG_PCI_IOV extern int pci_iov_init(struct pci_dev *dev); extern void pci_iov_release(struct pci_dev *dev); @@ -269,19 +260,6 @@ extern resource_size_t pci_sriov_resource_alignment(struct pci_dev *dev, extern void pci_restore_iov_state(struct pci_dev *dev); extern int pci_iov_bus_range(struct pci_bus *bus); -extern int pci_enable_ats(struct pci_dev *dev, int ps); -extern void pci_disable_ats(struct pci_dev *dev); -extern int pci_ats_queue_depth(struct pci_dev *dev); -/** - * pci_ats_enabled - query the ATS status - * @dev: the PCI device - * - * Returns 1 if ATS capability is enabled, or 0 if not. - */ -static inline int pci_ats_enabled(struct pci_dev *dev) -{ - return dev->ats && dev->ats->is_enabled; -} #else static inline int pci_iov_init(struct pci_dev *dev) { @@ -304,21 +282,6 @@ static inline int pci_iov_bus_range(struct pci_bus *bus) return 0; } -static inline int pci_enable_ats(struct pci_dev *dev, int ps) -{ - return -ENODEV; -} -static inline void pci_disable_ats(struct pci_dev *dev) -{ -} -static inline int pci_ats_queue_depth(struct pci_dev *dev) -{ - return -ENODEV; -} -static inline int pci_ats_enabled(struct pci_dev *dev) -{ - return 0; -} #endif /* CONFIG_PCI_IOV */ static inline resource_size_t pci_resource_alignment(struct pci_dev *dev, diff --git a/include/linux/pci-ats.h b/include/linux/pci-ats.h new file mode 100644 index 0000000..655824f --- /dev/null +++ b/include/linux/pci-ats.h @@ -0,0 +1,52 @@ +#ifndef LINUX_PCI_ATS_H +#define LINUX_PCI_ATS_H + +/* Address Translation Service */ +struct pci_ats { + int pos; /* capability position */ + int stu; /* Smallest Translation Unit */ + int qdep; /* Invalidate Queue Depth */ + int ref_cnt; /* Physical Function reference count */ + unsigned int is_enabled:1; /* Enable bit is set */ +}; + +#ifdef CONFIG_PCI_IOV + +extern int pci_enable_ats(struct pci_dev *dev, int ps); +extern void pci_disable_ats(struct pci_dev *dev); +extern int pci_ats_queue_depth(struct pci_dev *dev); +/** + * pci_ats_enabled - query the ATS status + * @dev: the PCI device + * + * Returns 1 if ATS capability is enabled, or 0 if not. + */ +static inline int pci_ats_enabled(struct pci_dev *dev) +{ + return dev->ats && dev->ats->is_enabled; +} + +#else /* CONFIG_PCI_IOV */ + +static inline int pci_enable_ats(struct pci_dev *dev, int ps) +{ + return -ENODEV; +} + +static inline void pci_disable_ats(struct pci_dev *dev) +{ +} + +static inline int pci_ats_queue_depth(struct pci_dev *dev) +{ + return -ENODEV; +} + +static inline int pci_ats_enabled(struct pci_dev *dev) +{ + return 0; +} + +#endif /* CONFIG_PCI_IOV */ + +#endif /* LINUX_PCI_ATS_H*/ -- cgit v0.10.2 From 9844b4e5dd1932e175a23d84ce09702bdf4b5689 Mon Sep 17 00:00:00 2001 From: Joerg Roedel Date: Tue, 5 Apr 2011 09:22:56 +0200 Subject: x86/amd-iommu: Select PCI_IOV with AMD IOMMU driver In order to support ATS in the AMD IOMMU driver this patch makes sure that the generic support for ATS is compiled in. Signed-off-by: Joerg Roedel diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig index cc6c53a..8cc29da 100644 --- a/arch/x86/Kconfig +++ b/arch/x86/Kconfig @@ -690,6 +690,7 @@ config AMD_IOMMU bool "AMD IOMMU support" select SWIOTLB select PCI_MSI + select PCI_IOV depends on X86_64 && PCI && ACPI ---help--- With this option you can enable support for AMD IOMMU hardware in -- cgit v0.10.2 From cb41ed85efa01e633388314c03a4f3004c6b783b Mon Sep 17 00:00:00 2001 From: Joerg Roedel Date: Tue, 5 Apr 2011 11:00:53 +0200 Subject: x86/amd-iommu: Flush device IOTLB if ATS is enabled This patch implements a function to flush the IOTLB on devices supporting ATS and makes sure that this TLB is also flushed if necessary. Signed-off-by: Joerg Roedel diff --git a/arch/x86/include/asm/amd_iommu_types.h b/arch/x86/include/asm/amd_iommu_types.h index 878ae00..f5d184e7 100644 --- a/arch/x86/include/asm/amd_iommu_types.h +++ b/arch/x86/include/asm/amd_iommu_types.h @@ -113,7 +113,8 @@ /* command specific defines */ #define CMD_COMPL_WAIT 0x01 #define CMD_INV_DEV_ENTRY 0x02 -#define CMD_INV_IOMMU_PAGES 0x03 +#define CMD_INV_IOMMU_PAGES 0x03 +#define CMD_INV_IOTLB_PAGES 0x04 #define CMD_COMPL_WAIT_STORE_MASK 0x01 #define CMD_COMPL_WAIT_INT_MASK 0x02 diff --git a/arch/x86/kernel/amd_iommu.c b/arch/x86/kernel/amd_iommu.c index bcf58ea..f3ce433 100644 --- a/arch/x86/kernel/amd_iommu.c +++ b/arch/x86/kernel/amd_iommu.c @@ -18,6 +18,7 @@ */ #include +#include #include #include #include @@ -463,6 +464,37 @@ static void build_inv_iommu_pages(struct iommu_cmd *cmd, u64 address, cmd->data[2] |= CMD_INV_IOMMU_PAGES_PDE_MASK; } +static void build_inv_iotlb_pages(struct iommu_cmd *cmd, u16 devid, int qdep, + u64 address, size_t size) +{ + u64 pages; + int s; + + pages = iommu_num_pages(address, size, PAGE_SIZE); + s = 0; + + if (pages > 1) { + /* + * If we have to flush more than one page, flush all + * TLB entries for this domain + */ + address = CMD_INV_IOMMU_ALL_PAGES_ADDRESS; + s = 1; + } + + address &= PAGE_MASK; + + memset(cmd, 0, sizeof(*cmd)); + cmd->data[0] = devid; + cmd->data[0] |= (qdep & 0xff) << 24; + cmd->data[1] = devid; + cmd->data[2] = lower_32_bits(address); + cmd->data[3] = upper_32_bits(address); + CMD_SET_TYPE(cmd, CMD_INV_IOTLB_PAGES); + if (s) + cmd->data[2] |= CMD_INV_IOMMU_PAGES_SIZE_MASK; +} + /* * Writes the command to the IOMMUs command buffer and informs the * hardware about the new command. @@ -574,17 +606,47 @@ void iommu_flush_all_caches(struct amd_iommu *iommu) } /* + * Command send function for flushing on-device TLB + */ +static int device_flush_iotlb(struct device *dev, u64 address, size_t size) +{ + struct pci_dev *pdev = to_pci_dev(dev); + struct amd_iommu *iommu; + struct iommu_cmd cmd; + u16 devid; + int qdep; + + qdep = pci_ats_queue_depth(pdev); + devid = get_device_id(dev); + iommu = amd_iommu_rlookup_table[devid]; + + build_inv_iotlb_pages(&cmd, devid, qdep, address, size); + + return iommu_queue_command(iommu, &cmd); +} + +/* * Command send function for invalidating a device table entry */ static int device_flush_dte(struct device *dev) { struct amd_iommu *iommu; + struct pci_dev *pdev; u16 devid; + int ret; + pdev = to_pci_dev(dev); devid = get_device_id(dev); iommu = amd_iommu_rlookup_table[devid]; - return iommu_flush_dte(iommu, devid); + ret = iommu_flush_dte(iommu, devid); + if (ret) + return ret; + + if (pci_ats_enabled(pdev)) + ret = device_flush_iotlb(dev, 0, ~0UL); + + return ret; } /* @@ -595,6 +657,7 @@ static int device_flush_dte(struct device *dev) static void __domain_flush_pages(struct protection_domain *domain, u64 address, size_t size, int pde) { + struct iommu_dev_data *dev_data; struct iommu_cmd cmd; int ret = 0, i; @@ -611,6 +674,15 @@ static void __domain_flush_pages(struct protection_domain *domain, ret |= iommu_queue_command(amd_iommus[i], &cmd); } + list_for_each_entry(dev_data, &domain->dev_list, list) { + struct pci_dev *pdev = to_pci_dev(dev_data->dev); + + if (!pci_ats_enabled(pdev)) + continue; + + ret |= device_flush_iotlb(dev_data->dev, address, size); + } + WARN_ON(ret); } -- cgit v0.10.2 From 60f723b4117507c05c8b0b5c8b98ecc12a76878e Mon Sep 17 00:00:00 2001 From: Joerg Roedel Date: Tue, 5 Apr 2011 12:50:24 +0200 Subject: x86/amd-iommu: Add flag to indicate IOTLB support This patch adds a flag to the AMD IOMMU driver to indicate that all IOMMUs present in the system support device IOTLBs. Signed-off-by: Joerg Roedel diff --git a/arch/x86/include/asm/amd_iommu_types.h b/arch/x86/include/asm/amd_iommu_types.h index f5d184e7..cb811c9 100644 --- a/arch/x86/include/asm/amd_iommu_types.h +++ b/arch/x86/include/asm/amd_iommu_types.h @@ -250,6 +250,8 @@ extern bool amd_iommu_dump; /* global flag if IOMMUs cache non-present entries */ extern bool amd_iommu_np_cache; +/* Only true if all IOMMUs support device IOTLBs */ +extern bool amd_iommu_iotlb_sup; /* * Make iterating over all IOMMUs easier diff --git a/arch/x86/kernel/amd_iommu_init.c b/arch/x86/kernel/amd_iommu_init.c index 8848dda..b6c634f 100644 --- a/arch/x86/kernel/amd_iommu_init.c +++ b/arch/x86/kernel/amd_iommu_init.c @@ -137,6 +137,7 @@ int amd_iommus_present; /* IOMMUs have a non-present cache? */ bool amd_iommu_np_cache __read_mostly; +bool amd_iommu_iotlb_sup __read_mostly = true; /* * The ACPI table parsing functions set this variable on an error @@ -673,6 +674,9 @@ static void __init init_iommu_from_pci(struct amd_iommu *iommu) MMIO_GET_LD(range)); iommu->evt_msi_num = MMIO_MSI_NUM(misc); + if (!(iommu->cap & (1 << IOMMU_CAP_IOTLB))) + amd_iommu_iotlb_sup = false; + if (!is_rd890_iommu(iommu->dev)) return; -- cgit v0.10.2 From fd7b5535e10ce820f030842da3f289f80ec0d4f3 Mon Sep 17 00:00:00 2001 From: Joerg Roedel Date: Tue, 5 Apr 2011 15:31:08 +0200 Subject: x86/amd-iommu: Add ATS enable/disable code This patch adds the necessary code to the AMD IOMMU driver for enabling and disabling the ATS capability on a device and to setup the IOMMU data structures correctly. Signed-off-by: Joerg Roedel diff --git a/arch/x86/include/asm/amd_iommu_types.h b/arch/x86/include/asm/amd_iommu_types.h index cb811c9..7434377 100644 --- a/arch/x86/include/asm/amd_iommu_types.h +++ b/arch/x86/include/asm/amd_iommu_types.h @@ -216,6 +216,8 @@ #define IOMMU_PTE_IR (1ULL << 61) #define IOMMU_PTE_IW (1ULL << 62) +#define DTE_FLAG_IOTLB 0x01 + #define IOMMU_PAGE_MASK (((1ULL << 52) - 1) & ~0xfffULL) #define IOMMU_PTE_PRESENT(pte) ((pte) & IOMMU_PTE_P) #define IOMMU_PTE_PAGE(pte) (phys_to_virt((pte) & IOMMU_PAGE_MASK)) diff --git a/arch/x86/kernel/amd_iommu.c b/arch/x86/kernel/amd_iommu.c index f3ce433..e4791f6 100644 --- a/arch/x86/kernel/amd_iommu.c +++ b/arch/x86/kernel/amd_iommu.c @@ -1452,17 +1452,22 @@ static bool dma_ops_domain(struct protection_domain *domain) return domain->flags & PD_DMA_OPS_MASK; } -static void set_dte_entry(u16 devid, struct protection_domain *domain) +static void set_dte_entry(u16 devid, struct protection_domain *domain, bool ats) { u64 pte_root = virt_to_phys(domain->pt_root); + u32 flags = 0; pte_root |= (domain->mode & DEV_ENTRY_MODE_MASK) << DEV_ENTRY_MODE_SHIFT; pte_root |= IOMMU_PTE_IR | IOMMU_PTE_IW | IOMMU_PTE_P | IOMMU_PTE_TV; - amd_iommu_dev_table[devid].data[2] = domain->id; - amd_iommu_dev_table[devid].data[1] = upper_32_bits(pte_root); - amd_iommu_dev_table[devid].data[0] = lower_32_bits(pte_root); + if (ats) + flags |= DTE_FLAG_IOTLB; + + amd_iommu_dev_table[devid].data[3] |= flags; + amd_iommu_dev_table[devid].data[2] = domain->id; + amd_iommu_dev_table[devid].data[1] = upper_32_bits(pte_root); + amd_iommu_dev_table[devid].data[0] = lower_32_bits(pte_root); } static void clear_dte_entry(u16 devid) @@ -1479,16 +1484,22 @@ static void do_attach(struct device *dev, struct protection_domain *domain) { struct iommu_dev_data *dev_data; struct amd_iommu *iommu; + struct pci_dev *pdev; + bool ats = false; u16 devid; devid = get_device_id(dev); iommu = amd_iommu_rlookup_table[devid]; dev_data = get_dev_data(dev); + pdev = to_pci_dev(dev); + + if (amd_iommu_iotlb_sup) + ats = pci_ats_enabled(pdev); /* Update data structures */ dev_data->domain = domain; list_add(&dev_data->list, &domain->dev_list); - set_dte_entry(devid, domain); + set_dte_entry(devid, domain, ats); /* Do reference counting */ domain->dev_iommu[iommu->index] += 1; @@ -1502,11 +1513,13 @@ static void do_detach(struct device *dev) { struct iommu_dev_data *dev_data; struct amd_iommu *iommu; + struct pci_dev *pdev; u16 devid; devid = get_device_id(dev); iommu = amd_iommu_rlookup_table[devid]; dev_data = get_dev_data(dev); + pdev = to_pci_dev(dev); /* decrease reference counters */ dev_data->domain->dev_iommu[iommu->index] -= 1; @@ -1581,9 +1594,13 @@ out_unlock: static int attach_device(struct device *dev, struct protection_domain *domain) { + struct pci_dev *pdev = to_pci_dev(dev); unsigned long flags; int ret; + if (amd_iommu_iotlb_sup) + pci_enable_ats(pdev, PAGE_SHIFT); + write_lock_irqsave(&amd_iommu_devtable_lock, flags); ret = __attach_device(dev, domain); write_unlock_irqrestore(&amd_iommu_devtable_lock, flags); @@ -1640,12 +1657,16 @@ static void __detach_device(struct device *dev) */ static void detach_device(struct device *dev) { + struct pci_dev *pdev = to_pci_dev(dev); unsigned long flags; /* lock device table */ write_lock_irqsave(&amd_iommu_devtable_lock, flags); __detach_device(dev); write_unlock_irqrestore(&amd_iommu_devtable_lock, flags); + + if (amd_iommu_iotlb_sup && pci_ats_enabled(pdev)) + pci_disable_ats(pdev); } /* @@ -1795,8 +1816,9 @@ static void update_device_table(struct protection_domain *domain) struct iommu_dev_data *dev_data; list_for_each_entry(dev_data, &domain->dev_list, list) { + struct pci_dev *pdev = to_pci_dev(dev_data->dev); u16 devid = get_device_id(dev_data->dev); - set_dte_entry(devid, domain); + set_dte_entry(devid, domain, pci_ats_enabled(pdev)); } } -- cgit v0.10.2 From f4ad9bd208c98f32a6f9136618e0b8bebe3fb370 Mon Sep 17 00:00:00 2001 From: Shaohua Li Date: Fri, 8 Apr 2011 12:53:09 +0800 Subject: sched: Eliminate dead code from wakeup_gran() calc_delta_fair() checks NICE_0_LOAD already, delete duplicate check. Signed-off-by: Shaohua Li Signed-off-by: Peter Zijlstra Cc: Mike Galbraith Link: http://lkml.kernel.org/r/1302238389.3981.92.camel@sli10-conroe Signed-off-by: Ingo Molnar diff --git a/kernel/sched_fair.c b/kernel/sched_fair.c index 6fa833a..4ee50f0 100644 --- a/kernel/sched_fair.c +++ b/kernel/sched_fair.c @@ -1789,10 +1789,7 @@ wakeup_gran(struct sched_entity *curr, struct sched_entity *se) * This is especially important for buddies when the leftmost * task is higher priority than the buddy. */ - if (unlikely(se->load.weight != NICE_0_LOAD)) - gran = calc_delta_fair(gran, se); - - return gran; + return calc_delta_fair(gran, se); } /* -- cgit v0.10.2 From c4a8849af939082052d8117f9ea3e170a99ff232 Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Thu, 7 Apr 2011 14:09:42 +0200 Subject: sched: Remove obsolete arch_ prefixes Non weak static functions clearly are not arch specific, so remove the arch_ prefix. Signed-off-by: Peter Zijlstra Cc: Mike Galbraith Cc: Nick Piggin Cc: Linus Torvalds Cc: Andrew Morton Link: http://lkml.kernel.org/r/20110407122941.820460566@chello.nl Signed-off-by: Ingo Molnar diff --git a/kernel/sched.c b/kernel/sched.c index 4801363..d3e183c 100644 --- a/kernel/sched.c +++ b/kernel/sched.c @@ -231,7 +231,7 @@ static void destroy_rt_bandwidth(struct rt_bandwidth *rt_b) #endif /* - * sched_domains_mutex serializes calls to arch_init_sched_domains, + * sched_domains_mutex serializes calls to init_sched_domains, * detach_destroy_domains and partition_sched_domains. */ static DEFINE_MUTEX(sched_domains_mutex); @@ -7670,7 +7670,7 @@ void free_sched_domains(cpumask_var_t doms[], unsigned int ndoms) * For now this just excludes isolated cpus, but could be used to * exclude other special cases in the future. */ -static int arch_init_sched_domains(const struct cpumask *cpu_map) +static int init_sched_domains(const struct cpumask *cpu_map) { int err; @@ -7687,7 +7687,7 @@ static int arch_init_sched_domains(const struct cpumask *cpu_map) return err; } -static void arch_destroy_sched_domains(const struct cpumask *cpu_map, +static void destroy_sched_domains(const struct cpumask *cpu_map, struct cpumask *tmpmask) { free_sched_groups(cpu_map, tmpmask); @@ -7706,7 +7706,7 @@ static void detach_destroy_domains(const struct cpumask *cpu_map) for_each_cpu(i, cpu_map) cpu_attach_domain(NULL, &def_root_domain, i); synchronize_sched(); - arch_destroy_sched_domains(cpu_map, to_cpumask(tmpmask)); + destroy_sched_domains(cpu_map, to_cpumask(tmpmask)); } /* handle null as "default" */ @@ -7815,7 +7815,7 @@ match2: } #if defined(CONFIG_SCHED_MC) || defined(CONFIG_SCHED_SMT) -static void arch_reinit_sched_domains(void) +static void reinit_sched_domains(void) { get_online_cpus(); @@ -7848,7 +7848,7 @@ static ssize_t sched_power_savings_store(const char *buf, size_t count, int smt) else sched_mc_power_savings = level; - arch_reinit_sched_domains(); + reinit_sched_domains(); return count; } @@ -7974,7 +7974,7 @@ void __init sched_init_smp(void) #endif get_online_cpus(); mutex_lock(&sched_domains_mutex); - arch_init_sched_domains(cpu_active_mask); + init_sched_domains(cpu_active_mask); cpumask_andnot(non_isolated_cpus, cpu_possible_mask, cpu_isolated_map); if (cpumask_empty(non_isolated_cpus)) cpumask_set_cpu(smp_processor_id(), non_isolated_cpus); -- cgit v0.10.2 From d274cb30f4a08045492d3f0c47cdf1a25668b1f5 Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Thu, 7 Apr 2011 14:09:43 +0200 Subject: sched: Simplify ->cpu_power initialization The code in update_group_power() does what init_sched_groups_power() does and more, so remove the special init_ code and call the generic code instead. Also move the sd->span_weight initialization because update_group_power() needs it. Signed-off-by: Peter Zijlstra Cc: Mike Galbraith Cc: Nick Piggin Cc: Linus Torvalds Cc: Andrew Morton Link: http://lkml.kernel.org/r/20110407122941.875856012@chello.nl Signed-off-by: Ingo Molnar diff --git a/kernel/sched.c b/kernel/sched.c index d3e183c..50d5fd3 100644 --- a/kernel/sched.c +++ b/kernel/sched.c @@ -6679,9 +6679,6 @@ cpu_attach_domain(struct sched_domain *sd, struct root_domain *rd, int cpu) struct rq *rq = cpu_rq(cpu); struct sched_domain *tmp; - for (tmp = sd; tmp; tmp = tmp->parent) - tmp->span_weight = cpumask_weight(sched_domain_span(tmp)); - /* Remove the sched domains which do not contribute to scheduling. */ for (tmp = sd; tmp; ) { struct sched_domain *parent = tmp->parent; @@ -7159,11 +7156,6 @@ static void free_sched_groups(const struct cpumask *cpu_map, */ static void init_sched_groups_power(int cpu, struct sched_domain *sd) { - struct sched_domain *child; - struct sched_group *group; - long power; - int weight; - WARN_ON(!sd || !sd->groups); if (cpu != group_first_cpu(sd->groups)) @@ -7171,36 +7163,7 @@ static void init_sched_groups_power(int cpu, struct sched_domain *sd) sd->groups->group_weight = cpumask_weight(sched_group_cpus(sd->groups)); - child = sd->child; - - sd->groups->cpu_power = 0; - - if (!child) { - power = SCHED_LOAD_SCALE; - weight = cpumask_weight(sched_domain_span(sd)); - /* - * SMT siblings share the power of a single core. - * Usually multiple threads get a better yield out of - * that one core than a single thread would have, - * reflect that in sd->smt_gain. - */ - if ((sd->flags & SD_SHARE_CPUPOWER) && weight > 1) { - power *= sd->smt_gain; - power /= weight; - power >>= SCHED_LOAD_SHIFT; - } - sd->groups->cpu_power += power; - return; - } - - /* - * Add cpu_power of each child group to this groups cpu_power. - */ - group = child->groups; - do { - sd->groups->cpu_power += group->cpu_power; - group = group->next; - } while (group != child->groups); + update_group_power(sd, cpu); } /* @@ -7507,7 +7470,7 @@ static int __build_sched_domains(const struct cpumask *cpu_map, { enum s_alloc alloc_state = sa_none; struct s_data d; - struct sched_domain *sd; + struct sched_domain *sd, *tmp; int i; #ifdef CONFIG_NUMA d.sd_allnodes = 0; @@ -7530,6 +7493,9 @@ static int __build_sched_domains(const struct cpumask *cpu_map, sd = __build_book_sched_domain(&d, cpu_map, attr, sd, i); sd = __build_mc_sched_domain(&d, cpu_map, attr, sd, i); sd = __build_smt_sched_domain(&d, cpu_map, attr, sd, i); + + for (tmp = sd; tmp; tmp = tmp->parent) + tmp->span_weight = cpumask_weight(sched_domain_span(tmp)); } for_each_cpu(i, cpu_map) { -- cgit v0.10.2 From a06dadbec5c5df0bf3a35f33616f67d10ca9ba28 Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Thu, 7 Apr 2011 14:09:44 +0200 Subject: sched: Simplify build_sched_groups() Notice that the mask being computed is the same as the domain span we just computed. By using the domain_span we can avoid some mask allocations and computations. Signed-off-by: Peter Zijlstra Cc: Mike Galbraith Cc: Nick Piggin Cc: Linus Torvalds Cc: Andrew Morton Link: http://lkml.kernel.org/r/20110407122941.925028189@chello.nl Signed-off-by: Ingo Molnar diff --git a/kernel/sched.c b/kernel/sched.c index 50d5fd3..e3818f1 100644 --- a/kernel/sched.c +++ b/kernel/sched.c @@ -6866,9 +6866,6 @@ struct s_data { cpumask_var_t notcovered; #endif cpumask_var_t nodemask; - cpumask_var_t this_sibling_map; - cpumask_var_t this_core_map; - cpumask_var_t this_book_map; cpumask_var_t send_covered; cpumask_var_t tmpmask; struct sched_group **sched_group_nodes; @@ -6880,9 +6877,6 @@ enum s_alloc { sa_rootdomain, sa_tmpmask, sa_send_covered, - sa_this_book_map, - sa_this_core_map, - sa_this_sibling_map, sa_nodemask, sa_sched_group_nodes, #ifdef CONFIG_NUMA @@ -7251,12 +7245,6 @@ static void __free_domain_allocs(struct s_data *d, enum s_alloc what, free_cpumask_var(d->tmpmask); /* fall through */ case sa_send_covered: free_cpumask_var(d->send_covered); /* fall through */ - case sa_this_book_map: - free_cpumask_var(d->this_book_map); /* fall through */ - case sa_this_core_map: - free_cpumask_var(d->this_core_map); /* fall through */ - case sa_this_sibling_map: - free_cpumask_var(d->this_sibling_map); /* fall through */ case sa_nodemask: free_cpumask_var(d->nodemask); /* fall through */ case sa_sched_group_nodes: @@ -7295,14 +7283,8 @@ static enum s_alloc __visit_domain_allocation_hell(struct s_data *d, #endif if (!alloc_cpumask_var(&d->nodemask, GFP_KERNEL)) return sa_sched_group_nodes; - if (!alloc_cpumask_var(&d->this_sibling_map, GFP_KERNEL)) - return sa_nodemask; - if (!alloc_cpumask_var(&d->this_core_map, GFP_KERNEL)) - return sa_this_sibling_map; - if (!alloc_cpumask_var(&d->this_book_map, GFP_KERNEL)) - return sa_this_core_map; if (!alloc_cpumask_var(&d->send_covered, GFP_KERNEL)) - return sa_this_book_map; + return sa_nodemask; if (!alloc_cpumask_var(&d->tmpmask, GFP_KERNEL)) return sa_send_covered; d->rd = alloc_rootdomain(); @@ -7414,39 +7396,40 @@ static struct sched_domain *__build_smt_sched_domain(struct s_data *d, static void build_sched_groups(struct s_data *d, enum sched_domain_level l, const struct cpumask *cpu_map, int cpu) { + struct sched_domain *sd; + switch (l) { #ifdef CONFIG_SCHED_SMT case SD_LV_SIBLING: /* set up CPU (sibling) groups */ - cpumask_and(d->this_sibling_map, cpu_map, - topology_thread_cpumask(cpu)); - if (cpu == cpumask_first(d->this_sibling_map)) - init_sched_build_groups(d->this_sibling_map, cpu_map, + sd = &per_cpu(cpu_domains, cpu).sd; + if (cpu == cpumask_first(sched_domain_span(sd))) + init_sched_build_groups(sched_domain_span(sd), cpu_map, &cpu_to_cpu_group, d->send_covered, d->tmpmask); break; #endif #ifdef CONFIG_SCHED_MC case SD_LV_MC: /* set up multi-core groups */ - cpumask_and(d->this_core_map, cpu_map, cpu_coregroup_mask(cpu)); - if (cpu == cpumask_first(d->this_core_map)) - init_sched_build_groups(d->this_core_map, cpu_map, + sd = &per_cpu(core_domains, cpu).sd; + if (cpu == cpumask_first(sched_domain_span(sd))) + init_sched_build_groups(sched_domain_span(sd), cpu_map, &cpu_to_core_group, d->send_covered, d->tmpmask); break; #endif #ifdef CONFIG_SCHED_BOOK case SD_LV_BOOK: /* set up book groups */ - cpumask_and(d->this_book_map, cpu_map, cpu_book_mask(cpu)); - if (cpu == cpumask_first(d->this_book_map)) - init_sched_build_groups(d->this_book_map, cpu_map, + sd = &per_cpu(book_domains, cpu).sd; + if (cpu == cpumask_first(sched_domain_span(sd))) + init_sched_build_groups(sched_domain_span(sd), cpu_map, &cpu_to_book_group, d->send_covered, d->tmpmask); break; #endif case SD_LV_CPU: /* set up physical groups */ - cpumask_and(d->nodemask, cpumask_of_node(cpu), cpu_map); - if (!cpumask_empty(d->nodemask)) - init_sched_build_groups(d->nodemask, cpu_map, + sd = &per_cpu(phys_domains, cpu).sd; + if (cpu == cpumask_first(sched_domain_span(sd))) + init_sched_build_groups(sched_domain_span(sd), cpu_map, &cpu_to_phys_group, d->send_covered, d->tmpmask); break; @@ -7502,11 +7485,8 @@ static int __build_sched_domains(const struct cpumask *cpu_map, build_sched_groups(&d, SD_LV_SIBLING, cpu_map, i); build_sched_groups(&d, SD_LV_BOOK, cpu_map, i); build_sched_groups(&d, SD_LV_MC, cpu_map, i); - } - - /* Set up physical groups */ - for (i = 0; i < nr_node_ids; i++) build_sched_groups(&d, SD_LV_CPU, cpu_map, i); + } #ifdef CONFIG_NUMA /* Set up node groups */ -- cgit v0.10.2 From cd4ea6ae3982f6861da3b510e69cbc194f331d83 Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Thu, 7 Apr 2011 14:09:45 +0200 Subject: sched: Change NODE sched_domain group creation The NODE sched_domain is 'special' in that it allocates sched_groups per CPU, instead of sharing the sched_groups between all CPUs. While this might have some benefits on large NUMA and avoid remote memory accesses when iterating the sched_groups, this does break current code that assumes sched_groups are shared between all sched_domains (since the dynamic cpu_power patches). So refactor the NODE groups to behave like all other groups. (The ALLNODES domain again shared its groups across the CPUs for some reason). If someone does measure a performance decrease due to this change we need to revisit this and come up with another way to have both dynamic cpu_power and NUMA work nice together. Signed-off-by: Peter Zijlstra Cc: Mike Galbraith Cc: Nick Piggin Cc: Linus Torvalds Cc: Andrew Morton Link: http://lkml.kernel.org/r/20110407122941.978111700@chello.nl Signed-off-by: Ingo Molnar diff --git a/kernel/sched.c b/kernel/sched.c index e3818f1..72d561f 100644 --- a/kernel/sched.c +++ b/kernel/sched.c @@ -6861,29 +6861,18 @@ struct static_sched_domain { struct s_data { #ifdef CONFIG_NUMA int sd_allnodes; - cpumask_var_t domainspan; - cpumask_var_t covered; - cpumask_var_t notcovered; #endif cpumask_var_t nodemask; cpumask_var_t send_covered; cpumask_var_t tmpmask; - struct sched_group **sched_group_nodes; struct root_domain *rd; }; enum s_alloc { - sa_sched_groups = 0, sa_rootdomain, sa_tmpmask, sa_send_covered, sa_nodemask, - sa_sched_group_nodes, -#ifdef CONFIG_NUMA - sa_notcovered, - sa_covered, - sa_domainspan, -#endif sa_none, }; @@ -6979,18 +6968,10 @@ cpu_to_phys_group(int cpu, const struct cpumask *cpu_map, } #ifdef CONFIG_NUMA -/* - * The init_sched_build_groups can't handle what we want to do with node - * groups, so roll our own. Now each node has its own list of groups which - * gets dynamically allocated. - */ static DEFINE_PER_CPU(struct static_sched_domain, node_domains); -static struct sched_group ***sched_group_nodes_bycpu; - -static DEFINE_PER_CPU(struct static_sched_domain, allnodes_domains); -static DEFINE_PER_CPU(struct static_sched_group, sched_group_allnodes); +static DEFINE_PER_CPU(struct static_sched_group, sched_group_node); -static int cpu_to_allnodes_group(int cpu, const struct cpumask *cpu_map, +static int cpu_to_node_group(int cpu, const struct cpumask *cpu_map, struct sched_group **sg, struct cpumask *nodemask) { @@ -7000,142 +6981,27 @@ static int cpu_to_allnodes_group(int cpu, const struct cpumask *cpu_map, group = cpumask_first(nodemask); if (sg) - *sg = &per_cpu(sched_group_allnodes, group).sg; + *sg = &per_cpu(sched_group_node, group).sg; return group; } -static void init_numa_sched_groups_power(struct sched_group *group_head) -{ - struct sched_group *sg = group_head; - int j; - - if (!sg) - return; - do { - for_each_cpu(j, sched_group_cpus(sg)) { - struct sched_domain *sd; - - sd = &per_cpu(phys_domains, j).sd; - if (j != group_first_cpu(sd->groups)) { - /* - * Only add "power" once for each - * physical package. - */ - continue; - } - - sg->cpu_power += sd->groups->cpu_power; - } - sg = sg->next; - } while (sg != group_head); -} +static DEFINE_PER_CPU(struct static_sched_domain, allnodes_domains); +static DEFINE_PER_CPU(struct static_sched_group, sched_group_allnodes); -static int build_numa_sched_groups(struct s_data *d, - const struct cpumask *cpu_map, int num) +static int cpu_to_allnodes_group(int cpu, const struct cpumask *cpu_map, + struct sched_group **sg, + struct cpumask *nodemask) { - struct sched_domain *sd; - struct sched_group *sg, *prev; - int n, j; - - cpumask_clear(d->covered); - cpumask_and(d->nodemask, cpumask_of_node(num), cpu_map); - if (cpumask_empty(d->nodemask)) { - d->sched_group_nodes[num] = NULL; - goto out; - } - - sched_domain_node_span(num, d->domainspan); - cpumask_and(d->domainspan, d->domainspan, cpu_map); - - sg = kmalloc_node(sizeof(struct sched_group) + cpumask_size(), - GFP_KERNEL, num); - if (!sg) { - printk(KERN_WARNING "Can not alloc domain group for node %d\n", - num); - return -ENOMEM; - } - d->sched_group_nodes[num] = sg; - - for_each_cpu(j, d->nodemask) { - sd = &per_cpu(node_domains, j).sd; - sd->groups = sg; - } + int group; - sg->cpu_power = 0; - cpumask_copy(sched_group_cpus(sg), d->nodemask); - sg->next = sg; - cpumask_or(d->covered, d->covered, d->nodemask); + cpumask_and(nodemask, cpumask_of_node(cpu_to_node(cpu)), cpu_map); + group = cpumask_first(nodemask); - prev = sg; - for (j = 0; j < nr_node_ids; j++) { - n = (num + j) % nr_node_ids; - cpumask_complement(d->notcovered, d->covered); - cpumask_and(d->tmpmask, d->notcovered, cpu_map); - cpumask_and(d->tmpmask, d->tmpmask, d->domainspan); - if (cpumask_empty(d->tmpmask)) - break; - cpumask_and(d->tmpmask, d->tmpmask, cpumask_of_node(n)); - if (cpumask_empty(d->tmpmask)) - continue; - sg = kmalloc_node(sizeof(struct sched_group) + cpumask_size(), - GFP_KERNEL, num); - if (!sg) { - printk(KERN_WARNING - "Can not alloc domain group for node %d\n", j); - return -ENOMEM; - } - sg->cpu_power = 0; - cpumask_copy(sched_group_cpus(sg), d->tmpmask); - sg->next = prev->next; - cpumask_or(d->covered, d->covered, d->tmpmask); - prev->next = sg; - prev = sg; - } -out: - return 0; + if (sg) + *sg = &per_cpu(sched_group_allnodes, group).sg; + return group; } -#endif /* CONFIG_NUMA */ - -#ifdef CONFIG_NUMA -/* Free memory allocated for various sched_group structures */ -static void free_sched_groups(const struct cpumask *cpu_map, - struct cpumask *nodemask) -{ - int cpu, i; - for_each_cpu(cpu, cpu_map) { - struct sched_group **sched_group_nodes - = sched_group_nodes_bycpu[cpu]; - - if (!sched_group_nodes) - continue; - - for (i = 0; i < nr_node_ids; i++) { - struct sched_group *oldsg, *sg = sched_group_nodes[i]; - - cpumask_and(nodemask, cpumask_of_node(i), cpu_map); - if (cpumask_empty(nodemask)) - continue; - - if (sg == NULL) - continue; - sg = sg->next; -next_sg: - oldsg = sg; - sg = sg->next; - kfree(oldsg); - if (oldsg != sched_group_nodes[i]) - goto next_sg; - } - kfree(sched_group_nodes); - sched_group_nodes_bycpu[cpu] = NULL; - } -} -#else /* !CONFIG_NUMA */ -static void free_sched_groups(const struct cpumask *cpu_map, - struct cpumask *nodemask) -{ -} #endif /* CONFIG_NUMA */ /* @@ -7236,9 +7102,6 @@ static void __free_domain_allocs(struct s_data *d, enum s_alloc what, const struct cpumask *cpu_map) { switch (what) { - case sa_sched_groups: - free_sched_groups(cpu_map, d->tmpmask); /* fall through */ - d->sched_group_nodes = NULL; case sa_rootdomain: free_rootdomain(d->rd); /* fall through */ case sa_tmpmask: @@ -7247,16 +7110,6 @@ static void __free_domain_allocs(struct s_data *d, enum s_alloc what, free_cpumask_var(d->send_covered); /* fall through */ case sa_nodemask: free_cpumask_var(d->nodemask); /* fall through */ - case sa_sched_group_nodes: -#ifdef CONFIG_NUMA - kfree(d->sched_group_nodes); /* fall through */ - case sa_notcovered: - free_cpumask_var(d->notcovered); /* fall through */ - case sa_covered: - free_cpumask_var(d->covered); /* fall through */ - case sa_domainspan: - free_cpumask_var(d->domainspan); /* fall through */ -#endif case sa_none: break; } @@ -7265,24 +7118,8 @@ static void __free_domain_allocs(struct s_data *d, enum s_alloc what, static enum s_alloc __visit_domain_allocation_hell(struct s_data *d, const struct cpumask *cpu_map) { -#ifdef CONFIG_NUMA - if (!alloc_cpumask_var(&d->domainspan, GFP_KERNEL)) - return sa_none; - if (!alloc_cpumask_var(&d->covered, GFP_KERNEL)) - return sa_domainspan; - if (!alloc_cpumask_var(&d->notcovered, GFP_KERNEL)) - return sa_covered; - /* Allocate the per-node list of sched groups */ - d->sched_group_nodes = kcalloc(nr_node_ids, - sizeof(struct sched_group *), GFP_KERNEL); - if (!d->sched_group_nodes) { - printk(KERN_WARNING "Can not alloc sched group node list\n"); - return sa_notcovered; - } - sched_group_nodes_bycpu[cpumask_first(cpu_map)] = d->sched_group_nodes; -#endif if (!alloc_cpumask_var(&d->nodemask, GFP_KERNEL)) - return sa_sched_group_nodes; + return sa_none; if (!alloc_cpumask_var(&d->send_covered, GFP_KERNEL)) return sa_nodemask; if (!alloc_cpumask_var(&d->tmpmask, GFP_KERNEL)) @@ -7322,6 +7159,7 @@ static struct sched_domain *__build_numa_sched_domains(struct s_data *d, if (parent) parent->child = sd; cpumask_and(sched_domain_span(sd), sched_domain_span(sd), cpu_map); + cpu_to_node_group(i, cpu_map, &sd->groups, d->tmpmask); #endif return sd; } @@ -7434,6 +7272,13 @@ static void build_sched_groups(struct s_data *d, enum sched_domain_level l, d->send_covered, d->tmpmask); break; #ifdef CONFIG_NUMA + case SD_LV_NODE: + sd = &per_cpu(node_domains, cpu).sd; + if (cpu == cpumask_first(sched_domain_span(sd))) + init_sched_build_groups(sched_domain_span(sd), cpu_map, + &cpu_to_node_group, + d->send_covered, d->tmpmask); + case SD_LV_ALLNODES: init_sched_build_groups(cpu_map, cpu_map, &cpu_to_allnodes_group, d->send_covered, d->tmpmask); @@ -7462,7 +7307,6 @@ static int __build_sched_domains(const struct cpumask *cpu_map, alloc_state = __visit_domain_allocation_hell(&d, cpu_map); if (alloc_state != sa_rootdomain) goto error; - alloc_state = sa_sched_groups; /* * Set up domains for cpus specified by the cpu_map. @@ -7486,16 +7330,13 @@ static int __build_sched_domains(const struct cpumask *cpu_map, build_sched_groups(&d, SD_LV_BOOK, cpu_map, i); build_sched_groups(&d, SD_LV_MC, cpu_map, i); build_sched_groups(&d, SD_LV_CPU, cpu_map, i); + build_sched_groups(&d, SD_LV_NODE, cpu_map, i); } #ifdef CONFIG_NUMA /* Set up node groups */ if (d.sd_allnodes) build_sched_groups(&d, SD_LV_ALLNODES, cpu_map, 0); - - for (i = 0; i < nr_node_ids; i++) - if (build_numa_sched_groups(&d, cpu_map, i)) - goto error; #endif /* Calculate CPU power for physical packages and nodes */ @@ -7524,15 +7365,16 @@ static int __build_sched_domains(const struct cpumask *cpu_map, } #ifdef CONFIG_NUMA - for (i = 0; i < nr_node_ids; i++) - init_numa_sched_groups_power(d.sched_group_nodes[i]); + for_each_cpu(i, cpu_map) { + sd = &per_cpu(node_domains, i).sd; + init_sched_groups_power(i, sd); + } if (d.sd_allnodes) { - struct sched_group *sg; - - cpu_to_allnodes_group(cpumask_first(cpu_map), cpu_map, &sg, - d.tmpmask); - init_numa_sched_groups_power(sg); + for_each_cpu(i, cpu_map) { + sd = &per_cpu(allnodes_domains, i).sd; + init_sched_groups_power(i, sd); + } } #endif @@ -7550,7 +7392,6 @@ static int __build_sched_domains(const struct cpumask *cpu_map, cpu_attach_domain(sd, d.rd, i); } - d.sched_group_nodes = NULL; /* don't free this we still need it */ __free_domain_allocs(&d, sa_tmpmask, cpu_map); return 0; @@ -7636,7 +7477,6 @@ static int init_sched_domains(const struct cpumask *cpu_map) static void destroy_sched_domains(const struct cpumask *cpu_map, struct cpumask *tmpmask) { - free_sched_groups(cpu_map, tmpmask); } /* @@ -7913,11 +7753,6 @@ void __init sched_init_smp(void) alloc_cpumask_var(&non_isolated_cpus, GFP_KERNEL); alloc_cpumask_var(&fallback_doms, GFP_KERNEL); -#if defined(CONFIG_NUMA) - sched_group_nodes_bycpu = kzalloc(nr_cpu_ids * sizeof(void **), - GFP_KERNEL); - BUG_ON(sched_group_nodes_bycpu == NULL); -#endif get_online_cpus(); mutex_lock(&sched_domains_mutex); init_sched_domains(cpu_active_mask); -- cgit v0.10.2 From 3739494e08da50c8a68d65eed5ba3012a54b40d4 Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Thu, 7 Apr 2011 14:09:46 +0200 Subject: sched: Clean up some ALLNODES code Signed-off-by: Peter Zijlstra Cc: Mike Galbraith Cc: Nick Piggin Cc: Linus Torvalds Cc: Andrew Morton Link: http://lkml.kernel.org/r/20110407122942.025636011@chello.nl Signed-off-by: Ingo Molnar diff --git a/kernel/sched.c b/kernel/sched.c index 72d561f..fa10cf7 100644 --- a/kernel/sched.c +++ b/kernel/sched.c @@ -7280,7 +7280,9 @@ static void build_sched_groups(struct s_data *d, enum sched_domain_level l, d->send_covered, d->tmpmask); case SD_LV_ALLNODES: - init_sched_build_groups(cpu_map, cpu_map, &cpu_to_allnodes_group, + if (cpu == cpumask_first(cpu_map)) + init_sched_build_groups(cpu_map, cpu_map, + &cpu_to_allnodes_group, d->send_covered, d->tmpmask); break; #endif @@ -7331,14 +7333,9 @@ static int __build_sched_domains(const struct cpumask *cpu_map, build_sched_groups(&d, SD_LV_MC, cpu_map, i); build_sched_groups(&d, SD_LV_CPU, cpu_map, i); build_sched_groups(&d, SD_LV_NODE, cpu_map, i); + build_sched_groups(&d, SD_LV_ALLNODES, cpu_map, i); } -#ifdef CONFIG_NUMA - /* Set up node groups */ - if (d.sd_allnodes) - build_sched_groups(&d, SD_LV_ALLNODES, cpu_map, 0); -#endif - /* Calculate CPU power for physical packages and nodes */ #ifdef CONFIG_SCHED_SMT for_each_cpu(i, cpu_map) { -- cgit v0.10.2 From 1cf51902546d60b8a7a6aba2dd557bd4ba8840ea Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Thu, 7 Apr 2011 14:09:47 +0200 Subject: sched: Simplify sched_group creation Instead of calling build_sched_groups() for each possible sched_domain we might have created, note that we can simply iterate the sched_domain tree and call it for each sched_domain present. Signed-off-by: Peter Zijlstra Cc: Mike Galbraith Cc: Nick Piggin Cc: Linus Torvalds Cc: Andrew Morton Link: http://lkml.kernel.org/r/20110407122942.077862519@chello.nl Signed-off-by: Ingo Molnar diff --git a/kernel/sched.c b/kernel/sched.c index fa10cf7..e66d24a 100644 --- a/kernel/sched.c +++ b/kernel/sched.c @@ -7231,15 +7231,12 @@ static struct sched_domain *__build_smt_sched_domain(struct s_data *d, return sd; } -static void build_sched_groups(struct s_data *d, enum sched_domain_level l, +static void build_sched_groups(struct s_data *d, struct sched_domain *sd, const struct cpumask *cpu_map, int cpu) { - struct sched_domain *sd; - - switch (l) { + switch (sd->level) { #ifdef CONFIG_SCHED_SMT case SD_LV_SIBLING: /* set up CPU (sibling) groups */ - sd = &per_cpu(cpu_domains, cpu).sd; if (cpu == cpumask_first(sched_domain_span(sd))) init_sched_build_groups(sched_domain_span(sd), cpu_map, &cpu_to_cpu_group, @@ -7248,7 +7245,6 @@ static void build_sched_groups(struct s_data *d, enum sched_domain_level l, #endif #ifdef CONFIG_SCHED_MC case SD_LV_MC: /* set up multi-core groups */ - sd = &per_cpu(core_domains, cpu).sd; if (cpu == cpumask_first(sched_domain_span(sd))) init_sched_build_groups(sched_domain_span(sd), cpu_map, &cpu_to_core_group, @@ -7257,7 +7253,6 @@ static void build_sched_groups(struct s_data *d, enum sched_domain_level l, #endif #ifdef CONFIG_SCHED_BOOK case SD_LV_BOOK: /* set up book groups */ - sd = &per_cpu(book_domains, cpu).sd; if (cpu == cpumask_first(sched_domain_span(sd))) init_sched_build_groups(sched_domain_span(sd), cpu_map, &cpu_to_book_group, @@ -7265,7 +7260,6 @@ static void build_sched_groups(struct s_data *d, enum sched_domain_level l, break; #endif case SD_LV_CPU: /* set up physical groups */ - sd = &per_cpu(phys_domains, cpu).sd; if (cpu == cpumask_first(sched_domain_span(sd))) init_sched_build_groups(sched_domain_span(sd), cpu_map, &cpu_to_phys_group, @@ -7273,7 +7267,6 @@ static void build_sched_groups(struct s_data *d, enum sched_domain_level l, break; #ifdef CONFIG_NUMA case SD_LV_NODE: - sd = &per_cpu(node_domains, cpu).sd; if (cpu == cpumask_first(sched_domain_span(sd))) init_sched_build_groups(sched_domain_span(sd), cpu_map, &cpu_to_node_group, @@ -7323,17 +7316,10 @@ static int __build_sched_domains(const struct cpumask *cpu_map, sd = __build_mc_sched_domain(&d, cpu_map, attr, sd, i); sd = __build_smt_sched_domain(&d, cpu_map, attr, sd, i); - for (tmp = sd; tmp; tmp = tmp->parent) + for (tmp = sd; tmp; tmp = tmp->parent) { tmp->span_weight = cpumask_weight(sched_domain_span(tmp)); - } - - for_each_cpu(i, cpu_map) { - build_sched_groups(&d, SD_LV_SIBLING, cpu_map, i); - build_sched_groups(&d, SD_LV_BOOK, cpu_map, i); - build_sched_groups(&d, SD_LV_MC, cpu_map, i); - build_sched_groups(&d, SD_LV_CPU, cpu_map, i); - build_sched_groups(&d, SD_LV_NODE, cpu_map, i); - build_sched_groups(&d, SD_LV_ALLNODES, cpu_map, i); + build_sched_groups(&d, tmp, cpu_map, i); + } } /* Calculate CPU power for physical packages and nodes */ -- cgit v0.10.2 From 21d42ccfd6c6c11f96c2acfd32a85cfc33514d3a Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Thu, 7 Apr 2011 14:09:48 +0200 Subject: sched: Simplify finding the lowest sched_domain Instead of relying on knowing the build order and various CONFIG_ flags simply remember the bottom most sched_domain when we created the domain hierarchy. Signed-off-by: Peter Zijlstra Cc: Mike Galbraith Cc: Nick Piggin Cc: Linus Torvalds Cc: Andrew Morton Link: http://lkml.kernel.org/r/20110407122942.134511046@chello.nl Signed-off-by: Ingo Molnar diff --git a/kernel/sched.c b/kernel/sched.c index e66d24a..d6992bf 100644 --- a/kernel/sched.c +++ b/kernel/sched.c @@ -6865,11 +6865,13 @@ struct s_data { cpumask_var_t nodemask; cpumask_var_t send_covered; cpumask_var_t tmpmask; + struct sched_domain ** __percpu sd; struct root_domain *rd; }; enum s_alloc { sa_rootdomain, + sa_sd, sa_tmpmask, sa_send_covered, sa_nodemask, @@ -7104,6 +7106,8 @@ static void __free_domain_allocs(struct s_data *d, enum s_alloc what, switch (what) { case sa_rootdomain: free_rootdomain(d->rd); /* fall through */ + case sa_sd: + free_percpu(d->sd); /* fall through */ case sa_tmpmask: free_cpumask_var(d->tmpmask); /* fall through */ case sa_send_covered: @@ -7124,10 +7128,15 @@ static enum s_alloc __visit_domain_allocation_hell(struct s_data *d, return sa_nodemask; if (!alloc_cpumask_var(&d->tmpmask, GFP_KERNEL)) return sa_send_covered; + d->sd = alloc_percpu(struct sched_domain *); + if (!d->sd) { + printk(KERN_WARNING "Cannot alloc per-cpu pointers\n"); + return sa_tmpmask; + } d->rd = alloc_rootdomain(); if (!d->rd) { printk(KERN_WARNING "Cannot alloc root domain\n"); - return sa_tmpmask; + return sa_sd; } return sa_rootdomain; } @@ -7316,6 +7325,8 @@ static int __build_sched_domains(const struct cpumask *cpu_map, sd = __build_mc_sched_domain(&d, cpu_map, attr, sd, i); sd = __build_smt_sched_domain(&d, cpu_map, attr, sd, i); + *per_cpu_ptr(d.sd, i) = sd; + for (tmp = sd; tmp; tmp = tmp->parent) { tmp->span_weight = cpumask_weight(sched_domain_span(tmp)); build_sched_groups(&d, tmp, cpu_map, i); @@ -7363,15 +7374,7 @@ static int __build_sched_domains(const struct cpumask *cpu_map, /* Attach the domains */ for_each_cpu(i, cpu_map) { -#ifdef CONFIG_SCHED_SMT - sd = &per_cpu(cpu_domains, i).sd; -#elif defined(CONFIG_SCHED_MC) - sd = &per_cpu(core_domains, i).sd; -#elif defined(CONFIG_SCHED_BOOK) - sd = &per_cpu(book_domains, i).sd; -#else - sd = &per_cpu(phys_domains, i).sd; -#endif + sd = *per_cpu_ptr(d.sd, i); cpu_attach_domain(sd, d.rd, i); } -- cgit v0.10.2 From a9c9a9b6bff27ac9c746344a9c1a19bf3327002c Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Thu, 7 Apr 2011 14:09:49 +0200 Subject: sched: Simplify sched_groups_power initialization Again, instead of relying on knowing the possible domains and their order, simply rely on the sched_domain tree and whatever domains are present in there to initialize the sched_group cpu_power. Note: we need to iterate the CPU mask backwards because of the cpumask_first() condition for iterating up the tree. By iterating the mask backwards we ensure all groups of a domain are set-up before starting on the parent groups that rely on its children to be completely done. Signed-off-by: Peter Zijlstra Cc: Mike Galbraith Cc: Nick Piggin Cc: Linus Torvalds Cc: Andrew Morton Link: http://lkml.kernel.org/r/20110407122942.187335414@chello.nl Signed-off-by: Ingo Molnar diff --git a/kernel/sched.c b/kernel/sched.c index d6992bf..1cca59e 100644 --- a/kernel/sched.c +++ b/kernel/sched.c @@ -7334,43 +7334,14 @@ static int __build_sched_domains(const struct cpumask *cpu_map, } /* Calculate CPU power for physical packages and nodes */ -#ifdef CONFIG_SCHED_SMT - for_each_cpu(i, cpu_map) { - sd = &per_cpu(cpu_domains, i).sd; - init_sched_groups_power(i, sd); - } -#endif -#ifdef CONFIG_SCHED_MC - for_each_cpu(i, cpu_map) { - sd = &per_cpu(core_domains, i).sd; - init_sched_groups_power(i, sd); - } -#endif -#ifdef CONFIG_SCHED_BOOK - for_each_cpu(i, cpu_map) { - sd = &per_cpu(book_domains, i).sd; - init_sched_groups_power(i, sd); - } -#endif - - for_each_cpu(i, cpu_map) { - sd = &per_cpu(phys_domains, i).sd; - init_sched_groups_power(i, sd); - } - -#ifdef CONFIG_NUMA - for_each_cpu(i, cpu_map) { - sd = &per_cpu(node_domains, i).sd; - init_sched_groups_power(i, sd); - } + for (i = nr_cpumask_bits-1; i >= 0; i--) { + if (!cpumask_test_cpu(i, cpu_map)) + continue; - if (d.sd_allnodes) { - for_each_cpu(i, cpu_map) { - sd = &per_cpu(allnodes_domains, i).sd; + sd = *per_cpu_ptr(d.sd, i); + for (; sd; sd = sd->parent) init_sched_groups_power(i, sd); - } } -#endif /* Attach the domains */ for_each_cpu(i, cpu_map) { -- cgit v0.10.2 From dce840a08702bd13a9a186e07e63d1ef82256b5e Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Thu, 7 Apr 2011 14:09:50 +0200 Subject: sched: Dynamically allocate sched_domain/sched_group data-structures Instead of relying on static allocations for the sched_domain and sched_group trees, dynamically allocate and RCU free them. Allocating this dynamically also allows for some build_sched_groups() simplification since we can now (like with other simplifications) rely on the sched_domain tree instead of hard-coded knowledge. One tricky to note is that detach_destroy_domains() needs to hold rcu_read_lock() over the entire tear-down, per-cpu is not sufficient since that can lead to partial sched_group existance (could possibly be solved by doing the tear-down backwards but this is much more robust). A concequence of the above is that we can no longer print the sched_domain debug stuff from cpu_attach_domain() since that might now run with preemption disabled (due to classic RCU etc.) and sched_domain_debug() does some GFP_KERNEL allocations. Another thing to note is that we now fully rely on normal RCU and not RCU-sched, this is because with the new and exiting RCU flavours we grew over the years BH doesn't necessarily hold off RCU-sched grace periods (-rt is known to break this). This would in fact already cause us grief since we do sched_domain/sched_group iterations from softirq context. This patch is somewhat larger than I would like it to be, but I didn't find any means of shrinking/splitting this. Signed-off-by: Peter Zijlstra Cc: Mike Galbraith Cc: Nick Piggin Cc: Linus Torvalds Cc: Andrew Morton Link: http://lkml.kernel.org/r/20110407122942.245307941@chello.nl Signed-off-by: Ingo Molnar diff --git a/include/linux/sched.h b/include/linux/sched.h index 4ec2c02..020b79d 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h @@ -868,6 +868,7 @@ static inline int sd_power_saving_flags(void) struct sched_group { struct sched_group *next; /* Must be a circular list */ + atomic_t ref; /* * CPU power of this group, SCHED_LOAD_SCALE being max power for a @@ -973,6 +974,10 @@ struct sched_domain { #ifdef CONFIG_SCHED_DEBUG char *name; #endif + union { + void *private; /* used during construction */ + struct rcu_head rcu; /* used during destruction */ + }; unsigned int span_weight; /* diff --git a/kernel/sched.c b/kernel/sched.c index 1cca59e..6520484 100644 --- a/kernel/sched.c +++ b/kernel/sched.c @@ -417,6 +417,7 @@ struct rt_rq { */ struct root_domain { atomic_t refcount; + struct rcu_head rcu; cpumask_var_t span; cpumask_var_t online; @@ -571,7 +572,7 @@ static inline int cpu_of(struct rq *rq) #define rcu_dereference_check_sched_domain(p) \ rcu_dereference_check((p), \ - rcu_read_lock_sched_held() || \ + rcu_read_lock_held() || \ lockdep_is_held(&sched_domains_mutex)) /* @@ -6572,12 +6573,11 @@ sd_parent_degenerate(struct sched_domain *sd, struct sched_domain *parent) return 1; } -static void free_rootdomain(struct root_domain *rd) +static void free_rootdomain(struct rcu_head *rcu) { - synchronize_sched(); + struct root_domain *rd = container_of(rcu, struct root_domain, rcu); cpupri_cleanup(&rd->cpupri); - free_cpumask_var(rd->rto_mask); free_cpumask_var(rd->online); free_cpumask_var(rd->span); @@ -6618,7 +6618,7 @@ static void rq_attach_root(struct rq *rq, struct root_domain *rd) raw_spin_unlock_irqrestore(&rq->lock, flags); if (old_rd) - free_rootdomain(old_rd); + call_rcu_sched(&old_rd->rcu, free_rootdomain); } static int init_rootdomain(struct root_domain *rd) @@ -6669,6 +6669,25 @@ static struct root_domain *alloc_rootdomain(void) return rd; } +static void free_sched_domain(struct rcu_head *rcu) +{ + struct sched_domain *sd = container_of(rcu, struct sched_domain, rcu); + if (atomic_dec_and_test(&sd->groups->ref)) + kfree(sd->groups); + kfree(sd); +} + +static void destroy_sched_domain(struct sched_domain *sd, int cpu) +{ + call_rcu(&sd->rcu, free_sched_domain); +} + +static void destroy_sched_domains(struct sched_domain *sd, int cpu) +{ + for (; sd; sd = sd->parent) + destroy_sched_domain(sd, cpu); +} + /* * Attach the domain 'sd' to 'cpu' as its base domain. Callers must * hold the hotplug lock. @@ -6689,20 +6708,25 @@ cpu_attach_domain(struct sched_domain *sd, struct root_domain *rd, int cpu) tmp->parent = parent->parent; if (parent->parent) parent->parent->child = tmp; + destroy_sched_domain(parent, cpu); } else tmp = tmp->parent; } if (sd && sd_degenerate(sd)) { + tmp = sd; sd = sd->parent; + destroy_sched_domain(tmp, cpu); if (sd) sd->child = NULL; } - sched_domain_debug(sd, cpu); + /* sched_domain_debug(sd, cpu); */ rq_attach_root(rq, rd); + tmp = rq->sd; rcu_assign_pointer(rq->sd, sd); + destroy_sched_domains(tmp, cpu); } /* cpus with isolated domains */ @@ -6718,56 +6742,6 @@ static int __init isolated_cpu_setup(char *str) __setup("isolcpus=", isolated_cpu_setup); -/* - * init_sched_build_groups takes the cpumask we wish to span, and a pointer - * to a function which identifies what group(along with sched group) a CPU - * belongs to. The return value of group_fn must be a >= 0 and < nr_cpu_ids - * (due to the fact that we keep track of groups covered with a struct cpumask). - * - * init_sched_build_groups will build a circular linked list of the groups - * covered by the given span, and will set each group's ->cpumask correctly, - * and ->cpu_power to 0. - */ -static void -init_sched_build_groups(const struct cpumask *span, - const struct cpumask *cpu_map, - int (*group_fn)(int cpu, const struct cpumask *cpu_map, - struct sched_group **sg, - struct cpumask *tmpmask), - struct cpumask *covered, struct cpumask *tmpmask) -{ - struct sched_group *first = NULL, *last = NULL; - int i; - - cpumask_clear(covered); - - for_each_cpu(i, span) { - struct sched_group *sg; - int group = group_fn(i, cpu_map, &sg, tmpmask); - int j; - - if (cpumask_test_cpu(i, covered)) - continue; - - cpumask_clear(sched_group_cpus(sg)); - sg->cpu_power = 0; - - for_each_cpu(j, span) { - if (group_fn(j, cpu_map, NULL, tmpmask) != group) - continue; - - cpumask_set_cpu(j, covered); - cpumask_set_cpu(j, sched_group_cpus(sg)); - } - if (!first) - first = sg; - if (last) - last->next = sg; - last = sg; - } - last->next = first; -} - #define SD_NODES_PER_DOMAIN 16 #ifdef CONFIG_NUMA @@ -6858,154 +6832,96 @@ struct static_sched_domain { DECLARE_BITMAP(span, CONFIG_NR_CPUS); }; +struct sd_data { + struct sched_domain **__percpu sd; + struct sched_group **__percpu sg; +}; + struct s_data { #ifdef CONFIG_NUMA int sd_allnodes; #endif cpumask_var_t nodemask; cpumask_var_t send_covered; - cpumask_var_t tmpmask; struct sched_domain ** __percpu sd; + struct sd_data sdd[SD_LV_MAX]; struct root_domain *rd; }; enum s_alloc { sa_rootdomain, sa_sd, - sa_tmpmask, + sa_sd_storage, sa_send_covered, sa_nodemask, sa_none, }; /* - * SMT sched-domains: + * Assumes the sched_domain tree is fully constructed */ -#ifdef CONFIG_SCHED_SMT -static DEFINE_PER_CPU(struct static_sched_domain, cpu_domains); -static DEFINE_PER_CPU(struct static_sched_group, sched_groups); - -static int -cpu_to_cpu_group(int cpu, const struct cpumask *cpu_map, - struct sched_group **sg, struct cpumask *unused) +static int get_group(int cpu, struct sd_data *sdd, struct sched_group **sg) { - if (sg) - *sg = &per_cpu(sched_groups, cpu).sg; - return cpu; -} -#endif /* CONFIG_SCHED_SMT */ + struct sched_domain *sd = *per_cpu_ptr(sdd->sd, cpu); + struct sched_domain *child = sd->child; -/* - * multi-core sched-domains: - */ -#ifdef CONFIG_SCHED_MC -static DEFINE_PER_CPU(struct static_sched_domain, core_domains); -static DEFINE_PER_CPU(struct static_sched_group, sched_group_core); + if (child) + cpu = cpumask_first(sched_domain_span(child)); -static int -cpu_to_core_group(int cpu, const struct cpumask *cpu_map, - struct sched_group **sg, struct cpumask *mask) -{ - int group; -#ifdef CONFIG_SCHED_SMT - cpumask_and(mask, topology_thread_cpumask(cpu), cpu_map); - group = cpumask_first(mask); -#else - group = cpu; -#endif if (sg) - *sg = &per_cpu(sched_group_core, group).sg; - return group; + *sg = *per_cpu_ptr(sdd->sg, cpu); + + return cpu; } -#endif /* CONFIG_SCHED_MC */ /* - * book sched-domains: + * build_sched_groups takes the cpumask we wish to span, and a pointer + * to a function which identifies what group(along with sched group) a CPU + * belongs to. The return value of group_fn must be a >= 0 and < nr_cpu_ids + * (due to the fact that we keep track of groups covered with a struct cpumask). + * + * build_sched_groups will build a circular linked list of the groups + * covered by the given span, and will set each group's ->cpumask correctly, + * and ->cpu_power to 0. */ -#ifdef CONFIG_SCHED_BOOK -static DEFINE_PER_CPU(struct static_sched_domain, book_domains); -static DEFINE_PER_CPU(struct static_sched_group, sched_group_book); - -static int -cpu_to_book_group(int cpu, const struct cpumask *cpu_map, - struct sched_group **sg, struct cpumask *mask) -{ - int group = cpu; -#ifdef CONFIG_SCHED_MC - cpumask_and(mask, cpu_coregroup_mask(cpu), cpu_map); - group = cpumask_first(mask); -#elif defined(CONFIG_SCHED_SMT) - cpumask_and(mask, topology_thread_cpumask(cpu), cpu_map); - group = cpumask_first(mask); -#endif - if (sg) - *sg = &per_cpu(sched_group_book, group).sg; - return group; -} -#endif /* CONFIG_SCHED_BOOK */ - -static DEFINE_PER_CPU(struct static_sched_domain, phys_domains); -static DEFINE_PER_CPU(struct static_sched_group, sched_group_phys); - -static int -cpu_to_phys_group(int cpu, const struct cpumask *cpu_map, - struct sched_group **sg, struct cpumask *mask) +static void +build_sched_groups(struct sched_domain *sd, struct cpumask *covered) { - int group; -#ifdef CONFIG_SCHED_BOOK - cpumask_and(mask, cpu_book_mask(cpu), cpu_map); - group = cpumask_first(mask); -#elif defined(CONFIG_SCHED_MC) - cpumask_and(mask, cpu_coregroup_mask(cpu), cpu_map); - group = cpumask_first(mask); -#elif defined(CONFIG_SCHED_SMT) - cpumask_and(mask, topology_thread_cpumask(cpu), cpu_map); - group = cpumask_first(mask); -#else - group = cpu; -#endif - if (sg) - *sg = &per_cpu(sched_group_phys, group).sg; - return group; -} - -#ifdef CONFIG_NUMA -static DEFINE_PER_CPU(struct static_sched_domain, node_domains); -static DEFINE_PER_CPU(struct static_sched_group, sched_group_node); + struct sched_group *first = NULL, *last = NULL; + struct sd_data *sdd = sd->private; + const struct cpumask *span = sched_domain_span(sd); + int i; -static int cpu_to_node_group(int cpu, const struct cpumask *cpu_map, - struct sched_group **sg, - struct cpumask *nodemask) -{ - int group; + cpumask_clear(covered); - cpumask_and(nodemask, cpumask_of_node(cpu_to_node(cpu)), cpu_map); - group = cpumask_first(nodemask); + for_each_cpu(i, span) { + struct sched_group *sg; + int group = get_group(i, sdd, &sg); + int j; - if (sg) - *sg = &per_cpu(sched_group_node, group).sg; - return group; -} + if (cpumask_test_cpu(i, covered)) + continue; -static DEFINE_PER_CPU(struct static_sched_domain, allnodes_domains); -static DEFINE_PER_CPU(struct static_sched_group, sched_group_allnodes); + cpumask_clear(sched_group_cpus(sg)); + sg->cpu_power = 0; -static int cpu_to_allnodes_group(int cpu, const struct cpumask *cpu_map, - struct sched_group **sg, - struct cpumask *nodemask) -{ - int group; + for_each_cpu(j, span) { + if (get_group(j, sdd, NULL) != group) + continue; - cpumask_and(nodemask, cpumask_of_node(cpu_to_node(cpu)), cpu_map); - group = cpumask_first(nodemask); + cpumask_set_cpu(j, covered); + cpumask_set_cpu(j, sched_group_cpus(sg)); + } - if (sg) - *sg = &per_cpu(sched_group_allnodes, group).sg; - return group; + if (!first) + first = sg; + if (last) + last->next = sg; + last = sg; + } + last->next = first; } -#endif /* CONFIG_NUMA */ - /* * Initialize sched groups cpu_power. * @@ -7039,15 +6955,15 @@ static void init_sched_groups_power(int cpu, struct sched_domain *sd) # define SD_INIT_NAME(sd, type) do { } while (0) #endif -#define SD_INIT(sd, type) sd_init_##type(sd) - -#define SD_INIT_FUNC(type) \ -static noinline void sd_init_##type(struct sched_domain *sd) \ -{ \ - memset(sd, 0, sizeof(*sd)); \ - *sd = SD_##type##_INIT; \ - sd->level = SD_LV_##type; \ - SD_INIT_NAME(sd, type); \ +#define SD_INIT_FUNC(type) \ +static noinline struct sched_domain *sd_init_##type(struct s_data *d, int cpu) \ +{ \ + struct sched_domain *sd = *per_cpu_ptr(d->sdd[SD_LV_##type].sd, cpu); \ + *sd = SD_##type##_INIT; \ + sd->level = SD_LV_##type; \ + SD_INIT_NAME(sd, type); \ + sd->private = &d->sdd[SD_LV_##type]; \ + return sd; \ } SD_INIT_FUNC(CPU) @@ -7103,13 +7019,22 @@ static void set_domain_attribute(struct sched_domain *sd, static void __free_domain_allocs(struct s_data *d, enum s_alloc what, const struct cpumask *cpu_map) { + int i, j; + switch (what) { case sa_rootdomain: - free_rootdomain(d->rd); /* fall through */ + free_rootdomain(&d->rd->rcu); /* fall through */ case sa_sd: free_percpu(d->sd); /* fall through */ - case sa_tmpmask: - free_cpumask_var(d->tmpmask); /* fall through */ + case sa_sd_storage: + for (i = 0; i < SD_LV_MAX; i++) { + for_each_cpu(j, cpu_map) { + kfree(*per_cpu_ptr(d->sdd[i].sd, j)); + kfree(*per_cpu_ptr(d->sdd[i].sg, j)); + } + free_percpu(d->sdd[i].sd); + free_percpu(d->sdd[i].sg); + } /* fall through */ case sa_send_covered: free_cpumask_var(d->send_covered); /* fall through */ case sa_nodemask: @@ -7122,25 +7047,70 @@ static void __free_domain_allocs(struct s_data *d, enum s_alloc what, static enum s_alloc __visit_domain_allocation_hell(struct s_data *d, const struct cpumask *cpu_map) { + int i, j; + + memset(d, 0, sizeof(*d)); + if (!alloc_cpumask_var(&d->nodemask, GFP_KERNEL)) return sa_none; if (!alloc_cpumask_var(&d->send_covered, GFP_KERNEL)) return sa_nodemask; - if (!alloc_cpumask_var(&d->tmpmask, GFP_KERNEL)) - return sa_send_covered; - d->sd = alloc_percpu(struct sched_domain *); - if (!d->sd) { - printk(KERN_WARNING "Cannot alloc per-cpu pointers\n"); - return sa_tmpmask; + for (i = 0; i < SD_LV_MAX; i++) { + d->sdd[i].sd = alloc_percpu(struct sched_domain *); + if (!d->sdd[i].sd) + return sa_sd_storage; + + d->sdd[i].sg = alloc_percpu(struct sched_group *); + if (!d->sdd[i].sg) + return sa_sd_storage; + + for_each_cpu(j, cpu_map) { + struct sched_domain *sd; + struct sched_group *sg; + + sd = kzalloc_node(sizeof(struct sched_domain) + cpumask_size(), + GFP_KERNEL, cpu_to_node(j)); + if (!sd) + return sa_sd_storage; + + *per_cpu_ptr(d->sdd[i].sd, j) = sd; + + sg = kzalloc_node(sizeof(struct sched_group) + cpumask_size(), + GFP_KERNEL, cpu_to_node(j)); + if (!sg) + return sa_sd_storage; + + *per_cpu_ptr(d->sdd[i].sg, j) = sg; + } } + d->sd = alloc_percpu(struct sched_domain *); + if (!d->sd) + return sa_sd_storage; d->rd = alloc_rootdomain(); - if (!d->rd) { - printk(KERN_WARNING "Cannot alloc root domain\n"); + if (!d->rd) return sa_sd; - } return sa_rootdomain; } +/* + * NULL the sd_data elements we've used to build the sched_domain and + * sched_group structure so that the subsequent __free_domain_allocs() + * will not free the data we're using. + */ +static void claim_allocations(int cpu, struct sched_domain *sd) +{ + struct sd_data *sdd = sd->private; + struct sched_group *sg = sd->groups; + + WARN_ON_ONCE(*per_cpu_ptr(sdd->sd, cpu) != sd); + *per_cpu_ptr(sdd->sd, cpu) = NULL; + + if (cpu == cpumask_first(sched_group_cpus(sg))) { + WARN_ON_ONCE(*per_cpu_ptr(sdd->sg, cpu) != sg); + *per_cpu_ptr(sdd->sg, cpu) = NULL; + } +} + static struct sched_domain *__build_numa_sched_domains(struct s_data *d, const struct cpumask *cpu_map, struct sched_domain_attr *attr, int i) { @@ -7151,24 +7121,20 @@ static struct sched_domain *__build_numa_sched_domains(struct s_data *d, d->sd_allnodes = 0; if (cpumask_weight(cpu_map) > SD_NODES_PER_DOMAIN * cpumask_weight(d->nodemask)) { - sd = &per_cpu(allnodes_domains, i).sd; - SD_INIT(sd, ALLNODES); + sd = sd_init_ALLNODES(d, i); set_domain_attribute(sd, attr); cpumask_copy(sched_domain_span(sd), cpu_map); - cpu_to_allnodes_group(i, cpu_map, &sd->groups, d->tmpmask); d->sd_allnodes = 1; } parent = sd; - sd = &per_cpu(node_domains, i).sd; - SD_INIT(sd, NODE); + sd = sd_init_NODE(d, i); set_domain_attribute(sd, attr); sched_domain_node_span(cpu_to_node(i), sched_domain_span(sd)); sd->parent = parent; if (parent) parent->child = sd; cpumask_and(sched_domain_span(sd), sched_domain_span(sd), cpu_map); - cpu_to_node_group(i, cpu_map, &sd->groups, d->tmpmask); #endif return sd; } @@ -7178,14 +7144,12 @@ static struct sched_domain *__build_cpu_sched_domain(struct s_data *d, struct sched_domain *parent, int i) { struct sched_domain *sd; - sd = &per_cpu(phys_domains, i).sd; - SD_INIT(sd, CPU); + sd = sd_init_CPU(d, i); set_domain_attribute(sd, attr); cpumask_copy(sched_domain_span(sd), d->nodemask); sd->parent = parent; if (parent) parent->child = sd; - cpu_to_phys_group(i, cpu_map, &sd->groups, d->tmpmask); return sd; } @@ -7195,13 +7159,11 @@ static struct sched_domain *__build_book_sched_domain(struct s_data *d, { struct sched_domain *sd = parent; #ifdef CONFIG_SCHED_BOOK - sd = &per_cpu(book_domains, i).sd; - SD_INIT(sd, BOOK); + sd = sd_init_BOOK(d, i); set_domain_attribute(sd, attr); cpumask_and(sched_domain_span(sd), cpu_map, cpu_book_mask(i)); sd->parent = parent; parent->child = sd; - cpu_to_book_group(i, cpu_map, &sd->groups, d->tmpmask); #endif return sd; } @@ -7212,13 +7174,11 @@ static struct sched_domain *__build_mc_sched_domain(struct s_data *d, { struct sched_domain *sd = parent; #ifdef CONFIG_SCHED_MC - sd = &per_cpu(core_domains, i).sd; - SD_INIT(sd, MC); + sd = sd_init_MC(d, i); set_domain_attribute(sd, attr); cpumask_and(sched_domain_span(sd), cpu_map, cpu_coregroup_mask(i)); sd->parent = parent; parent->child = sd; - cpu_to_core_group(i, cpu_map, &sd->groups, d->tmpmask); #endif return sd; } @@ -7229,92 +7189,32 @@ static struct sched_domain *__build_smt_sched_domain(struct s_data *d, { struct sched_domain *sd = parent; #ifdef CONFIG_SCHED_SMT - sd = &per_cpu(cpu_domains, i).sd; - SD_INIT(sd, SIBLING); + sd = sd_init_SIBLING(d, i); set_domain_attribute(sd, attr); cpumask_and(sched_domain_span(sd), cpu_map, topology_thread_cpumask(i)); sd->parent = parent; parent->child = sd; - cpu_to_cpu_group(i, cpu_map, &sd->groups, d->tmpmask); #endif return sd; } -static void build_sched_groups(struct s_data *d, struct sched_domain *sd, - const struct cpumask *cpu_map, int cpu) -{ - switch (sd->level) { -#ifdef CONFIG_SCHED_SMT - case SD_LV_SIBLING: /* set up CPU (sibling) groups */ - if (cpu == cpumask_first(sched_domain_span(sd))) - init_sched_build_groups(sched_domain_span(sd), cpu_map, - &cpu_to_cpu_group, - d->send_covered, d->tmpmask); - break; -#endif -#ifdef CONFIG_SCHED_MC - case SD_LV_MC: /* set up multi-core groups */ - if (cpu == cpumask_first(sched_domain_span(sd))) - init_sched_build_groups(sched_domain_span(sd), cpu_map, - &cpu_to_core_group, - d->send_covered, d->tmpmask); - break; -#endif -#ifdef CONFIG_SCHED_BOOK - case SD_LV_BOOK: /* set up book groups */ - if (cpu == cpumask_first(sched_domain_span(sd))) - init_sched_build_groups(sched_domain_span(sd), cpu_map, - &cpu_to_book_group, - d->send_covered, d->tmpmask); - break; -#endif - case SD_LV_CPU: /* set up physical groups */ - if (cpu == cpumask_first(sched_domain_span(sd))) - init_sched_build_groups(sched_domain_span(sd), cpu_map, - &cpu_to_phys_group, - d->send_covered, d->tmpmask); - break; -#ifdef CONFIG_NUMA - case SD_LV_NODE: - if (cpu == cpumask_first(sched_domain_span(sd))) - init_sched_build_groups(sched_domain_span(sd), cpu_map, - &cpu_to_node_group, - d->send_covered, d->tmpmask); - - case SD_LV_ALLNODES: - if (cpu == cpumask_first(cpu_map)) - init_sched_build_groups(cpu_map, cpu_map, - &cpu_to_allnodes_group, - d->send_covered, d->tmpmask); - break; -#endif - default: - break; - } -} - /* * Build sched domains for a given set of cpus and attach the sched domains * to the individual cpus */ -static int __build_sched_domains(const struct cpumask *cpu_map, - struct sched_domain_attr *attr) +static int build_sched_domains(const struct cpumask *cpu_map, + struct sched_domain_attr *attr) { enum s_alloc alloc_state = sa_none; + struct sched_domain *sd; struct s_data d; - struct sched_domain *sd, *tmp; int i; -#ifdef CONFIG_NUMA - d.sd_allnodes = 0; -#endif alloc_state = __visit_domain_allocation_hell(&d, cpu_map); if (alloc_state != sa_rootdomain) goto error; - /* - * Set up domains for cpus specified by the cpu_map. - */ + /* Set up domains for cpus specified by the cpu_map. */ for_each_cpu(i, cpu_map) { cpumask_and(d.nodemask, cpumask_of_node(cpu_to_node(i)), cpu_map); @@ -7326,10 +7226,19 @@ static int __build_sched_domains(const struct cpumask *cpu_map, sd = __build_smt_sched_domain(&d, cpu_map, attr, sd, i); *per_cpu_ptr(d.sd, i) = sd; + } + + /* Build the groups for the domains */ + for_each_cpu(i, cpu_map) { + for (sd = *per_cpu_ptr(d.sd, i); sd; sd = sd->parent) { + sd->span_weight = cpumask_weight(sched_domain_span(sd)); + get_group(i, sd->private, &sd->groups); + atomic_inc(&sd->groups->ref); - for (tmp = sd; tmp; tmp = tmp->parent) { - tmp->span_weight = cpumask_weight(sched_domain_span(tmp)); - build_sched_groups(&d, tmp, cpu_map, i); + if (i != cpumask_first(sched_domain_span(sd))) + continue; + + build_sched_groups(sd, d.send_covered); } } @@ -7338,18 +7247,21 @@ static int __build_sched_domains(const struct cpumask *cpu_map, if (!cpumask_test_cpu(i, cpu_map)) continue; - sd = *per_cpu_ptr(d.sd, i); - for (; sd; sd = sd->parent) + for (sd = *per_cpu_ptr(d.sd, i); sd; sd = sd->parent) { + claim_allocations(i, sd); init_sched_groups_power(i, sd); + } } /* Attach the domains */ + rcu_read_lock(); for_each_cpu(i, cpu_map) { sd = *per_cpu_ptr(d.sd, i); cpu_attach_domain(sd, d.rd, i); } + rcu_read_unlock(); - __free_domain_allocs(&d, sa_tmpmask, cpu_map); + __free_domain_allocs(&d, sa_sd, cpu_map); return 0; error: @@ -7357,11 +7269,6 @@ error: return -ENOMEM; } -static int build_sched_domains(const struct cpumask *cpu_map) -{ - return __build_sched_domains(cpu_map, NULL); -} - static cpumask_var_t *doms_cur; /* current sched domains */ static int ndoms_cur; /* number of sched domains in 'doms_cur' */ static struct sched_domain_attr *dattr_cur; @@ -7425,31 +7332,24 @@ static int init_sched_domains(const struct cpumask *cpu_map) doms_cur = &fallback_doms; cpumask_andnot(doms_cur[0], cpu_map, cpu_isolated_map); dattr_cur = NULL; - err = build_sched_domains(doms_cur[0]); + err = build_sched_domains(doms_cur[0], NULL); register_sched_domain_sysctl(); return err; } -static void destroy_sched_domains(const struct cpumask *cpu_map, - struct cpumask *tmpmask) -{ -} - /* * Detach sched domains from a group of cpus specified in cpu_map * These cpus will now be attached to the NULL domain */ static void detach_destroy_domains(const struct cpumask *cpu_map) { - /* Save because hotplug lock held. */ - static DECLARE_BITMAP(tmpmask, CONFIG_NR_CPUS); int i; + rcu_read_lock(); for_each_cpu(i, cpu_map) cpu_attach_domain(NULL, &def_root_domain, i); - synchronize_sched(); - destroy_sched_domains(cpu_map, to_cpumask(tmpmask)); + rcu_read_unlock(); } /* handle null as "default" */ @@ -7538,8 +7438,7 @@ match1: goto match2; } /* no match - add a new doms_new */ - __build_sched_domains(doms_new[i], - dattr_new ? dattr_new + i : NULL); + build_sched_domains(doms_new[i], dattr_new ? dattr_new + i : NULL); match2: ; } diff --git a/kernel/sched_fair.c b/kernel/sched_fair.c index 4ee50f0..4a8ac7c 100644 --- a/kernel/sched_fair.c +++ b/kernel/sched_fair.c @@ -1622,6 +1622,7 @@ static int select_idle_sibling(struct task_struct *p, int target) /* * Otherwise, iterate the domains and find an elegible idle cpu. */ + rcu_read_lock(); for_each_domain(target, sd) { if (!(sd->flags & SD_SHARE_PKG_RESOURCES)) break; @@ -1641,6 +1642,7 @@ static int select_idle_sibling(struct task_struct *p, int target) cpumask_test_cpu(prev_cpu, sched_domain_span(sd))) break; } + rcu_read_unlock(); return target; } @@ -1673,6 +1675,7 @@ select_task_rq_fair(struct rq *rq, struct task_struct *p, int sd_flag, int wake_ new_cpu = prev_cpu; } + rcu_read_lock(); for_each_domain(cpu, tmp) { if (!(tmp->flags & SD_LOAD_BALANCE)) continue; @@ -1723,9 +1726,10 @@ select_task_rq_fair(struct rq *rq, struct task_struct *p, int sd_flag, int wake_ if (affine_sd) { if (cpu == prev_cpu || wake_affine(affine_sd, p, sync)) - return select_idle_sibling(p, cpu); - else - return select_idle_sibling(p, prev_cpu); + prev_cpu = cpu; + + new_cpu = select_idle_sibling(p, prev_cpu); + goto unlock; } while (sd) { @@ -1766,6 +1770,8 @@ select_task_rq_fair(struct rq *rq, struct task_struct *p, int sd_flag, int wake_ } /* while loop will break here if sd == NULL */ } +unlock: + rcu_read_unlock(); return new_cpu; } @@ -3462,6 +3468,7 @@ static void idle_balance(int this_cpu, struct rq *this_rq) raw_spin_unlock(&this_rq->lock); update_shares(this_cpu); + rcu_read_lock(); for_each_domain(this_cpu, sd) { unsigned long interval; int balance = 1; @@ -3483,6 +3490,7 @@ static void idle_balance(int this_cpu, struct rq *this_rq) break; } } + rcu_read_unlock(); raw_spin_lock(&this_rq->lock); @@ -3531,6 +3539,7 @@ static int active_load_balance_cpu_stop(void *data) double_lock_balance(busiest_rq, target_rq); /* Search for an sd spanning us and the target CPU. */ + rcu_read_lock(); for_each_domain(target_cpu, sd) { if ((sd->flags & SD_LOAD_BALANCE) && cpumask_test_cpu(busiest_cpu, sched_domain_span(sd))) @@ -3546,6 +3555,7 @@ static int active_load_balance_cpu_stop(void *data) else schedstat_inc(sd, alb_failed); } + rcu_read_unlock(); double_unlock_balance(busiest_rq, target_rq); out_unlock: busiest_rq->active_balance = 0; @@ -3672,6 +3682,7 @@ static int find_new_ilb(int cpu) { struct sched_domain *sd; struct sched_group *ilb_group; + int ilb = nr_cpu_ids; /* * Have idle load balancer selection from semi-idle packages only @@ -3687,20 +3698,25 @@ static int find_new_ilb(int cpu) if (cpumask_weight(nohz.idle_cpus_mask) < 2) goto out_done; + rcu_read_lock(); for_each_flag_domain(cpu, sd, SD_POWERSAVINGS_BALANCE) { ilb_group = sd->groups; do { - if (is_semi_idle_group(ilb_group)) - return cpumask_first(nohz.grp_idle_mask); + if (is_semi_idle_group(ilb_group)) { + ilb = cpumask_first(nohz.grp_idle_mask); + goto unlock; + } ilb_group = ilb_group->next; } while (ilb_group != sd->groups); } +unlock: + rcu_read_unlock(); out_done: - return nr_cpu_ids; + return ilb; } #else /* (CONFIG_SCHED_MC || CONFIG_SCHED_SMT) */ static inline int find_new_ilb(int call_cpu) @@ -3845,6 +3861,7 @@ static void rebalance_domains(int cpu, enum cpu_idle_type idle) update_shares(cpu); + rcu_read_lock(); for_each_domain(cpu, sd) { if (!(sd->flags & SD_LOAD_BALANCE)) continue; @@ -3890,6 +3907,7 @@ out: if (!balance) break; } + rcu_read_unlock(); /* * next_balance will be updated only when there is a need. -- cgit v0.10.2 From 822ff793c34a5d4c8b5f3f9ce932602233d96464 Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Thu, 7 Apr 2011 14:09:51 +0200 Subject: sched: Simplify the free path some If we check the root_domain reference count we can see if its been used or not, use this observation to simplify some of the return paths. Signed-off-by: Peter Zijlstra Cc: Mike Galbraith Cc: Nick Piggin Cc: Linus Torvalds Cc: Andrew Morton Link: http://lkml.kernel.org/r/20110407122942.298339503@chello.nl Signed-off-by: Ingo Molnar diff --git a/kernel/sched.c b/kernel/sched.c index 6520484..72c194c 100644 --- a/kernel/sched.c +++ b/kernel/sched.c @@ -7023,7 +7023,8 @@ static void __free_domain_allocs(struct s_data *d, enum s_alloc what, switch (what) { case sa_rootdomain: - free_rootdomain(&d->rd->rcu); /* fall through */ + if (!atomic_read(&d->rd->refcount)) + free_rootdomain(&d->rd->rcu); /* fall through */ case sa_sd: free_percpu(d->sd); /* fall through */ case sa_sd_storage: @@ -7208,7 +7209,7 @@ static int build_sched_domains(const struct cpumask *cpu_map, enum s_alloc alloc_state = sa_none; struct sched_domain *sd; struct s_data d; - int i; + int i, ret = -ENOMEM; alloc_state = __visit_domain_allocation_hell(&d, cpu_map); if (alloc_state != sa_rootdomain) @@ -7261,12 +7262,10 @@ static int build_sched_domains(const struct cpumask *cpu_map, } rcu_read_unlock(); - __free_domain_allocs(&d, sa_sd, cpu_map); - return 0; - + ret = 0; error: __free_domain_allocs(&d, alloc_state, cpu_map); - return -ENOMEM; + return ret; } static cpumask_var_t *doms_cur; /* current sched domains */ -- cgit v0.10.2 From a6c75f2f8d988ecfecf971f98f1cb6fc4de522fe Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Thu, 7 Apr 2011 14:09:52 +0200 Subject: sched: Avoid using sd->level Don't use sd->level for identifying properties of the domain. Signed-off-by: Peter Zijlstra Cc: Mike Galbraith Cc: Nick Piggin Cc: Linus Torvalds Cc: Andrew Morton Link: http://lkml.kernel.org/r/20110407122942.350174079@chello.nl Signed-off-by: Ingo Molnar diff --git a/kernel/sched_fair.c b/kernel/sched_fair.c index 4a8ac7c..9c5679c 100644 --- a/kernel/sched_fair.c +++ b/kernel/sched_fair.c @@ -2651,7 +2651,7 @@ fix_small_capacity(struct sched_domain *sd, struct sched_group *group) /* * Only siblings can have significantly less than SCHED_LOAD_SCALE */ - if (sd->level != SD_LV_SIBLING) + if (!(sd->flags & SD_SHARE_CPUPOWER)) return 0; /* -- cgit v0.10.2 From 3859173d43658d51a749bc0201b943922577d39c Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Thu, 7 Apr 2011 14:09:53 +0200 Subject: sched: Reduce some allocation pressure Since we now allocate SD_LV_MAX * nr_cpu_ids sched_domain/sched_group structures when rebuilding the scheduler toplogy it might make sense to shrink that depending on the CONFIG_ options. This is only needed until we get rid of SD_LV_* alltogether and provide a full dynamic topology interface. Signed-off-by: Peter Zijlstra Cc: Mike Galbraith Cc: Nick Piggin Cc: Linus Torvalds Cc: Andrew Morton Link: http://lkml.kernel.org/r/20110407122942.406226449@chello.nl Signed-off-by: Ingo Molnar diff --git a/include/linux/sched.h b/include/linux/sched.h index 020b79d..5a9168b 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h @@ -897,12 +897,20 @@ static inline struct cpumask *sched_group_cpus(struct sched_group *sg) enum sched_domain_level { SD_LV_NONE = 0, +#ifdef CONFIG_SCHED_SMT SD_LV_SIBLING, +#endif +#ifdef CONFIG_SCHED_MC SD_LV_MC, +#endif +#ifdef CONFIG_SCHED_BOOK SD_LV_BOOK, +#endif SD_LV_CPU, +#ifdef CONFIG_NUMA SD_LV_NODE, SD_LV_ALLNODES, +#endif SD_LV_MAX }; -- cgit v0.10.2 From 3bd65a80affb9768b91f03c56dba46ee79525f9b Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Thu, 7 Apr 2011 14:09:54 +0200 Subject: sched: Simplify NODE/ALLNODES domain creation Don't treat ALLNODES/NODE different for difference's sake. Simply always create the ALLNODES domain and let the sd_degenerate() checks kill it when its redundant. This simplifies the code flow. Signed-off-by: Peter Zijlstra Cc: Mike Galbraith Cc: Nick Piggin Cc: Linus Torvalds Cc: Andrew Morton Link: http://lkml.kernel.org/r/20110407122942.455464579@chello.nl Signed-off-by: Ingo Molnar diff --git a/kernel/sched.c b/kernel/sched.c index 72c194c..d395fe5 100644 --- a/kernel/sched.c +++ b/kernel/sched.c @@ -6838,9 +6838,6 @@ struct sd_data { }; struct s_data { -#ifdef CONFIG_NUMA - int sd_allnodes; -#endif cpumask_var_t nodemask; cpumask_var_t send_covered; struct sched_domain ** __percpu sd; @@ -7112,30 +7109,35 @@ static void claim_allocations(int cpu, struct sched_domain *sd) } } -static struct sched_domain *__build_numa_sched_domains(struct s_data *d, - const struct cpumask *cpu_map, struct sched_domain_attr *attr, int i) +static struct sched_domain *__build_allnodes_sched_domain(struct s_data *d, + const struct cpumask *cpu_map, struct sched_domain_attr *attr, + struct sched_domain *parent, int i) { struct sched_domain *sd = NULL; #ifdef CONFIG_NUMA - struct sched_domain *parent; - - d->sd_allnodes = 0; - if (cpumask_weight(cpu_map) > - SD_NODES_PER_DOMAIN * cpumask_weight(d->nodemask)) { - sd = sd_init_ALLNODES(d, i); - set_domain_attribute(sd, attr); - cpumask_copy(sched_domain_span(sd), cpu_map); - d->sd_allnodes = 1; - } - parent = sd; + sd = sd_init_ALLNODES(d, i); + set_domain_attribute(sd, attr); + cpumask_copy(sched_domain_span(sd), cpu_map); + sd->parent = parent; + if (parent) + parent->child = sd; +#endif + return sd; +} +static struct sched_domain *__build_node_sched_domain(struct s_data *d, + const struct cpumask *cpu_map, struct sched_domain_attr *attr, + struct sched_domain *parent, int i) +{ + struct sched_domain *sd = NULL; +#ifdef CONFIG_NUMA sd = sd_init_NODE(d, i); set_domain_attribute(sd, attr); sched_domain_node_span(cpu_to_node(i), sched_domain_span(sd)); + cpumask_and(sched_domain_span(sd), sched_domain_span(sd), cpu_map); sd->parent = parent; if (parent) parent->child = sd; - cpumask_and(sched_domain_span(sd), sched_domain_span(sd), cpu_map); #endif return sd; } @@ -7220,7 +7222,9 @@ static int build_sched_domains(const struct cpumask *cpu_map, cpumask_and(d.nodemask, cpumask_of_node(cpu_to_node(i)), cpu_map); - sd = __build_numa_sched_domains(&d, cpu_map, attr, i); + sd = NULL; + sd = __build_allnodes_sched_domain(&d, cpu_map, attr, sd, i); + sd = __build_node_sched_domain(&d, cpu_map, attr, sd, i); sd = __build_cpu_sched_domain(&d, cpu_map, attr, sd, i); sd = __build_book_sched_domain(&d, cpu_map, attr, sd, i); sd = __build_mc_sched_domain(&d, cpu_map, attr, sd, i); -- cgit v0.10.2 From bf28b253266ebd73c331dde24d64606afde32ceb Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Thu, 7 Apr 2011 14:09:55 +0200 Subject: sched: Remove nodemask allocation There's only one nodemask user left so remove it with a direct computation and save some memory and reduce some code-flow complexity. Signed-off-by: Peter Zijlstra Cc: Mike Galbraith Cc: Nick Piggin Cc: Linus Torvalds Cc: Andrew Morton Link: http://lkml.kernel.org/r/20110407122942.505608966@chello.nl Signed-off-by: Ingo Molnar diff --git a/kernel/sched.c b/kernel/sched.c index d395fe5..f4d3a62 100644 --- a/kernel/sched.c +++ b/kernel/sched.c @@ -6838,7 +6838,6 @@ struct sd_data { }; struct s_data { - cpumask_var_t nodemask; cpumask_var_t send_covered; struct sched_domain ** __percpu sd; struct sd_data sdd[SD_LV_MAX]; @@ -6850,7 +6849,6 @@ enum s_alloc { sa_sd, sa_sd_storage, sa_send_covered, - sa_nodemask, sa_none, }; @@ -7035,8 +7033,6 @@ static void __free_domain_allocs(struct s_data *d, enum s_alloc what, } /* fall through */ case sa_send_covered: free_cpumask_var(d->send_covered); /* fall through */ - case sa_nodemask: - free_cpumask_var(d->nodemask); /* fall through */ case sa_none: break; } @@ -7049,10 +7045,8 @@ static enum s_alloc __visit_domain_allocation_hell(struct s_data *d, memset(d, 0, sizeof(*d)); - if (!alloc_cpumask_var(&d->nodemask, GFP_KERNEL)) - return sa_none; if (!alloc_cpumask_var(&d->send_covered, GFP_KERNEL)) - return sa_nodemask; + return sa_none; for (i = 0; i < SD_LV_MAX; i++) { d->sdd[i].sd = alloc_percpu(struct sched_domain *); if (!d->sdd[i].sd) @@ -7149,7 +7143,8 @@ static struct sched_domain *__build_cpu_sched_domain(struct s_data *d, struct sched_domain *sd; sd = sd_init_CPU(d, i); set_domain_attribute(sd, attr); - cpumask_copy(sched_domain_span(sd), d->nodemask); + cpumask_and(sched_domain_span(sd), + cpumask_of_node(cpu_to_node(i)), cpu_map); sd->parent = parent; if (parent) parent->child = sd; @@ -7219,9 +7214,6 @@ static int build_sched_domains(const struct cpumask *cpu_map, /* Set up domains for cpus specified by the cpu_map. */ for_each_cpu(i, cpu_map) { - cpumask_and(d.nodemask, cpumask_of_node(cpu_to_node(i)), - cpu_map); - sd = NULL; sd = __build_allnodes_sched_domain(&d, cpu_map, attr, sd, i); sd = __build_node_sched_domain(&d, cpu_map, attr, sd, i); -- cgit v0.10.2 From 7dd04b730749f957c116f363524fd622b05e5141 Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Thu, 7 Apr 2011 14:09:56 +0200 Subject: sched: Remove some dead code Signed-off-by: Peter Zijlstra Cc: Mike Galbraith Cc: Nick Piggin Cc: Linus Torvalds Cc: Andrew Morton Link: http://lkml.kernel.org/r/20110407122942.553814623@chello.nl Signed-off-by: Ingo Molnar diff --git a/include/linux/sched.h b/include/linux/sched.h index 5a9168b..09d9e02 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h @@ -883,9 +883,6 @@ struct sched_group { * NOTE: this field is variable length. (Allocated dynamically * by attaching extra space to the end of the structure, * depending on how many CPUs the kernel has booted up with) - * - * It is also be embedded into static data structures at build - * time. (See 'struct static_sched_group' in kernel/sched.c) */ unsigned long cpumask[0]; }; @@ -994,9 +991,6 @@ struct sched_domain { * NOTE: this field is variable length. (Allocated dynamically * by attaching extra space to the end of the structure, * depending on how many CPUs the kernel has booted up with) - * - * It is also be embedded into static data structures at build - * time. (See 'struct static_sched_domain' in kernel/sched.c) */ unsigned long span[0]; }; diff --git a/kernel/sched.c b/kernel/sched.c index f4d3a62..5ec685c 100644 --- a/kernel/sched.c +++ b/kernel/sched.c @@ -6816,22 +6816,6 @@ static void sched_domain_node_span(int node, struct cpumask *span) int sched_smt_power_savings = 0, sched_mc_power_savings = 0; -/* - * The cpus mask in sched_group and sched_domain hangs off the end. - * - * ( See the the comments in include/linux/sched.h:struct sched_group - * and struct sched_domain. ) - */ -struct static_sched_group { - struct sched_group sg; - DECLARE_BITMAP(cpus, CONFIG_NR_CPUS); -}; - -struct static_sched_domain { - struct sched_domain sd; - DECLARE_BITMAP(span, CONFIG_NR_CPUS); -}; - struct sd_data { struct sched_domain **__percpu sd; struct sched_group **__percpu sg; -- cgit v0.10.2 From f96225fd51893b6650cffd5427f13f6b1b356488 Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Thu, 7 Apr 2011 14:09:57 +0200 Subject: sched: Create persistent sched_domains_tmpmask Since sched domain creation is fully serialized by the sched_domains_mutex we can create a single persistent tmpmask to use during domain creation. This removes the need for s_data::send_covered. Signed-off-by: Peter Zijlstra Cc: Mike Galbraith Cc: Nick Piggin Cc: Linus Torvalds Cc: Andrew Morton Link: http://lkml.kernel.org/r/20110407122942.607287405@chello.nl Signed-off-by: Ingo Molnar diff --git a/kernel/sched.c b/kernel/sched.c index 5ec685c..fd73e91 100644 --- a/kernel/sched.c +++ b/kernel/sched.c @@ -6822,7 +6822,6 @@ struct sd_data { }; struct s_data { - cpumask_var_t send_covered; struct sched_domain ** __percpu sd; struct sd_data sdd[SD_LV_MAX]; struct root_domain *rd; @@ -6832,7 +6831,6 @@ enum s_alloc { sa_rootdomain, sa_sd, sa_sd_storage, - sa_send_covered, sa_none, }; @@ -6853,6 +6851,8 @@ static int get_group(int cpu, struct sd_data *sdd, struct sched_group **sg) return cpu; } +static cpumask_var_t sched_domains_tmpmask; /* sched_domains_mutex */ + /* * build_sched_groups takes the cpumask we wish to span, and a pointer * to a function which identifies what group(along with sched group) a CPU @@ -6864,13 +6864,17 @@ static int get_group(int cpu, struct sd_data *sdd, struct sched_group **sg) * and ->cpu_power to 0. */ static void -build_sched_groups(struct sched_domain *sd, struct cpumask *covered) +build_sched_groups(struct sched_domain *sd) { struct sched_group *first = NULL, *last = NULL; struct sd_data *sdd = sd->private; const struct cpumask *span = sched_domain_span(sd); + struct cpumask *covered; int i; + lockdep_assert_held(&sched_domains_mutex); + covered = sched_domains_tmpmask; + cpumask_clear(covered); for_each_cpu(i, span) { @@ -7015,8 +7019,6 @@ static void __free_domain_allocs(struct s_data *d, enum s_alloc what, free_percpu(d->sdd[i].sd); free_percpu(d->sdd[i].sg); } /* fall through */ - case sa_send_covered: - free_cpumask_var(d->send_covered); /* fall through */ case sa_none: break; } @@ -7029,8 +7031,6 @@ static enum s_alloc __visit_domain_allocation_hell(struct s_data *d, memset(d, 0, sizeof(*d)); - if (!alloc_cpumask_var(&d->send_covered, GFP_KERNEL)) - return sa_none; for (i = 0; i < SD_LV_MAX; i++) { d->sdd[i].sd = alloc_percpu(struct sched_domain *); if (!d->sdd[i].sd) @@ -7219,7 +7219,7 @@ static int build_sched_domains(const struct cpumask *cpu_map, if (i != cpumask_first(sched_domain_span(sd))) continue; - build_sched_groups(sd, d.send_covered); + build_sched_groups(sd); } } @@ -7896,6 +7896,7 @@ void __init sched_init(void) /* Allocate the nohz_cpu_mask if CONFIG_CPUMASK_OFFSTACK */ zalloc_cpumask_var(&nohz_cpu_mask, GFP_NOWAIT); + zalloc_cpumask_var(&sched_domains_tmpmask, GFP_NOWAIT); #ifdef CONFIG_SMP #ifdef CONFIG_NO_HZ zalloc_cpumask_var(&nohz.idle_cpus_mask, GFP_NOWAIT); -- cgit v0.10.2 From 4cb988395da6e16627a8be69729e50cd72ebb23e Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Thu, 7 Apr 2011 14:09:58 +0200 Subject: sched: Avoid allocations in sched_domain_debug() Since we're all serialized by sched_domains_mutex we can use sched_domains_tmpmask and avoid having to do allocations. This means we can use sched_domains_debug() for cpu_attach_domain() again. Signed-off-by: Peter Zijlstra Cc: Mike Galbraith Cc: Nick Piggin Cc: Linus Torvalds Cc: Andrew Morton Link: http://lkml.kernel.org/r/20110407122942.664347467@chello.nl Signed-off-by: Ingo Molnar diff --git a/kernel/sched.c b/kernel/sched.c index fd73e91..35fc995 100644 --- a/kernel/sched.c +++ b/kernel/sched.c @@ -6395,6 +6395,8 @@ early_initcall(migration_init); #ifdef CONFIG_SMP +static cpumask_var_t sched_domains_tmpmask; /* sched_domains_mutex */ + #ifdef CONFIG_SCHED_DEBUG static __read_mostly int sched_domain_debug_enabled; @@ -6490,7 +6492,6 @@ static int sched_domain_debug_one(struct sched_domain *sd, int cpu, int level, static void sched_domain_debug(struct sched_domain *sd, int cpu) { - cpumask_var_t groupmask; int level = 0; if (!sched_domain_debug_enabled) @@ -6503,20 +6504,14 @@ static void sched_domain_debug(struct sched_domain *sd, int cpu) printk(KERN_DEBUG "CPU%d attaching sched-domain:\n", cpu); - if (!alloc_cpumask_var(&groupmask, GFP_KERNEL)) { - printk(KERN_DEBUG "Cannot load-balance (out of memory)\n"); - return; - } - for (;;) { - if (sched_domain_debug_one(sd, cpu, level, groupmask)) + if (sched_domain_debug_one(sd, cpu, level, sched_domains_tmpmask)) break; level++; sd = sd->parent; if (!sd) break; } - free_cpumask_var(groupmask); } #else /* !CONFIG_SCHED_DEBUG */ # define sched_domain_debug(sd, cpu) do { } while (0) @@ -6721,7 +6716,7 @@ cpu_attach_domain(struct sched_domain *sd, struct root_domain *rd, int cpu) sd->child = NULL; } - /* sched_domain_debug(sd, cpu); */ + sched_domain_debug(sd, cpu); rq_attach_root(rq, rd); tmp = rq->sd; @@ -6851,8 +6846,6 @@ static int get_group(int cpu, struct sd_data *sdd, struct sched_group **sg) return cpu; } -static cpumask_var_t sched_domains_tmpmask; /* sched_domains_mutex */ - /* * build_sched_groups takes the cpumask we wish to span, and a pointer * to a function which identifies what group(along with sched group) a CPU @@ -7896,8 +7889,8 @@ void __init sched_init(void) /* Allocate the nohz_cpu_mask if CONFIG_CPUMASK_OFFSTACK */ zalloc_cpumask_var(&nohz_cpu_mask, GFP_NOWAIT); - zalloc_cpumask_var(&sched_domains_tmpmask, GFP_NOWAIT); #ifdef CONFIG_SMP + zalloc_cpumask_var(&sched_domains_tmpmask, GFP_NOWAIT); #ifdef CONFIG_NO_HZ zalloc_cpumask_var(&nohz.idle_cpus_mask, GFP_NOWAIT); alloc_cpumask_var(&nohz.grp_idle_mask, GFP_NOWAIT); -- cgit v0.10.2 From d3081f52f29da1ba6c27685519a9222b39eac763 Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Thu, 7 Apr 2011 14:09:59 +0200 Subject: sched: Create proper cpu_$DOM_mask() functions In order to unify the sched domain creation more, create proper cpu_$DOM_mask() functions for those domains that didn't already have one. Use the sched_domains_tmpmask for the weird NUMA domain span. Signed-off-by: Peter Zijlstra Cc: Mike Galbraith Cc: Nick Piggin Cc: Linus Torvalds Cc: Andrew Morton Link: http://lkml.kernel.org/r/20110407122942.717702108@chello.nl Signed-off-by: Ingo Molnar diff --git a/kernel/sched.c b/kernel/sched.c index 35fc995..3ae1e02 100644 --- a/kernel/sched.c +++ b/kernel/sched.c @@ -6807,8 +6807,22 @@ static void sched_domain_node_span(int node, struct cpumask *span) cpumask_or(span, span, cpumask_of_node(next_node)); } } + +static const struct cpumask *cpu_node_mask(int cpu) +{ + lockdep_assert_held(&sched_domains_mutex); + + sched_domain_node_span(cpu_to_node(cpu), sched_domains_tmpmask); + + return sched_domains_tmpmask; +} #endif /* CONFIG_NUMA */ +static const struct cpumask *cpu_cpu_mask(int cpu) +{ + return cpumask_of_node(cpu_to_node(cpu)); +} + int sched_smt_power_savings = 0, sched_mc_power_savings = 0; struct sd_data { @@ -7088,7 +7102,7 @@ static struct sched_domain *__build_allnodes_sched_domain(struct s_data *d, #ifdef CONFIG_NUMA sd = sd_init_ALLNODES(d, i); set_domain_attribute(sd, attr); - cpumask_copy(sched_domain_span(sd), cpu_map); + cpumask_and(sched_domain_span(sd), cpu_map, cpu_possible_mask); sd->parent = parent; if (parent) parent->child = sd; @@ -7104,8 +7118,7 @@ static struct sched_domain *__build_node_sched_domain(struct s_data *d, #ifdef CONFIG_NUMA sd = sd_init_NODE(d, i); set_domain_attribute(sd, attr); - sched_domain_node_span(cpu_to_node(i), sched_domain_span(sd)); - cpumask_and(sched_domain_span(sd), sched_domain_span(sd), cpu_map); + cpumask_and(sched_domain_span(sd), cpu_map, cpu_node_mask(i)); sd->parent = parent; if (parent) parent->child = sd; @@ -7120,8 +7133,7 @@ static struct sched_domain *__build_cpu_sched_domain(struct s_data *d, struct sched_domain *sd; sd = sd_init_CPU(d, i); set_domain_attribute(sd, attr); - cpumask_and(sched_domain_span(sd), - cpumask_of_node(cpu_to_node(i)), cpu_map); + cpumask_and(sched_domain_span(sd), cpu_map, cpu_cpu_mask(i)); sd->parent = parent; if (parent) parent->child = sd; -- cgit v0.10.2 From eb7a74e6cd936c00749e2921b9e058631d986648 Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Thu, 7 Apr 2011 14:10:00 +0200 Subject: sched: Stuff the sched_domain creation in a data-structure In order to make the topology contruction fully dynamic, remove the still hard-coded list of possible domains and stick them in a data-structure. Signed-off-by: Peter Zijlstra Cc: Mike Galbraith Cc: Nick Piggin Cc: Linus Torvalds Cc: Andrew Morton Link: http://lkml.kernel.org/r/20110407122942.770335383@chello.nl Signed-off-by: Ingo Molnar diff --git a/kernel/sched.c b/kernel/sched.c index 3ae1e02..f0e1821 100644 --- a/kernel/sched.c +++ b/kernel/sched.c @@ -6843,6 +6843,16 @@ enum s_alloc { sa_none, }; +typedef struct sched_domain *(*sched_domain_build_f)(struct s_data *d, + const struct cpumask *cpu_map, struct sched_domain_attr *attr, + struct sched_domain *parent, int cpu); + +typedef const struct cpumask *(*sched_domain_mask_f)(int cpu); + +struct sched_domain_topology_level { + sched_domain_build_f build; +}; + /* * Assumes the sched_domain tree is fully constructed */ @@ -7185,6 +7195,18 @@ static struct sched_domain *__build_smt_sched_domain(struct s_data *d, return sd; } +static struct sched_domain_topology_level default_topology[] = { + { __build_allnodes_sched_domain, }, + { __build_node_sched_domain, }, + { __build_cpu_sched_domain, }, + { __build_book_sched_domain, }, + { __build_mc_sched_domain, }, + { __build_smt_sched_domain, }, + { NULL, }, +}; + +static struct sched_domain_topology_level *sched_domain_topology = default_topology; + /* * Build sched domains for a given set of cpus and attach the sched domains * to the individual cpus @@ -7203,13 +7225,11 @@ static int build_sched_domains(const struct cpumask *cpu_map, /* Set up domains for cpus specified by the cpu_map. */ for_each_cpu(i, cpu_map) { + struct sched_domain_topology_level *tl; + sd = NULL; - sd = __build_allnodes_sched_domain(&d, cpu_map, attr, sd, i); - sd = __build_node_sched_domain(&d, cpu_map, attr, sd, i); - sd = __build_cpu_sched_domain(&d, cpu_map, attr, sd, i); - sd = __build_book_sched_domain(&d, cpu_map, attr, sd, i); - sd = __build_mc_sched_domain(&d, cpu_map, attr, sd, i); - sd = __build_smt_sched_domain(&d, cpu_map, attr, sd, i); + for (tl = sched_domain_topology; tl->build; tl++) + sd = tl->build(&d, cpu_map, attr, sd, i); *per_cpu_ptr(d.sd, i) = sd; } -- cgit v0.10.2 From 2c402dc3bb502e9dd74fce72c14d293fcef4719d Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Thu, 7 Apr 2011 14:10:01 +0200 Subject: sched: Unify the sched_domain build functions Since all the __build_$DOM_sched_domain() functions do pretty much the same thing, unify them. Signed-off-by: Peter Zijlstra Cc: Mike Galbraith Cc: Nick Piggin Cc: Linus Torvalds Cc: Andrew Morton Link: http://lkml.kernel.org/r/20110407122942.826347257@chello.nl Signed-off-by: Ingo Molnar diff --git a/kernel/sched.c b/kernel/sched.c index f0e1821..00d1e37 100644 --- a/kernel/sched.c +++ b/kernel/sched.c @@ -6816,6 +6816,11 @@ static const struct cpumask *cpu_node_mask(int cpu) return sched_domains_tmpmask; } + +static const struct cpumask *cpu_allnodes_mask(int cpu) +{ + return cpu_possible_mask; +} #endif /* CONFIG_NUMA */ static const struct cpumask *cpu_cpu_mask(int cpu) @@ -6843,14 +6848,12 @@ enum s_alloc { sa_none, }; -typedef struct sched_domain *(*sched_domain_build_f)(struct s_data *d, - const struct cpumask *cpu_map, struct sched_domain_attr *attr, - struct sched_domain *parent, int cpu); - +typedef struct sched_domain *(*sched_domain_init_f)(struct s_data *d, int cpu); typedef const struct cpumask *(*sched_domain_mask_f)(int cpu); struct sched_domain_topology_level { - sched_domain_build_f build; + sched_domain_init_f init; + sched_domain_mask_f mask; }; /* @@ -7104,109 +7107,51 @@ static void claim_allocations(int cpu, struct sched_domain *sd) } } -static struct sched_domain *__build_allnodes_sched_domain(struct s_data *d, - const struct cpumask *cpu_map, struct sched_domain_attr *attr, - struct sched_domain *parent, int i) +#ifdef CONFIG_SCHED_SMT +static const struct cpumask *cpu_smt_mask(int cpu) { - struct sched_domain *sd = NULL; -#ifdef CONFIG_NUMA - sd = sd_init_ALLNODES(d, i); - set_domain_attribute(sd, attr); - cpumask_and(sched_domain_span(sd), cpu_map, cpu_possible_mask); - sd->parent = parent; - if (parent) - parent->child = sd; -#endif - return sd; + return topology_thread_cpumask(cpu); } +#endif -static struct sched_domain *__build_node_sched_domain(struct s_data *d, - const struct cpumask *cpu_map, struct sched_domain_attr *attr, - struct sched_domain *parent, int i) -{ - struct sched_domain *sd = NULL; +static struct sched_domain_topology_level default_topology[] = { #ifdef CONFIG_NUMA - sd = sd_init_NODE(d, i); - set_domain_attribute(sd, attr); - cpumask_and(sched_domain_span(sd), cpu_map, cpu_node_mask(i)); - sd->parent = parent; - if (parent) - parent->child = sd; + { sd_init_ALLNODES, cpu_allnodes_mask, }, + { sd_init_NODE, cpu_node_mask, }, #endif - return sd; -} - -static struct sched_domain *__build_cpu_sched_domain(struct s_data *d, - const struct cpumask *cpu_map, struct sched_domain_attr *attr, - struct sched_domain *parent, int i) -{ - struct sched_domain *sd; - sd = sd_init_CPU(d, i); - set_domain_attribute(sd, attr); - cpumask_and(sched_domain_span(sd), cpu_map, cpu_cpu_mask(i)); - sd->parent = parent; - if (parent) - parent->child = sd; - return sd; -} - -static struct sched_domain *__build_book_sched_domain(struct s_data *d, - const struct cpumask *cpu_map, struct sched_domain_attr *attr, - struct sched_domain *parent, int i) -{ - struct sched_domain *sd = parent; + { sd_init_CPU, cpu_cpu_mask, }, #ifdef CONFIG_SCHED_BOOK - sd = sd_init_BOOK(d, i); - set_domain_attribute(sd, attr); - cpumask_and(sched_domain_span(sd), cpu_map, cpu_book_mask(i)); - sd->parent = parent; - parent->child = sd; + { sd_init_BOOK, cpu_book_mask, }, #endif - return sd; -} - -static struct sched_domain *__build_mc_sched_domain(struct s_data *d, - const struct cpumask *cpu_map, struct sched_domain_attr *attr, - struct sched_domain *parent, int i) -{ - struct sched_domain *sd = parent; #ifdef CONFIG_SCHED_MC - sd = sd_init_MC(d, i); - set_domain_attribute(sd, attr); - cpumask_and(sched_domain_span(sd), cpu_map, cpu_coregroup_mask(i)); - sd->parent = parent; - parent->child = sd; + { sd_init_MC, cpu_coregroup_mask, }, #endif - return sd; -} - -static struct sched_domain *__build_smt_sched_domain(struct s_data *d, - const struct cpumask *cpu_map, struct sched_domain_attr *attr, - struct sched_domain *parent, int i) -{ - struct sched_domain *sd = parent; #ifdef CONFIG_SCHED_SMT - sd = sd_init_SIBLING(d, i); - set_domain_attribute(sd, attr); - cpumask_and(sched_domain_span(sd), cpu_map, topology_thread_cpumask(i)); - sd->parent = parent; - parent->child = sd; + { sd_init_SIBLING, cpu_smt_mask, }, #endif - return sd; -} - -static struct sched_domain_topology_level default_topology[] = { - { __build_allnodes_sched_domain, }, - { __build_node_sched_domain, }, - { __build_cpu_sched_domain, }, - { __build_book_sched_domain, }, - { __build_mc_sched_domain, }, - { __build_smt_sched_domain, }, { NULL, }, }; static struct sched_domain_topology_level *sched_domain_topology = default_topology; +struct sched_domain *build_sched_domain(struct sched_domain_topology_level *tl, + struct s_data *d, const struct cpumask *cpu_map, + struct sched_domain_attr *attr, struct sched_domain *parent, + int cpu) +{ + struct sched_domain *sd = tl->init(d, cpu); + if (!sd) + return parent; + + set_domain_attribute(sd, attr); + cpumask_and(sched_domain_span(sd), cpu_map, tl->mask(cpu)); + sd->parent = parent; + if (parent) + parent->child = sd; + + return sd; +} + /* * Build sched domains for a given set of cpus and attach the sched domains * to the individual cpus @@ -7228,8 +7173,8 @@ static int build_sched_domains(const struct cpumask *cpu_map, struct sched_domain_topology_level *tl; sd = NULL; - for (tl = sched_domain_topology; tl->build; tl++) - sd = tl->build(&d, cpu_map, attr, sd, i); + for (tl = sched_domain_topology; tl->init; tl++) + sd = build_sched_domain(tl, &d, cpu_map, attr, sd, i); *per_cpu_ptr(d.sd, i) = sd; } -- cgit v0.10.2 From d069b916f7b50021d41d6ce498f86da32a7afaec Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Thu, 7 Apr 2011 14:10:02 +0200 Subject: sched: Reverse the topology list In order to get rid of static sched_domain::level assignments, reverse the topology iteration. Signed-off-by: Peter Zijlstra Cc: Mike Galbraith Cc: Nick Piggin Cc: Linus Torvalds Cc: Andrew Morton Link: http://lkml.kernel.org/r/20110407122942.876506131@chello.nl Signed-off-by: Ingo Molnar diff --git a/kernel/sched.c b/kernel/sched.c index 00d1e37..38bc53b 100644 --- a/kernel/sched.c +++ b/kernel/sched.c @@ -7114,20 +7114,23 @@ static const struct cpumask *cpu_smt_mask(int cpu) } #endif +/* + * Topology list, bottom-up. + */ static struct sched_domain_topology_level default_topology[] = { -#ifdef CONFIG_NUMA - { sd_init_ALLNODES, cpu_allnodes_mask, }, - { sd_init_NODE, cpu_node_mask, }, -#endif - { sd_init_CPU, cpu_cpu_mask, }, -#ifdef CONFIG_SCHED_BOOK - { sd_init_BOOK, cpu_book_mask, }, +#ifdef CONFIG_SCHED_SMT + { sd_init_SIBLING, cpu_smt_mask, }, #endif #ifdef CONFIG_SCHED_MC { sd_init_MC, cpu_coregroup_mask, }, #endif -#ifdef CONFIG_SCHED_SMT - { sd_init_SIBLING, cpu_smt_mask, }, +#ifdef CONFIG_SCHED_BOOK + { sd_init_BOOK, cpu_book_mask, }, +#endif + { sd_init_CPU, cpu_cpu_mask, }, +#ifdef CONFIG_NUMA + { sd_init_NODE, cpu_node_mask, }, + { sd_init_ALLNODES, cpu_allnodes_mask, }, #endif { NULL, }, }; @@ -7136,18 +7139,18 @@ static struct sched_domain_topology_level *sched_domain_topology = default_topol struct sched_domain *build_sched_domain(struct sched_domain_topology_level *tl, struct s_data *d, const struct cpumask *cpu_map, - struct sched_domain_attr *attr, struct sched_domain *parent, + struct sched_domain_attr *attr, struct sched_domain *child, int cpu) { struct sched_domain *sd = tl->init(d, cpu); if (!sd) - return parent; + return child; set_domain_attribute(sd, attr); cpumask_and(sched_domain_span(sd), cpu_map, tl->mask(cpu)); - sd->parent = parent; - if (parent) - parent->child = sd; + if (child) + child->parent = sd; + sd->child = child; return sd; } @@ -7176,6 +7179,9 @@ static int build_sched_domains(const struct cpumask *cpu_map, for (tl = sched_domain_topology; tl->init; tl++) sd = build_sched_domain(tl, &d, cpu_map, attr, sd, i); + while (sd->child) + sd = sd->child; + *per_cpu_ptr(d.sd, i) = sd; } -- cgit v0.10.2 From 54ab4ff4316eb329d2c1acc110fbc623d2966931 Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Thu, 7 Apr 2011 14:10:03 +0200 Subject: sched: Move sched domain storage into the topology list In order to remove the last dependency on the statid domain levels, move the sd_data storage into the topology structure. Signed-off-by: Peter Zijlstra Cc: Mike Galbraith Cc: Nick Piggin Cc: Linus Torvalds Cc: Andrew Morton Link: http://lkml.kernel.org/r/20110407122942.924926412@chello.nl Signed-off-by: Ingo Molnar diff --git a/kernel/sched.c b/kernel/sched.c index 38bc53b..3231e19 100644 --- a/kernel/sched.c +++ b/kernel/sched.c @@ -6837,7 +6837,6 @@ struct sd_data { struct s_data { struct sched_domain ** __percpu sd; - struct sd_data sdd[SD_LV_MAX]; struct root_domain *rd; }; @@ -6848,12 +6847,15 @@ enum s_alloc { sa_none, }; -typedef struct sched_domain *(*sched_domain_init_f)(struct s_data *d, int cpu); +struct sched_domain_topology_level; + +typedef struct sched_domain *(*sched_domain_init_f)(struct sched_domain_topology_level *tl, int cpu); typedef const struct cpumask *(*sched_domain_mask_f)(int cpu); struct sched_domain_topology_level { sched_domain_init_f init; sched_domain_mask_f mask; + struct sd_data data; }; /* @@ -6958,15 +6960,16 @@ static void init_sched_groups_power(int cpu, struct sched_domain *sd) # define SD_INIT_NAME(sd, type) do { } while (0) #endif -#define SD_INIT_FUNC(type) \ -static noinline struct sched_domain *sd_init_##type(struct s_data *d, int cpu) \ -{ \ - struct sched_domain *sd = *per_cpu_ptr(d->sdd[SD_LV_##type].sd, cpu); \ - *sd = SD_##type##_INIT; \ - sd->level = SD_LV_##type; \ - SD_INIT_NAME(sd, type); \ - sd->private = &d->sdd[SD_LV_##type]; \ - return sd; \ +#define SD_INIT_FUNC(type) \ +static noinline struct sched_domain * \ +sd_init_##type(struct sched_domain_topology_level *tl, int cpu) \ +{ \ + struct sched_domain *sd = *per_cpu_ptr(tl->data.sd, cpu); \ + *sd = SD_##type##_INIT; \ + sd->level = SD_LV_##type; \ + SD_INIT_NAME(sd, type); \ + sd->private = &tl->data; \ + return sd; \ } SD_INIT_FUNC(CPU) @@ -7019,11 +7022,12 @@ static void set_domain_attribute(struct sched_domain *sd, } } +static void __sdt_free(const struct cpumask *cpu_map); +static int __sdt_alloc(const struct cpumask *cpu_map); + static void __free_domain_allocs(struct s_data *d, enum s_alloc what, const struct cpumask *cpu_map) { - int i, j; - switch (what) { case sa_rootdomain: if (!atomic_read(&d->rd->refcount)) @@ -7031,14 +7035,7 @@ static void __free_domain_allocs(struct s_data *d, enum s_alloc what, case sa_sd: free_percpu(d->sd); /* fall through */ case sa_sd_storage: - for (i = 0; i < SD_LV_MAX; i++) { - for_each_cpu(j, cpu_map) { - kfree(*per_cpu_ptr(d->sdd[i].sd, j)); - kfree(*per_cpu_ptr(d->sdd[i].sg, j)); - } - free_percpu(d->sdd[i].sd); - free_percpu(d->sdd[i].sg); - } /* fall through */ + __sdt_free(cpu_map); /* fall through */ case sa_none: break; } @@ -7047,38 +7044,10 @@ static void __free_domain_allocs(struct s_data *d, enum s_alloc what, static enum s_alloc __visit_domain_allocation_hell(struct s_data *d, const struct cpumask *cpu_map) { - int i, j; - memset(d, 0, sizeof(*d)); - for (i = 0; i < SD_LV_MAX; i++) { - d->sdd[i].sd = alloc_percpu(struct sched_domain *); - if (!d->sdd[i].sd) - return sa_sd_storage; - - d->sdd[i].sg = alloc_percpu(struct sched_group *); - if (!d->sdd[i].sg) - return sa_sd_storage; - - for_each_cpu(j, cpu_map) { - struct sched_domain *sd; - struct sched_group *sg; - - sd = kzalloc_node(sizeof(struct sched_domain) + cpumask_size(), - GFP_KERNEL, cpu_to_node(j)); - if (!sd) - return sa_sd_storage; - - *per_cpu_ptr(d->sdd[i].sd, j) = sd; - - sg = kzalloc_node(sizeof(struct sched_group) + cpumask_size(), - GFP_KERNEL, cpu_to_node(j)); - if (!sg) - return sa_sd_storage; - - *per_cpu_ptr(d->sdd[i].sg, j) = sg; - } - } + if (__sdt_alloc(cpu_map)) + return sa_sd_storage; d->sd = alloc_percpu(struct sched_domain *); if (!d->sd) return sa_sd_storage; @@ -7137,12 +7106,68 @@ static struct sched_domain_topology_level default_topology[] = { static struct sched_domain_topology_level *sched_domain_topology = default_topology; +static int __sdt_alloc(const struct cpumask *cpu_map) +{ + struct sched_domain_topology_level *tl; + int j; + + for (tl = sched_domain_topology; tl->init; tl++) { + struct sd_data *sdd = &tl->data; + + sdd->sd = alloc_percpu(struct sched_domain *); + if (!sdd->sd) + return -ENOMEM; + + sdd->sg = alloc_percpu(struct sched_group *); + if (!sdd->sg) + return -ENOMEM; + + for_each_cpu(j, cpu_map) { + struct sched_domain *sd; + struct sched_group *sg; + + sd = kzalloc_node(sizeof(struct sched_domain) + cpumask_size(), + GFP_KERNEL, cpu_to_node(j)); + if (!sd) + return -ENOMEM; + + *per_cpu_ptr(sdd->sd, j) = sd; + + sg = kzalloc_node(sizeof(struct sched_group) + cpumask_size(), + GFP_KERNEL, cpu_to_node(j)); + if (!sg) + return -ENOMEM; + + *per_cpu_ptr(sdd->sg, j) = sg; + } + } + + return 0; +} + +static void __sdt_free(const struct cpumask *cpu_map) +{ + struct sched_domain_topology_level *tl; + int j; + + for (tl = sched_domain_topology; tl->init; tl++) { + struct sd_data *sdd = &tl->data; + + for_each_cpu(j, cpu_map) { + kfree(*per_cpu_ptr(sdd->sd, j)); + kfree(*per_cpu_ptr(sdd->sg, j)); + } + free_percpu(sdd->sd); + free_percpu(sdd->sg); + } +} + struct sched_domain *build_sched_domain(struct sched_domain_topology_level *tl, struct s_data *d, const struct cpumask *cpu_map, struct sched_domain_attr *attr, struct sched_domain *child, int cpu) { - struct sched_domain *sd = tl->init(d, cpu); + struct sched_domain *sd = tl->init(tl, cpu); if (!sd) return child; -- cgit v0.10.2 From 60495e7760d8ee364695006af37309b0755e0e17 Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Thu, 7 Apr 2011 14:10:04 +0200 Subject: sched: Dynamic sched_domain::level Remove the SD_LV_ enum and use dynamic level assignments. Signed-off-by: Peter Zijlstra Cc: Mike Galbraith Cc: Nick Piggin Cc: Linus Torvalds Cc: Andrew Morton Link: http://lkml.kernel.org/r/20110407122942.969433965@chello.nl Signed-off-by: Ingo Molnar diff --git a/include/linux/sched.h b/include/linux/sched.h index 09d9e02..e43e5b0 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h @@ -892,25 +892,6 @@ static inline struct cpumask *sched_group_cpus(struct sched_group *sg) return to_cpumask(sg->cpumask); } -enum sched_domain_level { - SD_LV_NONE = 0, -#ifdef CONFIG_SCHED_SMT - SD_LV_SIBLING, -#endif -#ifdef CONFIG_SCHED_MC - SD_LV_MC, -#endif -#ifdef CONFIG_SCHED_BOOK - SD_LV_BOOK, -#endif - SD_LV_CPU, -#ifdef CONFIG_NUMA - SD_LV_NODE, - SD_LV_ALLNODES, -#endif - SD_LV_MAX -}; - struct sched_domain_attr { int relax_domain_level; }; @@ -919,6 +900,8 @@ struct sched_domain_attr { .relax_domain_level = -1, \ } +extern int sched_domain_level_max; + struct sched_domain { /* These fields must be setup */ struct sched_domain *parent; /* top domain must be null terminated */ @@ -936,7 +919,7 @@ struct sched_domain { unsigned int forkexec_idx; unsigned int smt_gain; int flags; /* See SD_* */ - enum sched_domain_level level; + int level; /* Runtime fields. */ unsigned long last_balance; /* init to jiffies. units in jiffies */ diff --git a/kernel/cpuset.c b/kernel/cpuset.c index 33eee16..2bb8c2e 100644 --- a/kernel/cpuset.c +++ b/kernel/cpuset.c @@ -1159,7 +1159,7 @@ int current_cpuset_is_being_rebound(void) static int update_relax_domain_level(struct cpuset *cs, s64 val) { #ifdef CONFIG_SMP - if (val < -1 || val >= SD_LV_MAX) + if (val < -1 || val >= sched_domain_level_max) return -EINVAL; #endif diff --git a/kernel/sched.c b/kernel/sched.c index 3231e19..506cb81 100644 --- a/kernel/sched.c +++ b/kernel/sched.c @@ -6966,7 +6966,6 @@ sd_init_##type(struct sched_domain_topology_level *tl, int cpu) \ { \ struct sched_domain *sd = *per_cpu_ptr(tl->data.sd, cpu); \ *sd = SD_##type##_INIT; \ - sd->level = SD_LV_##type; \ SD_INIT_NAME(sd, type); \ sd->private = &tl->data; \ return sd; \ @@ -6988,13 +6987,14 @@ SD_INIT_FUNC(CPU) #endif static int default_relax_domain_level = -1; +int sched_domain_level_max; static int __init setup_relax_domain_level(char *str) { unsigned long val; val = simple_strtoul(str, NULL, 0); - if (val < SD_LV_MAX) + if (val < sched_domain_level_max) default_relax_domain_level = val; return 1; @@ -7173,8 +7173,11 @@ struct sched_domain *build_sched_domain(struct sched_domain_topology_level *tl, set_domain_attribute(sd, attr); cpumask_and(sched_domain_span(sd), cpu_map, tl->mask(cpu)); - if (child) + if (child) { + sd->level = child->level + 1; + sched_domain_level_max = max(sched_domain_level_max, sd->level); child->parent = sd; + } sd->child = child; return sd; -- cgit v0.10.2 From 4a39e781682828c1b81a839e7d343fd91945a8d5 Mon Sep 17 00:00:00 2001 From: "John W. Linville" Date: Mon, 11 Apr 2011 13:02:06 -0400 Subject: iwlegacy: make iwl3945 and iwl4965 select IWLWIFI_LEGACY Otherwise, IWLWIFI_LEGACY has to be selected independently before the drivers are made available. Reported-by: Dave Airlie Signed-off-by: John W. Linville Cc: Stanislaw Gruszka Cc: Wey-Yi Guy diff --git a/drivers/net/wireless/iwlegacy/Kconfig b/drivers/net/wireless/iwlegacy/Kconfig index 2a45dd4..aef65cd 100644 --- a/drivers/net/wireless/iwlegacy/Kconfig +++ b/drivers/net/wireless/iwlegacy/Kconfig @@ -1,6 +1,5 @@ config IWLWIFI_LEGACY - tristate "Intel Wireless Wifi legacy devices" - depends on PCI && MAC80211 + tristate select FW_LOADER select NEW_LEDS select LEDS_CLASS @@ -65,7 +64,8 @@ endmenu config IWL4965 tristate "Intel Wireless WiFi 4965AGN (iwl4965)" - depends on IWLWIFI_LEGACY + depends on PCI && MAC80211 + select IWLWIFI_LEGACY ---help--- This option enables support for @@ -92,7 +92,8 @@ config IWL4965 config IWL3945 tristate "Intel PRO/Wireless 3945ABG/BG Network Connection (iwl3945)" - depends on IWLWIFI_LEGACY + depends on PCI && MAC80211 + select IWLWIFI_LEGACY ---help--- Select to build the driver supporting the: -- cgit v0.10.2 From bded18c2dd09eee870f4446652dbce493a6dece1 Mon Sep 17 00:00:00 2001 From: Giuseppe CAVALLARO Date: Sun, 10 Apr 2011 23:16:44 +0000 Subject: stmmac: fixed dma lib build when turn-on the debug option This patch fixes a compilation error when build the dwmac_lib with the DEBUG option enabled. Signed-off-by: Giuseppe Cavallaro Signed-off-by: David S. Miller diff --git a/drivers/net/stmmac/dwmac_lib.c b/drivers/net/stmmac/dwmac_lib.c index d65fab1..e250935 100644 --- a/drivers/net/stmmac/dwmac_lib.c +++ b/drivers/net/stmmac/dwmac_lib.c @@ -26,9 +26,9 @@ #undef DWMAC_DMA_DEBUG #ifdef DWMAC_DMA_DEBUG -#define DBG(fmt, args...) printk(fmt, ## args) +#define DWMAC_LIB_DBG(fmt, args...) printk(fmt, ## args) #else -#define DBG(fmt, args...) do { } while (0) +#define DWMAC_LIB_DBG(fmt, args...) do { } while (0) #endif /* CSR1 enables the transmit DMA to check for new descriptor */ @@ -152,7 +152,7 @@ int dwmac_dma_interrupt(void __iomem *ioaddr, /* read the status register (CSR5) */ u32 intr_status = readl(ioaddr + DMA_STATUS); - DBG(INFO, "%s: [CSR5: 0x%08x]\n", __func__, intr_status); + DWMAC_LIB_DBG(KERN_INFO "%s: [CSR5: 0x%08x]\n", __func__, intr_status); #ifdef DWMAC_DMA_DEBUG /* It displays the DMA process states (CSR5 register) */ show_tx_process_state(intr_status); @@ -160,43 +160,43 @@ int dwmac_dma_interrupt(void __iomem *ioaddr, #endif /* ABNORMAL interrupts */ if (unlikely(intr_status & DMA_STATUS_AIS)) { - DBG(INFO, "CSR5[15] DMA ABNORMAL IRQ: "); + DWMAC_LIB_DBG(KERN_INFO "CSR5[15] DMA ABNORMAL IRQ: "); if (unlikely(intr_status & DMA_STATUS_UNF)) { - DBG(INFO, "transmit underflow\n"); + DWMAC_LIB_DBG(KERN_INFO "transmit underflow\n"); ret = tx_hard_error_bump_tc; x->tx_undeflow_irq++; } if (unlikely(intr_status & DMA_STATUS_TJT)) { - DBG(INFO, "transmit jabber\n"); + DWMAC_LIB_DBG(KERN_INFO "transmit jabber\n"); x->tx_jabber_irq++; } if (unlikely(intr_status & DMA_STATUS_OVF)) { - DBG(INFO, "recv overflow\n"); + DWMAC_LIB_DBG(KERN_INFO "recv overflow\n"); x->rx_overflow_irq++; } if (unlikely(intr_status & DMA_STATUS_RU)) { - DBG(INFO, "receive buffer unavailable\n"); + DWMAC_LIB_DBG(KERN_INFO "receive buffer unavailable\n"); x->rx_buf_unav_irq++; } if (unlikely(intr_status & DMA_STATUS_RPS)) { - DBG(INFO, "receive process stopped\n"); + DWMAC_LIB_DBG(KERN_INFO "receive process stopped\n"); x->rx_process_stopped_irq++; } if (unlikely(intr_status & DMA_STATUS_RWT)) { - DBG(INFO, "receive watchdog\n"); + DWMAC_LIB_DBG(KERN_INFO "receive watchdog\n"); x->rx_watchdog_irq++; } if (unlikely(intr_status & DMA_STATUS_ETI)) { - DBG(INFO, "transmit early interrupt\n"); + DWMAC_LIB_DBG(KERN_INFO "transmit early interrupt\n"); x->tx_early_irq++; } if (unlikely(intr_status & DMA_STATUS_TPS)) { - DBG(INFO, "transmit process stopped\n"); + DWMAC_LIB_DBG(KERN_INFO "transmit process stopped\n"); x->tx_process_stopped_irq++; ret = tx_hard_error; } if (unlikely(intr_status & DMA_STATUS_FBI)) { - DBG(INFO, "fatal bus error\n"); + DWMAC_LIB_DBG(KERN_INFO "fatal bus error\n"); x->fatal_bus_error_irq++; ret = tx_hard_error; } @@ -215,7 +215,7 @@ int dwmac_dma_interrupt(void __iomem *ioaddr, /* Clear the interrupt by writing a logic 1 to the CSR5[15-0] */ writel((intr_status & 0x1ffff), ioaddr + DMA_STATUS); - DBG(INFO, "\n\n"); + DWMAC_LIB_DBG(KERN_INFO "\n\n"); return ret; } -- cgit v0.10.2 From f66ffe285939559d2a6f630a36f676d7c056b99d Mon Sep 17 00:00:00 2001 From: Giuseppe CAVALLARO Date: Sun, 10 Apr 2011 23:16:45 +0000 Subject: stmmac: fix open funct when exit on error This patch reviews the open function and fixes some errors when exit with an error state. It also moves the request_irq after core is initialized when interrupts are properly masked. Signed-off-by: Shiraz Hashim Hacked-by: Giuseppe Cavallaro Signed-off-by: David S. Miller diff --git a/drivers/net/stmmac/stmmac_main.c b/drivers/net/stmmac/stmmac_main.c index 0e5f031..38f7b61 100644 --- a/drivers/net/stmmac/stmmac_main.c +++ b/drivers/net/stmmac/stmmac_main.c @@ -781,21 +781,6 @@ static int stmmac_open(struct net_device *dev) stmmac_verify_args(); - ret = stmmac_init_phy(dev); - if (unlikely(ret)) { - pr_err("%s: Cannot attach to PHY (error: %d)\n", __func__, ret); - return ret; - } - - /* Request the IRQ lines */ - ret = request_irq(dev->irq, stmmac_interrupt, - IRQF_SHARED, dev->name, dev); - if (unlikely(ret < 0)) { - pr_err("%s: ERROR: allocating the IRQ %d (error: %d)\n", - __func__, dev->irq, ret); - return ret; - } - #ifdef CONFIG_STMMAC_TIMER priv->tm = kzalloc(sizeof(struct stmmac_timer *), GFP_KERNEL); if (unlikely(priv->tm == NULL)) { @@ -814,6 +799,11 @@ static int stmmac_open(struct net_device *dev) } else priv->tm->enable = 1; #endif + ret = stmmac_init_phy(dev); + if (unlikely(ret)) { + pr_err("%s: Cannot attach to PHY (error: %d)\n", __func__, ret); + goto open_error; + } /* Create and initialize the TX/RX descriptors chains. */ priv->dma_tx_size = STMMAC_ALIGN(dma_txsize); @@ -822,12 +812,11 @@ static int stmmac_open(struct net_device *dev) init_dma_desc_rings(dev); /* DMA initialization and SW reset */ - if (unlikely(priv->hw->dma->init(priv->ioaddr, priv->plat->pbl, - priv->dma_tx_phy, - priv->dma_rx_phy) < 0)) { - + ret = priv->hw->dma->init(priv->ioaddr, priv->plat->pbl, + priv->dma_tx_phy, priv->dma_rx_phy); + if (ret < 0) { pr_err("%s: DMA initialization failed\n", __func__); - return -1; + goto open_error; } /* Copy the MAC addr into the HW */ @@ -848,6 +837,15 @@ static int stmmac_open(struct net_device *dev) writel(0xffffffff, priv->ioaddr + MMC_HIGH_INTR_MASK); writel(0xffffffff, priv->ioaddr + MMC_LOW_INTR_MASK); + /* Request the IRQ lines */ + ret = request_irq(dev->irq, stmmac_interrupt, + IRQF_SHARED, dev->name, dev); + if (unlikely(ret < 0)) { + pr_err("%s: ERROR: allocating the IRQ %d (error: %d)\n", + __func__, dev->irq, ret); + goto open_error; + } + /* Enable the MAC Rx/Tx */ stmmac_enable_mac(priv->ioaddr); @@ -878,7 +876,17 @@ static int stmmac_open(struct net_device *dev) napi_enable(&priv->napi); skb_queue_head_init(&priv->rx_recycle); netif_start_queue(dev); + return 0; + +open_error: +#ifdef CONFIG_STMMAC_TIMER + kfree(priv->tm); +#endif + if (priv->phydev) + phy_disconnect(priv->phydev); + + return ret; } /** -- cgit v0.10.2 From a08070acd43a76069ab20000cd02474369506add Mon Sep 17 00:00:00 2001 From: Giuseppe CAVALLARO Date: Sun, 10 Apr 2011 23:16:46 +0000 Subject: stmmac: fix Transmit Underflow error On some old MAC chips without COE sometime the Transmit Underflow error is issued. The driver aborted all the transmission process and initialized it from scratch. This breaks the network activity as raised by Nachiketa on a SPEAr board. The patch is to fix this rare underflow event. The driver will only clear the interrupt and the Tx DMA will go out the Suspend state as soon as the descriptor is fetched again. The driver will continue to bump-up the DMA FIFO threshold that, indeed, helped somebody to prevent this kind of error in the past as well. Reported-by: Nachiketa Prachanda Signed-off-by: Giuseppe Cavallaro Signed-off-by: David S. Miller diff --git a/drivers/net/stmmac/stmmac_main.c b/drivers/net/stmmac/stmmac_main.c index 38f7b61..cc973fc 100644 --- a/drivers/net/stmmac/stmmac_main.c +++ b/drivers/net/stmmac/stmmac_main.c @@ -750,7 +750,6 @@ static void stmmac_dma_interrupt(struct stmmac_priv *priv) priv->hw->dma->dma_mode(priv->ioaddr, tc, SF_DMA_MODE); priv->xstats.threshold = tc; } - stmmac_tx_err(priv); } else if (unlikely(status == tx_hard_error)) stmmac_tx_err(priv); } -- cgit v0.10.2 From 0b5ec87d3e1bcfe56515e550e1c6c94db9ab928b Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Fri, 8 Apr 2011 15:09:02 +0900 Subject: ASoC: fsi: take care in failing case of dai register Signed-off-by: Kuninori Morimoto Acked-by: Liam Girdwood Signed-off-by: Mark Brown diff --git a/sound/soc/sh/fsi.c b/sound/soc/sh/fsi.c index 0c9997e..8e51a6e 100644 --- a/sound/soc/sh/fsi.c +++ b/sound/soc/sh/fsi.c @@ -1218,8 +1218,17 @@ static int fsi_probe(struct platform_device *pdev) goto exit_free_irq; } - return snd_soc_register_dais(&pdev->dev, fsi_soc_dai, ARRAY_SIZE(fsi_soc_dai)); + ret = snd_soc_register_dais(&pdev->dev, fsi_soc_dai, + ARRAY_SIZE(fsi_soc_dai)); + if (ret < 0) { + dev_err(&pdev->dev, "cannot snd dai register\n"); + goto exit_snd_soc; + } + return ret; + +exit_snd_soc: + snd_soc_unregister_platform(&pdev->dev); exit_free_irq: free_irq(irq, master); exit_iounmap: -- cgit v0.10.2 From b9c9f9675fe002e95e596dbe086fdd3baa59db46 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Fri, 8 Apr 2011 15:09:17 +0900 Subject: ASoC: fsi: modify vague PM control on probe Signed-off-by: Kuninori Morimoto Acked-by: Liam Girdwood Signed-off-by: Mark Brown diff --git a/sound/soc/sh/fsi.c b/sound/soc/sh/fsi.c index 8e51a6e..8071bc6 100644 --- a/sound/soc/sh/fsi.c +++ b/sound/soc/sh/fsi.c @@ -1200,10 +1200,11 @@ static int fsi_probe(struct platform_device *pdev) master->fsib.master = master; pm_runtime_enable(&pdev->dev); - pm_runtime_resume(&pdev->dev); dev_set_drvdata(&pdev->dev, master); + pm_runtime_get_sync(&pdev->dev); fsi_soft_all_reset(master); + pm_runtime_put_sync(&pdev->dev); ret = request_irq(irq, &fsi_interrupt, IRQF_DISABLED, id_entry->name, master); -- cgit v0.10.2 From d985f27e13fe62e158a3416e3d8308ef1cf6028c Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Fri, 8 Apr 2011 15:09:25 +0900 Subject: ASoC: fsi: driver safely remove for against irq free_irq and pm_runtime_disable should be called before snd_soc_unregister_xxx Signed-off-by: Kuninori Morimoto Acked-by: Liam Girdwood Signed-off-by: Mark Brown diff --git a/sound/soc/sh/fsi.c b/sound/soc/sh/fsi.c index 8071bc6..5843158 100644 --- a/sound/soc/sh/fsi.c +++ b/sound/soc/sh/fsi.c @@ -1248,12 +1248,11 @@ static int fsi_remove(struct platform_device *pdev) master = dev_get_drvdata(&pdev->dev); - snd_soc_unregister_dais(&pdev->dev, ARRAY_SIZE(fsi_soc_dai)); - snd_soc_unregister_platform(&pdev->dev); - + free_irq(master->irq, master); pm_runtime_disable(&pdev->dev); - free_irq(master->irq, master); + snd_soc_unregister_dais(&pdev->dev, ARRAY_SIZE(fsi_soc_dai)); + snd_soc_unregister_platform(&pdev->dev); iounmap(master->base); kfree(master); -- cgit v0.10.2 From d89b0a136e61c2d7d37a8040269a2ae169345c7a Mon Sep 17 00:00:00 2001 From: Lu Guanqun Date: Fri, 8 Apr 2011 15:38:48 +0800 Subject: ASoC: sst_platform: Fix lock acquring Fix the possible dead lock shown below: spin_lock sst_get_stream_status sst_period_elapsed intel_sst_interrupt handle_IRQ_event handle_fasteoi_irq do_IRQ common_interrupt spin_lock sst_set_stream_status sst_platform_pcm_trigger Signed-off-by: Lu Guanqun Acked-by: Liam Girdwood Signed-off-by: Mark Brown diff --git a/sound/soc/mid-x86/sst_platform.c b/sound/soc/mid-x86/sst_platform.c index ee2c224..9ebe027 100644 --- a/sound/soc/mid-x86/sst_platform.c +++ b/sound/soc/mid-x86/sst_platform.c @@ -116,18 +116,20 @@ struct snd_soc_dai_driver sst_platform_dai[] = { static inline void sst_set_stream_status(struct sst_runtime_stream *stream, int state) { - spin_lock(&stream->status_lock); + unsigned long flags; + spin_lock_irqsave(&stream->status_lock, flags); stream->stream_status = state; - spin_unlock(&stream->status_lock); + spin_unlock_irqrestore(&stream->status_lock, flags); } static inline int sst_get_stream_status(struct sst_runtime_stream *stream) { int state; + unsigned long flags; - spin_lock(&stream->status_lock); + spin_lock_irqsave(&stream->status_lock, flags); state = stream->stream_status; - spin_unlock(&stream->status_lock); + spin_unlock_irqrestore(&stream->status_lock, flags); return state; } -- cgit v0.10.2 From 68e0c6696c98c0fe548627ad705b098ae1148c2b Mon Sep 17 00:00:00 2001 From: Sangbeom Kim Date: Sat, 9 Apr 2011 10:53:58 +0900 Subject: ASoC: SAMSUNG: Fix the inverted clocks handling for pcm driver Fix the inverted clocks handling for pcm cpu driver. By using SND_SOC_DAIFMT_NB_NF, Audio noise can be generated on SMDK. Signed-off-by: Sangbeom Kim Acked-by: Jassi Brar Acked-by: Liam Girdwood Signed-off-by: Mark Brown diff --git a/sound/soc/samsung/pcm.c b/sound/soc/samsung/pcm.c index 38aac7d..9c7e8b4 100644 --- a/sound/soc/samsung/pcm.c +++ b/sound/soc/samsung/pcm.c @@ -350,8 +350,8 @@ static int s3c_pcm_set_fmt(struct snd_soc_dai *cpu_dai, ctl = readl(regs + S3C_PCM_CTL); switch (fmt & SND_SOC_DAIFMT_INV_MASK) { - case SND_SOC_DAIFMT_NB_NF: - /* Nothing to do, NB_NF by default */ + case SND_SOC_DAIFMT_IB_NF: + /* Nothing to do, IB_NF by default */ break; default: dev_err(pcm->dev, "Unsupported clock inversion!\n"); -- cgit v0.10.2 From 38dbaf0afb518e462de7afca552acad048237a73 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Peter=20Pan=28=E6=BD=98=E5=8D=AB=E5=B9=B3=29?= Date: Fri, 8 Apr 2011 03:40:19 +0000 Subject: bonding:set save_load to 0 when initializing MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It is unnecessary to set save_load to 1 here, as the tx_hashtbl is just kzalloced. Signed-off-by: Weiping Pan(潘å«å¹³) Signed-off-by: Jay Vosburgh Signed-off-by: David S. Miller diff --git a/drivers/net/bonding/bond_alb.c b/drivers/net/bonding/bond_alb.c index 9bc5de3..ab69e5a 100644 --- a/drivers/net/bonding/bond_alb.c +++ b/drivers/net/bonding/bond_alb.c @@ -176,7 +176,7 @@ static int tlb_initialize(struct bonding *bond) bond_info->tx_hashtbl = new_hashtbl; for (i = 0; i < TLB_HASH_TABLE_SIZE; i++) { - tlb_init_table_entry(&bond_info->tx_hashtbl[i], 1); + tlb_init_table_entry(&bond_info->tx_hashtbl[i], 0); } _unlock_tx_hashtbl(bond); -- cgit v0.10.2 From 3b647568454acedb8f09f72931bfe92b73f812c7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Peter=20Pan=28=E6=BD=98=E5=8D=AB=E5=B9=B3=29?= Date: Sun, 10 Apr 2011 22:17:24 +0000 Subject: bonding:delete unused alb_timer MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Now bonding-alb uses delayed_work instead of timer_list. Signed-off-by: Weiping Pan(潘å«å¹³) Signed-off-by: David S. Miller diff --git a/drivers/net/bonding/bond_alb.h b/drivers/net/bonding/bond_alb.h index 86861f0..f2a1d0a 100644 --- a/drivers/net/bonding/bond_alb.h +++ b/drivers/net/bonding/bond_alb.h @@ -122,7 +122,6 @@ struct tlb_slave_info { }; struct alb_bond_info { - struct timer_list alb_timer; struct tlb_client_info *tx_hashtbl; /* Dynamically allocated */ spinlock_t tx_hashtbl_lock; u32 unbalanced_load; -- cgit v0.10.2 From 26f007b85a1bb73e1974ebd371cf5cd1e80c0a00 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Peter=20Pan=28=E6=BD=98=E5=8D=AB=E5=B9=B3=29?= Date: Sun, 10 Apr 2011 22:17:25 +0000 Subject: bonding:delete unused rlb_interval_counter MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Now, alb_bond_info uses rx_ntt,rlb_update_delay_counter and rlb_update_retry_counter to decide when to call rlb_update_rx_clients(). Signed-off-by: Weiping Pan(潘å«å¹³) Signed-off-by: David S. Miller diff --git a/drivers/net/bonding/bond_alb.h b/drivers/net/bonding/bond_alb.h index f2a1d0a..01ed1fb 100644 --- a/drivers/net/bonding/bond_alb.h +++ b/drivers/net/bonding/bond_alb.h @@ -139,7 +139,6 @@ struct alb_bond_info { struct slave *next_rx_slave;/* next slave to be assigned * to a new rx client for */ - u32 rlb_interval_counter; u8 primary_is_promisc; /* boolean */ u32 rlb_promisc_timeout_counter;/* counts primary * promiscuity time -- cgit v0.10.2 From 9814290ad0314fa0ce7991eae34ac44956e40b12 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Peter=20Pan=28=E6=BD=98=E5=8D=AB=E5=B9=B3=29?= Date: Mon, 11 Apr 2011 00:15:57 +0000 Subject: net: fix tranmitted/tranmitting typo MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit replace tranmitted with transmitted. replace tranmitting with transmitting. Signed-off-by: Weiping Pan(潘å«å¹³) Signed-off-by: David S. Miller diff --git a/drivers/net/bonding/bond_alb.h b/drivers/net/bonding/bond_alb.h index 01ed1fb..8ca7158 100644 --- a/drivers/net/bonding/bond_alb.h +++ b/drivers/net/bonding/bond_alb.h @@ -75,7 +75,7 @@ struct tlb_client_info { * gave this entry index. */ u32 tx_bytes; /* Each Client accumulates the BytesTx that - * were tranmitted to it, and after each + * were transmitted to it, and after each * CallBack the LoadHistory is divided * by the balance interval */ diff --git a/drivers/net/tokenring/3c359.c b/drivers/net/tokenring/3c359.c index 8a3b191..ff32bef 100644 --- a/drivers/net/tokenring/3c359.c +++ b/drivers/net/tokenring/3c359.c @@ -1251,7 +1251,7 @@ static netdev_tx_t xl_xmit(struct sk_buff *skb, struct net_device *dev) /* * The NIC has told us that a packet has been downloaded onto the card, we must * find out which packet it has done, clear the skb and information for the packet - * then advance around the ring for all tranmitted packets + * then advance around the ring for all transmitted packets */ static void xl_dn_comp(struct net_device *dev) @@ -1568,7 +1568,7 @@ static void xl_arb_cmd(struct net_device *dev) if (lan_status_diff & LSC_SOFT_ERR) printk(KERN_WARNING "%s: Adapter transmitted Soft Error Report Mac Frame\n",dev->name); if (lan_status_diff & LSC_TRAN_BCN) - printk(KERN_INFO "%s: We are tranmitting the beacon, aaah\n",dev->name); + printk(KERN_INFO "%s: We are transmitting the beacon, aaah\n",dev->name); if (lan_status_diff & LSC_SS) printk(KERN_INFO "%s: Single Station on the ring\n", dev->name); if (lan_status_diff & LSC_RING_REC) diff --git a/drivers/net/tokenring/lanstreamer.c b/drivers/net/tokenring/lanstreamer.c index 5bd1407..9354ca9 100644 --- a/drivers/net/tokenring/lanstreamer.c +++ b/drivers/net/tokenring/lanstreamer.c @@ -1675,7 +1675,7 @@ drop_frame: if (lan_status_diff & LSC_SOFT_ERR) printk(KERN_WARNING "%s: Adapter transmitted Soft Error Report Mac Frame\n", dev->name); if (lan_status_diff & LSC_TRAN_BCN) - printk(KERN_INFO "%s: We are tranmitting the beacon, aaah\n", dev->name); + printk(KERN_INFO "%s: We are transmitting the beacon, aaah\n", dev->name); if (lan_status_diff & LSC_SS) printk(KERN_INFO "%s: Single Station on the ring\n", dev->name); if (lan_status_diff & LSC_RING_REC) diff --git a/drivers/net/tokenring/olympic.c b/drivers/net/tokenring/olympic.c index 3d2fbe6..2684003 100644 --- a/drivers/net/tokenring/olympic.c +++ b/drivers/net/tokenring/olympic.c @@ -1500,7 +1500,7 @@ drop_frame: if (lan_status_diff & LSC_SOFT_ERR) printk(KERN_WARNING "%s: Adapter transmitted Soft Error Report Mac Frame\n",dev->name); if (lan_status_diff & LSC_TRAN_BCN) - printk(KERN_INFO "%s: We are tranmitting the beacon, aaah\n",dev->name); + printk(KERN_INFO "%s: We are transmitting the beacon, aaah\n",dev->name); if (lan_status_diff & LSC_SS) printk(KERN_INFO "%s: Single Station on the ring\n", dev->name); if (lan_status_diff & LSC_RING_REC) -- cgit v0.10.2 From 77c8e2c01542649f7a02fef8eb3b3d0e7fed6bbd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Peter=20Pan=28=E6=BD=98=E5=8D=AB=E5=B9=B3=29?= Date: Mon, 11 Apr 2011 00:16:32 +0000 Subject: bonding:fix two typos MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit replace relpy with reply. replace premanent with permanent. Signed-off-by: Weiping Pan(潘å«å¹³) Signed-off-by: David S. Miller diff --git a/drivers/net/bonding/bond_alb.c b/drivers/net/bonding/bond_alb.c index ab69e5a..ba71582 100644 --- a/drivers/net/bonding/bond_alb.c +++ b/drivers/net/bonding/bond_alb.c @@ -701,7 +701,7 @@ static struct slave *rlb_arp_xmit(struct sk_buff *skb, struct bonding *bond) */ rlb_choose_channel(skb, bond); - /* The ARP relpy packets must be delayed so that + /* The ARP reply packets must be delayed so that * they can cancel out the influence of the ARP request. */ bond->alb_info.rlb_update_delay_counter = RLB_UPDATE_DELAY; @@ -1042,7 +1042,7 @@ static void alb_change_hw_addr_on_detach(struct bonding *bond, struct slave *sla * * If the permanent hw address of @slave is @bond's hw address, we need to * find a different hw address to give @slave, that isn't in use by any other - * slave in the bond. This address must be, of course, one of the premanent + * slave in the bond. This address must be, of course, one of the permanent * addresses of the other slaves. * * We go over the slave list, and for each slave there we compare its -- cgit v0.10.2 From c968bdf6912cad6d0fc63d7037cc1c870604a808 Mon Sep 17 00:00:00 2001 From: amit salecha Date: Mon, 11 Apr 2011 02:10:22 +0000 Subject: netxen: limit skb frags for non tso packet Machines are getting deadlock in four node cluster environment. All nodes are accessing (find /gfs2 -depth -print|cpio -ocv > /dev/null) 200 GB storage on a GFS2 filesystem. This result in memory fragmentation and driver receives 18 frags for 1448 byte packets. For non tso packet, fw drops the tx request, if it has >14 frags. Fixing it by pulling extra frags. Cc: stable@kernel.org Signed-off-by: Amit Kumar Salecha Signed-off-by: David S. Miller diff --git a/drivers/net/netxen/netxen_nic.h b/drivers/net/netxen/netxen_nic.h index d7299f1..679dc85 100644 --- a/drivers/net/netxen/netxen_nic.h +++ b/drivers/net/netxen/netxen_nic.h @@ -174,7 +174,7 @@ #define MAX_NUM_CARDS 4 -#define MAX_BUFFERS_PER_CMD 32 +#define NETXEN_MAX_FRAGS_PER_TX 14 #define MAX_TSO_HEADER_DESC 2 #define MGMT_CMD_DESC_RESV 4 #define TX_STOP_THRESH ((MAX_SKB_FRAGS >> 2) + MAX_TSO_HEADER_DESC \ @@ -558,7 +558,7 @@ struct netxen_recv_crb { */ struct netxen_cmd_buffer { struct sk_buff *skb; - struct netxen_skb_frag frag_array[MAX_BUFFERS_PER_CMD + 1]; + struct netxen_skb_frag frag_array[MAX_SKB_FRAGS + 1]; u32 frag_count; }; diff --git a/drivers/net/netxen/netxen_nic_main.c b/drivers/net/netxen/netxen_nic_main.c index 83348dc..e8a4b66 100644 --- a/drivers/net/netxen/netxen_nic_main.c +++ b/drivers/net/netxen/netxen_nic_main.c @@ -1844,6 +1844,8 @@ netxen_nic_xmit_frame(struct sk_buff *skb, struct net_device *netdev) struct cmd_desc_type0 *hwdesc, *first_desc; struct pci_dev *pdev; int i, k; + int delta = 0; + struct skb_frag_struct *frag; u32 producer; int frag_count, no_of_desc; @@ -1851,6 +1853,21 @@ netxen_nic_xmit_frame(struct sk_buff *skb, struct net_device *netdev) frag_count = skb_shinfo(skb)->nr_frags + 1; + /* 14 frags supported for normal packet and + * 32 frags supported for TSO packet + */ + if (!skb_is_gso(skb) && frag_count > NETXEN_MAX_FRAGS_PER_TX) { + + for (i = 0; i < (frag_count - NETXEN_MAX_FRAGS_PER_TX); i++) { + frag = &skb_shinfo(skb)->frags[i]; + delta += frag->size; + } + + if (!__pskb_pull_tail(skb, delta)) + goto drop_packet; + + frag_count = 1 + skb_shinfo(skb)->nr_frags; + } /* 4 fragments per cmd des */ no_of_desc = (frag_count + 3) >> 2; -- cgit v0.10.2 From 0c184ed9032c58b21f0d90de28c796874b73d6a1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sjur=20Br=C3=A6ndeland?= Date: Mon, 11 Apr 2011 10:11:29 +0000 Subject: caif: Bugfix use for_each_safe when removing list nodes. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Sjur Brændeland Signed-off-by: David S. Miller diff --git a/net/caif/cfmuxl.c b/net/caif/cfmuxl.c index 46f34b2..24f1ffa 100644 --- a/net/caif/cfmuxl.c +++ b/net/caif/cfmuxl.c @@ -244,9 +244,9 @@ static void cfmuxl_ctrlcmd(struct cflayer *layr, enum caif_ctrlcmd ctrl, int phyid) { struct cfmuxl *muxl = container_obj(layr); - struct list_head *node; + struct list_head *node, *next; struct cflayer *layer; - list_for_each(node, &muxl->srvl_list) { + list_for_each_safe(node, next, &muxl->srvl_list) { layer = list_entry(node, struct cflayer, node); if (cfsrvl_phyid_match(layer, phyid)) layer->ctrlcmd(layer, ctrl, phyid); -- cgit v0.10.2 From 4a9f65f6304a00f6473e83b19c1e83caa1e42530 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sjur=20Br=C3=A6ndeland?= Date: Mon, 11 Apr 2011 10:11:30 +0000 Subject: caif: performance bugfix - allow radio stack to prioritize packets. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In the CAIF Payload message the Packet Type indication must be set to UNCLASSIFIED in order to allow packet prioritization in the modem's network stack. Otherwise TCP-Ack is not prioritized in the modems transmit queue. Signed-off-by: Sjur Brændeland Signed-off-by: David S. Miller diff --git a/net/caif/cfdgml.c b/net/caif/cfdgml.c index 27dab26..054fdb5 100644 --- a/net/caif/cfdgml.c +++ b/net/caif/cfdgml.c @@ -13,6 +13,7 @@ #include #include + #define container_obj(layr) ((struct cfsrvl *) layr) #define DGM_CMD_BIT 0x80 @@ -83,6 +84,7 @@ static int cfdgml_receive(struct cflayer *layr, struct cfpkt *pkt) static int cfdgml_transmit(struct cflayer *layr, struct cfpkt *pkt) { + u8 packet_type; u32 zero = 0; struct caif_payload_info *info; struct cfsrvl *service = container_obj(layr); @@ -94,7 +96,9 @@ static int cfdgml_transmit(struct cflayer *layr, struct cfpkt *pkt) if (cfpkt_getlen(pkt) > DGM_MTU) return -EMSGSIZE; - cfpkt_add_head(pkt, &zero, 4); + cfpkt_add_head(pkt, &zero, 3); + packet_type = 0x08; /* B9 set - UNCLASSIFIED */ + cfpkt_add_head(pkt, &packet_type, 1); /* Add info for MUX-layer to route the packet out. */ info = cfpkt_info(pkt); -- cgit v0.10.2 From 5d9f11cf5038587cc53975deb8beaa1a876a7a7b Mon Sep 17 00:00:00 2001 From: Alexander Duyck Date: Fri, 8 Apr 2011 12:07:22 +0000 Subject: ethtool: prevent null pointer dereference with NTUPLE set but no set_rx_ntuple This change is meant to prevent a possible null pointer dereference if NETIF_F_NTUPLE is defined but the set_rx_ntuple function pointer is not. The main motivation behind this patch is to eventually replace the ntuple interfaces entirely with the network flow classifier interfaces. This allows the device drivers to maintain the ntuple check internally while using the network flow classifier interface for setting up and displaying rules. Signed-off-by: Alexander Duyck Signed-off-by: David S. Miller diff --git a/net/core/ethtool.c b/net/core/ethtool.c index 1b7fa98..704e176 100644 --- a/net/core/ethtool.c +++ b/net/core/ethtool.c @@ -910,6 +910,9 @@ static noinline_for_stack int ethtool_set_rx_ntuple(struct net_device *dev, struct ethtool_rx_ntuple_flow_spec_container *fsc = NULL; int ret; + if (!ops->set_rx_ntuple) + return -EOPNOTSUPP; + if (!(dev->features & NETIF_F_NTUPLE)) return -EINVAL; -- cgit v0.10.2 From 127fe533ae56d7f4e7b5011869870982eba25723 Mon Sep 17 00:00:00 2001 From: Alexander Duyck Date: Fri, 8 Apr 2011 18:01:59 +0000 Subject: v3 ethtool: add ntuple flow specifier data to network flow classifier This change is meant to add an ntuple data extensions to the rx network flow classification specifiers. The idea is to allow ntuple to be displayed via the network flow classification interface. The first patch had some left over stuff from the original flow extension flags I had added. That bit is removed in this patch. The second had some left over comments that stated we ignored bits in the masks when we actually match them. This work is based on input from Ben Hutchings. Signed-off-by: Alexander Duyck Reviewed-by: Ben Hutchings Signed-off-by: David S. Miller diff --git a/include/linux/ethtool.h b/include/linux/ethtool.h index c04d131..c7eff13 100644 --- a/include/linux/ethtool.h +++ b/include/linux/ethtool.h @@ -380,27 +380,42 @@ struct ethtool_usrip4_spec { __u8 proto; }; +union ethtool_flow_union { + struct ethtool_tcpip4_spec tcp_ip4_spec; + struct ethtool_tcpip4_spec udp_ip4_spec; + struct ethtool_tcpip4_spec sctp_ip4_spec; + struct ethtool_ah_espip4_spec ah_ip4_spec; + struct ethtool_ah_espip4_spec esp_ip4_spec; + struct ethtool_usrip4_spec usr_ip4_spec; + struct ethhdr ether_spec; + __u8 hdata[60]; +}; + +struct ethtool_flow_ext { + __be16 vlan_etype; + __be16 vlan_tci; + __be32 data[2]; +}; + /** * struct ethtool_rx_flow_spec - specification for RX flow filter * @flow_type: Type of match to perform, e.g. %TCP_V4_FLOW * @h_u: Flow fields to match (dependent on @flow_type) - * @m_u: Masks for flow field bits to be ignored + * @h_ext: Additional fields to match + * @m_u: Masks for flow field bits to be matched + * @m_ext: Masks for additional field bits to be matched + * Note, all additional fields must be ignored unless @flow_type + * includes the %FLOW_EXT flag. * @ring_cookie: RX ring/queue index to deliver to, or %RX_CLS_FLOW_DISC * if packets should be discarded * @location: Index of filter in hardware table */ struct ethtool_rx_flow_spec { __u32 flow_type; - union { - struct ethtool_tcpip4_spec tcp_ip4_spec; - struct ethtool_tcpip4_spec udp_ip4_spec; - struct ethtool_tcpip4_spec sctp_ip4_spec; - struct ethtool_ah_espip4_spec ah_ip4_spec; - struct ethtool_ah_espip4_spec esp_ip4_spec; - struct ethtool_usrip4_spec usr_ip4_spec; - struct ethhdr ether_spec; - __u8 hdata[72]; - } h_u, m_u; + union ethtool_flow_union h_u; + struct ethtool_flow_ext h_ext; + union ethtool_flow_union m_u; + struct ethtool_flow_ext m_ext; __u64 ring_cookie; __u32 location; }; @@ -458,16 +473,10 @@ struct ethtool_rxnfc { struct compat_ethtool_rx_flow_spec { u32 flow_type; - union { - struct ethtool_tcpip4_spec tcp_ip4_spec; - struct ethtool_tcpip4_spec udp_ip4_spec; - struct ethtool_tcpip4_spec sctp_ip4_spec; - struct ethtool_ah_espip4_spec ah_ip4_spec; - struct ethtool_ah_espip4_spec esp_ip4_spec; - struct ethtool_usrip4_spec usr_ip4_spec; - struct ethhdr ether_spec; - u8 hdata[72]; - } h_u, m_u; + union ethtool_flow_union h_u; + struct ethtool_flow_ext h_ext; + union ethtool_flow_union m_u; + struct ethtool_flow_ext m_ext; compat_u64 ring_cookie; u32 location; }; @@ -1072,6 +1081,8 @@ struct ethtool_ops { #define IPV4_FLOW 0x10 /* hash only */ #define IPV6_FLOW 0x11 /* hash only */ #define ETHER_FLOW 0x12 /* spec only (ether_spec) */ +/* Flag to enable additional fields in struct ethtool_rx_flow_spec */ +#define FLOW_EXT 0x80000000 /* L3-L4 network traffic flow hash options */ #define RXH_L2DA (1 << 1) diff --git a/net/socket.c b/net/socket.c index 5212447..575c84f 100644 --- a/net/socket.c +++ b/net/socket.c @@ -2643,13 +2643,13 @@ static int ethtool_ioctl(struct net *net, struct compat_ifreq __user *ifr32) return -EFAULT; if (convert_in) { - /* We expect there to be holes between fs.m_u and + /* We expect there to be holes between fs.m_ext and * fs.ring_cookie and at the end of fs, but nowhere else. */ - BUILD_BUG_ON(offsetof(struct compat_ethtool_rxnfc, fs.m_u) + - sizeof(compat_rxnfc->fs.m_u) != - offsetof(struct ethtool_rxnfc, fs.m_u) + - sizeof(rxnfc->fs.m_u)); + BUILD_BUG_ON(offsetof(struct compat_ethtool_rxnfc, fs.m_ext) + + sizeof(compat_rxnfc->fs.m_ext) != + offsetof(struct ethtool_rxnfc, fs.m_ext) + + sizeof(rxnfc->fs.m_ext)); BUILD_BUG_ON( offsetof(struct compat_ethtool_rxnfc, fs.location) - offsetof(struct compat_ethtool_rxnfc, fs.ring_cookie) != @@ -2657,7 +2657,7 @@ static int ethtool_ioctl(struct net *net, struct compat_ifreq __user *ifr32) offsetof(struct ethtool_rxnfc, fs.ring_cookie)); if (copy_in_user(rxnfc, compat_rxnfc, - (void *)(&rxnfc->fs.m_u + 1) - + (void *)(&rxnfc->fs.m_ext + 1) - (void *)rxnfc) || copy_in_user(&rxnfc->fs.ring_cookie, &compat_rxnfc->fs.ring_cookie, @@ -2674,7 +2674,7 @@ static int ethtool_ioctl(struct net *net, struct compat_ifreq __user *ifr32) if (convert_out) { if (copy_in_user(compat_rxnfc, rxnfc, - (const void *)(&rxnfc->fs.m_u + 1) - + (const void *)(&rxnfc->fs.m_ext + 1) - (const void *)rxnfc) || copy_in_user(&compat_rxnfc->fs.ring_cookie, &rxnfc->fs.ring_cookie, -- cgit v0.10.2 From 1b3291241a658fb4d4bbdb41483e1f53c26445ec Mon Sep 17 00:00:00 2001 From: stephen hemminger Date: Wed, 6 Apr 2011 13:47:50 +0000 Subject: qlge: use ethtool set_phys_id This is a stab at replacing old ethtool phys_id with set_phys_id on the Qlogic 10Gb driver. Compile tested only. Not sure if set_led_cfg will flash continuously, or needs to be replaced by ETHTOOL_ID_ON/ETHTOOL_ID_OFF Signed-off-by: Stephen Hemminger Signed-off-by: Ron Mercer Signed-off-by: David S. Miller diff --git a/drivers/net/qlge/qlge_ethtool.c b/drivers/net/qlge/qlge_ethtool.c index 8149cc9..687754d 100644 --- a/drivers/net/qlge/qlge_ethtool.c +++ b/drivers/net/qlge/qlge_ethtool.c @@ -412,31 +412,31 @@ static int ql_set_wol(struct net_device *ndev, struct ethtool_wolinfo *wol) return 0; } -static int ql_phys_id(struct net_device *ndev, u32 data) +static int ql_set_phys_id(struct net_device *ndev, + enum ethtool_phys_id_state state) + { struct ql_adapter *qdev = netdev_priv(ndev); - u32 led_reg, i; - int status; - /* Save the current LED settings */ - status = ql_mb_get_led_cfg(qdev); - if (status) - return status; - led_reg = qdev->led_config; + switch (state) { + case ETHTOOL_ID_ACTIVE: + /* Save the current LED settings */ + if (ql_mb_get_led_cfg(qdev)) + return -EIO; - /* Start blinking the led */ - if (!data || data > 300) - data = 300; - - for (i = 0; i < (data * 10); i++) + /* Start blinking */ ql_mb_set_led_cfg(qdev, QL_LED_BLINK); + return 0; - /* Restore LED settings */ - status = ql_mb_set_led_cfg(qdev, led_reg); - if (status) - return status; + case ETHTOOL_ID_INACTIVE: + /* Restore LED settings */ + if (ql_mb_set_led_cfg(qdev, qdev->led_config)) + return -EIO; + return 0; - return 0; + default: + return -EINVAL; + } } static int ql_start_loopback(struct ql_adapter *qdev) @@ -703,7 +703,7 @@ const struct ethtool_ops qlge_ethtool_ops = { .get_msglevel = ql_get_msglevel, .set_msglevel = ql_set_msglevel, .get_link = ethtool_op_get_link, - .phys_id = ql_phys_id, + .set_phys_id = ql_set_phys_id, .self_test = ql_self_test, .get_pauseparam = ql_get_pauseparam, .set_pauseparam = ql_set_pauseparam, -- cgit v0.10.2 From bde3528f17aebb9c74d6b0ef81860868c91af049 Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Fri, 8 Apr 2011 13:45:11 +0000 Subject: gianfar: Clean up implementation of RX network flow classification This code was cribbed from niu, so gfar_set_hash_opts() begins by converting the ethtool flow class code into a class code for Sun Neptune hardware, then does the same thing again for the hardware it's really dealing with. It may also return -1 (-EPERM) for some unhandled ethtool flow class codes. Remove the useless code and definitions, and fix the error code. Signed-off-by: Ben Hutchings Signed-off-by: David S. Miller diff --git a/drivers/net/gianfar.h b/drivers/net/gianfar.h index ec5d595..57ee3b0 100644 --- a/drivers/net/gianfar.h +++ b/drivers/net/gianfar.h @@ -382,23 +382,6 @@ extern const char gfar_driver_version[]; #define BD_LFLAG(flags) ((flags) << 16) #define BD_LENGTH_MASK 0x0000ffff -#define CLASS_CODE_UNRECOG 0x00 -#define CLASS_CODE_DUMMY1 0x01 -#define CLASS_CODE_ETHERTYPE1 0x02 -#define CLASS_CODE_ETHERTYPE2 0x03 -#define CLASS_CODE_USER_PROG1 0x04 -#define CLASS_CODE_USER_PROG2 0x05 -#define CLASS_CODE_USER_PROG3 0x06 -#define CLASS_CODE_USER_PROG4 0x07 -#define CLASS_CODE_TCP_IPV4 0x08 -#define CLASS_CODE_UDP_IPV4 0x09 -#define CLASS_CODE_AH_ESP_IPV4 0x0a -#define CLASS_CODE_SCTP_IPV4 0x0b -#define CLASS_CODE_TCP_IPV6 0x0c -#define CLASS_CODE_UDP_IPV6 0x0d -#define CLASS_CODE_AH_ESP_IPV6 0x0e -#define CLASS_CODE_SCTP_IPV6 0x0f - #define FPR_FILER_MASK 0xFFFFFFFF #define MAX_FILER_IDX 0xFF diff --git a/drivers/net/gianfar_ethtool.c b/drivers/net/gianfar_ethtool.c index 3bc8e27..0840590 100644 --- a/drivers/net/gianfar_ethtool.c +++ b/drivers/net/gianfar_ethtool.c @@ -645,42 +645,6 @@ static int gfar_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol) } #endif -static int gfar_ethflow_to_class(int flow_type, u64 *class) -{ - switch (flow_type) { - case TCP_V4_FLOW: - *class = CLASS_CODE_TCP_IPV4; - break; - case UDP_V4_FLOW: - *class = CLASS_CODE_UDP_IPV4; - break; - case AH_V4_FLOW: - case ESP_V4_FLOW: - *class = CLASS_CODE_AH_ESP_IPV4; - break; - case SCTP_V4_FLOW: - *class = CLASS_CODE_SCTP_IPV4; - break; - case TCP_V6_FLOW: - *class = CLASS_CODE_TCP_IPV6; - break; - case UDP_V6_FLOW: - *class = CLASS_CODE_UDP_IPV6; - break; - case AH_V6_FLOW: - case ESP_V6_FLOW: - *class = CLASS_CODE_AH_ESP_IPV6; - break; - case SCTP_V6_FLOW: - *class = CLASS_CODE_SCTP_IPV6; - break; - default: - return 0; - } - - return 1; -} - static void ethflow_to_filer_rules (struct gfar_private *priv, u64 ethflow) { u32 fcr = 0x0, fpr = FPR_FILER_MASK; @@ -778,11 +742,6 @@ static int gfar_ethflow_to_filer_table(struct gfar_private *priv, u64 ethflow, u case UDP_V6_FLOW: cmp_rqfpr = RQFPR_IPV6 |RQFPR_UDP; break; - case IPV4_FLOW: - cmp_rqfpr = RQFPR_IPV4; - case IPV6_FLOW: - cmp_rqfpr = RQFPR_IPV6; - break; default: printk(KERN_ERR "Right now this class is not supported\n"); return 0; @@ -848,18 +807,9 @@ static int gfar_ethflow_to_filer_table(struct gfar_private *priv, u64 ethflow, u static int gfar_set_hash_opts(struct gfar_private *priv, struct ethtool_rxnfc *cmd) { - u64 class; - - if (!gfar_ethflow_to_class(cmd->flow_type, &class)) - return -EINVAL; - - if (class < CLASS_CODE_USER_PROG1 || - class > CLASS_CODE_SCTP_IPV6) - return -EINVAL; - /* write the filer rules here */ if (!gfar_ethflow_to_filer_table(priv, cmd->data, cmd->flow_type)) - return -1; + return -EINVAL; return 0; } -- cgit v0.10.2 From c44d79950b2daa1025e62eede73e4e4a274d1ef3 Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Fri, 8 Apr 2011 13:49:15 +0000 Subject: niu: Recognise original ethtool class code for AH/ESP flow hashing When the RX network flow classification interface was originally defined for reporting and controlling of flow hashing, AH and ESP were not given distinct flow class codes (apparently because the Sun Neptune hardware treats them very similarly). For flow steering, they must be distinguished, so new and separate flow class codes were added for AH and ESP. But for backward- compatibility, flow hash operations should continue to support the original class codes. Signed-off-by: Ben Hutchings Signed-off-by: David S. Miller diff --git a/drivers/net/niu.c b/drivers/net/niu.c index ab4e7dd..9e6330b 100644 --- a/drivers/net/niu.c +++ b/drivers/net/niu.c @@ -7022,6 +7022,7 @@ static int niu_ethflow_to_class(int flow_type, u64 *class) case UDP_V4_FLOW: *class = CLASS_CODE_UDP_IPV4; break; + case AH_ESP_V4_FLOW: case AH_V4_FLOW: case ESP_V4_FLOW: *class = CLASS_CODE_AH_ESP_IPV4; @@ -7035,6 +7036,7 @@ static int niu_ethflow_to_class(int flow_type, u64 *class) case UDP_V6_FLOW: *class = CLASS_CODE_UDP_IPV6; break; + case AH_ESP_V6_FLOW: case AH_V6_FLOW: case ESP_V6_FLOW: *class = CLASS_CODE_AH_ESP_IPV6; -- cgit v0.10.2 From 90db8ece6a3150228c46aaf1a0f6388bf7434288 Mon Sep 17 00:00:00 2001 From: Lu Guanqun Date: Sat, 9 Apr 2011 23:03:58 +0800 Subject: ASoC: sn95031: decorate function with __devexit_p() According to the comments in include/linux/init.h: "Pointers to __devexit functions must use __devexit_p(function_name), the wrapper will insert either the function_name or NULL, depending on the config options." Fix this issue in codecs sn95031. Signed-off-by: Lu Guanqun Acked-by: Liam Girdwood Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/sn95031.c b/sound/soc/codecs/sn95031.c index 2a30eae..f74d497 100644 --- a/sound/soc/codecs/sn95031.c +++ b/sound/soc/codecs/sn95031.c @@ -925,7 +925,7 @@ static struct platform_driver sn95031_codec_driver = { .owner = THIS_MODULE, }, .probe = sn95031_device_probe, - .remove = sn95031_device_remove, + .remove = __devexit_p(sn95031_device_remove), }; static int __init sn95031_init(void) -- cgit v0.10.2 From 39cca168bdfaef9d0c496ec27f292445d6184946 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Fri, 8 Apr 2011 16:32:16 +0900 Subject: ASoC: Fix output PGA enabling in wm_hubs CODECs The output PGA was not being powered up in headphone and speaker paths, removing the ability to offer volume control and mute with the output PGA. Signed-off-by: Mark Brown Acked-by: Liam Girdwood Cc: stable@kernel.org diff --git a/sound/soc/codecs/wm_hubs.c b/sound/soc/codecs/wm_hubs.c index 7b6b3c1..4005e9a 100644 --- a/sound/soc/codecs/wm_hubs.c +++ b/sound/soc/codecs/wm_hubs.c @@ -740,12 +740,12 @@ static const struct snd_soc_dapm_route analogue_routes[] = { { "SPKL", "Input Switch", "MIXINL" }, { "SPKL", "IN1LP Switch", "IN1LP" }, - { "SPKL", "Output Switch", "Left Output Mixer" }, + { "SPKL", "Output Switch", "Left Output PGA" }, { "SPKL", NULL, "TOCLK" }, { "SPKR", "Input Switch", "MIXINR" }, { "SPKR", "IN1RP Switch", "IN1RP" }, - { "SPKR", "Output Switch", "Right Output Mixer" }, + { "SPKR", "Output Switch", "Right Output PGA" }, { "SPKR", NULL, "TOCLK" }, { "SPKL Boost", "Direct Voice Switch", "Direct Voice" }, @@ -767,8 +767,8 @@ static const struct snd_soc_dapm_route analogue_routes[] = { { "SPKOUTRP", NULL, "SPKR Driver" }, { "SPKOUTRN", NULL, "SPKR Driver" }, - { "Left Headphone Mux", "Mixer", "Left Output Mixer" }, - { "Right Headphone Mux", "Mixer", "Right Output Mixer" }, + { "Left Headphone Mux", "Mixer", "Left Output PGA" }, + { "Right Headphone Mux", "Mixer", "Right Output PGA" }, { "Headphone PGA", NULL, "Left Headphone Mux" }, { "Headphone PGA", NULL, "Right Headphone Mux" }, -- cgit v0.10.2 From 73d6ac633c6c0ca703f90db0b808d9593e46aef6 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Mon, 11 Apr 2011 10:43:50 +0000 Subject: caif: code cleanup MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Cleanup of new CAIF code. * make local functions static * remove code that is never used * expand get_caif_conf() since wrapper is no longer needed * make args to comparison functions const * rename connect_req_to_link_param to keep exported names consistent Compile tested only. Signed-off-by: Stephen Hemminger Acked-by: Sjur Brændeland Signed-off-by: David S. Miller diff --git a/include/net/caif/caif_dev.h b/include/net/caif/caif_dev.h index 8eff83b..7e3f7a6 100644 --- a/include/net/caif/caif_dev.h +++ b/include/net/caif/caif_dev.h @@ -74,19 +74,8 @@ int caif_connect_client(struct caif_connect_request *conn_req, int caif_disconnect_client(struct cflayer *client_layer); /** - * caif_release_client - Release adaptation layer reference to client. - * - * @client_layer: Client layer. - * - * Releases a client/adaptation layer use of the caif stack. - * This function must be used after caif_disconnect_client to - * decrease the reference count of the service layer. - */ -void caif_release_client(struct cflayer *client_layer); - -/** - * connect_req_to_link_param - Translate configuration parameters - * from socket format to internal format. + * caif_connect_req_to_link_param - Translate configuration parameters + * from socket format to internal format. * @cnfg: Pointer to configuration handler * @con_req: Configuration parameters supplied in function * caif_connect_client @@ -94,14 +83,8 @@ void caif_release_client(struct cflayer *client_layer); * setting up channels. * */ -int connect_req_to_link_param(struct cfcnfg *cnfg, - struct caif_connect_request *con_req, - struct cfctrl_link_param *channel_setup_param); - -/** - * get_caif_conf() - Get the configuration handler. - */ -struct cfcnfg *get_caif_conf(void); - +int caif_connect_req_to_link_param(struct cfcnfg *cnfg, + struct caif_connect_request *con_req, + struct cfctrl_link_param *setup_param); #endif /* CAIF_DEV_H_ */ diff --git a/include/net/caif/cfctrl.h b/include/net/caif/cfctrl.h index e54f639..d84416f 100644 --- a/include/net/caif/cfctrl.h +++ b/include/net/caif/cfctrl.h @@ -121,19 +121,9 @@ int cfctrl_linkup_request(struct cflayer *cfctrl, struct cflayer *user_layer); int cfctrl_linkdown_req(struct cflayer *cfctrl, u8 linkid, struct cflayer *client); -void cfctrl_sleep_req(struct cflayer *cfctrl); -void cfctrl_wake_req(struct cflayer *cfctrl); -void cfctrl_getstartreason_req(struct cflayer *cfctrl); + struct cflayer *cfctrl_create(void); -void cfctrl_set_dnlayer(struct cflayer *this, struct cflayer *dn); -void cfctrl_set_uplayer(struct cflayer *this, struct cflayer *up); struct cfctrl_rsp *cfctrl_get_respfuncs(struct cflayer *layer); -bool cfctrl_req_eq(struct cfctrl_request_info *r1, - struct cfctrl_request_info *r2); -void cfctrl_insert_req(struct cfctrl *ctrl, - struct cfctrl_request_info *req); -struct cfctrl_request_info *cfctrl_remove_req(struct cfctrl *ctrl, - struct cfctrl_request_info *req); void cfctrl_cancel_req(struct cflayer *layr, struct cflayer *adap_layer); #endif /* CFCTRL_H_ */ diff --git a/include/net/caif/cfmuxl.h b/include/net/caif/cfmuxl.h index 4e1b4f3..5847a19 100644 --- a/include/net/caif/cfmuxl.h +++ b/include/net/caif/cfmuxl.h @@ -16,7 +16,5 @@ int cfmuxl_set_uplayer(struct cflayer *layr, struct cflayer *up, u8 linkid); struct cflayer *cfmuxl_remove_dnlayer(struct cflayer *layr, u8 phyid); int cfmuxl_set_dnlayer(struct cflayer *layr, struct cflayer *up, u8 phyid); struct cflayer *cfmuxl_remove_uplayer(struct cflayer *layr, u8 linkid); -bool cfmuxl_is_phy_inuse(struct cflayer *layr, u8 phyid); -u8 cfmuxl_get_phyid(struct cflayer *layr, u8 channel_id); #endif /* CFMUXL_H_ */ diff --git a/include/net/caif/cfpkt.h b/include/net/caif/cfpkt.h index fbc681b..8b550f8 100644 --- a/include/net/caif/cfpkt.h +++ b/include/net/caif/cfpkt.h @@ -16,12 +16,6 @@ struct cfpkt; */ struct cfpkt *cfpkt_create(u16 len); -/* Create a CAIF packet. - * data Data to copy. - * len Length of packet to be created - * @return New packet. - */ -struct cfpkt *cfpkt_create_uplink(const unsigned char *data, unsigned int len); /* * Destroy a CAIF Packet. * pkt Packet to be destoyed. @@ -181,22 +175,6 @@ u16 cfpkt_iterate(struct cfpkt *pkt, u16 (*iter_func)(u16 chks, void *buf, u16 len), u16 data); -/* Append by giving user access to packet buffer - * cfpkt Packet to append to - * buf Buffer inside pkt that user shall copy data into - * buflen Length of buffer and number of bytes added to packet - * @return 0 on error, 1 on success - */ -int cfpkt_raw_append(struct cfpkt *cfpkt, void **buf, unsigned int buflen); - -/* Extract by giving user access to packet buffer - * cfpkt Packet to extract from - * buf Buffer inside pkt that user shall copy data from - * buflen Length of buffer and number of bytes removed from packet - * @return 0 on error, 1 on success - */ -int cfpkt_raw_extract(struct cfpkt *cfpkt, void **buf, unsigned int buflen); - /* Map from a "native" packet (e.g. Linux Socket Buffer) to a CAIF packet. * dir - Direction indicating whether this packet is to be sent or received. * nativepkt - The native packet to be transformed to a CAIF packet @@ -210,59 +188,6 @@ struct cfpkt *cfpkt_fromnative(enum caif_direction dir, void *nativepkt); */ void *cfpkt_tonative(struct cfpkt *pkt); -/* - * Insert a packet in the packet queue. - * pktq Packet queue to insert into - * pkt Packet to be inserted in queue - * prio Priority of packet - */ -void cfpkt_queue(struct cfpktq *pktq, struct cfpkt *pkt, - unsigned short prio); - -/* - * Remove a packet from the packet queue. - * pktq Packet queue to fetch packets from. - * @return Dequeued packet. - */ -struct cfpkt *cfpkt_dequeue(struct cfpktq *pktq); - -/* - * Peek into a packet from the packet queue. - * pktq Packet queue to fetch packets from. - * @return Peeked packet. - */ -struct cfpkt *cfpkt_qpeek(struct cfpktq *pktq); - -/* - * Initiates the packet queue. - * @return Pointer to new packet queue. - */ -struct cfpktq *cfpktq_create(void); - -/* - * Get the number of packets in the queue. - * pktq Packet queue to fetch count from. - * @return Number of packets in queue. - */ -int cfpkt_qcount(struct cfpktq *pktq); - -/* - * Put content of packet into buffer for debuging purposes. - * pkt Packet to copy data from - * buf Buffer to copy data into - * buflen Length of data to copy - * @return Pointer to copied data - */ -char *cfpkt_log_pkt(struct cfpkt *pkt, char *buf, int buflen); - -/* - * Clones a packet and releases the original packet. - * This is used for taking ownership of a packet e.g queueing. - * pkt Packet to clone and release. - * @return Cloned packet. - */ -struct cfpkt *cfpkt_clone_release(struct cfpkt *pkt); - /* * Returns packet information for a packet. diff --git a/include/net/caif/cfsrvl.h b/include/net/caif/cfsrvl.h index b1fa87e..6c8279c 100644 --- a/include/net/caif/cfsrvl.h +++ b/include/net/caif/cfsrvl.h @@ -22,7 +22,6 @@ struct cfsrvl { struct kref ref; }; -void cfsrvl_release(struct kref *kref); struct cflayer *cfvei_create(u8 linkid, struct dev_info *dev_info); struct cflayer *cfdgml_create(u8 linkid, struct dev_info *dev_info); struct cflayer *cfutill_create(u8 linkid, struct dev_info *dev_info); @@ -31,7 +30,7 @@ struct cflayer *cfrfml_create(u8 linkid, struct dev_info *dev_info, int mtu_size); struct cflayer *cfdbgl_create(u8 linkid, struct dev_info *dev_info); bool cfsrvl_phyid_match(struct cflayer *layer, int phyid); -void cfservl_destroy(struct cflayer *layer); + void cfsrvl_init(struct cfsrvl *service, u8 channel_id, struct dev_info *dev_info, diff --git a/net/caif/caif_config_util.c b/net/caif/caif_config_util.c index d522d8c..9b63e4e 100644 --- a/net/caif/caif_config_util.c +++ b/net/caif/caif_config_util.c @@ -10,9 +10,9 @@ #include #include -int connect_req_to_link_param(struct cfcnfg *cnfg, - struct caif_connect_request *s, - struct cfctrl_link_param *l) +int caif_connect_req_to_link_param(struct cfcnfg *cnfg, + struct caif_connect_request *s, + struct cfctrl_link_param *l) { struct dev_info *dev_info; enum cfcnfg_phy_preference pref; diff --git a/net/caif/caif_dev.c b/net/caif/caif_dev.c index a42a408..b533bb0 100644 --- a/net/caif/caif_dev.c +++ b/net/caif/caif_dev.c @@ -257,7 +257,7 @@ static int caif_device_notify(struct notifier_block *me, unsigned long what, break; } dev_hold(dev); - cfcnfg_add_phy_layer(get_caif_conf(), + cfcnfg_add_phy_layer(cfg, phy_type, dev, &caifd->layer, @@ -300,7 +300,7 @@ static int caif_device_notify(struct notifier_block *me, unsigned long what, if (atomic_read(&caifd->in_use)) netdev_warn(dev, "Unregistering an active CAIF device\n"); - cfcnfg_del_phy_layer(get_caif_conf(), &caifd->layer); + cfcnfg_del_phy_layer(cfg, &caifd->layer); dev_put(dev); atomic_set(&caifd->state, what); break; @@ -322,24 +322,18 @@ static struct notifier_block caif_device_notifier = { .priority = 0, }; - -struct cfcnfg *get_caif_conf(void) -{ - return cfg; -} -EXPORT_SYMBOL(get_caif_conf); - int caif_connect_client(struct caif_connect_request *conn_req, struct cflayer *client_layer, int *ifindex, int *headroom, int *tailroom) { struct cfctrl_link_param param; int ret; - ret = connect_req_to_link_param(get_caif_conf(), conn_req, ¶m); + + ret = caif_connect_req_to_link_param(cfg, conn_req, ¶m); if (ret) return ret; /* Hook up the adaptation layer. */ - return cfcnfg_add_adaptation_layer(get_caif_conf(), ¶m, + return cfcnfg_add_adaptation_layer(cfg, ¶m, client_layer, ifindex, headroom, tailroom); } @@ -347,16 +341,10 @@ EXPORT_SYMBOL(caif_connect_client); int caif_disconnect_client(struct cflayer *adap_layer) { - return cfcnfg_disconn_adapt_layer(get_caif_conf(), adap_layer); + return cfcnfg_disconn_adapt_layer(cfg, adap_layer); } EXPORT_SYMBOL(caif_disconnect_client); -void caif_release_client(struct cflayer *adap_layer) -{ - cfcnfg_release_adap_layer(adap_layer); -} -EXPORT_SYMBOL(caif_release_client); - /* Per-namespace Caif devices handling */ static int caif_init_net(struct net *net) { diff --git a/net/caif/cfcnfg.c b/net/caif/cfcnfg.c index f1f98d9..25c0b19 100644 --- a/net/caif/cfcnfg.c +++ b/net/caif/cfcnfg.c @@ -253,7 +253,7 @@ static void cfcnfg_linkdestroy_rsp(struct cflayer *layer, u8 channel_id) { } -int protohead[CFCTRL_SRV_MASK] = { +static const int protohead[CFCTRL_SRV_MASK] = { [CFCTRL_SRV_VEI] = 4, [CFCTRL_SRV_DATAGRAM] = 7, [CFCTRL_SRV_UTIL] = 4, diff --git a/net/caif/cfctrl.c b/net/caif/cfctrl.c index 3cd8f97..397a2c0 100644 --- a/net/caif/cfctrl.c +++ b/net/caif/cfctrl.c @@ -58,7 +58,8 @@ struct cflayer *cfctrl_create(void) return &this->serv.layer; } -static bool param_eq(struct cfctrl_link_param *p1, struct cfctrl_link_param *p2) +static bool param_eq(const struct cfctrl_link_param *p1, + const struct cfctrl_link_param *p2) { bool eq = p1->linktype == p2->linktype && @@ -100,8 +101,8 @@ static bool param_eq(struct cfctrl_link_param *p1, struct cfctrl_link_param *p2) return false; } -bool cfctrl_req_eq(struct cfctrl_request_info *r1, - struct cfctrl_request_info *r2) +static bool cfctrl_req_eq(const struct cfctrl_request_info *r1, + const struct cfctrl_request_info *r2) { if (r1->cmd != r2->cmd) return false; @@ -112,7 +113,7 @@ bool cfctrl_req_eq(struct cfctrl_request_info *r1, } /* Insert request at the end */ -void cfctrl_insert_req(struct cfctrl *ctrl, +static void cfctrl_insert_req(struct cfctrl *ctrl, struct cfctrl_request_info *req) { spin_lock(&ctrl->info_list_lock); @@ -123,8 +124,8 @@ void cfctrl_insert_req(struct cfctrl *ctrl, } /* Compare and remove request */ -struct cfctrl_request_info *cfctrl_remove_req(struct cfctrl *ctrl, - struct cfctrl_request_info *req) +static struct cfctrl_request_info *cfctrl_remove_req(struct cfctrl *ctrl, + struct cfctrl_request_info *req) { struct cfctrl_request_info *p, *tmp, *first; @@ -154,16 +155,6 @@ struct cfctrl_rsp *cfctrl_get_respfuncs(struct cflayer *layer) return &this->res; } -void cfctrl_set_dnlayer(struct cflayer *this, struct cflayer *dn) -{ - this->dn = dn; -} - -void cfctrl_set_uplayer(struct cflayer *this, struct cflayer *up) -{ - this->up = up; -} - static void init_info(struct caif_payload_info *info, struct cfctrl *cfctrl) { info->hdr_len = 0; @@ -304,58 +295,6 @@ int cfctrl_linkdown_req(struct cflayer *layer, u8 channelid, return ret; } -void cfctrl_sleep_req(struct cflayer *layer) -{ - int ret; - struct cfctrl *cfctrl = container_obj(layer); - struct cfpkt *pkt = cfpkt_create(CFPKT_CTRL_PKT_LEN); - if (!pkt) { - pr_warn("Out of memory\n"); - return; - } - cfpkt_addbdy(pkt, CFCTRL_CMD_SLEEP); - init_info(cfpkt_info(pkt), cfctrl); - ret = - cfctrl->serv.layer.dn->transmit(cfctrl->serv.layer.dn, pkt); - if (ret < 0) - cfpkt_destroy(pkt); -} - -void cfctrl_wake_req(struct cflayer *layer) -{ - int ret; - struct cfctrl *cfctrl = container_obj(layer); - struct cfpkt *pkt = cfpkt_create(CFPKT_CTRL_PKT_LEN); - if (!pkt) { - pr_warn("Out of memory\n"); - return; - } - cfpkt_addbdy(pkt, CFCTRL_CMD_WAKE); - init_info(cfpkt_info(pkt), cfctrl); - ret = - cfctrl->serv.layer.dn->transmit(cfctrl->serv.layer.dn, pkt); - if (ret < 0) - cfpkt_destroy(pkt); -} - -void cfctrl_getstartreason_req(struct cflayer *layer) -{ - int ret; - struct cfctrl *cfctrl = container_obj(layer); - struct cfpkt *pkt = cfpkt_create(CFPKT_CTRL_PKT_LEN); - if (!pkt) { - pr_warn("Out of memory\n"); - return; - } - cfpkt_addbdy(pkt, CFCTRL_CMD_START_REASON); - init_info(cfpkt_info(pkt), cfctrl); - ret = - cfctrl->serv.layer.dn->transmit(cfctrl->serv.layer.dn, pkt); - if (ret < 0) - cfpkt_destroy(pkt); -} - - void cfctrl_cancel_req(struct cflayer *layr, struct cflayer *adap_layer) { struct cfctrl_request_info *p, *tmp; diff --git a/net/caif/cfmuxl.c b/net/caif/cfmuxl.c index 24f1ffa..f8ce0f3 100644 --- a/net/caif/cfmuxl.c +++ b/net/caif/cfmuxl.c @@ -71,41 +71,6 @@ int cfmuxl_set_uplayer(struct cflayer *layr, struct cflayer *up, u8 linkid) return 0; } -bool cfmuxl_is_phy_inuse(struct cflayer *layr, u8 phyid) -{ - struct list_head *node; - struct cflayer *layer; - struct cfmuxl *muxl = container_obj(layr); - bool match = false; - spin_lock(&muxl->receive_lock); - - list_for_each(node, &muxl->srvl_list) { - layer = list_entry(node, struct cflayer, node); - if (cfsrvl_phyid_match(layer, phyid)) { - match = true; - break; - } - - } - spin_unlock(&muxl->receive_lock); - return match; -} - -u8 cfmuxl_get_phyid(struct cflayer *layr, u8 channel_id) -{ - struct cflayer *up; - int phyid; - struct cfmuxl *muxl = container_obj(layr); - spin_lock(&muxl->receive_lock); - up = get_up(muxl, channel_id); - if (up != NULL) - phyid = cfsrvl_getphyid(up); - else - phyid = 0; - spin_unlock(&muxl->receive_lock); - return phyid; -} - int cfmuxl_set_dnlayer(struct cflayer *layr, struct cflayer *dn, u8 phyid) { struct cfmuxl *muxl = (struct cfmuxl *) layr; diff --git a/net/caif/cfpkt_skbuff.c b/net/caif/cfpkt_skbuff.c index d7e865e..20c6cb3 100644 --- a/net/caif/cfpkt_skbuff.c +++ b/net/caif/cfpkt_skbuff.c @@ -42,22 +42,22 @@ struct cfpkt_priv_data { bool erronous; }; -inline struct cfpkt_priv_data *cfpkt_priv(struct cfpkt *pkt) +static inline struct cfpkt_priv_data *cfpkt_priv(struct cfpkt *pkt) { return (struct cfpkt_priv_data *) pkt->skb.cb; } -inline bool is_erronous(struct cfpkt *pkt) +static inline bool is_erronous(struct cfpkt *pkt) { return cfpkt_priv(pkt)->erronous; } -inline struct sk_buff *pkt_to_skb(struct cfpkt *pkt) +static inline struct sk_buff *pkt_to_skb(struct cfpkt *pkt) { return &pkt->skb; } -inline struct cfpkt *skb_to_pkt(struct sk_buff *skb) +static inline struct cfpkt *skb_to_pkt(struct sk_buff *skb) { return (struct cfpkt *) skb; } @@ -317,17 +317,6 @@ int cfpkt_setlen(struct cfpkt *pkt, u16 len) } EXPORT_SYMBOL(cfpkt_setlen); -struct cfpkt *cfpkt_create_uplink(const unsigned char *data, unsigned int len) -{ - struct cfpkt *pkt = cfpkt_create_pfx(len + PKT_POSTFIX, PKT_PREFIX); - if (!pkt) - return NULL; - if (unlikely(data != NULL)) - cfpkt_add_body(pkt, data, len); - return pkt; -} -EXPORT_SYMBOL(cfpkt_create_uplink); - struct cfpkt *cfpkt_append(struct cfpkt *dstpkt, struct cfpkt *addpkt, u16 expectlen) @@ -408,169 +397,12 @@ struct cfpkt *cfpkt_split(struct cfpkt *pkt, u16 pos) } EXPORT_SYMBOL(cfpkt_split); -char *cfpkt_log_pkt(struct cfpkt *pkt, char *buf, int buflen) -{ - struct sk_buff *skb = pkt_to_skb(pkt); - char *p = buf; - int i; - - /* - * Sanity check buffer length, it needs to be at least as large as - * the header info: ~=50+ bytes - */ - if (buflen < 50) - return NULL; - - snprintf(buf, buflen, "%s: pkt:%p len:%ld(%ld+%ld) {%ld,%ld} data: [", - is_erronous(pkt) ? "ERRONOUS-SKB" : - (skb->data_len != 0 ? "COMPLEX-SKB" : "SKB"), - skb, - (long) skb->len, - (long) (skb_tail_pointer(skb) - skb->data), - (long) skb->data_len, - (long) (skb->data - skb->head), - (long) (skb_tail_pointer(skb) - skb->head)); - p = buf + strlen(buf); - - for (i = 0; i < skb_tail_pointer(skb) - skb->data && i < 300; i++) { - if (p > buf + buflen - 10) { - sprintf(p, "..."); - p = buf + strlen(buf); - break; - } - sprintf(p, "%02x,", skb->data[i]); - p = buf + strlen(buf); - } - sprintf(p, "]\n"); - return buf; -} -EXPORT_SYMBOL(cfpkt_log_pkt); - -int cfpkt_raw_append(struct cfpkt *pkt, void **buf, unsigned int buflen) -{ - struct sk_buff *skb = pkt_to_skb(pkt); - struct sk_buff *lastskb; - - caif_assert(buf != NULL); - if (unlikely(is_erronous(pkt))) - return -EPROTO; - /* Make sure SKB is writable */ - if (unlikely(skb_cow_data(skb, 0, &lastskb) < 0)) { - PKT_ERROR(pkt, "skb_cow_data failed\n"); - return -EPROTO; - } - - if (unlikely(skb_linearize(skb) != 0)) { - PKT_ERROR(pkt, "linearize failed\n"); - return -EPROTO; - } - - if (unlikely(skb_tailroom(skb) < buflen)) { - PKT_ERROR(pkt, "buffer too short - failed\n"); - return -EPROTO; - } - - *buf = skb_put(skb, buflen); - return 1; -} -EXPORT_SYMBOL(cfpkt_raw_append); - -int cfpkt_raw_extract(struct cfpkt *pkt, void **buf, unsigned int buflen) -{ - struct sk_buff *skb = pkt_to_skb(pkt); - - caif_assert(buf != NULL); - if (unlikely(is_erronous(pkt))) - return -EPROTO; - - if (unlikely(buflen > skb->len)) { - PKT_ERROR(pkt, "buflen too large - failed\n"); - return -EPROTO; - } - - if (unlikely(buflen > skb_headlen(skb))) { - if (unlikely(skb_linearize(skb) != 0)) { - PKT_ERROR(pkt, "linearize failed\n"); - return -EPROTO; - } - } - - *buf = skb->data; - skb_pull(skb, buflen); - - return 1; -} -EXPORT_SYMBOL(cfpkt_raw_extract); - -inline bool cfpkt_erroneous(struct cfpkt *pkt) +bool cfpkt_erroneous(struct cfpkt *pkt) { return cfpkt_priv(pkt)->erronous; } EXPORT_SYMBOL(cfpkt_erroneous); -struct cfpktq *cfpktq_create(void) -{ - struct cfpktq *q = kmalloc(sizeof(struct cfpktq), GFP_ATOMIC); - if (!q) - return NULL; - skb_queue_head_init(&q->head); - atomic_set(&q->count, 0); - spin_lock_init(&q->lock); - return q; -} -EXPORT_SYMBOL(cfpktq_create); - -void cfpkt_queue(struct cfpktq *pktq, struct cfpkt *pkt, unsigned short prio) -{ - atomic_inc(&pktq->count); - spin_lock(&pktq->lock); - skb_queue_tail(&pktq->head, pkt_to_skb(pkt)); - spin_unlock(&pktq->lock); - -} -EXPORT_SYMBOL(cfpkt_queue); - -struct cfpkt *cfpkt_qpeek(struct cfpktq *pktq) -{ - struct cfpkt *tmp; - spin_lock(&pktq->lock); - tmp = skb_to_pkt(skb_peek(&pktq->head)); - spin_unlock(&pktq->lock); - return tmp; -} -EXPORT_SYMBOL(cfpkt_qpeek); - -struct cfpkt *cfpkt_dequeue(struct cfpktq *pktq) -{ - struct cfpkt *pkt; - spin_lock(&pktq->lock); - pkt = skb_to_pkt(skb_dequeue(&pktq->head)); - if (pkt) { - atomic_dec(&pktq->count); - caif_assert(atomic_read(&pktq->count) >= 0); - } - spin_unlock(&pktq->lock); - return pkt; -} -EXPORT_SYMBOL(cfpkt_dequeue); - -int cfpkt_qcount(struct cfpktq *pktq) -{ - return atomic_read(&pktq->count); -} -EXPORT_SYMBOL(cfpkt_qcount); - -struct cfpkt *cfpkt_clone_release(struct cfpkt *pkt) -{ - struct cfpkt *clone; - clone = skb_to_pkt(skb_clone(pkt_to_skb(pkt), GFP_ATOMIC)); - /* Free original packet. */ - cfpkt_destroy(pkt); - if (!clone) - return NULL; - return clone; -} -EXPORT_SYMBOL(cfpkt_clone_release); struct caif_payload_info *cfpkt_info(struct cfpkt *pkt) { diff --git a/net/caif/cfsrvl.c b/net/caif/cfsrvl.c index ab5e542..24ba392 100644 --- a/net/caif/cfsrvl.c +++ b/net/caif/cfsrvl.c @@ -151,12 +151,7 @@ static int cfservl_modemcmd(struct cflayer *layr, enum caif_modemcmd ctrl) return -EINVAL; } -void cfservl_destroy(struct cflayer *layer) -{ - kfree(layer); -} - -void cfsrvl_release(struct kref *kref) +static void cfsrvl_release(struct kref *kref) { struct cfsrvl *service = container_of(kref, struct cfsrvl, ref); kfree(service); -- cgit v0.10.2 From 4dd820c088d201e526840c9dbc2f0b87a0a41868 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sjur=20Br=C3=A6ndeland?= Date: Mon, 11 Apr 2011 10:43:51 +0000 Subject: caif: Don't resend if dev_queue_xmit fails. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit If CAIF Link Layer returns an error, we no longer try to re-build the CAIF packet and resend it. Instead, we simply return any transmission errors to the socket client. Signed-off-by: Sjur Brændeland Signed-off-by: David S. Miller diff --git a/net/caif/caif_dev.c b/net/caif/caif_dev.c index b533bb0..a518fdd 100644 --- a/net/caif/caif_dev.c +++ b/net/caif/caif_dev.c @@ -120,25 +120,12 @@ static int transmit(struct cflayer *layer, struct cfpkt *pkt) { struct caif_device_entry *caifd = container_of(layer, struct caif_device_entry, layer); - struct sk_buff *skb, *skb2; - int ret = -EINVAL; + struct sk_buff *skb; + skb = cfpkt_tonative(pkt); skb->dev = caifd->netdev; - /* - * Don't allow SKB to be destroyed upon error, but signal resend - * notification to clients. We can't rely on the return value as - * congestion (NET_XMIT_CN) sometimes drops the packet, sometimes don't. - */ - if (netif_queue_stopped(caifd->netdev)) - return -EAGAIN; - skb2 = skb_get(skb); - - ret = dev_queue_xmit(skb2); - - if (!ret) - kfree_skb(skb); - else - return -EAGAIN; + + dev_queue_xmit(skb); return 0; } diff --git a/net/caif/caif_socket.c b/net/caif/caif_socket.c index 37a4034..2021242 100644 --- a/net/caif/caif_socket.c +++ b/net/caif/caif_socket.c @@ -519,43 +519,14 @@ static int transmit_skb(struct sk_buff *skb, struct caifsock *cf_sk, int noblock, long timeo) { struct cfpkt *pkt; - int ret, loopcnt = 0; pkt = cfpkt_fromnative(CAIF_DIR_OUT, skb); memset(cfpkt_info(pkt), 0, sizeof(struct caif_payload_info)); - do { - - ret = -ETIMEDOUT; - /* Slight paranoia, probably not needed. */ - if (unlikely(loopcnt++ > 1000)) { - pr_warn("transmit retries failed, error = %d\n", ret); - break; - } + if (cf_sk->layer.dn == NULL) + return -EINVAL; - if (cf_sk->layer.dn != NULL) - ret = cf_sk->layer.dn->transmit(cf_sk->layer.dn, pkt); - if (likely(ret >= 0)) - break; - /* if transmit return -EAGAIN, then retry */ - if (noblock && ret == -EAGAIN) - break; - timeo = caif_wait_for_flow_on(cf_sk, 0, timeo, &ret); - if (signal_pending(current)) { - ret = sock_intr_errno(timeo); - break; - } - if (ret) - break; - if (cf_sk->sk.sk_state != CAIF_CONNECTED || - sock_flag(&cf_sk->sk, SOCK_DEAD) || - (cf_sk->sk.sk_shutdown & RCV_SHUTDOWN)) { - ret = -EPIPE; - cf_sk->sk.sk_err = EPIPE; - break; - } - } while (ret == -EAGAIN); - return ret; + return cf_sk->layer.dn->transmit(cf_sk->layer.dn, pkt); } /* Copied from af_unix:unix_dgram_sendmsg, and adapted to CAIF */ diff --git a/net/caif/cfdgml.c b/net/caif/cfdgml.c index 054fdb5..0382dec 100644 --- a/net/caif/cfdgml.c +++ b/net/caif/cfdgml.c @@ -108,10 +108,5 @@ static int cfdgml_transmit(struct cflayer *layr, struct cfpkt *pkt) */ info->hdr_len = 4; info->dev_info = &service->dev_info; - ret = layr->dn->transmit(layr->dn, pkt); - if (ret < 0) { - u32 tmp32; - cfpkt_extr_head(pkt, &tmp32, 4); - } - return ret; + return layr->dn->transmit(layr->dn, pkt); } diff --git a/net/caif/cffrml.c b/net/caif/cffrml.c index a445043..2423fed 100644 --- a/net/caif/cffrml.c +++ b/net/caif/cffrml.c @@ -120,7 +120,6 @@ static int cffrml_transmit(struct cflayer *layr, struct cfpkt *pkt) int tmp; u16 chks; u16 len; - int ret; struct cffrml *this = container_obj(layr); if (this->dofcs) { chks = cfpkt_iterate(pkt, cffrml_checksum, 0xffff); @@ -137,12 +136,7 @@ static int cffrml_transmit(struct cflayer *layr, struct cfpkt *pkt) pr_err("Packet is erroneous!\n"); return -EPROTO; } - ret = layr->dn->transmit(layr->dn, pkt); - if (ret < 0) { - /* Remove header on faulty packet. */ - cfpkt_extr_head(pkt, &tmp, 2); - } - return ret; + return layr->dn->transmit(layr->dn, pkt); } static void cffrml_ctrlcmd(struct cflayer *layr, enum caif_ctrlcmd ctrl, diff --git a/net/caif/cfmuxl.c b/net/caif/cfmuxl.c index f8ce0f3..ebfda2c 100644 --- a/net/caif/cfmuxl.c +++ b/net/caif/cfmuxl.c @@ -184,7 +184,6 @@ static int cfmuxl_receive(struct cflayer *layr, struct cfpkt *pkt) static int cfmuxl_transmit(struct cflayer *layr, struct cfpkt *pkt) { - int ret; struct cfmuxl *muxl = container_obj(layr); u8 linkid; struct cflayer *dn; @@ -198,11 +197,7 @@ static int cfmuxl_transmit(struct cflayer *layr, struct cfpkt *pkt) info->hdr_len += 1; linkid = info->channel_id; cfpkt_add_head(pkt, &linkid, 1); - ret = dn->transmit(dn, pkt); - /* Remove MUX protocol header upon error. */ - if (ret < 0) - cfpkt_extr_head(pkt, &linkid, 1); - return ret; + return dn->transmit(dn, pkt); } static void cfmuxl_ctrlcmd(struct cflayer *layr, enum caif_ctrlcmd ctrl, diff --git a/net/caif/cfserl.c b/net/caif/cfserl.c index 8303fe3..2715c84 100644 --- a/net/caif/cfserl.c +++ b/net/caif/cfserl.c @@ -179,15 +179,10 @@ static int cfserl_receive(struct cflayer *l, struct cfpkt *newpkt) static int cfserl_transmit(struct cflayer *layer, struct cfpkt *newpkt) { struct cfserl *layr = container_obj(layer); - int ret; u8 tmp8 = CFSERL_STX; if (layr->usestx) cfpkt_add_head(newpkt, &tmp8, 1); - ret = layer->dn->transmit(layer->dn, newpkt); - if (ret < 0) - cfpkt_extr_head(newpkt, &tmp8, 1); - - return ret; + return layer->dn->transmit(layer->dn, newpkt); } static void cfserl_ctrlcmd(struct cflayer *layr, enum caif_ctrlcmd ctrl, diff --git a/net/caif/cfutill.c b/net/caif/cfutill.c index 315c0d6..98e027d 100644 --- a/net/caif/cfutill.c +++ b/net/caif/cfutill.c @@ -100,10 +100,5 @@ static int cfutill_transmit(struct cflayer *layr, struct cfpkt *pkt) */ info->hdr_len = 1; info->dev_info = &service->dev_info; - ret = layr->dn->transmit(layr->dn, pkt); - if (ret < 0) { - u32 tmp32; - cfpkt_extr_head(pkt, &tmp32, 4); - } - return ret; + return layr->dn->transmit(layr->dn, pkt); } diff --git a/net/caif/cfveil.c b/net/caif/cfveil.c index c3b1dec..1a588cd 100644 --- a/net/caif/cfveil.c +++ b/net/caif/cfveil.c @@ -96,8 +96,5 @@ static int cfvei_transmit(struct cflayer *layr, struct cfpkt *pkt) info->channel_id = service->layer.id; info->hdr_len = 1; info->dev_info = &service->dev_info; - ret = layr->dn->transmit(layr->dn, pkt); - if (ret < 0) - cfpkt_extr_head(pkt, &tmp, 1); - return ret; + return layr->dn->transmit(layr->dn, pkt); } diff --git a/net/caif/cfvidl.c b/net/caif/cfvidl.c index bf6fef2..b2f5989 100644 --- a/net/caif/cfvidl.c +++ b/net/caif/cfvidl.c @@ -60,8 +60,5 @@ static int cfvidl_transmit(struct cflayer *layr, struct cfpkt *pkt) info = cfpkt_info(pkt); info->channel_id = service->layer.id; info->dev_info = &service->dev_info; - ret = layr->dn->transmit(layr->dn, pkt); - if (ret < 0) - cfpkt_extr_head(pkt, &videoheader, 4); - return ret; + return layr->dn->transmit(layr->dn, pkt); } -- cgit v0.10.2 From 39b9afbb4c0750742eb61b7a015e12f483e0b4a3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sjur=20Br=C3=A6ndeland?= Date: Mon, 11 Apr 2011 10:43:52 +0000 Subject: caif: Add BUG_ON if dev_info is missing in packet MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Sjur Brændeland Signed-off-by: David S. Miller diff --git a/net/caif/cfmuxl.c b/net/caif/cfmuxl.c index ebfda2c..fc24974 100644 --- a/net/caif/cfmuxl.c +++ b/net/caif/cfmuxl.c @@ -188,7 +188,8 @@ static int cfmuxl_transmit(struct cflayer *layr, struct cfpkt *pkt) u8 linkid; struct cflayer *dn; struct caif_payload_info *info = cfpkt_info(pkt); - dn = get_dn(muxl, cfpkt_info(pkt)->dev_info); + BUG_ON(!info); + dn = get_dn(muxl, info->dev_info); if (dn == NULL) { pr_warn("Send data on unknown phy ID = %d (0x%x)\n", info->dev_info->id, info->dev_info->id); -- cgit v0.10.2 From f344c25dbab1a392ef7a7afc8ca061b3b7285423 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Mon, 11 Apr 2011 15:49:26 -0700 Subject: niu: Fix warnings due to -Wunused-but-set-variable Most of these were legitimate, and once case was a real bug (not propagating errors from ->xcvr_init() methods). Signed-off-by: David S. Miller diff --git a/drivers/net/niu.c b/drivers/net/niu.c index 9e6330b..3fa1e9c 100644 --- a/drivers/net/niu.c +++ b/drivers/net/niu.c @@ -1233,7 +1233,7 @@ static int link_status_1g_rgmii(struct niu *np, int *link_up_p) bmsr = err; if (bmsr & BMSR_LSTATUS) { - u16 adv, lpa, common, estat; + u16 adv, lpa; err = mii_read(np, np->phy_addr, MII_ADVERTISE); if (err < 0) @@ -1245,12 +1245,9 @@ static int link_status_1g_rgmii(struct niu *np, int *link_up_p) goto out; lpa = err; - common = adv & lpa; - err = mii_read(np, np->phy_addr, MII_ESTATUS); if (err < 0) goto out; - estat = err; link_up = 1; current_speed = SPEED_1000; current_duplex = DUPLEX_FULL; @@ -1650,7 +1647,7 @@ static int xcvr_init_10g(struct niu *np) break; } - return 0; + return err; } static int mii_reset(struct niu *np) @@ -2381,17 +2378,14 @@ static int serdes_init_10g_serdes(struct niu *np) struct niu_link_config *lp = &np->link_config; unsigned long ctrl_reg, test_cfg_reg, pll_cfg, i; u64 ctrl_val, test_cfg_val, sig, mask, val; - u64 reset_val; switch (np->port) { case 0: - reset_val = ENET_SERDES_RESET_0; ctrl_reg = ENET_SERDES_0_CTRL_CFG; test_cfg_reg = ENET_SERDES_0_TEST_CFG; pll_cfg = ENET_SERDES_0_PLL_CFG; break; case 1: - reset_val = ENET_SERDES_RESET_1; ctrl_reg = ENET_SERDES_1_CTRL_CFG; test_cfg_reg = ENET_SERDES_1_TEST_CFG; pll_cfg = ENET_SERDES_1_PLL_CFG; @@ -8135,7 +8129,7 @@ static int __devinit niu_pci_vpd_scan_props(struct niu *np, netif_printk(np, probe, KERN_DEBUG, np->dev, "VPD_SCAN: start[%x] end[%x]\n", start, end); while (start < end) { - int len, err, instance, type, prop_len; + int len, err, prop_len; char namebuf[64]; u8 *prop_buf; int max_len; @@ -8151,8 +8145,6 @@ static int __devinit niu_pci_vpd_scan_props(struct niu *np, len = err; start += 3; - instance = niu_pci_eeprom_read(np, start); - type = niu_pci_eeprom_read(np, start + 3); prop_len = niu_pci_eeprom_read(np, start + 4); err = niu_pci_vpd_get_propname(np, start + 5, namebuf, 64); if (err < 0) -- cgit v0.10.2 From 8fb27640d0e2b43c5584bf0087431b7b8d3c319a Mon Sep 17 00:00:00 2001 From: Yoshinori Sano Date: Sat, 9 Apr 2011 02:30:07 +0000 Subject: Btrfs: fix memory leaks in btrfs_new_inode() This patch fixes memory leaks in btrfs_new_inode(). Signed-off-by: Yoshinori Sano Signed-off-by: Chris Mason diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c index cc60228..2d1208f 100644 --- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c @@ -4526,14 +4526,17 @@ static struct inode *btrfs_new_inode(struct btrfs_trans_handle *trans, BUG_ON(!path); inode = new_inode(root->fs_info->sb); - if (!inode) + if (!inode) { + btrfs_free_path(path); return ERR_PTR(-ENOMEM); + } if (dir) { trace_btrfs_inode_request(dir); ret = btrfs_set_inode_index(dir, index); if (ret) { + btrfs_free_path(path); iput(inode); return ERR_PTR(ret); } -- cgit v0.10.2 From 3387206f26e1b48703e810175b98611a4fd8e8ea Mon Sep 17 00:00:00 2001 From: Sergei Trofimovich Date: Mon, 11 Apr 2011 21:52:52 +0000 Subject: btrfs: properly handle overlapping areas in memmove_extent_buffer Fix data corruption caused by memcpy() usage on overlapping data. I've observed it first when found out usermode linux crash on btrfs. ?all chain is the following: ------------[ cut here ]------------ WARNING: at /home/slyfox/linux-2.6/fs/btrfs/extent_io.c:3900 memcpy_extent_buffer+0x1a5/0x219() Call Trace: 6fa39a58: [<601b495e>] _raw_spin_unlock_irqrestore+0x18/0x1c 6fa39a68: [<60029ad9>] warn_slowpath_common+0x59/0x70 6fa39aa8: [<60029b05>] warn_slowpath_null+0x15/0x17 6fa39ab8: [<600efc97>] memcpy_extent_buffer+0x1a5/0x219 6fa39b48: [<600efd9f>] memmove_extent_buffer+0x94/0x208 6fa39bc8: [<600becbf>] btrfs_del_items+0x214/0x473 6fa39c78: [<600ce1b0>] btrfs_delete_one_dir_name+0x7c/0xda 6fa39cc8: [<600dad6b>] __btrfs_unlink_inode+0xad/0x25d 6fa39d08: [<600d7864>] btrfs_start_transaction+0xe/0x10 6fa39d48: [<600dc9ff>] btrfs_unlink_inode+0x1b/0x3b 6fa39d78: [<600e04bc>] btrfs_unlink+0x70/0xef 6fa39dc8: [<6007f0d0>] vfs_unlink+0x58/0xa3 6fa39df8: [<60080278>] do_unlinkat+0xd4/0x162 6fa39e48: [<600517db>] call_rcu_sched+0xe/0x10 6fa39e58: [<600452a8>] __put_cred+0x58/0x5a 6fa39e78: [<6007446c>] sys_faccessat+0x154/0x166 6fa39ed8: [<60080317>] sys_unlink+0x11/0x13 6fa39ee8: [<60016b80>] handle_syscall+0x58/0x70 6fa39f08: [<60021377>] userspace+0x2d4/0x381 6fa39fc8: [<60014507>] fork_handler+0x62/0x69 ---[ end trace 70b0ca2ef0266b93 ]--- http://www.mail-archive.com/linux-btrfs@vger.kernel.org/msg09302.html Signed-off-by: Sergei Trofimovich Reviewed-by: Josef Bacik Signed-off-by: Chris Mason diff --git a/fs/btrfs/extent_io.c b/fs/btrfs/extent_io.c index 77c65a0..864e049 100644 --- a/fs/btrfs/extent_io.c +++ b/fs/btrfs/extent_io.c @@ -3885,6 +3885,12 @@ static void move_pages(struct page *dst_page, struct page *src_page, kunmap_atomic(dst_kaddr, KM_USER0); } +static inline bool areas_overlap(unsigned long src, unsigned long dst, unsigned long len) +{ + unsigned long distance = (src > dst) ? src - dst : dst - src; + return distance < len; +} + static void copy_pages(struct page *dst_page, struct page *src_page, unsigned long dst_off, unsigned long src_off, unsigned long len) @@ -3892,10 +3898,12 @@ static void copy_pages(struct page *dst_page, struct page *src_page, char *dst_kaddr = kmap_atomic(dst_page, KM_USER0); char *src_kaddr; - if (dst_page != src_page) + if (dst_page != src_page) { src_kaddr = kmap_atomic(src_page, KM_USER1); - else + } else { src_kaddr = dst_kaddr; + BUG_ON(areas_overlap(src_off, dst_off, len)); + } memcpy(dst_kaddr + dst_off, src_kaddr + src_off, len); kunmap_atomic(dst_kaddr, KM_USER0); @@ -3970,7 +3978,7 @@ void memmove_extent_buffer(struct extent_buffer *dst, unsigned long dst_offset, "len %lu len %lu\n", dst_offset, len, dst->len); BUG_ON(1); } - if (dst_offset < src_offset) { + if (!areas_overlap(src_offset, dst_offset, len)) { memcpy_extent_buffer(dst, dst_offset, src_offset, len); return; } -- cgit v0.10.2 From a1b75f7d961955e697ec377f90115e3517df98f9 Mon Sep 17 00:00:00 2001 From: Josef Bacik Date: Fri, 8 Apr 2011 15:51:18 +0000 Subject: Btrfs: check for duplicate iov_base's when doing dio reads Apparently it is ok to submit a read to an IDE device with the same target page for different offsets. This is what Windows does under qemu. The problem is under DIO we expect them to be different buffers for checksumming reasons, and so this sort of thing will result in checksum errors, when in reality the file is fine. So when reading, check to make sure that all iov bases are different, and if they aren't fall back to buffered mode, since that will work out right. Thanks, Signed-off-by: Josef Bacik Signed-off-by: Chris Mason diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c index 2d1208f..edafc288 100644 --- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c @@ -6153,6 +6153,7 @@ static ssize_t check_direct_IO(struct btrfs_root *root, int rw, struct kiocb *io unsigned long nr_segs) { int seg; + int i; size_t size; unsigned long addr; unsigned blocksize_mask = root->sectorsize - 1; @@ -6167,8 +6168,22 @@ static ssize_t check_direct_IO(struct btrfs_root *root, int rw, struct kiocb *io addr = (unsigned long)iov[seg].iov_base; size = iov[seg].iov_len; end += size; - if ((addr & blocksize_mask) || (size & blocksize_mask)) + if ((addr & blocksize_mask) || (size & blocksize_mask)) goto out; + + /* If this is a write we don't need to check anymore */ + if (rw & WRITE) + continue; + + /* + * Check to make sure we don't have duplicate iov_base's in this + * iovec, if so return EINVAL, otherwise we'll get csum errors + * when reading back. + */ + for (i = seg + 1; i < nr_segs; i++) { + if (iov[seg].iov_base == iov[i].iov_base) + goto out; + } } retval = 0; out: -- cgit v0.10.2 From 13f2696f1da9700d401db0ac2bc27ebc17068b22 Mon Sep 17 00:00:00 2001 From: Daniel J Blueman Date: Mon, 11 Apr 2011 15:56:31 +0000 Subject: fix user annotation in ioctl.c Fix address space annotation correct in ioctl.c. Signed-off-by: Daniel J Blueman BTRFS_BLOCK_GROUP_SYSTEM, @@ -2387,7 +2387,7 @@ long btrfs_ioctl_space_info(struct btrfs_root *root, void __user *arg) up_read(&info->groups_sem); } - user_dest = (struct btrfs_ioctl_space_info *) + user_dest = (struct btrfs_ioctl_space_info __user *) (arg + sizeof(struct btrfs_ioctl_space_args)); if (copy_to_user(user_dest, dest_orig, alloc_size)) Reviewed-by: Josef Bacik Signed-off-by: Chris Mason diff --git a/fs/btrfs/ioctl.c b/fs/btrfs/ioctl.c index f9c93a9..f580a3a 100644 --- a/fs/btrfs/ioctl.c +++ b/fs/btrfs/ioctl.c @@ -2287,7 +2287,7 @@ long btrfs_ioctl_space_info(struct btrfs_root *root, void __user *arg) struct btrfs_ioctl_space_info space; struct btrfs_ioctl_space_info *dest; struct btrfs_ioctl_space_info *dest_orig; - struct btrfs_ioctl_space_info *user_dest; + struct btrfs_ioctl_space_info __user *user_dest; struct btrfs_space_info *info; u64 types[] = {BTRFS_BLOCK_GROUP_DATA, BTRFS_BLOCK_GROUP_SYSTEM, -- cgit v0.10.2 From e15d0542426f063dc53b4c51bdfc11e0bbe4d298 Mon Sep 17 00:00:00 2001 From: Xin Zhong Date: Wed, 6 Apr 2011 07:33:51 +0000 Subject: Btrfs: fix subvolume mount by name problem when default mount subvolume is set We create two subvolumes (meego_root and meego_home) in btrfs root directory. And set meego_root as default mount subvolume. After we remount btrfs, meego_root is mounted to top directory by default. Then when we try to mount meego_home (subvol=meego_home) to a subdirectory, it failed. The problem is when default mount subvolume is set to meego_root, we search meego_home in meego_root but can not find it. So the solution is to add a new mount option (subvolrootid) to specify subvol id of root and search subvol name in it. For our case, now we can use "-o subvolrootid=0,subvol=meego_home) to mount meego_home. Detail information can be found in meego bugzilla: https://bugs.meego.com/show_bug.cgi?id=15055 Signed-off-by: Zhong, Xin Signed-off-by: Chris Mason diff --git a/fs/btrfs/super.c b/fs/btrfs/super.c index 58e7de9..0ac712e 100644 --- a/fs/btrfs/super.c +++ b/fs/btrfs/super.c @@ -159,7 +159,7 @@ enum { Opt_compress_type, Opt_compress_force, Opt_compress_force_type, Opt_notreelog, Opt_ratio, Opt_flushoncommit, Opt_discard, Opt_space_cache, Opt_clear_cache, Opt_user_subvol_rm_allowed, - Opt_enospc_debug, Opt_err, + Opt_enospc_debug, Opt_subvolrootid, Opt_err, }; static match_table_t tokens = { @@ -189,6 +189,7 @@ static match_table_t tokens = { {Opt_clear_cache, "clear_cache"}, {Opt_user_subvol_rm_allowed, "user_subvol_rm_allowed"}, {Opt_enospc_debug, "enospc_debug"}, + {Opt_subvolrootid, "subvolrootid=%d"}, {Opt_err, NULL}, }; @@ -232,6 +233,7 @@ int btrfs_parse_options(struct btrfs_root *root, char *options) break; case Opt_subvol: case Opt_subvolid: + case Opt_subvolrootid: case Opt_device: /* * These are parsed by btrfs_parse_early_options @@ -388,7 +390,7 @@ out: */ static int btrfs_parse_early_options(const char *options, fmode_t flags, void *holder, char **subvol_name, u64 *subvol_objectid, - struct btrfs_fs_devices **fs_devices) + u64 *subvol_rootid, struct btrfs_fs_devices **fs_devices) { substring_t args[MAX_OPT_ARGS]; char *opts, *orig, *p; @@ -429,6 +431,18 @@ static int btrfs_parse_early_options(const char *options, fmode_t flags, *subvol_objectid = intarg; } break; + case Opt_subvolrootid: + intarg = 0; + error = match_int(&args[0], &intarg); + if (!error) { + /* we want the original fs_tree */ + if (!intarg) + *subvol_rootid = + BTRFS_FS_TREE_OBJECTID; + else + *subvol_rootid = intarg; + } + break; case Opt_device: error = btrfs_scan_one_device(match_strdup(&args[0]), flags, holder, fs_devices); @@ -736,6 +750,7 @@ static struct dentry *btrfs_mount(struct file_system_type *fs_type, int flags, fmode_t mode = FMODE_READ; char *subvol_name = NULL; u64 subvol_objectid = 0; + u64 subvol_rootid = 0; int error = 0; if (!(flags & MS_RDONLY)) @@ -743,7 +758,7 @@ static struct dentry *btrfs_mount(struct file_system_type *fs_type, int flags, error = btrfs_parse_early_options(data, mode, fs_type, &subvol_name, &subvol_objectid, - &fs_devices); + &subvol_rootid, &fs_devices); if (error) return ERR_PTR(error); @@ -807,15 +822,17 @@ static struct dentry *btrfs_mount(struct file_system_type *fs_type, int flags, s->s_flags |= MS_ACTIVE; } - root = get_default_root(s, subvol_objectid); - if (IS_ERR(root)) { - error = PTR_ERR(root); - deactivate_locked_super(s); - goto error_free_subvol_name; - } /* if they gave us a subvolume name bind mount into that */ if (strcmp(subvol_name, ".")) { struct dentry *new_root; + + root = get_default_root(s, subvol_rootid); + if (IS_ERR(root)) { + error = PTR_ERR(root); + deactivate_locked_super(s); + goto error_free_subvol_name; + } + mutex_lock(&root->d_inode->i_mutex); new_root = lookup_one_len(subvol_name, root, strlen(subvol_name)); @@ -836,6 +853,13 @@ static struct dentry *btrfs_mount(struct file_system_type *fs_type, int flags, } dput(root); root = new_root; + } else { + root = get_default_root(s, subvol_objectid); + if (IS_ERR(root)) { + error = PTR_ERR(root); + deactivate_locked_super(s); + goto error_free_subvol_name; + } } kfree(subvol_name); -- cgit v0.10.2 From 13c5a93e7005d7dae0b6d070d25203593e692d13 Mon Sep 17 00:00:00 2001 From: Josef Bacik Date: Mon, 11 Apr 2011 15:45:29 -0400 Subject: Btrfs: avoid taking the trans_mutex in btrfs_end_transaction I've been working on making our O_DIRECT latency not suck and I noticed we were taking the trans_mutex in btrfs_end_transaction. So to do this we convert num_writers and use_count to atomic_t's and just decrement them in btrfs_end_transaction. Instead of deleting the transaction from the trans list in put_transaction we do that in btrfs_commit_transaction() since that's the only time it actually needs to be removed from the list. Thanks, Signed-off-by: Josef Bacik diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c index a272bfd..ef6865c 100644 --- a/fs/btrfs/disk-io.c +++ b/fs/btrfs/disk-io.c @@ -3136,7 +3136,7 @@ static int btrfs_cleanup_transaction(struct btrfs_root *root) btrfs_destroy_pinned_extent(root, root->fs_info->pinned_extents); - t->use_count = 0; + atomic_set(&t->use_count, 0); list_del_init(&t->list); memset(t, 0, sizeof(*t)); kmem_cache_free(btrfs_transaction_cachep, t); diff --git a/fs/btrfs/transaction.c b/fs/btrfs/transaction.c index 4583008..c571734 100644 --- a/fs/btrfs/transaction.c +++ b/fs/btrfs/transaction.c @@ -32,10 +32,8 @@ static noinline void put_transaction(struct btrfs_transaction *transaction) { - WARN_ON(transaction->use_count == 0); - transaction->use_count--; - if (transaction->use_count == 0) { - list_del_init(&transaction->list); + WARN_ON(atomic_read(&transaction->use_count) == 0); + if (atomic_dec_and_test(&transaction->use_count)) { memset(transaction, 0, sizeof(*transaction)); kmem_cache_free(btrfs_transaction_cachep, transaction); } @@ -60,14 +58,14 @@ static noinline int join_transaction(struct btrfs_root *root) if (!cur_trans) return -ENOMEM; root->fs_info->generation++; - cur_trans->num_writers = 1; + atomic_set(&cur_trans->num_writers, 1); cur_trans->num_joined = 0; cur_trans->transid = root->fs_info->generation; init_waitqueue_head(&cur_trans->writer_wait); init_waitqueue_head(&cur_trans->commit_wait); cur_trans->in_commit = 0; cur_trans->blocked = 0; - cur_trans->use_count = 1; + atomic_set(&cur_trans->use_count, 1); cur_trans->commit_done = 0; cur_trans->start_time = get_seconds(); @@ -88,7 +86,7 @@ static noinline int join_transaction(struct btrfs_root *root) root->fs_info->running_transaction = cur_trans; spin_unlock(&root->fs_info->new_trans_lock); } else { - cur_trans->num_writers++; + atomic_inc(&cur_trans->num_writers); cur_trans->num_joined++; } @@ -145,7 +143,7 @@ static void wait_current_trans(struct btrfs_root *root) cur_trans = root->fs_info->running_transaction; if (cur_trans && cur_trans->blocked) { DEFINE_WAIT(wait); - cur_trans->use_count++; + atomic_inc(&cur_trans->use_count); while (1) { prepare_to_wait(&root->fs_info->transaction_wait, &wait, TASK_UNINTERRUPTIBLE); @@ -205,7 +203,7 @@ again: } cur_trans = root->fs_info->running_transaction; - cur_trans->use_count++; + atomic_inc(&cur_trans->use_count); if (type != TRANS_JOIN_NOLOCK) mutex_unlock(&root->fs_info->trans_mutex); @@ -336,7 +334,7 @@ int btrfs_wait_for_commit(struct btrfs_root *root, u64 transid) goto out_unlock; /* nothing committing|committed */ } - cur_trans->use_count++; + atomic_inc(&cur_trans->use_count); mutex_unlock(&root->fs_info->trans_mutex); wait_for_commit(root, cur_trans); @@ -466,18 +464,14 @@ static int __btrfs_end_transaction(struct btrfs_trans_handle *trans, wake_up_process(info->transaction_kthread); } - if (lock) - mutex_lock(&info->trans_mutex); WARN_ON(cur_trans != info->running_transaction); - WARN_ON(cur_trans->num_writers < 1); - cur_trans->num_writers--; + WARN_ON(atomic_read(&cur_trans->num_writers) < 1); + atomic_dec(&cur_trans->num_writers); smp_mb(); if (waitqueue_active(&cur_trans->writer_wait)) wake_up(&cur_trans->writer_wait); put_transaction(cur_trans); - if (lock) - mutex_unlock(&info->trans_mutex); if (current->journal_info == trans) current->journal_info = NULL; @@ -1187,7 +1181,7 @@ int btrfs_commit_transaction_async(struct btrfs_trans_handle *trans, /* take transaction reference */ mutex_lock(&root->fs_info->trans_mutex); cur_trans = trans->transaction; - cur_trans->use_count++; + atomic_inc(&cur_trans->use_count); mutex_unlock(&root->fs_info->trans_mutex); btrfs_end_transaction(trans, root); @@ -1246,7 +1240,7 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans, mutex_lock(&root->fs_info->trans_mutex); if (cur_trans->in_commit) { - cur_trans->use_count++; + atomic_inc(&cur_trans->use_count); mutex_unlock(&root->fs_info->trans_mutex); btrfs_end_transaction(trans, root); @@ -1268,7 +1262,7 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans, prev_trans = list_entry(cur_trans->list.prev, struct btrfs_transaction, list); if (!prev_trans->commit_done) { - prev_trans->use_count++; + atomic_inc(&prev_trans->use_count); mutex_unlock(&root->fs_info->trans_mutex); wait_for_commit(root, prev_trans); @@ -1309,14 +1303,14 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans, TASK_UNINTERRUPTIBLE); smp_mb(); - if (cur_trans->num_writers > 1) + if (atomic_read(&cur_trans->num_writers) > 1) schedule_timeout(MAX_SCHEDULE_TIMEOUT); else if (should_grow) schedule_timeout(1); mutex_lock(&root->fs_info->trans_mutex); finish_wait(&cur_trans->writer_wait, &wait); - } while (cur_trans->num_writers > 1 || + } while (atomic_read(&cur_trans->num_writers) > 1 || (should_grow && cur_trans->num_joined != joined)); ret = create_pending_snapshots(trans, root->fs_info); @@ -1403,6 +1397,7 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans, wake_up(&cur_trans->commit_wait); + list_del_init(&cur_trans->list); put_transaction(cur_trans); put_transaction(cur_trans); diff --git a/fs/btrfs/transaction.h b/fs/btrfs/transaction.h index 229a594..e441acc 100644 --- a/fs/btrfs/transaction.h +++ b/fs/btrfs/transaction.h @@ -27,11 +27,11 @@ struct btrfs_transaction { * total writers in this transaction, it must be zero before the * transaction can end */ - unsigned long num_writers; + atomic_t num_writers; unsigned long num_joined; int in_commit; - int use_count; + atomic_t use_count; int commit_done; int blocked; struct list_head list; -- cgit v0.10.2 From 507903b81840a70cc6a179d4eb03584ad50e8c5b Mon Sep 17 00:00:00 2001 From: Arne Jansen Date: Wed, 6 Apr 2011 10:02:20 +0000 Subject: btrfs: using cached extent_state in set/unlock combinations In several places the sequence (set_extent_uptodate, unlock_extent) is used. This leads to a duplicate lookup of the extent state. This patch lets set_extent_uptodate return a cached extent_state which can be passed to unlock_extent_cached. The occurences of the above sequences are updated to use the cache. Only end_bio_extent_readpage is updated that it first gets a cached state to pass it to the readpage_end_io_hook as the prototype requested and is later on being used for set/unlock. Signed-off-by: Arne Jansen Signed-off-by: Chris Mason diff --git a/fs/btrfs/extent_io.c b/fs/btrfs/extent_io.c index 864e049..8dcfb77 100644 --- a/fs/btrfs/extent_io.c +++ b/fs/btrfs/extent_io.c @@ -690,6 +690,17 @@ static void cache_state(struct extent_state *state, } } +static void uncache_state(struct extent_state **cached_ptr) +{ + if (cached_ptr && (*cached_ptr)) { + struct extent_state *state = *cached_ptr; + if (state->state & (EXTENT_IOBITS | EXTENT_BOUNDARY)) { + *cached_ptr = NULL; + free_extent_state(state); + } + } +} + /* * set some bits on a range in the tree. This may require allocations or * sleeping, so the gfp mask is used to indicate what is allowed. @@ -940,10 +951,10 @@ static int clear_extent_new(struct extent_io_tree *tree, u64 start, u64 end, } int set_extent_uptodate(struct extent_io_tree *tree, u64 start, u64 end, - gfp_t mask) + struct extent_state **cached_state, gfp_t mask) { - return set_extent_bit(tree, start, end, EXTENT_UPTODATE, 0, NULL, - NULL, mask); + return set_extent_bit(tree, start, end, EXTENT_UPTODATE, 0, + NULL, cached_state, mask); } static int clear_extent_uptodate(struct extent_io_tree *tree, u64 start, @@ -1012,8 +1023,7 @@ int unlock_extent_cached(struct extent_io_tree *tree, u64 start, u64 end, mask); } -int unlock_extent(struct extent_io_tree *tree, u64 start, u64 end, - gfp_t mask) +int unlock_extent(struct extent_io_tree *tree, u64 start, u64 end, gfp_t mask) { return clear_extent_bit(tree, start, end, EXTENT_LOCKED, 1, 0, NULL, mask); @@ -1735,6 +1745,9 @@ static void end_bio_extent_readpage(struct bio *bio, int err) do { struct page *page = bvec->bv_page; + struct extent_state *cached = NULL; + struct extent_state *state; + tree = &BTRFS_I(page->mapping->host)->io_tree; start = ((u64)page->index << PAGE_CACHE_SHIFT) + @@ -1749,9 +1762,20 @@ static void end_bio_extent_readpage(struct bio *bio, int err) if (++bvec <= bvec_end) prefetchw(&bvec->bv_page->flags); + spin_lock(&tree->lock); + state = find_first_extent_bit_state(tree, start, 0); + if (state) { + /* + * take a reference on the state, unlock will drop + * the ref + */ + cache_state(state, &cached); + } + spin_unlock(&tree->lock); + if (uptodate && tree->ops && tree->ops->readpage_end_io_hook) { ret = tree->ops->readpage_end_io_hook(page, start, end, - NULL); + state); if (ret) uptodate = 0; } @@ -1764,15 +1788,16 @@ static void end_bio_extent_readpage(struct bio *bio, int err) test_bit(BIO_UPTODATE, &bio->bi_flags); if (err) uptodate = 0; + uncache_state(&cached); continue; } } if (uptodate) { - set_extent_uptodate(tree, start, end, + set_extent_uptodate(tree, start, end, &cached, GFP_ATOMIC); } - unlock_extent(tree, start, end, GFP_ATOMIC); + unlock_extent_cached(tree, start, end, &cached, GFP_ATOMIC); if (whole_page) { if (uptodate) { @@ -1811,6 +1836,7 @@ static void end_bio_extent_preparewrite(struct bio *bio, int err) do { struct page *page = bvec->bv_page; + struct extent_state *cached = NULL; tree = &BTRFS_I(page->mapping->host)->io_tree; start = ((u64)page->index << PAGE_CACHE_SHIFT) + @@ -1821,13 +1847,14 @@ static void end_bio_extent_preparewrite(struct bio *bio, int err) prefetchw(&bvec->bv_page->flags); if (uptodate) { - set_extent_uptodate(tree, start, end, GFP_ATOMIC); + set_extent_uptodate(tree, start, end, &cached, + GFP_ATOMIC); } else { ClearPageUptodate(page); SetPageError(page); } - unlock_extent(tree, start, end, GFP_ATOMIC); + unlock_extent_cached(tree, start, end, &cached, GFP_ATOMIC); } while (bvec >= bio->bi_io_vec); @@ -2016,14 +2043,17 @@ static int __extent_read_full_page(struct extent_io_tree *tree, while (cur <= end) { if (cur >= last_byte) { char *userpage; + struct extent_state *cached = NULL; + iosize = PAGE_CACHE_SIZE - page_offset; userpage = kmap_atomic(page, KM_USER0); memset(userpage + page_offset, 0, iosize); flush_dcache_page(page); kunmap_atomic(userpage, KM_USER0); set_extent_uptodate(tree, cur, cur + iosize - 1, - GFP_NOFS); - unlock_extent(tree, cur, cur + iosize - 1, GFP_NOFS); + &cached, GFP_NOFS); + unlock_extent_cached(tree, cur, cur + iosize - 1, + &cached, GFP_NOFS); break; } em = get_extent(inode, page, page_offset, cur, @@ -2063,14 +2093,17 @@ static int __extent_read_full_page(struct extent_io_tree *tree, /* we've found a hole, just zero and go on */ if (block_start == EXTENT_MAP_HOLE) { char *userpage; + struct extent_state *cached = NULL; + userpage = kmap_atomic(page, KM_USER0); memset(userpage + page_offset, 0, iosize); flush_dcache_page(page); kunmap_atomic(userpage, KM_USER0); set_extent_uptodate(tree, cur, cur + iosize - 1, - GFP_NOFS); - unlock_extent(tree, cur, cur + iosize - 1, GFP_NOFS); + &cached, GFP_NOFS); + unlock_extent_cached(tree, cur, cur + iosize - 1, + &cached, GFP_NOFS); cur = cur + iosize; page_offset += iosize; continue; @@ -2789,9 +2822,12 @@ int extent_prepare_write(struct extent_io_tree *tree, iocount++; block_start = block_start + iosize; } else { - set_extent_uptodate(tree, block_start, cur_end, + struct extent_state *cached = NULL; + + set_extent_uptodate(tree, block_start, cur_end, &cached, GFP_NOFS); - unlock_extent(tree, block_start, cur_end, GFP_NOFS); + unlock_extent_cached(tree, block_start, cur_end, + &cached, GFP_NOFS); block_start = cur_end + 1; } page_offset = block_start & (PAGE_CACHE_SIZE - 1); @@ -3457,7 +3493,7 @@ int set_extent_buffer_uptodate(struct extent_io_tree *tree, num_pages = num_extent_pages(eb->start, eb->len); set_extent_uptodate(tree, eb->start, eb->start + eb->len - 1, - GFP_NOFS); + NULL, GFP_NOFS); for (i = 0; i < num_pages; i++) { page = extent_buffer_page(eb, i); if ((i == 0 && (eb->start & (PAGE_CACHE_SIZE - 1))) || diff --git a/fs/btrfs/extent_io.h b/fs/btrfs/extent_io.h index f62c5442..af2d717 100644 --- a/fs/btrfs/extent_io.h +++ b/fs/btrfs/extent_io.h @@ -208,7 +208,7 @@ int set_extent_bit(struct extent_io_tree *tree, u64 start, u64 end, int bits, int exclusive_bits, u64 *failed_start, struct extent_state **cached_state, gfp_t mask); int set_extent_uptodate(struct extent_io_tree *tree, u64 start, u64 end, - gfp_t mask); + struct extent_state **cached_state, gfp_t mask); int set_extent_new(struct extent_io_tree *tree, u64 start, u64 end, gfp_t mask); int set_extent_dirty(struct extent_io_tree *tree, u64 start, u64 end, diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c index edafc288..5a993e0 100644 --- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c @@ -5226,7 +5226,7 @@ again: btrfs_mark_buffer_dirty(leaf); } set_extent_uptodate(io_tree, em->start, - extent_map_end(em) - 1, GFP_NOFS); + extent_map_end(em) - 1, NULL, GFP_NOFS); goto insert; } else { printk(KERN_ERR "btrfs unknown found_type %d\n", found_type); -- cgit v0.10.2 From aa8673599f1d269b4e4d9b0c0f61fca57bc02699 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Mon, 11 Apr 2011 18:59:05 -0700 Subject: llc: Fix length check in llc_fixup_skb(). Fixes bugzilla #32872 The LLC stack pretends to support non-linear skbs but there is a direct use of skb_tail_pointer() in llc_fixup_skb(). Use pskb_may_pull() to see if data_size bytes remain and can be accessed linearly in the packet, instead of direct pointer checks. Signed-off-by: David S. Miller diff --git a/net/llc/llc_input.c b/net/llc/llc_input.c index 058f1e9..9032421 100644 --- a/net/llc/llc_input.c +++ b/net/llc/llc_input.c @@ -121,8 +121,7 @@ static inline int llc_fixup_skb(struct sk_buff *skb) s32 data_size = ntohs(pdulen) - llc_len; if (data_size < 0 || - ((skb_tail_pointer(skb) - - (u8 *)pdu) - llc_len) < data_size) + !pskb_may_pull(skb, data_size)) return 0; if (unlikely(pskb_trim_rcsum(skb, data_size))) return 0; -- cgit v0.10.2 From 3905c54f2bd2c6f937f87307987ca072eabc3e7b Mon Sep 17 00:00:00 2001 From: Stephen Rothwell Date: Tue, 12 Apr 2011 14:00:40 +1000 Subject: sched, sparc64: Turn cpu_coregroup_mask() into a real function This compile error triggers on Sparc64: kernel/sched.c:7140: error: 'cpu_coregroup_mask' undeclared here (not in a function) Because after the recent scheduler domain cleanups the scheduler uses this arch method as a function pointer in a scheduler topology data structure - which is not possible with a macro. Signed-off-by: Stephen Rothwell Acked-by: David S. Miller Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/20110412140040.3020ef55.sfr@canb.auug.org.au Signed-off-by: Ingo Molnar diff --git a/arch/sparc/include/asm/topology_64.h b/arch/sparc/include/asm/topology_64.h index 1c79f32..8b9c556 100644 --- a/arch/sparc/include/asm/topology_64.h +++ b/arch/sparc/include/asm/topology_64.h @@ -65,6 +65,10 @@ static inline int pcibus_to_node(struct pci_bus *pbus) #define smt_capable() (sparc64_multi_core) #endif /* CONFIG_SMP */ -#define cpu_coregroup_mask(cpu) (&cpu_core_map[cpu]) +extern cpumask_t cpu_core_map[NR_CPUS]; +static inline const struct cpumask *cpu_coregroup_mask(int cpu) +{ + return &cpu_core_map[cpu]; +} #endif /* _ASM_SPARC64_TOPOLOGY_H */ -- cgit v0.10.2 From c68b2081250a87ba9b9a173faa5a600cc684602e Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Mon, 11 Apr 2011 23:50:02 -0700 Subject: Input: twl4030_keypad - fix potential NULL dereference in twl4030_kp_probe() We should first check whether platform data is NULL or not, before dereferencing it to get the keymap. Signed-off-by: Axel Lin Reviewed-by: Felipe Balbi Signed-off-by: Dmitry Torokhov diff --git a/drivers/input/keyboard/twl4030_keypad.c b/drivers/input/keyboard/twl4030_keypad.c index cc06c4b..a26922c 100644 --- a/drivers/input/keyboard/twl4030_keypad.c +++ b/drivers/input/keyboard/twl4030_keypad.c @@ -332,7 +332,7 @@ static int __devinit twl4030_kp_program(struct twl4030_keypad *kp) static int __devinit twl4030_kp_probe(struct platform_device *pdev) { struct twl4030_keypad_data *pdata = pdev->dev.platform_data; - const struct matrix_keymap_data *keymap_data = pdata->keymap_data; + const struct matrix_keymap_data *keymap_data; struct twl4030_keypad *kp; struct input_dev *input; u8 reg; @@ -344,6 +344,8 @@ static int __devinit twl4030_kp_probe(struct platform_device *pdev) return -EINVAL; } + keymap_data = pdata->keymap_data; + kp = kzalloc(sizeof(*kp), GFP_KERNEL); input = input_allocate_device(); if (!kp || !input) { -- cgit v0.10.2 From d99ddec3eee0be8a43b2c1ff624b9dfaaa26b959 Mon Sep 17 00:00:00 2001 From: Joerg Roedel Date: Mon, 11 Apr 2011 11:03:18 +0200 Subject: x86/amd-iommu: Add extended feature detection This patch adds detection of the extended features of an AMD IOMMU. The available features are printed to dmesg on boot. Signed-off-by: Joerg Roedel diff --git a/arch/x86/include/asm/amd_iommu_proto.h b/arch/x86/include/asm/amd_iommu_proto.h index 1223c0f..a4ae6c3 100644 --- a/arch/x86/include/asm/amd_iommu_proto.h +++ b/arch/x86/include/asm/amd_iommu_proto.h @@ -19,7 +19,7 @@ #ifndef _ASM_X86_AMD_IOMMU_PROTO_H #define _ASM_X86_AMD_IOMMU_PROTO_H -struct amd_iommu; +#include extern int amd_iommu_init_dma_ops(void); extern int amd_iommu_init_passthrough(void); @@ -42,4 +42,12 @@ static inline bool is_rd890_iommu(struct pci_dev *pdev) (pdev->device == PCI_DEVICE_ID_RD890_IOMMU); } +static inline bool iommu_feature(struct amd_iommu *iommu, u64 f) +{ + if (!(iommu->cap & (1 << IOMMU_CAP_EFR))) + return false; + + return !!(iommu->features & f); +} + #endif /* _ASM_X86_AMD_IOMMU_PROTO_H */ diff --git a/arch/x86/include/asm/amd_iommu_types.h b/arch/x86/include/asm/amd_iommu_types.h index 878ae00..5c24e46 100644 --- a/arch/x86/include/asm/amd_iommu_types.h +++ b/arch/x86/include/asm/amd_iommu_types.h @@ -68,12 +68,25 @@ #define MMIO_CONTROL_OFFSET 0x0018 #define MMIO_EXCL_BASE_OFFSET 0x0020 #define MMIO_EXCL_LIMIT_OFFSET 0x0028 +#define MMIO_EXT_FEATURES 0x0030 #define MMIO_CMD_HEAD_OFFSET 0x2000 #define MMIO_CMD_TAIL_OFFSET 0x2008 #define MMIO_EVT_HEAD_OFFSET 0x2010 #define MMIO_EVT_TAIL_OFFSET 0x2018 #define MMIO_STATUS_OFFSET 0x2020 + +/* Extended Feature Bits */ +#define FEATURE_PREFETCH (1ULL<<0) +#define FEATURE_PPR (1ULL<<1) +#define FEATURE_X2APIC (1ULL<<2) +#define FEATURE_NX (1ULL<<3) +#define FEATURE_GT (1ULL<<4) +#define FEATURE_IA (1ULL<<6) +#define FEATURE_GA (1ULL<<7) +#define FEATURE_HE (1ULL<<8) +#define FEATURE_PC (1ULL<<9) + /* MMIO status bits */ #define MMIO_STATUS_COM_WAIT_INT_MASK 0x04 @@ -227,6 +240,7 @@ /* IOMMU capabilities */ #define IOMMU_CAP_IOTLB 24 #define IOMMU_CAP_NPCACHE 26 +#define IOMMU_CAP_EFR 27 #define MAX_DOMAIN_ID 65536 @@ -371,6 +385,9 @@ struct amd_iommu { /* flags read from acpi table */ u8 acpi_flags; + /* Extended features */ + u64 features; + /* * Capability pointer. There could be more than one IOMMU per PCI * device function if there are more than one AMD IOMMU capability diff --git a/arch/x86/kernel/amd_iommu_init.c b/arch/x86/kernel/amd_iommu_init.c index 8848dda..047905d 100644 --- a/arch/x86/kernel/amd_iommu_init.c +++ b/arch/x86/kernel/amd_iommu_init.c @@ -299,9 +299,23 @@ static void iommu_feature_disable(struct amd_iommu *iommu, u8 bit) /* Function to enable the hardware */ static void iommu_enable(struct amd_iommu *iommu) { - printk(KERN_INFO "AMD-Vi: Enabling IOMMU at %s cap 0x%hx\n", + static const char * const feat_str[] = { + "PreF", "PPR", "X2APIC", "NX", "GT", "[5]", + "IA", "GA", "HE", "PC", NULL + }; + int i; + + printk(KERN_INFO "AMD-Vi: Enabling IOMMU at %s cap 0x%hx", dev_name(&iommu->dev->dev), iommu->cap_ptr); + if (iommu->cap & (1 << IOMMU_CAP_EFR)) { + printk(KERN_CONT " extended features: "); + for (i = 0; feat_str[i]; ++i) + if (iommu_feature(iommu, (1ULL << i))) + printk(KERN_CONT " %s", feat_str[i]); + } + printk(KERN_CONT "\n"); + iommu_feature_enable(iommu, CONTROL_IOMMU_EN); } @@ -657,7 +671,7 @@ static void __init set_device_exclusion_range(u16 devid, struct ivmd_header *m) static void __init init_iommu_from_pci(struct amd_iommu *iommu) { int cap_ptr = iommu->cap_ptr; - u32 range, misc; + u32 range, misc, low, high; int i, j; pci_read_config_dword(iommu->dev, cap_ptr + MMIO_CAP_HDR_OFFSET, @@ -673,6 +687,12 @@ static void __init init_iommu_from_pci(struct amd_iommu *iommu) MMIO_GET_LD(range)); iommu->evt_msi_num = MMIO_MSI_NUM(misc); + /* read extended feature bits */ + low = readl(iommu->mmio_base + MMIO_EXT_FEATURES); + high = readl(iommu->mmio_base + MMIO_EXT_FEATURES + 4); + + iommu->features = ((u64)high << 32) | low; + if (!is_rd890_iommu(iommu->dev)) return; -- cgit v0.10.2 From 58fc7f1419560efa9c426b829c195050e0147d7f Mon Sep 17 00:00:00 2001 From: Joerg Roedel Date: Mon, 11 Apr 2011 11:13:24 +0200 Subject: x86/amd-iommu: Add support for invalidate_all command This patch adds support for the invalidate_all command present in new versions of the AMD IOMMU. Signed-off-by: Joerg Roedel diff --git a/arch/x86/include/asm/amd_iommu_types.h b/arch/x86/include/asm/amd_iommu_types.h index 5c24e46..df62d26 100644 --- a/arch/x86/include/asm/amd_iommu_types.h +++ b/arch/x86/include/asm/amd_iommu_types.h @@ -127,6 +127,7 @@ #define CMD_COMPL_WAIT 0x01 #define CMD_INV_DEV_ENTRY 0x02 #define CMD_INV_IOMMU_PAGES 0x03 +#define CMD_INV_ALL 0x08 #define CMD_COMPL_WAIT_STORE_MASK 0x01 #define CMD_COMPL_WAIT_INT_MASK 0x02 diff --git a/arch/x86/kernel/amd_iommu.c b/arch/x86/kernel/amd_iommu.c index bcf58ea..d6192bc 100644 --- a/arch/x86/kernel/amd_iommu.c +++ b/arch/x86/kernel/amd_iommu.c @@ -463,6 +463,12 @@ static void build_inv_iommu_pages(struct iommu_cmd *cmd, u64 address, cmd->data[2] |= CMD_INV_IOMMU_PAGES_PDE_MASK; } +static void build_inv_all(struct iommu_cmd *cmd) +{ + memset(cmd, 0, sizeof(*cmd)); + CMD_SET_TYPE(cmd, CMD_INV_ALL); +} + /* * Writes the command to the IOMMUs command buffer and informs the * hardware about the new command. @@ -567,10 +573,24 @@ static void iommu_flush_tlb_all(struct amd_iommu *iommu) iommu_completion_wait(iommu); } +static void iommu_flush_all(struct amd_iommu *iommu) +{ + struct iommu_cmd cmd; + + build_inv_all(&cmd); + + iommu_queue_command(iommu, &cmd); + iommu_completion_wait(iommu); +} + void iommu_flush_all_caches(struct amd_iommu *iommu) { - iommu_flush_dte_all(iommu); - iommu_flush_tlb_all(iommu); + if (iommu_feature(iommu, FEATURE_IA)) { + iommu_flush_all(iommu); + } else { + iommu_flush_dte_all(iommu); + iommu_flush_tlb_all(iommu); + } } /* -- cgit v0.10.2 From 32a90b6e65792260d6212ac52e8f5be140b6f5be Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Fri, 8 Apr 2011 12:01:51 +0200 Subject: ARM: imx: fix usb related build failure for mach-vpr200 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This was broken by 4bd597b (ARM i.MX ehci: do ehci init in board specific functions) and fixes: CC arch/arm/mach-mx3/mach-vpr200.o arch/arm/mach-mx3/mach-vpr200.c:263: error: unknown field 'flags' specified in initializer arch/arm/mach-mx3/mach-vpr200.c:264: warning: initialization makes pointer from integer without a cast by just applying the change to mach-vpr200.c that the other machine files got by 4bd597b. LAKML-Reference: 1302257029-17397-1-git-send-email-u.kleine-koenig@pengutronix.de Acked-by: Marc Reilly Signed-off-by: Uwe Kleine-König Signed-off-by: Sascha Hauer diff --git a/arch/arm/mach-mx3/mach-vpr200.c b/arch/arm/mach-mx3/mach-vpr200.c index 2cf390f..47a69cb 100644 --- a/arch/arm/mach-mx3/mach-vpr200.c +++ b/arch/arm/mach-mx3/mach-vpr200.c @@ -257,11 +257,16 @@ static const struct fsl_usb2_platform_data otg_device_pdata __initconst = { .workaround = FLS_USB2_WORKAROUND_ENGCM09152, }; +static int vpr200_usbh_init(struct platform_device *pdev) +{ + return mx35_initialize_usb_hw(pdev->id, + MXC_EHCI_INTERFACE_SINGLE_UNI | MXC_EHCI_INTERNAL_PHY); +} + /* USB HOST config */ static const struct mxc_usbh_platform_data usb_host_pdata __initconst = { - .portsc = MXC_EHCI_MODE_SERIAL, - .flags = MXC_EHCI_INTERFACE_SINGLE_UNI | - MXC_EHCI_INTERNAL_PHY, + .init = vpr200_usbh_init, + .portsc = MXC_EHCI_MODE_SERIAL, }; static struct platform_device *devices[] __initdata = { -- cgit v0.10.2 From f61b9fc27e5b61dbc330696f040cc66ba1dbcbaa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Mon, 4 Apr 2011 16:06:12 +0200 Subject: ARM: mxs/clock-mx28: fix up name##_set_rate MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit For the lcdif clock get_rate looks as follows: read div from HW_CLKCTRL_DIS_LCDIF.DIV return clk_get_rate(clk->parent) / div with clk->parent being ref_pix_clk on my system. ref_pix_clk's rate depends on HW_CLKCTRL_FRAC1.PIXFRAC. The set_rate function for lcdif does: parent_rate = clk_get_rate(clk->parent); based on that calculate frac and div such that parent_rate * 18 / frac / div is near the requested rate. HW_CLKCTRL_FRAC1.PIXFRAC is updated with frac HW_CLKCTRL_DIS_LCDIF.DIV is updated with div For this calculation to be correct parent_rate needs to be initialized not with the clock rate of lcdif's parent (i.e. ref_pix) but that of its grandparent (i.e. ref_pix' parent == pll0_clk). The obvious downside of this patch is that now set_rate(lcdif) changes its parent's rate, too. Still this is better than a wrong rate. Acked-by: Shawn Guo LAKML-Reference: 20110225084950.GA13684@S2101-09.ap.freescale.net Signed-off-by: Uwe Kleine-König Signed-off-by: Sascha Hauer diff --git a/arch/arm/mach-mxs/clock-mx28.c b/arch/arm/mach-mxs/clock-mx28.c index 1ad97fe..5dcc59d 100644 --- a/arch/arm/mach-mxs/clock-mx28.c +++ b/arch/arm/mach-mxs/clock-mx28.c @@ -295,11 +295,11 @@ static int name##_set_rate(struct clk *clk, unsigned long rate) \ unsigned long diff, parent_rate, calc_rate; \ int i; \ \ - parent_rate = clk_get_rate(clk->parent); \ div_max = BM_CLKCTRL_##dr##_DIV >> BP_CLKCTRL_##dr##_DIV; \ bm_busy = BM_CLKCTRL_##dr##_BUSY; \ \ if (clk->parent == &ref_xtal_clk) { \ + parent_rate = clk_get_rate(clk->parent); \ div = DIV_ROUND_UP(parent_rate, rate); \ if (clk == &cpu_clk) { \ div_max = BM_CLKCTRL_CPU_DIV_XTAL >> \ @@ -309,6 +309,11 @@ static int name##_set_rate(struct clk *clk, unsigned long rate) \ if (div == 0 || div > div_max) \ return -EINVAL; \ } else { \ + /* \ + * hack alert: this block modifies clk->parent, too, \ + * so the base to use it the grand parent. \ + */ \ + parent_rate = clk_get_rate(clk->parent->parent); \ rate >>= PARENT_RATE_SHIFT; \ parent_rate >>= PARENT_RATE_SHIFT; \ diff = parent_rate; \ -- cgit v0.10.2 From 0575b4b83edb0a766a9c1518a5da57780f386340 Mon Sep 17 00:00:00 2001 From: Dave Martin Date: Tue, 16 Nov 2010 13:13:37 +0000 Subject: ARM: mxc: Correct data alignment in headsmp.S for CONFIG_THUMB2_KERNEL MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Directives such as .long and .word do not magically cause the assembler location counter to become aligned in gas. As a result, using these directives in code sections can result in misaligned data words when building a Thumb-2 kernel (CONFIG_THUMB2_KERNEL). This is a Bad Thing, since the ABI permits the compiler to assume that fundamental types of word size or above are word- aligned when accessing them from C. If the data is not really word-aligned, this can cause impaired performance and stray alignment faults in some circumstances. In general, the following rules should be applied when using data word declaration directives inside code sections: * .quad and .double: .align 3 * .long, .word, .single, .float: .align (or .align 2) * .short: No explicit alignment required, since Thumb-2 instructions are always 2 or 4 bytes in size. immediately after an instruction. Signed-off-by: Dave Martin Signed-off-by: Sascha Hauer LAKML-Reference: 1289913217-8672-1-git-send-email-dave.martin@linaro.org Signed-off-by: Uwe Kleine-König Signed-off-by: Sascha Hauer diff --git a/arch/arm/plat-mxc/ssi-fiq.S b/arch/arm/plat-mxc/ssi-fiq.S index 4ddce56..8397a2d 100644 --- a/arch/arm/plat-mxc/ssi-fiq.S +++ b/arch/arm/plat-mxc/ssi-fiq.S @@ -124,6 +124,8 @@ imx_ssi_fiq_start: 1: @ return from FIQ subs pc, lr, #4 + + .align imx_ssi_fiq_base: .word 0x0 imx_ssi_fiq_rx_buffer: -- cgit v0.10.2 From b5eee2fdefc89df312034e5e0e6f5dd55c4e9bae Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Mon, 4 Apr 2011 14:29:58 +0200 Subject: ARM: mxc: Add missing lockdep annotation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The irq_set_wake() function of the gpio irq_chip calls enable/disable_irq_wake() on the demultiplex interrupt. That leads to a lockdep warning "INFO: possible recursive locking detected" because irq_set_type() is called under irq_desc->lock and the *_irq_wake() calls take irq_desc->lock of the demux interrupt. Tell lockdep that the gpio irqs are in a different lock class. Documentation/SubmitChecklist: 15: All codepaths have been exercised with all lockdep features enabled. That's a non-optional requirement, AFAICT. Reported-and-tested-by: Arnaud Patard Signed-off-by: Thomas Gleixner LAKML-Reference: alpine.LFD.2.00.1104041416290.19945@localhost6.localdomain6 Signed-off-by: Uwe Kleine-König Signed-off-by: Sascha Hauer diff --git a/arch/arm/plat-mxc/gpio.c b/arch/arm/plat-mxc/gpio.c index 7a10724..6cd6d7f 100644 --- a/arch/arm/plat-mxc/gpio.c +++ b/arch/arm/plat-mxc/gpio.c @@ -295,6 +295,12 @@ static int mxc_gpio_direction_output(struct gpio_chip *chip, return 0; } +/* + * This lock class tells lockdep that GPIO irqs are in a different + * category than their parents, so it won't report false recursion. + */ +static struct lock_class_key gpio_lock_class; + int __init mxc_gpio_init(struct mxc_gpio_port *port, int cnt) { int i, j; @@ -311,6 +317,7 @@ int __init mxc_gpio_init(struct mxc_gpio_port *port, int cnt) __raw_writel(~0, port[i].base + GPIO_ISR); for (j = port[i].virtual_irq_start; j < port[i].virtual_irq_start + 32; j++) { + irq_set_lockdep_class(j, &gpio_lock_class); irq_set_chip_and_handler(j, &gpio_irq_chip, handle_level_irq); set_irq_flags(j, IRQF_VALID); -- cgit v0.10.2 From ef1fd2df85f5ea8ca8876a45d0ebb152d3a144d1 Mon Sep 17 00:00:00 2001 From: Prabhakar Kushwaha Date: Thu, 31 Mar 2011 12:31:09 +0530 Subject: powerpc/85xx: Don't add disabled PCIe devices PCIe nodes with the property status="disabled" are not usable and so avoid adding "disabled" PCIe bridge with the system. Signed-off-by: Prabhakar Kushwaha Signed-off-by: Kumar Gala diff --git a/arch/powerpc/sysdev/fsl_pci.c b/arch/powerpc/sysdev/fsl_pci.c index f8f7f28..68ca929 100644 --- a/arch/powerpc/sysdev/fsl_pci.c +++ b/arch/powerpc/sysdev/fsl_pci.c @@ -324,6 +324,11 @@ int __init fsl_add_bridge(struct device_node *dev, int is_primary) struct resource rsrc; const int *bus_range; + if (!of_device_is_available(dev)) { + pr_warning("%s: disabled\n", dev->full_name); + return -ENODEV; + } + pr_debug("Adding PCI host bridge %s\n", dev->full_name); /* Fetch host bridge registers address */ -- cgit v0.10.2 From 07d9fce24d871785dbd25458469032fea73f17b8 Mon Sep 17 00:00:00 2001 From: Prabhakar Kushwaha Date: Wed, 6 Apr 2011 12:56:29 +0530 Subject: powerpc: Check device status before adding serial device serial port nodes with the property status="disabled" are not usable and so avoid adding "disabled" port with the system. Signed-off-by: Prabhakar Kushwaha Signed-off-by: Kumar Gala diff --git a/arch/powerpc/kernel/legacy_serial.c b/arch/powerpc/kernel/legacy_serial.c index c834757..2b97b80 100644 --- a/arch/powerpc/kernel/legacy_serial.c +++ b/arch/powerpc/kernel/legacy_serial.c @@ -330,9 +330,11 @@ void __init find_legacy_serial_ports(void) if (!parent) continue; if (of_match_node(legacy_serial_parents, parent) != NULL) { - index = add_legacy_soc_port(np, np); - if (index >= 0 && np == stdout) - legacy_serial_console = index; + if (of_device_is_available(np)) { + index = add_legacy_soc_port(np, np); + if (index >= 0 && np == stdout) + legacy_serial_console = index; + } } of_node_put(parent); } -- cgit v0.10.2 From 11ed0db9f6c7811233632d2ab79c50c011b89902 Mon Sep 17 00:00:00 2001 From: Kumar Gala Date: Wed, 6 Apr 2011 00:11:06 -0500 Subject: powerpc/book3e: Fix CPU feature handling on 64-bit e5500 The CPU_FTRS_POSSIBLE and CPU_FTRS_ALWAYS defines did not encompass e5500 CPU features when built for 64-bit. This causes issues with cpu_has_feature() as it utilizes the POSSIBLE & ALWAYS defines as part of its check. Create a unique CPU_FTRS_E5500 (as its different from CPU_FTRS_E500MC), created a new group for 64-bit Book3e based CPUs and add CPU_FTRS_E5500 to that group. Signed-off-by: Kumar Gala diff --git a/arch/powerpc/include/asm/cputable.h b/arch/powerpc/include/asm/cputable.h index be3cdf9..f1fbf60 100644 --- a/arch/powerpc/include/asm/cputable.h +++ b/arch/powerpc/include/asm/cputable.h @@ -386,6 +386,9 @@ extern const char *powerpc_base_platform; CPU_FTR_MAYBE_CAN_NAP | CPU_FTR_NODSISRALIGN | \ CPU_FTR_L2CSR | CPU_FTR_LWSYNC | CPU_FTR_NOEXECUTE | \ CPU_FTR_DBELL) +#define CPU_FTRS_E5500 (CPU_FTR_USE_TB | CPU_FTR_NODSISRALIGN | \ + CPU_FTR_L2CSR | CPU_FTR_LWSYNC | CPU_FTR_NOEXECUTE | \ + CPU_FTR_DBELL | CPU_FTR_POPCNTB | CPU_FTR_POPCNTD) #define CPU_FTRS_GENERIC_32 (CPU_FTR_COMMON | CPU_FTR_NODSISRALIGN) /* 64-bit CPUs */ @@ -435,11 +438,15 @@ extern const char *powerpc_base_platform; #define CPU_FTRS_COMPATIBLE (CPU_FTR_USE_TB | CPU_FTR_PPCAS_ARCH_V2) #ifdef __powerpc64__ +#ifdef CONFIG_PPC_BOOK3E +#define CPU_FTRS_POSSIBLE (CPU_FTRS_E5500) +#else #define CPU_FTRS_POSSIBLE \ (CPU_FTRS_POWER3 | CPU_FTRS_RS64 | CPU_FTRS_POWER4 | \ CPU_FTRS_PPC970 | CPU_FTRS_POWER5 | CPU_FTRS_POWER6 | \ CPU_FTRS_POWER7 | CPU_FTRS_CELL | CPU_FTRS_PA6T | \ CPU_FTR_1T_SEGMENT | CPU_FTR_VSX) +#endif #else enum { CPU_FTRS_POSSIBLE = @@ -473,16 +480,21 @@ enum { #endif #ifdef CONFIG_E500 CPU_FTRS_E500 | CPU_FTRS_E500_2 | CPU_FTRS_E500MC | + CPU_FTRS_E5500 | #endif 0, }; #endif /* __powerpc64__ */ #ifdef __powerpc64__ +#ifdef CONFIG_PPC_BOOK3E +#define CPU_FTRS_ALWAYS (CPU_FTRS_E5500) +#else #define CPU_FTRS_ALWAYS \ (CPU_FTRS_POWER3 & CPU_FTRS_RS64 & CPU_FTRS_POWER4 & \ CPU_FTRS_PPC970 & CPU_FTRS_POWER5 & CPU_FTRS_POWER6 & \ CPU_FTRS_POWER7 & CPU_FTRS_CELL & CPU_FTRS_PA6T & CPU_FTRS_POSSIBLE) +#endif #else enum { CPU_FTRS_ALWAYS = @@ -513,6 +525,7 @@ enum { #endif #ifdef CONFIG_E500 CPU_FTRS_E500 & CPU_FTRS_E500_2 & CPU_FTRS_E500MC & + CPU_FTRS_E5500 & #endif CPU_FTRS_POSSIBLE, }; diff --git a/arch/powerpc/kernel/cputable.c b/arch/powerpc/kernel/cputable.c index c9b68d0..b9602ee 100644 --- a/arch/powerpc/kernel/cputable.c +++ b/arch/powerpc/kernel/cputable.c @@ -1973,7 +1973,7 @@ static struct cpu_spec __initdata cpu_specs[] = { .pvr_mask = 0xffff0000, .pvr_value = 0x80240000, .cpu_name = "e5500", - .cpu_features = CPU_FTRS_E500MC, + .cpu_features = CPU_FTRS_E5500, .cpu_user_features = COMMON_USER_BOOKE, .mmu_features = MMU_FTR_TYPE_FSL_E | MMU_FTR_BIG_PHYS | MMU_FTR_USE_TLBILX, -- cgit v0.10.2 From d51ad91535b75c043f074f093ef913fe20ff2b5e Mon Sep 17 00:00:00 2001 From: Scott Wood Date: Thu, 27 May 2010 17:35:12 -0500 Subject: powerpc/e500mc: Remove CPU_FTR_MAYBE_CAN_NAP/CPU_FTR_MAYBE_CAN_DOZE e500mc does not support the HID0/MSR mechanism that is used by e500_idle (and there are also issues with waking on certain types of interrupts). Further, even if napping is never actually enabled, just having CPU_FTR_CAN_NAP will cause machine_init() to overwrite the board's supplied ppc_md.power_save(). We drop CPU_FTR_MAYBE_CAN_DOZE becuase we should use 'wait' instead on e500mc. Signed-off-by: Scott Wood Signed-off-by: Kumar Gala diff --git a/arch/powerpc/include/asm/cputable.h b/arch/powerpc/include/asm/cputable.h index f1fbf60..1833d1a 100644 --- a/arch/powerpc/include/asm/cputable.h +++ b/arch/powerpc/include/asm/cputable.h @@ -382,8 +382,7 @@ extern const char *powerpc_base_platform; #define CPU_FTRS_E500_2 (CPU_FTR_MAYBE_CAN_DOZE | CPU_FTR_USE_TB | \ CPU_FTR_SPE_COMP | CPU_FTR_MAYBE_CAN_NAP | \ CPU_FTR_NODSISRALIGN | CPU_FTR_NOEXECUTE) -#define CPU_FTRS_E500MC (CPU_FTR_MAYBE_CAN_DOZE | CPU_FTR_USE_TB | \ - CPU_FTR_MAYBE_CAN_NAP | CPU_FTR_NODSISRALIGN | \ +#define CPU_FTRS_E500MC (CPU_FTR_USE_TB | CPU_FTR_NODSISRALIGN | \ CPU_FTR_L2CSR | CPU_FTR_LWSYNC | CPU_FTR_NOEXECUTE | \ CPU_FTR_DBELL) #define CPU_FTRS_E5500 (CPU_FTR_USE_TB | CPU_FTR_NODSISRALIGN | \ -- cgit v0.10.2 From e5462d16f76ad7a9156a82a97fbafba298da9ca6 Mon Sep 17 00:00:00 2001 From: Kumar Gala Date: Fri, 8 Apr 2011 04:20:54 -0500 Subject: powerpc/85xx: disable Suspend support if SMP enabled We currently dont have CPU Hotplug support working on 85xx so we need to disable Suspsend support as it will force enabling of CPU Hotplug. arch/powerpc/kernel/built-in.o: In function `cpu_die': arch/powerpc/kernel/smp.c:702: undefined reference to `start_secondary_resume' make: *** [.tmp_vmlinux1] Error 1 Signed-off-by: Kumar Gala diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig index b6ff882..8f4d50b 100644 --- a/arch/powerpc/Kconfig +++ b/arch/powerpc/Kconfig @@ -209,7 +209,7 @@ config ARCH_HIBERNATION_POSSIBLE config ARCH_SUSPEND_POSSIBLE def_bool y depends on ADB_PMU || PPC_EFIKA || PPC_LITE5200 || PPC_83xx || \ - PPC_85xx || PPC_86xx || PPC_PSERIES || 44x || 40x + (PPC_85xx && !SMP) || PPC_86xx || PPC_PSERIES || 44x || 40x config PPC_DCR_NATIVE bool -- cgit v0.10.2 From 9d1aea62e45d447e7fc05d4e7f4e90f633e3abfc Mon Sep 17 00:00:00 2001 From: Neil Turton Date: Mon, 4 Apr 2011 13:46:23 +0100 Subject: sfc: Stop the TX queues during loopback self-tests If the TX queues are running during loopback self tests, host traffic gets looped back which causes the test to fail. Avoid restarting the TX queues after the port reset so that any packets sent by the host get held back until after the tests have completed. [bwh: Also wake all TX queues at the end of self-tests.] Signed-off-by: Ben Hutchings diff --git a/drivers/net/sfc/efx.c b/drivers/net/sfc/efx.c index d890679..0dc800b 100644 --- a/drivers/net/sfc/efx.c +++ b/drivers/net/sfc/efx.c @@ -1436,7 +1436,7 @@ static void efx_start_all(struct efx_nic *efx) * restart the transmit interface early so the watchdog timer stops */ efx_start_port(efx); - if (efx_dev_registered(efx)) + if (efx_dev_registered(efx) && !efx->port_inhibited) netif_tx_wake_all_queues(efx->net_dev); efx_for_each_channel(channel, efx) diff --git a/drivers/net/sfc/selftest.c b/drivers/net/sfc/selftest.c index a0f49b3..8458084 100644 --- a/drivers/net/sfc/selftest.c +++ b/drivers/net/sfc/selftest.c @@ -770,6 +770,8 @@ int efx_selftest(struct efx_nic *efx, struct efx_self_tests *tests, __efx_reconfigure_port(efx); mutex_unlock(&efx->mac_lock); + netif_tx_wake_all_queues(efx->net_dev); + return rc_test; } diff --git a/drivers/net/sfc/tx.c b/drivers/net/sfc/tx.c index 1398019..d2c85df 100644 --- a/drivers/net/sfc/tx.c +++ b/drivers/net/sfc/tx.c @@ -435,7 +435,8 @@ void efx_xmit_done(struct efx_tx_queue *tx_queue, unsigned int index) * queue state. */ smp_mb(); if (unlikely(netif_tx_queue_stopped(tx_queue->core_txq)) && - likely(efx->port_enabled)) { + likely(efx->port_enabled) && + likely(!efx->port_inhibited)) { fill_level = tx_queue->insert_count - tx_queue->read_count; if (fill_level < EFX_TXQ_THRESHOLD(efx)) { EFX_BUG_ON_PARANOID(!efx_dev_registered(efx)); -- cgit v0.10.2 From d4fabcc8e8ecac21262b1a5b9684fe415b128bd2 Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Mon, 4 Apr 2011 14:22:11 +0100 Subject: sfc: Do not use efx_process_channel_now() in online self-test During self-tests we use efx_process_channel_now() to handle completion and other events synchronously. This disables interrupts and NAPI processing for the channel in question, but it may still be interrupted by another channel. A single socket may receive packets from multiple net devices or even multiple channels of the same net device, so this can result in deadlock on a socket lock. Receiving packets in process context will also result in incorrect classification by the network cgroup classifier. Therefore, we must only use efx_process_channel_now() in the offline loopback tests (which never deliver packets up the stack) and not for the online interrupt and event tests. For the interrupt test, there is no reason to process events. We only care that an interrupt is raised. For the event test, we want to know whether events have been received, and there may be many events ahead of the one we inject. Therefore remove efx_channel::magic_count and instead test whether efx_channel::eventq_read_ptr advances. This is currently an event queue index and might wrap around to exactly the same value, resulting in a false negative. Therefore move the masking to efx_event() and efx_nic_eventq_read_ack() so that it cannot wrap within the time of the test. The event test also tries to diagnose failures by checking whether an event was delivered without causing an interrupt. Add and use a helper function that only does this. Signed-off-by: Ben Hutchings diff --git a/drivers/net/sfc/efx.c b/drivers/net/sfc/efx.c index 0dc800b..a3c2aab 100644 --- a/drivers/net/sfc/efx.c +++ b/drivers/net/sfc/efx.c @@ -328,7 +328,8 @@ static int efx_poll(struct napi_struct *napi, int budget) * processing to finish, then directly poll (and ack ) the eventq. * Finally reenable NAPI and interrupts. * - * Since we are touching interrupts the caller should hold the suspend lock + * This is for use only during a loopback self-test. It must not + * deliver any packets up the stack as this can result in deadlock. */ void efx_process_channel_now(struct efx_channel *channel) { @@ -336,6 +337,7 @@ void efx_process_channel_now(struct efx_channel *channel) BUG_ON(channel->channel >= efx->n_channels); BUG_ON(!channel->enabled); + BUG_ON(!efx->loopback_selftest); /* Disable interrupts and wait for ISRs to complete */ efx_nic_disable_interrupts(efx); diff --git a/drivers/net/sfc/net_driver.h b/drivers/net/sfc/net_driver.h index 9ffa9a6..191a311 100644 --- a/drivers/net/sfc/net_driver.h +++ b/drivers/net/sfc/net_driver.h @@ -330,7 +330,6 @@ enum efx_rx_alloc_method { * @eventq_mask: Event queue pointer mask * @eventq_read_ptr: Event queue read pointer * @last_eventq_read_ptr: Last event queue read pointer value. - * @magic_count: Event queue test event count * @irq_count: Number of IRQs since last adaptive moderation decision * @irq_mod_score: IRQ moderation score * @rx_alloc_level: Watermark based heuristic counter for pushing descriptors @@ -360,7 +359,6 @@ struct efx_channel { unsigned int eventq_mask; unsigned int eventq_read_ptr; unsigned int last_eventq_read_ptr; - unsigned int magic_count; unsigned int irq_count; unsigned int irq_mod_score; diff --git a/drivers/net/sfc/nic.c b/drivers/net/sfc/nic.c index e839661..10f1cb7 100644 --- a/drivers/net/sfc/nic.c +++ b/drivers/net/sfc/nic.c @@ -84,7 +84,8 @@ static inline void efx_write_buf_tbl(struct efx_nic *efx, efx_qword_t *value, static inline efx_qword_t *efx_event(struct efx_channel *channel, unsigned int index) { - return ((efx_qword_t *) (channel->eventq.addr)) + index; + return ((efx_qword_t *) (channel->eventq.addr)) + + (index & channel->eventq_mask); } /* See if an event is present @@ -673,7 +674,8 @@ void efx_nic_eventq_read_ack(struct efx_channel *channel) efx_dword_t reg; struct efx_nic *efx = channel->efx; - EFX_POPULATE_DWORD_1(reg, FRF_AZ_EVQ_RPTR, channel->eventq_read_ptr); + EFX_POPULATE_DWORD_1(reg, FRF_AZ_EVQ_RPTR, + channel->eventq_read_ptr & channel->eventq_mask); efx_writed_table(efx, ®, efx->type->evq_rptr_tbl_base, channel->channel); } @@ -908,7 +910,7 @@ efx_handle_generated_event(struct efx_channel *channel, efx_qword_t *event) code = EFX_QWORD_FIELD(*event, FSF_AZ_DRV_GEN_EV_MAGIC); if (code == EFX_CHANNEL_MAGIC_TEST(channel)) - ++channel->magic_count; + ; /* ignore */ else if (code == EFX_CHANNEL_MAGIC_FILL(channel)) /* The queue must be empty, so we won't receive any rx * events, so efx_process_channel() won't refill the @@ -1015,8 +1017,7 @@ int efx_nic_process_eventq(struct efx_channel *channel, int budget) /* Clear this event by marking it all ones */ EFX_SET_QWORD(*p_event); - /* Increment read pointer */ - read_ptr = (read_ptr + 1) & channel->eventq_mask; + ++read_ptr; ev_code = EFX_QWORD_FIELD(event, FSF_AZ_EV_CODE); @@ -1060,6 +1061,13 @@ out: return spent; } +/* Check whether an event is present in the eventq at the current + * read pointer. Only useful for self-test. + */ +bool efx_nic_event_present(struct efx_channel *channel) +{ + return efx_event_present(efx_event(channel, channel->eventq_read_ptr)); +} /* Allocate buffer table entries for event queue */ int efx_nic_probe_eventq(struct efx_channel *channel) @@ -1165,7 +1173,7 @@ static void efx_poll_flush_events(struct efx_nic *efx) struct efx_tx_queue *tx_queue; struct efx_rx_queue *rx_queue; unsigned int read_ptr = channel->eventq_read_ptr; - unsigned int end_ptr = (read_ptr - 1) & channel->eventq_mask; + unsigned int end_ptr = read_ptr + channel->eventq_mask - 1; do { efx_qword_t *event = efx_event(channel, read_ptr); @@ -1205,7 +1213,7 @@ static void efx_poll_flush_events(struct efx_nic *efx) * it's ok to throw away every non-flush event */ EFX_SET_QWORD(*event); - read_ptr = (read_ptr + 1) & channel->eventq_mask; + ++read_ptr; } while (read_ptr != end_ptr); channel->eventq_read_ptr = read_ptr; diff --git a/drivers/net/sfc/nic.h b/drivers/net/sfc/nic.h index d9de1b6..a42db6e 100644 --- a/drivers/net/sfc/nic.h +++ b/drivers/net/sfc/nic.h @@ -184,6 +184,7 @@ extern void efx_nic_fini_eventq(struct efx_channel *channel); extern void efx_nic_remove_eventq(struct efx_channel *channel); extern int efx_nic_process_eventq(struct efx_channel *channel, int rx_quota); extern void efx_nic_eventq_read_ack(struct efx_channel *channel); +extern bool efx_nic_event_present(struct efx_channel *channel); /* MAC/PHY */ extern void falcon_drain_tx_fifo(struct efx_nic *efx); diff --git a/drivers/net/sfc/selftest.c b/drivers/net/sfc/selftest.c index 8458084..50ad3bc 100644 --- a/drivers/net/sfc/selftest.c +++ b/drivers/net/sfc/selftest.c @@ -131,8 +131,6 @@ static int efx_test_chip(struct efx_nic *efx, struct efx_self_tests *tests) static int efx_test_interrupts(struct efx_nic *efx, struct efx_self_tests *tests) { - struct efx_channel *channel; - netif_dbg(efx, drv, efx->net_dev, "testing interrupts\n"); tests->interrupt = -1; @@ -140,15 +138,6 @@ static int efx_test_interrupts(struct efx_nic *efx, efx->last_irq_cpu = -1; smp_wmb(); - /* ACK each interrupting event queue. Receiving an interrupt due to - * traffic before a test event is raised is considered a pass */ - efx_for_each_channel(channel, efx) { - if (channel->work_pending) - efx_process_channel_now(channel); - if (efx->last_irq_cpu >= 0) - goto success; - } - efx_nic_generate_interrupt(efx); /* Wait for arrival of test interrupt. */ @@ -173,13 +162,13 @@ static int efx_test_eventq_irq(struct efx_channel *channel, struct efx_self_tests *tests) { struct efx_nic *efx = channel->efx; - unsigned int magic_count, count; + unsigned int read_ptr, count; tests->eventq_dma[channel->channel] = -1; tests->eventq_int[channel->channel] = -1; tests->eventq_poll[channel->channel] = -1; - magic_count = channel->magic_count; + read_ptr = channel->eventq_read_ptr; channel->efx->last_irq_cpu = -1; smp_wmb(); @@ -190,10 +179,7 @@ static int efx_test_eventq_irq(struct efx_channel *channel, do { schedule_timeout_uninterruptible(HZ / 100); - if (channel->work_pending) - efx_process_channel_now(channel); - - if (channel->magic_count != magic_count) + if (ACCESS_ONCE(channel->eventq_read_ptr) != read_ptr) goto eventq_ok; } while (++count < 2); @@ -211,8 +197,7 @@ static int efx_test_eventq_irq(struct efx_channel *channel, } /* Check to see if event was received even if interrupt wasn't */ - efx_process_channel_now(channel); - if (channel->magic_count != magic_count) { + if (efx_nic_event_present(channel)) { netif_err(efx, drv, efx->net_dev, "channel %d event was generated, but " "failed to trigger an interrupt\n", channel->channel); -- cgit v0.10.2 From 8a226e00eeed8db843d4a580013a49ae3559bcd7 Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Tue, 29 Mar 2011 09:45:57 -0700 Subject: PCI: pci-label: Fix build failure when CONFIG_NLS is set to 'm' by allmodconfig Create a kconfig option symbol for PCI_LABEL and enable it when DMI || ACPI are enabled. Signed-off-by: Randy Dunlap Signed-off-by: Jesse Barnes diff --git a/drivers/pci/Kconfig b/drivers/pci/Kconfig index c8ff646..0fa466a 100644 --- a/drivers/pci/Kconfig +++ b/drivers/pci/Kconfig @@ -88,4 +88,6 @@ config PCI_IOAPIC depends on HOTPLUG default y -select NLS if (DMI || ACPI) +config PCI_LABEL + def_bool y if (DMI || ACPI) + select NLS diff --git a/drivers/pci/Makefile b/drivers/pci/Makefile index 98d61c8..c85f744 100644 --- a/drivers/pci/Makefile +++ b/drivers/pci/Makefile @@ -56,10 +56,10 @@ obj-$(CONFIG_TILE) += setup-bus.o setup-irq.o # ACPI Related PCI FW Functions # ACPI _DSM provided firmware instance and string name # -obj-$(CONFIG_ACPI) += pci-acpi.o pci-label.o +obj-$(CONFIG_ACPI) += pci-acpi.o # SMBIOS provided firmware instance and labels -obj-$(CONFIG_DMI) += pci-label.o +obj-$(CONFIG_PCI_LABEL) += pci-label.o # Cardbus & CompactPCI use setup-bus obj-$(CONFIG_HOTPLUG) += setup-bus.o -- cgit v0.10.2 From d5627663f2088fa4be447fdcfd52bcb233448d85 Mon Sep 17 00:00:00 2001 From: Mathew McKernan Date: Tue, 12 Apr 2011 06:51:37 +0100 Subject: drm/i915/tv: Remember the detected TV type During detect() we would probe the connection bits to determine if there was a TV attached, and what video input type (Component, S-Video, Composite, etc) to use. However, we promptly discarded this vital bit of information and never propagated it to where it was used to determine the correct modes and setup the control registers. Fix it! This fixes a regression from 7b334fcb45b757ffb093696ca3de1b0c8b4a33f1. Reported-and-tested-by: Mathew McKernan Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=35977 Signed-off-by: Mathew McKernan Signed-off-by: Chris Wilson Cc: stable@kernel.org Acked-by: Paul Menzel Signed-off-by: Keith Packard diff --git a/drivers/gpu/drm/i915/intel_tv.c b/drivers/gpu/drm/i915/intel_tv.c index 4256b8ef..0be2265 100644 --- a/drivers/gpu/drm/i915/intel_tv.c +++ b/drivers/gpu/drm/i915/intel_tv.c @@ -1378,7 +1378,9 @@ intel_tv_detect(struct drm_connector *connector, bool force) if (type < 0) return connector_status_disconnected; + intel_tv->type = type; intel_tv_find_better_format(connector); + return connector_status_connected; } -- cgit v0.10.2 From 89ea42d716e1ee94f643ecdc516d90a4111ec135 Mon Sep 17 00:00:00 2001 From: Mathew McKernan Date: Tue, 12 Apr 2011 06:51:38 +0100 Subject: drm/i915/tv: Only poll for TV connections As a probe for a TV connection modifies the TV_CTL register, it causes a loss of sync and a regular glitch on the output. This is highly undesirable when using the TV, so only poll for TV connections and wait for an explicit query for detecting the disconnection event. Reported-by: Mathew McKernan Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=35977 Signed-off-by: Mathew McKernan Signed-off-by: Chris Wilson Signed-off-by: Keith Packard diff --git a/drivers/gpu/drm/i915/intel_tv.c b/drivers/gpu/drm/i915/intel_tv.c index 0be2265..f5848cb 100644 --- a/drivers/gpu/drm/i915/intel_tv.c +++ b/drivers/gpu/drm/i915/intel_tv.c @@ -1672,8 +1672,7 @@ intel_tv_init(struct drm_device *dev) * * More recent chipsets favour HDMI rather than integrated S-Video. */ - connector->polled = - DRM_CONNECTOR_POLL_CONNECT | DRM_CONNECTOR_POLL_DISCONNECT; + connector->polled = DRM_CONNECTOR_POLL_CONNECT; drm_connector_init(dev, connector, &intel_tv_connector_funcs, DRM_MODE_CONNECTOR_SVIDEO); -- cgit v0.10.2 From ccacfec6cc22157971bd970486fd3fd4972b8e2e Mon Sep 17 00:00:00 2001 From: Sitsofe Wheeler Date: Tue, 12 Apr 2011 06:51:39 +0100 Subject: drm/i915/tv: Fix modeset flickering introduced in 7f58aabc3 The tidy ups in 7f58aabc369014fda3a4a33604ba0a1b63b941ac ("drm/i915: cleanup per-pipe reg usage") changed intel_crtc->plane to intel_crtc->pipe in intel_tv_mode_set(). This caused the screen to quickly turn off before returning whenever modesetting/mode probing took place on my 915GM EeePC 900 creating a flickering effect. This patch changes intel_crtc->pipe back to intel_crtc->plane which solves the problem for me. References: https://bugs.freedesktop.org/show_bug.cgi?id=35903 Signed-off-by: Sitsofe Wheeler Cc: Jesse Barnes Signed-off-by: Chris Wilson Humbly-acked-by: Jesse Barnes Signed-off-by: Keith Packard diff --git a/drivers/gpu/drm/i915/intel_tv.c b/drivers/gpu/drm/i915/intel_tv.c index f5848cb..6b22c1d 100644 --- a/drivers/gpu/drm/i915/intel_tv.c +++ b/drivers/gpu/drm/i915/intel_tv.c @@ -1151,10 +1151,10 @@ intel_tv_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode, (video_levels->blank << TV_BLANK_LEVEL_SHIFT))); { int pipeconf_reg = PIPECONF(pipe); - int dspcntr_reg = DSPCNTR(pipe); + int dspcntr_reg = DSPCNTR(intel_crtc->plane); int pipeconf = I915_READ(pipeconf_reg); int dspcntr = I915_READ(dspcntr_reg); - int dspbase_reg = DSPADDR(pipe); + int dspbase_reg = DSPADDR(intel_crtc->plane); int xpos = 0x0, ypos = 0x0; unsigned int xsize, ysize; /* Pipe must be off here */ -- cgit v0.10.2 From d83d282bcbf24ec8ddd4f0eb57f7ad302c431b8a Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Mon, 11 Apr 2011 16:00:00 -0700 Subject: s2io: Fix warnings due to -Wunused-but-set-variable. Most of these are cases where we are trying to read back a register after a write to ensure completion. Simply pre-fixing the readl() or readq() with "(void)" is sufficient because these are volatile operations and the compiler cannot eliminate them just because no real assignment takes place. The case of free_rxd_blk()'s assignments to "struct buffAdd *ba" is a real spurious assignment as this variable is completely otherwise unused. Signed-off-by: David S. Miller Acked-by: Jon Mason diff --git a/drivers/net/s2io.c b/drivers/net/s2io.c index ca8e75e..2d5cc61 100644 --- a/drivers/net/s2io.c +++ b/drivers/net/s2io.c @@ -2244,13 +2244,12 @@ static int verify_xena_quiescence(struct s2io_nic *sp) static void fix_mac_address(struct s2io_nic *sp) { struct XENA_dev_config __iomem *bar0 = sp->bar0; - u64 val64; int i = 0; while (fix_mac[i] != END_SIGN) { writeq(fix_mac[i++], &bar0->gpio_control); udelay(10); - val64 = readq(&bar0->gpio_control); + (void) readq(&bar0->gpio_control); } } @@ -2727,7 +2726,6 @@ static void free_rxd_blk(struct s2io_nic *sp, int ring_no, int blk) int j; struct sk_buff *skb; struct RxD_t *rxdp; - struct buffAdd *ba; struct RxD1 *rxdp1; struct RxD3 *rxdp3; struct mac_info *mac_control = &sp->mac_control; @@ -2751,7 +2749,6 @@ static void free_rxd_blk(struct s2io_nic *sp, int ring_no, int blk) memset(rxdp, 0, sizeof(struct RxD1)); } else if (sp->rxd_mode == RXD_MODE_3B) { rxdp3 = (struct RxD3 *)rxdp; - ba = &mac_control->rings[ring_no].ba[blk][j]; pci_unmap_single(sp->pdev, (dma_addr_t)rxdp3->Buffer0_ptr, BUF0_LEN, diff --git a/drivers/net/s2io.h b/drivers/net/s2io.h index 628fd27..800b3a4 100644 --- a/drivers/net/s2io.h +++ b/drivers/net/s2io.h @@ -1002,18 +1002,16 @@ static inline void writeq(u64 val, void __iomem *addr) #define LF 2 static inline void SPECIAL_REG_WRITE(u64 val, void __iomem *addr, int order) { - u32 ret; - if (order == LF) { writel((u32) (val), addr); - ret = readl(addr); + (void) readl(addr); writel((u32) (val >> 32), (addr + 4)); - ret = readl(addr + 4); + (void) readl(addr + 4); } else { writel((u32) (val >> 32), (addr + 4)); - ret = readl(addr + 4); + (void) readl(addr + 4); writel((u32) (val), addr); - ret = readl(addr); + (void) readl(addr); } } -- cgit v0.10.2 From cd883a791b55c3c52ce402cd551585fed092d240 Mon Sep 17 00:00:00 2001 From: Jon Mason Date: Fri, 8 Apr 2011 11:11:21 +0000 Subject: vxge: always enable hardware time stamp Hardware time stamp calculation can only be enabled by the privileged function. Enable it always by default and simply use the ethtool interface to set a flag to indicate whether or not the respective function driver should indicate the timestamp along with the received packet. Also, make certain fields in vxge_hw_device_config bit-fields to reduce the size of the struct. Signed-off-by: Jon Mason Signed-off-by: David S. Miller diff --git a/drivers/net/vxge/vxge-config.h b/drivers/net/vxge/vxge-config.h index 3c53aa7..359b9b9 100644 --- a/drivers/net/vxge/vxge-config.h +++ b/drivers/net/vxge/vxge-config.h @@ -412,44 +412,48 @@ struct vxge_hw_vp_config { * See also: struct vxge_hw_tim_intr_config{}. */ struct vxge_hw_device_config { - u32 dma_blockpool_initial; - u32 dma_blockpool_max; -#define VXGE_HW_MIN_DMA_BLOCK_POOL_SIZE 0 -#define VXGE_HW_INITIAL_DMA_BLOCK_POOL_SIZE 0 -#define VXGE_HW_INCR_DMA_BLOCK_POOL_SIZE 4 -#define VXGE_HW_MAX_DMA_BLOCK_POOL_SIZE 4096 - -#define VXGE_HW_MAX_PAYLOAD_SIZE_512 2 - - u32 intr_mode; -#define VXGE_HW_INTR_MODE_IRQLINE 0 -#define VXGE_HW_INTR_MODE_MSIX 1 -#define VXGE_HW_INTR_MODE_MSIX_ONE_SHOT 2 - -#define VXGE_HW_INTR_MODE_DEF 0 - - u32 rth_en; -#define VXGE_HW_RTH_DISABLE 0 -#define VXGE_HW_RTH_ENABLE 1 -#define VXGE_HW_RTH_DEFAULT 0 - - u32 rth_it_type; -#define VXGE_HW_RTH_IT_TYPE_SOLO_IT 0 -#define VXGE_HW_RTH_IT_TYPE_MULTI_IT 1 -#define VXGE_HW_RTH_IT_TYPE_DEFAULT 0 - - u32 rts_mac_en; + u32 device_poll_millis; +#define VXGE_HW_MIN_DEVICE_POLL_MILLIS 1 +#define VXGE_HW_MAX_DEVICE_POLL_MILLIS 100000 +#define VXGE_HW_DEF_DEVICE_POLL_MILLIS 1000 + + u32 dma_blockpool_initial; + u32 dma_blockpool_max; +#define VXGE_HW_MIN_DMA_BLOCK_POOL_SIZE 0 +#define VXGE_HW_INITIAL_DMA_BLOCK_POOL_SIZE 0 +#define VXGE_HW_INCR_DMA_BLOCK_POOL_SIZE 4 +#define VXGE_HW_MAX_DMA_BLOCK_POOL_SIZE 4096 + +#define VXGE_HW_MAX_PAYLOAD_SIZE_512 2 + + u32 intr_mode:2, +#define VXGE_HW_INTR_MODE_IRQLINE 0 +#define VXGE_HW_INTR_MODE_MSIX 1 +#define VXGE_HW_INTR_MODE_MSIX_ONE_SHOT 2 + +#define VXGE_HW_INTR_MODE_DEF 0 + + rth_en:1, +#define VXGE_HW_RTH_DISABLE 0 +#define VXGE_HW_RTH_ENABLE 1 +#define VXGE_HW_RTH_DEFAULT 0 + + rth_it_type:1, +#define VXGE_HW_RTH_IT_TYPE_SOLO_IT 0 +#define VXGE_HW_RTH_IT_TYPE_MULTI_IT 1 +#define VXGE_HW_RTH_IT_TYPE_DEFAULT 0 + + rts_mac_en:1, #define VXGE_HW_RTS_MAC_DISABLE 0 #define VXGE_HW_RTS_MAC_ENABLE 1 #define VXGE_HW_RTS_MAC_DEFAULT 0 - struct vxge_hw_vp_config vp_config[VXGE_HW_MAX_VIRTUAL_PATHS]; - - u32 device_poll_millis; -#define VXGE_HW_MIN_DEVICE_POLL_MILLIS 1 -#define VXGE_HW_MAX_DEVICE_POLL_MILLIS 100000 -#define VXGE_HW_DEF_DEVICE_POLL_MILLIS 1000 + hwts_en:1; +#define VXGE_HW_HWTS_DISABLE 0 +#define VXGE_HW_HWTS_ENABLE 1 +#define VXGE_HW_HWTS_DEFAULT 1 + struct vxge_hw_vp_config vp_config[VXGE_HW_MAX_VIRTUAL_PATHS]; }; /** diff --git a/drivers/net/vxge/vxge-main.c b/drivers/net/vxge/vxge-main.c index aff68c1..d192dad 100644 --- a/drivers/net/vxge/vxge-main.c +++ b/drivers/net/vxge/vxge-main.c @@ -3112,8 +3112,7 @@ vxge_get_stats64(struct net_device *dev, struct rtnl_link_stats64 *net_stats) return net_stats; } -static enum vxge_hw_status vxge_timestamp_config(struct vxgedev *vdev, - int enable) +static enum vxge_hw_status vxge_timestamp_config(struct __vxge_hw_device *devh) { enum vxge_hw_status status; u64 val64; @@ -3123,27 +3122,24 @@ static enum vxge_hw_status vxge_timestamp_config(struct vxgedev *vdev, * required for the driver to load (due to a hardware bug), * there is no need to do anything special here. */ - if (enable) - val64 = VXGE_HW_XMAC_TIMESTAMP_EN | - VXGE_HW_XMAC_TIMESTAMP_USE_LINK_ID(0) | - VXGE_HW_XMAC_TIMESTAMP_INTERVAL(0); - else - val64 = 0; + val64 = VXGE_HW_XMAC_TIMESTAMP_EN | + VXGE_HW_XMAC_TIMESTAMP_USE_LINK_ID(0) | + VXGE_HW_XMAC_TIMESTAMP_INTERVAL(0); - status = vxge_hw_mgmt_reg_write(vdev->devh, + status = vxge_hw_mgmt_reg_write(devh, vxge_hw_mgmt_reg_type_mrpcim, 0, offsetof(struct vxge_hw_mrpcim_reg, xmac_timestamp), val64); - vxge_hw_device_flush_io(vdev->devh); + vxge_hw_device_flush_io(devh); + devh->config.hwts_en = VXGE_HW_HWTS_ENABLE; return status; } static int vxge_hwtstamp_ioctl(struct vxgedev *vdev, void __user *data) { struct hwtstamp_config config; - enum vxge_hw_status status; int i; if (copy_from_user(&config, data, sizeof(config))) @@ -3164,10 +3160,6 @@ static int vxge_hwtstamp_ioctl(struct vxgedev *vdev, void __user *data) switch (config.rx_filter) { case HWTSTAMP_FILTER_NONE: - status = vxge_timestamp_config(vdev, 0); - if (status != VXGE_HW_OK) - return -EFAULT; - vdev->rx_hwts = 0; config.rx_filter = HWTSTAMP_FILTER_NONE; break; @@ -3186,8 +3178,7 @@ static int vxge_hwtstamp_ioctl(struct vxgedev *vdev, void __user *data) case HWTSTAMP_FILTER_PTP_V2_EVENT: case HWTSTAMP_FILTER_PTP_V2_SYNC: case HWTSTAMP_FILTER_PTP_V2_DELAY_REQ: - status = vxge_timestamp_config(vdev, 1); - if (status != VXGE_HW_OK) + if (vdev->devh->config.hwts_en != VXGE_HW_HWTS_ENABLE) return -EFAULT; vdev->rx_hwts = 1; @@ -4575,6 +4566,24 @@ vxge_probe(struct pci_dev *pdev, const struct pci_device_id *pre) goto _exit4; } + /* Always enable HWTS. This will always cause the FCS to be invalid, + * due to the fact that HWTS is using the FCS as the location of the + * timestamp. The HW FCS checking will still correctly determine if + * there is a valid checksum, and the FCS is being removed by the driver + * anyway. So no fucntionality is being lost. Since it is always + * enabled, we now simply use the ioctl call to set whether or not the + * driver should be paying attention to the HWTS. + */ + if (is_privileged == VXGE_HW_OK) { + status = vxge_timestamp_config(hldev); + if (status != VXGE_HW_OK) { + vxge_debug_init(VXGE_ERR, "%s: HWTS enable failed", + VXGE_DRIVER_NAME); + ret = -EFAULT; + goto _exit4; + } + } + vxge_hw_device_debug_set(hldev, VXGE_ERR, VXGE_COMPONENT_LL); /* set private device info */ diff --git a/drivers/net/vxge/vxge-traffic.h b/drivers/net/vxge/vxge-traffic.h index 6c2fc0b..4a518a3 100644 --- a/drivers/net/vxge/vxge-traffic.h +++ b/drivers/net/vxge/vxge-traffic.h @@ -240,7 +240,7 @@ struct vxge_hw_tim_intr_config { u32 btimer_val; #define VXGE_HW_MIN_TIM_BTIMER_VAL 0 #define VXGE_HW_MAX_TIM_BTIMER_VAL 67108864 -#define VXGE_HW_USE_FLASH_DEFAULT 0xffffffff +#define VXGE_HW_USE_FLASH_DEFAULT (~0) u32 timer_ac_en; #define VXGE_HW_TIM_TIMER_AC_ENABLE 1 -- cgit v0.10.2 From 9f9b16458134ba9f06ef6f15369513aa9eebc81c Mon Sep 17 00:00:00 2001 From: Jon Mason Date: Fri, 8 Apr 2011 11:11:22 +0000 Subject: vxge: spin-lock issue In vxge_hw_vpath_close, __vxge_hw_vp_terminate memsets the vpath which clobbers the spin lock state, then the driver attempts to acquire the spin lock. Resolve this by not zeroing the lock part of vpath struct, clean-up vpath locking in init, close, and fix locking hole in fw_api call. Issue found by Bob Picco Signed-off-by: Jon Mason Signed-off-by: David S. Miller diff --git a/drivers/net/vxge/vxge-config.c b/drivers/net/vxge/vxge-config.c index 401bebf..32763b2 100644 --- a/drivers/net/vxge/vxge-config.c +++ b/drivers/net/vxge/vxge-config.c @@ -159,16 +159,15 @@ vxge_hw_vpath_fw_api(struct __vxge_hw_virtualpath *vpath, u32 action, u32 fw_memo, u32 offset, u64 *data0, u64 *data1, u64 *steer_ctrl) { - struct vxge_hw_vpath_reg __iomem *vp_reg; + struct vxge_hw_vpath_reg __iomem *vp_reg = vpath->vp_reg; enum vxge_hw_status status; u64 val64; - u32 retry = 0, max_retry = 100; - - vp_reg = vpath->vp_reg; + u32 retry = 0, max_retry = 3; - if (vpath->vp_open) { - max_retry = 3; - spin_lock(&vpath->lock); + spin_lock(&vpath->lock); + if (!vpath->vp_open) { + spin_unlock(&vpath->lock); + max_retry = 100; } writeq(*data0, &vp_reg->rts_access_steer_data0); @@ -1000,7 +999,7 @@ exit: /** * vxge_hw_device_hw_info_get - Get the hw information * Returns the vpath mask that has the bits set for each vpath allocated - * for the driver, FW version information and the first mac addresse for + * for the driver, FW version information, and the first mac address for * each vpath */ enum vxge_hw_status __devinit @@ -1064,9 +1063,10 @@ vxge_hw_device_hw_info_get(void __iomem *bar0, val64 = readq(&toc->toc_vpath_pointer[i]); + spin_lock_init(&vpath.lock); vpath.vp_reg = (struct vxge_hw_vpath_reg __iomem *) (bar0 + val64); - vpath.vp_open = 0; + vpath.vp_open = VXGE_HW_VP_NOT_OPEN; status = __vxge_hw_vpath_pci_func_mode_get(&vpath, hw_info); if (status != VXGE_HW_OK) @@ -1090,7 +1090,7 @@ vxge_hw_device_hw_info_get(void __iomem *bar0, val64 = readq(&toc->toc_vpath_pointer[i]); vpath.vp_reg = (struct vxge_hw_vpath_reg __iomem *) (bar0 + val64); - vpath.vp_open = 0; + vpath.vp_open = VXGE_HW_VP_NOT_OPEN; status = __vxge_hw_vpath_addr_get(&vpath, hw_info->mac_addrs[i], @@ -4646,7 +4646,27 @@ static void __vxge_hw_vp_terminate(struct __vxge_hw_device *hldev, u32 vp_id) vpath->hldev->tim_int_mask1, vpath->vp_id); hldev->stats.hw_dev_info_stats.vpath_info[vpath->vp_id] = NULL; - memset(vpath, 0, sizeof(struct __vxge_hw_virtualpath)); + /* If the whole struct __vxge_hw_virtualpath is zeroed, nothing will + * work after the interface is brought down. + */ + spin_lock(&vpath->lock); + vpath->vp_open = VXGE_HW_VP_NOT_OPEN; + spin_unlock(&vpath->lock); + + vpath->vpmgmt_reg = NULL; + vpath->nofl_db = NULL; + vpath->max_mtu = 0; + vpath->vsport_number = 0; + vpath->max_kdfc_db = 0; + vpath->max_nofl_db = 0; + vpath->ringh = NULL; + vpath->fifoh = NULL; + memset(&vpath->vpath_handles, 0, sizeof(struct list_head)); + vpath->stats_block = 0; + vpath->hw_stats = NULL; + vpath->hw_stats_sav = NULL; + vpath->sw_stats = NULL; + exit: return; } @@ -4670,7 +4690,7 @@ __vxge_hw_vp_initialize(struct __vxge_hw_device *hldev, u32 vp_id, vpath = &hldev->virtual_paths[vp_id]; - spin_lock_init(&hldev->virtual_paths[vp_id].lock); + spin_lock_init(&vpath->lock); vpath->vp_id = vp_id; vpath->vp_open = VXGE_HW_VP_OPEN; vpath->hldev = hldev; @@ -5019,10 +5039,6 @@ enum vxge_hw_status vxge_hw_vpath_close(struct __vxge_hw_vpath_handle *vp) __vxge_hw_vp_terminate(devh, vp_id); - spin_lock(&vpath->lock); - vpath->vp_open = VXGE_HW_VP_NOT_OPEN; - spin_unlock(&vpath->lock); - vpath_close_exit: return status; } -- cgit v0.10.2 From 6ba1037c3d871ab70e342631516dbf841c35b086 Mon Sep 17 00:00:00 2001 From: Jon Mason Date: Fri, 8 Apr 2011 11:11:23 +0000 Subject: vxge: update driver version Update vxge driver version to 2.5.3 Signed-off-by: Jon Mason Signed-off-by: David S. Miller diff --git a/drivers/net/vxge/vxge-version.h b/drivers/net/vxge/vxge-version.h index 581e215..b9efa28 100644 --- a/drivers/net/vxge/vxge-version.h +++ b/drivers/net/vxge/vxge-version.h @@ -16,8 +16,8 @@ #define VXGE_VERSION_MAJOR "2" #define VXGE_VERSION_MINOR "5" -#define VXGE_VERSION_FIX "2" -#define VXGE_VERSION_BUILD "22259" +#define VXGE_VERSION_FIX "3" +#define VXGE_VERSION_BUILD "22640" #define VXGE_VERSION_FOR "k" #define VXGE_FW_VER(maj, min, bld) (((maj) << 16) + ((min) << 8) + (bld)) -- cgit v0.10.2 From f6e5b1603b8bb7131b6778d0d4e2e5dda120a379 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Tue, 12 Apr 2011 18:06:51 +0100 Subject: drm/i915: Sanitize the output registers after resume Similar to booting, we need to inspect the state left by the BIOS and remove any conflicting bits before we take over. The example reported by Seth Forshee is very similar to the bug we encountered with the state left by grub2, that the crtc pipe<->planning mapping was reversed from our expectations and so we failed to turn off the outputs when booting or, in this case, resuming. This may be in fact the same bug, but triggered at resume time. This patch rearranges the code we already have to clear up the conflicting state upon init and calls it from reset (which is called after we have lost control of the hardware, i.e. along both the boot and resume paths) instead. Reported-and-tested-by: Seth Forshee Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=35796 Signed-off-by: Chris Wilson Cc: stable@kernel.org Reviewed-by: Keith Packard Signed-off-by: Keith Packard diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 432fc04..4fc21e0 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -6215,36 +6215,6 @@ cleanup_work: return ret; } -static void intel_crtc_reset(struct drm_crtc *crtc) -{ - struct intel_crtc *intel_crtc = to_intel_crtc(crtc); - - /* Reset flags back to the 'unknown' status so that they - * will be correctly set on the initial modeset. - */ - intel_crtc->dpms_mode = -1; -} - -static struct drm_crtc_helper_funcs intel_helper_funcs = { - .dpms = intel_crtc_dpms, - .mode_fixup = intel_crtc_mode_fixup, - .mode_set = intel_crtc_mode_set, - .mode_set_base = intel_pipe_set_base, - .mode_set_base_atomic = intel_pipe_set_base_atomic, - .load_lut = intel_crtc_load_lut, - .disable = intel_crtc_disable, -}; - -static const struct drm_crtc_funcs intel_crtc_funcs = { - .reset = intel_crtc_reset, - .cursor_set = intel_crtc_cursor_set, - .cursor_move = intel_crtc_cursor_move, - .gamma_set = intel_crtc_gamma_set, - .set_config = drm_crtc_helper_set_config, - .destroy = intel_crtc_destroy, - .page_flip = intel_crtc_page_flip, -}; - static void intel_sanitize_modesetting(struct drm_device *dev, int pipe, int plane) { @@ -6281,6 +6251,42 @@ static void intel_sanitize_modesetting(struct drm_device *dev, intel_disable_pipe(dev_priv, pipe); } +static void intel_crtc_reset(struct drm_crtc *crtc) +{ + struct drm_device *dev = crtc->dev; + struct intel_crtc *intel_crtc = to_intel_crtc(crtc); + + /* Reset flags back to the 'unknown' status so that they + * will be correctly set on the initial modeset. + */ + intel_crtc->dpms_mode = -1; + + /* We need to fix up any BIOS configuration that conflicts with + * our expectations. + */ + intel_sanitize_modesetting(dev, intel_crtc->pipe, intel_crtc->plane); +} + +static struct drm_crtc_helper_funcs intel_helper_funcs = { + .dpms = intel_crtc_dpms, + .mode_fixup = intel_crtc_mode_fixup, + .mode_set = intel_crtc_mode_set, + .mode_set_base = intel_pipe_set_base, + .mode_set_base_atomic = intel_pipe_set_base_atomic, + .load_lut = intel_crtc_load_lut, + .disable = intel_crtc_disable, +}; + +static const struct drm_crtc_funcs intel_crtc_funcs = { + .reset = intel_crtc_reset, + .cursor_set = intel_crtc_cursor_set, + .cursor_move = intel_crtc_cursor_move, + .gamma_set = intel_crtc_gamma_set, + .set_config = drm_crtc_helper_set_config, + .destroy = intel_crtc_destroy, + .page_flip = intel_crtc_page_flip, +}; + static void intel_crtc_init(struct drm_device *dev, int pipe) { drm_i915_private_t *dev_priv = dev->dev_private; @@ -6330,8 +6336,6 @@ static void intel_crtc_init(struct drm_device *dev, int pipe) setup_timer(&intel_crtc->idle_timer, intel_crtc_idle_timer, (unsigned long)intel_crtc); - - intel_sanitize_modesetting(dev, intel_crtc->pipe, intel_crtc->plane); } int intel_get_pipe_from_crtc_id(struct drm_device *dev, void *data, -- cgit v0.10.2 From f8e9881c2aef1e982e5abc25c046820cd0b7cf64 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Tue, 12 Apr 2011 13:39:14 -0700 Subject: bridge: reset IPCB in br_parse_ip_options MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Commit 462fb2af9788a82 (bridge : Sanitize skb before it enters the IP stack), missed one IPCB init before calling ip_options_compile() Thanks to Scot Doyle for his tests and bug reports. Reported-by: Scot Doyle Signed-off-by: Eric Dumazet Cc: Hiroaki SHIMODA Acked-by: Bandan Das Acked-by: Stephen Hemminger Cc: Jan Lübbe Signed-off-by: David S. Miller diff --git a/net/bridge/br_netfilter.c b/net/bridge/br_netfilter.c index 008ff6c..f3bc322 100644 --- a/net/bridge/br_netfilter.c +++ b/net/bridge/br_netfilter.c @@ -249,11 +249,9 @@ static int br_parse_ip_options(struct sk_buff *skb) goto drop; } - /* Zero out the CB buffer if no options present */ - if (iph->ihl == 5) { - memset(IPCB(skb), 0, sizeof(struct inet_skb_parm)); + memset(IPCB(skb), 0, sizeof(struct inet_skb_parm)); + if (iph->ihl == 5) return 0; - } opt->optlen = iph->ihl*4 - sizeof(struct iphdr); if (ip_options_compile(dev_net(dev), opt, skb)) -- cgit v0.10.2 From 5882da02e9d9089b7e8c739f3e774aaeeff8b7ba Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Fri, 8 Apr 2011 20:13:18 +0200 Subject: ath9k_hw: fix stopping rx DMA during resets During PHY errors, the MAC can sometimes fail to enter an idle state on older hardware (before AR9380) after an rx stop has been requested. This typically shows up in the kernel log with messages like these: ath: Could not stop RX, we could be confusing the DMA engine when we start RX up ------------[ cut here ]------------ WARNING: at drivers/net/wireless/ath/ath9k/recv.c:504 ath_stoprecv+0xcc/0xf0 [ath9k]() Call Trace: [<8023f0e8>] dump_stack+0x8/0x34 [<80075050>] warn_slowpath_common+0x78/0xa4 [<80075094>] warn_slowpath_null+0x18/0x24 [<80d66d60>] ath_stoprecv+0xcc/0xf0 [ath9k] [<80d642cc>] ath_set_channel+0xbc/0x270 [ath9k] [<80d65254>] ath_radio_disable+0x4a4/0x7fc [ath9k] When this happens, the state that the MAC enters is easy to identify and does not result in bogus DMA traffic, however to ensure a working state after a channel change, the hardware should still be reset. This patch adds detection for this specific MAC state, after which the above warnings completely disappear in my tests. Signed-off-by: Felix Fietkau Cc: stable@kernel.org Cc: Kyungwan Nam Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index 1ec9bcd..c95bc5c 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c @@ -1254,15 +1254,6 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan, ah->txchainmask = common->tx_chainmask; ah->rxchainmask = common->rx_chainmask; - if ((common->bus_ops->ath_bus_type != ATH_USB) && !ah->chip_fullsleep) { - ath9k_hw_abortpcurecv(ah); - if (!ath9k_hw_stopdmarecv(ah)) { - ath_dbg(common, ATH_DBG_XMIT, - "Failed to stop receive dma\n"); - bChannelChange = false; - } - } - if (!ath9k_hw_setpower(ah, ATH9K_PM_AWAKE)) return -EIO; diff --git a/drivers/net/wireless/ath/ath9k/mac.c b/drivers/net/wireless/ath/ath9k/mac.c index 562257a..edc1cbb 100644 --- a/drivers/net/wireless/ath/ath9k/mac.c +++ b/drivers/net/wireless/ath/ath9k/mac.c @@ -751,28 +751,47 @@ void ath9k_hw_abortpcurecv(struct ath_hw *ah) } EXPORT_SYMBOL(ath9k_hw_abortpcurecv); -bool ath9k_hw_stopdmarecv(struct ath_hw *ah) +bool ath9k_hw_stopdmarecv(struct ath_hw *ah, bool *reset) { #define AH_RX_STOP_DMA_TIMEOUT 10000 /* usec */ #define AH_RX_TIME_QUANTUM 100 /* usec */ struct ath_common *common = ath9k_hw_common(ah); + u32 mac_status, last_mac_status = 0; int i; + /* Enable access to the DMA observation bus */ + REG_WRITE(ah, AR_MACMISC, + ((AR_MACMISC_DMA_OBS_LINE_8 << AR_MACMISC_DMA_OBS_S) | + (AR_MACMISC_MISC_OBS_BUS_1 << + AR_MACMISC_MISC_OBS_BUS_MSB_S))); + REG_WRITE(ah, AR_CR, AR_CR_RXD); /* Wait for rx enable bit to go low */ for (i = AH_RX_STOP_DMA_TIMEOUT / AH_TIME_QUANTUM; i != 0; i--) { if ((REG_READ(ah, AR_CR) & AR_CR_RXE) == 0) break; + + if (!AR_SREV_9300_20_OR_LATER(ah)) { + mac_status = REG_READ(ah, AR_DMADBG_7) & 0x7f0; + if (mac_status == 0x1c0 && mac_status == last_mac_status) { + *reset = true; + break; + } + + last_mac_status = mac_status; + } + udelay(AH_TIME_QUANTUM); } if (i == 0) { ath_err(common, - "DMA failed to stop in %d ms AR_CR=0x%08x AR_DIAG_SW=0x%08x\n", + "DMA failed to stop in %d ms AR_CR=0x%08x AR_DIAG_SW=0x%08x DMADBG_7=0x%08x\n", AH_RX_STOP_DMA_TIMEOUT / 1000, REG_READ(ah, AR_CR), - REG_READ(ah, AR_DIAG_SW)); + REG_READ(ah, AR_DIAG_SW), + REG_READ(ah, AR_DMADBG_7)); return false; } else { return true; diff --git a/drivers/net/wireless/ath/ath9k/mac.h b/drivers/net/wireless/ath/ath9k/mac.h index b2b2ff8..c2a5938 100644 --- a/drivers/net/wireless/ath/ath9k/mac.h +++ b/drivers/net/wireless/ath/ath9k/mac.h @@ -695,7 +695,7 @@ bool ath9k_hw_setrxabort(struct ath_hw *ah, bool set); void ath9k_hw_putrxbuf(struct ath_hw *ah, u32 rxdp); void ath9k_hw_startpcureceive(struct ath_hw *ah, bool is_scanning); void ath9k_hw_abortpcurecv(struct ath_hw *ah); -bool ath9k_hw_stopdmarecv(struct ath_hw *ah); +bool ath9k_hw_stopdmarecv(struct ath_hw *ah, bool *reset); int ath9k_hw_beaconq_setup(struct ath_hw *ah); /* Interrupt Handling */ diff --git a/drivers/net/wireless/ath/ath9k/recv.c b/drivers/net/wireless/ath/ath9k/recv.c index a9c3f46..dcd19bc 100644 --- a/drivers/net/wireless/ath/ath9k/recv.c +++ b/drivers/net/wireless/ath/ath9k/recv.c @@ -486,12 +486,12 @@ start_recv: bool ath_stoprecv(struct ath_softc *sc) { struct ath_hw *ah = sc->sc_ah; - bool stopped; + bool stopped, reset = false; spin_lock_bh(&sc->rx.rxbuflock); ath9k_hw_abortpcurecv(ah); ath9k_hw_setrxfilter(ah, 0); - stopped = ath9k_hw_stopdmarecv(ah); + stopped = ath9k_hw_stopdmarecv(ah, &reset); if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) ath_edma_stop_recv(sc); @@ -506,7 +506,7 @@ bool ath_stoprecv(struct ath_softc *sc) "confusing the DMA engine when we start RX up\n"); ATH_DBG_WARN_ON_ONCE(!stopped); } - return stopped; + return stopped || reset; } void ath_flushrecv(struct ath_softc *sc) -- cgit v0.10.2 From 50f6871218802be528961e24487f00c203a5c3c7 Mon Sep 17 00:00:00 2001 From: Sujith Manoharan Date: Mon, 11 Apr 2011 22:56:55 +0530 Subject: ath9k_htc: Fix ethtool reporting Pass the correct module name and device interface so that ethtool can display the proper values. The firmware version will be fixed later on when the FW can actually report a version. :) Reported-by: Richard Farina Signed-off-by: Sujith Manoharan Tested-by: Richard Farina Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/hif_usb.c b/drivers/net/wireless/ath/ath9k/hif_usb.c index f1b8af6..2d10239 100644 --- a/drivers/net/wireless/ath/ath9k/hif_usb.c +++ b/drivers/net/wireless/ath/ath9k/hif_usb.c @@ -1040,7 +1040,7 @@ static int ath9k_hif_usb_probe(struct usb_interface *interface, } ret = ath9k_htc_hw_init(hif_dev->htc_handle, - &hif_dev->udev->dev, hif_dev->device_id, + &interface->dev, hif_dev->device_id, hif_dev->udev->product, id->driver_info); if (ret) { ret = -EINVAL; @@ -1158,7 +1158,7 @@ fail_resume: #endif static struct usb_driver ath9k_hif_usb_driver = { - .name = "ath9k_hif_usb", + .name = KBUILD_MODNAME, .probe = ath9k_hif_usb_probe, .disconnect = ath9k_hif_usb_disconnect, #ifdef CONFIG_PM -- cgit v0.10.2 From 143780c6562080c1117cd9197ee1b33c0d838376 Mon Sep 17 00:00:00 2001 From: "Allan, Bruce W" Date: Mon, 11 Apr 2011 13:01:59 +0000 Subject: ethtool: time to blink provided in seconds not jiffies When blinking for a duration set by the user, the value specified is in seconds but it is used as the number of jiffies in the timeout after which the Physical ID indicator is deactivated. Fix by converting the timeout to seconds. Signed-off-by: Bruce Allan Acked-by: Ben Hutchings Signed-off-by: David S. Miller diff --git a/net/core/ethtool.c b/net/core/ethtool.c index 704e176..43ef09f 100644 --- a/net/core/ethtool.c +++ b/net/core/ethtool.c @@ -1653,7 +1653,7 @@ static int ethtool_phys_id(struct net_device *dev, void __user *useraddr) if (rc == 0) { /* Driver will handle this itself */ schedule_timeout_interruptible( - id.data ? id.data : MAX_SCHEDULE_TIMEOUT); + id.data ? (id.data * HZ) : MAX_SCHEDULE_TIMEOUT); } else { /* Driver expects to be called periodically */ do { -- cgit v0.10.2 From e8306f989483e4b97a8b37dd268de6c8c6f35e75 Mon Sep 17 00:00:00 2001 From: Vivek Natarajan Date: Wed, 6 Apr 2011 11:41:10 +0530 Subject: mac80211: Check for queued frames before entering power save. In a highly noisy environment, the tx rate of the driver drops and the application slows down since it has not yet received ACKs for the frames already queued in the hardware. Since this ACK may take more than 100ms, stopping the dev queues for entering PS at this stage breaks applications, WMM test cases in my testing. If there are frames already pending in the tx queue, postponing the PS logic helps to avoid redundant queue stops. When power save is enabled by default and in a noisy environment, this API certainly helps in improving the average throughput. Signed-off-by: Vivek Natarajan Signed-off-by: John W. Linville diff --git a/include/net/mac80211.h b/include/net/mac80211.h index 965f1b1..361bc5d 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -1819,6 +1819,9 @@ enum ieee80211_ampdu_mlme_action { * @set_ringparam: Set tx and rx ring sizes. * * @get_ringparam: Get tx and rx ring current and maximum sizes. + * + * @tx_frames_pending: Check if there is any pending frame in the hardware + * queues before entering power save. */ struct ieee80211_ops { void (*tx)(struct ieee80211_hw *hw, struct sk_buff *skb); @@ -1906,6 +1909,7 @@ struct ieee80211_ops { int (*set_ringparam)(struct ieee80211_hw *hw, u32 tx, u32 rx); void (*get_ringparam)(struct ieee80211_hw *hw, u32 *tx, u32 *tx_max, u32 *rx, u32 *rx_max); + bool (*tx_frames_pending)(struct ieee80211_hw *hw); }; /** diff --git a/net/mac80211/driver-ops.h b/net/mac80211/driver-ops.h index 9c0d62b..00a0685 100644 --- a/net/mac80211/driver-ops.h +++ b/net/mac80211/driver-ops.h @@ -552,4 +552,17 @@ static inline void drv_get_ringparam(struct ieee80211_local *local, trace_drv_return_void(local); } +static inline bool drv_tx_frames_pending(struct ieee80211_local *local) +{ + bool ret = false; + + might_sleep(); + + trace_drv_tx_frames_pending(local); + if (local->ops->tx_frames_pending) + ret = local->ops->tx_frames_pending(&local->hw); + trace_drv_return_bool(local, ret); + + return ret; +} #endif /* __MAC80211_DRIVER_OPS */ diff --git a/net/mac80211/driver-trace.h b/net/mac80211/driver-trace.h index 45aab80..c8c934d 100644 --- a/net/mac80211/driver-trace.h +++ b/net/mac80211/driver-trace.h @@ -74,6 +74,21 @@ TRACE_EVENT(drv_return_int, TP_printk(LOCAL_PR_FMT " - %d", LOCAL_PR_ARG, __entry->ret) ); +TRACE_EVENT(drv_return_bool, + TP_PROTO(struct ieee80211_local *local, bool ret), + TP_ARGS(local, ret), + TP_STRUCT__entry( + LOCAL_ENTRY + __field(bool, ret) + ), + TP_fast_assign( + LOCAL_ASSIGN; + __entry->ret = ret; + ), + TP_printk(LOCAL_PR_FMT " - %s", LOCAL_PR_ARG, (__entry->ret) ? + "true" : "false") +); + TRACE_EVENT(drv_return_u64, TP_PROTO(struct ieee80211_local *local, u64 ret), TP_ARGS(local, ret), @@ -964,6 +979,11 @@ TRACE_EVENT(drv_get_ringparam, ) ); +DEFINE_EVENT(local_only_evt, drv_tx_frames_pending, + TP_PROTO(struct ieee80211_local *local), + TP_ARGS(local) +); + DEFINE_EVENT(local_only_evt, drv_offchannel_tx_cancel_wait, TP_PROTO(struct ieee80211_local *local), TP_ARGS(local) diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 865fed4..a41f234 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -761,15 +761,16 @@ void ieee80211_dynamic_ps_enable_work(struct work_struct *work) if ((local->hw.flags & IEEE80211_HW_PS_NULLFUNC_STACK) && (!(ifmgd->flags & IEEE80211_STA_NULLFUNC_ACKED))) { netif_tx_stop_all_queues(sdata->dev); - /* - * Flush all the frames queued in the driver before - * going to power save - */ - drv_flush(local, false); - ieee80211_send_nullfunc(local, sdata, 1); - /* Flush once again to get the tx status of nullfunc frame */ - drv_flush(local, false); + if (drv_tx_frames_pending(local)) + mod_timer(&local->dynamic_ps_timer, jiffies + + msecs_to_jiffies( + local->hw.conf.dynamic_ps_timeout)); + else { + ieee80211_send_nullfunc(local, sdata, 1); + /* Flush to get the tx status of nullfunc frame */ + drv_flush(local, false); + } } if (!((local->hw.flags & IEEE80211_HW_REPORTS_TX_ACK_STATUS) && -- cgit v0.10.2 From 15b91e830dbf300d653b3fe70f6ef71b568164a3 Mon Sep 17 00:00:00 2001 From: Vivek Natarajan Date: Wed, 6 Apr 2011 11:41:11 +0530 Subject: ath9k: Implement dev_tx_frames_pending callback. This function returns true if there is atleast one frame in any one of the tx queues. Signed-off-by: Vivek Natarajan Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index ba1c9a6..93b9fa2 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -2201,6 +2201,21 @@ out: ath9k_ps_restore(sc); } +static bool ath9k_tx_frames_pending(struct ieee80211_hw *hw) +{ + struct ath_softc *sc = hw->priv; + int i; + + for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) { + if (!ATH_TXQ_SETUP(sc, i)) + continue; + + if (ath9k_has_pending_frames(sc, &sc->tx.txq[i])) + return true; + } + return false; +} + struct ieee80211_ops ath9k_ops = { .tx = ath9k_tx, .start = ath9k_start, @@ -2223,4 +2238,5 @@ struct ieee80211_ops ath9k_ops = { .rfkill_poll = ath9k_rfkill_poll_state, .set_coverage_class = ath9k_set_coverage_class, .flush = ath9k_flush, + .tx_frames_pending = ath9k_tx_frames_pending, }; -- cgit v0.10.2 From d88525e8fdc00c0078d38353caffc29e5a9c70cc Mon Sep 17 00:00:00 2001 From: Rajkumar Manoharan Date: Wed, 6 Apr 2011 21:42:52 +0530 Subject: ath9k_hw: Fix instable target power control b/w CCK/OFDM The problem is that when the attenuation is increased, the rate will start to drop from MCS7 -> MCS6, and finally will see MCS1 -> CCK_11Mbps. When the rate is changed b/w CCK and OFDM, it will use register desired_scale to calculate how much tx gain need to change. The output power with the same tx gain for CCK and OFDM modulated signals are different. This difference is constant for AR9280 but not AR9285/AR9271. It has different PA architecture a constant. So it should be calibrated against this PA characteristic. The driver has to read the calibrated values from EEPROM and set the tx power registers accordingly. Signed-off-by: Rajkumar Manoharan Acked-by: Felix Fietkau Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/ar9002_phy.h b/drivers/net/wireless/ath/ath9k/ar9002_phy.h index 37663db..47780ef 100644 --- a/drivers/net/wireless/ath/ath9k/ar9002_phy.h +++ b/drivers/net/wireless/ath/ath9k/ar9002_phy.h @@ -483,7 +483,11 @@ #define AR_PHY_TX_PWRCTRL_INIT_TX_GAIN 0x01F80000 #define AR_PHY_TX_PWRCTRL_INIT_TX_GAIN_S 19 +#define AR_PHY_TX_PWRCTRL8 0xa278 + #define AR_PHY_TX_PWRCTRL9 0xa27C + +#define AR_PHY_TX_PWRCTRL10 0xa394 #define AR_PHY_TX_DESIRED_SCALE_CCK 0x00007C00 #define AR_PHY_TX_DESIRED_SCALE_CCK_S 10 #define AR_PHY_TX_PWRCTRL9_RES_DC_REMOVAL 0x80000000 @@ -495,6 +499,8 @@ #define AR_PHY_CH0_TX_PWRCTRL11 0xa398 #define AR_PHY_CH1_TX_PWRCTRL11 0xb398 +#define AR_PHY_CH0_TX_PWRCTRL12 0xa3dc +#define AR_PHY_CH0_TX_PWRCTRL13 0xa3e0 #define AR_PHY_TX_PWRCTRL_OLPC_TEMP_COMP 0x0000FC00 #define AR_PHY_TX_PWRCTRL_OLPC_TEMP_COMP_S 10 diff --git a/drivers/net/wireless/ath/ath9k/eeprom.h b/drivers/net/wireless/ath/ath9k/eeprom.h index bd82447..3e31613 100644 --- a/drivers/net/wireless/ath/ath9k/eeprom.h +++ b/drivers/net/wireless/ath/ath9k/eeprom.h @@ -436,7 +436,11 @@ struct modal_eep_4k_header { u8 db2_2:4, db2_3:4; u8 db2_4:4, reserved:4; #endif - u8 futureModal[4]; + u8 tx_diversity; + u8 flc_pwr_thresh; + u8 bb_scale_smrt_antenna; +#define EEP_4K_BB_DESIRED_SCALE_MASK 0x1f + u8 futureModal[1]; struct spur_chan spurChans[AR_EEPROM_MODAL_SPURS]; } __packed; diff --git a/drivers/net/wireless/ath/ath9k/eeprom_4k.c b/drivers/net/wireless/ath/ath9k/eeprom_4k.c index bc77a30..6f714dd 100644 --- a/drivers/net/wireless/ath/ath9k/eeprom_4k.c +++ b/drivers/net/wireless/ath/ath9k/eeprom_4k.c @@ -781,6 +781,7 @@ static void ath9k_hw_4k_set_board_values(struct ath_hw *ah, { struct modal_eep_4k_header *pModal; struct ar5416_eeprom_4k *eep = &ah->eeprom.map4k; + struct base_eep_header_4k *pBase = &eep->baseEepHeader; u8 txRxAttenLocal; u8 ob[5], db1[5], db2[5]; u8 ant_div_control1, ant_div_control2; @@ -1003,6 +1004,31 @@ static void ath9k_hw_4k_set_board_values(struct ath_hw *ah, AR_PHY_SETTLING_SWITCH, pModal->swSettleHt40); } + if (AR_SREV_9271(ah) || AR_SREV_9285(ah)) { + u8 bb_desired_scale = (pModal->bb_scale_smrt_antenna & + EEP_4K_BB_DESIRED_SCALE_MASK); + if ((pBase->txGainType == 0) && (bb_desired_scale != 0)) { + u32 pwrctrl, mask, clr; + + mask = BIT(0)|BIT(5)|BIT(10)|BIT(15)|BIT(20)|BIT(25); + pwrctrl = mask * bb_desired_scale; + clr = mask * 0x1f; + REG_RMW(ah, AR_PHY_TX_PWRCTRL8, pwrctrl, clr); + REG_RMW(ah, AR_PHY_TX_PWRCTRL10, pwrctrl, clr); + REG_RMW(ah, AR_PHY_CH0_TX_PWRCTRL12, pwrctrl, clr); + + mask = BIT(0)|BIT(5)|BIT(15); + pwrctrl = mask * bb_desired_scale; + clr = mask * 0x1f; + REG_RMW(ah, AR_PHY_TX_PWRCTRL9, pwrctrl, clr); + + mask = BIT(0)|BIT(5); + pwrctrl = mask * bb_desired_scale; + clr = mask * 0x1f; + REG_RMW(ah, AR_PHY_CH0_TX_PWRCTRL11, pwrctrl, clr); + REG_RMW(ah, AR_PHY_CH0_TX_PWRCTRL13, pwrctrl, clr); + } + } } static u16 ath9k_hw_4k_get_spur_channel(struct ath_hw *ah, u16 i, bool is2GHz) -- cgit v0.10.2 From 18bf965702058f5f8039e6a46bb5ebaa18d38ebd Mon Sep 17 00:00:00 2001 From: Bing Zhao Date: Wed, 6 Apr 2011 16:46:55 -0700 Subject: mwifiex: fix cmd_skb headroom decreasing issue Before calling host_to_card() to send the cmd to firmware, we use skb_push() to add 4 bytes SDIO interface header at the start of the data buffer. Since cmd_skb data structure will be re-used at a later time, we need to restore its headroom by removing the 4 bytes header. Signed-off-by: Bing Zhao Signed-off-by: Marc Yang Signed-off-by: Yogesh Ashok Powar Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/mwifiex/cmdevt.c b/drivers/net/wireless/mwifiex/cmdevt.c index a9aeb31..8676480 100644 --- a/drivers/net/wireless/mwifiex/cmdevt.c +++ b/drivers/net/wireless/mwifiex/cmdevt.c @@ -206,6 +206,8 @@ static int mwifiex_dnld_cmd_to_fw(struct mwifiex_private *priv, cmd_node->cmd_skb->data, cmd_node->cmd_skb->len, NULL); + skb_pull(cmd_node->cmd_skb, INTF_HEADER_LEN); + if (ret == -1) { dev_err(adapter->dev, "DNLD_CMD: host to card failed\n"); if (wait_queue) -- cgit v0.10.2 From 6a35a0ac5771fa962c45926678d1f194cbc98c4e Mon Sep 17 00:00:00 2001 From: Yogesh Ashok Powar Date: Wed, 6 Apr 2011 16:46:56 -0700 Subject: mwifiex: use common keyinfo bitmap for different key types Instead of having separate key information definitions for each type of key, a common key information bitmap is used. Signed-off-by: Yogesh Ashok Powar Signed-off-by: Bing Zhao Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/mwifiex/fw.h b/drivers/net/wireless/mwifiex/fw.h index 2b93811..f8c008f 100644 --- a/drivers/net/wireless/mwifiex/fw.h +++ b/drivers/net/wireless/mwifiex/fw.h @@ -72,33 +72,12 @@ enum KEY_TYPE_ID { KEY_TYPE_ID_AES, KEY_TYPE_ID_WAPI, }; - -enum KEY_INFO_WEP { - KEY_INFO_WEP_MCAST = 0x01, - KEY_INFO_WEP_UNICAST = 0x02, - KEY_INFO_WEP_ENABLED = 0x04 -}; - -enum KEY_INFO_TKIP { - KEY_INFO_TKIP_MCAST = 0x01, - KEY_INFO_TKIP_UNICAST = 0x02, - KEY_INFO_TKIP_ENABLED = 0x04 -}; - -enum KEY_INFO_AES { - KEY_INFO_AES_MCAST = 0x01, - KEY_INFO_AES_UNICAST = 0x02, - KEY_INFO_AES_ENABLED = 0x04 -}; +#define KEY_MCAST BIT(0) +#define KEY_UNICAST BIT(1) +#define KEY_ENABLED BIT(2) #define WAPI_KEY_LEN 50 -enum KEY_INFO_WAPI { - KEY_INFO_WAPI_MCAST = 0x01, - KEY_INFO_WAPI_UNICAST = 0x02, - KEY_INFO_WAPI_ENABLED = 0x04 -}; - #define MAX_POLL_TRIES 100 #define MAX_MULTI_INTERFACE_POLL_TRIES 1000 diff --git a/drivers/net/wireless/mwifiex/sta_cmd.c b/drivers/net/wireless/mwifiex/sta_cmd.c index 6fff261..19de652 100644 --- a/drivers/net/wireless/mwifiex/sta_cmd.c +++ b/drivers/net/wireless/mwifiex/sta_cmd.c @@ -500,9 +500,8 @@ mwifiex_set_keyparamset_wep(struct mwifiex_private *priv, key_param_set->key_type_id = cpu_to_le16(KEY_TYPE_ID_WEP); key_param_set->key_info = - cpu_to_le16(KEY_INFO_WEP_ENABLED | - KEY_INFO_WEP_UNICAST | - KEY_INFO_WEP_MCAST); + cpu_to_le16(KEY_ENABLED | KEY_UNICAST | + KEY_MCAST); key_param_set->key_len = cpu_to_le16(priv->wep_key[i].key_length); /* Set WEP key index */ @@ -589,10 +588,10 @@ static int mwifiex_cmd_802_11_key_material(struct mwifiex_private *priv, cpu_to_le16(KEY_TYPE_ID_WAPI); if (cmd_oid == KEY_INFO_ENABLED) key_material->key_param_set.key_info = - cpu_to_le16(KEY_INFO_WAPI_ENABLED); + cpu_to_le16(KEY_ENABLED); else key_material->key_param_set.key_info = - cpu_to_le16(!KEY_INFO_WAPI_ENABLED); + cpu_to_le16(!KEY_ENABLED); key_material->key_param_set.key[0] = enc_key->key_index; if (!priv->sec_info.wapi_key_on) @@ -604,10 +603,10 @@ static int mwifiex_cmd_802_11_key_material(struct mwifiex_private *priv, if (0 != memcmp(enc_key->mac_addr, bc_mac, sizeof(bc_mac))) { /* WAPI pairwise key: unicast */ key_material->key_param_set.key_info |= - cpu_to_le16(KEY_INFO_WAPI_UNICAST); + cpu_to_le16(KEY_UNICAST); } else { /* WAPI group key: multicast */ key_material->key_param_set.key_info |= - cpu_to_le16(KEY_INFO_WAPI_MCAST); + cpu_to_le16(KEY_MCAST); priv->sec_info.wapi_key_on = true; } @@ -634,32 +633,32 @@ static int mwifiex_cmd_802_11_key_material(struct mwifiex_private *priv, cpu_to_le16(KEY_TYPE_ID_AES); if (cmd_oid == KEY_INFO_ENABLED) key_material->key_param_set.key_info = - cpu_to_le16(KEY_INFO_AES_ENABLED); + cpu_to_le16(KEY_ENABLED); else key_material->key_param_set.key_info = - cpu_to_le16(!KEY_INFO_AES_ENABLED); + cpu_to_le16(!KEY_ENABLED); if (enc_key->key_index & MWIFIEX_KEY_INDEX_UNICAST) /* AES pairwise key: unicast */ key_material->key_param_set.key_info |= - cpu_to_le16(KEY_INFO_AES_UNICAST); + cpu_to_le16(KEY_UNICAST); else /* AES group key: multicast */ key_material->key_param_set.key_info |= - cpu_to_le16(KEY_INFO_AES_MCAST); + cpu_to_le16(KEY_MCAST); } else if (enc_key->key_len == WLAN_KEY_LEN_TKIP) { dev_dbg(priv->adapter->dev, "cmd: WPA_TKIP\n"); key_material->key_param_set.key_type_id = cpu_to_le16(KEY_TYPE_ID_TKIP); key_material->key_param_set.key_info = - cpu_to_le16(KEY_INFO_TKIP_ENABLED); + cpu_to_le16(KEY_ENABLED); if (enc_key->key_index & MWIFIEX_KEY_INDEX_UNICAST) /* TKIP pairwise key: unicast */ key_material->key_param_set.key_info |= - cpu_to_le16(KEY_INFO_TKIP_UNICAST); + cpu_to_le16(KEY_UNICAST); else /* TKIP group key: multicast */ key_material->key_param_set.key_info |= - cpu_to_le16(KEY_INFO_TKIP_MCAST); + cpu_to_le16(KEY_MCAST); } if (key_material->key_param_set.key_type_id) { diff --git a/drivers/net/wireless/mwifiex/sta_cmdresp.c b/drivers/net/wireless/mwifiex/sta_cmdresp.c index 74add45..648df69 100644 --- a/drivers/net/wireless/mwifiex/sta_cmdresp.c +++ b/drivers/net/wireless/mwifiex/sta_cmdresp.c @@ -574,8 +574,7 @@ static int mwifiex_ret_802_11_key_material(struct mwifiex_private *priv, &resp->params.key_material; if (le16_to_cpu(key->action) == HostCmd_ACT_GEN_SET) { - if ((le16_to_cpu(key->key_param_set.key_info) & - KEY_INFO_TKIP_MCAST)) { + if ((le16_to_cpu(key->key_param_set.key_info) & KEY_MCAST)) { dev_dbg(priv->adapter->dev, "info: key: GTK is set\n"); priv->wpa_is_gtk_set = true; priv->scan_block = false; diff --git a/drivers/net/wireless/mwifiex/sta_ioctl.c b/drivers/net/wireless/mwifiex/sta_ioctl.c index b163507..2fcdbc2 100644 --- a/drivers/net/wireless/mwifiex/sta_ioctl.c +++ b/drivers/net/wireless/mwifiex/sta_ioctl.c @@ -1729,8 +1729,7 @@ static int mwifiex_sec_ioctl_set_wpa_key(struct mwifiex_adapter *adapter, sizeof(ibss_key->key_param_set.key_len)); ibss_key->key_param_set.key_type_id = cpu_to_le16(KEY_TYPE_ID_TKIP); - ibss_key->key_param_set.key_info - = cpu_to_le16(KEY_INFO_TKIP_ENABLED); + ibss_key->key_param_set.key_info = cpu_to_le16(KEY_ENABLED); /* Send the key as GTK to firmware */ encrypt_key->key_index = ~MWIFIEX_KEY_INDEX_UNICAST; -- cgit v0.10.2 From 264bbec811024e39fe8f9e7a45743f81f373529e Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Thu, 7 Apr 2011 19:24:23 +0200 Subject: ath9k: fix PS-Poll reception on AR9160 and earlier I can't find any valid reason for not setting the ATH9K_RX_FILTER_PSPOLL flag on older hardware and neither the documentation nor the reference code mention any reason for excluding older hardware here. Signed-off-by: Felix Fietkau Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/recv.c b/drivers/net/wireless/ath/ath9k/recv.c index 3842b75..ef198ae 100644 --- a/drivers/net/wireless/ath/ath9k/recv.c +++ b/drivers/net/wireless/ath/ath9k/recv.c @@ -426,9 +426,7 @@ u32 ath_calcrxfilter(struct ath_softc *sc) else rfilt |= ATH9K_RX_FILTER_BEACON; - if ((AR_SREV_9280_20_OR_LATER(sc->sc_ah) || - AR_SREV_9285_12_OR_LATER(sc->sc_ah)) && - (sc->sc_ah->opmode == NL80211_IFTYPE_AP) && + if ((sc->sc_ah->opmode == NL80211_IFTYPE_AP) || (sc->rx.rxfilter & FIF_PSPOLL)) rfilt |= ATH9K_RX_FILTER_PSPOLL; -- cgit v0.10.2 From 952949738aba19f84dae9def18e0baa58f0ce0b8 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Thu, 7 Apr 2011 19:30:32 +0200 Subject: ath9k: fix too early enabling of rx during ath_startrecv() rx should only be enabled after enough rx buffers have been given to the hardware, however ath_rx_buf_link was calling ath9k_hw_rxena after every single added buffer. Fix this by calling ath9k_hw_rxena directly from the rx tasklet after completion instead. Signed-off-by: Felix Fietkau Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/recv.c b/drivers/net/wireless/ath/ath9k/recv.c index ef198ae..b81bfc4 100644 --- a/drivers/net/wireless/ath/ath9k/recv.c +++ b/drivers/net/wireless/ath/ath9k/recv.c @@ -75,7 +75,6 @@ static void ath_rx_buf_link(struct ath_softc *sc, struct ath_buf *bf) *sc->rx.rxlink = bf->bf_daddr; sc->rx.rxlink = &ds->ds_link; - ath9k_hw_rxena(ah); } static void ath_setdefantenna(struct ath_softc *sc, u32 antenna) @@ -1765,6 +1764,7 @@ requeue: } else { list_move_tail(&bf->list, &sc->rx.rxbuf); ath_rx_buf_link(sc, bf); + ath9k_hw_rxena(ah); } } while (1); -- cgit v0.10.2 From a22e93f5d819f11d2a2d6332e20ff5b462e5c208 Mon Sep 17 00:00:00 2001 From: Paul Bolle Date: Thu, 7 Apr 2011 20:40:32 +0200 Subject: iwl4965: drop a lone pr_err() iwl4965_rate_control_register() prints a message at KERN_ERR level. It looks like it's just a debugging message, so pr_err() seems to be overdone. But none of the similar functions in drivers/net/wireless print a message, so let's just drop it. Signed-off-by: Paul Bolle Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwlegacy/iwl-4965-rs.c b/drivers/net/wireless/iwlegacy/iwl-4965-rs.c index 31ac672..8950939 100644 --- a/drivers/net/wireless/iwlegacy/iwl-4965-rs.c +++ b/drivers/net/wireless/iwlegacy/iwl-4965-rs.c @@ -2860,7 +2860,6 @@ static struct rate_control_ops rs_4965_ops = { int iwl4965_rate_control_register(void) { - pr_err("Registering 4965 rate control operations\n"); return ieee80211_rate_control_register(&rs_4965_ops); } -- cgit v0.10.2 From 581a8b0feeed8877aab3a8ca4c972419790cd07f Mon Sep 17 00:00:00 2001 From: Javier Cardona Date: Thu, 7 Apr 2011 15:08:27 -0700 Subject: nl80211: rename NL80211_MESH_SETUP_VENDOR_PATH_SEL_IE To NL80211_MESH_SETUP_IE. This reflects our ability to insert any ie into a mesh beacon, not simply path selection ies. Signed-off-by: Javier Cardona Signed-off-by: John W. Linville diff --git a/include/linux/nl80211.h b/include/linux/nl80211.h index 16eea72..ecf6b68 100644 --- a/include/linux/nl80211.h +++ b/include/linux/nl80211.h @@ -545,6 +545,7 @@ enum nl80211_commands { /* source-level API compatibility */ #define NL80211_CMD_GET_MESH_PARAMS NL80211_CMD_GET_MESH_CONFIG #define NL80211_CMD_SET_MESH_PARAMS NL80211_CMD_SET_MESH_CONFIG +#define NL80211_MESH_SETUP_VENDOR_PATH_SEL_IE NL80211_MESH_SETUP_IE /** * enum nl80211_attrs - nl80211 netlink attributes @@ -1719,9 +1720,9 @@ enum nl80211_meshconf_params { * vendor specific path metric or disable it to use the default Airtime * metric. * - * @NL80211_MESH_SETUP_VENDOR_PATH_SEL_IE: A vendor specific information - * element that vendors will use to identify the path selection methods and - * metrics in use. + * @NL80211_MESH_SETUP_IE: Information elements for this mesh, for instance, a + * robust security network ie, or a vendor specific information element that + * vendors will use to identify the path selection methods and metrics in use. * * @NL80211_MESH_SETUP_ATTR_MAX: highest possible mesh setup attribute number * @__NL80211_MESH_SETUP_ATTR_AFTER_LAST: Internal use @@ -1730,7 +1731,7 @@ enum nl80211_mesh_setup_params { __NL80211_MESH_SETUP_INVALID, NL80211_MESH_SETUP_ENABLE_VENDOR_PATH_SEL, NL80211_MESH_SETUP_ENABLE_VENDOR_METRIC, - NL80211_MESH_SETUP_VENDOR_PATH_SEL_IE, + NL80211_MESH_SETUP_IE, /* keep last */ __NL80211_MESH_SETUP_ATTR_AFTER_LAST, diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index ba7384a..1d02ddf 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -689,8 +689,8 @@ struct mesh_config { * @mesh_id_len: length of the mesh ID, at least 1 and at most 32 bytes * @path_sel_proto: which path selection protocol to use * @path_metric: which metric to use - * @vendor_ie: vendor information elements (optional) - * @vendor_ie_len: length of vendor information elements + * @ie: vendor information elements (optional) + * @ie_len: length of vendor information elements * * These parameters are fixed when the mesh is created. */ @@ -699,8 +699,8 @@ struct mesh_setup { u8 mesh_id_len; u8 path_sel_proto; u8 path_metric; - const u8 *vendor_ie; - u8 vendor_ie_len; + const u8 *ie; + u8 ie_len; }; /** diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index bf5d28d..d9428af 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -1034,26 +1034,25 @@ static int copy_mesh_setup(struct ieee80211_if_mesh *ifmsh, u8 *new_ie; const u8 *old_ie; - /* first allocate the new vendor information element */ + /* allocate information elements */ new_ie = NULL; - old_ie = ifmsh->vendor_ie; + old_ie = ifmsh->ie; - ifmsh->vendor_ie_len = setup->vendor_ie_len; - if (setup->vendor_ie_len) { - new_ie = kmemdup(setup->vendor_ie, setup->vendor_ie_len, + if (setup->ie_len) { + new_ie = kmemdup(setup->ie, setup->ie_len, GFP_KERNEL); if (!new_ie) return -ENOMEM; } + ifmsh->ie_len = setup->ie_len; + ifmsh->ie = new_ie; + kfree(old_ie); /* now copy the rest of the setup parameters */ ifmsh->mesh_id_len = setup->mesh_id_len; memcpy(ifmsh->mesh_id, setup->mesh_id, ifmsh->mesh_id_len); ifmsh->mesh_pp_id = setup->path_sel_proto; ifmsh->mesh_pm_id = setup->path_metric; - ifmsh->vendor_ie = new_ie; - - kfree(old_ie); return 0; } diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 6eb2c852..6450100 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -488,8 +488,8 @@ struct ieee80211_if_mesh { struct mesh_config mshcfg; u32 mesh_seqnum; bool accepting_plinks; - const u8 *vendor_ie; - u8 vendor_ie_len; + const u8 *ie; + u8 ie_len; }; #ifdef CONFIG_MAC80211_MESH diff --git a/net/mac80211/mesh.c b/net/mac80211/mesh.c index 2a57cc0..1c244c0 100644 --- a/net/mac80211/mesh.c +++ b/net/mac80211/mesh.c @@ -279,9 +279,9 @@ void mesh_mgmt_ies_add(struct sk_buff *skb, struct ieee80211_sub_if_data *sdata) MESHCONF_CAPAB_ACCEPT_PLINKS : 0x00; *pos++ = 0x00; - if (sdata->u.mesh.vendor_ie) { - int len = sdata->u.mesh.vendor_ie_len; - const u8 *data = sdata->u.mesh.vendor_ie; + if (sdata->u.mesh.ie) { + int len = sdata->u.mesh.ie_len; + const u8 *data = sdata->u.mesh.ie; if (skb_tailroom(skb) > len) memcpy(skb_put(skb, len), data, len); } diff --git a/net/mac80211/mesh_plink.c b/net/mac80211/mesh_plink.c index 44b5393..c705b20 100644 --- a/net/mac80211/mesh_plink.c +++ b/net/mac80211/mesh_plink.c @@ -161,7 +161,7 @@ static int mesh_plink_frame_tx(struct ieee80211_sub_if_data *sdata, __le16 reason) { struct ieee80211_local *local = sdata->local; struct sk_buff *skb = dev_alloc_skb(local->hw.extra_tx_headroom + 400 + - sdata->u.mesh.vendor_ie_len); + sdata->u.mesh.ie_len); struct ieee80211_mgmt *mgmt; bool include_plid = false; static const u8 meshpeeringproto[] = { 0x00, 0x0F, 0xAC, 0x2A }; diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index ce4596e..17b10be 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -2262,7 +2262,7 @@ struct sk_buff *ieee80211_beacon_get_tim(struct ieee80211_hw *hw, /* headroom, head length, tail length and maximum TIM length */ skb = dev_alloc_skb(local->tx_headroom + 400 + - sdata->u.mesh.vendor_ie_len); + sdata->u.mesh.ie_len); if (!skb) goto out; diff --git a/net/wireless/mesh.c b/net/wireless/mesh.c index 73e39c1..0d4b226 100644 --- a/net/wireless/mesh.c +++ b/net/wireless/mesh.c @@ -53,8 +53,8 @@ const struct mesh_config default_mesh_config = { const struct mesh_setup default_mesh_setup = { .path_sel_proto = IEEE80211_PATH_PROTOCOL_HWMP, .path_metric = IEEE80211_PATH_METRIC_AIRTIME, - .vendor_ie = NULL, - .vendor_ie_len = 0, + .ie = NULL, + .ie_len = 0, }; int __cfg80211_join_mesh(struct cfg80211_registered_device *rdev, diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 297d7ce..ccd825a 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -2823,7 +2823,7 @@ static const struct nla_policy nl80211_mesh_setup_params_policy[NL80211_MESH_SETUP_ATTR_MAX+1] = { [NL80211_MESH_SETUP_ENABLE_VENDOR_PATH_SEL] = { .type = NLA_U8 }, [NL80211_MESH_SETUP_ENABLE_VENDOR_METRIC] = { .type = NLA_U8 }, - [NL80211_MESH_SETUP_VENDOR_PATH_SEL_IE] = { .type = NLA_BINARY, + [NL80211_MESH_SETUP_IE] = { .type = NLA_BINARY, .len = IEEE80211_MAX_DATA_LEN }, }; @@ -2925,13 +2925,14 @@ static int nl80211_parse_mesh_setup(struct genl_info *info, IEEE80211_PATH_METRIC_VENDOR : IEEE80211_PATH_METRIC_AIRTIME; - if (tb[NL80211_MESH_SETUP_VENDOR_PATH_SEL_IE]) { + + if (tb[NL80211_MESH_SETUP_IE]) { struct nlattr *ieattr = - tb[NL80211_MESH_SETUP_VENDOR_PATH_SEL_IE]; + tb[NL80211_MESH_SETUP_IE]; if (!is_valid_ie_attr(ieattr)) return -EINVAL; - setup->vendor_ie = nla_data(ieattr); - setup->vendor_ie_len = nla_len(ieattr); + setup->ie = nla_data(ieattr); + setup->ie_len = nla_len(ieattr); } return 0; -- cgit v0.10.2 From 15d5dda623139bbf6165030fc251bbd5798f4130 Mon Sep 17 00:00:00 2001 From: Javier Cardona Date: Thu, 7 Apr 2011 15:08:28 -0700 Subject: cfg80211/nl80211: Add userspace authentication flag to mesh setup During mesh setup, use NL80211_MESH_SETUP_USERSPACE_AUTH flag to create a secure mesh and route management frames to userspace. Also, NL80211_CMD_GET_WIPHY now returns a flag NL80211_SUPPORT_MESH_AUTH if the wiphy's mesh implementation supports routing of mesh auth frames to userspace. This is useful for forward compatibility between old kernels and new userspace tools. Signed-off-by: Javier Cardona Signed-off-by: Thomas Pedersen Signed-off-by: John W. Linville diff --git a/include/linux/nl80211.h b/include/linux/nl80211.h index ecf6b68..0e652d8 100644 --- a/include/linux/nl80211.h +++ b/include/linux/nl80211.h @@ -887,6 +887,9 @@ enum nl80211_commands { * changed once the mesh is active. * @NL80211_ATTR_MESH_CONFIG: Mesh configuration parameters, a nested attribute * containing attributes from &enum nl80211_meshconf_params. + * @NL80211_ATTR_SUPPORT_MESH_AUTH: Currently, this means the underlying driver + * allows auth frames in a mesh to be passed to userspace for processing via + * the @NL80211_MESH_SETUP_USERSPACE_AUTH flag. * * @NL80211_ATTR_MAX: highest attribute number currently defined * @__NL80211_ATTR_AFTER_LAST: internal use @@ -1075,6 +1078,8 @@ enum nl80211_attrs { NL80211_ATTR_WIPHY_ANTENNA_AVAIL_TX, NL80211_ATTR_WIPHY_ANTENNA_AVAIL_RX, + NL80211_ATTR_SUPPORT_MESH_AUTH, + /* add attributes here, update the policy in nl80211.c */ __NL80211_ATTR_AFTER_LAST, @@ -1724,6 +1729,9 @@ enum nl80211_meshconf_params { * robust security network ie, or a vendor specific information element that * vendors will use to identify the path selection methods and metrics in use. * + * @NL80211_MESH_SETUP_USERSPACE_AUTH: Enable this option if an authentication + * daemon will be authenticating mesh candidates. + * * @NL80211_MESH_SETUP_ATTR_MAX: highest possible mesh setup attribute number * @__NL80211_MESH_SETUP_ATTR_AFTER_LAST: Internal use */ @@ -1732,6 +1740,7 @@ enum nl80211_mesh_setup_params { NL80211_MESH_SETUP_ENABLE_VENDOR_PATH_SEL, NL80211_MESH_SETUP_ENABLE_VENDOR_METRIC, NL80211_MESH_SETUP_IE, + NL80211_MESH_SETUP_USERSPACE_AUTH, /* keep last */ __NL80211_MESH_SETUP_ATTR_AFTER_LAST, diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index 1d02ddf..e77603b 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -691,6 +691,7 @@ struct mesh_config { * @path_metric: which metric to use * @ie: vendor information elements (optional) * @ie_len: length of vendor information elements + * @is_secure: or not * * These parameters are fixed when the mesh is created. */ @@ -701,6 +702,7 @@ struct mesh_setup { u8 path_metric; const u8 *ie; u8 ie_len; + bool is_secure; }; /** @@ -1451,6 +1453,8 @@ struct cfg80211_ops { * @WIPHY_FLAG_IBSS_RSN: The device supports IBSS RSN. * @WIPHY_FLAG_SUPPORTS_SEPARATE_DEFAULT_KEYS: The device supports separate * unicast and multicast TX keys. + * @WIPHY_FLAG_MESH_AUTH: The device supports mesh authentication by routing + * auth frames to userspace. See @NL80211_MESH_SETUP_USERSPACE_AUTH. */ enum wiphy_flags { WIPHY_FLAG_CUSTOM_REGULATORY = BIT(0), @@ -1463,6 +1467,7 @@ enum wiphy_flags { WIPHY_FLAG_CONTROL_PORT_PROTOCOL = BIT(7), WIPHY_FLAG_IBSS_RSN = BIT(8), WIPHY_FLAG_SUPPORTS_SEPARATE_DEFAULT_KEYS= BIT(9), + WIPHY_FLAG_MESH_AUTH = BIT(10), }; struct mac_address { diff --git a/net/wireless/mesh.c b/net/wireless/mesh.c index 0d4b226..0e5c122 100644 --- a/net/wireless/mesh.c +++ b/net/wireless/mesh.c @@ -72,6 +72,10 @@ int __cfg80211_join_mesh(struct cfg80211_registered_device *rdev, if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_MESH_POINT) return -EOPNOTSUPP; + if (!(rdev->wiphy.flags & WIPHY_FLAG_MESH_AUTH) && + setup->is_secure) + return -EOPNOTSUPP; + if (wdev->mesh_id_len) return -EALREADY; diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index ccd825a..cbedfc2 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -124,6 +124,7 @@ static const struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] = { [NL80211_ATTR_BSS_HT_OPMODE] = { .type = NLA_U16 }, [NL80211_ATTR_MESH_CONFIG] = { .type = NLA_NESTED }, + [NL80211_ATTR_SUPPORT_MESH_AUTH] = { .type = NLA_FLAG }, [NL80211_ATTR_HT_CAPABILITY] = { .type = NLA_BINARY, .len = NL80211_HT_CAPABILITY_LEN }, @@ -594,6 +595,8 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags, if (dev->wiphy.flags & WIPHY_FLAG_IBSS_RSN) NLA_PUT_FLAG(msg, NL80211_ATTR_SUPPORT_IBSS_RSN); + if (dev->wiphy.flags & WIPHY_FLAG_MESH_AUTH) + NLA_PUT_FLAG(msg, NL80211_ATTR_SUPPORT_MESH_AUTH); NLA_PUT(msg, NL80211_ATTR_CIPHER_SUITES, sizeof(u32) * dev->wiphy.n_cipher_suites, @@ -2823,6 +2826,7 @@ static const struct nla_policy nl80211_mesh_setup_params_policy[NL80211_MESH_SETUP_ATTR_MAX+1] = { [NL80211_MESH_SETUP_ENABLE_VENDOR_PATH_SEL] = { .type = NLA_U8 }, [NL80211_MESH_SETUP_ENABLE_VENDOR_METRIC] = { .type = NLA_U8 }, + [NL80211_MESH_SETUP_USERSPACE_AUTH] = { .type = NLA_FLAG }, [NL80211_MESH_SETUP_IE] = { .type = NLA_BINARY, .len = IEEE80211_MAX_DATA_LEN }, }; @@ -2934,6 +2938,7 @@ static int nl80211_parse_mesh_setup(struct genl_info *info, setup->ie = nla_data(ieattr); setup->ie_len = nla_len(ieattr); } + setup->is_secure = nla_get_flag(tb[NL80211_MESH_SETUP_USERSPACE_AUTH]); return 0; } -- cgit v0.10.2 From 5cff5e01e818029a5d2c3c31b7ae5e5e7ee70452 Mon Sep 17 00:00:00 2001 From: Javier Cardona Date: Thu, 7 Apr 2011 15:08:29 -0700 Subject: mac80211: ignore peers if security is enabled for this mesh Signed-off-by: Javier Cardona Signed-off-by: John W. Linville diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index d9428af..dc623d8 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -1053,6 +1053,7 @@ static int copy_mesh_setup(struct ieee80211_if_mesh *ifmsh, memcpy(ifmsh->mesh_id, setup->mesh_id, ifmsh->mesh_id_len); ifmsh->mesh_pp_id = setup->path_sel_proto; ifmsh->mesh_pm_id = setup->path_metric; + ifmsh->is_secure = setup->is_secure; return 0; } diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 6450100..8d6d6e3 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -490,6 +490,7 @@ struct ieee80211_if_mesh { bool accepting_plinks; const u8 *ie; u8 ie_len; + bool is_secure; }; #ifdef CONFIG_MAC80211_MESH diff --git a/net/mac80211/mesh.c b/net/mac80211/mesh.c index 1c244c0..47a26c0 100644 --- a/net/mac80211/mesh.c +++ b/net/mac80211/mesh.c @@ -573,6 +573,10 @@ static void ieee80211_mesh_rx_bcn_presp(struct ieee80211_sub_if_data *sdata, ieee802_11_parse_elems(mgmt->u.probe_resp.variable, len - baselen, &elems); + /* ignore beacons from secure mesh peers if our security is off */ + if (elems.rsn_len && !sdata->u.mesh.is_secure) + return; + if (elems.ds_params && elems.ds_params_len == 1) freq = ieee80211_channel_to_frequency(elems.ds_params[0], band); else diff --git a/net/mac80211/mesh_plink.c b/net/mac80211/mesh_plink.c index c705b20..bafe255 100644 --- a/net/mac80211/mesh_plink.c +++ b/net/mac80211/mesh_plink.c @@ -449,6 +449,10 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m mpl_dbg("Mesh plink: missing necessary peer link ie\n"); return; } + if (elems.rsn_len && !sdata->u.mesh.is_secure) { + mpl_dbg("Mesh plink: can't establish link with secure peer\n"); + return; + } ftype = mgmt->u.action.u.plink_action.action_code; ie_len = elems.peer_link_len; diff --git a/net/wireless/mesh.c b/net/wireless/mesh.c index 0e5c122..e0226e8 100644 --- a/net/wireless/mesh.c +++ b/net/wireless/mesh.c @@ -55,6 +55,7 @@ const struct mesh_setup default_mesh_setup = { .path_metric = IEEE80211_PATH_METRIC_AIRTIME, .ie = NULL, .ie_len = 0, + .is_secure = false, }; int __cfg80211_join_mesh(struct cfg80211_registered_device *rdev, -- cgit v0.10.2 From b39c48fac1fc915a5dcd024bf6e9aabc855ed591 Mon Sep 17 00:00:00 2001 From: Javier Cardona Date: Thu, 7 Apr 2011 15:08:30 -0700 Subject: nl80211/mac80211: let userspace authenticate stations Signed-off-by: Javier Cardona Signed-off-by: John W. Linville diff --git a/include/linux/nl80211.h b/include/linux/nl80211.h index 0e652d8..5ec4ac3 100644 --- a/include/linux/nl80211.h +++ b/include/linux/nl80211.h @@ -1174,6 +1174,7 @@ enum nl80211_iftype { * with short barker preamble * @NL80211_STA_FLAG_WME: station is WME/QoS capable * @NL80211_STA_FLAG_MFP: station uses management frame protection + * @NL80211_STA_FLAG_AUTHENTICATED: station is authenticated * @NL80211_STA_FLAG_MAX: highest station flag number currently defined * @__NL80211_STA_FLAG_AFTER_LAST: internal use */ @@ -1183,6 +1184,7 @@ enum nl80211_sta_flags { NL80211_STA_FLAG_SHORT_PREAMBLE, NL80211_STA_FLAG_WME, NL80211_STA_FLAG_MFP, + NL80211_STA_FLAG_AUTHENTICATED, /* keep last */ __NL80211_STA_FLAG_AFTER_LAST, diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index dc623d8..1c25723 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -686,6 +686,12 @@ static void sta_apply_parameters(struct ieee80211_local *local, if (set & BIT(NL80211_STA_FLAG_MFP)) sta->flags |= WLAN_STA_MFP; } + + if (mask & BIT(NL80211_STA_FLAG_AUTHENTICATED)) { + sta->flags &= ~WLAN_STA_AUTH; + if (set & BIT(NL80211_STA_FLAG_AUTHENTICATED)) + sta->flags |= WLAN_STA_AUTH; + } spin_unlock_irqrestore(&sta->flaglock, flags); /* diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index cbedfc2..ce29a0d 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -1925,6 +1925,7 @@ static const struct nla_policy sta_flags_policy[NL80211_STA_FLAG_MAX + 1] = { [NL80211_STA_FLAG_SHORT_PREAMBLE] = { .type = NLA_FLAG }, [NL80211_STA_FLAG_WME] = { .type = NLA_FLAG }, [NL80211_STA_FLAG_MFP] = { .type = NLA_FLAG }, + [NL80211_STA_FLAG_AUTHENTICATED] = { .type = NLA_FLAG }, }; static int parse_station_flags(struct genl_info *info, @@ -2284,7 +2285,9 @@ static int nl80211_set_station(struct sk_buff *skb, struct genl_info *info) err = -EINVAL; if (params.supported_rates) err = -EINVAL; - if (params.sta_flags_mask) + if (params.sta_flags_mask & + ~(BIT(NL80211_STA_FLAG_AUTHENTICATED) | + BIT(NL80211_STA_FLAG_AUTHORIZED))) err = -EINVAL; break; default: -- cgit v0.10.2 From 71839121a0f35f9968d2e204a76eb22683156fd8 Mon Sep 17 00:00:00 2001 From: Javier Cardona Date: Thu, 7 Apr 2011 15:08:31 -0700 Subject: mac80211: Let user space receive and send mesh auth/deauth frames Signed-off-by: Javier Cardona Signed-off-by: John W. Linville diff --git a/net/mac80211/main.c b/net/mac80211/main.c index dc50fc31..e2db3dc 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c @@ -545,7 +545,9 @@ ieee80211_default_mgmt_stypes[NUM_NL80211_IFTYPES] = { }, [NL80211_IFTYPE_MESH_POINT] = { .tx = 0xffff, - .rx = BIT(IEEE80211_STYPE_ACTION >> 4), + .rx = BIT(IEEE80211_STYPE_ACTION >> 4) | + BIT(IEEE80211_STYPE_AUTH >> 4) | + BIT(IEEE80211_STYPE_DEAUTH >> 4), }, }; diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index fc2ff78..359fc39 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -502,7 +502,8 @@ ieee80211_rx_mesh_check(struct ieee80211_rx_data *rx) if (ieee80211_is_probe_req(hdr->frame_control) || ieee80211_is_probe_resp(hdr->frame_control) || - ieee80211_is_beacon(hdr->frame_control)) + ieee80211_is_beacon(hdr->frame_control) || + ieee80211_is_auth(hdr->frame_control)) return RX_CONTINUE; return RX_DROP_MONITOR; -- cgit v0.10.2 From 53e805111b69d55834f4e1ed0a31a97ea0b9e425 Mon Sep 17 00:00:00 2001 From: Javier Cardona Date: Thu, 7 Apr 2011 15:08:32 -0700 Subject: mac80211: ignore peer link requests from unauthenticated stations. Signed-off-by: Javier Cardona Signed-off-by: John W. Linville diff --git a/net/mac80211/mesh_plink.c b/net/mac80211/mesh_plink.c index bafe255..5d0dd92 100644 --- a/net/mac80211/mesh_plink.c +++ b/net/mac80211/mesh_plink.c @@ -372,6 +372,9 @@ int mesh_plink_open(struct sta_info *sta) __le16 llid; struct ieee80211_sub_if_data *sdata = sta->sdata; + if (!test_sta_flags(sta, WLAN_STA_AUTH)) + return -EPERM; + spin_lock_bh(&sta->lock); get_random_bytes(&llid, 2); sta->llid = llid; @@ -484,6 +487,12 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m return; } + if (sta && !test_sta_flags(sta, WLAN_STA_AUTH)) { + mpl_dbg("Mesh plink: Action frame from non-authed peer\n"); + rcu_read_unlock(); + return; + } + if (sta && sta->plink_state == PLINK_BLOCKED) { rcu_read_unlock(); return; -- cgit v0.10.2 From 96b78dff0321d881ef27d858a462c476e0444619 Mon Sep 17 00:00:00 2001 From: Javier Cardona Date: Thu, 7 Apr 2011 15:08:33 -0700 Subject: nl80211/mac80211: Perform PLINK_ACTION on new station Modify the NEW_STATION command to accept PLINK_ACTIONS, in case userspace wants to create stations and initiate a peer link right away (for authenticated stations) or create a blocked station (for debugging). Signed-off-by: Javier Cardona Signed-off-by: John W. Linville diff --git a/net/mac80211/mesh_plink.c b/net/mac80211/mesh_plink.c index 5d0dd92..b327e0e 100644 --- a/net/mac80211/mesh_plink.c +++ b/net/mac80211/mesh_plink.c @@ -105,7 +105,7 @@ static struct sta_info *mesh_plink_alloc(struct ieee80211_sub_if_data *sdata, if (!sta) return NULL; - sta->flags = WLAN_STA_AUTHORIZED; + sta->flags = WLAN_STA_AUTHORIZED | WLAN_STA_AUTH; sta->sta.supp_rates[local->hw.conf.channel->band] = rates; rate_control_rate_init(sta); diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index ce29a0d..f4cb8ef 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -2349,11 +2349,16 @@ static int nl80211_new_station(struct sk_buff *skb, struct genl_info *info) params.ht_capa = nla_data(info->attrs[NL80211_ATTR_HT_CAPABILITY]); + if (info->attrs[NL80211_ATTR_STA_PLINK_ACTION]) + params.plink_action = + nla_get_u8(info->attrs[NL80211_ATTR_STA_PLINK_ACTION]); + if (parse_station_flags(info, ¶ms)) return -EINVAL; if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP && dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP_VLAN && + dev->ieee80211_ptr->iftype != NL80211_IFTYPE_MESH_POINT && dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO) return -EINVAL; -- cgit v0.10.2 From c93b5e717ec47b57abfe0229360bc11e77520984 Mon Sep 17 00:00:00 2001 From: Javier Cardona Date: Thu, 7 Apr 2011 15:08:34 -0700 Subject: nl80211: New notification to discover mesh peer candidates. Notify userspace when a beacon/presp is received from a suitable mesh peer candidate for whom no sta information exists. Userspace can then decide to create a sta info for the candidate. If userspace is not ready to authenticate the peer right away, it can create the sta info with the authenticated flag unset and set it later. Signed-off-by: Javier Cardona Signed-off-by: John W. Linville diff --git a/include/linux/nl80211.h b/include/linux/nl80211.h index 5ec4ac3..b874818 100644 --- a/include/linux/nl80211.h +++ b/include/linux/nl80211.h @@ -410,6 +410,16 @@ * notification. This event is used to indicate that an unprotected * disassociation frame was dropped when MFP is in use. * + * @NL80211_CMD_NEW_PEER_CANDIDATE: Notification on the reception of a + * beacon or probe response from a compatible mesh peer. This is only + * sent while no station information (sta_info) exists for the new peer + * candidate and when @NL80211_MESH_SETUP_USERSPACE_AUTH is set. On + * reception of this notification, userspace may decide to create a new + * station (@NL80211_CMD_NEW_STATION). To stop this notification from + * reoccurring, the userspace authentication daemon may want to create the + * new station with the AUTHENTICATED flag unset and maybe change it later + * depending on the authentication result. + * * @NL80211_CMD_MAX: highest used command number * @__NL80211_CMD_AFTER_LAST: internal use */ @@ -522,6 +532,8 @@ enum nl80211_commands { NL80211_CMD_UNPROT_DEAUTHENTICATE, NL80211_CMD_UNPROT_DISASSOCIATE, + NL80211_CMD_NEW_PEER_CANDIDATE, + /* add new commands above here */ /* used to define NL80211_CMD_MAX below */ diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index e77603b..f40cd30 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -2489,6 +2489,22 @@ void cfg80211_michael_mic_failure(struct net_device *dev, const u8 *addr, void cfg80211_ibss_joined(struct net_device *dev, const u8 *bssid, gfp_t gfp); /** + * cfg80211_notify_new_candidate - notify cfg80211 of a new mesh peer candidate + * + * @dev: network device + * @macaddr: the MAC address of the new candidate + * @ie: information elements advertised by the peer candidate + * @ie_len: lenght of the information elements buffer + * @gfp: allocation flags + * + * This function notifies cfg80211 that the mesh peer candidate has been + * detected, most likely via a beacon or, less likely, via a probe response. + * cfg80211 then sends a notification to userspace. + */ +void cfg80211_notify_new_peer_candidate(struct net_device *dev, + const u8 *macaddr, const u8 *ie, u8 ie_len, gfp_t gfp); + +/** * DOC: RFkill integration * * RFkill integration in cfg80211 is almost invisible to drivers, diff --git a/net/wireless/mesh.c b/net/wireless/mesh.c index e0226e8..5c11608 100644 --- a/net/wireless/mesh.c +++ b/net/wireless/mesh.c @@ -1,5 +1,6 @@ #include #include +#include "nl80211.h" #include "core.h" /* Default values, timeouts in ms */ @@ -110,6 +111,19 @@ int cfg80211_join_mesh(struct cfg80211_registered_device *rdev, return err; } +void cfg80211_notify_new_peer_candidate(struct net_device *dev, + const u8 *macaddr, const u8* ie, u8 ie_len, gfp_t gfp) +{ + struct wireless_dev *wdev = dev->ieee80211_ptr; + + if (WARN_ON(wdev->iftype != NL80211_IFTYPE_MESH_POINT)) + return; + + nl80211_send_new_peer_candidate(wiphy_to_dev(wdev->wiphy), dev, + macaddr, ie, ie_len, gfp); +} +EXPORT_SYMBOL(cfg80211_notify_new_peer_candidate); + static int __cfg80211_leave_mesh(struct cfg80211_registered_device *rdev, struct net_device *dev) { diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index f4cb8ef..58f501a 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -5818,6 +5818,44 @@ void nl80211_send_ibss_bssid(struct cfg80211_registered_device *rdev, nlmsg_free(msg); } +void nl80211_send_new_peer_candidate(struct cfg80211_registered_device *rdev, + struct net_device *netdev, + const u8 *macaddr, const u8* ie, u8 ie_len, + gfp_t gfp) +{ + struct sk_buff *msg; + void *hdr; + + msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp); + if (!msg) + return; + + hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_NEW_PEER_CANDIDATE); + if (!hdr) { + nlmsg_free(msg); + return; + } + + NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx); + NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex); + NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, macaddr); + if (ie_len && ie) + NLA_PUT(msg, NL80211_ATTR_IE, ie_len , ie); + + if (genlmsg_end(msg, hdr) < 0) { + nlmsg_free(msg); + return; + } + + genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0, + nl80211_mlme_mcgrp.id, gfp); + return; + + nla_put_failure: + genlmsg_cancel(msg, hdr); + nlmsg_free(msg); +} + void nl80211_michael_mic_failure(struct cfg80211_registered_device *rdev, struct net_device *netdev, const u8 *addr, enum nl80211_key_type key_type, int key_id, diff --git a/net/wireless/nl80211.h b/net/wireless/nl80211.h index dcac5cd..f2af695 100644 --- a/net/wireless/nl80211.h +++ b/net/wireless/nl80211.h @@ -50,6 +50,10 @@ void nl80211_send_disconnected(struct cfg80211_registered_device *rdev, struct net_device *netdev, u16 reason, const u8 *ie, size_t ie_len, bool from_ap); +void nl80211_send_new_peer_candidate(struct cfg80211_registered_device *rdev, + struct net_device *netdev, + const u8 *macaddr, const u8* ie, u8 ie_len, + gfp_t gfp); void nl80211_michael_mic_failure(struct cfg80211_registered_device *rdev, struct net_device *netdev, const u8 *addr, -- cgit v0.10.2 From 1570ca59279a74db73b8ff840abdfaf64a9ee2ff Mon Sep 17 00:00:00 2001 From: Javier Cardona Date: Thu, 7 Apr 2011 15:08:35 -0700 Subject: mac80211: send notification on new peer candidate for our secure mesh Also, advertise support for mesh authentication. Signed-off-by: Javier Cardona Signed-off-by: John W. Linville diff --git a/net/mac80211/main.c b/net/mac80211/main.c index e2db3dc..0ab2a8d 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c @@ -762,6 +762,11 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) local->hw.wiphy->interface_modes &= ~BIT(NL80211_IFTYPE_MESH_POINT); #endif + /* if the underlying driver supports mesh, mac80211 will (at least) + * provide routing of mesh authentication frames to userspace */ + if (local->hw.wiphy->interface_modes & BIT(NL80211_IFTYPE_MESH_POINT)) + local->hw.wiphy->flags |= WIPHY_FLAG_MESH_AUTH; + /* mac80211 supports control port protocol changing */ local->hw.wiphy->flags |= WIPHY_FLAG_CONTROL_PORT_PROTOCOL; diff --git a/net/mac80211/mesh.c b/net/mac80211/mesh.c index 47a26c0..1120797 100644 --- a/net/mac80211/mesh.c +++ b/net/mac80211/mesh.c @@ -590,9 +590,7 @@ static void ieee80211_mesh_rx_bcn_presp(struct ieee80211_sub_if_data *sdata, if (elems.mesh_id && elems.mesh_config && mesh_matches_local(&elems, sdata)) { supp_rates = ieee80211_sta_get_rates(local, &elems, band); - - mesh_neighbour_update(mgmt->sa, supp_rates, sdata, - mesh_peer_accepts_plinks(&elems)); + mesh_neighbour_update(mgmt->sa, supp_rates, sdata, &elems); } } diff --git a/net/mac80211/mesh.h b/net/mac80211/mesh.h index b99e230..10acf1c 100644 --- a/net/mac80211/mesh.h +++ b/net/mac80211/mesh.h @@ -226,7 +226,8 @@ void mesh_rx_path_sel_frame(struct ieee80211_sub_if_data *sdata, int mesh_path_add(u8 *dst, struct ieee80211_sub_if_data *sdata); /* Mesh plinks */ void mesh_neighbour_update(u8 *hw_addr, u32 rates, - struct ieee80211_sub_if_data *sdata, bool add); + struct ieee80211_sub_if_data *sdata, + struct ieee802_11_elems *ie); bool mesh_peer_accepts_plinks(struct ieee802_11_elems *ie); void mesh_accept_plinks_update(struct ieee80211_sub_if_data *sdata); void mesh_plink_broken(struct sta_info *sta); diff --git a/net/mac80211/mesh_plink.c b/net/mac80211/mesh_plink.c index b327e0e..84e5b05 100644 --- a/net/mac80211/mesh_plink.c +++ b/net/mac80211/mesh_plink.c @@ -237,8 +237,9 @@ static int mesh_plink_frame_tx(struct ieee80211_sub_if_data *sdata, return 0; } -void mesh_neighbour_update(u8 *hw_addr, u32 rates, struct ieee80211_sub_if_data *sdata, - bool peer_accepting_plinks) +void mesh_neighbour_update(u8 *hw_addr, u32 rates, + struct ieee80211_sub_if_data *sdata, + struct ieee802_11_elems *elems) { struct ieee80211_local *local = sdata->local; struct sta_info *sta; @@ -248,8 +249,14 @@ void mesh_neighbour_update(u8 *hw_addr, u32 rates, struct ieee80211_sub_if_data sta = sta_info_get(sdata, hw_addr); if (!sta) { rcu_read_unlock(); - - sta = mesh_plink_alloc(sdata, hw_addr, rates); + /* Userspace handles peer allocation when security is enabled + * */ + if (sdata->u.mesh.is_secure) + cfg80211_notify_new_peer_candidate(sdata->dev, hw_addr, + elems->ie_start, elems->total_len, + GFP_KERNEL); + else + sta = mesh_plink_alloc(sdata, hw_addr, rates); if (!sta) return; if (sta_info_insert_rcu(sta)) { @@ -260,7 +267,8 @@ void mesh_neighbour_update(u8 *hw_addr, u32 rates, struct ieee80211_sub_if_data sta->last_rx = jiffies; sta->sta.supp_rates[local->hw.conf.channel->band] = rates; - if (peer_accepting_plinks && sta->plink_state == PLINK_LISTEN && + if (mesh_peer_accepts_plinks(elems) && + sta->plink_state == PLINK_LISTEN && sdata->u.mesh.accepting_plinks && sdata->u.mesh.mshcfg.auto_open_plinks) mesh_plink_open(sta); -- cgit v0.10.2 From 66944e1c5797562cebe2d1857d46dff60bf9a69e Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Mon, 11 Apr 2011 22:39:40 +0000 Subject: inetpeer: reduce stack usage On 64bit arches, we use 752 bytes of stack when cleanup_once() is called from inet_getpeer(). Lets share the avl stack to save ~376 bytes. Before patch : # objdump -d net/ipv4/inetpeer.o | scripts/checkstack.pl 0x000006c3 unlink_from_pool [inetpeer.o]: 376 0x00000721 unlink_from_pool [inetpeer.o]: 376 0x00000cb1 inet_getpeer [inetpeer.o]: 376 0x00000e6d inet_getpeer [inetpeer.o]: 376 0x0004 inet_initpeers [inetpeer.o]: 112 # size net/ipv4/inetpeer.o text data bss dec hex filename 5320 432 21 5773 168d net/ipv4/inetpeer.o After patch : objdump -d net/ipv4/inetpeer.o | scripts/checkstack.pl 0x00000c11 inet_getpeer [inetpeer.o]: 376 0x00000dcd inet_getpeer [inetpeer.o]: 376 0x00000ab9 peer_check_expire [inetpeer.o]: 328 0x00000b7f peer_check_expire [inetpeer.o]: 328 0x0004 inet_initpeers [inetpeer.o]: 112 # size net/ipv4/inetpeer.o text data bss dec hex filename 5163 432 21 5616 15f0 net/ipv4/inetpeer.o Signed-off-by: Eric Dumazet Cc: Scot Doyle Cc: Stephen Hemminger Cc: Hiroaki SHIMODA Reviewed-by: Hiroaki SHIMODA Signed-off-by: David S. Miller diff --git a/net/ipv4/inetpeer.c b/net/ipv4/inetpeer.c index dd1b20e..9df4e63 100644 --- a/net/ipv4/inetpeer.c +++ b/net/ipv4/inetpeer.c @@ -354,7 +354,8 @@ static void inetpeer_free_rcu(struct rcu_head *head) } /* May be called with local BH enabled. */ -static void unlink_from_pool(struct inet_peer *p, struct inet_peer_base *base) +static void unlink_from_pool(struct inet_peer *p, struct inet_peer_base *base, + struct inet_peer __rcu **stack[PEER_MAXDEPTH]) { int do_free; @@ -368,7 +369,6 @@ static void unlink_from_pool(struct inet_peer *p, struct inet_peer_base *base) * We use refcnt=-1 to alert lockless readers this entry is deleted. */ if (atomic_cmpxchg(&p->refcnt, 1, -1) == 1) { - struct inet_peer __rcu **stack[PEER_MAXDEPTH]; struct inet_peer __rcu ***stackptr, ***delp; if (lookup(&p->daddr, stack, base) != p) BUG(); @@ -422,7 +422,7 @@ static struct inet_peer_base *peer_to_base(struct inet_peer *p) } /* May be called with local BH enabled. */ -static int cleanup_once(unsigned long ttl) +static int cleanup_once(unsigned long ttl, struct inet_peer __rcu **stack[PEER_MAXDEPTH]) { struct inet_peer *p = NULL; @@ -454,7 +454,7 @@ static int cleanup_once(unsigned long ttl) * happen because of entry limits in route cache. */ return -1; - unlink_from_pool(p, peer_to_base(p)); + unlink_from_pool(p, peer_to_base(p), stack); return 0; } @@ -524,7 +524,7 @@ struct inet_peer *inet_getpeer(struct inetpeer_addr *daddr, int create) if (base->total >= inet_peer_threshold) /* Remove one less-recently-used entry. */ - cleanup_once(0); + cleanup_once(0, stack); return p; } @@ -540,6 +540,7 @@ static void peer_check_expire(unsigned long dummy) { unsigned long now = jiffies; int ttl, total; + struct inet_peer __rcu **stack[PEER_MAXDEPTH]; total = compute_total(); if (total >= inet_peer_threshold) @@ -548,7 +549,7 @@ static void peer_check_expire(unsigned long dummy) ttl = inet_peer_maxttl - (inet_peer_maxttl - inet_peer_minttl) / HZ * total / inet_peer_threshold * HZ; - while (!cleanup_once(ttl)) { + while (!cleanup_once(ttl, stack)) { if (jiffies != now) break; } -- cgit v0.10.2 From 7d75541499319dff375af252345ae1999540b4a9 Mon Sep 17 00:00:00 2001 From: Senthil Balasubramanian Date: Fri, 8 Apr 2011 15:30:34 +0530 Subject: ath9k: Add RSSI information from control and extension chains Export RSSI information from all the control and extension channel chains to debugfs. Also add rx antenna information to debugfs. This will be useful for debugging purpose. Signed-off-by: Senthil Balasubramanian Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/debug.c b/drivers/net/wireless/ath/ath9k/debug.c index a762cad..34f191e 100644 --- a/drivers/net/wireless/ath/ath9k/debug.c +++ b/drivers/net/wireless/ath/ath9k/debug.c @@ -845,7 +845,7 @@ static ssize_t read_file_recv(struct file *file, char __user *user_buf, struct ath_softc *sc = file->private_data; char *buf; - unsigned int len = 0, size = 1152; + unsigned int len = 0, size = 1400; ssize_t retval = 0; buf = kzalloc(size, GFP_KERNEL); @@ -874,6 +874,34 @@ static ssize_t read_file_recv(struct file *file, char __user *user_buf, "%18s : %10u\n", "DECRYPT BUSY ERR", sc->debug.stats.rxstats.decrypt_busy_err); + len += snprintf(buf + len, size - len, + "%18s : %10d\n", "RSSI-CTL0", + sc->debug.stats.rxstats.rs_rssi_ctl0); + + len += snprintf(buf + len, size - len, + "%18s : %10d\n", "RSSI-CTL1", + sc->debug.stats.rxstats.rs_rssi_ctl1); + + len += snprintf(buf + len, size - len, + "%18s : %10d\n", "RSSI-CTL2", + sc->debug.stats.rxstats.rs_rssi_ctl2); + + len += snprintf(buf + len, size - len, + "%18s : %10d\n", "RSSI-EXT0", + sc->debug.stats.rxstats.rs_rssi_ext0); + + len += snprintf(buf + len, size - len, + "%18s : %10d\n", "RSSI-EXT1", + sc->debug.stats.rxstats.rs_rssi_ext1); + + len += snprintf(buf + len, size - len, + "%18s : %10d\n", "RSSI-EXT2", + sc->debug.stats.rxstats.rs_rssi_ext2); + + len += snprintf(buf + len, size - len, + "%18s : %10d\n", "Rx Antenna", + sc->debug.stats.rxstats.rs_antenna); + PHY_ERR("UNDERRUN", ATH9K_PHYERR_UNDERRUN); PHY_ERR("TIMING", ATH9K_PHYERR_TIMING); PHY_ERR("PARITY", ATH9K_PHYERR_PARITY); @@ -948,6 +976,16 @@ void ath_debug_stat_rx(struct ath_softc *sc, struct ath_rx_status *rs) RX_PHY_ERR_INC(phyerr); } + sc->debug.stats.rxstats.rs_rssi_ctl0 = rs->rs_rssi_ctl0; + sc->debug.stats.rxstats.rs_rssi_ctl1 = rs->rs_rssi_ctl1; + sc->debug.stats.rxstats.rs_rssi_ctl2 = rs->rs_rssi_ctl2; + + sc->debug.stats.rxstats.rs_rssi_ext0 = rs->rs_rssi_ext0; + sc->debug.stats.rxstats.rs_rssi_ext1 = rs->rs_rssi_ext1; + sc->debug.stats.rxstats.rs_rssi_ext2 = rs->rs_rssi_ext2; + + sc->debug.stats.rxstats.rs_antenna = rs->rs_antenna; + #undef RX_STAT_INC #undef RX_PHY_ERR_INC } diff --git a/drivers/net/wireless/ath/ath9k/debug.h b/drivers/net/wireless/ath/ath9k/debug.h index 59338de..1f9f8ea 100644 --- a/drivers/net/wireless/ath/ath9k/debug.h +++ b/drivers/net/wireless/ath/ath9k/debug.h @@ -157,6 +157,13 @@ struct ath_rx_stats { u32 post_delim_crc_err; u32 decrypt_busy_err; u32 phy_err_stats[ATH9K_PHYERR_MAX]; + int8_t rs_rssi_ctl0; + int8_t rs_rssi_ctl1; + int8_t rs_rssi_ctl2; + int8_t rs_rssi_ext0; + int8_t rs_rssi_ext1; + int8_t rs_rssi_ext2; + u8 rs_antenna; }; struct ath_stats { -- cgit v0.10.2 From d0ef824b9a712b866e38212089ade3a7114225a4 Mon Sep 17 00:00:00 2001 From: Senthil Balasubramanian Date: Fri, 8 Apr 2011 15:30:35 +0530 Subject: ath9k: Update gain table for AR9485 Update Tx gain 23 for all tx gain table. Signed-off-by: Senthil Balasubramanian Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/ar9485_initvals.h b/drivers/net/wireless/ath/ath9k/ar9485_initvals.h index f91f73e..fbdde29 100644 --- a/drivers/net/wireless/ath/ath9k/ar9485_initvals.h +++ b/drivers/net/wireless/ath/ath9k/ar9485_initvals.h @@ -396,7 +396,7 @@ static const u32 ar9485Modes_high_ob_db_tx_gain_1_1[][5] = { {0x0000a54c, 0x7203feca, 0x7203feca, 0x51001865, 0x51001865}, {0x0000a550, 0x7703ff0b, 0x7703ff0b, 0x55001a86, 0x55001a86}, {0x0000a554, 0x7d06ffcb, 0x7d06ffcb, 0x57001ce9, 0x57001ce9}, - {0x0000a558, 0x8407ff0b, 0x8407ff0b, 0x5a001eeb, 0x5a001eeb}, + {0x0000a558, 0x8407ff0b, 0x8407ff0b, 0x5a001ceb, 0x5a001ceb}, {0x0000a55c, 0x8907ffcb, 0x8907ffcb, 0x5e001eeb, 0x5e001eeb}, {0x0000a560, 0x900fff0b, 0x900fff0b, 0x5e001eeb, 0x5e001eeb}, {0x0000a564, 0x960fffcb, 0x960fffcb, 0x5e001eeb, 0x5e001eeb}, @@ -469,7 +469,7 @@ static const u32 ar9485_modes_lowest_ob_db_tx_gain_1_1[][5] = { {0x0000a54c, 0x7203feca, 0x7203feca, 0x51001865, 0x51001865}, {0x0000a550, 0x7703ff0b, 0x7703ff0b, 0x55001a86, 0x55001a86}, {0x0000a554, 0x7d06ffcb, 0x7d06ffcb, 0x57001ce9, 0x57001ce9}, - {0x0000a558, 0x8407ff0b, 0x8407ff0b, 0x5a001eeb, 0x5a001eeb}, + {0x0000a558, 0x8407ff0b, 0x8407ff0b, 0x5a001ceb, 0x5a001ceb}, {0x0000a55c, 0x8907ffcb, 0x8907ffcb, 0x5e001eeb, 0x5e001eeb}, {0x0000a560, 0x900fff0b, 0x900fff0b, 0x5e001eeb, 0x5e001eeb}, {0x0000a564, 0x960fffcb, 0x960fffcb, 0x5e001eeb, 0x5e001eeb}, @@ -635,7 +635,7 @@ static const u32 ar9485Modes_high_power_tx_gain_1_1[][5] = { {0x0000a54c, 0x7203feca, 0x7203feca, 0x51001865, 0x51001865}, {0x0000a550, 0x7703ff0b, 0x7703ff0b, 0x55001a86, 0x55001a86}, {0x0000a554, 0x7d06ffcb, 0x7d06ffcb, 0x57001ce9, 0x57001ce9}, - {0x0000a558, 0x8407ff0b, 0x8407ff0b, 0x5a001eeb, 0x5a001eeb}, + {0x0000a558, 0x8407ff0b, 0x8407ff0b, 0x5a001ceb, 0x5a001ceb}, {0x0000a55c, 0x8907ffcb, 0x8907ffcb, 0x5e001eeb, 0x5e001eeb}, {0x0000a560, 0x900fff0b, 0x900fff0b, 0x5e001eeb, 0x5e001eeb}, {0x0000a564, 0x960fffcb, 0x960fffcb, 0x5e001eeb, 0x5e001eeb}, @@ -728,7 +728,7 @@ static const u32 ar9485_modes_green_ob_db_tx_gain_1_1[][5] = { {0x0000a54c, 0x7203feca, 0x7203feca, 0x51001865, 0x51001865}, {0x0000a550, 0x7703ff0b, 0x7703ff0b, 0x55001a86, 0x55001a86}, {0x0000a554, 0x7d06ffcb, 0x7d06ffcb, 0x57001ce9, 0x57001ce9}, - {0x0000a558, 0x8407ff0b, 0x8407ff0b, 0x5a001eeb, 0x5a001eeb}, + {0x0000a558, 0x8407ff0b, 0x8407ff0b, 0x5a001ceb, 0x5a001ceb}, {0x0000a55c, 0x8907ffcb, 0x8907ffcb, 0x5e001eeb, 0x5e001eeb}, {0x0000a560, 0x900fff0b, 0x900fff0b, 0x5e001eeb, 0x5e001eeb}, {0x0000a564, 0x960fffcb, 0x960fffcb, 0x5e001eeb, 0x5e001eeb}, @@ -827,7 +827,7 @@ static const u32 ar9485Modes_low_ob_db_tx_gain_1_1[][5] = { {0x0000a54c, 0x7203feca, 0x7203feca, 0x51001865, 0x51001865}, {0x0000a550, 0x7703ff0b, 0x7703ff0b, 0x55001a86, 0x55001a86}, {0x0000a554, 0x7d06ffcb, 0x7d06ffcb, 0x57001ce9, 0x57001ce9}, - {0x0000a558, 0x8407ff0b, 0x8407ff0b, 0x5a001eeb, 0x5a001eeb}, + {0x0000a558, 0x8407ff0b, 0x8407ff0b, 0x5a001ceb, 0x5a001ceb}, {0x0000a55c, 0x8907ffcb, 0x8907ffcb, 0x5e001eeb, 0x5e001eeb}, {0x0000a560, 0x900fff0b, 0x900fff0b, 0x5e001eeb, 0x5e001eeb}, {0x0000a564, 0x960fffcb, 0x960fffcb, 0x5e001eeb, 0x5e001eeb}, -- cgit v0.10.2 From f60c49b67dd6db2ccb740a6a671414f9dab00c4f Mon Sep 17 00:00:00 2001 From: Rajkumar Manoharan Date: Fri, 8 Apr 2011 17:06:25 +0530 Subject: ath9k: Fix kernel panic on module unload The commit "ath9k: configure beacons based on hw opmode" introduced a regression which leads to kernel panic. Failed to stop ani timer during the driver unload while any of the beaconing vif is running. Signed-off-by: Rajkumar Manoharan Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/beacon.c b/drivers/net/wireless/ath/ath9k/beacon.c index eccb0ec..b56f69e 100644 --- a/drivers/net/wireless/ath/ath9k/beacon.c +++ b/drivers/net/wireless/ath/ath9k/beacon.c @@ -320,6 +320,7 @@ void ath_beacon_return(struct ath_softc *sc, struct ath_vif *avp) if (avp->av_bcbuf != NULL) { struct ath_buf *bf; + avp->is_bslot_active = false; if (avp->av_bslot != -1) { sc->beacon.bslot[avp->av_bslot] = NULL; sc->nbcnvifs--; diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index 93b9fa2..a55a892 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -1375,6 +1375,9 @@ static void ath9k_calculate_summary_state(struct ieee80211_hw *hw, if ((iter_data.naps + iter_data.nadhocs) > 0) { sc->sc_flags |= SC_OP_ANI_RUN; ath_start_ani(common); + } else { + sc->sc_flags &= ~SC_OP_ANI_RUN; + del_timer_sync(&common->ani.timer); } } -- cgit v0.10.2 From ebe27c91af8b7f4810ae906fbd3eeb2d87850026 Mon Sep 17 00:00:00 2001 From: Mohammed Shafi Shajakhan Date: Fri, 8 Apr 2011 21:24:24 +0530 Subject: {mac|nl}80211: Add station connected time Add station connected time in debugfs. This will be helpful to get a measure of stability of the connection and for debugging stress issues Cc: Senthilkumar Balasubramanian Signed-off-by: Mohammed Shafi Shajakhan Signed-off-by: John W. Linville diff --git a/include/linux/nl80211.h b/include/linux/nl80211.h index b874818..be8df57 100644 --- a/include/linux/nl80211.h +++ b/include/linux/nl80211.h @@ -1297,6 +1297,7 @@ enum nl80211_sta_bss_param { * attribute, like NL80211_STA_INFO_TX_BITRATE. * @NL80211_STA_INFO_BSS_PARAM: current station's view of BSS, nested attribute * containing info as possible, see &enum nl80211_sta_bss_param + * @NL80211_STA_INFO_CONNECTED_TIME: time since the station is last connected * @__NL80211_STA_INFO_AFTER_LAST: internal * @NL80211_STA_INFO_MAX: highest possible station info attribute */ @@ -1317,6 +1318,7 @@ enum nl80211_sta_info { NL80211_STA_INFO_SIGNAL_AVG, NL80211_STA_INFO_RX_BITRATE, NL80211_STA_INFO_BSS_PARAM, + NL80211_STA_INFO_CONNECTED_TIME, /* keep last */ __NL80211_STA_INFO_AFTER_LAST, diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index f40cd30..d30eada 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -423,6 +423,7 @@ struct station_parameters { * @STATION_INFO_SIGNAL_AVG: @signal_avg filled * @STATION_INFO_RX_BITRATE: @rxrate fields are filled * @STATION_INFO_BSS_PARAM: @bss_param filled + * @STATION_INFO_CONNECTED_TIME: @connected_time filled */ enum station_info_flags { STATION_INFO_INACTIVE_TIME = 1<<0, @@ -441,6 +442,7 @@ enum station_info_flags { STATION_INFO_SIGNAL_AVG = 1<<13, STATION_INFO_RX_BITRATE = 1<<14, STATION_INFO_BSS_PARAM = 1<<15, + STATION_INFO_CONNECTED_TIME = 1<<16 }; /** @@ -511,6 +513,7 @@ struct sta_bss_parameters { * Station information filled by driver for get_station() and dump_station. * * @filled: bitflag of flags from &enum station_info_flags + * @connected_time: time(in secs) since a station is last connected * @inactive_time: time since last station activity (tx/rx) in milliseconds * @rx_bytes: bytes received from this station * @tx_bytes: bytes transmitted to this station @@ -533,6 +536,7 @@ struct sta_bss_parameters { */ struct station_info { u32 filled; + u32 connected_time; u32 inactive_time; u32 rx_bytes; u32 tx_bytes; diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index 1c25723..a6d191f 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -330,6 +330,7 @@ static void rate_idx_to_bitrate(struct rate_info *rate, struct sta_info *sta, in static void sta_set_sinfo(struct sta_info *sta, struct station_info *sinfo) { struct ieee80211_sub_if_data *sdata = sta->sdata; + struct timespec uptime; sinfo->generation = sdata->local->sta_generation; @@ -343,7 +344,11 @@ static void sta_set_sinfo(struct sta_info *sta, struct station_info *sinfo) STATION_INFO_TX_BITRATE | STATION_INFO_RX_BITRATE | STATION_INFO_RX_DROP_MISC | - STATION_INFO_BSS_PARAM; + STATION_INFO_BSS_PARAM | + STATION_INFO_CONNECTED_TIME; + + do_posix_clock_monotonic_gettime(&uptime); + sinfo->connected_time = uptime.tv_sec - sta->last_connected; sinfo->inactive_time = jiffies_to_msecs(jiffies - sta->last_rx); sinfo->rx_bytes = sta->rx_bytes; diff --git a/net/mac80211/debugfs_sta.c b/net/mac80211/debugfs_sta.c index c04a139..c008232 100644 --- a/net/mac80211/debugfs_sta.c +++ b/net/mac80211/debugfs_sta.c @@ -92,6 +92,31 @@ static ssize_t sta_inactive_ms_read(struct file *file, char __user *userbuf, } STA_OPS(inactive_ms); + +static ssize_t sta_connected_time_read(struct file *file, char __user *userbuf, + size_t count, loff_t *ppos) +{ + struct sta_info *sta = file->private_data; + struct timespec uptime; + struct tm result; + long connected_time_secs; + char buf[100]; + int res; + do_posix_clock_monotonic_gettime(&uptime); + connected_time_secs = uptime.tv_sec - sta->last_connected; + time_to_tm(connected_time_secs, 0, &result); + result.tm_year -= 70; + result.tm_mday -= 1; + res = scnprintf(buf, sizeof(buf), + "years - %d\nmonths - %d\ndays - %d\nclock - %d:%d:%d\n\n", + result.tm_year, result.tm_mon, result.tm_mday, + result.tm_hour, result.tm_min, result.tm_sec); + return simple_read_from_buffer(userbuf, count, ppos, buf, res); +} +STA_OPS(connected_time); + + + static ssize_t sta_last_seq_ctrl_read(struct file *file, char __user *userbuf, size_t count, loff_t *ppos) { @@ -324,6 +349,7 @@ void ieee80211_sta_debugfs_add(struct sta_info *sta) DEBUGFS_ADD(flags); DEBUGFS_ADD(num_ps_buf_frames); DEBUGFS_ADD(inactive_ms); + DEBUGFS_ADD(connected_time); DEBUGFS_ADD(last_seq_ctrl); DEBUGFS_ADD(agg_status); DEBUGFS_ADD(dev); diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c index 999f8fb..8a9068a 100644 --- a/net/mac80211/sta_info.c +++ b/net/mac80211/sta_info.c @@ -228,6 +228,7 @@ struct sta_info *sta_info_alloc(struct ieee80211_sub_if_data *sdata, { struct ieee80211_local *local = sdata->local; struct sta_info *sta; + struct timespec uptime; int i; sta = kzalloc(sizeof(*sta) + local->hw.sta_data_size, gfp); @@ -245,6 +246,8 @@ struct sta_info *sta_info_alloc(struct ieee80211_sub_if_data *sdata, sta->sdata = sdata; sta->last_rx = jiffies; + do_posix_clock_monotonic_gettime(&uptime); + sta->last_connected = uptime.tv_sec; ewma_init(&sta->avg_signal, 1024, 8); if (sta_prepare_rate_control(local, sta, gfp)) { diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h index 43238e9..984a03d 100644 --- a/net/mac80211/sta_info.h +++ b/net/mac80211/sta_info.h @@ -226,6 +226,7 @@ enum plink_state { * @rx_bytes: Number of bytes received from this STA * @wep_weak_iv_count: number of weak WEP IVs received from this station * @last_rx: time (in jiffies) when last frame was received from this STA + * @last_connected: time (in seconds) when a station got connected * @num_duplicates: number of duplicate frames received from this STA * @rx_fragments: number of received MPDUs * @rx_dropped: number of dropped MPDUs from this STA @@ -295,6 +296,7 @@ struct sta_info { unsigned long rx_packets, rx_bytes; unsigned long wep_weak_iv_count; unsigned long last_rx; + long last_connected; unsigned long num_duplicates; unsigned long rx_fragments; unsigned long rx_dropped; diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 58f501a..0efa7fd 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -2020,6 +2020,9 @@ static int nl80211_send_station(struct sk_buff *msg, u32 pid, u32 seq, sinfoattr = nla_nest_start(msg, NL80211_ATTR_STA_INFO); if (!sinfoattr) goto nla_put_failure; + if (sinfo->filled & STATION_INFO_CONNECTED_TIME) + NLA_PUT_U32(msg, NL80211_STA_INFO_CONNECTED_TIME, + sinfo->connected_time); if (sinfo->filled & STATION_INFO_INACTIVE_TIME) NLA_PUT_U32(msg, NL80211_STA_INFO_INACTIVE_TIME, sinfo->inactive_time); -- cgit v0.10.2 From 1296433bf39a8dea852aafad1f29b775f993bca1 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Fri, 8 Apr 2011 20:49:16 +0200 Subject: ath9k_hw: remove unnecessary parts of the AR9380 SREV check Older versions have not been sold and the driver does not explicitly check for them anyway, so we can simply ignore the macRev here. Reduces ath9k_hw size on mips by more than 2 KB. Signed-off-by: Felix Fietkau Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/reg.h b/drivers/net/wireless/ath/ath9k/reg.h index 693d543..2fbbe88 100644 --- a/drivers/net/wireless/ath/ath9k/reg.h +++ b/drivers/net/wireless/ath/ath9k/reg.h @@ -858,9 +858,7 @@ #define AR_SREV_9300(_ah) \ (((_ah)->hw_version.macVersion == AR_SREV_VERSION_9300)) #define AR_SREV_9300_20_OR_LATER(_ah) \ - (((_ah)->hw_version.macVersion > AR_SREV_VERSION_9300) || \ - (((_ah)->hw_version.macVersion == AR_SREV_VERSION_9300) && \ - ((_ah)->hw_version.macRev >= AR_SREV_REVISION_9300_20))) + ((_ah)->hw_version.macVersion >= AR_SREV_VERSION_9300) #define AR_SREV_9485(_ah) \ (((_ah)->hw_version.macVersion == AR_SREV_VERSION_9485)) -- cgit v0.10.2 From ba30c4a58ceb10e81dbf6bd80aeb6a4db42db8fe Mon Sep 17 00:00:00 2001 From: Yogesh Ashok Powar Date: Sat, 9 Apr 2011 00:25:37 +0530 Subject: mwl8k: Fix checkpatch.pl and sparse warnings and errors Fix checkpatch errors and warnings comprising of indent errors, spaces and __packed warnings. Also fix 'make C = 2' warnings. Signed-off-by: Yogesh Ashok Powar Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c index 8913180..fb472f4 100644 --- a/drivers/net/wireless/mwl8k.c +++ b/drivers/net/wireless/mwl8k.c @@ -701,7 +701,7 @@ static int mwl8k_load_firmware(struct ieee80211_hw *hw) "helper image\n", pci_name(priv->pdev)); return rc; } - msleep(5); + msleep(20); rc = mwl8k_feed_fw_image(priv, fw->data, fw->size); } else { @@ -823,8 +823,8 @@ static void mwl8k_encapsulate_tx_frame(struct sk_buff *skb) /* * Make sure the packet header is in the DMA header format (4-address * without QoS), the necessary crypto padding between the header and the - * payload has already been provided by mac80211, but it doesn't add tail - * padding when HW crypto is enabled. + * payload has already been provided by mac80211, but it doesn't add + * tail padding when HW crypto is enabled. * * We have the following trailer padding requirements: * - WEP: 4 trailer bytes (ICV) @@ -1487,9 +1487,8 @@ static int mwl8k_tx_wait_empty(struct ieee80211_hw *hw) if (timeout) { WARN_ON(priv->pending_tx_pkts); - if (retry) { + if (retry) wiphy_notice(hw->wiphy, "tx rings drained\n"); - } break; } @@ -1649,8 +1648,8 @@ mwl8k_txq_reclaim(struct ieee80211_hw *hw, int index, int limit, int force) /* Rate control is happening in the firmware. * Ensure no tx rate is being reported. */ - info->status.rates[0].idx = -1; - info->status.rates[0].count = 1; + info->status.rates[0].idx = -1; + info->status.rates[0].count = 1; if (MWL8K_TXD_SUCCESS(status)) info->flags |= IEEE80211_TX_STAT_ACK; @@ -1688,7 +1687,7 @@ static void mwl8k_txq_deinit(struct ieee80211_hw *hw, int index) } /* caller must hold priv->stream_lock when calling the stream functions */ -struct mwl8k_ampdu_stream * +static struct mwl8k_ampdu_stream * mwl8k_add_stream(struct ieee80211_hw *hw, struct ieee80211_sta *sta, u8 tid) { struct mwl8k_ampdu_stream *stream; @@ -2657,7 +2656,7 @@ struct mwl8k_cmd_tx_power { __le16 bw; __le16 sub_ch; __le16 power_level_list[MWL8K_TX_POWER_LEVEL_TOTAL]; -} __attribute__((packed)); +} __packed; static int mwl8k_cmd_tx_power(struct ieee80211_hw *hw, struct ieee80211_conf *conf, @@ -3520,13 +3519,13 @@ static int mwl8k_cmd_bss_start(struct ieee80211_hw *hw, #define BASTREAM_FLAG_DIRECTION_UPSTREAM 0x00 #define BASTREAM_FLAG_IMMEDIATE_TYPE 0x01 -enum { +enum ba_stream_action_type { MWL8K_BA_CREATE, MWL8K_BA_UPDATE, MWL8K_BA_DESTROY, MWL8K_BA_FLUSH, MWL8K_BA_CHECK, -} ba_stream_action_type; +}; struct mwl8k_create_ba_stream { @@ -3780,7 +3779,7 @@ struct mwl8k_cmd_update_encryption { __u8 mac_addr[6]; __u8 encr_type; -} __attribute__((packed)); +} __packed; struct mwl8k_cmd_set_key { struct mwl8k_cmd_pkt header; @@ -3800,7 +3799,7 @@ struct mwl8k_cmd_set_key { __le16 tkip_tsc_low; __le32 tkip_tsc_high; __u8 mac_addr[6]; -} __attribute__((packed)); +} __packed; enum { MWL8K_ENCR_ENABLE, @@ -4502,7 +4501,7 @@ mwl8k_bss_info_changed_sta(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_bss_conf *info, u32 changed) { struct mwl8k_priv *priv = hw->priv; - u32 ap_legacy_rates; + u32 ap_legacy_rates = 0; u8 ap_mcs_rates[16]; int rc; -- cgit v0.10.2 From a065784620a2b78a2bbd00e066c004644d227ea8 Mon Sep 17 00:00:00 2001 From: "John W. Linville" Date: Fri, 8 Apr 2011 15:33:12 -0400 Subject: ath5k: improve pcal error handling for ENOMEM case The ath5k driver does kmalloc allocations for pcal info in a loop. But, if one fails it was simply returning -ENOMEM without freeing already allocated memory. This patch corrects that oversight. Reported-by: Eugene A. Shatokhin Signed-off-by: John W. Linville Reviewed-by: Bob Copeland diff --git a/drivers/net/wireless/ath/ath5k/eeprom.c b/drivers/net/wireless/ath/ath5k/eeprom.c index b6561f7..fb12027 100644 --- a/drivers/net/wireless/ath/ath5k/eeprom.c +++ b/drivers/net/wireless/ath/ath5k/eeprom.c @@ -660,6 +660,53 @@ ath5k_get_pcdac_intercepts(struct ath5k_hw *ah, u8 min, u8 max, u8 *vp) vp[i] = (ip[i] * max + (100 - ip[i]) * min) / 100; } +static int +ath5k_eeprom_free_pcal_info(struct ath5k_hw *ah, int mode) +{ + struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom; + struct ath5k_chan_pcal_info *chinfo; + u8 pier, pdg; + + switch (mode) { + case AR5K_EEPROM_MODE_11A: + if (!AR5K_EEPROM_HDR_11A(ee->ee_header)) + return 0; + chinfo = ee->ee_pwr_cal_a; + break; + case AR5K_EEPROM_MODE_11B: + if (!AR5K_EEPROM_HDR_11B(ee->ee_header)) + return 0; + chinfo = ee->ee_pwr_cal_b; + break; + case AR5K_EEPROM_MODE_11G: + if (!AR5K_EEPROM_HDR_11G(ee->ee_header)) + return 0; + chinfo = ee->ee_pwr_cal_g; + break; + default: + return -EINVAL; + } + + for (pier = 0; pier < ee->ee_n_piers[mode]; pier++) { + if (!chinfo[pier].pd_curves) + continue; + + for (pdg = 0; pdg < ee->ee_pd_gains[mode]; pdg++) { + struct ath5k_pdgain_info *pd = + &chinfo[pier].pd_curves[pdg]; + + if (pd != NULL) { + kfree(pd->pd_step); + kfree(pd->pd_pwr); + } + } + + kfree(chinfo[pier].pd_curves); + } + + return 0; +} + /* Convert RF5111 specific data to generic raw data * used by interpolation code */ static int @@ -684,7 +731,7 @@ ath5k_eeprom_convert_pcal_info_5111(struct ath5k_hw *ah, int mode, GFP_KERNEL); if (!chinfo[pier].pd_curves) - return -ENOMEM; + goto err_out; /* Only one curve for RF5111 * find out which one and place @@ -708,12 +755,12 @@ ath5k_eeprom_convert_pcal_info_5111(struct ath5k_hw *ah, int mode, pd->pd_step = kcalloc(AR5K_EEPROM_N_PWR_POINTS_5111, sizeof(u8), GFP_KERNEL); if (!pd->pd_step) - return -ENOMEM; + goto err_out; pd->pd_pwr = kcalloc(AR5K_EEPROM_N_PWR_POINTS_5111, sizeof(s16), GFP_KERNEL); if (!pd->pd_pwr) - return -ENOMEM; + goto err_out; /* Fill raw dataset * (convert power to 0.25dB units @@ -734,6 +781,10 @@ ath5k_eeprom_convert_pcal_info_5111(struct ath5k_hw *ah, int mode, } return 0; + +err_out: + ath5k_eeprom_free_pcal_info(ah, mode); + return -ENOMEM; } /* Parse EEPROM data */ @@ -867,7 +918,7 @@ ath5k_eeprom_convert_pcal_info_5112(struct ath5k_hw *ah, int mode, GFP_KERNEL); if (!chinfo[pier].pd_curves) - return -ENOMEM; + goto err_out; /* Fill pd_curves */ for (pdg = 0; pdg < ee->ee_pd_gains[mode]; pdg++) { @@ -886,14 +937,13 @@ ath5k_eeprom_convert_pcal_info_5112(struct ath5k_hw *ah, int mode, sizeof(u8), GFP_KERNEL); if (!pd->pd_step) - return -ENOMEM; + goto err_out; pd->pd_pwr = kcalloc(pd->pd_points, sizeof(s16), GFP_KERNEL); if (!pd->pd_pwr) - return -ENOMEM; - + goto err_out; /* Fill raw dataset * (all power levels are in 0.25dB units) */ @@ -925,13 +975,13 @@ ath5k_eeprom_convert_pcal_info_5112(struct ath5k_hw *ah, int mode, sizeof(u8), GFP_KERNEL); if (!pd->pd_step) - return -ENOMEM; + goto err_out; pd->pd_pwr = kcalloc(pd->pd_points, sizeof(s16), GFP_KERNEL); if (!pd->pd_pwr) - return -ENOMEM; + goto err_out; /* Fill raw dataset * (all power levels are in 0.25dB units) */ @@ -954,6 +1004,10 @@ ath5k_eeprom_convert_pcal_info_5112(struct ath5k_hw *ah, int mode, } return 0; + +err_out: + ath5k_eeprom_free_pcal_info(ah, mode); + return -ENOMEM; } /* Parse EEPROM data */ @@ -1156,7 +1210,7 @@ ath5k_eeprom_convert_pcal_info_2413(struct ath5k_hw *ah, int mode, GFP_KERNEL); if (!chinfo[pier].pd_curves) - return -ENOMEM; + goto err_out; /* Fill pd_curves */ for (pdg = 0; pdg < ee->ee_pd_gains[mode]; pdg++) { @@ -1177,13 +1231,13 @@ ath5k_eeprom_convert_pcal_info_2413(struct ath5k_hw *ah, int mode, sizeof(u8), GFP_KERNEL); if (!pd->pd_step) - return -ENOMEM; + goto err_out; pd->pd_pwr = kcalloc(pd->pd_points, sizeof(s16), GFP_KERNEL); if (!pd->pd_pwr) - return -ENOMEM; + goto err_out; /* Fill raw dataset * convert all pwr levels to @@ -1213,6 +1267,10 @@ ath5k_eeprom_convert_pcal_info_2413(struct ath5k_hw *ah, int mode, } return 0; + +err_out: + ath5k_eeprom_free_pcal_info(ah, mode); + return -ENOMEM; } /* Parse EEPROM data */ @@ -1534,53 +1592,6 @@ ath5k_eeprom_read_pcal_info(struct ath5k_hw *ah) return 0; } -static int -ath5k_eeprom_free_pcal_info(struct ath5k_hw *ah, int mode) -{ - struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom; - struct ath5k_chan_pcal_info *chinfo; - u8 pier, pdg; - - switch (mode) { - case AR5K_EEPROM_MODE_11A: - if (!AR5K_EEPROM_HDR_11A(ee->ee_header)) - return 0; - chinfo = ee->ee_pwr_cal_a; - break; - case AR5K_EEPROM_MODE_11B: - if (!AR5K_EEPROM_HDR_11B(ee->ee_header)) - return 0; - chinfo = ee->ee_pwr_cal_b; - break; - case AR5K_EEPROM_MODE_11G: - if (!AR5K_EEPROM_HDR_11G(ee->ee_header)) - return 0; - chinfo = ee->ee_pwr_cal_g; - break; - default: - return -EINVAL; - } - - for (pier = 0; pier < ee->ee_n_piers[mode]; pier++) { - if (!chinfo[pier].pd_curves) - continue; - - for (pdg = 0; pdg < ee->ee_pd_gains[mode]; pdg++) { - struct ath5k_pdgain_info *pd = - &chinfo[pier].pd_curves[pdg]; - - if (pd != NULL) { - kfree(pd->pd_step); - kfree(pd->pd_pwr); - } - } - - kfree(chinfo[pier].pd_curves); - } - - return 0; -} - /* Read conformance test limits used for regulatory control */ static int ath5k_eeprom_read_ctl_info(struct ath5k_hw *ah) -- cgit v0.10.2 From 6d7b97b23e114c8fbb825e6721164d228c1af3fc Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Sat, 9 Apr 2011 21:37:14 +0200 Subject: ath5k: fix tx status reporting issues During normal operation, minstrel was showing suspicious EWMA probabilities exceeding 100%. It looks like the tx status reporting in ath5k was not properly clearing the rate index for rates which were never attempted. This is caused by uninitialized stale data in the on-stack tx status information, which is reused when more frames are received. To fix this, rely on ts->ts_final_idx to select the last attempted rate, instead of checking whether ts->ts_rate is set. Additionally, the conversion from the driver rate index back to the mac80211 rate index can be dropped, as the mac80211 tx status will still have the original rate index which was used to set up the descriptor. Additionally, one more inaccuracy was fixed - the final rate attempt count only needs to be increased by one if the transmission attempt was successful. Signed-off-by: Felix Fietkau Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath5k/base.c b/drivers/net/wireless/ath/ath5k/base.c index 4d7f21e..753662f 100644 --- a/drivers/net/wireless/ath/ath5k/base.c +++ b/drivers/net/wireless/ath/ath5k/base.c @@ -1580,21 +1580,14 @@ ath5k_tx_frame_completed(struct ath5k_softc *sc, struct sk_buff *skb, info = IEEE80211_SKB_CB(skb); ieee80211_tx_info_clear_status(info); - for (i = 0; i < 4; i++) { + for (i = 0; i <= ts->ts_final_idx; i++) { struct ieee80211_tx_rate *r = &info->status.rates[i]; - if (ts->ts_rate[i]) { - r->idx = ath5k_hw_to_driver_rix(sc, ts->ts_rate[i]); - r->count = ts->ts_retry[i]; - } else { - r->idx = -1; - r->count = 0; - } + r->count = ts->ts_retry[i]; } - /* count the successful attempt as well */ - info->status.rates[ts->ts_final_idx].count++; + info->status.rates[ts->ts_final_idx + 1].idx = -1; if (unlikely(ts->ts_status)) { sc->stats.ack_fail++; @@ -1609,6 +1602,9 @@ ath5k_tx_frame_completed(struct ath5k_softc *sc, struct sk_buff *skb, } else { info->flags |= IEEE80211_TX_STAT_ACK; info->status.ack_signal = ts->ts_rssi; + + /* count the successful attempt as well */ + info->status.rates[ts->ts_final_idx].count++; } /* -- cgit v0.10.2 From a27049e2c926bcf68360532a5ae66e408296ae85 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Sat, 9 Apr 2011 23:10:19 +0200 Subject: ath5k: fix short preamble rate duration value Subtract the difference in preamble duration (in usec) from the value returned by ieee80211_generic_frame_duration. Signed-off-by: Felix Fietkau Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath5k/ath5k.h b/drivers/net/wireless/ath/ath5k/ath5k.h index 8a06dbd..996d8af 100644 --- a/drivers/net/wireless/ath/ath5k/ath5k.h +++ b/drivers/net/wireless/ath/ath5k/ath5k.h @@ -1233,7 +1233,7 @@ int ath5k_eeprom_read_mac(struct ath5k_hw *ah, u8 *mac); /* Protocol Control Unit Functions */ /* Helpers */ int ath5k_hw_get_frame_duration(struct ath5k_hw *ah, - int len, struct ieee80211_rate *rate); + int len, struct ieee80211_rate *rate, bool shortpre); unsigned int ath5k_hw_get_default_slottime(struct ath5k_hw *ah); unsigned int ath5k_hw_get_default_sifs(struct ath5k_hw *ah); extern int ath5k_hw_set_opmode(struct ath5k_hw *ah, enum nl80211_iftype opmode); diff --git a/drivers/net/wireless/ath/ath5k/pcu.c b/drivers/net/wireless/ath/ath5k/pcu.c index a702817..e342e47 100644 --- a/drivers/net/wireless/ath/ath5k/pcu.c +++ b/drivers/net/wireless/ath/ath5k/pcu.c @@ -75,7 +75,7 @@ static const unsigned int ack_rates_high[] = * bwmodes. */ int ath5k_hw_get_frame_duration(struct ath5k_hw *ah, - int len, struct ieee80211_rate *rate) + int len, struct ieee80211_rate *rate, bool shortpre) { struct ath5k_softc *sc = ah->ah_sc; int sifs, preamble, plcp_bits, sym_time; @@ -84,9 +84,15 @@ int ath5k_hw_get_frame_duration(struct ath5k_hw *ah, /* Fallback */ if (!ah->ah_bwmode) { - dur = ieee80211_generic_frame_duration(sc->hw, - NULL, len, rate); - return le16_to_cpu(dur); + __le16 raw_dur = ieee80211_generic_frame_duration(sc->hw, + NULL, len, rate); + + /* subtract difference between long and short preamble */ + dur = le16_to_cpu(raw_dur); + if (shortpre) + dur -= 96; + + return dur; } bitrate = rate->bitrate; @@ -263,27 +269,14 @@ static inline void ath5k_hw_write_rate_duration(struct ath5k_hw *ah) * actual rate for this rate. See mac80211 tx.c * ieee80211_duration() for a brief description of * what rate we should choose to TX ACKs. */ - tx_time = ath5k_hw_get_frame_duration(ah, 10, rate); + tx_time = ath5k_hw_get_frame_duration(ah, 10, rate, false); ath5k_hw_reg_write(ah, tx_time, reg); if (!(rate->flags & IEEE80211_RATE_SHORT_PREAMBLE)) continue; - /* - * We're not distinguishing short preamble here, - * This is true, all we'll get is a longer value here - * which is not necessarilly bad. We could use - * export ieee80211_frame_duration() but that needs to be - * fixed first to be properly used by mac802111 drivers: - * - * - remove erp stuff and let the routine figure ofdm - * erp rates - * - remove passing argument ieee80211_local as - * drivers don't have access to it - * - move drivers using ieee80211_generic_frame_duration() - * to this - */ + tx_time = ath5k_hw_get_frame_duration(ah, 10, rate, true); ath5k_hw_reg_write(ah, tx_time, reg + (AR5K_SET_SHORT_PREAMBLE << 2)); } diff --git a/drivers/net/wireless/ath/ath5k/qcu.c b/drivers/net/wireless/ath/ath5k/qcu.c index 3343fb9..93abcfa 100644 --- a/drivers/net/wireless/ath/ath5k/qcu.c +++ b/drivers/net/wireless/ath/ath5k/qcu.c @@ -550,7 +550,7 @@ int ath5k_hw_set_ifs_intervals(struct ath5k_hw *ah, unsigned int slot_time) else rate = &sc->sbands[IEEE80211_BAND_2GHZ].bitrates[0]; - ack_tx_time = ath5k_hw_get_frame_duration(ah, 10, rate); + ack_tx_time = ath5k_hw_get_frame_duration(ah, 10, rate, false); /* ack_tx_time includes an SIFS already */ eifs = ack_tx_time + sifs + 2 * slot_time; -- cgit v0.10.2 From 488a50176c169eb36544b4f970c8bba68ede30a1 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Sat, 9 Apr 2011 23:10:20 +0200 Subject: ath5k: fix SIFS time handling ath5k uses 8 usec as a sifs time, extracted from the initvals, whereas the standard requires a sifs time of 10. The difference originates from the fact that the SIFS register has an offset of 2 usec. Fix the SIFS time definition to use the standard value of 10 usec and subtract 2 usecs when writing the SIFS register. Signed-off-by: Felix Fietkau Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath5k/ath5k.h b/drivers/net/wireless/ath/ath5k/ath5k.h index 996d8af..a49aeac 100644 --- a/drivers/net/wireless/ath/ath5k/ath5k.h +++ b/drivers/net/wireless/ath/ath5k/ath5k.h @@ -224,8 +224,7 @@ /* SIFS */ #define AR5K_INIT_SIFS_TURBO 6 -/* XXX: 8 from initvals 10 from standard */ -#define AR5K_INIT_SIFS_DEFAULT_BG 8 +#define AR5K_INIT_SIFS_DEFAULT_BG 10 #define AR5K_INIT_SIFS_DEFAULT_A 16 #define AR5K_INIT_SIFS_HALF_RATE 32 #define AR5K_INIT_SIFS_QUARTER_RATE 64 diff --git a/drivers/net/wireless/ath/ath5k/qcu.c b/drivers/net/wireless/ath/ath5k/qcu.c index 93abcfa..b18c502 100644 --- a/drivers/net/wireless/ath/ath5k/qcu.c +++ b/drivers/net/wireless/ath/ath5k/qcu.c @@ -519,7 +519,7 @@ int ath5k_hw_set_ifs_intervals(struct ath5k_hw *ah, unsigned int slot_time) return -EINVAL; sifs = ath5k_hw_get_default_sifs(ah); - sifs_clock = ath5k_hw_htoclock(ah, sifs); + sifs_clock = ath5k_hw_htoclock(ah, sifs - 2); /* EIFS * Txtime of ack at lowest rate + SIFS + DIFS -- cgit v0.10.2 From b1ad1b6febb7772583c98d9a879fbbdb82a726a7 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Sat, 9 Apr 2011 23:10:21 +0200 Subject: ath5k: fix slot time handling Set the slot time based on the mac80211 short slot vs long slot setting instead of just forcing long slot for all CCK-enabled channels. This slightly improves 802.11g mode performance in in my tests. Signed-off-by: Felix Fietkau Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath5k/ath5k.h b/drivers/net/wireless/ath/ath5k/ath5k.h index a49aeac..4bb381c 100644 --- a/drivers/net/wireless/ath/ath5k/ath5k.h +++ b/drivers/net/wireless/ath/ath5k/ath5k.h @@ -1057,6 +1057,7 @@ struct ath5k_hw { u8 ah_coverage_class; bool ah_ack_bitrate_high; u8 ah_bwmode; + bool ah_short_slot; /* Antenna Control */ u32 ah_ant_ctl[AR5K_EEPROM_N_MODES][AR5K_ANT_MAX]; diff --git a/drivers/net/wireless/ath/ath5k/mac80211-ops.c b/drivers/net/wireless/ath/ath5k/mac80211-ops.c index 9be29b7..807bd64 100644 --- a/drivers/net/wireless/ath/ath5k/mac80211-ops.c +++ b/drivers/net/wireless/ath/ath5k/mac80211-ops.c @@ -282,6 +282,15 @@ ath5k_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif, if (changes & BSS_CHANGED_BEACON_INT) sc->bintval = bss_conf->beacon_int; + if (changes & BSS_CHANGED_ERP_SLOT) { + int slot_time; + + ah->ah_short_slot = bss_conf->use_short_slot; + slot_time = ath5k_hw_get_default_slottime(ah) + + 3 * ah->ah_coverage_class; + ath5k_hw_set_ifs_intervals(ah, slot_time); + } + if (changes & BSS_CHANGED_ASSOC) { avf->assoc = bss_conf->assoc; if (bss_conf->assoc) diff --git a/drivers/net/wireless/ath/ath5k/pcu.c b/drivers/net/wireless/ath/ath5k/pcu.c index e342e47..71b60b7 100644 --- a/drivers/net/wireless/ath/ath5k/pcu.c +++ b/drivers/net/wireless/ath/ath5k/pcu.c @@ -151,9 +151,9 @@ unsigned int ath5k_hw_get_default_slottime(struct ath5k_hw *ah) slot_time = AR5K_INIT_SLOT_TIME_QUARTER_RATE; break; case AR5K_BWMODE_DEFAULT: - slot_time = AR5K_INIT_SLOT_TIME_DEFAULT; default: - if (channel->hw_value & CHANNEL_CCK) + slot_time = AR5K_INIT_SLOT_TIME_DEFAULT; + if ((channel->hw_value & CHANNEL_CCK) && !ah->ah_short_slot) slot_time = AR5K_INIT_SLOT_TIME_B; break; } -- cgit v0.10.2 From c5e0a88aa2e0f42cdb4c79c977c52f6bc38ec160 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Sun, 10 Apr 2011 18:32:13 +0200 Subject: ath5k: optimize tx descriptor setup Use local variables to reduce the number of load/store operations on uncached memory. Signed-off-by: Felix Fietkau Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath5k/desc.c b/drivers/net/wireless/ath/ath5k/desc.c index 16b44ff..0a8a9ef 100644 --- a/drivers/net/wireless/ath/ath5k/desc.c +++ b/drivers/net/wireless/ath/ath5k/desc.c @@ -184,6 +184,7 @@ static int ath5k_hw_setup_4word_tx_desc(struct ath5k_hw *ah, { struct ath5k_hw_4w_tx_ctl *tx_ctl; unsigned int frame_len; + u32 txctl0 = 0, txctl1 = 0, txctl2 = 0, txctl3 = 0; tx_ctl = &desc->ud.ds_tx5212.tx_ctl; @@ -209,7 +210,8 @@ static int ath5k_hw_setup_4word_tx_desc(struct ath5k_hw *ah, tx_power = AR5K_TUNE_MAX_TXPOWER; /* Clear descriptor */ - memset(&desc->ud.ds_tx5212, 0, sizeof(struct ath5k_hw_5212_tx_desc)); + memset(&desc->ud.ds_tx5212.tx_stat, 0, + sizeof(desc->ud.ds_tx5212.tx_stat)); /* Setup control descriptor */ @@ -221,7 +223,7 @@ static int ath5k_hw_setup_4word_tx_desc(struct ath5k_hw *ah, if (frame_len & ~AR5K_4W_TX_DESC_CTL0_FRAME_LEN) return -EINVAL; - tx_ctl->tx_control_0 = frame_len & AR5K_4W_TX_DESC_CTL0_FRAME_LEN; + txctl0 = frame_len & AR5K_4W_TX_DESC_CTL0_FRAME_LEN; /* Verify and set buffer length */ @@ -232,21 +234,17 @@ static int ath5k_hw_setup_4word_tx_desc(struct ath5k_hw *ah, if (pkt_len & ~AR5K_4W_TX_DESC_CTL1_BUF_LEN) return -EINVAL; - tx_ctl->tx_control_1 = pkt_len & AR5K_4W_TX_DESC_CTL1_BUF_LEN; + txctl1 = pkt_len & AR5K_4W_TX_DESC_CTL1_BUF_LEN; - tx_ctl->tx_control_0 |= - AR5K_REG_SM(tx_power, AR5K_4W_TX_DESC_CTL0_XMIT_POWER) | - AR5K_REG_SM(antenna_mode, AR5K_4W_TX_DESC_CTL0_ANT_MODE_XMIT); - tx_ctl->tx_control_1 |= AR5K_REG_SM(type, - AR5K_4W_TX_DESC_CTL1_FRAME_TYPE); - tx_ctl->tx_control_2 = AR5K_REG_SM(tx_tries0, - AR5K_4W_TX_DESC_CTL2_XMIT_TRIES0); - tx_ctl->tx_control_3 = tx_rate0 & AR5K_4W_TX_DESC_CTL3_XMIT_RATE0; + txctl0 |= AR5K_REG_SM(tx_power, AR5K_4W_TX_DESC_CTL0_XMIT_POWER) | + AR5K_REG_SM(antenna_mode, AR5K_4W_TX_DESC_CTL0_ANT_MODE_XMIT); + txctl1 |= AR5K_REG_SM(type, AR5K_4W_TX_DESC_CTL1_FRAME_TYPE); + txctl2 = AR5K_REG_SM(tx_tries0, AR5K_4W_TX_DESC_CTL2_XMIT_TRIES0); + txctl3 = tx_rate0 & AR5K_4W_TX_DESC_CTL3_XMIT_RATE0; #define _TX_FLAGS(_c, _flag) \ if (flags & AR5K_TXDESC_##_flag) { \ - tx_ctl->tx_control_##_c |= \ - AR5K_4W_TX_DESC_CTL##_c##_##_flag; \ + txctl##_c |= AR5K_4W_TX_DESC_CTL##_c##_##_flag; \ } _TX_FLAGS(0, CLRDMASK); @@ -262,8 +260,8 @@ static int ath5k_hw_setup_4word_tx_desc(struct ath5k_hw *ah, * WEP crap */ if (key_index != AR5K_TXKEYIX_INVALID) { - tx_ctl->tx_control_0 |= AR5K_4W_TX_DESC_CTL0_ENCRYPT_KEY_VALID; - tx_ctl->tx_control_1 |= AR5K_REG_SM(key_index, + txctl0 |= AR5K_4W_TX_DESC_CTL0_ENCRYPT_KEY_VALID; + txctl1 |= AR5K_REG_SM(key_index, AR5K_4W_TX_DESC_CTL1_ENCRYPT_KEY_IDX); } @@ -274,12 +272,16 @@ static int ath5k_hw_setup_4word_tx_desc(struct ath5k_hw *ah, if ((flags & AR5K_TXDESC_RTSENA) && (flags & AR5K_TXDESC_CTSENA)) return -EINVAL; - tx_ctl->tx_control_2 |= rtscts_duration & - AR5K_4W_TX_DESC_CTL2_RTS_DURATION; - tx_ctl->tx_control_3 |= AR5K_REG_SM(rtscts_rate, + txctl2 |= rtscts_duration & AR5K_4W_TX_DESC_CTL2_RTS_DURATION; + txctl3 |= AR5K_REG_SM(rtscts_rate, AR5K_4W_TX_DESC_CTL3_RTS_CTS_RATE); } + tx_ctl->tx_control_0 = txctl0; + tx_ctl->tx_control_1 = txctl1; + tx_ctl->tx_control_2 = txctl2; + tx_ctl->tx_control_3 = txctl3; + return 0; } -- cgit v0.10.2 From fe12081cb664cd5d412dc56de0585a80484b1331 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Sun, 10 Apr 2011 18:32:14 +0200 Subject: ath5k: remove ts_rate from ath5k_tx_status It is no longer necessary for preparing mac80211 tx status Signed-off-by: Felix Fietkau Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath5k/ath5k.h b/drivers/net/wireless/ath/ath5k/ath5k.h index 4bb381c..aa588a0 100644 --- a/drivers/net/wireless/ath/ath5k/ath5k.h +++ b/drivers/net/wireless/ath/ath5k/ath5k.h @@ -452,7 +452,6 @@ struct ath5k_tx_status { u16 ts_seqnum; u16 ts_tstamp; u8 ts_status; - u8 ts_rate[4]; u8 ts_retry[4]; u8 ts_final_idx; s8 ts_rssi; diff --git a/drivers/net/wireless/ath/ath5k/desc.c b/drivers/net/wireless/ath/ath5k/desc.c index 0a8a9ef..990a3b4 100644 --- a/drivers/net/wireless/ath/ath5k/desc.c +++ b/drivers/net/wireless/ath/ath5k/desc.c @@ -375,8 +375,6 @@ static int ath5k_hw_proc_2word_tx_status(struct ath5k_hw *ah, AR5K_DESC_TX_STATUS1_ACK_SIG_STRENGTH); ts->ts_antenna = 1; ts->ts_status = 0; - ts->ts_rate[0] = AR5K_REG_MS(tx_ctl->tx_control_0, - AR5K_2W_TX_DESC_CTL0_XMIT_RATE); ts->ts_retry[0] = ts->ts_longretry; ts->ts_final_idx = 0; @@ -439,32 +437,21 @@ static int ath5k_hw_proc_4word_tx_status(struct ath5k_hw *ah, ts->ts_retry[ts->ts_final_idx] = ts->ts_longretry; switch (ts->ts_final_idx) { case 3: - ts->ts_rate[3] = AR5K_REG_MS(tx_ctl->tx_control_3, - AR5K_4W_TX_DESC_CTL3_XMIT_RATE3); - ts->ts_retry[2] = AR5K_REG_MS(tx_ctl->tx_control_2, AR5K_4W_TX_DESC_CTL2_XMIT_TRIES2); ts->ts_longretry += ts->ts_retry[2]; /* fall through */ case 2: - ts->ts_rate[2] = AR5K_REG_MS(tx_ctl->tx_control_3, - AR5K_4W_TX_DESC_CTL3_XMIT_RATE2); - ts->ts_retry[1] = AR5K_REG_MS(tx_ctl->tx_control_2, AR5K_4W_TX_DESC_CTL2_XMIT_TRIES1); ts->ts_longretry += ts->ts_retry[1]; /* fall through */ case 1: - ts->ts_rate[1] = AR5K_REG_MS(tx_ctl->tx_control_3, - AR5K_4W_TX_DESC_CTL3_XMIT_RATE1); - ts->ts_retry[0] = AR5K_REG_MS(tx_ctl->tx_control_2, AR5K_4W_TX_DESC_CTL2_XMIT_TRIES1); ts->ts_longretry += ts->ts_retry[0]; /* fall through */ case 0: - ts->ts_rate[0] = tx_ctl->tx_control_3 & - AR5K_4W_TX_DESC_CTL3_XMIT_RATE0; break; } -- cgit v0.10.2 From b161b89fb97b30233526d31c5f94397ed94ffea6 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Sun, 10 Apr 2011 18:32:15 +0200 Subject: ath5k: optimize tx status processing Use ACCESS_ONCE to reduce the number of variable reloads on uncached memory Signed-off-by: Felix Fietkau Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath5k/desc.c b/drivers/net/wireless/ath/ath5k/desc.c index 990a3b4..3758b96 100644 --- a/drivers/net/wireless/ath/ath5k/desc.c +++ b/drivers/net/wireless/ath/ath5k/desc.c @@ -401,32 +401,38 @@ static int ath5k_hw_proc_4word_tx_status(struct ath5k_hw *ah, { struct ath5k_hw_4w_tx_ctl *tx_ctl; struct ath5k_hw_tx_status *tx_status; + u32 txstat0, txstat1, txctl2; tx_ctl = &desc->ud.ds_tx5212.tx_ctl; tx_status = &desc->ud.ds_tx5212.tx_stat; + txstat1 = ACCESS_ONCE(tx_status->tx_status_1); + /* No frame has been send or error */ - if (unlikely(!(tx_status->tx_status_1 & AR5K_DESC_TX_STATUS1_DONE))) + if (unlikely(!(txstat1 & AR5K_DESC_TX_STATUS1_DONE))) return -EINPROGRESS; + txstat0 = ACCESS_ONCE(tx_status->tx_status_0); + txctl2 = ACCESS_ONCE(tx_ctl->tx_control_2); + /* * Get descriptor status */ - ts->ts_tstamp = AR5K_REG_MS(tx_status->tx_status_0, + ts->ts_tstamp = AR5K_REG_MS(txstat0, AR5K_DESC_TX_STATUS0_SEND_TIMESTAMP); - ts->ts_shortretry = AR5K_REG_MS(tx_status->tx_status_0, + ts->ts_shortretry = AR5K_REG_MS(txstat0, AR5K_DESC_TX_STATUS0_SHORT_RETRY_COUNT); - ts->ts_longretry = AR5K_REG_MS(tx_status->tx_status_0, + ts->ts_longretry = AR5K_REG_MS(txstat0, AR5K_DESC_TX_STATUS0_LONG_RETRY_COUNT); - ts->ts_seqnum = AR5K_REG_MS(tx_status->tx_status_1, + ts->ts_seqnum = AR5K_REG_MS(txstat1, AR5K_DESC_TX_STATUS1_SEQ_NUM); - ts->ts_rssi = AR5K_REG_MS(tx_status->tx_status_1, + ts->ts_rssi = AR5K_REG_MS(txstat1, AR5K_DESC_TX_STATUS1_ACK_SIG_STRENGTH); - ts->ts_antenna = (tx_status->tx_status_1 & + ts->ts_antenna = (txstat1 & AR5K_DESC_TX_STATUS1_XMIT_ANTENNA_5212) ? 2 : 1; ts->ts_status = 0; - ts->ts_final_idx = AR5K_REG_MS(tx_status->tx_status_1, + ts->ts_final_idx = AR5K_REG_MS(txstat1, AR5K_DESC_TX_STATUS1_FINAL_TS_IX_5212); /* The longretry counter has the number of un-acked retries @@ -437,17 +443,17 @@ static int ath5k_hw_proc_4word_tx_status(struct ath5k_hw *ah, ts->ts_retry[ts->ts_final_idx] = ts->ts_longretry; switch (ts->ts_final_idx) { case 3: - ts->ts_retry[2] = AR5K_REG_MS(tx_ctl->tx_control_2, + ts->ts_retry[2] = AR5K_REG_MS(txctl2, AR5K_4W_TX_DESC_CTL2_XMIT_TRIES2); ts->ts_longretry += ts->ts_retry[2]; /* fall through */ case 2: - ts->ts_retry[1] = AR5K_REG_MS(tx_ctl->tx_control_2, + ts->ts_retry[1] = AR5K_REG_MS(txctl2, AR5K_4W_TX_DESC_CTL2_XMIT_TRIES1); ts->ts_longretry += ts->ts_retry[1]; /* fall through */ case 1: - ts->ts_retry[0] = AR5K_REG_MS(tx_ctl->tx_control_2, + ts->ts_retry[0] = AR5K_REG_MS(txctl2, AR5K_4W_TX_DESC_CTL2_XMIT_TRIES1); ts->ts_longretry += ts->ts_retry[0]; /* fall through */ @@ -456,15 +462,14 @@ static int ath5k_hw_proc_4word_tx_status(struct ath5k_hw *ah, } /* TX error */ - if (!(tx_status->tx_status_0 & AR5K_DESC_TX_STATUS0_FRAME_XMIT_OK)) { - if (tx_status->tx_status_0 & - AR5K_DESC_TX_STATUS0_EXCESSIVE_RETRIES) + if (!(txstat0 & AR5K_DESC_TX_STATUS0_FRAME_XMIT_OK)) { + if (txstat0 & AR5K_DESC_TX_STATUS0_EXCESSIVE_RETRIES) ts->ts_status |= AR5K_TXERR_XRETRY; - if (tx_status->tx_status_0 & AR5K_DESC_TX_STATUS0_FIFO_UNDERRUN) + if (txstat0 & AR5K_DESC_TX_STATUS0_FIFO_UNDERRUN) ts->ts_status |= AR5K_TXERR_FIFO; - if (tx_status->tx_status_0 & AR5K_DESC_TX_STATUS0_FILTERED) + if (txstat0 & AR5K_DESC_TX_STATUS0_FILTERED) ts->ts_status |= AR5K_TXERR_FILT; } -- cgit v0.10.2 From b2fd97d0190a400b49a2f910109a4a492bfea319 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Sun, 10 Apr 2011 18:32:16 +0200 Subject: ath5k: optimize rx status processing Use ACCESS_ONCE to reduce the number of redundant loads on uncached memory Signed-off-by: Felix Fietkau Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath5k/desc.c b/drivers/net/wireless/ath/ath5k/desc.c index 3758b96..e366d30 100644 --- a/drivers/net/wireless/ath/ath5k/desc.c +++ b/drivers/net/wireless/ath/ath5k/desc.c @@ -603,37 +603,37 @@ static int ath5k_hw_proc_5212_rx_status(struct ath5k_hw *ah, struct ath5k_rx_status *rs) { struct ath5k_hw_rx_status *rx_status; + u32 rxstat0, rxstat1; rx_status = &desc->ud.ds_rx.rx_stat; + rxstat1 = ACCESS_ONCE(rx_status->rx_status_1); /* No frame received / not ready */ - if (unlikely(!(rx_status->rx_status_1 & - AR5K_5212_RX_DESC_STATUS1_DONE))) + if (unlikely(!(rxstat1 & AR5K_5212_RX_DESC_STATUS1_DONE))) return -EINPROGRESS; memset(rs, 0, sizeof(struct ath5k_rx_status)); + rxstat0 = ACCESS_ONCE(rx_status->rx_status_0); /* * Frame receive status */ - rs->rs_datalen = rx_status->rx_status_0 & - AR5K_5212_RX_DESC_STATUS0_DATA_LEN; - rs->rs_rssi = AR5K_REG_MS(rx_status->rx_status_0, + rs->rs_datalen = rxstat0 & AR5K_5212_RX_DESC_STATUS0_DATA_LEN; + rs->rs_rssi = AR5K_REG_MS(rxstat0, AR5K_5212_RX_DESC_STATUS0_RECEIVE_SIGNAL); - rs->rs_rate = AR5K_REG_MS(rx_status->rx_status_0, + rs->rs_rate = AR5K_REG_MS(rxstat0, AR5K_5212_RX_DESC_STATUS0_RECEIVE_RATE); - rs->rs_antenna = AR5K_REG_MS(rx_status->rx_status_0, + rs->rs_antenna = AR5K_REG_MS(rxstat0, AR5K_5212_RX_DESC_STATUS0_RECEIVE_ANTENNA); - rs->rs_more = !!(rx_status->rx_status_0 & - AR5K_5212_RX_DESC_STATUS0_MORE); - rs->rs_tstamp = AR5K_REG_MS(rx_status->rx_status_1, + rs->rs_more = !!(rxstat0 & AR5K_5212_RX_DESC_STATUS0_MORE); + rs->rs_tstamp = AR5K_REG_MS(rxstat1, AR5K_5212_RX_DESC_STATUS1_RECEIVE_TIMESTAMP); /* * Key table status */ - if (rx_status->rx_status_1 & AR5K_5212_RX_DESC_STATUS1_KEY_INDEX_VALID) - rs->rs_keyix = AR5K_REG_MS(rx_status->rx_status_1, + if (rxstat1 & AR5K_5212_RX_DESC_STATUS1_KEY_INDEX_VALID) + rs->rs_keyix = AR5K_REG_MS(rxstat1, AR5K_5212_RX_DESC_STATUS1_KEY_INDEX); else rs->rs_keyix = AR5K_RXKEYIX_INVALID; @@ -641,27 +641,22 @@ static int ath5k_hw_proc_5212_rx_status(struct ath5k_hw *ah, /* * Receive/descriptor errors */ - if (!(rx_status->rx_status_1 & - AR5K_5212_RX_DESC_STATUS1_FRAME_RECEIVE_OK)) { - if (rx_status->rx_status_1 & - AR5K_5212_RX_DESC_STATUS1_CRC_ERROR) + if (!(rxstat1 & AR5K_5212_RX_DESC_STATUS1_FRAME_RECEIVE_OK)) { + if (rxstat1 & AR5K_5212_RX_DESC_STATUS1_CRC_ERROR) rs->rs_status |= AR5K_RXERR_CRC; - if (rx_status->rx_status_1 & - AR5K_5212_RX_DESC_STATUS1_PHY_ERROR) { + if (rxstat1 & AR5K_5212_RX_DESC_STATUS1_PHY_ERROR) { rs->rs_status |= AR5K_RXERR_PHY; - rs->rs_phyerr = AR5K_REG_MS(rx_status->rx_status_1, + rs->rs_phyerr = AR5K_REG_MS(rxstat1, AR5K_5212_RX_DESC_STATUS1_PHY_ERROR_CODE); if (!ah->ah_capabilities.cap_has_phyerr_counters) ath5k_ani_phy_error_report(ah, rs->rs_phyerr); } - if (rx_status->rx_status_1 & - AR5K_5212_RX_DESC_STATUS1_DECRYPT_CRC_ERROR) + if (rxstat1 & AR5K_5212_RX_DESC_STATUS1_DECRYPT_CRC_ERROR) rs->rs_status |= AR5K_RXERR_DECRYPT; - if (rx_status->rx_status_1 & - AR5K_5212_RX_DESC_STATUS1_MIC_ERROR) + if (rxstat1 & AR5K_5212_RX_DESC_STATUS1_MIC_ERROR) rs->rs_status |= AR5K_RXERR_MIC; } return 0; -- cgit v0.10.2 From ed8950857f728303a1463ac9267e72c278738bf6 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Sun, 10 Apr 2011 18:32:17 +0200 Subject: ath5k: remove ts_retry from ath5k_tx_status Reusing the configured retry counts from the skb cb is more efficient than reloading the data from uncached memory. Replace ts_longretry (unused) with ts_final_retry which contains the retry count for the final rate only Signed-off-by: Felix Fietkau Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath5k/ath5k.h b/drivers/net/wireless/ath/ath5k/ath5k.h index aa588a0..fcaf4ed 100644 --- a/drivers/net/wireless/ath/ath5k/ath5k.h +++ b/drivers/net/wireless/ath/ath5k/ath5k.h @@ -452,11 +452,10 @@ struct ath5k_tx_status { u16 ts_seqnum; u16 ts_tstamp; u8 ts_status; - u8 ts_retry[4]; u8 ts_final_idx; + u8 ts_final_retry; s8 ts_rssi; u8 ts_shortretry; - u8 ts_longretry; u8 ts_virtcol; u8 ts_antenna; }; diff --git a/drivers/net/wireless/ath/ath5k/base.c b/drivers/net/wireless/ath/ath5k/base.c index 753662f..1a561b8 100644 --- a/drivers/net/wireless/ath/ath5k/base.c +++ b/drivers/net/wireless/ath/ath5k/base.c @@ -1573,20 +1573,27 @@ ath5k_tx_frame_completed(struct ath5k_softc *sc, struct sk_buff *skb, struct ath5k_txq *txq, struct ath5k_tx_status *ts) { struct ieee80211_tx_info *info; + u8 tries[3]; int i; sc->stats.tx_all_count++; sc->stats.tx_bytes_count += skb->len; info = IEEE80211_SKB_CB(skb); + tries[0] = info->status.rates[0].count; + tries[1] = info->status.rates[1].count; + tries[2] = info->status.rates[2].count; + ieee80211_tx_info_clear_status(info); - for (i = 0; i <= ts->ts_final_idx; i++) { + + for (i = 0; i < ts->ts_final_idx; i++) { struct ieee80211_tx_rate *r = &info->status.rates[i]; - r->count = ts->ts_retry[i]; + r->count = tries[i]; } + info->status.rates[ts->ts_final_idx].count = ts->ts_final_retry; info->status.rates[ts->ts_final_idx + 1].idx = -1; if (unlikely(ts->ts_status)) { diff --git a/drivers/net/wireless/ath/ath5k/desc.c b/drivers/net/wireless/ath/ath5k/desc.c index e366d30..0391813 100644 --- a/drivers/net/wireless/ath/ath5k/desc.c +++ b/drivers/net/wireless/ath/ath5k/desc.c @@ -366,7 +366,7 @@ static int ath5k_hw_proc_2word_tx_status(struct ath5k_hw *ah, AR5K_DESC_TX_STATUS0_SEND_TIMESTAMP); ts->ts_shortretry = AR5K_REG_MS(tx_status->tx_status_0, AR5K_DESC_TX_STATUS0_SHORT_RETRY_COUNT); - ts->ts_longretry = AR5K_REG_MS(tx_status->tx_status_0, + ts->ts_final_retry = AR5K_REG_MS(tx_status->tx_status_0, AR5K_DESC_TX_STATUS0_LONG_RETRY_COUNT); /*TODO: ts->ts_virtcol + test*/ ts->ts_seqnum = AR5K_REG_MS(tx_status->tx_status_1, @@ -375,7 +375,6 @@ static int ath5k_hw_proc_2word_tx_status(struct ath5k_hw *ah, AR5K_DESC_TX_STATUS1_ACK_SIG_STRENGTH); ts->ts_antenna = 1; ts->ts_status = 0; - ts->ts_retry[0] = ts->ts_longretry; ts->ts_final_idx = 0; if (!(tx_status->tx_status_0 & AR5K_DESC_TX_STATUS0_FRAME_XMIT_OK)) { @@ -401,7 +400,7 @@ static int ath5k_hw_proc_4word_tx_status(struct ath5k_hw *ah, { struct ath5k_hw_4w_tx_ctl *tx_ctl; struct ath5k_hw_tx_status *tx_status; - u32 txstat0, txstat1, txctl2; + u32 txstat0, txstat1; tx_ctl = &desc->ud.ds_tx5212.tx_ctl; tx_status = &desc->ud.ds_tx5212.tx_stat; @@ -413,7 +412,6 @@ static int ath5k_hw_proc_4word_tx_status(struct ath5k_hw *ah, return -EINPROGRESS; txstat0 = ACCESS_ONCE(tx_status->tx_status_0); - txctl2 = ACCESS_ONCE(tx_ctl->tx_control_2); /* * Get descriptor status @@ -422,7 +420,7 @@ static int ath5k_hw_proc_4word_tx_status(struct ath5k_hw *ah, AR5K_DESC_TX_STATUS0_SEND_TIMESTAMP); ts->ts_shortretry = AR5K_REG_MS(txstat0, AR5K_DESC_TX_STATUS0_SHORT_RETRY_COUNT); - ts->ts_longretry = AR5K_REG_MS(txstat0, + ts->ts_final_retry = AR5K_REG_MS(txstat0, AR5K_DESC_TX_STATUS0_LONG_RETRY_COUNT); ts->ts_seqnum = AR5K_REG_MS(txstat1, AR5K_DESC_TX_STATUS1_SEQ_NUM); @@ -435,32 +433,6 @@ static int ath5k_hw_proc_4word_tx_status(struct ath5k_hw *ah, ts->ts_final_idx = AR5K_REG_MS(txstat1, AR5K_DESC_TX_STATUS1_FINAL_TS_IX_5212); - /* The longretry counter has the number of un-acked retries - * for the final rate. To get the total number of retries - * we have to add the retry counters for the other rates - * as well - */ - ts->ts_retry[ts->ts_final_idx] = ts->ts_longretry; - switch (ts->ts_final_idx) { - case 3: - ts->ts_retry[2] = AR5K_REG_MS(txctl2, - AR5K_4W_TX_DESC_CTL2_XMIT_TRIES2); - ts->ts_longretry += ts->ts_retry[2]; - /* fall through */ - case 2: - ts->ts_retry[1] = AR5K_REG_MS(txctl2, - AR5K_4W_TX_DESC_CTL2_XMIT_TRIES1); - ts->ts_longretry += ts->ts_retry[1]; - /* fall through */ - case 1: - ts->ts_retry[0] = AR5K_REG_MS(txctl2, - AR5K_4W_TX_DESC_CTL2_XMIT_TRIES1); - ts->ts_longretry += ts->ts_retry[0]; - /* fall through */ - case 0: - break; - } - /* TX error */ if (!(txstat0 & AR5K_DESC_TX_STATUS0_FRAME_XMIT_OK)) { if (txstat0 & AR5K_DESC_TX_STATUS0_EXCESSIVE_RETRIES) -- cgit v0.10.2 From 5b7916ad8c29da9f30fbf03a8b61862acdba00ce Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Sun, 10 Apr 2011 18:32:18 +0200 Subject: ath5k: clean up debugfs code The pointers to the debugfs entries do not need to be saved, because they will be recursively removed when the wiphy is unregistered. Signed-off-by: Felix Fietkau Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath5k/base.c b/drivers/net/wireless/ath/ath5k/base.c index 1a561b8..a799d04 100644 --- a/drivers/net/wireless/ath/ath5k/base.c +++ b/drivers/net/wireless/ath/ath5k/base.c @@ -2901,7 +2901,6 @@ ath5k_deinit_softc(struct ath5k_softc *sc) * XXX: ??? detach ath5k_hw ??? * Other than that, it's straightforward... */ - ath5k_debug_finish_device(sc); ieee80211_unregister_hw(hw); ath5k_desc_free(sc); ath5k_txq_release(sc); diff --git a/drivers/net/wireless/ath/ath5k/debug.c b/drivers/net/wireless/ath/ath5k/debug.c index 0230f30..0bf7313 100644 --- a/drivers/net/wireless/ath/ath5k/debug.c +++ b/drivers/net/wireless/ath/ath5k/debug.c @@ -888,65 +888,38 @@ static const struct file_operations fops_queue = { void ath5k_debug_init_device(struct ath5k_softc *sc) { - sc->debug.level = ath5k_debug; + struct dentry *phydir; - sc->debug.debugfs_phydir = debugfs_create_dir("ath5k", - sc->hw->wiphy->debugfsdir); + sc->debug.level = ath5k_debug; - sc->debug.debugfs_debug = debugfs_create_file("debug", - S_IWUSR | S_IRUSR, - sc->debug.debugfs_phydir, sc, &fops_debug); + phydir = debugfs_create_dir("ath5k", sc->hw->wiphy->debugfsdir); + if (!phydir) + return; - sc->debug.debugfs_registers = debugfs_create_file("registers", S_IRUSR, - sc->debug.debugfs_phydir, sc, &fops_registers); + debugfs_create_file("debug", S_IWUSR | S_IRUSR, phydir, sc, + &fops_debug); - sc->debug.debugfs_beacon = debugfs_create_file("beacon", - S_IWUSR | S_IRUSR, - sc->debug.debugfs_phydir, sc, &fops_beacon); + debugfs_create_file("registers", S_IRUSR, phydir, sc, &fops_registers); - sc->debug.debugfs_reset = debugfs_create_file("reset", S_IWUSR, - sc->debug.debugfs_phydir, sc, &fops_reset); + debugfs_create_file("beacon", S_IWUSR | S_IRUSR, phydir, sc, + &fops_beacon); - sc->debug.debugfs_antenna = debugfs_create_file("antenna", - S_IWUSR | S_IRUSR, - sc->debug.debugfs_phydir, sc, &fops_antenna); + debugfs_create_file("reset", S_IWUSR, phydir, sc, &fops_reset); - sc->debug.debugfs_misc = debugfs_create_file("misc", - S_IRUSR, - sc->debug.debugfs_phydir, sc, &fops_misc); + debugfs_create_file("antenna", S_IWUSR | S_IRUSR, phydir, sc, + &fops_antenna); - sc->debug.debugfs_frameerrors = debugfs_create_file("frameerrors", - S_IWUSR | S_IRUSR, - sc->debug.debugfs_phydir, sc, - &fops_frameerrors); + debugfs_create_file("misc", S_IRUSR, phydir, sc, &fops_misc); - sc->debug.debugfs_ani = debugfs_create_file("ani", - S_IWUSR | S_IRUSR, - sc->debug.debugfs_phydir, sc, - &fops_ani); + debugfs_create_file("frameerrors", S_IWUSR | S_IRUSR, phydir, sc, + &fops_frameerrors); - sc->debug.debugfs_queue = debugfs_create_file("queue", - S_IWUSR | S_IRUSR, - sc->debug.debugfs_phydir, sc, - &fops_queue); -} + debugfs_create_file("ani", S_IWUSR | S_IRUSR, phydir, sc, &fops_ani); -void -ath5k_debug_finish_device(struct ath5k_softc *sc) -{ - debugfs_remove(sc->debug.debugfs_debug); - debugfs_remove(sc->debug.debugfs_registers); - debugfs_remove(sc->debug.debugfs_beacon); - debugfs_remove(sc->debug.debugfs_reset); - debugfs_remove(sc->debug.debugfs_antenna); - debugfs_remove(sc->debug.debugfs_misc); - debugfs_remove(sc->debug.debugfs_frameerrors); - debugfs_remove(sc->debug.debugfs_ani); - debugfs_remove(sc->debug.debugfs_queue); - debugfs_remove(sc->debug.debugfs_phydir); + debugfs_create_file("queue", S_IWUSR | S_IRUSR, phydir, sc, + &fops_queue); } - /* functions used in other places */ void diff --git a/drivers/net/wireless/ath/ath5k/debug.h b/drivers/net/wireless/ath/ath5k/debug.h index b0355ae..193dd2d 100644 --- a/drivers/net/wireless/ath/ath5k/debug.h +++ b/drivers/net/wireless/ath/ath5k/debug.h @@ -68,17 +68,6 @@ struct ath5k_buf; struct ath5k_dbg_info { unsigned int level; /* debug level */ - /* debugfs entries */ - struct dentry *debugfs_phydir; - struct dentry *debugfs_debug; - struct dentry *debugfs_registers; - struct dentry *debugfs_beacon; - struct dentry *debugfs_reset; - struct dentry *debugfs_antenna; - struct dentry *debugfs_misc; - struct dentry *debugfs_frameerrors; - struct dentry *debugfs_ani; - struct dentry *debugfs_queue; }; /** @@ -141,9 +130,6 @@ void ath5k_debug_init_device(struct ath5k_softc *sc); void -ath5k_debug_finish_device(struct ath5k_softc *sc); - -void ath5k_debug_printrxbuffs(struct ath5k_softc *sc, struct ath5k_hw *ah); void @@ -167,9 +153,6 @@ static inline void ath5k_debug_init_device(struct ath5k_softc *sc) {} static inline void -ath5k_debug_finish_device(struct ath5k_softc *sc) {} - -static inline void ath5k_debug_printrxbuffs(struct ath5k_softc *sc, struct ath5k_hw *ah) {} static inline void -- cgit v0.10.2 From c266c71a9cbdccb40fb6f4c05d4ddaa6226e5eba Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Sun, 10 Apr 2011 18:32:19 +0200 Subject: ath5k: reduce interrupt load caused by rx/tx interrupts While the rx/tx tasklet is pending, new unnecessary interrupts may arrive. Decrease the load by temporarily disabling the interrupts until the tasklet has completed. Signed-off-by: Felix Fietkau Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath5k/ath5k.h b/drivers/net/wireless/ath/ath5k/ath5k.h index fcaf4ed..e303db7 100644 --- a/drivers/net/wireless/ath/ath5k/ath5k.h +++ b/drivers/net/wireless/ath/ath5k/ath5k.h @@ -872,6 +872,19 @@ enum ath5k_int { AR5K_INT_QTRIG = 0x40000000, /* Non common */ AR5K_INT_GLOBAL = 0x80000000, + AR5K_INT_TX_ALL = AR5K_INT_TXOK + | AR5K_INT_TXDESC + | AR5K_INT_TXERR + | AR5K_INT_TXEOL + | AR5K_INT_TXURN, + + AR5K_INT_RX_ALL = AR5K_INT_RXOK + | AR5K_INT_RXDESC + | AR5K_INT_RXERR + | AR5K_INT_RXNOFRM + | AR5K_INT_RXEOL + | AR5K_INT_RXORN, + AR5K_INT_COMMON = AR5K_INT_RXOK | AR5K_INT_RXDESC | AR5K_INT_RXERR diff --git a/drivers/net/wireless/ath/ath5k/base.c b/drivers/net/wireless/ath/ath5k/base.c index a799d04..c7da004 100644 --- a/drivers/net/wireless/ath/ath5k/base.c +++ b/drivers/net/wireless/ath/ath5k/base.c @@ -1444,6 +1444,21 @@ ath5k_receive_frame_ok(struct ath5k_softc *sc, struct ath5k_rx_status *rs) } static void +ath5k_set_current_imask(struct ath5k_softc *sc) +{ + enum ath5k_int imask = sc->imask; + unsigned long flags; + + spin_lock_irqsave(&sc->irqlock, flags); + if (sc->rx_pending) + imask &= ~AR5K_INT_RX_ALL; + if (sc->tx_pending) + imask &= ~AR5K_INT_TX_ALL; + ath5k_hw_set_imr(sc->ah, imask); + spin_unlock_irqrestore(&sc->irqlock, flags); +} + +static void ath5k_tasklet_rx(unsigned long data) { struct ath5k_rx_status rs = {}; @@ -1506,6 +1521,8 @@ next: } while (ath5k_rxbuf_setup(sc, bf) == 0); unlock: spin_unlock(&sc->rxbuflock); + sc->rx_pending = false; + ath5k_set_current_imask(sc); } @@ -1693,6 +1710,9 @@ ath5k_tasklet_tx(unsigned long data) for (i=0; i < AR5K_NUM_TX_QUEUES; i++) if (sc->txqs[i].setup && (sc->ah->ah_txq_isr & BIT(i))) ath5k_tx_processq(sc, &sc->txqs[i]); + + sc->tx_pending = false; + ath5k_set_current_imask(sc); } @@ -2122,6 +2142,20 @@ ath5k_intr_calibration_poll(struct ath5k_hw *ah) * AR5K_REG_ENABLE_BITS(ah, AR5K_CR, AR5K_CR_SWI); */ } +static void +ath5k_schedule_rx(struct ath5k_softc *sc) +{ + sc->rx_pending = true; + tasklet_schedule(&sc->rxtq); +} + +static void +ath5k_schedule_tx(struct ath5k_softc *sc) +{ + sc->tx_pending = true; + tasklet_schedule(&sc->txtq); +} + irqreturn_t ath5k_intr(int irq, void *dev_id) { @@ -2164,7 +2198,7 @@ ath5k_intr(int irq, void *dev_id) ieee80211_queue_work(sc->hw, &sc->reset_work); } else - tasklet_schedule(&sc->rxtq); + ath5k_schedule_rx(sc); } else { if (status & AR5K_INT_SWBA) { tasklet_hi_schedule(&sc->beacontq); @@ -2182,10 +2216,10 @@ ath5k_intr(int irq, void *dev_id) ath5k_hw_update_tx_triglevel(ah, true); } if (status & (AR5K_INT_RXOK | AR5K_INT_RXERR)) - tasklet_schedule(&sc->rxtq); + ath5k_schedule_rx(sc); if (status & (AR5K_INT_TXOK | AR5K_INT_TXDESC | AR5K_INT_TXERR | AR5K_INT_TXEOL)) - tasklet_schedule(&sc->txtq); + ath5k_schedule_tx(sc); if (status & AR5K_INT_BMISS) { /* TODO */ } @@ -2204,6 +2238,9 @@ ath5k_intr(int irq, void *dev_id) } while (ath5k_hw_is_intr_pending(ah) && --counter > 0); + if (sc->rx_pending || sc->tx_pending) + ath5k_set_current_imask(sc); + if (unlikely(!counter)) ATH5K_WARN(sc, "too many interrupts, giving up for now\n"); @@ -2575,6 +2612,8 @@ done: static void stop_tasklets(struct ath5k_softc *sc) { + sc->rx_pending = false; + sc->tx_pending = false; tasklet_kill(&sc->rxtq); tasklet_kill(&sc->txtq); tasklet_kill(&sc->calib); diff --git a/drivers/net/wireless/ath/ath5k/base.h b/drivers/net/wireless/ath/ath5k/base.h index 978f1f4..4c4e360 100644 --- a/drivers/net/wireless/ath/ath5k/base.h +++ b/drivers/net/wireless/ath/ath5k/base.h @@ -207,6 +207,10 @@ struct ath5k_softc { enum ath5k_int imask; /* interrupt mask copy */ + spinlock_t irqlock; + bool rx_pending; /* rx tasklet pending */ + bool tx_pending; /* tx tasklet pending */ + u8 lladdr[ETH_ALEN]; u8 bssidmask[ETH_ALEN]; -- cgit v0.10.2 From 0f8e94d2ae4f7966d09c8105ccabb3b3d8238a4d Mon Sep 17 00:00:00 2001 From: roel Date: Sun, 10 Apr 2011 21:09:50 +0200 Subject: ath9k_hw: index out of bounds Check whether index is within bounds before testing the element Both spurChans arrays in modalHeader5G and modalHeader2G have 5 elements, AR_EEPROM_MODAL_SPURS is defined 5. So unless a break occurs, in the last iteration (i=5) we tried to access spurChansPtr[5] before testing whether i was within bounds. Fix this. Signed-off-by: Roel Kluin Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/ar9003_phy.c b/drivers/net/wireless/ath/ath9k/ar9003_phy.c index eb250d6..93398de 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_phy.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_phy.c @@ -401,7 +401,7 @@ static void ar9003_hw_spur_mitigate_ofdm(struct ath_hw *ah, ar9003_hw_spur_ofdm_clear(ah); - for (i = 0; spurChansPtr[i] && i < 5; i++) { + for (i = 0; i < AR_EEPROM_MODAL_SPURS && spurChansPtr[i]; i++) { freq_offset = FBIN2FREQ(spurChansPtr[i], mode) - synth_freq; if (abs(freq_offset) < range) { ar9003_hw_spur_ofdm_work(ah, chan, freq_offset); -- cgit v0.10.2 From f0bce44f5f2eb37dba58aa992d0c58da92ded201 Mon Sep 17 00:00:00 2001 From: roel Date: Sun, 10 Apr 2011 21:09:55 +0200 Subject: ath9k: index out of bounds Check whether index is within bounds before testing the element Signed-off-by: Roel Kluin Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/rc.c b/drivers/net/wireless/ath/ath9k/rc.c index a3241cd..2a40532 100644 --- a/drivers/net/wireless/ath/ath9k/rc.c +++ b/drivers/net/wireless/ath/ath9k/rc.c @@ -1092,8 +1092,7 @@ static int ath_rc_get_rateindex(const struct ath_rate_table *rate_table, if (!(rate->flags & IEEE80211_TX_RC_MCS)) return rate->idx; - while (rate->idx > mcs_rix_off[i] && - i < ARRAY_SIZE(mcs_rix_off)) { + while (i < ARRAY_SIZE(mcs_rix_off) && rate->idx > mcs_rix_off[i]) { rix++; i++; } -- cgit v0.10.2 From 192910a6cca5e50e5bd6cbd1da0e7376c7adfe62 Mon Sep 17 00:00:00 2001 From: Joakim Tjernlund Date: Tue, 12 Apr 2011 13:59:33 -0700 Subject: net: Do not wrap sysctl igmp_max_memberships in IP_MULTICAST controlling igmp_max_membership is useful even when IP_MULTICAST is off. Quagga(an OSPF deamon) uses multicast addresses for all interfaces using a single socket and hits igmp_max_membership limit when there are 20 interfaces or more. Always export sysctl igmp_max_memberships in proc, just like igmp_max_msf Signed-off-by: Joakim Tjernlund Signed-off-by: David S. Miller diff --git a/net/ipv4/sysctl_net_ipv4.c b/net/ipv4/sysctl_net_ipv4.c index 1a45665..321e6e8 100644 --- a/net/ipv4/sysctl_net_ipv4.c +++ b/net/ipv4/sysctl_net_ipv4.c @@ -311,7 +311,6 @@ static struct ctl_table ipv4_table[] = { .mode = 0644, .proc_handler = proc_do_large_bitmap, }, -#ifdef CONFIG_IP_MULTICAST { .procname = "igmp_max_memberships", .data = &sysctl_igmp_max_memberships, @@ -319,8 +318,6 @@ static struct ctl_table ipv4_table[] = { .mode = 0644, .proc_handler = proc_dointvec }, - -#endif { .procname = "igmp_max_msf", .data = &sysctl_igmp_max_msf, -- cgit v0.10.2 From 228bdfca9a09c1263c24509b4bc23a67be168e1a Mon Sep 17 00:00:00 2001 From: Chaoming Li Date: Sun, 10 Apr 2011 18:30:23 -0500 Subject: rtlwifi: rtl8192ce: Fix LED initialization Driver rtl8192ce does not initialize the LED correctly. Signed-off-by: Chaoming Li Signed-off-by: Larry Finger Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/rtlwifi/base.c b/drivers/net/wireless/rtlwifi/base.c index dd5318e..9477785 100644 --- a/drivers/net/wireless/rtlwifi/base.c +++ b/drivers/net/wireless/rtlwifi/base.c @@ -251,14 +251,16 @@ void rtl_init_rfkill(struct ieee80211_hw *hw) bool blocked; u8 valid = 0; - radio_state = rtlpriv->cfg->ops->radio_onoff_checking(hw, &valid); + /*set init state to on */ + rtlpriv->rfkill.rfkill_state = 1; + wiphy_rfkill_set_hw_state(hw->wiphy, 0); - /*set init state to that of switch */ - rtlpriv->rfkill.rfkill_state = radio_state; - printk(KERN_INFO "rtlwifi: wireless switch is %s\n", - rtlpriv->rfkill.rfkill_state ? "on" : "off"); + radio_state = rtlpriv->cfg->ops->radio_onoff_checking(hw, &valid); if (valid) { + printk(KERN_INFO "rtlwifi: wireless switch is %s\n", + rtlpriv->rfkill.rfkill_state ? "on" : "off"); + rtlpriv->rfkill.rfkill_state = radio_state; blocked = (rtlpriv->rfkill.rfkill_state == 1) ? 0 : 1; diff --git a/drivers/net/wireless/rtlwifi/pci.c b/drivers/net/wireless/rtlwifi/pci.c index efded43..59a150c 100644 --- a/drivers/net/wireless/rtlwifi/pci.c +++ b/drivers/net/wireless/rtlwifi/pci.c @@ -1785,7 +1785,8 @@ void rtl_pci_disconnect(struct pci_dev *pdev) rtl_pci_deinit(hw); rtl_deinit_core(hw); - rtlpriv->cfg->ops->deinit_sw_leds(hw); + if (rtlpriv->cfg->ops->deinit_sw_leds) + rtlpriv->cfg->ops->deinit_sw_leds(hw); _rtl_pci_io_handler_release(hw); rtlpriv->cfg->ops->deinit_sw_vars(hw); diff --git a/drivers/net/wireless/rtlwifi/rtl8192ce/led.c b/drivers/net/wireless/rtlwifi/rtl8192ce/led.c index 7b1da8d..d21b934 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192ce/led.c +++ b/drivers/net/wireless/rtlwifi/rtl8192ce/led.c @@ -32,6 +32,14 @@ #include "reg.h" #include "led.h" +static void _rtl92ce_init_led(struct ieee80211_hw *hw, + struct rtl_led *pled, enum rtl_led_pin ledpin) +{ + pled->hw = hw; + pled->ledpin = ledpin; + pled->ledon = false; +} + void rtl92ce_sw_led_on(struct ieee80211_hw *hw, struct rtl_led *pled) { u8 ledcfg; @@ -97,10 +105,10 @@ void rtl92ce_sw_led_off(struct ieee80211_hw *hw, struct rtl_led *pled) void rtl92ce_init_sw_leds(struct ieee80211_hw *hw) { -} + struct rtl_pci_priv *pcipriv = rtl_pcipriv(hw); -void rtl92ce_deinit_sw_leds(struct ieee80211_hw *hw) -{ + _rtl92ce_init_led(hw, &(pcipriv->ledctl.sw_led0), LED_PIN_LED0); + _rtl92ce_init_led(hw, &(pcipriv->ledctl.sw_led1), LED_PIN_LED1); } void _rtl92ce_sw_led_control(struct ieee80211_hw *hw, diff --git a/drivers/net/wireless/rtlwifi/rtl8192ce/led.h b/drivers/net/wireless/rtlwifi/rtl8192ce/led.h index 10da301..94332b3 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192ce/led.h +++ b/drivers/net/wireless/rtlwifi/rtl8192ce/led.h @@ -31,7 +31,6 @@ #define __RTL92CE_LED_H__ void rtl92ce_init_sw_leds(struct ieee80211_hw *hw); -void rtl92ce_deinit_sw_leds(struct ieee80211_hw *hw); void rtl92ce_sw_led_on(struct ieee80211_hw *hw, struct rtl_led *pled); void rtl92ce_sw_led_off(struct ieee80211_hw *hw, struct rtl_led *pled); void rtl92ce_led_control(struct ieee80211_hw *hw, enum led_ctl_mode ledaction); diff --git a/drivers/net/wireless/rtlwifi/rtl8192ce/sw.c b/drivers/net/wireless/rtlwifi/rtl8192ce/sw.c index b1cc4d4..f4e2f3d 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192ce/sw.c +++ b/drivers/net/wireless/rtlwifi/rtl8192ce/sw.c @@ -131,7 +131,6 @@ static struct rtl_hal_ops rtl8192ce_hal_ops = { .enable_hw_sec = rtl92ce_enable_hw_security_config, .set_key = rtl92ce_set_key, .init_sw_leds = rtl92ce_init_sw_leds, - .deinit_sw_leds = rtl92ce_deinit_sw_leds, .get_bbreg = rtl92c_phy_query_bb_reg, .set_bbreg = rtl92c_phy_set_bb_reg, .get_rfreg = rtl92ce_phy_query_rf_reg, -- cgit v0.10.2 From 3dfd7f606645279c788f48cfdfdf9565ec72c4f0 Mon Sep 17 00:00:00 2001 From: Vasanthakumar Thiagarajan Date: Mon, 11 Apr 2011 16:39:40 +0530 Subject: ath9k: Implement integer mode for AR9485 This fixes random disconnect. Signed-off-by: Vasanthakumar Thiagarajan Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/ar9003_phy.c b/drivers/net/wireless/ath/ath9k/ar9003_phy.c index 93398de..1bc33f5 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_phy.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_phy.c @@ -75,9 +75,18 @@ static int ar9003_hw_set_channel(struct ath_hw *ah, struct ath9k_channel *chan) freq = centers.synth_center; if (freq < 4800) { /* 2 GHz, fractional mode */ - if (AR_SREV_9485(ah)) - channelSel = CHANSEL_2G_9485(freq); - else + if (AR_SREV_9485(ah)) { + u32 chan_frac; + + /* + * freq_ref = 40 / (refdiva >> amoderefsel); where refdiva=1 and amoderefsel=0 + * ndiv = ((chan_mhz * 4) / 3) / freq_ref; + * chansel = int(ndiv), chanfrac = (ndiv - chansel) * 0x20000 + */ + channelSel = (freq * 4) / 120; + chan_frac = (((freq * 4) % 120) * 0x20000) / 120; + channelSel = (channelSel << 17) | chan_frac; + } else channelSel = CHANSEL_2G(freq); /* Set to 2G mode */ bMode = 1; diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index 1b5bd13..3a8c41c 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c @@ -676,42 +676,55 @@ unsigned long ar9003_get_pll_sqsum_dvc(struct ath_hw *ah) } EXPORT_SYMBOL(ar9003_get_pll_sqsum_dvc); -#define DPLL2_KD_VAL 0x3D -#define DPLL2_KI_VAL 0x06 -#define DPLL3_PHASE_SHIFT_VAL 0x1 - +#define DPLL3_PHASE_SHIFT_VAL 0x1 static void ath9k_hw_init_pll(struct ath_hw *ah, struct ath9k_channel *chan) { u32 pll; if (AR_SREV_9485(ah)) { - REG_WRITE(ah, AR_RTC_PLL_CONTROL2, 0x886666); - REG_WRITE(ah, AR_CH0_DDR_DPLL2, 0x19e82f01); - - REG_RMW_FIELD(ah, AR_CH0_DDR_DPLL3, - AR_CH0_DPLL3_PHASE_SHIFT, DPLL3_PHASE_SHIFT_VAL); - REG_WRITE(ah, AR_RTC_PLL_CONTROL, 0x1142c); - udelay(1000); + /* program BB PLL ki and kd value, ki=0x4, kd=0x40 */ + REG_RMW_FIELD(ah, AR_CH0_BB_DPLL2, + AR_CH0_BB_DPLL2_PLL_PWD, 0x1); + REG_RMW_FIELD(ah, AR_CH0_BB_DPLL2, + AR_CH0_DPLL2_KD, 0x40); + REG_RMW_FIELD(ah, AR_CH0_BB_DPLL2, + AR_CH0_DPLL2_KI, 0x4); - REG_WRITE(ah, AR_RTC_PLL_CONTROL2, 0x886666); + REG_RMW_FIELD(ah, AR_CH0_BB_DPLL1, + AR_CH0_BB_DPLL1_REFDIV, 0x5); + REG_RMW_FIELD(ah, AR_CH0_BB_DPLL1, + AR_CH0_BB_DPLL1_NINI, 0x58); + REG_RMW_FIELD(ah, AR_CH0_BB_DPLL1, + AR_CH0_BB_DPLL1_NFRAC, 0x0); REG_RMW_FIELD(ah, AR_CH0_BB_DPLL2, - AR_CH0_DPLL2_KD, DPLL2_KD_VAL); + AR_CH0_BB_DPLL2_OUTDIV, 0x1); + REG_RMW_FIELD(ah, AR_CH0_BB_DPLL2, + AR_CH0_BB_DPLL2_LOCAL_PLL, 0x1); REG_RMW_FIELD(ah, AR_CH0_BB_DPLL2, - AR_CH0_DPLL2_KI, DPLL2_KI_VAL); + AR_CH0_BB_DPLL2_EN_NEGTRIG, 0x1); + /* program BB PLL phase_shift to 0x6 */ REG_RMW_FIELD(ah, AR_CH0_BB_DPLL3, - AR_CH0_DPLL3_PHASE_SHIFT, DPLL3_PHASE_SHIFT_VAL); - REG_WRITE(ah, AR_RTC_PLL_CONTROL, 0x142c); + AR_CH0_BB_DPLL3_PHASE_SHIFT, 0x6); + + REG_RMW_FIELD(ah, AR_CH0_BB_DPLL2, + AR_CH0_BB_DPLL2_PLL_PWD, 0x0); udelay(1000); + + REG_RMW_FIELD(ah, AR_CH0_BB_DPLL3, + AR_CH0_DPLL3_PHASE_SHIFT, DPLL3_PHASE_SHIFT_VAL); } pll = ath9k_hw_compute_pll_control(ah, chan); REG_WRITE(ah, AR_RTC_PLL_CONTROL, pll); + if (AR_SREV_9485(ah)) + udelay(1000); + /* Switch the core clock for ar9271 to 117Mhz */ if (AR_SREV_9271(ah)) { udelay(500); diff --git a/drivers/net/wireless/ath/ath9k/phy.h b/drivers/net/wireless/ath/ath9k/phy.h index f50e2c2..8e5fe9d 100644 --- a/drivers/net/wireless/ath/ath9k/phy.h +++ b/drivers/net/wireless/ath/ath9k/phy.h @@ -19,7 +19,6 @@ #define CHANSEL_DIV 15 #define CHANSEL_2G(_freq) (((_freq) * 0x10000) / CHANSEL_DIV) -#define CHANSEL_2G_9485(_freq) ((((_freq) * 0x10000) - 215) / CHANSEL_DIV) #define CHANSEL_5G(_freq) (((_freq) * 0x8000) / CHANSEL_DIV) #define AR_PHY_BASE 0x9800 diff --git a/drivers/net/wireless/ath/ath9k/reg.h b/drivers/net/wireless/ath/ath9k/reg.h index 2fbbe88..6acbf0e 100644 --- a/drivers/net/wireless/ath/ath9k/reg.h +++ b/drivers/net/wireless/ath/ath9k/reg.h @@ -1086,14 +1086,35 @@ enum { #define AR_ENT_OTP 0x40d8 #define AR_ENT_OTP_CHAIN2_DISABLE 0x00020000 #define AR_ENT_OTP_MPSD 0x00800000 -#define AR_CH0_BB_DPLL2 0x16184 + +#define AR_CH0_BB_DPLL1 0x16180 +#define AR_CH0_BB_DPLL1_REFDIV 0xF8000000 +#define AR_CH0_BB_DPLL1_REFDIV_S 27 +#define AR_CH0_BB_DPLL1_NINI 0x07FC0000 +#define AR_CH0_BB_DPLL1_NINI_S 18 +#define AR_CH0_BB_DPLL1_NFRAC 0x0003FFFF +#define AR_CH0_BB_DPLL1_NFRAC_S 0 + +#define AR_CH0_BB_DPLL2 0x16184 +#define AR_CH0_BB_DPLL2_LOCAL_PLL 0x40000000 +#define AR_CH0_BB_DPLL2_LOCAL_PLL_S 30 +#define AR_CH0_DPLL2_KI 0x3C000000 +#define AR_CH0_DPLL2_KI_S 26 +#define AR_CH0_DPLL2_KD 0x03F80000 +#define AR_CH0_DPLL2_KD_S 19 +#define AR_CH0_BB_DPLL2_EN_NEGTRIG 0x00040000 +#define AR_CH0_BB_DPLL2_EN_NEGTRIG_S 18 +#define AR_CH0_BB_DPLL2_PLL_PWD 0x00010000 +#define AR_CH0_BB_DPLL2_PLL_PWD_S 16 +#define AR_CH0_BB_DPLL2_OUTDIV 0x0000E000 +#define AR_CH0_BB_DPLL2_OUTDIV_S 13 + #define AR_CH0_BB_DPLL3 0x16188 +#define AR_CH0_BB_DPLL3_PHASE_SHIFT 0x3F800000 +#define AR_CH0_BB_DPLL3_PHASE_SHIFT_S 23 + #define AR_CH0_DDR_DPLL2 0x16244 #define AR_CH0_DDR_DPLL3 0x16248 -#define AR_CH0_DPLL2_KD 0x03F80000 -#define AR_CH0_DPLL2_KD_S 19 -#define AR_CH0_DPLL2_KI 0x3C000000 -#define AR_CH0_DPLL2_KI_S 26 #define AR_CH0_DPLL3_PHASE_SHIFT 0x3F800000 #define AR_CH0_DPLL3_PHASE_SHIFT_S 23 #define AR_PHY_CCA_NOM_VAL_2GHZ -118 -- cgit v0.10.2 From 2d05a0c2b4ac614cb5e0eba75d39a37205d129e8 Mon Sep 17 00:00:00 2001 From: Rajkumar Manoharan Date: Mon, 11 Apr 2011 20:22:28 +0530 Subject: ath9k_hw: Remove unused code in AR9287 eeprom Signed-off-by: Rajkumar Manoharan Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/eeprom_9287.c b/drivers/net/wireless/ath/ath9k/eeprom_9287.c index 2f0712e..1357975 100644 --- a/drivers/net/wireless/ath/ath9k/eeprom_9287.c +++ b/drivers/net/wireless/ath/ath9k/eeprom_9287.c @@ -858,35 +858,12 @@ static void ath9k_hw_ar9287_set_board_values(struct ath_hw *ah, { struct ar9287_eeprom *eep = &ah->eeprom.map9287; struct modal_eep_ar9287_header *pModal = &eep->modalHeader; - u16 antWrites[AR9287_ANT_16S]; u32 regChainOffset, regval; u8 txRxAttenLocal; - int i, j, offset_num; + int i; pModal = &eep->modalHeader; - antWrites[0] = (u16)((pModal->antCtrlCommon >> 28) & 0xF); - antWrites[1] = (u16)((pModal->antCtrlCommon >> 24) & 0xF); - antWrites[2] = (u16)((pModal->antCtrlCommon >> 20) & 0xF); - antWrites[3] = (u16)((pModal->antCtrlCommon >> 16) & 0xF); - antWrites[4] = (u16)((pModal->antCtrlCommon >> 12) & 0xF); - antWrites[5] = (u16)((pModal->antCtrlCommon >> 8) & 0xF); - antWrites[6] = (u16)((pModal->antCtrlCommon >> 4) & 0xF); - antWrites[7] = (u16)(pModal->antCtrlCommon & 0xF); - - offset_num = 8; - - for (i = 0, j = offset_num; i < AR9287_MAX_CHAINS; i++) { - antWrites[j++] = (u16)((pModal->antCtrlChain[i] >> 28) & 0xf); - antWrites[j++] = (u16)((pModal->antCtrlChain[i] >> 10) & 0x3); - antWrites[j++] = (u16)((pModal->antCtrlChain[i] >> 8) & 0x3); - antWrites[j++] = 0; - antWrites[j++] = (u16)((pModal->antCtrlChain[i] >> 6) & 0x3); - antWrites[j++] = (u16)((pModal->antCtrlChain[i] >> 4) & 0x3); - antWrites[j++] = (u16)((pModal->antCtrlChain[i] >> 2) & 0x3); - antWrites[j++] = (u16)(pModal->antCtrlChain[i] & 0x3); - } - REG_WRITE(ah, AR_PHY_SWITCH_COM, pModal->antCtrlCommon); for (i = 0; i < AR9287_MAX_CHAINS; i++) { -- cgit v0.10.2 From 5fb32faf821586312dc0b51a64bfa17ad0633daf Mon Sep 17 00:00:00 2001 From: Rajkumar Manoharan Date: Mon, 11 Apr 2011 20:22:29 +0530 Subject: ath9k_hw: update Ar9003 intervals to fix carrier leak Signed-off-by: Rajkumar Manoharan Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/ar9003_2p2_initvals.h b/drivers/net/wireless/ath/ath9k/ar9003_2p2_initvals.h index 9ecca93..7f30bc6 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_2p2_initvals.h +++ b/drivers/net/wireless/ath/ath9k/ar9003_2p2_initvals.h @@ -34,10 +34,10 @@ static const u32 ar9300_2p2_radio_postamble[][5] = { static const u32 ar9300Modes_lowest_ob_db_tx_gain_table_2p2[][5] = { /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ - {0x0000a2dc, 0x00033800, 0x00033800, 0x00637800, 0x00637800}, - {0x0000a2e0, 0x0003c000, 0x0003c000, 0x03838000, 0x03838000}, - {0x0000a2e4, 0x03fc0000, 0x03fc0000, 0x03fc0000, 0x03fc0000}, - {0x0000a2e8, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000a2dc, 0x00033800, 0x00033800, 0x03aaa352, 0x03aaa352}, + {0x0000a2e0, 0x0003c000, 0x0003c000, 0x03ccc584, 0x03ccc584}, + {0x0000a2e4, 0x03fc0000, 0x03fc0000, 0x03f0f800, 0x03f0f800}, + {0x0000a2e8, 0x00000000, 0x00000000, 0x03ff0000, 0x03ff0000}, {0x0000a410, 0x000050d9, 0x000050d9, 0x000050d9, 0x000050d9}, {0x0000a500, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, {0x0000a504, 0x06000003, 0x06000003, 0x04000002, 0x04000002}, @@ -119,14 +119,14 @@ static const u32 ar9300Modes_lowest_ob_db_tx_gain_table_2p2[][5] = { {0x0000a634, 0x04411104, 0x04411104, 0x04015005, 0x04015005}, {0x0000a638, 0x04411104, 0x04411104, 0x04015005, 0x04015005}, {0x0000a63c, 0x04411104, 0x04411104, 0x04015005, 0x04015005}, - {0x0000b2dc, 0x00033800, 0x00033800, 0x00637800, 0x00637800}, - {0x0000b2e0, 0x0003c000, 0x0003c000, 0x03838000, 0x03838000}, - {0x0000b2e4, 0x03fc0000, 0x03fc0000, 0x03fc0000, 0x03fc0000}, - {0x0000b2e8, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x0000c2dc, 0x00033800, 0x00033800, 0x00637800, 0x00637800}, - {0x0000c2e0, 0x0003c000, 0x0003c000, 0x03838000, 0x03838000}, - {0x0000c2e4, 0x03fc0000, 0x03fc0000, 0x03fc0000, 0x03fc0000}, - {0x0000c2e8, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000b2dc, 0x00033800, 0x00033800, 0x03aaa352, 0x03aaa352}, + {0x0000b2e0, 0x0003c000, 0x0003c000, 0x03ccc584, 0x03ccc584}, + {0x0000b2e4, 0x03fc0000, 0x03fc0000, 0x03f0f800, 0x03f0f800}, + {0x0000b2e8, 0x00000000, 0x00000000, 0x03ff0000, 0x03ff0000}, + {0x0000c2dc, 0x00033800, 0x00033800, 0x03aaa352, 0x03aaa352}, + {0x0000c2e0, 0x0003c000, 0x0003c000, 0x03ccc584, 0x03ccc584}, + {0x0000c2e4, 0x03fc0000, 0x03fc0000, 0x03f0f800, 0x03f0f800}, + {0x0000c2e8, 0x00000000, 0x00000000, 0x03ff0000, 0x03ff0000}, {0x00016044, 0x012492d4, 0x012492d4, 0x012492d4, 0x012492d4}, {0x00016048, 0x62480001, 0x62480001, 0x62480001, 0x62480001}, {0x00016068, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c}, @@ -835,10 +835,10 @@ static const u32 ar9300_2p2_baseband_core[][2] = { static const u32 ar9300Modes_high_power_tx_gain_table_2p2[][5] = { /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ - {0x0000a2dc, 0x0380c7fc, 0x0380c7fc, 0x00637800, 0x00637800}, - {0x0000a2e0, 0x0000f800, 0x0000f800, 0x03838000, 0x03838000}, - {0x0000a2e4, 0x03ff0000, 0x03ff0000, 0x03fc0000, 0x03fc0000}, - {0x0000a2e8, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000a2dc, 0x0380c7fc, 0x0380c7fc, 0x03aaa352, 0x03aaa352}, + {0x0000a2e0, 0x0000f800, 0x0000f800, 0x03ccc584, 0x03ccc584}, + {0x0000a2e4, 0x03ff0000, 0x03ff0000, 0x03f0f800, 0x03f0f800}, + {0x0000a2e8, 0x00000000, 0x00000000, 0x03ff0000, 0x03ff0000}, {0x0000a410, 0x000050d8, 0x000050d8, 0x000050d9, 0x000050d9}, {0x0000a500, 0x00002220, 0x00002220, 0x00000000, 0x00000000}, {0x0000a504, 0x04002222, 0x04002222, 0x04000002, 0x04000002}, @@ -920,14 +920,14 @@ static const u32 ar9300Modes_high_power_tx_gain_table_2p2[][5] = { {0x0000a634, 0x04c15305, 0x04c15305, 0x04015005, 0x04015005}, {0x0000a638, 0x04c15305, 0x04c15305, 0x04015005, 0x04015005}, {0x0000a63c, 0x04c15305, 0x04c15305, 0x04015005, 0x04015005}, - {0x0000b2dc, 0x0380c7fc, 0x0380c7fc, 0x00637800, 0x00637800}, - {0x0000b2e0, 0x0000f800, 0x0000f800, 0x03838000, 0x03838000}, - {0x0000b2e4, 0x03ff0000, 0x03ff0000, 0x03fc0000, 0x03fc0000}, - {0x0000b2e8, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x0000c2dc, 0x0380c7fc, 0x0380c7fc, 0x00637800, 0x00637800}, - {0x0000c2e0, 0x0000f800, 0x0000f800, 0x03838000, 0x03838000}, - {0x0000c2e4, 0x03ff0000, 0x03ff0000, 0x03fc0000, 0x03fc0000}, - {0x0000c2e8, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000b2dc, 0x0380c7fc, 0x0380c7fc, 0x03aaa352, 0x03aaa352}, + {0x0000b2e0, 0x0000f800, 0x0000f800, 0x03ccc584, 0x03ccc584}, + {0x0000b2e4, 0x03ff0000, 0x03ff0000, 0x03f0f800, 0x03f0f800}, + {0x0000b2e8, 0x00000000, 0x00000000, 0x03ff0000, 0x03ff0000}, + {0x0000c2dc, 0x0380c7fc, 0x0380c7fc, 0x03aaa352, 0x03aaa352}, + {0x0000c2e0, 0x0000f800, 0x0000f800, 0x03ccc584, 0x03ccc584}, + {0x0000c2e4, 0x03ff0000, 0x03ff0000, 0x03f0f800, 0x03f0f800}, + {0x0000c2e8, 0x00000000, 0x00000000, 0x03ff0000, 0x03ff0000}, {0x00016044, 0x056db2e6, 0x056db2e6, 0x056db2e6, 0x056db2e6}, {0x00016048, 0xae480001, 0xae480001, 0xae480001, 0xae480001}, {0x00016068, 0x6eb6db6c, 0x6eb6db6c, 0x6eb6db6c, 0x6eb6db6c}, @@ -941,10 +941,10 @@ static const u32 ar9300Modes_high_power_tx_gain_table_2p2[][5] = { static const u32 ar9300Modes_high_ob_db_tx_gain_table_2p2[][5] = { /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ - {0x0000a2dc, 0x01feee00, 0x01feee00, 0x00637800, 0x00637800}, - {0x0000a2e0, 0x0000f000, 0x0000f000, 0x03838000, 0x03838000}, - {0x0000a2e4, 0x01ff0000, 0x01ff0000, 0x03fc0000, 0x03fc0000}, - {0x0000a2e8, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000a2dc, 0x01feee00, 0x01feee00, 0x03aaa352, 0x03aaa352}, + {0x0000a2e0, 0x0000f000, 0x0000f000, 0x03ccc584, 0x03ccc584}, + {0x0000a2e4, 0x01ff0000, 0x01ff0000, 0x03f0f800, 0x03f0f800}, + {0x0000a2e8, 0x00000000, 0x00000000, 0x03ff0000, 0x03ff0000}, {0x0000a410, 0x000050d8, 0x000050d8, 0x000050d9, 0x000050d9}, {0x0000a500, 0x00002220, 0x00002220, 0x00000000, 0x00000000}, {0x0000a504, 0x04002222, 0x04002222, 0x04000002, 0x04000002}, @@ -1026,14 +1026,14 @@ static const u32 ar9300Modes_high_ob_db_tx_gain_table_2p2[][5] = { {0x0000a634, 0x04c15305, 0x04c15305, 0x04015005, 0x04015005}, {0x0000a638, 0x04c15305, 0x04c15305, 0x04015005, 0x04015005}, {0x0000a63c, 0x04c15305, 0x04c15305, 0x04015005, 0x04015005}, - {0x0000b2dc, 0x01feee00, 0x01feee00, 0x00637800, 0x00637800}, - {0x0000b2e0, 0x0000f000, 0x0000f000, 0x03838000, 0x03838000}, - {0x0000b2e4, 0x01ff0000, 0x01ff0000, 0x03fc0000, 0x03fc0000}, - {0x0000b2e8, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x0000c2dc, 0x01feee00, 0x01feee00, 0x00637800, 0x00637800}, - {0x0000c2e0, 0x0000f000, 0x0000f000, 0x03838000, 0x03838000}, - {0x0000c2e4, 0x01ff0000, 0x01ff0000, 0x03fc0000, 0x03fc0000}, - {0x0000c2e8, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000b2dc, 0x01feee00, 0x01feee00, 0x03aaa352, 0x03aaa352}, + {0x0000b2e0, 0x0000f000, 0x0000f000, 0x03ccc584, 0x03ccc584}, + {0x0000b2e4, 0x01ff0000, 0x01ff0000, 0x03f0f800, 0x03f0f800}, + {0x0000b2e8, 0x00000000, 0x00000000, 0x03ff0000, 0x03ff0000}, + {0x0000c2dc, 0x01feee00, 0x01feee00, 0x03aaa352, 0x03aaa352}, + {0x0000c2e0, 0x0000f000, 0x0000f000, 0x03ccc584, 0x03ccc584}, + {0x0000c2e4, 0x01ff0000, 0x01ff0000, 0x03f0f800, 0x03f0f800}, + {0x0000c2e8, 0x00000000, 0x00000000, 0x03ff0000, 0x03ff0000}, {0x00016044, 0x056db2e4, 0x056db2e4, 0x056db2e4, 0x056db2e4}, {0x00016048, 0x8e480001, 0x8e480001, 0x8e480001, 0x8e480001}, {0x00016068, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c}, @@ -1307,10 +1307,10 @@ static const u32 ar9300Common_rx_gain_table_2p2[][2] = { static const u32 ar9300Modes_low_ob_db_tx_gain_table_2p2[][5] = { /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ - {0x0000a2dc, 0x0380c7fc, 0x0380c7fc, 0x00637800, 0x00637800}, - {0x0000a2e0, 0x0000f800, 0x0000f800, 0x03838000, 0x03838000}, - {0x0000a2e4, 0x03ff0000, 0x03ff0000, 0x03fc0000, 0x03fc0000}, - {0x0000a2e8, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000a2dc, 0x0380c7fc, 0x0380c7fc, 0x03aaa352, 0x03aaa352}, + {0x0000a2e0, 0x0000f800, 0x0000f800, 0x03ccc584, 0x03ccc584}, + {0x0000a2e4, 0x03ff0000, 0x03ff0000, 0x03f0f800, 0x03f0f800}, + {0x0000a2e8, 0x00000000, 0x00000000, 0x03ff0000, 0x03ff0000}, {0x0000a410, 0x000050d9, 0x000050d9, 0x000050d9, 0x000050d9}, {0x0000a500, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, {0x0000a504, 0x06000003, 0x06000003, 0x04000002, 0x04000002}, @@ -1392,14 +1392,14 @@ static const u32 ar9300Modes_low_ob_db_tx_gain_table_2p2[][5] = { {0x0000a634, 0x03810e04, 0x03810e04, 0x04015005, 0x04015005}, {0x0000a638, 0x03810e04, 0x03810e04, 0x04015005, 0x04015005}, {0x0000a63c, 0x03810e04, 0x03810e04, 0x04015005, 0x04015005}, - {0x0000b2dc, 0x0380c7fc, 0x0380c7fc, 0x00637800, 0x00637800}, - {0x0000b2e0, 0x0000f800, 0x0000f800, 0x03838000, 0x03838000}, - {0x0000b2e4, 0x03ff0000, 0x03ff0000, 0x03fc0000, 0x03fc0000}, - {0x0000b2e8, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x0000c2dc, 0x0380c7fc, 0x0380c7fc, 0x00637800, 0x00637800}, - {0x0000c2e0, 0x0000f800, 0x0000f800, 0x03838000, 0x03838000}, - {0x0000c2e4, 0x03ff0000, 0x03ff0000, 0x03fc0000, 0x03fc0000}, - {0x0000c2e8, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000b2dc, 0x0380c7fc, 0x0380c7fc, 0x03aaa352, 0x03aaa352}, + {0x0000b2e0, 0x0000f800, 0x0000f800, 0x03ccc584, 0x03ccc584}, + {0x0000b2e4, 0x03ff0000, 0x03ff0000, 0x03f0f800, 0x03f0f800}, + {0x0000b2e8, 0x00000000, 0x00000000, 0x03ff0000, 0x03ff0000}, + {0x0000c2dc, 0x0380c7fc, 0x0380c7fc, 0x03aaa352, 0x03aaa352}, + {0x0000c2e0, 0x0000f800, 0x0000f800, 0x03ccc584, 0x03ccc584}, + {0x0000c2e4, 0x03ff0000, 0x03ff0000, 0x03f0f800, 0x03f0f800}, + {0x0000c2e8, 0x00000000, 0x00000000, 0x03ff0000, 0x03ff0000}, {0x00016044, 0x012492d4, 0x012492d4, 0x012492d4, 0x012492d4}, {0x00016048, 0x66480001, 0x66480001, 0x66480001, 0x66480001}, {0x00016068, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c}, -- cgit v0.10.2 From 901c1113da1efc98881233a8a67f98286a0b766a Mon Sep 17 00:00:00 2001 From: Rajkumar Manoharan Date: Mon, 11 Apr 2011 20:22:30 +0530 Subject: ath9k_hw: update AR9003 low_ob_db_tx_gain to improve spur performance Signed-off-by: Rajkumar Manoharan Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/ar9003_2p2_initvals.h b/drivers/net/wireless/ath/ath9k/ar9003_2p2_initvals.h index 7f30bc6..f915a3d 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_2p2_initvals.h +++ b/drivers/net/wireless/ath/ath9k/ar9003_2p2_initvals.h @@ -1307,9 +1307,9 @@ static const u32 ar9300Common_rx_gain_table_2p2[][2] = { static const u32 ar9300Modes_low_ob_db_tx_gain_table_2p2[][5] = { /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ - {0x0000a2dc, 0x0380c7fc, 0x0380c7fc, 0x03aaa352, 0x03aaa352}, - {0x0000a2e0, 0x0000f800, 0x0000f800, 0x03ccc584, 0x03ccc584}, - {0x0000a2e4, 0x03ff0000, 0x03ff0000, 0x03f0f800, 0x03f0f800}, + {0x0000a2dc, 0x00033800, 0x00033800, 0x03aaa352, 0x03aaa352}, + {0x0000a2e0, 0x0003c000, 0x0003c000, 0x03ccc584, 0x03ccc584}, + {0x0000a2e4, 0x03fc0000, 0x03fc0000, 0x03f0f800, 0x03f0f800}, {0x0000a2e8, 0x00000000, 0x00000000, 0x03ff0000, 0x03ff0000}, {0x0000a410, 0x000050d9, 0x000050d9, 0x000050d9, 0x000050d9}, {0x0000a500, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, @@ -1329,21 +1329,21 @@ static const u32 ar9300Modes_low_ob_db_tx_gain_table_2p2[][5] = { {0x0000a538, 0x4702244a, 0x4702244a, 0x34000e24, 0x34000e24}, {0x0000a53c, 0x4b02244c, 0x4b02244c, 0x38001640, 0x38001640}, {0x0000a540, 0x4e02246c, 0x4e02246c, 0x3c001660, 0x3c001660}, - {0x0000a544, 0x5302266c, 0x5302266c, 0x3f001861, 0x3f001861}, - {0x0000a548, 0x5702286c, 0x5702286c, 0x43001a81, 0x43001a81}, - {0x0000a54c, 0x5c02486b, 0x5c02486b, 0x47001a83, 0x47001a83}, - {0x0000a550, 0x61024a6c, 0x61024a6c, 0x4a001c84, 0x4a001c84}, - {0x0000a554, 0x66026a6c, 0x66026a6c, 0x4e001ce3, 0x4e001ce3}, - {0x0000a558, 0x6b026e6c, 0x6b026e6c, 0x52001ce5, 0x52001ce5}, - {0x0000a55c, 0x7002708c, 0x7002708c, 0x56001ce9, 0x56001ce9}, - {0x0000a560, 0x7302b08a, 0x7302b08a, 0x5a001ceb, 0x5a001ceb}, - {0x0000a564, 0x7702b08c, 0x7702b08c, 0x5d001eec, 0x5d001eec}, - {0x0000a568, 0x7702b08c, 0x7702b08c, 0x5d001eec, 0x5d001eec}, - {0x0000a56c, 0x7702b08c, 0x7702b08c, 0x5d001eec, 0x5d001eec}, - {0x0000a570, 0x7702b08c, 0x7702b08c, 0x5d001eec, 0x5d001eec}, - {0x0000a574, 0x7702b08c, 0x7702b08c, 0x5d001eec, 0x5d001eec}, - {0x0000a578, 0x7702b08c, 0x7702b08c, 0x5d001eec, 0x5d001eec}, - {0x0000a57c, 0x7702b08c, 0x7702b08c, 0x5d001eec, 0x5d001eec}, + {0x0000a544, 0x52022470, 0x52022470, 0x3f001861, 0x3f001861}, + {0x0000a548, 0x55022490, 0x55022490, 0x43001a81, 0x43001a81}, + {0x0000a54c, 0x59022492, 0x59022492, 0x47001a83, 0x47001a83}, + {0x0000a550, 0x5d022692, 0x5d022692, 0x4a001c84, 0x4a001c84}, + {0x0000a554, 0x61022892, 0x61022892, 0x4e001ce3, 0x4e001ce3}, + {0x0000a558, 0x65024890, 0x65024890, 0x52001ce5, 0x52001ce5}, + {0x0000a55c, 0x69024892, 0x69024892, 0x56001ce9, 0x56001ce9}, + {0x0000a560, 0x6e024c92, 0x6e024c92, 0x5a001ceb, 0x5a001ceb}, + {0x0000a564, 0x74026e92, 0x74026e92, 0x5d001eec, 0x5d001eec}, + {0x0000a568, 0x74026e92, 0x74026e92, 0x5d001eec, 0x5d001eec}, + {0x0000a56c, 0x74026e92, 0x74026e92, 0x5d001eec, 0x5d001eec}, + {0x0000a570, 0x74026e92, 0x74026e92, 0x5d001eec, 0x5d001eec}, + {0x0000a574, 0x74026e92, 0x74026e92, 0x5d001eec, 0x5d001eec}, + {0x0000a578, 0x74026e92, 0x74026e92, 0x5d001eec, 0x5d001eec}, + {0x0000a57c, 0x74026e92, 0x74026e92, 0x5d001eec, 0x5d001eec}, {0x0000a580, 0x00800000, 0x00800000, 0x00800000, 0x00800000}, {0x0000a584, 0x06800003, 0x06800003, 0x04800002, 0x04800002}, {0x0000a588, 0x0a800020, 0x0a800020, 0x08800004, 0x08800004}, @@ -1361,44 +1361,44 @@ static const u32 ar9300Modes_low_ob_db_tx_gain_table_2p2[][5] = { {0x0000a5b8, 0x4782244a, 0x4782244a, 0x34800e24, 0x34800e24}, {0x0000a5bc, 0x4b82244c, 0x4b82244c, 0x38801640, 0x38801640}, {0x0000a5c0, 0x4e82246c, 0x4e82246c, 0x3c801660, 0x3c801660}, - {0x0000a5c4, 0x5382266c, 0x5382266c, 0x3f801861, 0x3f801861}, - {0x0000a5c8, 0x5782286c, 0x5782286c, 0x43801a81, 0x43801a81}, - {0x0000a5cc, 0x5c82486b, 0x5c82486b, 0x47801a83, 0x47801a83}, - {0x0000a5d0, 0x61824a6c, 0x61824a6c, 0x4a801c84, 0x4a801c84}, - {0x0000a5d4, 0x66826a6c, 0x66826a6c, 0x4e801ce3, 0x4e801ce3}, - {0x0000a5d8, 0x6b826e6c, 0x6b826e6c, 0x52801ce5, 0x52801ce5}, - {0x0000a5dc, 0x7082708c, 0x7082708c, 0x56801ce9, 0x56801ce9}, - {0x0000a5e0, 0x7382b08a, 0x7382b08a, 0x5a801ceb, 0x5a801ceb}, - {0x0000a5e4, 0x7782b08c, 0x7782b08c, 0x5d801eec, 0x5d801eec}, - {0x0000a5e8, 0x7782b08c, 0x7782b08c, 0x5d801eec, 0x5d801eec}, - {0x0000a5ec, 0x7782b08c, 0x7782b08c, 0x5d801eec, 0x5d801eec}, - {0x0000a5f0, 0x7782b08c, 0x7782b08c, 0x5d801eec, 0x5d801eec}, - {0x0000a5f4, 0x7782b08c, 0x7782b08c, 0x5d801eec, 0x5d801eec}, - {0x0000a5f8, 0x7782b08c, 0x7782b08c, 0x5d801eec, 0x5d801eec}, - {0x0000a5fc, 0x7782b08c, 0x7782b08c, 0x5d801eec, 0x5d801eec}, + {0x0000a5c4, 0x52822470, 0x52822470, 0x3f801861, 0x3f801861}, + {0x0000a5c8, 0x55822490, 0x55822490, 0x43801a81, 0x43801a81}, + {0x0000a5cc, 0x59822492, 0x59822492, 0x47801a83, 0x47801a83}, + {0x0000a5d0, 0x5d822692, 0x5d822692, 0x4a801c84, 0x4a801c84}, + {0x0000a5d4, 0x61822892, 0x61822892, 0x4e801ce3, 0x4e801ce3}, + {0x0000a5d8, 0x65824890, 0x65824890, 0x52801ce5, 0x52801ce5}, + {0x0000a5dc, 0x69824892, 0x69824892, 0x56801ce9, 0x56801ce9}, + {0x0000a5e0, 0x6e824c92, 0x6e824c92, 0x5a801ceb, 0x5a801ceb}, + {0x0000a5e4, 0x74826e92, 0x74826e92, 0x5d801eec, 0x5d801eec}, + {0x0000a5e8, 0x74826e92, 0x74826e92, 0x5d801eec, 0x5d801eec}, + {0x0000a5ec, 0x74826e92, 0x74826e92, 0x5d801eec, 0x5d801eec}, + {0x0000a5f0, 0x74826e92, 0x74826e92, 0x5d801eec, 0x5d801eec}, + {0x0000a5f4, 0x74826e92, 0x74826e92, 0x5d801eec, 0x5d801eec}, + {0x0000a5f8, 0x74826e92, 0x74826e92, 0x5d801eec, 0x5d801eec}, + {0x0000a5fc, 0x74826e92, 0x74826e92, 0x5d801eec, 0x5d801eec}, {0x0000a600, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, {0x0000a604, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, {0x0000a608, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, {0x0000a60c, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, {0x0000a610, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x0000a614, 0x01404000, 0x01404000, 0x01404000, 0x01404000}, - {0x0000a618, 0x01404501, 0x01404501, 0x01404501, 0x01404501}, - {0x0000a61c, 0x02008802, 0x02008802, 0x02008501, 0x02008501}, - {0x0000a620, 0x0300cc03, 0x0300cc03, 0x0280ca03, 0x0280ca03}, - {0x0000a624, 0x0300cc03, 0x0300cc03, 0x03010c04, 0x03010c04}, - {0x0000a628, 0x0300cc03, 0x0300cc03, 0x04014c04, 0x04014c04}, - {0x0000a62c, 0x03810c03, 0x03810c03, 0x04015005, 0x04015005}, - {0x0000a630, 0x03810e04, 0x03810e04, 0x04015005, 0x04015005}, - {0x0000a634, 0x03810e04, 0x03810e04, 0x04015005, 0x04015005}, - {0x0000a638, 0x03810e04, 0x03810e04, 0x04015005, 0x04015005}, - {0x0000a63c, 0x03810e04, 0x03810e04, 0x04015005, 0x04015005}, - {0x0000b2dc, 0x0380c7fc, 0x0380c7fc, 0x03aaa352, 0x03aaa352}, - {0x0000b2e0, 0x0000f800, 0x0000f800, 0x03ccc584, 0x03ccc584}, - {0x0000b2e4, 0x03ff0000, 0x03ff0000, 0x03f0f800, 0x03f0f800}, + {0x0000a614, 0x02004000, 0x02004000, 0x01404000, 0x01404000}, + {0x0000a618, 0x02004801, 0x02004801, 0x01404501, 0x01404501}, + {0x0000a61c, 0x02808a02, 0x02808a02, 0x02008501, 0x02008501}, + {0x0000a620, 0x0380ce03, 0x0380ce03, 0x0280ca03, 0x0280ca03}, + {0x0000a624, 0x04411104, 0x04411104, 0x03010c04, 0x03010c04}, + {0x0000a628, 0x04411104, 0x04411104, 0x04014c04, 0x04014c04}, + {0x0000a62c, 0x04411104, 0x04411104, 0x04015005, 0x04015005}, + {0x0000a630, 0x04411104, 0x04411104, 0x04015005, 0x04015005}, + {0x0000a634, 0x04411104, 0x04411104, 0x04015005, 0x04015005}, + {0x0000a638, 0x04411104, 0x04411104, 0x04015005, 0x04015005}, + {0x0000a63c, 0x04411104, 0x04411104, 0x04015005, 0x04015005}, + {0x0000b2dc, 0x00033800, 0x00033800, 0x03aaa352, 0x03aaa352}, + {0x0000b2e0, 0x0003c000, 0x0003c000, 0x03ccc584, 0x03ccc584}, + {0x0000b2e4, 0x03fc0000, 0x03fc0000, 0x03f0f800, 0x03f0f800}, {0x0000b2e8, 0x00000000, 0x00000000, 0x03ff0000, 0x03ff0000}, - {0x0000c2dc, 0x0380c7fc, 0x0380c7fc, 0x03aaa352, 0x03aaa352}, - {0x0000c2e0, 0x0000f800, 0x0000f800, 0x03ccc584, 0x03ccc584}, - {0x0000c2e4, 0x03ff0000, 0x03ff0000, 0x03f0f800, 0x03f0f800}, + {0x0000c2dc, 0x00033800, 0x00033800, 0x03aaa352, 0x03aaa352}, + {0x0000c2e0, 0x0003c000, 0x0003c000, 0x03ccc584, 0x03ccc584}, + {0x0000c2e4, 0x03fc0000, 0x03fc0000, 0x03f0f800, 0x03f0f800}, {0x0000c2e8, 0x00000000, 0x00000000, 0x03ff0000, 0x03ff0000}, {0x00016044, 0x012492d4, 0x012492d4, 0x012492d4, 0x012492d4}, {0x00016048, 0x66480001, 0x66480001, 0x66480001, 0x66480001}, -- cgit v0.10.2 From b3ba44c6d1633692b45910ee77064e635e2c3143 Mon Sep 17 00:00:00 2001 From: Mark Davis Date: Tue, 12 Apr 2011 00:19:10 -0400 Subject: rt2800usb: Add seven new USB IDs Adds USB IDs for seven previously missing devices. Additionally, all instances of 'Conceptronic' have been replaced by the OEM name. Devices added are.. 0411:01a2 - Buffalo WLI-UC-GNM, RT3070V 0586:341e - ZyXEL NWD2105, RT3070 13b1:002f - Linksys AE1000, RT3572 13b1:0031 - Cisco / Linksys AM10, RT3072 14b2:3c2c - Keebox W150NU / Alpha Networks WUS-N12, RT3070 157e:3013 - TRENDnet TEW-645UB, RT2770+RT2720 15a9:0012 - Airlink AWLL7025 / Gemtek WUBR-208N, RT2870+RT2850 Signed-off-by: Mark Davis Acked-by: Gertjan van Wingerde Acked-by: Ivo van Doorn Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/rt2x00/rt2800usb.c b/drivers/net/wireless/rt2x00/rt2800usb.c index 6ba31a0..d2f5c87 100644 --- a/drivers/net/wireless/rt2x00/rt2800usb.c +++ b/drivers/net/wireless/rt2x00/rt2800usb.c @@ -710,6 +710,16 @@ static struct usb_device_id rt2800usb_device_table[] = { { USB_DEVICE(0x8516, 0x3070), USB_DEVICE_DATA(&rt2800usb_ops) }, { USB_DEVICE(0x8516, 0x3071), USB_DEVICE_DATA(&rt2800usb_ops) }, { USB_DEVICE(0x8516, 0x3072), USB_DEVICE_DATA(&rt2800usb_ops) }, + /* Alpha Networks */ + { USB_DEVICE(0x14b2, 0x3c06), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x14b2, 0x3c07), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x14b2, 0x3c09), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x14b2, 0x3c12), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x14b2, 0x3c23), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x14b2, 0x3c25), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x14b2, 0x3c27), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x14b2, 0x3c28), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x14b2, 0x3c2c), USB_DEVICE_DATA(&rt2800usb_ops) }, /* Amit */ { USB_DEVICE(0x15c5, 0x0008), USB_DEVICE_DATA(&rt2800usb_ops) }, /* Askey */ @@ -736,15 +746,7 @@ static struct usb_device_id rt2800usb_device_table[] = { /* Buffalo */ { USB_DEVICE(0x0411, 0x00e8), USB_DEVICE_DATA(&rt2800usb_ops) }, { USB_DEVICE(0x0411, 0x016f), USB_DEVICE_DATA(&rt2800usb_ops) }, - /* Conceptronic */ - { USB_DEVICE(0x14b2, 0x3c06), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x14b2, 0x3c07), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x14b2, 0x3c09), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x14b2, 0x3c12), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x14b2, 0x3c23), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x14b2, 0x3c25), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x14b2, 0x3c27), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x14b2, 0x3c28), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x0411, 0x01a2), USB_DEVICE_DATA(&rt2800usb_ops) }, /* Corega */ { USB_DEVICE(0x07aa, 0x002f), USB_DEVICE_DATA(&rt2800usb_ops) }, { USB_DEVICE(0x07aa, 0x003c), USB_DEVICE_DATA(&rt2800usb_ops) }, @@ -776,6 +778,8 @@ static struct usb_device_id rt2800usb_device_table[] = { { USB_DEVICE(0x1740, 0x9707), USB_DEVICE_DATA(&rt2800usb_ops) }, { USB_DEVICE(0x1740, 0x9708), USB_DEVICE_DATA(&rt2800usb_ops) }, { USB_DEVICE(0x1740, 0x9709), USB_DEVICE_DATA(&rt2800usb_ops) }, + /* Gemtek */ + { USB_DEVICE(0x15a9, 0x0012), USB_DEVICE_DATA(&rt2800usb_ops) }, /* Gigabyte */ { USB_DEVICE(0x1044, 0x800b), USB_DEVICE_DATA(&rt2800usb_ops) }, { USB_DEVICE(0x1044, 0x800d), USB_DEVICE_DATA(&rt2800usb_ops) }, @@ -792,6 +796,7 @@ static struct usb_device_id rt2800usb_device_table[] = { { USB_DEVICE(0x04bb, 0x0947), USB_DEVICE_DATA(&rt2800usb_ops) }, { USB_DEVICE(0x04bb, 0x0948), USB_DEVICE_DATA(&rt2800usb_ops) }, /* Linksys */ + { USB_DEVICE(0x13b1, 0x0031), USB_DEVICE_DATA(&rt2800usb_ops) }, { USB_DEVICE(0x1737, 0x0070), USB_DEVICE_DATA(&rt2800usb_ops) }, { USB_DEVICE(0x1737, 0x0071), USB_DEVICE_DATA(&rt2800usb_ops) }, /* Logitec */ @@ -870,8 +875,9 @@ static struct usb_device_id rt2800usb_device_table[] = { { USB_DEVICE(0x15a9, 0x0006), USB_DEVICE_DATA(&rt2800usb_ops) }, /* Sweex */ { USB_DEVICE(0x177f, 0x0302), USB_DEVICE_DATA(&rt2800usb_ops) }, - /* U-Media*/ + /* U-Media */ { USB_DEVICE(0x157e, 0x300e), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x157e, 0x3013), USB_DEVICE_DATA(&rt2800usb_ops) }, /* ZCOM */ { USB_DEVICE(0x0cde, 0x0022), USB_DEVICE_DATA(&rt2800usb_ops) }, { USB_DEVICE(0x0cde, 0x0025), USB_DEVICE_DATA(&rt2800usb_ops) }, @@ -883,6 +889,7 @@ static struct usb_device_id rt2800usb_device_table[] = { /* Zyxel */ { USB_DEVICE(0x0586, 0x3416), USB_DEVICE_DATA(&rt2800usb_ops) }, { USB_DEVICE(0x0586, 0x3418), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x0586, 0x341e), USB_DEVICE_DATA(&rt2800usb_ops) }, #ifdef CONFIG_RT2800USB_RT33XX /* Ralink */ { USB_DEVICE(0x148f, 0x3370), USB_DEVICE_DATA(&rt2800usb_ops) }, @@ -901,6 +908,8 @@ static struct usb_device_id rt2800usb_device_table[] = { { USB_DEVICE(0x1740, 0x9801), USB_DEVICE_DATA(&rt2800usb_ops) }, /* I-O DATA */ { USB_DEVICE(0x04bb, 0x0944), USB_DEVICE_DATA(&rt2800usb_ops) }, + /* Linksys */ + { USB_DEVICE(0x13b1, 0x002f), USB_DEVICE_DATA(&rt2800usb_ops) }, /* Ralink */ { USB_DEVICE(0x148f, 0x3572), USB_DEVICE_DATA(&rt2800usb_ops) }, /* Sitecom */ @@ -915,6 +924,9 @@ static struct usb_device_id rt2800usb_device_table[] = { * Unclear what kind of devices these are (they aren't supported by the * vendor linux driver). */ + /* Alpha Networks */ + { USB_DEVICE(0x14b2, 0x3c08), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x14b2, 0x3c11), USB_DEVICE_DATA(&rt2800usb_ops) }, /* Amigo */ { USB_DEVICE(0x0e0b, 0x9031), USB_DEVICE_DATA(&rt2800usb_ops) }, { USB_DEVICE(0x0e0b, 0x9041), USB_DEVICE_DATA(&rt2800usb_ops) }, @@ -933,9 +945,6 @@ static struct usb_device_id rt2800usb_device_table[] = { { USB_DEVICE(0x0411, 0x0148), USB_DEVICE_DATA(&rt2800usb_ops) }, { USB_DEVICE(0x0411, 0x0150), USB_DEVICE_DATA(&rt2800usb_ops) }, { USB_DEVICE(0x0411, 0x015d), USB_DEVICE_DATA(&rt2800usb_ops) }, - /* Conceptronic */ - { USB_DEVICE(0x14b2, 0x3c08), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x14b2, 0x3c11), USB_DEVICE_DATA(&rt2800usb_ops) }, /* Corega */ { USB_DEVICE(0x07aa, 0x0041), USB_DEVICE_DATA(&rt2800usb_ops) }, { USB_DEVICE(0x07aa, 0x0042), USB_DEVICE_DATA(&rt2800usb_ops) }, -- cgit v0.10.2 From 6f11c819d5fb24b637f2db605e5d3c270c979627 Mon Sep 17 00:00:00 2001 From: Vasanthakumar Thiagarajan Date: Tue, 12 Apr 2011 12:42:22 +0530 Subject: ath9k: Register id table for platform device Currently the device id in the platform driver is hardcoded to an id which is specific to AR9130/AR9132 SOCs as it supports only wmac (wireless mac) of these SOCs. But this needs to be dynamic when we want to support different wmac of SOCs. So add id_table to driver to make it extendable to more SOCs. Signed-off-by: Vasanthakumar Thiagarajan Acked-by: Gabor Juhos Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/ahb.c b/drivers/net/wireless/ath/ath9k/ahb.c index 9cb0efa..5193ed5 100644 --- a/drivers/net/wireless/ath/ath9k/ahb.c +++ b/drivers/net/wireless/ath/ath9k/ahb.c @@ -21,6 +21,14 @@ #include #include "ath9k.h" +const struct platform_device_id ath9k_platform_id_table[] = { + { + .name = "ath9k", + .driver_data = AR5416_AR9100_DEVID, + }, + {}, +}; + /* return bus cachesize in 4B word units */ static void ath_ahb_read_cachesize(struct ath_common *common, int *csz) { @@ -57,6 +65,7 @@ static int ath_ahb_probe(struct platform_device *pdev) struct ath_softc *sc; struct ieee80211_hw *hw; struct resource *res; + const struct platform_device_id *id = platform_get_device_id(pdev); int irq; int ret = 0; struct ath_hw *ah; @@ -116,7 +125,7 @@ static int ath_ahb_probe(struct platform_device *pdev) goto err_free_hw; } - ret = ath9k_init_device(AR5416_AR9100_DEVID, sc, 0x0, &ath_ahb_bus_ops); + ret = ath9k_init_device(id->driver_data, sc, 0x0, &ath_ahb_bus_ops); if (ret) { dev_err(&pdev->dev, "failed to initialize device\n"); goto err_irq; @@ -165,8 +174,11 @@ static struct platform_driver ath_ahb_driver = { .name = "ath9k", .owner = THIS_MODULE, }, + .id_table = ath9k_platform_id_table, }; +MODULE_DEVICE_TABLE(platform, ath9k_platform_id_table); + int ath_ahb_init(void) { return platform_driver_register(&ath_ahb_driver); -- cgit v0.10.2 From bcc6d47903612c3861201cc3a866fb604f26b8b2 Mon Sep 17 00:00:00 2001 From: Jiri Pirko Date: Thu, 7 Apr 2011 19:48:33 +0000 Subject: net: vlan: make non-hw-accel rx path similar to hw-accel Now there are 2 paths for rx vlan frames. When rx-vlan-hw-accel is enabled, skb is untagged by NIC, vlan_tci is set and the skb gets into vlan code in __netif_receive_skb - vlan_hwaccel_do_receive. For non-rx-vlan-hw-accel however, tagged skb goes thru whole __netif_receive_skb, it's untagged in ptype_base hander and reinjected This incosistency is fixed by this patch. Vlan untagging happens early in __netif_receive_skb so the rest of code (ptype_all handlers, rx_handlers) see the skb like it was untagged by hw. Signed-off-by: Jiri Pirko v1->v2: remove "inline" from vlan_core.c functions Signed-off-by: David S. Miller diff --git a/include/linux/if_vlan.h b/include/linux/if_vlan.h index 635e1fa..998b299 100644 --- a/include/linux/if_vlan.h +++ b/include/linux/if_vlan.h @@ -132,7 +132,8 @@ extern u16 vlan_dev_vlan_id(const struct net_device *dev); extern int __vlan_hwaccel_rx(struct sk_buff *skb, struct vlan_group *grp, u16 vlan_tci, int polling); -extern bool vlan_hwaccel_do_receive(struct sk_buff **skb); +extern bool vlan_do_receive(struct sk_buff **skb); +extern struct sk_buff *vlan_untag(struct sk_buff *skb); extern gro_result_t vlan_gro_receive(struct napi_struct *napi, struct vlan_group *grp, unsigned int vlan_tci, struct sk_buff *skb); @@ -166,13 +167,18 @@ static inline int __vlan_hwaccel_rx(struct sk_buff *skb, struct vlan_group *grp, return NET_XMIT_SUCCESS; } -static inline bool vlan_hwaccel_do_receive(struct sk_buff **skb) +static inline bool vlan_do_receive(struct sk_buff **skb) { if ((*skb)->vlan_tci & VLAN_VID_MASK) (*skb)->pkt_type = PACKET_OTHERHOST; return false; } +inline struct sk_buff *vlan_untag(struct sk_buff *skb) +{ + return skb; +} + static inline gro_result_t vlan_gro_receive(struct napi_struct *napi, struct vlan_group *grp, unsigned int vlan_tci, struct sk_buff *skb) diff --git a/net/8021q/vlan.c b/net/8021q/vlan.c index e47600b..14ef5ef 100644 --- a/net/8021q/vlan.c +++ b/net/8021q/vlan.c @@ -49,11 +49,6 @@ const char vlan_version[] = DRV_VERSION; static const char vlan_copyright[] = "Ben Greear "; static const char vlan_buggyright[] = "David S. Miller "; -static struct packet_type vlan_packet_type __read_mostly = { - .type = cpu_to_be16(ETH_P_8021Q), - .func = vlan_skb_recv, /* VLAN receive method */ -}; - /* End of global variables definitions. */ static void vlan_group_free(struct vlan_group *grp) @@ -684,7 +679,6 @@ static int __init vlan_proto_init(void) if (err < 0) goto err4; - dev_add_pack(&vlan_packet_type); vlan_ioctl_set(vlan_ioctl_handler); return 0; @@ -705,8 +699,6 @@ static void __exit vlan_cleanup_module(void) unregister_netdevice_notifier(&vlan_notifier_block); - dev_remove_pack(&vlan_packet_type); - unregister_pernet_subsys(&vlan_net_ops); rcu_barrier(); /* Wait for completion of call_rcu()'s */ diff --git a/net/8021q/vlan.h b/net/8021q/vlan.h index 5687c9b..c3408de 100644 --- a/net/8021q/vlan.h +++ b/net/8021q/vlan.h @@ -75,8 +75,6 @@ static inline struct vlan_dev_info *vlan_dev_info(const struct net_device *dev) } /* found in vlan_dev.c */ -int vlan_skb_recv(struct sk_buff *skb, struct net_device *dev, - struct packet_type *ptype, struct net_device *orig_dev); void vlan_dev_set_ingress_priority(const struct net_device *dev, u32 skb_prio, u16 vlan_prio); int vlan_dev_set_egress_priority(const struct net_device *dev, diff --git a/net/8021q/vlan_core.c b/net/8021q/vlan_core.c index ce8e3ab..41495dc2 100644 --- a/net/8021q/vlan_core.c +++ b/net/8021q/vlan_core.c @@ -4,7 +4,7 @@ #include #include "vlan.h" -bool vlan_hwaccel_do_receive(struct sk_buff **skbp) +bool vlan_do_receive(struct sk_buff **skbp) { struct sk_buff *skb = *skbp; u16 vlan_id = skb->vlan_tci & VLAN_VID_MASK; @@ -88,3 +88,86 @@ gro_result_t vlan_gro_frags(struct napi_struct *napi, struct vlan_group *grp, return napi_gro_frags(napi); } EXPORT_SYMBOL(vlan_gro_frags); + +static struct sk_buff *vlan_check_reorder_header(struct sk_buff *skb) +{ + if (vlan_dev_info(skb->dev)->flags & VLAN_FLAG_REORDER_HDR) { + if (skb_cow(skb, skb_headroom(skb)) < 0) + skb = NULL; + if (skb) { + /* Lifted from Gleb's VLAN code... */ + memmove(skb->data - ETH_HLEN, + skb->data - VLAN_ETH_HLEN, 12); + skb->mac_header += VLAN_HLEN; + } + } + return skb; +} + +static void vlan_set_encap_proto(struct sk_buff *skb, struct vlan_hdr *vhdr) +{ + __be16 proto; + unsigned char *rawp; + + /* + * Was a VLAN packet, grab the encapsulated protocol, which the layer + * three protocols care about. + */ + + proto = vhdr->h_vlan_encapsulated_proto; + if (ntohs(proto) >= 1536) { + skb->protocol = proto; + return; + } + + rawp = skb->data; + if (*(unsigned short *) rawp == 0xFFFF) + /* + * This is a magic hack to spot IPX packets. Older Novell + * breaks the protocol design and runs IPX over 802.3 without + * an 802.2 LLC layer. We look for FFFF which isn't a used + * 802.2 SSAP/DSAP. This won't work for fault tolerant netware + * but does for the rest. + */ + skb->protocol = htons(ETH_P_802_3); + else + /* + * Real 802.2 LLC + */ + skb->protocol = htons(ETH_P_802_2); +} + +struct sk_buff *vlan_untag(struct sk_buff *skb) +{ + struct vlan_hdr *vhdr; + u16 vlan_tci; + + if (unlikely(vlan_tx_tag_present(skb))) { + /* vlan_tci is already set-up so leave this for another time */ + return skb; + } + + skb = skb_share_check(skb, GFP_ATOMIC); + if (unlikely(!skb)) + goto err_free; + + if (unlikely(!pskb_may_pull(skb, VLAN_HLEN))) + goto err_free; + + vhdr = (struct vlan_hdr *) skb->data; + vlan_tci = ntohs(vhdr->h_vlan_TCI); + __vlan_hwaccel_put_tag(skb, vlan_tci); + + skb_pull_rcsum(skb, VLAN_HLEN); + vlan_set_encap_proto(skb, vhdr); + + skb = vlan_check_reorder_header(skb); + if (unlikely(!skb)) + goto err_free; + + return skb; + +err_free: + kfree_skb(skb); + return NULL; +} diff --git a/net/8021q/vlan_dev.c b/net/8021q/vlan_dev.c index b84a46b..d174c31 100644 --- a/net/8021q/vlan_dev.c +++ b/net/8021q/vlan_dev.c @@ -65,179 +65,6 @@ static int vlan_dev_rebuild_header(struct sk_buff *skb) return 0; } -static inline struct sk_buff *vlan_check_reorder_header(struct sk_buff *skb) -{ - if (vlan_dev_info(skb->dev)->flags & VLAN_FLAG_REORDER_HDR) { - if (skb_cow(skb, skb_headroom(skb)) < 0) - skb = NULL; - if (skb) { - /* Lifted from Gleb's VLAN code... */ - memmove(skb->data - ETH_HLEN, - skb->data - VLAN_ETH_HLEN, 12); - skb->mac_header += VLAN_HLEN; - } - } - - return skb; -} - -static inline void vlan_set_encap_proto(struct sk_buff *skb, - struct vlan_hdr *vhdr) -{ - __be16 proto; - unsigned char *rawp; - - /* - * Was a VLAN packet, grab the encapsulated protocol, which the layer - * three protocols care about. - */ - - proto = vhdr->h_vlan_encapsulated_proto; - if (ntohs(proto) >= 1536) { - skb->protocol = proto; - return; - } - - rawp = skb->data; - if (*(unsigned short *)rawp == 0xFFFF) - /* - * This is a magic hack to spot IPX packets. Older Novell - * breaks the protocol design and runs IPX over 802.3 without - * an 802.2 LLC layer. We look for FFFF which isn't a used - * 802.2 SSAP/DSAP. This won't work for fault tolerant netware - * but does for the rest. - */ - skb->protocol = htons(ETH_P_802_3); - else - /* - * Real 802.2 LLC - */ - skb->protocol = htons(ETH_P_802_2); -} - -/* - * Determine the packet's protocol ID. The rule here is that we - * assume 802.3 if the type field is short enough to be a length. - * This is normal practice and works for any 'now in use' protocol. - * - * Also, at this point we assume that we ARE dealing exclusively with - * VLAN packets, or packets that should be made into VLAN packets based - * on a default VLAN ID. - * - * NOTE: Should be similar to ethernet/eth.c. - * - * SANITY NOTE: This method is called when a packet is moving up the stack - * towards userland. To get here, it would have already passed - * through the ethernet/eth.c eth_type_trans() method. - * SANITY NOTE 2: We are referencing to the VLAN_HDR frields, which MAY be - * stored UNALIGNED in the memory. RISC systems don't like - * such cases very much... - * SANITY NOTE 2a: According to Dave Miller & Alexey, it will always be - * aligned, so there doesn't need to be any of the unaligned - * stuff. It has been commented out now... --Ben - * - */ -int vlan_skb_recv(struct sk_buff *skb, struct net_device *dev, - struct packet_type *ptype, struct net_device *orig_dev) -{ - struct vlan_hdr *vhdr; - struct vlan_pcpu_stats *rx_stats; - struct net_device *vlan_dev; - u16 vlan_id; - u16 vlan_tci; - - skb = skb_share_check(skb, GFP_ATOMIC); - if (skb == NULL) - goto err_free; - - if (unlikely(!pskb_may_pull(skb, VLAN_HLEN))) - goto err_free; - - vhdr = (struct vlan_hdr *)skb->data; - vlan_tci = ntohs(vhdr->h_vlan_TCI); - vlan_id = vlan_tci & VLAN_VID_MASK; - - rcu_read_lock(); - vlan_dev = vlan_find_dev(dev, vlan_id); - - /* If the VLAN device is defined, we use it. - * If not, and the VID is 0, it is a 802.1p packet (not - * really a VLAN), so we will just netif_rx it later to the - * original interface, but with the skb->proto set to the - * wrapped proto: we do nothing here. - */ - - if (!vlan_dev) { - if (vlan_id) { - pr_debug("%s: ERROR: No net_device for VID: %u on dev: %s\n", - __func__, vlan_id, dev->name); - goto err_unlock; - } - rx_stats = NULL; - } else { - skb->dev = vlan_dev; - - rx_stats = this_cpu_ptr(vlan_dev_info(skb->dev)->vlan_pcpu_stats); - - u64_stats_update_begin(&rx_stats->syncp); - rx_stats->rx_packets++; - rx_stats->rx_bytes += skb->len; - - skb->priority = vlan_get_ingress_priority(skb->dev, vlan_tci); - - pr_debug("%s: priority: %u for TCI: %hu\n", - __func__, skb->priority, vlan_tci); - - switch (skb->pkt_type) { - case PACKET_BROADCAST: - /* Yeah, stats collect these together.. */ - /* stats->broadcast ++; // no such counter :-( */ - break; - - case PACKET_MULTICAST: - rx_stats->rx_multicast++; - break; - - case PACKET_OTHERHOST: - /* Our lower layer thinks this is not local, let's make - * sure. - * This allows the VLAN to have a different MAC than the - * underlying device, and still route correctly. - */ - if (!compare_ether_addr(eth_hdr(skb)->h_dest, - skb->dev->dev_addr)) - skb->pkt_type = PACKET_HOST; - break; - default: - break; - } - u64_stats_update_end(&rx_stats->syncp); - } - - skb_pull_rcsum(skb, VLAN_HLEN); - vlan_set_encap_proto(skb, vhdr); - - if (vlan_dev) { - skb = vlan_check_reorder_header(skb); - if (!skb) { - rx_stats->rx_errors++; - goto err_unlock; - } - } - - netif_rx(skb); - - rcu_read_unlock(); - return NET_RX_SUCCESS; - -err_unlock: - rcu_read_unlock(); -err_free: - atomic_long_inc(&dev->rx_dropped); - kfree_skb(skb); - return NET_RX_DROP; -} - static inline u16 vlan_dev_get_egress_qos_mask(struct net_device *dev, struct sk_buff *skb) { diff --git a/net/core/dev.c b/net/core/dev.c index 95897ff..d1aebf7 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -3130,6 +3130,12 @@ another_round: __this_cpu_inc(softnet_data.processed); + if (skb->protocol == cpu_to_be16(ETH_P_8021Q)) { + skb = vlan_untag(skb); + if (unlikely(!skb)) + goto out; + } + #ifdef CONFIG_NET_CLS_ACT if (skb->tc_verd & TC_NCLS) { skb->tc_verd = CLR_TC_NCLS(skb->tc_verd); @@ -3177,7 +3183,7 @@ ncls: ret = deliver_skb(skb, pt_prev, orig_dev); pt_prev = NULL; } - if (vlan_hwaccel_do_receive(&skb)) { + if (vlan_do_receive(&skb)) { ret = __netif_receive_skb(skb); goto out; } else if (unlikely(!skb)) -- cgit v0.10.2 From 872674858fe236b746317741013c830bb70775c2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Miros=C5=82aw?= Date: Tue, 12 Apr 2011 09:56:38 +0000 Subject: net: add RTNL_ASSERT in __netdev_update_features() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: MichaÅ‚ MirosÅ‚aw Signed-off-by: David S. Miller diff --git a/net/core/dev.c b/net/core/dev.c index d1aebf7..f523eee 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -5247,6 +5247,8 @@ int __netdev_update_features(struct net_device *dev) u32 features; int err = 0; + ASSERT_RTNL(); + features = netdev_get_wanted_features(dev); if (dev->netdev_ops->ndo_fix_features) -- cgit v0.10.2 From 0e08785845093ef4ed220463a739bc8d0db95de7 Mon Sep 17 00:00:00 2001 From: Patrick McHardy Date: Tue, 12 Apr 2011 05:39:51 +0000 Subject: connector: fix skb double free in cn_rx_skb() When a skb is delivered to a registered callback, cn_call_callback() incorrectly returns -ENODEV after freeing the skb, causing cn_rx_skb() to free the skb a second time. Reported-by: Eric B Munson Signed-off-by: Patrick McHardy Tested-by: Eric B Munson Signed-off-by: David S. Miller diff --git a/drivers/connector/connector.c b/drivers/connector/connector.c index d770058..219d88a 100644 --- a/drivers/connector/connector.c +++ b/drivers/connector/connector.c @@ -142,6 +142,7 @@ static int cn_call_callback(struct sk_buff *skb) cbq->callback(msg, nsp); kfree_skb(skb); cn_queue_release_callback(cbq); + err = 0; } return err; -- cgit v0.10.2 From f5d640371dacda100a32a30e8013f957aff26ce1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Miros=C5=82aw?= Date: Sun, 10 Apr 2011 03:13:21 +0000 Subject: net: sky2: convert to hw_features MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Caveats: - driver modifies vlan_features on HW VLAN TX changes - broken RX checksum will be reenabled on features change Signed-off-by: MichaÅ‚ MirosÅ‚aw Signed-off-by: David S. Miller diff --git a/drivers/net/sky2.c b/drivers/net/sky2.c index 336c762..a4b8fe5 100644 --- a/drivers/net/sky2.c +++ b/drivers/net/sky2.c @@ -1198,12 +1198,12 @@ static void rx_set_checksum(struct sky2_port *sky2) sky2_write32(sky2->hw, Q_ADDR(rxqaddr[sky2->port], Q_CSR), - (sky2->flags & SKY2_FLAG_RX_CHECKSUM) + (sky2->netdev->features & NETIF_F_RXCSUM) ? BMU_ENA_RX_CHKSUM : BMU_DIS_RX_CHKSUM); } /* Enable/disable receive hash calculation (RSS) */ -static void rx_set_rss(struct net_device *dev) +static void rx_set_rss(struct net_device *dev, u32 features) { struct sky2_port *sky2 = netdev_priv(dev); struct sky2_hw *hw = sky2->hw; @@ -1216,7 +1216,7 @@ static void rx_set_rss(struct net_device *dev) } /* Program RSS initial values */ - if (dev->features & NETIF_F_RXHASH) { + if (features & NETIF_F_RXHASH) { u32 key[nkeys]; get_random_bytes(key, nkeys * sizeof(u32)); @@ -1322,32 +1322,32 @@ static int sky2_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) return err; } -#define NETIF_F_ALL_VLAN (NETIF_F_HW_VLAN_TX|NETIF_F_HW_VLAN_RX) +#define SKY2_VLAN_OFFLOADS (NETIF_F_IP_CSUM | NETIF_F_SG | NETIF_F_TSO) -static void sky2_vlan_mode(struct net_device *dev) +static void sky2_vlan_mode(struct net_device *dev, u32 features) { struct sky2_port *sky2 = netdev_priv(dev); struct sky2_hw *hw = sky2->hw; u16 port = sky2->port; - if (dev->features & NETIF_F_HW_VLAN_RX) + if (features & NETIF_F_HW_VLAN_RX) sky2_write32(hw, SK_REG(port, RX_GMF_CTRL_T), RX_VLAN_STRIP_ON); else sky2_write32(hw, SK_REG(port, RX_GMF_CTRL_T), RX_VLAN_STRIP_OFF); - dev->vlan_features = dev->features &~ NETIF_F_ALL_VLAN; - if (dev->features & NETIF_F_HW_VLAN_TX) + if (features & NETIF_F_HW_VLAN_TX) { sky2_write32(hw, SK_REG(port, TX_GMF_CTRL_T), TX_VLAN_TAG_ON); - else { + + dev->vlan_features |= SKY2_VLAN_OFFLOADS; + } else { sky2_write32(hw, SK_REG(port, TX_GMF_CTRL_T), TX_VLAN_TAG_OFF); /* Can't do transmit offload of vlan without hw vlan */ - dev->vlan_features &= ~(NETIF_F_TSO | NETIF_F_SG - | NETIF_F_ALL_CSUM); + dev->vlan_features &= ~SKY2_VLAN_OFFLOADS; } } @@ -1463,7 +1463,7 @@ static void sky2_rx_start(struct sky2_port *sky2) rx_set_checksum(sky2); if (!(hw->flags & SKY2_HW_RSS_BROKEN)) - rx_set_rss(sky2->netdev); + rx_set_rss(sky2->netdev, sky2->netdev->features); /* submit Rx ring */ for (i = 0; i < sky2->rx_pending; i++) { @@ -1626,7 +1626,8 @@ static void sky2_hw_up(struct sky2_port *sky2) sky2_prefetch_init(hw, txqaddr[port], sky2->tx_le_map, sky2->tx_ring_size - 1); - sky2_vlan_mode(sky2->netdev); + sky2_vlan_mode(sky2->netdev, sky2->netdev->features); + netdev_update_features(sky2->netdev); sky2_rx_start(sky2); } @@ -2261,12 +2262,9 @@ static int sky2_change_mtu(struct net_device *dev, int new_mtu) hw->chip_id == CHIP_ID_YUKON_FE_P)) return -EINVAL; - /* TSO, etc on Yukon Ultra and MTU > 1500 not supported */ - if (new_mtu > ETH_DATA_LEN && hw->chip_id == CHIP_ID_YUKON_EC_U) - dev->features &= ~(NETIF_F_TSO|NETIF_F_SG|NETIF_F_ALL_CSUM); - if (!netif_running(dev)) { dev->mtu = new_mtu; + netdev_update_features(dev); return 0; } @@ -2288,6 +2286,7 @@ static int sky2_change_mtu(struct net_device *dev, int new_mtu) sky2_rx_clean(sky2); dev->mtu = new_mtu; + netdev_update_features(dev); mode = DATA_BLIND_VAL(DATA_BLIND_DEF) | GM_SMOD_VLAN_ENA | IPG_DATA_VAL(IPG_DATA_DEF); @@ -2535,8 +2534,11 @@ static void sky2_rx_checksum(struct sky2_port *sky2, u32 status) "%s: receive checksum problem (status = %#x)\n", sky2->netdev->name, status); - /* Disable checksum offload */ - sky2->flags &= ~SKY2_FLAG_RX_CHECKSUM; + /* Disable checksum offload + * It will be reenabled on next ndo_set_features, but if it's + * really broken, will get disabled again + */ + sky2->netdev->features &= ~NETIF_F_RXCSUM; sky2_write32(sky2->hw, Q_ADDR(rxqaddr[sky2->port], Q_CSR), BMU_DIS_RX_CHKSUM); } @@ -2591,7 +2593,7 @@ static int sky2_status_intr(struct sky2_hw *hw, int to_do, u16 idx) /* This chip reports checksum status differently */ if (hw->flags & SKY2_HW_NEW_LE) { - if ((sky2->flags & SKY2_FLAG_RX_CHECKSUM) && + if ((dev->features & NETIF_F_RXCSUM) && (le->css & (CSS_ISIPV4 | CSS_ISIPV6)) && (le->css & CSS_TCPUDPCSOK)) skb->ip_summed = CHECKSUM_UNNECESSARY; @@ -2616,7 +2618,7 @@ static int sky2_status_intr(struct sky2_hw *hw, int to_do, u16 idx) sky2->rx_tag = length; /* fall through */ case OP_RXCHKS: - if (likely(sky2->flags & SKY2_FLAG_RX_CHECKSUM)) + if (likely(dev->features & NETIF_F_RXCSUM)) sky2_rx_checksum(sky2, status); break; @@ -3552,28 +3554,6 @@ static const struct sky2_stat { { "tx_fifo_underrun", GM_TXE_FIFO_UR }, }; -static u32 sky2_get_rx_csum(struct net_device *dev) -{ - struct sky2_port *sky2 = netdev_priv(dev); - - return !!(sky2->flags & SKY2_FLAG_RX_CHECKSUM); -} - -static int sky2_set_rx_csum(struct net_device *dev, u32 data) -{ - struct sky2_port *sky2 = netdev_priv(dev); - - if (data) - sky2->flags |= SKY2_FLAG_RX_CHECKSUM; - else - sky2->flags &= ~SKY2_FLAG_RX_CHECKSUM; - - sky2_write32(sky2->hw, Q_ADDR(rxqaddr[sky2->port], Q_CSR), - data ? BMU_ENA_RX_CHKSUM : BMU_DIS_RX_CHKSUM); - - return 0; -} - static u32 sky2_get_msglevel(struct net_device *netdev) { struct sky2_port *sky2 = netdev_priv(netdev); @@ -4084,34 +4064,6 @@ static void sky2_get_regs(struct net_device *dev, struct ethtool_regs *regs, } } -/* In order to do Jumbo packets on these chips, need to turn off the - * transmit store/forward. Therefore checksum offload won't work. - */ -static int no_tx_offload(struct net_device *dev) -{ - const struct sky2_port *sky2 = netdev_priv(dev); - const struct sky2_hw *hw = sky2->hw; - - return dev->mtu > ETH_DATA_LEN && hw->chip_id == CHIP_ID_YUKON_EC_U; -} - -static int sky2_set_tx_csum(struct net_device *dev, u32 data) -{ - if (data && no_tx_offload(dev)) - return -EINVAL; - - return ethtool_op_set_tx_csum(dev, data); -} - - -static int sky2_set_tso(struct net_device *dev, u32 data) -{ - if (data && no_tx_offload(dev)) - return -EINVAL; - - return ethtool_op_set_tso(dev, data); -} - static int sky2_get_eeprom_len(struct net_device *dev) { struct sky2_port *sky2 = netdev_priv(dev); @@ -4214,31 +4166,36 @@ static int sky2_set_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom return sky2_vpd_write(sky2->hw, cap, data, eeprom->offset, eeprom->len); } -static int sky2_set_flags(struct net_device *dev, u32 data) +static u32 sky2_fix_features(struct net_device *dev, u32 features) { - struct sky2_port *sky2 = netdev_priv(dev); - unsigned long old_feat = dev->features; - u32 supported = 0; - int rc; + const struct sky2_port *sky2 = netdev_priv(dev); + const struct sky2_hw *hw = sky2->hw; - if (!(sky2->hw->flags & SKY2_HW_RSS_BROKEN)) - supported |= ETH_FLAG_RXHASH; + /* In order to do Jumbo packets on these chips, need to turn off the + * transmit store/forward. Therefore checksum offload won't work. + */ + if (dev->mtu > ETH_DATA_LEN && hw->chip_id == CHIP_ID_YUKON_EC_U) + features &= ~(NETIF_F_TSO|NETIF_F_SG|NETIF_F_ALL_CSUM); - if (!(sky2->hw->flags & SKY2_HW_VLAN_BROKEN)) - supported |= ETH_FLAG_RXVLAN | ETH_FLAG_TXVLAN; + return features; +} - printk(KERN_DEBUG "sky2 set_flags: supported %x data %x\n", - supported, data); +static int sky2_set_features(struct net_device *dev, u32 features) +{ + struct sky2_port *sky2 = netdev_priv(dev); + u32 changed = dev->features ^ features; - rc = ethtool_op_set_flags(dev, data, supported); - if (rc) - return rc; + if (changed & NETIF_F_RXCSUM) { + u32 on = features & NETIF_F_RXCSUM; + sky2_write32(sky2->hw, Q_ADDR(rxqaddr[sky2->port], Q_CSR), + on ? BMU_ENA_RX_CHKSUM : BMU_DIS_RX_CHKSUM); + } - if ((old_feat ^ dev->features) & NETIF_F_RXHASH) - rx_set_rss(dev); + if (changed & NETIF_F_RXHASH) + rx_set_rss(dev, features); - if ((old_feat ^ dev->features) & NETIF_F_ALL_VLAN) - sky2_vlan_mode(dev); + if (changed & (NETIF_F_HW_VLAN_TX|NETIF_F_HW_VLAN_RX)) + sky2_vlan_mode(dev, features); return 0; } @@ -4258,11 +4215,6 @@ static const struct ethtool_ops sky2_ethtool_ops = { .get_eeprom_len = sky2_get_eeprom_len, .get_eeprom = sky2_get_eeprom, .set_eeprom = sky2_set_eeprom, - .set_sg = ethtool_op_set_sg, - .set_tx_csum = sky2_set_tx_csum, - .set_tso = sky2_set_tso, - .get_rx_csum = sky2_get_rx_csum, - .set_rx_csum = sky2_set_rx_csum, .get_strings = sky2_get_strings, .get_coalesce = sky2_get_coalesce, .set_coalesce = sky2_set_coalesce, @@ -4273,8 +4225,6 @@ static const struct ethtool_ops sky2_ethtool_ops = { .set_phys_id = sky2_set_phys_id, .get_sset_count = sky2_get_sset_count, .get_ethtool_stats = sky2_get_ethtool_stats, - .set_flags = sky2_set_flags, - .get_flags = ethtool_op_get_flags, }; #ifdef CONFIG_SKY2_DEBUG @@ -4554,6 +4504,8 @@ static const struct net_device_ops sky2_netdev_ops[2] = { .ndo_set_mac_address = sky2_set_mac_address, .ndo_set_multicast_list = sky2_set_multicast, .ndo_change_mtu = sky2_change_mtu, + .ndo_fix_features = sky2_fix_features, + .ndo_set_features = sky2_set_features, .ndo_tx_timeout = sky2_tx_timeout, .ndo_get_stats64 = sky2_get_stats, #ifdef CONFIG_NET_POLL_CONTROLLER @@ -4569,6 +4521,8 @@ static const struct net_device_ops sky2_netdev_ops[2] = { .ndo_set_mac_address = sky2_set_mac_address, .ndo_set_multicast_list = sky2_set_multicast, .ndo_change_mtu = sky2_change_mtu, + .ndo_fix_features = sky2_fix_features, + .ndo_set_features = sky2_set_features, .ndo_tx_timeout = sky2_tx_timeout, .ndo_get_stats64 = sky2_get_stats, }, @@ -4601,7 +4555,7 @@ static __devinit struct net_device *sky2_init_netdev(struct sky2_hw *hw, /* Auto speed and flow control */ sky2->flags = SKY2_FLAG_AUTO_SPEED | SKY2_FLAG_AUTO_PAUSE; if (hw->chip_id != CHIP_ID_YUKON_XL) - sky2->flags |= SKY2_FLAG_RX_CHECKSUM; + dev->hw_features |= NETIF_F_RXCSUM; sky2->flow_mode = FC_BOTH; @@ -4620,18 +4574,21 @@ static __devinit struct net_device *sky2_init_netdev(struct sky2_hw *hw, sky2->port = port; - dev->features |= NETIF_F_IP_CSUM | NETIF_F_SG - | NETIF_F_TSO | NETIF_F_GRO; + dev->hw_features |= NETIF_F_IP_CSUM | NETIF_F_SG | NETIF_F_TSO; if (highmem) dev->features |= NETIF_F_HIGHDMA; /* Enable receive hashing unless hardware is known broken */ if (!(hw->flags & SKY2_HW_RSS_BROKEN)) - dev->features |= NETIF_F_RXHASH; + dev->hw_features |= NETIF_F_RXHASH; + + if (!(hw->flags & SKY2_HW_VLAN_BROKEN)) { + dev->hw_features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX; + dev->vlan_features |= SKY2_VLAN_OFFLOADS; + } - if (!(hw->flags & SKY2_HW_VLAN_BROKEN)) - dev->features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX; + dev->features |= dev->hw_features; /* read the mac address */ memcpy_fromio(dev->dev_addr, hw->regs + B2_MAC_1 + port * 8, ETH_ALEN); diff --git a/drivers/net/sky2.h b/drivers/net/sky2.h index 0c6d10c..318c9ae 100644 --- a/drivers/net/sky2.h +++ b/drivers/net/sky2.h @@ -2254,7 +2254,6 @@ struct sky2_port { u8 wol; /* WAKE_ bits */ u8 duplex; /* DUPLEX_HALF, DUPLEX_FULL */ u16 flags; -#define SKY2_FLAG_RX_CHECKSUM 0x0001 #define SKY2_FLAG_AUTO_SPEED 0x0002 #define SKY2_FLAG_AUTO_PAUSE 0x0004 -- cgit v0.10.2 From d1423c7ab847e72a63e0e3512a1a7f3bce55ae01 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Miros=C5=82aw?= Date: Sun, 10 Apr 2011 04:49:55 +0000 Subject: net: ps3_gelic: convert to hw_features MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: MichaÅ‚ MirosÅ‚aw Signed-off-by: David S. Miller diff --git a/drivers/net/ps3_gelic_net.c b/drivers/net/ps3_gelic_net.c index ffdf734..4383ed2 100644 --- a/drivers/net/ps3_gelic_net.c +++ b/drivers/net/ps3_gelic_net.c @@ -951,7 +951,7 @@ static void gelic_net_pass_skb_up(struct gelic_descr *descr, skb->protocol = eth_type_trans(skb, netdev); /* checksum offload */ - if (card->rx_csum) { + if (netdev->features & NETIF_F_RXCSUM) { if ((data_status & GELIC_DESCR_DATA_STATUS_CHK_MASK) && (!(data_error & GELIC_DESCR_DATA_ERROR_CHK_MASK))) skb->ip_summed = CHECKSUM_UNNECESSARY; @@ -1312,21 +1312,6 @@ static int gelic_ether_set_settings(struct net_device *netdev, return 0; } -u32 gelic_net_get_rx_csum(struct net_device *netdev) -{ - struct gelic_card *card = netdev_card(netdev); - - return card->rx_csum; -} - -int gelic_net_set_rx_csum(struct net_device *netdev, u32 data) -{ - struct gelic_card *card = netdev_card(netdev); - - card->rx_csum = data; - return 0; -} - static void gelic_net_get_wol(struct net_device *netdev, struct ethtool_wolinfo *wol) { @@ -1411,10 +1396,6 @@ static const struct ethtool_ops gelic_ether_ethtool_ops = { .get_settings = gelic_ether_get_settings, .set_settings = gelic_ether_set_settings, .get_link = ethtool_op_get_link, - .get_tx_csum = ethtool_op_get_tx_csum, - .set_tx_csum = ethtool_op_set_tx_csum, - .get_rx_csum = gelic_net_get_rx_csum, - .set_rx_csum = gelic_net_set_rx_csum, .get_wol = gelic_net_get_wol, .set_wol = gelic_net_set_wol, }; @@ -1512,7 +1493,11 @@ int __devinit gelic_net_setup_netdev(struct net_device *netdev, int status; u64 v1, v2; + netdev->hw_features = NETIF_F_IP_CSUM | NETIF_F_RXCSUM; + netdev->features = NETIF_F_IP_CSUM; + if (GELIC_CARD_RX_CSUM_DEFAULT) + netdev->features |= NETIF_F_RXCSUM; status = lv1_net_control(bus_id(card), dev_id(card), GELIC_LV1_GET_MAC_ADDRESS, @@ -1756,7 +1741,6 @@ static int __devinit ps3_gelic_driver_probe(struct ps3_system_bus_device *dev) /* setup card structure */ card->irq_mask = GELIC_CARD_RXINT | GELIC_CARD_TXINT | GELIC_CARD_PORT_STATUS_CHANGED; - card->rx_csum = GELIC_CARD_RX_CSUM_DEFAULT; if (gelic_card_init_chain(card, &card->tx_chain, diff --git a/drivers/net/ps3_gelic_net.h b/drivers/net/ps3_gelic_net.h index fadadf9..d9a55b9 100644 --- a/drivers/net/ps3_gelic_net.h +++ b/drivers/net/ps3_gelic_net.h @@ -290,7 +290,6 @@ struct gelic_card { struct gelic_descr_chain tx_chain; struct gelic_descr_chain rx_chain; int rx_dma_restart_required; - int rx_csum; /* * tx_lock guards tx descriptor list and * tx_dma_progress. @@ -377,8 +376,6 @@ extern int gelic_net_setup_netdev(struct net_device *netdev, /* shared ethtool ops */ extern void gelic_net_get_drvinfo(struct net_device *netdev, struct ethtool_drvinfo *info); -extern u32 gelic_net_get_rx_csum(struct net_device *netdev); -extern int gelic_net_set_rx_csum(struct net_device *netdev, u32 data); extern void gelic_net_poll_controller(struct net_device *netdev); #endif /* _GELIC_NET_H */ diff --git a/drivers/net/ps3_gelic_wireless.c b/drivers/net/ps3_gelic_wireless.c index b5ae29d..2e62938 100644 --- a/drivers/net/ps3_gelic_wireless.c +++ b/drivers/net/ps3_gelic_wireless.c @@ -2581,10 +2581,6 @@ static const struct net_device_ops gelic_wl_netdevice_ops = { static const struct ethtool_ops gelic_wl_ethtool_ops = { .get_drvinfo = gelic_net_get_drvinfo, .get_link = gelic_wl_get_link, - .get_tx_csum = ethtool_op_get_tx_csum, - .set_tx_csum = ethtool_op_set_tx_csum, - .get_rx_csum = gelic_net_get_rx_csum, - .set_rx_csum = gelic_net_set_rx_csum, }; static void __devinit gelic_wl_setup_netdev_ops(struct net_device *netdev) -- cgit v0.10.2 From e5ee20e70f078d584572709962f5d90f876912c3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Miros=C5=82aw?= Date: Tue, 12 Apr 2011 09:38:23 +0000 Subject: net: bna: convert to hw_features MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Note: looks like bnad->conf_mutex is duplicating rtnl_lock. Signed-off-by: MichaÅ‚ MirosÅ‚aw Signed-off-by: David S. Miller diff --git a/drivers/net/bna/bnad.c b/drivers/net/bna/bnad.c index 9f356d5..b9f2534 100644 --- a/drivers/net/bna/bnad.c +++ b/drivers/net/bna/bnad.c @@ -501,7 +501,7 @@ bnad_poll_cq(struct bnad *bnad, struct bna_ccb *ccb, int budget) skb_put(skb, ntohs(cmpl->length)); if (likely - (bnad->rx_csum && + ((bnad->netdev->features & NETIF_F_RXCSUM) && (((flags & BNA_CQ_EF_IPV4) && (flags & BNA_CQ_EF_L3_CKSUM_OK)) || (flags & BNA_CQ_EF_IPV6)) && @@ -2903,23 +2903,20 @@ bnad_netdev_init(struct bnad *bnad, bool using_dac) { struct net_device *netdev = bnad->netdev; - netdev->features |= NETIF_F_IPV6_CSUM; - netdev->features |= NETIF_F_TSO; - netdev->features |= NETIF_F_TSO6; + netdev->hw_features = NETIF_F_SG | NETIF_F_RXCSUM | + NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM | + NETIF_F_TSO | NETIF_F_TSO6 | NETIF_F_HW_VLAN_TX; - netdev->features |= NETIF_F_GRO; - pr_warn("bna: GRO enabled, using kernel stack GRO\n"); + netdev->vlan_features = NETIF_F_SG | NETIF_F_HIGHDMA | + NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM | + NETIF_F_TSO | NETIF_F_TSO6; - netdev->features |= NETIF_F_SG | NETIF_F_IP_CSUM; + netdev->features |= netdev->hw_features | + NETIF_F_HW_VLAN_RX | NETIF_F_HW_VLAN_FILTER; if (using_dac) netdev->features |= NETIF_F_HIGHDMA; - netdev->features |= - NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX | - NETIF_F_HW_VLAN_FILTER; - - netdev->vlan_features = netdev->features; netdev->mem_start = bnad->mmio_start; netdev->mem_end = bnad->mmio_start + bnad->mmio_len - 1; @@ -2970,7 +2967,6 @@ bnad_init(struct bnad *bnad, bnad->txq_depth = BNAD_TXQ_DEPTH; bnad->rxq_depth = BNAD_RXQ_DEPTH; - bnad->rx_csum = true; bnad->tx_coalescing_timeo = BFI_TX_COALESCING_TIMEO; bnad->rx_coalescing_timeo = BFI_RX_COALESCING_TIMEO; diff --git a/drivers/net/bna/bnad.h b/drivers/net/bna/bnad.h index a89117f..ccdabad 100644 --- a/drivers/net/bna/bnad.h +++ b/drivers/net/bna/bnad.h @@ -237,8 +237,6 @@ struct bnad { struct bna_rx_config rx_config[BNAD_MAX_RXS]; struct bna_tx_config tx_config[BNAD_MAX_TXS]; - u32 rx_csum; - void __iomem *bar0; /* BAR0 address */ struct bna bna; diff --git a/drivers/net/bna/bnad_ethtool.c b/drivers/net/bna/bnad_ethtool.c index 142d604..c51e078e 100644 --- a/drivers/net/bna/bnad_ethtool.c +++ b/drivers/net/bna/bnad_ethtool.c @@ -806,61 +806,6 @@ bnad_set_pauseparam(struct net_device *netdev, return 0; } -static u32 -bnad_get_rx_csum(struct net_device *netdev) -{ - u32 rx_csum; - struct bnad *bnad = netdev_priv(netdev); - - rx_csum = bnad->rx_csum; - return rx_csum; -} - -static int -bnad_set_rx_csum(struct net_device *netdev, u32 rx_csum) -{ - struct bnad *bnad = netdev_priv(netdev); - - mutex_lock(&bnad->conf_mutex); - bnad->rx_csum = rx_csum; - mutex_unlock(&bnad->conf_mutex); - return 0; -} - -static int -bnad_set_tx_csum(struct net_device *netdev, u32 tx_csum) -{ - struct bnad *bnad = netdev_priv(netdev); - - mutex_lock(&bnad->conf_mutex); - if (tx_csum) { - netdev->features |= NETIF_F_IP_CSUM; - netdev->features |= NETIF_F_IPV6_CSUM; - } else { - netdev->features &= ~NETIF_F_IP_CSUM; - netdev->features &= ~NETIF_F_IPV6_CSUM; - } - mutex_unlock(&bnad->conf_mutex); - return 0; -} - -static int -bnad_set_tso(struct net_device *netdev, u32 tso) -{ - struct bnad *bnad = netdev_priv(netdev); - - mutex_lock(&bnad->conf_mutex); - if (tso) { - netdev->features |= NETIF_F_TSO; - netdev->features |= NETIF_F_TSO6; - } else { - netdev->features &= ~NETIF_F_TSO; - netdev->features &= ~NETIF_F_TSO6; - } - mutex_unlock(&bnad->conf_mutex); - return 0; -} - static void bnad_get_strings(struct net_device *netdev, u32 stringset, u8 * string) { @@ -1256,14 +1201,6 @@ static struct ethtool_ops bnad_ethtool_ops = { .set_ringparam = bnad_set_ringparam, .get_pauseparam = bnad_get_pauseparam, .set_pauseparam = bnad_set_pauseparam, - .get_rx_csum = bnad_get_rx_csum, - .set_rx_csum = bnad_set_rx_csum, - .get_tx_csum = ethtool_op_get_tx_csum, - .set_tx_csum = bnad_set_tx_csum, - .get_sg = ethtool_op_get_sg, - .set_sg = ethtool_op_set_sg, - .get_tso = ethtool_op_get_tso, - .set_tso = bnad_set_tso, .get_strings = bnad_get_strings, .get_ethtool_stats = bnad_get_ethtool_stats, .get_sset_count = bnad_get_sset_count -- cgit v0.10.2 From 66371c44136b566f39f70c72cb4d117558bee3fa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Miros=C5=82aw?= Date: Tue, 12 Apr 2011 09:38:23 +0000 Subject: net: bnx2x: convert to hw_features MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Since ndo_fix_features callback is postponing features change when bp->recovery_state != BNX2X_RECOVERY_DONE, netdev_update_features() has to be called again when this condition changes. Previously, ethtool_ops->set_flags callback returned -EBUSY in that case (it's not possible in the new model). Signed-off-by: MichaÅ‚ MirosÅ‚aw v5: - don't delay set_features, as it's rtnl_locked - same as recovery process v4: - complete bp->rx_csum -> NETIF_F_RXCSUM conversion - add check for failed ndo_set_features in ndo_open callback v3: - include NETIF_F_LRO in hw_features - don't call netdev_update_features() if bnx2x_nic_load() failed v2: - comment in ndo_fix_features callback Signed-off-by: David S. Miller diff --git a/drivers/net/bnx2x/bnx2x.h b/drivers/net/bnx2x/bnx2x.h index e0fca70..9e87417 100644 --- a/drivers/net/bnx2x/bnx2x.h +++ b/drivers/net/bnx2x/bnx2x.h @@ -918,7 +918,6 @@ struct bnx2x { int tx_ring_size; - u32 rx_csum; /* L2 header size + 2*VLANs (8 bytes) + LLC SNAP (8 bytes) */ #define ETH_OVREHEAD (ETH_HLEN + 8 + 8) #define ETH_MIN_PACKET_SIZE 60 diff --git a/drivers/net/bnx2x/bnx2x_cmn.c b/drivers/net/bnx2x/bnx2x_cmn.c index e83ac6d..bec33a8 100644 --- a/drivers/net/bnx2x/bnx2x_cmn.c +++ b/drivers/net/bnx2x/bnx2x_cmn.c @@ -640,7 +640,7 @@ reuse_rx: skb_checksum_none_assert(skb); - if (bp->rx_csum) { + if (bp->dev->features & NETIF_F_RXCSUM) { if (likely(BNX2X_RX_CSUM_OK(cqe))) skb->ip_summed = CHECKSUM_UNNECESSARY; else @@ -2443,11 +2443,21 @@ alloc_err: } +static int bnx2x_reload_if_running(struct net_device *dev) +{ + struct bnx2x *bp = netdev_priv(dev); + + if (unlikely(!netif_running(dev))) + return 0; + + bnx2x_nic_unload(bp, UNLOAD_NORMAL); + return bnx2x_nic_load(bp, LOAD_NORMAL); +} + /* called with rtnl_lock */ int bnx2x_change_mtu(struct net_device *dev, int new_mtu) { struct bnx2x *bp = netdev_priv(dev); - int rc = 0; if (bp->recovery_state != BNX2X_RECOVERY_DONE) { printk(KERN_ERR "Handling parity error recovery. Try again later\n"); @@ -2464,12 +2474,39 @@ int bnx2x_change_mtu(struct net_device *dev, int new_mtu) */ dev->mtu = new_mtu; - if (netif_running(dev)) { - bnx2x_nic_unload(bp, UNLOAD_NORMAL); - rc = bnx2x_nic_load(bp, LOAD_NORMAL); + return bnx2x_reload_if_running(dev); +} + +u32 bnx2x_fix_features(struct net_device *dev, u32 features) +{ + struct bnx2x *bp = netdev_priv(dev); + + /* TPA requires Rx CSUM offloading */ + if (!(features & NETIF_F_RXCSUM) || bp->disable_tpa) + features &= ~NETIF_F_LRO; + + return features; +} + +int bnx2x_set_features(struct net_device *dev, u32 features) +{ + struct bnx2x *bp = netdev_priv(dev); + u32 flags = bp->flags; + + if (features & NETIF_F_LRO) + flags |= TPA_ENABLE_FLAG; + else + flags &= ~TPA_ENABLE_FLAG; + + if (flags ^ bp->flags) { + bp->flags = flags; + + if (bp->recovery_state == BNX2X_RECOVERY_DONE) + return bnx2x_reload_if_running(dev); + /* else: bnx2x_nic_load() will be called at end of recovery */ } - return rc; + return 0; } void bnx2x_tx_timeout(struct net_device *dev) diff --git a/drivers/net/bnx2x/bnx2x_cmn.h b/drivers/net/bnx2x/bnx2x_cmn.h index 775fef0..1cdab69 100644 --- a/drivers/net/bnx2x/bnx2x_cmn.h +++ b/drivers/net/bnx2x/bnx2x_cmn.h @@ -431,6 +431,9 @@ void bnx2x_free_mem_bp(struct bnx2x *bp); */ int bnx2x_change_mtu(struct net_device *dev, int new_mtu); +u32 bnx2x_fix_features(struct net_device *dev, u32 features); +int bnx2x_set_features(struct net_device *dev, u32 features); + /** * tx timeout netdev callback * diff --git a/drivers/net/bnx2x/bnx2x_ethtool.c b/drivers/net/bnx2x/bnx2x_ethtool.c index 1479994..ad7d91e 100644 --- a/drivers/net/bnx2x/bnx2x_ethtool.c +++ b/drivers/net/bnx2x/bnx2x_ethtool.c @@ -1299,91 +1299,6 @@ static int bnx2x_set_pauseparam(struct net_device *dev, return 0; } -static int bnx2x_set_flags(struct net_device *dev, u32 data) -{ - struct bnx2x *bp = netdev_priv(dev); - int changed = 0; - int rc = 0; - - if (bp->recovery_state != BNX2X_RECOVERY_DONE) { - printk(KERN_ERR "Handling parity error recovery. Try again later\n"); - return -EAGAIN; - } - - if (!(data & ETH_FLAG_RXVLAN)) - return -EINVAL; - - if ((data & ETH_FLAG_LRO) && bp->rx_csum && bp->disable_tpa) - return -EINVAL; - - rc = ethtool_op_set_flags(dev, data, ETH_FLAG_LRO | ETH_FLAG_RXVLAN | - ETH_FLAG_TXVLAN | ETH_FLAG_RXHASH); - if (rc) - return rc; - - /* TPA requires Rx CSUM offloading */ - if ((data & ETH_FLAG_LRO) && bp->rx_csum) { - if (!(bp->flags & TPA_ENABLE_FLAG)) { - bp->flags |= TPA_ENABLE_FLAG; - changed = 1; - } - } else if (bp->flags & TPA_ENABLE_FLAG) { - dev->features &= ~NETIF_F_LRO; - bp->flags &= ~TPA_ENABLE_FLAG; - changed = 1; - } - - if (changed && netif_running(dev)) { - bnx2x_nic_unload(bp, UNLOAD_NORMAL); - rc = bnx2x_nic_load(bp, LOAD_NORMAL); - } - - return rc; -} - -static u32 bnx2x_get_rx_csum(struct net_device *dev) -{ - struct bnx2x *bp = netdev_priv(dev); - - return bp->rx_csum; -} - -static int bnx2x_set_rx_csum(struct net_device *dev, u32 data) -{ - struct bnx2x *bp = netdev_priv(dev); - int rc = 0; - - if (bp->recovery_state != BNX2X_RECOVERY_DONE) { - printk(KERN_ERR "Handling parity error recovery. Try again later\n"); - return -EAGAIN; - } - - bp->rx_csum = data; - - /* Disable TPA, when Rx CSUM is disabled. Otherwise all - TPA'ed packets will be discarded due to wrong TCP CSUM */ - if (!data) { - u32 flags = ethtool_op_get_flags(dev); - - rc = bnx2x_set_flags(dev, (flags & ~ETH_FLAG_LRO)); - } - - return rc; -} - -static int bnx2x_set_tso(struct net_device *dev, u32 data) -{ - if (data) { - dev->features |= (NETIF_F_TSO | NETIF_F_TSO_ECN); - dev->features |= NETIF_F_TSO6; - } else { - dev->features &= ~(NETIF_F_TSO | NETIF_F_TSO_ECN); - dev->features &= ~NETIF_F_TSO6; - } - - return 0; -} - static const struct { char string[ETH_GSTRING_LEN]; } bnx2x_tests_str_arr[BNX2X_NUM_TESTS] = { @@ -2207,16 +2122,6 @@ static const struct ethtool_ops bnx2x_ethtool_ops = { .set_ringparam = bnx2x_set_ringparam, .get_pauseparam = bnx2x_get_pauseparam, .set_pauseparam = bnx2x_set_pauseparam, - .get_rx_csum = bnx2x_get_rx_csum, - .set_rx_csum = bnx2x_set_rx_csum, - .get_tx_csum = ethtool_op_get_tx_csum, - .set_tx_csum = ethtool_op_set_tx_hw_csum, - .set_flags = bnx2x_set_flags, - .get_flags = ethtool_op_get_flags, - .get_sg = ethtool_op_get_sg, - .set_sg = ethtool_op_set_sg, - .get_tso = ethtool_op_get_tso, - .set_tso = bnx2x_set_tso, .self_test = bnx2x_self_test, .get_sset_count = bnx2x_get_sset_count, .get_strings = bnx2x_get_strings, diff --git a/drivers/net/bnx2x/bnx2x_main.c b/drivers/net/bnx2x/bnx2x_main.c index a6915aa..696e84a 100644 --- a/drivers/net/bnx2x/bnx2x_main.c +++ b/drivers/net/bnx2x/bnx2x_main.c @@ -8904,8 +8904,6 @@ static int __devinit bnx2x_init_bp(struct bnx2x *bp) bp->multi_mode = multi_mode; bp->int_mode = int_mode; - bp->dev->features |= NETIF_F_GRO; - /* Set TPA flags */ if (disable_tpa) { bp->flags &= ~TPA_ENABLE_FLAG; @@ -8925,8 +8923,6 @@ static int __devinit bnx2x_init_bp(struct bnx2x *bp) bp->tx_ring_size = MAX_TX_AVAIL; - bp->rx_csum = 1; - /* make sure that the numbers are in the right granularity */ bp->tx_ticks = (50 / BNX2X_BTR) * BNX2X_BTR; bp->rx_ticks = (25 / BNX2X_BTR) * BNX2X_BTR; @@ -9304,6 +9300,8 @@ static const struct net_device_ops bnx2x_netdev_ops = { .ndo_validate_addr = eth_validate_addr, .ndo_do_ioctl = bnx2x_ioctl, .ndo_change_mtu = bnx2x_change_mtu, + .ndo_fix_features = bnx2x_fix_features, + .ndo_set_features = bnx2x_set_features, .ndo_tx_timeout = bnx2x_tx_timeout, #ifdef CONFIG_NET_POLL_CONTROLLER .ndo_poll_controller = poll_bnx2x, @@ -9430,20 +9428,17 @@ static int __devinit bnx2x_init_dev(struct pci_dev *pdev, dev->netdev_ops = &bnx2x_netdev_ops; bnx2x_set_ethtool_ops(dev); - dev->features |= NETIF_F_SG; - dev->features |= NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM; - if (bp->flags & USING_DAC_FLAG) - dev->features |= NETIF_F_HIGHDMA; - dev->features |= (NETIF_F_TSO | NETIF_F_TSO_ECN); - dev->features |= NETIF_F_TSO6; - dev->features |= (NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX); - dev->vlan_features |= NETIF_F_SG; - dev->vlan_features |= NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM; + dev->hw_features = NETIF_F_SG | NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM | + NETIF_F_TSO | NETIF_F_TSO_ECN | NETIF_F_TSO6 | + NETIF_F_RXCSUM | NETIF_F_LRO | NETIF_F_HW_VLAN_TX; + + dev->vlan_features = NETIF_F_SG | NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM | + NETIF_F_TSO | NETIF_F_TSO_ECN | NETIF_F_TSO6 | NETIF_F_HIGHDMA; + + dev->features |= dev->hw_features | NETIF_F_HW_VLAN_RX; if (bp->flags & USING_DAC_FLAG) - dev->vlan_features |= NETIF_F_HIGHDMA; - dev->vlan_features |= (NETIF_F_TSO | NETIF_F_TSO_ECN); - dev->vlan_features |= NETIF_F_TSO6; + dev->features |= NETIF_F_HIGHDMA; #ifdef BCM_DCBNL dev->dcbnl_ops = &bnx2x_dcbnl_ops; -- cgit v0.10.2 From 6d95ff974a4b51121777973ffba7547c648da974 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Miros=C5=82aw?= Date: Tue, 12 Apr 2011 09:48:17 +0000 Subject: net: ioc3: convert to hw_features MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: MichaÅ‚ MirosÅ‚aw Signed-off-by: David S. Miller diff --git a/drivers/net/ioc3-eth.c b/drivers/net/ioc3-eth.c index c8ee8d2..96c9561 100644 --- a/drivers/net/ioc3-eth.c +++ b/drivers/net/ioc3-eth.c @@ -90,8 +90,6 @@ struct ioc3_private { u32 emcr, ehar_h, ehar_l; spinlock_t ioc3_lock; struct mii_if_info mii; - unsigned long flags; -#define IOC3_FLAG_RX_CHECKSUMS 1 struct pci_dev *pdev; @@ -609,7 +607,7 @@ static inline void ioc3_rx(struct net_device *dev) goto next; } - if (likely(ip->flags & IOC3_FLAG_RX_CHECKSUMS)) + if (likely(dev->features & NETIF_F_RXCSUM)) ioc3_tcpudp_checksum(skb, w0 & ERXBUF_IPCKSUM_MASK, len); @@ -1328,6 +1326,7 @@ static int __devinit ioc3_probe(struct pci_dev *pdev, dev->watchdog_timeo = 5 * HZ; dev->netdev_ops = &ioc3_netdev_ops; dev->ethtool_ops = &ioc3_ethtool_ops; + dev->hw_features = NETIF_F_IP_CSUM | NETIF_F_RXCSUM; dev->features = NETIF_F_IP_CSUM; sw_physid1 = ioc3_mdio_read(dev, ip->mii.phy_id, MII_PHYSID1); @@ -1618,37 +1617,12 @@ static u32 ioc3_get_link(struct net_device *dev) return rc; } -static u32 ioc3_get_rx_csum(struct net_device *dev) -{ - struct ioc3_private *ip = netdev_priv(dev); - - return ip->flags & IOC3_FLAG_RX_CHECKSUMS; -} - -static int ioc3_set_rx_csum(struct net_device *dev, u32 data) -{ - struct ioc3_private *ip = netdev_priv(dev); - - spin_lock_bh(&ip->ioc3_lock); - if (data) - ip->flags |= IOC3_FLAG_RX_CHECKSUMS; - else - ip->flags &= ~IOC3_FLAG_RX_CHECKSUMS; - spin_unlock_bh(&ip->ioc3_lock); - - return 0; -} - static const struct ethtool_ops ioc3_ethtool_ops = { .get_drvinfo = ioc3_get_drvinfo, .get_settings = ioc3_get_settings, .set_settings = ioc3_set_settings, .nway_reset = ioc3_nway_reset, .get_link = ioc3_get_link, - .get_rx_csum = ioc3_get_rx_csum, - .set_rx_csum = ioc3_set_rx_csum, - .get_tx_csum = ethtool_op_get_tx_csum, - .set_tx_csum = ethtool_op_set_tx_csum }; static int ioc3_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) -- cgit v0.10.2 From 1aac62671686e6234c91b5f6fc4caaa850419d5d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Miros=C5=82aw?= Date: Tue, 12 Apr 2011 04:07:39 +0000 Subject: net: vlan_features comment clarification MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: MichaÅ‚ MirosÅ‚aw Signed-off-by: David S. Miller diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index 09d2624..cb8178a 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -1035,7 +1035,7 @@ struct net_device { u32 hw_features; /* user-requested features */ u32 wanted_features; - /* VLAN feature mask */ + /* mask of features inheritable by VLAN devices */ u32 vlan_features; /* Net device feature bits; if you change something, -- cgit v0.10.2 From efa2ad8918afc2f5e4ea533110758b26991f1937 Mon Sep 17 00:00:00 2001 From: Otavio Salvador Date: Tue, 12 Apr 2011 05:30:40 +0000 Subject: net/sis900: store MAC into perm_addr for SiS 900, 630E, 635 and 96x variants Signed-off-by: Otavio Salvador Signed-off-by: David S. Miller diff --git a/drivers/net/sis900.c b/drivers/net/sis900.c index cb317cd..484f795 100644 --- a/drivers/net/sis900.c +++ b/drivers/net/sis900.c @@ -240,7 +240,8 @@ static const struct ethtool_ops sis900_ethtool_ops; * @net_dev: the net device to get address for * * Older SiS900 and friends, use EEPROM to store MAC address. - * MAC address is read from read_eeprom() into @net_dev->dev_addr. + * MAC address is read from read_eeprom() into @net_dev->dev_addr and + * @net_dev->perm_addr. */ static int __devinit sis900_get_mac_addr(struct pci_dev * pci_dev, struct net_device *net_dev) @@ -261,6 +262,9 @@ static int __devinit sis900_get_mac_addr(struct pci_dev * pci_dev, struct net_de for (i = 0; i < 3; i++) ((u16 *)(net_dev->dev_addr))[i] = read_eeprom(ioaddr, i+EEPROMMACAddr); + /* Store MAC Address in perm_addr */ + memcpy(net_dev->perm_addr, net_dev->dev_addr, ETH_ALEN); + return 1; } @@ -271,7 +275,8 @@ static int __devinit sis900_get_mac_addr(struct pci_dev * pci_dev, struct net_de * * SiS630E model, use APC CMOS RAM to store MAC address. * APC CMOS RAM is accessed through ISA bridge. - * MAC address is read into @net_dev->dev_addr. + * MAC address is read into @net_dev->dev_addr and + * @net_dev->perm_addr. */ static int __devinit sis630e_get_mac_addr(struct pci_dev * pci_dev, @@ -296,6 +301,10 @@ static int __devinit sis630e_get_mac_addr(struct pci_dev * pci_dev, outb(0x09 + i, 0x70); ((u8 *)(net_dev->dev_addr))[i] = inb(0x71); } + + /* Store MAC Address in perm_addr */ + memcpy(net_dev->perm_addr, net_dev->dev_addr, ETH_ALEN); + pci_write_config_byte(isa_bridge, 0x48, reg & ~0x40); pci_dev_put(isa_bridge); @@ -310,7 +319,7 @@ static int __devinit sis630e_get_mac_addr(struct pci_dev * pci_dev, * * SiS635 model, set MAC Reload Bit to load Mac address from APC * to rfdr. rfdr is accessed through rfcr. MAC address is read into - * @net_dev->dev_addr. + * @net_dev->dev_addr and @net_dev->perm_addr. */ static int __devinit sis635_get_mac_addr(struct pci_dev * pci_dev, @@ -334,6 +343,9 @@ static int __devinit sis635_get_mac_addr(struct pci_dev * pci_dev, *( ((u16 *)net_dev->dev_addr) + i) = inw(ioaddr + rfdr); } + /* Store MAC Address in perm_addr */ + memcpy(net_dev->perm_addr, net_dev->dev_addr, ETH_ALEN); + /* enable packet filtering */ outl(rfcrSave | RFEN, rfcr + ioaddr); @@ -353,7 +365,7 @@ static int __devinit sis635_get_mac_addr(struct pci_dev * pci_dev, * EEDONE signal to refuse EEPROM access by LAN. * The EEPROM map of SiS962 or SiS963 is different to SiS900. * The signature field in SiS962 or SiS963 spec is meaningless. - * MAC address is read into @net_dev->dev_addr. + * MAC address is read into @net_dev->dev_addr and @net_dev->perm_addr. */ static int __devinit sis96x_get_mac_addr(struct pci_dev * pci_dev, @@ -372,6 +384,9 @@ static int __devinit sis96x_get_mac_addr(struct pci_dev * pci_dev, for (i = 0; i < 3; i++) ((u16 *)(net_dev->dev_addr))[i] = read_eeprom(ioaddr, i+EEPROMMACAddr); + /* Store MAC Address in perm_addr */ + memcpy(net_dev->perm_addr, net_dev->dev_addr, ETH_ALEN); + outl(EEDONE, ee_addr); return 1; } else { -- cgit v0.10.2 From 3d894a9c1959acaa6981283619b465f75f7e535e Mon Sep 17 00:00:00 2001 From: Otavio Salvador Date: Tue, 12 Apr 2011 05:30:41 +0000 Subject: net/natsami: store MAC into perm_addr Signed-off-by: Otavio Salvador Signed-off-by: David S. Miller diff --git a/drivers/net/natsemi.c b/drivers/net/natsemi.c index aa2813e..1074231 100644 --- a/drivers/net/natsemi.c +++ b/drivers/net/natsemi.c @@ -860,6 +860,9 @@ static int __devinit natsemi_probe1 (struct pci_dev *pdev, prev_eedata = eedata; } + /* Store MAC Address in perm_addr */ + memcpy(dev->perm_addr, dev->dev_addr, ETH_ALEN); + dev->base_addr = (unsigned long __force) ioaddr; dev->irq = irq; -- cgit v0.10.2 From 020318d0d2af51e0fd59ba654ede9b2171558720 Mon Sep 17 00:00:00 2001 From: Dave Jones Date: Tue, 12 Apr 2011 15:29:54 -0700 Subject: irda: fix locking unbalance in irda_sendmsg 5b40964eadea40509d353318d2c82e8b7bf5e8a5 ("irda: Remove BKL instances from af_irda.c") introduced a path where we have a locking unbalance. If we pass invalid flags, we unlock a socket we never locked, resulting in this... ===================================== [ BUG: bad unlock balance detected! ] ------------------------------------- trinity/20101 is trying to release lock (sk_lock-AF_IRDA) at: [] irda_sendmsg+0x207/0x21d [irda] but there are no more locks to release! other info that might help us debug this: no locks held by trinity/20101. stack backtrace: Pid: 20101, comm: trinity Not tainted 2.6.39-rc3+ #3 Call Trace: [] ? irda_sendmsg+0x207/0x21d [irda] [] print_unlock_inbalance_bug+0xc7/0xd2 [] ? irda_sendmsg+0x207/0x21d [irda] [] lock_release+0xcf/0x18e [] release_sock+0x2d/0x155 [] irda_sendmsg+0x207/0x21d [irda] [] __sock_sendmsg+0x69/0x75 [] sock_sendmsg+0xa1/0xb6 [] ? might_fault+0x5c/0xac [] ? lock_release+0x181/0x18e [] ? might_fault+0xa5/0xac [] ? might_fault+0x5c/0xac [] ? fcheck_files+0xb9/0xf0 [] ? copy_from_user+0x2f/0x31 [] ? verify_iovec+0x52/0xa6 [] sys_sendmsg+0x23a/0x2b8 [] ? lock_release+0x181/0x18e [] ? up_read+0x28/0x2c [] ? do_page_fault+0x360/0x3b4 [] ? trace_hardirqs_on_caller+0x10b/0x12f [] ? finish_task_switch+0xb2/0xe3 [] ? finish_task_switch+0x46/0xe3 [] ? trace_hardirqs_off_caller+0x33/0x90 [] ? retint_swapgs+0x13/0x1b [] ? trace_hardirqs_on_caller+0x10b/0x12f [] ? audit_syscall_entry+0x11c/0x148 [] ? trace_hardirqs_on_thunk+0x3a/0x3f [] system_call_fastpath+0x16/0x1b Signed-off-by: Dave Jones Signed-off-by: David S. Miller diff --git a/net/irda/af_irda.c b/net/irda/af_irda.c index c9890e2..cc61697 100644 --- a/net/irda/af_irda.c +++ b/net/irda/af_irda.c @@ -1297,8 +1297,7 @@ static int irda_sendmsg(struct kiocb *iocb, struct socket *sock, /* Note : socket.c set MSG_EOR on SEQPACKET sockets */ if (msg->msg_flags & ~(MSG_DONTWAIT | MSG_EOR | MSG_CMSG_COMPAT | MSG_NOSIGNAL)) { - err = -EINVAL; - goto out; + return -EINVAL; } lock_sock(sk); -- cgit v0.10.2 From bfac3693c426d280b026f6a1b77dc2294ea43fea Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Tue, 12 Apr 2011 15:33:23 -0700 Subject: ieee802154: Remove hacked CFLAGS in net/ieee802154/Makefile It adds -Wall (which the kernel carefully controls already) and of all things -DDEBUG (which should be set by other means if desired, please we have dynamic-debug these days). Kill this noise. Reported-by: Dave Jones Signed-off-by: David S. Miller diff --git a/net/ieee802154/Makefile b/net/ieee802154/Makefile index ce2d335..5761185 100644 --- a/net/ieee802154/Makefile +++ b/net/ieee802154/Makefile @@ -1,5 +1,3 @@ obj-$(CONFIG_IEEE802154) += ieee802154.o af_802154.o ieee802154-y := netlink.o nl-mac.o nl-phy.o nl_policy.o wpan-class.o af_802154-y := af_ieee802154.o raw.o dgram.o - -ccflags-y += -Wall -DDEBUG -- cgit v0.10.2 From fcfa060468a4edcf776f0c1211d826d5de1668c1 Mon Sep 17 00:00:00 2001 From: Neil Turton Date: Mon, 11 Apr 2011 11:42:43 +0100 Subject: sfc: Use rmb() to ensure reads occur in order Enabling write-combining may also enable read reordering. The BIU is only guaranteed to read from a 128-bit CSR or 64-bit SRAM word when the host reads from its lowest address; otherwise the BIU may use the latched value. Therefore we need to reinstate the read memory barriers after the first read operation for each CSR or SRAM word. Signed-off-by; Ben Hutchings diff --git a/drivers/net/sfc/io.h b/drivers/net/sfc/io.h index d9d8c2e..cc97880 100644 --- a/drivers/net/sfc/io.h +++ b/drivers/net/sfc/io.h @@ -152,6 +152,7 @@ static inline void efx_reado(struct efx_nic *efx, efx_oword_t *value, spin_lock_irqsave(&efx->biu_lock, flags); value->u32[0] = _efx_readd(efx, reg + 0); + rmb(); value->u32[1] = _efx_readd(efx, reg + 4); value->u32[2] = _efx_readd(efx, reg + 8); value->u32[3] = _efx_readd(efx, reg + 12); @@ -174,6 +175,7 @@ static inline void efx_sram_readq(struct efx_nic *efx, void __iomem *membase, value->u64[0] = (__force __le64)__raw_readq(membase + addr); #else value->u32[0] = (__force __le32)__raw_readl(membase + addr); + rmb(); value->u32[1] = (__force __le32)__raw_readl(membase + addr + 4); #endif spin_unlock_irqrestore(&efx->biu_lock, flags); -- cgit v0.10.2 From 095d3da610d4022d341c517c59dd5a5d656d966f Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Tue, 12 Apr 2011 15:58:41 -0700 Subject: 9p: Kill set but unused variable in 9p_client_{read,write}() and p9_client_readdir() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes the following warnings: net/9p/client.c:1305:18: warning: variable ‘total’ set but not used [-Wunused-but-set-variable] net/9p/client.c:1370:18: warning: variable ‘total’ set but not used [-Wunused-but-set-variable] net/9p/client.c:1769:18: warning: variable ‘total’ set but not used [-Wunused-but-set-variable] Signed-off-by: David S. Miller diff --git a/net/9p/client.c b/net/9p/client.c index 48b8e08..0ce9592 100644 --- a/net/9p/client.c +++ b/net/9p/client.c @@ -1302,7 +1302,7 @@ int p9_client_read(struct p9_fid *fid, char *data, char __user *udata, u64 offset, u32 count) { - int err, rsize, total; + int err, rsize; struct p9_client *clnt; struct p9_req_t *req; char *dataptr; @@ -1311,7 +1311,6 @@ p9_client_read(struct p9_fid *fid, char *data, char __user *udata, u64 offset, (long long unsigned) offset, count); err = 0; clnt = fid->clnt; - total = 0; rsize = fid->iounit; if (!rsize || rsize > clnt->msize-P9_IOHDRSZ) @@ -1367,7 +1366,7 @@ int p9_client_write(struct p9_fid *fid, char *data, const char __user *udata, u64 offset, u32 count) { - int err, rsize, total; + int err, rsize; struct p9_client *clnt; struct p9_req_t *req; @@ -1375,7 +1374,6 @@ p9_client_write(struct p9_fid *fid, char *data, const char __user *udata, fid->fid, (long long unsigned) offset, count); err = 0; clnt = fid->clnt; - total = 0; rsize = fid->iounit; if (!rsize || rsize > clnt->msize-P9_IOHDRSZ) @@ -1766,7 +1764,7 @@ EXPORT_SYMBOL_GPL(p9_client_xattrcreate); int p9_client_readdir(struct p9_fid *fid, char *data, u32 count, u64 offset) { - int err, rsize, total; + int err, rsize; struct p9_client *clnt; struct p9_req_t *req; char *dataptr; @@ -1776,7 +1774,6 @@ int p9_client_readdir(struct p9_fid *fid, char *data, u32 count, u64 offset) err = 0; clnt = fid->clnt; - total = 0; rsize = fid->iounit; if (!rsize || rsize > clnt->msize-P9_READDIRHDRSZ) -- cgit v0.10.2 From 24743537d3f784a8b3014e934fad0a9c45e4e789 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Tue, 12 Apr 2011 16:14:21 -0700 Subject: atm: iphase: Fix set-but-not-used warnings. The "iavcc" and "iadev" cases are obvious. The intr_status and frmr_intr cases are reading a register to clear the chip status. This driver is pretty old and creaky, and uses volatile pointer dereferences to do register I/O when it should be using readl() and friends. However that it outside of the scope of these changes. Signed-off-by: David S. Miller diff --git a/drivers/atm/iphase.c b/drivers/atm/iphase.c index 1c674a9..dee4f01 100644 --- a/drivers/atm/iphase.c +++ b/drivers/atm/iphase.c @@ -613,7 +613,6 @@ static int ia_que_tx (IADEV *iadev) { struct sk_buff *skb; int num_desc; struct atm_vcc *vcc; - struct ia_vcc *iavcc; num_desc = ia_avail_descs(iadev); while (num_desc && (skb = skb_dequeue(&iadev->tx_backlog))) { @@ -627,7 +626,6 @@ static int ia_que_tx (IADEV *iadev) { printk("Free the SKB on closed vci %d \n", vcc->vci); break; } - iavcc = INPH_IA_VCC(vcc); if (ia_pkt_tx (vcc, skb)) { skb_queue_head(&iadev->tx_backlog, skb); } @@ -823,8 +821,6 @@ static void IaFrontEndIntr(IADEV *iadev) { volatile IA_SUNI *suni; volatile ia_mb25_t *mb25; volatile suni_pm7345_t *suni_pm7345; - u32 intr_status; - u_int frmr_intr; if(iadev->phy_type & FE_25MBIT_PHY) { mb25 = (ia_mb25_t*)iadev->phy; @@ -832,18 +828,18 @@ static void IaFrontEndIntr(IADEV *iadev) { } else if (iadev->phy_type & FE_DS3_PHY) { suni_pm7345 = (suni_pm7345_t *)iadev->phy; /* clear FRMR interrupts */ - frmr_intr = suni_pm7345->suni_ds3_frm_intr_stat; + (void) suni_pm7345->suni_ds3_frm_intr_stat; iadev->carrier_detect = Boolean(!(suni_pm7345->suni_ds3_frm_stat & SUNI_DS3_LOSV)); } else if (iadev->phy_type & FE_E3_PHY ) { suni_pm7345 = (suni_pm7345_t *)iadev->phy; - frmr_intr = suni_pm7345->suni_e3_frm_maint_intr_ind; + (void) suni_pm7345->suni_e3_frm_maint_intr_ind; iadev->carrier_detect = Boolean(!(suni_pm7345->suni_e3_frm_fram_intr_ind_stat&SUNI_E3_LOS)); } else { suni = (IA_SUNI *)iadev->phy; - intr_status = suni->suni_rsop_status & 0xff; + (void) suni->suni_rsop_status; iadev->carrier_detect = Boolean(!(suni->suni_rsop_status & SUNI_LOSV)); } if (iadev->carrier_detect) @@ -2660,7 +2656,6 @@ static void ia_close(struct atm_vcc *vcc) static int ia_open(struct atm_vcc *vcc) { - IADEV *iadev; struct ia_vcc *ia_vcc; int error; if (!test_bit(ATM_VF_PARTIAL,&vcc->flags)) @@ -2668,7 +2663,6 @@ static int ia_open(struct atm_vcc *vcc) IF_EVENT(printk("ia: not partially allocated resources\n");) vcc->dev_data = NULL; } - iadev = INPH_IA_DEV(vcc->dev); if (vcc->vci != ATM_VPI_UNSPEC && vcc->vpi != ATM_VCI_UNSPEC) { IF_EVENT(printk("iphase open: unspec part\n");) @@ -3052,11 +3046,9 @@ static int ia_pkt_tx (struct atm_vcc *vcc, struct sk_buff *skb) { static int ia_send(struct atm_vcc *vcc, struct sk_buff *skb) { IADEV *iadev; - struct ia_vcc *iavcc; unsigned long flags; iadev = INPH_IA_DEV(vcc->dev); - iavcc = INPH_IA_VCC(vcc); if ((!skb)||(skb->len>(iadev->tx_buf_sz-sizeof(struct cpcs_trailer)))) { if (!skb) -- cgit v0.10.2 From 160bc1604f8a33202578846c9a63e2a61105a4b7 Mon Sep 17 00:00:00 2001 From: Jesper Juhl Date: Sun, 10 Apr 2011 17:57:07 +0200 Subject: NFS: Remove dead code from nfs_fs_mount() In fs/nfs/super.c::nfs_fs_mount() we test for a NULL 'data': ... if (data == NULL || mntfh == NULL) goto out_free_fh; ... and then further down in the function we test 'data' again: ... nfs_fscache_get_super_cookie( s, data ? data->fscache_uniq : NULL, NULL); ... this second check is just dead code since there is no way 'data' could possibly be NULL here. We also rely on a non-NULL 'data' in more than one location between these two tests, further proving the point that the second test is bogus. This patch removes the dead code. Signed-off-by: Jesper Juhl Signed-off-by: Trond Myklebust diff --git a/fs/nfs/super.c b/fs/nfs/super.c index 2b8e9a5..685a8a7 100644 --- a/fs/nfs/super.c +++ b/fs/nfs/super.c @@ -2235,8 +2235,7 @@ static struct dentry *nfs_fs_mount(struct file_system_type *fs_type, if (!s->s_root) { /* initial superblock/root creation */ nfs_fill_super(s, data); - nfs_fscache_get_super_cookie( - s, data ? data->fscache_uniq : NULL, NULL); + nfs_fscache_get_super_cookie(s, data->fscache_uniq, NULL); } mntroot = nfs_get_root(s, mntfh, dev_name); -- cgit v0.10.2 From 4b38a6db01b09198f4045661815a0039c3d80660 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Mon, 11 Apr 2011 11:56:23 -0400 Subject: NFS: Eliminate duplicate call to nfs_mark_request_dirty We only need to call nfs_mark_request_dirty() once in nfs_writepage_setup(). Signed-off-by: Trond Myklebust diff --git a/fs/nfs/write.c b/fs/nfs/write.c index e4cbc11..bb60818 100644 --- a/fs/nfs/write.c +++ b/fs/nfs/write.c @@ -680,7 +680,6 @@ static int nfs_writepage_setup(struct nfs_open_context *ctx, struct page *page, req = nfs_setup_write_request(ctx, page, offset, count); if (IS_ERR(req)) return PTR_ERR(req); - nfs_mark_request_dirty(req); /* Update file length */ nfs_grow_file(page, offset, count); nfs_mark_uptodate(page, req->wb_pgbase, req->wb_bytes); -- cgit v0.10.2 From 561f0b0ad073859a87d22845ddfd9df149b22e5f Mon Sep 17 00:00:00 2001 From: Bryan Schumaker Date: Tue, 12 Apr 2011 08:47:15 -0400 Subject: NFS: Remove unused argument from nfs_find_best_sec() The inode was used in an earlier version of the code, but it isn't used anymore. Signed-off-by: Bryan Schumaker Signed-off-by: Trond Myklebust diff --git a/fs/nfs/namespace.c b/fs/nfs/namespace.c index 89fc160..1f063ba 100644 --- a/fs/nfs/namespace.c +++ b/fs/nfs/namespace.c @@ -119,7 +119,7 @@ Elong: } #ifdef CONFIG_NFS_V4 -static rpc_authflavor_t nfs_find_best_sec(struct nfs4_secinfo_flavors *flavors, struct inode *inode) +static rpc_authflavor_t nfs_find_best_sec(struct nfs4_secinfo_flavors *flavors) { struct gss_api_mech *mech; struct xdr_netobj oid; @@ -166,7 +166,7 @@ static int nfs_negotiate_security(const struct dentry *parent, } flavors = page_address(page); ret = secinfo(parent->d_inode, &dentry->d_name, flavors); - *flavor = nfs_find_best_sec(flavors, dentry->d_inode); + *flavor = nfs_find_best_sec(flavors); put_page(page); } -- cgit v0.10.2 From c0d0e96b840dcc73f9b9d45bf8f405dbce72a079 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Tue, 12 Apr 2011 12:29:15 -0400 Subject: NFS: Get rid of pointless test in nfs_commit_done Signed-off-by: Trond Myklebust diff --git a/fs/nfs/write.c b/fs/nfs/write.c index bb60818..3bd5d7e 100644 --- a/fs/nfs/write.c +++ b/fs/nfs/write.c @@ -1417,8 +1417,7 @@ static void nfs_commit_done(struct rpc_task *task, void *calldata) task->tk_pid, task->tk_status); /* Call the NFS version-specific code */ - if (NFS_PROTO(data->inode)->commit_done(task, data) != 0) - return; + NFS_PROTO(data->inode)->commit_done(task, data); } void nfs_commit_release_pages(struct nfs_write_data *data) -- cgit v0.10.2 From 109b36a2bb3eebf5c9994980e724958a5b2b62b6 Mon Sep 17 00:00:00 2001 From: Chris Mason Date: Tue, 12 Apr 2011 13:57:39 -0400 Subject: Btrfs: make uncache_state unconditional The extent_io code can take cached pointers into the extent state trees, and these can make lookups much faster in common operations. The caching only happens when specific bits are set that prevent merging and splitting of the extent state. A help function was added to uncache the state, and it was testing the same set of conditionals. This can leak in very strange corner cases where the lock bit goes away unexpectedly. The uncaching should be unconditional. Once we have a ref on the extent we should always give it up. Signed-off-by: Chris Mason diff --git a/fs/btrfs/extent_io.c b/fs/btrfs/extent_io.c index 8dcfb77..1c462f89 100644 --- a/fs/btrfs/extent_io.c +++ b/fs/btrfs/extent_io.c @@ -694,10 +694,8 @@ static void uncache_state(struct extent_state **cached_ptr) { if (cached_ptr && (*cached_ptr)) { struct extent_state *state = *cached_ptr; - if (state->state & (EXTENT_IOBITS | EXTENT_BOUNDARY)) { - *cached_ptr = NULL; - free_extent_state(state); - } + *cached_ptr = NULL; + free_extent_state(state); } } @@ -1764,7 +1762,7 @@ static void end_bio_extent_readpage(struct bio *bio, int err) spin_lock(&tree->lock); state = find_first_extent_bit_state(tree, start, 0); - if (state) { + if (state && state->start == start) { /* * take a reference on the state, unlock will drop * the ref -- cgit v0.10.2 From 6139e75f4a413bdc8f366fc11e437347be8abc59 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Tue, 12 Apr 2011 19:27:51 -0700 Subject: net: Missing 'inline' in vlan-disabled vlan_untag() Reported-by: Stephen Rothwell Signed-off-by: David S. Miller diff --git a/include/linux/if_vlan.h b/include/linux/if_vlan.h index 998b299..546d9d3 100644 --- a/include/linux/if_vlan.h +++ b/include/linux/if_vlan.h @@ -174,7 +174,7 @@ static inline bool vlan_do_receive(struct sk_buff **skb) return false; } -inline struct sk_buff *vlan_untag(struct sk_buff *skb) +static inline struct sk_buff *vlan_untag(struct sk_buff *skb) { return skb; } -- cgit v0.10.2 From ea2d36883ca8e6caab23b6d15bfa80b1d1d81d2f Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Tue, 12 Apr 2011 14:38:37 +0000 Subject: net: Disable all TSO features when SG is disabled The feature flags NETIF_F_TSO and NETIF_F_TSO6 independently enable TSO for IPv4 and IPv6 respectively. However, the test in netdev_fix_features() and its predecessor functions was never updated to check for NETIF_F_TSO6, possibly because it was originally proposed that TSO for IPv6 would be dependent on both feature flags. Now that these feature flags can be changed independently from user-space and we depend on netdev_fix_features() to fix invalid feature combinations, it's important to disable them both if scatter-gather is disabled. Also disable NETIF_F_TSO_ECN so user-space sees all TSO features as disabled. Signed-off-by: Ben Hutchings Signed-off-by: David S. Miller diff --git a/net/core/dev.c b/net/core/dev.c index 956d3b0..6401fb5 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -5203,9 +5203,9 @@ u32 netdev_fix_features(struct net_device *dev, u32 features) } /* TSO requires that SG is present as well. */ - if ((features & NETIF_F_TSO) && !(features & NETIF_F_SG)) { - netdev_info(dev, "Dropping NETIF_F_TSO since no SG feature.\n"); - features &= ~NETIF_F_TSO; + if ((features & NETIF_F_ALL_TSO) && !(features & NETIF_F_SG)) { + netdev_info(dev, "Dropping TSO features since no SG feature.\n"); + features &= ~NETIF_F_ALL_TSO; } /* Software GSO depends on SG. */ -- cgit v0.10.2 From 31d8b9e099e59f880aa65095951559896d4e20fa Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Tue, 12 Apr 2011 14:47:15 +0000 Subject: net: Disable NETIF_F_TSO_ECN when TSO is disabled NETIF_F_TSO_ECN has no effect when TSO is disabled; this just means that feature state will be accurately reported to user-space. Signed-off-by: Ben Hutchings Signed-off-by: David S. Miller diff --git a/net/core/dev.c b/net/core/dev.c index 6401fb5..c2ac599 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -5208,6 +5208,10 @@ u32 netdev_fix_features(struct net_device *dev, u32 features) features &= ~NETIF_F_ALL_TSO; } + /* TSO ECN requires that TSO is present as well. */ + if ((features & NETIF_F_ALL_TSO) == NETIF_F_TSO_ECN) + features &= ~NETIF_F_TSO_ECN; + /* Software GSO depends on SG. */ if ((features & NETIF_F_GSO) && !(features & NETIF_F_SG)) { netdev_info(dev, "Dropping NETIF_F_GSO since no SG feature.\n"); -- cgit v0.10.2 From 25f7bf7d0dfb460505cbe42676340e33100aca2e Mon Sep 17 00:00:00 2001 From: Vlad Yasevich Date: Tue, 12 Apr 2011 15:20:48 +0000 Subject: sctp: fix oops when updating retransmit path with DEBUG on commit fbdf501c9374966a56829ecca3a7f25d2b49a305 sctp: Do no select unconfirmed transports for retransmissions Introduced the initial falt. commit d598b166ced20d9b9281ea3527c0e18405ddb803 sctp: Make sure we always return valid retransmit path Solved the problem, but forgot to change the DEBUG statement. Thus it was still possible to dereference a NULL pointer. Signed-off-by: Wei Yongjun Signed-off-by: Vlad Yasevich Signed-off-by: David S. Miller diff --git a/net/sctp/associola.c b/net/sctp/associola.c index 0698cad..922fdd7 100644 --- a/net/sctp/associola.c +++ b/net/sctp/associola.c @@ -1323,6 +1323,8 @@ void sctp_assoc_update_retran_path(struct sctp_association *asoc) if (t) asoc->peer.retran_path = t; + else + t = asoc->peer.retran_path; SCTP_DEBUG_PRINTK_IPADDR("sctp_assoc_update_retran_path:association" " %p addr: ", -- cgit v0.10.2 From 9494c7c5774d64a84a269aad38c153c4dbff97e6 Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Tue, 12 Apr 2011 15:22:22 +0000 Subject: sctp: fix oops while removed transport still using as retran path Since we can not update retran path to unconfirmed transports, when we remove a peer, the retran path may not be update if the other transports are all unconfirmed, and we will still using the removed transport as the retran path. This may cause panic if retrasnmit happen. Signed-off-by: Wei Yongjun Signed-off-by: David S. Miller diff --git a/net/sctp/associola.c b/net/sctp/associola.c index 922fdd7..1a21c57 100644 --- a/net/sctp/associola.c +++ b/net/sctp/associola.c @@ -569,6 +569,8 @@ void sctp_assoc_rm_peer(struct sctp_association *asoc, sctp_assoc_set_primary(asoc, transport); if (asoc->peer.active_path == peer) asoc->peer.active_path = transport; + if (asoc->peer.retran_path == peer) + asoc->peer.retran_path = transport; if (asoc->peer.last_data_from == peer) asoc->peer.last_data_from = transport; -- cgit v0.10.2 From 2e6a00356a066d34cd00872b067589549169ad48 Mon Sep 17 00:00:00 2001 From: Li Zefan Date: Thu, 17 Mar 2011 15:17:59 +0800 Subject: Btrfs: Check if btrfs_next_leaf() returns error in btrfs_listxattr() btrfs_next_leaf() can return -errno, and we should propagate it to userspace. This also simplifies how we walk the btree path. Signed-off-by: Li Zefan diff --git a/fs/btrfs/xattr.c b/fs/btrfs/xattr.c index e5d22f2..07b9bc3 100644 --- a/fs/btrfs/xattr.c +++ b/fs/btrfs/xattr.c @@ -180,11 +180,10 @@ ssize_t btrfs_listxattr(struct dentry *dentry, char *buffer, size_t size) struct btrfs_path *path; struct extent_buffer *leaf; struct btrfs_dir_item *di; - int ret = 0, slot, advance; + int ret = 0, slot; size_t total_size = 0, size_left = size; unsigned long name_ptr; size_t name_len; - u32 nritems; /* * ok we want all objects associated with this id. @@ -204,34 +203,24 @@ ssize_t btrfs_listxattr(struct dentry *dentry, char *buffer, size_t size) ret = btrfs_search_slot(NULL, root, &key, path, 0, 0); if (ret < 0) goto err; - advance = 0; + while (1) { leaf = path->nodes[0]; - nritems = btrfs_header_nritems(leaf); slot = path->slots[0]; /* this is where we start walking through the path */ - if (advance || slot >= nritems) { + if (slot >= btrfs_header_nritems(leaf)) { /* * if we've reached the last slot in this leaf we need * to go to the next leaf and reset everything */ - if (slot >= nritems-1) { - ret = btrfs_next_leaf(root, path); - if (ret) - break; - leaf = path->nodes[0]; - nritems = btrfs_header_nritems(leaf); - slot = path->slots[0]; - } else { - /* - * just walking through the slots on this leaf - */ - slot++; - path->slots[0]++; - } + ret = btrfs_next_leaf(root, path); + if (ret < 0) + goto err; + else if (ret > 0) + break; + continue; } - advance = 1; btrfs_item_key_to_cpu(leaf, &found_key, slot); @@ -250,7 +239,7 @@ ssize_t btrfs_listxattr(struct dentry *dentry, char *buffer, size_t size) /* we are just looking for how big our buffer needs to be */ if (!size) - continue; + goto next; if (!buffer || (name_len + 1) > size_left) { ret = -ERANGE; @@ -263,6 +252,8 @@ ssize_t btrfs_listxattr(struct dentry *dentry, char *buffer, size_t size) size_left -= name_len + 1; buffer += name_len + 1; +next: + path->slots[0]++; } ret = total_size; -- cgit v0.10.2 From b9e03af0bcc11310f6be4a3951c9ee2c26465011 Mon Sep 17 00:00:00 2001 From: Li Zefan Date: Wed, 23 Mar 2011 10:43:58 +0800 Subject: Btrfs: Check if btrfs_next_leaf() returns error in btrfs_real_readdir() btrfs_next_leaf() can return -errno, and we should propagate it to userspace. This also simplifies how we walk the btree path. Signed-off-by: Li Zefan diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c index 55a6a0b..b9f7f52 100644 --- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c @@ -4221,10 +4221,8 @@ static int btrfs_real_readdir(struct file *filp, void *dirent, struct btrfs_key found_key; struct btrfs_path *path; int ret; - u32 nritems; struct extent_buffer *leaf; int slot; - int advance; unsigned char d_type; int over = 0; u32 di_cur; @@ -4267,27 +4265,19 @@ static int btrfs_real_readdir(struct file *filp, void *dirent, ret = btrfs_search_slot(NULL, root, &key, path, 0, 0); if (ret < 0) goto err; - advance = 0; while (1) { leaf = path->nodes[0]; - nritems = btrfs_header_nritems(leaf); slot = path->slots[0]; - if (advance || slot >= nritems) { - if (slot >= nritems - 1) { - ret = btrfs_next_leaf(root, path); - if (ret) - break; - leaf = path->nodes[0]; - nritems = btrfs_header_nritems(leaf); - slot = path->slots[0]; - } else { - slot++; - path->slots[0]++; - } + if (slot >= btrfs_header_nritems(leaf)) { + ret = btrfs_next_leaf(root, path); + if (ret < 0) + goto err; + else if (ret > 0) + break; + continue; } - advance = 1; item = btrfs_item_nr(leaf, slot); btrfs_item_key_to_cpu(leaf, &found_key, slot); @@ -4296,7 +4286,7 @@ static int btrfs_real_readdir(struct file *filp, void *dirent, if (btrfs_key_type(&found_key) != key_type) break; if (found_key.offset < filp->f_pos) - continue; + goto next; filp->f_pos = found_key.offset; @@ -4349,6 +4339,8 @@ skip: di_cur += di_len; di = (struct btrfs_dir_item *)((char *)di + di_len); } +next: + path->slots[0]++; } /* Reached end of directory/root. Bump pos past the last item. */ -- cgit v0.10.2 From 3153495d8ed6a9bb9f00aea42c18dc488a885dd6 Mon Sep 17 00:00:00 2001 From: Miao Xie Date: Wed, 13 Apr 2011 13:19:21 +0800 Subject: Btrfs: Fix incorrect inode nlink in btrfs_link() Link count of the inode is not decreased if btrfs_set_inode_index() fails. Signed-off-by: Miao Xie Singed-off-by: Li Zefan diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c index b9f7f52..a4157cf 100644 --- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c @@ -4846,9 +4846,6 @@ static int btrfs_link(struct dentry *old_dentry, struct inode *dir, if (inode->i_nlink == ~0U) return -EMLINK; - btrfs_inc_nlink(inode); - inode->i_ctime = CURRENT_TIME; - err = btrfs_set_inode_index(dir, &index); if (err) goto fail; @@ -4864,6 +4861,9 @@ static int btrfs_link(struct dentry *old_dentry, struct inode *dir, goto fail; } + btrfs_inc_nlink(inode); + inode->i_ctime = CURRENT_TIME; + btrfs_set_trans_block_group(trans, dir); ihold(inode); -- cgit v0.10.2 From 329c5056be8774255db04b01242a9ff4f02eb8ea Mon Sep 17 00:00:00 2001 From: Miao Xie Date: Wed, 13 Apr 2011 14:07:59 +0800 Subject: Btrfs: Check validity before setting an acl Call posix_acl_valid() to check if an acl is valid or not. Signed-off-by: Miao Xie Signed-off-by: Li Zefan diff --git a/fs/btrfs/acl.c b/fs/btrfs/acl.c index 9c94934..a892bc2 100644 --- a/fs/btrfs/acl.c +++ b/fs/btrfs/acl.c @@ -178,16 +178,17 @@ static int btrfs_xattr_acl_set(struct dentry *dentry, const char *name, if (value) { acl = posix_acl_from_xattr(value, size); - if (acl == NULL) { - value = NULL; - size = 0; + if (acl) { + ret = posix_acl_valid(acl); + if (ret) + goto out; } else if (IS_ERR(acl)) { return PTR_ERR(acl); } } ret = btrfs_set_acl(NULL, dentry->d_inode, acl, type); - +out: posix_acl_release(acl); return ret; -- cgit v0.10.2 From ba6a078b77e0dc1309d7e6e2ee034b92ab91f88c Mon Sep 17 00:00:00 2001 From: Jarod Wilson Date: Tue, 12 Apr 2011 23:13:08 -0700 Subject: Input: add KEY_IMAGES specifically for AL Image Browser Many media center remotes have buttons intended for jumping straight to one type of media browser or another -- commonly, images/photos/pictures, audio/music, television, and movies. At present, remotes with an images or photos or pictures button use any number of different keycodes which sort of maybe fit. I've seen at least KEY_MEDIA, KEY_CAMERA, KEY_GRAPHICSEDITOR and KEY_PRESENTATION. None of those seem quite right. In my mind, KEY_MEDIA should be something more like a media center application launcher (and I'd like to standardize on that for things like the windows media center button on the mce remotes). KEY_CAMERA is used in a lot of webcams, and typically means "take a picture now". KEY_GRAPHICSEDITOR implies an editor, not a browser. KEY_PRESENTATION might be the closest fit here, if you think "photo slide show", but it may well be more intended for "run application in full-screen presentation mode" or to launch something like magicpoint, I dunno. And thus, I'd like to have a KEY_IMAGES, which matches the HID Usage AL Image Browser, the meaning of which I think is crystal-clear. I believe AL Audio Browser is already covered by KEY_AUDIO, and AL Movie Browser by KEY_VIDEO, so I'm also adding appropriate comments next to those keys. Signed-off-by: Jarod Wilson Signed-off-by: Dmitry Torokhov diff --git a/include/linux/input.h b/include/linux/input.h index 056ae8a..0cc25e4 100644 --- a/include/linux/input.h +++ b/include/linux/input.h @@ -553,8 +553,8 @@ struct input_keymap_entry { #define KEY_DVD 0x185 /* Media Select DVD */ #define KEY_AUX 0x186 #define KEY_MP3 0x187 -#define KEY_AUDIO 0x188 -#define KEY_VIDEO 0x189 +#define KEY_AUDIO 0x188 /* AL Audio Browser */ +#define KEY_VIDEO 0x189 /* AL Movie Browser */ #define KEY_DIRECTORY 0x18a #define KEY_LIST 0x18b #define KEY_MEMO 0x18c /* Media Select Messages */ @@ -603,8 +603,9 @@ struct input_keymap_entry { #define KEY_FRAMEFORWARD 0x1b5 #define KEY_CONTEXT_MENU 0x1b6 /* GenDesc - system context menu */ #define KEY_MEDIA_REPEAT 0x1b7 /* Consumer - transport control */ -#define KEY_10CHANNELSUP 0x1b8 /* 10 channels up (10+) */ -#define KEY_10CHANNELSDOWN 0x1b9 /* 10 channels down (10-) */ +#define KEY_10CHANNELSUP 0x1b8 /* 10 channels up (10+) */ +#define KEY_10CHANNELSDOWN 0x1b9 /* 10 channels down (10-) */ +#define KEY_IMAGES 0x1ba /* AL Image Browser */ #define KEY_DEL_EOL 0x1c0 #define KEY_DEL_EOS 0x1c1 -- cgit v0.10.2 From b1e064b81e238d47cb56544b34c9baf473e09837 Mon Sep 17 00:00:00 2001 From: Chase Douglas Date: Tue, 12 Apr 2011 23:29:07 -0700 Subject: Input: document event types and codes and their intended use This commit adds the file Documentation/input/event-codes.txt. Acked-by: Henrik Rydberg Reviewed-by: Peter Hutterer Signed-off-by: Chase Douglas Signed-off-by: Chris Bagwell Signed-off-by: Dmitry Torokhov diff --git a/Documentation/input/event-codes.txt b/Documentation/input/event-codes.txt new file mode 100644 index 0000000..f13aee5 --- /dev/null +++ b/Documentation/input/event-codes.txt @@ -0,0 +1,256 @@ +The input protocol uses a map of types and codes to express input device values +to userspace. This document describes the types and codes and how and when they +may be used. + +A single hardware event generates multiple input events. Each input event +contains the new value of a single data item. A special event type, EV_SYN, is +used to separate input events into packets of input data changes occurring at +the same moment in time. In the following, the term "event" refers to a single +input event encompassing a type, code, and value. + +The input protocol is a stateful protocol. Events are emitted only when values +of event codes have changed. However, the state is maintained within the Linux +input subsystem; drivers do not need to maintain the state and may attempt to +emit unchanged values without harm. Userspace may obtain the current state of +event code values using the EVIOCG* ioctls defined in linux/input.h. The event +reports supported by a device are also provided by sysfs in +class/input/event*/device/capabilities/, and the properties of a device are +provided in class/input/event*/device/properties. + +Types: +========== +Types are groupings of codes under a logical input construct. Each type has a +set of applicable codes to be used in generating events. See the Codes section +for details on valid codes for each type. + +* EV_SYN: + - Used as markers to separate events. Events may be separated in time or in + space, such as with the multitouch protocol. + +* EV_KEY: + - Used to describe state changes of keyboards, buttons, or other key-like + devices. + +* EV_REL: + - Used to describe relative axis value changes, e.g. moving the mouse 5 units + to the left. + +* EV_ABS: + - Used to describe absolute axis value changes, e.g. describing the + coordinates of a touch on a touchscreen. + +* EV_MSC: + - Used to describe miscellaneous input data that do not fit into other types. + +* EV_SW: + - Used to describe binary state input switches. + +* EV_LED: + - Used to turn LEDs on devices on and off. + +* EV_SND: + - Used to output sound to devices. + +* EV_REP: + - Used for autorepeating devices. + +* EV_FF: + - Used to send force feedback commands to an input device. + +* EV_PWR: + - A special type for power button and switch input. + +* EV_FF_STATUS: + - Used to receive force feedback device status. + +Codes: +========== +Codes define the precise type of event. + +EV_SYN: +---------- +EV_SYN event values are undefined. Their usage is defined only by when they are +sent in the evdev event stream. + +* SYN_REPORT: + - Used to synchronize and separate events into packets of input data changes + occurring at the same moment in time. For example, motion of a mouse may set + the REL_X and REL_Y values for one motion, then emit a SYN_REPORT. The next + motion will emit more REL_X and REL_Y values and send another SYN_REPORT. + +* SYN_CONFIG: + - TBD + +* SYN_MT_REPORT: + - Used to synchronize and separate touch events. See the + multi-touch-protocol.txt document for more information. + +EV_KEY: +---------- +EV_KEY events take the form KEY_ or BTN_. For example, KEY_A is used +to represent the 'A' key on a keyboard. When a key is depressed, an event with +the key's code is emitted with value 1. When the key is released, an event is +emitted with value 0. Some hardware send events when a key is repeated. These +events have a value of 2. In general, KEY_ is used for keyboard keys, and +BTN_ is used for other types of momentary switch events. + +A few EV_KEY codes have special meanings: + +* BTN_TOOL_: + - These codes are used in conjunction with input trackpads, tablets, and + touchscreens. These devices may be used with fingers, pens, or other tools. + When an event occurs and a tool is used, the corresponding BTN_TOOL_ + code should be set to a value of 1. When the tool is no longer interacting + with the input device, the BTN_TOOL_ code should be reset to 0. All + trackpads, tablets, and touchscreens should use at least one BTN_TOOL_ + code when events are generated. + +* BTN_TOUCH: + BTN_TOUCH is used for touch contact. While an input tool is determined to be + within meaningful physical contact, the value of this property must be set + to 1. Meaningful physical contact may mean any contact, or it may mean + contact conditioned by an implementation defined property. For example, a + touchpad may set the value to 1 only when the touch pressure rises above a + certain value. BTN_TOUCH may be combined with BTN_TOOL_ codes. For + example, a pen tablet may set BTN_TOOL_PEN to 1 and BTN_TOUCH to 0 while the + pen is hovering over but not touching the tablet surface. + +Note: For appropriate function of the legacy mousedev emulation driver, +BTN_TOUCH must be the first evdev code emitted in a synchronization frame. + +Note: Historically a touch device with BTN_TOOL_FINGER and BTN_TOUCH was +interpreted as a touchpad by userspace, while a similar device without +BTN_TOOL_FINGER was interpreted as a touchscreen. For backwards compatibility +with current userspace it is recommended to follow this distinction. In the +future, this distinction will be deprecated and the device properties ioctl +EVIOCGPROP, defined in linux/input.h, will be used to convey the device type. + +* BTN_TOOL_FINGER, BTN_TOOL_DOUBLETAP, BTN_TOOL_TRIPLETAP, BTN_TOOL_QUADTAP: + - These codes denote one, two, three, and four finger interaction on a + trackpad or touchscreen. For example, if the user uses two fingers and moves + them on the touchpad in an effort to scroll content on screen, + BTN_TOOL_DOUBLETAP should be set to value 1 for the duration of the motion. + Note that all BTN_TOOL_ codes and the BTN_TOUCH code are orthogonal in + purpose. A trackpad event generated by finger touches should generate events + for one code from each group. At most only one of these BTN_TOOL_ + codes should have a value of 1 during any synchronization frame. + +Note: Historically some drivers emitted multiple of the finger count codes with +a value of 1 in the same synchronization frame. This usage is deprecated. + +Note: In multitouch drivers, the input_mt_report_finger_count() function should +be used to emit these codes. Please see multi-touch-protocol.txt for details. + +EV_REL: +---------- +EV_REL events describe relative changes in a property. For example, a mouse may +move to the left by a certain number of units, but its absolute position in +space is unknown. If the absolute position is known, EV_ABS codes should be used +instead of EV_REL codes. + +A few EV_REL codes have special meanings: + +* REL_WHEEL, REL_HWHEEL: + - These codes are used for vertical and horizontal scroll wheels, + respectively. + +EV_ABS: +---------- +EV_ABS events describe absolute changes in a property. For example, a touchpad +may emit coordinates for a touch location. + +A few EV_ABS codes have special meanings: + +* ABS_DISTANCE: + - Used to describe the distance of a tool from an interaction surface. This + event should only be emitted while the tool is hovering, meaning in close + proximity of the device and while the value of the BTN_TOUCH code is 0. If + the input device may be used freely in three dimensions, consider ABS_Z + instead. + +* ABS_MT_: + - Used to describe multitouch input events. Please see + multi-touch-protocol.txt for details. + +EV_SW: +---------- +EV_SW events describe stateful binary switches. For example, the SW_LID code is +used to denote when a laptop lid is closed. + +Upon binding to a device or resuming from suspend, a driver must report +the current switch state. This ensures that the device, kernel, and userspace +state is in sync. + +Upon resume, if the switch state is the same as before suspend, then the input +subsystem will filter out the duplicate switch state reports. The driver does +not need to keep the state of the switch at any time. + +EV_MSC: +---------- +EV_MSC events are used for input and output events that do not fall under other +categories. + +EV_LED: +---------- +EV_LED events are used for input and output to set and query the state of +various LEDs on devices. + +EV_REP: +---------- +EV_REP events are used for specifying autorepeating events. + +EV_SND: +---------- +EV_SND events are used for sending sound commands to simple sound output +devices. + +EV_FF: +---------- +EV_FF events are used to initialize a force feedback capable device and to cause +such device to feedback. + +EV_PWR: +---------- +EV_PWR events are a special type of event used specifically for power +mangement. Its usage is not well defined. To be addressed later. + +Guidelines: +========== +The guidelines below ensure proper single-touch and multi-finger functionality. +For multi-touch functionality, see the multi-touch-protocol.txt document for +more information. + +Mice: +---------- +REL_{X,Y} must be reported when the mouse moves. BTN_LEFT must be used to report +the primary button press. BTN_{MIDDLE,RIGHT,4,5,etc.} should be used to report +further buttons of the device. REL_WHEEL and REL_HWHEEL should be used to report +scroll wheel events where available. + +Touchscreens: +---------- +ABS_{X,Y} must be reported with the location of the touch. BTN_TOUCH must be +used to report when a touch is active on the screen. +BTN_{MOUSE,LEFT,MIDDLE,RIGHT} must not be reported as the result of touch +contact. BTN_TOOL_ events should be reported where possible. + +Trackpads: +---------- +Legacy trackpads that only provide relative position information must report +events like mice described above. + +Trackpads that provide absolute touch position must report ABS_{X,Y} for the +location of the touch. BTN_TOUCH should be used to report when a touch is active +on the trackpad. Where multi-finger support is available, BTN_TOOL_ should +be used to report the number of touches active on the trackpad. + +Tablets: +---------- +BTN_TOOL_ events must be reported when a stylus or other tool is active on +the tablet. ABS_{X,Y} must be reported with the location of the tool. BTN_TOUCH +should be used to report when the tool is in contact with the tablet. +BTN_{STYLUS,STYLUS2} should be used to report buttons on the tool itself. Any +button may be used for buttons on the tablet except BTN_{MOUSE,LEFT}. +BTN_{0,1,2,etc} are good generic codes for unlabeled buttons. Do not use +meaningful buttons, like BTN_FORWARD, unless the button is labeled for that +purpose on the device. -- cgit v0.10.2 From 9fb0f14e31b6101a0cc69a333b43541044f9b0a6 Mon Sep 17 00:00:00 2001 From: Jeff Brown Date: Tue, 12 Apr 2011 23:29:38 -0700 Subject: Input: evdev - indicate buffer overrun with SYN_DROPPED Add a new EV_SYN code, SYN_DROPPED, to inform the client when input events have been dropped from the evdev input buffer due to a buffer overrun. The client should use this event as a hint to reset its state or ignore all following events until the next packet begins. Signed-off-by: Jeff Brown [dtor@mail.ru: Implement Henrik's suggestion and drop old events in case of overflow.] Signed-off-by: Dmitry Torokhov diff --git a/Documentation/input/event-codes.txt b/Documentation/input/event-codes.txt index f13aee5..23fcb05 100644 --- a/Documentation/input/event-codes.txt +++ b/Documentation/input/event-codes.txt @@ -85,6 +85,12 @@ sent in the evdev event stream. - Used to synchronize and separate touch events. See the multi-touch-protocol.txt document for more information. +* SYN_DROPPED: + - Used to indicate buffer overrun in the evdev client's event queue. + Client should ignore all events up to and including next SYN_REPORT + event and query the device (using EVIOCG* ioctls) to obtain its + current state. + EV_KEY: ---------- EV_KEY events take the form KEY_ or BTN_. For example, KEY_A is used diff --git a/drivers/input/evdev.c b/drivers/input/evdev.c index 7f42d3a..88d8e4c 100644 --- a/drivers/input/evdev.c +++ b/drivers/input/evdev.c @@ -39,13 +39,13 @@ struct evdev { }; struct evdev_client { - int head; - int tail; + unsigned int head; + unsigned int tail; spinlock_t buffer_lock; /* protects access to buffer, head and tail */ struct fasync_struct *fasync; struct evdev *evdev; struct list_head node; - int bufsize; + unsigned int bufsize; struct input_event buffer[]; }; @@ -55,16 +55,25 @@ static DEFINE_MUTEX(evdev_table_mutex); static void evdev_pass_event(struct evdev_client *client, struct input_event *event) { - /* - * Interrupts are disabled, just acquire the lock. - * Make sure we don't leave with the client buffer - * "empty" by having client->head == client->tail. - */ + /* Interrupts are disabled, just acquire the lock. */ spin_lock(&client->buffer_lock); - do { - client->buffer[client->head++] = *event; - client->head &= client->bufsize - 1; - } while (client->head == client->tail); + + client->buffer[client->head++] = *event; + client->head &= client->bufsize - 1; + + if (unlikely(client->head == client->tail)) { + /* + * This effectively "drops" all unconsumed events, leaving + * EV_SYN/SYN_DROPPED plus the newest event in the queue. + */ + client->tail = (client->head - 2) & (client->bufsize - 1); + + client->buffer[client->tail].time = event->time; + client->buffer[client->tail].type = EV_SYN; + client->buffer[client->tail].code = SYN_DROPPED; + client->buffer[client->tail].value = 0; + } + spin_unlock(&client->buffer_lock); if (event->type == EV_SYN) diff --git a/include/linux/input.h b/include/linux/input.h index 0cc25e4..73a8c6e 100644 --- a/include/linux/input.h +++ b/include/linux/input.h @@ -167,6 +167,7 @@ struct input_keymap_entry { #define SYN_REPORT 0 #define SYN_CONFIG 1 #define SYN_MT_REPORT 2 +#define SYN_DROPPED 3 /* * Keys and buttons -- cgit v0.10.2 From 0e8a835aa59d08d702af0fcfd296e2218b2e344b Mon Sep 17 00:00:00 2001 From: Jozsef Kadlecsik Date: Wed, 13 Apr 2011 13:43:23 +0200 Subject: netfilter: ipset: bitmap:ip,mac type requires "src" for MAC Enforce that the second "src/dst" parameter of the set match and SET target must be "src", because we have access to the source MAC only in the packet. The previous behaviour, that the type required the second parameter but actually ignored the value was counter-intuitive and confusing. Signed-off-by: Jozsef Kadlecsik Signed-off-by: Patrick McHardy diff --git a/net/netfilter/ipset/ip_set_bitmap_ipmac.c b/net/netfilter/ipset/ip_set_bitmap_ipmac.c index 00a3324..a274300 100644 --- a/net/netfilter/ipset/ip_set_bitmap_ipmac.c +++ b/net/netfilter/ipset/ip_set_bitmap_ipmac.c @@ -343,6 +343,10 @@ bitmap_ipmac_kadt(struct ip_set *set, const struct sk_buff *skb, ipset_adtfn adtfn = set->variant->adt[adt]; struct ipmac data; + /* MAC can be src only */ + if (!(flags & IPSET_DIM_TWO_SRC)) + return 0; + data.id = ntohl(ip4addr(skb, flags & IPSET_DIM_ONE_SRC)); if (data.id < map->first_ip || data.id > map->last_ip) return -IPSET_ERR_BITMAP_RANGE; -- cgit v0.10.2 From eafbd3fde6fc5ada0d61307367e408813b04928a Mon Sep 17 00:00:00 2001 From: Jozsef Kadlecsik Date: Wed, 13 Apr 2011 13:45:57 +0200 Subject: netfilter: ipset: set match and SET target fixes The SET target with --del-set did not work due to using wrongly the internal dimension of --add-set instead of --del-set. Also, the checkentries did not release the set references when returned an error. Bugs reported by Lennert Buytenhek. Signed-off-by: Jozsef Kadlecsik Signed-off-by: Patrick McHardy diff --git a/net/netfilter/xt_set.c b/net/netfilter/xt_set.c index 061d48c..b3babae 100644 --- a/net/netfilter/xt_set.c +++ b/net/netfilter/xt_set.c @@ -81,6 +81,7 @@ set_match_v0_checkentry(const struct xt_mtchk_param *par) if (info->match_set.u.flags[IPSET_DIM_MAX-1] != 0) { pr_warning("Protocol error: set match dimension " "is over the limit!\n"); + ip_set_nfnl_put(info->match_set.index); return -ERANGE; } @@ -135,6 +136,8 @@ set_target_v0_checkentry(const struct xt_tgchk_param *par) if (index == IPSET_INVALID_ID) { pr_warning("Cannot find del_set index %u as target\n", info->del_set.index); + if (info->add_set.index != IPSET_INVALID_ID) + ip_set_nfnl_put(info->add_set.index); return -ENOENT; } } @@ -142,6 +145,10 @@ set_target_v0_checkentry(const struct xt_tgchk_param *par) info->del_set.u.flags[IPSET_DIM_MAX-1] != 0) { pr_warning("Protocol error: SET target dimension " "is over the limit!\n"); + if (info->add_set.index != IPSET_INVALID_ID) + ip_set_nfnl_put(info->add_set.index); + if (info->del_set.index != IPSET_INVALID_ID) + ip_set_nfnl_put(info->del_set.index); return -ERANGE; } @@ -192,6 +199,7 @@ set_match_checkentry(const struct xt_mtchk_param *par) if (info->match_set.dim > IPSET_DIM_MAX) { pr_warning("Protocol error: set match dimension " "is over the limit!\n"); + ip_set_nfnl_put(info->match_set.index); return -ERANGE; } @@ -219,7 +227,7 @@ set_target(struct sk_buff *skb, const struct xt_action_param *par) if (info->del_set.index != IPSET_INVALID_ID) ip_set_del(info->del_set.index, skb, par->family, - info->add_set.dim, + info->del_set.dim, info->del_set.flags); return XT_CONTINUE; @@ -245,13 +253,19 @@ set_target_checkentry(const struct xt_tgchk_param *par) if (index == IPSET_INVALID_ID) { pr_warning("Cannot find del_set index %u as target\n", info->del_set.index); + if (info->add_set.index != IPSET_INVALID_ID) + ip_set_nfnl_put(info->add_set.index); return -ENOENT; } } if (info->add_set.dim > IPSET_DIM_MAX || - info->del_set.flags > IPSET_DIM_MAX) { + info->del_set.dim > IPSET_DIM_MAX) { pr_warning("Protocol error: SET target dimension " "is over the limit!\n"); + if (info->add_set.index != IPSET_INVALID_ID) + ip_set_nfnl_put(info->add_set.index); + if (info->del_set.index != IPSET_INVALID_ID) + ip_set_nfnl_put(info->del_set.index); return -ERANGE; } -- cgit v0.10.2 From 91eb7c08c6cb3b8eeba1c61f5753c56dcb77f018 Mon Sep 17 00:00:00 2001 From: Jozsef Kadlecsik Date: Wed, 13 Apr 2011 13:51:38 +0200 Subject: netfilter: ipset: SCTP, UDPLITE support added SCTP and UDPLITE port support added to the hash:*port* set types. Signed-off-by: Jozsef Kadlecsik Signed-off-by: Patrick McHardy diff --git a/include/linux/netfilter/ipset/ip_set_getport.h b/include/linux/netfilter/ipset/ip_set_getport.h index 5aebd17..90d0930 100644 --- a/include/linux/netfilter/ipset/ip_set_getport.h +++ b/include/linux/netfilter/ipset/ip_set_getport.h @@ -22,7 +22,9 @@ static inline bool ip_set_proto_with_ports(u8 proto) { switch (proto) { case IPPROTO_TCP: + case IPPROTO_SCTP: case IPPROTO_UDP: + case IPPROTO_UDPLITE: return true; } return false; diff --git a/net/netfilter/ipset/ip_set_getport.c b/net/netfilter/ipset/ip_set_getport.c index 8d52272..757143b 100644 --- a/net/netfilter/ipset/ip_set_getport.c +++ b/net/netfilter/ipset/ip_set_getport.c @@ -11,6 +11,7 @@ #include #include #include +#include #include #include #include @@ -35,7 +36,20 @@ get_port(const struct sk_buff *skb, int protocol, unsigned int protooff, *port = src ? th->source : th->dest; break; } - case IPPROTO_UDP: { + case IPPROTO_SCTP: { + sctp_sctphdr_t _sh; + const sctp_sctphdr_t *sh; + + sh = skb_header_pointer(skb, protooff, sizeof(_sh), &_sh); + if (sh == NULL) + /* No choice either */ + return false; + + *port = src ? sh->source : sh->dest; + break; + } + case IPPROTO_UDP: + case IPPROTO_UDPLITE: { struct udphdr _udph; const struct udphdr *uh; diff --git a/net/netfilter/ipset/ip_set_hash_ipport.c b/net/netfilter/ipset/ip_set_hash_ipport.c index b921414..14281b6 100644 --- a/net/netfilter/ipset/ip_set_hash_ipport.c +++ b/net/netfilter/ipset/ip_set_hash_ipport.c @@ -491,7 +491,7 @@ static struct ip_set_type hash_ipport_type __read_mostly = { .features = IPSET_TYPE_IP | IPSET_TYPE_PORT, .dimension = IPSET_DIM_TWO, .family = AF_UNSPEC, - .revision = 0, + .revision = 1, .create = hash_ipport_create, .create_policy = { [IPSET_ATTR_HASHSIZE] = { .type = NLA_U32 }, diff --git a/net/netfilter/ipset/ip_set_hash_ipportip.c b/net/netfilter/ipset/ip_set_hash_ipportip.c index 4642872..401c8a2 100644 --- a/net/netfilter/ipset/ip_set_hash_ipportip.c +++ b/net/netfilter/ipset/ip_set_hash_ipportip.c @@ -509,7 +509,7 @@ static struct ip_set_type hash_ipportip_type __read_mostly = { .features = IPSET_TYPE_IP | IPSET_TYPE_PORT | IPSET_TYPE_IP2, .dimension = IPSET_DIM_THREE, .family = AF_UNSPEC, - .revision = 0, + .revision = 1, .create = hash_ipportip_create, .create_policy = { [IPSET_ATTR_HASHSIZE] = { .type = NLA_U32 }, diff --git a/net/netfilter/ipset/ip_set_hash_ipportnet.c b/net/netfilter/ipset/ip_set_hash_ipportnet.c index 2cb84a5..4743e54 100644 --- a/net/netfilter/ipset/ip_set_hash_ipportnet.c +++ b/net/netfilter/ipset/ip_set_hash_ipportnet.c @@ -574,7 +574,7 @@ static struct ip_set_type hash_ipportnet_type __read_mostly = { .features = IPSET_TYPE_IP | IPSET_TYPE_PORT | IPSET_TYPE_IP2, .dimension = IPSET_DIM_THREE, .family = AF_UNSPEC, - .revision = 0, + .revision = 1, .create = hash_ipportnet_create, .create_policy = { [IPSET_ATTR_HASHSIZE] = { .type = NLA_U32 }, diff --git a/net/netfilter/ipset/ip_set_hash_netport.c b/net/netfilter/ipset/ip_set_hash_netport.c index 8598676..d2a4036 100644 --- a/net/netfilter/ipset/ip_set_hash_netport.c +++ b/net/netfilter/ipset/ip_set_hash_netport.c @@ -526,7 +526,7 @@ static struct ip_set_type hash_netport_type __read_mostly = { .features = IPSET_TYPE_IP | IPSET_TYPE_PORT, .dimension = IPSET_DIM_TWO, .family = AF_UNSPEC, - .revision = 0, + .revision = 1, .create = hash_netport_create, .create_policy = { [IPSET_ATTR_HASHSIZE] = { .type = NLA_U32 }, -- cgit v0.10.2 From 0f890ab1b51a5e59f078f046229825076d1e3c77 Mon Sep 17 00:00:00 2001 From: Andy Walls Date: Sun, 27 Mar 2011 20:19:15 -0300 Subject: [media] cx18: Fix list BUG for IDX stream, triggerable in cx18_probe() error clean up, If allocating stream buffers for one of the primary streams (e.g. YUV) failed during card probe, the error path clean up would try to manipulate the yet unitialized IDX stream structures. This caused a BUG due to unitialized list heads. Detect that case and ignore the uninitialized IDX stream. Signed-off-by: Andy Walls Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/video/cx18/cx18-streams.c b/drivers/media/video/cx18/cx18-streams.c index c6e2ca3..6fbc356 100644 --- a/drivers/media/video/cx18/cx18-streams.c +++ b/drivers/media/video/cx18/cx18-streams.c @@ -350,9 +350,17 @@ void cx18_streams_cleanup(struct cx18 *cx, int unregister) /* No struct video_device, but can have buffers allocated */ if (type == CX18_ENC_STREAM_TYPE_IDX) { + /* If the module params didn't inhibit IDX ... */ if (cx->stream_buffers[type] != 0) { cx->stream_buffers[type] = 0; - cx18_stream_free(&cx->streams[type]); + /* + * Before calling cx18_stream_free(), + * check if the IDX stream was actually set up. + * Needed, since the cx18_probe() error path + * exits through here as well as normal clean up + */ + if (cx->streams[type].buffers != 0) + cx18_stream_free(&cx->streams[type]); } continue; } -- cgit v0.10.2 From 8962d87129ec0a820d17ac44cbf3f51010ad8db8 Mon Sep 17 00:00:00 2001 From: "John W. Linville" Date: Wed, 13 Apr 2011 08:47:32 -0400 Subject: ath5k: improve comments for optimized tx descriptor setup Comment the use of local variables to reduce the number of load/store operations on uncached memory, in hopes of not losing this optimization accidentally in the future. Signed-off-by: Felix Fietkau Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath5k/desc.c b/drivers/net/wireless/ath/ath5k/desc.c index 0391813..dd7cd95 100644 --- a/drivers/net/wireless/ath/ath5k/desc.c +++ b/drivers/net/wireless/ath/ath5k/desc.c @@ -184,6 +184,11 @@ static int ath5k_hw_setup_4word_tx_desc(struct ath5k_hw *ah, { struct ath5k_hw_4w_tx_ctl *tx_ctl; unsigned int frame_len; + + /* + * Use local variables for these to reduce load/store access on + * uncached memory + */ u32 txctl0 = 0, txctl1 = 0, txctl2 = 0, txctl3 = 0; tx_ctl = &desc->ud.ds_tx5212.tx_ctl; @@ -209,7 +214,7 @@ static int ath5k_hw_setup_4word_tx_desc(struct ath5k_hw *ah, if (tx_power > AR5K_TUNE_MAX_TXPOWER) tx_power = AR5K_TUNE_MAX_TXPOWER; - /* Clear descriptor */ + /* Clear descriptor status area */ memset(&desc->ud.ds_tx5212.tx_stat, 0, sizeof(desc->ud.ds_tx5212.tx_stat)); -- cgit v0.10.2 From 62a79436a54e5f33920bf95a3fae677540c7ef2c Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Tue, 22 Mar 2011 09:24:58 -0300 Subject: [media] videobuf2: fix core to correctly identify allocation failures The videobuf2-dma-contig allocator returns an ERR_PTR() on failure, not a NULL like all other allocators. Fix videobuf2-core to also correctly recognise those failures. Signed-off-by: Guennadi Liakhovetski Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/video/videobuf2-core.c b/drivers/media/video/videobuf2-core.c index 6698c77..71734a4 100644 --- a/drivers/media/video/videobuf2-core.c +++ b/drivers/media/video/videobuf2-core.c @@ -51,7 +51,7 @@ static int __vb2_buf_mem_alloc(struct vb2_buffer *vb, for (plane = 0; plane < vb->num_planes; ++plane) { mem_priv = call_memop(q, plane, alloc, q->alloc_ctx[plane], plane_sizes[plane]); - if (!mem_priv) + if (IS_ERR_OR_NULL(mem_priv)) goto free; /* Associate allocator private data with this plane */ -- cgit v0.10.2 From 99a41771bfbd4fb350b0021d3298b0cb49dd747b Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Tue, 22 Mar 2011 09:29:32 -0300 Subject: [media] videobuf2: fix an error message buf->size is not yet initialised in videobuf2-dma-contig at the time of the error message, use "size." Signed-off-by: Guennadi Liakhovetski Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/video/videobuf2-dma-contig.c b/drivers/media/video/videobuf2-dma-contig.c index 58205d5..a790a5f 100644 --- a/drivers/media/video/videobuf2-dma-contig.c +++ b/drivers/media/video/videobuf2-dma-contig.c @@ -46,7 +46,7 @@ static void *vb2_dma_contig_alloc(void *alloc_ctx, unsigned long size) GFP_KERNEL); if (!buf->vaddr) { dev_err(conf->dev, "dma_alloc_coherent of size %ld failed\n", - buf->size); + size); kfree(buf); return ERR_PTR(-ENOMEM); } -- cgit v0.10.2 From c6c735441207b2ab54e45b0eb47671c508ee9847 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Tue, 22 Mar 2011 09:32:51 -0300 Subject: [media] v4l2-device: fix a macro definition v4l2_device_unregister_subdev() wrongly uses "arg..." instead of "## arg" in its body. Fix it. Signed-off-by: Guennadi Liakhovetski Signed-off-by: Mauro Carvalho Chehab diff --git a/include/media/v4l2-device.h b/include/media/v4l2-device.h index bd102cf..d61febfb 100644 --- a/include/media/v4l2-device.h +++ b/include/media/v4l2-device.h @@ -163,7 +163,7 @@ v4l2_device_register_subdev_nodes(struct v4l2_device *v4l2_dev); ({ \ struct v4l2_subdev *__sd; \ __v4l2_device_call_subdevs_until_err_p(v4l2_dev, __sd, cond, o, \ - f, args...); \ + f , ##args); \ }) /* Call the specified callback for all subdevs matching grp_id (if 0, then -- cgit v0.10.2 From 24105ebc0567f2864999a8176be681c62fe31350 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Wed, 23 Mar 2011 05:41:28 -0300 Subject: [media] soc-camera: fix a recent multi-camera breakage on sh-mobile With the introduction of CSI2 support on sh-mobile, the host driver switched to using v4l2_device_call_until_err() with grp_id == 0 to call subdev operations on the sensor and the CSI2 subdev. However, this has broken multi-client set ups like the one on migor, because that way all operations get called on both clients. To fix this add a grp_id and set it to the client private context. Signed-off-by: Guennadi Liakhovetski Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/video/sh_mobile_ceu_camera.c b/drivers/media/video/sh_mobile_ceu_camera.c index 3fe54bf..134e86b 100644 --- a/drivers/media/video/sh_mobile_ceu_camera.c +++ b/drivers/media/video/sh_mobile_ceu_camera.c @@ -922,7 +922,7 @@ static int sh_mobile_ceu_get_formats(struct soc_camera_device *icd, unsigned int /* Try 2560x1920, 1280x960, 640x480, 320x240 */ mf.width = 2560 >> shift; mf.height = 1920 >> shift; - ret = v4l2_device_call_until_err(sd->v4l2_dev, 0, video, + ret = v4l2_device_call_until_err(sd->v4l2_dev, (long)icd, video, s_mbus_fmt, &mf); if (ret < 0) return ret; @@ -1224,7 +1224,7 @@ static int client_s_fmt(struct soc_camera_device *icd, struct v4l2_cropcap cap; int ret; - ret = v4l2_device_call_until_err(sd->v4l2_dev, 0, video, + ret = v4l2_device_call_until_err(sd->v4l2_dev, (long)icd, video, s_mbus_fmt, mf); if (ret < 0) return ret; @@ -1254,7 +1254,7 @@ static int client_s_fmt(struct soc_camera_device *icd, tmp_h = min(2 * tmp_h, max_height); mf->width = tmp_w; mf->height = tmp_h; - ret = v4l2_device_call_until_err(sd->v4l2_dev, 0, video, + ret = v4l2_device_call_until_err(sd->v4l2_dev, (long)icd, video, s_mbus_fmt, mf); dev_geo(dev, "Camera scaled to %ux%u\n", mf->width, mf->height); @@ -1658,7 +1658,7 @@ static int sh_mobile_ceu_try_fmt(struct soc_camera_device *icd, mf.code = xlate->code; mf.colorspace = pix->colorspace; - ret = v4l2_device_call_until_err(sd->v4l2_dev, 0, video, try_mbus_fmt, &mf); + ret = v4l2_device_call_until_err(sd->v4l2_dev, (long)icd, video, try_mbus_fmt, &mf); if (ret < 0) return ret; @@ -1682,7 +1682,7 @@ static int sh_mobile_ceu_try_fmt(struct soc_camera_device *icd, */ mf.width = 2560; mf.height = 1920; - ret = v4l2_device_call_until_err(sd->v4l2_dev, 0, video, + ret = v4l2_device_call_until_err(sd->v4l2_dev, (long)icd, video, try_mbus_fmt, &mf); if (ret < 0) { /* Shouldn't actually happen... */ diff --git a/drivers/media/video/sh_mobile_csi2.c b/drivers/media/video/sh_mobile_csi2.c index dd1b81b..9e7c1a7 100644 --- a/drivers/media/video/sh_mobile_csi2.c +++ b/drivers/media/video/sh_mobile_csi2.c @@ -208,6 +208,7 @@ static int sh_csi2_notify(struct notifier_block *nb, case BUS_NOTIFY_BOUND_DRIVER: snprintf(priv->subdev.name, V4L2_SUBDEV_NAME_SIZE, "%s%s", dev_name(v4l2_dev->dev), ".mipi-csi"); + priv->subdev.grp_id = (long)icd; ret = v4l2_device_register_subdev(v4l2_dev, &priv->subdev); dev_dbg(dev, "%s(%p): ret(register_subdev) = %d\n", __func__, priv, ret); if (ret < 0) diff --git a/drivers/media/video/soc_camera.c b/drivers/media/video/soc_camera.c index 4628448..9219930 100644 --- a/drivers/media/video/soc_camera.c +++ b/drivers/media/video/soc_camera.c @@ -1071,6 +1071,9 @@ static int soc_camera_probe(struct device *dev) } } + sd = soc_camera_to_subdev(icd); + sd->grp_id = (long)icd; + /* At this point client .probe() should have run already */ ret = soc_camera_init_user_formats(icd); if (ret < 0) @@ -1092,7 +1095,6 @@ static int soc_camera_probe(struct device *dev) goto evidstart; /* Try to improve our guess of a reasonable window format */ - sd = soc_camera_to_subdev(icd); if (!v4l2_subdev_call(sd, video, g_mbus_fmt, &mf)) { icd->user_width = mf.width; icd->user_height = mf.height; -- cgit v0.10.2 From 3e31f2b9456d0777a41d9d26429d6f2ad6894014 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Wed, 23 Mar 2011 05:24:42 -0300 Subject: [media] imx074: return a meaningful error code instead of -1 Signed-off-by: Guennadi Liakhovetski Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/video/imx074.c b/drivers/media/video/imx074.c index 1a11691..0382ea7 100644 --- a/drivers/media/video/imx074.c +++ b/drivers/media/video/imx074.c @@ -298,7 +298,7 @@ static unsigned long imx074_query_bus_param(struct soc_camera_device *icd) static int imx074_set_bus_param(struct soc_camera_device *icd, unsigned long flags) { - return -1; + return -EINVAL; } static struct soc_camera_ops imx074_ops = { -- cgit v0.10.2 From c8dd707805af100965c93cdca7d61e61165e9c07 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Wed, 23 Mar 2011 05:26:11 -0300 Subject: [media] soc-camera: don't dereference I2C client after it has been removed i2c_unregister_device() frees the I2C client, so, dereferencing it afterwards is a bug, that leads to Oopses. Signed-off-by: Guennadi Liakhovetski Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/video/soc_camera.c b/drivers/media/video/soc_camera.c index 9219930..3973f9a 100644 --- a/drivers/media/video/soc_camera.c +++ b/drivers/media/video/soc_camera.c @@ -996,10 +996,11 @@ static void soc_camera_free_i2c(struct soc_camera_device *icd) { struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd)); + struct i2c_adapter *adap = client->adapter; dev_set_drvdata(&icd->dev, NULL); v4l2_device_unregister_subdev(i2c_get_clientdata(client)); i2c_unregister_device(client); - i2c_put_adapter(client->adapter); + i2c_put_adapter(adap); } #else #define soc_camera_init_i2c(icd, icl) (-ENODEV) -- cgit v0.10.2 From cb743930eb91e5b608c4491ce1b930dfeca43943 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Wed, 23 Mar 2011 05:43:51 -0300 Subject: [media] sh_mobile_csi2: fix module reloading If the camera host driver (sh_mobile_ceu_camera.c) is unloaded and then reloaded, probe will fail, because camera client .set_bus_param() and .query_bus_param() methods have been set to NULL. Fix this by caching the original pointers and restoring them on driver-unbind. Signed-off-by: Guennadi Liakhovetski Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/video/sh_mobile_csi2.c b/drivers/media/video/sh_mobile_csi2.c index 9e7c1a7..98b8748 100644 --- a/drivers/media/video/sh_mobile_csi2.c +++ b/drivers/media/video/sh_mobile_csi2.c @@ -38,6 +38,8 @@ struct sh_csi2 { void __iomem *base; struct platform_device *pdev; struct sh_csi2_client_config *client; + unsigned long (*query_bus_param)(struct soc_camera_device *); + int (*set_bus_param)(struct soc_camera_device *, unsigned long); }; static int sh_csi2_try_fmt(struct v4l2_subdev *sd, @@ -216,6 +218,8 @@ static int sh_csi2_notify(struct notifier_block *nb, priv->client = pdata->clients + i; + priv->set_bus_param = icd->ops->set_bus_param; + priv->query_bus_param = icd->ops->query_bus_param; icd->ops->set_bus_param = sh_csi2_set_bus_param; icd->ops->query_bus_param = sh_csi2_query_bus_param; @@ -227,8 +231,10 @@ static int sh_csi2_notify(struct notifier_block *nb, priv->client = NULL; /* Driver is about to be unbound */ - icd->ops->set_bus_param = NULL; - icd->ops->query_bus_param = NULL; + icd->ops->set_bus_param = priv->set_bus_param; + icd->ops->query_bus_param = priv->query_bus_param; + priv->set_bus_param = NULL; + priv->query_bus_param = NULL; v4l2_device_unregister_subdev(&priv->subdev); -- cgit v0.10.2 From d16290d77a3c81121a5bc050dba0b6aaf971b7e8 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Mon, 28 Mar 2011 13:16:43 -0300 Subject: [media] V4L: sh_mobile_ceu_camera: fix typos in documentation Fix a couple of typos and clarify a formula in sh_mobile_ceu driver documentation. Signed-off-by: Guennadi Liakhovetski Signed-off-by: Mauro Carvalho Chehab diff --git a/Documentation/video4linux/sh_mobile_ceu_camera.txt b/Documentation/video4linux/sh_mobile_ceu_camera.txt index cb47e72..1e96ce6 100644 --- a/Documentation/video4linux/sh_mobile_ceu_camera.txt +++ b/Documentation/video4linux/sh_mobile_ceu_camera.txt @@ -37,7 +37,7 @@ Generic scaling / cropping scheme -1'- In the above chart minuses and slashes represent "real" data amounts, points and -accents represent "useful" data, basically, CEU scaled amd cropped output, +accents represent "useful" data, basically, CEU scaled and cropped output, mapped back onto the client's source plane. Such a configuration can be produced by user requests: @@ -65,7 +65,7 @@ Do not touch input rectangle - it is already optimal. 1. Calculate current sensor scales: - scale_s = ((3') - (3)) / ((2') - (2)) + scale_s = ((2') - (2)) / ((3') - (3)) 2. Calculate "effective" input crop (sensor subwindow) - CEU crop scaled back at current sensor scales onto input window - this is user S_CROP: @@ -80,7 +80,7 @@ window: 4. Calculate sensor output window by applying combined scales to real input window: - width_s_out = ((2') - (2)) / scale_comb + width_s_out = ((7') - (7)) = ((2') - (2)) / scale_comb 5. Apply iterative sensor S_FMT for sensor output window. -- cgit v0.10.2 From 122af366015abc2787a06b1564d62962b08b2042 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Thu, 7 Apr 2011 05:50:43 -0300 Subject: [media] V4L: mx3_camera: select VIDEOBUF2_DMA_CONTIG instead of VIDEOBUF_DMA_CONTIG MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Since commit 379fa5d ([media] V4L: mx3_camera: convert to videobuf2) mx3_camera uses videobuf2, but that commit didn't upgrade the select resulting in the following build failure: drivers/built-in.o: In function `mx3_camera_init_videobuf': clkdev.c:(.text+0x86580): undefined reference to `vb2_dma_contig_memops' drivers/built-in.o: In function `mx3_camera_probe': clkdev.c:(.devinit.text+0x3548): undefined reference to `vb2_dma_contig_init_ctx' clkdev.c:(.devinit.text+0x3578): undefined reference to `vb2_dma_contig_cleanup_ctx' drivers/built-in.o: In function `mx3_camera_remove': clkdev.c:(.devexit.text+0x674): undefined reference to `vb2_dma_contig_cleanup_ctx' make[2]: *** [.tmp_vmlinux1] Error 1 make[1]: *** [sub-make] Error 2 make: *** [all] Error 2 Signed-off-by: Uwe Kleine-König Signed-off-by: Guennadi Liakhovetski Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/video/Kconfig b/drivers/media/video/Kconfig index 4498b94..00f51dd 100644 --- a/drivers/media/video/Kconfig +++ b/drivers/media/video/Kconfig @@ -875,7 +875,7 @@ config MX3_VIDEO config VIDEO_MX3 tristate "i.MX3x Camera Sensor Interface driver" depends on VIDEO_DEV && MX3_IPU && SOC_CAMERA - select VIDEOBUF_DMA_CONTIG + select VIDEOBUF2_DMA_CONTIG select MX3_VIDEO ---help--- This is a v4l2 driver for the i.MX3x Camera Sensor Interface -- cgit v0.10.2 From 21d2b9587f93302d4f13bf3d99482f3642f48b96 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Thu, 17 Mar 2011 12:23:22 -0300 Subject: [media] media: Use correct ioctl name in MEDIA_IOC_SETUP_LINK documentation The documentation incorrectly refers to MEDIA_IOC_ENUM_LINKS, fix it. Signed-off-by: Laurent Pinchart Signed-off-by: Mauro Carvalho Chehab diff --git a/Documentation/DocBook/v4l/media-ioc-setup-link.xml b/Documentation/DocBook/v4l/media-ioc-setup-link.xml index 2331e76..cec97af 100644 --- a/Documentation/DocBook/v4l/media-ioc-setup-link.xml +++ b/Documentation/DocBook/v4l/media-ioc-setup-link.xml @@ -34,7 +34,7 @@ request - MEDIA_IOC_ENUM_LINKS + MEDIA_IOC_SETUP_LINK -- cgit v0.10.2 From 8eca7a004ef9fec2fdca8a2b4b65410ff1515b80 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Fri, 18 Feb 2011 09:41:49 -0300 Subject: [media] omap3isp: resizer: Center the crop rectangle When the crop rectangle needs to be modified to match hardware requirements, center the resulting rectangle on the requested rectangle instead of removing pixels from the right and bottom sides only. Signed-off-by: Laurent Pinchart Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/video/omap3isp/ispresizer.c b/drivers/media/video/omap3isp/ispresizer.c index 75d39b1..829d7bf 100644 --- a/drivers/media/video/omap3isp/ispresizer.c +++ b/drivers/media/video/omap3isp/ispresizer.c @@ -775,6 +775,8 @@ static void resizer_calc_ratios(struct isp_res_device *res, unsigned int max_width; unsigned int max_height; unsigned int width_alignment; + unsigned int width; + unsigned int height; /* * Clamp the output height based on the hardware capabilities and @@ -794,11 +796,11 @@ static void resizer_calc_ratios(struct isp_res_device *res, if (ratio->vert <= MID_RESIZE_VALUE) { upscaled_height = (output->height - 1) * ratio->vert + 32 * spv + 16; - input->height = (upscaled_height >> 8) + 4; + height = (upscaled_height >> 8) + 4; } else { upscaled_height = (output->height - 1) * ratio->vert + 64 * spv + 32; - input->height = (upscaled_height >> 8) + 7; + height = (upscaled_height >> 8) + 7; } /* @@ -862,12 +864,18 @@ static void resizer_calc_ratios(struct isp_res_device *res, if (ratio->horz <= MID_RESIZE_VALUE) { upscaled_width = (output->width - 1) * ratio->horz + 32 * sph + 16; - input->width = (upscaled_width >> 8) + 7; + width = (upscaled_width >> 8) + 7; } else { upscaled_width = (output->width - 1) * ratio->horz + 64 * sph + 32; - input->width = (upscaled_width >> 8) + 7; + width = (upscaled_width >> 8) + 7; } + + /* Center the new crop rectangle. */ + input->left += (input->width - width) / 2; + input->top += (input->height - height) / 2; + input->width = width; + input->height = height; } /* -- cgit v0.10.2 From 39d5a3ee355fa903ef4609402c79f570eb9fc4d2 Mon Sep 17 00:00:00 2001 From: "Gustavo F. Padovan" Date: Mon, 4 Apr 2011 15:40:12 -0300 Subject: Bluetooth: Move SREJ list to struct l2cap_chan As part of moving all the Channel related operation to struct l2cap_chan. Signed-off-by: Gustavo F. Padovan diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h index d05d91f..ec56d88 100644 --- a/include/net/bluetooth/l2cap.h +++ b/include/net/bluetooth/l2cap.h @@ -277,6 +277,11 @@ struct l2cap_conn_param_update_rsp { #define L2CAP_CONN_PARAM_REJECTED 0x0001 /* ----- L2CAP channels and connections ----- */ +struct srej_list { + __u8 tx_seq; + struct list_head list; +}; + struct l2cap_chan { struct sock *sk; __u8 ident; @@ -312,6 +317,7 @@ struct l2cap_chan { struct sk_buff_head srej_q; struct sk_buff_head busy_q; struct work_struct busy_work; + struct list_head srej_l; struct list_head list; }; @@ -350,12 +356,6 @@ struct l2cap_conn { /* ----- L2CAP socket info ----- */ #define l2cap_pi(sk) ((struct l2cap_pinfo *) sk) #define TX_QUEUE(sk) (&l2cap_pi(sk)->tx_queue) -#define SREJ_LIST(sk) (&l2cap_pi(sk)->srej_l.list) - -struct srej_list { - __u8 tx_seq; - struct list_head list; -}; struct l2cap_pinfo { struct bt_sock bt; @@ -385,7 +385,6 @@ struct l2cap_pinfo { __le16 sport; struct sk_buff_head tx_queue; - struct srej_list srej_l; struct l2cap_conn *conn; struct l2cap_chan *chan; }; diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index 7264119..9580d6c 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -252,7 +252,7 @@ void l2cap_chan_del(struct l2cap_chan *chan, int err) skb_queue_purge(&chan->srej_q); skb_queue_purge(&chan->busy_q); - list_for_each_entry_safe(l, tmp, SREJ_LIST(sk), list) { + list_for_each_entry_safe(l, tmp, &chan->srej_l, list) { list_del(&l->list); kfree(l); } @@ -1205,7 +1205,7 @@ static void l2cap_send_srejtail(struct l2cap_chan *chan) control = L2CAP_SUPER_SELECT_REJECT; control |= L2CAP_CTRL_FINAL; - tail = list_entry(SREJ_LIST(chan->sk)->prev, struct srej_list, list); + tail = list_entry((&chan->srej_l)->prev, struct srej_list, list); control |= tail->tx_seq << L2CAP_CTRL_REQSEQ_SHIFT; l2cap_send_sframe(chan, control); @@ -1596,6 +1596,8 @@ static inline void l2cap_ertm_init(struct l2cap_chan *chan) skb_queue_head_init(&chan->srej_q); skb_queue_head_init(&chan->busy_q); + INIT_LIST_HEAD(&chan->srej_l); + INIT_WORK(&chan->busy_work, l2cap_busy_work); sk->sk_backlog_rcv = l2cap_ertm_data_rcv; @@ -3207,11 +3209,10 @@ static void l2cap_check_srej_gap(struct l2cap_chan *chan, u8 tx_seq) static void l2cap_resend_srejframe(struct l2cap_chan *chan, u8 tx_seq) { - struct sock *sk = chan->sk; struct srej_list *l, *tmp; u16 control; - list_for_each_entry_safe(l, tmp, SREJ_LIST(sk), list) { + list_for_each_entry_safe(l, tmp, &chan->srej_l, list) { if (l->tx_seq == tx_seq) { list_del(&l->list); kfree(l); @@ -3221,13 +3222,12 @@ static void l2cap_resend_srejframe(struct l2cap_chan *chan, u8 tx_seq) control |= l->tx_seq << L2CAP_CTRL_REQSEQ_SHIFT; l2cap_send_sframe(chan, control); list_del(&l->list); - list_add_tail(&l->list, SREJ_LIST(sk)); + list_add_tail(&l->list, &chan->srej_l); } } static void l2cap_send_srejframe(struct l2cap_chan *chan, u8 tx_seq) { - struct sock *sk = chan->sk; struct srej_list *new; u16 control; @@ -3239,7 +3239,7 @@ static void l2cap_send_srejframe(struct l2cap_chan *chan, u8 tx_seq) new = kzalloc(sizeof(struct srej_list), GFP_ATOMIC); new->tx_seq = chan->expected_tx_seq; chan->expected_tx_seq = (chan->expected_tx_seq + 1) % 64; - list_add_tail(&new->list, SREJ_LIST(sk)); + list_add_tail(&new->list, &chan->srej_l); } chan->expected_tx_seq = (chan->expected_tx_seq + 1) % 64; } @@ -3288,7 +3288,7 @@ static inline int l2cap_data_channel_iframe(struct l2cap_chan *chan, u16 rx_cont if (chan->conn_state & L2CAP_CONN_SREJ_SENT) { struct srej_list *first; - first = list_first_entry(SREJ_LIST(sk), + first = list_first_entry(&chan->srej_l, struct srej_list, list); if (tx_seq == first->tx_seq) { l2cap_add_to_srej_queue(chan, skb, tx_seq, sar); @@ -3297,7 +3297,7 @@ static inline int l2cap_data_channel_iframe(struct l2cap_chan *chan, u16 rx_cont list_del(&first->list); kfree(first); - if (list_empty(SREJ_LIST(sk))) { + if (list_empty(&chan->srej_l)) { chan->buffer_seq = chan->buffer_seq_srej; chan->conn_state &= ~L2CAP_CONN_SREJ_SENT; l2cap_send_ack(chan); @@ -3310,7 +3310,7 @@ static inline int l2cap_data_channel_iframe(struct l2cap_chan *chan, u16 rx_cont if (l2cap_add_to_srej_queue(chan, skb, tx_seq, sar) < 0) goto drop; - list_for_each_entry(l, SREJ_LIST(sk), list) { + list_for_each_entry(l, &chan->srej_l, list) { if (l->tx_seq == tx_seq) { l2cap_resend_srejframe(chan, tx_seq); return 0; @@ -3332,7 +3332,7 @@ static inline int l2cap_data_channel_iframe(struct l2cap_chan *chan, u16 rx_cont BT_DBG("sk %p, Enter SREJ", sk); - INIT_LIST_HEAD(SREJ_LIST(sk)); + INIT_LIST_HEAD(&chan->srej_l); chan->buffer_seq_srej = chan->buffer_seq; __skb_queue_head_init(&chan->srej_q); diff --git a/net/bluetooth/l2cap_sock.c b/net/bluetooth/l2cap_sock.c index 55dee99..16a223b 100644 --- a/net/bluetooth/l2cap_sock.c +++ b/net/bluetooth/l2cap_sock.c @@ -1018,7 +1018,6 @@ void l2cap_sock_init(struct sock *sk, struct sock *parent) /* Default config options */ pi->flush_to = L2CAP_DEFAULT_FLUSH_TO; skb_queue_head_init(TX_QUEUE(sk)); - INIT_LIST_HEAD(SREJ_LIST(sk)); } static struct proto l2cap_proto = { -- cgit v0.10.2 From 49208c9c7b483098401683fef5cfbd66931ca643 Mon Sep 17 00:00:00 2001 From: "Gustavo F. Padovan" Date: Mon, 4 Apr 2011 15:59:54 -0300 Subject: Bluetooth: Remove some sk references from l2cap_core.c Change some BT_DBG messages and consequently remove some struct sock declarations. Signed-off-by: Gustavo F. Padovan diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index 9580d6c..0edfa65 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -211,7 +211,7 @@ void l2cap_chan_del(struct l2cap_chan *chan, int err) l2cap_sock_clear_timer(sk); - BT_DBG("sk %p, conn %p, err %d", sk, conn, err); + BT_DBG("chan %p, conn %p, err %d", chan, conn, err); if (conn) { /* Delete from channel list */ @@ -361,7 +361,7 @@ static inline void l2cap_send_sframe(struct l2cap_chan *chan, u16 control) if (pi->fcs == L2CAP_FCS_CRC16) hlen += 2; - BT_DBG("pi %p, control 0x%2.2x", pi, control); + BT_DBG("chan %p, control 0x%2.2x", chan, control); count = min_t(unsigned int, conn->mtu, hlen); control |= L2CAP_CTRL_FRAME_TYPE; @@ -982,7 +982,7 @@ static void l2cap_retrans_timeout(unsigned long arg) struct l2cap_chan *chan = (void *) arg; struct sock *sk = chan->sk; - BT_DBG("sk %p", sk); + BT_DBG("chan %p", chan); bh_lock_sock(sk); chan->retry_count = 1; @@ -1618,13 +1618,12 @@ static inline __u8 l2cap_select_mode(__u8 mode, __u16 remote_feat_mask) static int l2cap_build_conf_req(struct l2cap_chan *chan, void *data) { - struct sock *sk = chan->sk; - struct l2cap_pinfo *pi = l2cap_pi(sk); + struct l2cap_pinfo *pi = l2cap_pi(chan->sk); struct l2cap_conf_req *req = data; struct l2cap_conf_rfc rfc = { .mode = pi->mode }; void *ptr = req->data; - BT_DBG("sk %p", sk); + BT_DBG("chan %p", chan); if (chan->num_conf_req || chan->num_conf_rsp) goto done; @@ -2972,7 +2971,6 @@ disconnect: static int l2cap_try_push_rx_skb(struct l2cap_chan *chan) { - struct sock *sk = chan->sk; struct sk_buff *skb; u16 control; int err; @@ -3005,7 +3003,7 @@ done: chan->conn_state &= ~L2CAP_CONN_LOCAL_BUSY; chan->conn_state &= ~L2CAP_CONN_RNR_SENT; - BT_DBG("sk %p, Exit local busy", sk); + BT_DBG("chan %p, Exit local busy", chan); return 0; } @@ -3246,8 +3244,7 @@ static void l2cap_send_srejframe(struct l2cap_chan *chan, u8 tx_seq) static inline int l2cap_data_channel_iframe(struct l2cap_chan *chan, u16 rx_control, struct sk_buff *skb) { - struct sock *sk = chan->sk; - struct l2cap_pinfo *pi = l2cap_pi(sk); + struct l2cap_pinfo *pi = l2cap_pi(chan->sk); u8 tx_seq = __get_txseq(rx_control); u8 req_seq = __get_reqseq(rx_control); u8 sar = rx_control >> L2CAP_CTRL_SAR_SHIFT; @@ -3301,7 +3298,7 @@ static inline int l2cap_data_channel_iframe(struct l2cap_chan *chan, u16 rx_cont chan->buffer_seq = chan->buffer_seq_srej; chan->conn_state &= ~L2CAP_CONN_SREJ_SENT; l2cap_send_ack(chan); - BT_DBG("sk %p, Exit SREJ_SENT", sk); + BT_DBG("chan %p, Exit SREJ_SENT", chan); } } else { struct srej_list *l; @@ -3330,7 +3327,7 @@ static inline int l2cap_data_channel_iframe(struct l2cap_chan *chan, u16 rx_cont chan->conn_state |= L2CAP_CONN_SREJ_SENT; - BT_DBG("sk %p, Enter SREJ", sk); + BT_DBG("chan %p, Enter SREJ", chan); INIT_LIST_HEAD(&chan->srej_l); chan->buffer_seq_srej = chan->buffer_seq; @@ -3383,9 +3380,7 @@ drop: static inline void l2cap_data_channel_rrframe(struct l2cap_chan *chan, u16 rx_control) { - struct sock *sk = chan->sk; - - BT_DBG("sk %p, req_seq %d ctrl 0x%4.4x", sk, __get_reqseq(rx_control), + BT_DBG("chan %p, req_seq %d ctrl 0x%4.4x", chan, __get_reqseq(rx_control), rx_control); chan->expected_ack_seq = __get_reqseq(rx_control); @@ -3633,7 +3628,7 @@ static inline int l2cap_data_channel(struct l2cap_conn *conn, u16 cid, struct sk sk = chan->sk; pi = l2cap_pi(sk); - BT_DBG("sk %p, len %d", sk, skb->len); + BT_DBG("chan %p, len %d", chan, skb->len); if (sk->sk_state != BT_CONNECTED) goto drop; @@ -3691,7 +3686,7 @@ static inline int l2cap_data_channel(struct l2cap_conn *conn, u16 cid, struct sk goto done; default: - BT_DBG("sk %p: bad mode 0x%2.2x", sk, pi->mode); + BT_DBG("chan %p: bad mode 0x%2.2x", chan, pi->mode); break; } -- cgit v0.10.2 From c916fbe45c1f30417fa28e62cbbfae295a3f315c Mon Sep 17 00:00:00 2001 From: "Gustavo F. Padovan" Date: Mon, 4 Apr 2011 16:00:55 -0300 Subject: Bluetooth: Remove unneeded uninitialized_vars() That was unnecessary use of it. Signed-off-by: Gustavo F. Padovan diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index 0edfa65..5fc852a 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -623,7 +623,7 @@ static struct sock *l2cap_get_sock_by_scid(int state, __le16 cid, bdaddr_t *src) static void l2cap_le_conn_ready(struct l2cap_conn *conn) { - struct sock *parent, *uninitialized_var(sk); + struct sock *parent, *sk; struct l2cap_chan *chan; BT_DBG(""); -- cgit v0.10.2 From 58d35f87effa0235181a24d55576aaa756ef7312 Mon Sep 17 00:00:00 2001 From: "Gustavo F. Padovan" Date: Mon, 4 Apr 2011 16:16:44 -0300 Subject: Bluetooth: Move tx queue to struct l2cap_chan tx_q is the queue used by ERTM mode. Signed-off-by: Gustavo F. Padovan diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h index ec56d88..7a215a7 100644 --- a/include/net/bluetooth/l2cap.h +++ b/include/net/bluetooth/l2cap.h @@ -314,6 +314,8 @@ struct l2cap_chan { struct timer_list retrans_timer; struct timer_list monitor_timer; struct timer_list ack_timer; + struct sk_buff *tx_send_head; + struct sk_buff_head tx_q; struct sk_buff_head srej_q; struct sk_buff_head busy_q; struct work_struct busy_work; @@ -355,7 +357,6 @@ struct l2cap_conn { /* ----- L2CAP socket info ----- */ #define l2cap_pi(sk) ((struct l2cap_pinfo *) sk) -#define TX_QUEUE(sk) (&l2cap_pi(sk)->tx_queue) struct l2cap_pinfo { struct bt_sock bt; @@ -384,7 +385,6 @@ struct l2cap_pinfo { __le16 sport; - struct sk_buff_head tx_queue; struct l2cap_conn *conn; struct l2cap_chan *chan; }; diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index 5fc852a..9782750 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -240,7 +240,7 @@ void l2cap_chan_del(struct l2cap_chan *chan, int err) l2cap_pi(sk)->conf_state & L2CAP_CONF_INPUT_DONE)) goto free; - skb_queue_purge(TX_QUEUE(sk)); + skb_queue_purge(&chan->tx_q); if (l2cap_pi(sk)->mode == L2CAP_MODE_ERTM) { struct srej_list *l, *tmp; @@ -477,7 +477,7 @@ void l2cap_send_disconn_req(struct l2cap_conn *conn, struct l2cap_chan *chan, in sk = chan->sk; - skb_queue_purge(TX_QUEUE(sk)); + skb_queue_purge(&chan->tx_q); if (l2cap_pi(sk)->mode == L2CAP_MODE_ERTM) { del_timer(&chan->retrans_timer); @@ -996,15 +996,14 @@ static void l2cap_retrans_timeout(unsigned long arg) static void l2cap_drop_acked_frames(struct l2cap_chan *chan) { - struct sock *sk = chan->sk; struct sk_buff *skb; - while ((skb = skb_peek(TX_QUEUE(sk))) && + while ((skb = skb_peek(&chan->tx_q)) && chan->unacked_frames) { if (bt_cb(skb)->tx_seq == chan->expected_ack_seq) break; - skb = skb_dequeue(TX_QUEUE(sk)); + skb = skb_dequeue(&chan->tx_q); kfree_skb(skb); chan->unacked_frames--; @@ -1037,7 +1036,7 @@ void l2cap_streaming_send(struct l2cap_chan *chan) struct l2cap_pinfo *pi = l2cap_pi(sk); u16 control, fcs; - while ((skb = skb_dequeue(TX_QUEUE(sk)))) { + while ((skb = skb_dequeue(&chan->tx_q))) { control = get_unaligned_le16(skb->data + L2CAP_HDR_SIZE); control |= chan->next_tx_seq << L2CAP_CTRL_TXSEQ_SHIFT; put_unaligned_le16(control, skb->data + L2CAP_HDR_SIZE); @@ -1060,7 +1059,7 @@ static void l2cap_retransmit_one_frame(struct l2cap_chan *chan, u8 tx_seq) struct sk_buff *skb, *tx_skb; u16 control, fcs; - skb = skb_peek(TX_QUEUE(sk)); + skb = skb_peek(&chan->tx_q); if (!skb) return; @@ -1068,10 +1067,10 @@ static void l2cap_retransmit_one_frame(struct l2cap_chan *chan, u8 tx_seq) if (bt_cb(skb)->tx_seq == tx_seq) break; - if (skb_queue_is_last(TX_QUEUE(sk), skb)) + if (skb_queue_is_last(&chan->tx_q, skb)) return; - } while ((skb = skb_queue_next(TX_QUEUE(sk), skb))); + } while ((skb = skb_queue_next(&chan->tx_q, skb))); if (chan->remote_max_tx && bt_cb(skb)->retries == chan->remote_max_tx) { @@ -1112,7 +1111,7 @@ int l2cap_ertm_send(struct l2cap_chan *chan) if (sk->sk_state != BT_CONNECTED) return -ENOTCONN; - while ((skb = sk->sk_send_head) && (!l2cap_tx_window_full(chan))) { + while ((skb = chan->tx_send_head) && (!l2cap_tx_window_full(chan))) { if (chan->remote_max_tx && bt_cb(skb)->retries == chan->remote_max_tx) { @@ -1153,10 +1152,10 @@ int l2cap_ertm_send(struct l2cap_chan *chan) chan->frames_sent++; - if (skb_queue_is_last(TX_QUEUE(sk), skb)) - sk->sk_send_head = NULL; + if (skb_queue_is_last(&chan->tx_q, skb)) + chan->tx_send_head = NULL; else - sk->sk_send_head = skb_queue_next(TX_QUEUE(sk), skb); + chan->tx_send_head = skb_queue_next(&chan->tx_q, skb); nsent++; } @@ -1166,11 +1165,10 @@ int l2cap_ertm_send(struct l2cap_chan *chan) static int l2cap_retransmit_frames(struct l2cap_chan *chan) { - struct sock *sk = chan->sk; int ret; - if (!skb_queue_empty(TX_QUEUE(sk))) - sk->sk_send_head = TX_QUEUE(sk)->next; + if (!skb_queue_empty(&chan->tx_q)) + chan->tx_send_head = chan->tx_q.next; chan->next_tx_seq = chan->expected_ack_seq; ret = l2cap_ertm_send(chan); @@ -1384,9 +1382,9 @@ int l2cap_sar_segment_sdu(struct l2cap_chan *chan, struct msghdr *msg, size_t le len -= buflen; size += buflen; } - skb_queue_splice_tail(&sar_queue, TX_QUEUE(sk)); - if (sk->sk_send_head == NULL) - sk->sk_send_head = sar_queue.next; + skb_queue_splice_tail(&sar_queue, &chan->tx_q); + if (chan->tx_send_head == NULL) + chan->tx_send_head = sar_queue.next; return size; } @@ -2319,7 +2317,7 @@ static inline int l2cap_config_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr chan->next_tx_seq = 0; chan->expected_tx_seq = 0; - __skb_queue_head_init(TX_QUEUE(sk)); + skb_queue_head_init(&chan->tx_q); if (l2cap_pi(sk)->mode == L2CAP_MODE_ERTM) l2cap_ertm_init(chan); @@ -2410,7 +2408,7 @@ static inline int l2cap_config_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hdr sk->sk_state = BT_CONNECTED; chan->next_tx_seq = 0; chan->expected_tx_seq = 0; - __skb_queue_head_init(TX_QUEUE(sk)); + skb_queue_head_init(&chan->tx_q); if (l2cap_pi(sk)->mode == L2CAP_MODE_ERTM) l2cap_ertm_init(chan); diff --git a/net/bluetooth/l2cap_sock.c b/net/bluetooth/l2cap_sock.c index 16a223b..b2bfa1e 100644 --- a/net/bluetooth/l2cap_sock.c +++ b/net/bluetooth/l2cap_sock.c @@ -764,10 +764,10 @@ static int l2cap_sock_sendmsg(struct kiocb *iocb, struct socket *sock, struct ms err = PTR_ERR(skb); goto done; } - __skb_queue_tail(TX_QUEUE(sk), skb); + __skb_queue_tail(&pi->chan->tx_q, skb); - if (sk->sk_send_head == NULL) - sk->sk_send_head = skb; + if (pi->chan->tx_send_head == NULL) + pi->chan->tx_send_head = skb; } else { /* Segment SDU into multiples PDUs */ @@ -1017,7 +1017,6 @@ void l2cap_sock_init(struct sock *sk, struct sock *parent) /* Default config options */ pi->flush_to = L2CAP_DEFAULT_FLUSH_TO; - skb_queue_head_init(TX_QUEUE(sk)); } static struct proto l2cap_proto = { -- cgit v0.10.2 From cd69a03af1106c486033df600c7945957ea5abeb Mon Sep 17 00:00:00 2001 From: "Gustavo F. Padovan" Date: Tue, 5 Apr 2011 15:24:40 -0300 Subject: Bluetooth: Fix wrong comparison in listen() We should check for the pi->scid there. Signed-off-by: Gustavo F. Padovan diff --git a/net/bluetooth/l2cap_sock.c b/net/bluetooth/l2cap_sock.c index b2bfa1e..473e597 100644 --- a/net/bluetooth/l2cap_sock.c +++ b/net/bluetooth/l2cap_sock.c @@ -269,7 +269,7 @@ static int l2cap_sock_listen(struct socket *sock, int backlog) goto done; } - if (!l2cap_pi(sk)->psm && !l2cap_pi(sk)->dcid) { + if (!l2cap_pi(sk)->psm && !l2cap_pi(sk)->scid) { bdaddr_t *src = &bt_sk(sk)->src; u16 psm; -- cgit v0.10.2 From 0733119c0bed37eda4bb832d049939a0dc53a233 Mon Sep 17 00:00:00 2001 From: "Gustavo F. Padovan" Date: Tue, 5 Apr 2011 22:29:31 -0300 Subject: Bluetooth: Clean up ath3k_load_firmware() Signed-off-by: Gustavo F. Padovan diff --git a/drivers/bluetooth/ath3k.c b/drivers/bluetooth/ath3k.c index 5577ed6..695d441 100644 --- a/drivers/bluetooth/ath3k.c +++ b/drivers/bluetooth/ath3k.c @@ -138,9 +138,6 @@ static int ath3k_load_firmware(struct usb_device *udev, count -= size; } - kfree(send_buf); - return 0; - error: kfree(send_buf); return err; -- cgit v0.10.2 From 9f69bda6aa8b365169b4a6fd35432ee40574d661 Mon Sep 17 00:00:00 2001 From: "Gustavo F. Padovan" Date: Thu, 7 Apr 2011 16:40:25 -0300 Subject: Bluetooth: Add proper handling of received LE data Despite it works, handling through l2cap_data_channel() is wrongs. That function should handle only connection oriented data. Signed-off-by: Gustavo F. Padovan diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index 9782750..c9c1f92 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -3728,6 +3728,36 @@ done: return 0; } +static inline int l2cap_att_channel(struct l2cap_conn *conn, __le16 cid, struct sk_buff *skb) +{ + struct sock *sk; + + sk = l2cap_get_sock_by_scid(0, cid, conn->src); + if (!sk) + goto drop; + + bh_lock_sock(sk); + + BT_DBG("sk %p, len %d", sk, skb->len); + + if (sk->sk_state != BT_BOUND && sk->sk_state != BT_CONNECTED) + goto drop; + + if (l2cap_pi(sk)->imtu < skb->len) + goto drop; + + if (!sock_queue_rcv_skb(sk, skb)) + goto done; + +drop: + kfree_skb(skb); + +done: + if (sk) + bh_unlock_sock(sk); + return 0; +} + static void l2cap_recv_frame(struct l2cap_conn *conn, struct sk_buff *skb) { struct l2cap_hdr *lh = (void *) skb->data; @@ -3757,6 +3787,10 @@ static void l2cap_recv_frame(struct l2cap_conn *conn, struct sk_buff *skb) l2cap_conless_channel(conn, psm, skb); break; + case L2CAP_CID_LE_DATA: + l2cap_att_channel(conn, cid, skb); + break; + default: l2cap_data_channel(conn, cid, skb); break; -- cgit v0.10.2 From e1ba1f15469903b6f443fbf00f069d169e3fba6d Mon Sep 17 00:00:00 2001 From: Szymon Janc Date: Wed, 6 Apr 2011 13:01:59 +0200 Subject: Bluetooth: Fix Out Of Band pairing when mgmt interface is disabled Use kernel stored remote Out Of Band data only if management interface is enabled. Otherwise HCI_OP_REMOTE_OOB_DATA_NEG_REPLY was sent to controller even if remote Out Of Band data was present in bluetoothd. Signed-off-by: Szymon Janc Signed-off-by: Gustavo F. Padovan diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index 7a3398d..c7eb073 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -2497,6 +2497,9 @@ static inline void hci_remote_oob_data_request_evt(struct hci_dev *hdev, hci_dev_lock(hdev); + if (!test_bit(HCI_MGMT, &hdev->flags)) + goto unlock; + data = hci_find_remote_oob_data(hdev, &ev->bdaddr); if (data) { struct hci_cp_remote_oob_data_reply cp; @@ -2515,6 +2518,7 @@ static inline void hci_remote_oob_data_request_evt(struct hci_dev *hdev, &cp); } +unlock: hci_dev_unlock(hdev); } -- cgit v0.10.2 From 78b4a56c28c096a1eb02f1d864eb450eb910e43d Mon Sep 17 00:00:00 2001 From: Jiejing Zhang Date: Thu, 7 Apr 2011 20:37:06 +0800 Subject: Bluetooth: hci_uart: check the return value of recv() Check the return value of hu->proto->recv() in hci_uart_tty_receive() the recv() may return error, check it, not add this to statistics. Signed-off-by: Jiejing Zhang Signed-off-by: Gustavo F. Padovan diff --git a/drivers/bluetooth/hci_ath.c b/drivers/bluetooth/hci_ath.c index bd34406..4093935 100644 --- a/drivers/bluetooth/hci_ath.c +++ b/drivers/bluetooth/hci_ath.c @@ -201,8 +201,13 @@ static struct sk_buff *ath_dequeue(struct hci_uart *hu) /* Recv data */ static int ath_recv(struct hci_uart *hu, void *data, int count) { - if (hci_recv_stream_fragment(hu->hdev, data, count) < 0) + int ret; + + ret = hci_recv_stream_fragment(hu->hdev, data, count); + if (ret < 0) { BT_ERR("Frame Reassembly Failed"); + return ret; + } return count; } diff --git a/drivers/bluetooth/hci_ldisc.c b/drivers/bluetooth/hci_ldisc.c index 48ad2a7..320f718 100644 --- a/drivers/bluetooth/hci_ldisc.c +++ b/drivers/bluetooth/hci_ldisc.c @@ -359,6 +359,7 @@ static void hci_uart_tty_wakeup(struct tty_struct *tty) */ static void hci_uart_tty_receive(struct tty_struct *tty, const u8 *data, char *flags, int count) { + int ret; struct hci_uart *hu = (void *)tty->disc_data; if (!hu || tty != hu->tty) @@ -368,8 +369,9 @@ static void hci_uart_tty_receive(struct tty_struct *tty, const u8 *data, char *f return; spin_lock(&hu->rx_lock); - hu->proto->recv(hu, (void *) data, count); - hu->hdev->stat.byte_rx += count; + ret = hu->proto->recv(hu, (void *) data, count); + if (ret > 0) + hu->hdev->stat.byte_rx += count; spin_unlock(&hu->rx_lock); tty_unthrottle(tty); -- cgit v0.10.2 From b86ed368f1f0b19de1918c57e4b056e73d5613a0 Mon Sep 17 00:00:00 2001 From: "Gustavo F. Padovan" Date: Thu, 7 Apr 2011 18:53:45 -0300 Subject: Bluetooth: Check return value of hci_recv_stream_fragment() It may return error and in this case we do add to the stats. Signed-off-by: Gustavo F. Padovan diff --git a/drivers/bluetooth/hci_h4.c b/drivers/bluetooth/hci_h4.c index 7b8ad93..2fcd8b3 100644 --- a/drivers/bluetooth/hci_h4.c +++ b/drivers/bluetooth/hci_h4.c @@ -151,8 +151,13 @@ static inline int h4_check_data_len(struct h4_struct *h4, int len) /* Recv data */ static int h4_recv(struct hci_uart *hu, void *data, int count) { - if (hci_recv_stream_fragment(hu->hdev, data, count) < 0) + int ret; + + ret = hci_recv_stream_fragment(hu->hdev, data, count); + if (ret < 0) { BT_ERR("Frame Reassembly Failed"); + return ret; + } return count; } -- cgit v0.10.2 From 9f72c1d977e47a7d182d49ea131067cba0a96ab8 Mon Sep 17 00:00:00 2001 From: Kevin Gan Date: Fri, 8 Apr 2011 18:19:33 -0700 Subject: Bluetooth: btmrvl: support Marvell Bluetooth device SD8787 The SD8787 firmware image is shared with mwifiex driver. Whoever gets loaded first will be responsible for firmware downloading. Signed-off-by: Kevin Gan Signed-off-by: Tristan Xu Signed-off-by: Bing Zhao Signed-off-by: Gustavo F. Padovan diff --git a/drivers/bluetooth/Kconfig b/drivers/bluetooth/Kconfig index 8e0de9a..11b41fd 100644 --- a/drivers/bluetooth/Kconfig +++ b/drivers/bluetooth/Kconfig @@ -188,7 +188,7 @@ config BT_MRVL The core driver to support Marvell Bluetooth devices. This driver is required if you want to support - Marvell Bluetooth devices, such as 8688. + Marvell Bluetooth devices, such as 8688/8787. Say Y here to compile Marvell Bluetooth driver into the kernel or say M to compile it as module. @@ -201,7 +201,7 @@ config BT_MRVL_SDIO The driver for Marvell Bluetooth chipsets with SDIO interface. This driver is required if you want to use Marvell Bluetooth - devices with SDIO interface. Currently only SD8688 chipset is + devices with SDIO interface. Currently SD8688/SD8787 chipsets are supported. Say Y here to compile support for Marvell BT-over-SDIO driver diff --git a/drivers/bluetooth/btmrvl_sdio.c b/drivers/bluetooth/btmrvl_sdio.c index dcc2a6e..7f521d4 100644 --- a/drivers/bluetooth/btmrvl_sdio.c +++ b/drivers/bluetooth/btmrvl_sdio.c @@ -49,15 +49,59 @@ static u8 user_rmmod; static u8 sdio_ireg; +static const struct btmrvl_sdio_card_reg btmrvl_reg_8688 = { + .cfg = 0x03, + .host_int_mask = 0x04, + .host_intstatus = 0x05, + .card_status = 0x20, + .sq_read_base_addr_a0 = 0x10, + .sq_read_base_addr_a1 = 0x11, + .card_fw_status0 = 0x40, + .card_fw_status1 = 0x41, + .card_rx_len = 0x42, + .card_rx_unit = 0x43, + .io_port_0 = 0x00, + .io_port_1 = 0x01, + .io_port_2 = 0x02, +}; +static const struct btmrvl_sdio_card_reg btmrvl_reg_8787 = { + .cfg = 0x00, + .host_int_mask = 0x02, + .host_intstatus = 0x03, + .card_status = 0x30, + .sq_read_base_addr_a0 = 0x40, + .sq_read_base_addr_a1 = 0x41, + .card_revision = 0x5c, + .card_fw_status0 = 0x60, + .card_fw_status1 = 0x61, + .card_rx_len = 0x62, + .card_rx_unit = 0x63, + .io_port_0 = 0x78, + .io_port_1 = 0x79, + .io_port_2 = 0x7a, +}; + static const struct btmrvl_sdio_device btmrvl_sdio_sd6888 = { .helper = "sd8688_helper.bin", .firmware = "sd8688.bin", + .reg = &btmrvl_reg_8688, + .sd_blksz_fw_dl = 64, +}; + +static const struct btmrvl_sdio_device btmrvl_sdio_sd8787 = { + .helper = NULL, + .firmware = "mrvl/sd8787_uapsta.bin", + .reg = &btmrvl_reg_8787, + .sd_blksz_fw_dl = 256, }; static const struct sdio_device_id btmrvl_sdio_ids[] = { /* Marvell SD8688 Bluetooth device */ { SDIO_DEVICE(SDIO_VENDOR_ID_MARVELL, 0x9105), .driver_data = (unsigned long) &btmrvl_sdio_sd6888 }, + /* Marvell SD8787 Bluetooth device */ + { SDIO_DEVICE(SDIO_VENDOR_ID_MARVELL, 0x911A), + .driver_data = (unsigned long) &btmrvl_sdio_sd8787 }, { } /* Terminating entry */ }; @@ -69,7 +113,7 @@ static int btmrvl_sdio_get_rx_unit(struct btmrvl_sdio_card *card) u8 reg; int ret; - reg = sdio_readb(card->func, CARD_RX_UNIT_REG, &ret); + reg = sdio_readb(card->func, card->reg->card_rx_unit, &ret); if (!ret) card->rx_unit = reg; @@ -83,11 +127,11 @@ static int btmrvl_sdio_read_fw_status(struct btmrvl_sdio_card *card, u16 *dat) *dat = 0; - fws0 = sdio_readb(card->func, CARD_FW_STATUS0_REG, &ret); + fws0 = sdio_readb(card->func, card->reg->card_fw_status0, &ret); if (ret) return -EIO; - fws1 = sdio_readb(card->func, CARD_FW_STATUS1_REG, &ret); + fws1 = sdio_readb(card->func, card->reg->card_fw_status1, &ret); if (ret) return -EIO; @@ -101,7 +145,7 @@ static int btmrvl_sdio_read_rx_len(struct btmrvl_sdio_card *card, u16 *dat) u8 reg; int ret; - reg = sdio_readb(card->func, CARD_RX_LEN_REG, &ret); + reg = sdio_readb(card->func, card->reg->card_rx_len, &ret); if (!ret) *dat = (u16) reg << card->rx_unit; @@ -113,7 +157,7 @@ static int btmrvl_sdio_enable_host_int_mask(struct btmrvl_sdio_card *card, { int ret; - sdio_writeb(card->func, mask, HOST_INT_MASK_REG, &ret); + sdio_writeb(card->func, mask, card->reg->host_int_mask, &ret); if (ret) { BT_ERR("Unable to enable the host interrupt!"); ret = -EIO; @@ -128,13 +172,13 @@ static int btmrvl_sdio_disable_host_int_mask(struct btmrvl_sdio_card *card, u8 host_int_mask; int ret; - host_int_mask = sdio_readb(card->func, HOST_INT_MASK_REG, &ret); + host_int_mask = sdio_readb(card->func, card->reg->host_int_mask, &ret); if (ret) return -EIO; host_int_mask &= ~mask; - sdio_writeb(card->func, host_int_mask, HOST_INT_MASK_REG, &ret); + sdio_writeb(card->func, host_int_mask, card->reg->host_int_mask, &ret); if (ret < 0) { BT_ERR("Unable to disable the host interrupt!"); return -EIO; @@ -150,7 +194,7 @@ static int btmrvl_sdio_poll_card_status(struct btmrvl_sdio_card *card, u8 bits) int ret; for (tries = 0; tries < MAX_POLL_TRIES * 1000; tries++) { - status = sdio_readb(card->func, CARD_STATUS_REG, &ret); + status = sdio_readb(card->func, card->reg->card_status, &ret); if (ret) goto failed; if ((status & bits) == bits) @@ -299,7 +343,7 @@ static int btmrvl_sdio_download_fw_w_helper(struct btmrvl_sdio_card *card) u8 base0, base1; void *tmpfwbuf = NULL; u8 *fwbuf; - u16 len; + u16 len, blksz_dl = card->sd_blksz_fw_dl; int txlen = 0, tx_blocks = 0, count = 0; ret = request_firmware(&fw_firmware, card->firmware, @@ -345,7 +389,7 @@ static int btmrvl_sdio_download_fw_w_helper(struct btmrvl_sdio_card *card) for (tries = 0; tries < MAX_POLL_TRIES; tries++) { base0 = sdio_readb(card->func, - SQ_READ_BASE_ADDRESS_A0_REG, &ret); + card->reg->sq_read_base_addr_a0, &ret); if (ret) { BT_ERR("BASE0 register read failed:" " base0 = 0x%04X(%d)." @@ -355,7 +399,7 @@ static int btmrvl_sdio_download_fw_w_helper(struct btmrvl_sdio_card *card) goto done; } base1 = sdio_readb(card->func, - SQ_READ_BASE_ADDRESS_A1_REG, &ret); + card->reg->sq_read_base_addr_a1, &ret); if (ret) { BT_ERR("BASE1 register read failed:" " base1 = 0x%04X(%d)." @@ -403,20 +447,19 @@ static int btmrvl_sdio_download_fw_w_helper(struct btmrvl_sdio_card *card) if (firmwarelen - offset < txlen) txlen = firmwarelen - offset; - tx_blocks = - (txlen + SDIO_BLOCK_SIZE - 1) / SDIO_BLOCK_SIZE; + tx_blocks = (txlen + blksz_dl - 1) / blksz_dl; memcpy(fwbuf, &firmware[offset], txlen); } ret = sdio_writesb(card->func, card->ioport, fwbuf, - tx_blocks * SDIO_BLOCK_SIZE); + tx_blocks * blksz_dl); if (ret < 0) { BT_ERR("FW download, writesb(%d) failed @%d", count, offset); - sdio_writeb(card->func, HOST_CMD53_FIN, CONFIG_REG, - &ret); + sdio_writeb(card->func, HOST_CMD53_FIN, + card->reg->cfg, &ret); if (ret) BT_ERR("writeb failed (CFG)"); } @@ -597,7 +640,7 @@ static void btmrvl_sdio_interrupt(struct sdio_func *func) priv = card->priv; - ireg = sdio_readb(card->func, HOST_INTSTATUS_REG, &ret); + ireg = sdio_readb(card->func, card->reg->host_intstatus, &ret); if (ret) { BT_ERR("sdio_readb: read int status register failed"); return; @@ -613,7 +656,7 @@ static void btmrvl_sdio_interrupt(struct sdio_func *func) sdio_writeb(card->func, ~(ireg) & (DN_LD_HOST_INT_STATUS | UP_LD_HOST_INT_STATUS), - HOST_INTSTATUS_REG, &ret); + card->reg->host_intstatus, &ret); if (ret) { BT_ERR("sdio_writeb: clear int status register failed"); return; @@ -664,7 +707,7 @@ static int btmrvl_sdio_register_dev(struct btmrvl_sdio_card *card) goto release_irq; } - reg = sdio_readb(func, IO_PORT_0_REG, &ret); + reg = sdio_readb(func, card->reg->io_port_0, &ret); if (ret < 0) { ret = -EIO; goto release_irq; @@ -672,7 +715,7 @@ static int btmrvl_sdio_register_dev(struct btmrvl_sdio_card *card) card->ioport = reg; - reg = sdio_readb(func, IO_PORT_1_REG, &ret); + reg = sdio_readb(func, card->reg->io_port_1, &ret); if (ret < 0) { ret = -EIO; goto release_irq; @@ -680,7 +723,7 @@ static int btmrvl_sdio_register_dev(struct btmrvl_sdio_card *card) card->ioport |= (reg << 8); - reg = sdio_readb(func, IO_PORT_2_REG, &ret); + reg = sdio_readb(func, card->reg->io_port_2, &ret); if (ret < 0) { ret = -EIO; goto release_irq; @@ -815,6 +858,8 @@ exit: static int btmrvl_sdio_download_fw(struct btmrvl_sdio_card *card) { int ret = 0; + u8 fws0; + int pollnum = MAX_POLL_TRIES; if (!card || !card->func) { BT_ERR("card or function is NULL!"); @@ -827,20 +872,36 @@ static int btmrvl_sdio_download_fw(struct btmrvl_sdio_card *card) goto done; } - ret = btmrvl_sdio_download_helper(card); + /* Check if other function driver is downloading the firmware */ + fws0 = sdio_readb(card->func, card->reg->card_fw_status0, &ret); if (ret) { - BT_ERR("Failed to download helper!"); + BT_ERR("Failed to read FW downloading status!"); ret = -EIO; goto done; } + if (fws0) { + BT_DBG("BT not the winner (%#x). Skip FW downloading", fws0); + + /* Give other function more time to download the firmware */ + pollnum *= 10; + } else { + if (card->helper) { + ret = btmrvl_sdio_download_helper(card); + if (ret) { + BT_ERR("Failed to download helper!"); + ret = -EIO; + goto done; + } + } - if (btmrvl_sdio_download_fw_w_helper(card)) { - BT_ERR("Failed to download firmware!"); - ret = -EIO; - goto done; + if (btmrvl_sdio_download_fw_w_helper(card)) { + BT_ERR("Failed to download firmware!"); + ret = -EIO; + goto done; + } } - if (btmrvl_sdio_verify_fw_download(card, MAX_POLL_TRIES)) { + if (btmrvl_sdio_verify_fw_download(card, pollnum)) { BT_ERR("FW failed to be active in time!"); ret = -ETIMEDOUT; goto done; @@ -864,7 +925,7 @@ static int btmrvl_sdio_wakeup_fw(struct btmrvl_private *priv) sdio_claim_host(card->func); - sdio_writeb(card->func, HOST_POWER_UP, CONFIG_REG, &ret); + sdio_writeb(card->func, HOST_POWER_UP, card->reg->cfg, &ret); sdio_release_host(card->func); @@ -893,8 +954,10 @@ static int btmrvl_sdio_probe(struct sdio_func *func, if (id->driver_data) { struct btmrvl_sdio_device *data = (void *) id->driver_data; - card->helper = data->helper; + card->helper = data->helper; card->firmware = data->firmware; + card->reg = data->reg; + card->sd_blksz_fw_dl = data->sd_blksz_fw_dl; } if (btmrvl_sdio_register_dev(card) < 0) { @@ -1011,3 +1074,4 @@ MODULE_VERSION(VERSION); MODULE_LICENSE("GPL v2"); MODULE_FIRMWARE("sd8688_helper.bin"); MODULE_FIRMWARE("sd8688.bin"); +MODULE_FIRMWARE("mrvl/sd8787_uapsta.bin"); diff --git a/drivers/bluetooth/btmrvl_sdio.h b/drivers/bluetooth/btmrvl_sdio.h index 27329f1..43d35a6 100644 --- a/drivers/bluetooth/btmrvl_sdio.h +++ b/drivers/bluetooth/btmrvl_sdio.h @@ -47,44 +47,46 @@ /* Max retry number of CMD53 write */ #define MAX_WRITE_IOMEM_RETRY 2 -/* Host Control Registers */ -#define IO_PORT_0_REG 0x00 -#define IO_PORT_1_REG 0x01 -#define IO_PORT_2_REG 0x02 - -#define CONFIG_REG 0x03 -#define HOST_POWER_UP BIT(1) -#define HOST_CMD53_FIN BIT(2) - -#define HOST_INT_MASK_REG 0x04 -#define HIM_DISABLE 0xff -#define HIM_ENABLE (BIT(0) | BIT(1)) - -#define HOST_INTSTATUS_REG 0x05 -#define UP_LD_HOST_INT_STATUS BIT(0) -#define DN_LD_HOST_INT_STATUS BIT(1) - -/* Card Control Registers */ -#define SQ_READ_BASE_ADDRESS_A0_REG 0x10 -#define SQ_READ_BASE_ADDRESS_A1_REG 0x11 - -#define CARD_STATUS_REG 0x20 -#define DN_LD_CARD_RDY BIT(0) -#define CARD_IO_READY BIT(3) - -#define CARD_FW_STATUS0_REG 0x40 -#define CARD_FW_STATUS1_REG 0x41 -#define FIRMWARE_READY 0xfedc - -#define CARD_RX_LEN_REG 0x42 -#define CARD_RX_UNIT_REG 0x43 - +/* register bitmasks */ +#define HOST_POWER_UP BIT(1) +#define HOST_CMD53_FIN BIT(2) + +#define HIM_DISABLE 0xff +#define HIM_ENABLE (BIT(0) | BIT(1)) + +#define UP_LD_HOST_INT_STATUS BIT(0) +#define DN_LD_HOST_INT_STATUS BIT(1) + +#define DN_LD_CARD_RDY BIT(0) +#define CARD_IO_READY BIT(3) + +#define FIRMWARE_READY 0xfedc + + +struct btmrvl_sdio_card_reg { + u8 cfg; + u8 host_int_mask; + u8 host_intstatus; + u8 card_status; + u8 sq_read_base_addr_a0; + u8 sq_read_base_addr_a1; + u8 card_revision; + u8 card_fw_status0; + u8 card_fw_status1; + u8 card_rx_len; + u8 card_rx_unit; + u8 io_port_0; + u8 io_port_1; + u8 io_port_2; +}; struct btmrvl_sdio_card { struct sdio_func *func; u32 ioport; const char *helper; const char *firmware; + const struct btmrvl_sdio_card_reg *reg; + u16 sd_blksz_fw_dl; u8 rx_unit; struct btmrvl_private *priv; }; @@ -92,6 +94,8 @@ struct btmrvl_sdio_card { struct btmrvl_sdio_device { const char *helper; const char *firmware; + const struct btmrvl_sdio_card_reg *reg; + u16 sd_blksz_fw_dl; }; -- cgit v0.10.2 From 5c72d064f7ead1126bed6faab0c2bfb7418036e2 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Wed, 13 Apr 2011 09:28:23 +0100 Subject: drm/i915: Initialise g4x watermarks for disabled pipes We were using uninitialised watermarks values for disabled pipes which were combined into a single WM register and so corrupting the values for the enabled pipe and upsetting the display hardware. Reported-by: Riccardo Magliocchetti Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=32612 Signed-off-by: Chris Wilson Signed-off-by: Keith Packard diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 4fc21e0..e522c70 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -3771,8 +3771,11 @@ static bool g4x_compute_wm0(struct drm_device *dev, int entries, tlb_miss; crtc = intel_get_crtc_for_plane(dev, plane); - if (crtc->fb == NULL || !crtc->enabled) + if (crtc->fb == NULL || !crtc->enabled) { + *cursor_wm = cursor->guard_size; + *plane_wm = display->guard_size; return false; + } htotal = crtc->mode.htotal; hdisplay = crtc->mode.hdisplay; -- cgit v0.10.2 From 79a48a1f5d99ab66cf83d2d5d805e7a0e08452ed Mon Sep 17 00:00:00 2001 From: Weston Andros Adamson Date: Wed, 13 Apr 2011 10:53:51 -0400 Subject: Don't mark_inode_dirty_sync() while holding lock mark_inode_dirty_sync() grabs the same inode lock! race conditions between holding the lock in pnfs_set_layoutcommit() and in mark_inode_dirty_sync() can result in a second call to pnfs_layoutcommit_inode(), but this will be a noop as NFS_INO_LAYOUTCOMMIT won't be set in the second call Signed-off-by: Weston Andros Adamson Signed-off-by: Trond Myklebust diff --git a/fs/nfs/pnfs.c b/fs/nfs/pnfs.c index d9ab972..ff681ab 100644 --- a/fs/nfs/pnfs.c +++ b/fs/nfs/pnfs.c @@ -1004,6 +1004,7 @@ pnfs_set_layoutcommit(struct nfs_write_data *wdata) { struct nfs_inode *nfsi = NFS_I(wdata->inode); loff_t end_pos = wdata->args.offset + wdata->res.count; + bool mark_as_dirty = false; spin_lock(&nfsi->vfs_inode.i_lock); if (!test_and_set_bit(NFS_INO_LAYOUTCOMMIT, &nfsi->flags)) { @@ -1011,13 +1012,18 @@ pnfs_set_layoutcommit(struct nfs_write_data *wdata) get_lseg(wdata->lseg); wdata->lseg->pls_lc_cred = get_rpccred(wdata->args.context->state->owner->so_cred); - mark_inode_dirty_sync(wdata->inode); + mark_as_dirty = true; dprintk("%s: Set layoutcommit for inode %lu ", __func__, wdata->inode->i_ino); } if (end_pos > wdata->lseg->pls_end_pos) wdata->lseg->pls_end_pos = end_pos; spin_unlock(&nfsi->vfs_inode.i_lock); + + /* if pnfs_layoutcommit_inode() runs between inode locks, the next one + * will be a noop because NFS_INO_LAYOUTCOMMIT will not be set */ + if (mark_as_dirty) + mark_inode_dirty_sync(wdata->inode); } EXPORT_SYMBOL_GPL(pnfs_set_layoutcommit); -- cgit v0.10.2 From 1fdf9b49e9e7788d09bad4b08a6a821ac39798f3 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Tue, 12 Apr 2011 19:33:28 +0200 Subject: ASoC: codecs: JZ4740: Fix OOPS Commit ce6120cc(ASoC: Decouple DAPM from CODECs) changed the signature of snd_soc_dapm_widgets_new to take an pointer to a snd_soc_dapm_context instead of a snd_soc_codec. The call to snd_soc_dapm_widgets_new in jz4740_codec_dev_probe was not updated to reflect this change, which results in a compiletime warning and a runtime OOPS. Since the core code calls snd_soc_dapm_widgets_new after the codec has been registered it can be dropped here. Signed-off-by: Lars-Peter Clausen Acked-by: Liam Girdwood Signed-off-by: Mark Brown Cc: stable@kernel.org diff --git a/sound/soc/codecs/jz4740.c b/sound/soc/codecs/jz4740.c index f7cd346f..f5ccdbf 100644 --- a/sound/soc/codecs/jz4740.c +++ b/sound/soc/codecs/jz4740.c @@ -308,8 +308,6 @@ static int jz4740_codec_dev_probe(struct snd_soc_codec *codec) snd_soc_dapm_add_routes(dapm, jz4740_codec_dapm_routes, ARRAY_SIZE(jz4740_codec_dapm_routes)); - snd_soc_dapm_new_widgets(codec); - jz4740_codec_set_bias_level(codec, SND_SOC_BIAS_STANDBY); return 0; -- cgit v0.10.2 From 6caa15d0b84d2ea688fd31f4f172c8353463e109 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Tue, 12 Apr 2011 22:51:04 +0200 Subject: ARM: s3c2440: gta02; Register dfbmcs320 device for BT audio interface Register the dfbmcs320 device which provides the PCM DAI for the bluetooth module. Signed-off-by: Lars-Peter Clausen Acked-by: Liam Girdwood Signed-off-by: Mark Brown diff --git a/arch/arm/mach-s3c2440/mach-gta02.c b/arch/arm/mach-s3c2440/mach-gta02.c index 0db2411..7166620 100644 --- a/arch/arm/mach-s3c2440/mach-gta02.c +++ b/arch/arm/mach-s3c2440/mach-gta02.c @@ -409,6 +409,10 @@ struct platform_device s3c24xx_pwm_device = { .num_resources = 0, }; +static struct platform_device gta02_dfbmcs320_device = { + .name = "dfbmcs320", +}; + static struct i2c_board_info gta02_i2c_devs[] __initdata = { { I2C_BOARD_INFO("pcf50633", 0x73), @@ -523,6 +527,7 @@ static struct platform_device *gta02_devices[] __initdata = { &s3c_device_iis, &samsung_asoc_dma, &s3c_device_i2c0, + >a02_dfbmcs320_device, >a02_buttons_device, &s3c_device_adc, &s3c_device_ts, -- cgit v0.10.2 From 8b5933c380fc66a6311739f9b36a812383f82141 Mon Sep 17 00:00:00 2001 From: amit salecha Date: Thu, 7 Apr 2011 01:58:42 +0000 Subject: net: ethtool support to configure number of channels Ethtool support to configure RX, TX and other channels. combined field in struct ethtool_channels to reflect set of channel (RX, TX or other). Other channel can be link interrupts, SR-IOV coordination etc. ETHTOOL_GCHANNELS will report max and current number of RX channels, max and current number of TX channels, max and current number of other channel or max and current number of combined channel. Number of channel can be modify upto max number of channel through ETHTOOL_SCHANNELS command. Ben Hutchings: o define 'combined' and 'other' types. Most multiqueue drivers pair up RX and TX queues so that most channels combine RX and TX work. o Please could you use a kernel-doc comment to describe the structure. Signed-off-by: Amit Kumar Salecha Reviewed-by: Ben Hutchings Signed-off-by: David S. Miller diff --git a/include/linux/ethtool.h b/include/linux/ethtool.h index 12cfbd0..ad22a68 100644 --- a/include/linux/ethtool.h +++ b/include/linux/ethtool.h @@ -229,6 +229,34 @@ struct ethtool_ringparam { __u32 tx_pending; }; +/** + * struct ethtool_channels - configuring number of network channel + * @cmd: ETHTOOL_{G,S}CHANNELS + * @max_rx: Read only. Maximum number of receive channel the driver support. + * @max_tx: Read only. Maximum number of transmit channel the driver support. + * @max_other: Read only. Maximum number of other channel the driver support. + * @max_combined: Read only. Maximum number of combined channel the driver + * support. Set of queues RX, TX or other. + * @rx_count: Valid values are in the range 1 to the max_rx. + * @tx_count: Valid values are in the range 1 to the max_tx. + * @other_count: Valid values are in the range 1 to the max_other. + * @combined_count: Valid values are in the range 1 to the max_combined. + * + * This can be used to configure RX, TX and other channels. + */ + +struct ethtool_channels { + __u32 cmd; + __u32 max_rx; + __u32 max_tx; + __u32 max_other; + __u32 max_combined; + __u32 rx_count; + __u32 tx_count; + __u32 other_count; + __u32 combined_count; +}; + /* for configuring link flow control parameters */ struct ethtool_pauseparam { __u32 cmd; /* ETHTOOL_{G,S}PAUSEPARAM */ @@ -818,6 +846,9 @@ bool ethtool_invalid_flags(struct net_device *dev, u32 data, u32 supported); * Returns a negative error code or zero. * @set_rxfh_indir: Set the contents of the RX flow hash indirection table. * Returns a negative error code or zero. + * @get_channels: Get number of channels. + * @set_channels: Set number of channels. Returns a negative error code or + * zero. * * All operations are optional (i.e. the function pointer may be set * to %NULL) and callers must take this into account. Callers must @@ -891,6 +922,9 @@ struct ethtool_ops { struct ethtool_rxfh_indir *); int (*set_rxfh_indir)(struct net_device *, const struct ethtool_rxfh_indir *); + void (*get_channels)(struct net_device *, struct ethtool_channels *); + int (*set_channels)(struct net_device *, struct ethtool_channels *); + }; #endif /* __KERNEL__ */ @@ -959,6 +993,8 @@ struct ethtool_ops { #define ETHTOOL_GFEATURES 0x0000003a /* Get device offload settings */ #define ETHTOOL_SFEATURES 0x0000003b /* Change device offload settings */ +#define ETHTOOL_GCHANNELS 0x0000003c /* Get no of channels */ +#define ETHTOOL_SCHANNELS 0x0000003d /* Set no of channels */ /* compatibility with older code */ #define SPARC_ETH_GSET ETHTOOL_GSET diff --git a/net/core/ethtool.c b/net/core/ethtool.c index 43ef09f..41dee2d 100644 --- a/net/core/ethtool.c +++ b/net/core/ethtool.c @@ -1446,6 +1446,35 @@ static int ethtool_set_ringparam(struct net_device *dev, void __user *useraddr) return dev->ethtool_ops->set_ringparam(dev, &ringparam); } +static noinline_for_stack int ethtool_get_channels(struct net_device *dev, + void __user *useraddr) +{ + struct ethtool_channels channels = { .cmd = ETHTOOL_GCHANNELS }; + + if (!dev->ethtool_ops->get_channels) + return -EOPNOTSUPP; + + dev->ethtool_ops->get_channels(dev, &channels); + + if (copy_to_user(useraddr, &channels, sizeof(channels))) + return -EFAULT; + return 0; +} + +static noinline_for_stack int ethtool_set_channels(struct net_device *dev, + void __user *useraddr) +{ + struct ethtool_channels channels; + + if (!dev->ethtool_ops->set_channels) + return -EOPNOTSUPP; + + if (copy_from_user(&channels, useraddr, sizeof(channels))) + return -EFAULT; + + return dev->ethtool_ops->set_channels(dev, &channels); +} + static int ethtool_get_pauseparam(struct net_device *dev, void __user *useraddr) { struct ethtool_pauseparam pauseparam = { ETHTOOL_GPAUSEPARAM }; @@ -2007,6 +2036,12 @@ int dev_ethtool(struct net *net, struct ifreq *ifr) case ETHTOOL_SGRO: rc = ethtool_set_one_feature(dev, useraddr, ethcmd); break; + case ETHTOOL_GCHANNELS: + rc = ethtool_get_channels(dev, useraddr); + break; + case ETHTOOL_SCHANNELS: + rc = ethtool_set_channels(dev, useraddr); + break; default: rc = -EOPNOTSUPP; } -- cgit v0.10.2 From 7c9f6472d46d07000c197e1d24fa2a332606968e Mon Sep 17 00:00:00 2001 From: Anatolij Gustschin Date: Tue, 12 Apr 2011 23:49:28 +0000 Subject: net: can: mscan: fix build breakage in mpc5xxx_can Commit 74888760d40b3ac9054f9c5fa07b566c0676ba2d "dt/net: Eliminate users of of_platform_{,un}register_driver" broke building mscan driver. Fix it. Signed-off-by: Anatolij Gustschin Cc: Grant Likely Acked-by: Wolfgang Grandegger Acked-by: Marc Kleine-Budde Signed-off-by: David S. Miller diff --git a/drivers/net/can/mscan/mpc5xxx_can.c b/drivers/net/can/mscan/mpc5xxx_can.c index c0a1bc5..bd1d811 100644 --- a/drivers/net/can/mscan/mpc5xxx_can.c +++ b/drivers/net/can/mscan/mpc5xxx_can.c @@ -260,7 +260,7 @@ static int __devinit mpc5xxx_can_probe(struct platform_device *ofdev) if (!ofdev->dev.of_match) return -EINVAL; - data = (struct mpc5xxx_can_data *)of_dev->dev.of_match->data; + data = (struct mpc5xxx_can_data *)ofdev->dev.of_match->data; base = of_iomap(np, 0); if (!base) { -- cgit v0.10.2 From b19f7f71b6fa5e0c49f65082044b8a2ff1009f00 Mon Sep 17 00:00:00 2001 From: Alexander Stein Date: Wed, 13 Apr 2011 05:03:24 +0000 Subject: macb: Add rx overrun counter Signed-off-by: Alexander Stein Signed-off-by: David S. Miller diff --git a/drivers/net/macb.c b/drivers/net/macb.c index 2cb4e79..629bd26 100644 --- a/drivers/net/macb.c +++ b/drivers/net/macb.c @@ -576,6 +576,11 @@ static irqreturn_t macb_interrupt(int irq, void *dev_id) * add that if/when we get our hands on a full-blown MII PHY. */ + if (status & MACB_BIT(ISR_ROVR)) { + /* We missed at least one packet */ + bp->hw_stats.rx_overruns++; + } + if (status & MACB_BIT(HRESP)) { /* * TODO: Reset the hardware, and maybe move the printk @@ -1024,7 +1029,8 @@ static struct net_device_stats *macb_get_stats(struct net_device *dev) hwstat->rx_jabbers + hwstat->rx_undersize_pkts + hwstat->rx_length_mismatch); - nstat->rx_over_errors = hwstat->rx_resource_errors; + nstat->rx_over_errors = hwstat->rx_resource_errors + + hwstat->rx_overruns; nstat->rx_crc_errors = hwstat->rx_fcs_errors; nstat->rx_frame_errors = hwstat->rx_align_errors; nstat->rx_fifo_errors = hwstat->rx_overruns; -- cgit v0.10.2 From 74ae2fd7d326750d973920c30d5269596724ca71 Mon Sep 17 00:00:00 2001 From: Giuseppe Cavallaro Date: Wed, 13 Apr 2011 11:51:43 -0700 Subject: stmmac: review Wol and enable the Unicast support Signed-off-by: Giuseppe Cavallaro Signed-off-by: David S. Miller diff --git a/drivers/net/stmmac/dwmac1000_core.c b/drivers/net/stmmac/dwmac1000_core.c index 6ae4c3f..f20455c 100644 --- a/drivers/net/stmmac/dwmac1000_core.c +++ b/drivers/net/stmmac/dwmac1000_core.c @@ -178,10 +178,11 @@ static void dwmac1000_pmt(void __iomem *ioaddr, unsigned long mode) { unsigned int pmt = 0; - if (mode == WAKE_MAGIC) { + if (mode & WAKE_MAGIC) { CHIP_DBG(KERN_DEBUG "GMAC: WOL Magic frame\n"); pmt |= power_down | magic_pkt_en; - } else if (mode == WAKE_UCAST) { + } + if (mode & WAKE_UCAST) { CHIP_DBG(KERN_DEBUG "GMAC: WOL on global unicast\n"); pmt |= global_unicast; } diff --git a/drivers/net/stmmac/stmmac_ethtool.c b/drivers/net/stmmac/stmmac_ethtool.c index 156a805..0e61ac8 100644 --- a/drivers/net/stmmac/stmmac_ethtool.c +++ b/drivers/net/stmmac/stmmac_ethtool.c @@ -308,7 +308,7 @@ static void stmmac_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol) spin_lock_irq(&priv->lock); if (device_can_wakeup(priv->device)) { - wol->supported = WAKE_MAGIC; + wol->supported = WAKE_MAGIC | WAKE_UCAST; wol->wolopts = priv->wolopts; } spin_unlock_irq(&priv->lock); @@ -317,7 +317,7 @@ static void stmmac_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol) static int stmmac_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol) { struct stmmac_priv *priv = netdev_priv(dev); - u32 support = WAKE_MAGIC; + u32 support = WAKE_MAGIC | WAKE_UCAST; if (!device_can_wakeup(priv->device)) return -EINVAL; -- cgit v0.10.2 From 91a403caf0f26c71ce4407fd235b2d6fb225fba9 Mon Sep 17 00:00:00 2001 From: Amit Kumar Salecha Date: Tue, 12 Apr 2011 17:05:55 +0000 Subject: qlcnic: limit skb frags for non tso packet Machines are getting deadlock in four node cluster environment. All nodes are accessing (find /gfs2 -depth -print|cpio -ocv > /dev/null) 200 GB storage on a GFS2 filesystem. This result in memory fragmentation and driver receives 18 frags for 1448 byte packets. For non tso packet, fw drops the tx request, if it has >14 frags. Fixing it by pulling extra frags. Cc: stable@kernel.org Signed-off-by: Amit Kumar Salecha Signed-off-by: David S. Miller diff --git a/drivers/net/qlcnic/qlcnic.h b/drivers/net/qlcnic/qlcnic.h index dc44564..b0dead0 100644 --- a/drivers/net/qlcnic/qlcnic.h +++ b/drivers/net/qlcnic/qlcnic.h @@ -99,6 +99,7 @@ #define TX_UDPV6_PKT 0x0c /* Tx defines */ +#define QLCNIC_MAX_FRAGS_PER_TX 14 #define MAX_TSO_HEADER_DESC 2 #define MGMT_CMD_DESC_RESV 4 #define TX_STOP_THRESH ((MAX_SKB_FRAGS >> 2) + MAX_TSO_HEADER_DESC \ diff --git a/drivers/net/qlcnic/qlcnic_main.c b/drivers/net/qlcnic/qlcnic_main.c index cd88c7e..cb1a1ef 100644 --- a/drivers/net/qlcnic/qlcnic_main.c +++ b/drivers/net/qlcnic/qlcnic_main.c @@ -2099,6 +2099,7 @@ qlcnic_xmit_frame(struct sk_buff *skb, struct net_device *netdev) struct cmd_desc_type0 *hwdesc, *first_desc; struct pci_dev *pdev; struct ethhdr *phdr; + int delta = 0; int i, k; u32 producer; @@ -2118,6 +2119,19 @@ qlcnic_xmit_frame(struct sk_buff *skb, struct net_device *netdev) } frag_count = skb_shinfo(skb)->nr_frags + 1; + /* 14 frags supported for normal packet and + * 32 frags supported for TSO packet + */ + if (!skb_is_gso(skb) && frag_count > QLCNIC_MAX_FRAGS_PER_TX) { + + for (i = 0; i < (frag_count - QLCNIC_MAX_FRAGS_PER_TX); i++) + delta += skb_shinfo(skb)->frags[i].size; + + if (!__pskb_pull_tail(skb, delta)) + goto drop_packet; + + frag_count = 1 + skb_shinfo(skb)->nr_frags; + } /* 4 fragments per cmd des */ no_of_desc = (frag_count + 3) >> 2; -- cgit v0.10.2 From 3e8c806a08c7beecd972e7ce15c570b9aba64baa Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Wed, 13 Apr 2011 12:01:14 -0700 Subject: Revert "tcp: disallow bind() to reuse addr/port" This reverts commit c191a836a908d1dd6b40c503741f91b914de3348. It causes known regressions for programs that expect to be able to use SO_REUSEADDR to shutdown a socket, then successfully rebind another socket to the same ID. Programs such as haproxy and amavisd expect this to work. This should fix kernel bugzilla 32832. Signed-off-by: David S. Miller diff --git a/net/ipv4/inet_connection_sock.c b/net/ipv4/inet_connection_sock.c index 6c0b7f4..38f23e7 100644 --- a/net/ipv4/inet_connection_sock.c +++ b/net/ipv4/inet_connection_sock.c @@ -73,7 +73,7 @@ int inet_csk_bind_conflict(const struct sock *sk, !sk2->sk_bound_dev_if || sk->sk_bound_dev_if == sk2->sk_bound_dev_if)) { if (!reuse || !sk2->sk_reuse || - ((1 << sk2->sk_state) & (TCPF_LISTEN | TCPF_CLOSE))) { + sk2->sk_state == TCP_LISTEN) { const __be32 sk2_rcv_saddr = sk_rcv_saddr(sk2); if (!sk2_rcv_saddr || !sk_rcv_saddr(sk) || sk2_rcv_saddr == sk_rcv_saddr(sk)) @@ -122,8 +122,7 @@ again: (tb->num_owners < smallest_size || smallest_size == -1)) { smallest_size = tb->num_owners; smallest_rover = rover; - if (atomic_read(&hashinfo->bsockets) > (high - low) + 1 && - !inet_csk(sk)->icsk_af_ops->bind_conflict(sk, tb)) { + if (atomic_read(&hashinfo->bsockets) > (high - low) + 1) { spin_unlock(&head->lock); snum = smallest_rover; goto have_snum; diff --git a/net/ipv6/inet6_connection_sock.c b/net/ipv6/inet6_connection_sock.c index 1660546..f2c5b0f 100644 --- a/net/ipv6/inet6_connection_sock.c +++ b/net/ipv6/inet6_connection_sock.c @@ -44,7 +44,7 @@ int inet6_csk_bind_conflict(const struct sock *sk, !sk2->sk_bound_dev_if || sk->sk_bound_dev_if == sk2->sk_bound_dev_if) && (!sk->sk_reuse || !sk2->sk_reuse || - ((1 << sk2->sk_state) & (TCPF_LISTEN | TCPF_CLOSE))) && + sk2->sk_state == TCP_LISTEN) && ipv6_rcv_saddr_equal(sk, sk2)) break; } -- cgit v0.10.2 From 332704a51498a7e29aa92c19dc03f11f80b71bfe Mon Sep 17 00:00:00 2001 From: Stanislaw Gruszka Date: Wed, 13 Apr 2011 10:56:51 +0200 Subject: iwlegacy: fix tx_power initialization priv->tx_power_next is not initialized to max supported power, but instead default value is used, what cause errors like [ 58.597834] iwl3945 0000:03:00.0: Requested user TXPOWER 15 above upper limit 14. [ 58.597839] iwl3945 0000:03:00.0: Error setting Tx power (-22). if maximum tx power read from the eeprom is smaller than default. In consequence card is unable to initialize properly. Fix the problem and cleanup tx power initialization. Reported-and-tested-by: Robin Dong Signed-off-by: Stanislaw Gruszka Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwlegacy/iwl-3945-hw.h b/drivers/net/wireless/iwlegacy/iwl-3945-hw.h index 779d3cb..5c3a68d 100644 --- a/drivers/net/wireless/iwlegacy/iwl-3945-hw.h +++ b/drivers/net/wireless/iwlegacy/iwl-3945-hw.h @@ -74,8 +74,6 @@ /* RSSI to dBm */ #define IWL39_RSSI_OFFSET 95 -#define IWL_DEFAULT_TX_POWER 0x0F - /* * EEPROM related constants, enums, and structures. */ diff --git a/drivers/net/wireless/iwlegacy/iwl-4965-hw.h b/drivers/net/wireless/iwlegacy/iwl-4965-hw.h index 08b189c..fc6fa28 100644 --- a/drivers/net/wireless/iwlegacy/iwl-4965-hw.h +++ b/drivers/net/wireless/iwlegacy/iwl-4965-hw.h @@ -804,9 +804,6 @@ struct iwl4965_scd_bc_tbl { #define IWL4965_DEFAULT_TX_RETRY 15 -/* Limit range of txpower output target to be between these values */ -#define IWL4965_TX_POWER_TARGET_POWER_MIN (0) /* 0 dBm: 1 milliwatt */ - /* EEPROM */ #define IWL4965_FIRST_AMPDU_QUEUE 10 diff --git a/drivers/net/wireless/iwlegacy/iwl-core.c b/drivers/net/wireless/iwlegacy/iwl-core.c index a209a0e..2b08efb 100644 --- a/drivers/net/wireless/iwlegacy/iwl-core.c +++ b/drivers/net/wireless/iwlegacy/iwl-core.c @@ -160,6 +160,7 @@ int iwl_legacy_init_geos(struct iwl_priv *priv) struct ieee80211_channel *geo_ch; struct ieee80211_rate *rates; int i = 0; + s8 max_tx_power = 0; if (priv->bands[IEEE80211_BAND_2GHZ].n_bitrates || priv->bands[IEEE80211_BAND_5GHZ].n_bitrates) { @@ -235,8 +236,8 @@ int iwl_legacy_init_geos(struct iwl_priv *priv) geo_ch->flags |= ch->ht40_extension_channel; - if (ch->max_power_avg > priv->tx_power_device_lmt) - priv->tx_power_device_lmt = ch->max_power_avg; + if (ch->max_power_avg > max_tx_power) + max_tx_power = ch->max_power_avg; } else { geo_ch->flags |= IEEE80211_CHAN_DISABLED; } @@ -249,6 +250,10 @@ int iwl_legacy_init_geos(struct iwl_priv *priv) geo_ch->flags); } + priv->tx_power_device_lmt = max_tx_power; + priv->tx_power_user_lmt = max_tx_power; + priv->tx_power_next = max_tx_power; + if ((priv->bands[IEEE80211_BAND_5GHZ].n_channels == 0) && priv->cfg->sku & IWL_SKU_A) { IWL_INFO(priv, "Incorrectly detected BG card as ABG. " @@ -1124,11 +1129,11 @@ int iwl_legacy_set_tx_power(struct iwl_priv *priv, s8 tx_power, bool force) if (!priv->cfg->ops->lib->send_tx_power) return -EOPNOTSUPP; - if (tx_power < IWL4965_TX_POWER_TARGET_POWER_MIN) { + /* 0 dBm mean 1 milliwatt */ + if (tx_power < 0) { IWL_WARN(priv, - "Requested user TXPOWER %d below lower limit %d.\n", - tx_power, - IWL4965_TX_POWER_TARGET_POWER_MIN); + "Requested user TXPOWER %d below 1 mW.\n", + tx_power); return -EINVAL; } diff --git a/drivers/net/wireless/iwlegacy/iwl-eeprom.c b/drivers/net/wireless/iwlegacy/iwl-eeprom.c index 04c5648..cb346d1 100644 --- a/drivers/net/wireless/iwlegacy/iwl-eeprom.c +++ b/drivers/net/wireless/iwlegacy/iwl-eeprom.c @@ -471,13 +471,6 @@ int iwl_legacy_init_channel_map(struct iwl_priv *priv) flags & EEPROM_CHANNEL_RADAR)) ? "" : "not "); - /* Set the tx_power_user_lmt to the highest power - * supported by any channel */ - if (eeprom_ch_info[ch].max_power_avg > - priv->tx_power_user_lmt) - priv->tx_power_user_lmt = - eeprom_ch_info[ch].max_power_avg; - ch_info++; } } diff --git a/drivers/net/wireless/iwlegacy/iwl3945-base.c b/drivers/net/wireless/iwlegacy/iwl3945-base.c index 28eb3d8..cc7ebce 100644 --- a/drivers/net/wireless/iwlegacy/iwl3945-base.c +++ b/drivers/net/wireless/iwlegacy/iwl3945-base.c @@ -3825,10 +3825,6 @@ static int iwl3945_init_drv(struct iwl_priv *priv) priv->force_reset[IWL_FW_RESET].reset_duration = IWL_DELAY_NEXT_FORCE_FW_RELOAD; - - priv->tx_power_user_lmt = IWL_DEFAULT_TX_POWER; - priv->tx_power_next = IWL_DEFAULT_TX_POWER; - if (eeprom->version < EEPROM_3945_EEPROM_VERSION) { IWL_WARN(priv, "Unsupported EEPROM version: 0x%04X\n", eeprom->version); diff --git a/drivers/net/wireless/iwlegacy/iwl4965-base.c b/drivers/net/wireless/iwlegacy/iwl4965-base.c index 91b3d8b..d484c36 100644 --- a/drivers/net/wireless/iwlegacy/iwl4965-base.c +++ b/drivers/net/wireless/iwlegacy/iwl4965-base.c @@ -3140,12 +3140,6 @@ static int iwl4965_init_drv(struct iwl_priv *priv) iwl_legacy_init_scan_params(priv); - /* Set the tx_power_user_lmt to the lowest power level - * this value will get overwritten by channel max power avg - * from eeprom */ - priv->tx_power_user_lmt = IWL4965_TX_POWER_TARGET_POWER_MIN; - priv->tx_power_next = IWL4965_TX_POWER_TARGET_POWER_MIN; - ret = iwl_legacy_init_channel_map(priv); if (ret) { IWL_ERR(priv, "initializing regulatory failed: %d\n", ret); -- cgit v0.10.2 From d1a8016a2d1e75021ecc8715e3c81442d7218eb6 Mon Sep 17 00:00:00 2001 From: Bryan Schumaker Date: Wed, 13 Apr 2011 14:31:28 -0400 Subject: NFS: Fix infinite loop in gss_create_upcall() There can be an infinite loop if gss_create_upcall() is called without the userspace program running. To prevent this, we return -EACCES if we notice that pipe_version hasn't changed (indicating that the pipe has not been opened). Signed-off-by: Bryan Schumaker Signed-off-by: Trond Myklebust diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index 9bf41ea..8a03ee0 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c @@ -2224,8 +2224,9 @@ static int nfs4_proc_get_root(struct nfs_server *server, struct nfs_fh *fhandle, for (i = 0; i < len; i++) { status = nfs4_lookup_root_sec(server, fhandle, info, flav_array[i]); - if (status != -EPERM) - break; + if (status == -EPERM || status == -EACCES) + continue; + break; } if (status == 0) status = nfs4_server_capabilities(server, fhandle); diff --git a/net/sunrpc/auth_gss/auth_gss.c b/net/sunrpc/auth_gss/auth_gss.c index f3914d0..339ba64 100644 --- a/net/sunrpc/auth_gss/auth_gss.c +++ b/net/sunrpc/auth_gss/auth_gss.c @@ -520,7 +520,7 @@ gss_refresh_upcall(struct rpc_task *task) warn_gssd(); task->tk_timeout = 15*HZ; rpc_sleep_on(&pipe_version_rpc_waitqueue, task, NULL); - return 0; + return -EAGAIN; } if (IS_ERR(gss_msg)) { err = PTR_ERR(gss_msg); @@ -563,10 +563,12 @@ retry: if (PTR_ERR(gss_msg) == -EAGAIN) { err = wait_event_interruptible_timeout(pipe_version_waitqueue, pipe_version >= 0, 15*HZ); + if (pipe_version < 0) { + warn_gssd(); + err = -EACCES; + } if (err) goto out; - if (pipe_version < 0) - warn_gssd(); goto retry; } if (IS_ERR(gss_msg)) { -- cgit v0.10.2 From 0fabee243a2c6edd66284a4d8948ccbe6727e3bb Mon Sep 17 00:00:00 2001 From: Bryan Schumaker Date: Wed, 13 Apr 2011 14:31:29 -0400 Subject: NFS: flav_array honors NFS_MAX_SECFLAVORS NFS_MAX_SECFLAVORS should already take into account RPC_AUTH_UNIX and RPC_AUTH_NULL, so we don't need to set aside extra slots for them. Signed-off-by: Bryan Schumaker Signed-off-by: Trond Myklebust diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index 8a03ee0..8833472 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c @@ -2215,7 +2215,7 @@ static int nfs4_proc_get_root(struct nfs_server *server, struct nfs_fh *fhandle, struct nfs_fsinfo *info) { int i, len, status = 0; - rpc_authflavor_t flav_array[NFS_MAX_SECFLAVORS + 2]; + rpc_authflavor_t flav_array[NFS_MAX_SECFLAVORS]; flav_array[0] = RPC_AUTH_UNIX; len = gss_mech_list_pseudoflavors(&flav_array[1]); -- cgit v0.10.2 From 801a16dc7b5c146f7980a0c61c30cef3ba93344d Mon Sep 17 00:00:00 2001 From: Bryan Schumaker Date: Wed, 13 Apr 2011 14:31:30 -0400 Subject: NFS: Attempt mount with default sec flavor first nfs4_lookup_root() is already configured to use either RPC_AUTH_UNIX or a user specified flavor (through -o sec=). We should use this flavor first, and only attempt negotiation if it fails with -EPERM. Signed-off-by: Bryan Schumaker Signed-off-by: Trond Myklebust diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index 8833472..7e27ebf 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c @@ -2208,19 +2208,15 @@ out: return ret; } -/* - * get the file handle for the "/" directory on the server - */ -static int nfs4_proc_get_root(struct nfs_server *server, struct nfs_fh *fhandle, +static int nfs4_find_root_sec(struct nfs_server *server, struct nfs_fh *fhandle, struct nfs_fsinfo *info) { int i, len, status = 0; rpc_authflavor_t flav_array[NFS_MAX_SECFLAVORS]; - flav_array[0] = RPC_AUTH_UNIX; - len = gss_mech_list_pseudoflavors(&flav_array[1]); - flav_array[1+len] = RPC_AUTH_NULL; - len += 2; + len = gss_mech_list_pseudoflavors(&flav_array[0]); + flav_array[len] = RPC_AUTH_NULL; + len += 1; for (i = 0; i < len; i++) { status = nfs4_lookup_root_sec(server, fhandle, info, flav_array[i]); @@ -2228,6 +2224,18 @@ static int nfs4_proc_get_root(struct nfs_server *server, struct nfs_fh *fhandle, continue; break; } + return status; +} + +/* + * get the file handle for the "/" directory on the server + */ +static int nfs4_proc_get_root(struct nfs_server *server, struct nfs_fh *fhandle, + struct nfs_fsinfo *info) +{ + int status = nfs4_lookup_root(server, fhandle, info); + if (status == -EPERM) + status = nfs4_find_root_sec(server, fhandle, info); if (status == 0) status = nfs4_server_capabilities(server, fhandle); if (status == 0) -- cgit v0.10.2 From 9b7160c55a41dd2fec3d467f979e55782d3f92ad Mon Sep 17 00:00:00 2001 From: Bryan Schumaker Date: Wed, 13 Apr 2011 14:31:30 -0400 Subject: NFS: don't negotiate when user specifies sec flavor We were always attempting sec flavor negotiation, even if the user told us a specific sec flavor to use. If that sec flavor fails, we should return an error rather than continuing with sec flavor negotiation. Signed-off-by: Bryan Schumaker Signed-off-by: Trond Myklebust diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index 7e27ebf..b8e1ac6 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c @@ -46,6 +46,7 @@ #include #include #include +#include #include #include #include @@ -2234,7 +2235,7 @@ static int nfs4_proc_get_root(struct nfs_server *server, struct nfs_fh *fhandle, struct nfs_fsinfo *info) { int status = nfs4_lookup_root(server, fhandle, info); - if (status == -EPERM) + if ((status == -EPERM) && !(server->flags & NFS_MOUNT_SECFLAVOUR)) status = nfs4_find_root_sec(server, fhandle, info); if (status == 0) status = nfs4_server_capabilities(server, fhandle); diff --git a/fs/nfs/super.c b/fs/nfs/super.c index 685a8a7..75bcc3f 100644 --- a/fs/nfs/super.c +++ b/fs/nfs/super.c @@ -1004,6 +1004,7 @@ static int nfs_parse_security_flavors(char *value, return 0; } + mnt->flags |= NFS_MOUNT_SECFLAVOUR; mnt->auth_flavor_len = 1; return 1; } -- cgit v0.10.2 From c3dfc2808ab82b13f8b6db62189da959c2eadeea Mon Sep 17 00:00:00 2001 From: Bryan Schumaker Date: Wed, 13 Apr 2011 14:31:31 -0400 Subject: NFS: Use correct variable for page bounds checking While decoding a secinfo reply, I store the list of supported sec flavors on a page accessible through res->flavors. Before reading each new flavor, I do some math to determine if there is enough space left on this page, and I break out of my read look if there isn't. In order to perform this check correctly, I need to use the address of res->flavors, rather than the address of res. When this loop was broken early I lied to the caller and told them that the entire list had been decoded. This could lead to problems if the caller tries to use any the garbage data claiming to be a valid sec flavor. I fixed this by using res->flavors->num_flavors as a counter, incrementing it every time a sec flavor is successfully decoded. Signed-off-by: Bryan Schumaker Signed-off-by: Trond Myklebust diff --git a/fs/nfs/nfs4xdr.c b/fs/nfs/nfs4xdr.c index dddfb57..ba952bd 100644 --- a/fs/nfs/nfs4xdr.c +++ b/fs/nfs/nfs4xdr.c @@ -4838,17 +4838,19 @@ static int decode_secinfo(struct xdr_stream *xdr, struct nfs4_secinfo_res *res) struct nfs4_secinfo_flavor *sec_flavor; int status; __be32 *p; - int i; + int i, num_flavors; status = decode_op_hdr(xdr, OP_SECINFO); p = xdr_inline_decode(xdr, 4); if (unlikely(!p)) goto out_overflow; - res->flavors->num_flavors = be32_to_cpup(p); - for (i = 0; i < res->flavors->num_flavors; i++) { + res->flavors->num_flavors = 0; + num_flavors = be32_to_cpup(p); + + for (i = 0; i < num_flavors; i++) { sec_flavor = &res->flavors->flavors[i]; - if ((char *)&sec_flavor[1] - (char *)res > PAGE_SIZE) + if ((char *)&sec_flavor[1] - (char *)res->flavors > PAGE_SIZE) break; p = xdr_inline_decode(xdr, 4); @@ -4860,6 +4862,7 @@ static int decode_secinfo(struct xdr_stream *xdr, struct nfs4_secinfo_res *res) if (decode_secinfo_gss(xdr, sec_flavor)) break; } + res->flavors->num_flavors++; } return 0; -- cgit v0.10.2 From 12488e01fb2b06bb3f6ee137efc88e29d827817e Mon Sep 17 00:00:00 2001 From: Nishant Sarmukadam Date: Fri, 8 Apr 2011 14:38:27 +0530 Subject: mwl8k: interrupt handling changes We do not need to enable all the interrupts in mwl8k_probe_hw. We need to enable only MWL8K_A2H_INT_OPC_DONE interrupt for sending commands to the firmware. Keep the other interrupts masked in mwl8k_probe_hw. Also, in mwl8k_start, where we expect other interrupts, enable only those interrupts we are interested in. Signed-off-by: Nishant Sarmukadam Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c index fb472f4..d241670 100644 --- a/drivers/net/wireless/mwl8k.c +++ b/drivers/net/wireless/mwl8k.c @@ -4284,6 +4284,8 @@ static int mwl8k_start(struct ieee80211_hw *hw) /* Enable interrupts */ iowrite32(MWL8K_A2H_EVENTS, priv->regs + MWL8K_HIU_A2H_INTERRUPT_MASK); + iowrite32(MWL8K_A2H_EVENTS, + priv->regs + MWL8K_HIU_A2H_INTERRUPT_STATUS_MASK); rc = mwl8k_fw_lock(hw); if (!rc) { @@ -5282,7 +5284,8 @@ static int mwl8k_probe_hw(struct ieee80211_hw *hw) iowrite32(MWL8K_A2H_INT_TX_DONE|MWL8K_A2H_INT_RX_READY| MWL8K_A2H_INT_BA_WATCHDOG, priv->regs + MWL8K_HIU_A2H_INTERRUPT_CLEAR_SEL); - iowrite32(0xffffffff, priv->regs + MWL8K_HIU_A2H_INTERRUPT_STATUS_MASK); + iowrite32(MWL8K_A2H_INT_OPC_DONE, + priv->regs + MWL8K_HIU_A2H_INTERRUPT_STATUS_MASK); rc = request_irq(priv->pdev->irq, mwl8k_interrupt, IRQF_SHARED, MWL8K_NAME, hw); -- cgit v0.10.2 From 8e26a0303614e766f993b1ac4a5bfbf80436d9dd Mon Sep 17 00:00:00 2001 From: Gabor Juhos Date: Tue, 12 Apr 2011 18:23:16 +0200 Subject: ath9k: introduce ATH9K_{PCI,AHB} config options Currently ath9k only available in menuconfig if PCI bus support is enabled. However the driver is required for the built-in wireless MACs of the Atheros AR9130/AR9132 SoCs. These SoCs have no PCI controller, the wireless MAC is connected to the AHB bus on them. Introduce separated config options for the supported buses, in order to allow building of ath9h without PCI bus support. As a bonus, this patch removes the cross-reference of the ATHEROS_AR71XX option which is not present in the kernel. Cc: Luis R. Rodriguez Cc: Vasanthakumar Thiagarajan Signed-off-by: Gabor Juhos Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/Kconfig b/drivers/net/wireless/ath/ath9k/Kconfig index ad57a6d..d9ff841 100644 --- a/drivers/net/wireless/ath/ath9k/Kconfig +++ b/drivers/net/wireless/ath/ath9k/Kconfig @@ -5,7 +5,7 @@ config ATH9K_COMMON config ATH9K tristate "Atheros 802.11n wireless cards support" - depends on PCI && MAC80211 + depends on MAC80211 select ATH9K_HW select MAC80211_LEDS select LEDS_CLASS @@ -23,6 +23,25 @@ config ATH9K If you choose to build a module, it'll be called ath9k. +config ATH9K_PCI + bool "Atheros ath9k PCI/PCIe bus support" + depends on ATH9K && PCI + default PCI + ---help--- + This option enables the PCI bus support in ath9k. + + Say Y, if you have a compatible PCI/PCIe wireless card. + +config ATH9K_AHB + bool "Atheros ath9k AHB bus support" + depends on ATH9K + default n + ---help--- + This option enables the AHB bus support in ath9k. + + Say Y, if you have a SoC with a compatible built-in + wireless MAC. Say N if unsure. + config ATH9K_DEBUGFS bool "Atheros ath9k debugging" depends on ATH9K && DEBUG_FS diff --git a/drivers/net/wireless/ath/ath9k/Makefile b/drivers/net/wireless/ath/ath9k/Makefile index 4d66ca8..ca4c436 100644 --- a/drivers/net/wireless/ath/ath9k/Makefile +++ b/drivers/net/wireless/ath/ath9k/Makefile @@ -6,8 +6,8 @@ ath9k-y += beacon.o \ xmit.o \ ath9k-$(CONFIG_ATH9K_RATE_CONTROL) += rc.o -ath9k-$(CONFIG_PCI) += pci.o -ath9k-$(CONFIG_ATHEROS_AR71XX) += ahb.o +ath9k-$(CONFIG_ATH9K_PCI) += pci.o +ath9k-$(CONFIG_ATH9K_AHB) += ahb.o ath9k-$(CONFIG_ATH9K_DEBUGFS) += debug.o obj-$(CONFIG_ATH9K) += ath9k.o diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h index 38835bc..77ad407 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h @@ -665,7 +665,7 @@ void ath_radio_disable(struct ath_softc *sc, struct ieee80211_hw *hw); bool ath9k_setpower(struct ath_softc *sc, enum ath9k_power_mode mode); bool ath9k_uses_beacons(int type); -#ifdef CONFIG_PCI +#ifdef CONFIG_ATH9K_PCI int ath_pci_init(void); void ath_pci_exit(void); #else @@ -673,7 +673,7 @@ static inline int ath_pci_init(void) { return 0; }; static inline void ath_pci_exit(void) {}; #endif -#ifdef CONFIG_ATHEROS_AR71XX +#ifdef CONFIG_ATH9K_AHB int ath_ahb_init(void); void ath_ahb_exit(void); #else -- cgit v0.10.2 From 4114fa21465ec7ee9526173676d3122a98bbbbd8 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Tue, 12 Apr 2011 19:15:22 +0200 Subject: mac80211: receive EAP frames from a station in an AP VLAN on the main AP This makes it easier to handle moving stations to VLAN interfaces that are part of a different bridge. Signed-off-by: Felix Fietkau Signed-off-by: John W. Linville diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index 359fc39..54858a6 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -1586,7 +1586,7 @@ ieee80211_drop_unencrypted_mgmt(struct ieee80211_rx_data *rx) } static int -__ieee80211_data_to_8023(struct ieee80211_rx_data *rx) +__ieee80211_data_to_8023(struct ieee80211_rx_data *rx, bool *port_control) { struct ieee80211_sub_if_data *sdata = rx->sdata; struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)rx->skb->data; @@ -1594,6 +1594,7 @@ __ieee80211_data_to_8023(struct ieee80211_rx_data *rx) struct ethhdr *ehdr; int ret; + *port_control = false; if (ieee80211_has_a4(hdr->frame_control) && sdata->vif.type == NL80211_IFTYPE_AP_VLAN && !sdata->u.vlan.sta) return -1; @@ -1612,11 +1613,13 @@ __ieee80211_data_to_8023(struct ieee80211_rx_data *rx) return -1; ret = ieee80211_data_to_8023(rx->skb, sdata->vif.addr, sdata->vif.type); - if (ret < 0 || !check_port_control) + if (ret < 0) return ret; ehdr = (struct ethhdr *) rx->skb->data; - if (ehdr->h_proto != rx->sdata->control_port_protocol) + if (ehdr->h_proto == rx->sdata->control_port_protocol) + *port_control = true; + else if (check_port_control) return -1; return 0; @@ -1917,6 +1920,7 @@ ieee80211_rx_h_data(struct ieee80211_rx_data *rx) struct net_device *dev = sdata->dev; struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)rx->skb->data; __le16 fc = hdr->frame_control; + bool port_control; int err; if (unlikely(!ieee80211_is_data(hdr->frame_control))) @@ -1933,13 +1937,21 @@ ieee80211_rx_h_data(struct ieee80211_rx_data *rx) sdata->vif.type == NL80211_IFTYPE_AP) return RX_DROP_MONITOR; - err = __ieee80211_data_to_8023(rx); + err = __ieee80211_data_to_8023(rx, &port_control); if (unlikely(err)) return RX_DROP_UNUSABLE; if (!ieee80211_frame_allowed(rx, fc)) return RX_DROP_MONITOR; + if (rx->sdata->vif.type == NL80211_IFTYPE_AP_VLAN && + unlikely(port_control) && sdata->bss) { + sdata = container_of(sdata->bss, struct ieee80211_sub_if_data, + u.ap); + dev = sdata->dev; + rx->sdata = sdata; + } + rx->skb->dev = dev; dev->stats.rx_packets++; -- cgit v0.10.2 From d0805c1c5758f8fd16c88bf1efa8fb4be4408ce1 Mon Sep 17 00:00:00 2001 From: Brian Cavagnolo Date: Tue, 12 Apr 2011 11:06:28 -0700 Subject: mwl8k: use traffic threshold to decide when to start ampdu Currently, ampdu stream is created on the first qos packet to an HT sta. The overhead of setting up the BA session may not be justified if the outgoing packet rate is minimal (e.g., ping). So we only allow ampdu streams after seeing a critical number of packets in an arbitrary one-second interval. Based on work by Nishant Sarmukadam Signed-off-by: Brian Cavagnolo Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c index d241670..28ebaec 100644 --- a/drivers/net/wireless/mwl8k.c +++ b/drivers/net/wireless/mwl8k.c @@ -289,10 +289,17 @@ struct mwl8k_vif { #define MWL8K_VIF(_vif) ((struct mwl8k_vif *)&((_vif)->drv_priv)) #define IEEE80211_KEY_CONF(_u8) ((struct ieee80211_key_conf *)(_u8)) +struct tx_traffic_info { + u32 start_time; + u32 pkts; +}; + +#define MWL8K_MAX_TID 8 struct mwl8k_sta { /* Index into station database. Returned by UPDATE_STADB. */ u8 peer_id; u8 is_ampdu_allowed; + struct tx_traffic_info tx_stats[MWL8K_MAX_TID]; }; #define MWL8K_STA(_sta) ((struct mwl8k_sta *)&((_sta)->drv_priv)) @@ -1754,6 +1761,41 @@ mwl8k_lookup_stream(struct ieee80211_hw *hw, u8 *addr, u8 tid) return NULL; } +#define MWL8K_AMPDU_PACKET_THRESHOLD 64 +static inline bool mwl8k_ampdu_allowed(struct ieee80211_sta *sta, u8 tid) +{ + struct mwl8k_sta *sta_info = MWL8K_STA(sta); + struct tx_traffic_info *tx_stats; + + BUG_ON(tid >= MWL8K_MAX_TID); + tx_stats = &sta_info->tx_stats[tid]; + + return sta_info->is_ampdu_allowed && + tx_stats->pkts > MWL8K_AMPDU_PACKET_THRESHOLD; +} + +static inline void mwl8k_tx_count_packet(struct ieee80211_sta *sta, u8 tid) +{ + struct mwl8k_sta *sta_info = MWL8K_STA(sta); + struct tx_traffic_info *tx_stats; + + BUG_ON(tid >= MWL8K_MAX_TID); + tx_stats = &sta_info->tx_stats[tid]; + + if (tx_stats->start_time == 0) + tx_stats->start_time = jiffies; + + /* reset the packet count after each second elapses. If the number of + * packets ever exceeds the ampdu_min_traffic threshold, we will allow + * an ampdu stream to be started. + */ + if (jiffies - tx_stats->start_time > HZ) { + tx_stats->pkts = 0; + tx_stats->start_time = 0; + } else + tx_stats->pkts++; +} + static void mwl8k_txq_xmit(struct ieee80211_hw *hw, int index, struct sk_buff *skb) { @@ -1840,6 +1882,7 @@ mwl8k_txq_xmit(struct ieee80211_hw *hw, int index, struct sk_buff *skb) skb->protocol != cpu_to_be16(ETH_P_PAE) && sta->ht_cap.ht_supported && priv->ap_fw) { tid = qos & 0xf; + mwl8k_tx_count_packet(sta, tid); spin_lock(&priv->stream_lock); stream = mwl8k_lookup_stream(hw, sta->addr, tid); if (stream != NULL) { @@ -1880,7 +1923,7 @@ mwl8k_txq_xmit(struct ieee80211_hw *hw, int index, struct sk_buff *skb) * prevents sequence number mismatch at the recepient * as described above. */ - if (MWL8K_STA(sta)->is_ampdu_allowed) { + if (mwl8k_ampdu_allowed(sta, tid)) { stream = mwl8k_add_stream(hw, sta, tid); if (stream != NULL) start_ba_session = true; -- cgit v0.10.2 From 9efabad2b228ef820f5ce969baa62860cf65b9ea Mon Sep 17 00:00:00 2001 From: Sujith Manoharan Date: Wed, 13 Apr 2011 11:22:33 +0530 Subject: ath9k_htc: Remove AR7010 v1.0 support All the AR7010 devices supoprted by ath9k_htc are based on version v1.1, so remove support for v1.0. Signed-off-by: Sujith Manoharan Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/hif_usb.c b/drivers/net/wireless/ath/ath9k/hif_usb.c index f1b8af6..3d53d98 100644 --- a/drivers/net/wireless/ath/ath9k/hif_usb.c +++ b/drivers/net/wireless/ath/ath9k/hif_usb.c @@ -17,11 +17,9 @@ #include "htc.h" /* identify firmware images */ -#define FIRMWARE_AR7010 "ar7010.fw" #define FIRMWARE_AR7010_1_1 "ar7010_1_1.fw" #define FIRMWARE_AR9271 "ar9271.fw" -MODULE_FIRMWARE(FIRMWARE_AR7010); MODULE_FIRMWARE(FIRMWARE_AR7010_1_1); MODULE_FIRMWARE(FIRMWARE_AR9271); @@ -1026,10 +1024,7 @@ static int ath9k_hif_usb_probe(struct usb_interface *interface, /* Find out which firmware to load */ if (IS_AR7010_DEVICE(id->driver_info)) - if (le16_to_cpu(udev->descriptor.bcdDevice) == 0x0202) - hif_dev->fw_name = FIRMWARE_AR7010_1_1; - else - hif_dev->fw_name = FIRMWARE_AR7010; + hif_dev->fw_name = FIRMWARE_AR7010_1_1; else hif_dev->fw_name = FIRMWARE_AR9271; -- cgit v0.10.2 From ce18f391aa872a910e7798c340b6cf22d02c77a2 Mon Sep 17 00:00:00 2001 From: Sujith Manoharan Date: Wed, 13 Apr 2011 11:22:42 +0530 Subject: ath9k_htc: Rename firmware Since the new FW requires backward incompatible host driver changes, rename the FW to allow older driver versions to work with the older FW. Signed-off-by: Sujith Manoharan Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/hif_usb.c b/drivers/net/wireless/ath/ath9k/hif_usb.c index 3d53d98..23094b7 100644 --- a/drivers/net/wireless/ath/ath9k/hif_usb.c +++ b/drivers/net/wireless/ath/ath9k/hif_usb.c @@ -17,8 +17,8 @@ #include "htc.h" /* identify firmware images */ -#define FIRMWARE_AR7010_1_1 "ar7010_1_1.fw" -#define FIRMWARE_AR9271 "ar9271.fw" +#define FIRMWARE_AR7010_1_1 "htc_7010.fw" +#define FIRMWARE_AR9271 "htc_9271.fw" MODULE_FIRMWARE(FIRMWARE_AR7010_1_1); MODULE_FIRMWARE(FIRMWARE_AR9271); -- cgit v0.10.2 From 29bbfb2491316f9a3888e74b0de7fccdbde67aaa Mon Sep 17 00:00:00 2001 From: Sujith Manoharan Date: Wed, 13 Apr 2011 11:22:51 +0530 Subject: ath9k_htc: Add a WMI command to get the firmware version Also, update the wiphy information and use the correct device pointer when registering. This would fix ethtool. Signed-off-by: Sujith Manoharan Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/htc.h b/drivers/net/wireless/ath/ath9k/htc.h index ec47be9..9544cd7 100644 --- a/drivers/net/wireless/ath/ath9k/htc.h +++ b/drivers/net/wireless/ath/ath9k/htc.h @@ -388,6 +388,9 @@ struct ath9k_htc_priv { struct htc_target *htc; struct wmi *wmi; + u16 fw_version_major; + u16 fw_version_minor; + enum htc_endpoint_id wmi_cmd_ep; enum htc_endpoint_id beacon_ep; enum htc_endpoint_id cab_ep; diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_init.c b/drivers/net/wireless/ath/ath9k/htc_drv_init.c index 8303b34..6bbfca5 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_init.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_init.c @@ -782,6 +782,32 @@ static void ath9k_set_hw_capab(struct ath9k_htc_priv *priv, SET_IEEE80211_PERM_ADDR(hw, common->macaddr); } +static int ath9k_init_firmware_version(struct ath9k_htc_priv *priv) +{ + struct ieee80211_hw *hw = priv->hw; + struct wmi_fw_version cmd_rsp; + int ret; + + memset(&cmd_rsp, 0, sizeof(cmd_rsp)); + + WMI_CMD(WMI_GET_FW_VERSION); + if (ret) + return -EINVAL; + + priv->fw_version_major = be16_to_cpu(cmd_rsp.major); + priv->fw_version_minor = be16_to_cpu(cmd_rsp.minor); + + snprintf(hw->wiphy->fw_version, ETHTOOL_BUSINFO_LEN, "%d.%d", + priv->fw_version_major, + priv->fw_version_minor); + + dev_info(priv->dev, "ath9k_htc: FW Version: %d.%d\n", + priv->fw_version_major, + priv->fw_version_minor); + + return 0; +} + static int ath9k_init_device(struct ath9k_htc_priv *priv, u16 devid, char *product, u32 drv_info) { @@ -801,6 +827,10 @@ static int ath9k_init_device(struct ath9k_htc_priv *priv, common = ath9k_hw_common(ah); ath9k_set_hw_capab(priv, hw); + error = ath9k_init_firmware_version(priv); + if (error != 0) + goto err_fw; + /* Initialize regulatory */ error = ath_regd_init(&common->regulatory, priv->hw->wiphy, ath9k_reg_notifier); @@ -861,6 +891,8 @@ err_rx: err_tx: /* Nothing */ err_regd: + /* Nothing */ +err_fw: ath9k_deinit_priv(priv); err_init: return error; diff --git a/drivers/net/wireless/ath/ath9k/wmi.c b/drivers/net/wireless/ath/ath9k/wmi.c index d3d2490..267a98f 100644 --- a/drivers/net/wireless/ath/ath9k/wmi.c +++ b/drivers/net/wireless/ath/ath9k/wmi.c @@ -23,6 +23,8 @@ static const char *wmi_cmd_to_name(enum wmi_cmd_id wmi_cmd) return "WMI_ECHO_CMDID"; case WMI_ACCESS_MEMORY_CMDID: return "WMI_ACCESS_MEMORY_CMDID"; + case WMI_GET_FW_VERSION: + return "WMI_GET_FW_VERSION"; case WMI_DISABLE_INTR_CMDID: return "WMI_DISABLE_INTR_CMDID"; case WMI_ENABLE_INTR_CMDID: diff --git a/drivers/net/wireless/ath/ath9k/wmi.h b/drivers/net/wireless/ath/ath9k/wmi.h index 4208427..6a36572 100644 --- a/drivers/net/wireless/ath/ath9k/wmi.h +++ b/drivers/net/wireless/ath/ath9k/wmi.h @@ -31,11 +31,17 @@ struct wmi_cmd_hdr { __be16 seq_no; } __packed; +struct wmi_fw_version { + __be16 major; + __be16 minor; + +} __packed; enum wmi_cmd_id { WMI_ECHO_CMDID = 0x0001, WMI_ACCESS_MEMORY_CMDID, /* Commands to Target */ + WMI_GET_FW_VERSION, WMI_DISABLE_INTR_CMDID, WMI_ENABLE_INTR_CMDID, WMI_RX_LINK_CMDID, -- cgit v0.10.2 From 1c165c972b040f9ce199b8d8d3cc4f619872cba5 Mon Sep 17 00:00:00 2001 From: Sujith Manoharan Date: Wed, 13 Apr 2011 11:22:59 +0530 Subject: ath9k_htc: Fix WMI and beacon header Match the beacon header with that of the firmware. Also, the firmware reports the TSF for an SWBA, so store it. Signed-off-by: Sujith Manoharan Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/htc.h b/drivers/net/wireless/ath/ath9k/htc.h index 9544cd7..cf7909e 100644 --- a/drivers/net/wireless/ath/ath9k/htc.h +++ b/drivers/net/wireless/ath/ath9k/htc.h @@ -96,8 +96,8 @@ struct tx_mgmt_hdr { } __packed; struct tx_beacon_header { - u8 len_changed; u8 vif_index; + u8 len_changed; u16 rev; } __packed; diff --git a/drivers/net/wireless/ath/ath9k/wmi.c b/drivers/net/wireless/ath/ath9k/wmi.c index 267a98f..96171a2 100644 --- a/drivers/net/wireless/ath/ath9k/wmi.c +++ b/drivers/net/wireless/ath/ath9k/wmi.c @@ -156,6 +156,7 @@ static void ath9k_wmi_ctrl_rx(void *priv, struct sk_buff *skb, struct wmi_cmd_hdr *hdr; u16 cmd_id; void *wmi_event; + struct wmi_event_swba *swba; #ifdef CONFIG_ATH9K_HTC_DEBUGFS __be32 txrate; #endif @@ -170,7 +171,11 @@ static void ath9k_wmi_ctrl_rx(void *priv, struct sk_buff *skb, wmi_event = skb_pull(skb, sizeof(struct wmi_cmd_hdr)); switch (cmd_id) { case WMI_SWBA_EVENTID: - wmi->beacon_pending = *(u8 *)wmi_event; + swba = (struct wmi_event_swba *) wmi_event; + + wmi->tsf = be64_to_cpu(swba->tsf); + wmi->beacon_pending = swba->beacon_pending; + tasklet_schedule(&wmi->drv_priv->swba_tasklet); break; case WMI_FATAL_EVENTID: diff --git a/drivers/net/wireless/ath/ath9k/wmi.h b/drivers/net/wireless/ath/ath9k/wmi.h index 6a36572..2fa91a9 100644 --- a/drivers/net/wireless/ath/ath9k/wmi.h +++ b/drivers/net/wireless/ath/ath9k/wmi.h @@ -36,6 +36,11 @@ struct wmi_fw_version { __be16 minor; } __packed; + +struct wmi_event_swba { + __be64 tsf; + u8 beacon_pending; +}; enum wmi_cmd_id { WMI_ECHO_CMDID = 0x0001, WMI_ACCESS_MEMORY_CMDID, @@ -106,6 +111,7 @@ struct wmi { u32 cmd_rsp_len; bool stopped; + u64 tsf; u8 beacon_pending; spinlock_t wmi_lock; -- cgit v0.10.2 From 832f6a18fc2aead14954c081ece03b7a5b425f81 Mon Sep 17 00:00:00 2001 From: Sujith Manoharan Date: Wed, 13 Apr 2011 11:23:08 +0530 Subject: ath9k_htc: Add beacon slots Beacon transmission is now handled through a slot mechanism. This allows multiple beaconing interfaces to be be present. Signed-off-by: Sujith Manoharan Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/htc.h b/drivers/net/wireless/ath/ath9k/htc.h index cf7909e..31c6496 100644 --- a/drivers/net/wireless/ath/ath9k/htc.h +++ b/drivers/net/wireless/ath/ath9k/htc.h @@ -244,6 +244,7 @@ struct ath9k_htc_vif { u8 index; u16 seq_no; bool beacon_configured; + int bslot; }; struct ath9k_vif_iter_data { @@ -351,10 +352,14 @@ struct ath_led { int brightness; }; +#define BSTUCK_THRESHOLD 10 + struct htc_beacon_config { + struct ieee80211_vif *bslot[ATH9K_HTC_MAX_BCN_VIF]; u16 beacon_interval; u16 dtim_period; u16 bmiss_timeout; + u32 bmiss_cnt; }; struct ath_btcoex { @@ -414,7 +419,6 @@ struct ath9k_htc_priv { u16 txpowlimit; u16 nvifs; u16 nstations; - u32 bmiss_cnt; bool rearm_ani; bool reconfig_beacon; @@ -425,7 +429,6 @@ struct ath9k_htc_priv { bool tx_queues_stop; spinlock_t tx_lock; - struct ieee80211_vif *vif; struct htc_beacon_config cur_beacon_conf; unsigned int rxfilter; struct tasklet_struct swba_tasklet; @@ -473,11 +476,15 @@ static inline void ath_read_cachesize(struct ath_common *common, int *csz) void ath9k_htc_reset(struct ath9k_htc_priv *priv); +void ath9k_htc_assign_bslot(struct ath9k_htc_priv *priv, + struct ieee80211_vif *vif); +void ath9k_htc_remove_bslot(struct ath9k_htc_priv *priv, + struct ieee80211_vif *vif); void ath9k_htc_beaconq_config(struct ath9k_htc_priv *priv); void ath9k_htc_beacon_config(struct ath9k_htc_priv *priv, struct ieee80211_vif *vif); void ath9k_htc_beacon_reconfig(struct ath9k_htc_priv *priv); -void ath9k_htc_swba(struct ath9k_htc_priv *priv, u8 beacon_pending); +void ath9k_htc_swba(struct ath9k_htc_priv *priv); void ath9k_htc_rxep(void *priv, struct sk_buff *skb, enum htc_endpoint_id ep_id); diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c b/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c index 8f56158..b561f70 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c @@ -172,12 +172,13 @@ static void ath9k_htc_beacon_config_ap(struct ath9k_htc_priv *priv, imask |= ATH9K_INT_SWBA; ath_dbg(common, ATH_DBG_CONFIG, - "AP Beacon config, intval: %d, nexttbtt: %u imask: 0x%x\n", + "AP Beacon config, intval: %d, nexttbtt: %u " + "imask: 0x%x\n", bss_conf->beacon_interval, nexttbtt, imask); WMI_CMD(WMI_DISABLE_INTR_CMDID); ath9k_hw_beaconinit(priv->ah, TU_TO_USEC(nexttbtt), TU_TO_USEC(intval)); - priv->bmiss_cnt = 0; + priv->cur_beacon_conf.bmiss_cnt = 0; htc_imask = cpu_to_be32(imask); WMI_CMD_BUF(WMI_ENABLE_INTR_CMDID, &htc_imask); } @@ -214,7 +215,7 @@ static void ath9k_htc_beacon_config_adhoc(struct ath9k_htc_priv *priv, WMI_CMD(WMI_DISABLE_INTR_CMDID); ath9k_hw_beaconinit(priv->ah, TU_TO_USEC(nexttbtt), TU_TO_USEC(intval)); - priv->bmiss_cnt = 0; + priv->cur_beacon_conf.bmiss_cnt = 0; htc_imask = cpu_to_be32(imask); WMI_CMD_BUF(WMI_ENABLE_INTR_CMDID, &htc_imask); } @@ -225,9 +226,11 @@ void ath9k_htc_beaconep(void *drv_priv, struct sk_buff *skb, dev_kfree_skb_any(skb); } -void ath9k_htc_swba(struct ath9k_htc_priv *priv, u8 beacon_pending) +static void ath9k_htc_send_beacon(struct ath9k_htc_priv *priv, + int slot) { - struct ath9k_htc_vif *avp = (void *)priv->vif->drv_priv; + struct ieee80211_vif *vif; + struct ath9k_htc_vif *avp; struct tx_beacon_header beacon_hdr; struct ath9k_htc_tx_ctl tx_ctl; struct ieee80211_tx_info *info; @@ -237,21 +240,18 @@ void ath9k_htc_swba(struct ath9k_htc_priv *priv, u8 beacon_pending) memset(&beacon_hdr, 0, sizeof(struct tx_beacon_header)); memset(&tx_ctl, 0, sizeof(struct ath9k_htc_tx_ctl)); - /* FIXME: Handle BMISS */ - if (beacon_pending != 0) { - priv->bmiss_cnt++; - return; - } - spin_lock_bh(&priv->beacon_lock); + vif = priv->cur_beacon_conf.bslot[slot]; + avp = (struct ath9k_htc_vif *)vif->drv_priv; + if (unlikely(priv->op_flags & OP_SCANNING)) { spin_unlock_bh(&priv->beacon_lock); return; } /* Get a new beacon */ - beacon = ieee80211_beacon_get(priv->hw, priv->vif); + beacon = ieee80211_beacon_get(priv->hw, vif); if (!beacon) { spin_unlock_bh(&priv->beacon_lock); return; @@ -276,6 +276,69 @@ void ath9k_htc_swba(struct ath9k_htc_priv *priv, u8 beacon_pending) spin_unlock_bh(&priv->beacon_lock); } +static int ath9k_htc_choose_bslot(struct ath9k_htc_priv *priv) +{ + struct ath_common *common = ath9k_hw_common(priv->ah); + unsigned long flags; + u64 tsf; + u32 tsftu; + u16 intval; + int slot; + + intval = priv->cur_beacon_conf.beacon_interval & ATH9K_BEACON_PERIOD; + + spin_lock_irqsave(&priv->wmi->wmi_lock, flags); + tsf = priv->wmi->tsf; + spin_unlock_irqrestore(&priv->wmi->wmi_lock, flags); + + tsftu = TSF_TO_TU(tsf >> 32, tsf); + slot = ((tsftu % intval) * ATH9K_HTC_MAX_BCN_VIF) / intval; + slot = ATH9K_HTC_MAX_BCN_VIF - slot - 1; + + ath_dbg(common, ATH_DBG_BEACON, + "Choose slot: %d, tsf: %llu, tsftu: %u, intval: %u\n", + slot, tsf, tsftu, intval); + + return slot; +} + +void ath9k_htc_swba(struct ath9k_htc_priv *priv) +{ + struct ath_common *common = ath9k_hw_common(priv->ah); + unsigned long flags; + int slot; + + spin_lock_irqsave(&priv->wmi->wmi_lock, flags); + if (priv->wmi->beacon_pending != 0) { + spin_unlock_irqrestore(&priv->wmi->wmi_lock, flags); + priv->cur_beacon_conf.bmiss_cnt++; + if (priv->cur_beacon_conf.bmiss_cnt > BSTUCK_THRESHOLD) { + ath_dbg(common, ATH_DBG_BEACON, + "Beacon stuck, HW reset\n"); + ath9k_htc_reset(priv); + } + return; + } + spin_unlock_irqrestore(&priv->wmi->wmi_lock, flags); + + if (priv->cur_beacon_conf.bmiss_cnt) { + ath_dbg(common, ATH_DBG_BEACON, + "Resuming beacon xmit after %u misses\n", + priv->cur_beacon_conf.bmiss_cnt); + priv->cur_beacon_conf.bmiss_cnt = 0; + } + + slot = ath9k_htc_choose_bslot(priv); + spin_lock_bh(&priv->beacon_lock); + if (priv->cur_beacon_conf.bslot[slot] == NULL) { + spin_unlock_bh(&priv->beacon_lock); + return; + } + spin_unlock_bh(&priv->beacon_lock); + + ath9k_htc_send_beacon(priv, slot); +} + /* Currently, only for IBSS */ void ath9k_htc_beaconq_config(struct ath9k_htc_priv *priv) { @@ -307,6 +370,42 @@ void ath9k_htc_beaconq_config(struct ath9k_htc_priv *priv) } } +void ath9k_htc_assign_bslot(struct ath9k_htc_priv *priv, + struct ieee80211_vif *vif) +{ + struct ath_common *common = ath9k_hw_common(priv->ah); + struct ath9k_htc_vif *avp = (struct ath9k_htc_vif *)vif->drv_priv; + int i = 0; + + spin_lock_bh(&priv->beacon_lock); + for (i = 0; i < ATH9K_HTC_MAX_BCN_VIF; i++) { + if (priv->cur_beacon_conf.bslot[i] == NULL) { + avp->bslot = i; + break; + } + } + + priv->cur_beacon_conf.bslot[avp->bslot] = vif; + spin_unlock_bh(&priv->beacon_lock); + + ath_dbg(common, ATH_DBG_CONFIG, + "Added interface at beacon slot: %d\n", avp->bslot); +} + +void ath9k_htc_remove_bslot(struct ath9k_htc_priv *priv, + struct ieee80211_vif *vif) +{ + struct ath_common *common = ath9k_hw_common(priv->ah); + struct ath9k_htc_vif *avp = (struct ath9k_htc_vif *)vif->drv_priv; + + spin_lock_bh(&priv->beacon_lock); + priv->cur_beacon_conf.bslot[avp->bslot] = NULL; + spin_unlock_bh(&priv->beacon_lock); + + ath_dbg(common, ATH_DBG_CONFIG, + "Removed interface at beacon slot: %d\n", avp->bslot); +} + static void ath9k_htc_beacon_iter(void *data, u8 *mac, struct ieee80211_vif *vif) { bool *beacon_configured = (bool *)data; diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_init.c b/drivers/net/wireless/ath/ath9k/htc_drv_init.c index 6bbfca5..9405e0a 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_init.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_init.c @@ -643,7 +643,7 @@ static int ath9k_init_priv(struct ath9k_htc_priv *priv, { struct ath_hw *ah = NULL; struct ath_common *common; - int ret = 0, csz = 0; + int i, ret = 0, csz = 0; priv->op_flags |= OP_INVALID; @@ -711,6 +711,9 @@ static int ath9k_init_priv(struct ath9k_htc_priv *priv, if (ret) goto err_queues; + for (i = 0; i < ATH9K_HTC_MAX_BCN_VIF; i++) + priv->cur_beacon_conf.bslot[i] = NULL; + ath9k_init_crypto(priv); ath9k_init_channels_rates(priv); ath9k_init_misc(priv); diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_main.c b/drivers/net/wireless/ath/ath9k/htc_drv_main.c index db8c0c0..293a9b3 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_main.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_main.c @@ -1281,9 +1281,13 @@ static int ath9k_htc_add_interface(struct ieee80211_hw *hw, priv->vif_slot |= (1 << avp->index); priv->nvifs++; - priv->vif = vif; INC_VIF(priv, vif->type); + + if ((vif->type == NL80211_IFTYPE_AP) || + (vif->type == NL80211_IFTYPE_ADHOC)) + ath9k_htc_assign_bslot(priv, vif); + ath9k_htc_set_opmode(priv); if ((priv->ah->opmode == NL80211_IFTYPE_AP) && @@ -1321,9 +1325,13 @@ static void ath9k_htc_remove_interface(struct ieee80211_hw *hw, priv->vif_slot &= ~(1 << avp->index); ath9k_htc_remove_station(priv, vif, NULL); - priv->vif = NULL; DEC_VIF(priv, vif->type); + + if ((vif->type == NL80211_IFTYPE_AP) || + (vif->type == NL80211_IFTYPE_ADHOC)) + ath9k_htc_remove_bslot(priv, vif); + ath9k_htc_set_opmode(priv); /* diff --git a/drivers/net/wireless/ath/ath9k/wmi.c b/drivers/net/wireless/ath/ath9k/wmi.c index 96171a2..a39552b 100644 --- a/drivers/net/wireless/ath/ath9k/wmi.c +++ b/drivers/net/wireless/ath/ath9k/wmi.c @@ -126,7 +126,7 @@ void ath9k_swba_tasklet(unsigned long data) { struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *)data; - ath9k_htc_swba(priv, priv->wmi->beacon_pending); + ath9k_htc_swba(priv); } void ath9k_fatal_work(struct work_struct *work) @@ -173,8 +173,10 @@ static void ath9k_wmi_ctrl_rx(void *priv, struct sk_buff *skb, case WMI_SWBA_EVENTID: swba = (struct wmi_event_swba *) wmi_event; + spin_lock(&wmi->wmi_lock); wmi->tsf = be64_to_cpu(swba->tsf); wmi->beacon_pending = swba->beacon_pending; + spin_unlock(&wmi->wmi_lock); tasklet_schedule(&wmi->drv_priv->swba_tasklet); break; -- cgit v0.10.2 From 9b674a0207c9b75ddcdcdb07e46843fac8267507 Mon Sep 17 00:00:00 2001 From: Sujith Manoharan Date: Wed, 13 Apr 2011 11:23:17 +0530 Subject: ath9k_htc: Add TSF adjust capability In multi-interface mode, beacons/probe responses that are sent out must have their timestamp field updated. Calculate the TSF adjustment value for each beaconing interface and set it in the frame properly. Signed-off-by: Sujith Manoharan Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/htc.h b/drivers/net/wireless/ath/ath9k/htc.h index 31c6496..87e4ca9 100644 --- a/drivers/net/wireless/ath/ath9k/htc.h +++ b/drivers/net/wireless/ath/ath9k/htc.h @@ -245,6 +245,7 @@ struct ath9k_htc_vif { u16 seq_no; bool beacon_configured; int bslot; + __le64 tsfadjust; }; struct ath9k_vif_iter_data { @@ -480,6 +481,8 @@ void ath9k_htc_assign_bslot(struct ath9k_htc_priv *priv, struct ieee80211_vif *vif); void ath9k_htc_remove_bslot(struct ath9k_htc_priv *priv, struct ieee80211_vif *vif); +void ath9k_htc_set_tsfadjust(struct ath9k_htc_priv *priv, + struct ieee80211_vif *vif); void ath9k_htc_beaconq_config(struct ath9k_htc_priv *priv); void ath9k_htc_beacon_config(struct ath9k_htc_priv *priv, struct ieee80211_vif *vif); diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c b/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c index b561f70..2fad613 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c @@ -234,6 +234,7 @@ static void ath9k_htc_send_beacon(struct ath9k_htc_priv *priv, struct tx_beacon_header beacon_hdr; struct ath9k_htc_tx_ctl tx_ctl; struct ieee80211_tx_info *info; + struct ieee80211_mgmt *mgmt; struct sk_buff *beacon; u8 *tx_fhdr; @@ -257,6 +258,13 @@ static void ath9k_htc_send_beacon(struct ath9k_htc_priv *priv, return; } + /* + * Update the TSF adjust value here, the HW will + * add this value for every beacon. + */ + mgmt = (struct ieee80211_mgmt *)beacon->data; + mgmt->u.beacon.timestamp = avp->tsfadjust; + info = IEEE80211_SKB_CB(beacon); if (info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ) { struct ieee80211_hdr *hdr = @@ -406,6 +414,34 @@ void ath9k_htc_remove_bslot(struct ath9k_htc_priv *priv, "Removed interface at beacon slot: %d\n", avp->bslot); } +/* + * Calculate the TSF adjustment value for all slots + * other than zero. + */ +void ath9k_htc_set_tsfadjust(struct ath9k_htc_priv *priv, + struct ieee80211_vif *vif) +{ + struct ath_common *common = ath9k_hw_common(priv->ah); + struct ath9k_htc_vif *avp = (struct ath9k_htc_vif *)vif->drv_priv; + struct htc_beacon_config *cur_conf = &priv->cur_beacon_conf; + u64 tsfadjust; + + if (avp->bslot == 0) + return; + + /* + * The beacon interval cannot be different for multi-AP mode, + * and we reach here only for VIF slots greater than zero, + * so beacon_interval is guaranteed to be set in cur_conf. + */ + tsfadjust = cur_conf->beacon_interval * avp->bslot / ATH9K_HTC_MAX_BCN_VIF; + avp->tsfadjust = cpu_to_le64(TU_TO_USEC(tsfadjust)); + + ath_dbg(common, ATH_DBG_CONFIG, + "tsfadjust is: %llu for bslot: %d\n", + (unsigned long long)tsfadjust, avp->bslot); +} + static void ath9k_htc_beacon_iter(void *data, u8 *mac, struct ieee80211_vif *vif) { bool *beacon_configured = (bool *)data; diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_main.c b/drivers/net/wireless/ath/ath9k/htc_drv_main.c index 293a9b3..6926ac0 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_main.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_main.c @@ -1291,8 +1291,10 @@ static int ath9k_htc_add_interface(struct ieee80211_hw *hw, ath9k_htc_set_opmode(priv); if ((priv->ah->opmode == NL80211_IFTYPE_AP) && - !(priv->op_flags & OP_ANI_RUNNING)) + !(priv->op_flags & OP_ANI_RUNNING)) { + ath9k_hw_set_tsfadjust(priv->ah, 1); ath9k_htc_start_ani(priv); + } ath_dbg(common, ATH_DBG_CONFIG, "Attach a VIF of type: %d at idx: %d\n", vif->type, avp->index); @@ -1652,6 +1654,7 @@ static void ath9k_htc_bss_info_changed(struct ieee80211_hw *hw, if ((changed & BSS_CHANGED_BEACON_ENABLED) && bss_conf->enable_beacon) { ath_dbg(common, ATH_DBG_CONFIG, "Beacon enabled for BSS: %pM\n", bss_conf->bssid); + ath9k_htc_set_tsfadjust(priv, vif); priv->op_flags |= OP_ENABLE_BEACON; ath9k_htc_beacon_config(priv, vif); } diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c b/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c index 4a4f27b..b3f9485 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c @@ -82,11 +82,12 @@ int ath_htc_txq_update(struct ath9k_htc_priv *priv, int qnum, int ath9k_htc_tx_start(struct ath9k_htc_priv *priv, struct sk_buff *skb) { struct ieee80211_hdr *hdr; + struct ieee80211_mgmt *mgmt; struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); struct ieee80211_sta *sta = tx_info->control.sta; struct ieee80211_vif *vif = tx_info->control.vif; struct ath9k_htc_sta *ista; - struct ath9k_htc_vif *avp; + struct ath9k_htc_vif *avp = NULL; struct ath9k_htc_tx_ctl tx_ctl; enum htc_endpoint_id epid; u16 qnum; @@ -195,6 +196,15 @@ int ath9k_htc_tx_start(struct ath9k_htc_priv *priv, struct sk_buff *skb) memset(&mgmt_hdr, 0, sizeof(struct tx_mgmt_hdr)); + /* + * Set the TSF adjust value for probe response + * frame also. + */ + if (avp && unlikely(ieee80211_is_probe_resp(fc))) { + mgmt = (struct ieee80211_mgmt *)skb->data; + mgmt->u.probe_resp.timestamp = avp->tsfadjust; + } + tx_ctl.type = ATH9K_HTC_NORMAL; mgmt_hdr.node_idx = sta_idx; -- cgit v0.10.2 From 2493a547ee81e6daca812d5dd7cf9357aebc379b Mon Sep 17 00:00:00 2001 From: Sujith Manoharan Date: Wed, 13 Apr 2011 11:23:26 +0530 Subject: ath9k_htc: Configure the beacon queue Set operating parameters (cwmin, cwmax) for the beacon queue in AP mode. Signed-off-by: Sujith Manoharan Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c b/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c index 2fad613..7aafd21 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c @@ -18,6 +18,50 @@ #define FUDGE 2 +void ath9k_htc_beaconq_config(struct ath9k_htc_priv *priv) +{ + struct ath_hw *ah = priv->ah; + struct ath9k_tx_queue_info qi, qi_be; + + memset(&qi, 0, sizeof(struct ath9k_tx_queue_info)); + memset(&qi_be, 0, sizeof(struct ath9k_tx_queue_info)); + + ath9k_hw_get_txq_props(ah, priv->beaconq, &qi); + + if (priv->ah->opmode == NL80211_IFTYPE_AP) { + qi.tqi_aifs = 1; + qi.tqi_cwmin = 0; + qi.tqi_cwmax = 0; + } else if (priv->ah->opmode == NL80211_IFTYPE_ADHOC) { + int qnum = priv->hwq_map[WME_AC_BE]; + + ath9k_hw_get_txq_props(ah, qnum, &qi_be); + + qi.tqi_aifs = qi_be.tqi_aifs; + + /* + * For WIFI Beacon Distribution + * Long slot time : 2x cwmin + * Short slot time : 4x cwmin + */ + if (ah->slottime == ATH9K_SLOT_TIME_20) + qi.tqi_cwmin = 2*qi_be.tqi_cwmin; + else + qi.tqi_cwmin = 4*qi_be.tqi_cwmin; + + qi.tqi_cwmax = qi_be.tqi_cwmax; + + } + + if (!ath9k_hw_set_txq_props(ah, priv->beaconq, &qi)) { + ath_err(ath9k_hw_common(ah), + "Unable to update beacon queue %u!\n", priv->beaconq); + } else { + ath9k_hw_resettxqueue(ah, priv->beaconq); + } +} + + static void ath9k_htc_beacon_config_sta(struct ath9k_htc_priv *priv, struct htc_beacon_config *bss_conf) { @@ -176,6 +220,8 @@ static void ath9k_htc_beacon_config_ap(struct ath9k_htc_priv *priv, "imask: 0x%x\n", bss_conf->beacon_interval, nexttbtt, imask); + ath9k_htc_beaconq_config(priv); + WMI_CMD(WMI_DISABLE_INTR_CMDID); ath9k_hw_beaconinit(priv->ah, TU_TO_USEC(nexttbtt), TU_TO_USEC(intval)); priv->cur_beacon_conf.bmiss_cnt = 0; @@ -347,37 +393,6 @@ void ath9k_htc_swba(struct ath9k_htc_priv *priv) ath9k_htc_send_beacon(priv, slot); } -/* Currently, only for IBSS */ -void ath9k_htc_beaconq_config(struct ath9k_htc_priv *priv) -{ - struct ath_hw *ah = priv->ah; - struct ath9k_tx_queue_info qi, qi_be; - int qnum = priv->hwq_map[WME_AC_BE]; - - memset(&qi, 0, sizeof(struct ath9k_tx_queue_info)); - memset(&qi_be, 0, sizeof(struct ath9k_tx_queue_info)); - - ath9k_hw_get_txq_props(ah, qnum, &qi_be); - - qi.tqi_aifs = qi_be.tqi_aifs; - /* For WIFI Beacon Distribution - * Long slot time : 2x cwmin - * Short slot time : 4x cwmin - */ - if (ah->slottime == ATH9K_SLOT_TIME_20) - qi.tqi_cwmin = 2*qi_be.tqi_cwmin; - else - qi.tqi_cwmin = 4*qi_be.tqi_cwmin; - qi.tqi_cwmax = qi_be.tqi_cwmax; - - if (!ath9k_hw_set_txq_props(ah, priv->beaconq, &qi)) { - ath_err(ath9k_hw_common(ah), - "Unable to update beacon queue %u!\n", qnum); - } else { - ath9k_hw_resettxqueue(ah, priv->beaconq); - } -} - void ath9k_htc_assign_bslot(struct ath9k_htc_priv *priv, struct ieee80211_vif *vif) { -- cgit v0.10.2 From 7d547eb4bb664c5a6b7c8790c2ecb0aec5d15385 Mon Sep 17 00:00:00 2001 From: Sujith Manoharan Date: Wed, 13 Apr 2011 11:23:34 +0530 Subject: ath9k_htc: Handle buffered frames in AP mode Use the CAB endpoint to send buffered multicast or broadcast frames after each SWBA event. Signed-off-by: Sujith Manoharan Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/htc.h b/drivers/net/wireless/ath/ath9k/htc.h index 87e4ca9..a072a9e 100644 --- a/drivers/net/wireless/ath/ath9k/htc.h +++ b/drivers/net/wireless/ath/ath9k/htc.h @@ -292,6 +292,7 @@ struct ath9k_htc_tx_ctl { #define TX_STAT_INC(c) (hif_dev->htc_handle->drv_priv->debug.tx_stats.c++) #define RX_STAT_INC(c) (hif_dev->htc_handle->drv_priv->debug.rx_stats.c++) +#define CAB_STAT_INC priv->debug.tx_stats.cab_queued++ #define TX_QSTAT_INC(q) (priv->debug.tx_stats.queue_stats[q]++) @@ -301,6 +302,7 @@ struct ath_tx_stats { u32 skb_queued; u32 skb_completed; u32 skb_dropped; + u32 cab_queued; u32 queue_stats[WME_NUM_AC]; }; @@ -324,6 +326,7 @@ struct ath9k_debug { #define TX_STAT_INC(c) do { } while (0) #define RX_STAT_INC(c) do { } while (0) +#define CAB_STAT_INC do { } while (0) #define TX_QSTAT_INC(c) do { } while (0) @@ -505,7 +508,8 @@ void ath9k_htc_stop_ani(struct ath9k_htc_priv *priv); int ath9k_tx_init(struct ath9k_htc_priv *priv); void ath9k_tx_tasklet(unsigned long data); -int ath9k_htc_tx_start(struct ath9k_htc_priv *priv, struct sk_buff *skb); +int ath9k_htc_tx_start(struct ath9k_htc_priv *priv, + struct sk_buff *skb, bool is_cab); void ath9k_tx_cleanup(struct ath9k_htc_priv *priv); bool ath9k_htc_txq_setup(struct ath9k_htc_priv *priv, int subtype); int ath9k_htc_cabq_setup(struct ath9k_htc_priv *priv); diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c b/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c index 7aafd21..c96779c 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c @@ -272,6 +272,48 @@ void ath9k_htc_beaconep(void *drv_priv, struct sk_buff *skb, dev_kfree_skb_any(skb); } +static void ath9k_htc_send_buffered(struct ath9k_htc_priv *priv, + int slot) +{ + struct ath_common *common = ath9k_hw_common(priv->ah); + struct ieee80211_vif *vif; + struct sk_buff *skb; + struct ieee80211_hdr *hdr; + int padpos, padsize, ret; + + spin_lock_bh(&priv->beacon_lock); + + vif = priv->cur_beacon_conf.bslot[slot]; + + skb = ieee80211_get_buffered_bc(priv->hw, vif); + + while(skb) { + hdr = (struct ieee80211_hdr *) skb->data; + + padpos = ath9k_cmn_padpos(hdr->frame_control); + padsize = padpos & 3; + if (padsize && skb->len > padpos) { + if (skb_headroom(skb) < padsize) { + dev_kfree_skb_any(skb); + goto next; + } + skb_push(skb, padsize); + memmove(skb->data, skb->data + padsize, padpos); + } + + ret = ath9k_htc_tx_start(priv, skb, true); + if (ret != 0) { + ath_dbg(common, ATH_DBG_FATAL, + "Failed to send CAB frame\n"); + dev_kfree_skb_any(skb); + } + next: + skb = ieee80211_get_buffered_bc(priv->hw, vif); + } + + spin_unlock_bh(&priv->beacon_lock); +} + static void ath9k_htc_send_beacon(struct ath9k_htc_priv *priv, int slot) { @@ -390,6 +432,7 @@ void ath9k_htc_swba(struct ath9k_htc_priv *priv) } spin_unlock_bh(&priv->beacon_lock); + ath9k_htc_send_buffered(priv, slot); ath9k_htc_send_beacon(priv, slot); } diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_init.c b/drivers/net/wireless/ath/ath9k/htc_drv_init.c index 9405e0a..b1c68bf 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_init.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_init.c @@ -748,7 +748,8 @@ static void ath9k_set_hw_capab(struct ath9k_htc_priv *priv, IEEE80211_HW_HAS_RATE_CONTROL | IEEE80211_HW_RX_INCLUDES_FCS | IEEE80211_HW_SUPPORTS_PS | - IEEE80211_HW_PS_NULLFUNC_STACK; + IEEE80211_HW_PS_NULLFUNC_STACK | + IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING; hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) | diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_main.c b/drivers/net/wireless/ath/ath9k/htc_drv_main.c index 6926ac0..8f38075 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_main.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_main.c @@ -797,6 +797,9 @@ static ssize_t read_file_xmit(struct file *file, char __user *user_buf, len += snprintf(buf + len, sizeof(buf) - len, "%20s : %10u\n", "SKBs dropped", priv->debug.tx_stats.skb_dropped); + len += snprintf(buf + len, sizeof(buf) - len, + "%20s : %10u\n", "CAB queued", + priv->debug.tx_stats.cab_queued); len += snprintf(buf + len, sizeof(buf) - len, "%20s : %10u\n", "BE queued", @@ -1054,7 +1057,7 @@ static void ath9k_htc_tx(struct ieee80211_hw *hw, struct sk_buff *skb) memmove(skb->data, skb->data + padsize, padpos); } - ret = ath9k_htc_tx_start(priv, skb); + ret = ath9k_htc_tx_start(priv, skb, false); if (ret != 0) { if (ret == -ENOMEM) { ath_dbg(ath9k_hw_common(priv->ah), ATH_DBG_XMIT, diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c b/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c index b3f9485..0e28558 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c @@ -79,7 +79,8 @@ int ath_htc_txq_update(struct ath9k_htc_priv *priv, int qnum, return error; } -int ath9k_htc_tx_start(struct ath9k_htc_priv *priv, struct sk_buff *skb) +int ath9k_htc_tx_start(struct ath9k_htc_priv *priv, + struct sk_buff *skb, bool is_cab) { struct ieee80211_hdr *hdr; struct ieee80211_mgmt *mgmt; @@ -170,6 +171,12 @@ int ath9k_htc_tx_start(struct ath9k_htc_priv *priv, struct sk_buff *skb) tx_fhdr = skb_push(skb, sizeof(tx_hdr)); memcpy(tx_fhdr, (u8 *) &tx_hdr, sizeof(tx_hdr)); + if (is_cab) { + CAB_STAT_INC; + epid = priv->cab_ep; + goto send; + } + qnum = skb_get_queue_mapping(skb); switch (qnum) { @@ -222,7 +229,7 @@ int ath9k_htc_tx_start(struct ath9k_htc_priv *priv, struct sk_buff *skb) memcpy(tx_fhdr, (u8 *) &mgmt_hdr, sizeof(mgmt_hdr)); epid = priv->mgmt_ep; } - +send: return htc_send(priv->htc, skb, epid, &tx_ctl); } @@ -326,7 +333,8 @@ void ath9k_htc_txep(void *drv_priv, struct sk_buff *skb, } else if ((ep_id == priv->data_bk_ep) || (ep_id == priv->data_be_ep) || (ep_id == priv->data_vi_ep) || - (ep_id == priv->data_vo_ep)) { + (ep_id == priv->data_vo_ep) || + (ep_id == priv->cab_ep)) { skb_pull(skb, sizeof(struct tx_frame_hdr)); } else { ath_err(common, "Unsupported TX EPID: %d\n", ep_id); -- cgit v0.10.2 From b0a6ba983e3663bf256ca2e79d17bb846878cd9e Mon Sep 17 00:00:00 2001 From: Sujith Manoharan Date: Wed, 13 Apr 2011 11:23:44 +0530 Subject: ath9k_htc: Fix beacon miss under heavy load Transmission of beacons becomes erratic when TX load is high, since the latency involved in the generation of a SWBA interrupt on the target to the actual sending of a beacon is quite high for USB devices. Fix this by adjusting the beacon response time. Signed-off-by: Sujith Manoharan Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/htc.h b/drivers/net/wireless/ath/ath9k/htc.h index a072a9e..133fc6d 100644 --- a/drivers/net/wireless/ath/ath9k/htc.h +++ b/drivers/net/wireless/ath/ath9k/htc.h @@ -358,6 +358,13 @@ struct ath_led { #define BSTUCK_THRESHOLD 10 +/* + * Adjust these when the max. no of beaconing interfaces is + * increased. + */ +#define DEFAULT_SWBA_RESPONSE 40 /* in TUs */ +#define MIN_SWBA_RESPONSE 10 /* in TUs */ + struct htc_beacon_config { struct ieee80211_vif *bslot[ATH9K_HTC_MAX_BCN_VIF]; u16 beacon_interval; diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c b/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c index c96779c..48bc288 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c @@ -198,6 +198,15 @@ static void ath9k_htc_beacon_config_ap(struct ath9k_htc_priv *priv, intval /= ATH9K_HTC_MAX_BCN_VIF; nexttbtt = intval; + /* + * To reduce beacon misses under heavy TX load, + * set the beacon response time to a larger value. + */ + if (intval > DEFAULT_SWBA_RESPONSE) + priv->ah->config.sw_beacon_response_time = DEFAULT_SWBA_RESPONSE; + else + priv->ah->config.sw_beacon_response_time = MIN_SWBA_RESPONSE; + if (priv->op_flags & OP_TSF_RESET) { ath9k_hw_reset_tsf(priv->ah); priv->op_flags &= ~OP_TSF_RESET; @@ -216,9 +225,10 @@ static void ath9k_htc_beacon_config_ap(struct ath9k_htc_priv *priv, imask |= ATH9K_INT_SWBA; ath_dbg(common, ATH_DBG_CONFIG, - "AP Beacon config, intval: %d, nexttbtt: %u " + "AP Beacon config, intval: %d, nexttbtt: %u, resp_time: %d " "imask: 0x%x\n", - bss_conf->beacon_interval, nexttbtt, imask); + bss_conf->beacon_interval, nexttbtt, + priv->ah->config.sw_beacon_response_time, imask); ath9k_htc_beaconq_config(priv); @@ -252,12 +262,22 @@ static void ath9k_htc_beacon_config_adhoc(struct ath9k_htc_priv *priv, nexttbtt += intval; } while (nexttbtt < tsftu); + /* + * Only one IBSS interfce is allowed. + */ + if (intval > DEFAULT_SWBA_RESPONSE) + priv->ah->config.sw_beacon_response_time = DEFAULT_SWBA_RESPONSE; + else + priv->ah->config.sw_beacon_response_time = MIN_SWBA_RESPONSE; + if (priv->op_flags & OP_ENABLE_BEACON) imask |= ATH9K_INT_SWBA; ath_dbg(common, ATH_DBG_CONFIG, - "IBSS Beacon config, intval: %d, nexttbtt: %u, imask: 0x%x\n", - bss_conf->beacon_interval, nexttbtt, imask); + "IBSS Beacon config, intval: %d, nexttbtt: %u, " + "resp_time: %d, imask: 0x%x\n", + bss_conf->beacon_interval, nexttbtt, + priv->ah->config.sw_beacon_response_time, imask); WMI_CMD(WMI_DISABLE_INTR_CMDID); ath9k_hw_beaconinit(priv->ah, TU_TO_USEC(nexttbtt), TU_TO_USEC(intval)); @@ -317,6 +337,7 @@ static void ath9k_htc_send_buffered(struct ath9k_htc_priv *priv, static void ath9k_htc_send_beacon(struct ath9k_htc_priv *priv, int slot) { + struct ath_common *common = ath9k_hw_common(priv->ah); struct ieee80211_vif *vif; struct ath9k_htc_vif *avp; struct tx_beacon_header beacon_hdr; @@ -325,6 +346,7 @@ static void ath9k_htc_send_beacon(struct ath9k_htc_priv *priv, struct ieee80211_mgmt *mgmt; struct sk_buff *beacon; u8 *tx_fhdr; + int ret; memset(&beacon_hdr, 0, sizeof(struct tx_beacon_header)); memset(&tx_ctl, 0, sizeof(struct ath9k_htc_tx_ctl)); @@ -367,7 +389,14 @@ static void ath9k_htc_send_beacon(struct ath9k_htc_priv *priv, tx_fhdr = skb_push(beacon, sizeof(beacon_hdr)); memcpy(tx_fhdr, (u8 *) &beacon_hdr, sizeof(beacon_hdr)); - htc_send(priv->htc, beacon, priv->beacon_ep, &tx_ctl); + ret = htc_send(priv->htc, beacon, priv->beacon_ep, &tx_ctl); + if (ret != 0) { + if (ret == -ENOMEM) { + ath_dbg(common, ATH_DBG_BSTUCK, + "Failed to send beacon, no free TX buffer\n"); + } + dev_kfree_skb_any(beacon); + } spin_unlock_bh(&priv->beacon_lock); } -- cgit v0.10.2 From f4c88991f51e097b6541f998fd23d477999e5886 Mon Sep 17 00:00:00 2001 From: Sujith Manoharan Date: Wed, 13 Apr 2011 11:23:52 +0530 Subject: ath9k_htc: Queue WMI events Use a queue to handle WMI events and schedule a tasklet to process the events. This fixes the race between the WMI event ISR and the SWBA tasklet when the arrival of WMI events in quick succession could overwrite the SWBA data before the tasklet from a previous iteration could have been scheduled. Also, drain the WMI queue properly. Signed-off-by: Sujith Manoharan Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/htc.h b/drivers/net/wireless/ath/ath9k/htc.h index 133fc6d..20511af 100644 --- a/drivers/net/wireless/ath/ath9k/htc.h +++ b/drivers/net/wireless/ath/ath9k/htc.h @@ -497,7 +497,8 @@ void ath9k_htc_beaconq_config(struct ath9k_htc_priv *priv); void ath9k_htc_beacon_config(struct ath9k_htc_priv *priv, struct ieee80211_vif *vif); void ath9k_htc_beacon_reconfig(struct ath9k_htc_priv *priv); -void ath9k_htc_swba(struct ath9k_htc_priv *priv); +void ath9k_htc_swba(struct ath9k_htc_priv *priv, + struct wmi_event_swba *swba); void ath9k_htc_rxep(void *priv, struct sk_buff *skb, enum htc_endpoint_id ep_id); diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c b/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c index 48bc288..2180a9d 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c @@ -401,10 +401,10 @@ static void ath9k_htc_send_beacon(struct ath9k_htc_priv *priv, spin_unlock_bh(&priv->beacon_lock); } -static int ath9k_htc_choose_bslot(struct ath9k_htc_priv *priv) +static int ath9k_htc_choose_bslot(struct ath9k_htc_priv *priv, + struct wmi_event_swba *swba) { struct ath_common *common = ath9k_hw_common(priv->ah); - unsigned long flags; u64 tsf; u32 tsftu; u16 intval; @@ -412,10 +412,7 @@ static int ath9k_htc_choose_bslot(struct ath9k_htc_priv *priv) intval = priv->cur_beacon_conf.beacon_interval & ATH9K_BEACON_PERIOD; - spin_lock_irqsave(&priv->wmi->wmi_lock, flags); - tsf = priv->wmi->tsf; - spin_unlock_irqrestore(&priv->wmi->wmi_lock, flags); - + tsf = be64_to_cpu(swba->tsf); tsftu = TSF_TO_TU(tsf >> 32, tsf); slot = ((tsftu % intval) * ATH9K_HTC_MAX_BCN_VIF) / intval; slot = ATH9K_HTC_MAX_BCN_VIF - slot - 1; @@ -427,33 +424,31 @@ static int ath9k_htc_choose_bslot(struct ath9k_htc_priv *priv) return slot; } -void ath9k_htc_swba(struct ath9k_htc_priv *priv) +void ath9k_htc_swba(struct ath9k_htc_priv *priv, + struct wmi_event_swba *swba) { struct ath_common *common = ath9k_hw_common(priv->ah); - unsigned long flags; int slot; - spin_lock_irqsave(&priv->wmi->wmi_lock, flags); - if (priv->wmi->beacon_pending != 0) { - spin_unlock_irqrestore(&priv->wmi->wmi_lock, flags); + if (swba->beacon_pending != 0) { priv->cur_beacon_conf.bmiss_cnt++; if (priv->cur_beacon_conf.bmiss_cnt > BSTUCK_THRESHOLD) { - ath_dbg(common, ATH_DBG_BEACON, + ath_dbg(common, ATH_DBG_BSTUCK, "Beacon stuck, HW reset\n"); - ath9k_htc_reset(priv); + ieee80211_queue_work(priv->hw, + &priv->fatal_work); } return; } - spin_unlock_irqrestore(&priv->wmi->wmi_lock, flags); if (priv->cur_beacon_conf.bmiss_cnt) { - ath_dbg(common, ATH_DBG_BEACON, + ath_dbg(common, ATH_DBG_BSTUCK, "Resuming beacon xmit after %u misses\n", priv->cur_beacon_conf.bmiss_cnt); priv->cur_beacon_conf.bmiss_cnt = 0; } - slot = ath9k_htc_choose_bslot(priv); + slot = ath9k_htc_choose_bslot(priv, swba); spin_lock_bh(&priv->beacon_lock); if (priv->cur_beacon_conf.bslot[slot] == NULL) { spin_unlock_bh(&priv->beacon_lock); diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_gpio.c b/drivers/net/wireless/ath/ath9k/htc_drv_gpio.c index 7e630a8..459ba0d 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_gpio.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_gpio.c @@ -436,6 +436,9 @@ void ath9k_htc_radio_disable(struct ieee80211_hw *hw) /* Stop RX */ WMI_CMD(WMI_STOP_RECV_CMDID); + /* Clear the WMI event queue */ + ath9k_wmi_event_drain(priv); + /* * The MIB counters have to be disabled here, * since the target doesn't do it. diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_init.c b/drivers/net/wireless/ath/ath9k/htc_drv_init.c index b1c68bf..921d76f 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_init.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_init.c @@ -676,8 +676,6 @@ static int ath9k_init_priv(struct ath9k_htc_priv *priv, spin_lock_init(&priv->tx_lock); mutex_init(&priv->mutex); mutex_init(&priv->htc_pm_lock); - tasklet_init(&priv->swba_tasklet, ath9k_swba_tasklet, - (unsigned long)priv); tasklet_init(&priv->rx_tasklet, ath9k_rx_tasklet, (unsigned long)priv); tasklet_init(&priv->tx_tasklet, ath9k_tx_tasklet, diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_main.c b/drivers/net/wireless/ath/ath9k/htc_drv_main.c index 8f38075..81dfe07 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_main.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_main.c @@ -202,6 +202,8 @@ void ath9k_htc_reset(struct ath9k_htc_priv *priv) WMI_CMD(WMI_DRAIN_TXQ_ALL_CMDID); WMI_CMD(WMI_STOP_RECV_CMDID); + ath9k_wmi_event_drain(priv); + caldata = &priv->caldata; ret = ath9k_hw_reset(ah, ah->curchan, caldata, false); if (ret) { @@ -255,6 +257,8 @@ static int ath9k_htc_set_channel(struct ath9k_htc_priv *priv, WMI_CMD(WMI_DRAIN_TXQ_ALL_CMDID); WMI_CMD(WMI_STOP_RECV_CMDID); + ath9k_wmi_event_drain(priv); + ath_dbg(common, ATH_DBG_CONFIG, "(%u MHz) -> (%u MHz), HT: %d, HT40: %d fastcc: %d\n", priv->ah->curchan->channel, @@ -1172,12 +1176,13 @@ static void ath9k_htc_stop(struct ieee80211_hw *hw) WMI_CMD(WMI_DRAIN_TXQ_ALL_CMDID); WMI_CMD(WMI_STOP_RECV_CMDID); - tasklet_kill(&priv->swba_tasklet); tasklet_kill(&priv->rx_tasklet); tasklet_kill(&priv->tx_tasklet); skb_queue_purge(&priv->tx_queue); + ath9k_wmi_event_drain(priv); + mutex_unlock(&priv->mutex); /* Cancel all the running timers/work .. */ diff --git a/drivers/net/wireless/ath/ath9k/wmi.c b/drivers/net/wireless/ath/ath9k/wmi.c index a39552b..4578475 100644 --- a/drivers/net/wireless/ath/ath9k/wmi.c +++ b/drivers/net/wireless/ath/ath9k/wmi.c @@ -104,9 +104,12 @@ struct wmi *ath9k_init_wmi(struct ath9k_htc_priv *priv) wmi->drv_priv = priv; wmi->stopped = false; + skb_queue_head_init(&wmi->wmi_event_queue); mutex_init(&wmi->op_mutex); mutex_init(&wmi->multi_write_mutex); init_completion(&wmi->cmd_wait); + tasklet_init(&wmi->wmi_event_tasklet, ath9k_wmi_event_tasklet, + (unsigned long)wmi); return wmi; } @@ -122,11 +125,64 @@ void ath9k_deinit_wmi(struct ath9k_htc_priv *priv) kfree(priv->wmi); } -void ath9k_swba_tasklet(unsigned long data) +void ath9k_wmi_event_drain(struct ath9k_htc_priv *priv) { - struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *)data; + unsigned long flags; - ath9k_htc_swba(priv); + tasklet_kill(&priv->wmi->wmi_event_tasklet); + spin_lock_irqsave(&priv->wmi->wmi_lock, flags); + __skb_queue_purge(&priv->wmi->wmi_event_queue); + spin_unlock_irqrestore(&priv->wmi->wmi_lock, flags); +} + +void ath9k_wmi_event_tasklet(unsigned long data) +{ + struct wmi *wmi = (struct wmi *)data; + struct ath9k_htc_priv *priv = wmi->drv_priv; + struct wmi_cmd_hdr *hdr; + void *wmi_event; + struct wmi_event_swba *swba; + struct sk_buff *skb = NULL; + unsigned long flags; + u16 cmd_id; +#ifdef CONFIG_ATH9K_HTC_DEBUGFS + __be32 txrate; +#endif + + do { + spin_lock_irqsave(&wmi->wmi_lock, flags); + skb = __skb_dequeue(&wmi->wmi_event_queue); + if (!skb) { + spin_unlock_irqrestore(&wmi->wmi_lock, flags); + return; + } + spin_unlock_irqrestore(&wmi->wmi_lock, flags); + + hdr = (struct wmi_cmd_hdr *) skb->data; + cmd_id = be16_to_cpu(hdr->command_id); + wmi_event = skb_pull(skb, sizeof(struct wmi_cmd_hdr)); + + switch (cmd_id) { + case WMI_SWBA_EVENTID: + swba = (struct wmi_event_swba *) wmi_event; + ath9k_htc_swba(priv, swba); + break; + case WMI_FATAL_EVENTID: + ieee80211_queue_work(wmi->drv_priv->hw, + &wmi->drv_priv->fatal_work); + break; + case WMI_TXRATE_EVENTID: +#ifdef CONFIG_ATH9K_HTC_DEBUGFS + txrate = ((struct wmi_event_txrate *)wmi_event)->txrate; + wmi->drv_priv->debug.txrate = be32_to_cpu(txrate); +#endif + break; + default: + break; + } + + kfree_skb(skb); + } while (1); } void ath9k_fatal_work(struct work_struct *work) @@ -155,11 +211,6 @@ static void ath9k_wmi_ctrl_rx(void *priv, struct sk_buff *skb, struct wmi *wmi = (struct wmi *) priv; struct wmi_cmd_hdr *hdr; u16 cmd_id; - void *wmi_event; - struct wmi_event_swba *swba; -#ifdef CONFIG_ATH9K_HTC_DEBUGFS - __be32 txrate; -#endif if (unlikely(wmi->stopped)) goto free_skb; @@ -168,32 +219,10 @@ static void ath9k_wmi_ctrl_rx(void *priv, struct sk_buff *skb, cmd_id = be16_to_cpu(hdr->command_id); if (cmd_id & 0x1000) { - wmi_event = skb_pull(skb, sizeof(struct wmi_cmd_hdr)); - switch (cmd_id) { - case WMI_SWBA_EVENTID: - swba = (struct wmi_event_swba *) wmi_event; - - spin_lock(&wmi->wmi_lock); - wmi->tsf = be64_to_cpu(swba->tsf); - wmi->beacon_pending = swba->beacon_pending; - spin_unlock(&wmi->wmi_lock); - - tasklet_schedule(&wmi->drv_priv->swba_tasklet); - break; - case WMI_FATAL_EVENTID: - ieee80211_queue_work(wmi->drv_priv->hw, - &wmi->drv_priv->fatal_work); - break; - case WMI_TXRATE_EVENTID: -#ifdef CONFIG_ATH9K_HTC_DEBUGFS - txrate = ((struct wmi_event_txrate *)wmi_event)->txrate; - wmi->drv_priv->debug.txrate = be32_to_cpu(txrate); -#endif - break; - default: - break; - } - kfree_skb(skb); + spin_lock(&wmi->wmi_lock); + __skb_queue_tail(&wmi->wmi_event_queue, skb); + spin_unlock(&wmi->wmi_lock); + tasklet_schedule(&wmi->wmi_event_tasklet); return; } diff --git a/drivers/net/wireless/ath/ath9k/wmi.h b/drivers/net/wireless/ath/ath9k/wmi.h index 2fa91a9..ff5ba2b 100644 --- a/drivers/net/wireless/ath/ath9k/wmi.h +++ b/drivers/net/wireless/ath/ath9k/wmi.h @@ -106,13 +106,13 @@ struct wmi { struct mutex op_mutex; struct completion cmd_wait; enum wmi_cmd_id last_cmd_id; + struct sk_buff_head wmi_event_queue; + struct tasklet_struct wmi_event_tasklet; u16 tx_seq_id; u8 *cmd_rsp_buf; u32 cmd_rsp_len; bool stopped; - u64 tsf; - u8 beacon_pending; spinlock_t wmi_lock; atomic_t mwrite_cnt; @@ -129,8 +129,9 @@ int ath9k_wmi_cmd(struct wmi *wmi, enum wmi_cmd_id cmd_id, u8 *cmd_buf, u32 cmd_len, u8 *rsp_buf, u32 rsp_len, u32 timeout); -void ath9k_swba_tasklet(unsigned long data); +void ath9k_wmi_event_tasklet(unsigned long data); void ath9k_fatal_work(struct work_struct *work); +void ath9k_wmi_event_drain(struct ath9k_htc_priv *priv); #define WMI_CMD(_wmi_cmd) \ do { \ -- cgit v0.10.2 From 8e42e4ba98f986be64016df79eacbb671dbd3d18 Mon Sep 17 00:00:00 2001 From: Sujith Manoharan Date: Wed, 13 Apr 2011 11:24:00 +0530 Subject: ath9k_htc: Move debug code to a separate file Signed-off-by: Sujith Manoharan Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/Makefile b/drivers/net/wireless/ath/ath9k/Makefile index ca4c436..05a6fad 100644 --- a/drivers/net/wireless/ath/ath9k/Makefile +++ b/drivers/net/wireless/ath/ath9k/Makefile @@ -48,4 +48,6 @@ ath9k_htc-y += htc_hst.o \ htc_drv_init.o \ htc_drv_gpio.o +ath9k_htc-$(CONFIG_ATH9K_HTC_DEBUGFS) += htc_drv_debug.o + obj-$(CONFIG_ATH9K_HTC) += ath9k_htc.o diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_debug.c b/drivers/net/wireless/ath/ath9k/htc_drv_debug.c new file mode 100644 index 0000000..8b679aa --- /dev/null +++ b/drivers/net/wireless/ath/ath9k/htc_drv_debug.c @@ -0,0 +1,219 @@ +/* + * Copyright (c) 2010-2011 Atheros Communications Inc. + * + * 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 "htc.h" + +static struct dentry *ath9k_debugfs_root; + +static int ath9k_debugfs_open(struct inode *inode, struct file *file) +{ + file->private_data = inode->i_private; + return 0; +} + +static ssize_t read_file_tgt_stats(struct file *file, char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct ath9k_htc_priv *priv = file->private_data; + struct ath9k_htc_target_stats cmd_rsp; + char buf[512]; + unsigned int len = 0; + int ret = 0; + + memset(&cmd_rsp, 0, sizeof(cmd_rsp)); + + WMI_CMD(WMI_TGT_STATS_CMDID); + if (ret) + return -EINVAL; + + + len += snprintf(buf + len, sizeof(buf) - len, + "%19s : %10u\n", "TX Short Retries", + be32_to_cpu(cmd_rsp.tx_shortretry)); + len += snprintf(buf + len, sizeof(buf) - len, + "%19s : %10u\n", "TX Long Retries", + be32_to_cpu(cmd_rsp.tx_longretry)); + len += snprintf(buf + len, sizeof(buf) - len, + "%19s : %10u\n", "TX Xretries", + be32_to_cpu(cmd_rsp.tx_xretries)); + len += snprintf(buf + len, sizeof(buf) - len, + "%19s : %10u\n", "TX Unaggr. Xretries", + be32_to_cpu(cmd_rsp.ht_txunaggr_xretry)); + len += snprintf(buf + len, sizeof(buf) - len, + "%19s : %10u\n", "TX Xretries (HT)", + be32_to_cpu(cmd_rsp.ht_tx_xretries)); + len += snprintf(buf + len, sizeof(buf) - len, + "%19s : %10u\n", "TX Rate", priv->debug.txrate); + + if (len > sizeof(buf)) + len = sizeof(buf); + + return simple_read_from_buffer(user_buf, count, ppos, buf, len); +} + +static const struct file_operations fops_tgt_stats = { + .read = read_file_tgt_stats, + .open = ath9k_debugfs_open, + .owner = THIS_MODULE, + .llseek = default_llseek, +}; + +static ssize_t read_file_xmit(struct file *file, char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct ath9k_htc_priv *priv = file->private_data; + char buf[512]; + unsigned int len = 0; + + len += snprintf(buf + len, sizeof(buf) - len, + "%20s : %10u\n", "Buffers queued", + priv->debug.tx_stats.buf_queued); + len += snprintf(buf + len, sizeof(buf) - len, + "%20s : %10u\n", "Buffers completed", + priv->debug.tx_stats.buf_completed); + len += snprintf(buf + len, sizeof(buf) - len, + "%20s : %10u\n", "SKBs queued", + priv->debug.tx_stats.skb_queued); + len += snprintf(buf + len, sizeof(buf) - len, + "%20s : %10u\n", "SKBs completed", + priv->debug.tx_stats.skb_completed); + len += snprintf(buf + len, sizeof(buf) - len, + "%20s : %10u\n", "SKBs dropped", + priv->debug.tx_stats.skb_dropped); + len += snprintf(buf + len, sizeof(buf) - len, + "%20s : %10u\n", "CAB queued", + priv->debug.tx_stats.cab_queued); + + len += snprintf(buf + len, sizeof(buf) - len, + "%20s : %10u\n", "BE queued", + priv->debug.tx_stats.queue_stats[WME_AC_BE]); + len += snprintf(buf + len, sizeof(buf) - len, + "%20s : %10u\n", "BK queued", + priv->debug.tx_stats.queue_stats[WME_AC_BK]); + len += snprintf(buf + len, sizeof(buf) - len, + "%20s : %10u\n", "VI queued", + priv->debug.tx_stats.queue_stats[WME_AC_VI]); + len += snprintf(buf + len, sizeof(buf) - len, + "%20s : %10u\n", "VO queued", + priv->debug.tx_stats.queue_stats[WME_AC_VO]); + + if (len > sizeof(buf)) + len = sizeof(buf); + + return simple_read_from_buffer(user_buf, count, ppos, buf, len); +} + +static const struct file_operations fops_xmit = { + .read = read_file_xmit, + .open = ath9k_debugfs_open, + .owner = THIS_MODULE, + .llseek = default_llseek, +}; + +static ssize_t read_file_recv(struct file *file, char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct ath9k_htc_priv *priv = file->private_data; + char buf[512]; + unsigned int len = 0; + + len += snprintf(buf + len, sizeof(buf) - len, + "%20s : %10u\n", "SKBs allocated", + priv->debug.rx_stats.skb_allocated); + len += snprintf(buf + len, sizeof(buf) - len, + "%20s : %10u\n", "SKBs completed", + priv->debug.rx_stats.skb_completed); + len += snprintf(buf + len, sizeof(buf) - len, + "%20s : %10u\n", "SKBs Dropped", + priv->debug.rx_stats.skb_dropped); + + if (len > sizeof(buf)) + len = sizeof(buf); + + return simple_read_from_buffer(user_buf, count, ppos, buf, len); +} + +static const struct file_operations fops_recv = { + .read = read_file_recv, + .open = ath9k_debugfs_open, + .owner = THIS_MODULE, + .llseek = default_llseek, +}; + +int ath9k_htc_init_debug(struct ath_hw *ah) +{ + struct ath_common *common = ath9k_hw_common(ah); + struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *) common->priv; + + if (!ath9k_debugfs_root) + return -ENOENT; + + priv->debug.debugfs_phy = debugfs_create_dir(wiphy_name(priv->hw->wiphy), + ath9k_debugfs_root); + if (!priv->debug.debugfs_phy) + goto err; + + priv->debug.debugfs_tgt_stats = debugfs_create_file("tgt_stats", S_IRUSR, + priv->debug.debugfs_phy, + priv, &fops_tgt_stats); + if (!priv->debug.debugfs_tgt_stats) + goto err; + + + priv->debug.debugfs_xmit = debugfs_create_file("xmit", S_IRUSR, + priv->debug.debugfs_phy, + priv, &fops_xmit); + if (!priv->debug.debugfs_xmit) + goto err; + + priv->debug.debugfs_recv = debugfs_create_file("recv", S_IRUSR, + priv->debug.debugfs_phy, + priv, &fops_recv); + if (!priv->debug.debugfs_recv) + goto err; + + return 0; + +err: + ath9k_htc_exit_debug(ah); + return -ENOMEM; +} + +void ath9k_htc_exit_debug(struct ath_hw *ah) +{ + struct ath_common *common = ath9k_hw_common(ah); + struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *) common->priv; + + debugfs_remove(priv->debug.debugfs_recv); + debugfs_remove(priv->debug.debugfs_xmit); + debugfs_remove(priv->debug.debugfs_tgt_stats); + debugfs_remove(priv->debug.debugfs_phy); +} + +int ath9k_htc_debug_create_root(void) +{ + ath9k_debugfs_root = debugfs_create_dir(KBUILD_MODNAME, NULL); + if (!ath9k_debugfs_root) + return -ENOENT; + + return 0; +} + +void ath9k_htc_debug_remove_root(void) +{ + debugfs_remove(ath9k_debugfs_root); + ath9k_debugfs_root = NULL; +} diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_main.c b/drivers/net/wireless/ath/ath9k/htc_drv_main.c index 81dfe07..59710e7 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_main.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_main.c @@ -16,10 +16,6 @@ #include "htc.h" -#ifdef CONFIG_ATH9K_HTC_DEBUGFS -static struct dentry *ath9k_debugfs_root; -#endif - /*************/ /* Utilities */ /*************/ @@ -720,214 +716,6 @@ static int ath9k_htc_tx_aggr_oper(struct ath9k_htc_priv *priv, return ret; } -/*********/ -/* DEBUG */ -/*********/ - -#ifdef CONFIG_ATH9K_HTC_DEBUGFS - -static int ath9k_debugfs_open(struct inode *inode, struct file *file) -{ - file->private_data = inode->i_private; - return 0; -} - -static ssize_t read_file_tgt_stats(struct file *file, char __user *user_buf, - size_t count, loff_t *ppos) -{ - struct ath9k_htc_priv *priv = file->private_data; - struct ath9k_htc_target_stats cmd_rsp; - char buf[512]; - unsigned int len = 0; - int ret = 0; - - memset(&cmd_rsp, 0, sizeof(cmd_rsp)); - - WMI_CMD(WMI_TGT_STATS_CMDID); - if (ret) - return -EINVAL; - - - len += snprintf(buf + len, sizeof(buf) - len, - "%19s : %10u\n", "TX Short Retries", - be32_to_cpu(cmd_rsp.tx_shortretry)); - len += snprintf(buf + len, sizeof(buf) - len, - "%19s : %10u\n", "TX Long Retries", - be32_to_cpu(cmd_rsp.tx_longretry)); - len += snprintf(buf + len, sizeof(buf) - len, - "%19s : %10u\n", "TX Xretries", - be32_to_cpu(cmd_rsp.tx_xretries)); - len += snprintf(buf + len, sizeof(buf) - len, - "%19s : %10u\n", "TX Unaggr. Xretries", - be32_to_cpu(cmd_rsp.ht_txunaggr_xretry)); - len += snprintf(buf + len, sizeof(buf) - len, - "%19s : %10u\n", "TX Xretries (HT)", - be32_to_cpu(cmd_rsp.ht_tx_xretries)); - len += snprintf(buf + len, sizeof(buf) - len, - "%19s : %10u\n", "TX Rate", priv->debug.txrate); - - if (len > sizeof(buf)) - len = sizeof(buf); - - return simple_read_from_buffer(user_buf, count, ppos, buf, len); -} - -static const struct file_operations fops_tgt_stats = { - .read = read_file_tgt_stats, - .open = ath9k_debugfs_open, - .owner = THIS_MODULE, - .llseek = default_llseek, -}; - -static ssize_t read_file_xmit(struct file *file, char __user *user_buf, - size_t count, loff_t *ppos) -{ - struct ath9k_htc_priv *priv = file->private_data; - char buf[512]; - unsigned int len = 0; - - len += snprintf(buf + len, sizeof(buf) - len, - "%20s : %10u\n", "Buffers queued", - priv->debug.tx_stats.buf_queued); - len += snprintf(buf + len, sizeof(buf) - len, - "%20s : %10u\n", "Buffers completed", - priv->debug.tx_stats.buf_completed); - len += snprintf(buf + len, sizeof(buf) - len, - "%20s : %10u\n", "SKBs queued", - priv->debug.tx_stats.skb_queued); - len += snprintf(buf + len, sizeof(buf) - len, - "%20s : %10u\n", "SKBs completed", - priv->debug.tx_stats.skb_completed); - len += snprintf(buf + len, sizeof(buf) - len, - "%20s : %10u\n", "SKBs dropped", - priv->debug.tx_stats.skb_dropped); - len += snprintf(buf + len, sizeof(buf) - len, - "%20s : %10u\n", "CAB queued", - priv->debug.tx_stats.cab_queued); - - len += snprintf(buf + len, sizeof(buf) - len, - "%20s : %10u\n", "BE queued", - priv->debug.tx_stats.queue_stats[WME_AC_BE]); - len += snprintf(buf + len, sizeof(buf) - len, - "%20s : %10u\n", "BK queued", - priv->debug.tx_stats.queue_stats[WME_AC_BK]); - len += snprintf(buf + len, sizeof(buf) - len, - "%20s : %10u\n", "VI queued", - priv->debug.tx_stats.queue_stats[WME_AC_VI]); - len += snprintf(buf + len, sizeof(buf) - len, - "%20s : %10u\n", "VO queued", - priv->debug.tx_stats.queue_stats[WME_AC_VO]); - - if (len > sizeof(buf)) - len = sizeof(buf); - - return simple_read_from_buffer(user_buf, count, ppos, buf, len); -} - -static const struct file_operations fops_xmit = { - .read = read_file_xmit, - .open = ath9k_debugfs_open, - .owner = THIS_MODULE, - .llseek = default_llseek, -}; - -static ssize_t read_file_recv(struct file *file, char __user *user_buf, - size_t count, loff_t *ppos) -{ - struct ath9k_htc_priv *priv = file->private_data; - char buf[512]; - unsigned int len = 0; - - len += snprintf(buf + len, sizeof(buf) - len, - "%20s : %10u\n", "SKBs allocated", - priv->debug.rx_stats.skb_allocated); - len += snprintf(buf + len, sizeof(buf) - len, - "%20s : %10u\n", "SKBs completed", - priv->debug.rx_stats.skb_completed); - len += snprintf(buf + len, sizeof(buf) - len, - "%20s : %10u\n", "SKBs Dropped", - priv->debug.rx_stats.skb_dropped); - - if (len > sizeof(buf)) - len = sizeof(buf); - - return simple_read_from_buffer(user_buf, count, ppos, buf, len); -} - -static const struct file_operations fops_recv = { - .read = read_file_recv, - .open = ath9k_debugfs_open, - .owner = THIS_MODULE, - .llseek = default_llseek, -}; - -int ath9k_htc_init_debug(struct ath_hw *ah) -{ - struct ath_common *common = ath9k_hw_common(ah); - struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *) common->priv; - - if (!ath9k_debugfs_root) - return -ENOENT; - - priv->debug.debugfs_phy = debugfs_create_dir(wiphy_name(priv->hw->wiphy), - ath9k_debugfs_root); - if (!priv->debug.debugfs_phy) - goto err; - - priv->debug.debugfs_tgt_stats = debugfs_create_file("tgt_stats", S_IRUSR, - priv->debug.debugfs_phy, - priv, &fops_tgt_stats); - if (!priv->debug.debugfs_tgt_stats) - goto err; - - - priv->debug.debugfs_xmit = debugfs_create_file("xmit", S_IRUSR, - priv->debug.debugfs_phy, - priv, &fops_xmit); - if (!priv->debug.debugfs_xmit) - goto err; - - priv->debug.debugfs_recv = debugfs_create_file("recv", S_IRUSR, - priv->debug.debugfs_phy, - priv, &fops_recv); - if (!priv->debug.debugfs_recv) - goto err; - - return 0; - -err: - ath9k_htc_exit_debug(ah); - return -ENOMEM; -} - -void ath9k_htc_exit_debug(struct ath_hw *ah) -{ - struct ath_common *common = ath9k_hw_common(ah); - struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *) common->priv; - - debugfs_remove(priv->debug.debugfs_recv); - debugfs_remove(priv->debug.debugfs_xmit); - debugfs_remove(priv->debug.debugfs_tgt_stats); - debugfs_remove(priv->debug.debugfs_phy); -} - -int ath9k_htc_debug_create_root(void) -{ - ath9k_debugfs_root = debugfs_create_dir(KBUILD_MODNAME, NULL); - if (!ath9k_debugfs_root) - return -ENOENT; - - return 0; -} - -void ath9k_htc_debug_remove_root(void) -{ - debugfs_remove(ath9k_debugfs_root); - ath9k_debugfs_root = NULL; -} - -#endif /* CONFIG_ATH9K_HTC_DEBUGFS */ - /*******/ /* ANI */ /*******/ -- cgit v0.10.2 From 719c4cf6b1b113e9caf377c6607ae45758a85871 Mon Sep 17 00:00:00 2001 From: Sujith Manoharan Date: Wed, 13 Apr 2011 11:24:10 +0530 Subject: ath9k_htc: Add RX error statistics Signed-off-by: Sujith Manoharan Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/htc.h b/drivers/net/wireless/ath/ath9k/htc.h index 20511af..0e48fa0 100644 --- a/drivers/net/wireless/ath/ath9k/htc.h +++ b/drivers/net/wireless/ath/ath9k/htc.h @@ -296,6 +296,9 @@ struct ath9k_htc_tx_ctl { #define TX_QSTAT_INC(q) (priv->debug.tx_stats.queue_stats[q]++) +void ath9k_htc_err_stat_rx(struct ath9k_htc_priv *priv, + struct ath_htc_rx_status *rxs); + struct ath_tx_stats { u32 buf_queued; u32 buf_completed; @@ -310,6 +313,14 @@ struct ath_rx_stats { u32 skb_allocated; u32 skb_completed; u32 skb_dropped; + u32 err_crc; + u32 err_decrypt_crc; + u32 err_mic; + u32 err_pre_delim; + u32 err_post_delim; + u32 err_decrypt_busy; + u32 err_phy; + u32 err_phy_stats[ATH9K_PHYERR_MAX]; }; struct ath9k_debug { @@ -330,6 +341,11 @@ struct ath9k_debug { #define TX_QSTAT_INC(c) do { } while (0) +static inline void ath9k_htc_err_stat_rx(struct ath9k_htc_priv *priv, + struct ath_htc_rx_status *rxs) +{ +} + #endif /* CONFIG_ATH9K_HTC_DEBUGFS */ #define ATH_LED_PIN_DEF 1 diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_debug.c b/drivers/net/wireless/ath/ath9k/htc_drv_debug.c index 8b679aa..6fc6cb7 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_debug.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_debug.c @@ -123,27 +123,118 @@ static const struct file_operations fops_xmit = { .llseek = default_llseek, }; +void ath9k_htc_err_stat_rx(struct ath9k_htc_priv *priv, + struct ath_htc_rx_status *rxs) +{ +#define RX_PHY_ERR_INC(c) priv->debug.rx_stats.err_phy_stats[c]++ + + if (rxs->rs_status & ATH9K_RXERR_CRC) + priv->debug.rx_stats.err_crc++; + if (rxs->rs_status & ATH9K_RXERR_DECRYPT) + priv->debug.rx_stats.err_decrypt_crc++; + if (rxs->rs_status & ATH9K_RXERR_MIC) + priv->debug.rx_stats.err_mic++; + if (rxs->rs_status & ATH9K_RX_DELIM_CRC_PRE) + priv->debug.rx_stats.err_pre_delim++; + if (rxs->rs_status & ATH9K_RX_DELIM_CRC_POST) + priv->debug.rx_stats.err_post_delim++; + if (rxs->rs_status & ATH9K_RX_DECRYPT_BUSY) + priv->debug.rx_stats.err_decrypt_busy++; + + if (rxs->rs_status & ATH9K_RXERR_PHY) { + priv->debug.rx_stats.err_phy++; + if (rxs->rs_phyerr < ATH9K_PHYERR_MAX) + RX_PHY_ERR_INC(rxs->rs_phyerr); + } + +#undef RX_PHY_ERR_INC +} + static ssize_t read_file_recv(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) { +#define PHY_ERR(s, p) \ + len += snprintf(buf + len, size - len, "%20s : %10u\n", s, \ + priv->debug.rx_stats.err_phy_stats[p]); + struct ath9k_htc_priv *priv = file->private_data; - char buf[512]; - unsigned int len = 0; + char *buf; + unsigned int len = 0, size = 1500; + ssize_t retval = 0; - len += snprintf(buf + len, sizeof(buf) - len, + buf = kzalloc(size, GFP_KERNEL); + if (buf == NULL) + return -ENOMEM; + + len += snprintf(buf + len, size - len, "%20s : %10u\n", "SKBs allocated", priv->debug.rx_stats.skb_allocated); - len += snprintf(buf + len, sizeof(buf) - len, + len += snprintf(buf + len, size - len, "%20s : %10u\n", "SKBs completed", priv->debug.rx_stats.skb_completed); - len += snprintf(buf + len, sizeof(buf) - len, + len += snprintf(buf + len, size - len, "%20s : %10u\n", "SKBs Dropped", priv->debug.rx_stats.skb_dropped); - if (len > sizeof(buf)) - len = sizeof(buf); - - return simple_read_from_buffer(user_buf, count, ppos, buf, len); + len += snprintf(buf + len, size - len, + "%20s : %10u\n", "CRC ERR", + priv->debug.rx_stats.err_crc); + len += snprintf(buf + len, size - len, + "%20s : %10u\n", "DECRYPT CRC ERR", + priv->debug.rx_stats.err_decrypt_crc); + len += snprintf(buf + len, size - len, + "%20s : %10u\n", "MIC ERR", + priv->debug.rx_stats.err_mic); + len += snprintf(buf + len, size - len, + "%20s : %10u\n", "PRE-DELIM CRC ERR", + priv->debug.rx_stats.err_pre_delim); + len += snprintf(buf + len, size - len, + "%20s : %10u\n", "POST-DELIM CRC ERR", + priv->debug.rx_stats.err_post_delim); + len += snprintf(buf + len, size - len, + "%20s : %10u\n", "DECRYPT BUSY ERR", + priv->debug.rx_stats.err_decrypt_busy); + len += snprintf(buf + len, size - len, + "%20s : %10u\n", "TOTAL PHY ERR", + priv->debug.rx_stats.err_phy); + + + PHY_ERR("UNDERRUN", ATH9K_PHYERR_UNDERRUN); + PHY_ERR("TIMING", ATH9K_PHYERR_TIMING); + PHY_ERR("PARITY", ATH9K_PHYERR_PARITY); + PHY_ERR("RATE", ATH9K_PHYERR_RATE); + PHY_ERR("LENGTH", ATH9K_PHYERR_LENGTH); + PHY_ERR("RADAR", ATH9K_PHYERR_RADAR); + PHY_ERR("SERVICE", ATH9K_PHYERR_SERVICE); + PHY_ERR("TOR", ATH9K_PHYERR_TOR); + PHY_ERR("OFDM-TIMING", ATH9K_PHYERR_OFDM_TIMING); + PHY_ERR("OFDM-SIGNAL-PARITY", ATH9K_PHYERR_OFDM_SIGNAL_PARITY); + PHY_ERR("OFDM-RATE", ATH9K_PHYERR_OFDM_RATE_ILLEGAL); + PHY_ERR("OFDM-LENGTH", ATH9K_PHYERR_OFDM_LENGTH_ILLEGAL); + PHY_ERR("OFDM-POWER-DROP", ATH9K_PHYERR_OFDM_POWER_DROP); + PHY_ERR("OFDM-SERVICE", ATH9K_PHYERR_OFDM_SERVICE); + PHY_ERR("OFDM-RESTART", ATH9K_PHYERR_OFDM_RESTART); + PHY_ERR("FALSE-RADAR-EXT", ATH9K_PHYERR_FALSE_RADAR_EXT); + PHY_ERR("CCK-TIMING", ATH9K_PHYERR_CCK_TIMING); + PHY_ERR("CCK-HEADER-CRC", ATH9K_PHYERR_CCK_HEADER_CRC); + PHY_ERR("CCK-RATE", ATH9K_PHYERR_CCK_RATE_ILLEGAL); + PHY_ERR("CCK-SERVICE", ATH9K_PHYERR_CCK_SERVICE); + PHY_ERR("CCK-RESTART", ATH9K_PHYERR_CCK_RESTART); + PHY_ERR("CCK-LENGTH", ATH9K_PHYERR_CCK_LENGTH_ILLEGAL); + PHY_ERR("CCK-POWER-DROP", ATH9K_PHYERR_CCK_POWER_DROP); + PHY_ERR("HT-CRC", ATH9K_PHYERR_HT_CRC_ERROR); + PHY_ERR("HT-LENGTH", ATH9K_PHYERR_HT_LENGTH_ILLEGAL); + PHY_ERR("HT-RATE", ATH9K_PHYERR_HT_RATE_ILLEGAL); + + if (len > size) + len = size; + + retval = simple_read_from_buffer(user_buf, count, ppos, buf, len); + kfree(buf); + + return retval; + +#undef PHY_ERR } static const struct file_operations fops_recv = { diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c b/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c index 0e28558..a62495d 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c @@ -540,6 +540,8 @@ static bool ath9k_rx_prepare(struct ath9k_htc_priv *priv, goto rx_next; } + ath9k_htc_err_stat_rx(priv, rxstatus); + /* Get the RX status information */ memcpy(&rxbuf->rxstatus, rxstatus, HTC_RX_FRAME_HEADER_SIZE); skb_pull(skb, HTC_RX_FRAME_HEADER_SIZE); -- cgit v0.10.2 From b1563a4c3d721cb0496b8e1fb874f08a8f2b62cc Mon Sep 17 00:00:00 2001 From: Sujith Manoharan Date: Wed, 13 Apr 2011 11:24:19 +0530 Subject: ath9k_htc: Fix RX length check The length of the received SKB could be equal to HTC_RX_FRAME_HEADER_SIZE in case of packets with phy/crc errors, in which case they are dropped without being processed. Fix this check so that the error counters are updated correctly. Signed-off-by: Sujith Manoharan Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c b/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c index a62495d..7cd3e4e 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c @@ -525,8 +525,9 @@ static bool ath9k_rx_prepare(struct ath9k_htc_priv *priv, int last_rssi = ATH_RSSI_DUMMY_MARKER; __le16 fc; - if (skb->len <= HTC_RX_FRAME_HEADER_SIZE) { - ath_err(common, "Corrupted RX frame, dropping\n"); + if (skb->len < HTC_RX_FRAME_HEADER_SIZE) { + ath_err(common, "Corrupted RX frame, dropping (len: %d)\n", + skb->len); goto rx_next; } -- cgit v0.10.2 From e723f3900c3b23feb427672c6ccfe5d4243d2c2d Mon Sep 17 00:00:00 2001 From: Sujith Manoharan Date: Wed, 13 Apr 2011 11:24:25 +0530 Subject: ath9k_htc: Remove unused WMI commands WMI_TGT_TXQ_ENABLE_CMDID WMI_HOST_ATTACH WMI_DEBUG_INFO_CMDID WMI_BEACON_UPDATE_CMDID WMI_RESET_CMDID WMI_RX_LINK_CMDID WMI_STOP_DMA_RECV_CMDID Signed-off-by: Sujith Manoharan Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/wmi.c b/drivers/net/wireless/ath/ath9k/wmi.c index 4578475..3b8f25f 100644 --- a/drivers/net/wireless/ath/ath9k/wmi.c +++ b/drivers/net/wireless/ath/ath9k/wmi.c @@ -29,16 +29,12 @@ static const char *wmi_cmd_to_name(enum wmi_cmd_id wmi_cmd) return "WMI_DISABLE_INTR_CMDID"; case WMI_ENABLE_INTR_CMDID: return "WMI_ENABLE_INTR_CMDID"; - case WMI_RX_LINK_CMDID: - return "WMI_RX_LINK_CMDID"; case WMI_ATH_INIT_CMDID: return "WMI_ATH_INIT_CMDID"; case WMI_ABORT_TXQ_CMDID: return "WMI_ABORT_TXQ_CMDID"; case WMI_STOP_TX_DMA_CMDID: return "WMI_STOP_TX_DMA_CMDID"; - case WMI_STOP_DMA_RECV_CMDID: - return "WMI_STOP_DMA_RECV_CMDID"; case WMI_ABORT_TX_DMA_CMDID: return "WMI_ABORT_TX_DMA_CMDID"; case WMI_DRAIN_TXQ_CMDID: @@ -53,8 +49,6 @@ static const char *wmi_cmd_to_name(enum wmi_cmd_id wmi_cmd) return "WMI_FLUSH_RECV_CMDID"; case WMI_SET_MODE_CMDID: return "WMI_SET_MODE_CMDID"; - case WMI_RESET_CMDID: - return "WMI_RESET_CMDID"; case WMI_NODE_CREATE_CMDID: return "WMI_NODE_CREATE_CMDID"; case WMI_NODE_REMOVE_CMDID: @@ -63,8 +57,6 @@ static const char *wmi_cmd_to_name(enum wmi_cmd_id wmi_cmd) return "WMI_VAP_REMOVE_CMDID"; case WMI_VAP_CREATE_CMDID: return "WMI_VAP_CREATE_CMDID"; - case WMI_BEACON_UPDATE_CMDID: - return "WMI_BEACON_UPDATE_CMDID"; case WMI_REG_READ_CMDID: return "WMI_REG_READ_CMDID"; case WMI_REG_WRITE_CMDID: @@ -73,10 +65,6 @@ static const char *wmi_cmd_to_name(enum wmi_cmd_id wmi_cmd) return "WMI_RC_STATE_CHANGE_CMDID"; case WMI_RC_RATE_UPDATE_CMDID: return "WMI_RC_RATE_UPDATE_CMDID"; - case WMI_DEBUG_INFO_CMDID: - return "WMI_DEBUG_INFO_CMDID"; - case WMI_HOST_ATTACH: - return "WMI_HOST_ATTACH"; case WMI_TARGET_IC_UPDATE_CMDID: return "WMI_TARGET_IC_UPDATE_CMDID"; case WMI_TGT_STATS_CMDID: @@ -85,8 +73,6 @@ static const char *wmi_cmd_to_name(enum wmi_cmd_id wmi_cmd) return "WMI_TX_AGGR_ENABLE_CMDID"; case WMI_TGT_DETACH_CMDID: return "WMI_TGT_DETACH_CMDID"; - case WMI_TGT_TXQ_ENABLE_CMDID: - return "WMI_TGT_TXQ_ENABLE_CMDID"; case WMI_AGGR_LIMIT_CMD: return "WMI_AGGR_LIMIT_CMD"; } diff --git a/drivers/net/wireless/ath/ath9k/wmi.h b/drivers/net/wireless/ath/ath9k/wmi.h index ff5ba2b..3ab9604 100644 --- a/drivers/net/wireless/ath/ath9k/wmi.h +++ b/drivers/net/wireless/ath/ath9k/wmi.h @@ -49,11 +49,9 @@ enum wmi_cmd_id { WMI_GET_FW_VERSION, WMI_DISABLE_INTR_CMDID, WMI_ENABLE_INTR_CMDID, - WMI_RX_LINK_CMDID, WMI_ATH_INIT_CMDID, WMI_ABORT_TXQ_CMDID, WMI_STOP_TX_DMA_CMDID, - WMI_STOP_DMA_RECV_CMDID, WMI_ABORT_TX_DMA_CMDID, WMI_DRAIN_TXQ_CMDID, WMI_DRAIN_TXQ_ALL_CMDID, @@ -61,23 +59,18 @@ enum wmi_cmd_id { WMI_STOP_RECV_CMDID, WMI_FLUSH_RECV_CMDID, WMI_SET_MODE_CMDID, - WMI_RESET_CMDID, WMI_NODE_CREATE_CMDID, WMI_NODE_REMOVE_CMDID, WMI_VAP_REMOVE_CMDID, WMI_VAP_CREATE_CMDID, - WMI_BEACON_UPDATE_CMDID, WMI_REG_READ_CMDID, WMI_REG_WRITE_CMDID, WMI_RC_STATE_CHANGE_CMDID, WMI_RC_RATE_UPDATE_CMDID, - WMI_DEBUG_INFO_CMDID, - WMI_HOST_ATTACH, WMI_TARGET_IC_UPDATE_CMDID, WMI_TGT_STATS_CMDID, WMI_TX_AGGR_ENABLE_CMDID, WMI_TGT_DETACH_CMDID, - WMI_TGT_TXQ_ENABLE_CMDID, WMI_AGGR_LIMIT_CMD = 0x0026, }; -- cgit v0.10.2 From 40dc9e4b86963b77918f1b8fa02b98c1e420a7e1 Mon Sep 17 00:00:00 2001 From: Sujith Manoharan Date: Wed, 13 Apr 2011 11:24:31 +0530 Subject: ath9k_htc: Use SKB's private area for TX parameters For all packets sent through the USB_WLAN_TX_PIPE endpoint, the private area of the SKB's tx_info can be used to store driver-specific information. For packets sent through USB_REG_OUT_PIPE, this will not make a difference since they are routed through a separate routine that doesn't access the private region. This would help in situations where TX information is required in the URB callback. Signed-off-by: Sujith Manoharan Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/hif_usb.c b/drivers/net/wireless/ath/ath9k/hif_usb.c index 23094b7..e252576 100644 --- a/drivers/net/wireless/ath/ath9k/hif_usb.c +++ b/drivers/net/wireless/ath/ath9k/hif_usb.c @@ -284,9 +284,9 @@ static int __hif_usb_tx(struct hif_device_usb *hif_dev) return ret; } -static int hif_usb_send_tx(struct hif_device_usb *hif_dev, struct sk_buff *skb, - struct ath9k_htc_tx_ctl *tx_ctl) +static int hif_usb_send_tx(struct hif_device_usb *hif_dev, struct sk_buff *skb) { + struct ath9k_htc_tx_ctl *tx_ctl; unsigned long flags; spin_lock_irqsave(&hif_dev->tx.tx_lock, flags); @@ -305,12 +305,14 @@ static int hif_usb_send_tx(struct hif_device_usb *hif_dev, struct sk_buff *skb, __skb_queue_tail(&hif_dev->tx.tx_skb_queue, skb); hif_dev->tx.tx_skb_cnt++; - /* Send normal frames immediately */ - if (!tx_ctl || (tx_ctl && (tx_ctl->type == ATH9K_HTC_NORMAL))) + tx_ctl = HTC_SKB_CB(skb); + + /* Send normal/mgmt/beacon frames immediately */ + if (tx_ctl->type != ATH9K_HTC_AMPDU) __hif_usb_tx(hif_dev); /* Check if AMPDUs have to be sent immediately */ - if (tx_ctl && (tx_ctl->type == ATH9K_HTC_AMPDU) && + if ((tx_ctl->type == ATH9K_HTC_AMPDU) && (hif_dev->tx.tx_buf_cnt == MAX_TX_URB_NUM) && (hif_dev->tx.tx_skb_cnt < 2)) { __hif_usb_tx(hif_dev); @@ -352,15 +354,14 @@ static void hif_usb_stop(void *hif_handle, u8 pipe_id) } } -static int hif_usb_send(void *hif_handle, u8 pipe_id, struct sk_buff *skb, - struct ath9k_htc_tx_ctl *tx_ctl) +static int hif_usb_send(void *hif_handle, u8 pipe_id, struct sk_buff *skb) { struct hif_device_usb *hif_dev = (struct hif_device_usb *)hif_handle; int ret = 0; switch (pipe_id) { case USB_WLAN_TX_PIPE: - ret = hif_usb_send_tx(hif_dev, skb, tx_ctl); + ret = hif_usb_send_tx(hif_dev, skb); break; case USB_REG_OUT_PIPE: ret = hif_usb_send_regout(hif_dev, skb); diff --git a/drivers/net/wireless/ath/ath9k/htc.h b/drivers/net/wireless/ath/ath9k/htc.h index 0e48fa0..2eabfe4 100644 --- a/drivers/net/wireless/ath/ath9k/htc.h +++ b/drivers/net/wireless/ath/ath9k/htc.h @@ -67,8 +67,11 @@ enum htc_opmode { }; #define ATH9K_HTC_HDRSPACE sizeof(struct htc_frame_hdr) -#define ATH9K_HTC_AMPDU 1 + +#define ATH9K_HTC_AMPDU 1 #define ATH9K_HTC_NORMAL 2 +#define ATH9K_HTC_BEACON 3 +#define ATH9K_HTC_MGMT 4 #define ATH9K_HTC_TX_CTSONLY 0x1 #define ATH9K_HTC_TX_RTSCTS 0x2 @@ -288,6 +291,15 @@ struct ath9k_htc_tx_ctl { u8 type; /* ATH9K_HTC_* */ }; +static inline struct ath9k_htc_tx_ctl *HTC_SKB_CB(struct sk_buff *skb) +{ + struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); + + BUILD_BUG_ON(sizeof(struct ath9k_htc_tx_ctl) > + IEEE80211_TX_INFO_DRIVER_DATA_SIZE); + return (struct ath9k_htc_tx_ctl *) &tx_info->driver_data; +} + #ifdef CONFIG_ATH9K_HTC_DEBUGFS #define TX_STAT_INC(c) (hif_dev->htc_handle->drv_priv->debug.tx_stats.c++) diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c b/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c index 2180a9d..713def1 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c @@ -341,7 +341,7 @@ static void ath9k_htc_send_beacon(struct ath9k_htc_priv *priv, struct ieee80211_vif *vif; struct ath9k_htc_vif *avp; struct tx_beacon_header beacon_hdr; - struct ath9k_htc_tx_ctl tx_ctl; + struct ath9k_htc_tx_ctl *tx_ctl; struct ieee80211_tx_info *info; struct ieee80211_mgmt *mgmt; struct sk_buff *beacon; @@ -349,7 +349,6 @@ static void ath9k_htc_send_beacon(struct ath9k_htc_priv *priv, int ret; memset(&beacon_hdr, 0, sizeof(struct tx_beacon_header)); - memset(&tx_ctl, 0, sizeof(struct ath9k_htc_tx_ctl)); spin_lock_bh(&priv->beacon_lock); @@ -384,12 +383,16 @@ static void ath9k_htc_send_beacon(struct ath9k_htc_priv *priv, hdr->seq_ctrl |= cpu_to_le16(avp->seq_no); } - tx_ctl.type = ATH9K_HTC_NORMAL; + tx_ctl = HTC_SKB_CB(beacon); + memset(tx_ctl, 0, sizeof(*tx_ctl)); + + tx_ctl->type = ATH9K_HTC_BEACON; + beacon_hdr.vif_index = avp->index; tx_fhdr = skb_push(beacon, sizeof(beacon_hdr)); memcpy(tx_fhdr, (u8 *) &beacon_hdr, sizeof(beacon_hdr)); - ret = htc_send(priv->htc, beacon, priv->beacon_ep, &tx_ctl); + ret = htc_send(priv->htc, beacon, priv->beacon_ep); if (ret != 0) { if (ret == -ENOMEM) { ath_dbg(common, ATH_DBG_BSTUCK, diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c b/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c index 7cd3e4e..ab55dff 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c @@ -89,13 +89,16 @@ int ath9k_htc_tx_start(struct ath9k_htc_priv *priv, struct ieee80211_vif *vif = tx_info->control.vif; struct ath9k_htc_sta *ista; struct ath9k_htc_vif *avp = NULL; - struct ath9k_htc_tx_ctl tx_ctl; + struct ath9k_htc_tx_ctl *tx_ctl; enum htc_endpoint_id epid; u16 qnum; __le16 fc; u8 *tx_fhdr; u8 sta_idx, vif_idx; + tx_ctl = HTC_SKB_CB(skb); + memset(tx_ctl, 0, sizeof(*tx_ctl)); + hdr = (struct ieee80211_hdr *) skb->data; fc = hdr->frame_control; @@ -126,8 +129,6 @@ int ath9k_htc_tx_start(struct ath9k_htc_priv *priv, sta_idx = priv->vif_sta_pos[vif_idx]; } - memset(&tx_ctl, 0, sizeof(struct ath9k_htc_tx_ctl)); - if (ieee80211_is_data(fc)) { struct tx_frame_hdr tx_hdr; u32 flags = 0; @@ -139,10 +140,10 @@ int ath9k_htc_tx_start(struct ath9k_htc_priv *priv, tx_hdr.vif_idx = vif_idx; if (tx_info->flags & IEEE80211_TX_CTL_AMPDU) { - tx_ctl.type = ATH9K_HTC_AMPDU; + tx_ctl->type = ATH9K_HTC_AMPDU; tx_hdr.data_type = ATH9K_HTC_AMPDU; } else { - tx_ctl.type = ATH9K_HTC_NORMAL; + tx_ctl->type = ATH9K_HTC_NORMAL; tx_hdr.data_type = ATH9K_HTC_NORMAL; } @@ -212,7 +213,7 @@ int ath9k_htc_tx_start(struct ath9k_htc_priv *priv, mgmt->u.probe_resp.timestamp = avp->tsfadjust; } - tx_ctl.type = ATH9K_HTC_NORMAL; + tx_ctl->type = ATH9K_HTC_MGMT; mgmt_hdr.node_idx = sta_idx; mgmt_hdr.vif_idx = vif_idx; @@ -230,7 +231,7 @@ int ath9k_htc_tx_start(struct ath9k_htc_priv *priv, epid = priv->mgmt_ep; } send: - return htc_send(priv->htc, skb, epid, &tx_ctl); + return htc_send(priv->htc, skb, epid); } static bool ath9k_htc_check_tx_aggr(struct ath9k_htc_priv *priv, diff --git a/drivers/net/wireless/ath/ath9k/htc_hst.c b/drivers/net/wireless/ath/ath9k/htc_hst.c index c41ab8c..6ee53de 100644 --- a/drivers/net/wireless/ath/ath9k/htc_hst.c +++ b/drivers/net/wireless/ath/ath9k/htc_hst.c @@ -17,8 +17,8 @@ #include "htc.h" static int htc_issue_send(struct htc_target *target, struct sk_buff* skb, - u16 len, u8 flags, u8 epid, - struct ath9k_htc_tx_ctl *tx_ctl) + u16 len, u8 flags, u8 epid) + { struct htc_frame_hdr *hdr; struct htc_endpoint *endpoint = &target->endpoint[epid]; @@ -30,8 +30,8 @@ static int htc_issue_send(struct htc_target *target, struct sk_buff* skb, hdr->flags = flags; hdr->payload_len = cpu_to_be16(len); - status = target->hif->send(target->hif_dev, endpoint->ul_pipeid, skb, - tx_ctl); + status = target->hif->send(target->hif_dev, endpoint->ul_pipeid, skb); + return status; } @@ -162,7 +162,7 @@ static int htc_config_pipe_credits(struct htc_target *target) target->htc_flags |= HTC_OP_CONFIG_PIPE_CREDITS; - ret = htc_issue_send(target, skb, skb->len, 0, ENDPOINT0, NULL); + ret = htc_issue_send(target, skb, skb->len, 0, ENDPOINT0); if (ret) goto err; @@ -197,7 +197,7 @@ static int htc_setup_complete(struct htc_target *target) target->htc_flags |= HTC_OP_START_WAIT; - ret = htc_issue_send(target, skb, skb->len, 0, ENDPOINT0, NULL); + ret = htc_issue_send(target, skb, skb->len, 0, ENDPOINT0); if (ret) goto err; @@ -268,7 +268,7 @@ int htc_connect_service(struct htc_target *target, conn_msg->dl_pipeid = endpoint->dl_pipeid; conn_msg->ul_pipeid = endpoint->ul_pipeid; - ret = htc_issue_send(target, skb, skb->len, 0, ENDPOINT0, NULL); + ret = htc_issue_send(target, skb, skb->len, 0, ENDPOINT0); if (ret) goto err; @@ -287,9 +287,9 @@ err: } int htc_send(struct htc_target *target, struct sk_buff *skb, - enum htc_endpoint_id epid, struct ath9k_htc_tx_ctl *tx_ctl) + enum htc_endpoint_id epid) { - return htc_issue_send(target, skb, skb->len, 0, epid, tx_ctl); + return htc_issue_send(target, skb, skb->len, 0, epid); } void htc_stop(struct htc_target *target) diff --git a/drivers/net/wireless/ath/ath9k/htc_hst.h b/drivers/net/wireless/ath/ath9k/htc_hst.h index ecd0187..3531552 100644 --- a/drivers/net/wireless/ath/ath9k/htc_hst.h +++ b/drivers/net/wireless/ath/ath9k/htc_hst.h @@ -35,8 +35,7 @@ struct ath9k_htc_hif { void (*start) (void *hif_handle, u8 pipe); void (*stop) (void *hif_handle, u8 pipe); - int (*send) (void *hif_handle, u8 pipe, struct sk_buff *buf, - struct ath9k_htc_tx_ctl *tx_ctl); + int (*send) (void *hif_handle, u8 pipe, struct sk_buff *buf); }; enum htc_endpoint_id { @@ -206,7 +205,7 @@ int htc_connect_service(struct htc_target *target, struct htc_service_connreq *service_connreq, enum htc_endpoint_id *conn_rsp_eid); int htc_send(struct htc_target *target, struct sk_buff *skb, - enum htc_endpoint_id eid, struct ath9k_htc_tx_ctl *tx_ctl); + enum htc_endpoint_id eid); void htc_stop(struct htc_target *target); void htc_start(struct htc_target *target); diff --git a/drivers/net/wireless/ath/ath9k/wmi.c b/drivers/net/wireless/ath/ath9k/wmi.c index 3b8f25f..83d1e0e 100644 --- a/drivers/net/wireless/ath/ath9k/wmi.c +++ b/drivers/net/wireless/ath/ath9k/wmi.c @@ -267,7 +267,7 @@ static int ath9k_wmi_cmd_issue(struct wmi *wmi, hdr->command_id = cpu_to_be16(cmd); hdr->seq_no = cpu_to_be16(++wmi->tx_seq_id); - return htc_send(wmi->htc, skb, wmi->ctrl_epid, NULL); + return htc_send(wmi->htc, skb, wmi->ctrl_epid); } int ath9k_wmi_cmd(struct wmi *wmi, enum wmi_cmd_id cmd_id, -- cgit v0.10.2 From b97c57ff3f568b33ed91915f48431feae2dab288 Mon Sep 17 00:00:00 2001 From: Sujith Manoharan Date: Wed, 13 Apr 2011 11:24:37 +0530 Subject: ath9k_htc: Sync struct ath9k_htc_target_sta with FW Signed-off-by: Sujith Manoharan Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/htc.h b/drivers/net/wireless/ath/ath9k/htc.h index 2eabfe4..e096624 100644 --- a/drivers/net/wireless/ath/ath9k/htc.h +++ b/drivers/net/wireless/ath/ath9k/htc.h @@ -104,17 +104,6 @@ struct tx_beacon_header { u16 rev; } __packed; -struct ath9k_htc_target_hw { - u32 flags; - u32 flags_ext; - u32 ampdu_limit; - u8 ampdu_subframes; - u8 tx_chainmask; - u8 tx_chainmask_legacy; - u8 rtscts_ratecode; - u8 protmode; -} __packed; - struct ath9k_htc_cap_target { u32 flags; u32 flags_ext; @@ -146,27 +135,16 @@ struct ath9k_htc_target_vif { #define ATH_HTC_STA_ERP 0x0004 #define ATH_HTC_STA_HT 0x0008 -/* FIXME: UAPSD variables */ struct ath9k_htc_target_sta { - u16 associd; - u16 txpower; - u32 ucastkey; u8 macaddr[ETH_ALEN]; u8 bssid[ETH_ALEN]; u8 sta_index; u8 vif_index; - u8 vif_sta; - __be16 flags; /* ATH_HTC_STA_* */ - u16 htcap; - u8 valid; - u16 capinfo; - struct ath9k_htc_target_hw *hw; - struct ath9k_htc_target_vif *vif; - u16 txseqmgmt; u8 is_vif_sta; - u16 maxampdu; - u16 iv16; - u32 iv32; + __be16 flags; /* ATH_HTC_STA_* */ + __be16 htcap; + __be16 maxampdu; + u8 pad; } __packed; struct ath9k_htc_target_aggr { diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_main.c b/drivers/net/wireless/ath/ath9k/htc_drv_main.c index 59710e7..9bb20f3 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_main.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_main.c @@ -382,7 +382,7 @@ static int ath9k_htc_add_monitor_interface(struct ath9k_htc_priv *priv) tsta.is_vif_sta = 1; tsta.sta_index = sta_idx; tsta.vif_index = hvif.index; - tsta.maxampdu = 0xffff; + tsta.maxampdu = cpu_to_be16(0xffff); WMI_CMD_BUF(WMI_NODE_CREATE_CMDID, &tsta); if (ret) { @@ -463,9 +463,7 @@ static int ath9k_htc_add_station(struct ath9k_htc_priv *priv, ista = (struct ath9k_htc_sta *) sta->drv_priv; memcpy(&tsta.macaddr, sta->addr, ETH_ALEN); memcpy(&tsta.bssid, common->curbssid, ETH_ALEN); - tsta.associd = common->curaid; tsta.is_vif_sta = 0; - tsta.valid = true; ista->index = sta_idx; } else { memcpy(&tsta.macaddr, vif->addr, ETH_ALEN); @@ -474,7 +472,7 @@ static int ath9k_htc_add_station(struct ath9k_htc_priv *priv, tsta.sta_index = sta_idx; tsta.vif_index = avp->index; - tsta.maxampdu = 0xffff; + tsta.maxampdu = cpu_to_be16(0xffff); if (sta && sta->ht_cap.ht_supported) tsta.flags = cpu_to_be16(ATH_HTC_STA_HT); -- cgit v0.10.2 From e4c62506fcfa7c1fa7c586ab518a172c3a65db0f Mon Sep 17 00:00:00 2001 From: Sujith Manoharan Date: Wed, 13 Apr 2011 11:24:43 +0530 Subject: ath9k_htc: Sync struct ath9k_htc_target_vif with FW Signed-off-by: Sujith Manoharan Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/htc.h b/drivers/net/wireless/ath/ath9k/htc.h index e096624..f74f45f 100644 --- a/drivers/net/wireless/ath/ath9k/htc.h +++ b/drivers/net/wireless/ath/ath9k/htc.h @@ -117,17 +117,11 @@ struct ath9k_htc_cap_target { struct ath9k_htc_target_vif { u8 index; - u8 des_bssid[ETH_ALEN]; - __be32 opmode; + u8 opmode; u8 myaddr[ETH_ALEN]; - u8 bssid[ETH_ALEN]; - u32 flags; - u32 flags_ext; - u16 ps_sta; - __be16 rtsthreshold; u8 ath_cap; - u8 node; - s8 mcast_rate; + __be16 rtsthreshold; + u8 pad; } __packed; #define ATH_HTC_STA_AUTH 0x0001 diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_main.c b/drivers/net/wireless/ath/ath9k/htc_drv_main.c index 9bb20f3..4002267 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_main.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_main.c @@ -349,7 +349,7 @@ static int ath9k_htc_add_monitor_interface(struct ath9k_htc_priv *priv) memset(&hvif, 0, sizeof(struct ath9k_htc_target_vif)); memcpy(&hvif.myaddr, common->macaddr, ETH_ALEN); - hvif.opmode = cpu_to_be32(HTC_M_MONITOR); + hvif.opmode = HTC_M_MONITOR; hvif.index = ffz(priv->vif_slot); WMI_CMD_BUF(WMI_VAP_CREATE_CMDID, &hvif); @@ -1039,13 +1039,13 @@ static int ath9k_htc_add_interface(struct ieee80211_hw *hw, switch (vif->type) { case NL80211_IFTYPE_STATION: - hvif.opmode = cpu_to_be32(HTC_M_STA); + hvif.opmode = HTC_M_STA; break; case NL80211_IFTYPE_ADHOC: - hvif.opmode = cpu_to_be32(HTC_M_IBSS); + hvif.opmode = HTC_M_IBSS; break; case NL80211_IFTYPE_AP: - hvif.opmode = cpu_to_be32(HTC_M_HOSTAP); + hvif.opmode = HTC_M_HOSTAP; break; default: ath_err(common, -- cgit v0.10.2 From 0a8579f6b7c3f4332ad9eb6615c7631ef9cd4ed6 Mon Sep 17 00:00:00 2001 From: Sujith Manoharan Date: Wed, 13 Apr 2011 11:24:49 +0530 Subject: ath9k_htc: Sync struct ath9k_htc_cap_target with FW Signed-off-by: Sujith Manoharan Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/htc.h b/drivers/net/wireless/ath/ath9k/htc.h index f74f45f..1568c36 100644 --- a/drivers/net/wireless/ath/ath9k/htc.h +++ b/drivers/net/wireless/ath/ath9k/htc.h @@ -113,6 +113,7 @@ struct ath9k_htc_cap_target { u8 tx_chainmask_legacy; u8 rtscts_ratecode; u8 protmode; + u8 pad; } __packed; struct ath9k_htc_target_vif { -- cgit v0.10.2 From ee3fa1bdadd998652083a7814af745f765a06a25 Mon Sep 17 00:00:00 2001 From: Sujith Manoharan Date: Wed, 13 Apr 2011 11:24:55 +0530 Subject: ath9k_htc: Remove unused WMI_WLAN_TXCOMP_EVENTID Signed-off-by: Sujith Manoharan Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/wmi.h b/drivers/net/wireless/ath/ath9k/wmi.h index 3ab9604..a81d554 100644 --- a/drivers/net/wireless/ath/ath9k/wmi.h +++ b/drivers/net/wireless/ath/ath9k/wmi.h @@ -80,7 +80,6 @@ enum wmi_event_id { WMI_FATAL_EVENTID, WMI_TXTO_EVENTID, WMI_BMISS_EVENTID, - WMI_WLAN_TXCOMP_EVENTID, WMI_DELBA_EVENTID, WMI_TXRATE_EVENTID, }; -- cgit v0.10.2 From 658ef04fd42a587b17a379ad9208023473442ddd Mon Sep 17 00:00:00 2001 From: Sujith Manoharan Date: Wed, 13 Apr 2011 11:25:00 +0530 Subject: ath9k_htc: Move TX specific stuff to a separate structure Signed-off-by: Sujith Manoharan Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/htc.h b/drivers/net/wireless/ath/ath9k/htc.h index 1568c36..3af8a58 100644 --- a/drivers/net/wireless/ath/ath9k/htc.h +++ b/drivers/net/wireless/ath/ath9k/htc.h @@ -260,6 +260,13 @@ struct ath9k_htc_rx { spinlock_t rxbuflock; }; +struct ath9k_htc_tx { + bool tx_queues_stop; + spinlock_t tx_lock; + + struct sk_buff_head tx_queue; +}; + struct ath9k_htc_tx_ctl { u8 type; /* ATH9K_HTC_* */ }; @@ -433,22 +440,20 @@ struct ath9k_htc_priv { u16 nstations; bool rearm_ani; bool reconfig_beacon; + unsigned int rxfilter; struct ath9k_hw_cal_data caldata; + struct ieee80211_supported_band sbands[IEEE80211_NUM_BANDS]; spinlock_t beacon_lock; + struct htc_beacon_config cur_beacon_conf; - bool tx_queues_stop; - spinlock_t tx_lock; + struct ath9k_htc_rx rx; + struct ath9k_htc_tx tx; - struct htc_beacon_config cur_beacon_conf; - unsigned int rxfilter; struct tasklet_struct swba_tasklet; struct tasklet_struct rx_tasklet; - struct ieee80211_supported_band sbands[IEEE80211_NUM_BANDS]; - struct ath9k_htc_rx rx; struct tasklet_struct tx_tasklet; - struct sk_buff_head tx_queue; struct delayed_work ani_work; struct work_struct ps_work; struct work_struct fatal_work; diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_gpio.c b/drivers/net/wireless/ath/ath9k/htc_drv_gpio.c index 459ba0d..1f6df4a 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_gpio.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_gpio.c @@ -398,9 +398,9 @@ void ath9k_htc_radio_enable(struct ieee80211_hw *hw) /* Start TX */ htc_start(priv->htc); - spin_lock_bh(&priv->tx_lock); - priv->tx_queues_stop = false; - spin_unlock_bh(&priv->tx_lock); + spin_lock_bh(&priv->tx.tx_lock); + priv->tx.tx_queues_stop = false; + spin_unlock_bh(&priv->tx.tx_lock); ieee80211_wake_queues(hw); WMI_CMD(WMI_ENABLE_INTR_CMDID); @@ -431,7 +431,7 @@ void ath9k_htc_radio_disable(struct ieee80211_hw *hw) ieee80211_stop_queues(hw); htc_stop(priv->htc); WMI_CMD(WMI_DRAIN_TXQ_ALL_CMDID); - skb_queue_purge(&priv->tx_queue); + skb_queue_purge(&priv->tx.tx_queue); /* Stop RX */ WMI_CMD(WMI_STOP_RECV_CMDID); diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_init.c b/drivers/net/wireless/ath/ath9k/htc_drv_init.c index 921d76f..c270da7 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_init.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_init.c @@ -673,7 +673,7 @@ static int ath9k_init_priv(struct ath9k_htc_priv *priv, spin_lock_init(&priv->wmi->wmi_lock); spin_lock_init(&priv->beacon_lock); - spin_lock_init(&priv->tx_lock); + spin_lock_init(&priv->tx.tx_lock); mutex_init(&priv->mutex); mutex_init(&priv->htc_pm_lock); tasklet_init(&priv->rx_tasklet, ath9k_rx_tasklet, diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_main.c b/drivers/net/wireless/ath/ath9k/htc_drv_main.c index 4002267..ff3a495 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_main.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_main.c @@ -707,9 +707,9 @@ static int ath9k_htc_tx_aggr_oper(struct ath9k_htc_priv *priv, (aggr.aggr_enable) ? "Starting" : "Stopping", sta->addr, tid); - spin_lock_bh(&priv->tx_lock); + spin_lock_bh(&priv->tx.tx_lock); ista->tid_state[tid] = (aggr.aggr_enable && !ret) ? AGGR_START : AGGR_STOP; - spin_unlock_bh(&priv->tx_lock); + spin_unlock_bh(&priv->tx.tx_lock); return ret; } @@ -853,9 +853,9 @@ static void ath9k_htc_tx(struct ieee80211_hw *hw, struct sk_buff *skb) ath_dbg(ath9k_hw_common(priv->ah), ATH_DBG_XMIT, "Stopping TX queues\n"); ieee80211_stop_queues(hw); - spin_lock_bh(&priv->tx_lock); - priv->tx_queues_stop = true; - spin_unlock_bh(&priv->tx_lock); + spin_lock_bh(&priv->tx.tx_lock); + priv->tx.tx_queues_stop = true; + spin_unlock_bh(&priv->tx.tx_lock); } else { ath_dbg(ath9k_hw_common(priv->ah), ATH_DBG_XMIT, "Tx failed\n"); @@ -923,9 +923,9 @@ static int ath9k_htc_start(struct ieee80211_hw *hw) priv->op_flags &= ~OP_INVALID; htc_start(priv->htc); - spin_lock_bh(&priv->tx_lock); - priv->tx_queues_stop = false; - spin_unlock_bh(&priv->tx_lock); + spin_lock_bh(&priv->tx.tx_lock); + priv->tx.tx_queues_stop = false; + spin_unlock_bh(&priv->tx.tx_lock); ieee80211_wake_queues(hw); @@ -965,7 +965,7 @@ static void ath9k_htc_stop(struct ieee80211_hw *hw) tasklet_kill(&priv->rx_tasklet); tasklet_kill(&priv->tx_tasklet); - skb_queue_purge(&priv->tx_queue); + skb_queue_purge(&priv->tx.tx_queue); ath9k_wmi_event_drain(priv); @@ -1563,9 +1563,9 @@ static int ath9k_htc_ampdu_action(struct ieee80211_hw *hw, break; case IEEE80211_AMPDU_TX_OPERATIONAL: ista = (struct ath9k_htc_sta *) sta->drv_priv; - spin_lock_bh(&priv->tx_lock); + spin_lock_bh(&priv->tx.tx_lock); ista->tid_state[tid] = AGGR_OPERATIONAL; - spin_unlock_bh(&priv->tx_lock); + spin_unlock_bh(&priv->tx.tx_lock); break; default: ath_err(ath9k_hw_common(priv->ah), "Unknown AMPDU action\n"); diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c b/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c index ab55dff..6f7987d 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c @@ -239,10 +239,10 @@ static bool ath9k_htc_check_tx_aggr(struct ath9k_htc_priv *priv, { bool ret = false; - spin_lock_bh(&priv->tx_lock); + spin_lock_bh(&priv->tx.tx_lock); if ((tid < ATH9K_HTC_MAX_TID) && (ista->tid_state[tid] == AGGR_STOP)) ret = true; - spin_unlock_bh(&priv->tx_lock); + spin_unlock_bh(&priv->tx.tx_lock); return ret; } @@ -257,7 +257,7 @@ void ath9k_tx_tasklet(unsigned long data) struct sk_buff *skb = NULL; __le16 fc; - while ((skb = skb_dequeue(&priv->tx_queue)) != NULL) { + while ((skb = skb_dequeue(&priv->tx.tx_queue)) != NULL) { hdr = (struct ieee80211_hdr *) skb->data; fc = hdr->frame_control; @@ -292,9 +292,9 @@ void ath9k_tx_tasklet(unsigned long data) if (ath9k_htc_check_tx_aggr(priv, ista, tid)) { ieee80211_start_tx_ba_session(sta, tid, 0); - spin_lock_bh(&priv->tx_lock); + spin_lock_bh(&priv->tx.tx_lock); ista->tid_state[tid] = AGGR_PROGRESS; - spin_unlock_bh(&priv->tx_lock); + spin_unlock_bh(&priv->tx.tx_lock); } } } @@ -307,16 +307,16 @@ void ath9k_tx_tasklet(unsigned long data) } /* Wake TX queues if needed */ - spin_lock_bh(&priv->tx_lock); - if (priv->tx_queues_stop) { - priv->tx_queues_stop = false; - spin_unlock_bh(&priv->tx_lock); + spin_lock_bh(&priv->tx.tx_lock); + if (priv->tx.tx_queues_stop) { + priv->tx.tx_queues_stop = false; + spin_unlock_bh(&priv->tx.tx_lock); ath_dbg(ath9k_hw_common(priv->ah), ATH_DBG_XMIT, "Waking up TX queues\n"); ieee80211_wake_queues(priv->hw); return; } - spin_unlock_bh(&priv->tx_lock); + spin_unlock_bh(&priv->tx.tx_lock); } void ath9k_htc_txep(void *drv_priv, struct sk_buff *skb, @@ -348,13 +348,13 @@ void ath9k_htc_txep(void *drv_priv, struct sk_buff *skb, if (txok) tx_info->flags |= IEEE80211_TX_STAT_ACK; - skb_queue_tail(&priv->tx_queue, skb); + skb_queue_tail(&priv->tx.tx_queue, skb); tasklet_schedule(&priv->tx_tasklet); } int ath9k_tx_init(struct ath9k_htc_priv *priv) { - skb_queue_head_init(&priv->tx_queue); + skb_queue_head_init(&priv->tx.tx_queue); return 0; } -- cgit v0.10.2 From 15f6d6d52fe0d9fcf8c09788caff5d1684e5f12c Mon Sep 17 00:00:00 2001 From: Sujith Manoharan Date: Wed, 13 Apr 2011 11:25:06 +0530 Subject: ath9k_htc: Reduce TX queue size The current max queue length of 1024 is quite large and unnecessary. 256 suffices well enough even for high throughput situations. Signed-off-by: Sujith Manoharan Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/hif_usb.h b/drivers/net/wireless/ath/ath9k/hif_usb.h index 7b9d863..f82b32b 100644 --- a/drivers/net/wireless/ath/ath9k/hif_usb.h +++ b/drivers/net/wireless/ath/ath9k/hif_usb.h @@ -31,7 +31,7 @@ /* FIXME: Verify these numbers (with Windows) */ #define MAX_TX_URB_NUM 8 -#define MAX_TX_BUF_NUM 1024 +#define MAX_TX_BUF_NUM 256 #define MAX_TX_BUF_SIZE 32768 #define MAX_TX_AGGR_NUM 20 -- cgit v0.10.2 From e8e3860765641d5e9d1607ec50191cb33c28371d Mon Sep 17 00:00:00 2001 From: Sujith Manoharan Date: Wed, 13 Apr 2011 11:25:12 +0530 Subject: ath9k_htc: Sync MGMT/DATA packet headers with firmware Add a new cookie field that would be filled by the host. This can be used to match the TX status WMI event with the appropriate packet. Signed-off-by: Sujith Manoharan Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/htc.h b/drivers/net/wireless/ath/ath9k/htc.h index 3af8a58..3185fe7 100644 --- a/drivers/net/wireless/ath/ath9k/htc.h +++ b/drivers/net/wireless/ath/ath9k/htc.h @@ -85,7 +85,8 @@ struct tx_frame_hdr { __be32 flags; /* ATH9K_HTC_TX_* */ u8 key_type; u8 keyix; - u8 reserved[26]; + u8 cookie; + u8 pad; } __packed; struct tx_mgmt_hdr { @@ -95,7 +96,8 @@ struct tx_mgmt_hdr { u8 flags; u8 key_type; u8 keyix; - u16 reserved; + u8 cookie; + u8 pad; } __packed; struct tx_beacon_header { -- cgit v0.10.2 From 16c56ae87509d9bbcd8c711dc4f99b38c234d6c5 Mon Sep 17 00:00:00 2001 From: Sujith Manoharan Date: Wed, 13 Apr 2011 11:25:18 +0530 Subject: ath9k_htc: Add a new WMI event WMI_TXSTATUS_EVENTID This event will be generated by the target for packet completions. Signed-off-by: Sujith Manoharan Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/wmi.h b/drivers/net/wireless/ath/ath9k/wmi.h index a81d554..8c877dc 100644 --- a/drivers/net/wireless/ath/ath9k/wmi.h +++ b/drivers/net/wireless/ath/ath9k/wmi.h @@ -41,6 +41,44 @@ struct wmi_event_swba { __be64 tsf; u8 beacon_pending; }; + +/* + * 64 - HTC header - WMI header - 1 / txstatus + * And some other hdr. space is also accounted for. + * 13 seems to be the magic number. + */ +#define HTC_MAX_TX_STATUS 13 + +#define ATH9K_HTC_TXSTAT_ACK BIT(0) +#define ATH9K_HTC_TXSTAT_FILT BIT(1) +#define ATH9K_HTC_TXSTAT_RTC_CTS BIT(2) +#define ATH9K_HTC_TXSTAT_MCS BIT(3) +#define ATH9K_HTC_TXSTAT_CW40 BIT(4) +#define ATH9K_HTC_TXSTAT_SGI BIT(5) + +/* + * Legacy rates are indicated as indices. + * HT rates are indicated as dot11 numbers. + * This allows us to resrict the rate field + * to 4 bits. + */ +#define ATH9K_HTC_TXSTAT_RATE 0x0f +#define ATH9K_HTC_TXSTAT_RATE_S 0 + +#define ATH9K_HTC_TXSTAT_EPID 0xf0 +#define ATH9K_HTC_TXSTAT_EPID_S 4 + +struct __wmi_event_txstatus { + u8 cookie; + u8 ts_rate; /* Also holds EP ID */ + u8 ts_flags; +}; + +struct wmi_event_txstatus { + u8 cnt; + struct __wmi_event_txstatus txstatus[HTC_MAX_TX_STATUS]; +} __packed; + enum wmi_cmd_id { WMI_ECHO_CMDID = 0x0001, WMI_ACCESS_MEMORY_CMDID, @@ -82,6 +120,7 @@ enum wmi_event_id { WMI_BMISS_EVENTID, WMI_DELBA_EVENTID, WMI_TXRATE_EVENTID, + WMI_TXSTATUS_EVENTID, }; #define MAX_CMD_NUMBER 62 -- cgit v0.10.2 From 3deff76095c4ac4252e27c537db3041f619c23a2 Mon Sep 17 00:00:00 2001 From: Sujith Manoharan Date: Wed, 13 Apr 2011 11:25:23 +0530 Subject: ath9k_htc: Increase URB count for REG_IN pipe Using a single URB for receiving WMI events is insufficient, increase it to 64 to not lose WMI events in high throughput situations. Signed-off-by: Sujith Manoharan Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/hif_usb.c b/drivers/net/wireless/ath/ath9k/hif_usb.c index e252576..0b63a48 100644 --- a/drivers/net/wireless/ath/ath9k/hif_usb.c +++ b/drivers/net/wireless/ath/ath9k/hif_usb.c @@ -566,6 +566,9 @@ static void ath9k_hif_usb_reg_in_cb(struct urb *urb) case -ESHUTDOWN: goto free; default: + skb_reset_tail_pointer(skb); + skb_trim(skb, 0); + goto resubmit; } @@ -590,23 +593,15 @@ static void ath9k_hif_usb_reg_in_cb(struct urb *urb) USB_REG_IN_PIPE), nskb->data, MAX_REG_IN_BUF_SIZE, ath9k_hif_usb_reg_in_cb, nskb); - - ret = usb_submit_urb(urb, GFP_ATOMIC); - if (ret) { - kfree_skb(nskb); - urb->context = NULL; - } - - return; } resubmit: - skb_reset_tail_pointer(skb); - skb_trim(skb, 0); - + usb_anchor_urb(urb, &hif_dev->reg_in_submitted); ret = usb_submit_urb(urb, GFP_ATOMIC); - if (ret) + if (ret) { + usb_unanchor_urb(urb); goto free; + } return; free: @@ -747,43 +742,67 @@ err_urb: return ret; } -static void ath9k_hif_usb_dealloc_reg_in_urb(struct hif_device_usb *hif_dev) +static void ath9k_hif_usb_dealloc_reg_in_urbs(struct hif_device_usb *hif_dev) { - if (hif_dev->reg_in_urb) { - usb_kill_urb(hif_dev->reg_in_urb); - if (hif_dev->reg_in_urb->context) - kfree_skb((void *)hif_dev->reg_in_urb->context); - usb_free_urb(hif_dev->reg_in_urb); - hif_dev->reg_in_urb = NULL; - } + usb_kill_anchored_urbs(&hif_dev->reg_in_submitted); } -static int ath9k_hif_usb_alloc_reg_in_urb(struct hif_device_usb *hif_dev) +static int ath9k_hif_usb_alloc_reg_in_urbs(struct hif_device_usb *hif_dev) { - struct sk_buff *skb; + struct urb *urb = NULL; + struct sk_buff *skb = NULL; + int i, ret; - hif_dev->reg_in_urb = usb_alloc_urb(0, GFP_KERNEL); - if (hif_dev->reg_in_urb == NULL) - return -ENOMEM; + init_usb_anchor(&hif_dev->reg_in_submitted); - skb = alloc_skb(MAX_REG_IN_BUF_SIZE, GFP_KERNEL); - if (!skb) - goto err; + for (i = 0; i < MAX_REG_IN_URB_NUM; i++) { - usb_fill_bulk_urb(hif_dev->reg_in_urb, hif_dev->udev, - usb_rcvbulkpipe(hif_dev->udev, - USB_REG_IN_PIPE), - skb->data, MAX_REG_IN_BUF_SIZE, - ath9k_hif_usb_reg_in_cb, skb); + /* Allocate URB */ + urb = usb_alloc_urb(0, GFP_KERNEL); + if (urb == NULL) { + ret = -ENOMEM; + goto err_urb; + } - if (usb_submit_urb(hif_dev->reg_in_urb, GFP_KERNEL) != 0) - goto err; + /* Allocate buffer */ + skb = alloc_skb(MAX_REG_IN_BUF_SIZE, GFP_KERNEL); + if (!skb) { + ret = -ENOMEM; + goto err_skb; + } + + usb_fill_bulk_urb(urb, hif_dev->udev, + usb_rcvbulkpipe(hif_dev->udev, + USB_REG_IN_PIPE), + skb->data, MAX_REG_IN_BUF_SIZE, + ath9k_hif_usb_reg_in_cb, skb); + + /* Anchor URB */ + usb_anchor_urb(urb, &hif_dev->reg_in_submitted); + + /* Submit URB */ + ret = usb_submit_urb(urb, GFP_KERNEL); + if (ret) { + usb_unanchor_urb(urb); + goto err_submit; + } + + /* + * Drop reference count. + * This ensures that the URB is freed when killing them. + */ + usb_free_urb(urb); + } return 0; -err: - ath9k_hif_usb_dealloc_reg_in_urb(hif_dev); - return -ENOMEM; +err_submit: + kfree_skb(skb); +err_skb: + usb_free_urb(urb); +err_urb: + ath9k_hif_usb_dealloc_reg_in_urbs(hif_dev); + return ret; } static int ath9k_hif_usb_alloc_urbs(struct hif_device_usb *hif_dev) @@ -800,7 +819,7 @@ static int ath9k_hif_usb_alloc_urbs(struct hif_device_usb *hif_dev) goto err_rx; /* Register Read */ - if (ath9k_hif_usb_alloc_reg_in_urb(hif_dev) < 0) + if (ath9k_hif_usb_alloc_reg_in_urbs(hif_dev) < 0) goto err_reg; return 0; @@ -815,7 +834,7 @@ err: static void ath9k_hif_usb_dealloc_urbs(struct hif_device_usb *hif_dev) { usb_kill_anchored_urbs(&hif_dev->regout_submitted); - ath9k_hif_usb_dealloc_reg_in_urb(hif_dev); + ath9k_hif_usb_dealloc_reg_in_urbs(hif_dev); ath9k_hif_usb_dealloc_tx_urbs(hif_dev); ath9k_hif_usb_dealloc_rx_urbs(hif_dev); } diff --git a/drivers/net/wireless/ath/ath9k/hif_usb.h b/drivers/net/wireless/ath/ath9k/hif_usb.h index f82b32b..8b98d64 100644 --- a/drivers/net/wireless/ath/ath9k/hif_usb.h +++ b/drivers/net/wireless/ath/ath9k/hif_usb.h @@ -40,7 +40,7 @@ #define MAX_PKT_NUM_IN_TRANSFER 10 #define MAX_REG_OUT_URB_NUM 1 -#define MAX_REG_OUT_BUF_NUM 8 +#define MAX_REG_IN_URB_NUM 64 #define MAX_REG_IN_BUF_SIZE 64 @@ -90,9 +90,9 @@ struct hif_device_usb { const struct firmware *firmware; struct htc_target *htc_handle; struct hif_usb_tx tx; - struct urb *reg_in_urb; struct usb_anchor regout_submitted; struct usb_anchor rx_submitted; + struct usb_anchor reg_in_submitted; struct sk_buff *remain_skb; const char *fw_name; int rx_remain_len; -- cgit v0.10.2 From 8e86a54715c4102a8ed697939de9ebd9715dc59c Mon Sep 17 00:00:00 2001 From: Sujith Manoharan Date: Wed, 13 Apr 2011 11:25:29 +0530 Subject: ath9k_htc: Fix TX queue management Handle queue start/stop properly by maintaining a counter to check if the pending frame count has exceeded the threshold. Otherwise, packets would be dropped needlessly. While at it, use a simple flag to track queue status and use helper functions too. Signed-off-by: Sujith Manoharan Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/htc.h b/drivers/net/wireless/ath/ath9k/htc.h index 3185fe7..fc4c466 100644 --- a/drivers/net/wireless/ath/ath9k/htc.h +++ b/drivers/net/wireless/ath/ath9k/htc.h @@ -262,11 +262,16 @@ struct ath9k_htc_rx { spinlock_t rxbuflock; }; -struct ath9k_htc_tx { - bool tx_queues_stop; - spinlock_t tx_lock; +#define ATH9K_HTC_TX_RESERVE 10 +#define ATH9K_HTC_TX_THRESHOLD (MAX_TX_BUF_NUM - ATH9K_HTC_TX_RESERVE) + +#define ATH9K_HTC_OP_TX_QUEUES_STOP BIT(0) +struct ath9k_htc_tx { + u8 flags; + int queued_cnt; struct sk_buff_head tx_queue; + spinlock_t tx_lock; }; struct ath9k_htc_tx_ctl { @@ -532,6 +537,8 @@ int ath9k_htc_cabq_setup(struct ath9k_htc_priv *priv); int get_hw_qnum(u16 queue, int *hwq_map); int ath_htc_txq_update(struct ath9k_htc_priv *priv, int qnum, struct ath9k_tx_queue_info *qinfo); +void ath9k_htc_check_stop_queues(struct ath9k_htc_priv *priv); +void ath9k_htc_check_wake_queues(struct ath9k_htc_priv *priv); int ath9k_rx_init(struct ath9k_htc_priv *priv); void ath9k_rx_cleanup(struct ath9k_htc_priv *priv); diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c b/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c index 713def1..de37d46 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c @@ -326,6 +326,10 @@ static void ath9k_htc_send_buffered(struct ath9k_htc_priv *priv, ath_dbg(common, ATH_DBG_FATAL, "Failed to send CAB frame\n"); dev_kfree_skb_any(skb); + } else { + spin_lock_bh(&priv->tx.tx_lock); + priv->tx.queued_cnt++; + spin_unlock_bh(&priv->tx.tx_lock); } next: skb = ieee80211_get_buffered_bc(priv->hw, vif); diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_gpio.c b/drivers/net/wireless/ath/ath9k/htc_drv_gpio.c index 1f6df4a..92e4b31 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_gpio.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_gpio.c @@ -399,7 +399,7 @@ void ath9k_htc_radio_enable(struct ieee80211_hw *hw) /* Start TX */ htc_start(priv->htc); spin_lock_bh(&priv->tx.tx_lock); - priv->tx.tx_queues_stop = false; + priv->tx.flags &= ~ATH9K_HTC_OP_TX_QUEUES_STOP; spin_unlock_bh(&priv->tx.tx_lock); ieee80211_wake_queues(hw); diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_main.c b/drivers/net/wireless/ath/ath9k/htc_drv_main.c index ff3a495..6901136 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_main.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_main.c @@ -833,6 +833,7 @@ static void ath9k_htc_tx(struct ieee80211_hw *hw, struct sk_buff *skb) { struct ieee80211_hdr *hdr; struct ath9k_htc_priv *priv = hw->priv; + struct ath_common *common = ath9k_hw_common(priv->ah); int padpos, padsize, ret; hdr = (struct ieee80211_hdr *) skb->data; @@ -841,28 +842,22 @@ static void ath9k_htc_tx(struct ieee80211_hw *hw, struct sk_buff *skb) padpos = ath9k_cmn_padpos(hdr->frame_control); padsize = padpos & 3; if (padsize && skb->len > padpos) { - if (skb_headroom(skb) < padsize) + if (skb_headroom(skb) < padsize) { + ath_dbg(common, ATH_DBG_XMIT, "No room for padding\n"); goto fail_tx; + } skb_push(skb, padsize); memmove(skb->data, skb->data + padsize, padpos); } ret = ath9k_htc_tx_start(priv, skb, false); if (ret != 0) { - if (ret == -ENOMEM) { - ath_dbg(ath9k_hw_common(priv->ah), ATH_DBG_XMIT, - "Stopping TX queues\n"); - ieee80211_stop_queues(hw); - spin_lock_bh(&priv->tx.tx_lock); - priv->tx.tx_queues_stop = true; - spin_unlock_bh(&priv->tx.tx_lock); - } else { - ath_dbg(ath9k_hw_common(priv->ah), ATH_DBG_XMIT, - "Tx failed\n"); - } + ath_dbg(common, ATH_DBG_XMIT, "Tx failed\n"); goto fail_tx; } + ath9k_htc_check_stop_queues(priv); + return; fail_tx: @@ -924,7 +919,7 @@ static int ath9k_htc_start(struct ieee80211_hw *hw) htc_start(priv->htc); spin_lock_bh(&priv->tx.tx_lock); - priv->tx.tx_queues_stop = false; + priv->tx.flags &= ~ATH9K_HTC_OP_TX_QUEUES_STOP; spin_unlock_bh(&priv->tx.tx_lock); ieee80211_wake_queues(hw); diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c b/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c index 6f7987d..1cbe194 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c @@ -53,6 +53,29 @@ int get_hw_qnum(u16 queue, int *hwq_map) } } +void ath9k_htc_check_stop_queues(struct ath9k_htc_priv *priv) +{ + spin_lock_bh(&priv->tx.tx_lock); + priv->tx.queued_cnt++; + if ((priv->tx.queued_cnt >= ATH9K_HTC_TX_THRESHOLD) && + !(priv->tx.flags & ATH9K_HTC_OP_TX_QUEUES_STOP)) { + priv->tx.flags |= ATH9K_HTC_OP_TX_QUEUES_STOP; + ieee80211_stop_queues(priv->hw); + } + spin_unlock_bh(&priv->tx.tx_lock); +} + +void ath9k_htc_check_wake_queues(struct ath9k_htc_priv *priv) +{ + spin_lock_bh(&priv->tx.tx_lock); + if ((priv->tx.queued_cnt < ATH9K_HTC_TX_THRESHOLD) && + (priv->tx.flags & ATH9K_HTC_OP_TX_QUEUES_STOP)) { + priv->tx.flags &= ~ATH9K_HTC_OP_TX_QUEUES_STOP; + ieee80211_wake_queues(priv->hw); + } + spin_unlock_bh(&priv->tx.tx_lock); +} + int ath_htc_txq_update(struct ath9k_htc_priv *priv, int qnum, struct ath9k_tx_queue_info *qinfo) { @@ -302,21 +325,17 @@ void ath9k_tx_tasklet(unsigned long data) rcu_read_unlock(); send_mac80211: + spin_lock_bh(&priv->tx.tx_lock); + if (WARN_ON(--priv->tx.queued_cnt < 0)) + priv->tx.queued_cnt = 0; + spin_unlock_bh(&priv->tx.tx_lock); + /* Send status to mac80211 */ ieee80211_tx_status(priv->hw, skb); } /* Wake TX queues if needed */ - spin_lock_bh(&priv->tx.tx_lock); - if (priv->tx.tx_queues_stop) { - priv->tx.tx_queues_stop = false; - spin_unlock_bh(&priv->tx.tx_lock); - ath_dbg(ath9k_hw_common(priv->ah), ATH_DBG_XMIT, - "Waking up TX queues\n"); - ieee80211_wake_queues(priv->hw); - return; - } - spin_unlock_bh(&priv->tx.tx_lock); + ath9k_htc_check_wake_queues(priv); } void ath9k_htc_txep(void *drv_priv, struct sk_buff *skb, -- cgit v0.10.2 From d67ee5339363608adce786ec8fd62a0fb2b66116 Mon Sep 17 00:00:00 2001 From: Sujith Manoharan Date: Wed, 13 Apr 2011 11:25:35 +0530 Subject: ath9k_htc: Introduce new HTC API A new routine that takes an endpoint explicitly is introduced. The normal htc_send() now retrieves the endpoint from the packet's private data. This would be useful in TX completion when the endpoint ID would be required. While at it, use a helper function to map the queue to endpoint. Data/mgmt/beacon packets use htc_send(), while WMI comamnds pass the endpoint to HTC. Signed-off-by: Sujith Manoharan Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/htc.h b/drivers/net/wireless/ath/ath9k/htc.h index fc4c466..356f49c 100644 --- a/drivers/net/wireless/ath/ath9k/htc.h +++ b/drivers/net/wireless/ath/ath9k/htc.h @@ -276,6 +276,7 @@ struct ath9k_htc_tx { struct ath9k_htc_tx_ctl { u8 type; /* ATH9K_HTC_* */ + u8 epid; }; static inline struct ath9k_htc_tx_ctl *HTC_SKB_CB(struct sk_buff *skb) diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c b/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c index de37d46..97b116f 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c @@ -391,12 +391,13 @@ static void ath9k_htc_send_beacon(struct ath9k_htc_priv *priv, memset(tx_ctl, 0, sizeof(*tx_ctl)); tx_ctl->type = ATH9K_HTC_BEACON; + tx_ctl->epid = priv->beacon_ep; beacon_hdr.vif_index = avp->index; tx_fhdr = skb_push(beacon, sizeof(beacon_hdr)); memcpy(tx_fhdr, (u8 *) &beacon_hdr, sizeof(beacon_hdr)); - ret = htc_send(priv->htc, beacon, priv->beacon_ep); + ret = htc_send(priv->htc, beacon); if (ret != 0) { if (ret == -ENOMEM) { ath_dbg(common, ATH_DBG_BSTUCK, diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c b/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c index 1cbe194..d17662f 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c @@ -76,6 +76,34 @@ void ath9k_htc_check_wake_queues(struct ath9k_htc_priv *priv) spin_unlock_bh(&priv->tx.tx_lock); } +static enum htc_endpoint_id get_htc_epid(struct ath9k_htc_priv *priv, + u16 qnum) +{ + enum htc_endpoint_id epid; + + switch (qnum) { + case 0: + TX_QSTAT_INC(WME_AC_VO); + epid = priv->data_vo_ep; + break; + case 1: + TX_QSTAT_INC(WME_AC_VI); + epid = priv->data_vi_ep; + break; + case 2: + TX_QSTAT_INC(WME_AC_BE); + epid = priv->data_be_ep; + break; + case 3: + default: + TX_QSTAT_INC(WME_AC_BK); + epid = priv->data_bk_ep; + break; + } + + return epid; +} + int ath_htc_txq_update(struct ath9k_htc_priv *priv, int qnum, struct ath9k_tx_queue_info *qinfo) { @@ -113,7 +141,6 @@ int ath9k_htc_tx_start(struct ath9k_htc_priv *priv, struct ath9k_htc_sta *ista; struct ath9k_htc_vif *avp = NULL; struct ath9k_htc_tx_ctl *tx_ctl; - enum htc_endpoint_id epid; u16 qnum; __le16 fc; u8 *tx_fhdr; @@ -197,31 +224,12 @@ int ath9k_htc_tx_start(struct ath9k_htc_priv *priv, if (is_cab) { CAB_STAT_INC; - epid = priv->cab_ep; + tx_ctl->epid = priv->cab_ep; goto send; } qnum = skb_get_queue_mapping(skb); - - switch (qnum) { - case 0: - TX_QSTAT_INC(WME_AC_VO); - epid = priv->data_vo_ep; - break; - case 1: - TX_QSTAT_INC(WME_AC_VI); - epid = priv->data_vi_ep; - break; - case 2: - TX_QSTAT_INC(WME_AC_BE); - epid = priv->data_be_ep; - break; - case 3: - default: - TX_QSTAT_INC(WME_AC_BK); - epid = priv->data_bk_ep; - break; - } + tx_ctl->epid = get_htc_epid(priv, qnum); } else { struct tx_mgmt_hdr mgmt_hdr; @@ -251,10 +259,10 @@ int ath9k_htc_tx_start(struct ath9k_htc_priv *priv, tx_fhdr = skb_push(skb, sizeof(mgmt_hdr)); memcpy(tx_fhdr, (u8 *) &mgmt_hdr, sizeof(mgmt_hdr)); - epid = priv->mgmt_ep; + tx_ctl->epid = priv->mgmt_ep; } send: - return htc_send(priv->htc, skb, epid); + return htc_send(priv->htc, skb); } static bool ath9k_htc_check_tx_aggr(struct ath9k_htc_priv *priv, diff --git a/drivers/net/wireless/ath/ath9k/htc_hst.c b/drivers/net/wireless/ath/ath9k/htc_hst.c index 6ee53de..be87f47 100644 --- a/drivers/net/wireless/ath/ath9k/htc_hst.c +++ b/drivers/net/wireless/ath/ath9k/htc_hst.c @@ -286,8 +286,16 @@ err: return ret; } -int htc_send(struct htc_target *target, struct sk_buff *skb, - enum htc_endpoint_id epid) +int htc_send(struct htc_target *target, struct sk_buff *skb) +{ + struct ath9k_htc_tx_ctl *tx_ctl; + + tx_ctl = HTC_SKB_CB(skb); + return htc_issue_send(target, skb, skb->len, 0, tx_ctl->epid); +} + +int htc_send_epid(struct htc_target *target, struct sk_buff *skb, + enum htc_endpoint_id epid) { return htc_issue_send(target, skb, skb->len, 0, epid); } diff --git a/drivers/net/wireless/ath/ath9k/htc_hst.h b/drivers/net/wireless/ath/ath9k/htc_hst.h index 3531552..064a324 100644 --- a/drivers/net/wireless/ath/ath9k/htc_hst.h +++ b/drivers/net/wireless/ath/ath9k/htc_hst.h @@ -204,8 +204,9 @@ int htc_init(struct htc_target *target); int htc_connect_service(struct htc_target *target, struct htc_service_connreq *service_connreq, enum htc_endpoint_id *conn_rsp_eid); -int htc_send(struct htc_target *target, struct sk_buff *skb, - enum htc_endpoint_id eid); +int htc_send(struct htc_target *target, struct sk_buff *skb); +int htc_send_epid(struct htc_target *target, struct sk_buff *skb, + enum htc_endpoint_id epid); void htc_stop(struct htc_target *target); void htc_start(struct htc_target *target); diff --git a/drivers/net/wireless/ath/ath9k/wmi.c b/drivers/net/wireless/ath/ath9k/wmi.c index 83d1e0e..e66f6c3 100644 --- a/drivers/net/wireless/ath/ath9k/wmi.c +++ b/drivers/net/wireless/ath/ath9k/wmi.c @@ -267,7 +267,7 @@ static int ath9k_wmi_cmd_issue(struct wmi *wmi, hdr->command_id = cpu_to_be16(cmd); hdr->seq_no = cpu_to_be16(++wmi->tx_seq_id); - return htc_send(wmi->htc, skb, wmi->ctrl_epid); + return htc_send_epid(wmi->htc, skb, wmi->ctrl_epid); } int ath9k_wmi_cmd(struct wmi *wmi, enum wmi_cmd_id cmd_id, -- cgit v0.10.2 From 729bd3ab460d3bb8236cc8f6fd0289201124112d Mon Sep 17 00:00:00 2001 From: Sujith Manoharan Date: Wed, 13 Apr 2011 11:25:41 +0530 Subject: ath9k_htc: Move endpoint header parsing to TX tasklet There is no need to do endpoint header removal in the ISR. Also, this is needed when TX slot management is added later on. Use a helper function to strip the driver header. Signed-off-by: Sujith Manoharan Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/htc.h b/drivers/net/wireless/ath/ath9k/htc.h index 356f49c..0831ca3 100644 --- a/drivers/net/wireless/ath/ath9k/htc.h +++ b/drivers/net/wireless/ath/ath9k/htc.h @@ -277,6 +277,7 @@ struct ath9k_htc_tx { struct ath9k_htc_tx_ctl { u8 type; /* ATH9K_HTC_* */ u8 epid; + u8 txok; }; static inline struct ath9k_htc_tx_ctl *HTC_SKB_CB(struct sk_buff *skb) diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c b/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c index d17662f..7b218da 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c @@ -104,6 +104,30 @@ static enum htc_endpoint_id get_htc_epid(struct ath9k_htc_priv *priv, return epid; } +static inline int strip_drv_header(struct ath9k_htc_priv *priv, + struct sk_buff *skb) +{ + struct ath_common *common = ath9k_hw_common(priv->ah); + struct ath9k_htc_tx_ctl *tx_ctl; + + tx_ctl = HTC_SKB_CB(skb); + + if (tx_ctl->epid == priv->mgmt_ep) { + skb_pull(skb, sizeof(struct tx_mgmt_hdr)); + } else if ((tx_ctl->epid == priv->data_bk_ep) || + (tx_ctl->epid == priv->data_be_ep) || + (tx_ctl->epid == priv->data_vi_ep) || + (tx_ctl->epid == priv->data_vo_ep) || + (tx_ctl->epid == priv->cab_ep)) { + skb_pull(skb, sizeof(struct tx_frame_hdr)); + } else { + ath_err(common, "Unsupported EPID: %d\n", tx_ctl->epid); + return -EINVAL; + } + + return 0; +} + int ath_htc_txq_update(struct ath9k_htc_priv *priv, int qnum, struct ath9k_tx_queue_info *qinfo) { @@ -281,22 +305,40 @@ static bool ath9k_htc_check_tx_aggr(struct ath9k_htc_priv *priv, void ath9k_tx_tasklet(unsigned long data) { struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *)data; + struct ath9k_htc_tx_ctl *tx_ctl; struct ieee80211_vif *vif; struct ieee80211_sta *sta; struct ieee80211_hdr *hdr; struct ieee80211_tx_info *tx_info; struct sk_buff *skb = NULL; __le16 fc; + bool txok; while ((skb = skb_dequeue(&priv->tx.tx_queue)) != NULL) { + if (strip_drv_header(priv, skb) < 0) { + dev_kfree_skb_any(skb); + continue; + } + + tx_ctl = HTC_SKB_CB(skb); hdr = (struct ieee80211_hdr *) skb->data; fc = hdr->frame_control; tx_info = IEEE80211_SKB_CB(skb); vif = tx_info->control.vif; + txok = tx_ctl->txok; memset(&tx_info->status, 0, sizeof(tx_info->status)); + /* + * URB submission failed for this frame, it never reached + * the target. + */ + if (!txok) + goto send_mac80211; + + tx_info->flags |= IEEE80211_TX_STAT_ACK; + if (!vif) goto send_mac80211; @@ -350,30 +392,10 @@ void ath9k_htc_txep(void *drv_priv, struct sk_buff *skb, enum htc_endpoint_id ep_id, bool txok) { struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *) drv_priv; - struct ath_common *common = ath9k_hw_common(priv->ah); - struct ieee80211_tx_info *tx_info; - - if (!skb) - return; - - if (ep_id == priv->mgmt_ep) { - skb_pull(skb, sizeof(struct tx_mgmt_hdr)); - } else if ((ep_id == priv->data_bk_ep) || - (ep_id == priv->data_be_ep) || - (ep_id == priv->data_vi_ep) || - (ep_id == priv->data_vo_ep) || - (ep_id == priv->cab_ep)) { - skb_pull(skb, sizeof(struct tx_frame_hdr)); - } else { - ath_err(common, "Unsupported TX EPID: %d\n", ep_id); - dev_kfree_skb_any(skb); - return; - } - - tx_info = IEEE80211_SKB_CB(skb); + struct ath9k_htc_tx_ctl *tx_ctl; - if (txok) - tx_info->flags |= IEEE80211_TX_STAT_ACK; + tx_ctl = HTC_SKB_CB(skb); + tx_ctl->txok = txok; skb_queue_tail(&priv->tx.tx_queue, skb); tasklet_schedule(&priv->tx_tasklet); -- cgit v0.10.2 From 2c5d57f004673a9c8658e20b1fa3f992b5a10f70 Mon Sep 17 00:00:00 2001 From: Sujith Manoharan Date: Wed, 13 Apr 2011 11:25:47 +0530 Subject: ath9k_htc: Add TX slots Maintain a bitmap of slots for transmission and update the cookie field for every packet with the slot value. This value would be used for matching packets when TX completion processing is added. Signed-off-by: Sujith Manoharan Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/htc.h b/drivers/net/wireless/ath/ath9k/htc.h index 0831ca3..45cf755 100644 --- a/drivers/net/wireless/ath/ath9k/htc.h +++ b/drivers/net/wireless/ath/ath9k/htc.h @@ -271,6 +271,7 @@ struct ath9k_htc_tx { u8 flags; int queued_cnt; struct sk_buff_head tx_queue; + DECLARE_BITMAP(tx_slot, MAX_TX_BUF_NUM); spinlock_t tx_lock; }; @@ -532,7 +533,7 @@ void ath9k_htc_stop_ani(struct ath9k_htc_priv *priv); int ath9k_tx_init(struct ath9k_htc_priv *priv); void ath9k_tx_tasklet(unsigned long data); int ath9k_htc_tx_start(struct ath9k_htc_priv *priv, - struct sk_buff *skb, bool is_cab); + struct sk_buff *skb, u8 slot, bool is_cab); void ath9k_tx_cleanup(struct ath9k_htc_priv *priv); bool ath9k_htc_txq_setup(struct ath9k_htc_priv *priv, int subtype); int ath9k_htc_cabq_setup(struct ath9k_htc_priv *priv); @@ -541,6 +542,8 @@ int ath_htc_txq_update(struct ath9k_htc_priv *priv, int qnum, struct ath9k_tx_queue_info *qinfo); void ath9k_htc_check_stop_queues(struct ath9k_htc_priv *priv); void ath9k_htc_check_wake_queues(struct ath9k_htc_priv *priv); +int ath9k_htc_tx_get_slot(struct ath9k_htc_priv *priv); +void ath9k_htc_tx_clear_slot(struct ath9k_htc_priv *priv, int slot); int ath9k_rx_init(struct ath9k_htc_priv *priv); void ath9k_rx_cleanup(struct ath9k_htc_priv *priv); diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c b/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c index 97b116f..bf7ef1b 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c @@ -299,7 +299,7 @@ static void ath9k_htc_send_buffered(struct ath9k_htc_priv *priv, struct ieee80211_vif *vif; struct sk_buff *skb; struct ieee80211_hdr *hdr; - int padpos, padsize, ret; + int padpos, padsize, ret, tx_slot; spin_lock_bh(&priv->beacon_lock); @@ -321,11 +321,20 @@ static void ath9k_htc_send_buffered(struct ath9k_htc_priv *priv, memmove(skb->data, skb->data + padsize, padpos); } - ret = ath9k_htc_tx_start(priv, skb, true); + tx_slot = ath9k_htc_tx_get_slot(priv); + if (tx_slot != 0) { + ath_dbg(common, ATH_DBG_XMIT, "No free CAB slot\n"); + dev_kfree_skb_any(skb); + goto next; + } + + ret = ath9k_htc_tx_start(priv, skb, tx_slot, true); if (ret != 0) { - ath_dbg(common, ATH_DBG_FATAL, - "Failed to send CAB frame\n"); + ath9k_htc_tx_clear_slot(priv, tx_slot); dev_kfree_skb_any(skb); + + ath_dbg(common, ATH_DBG_XMIT, + "Failed to send CAB frame\n"); } else { spin_lock_bh(&priv->tx.tx_lock); priv->tx.queued_cnt++; diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_main.c b/drivers/net/wireless/ath/ath9k/htc_drv_main.c index 6901136..c7e056b 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_main.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_main.c @@ -834,7 +834,7 @@ static void ath9k_htc_tx(struct ieee80211_hw *hw, struct sk_buff *skb) struct ieee80211_hdr *hdr; struct ath9k_htc_priv *priv = hw->priv; struct ath_common *common = ath9k_hw_common(priv->ah); - int padpos, padsize, ret; + int padpos, padsize, ret, slot; hdr = (struct ieee80211_hdr *) skb->data; @@ -850,16 +850,24 @@ static void ath9k_htc_tx(struct ieee80211_hw *hw, struct sk_buff *skb) memmove(skb->data, skb->data + padsize, padpos); } - ret = ath9k_htc_tx_start(priv, skb, false); + slot = ath9k_htc_tx_get_slot(priv); + if (slot < 0) { + ath_dbg(common, ATH_DBG_XMIT, "No free TX slot\n"); + goto fail_tx; + } + + ret = ath9k_htc_tx_start(priv, skb, slot, false); if (ret != 0) { ath_dbg(common, ATH_DBG_XMIT, "Tx failed\n"); - goto fail_tx; + goto clear_slot; } ath9k_htc_check_stop_queues(priv); return; +clear_slot: + ath9k_htc_tx_clear_slot(priv, slot); fail_tx: dev_kfree_skb_any(skb); } diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c b/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c index 7b218da..ee5b3e2 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c @@ -76,6 +76,29 @@ void ath9k_htc_check_wake_queues(struct ath9k_htc_priv *priv) spin_unlock_bh(&priv->tx.tx_lock); } +int ath9k_htc_tx_get_slot(struct ath9k_htc_priv *priv) +{ + int slot; + + spin_lock_bh(&priv->tx.tx_lock); + slot = find_first_zero_bit(priv->tx.tx_slot, MAX_TX_BUF_NUM); + if (slot >= MAX_TX_BUF_NUM) { + spin_unlock_bh(&priv->tx.tx_lock); + return -ENOBUFS; + } + __set_bit(slot, priv->tx.tx_slot); + spin_unlock_bh(&priv->tx.tx_lock); + + return slot; +} + +void ath9k_htc_tx_clear_slot(struct ath9k_htc_priv *priv, int slot) +{ + spin_lock_bh(&priv->tx.tx_lock); + __clear_bit(slot, priv->tx.tx_slot); + spin_unlock_bh(&priv->tx.tx_lock); +} + static enum htc_endpoint_id get_htc_epid(struct ath9k_htc_priv *priv, u16 qnum) { @@ -104,28 +127,38 @@ static enum htc_endpoint_id get_htc_epid(struct ath9k_htc_priv *priv, return epid; } +/* + * Removes the driver header and returns the TX slot number + */ static inline int strip_drv_header(struct ath9k_htc_priv *priv, struct sk_buff *skb) { struct ath_common *common = ath9k_hw_common(priv->ah); struct ath9k_htc_tx_ctl *tx_ctl; + int slot; tx_ctl = HTC_SKB_CB(skb); if (tx_ctl->epid == priv->mgmt_ep) { + struct tx_mgmt_hdr *tx_mhdr = + (struct tx_mgmt_hdr *)skb->data; + slot = tx_mhdr->cookie; skb_pull(skb, sizeof(struct tx_mgmt_hdr)); } else if ((tx_ctl->epid == priv->data_bk_ep) || (tx_ctl->epid == priv->data_be_ep) || (tx_ctl->epid == priv->data_vi_ep) || (tx_ctl->epid == priv->data_vo_ep) || (tx_ctl->epid == priv->cab_ep)) { + struct tx_frame_hdr *tx_fhdr = + (struct tx_frame_hdr *)skb->data; + slot = tx_fhdr->cookie; skb_pull(skb, sizeof(struct tx_frame_hdr)); } else { ath_err(common, "Unsupported EPID: %d\n", tx_ctl->epid); - return -EINVAL; + slot = -EINVAL; } - return 0; + return slot; } int ath_htc_txq_update(struct ath9k_htc_priv *priv, int qnum, @@ -155,7 +188,8 @@ int ath_htc_txq_update(struct ath9k_htc_priv *priv, int qnum, } int ath9k_htc_tx_start(struct ath9k_htc_priv *priv, - struct sk_buff *skb, bool is_cab) + struct sk_buff *skb, + u8 slot, bool is_cab) { struct ieee80211_hdr *hdr; struct ieee80211_mgmt *mgmt; @@ -212,6 +246,7 @@ int ath9k_htc_tx_start(struct ath9k_htc_priv *priv, tx_hdr.node_idx = sta_idx; tx_hdr.vif_idx = vif_idx; + tx_hdr.cookie = slot; if (tx_info->flags & IEEE80211_TX_CTL_AMPDU) { tx_ctl->type = ATH9K_HTC_AMPDU; @@ -274,6 +309,7 @@ int ath9k_htc_tx_start(struct ath9k_htc_priv *priv, mgmt_hdr.vif_idx = vif_idx; mgmt_hdr.tidno = 0; mgmt_hdr.flags = 0; + mgmt_hdr.cookie = slot; mgmt_hdr.key_type = ath9k_cmn_get_hw_crypto_keytype(skb); if (mgmt_hdr.key_type == ATH9K_KEY_TYPE_CLEAR) @@ -313,10 +349,12 @@ void ath9k_tx_tasklet(unsigned long data) struct sk_buff *skb = NULL; __le16 fc; bool txok; + int slot; while ((skb = skb_dequeue(&priv->tx.tx_queue)) != NULL) { - if (strip_drv_header(priv, skb) < 0) { + slot = strip_drv_header(priv, skb); + if (slot < 0) { dev_kfree_skb_any(skb); continue; } @@ -347,8 +385,7 @@ void ath9k_tx_tasklet(unsigned long data) sta = ieee80211_find_sta(vif, hdr->addr1); if (!sta) { rcu_read_unlock(); - ieee80211_tx_status(priv->hw, skb); - continue; + goto send_mac80211; } /* Check if we need to start aggregation */ @@ -380,6 +417,8 @@ void ath9k_tx_tasklet(unsigned long data) priv->tx.queued_cnt = 0; spin_unlock_bh(&priv->tx.tx_lock); + ath9k_htc_tx_clear_slot(priv, slot); + /* Send status to mac80211 */ ieee80211_tx_status(priv->hw, skb); } -- cgit v0.10.2 From f2820f4583b233827f10d91adea70225e196d852 Mon Sep 17 00:00:00 2001 From: Sujith Manoharan Date: Wed, 13 Apr 2011 11:25:54 +0530 Subject: ath9k_htc: Use helper functions for TX processing Signed-off-by: Sujith Manoharan Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c b/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c index ee5b3e2..944440c 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c @@ -325,8 +325,8 @@ send: return htc_send(priv->htc, skb); } -static bool ath9k_htc_check_tx_aggr(struct ath9k_htc_priv *priv, - struct ath9k_htc_sta *ista, u8 tid) +static inline bool __ath9k_htc_check_tx_aggr(struct ath9k_htc_priv *priv, + struct ath9k_htc_sta *ista, u8 tid) { bool ret = false; @@ -338,89 +338,98 @@ static bool ath9k_htc_check_tx_aggr(struct ath9k_htc_priv *priv, return ret; } -void ath9k_tx_tasklet(unsigned long data) +static void ath9k_htc_check_tx_aggr(struct ath9k_htc_priv *priv, + struct ieee80211_vif *vif, + struct sk_buff *skb) { - struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *)data; - struct ath9k_htc_tx_ctl *tx_ctl; - struct ieee80211_vif *vif; struct ieee80211_sta *sta; struct ieee80211_hdr *hdr; - struct ieee80211_tx_info *tx_info; - struct sk_buff *skb = NULL; __le16 fc; - bool txok; - int slot; - while ((skb = skb_dequeue(&priv->tx.tx_queue)) != NULL) { + hdr = (struct ieee80211_hdr *) skb->data; + fc = hdr->frame_control; - slot = strip_drv_header(priv, skb); - if (slot < 0) { - dev_kfree_skb_any(skb); - continue; - } + rcu_read_lock(); - tx_ctl = HTC_SKB_CB(skb); - hdr = (struct ieee80211_hdr *) skb->data; - fc = hdr->frame_control; - tx_info = IEEE80211_SKB_CB(skb); - vif = tx_info->control.vif; - txok = tx_ctl->txok; + sta = ieee80211_find_sta(vif, hdr->addr1); + if (!sta) { + rcu_read_unlock(); + return; + } - memset(&tx_info->status, 0, sizeof(tx_info->status)); + if (sta && conf_is_ht(&priv->hw->conf) && + !(skb->protocol == cpu_to_be16(ETH_P_PAE))) { + if (ieee80211_is_data_qos(fc)) { + u8 *qc, tid; + struct ath9k_htc_sta *ista; - /* - * URB submission failed for this frame, it never reached - * the target. - */ - if (!txok) - goto send_mac80211; + qc = ieee80211_get_qos_ctl(hdr); + tid = qc[0] & 0xf; + ista = (struct ath9k_htc_sta *)sta->drv_priv; + if (__ath9k_htc_check_tx_aggr(priv, ista, tid)) { + ieee80211_start_tx_ba_session(sta, tid, 0); + spin_lock_bh(&priv->tx.tx_lock); + ista->tid_state[tid] = AGGR_PROGRESS; + spin_unlock_bh(&priv->tx.tx_lock); + } + } + } - tx_info->flags |= IEEE80211_TX_STAT_ACK; + rcu_read_unlock(); +} - if (!vif) - goto send_mac80211; +static void ath9k_htc_tx_process(struct ath9k_htc_priv *priv, + struct sk_buff *skb) +{ + struct ieee80211_vif *vif; + struct ath9k_htc_tx_ctl *tx_ctl; + struct ieee80211_tx_info *tx_info; + bool txok; + int slot; - rcu_read_lock(); + slot = strip_drv_header(priv, skb); + if (slot < 0) { + dev_kfree_skb_any(skb); + return; + } - sta = ieee80211_find_sta(vif, hdr->addr1); - if (!sta) { - rcu_read_unlock(); - goto send_mac80211; - } + tx_ctl = HTC_SKB_CB(skb); + txok = tx_ctl->txok; + tx_info = IEEE80211_SKB_CB(skb); + vif = tx_info->control.vif; - /* Check if we need to start aggregation */ + memset(&tx_info->status, 0, sizeof(tx_info->status)); - if (sta && conf_is_ht(&priv->hw->conf) && - !(skb->protocol == cpu_to_be16(ETH_P_PAE))) { - if (ieee80211_is_data_qos(fc)) { - u8 *qc, tid; - struct ath9k_htc_sta *ista; + /* + * URB submission failed for this frame, it never reached + * the target. + */ + if (!txok || !vif) + goto send_mac80211; - qc = ieee80211_get_qos_ctl(hdr); - tid = qc[0] & 0xf; - ista = (struct ath9k_htc_sta *)sta->drv_priv; + tx_info->flags |= IEEE80211_TX_STAT_ACK; - if (ath9k_htc_check_tx_aggr(priv, ista, tid)) { - ieee80211_start_tx_ba_session(sta, tid, 0); - spin_lock_bh(&priv->tx.tx_lock); - ista->tid_state[tid] = AGGR_PROGRESS; - spin_unlock_bh(&priv->tx.tx_lock); - } - } - } + ath9k_htc_check_tx_aggr(priv, vif, skb); - rcu_read_unlock(); +send_mac80211: + spin_lock_bh(&priv->tx.tx_lock); + if (WARN_ON(--priv->tx.queued_cnt < 0)) + priv->tx.queued_cnt = 0; + spin_unlock_bh(&priv->tx.tx_lock); - send_mac80211: - spin_lock_bh(&priv->tx.tx_lock); - if (WARN_ON(--priv->tx.queued_cnt < 0)) - priv->tx.queued_cnt = 0; - spin_unlock_bh(&priv->tx.tx_lock); + ath9k_htc_tx_clear_slot(priv, slot); + + /* Send status to mac80211 */ + ieee80211_tx_status(priv->hw, skb); +} - ath9k_htc_tx_clear_slot(priv, slot); +void ath9k_tx_tasklet(unsigned long data) +{ + struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *)data; + struct sk_buff *skb = NULL; - /* Send status to mac80211 */ - ieee80211_tx_status(priv->hw, skb); + while ((skb = skb_dequeue(&priv->tx.tx_queue)) != NULL) { + ath9k_htc_tx_process(priv, skb); } /* Wake TX queues if needed */ -- cgit v0.10.2 From b587fc81a80b9656f64e89fe0a106ffa4b35abca Mon Sep 17 00:00:00 2001 From: Sujith Manoharan Date: Wed, 13 Apr 2011 11:25:59 +0530 Subject: ath9k_htc: Drain pending TX frames properly When doing a channel set or a reset operation the pending frames queued up for transmission have to be flushed and sent to mac80211. Fixing this has to be done in two separate steps: * Flush queued frames and kill the URB TX completion handler. * Complete all the frames that in the TX pending queue. This patch adds proper support for draining and all the callsites namely, channel change/reset/idle/stop are fixed. A separate queue is used for handling failed frames. Signed-off-by: Sujith Manoharan Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/hif_usb.c b/drivers/net/wireless/ath/ath9k/hif_usb.c index 0b63a48..db07e7b 100644 --- a/drivers/net/wireless/ath/ath9k/hif_usb.c +++ b/drivers/net/wireless/ath/ath9k/hif_usb.c @@ -131,7 +131,19 @@ static inline void ath9k_skb_queue_purge(struct hif_device_usb *hif_dev, while ((skb = __skb_dequeue(list)) != NULL) { dev_kfree_skb_any(skb); - TX_STAT_INC(skb_dropped); + } +} + +static inline void ath9k_skb_queue_complete(struct hif_device_usb *hif_dev, + struct sk_buff_head *queue, + bool txok) +{ + struct sk_buff *skb; + + while ((skb = __skb_dequeue(queue)) != NULL) { + ath9k_htc_txcompletion_cb(hif_dev->htc_handle, + skb, txok); + (txok) ? TX_STAT_INC(skb_success) : TX_STAT_INC(skb_failed); } } @@ -139,7 +151,7 @@ static void hif_usb_tx_cb(struct urb *urb) { struct tx_buf *tx_buf = (struct tx_buf *) urb->context; struct hif_device_usb *hif_dev; - struct sk_buff *skb; + bool txok = true; if (!tx_buf || !tx_buf->hif_dev) return; @@ -153,10 +165,7 @@ static void hif_usb_tx_cb(struct urb *urb) case -ECONNRESET: case -ENODEV: case -ESHUTDOWN: - /* - * The URB has been killed, free the SKBs. - */ - ath9k_skb_queue_purge(hif_dev, &tx_buf->skb_queue); + txok = false; /* * If the URBs are being flushed, no need to add this @@ -165,41 +174,19 @@ static void hif_usb_tx_cb(struct urb *urb) spin_lock(&hif_dev->tx.tx_lock); if (hif_dev->tx.flags & HIF_USB_TX_FLUSH) { spin_unlock(&hif_dev->tx.tx_lock); + ath9k_skb_queue_purge(hif_dev, &tx_buf->skb_queue); return; } spin_unlock(&hif_dev->tx.tx_lock); - /* - * In the stop() case, this URB has to be added to - * the free list. - */ - goto add_free; + break; default: + txok = false; break; } - /* - * Check if TX has been stopped, this is needed because - * this CB could have been invoked just after the TX lock - * was released in hif_stop() and kill_urb() hasn't been - * called yet. - */ - spin_lock(&hif_dev->tx.tx_lock); - if (hif_dev->tx.flags & HIF_USB_TX_STOP) { - spin_unlock(&hif_dev->tx.tx_lock); - ath9k_skb_queue_purge(hif_dev, &tx_buf->skb_queue); - goto add_free; - } - spin_unlock(&hif_dev->tx.tx_lock); - - /* Complete the queued SKBs. */ - while ((skb = __skb_dequeue(&tx_buf->skb_queue)) != NULL) { - ath9k_htc_txcompletion_cb(hif_dev->htc_handle, - skb, 1); - TX_STAT_INC(skb_completed); - } + ath9k_skb_queue_complete(hif_dev, &tx_buf->skb_queue, txok); -add_free: /* Re-initialize the SKB queue */ tx_buf->len = tx_buf->offset = 0; __skb_queue_head_init(&tx_buf->skb_queue); @@ -272,7 +259,7 @@ static int __hif_usb_tx(struct hif_device_usb *hif_dev) ret = usb_submit_urb(tx_buf->urb, GFP_ATOMIC); if (ret) { tx_buf->len = tx_buf->offset = 0; - ath9k_skb_queue_purge(hif_dev, &tx_buf->skb_queue); + ath9k_skb_queue_complete(hif_dev, &tx_buf->skb_queue, false); __skb_queue_head_init(&tx_buf->skb_queue); list_move_tail(&tx_buf->list, &hif_dev->tx.tx_buf); hif_dev->tx.tx_buf_cnt++; @@ -342,7 +329,7 @@ static void hif_usb_stop(void *hif_handle, u8 pipe_id) unsigned long flags; spin_lock_irqsave(&hif_dev->tx.tx_lock, flags); - ath9k_skb_queue_purge(hif_dev, &hif_dev->tx.tx_skb_queue); + ath9k_skb_queue_complete(hif_dev, &hif_dev->tx.tx_skb_queue, false); hif_dev->tx.tx_skb_cnt = 0; hif_dev->tx.flags |= HIF_USB_TX_STOP; spin_unlock_irqrestore(&hif_dev->tx.tx_lock, flags); diff --git a/drivers/net/wireless/ath/ath9k/htc.h b/drivers/net/wireless/ath/ath9k/htc.h index 45cf755..0d2e2b1 100644 --- a/drivers/net/wireless/ath/ath9k/htc.h +++ b/drivers/net/wireless/ath/ath9k/htc.h @@ -271,6 +271,7 @@ struct ath9k_htc_tx { u8 flags; int queued_cnt; struct sk_buff_head tx_queue; + struct sk_buff_head tx_failed; DECLARE_BITMAP(tx_slot, MAX_TX_BUF_NUM); spinlock_t tx_lock; }; @@ -305,8 +306,8 @@ struct ath_tx_stats { u32 buf_queued; u32 buf_completed; u32 skb_queued; - u32 skb_completed; - u32 skb_dropped; + u32 skb_success; + u32 skb_failed; u32 cab_queued; u32 queue_stats[WME_NUM_AC]; }; @@ -544,6 +545,7 @@ void ath9k_htc_check_stop_queues(struct ath9k_htc_priv *priv); void ath9k_htc_check_wake_queues(struct ath9k_htc_priv *priv); int ath9k_htc_tx_get_slot(struct ath9k_htc_priv *priv); void ath9k_htc_tx_clear_slot(struct ath9k_htc_priv *priv, int slot); +void ath9k_htc_tx_drain(struct ath9k_htc_priv *priv); int ath9k_rx_init(struct ath9k_htc_priv *priv); void ath9k_rx_cleanup(struct ath9k_htc_priv *priv); diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_debug.c b/drivers/net/wireless/ath/ath9k/htc_drv_debug.c index 6fc6cb7..91a486c 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_debug.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_debug.c @@ -88,11 +88,11 @@ static ssize_t read_file_xmit(struct file *file, char __user *user_buf, "%20s : %10u\n", "SKBs queued", priv->debug.tx_stats.skb_queued); len += snprintf(buf + len, sizeof(buf) - len, - "%20s : %10u\n", "SKBs completed", - priv->debug.tx_stats.skb_completed); + "%20s : %10u\n", "SKBs success", + priv->debug.tx_stats.skb_success); len += snprintf(buf + len, sizeof(buf) - len, - "%20s : %10u\n", "SKBs dropped", - priv->debug.tx_stats.skb_dropped); + "%20s : %10u\n", "SKBs failed", + priv->debug.tx_stats.skb_failed); len += snprintf(buf + len, sizeof(buf) - len, "%20s : %10u\n", "CAB queued", priv->debug.tx_stats.cab_queued); diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_gpio.c b/drivers/net/wireless/ath/ath9k/htc_drv_gpio.c index 92e4b31..dc0b33d 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_gpio.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_gpio.c @@ -429,9 +429,8 @@ void ath9k_htc_radio_disable(struct ieee80211_hw *hw) /* Stop TX */ ieee80211_stop_queues(hw); - htc_stop(priv->htc); + ath9k_htc_tx_drain(priv); WMI_CMD(WMI_DRAIN_TXQ_ALL_CMDID); - skb_queue_purge(&priv->tx.tx_queue); /* Stop RX */ WMI_CMD(WMI_STOP_RECV_CMDID); diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_main.c b/drivers/net/wireless/ath/ath9k/htc_drv_main.c index c7e056b..fb9ff11 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_main.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_main.c @@ -193,7 +193,9 @@ void ath9k_htc_reset(struct ath9k_htc_priv *priv) ath9k_htc_stop_ani(priv); ieee80211_stop_queues(priv->hw); - htc_stop(priv->htc); + + ath9k_htc_tx_drain(priv); + WMI_CMD(WMI_DISABLE_INTR_CMDID); WMI_CMD(WMI_DRAIN_TXQ_ALL_CMDID); WMI_CMD(WMI_STOP_RECV_CMDID); @@ -248,7 +250,9 @@ static int ath9k_htc_set_channel(struct ath9k_htc_priv *priv, fastcc = !!(hw->conf.flags & IEEE80211_CONF_OFFCHANNEL); ath9k_htc_ps_wakeup(priv); - htc_stop(priv->htc); + + ath9k_htc_tx_drain(priv); + WMI_CMD(WMI_DISABLE_INTR_CMDID); WMI_CMD(WMI_DRAIN_TXQ_ALL_CMDID); WMI_CMD(WMI_STOP_RECV_CMDID); @@ -263,6 +267,7 @@ static int ath9k_htc_set_channel(struct ath9k_htc_priv *priv, if (!fastcc) caldata = &priv->caldata; + ret = ath9k_hw_reset(ah, hchan, caldata, fastcc); if (ret) { ath_err(common, @@ -960,16 +965,14 @@ static void ath9k_htc_stop(struct ieee80211_hw *hw) } ath9k_htc_ps_wakeup(priv); - htc_stop(priv->htc); + WMI_CMD(WMI_DISABLE_INTR_CMDID); WMI_CMD(WMI_DRAIN_TXQ_ALL_CMDID); WMI_CMD(WMI_STOP_RECV_CMDID); tasklet_kill(&priv->rx_tasklet); - tasklet_kill(&priv->tx_tasklet); - - skb_queue_purge(&priv->tx.tx_queue); + ath9k_htc_tx_drain(priv); ath9k_wmi_event_drain(priv); mutex_unlock(&priv->mutex); diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c b/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c index 944440c..9e0c34b 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c @@ -423,6 +423,26 @@ send_mac80211: ieee80211_tx_status(priv->hw, skb); } +void ath9k_htc_tx_drain(struct ath9k_htc_priv *priv) +{ + struct sk_buff *skb = NULL; + + /* + * Ensure that all pending TX frames are flushed, + * and that the TX completion tasklet is killed. + */ + htc_stop(priv->htc); + tasklet_kill(&priv->tx_tasklet); + + while ((skb = skb_dequeue(&priv->tx.tx_queue)) != NULL) { + ath9k_htc_tx_process(priv, skb); + } + + while ((skb = skb_dequeue(&priv->tx.tx_failed)) != NULL) { + ath9k_htc_tx_process(priv, skb); + } +} + void ath9k_tx_tasklet(unsigned long data) { struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *)data; @@ -432,6 +452,10 @@ void ath9k_tx_tasklet(unsigned long data) ath9k_htc_tx_process(priv, skb); } + while ((skb = skb_dequeue(&priv->tx.tx_failed)) != NULL) { + ath9k_htc_tx_process(priv, skb); + } + /* Wake TX queues if needed */ ath9k_htc_check_wake_queues(priv); } @@ -445,13 +469,18 @@ void ath9k_htc_txep(void *drv_priv, struct sk_buff *skb, tx_ctl = HTC_SKB_CB(skb); tx_ctl->txok = txok; - skb_queue_tail(&priv->tx.tx_queue, skb); + if (txok) + skb_queue_tail(&priv->tx.tx_queue, skb); + else + skb_queue_tail(&priv->tx.tx_failed, skb); + tasklet_schedule(&priv->tx_tasklet); } int ath9k_tx_init(struct ath9k_htc_priv *priv) { skb_queue_head_init(&priv->tx.tx_queue); + skb_queue_head_init(&priv->tx.tx_failed); return 0; } -- cgit v0.10.2 From e1fe7c38d39f8f6ebdffc3a55e2ec6e2ec0d1872 Mon Sep 17 00:00:00 2001 From: Sujith Manoharan Date: Wed, 13 Apr 2011 11:26:06 +0530 Subject: ath9k_htc: Optimize HTC start/stop API There is no point in looping over all the endpoints, since the HIF layer uses the start/stop APIs only for the TX pipe. Simplify the API accordingly. Signed-off-by: Sujith Manoharan Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/hif_usb.c b/drivers/net/wireless/ath/ath9k/hif_usb.c index db07e7b..b3f23c2 100644 --- a/drivers/net/wireless/ath/ath9k/hif_usb.c +++ b/drivers/net/wireless/ath/ath9k/hif_usb.c @@ -310,7 +310,7 @@ static int hif_usb_send_tx(struct hif_device_usb *hif_dev, struct sk_buff *skb) return 0; } -static void hif_usb_start(void *hif_handle, u8 pipe_id) +static void hif_usb_start(void *hif_handle) { struct hif_device_usb *hif_dev = (struct hif_device_usb *)hif_handle; unsigned long flags; @@ -322,7 +322,7 @@ static void hif_usb_start(void *hif_handle, u8 pipe_id) spin_unlock_irqrestore(&hif_dev->tx.tx_lock, flags); } -static void hif_usb_stop(void *hif_handle, u8 pipe_id) +static void hif_usb_stop(void *hif_handle) { struct hif_device_usb *hif_dev = (struct hif_device_usb *)hif_handle; struct tx_buf *tx_buf = NULL, *tx_buf_tmp = NULL; diff --git a/drivers/net/wireless/ath/ath9k/htc_hst.c b/drivers/net/wireless/ath/ath9k/htc_hst.c index be87f47..7ced8ab 100644 --- a/drivers/net/wireless/ath/ath9k/htc_hst.c +++ b/drivers/net/wireless/ath/ath9k/htc_hst.c @@ -302,27 +302,12 @@ int htc_send_epid(struct htc_target *target, struct sk_buff *skb, void htc_stop(struct htc_target *target) { - enum htc_endpoint_id epid; - struct htc_endpoint *endpoint; - - for (epid = ENDPOINT0; epid < ENDPOINT_MAX; epid++) { - endpoint = &target->endpoint[epid]; - if (endpoint->service_id != 0) - target->hif->stop(target->hif_dev, endpoint->ul_pipeid); - } + target->hif->stop(target->hif_dev); } void htc_start(struct htc_target *target) { - enum htc_endpoint_id epid; - struct htc_endpoint *endpoint; - - for (epid = ENDPOINT0; epid < ENDPOINT_MAX; epid++) { - endpoint = &target->endpoint[epid]; - if (endpoint->service_id != 0) - target->hif->start(target->hif_dev, - endpoint->ul_pipeid); - } + target->hif->start(target->hif_dev); } void ath9k_htc_txcompletion_cb(struct htc_target *htc_handle, diff --git a/drivers/net/wireless/ath/ath9k/htc_hst.h b/drivers/net/wireless/ath/ath9k/htc_hst.h index 064a324..191e3c0 100644 --- a/drivers/net/wireless/ath/ath9k/htc_hst.h +++ b/drivers/net/wireless/ath/ath9k/htc_hst.h @@ -33,8 +33,8 @@ struct ath9k_htc_hif { u8 control_dl_pipe; u8 control_ul_pipe; - void (*start) (void *hif_handle, u8 pipe); - void (*stop) (void *hif_handle, u8 pipe); + void (*start) (void *hif_handle); + void (*stop) (void *hif_handle); int (*send) (void *hif_handle, u8 pipe, struct sk_buff *buf); }; -- cgit v0.10.2 From 84c9e164468bd707e52b440e1c34bc3c85299332 Mon Sep 17 00:00:00 2001 From: Sujith Manoharan Date: Wed, 13 Apr 2011 11:26:11 +0530 Subject: ath9k_htc: Drain packets on station removal When a station entry is removed, there could still be pending packets destined for that station in the HIF layer. Sending these to the target is not necessary, so drain them in the driver itself. Signed-off-by: Sujith Manoharan Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/hif_usb.c b/drivers/net/wireless/ath/ath9k/hif_usb.c index b3f23c2..7fae79d 100644 --- a/drivers/net/wireless/ath/ath9k/hif_usb.c +++ b/drivers/net/wireless/ath/ath9k/hif_usb.c @@ -363,6 +363,40 @@ static int hif_usb_send(void *hif_handle, u8 pipe_id, struct sk_buff *skb) return ret; } +static inline bool check_index(struct sk_buff *skb, u8 idx) +{ + struct ath9k_htc_tx_ctl *tx_ctl; + + tx_ctl = HTC_SKB_CB(skb); + + if ((tx_ctl->type == ATH9K_HTC_AMPDU) && + (tx_ctl->sta_idx == idx)) + return true; + + return false; +} + +static void hif_usb_sta_drain(void *hif_handle, u8 idx) +{ + struct hif_device_usb *hif_dev = (struct hif_device_usb *)hif_handle; + struct sk_buff *skb, *tmp; + unsigned long flags; + + spin_lock_irqsave(&hif_dev->tx.tx_lock, flags); + + skb_queue_walk_safe(&hif_dev->tx.tx_skb_queue, skb, tmp) { + if (check_index(skb, idx)) { + __skb_unlink(skb, &hif_dev->tx.tx_skb_queue); + ath9k_htc_txcompletion_cb(hif_dev->htc_handle, + skb, false); + hif_dev->tx.tx_skb_cnt--; + TX_STAT_INC(skb_failed); + } + } + + spin_unlock_irqrestore(&hif_dev->tx.tx_lock, flags); +} + static struct ath9k_htc_hif hif_usb = { .transport = ATH9K_HIF_USB, .name = "ath9k_hif_usb", @@ -372,6 +406,7 @@ static struct ath9k_htc_hif hif_usb = { .start = hif_usb_start, .stop = hif_usb_stop, + .sta_drain = hif_usb_sta_drain, .send = hif_usb_send, }; diff --git a/drivers/net/wireless/ath/ath9k/htc.h b/drivers/net/wireless/ath/ath9k/htc.h index 0d2e2b1..41823fd 100644 --- a/drivers/net/wireless/ath/ath9k/htc.h +++ b/drivers/net/wireless/ath/ath9k/htc.h @@ -280,6 +280,7 @@ struct ath9k_htc_tx_ctl { u8 type; /* ATH9K_HTC_* */ u8 epid; u8 txok; + u8 sta_idx; }; static inline struct ath9k_htc_tx_ctl *HTC_SKB_CB(struct sk_buff *skb) diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_main.c b/drivers/net/wireless/ath/ath9k/htc_drv_main.c index fb9ff11..ae85cc4 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_main.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_main.c @@ -1303,10 +1303,13 @@ static int ath9k_htc_sta_remove(struct ieee80211_hw *hw, struct ieee80211_sta *sta) { struct ath9k_htc_priv *priv = hw->priv; + struct ath9k_htc_sta *ista; int ret; mutex_lock(&priv->mutex); ath9k_htc_ps_wakeup(priv); + ista = (struct ath9k_htc_sta *) sta->drv_priv; + htc_sta_drain(priv->htc, ista->index); ret = ath9k_htc_remove_station(priv, vif, sta); ath9k_htc_ps_restore(priv); mutex_unlock(&priv->mutex); diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c b/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c index 9e0c34b..0790070 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c @@ -248,6 +248,14 @@ int ath9k_htc_tx_start(struct ath9k_htc_priv *priv, tx_hdr.vif_idx = vif_idx; tx_hdr.cookie = slot; + /* + * This is a bit redundant but it helps to get + * the per-packet index quickly when draining the + * TX queue in the HIF layer. Otherwise we would + * have to parse the packet contents ... + */ + tx_ctl->sta_idx = sta_idx; + if (tx_info->flags & IEEE80211_TX_CTL_AMPDU) { tx_ctl->type = ATH9K_HTC_AMPDU; tx_hdr.data_type = ATH9K_HTC_AMPDU; diff --git a/drivers/net/wireless/ath/ath9k/htc_hst.c b/drivers/net/wireless/ath/ath9k/htc_hst.c index 7ced8ab..5c76352 100644 --- a/drivers/net/wireless/ath/ath9k/htc_hst.c +++ b/drivers/net/wireless/ath/ath9k/htc_hst.c @@ -310,6 +310,11 @@ void htc_start(struct htc_target *target) target->hif->start(target->hif_dev); } +void htc_sta_drain(struct htc_target *target, u8 idx) +{ + target->hif->sta_drain(target->hif_dev, idx); +} + void ath9k_htc_txcompletion_cb(struct htc_target *htc_handle, struct sk_buff *skb, bool txok) { diff --git a/drivers/net/wireless/ath/ath9k/htc_hst.h b/drivers/net/wireless/ath/ath9k/htc_hst.h index 191e3c0..cb9174a 100644 --- a/drivers/net/wireless/ath/ath9k/htc_hst.h +++ b/drivers/net/wireless/ath/ath9k/htc_hst.h @@ -35,6 +35,7 @@ struct ath9k_htc_hif { void (*start) (void *hif_handle); void (*stop) (void *hif_handle); + void (*sta_drain) (void *hif_handle, u8 idx); int (*send) (void *hif_handle, u8 pipe, struct sk_buff *buf); }; @@ -209,6 +210,7 @@ int htc_send_epid(struct htc_target *target, struct sk_buff *skb, enum htc_endpoint_id epid); void htc_stop(struct htc_target *target); void htc_start(struct htc_target *target); +void htc_sta_drain(struct htc_target *target, u8 idx); void ath9k_htc_rx_msg(struct htc_target *htc_handle, struct sk_buff *skb, u32 len, u8 pipe_id); -- cgit v0.10.2 From 27876a29de221186c9d5883e5fe5f6da18ef9a45 Mon Sep 17 00:00:00 2001 From: Sujith Manoharan Date: Wed, 13 Apr 2011 11:26:18 +0530 Subject: ath9k_htc: Add support for TX completion Now that the infrastructure is in place, process WMI TX status events and complete packets. Signed-off-by: Sujith Manoharan Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/htc.h b/drivers/net/wireless/ath/ath9k/htc.h index 41823fd..6c103ed 100644 --- a/drivers/net/wireless/ath/ath9k/htc.h +++ b/drivers/net/wireless/ath/ath9k/htc.h @@ -266,11 +266,17 @@ struct ath9k_htc_rx { #define ATH9K_HTC_TX_THRESHOLD (MAX_TX_BUF_NUM - ATH9K_HTC_TX_RESERVE) #define ATH9K_HTC_OP_TX_QUEUES_STOP BIT(0) +#define ATH9K_HTC_OP_TX_DRAIN BIT(1) struct ath9k_htc_tx { u8 flags; int queued_cnt; - struct sk_buff_head tx_queue; + struct sk_buff_head mgmt_ep_queue; + struct sk_buff_head cab_ep_queue; + struct sk_buff_head data_be_queue; + struct sk_buff_head data_bk_queue; + struct sk_buff_head data_vi_queue; + struct sk_buff_head data_vo_queue; struct sk_buff_head tx_failed; DECLARE_BITMAP(tx_slot, MAX_TX_BUF_NUM); spinlock_t tx_lock; @@ -465,8 +471,8 @@ struct ath9k_htc_priv { struct tasklet_struct swba_tasklet; struct tasklet_struct rx_tasklet; - struct tasklet_struct tx_tasklet; struct delayed_work ani_work; + struct tasklet_struct tx_failed_tasklet; struct work_struct ps_work; struct work_struct fatal_work; @@ -533,7 +539,6 @@ void ath9k_htc_start_ani(struct ath9k_htc_priv *priv); void ath9k_htc_stop_ani(struct ath9k_htc_priv *priv); int ath9k_tx_init(struct ath9k_htc_priv *priv); -void ath9k_tx_tasklet(unsigned long data); int ath9k_htc_tx_start(struct ath9k_htc_priv *priv, struct sk_buff *skb, u8 slot, bool is_cab); void ath9k_tx_cleanup(struct ath9k_htc_priv *priv); @@ -547,6 +552,9 @@ void ath9k_htc_check_wake_queues(struct ath9k_htc_priv *priv); int ath9k_htc_tx_get_slot(struct ath9k_htc_priv *priv); void ath9k_htc_tx_clear_slot(struct ath9k_htc_priv *priv, int slot); void ath9k_htc_tx_drain(struct ath9k_htc_priv *priv); +void ath9k_htc_txstatus(struct ath9k_htc_priv *priv, void *wmi_event); +void ath9k_htc_tx_failed(struct ath9k_htc_priv *priv); +void ath9k_tx_failed_tasklet(unsigned long data); int ath9k_rx_init(struct ath9k_htc_priv *priv); void ath9k_rx_cleanup(struct ath9k_htc_priv *priv); diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_init.c b/drivers/net/wireless/ath/ath9k/htc_drv_init.c index c270da7..afceeaa 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_init.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_init.c @@ -678,7 +678,7 @@ static int ath9k_init_priv(struct ath9k_htc_priv *priv, mutex_init(&priv->htc_pm_lock); tasklet_init(&priv->rx_tasklet, ath9k_rx_tasklet, (unsigned long)priv); - tasklet_init(&priv->tx_tasklet, ath9k_tx_tasklet, + tasklet_init(&priv->tx_failed_tasklet, ath9k_tx_failed_tasklet, (unsigned long)priv); INIT_DELAYED_WORK(&priv->ani_work, ath9k_htc_ani_work); INIT_WORK(&priv->ps_work, ath9k_ps_work); diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c b/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c index 0790070..a9b6bb1 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c @@ -99,8 +99,8 @@ void ath9k_htc_tx_clear_slot(struct ath9k_htc_priv *priv, int slot) spin_unlock_bh(&priv->tx.tx_lock); } -static enum htc_endpoint_id get_htc_epid(struct ath9k_htc_priv *priv, - u16 qnum) +static inline enum htc_endpoint_id get_htc_epid(struct ath9k_htc_priv *priv, + u16 qnum) { enum htc_endpoint_id epid; @@ -127,6 +127,30 @@ static enum htc_endpoint_id get_htc_epid(struct ath9k_htc_priv *priv, return epid; } +static inline struct sk_buff_head* +get_htc_epid_queue(struct ath9k_htc_priv *priv, u8 epid) +{ + struct ath_common *common = ath9k_hw_common(priv->ah); + struct sk_buff_head *epid_queue = NULL; + + if (epid == priv->mgmt_ep) + epid_queue = &priv->tx.mgmt_ep_queue; + else if (epid == priv->cab_ep) + epid_queue = &priv->tx.cab_ep_queue; + else if (epid == priv->data_be_ep) + epid_queue = &priv->tx.data_be_queue; + else if (epid == priv->data_bk_ep) + epid_queue = &priv->tx.data_bk_queue; + else if (epid == priv->data_vi_ep) + epid_queue = &priv->tx.data_vi_queue; + else if (epid == priv->data_vo_ep) + epid_queue = &priv->tx.data_vo_queue; + else + ath_err(common, "Invalid EPID: %d\n", epid); + + return epid_queue; +} + /* * Removes the driver header and returns the TX slot number */ @@ -387,11 +411,15 @@ static void ath9k_htc_check_tx_aggr(struct ath9k_htc_priv *priv, } static void ath9k_htc_tx_process(struct ath9k_htc_priv *priv, - struct sk_buff *skb) + struct sk_buff *skb, + struct __wmi_event_txstatus *txs) { struct ieee80211_vif *vif; struct ath9k_htc_tx_ctl *tx_ctl; struct ieee80211_tx_info *tx_info; + struct ieee80211_tx_rate *rate; + struct ieee80211_conf *cur_conf = &priv->hw->conf; + struct ieee80211_supported_band *sband; bool txok; int slot; @@ -405,6 +433,8 @@ static void ath9k_htc_tx_process(struct ath9k_htc_priv *priv, txok = tx_ctl->txok; tx_info = IEEE80211_SKB_CB(skb); vif = tx_info->control.vif; + rate = &tx_info->status.rates[0]; + sband = priv->hw->wiphy->bands[cur_conf->channel->band]; memset(&tx_info->status, 0, sizeof(tx_info->status)); @@ -412,10 +442,32 @@ static void ath9k_htc_tx_process(struct ath9k_htc_priv *priv, * URB submission failed for this frame, it never reached * the target. */ - if (!txok || !vif) + if (!txok || !vif || !txs) goto send_mac80211; - tx_info->flags |= IEEE80211_TX_STAT_ACK; + if (txs->ts_flags & ATH9K_HTC_TXSTAT_ACK) + tx_info->flags |= IEEE80211_TX_STAT_ACK; + + if (txs->ts_flags & ATH9K_HTC_TXSTAT_FILT) + tx_info->flags |= IEEE80211_TX_STAT_TX_FILTERED; + + if (txs->ts_flags & ATH9K_HTC_TXSTAT_RTC_CTS) + rate->flags |= IEEE80211_TX_RC_USE_RTS_CTS; + + rate->count = 1; + rate->idx = MS(txs->ts_rate, ATH9K_HTC_TXSTAT_RATE); + + if (txs->ts_flags & ATH9K_HTC_TXSTAT_MCS) { + rate->flags |= IEEE80211_TX_RC_MCS; + + if (txs->ts_flags & ATH9K_HTC_TXSTAT_CW40) + rate->flags |= IEEE80211_TX_RC_40_MHZ_WIDTH; + if (txs->ts_flags & ATH9K_HTC_TXSTAT_SGI) + rate->flags |= IEEE80211_TX_RC_SHORT_GI; + } else { + if (cur_conf->channel->band == IEEE80211_BAND_5GHZ) + rate->idx += 4; /* No CCK rates */ + } ath9k_htc_check_tx_aggr(priv, vif, skb); @@ -431,37 +483,130 @@ send_mac80211: ieee80211_tx_status(priv->hw, skb); } +static inline void ath9k_htc_tx_drainq(struct ath9k_htc_priv *priv, + struct sk_buff_head *queue) +{ + struct sk_buff *skb; + + while ((skb = skb_dequeue(queue)) != NULL) { + ath9k_htc_tx_process(priv, skb, NULL); + } +} + void ath9k_htc_tx_drain(struct ath9k_htc_priv *priv) { - struct sk_buff *skb = NULL; + spin_lock_bh(&priv->tx.tx_lock); + priv->tx.flags |= ATH9K_HTC_OP_TX_DRAIN; + spin_unlock_bh(&priv->tx.tx_lock); /* * Ensure that all pending TX frames are flushed, - * and that the TX completion tasklet is killed. + * and that the TX completion/failed tasklets is killed. */ htc_stop(priv->htc); - tasklet_kill(&priv->tx_tasklet); + tasklet_kill(&priv->wmi->wmi_event_tasklet); + tasklet_kill(&priv->tx_failed_tasklet); - while ((skb = skb_dequeue(&priv->tx.tx_queue)) != NULL) { - ath9k_htc_tx_process(priv, skb); - } + ath9k_htc_tx_drainq(priv, &priv->tx.mgmt_ep_queue); + ath9k_htc_tx_drainq(priv, &priv->tx.cab_ep_queue); + ath9k_htc_tx_drainq(priv, &priv->tx.data_be_queue); + ath9k_htc_tx_drainq(priv, &priv->tx.data_bk_queue); + ath9k_htc_tx_drainq(priv, &priv->tx.data_vi_queue); + ath9k_htc_tx_drainq(priv, &priv->tx.data_vo_queue); + ath9k_htc_tx_drainq(priv, &priv->tx.tx_failed); - while ((skb = skb_dequeue(&priv->tx.tx_failed)) != NULL) { - ath9k_htc_tx_process(priv, skb); - } + spin_lock_bh(&priv->tx.tx_lock); + priv->tx.flags &= ~ATH9K_HTC_OP_TX_DRAIN; + spin_unlock_bh(&priv->tx.tx_lock); } -void ath9k_tx_tasklet(unsigned long data) +void ath9k_tx_failed_tasklet(unsigned long data) { struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *)data; - struct sk_buff *skb = NULL; - while ((skb = skb_dequeue(&priv->tx.tx_queue)) != NULL) { - ath9k_htc_tx_process(priv, skb); + spin_lock_bh(&priv->tx.tx_lock); + if (priv->tx.flags & ATH9K_HTC_OP_TX_DRAIN) { + spin_unlock_bh(&priv->tx.tx_lock); + return; } + spin_unlock_bh(&priv->tx.tx_lock); - while ((skb = skb_dequeue(&priv->tx.tx_failed)) != NULL) { - ath9k_htc_tx_process(priv, skb); + ath9k_htc_tx_drainq(priv, &priv->tx.tx_failed); +} + +static inline bool check_cookie(struct ath9k_htc_priv *priv, + struct sk_buff *skb, + u8 cookie, u8 epid) +{ + u8 fcookie = 0; + + if (epid == priv->mgmt_ep) { + struct tx_mgmt_hdr *hdr; + hdr = (struct tx_mgmt_hdr *) skb->data; + fcookie = hdr->cookie; + } else if ((epid == priv->data_bk_ep) || + (epid == priv->data_be_ep) || + (epid == priv->data_vi_ep) || + (epid == priv->data_vo_ep) || + (epid == priv->cab_ep)) { + struct tx_frame_hdr *hdr; + hdr = (struct tx_frame_hdr *) skb->data; + fcookie = hdr->cookie; + } + + if (fcookie == cookie) + return true; + + return false; +} + +static struct sk_buff* ath9k_htc_tx_get_packet(struct ath9k_htc_priv *priv, + struct __wmi_event_txstatus *txs) +{ + struct ath_common *common = ath9k_hw_common(priv->ah); + struct sk_buff_head *epid_queue; + struct sk_buff *skb, *tmp; + unsigned long flags; + u8 epid = MS(txs->ts_rate, ATH9K_HTC_TXSTAT_EPID); + + epid_queue = get_htc_epid_queue(priv, epid); + if (!epid_queue) + return NULL; + + spin_lock_irqsave(&epid_queue->lock, flags); + skb_queue_walk_safe(epid_queue, skb, tmp) { + if (check_cookie(priv, skb, txs->cookie, epid)) { + __skb_unlink(skb, epid_queue); + spin_unlock_irqrestore(&epid_queue->lock, flags); + return skb; + } + } + spin_unlock_irqrestore(&epid_queue->lock, flags); + + ath_dbg(common, ATH_DBG_XMIT, + "No matching packet for cookie: %d, epid: %d\n", + txs->cookie, epid); + + return NULL; +} + +void ath9k_htc_txstatus(struct ath9k_htc_priv *priv, void *wmi_event) +{ + struct wmi_event_txstatus *txs = (struct wmi_event_txstatus *)wmi_event; + struct __wmi_event_txstatus *__txs; + struct sk_buff *skb; + int i; + + for (i = 0; i < txs->cnt; i++) { + WARN_ON(txs->cnt > HTC_MAX_TX_STATUS); + + __txs = &txs->txstatus[i]; + + skb = ath9k_htc_tx_get_packet(priv, __txs); + if (!skb) + continue; + + ath9k_htc_tx_process(priv, skb, __txs); } /* Wake TX queues if needed */ @@ -473,21 +618,34 @@ void ath9k_htc_txep(void *drv_priv, struct sk_buff *skb, { struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *) drv_priv; struct ath9k_htc_tx_ctl *tx_ctl; + struct sk_buff_head *epid_queue; tx_ctl = HTC_SKB_CB(skb); tx_ctl->txok = txok; - if (txok) - skb_queue_tail(&priv->tx.tx_queue, skb); - else + if (!txok) { skb_queue_tail(&priv->tx.tx_failed, skb); + tasklet_schedule(&priv->tx_failed_tasklet); + return; + } + + epid_queue = get_htc_epid_queue(priv, ep_id); + if (!epid_queue) { + dev_kfree_skb_any(skb); + return; + } - tasklet_schedule(&priv->tx_tasklet); + skb_queue_tail(epid_queue, skb); } int ath9k_tx_init(struct ath9k_htc_priv *priv) { - skb_queue_head_init(&priv->tx.tx_queue); + skb_queue_head_init(&priv->tx.mgmt_ep_queue); + skb_queue_head_init(&priv->tx.cab_ep_queue); + skb_queue_head_init(&priv->tx.data_be_queue); + skb_queue_head_init(&priv->tx.data_bk_queue); + skb_queue_head_init(&priv->tx.data_vi_queue); + skb_queue_head_init(&priv->tx.data_vo_queue); skb_queue_head_init(&priv->tx.tx_failed); return 0; } diff --git a/drivers/net/wireless/ath/ath9k/wmi.c b/drivers/net/wireless/ath/ath9k/wmi.c index e66f6c3..3f5a4d1 100644 --- a/drivers/net/wireless/ath/ath9k/wmi.c +++ b/drivers/net/wireless/ath/ath9k/wmi.c @@ -163,6 +163,16 @@ void ath9k_wmi_event_tasklet(unsigned long data) wmi->drv_priv->debug.txrate = be32_to_cpu(txrate); #endif break; + case WMI_TXSTATUS_EVENTID: + spin_lock_bh(&priv->tx.tx_lock); + if (priv->tx.flags & ATH9K_HTC_OP_TX_DRAIN) { + spin_unlock_bh(&priv->tx.tx_lock); + break; + } + spin_unlock_bh(&priv->tx.tx_lock); + + ath9k_htc_txstatus(priv, wmi_event); + break; default: break; } diff --git a/drivers/net/wireless/ath/ath9k/wmi.h b/drivers/net/wireless/ath/ath9k/wmi.h index 8c877dc..44b1738 100644 --- a/drivers/net/wireless/ath/ath9k/wmi.h +++ b/drivers/net/wireless/ath/ath9k/wmi.h @@ -45,9 +45,9 @@ struct wmi_event_swba { /* * 64 - HTC header - WMI header - 1 / txstatus * And some other hdr. space is also accounted for. - * 13 seems to be the magic number. + * 12 seems to be the magic number. */ -#define HTC_MAX_TX_STATUS 13 +#define HTC_MAX_TX_STATUS 12 #define ATH9K_HTC_TXSTAT_ACK BIT(0) #define ATH9K_HTC_TXSTAT_FILT BIT(1) -- cgit v0.10.2 From 01f684de7cc0641a9ee968f2d2c45c3a67241252 Mon Sep 17 00:00:00 2001 From: Sujith Manoharan Date: Wed, 13 Apr 2011 11:26:26 +0530 Subject: ath9k_htc: Add a debugfs file to dump TX slot information Location: ath9k_htc/phy#/slot Signed-off-by: Sujith Manoharan Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/htc.h b/drivers/net/wireless/ath/ath9k/htc.h index 6c103ed..b9c7bec 100644 --- a/drivers/net/wireless/ath/ath9k/htc.h +++ b/drivers/net/wireless/ath/ath9k/htc.h @@ -338,6 +338,7 @@ struct ath9k_debug { struct dentry *debugfs_tgt_stats; struct dentry *debugfs_xmit; struct dentry *debugfs_recv; + struct dentry *debugfs_slot; struct ath_tx_stats tx_stats; struct ath_rx_stats rx_stats; u32 txrate; diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_debug.c b/drivers/net/wireless/ath/ath9k/htc_drv_debug.c index 91a486c..119cc54 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_debug.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_debug.c @@ -244,6 +244,41 @@ static const struct file_operations fops_recv = { .llseek = default_llseek, }; +static ssize_t read_file_slot(struct file *file, char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct ath9k_htc_priv *priv = file->private_data; + char buf[512]; + unsigned int len = 0; + + spin_lock_bh(&priv->tx.tx_lock); + + len += snprintf(buf + len, sizeof(buf) - len, "TX slot bitmap : "); + + len += bitmap_scnprintf(buf + len, sizeof(buf) - len, + priv->tx.tx_slot, MAX_TX_BUF_NUM); + + len += snprintf(buf + len, sizeof(buf) - len, "\n"); + + len += snprintf(buf + len, sizeof(buf) - len, + "Used slots : %d\n", + bitmap_weight(priv->tx.tx_slot, MAX_TX_BUF_NUM)); + + spin_unlock_bh(&priv->tx.tx_lock); + + if (len > sizeof(buf)) + len = sizeof(buf); + + return simple_read_from_buffer(user_buf, count, ppos, buf, len); +} + +static const struct file_operations fops_slot = { + .read = read_file_slot, + .open = ath9k_debugfs_open, + .owner = THIS_MODULE, + .llseek = default_llseek, +}; + int ath9k_htc_init_debug(struct ath_hw *ah) { struct ath_common *common = ath9k_hw_common(ah); @@ -276,6 +311,12 @@ int ath9k_htc_init_debug(struct ath_hw *ah) if (!priv->debug.debugfs_recv) goto err; + priv->debug.debugfs_slot = debugfs_create_file("slot", S_IRUSR, + priv->debug.debugfs_phy, + priv, &fops_slot); + if (!priv->debug.debugfs_slot) + goto err; + return 0; err: @@ -288,6 +329,7 @@ void ath9k_htc_exit_debug(struct ath_hw *ah) struct ath_common *common = ath9k_hw_common(ah); struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *) common->priv; + debugfs_remove(priv->debug.debugfs_slot); debugfs_remove(priv->debug.debugfs_recv); debugfs_remove(priv->debug.debugfs_xmit); debugfs_remove(priv->debug.debugfs_tgt_stats); -- cgit v0.10.2 From c4d04186c7023d54445b695da226b3e98e0a55f9 Mon Sep 17 00:00:00 2001 From: Sujith Manoharan Date: Wed, 13 Apr 2011 11:26:31 +0530 Subject: ath9k_htc: Add a debugfs file showing endpoint status Location: ath9k_htc/phy#/queue Signed-off-by: Sujith Manoharan Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/htc.h b/drivers/net/wireless/ath/ath9k/htc.h index b9c7bec..b40753c 100644 --- a/drivers/net/wireless/ath/ath9k/htc.h +++ b/drivers/net/wireless/ath/ath9k/htc.h @@ -339,6 +339,7 @@ struct ath9k_debug { struct dentry *debugfs_xmit; struct dentry *debugfs_recv; struct dentry *debugfs_slot; + struct dentry *debugfs_queue; struct ath_tx_stats tx_stats; struct ath_rx_stats rx_stats; u32 txrate; diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_debug.c b/drivers/net/wireless/ath/ath9k/htc_drv_debug.c index 119cc54..961bec2 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_debug.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_debug.c @@ -279,6 +279,53 @@ static const struct file_operations fops_slot = { .llseek = default_llseek, }; +static ssize_t read_file_queue(struct file *file, char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct ath9k_htc_priv *priv = file->private_data; + char buf[512]; + unsigned int len = 0; + + len += snprintf(buf + len, sizeof(buf) - len, "%16s : %3d\n", + "Mgmt endpoint", skb_queue_len(&priv->tx.mgmt_ep_queue)); + + len += snprintf(buf + len, sizeof(buf) - len, "%16s : %3d\n", + "Cab endpoint", skb_queue_len(&priv->tx.cab_ep_queue)); + + len += snprintf(buf + len, sizeof(buf) - len, "%16s : %3d\n", + "Data BE endpoint", skb_queue_len(&priv->tx.data_be_queue)); + + len += snprintf(buf + len, sizeof(buf) - len, "%16s : %3d\n", + "Data BK endpoint", skb_queue_len(&priv->tx.data_bk_queue)); + + len += snprintf(buf + len, sizeof(buf) - len, "%16s : %3d\n", + "Data VI endpoint", skb_queue_len(&priv->tx.data_vi_queue)); + + len += snprintf(buf + len, sizeof(buf) - len, "%16s : %3d\n", + "Data VO endpoint", skb_queue_len(&priv->tx.data_vo_queue)); + + len += snprintf(buf + len, sizeof(buf) - len, "%16s : %3d\n", + "Failed queue", skb_queue_len(&priv->tx.tx_failed)); + + spin_lock_bh(&priv->tx.tx_lock); + len += snprintf(buf + len, sizeof(buf) - len, "%16s : %3d\n", + "Queued count", priv->tx.queued_cnt); + spin_unlock_bh(&priv->tx.tx_lock); + + if (len > sizeof(buf)) + len = sizeof(buf); + + return simple_read_from_buffer(user_buf, count, ppos, buf, len); + +} + +static const struct file_operations fops_queue = { + .read = read_file_queue, + .open = ath9k_debugfs_open, + .owner = THIS_MODULE, + .llseek = default_llseek, +}; + int ath9k_htc_init_debug(struct ath_hw *ah) { struct ath_common *common = ath9k_hw_common(ah); @@ -317,6 +364,12 @@ int ath9k_htc_init_debug(struct ath_hw *ah) if (!priv->debug.debugfs_slot) goto err; + priv->debug.debugfs_queue = debugfs_create_file("queue", S_IRUSR, + priv->debug.debugfs_phy, + priv, &fops_queue); + if (!priv->debug.debugfs_queue) + goto err; + return 0; err: @@ -329,6 +382,7 @@ void ath9k_htc_exit_debug(struct ath_hw *ah) struct ath_common *common = ath9k_hw_common(ah); struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *) common->priv; + debugfs_remove(priv->debug.debugfs_queue); debugfs_remove(priv->debug.debugfs_slot); debugfs_remove(priv->debug.debugfs_recv); debugfs_remove(priv->debug.debugfs_xmit); -- cgit v0.10.2 From 859c3ca1e4608615788dc6cbc199210fe4b5efa2 Mon Sep 17 00:00:00 2001 From: Sujith Manoharan Date: Wed, 13 Apr 2011 11:26:39 +0530 Subject: ath9k_htc: Add a timer to cleanup WMI events Occasionally, a WMI event would arrive ahead of the TX URB completion handler. Discarding these events would exhaust the available TX slots, so handle them by running a timer cleaning up such events. Also, timeout packets for which TX completion events have not arrived. Signed-off-by: Sujith Manoharan Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/htc.h b/drivers/net/wireless/ath/ath9k/htc.h index b40753c..b413b46 100644 --- a/drivers/net/wireless/ath/ath9k/htc.h +++ b/drivers/net/wireless/ath/ath9k/htc.h @@ -262,7 +262,10 @@ struct ath9k_htc_rx { spinlock_t rxbuflock; }; -#define ATH9K_HTC_TX_RESERVE 10 +#define ATH9K_HTC_TX_CLEANUP_INTERVAL 50 /* ms */ +#define ATH9K_HTC_TX_TIMEOUT_INTERVAL 2500 /* ms */ +#define ATH9K_HTC_TX_RESERVE 10 +#define ATH9K_HTC_TX_TIMEOUT_COUNT 20 #define ATH9K_HTC_TX_THRESHOLD (MAX_TX_BUF_NUM - ATH9K_HTC_TX_RESERVE) #define ATH9K_HTC_OP_TX_QUEUES_STOP BIT(0) @@ -279,6 +282,7 @@ struct ath9k_htc_tx { struct sk_buff_head data_vo_queue; struct sk_buff_head tx_failed; DECLARE_BITMAP(tx_slot, MAX_TX_BUF_NUM); + struct timer_list cleanup_timer; spinlock_t tx_lock; }; @@ -287,6 +291,7 @@ struct ath9k_htc_tx_ctl { u8 epid; u8 txok; u8 sta_idx; + unsigned long timestamp; }; static inline struct ath9k_htc_tx_ctl *HTC_SKB_CB(struct sk_buff *skb) @@ -557,6 +562,7 @@ void ath9k_htc_tx_drain(struct ath9k_htc_priv *priv); void ath9k_htc_txstatus(struct ath9k_htc_priv *priv, void *wmi_event); void ath9k_htc_tx_failed(struct ath9k_htc_priv *priv); void ath9k_tx_failed_tasklet(unsigned long data); +void ath9k_htc_tx_cleanup_timer(unsigned long data); int ath9k_rx_init(struct ath9k_htc_priv *priv); void ath9k_rx_cleanup(struct ath9k_htc_priv *priv); diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_init.c b/drivers/net/wireless/ath/ath9k/htc_drv_init.c index afceeaa..0aec259 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_init.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_init.c @@ -671,7 +671,6 @@ static int ath9k_init_priv(struct ath9k_htc_priv *priv, common->priv = priv; common->debug_mask = ath9k_debug; - spin_lock_init(&priv->wmi->wmi_lock); spin_lock_init(&priv->beacon_lock); spin_lock_init(&priv->tx.tx_lock); mutex_init(&priv->mutex); @@ -683,6 +682,8 @@ static int ath9k_init_priv(struct ath9k_htc_priv *priv, INIT_DELAYED_WORK(&priv->ani_work, ath9k_htc_ani_work); INIT_WORK(&priv->ps_work, ath9k_ps_work); INIT_WORK(&priv->fatal_work, ath9k_fatal_work); + setup_timer(&priv->tx.cleanup_timer, ath9k_htc_tx_cleanup_timer, + (unsigned long)priv); /* * Cache line size is used to size and align various diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_main.c b/drivers/net/wireless/ath/ath9k/htc_drv_main.c index ae85cc4..4de3864 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_main.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_main.c @@ -194,6 +194,7 @@ void ath9k_htc_reset(struct ath9k_htc_priv *priv) ath9k_htc_stop_ani(priv); ieee80211_stop_queues(priv->hw); + del_timer_sync(&priv->tx.cleanup_timer); ath9k_htc_tx_drain(priv); WMI_CMD(WMI_DISABLE_INTR_CMDID); @@ -225,6 +226,9 @@ void ath9k_htc_reset(struct ath9k_htc_priv *priv) ath9k_htc_vif_reconfig(priv); ieee80211_wake_queues(priv->hw); + mod_timer(&priv->tx.cleanup_timer, + jiffies + msecs_to_jiffies(ATH9K_HTC_TX_CLEANUP_INTERVAL)); + ath9k_htc_ps_restore(priv); mutex_unlock(&priv->mutex); } @@ -251,6 +255,7 @@ static int ath9k_htc_set_channel(struct ath9k_htc_priv *priv, ath9k_htc_ps_wakeup(priv); + del_timer_sync(&priv->tx.cleanup_timer); ath9k_htc_tx_drain(priv); WMI_CMD(WMI_DISABLE_INTR_CMDID); @@ -301,6 +306,9 @@ static int ath9k_htc_set_channel(struct ath9k_htc_priv *priv, !(hw->conf.flags & IEEE80211_CONF_OFFCHANNEL)) ath9k_htc_vif_reconfig(priv); + mod_timer(&priv->tx.cleanup_timer, + jiffies + msecs_to_jiffies(ATH9K_HTC_TX_CLEANUP_INTERVAL)); + err: ath9k_htc_ps_restore(priv); return ret; @@ -937,6 +945,9 @@ static int ath9k_htc_start(struct ieee80211_hw *hw) ieee80211_wake_queues(hw); + mod_timer(&priv->tx.cleanup_timer, + jiffies + msecs_to_jiffies(ATH9K_HTC_TX_CLEANUP_INTERVAL)); + if (ah->btcoex_hw.scheme == ATH_BTCOEX_CFG_3WIRE) { ath9k_hw_btcoex_set_weight(ah, AR_BT_COEX_WGHT, AR_STOMP_LOW_WLAN_WGHT); @@ -972,6 +983,7 @@ static void ath9k_htc_stop(struct ieee80211_hw *hw) tasklet_kill(&priv->rx_tasklet); + del_timer_sync(&priv->tx.cleanup_timer); ath9k_htc_tx_drain(priv); ath9k_wmi_event_drain(priv); diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c b/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c index a9b6bb1..86f5ce9 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c @@ -495,6 +495,8 @@ static inline void ath9k_htc_tx_drainq(struct ath9k_htc_priv *priv, void ath9k_htc_tx_drain(struct ath9k_htc_priv *priv) { + struct ath9k_htc_tx_event *event, *tmp; + spin_lock_bh(&priv->tx.tx_lock); priv->tx.flags |= ATH9K_HTC_OP_TX_DRAIN; spin_unlock_bh(&priv->tx.tx_lock); @@ -515,6 +517,16 @@ void ath9k_htc_tx_drain(struct ath9k_htc_priv *priv) ath9k_htc_tx_drainq(priv, &priv->tx.data_vo_queue); ath9k_htc_tx_drainq(priv, &priv->tx.tx_failed); + /* + * The TX cleanup timer has already been killed. + */ + spin_lock_bh(&priv->wmi->event_lock); + list_for_each_entry_safe(event, tmp, &priv->wmi->pending_tx_events, list) { + list_del(&event->list); + kfree(event); + } + spin_unlock_bh(&priv->wmi->event_lock); + spin_lock_bh(&priv->tx.tx_lock); priv->tx.flags &= ~ATH9K_HTC_OP_TX_DRAIN; spin_unlock_bh(&priv->tx.tx_lock); @@ -595,6 +607,7 @@ void ath9k_htc_txstatus(struct ath9k_htc_priv *priv, void *wmi_event) struct wmi_event_txstatus *txs = (struct wmi_event_txstatus *)wmi_event; struct __wmi_event_txstatus *__txs; struct sk_buff *skb; + struct ath9k_htc_tx_event *tx_pend; int i; for (i = 0; i < txs->cnt; i++) { @@ -603,8 +616,26 @@ void ath9k_htc_txstatus(struct ath9k_htc_priv *priv, void *wmi_event) __txs = &txs->txstatus[i]; skb = ath9k_htc_tx_get_packet(priv, __txs); - if (!skb) + if (!skb) { + /* + * Store this event, so that the TX cleanup + * routine can check later for the needed packet. + */ + tx_pend = kzalloc(sizeof(struct ath9k_htc_tx_event), + GFP_ATOMIC); + if (!tx_pend) + continue; + + memcpy(&tx_pend->txs, __txs, + sizeof(struct __wmi_event_txstatus)); + + spin_lock(&priv->wmi->event_lock); + list_add_tail(&tx_pend->list, + &priv->wmi->pending_tx_events); + spin_unlock(&priv->wmi->event_lock); + continue; + } ath9k_htc_tx_process(priv, skb, __txs); } @@ -622,6 +653,7 @@ void ath9k_htc_txep(void *drv_priv, struct sk_buff *skb, tx_ctl = HTC_SKB_CB(skb); tx_ctl->txok = txok; + tx_ctl->timestamp = jiffies; if (!txok) { skb_queue_tail(&priv->tx.tx_failed, skb); @@ -638,6 +670,99 @@ void ath9k_htc_txep(void *drv_priv, struct sk_buff *skb, skb_queue_tail(epid_queue, skb); } +static inline bool check_packet(struct ath9k_htc_priv *priv, struct sk_buff *skb) +{ + struct ath_common *common = ath9k_hw_common(priv->ah); + struct ath9k_htc_tx_ctl *tx_ctl; + + tx_ctl = HTC_SKB_CB(skb); + + if (time_after(jiffies, + tx_ctl->timestamp + + msecs_to_jiffies(ATH9K_HTC_TX_TIMEOUT_INTERVAL))) { + ath_dbg(common, ATH_DBG_XMIT, + "Dropping a packet due to TX timeout\n"); + return true; + } + + return false; +} + +static void ath9k_htc_tx_cleanup_queue(struct ath9k_htc_priv *priv, + struct sk_buff_head *epid_queue) +{ + bool process = false; + unsigned long flags; + struct sk_buff *skb, *tmp; + struct sk_buff_head queue; + + skb_queue_head_init(&queue); + + spin_lock_irqsave(&epid_queue->lock, flags); + skb_queue_walk_safe(epid_queue, skb, tmp) { + if (check_packet(priv, skb)) { + __skb_unlink(skb, epid_queue); + __skb_queue_tail(&queue, skb); + process = true; + } + } + spin_unlock_irqrestore(&epid_queue->lock, flags); + + if (process) { + skb_queue_walk_safe(&queue, skb, tmp) { + __skb_unlink(skb, &queue); + ath9k_htc_tx_process(priv, skb, NULL); + } + } +} + +void ath9k_htc_tx_cleanup_timer(unsigned long data) +{ + struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *) data; + struct ath_common *common = ath9k_hw_common(priv->ah); + struct ath9k_htc_tx_event *event, *tmp; + struct sk_buff *skb; + + spin_lock(&priv->wmi->event_lock); + list_for_each_entry_safe(event, tmp, &priv->wmi->pending_tx_events, list) { + + skb = ath9k_htc_tx_get_packet(priv, &event->txs); + if (skb) { + ath_dbg(common, ATH_DBG_XMIT, + "Found packet for cookie: %d, epid: %d\n", + event->txs.cookie, + MS(event->txs.ts_rate, ATH9K_HTC_TXSTAT_EPID)); + + ath9k_htc_tx_process(priv, skb, &event->txs); + list_del(&event->list); + kfree(event); + continue; + } + + if (++event->count >= ATH9K_HTC_TX_TIMEOUT_COUNT) { + list_del(&event->list); + kfree(event); + } + } + spin_unlock(&priv->wmi->event_lock); + + /* + * Check if status-pending packets have to be cleaned up. + */ + ath9k_htc_tx_cleanup_queue(priv, &priv->tx.mgmt_ep_queue); + ath9k_htc_tx_cleanup_queue(priv, &priv->tx.cab_ep_queue); + ath9k_htc_tx_cleanup_queue(priv, &priv->tx.data_be_queue); + ath9k_htc_tx_cleanup_queue(priv, &priv->tx.data_bk_queue); + ath9k_htc_tx_cleanup_queue(priv, &priv->tx.data_vi_queue); + ath9k_htc_tx_cleanup_queue(priv, &priv->tx.data_vo_queue); + + /* Wake TX queues if needed */ + ath9k_htc_check_wake_queues(priv); + + mod_timer(&priv->tx.cleanup_timer, + jiffies + msecs_to_jiffies(ATH9K_HTC_TX_CLEANUP_INTERVAL)); +} + int ath9k_tx_init(struct ath9k_htc_priv *priv) { skb_queue_head_init(&priv->tx.mgmt_ep_queue); diff --git a/drivers/net/wireless/ath/ath9k/wmi.c b/drivers/net/wireless/ath/ath9k/wmi.c index 3f5a4d1..697e5af 100644 --- a/drivers/net/wireless/ath/ath9k/wmi.c +++ b/drivers/net/wireless/ath/ath9k/wmi.c @@ -91,9 +91,12 @@ struct wmi *ath9k_init_wmi(struct ath9k_htc_priv *priv) wmi->drv_priv = priv; wmi->stopped = false; skb_queue_head_init(&wmi->wmi_event_queue); + spin_lock_init(&wmi->wmi_lock); + spin_lock_init(&wmi->event_lock); mutex_init(&wmi->op_mutex); mutex_init(&wmi->multi_write_mutex); init_completion(&wmi->cmd_wait); + INIT_LIST_HEAD(&wmi->pending_tx_events); tasklet_init(&wmi->wmi_event_tasklet, ath9k_wmi_event_tasklet, (unsigned long)wmi); diff --git a/drivers/net/wireless/ath/ath9k/wmi.h b/drivers/net/wireless/ath/ath9k/wmi.h index 44b1738..310d94e 100644 --- a/drivers/net/wireless/ath/ath9k/wmi.h +++ b/drivers/net/wireless/ath/ath9k/wmi.h @@ -130,6 +130,12 @@ struct register_write { __be32 val; }; +struct ath9k_htc_tx_event { + int count; + struct __wmi_event_txstatus txs; + struct list_head list; +}; + struct wmi { struct ath9k_htc_priv *drv_priv; struct htc_target *htc; @@ -144,6 +150,9 @@ struct wmi { u32 cmd_rsp_len; bool stopped; + struct list_head pending_tx_events; + spinlock_t event_lock; + spinlock_t wmi_lock; atomic_t mwrite_cnt; -- cgit v0.10.2 From 2f80194c90caea3668d0e3739518bf100449a813 Mon Sep 17 00:00:00 2001 From: Sujith Manoharan Date: Wed, 13 Apr 2011 11:26:46 +0530 Subject: ath9k_htc: Use separate URB pool for management frames Beacon transmission needs to involve as little latency as possible after receiving a SWBA event from the target. Since packets are buffered to use TX stream mode, beacon frames sometimes gets queued up and are not sent out immediately. Fix this by decoupling management frame transmission from the normal data path and send them out immediately. Signed-off-by: Sujith Manoharan Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/hif_usb.c b/drivers/net/wireless/ath/ath9k/hif_usb.c index 7fae79d..3b0efab 100644 --- a/drivers/net/wireless/ath/ath9k/hif_usb.c +++ b/drivers/net/wireless/ath/ath9k/hif_usb.c @@ -78,7 +78,7 @@ static void hif_usb_regout_cb(struct urb *urb) if (cmd) { ath9k_htc_txcompletion_cb(cmd->hif_dev->htc_handle, - cmd->skb, 1); + cmd->skb, true); kfree(cmd); } @@ -124,6 +124,90 @@ static int hif_usb_send_regout(struct hif_device_usb *hif_dev, return ret; } +static void hif_usb_mgmt_cb(struct urb *urb) +{ + struct cmd_buf *cmd = (struct cmd_buf *)urb->context; + struct hif_device_usb *hif_dev = cmd->hif_dev; + bool txok = true; + + if (!cmd || !cmd->skb || !cmd->hif_dev) + return; + + switch (urb->status) { + case 0: + break; + case -ENOENT: + case -ECONNRESET: + case -ENODEV: + case -ESHUTDOWN: + txok = false; + + /* + * If the URBs are being flushed, no need to complete + * this packet. + */ + spin_lock(&hif_dev->tx.tx_lock); + if (hif_dev->tx.flags & HIF_USB_TX_FLUSH) { + spin_unlock(&hif_dev->tx.tx_lock); + dev_kfree_skb_any(cmd->skb); + kfree(cmd); + return; + } + spin_unlock(&hif_dev->tx.tx_lock); + + break; + default: + txok = false; + break; + } + + skb_pull(cmd->skb, 4); + ath9k_htc_txcompletion_cb(cmd->hif_dev->htc_handle, + cmd->skb, txok); + kfree(cmd); +} + +static int hif_usb_send_mgmt(struct hif_device_usb *hif_dev, + struct sk_buff *skb) +{ + struct urb *urb; + struct cmd_buf *cmd; + int ret = 0; + __le16 *hdr; + + urb = usb_alloc_urb(0, GFP_ATOMIC); + if (urb == NULL) + return -ENOMEM; + + cmd = kzalloc(sizeof(*cmd), GFP_ATOMIC); + if (cmd == NULL) { + usb_free_urb(urb); + return -ENOMEM; + } + + cmd->skb = skb; + cmd->hif_dev = hif_dev; + + hdr = (__le16 *) skb_push(skb, 4); + *hdr++ = cpu_to_le16(skb->len - 4); + *hdr++ = cpu_to_le16(ATH_USB_TX_STREAM_MODE_TAG); + + usb_fill_bulk_urb(urb, hif_dev->udev, + usb_sndbulkpipe(hif_dev->udev, USB_WLAN_TX_PIPE), + skb->data, skb->len, + hif_usb_mgmt_cb, cmd); + + usb_anchor_urb(urb, &hif_dev->mgmt_submitted); + ret = usb_submit_urb(urb, GFP_ATOMIC); + if (ret) { + usb_unanchor_urb(urb); + kfree(cmd); + } + usb_free_urb(urb); + + return ret; +} + static inline void ath9k_skb_queue_purge(struct hif_device_usb *hif_dev, struct sk_buff_head *list) { @@ -275,6 +359,7 @@ static int hif_usb_send_tx(struct hif_device_usb *hif_dev, struct sk_buff *skb) { struct ath9k_htc_tx_ctl *tx_ctl; unsigned long flags; + int ret = 0; spin_lock_irqsave(&hif_dev->tx.tx_lock, flags); @@ -289,25 +374,33 @@ static int hif_usb_send_tx(struct hif_device_usb *hif_dev, struct sk_buff *skb) return -ENOMEM; } - __skb_queue_tail(&hif_dev->tx.tx_skb_queue, skb); - hif_dev->tx.tx_skb_cnt++; + spin_unlock_irqrestore(&hif_dev->tx.tx_lock, flags); tx_ctl = HTC_SKB_CB(skb); - /* Send normal/mgmt/beacon frames immediately */ - if (tx_ctl->type != ATH9K_HTC_AMPDU) - __hif_usb_tx(hif_dev); + /* Mgmt/Beacon frames don't use the TX buffer pool */ + if ((tx_ctl->type == ATH9K_HTC_MGMT) || + (tx_ctl->type == ATH9K_HTC_BEACON)) { + ret = hif_usb_send_mgmt(hif_dev, skb); + } + + spin_lock_irqsave(&hif_dev->tx.tx_lock, flags); + + if ((tx_ctl->type == ATH9K_HTC_NORMAL) || + (tx_ctl->type == ATH9K_HTC_AMPDU)) { + __skb_queue_tail(&hif_dev->tx.tx_skb_queue, skb); + hif_dev->tx.tx_skb_cnt++; + } /* Check if AMPDUs have to be sent immediately */ - if ((tx_ctl->type == ATH9K_HTC_AMPDU) && - (hif_dev->tx.tx_buf_cnt == MAX_TX_URB_NUM) && + if ((hif_dev->tx.tx_buf_cnt == MAX_TX_URB_NUM) && (hif_dev->tx.tx_skb_cnt < 2)) { __hif_usb_tx(hif_dev); } spin_unlock_irqrestore(&hif_dev->tx.tx_lock, flags); - return 0; + return ret; } static void hif_usb_start(void *hif_handle) @@ -339,6 +432,8 @@ static void hif_usb_stop(void *hif_handle) &hif_dev->tx.tx_pending, list) { usb_kill_urb(tx_buf->urb); } + + usb_kill_anchored_urbs(&hif_dev->mgmt_submitted); } static int hif_usb_send(void *hif_handle, u8 pipe_id, struct sk_buff *skb) @@ -657,6 +752,8 @@ static void ath9k_hif_usb_dealloc_tx_urbs(struct hif_device_usb *hif_dev) kfree(tx_buf->buf); kfree(tx_buf); } + + usb_kill_anchored_urbs(&hif_dev->mgmt_submitted); } static int ath9k_hif_usb_alloc_tx_urbs(struct hif_device_usb *hif_dev) @@ -668,6 +765,7 @@ static int ath9k_hif_usb_alloc_tx_urbs(struct hif_device_usb *hif_dev) INIT_LIST_HEAD(&hif_dev->tx.tx_pending); spin_lock_init(&hif_dev->tx.tx_lock); __skb_queue_head_init(&hif_dev->tx.tx_skb_queue); + init_usb_anchor(&hif_dev->mgmt_submitted); for (i = 0; i < MAX_TX_URB_NUM; i++) { tx_buf = kzalloc(sizeof(struct tx_buf), GFP_KERNEL); diff --git a/drivers/net/wireless/ath/ath9k/hif_usb.h b/drivers/net/wireless/ath/ath9k/hif_usb.h index 8b98d64..f59df48 100644 --- a/drivers/net/wireless/ath/ath9k/hif_usb.h +++ b/drivers/net/wireless/ath/ath9k/hif_usb.h @@ -93,6 +93,7 @@ struct hif_device_usb { struct usb_anchor regout_submitted; struct usb_anchor rx_submitted; struct usb_anchor reg_in_submitted; + struct usb_anchor mgmt_submitted; struct sk_buff *remain_skb; const char *fw_name; int rx_remain_len; -- cgit v0.10.2 From 821f9414c0546fbc99a999e9dc613d1756e1de8a Mon Sep 17 00:00:00 2001 From: Sujith Manoharan Date: Wed, 13 Apr 2011 11:26:52 +0530 Subject: ath9k_htc: Use helper routines for transmission Signed-off-by: Sujith Manoharan Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c b/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c index 86f5ce9..723a3a9 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c @@ -211,28 +211,140 @@ int ath_htc_txq_update(struct ath9k_htc_priv *priv, int qnum, return error; } +static void ath9k_htc_tx_mgmt(struct ath9k_htc_priv *priv, + struct ath9k_htc_vif *avp, + struct sk_buff *skb, + u8 sta_idx, u8 vif_idx, u8 slot) +{ + struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); + struct ieee80211_mgmt *mgmt; + struct ieee80211_hdr *hdr; + struct tx_mgmt_hdr mgmt_hdr; + struct ath9k_htc_tx_ctl *tx_ctl; + u8 *tx_fhdr; + + tx_ctl = HTC_SKB_CB(skb); + hdr = (struct ieee80211_hdr *) skb->data; + + memset(tx_ctl, 0, sizeof(*tx_ctl)); + memset(&mgmt_hdr, 0, sizeof(struct tx_mgmt_hdr)); + + /* + * Set the TSF adjust value for probe response + * frame also. + */ + if (avp && unlikely(ieee80211_is_probe_resp(hdr->frame_control))) { + mgmt = (struct ieee80211_mgmt *)skb->data; + mgmt->u.probe_resp.timestamp = avp->tsfadjust; + } + + tx_ctl->type = ATH9K_HTC_MGMT; + + mgmt_hdr.node_idx = sta_idx; + mgmt_hdr.vif_idx = vif_idx; + mgmt_hdr.tidno = 0; + mgmt_hdr.flags = 0; + mgmt_hdr.cookie = slot; + + mgmt_hdr.key_type = ath9k_cmn_get_hw_crypto_keytype(skb); + if (mgmt_hdr.key_type == ATH9K_KEY_TYPE_CLEAR) + mgmt_hdr.keyix = (u8) ATH9K_TXKEYIX_INVALID; + else + mgmt_hdr.keyix = tx_info->control.hw_key->hw_key_idx; + + tx_fhdr = skb_push(skb, sizeof(mgmt_hdr)); + memcpy(tx_fhdr, (u8 *) &mgmt_hdr, sizeof(mgmt_hdr)); + tx_ctl->epid = priv->mgmt_ep; +} + +static void ath9k_htc_tx_data(struct ath9k_htc_priv *priv, + struct ieee80211_vif *vif, + struct sk_buff *skb, + u8 sta_idx, u8 vif_idx, u8 slot, + bool is_cab) +{ + struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); + struct ieee80211_hdr *hdr; + struct ath9k_htc_tx_ctl *tx_ctl; + struct tx_frame_hdr tx_hdr; + u32 flags = 0; + u8 *qc, *tx_fhdr; + u16 qnum; + + tx_ctl = HTC_SKB_CB(skb); + hdr = (struct ieee80211_hdr *) skb->data; + + memset(tx_ctl, 0, sizeof(*tx_ctl)); + memset(&tx_hdr, 0, sizeof(struct tx_frame_hdr)); + + tx_hdr.node_idx = sta_idx; + tx_hdr.vif_idx = vif_idx; + tx_hdr.cookie = slot; + + /* + * This is a bit redundant but it helps to get + * the per-packet index quickly when draining the + * TX queue in the HIF layer. Otherwise we would + * have to parse the packet contents ... + */ + tx_ctl->sta_idx = sta_idx; + + if (tx_info->flags & IEEE80211_TX_CTL_AMPDU) { + tx_ctl->type = ATH9K_HTC_AMPDU; + tx_hdr.data_type = ATH9K_HTC_AMPDU; + } else { + tx_ctl->type = ATH9K_HTC_NORMAL; + tx_hdr.data_type = ATH9K_HTC_NORMAL; + } + + if (ieee80211_is_data_qos(hdr->frame_control)) { + qc = ieee80211_get_qos_ctl(hdr); + tx_hdr.tidno = qc[0] & IEEE80211_QOS_CTL_TID_MASK; + } + + /* Check for RTS protection */ + if (priv->hw->wiphy->rts_threshold != (u32) -1) + if (skb->len > priv->hw->wiphy->rts_threshold) + flags |= ATH9K_HTC_TX_RTSCTS; + + /* CTS-to-self */ + if (!(flags & ATH9K_HTC_TX_RTSCTS) && + (vif && vif->bss_conf.use_cts_prot)) + flags |= ATH9K_HTC_TX_CTSONLY; + + tx_hdr.flags = cpu_to_be32(flags); + tx_hdr.key_type = ath9k_cmn_get_hw_crypto_keytype(skb); + if (tx_hdr.key_type == ATH9K_KEY_TYPE_CLEAR) + tx_hdr.keyix = (u8) ATH9K_TXKEYIX_INVALID; + else + tx_hdr.keyix = tx_info->control.hw_key->hw_key_idx; + + tx_fhdr = skb_push(skb, sizeof(tx_hdr)); + memcpy(tx_fhdr, (u8 *) &tx_hdr, sizeof(tx_hdr)); + + if (is_cab) { + CAB_STAT_INC; + tx_ctl->epid = priv->cab_ep; + return; + } + + qnum = skb_get_queue_mapping(skb); + tx_ctl->epid = get_htc_epid(priv, qnum); +} + int ath9k_htc_tx_start(struct ath9k_htc_priv *priv, struct sk_buff *skb, u8 slot, bool is_cab) { struct ieee80211_hdr *hdr; - struct ieee80211_mgmt *mgmt; struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); struct ieee80211_sta *sta = tx_info->control.sta; struct ieee80211_vif *vif = tx_info->control.vif; struct ath9k_htc_sta *ista; struct ath9k_htc_vif *avp = NULL; - struct ath9k_htc_tx_ctl *tx_ctl; - u16 qnum; - __le16 fc; - u8 *tx_fhdr; u8 sta_idx, vif_idx; - tx_ctl = HTC_SKB_CB(skb); - memset(tx_ctl, 0, sizeof(*tx_ctl)); - hdr = (struct ieee80211_hdr *) skb->data; - fc = hdr->frame_control; /* * Find out on which interface this packet has to be @@ -261,99 +373,14 @@ int ath9k_htc_tx_start(struct ath9k_htc_priv *priv, sta_idx = priv->vif_sta_pos[vif_idx]; } - if (ieee80211_is_data(fc)) { - struct tx_frame_hdr tx_hdr; - u32 flags = 0; - u8 *qc; - - memset(&tx_hdr, 0, sizeof(struct tx_frame_hdr)); - - tx_hdr.node_idx = sta_idx; - tx_hdr.vif_idx = vif_idx; - tx_hdr.cookie = slot; - - /* - * This is a bit redundant but it helps to get - * the per-packet index quickly when draining the - * TX queue in the HIF layer. Otherwise we would - * have to parse the packet contents ... - */ - tx_ctl->sta_idx = sta_idx; - - if (tx_info->flags & IEEE80211_TX_CTL_AMPDU) { - tx_ctl->type = ATH9K_HTC_AMPDU; - tx_hdr.data_type = ATH9K_HTC_AMPDU; - } else { - tx_ctl->type = ATH9K_HTC_NORMAL; - tx_hdr.data_type = ATH9K_HTC_NORMAL; - } - - if (ieee80211_is_data_qos(fc)) { - qc = ieee80211_get_qos_ctl(hdr); - tx_hdr.tidno = qc[0] & IEEE80211_QOS_CTL_TID_MASK; - } - - /* Check for RTS protection */ - if (priv->hw->wiphy->rts_threshold != (u32) -1) - if (skb->len > priv->hw->wiphy->rts_threshold) - flags |= ATH9K_HTC_TX_RTSCTS; - - /* CTS-to-self */ - if (!(flags & ATH9K_HTC_TX_RTSCTS) && - (vif && vif->bss_conf.use_cts_prot)) - flags |= ATH9K_HTC_TX_CTSONLY; - - tx_hdr.flags = cpu_to_be32(flags); - tx_hdr.key_type = ath9k_cmn_get_hw_crypto_keytype(skb); - if (tx_hdr.key_type == ATH9K_KEY_TYPE_CLEAR) - tx_hdr.keyix = (u8) ATH9K_TXKEYIX_INVALID; - else - tx_hdr.keyix = tx_info->control.hw_key->hw_key_idx; - - tx_fhdr = skb_push(skb, sizeof(tx_hdr)); - memcpy(tx_fhdr, (u8 *) &tx_hdr, sizeof(tx_hdr)); - - if (is_cab) { - CAB_STAT_INC; - tx_ctl->epid = priv->cab_ep; - goto send; - } - - qnum = skb_get_queue_mapping(skb); - tx_ctl->epid = get_htc_epid(priv, qnum); - } else { - struct tx_mgmt_hdr mgmt_hdr; - - memset(&mgmt_hdr, 0, sizeof(struct tx_mgmt_hdr)); - - /* - * Set the TSF adjust value for probe response - * frame also. - */ - if (avp && unlikely(ieee80211_is_probe_resp(fc))) { - mgmt = (struct ieee80211_mgmt *)skb->data; - mgmt->u.probe_resp.timestamp = avp->tsfadjust; - } - - tx_ctl->type = ATH9K_HTC_MGMT; - - mgmt_hdr.node_idx = sta_idx; - mgmt_hdr.vif_idx = vif_idx; - mgmt_hdr.tidno = 0; - mgmt_hdr.flags = 0; - mgmt_hdr.cookie = slot; + if (ieee80211_is_data(hdr->frame_control)) + ath9k_htc_tx_data(priv, vif, skb, + sta_idx, vif_idx, slot, is_cab); + else + ath9k_htc_tx_mgmt(priv, avp, skb, + sta_idx, vif_idx, slot); - mgmt_hdr.key_type = ath9k_cmn_get_hw_crypto_keytype(skb); - if (mgmt_hdr.key_type == ATH9K_KEY_TYPE_CLEAR) - mgmt_hdr.keyix = (u8) ATH9K_TXKEYIX_INVALID; - else - mgmt_hdr.keyix = tx_info->control.hw_key->hw_key_idx; - tx_fhdr = skb_push(skb, sizeof(mgmt_hdr)); - memcpy(tx_fhdr, (u8 *) &mgmt_hdr, sizeof(mgmt_hdr)); - tx_ctl->epid = priv->mgmt_ep; - } -send: return htc_send(priv->htc, skb); } -- cgit v0.10.2 From fbc29d6c3da58bc51416f65a50bdb419d4ea85b8 Mon Sep 17 00:00:00 2001 From: Sujith Manoharan Date: Wed, 13 Apr 2011 11:26:58 +0530 Subject: ath9k_htc: Add detailed firmware statistics New debugfs files: /ath9k_htc//tgt_int_stats /ath9k_htc//tgt_tx_stats /ath9k_htc//tgt_rx_stats Signed-off-by: Sujith Manoharan Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/htc.h b/drivers/net/wireless/ath/ath9k/htc.h index b413b46..cc5d0a4 100644 --- a/drivers/net/wireless/ath/ath9k/htc.h +++ b/drivers/net/wireless/ath/ath9k/htc.h @@ -175,12 +175,31 @@ struct ath9k_htc_target_rate { struct ath9k_htc_rate rates; }; -struct ath9k_htc_target_stats { - __be32 tx_shortretry; - __be32 tx_longretry; - __be32 tx_xretries; - __be32 ht_txunaggr_xretry; - __be32 ht_tx_xretries; +struct ath9k_htc_target_int_stats { + __be32 rx; + __be32 rxorn; + __be32 rxeol; + __be32 txurn; + __be32 txto; + __be32 cst; +} __packed; + +struct ath9k_htc_target_tx_stats { + __be32 xretries; + __be32 fifoerr; + __be32 filtered; + __be32 timer_exp; + __be32 shortretries; + __be32 longretries; + __be32 qnull; + __be32 encap_fail; + __be32 nobuf; +} __packed; + +struct ath9k_htc_target_rx_stats { + __be32 nobuf; + __be32 host_send; + __be32 host_done; } __packed; #define ATH9K_HTC_MAX_VIF 2 @@ -340,14 +359,15 @@ struct ath_rx_stats { struct ath9k_debug { struct dentry *debugfs_phy; - struct dentry *debugfs_tgt_stats; + struct dentry *debugfs_tgt_int_stats; + struct dentry *debugfs_tgt_tx_stats; + struct dentry *debugfs_tgt_rx_stats; struct dentry *debugfs_xmit; struct dentry *debugfs_recv; struct dentry *debugfs_slot; struct dentry *debugfs_queue; struct ath_tx_stats tx_stats; struct ath_rx_stats rx_stats; - u32 txrate; }; #else diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_debug.c b/drivers/net/wireless/ath/ath9k/htc_drv_debug.c index 961bec2..8d0de60 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_debug.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_debug.c @@ -24,39 +24,108 @@ static int ath9k_debugfs_open(struct inode *inode, struct file *file) return 0; } -static ssize_t read_file_tgt_stats(struct file *file, char __user *user_buf, - size_t count, loff_t *ppos) +static ssize_t read_file_tgt_int_stats(struct file *file, char __user *user_buf, + size_t count, loff_t *ppos) { struct ath9k_htc_priv *priv = file->private_data; - struct ath9k_htc_target_stats cmd_rsp; + struct ath9k_htc_target_int_stats cmd_rsp; char buf[512]; unsigned int len = 0; int ret = 0; memset(&cmd_rsp, 0, sizeof(cmd_rsp)); - WMI_CMD(WMI_TGT_STATS_CMDID); + WMI_CMD(WMI_INT_STATS_CMDID); if (ret) return -EINVAL; + len += snprintf(buf + len, sizeof(buf) - len, + "%20s : %10u\n", "RX", + be32_to_cpu(cmd_rsp.rx)); + + len += snprintf(buf + len, sizeof(buf) - len, + "%20s : %10u\n", "RXORN", + be32_to_cpu(cmd_rsp.rxorn)); + + len += snprintf(buf + len, sizeof(buf) - len, + "%20s : %10u\n", "RXEOL", + be32_to_cpu(cmd_rsp.rxeol)); + + len += snprintf(buf + len, sizeof(buf) - len, + "%20s : %10u\n", "TXURN", + be32_to_cpu(cmd_rsp.txurn)); + + len += snprintf(buf + len, sizeof(buf) - len, + "%20s : %10u\n", "TXTO", + be32_to_cpu(cmd_rsp.txto)); + + len += snprintf(buf + len, sizeof(buf) - len, + "%20s : %10u\n", "CST", + be32_to_cpu(cmd_rsp.cst)); + + if (len > sizeof(buf)) + len = sizeof(buf); + + return simple_read_from_buffer(user_buf, count, ppos, buf, len); +} + +static const struct file_operations fops_tgt_int_stats = { + .read = read_file_tgt_int_stats, + .open = ath9k_debugfs_open, + .owner = THIS_MODULE, + .llseek = default_llseek, +}; + +static ssize_t read_file_tgt_tx_stats(struct file *file, char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct ath9k_htc_priv *priv = file->private_data; + struct ath9k_htc_target_tx_stats cmd_rsp; + char buf[512]; + unsigned int len = 0; + int ret = 0; + + memset(&cmd_rsp, 0, sizeof(cmd_rsp)); + + WMI_CMD(WMI_TX_STATS_CMDID); + if (ret) + return -EINVAL; + + len += snprintf(buf + len, sizeof(buf) - len, + "%20s : %10u\n", "Xretries", + be32_to_cpu(cmd_rsp.xretries)); + + len += snprintf(buf + len, sizeof(buf) - len, + "%20s : %10u\n", "FifoErr", + be32_to_cpu(cmd_rsp.fifoerr)); + + len += snprintf(buf + len, sizeof(buf) - len, + "%20s : %10u\n", "Filtered", + be32_to_cpu(cmd_rsp.filtered)); len += snprintf(buf + len, sizeof(buf) - len, - "%19s : %10u\n", "TX Short Retries", - be32_to_cpu(cmd_rsp.tx_shortretry)); + "%20s : %10u\n", "TimerExp", + be32_to_cpu(cmd_rsp.timer_exp)); + len += snprintf(buf + len, sizeof(buf) - len, - "%19s : %10u\n", "TX Long Retries", - be32_to_cpu(cmd_rsp.tx_longretry)); + "%20s : %10u\n", "ShortRetries", + be32_to_cpu(cmd_rsp.shortretries)); + len += snprintf(buf + len, sizeof(buf) - len, - "%19s : %10u\n", "TX Xretries", - be32_to_cpu(cmd_rsp.tx_xretries)); + "%20s : %10u\n", "LongRetries", + be32_to_cpu(cmd_rsp.longretries)); + len += snprintf(buf + len, sizeof(buf) - len, - "%19s : %10u\n", "TX Unaggr. Xretries", - be32_to_cpu(cmd_rsp.ht_txunaggr_xretry)); + "%20s : %10u\n", "QueueNull", + be32_to_cpu(cmd_rsp.qnull)); + len += snprintf(buf + len, sizeof(buf) - len, - "%19s : %10u\n", "TX Xretries (HT)", - be32_to_cpu(cmd_rsp.ht_tx_xretries)); + "%20s : %10u\n", "EncapFail", + be32_to_cpu(cmd_rsp.encap_fail)); + len += snprintf(buf + len, sizeof(buf) - len, - "%19s : %10u\n", "TX Rate", priv->debug.txrate); + "%20s : %10u\n", "NoBuf", + be32_to_cpu(cmd_rsp.nobuf)); if (len > sizeof(buf)) len = sizeof(buf); @@ -64,8 +133,48 @@ static ssize_t read_file_tgt_stats(struct file *file, char __user *user_buf, return simple_read_from_buffer(user_buf, count, ppos, buf, len); } -static const struct file_operations fops_tgt_stats = { - .read = read_file_tgt_stats, +static const struct file_operations fops_tgt_tx_stats = { + .read = read_file_tgt_tx_stats, + .open = ath9k_debugfs_open, + .owner = THIS_MODULE, + .llseek = default_llseek, +}; + +static ssize_t read_file_tgt_rx_stats(struct file *file, char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct ath9k_htc_priv *priv = file->private_data; + struct ath9k_htc_target_rx_stats cmd_rsp; + char buf[512]; + unsigned int len = 0; + int ret = 0; + + memset(&cmd_rsp, 0, sizeof(cmd_rsp)); + + WMI_CMD(WMI_RX_STATS_CMDID); + if (ret) + return -EINVAL; + + len += snprintf(buf + len, sizeof(buf) - len, + "%20s : %10u\n", "NoBuf", + be32_to_cpu(cmd_rsp.nobuf)); + + len += snprintf(buf + len, sizeof(buf) - len, + "%20s : %10u\n", "HostSend", + be32_to_cpu(cmd_rsp.host_send)); + + len += snprintf(buf + len, sizeof(buf) - len, + "%20s : %10u\n", "HostDone", + be32_to_cpu(cmd_rsp.host_done)); + + if (len > sizeof(buf)) + len = sizeof(buf); + + return simple_read_from_buffer(user_buf, count, ppos, buf, len); +} + +static const struct file_operations fops_tgt_rx_stats = { + .read = read_file_tgt_rx_stats, .open = ath9k_debugfs_open, .owner = THIS_MODULE, .llseek = default_llseek, @@ -286,29 +395,29 @@ static ssize_t read_file_queue(struct file *file, char __user *user_buf, char buf[512]; unsigned int len = 0; - len += snprintf(buf + len, sizeof(buf) - len, "%16s : %3d\n", + len += snprintf(buf + len, sizeof(buf) - len, "%20s : %10u\n", "Mgmt endpoint", skb_queue_len(&priv->tx.mgmt_ep_queue)); - len += snprintf(buf + len, sizeof(buf) - len, "%16s : %3d\n", + len += snprintf(buf + len, sizeof(buf) - len, "%20s : %10u\n", "Cab endpoint", skb_queue_len(&priv->tx.cab_ep_queue)); - len += snprintf(buf + len, sizeof(buf) - len, "%16s : %3d\n", + len += snprintf(buf + len, sizeof(buf) - len, "%20s : %10u\n", "Data BE endpoint", skb_queue_len(&priv->tx.data_be_queue)); - len += snprintf(buf + len, sizeof(buf) - len, "%16s : %3d\n", + len += snprintf(buf + len, sizeof(buf) - len, "%20s : %10u\n", "Data BK endpoint", skb_queue_len(&priv->tx.data_bk_queue)); - len += snprintf(buf + len, sizeof(buf) - len, "%16s : %3d\n", + len += snprintf(buf + len, sizeof(buf) - len, "%20s : %10u\n", "Data VI endpoint", skb_queue_len(&priv->tx.data_vi_queue)); - len += snprintf(buf + len, sizeof(buf) - len, "%16s : %3d\n", + len += snprintf(buf + len, sizeof(buf) - len, "%20s : %10u\n", "Data VO endpoint", skb_queue_len(&priv->tx.data_vo_queue)); - len += snprintf(buf + len, sizeof(buf) - len, "%16s : %3d\n", + len += snprintf(buf + len, sizeof(buf) - len, "%20s : %10u\n", "Failed queue", skb_queue_len(&priv->tx.tx_failed)); spin_lock_bh(&priv->tx.tx_lock); - len += snprintf(buf + len, sizeof(buf) - len, "%16s : %3d\n", + len += snprintf(buf + len, sizeof(buf) - len, "%20s : %10u\n", "Queued count", priv->tx.queued_cnt); spin_unlock_bh(&priv->tx.tx_lock); @@ -339,12 +448,26 @@ int ath9k_htc_init_debug(struct ath_hw *ah) if (!priv->debug.debugfs_phy) goto err; - priv->debug.debugfs_tgt_stats = debugfs_create_file("tgt_stats", S_IRUSR, - priv->debug.debugfs_phy, - priv, &fops_tgt_stats); - if (!priv->debug.debugfs_tgt_stats) + priv->debug.debugfs_tgt_int_stats = debugfs_create_file("tgt_int_stats", + S_IRUSR, + priv->debug.debugfs_phy, + priv, &fops_tgt_int_stats); + if (!priv->debug.debugfs_tgt_int_stats) goto err; + priv->debug.debugfs_tgt_tx_stats = debugfs_create_file("tgt_tx_stats", + S_IRUSR, + priv->debug.debugfs_phy, + priv, &fops_tgt_tx_stats); + if (!priv->debug.debugfs_tgt_tx_stats) + goto err; + + priv->debug.debugfs_tgt_rx_stats = debugfs_create_file("tgt_rx_stats", + S_IRUSR, + priv->debug.debugfs_phy, + priv, &fops_tgt_rx_stats); + if (!priv->debug.debugfs_tgt_rx_stats) + goto err; priv->debug.debugfs_xmit = debugfs_create_file("xmit", S_IRUSR, priv->debug.debugfs_phy, @@ -386,7 +509,9 @@ void ath9k_htc_exit_debug(struct ath_hw *ah) debugfs_remove(priv->debug.debugfs_slot); debugfs_remove(priv->debug.debugfs_recv); debugfs_remove(priv->debug.debugfs_xmit); - debugfs_remove(priv->debug.debugfs_tgt_stats); + debugfs_remove(priv->debug.debugfs_tgt_int_stats); + debugfs_remove(priv->debug.debugfs_tgt_tx_stats); + debugfs_remove(priv->debug.debugfs_tgt_rx_stats); debugfs_remove(priv->debug.debugfs_phy); } diff --git a/drivers/net/wireless/ath/ath9k/wmi.c b/drivers/net/wireless/ath/ath9k/wmi.c index 697e5af..8f095ad 100644 --- a/drivers/net/wireless/ath/ath9k/wmi.c +++ b/drivers/net/wireless/ath/ath9k/wmi.c @@ -67,12 +67,18 @@ static const char *wmi_cmd_to_name(enum wmi_cmd_id wmi_cmd) return "WMI_RC_RATE_UPDATE_CMDID"; case WMI_TARGET_IC_UPDATE_CMDID: return "WMI_TARGET_IC_UPDATE_CMDID"; - case WMI_TGT_STATS_CMDID: - return "WMI_TGT_STATS_CMDID"; case WMI_TX_AGGR_ENABLE_CMDID: return "WMI_TX_AGGR_ENABLE_CMDID"; case WMI_TGT_DETACH_CMDID: return "WMI_TGT_DETACH_CMDID"; + case WMI_NODE_UPDATE_CMDID: + return "WMI_NODE_UPDATE_CMDID"; + case WMI_INT_STATS_CMDID: + return "WMI_INT_STATS_CMDID"; + case WMI_TX_STATS_CMDID: + return "WMI_TX_STATS_CMDID"; + case WMI_RX_STATS_CMDID: + return "WMI_RX_STATS_CMDID"; case WMI_AGGR_LIMIT_CMD: return "WMI_AGGR_LIMIT_CMD"; } @@ -134,9 +140,6 @@ void ath9k_wmi_event_tasklet(unsigned long data) struct sk_buff *skb = NULL; unsigned long flags; u16 cmd_id; -#ifdef CONFIG_ATH9K_HTC_DEBUGFS - __be32 txrate; -#endif do { spin_lock_irqsave(&wmi->wmi_lock, flags); @@ -160,12 +163,6 @@ void ath9k_wmi_event_tasklet(unsigned long data) ieee80211_queue_work(wmi->drv_priv->hw, &wmi->drv_priv->fatal_work); break; - case WMI_TXRATE_EVENTID: -#ifdef CONFIG_ATH9K_HTC_DEBUGFS - txrate = ((struct wmi_event_txrate *)wmi_event)->txrate; - wmi->drv_priv->debug.txrate = be32_to_cpu(txrate); -#endif - break; case WMI_TXSTATUS_EVENTID: spin_lock_bh(&priv->tx.tx_lock); if (priv->tx.flags & ATH9K_HTC_OP_TX_DRAIN) { diff --git a/drivers/net/wireless/ath/ath9k/wmi.h b/drivers/net/wireless/ath/ath9k/wmi.h index 310d94e..02ecb9f 100644 --- a/drivers/net/wireless/ath/ath9k/wmi.h +++ b/drivers/net/wireless/ath/ath9k/wmi.h @@ -17,7 +17,6 @@ #ifndef WMI_H #define WMI_H - struct wmi_event_txrate { __be32 txrate; struct { @@ -106,9 +105,12 @@ enum wmi_cmd_id { WMI_RC_STATE_CHANGE_CMDID, WMI_RC_RATE_UPDATE_CMDID, WMI_TARGET_IC_UPDATE_CMDID, - WMI_TGT_STATS_CMDID, WMI_TX_AGGR_ENABLE_CMDID, WMI_TGT_DETACH_CMDID, + WMI_NODE_UPDATE_CMDID, + WMI_INT_STATS_CMDID, + WMI_TX_STATS_CMDID, + WMI_RX_STATS_CMDID, WMI_AGGR_LIMIT_CMD = 0x0026, }; @@ -119,7 +121,6 @@ enum wmi_event_id { WMI_TXTO_EVENTID, WMI_BMISS_EVENTID, WMI_DELBA_EVENTID, - WMI_TXRATE_EVENTID, WMI_TXSTATUS_EVENTID, }; -- cgit v0.10.2 From 09d5b94d2cbc6c3ebb70a9a318f6390d0b4cf010 Mon Sep 17 00:00:00 2001 From: Sujith Manoharan Date: Wed, 13 Apr 2011 11:27:06 +0530 Subject: ath9k_htc: Enable AP and P2P modes Signed-off-by: Sujith Manoharan Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_init.c b/drivers/net/wireless/ath/ath9k/htc_drv_init.c index 0aec259..22736eb 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_init.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_init.c @@ -752,7 +752,10 @@ static void ath9k_set_hw_capab(struct ath9k_htc_priv *priv, hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) | - BIT(NL80211_IFTYPE_ADHOC); + BIT(NL80211_IFTYPE_ADHOC) | + BIT(NL80211_IFTYPE_AP) | + BIT(NL80211_IFTYPE_P2P_GO) | + BIT(NL80211_IFTYPE_P2P_CLIENT); hw->wiphy->flags &= ~WIPHY_FLAG_PS_ON_BY_DEFAULT; -- cgit v0.10.2 From a3e6b12c0232748658a602eda39f12fddb254ba8 Mon Sep 17 00:00:00 2001 From: cozybit Inc Date: Wed, 13 Apr 2011 11:10:28 -0700 Subject: mac80211: Allocate new mesh path and portal tables before taking locks It is unnecessary to hold the path table resize lock while allocating a new table. Allocate first and take lock later. This resolves a soft-lockup: [ 293.385799] BUG: soft lockup - CPU#0 stuck for 61s! [kworker/u:3:744] (...) [ 293.386049] Call Trace: [ 293.386049] [] do_raw_read_lock+0x26/0x29 [ 293.386049] [] _raw_read_lock+0x8/0xa [ 293.386049] [] mesh_path_add+0xb7/0x24e [ 293.386049] [] ? mesh_path_lookup+0x1b/0xa6 [ 293.386049] [] hwmp_route_info_get+0x276/0x2fd [ 293.386049] [] mesh_rx_path_sel_frame+0x5a/0x5d9 [ 293.386049] [] ? update_curr+0x1cf/0x1d7 [ 293.386049] [] ieee80211_mesh_rx_queued_mgmt+0x60/0x67 [ 293.386049] [] ieee80211_iface_work+0x1f0/0x258 (...) Signed-off-by: Javier Cardona Signed-off-by: John W. Linville diff --git a/net/mac80211/mesh_pathtbl.c b/net/mac80211/mesh_pathtbl.c index 8d65b47..7776ae5 100644 --- a/net/mac80211/mesh_pathtbl.c +++ b/net/mac80211/mesh_pathtbl.c @@ -65,42 +65,37 @@ void mesh_table_free(struct mesh_table *tbl, bool free_leafs) __mesh_table_free(tbl); } -static struct mesh_table *mesh_table_grow(struct mesh_table *tbl) +static int mesh_table_grow(struct mesh_table *oldtbl, + struct mesh_table *newtbl) { - struct mesh_table *newtbl; struct hlist_head *oldhash; struct hlist_node *p, *q; int i; - if (atomic_read(&tbl->entries) - < tbl->mean_chain_len * (tbl->hash_mask + 1)) - goto endgrow; + if (atomic_read(&oldtbl->entries) + < oldtbl->mean_chain_len * (oldtbl->hash_mask + 1)) + return -EAGAIN; - newtbl = mesh_table_alloc(tbl->size_order + 1); - if (!newtbl) - goto endgrow; - newtbl->free_node = tbl->free_node; - newtbl->mean_chain_len = tbl->mean_chain_len; - newtbl->copy_node = tbl->copy_node; - atomic_set(&newtbl->entries, atomic_read(&tbl->entries)); + newtbl->free_node = oldtbl->free_node; + newtbl->mean_chain_len = oldtbl->mean_chain_len; + newtbl->copy_node = oldtbl->copy_node; + atomic_set(&newtbl->entries, atomic_read(&oldtbl->entries)); - oldhash = tbl->hash_buckets; - for (i = 0; i <= tbl->hash_mask; i++) + oldhash = oldtbl->hash_buckets; + for (i = 0; i <= oldtbl->hash_mask; i++) hlist_for_each(p, &oldhash[i]) - if (tbl->copy_node(p, newtbl) < 0) + if (oldtbl->copy_node(p, newtbl) < 0) goto errcopy; - return newtbl; + return 0; errcopy: for (i = 0; i <= newtbl->hash_mask; i++) { hlist_for_each_safe(p, q, &newtbl->hash_buckets[i]) - tbl->free_node(p, 0); + oldtbl->free_node(p, 0); } - __mesh_table_free(newtbl); -endgrow: - return NULL; + return -ENOMEM; } @@ -334,10 +329,13 @@ void mesh_mpath_table_grow(void) { struct mesh_table *oldtbl, *newtbl; + newtbl = mesh_table_alloc(mesh_paths->size_order + 1); + if (!newtbl) + return; write_lock(&pathtbl_resize_lock); oldtbl = mesh_paths; - newtbl = mesh_table_grow(mesh_paths); - if (!newtbl) { + if (mesh_table_grow(mesh_paths, newtbl) < 0) { + __mesh_table_free(newtbl); write_unlock(&pathtbl_resize_lock); return; } @@ -352,10 +350,13 @@ void mesh_mpp_table_grow(void) { struct mesh_table *oldtbl, *newtbl; + newtbl = mesh_table_alloc(mpp_paths->size_order + 1); + if (!newtbl) + return; write_lock(&pathtbl_resize_lock); oldtbl = mpp_paths; - newtbl = mesh_table_grow(mpp_paths); - if (!newtbl) { + if (mesh_table_grow(mpp_paths, newtbl) < 0) { + __mesh_table_free(newtbl); write_unlock(&pathtbl_resize_lock); return; } -- cgit v0.10.2 From 4d42d417be75d750b82798922b6e775915e11bce Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Wed, 13 Apr 2011 14:48:55 -0700 Subject: rndis_host: Poll status before control channel where necessary Some RNDIS devices don't respond on the control channel until polled on the status channel. In particular, this was reported to be the case for the 2Wire HomePortal 1000SW and for some Windows Mobile devices. This is roughly based on a patch by John Carr which is currently applied by Mandriva. Reported-by: Mark Glassberg Signed-off-by: Ben Hutchings Signed-off-by: David S. Miller diff --git a/drivers/net/usb/rndis_host.c b/drivers/net/usb/rndis_host.c index 5994a25..6d6c1da 100644 --- a/drivers/net/usb/rndis_host.c +++ b/drivers/net/usb/rndis_host.c @@ -104,8 +104,10 @@ static void rndis_msg_indicate(struct usbnet *dev, struct rndis_indicate *msg, int rndis_command(struct usbnet *dev, struct rndis_msg_hdr *buf, int buflen) { struct cdc_state *info = (void *) &dev->data; + struct usb_cdc_notification notification; int master_ifnum; int retval; + int partial; unsigned count; __le32 rsp; u32 xid = 0, msg_len, request_id; @@ -133,13 +135,20 @@ int rndis_command(struct usbnet *dev, struct rndis_msg_hdr *buf, int buflen) if (unlikely(retval < 0 || xid == 0)) return retval; - // FIXME Seems like some devices discard responses when - // we time out and cancel our "get response" requests... - // so, this is fragile. Probably need to poll for status. + /* Some devices don't respond on the control channel until + * polled on the status channel, so do that first. */ + if (dev->driver_info->data & RNDIS_DRIVER_DATA_POLL_STATUS) { + retval = usb_interrupt_msg( + dev->udev, + usb_rcvintpipe(dev->udev, + dev->status->desc.bEndpointAddress), + ¬ification, sizeof(notification), &partial, + RNDIS_CONTROL_TIMEOUT_MS); + if (unlikely(retval < 0)) + return retval; + } - /* ignore status endpoint, just poll the control channel; - * the request probably completed immediately - */ + /* Poll the control channel; the request probably completed immediately */ rsp = buf->msg_type | RNDIS_MSG_COMPLETION; for (count = 0; count < 10; count++) { memset(buf, 0, CONTROL_BUFFER_SIZE); @@ -581,17 +590,33 @@ static const struct driver_info rndis_info = { .tx_fixup = rndis_tx_fixup, }; +static const struct driver_info rndis_poll_status_info = { + .description = "RNDIS device (poll status before control)", + .flags = FLAG_ETHER | FLAG_FRAMING_RN | FLAG_NO_SETINT, + .data = RNDIS_DRIVER_DATA_POLL_STATUS, + .bind = rndis_bind, + .unbind = rndis_unbind, + .status = rndis_status, + .rx_fixup = rndis_rx_fixup, + .tx_fixup = rndis_tx_fixup, +}; + /*-------------------------------------------------------------------------*/ static const struct usb_device_id products [] = { { + /* 2Wire HomePortal 1000SW */ + USB_DEVICE_AND_INTERFACE_INFO(0x1630, 0x0042, + USB_CLASS_COMM, 2 /* ACM */, 0x0ff), + .driver_info = (unsigned long) &rndis_poll_status_info, +}, { /* RNDIS is MSFT's un-official variant of CDC ACM */ USB_INTERFACE_INFO(USB_CLASS_COMM, 2 /* ACM */, 0x0ff), .driver_info = (unsigned long) &rndis_info, }, { /* "ActiveSync" is an undocumented variant of RNDIS, used in WM5 */ USB_INTERFACE_INFO(USB_CLASS_MISC, 1, 1), - .driver_info = (unsigned long) &rndis_info, + .driver_info = (unsigned long) &rndis_poll_status_info, }, { /* RNDIS for tethering */ USB_INTERFACE_INFO(USB_CLASS_WIRELESS_CONTROLLER, 1, 3), diff --git a/include/linux/usb/rndis_host.h b/include/linux/usb/rndis_host.h index 05ef528..88fceb7 100644 --- a/include/linux/usb/rndis_host.h +++ b/include/linux/usb/rndis_host.h @@ -256,6 +256,8 @@ struct rndis_keepalive_c { /* IN (optionally OUT) */ #define FLAG_RNDIS_PHYM_NOT_WIRELESS 0x0001 #define FLAG_RNDIS_PHYM_WIRELESS 0x0002 +/* Flags for driver_info::data */ +#define RNDIS_DRIVER_DATA_POLL_STATUS 1 /* poll status before control */ extern void rndis_status(struct usbnet *dev, struct urb *urb); extern int -- cgit v0.10.2 From 280f294f7bd0c14d9f802a551c95dc930e31d723 Mon Sep 17 00:00:00 2001 From: "Gustavo F. Padovan" Date: Wed, 13 Apr 2011 19:01:22 -0300 Subject: Bluetooth: Don't lock sock inside l2cap_get_sock_by_scid() Fix an locking issue with the new l2cap_att_channel(). l2cap_att_channel() was trying to lock a locked socket. Reported-by: Anderson Lizardo Signed-off-by: Gustavo F. Padovan diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index c9c1f92..d5db5a3 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -594,7 +594,7 @@ static void l2cap_conn_start(struct l2cap_conn *conn) */ static struct sock *l2cap_get_sock_by_scid(int state, __le16 cid, bdaddr_t *src) { - struct sock *s, *sk = NULL, *sk1 = NULL; + struct sock *sk = NULL, *sk1 = NULL; struct hlist_node *node; read_lock(&l2cap_sk_list.lock); @@ -613,12 +613,10 @@ static struct sock *l2cap_get_sock_by_scid(int state, __le16 cid, bdaddr_t *src) sk1 = sk; } } - s = node ? sk : sk1; - if (s) - bh_lock_sock(s); + read_unlock(&l2cap_sk_list.lock); - return s; + return node ? sk : sk1; } static void l2cap_le_conn_ready(struct l2cap_conn *conn) -- cgit v0.10.2 From 97bd8e491d1786f0020372a5a470bb8b3184856f Mon Sep 17 00:00:00 2001 From: Matt Carlson Date: Wed, 13 Apr 2011 11:05:04 +0000 Subject: tg3: Provide full regdump on tx timeout The current amount of information provided in the output of a tx timeout is insufficient to determine a root cause. This patch replaces the terse, four-register status output with a more complete body of information. For PCIe devices, the full register space is dumped. For other devices, select registers are dumped instead. Signed-off-by: Matt Carlson Signed-off-by: Michael Chan Reviewed-by: Benjamin Li Signed-off-by: David S. Miller diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index 9d7defc..7274435 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -4459,6 +4459,123 @@ static inline int tg3_irq_sync(struct tg3 *tp) return tp->irq_sync; } +static inline void tg3_rd32_loop(struct tg3 *tp, u32 *dst, u32 off, u32 len) +{ + int i; + + dst = (u32 *)((u8 *)dst + off); + for (i = 0; i < len; i += sizeof(u32)) + *dst++ = tr32(off + i); +} + +static void tg3_dump_legacy_regs(struct tg3 *tp, u32 *regs) +{ + tg3_rd32_loop(tp, regs, TG3PCI_VENDOR, 0xb0); + tg3_rd32_loop(tp, regs, MAILBOX_INTERRUPT_0, 0x200); + tg3_rd32_loop(tp, regs, MAC_MODE, 0x4f0); + tg3_rd32_loop(tp, regs, SNDDATAI_MODE, 0xe0); + tg3_rd32_loop(tp, regs, SNDDATAC_MODE, 0x04); + tg3_rd32_loop(tp, regs, SNDBDS_MODE, 0x80); + tg3_rd32_loop(tp, regs, SNDBDI_MODE, 0x48); + tg3_rd32_loop(tp, regs, SNDBDC_MODE, 0x04); + tg3_rd32_loop(tp, regs, RCVLPC_MODE, 0x20); + tg3_rd32_loop(tp, regs, RCVLPC_SELLST_BASE, 0x15c); + tg3_rd32_loop(tp, regs, RCVDBDI_MODE, 0x0c); + tg3_rd32_loop(tp, regs, RCVDBDI_JUMBO_BD, 0x3c); + tg3_rd32_loop(tp, regs, RCVDBDI_BD_PROD_IDX_0, 0x44); + tg3_rd32_loop(tp, regs, RCVDCC_MODE, 0x04); + tg3_rd32_loop(tp, regs, RCVBDI_MODE, 0x20); + tg3_rd32_loop(tp, regs, RCVCC_MODE, 0x14); + tg3_rd32_loop(tp, regs, RCVLSC_MODE, 0x08); + tg3_rd32_loop(tp, regs, MBFREE_MODE, 0x08); + tg3_rd32_loop(tp, regs, HOSTCC_MODE, 0x100); + + if (tp->tg3_flags & TG3_FLAG_SUPPORT_MSIX) + tg3_rd32_loop(tp, regs, HOSTCC_RXCOL_TICKS_VEC1, 0x180); + + tg3_rd32_loop(tp, regs, MEMARB_MODE, 0x10); + tg3_rd32_loop(tp, regs, BUFMGR_MODE, 0x58); + tg3_rd32_loop(tp, regs, RDMAC_MODE, 0x08); + tg3_rd32_loop(tp, regs, WDMAC_MODE, 0x08); + tg3_rd32_loop(tp, regs, RX_CPU_MODE, 0x04); + tg3_rd32_loop(tp, regs, RX_CPU_STATE, 0x04); + tg3_rd32_loop(tp, regs, RX_CPU_PGMCTR, 0x04); + tg3_rd32_loop(tp, regs, RX_CPU_HWBKPT, 0x04); + + if (!(tp->tg3_flags2 & TG3_FLG2_5705_PLUS)) { + tg3_rd32_loop(tp, regs, TX_CPU_MODE, 0x04); + tg3_rd32_loop(tp, regs, TX_CPU_STATE, 0x04); + tg3_rd32_loop(tp, regs, TX_CPU_PGMCTR, 0x04); + } + + tg3_rd32_loop(tp, regs, GRCMBOX_INTERRUPT_0, 0x110); + tg3_rd32_loop(tp, regs, FTQ_RESET, 0x120); + tg3_rd32_loop(tp, regs, MSGINT_MODE, 0x0c); + tg3_rd32_loop(tp, regs, DMAC_MODE, 0x04); + tg3_rd32_loop(tp, regs, GRC_MODE, 0x4c); + + if (tp->tg3_flags & TG3_FLAG_NVRAM) + tg3_rd32_loop(tp, regs, NVRAM_CMD, 0x24); +} + +static void tg3_dump_state(struct tg3 *tp) +{ + int i; + u32 *regs; + + regs = kzalloc(TG3_REG_BLK_SIZE, GFP_ATOMIC); + if (!regs) { + netdev_err(tp->dev, "Failed allocating register dump buffer\n"); + return; + } + + if (tp->tg3_flags2 & TG3_FLG2_PCI_EXPRESS) { + /* Read up to but not including private PCI registers */ + for (i = 0; i < TG3_PCIE_TLDLPL_PORT; i += sizeof(u32)) + regs[i / sizeof(u32)] = tr32(i); + } else + tg3_dump_legacy_regs(tp, regs); + + for (i = 0; i < TG3_REG_BLK_SIZE / sizeof(u32); i += 4) { + if (!regs[i + 0] && !regs[i + 1] && + !regs[i + 2] && !regs[i + 3]) + continue; + + netdev_err(tp->dev, "0x%08x: 0x%08x, 0x%08x, 0x%08x, 0x%08x\n", + i * 4, + regs[i + 0], regs[i + 1], regs[i + 2], regs[i + 3]); + } + + kfree(regs); + + for (i = 0; i < tp->irq_cnt; i++) { + struct tg3_napi *tnapi = &tp->napi[i]; + + /* SW status block */ + netdev_err(tp->dev, + "%d: Host status block [%08x:%08x:(%04x:%04x:%04x):(%04x:%04x)]\n", + i, + tnapi->hw_status->status, + tnapi->hw_status->status_tag, + tnapi->hw_status->rx_jumbo_consumer, + tnapi->hw_status->rx_consumer, + tnapi->hw_status->rx_mini_consumer, + tnapi->hw_status->idx[0].rx_producer, + tnapi->hw_status->idx[0].tx_consumer); + + netdev_err(tp->dev, + "%d: NAPI info [%08x:%08x:(%04x:%04x:%04x):%04x:(%04x:%04x:%04x:%04x)]\n", + i, + tnapi->last_tag, tnapi->last_irq_tag, + tnapi->tx_prod, tnapi->tx_cons, tnapi->tx_pending, + tnapi->rx_rcb_ptr, + tnapi->prodring.rx_std_prod_idx, + tnapi->prodring.rx_std_cons_idx, + tnapi->prodring.rx_jmb_prod_idx, + tnapi->prodring.rx_jmb_cons_idx); + } +} + /* This is called whenever we suspect that the system chipset is re- * ordering the sequence of MMIO to the tx send mailbox. The symptom * is bogus tx completions. We try to recover by setting the @@ -5516,21 +5633,13 @@ out: tg3_phy_start(tp); } -static void tg3_dump_short_state(struct tg3 *tp) -{ - netdev_err(tp->dev, "DEBUG: MAC_TX_STATUS[%08x] MAC_RX_STATUS[%08x]\n", - tr32(MAC_TX_STATUS), tr32(MAC_RX_STATUS)); - netdev_err(tp->dev, "DEBUG: RDMAC_STATUS[%08x] WDMAC_STATUS[%08x]\n", - tr32(RDMAC_STATUS), tr32(WDMAC_STATUS)); -} - static void tg3_tx_timeout(struct net_device *dev) { struct tg3 *tp = netdev_priv(dev); if (netif_msg_tx_err(tp)) { netdev_err(dev, "transmit timed out, resetting\n"); - tg3_dump_short_state(tp); + tg3_dump_state(tp); } schedule_work(&tp->reset_task); @@ -9624,82 +9733,26 @@ static void tg3_set_rx_mode(struct net_device *dev) tg3_full_unlock(tp); } -#define TG3_REGDUMP_LEN (32 * 1024) - static int tg3_get_regs_len(struct net_device *dev) { - return TG3_REGDUMP_LEN; + return TG3_REG_BLK_SIZE; } static void tg3_get_regs(struct net_device *dev, struct ethtool_regs *regs, void *_p) { - u32 *p = _p; struct tg3 *tp = netdev_priv(dev); - u8 *orig_p = _p; - int i; regs->version = 0; - memset(p, 0, TG3_REGDUMP_LEN); + memset(_p, 0, TG3_REG_BLK_SIZE); if (tp->phy_flags & TG3_PHYFLG_IS_LOW_POWER) return; tg3_full_lock(tp, 0); -#define __GET_REG32(reg) (*(p)++ = tr32(reg)) -#define GET_REG32_LOOP(base, len) \ -do { p = (u32 *)(orig_p + (base)); \ - for (i = 0; i < len; i += 4) \ - __GET_REG32((base) + i); \ -} while (0) -#define GET_REG32_1(reg) \ -do { p = (u32 *)(orig_p + (reg)); \ - __GET_REG32((reg)); \ -} while (0) - - GET_REG32_LOOP(TG3PCI_VENDOR, 0xb0); - GET_REG32_LOOP(MAILBOX_INTERRUPT_0, 0x200); - GET_REG32_LOOP(MAC_MODE, 0x4f0); - GET_REG32_LOOP(SNDDATAI_MODE, 0xe0); - GET_REG32_1(SNDDATAC_MODE); - GET_REG32_LOOP(SNDBDS_MODE, 0x80); - GET_REG32_LOOP(SNDBDI_MODE, 0x48); - GET_REG32_1(SNDBDC_MODE); - GET_REG32_LOOP(RCVLPC_MODE, 0x20); - GET_REG32_LOOP(RCVLPC_SELLST_BASE, 0x15c); - GET_REG32_LOOP(RCVDBDI_MODE, 0x0c); - GET_REG32_LOOP(RCVDBDI_JUMBO_BD, 0x3c); - GET_REG32_LOOP(RCVDBDI_BD_PROD_IDX_0, 0x44); - GET_REG32_1(RCVDCC_MODE); - GET_REG32_LOOP(RCVBDI_MODE, 0x20); - GET_REG32_LOOP(RCVCC_MODE, 0x14); - GET_REG32_LOOP(RCVLSC_MODE, 0x08); - GET_REG32_1(MBFREE_MODE); - GET_REG32_LOOP(HOSTCC_MODE, 0x100); - GET_REG32_LOOP(MEMARB_MODE, 0x10); - GET_REG32_LOOP(BUFMGR_MODE, 0x58); - GET_REG32_LOOP(RDMAC_MODE, 0x08); - GET_REG32_LOOP(WDMAC_MODE, 0x08); - GET_REG32_1(RX_CPU_MODE); - GET_REG32_1(RX_CPU_STATE); - GET_REG32_1(RX_CPU_PGMCTR); - GET_REG32_1(RX_CPU_HWBKPT); - GET_REG32_1(TX_CPU_MODE); - GET_REG32_1(TX_CPU_STATE); - GET_REG32_1(TX_CPU_PGMCTR); - GET_REG32_LOOP(GRCMBOX_INTERRUPT_0, 0x110); - GET_REG32_LOOP(FTQ_RESET, 0x120); - GET_REG32_LOOP(MSGINT_MODE, 0x0c); - GET_REG32_1(DMAC_MODE); - GET_REG32_LOOP(GRC_MODE, 0x4c); - if (tp->tg3_flags & TG3_FLAG_NVRAM) - GET_REG32_LOOP(NVRAM_CMD, 0x24); - -#undef __GET_REG32 -#undef GET_REG32_LOOP -#undef GET_REG32_1 + tg3_dump_legacy_regs(tp, (u32 *)_p); tg3_full_unlock(tp); } diff --git a/drivers/net/tg3.h b/drivers/net/tg3.h index 829a84a..9912010 100644 --- a/drivers/net/tg3.h +++ b/drivers/net/tg3.h @@ -1954,6 +1954,8 @@ #define TG3_PCIE_PL_LO_PHYCTL5 0x00000014 #define TG3_PCIE_PL_LO_PHYCTL5_DIS_L2CLKREQ 0x80000000 +#define TG3_REG_BLK_SIZE 0x00008000 + /* OTP bit definitions */ #define TG3_OTP_AGCTGT_MASK 0x000000e0 #define TG3_OTP_AGCTGT_SHIFT 1 -- cgit v0.10.2 From e64de4e6c660dae6d6370b3acb59d5d5cc9ecf20 Mon Sep 17 00:00:00 2001 From: Matt Carlson Date: Wed, 13 Apr 2011 11:05:05 +0000 Subject: tg3: Dump registers when status block shows errors This patch monitors the error bit of the status word within the status block. If it is set, the driver will dump the driver state after validating the error and then reset the chip. Signed-off-by: Matt Carlson Signed-off-by: Michael Chan Reviewed-by: Benjamin Li Signed-off-by: David S. Miller diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index 7274435..b61b52f 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -5259,6 +5259,40 @@ tx_recovery: return work_done; } +static void tg3_process_error(struct tg3 *tp) +{ + u32 val; + bool real_error = false; + + if (tp->tg3_flags & TG3_FLAG_ERROR_PROCESSED) + return; + + /* Check Flow Attention register */ + val = tr32(HOSTCC_FLOW_ATTN); + if (val & ~HOSTCC_FLOW_ATTN_MBUF_LWM) { + netdev_err(tp->dev, "FLOW Attention error. Resetting chip.\n"); + real_error = true; + } + + if (tr32(MSGINT_STATUS) & ~MSGINT_STATUS_MSI_REQ) { + netdev_err(tp->dev, "MSI Status error. Resetting chip.\n"); + real_error = true; + } + + if (tr32(RDMAC_STATUS) || tr32(WDMAC_STATUS)) { + netdev_err(tp->dev, "DMA Status error. Resetting chip.\n"); + real_error = true; + } + + if (!real_error) + return; + + tg3_dump_state(tp); + + tp->tg3_flags |= TG3_FLAG_ERROR_PROCESSED; + schedule_work(&tp->reset_task); +} + static int tg3_poll(struct napi_struct *napi, int budget) { struct tg3_napi *tnapi = container_of(napi, struct tg3_napi, napi); @@ -5267,6 +5301,9 @@ static int tg3_poll(struct napi_struct *napi, int budget) struct tg3_hw_status *sblk = tnapi->hw_status; while (1) { + if (sblk->status & SD_STATUS_ERROR) + tg3_process_error(tp); + tg3_poll_link(tp); work_done = tg3_poll_work(tnapi, work_done, budget); @@ -7316,7 +7353,8 @@ static int tg3_chip_reset(struct tg3 *tp) tg3_restore_pci_state(tp); - tp->tg3_flags &= ~TG3_FLAG_CHIP_RESETTING; + tp->tg3_flags &= ~(TG3_FLAG_CHIP_RESETTING | + TG3_FLAG_ERROR_PROCESSED); val = 0; if (tp->tg3_flags2 & TG3_FLG2_5780_CLASS) diff --git a/drivers/net/tg3.h b/drivers/net/tg3.h index 9912010..b3ccfcc 100644 --- a/drivers/net/tg3.h +++ b/drivers/net/tg3.h @@ -1201,6 +1201,7 @@ #define HOSTCC_STATS_BLK_NIC_ADDR 0x00003c40 #define HOSTCC_STATUS_BLK_NIC_ADDR 0x00003c44 #define HOSTCC_FLOW_ATTN 0x00003c48 +#define HOSTCC_FLOW_ATTN_MBUF_LWM 0x00000040 /* 0x3c4c --> 0x3c50 unused */ #define HOSTCC_JUMBO_CON_IDX 0x00003c50 #define HOSTCC_STD_CON_IDX 0x00003c54 @@ -1611,6 +1612,7 @@ #define MSGINT_MODE_ONE_SHOT_DISABLE 0x00000020 #define MSGINT_MODE_MULTIVEC_EN 0x00000080 #define MSGINT_STATUS 0x00006004 +#define MSGINT_STATUS_MSI_REQ 0x00000001 #define MSGINT_FIFO 0x00006008 /* 0x600c --> 0x6400 unused */ @@ -2886,6 +2888,7 @@ struct tg3 { #define TG3_FLAG_TAGGED_STATUS 0x00000001 #define TG3_FLAG_TXD_MBOX_HWBUG 0x00000002 #define TG3_FLAG_USE_LINKCHG_REG 0x00000008 +#define TG3_FLAG_ERROR_PROCESSED 0x00000010 #define TG3_FLAG_ENABLE_ASF 0x00000020 #define TG3_FLAG_ASPM_WORKAROUND 0x00000040 #define TG3_FLAG_POLL_SERDES 0x00000080 -- cgit v0.10.2 From 48fa55a0a5e20b9e2a28a72c66c7027678cae6bb Mon Sep 17 00:00:00 2001 From: Matt Carlson Date: Wed, 13 Apr 2011 11:05:06 +0000 Subject: tg3: Automatically size stat/test string arrays This patch reimplements the size preprocessor constants of the stats and ethtool test string arrays. The size is calculated at compile time rather than using static constants. Signed-off-by: Matt Carlson Signed-off-by: Benjamin Li Reviewed-by: Michael Chan Signed-off-by: David S. Miller diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index b61b52f..9975cdb 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -165,11 +165,6 @@ #define TG3_RAW_IP_ALIGN 2 -/* number of ETHTOOL_GSTATS u64's */ -#define TG3_NUM_STATS (sizeof(struct tg3_ethtool_stats)/sizeof(u64)) - -#define TG3_NUM_TEST 6 - #define TG3_FW_UPDATE_TIMEOUT_SEC 5 #define FIRMWARE_TG3 "tigon/tg3.bin" @@ -279,7 +274,7 @@ MODULE_DEVICE_TABLE(pci, tg3_pci_tbl); static const struct { const char string[ETH_GSTRING_LEN]; -} ethtool_stats_keys[TG3_NUM_STATS] = { +} ethtool_stats_keys[] = { { "rx_octets" }, { "rx_fragments" }, { "rx_ucast_packets" }, @@ -358,9 +353,12 @@ static const struct { { "nic_tx_threshold_hit" } }; +#define TG3_NUM_STATS ARRAY_SIZE(ethtool_stats_keys) + + static const struct { const char string[ETH_GSTRING_LEN]; -} ethtool_test_keys[TG3_NUM_TEST] = { +} ethtool_test_keys[] = { { "nvram test (online) " }, { "link test (online) " }, { "register test (offline)" }, @@ -369,6 +367,9 @@ static const struct { { "interrupt test (offline)" }, }; +#define TG3_NUM_TEST ARRAY_SIZE(ethtool_test_keys) + + static void tg3_write32(struct tg3 *tp, u32 off, u32 val) { writel(val, tp->regs + off); -- cgit v0.10.2 From 4852a8614f63999e38539ad16615054dcd20a05d Mon Sep 17 00:00:00 2001 From: Matt Carlson Date: Wed, 13 Apr 2011 11:05:07 +0000 Subject: tg3: Add jumbo frame loopback tests to selftest This patch adds jumbo frame loopback test support to the ethtool selftest. Signed-off-by: Matt Carlson Reviewed-by: Michael Chan Reviewed-by: Benjamin Li Signed-off-by: David S. Miller diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index 9975cdb..52dd516 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -10935,7 +10935,7 @@ static int tg3_test_memory(struct tg3 *tp) #define TG3_MAC_LOOPBACK 0 #define TG3_PHY_LOOPBACK 1 -static int tg3_run_loopback(struct tg3 *tp, int loopback_mode) +static int tg3_run_loopback(struct tg3 *tp, u32 pktsz, int loopback_mode) { u32 mac_mode, rx_start_idx, rx_idx, tx_idx, opaque_key; u32 desc_idx, coal_now; @@ -11033,7 +11033,7 @@ static int tg3_run_loopback(struct tg3 *tp, int loopback_mode) err = -EIO; - tx_len = 1514; + tx_len = pktsz; skb = netdev_alloc_skb(tp->dev, tx_len); if (!skb) return -ENOMEM; @@ -11042,7 +11042,7 @@ static int tg3_run_loopback(struct tg3 *tp, int loopback_mode) memcpy(tx_data, tp->dev->dev_addr, 6); memset(tx_data + 6, 0x0, 8); - tw32(MAC_RX_MTU_SIZE, tx_len + 4); + tw32(MAC_RX_MTU_SIZE, tx_len + ETH_FCS_LEN); for (i = 14; i < tx_len; i++) tx_data[i] = (u8) (i & 0xff); @@ -11098,8 +11098,6 @@ static int tg3_run_loopback(struct tg3 *tp, int loopback_mode) desc = &rnapi->rx_rcb[rx_start_idx]; desc_idx = desc->opaque & RXD_OPAQUE_INDEX_MASK; opaque_key = desc->opaque & RXD_OPAQUE_RING_MASK; - if (opaque_key != RXD_OPAQUE_RING_STD) - goto out; if ((desc->err_vlan & RXD_ERR_MASK) != 0 && (desc->err_vlan != RXD_ERR_ODD_NIBBLE_RCVD_MII)) @@ -11109,9 +11107,20 @@ static int tg3_run_loopback(struct tg3 *tp, int loopback_mode) if (rx_len != tx_len) goto out; - rx_skb = tpr->rx_std_buffers[desc_idx].skb; + if (pktsz <= TG3_RX_STD_DMA_SZ - ETH_FCS_LEN) { + if (opaque_key != RXD_OPAQUE_RING_STD) + goto out; + + rx_skb = tpr->rx_std_buffers[desc_idx].skb; + map = dma_unmap_addr(&tpr->rx_std_buffers[desc_idx], mapping); + } else { + if (opaque_key != RXD_OPAQUE_RING_JUMBO) + goto out; + + rx_skb = tpr->rx_jmb_buffers[desc_idx].skb; + map = dma_unmap_addr(&tpr->rx_jmb_buffers[desc_idx], mapping); + } - map = dma_unmap_addr(&tpr->rx_std_buffers[desc_idx], mapping); pci_dma_sync_single_for_cpu(tp->pdev, map, rx_len, PCI_DMA_FROMDEVICE); for (i = 14; i < tx_len; i++) { @@ -11177,9 +11186,13 @@ static int tg3_test_loopback(struct tg3 *tp) CPMU_CTRL_LINK_AWARE_MODE)); } - if (tg3_run_loopback(tp, TG3_MAC_LOOPBACK)) + if (tg3_run_loopback(tp, ETH_FRAME_LEN, TG3_MAC_LOOPBACK)) err |= TG3_MAC_LOOPBACK_FAILED; + if ((tp->tg3_flags & TG3_FLAG_JUMBO_RING_ENABLE) && + tg3_run_loopback(tp, 9000 + ETH_HLEN, TG3_MAC_LOOPBACK)) + err |= (TG3_MAC_LOOPBACK_FAILED << 2); + if (tp->tg3_flags & TG3_FLAG_CPMU_PRESENT) { tw32(TG3_CPMU_CTRL, cpmuctrl); @@ -11189,8 +11202,11 @@ static int tg3_test_loopback(struct tg3 *tp) if (!(tp->phy_flags & TG3_PHYFLG_PHY_SERDES) && !(tp->tg3_flags3 & TG3_FLG3_USE_PHYLIB)) { - if (tg3_run_loopback(tp, TG3_PHY_LOOPBACK)) + if (tg3_run_loopback(tp, ETH_FRAME_LEN, TG3_PHY_LOOPBACK)) err |= TG3_PHY_LOOPBACK_FAILED; + if ((tp->tg3_flags & TG3_FLAG_JUMBO_RING_ENABLE) && + tg3_run_loopback(tp, 9000 + ETH_HLEN, TG3_PHY_LOOPBACK)) + err |= (TG3_PHY_LOOPBACK_FAILED << 2); } /* Re-enable gphy autopowerdown. */ -- cgit v0.10.2 From c3e945006ab2295e9a3f4327aa74a502ad123fe6 Mon Sep 17 00:00:00 2001 From: Matt Carlson Date: Wed, 13 Apr 2011 11:05:08 +0000 Subject: tg3: Add support for extended VPD blocks In some devices, the VPD block is relocated to a different area in NVRAM. The original location can still contain old, but still valid VPD data. This patch changes the code to look for an extended VPD block in NVRAM. If one is found, that block is used for all VPD operations instead. Signed-off-by: Matt Carlson Reviewed-by: Michael Chan Reviewed-by: Benjamin Li Signed-off-by: David S. Miller diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index 52dd516..10fa476 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -10416,6 +10416,81 @@ static void tg3_get_ethtool_stats(struct net_device *dev, memcpy(tmp_stats, tg3_get_estats(tp), sizeof(tp->estats)); } +static __be32 * tg3_vpd_readblock(struct tg3 *tp) +{ + int i; + __be32 *buf; + u32 offset = 0, len = 0; + u32 magic, val; + + if ((tp->tg3_flags3 & TG3_FLG3_NO_NVRAM) || + tg3_nvram_read(tp, 0, &magic)) + return NULL; + + if (magic == TG3_EEPROM_MAGIC) { + for (offset = TG3_NVM_DIR_START; + offset < TG3_NVM_DIR_END; + offset += TG3_NVM_DIRENT_SIZE) { + if (tg3_nvram_read(tp, offset, &val)) + return NULL; + + if ((val >> TG3_NVM_DIRTYPE_SHIFT) == + TG3_NVM_DIRTYPE_EXTVPD) + break; + } + + if (offset != TG3_NVM_DIR_END) { + len = (val & TG3_NVM_DIRTYPE_LENMSK) * 4; + if (tg3_nvram_read(tp, offset + 4, &offset)) + return NULL; + + offset = tg3_nvram_logical_addr(tp, offset); + } + } + + if (!offset || !len) { + offset = TG3_NVM_VPD_OFF; + len = TG3_NVM_VPD_LEN; + } + + buf = kmalloc(len, GFP_KERNEL); + if (buf == NULL) + return NULL; + + if (magic == TG3_EEPROM_MAGIC) { + for (i = 0; i < len; i += 4) { + /* The data is in little-endian format in NVRAM. + * Use the big-endian read routines to preserve + * the byte order as it exists in NVRAM. + */ + if (tg3_nvram_read_be32(tp, offset + i, &buf[i/4])) + goto error; + } + } else { + u8 *ptr; + ssize_t cnt; + unsigned int pos = 0; + + ptr = (u8 *)&buf[0]; + for (i = 0; pos < len && i < 3; i++, pos += cnt, ptr += cnt) { + cnt = pci_read_vpd(tp->pdev, pos, + len - pos, ptr); + if (cnt == -ETIMEDOUT || cnt == -EINTR) + cnt = 0; + else if (cnt < 0) + goto error; + } + if (pos != len) + goto error; + } + + return buf; + +error: + kfree(buf); + return NULL; +} + #define NVRAM_TEST_SIZE 0x100 #define NVRAM_SELFBOOT_FORMAT1_0_SIZE 0x14 #define NVRAM_SELFBOOT_FORMAT1_2_SIZE 0x18 @@ -10555,14 +10630,11 @@ static int tg3_test_nvram(struct tg3 *tp) if (csum != le32_to_cpu(buf[0xfc/4])) goto out; - for (i = 0; i < TG3_NVM_VPD_LEN; i += 4) { - /* The data is in little-endian format in NVRAM. - * Use the big-endian read routines to preserve - * the byte order as it exists in NVRAM. - */ - if (tg3_nvram_read_be32(tp, TG3_NVM_VPD_OFF + i, &buf[i/4])) - goto out; - } + kfree(buf); + + buf = tg3_vpd_readblock(tp); + if (!buf) + return -ENOMEM; i = pci_vpd_find_tag((u8 *)buf, 0, TG3_NVM_VPD_LEN, PCI_VPD_LRDT_RO_DATA); @@ -12905,46 +12977,11 @@ static void __devinit tg3_read_vpd(struct tg3 *tp) u8 *vpd_data; unsigned int block_end, rosize, len; int j, i = 0; - u32 magic; - - if ((tp->tg3_flags3 & TG3_FLG3_NO_NVRAM) || - tg3_nvram_read(tp, 0x0, &magic)) - goto out_no_vpd; - vpd_data = kmalloc(TG3_NVM_VPD_LEN, GFP_KERNEL); + vpd_data = (u8 *)tg3_vpd_readblock(tp); if (!vpd_data) goto out_no_vpd; - if (magic == TG3_EEPROM_MAGIC) { - for (i = 0; i < TG3_NVM_VPD_LEN; i += 4) { - u32 tmp; - - /* The data is in little-endian format in NVRAM. - * Use the big-endian read routines to preserve - * the byte order as it exists in NVRAM. - */ - if (tg3_nvram_read_be32(tp, TG3_NVM_VPD_OFF + i, &tmp)) - goto out_not_found; - - memcpy(&vpd_data[i], &tmp, sizeof(tmp)); - } - } else { - ssize_t cnt; - unsigned int pos = 0; - - for (; pos < TG3_NVM_VPD_LEN && i < 3; i++, pos += cnt) { - cnt = pci_read_vpd(tp->pdev, pos, - TG3_NVM_VPD_LEN - pos, - &vpd_data[pos]); - if (cnt == -ETIMEDOUT || cnt == -EINTR) - cnt = 0; - else if (cnt < 0) - goto out_not_found; - } - if (pos != TG3_NVM_VPD_LEN) - goto out_not_found; - } - i = pci_vpd_find_tag(vpd_data, 0, TG3_NVM_VPD_LEN, PCI_VPD_LRDT_RO_DATA); if (i < 0) diff --git a/drivers/net/tg3.h b/drivers/net/tg3.h index b3ccfcc..224c3e0 100644 --- a/drivers/net/tg3.h +++ b/drivers/net/tg3.h @@ -2009,7 +2009,9 @@ #define TG3_NVM_DIR_END 0x78 #define TG3_NVM_DIRENT_SIZE 0xc #define TG3_NVM_DIRTYPE_SHIFT 24 +#define TG3_NVM_DIRTYPE_LENMSK 0x003fffff #define TG3_NVM_DIRTYPE_ASFINI 1 +#define TG3_NVM_DIRTYPE_EXTVPD 20 #define TG3_NVM_PTREV_BCVER 0x94 #define TG3_NVM_BCVER_MAJMSK 0x0000ff00 #define TG3_NVM_BCVER_MAJSFT 8 -- cgit v0.10.2 From c326de88b8ac7ed1cd1027017ba6079dbe91be49 Mon Sep 17 00:00:00 2001 From: "Mathieu J. Poirier" Date: Wed, 13 Apr 2011 17:13:00 -0700 Subject: net: allow shifted access in smsc911x V2 This is a revised patch that permits a shifted access to the LAN9221 registers. More specifically: It adds a shift parameter in the platform_data. It introduces an ops in smsc911x_data. A choice of access function to use at run-time. Four new shifted access function. Signed-off-by: Mathieu Poirier Signed-off-by: Alessandro Rubini Signed-off-by: David S. Miller diff --git a/drivers/net/smsc911x.c b/drivers/net/smsc911x.c index b8faab7..c6d47d1 100644 --- a/drivers/net/smsc911x.c +++ b/drivers/net/smsc911x.c @@ -71,6 +71,17 @@ static int debug = 3; module_param(debug, int, 0); MODULE_PARM_DESC(debug, "Debug level (0=none,...,16=all)"); +struct smsc911x_data; + +struct smsc911x_ops { + u32 (*reg_read)(struct smsc911x_data *pdata, u32 reg); + void (*reg_write)(struct smsc911x_data *pdata, u32 reg, u32 val); + void (*rx_readfifo)(struct smsc911x_data *pdata, + unsigned int *buf, unsigned int wordcount); + void (*tx_writefifo)(struct smsc911x_data *pdata, + unsigned int *buf, unsigned int wordcount); +}; + struct smsc911x_data { void __iomem *ioaddr; @@ -118,8 +129,14 @@ struct smsc911x_data { unsigned int clear_bits_mask; unsigned int hashhi; unsigned int hashlo; + + /* register access functions */ + const struct smsc911x_ops *ops; }; +/* Easy access to information */ +#define __smsc_shift(pdata, reg) ((reg) << ((pdata)->config.shift)) + static inline u32 __smsc911x_reg_read(struct smsc911x_data *pdata, u32 reg) { if (pdata->config.flags & SMSC911X_USE_32BIT) @@ -133,13 +150,29 @@ static inline u32 __smsc911x_reg_read(struct smsc911x_data *pdata, u32 reg) return 0; } +static inline u32 +__smsc911x_reg_read_shift(struct smsc911x_data *pdata, u32 reg) +{ + if (pdata->config.flags & SMSC911X_USE_32BIT) + return readl(pdata->ioaddr + __smsc_shift(pdata, reg)); + + if (pdata->config.flags & SMSC911X_USE_16BIT) + return (readw(pdata->ioaddr + + __smsc_shift(pdata, reg)) & 0xFFFF) | + ((readw(pdata->ioaddr + + __smsc_shift(pdata, reg + 2)) & 0xFFFF) << 16); + + BUG(); + return 0; +} + static inline u32 smsc911x_reg_read(struct smsc911x_data *pdata, u32 reg) { u32 data; unsigned long flags; spin_lock_irqsave(&pdata->dev_lock, flags); - data = __smsc911x_reg_read(pdata, reg); + data = pdata->ops->reg_read(pdata, reg); spin_unlock_irqrestore(&pdata->dev_lock, flags); return data; @@ -162,13 +195,32 @@ static inline void __smsc911x_reg_write(struct smsc911x_data *pdata, u32 reg, BUG(); } +static inline void +__smsc911x_reg_write_shift(struct smsc911x_data *pdata, u32 reg, u32 val) +{ + if (pdata->config.flags & SMSC911X_USE_32BIT) { + writel(val, pdata->ioaddr + __smsc_shift(pdata, reg)); + return; + } + + if (pdata->config.flags & SMSC911X_USE_16BIT) { + writew(val & 0xFFFF, + pdata->ioaddr + __smsc_shift(pdata, reg)); + writew((val >> 16) & 0xFFFF, + pdata->ioaddr + __smsc_shift(pdata, reg + 2)); + return; + } + + BUG(); +} + static inline void smsc911x_reg_write(struct smsc911x_data *pdata, u32 reg, u32 val) { unsigned long flags; spin_lock_irqsave(&pdata->dev_lock, flags); - __smsc911x_reg_write(pdata, reg, val); + pdata->ops->reg_write(pdata, reg, val); spin_unlock_irqrestore(&pdata->dev_lock, flags); } @@ -204,6 +256,40 @@ out: spin_unlock_irqrestore(&pdata->dev_lock, flags); } +/* Writes a packet to the TX_DATA_FIFO - shifted version */ +static inline void +smsc911x_tx_writefifo_shift(struct smsc911x_data *pdata, unsigned int *buf, + unsigned int wordcount) +{ + unsigned long flags; + + spin_lock_irqsave(&pdata->dev_lock, flags); + + if (pdata->config.flags & SMSC911X_SWAP_FIFO) { + while (wordcount--) + __smsc911x_reg_write_shift(pdata, TX_DATA_FIFO, + swab32(*buf++)); + goto out; + } + + if (pdata->config.flags & SMSC911X_USE_32BIT) { + writesl(pdata->ioaddr + __smsc_shift(pdata, + TX_DATA_FIFO), buf, wordcount); + goto out; + } + + if (pdata->config.flags & SMSC911X_USE_16BIT) { + while (wordcount--) + __smsc911x_reg_write_shift(pdata, + TX_DATA_FIFO, *buf++); + goto out; + } + + BUG(); +out: + spin_unlock_irqrestore(&pdata->dev_lock, flags); +} + /* Reads a packet out of the RX_DATA_FIFO */ static inline void smsc911x_rx_readfifo(struct smsc911x_data *pdata, unsigned int *buf, @@ -236,6 +322,40 @@ out: spin_unlock_irqrestore(&pdata->dev_lock, flags); } +/* Reads a packet out of the RX_DATA_FIFO - shifted version */ +static inline void +smsc911x_rx_readfifo_shift(struct smsc911x_data *pdata, unsigned int *buf, + unsigned int wordcount) +{ + unsigned long flags; + + spin_lock_irqsave(&pdata->dev_lock, flags); + + if (pdata->config.flags & SMSC911X_SWAP_FIFO) { + while (wordcount--) + *buf++ = swab32(__smsc911x_reg_read_shift(pdata, + RX_DATA_FIFO)); + goto out; + } + + if (pdata->config.flags & SMSC911X_USE_32BIT) { + readsl(pdata->ioaddr + __smsc_shift(pdata, + RX_DATA_FIFO), buf, wordcount); + goto out; + } + + if (pdata->config.flags & SMSC911X_USE_16BIT) { + while (wordcount--) + *buf++ = __smsc911x_reg_read_shift(pdata, + RX_DATA_FIFO); + goto out; + } + + BUG(); +out: + spin_unlock_irqrestore(&pdata->dev_lock, flags); +} + /* waits for MAC not busy, with timeout. Only called by smsc911x_mac_read * and smsc911x_mac_write, so assumes mac_lock is held */ static int smsc911x_mac_complete(struct smsc911x_data *pdata) @@ -500,7 +620,7 @@ static int smsc911x_phy_check_loopbackpkt(struct smsc911x_data *pdata) wrsz += (u32)((ulong)pdata->loopback_tx_pkt & 0x3); wrsz >>= 2; - smsc911x_tx_writefifo(pdata, (unsigned int *)bufp, wrsz); + pdata->ops->tx_writefifo(pdata, (unsigned int *)bufp, wrsz); /* Wait till transmit is done */ i = 60; @@ -544,7 +664,7 @@ static int smsc911x_phy_check_loopbackpkt(struct smsc911x_data *pdata) rdsz += (u32)((ulong)pdata->loopback_rx_pkt & 0x3); rdsz >>= 2; - smsc911x_rx_readfifo(pdata, (unsigned int *)bufp, rdsz); + pdata->ops->rx_readfifo(pdata, (unsigned int *)bufp, rdsz); if (pktlength != (MIN_PACKET_SIZE + 4)) { SMSC_WARN(pdata, hw, "Unexpected packet size " @@ -1046,8 +1166,8 @@ static int smsc911x_poll(struct napi_struct *napi, int budget) /* Align IP on 16B boundary */ skb_reserve(skb, NET_IP_ALIGN); skb_put(skb, pktlength - 4); - smsc911x_rx_readfifo(pdata, (unsigned int *)skb->head, - pktwords); + pdata->ops->rx_readfifo(pdata, + (unsigned int *)skb->head, pktwords); skb->protocol = eth_type_trans(skb, dev); skb_checksum_none_assert(skb); netif_receive_skb(skb); @@ -1351,7 +1471,7 @@ static int smsc911x_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) wrsz += (u32)((ulong)skb->data & 0x3); wrsz >>= 2; - smsc911x_tx_writefifo(pdata, (unsigned int *)bufp, wrsz); + pdata->ops->tx_writefifo(pdata, (unsigned int *)bufp, wrsz); freespace -= (skb->len + 32); dev_kfree_skb(skb); @@ -1957,6 +2077,22 @@ static int __devexit smsc911x_drv_remove(struct platform_device *pdev) return 0; } +/* standard register acces */ +static const struct smsc911x_ops standard_smsc911x_ops = { + .reg_read = __smsc911x_reg_read, + .reg_write = __smsc911x_reg_write, + .rx_readfifo = smsc911x_rx_readfifo, + .tx_writefifo = smsc911x_tx_writefifo, +}; + +/* shifted register access */ +static const struct smsc911x_ops shifted_smsc911x_ops = { + .reg_read = __smsc911x_reg_read_shift, + .reg_write = __smsc911x_reg_write_shift, + .rx_readfifo = smsc911x_rx_readfifo_shift, + .tx_writefifo = smsc911x_tx_writefifo_shift, +}; + static int __devinit smsc911x_drv_probe(struct platform_device *pdev) { struct net_device *dev; @@ -2026,6 +2162,12 @@ static int __devinit smsc911x_drv_probe(struct platform_device *pdev) goto out_free_netdev_2; } + /* assume standard, non-shifted, access to HW registers */ + pdata->ops = &standard_smsc911x_ops; + /* apply the right access if shifting is needed */ + if (config->shift) + pdata->ops = &shifted_smsc911x_ops; + retval = smsc911x_init(dev); if (retval < 0) goto out_unmap_io_3; diff --git a/include/linux/smsc911x.h b/include/linux/smsc911x.h index 7144e8a..4dde70e 100644 --- a/include/linux/smsc911x.h +++ b/include/linux/smsc911x.h @@ -29,6 +29,7 @@ struct smsc911x_platform_config { unsigned int irq_polarity; unsigned int irq_type; unsigned int flags; + unsigned int shift; phy_interface_t phy_interface; unsigned char mac[6]; }; -- cgit v0.10.2 From 7c158399c21e4eabb33965a5fc689ebbd2ded4f6 Mon Sep 17 00:00:00 2001 From: Greg Rose Date: Sat, 12 Mar 2011 11:56:02 +0000 Subject: igb: Add anti-spoofing feature documentation Add the documentation for the anti-spoofing feature in the HW. Signed-off-by: Greg Rose Signed-off-by: Jeff Kirsher diff --git a/Documentation/networking/igb.txt b/Documentation/networking/igb.txt index 98953c0..9a2a0371 100644 --- a/Documentation/networking/igb.txt +++ b/Documentation/networking/igb.txt @@ -93,6 +93,19 @@ Additional Configurations REQUIREMENTS: MSI-X support is required for Multiqueue. If MSI-X is not found, the system will fallback to MSI or to Legacy interrupts. + MAC and VLAN anti-spoofing feature + ---------------------------------- + When a malicious driver attempts to send a spoofed packet, it is dropped by + the hardware and not transmitted. An interrupt is sent to the PF driver + notifying it of the spoof attempt. + + When a spoofed packet is detected the PF driver will send the following + message to the system log (displayed by the "dmesg" command): + + Spoof event(s) detected on VF(n) + + Where n=the VF that attempted to do the spoofing. + Support ======= -- cgit v0.10.2 From 34a0326e3aaf1d67fe3de55e77e92961c6a9a847 Mon Sep 17 00:00:00 2001 From: Stefan Assmann Date: Tue, 5 Apr 2011 04:27:05 +0000 Subject: igb: fix typo in igb_validate_nvm_checksum_82580 Comment spelling fix. Signed-off-by: Stefan Assmann Tested-by: Aaron Brown Signed-off-by: Jeff Kirsher diff --git a/drivers/net/igb/e1000_82575.c b/drivers/net/igb/e1000_82575.c index 6b256c2..0cd41c4 100644 --- a/drivers/net/igb/e1000_82575.c +++ b/drivers/net/igb/e1000_82575.c @@ -1877,7 +1877,7 @@ static s32 igb_validate_nvm_checksum_82580(struct e1000_hw *hw) } if (nvm_data & NVM_COMPATIBILITY_BIT_MASK) { - /* if chekcsums compatibility bit is set validate checksums + /* if checksums compatibility bit is set validate checksums * for all 4 ports. */ eeprom_regions_count = 4; } @@ -1988,6 +1988,7 @@ static s32 igb_update_nvm_checksum_i350(struct e1000_hw *hw) out: return ret_val; } + /** * igb_set_eee_i350 - Enable/disable EEE support * @hw: pointer to the HW structure -- cgit v0.10.2 From 563988dcfe706457ec7049d59e18d6147179bb0a Mon Sep 17 00:00:00 2001 From: Stefan Assmann Date: Tue, 5 Apr 2011 04:27:15 +0000 Subject: igb: introduce igb_thermal_sensor_event for sensor checking The code for thermal sensor checking should be wrapped into a function. Signed-off-by: Stefan Assmann Tested-by: Jeff Pieper Signed-off-by: Jeff Kirsher diff --git a/drivers/net/igb/igb_main.c b/drivers/net/igb/igb_main.c index 0dfd1b9..cdfd572 100644 --- a/drivers/net/igb/igb_main.c +++ b/drivers/net/igb/igb_main.c @@ -3532,6 +3532,25 @@ bool igb_has_link(struct igb_adapter *adapter) return link_active; } +static bool igb_thermal_sensor_event(struct e1000_hw *hw, u32 event) +{ + bool ret = false; + u32 ctrl_ext, thstat; + + /* check for thermal sensor event on i350, copper only */ + if (hw->mac.type == e1000_i350) { + thstat = rd32(E1000_THSTAT); + ctrl_ext = rd32(E1000_CTRL_EXT); + + if ((hw->phy.media_type == e1000_media_type_copper) && + !(ctrl_ext & E1000_CTRL_EXT_LINK_MODE_SGMII)) { + ret = !!(thstat & event); + } + } + + return ret; +} + /** * igb_watchdog - Timer Call-back * @data: pointer to adapter cast into an unsigned long @@ -3550,7 +3569,7 @@ static void igb_watchdog_task(struct work_struct *work) watchdog_task); struct e1000_hw *hw = &adapter->hw; struct net_device *netdev = adapter->netdev; - u32 link, ctrl_ext, thstat; + u32 link; int i; link = igb_has_link(adapter); @@ -3574,25 +3593,14 @@ static void igb_watchdog_task(struct work_struct *work) ((ctrl & E1000_CTRL_RFCE) ? "RX" : ((ctrl & E1000_CTRL_TFCE) ? "TX" : "None"))); - /* check for thermal sensor event on i350, - * copper only */ - if (hw->mac.type == e1000_i350) { - thstat = rd32(E1000_THSTAT); - ctrl_ext = rd32(E1000_CTRL_EXT); - if ((hw->phy.media_type == - e1000_media_type_copper) && !(ctrl_ext & - E1000_CTRL_EXT_LINK_MODE_SGMII)) { - if (thstat & - E1000_THSTAT_LINK_THROTTLE) { - printk(KERN_INFO "igb: %s The " - "network adapter link " - "speed was downshifted " - "because it " - "overheated.\n", - netdev->name); - } - } + /* check for thermal sensor event */ + if (igb_thermal_sensor_event(hw, E1000_THSTAT_LINK_THROTTLE)) { + printk(KERN_INFO "igb: %s The network adapter " + "link speed was downshifted " + "because it overheated.\n", + netdev->name); } + /* adjust timeout factor according to speed/duplex */ adapter->tx_timeout_factor = 1; switch (adapter->link_speed) { @@ -3618,22 +3626,15 @@ static void igb_watchdog_task(struct work_struct *work) if (netif_carrier_ok(netdev)) { adapter->link_speed = 0; adapter->link_duplex = 0; - /* check for thermal sensor event on i350 - * copper only*/ - if (hw->mac.type == e1000_i350) { - thstat = rd32(E1000_THSTAT); - ctrl_ext = rd32(E1000_CTRL_EXT); - if ((hw->phy.media_type == - e1000_media_type_copper) && !(ctrl_ext & - E1000_CTRL_EXT_LINK_MODE_SGMII)) { - if (thstat & E1000_THSTAT_PWR_DOWN) { - printk(KERN_ERR "igb: %s The " - "network adapter was stopped " - "because it overheated.\n", + + /* check for thermal sensor event */ + if (igb_thermal_sensor_event(hw, E1000_THSTAT_PWR_DOWN)) { + printk(KERN_ERR "igb: %s The network adapter " + "was stopped because it " + "overheated.\n", netdev->name); - } - } } + /* Links status message must follow this format */ printk(KERN_INFO "igb: %s NIC Link is Down\n", netdev->name); -- cgit v0.10.2 From 1bba4386ab4f67a53c9649268dd9c83bc6110a9b Mon Sep 17 00:00:00 2001 From: Bruce Allan Date: Sat, 19 Mar 2011 00:27:20 +0000 Subject: e1000e: convert short duration msleep() to usleep_range() With durations less than 20ms, the jiffies or legacy timer backed msleep() may sleep ~20ms which might not be what the caller expects. Instead, it is recommended to use the hrtimers backed usleep_range(). For more, see Documentation/timers/timers-howto.txt. Issues reported by checkpatch. In addition, remove unnecessary sleep in e1000e_write_nvm_spi(). Signed-off-by: Bruce Allan Tested-by: Aaron Brown Signed-off-by: Jeff Kirsher diff --git a/drivers/net/e1000e/82571.c b/drivers/net/e1000e/82571.c index 89a6903..9fedbca 100644 --- a/drivers/net/e1000e/82571.c +++ b/drivers/net/e1000e/82571.c @@ -594,7 +594,7 @@ static s32 e1000_get_hw_semaphore_82573(struct e1000_hw *hw) extcnf_ctrl |= E1000_EXTCNF_CTRL_MDIO_SW_OWNERSHIP; - msleep(2); + usleep_range(2000, 4000); i++; } while (i < MDIO_OWNERSHIP_TIMEOUT); @@ -816,7 +816,7 @@ static s32 e1000_update_nvm_checksum_82571(struct e1000_hw *hw) /* Check for pending operations. */ for (i = 0; i < E1000_FLASH_UPDATES; i++) { - msleep(1); + usleep_range(1000, 2000); if ((er32(EECD) & E1000_EECD_FLUPD) == 0) break; } @@ -840,7 +840,7 @@ static s32 e1000_update_nvm_checksum_82571(struct e1000_hw *hw) ew32(EECD, eecd); for (i = 0; i < E1000_FLASH_UPDATES; i++) { - msleep(1); + usleep_range(1000, 2000); if ((er32(EECD) & E1000_EECD_FLUPD) == 0) break; } @@ -930,7 +930,7 @@ static s32 e1000_get_cfg_done_82571(struct e1000_hw *hw) if (er32(EEMNGCTL) & E1000_NVM_CFG_DONE_PORT_0) break; - msleep(1); + usleep_range(1000, 2000); timeout--; } if (!timeout) { @@ -1037,7 +1037,7 @@ static s32 e1000_reset_hw_82571(struct e1000_hw *hw) ew32(TCTL, E1000_TCTL_PSP); e1e_flush(); - msleep(10); + usleep_range(10000, 20000); /* * Must acquire the MDIO ownership before MAC reset. diff --git a/drivers/net/e1000e/es2lan.c b/drivers/net/e1000e/es2lan.c index 2fefa82..0279695 100644 --- a/drivers/net/e1000e/es2lan.c +++ b/drivers/net/e1000e/es2lan.c @@ -612,7 +612,7 @@ static s32 e1000_get_cfg_done_80003es2lan(struct e1000_hw *hw) while (timeout) { if (er32(EEMNGCTL) & mask) break; - msleep(1); + usleep_range(1000, 2000); timeout--; } if (!timeout) { @@ -802,7 +802,7 @@ static s32 e1000_reset_hw_80003es2lan(struct e1000_hw *hw) ew32(TCTL, E1000_TCTL_PSP); e1e_flush(); - msleep(10); + usleep_range(10000, 20000); ctrl = er32(CTRL); diff --git a/drivers/net/e1000e/ethtool.c b/drivers/net/e1000e/ethtool.c index 07f09e9..5b4cf90 100644 --- a/drivers/net/e1000e/ethtool.c +++ b/drivers/net/e1000e/ethtool.c @@ -253,7 +253,7 @@ static int e1000_set_settings(struct net_device *netdev, } while (test_and_set_bit(__E1000_RESETTING, &adapter->state)) - msleep(1); + usleep_range(1000, 2000); if (ecmd->autoneg == AUTONEG_ENABLE) { hw->mac.autoneg = 1; @@ -317,7 +317,7 @@ static int e1000_set_pauseparam(struct net_device *netdev, adapter->fc_autoneg = pause->autoneg; while (test_and_set_bit(__E1000_RESETTING, &adapter->state)) - msleep(1); + usleep_range(1000, 2000); if (adapter->fc_autoneg == AUTONEG_ENABLE) { hw->fc.requested_mode = e1000_fc_default; @@ -673,7 +673,7 @@ static int e1000_set_ringparam(struct net_device *netdev, return -EINVAL; while (test_and_set_bit(__E1000_RESETTING, &adapter->state)) - msleep(1); + usleep_range(1000, 2000); if (netif_running(adapter->netdev)) e1000e_down(adapter); @@ -952,7 +952,7 @@ static int e1000_intr_test(struct e1000_adapter *adapter, u64 *data) /* Disable all the interrupts */ ew32(IMC, 0xFFFFFFFF); - msleep(10); + usleep_range(10000, 20000); /* Test each interrupt */ for (i = 0; i < 10; i++) { @@ -984,7 +984,7 @@ static int e1000_intr_test(struct e1000_adapter *adapter, u64 *data) adapter->test_icr = 0; ew32(IMC, mask); ew32(ICS, mask); - msleep(10); + usleep_range(10000, 20000); if (adapter->test_icr & mask) { *data = 3; @@ -1002,7 +1002,7 @@ static int e1000_intr_test(struct e1000_adapter *adapter, u64 *data) adapter->test_icr = 0; ew32(IMS, mask); ew32(ICS, mask); - msleep(10); + usleep_range(10000, 20000); if (!(adapter->test_icr & mask)) { *data = 4; @@ -1020,7 +1020,7 @@ static int e1000_intr_test(struct e1000_adapter *adapter, u64 *data) adapter->test_icr = 0; ew32(IMC, ~mask & 0x00007FFF); ew32(ICS, ~mask & 0x00007FFF); - msleep(10); + usleep_range(10000, 20000); if (adapter->test_icr) { *data = 5; @@ -1031,7 +1031,7 @@ static int e1000_intr_test(struct e1000_adapter *adapter, u64 *data) /* Disable all the interrupts */ ew32(IMC, 0xFFFFFFFF); - msleep(10); + usleep_range(10000, 20000); /* Unhook test interrupt handler */ free_irq(irq, netdev); @@ -1406,7 +1406,7 @@ static int e1000_set_82571_fiber_loopback(struct e1000_adapter *adapter) */ #define E1000_SERDES_LB_ON 0x410 ew32(SCTL, E1000_SERDES_LB_ON); - msleep(10); + usleep_range(10000, 20000); return 0; } @@ -1501,7 +1501,7 @@ static void e1000_loopback_cleanup(struct e1000_adapter *adapter) hw->phy.media_type == e1000_media_type_internal_serdes) { #define E1000_SERDES_LB_OFF 0x400 ew32(SCTL, E1000_SERDES_LB_OFF); - msleep(10); + usleep_range(10000, 20000); break; } /* Fall Through */ diff --git a/drivers/net/e1000e/ich8lan.c b/drivers/net/e1000e/ich8lan.c index ce1dbfd..06ff884 100644 --- a/drivers/net/e1000e/ich8lan.c +++ b/drivers/net/e1000e/ich8lan.c @@ -338,7 +338,7 @@ static s32 e1000_init_phy_params_pchlan(struct e1000_hw *hw) /* Ungate automatic PHY configuration on non-managed 82579 */ if ((hw->mac.type == e1000_pch2lan) && !(fwsm & E1000_ICH_FWSM_FW_VALID)) { - msleep(10); + usleep_range(10000, 20000); e1000_gate_hw_phy_config_ich8lan(hw, false); } @@ -427,7 +427,7 @@ static s32 e1000_init_phy_params_ich8lan(struct e1000_hw *hw) phy->id = 0; while ((e1000_phy_unknown == e1000e_get_phy_type_from_id(phy->id)) && (i++ < 100)) { - msleep(1); + usleep_range(1000, 2000); ret_val = e1000e_get_phy_id(hw); if (ret_val) return ret_val; @@ -1704,7 +1704,7 @@ static s32 e1000_post_phy_reset_ich8lan(struct e1000_hw *hw) goto out; /* Allow time for h/w to get to quiescent state after reset */ - msleep(10); + usleep_range(10000, 20000); /* Perform any necessary post-reset workarounds */ switch (hw->mac.type) { @@ -1737,7 +1737,7 @@ static s32 e1000_post_phy_reset_ich8lan(struct e1000_hw *hw) if (hw->mac.type == e1000_pch2lan) { /* Ungate automatic PHY configuration on non-managed 82579 */ if (!(er32(FWSM) & E1000_ICH_FWSM_FW_VALID)) { - msleep(10); + usleep_range(10000, 20000); e1000_gate_hw_phy_config_ich8lan(hw, false); } @@ -2532,7 +2532,7 @@ release: */ if (!ret_val) { e1000e_reload_nvm(hw); - msleep(10); + usleep_range(10000, 20000); } out: @@ -3009,7 +3009,7 @@ static s32 e1000_reset_hw_ich8lan(struct e1000_hw *hw) ew32(TCTL, E1000_TCTL_PSP); e1e_flush(); - msleep(10); + usleep_range(10000, 20000); /* Workaround for ICH8 bit corruption issue in FIFO memory */ if (hw->mac.type == e1000_ich8lan) { diff --git a/drivers/net/e1000e/lib.c b/drivers/net/e1000e/lib.c index 96921de5..30ef8fa 100644 --- a/drivers/net/e1000e/lib.c +++ b/drivers/net/e1000e/lib.c @@ -868,7 +868,7 @@ static s32 e1000_poll_fiber_serdes_link_generic(struct e1000_hw *hw) * milliseconds even if the other end is doing it in SW). */ for (i = 0; i < FIBER_LINK_UP_LIMIT; i++) { - msleep(10); + usleep_range(10000, 20000); status = er32(STATUS); if (status & E1000_STATUS_LU) break; @@ -930,7 +930,7 @@ s32 e1000e_setup_fiber_serdes_link(struct e1000_hw *hw) ew32(CTRL, ctrl); e1e_flush(); - msleep(1); + usleep_range(1000, 2000); /* * For these adapters, the SW definable pin 1 is set when the optics @@ -1385,7 +1385,7 @@ s32 e1000e_get_auto_rd_done(struct e1000_hw *hw) while (i < AUTO_READ_DONE_TIMEOUT) { if (er32(EECD) & E1000_EECD_AUTO_RD) break; - msleep(1); + usleep_range(1000, 2000); i++; } @@ -2087,8 +2087,6 @@ s32 e1000e_write_nvm_spi(struct e1000_hw *hw, u16 offset, u16 words, u16 *data) if (ret_val) return ret_val; - msleep(10); - while (widx < words) { u8 write_opcode = NVM_WRITE_OPCODE_SPI; @@ -2132,7 +2130,7 @@ s32 e1000e_write_nvm_spi(struct e1000_hw *hw, u16 offset, u16 words, u16 *data) } } - msleep(10); + usleep_range(10000, 20000); nvm->ops.release(hw); return 0; } diff --git a/drivers/net/e1000e/netdev.c b/drivers/net/e1000e/netdev.c index 506a0a0..909c8de 100644 --- a/drivers/net/e1000e/netdev.c +++ b/drivers/net/e1000e/netdev.c @@ -2902,7 +2902,7 @@ static void e1000_configure_rx(struct e1000_adapter *adapter) rctl = er32(RCTL); ew32(RCTL, rctl & ~E1000_RCTL_EN); e1e_flush(); - msleep(10); + usleep_range(10000, 20000); if (adapter->flags2 & FLAG2_DMA_BURST) { /* @@ -3383,7 +3383,7 @@ void e1000e_down(struct e1000_adapter *adapter) ew32(TCTL, tctl); /* flush both disables and wait for them to finish */ e1e_flush(); - msleep(10); + usleep_range(10000, 20000); napi_disable(&adapter->napi); e1000_irq_disable(adapter); @@ -3418,7 +3418,7 @@ void e1000e_reinit_locked(struct e1000_adapter *adapter) { might_sleep(); while (test_and_set_bit(__E1000_RESETTING, &adapter->state)) - msleep(1); + usleep_range(1000, 2000); e1000e_down(adapter); e1000e_up(adapter); clear_bit(__E1000_RESETTING, &adapter->state); @@ -5028,7 +5028,7 @@ static int e1000_change_mtu(struct net_device *netdev, int new_mtu) } while (test_and_set_bit(__E1000_RESETTING, &adapter->state)) - msleep(1); + usleep_range(1000, 2000); /* e1000e_down -> e1000e_reset dependent on max_frame_size & mtu */ adapter->max_frame_size = max_frame; e_info("changing MTU from %d to %d\n", netdev->mtu, new_mtu); diff --git a/drivers/net/e1000e/phy.c b/drivers/net/e1000e/phy.c index 6ae31fc..484774c 100644 --- a/drivers/net/e1000e/phy.c +++ b/drivers/net/e1000e/phy.c @@ -2372,7 +2372,7 @@ s32 e1000e_determine_phy_address(struct e1000_hw *hw) ret_val = 0; goto out; } - msleep(1); + usleep_range(1000, 2000); i++; } while (i < 10); } @@ -2740,7 +2740,7 @@ void e1000_power_down_phy_copper(struct e1000_hw *hw) e1e_rphy(hw, PHY_CONTROL, &mii_reg); mii_reg |= MII_CR_POWER_DOWN; e1e_wphy(hw, PHY_CONTROL, mii_reg); - msleep(1); + usleep_range(1000, 2000); } /** -- cgit v0.10.2 From a5cc764206a3d01dce8ebc17b4e1534afb53c495 Mon Sep 17 00:00:00 2001 From: Bruce Allan Date: Sat, 19 Mar 2011 00:31:23 +0000 Subject: e1000e: PCIe link speed in GT/s, not GB/s Correct the log message when driver loads. Signed-off-by: Bruce Allan Tested-by: Aaron Brown Signed-off-by: Jeff Kirsher diff --git a/drivers/net/e1000e/netdev.c b/drivers/net/e1000e/netdev.c index 909c8de..99c8c7c 100644 --- a/drivers/net/e1000e/netdev.c +++ b/drivers/net/e1000e/netdev.c @@ -5714,7 +5714,7 @@ static void e1000_print_device_info(struct e1000_adapter *adapter) u8 pba_str[E1000_PBANUM_LENGTH]; /* print bus type/speed/width info */ - e_info("(PCI Express:2.5GB/s:%s) %pM\n", + e_info("(PCI Express:2.5GT/s:%s) %pM\n", /* bus width */ ((hw->bus.width == e1000_bus_width_pcie_x4) ? "Width x4" : "Width x1"), -- cgit v0.10.2 From 86d70e532c352bd309dab5f1d18d113f441cb3ae Mon Sep 17 00:00:00 2001 From: Jeff Kirsher Date: Fri, 25 Mar 2011 16:01:01 +0000 Subject: e1000e: convert to new VLAN model This switches the e1000e driver to use the new VLAN interfaces. CC: Jesse Gross Signed-off-by: Jeff Kirsher Tested-by: Jeff Pieper diff --git a/drivers/net/e1000e/e1000.h b/drivers/net/e1000e/e1000.h index 00bf595..500896e 100644 --- a/drivers/net/e1000e/e1000.h +++ b/drivers/net/e1000e/e1000.h @@ -31,6 +31,7 @@ #ifndef _E1000_H_ #define _E1000_H_ +#include #include #include #include @@ -39,6 +40,7 @@ #include #include #include +#include #include "hw.h" @@ -280,7 +282,7 @@ struct e1000_adapter { const struct e1000_info *ei; - struct vlan_group *vlgrp; + unsigned long active_vlans[BITS_TO_LONGS(VLAN_N_VID)]; u32 bd_number; u32 rx_buffer_len; u16 mng_vlan_id; diff --git a/drivers/net/e1000e/ethtool.c b/drivers/net/e1000e/ethtool.c index 5b4cf90..a31d280 100644 --- a/drivers/net/e1000e/ethtool.c +++ b/drivers/net/e1000e/ethtool.c @@ -2020,6 +2020,31 @@ static void e1000_get_strings(struct net_device *netdev, u32 stringset, } } +static int e1000e_set_flags(struct net_device *netdev, u32 data) +{ + struct e1000_adapter *adapter = netdev_priv(netdev); + bool need_reset = false; + int rc; + + need_reset = (data & ETH_FLAG_RXVLAN) != + (netdev->features & NETIF_F_HW_VLAN_RX); + + rc = ethtool_op_set_flags(netdev, data, ETH_FLAG_RXVLAN | + ETH_FLAG_TXVLAN); + + if (rc) + return rc; + + if (need_reset) { + if (netif_running(netdev)) + e1000e_reinit_locked(adapter); + else + e1000e_reset(adapter); + } + + return 0; +} + static const struct ethtool_ops e1000_ethtool_ops = { .get_settings = e1000_get_settings, .set_settings = e1000_set_settings, @@ -2055,6 +2080,7 @@ static const struct ethtool_ops e1000_ethtool_ops = { .get_coalesce = e1000_get_coalesce, .set_coalesce = e1000_set_coalesce, .get_flags = ethtool_op_get_flags, + .set_flags = e1000e_set_flags, }; void e1000e_set_ethtool_ops(struct net_device *netdev) diff --git a/drivers/net/e1000e/netdev.c b/drivers/net/e1000e/netdev.c index 99c8c7c..8812eb2 100644 --- a/drivers/net/e1000e/netdev.c +++ b/drivers/net/e1000e/netdev.c @@ -459,13 +459,13 @@ static void e1000_receive_skb(struct e1000_adapter *adapter, struct net_device *netdev, struct sk_buff *skb, u8 status, __le16 vlan) { + u16 tag = le16_to_cpu(vlan); skb->protocol = eth_type_trans(skb, netdev); - if (adapter->vlgrp && (status & E1000_RXD_STAT_VP)) - vlan_gro_receive(&adapter->napi, adapter->vlgrp, - le16_to_cpu(vlan), skb); - else - napi_gro_receive(&adapter->napi, skb); + if (status & E1000_RXD_STAT_VP) + __vlan_hwaccel_put_tag(skb, tag); + + napi_gro_receive(&adapter->napi, skb); } /** @@ -2433,6 +2433,8 @@ static void e1000_vlan_rx_add_vid(struct net_device *netdev, u16 vid) vfta |= (1 << (vid & 0x1F)); hw->mac.ops.write_vfta(hw, index, vfta); } + + set_bit(vid, adapter->active_vlans); } static void e1000_vlan_rx_kill_vid(struct net_device *netdev, u16 vid) @@ -2441,13 +2443,6 @@ static void e1000_vlan_rx_kill_vid(struct net_device *netdev, u16 vid) struct e1000_hw *hw = &adapter->hw; u32 vfta, index; - if (!test_bit(__E1000_DOWN, &adapter->state)) - e1000_irq_disable(adapter); - vlan_group_set_device(adapter->vlgrp, vid, NULL); - - if (!test_bit(__E1000_DOWN, &adapter->state)) - e1000_irq_enable(adapter); - if ((adapter->hw.mng_cookie.status & E1000_MNG_DHCP_COOKIE_STATUS_VLAN) && (vid == adapter->mng_vlan_id)) { @@ -2463,93 +2458,105 @@ static void e1000_vlan_rx_kill_vid(struct net_device *netdev, u16 vid) vfta &= ~(1 << (vid & 0x1F)); hw->mac.ops.write_vfta(hw, index, vfta); } + + clear_bit(vid, adapter->active_vlans); } -static void e1000_update_mng_vlan(struct e1000_adapter *adapter) +/** + * e1000e_vlan_filter_disable - helper to disable hw VLAN filtering + * @adapter: board private structure to initialize + **/ +static void e1000e_vlan_filter_disable(struct e1000_adapter *adapter) { struct net_device *netdev = adapter->netdev; - u16 vid = adapter->hw.mng_cookie.vlan_id; - u16 old_vid = adapter->mng_vlan_id; - - if (!adapter->vlgrp) - return; + struct e1000_hw *hw = &adapter->hw; + u32 rctl; - if (!vlan_group_get_device(adapter->vlgrp, vid)) { - adapter->mng_vlan_id = E1000_MNG_VLAN_NONE; - if (adapter->hw.mng_cookie.status & - E1000_MNG_DHCP_COOKIE_STATUS_VLAN) { - e1000_vlan_rx_add_vid(netdev, vid); - adapter->mng_vlan_id = vid; + if (adapter->flags & FLAG_HAS_HW_VLAN_FILTER) { + /* disable VLAN receive filtering */ + rctl = er32(RCTL); + rctl &= ~(E1000_RCTL_VFE | E1000_RCTL_CFIEN); + ew32(RCTL, rctl); + + if (adapter->mng_vlan_id != (u16)E1000_MNG_VLAN_NONE) { + e1000_vlan_rx_kill_vid(netdev, adapter->mng_vlan_id); + adapter->mng_vlan_id = E1000_MNG_VLAN_NONE; } - - if ((old_vid != (u16)E1000_MNG_VLAN_NONE) && - (vid != old_vid) && - !vlan_group_get_device(adapter->vlgrp, old_vid)) - e1000_vlan_rx_kill_vid(netdev, old_vid); - } else { - adapter->mng_vlan_id = vid; } } +/** + * e1000e_vlan_filter_enable - helper to enable HW VLAN filtering + * @adapter: board private structure to initialize + **/ +static void e1000e_vlan_filter_enable(struct e1000_adapter *adapter) +{ + struct e1000_hw *hw = &adapter->hw; + u32 rctl; + + if (adapter->flags & FLAG_HAS_HW_VLAN_FILTER) { + /* enable VLAN receive filtering */ + rctl = er32(RCTL); + rctl |= E1000_RCTL_VFE; + rctl &= ~E1000_RCTL_CFIEN; + ew32(RCTL, rctl); + } +} -static void e1000_vlan_rx_register(struct net_device *netdev, - struct vlan_group *grp) +/** + * e1000e_vlan_strip_enable - helper to disable HW VLAN stripping + * @adapter: board private structure to initialize + **/ +static void e1000e_vlan_strip_disable(struct e1000_adapter *adapter) { - struct e1000_adapter *adapter = netdev_priv(netdev); struct e1000_hw *hw = &adapter->hw; - u32 ctrl, rctl; + u32 ctrl; - if (!test_bit(__E1000_DOWN, &adapter->state)) - e1000_irq_disable(adapter); - adapter->vlgrp = grp; + /* disable VLAN tag insert/strip */ + ctrl = er32(CTRL); + ctrl &= ~E1000_CTRL_VME; + ew32(CTRL, ctrl); +} - if (grp) { - /* enable VLAN tag insert/strip */ - ctrl = er32(CTRL); - ctrl |= E1000_CTRL_VME; - ew32(CTRL, ctrl); +/** + * e1000e_vlan_strip_enable - helper to enable HW VLAN stripping + * @adapter: board private structure to initialize + **/ +static void e1000e_vlan_strip_enable(struct e1000_adapter *adapter) +{ + struct e1000_hw *hw = &adapter->hw; + u32 ctrl; - if (adapter->flags & FLAG_HAS_HW_VLAN_FILTER) { - /* enable VLAN receive filtering */ - rctl = er32(RCTL); - rctl &= ~E1000_RCTL_CFIEN; - ew32(RCTL, rctl); - e1000_update_mng_vlan(adapter); - } - } else { - /* disable VLAN tag insert/strip */ - ctrl = er32(CTRL); - ctrl &= ~E1000_CTRL_VME; - ew32(CTRL, ctrl); + /* enable VLAN tag insert/strip */ + ctrl = er32(CTRL); + ctrl |= E1000_CTRL_VME; + ew32(CTRL, ctrl); +} - if (adapter->flags & FLAG_HAS_HW_VLAN_FILTER) { - if (adapter->mng_vlan_id != - (u16)E1000_MNG_VLAN_NONE) { - e1000_vlan_rx_kill_vid(netdev, - adapter->mng_vlan_id); - adapter->mng_vlan_id = E1000_MNG_VLAN_NONE; - } - } +static void e1000_update_mng_vlan(struct e1000_adapter *adapter) +{ + struct net_device *netdev = adapter->netdev; + u16 vid = adapter->hw.mng_cookie.vlan_id; + u16 old_vid = adapter->mng_vlan_id; + + if (adapter->hw.mng_cookie.status & + E1000_MNG_DHCP_COOKIE_STATUS_VLAN) { + e1000_vlan_rx_add_vid(netdev, vid); + adapter->mng_vlan_id = vid; } - if (!test_bit(__E1000_DOWN, &adapter->state)) - e1000_irq_enable(adapter); + if ((old_vid != (u16)E1000_MNG_VLAN_NONE) && (vid != old_vid)) + e1000_vlan_rx_kill_vid(netdev, old_vid); } static void e1000_restore_vlan(struct e1000_adapter *adapter) { u16 vid; - e1000_vlan_rx_register(adapter->netdev, adapter->vlgrp); - - if (!adapter->vlgrp) - return; + e1000_vlan_rx_add_vid(adapter->netdev, 0); - for (vid = 0; vid < VLAN_N_VID; vid++) { - if (!vlan_group_get_device(adapter->vlgrp, vid)) - continue; + for_each_set_bit(vid, adapter->active_vlans, VLAN_N_VID) e1000_vlan_rx_add_vid(adapter->netdev, vid); - } } static void e1000_init_manageability_pt(struct e1000_adapter *adapter) @@ -3039,6 +3046,8 @@ static void e1000_set_multi(struct net_device *netdev) if (netdev->flags & IFF_PROMISC) { rctl |= (E1000_RCTL_UPE | E1000_RCTL_MPE); rctl &= ~E1000_RCTL_VFE; + /* Do not hardware filter VLANs in promisc mode */ + e1000e_vlan_filter_disable(adapter); } else { if (netdev->flags & IFF_ALLMULTI) { rctl |= E1000_RCTL_MPE; @@ -3046,8 +3055,7 @@ static void e1000_set_multi(struct net_device *netdev) } else { rctl &= ~(E1000_RCTL_UPE | E1000_RCTL_MPE); } - if (adapter->flags & FLAG_HAS_HW_VLAN_FILTER) - rctl |= E1000_RCTL_VFE; + e1000e_vlan_filter_enable(adapter); } ew32(RCTL, rctl); @@ -3072,6 +3080,11 @@ static void e1000_set_multi(struct net_device *netdev) */ e1000_update_mc_addr_list(hw, NULL, 0); } + + if (netdev->features & NETIF_F_HW_VLAN_RX) + e1000e_vlan_strip_enable(adapter); + else + e1000e_vlan_strip_disable(adapter); } /** @@ -3721,10 +3734,8 @@ static int e1000_close(struct net_device *netdev) * kill manageability vlan ID if supported, but not if a vlan with * the same ID is registered on the host OS (let 8021q kill it) */ - if ((adapter->hw.mng_cookie.status & - E1000_MNG_DHCP_COOKIE_STATUS_VLAN) && - !(adapter->vlgrp && - vlan_group_get_device(adapter->vlgrp, adapter->mng_vlan_id))) + if (adapter->hw.mng_cookie.status & + E1000_MNG_DHCP_COOKIE_STATUS_VLAN) e1000_vlan_rx_kill_vid(netdev, adapter->mng_vlan_id); /* @@ -5759,7 +5770,6 @@ static const struct net_device_ops e1000e_netdev_ops = { .ndo_tx_timeout = e1000_tx_timeout, .ndo_validate_addr = eth_validate_addr, - .ndo_vlan_rx_register = e1000_vlan_rx_register, .ndo_vlan_rx_add_vid = e1000_vlan_rx_add_vid, .ndo_vlan_rx_kill_vid = e1000_vlan_rx_kill_vid, #ifdef CONFIG_NET_POLL_CONTROLLER -- cgit v0.10.2 From 2084b114e3fb0d84e5882f5ee6c7039be52da715 Mon Sep 17 00:00:00 2001 From: Flavio Leitner Date: Tue, 5 Apr 2011 04:27:43 +0000 Subject: e1000e: fix stats locking in e1000_watchdog_task Just move the unlock down a bit because it unlocks too early leaving a chance for get_stats64() run in parallel while it is still accessing the stats. Signed-off-by: Flavio Leitner Acked-by: Bruce Allan Tested-by: Aaron Brown Signed-off-by: Jeff Kirsher diff --git a/drivers/net/e1000e/netdev.c b/drivers/net/e1000e/netdev.c index 8812eb2..8a3145e 100644 --- a/drivers/net/e1000e/netdev.c +++ b/drivers/net/e1000e/netdev.c @@ -4339,7 +4339,6 @@ static void e1000_watchdog_task(struct work_struct *work) link_up: spin_lock(&adapter->stats64_lock); e1000e_update_stats(adapter); - spin_unlock(&adapter->stats64_lock); mac->tx_packet_delta = adapter->stats.tpt - adapter->tpt_old; adapter->tpt_old = adapter->stats.tpt; @@ -4350,6 +4349,7 @@ link_up: adapter->gorc_old = adapter->stats.gorc; adapter->gotc = adapter->stats.gotc - adapter->gotc_old; adapter->gotc_old = adapter->stats.gotc; + spin_unlock(&adapter->stats64_lock); e1000e_update_adaptive(&adapter->hw); -- cgit v0.10.2 From 78cd29d5a92ae5067377ad42089f2c8781312f4a Mon Sep 17 00:00:00 2001 From: Bruce Allan Date: Thu, 24 Mar 2011 03:09:03 +0000 Subject: e1000e: If ASPM L0s needs to be disabled, do it prior to enabling device Based on a patch from Naga Chumbalkar : If ASPM L0s needs to be disabled due to HW errata, do it prior to "enabling" the device. This way if the kernel ever defaults its aspm_policy to POLICY_POWERSAVE, then the e1000e driver will get a chance to disable ASPM on the misbehaving device *prior* to calling pci_enable_device_mem(). This will be useful in situations where the BIOS indicates ASPM support on the server by clearing the ACPI FADT "ASPM Controls" bit. Note: The kernel (2.6.38) currently uses the BIOS "default" as its aspm_policy. However, Linux distros can diverge from that and set the default to "powersave". v2: o cleanup namespace pollution of e1000e_disable_aspm(), o fix type and initialization of the new aspm_disable_flag in a few functions, and o redefine FLAG2_DISABLE_ASPM_L0S to the first unused bit in adapter->flags2. Signed-off-by: Bruce Allan Cc: Naga Chumbalkar Tested-by: Aaron Brown Signed-off-by: Jeff Kirsher diff --git a/drivers/net/e1000e/82571.c b/drivers/net/e1000e/82571.c index 9fedbca..ae07d37 100644 --- a/drivers/net/e1000e/82571.c +++ b/drivers/net/e1000e/82571.c @@ -431,9 +431,6 @@ static s32 e1000_get_variants_82571(struct e1000_adapter *adapter) case e1000_82573: case e1000_82574: case e1000_82583: - /* Disable ASPM L0s due to hardware errata */ - e1000e_disable_aspm(adapter->pdev, PCIE_LINK_STATE_L0S); - if (pdev->device == E1000_DEV_ID_82573L) { adapter->flags |= FLAG_HAS_JUMBO_FRAMES; adapter->max_hw_frame_size = DEFAULT_JUMBO; @@ -2066,7 +2063,8 @@ struct e1000_info e1000_82573_info = { | FLAG_HAS_SMART_POWER_DOWN | FLAG_HAS_AMT | FLAG_HAS_SWSM_ON_LOAD, - .flags2 = FLAG2_DISABLE_ASPM_L1, + .flags2 = FLAG2_DISABLE_ASPM_L1 + | FLAG2_DISABLE_ASPM_L0S, .pba = 20, .max_hw_frame_size = ETH_FRAME_LEN + ETH_FCS_LEN, .get_variants = e1000_get_variants_82571, @@ -2086,7 +2084,8 @@ struct e1000_info e1000_82574_info = { | FLAG_HAS_SMART_POWER_DOWN | FLAG_HAS_AMT | FLAG_HAS_CTRLEXT_ON_LOAD, - .flags2 = FLAG2_CHECK_PHY_HANG, + .flags2 = FLAG2_CHECK_PHY_HANG + | FLAG2_DISABLE_ASPM_L0S, .pba = 32, .max_hw_frame_size = DEFAULT_JUMBO, .get_variants = e1000_get_variants_82571, @@ -2104,6 +2103,7 @@ struct e1000_info e1000_82583_info = { | FLAG_HAS_SMART_POWER_DOWN | FLAG_HAS_AMT | FLAG_HAS_CTRLEXT_ON_LOAD, + .flags2 = FLAG2_DISABLE_ASPM_L0S, .pba = 32, .max_hw_frame_size = ETH_FRAME_LEN + ETH_FCS_LEN, .get_variants = e1000_get_variants_82571, diff --git a/drivers/net/e1000e/e1000.h b/drivers/net/e1000e/e1000.h index 500896e..3be5478 100644 --- a/drivers/net/e1000e/e1000.h +++ b/drivers/net/e1000e/e1000.h @@ -458,6 +458,7 @@ struct e1000_info { #define FLAG2_HAS_PHY_STATS (1 << 4) #define FLAG2_HAS_EEE (1 << 5) #define FLAG2_DMA_BURST (1 << 6) +#define FLAG2_DISABLE_ASPM_L0S (1 << 7) #define FLAG2_DISABLE_AIM (1 << 8) #define FLAG2_CHECK_PHY_HANG (1 << 9) @@ -504,7 +505,6 @@ extern void e1000e_set_interrupt_capability(struct e1000_adapter *adapter); extern void e1000e_reset_interrupt_capability(struct e1000_adapter *adapter); extern void e1000e_get_hw_control(struct e1000_adapter *adapter); extern void e1000e_release_hw_control(struct e1000_adapter *adapter); -extern void e1000e_disable_aspm(struct pci_dev *pdev, u16 state); extern unsigned int copybreak; diff --git a/drivers/net/e1000e/netdev.c b/drivers/net/e1000e/netdev.c index 8a3145e..4deb67d 100644 --- a/drivers/net/e1000e/netdev.c +++ b/drivers/net/e1000e/netdev.c @@ -58,6 +58,8 @@ char e1000e_driver_name[] = "e1000e"; const char e1000e_driver_version[] = DRV_VERSION; +static void e1000e_disable_aspm(struct pci_dev *pdev, u16 state); + static const struct e1000_info *e1000_info_tbl[] = { [board_82571] = &e1000_82571_info, [board_82572] = &e1000_82572_info, @@ -5384,7 +5386,7 @@ static void __e1000e_disable_aspm(struct pci_dev *pdev, u16 state) pci_write_config_word(pdev->bus->self, pos + PCI_EXP_LNKCTL, reg16); } #endif -void e1000e_disable_aspm(struct pci_dev *pdev, u16 state) +static void e1000e_disable_aspm(struct pci_dev *pdev, u16 state) { dev_info(&pdev->dev, "Disabling ASPM %s %s\n", (state & PCIE_LINK_STATE_L0S) ? "L0s" : "", @@ -5404,13 +5406,19 @@ static int __e1000_resume(struct pci_dev *pdev) struct net_device *netdev = pci_get_drvdata(pdev); struct e1000_adapter *adapter = netdev_priv(netdev); struct e1000_hw *hw = &adapter->hw; + u16 aspm_disable_flag = 0; u32 err; + if (adapter->flags2 & FLAG2_DISABLE_ASPM_L0S) + aspm_disable_flag = PCIE_LINK_STATE_L0S; + if (adapter->flags2 & FLAG2_DISABLE_ASPM_L1) + aspm_disable_flag |= PCIE_LINK_STATE_L1; + if (aspm_disable_flag) + e1000e_disable_aspm(pdev, aspm_disable_flag); + pci_set_power_state(pdev, PCI_D0); pci_restore_state(pdev); pci_save_state(pdev); - if (adapter->flags2 & FLAG2_DISABLE_ASPM_L1) - e1000e_disable_aspm(pdev, PCIE_LINK_STATE_L1); e1000e_set_interrupt_capability(adapter); if (netif_running(netdev)) { @@ -5654,11 +5662,17 @@ static pci_ers_result_t e1000_io_slot_reset(struct pci_dev *pdev) struct net_device *netdev = pci_get_drvdata(pdev); struct e1000_adapter *adapter = netdev_priv(netdev); struct e1000_hw *hw = &adapter->hw; + u16 aspm_disable_flag = 0; int err; pci_ers_result_t result; + if (adapter->flags2 & FLAG2_DISABLE_ASPM_L0S) + aspm_disable_flag = PCIE_LINK_STATE_L0S; if (adapter->flags2 & FLAG2_DISABLE_ASPM_L1) - e1000e_disable_aspm(pdev, PCIE_LINK_STATE_L1); + aspm_disable_flag |= PCIE_LINK_STATE_L1; + if (aspm_disable_flag) + e1000e_disable_aspm(pdev, aspm_disable_flag); + err = pci_enable_device_mem(pdev); if (err) { dev_err(&pdev->dev, @@ -5799,12 +5813,17 @@ static int __devinit e1000_probe(struct pci_dev *pdev, resource_size_t flash_start, flash_len; static int cards_found; + u16 aspm_disable_flag = 0; int i, err, pci_using_dac; u16 eeprom_data = 0; u16 eeprom_apme_mask = E1000_EEPROM_APME; + if (ei->flags2 & FLAG2_DISABLE_ASPM_L0S) + aspm_disable_flag = PCIE_LINK_STATE_L0S; if (ei->flags2 & FLAG2_DISABLE_ASPM_L1) - e1000e_disable_aspm(pdev, PCIE_LINK_STATE_L1); + aspm_disable_flag |= PCIE_LINK_STATE_L1; + if (aspm_disable_flag) + e1000e_disable_aspm(pdev, aspm_disable_flag); err = pci_enable_device_mem(pdev); if (err) -- cgit v0.10.2 From c8ca76ebc6e50752c5311b92bb9aef7edb324577 Mon Sep 17 00:00:00 2001 From: John Fastabend Date: Sat, 12 Mar 2011 03:50:53 +0000 Subject: ixgbe: DCB, further cleanups to app configuration With the app data on the kernel dcb_app list we no longer need to specifically handle them in ixgbe for the CEE case. So now we can remove app handling logic and check when the hw is configured if the app data matches the hardware configuration in set_hw_all(). If it does not match then we can reconfigure. Signed-off-by: John Fastabend Tested-by: Ross Brattain Signed-off-by: Jeff Kirsher diff --git a/drivers/net/ixgbe/ixgbe_dcb_nl.c b/drivers/net/ixgbe/ixgbe_dcb_nl.c index 327c861..7b59f64 100644 --- a/drivers/net/ixgbe/ixgbe_dcb_nl.c +++ b/drivers/net/ixgbe/ixgbe_dcb_nl.c @@ -347,18 +347,28 @@ static void ixgbe_dcbnl_get_pfc_cfg(struct net_device *netdev, int priority, static u8 ixgbe_dcbnl_set_all(struct net_device *netdev) { struct ixgbe_adapter *adapter = netdev_priv(netdev); + struct dcb_app app = { + .selector = DCB_APP_IDTYPE_ETHTYPE, + .protocol = ETH_P_FCOE, + }; + u8 up = dcb_getapp(netdev, &app); int ret; - if (!adapter->dcb_set_bitmap || - !(adapter->dcbx_cap & DCB_CAP_DCBX_VER_CEE)) - return DCB_NO_HW_CHG; - ret = ixgbe_copy_dcb_cfg(&adapter->temp_dcb_cfg, &adapter->dcb_cfg, MAX_TRAFFIC_CLASS); - if (ret) return DCB_NO_HW_CHG; + /* In IEEE mode app data must be parsed into DCBX format for + * hardware routines. + */ + if (adapter->dcbx_cap & DCB_CAP_DCBX_VER_IEEE) + up = (1 << up); + +#ifdef IXGBE_FCOE + if (up && (up != (1 << adapter->fcoe.up))) + adapter->dcb_set_bitmap |= BIT_APP_UPCHG; + /* * Only take down the adapter if an app change occurred. FCoE * may shuffle tx rings in this case and this can not be done @@ -368,10 +378,13 @@ static u8 ixgbe_dcbnl_set_all(struct net_device *netdev) while (test_and_set_bit(__IXGBE_RESETTING, &adapter->state)) msleep(1); + ixgbe_fcoe_setapp(adapter, up); + if (netif_running(netdev)) netdev->netdev_ops->ndo_stop(netdev); ixgbe_clear_interrupt_scheme(adapter); } +#endif if (adapter->dcb_cfg.pfc_mode_enable) { switch (adapter->hw.mac.type) { @@ -399,12 +412,14 @@ static u8 ixgbe_dcbnl_set_all(struct net_device *netdev) } } +#ifdef IXGBE_FCOE if (adapter->dcb_set_bitmap & BIT_APP_UPCHG) { ixgbe_init_interrupt_scheme(adapter); if (netif_running(netdev)) netdev->netdev_ops->ndo_open(netdev); ret = DCB_HW_CHG_RST; } +#endif if (adapter->dcb_set_bitmap & BIT_PFC) { u8 pfc_en; @@ -558,68 +573,6 @@ static u8 ixgbe_dcbnl_getapp(struct net_device *netdev, u8 idtype, u16 id) return dcb_getapp(netdev, &app); } -/** - * ixgbe_dcbnl_setapp - set the DCBX application user priority - * @netdev : the corresponding netdev - * @idtype : identifies the id as ether type or TCP/UDP port number - * @id: id is either ether type or TCP/UDP port number - * @up: the 802.1p user priority bitmap - * - * Returns : 0 on success or 1 on error - */ -static u8 ixgbe_dcbnl_setapp(struct net_device *netdev, - u8 idtype, u16 id, u8 up) -{ - struct ixgbe_adapter *adapter = netdev_priv(netdev); - u8 rval = 1; - struct dcb_app app = { - .selector = idtype, - .protocol = id, - .priority = up - }; - - if (!(adapter->dcbx_cap & DCB_CAP_DCBX_VER_CEE)) - return rval; - - rval = dcb_setapp(netdev, &app); - - switch (idtype) { - case DCB_APP_IDTYPE_ETHTYPE: -#ifdef IXGBE_FCOE - if (id == ETH_P_FCOE) { - u8 old_tc; - - /* Get current programmed tc */ - old_tc = adapter->fcoe.tc; - rval = ixgbe_fcoe_setapp(adapter, up); - - if (rval || - !(adapter->flags & IXGBE_FLAG_DCB_ENABLED) || - !(adapter->flags & IXGBE_FLAG_FCOE_ENABLED)) - break; - - /* The FCoE application priority may be changed multiple - * times in quick succession with switches that build up - * TLVs. To avoid creating uneeded device resets this - * checks the actual HW configuration and clears - * BIT_APP_UPCHG if a HW configuration change is not - * need - */ - if (old_tc == adapter->fcoe.tc) - adapter->dcb_set_bitmap &= ~BIT_APP_UPCHG; - else - adapter->dcb_set_bitmap |= BIT_APP_UPCHG; - } -#endif - break; - case DCB_APP_IDTYPE_PORTNUM: - break; - default: - break; - } - return rval; -} - static int ixgbe_dcbnl_ieee_getets(struct net_device *dev, struct ieee_ets *ets) { @@ -745,25 +698,14 @@ static int ixgbe_dcbnl_ieee_setapp(struct net_device *dev, if (!(adapter->dcbx_cap & DCB_CAP_DCBX_VER_IEEE)) return -EINVAL; -#ifdef IXGBE_FCOE - if (app->selector == 1 && app->protocol == ETH_P_FCOE) { - if (adapter->fcoe.tc == app->priority) - goto setapp; - /* In IEEE mode map up to tc 1:1 */ - adapter->fcoe.tc = app->priority; - adapter->fcoe.up = app->priority; + dcb_setapp(dev, app); - /* Force hardware reset required to push FCoE - * setup on {tx|rx}_rings - */ - adapter->dcb_set_bitmap |= BIT_APP_UPCHG; +#ifdef IXGBE_FCOE + if (app->selector == 1 && app->protocol == ETH_P_FCOE && + adapter->fcoe.tc == app->priority) ixgbe_dcbnl_set_all(dev); - } - -setapp: #endif - dcb_setapp(dev, app); return 0; } @@ -838,7 +780,6 @@ const struct dcbnl_rtnl_ops dcbnl_ops = { .getpfcstate = ixgbe_dcbnl_getpfcstate, .setpfcstate = ixgbe_dcbnl_setpfcstate, .getapp = ixgbe_dcbnl_getapp, - .setapp = ixgbe_dcbnl_setapp, .getdcbx = ixgbe_dcbnl_getdcbx, .setdcbx = ixgbe_dcbnl_setdcbx, }; -- cgit v0.10.2 From 2ea5ea5fc4f4f1daa74708c2a14e364d8474812d Mon Sep 17 00:00:00 2001 From: Emil Tantilov Date: Sat, 12 Mar 2011 08:56:38 +0000 Subject: ixgbe: fix return value checks The value of status was incorrectly tested. Also whitespace cleanup. Signed-off-by: Emil Tantilov Tested-by: Evan Swanson Signed-off-by: Jeff Kirsher diff --git a/drivers/net/ixgbe/ixgbe_x540.c b/drivers/net/ixgbe/ixgbe_x540.c index d9323c0..7ce3f45 100644 --- a/drivers/net/ixgbe/ixgbe_x540.c +++ b/drivers/net/ixgbe/ixgbe_x540.c @@ -452,7 +452,7 @@ static s32 ixgbe_update_flash_X540(struct ixgbe_hw *hw) IXGBE_WRITE_REG(hw, IXGBE_EEC, flup); status = ixgbe_poll_flash_update_done_X540(hw); - if (status) + if (status == 0) hw_dbg(hw, "Flash update complete\n"); else hw_dbg(hw, "Flash update time out\n"); @@ -466,11 +466,10 @@ static s32 ixgbe_update_flash_X540(struct ixgbe_hw *hw) } status = ixgbe_poll_flash_update_done_X540(hw); - if (status) + if (status == 0) hw_dbg(hw, "Flash update complete\n"); else hw_dbg(hw, "Flash update time out\n"); - } out: return status; -- cgit v0.10.2 From c9130180a8dc48943f2a072acec4a53616a1f0ab Mon Sep 17 00:00:00 2001 From: Emil Tantilov Date: Wed, 16 Mar 2011 01:55:55 +0000 Subject: ixgbe: correct function number for some 82598 parts Some 82598 parts have LAN0 disabled and LAN1 enabled and the LAN ID bits in Device Status register report the NIC as having only LAN1 as enabled. This causes ixgbe_set_lan_id_multi_port_pcie() to set bus->func = 1 which is incorrect. Force bus->func to 0 when LAN0 is disabled in the EEPROM. Signed-off-by: Emil Tantilov Tested-by: Evan Swanson Signed-off-by: Jeff Kirsher diff --git a/drivers/net/ixgbe/ixgbe_82598.c b/drivers/net/ixgbe/ixgbe_82598.c index 845c679..c9b6574 100644 --- a/drivers/net/ixgbe/ixgbe_82598.c +++ b/drivers/net/ixgbe/ixgbe_82598.c @@ -1188,6 +1188,38 @@ out: return physical_layer; } +/** + * ixgbe_set_lan_id_multi_port_pcie_82598 - Set LAN id for PCIe multiple + * port devices. + * @hw: pointer to the HW structure + * + * Calls common function and corrects issue with some single port devices + * that enable LAN1 but not LAN0. + **/ +static void ixgbe_set_lan_id_multi_port_pcie_82598(struct ixgbe_hw *hw) +{ + struct ixgbe_bus_info *bus = &hw->bus; + u16 pci_gen = 0; + u16 pci_ctrl2 = 0; + + ixgbe_set_lan_id_multi_port_pcie(hw); + + /* check if LAN0 is disabled */ + hw->eeprom.ops.read(hw, IXGBE_PCIE_GENERAL_PTR, &pci_gen); + if ((pci_gen != 0) && (pci_gen != 0xFFFF)) { + + hw->eeprom.ops.read(hw, pci_gen + IXGBE_PCIE_CTRL2, &pci_ctrl2); + + /* if LAN0 is completely disabled force function to 0 */ + if ((pci_ctrl2 & IXGBE_PCIE_CTRL2_LAN_DISABLE) && + !(pci_ctrl2 & IXGBE_PCIE_CTRL2_DISABLE_SELECT) && + !(pci_ctrl2 & IXGBE_PCIE_CTRL2_DUMMY_ENABLE)) { + + bus->func = 0; + } + } +} + static struct ixgbe_mac_operations mac_ops_82598 = { .init_hw = &ixgbe_init_hw_generic, .reset_hw = &ixgbe_reset_hw_82598, @@ -1199,7 +1231,7 @@ static struct ixgbe_mac_operations mac_ops_82598 = { .get_mac_addr = &ixgbe_get_mac_addr_generic, .stop_adapter = &ixgbe_stop_adapter_generic, .get_bus_info = &ixgbe_get_bus_info_generic, - .set_lan_id = &ixgbe_set_lan_id_multi_port_pcie, + .set_lan_id = &ixgbe_set_lan_id_multi_port_pcie_82598, .read_analog_reg8 = &ixgbe_read_analog_reg8_82598, .write_analog_reg8 = &ixgbe_write_analog_reg8_82598, .setup_link = &ixgbe_setup_mac_link_82598, diff --git a/drivers/net/ixgbe/ixgbe_type.h b/drivers/net/ixgbe/ixgbe_type.h index 25c1fb7..cd1c2b6 100644 --- a/drivers/net/ixgbe/ixgbe_type.h +++ b/drivers/net/ixgbe/ixgbe_type.h @@ -1616,6 +1616,11 @@ #define IXGBE_FLUDONE_ATTEMPTS 20000 #endif +#define IXGBE_PCIE_CTRL2 0x5 /* PCIe Control 2 Offset */ +#define IXGBE_PCIE_CTRL2_DUMMY_ENABLE 0x8 /* Dummy Function Enable */ +#define IXGBE_PCIE_CTRL2_LAN_DISABLE 0x2 /* LAN PCI Disable */ +#define IXGBE_PCIE_CTRL2_DISABLE_SELECT 0x1 /* LAN Disable Select */ + #define IXGBE_SAN_MAC_ADDR_PORT0_OFFSET 0x0 #define IXGBE_SAN_MAC_ADDR_PORT1_OFFSET 0x3 #define IXGBE_DEVICE_CAPS_ALLOW_ANY_SFP 0x1 -- cgit v0.10.2 From d6cd8e0e75b66896bd4e14c8883d62322831cb8f Mon Sep 17 00:00:00 2001 From: Emil Tantilov Date: Wed, 16 Mar 2011 01:58:20 +0000 Subject: ixgbe: fix namespacecheck issue Set ixgbe_identify_82599() as static Signed-off-by: Emil Tantilov Tested-by: Stephen Ko Signed-off-by: Jeff Kirsher diff --git a/drivers/net/ixgbe/ixgbe_82599.c b/drivers/net/ixgbe/ixgbe_82599.c index 00aeba3..32ad411 100644 --- a/drivers/net/ixgbe/ixgbe_82599.c +++ b/drivers/net/ixgbe/ixgbe_82599.c @@ -1775,7 +1775,7 @@ static s32 ixgbe_start_hw_82599(struct ixgbe_hw *hw) * If PHY already detected, maintains current PHY type in hw struct, * otherwise executes the PHY detection routine. **/ -s32 ixgbe_identify_phy_82599(struct ixgbe_hw *hw) +static s32 ixgbe_identify_phy_82599(struct ixgbe_hw *hw) { s32 status = IXGBE_ERR_PHY_ADDR_INVALID; -- cgit v0.10.2 From 75e3d3c6812ef2387f8dcfd86437cff00f64b68b Mon Sep 17 00:00:00 2001 From: Jeff Kirsher Date: Thu, 17 Mar 2011 18:11:38 +0000 Subject: ixgbe: update version string for Dell CEM use Signed-off-by: Jeff Kirsher Acked-by: Don Skidmore Tested-by: Stephen Ko diff --git a/drivers/net/ixgbe/ixgbe_main.c b/drivers/net/ixgbe/ixgbe_main.c index 6f8adc7..3dbe689 100644 --- a/drivers/net/ixgbe/ixgbe_main.c +++ b/drivers/net/ixgbe/ixgbe_main.c @@ -51,8 +51,12 @@ char ixgbe_driver_name[] = "ixgbe"; static const char ixgbe_driver_string[] = "Intel(R) 10 Gigabit PCI Express Network Driver"; - -#define DRV_VERSION "3.2.9-k2" +#define MAJ 3 +#define MIN 2 +#define BUILD 9 +#define KFIX 2 +#define DRV_VERSION __stringify(MAJ) "." __stringify(MIN) "." \ + __stringify(BUILD) "-k" __stringify(KFIX) const char ixgbe_driver_version[] = DRV_VERSION; static const char ixgbe_copyright[] = "Copyright (c) 1999-2011 Intel Corporation."; -- cgit v0.10.2 From 7184b7cf555f5bc08e34994147c341abb07d1dbb Mon Sep 17 00:00:00 2001 From: Emil Tantilov Date: Fri, 18 Mar 2011 08:18:22 +0000 Subject: ixgbe: refactor common start_hw code for 82599 and x540 Factored out the common start_hw code into a new function ixgbe_start_hw_gen2() so that it can be used by x540 and 82599. Signed-off-by: Emil Tantilov Acked-by: Don Skidmore Tested-by: Evan Swanson Signed-off-by: Jeff Kirsher diff --git a/drivers/net/ixgbe/ixgbe_82599.c b/drivers/net/ixgbe/ixgbe_82599.c index 32ad411..09934a8 100644 --- a/drivers/net/ixgbe/ixgbe_82599.c +++ b/drivers/net/ixgbe/ixgbe_82599.c @@ -1740,30 +1740,28 @@ static s32 ixgbe_write_analog_reg8_82599(struct ixgbe_hw *hw, u32 reg, u8 val) * ixgbe_start_hw_82599 - Prepare hardware for Tx/Rx * @hw: pointer to hardware structure * - * Starts the hardware using the generic start_hw function. - * Then performs device-specific: - * Clears the rate limiter registers. + * Starts the hardware using the generic start_hw function + * and the generation start_hw function. + * Then performs revision-specific operations, if any. **/ static s32 ixgbe_start_hw_82599(struct ixgbe_hw *hw) { - u32 q_num; - s32 ret_val; + s32 ret_val = 0; ret_val = ixgbe_start_hw_generic(hw); + if (ret_val != 0) + goto out; - /* Clear the rate limiters */ - for (q_num = 0; q_num < hw->mac.max_tx_queues; q_num++) { - IXGBE_WRITE_REG(hw, IXGBE_RTTDQSEL, q_num); - IXGBE_WRITE_REG(hw, IXGBE_RTTBCNRC, 0); - } - IXGBE_WRITE_FLUSH(hw); + ret_val = ixgbe_start_hw_gen2(hw); + if (ret_val != 0) + goto out; /* We need to run link autotry after the driver loads */ hw->mac.autotry_restart = true; if (ret_val == 0) ret_val = ixgbe_verify_fw_version_82599(hw); - +out: return ret_val; } diff --git a/drivers/net/ixgbe/ixgbe_common.c b/drivers/net/ixgbe/ixgbe_common.c index bcd9529..c66fd95 100644 --- a/drivers/net/ixgbe/ixgbe_common.c +++ b/drivers/net/ixgbe/ixgbe_common.c @@ -96,6 +96,30 @@ s32 ixgbe_start_hw_generic(struct ixgbe_hw *hw) } /** + * ixgbe_start_hw_gen2 - Init sequence for common device family + * @hw: pointer to hw structure + * + * Performs the init sequence common to the second generation + * of 10 GbE devices. + * Devices in the second generation: + * 82599 + * X540 + **/ +s32 ixgbe_start_hw_gen2(struct ixgbe_hw *hw) +{ + u32 i; + + /* Clear the rate limiters */ + for (i = 0; i < hw->mac.max_tx_queues; i++) { + IXGBE_WRITE_REG(hw, IXGBE_RTTDQSEL, i); + IXGBE_WRITE_REG(hw, IXGBE_RTTBCNRC, 0); + } + IXGBE_WRITE_FLUSH(hw); + + return 0; +} + +/** * ixgbe_init_hw_generic - Generic hardware initialization * @hw: pointer to hardware structure * diff --git a/drivers/net/ixgbe/ixgbe_common.h b/drivers/net/ixgbe/ixgbe_common.h index 508f635..2585bf3 100644 --- a/drivers/net/ixgbe/ixgbe_common.h +++ b/drivers/net/ixgbe/ixgbe_common.h @@ -35,6 +35,7 @@ u32 ixgbe_get_pcie_msix_count_generic(struct ixgbe_hw *hw); s32 ixgbe_init_ops_generic(struct ixgbe_hw *hw); s32 ixgbe_init_hw_generic(struct ixgbe_hw *hw); s32 ixgbe_start_hw_generic(struct ixgbe_hw *hw); +s32 ixgbe_start_hw_gen2(struct ixgbe_hw *hw); s32 ixgbe_clear_hw_cntrs_generic(struct ixgbe_hw *hw); s32 ixgbe_read_pba_string_generic(struct ixgbe_hw *hw, u8 *pba_num, u32 pba_num_size); diff --git a/drivers/net/ixgbe/ixgbe_x540.c b/drivers/net/ixgbe/ixgbe_x540.c index 7ce3f45..295c170 100644 --- a/drivers/net/ixgbe/ixgbe_x540.c +++ b/drivers/net/ixgbe/ixgbe_x540.c @@ -226,6 +226,28 @@ mac_reset_top: } /** + * ixgbe_start_hw_X540 - Prepare hardware for Tx/Rx + * @hw: pointer to hardware structure + * + * Starts the hardware using the generic start_hw function + * and the generation start_hw function. + * Then performs revision-specific operations, if any. + **/ +static s32 ixgbe_start_hw_X540(struct ixgbe_hw *hw) +{ + s32 ret_val = 0; + + ret_val = ixgbe_start_hw_generic(hw); + if (ret_val != 0) + goto out; + + ret_val = ixgbe_start_hw_gen2(hw); + +out: + return ret_val; +} + +/** * ixgbe_get_supported_physical_layer_X540 - Returns physical layer type * @hw: pointer to hardware structure * @@ -660,7 +682,7 @@ static void ixgbe_release_swfw_sync_semaphore(struct ixgbe_hw *hw) static struct ixgbe_mac_operations mac_ops_X540 = { .init_hw = &ixgbe_init_hw_generic, .reset_hw = &ixgbe_reset_hw_X540, - .start_hw = &ixgbe_start_hw_generic, + .start_hw = &ixgbe_start_hw_X540, .clear_hw_cntrs = &ixgbe_clear_hw_cntrs_generic, .get_media_type = &ixgbe_get_media_type_X540, .get_supported_physical_layer = -- cgit v0.10.2 From 3d5c520727ce3dbf418eec38e431856708f946f8 Mon Sep 17 00:00:00 2001 From: Emil Tantilov Date: Sat, 19 Mar 2011 01:32:46 +0000 Subject: ixgbe: move disabling of relaxed ordering in start_hw() Relaxed ordering can lead to issues with some chipsets. This patch makes sure that it is disabled by default and not only when DCA is on. Signed-off-by: Emil Tantilov Tested-by: Evan Swanson Signed-off-by: Jeff Kirsher diff --git a/drivers/net/ixgbe/ixgbe_82598.c b/drivers/net/ixgbe/ixgbe_82598.c index c9b6574..a93275f 100644 --- a/drivers/net/ixgbe/ixgbe_82598.c +++ b/drivers/net/ixgbe/ixgbe_82598.c @@ -197,14 +197,33 @@ out: * @hw: pointer to hardware structure * * Starts the hardware using the generic start_hw function. - * Then set pcie completion timeout + * Disables relaxed ordering Then set pcie completion timeout + * **/ static s32 ixgbe_start_hw_82598(struct ixgbe_hw *hw) { + u32 regval; + u32 i; s32 ret_val = 0; ret_val = ixgbe_start_hw_generic(hw); + /* Disable relaxed ordering */ + for (i = 0; ((i < hw->mac.max_tx_queues) && + (i < IXGBE_DCA_MAX_QUEUES_82598)); i++) { + regval = IXGBE_READ_REG(hw, IXGBE_DCA_TXCTRL(i)); + regval &= ~IXGBE_DCA_TXCTRL_TX_WB_RO_EN; + IXGBE_WRITE_REG(hw, IXGBE_DCA_TXCTRL(i), regval); + } + + for (i = 0; ((i < hw->mac.max_rx_queues) && + (i < IXGBE_DCA_MAX_QUEUES_82598)); i++) { + regval = IXGBE_READ_REG(hw, IXGBE_DCA_RXCTRL(i)); + regval &= ~(IXGBE_DCA_RXCTRL_DESC_WRO_EN | + IXGBE_DCA_RXCTRL_DESC_HSRO_EN); + IXGBE_WRITE_REG(hw, IXGBE_DCA_RXCTRL(i), regval); + } + /* set the completion timeout for interface */ if (ret_val == 0) ixgbe_set_pcie_completion_timeout(hw); diff --git a/drivers/net/ixgbe/ixgbe_common.c b/drivers/net/ixgbe/ixgbe_common.c index c66fd95..1b8b3cd 100644 --- a/drivers/net/ixgbe/ixgbe_common.c +++ b/drivers/net/ixgbe/ixgbe_common.c @@ -108,6 +108,7 @@ s32 ixgbe_start_hw_generic(struct ixgbe_hw *hw) s32 ixgbe_start_hw_gen2(struct ixgbe_hw *hw) { u32 i; + u32 regval; /* Clear the rate limiters */ for (i = 0; i < hw->mac.max_tx_queues; i++) { @@ -116,6 +117,20 @@ s32 ixgbe_start_hw_gen2(struct ixgbe_hw *hw) } IXGBE_WRITE_FLUSH(hw); + /* Disable relaxed ordering */ + for (i = 0; i < hw->mac.max_tx_queues; i++) { + regval = IXGBE_READ_REG(hw, IXGBE_DCA_TXCTRL_82599(i)); + regval &= ~IXGBE_DCA_TXCTRL_TX_WB_RO_EN; + IXGBE_WRITE_REG(hw, IXGBE_DCA_TXCTRL_82599(i), regval); + } + + for (i = 0; i < hw->mac.max_rx_queues; i++) { + regval = IXGBE_READ_REG(hw, IXGBE_DCA_RXCTRL(i)); + regval &= ~(IXGBE_DCA_RXCTRL_DESC_WRO_EN | + IXGBE_DCA_RXCTRL_DESC_HSRO_EN); + IXGBE_WRITE_REG(hw, IXGBE_DCA_RXCTRL(i), regval); + } + return 0; } diff --git a/drivers/net/ixgbe/ixgbe_main.c b/drivers/net/ixgbe/ixgbe_main.c index 3dbe689..3148e21 100644 --- a/drivers/net/ixgbe/ixgbe_main.c +++ b/drivers/net/ixgbe/ixgbe_main.c @@ -947,8 +947,6 @@ static void ixgbe_update_rx_dca(struct ixgbe_adapter *adapter, rxctrl |= IXGBE_DCA_RXCTRL_DESC_DCA_EN; rxctrl |= IXGBE_DCA_RXCTRL_HEAD_DCA_EN; rxctrl &= ~(IXGBE_DCA_RXCTRL_DESC_RRO_EN); - rxctrl &= ~(IXGBE_DCA_RXCTRL_DESC_WRO_EN | - IXGBE_DCA_RXCTRL_DESC_HSRO_EN); IXGBE_WRITE_REG(hw, IXGBE_DCA_RXCTRL(reg_idx), rxctrl); } @@ -966,7 +964,6 @@ static void ixgbe_update_tx_dca(struct ixgbe_adapter *adapter, txctrl &= ~IXGBE_DCA_TXCTRL_CPUID_MASK; txctrl |= dca3_get_tag(&adapter->pdev->dev, cpu); txctrl |= IXGBE_DCA_TXCTRL_DESC_DCA_EN; - txctrl &= ~IXGBE_DCA_TXCTRL_TX_WB_RO_EN; IXGBE_WRITE_REG(hw, IXGBE_DCA_TXCTRL(reg_idx), txctrl); break; case ixgbe_mac_82599EB: @@ -976,7 +973,6 @@ static void ixgbe_update_tx_dca(struct ixgbe_adapter *adapter, txctrl |= (dca3_get_tag(&adapter->pdev->dev, cpu) << IXGBE_DCA_TXCTRL_CPUID_SHIFT_82599); txctrl |= IXGBE_DCA_TXCTRL_DESC_DCA_EN; - txctrl &= ~IXGBE_DCA_TXCTRL_TX_WB_RO_EN; IXGBE_WRITE_REG(hw, IXGBE_DCA_TXCTRL_82599(reg_idx), txctrl); break; default: -- cgit v0.10.2 From 0fa6d83258252695203d24c8818092644df10fd7 Mon Sep 17 00:00:00 2001 From: Emil Tantilov Date: Fri, 18 Mar 2011 08:18:32 +0000 Subject: ixgbe: fix 82599 KR downshift coexistence with LESM FW module Disable KR to KX4/KX downshift on 82599 backplane devices when LESM (Link Establishment State Machine) is enabled in FW. Those features cannot co-exist as they both manipulate the same registers. Signed-off-by: Emil Tantilov Acked-by: Don Skidmore Tested-by: Phillip Schmitt Signed-off-by: Jeff Kirsher diff --git a/drivers/net/ixgbe/ixgbe_82599.c b/drivers/net/ixgbe/ixgbe_82599.c index 09934a8..d195278 100644 --- a/drivers/net/ixgbe/ixgbe_82599.c +++ b/drivers/net/ixgbe/ixgbe_82599.c @@ -61,6 +61,7 @@ static s32 ixgbe_setup_copper_link_82599(struct ixgbe_hw *hw, bool autoneg, bool autoneg_wait_to_complete); static s32 ixgbe_verify_fw_version_82599(struct ixgbe_hw *hw); +static bool ixgbe_verify_lesm_fw_enabled_82599(struct ixgbe_hw *hw); static void ixgbe_init_mac_link_ops_82599(struct ixgbe_hw *hw) { @@ -86,7 +87,8 @@ static void ixgbe_init_mac_link_ops_82599(struct ixgbe_hw *hw) if ((mac->ops.get_media_type(hw) == ixgbe_media_type_backplane) && (hw->phy.smart_speed == ixgbe_smart_speed_auto || - hw->phy.smart_speed == ixgbe_smart_speed_on)) + hw->phy.smart_speed == ixgbe_smart_speed_on) && + !ixgbe_verify_lesm_fw_enabled_82599(hw)) mac->ops.setup_link = &ixgbe_setup_mac_link_smartspeed; else mac->ops.setup_link = &ixgbe_setup_mac_link_82599; @@ -2028,6 +2030,48 @@ fw_version_out: return status; } +/** + * ixgbe_verify_lesm_fw_enabled_82599 - Checks LESM FW module state. + * @hw: pointer to hardware structure + * + * Returns true if the LESM FW module is present and enabled. Otherwise + * returns false. Smart Speed must be disabled if LESM FW module is enabled. + **/ +static bool ixgbe_verify_lesm_fw_enabled_82599(struct ixgbe_hw *hw) +{ + bool lesm_enabled = false; + u16 fw_offset, fw_lesm_param_offset, fw_lesm_state; + s32 status; + + /* get the offset to the Firmware Module block */ + status = hw->eeprom.ops.read(hw, IXGBE_FW_PTR, &fw_offset); + + if ((status != 0) || + (fw_offset == 0) || (fw_offset == 0xFFFF)) + goto out; + + /* get the offset to the LESM Parameters block */ + status = hw->eeprom.ops.read(hw, (fw_offset + + IXGBE_FW_LESM_PARAMETERS_PTR), + &fw_lesm_param_offset); + + if ((status != 0) || + (fw_lesm_param_offset == 0) || (fw_lesm_param_offset == 0xFFFF)) + goto out; + + /* get the lesm state word */ + status = hw->eeprom.ops.read(hw, (fw_lesm_param_offset + + IXGBE_FW_LESM_STATE_1), + &fw_lesm_state); + + if ((status == 0) && + (fw_lesm_state & IXGBE_FW_LESM_STATE_ENABLED)) + lesm_enabled = true; + +out: + return lesm_enabled; +} + static struct ixgbe_mac_operations mac_ops_82599 = { .init_hw = &ixgbe_init_hw_generic, .reset_hw = &ixgbe_reset_hw_82599, diff --git a/drivers/net/ixgbe/ixgbe_type.h b/drivers/net/ixgbe/ixgbe_type.h index cd1c2b6..e00356a 100644 --- a/drivers/net/ixgbe/ixgbe_type.h +++ b/drivers/net/ixgbe/ixgbe_type.h @@ -1625,6 +1625,9 @@ #define IXGBE_SAN_MAC_ADDR_PORT1_OFFSET 0x3 #define IXGBE_DEVICE_CAPS_ALLOW_ANY_SFP 0x1 #define IXGBE_DEVICE_CAPS_FCOE_OFFLOADS 0x2 +#define IXGBE_FW_LESM_PARAMETERS_PTR 0x2 +#define IXGBE_FW_LESM_STATE_1 0x1 +#define IXGBE_FW_LESM_STATE_ENABLED 0x8000 /* LESM Enable bit */ #define IXGBE_FW_PASSTHROUGH_PATCH_CONFIG_PTR 0x4 #define IXGBE_FW_PATCH_VERSION_4 0x7 -- cgit v0.10.2 From 032b4325b61b03f87f0346d0e92e39f785e24105 Mon Sep 17 00:00:00 2001 From: Don Skidmore Date: Fri, 18 Mar 2011 09:32:53 +0000 Subject: ixgbe: cleanup short msleep's (<20ms) to use usleep_range Since msleep might not sleep for the desired amount when less than 20ms use usleep_range. Signed-off-by: Don Skidmore Tested-by: Stephen Ko Signed-off-by: Jeff Kirsher diff --git a/drivers/net/ixgbe/ixgbe_82598.c b/drivers/net/ixgbe/ixgbe_82598.c index a93275f..af4054a 100644 --- a/drivers/net/ixgbe/ixgbe_82598.c +++ b/drivers/net/ixgbe/ixgbe_82598.c @@ -1083,7 +1083,7 @@ static s32 ixgbe_read_i2c_eeprom_82598(struct ixgbe_hw *hw, u8 byte_offset, sfp_stat = sfp_stat & IXGBE_I2C_EEPROM_STATUS_MASK; if (sfp_stat != IXGBE_I2C_EEPROM_STATUS_IN_PROGRESS) break; - msleep(10); + usleep_range(10000, 20000); } if (sfp_stat != IXGBE_I2C_EEPROM_STATUS_PASS) { diff --git a/drivers/net/ixgbe/ixgbe_82599.c b/drivers/net/ixgbe/ixgbe_82599.c index d195278..e39380c 100644 --- a/drivers/net/ixgbe/ixgbe_82599.c +++ b/drivers/net/ixgbe/ixgbe_82599.c @@ -130,8 +130,12 @@ static s32 ixgbe_setup_sfp_modules_82599(struct ixgbe_hw *hw) /* Release the semaphore */ ixgbe_release_swfw_sync(hw, IXGBE_GSSR_MAC_CSR_SM); - /* Delay obtaining semaphore again to allow FW access */ - msleep(hw->eeprom.semaphore_delay); + /* + * Delay obtaining semaphore again to allow FW access, + * semaphore_delay is in ms usleep_range needs us. + */ + usleep_range(hw->eeprom.semaphore_delay * 1000, + hw->eeprom.semaphore_delay * 2000); /* Now restart DSP by setting Restart_AN and clearing LMS */ IXGBE_WRITE_REG(hw, IXGBE_AUTOC, ((IXGBE_READ_REG(hw, @@ -140,7 +144,7 @@ static s32 ixgbe_setup_sfp_modules_82599(struct ixgbe_hw *hw) /* Wait for AN to leave state 0 */ for (i = 0; i < 10; i++) { - msleep(4); + usleep_range(4000, 8000); reg_anlp1 = IXGBE_READ_REG(hw, IXGBE_ANLP1); if (reg_anlp1 & IXGBE_ANLP1_AN_STATE_MASK) break; @@ -1178,7 +1182,7 @@ s32 ixgbe_init_fdir_signature_82599(struct ixgbe_hw *hw, u32 pballoc) if (IXGBE_READ_REG(hw, IXGBE_FDIRCTRL) & IXGBE_FDIRCTRL_INIT_DONE) break; - msleep(1); + usleep_range(1000, 2000); } if (i >= IXGBE_FDIR_INIT_DONE_POLL) hw_dbg(hw, "Flow Director Signature poll time exceeded!\n"); @@ -1273,7 +1277,7 @@ s32 ixgbe_init_fdir_perfect_82599(struct ixgbe_hw *hw, u32 pballoc) if (IXGBE_READ_REG(hw, IXGBE_FDIRCTRL) & IXGBE_FDIRCTRL_INIT_DONE) break; - msleep(1); + usleep_range(1000, 2000); } if (i >= IXGBE_FDIR_INIT_DONE_POLL) hw_dbg(hw, "Flow Director Perfect poll time exceeded!\n"); diff --git a/drivers/net/ixgbe/ixgbe_common.c b/drivers/net/ixgbe/ixgbe_common.c index 1b8b3cd..a67cba5 100644 --- a/drivers/net/ixgbe/ixgbe_common.c +++ b/drivers/net/ixgbe/ixgbe_common.c @@ -503,7 +503,7 @@ s32 ixgbe_stop_adapter_generic(struct ixgbe_hw *hw) reg_val &= ~(IXGBE_RXCTRL_RXEN); IXGBE_WRITE_REG(hw, IXGBE_RXCTRL, reg_val); IXGBE_WRITE_FLUSH(hw); - msleep(2); + usleep_range(2000, 4000); /* Clear interrupt mask to stop from interrupts being generated */ IXGBE_WRITE_REG(hw, IXGBE_EIMC, IXGBE_IRQ_CLEAR_MASK); @@ -1151,8 +1151,12 @@ static void ixgbe_release_eeprom(struct ixgbe_hw *hw) hw->mac.ops.release_swfw_sync(hw, IXGBE_GSSR_EEP_SM); - /* Delay before attempt to obtain semaphore again to allow FW access */ - msleep(hw->eeprom.semaphore_delay); + /* + * Delay before attempt to obtain semaphore again to allow FW + * access. semaphore_delay is in ms we need us for usleep_range + */ + usleep_range(hw->eeprom.semaphore_delay * 1000, + hw->eeprom.semaphore_delay * 2000); } /** @@ -2228,7 +2232,7 @@ s32 ixgbe_acquire_swfw_sync(struct ixgbe_hw *hw, u16 mask) * thread currently using resource (swmask) */ ixgbe_release_eeprom_semaphore(hw); - msleep(5); + usleep_range(5000, 10000); timeout--; } @@ -2302,7 +2306,7 @@ s32 ixgbe_blink_led_start_generic(struct ixgbe_hw *hw, u32 index) autoc_reg |= IXGBE_AUTOC_AN_RESTART; autoc_reg |= IXGBE_AUTOC_FLU; IXGBE_WRITE_REG(hw, IXGBE_AUTOC, autoc_reg); - msleep(10); + usleep_range(10000, 20000); } led_reg &= ~IXGBE_LED_MODE_MASK(index); diff --git a/drivers/net/ixgbe/ixgbe_dcb_nl.c b/drivers/net/ixgbe/ixgbe_dcb_nl.c index 7b59f64..5e7ed22 100644 --- a/drivers/net/ixgbe/ixgbe_dcb_nl.c +++ b/drivers/net/ixgbe/ixgbe_dcb_nl.c @@ -376,7 +376,7 @@ static u8 ixgbe_dcbnl_set_all(struct net_device *netdev) */ if (adapter->dcb_set_bitmap & BIT_APP_UPCHG) { while (test_and_set_bit(__IXGBE_RESETTING, &adapter->state)) - msleep(1); + usleep_range(1000, 2000); ixgbe_fcoe_setapp(adapter, up); diff --git a/drivers/net/ixgbe/ixgbe_ethtool.c b/drivers/net/ixgbe/ixgbe_ethtool.c index 76380a2..5005a36 100644 --- a/drivers/net/ixgbe/ixgbe_ethtool.c +++ b/drivers/net/ixgbe/ixgbe_ethtool.c @@ -931,7 +931,7 @@ static int ixgbe_set_ringparam(struct net_device *netdev, } while (test_and_set_bit(__IXGBE_RESETTING, &adapter->state)) - msleep(1); + usleep_range(1000, 2000); if (!netif_running(adapter->netdev)) { for (i = 0; i < adapter->num_tx_queues; i++) @@ -1417,7 +1417,7 @@ static int ixgbe_intr_test(struct ixgbe_adapter *adapter, u64 *data) /* Disable all the interrupts */ IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMC, 0xFFFFFFFF); - msleep(10); + usleep_range(10000, 20000); /* Test each interrupt */ for (; i < 10; i++) { @@ -1437,7 +1437,7 @@ static int ixgbe_intr_test(struct ixgbe_adapter *adapter, u64 *data) ~mask & 0x00007FFF); IXGBE_WRITE_REG(&adapter->hw, IXGBE_EICS, ~mask & 0x00007FFF); - msleep(10); + usleep_range(10000, 20000); if (adapter->test_icr & mask) { *data = 3; @@ -1454,7 +1454,7 @@ static int ixgbe_intr_test(struct ixgbe_adapter *adapter, u64 *data) adapter->test_icr = 0; IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMS, mask); IXGBE_WRITE_REG(&adapter->hw, IXGBE_EICS, mask); - msleep(10); + usleep_range(10000, 20000); if (!(adapter->test_icr &mask)) { *data = 4; @@ -1474,7 +1474,7 @@ static int ixgbe_intr_test(struct ixgbe_adapter *adapter, u64 *data) ~mask & 0x00007FFF); IXGBE_WRITE_REG(&adapter->hw, IXGBE_EICS, ~mask & 0x00007FFF); - msleep(10); + usleep_range(10000, 20000); if (adapter->test_icr) { *data = 5; @@ -1485,7 +1485,7 @@ static int ixgbe_intr_test(struct ixgbe_adapter *adapter, u64 *data) /* Disable all the interrupts */ IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMC, 0xFFFFFFFF); - msleep(10); + usleep_range(10000, 20000); /* Unhook test interrupt handler */ free_irq(irq, netdev); @@ -1613,7 +1613,7 @@ static int ixgbe_setup_loopback_test(struct ixgbe_adapter *adapter) reg_data |= IXGBE_AUTOC_LMS_10G_LINK_NO_AN | IXGBE_AUTOC_FLU; IXGBE_WRITE_REG(&adapter->hw, IXGBE_AUTOC, reg_data); IXGBE_WRITE_FLUSH(&adapter->hw); - msleep(10); + usleep_range(10000, 20000); /* Disable Atlas Tx lanes; re-enabled in reset path */ if (hw->mac.type == ixgbe_mac_82598EB) { diff --git a/drivers/net/ixgbe/ixgbe_main.c b/drivers/net/ixgbe/ixgbe_main.c index 3148e21..5cd2cd3 100644 --- a/drivers/net/ixgbe/ixgbe_main.c +++ b/drivers/net/ixgbe/ixgbe_main.c @@ -2731,7 +2731,7 @@ void ixgbe_configure_tx_ring(struct ixgbe_adapter *adapter, /* poll to verify queue is enabled */ do { - msleep(1); + usleep_range(1000, 2000); txdctl = IXGBE_READ_REG(hw, IXGBE_TXDCTL(reg_idx)); } while (--wait_loop && !(txdctl & IXGBE_TXDCTL_ENABLE)); if (!wait_loop) @@ -3023,7 +3023,7 @@ static void ixgbe_rx_desc_queue_enable(struct ixgbe_adapter *adapter, return; do { - msleep(1); + usleep_range(1000, 2000); rxdctl = IXGBE_READ_REG(hw, IXGBE_RXDCTL(reg_idx)); } while (--wait_loop && !(rxdctl & IXGBE_RXDCTL_ENABLE)); @@ -3945,7 +3945,7 @@ void ixgbe_reinit_locked(struct ixgbe_adapter *adapter) { WARN_ON(in_interrupt()); while (test_and_set_bit(__IXGBE_RESETTING, &adapter->state)) - msleep(1); + usleep_range(1000, 2000); ixgbe_down(adapter); /* * If SR-IOV enabled then wait a bit before bringing the adapter @@ -4150,7 +4150,7 @@ void ixgbe_down(struct ixgbe_adapter *adapter) /* this call also flushes the previous write */ ixgbe_disable_rx_queue(adapter, adapter->rx_ring[i]); - msleep(10); + usleep_range(10000, 20000); netif_tx_stop_all_queues(netdev); diff --git a/drivers/net/ixgbe/ixgbe_phy.c b/drivers/net/ixgbe/ixgbe_phy.c index df5b8aa..31cc29e 100644 --- a/drivers/net/ixgbe/ixgbe_phy.c +++ b/drivers/net/ixgbe/ixgbe_phy.c @@ -753,7 +753,7 @@ s32 ixgbe_reset_phy_nl(struct ixgbe_hw *hw) &phy_data); if ((phy_data & MDIO_CTRL1_RESET) == 0) break; - msleep(10); + usleep_range(10000, 20000); } if ((phy_data & MDIO_CTRL1_RESET) != 0) { @@ -782,7 +782,7 @@ s32 ixgbe_reset_phy_nl(struct ixgbe_hw *hw) case IXGBE_DELAY_NL: data_offset++; hw_dbg(hw, "DELAY: %d MS\n", edata); - msleep(edata); + usleep_range(edata * 1000, edata * 2000); break; case IXGBE_DATA_NL: hw_dbg(hw, "DATA:\n"); diff --git a/drivers/net/ixgbe/ixgbe_x540.c b/drivers/net/ixgbe/ixgbe_x540.c index 295c170..8aa1dc1 100644 --- a/drivers/net/ixgbe/ixgbe_x540.c +++ b/drivers/net/ixgbe/ixgbe_x540.c @@ -563,7 +563,7 @@ static s32 ixgbe_acquire_swfw_sync_X540(struct ixgbe_hw *hw, u16 mask) * resource (swmask) */ ixgbe_release_swfw_sync_semaphore(hw); - msleep(5); + usleep_range(5000, 10000); } } @@ -585,7 +585,7 @@ static s32 ixgbe_acquire_swfw_sync_X540(struct ixgbe_hw *hw, u16 mask) } } - msleep(5); + usleep_range(5000, 10000); return 0; } @@ -609,7 +609,7 @@ static void ixgbe_release_swfw_sync_X540(struct ixgbe_hw *hw, u16 mask) IXGBE_WRITE_REG(hw, IXGBE_SWFW_SYNC, swfw_sync); ixgbe_release_swfw_sync_semaphore(hw); - msleep(5); + usleep_range(5000, 10000); } /** -- cgit v0.10.2 From eb9c3e3ea2981e56c71e8f5477c51783856090b1 Mon Sep 17 00:00:00 2001 From: Emil Tantilov Date: Thu, 24 Mar 2011 00:57:50 +0000 Subject: ixgbe: fix semaphores in eeprom routines for x540 HW can upload EEPROM content from flash while in a middle of checksum calculation. Take NVM ownership for the whole process of checksum update. Call ixgbe_read_eerd_generic() and ixgbe_write_eewr_generic() directly to avoid double take of semaphores which leads to long loading times. Signed-off-by: Emil Tantilov Tested-by: Stephen Ko Signed-off-by: Jeff Kirsher diff --git a/drivers/net/ixgbe/ixgbe_common.c b/drivers/net/ixgbe/ixgbe_common.c index a67cba5..fc31e02 100644 --- a/drivers/net/ixgbe/ixgbe_common.c +++ b/drivers/net/ixgbe/ixgbe_common.c @@ -54,6 +54,7 @@ static s32 ixgbe_device_supports_autoneg_fc(struct ixgbe_hw *hw); static s32 ixgbe_negotiate_fc(struct ixgbe_hw *hw, u32 adv_reg, u32 lp_reg, u32 adv_sym, u32 adv_asm, u32 lp_sym, u32 lp_asm); static s32 ixgbe_setup_fc(struct ixgbe_hw *hw, s32 packetbuf_num); +static s32 ixgbe_poll_eerd_eewr_done(struct ixgbe_hw *hw, u32 ee_reg); /** * ixgbe_start_hw_generic - Prepare hardware for Tx/Rx @@ -778,6 +779,47 @@ out: } /** + * ixgbe_write_eewr_generic - Write EEPROM word using EEWR + * @hw: pointer to hardware structure + * @offset: offset of word in the EEPROM to write + * @data: word write to the EEPROM + * + * Write a 16 bit word to the EEPROM using the EEWR register. + **/ +s32 ixgbe_write_eewr_generic(struct ixgbe_hw *hw, u16 offset, u16 data) +{ + u32 eewr; + s32 status; + + hw->eeprom.ops.init_params(hw); + + if (offset >= hw->eeprom.word_size) { + status = IXGBE_ERR_EEPROM; + goto out; + } + + eewr = (offset << IXGBE_EEPROM_RW_ADDR_SHIFT) | + (data << IXGBE_EEPROM_RW_REG_DATA) | IXGBE_EEPROM_RW_REG_START; + + status = ixgbe_poll_eerd_eewr_done(hw, IXGBE_NVM_POLL_WRITE); + if (status != 0) { + hw_dbg(hw, "Eeprom write EEWR timed out\n"); + goto out; + } + + IXGBE_WRITE_REG(hw, IXGBE_EEWR, eewr); + + status = ixgbe_poll_eerd_eewr_done(hw, IXGBE_NVM_POLL_WRITE); + if (status != 0) { + hw_dbg(hw, "Eeprom write EEWR timed out\n"); + goto out; + } + +out: + return status; +} + +/** * ixgbe_poll_eerd_eewr_done - Poll EERD read or EEWR write status * @hw: pointer to hardware structure * @ee_reg: EEPROM flag for polling @@ -785,7 +827,7 @@ out: * Polls the status bit (bit 1) of the EERD or EEWR to determine when the * read or write is done respectively. **/ -s32 ixgbe_poll_eerd_eewr_done(struct ixgbe_hw *hw, u32 ee_reg) +static s32 ixgbe_poll_eerd_eewr_done(struct ixgbe_hw *hw, u32 ee_reg) { u32 i; u32 reg; diff --git a/drivers/net/ixgbe/ixgbe_common.h b/drivers/net/ixgbe/ixgbe_common.h index 2585bf3..e18dc13 100644 --- a/drivers/net/ixgbe/ixgbe_common.h +++ b/drivers/net/ixgbe/ixgbe_common.h @@ -50,13 +50,13 @@ s32 ixgbe_led_off_generic(struct ixgbe_hw *hw, u32 index); s32 ixgbe_init_eeprom_params_generic(struct ixgbe_hw *hw); s32 ixgbe_write_eeprom_generic(struct ixgbe_hw *hw, u16 offset, u16 data); s32 ixgbe_read_eerd_generic(struct ixgbe_hw *hw, u16 offset, u16 *data); +s32 ixgbe_write_eewr_generic(struct ixgbe_hw *hw, u16 offset, u16 data); s32 ixgbe_read_eeprom_bit_bang_generic(struct ixgbe_hw *hw, u16 offset, u16 *data); u16 ixgbe_calc_eeprom_checksum_generic(struct ixgbe_hw *hw); s32 ixgbe_validate_eeprom_checksum_generic(struct ixgbe_hw *hw, u16 *checksum_val); s32 ixgbe_update_eeprom_checksum_generic(struct ixgbe_hw *hw); -s32 ixgbe_poll_eerd_eewr_done(struct ixgbe_hw *hw, u32 ee_reg); s32 ixgbe_set_rar_generic(struct ixgbe_hw *hw, u32 index, u8 *addr, u32 vmdq, u32 enable_addr); diff --git a/drivers/net/ixgbe/ixgbe_x540.c b/drivers/net/ixgbe/ixgbe_x540.c index 8aa1dc1..5433f15 100644 --- a/drivers/net/ixgbe/ixgbe_x540.c +++ b/drivers/net/ixgbe/ixgbe_x540.c @@ -322,55 +322,33 @@ static s32 ixgbe_read_eerd_X540(struct ixgbe_hw *hw, u16 offset, u16 *data) } /** - * ixgbe_write_eewr_X540 - Write EEPROM word using EEWR - * @hw: pointer to hardware structure - * @offset: offset of word in the EEPROM to write - * @data: word write to the EEPROM + * ixgbe_write_eewr_X540 - Write EEPROM word using EEWR + * @hw: pointer to hardware structure + * @offset: offset of word in the EEPROM to write + * @data: word write to the EEPROM * - * Write a 16 bit word to the EEPROM using the EEWR register. + * Write a 16 bit word to the EEPROM using the EEWR register. **/ static s32 ixgbe_write_eewr_X540(struct ixgbe_hw *hw, u16 offset, u16 data) { - u32 eewr; - s32 status; - - hw->eeprom.ops.init_params(hw); - - if (offset >= hw->eeprom.word_size) { - status = IXGBE_ERR_EEPROM; - goto out; - } - - eewr = (offset << IXGBE_EEPROM_RW_ADDR_SHIFT) | - (data << IXGBE_EEPROM_RW_REG_DATA) | - IXGBE_EEPROM_RW_REG_START; - - if (hw->mac.ops.acquire_swfw_sync(hw, IXGBE_GSSR_EEP_SM) == 0) { - status = ixgbe_poll_eerd_eewr_done(hw, IXGBE_NVM_POLL_WRITE); - if (status != 0) { - hw_dbg(hw, "Eeprom write EEWR timed out\n"); - goto out; - } - - IXGBE_WRITE_REG(hw, IXGBE_EEWR, eewr); + s32 status = 0; - status = ixgbe_poll_eerd_eewr_done(hw, IXGBE_NVM_POLL_WRITE); - if (status != 0) { - hw_dbg(hw, "Eeprom write EEWR timed out\n"); - goto out; - } - } else { + if (hw->mac.ops.acquire_swfw_sync(hw, IXGBE_GSSR_EEP_SM) == 0) + status = ixgbe_write_eewr_generic(hw, offset, data); + else status = IXGBE_ERR_SWFW_SYNC; - } -out: - ixgbe_release_swfw_sync_X540(hw, IXGBE_GSSR_EEP_SM); + hw->mac.ops.release_swfw_sync(hw, IXGBE_GSSR_EEP_SM); return status; } /** - * ixgbe_calc_eeprom_checksum_X540 - Calculates and returns the checksum - * @hw: pointer to hardware structure + * ixgbe_calc_eeprom_checksum_X540 - Calculates and returns the checksum + * + * This function does not use synchronization for EERD and EEWR. It can + * be used internally by function which utilize ixgbe_acquire_swfw_sync_X540. + * + * @hw: pointer to hardware structure **/ static u16 ixgbe_calc_eeprom_checksum_X540(struct ixgbe_hw *hw) { @@ -381,9 +359,15 @@ static u16 ixgbe_calc_eeprom_checksum_X540(struct ixgbe_hw *hw) u16 pointer = 0; u16 word = 0; + /* + * Do not use hw->eeprom.ops.read because we do not want to take + * the synchronization semaphores here. Instead use + * ixgbe_read_eerd_generic + */ + /* Include 0x0-0x3F in the checksum */ for (i = 0; i < IXGBE_EEPROM_CHECKSUM; i++) { - if (hw->eeprom.ops.read(hw, i, &word) != 0) { + if (ixgbe_read_eerd_generic(hw, i, &word) != 0) { hw_dbg(hw, "EEPROM read failed\n"); break; } @@ -398,7 +382,7 @@ static u16 ixgbe_calc_eeprom_checksum_X540(struct ixgbe_hw *hw) if (i == IXGBE_PHY_PTR || i == IXGBE_OPTION_ROM_PTR) continue; - if (hw->eeprom.ops.read(hw, i, &pointer) != 0) { + if (ixgbe_read_eerd_generic(hw, i, &pointer) != 0) { hw_dbg(hw, "EEPROM read failed\n"); break; } @@ -408,7 +392,7 @@ static u16 ixgbe_calc_eeprom_checksum_X540(struct ixgbe_hw *hw) pointer >= hw->eeprom.word_size) continue; - if (hw->eeprom.ops.read(hw, pointer, &length) != 0) { + if (ixgbe_read_eerd_generic(hw, pointer, &length) != 0) { hw_dbg(hw, "EEPROM read failed\n"); break; } @@ -419,7 +403,7 @@ static u16 ixgbe_calc_eeprom_checksum_X540(struct ixgbe_hw *hw) continue; for (j = pointer+1; j <= pointer+length; j++) { - if (hw->eeprom.ops.read(hw, j, &word) != 0) { + if (ixgbe_read_eerd_generic(hw, j, &word) != 0) { hw_dbg(hw, "EEPROM read failed\n"); break; } @@ -433,6 +417,62 @@ static u16 ixgbe_calc_eeprom_checksum_X540(struct ixgbe_hw *hw) } /** + * ixgbe_validate_eeprom_checksum_X540 - Validate EEPROM checksum + * @hw: pointer to hardware structure + * @checksum_val: calculated checksum + * + * Performs checksum calculation and validates the EEPROM checksum. If the + * caller does not need checksum_val, the value can be NULL. + **/ +static s32 ixgbe_validate_eeprom_checksum_X540(struct ixgbe_hw *hw, + u16 *checksum_val) +{ + s32 status; + u16 checksum; + u16 read_checksum = 0; + + /* + * Read the first word from the EEPROM. If this times out or fails, do + * not continue or we could be in for a very long wait while every + * EEPROM read fails + */ + status = hw->eeprom.ops.read(hw, 0, &checksum); + + if (status != 0) { + hw_dbg(hw, "EEPROM read failed\n"); + goto out; + } + + if (hw->mac.ops.acquire_swfw_sync(hw, IXGBE_GSSR_EEP_SM) == 0) { + checksum = hw->eeprom.ops.calc_checksum(hw); + + /* + * Do not use hw->eeprom.ops.read because we do not want to take + * the synchronization semaphores twice here. + */ + ixgbe_read_eerd_generic(hw, IXGBE_EEPROM_CHECKSUM, + &read_checksum); + + /* + * Verify read checksum from EEPROM is the same as + * calculated checksum + */ + if (read_checksum != checksum) + status = IXGBE_ERR_EEPROM_CHECKSUM; + + /* If the user cares, return the calculated checksum */ + if (checksum_val) + *checksum_val = checksum; + } else { + status = IXGBE_ERR_SWFW_SYNC; + } + + hw->mac.ops.release_swfw_sync(hw, IXGBE_GSSR_EEP_SM); +out: + return status; +} + +/** * ixgbe_update_eeprom_checksum_X540 - Updates the EEPROM checksum and flash * @hw: pointer to hardware structure * @@ -443,11 +483,35 @@ static u16 ixgbe_calc_eeprom_checksum_X540(struct ixgbe_hw *hw) static s32 ixgbe_update_eeprom_checksum_X540(struct ixgbe_hw *hw) { s32 status; + u16 checksum; - status = ixgbe_update_eeprom_checksum_generic(hw); + /* + * Read the first word from the EEPROM. If this times out or fails, do + * not continue or we could be in for a very long wait while every + * EEPROM read fails + */ + status = hw->eeprom.ops.read(hw, 0, &checksum); + + if (status != 0) + hw_dbg(hw, "EEPROM read failed\n"); + + if (hw->mac.ops.acquire_swfw_sync(hw, IXGBE_GSSR_EEP_SM) == 0) { + checksum = hw->eeprom.ops.calc_checksum(hw); - if (status) + /* + * Do not use hw->eeprom.ops.write because we do not want to + * take the synchronization semaphores twice here. + */ + status = ixgbe_write_eewr_generic(hw, IXGBE_EEPROM_CHECKSUM, + checksum); + + if (status == 0) status = ixgbe_update_flash_X540(hw); + else + status = IXGBE_ERR_SWFW_SYNC; + } + + hw->mac.ops.release_swfw_sync(hw, IXGBE_GSSR_EEP_SM); return status; } @@ -728,7 +792,7 @@ static struct ixgbe_eeprom_operations eeprom_ops_X540 = { .read = &ixgbe_read_eerd_X540, .write = &ixgbe_write_eewr_X540, .calc_checksum = &ixgbe_calc_eeprom_checksum_X540, - .validate_checksum = &ixgbe_validate_eeprom_checksum_generic, + .validate_checksum = &ixgbe_validate_eeprom_checksum_X540, .update_checksum = &ixgbe_update_eeprom_checksum_X540, }; -- cgit v0.10.2 From 4c40ef0291acebf32435e5a4921178ee53bd8933 Mon Sep 17 00:00:00 2001 From: Emil Tantilov Date: Thu, 24 Mar 2011 07:06:02 +0000 Subject: ixgbe: add support for new HW Add new device ID supported by ixgbe. Signed-off-by: Emil Tantilov Tested-by: Stephen Ko Signed-off-by: Jeff Kirsher diff --git a/drivers/net/ixgbe/ixgbe_82599.c b/drivers/net/ixgbe/ixgbe_82599.c index e39380c..63b4da6 100644 --- a/drivers/net/ixgbe/ixgbe_82599.c +++ b/drivers/net/ixgbe/ixgbe_82599.c @@ -359,6 +359,7 @@ static enum ixgbe_media_type ixgbe_get_media_type_82599(struct ixgbe_hw *hw) case IXGBE_DEV_ID_82599_SFP: case IXGBE_DEV_ID_82599_SFP_FCOE: case IXGBE_DEV_ID_82599_SFP_EM: + case IXGBE_DEV_ID_82599_SFP_SF2: media_type = ixgbe_media_type_fiber; break; case IXGBE_DEV_ID_82599_CX4: diff --git a/drivers/net/ixgbe/ixgbe_main.c b/drivers/net/ixgbe/ixgbe_main.c index 5cd2cd3..200ae7e 100644 --- a/drivers/net/ixgbe/ixgbe_main.c +++ b/drivers/net/ixgbe/ixgbe_main.c @@ -124,6 +124,8 @@ static DEFINE_PCI_DEVICE_TABLE(ixgbe_pci_tbl) = { board_82599 }, {PCI_VDEVICE(INTEL, IXGBE_DEV_ID_X540T), board_X540 }, + {PCI_VDEVICE(INTEL, IXGBE_DEV_ID_82599_SFP_SF2), + board_82599 }, /* required last entry */ {0, } diff --git a/drivers/net/ixgbe/ixgbe_type.h b/drivers/net/ixgbe/ixgbe_type.h index e00356a..15580d6 100644 --- a/drivers/net/ixgbe/ixgbe_type.h +++ b/drivers/net/ixgbe/ixgbe_type.h @@ -58,6 +58,7 @@ #define IXGBE_DEV_ID_82599_SFP_FCOE 0x1529 #define IXGBE_SUBDEV_ID_82599_SFP 0x11A9 #define IXGBE_DEV_ID_82599_SFP_EM 0x1507 +#define IXGBE_DEV_ID_82599_SFP_SF2 0x154D #define IXGBE_DEV_ID_82599_XAUI_LOM 0x10FC #define IXGBE_DEV_ID_82599_COMBO_BACKPLANE 0x10F8 #define IXGBE_SUBDEV_ID_82599_KX4_KR_MEZZ 0x000C -- cgit v0.10.2 From a59e8a1a72806057084adc2d321fc2a7cbce9579 Mon Sep 17 00:00:00 2001 From: Emil Tantilov Date: Thu, 31 Mar 2011 09:36:12 +0000 Subject: ixgbe: explicitly disable 100H for x540 100H is not supported on this HW, but the bit is set on the PHY. This can result in link at 100F when advertising only 1000F. Signed-off-by: Emil Tantilov Tested-by: Evan Swanson Signed-off-by: Jeff Kirsher diff --git a/drivers/net/ixgbe/ixgbe_phy.c b/drivers/net/ixgbe/ixgbe_phy.c index 31cc29e..fd381ea 100644 --- a/drivers/net/ixgbe/ixgbe_phy.c +++ b/drivers/net/ixgbe/ixgbe_phy.c @@ -449,7 +449,8 @@ s32 ixgbe_setup_phy_link_generic(struct ixgbe_hw *hw) MDIO_MMD_AN, &autoneg_reg); - autoneg_reg &= ~ADVERTISE_100FULL; + autoneg_reg &= ~(ADVERTISE_100FULL | + ADVERTISE_100HALF); if (hw->phy.autoneg_advertised & IXGBE_LINK_SPEED_100_FULL) autoneg_reg |= ADVERTISE_100FULL; -- cgit v0.10.2 From b776d1043510c60f59220eb5e58b524f5a7f0e52 Mon Sep 17 00:00:00 2001 From: Emil Tantilov Date: Thu, 31 Mar 2011 09:36:18 +0000 Subject: ixgbe: make device_caps() generic x540 has the same device capability word in the EEPROM as 82599. This patch renames ixgbe_get_device_caps_82599 to ixgbe_get_device_caps_generic, moves it to ixgbe_common.h and sets up the function pointer for x540. Signed-off-by: Emil Tantilov Tested-by: Evan Swanson Signed-off-by: Jeff Kirsher diff --git a/drivers/net/ixgbe/ixgbe_82599.c b/drivers/net/ixgbe/ixgbe_82599.c index 63b4da6..e432305 100644 --- a/drivers/net/ixgbe/ixgbe_82599.c +++ b/drivers/net/ixgbe/ixgbe_82599.c @@ -1973,21 +1973,6 @@ static s32 ixgbe_enable_rx_dma_82599(struct ixgbe_hw *hw, u32 regval) } /** - * ixgbe_get_device_caps_82599 - Get additional device capabilities - * @hw: pointer to hardware structure - * @device_caps: the EEPROM word with the extra device capabilities - * - * This function will read the EEPROM location for the device capabilities, - * and return the word through device_caps. - **/ -static s32 ixgbe_get_device_caps_82599(struct ixgbe_hw *hw, u16 *device_caps) -{ - hw->eeprom.ops.read(hw, IXGBE_DEVICE_CAPS, device_caps); - - return 0; -} - -/** * ixgbe_verify_fw_version_82599 - verify fw version for 82599 * @hw: pointer to hardware structure * @@ -2087,7 +2072,7 @@ static struct ixgbe_mac_operations mac_ops_82599 = { .enable_rx_dma = &ixgbe_enable_rx_dma_82599, .get_mac_addr = &ixgbe_get_mac_addr_generic, .get_san_mac_addr = &ixgbe_get_san_mac_addr_generic, - .get_device_caps = &ixgbe_get_device_caps_82599, + .get_device_caps = &ixgbe_get_device_caps_generic, .get_wwn_prefix = &ixgbe_get_wwn_prefix_generic, .stop_adapter = &ixgbe_stop_adapter_generic, .get_bus_info = &ixgbe_get_bus_info_generic, diff --git a/drivers/net/ixgbe/ixgbe_common.c b/drivers/net/ixgbe/ixgbe_common.c index fc31e02..cb2e8e1 100644 --- a/drivers/net/ixgbe/ixgbe_common.c +++ b/drivers/net/ixgbe/ixgbe_common.c @@ -2968,3 +2968,18 @@ void ixgbe_set_vlan_anti_spoofing(struct ixgbe_hw *hw, bool enable, int vf) pfvfspoof &= ~(1 << vf_target_shift); IXGBE_WRITE_REG(hw, IXGBE_PFVFSPOOF(vf_target_reg), pfvfspoof); } + +/** + * ixgbe_get_device_caps_generic - Get additional device capabilities + * @hw: pointer to hardware structure + * @device_caps: the EEPROM word with the extra device capabilities + * + * This function will read the EEPROM location for the device capabilities, + * and return the word through device_caps. + **/ +s32 ixgbe_get_device_caps_generic(struct ixgbe_hw *hw, u16 *device_caps) +{ + hw->eeprom.ops.read(hw, IXGBE_DEVICE_CAPS, device_caps); + + return 0; +} diff --git a/drivers/net/ixgbe/ixgbe_common.h b/drivers/net/ixgbe/ixgbe_common.h index e18dc13..e850adb 100644 --- a/drivers/net/ixgbe/ixgbe_common.h +++ b/drivers/net/ixgbe/ixgbe_common.h @@ -90,6 +90,7 @@ s32 ixgbe_blink_led_start_generic(struct ixgbe_hw *hw, u32 index); s32 ixgbe_blink_led_stop_generic(struct ixgbe_hw *hw, u32 index); void ixgbe_set_mac_anti_spoofing(struct ixgbe_hw *hw, bool enable, int pf); void ixgbe_set_vlan_anti_spoofing(struct ixgbe_hw *hw, bool enable, int vf); +s32 ixgbe_get_device_caps_generic(struct ixgbe_hw *hw, u16 *device_caps); #define IXGBE_WRITE_REG(a, reg, value) writel((value), ((a)->hw_addr + (reg))) diff --git a/drivers/net/ixgbe/ixgbe_x540.c b/drivers/net/ixgbe/ixgbe_x540.c index 5433f15..05f8e9c 100644 --- a/drivers/net/ixgbe/ixgbe_x540.c +++ b/drivers/net/ixgbe/ixgbe_x540.c @@ -754,7 +754,7 @@ static struct ixgbe_mac_operations mac_ops_X540 = { .enable_rx_dma = &ixgbe_enable_rx_dma_generic, .get_mac_addr = &ixgbe_get_mac_addr_generic, .get_san_mac_addr = &ixgbe_get_san_mac_addr_generic, - .get_device_caps = NULL, + .get_device_caps = &ixgbe_get_device_caps_generic, .get_wwn_prefix = &ixgbe_get_wwn_prefix_generic, .stop_adapter = &ixgbe_stop_adapter_generic, .get_bus_info = &ixgbe_get_bus_info_generic, -- cgit v0.10.2 From e09ad236fc85b1d6e010138f59aba76f6c9a295b Mon Sep 17 00:00:00 2001 From: John Fastabend Date: Mon, 4 Apr 2011 04:29:41 +0000 Subject: ixgbe: DCB, misallocated packet buffer size with X540 device The X540 device has a smaller packet buffer but the DCB configuration never took this into account. Under stress this can result in the DMA engine hanging and TX Unit hang occurring to reset the device. This patch reworks the packet buffer allocation routine used for DCB on 82599 and X540 devices to account for RX packet buffer sizes. This fixes the immediate hang. We should consolidate the various hardware specific routines for configuring features into a single routine. This will make it much harder to miss feature cases like this. Signed-off-by: John Fastabend Tested-by: Ross Brattain Tested-by: Evan Swanson Signed-off-by: Jeff Kirsher diff --git a/drivers/net/ixgbe/ixgbe_82598.c b/drivers/net/ixgbe/ixgbe_82598.c index af4054a..7a64f50 100644 --- a/drivers/net/ixgbe/ixgbe_82598.c +++ b/drivers/net/ixgbe/ixgbe_82598.c @@ -37,6 +37,7 @@ #define IXGBE_82598_RAR_ENTRIES 16 #define IXGBE_82598_MC_TBL_SIZE 128 #define IXGBE_82598_VFT_TBL_SIZE 128 +#define IXGBE_82598_RX_PB_SIZE 512 static s32 ixgbe_setup_copper_link_82598(struct ixgbe_hw *hw, ixgbe_link_speed speed, @@ -224,6 +225,8 @@ static s32 ixgbe_start_hw_82598(struct ixgbe_hw *hw) IXGBE_WRITE_REG(hw, IXGBE_DCA_RXCTRL(i), regval); } + hw->mac.rx_pb_size = IXGBE_82598_RX_PB_SIZE; + /* set the completion timeout for interface */ if (ret_val == 0) ixgbe_set_pcie_completion_timeout(hw); diff --git a/drivers/net/ixgbe/ixgbe_82599.c b/drivers/net/ixgbe/ixgbe_82599.c index e432305..b341ed8 100644 --- a/drivers/net/ixgbe/ixgbe_82599.c +++ b/drivers/net/ixgbe/ixgbe_82599.c @@ -38,6 +38,7 @@ #define IXGBE_82599_RAR_ENTRIES 128 #define IXGBE_82599_MC_TBL_SIZE 128 #define IXGBE_82599_VFT_TBL_SIZE 128 +#define IXGBE_82599_RX_PB_SIZE 512 static void ixgbe_disable_tx_laser_multispeed_fiber(struct ixgbe_hw *hw); static void ixgbe_enable_tx_laser_multispeed_fiber(struct ixgbe_hw *hw); @@ -1765,6 +1766,7 @@ static s32 ixgbe_start_hw_82599(struct ixgbe_hw *hw) /* We need to run link autotry after the driver loads */ hw->mac.autotry_restart = true; + hw->mac.rx_pb_size = IXGBE_82599_RX_PB_SIZE; if (ret_val == 0) ret_val = ixgbe_verify_fw_version_82599(hw); diff --git a/drivers/net/ixgbe/ixgbe_dcb_82599.c b/drivers/net/ixgbe/ixgbe_dcb_82599.c index 025af8c..865ddd8 100644 --- a/drivers/net/ixgbe/ixgbe_dcb_82599.c +++ b/drivers/net/ixgbe/ixgbe_dcb_82599.c @@ -39,36 +39,52 @@ */ static s32 ixgbe_dcb_config_packet_buffers_82599(struct ixgbe_hw *hw, u8 rx_pba) { - s32 ret_val = 0; - u32 value = IXGBE_RXPBSIZE_64KB; + int num_tcs = IXGBE_MAX_PACKET_BUFFERS; + u32 rx_pb_size = hw->mac.rx_pb_size << IXGBE_RXPBSIZE_SHIFT; + u32 rxpktsize; + u32 txpktsize; + u32 txpbthresh; u8 i = 0; - /* Setup Rx packet buffer sizes */ - switch (rx_pba) { - case pba_80_48: - /* Setup the first four at 80KB */ - value = IXGBE_RXPBSIZE_80KB; - for (; i < 4; i++) - IXGBE_WRITE_REG(hw, IXGBE_RXPBSIZE(i), value); - /* Setup the last four at 48KB...don't re-init i */ - value = IXGBE_RXPBSIZE_48KB; - /* Fall Through */ - case pba_equal: - default: - for (; i < IXGBE_MAX_PACKET_BUFFERS; i++) - IXGBE_WRITE_REG(hw, IXGBE_RXPBSIZE(i), value); - - /* Setup Tx packet buffer sizes */ - for (i = 0; i < IXGBE_MAX_PACKET_BUFFERS; i++) { - IXGBE_WRITE_REG(hw, IXGBE_TXPBSIZE(i), - IXGBE_TXPBSIZE_20KB); - IXGBE_WRITE_REG(hw, IXGBE_TXPBTHRESH(i), - IXGBE_TXPBTHRESH_DCB); - } - break; + /* + * This really means configure the first half of the TCs + * (Traffic Classes) to use 5/8 of the Rx packet buffer + * space. To determine the size of the buffer for each TC, + * we are multiplying the average size by 5/4 and applying + * it to half of the traffic classes. + */ + if (rx_pba == pba_80_48) { + rxpktsize = (rx_pb_size * 5) / (num_tcs * 4); + rx_pb_size -= rxpktsize * (num_tcs / 2); + for (; i < (num_tcs / 2); i++) + IXGBE_WRITE_REG(hw, IXGBE_RXPBSIZE(i), rxpktsize); + } + + /* Divide the remaining Rx packet buffer evenly among the TCs */ + rxpktsize = rx_pb_size / (num_tcs - i); + for (; i < num_tcs; i++) + IXGBE_WRITE_REG(hw, IXGBE_RXPBSIZE(i), rxpktsize); + + /* + * Setup Tx packet buffer and threshold equally for all TCs + * TXPBTHRESH register is set in K so divide by 1024 and subtract + * 10 since the largest packet we support is just over 9K. + */ + txpktsize = IXGBE_TXPBSIZE_MAX / num_tcs; + txpbthresh = (txpktsize / 1024) - IXGBE_TXPKT_SIZE_MAX; + for (i = 0; i < num_tcs; i++) { + IXGBE_WRITE_REG(hw, IXGBE_TXPBSIZE(i), txpktsize); + IXGBE_WRITE_REG(hw, IXGBE_TXPBTHRESH(i), txpbthresh); } - return ret_val; + /* Clear unused TCs, if any, to zero buffer size*/ + for (; i < MAX_TRAFFIC_CLASS; i++) { + IXGBE_WRITE_REG(hw, IXGBE_RXPBSIZE(i), 0); + IXGBE_WRITE_REG(hw, IXGBE_TXPBSIZE(i), 0); + IXGBE_WRITE_REG(hw, IXGBE_TXPBTHRESH(i), 0); + } + + return 0; } /** diff --git a/drivers/net/ixgbe/ixgbe_dcb_82599.h b/drivers/net/ixgbe/ixgbe_dcb_82599.h index 148fd8b..2de71a5 100644 --- a/drivers/net/ixgbe/ixgbe_dcb_82599.h +++ b/drivers/net/ixgbe/ixgbe_dcb_82599.h @@ -92,8 +92,10 @@ #define IXGBE_RXPBSIZE_64KB 0x00010000 /* 64KB Packet Buffer */ #define IXGBE_RXPBSIZE_80KB 0x00014000 /* 80KB Packet Buffer */ #define IXGBE_RXPBSIZE_128KB 0x00020000 /* 128KB Packet Buffer */ +#define IXGBE_TXPBSIZE_MAX 0x00028000 /* 160KB Packet Buffer*/ #define IXGBE_TXPBTHRESH_DCB 0xA /* THRESH value for DCB mode */ +#define IXGBE_TXPKT_SIZE_MAX 0xA /* Max Tx Packet size */ /* SECTXMINIFG DCB */ #define IXGBE_SECTX_DCB 0x00001F00 /* DCB TX Buffer IFG */ diff --git a/drivers/net/ixgbe/ixgbe_type.h b/drivers/net/ixgbe/ixgbe_type.h index 15580d6..7d0b37d 100644 --- a/drivers/net/ixgbe/ixgbe_type.h +++ b/drivers/net/ixgbe/ixgbe_type.h @@ -2606,6 +2606,7 @@ struct ixgbe_mac_info { u32 vft_size; u32 num_rar_entries; u32 rar_highwater; + u32 rx_pb_size; u32 max_tx_queues; u32 max_rx_queues; u32 max_msix_vectors; diff --git a/drivers/net/ixgbe/ixgbe_x540.c b/drivers/net/ixgbe/ixgbe_x540.c index 05f8e9c..932394f 100644 --- a/drivers/net/ixgbe/ixgbe_x540.c +++ b/drivers/net/ixgbe/ixgbe_x540.c @@ -37,6 +37,7 @@ #define IXGBE_X540_RAR_ENTRIES 128 #define IXGBE_X540_MC_TBL_SIZE 128 #define IXGBE_X540_VFT_TBL_SIZE 128 +#define IXGBE_X540_RX_PB_SIZE 384 static s32 ixgbe_update_flash_X540(struct ixgbe_hw *hw); static s32 ixgbe_poll_flash_update_done_X540(struct ixgbe_hw *hw); @@ -242,7 +243,7 @@ static s32 ixgbe_start_hw_X540(struct ixgbe_hw *hw) goto out; ret_val = ixgbe_start_hw_gen2(hw); - + hw->mac.rx_pb_size = IXGBE_X540_RX_PB_SIZE; out: return ret_val; } -- cgit v0.10.2 From 45a5f720fe37d21059da3c333c373c845ccbd82b Mon Sep 17 00:00:00 2001 From: John Fastabend Date: Mon, 4 Apr 2011 04:29:46 +0000 Subject: ixgbe: DCB, X540 devices do not respond to pause frames DCB enabled X540 devices are not responding to pause frames due to a missing register set that was added for these devices that did not exist in other devices. Signed-off-by: John Fastabend Tested-by: Ross Brattain Signed-off-by: Jeff Kirsher diff --git a/drivers/net/ixgbe/ixgbe_dcb_82599.c b/drivers/net/ixgbe/ixgbe_dcb_82599.c index 865ddd8..d50cf78 100644 --- a/drivers/net/ixgbe/ixgbe_dcb_82599.c +++ b/drivers/net/ixgbe/ixgbe_dcb_82599.c @@ -301,12 +301,17 @@ s32 ixgbe_dcb_config_pfc_82599(struct ixgbe_hw *hw, u8 pfc_en) IXGBE_WRITE_REG(hw, IXGBE_FCCFG, reg); /* * Enable Receive PFC - * We will always honor XOFF frames we receive when - * we are in PFC mode. + * 82599 will always honor XOFF frames we receive when + * we are in PFC mode however X540 only honors enabled + * traffic classes. */ reg = IXGBE_READ_REG(hw, IXGBE_MFLCN); reg &= ~IXGBE_MFLCN_RFCE; reg |= IXGBE_MFLCN_RPFCE | IXGBE_MFLCN_DPF; + + if (hw->mac.type == ixgbe_mac_X540) + reg |= pfc_en << IXGBE_MFLCN_RPFCE_SHIFT; + IXGBE_WRITE_REG(hw, IXGBE_MFLCN, reg); } else { diff --git a/drivers/net/ixgbe/ixgbe_type.h b/drivers/net/ixgbe/ixgbe_type.h index 7d0b37d..f5bec97 100644 --- a/drivers/net/ixgbe/ixgbe_type.h +++ b/drivers/net/ixgbe/ixgbe_type.h @@ -1728,6 +1728,8 @@ #define IXGBE_MFLCN_RPFCE 0x00000004 /* Receive Priority FC Enable */ #define IXGBE_MFLCN_RFCE 0x00000008 /* Receive FC Enable */ +#define IXGBE_MFLCN_RPFCE_SHIFT 4 + /* Multiple Receive Queue Control */ #define IXGBE_MRQC_RSSEN 0x00000001 /* RSS Enable */ #define IXGBE_MRQC_MRQE_MASK 0xF /* Bits 3:0 */ -- cgit v0.10.2 From 184748cc50b2dceb8287f9fb657eda48ff8fcfe7 Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Tue, 5 Apr 2011 17:23:39 +0200 Subject: sched: Provide scheduler_ipi() callback in response to smp_send_reschedule() For future rework of try_to_wake_up() we'd like to push part of that function onto the CPU the task is actually going to run on. In order to do so we need a generic callback from the existing scheduler IPI. This patch introduces such a generic callback: scheduler_ipi() and implements it as a NOP. BenH notes: PowerPC might use this IPI on offline CPUs under rare conditions! Acked-by: Russell King Acked-by: Martin Schwidefsky Acked-by: Chris Metcalf Acked-by: Jesper Nilsson Acked-by: Benjamin Herrenschmidt Signed-off-by: Ralf Baechle Reviewed-by: Frank Rowand Cc: Mike Galbraith Cc: Nick Piggin Cc: Linus Torvalds Cc: Andrew Morton Signed-off-by: Ingo Molnar Signed-off-by: Peter Zijlstra Link: http://lkml.kernel.org/r/20110405152728.744338123@chello.nl diff --git a/arch/alpha/kernel/smp.c b/arch/alpha/kernel/smp.c index 42aa078..5a621c6 100644 --- a/arch/alpha/kernel/smp.c +++ b/arch/alpha/kernel/smp.c @@ -585,8 +585,7 @@ handle_ipi(struct pt_regs *regs) switch (which) { case IPI_RESCHEDULE: - /* Reschedule callback. Everything to be done - is done by the interrupt return path. */ + scheduler_ipi(); break; case IPI_CALL_FUNC: diff --git a/arch/arm/kernel/smp.c b/arch/arm/kernel/smp.c index 8fe05ad..7a561eb 100644 --- a/arch/arm/kernel/smp.c +++ b/arch/arm/kernel/smp.c @@ -560,10 +560,7 @@ asmlinkage void __exception_irq_entry do_IPI(int ipinr, struct pt_regs *regs) break; case IPI_RESCHEDULE: - /* - * nothing more to do - eveything is - * done on the interrupt return path - */ + scheduler_ipi(); break; case IPI_CALL_FUNC: diff --git a/arch/blackfin/mach-common/smp.c b/arch/blackfin/mach-common/smp.c index 6e17a26..326bb86 100644 --- a/arch/blackfin/mach-common/smp.c +++ b/arch/blackfin/mach-common/smp.c @@ -164,6 +164,9 @@ static irqreturn_t ipi_handler_int1(int irq, void *dev_instance) while (msg_queue->count) { msg = &msg_queue->ipi_message[msg_queue->head]; switch (msg->type) { + case BFIN_IPI_RESCHEDULE: + scheduler_ipi(); + break; case BFIN_IPI_CALL_FUNC: spin_unlock_irqrestore(&msg_queue->lock, flags); ipi_call_function(cpu, msg); diff --git a/arch/cris/arch-v32/kernel/smp.c b/arch/cris/arch-v32/kernel/smp.c index 4c9e3e1..66cc756 100644 --- a/arch/cris/arch-v32/kernel/smp.c +++ b/arch/cris/arch-v32/kernel/smp.c @@ -342,15 +342,18 @@ irqreturn_t crisv32_ipi_interrupt(int irq, void *dev_id) ipi = REG_RD(intr_vect, irq_regs[smp_processor_id()], rw_ipi); + if (ipi.vector & IPI_SCHEDULE) { + scheduler_ipi(); + } if (ipi.vector & IPI_CALL) { - func(info); + func(info); } if (ipi.vector & IPI_FLUSH_TLB) { - if (flush_mm == FLUSH_ALL) - __flush_tlb_all(); - else if (flush_vma == FLUSH_ALL) + if (flush_mm == FLUSH_ALL) + __flush_tlb_all(); + else if (flush_vma == FLUSH_ALL) __flush_tlb_mm(flush_mm); - else + else __flush_tlb_page(flush_vma, flush_addr); } diff --git a/arch/ia64/kernel/irq_ia64.c b/arch/ia64/kernel/irq_ia64.c index 5b70474..782c3a35 100644 --- a/arch/ia64/kernel/irq_ia64.c +++ b/arch/ia64/kernel/irq_ia64.c @@ -31,6 +31,7 @@ #include #include #include +#include #include #include @@ -496,6 +497,7 @@ ia64_handle_irq (ia64_vector vector, struct pt_regs *regs) smp_local_flush_tlb(); kstat_incr_irqs_this_cpu(irq, desc); } else if (unlikely(IS_RESCHEDULE(vector))) { + scheduler_ipi(); kstat_incr_irqs_this_cpu(irq, desc); } else { ia64_setreg(_IA64_REG_CR_TPR, vector); diff --git a/arch/ia64/xen/irq_xen.c b/arch/ia64/xen/irq_xen.c index 108bb85..b279e14 100644 --- a/arch/ia64/xen/irq_xen.c +++ b/arch/ia64/xen/irq_xen.c @@ -92,6 +92,8 @@ static unsigned short saved_irq_cnt; static int xen_slab_ready; #ifdef CONFIG_SMP +#include + /* Dummy stub. Though we may check XEN_RESCHEDULE_VECTOR before __do_IRQ, * it ends up to issue several memory accesses upon percpu data and * thus adds unnecessary traffic to other paths. @@ -99,7 +101,13 @@ static int xen_slab_ready; static irqreturn_t xen_dummy_handler(int irq, void *dev_id) { + return IRQ_HANDLED; +} +static irqreturn_t +xen_resched_handler(int irq, void *dev_id) +{ + scheduler_ipi(); return IRQ_HANDLED; } @@ -110,7 +118,7 @@ static struct irqaction xen_ipi_irqaction = { }; static struct irqaction xen_resched_irqaction = { - .handler = xen_dummy_handler, + .handler = xen_resched_handler, .flags = IRQF_DISABLED, .name = "resched" }; diff --git a/arch/m32r/kernel/smp.c b/arch/m32r/kernel/smp.c index 31cef20..fc10b39 100644 --- a/arch/m32r/kernel/smp.c +++ b/arch/m32r/kernel/smp.c @@ -122,8 +122,6 @@ void smp_send_reschedule(int cpu_id) * * Description: This routine executes on CPU which received * 'RESCHEDULE_IPI'. - * Rescheduling is processed at the exit of interrupt - * operation. * * Born on Date: 2002.02.05 * @@ -138,7 +136,7 @@ void smp_send_reschedule(int cpu_id) *==========================================================================*/ void smp_reschedule_interrupt(void) { - /* nothing to do */ + scheduler_ipi(); } /*==========================================================================* diff --git a/arch/mips/cavium-octeon/smp.c b/arch/mips/cavium-octeon/smp.c index ba78b21..76923ee 100644 --- a/arch/mips/cavium-octeon/smp.c +++ b/arch/mips/cavium-octeon/smp.c @@ -44,6 +44,8 @@ static irqreturn_t mailbox_interrupt(int irq, void *dev_id) if (action & SMP_CALL_FUNCTION) smp_call_function_interrupt(); + if (action & SMP_RESCHEDULE_YOURSELF) + scheduler_ipi(); /* Check if we've been told to flush the icache */ if (action & SMP_ICACHE_FLUSH) diff --git a/arch/mips/kernel/smtc.c b/arch/mips/kernel/smtc.c index 5a88cc4..cedac46 100644 --- a/arch/mips/kernel/smtc.c +++ b/arch/mips/kernel/smtc.c @@ -929,7 +929,7 @@ static void post_direct_ipi(int cpu, struct smtc_ipi *pipi) static void ipi_resched_interrupt(void) { - /* Return from interrupt should be enough to cause scheduler check */ + scheduler_ipi(); } static void ipi_call_interrupt(void) diff --git a/arch/mips/mti-malta/malta-int.c b/arch/mips/mti-malta/malta-int.c index 9027061..7d93e6fb 100644 --- a/arch/mips/mti-malta/malta-int.c +++ b/arch/mips/mti-malta/malta-int.c @@ -309,6 +309,8 @@ static void ipi_call_dispatch(void) static irqreturn_t ipi_resched_interrupt(int irq, void *dev_id) { + scheduler_ipi(); + return IRQ_HANDLED; } diff --git a/arch/mips/pmc-sierra/yosemite/smp.c b/arch/mips/pmc-sierra/yosemite/smp.c index efc9e88..2608752 100644 --- a/arch/mips/pmc-sierra/yosemite/smp.c +++ b/arch/mips/pmc-sierra/yosemite/smp.c @@ -55,6 +55,8 @@ void titan_mailbox_irq(void) if (status & 0x2) smp_call_function_interrupt(); + if (status & 0x4) + scheduler_ipi(); break; case 1: @@ -63,6 +65,8 @@ void titan_mailbox_irq(void) if (status & 0x2) smp_call_function_interrupt(); + if (status & 0x4) + scheduler_ipi(); break; } } diff --git a/arch/mips/sgi-ip27/ip27-irq.c b/arch/mips/sgi-ip27/ip27-irq.c index 0a04603..b18b04e 100644 --- a/arch/mips/sgi-ip27/ip27-irq.c +++ b/arch/mips/sgi-ip27/ip27-irq.c @@ -147,8 +147,10 @@ static void ip27_do_irq_mask0(void) #ifdef CONFIG_SMP if (pend0 & (1UL << CPU_RESCHED_A_IRQ)) { LOCAL_HUB_CLR_INTR(CPU_RESCHED_A_IRQ); + scheduler_ipi(); } else if (pend0 & (1UL << CPU_RESCHED_B_IRQ)) { LOCAL_HUB_CLR_INTR(CPU_RESCHED_B_IRQ); + scheduler_ipi(); } else if (pend0 & (1UL << CPU_CALL_A_IRQ)) { LOCAL_HUB_CLR_INTR(CPU_CALL_A_IRQ); smp_call_function_interrupt(); diff --git a/arch/mips/sibyte/bcm1480/smp.c b/arch/mips/sibyte/bcm1480/smp.c index 47b347c..d667875 100644 --- a/arch/mips/sibyte/bcm1480/smp.c +++ b/arch/mips/sibyte/bcm1480/smp.c @@ -20,6 +20,7 @@ #include #include #include +#include #include #include @@ -189,10 +190,8 @@ void bcm1480_mailbox_interrupt(void) /* Clear the mailbox to clear the interrupt */ __raw_writeq(((u64)action)<<48, mailbox_0_clear_regs[cpu]); - /* - * Nothing to do for SMP_RESCHEDULE_YOURSELF; returning from the - * interrupt will do the reschedule for us - */ + if (action & SMP_RESCHEDULE_YOURSELF) + scheduler_ipi(); if (action & SMP_CALL_FUNCTION) smp_call_function_interrupt(); diff --git a/arch/mips/sibyte/sb1250/smp.c b/arch/mips/sibyte/sb1250/smp.c index c00a5cb..38e7f6b 100644 --- a/arch/mips/sibyte/sb1250/smp.c +++ b/arch/mips/sibyte/sb1250/smp.c @@ -21,6 +21,7 @@ #include #include #include +#include #include #include @@ -177,10 +178,8 @@ void sb1250_mailbox_interrupt(void) /* Clear the mailbox to clear the interrupt */ ____raw_writeq(((u64)action) << 48, mailbox_clear_regs[cpu]); - /* - * Nothing to do for SMP_RESCHEDULE_YOURSELF; returning from the - * interrupt will do the reschedule for us - */ + if (action & SMP_RESCHEDULE_YOURSELF) + scheduler_ipi(); if (action & SMP_CALL_FUNCTION) smp_call_function_interrupt(); diff --git a/arch/mn10300/kernel/smp.c b/arch/mn10300/kernel/smp.c index 226c826..83fb279 100644 --- a/arch/mn10300/kernel/smp.c +++ b/arch/mn10300/kernel/smp.c @@ -494,14 +494,11 @@ void smp_send_stop(void) * @irq: The interrupt number. * @dev_id: The device ID. * - * We need do nothing here, since the scheduling will be effected on our way - * back through entry.S. - * * Returns IRQ_HANDLED to indicate we handled the interrupt successfully. */ static irqreturn_t smp_reschedule_interrupt(int irq, void *dev_id) { - /* do nothing */ + scheduler_ipi(); return IRQ_HANDLED; } diff --git a/arch/parisc/kernel/smp.c b/arch/parisc/kernel/smp.c index 69d63d3..828305f 100644 --- a/arch/parisc/kernel/smp.c +++ b/arch/parisc/kernel/smp.c @@ -155,10 +155,7 @@ ipi_interrupt(int irq, void *dev_id) case IPI_RESCHEDULE: smp_debug(100, KERN_DEBUG "CPU%d IPI_RESCHEDULE\n", this_cpu); - /* - * Reschedule callback. Everything to be - * done is done by the interrupt return path. - */ + scheduler_ipi(); break; case IPI_CALL_FUNC: diff --git a/arch/powerpc/kernel/smp.c b/arch/powerpc/kernel/smp.c index cbdbb14..9f9c204 100644 --- a/arch/powerpc/kernel/smp.c +++ b/arch/powerpc/kernel/smp.c @@ -116,7 +116,7 @@ void smp_message_recv(int msg) generic_smp_call_function_interrupt(); break; case PPC_MSG_RESCHEDULE: - /* we notice need_resched on exit */ + scheduler_ipi(); break; case PPC_MSG_CALL_FUNC_SINGLE: generic_smp_call_function_single_interrupt(); @@ -146,7 +146,7 @@ static irqreturn_t call_function_action(int irq, void *data) static irqreturn_t reschedule_action(int irq, void *data) { - /* we just need the return path side effect of checking need_resched */ + scheduler_ipi(); return IRQ_HANDLED; } diff --git a/arch/s390/kernel/smp.c b/arch/s390/kernel/smp.c index 63a97db..63c7d9f 100644 --- a/arch/s390/kernel/smp.c +++ b/arch/s390/kernel/smp.c @@ -165,12 +165,12 @@ static void do_ext_call_interrupt(unsigned int ext_int_code, kstat_cpu(smp_processor_id()).irqs[EXTINT_IPI]++; /* * handle bit signal external calls - * - * For the ec_schedule signal we have to do nothing. All the work - * is done automatically when we return from the interrupt. */ bits = xchg(&S390_lowcore.ext_call_fast, 0); + if (test_bit(ec_schedule, &bits)) + scheduler_ipi(); + if (test_bit(ec_call_function, &bits)) generic_smp_call_function_interrupt(); diff --git a/arch/sh/kernel/smp.c b/arch/sh/kernel/smp.c index 509b36b..6207561 100644 --- a/arch/sh/kernel/smp.c +++ b/arch/sh/kernel/smp.c @@ -20,6 +20,7 @@ #include #include #include +#include #include #include #include @@ -323,6 +324,7 @@ void smp_message_recv(unsigned int msg) generic_smp_call_function_interrupt(); break; case SMP_MSG_RESCHEDULE: + scheduler_ipi(); break; case SMP_MSG_FUNCTION_SINGLE: generic_smp_call_function_single_interrupt(); diff --git a/arch/sparc/kernel/smp_32.c b/arch/sparc/kernel/smp_32.c index 91c10fb..f95690c 100644 --- a/arch/sparc/kernel/smp_32.c +++ b/arch/sparc/kernel/smp_32.c @@ -125,7 +125,9 @@ struct linux_prom_registers smp_penguin_ctable __cpuinitdata = { 0 }; void smp_send_reschedule(int cpu) { - /* See sparc64 */ + /* + * XXX missing reschedule IPI, see scheduler_ipi() + */ } void smp_send_stop(void) diff --git a/arch/sparc/kernel/smp_64.c b/arch/sparc/kernel/smp_64.c index 3e94a8c..9478da7 100644 --- a/arch/sparc/kernel/smp_64.c +++ b/arch/sparc/kernel/smp_64.c @@ -1368,6 +1368,7 @@ void smp_send_reschedule(int cpu) void __irq_entry smp_receive_signal_client(int irq, struct pt_regs *regs) { clear_softint(1 << irq); + scheduler_ipi(); } /* This is a nop because we capture all other cpus diff --git a/arch/tile/kernel/smp.c b/arch/tile/kernel/smp.c index a429310..c52224d 100644 --- a/arch/tile/kernel/smp.c +++ b/arch/tile/kernel/smp.c @@ -189,12 +189,8 @@ void flush_icache_range(unsigned long start, unsigned long end) /* Called when smp_send_reschedule() triggers IRQ_RESCHEDULE. */ static irqreturn_t handle_reschedule_ipi(int irq, void *token) { - /* - * Nothing to do here; when we return from interrupt, the - * rescheduling will occur there. But do bump the interrupt - * profiler count in the meantime. - */ __get_cpu_var(irq_stat).irq_resched_count++; + scheduler_ipi(); return IRQ_HANDLED; } diff --git a/arch/um/kernel/smp.c b/arch/um/kernel/smp.c index 106bf27..eefb107 100644 --- a/arch/um/kernel/smp.c +++ b/arch/um/kernel/smp.c @@ -173,7 +173,7 @@ void IPI_handler(int cpu) break; case 'R': - set_tsk_need_resched(current); + scheduler_ipi(); break; case 'S': diff --git a/arch/x86/kernel/smp.c b/arch/x86/kernel/smp.c index 513deac..013e7eb 100644 --- a/arch/x86/kernel/smp.c +++ b/arch/x86/kernel/smp.c @@ -194,14 +194,13 @@ static void native_stop_other_cpus(int wait) } /* - * Reschedule call back. Nothing to do, - * all the work is done automatically when - * we return from the interrupt. + * Reschedule call back. */ void smp_reschedule_interrupt(struct pt_regs *regs) { ack_APIC_irq(); inc_irq_stat(irq_resched_count); + scheduler_ipi(); /* * KVM uses this interrupt to force a cpu out of guest mode */ diff --git a/arch/x86/xen/smp.c b/arch/x86/xen/smp.c index 3061244..762b46a 100644 --- a/arch/x86/xen/smp.c +++ b/arch/x86/xen/smp.c @@ -46,13 +46,12 @@ static irqreturn_t xen_call_function_interrupt(int irq, void *dev_id); static irqreturn_t xen_call_function_single_interrupt(int irq, void *dev_id); /* - * Reschedule call back. Nothing to do, - * all the work is done automatically when - * we return from the interrupt. + * Reschedule call back. */ static irqreturn_t xen_reschedule_interrupt(int irq, void *dev_id) { inc_irq_stat(irq_resched_count); + scheduler_ipi(); return IRQ_HANDLED; } diff --git a/include/linux/sched.h b/include/linux/sched.h index 4ec2c02..758e27a 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h @@ -2189,8 +2189,10 @@ extern void set_task_comm(struct task_struct *tsk, char *from); extern char *get_task_comm(char *to, struct task_struct *tsk); #ifdef CONFIG_SMP +static inline void scheduler_ipi(void) { } extern unsigned long wait_task_inactive(struct task_struct *, long match_state); #else +static inline void scheduler_ipi(void) { } static inline unsigned long wait_task_inactive(struct task_struct *p, long match_state) { -- cgit v0.10.2 From 3ca7a440da394808571dad32d33d3bc0389982e6 Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Tue, 5 Apr 2011 17:23:40 +0200 Subject: sched: Always provide p->on_cpu Always provide p->on_cpu so that we can determine if its on a cpu without having to lock the rq. Reviewed-by: Frank Rowand Signed-off-by: Peter Zijlstra Cc: Mike Galbraith Cc: Nick Piggin Cc: Linus Torvalds Cc: Andrew Morton Link: http://lkml.kernel.org/r/20110405152728.785452014@chello.nl Signed-off-by: Ingo Molnar diff --git a/include/linux/sched.h b/include/linux/sched.h index 758e27a..3435837 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h @@ -1200,9 +1200,7 @@ struct task_struct { int lock_depth; /* BKL lock depth */ #ifdef CONFIG_SMP -#ifdef __ARCH_WANT_UNLOCKED_CTXSW - int oncpu; -#endif + int on_cpu; #endif int prio, static_prio, normal_prio; diff --git a/kernel/sched.c b/kernel/sched.c index a187c3f..cd2593e 100644 --- a/kernel/sched.c +++ b/kernel/sched.c @@ -838,18 +838,39 @@ static inline int task_current(struct rq *rq, struct task_struct *p) return rq->curr == p; } -#ifndef __ARCH_WANT_UNLOCKED_CTXSW static inline int task_running(struct rq *rq, struct task_struct *p) { +#ifdef CONFIG_SMP + return p->on_cpu; +#else return task_current(rq, p); +#endif } +#ifndef __ARCH_WANT_UNLOCKED_CTXSW static inline void prepare_lock_switch(struct rq *rq, struct task_struct *next) { +#ifdef CONFIG_SMP + /* + * We can optimise this out completely for !SMP, because the + * SMP rebalancing from interrupt is the only thing that cares + * here. + */ + next->on_cpu = 1; +#endif } static inline void finish_lock_switch(struct rq *rq, struct task_struct *prev) { +#ifdef CONFIG_SMP + /* + * After ->on_cpu is cleared, the task can be moved to a different CPU. + * We must ensure this doesn't happen until the switch is completely + * finished. + */ + smp_wmb(); + prev->on_cpu = 0; +#endif #ifdef CONFIG_DEBUG_SPINLOCK /* this is a valid case when another task releases the spinlock */ rq->lock.owner = current; @@ -865,15 +886,6 @@ static inline void finish_lock_switch(struct rq *rq, struct task_struct *prev) } #else /* __ARCH_WANT_UNLOCKED_CTXSW */ -static inline int task_running(struct rq *rq, struct task_struct *p) -{ -#ifdef CONFIG_SMP - return p->oncpu; -#else - return task_current(rq, p); -#endif -} - static inline void prepare_lock_switch(struct rq *rq, struct task_struct *next) { #ifdef CONFIG_SMP @@ -882,7 +894,7 @@ static inline void prepare_lock_switch(struct rq *rq, struct task_struct *next) * SMP rebalancing from interrupt is the only thing that cares * here. */ - next->oncpu = 1; + next->on_cpu = 1; #endif #ifdef __ARCH_WANT_INTERRUPTS_ON_CTXSW raw_spin_unlock_irq(&rq->lock); @@ -895,12 +907,12 @@ static inline void finish_lock_switch(struct rq *rq, struct task_struct *prev) { #ifdef CONFIG_SMP /* - * After ->oncpu is cleared, the task can be moved to a different CPU. + * After ->on_cpu is cleared, the task can be moved to a different CPU. * We must ensure this doesn't happen until the switch is completely * finished. */ smp_wmb(); - prev->oncpu = 0; + prev->on_cpu = 0; #endif #ifndef __ARCH_WANT_INTERRUPTS_ON_CTXSW local_irq_enable(); @@ -2686,8 +2698,8 @@ void sched_fork(struct task_struct *p, int clone_flags) if (likely(sched_info_on())) memset(&p->sched_info, 0, sizeof(p->sched_info)); #endif -#if defined(CONFIG_SMP) && defined(__ARCH_WANT_UNLOCKED_CTXSW) - p->oncpu = 0; +#if defined(CONFIG_SMP) + p->on_cpu = 0; #endif #ifdef CONFIG_PREEMPT /* Want to start with kernel preemption disabled. */ @@ -5776,8 +5788,8 @@ void __cpuinit init_idle(struct task_struct *idle, int cpu) rcu_read_unlock(); rq->curr = rq->idle = idle; -#if defined(CONFIG_SMP) && defined(__ARCH_WANT_UNLOCKED_CTXSW) - idle->oncpu = 1; +#if defined(CONFIG_SMP) + idle->on_cpu = 1; #endif raw_spin_unlock_irqrestore(&rq->lock, flags); -- cgit v0.10.2 From c6eb3dda25892f1f974f5420f63e6721aab02f6f Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Tue, 5 Apr 2011 17:23:41 +0200 Subject: mutex: Use p->on_cpu for the adaptive spin Since we now have p->on_cpu unconditionally available, use it to re-implement mutex_spin_on_owner. Requested-by: Thomas Gleixner Reviewed-by: Frank Rowand Cc: Mike Galbraith Cc: Nick Piggin Cc: Linus Torvalds Cc: Andrew Morton Signed-off-by: Ingo Molnar Signed-off-by: Peter Zijlstra Link: http://lkml.kernel.org/r/20110405152728.826338173@chello.nl diff --git a/include/linux/mutex.h b/include/linux/mutex.h index 94b48bd..c75471d 100644 --- a/include/linux/mutex.h +++ b/include/linux/mutex.h @@ -51,7 +51,7 @@ struct mutex { spinlock_t wait_lock; struct list_head wait_list; #if defined(CONFIG_DEBUG_MUTEXES) || defined(CONFIG_SMP) - struct thread_info *owner; + struct task_struct *owner; #endif #ifdef CONFIG_DEBUG_MUTEXES const char *name; diff --git a/include/linux/sched.h b/include/linux/sched.h index 3435837..1738504 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h @@ -360,7 +360,7 @@ extern signed long schedule_timeout_interruptible(signed long timeout); extern signed long schedule_timeout_killable(signed long timeout); extern signed long schedule_timeout_uninterruptible(signed long timeout); asmlinkage void schedule(void); -extern int mutex_spin_on_owner(struct mutex *lock, struct thread_info *owner); +extern int mutex_spin_on_owner(struct mutex *lock, struct task_struct *owner); struct nsproxy; struct user_namespace; diff --git a/kernel/mutex-debug.c b/kernel/mutex-debug.c index ec815a9..73da83a 100644 --- a/kernel/mutex-debug.c +++ b/kernel/mutex-debug.c @@ -75,7 +75,7 @@ void debug_mutex_unlock(struct mutex *lock) return; DEBUG_LOCKS_WARN_ON(lock->magic != lock); - DEBUG_LOCKS_WARN_ON(lock->owner != current_thread_info()); + DEBUG_LOCKS_WARN_ON(lock->owner != current); DEBUG_LOCKS_WARN_ON(!lock->wait_list.prev && !lock->wait_list.next); mutex_clear_owner(lock); } diff --git a/kernel/mutex-debug.h b/kernel/mutex-debug.h index 57d527a..0799fd3 100644 --- a/kernel/mutex-debug.h +++ b/kernel/mutex-debug.h @@ -29,7 +29,7 @@ extern void debug_mutex_init(struct mutex *lock, const char *name, static inline void mutex_set_owner(struct mutex *lock) { - lock->owner = current_thread_info(); + lock->owner = current; } static inline void mutex_clear_owner(struct mutex *lock) diff --git a/kernel/mutex.c b/kernel/mutex.c index c4195fa..fe4706c 100644 --- a/kernel/mutex.c +++ b/kernel/mutex.c @@ -160,7 +160,7 @@ __mutex_lock_common(struct mutex *lock, long state, unsigned int subclass, */ for (;;) { - struct thread_info *owner; + struct task_struct *owner; /* * If we own the BKL, then don't spin. The owner of diff --git a/kernel/mutex.h b/kernel/mutex.h index 67578ca..4115fbf 100644 --- a/kernel/mutex.h +++ b/kernel/mutex.h @@ -19,7 +19,7 @@ #ifdef CONFIG_SMP static inline void mutex_set_owner(struct mutex *lock) { - lock->owner = current_thread_info(); + lock->owner = current; } static inline void mutex_clear_owner(struct mutex *lock) diff --git a/kernel/sched.c b/kernel/sched.c index cd2593e..55cc503 100644 --- a/kernel/sched.c +++ b/kernel/sched.c @@ -4173,70 +4173,53 @@ need_resched: EXPORT_SYMBOL(schedule); #ifdef CONFIG_MUTEX_SPIN_ON_OWNER -/* - * Look out! "owner" is an entirely speculative pointer - * access and not reliable. - */ -int mutex_spin_on_owner(struct mutex *lock, struct thread_info *owner) -{ - unsigned int cpu; - struct rq *rq; - if (!sched_feat(OWNER_SPIN)) - return 0; +static inline bool owner_running(struct mutex *lock, struct task_struct *owner) +{ + bool ret = false; -#ifdef CONFIG_DEBUG_PAGEALLOC - /* - * Need to access the cpu field knowing that - * DEBUG_PAGEALLOC could have unmapped it if - * the mutex owner just released it and exited. - */ - if (probe_kernel_address(&owner->cpu, cpu)) - return 0; -#else - cpu = owner->cpu; -#endif + rcu_read_lock(); + if (lock->owner != owner) + goto fail; /* - * Even if the access succeeded (likely case), - * the cpu field may no longer be valid. + * Ensure we emit the owner->on_cpu, dereference _after_ checking + * lock->owner still matches owner, if that fails, owner might + * point to free()d memory, if it still matches, the rcu_read_lock() + * ensures the memory stays valid. */ - if (cpu >= nr_cpumask_bits) - return 0; + barrier(); - /* - * We need to validate that we can do a - * get_cpu() and that we have the percpu area. - */ - if (!cpu_online(cpu)) - return 0; + ret = owner->on_cpu; +fail: + rcu_read_unlock(); - rq = cpu_rq(cpu); + return ret; +} - for (;;) { - /* - * Owner changed, break to re-assess state. - */ - if (lock->owner != owner) { - /* - * If the lock has switched to a different owner, - * we likely have heavy contention. Return 0 to quit - * optimistic spinning and not contend further: - */ - if (lock->owner) - return 0; - break; - } +/* + * Look out! "owner" is an entirely speculative pointer + * access and not reliable. + */ +int mutex_spin_on_owner(struct mutex *lock, struct task_struct *owner) +{ + if (!sched_feat(OWNER_SPIN)) + return 0; - /* - * Is that owner really running on that cpu? - */ - if (task_thread_info(rq->curr) != owner || need_resched()) + while (owner_running(lock, owner)) { + if (need_resched()) return 0; arch_mutex_cpu_relax(); } + /* + * If the owner changed to another task there is likely + * heavy contention, stop spinning. + */ + if (lock->owner) + return 0; + return 1; } #endif -- cgit v0.10.2 From c2f7115e2e52a6c187b8c1f54f0e4970bb677be0 Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Wed, 13 Apr 2011 13:28:56 +0200 Subject: sched: Move wq_worker_waking to the correct site wq_worker_waking_up() needs to match wq_worker_sleeping(), since the latter is only called on deactivate, move the former near activate. Signed-off-by: Peter Zijlstra Cc: Tejun Heo Link: http://lkml.kernel.org/n/top-t3m7n70n9frmv4pv2n5fwmov@git.kernel.org Signed-off-by: Ingo Molnar diff --git a/kernel/sched.c b/kernel/sched.c index 55cc503..81ab58e 100644 --- a/kernel/sched.c +++ b/kernel/sched.c @@ -2421,6 +2421,10 @@ static inline void ttwu_activate(struct task_struct *p, struct rq *rq, schedstat_inc(p, se.statistics.nr_wakeups_remote); activate_task(rq, p, en_flags); + + /* if a worker is waking up, notify workqueue */ + if (p->flags & PF_WQ_WORKER) + wq_worker_waking_up(p, cpu_of(rq)); } static inline void ttwu_post_activation(struct task_struct *p, struct rq *rq, @@ -2445,9 +2449,6 @@ static inline void ttwu_post_activation(struct task_struct *p, struct rq *rq, rq->idle_stamp = 0; } #endif - /* if a worker is waking up, notify workqueue */ - if ((p->flags & PF_WQ_WORKER) && success) - wq_worker_waking_up(p, cpu_of(rq)); } /** -- cgit v0.10.2 From 893633817f5b58f5227365d74344e0170a718213 Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Tue, 5 Apr 2011 17:23:42 +0200 Subject: sched: Change the ttwu() success details try_to_wake_up() would only return a success when it would have to place a task on a rq, change that to every time we change p->state to TASK_RUNNING, because that's the real measure of wakeups. This results in that success is always true for the tracepoints. Reviewed-by: Frank Rowand Cc: Mike Galbraith Cc: Nick Piggin Cc: Linus Torvalds Cc: Andrew Morton Signed-off-by: Ingo Molnar Signed-off-by: Peter Zijlstra Link: http://lkml.kernel.org/r/20110405152728.866866929@chello.nl diff --git a/kernel/sched.c b/kernel/sched.c index 81ab58e..3919aa4 100644 --- a/kernel/sched.c +++ b/kernel/sched.c @@ -2427,10 +2427,10 @@ static inline void ttwu_activate(struct task_struct *p, struct rq *rq, wq_worker_waking_up(p, cpu_of(rq)); } -static inline void ttwu_post_activation(struct task_struct *p, struct rq *rq, - int wake_flags, bool success) +static void +ttwu_post_activation(struct task_struct *p, struct rq *rq, int wake_flags) { - trace_sched_wakeup(p, success); + trace_sched_wakeup(p, true); check_preempt_curr(rq, p, wake_flags); p->state = TASK_RUNNING; @@ -2546,9 +2546,9 @@ out_activate: #endif /* CONFIG_SMP */ ttwu_activate(p, rq, wake_flags & WF_SYNC, orig_cpu != cpu, cpu == this_cpu, en_flags); - success = 1; out_running: - ttwu_post_activation(p, rq, wake_flags, success); + ttwu_post_activation(p, rq, wake_flags); + success = 1; out: task_rq_unlock(rq, &flags); put_cpu(); @@ -2567,7 +2567,6 @@ out: static void try_to_wake_up_local(struct task_struct *p) { struct rq *rq = task_rq(p); - bool success = false; BUG_ON(rq != this_rq()); BUG_ON(p == current); @@ -2582,9 +2581,8 @@ static void try_to_wake_up_local(struct task_struct *p) schedstat_inc(rq, ttwu_local); } ttwu_activate(p, rq, false, false, true, ENQUEUE_WAKEUP); - success = true; } - ttwu_post_activation(p, rq, 0, success); + ttwu_post_activation(p, rq, 0); } /** @@ -2747,7 +2745,7 @@ void wake_up_new_task(struct task_struct *p, unsigned long clone_flags) rq = task_rq_lock(p, &flags); activate_task(rq, p, 0); - trace_sched_wakeup_new(p, 1); + trace_sched_wakeup_new(p, true); check_preempt_curr(rq, p, WF_FORK); #ifdef CONFIG_SMP if (p->sched_class->task_woken) -- cgit v0.10.2 From d7c01d27ab767a30d672d1fd657aa8336ebdcbca Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Tue, 5 Apr 2011 17:23:43 +0200 Subject: sched: Clean up ttwu() stats Collect all ttwu() stat code into a single function and ensure its always called for an actual wakeup (changing p->state to TASK_RUNNING). Reviewed-by: Frank Rowand Cc: Mike Galbraith Cc: Nick Piggin Cc: Linus Torvalds Cc: Andrew Morton Signed-off-by: Ingo Molnar Signed-off-by: Peter Zijlstra Link: http://lkml.kernel.org/r/20110405152728.908177058@chello.nl diff --git a/kernel/sched.c b/kernel/sched.c index 3919aa4..4481638 100644 --- a/kernel/sched.c +++ b/kernel/sched.c @@ -2406,20 +2406,43 @@ static void update_avg(u64 *avg, u64 sample) } #endif -static inline void ttwu_activate(struct task_struct *p, struct rq *rq, - bool is_sync, bool is_migrate, bool is_local, - unsigned long en_flags) +static void +ttwu_stat(struct rq *rq, struct task_struct *p, int cpu, int wake_flags) { +#ifdef CONFIG_SCHEDSTATS +#ifdef CONFIG_SMP + int this_cpu = smp_processor_id(); + + if (cpu == this_cpu) { + schedstat_inc(rq, ttwu_local); + schedstat_inc(p, se.statistics.nr_wakeups_local); + } else { + struct sched_domain *sd; + + schedstat_inc(p, se.statistics.nr_wakeups_remote); + for_each_domain(this_cpu, sd) { + if (cpumask_test_cpu(cpu, sched_domain_span(sd))) { + schedstat_inc(sd, ttwu_wake_remote); + break; + } + } + } +#endif /* CONFIG_SMP */ + + schedstat_inc(rq, ttwu_count); schedstat_inc(p, se.statistics.nr_wakeups); - if (is_sync) + + if (wake_flags & WF_SYNC) schedstat_inc(p, se.statistics.nr_wakeups_sync); - if (is_migrate) + + if (cpu != task_cpu(p)) schedstat_inc(p, se.statistics.nr_wakeups_migrate); - if (is_local) - schedstat_inc(p, se.statistics.nr_wakeups_local); - else - schedstat_inc(p, se.statistics.nr_wakeups_remote); +#endif /* CONFIG_SCHEDSTATS */ +} + +static void ttwu_activate(struct rq *rq, struct task_struct *p, int en_flags) +{ activate_task(rq, p, en_flags); /* if a worker is waking up, notify workqueue */ @@ -2481,12 +2504,12 @@ static int try_to_wake_up(struct task_struct *p, unsigned int state, if (!(p->state & state)) goto out; + cpu = task_cpu(p); + if (p->se.on_rq) goto out_running; - cpu = task_cpu(p); orig_cpu = cpu; - #ifdef CONFIG_SMP if (unlikely(task_running(rq, p))) goto out_activate; @@ -2527,27 +2550,12 @@ static int try_to_wake_up(struct task_struct *p, unsigned int state, WARN_ON(task_cpu(p) != cpu); WARN_ON(p->state != TASK_WAKING); -#ifdef CONFIG_SCHEDSTATS - schedstat_inc(rq, ttwu_count); - if (cpu == this_cpu) - schedstat_inc(rq, ttwu_local); - else { - struct sched_domain *sd; - for_each_domain(this_cpu, sd) { - if (cpumask_test_cpu(cpu, sched_domain_span(sd))) { - schedstat_inc(sd, ttwu_wake_remote); - break; - } - } - } -#endif /* CONFIG_SCHEDSTATS */ - out_activate: #endif /* CONFIG_SMP */ - ttwu_activate(p, rq, wake_flags & WF_SYNC, orig_cpu != cpu, - cpu == this_cpu, en_flags); + ttwu_activate(rq, p, en_flags); out_running: ttwu_post_activation(p, rq, wake_flags); + ttwu_stat(rq, p, cpu, wake_flags); success = 1; out: task_rq_unlock(rq, &flags); @@ -2575,14 +2583,11 @@ static void try_to_wake_up_local(struct task_struct *p) if (!(p->state & TASK_NORMAL)) return; - if (!p->se.on_rq) { - if (likely(!task_running(rq, p))) { - schedstat_inc(rq, ttwu_count); - schedstat_inc(rq, ttwu_local); - } - ttwu_activate(p, rq, false, false, true, ENQUEUE_WAKEUP); - } + if (!p->se.on_rq) + ttwu_activate(rq, p, ENQUEUE_WAKEUP); + ttwu_post_activation(p, rq, 0); + ttwu_stat(rq, p, smp_processor_id(), 0); } /** -- cgit v0.10.2 From fd2f4419b4cbe8fe90796df9617c355762afd6a4 Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Tue, 5 Apr 2011 17:23:44 +0200 Subject: sched: Provide p->on_rq Provide a generic p->on_rq because the p->se.on_rq semantics are unfavourable for lockless wakeups but needed for sched_fair. In particular, p->on_rq is only cleared when we actually dequeue the task in schedule() and not on any random dequeue as done by things like __migrate_task() and __sched_setscheduler(). This also allows us to remove p->se usage from !sched_fair code. Reviewed-by: Frank Rowand Cc: Mike Galbraith Cc: Nick Piggin Cc: Linus Torvalds Cc: Andrew Morton Signed-off-by: Ingo Molnar Signed-off-by: Peter Zijlstra Link: http://lkml.kernel.org/r/20110405152728.949545047@chello.nl diff --git a/include/linux/sched.h b/include/linux/sched.h index 1738504..b33a700 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h @@ -1202,6 +1202,7 @@ struct task_struct { #ifdef CONFIG_SMP int on_cpu; #endif + int on_rq; int prio, static_prio, normal_prio; unsigned int rt_priority; diff --git a/kernel/sched.c b/kernel/sched.c index 4481638..dece28e 100644 --- a/kernel/sched.c +++ b/kernel/sched.c @@ -1785,7 +1785,6 @@ static void enqueue_task(struct rq *rq, struct task_struct *p, int flags) update_rq_clock(rq); sched_info_queued(p); p->sched_class->enqueue_task(rq, p, flags); - p->se.on_rq = 1; } static void dequeue_task(struct rq *rq, struct task_struct *p, int flags) @@ -1793,7 +1792,6 @@ static void dequeue_task(struct rq *rq, struct task_struct *p, int flags) update_rq_clock(rq); sched_info_dequeued(p); p->sched_class->dequeue_task(rq, p, flags); - p->se.on_rq = 0; } /* @@ -2128,7 +2126,7 @@ static void check_preempt_curr(struct rq *rq, struct task_struct *p, int flags) * A queue event has occurred, and we're going to schedule. In * this case, we can save a useless back to back clock update. */ - if (rq->curr->se.on_rq && test_tsk_need_resched(rq->curr)) + if (rq->curr->on_rq && test_tsk_need_resched(rq->curr)) rq->skip_clock_update = 1; } @@ -2203,7 +2201,7 @@ static bool migrate_task(struct task_struct *p, struct rq *rq) * If the task is not on a runqueue (and not running), then * the next wake-up will properly place the task. */ - return p->se.on_rq || task_running(rq, p); + return p->on_rq || task_running(rq, p); } /* @@ -2263,7 +2261,7 @@ unsigned long wait_task_inactive(struct task_struct *p, long match_state) rq = task_rq_lock(p, &flags); trace_sched_wait_task(p); running = task_running(rq, p); - on_rq = p->se.on_rq; + on_rq = p->on_rq; ncsw = 0; if (!match_state || p->state == match_state) ncsw = p->nvcsw | LONG_MIN; /* sets MSB */ @@ -2444,6 +2442,7 @@ ttwu_stat(struct rq *rq, struct task_struct *p, int cpu, int wake_flags) static void ttwu_activate(struct rq *rq, struct task_struct *p, int en_flags) { activate_task(rq, p, en_flags); + p->on_rq = 1; /* if a worker is waking up, notify workqueue */ if (p->flags & PF_WQ_WORKER) @@ -2506,7 +2505,7 @@ static int try_to_wake_up(struct task_struct *p, unsigned int state, cpu = task_cpu(p); - if (p->se.on_rq) + if (p->on_rq) goto out_running; orig_cpu = cpu; @@ -2583,7 +2582,7 @@ static void try_to_wake_up_local(struct task_struct *p) if (!(p->state & TASK_NORMAL)) return; - if (!p->se.on_rq) + if (!p->on_rq) ttwu_activate(rq, p, ENQUEUE_WAKEUP); ttwu_post_activation(p, rq, 0); @@ -2620,19 +2619,21 @@ int wake_up_state(struct task_struct *p, unsigned int state) */ static void __sched_fork(struct task_struct *p) { + p->on_rq = 0; + + p->se.on_rq = 0; p->se.exec_start = 0; p->se.sum_exec_runtime = 0; p->se.prev_sum_exec_runtime = 0; p->se.nr_migrations = 0; p->se.vruntime = 0; + INIT_LIST_HEAD(&p->se.group_node); #ifdef CONFIG_SCHEDSTATS memset(&p->se.statistics, 0, sizeof(p->se.statistics)); #endif INIT_LIST_HEAD(&p->rt.run_list); - p->se.on_rq = 0; - INIT_LIST_HEAD(&p->se.group_node); #ifdef CONFIG_PREEMPT_NOTIFIERS INIT_HLIST_HEAD(&p->preempt_notifiers); @@ -2750,6 +2751,7 @@ void wake_up_new_task(struct task_struct *p, unsigned long clone_flags) rq = task_rq_lock(p, &flags); activate_task(rq, p, 0); + p->on_rq = 1; trace_sched_wakeup_new(p, true); check_preempt_curr(rq, p, WF_FORK); #ifdef CONFIG_SMP @@ -4051,7 +4053,7 @@ static inline void schedule_debug(struct task_struct *prev) static void put_prev_task(struct rq *rq, struct task_struct *prev) { - if (prev->se.on_rq) + if (prev->on_rq) update_rq_clock(rq); prev->sched_class->put_prev_task(rq, prev); } @@ -4126,7 +4128,9 @@ need_resched: if (to_wakeup) try_to_wake_up_local(to_wakeup); } + deactivate_task(rq, prev, DEQUEUE_SLEEP); + prev->on_rq = 0; /* * If we are going to sleep and we have plugged IO queued, make @@ -4695,7 +4699,7 @@ void rt_mutex_setprio(struct task_struct *p, int prio) trace_sched_pi_setprio(p, prio); oldprio = p->prio; prev_class = p->sched_class; - on_rq = p->se.on_rq; + on_rq = p->on_rq; running = task_current(rq, p); if (on_rq) dequeue_task(rq, p, 0); @@ -4743,7 +4747,7 @@ void set_user_nice(struct task_struct *p, long nice) p->static_prio = NICE_TO_PRIO(nice); goto out_unlock; } - on_rq = p->se.on_rq; + on_rq = p->on_rq; if (on_rq) dequeue_task(rq, p, 0); @@ -4877,8 +4881,6 @@ static struct task_struct *find_process_by_pid(pid_t pid) static void __setscheduler(struct rq *rq, struct task_struct *p, int policy, int prio) { - BUG_ON(p->se.on_rq); - p->policy = policy; p->rt_priority = prio; p->normal_prio = normal_prio(p); @@ -5044,7 +5046,7 @@ recheck: raw_spin_unlock_irqrestore(&p->pi_lock, flags); goto recheck; } - on_rq = p->se.on_rq; + on_rq = p->on_rq; running = task_current(rq, p); if (on_rq) deactivate_task(rq, p, 0); @@ -5965,7 +5967,7 @@ static int __migrate_task(struct task_struct *p, int src_cpu, int dest_cpu) * If we're not on a rq, the next wake-up will ensure we're * placed properly. */ - if (p->se.on_rq) { + if (p->on_rq) { deactivate_task(rq_src, p, 0); set_task_cpu(p, dest_cpu); activate_task(rq_dest, p, 0); @@ -8339,7 +8341,7 @@ static void normalize_task(struct rq *rq, struct task_struct *p) int old_prio = p->prio; int on_rq; - on_rq = p->se.on_rq; + on_rq = p->on_rq; if (on_rq) deactivate_task(rq, p, 0); __setscheduler(rq, p, SCHED_NORMAL, 0); @@ -8682,7 +8684,7 @@ void sched_move_task(struct task_struct *tsk) rq = task_rq_lock(tsk, &flags); running = task_current(rq, tsk); - on_rq = tsk->se.on_rq; + on_rq = tsk->on_rq; if (on_rq) dequeue_task(rq, tsk, 0); diff --git a/kernel/sched_debug.c b/kernel/sched_debug.c index 7bacd83..3669bec6 100644 --- a/kernel/sched_debug.c +++ b/kernel/sched_debug.c @@ -152,7 +152,7 @@ static void print_rq(struct seq_file *m, struct rq *rq, int rq_cpu) read_lock_irqsave(&tasklist_lock, flags); do_each_thread(g, p) { - if (!p->se.on_rq || task_cpu(p) != rq_cpu) + if (!p->on_rq || task_cpu(p) != rq_cpu) continue; print_task(m, rq, p); diff --git a/kernel/sched_rt.c b/kernel/sched_rt.c index e7cebdc..9ca4f5f 100644 --- a/kernel/sched_rt.c +++ b/kernel/sched_rt.c @@ -1136,7 +1136,7 @@ static void put_prev_task_rt(struct rq *rq, struct task_struct *p) * The previous task needs to be made eligible for pushing * if it is still active */ - if (p->se.on_rq && p->rt.nr_cpus_allowed > 1) + if (on_rt_rq(&p->rt) && p->rt.nr_cpus_allowed > 1) enqueue_pushable_task(rq, p); } @@ -1287,7 +1287,7 @@ static struct rq *find_lock_lowest_rq(struct task_struct *task, struct rq *rq) !cpumask_test_cpu(lowest_rq->cpu, &task->cpus_allowed) || task_running(rq, task) || - !task->se.on_rq)) { + !task->on_rq)) { raw_spin_unlock(&lowest_rq->lock); lowest_rq = NULL; @@ -1321,7 +1321,7 @@ static struct task_struct *pick_next_pushable_task(struct rq *rq) BUG_ON(task_current(rq, p)); BUG_ON(p->rt.nr_cpus_allowed <= 1); - BUG_ON(!p->se.on_rq); + BUG_ON(!p->on_rq); BUG_ON(!rt_task(p)); return p; @@ -1467,7 +1467,7 @@ static int pull_rt_task(struct rq *this_rq) */ if (p && (p->prio < this_rq->rt.highest_prio.curr)) { WARN_ON(p == src_rq->curr); - WARN_ON(!p->se.on_rq); + WARN_ON(!p->on_rq); /* * There's a chance that p is higher in priority @@ -1538,7 +1538,7 @@ static void set_cpus_allowed_rt(struct task_struct *p, * Update the migration status of the RQ if we have an RT task * which is running AND changing its weight value. */ - if (p->se.on_rq && (weight != p->rt.nr_cpus_allowed)) { + if (p->on_rq && (weight != p->rt.nr_cpus_allowed)) { struct rq *rq = task_rq(p); if (!task_current(rq, p)) { @@ -1608,7 +1608,7 @@ static void switched_from_rt(struct rq *rq, struct task_struct *p) * we may need to handle the pulling of RT tasks * now. */ - if (p->se.on_rq && !rq->rt.rt_nr_running) + if (p->on_rq && !rq->rt.rt_nr_running) pull_rt_task(rq); } @@ -1638,7 +1638,7 @@ static void switched_to_rt(struct rq *rq, struct task_struct *p) * If that current running task is also an RT task * then see if we can move to another run queue. */ - if (p->se.on_rq && rq->curr != p) { + if (p->on_rq && rq->curr != p) { #ifdef CONFIG_SMP if (rq->rt.overloaded && push_rt_task(rq) && /* Don't resched if we changed runqueues */ @@ -1657,7 +1657,7 @@ static void switched_to_rt(struct rq *rq, struct task_struct *p) static void prio_changed_rt(struct rq *rq, struct task_struct *p, int oldprio) { - if (!p->se.on_rq) + if (!p->on_rq) return; if (rq->curr == p) { diff --git a/kernel/sched_stoptask.c b/kernel/sched_stoptask.c index 1ba2bd4..f607de4 100644 --- a/kernel/sched_stoptask.c +++ b/kernel/sched_stoptask.c @@ -26,7 +26,7 @@ static struct task_struct *pick_next_task_stop(struct rq *rq) { struct task_struct *stop = rq->stop; - if (stop && stop->se.on_rq) + if (stop && stop->on_rq) return stop; return NULL; -- cgit v0.10.2 From 013fdb8086acaae5f8eb96f9ad48fcd98882ac46 Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Tue, 5 Apr 2011 17:23:45 +0200 Subject: sched: Serialize p->cpus_allowed and ttwu() using p->pi_lock Currently p->pi_lock already serializes p->sched_class, also put p->cpus_allowed and try_to_wake_up() under it, this prepares the way to do the first part of ttwu() without holding rq->lock. By having p->sched_class and p->cpus_allowed serialized by p->pi_lock, we prepare the way to call select_task_rq() without holding rq->lock. Reviewed-by: Frank Rowand Signed-off-by: Peter Zijlstra Cc: Mike Galbraith Cc: Nick Piggin Cc: Linus Torvalds Cc: Andrew Morton Link: http://lkml.kernel.org/r/20110405152728.990364093@chello.nl Signed-off-by: Ingo Molnar diff --git a/kernel/sched.c b/kernel/sched.c index dece28e..d398f2f 100644 --- a/kernel/sched.c +++ b/kernel/sched.c @@ -2340,7 +2340,7 @@ EXPORT_SYMBOL_GPL(kick_process); #ifdef CONFIG_SMP /* - * ->cpus_allowed is protected by either TASK_WAKING or rq->lock held. + * ->cpus_allowed is protected by both rq->lock and p->pi_lock */ static int select_fallback_rq(int cpu, struct task_struct *p) { @@ -2373,7 +2373,7 @@ static int select_fallback_rq(int cpu, struct task_struct *p) } /* - * The caller (fork, wakeup) owns TASK_WAKING, ->cpus_allowed is stable. + * The caller (fork, wakeup) owns p->pi_lock, ->cpus_allowed is stable. */ static inline int select_task_rq(struct rq *rq, struct task_struct *p, int sd_flags, int wake_flags) @@ -2499,7 +2499,8 @@ static int try_to_wake_up(struct task_struct *p, unsigned int state, this_cpu = get_cpu(); smp_wmb(); - rq = task_rq_lock(p, &flags); + raw_spin_lock_irqsave(&p->pi_lock, flags); + rq = __task_rq_lock(p); if (!(p->state & state)) goto out; @@ -2557,7 +2558,8 @@ out_running: ttwu_stat(rq, p, cpu, wake_flags); success = 1; out: - task_rq_unlock(rq, &flags); + __task_rq_unlock(rq); + raw_spin_unlock_irqrestore(&p->pi_lock, flags); put_cpu(); return success; @@ -4694,6 +4696,8 @@ void rt_mutex_setprio(struct task_struct *p, int prio) BUG_ON(prio < 0 || prio > MAX_PRIO); + lockdep_assert_held(&p->pi_lock); + rq = task_rq_lock(p, &flags); trace_sched_pi_setprio(p, prio); @@ -5317,7 +5321,6 @@ long sched_getaffinity(pid_t pid, struct cpumask *mask) { struct task_struct *p; unsigned long flags; - struct rq *rq; int retval; get_online_cpus(); @@ -5332,9 +5335,9 @@ long sched_getaffinity(pid_t pid, struct cpumask *mask) if (retval) goto out_unlock; - rq = task_rq_lock(p, &flags); + raw_spin_lock_irqsave(&p->pi_lock, flags); cpumask_and(mask, &p->cpus_allowed, cpu_online_mask); - task_rq_unlock(rq, &flags); + raw_spin_unlock_irqrestore(&p->pi_lock, flags); out_unlock: rcu_read_unlock(); @@ -5882,18 +5885,8 @@ int set_cpus_allowed_ptr(struct task_struct *p, const struct cpumask *new_mask) unsigned int dest_cpu; int ret = 0; - /* - * Serialize against TASK_WAKING so that ttwu() and wunt() can - * drop the rq->lock and still rely on ->cpus_allowed. - */ -again: - while (task_is_waking(p)) - cpu_relax(); - rq = task_rq_lock(p, &flags); - if (task_is_waking(p)) { - task_rq_unlock(rq, &flags); - goto again; - } + raw_spin_lock_irqsave(&p->pi_lock, flags); + rq = __task_rq_lock(p); if (!cpumask_intersects(new_mask, cpu_active_mask)) { ret = -EINVAL; @@ -5921,13 +5914,15 @@ again: if (migrate_task(p, rq)) { struct migration_arg arg = { p, dest_cpu }; /* Need help from migration thread: drop lock and wait. */ - task_rq_unlock(rq, &flags); + __task_rq_unlock(rq); + raw_spin_unlock_irqrestore(&p->pi_lock, flags); stop_one_cpu(cpu_of(rq), migration_cpu_stop, &arg); tlb_migrate_finish(p->mm); return 0; } out: - task_rq_unlock(rq, &flags); + __task_rq_unlock(rq); + raw_spin_unlock_irqrestore(&p->pi_lock, flags); return ret; } -- cgit v0.10.2 From 7608dec2ce2004c234339bef8c8074e5e601d0e9 Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Tue, 5 Apr 2011 17:23:46 +0200 Subject: sched: Drop the rq argument to sched_class::select_task_rq() In preparation of calling select_task_rq() without rq->lock held, drop the dependency on the rq argument. Reviewed-by: Frank Rowand Signed-off-by: Peter Zijlstra Cc: Mike Galbraith Cc: Nick Piggin Cc: Linus Torvalds Cc: Andrew Morton Link: http://lkml.kernel.org/r/20110405152729.031077745@chello.nl Signed-off-by: Ingo Molnar diff --git a/include/linux/sched.h b/include/linux/sched.h index b33a700..ff4e2f9 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h @@ -1067,8 +1067,7 @@ struct sched_class { void (*put_prev_task) (struct rq *rq, struct task_struct *p); #ifdef CONFIG_SMP - int (*select_task_rq)(struct rq *rq, struct task_struct *p, - int sd_flag, int flags); + int (*select_task_rq)(struct task_struct *p, int sd_flag, int flags); void (*pre_schedule) (struct rq *this_rq, struct task_struct *task); void (*post_schedule) (struct rq *this_rq); diff --git a/kernel/sched.c b/kernel/sched.c index d398f2f..d4b815d 100644 --- a/kernel/sched.c +++ b/kernel/sched.c @@ -2195,13 +2195,15 @@ static int migration_cpu_stop(void *data); * The task's runqueue lock must be held. * Returns true if you have to wait for migration thread. */ -static bool migrate_task(struct task_struct *p, struct rq *rq) +static bool need_migrate_task(struct task_struct *p) { /* * If the task is not on a runqueue (and not running), then * the next wake-up will properly place the task. */ - return p->on_rq || task_running(rq, p); + bool running = p->on_rq || p->on_cpu; + smp_rmb(); /* finish_lock_switch() */ + return running; } /* @@ -2376,9 +2378,9 @@ static int select_fallback_rq(int cpu, struct task_struct *p) * The caller (fork, wakeup) owns p->pi_lock, ->cpus_allowed is stable. */ static inline -int select_task_rq(struct rq *rq, struct task_struct *p, int sd_flags, int wake_flags) +int select_task_rq(struct task_struct *p, int sd_flags, int wake_flags) { - int cpu = p->sched_class->select_task_rq(rq, p, sd_flags, wake_flags); + int cpu = p->sched_class->select_task_rq(p, sd_flags, wake_flags); /* * In order not to call set_task_cpu() on a blocking task we need @@ -2533,7 +2535,7 @@ static int try_to_wake_up(struct task_struct *p, unsigned int state, en_flags |= ENQUEUE_WAKING; } - cpu = select_task_rq(rq, p, SD_BALANCE_WAKE, wake_flags); + cpu = select_task_rq(p, SD_BALANCE_WAKE, wake_flags); if (cpu != orig_cpu) set_task_cpu(p, cpu); __task_rq_unlock(rq); @@ -2744,7 +2746,7 @@ void wake_up_new_task(struct task_struct *p, unsigned long clone_flags) * We set TASK_WAKING so that select_task_rq() can drop rq->lock * without people poking at ->cpus_allowed. */ - cpu = select_task_rq(rq, p, SD_BALANCE_FORK, 0); + cpu = select_task_rq(p, SD_BALANCE_FORK, 0); set_task_cpu(p, cpu); p->state = TASK_RUNNING; @@ -3474,7 +3476,7 @@ void sched_exec(void) int dest_cpu; rq = task_rq_lock(p, &flags); - dest_cpu = p->sched_class->select_task_rq(rq, p, SD_BALANCE_EXEC, 0); + dest_cpu = p->sched_class->select_task_rq(p, SD_BALANCE_EXEC, 0); if (dest_cpu == smp_processor_id()) goto unlock; @@ -3482,7 +3484,7 @@ void sched_exec(void) * select_task_rq() can race against ->cpus_allowed */ if (cpumask_test_cpu(dest_cpu, &p->cpus_allowed) && - likely(cpu_active(dest_cpu)) && migrate_task(p, rq)) { + likely(cpu_active(dest_cpu)) && need_migrate_task(p)) { struct migration_arg arg = { p, dest_cpu }; task_rq_unlock(rq, &flags); @@ -5911,7 +5913,7 @@ int set_cpus_allowed_ptr(struct task_struct *p, const struct cpumask *new_mask) goto out; dest_cpu = cpumask_any_and(cpu_active_mask, new_mask); - if (migrate_task(p, rq)) { + if (need_migrate_task(p)) { struct migration_arg arg = { p, dest_cpu }; /* Need help from migration thread: drop lock and wait. */ __task_rq_unlock(rq); diff --git a/kernel/sched_fair.c b/kernel/sched_fair.c index 4ee50f0..96b2c95 100644 --- a/kernel/sched_fair.c +++ b/kernel/sched_fair.c @@ -1657,7 +1657,7 @@ static int select_idle_sibling(struct task_struct *p, int target) * preempt must be disabled. */ static int -select_task_rq_fair(struct rq *rq, struct task_struct *p, int sd_flag, int wake_flags) +select_task_rq_fair(struct task_struct *p, int sd_flag, int wake_flags) { struct sched_domain *tmp, *affine_sd = NULL, *sd = NULL; int cpu = smp_processor_id(); diff --git a/kernel/sched_idletask.c b/kernel/sched_idletask.c index a776a63..0a51882 100644 --- a/kernel/sched_idletask.c +++ b/kernel/sched_idletask.c @@ -7,7 +7,7 @@ #ifdef CONFIG_SMP static int -select_task_rq_idle(struct rq *rq, struct task_struct *p, int sd_flag, int flags) +select_task_rq_idle(struct task_struct *p, int sd_flag, int flags) { return task_cpu(p); /* IDLE tasks as never migrated */ } diff --git a/kernel/sched_rt.c b/kernel/sched_rt.c index 9ca4f5f..19ecb31 100644 --- a/kernel/sched_rt.c +++ b/kernel/sched_rt.c @@ -977,13 +977,23 @@ static void yield_task_rt(struct rq *rq) static int find_lowest_rq(struct task_struct *task); static int -select_task_rq_rt(struct rq *rq, struct task_struct *p, int sd_flag, int flags) +select_task_rq_rt(struct task_struct *p, int sd_flag, int flags) { + struct task_struct *curr; + struct rq *rq; + int cpu; + if (sd_flag != SD_BALANCE_WAKE) return smp_processor_id(); + cpu = task_cpu(p); + rq = cpu_rq(cpu); + + rcu_read_lock(); + curr = ACCESS_ONCE(rq->curr); /* unlocked access */ + /* - * If the current task is an RT task, then + * If the current task on @p's runqueue is an RT task, then * try to see if we can wake this RT task up on another * runqueue. Otherwise simply start this RT task * on its current runqueue. @@ -997,21 +1007,25 @@ select_task_rq_rt(struct rq *rq, struct task_struct *p, int sd_flag, int flags) * lock? * * For equal prio tasks, we just let the scheduler sort it out. + * + * Otherwise, just let it ride on the affined RQ and the + * post-schedule router will push the preempted task away + * + * This test is optimistic, if we get it wrong the load-balancer + * will have to sort it out. */ - if (unlikely(rt_task(rq->curr)) && - (rq->curr->rt.nr_cpus_allowed < 2 || - rq->curr->prio < p->prio) && + if (curr && unlikely(rt_task(curr)) && + (curr->rt.nr_cpus_allowed < 2 || + curr->prio < p->prio) && (p->rt.nr_cpus_allowed > 1)) { - int cpu = find_lowest_rq(p); + int target = find_lowest_rq(p); - return (cpu == -1) ? task_cpu(p) : cpu; + if (target != -1) + cpu = target; } + rcu_read_unlock(); - /* - * Otherwise, just let it ride on the affined RQ and the - * post-schedule router will push the preempted task away - */ - return task_cpu(p); + return cpu; } static void check_preempt_equal_prio(struct rq *rq, struct task_struct *p) diff --git a/kernel/sched_stoptask.c b/kernel/sched_stoptask.c index f607de4..6f43763 100644 --- a/kernel/sched_stoptask.c +++ b/kernel/sched_stoptask.c @@ -9,8 +9,7 @@ #ifdef CONFIG_SMP static int -select_task_rq_stop(struct rq *rq, struct task_struct *p, - int sd_flag, int flags) +select_task_rq_stop(struct task_struct *p, int sd_flag, int flags) { return task_cpu(p); /* stop tasks as never migrate */ } -- cgit v0.10.2 From 74f8e4b2335de45485b8d5b31a504747f13c8070 Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Tue, 5 Apr 2011 17:23:47 +0200 Subject: sched: Remove rq argument to sched_class::task_waking() In preparation of calling this without rq->lock held, remove the dependency on the rq argument. Reviewed-by: Frank Rowand Signed-off-by: Peter Zijlstra Cc: Mike Galbraith Cc: Nick Piggin Cc: Linus Torvalds Cc: Andrew Morton Link: http://lkml.kernel.org/r/20110405152729.071474242@chello.nl Signed-off-by: Ingo Molnar diff --git a/include/linux/sched.h b/include/linux/sched.h index ff4e2f9..7f5732f 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h @@ -1048,8 +1048,12 @@ struct sched_domain; #define WF_FORK 0x02 /* child wakeup after fork */ #define ENQUEUE_WAKEUP 1 -#define ENQUEUE_WAKING 2 -#define ENQUEUE_HEAD 4 +#define ENQUEUE_HEAD 2 +#ifdef CONFIG_SMP +#define ENQUEUE_WAKING 4 /* sched_class::task_waking was called */ +#else +#define ENQUEUE_WAKING 0 +#endif #define DEQUEUE_SLEEP 1 @@ -1071,7 +1075,7 @@ struct sched_class { void (*pre_schedule) (struct rq *this_rq, struct task_struct *task); void (*post_schedule) (struct rq *this_rq); - void (*task_waking) (struct rq *this_rq, struct task_struct *task); + void (*task_waking) (struct task_struct *task); void (*task_woken) (struct rq *this_rq, struct task_struct *task); void (*set_cpus_allowed)(struct task_struct *p, diff --git a/kernel/sched.c b/kernel/sched.c index d4b815d..46f42ca 100644 --- a/kernel/sched.c +++ b/kernel/sched.c @@ -2531,7 +2531,7 @@ static int try_to_wake_up(struct task_struct *p, unsigned int state, p->state = TASK_WAKING; if (p->sched_class->task_waking) { - p->sched_class->task_waking(rq, p); + p->sched_class->task_waking(p); en_flags |= ENQUEUE_WAKING; } diff --git a/kernel/sched_fair.c b/kernel/sched_fair.c index 96b2c95..ad4c414f 100644 --- a/kernel/sched_fair.c +++ b/kernel/sched_fair.c @@ -1372,11 +1372,13 @@ static void dequeue_task_fair(struct rq *rq, struct task_struct *p, int flags) #ifdef CONFIG_SMP -static void task_waking_fair(struct rq *rq, struct task_struct *p) +static void task_waking_fair(struct task_struct *p) { struct sched_entity *se = &p->se; struct cfs_rq *cfs_rq = cfs_rq_of(se); + lockdep_assert_held(&task_rq(p)->lock); + se->vruntime -= cfs_rq->min_vruntime; } -- cgit v0.10.2 From 3fe1698b7fe05aeb063564e71e40d09f28d8e80c Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Tue, 5 Apr 2011 17:23:48 +0200 Subject: sched: Deal with non-atomic min_vruntime reads on 32bits In order to avoid reading partial updated min_vruntime values on 32bit implement a seqcount like solution. Reviewed-by: Frank Rowand Signed-off-by: Peter Zijlstra Cc: Mike Galbraith Cc: Nick Piggin Cc: Linus Torvalds Cc: Andrew Morton Link: http://lkml.kernel.org/r/20110405152729.111378493@chello.nl Signed-off-by: Ingo Molnar diff --git a/kernel/sched.c b/kernel/sched.c index 46f42ca..7a5eb26 100644 --- a/kernel/sched.c +++ b/kernel/sched.c @@ -312,6 +312,9 @@ struct cfs_rq { u64 exec_clock; u64 min_vruntime; +#ifndef CONFIG_64BIT + u64 min_vruntime_copy; +#endif struct rb_root tasks_timeline; struct rb_node *rb_leftmost; diff --git a/kernel/sched_fair.c b/kernel/sched_fair.c index ad4c414f..054cebb 100644 --- a/kernel/sched_fair.c +++ b/kernel/sched_fair.c @@ -358,6 +358,10 @@ static void update_min_vruntime(struct cfs_rq *cfs_rq) } cfs_rq->min_vruntime = max_vruntime(cfs_rq->min_vruntime, vruntime); +#ifndef CONFIG_64BIT + smp_wmb(); + cfs_rq->min_vruntime_copy = cfs_rq->min_vruntime; +#endif } /* @@ -1376,10 +1380,21 @@ static void task_waking_fair(struct task_struct *p) { struct sched_entity *se = &p->se; struct cfs_rq *cfs_rq = cfs_rq_of(se); + u64 min_vruntime; - lockdep_assert_held(&task_rq(p)->lock); +#ifndef CONFIG_64BIT + u64 min_vruntime_copy; - se->vruntime -= cfs_rq->min_vruntime; + do { + min_vruntime_copy = cfs_rq->min_vruntime_copy; + smp_rmb(); + min_vruntime = cfs_rq->min_vruntime; + } while (min_vruntime != min_vruntime_copy); +#else + min_vruntime = cfs_rq->min_vruntime; +#endif + + se->vruntime -= min_vruntime; } #ifdef CONFIG_FAIR_GROUP_SCHED -- cgit v0.10.2 From a8e4f2eaecc9bfa4954adf79a04f4f22fddd829c Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Tue, 5 Apr 2011 17:23:49 +0200 Subject: sched: Delay task_contributes_to_load() In prepratation of having to call task_contributes_to_load() without holding rq->lock, we need to store the result until we do and can update the rq accounting accordingly. Reviewed-by: Frank Rowand Cc: Mike Galbraith Cc: Nick Piggin Cc: Linus Torvalds Cc: Andrew Morton Signed-off-by: Ingo Molnar Signed-off-by: Peter Zijlstra Link: http://lkml.kernel.org/r/20110405152729.151523907@chello.nl diff --git a/include/linux/sched.h b/include/linux/sched.h index 7f5732f..25c5031 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h @@ -1273,6 +1273,7 @@ struct task_struct { /* Revert to default priority/policy when forking */ unsigned sched_reset_on_fork:1; + unsigned sched_contributes_to_load:1; pid_t pid; pid_t tgid; diff --git a/kernel/sched.c b/kernel/sched.c index 7a5eb26..fd32b78 100644 --- a/kernel/sched.c +++ b/kernel/sched.c @@ -2519,18 +2519,7 @@ static int try_to_wake_up(struct task_struct *p, unsigned int state, if (unlikely(task_running(rq, p))) goto out_activate; - /* - * In order to handle concurrent wakeups and release the rq->lock - * we put the task in TASK_WAKING state. - * - * First fix up the nr_uninterruptible count: - */ - if (task_contributes_to_load(p)) { - if (likely(cpu_online(orig_cpu))) - rq->nr_uninterruptible--; - else - this_rq()->nr_uninterruptible--; - } + p->sched_contributes_to_load = !!task_contributes_to_load(p); p->state = TASK_WAKING; if (p->sched_class->task_waking) { @@ -2555,6 +2544,9 @@ static int try_to_wake_up(struct task_struct *p, unsigned int state, WARN_ON(task_cpu(p) != cpu); WARN_ON(p->state != TASK_WAKING); + if (p->sched_contributes_to_load) + rq->nr_uninterruptible--; + out_activate: #endif /* CONFIG_SMP */ ttwu_activate(rq, p, en_flags); -- cgit v0.10.2 From 2acca55ed98ad9b9aa25e7e587ebe306c0313dc7 Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Tue, 5 Apr 2011 17:23:50 +0200 Subject: sched: Also serialize ttwu_local() with p->pi_lock Since we now serialize ttwu() using p->pi_lock, we also need to serialize ttwu_local() using that, otherwise, once we drop the rq->lock from ttwu() it can race with ttwu_local(). Reviewed-by: Frank Rowand Cc: Mike Galbraith Cc: Nick Piggin Cc: Linus Torvalds Cc: Andrew Morton Signed-off-by: Ingo Molnar Signed-off-by: Peter Zijlstra Link: http://lkml.kernel.org/r/20110405152729.192366907@chello.nl diff --git a/kernel/sched.c b/kernel/sched.c index fd32b78..6b269b7 100644 --- a/kernel/sched.c +++ b/kernel/sched.c @@ -2566,9 +2566,9 @@ out: * try_to_wake_up_local - try to wake up a local task with rq lock held * @p: the thread to be awakened * - * Put @p on the run-queue if it's not already there. The caller must + * Put @p on the run-queue if it's not already there. The caller must * ensure that this_rq() is locked, @p is bound to this_rq() and not - * the current task. this_rq() stays locked over invocation. + * the current task. */ static void try_to_wake_up_local(struct task_struct *p) { @@ -2578,14 +2578,22 @@ static void try_to_wake_up_local(struct task_struct *p) BUG_ON(p == current); lockdep_assert_held(&rq->lock); + if (!raw_spin_trylock(&p->pi_lock)) { + raw_spin_unlock(&rq->lock); + raw_spin_lock(&p->pi_lock); + raw_spin_lock(&rq->lock); + } + if (!(p->state & TASK_NORMAL)) - return; + goto out; if (!p->on_rq) ttwu_activate(rq, p, ENQUEUE_WAKEUP); ttwu_post_activation(p, rq, 0); ttwu_stat(rq, p, smp_processor_id(), 0); +out: + raw_spin_unlock(&p->pi_lock); } /** @@ -4114,11 +4122,13 @@ need_resched: if (unlikely(signal_pending_state(prev->state, prev))) { prev->state = TASK_RUNNING; } else { + deactivate_task(rq, prev, DEQUEUE_SLEEP); + prev->on_rq = 0; + /* - * If a worker is going to sleep, notify and - * ask workqueue whether it wants to wake up a - * task to maintain concurrency. If so, wake - * up the task. + * If a worker went to sleep, notify and ask workqueue + * whether it wants to wake up a task to maintain + * concurrency. */ if (prev->flags & PF_WQ_WORKER) { struct task_struct *to_wakeup; @@ -4128,12 +4138,9 @@ need_resched: try_to_wake_up_local(to_wakeup); } - deactivate_task(rq, prev, DEQUEUE_SLEEP); - prev->on_rq = 0; - /* - * If we are going to sleep and we have plugged IO queued, make - * sure to submit it to avoid deadlocks. + * If we are going to sleep and we have plugged IO + * queued, make sure to submit it to avoid deadlocks. */ if (blk_needs_flush_plug(prev)) { raw_spin_unlock(&rq->lock); -- cgit v0.10.2 From 0122ec5b02f766c355b3168df53a6c038a24fa0d Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Tue, 5 Apr 2011 17:23:51 +0200 Subject: sched: Add p->pi_lock to task_rq_lock() In order to be able to call set_task_cpu() while either holding p->pi_lock or task_rq(p)->lock we need to hold both locks in order to stabilize task_rq(). This makes task_rq_lock() acquire both locks, and have __task_rq_lock() validate that p->pi_lock is held. This increases the locking overhead for most scheduler syscalls but allows reduction of rq->lock contention for some scheduler hot paths (ttwu). Reviewed-by: Frank Rowand Signed-off-by: Peter Zijlstra Cc: Mike Galbraith Cc: Nick Piggin Cc: Linus Torvalds Cc: Andrew Morton Link: http://lkml.kernel.org/r/20110405152729.232781355@chello.nl Signed-off-by: Ingo Molnar diff --git a/kernel/sched.c b/kernel/sched.c index 6b269b7..f155127 100644 --- a/kernel/sched.c +++ b/kernel/sched.c @@ -599,7 +599,7 @@ static inline int cpu_of(struct rq *rq) * Return the group to which this tasks belongs. * * We use task_subsys_state_check() and extend the RCU verification - * with lockdep_is_held(&task_rq(p)->lock) because cpu_cgroup_attach() + * with lockdep_is_held(&p->pi_lock) because cpu_cgroup_attach() * holds that lock for each task it moves into the cgroup. Therefore * by holding that lock, we pin the task to the current cgroup. */ @@ -609,7 +609,7 @@ static inline struct task_group *task_group(struct task_struct *p) struct cgroup_subsys_state *css; css = task_subsys_state_check(p, cpu_cgroup_subsys_id, - lockdep_is_held(&task_rq(p)->lock)); + lockdep_is_held(&p->pi_lock)); tg = container_of(css, struct task_group, css); return autogroup_task_group(p, tg); @@ -924,23 +924,15 @@ static inline void finish_lock_switch(struct rq *rq, struct task_struct *prev) #endif /* __ARCH_WANT_UNLOCKED_CTXSW */ /* - * Check whether the task is waking, we use this to synchronize ->cpus_allowed - * against ttwu(). - */ -static inline int task_is_waking(struct task_struct *p) -{ - return unlikely(p->state == TASK_WAKING); -} - -/* - * __task_rq_lock - lock the runqueue a given task resides on. - * Must be called interrupts disabled. + * __task_rq_lock - lock the rq @p resides on. */ static inline struct rq *__task_rq_lock(struct task_struct *p) __acquires(rq->lock) { struct rq *rq; + lockdep_assert_held(&p->pi_lock); + for (;;) { rq = task_rq(p); raw_spin_lock(&rq->lock); @@ -951,22 +943,22 @@ static inline struct rq *__task_rq_lock(struct task_struct *p) } /* - * task_rq_lock - lock the runqueue a given task resides on and disable - * interrupts. Note the ordering: we can safely lookup the task_rq without - * explicitly disabling preemption. + * task_rq_lock - lock p->pi_lock and lock the rq @p resides on. */ static struct rq *task_rq_lock(struct task_struct *p, unsigned long *flags) + __acquires(p->pi_lock) __acquires(rq->lock) { struct rq *rq; for (;;) { - local_irq_save(*flags); + raw_spin_lock_irqsave(&p->pi_lock, *flags); rq = task_rq(p); raw_spin_lock(&rq->lock); if (likely(rq == task_rq(p))) return rq; - raw_spin_unlock_irqrestore(&rq->lock, *flags); + raw_spin_unlock(&rq->lock); + raw_spin_unlock_irqrestore(&p->pi_lock, *flags); } } @@ -976,10 +968,13 @@ static void __task_rq_unlock(struct rq *rq) raw_spin_unlock(&rq->lock); } -static inline void task_rq_unlock(struct rq *rq, unsigned long *flags) +static inline void +task_rq_unlock(struct rq *rq, struct task_struct *p, unsigned long *flags) __releases(rq->lock) + __releases(p->pi_lock) { - raw_spin_unlock_irqrestore(&rq->lock, *flags); + raw_spin_unlock(&rq->lock); + raw_spin_unlock_irqrestore(&p->pi_lock, *flags); } /* @@ -2175,6 +2170,11 @@ void set_task_cpu(struct task_struct *p, unsigned int new_cpu) */ WARN_ON_ONCE(p->state != TASK_RUNNING && p->state != TASK_WAKING && !(task_thread_info(p)->preempt_count & PREEMPT_ACTIVE)); + +#ifdef CONFIG_LOCKDEP + WARN_ON_ONCE(debug_locks && !(lockdep_is_held(&p->pi_lock) || + lockdep_is_held(&task_rq(p)->lock))); +#endif #endif trace_sched_migrate_task(p, new_cpu); @@ -2270,7 +2270,7 @@ unsigned long wait_task_inactive(struct task_struct *p, long match_state) ncsw = 0; if (!match_state || p->state == match_state) ncsw = p->nvcsw | LONG_MIN; /* sets MSB */ - task_rq_unlock(rq, &flags); + task_rq_unlock(rq, p, &flags); /* * If it changed from the expected state, bail out now. @@ -2652,6 +2652,7 @@ static void __sched_fork(struct task_struct *p) */ void sched_fork(struct task_struct *p, int clone_flags) { + unsigned long flags; int cpu = get_cpu(); __sched_fork(p); @@ -2702,9 +2703,9 @@ void sched_fork(struct task_struct *p, int clone_flags) * * Silence PROVE_RCU. */ - rcu_read_lock(); + raw_spin_lock_irqsave(&p->pi_lock, flags); set_task_cpu(p, cpu); - rcu_read_unlock(); + raw_spin_unlock_irqrestore(&p->pi_lock, flags); #if defined(CONFIG_SCHEDSTATS) || defined(CONFIG_TASK_DELAY_ACCT) if (likely(sched_info_on())) @@ -2753,7 +2754,7 @@ void wake_up_new_task(struct task_struct *p, unsigned long clone_flags) set_task_cpu(p, cpu); p->state = TASK_RUNNING; - task_rq_unlock(rq, &flags); + task_rq_unlock(rq, p, &flags); #endif rq = task_rq_lock(p, &flags); @@ -2765,7 +2766,7 @@ void wake_up_new_task(struct task_struct *p, unsigned long clone_flags) if (p->sched_class->task_woken) p->sched_class->task_woken(rq, p); #endif - task_rq_unlock(rq, &flags); + task_rq_unlock(rq, p, &flags); put_cpu(); } @@ -3490,12 +3491,12 @@ void sched_exec(void) likely(cpu_active(dest_cpu)) && need_migrate_task(p)) { struct migration_arg arg = { p, dest_cpu }; - task_rq_unlock(rq, &flags); + task_rq_unlock(rq, p, &flags); stop_one_cpu(cpu_of(rq), migration_cpu_stop, &arg); return; } unlock: - task_rq_unlock(rq, &flags); + task_rq_unlock(rq, p, &flags); } #endif @@ -3532,7 +3533,7 @@ unsigned long long task_delta_exec(struct task_struct *p) rq = task_rq_lock(p, &flags); ns = do_task_delta_exec(p, rq); - task_rq_unlock(rq, &flags); + task_rq_unlock(rq, p, &flags); return ns; } @@ -3550,7 +3551,7 @@ unsigned long long task_sched_runtime(struct task_struct *p) rq = task_rq_lock(p, &flags); ns = p->se.sum_exec_runtime + do_task_delta_exec(p, rq); - task_rq_unlock(rq, &flags); + task_rq_unlock(rq, p, &flags); return ns; } @@ -3574,7 +3575,7 @@ unsigned long long thread_group_sched_runtime(struct task_struct *p) rq = task_rq_lock(p, &flags); thread_group_cputime(p, &totals); ns = totals.sum_exec_runtime + do_task_delta_exec(p, rq); - task_rq_unlock(rq, &flags); + task_rq_unlock(rq, p, &flags); return ns; } @@ -4693,16 +4694,13 @@ EXPORT_SYMBOL(sleep_on_timeout); */ void rt_mutex_setprio(struct task_struct *p, int prio) { - unsigned long flags; int oldprio, on_rq, running; struct rq *rq; const struct sched_class *prev_class; BUG_ON(prio < 0 || prio > MAX_PRIO); - lockdep_assert_held(&p->pi_lock); - - rq = task_rq_lock(p, &flags); + rq = __task_rq_lock(p); trace_sched_pi_setprio(p, prio); oldprio = p->prio; @@ -4727,7 +4725,7 @@ void rt_mutex_setprio(struct task_struct *p, int prio) enqueue_task(rq, p, oldprio < prio ? ENQUEUE_HEAD : 0); check_class_changed(rq, p, prev_class, oldprio); - task_rq_unlock(rq, &flags); + __task_rq_unlock(rq); } #endif @@ -4775,7 +4773,7 @@ void set_user_nice(struct task_struct *p, long nice) resched_task(rq->curr); } out_unlock: - task_rq_unlock(rq, &flags); + task_rq_unlock(rq, p, &flags); } EXPORT_SYMBOL(set_user_nice); @@ -5003,20 +5001,17 @@ recheck: /* * make sure no PI-waiters arrive (or leave) while we are * changing the priority of the task: - */ - raw_spin_lock_irqsave(&p->pi_lock, flags); - /* + * * To be able to change p->policy safely, the appropriate * runqueue lock must be held. */ - rq = __task_rq_lock(p); + rq = task_rq_lock(p, &flags); /* * Changing the policy of the stop threads its a very bad idea */ if (p == rq->stop) { - __task_rq_unlock(rq); - raw_spin_unlock_irqrestore(&p->pi_lock, flags); + task_rq_unlock(rq, p, &flags); return -EINVAL; } @@ -5040,8 +5035,7 @@ recheck: if (rt_bandwidth_enabled() && rt_policy(policy) && task_group(p)->rt_bandwidth.rt_runtime == 0 && !task_group_is_autogroup(task_group(p))) { - __task_rq_unlock(rq); - raw_spin_unlock_irqrestore(&p->pi_lock, flags); + task_rq_unlock(rq, p, &flags); return -EPERM; } } @@ -5050,8 +5044,7 @@ recheck: /* recheck policy now with rq lock held */ if (unlikely(oldpolicy != -1 && oldpolicy != p->policy)) { policy = oldpolicy = -1; - __task_rq_unlock(rq); - raw_spin_unlock_irqrestore(&p->pi_lock, flags); + task_rq_unlock(rq, p, &flags); goto recheck; } on_rq = p->on_rq; @@ -5073,8 +5066,7 @@ recheck: activate_task(rq, p, 0); check_class_changed(rq, p, prev_class, oldprio); - __task_rq_unlock(rq); - raw_spin_unlock_irqrestore(&p->pi_lock, flags); + task_rq_unlock(rq, p, &flags); rt_mutex_adjust_pi(p); @@ -5666,7 +5658,7 @@ SYSCALL_DEFINE2(sched_rr_get_interval, pid_t, pid, rq = task_rq_lock(p, &flags); time_slice = p->sched_class->get_rr_interval(rq, p); - task_rq_unlock(rq, &flags); + task_rq_unlock(rq, p, &flags); rcu_read_unlock(); jiffies_to_timespec(time_slice, &t); @@ -5889,8 +5881,7 @@ int set_cpus_allowed_ptr(struct task_struct *p, const struct cpumask *new_mask) unsigned int dest_cpu; int ret = 0; - raw_spin_lock_irqsave(&p->pi_lock, flags); - rq = __task_rq_lock(p); + rq = task_rq_lock(p, &flags); if (!cpumask_intersects(new_mask, cpu_active_mask)) { ret = -EINVAL; @@ -5918,15 +5909,13 @@ int set_cpus_allowed_ptr(struct task_struct *p, const struct cpumask *new_mask) if (need_migrate_task(p)) { struct migration_arg arg = { p, dest_cpu }; /* Need help from migration thread: drop lock and wait. */ - __task_rq_unlock(rq); - raw_spin_unlock_irqrestore(&p->pi_lock, flags); + task_rq_unlock(rq, p, &flags); stop_one_cpu(cpu_of(rq), migration_cpu_stop, &arg); tlb_migrate_finish(p->mm); return 0; } out: - __task_rq_unlock(rq); - raw_spin_unlock_irqrestore(&p->pi_lock, flags); + task_rq_unlock(rq, p, &flags); return ret; } @@ -5954,6 +5943,7 @@ static int __migrate_task(struct task_struct *p, int src_cpu, int dest_cpu) rq_src = cpu_rq(src_cpu); rq_dest = cpu_rq(dest_cpu); + raw_spin_lock(&p->pi_lock); double_rq_lock(rq_src, rq_dest); /* Already moved. */ if (task_cpu(p) != src_cpu) @@ -5976,6 +5966,7 @@ done: ret = 1; fail: double_rq_unlock(rq_src, rq_dest); + raw_spin_unlock(&p->pi_lock); return ret; } @@ -8702,7 +8693,7 @@ void sched_move_task(struct task_struct *tsk) if (on_rq) enqueue_task(rq, tsk, 0); - task_rq_unlock(rq, &flags); + task_rq_unlock(rq, tsk, &flags); } #endif /* CONFIG_CGROUP_SCHED */ -- cgit v0.10.2 From ab2515c4b98f7bc4fa11cad9fa0f811d63a72a26 Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Tue, 5 Apr 2011 17:23:52 +0200 Subject: sched: Drop rq->lock from first part of wake_up_new_task() Since p->pi_lock now protects all things needed to call select_task_rq() avoid the double remote rq->lock acquisition and rely on p->pi_lock. Reviewed-by: Frank Rowand Signed-off-by: Peter Zijlstra Cc: Mike Galbraith Cc: Nick Piggin Cc: Linus Torvalds Cc: Andrew Morton Link: http://lkml.kernel.org/r/20110405152729.273362517@chello.nl Signed-off-by: Ingo Molnar diff --git a/kernel/sched.c b/kernel/sched.c index f155127..7c5494d 100644 --- a/kernel/sched.c +++ b/kernel/sched.c @@ -2736,28 +2736,18 @@ void wake_up_new_task(struct task_struct *p, unsigned long clone_flags) { unsigned long flags; struct rq *rq; - int cpu __maybe_unused = get_cpu(); + raw_spin_lock_irqsave(&p->pi_lock, flags); #ifdef CONFIG_SMP - rq = task_rq_lock(p, &flags); - p->state = TASK_WAKING; - /* * Fork balancing, do it here and not earlier because: * - cpus_allowed can change in the fork path * - any previously selected cpu might disappear through hotplug - * - * We set TASK_WAKING so that select_task_rq() can drop rq->lock - * without people poking at ->cpus_allowed. */ - cpu = select_task_rq(p, SD_BALANCE_FORK, 0); - set_task_cpu(p, cpu); - - p->state = TASK_RUNNING; - task_rq_unlock(rq, p, &flags); + set_task_cpu(p, select_task_rq(p, SD_BALANCE_FORK, 0)); #endif - rq = task_rq_lock(p, &flags); + rq = __task_rq_lock(p); activate_task(rq, p, 0); p->on_rq = 1; trace_sched_wakeup_new(p, true); @@ -2767,7 +2757,6 @@ void wake_up_new_task(struct task_struct *p, unsigned long clone_flags) p->sched_class->task_woken(rq, p); #endif task_rq_unlock(rq, p, &flags); - put_cpu(); } #ifdef CONFIG_PREEMPT_NOTIFIERS -- cgit v0.10.2 From 8f42ced974df7d5af2de4cf5ea21fe978c7e4478 Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Tue, 5 Apr 2011 17:23:53 +0200 Subject: sched: Drop rq->lock from sched_exec() Since we can now call select_task_rq() and set_task_cpu() with only p->pi_lock held, and sched_exec() load-balancing has always been optimistic, drop all rq->lock usage. Oleg also noted that need_migrate_task() will always be true for current, so don't bother calling that at all. Reviewed-by: Frank Rowand Signed-off-by: Peter Zijlstra Cc: Mike Galbraith Cc: Nick Piggin Cc: Linus Torvalds Cc: Andrew Morton Link: http://lkml.kernel.org/r/20110405152729.314204889@chello.nl Signed-off-by: Ingo Molnar diff --git a/kernel/sched.c b/kernel/sched.c index 7c5494d..1be1a09 100644 --- a/kernel/sched.c +++ b/kernel/sched.c @@ -3465,27 +3465,22 @@ void sched_exec(void) { struct task_struct *p = current; unsigned long flags; - struct rq *rq; int dest_cpu; - rq = task_rq_lock(p, &flags); + raw_spin_lock_irqsave(&p->pi_lock, flags); dest_cpu = p->sched_class->select_task_rq(p, SD_BALANCE_EXEC, 0); if (dest_cpu == smp_processor_id()) goto unlock; - /* - * select_task_rq() can race against ->cpus_allowed - */ - if (cpumask_test_cpu(dest_cpu, &p->cpus_allowed) && - likely(cpu_active(dest_cpu)) && need_migrate_task(p)) { + if (likely(cpu_active(dest_cpu))) { struct migration_arg arg = { p, dest_cpu }; - task_rq_unlock(rq, p, &flags); - stop_one_cpu(cpu_of(rq), migration_cpu_stop, &arg); + raw_spin_unlock_irqrestore(&p->pi_lock, flags); + stop_one_cpu(task_cpu(p), migration_cpu_stop, &arg); return; } unlock: - task_rq_unlock(rq, p, &flags); + raw_spin_unlock_irqrestore(&p->pi_lock, flags); } #endif -- cgit v0.10.2 From e4a52bcb9a18142d79e231b6733cabdbf2e67c1f Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Tue, 5 Apr 2011 17:23:54 +0200 Subject: sched: Remove rq->lock from the first half of ttwu() Currently ttwu() does two rq->lock acquisitions, once on the task's old rq, holding it over the p->state fiddling and load-balance pass. Then it drops the old rq->lock to acquire the new rq->lock. By having serialized ttwu(), p->sched_class, p->cpus_allowed with p->pi_lock, we can now drop the whole first rq->lock acquisition. The p->pi_lock serializing concurrent ttwu() calls protects p->state, which we will set to TASK_WAKING to bridge possible p->pi_lock to rq->lock gaps and serialize set_task_cpu() calls against task_rq_lock(). The p->pi_lock serialization of p->sched_class allows us to call scheduling class methods without holding the rq->lock, and the serialization of p->cpus_allowed allows us to do the load-balancing bits without races. Reviewed-by: Frank Rowand Cc: Mike Galbraith Cc: Nick Piggin Cc: Linus Torvalds Cc: Andrew Morton Signed-off-by: Ingo Molnar Signed-off-by: Peter Zijlstra Link: http://lkml.kernel.org/r/20110405152729.354401150@chello.nl diff --git a/kernel/sched.c b/kernel/sched.c index 1be1a09..871dd9e 100644 --- a/kernel/sched.c +++ b/kernel/sched.c @@ -2493,69 +2493,78 @@ ttwu_post_activation(struct task_struct *p, struct rq *rq, int wake_flags) * Returns %true if @p was woken up, %false if it was already running * or @state didn't match @p's state. */ -static int try_to_wake_up(struct task_struct *p, unsigned int state, - int wake_flags) +static int +try_to_wake_up(struct task_struct *p, unsigned int state, int wake_flags) { - int cpu, orig_cpu, this_cpu, success = 0; + int cpu, this_cpu, success = 0; unsigned long flags; - unsigned long en_flags = ENQUEUE_WAKEUP; struct rq *rq; this_cpu = get_cpu(); smp_wmb(); raw_spin_lock_irqsave(&p->pi_lock, flags); - rq = __task_rq_lock(p); if (!(p->state & state)) goto out; cpu = task_cpu(p); - if (p->on_rq) - goto out_running; + if (p->on_rq) { + rq = __task_rq_lock(p); + if (p->on_rq) + goto out_running; + __task_rq_unlock(rq); + } - orig_cpu = cpu; #ifdef CONFIG_SMP - if (unlikely(task_running(rq, p))) - goto out_activate; + while (p->on_cpu) { +#ifdef __ARCH_WANT_INTERRUPTS_ON_CTXSW + /* + * If called from interrupt context we could have landed in the + * middle of schedule(), in this case we should take care not + * to spin on ->on_cpu if p is current, since that would + * deadlock. + */ + if (p == current) + goto out_activate; +#endif + cpu_relax(); + } + /* + * Pairs with the smp_wmb() in finish_lock_switch(). + */ + smp_rmb(); p->sched_contributes_to_load = !!task_contributes_to_load(p); p->state = TASK_WAKING; - if (p->sched_class->task_waking) { + if (p->sched_class->task_waking) p->sched_class->task_waking(p); - en_flags |= ENQUEUE_WAKING; - } cpu = select_task_rq(p, SD_BALANCE_WAKE, wake_flags); - if (cpu != orig_cpu) - set_task_cpu(p, cpu); - __task_rq_unlock(rq); +#ifdef __ARCH_WANT_INTERRUPTS_ON_CTXSW +out_activate: +#endif +#endif /* CONFIG_SMP */ rq = cpu_rq(cpu); raw_spin_lock(&rq->lock); - /* - * We migrated the task without holding either rq->lock, however - * since the task is not on the task list itself, nobody else - * will try and migrate the task, hence the rq should match the - * cpu we just moved it to. - */ - WARN_ON(task_cpu(p) != cpu); - WARN_ON(p->state != TASK_WAKING); +#ifdef CONFIG_SMP + if (cpu != task_cpu(p)) + set_task_cpu(p, cpu); if (p->sched_contributes_to_load) rq->nr_uninterruptible--; +#endif -out_activate: -#endif /* CONFIG_SMP */ - ttwu_activate(rq, p, en_flags); + ttwu_activate(rq, p, ENQUEUE_WAKEUP | ENQUEUE_WAKING); out_running: ttwu_post_activation(p, rq, wake_flags); ttwu_stat(rq, p, cpu, wake_flags); success = 1; -out: __task_rq_unlock(rq); +out: raw_spin_unlock_irqrestore(&p->pi_lock, flags); put_cpu(); -- cgit v0.10.2 From b84cb5df1f9ad6da3f214c638d5fb08d0c99de1f Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Tue, 5 Apr 2011 17:23:55 +0200 Subject: sched: Remove rq argument from ttwu_stat() In order to call ttwu_stat() without holding rq->lock we must remove its rq argument. Since we need to change rq stats, account to the local rq instead of the task rq, this is safe since we have IRQs disabled. Reviewed-by: Frank Rowand Cc: Mike Galbraith Cc: Nick Piggin Cc: Linus Torvalds Cc: Andrew Morton Signed-off-by: Ingo Molnar Signed-off-by: Peter Zijlstra Link: http://lkml.kernel.org/r/20110405152729.394638826@chello.nl diff --git a/kernel/sched.c b/kernel/sched.c index 871dd9e..5ec2e8b 100644 --- a/kernel/sched.c +++ b/kernel/sched.c @@ -2410,9 +2410,11 @@ static void update_avg(u64 *avg, u64 sample) #endif static void -ttwu_stat(struct rq *rq, struct task_struct *p, int cpu, int wake_flags) +ttwu_stat(struct task_struct *p, int cpu, int wake_flags) { #ifdef CONFIG_SCHEDSTATS + struct rq *rq = this_rq(); + #ifdef CONFIG_SMP int this_cpu = smp_processor_id(); @@ -2561,9 +2563,10 @@ out_activate: ttwu_activate(rq, p, ENQUEUE_WAKEUP | ENQUEUE_WAKING); out_running: ttwu_post_activation(p, rq, wake_flags); - ttwu_stat(rq, p, cpu, wake_flags); success = 1; __task_rq_unlock(rq); + + ttwu_stat(p, cpu, wake_flags); out: raw_spin_unlock_irqrestore(&p->pi_lock, flags); put_cpu(); @@ -2600,7 +2603,7 @@ static void try_to_wake_up_local(struct task_struct *p) ttwu_activate(rq, p, ENQUEUE_WAKEUP); ttwu_post_activation(p, rq, 0); - ttwu_stat(rq, p, smp_processor_id(), 0); + ttwu_stat(p, smp_processor_id(), 0); out: raw_spin_unlock(&p->pi_lock); } -- cgit v0.10.2 From 23f41eeb42ce7f6f1210904e49e84718f02cb61c Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Tue, 5 Apr 2011 17:23:56 +0200 Subject: sched: Rename ttwu_post_activation() to ttwu_do_wakeup() The ttwu_post_activation() code does the core wakeup, it sets TASK_RUNNING and performs wakeup-preemption, so give is a more descriptive name. Reviewed-by: Frank Rowand Cc: Mike Galbraith Cc: Nick Piggin Cc: Linus Torvalds Cc: Andrew Morton Signed-off-by: Ingo Molnar Signed-off-by: Peter Zijlstra Link: http://lkml.kernel.org/r/20110405152729.434609705@chello.nl diff --git a/kernel/sched.c b/kernel/sched.c index 5ec2e8b..e309dba 100644 --- a/kernel/sched.c +++ b/kernel/sched.c @@ -2456,8 +2456,11 @@ static void ttwu_activate(struct rq *rq, struct task_struct *p, int en_flags) wq_worker_waking_up(p, cpu_of(rq)); } +/* + * Mark the task runnable and perform wakeup-preemption. + */ static void -ttwu_post_activation(struct task_struct *p, struct rq *rq, int wake_flags) +ttwu_do_wakeup(struct rq *rq, struct task_struct *p, int wake_flags) { trace_sched_wakeup(p, true); check_preempt_curr(rq, p, wake_flags); @@ -2562,7 +2565,7 @@ out_activate: ttwu_activate(rq, p, ENQUEUE_WAKEUP | ENQUEUE_WAKING); out_running: - ttwu_post_activation(p, rq, wake_flags); + ttwu_do_wakeup(rq, p, wake_flags); success = 1; __task_rq_unlock(rq); @@ -2602,7 +2605,7 @@ static void try_to_wake_up_local(struct task_struct *p) if (!p->on_rq) ttwu_activate(rq, p, ENQUEUE_WAKEUP); - ttwu_post_activation(p, rq, 0); + ttwu_do_wakeup(rq, p, 0); ttwu_stat(p, smp_processor_id(), 0); out: raw_spin_unlock(&p->pi_lock); -- cgit v0.10.2 From c05fbafba1c5482bee399b360288fa405415e126 Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Tue, 5 Apr 2011 17:23:57 +0200 Subject: sched: Restructure ttwu() some more Factor our helper functions to make the inner workings of try_to_wake_up() more obvious, this also allows for adding remote queues. Reviewed-by: Frank Rowand Cc: Mike Galbraith Cc: Nick Piggin Cc: Linus Torvalds Cc: Andrew Morton Signed-off-by: Ingo Molnar Signed-off-by: Peter Zijlstra Link: http://lkml.kernel.org/r/20110405152729.475848012@chello.nl diff --git a/kernel/sched.c b/kernel/sched.c index e309dba..7d8b85f 100644 --- a/kernel/sched.c +++ b/kernel/sched.c @@ -2483,6 +2483,48 @@ ttwu_do_wakeup(struct rq *rq, struct task_struct *p, int wake_flags) #endif } +static void +ttwu_do_activate(struct rq *rq, struct task_struct *p, int wake_flags) +{ +#ifdef CONFIG_SMP + if (p->sched_contributes_to_load) + rq->nr_uninterruptible--; +#endif + + ttwu_activate(rq, p, ENQUEUE_WAKEUP | ENQUEUE_WAKING); + ttwu_do_wakeup(rq, p, wake_flags); +} + +/* + * Called in case the task @p isn't fully descheduled from its runqueue, + * in this case we must do a remote wakeup. Its a 'light' wakeup though, + * since all we need to do is flip p->state to TASK_RUNNING, since + * the task is still ->on_rq. + */ +static int ttwu_remote(struct task_struct *p, int wake_flags) +{ + struct rq *rq; + int ret = 0; + + rq = __task_rq_lock(p); + if (p->on_rq) { + ttwu_do_wakeup(rq, p, wake_flags); + ret = 1; + } + __task_rq_unlock(rq); + + return ret; +} + +static void ttwu_queue(struct task_struct *p, int cpu) +{ + struct rq *rq = cpu_rq(cpu); + + raw_spin_lock(&rq->lock); + ttwu_do_activate(rq, p, 0); + raw_spin_unlock(&rq->lock); +} + /** * try_to_wake_up - wake up a thread * @p: the thread to be awakened @@ -2501,27 +2543,25 @@ ttwu_do_wakeup(struct rq *rq, struct task_struct *p, int wake_flags) static int try_to_wake_up(struct task_struct *p, unsigned int state, int wake_flags) { - int cpu, this_cpu, success = 0; unsigned long flags; - struct rq *rq; - - this_cpu = get_cpu(); + int cpu, success = 0; smp_wmb(); raw_spin_lock_irqsave(&p->pi_lock, flags); if (!(p->state & state)) goto out; + success = 1; /* we're going to change ->state */ cpu = task_cpu(p); - if (p->on_rq) { - rq = __task_rq_lock(p); - if (p->on_rq) - goto out_running; - __task_rq_unlock(rq); - } + if (p->on_rq && ttwu_remote(p, wake_flags)) + goto stat; #ifdef CONFIG_SMP + /* + * If the owning (remote) cpu is still in the middle of schedule() with + * this task as prev, wait until its done referencing the task. + */ while (p->on_cpu) { #ifdef __ARCH_WANT_INTERRUPTS_ON_CTXSW /* @@ -2530,8 +2570,10 @@ try_to_wake_up(struct task_struct *p, unsigned int state, int wake_flags) * to spin on ->on_cpu if p is current, since that would * deadlock. */ - if (p == current) - goto out_activate; + if (p == current) { + ttwu_queue(p, cpu); + goto stat; + } #endif cpu_relax(); } @@ -2547,32 +2589,15 @@ try_to_wake_up(struct task_struct *p, unsigned int state, int wake_flags) p->sched_class->task_waking(p); cpu = select_task_rq(p, SD_BALANCE_WAKE, wake_flags); -#ifdef __ARCH_WANT_INTERRUPTS_ON_CTXSW -out_activate: -#endif -#endif /* CONFIG_SMP */ - - rq = cpu_rq(cpu); - raw_spin_lock(&rq->lock); - -#ifdef CONFIG_SMP - if (cpu != task_cpu(p)) + if (task_cpu(p) != cpu) set_task_cpu(p, cpu); +#endif /* CONFIG_SMP */ - if (p->sched_contributes_to_load) - rq->nr_uninterruptible--; -#endif - - ttwu_activate(rq, p, ENQUEUE_WAKEUP | ENQUEUE_WAKING); -out_running: - ttwu_do_wakeup(rq, p, wake_flags); - success = 1; - __task_rq_unlock(rq); - + ttwu_queue(p, cpu); +stat: ttwu_stat(p, cpu, wake_flags); out: raw_spin_unlock_irqrestore(&p->pi_lock, flags); - put_cpu(); return success; } -- cgit v0.10.2 From 317f394160e9beb97d19a84c39b7e5eb3d7815a8 Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Tue, 5 Apr 2011 17:23:58 +0200 Subject: sched: Move the second half of ttwu() to the remote cpu Now that we've removed the rq->lock requirement from the first part of ttwu() and can compute placement without holding any rq->lock, ensure we execute the second half of ttwu() on the actual cpu we want the task to run on. This avoids having to take rq->lock and doing the task enqueue remotely, saving lots on cacheline transfers. As measured using: http://oss.oracle.com/~mason/sembench.c $ for i in /sys/devices/system/cpu/cpu*/cpufreq/scaling_governor ; do echo performance > $i; done $ echo 4096 32000 64 128 > /proc/sys/kernel/sem $ ./sembench -t 2048 -w 1900 -o 0 unpatched: run time 30 seconds 647278 worker burns per second patched: run time 30 seconds 816715 worker burns per second Reviewed-by: Frank Rowand Cc: Mike Galbraith Cc: Nick Piggin Cc: Linus Torvalds Cc: Andrew Morton Signed-off-by: Ingo Molnar Signed-off-by: Peter Zijlstra Link: http://lkml.kernel.org/r/20110405152729.515897185@chello.nl diff --git a/include/linux/sched.h b/include/linux/sched.h index 25c5031..e09dafa 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h @@ -1203,6 +1203,7 @@ struct task_struct { int lock_depth; /* BKL lock depth */ #ifdef CONFIG_SMP + struct task_struct *wake_entry; int on_cpu; #endif int on_rq; @@ -2192,7 +2193,7 @@ extern void set_task_comm(struct task_struct *tsk, char *from); extern char *get_task_comm(char *to, struct task_struct *tsk); #ifdef CONFIG_SMP -static inline void scheduler_ipi(void) { } +void scheduler_ipi(void); extern unsigned long wait_task_inactive(struct task_struct *, long match_state); #else static inline void scheduler_ipi(void) { } diff --git a/init/Kconfig b/init/Kconfig index 56240e7..32745bf 100644 --- a/init/Kconfig +++ b/init/Kconfig @@ -827,6 +827,11 @@ config SCHED_AUTOGROUP desktop applications. Task group autogeneration is currently based upon task session. +config SCHED_TTWU_QUEUE + bool + depends on !SPARC32 + default y + config MM_OWNER bool diff --git a/kernel/sched.c b/kernel/sched.c index 7d8b85f..9e3ede1 100644 --- a/kernel/sched.c +++ b/kernel/sched.c @@ -556,6 +556,10 @@ struct rq { unsigned int ttwu_count; unsigned int ttwu_local; #endif + +#ifdef CONFIG_SMP + struct task_struct *wake_list; +#endif }; static DEFINE_PER_CPU_SHARED_ALIGNED(struct rq, runqueues); @@ -2516,10 +2520,61 @@ static int ttwu_remote(struct task_struct *p, int wake_flags) return ret; } +#ifdef CONFIG_SMP +static void sched_ttwu_pending(void) +{ + struct rq *rq = this_rq(); + struct task_struct *list = xchg(&rq->wake_list, NULL); + + if (!list) + return; + + raw_spin_lock(&rq->lock); + + while (list) { + struct task_struct *p = list; + list = list->wake_entry; + ttwu_do_activate(rq, p, 0); + } + + raw_spin_unlock(&rq->lock); +} + +void scheduler_ipi(void) +{ + sched_ttwu_pending(); +} + +static void ttwu_queue_remote(struct task_struct *p, int cpu) +{ + struct rq *rq = cpu_rq(cpu); + struct task_struct *next = rq->wake_list; + + for (;;) { + struct task_struct *old = next; + + p->wake_entry = next; + next = cmpxchg(&rq->wake_list, old, p); + if (next == old) + break; + } + + if (!next) + smp_send_reschedule(cpu); +} +#endif + static void ttwu_queue(struct task_struct *p, int cpu) { struct rq *rq = cpu_rq(cpu); +#if defined(CONFIG_SMP) && defined(CONFIG_SCHED_TTWU_QUEUE) + if (sched_feat(TTWU_QUEUE) && cpu != smp_processor_id()) { + ttwu_queue_remote(p, cpu); + return; + } +#endif + raw_spin_lock(&rq->lock); ttwu_do_activate(rq, p, 0); raw_spin_unlock(&rq->lock); @@ -6331,6 +6386,7 @@ migration_call(struct notifier_block *nfb, unsigned long action, void *hcpu) #ifdef CONFIG_HOTPLUG_CPU case CPU_DYING: + sched_ttwu_pending(); /* Update our root-domain */ raw_spin_lock_irqsave(&rq->lock, flags); if (rq->rd) { diff --git a/kernel/sched_features.h b/kernel/sched_features.h index 68e69ac..be40f73 100644 --- a/kernel/sched_features.h +++ b/kernel/sched_features.h @@ -64,3 +64,9 @@ SCHED_FEAT(OWNER_SPIN, 1) * Decrement CPU power based on irq activity */ SCHED_FEAT(NONIRQ_POWER, 1) + +/* + * Queue remote wakeups on the target CPU and process them + * using the scheduler IPI. Reduces rq->lock contention/bounces. + */ +SCHED_FEAT(TTWU_QUEUE, 1) -- cgit v0.10.2 From bd8e7dded88a3e1c085c333f19ff31387616f71a Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Tue, 5 Apr 2011 17:23:59 +0200 Subject: sched: Remove need_migrate_task() Oleg noticed that need_migrate_task() doesn't need the ->on_cpu check now that ttwu() doesn't do remote enqueues for !->on_rq && ->on_cpu, so remove the helper and replace the single instance with a direct ->on_rq test. Suggested-by: Oleg Nesterov Reviewed-by: Frank Rowand Signed-off-by: Peter Zijlstra Cc: Mike Galbraith Cc: Nick Piggin Cc: Linus Torvalds Cc: Andrew Morton Link: http://lkml.kernel.org/r/20110405152729.556674812@chello.nl Signed-off-by: Ingo Molnar diff --git a/kernel/sched.c b/kernel/sched.c index 9e3ede1..cd597c7 100644 --- a/kernel/sched.c +++ b/kernel/sched.c @@ -2199,21 +2199,6 @@ struct migration_arg { static int migration_cpu_stop(void *data); /* - * The task's runqueue lock must be held. - * Returns true if you have to wait for migration thread. - */ -static bool need_migrate_task(struct task_struct *p) -{ - /* - * If the task is not on a runqueue (and not running), then - * the next wake-up will properly place the task. - */ - bool running = p->on_rq || p->on_cpu; - smp_rmb(); /* finish_lock_switch() */ - return running; -} - -/* * wait_task_inactive - wait for a thread to unschedule. * * If @match_state is nonzero, it's the @p->state value just checked and @@ -5985,7 +5970,7 @@ int set_cpus_allowed_ptr(struct task_struct *p, const struct cpumask *new_mask) goto out; dest_cpu = cpumask_any_and(cpu_active_mask, new_mask); - if (need_migrate_task(p)) { + if (p->on_rq) { struct migration_arg arg = { p, dest_cpu }; /* Need help from migration thread: drop lock and wait. */ task_rq_unlock(rq, p, &flags); -- cgit v0.10.2 From 8849b720e9632acef139a349f9ec62e63ce7e497 Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Thu, 14 Apr 2011 00:20:07 -0700 Subject: NET: AX.25, NETROM, ROSE: Remove SOCK_DEBUG calls Nobody alive seems to recall when they last were useful. Signed-off-by: Ralf Baechle Signed-off-by: David S. Miller diff --git a/net/ax25/af_ax25.c b/net/ax25/af_ax25.c index 6da5dae..e7c69f4 100644 --- a/net/ax25/af_ax25.c +++ b/net/ax25/af_ax25.c @@ -1538,8 +1538,6 @@ static int ax25_sendmsg(struct kiocb *iocb, struct socket *sock, } /* Build a packet */ - SOCK_DEBUG(sk, "AX.25: sendto: Addresses built. Building packet.\n"); - /* Assume the worst case */ size = len + ax25->ax25_dev->dev->hard_header_len; @@ -1549,8 +1547,6 @@ static int ax25_sendmsg(struct kiocb *iocb, struct socket *sock, skb_reserve(skb, size - len); - SOCK_DEBUG(sk, "AX.25: Appending user data\n"); - /* User data follows immediately after the AX.25 data */ if (memcpy_fromiovec(skb_put(skb, len), msg->msg_iov, len)) { err = -EFAULT; @@ -1564,8 +1560,6 @@ static int ax25_sendmsg(struct kiocb *iocb, struct socket *sock, if (!ax25->pidincl) *skb_push(skb, 1) = sk->sk_protocol; - SOCK_DEBUG(sk, "AX.25: Transmitting buffer\n"); - if (sk->sk_type == SOCK_SEQPACKET) { /* Connected mode sockets go via the LAPB machine */ if (sk->sk_state != TCP_ESTABLISHED) { @@ -1583,22 +1577,14 @@ static int ax25_sendmsg(struct kiocb *iocb, struct socket *sock, skb_push(skb, 1 + ax25_addr_size(dp)); - SOCK_DEBUG(sk, "Building AX.25 Header (dp=%p).\n", dp); - - if (dp != NULL) - SOCK_DEBUG(sk, "Num digipeaters=%d\n", dp->ndigi); + /* Building AX.25 Header */ /* Build an AX.25 header */ lv = ax25_addr_build(skb->data, &ax25->source_addr, &sax.sax25_call, dp, AX25_COMMAND, AX25_MODULUS); - SOCK_DEBUG(sk, "Built header (%d bytes)\n",lv); - skb_set_transport_header(skb, lv); - SOCK_DEBUG(sk, "base=%p pos=%p\n", - skb->data, skb_transport_header(skb)); - *skb_transport_header(skb) = AX25_UI; /* Datagram frames go straight out of the door as UI */ diff --git a/net/netrom/af_netrom.c b/net/netrom/af_netrom.c index 06cb027..732152f 100644 --- a/net/netrom/af_netrom.c +++ b/net/netrom/af_netrom.c @@ -591,7 +591,6 @@ static int nr_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len) return -EINVAL; } if ((dev = nr_dev_get(&addr->fsa_ax25.sax25_call)) == NULL) { - SOCK_DEBUG(sk, "NET/ROM: bind failed: invalid node callsign\n"); release_sock(sk); return -EADDRNOTAVAIL; } @@ -632,7 +631,7 @@ static int nr_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len) sock_reset_flag(sk, SOCK_ZAPPED); dev_put(dev); release_sock(sk); - SOCK_DEBUG(sk, "NET/ROM: socket is bound\n"); + return 0; } @@ -1082,8 +1081,6 @@ static int nr_sendmsg(struct kiocb *iocb, struct socket *sock, sax.sax25_call = nr->dest_addr; } - SOCK_DEBUG(sk, "NET/ROM: sendto: Addresses built.\n"); - /* Build a packet - the conventional user limit is 236 bytes. We can do ludicrously large NetROM frames but must not overflow */ if (len > 65536) { @@ -1091,7 +1088,6 @@ static int nr_sendmsg(struct kiocb *iocb, struct socket *sock, goto out; } - SOCK_DEBUG(sk, "NET/ROM: sendto: building packet.\n"); size = len + NR_NETWORK_LEN + NR_TRANSPORT_LEN; if ((skb = sock_alloc_send_skb(sk, size, msg->msg_flags & MSG_DONTWAIT, &err)) == NULL) @@ -1105,7 +1101,6 @@ static int nr_sendmsg(struct kiocb *iocb, struct socket *sock, */ asmptr = skb_push(skb, NR_TRANSPORT_LEN); - SOCK_DEBUG(sk, "Building NET/ROM Header.\n"); /* Build a NET/ROM Transport header */ @@ -1114,15 +1109,12 @@ static int nr_sendmsg(struct kiocb *iocb, struct socket *sock, *asmptr++ = 0; /* To be filled in later */ *asmptr++ = 0; /* Ditto */ *asmptr++ = NR_INFO; - SOCK_DEBUG(sk, "Built header.\n"); /* * Put the data on the end */ skb_put(skb, len); - SOCK_DEBUG(sk, "NET/ROM: Appending user data\n"); - /* User data follows immediately after the NET/ROM transport header */ if (memcpy_fromiovec(skb_transport_header(skb), msg->msg_iov, len)) { kfree_skb(skb); @@ -1130,8 +1122,6 @@ static int nr_sendmsg(struct kiocb *iocb, struct socket *sock, goto out; } - SOCK_DEBUG(sk, "NET/ROM: Transmitting buffer\n"); - if (sk->sk_state != TCP_ESTABLISHED) { kfree_skb(skb); err = -ENOTCONN; diff --git a/net/rose/af_rose.c b/net/rose/af_rose.c index a80aef6..f9ea925 100644 --- a/net/rose/af_rose.c +++ b/net/rose/af_rose.c @@ -682,10 +682,8 @@ static int rose_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len) if ((unsigned int) addr->srose_ndigis > ROSE_MAX_DIGIS) return -EINVAL; - if ((dev = rose_dev_get(&addr->srose_addr)) == NULL) { - SOCK_DEBUG(sk, "ROSE: bind failed: invalid address\n"); + if ((dev = rose_dev_get(&addr->srose_addr)) == NULL) return -EADDRNOTAVAIL; - } source = &addr->srose_call; @@ -716,7 +714,7 @@ static int rose_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len) rose_insert_socket(sk); sock_reset_flag(sk, SOCK_ZAPPED); - SOCK_DEBUG(sk, "ROSE: socket is bound\n"); + return 0; } @@ -1109,10 +1107,7 @@ static int rose_sendmsg(struct kiocb *iocb, struct socket *sock, srose.srose_digis[n] = rose->dest_digis[n]; } - SOCK_DEBUG(sk, "ROSE: sendto: Addresses built.\n"); - /* Build a packet */ - SOCK_DEBUG(sk, "ROSE: sendto: building packet.\n"); /* Sanity check the packet size */ if (len > 65535) return -EMSGSIZE; @@ -1127,7 +1122,6 @@ static int rose_sendmsg(struct kiocb *iocb, struct socket *sock, /* * Put the data on the end */ - SOCK_DEBUG(sk, "ROSE: Appending user data\n"); skb_reset_transport_header(skb); skb_put(skb, len); @@ -1152,8 +1146,6 @@ static int rose_sendmsg(struct kiocb *iocb, struct socket *sock, */ asmptr = skb_push(skb, ROSE_MIN_LEN); - SOCK_DEBUG(sk, "ROSE: Building Network Header.\n"); - /* Build a ROSE Network header */ asmptr[0] = ((rose->lci >> 8) & 0x0F) | ROSE_GFI; asmptr[1] = (rose->lci >> 0) & 0xFF; @@ -1162,10 +1154,6 @@ static int rose_sendmsg(struct kiocb *iocb, struct socket *sock, if (qbit) asmptr[0] |= ROSE_Q_BIT; - SOCK_DEBUG(sk, "ROSE: Built header.\n"); - - SOCK_DEBUG(sk, "ROSE: Transmitting buffer\n"); - if (sk->sk_state != TCP_ESTABLISHED) { kfree_skb(skb); return -ENOTCONN; -- cgit v0.10.2 From 38a2f37258f9e2ae3f6e4241e01088be8dfaf4e9 Mon Sep 17 00:00:00 2001 From: huajun li Date: Wed, 13 Apr 2011 15:43:32 +0000 Subject: usbnet: Fix up 'FLAG_POINTTOPOINT' and 'FLAG_MULTI_PACKET' overlaps. USB tethering does not work anymore since 2.6.39-rc2, but it's okay in -rc1. The root cause is the new added mask code 'FLAG_POINTTOPOINT' overlaps 'FLAG_MULTI_PACKET' in include/linux/usb/usbnet.h, this causes logic issue in rx_process(). This patch cleans up the overlap. Reported-and-Tested-by: Gottfried Haider Signed-off-by: Huajun Li Signed-off-by: David S. Miller diff --git a/include/linux/usb/usbnet.h b/include/linux/usb/usbnet.h index 3c7329b..0e18550 100644 --- a/include/linux/usb/usbnet.h +++ b/include/linux/usb/usbnet.h @@ -103,8 +103,8 @@ struct driver_info { * Indicates to usbnet, that USB driver accumulates multiple IP packets. * Affects statistic (counters) and short packet handling. */ -#define FLAG_MULTI_PACKET 0x1000 -#define FLAG_RX_ASSEMBLE 0x2000 /* rx packets may span >1 frames */ +#define FLAG_MULTI_PACKET 0x2000 +#define FLAG_RX_ASSEMBLE 0x4000 /* rx packets may span >1 frames */ /* init device ... can sleep, or cause probe() failure */ int (*bind)(struct usbnet *, struct usb_interface *); -- cgit v0.10.2 From 9ce24a7ea9c257b02151d9a31fc30afad89a5966 Mon Sep 17 00:00:00 2001 From: Raymond Yau Date: Fri, 8 Apr 2011 15:46:17 +0800 Subject: ALSA: emu10k1 - Fix "Music" controls to "Synth" controls in documents Signed-off-by: Raymond Yau Signed-off-by: Takashi Iwai diff --git a/Documentation/sound/alsa/SB-Live-mixer.txt b/Documentation/sound/alsa/SB-Live-mixer.txt index f5639d4..f4b5988 100644 --- a/Documentation/sound/alsa/SB-Live-mixer.txt +++ b/Documentation/sound/alsa/SB-Live-mixer.txt @@ -87,14 +87,14 @@ accumulator. ALSA uses accumulators 0 and 1 for left and right PCM. The result is forwarded to the ADC capture FIFO (thus to the standard capture PCM device). -name='Music Playback Volume',index=0 +name='Synth Playback Volume',index=0 This control is used to attenuate samples for left and right MIDI FX-bus accumulators. ALSA uses accumulators 4 and 5 for left and right MIDI samples. The result samples are forwarded to the front DAC PCM slots of the AC97 codec. -name='Music Capture Volume',index=0 -name='Music Capture Switch',index=0 +name='Synth Capture Volume',index=0 +name='Synth Capture Switch',index=0 These controls are used to attenuate samples for left and right MIDI FX-bus accumulator. ALSA uses accumulators 4 and 5 for left and right PCM. -- cgit v0.10.2 From c55fa78b13b32d3f19e19cd0c8b9378fdc09e521 Mon Sep 17 00:00:00 2001 From: Konrad Rzeszutek Wilk Date: Mon, 8 Nov 2010 14:13:35 -0500 Subject: xen/pci: Add xen_[find|register|unregister]_device_domain_owner functions. When the Xen PCI backend is told to enable or disable MSI/MSI-X functions, the initial domain performs these operations. The initial domain needs to know which domain (guest) is going to use the PCI device so when it makes the appropiate hypercall to retrieve the MSI/MSI-X vector it will also assign the PCI device to the appropiate domain (guest). This boils down to us needing a mechanism to find, set and unset the domain id that will be using the device. [v2: EXPORT_SYMBOL -> EXPORT_SYMBOL_GPL.] Signed-off-by: Konrad Rzeszutek Wilk diff --git a/arch/x86/include/asm/xen/pci.h b/arch/x86/include/asm/xen/pci.h index aa86209..4fbda9a 100644 --- a/arch/x86/include/asm/xen/pci.h +++ b/arch/x86/include/asm/xen/pci.h @@ -15,10 +15,26 @@ static inline int pci_xen_hvm_init(void) #endif #if defined(CONFIG_XEN_DOM0) void __init xen_setup_pirqs(void); +int xen_find_device_domain_owner(struct pci_dev *dev); +int xen_register_device_domain_owner(struct pci_dev *dev, uint16_t domain); +int xen_unregister_device_domain_owner(struct pci_dev *dev); #else static inline void __init xen_setup_pirqs(void) { } +static inline int xen_find_device_domain_owner(struct pci_dev *dev) +{ + return -1; +} +static inline int xen_register_device_domain_owner(struct pci_dev *dev, + uint16_t domain) +{ + return -1; +} +static inline int xen_unregister_device_domain_owner(struct pci_dev *dev) +{ + return -1; +} #endif #if defined(CONFIG_PCI_MSI) diff --git a/arch/x86/pci/xen.c b/arch/x86/pci/xen.c index e37b407..6075f2d 100644 --- a/arch/x86/pci/xen.c +++ b/arch/x86/pci/xen.c @@ -461,3 +461,76 @@ void __init xen_setup_pirqs(void) } } #endif + +struct xen_device_domain_owner { + domid_t domain; + struct pci_dev *dev; + struct list_head list; +}; + +static DEFINE_SPINLOCK(dev_domain_list_spinlock); +static struct list_head dev_domain_list = LIST_HEAD_INIT(dev_domain_list); + +static struct xen_device_domain_owner *find_device(struct pci_dev *dev) +{ + struct xen_device_domain_owner *owner; + + list_for_each_entry(owner, &dev_domain_list, list) { + if (owner->dev == dev) + return owner; + } + return NULL; +} + +int xen_find_device_domain_owner(struct pci_dev *dev) +{ + struct xen_device_domain_owner *owner; + int domain = -ENODEV; + + spin_lock(&dev_domain_list_spinlock); + owner = find_device(dev); + if (owner) + domain = owner->domain; + spin_unlock(&dev_domain_list_spinlock); + return domain; +} +EXPORT_SYMBOL_GPL(xen_find_device_domain_owner); + +int xen_register_device_domain_owner(struct pci_dev *dev, uint16_t domain) +{ + struct xen_device_domain_owner *owner; + + owner = kzalloc(sizeof(struct xen_device_domain_owner), GFP_KERNEL); + if (!owner) + return -ENODEV; + + spin_lock(&dev_domain_list_spinlock); + if (find_device(dev)) { + spin_unlock(&dev_domain_list_spinlock); + kfree(owner); + return -EEXIST; + } + owner->domain = domain; + owner->dev = dev; + list_add_tail(&owner->list, &dev_domain_list); + spin_unlock(&dev_domain_list_spinlock); + return 0; +} +EXPORT_SYMBOL_GPL(xen_register_device_domain_owner); + +int xen_unregister_device_domain_owner(struct pci_dev *dev) +{ + struct xen_device_domain_owner *owner; + + spin_lock(&dev_domain_list_spinlock); + owner = find_device(dev); + if (!owner) { + spin_unlock(&dev_domain_list_spinlock); + return -ENODEV; + } + list_del(&owner->list); + spin_unlock(&dev_domain_list_spinlock); + kfree(owner); + return 0; +} +EXPORT_SYMBOL_GPL(xen_unregister_device_domain_owner); -- cgit v0.10.2 From beafbdc1df02877612dc9039c1de0639921fddec Mon Sep 17 00:00:00 2001 From: Konrad Rzeszutek Wilk Date: Thu, 14 Apr 2011 11:17:36 -0400 Subject: xen/irq: Check if the PCI device is owned by a domain different than DOMID_SELF. We check if there is a domain owner for the PCI device. In case of failure (meaning no domain has registered for this device) we make DOMID_SELF the owner. Signed-off-by: Konrad Rzeszutek Wilk [v2: deal with rebasing on v2.6.37-1] [v3: deal with rebasing on stable/irq.cleanup] [v4: deal with rebasing on stable/irq.ween_of_nr_irqs] [v5: deal with rebasing on v2.6.39-rc3] Signed-off-by: Jeremy Fitzhardinge Acked-by: Xiantao Zhang diff --git a/arch/x86/pci/xen.c b/arch/x86/pci/xen.c index 6075f2d..393981f 100644 --- a/arch/x86/pci/xen.c +++ b/arch/x86/pci/xen.c @@ -108,7 +108,8 @@ static int xen_hvm_setup_msi_irqs(struct pci_dev *dev, int nvec, int type) } irq = xen_bind_pirq_msi_to_irq(dev, msidesc, pirq, 0, (type == PCI_CAP_ID_MSIX) ? - "msi-x" : "msi"); + "msi-x" : "msi", + DOMID_SELF); if (irq < 0) goto error; dev_dbg(&dev->dev, @@ -148,7 +149,8 @@ static int xen_setup_msi_irqs(struct pci_dev *dev, int nvec, int type) irq = xen_bind_pirq_msi_to_irq(dev, msidesc, v[i], 0, (type == PCI_CAP_ID_MSIX) ? "pcifront-msi-x" : - "pcifront-msi"); + "pcifront-msi", + DOMID_SELF); if (irq < 0) goto free; i++; @@ -190,9 +192,16 @@ static int xen_initdom_setup_msi_irqs(struct pci_dev *dev, int nvec, int type) list_for_each_entry(msidesc, &dev->msi_list, list) { struct physdev_map_pirq map_irq; + domid_t domid; + + domid = ret = xen_find_device_domain_owner(dev); + /* N.B. Casting int's -ENODEV to uint16_t results in 0xFFED, + * hence check ret value for < 0. */ + if (ret < 0) + domid = DOMID_SELF; memset(&map_irq, 0, sizeof(map_irq)); - map_irq.domid = DOMID_SELF; + map_irq.domid = domid; map_irq.type = MAP_PIRQ_TYPE_MSI; map_irq.index = -1; map_irq.pirq = -1; @@ -215,14 +224,16 @@ static int xen_initdom_setup_msi_irqs(struct pci_dev *dev, int nvec, int type) ret = HYPERVISOR_physdev_op(PHYSDEVOP_map_pirq, &map_irq); if (ret) { - dev_warn(&dev->dev, "xen map irq failed %d\n", ret); + dev_warn(&dev->dev, "xen map irq failed %d for %d domain\n", + ret, domid); goto out; } ret = xen_bind_pirq_msi_to_irq(dev, msidesc, map_irq.pirq, map_irq.index, (type == PCI_CAP_ID_MSIX) ? - "msi-x" : "msi"); + "msi-x" : "msi", + domid); if (ret < 0) goto out; } diff --git a/drivers/xen/events.c b/drivers/xen/events.c index 42d6c93..ac0e228 100644 --- a/drivers/xen/events.c +++ b/drivers/xen/events.c @@ -101,6 +101,7 @@ struct irq_info unsigned short gsi; unsigned char vector; unsigned char flags; + uint16_t domid; } pirq; } u; }; @@ -184,6 +185,7 @@ static void xen_irq_info_pirq_init(unsigned irq, unsigned short pirq, unsigned short gsi, unsigned short vector, + uint16_t domid, unsigned char flags) { struct irq_info *info = info_for_irq(irq); @@ -193,6 +195,7 @@ static void xen_irq_info_pirq_init(unsigned irq, info->u.pirq.pirq = pirq; info->u.pirq.gsi = gsi; info->u.pirq.vector = vector; + info->u.pirq.domid = domid; info->u.pirq.flags = flags; } @@ -655,7 +658,7 @@ int xen_bind_pirq_gsi_to_irq(unsigned gsi, goto out; } - xen_irq_info_pirq_init(irq, 0, pirq, gsi, irq_op.vector, + xen_irq_info_pirq_init(irq, 0, pirq, gsi, irq_op.vector, DOMID_SELF, shareable ? PIRQ_SHAREABLE : 0); out: @@ -680,7 +683,8 @@ int xen_allocate_pirq_msi(struct pci_dev *dev, struct msi_desc *msidesc) } int xen_bind_pirq_msi_to_irq(struct pci_dev *dev, struct msi_desc *msidesc, - int pirq, int vector, const char *name) + int pirq, int vector, const char *name, + domid_t domid) { int irq, ret; @@ -693,7 +697,7 @@ int xen_bind_pirq_msi_to_irq(struct pci_dev *dev, struct msi_desc *msidesc, irq_set_chip_and_handler_name(irq, &xen_pirq_chip, handle_level_irq, name); - xen_irq_info_pirq_init(irq, 0, pirq, 0, vector, 0); + xen_irq_info_pirq_init(irq, 0, pirq, 0, vector, domid, 0); ret = irq_set_msi_desc(irq, msidesc); if (ret < 0) goto error_irq; @@ -722,7 +726,7 @@ int xen_destroy_irq(int irq) if (xen_initial_domain()) { unmap_irq.pirq = info->u.pirq.pirq; - unmap_irq.domid = DOMID_SELF; + unmap_irq.domid = info->u.pirq.domid; rc = HYPERVISOR_physdev_op(PHYSDEVOP_unmap_pirq, &unmap_irq); if (rc) { printk(KERN_WARNING "unmap irq failed %d\n", rc); diff --git a/include/xen/events.h b/include/xen/events.h index f1b87ad..9aecc0b 100644 --- a/include/xen/events.h +++ b/include/xen/events.h @@ -85,7 +85,8 @@ int xen_bind_pirq_gsi_to_irq(unsigned gsi, int xen_allocate_pirq_msi(struct pci_dev *dev, struct msi_desc *msidesc); /* Bind an PSI pirq to an irq. */ int xen_bind_pirq_msi_to_irq(struct pci_dev *dev, struct msi_desc *msidesc, - int pirq, int vector, const char *name); + int pirq, int vector, const char *name, + domid_t domid); #endif /* De-allocates the above mentioned physical interrupt. */ -- cgit v0.10.2 From c7c2c3a28657cfdcef50c02b18ccca3761209e17 Mon Sep 17 00:00:00 2001 From: Konrad Rzeszutek Wilk Date: Mon, 8 Nov 2010 14:26:36 -0500 Subject: xen/irq: Add support to check if IRQ line is shared with other domains. We do this via the PHYSDEVOP_irq_status_query support hypervisor call. We will get a positive value if another domain has binded its PIRQ to the specified GSI (IRQ line). [v2: Deal with v2.6.37-rc1 rebase fallout] [v3: Deal with stable/irq.cleanup fallout] [v4: xen_ignore_irq->xen_test_irq_shared] Signed-off-by: Konrad Rzeszutek Wilk diff --git a/drivers/xen/events.c b/drivers/xen/events.c index ac0e228..0ac7a14 100644 --- a/drivers/xen/events.c +++ b/drivers/xen/events.c @@ -1508,6 +1508,18 @@ void xen_poll_irq(int irq) xen_poll_irq_timeout(irq, 0 /* no timeout */); } +/* Check whether the IRQ line is shared with other guests. */ +int xen_test_irq_shared(int irq) +{ + struct irq_info *info = info_for_irq(irq); + struct physdev_irq_status_query irq_status = { .irq = info->u.pirq.pirq }; + + if (HYPERVISOR_physdev_op(PHYSDEVOP_irq_status_query, &irq_status)) + return 0; + return !(irq_status.flags & XENIRQSTAT_shared); +} +EXPORT_SYMBOL_GPL(xen_test_irq_shared); + void xen_irq_resume(void) { unsigned int cpu, evtchn; diff --git a/include/xen/events.h b/include/xen/events.h index 9aecc0b..932e540 100644 --- a/include/xen/events.h +++ b/include/xen/events.h @@ -95,4 +95,7 @@ int xen_destroy_irq(int irq); /* Return irq from pirq */ int xen_irq_from_pirq(unsigned pirq); +/* Determine whether to ignore this IRQ if it is passed to a guest. */ +int xen_test_irq_shared(int irq); + #endif /* _XEN_EVENTS_H */ -- cgit v0.10.2 From e6197acc726ab3baa60375a5891d58c2ee87e0f3 Mon Sep 17 00:00:00 2001 From: Konrad Rzeszutek Wilk Date: Thu, 24 Feb 2011 14:20:12 -0500 Subject: xen/irq: Export 'xen_pirq_from_irq' function. We need this to find the real Xen PIRQ value for a device that requests an MSI or MSI-X. In the past we used 'xen_gsi_from_irq' since that function would return an Xen PIRQ or GSI depending on the provided IRQ. Now that we have seperated that we need to use the correct function. [v2: Deal with rebase on stable/irq.cleanup] Signed-off-by: Konrad Rzeszutek Wilk diff --git a/drivers/xen/events.c b/drivers/xen/events.c index 0ac7a14..e4e8e9a 100644 --- a/drivers/xen/events.c +++ b/drivers/xen/events.c @@ -763,6 +763,12 @@ out: return irq; } + +int xen_pirq_from_irq(unsigned irq) +{ + return pirq_from_irq(irq); +} +EXPORT_SYMBOL_GPL(xen_pirq_from_irq); int bind_evtchn_to_irq(unsigned int evtchn) { int irq; diff --git a/include/xen/events.h b/include/xen/events.h index 932e540..9af21e1 100644 --- a/include/xen/events.h +++ b/include/xen/events.h @@ -95,6 +95,9 @@ int xen_destroy_irq(int irq); /* Return irq from pirq */ int xen_irq_from_pirq(unsigned pirq); +/* Return the pirq allocated to the irq. */ +int xen_pirq_from_irq(unsigned irq); + /* Determine whether to ignore this IRQ if it is passed to a guest. */ int xen_test_irq_shared(int irq); -- cgit v0.10.2 From 1eff1ad0285038e309a81da4a004f071608309fb Mon Sep 17 00:00:00 2001 From: Konrad Rzeszutek Wilk Date: Wed, 16 Feb 2011 16:26:44 -0500 Subject: xen/irq: The Xen hypervisor cleans up the PIRQs if the other domain forgot. And if the other domain forgot to clean up its PIRQs we don't need to fail the operation. Just take a note of it and continue on. Signed-off-by: Konrad Rzeszutek Wilk diff --git a/drivers/xen/events.c b/drivers/xen/events.c index e4e8e9a..e51f3c5 100644 --- a/drivers/xen/events.c +++ b/drivers/xen/events.c @@ -728,7 +728,14 @@ int xen_destroy_irq(int irq) unmap_irq.pirq = info->u.pirq.pirq; unmap_irq.domid = info->u.pirq.domid; rc = HYPERVISOR_physdev_op(PHYSDEVOP_unmap_pirq, &unmap_irq); - if (rc) { + /* If another domain quits without making the pci_disable_msix + * call, the Xen hypervisor takes care of freeing the PIRQs + * (free_domain_pirqs). + */ + if ((rc == -ESRCH && info->u.pirq.domid != DOMID_SELF)) + printk(KERN_INFO "domain %d does not have %d anymore\n", + info->u.pirq.domid, info->u.pirq.pirq); + else if (rc) { printk(KERN_WARNING "unmap irq failed %d\n", rc); goto out; } -- cgit v0.10.2 From dfa8fc69d92f8418e1296d762f3b1624df59f0ac Mon Sep 17 00:00:00 2001 From: "John W. Linville" Date: Thu, 14 Apr 2011 10:38:22 -0400 Subject: ath9k: avoid using trinary operator w/ TX_STAT_INC MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Otherwise, you get this: CC [M] drivers/net/wireless/ath/ath9k/hif_usb.o drivers/net/wireless/ath/ath9k/hif_usb.c: In function ‘ath9k_skb_queue_complete’: drivers/net/wireless/ath/ath9k/hif_usb.c:230:12: error: expected expression before ‘do’ make[2]: *** [drivers/net/wireless/ath/ath9k/hif_usb.o] Error 1 make[1]: *** [drivers/net/wireless/ath/ath9k] Error 2 make: *** [drivers/net/wireless/ath/] Error 2 The TX_STAT_INC macro should probably be changed to accomodate such usage, although using a trinary operator in place of an if-else seems questionable to me anyway. Signed-off-by: John W. Linville Acked-by: Sujith Manoharan diff --git a/drivers/net/wireless/ath/ath9k/hif_usb.c b/drivers/net/wireless/ath/ath9k/hif_usb.c index 3b0efab..48bcc1a 100644 --- a/drivers/net/wireless/ath/ath9k/hif_usb.c +++ b/drivers/net/wireless/ath/ath9k/hif_usb.c @@ -227,7 +227,10 @@ static inline void ath9k_skb_queue_complete(struct hif_device_usb *hif_dev, while ((skb = __skb_dequeue(queue)) != NULL) { ath9k_htc_txcompletion_cb(hif_dev->htc_handle, skb, txok); - (txok) ? TX_STAT_INC(skb_success) : TX_STAT_INC(skb_failed); + if (txok) + TX_STAT_INC(skb_success); + else + TX_STAT_INC(skb_failed); } } -- cgit v0.10.2 From 10add41f2b7a7bc1a74ba7bb535a6745cac318a2 Mon Sep 17 00:00:00 2001 From: Rajkumar Manoharan Date: Tue, 12 Apr 2011 17:29:29 +0530 Subject: ath9k: Fix improper beacon slot selection in IBSS Request a re-configuration of Beacon related timers on the receipt of the first Beacon frame has to be set only for station mode. Setting beacon sync for IBSS is causing wrong beacon slot selection on beacon generation. Signed-off-by: Rajkumar Manoharan Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/beacon.c b/drivers/net/wireless/ath/ath9k/beacon.c index b56f69e..9193a38 100644 --- a/drivers/net/wireless/ath/ath9k/beacon.c +++ b/drivers/net/wireless/ath/ath9k/beacon.c @@ -744,7 +744,6 @@ void ath_beacon_config(struct ath_softc *sc, struct ieee80211_vif *vif) cur_conf->dtim_period = 1; ath_set_beacon(sc); - sc->ps_flags |= PS_BEACON_SYNC | PS_WAIT_FOR_BEACON; } void ath_set_beacon(struct ath_softc *sc) @@ -762,6 +761,12 @@ void ath_set_beacon(struct ath_softc *sc) break; case NL80211_IFTYPE_STATION: ath_beacon_config_sta(sc, cur_conf); + /* + * Request a re-configuration of Beacon related timers + * on the receipt of the first Beacon frame (i.e., + * after time sync with the AP). + */ + sc->ps_flags |= PS_BEACON_SYNC | PS_WAIT_FOR_BEACON; break; default: ath_dbg(common, ATH_DBG_CONFIG, -- cgit v0.10.2 From 7f94f05b24b47f6b70f2322b26876d0636329dfe Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Wed, 13 Apr 2011 21:56:42 +0200 Subject: ath5k: disable 5 GHz support if a 2.4 GHz radio is detected On a dual-radio dual-band AR5312 device, the calibration data is shared between the 5 GHz and the 2.4 GHz radio/MAC. Signed-off-by: Felix Fietkau Tested-by: Sedat Dilek Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath5k/caps.c b/drivers/net/wireless/ath/ath5k/caps.c index f77e8a7..7dd88e1 100644 --- a/drivers/net/wireless/ath/ath5k/caps.c +++ b/drivers/net/wireless/ath/ath5k/caps.c @@ -94,6 +94,9 @@ int ath5k_hw_set_capabilities(struct ath5k_hw *ah) } } + if ((ah->ah_radio_5ghz_revision & 0xf0) == AR5K_SREV_RAD_2112) + __clear_bit(AR5K_MODE_11A, caps->cap_mode); + /* Set number of supported TX queues */ if (ah->ah_version == AR5K_AR5210) caps->cap_queues.q_tx_num = AR5K_NUM_TX_QUEUES_NOQCU; -- cgit v0.10.2 From 0cb9e06b6359bfa82f46c38a0b43e72d90b84081 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Wed, 13 Apr 2011 21:56:43 +0200 Subject: ath: unshare struct ath_bus_ops between ath5k and ath9k This struct is not used in any common code, and moving it out of the ath header makes it easier to add more driver specific ops. Signed-off-by: Felix Fietkau Tested-by: Sedat Dilek Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath.h b/drivers/net/wireless/ath/ath.h index 6d7105b..7cf4317 100644 --- a/drivers/net/wireless/ath/ath.h +++ b/drivers/net/wireless/ath/ath.h @@ -123,14 +123,7 @@ struct ath_ops { }; struct ath_common; - -struct ath_bus_ops { - enum ath_bus_type ath_bus_type; - void (*read_cachesize)(struct ath_common *common, int *csz); - bool (*eeprom_read)(struct ath_common *common, u32 off, u16 *data); - void (*bt_coex_prep)(struct ath_common *common); - void (*extn_synch_en)(struct ath_common *common); -}; +struct ath_bus_ops; struct ath_common { void *ah; diff --git a/drivers/net/wireless/ath/ath5k/ath5k.h b/drivers/net/wireless/ath/ath5k/ath5k.h index e303db7..266e548 100644 --- a/drivers/net/wireless/ath/ath5k/ath5k.h +++ b/drivers/net/wireless/ath/ath5k/ath5k.h @@ -1155,6 +1155,12 @@ struct ath5k_hw { struct ath5k_rx_status *); }; +struct ath_bus_ops { + enum ath_bus_type ath_bus_type; + void (*read_cachesize)(struct ath_common *common, int *csz); + bool (*eeprom_read)(struct ath_common *common, u32 off, u16 *data); +}; + /* * Prototypes */ diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h index a778b66..073bc9e 100644 --- a/drivers/net/wireless/ath/ath9k/hw.h +++ b/drivers/net/wireless/ath/ath9k/hw.h @@ -846,6 +846,14 @@ struct ath_hw { u32 ent_mode; }; +struct ath_bus_ops { + enum ath_bus_type ath_bus_type; + void (*read_cachesize)(struct ath_common *common, int *csz); + bool (*eeprom_read)(struct ath_common *common, u32 off, u16 *data); + void (*bt_coex_prep)(struct ath_common *common); + void (*extn_synch_en)(struct ath_common *common); +}; + static inline struct ath_common *ath9k_hw_common(struct ath_hw *ah) { return &ah->common; -- cgit v0.10.2 From fa9bfd61e03e8dbcf110a93b373234d17a732233 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Wed, 13 Apr 2011 21:56:44 +0200 Subject: ath5k: add a new bus op for reading the mac address On AHB, the calibration data usually does not contain a valid MAC address, the correct MAC address is stored in the board config. Signed-off-by: Felix Fietkau Tested-by: Sedat Dilek Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath5k/ahb.c b/drivers/net/wireless/ath/ath5k/ahb.c index 82324e9..1374e64 100644 --- a/drivers/net/wireless/ath/ath5k/ahb.c +++ b/drivers/net/wireless/ath/ath5k/ahb.c @@ -18,6 +18,7 @@ #include #include +#include #include #include "ath5k.h" #include "debug.h" @@ -62,10 +63,27 @@ int ath5k_hw_read_srev(struct ath5k_hw *ah) return 0; } +static int ath5k_ahb_eeprom_read_mac(struct ath5k_hw *ah, u8 *mac) +{ + struct ath5k_softc *sc = ah->ah_sc; + struct platform_device *pdev = to_platform_device(sc->dev); + struct ar231x_board_config *bcfg = pdev->dev.platform_data; + u8 *cfg_mac; + + if (to_platform_device(sc->dev)->id == 0) + cfg_mac = bcfg->config->wlan0_mac; + else + cfg_mac = bcfg->config->wlan1_mac; + + memcpy(mac, cfg_mac, ETH_ALEN); + return 0; +} + static const struct ath_bus_ops ath_ahb_bus_ops = { .ath_bus_type = ATH_AHB, .read_cachesize = ath5k_ahb_read_cachesize, .eeprom_read = ath5k_ahb_eeprom_read, + .eeprom_read_mac = ath5k_ahb_eeprom_read_mac, }; /*Initialization*/ diff --git a/drivers/net/wireless/ath/ath5k/ath5k.h b/drivers/net/wireless/ath/ath5k/ath5k.h index 266e548..bb50700 100644 --- a/drivers/net/wireless/ath/ath5k/ath5k.h +++ b/drivers/net/wireless/ath/ath5k/ath5k.h @@ -1159,6 +1159,7 @@ struct ath_bus_ops { enum ath_bus_type ath_bus_type; void (*read_cachesize)(struct ath_common *common, int *csz); bool (*eeprom_read)(struct ath_common *common, u32 off, u16 *data); + int (*eeprom_read_mac)(struct ath5k_hw *ah, u8 *mac); }; /* @@ -1244,7 +1245,6 @@ int ath5k_hw_dma_stop(struct ath5k_hw *ah); /* EEPROM access functions */ int ath5k_eeprom_init(struct ath5k_hw *ah); void ath5k_eeprom_detach(struct ath5k_hw *ah); -int ath5k_eeprom_read_mac(struct ath5k_hw *ah, u8 *mac); /* Protocol Control Unit Functions */ diff --git a/drivers/net/wireless/ath/ath5k/base.c b/drivers/net/wireless/ath/ath5k/base.c index c7da004..7583841 100644 --- a/drivers/net/wireless/ath/ath5k/base.c +++ b/drivers/net/wireless/ath/ath5k/base.c @@ -2880,7 +2880,7 @@ ath5k_init(struct ieee80211_hw *hw) INIT_WORK(&sc->reset_work, ath5k_reset_work); INIT_DELAYED_WORK(&sc->tx_complete_work, ath5k_tx_complete_poll_work); - ret = ath5k_eeprom_read_mac(ah, mac); + ret = ath5k_hw_common(ah)->bus_ops->eeprom_read_mac(ah, mac); if (ret) { ATH5K_ERR(sc, "unable to read address from EEPROM\n"); goto err_queues; diff --git a/drivers/net/wireless/ath/ath5k/eeprom.c b/drivers/net/wireless/ath/ath5k/eeprom.c index fb12027..e9263e4 100644 --- a/drivers/net/wireless/ath/ath5k/eeprom.c +++ b/drivers/net/wireless/ath/ath5k/eeprom.c @@ -1732,35 +1732,6 @@ ath5k_eeprom_read_spur_chans(struct ath5k_hw *ah) return ret; } -/* - * Read the MAC address from eeprom - */ -int ath5k_eeprom_read_mac(struct ath5k_hw *ah, u8 *mac) -{ - u8 mac_d[ETH_ALEN] = {}; - u32 total, offset; - u16 data; - int octet; - - AR5K_EEPROM_READ(0x20, data); - - for (offset = 0x1f, octet = 0, total = 0; offset >= 0x1d; offset--) { - AR5K_EEPROM_READ(offset, data); - - total += data; - mac_d[octet + 1] = data & 0xff; - mac_d[octet] = data >> 8; - octet += 2; - } - - if (!total || total == 3 * 0xffff) - return -EINVAL; - - memcpy(mac, mac_d, ETH_ALEN); - - return 0; -} - /***********************\ * Init/Detach functions * diff --git a/drivers/net/wireless/ath/ath5k/pci.c b/drivers/net/wireless/ath/ath5k/pci.c index 66598a0..5cc4a2f 100644 --- a/drivers/net/wireless/ath/ath5k/pci.c +++ b/drivers/net/wireless/ath/ath5k/pci.c @@ -17,6 +17,7 @@ #include #include #include +#include #include "../ath.h" #include "ath5k.h" #include "debug.h" @@ -108,11 +109,42 @@ int ath5k_hw_read_srev(struct ath5k_hw *ah) return 0; } +/* + * Read the MAC address from eeprom or platform_data + */ +static int ath5k_pci_eeprom_read_mac(struct ath5k_hw *ah, u8 *mac) +{ + u8 mac_d[ETH_ALEN] = {}; + u32 total, offset; + u16 data; + int octet; + + AR5K_EEPROM_READ(0x20, data); + + for (offset = 0x1f, octet = 0, total = 0; offset >= 0x1d; offset--) { + AR5K_EEPROM_READ(offset, data); + + total += data; + mac_d[octet + 1] = data & 0xff; + mac_d[octet] = data >> 8; + octet += 2; + } + + if (!total || total == 3 * 0xffff) + return -EINVAL; + + memcpy(mac, mac_d, ETH_ALEN); + + return 0; +} + + /* Common ath_bus_opts structure */ static const struct ath_bus_ops ath_pci_bus_ops = { .ath_bus_type = ATH_PCI, .read_cachesize = ath5k_pci_read_cachesize, .eeprom_read = ath5k_pci_eeprom_read, + .eeprom_read_mac = ath5k_pci_eeprom_read_mac, }; /********************\ -- cgit v0.10.2 From 32377b6cf75247cbdd0640efb43bef992efe3b68 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Wed, 13 Apr 2011 21:56:45 +0200 Subject: ath5k: fix the EEPROM check for hw AES crypto support EEPROM version 5.0 adds a new field for disabling AES support, having an older version means that AES is present. This patch fixes hw AES crypto support on AR5312 boards, which have an older EEPROM version. Signed-off-by: Felix Fietkau Tested-by: Sedat Dilek Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath5k/attach.c b/drivers/net/wireless/ath/ath5k/attach.c index bc82405..326d7c8 100644 --- a/drivers/net/wireless/ath/ath5k/attach.c +++ b/drivers/net/wireless/ath/ath5k/attach.c @@ -318,7 +318,7 @@ int ath5k_hw_init(struct ath5k_softc *sc) AR5K_KEYTABLE_SIZE_5210 : AR5K_KEYTABLE_SIZE_5211); if (srev >= AR5K_SREV_AR5212_V4 && - (ee->ee_version >= AR5K_EEPROM_VERSION_5_0 && + (ee->ee_version < AR5K_EEPROM_VERSION_5_0 || !AR5K_EEPROM_AES_DIS(ee->ee_misc5))) common->crypt_caps |= ATH_CRYPT_CAP_CIPHER_AESCCM; -- cgit v0.10.2 From 3a9dddea89eb2132ba919fe04cb3b44a3b1e6db7 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Wed, 13 Apr 2011 21:56:46 +0200 Subject: ath5k: disable 5 GHz support for the dualband PHY chip on dual-radio AR5312 There are two variants of AR5312 dual-band devices, one single-radio and the other one dual-radio. On the dual-radio board, the first MAC only supports 5 GHz, even though it has a dual-band PHY. The 2.4 GHz part of this phy is used in pass-through mode, connecting the second MAC with the second PHY. Disable 2.4 GHz for the first MAC on an AR5312, but only if the board configuration indicates a dual-radio device. Signed-off-by: Felix Fietkau Tested-by: Sedat Dilek Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath5k/ahb.c b/drivers/net/wireless/ath/ath5k/ahb.c index 1374e64..ea99827 100644 --- a/drivers/net/wireless/ath/ath5k/ahb.c +++ b/drivers/net/wireless/ath/ath5k/ahb.c @@ -160,6 +160,16 @@ static int ath_ahb_probe(struct platform_device *pdev) else reg |= AR5K_AR5312_ENABLE_WLAN1; __raw_writel(reg, (void __iomem *) AR5K_AR5312_ENABLE); + + /* + * On a dual-band AR5312, the multiband radio is only + * used as pass-through. Disable 2 GHz support in the + * driver for it + */ + if (to_platform_device(sc->dev)->id == 0 && + (bcfg->config->flags & (BD_WLAN0|BD_WLAN1)) == + (BD_WLAN1|BD_WLAN0)) + __set_bit(ATH_STAT_2G_DISABLED, sc->status); } ret = ath5k_init_softc(sc, &ath_ahb_bus_ops); diff --git a/drivers/net/wireless/ath/ath5k/attach.c b/drivers/net/wireless/ath/ath5k/attach.c index 326d7c8..1588401 100644 --- a/drivers/net/wireless/ath/ath5k/attach.c +++ b/drivers/net/wireless/ath/ath5k/attach.c @@ -313,6 +313,11 @@ int ath5k_hw_init(struct ath5k_softc *sc) goto err; } + if (test_bit(ATH_STAT_2G_DISABLED, sc->status)) { + __clear_bit(AR5K_MODE_11B, ah->ah_capabilities.cap_mode); + __clear_bit(AR5K_MODE_11G, ah->ah_capabilities.cap_mode); + } + /* Crypto settings */ common->keymax = (sc->ah->ah_version == AR5K_AR5210 ? AR5K_KEYTABLE_SIZE_5210 : AR5K_KEYTABLE_SIZE_5211); diff --git a/drivers/net/wireless/ath/ath5k/base.h b/drivers/net/wireless/ath/ath5k/base.h index 4c4e360..b294f33 100644 --- a/drivers/net/wireless/ath/ath5k/base.h +++ b/drivers/net/wireless/ath/ath5k/base.h @@ -193,12 +193,13 @@ struct ath5k_softc { dma_addr_t desc_daddr; /* DMA (physical) address */ size_t desc_len; /* size of TX/RX descriptors */ - DECLARE_BITMAP(status, 5); + DECLARE_BITMAP(status, 6); #define ATH_STAT_INVALID 0 /* disable hardware accesses */ #define ATH_STAT_MRRETRY 1 /* multi-rate retry support */ #define ATH_STAT_PROMISC 2 #define ATH_STAT_LEDSOFT 3 /* enable LED gpio status */ #define ATH_STAT_STARTED 4 /* opened & irqs enabled */ +#define ATH_STAT_2G_DISABLED 5 /* multiband radio without 2G */ unsigned int filter_flags; /* HW flags, AR5K_RX_FILTER_* */ struct ieee80211_channel *curchan; /* current h/w channel */ -- cgit v0.10.2 From 600f5d909a54a8dccf8c8c23898fc2e91bc0953e Mon Sep 17 00:00:00 2001 From: Amitkumar Karwar Date: Wed, 13 Apr 2011 17:27:06 -0700 Subject: mwifiex: cleanup ioctl wait queue and abstraction layer 1) remove mwifiex_alloc_fill_wait_queue() and mwifiex_request_ioctl() 2) avoid dynamic allocation of wait queue 3) remove unnecessary mwifiex_error_code macros that were used mainly by the wait queue status code 4) remove some abstraction functions 5) split mwifiex_prepare_cmd() to mwifiex_send_cmd_async() and mwifiex_send_sync() to handle asynchronous and synchronous commands respectively Signed-off-by: Amitkumar Karwar Signed-off-by: Bing Zhao Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/mwifiex/11n.c b/drivers/net/wireless/mwifiex/11n.c index 73a6e62..edf4c27 100644 --- a/drivers/net/wireless/mwifiex/11n.c +++ b/drivers/net/wireless/mwifiex/11n.c @@ -541,9 +541,8 @@ mwifiex_cfg_tx_buf(struct mwifiex_private *priv, else if (priv->adapter->curr_tx_buf_size <= MWIFIEX_TX_DATA_BUF_SIZE_8K) curr_tx_buf_size = MWIFIEX_TX_DATA_BUF_SIZE_8K; if (curr_tx_buf_size != tx_buf) - mwifiex_prepare_cmd(priv, HostCmd_CMD_RECONFIGURE_TX_BUFF, - HostCmd_ACT_GEN_SET, 0, - NULL, &tx_buf); + mwifiex_send_cmd_async(priv, HostCmd_CMD_RECONFIGURE_TX_BUFF, + HostCmd_ACT_GEN_SET, 0, &tx_buf); return; } @@ -694,8 +693,8 @@ int mwifiex_send_addba(struct mwifiex_private *priv, int tid, u8 *peer_mac) memcpy(&add_ba_req.peer_mac_addr, peer_mac, ETH_ALEN); /* We don't wait for the response of this command */ - ret = mwifiex_prepare_cmd(priv, HostCmd_CMD_11N_ADDBA_REQ, - 0, 0, NULL, &add_ba_req); + ret = mwifiex_send_cmd_async(priv, HostCmd_CMD_11N_ADDBA_REQ, + 0, 0, &add_ba_req); return ret; } @@ -722,8 +721,8 @@ int mwifiex_send_delba(struct mwifiex_private *priv, int tid, u8 *peer_mac, memcpy(&delba.peer_mac_addr, peer_mac, ETH_ALEN); /* We don't wait for the response of this command */ - ret = mwifiex_prepare_cmd(priv, HostCmd_CMD_11N_DELBA, - HostCmd_ACT_GEN_SET, 0, NULL, &delba); + ret = mwifiex_send_cmd_async(priv, HostCmd_CMD_11N_DELBA, + HostCmd_ACT_GEN_SET, 0, &delba); return ret; } diff --git a/drivers/net/wireless/mwifiex/11n_rxreorder.c b/drivers/net/wireless/mwifiex/11n_rxreorder.c index 8e94e62..ef46d0a 100644 --- a/drivers/net/wireless/mwifiex/11n_rxreorder.c +++ b/drivers/net/wireless/mwifiex/11n_rxreorder.c @@ -609,7 +609,7 @@ void mwifiex_11n_ba_stream_timeout(struct mwifiex_private *priv, delba.del_ba_param_set |= cpu_to_le16( (u16) event->origninator << DELBA_INITIATOR_POS); delba.reason_code = cpu_to_le16(WLAN_REASON_QSTA_TIMEOUT); - mwifiex_prepare_cmd(priv, HostCmd_CMD_11N_DELBA, 0, 0, NULL, &delba); + mwifiex_send_cmd_async(priv, HostCmd_CMD_11N_DELBA, 0, 0, &delba); return; } diff --git a/drivers/net/wireless/mwifiex/README b/drivers/net/wireless/mwifiex/README index 338377f..b55bade 100644 --- a/drivers/net/wireless/mwifiex/README +++ b/drivers/net/wireless/mwifiex/README @@ -157,7 +157,7 @@ info mp_wr_bitmap = cmd_resp_received = <0/1, no cmd response to process/response received and yet to process> event_received = <0/1, no event to process/event received and yet to process> - ioctl_pending = + cmd_pending = tx_pending = rx_pending = diff --git a/drivers/net/wireless/mwifiex/cfg80211.c b/drivers/net/wireless/mwifiex/cfg80211.c index ec0895f..a1ff490 100644 --- a/drivers/net/wireless/mwifiex/cfg80211.c +++ b/drivers/net/wireless/mwifiex/cfg80211.c @@ -139,8 +139,16 @@ mwifiex_cfg80211_set_tx_power(struct wiphy *wiphy, { int ret = 0; struct mwifiex_private *priv = mwifiex_cfg80211_get_priv(wiphy); + struct mwifiex_power_cfg power_cfg; - ret = mwifiex_set_tx_power(priv, type, dbm); + if (type == NL80211_TX_POWER_FIXED) { + power_cfg.is_power_auto = 0; + power_cfg.power_level = dbm; + } else { + power_cfg.is_power_auto = 1; + } + + ret = mwifiex_set_tx_power(priv, &power_cfg); return ret; } @@ -157,13 +165,15 @@ mwifiex_cfg80211_set_power_mgmt(struct wiphy *wiphy, { int ret = 0; struct mwifiex_private *priv = mwifiex_cfg80211_get_priv(wiphy); + u32 ps_mode; if (timeout) wiphy_dbg(wiphy, "info: ignoring the timeout value" " for IEEE power save\n"); - ret = mwifiex_drv_set_power(priv, enabled); + ps_mode = enabled; + ret = mwifiex_drv_set_power(priv, &ps_mode); return ret; } @@ -291,8 +301,8 @@ static int mwifiex_send_domain_info_cmd_fw(struct wiphy *wiphy) domain_info->no_of_triplet = no_of_triplet; /* Send cmd to FW to set domain info */ - ret = mwifiex_prepare_cmd(priv, HostCmd_CMD_802_11D_DOMAIN_INFO, - HostCmd_ACT_GEN_SET, 0, NULL, NULL); + ret = mwifiex_send_cmd_async(priv, HostCmd_CMD_802_11D_DOMAIN_INFO, + HostCmd_ACT_GEN_SET, 0, NULL); if (ret) wiphy_err(wiphy, "11D: setting domain info in FW\n"); @@ -347,7 +357,6 @@ mwifiex_set_rf_channel(struct mwifiex_private *priv, { struct mwifiex_chan_freq_power cfp; int ret = 0; - int status = 0; struct mwifiex_ds_band_cfg band_cfg; u32 config_bands = 0; struct wiphy *wiphy = priv->wdev->wiphy; @@ -370,10 +379,9 @@ mwifiex_set_rf_channel(struct mwifiex_private *priv, band_cfg.sec_chan_offset = mwifiex_cfg80211_channel_type_to_mwifiex_channels (channel_type); - status = mwifiex_radio_ioctl_band_cfg(priv, HostCmd_ACT_GEN_SET, - &band_cfg); + ret = mwifiex_set_radio_band_cfg(priv, &band_cfg); - if (status) + if (ret) return -EFAULT; mwifiex_send_domain_info_cmd_fw(wiphy); } @@ -389,8 +397,8 @@ mwifiex_set_rf_channel(struct mwifiex_private *priv, /* Convert frequency to channel */ cfp.channel = ieee80211_frequency_to_channel(chan->center_freq); - status = mwifiex_bss_ioctl_channel(priv, HostCmd_ACT_GEN_SET, &cfp); - if (status) + ret = mwifiex_bss_set_channel(priv, &cfp); + if (ret) return -EFAULT; ret = mwifiex_drv_change_adhoc_chan(priv, cfp.channel); @@ -422,66 +430,45 @@ mwifiex_cfg80211_set_channel(struct wiphy *wiphy, struct net_device *dev, /* * This function sets the fragmentation threshold. * - * This function creates an IOCTL request, populates it accordingly - * and issues an IOCTL. - * - * The fragmentation threshold value must lies between MWIFIEX_FRAG_MIN_VALUE + * The fragmentation threshold value must lie between MWIFIEX_FRAG_MIN_VALUE * and MWIFIEX_FRAG_MAX_VALUE. */ static int mwifiex_set_frag(struct mwifiex_private *priv, u32 frag_thr) { int ret = 0; - int status = 0; - struct mwifiex_wait_queue *wait = NULL; - u8 wait_option = MWIFIEX_IOCTL_WAIT; if (frag_thr < MWIFIEX_FRAG_MIN_VALUE || frag_thr > MWIFIEX_FRAG_MAX_VALUE) return -EINVAL; - wait = mwifiex_alloc_fill_wait_queue(priv, wait_option); - if (!wait) - return -ENOMEM; + /* Send request to firmware */ + ret = mwifiex_send_cmd_sync(priv, HostCmd_CMD_802_11_SNMP_MIB, + HostCmd_ACT_GEN_SET, FRAG_THRESH_I, + &frag_thr); - status = mwifiex_snmp_mib_ioctl(priv, wait, FRAG_THRESH_I, - HostCmd_ACT_GEN_SET, &frag_thr); - - if (mwifiex_request_ioctl(priv, wait, status, wait_option)) - ret = -EFAULT; - - kfree(wait); return ret; } /* * This function sets the RTS threshold. - * - * This function creates an IOCTL request, populates it accordingly - * and issues an IOCTL. + + * The rts value must lie between MWIFIEX_RTS_MIN_VALUE + * and MWIFIEX_RTS_MAX_VALUE. */ static int mwifiex_set_rts(struct mwifiex_private *priv, u32 rts_thr) { int ret = 0; - struct mwifiex_wait_queue *wait = NULL; - int status = 0; - u8 wait_option = MWIFIEX_IOCTL_WAIT; if (rts_thr < MWIFIEX_RTS_MIN_VALUE || rts_thr > MWIFIEX_RTS_MAX_VALUE) rts_thr = MWIFIEX_RTS_MAX_VALUE; - wait = mwifiex_alloc_fill_wait_queue(priv, wait_option); - if (!wait) - return -ENOMEM; - - status = mwifiex_snmp_mib_ioctl(priv, wait, RTS_THRESH_I, - HostCmd_ACT_GEN_SET, &rts_thr); - - if (mwifiex_request_ioctl(priv, wait, status, wait_option)) - ret = -EFAULT; + /* Send request to firmware */ + ret = mwifiex_send_cmd_sync(priv, HostCmd_CMD_802_11_SNMP_MIB, + HostCmd_ACT_GEN_SET, RTS_THRESH_I, + &rts_thr); - kfree(wait); return ret; } @@ -518,7 +505,6 @@ mwifiex_cfg80211_change_virtual_intf(struct wiphy *wiphy, { int ret = 0; struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev); - struct mwifiex_wait_queue *wait = NULL; if (priv->bss_mode == type) { wiphy_warn(wiphy, "already set to required type\n"); @@ -545,24 +531,13 @@ mwifiex_cfg80211_change_virtual_intf(struct wiphy *wiphy, return -EINVAL; } - wait = mwifiex_alloc_fill_wait_queue(priv, MWIFIEX_IOCTL_WAIT); - if (!wait) - return -ENOMEM; - - mwifiex_deauthenticate(priv, wait, NULL); + mwifiex_deauthenticate(priv, NULL); priv->sec_info.authentication_mode = NL80211_AUTHTYPE_OPEN_SYSTEM; - ret = mwifiex_prepare_cmd(priv, HostCmd_CMD_SET_BSS_MODE, - HostCmd_ACT_GEN_SET, 0, wait, NULL); - if (!ret) - ret = -EINPROGRESS; + ret = mwifiex_send_cmd_sync(priv, HostCmd_CMD_SET_BSS_MODE, + HostCmd_ACT_GEN_SET, 0, NULL); - ret = mwifiex_request_ioctl(priv, wait, ret, MWIFIEX_IOCTL_WAIT); - if (ret) - ret = -EFAULT; - - kfree(wait); return ret; } @@ -592,7 +567,7 @@ mwifiex_dump_station_info(struct mwifiex_private *priv, /* Get signal information from the firmware */ memset(&signal, 0, sizeof(struct mwifiex_ds_get_signal)); - if (mwifiex_get_signal_info(priv, MWIFIEX_IOCTL_WAIT, &signal)) { + if (mwifiex_get_signal_info(priv, &signal)) { dev_err(priv->adapter->dev, "getting signal information\n"); ret = -EFAULT; } @@ -750,7 +725,7 @@ mwifiex_cfg80211_disconnect(struct wiphy *wiphy, struct net_device *dev, return -EBUSY; priv->disconnect = 1; - if (mwifiex_disconnect(priv, MWIFIEX_IOCTL_WAIT, NULL)) + if (mwifiex_deauthenticate(priv, NULL)) return -EFAULT; wiphy_dbg(wiphy, "info: successfully disconnected from %pM:" @@ -838,8 +813,8 @@ static int mwifiex_inform_bss_from_scan_result(struct mwifiex_private *priv, u8 element_id, element_len; memset(&scan_resp, 0, sizeof(scan_resp)); - if (mwifiex_get_scan_table(priv, MWIFIEX_IOCTL_WAIT, &scan_resp)) - return -EFAULT; + scan_resp.scan_table = (u8 *) priv->adapter->scan_table; + scan_resp.num_in_scan_table = priv->adapter->num_in_scan_table; #define MAX_IE_BUF 2048 ie_buf = kzalloc(MAX_IE_BUF, GFP_KERNEL); @@ -986,7 +961,7 @@ mwifiex_cfg80211_assoc(struct mwifiex_private *priv, size_t ssid_len, u8 *ssid, } /* disconnect before try to associate */ - mwifiex_disconnect(priv, MWIFIEX_IOCTL_WAIT, NULL); + mwifiex_deauthenticate(priv, NULL); if (channel) ret = mwifiex_set_rf_channel(priv, channel, @@ -1046,7 +1021,7 @@ mwifiex_cfg80211_assoc(struct mwifiex_private *priv, size_t ssid_len, u8 *ssid, } done: /* Do specific SSID scanning */ - if (mwifiex_request_scan(priv, MWIFIEX_IOCTL_WAIT, &req_ssid)) { + if (mwifiex_request_scan(priv, &req_ssid)) { dev_err(priv->adapter->dev, "scan error\n"); return -EFAULT; } @@ -1055,8 +1030,7 @@ done: memcpy(&ssid_bssid.ssid, &req_ssid, sizeof(struct mwifiex_802_11_ssid)); if (mode != NL80211_IFTYPE_ADHOC) { - if (mwifiex_find_best_bss(priv, MWIFIEX_IOCTL_WAIT, - &ssid_bssid)) + if (mwifiex_find_best_bss(priv, &ssid_bssid)) return -EFAULT; /* Inform the BSS information to kernel, otherwise * kernel will give a panic after successful assoc */ @@ -1072,7 +1046,10 @@ done: /* Connect to BSS by ESSID */ memset(&ssid_bssid.bssid, 0, ETH_ALEN); - if (mwifiex_bss_start(priv, MWIFIEX_IOCTL_WAIT, &ssid_bssid)) + if (!netif_queue_stopped(priv->netdev)) + netif_stop_queue(priv->netdev); + + if (mwifiex_bss_start(priv, &ssid_bssid)) return -EFAULT; if (mode == NL80211_IFTYPE_ADHOC) { @@ -1176,7 +1153,7 @@ mwifiex_cfg80211_leave_ibss(struct wiphy *wiphy, struct net_device *dev) wiphy_dbg(wiphy, "info: disconnecting from essid %pM\n", priv->cfg_bssid); - if (mwifiex_disconnect(priv, MWIFIEX_IOCTL_WAIT, NULL)) + if (mwifiex_deauthenticate(priv, NULL)) return -EFAULT; queue_work(priv->workqueue, &priv->cfg_workqueue); diff --git a/drivers/net/wireless/mwifiex/cmdevt.c b/drivers/net/wireless/mwifiex/cmdevt.c index 8676480..bb6fecd 100644 --- a/drivers/net/wireless/mwifiex/cmdevt.c +++ b/drivers/net/wireless/mwifiex/cmdevt.c @@ -36,11 +36,12 @@ static void mwifiex_init_cmd_node(struct mwifiex_private *priv, struct cmd_ctrl_node *cmd_node, - u32 cmd_oid, void *wait_queue, void *data_buf) + u32 cmd_oid, void *data_buf) { cmd_node->priv = priv; cmd_node->cmd_oid = cmd_oid; - cmd_node->wq_buf = wait_queue; + cmd_node->wait_q_enabled = priv->adapter->cmd_wait_q_required; + priv->adapter->cmd_wait_q_required = false; cmd_node->data_buf = data_buf; cmd_node->cmd_skb = cmd_node->skb; } @@ -86,8 +87,8 @@ mwifiex_clean_cmd_node(struct mwifiex_adapter *adapter, { cmd_node->cmd_oid = 0; cmd_node->cmd_flag = 0; - cmd_node->wq_buf = NULL; cmd_node->data_buf = NULL; + cmd_node->wait_q_enabled = false; if (cmd_node->resp_skb) { mwifiex_recv_complete(adapter, cmd_node->resp_skb, 0); @@ -98,30 +99,6 @@ mwifiex_clean_cmd_node(struct mwifiex_adapter *adapter, } /* - * This function returns a command node from the pending queue which - * matches the given IOCTL request. - */ -static struct cmd_ctrl_node * -mwifiex_get_pending_ioctl_cmd(struct mwifiex_adapter *adapter, - struct mwifiex_wait_queue *wait_queue) -{ - unsigned long flags; - struct cmd_ctrl_node *cmd_node; - - spin_lock_irqsave(&adapter->cmd_pending_q_lock, flags); - list_for_each_entry(cmd_node, &adapter->cmd_pending_q, list) { - if (cmd_node->wq_buf == wait_queue) { - spin_unlock_irqrestore(&adapter->cmd_pending_q_lock, - flags); - return cmd_node; - } - } - spin_unlock_irqrestore(&adapter->cmd_pending_q_lock, flags); - - return NULL; -} - -/* * This function sends a host command to the firmware. * * The function copies the host command into the driver command @@ -155,7 +132,6 @@ static int mwifiex_dnld_cmd_to_fw(struct mwifiex_private *priv, struct mwifiex_adapter *adapter = priv->adapter; int ret = 0; struct host_cmd_ds_command *host_cmd; - struct mwifiex_wait_queue *wait_queue = NULL; uint16_t cmd_code; uint16_t cmd_size; struct timeval tstamp; @@ -165,15 +141,13 @@ static int mwifiex_dnld_cmd_to_fw(struct mwifiex_private *priv, return -1; host_cmd = (struct host_cmd_ds_command *) (cmd_node->cmd_skb->data); - if (cmd_node->wq_buf) - wait_queue = (struct mwifiex_wait_queue *) cmd_node->wq_buf; /* Sanity test */ if (host_cmd == NULL || host_cmd->size == 0) { dev_err(adapter->dev, "DNLD_CMD: host_cmd is null" " or cmd size is 0, not sending\n"); - if (wait_queue) - wait_queue->status = MWIFIEX_ERROR_CMD_DNLD_FAIL; + if (cmd_node->wait_q_enabled) + adapter->cmd_wait_q.status = -1; mwifiex_insert_cmd_to_free_q(adapter, cmd_node); return -1; } @@ -210,8 +184,8 @@ static int mwifiex_dnld_cmd_to_fw(struct mwifiex_private *priv, if (ret == -1) { dev_err(adapter->dev, "DNLD_CMD: host to card failed\n"); - if (wait_queue) - wait_queue->status = MWIFIEX_ERROR_CMD_DNLD_FAIL; + if (cmd_node->wait_q_enabled) + adapter->cmd_wait_q.status = -1; mwifiex_insert_cmd_to_free_q(adapter, adapter->curr_cmd); spin_lock_irqsave(&adapter->mwifiex_cmd_lock, flags); @@ -437,7 +411,31 @@ int mwifiex_process_event(struct mwifiex_adapter *adapter) } /* - * This function prepares a command before sending it to the firmware. + * This function is used to send synchronous command to the firmware. + * + * it allocates a wait queue for the command and wait for the command + * response. + */ +int mwifiex_send_cmd_sync(struct mwifiex_private *priv, uint16_t cmd_no, + u16 cmd_action, u32 cmd_oid, void *data_buf) +{ + int ret = 0; + struct mwifiex_adapter *adapter = priv->adapter; + + adapter->cmd_wait_q_required = true; + adapter->cmd_wait_q.condition = false; + + ret = mwifiex_send_cmd_async(priv, cmd_no, cmd_action, cmd_oid, + data_buf); + if (!ret) + ret = mwifiex_wait_queue_complete(adapter); + + return ret; +} + + +/* + * This function prepares a command and asynchronously send it to the firmware. * * Preparation includes - * - Sanity tests to make sure the card is still present or the FW @@ -447,9 +445,8 @@ int mwifiex_process_event(struct mwifiex_adapter *adapter) * - Fill up the non-default parameters and buffer pointers * - Add the command to pending queue */ -int mwifiex_prepare_cmd(struct mwifiex_private *priv, uint16_t cmd_no, - u16 cmd_action, u32 cmd_oid, - void *wait_queue, void *data_buf) +int mwifiex_send_cmd_async(struct mwifiex_private *priv, uint16_t cmd_no, + u16 cmd_action, u32 cmd_oid, void *data_buf) { int ret = 0; struct mwifiex_adapter *adapter = priv->adapter; @@ -487,7 +484,7 @@ int mwifiex_prepare_cmd(struct mwifiex_private *priv, uint16_t cmd_no, } /* Initialize the command node */ - mwifiex_init_cmd_node(priv, cmd_node, cmd_oid, wait_queue, data_buf); + mwifiex_init_cmd_node(priv, cmd_node, cmd_oid, data_buf); if (!cmd_node->cmd_skb) { dev_err(adapter->dev, "PREP_CMD: no free cmd buf\n"); @@ -537,18 +534,13 @@ void mwifiex_insert_cmd_to_free_q(struct mwifiex_adapter *adapter, struct cmd_ctrl_node *cmd_node) { - struct mwifiex_wait_queue *wait_queue = NULL; unsigned long flags; if (cmd_node == NULL) return; - if (cmd_node->wq_buf) { - wait_queue = (struct mwifiex_wait_queue *) cmd_node->wq_buf; - if (wait_queue->status != MWIFIEX_ERROR_NO_ERROR) - mwifiex_ioctl_complete(adapter, wait_queue, -1); - else - mwifiex_ioctl_complete(adapter, wait_queue, 0); - } + + if (cmd_node->wait_q_enabled) + mwifiex_complete_cmd(adapter); /* Clean the node */ mwifiex_clean_cmd_node(adapter, cmd_node); @@ -694,7 +686,6 @@ int mwifiex_process_cmdresp(struct mwifiex_adapter *adapter) uint16_t orig_cmdresp_no; uint16_t cmdresp_no; uint16_t cmdresp_result; - struct mwifiex_wait_queue *wait_queue = NULL; struct timeval tstamp; unsigned long flags; @@ -708,10 +699,6 @@ int mwifiex_process_cmdresp(struct mwifiex_adapter *adapter) return -1; } - if (adapter->curr_cmd->wq_buf) - wait_queue = (struct mwifiex_wait_queue *) - adapter->curr_cmd->wq_buf; - adapter->num_cmd_timeout = 0; resp = (struct host_cmd_ds_command *) adapter->curr_cmd->resp_skb->data; @@ -766,8 +753,8 @@ int mwifiex_process_cmdresp(struct mwifiex_adapter *adapter) if (!(orig_cmdresp_no & HostCmd_RET_BIT)) { dev_err(adapter->dev, "CMD_RESP: invalid cmd resp\n"); - if (wait_queue) - wait_queue->status = MWIFIEX_ERROR_FW_CMDRESP; + if (adapter->curr_cmd->wait_q_enabled) + adapter->cmd_wait_q.status = -1; mwifiex_insert_cmd_to_free_q(adapter, adapter->curr_cmd); spin_lock_irqsave(&adapter->mwifiex_cmd_lock, flags); @@ -783,8 +770,7 @@ int mwifiex_process_cmdresp(struct mwifiex_adapter *adapter) ret = mwifiex_ret_802_11_hs_cfg(priv, resp); } else { /* handle response */ - ret = mwifiex_process_sta_cmdresp(priv, cmdresp_no, resp, - wait_queue); + ret = mwifiex_process_sta_cmdresp(priv, cmdresp_no, resp); } /* Check init command response */ @@ -799,10 +785,10 @@ int mwifiex_process_cmdresp(struct mwifiex_adapter *adapter) } if (adapter->curr_cmd) { - if (wait_queue && (!ret)) - wait_queue->status = MWIFIEX_ERROR_NO_ERROR; - else if (wait_queue && (ret == -1)) - wait_queue->status = MWIFIEX_ERROR_CMD_RESP_FAIL; + if (adapter->curr_cmd->wait_q_enabled && (!ret)) + adapter->cmd_wait_q.status = 0; + else if (adapter->curr_cmd->wait_q_enabled && (ret == -1)) + adapter->cmd_wait_q.status = -1; /* Clean up and put current command back to cmd_free_q */ mwifiex_insert_cmd_to_free_q(adapter, adapter->curr_cmd); @@ -826,7 +812,6 @@ mwifiex_cmd_timeout_func(unsigned long function_context) struct mwifiex_adapter *adapter = (struct mwifiex_adapter *) function_context; struct cmd_ctrl_node *cmd_node = NULL; - struct mwifiex_wait_queue *wait_queue = NULL; struct timeval tstamp; adapter->num_cmd_timeout++; @@ -836,10 +821,8 @@ mwifiex_cmd_timeout_func(unsigned long function_context) return; } cmd_node = adapter->curr_cmd; - if (cmd_node->wq_buf) { - wait_queue = (struct mwifiex_wait_queue *) cmd_node->wq_buf; - wait_queue->status = MWIFIEX_ERROR_CMD_TIMEOUT; - } + if (cmd_node->wait_q_enabled) + adapter->cmd_wait_q.status = -ETIMEDOUT; if (cmd_node) { adapter->dbg.timeout_cmd_id = @@ -903,18 +886,15 @@ void mwifiex_cancel_all_pending_cmd(struct mwifiex_adapter *adapter) { struct cmd_ctrl_node *cmd_node = NULL, *tmp_node = NULL; - struct mwifiex_wait_queue *wait_queue = NULL; unsigned long flags; /* Cancel current cmd */ - if ((adapter->curr_cmd) && (adapter->curr_cmd->wq_buf)) { - wait_queue = - (struct mwifiex_wait_queue *) adapter->curr_cmd->wq_buf; + if ((adapter->curr_cmd) && (adapter->curr_cmd->wait_q_enabled)) { spin_lock_irqsave(&adapter->mwifiex_cmd_lock, flags); - adapter->curr_cmd->wq_buf = NULL; + adapter->curr_cmd->wait_q_enabled = false; spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock, flags); - wait_queue->status = MWIFIEX_ERROR_CMD_CANCEL; - mwifiex_ioctl_complete(adapter, wait_queue, -1); + adapter->cmd_wait_q.status = -1; + mwifiex_complete_cmd(adapter); } /* Cancel all pending command */ spin_lock_irqsave(&adapter->cmd_pending_q_lock, flags); @@ -923,12 +903,10 @@ mwifiex_cancel_all_pending_cmd(struct mwifiex_adapter *adapter) list_del(&cmd_node->list); spin_unlock_irqrestore(&adapter->cmd_pending_q_lock, flags); - if (cmd_node->wq_buf) { - wait_queue = - (struct mwifiex_wait_queue *) cmd_node->wq_buf; - wait_queue->status = MWIFIEX_ERROR_CMD_CANCEL; - mwifiex_ioctl_complete(adapter, wait_queue, -1); - cmd_node->wq_buf = NULL; + if (cmd_node->wait_q_enabled) { + adapter->cmd_wait_q.status = -1; + mwifiex_complete_cmd(adapter); + cmd_node->wait_q_enabled = false; } mwifiex_insert_cmd_to_free_q(adapter, cmd_node); spin_lock_irqsave(&adapter->cmd_pending_q_lock, flags); @@ -942,7 +920,7 @@ mwifiex_cancel_all_pending_cmd(struct mwifiex_adapter *adapter) list_del(&cmd_node->list); spin_unlock_irqrestore(&adapter->scan_pending_q_lock, flags); - cmd_node->wq_buf = NULL; + cmd_node->wait_q_enabled = false; mwifiex_insert_cmd_to_free_q(adapter, cmd_node); spin_lock_irqsave(&adapter->scan_pending_q_lock, flags); } @@ -964,8 +942,7 @@ mwifiex_cancel_all_pending_cmd(struct mwifiex_adapter *adapter) * are cancelled. */ void -mwifiex_cancel_pending_ioctl(struct mwifiex_adapter *adapter, - struct mwifiex_wait_queue *wait_queue) +mwifiex_cancel_pending_ioctl(struct mwifiex_adapter *adapter) { struct cmd_ctrl_node *cmd_node = NULL, *tmp_node = NULL; unsigned long cmd_flags; @@ -974,45 +951,33 @@ mwifiex_cancel_pending_ioctl(struct mwifiex_adapter *adapter, uint16_t cancel_scan_cmd = false; if ((adapter->curr_cmd) && - (adapter->curr_cmd->wq_buf == wait_queue)) { + (adapter->curr_cmd->wait_q_enabled)) { spin_lock_irqsave(&adapter->mwifiex_cmd_lock, cmd_flags); cmd_node = adapter->curr_cmd; - cmd_node->wq_buf = NULL; + cmd_node->wait_q_enabled = false; cmd_node->cmd_flag |= CMD_F_CANCELED; - spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock, cmd_flags); - } - - spin_lock_irqsave(&adapter->mwifiex_cmd_lock, cmd_flags); - while (1) { - cmd_node = mwifiex_get_pending_ioctl_cmd(adapter, wait_queue); - if (!cmd_node) - break; - spin_lock_irqsave(&adapter->cmd_pending_q_lock, cmd_pending_q_flags); list_del(&cmd_node->list); spin_unlock_irqrestore(&adapter->cmd_pending_q_lock, cmd_pending_q_flags); - - cmd_node->wq_buf = NULL; mwifiex_insert_cmd_to_free_q(adapter, cmd_node); + spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock, cmd_flags); } - spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock, cmd_flags); + /* Cancel all pending scan command */ spin_lock_irqsave(&adapter->scan_pending_q_lock, scan_pending_q_flags); list_for_each_entry_safe(cmd_node, tmp_node, &adapter->scan_pending_q, list) { - if (cmd_node->wq_buf == wait_queue) { - list_del(&cmd_node->list); - spin_unlock_irqrestore(&adapter->scan_pending_q_lock, - scan_pending_q_flags); - cmd_node->wq_buf = NULL; - mwifiex_insert_cmd_to_free_q(adapter, cmd_node); - spin_lock_irqsave(&adapter->scan_pending_q_lock, - scan_pending_q_flags); - cancel_scan_cmd = true; - } + list_del(&cmd_node->list); + spin_unlock_irqrestore(&adapter->scan_pending_q_lock, + scan_pending_q_flags); + cmd_node->wait_q_enabled = false; + mwifiex_insert_cmd_to_free_q(adapter, cmd_node); + spin_lock_irqsave(&adapter->scan_pending_q_lock, + scan_pending_q_flags); + cancel_scan_cmd = true; } spin_unlock_irqrestore(&adapter->scan_pending_q_lock, scan_pending_q_flags); @@ -1022,8 +987,8 @@ mwifiex_cancel_pending_ioctl(struct mwifiex_adapter *adapter, adapter->scan_processing = false; spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock, cmd_flags); } - wait_queue->status = MWIFIEX_ERROR_CMD_CANCEL; - mwifiex_ioctl_complete(adapter, wait_queue, -1); + adapter->cmd_wait_q.status = -1; + mwifiex_complete_cmd(adapter); return; } diff --git a/drivers/net/wireless/mwifiex/debugfs.c b/drivers/net/wireless/mwifiex/debugfs.c index 63b0969..77d7c77 100644 --- a/drivers/net/wireless/mwifiex/debugfs.c +++ b/drivers/net/wireless/mwifiex/debugfs.c @@ -129,8 +129,8 @@ static struct mwifiex_debug_data items[] = { item_addr(event_received), 1}, /* variables defined in struct mwifiex_adapter */ - {"ioctl_pending", adapter_item_size(ioctl_pending), - adapter_item_addr(ioctl_pending), 1}, + {"cmd_pending", adapter_item_size(cmd_pending), + adapter_item_addr(cmd_pending), 1}, {"tx_pending", adapter_item_size(tx_pending), adapter_item_addr(tx_pending), 1}, {"rx_pending", adapter_item_size(rx_pending), diff --git a/drivers/net/wireless/mwifiex/decl.h b/drivers/net/wireless/mwifiex/decl.h index c3c15f9..8364b62 100644 --- a/drivers/net/wireless/mwifiex/decl.h +++ b/drivers/net/wireless/mwifiex/decl.h @@ -61,23 +61,6 @@ #define MWIFIEX_BUF_FLAG_REQUEUED_PKT BIT(0) -enum mwifiex_error_code { - MWIFIEX_ERROR_NO_ERROR = 0, - MWIFIEX_ERROR_FW_NOT_READY = 0x00000001, - MWIFIEX_ERROR_FW_BUSY, - MWIFIEX_ERROR_FW_CMDRESP, - MWIFIEX_ERROR_PKT_SIZE_INVALID = 0x80000001, - MWIFIEX_ERROR_PKT_TIMEOUT, - MWIFIEX_ERROR_CMD_INVALID, - MWIFIEX_ERROR_CMD_TIMEOUT, - MWIFIEX_ERROR_CMD_DNLD_FAIL, - MWIFIEX_ERROR_CMD_CANCEL, - MWIFIEX_ERROR_CMD_RESP_FAIL, - MWIFIEX_ERROR_ASSOC_FAIL, - MWIFIEX_ERROR_EVENT_UNKNOWN, - MWIFIEX_ERROR_INVALID_PARAMETER, -}; - enum mwifiex_bss_type { MWIFIEX_BSS_TYPE_STA = 0, MWIFIEX_BSS_TYPE_UAP = 1, @@ -112,12 +95,9 @@ struct mwifiex_802_11_ssid { }; struct mwifiex_wait_queue { - u32 bss_index; - wait_queue_head_t *wait; - u16 *condition; - u32 start_time; + wait_queue_head_t wait; + u16 condition; int status; - u32 enabled; }; struct mwifiex_rxinfo { diff --git a/drivers/net/wireless/mwifiex/init.c b/drivers/net/wireless/mwifiex/init.c index 8189862..26931d5 100644 --- a/drivers/net/wireless/mwifiex/init.c +++ b/drivers/net/wireless/mwifiex/init.c @@ -35,7 +35,6 @@ static int mwifiex_add_bss_prio_tbl(struct mwifiex_private *priv) { struct mwifiex_adapter *adapter = priv->adapter; struct mwifiex_bss_prio_node *bss_prio; - int status = 0; unsigned long flags; bss_prio = kzalloc(sizeof(struct mwifiex_bss_prio_node), GFP_KERNEL); @@ -59,7 +58,7 @@ static int mwifiex_add_bss_prio_tbl(struct mwifiex_private *priv) spin_unlock_irqrestore(&adapter->bss_prio_tbl[priv->bss_priority] .bss_prio_lock, flags); - return status; + return 0; } /* diff --git a/drivers/net/wireless/mwifiex/join.c b/drivers/net/wireless/mwifiex/join.c index 7a9e0b5..60d25c6 100644 --- a/drivers/net/wireless/mwifiex/join.c +++ b/drivers/net/wireless/mwifiex/join.c @@ -590,11 +590,10 @@ int mwifiex_cmd_802_11_associate(struct mwifiex_private *priv, * an association success (0) or failure (non-zero). */ int mwifiex_ret_802_11_associate(struct mwifiex_private *priv, - struct host_cmd_ds_command *resp, void *wq_buf) + struct host_cmd_ds_command *resp) { + struct mwifiex_adapter *adapter = priv->adapter; int ret = 0; - struct mwifiex_wait_queue *wait_queue = - (struct mwifiex_wait_queue *) wq_buf; struct ieee_types_assoc_rsp *assoc_rsp; struct mwifiex_bssdescriptor *bss_desc; u8 enable_data = true; @@ -718,16 +717,11 @@ int mwifiex_ret_802_11_associate(struct mwifiex_private *priv, done: /* Need to indicate IOCTL complete */ - if (wait_queue) { - if (ret) { - if (assoc_rsp->status_code) - wait_queue->status = - le16_to_cpu(assoc_rsp->status_code); - else - wait_queue->status = MWIFIEX_ERROR_ASSOC_FAIL; - } else { - wait_queue->status = MWIFIEX_ERROR_NO_ERROR; - } + if (adapter->curr_cmd->wait_q_enabled) { + if (ret) + adapter->cmd_wait_q.status = -1; + else + adapter->cmd_wait_q.status = 0; } return ret; @@ -885,9 +879,9 @@ mwifiex_cmd_802_11_ad_hoc_start(struct mwifiex_private *priv, mwifiex_get_active_data_rates(priv, adhoc_start->DataRate); if ((adapter->adhoc_start_band & BAND_G) && (priv->curr_pkt_filter & HostCmd_ACT_MAC_ADHOC_G_PROTECTION_ON)) { - ret = mwifiex_prepare_cmd(priv, HostCmd_CMD_MAC_CONTROL, - HostCmd_ACT_GEN_SET, - 0, NULL, &priv->curr_pkt_filter); + ret = mwifiex_send_cmd_async(priv, HostCmd_CMD_MAC_CONTROL, + HostCmd_ACT_GEN_SET, 0, + &priv->curr_pkt_filter); if (ret) { dev_err(adapter->dev, @@ -1066,9 +1060,9 @@ mwifiex_cmd_802_11_ad_hoc_join(struct mwifiex_private *priv, priv-> curr_pkt_filter | HostCmd_ACT_MAC_ADHOC_G_PROTECTION_ON; - ret = mwifiex_prepare_cmd(priv, HostCmd_CMD_MAC_CONTROL, - HostCmd_ACT_GEN_SET, 0, NULL, - &curr_pkt_filter); + ret = mwifiex_send_cmd_async(priv, HostCmd_CMD_MAC_CONTROL, + HostCmd_ACT_GEN_SET, 0, + &curr_pkt_filter); if (ret) { dev_err(priv->adapter->dev, "ADHOC_J_CMD: G Protection config failed\n"); @@ -1192,11 +1186,10 @@ mwifiex_cmd_802_11_ad_hoc_join(struct mwifiex_private *priv, * saves the beacon buffer. */ int mwifiex_ret_802_11_ad_hoc(struct mwifiex_private *priv, - struct host_cmd_ds_command *resp, void *wq_buf) + struct host_cmd_ds_command *resp) { int ret = 0; - struct mwifiex_wait_queue *wait_queue = - (struct mwifiex_wait_queue *) wq_buf; + struct mwifiex_adapter *adapter = priv->adapter; struct host_cmd_ds_802_11_ad_hoc_result *adhoc_result; struct mwifiex_bssdescriptor *bss_desc; u16 command = le16_to_cpu(resp->command); @@ -1264,11 +1257,11 @@ int mwifiex_ret_802_11_ad_hoc(struct mwifiex_private *priv, done: /* Need to indicate IOCTL complete */ - if (wait_queue) { + if (adapter->curr_cmd->wait_q_enabled) { if (ret) - wait_queue->status = MWIFIEX_ERROR_ASSOC_FAIL; + adapter->cmd_wait_q.status = -1; else - wait_queue->status = MWIFIEX_ERROR_NO_ERROR; + adapter->cmd_wait_q.status = 0; } @@ -1283,7 +1276,7 @@ done: * command to firmware. */ int mwifiex_associate(struct mwifiex_private *priv, - void *wait_queue, struct mwifiex_bssdescriptor *bss_desc) + struct mwifiex_bssdescriptor *bss_desc) { int ret = 0; u8 current_bssid[ETH_ALEN]; @@ -1301,9 +1294,8 @@ int mwifiex_associate(struct mwifiex_private *priv, retrieval */ priv->assoc_rsp_size = 0; - ret = mwifiex_prepare_cmd(priv, HostCmd_CMD_802_11_ASSOCIATE, - HostCmd_ACT_GEN_SET, 0, wait_queue, - bss_desc); + ret = mwifiex_send_cmd_sync(priv, HostCmd_CMD_802_11_ASSOCIATE, + HostCmd_ACT_GEN_SET, 0, bss_desc); return ret; } @@ -1315,7 +1307,7 @@ int mwifiex_associate(struct mwifiex_private *priv, */ int mwifiex_adhoc_start(struct mwifiex_private *priv, - void *wait_queue, struct mwifiex_802_11_ssid *adhoc_ssid) + struct mwifiex_802_11_ssid *adhoc_ssid) { int ret = 0; @@ -1326,9 +1318,8 @@ mwifiex_adhoc_start(struct mwifiex_private *priv, dev_dbg(priv->adapter->dev, "info: curr_bss_params.band = %d\n", priv->curr_bss_params.band); - ret = mwifiex_prepare_cmd(priv, HostCmd_CMD_802_11_AD_HOC_START, - HostCmd_ACT_GEN_SET, 0, wait_queue, - adhoc_ssid); + ret = mwifiex_send_cmd_sync(priv, HostCmd_CMD_802_11_AD_HOC_START, + HostCmd_ACT_GEN_SET, 0, adhoc_ssid); return ret; } @@ -1340,7 +1331,7 @@ mwifiex_adhoc_start(struct mwifiex_private *priv, * if already not connected to the requested SSID. */ int mwifiex_adhoc_join(struct mwifiex_private *priv, - void *wait_queue, struct mwifiex_bssdescriptor *bss_desc) + struct mwifiex_bssdescriptor *bss_desc) { int ret = 0; @@ -1369,9 +1360,8 @@ int mwifiex_adhoc_join(struct mwifiex_private *priv, dev_dbg(priv->adapter->dev, "info: curr_bss_params.band = %c\n", priv->curr_bss_params.band); - ret = mwifiex_prepare_cmd(priv, HostCmd_CMD_802_11_AD_HOC_JOIN, - HostCmd_ACT_GEN_SET, 0, wait_queue, - bss_desc); + ret = mwifiex_send_cmd_sync(priv, HostCmd_CMD_802_11_AD_HOC_JOIN, + HostCmd_ACT_GEN_SET, 0, bss_desc); return ret; } @@ -1380,9 +1370,7 @@ int mwifiex_adhoc_join(struct mwifiex_private *priv, * This function deauthenticates/disconnects from infra network by sending * deauthentication request. */ -static int mwifiex_deauthenticate_infra(struct mwifiex_private *priv, - struct mwifiex_wait_queue *wait, - u8 *mac) +static int mwifiex_deauthenticate_infra(struct mwifiex_private *priv, u8 *mac) { u8 mac_address[ETH_ALEN]; int ret = 0; @@ -1400,11 +1388,8 @@ static int mwifiex_deauthenticate_infra(struct mwifiex_private *priv, bss_descriptor.mac_address, ETH_ALEN); } - ret = mwifiex_prepare_cmd(priv, HostCmd_CMD_802_11_DEAUTHENTICATE, - HostCmd_ACT_GEN_SET, 0, wait, &mac_address); - - if (!ret && wait) - ret = -EINPROGRESS; + ret = mwifiex_send_cmd_sync(priv, HostCmd_CMD_802_11_DEAUTHENTICATE, + HostCmd_ACT_GEN_SET, 0, &mac_address); return ret; } @@ -1415,26 +1400,23 @@ static int mwifiex_deauthenticate_infra(struct mwifiex_private *priv, * In case of infra made, it sends deauthentication request, and * in case of ad-hoc mode, a stop network request is sent to the firmware. */ -int mwifiex_deauthenticate(struct mwifiex_private *priv, - struct mwifiex_wait_queue *wait, u8 *mac) +int mwifiex_deauthenticate(struct mwifiex_private *priv, u8 *mac) { int ret = 0; if (priv->media_connected) { if (priv->bss_mode == NL80211_IFTYPE_STATION) { - ret = mwifiex_deauthenticate_infra(priv, wait, mac); + ret = mwifiex_deauthenticate_infra(priv, mac); } else if (priv->bss_mode == NL80211_IFTYPE_ADHOC) { - ret = mwifiex_prepare_cmd(priv, - HostCmd_CMD_802_11_AD_HOC_STOP, - HostCmd_ACT_GEN_SET, 0, wait, NULL); - - if (!ret && wait) - ret = -EINPROGRESS; + ret = mwifiex_send_cmd_sync(priv, + HostCmd_CMD_802_11_AD_HOC_STOP, + HostCmd_ACT_GEN_SET, 0, NULL); } } return ret; } +EXPORT_SYMBOL_GPL(mwifiex_deauthenticate); /* * This function converts band to radio type used in channel TLV. diff --git a/drivers/net/wireless/mwifiex/main.c b/drivers/net/wireless/mwifiex/main.c index ed89ca4..df665db 100644 --- a/drivers/net/wireless/mwifiex/main.c +++ b/drivers/net/wireless/mwifiex/main.c @@ -597,16 +597,23 @@ mwifiex_set_mac_address(struct net_device *dev, void *addr) { struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev); struct sockaddr *hw_addr = (struct sockaddr *) addr; + int ret = 0; memcpy(priv->curr_addr, hw_addr->sa_data, ETH_ALEN); - if (mwifiex_request_set_mac_address(priv)) { - dev_err(priv->adapter->dev, "set MAC address failed\n"); - return -EFAULT; - } + /* Send request to firmware */ + ret = mwifiex_send_cmd_sync(priv, HostCmd_CMD_802_11_MAC_ADDRESS, + HostCmd_ACT_GEN_SET, 0, NULL); + + if (!ret) + memcpy(priv->netdev->dev_addr, priv->curr_addr, ETH_ALEN); + else + dev_err(priv->adapter->dev, "set mac address failed: ret=%d" + "\n", ret); + memcpy(dev->dev_addr, priv->curr_addr, ETH_ALEN); - return 0; + return ret; } /* @@ -615,7 +622,20 @@ mwifiex_set_mac_address(struct net_device *dev, void *addr) static void mwifiex_set_multicast_list(struct net_device *dev) { struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev); - mwifiex_request_set_multicast_list(priv, dev); + struct mwifiex_multicast_list mcast_list; + + if (dev->flags & IFF_PROMISC) { + mcast_list.mode = MWIFIEX_PROMISC_MODE; + } else if (dev->flags & IFF_ALLMULTI || + netdev_mc_count(dev) > MWIFIEX_MAX_MULTICAST_LIST_SIZE) { + mcast_list.mode = MWIFIEX_ALL_MULTI_MODE; + } else { + mcast_list.mode = MWIFIEX_MULTICAST_MODE; + if (netdev_mc_count(dev)) + mcast_list.num_multicast_addr = + mwifiex_copy_mcast_addr(&mcast_list, dev); + } + mwifiex_request_set_multicast_list(priv, &mcast_list); } /* @@ -677,9 +697,6 @@ mwifiex_init_priv_params(struct mwifiex_private *priv, struct net_device *dev) { dev->netdev_ops = &mwifiex_netdev_ops; /* Initialize private structure */ - init_waitqueue_head(&priv->ioctl_wait_q); - init_waitqueue_head(&priv->cmd_wait_q); - init_waitqueue_head(&priv->w_stats_wait_q); priv->current_key_index = 0; priv->media_connected = false; memset(&priv->nick_name, 0, sizeof(priv->nick_name)); @@ -808,32 +825,6 @@ mwifiex_remove_interface(struct mwifiex_adapter *adapter, u8 bss_index) } /* - * Sends IOCTL request to shutdown firmware. - * - * This function allocates the IOCTL request buffer, fills it - * with requisite parameters and calls the IOCTL handler. - */ -int mwifiex_shutdown_fw(struct mwifiex_private *priv, u8 wait_option) -{ - struct mwifiex_wait_queue *wait = NULL; - int status = 0; - - /* Allocate an IOCTL request buffer */ - wait = mwifiex_alloc_fill_wait_queue(priv, wait_option); - if (!wait) - return -ENOMEM; - - status = mwifiex_misc_ioctl_init_shutdown(priv->adapter, wait, - MWIFIEX_FUNC_SHUTDOWN); - - status = mwifiex_request_ioctl(priv, wait, status, wait_option); - - kfree(wait); - return status; -} -EXPORT_SYMBOL_GPL(mwifiex_shutdown_fw); - -/* * This function check if command is pending. */ int is_command_pending(struct mwifiex_adapter *adapter) @@ -927,6 +918,10 @@ mwifiex_add_card(void *card, struct semaphore *sem, adapter->is_suspended = false; adapter->hs_activated = false; init_waitqueue_head(&adapter->hs_activate_wait_q); + adapter->cmd_wait_q_required = false; + init_waitqueue_head(&adapter->cmd_wait_q.wait); + adapter->cmd_wait_q.condition = false; + adapter->cmd_wait_q.status = 0; /* Create workqueue */ adapter->workqueue = create_workqueue("MWIFIEX_WORK_QUEUE"); @@ -1038,12 +1033,12 @@ int mwifiex_remove_card(struct mwifiex_adapter *adapter, struct semaphore *sem) dev_dbg(adapter->dev, "cmd: mwifiex_shutdown_drv done\n"); if (atomic_read(&adapter->rx_pending) || atomic_read(&adapter->tx_pending) || - atomic_read(&adapter->ioctl_pending)) { + atomic_read(&adapter->cmd_pending)) { dev_err(adapter->dev, "rx_pending=%d, tx_pending=%d, " - "ioctl_pending=%d\n", + "cmd_pending=%d\n", atomic_read(&adapter->rx_pending), atomic_read(&adapter->tx_pending), - atomic_read(&adapter->ioctl_pending)); + atomic_read(&adapter->cmd_pending)); } /* Remove interface */ diff --git a/drivers/net/wireless/mwifiex/main.h b/drivers/net/wireless/mwifiex/main.h index 43ff149..7ead15e 100644 --- a/drivers/net/wireless/mwifiex/main.h +++ b/drivers/net/wireless/mwifiex/main.h @@ -42,11 +42,8 @@ extern const char driver_version[]; extern struct mwifiex_adapter *g_adapter; enum { - MWIFIEX_NO_WAIT, - MWIFIEX_IOCTL_WAIT, - MWIFIEX_CMD_WAIT, - MWIFIEX_PROC_WAIT, - MWIFIEX_WSTATS_WAIT + MWIFIEX_ASYNC_CMD, + MWIFIEX_SYNC_CMD }; #define DRV_MODE_STA 0x1 @@ -468,10 +465,6 @@ struct mwifiex_private { u32 curr_bcn_size; /* spin lock for beacon buffer */ spinlock_t curr_bcn_buf_lock; - u16 ioctl_wait_q_woken; - wait_queue_head_t ioctl_wait_q; - u16 cmd_wait_q_woken; - wait_queue_head_t cmd_wait_q; struct wireless_dev *wdev; struct mwifiex_chan_freq_power cfp; char version_str[128]; @@ -480,8 +473,6 @@ struct mwifiex_private { #endif u8 nick_name[16]; struct iw_statistics w_stats; - u16 w_stats_wait_q_woken; - wait_queue_head_t w_stats_wait_q; u16 current_key_index; struct semaphore async_sem; u8 scan_pending_on_block; @@ -552,7 +543,7 @@ struct cmd_ctrl_node { struct sk_buff *cmd_skb; struct sk_buff *resp_skb; void *data_buf; - void *wq_buf; + u32 wait_q_enabled; struct sk_buff *skb; }; @@ -590,7 +581,7 @@ struct mwifiex_adapter { struct mwifiex_if_ops if_ops; atomic_t rx_pending; atomic_t tx_pending; - atomic_t ioctl_pending; + atomic_t cmd_pending; struct workqueue_struct *workqueue; struct work_struct main_work; struct mwifiex_bss_prio_tbl bss_prio_tbl[MWIFIEX_MAX_BSS_NUM]; @@ -684,6 +675,8 @@ struct mwifiex_adapter { struct mwifiex_dbg dbg; u8 arp_filter[ARP_FILTER_MAX_BUF_SIZE]; u32 arp_filter_size; + u16 cmd_wait_q_required; + struct mwifiex_wait_queue cmd_wait_q; }; int mwifiex_init_lock_list(struct mwifiex_adapter *adapter); @@ -707,29 +700,23 @@ int mwifiex_recv_packet(struct mwifiex_adapter *, struct sk_buff *skb); int mwifiex_process_event(struct mwifiex_adapter *adapter); -int mwifiex_ioctl_complete(struct mwifiex_adapter *adapter, - struct mwifiex_wait_queue *ioctl_wq, - int status); +int mwifiex_complete_cmd(struct mwifiex_adapter *adapter); -int mwifiex_prepare_cmd(struct mwifiex_private *priv, - uint16_t cmd_no, - u16 cmd_action, - u32 cmd_oid, - void *wait_queue, void *data_buf); +int mwifiex_send_cmd_async(struct mwifiex_private *priv, uint16_t cmd_no, + u16 cmd_action, u32 cmd_oid, void *data_buf); + +int mwifiex_send_cmd_sync(struct mwifiex_private *priv, uint16_t cmd_no, + u16 cmd_action, u32 cmd_oid, void *data_buf); void mwifiex_cmd_timeout_func(unsigned long function_context); -int mwifiex_misc_ioctl_init_shutdown(struct mwifiex_adapter *adapter, - struct mwifiex_wait_queue *wait_queue, - u32 func_init_shutdown); int mwifiex_get_debug_info(struct mwifiex_private *, struct mwifiex_debug_info *); int mwifiex_alloc_cmd_buffer(struct mwifiex_adapter *adapter); int mwifiex_free_cmd_buffer(struct mwifiex_adapter *adapter); void mwifiex_cancel_all_pending_cmd(struct mwifiex_adapter *adapter); -void mwifiex_cancel_pending_ioctl(struct mwifiex_adapter *adapter, - struct mwifiex_wait_queue *ioctl_wq); +void mwifiex_cancel_pending_ioctl(struct mwifiex_adapter *adapter); void mwifiex_insert_cmd_to_free_q(struct mwifiex_adapter *adapter, struct cmd_ctrl_node *cmd_node); @@ -772,24 +759,21 @@ int mwifiex_sta_prepare_cmd(struct mwifiex_private *, uint16_t cmd_no, u16 cmd_action, u32 cmd_oid, void *data_buf, void *cmd_buf); int mwifiex_process_sta_cmdresp(struct mwifiex_private *, u16 cmdresp_no, - void *cmd_buf, void *ioctl); + void *cmd_buf); int mwifiex_process_sta_rx_packet(struct mwifiex_adapter *, struct sk_buff *skb); int mwifiex_process_sta_event(struct mwifiex_private *); void *mwifiex_process_sta_txpd(struct mwifiex_private *, struct sk_buff *skb); int mwifiex_sta_init_cmd(struct mwifiex_private *, u8 first_sta); -int mwifiex_scan_networks(struct mwifiex_private *priv, void *wait_queue, - u16 action, - const struct mwifiex_user_scan_cfg - *user_scan_in, struct mwifiex_scan_resp *); +int mwifiex_scan_networks(struct mwifiex_private *priv, + const struct mwifiex_user_scan_cfg *user_scan_in); int mwifiex_cmd_802_11_scan(struct mwifiex_private *priv, struct host_cmd_ds_command *cmd, void *data_buf); void mwifiex_queue_scan_cmd(struct mwifiex_private *priv, struct cmd_ctrl_node *cmd_node); int mwifiex_ret_802_11_scan(struct mwifiex_private *priv, - struct host_cmd_ds_command *resp, - void *wait_queue); + struct host_cmd_ds_command *resp); s32 mwifiex_find_ssid_in_list(struct mwifiex_private *priv, struct mwifiex_802_11_ssid *ssid, u8 *bssid, u32 mode); @@ -799,23 +783,20 @@ int mwifiex_find_best_network(struct mwifiex_private *priv, struct mwifiex_ssid_bssid *req_ssid_bssid); s32 mwifiex_ssid_cmp(struct mwifiex_802_11_ssid *ssid1, struct mwifiex_802_11_ssid *ssid2); -int mwifiex_associate(struct mwifiex_private *priv, void *wait_queue, +int mwifiex_associate(struct mwifiex_private *priv, struct mwifiex_bssdescriptor *bss_desc); int mwifiex_cmd_802_11_associate(struct mwifiex_private *priv, struct host_cmd_ds_command *cmd, void *data_buf); int mwifiex_ret_802_11_associate(struct mwifiex_private *priv, - struct host_cmd_ds_command *resp, - void *wait_queue); + struct host_cmd_ds_command *resp); void mwifiex_reset_connect_state(struct mwifiex_private *priv); void mwifiex_2040_coex_event(struct mwifiex_private *priv); u8 mwifiex_band_to_radio_type(u8 band); -int mwifiex_deauthenticate(struct mwifiex_private *priv, - struct mwifiex_wait_queue *wait_queue, - u8 *mac); -int mwifiex_adhoc_start(struct mwifiex_private *priv, void *wait_queue, +int mwifiex_deauthenticate(struct mwifiex_private *priv, u8 *mac); +int mwifiex_adhoc_start(struct mwifiex_private *priv, struct mwifiex_802_11_ssid *adhoc_ssid); -int mwifiex_adhoc_join(struct mwifiex_private *priv, void *wait_queue, +int mwifiex_adhoc_join(struct mwifiex_private *priv, struct mwifiex_bssdescriptor *bss_desc); int mwifiex_cmd_802_11_ad_hoc_start(struct mwifiex_private *priv, struct host_cmd_ds_command *cmd, @@ -824,8 +805,7 @@ int mwifiex_cmd_802_11_ad_hoc_join(struct mwifiex_private *priv, struct host_cmd_ds_command *cmd, void *data_buf); int mwifiex_ret_802_11_ad_hoc(struct mwifiex_private *priv, - struct host_cmd_ds_command *resp, - void *wait_queue); + struct host_cmd_ds_command *resp); int mwifiex_cmd_802_11_bg_scan_query(struct mwifiex_private *priv, struct host_cmd_ds_command *cmd, void *data_buf); @@ -943,52 +923,34 @@ mwifiex_netdev_get_priv(struct net_device *dev) return (struct mwifiex_private *) (*(unsigned long *) netdev_priv(dev)); } -struct mwifiex_wait_queue *mwifiex_alloc_fill_wait_queue( - struct mwifiex_private *, - u8 wait_option); struct mwifiex_private *mwifiex_bss_index_to_priv(struct mwifiex_adapter *adapter, u8 bss_index); -int mwifiex_shutdown_fw(struct mwifiex_private *, u8); - +int mwifiex_init_shutdown_fw(struct mwifiex_private *priv, + u32 func_init_shutdown); int mwifiex_add_card(void *, struct semaphore *, struct mwifiex_if_ops *); int mwifiex_remove_card(struct mwifiex_adapter *, struct semaphore *); void mwifiex_get_version(struct mwifiex_adapter *adapter, char *version, int maxlen); -int mwifiex_request_set_mac_address(struct mwifiex_private *priv); -void mwifiex_request_set_multicast_list(struct mwifiex_private *priv, - struct net_device *dev); -int mwifiex_request_ioctl(struct mwifiex_private *priv, - struct mwifiex_wait_queue *req, - int, u8 wait_option); -int mwifiex_disconnect(struct mwifiex_private *, u8, u8 *); +int mwifiex_request_set_multicast_list(struct mwifiex_private *priv, + struct mwifiex_multicast_list *mcast_list); +int mwifiex_copy_mcast_addr(struct mwifiex_multicast_list *mlist, + struct net_device *dev); +int mwifiex_wait_queue_complete(struct mwifiex_adapter *adapter); int mwifiex_bss_start(struct mwifiex_private *priv, - u8 wait_option, struct mwifiex_ssid_bssid *ssid_bssid); int mwifiex_set_hs_params(struct mwifiex_private *priv, - u16 action, u8 wait_option, + u16 action, int cmd_type, struct mwifiex_ds_hs_cfg *hscfg); -int mwifiex_cancel_hs(struct mwifiex_private *priv, u8 wait_option); +int mwifiex_cancel_hs(struct mwifiex_private *priv, int cmd_type); int mwifiex_enable_hs(struct mwifiex_adapter *adapter); -void mwifiex_process_ioctl_resp(struct mwifiex_private *priv, - struct mwifiex_wait_queue *req); -u32 mwifiex_get_mode(struct mwifiex_private *priv, u8 wait_option); int mwifiex_get_signal_info(struct mwifiex_private *priv, - u8 wait_option, struct mwifiex_ds_get_signal *signal); int mwifiex_drv_get_data_rate(struct mwifiex_private *priv, struct mwifiex_rate_cfg *rate); -int mwifiex_get_channel_list(struct mwifiex_private *priv, - u8 wait_option, - struct mwifiex_chan_list *chanlist); -int mwifiex_get_scan_table(struct mwifiex_private *priv, - u8 wait_option, - struct mwifiex_scan_resp *scanresp); -int mwifiex_enable_wep_key(struct mwifiex_private *priv, u8 wait_option); -int mwifiex_find_best_bss(struct mwifiex_private *priv, u8 wait_option, +int mwifiex_find_best_bss(struct mwifiex_private *priv, struct mwifiex_ssid_bssid *ssid_bssid); int mwifiex_request_scan(struct mwifiex_private *priv, - u8 wait_option, struct mwifiex_802_11_ssid *req_ssid); int mwifiex_set_user_scan_ioctl(struct mwifiex_private *priv, struct mwifiex_user_scan_cfg *scan_req); @@ -1024,27 +986,22 @@ int mwifiex_set_tx_rate_cfg(struct mwifiex_private *priv, int tx_rate_index); int mwifiex_get_tx_rate_cfg(struct mwifiex_private *priv, int *tx_rate_index); -int mwifiex_drv_set_power(struct mwifiex_private *priv, bool power_on); +int mwifiex_drv_set_power(struct mwifiex_private *priv, u32 *ps_mode); int mwifiex_drv_get_driver_version(struct mwifiex_adapter *adapter, char *version, int max_len); -int mwifiex_set_tx_power(struct mwifiex_private *priv, int type, int dbm); +int mwifiex_set_tx_power(struct mwifiex_private *priv, + struct mwifiex_power_cfg *power_cfg); int mwifiex_main_process(struct mwifiex_adapter *); -int mwifiex_bss_ioctl_channel(struct mwifiex_private *, - u16 action, - struct mwifiex_chan_freq_power *cfp); +int mwifiex_bss_set_channel(struct mwifiex_private *, + struct mwifiex_chan_freq_power *cfp); int mwifiex_bss_ioctl_find_bss(struct mwifiex_private *, - struct mwifiex_wait_queue *, struct mwifiex_ssid_bssid *); -int mwifiex_radio_ioctl_band_cfg(struct mwifiex_private *, - u16 action, - struct mwifiex_ds_band_cfg *); -int mwifiex_snmp_mib_ioctl(struct mwifiex_private *, - struct mwifiex_wait_queue *, - u32 cmd_oid, u16 action, u32 *value); +int mwifiex_set_radio_band_cfg(struct mwifiex_private *, + struct mwifiex_ds_band_cfg *); int mwifiex_get_bss_info(struct mwifiex_private *, struct mwifiex_bss_info *); diff --git a/drivers/net/wireless/mwifiex/scan.c b/drivers/net/wireless/mwifiex/scan.c index 6bb52d0..12fe021 100644 --- a/drivers/net/wireless/mwifiex/scan.c +++ b/drivers/net/wireless/mwifiex/scan.c @@ -178,9 +178,8 @@ mwifiex_ssid_cmp(struct mwifiex_802_11_ssid *ssid1, * with requisite parameters and calls the IOCTL handler. */ int mwifiex_find_best_bss(struct mwifiex_private *priv, - u8 wait_option, struct mwifiex_ssid_bssid *ssid_bssid) + struct mwifiex_ssid_bssid *ssid_bssid) { - struct mwifiex_wait_queue *wait = NULL; struct mwifiex_ssid_bssid tmp_ssid_bssid; int ret = 0; u8 *mac = NULL; @@ -188,14 +187,9 @@ int mwifiex_find_best_bss(struct mwifiex_private *priv, if (!ssid_bssid) return -1; - /* Allocate wait request buffer */ - wait = mwifiex_alloc_fill_wait_queue(priv, wait_option); - if (!wait) - return -ENOMEM; - memcpy(&tmp_ssid_bssid, ssid_bssid, sizeof(struct mwifiex_ssid_bssid)); - ret = mwifiex_bss_ioctl_find_bss(priv, wait, &tmp_ssid_bssid); + ret = mwifiex_bss_ioctl_find_bss(priv, &tmp_ssid_bssid); if (!ret) { memcpy(ssid_bssid, &tmp_ssid_bssid, @@ -205,7 +199,6 @@ int mwifiex_find_best_bss(struct mwifiex_private *priv, " %pM\n", ssid_bssid->ssid.ssid, mac); } - kfree(wait); return ret; } @@ -221,22 +214,14 @@ int mwifiex_find_best_bss(struct mwifiex_private *priv, int mwifiex_set_user_scan_ioctl(struct mwifiex_private *priv, struct mwifiex_user_scan_cfg *scan_req) { - struct mwifiex_wait_queue *wait = NULL; int status = 0; - u8 wait_option = MWIFIEX_IOCTL_WAIT; - - /* Allocate an IOCTL request buffer */ - wait = mwifiex_alloc_fill_wait_queue(priv, wait_option); - if (!wait) - return -ENOMEM; - status = mwifiex_scan_networks(priv, wait, HostCmd_ACT_GEN_SET, - scan_req, NULL); + priv->adapter->cmd_wait_q.condition = false; - status = mwifiex_request_ioctl(priv, wait, status, wait_option); + status = mwifiex_scan_networks(priv, scan_req); + if (!status) + status = mwifiex_wait_queue_complete(priv->adapter); - if (wait && (status != -EINPROGRESS)) - kfree(wait); return status; } @@ -674,7 +659,7 @@ mwifiex_scan_create_channel_list(struct mwifiex_private *priv, * along with the other TLVs, to the firmware. */ static int -mwifiex_scan_channel_list(struct mwifiex_private *priv, void *wait_buf, +mwifiex_scan_channel_list(struct mwifiex_private *priv, u32 max_chan_per_scan, u8 filtered_scan, struct mwifiex_scan_cmd_config *scan_cfg_out, struct mwifiex_ie_types_chan_list_param_set @@ -808,9 +793,9 @@ mwifiex_scan_channel_list(struct mwifiex_private *priv, void *wait_buf, /* Send the scan command to the firmware with the specified cfg */ - ret = mwifiex_prepare_cmd(priv, HostCmd_CMD_802_11_SCAN, - HostCmd_ACT_GEN_SET, - 0, wait_buf, scan_cfg_out); + ret = mwifiex_send_cmd_async(priv, HostCmd_CMD_802_11_SCAN, + HostCmd_ACT_GEN_SET, 0, + scan_cfg_out); if (ret) break; } @@ -2271,9 +2256,7 @@ mwifiex_scan_delete_ssid_table_entry(struct mwifiex_private *priv, * update the internal driver scan table. */ int mwifiex_scan_networks(struct mwifiex_private *priv, - void *wait_buf, u16 action, - const struct mwifiex_user_scan_cfg *user_scan_in, - struct mwifiex_scan_resp *scan_resp) + const struct mwifiex_user_scan_cfg *user_scan_in) { int ret = 0; struct mwifiex_adapter *adapter = priv->adapter; @@ -2288,18 +2271,7 @@ int mwifiex_scan_networks(struct mwifiex_private *priv, u8 max_chan_per_scan; unsigned long flags; - if (action == HostCmd_ACT_GEN_GET) { - if (scan_resp) { - scan_resp->scan_table = (u8 *) adapter->scan_table; - scan_resp->num_in_scan_table = - adapter->num_in_scan_table; - } else { - ret = -1; - } - return ret; - } - - if (adapter->scan_processing && action == HostCmd_ACT_GEN_SET) { + if (adapter->scan_processing) { dev_dbg(adapter->dev, "cmd: Scan already in process...\n"); return ret; } @@ -2308,7 +2280,7 @@ int mwifiex_scan_networks(struct mwifiex_private *priv, adapter->scan_processing = true; spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock, flags); - if (priv->scan_block && action == HostCmd_ACT_GEN_SET) { + if (priv->scan_block) { dev_dbg(adapter->dev, "cmd: Scan is blocked during association...\n"); return ret; @@ -2348,9 +2320,9 @@ int mwifiex_scan_networks(struct mwifiex_private *priv, adapter->bcn_buf_end = adapter->bcn_buf; } - ret = mwifiex_scan_channel_list(priv, wait_buf, max_chan_per_scan, - filtered_scan, &scan_cfg_out->config, - chan_list_out, scan_chan_list); + ret = mwifiex_scan_channel_list(priv, max_chan_per_scan, filtered_scan, + &scan_cfg_out->config, chan_list_out, + scan_chan_list); /* Get scan command from scan_pending_q and put to cmd_pending_q */ if (!ret) { @@ -2367,7 +2339,6 @@ int mwifiex_scan_networks(struct mwifiex_private *priv, spin_unlock_irqrestore(&adapter->scan_pending_q_lock, flags); } - ret = -EINPROGRESS; } else { spin_lock_irqsave(&adapter->mwifiex_cmd_lock, flags); adapter->scan_processing = true; @@ -2437,11 +2408,10 @@ int mwifiex_cmd_802_11_scan(struct mwifiex_private *priv, * .-------------------------------------------------------------. */ int mwifiex_ret_802_11_scan(struct mwifiex_private *priv, - struct host_cmd_ds_command *resp, void *wq_buf) + struct host_cmd_ds_command *resp) { int ret = 0; struct mwifiex_adapter *adapter = priv->adapter; - struct mwifiex_wait_queue *wait_queue = NULL; struct cmd_ctrl_node *cmd_node = NULL; struct host_cmd_ds_802_11_scan_rsp *scan_rsp = NULL; struct mwifiex_bssdescriptor *bss_new_entry = NULL; @@ -2653,13 +2623,9 @@ int mwifiex_ret_802_11_scan(struct mwifiex_private *priv, mwifiex_process_scan_results(priv); /* Need to indicate IOCTL complete */ - wait_queue = (struct mwifiex_wait_queue *) wq_buf; - if (wait_queue) { - wait_queue->status = MWIFIEX_ERROR_NO_ERROR; - - /* Indicate ioctl complete */ - mwifiex_ioctl_complete(adapter, - (struct mwifiex_wait_queue *) wait_queue, 0); + if (adapter->curr_cmd->wait_q_enabled) { + adapter->cmd_wait_q.status = 0; + mwifiex_complete_cmd(adapter); } if (priv->report_scan_result) priv->report_scan_result = false; @@ -2853,6 +2819,7 @@ mwifiex_queue_scan_cmd(struct mwifiex_private *priv, struct mwifiex_adapter *adapter = priv->adapter; unsigned long flags; + cmd_node->wait_q_enabled = true; spin_lock_irqsave(&adapter->scan_pending_q_lock, flags); list_add_tail(&cmd_node->list, &adapter->scan_pending_q); spin_unlock_irqrestore(&adapter->scan_pending_q_lock, flags); @@ -2899,9 +2866,7 @@ int mwifiex_find_best_network(struct mwifiex_private *priv, * firmware, filtered on a specific SSID. */ static int mwifiex_scan_specific_ssid(struct mwifiex_private *priv, - void *wait_buf, u16 action, - struct mwifiex_802_11_ssid *req_ssid, - struct mwifiex_scan_resp *scan_resp) + struct mwifiex_802_11_ssid *req_ssid) { struct mwifiex_adapter *adapter = priv->adapter; int ret = 0; @@ -2910,24 +2875,12 @@ static int mwifiex_scan_specific_ssid(struct mwifiex_private *priv, if (!req_ssid) return -1; - if (action == HostCmd_ACT_GEN_GET) { - if (scan_resp) { - scan_resp->scan_table = - (u8 *) &priv->curr_bss_params.bss_descriptor; - scan_resp->num_in_scan_table = - adapter->num_in_scan_table; - } else { - ret = -1; - } - return ret; - } - - if (adapter->scan_processing && action == HostCmd_ACT_GEN_SET) { + if (adapter->scan_processing) { dev_dbg(adapter->dev, "cmd: Scan already in process...\n"); return ret; } - if (priv->scan_block && action == HostCmd_ACT_GEN_SET) { + if (priv->scan_block) { dev_dbg(adapter->dev, "cmd: Scan is blocked during association...\n"); return ret; @@ -2945,7 +2898,7 @@ static int mwifiex_scan_specific_ssid(struct mwifiex_private *priv, req_ssid->ssid_len); scan_cfg->keep_previous_scan = true; - ret = mwifiex_scan_networks(priv, wait_buf, action, scan_cfg, NULL); + ret = mwifiex_scan_networks(priv, scan_cfg); kfree(scan_cfg); return ret; @@ -2960,12 +2913,10 @@ static int mwifiex_scan_specific_ssid(struct mwifiex_private *priv, * Scan command can be issued for both normal scan and specific SSID * scan, depending upon whether an SSID is provided or not. */ -int mwifiex_request_scan(struct mwifiex_private *priv, u8 wait_option, +int mwifiex_request_scan(struct mwifiex_private *priv, struct mwifiex_802_11_ssid *req_ssid) { int ret = 0; - struct mwifiex_wait_queue *wait = NULL; - int status = 0; if (down_interruptible(&priv->async_sem)) { dev_err(priv->adapter->dev, "%s: acquire semaphore\n", @@ -2974,32 +2925,23 @@ int mwifiex_request_scan(struct mwifiex_private *priv, u8 wait_option, } priv->scan_pending_on_block = true; - /* Allocate wait request buffer */ - wait = mwifiex_alloc_fill_wait_queue(priv, wait_option); - if (!wait) { - ret = -1; - goto done; - } + priv->adapter->cmd_wait_q.condition = false; if (req_ssid && req_ssid->ssid_len != 0) /* Specific SSID scan */ - status = mwifiex_scan_specific_ssid(priv, wait, - HostCmd_ACT_GEN_SET, - req_ssid, NULL); + ret = mwifiex_scan_specific_ssid(priv, req_ssid); else /* Normal scan */ - status = mwifiex_scan_networks(priv, wait, HostCmd_ACT_GEN_SET, - NULL, NULL); - status = mwifiex_request_ioctl(priv, wait, status, wait_option); - if (status == -1) - ret = -1; -done: - if ((wait) && (status != -EINPROGRESS)) - kfree(wait); + ret = mwifiex_scan_networks(priv, NULL); + + if (!ret) + ret = mwifiex_wait_queue_complete(priv->adapter); + if (ret == -1) { priv->scan_pending_on_block = false; up(&priv->async_sem); } + return ret; } diff --git a/drivers/net/wireless/mwifiex/sdio.c b/drivers/net/wireless/mwifiex/sdio.c index f21e5cd..f207756 100644 --- a/drivers/net/wireless/mwifiex/sdio.c +++ b/drivers/net/wireless/mwifiex/sdio.c @@ -208,7 +208,7 @@ static int mwifiex_sdio_resume(struct device *dev) /* Disable Host Sleep */ mwifiex_cancel_hs(mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_STA), - MWIFIEX_NO_WAIT); + MWIFIEX_ASYNC_CMD); return 0; } @@ -1745,13 +1745,12 @@ mwifiex_sdio_cleanup_module(void) for (i = 0; i < adapter->priv_num; i++) if ((GET_BSS_ROLE(adapter->priv[i]) == MWIFIEX_BSS_ROLE_STA) && adapter->priv[i]->media_connected) - mwifiex_disconnect(adapter->priv[i], MWIFIEX_CMD_WAIT, - NULL); + mwifiex_deauthenticate(adapter->priv[i], NULL); if (!adapter->surprise_removed) - mwifiex_shutdown_fw(mwifiex_get_priv - (adapter, MWIFIEX_BSS_ROLE_ANY), - MWIFIEX_CMD_WAIT); + mwifiex_init_shutdown_fw(mwifiex_get_priv(adapter, + MWIFIEX_BSS_ROLE_ANY), + MWIFIEX_FUNC_SHUTDOWN); exit: up(&add_remove_card_sem); diff --git a/drivers/net/wireless/mwifiex/sta_cmd.c b/drivers/net/wireless/mwifiex/sta_cmd.c index 19de652..dec4963 100644 --- a/drivers/net/wireless/mwifiex/sta_cmd.c +++ b/drivers/net/wireless/mwifiex/sta_cmd.c @@ -1135,65 +1135,66 @@ int mwifiex_sta_init_cmd(struct mwifiex_private *priv, u8 first_sta) if (first_sta) { - ret = mwifiex_prepare_cmd(priv, HostCmd_CMD_FUNC_INIT, - HostCmd_ACT_GEN_SET, 0, NULL, NULL); + ret = mwifiex_send_cmd_async(priv, HostCmd_CMD_FUNC_INIT, + HostCmd_ACT_GEN_SET, 0, NULL); if (ret) return -1; /* Read MAC address from HW */ - ret = mwifiex_prepare_cmd(priv, HostCmd_CMD_GET_HW_SPEC, - HostCmd_ACT_GEN_GET, 0, NULL, NULL); + ret = mwifiex_send_cmd_async(priv, HostCmd_CMD_GET_HW_SPEC, + HostCmd_ACT_GEN_GET, 0, NULL); if (ret) return -1; /* Reconfigure tx buf size */ - ret = mwifiex_prepare_cmd(priv, HostCmd_CMD_RECONFIGURE_TX_BUFF, - HostCmd_ACT_GEN_SET, 0, NULL, - &priv->adapter->tx_buf_size); + ret = mwifiex_send_cmd_async(priv, + HostCmd_CMD_RECONFIGURE_TX_BUFF, + HostCmd_ACT_GEN_SET, 0, + &priv->adapter->tx_buf_size); if (ret) return -1; /* Enable IEEE PS by default */ priv->adapter->ps_mode = MWIFIEX_802_11_POWER_MODE_PSP; - ret = mwifiex_prepare_cmd(priv, HostCmd_CMD_802_11_PS_MODE_ENH, - EN_AUTO_PS, BITMAP_STA_PS, NULL, - NULL); + ret = mwifiex_send_cmd_async(priv, + HostCmd_CMD_802_11_PS_MODE_ENH, + EN_AUTO_PS, BITMAP_STA_PS, NULL); if (ret) return -1; } /* get tx rate */ - ret = mwifiex_prepare_cmd(priv, HostCmd_CMD_TX_RATE_CFG, - HostCmd_ACT_GEN_GET, 0, NULL, NULL); + ret = mwifiex_send_cmd_async(priv, HostCmd_CMD_TX_RATE_CFG, + HostCmd_ACT_GEN_GET, 0, NULL); if (ret) return -1; priv->data_rate = 0; /* get tx power */ - ret = mwifiex_prepare_cmd(priv, HostCmd_CMD_TXPWR_CFG, - HostCmd_ACT_GEN_GET, 0, NULL, NULL); + ret = mwifiex_send_cmd_async(priv, HostCmd_CMD_TXPWR_CFG, + HostCmd_ACT_GEN_GET, 0, NULL); if (ret) return -1; /* set ibss coalescing_status */ - ret = mwifiex_prepare_cmd(priv, - HostCmd_CMD_802_11_IBSS_COALESCING_STATUS, - HostCmd_ACT_GEN_SET, 0, NULL, &enable); + ret = mwifiex_send_cmd_async(priv, + HostCmd_CMD_802_11_IBSS_COALESCING_STATUS, + HostCmd_ACT_GEN_SET, 0, &enable); if (ret) return -1; memset(&amsdu_aggr_ctrl, 0, sizeof(amsdu_aggr_ctrl)); amsdu_aggr_ctrl.enable = true; /* Send request to firmware */ - ret = mwifiex_prepare_cmd(priv, HostCmd_CMD_AMSDU_AGGR_CTRL, - HostCmd_ACT_GEN_SET, 0, NULL, - (void *) &amsdu_aggr_ctrl); + ret = mwifiex_send_cmd_async(priv, HostCmd_CMD_AMSDU_AGGR_CTRL, + HostCmd_ACT_GEN_SET, 0, + (void *) &amsdu_aggr_ctrl); if (ret) return -1; /* MAC Control must be the last command in init_fw */ /* set MAC Control */ - ret = mwifiex_prepare_cmd(priv, HostCmd_CMD_MAC_CONTROL, - HostCmd_ACT_GEN_SET, 0, NULL, - &priv->curr_pkt_filter); + ret = mwifiex_send_cmd_async(priv, HostCmd_CMD_MAC_CONTROL, + HostCmd_ACT_GEN_SET, 0, + &priv->curr_pkt_filter); if (ret) return -1; @@ -1201,19 +1202,18 @@ int mwifiex_sta_init_cmd(struct mwifiex_private *priv, u8 first_sta) /* Enable auto deep sleep */ auto_ds.auto_ds = DEEP_SLEEP_ON; auto_ds.idle_time = DEEP_SLEEP_IDLE_TIME; - ret = mwifiex_prepare_cmd(priv, - HostCmd_CMD_802_11_PS_MODE_ENH, - EN_AUTO_PS, BITMAP_AUTO_DS, NULL, - &auto_ds); + ret = mwifiex_send_cmd_async(priv, + HostCmd_CMD_802_11_PS_MODE_ENH, + EN_AUTO_PS, BITMAP_AUTO_DS, + &auto_ds); if (ret) return -1; } /* Send cmd to FW to enable/disable 11D function */ state_11d = ENABLE_11D; - ret = mwifiex_prepare_cmd(priv, HostCmd_CMD_802_11_SNMP_MIB, - HostCmd_ACT_GEN_SET, DOT11D_I, - NULL, &state_11d); + ret = mwifiex_send_cmd_async(priv, HostCmd_CMD_802_11_SNMP_MIB, + HostCmd_ACT_GEN_SET, DOT11D_I, &state_11d); if (ret) dev_err(priv->adapter->dev, "11D: failed to enable 11D\n"); diff --git a/drivers/net/wireless/mwifiex/sta_cmdresp.c b/drivers/net/wireless/mwifiex/sta_cmdresp.c index 648df69..8743c11 100644 --- a/drivers/net/wireless/mwifiex/sta_cmdresp.c +++ b/drivers/net/wireless/mwifiex/sta_cmdresp.c @@ -41,8 +41,7 @@ */ static void mwifiex_process_cmdresp_error(struct mwifiex_private *priv, - struct host_cmd_ds_command *resp, - struct mwifiex_wait_queue *wq_buf) + struct host_cmd_ds_command *resp) { struct cmd_ctrl_node *cmd_node = NULL, *tmp_node = NULL; struct mwifiex_adapter *adapter = priv->adapter; @@ -51,8 +50,9 @@ mwifiex_process_cmdresp_error(struct mwifiex_private *priv, dev_err(adapter->dev, "CMD_RESP: cmd %#x error, result=%#x\n", resp->command, resp->result); - if (wq_buf) - wq_buf->status = MWIFIEX_ERROR_FW_CMDRESP; + + if (adapter->curr_cmd->wait_q_enabled) + adapter->cmd_wait_q.status = -1; switch (le16_to_cpu(resp->command)) { case HostCmd_CMD_802_11_PS_MODE_ENH: @@ -328,9 +328,9 @@ static int mwifiex_ret_tx_rate_cfg(struct mwifiex_private *priv, if (priv->is_data_rate_auto) priv->data_rate = 0; else - ret = mwifiex_prepare_cmd(priv, + ret = mwifiex_send_cmd_async(priv, HostCmd_CMD_802_11_TX_RATE_QUERY, - HostCmd_ACT_GEN_GET, 0, NULL, NULL); + HostCmd_ACT_GEN_GET, 0, NULL); if (data_buf) { ds_rate = (struct mwifiex_rate_cfg *) data_buf; @@ -833,19 +833,17 @@ static int mwifiex_ret_ibss_coalescing_status(struct mwifiex_private *priv, * response handlers based on the command ID. */ int mwifiex_process_sta_cmdresp(struct mwifiex_private *priv, - u16 cmdresp_no, void *cmd_buf, void *wq_buf) + u16 cmdresp_no, void *cmd_buf) { int ret = 0; struct mwifiex_adapter *adapter = priv->adapter; struct host_cmd_ds_command *resp = (struct host_cmd_ds_command *) cmd_buf; - struct mwifiex_wait_queue *wait_queue = - (struct mwifiex_wait_queue *) wq_buf; void *data_buf = adapter->curr_cmd->data_buf; /* If the command is not successful, cleanup and return failure */ if (resp->result != HostCmd_RESULT_OK) { - mwifiex_process_cmdresp_error(priv, resp, wait_queue); + mwifiex_process_cmdresp_error(priv, resp); return -1; } /* Command successful, handle response */ @@ -865,12 +863,11 @@ int mwifiex_process_sta_cmdresp(struct mwifiex_private *priv, ret = mwifiex_ret_tx_rate_cfg(priv, resp, data_buf); break; case HostCmd_CMD_802_11_SCAN: - ret = mwifiex_ret_802_11_scan(priv, resp, wait_queue); - wait_queue = NULL; - adapter->curr_cmd->wq_buf = NULL; + ret = mwifiex_ret_802_11_scan(priv, resp); + adapter->curr_cmd->wait_q_enabled = false; break; case HostCmd_CMD_802_11_BG_SCAN_QUERY: - ret = mwifiex_ret_802_11_scan(priv, resp, wait_queue); + ret = mwifiex_ret_802_11_scan(priv, resp); dev_dbg(adapter->dev, "info: CMD_RESP: BG_SCAN result is ready!\n"); break; @@ -884,14 +881,14 @@ int mwifiex_process_sta_cmdresp(struct mwifiex_private *priv, ret = mwifiex_ret_802_11_hs_cfg(priv, resp); break; case HostCmd_CMD_802_11_ASSOCIATE: - ret = mwifiex_ret_802_11_associate(priv, resp, wait_queue); + ret = mwifiex_ret_802_11_associate(priv, resp); break; case HostCmd_CMD_802_11_DEAUTHENTICATE: ret = mwifiex_ret_802_11_deauthenticate(priv, resp); break; case HostCmd_CMD_802_11_AD_HOC_START: case HostCmd_CMD_802_11_AD_HOC_JOIN: - ret = mwifiex_ret_802_11_ad_hoc(priv, resp, wait_queue); + ret = mwifiex_ret_802_11_ad_hoc(priv, resp); break; case HostCmd_CMD_802_11_AD_HOC_STOP: ret = mwifiex_ret_802_11_ad_hoc_stop(priv, resp); diff --git a/drivers/net/wireless/mwifiex/sta_event.c b/drivers/net/wireless/mwifiex/sta_event.c index 936d7c1..fc265ca 100644 --- a/drivers/net/wireless/mwifiex/sta_event.c +++ b/drivers/net/wireless/mwifiex/sta_event.c @@ -271,8 +271,9 @@ int mwifiex_process_sta_event(struct mwifiex_private *priv) case EVENT_HS_ACT_REQ: dev_dbg(adapter->dev, "event: HS_ACT_REQ\n"); - ret = mwifiex_prepare_cmd(priv, HostCmd_CMD_802_11_HS_CFG_ENH, - 0, 0, NULL, NULL); + ret = mwifiex_send_cmd_async(priv, + HostCmd_CMD_802_11_HS_CFG_ENH, + 0, 0, NULL); break; case EVENT_MIC_ERR_UNICAST: @@ -303,9 +304,9 @@ int mwifiex_process_sta_event(struct mwifiex_private *priv) sizeof(struct mwifiex_bssdescriptor) * IW_MAX_AP); adapter->num_in_scan_table = 0; adapter->bcn_buf_end = adapter->bcn_buf; - ret = mwifiex_prepare_cmd(priv, - HostCmd_CMD_802_11_BG_SCAN_QUERY, - HostCmd_ACT_GEN_GET, 0, NULL, NULL); + ret = mwifiex_send_cmd_async(priv, + HostCmd_CMD_802_11_BG_SCAN_QUERY, + HostCmd_ACT_GEN_GET, 0, NULL); break; case EVENT_PORT_RELEASE: @@ -314,8 +315,8 @@ int mwifiex_process_sta_event(struct mwifiex_private *priv) case EVENT_WMM_STATUS_CHANGE: dev_dbg(adapter->dev, "event: WMM status changed\n"); - ret = mwifiex_prepare_cmd(priv, HostCmd_CMD_WMM_GET_STATUS, - 0, 0, NULL, NULL); + ret = mwifiex_send_cmd_async(priv, HostCmd_CMD_WMM_GET_STATUS, + 0, 0, NULL); break; case EVENT_RSSI_LOW: @@ -353,15 +354,15 @@ int mwifiex_process_sta_event(struct mwifiex_private *priv) break; case EVENT_IBSS_COALESCED: dev_dbg(adapter->dev, "event: IBSS_COALESCED\n"); - ret = mwifiex_prepare_cmd(priv, + ret = mwifiex_send_cmd_async(priv, HostCmd_CMD_802_11_IBSS_COALESCING_STATUS, - HostCmd_ACT_GEN_GET, 0, NULL, NULL); + HostCmd_ACT_GEN_GET, 0, NULL); break; case EVENT_ADDBA: dev_dbg(adapter->dev, "event: ADDBA Request\n"); - mwifiex_prepare_cmd(priv, HostCmd_CMD_11N_ADDBA_RSP, - HostCmd_ACT_GEN_SET, 0, NULL, - adapter->event_body); + mwifiex_send_cmd_async(priv, HostCmd_CMD_11N_ADDBA_RSP, + HostCmd_ACT_GEN_SET, 0, + adapter->event_body); break; case EVENT_DELBA: dev_dbg(adapter->dev, "event: DELBA Request\n"); diff --git a/drivers/net/wireless/mwifiex/sta_ioctl.c b/drivers/net/wireless/mwifiex/sta_ioctl.c index 2fcdbc2..5f2ce94 100644 --- a/drivers/net/wireless/mwifiex/sta_ioctl.c +++ b/drivers/net/wireless/mwifiex/sta_ioctl.c @@ -33,9 +33,8 @@ * size, and the calling function must ensure enough memory is * available. */ -static int -mwifiex_copy_mcast_addr(struct mwifiex_multicast_list *mlist, - struct net_device *dev) +int mwifiex_copy_mcast_addr(struct mwifiex_multicast_list *mlist, + struct net_device *dev) { int i = 0; struct netdev_hw_addr *ha; @@ -47,216 +46,51 @@ mwifiex_copy_mcast_addr(struct mwifiex_multicast_list *mlist, } /* - * Allocate and fills a wait queue with proper parameters. - * - * This function needs to be called before an IOCTL request can be made. - * It can handle the following wait options: - * MWIFIEX_NO_WAIT - Waiting is disabled - * MWIFIEX_IOCTL_WAIT - Waiting is done on IOCTL wait queue - * MWIFIEX_CMD_WAIT - Waiting is done on command wait queue - * MWIFIEX_WSTATS_WAIT - Waiting is done on stats wait queue - */ -struct mwifiex_wait_queue * -mwifiex_alloc_fill_wait_queue(struct mwifiex_private *priv, - u8 wait_option) -{ - struct mwifiex_wait_queue *wait = NULL; - - wait = (struct mwifiex_wait_queue *) - kzalloc(sizeof(struct mwifiex_wait_queue), GFP_ATOMIC); - if (!wait) { - dev_err(priv->adapter->dev, "%s: fail to alloc buffer\n", - __func__); - return wait; - } - - wait->bss_index = priv->bss_index; - - switch (wait_option) { - case MWIFIEX_NO_WAIT: - wait->enabled = 0; - break; - case MWIFIEX_IOCTL_WAIT: - priv->ioctl_wait_q_woken = false; - wait->start_time = jiffies; - wait->wait = &priv->ioctl_wait_q; - wait->condition = &priv->ioctl_wait_q_woken; - wait->enabled = 1; - break; - case MWIFIEX_CMD_WAIT: - priv->cmd_wait_q_woken = false; - wait->start_time = jiffies; - wait->wait = &priv->cmd_wait_q; - wait->condition = &priv->cmd_wait_q_woken; - wait->enabled = 1; - break; - case MWIFIEX_WSTATS_WAIT: - priv->w_stats_wait_q_woken = false; - wait->start_time = jiffies; - wait->wait = &priv->w_stats_wait_q; - wait->condition = &priv->w_stats_wait_q_woken; - wait->enabled = 1; - break; - } - - return wait; -} - -/* * Wait queue completion handler. * - * This function waits on a particular wait queue. - * For NO_WAIT option, it returns immediately. It also cancels the - * pending IOCTL request after waking up, in case of errors. + * This function waits on a cmd wait queue. It also cancels the pending + * request after waking up, in case of errors. */ -static void -mwifiex_wait_ioctl_complete(struct mwifiex_private *priv, - struct mwifiex_wait_queue *wait, - u8 wait_option) +int mwifiex_wait_queue_complete(struct mwifiex_adapter *adapter) { bool cancel_flag = false; + int status = adapter->cmd_wait_q.status; - switch (wait_option) { - case MWIFIEX_NO_WAIT: - break; - case MWIFIEX_IOCTL_WAIT: - wait_event_interruptible(priv->ioctl_wait_q, - priv->ioctl_wait_q_woken); - if (!priv->ioctl_wait_q_woken) - cancel_flag = true; - break; - case MWIFIEX_CMD_WAIT: - wait_event_interruptible(priv->cmd_wait_q, - priv->cmd_wait_q_woken); - if (!priv->cmd_wait_q_woken) - cancel_flag = true; - break; - case MWIFIEX_WSTATS_WAIT: - wait_event_interruptible(priv->w_stats_wait_q, - priv->w_stats_wait_q_woken); - if (!priv->w_stats_wait_q_woken) - cancel_flag = true; - break; - } - if (cancel_flag) { - mwifiex_cancel_pending_ioctl(priv->adapter, wait); - dev_dbg(priv->adapter->dev, "cmd: IOCTL cancel: wait=%p, wait_option=%d\n", - wait, wait_option); - } + dev_dbg(adapter->dev, "cmd pending\n"); + atomic_inc(&adapter->cmd_pending); - return; -} + /* Status pending, wake up main process */ + queue_work(adapter->workqueue, &adapter->main_work); -/* - * The function waits for the request to complete and issues the - * completion handler, if required. - */ -int mwifiex_request_ioctl(struct mwifiex_private *priv, - struct mwifiex_wait_queue *wait, - int status, u8 wait_option) -{ - switch (status) { - case -EINPROGRESS: - dev_dbg(priv->adapter->dev, "cmd: IOCTL pending: wait=%p, wait_option=%d\n", - wait, wait_option); - atomic_inc(&priv->adapter->ioctl_pending); - /* Status pending, wake up main process */ - queue_work(priv->adapter->workqueue, &priv->adapter->main_work); - - /* Wait for completion */ - if (wait_option) { - mwifiex_wait_ioctl_complete(priv, wait, wait_option); - status = wait->status; - } - break; - case 0: - case -1: - case -EBUSY: - default: - break; - } - return status; -} -EXPORT_SYMBOL_GPL(mwifiex_request_ioctl); + /* Wait for completion */ + wait_event_interruptible(adapter->cmd_wait_q.wait, + adapter->cmd_wait_q.condition); + if (!adapter->cmd_wait_q.condition) + cancel_flag = true; -/* - * IOCTL request handler to set/get MAC address. - * - * This function prepares the correct firmware command and - * issues it to get the extended version information. - */ -static int mwifiex_bss_ioctl_mac_address(struct mwifiex_private *priv, - struct mwifiex_wait_queue *wait, - u8 action, u8 *mac) -{ - int ret = 0; - - if ((action == HostCmd_ACT_GEN_GET) && mac) { - memcpy(mac, priv->curr_addr, ETH_ALEN); - return 0; + if (cancel_flag) { + mwifiex_cancel_pending_ioctl(adapter); + dev_dbg(adapter->dev, "cmd cancel\n"); } + adapter->cmd_wait_q.status = 0; - /* Send request to firmware */ - ret = mwifiex_prepare_cmd(priv, HostCmd_CMD_802_11_MAC_ADDRESS, - action, 0, wait, mac); - if (!ret) - ret = -EINPROGRESS; - - return ret; -} - -/* - * Sends IOCTL request to set MAC address. - * - * This function allocates the IOCTL request buffer, fills it - * with requisite parameters and calls the IOCTL handler. - */ -int mwifiex_request_set_mac_address(struct mwifiex_private *priv) -{ - struct mwifiex_wait_queue *wait = NULL; - int status = 0; - u8 wait_option = MWIFIEX_CMD_WAIT; - - /* Allocate wait buffer */ - wait = mwifiex_alloc_fill_wait_queue(priv, wait_option); - if (!wait) - return -ENOMEM; - - status = mwifiex_bss_ioctl_mac_address(priv, wait, HostCmd_ACT_GEN_SET, - NULL); - - status = mwifiex_request_ioctl(priv, wait, status, wait_option); - if (!status) - memcpy(priv->netdev->dev_addr, priv->curr_addr, ETH_ALEN); - else - dev_err(priv->adapter->dev, "set mac address failed: status=%d" - " error_code=%#x\n", status, wait->status); - - kfree(wait); return status; } /* - * IOCTL request handler to set multicast list. - * * This function prepares the correct firmware command and * issues it to set the multicast list. * * This function can be used to enable promiscuous mode, or enable all * multicast packets, or to enable selective multicast. */ -static int -mwifiex_bss_ioctl_multicast_list(struct mwifiex_private *priv, - struct mwifiex_wait_queue *wait, - u16 action, - struct mwifiex_multicast_list *mcast_list) +int mwifiex_request_set_multicast_list(struct mwifiex_private *priv, + struct mwifiex_multicast_list *mcast_list) { int ret = 0; u16 old_pkt_filter; old_pkt_filter = priv->curr_pkt_filter; - if (action == HostCmd_ACT_GEN_GET) - return -1; if (mcast_list->mode == MWIFIEX_PROMISC_MODE) { dev_dbg(priv->adapter->dev, "info: Enable Promiscuous mode\n"); @@ -281,16 +115,15 @@ mwifiex_bss_ioctl_multicast_list(struct mwifiex_private *priv, /* Set multicast addresses to firmware */ if (old_pkt_filter == priv->curr_pkt_filter) { /* Send request to firmware */ - ret = mwifiex_prepare_cmd(priv, + ret = mwifiex_send_cmd_async(priv, HostCmd_CMD_MAC_MULTICAST_ADR, - action, 0, wait, mcast_list); - if (!ret) - ret = -EINPROGRESS; + HostCmd_ACT_GEN_SET, 0, + mcast_list); } else { /* Send request to firmware */ - ret = mwifiex_prepare_cmd(priv, + ret = mwifiex_send_cmd_async(priv, HostCmd_CMD_MAC_MULTICAST_ADR, - action, 0, NULL, + HostCmd_ACT_GEN_SET, 0, mcast_list); } } @@ -300,101 +133,21 @@ mwifiex_bss_ioctl_multicast_list(struct mwifiex_private *priv, "info: old_pkt_filter=%#x, curr_pkt_filter=%#x\n", old_pkt_filter, priv->curr_pkt_filter); if (old_pkt_filter != priv->curr_pkt_filter) { - ret = mwifiex_prepare_cmd(priv, HostCmd_CMD_MAC_CONTROL, action, - 0, wait, &priv->curr_pkt_filter); - if (!ret) - ret = -EINPROGRESS; + ret = mwifiex_send_cmd_async(priv, HostCmd_CMD_MAC_CONTROL, + HostCmd_ACT_GEN_SET, + 0, &priv->curr_pkt_filter); } return ret; } /* - * Sends IOCTL request to set multicast list. - * - * This function allocates the IOCTL request buffer, fills it - * with requisite parameters and calls the IOCTL handler. - */ -void -mwifiex_request_set_multicast_list(struct mwifiex_private *priv, - struct net_device *dev) -{ - struct mwifiex_wait_queue *wait = NULL; - struct mwifiex_multicast_list mcast_list; - u8 wait_option = MWIFIEX_NO_WAIT; - int status = 0; - - /* Allocate wait buffer */ - wait = mwifiex_alloc_fill_wait_queue(priv, wait_option); - if (!wait) - return; - - if (dev->flags & IFF_PROMISC) { - mcast_list.mode = MWIFIEX_PROMISC_MODE; - } else if (dev->flags & IFF_ALLMULTI || - netdev_mc_count(dev) > MWIFIEX_MAX_MULTICAST_LIST_SIZE) { - mcast_list.mode = MWIFIEX_ALL_MULTI_MODE; - } else { - mcast_list.mode = MWIFIEX_MULTICAST_MODE; - if (netdev_mc_count(dev)) - mcast_list.num_multicast_addr = - mwifiex_copy_mcast_addr(&mcast_list, dev); - } - status = mwifiex_bss_ioctl_multicast_list(priv, wait, - HostCmd_ACT_GEN_SET, - &mcast_list); - - status = mwifiex_request_ioctl(priv, wait, status, wait_option); - if (wait && status != -EINPROGRESS) - kfree(wait); - - return; -} - -/* - * IOCTL request handler to disconnect from a BSS/IBSS. - */ -static int mwifiex_bss_ioctl_stop(struct mwifiex_private *priv, - struct mwifiex_wait_queue *wait, u8 *mac) -{ - return mwifiex_deauthenticate(priv, wait, mac); -} - -/* - * Sends IOCTL request to disconnect from a BSS. - * - * This function allocates the IOCTL request buffer, fills it - * with requisite parameters and calls the IOCTL handler. - */ -int mwifiex_disconnect(struct mwifiex_private *priv, u8 wait_option, u8 *mac) -{ - struct mwifiex_wait_queue *wait = NULL; - int status = 0; - - /* Allocate wait buffer */ - wait = mwifiex_alloc_fill_wait_queue(priv, wait_option); - if (!wait) - return -ENOMEM; - - status = mwifiex_bss_ioctl_stop(priv, wait, mac); - - status = mwifiex_request_ioctl(priv, wait, status, wait_option); - - kfree(wait); - return status; -} -EXPORT_SYMBOL_GPL(mwifiex_disconnect); - -/* - * IOCTL request handler to join a BSS/IBSS. - * * In Ad-Hoc mode, the IBSS is created if not found in scan list. * In both Ad-Hoc and infra mode, an deauthentication is performed * first. */ -static int mwifiex_bss_ioctl_start(struct mwifiex_private *priv, - struct mwifiex_wait_queue *wait, - struct mwifiex_ssid_bssid *ssid_bssid) +int mwifiex_bss_start(struct mwifiex_private *priv, + struct mwifiex_ssid_bssid *ssid_bssid) { int ret = 0; struct mwifiex_adapter *adapter = priv->adapter; @@ -406,7 +159,7 @@ static int mwifiex_bss_ioctl_start(struct mwifiex_private *priv, if (priv->bss_mode == NL80211_IFTYPE_STATION) { /* Infra mode */ - ret = mwifiex_deauthenticate(priv, NULL, NULL); + ret = mwifiex_deauthenticate(priv, NULL); if (ret) return ret; @@ -427,7 +180,7 @@ static int mwifiex_bss_ioctl_start(struct mwifiex_private *priv, /* Clear any past association response stored for * application retrieval */ priv->assoc_rsp_size = 0; - ret = mwifiex_associate(priv, wait, &adapter->scan_table[i]); + ret = mwifiex_associate(priv, &adapter->scan_table[i]); if (ret) return ret; } else { @@ -441,7 +194,7 @@ static int mwifiex_bss_ioctl_start(struct mwifiex_private *priv, /* Exit Adhoc mode first */ dev_dbg(adapter->dev, "info: Sending Adhoc Stop\n"); - ret = mwifiex_deauthenticate(priv, NULL, NULL); + ret = mwifiex_deauthenticate(priv, NULL); if (ret) return ret; @@ -460,75 +213,39 @@ static int mwifiex_bss_ioctl_start(struct mwifiex_private *priv, if (i >= 0) { dev_dbg(adapter->dev, "info: network found in scan" " list. Joining...\n"); - ret = mwifiex_adhoc_join(priv, wait, - &adapter->scan_table[i]); + ret = mwifiex_adhoc_join(priv, &adapter->scan_table[i]); if (ret) return ret; } else { /* i >= 0 */ dev_dbg(adapter->dev, "info: Network not found in " "the list, creating adhoc with ssid = %s\n", ssid_bssid->ssid.ssid); - ret = mwifiex_adhoc_start(priv, wait, - &ssid_bssid->ssid); + ret = mwifiex_adhoc_start(priv, &ssid_bssid->ssid); if (ret) return ret; } } - if (!ret) - ret = -EINPROGRESS; - return ret; } /* - * Sends IOCTL request to connect with a BSS. - * - * This function allocates the IOCTL request buffer, fills it - * with requisite parameters and calls the IOCTL handler. - */ -int mwifiex_bss_start(struct mwifiex_private *priv, u8 wait_option, - struct mwifiex_ssid_bssid *ssid_bssid) -{ - struct mwifiex_wait_queue *wait = NULL; - struct mwifiex_ssid_bssid tmp_ssid_bssid; - int status = 0; - - /* Stop the O.S. TX queue if needed */ - if (!netif_queue_stopped(priv->netdev)) - netif_stop_queue(priv->netdev); - - /* Allocate wait buffer */ - wait = mwifiex_alloc_fill_wait_queue(priv, wait_option); - if (!wait) - return -ENOMEM; - - if (ssid_bssid) - memcpy(&tmp_ssid_bssid, ssid_bssid, - sizeof(struct mwifiex_ssid_bssid)); - status = mwifiex_bss_ioctl_start(priv, wait, &tmp_ssid_bssid); - - status = mwifiex_request_ioctl(priv, wait, status, wait_option); - - kfree(wait); - return status; -} - -/* * IOCTL request handler to set host sleep configuration. * * This function prepares the correct firmware command and * issues it. */ -static int -mwifiex_pm_ioctl_hs_cfg(struct mwifiex_private *priv, - struct mwifiex_wait_queue *wait, - u16 action, struct mwifiex_ds_hs_cfg *hs_cfg) +int mwifiex_set_hs_params(struct mwifiex_private *priv, u16 action, + int cmd_type, struct mwifiex_ds_hs_cfg *hs_cfg) + { struct mwifiex_adapter *adapter = priv->adapter; int status = 0; u32 prev_cond = 0; + if (!hs_cfg) + return -ENOMEM; + switch (action) { case HostCmd_ACT_GEN_SET: if (adapter->pps_uapsd_mode) { @@ -561,12 +278,16 @@ mwifiex_pm_ioctl_hs_cfg(struct mwifiex_private *priv, status = -1; break; } - status = mwifiex_prepare_cmd(priv, - HostCmd_CMD_802_11_HS_CFG_ENH, - HostCmd_ACT_GEN_SET, - 0, wait, &adapter->hs_cfg); - if (!status) - status = -EINPROGRESS; + if (cmd_type == MWIFIEX_SYNC_CMD) + status = mwifiex_send_cmd_sync(priv, + HostCmd_CMD_802_11_HS_CFG_ENH, + HostCmd_ACT_GEN_SET, 0, + &adapter->hs_cfg); + else + status = mwifiex_send_cmd_async(priv, + HostCmd_CMD_802_11_HS_CFG_ENH, + HostCmd_ACT_GEN_SET, 0, + &adapter->hs_cfg); if (hs_cfg->conditions == HOST_SLEEP_CFG_CANCEL) /* Restore previous condition */ adapter->hs_cfg.conditions = @@ -592,42 +313,12 @@ mwifiex_pm_ioctl_hs_cfg(struct mwifiex_private *priv, } /* - * Sends IOCTL request to set Host Sleep parameters. - * - * This function allocates the IOCTL request buffer, fills it - * with requisite parameters and calls the IOCTL handler. - */ -int mwifiex_set_hs_params(struct mwifiex_private *priv, u16 action, - u8 wait_option, - struct mwifiex_ds_hs_cfg *hscfg) -{ - int ret = 0; - struct mwifiex_wait_queue *wait = NULL; - - if (!hscfg) - return -ENOMEM; - - /* Allocate wait buffer */ - wait = mwifiex_alloc_fill_wait_queue(priv, wait_option); - if (!wait) - return -ENOMEM; - - ret = mwifiex_pm_ioctl_hs_cfg(priv, wait, action, hscfg); - - ret = mwifiex_request_ioctl(priv, wait, ret, wait_option); - - if (wait && (ret != -EINPROGRESS)) - kfree(wait); - return ret; -} - -/* * Sends IOCTL request to cancel the existing Host Sleep configuration. * * This function allocates the IOCTL request buffer, fills it * with requisite parameters and calls the IOCTL handler. */ -int mwifiex_cancel_hs(struct mwifiex_private *priv, u8 wait_option) +int mwifiex_cancel_hs(struct mwifiex_private *priv, int cmd_type) { int ret = 0; struct mwifiex_ds_hs_cfg hscfg; @@ -636,7 +327,7 @@ int mwifiex_cancel_hs(struct mwifiex_private *priv, u8 wait_option) hscfg.conditions = HOST_SLEEP_CFG_CANCEL; hscfg.is_invoke_hostcmd = true; ret = mwifiex_set_hs_params(priv, HostCmd_ACT_GEN_SET, - wait_option, &hscfg); + cmd_type, &hscfg); return ret; } @@ -665,8 +356,8 @@ int mwifiex_enable_hs(struct mwifiex_adapter *adapter) if (mwifiex_set_hs_params(mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_STA), - HostCmd_ACT_GEN_SET, - MWIFIEX_IOCTL_WAIT, &hscfg)) { + HostCmd_ACT_GEN_SET, MWIFIEX_SYNC_CMD, + &hscfg)) { dev_err(adapter->dev, "IOCTL request HS enable failed\n"); return false; } @@ -679,69 +370,6 @@ int mwifiex_enable_hs(struct mwifiex_adapter *adapter) EXPORT_SYMBOL_GPL(mwifiex_enable_hs); /* - * IOCTL request handler to get signal information. - * - * This function prepares the correct firmware command and - * issues it to get the signal (RSSI) information. - * - * This only works in the connected mode. - */ -static int mwifiex_get_info_signal(struct mwifiex_private *priv, - struct mwifiex_wait_queue *wait, - struct mwifiex_ds_get_signal *signal) -{ - int ret = 0; - - if (!wait) { - dev_err(priv->adapter->dev, "WAIT information is not present\n"); - return -1; - } - - /* Signal info can be obtained only if connected */ - if (!priv->media_connected) { - dev_dbg(priv->adapter->dev, - "info: Can not get signal in disconnected state\n"); - return -1; - } - - /* Send request to firmware */ - ret = mwifiex_prepare_cmd(priv, HostCmd_CMD_RSSI_INFO, - HostCmd_ACT_GEN_GET, 0, wait, signal); - - if (!ret) - ret = -EINPROGRESS; - - return ret; -} - -/* - * IOCTL request handler to get statistics. - * - * This function prepares the correct firmware command and - * issues it to get the statistics (RSSI) information. - */ -static int mwifiex_get_info_stats(struct mwifiex_private *priv, - struct mwifiex_wait_queue *wait, - struct mwifiex_ds_get_stats *log) -{ - int ret = 0; - - if (!wait) { - dev_err(priv->adapter->dev, "MWIFIEX IOCTL information is not present\n"); - return -1; - } - - /* Send request to firmware */ - ret = mwifiex_prepare_cmd(priv, HostCmd_CMD_802_11_GET_LOG, - HostCmd_ACT_GEN_GET, 0, wait, log); - - if (!ret) - ret = -EINPROGRESS; - - return ret; -} - -/* * IOCTL request handler to get BSS information. * * This function collates the information from different driver structures @@ -813,90 +441,20 @@ int mwifiex_get_bss_info(struct mwifiex_private *priv, } /* - * IOCTL request handler to get extended version information. - * - * This function prepares the correct firmware command and - * issues it to get the extended version information. - */ -static int mwifiex_get_info_ver_ext(struct mwifiex_private *priv, - struct mwifiex_wait_queue *wait, - struct mwifiex_ver_ext *ver_ext) -{ - int ret = 0; - - /* Send request to firmware */ - ret = mwifiex_prepare_cmd(priv, HostCmd_CMD_VERSION_EXT, - HostCmd_ACT_GEN_GET, 0, wait, ver_ext); - if (!ret) - ret = -EINPROGRESS; - - return ret; -} - -/* - * IOCTL request handler to set/get SNMP MIB parameters. - * - * This function prepares the correct firmware command and - * issues it. + * The function sets band configurations. * - * Currently the following parameters are supported - - * Set/get RTS Threshold - * Set/get fragmentation threshold - * Set/get retry count - */ -int mwifiex_snmp_mib_ioctl(struct mwifiex_private *priv, - struct mwifiex_wait_queue *wait, - u32 cmd_oid, u16 action, u32 *value) -{ - int ret = 0; - - if (!value) - return -1; - - /* Send request to firmware */ - ret = mwifiex_prepare_cmd(priv, HostCmd_CMD_802_11_SNMP_MIB, - action, cmd_oid, wait, value); - - if (!ret) - ret = -EINPROGRESS; - - return ret; -} - -/* - * IOCTL request handler to set/get band configurations. - * - * For SET operation, it performs extra checks to make sure the Ad-Hoc + * it performs extra checks to make sure the Ad-Hoc * band and channel are compatible. Otherwise it returns an error. * - * For GET operation, this function retrieves the following information - - * - Infra bands - * - Ad-hoc band - * - Ad-hoc channel - * - Secondary channel offset */ -int mwifiex_radio_ioctl_band_cfg(struct mwifiex_private *priv, - u16 action, - struct mwifiex_ds_band_cfg *radio_cfg) +int mwifiex_set_radio_band_cfg(struct mwifiex_private *priv, + struct mwifiex_ds_band_cfg *radio_cfg) { struct mwifiex_adapter *adapter = priv->adapter; u8 infra_band = 0; u8 adhoc_band = 0; u32 adhoc_channel = 0; - if (action == HostCmd_ACT_GEN_GET) { - /* Infra Bands */ - radio_cfg->config_bands = adapter->config_bands; - /* Adhoc Band */ - radio_cfg->adhoc_start_band = adapter->adhoc_start_band; - /* Adhoc channel */ - radio_cfg->adhoc_channel = priv->adhoc_channel; - /* Secondary channel offset */ - radio_cfg->sec_chan_offset = adapter->chan_offset; - return 0; - } - - /* For action = SET */ infra_band = (u8) radio_cfg->config_bands; adhoc_band = (u8) radio_cfg->adhoc_start_band; adhoc_channel = radio_cfg->adhoc_channel; @@ -950,8 +508,8 @@ int mwifiex_radio_ioctl_band_cfg(struct mwifiex_private *priv, * This function performs validity checking on channel/frequency * compatibility and returns failure if not valid. */ -int mwifiex_bss_ioctl_channel(struct mwifiex_private *priv, u16 action, - struct mwifiex_chan_freq_power *chan) +int mwifiex_bss_set_channel(struct mwifiex_private *priv, + struct mwifiex_chan_freq_power *chan) { struct mwifiex_adapter *adapter = priv->adapter; struct mwifiex_chan_freq_power *cfp = NULL; @@ -959,16 +517,6 @@ int mwifiex_bss_ioctl_channel(struct mwifiex_private *priv, u16 action, if (!chan) return -1; - if (action == HostCmd_ACT_GEN_GET) { - cfp = mwifiex_get_cfp_by_band_and_channel_from_cfg80211(priv, - priv->curr_bss_params.band, - (u16) priv->curr_bss_params.bss_descriptor. - channel); - chan->channel = cfp->channel; - chan->freq = cfp->freq; - - return 0; - } if (!chan->channel && !chan->freq) return -1; if (adapter->adhoc_start_band & BAND_AN) @@ -1024,7 +572,6 @@ int mwifiex_bss_ioctl_channel(struct mwifiex_private *priv, u16 action, * issues it to set or get the ad-hoc channel. */ static int mwifiex_bss_ioctl_ibss_channel(struct mwifiex_private *priv, - struct mwifiex_wait_queue *wait, u16 action, u16 *channel) { int ret = 0; @@ -1039,10 +586,8 @@ static int mwifiex_bss_ioctl_ibss_channel(struct mwifiex_private *priv, } /* Send request to firmware */ - ret = mwifiex_prepare_cmd(priv, HostCmd_CMD_802_11_RF_CHANNEL, - action, 0, wait, channel); - if (!ret) - ret = -EINPROGRESS; + ret = mwifiex_send_cmd_sync(priv, HostCmd_CMD_802_11_RF_CHANNEL, + action, 0, channel); return ret; } @@ -1054,7 +599,6 @@ static int mwifiex_bss_ioctl_ibss_channel(struct mwifiex_private *priv, * these are provided, just the best BSS (best RSSI) is returned. */ int mwifiex_bss_ioctl_find_bss(struct mwifiex_private *priv, - struct mwifiex_wait_queue *wait, struct mwifiex_ssid_bssid *ssid_bssid) { struct mwifiex_adapter *adapter = priv->adapter; @@ -1114,10 +658,7 @@ int mwifiex_drv_change_adhoc_chan(struct mwifiex_private *priv, int channel) { int ret = 0; - int status = 0; struct mwifiex_bss_info bss_info; - struct mwifiex_wait_queue *wait = NULL; - u8 wait_option = MWIFIEX_IOCTL_WAIT; struct mwifiex_ssid_bssid ssid_bssid; u16 curr_chan = 0; @@ -1127,19 +668,10 @@ mwifiex_drv_change_adhoc_chan(struct mwifiex_private *priv, int channel) if (mwifiex_get_bss_info(priv, &bss_info)) return -1; - /* Allocate wait buffer */ - wait = mwifiex_alloc_fill_wait_queue(priv, wait_option); - if (!wait) - return -ENOMEM; - /* Get current channel */ - status = mwifiex_bss_ioctl_ibss_channel(priv, wait, HostCmd_ACT_GEN_GET, - &curr_chan); + ret = mwifiex_bss_ioctl_ibss_channel(priv, HostCmd_ACT_GEN_GET, + &curr_chan); - if (mwifiex_request_ioctl(priv, wait, status, wait_option)) { - ret = -1; - goto done; - } if (curr_chan == channel) { ret = 0; goto done; @@ -1154,23 +686,13 @@ mwifiex_drv_change_adhoc_chan(struct mwifiex_private *priv, int channel) /* Do disonnect */ memset(&ssid_bssid, 0, ETH_ALEN); - status = mwifiex_bss_ioctl_stop(priv, wait, ssid_bssid.bssid); + ret = mwifiex_deauthenticate(priv, ssid_bssid.bssid); - if (mwifiex_request_ioctl(priv, wait, status, wait_option)) { - ret = -1; - goto done; - } - - status = mwifiex_bss_ioctl_ibss_channel(priv, wait, HostCmd_ACT_GEN_SET, - (u16 *) &channel); - - if (mwifiex_request_ioctl(priv, wait, status, wait_option)) { - ret = -1; - goto done; - } + ret = mwifiex_bss_ioctl_ibss_channel(priv, HostCmd_ACT_GEN_SET, + (u16 *) &channel); /* Do specific SSID scanning */ - if (mwifiex_request_scan(priv, wait_option, &bss_info.ssid)) { + if (mwifiex_request_scan(priv, &bss_info.ssid)) { ret = -1; goto done; } @@ -1179,13 +701,8 @@ mwifiex_drv_change_adhoc_chan(struct mwifiex_private *priv, int channel) memcpy(&ssid_bssid.ssid, &bss_info.ssid, sizeof(struct mwifiex_802_11_ssid)); - status = mwifiex_bss_ioctl_start(priv, wait, &ssid_bssid); - - if (mwifiex_request_ioctl(priv, wait, status, wait_option)) - ret = -1; - + ret = mwifiex_bss_start(priv, &ssid_bssid); done: - kfree(wait); return ret; } @@ -1198,7 +715,6 @@ done: * for the band. */ static int mwifiex_rate_ioctl_get_rate_value(struct mwifiex_private *priv, - struct mwifiex_wait_queue *wait, struct mwifiex_rate_cfg *rate_cfg) { struct mwifiex_adapter *adapter = priv->adapter; @@ -1242,11 +758,9 @@ static int mwifiex_rate_ioctl_get_rate_value(struct mwifiex_private *priv, } } else { /* Send request to firmware */ - ret = mwifiex_prepare_cmd(priv, - HostCmd_CMD_802_11_TX_RATE_QUERY, - HostCmd_ACT_GEN_GET, 0, wait, NULL); - if (!ret) - ret = -EINPROGRESS; + ret = mwifiex_send_cmd_sync(priv, + HostCmd_CMD_802_11_TX_RATE_QUERY, + HostCmd_ACT_GEN_GET, 0, NULL); } return ret; @@ -1261,7 +775,6 @@ static int mwifiex_rate_ioctl_get_rate_value(struct mwifiex_private *priv, * The function also performs validation checking on the supplied value. */ static int mwifiex_rate_ioctl_set_rate_value(struct mwifiex_private *priv, - struct mwifiex_wait_queue *wait, struct mwifiex_rate_cfg *rate_cfg) { u8 rates[MWIFIEX_SUPPORTED_RATES]; @@ -1316,10 +829,8 @@ static int mwifiex_rate_ioctl_set_rate_value(struct mwifiex_private *priv, } /* Send request to firmware */ - ret = mwifiex_prepare_cmd(priv, HostCmd_CMD_TX_RATE_CFG, - HostCmd_ACT_GEN_SET, 0, wait, bitmap_rates); - if (!ret) - ret = -EINPROGRESS; + ret = mwifiex_send_cmd_sync(priv, HostCmd_CMD_TX_RATE_CFG, + HostCmd_ACT_GEN_SET, 0, bitmap_rates); return ret; } @@ -1331,7 +842,6 @@ static int mwifiex_rate_ioctl_set_rate_value(struct mwifiex_private *priv, * rate index. */ static int mwifiex_rate_ioctl_cfg(struct mwifiex_private *priv, - struct mwifiex_wait_queue *wait, struct mwifiex_rate_cfg *rate_cfg) { int status = 0; @@ -1340,11 +850,9 @@ static int mwifiex_rate_ioctl_cfg(struct mwifiex_private *priv, return -1; if (rate_cfg->action == HostCmd_ACT_GEN_GET) - status = mwifiex_rate_ioctl_get_rate_value( - priv, wait, rate_cfg); + status = mwifiex_rate_ioctl_get_rate_value(priv, rate_cfg); else - status = mwifiex_rate_ioctl_set_rate_value( - priv, wait, rate_cfg); + status = mwifiex_rate_ioctl_set_rate_value(priv, rate_cfg); return status; } @@ -1359,19 +867,11 @@ int mwifiex_drv_get_data_rate(struct mwifiex_private *priv, struct mwifiex_rate_cfg *rate) { int ret = 0; - struct mwifiex_wait_queue *wait = NULL; - u8 wait_option = MWIFIEX_IOCTL_WAIT; - - /* Allocate wait buffer */ - wait = mwifiex_alloc_fill_wait_queue(priv, wait_option); - if (!wait) - return -ENOMEM; memset(rate, 0, sizeof(struct mwifiex_rate_cfg)); rate->action = HostCmd_ACT_GEN_GET; - ret = mwifiex_rate_ioctl_cfg(priv, wait, rate); + ret = mwifiex_rate_ioctl_cfg(priv, rate); - ret = mwifiex_request_ioctl(priv, wait, ret, wait_option); if (!ret) { if (rate && rate->is_rate_auto) rate->rate = mwifiex_index_to_data_rate(priv->adapter, @@ -1382,7 +882,6 @@ int mwifiex_drv_get_data_rate(struct mwifiex_private *priv, ret = -1; } - kfree(wait); return ret; } @@ -1398,9 +897,8 @@ int mwifiex_drv_get_data_rate(struct mwifiex_private *priv, * - Modulation class HTBW20 * - Modulation class HTBW40 */ -static int mwifiex_power_ioctl_set_power(struct mwifiex_private *priv, - struct mwifiex_wait_queue *wait, - struct mwifiex_power_cfg *power_cfg) +int mwifiex_set_tx_power(struct mwifiex_private *priv, + struct mwifiex_power_cfg *power_cfg) { int ret = 0; struct host_cmd_ds_txpwr_cfg *txp_cfg = NULL; @@ -1473,12 +971,10 @@ static int mwifiex_power_ioctl_set_power(struct mwifiex_private *priv, pg->ht_bandwidth = HT_BW_40; } /* Send request to firmware */ - ret = mwifiex_prepare_cmd(priv, HostCmd_CMD_TXPWR_CFG, - HostCmd_ACT_GEN_SET, 0, wait, buf); - if (!ret) - ret = -EINPROGRESS; - kfree(buf); + ret = mwifiex_send_cmd_sync(priv, HostCmd_CMD_TXPWR_CFG, + HostCmd_ACT_GEN_SET, 0, buf); + kfree(buf); return ret; } @@ -1488,33 +984,23 @@ static int mwifiex_power_ioctl_set_power(struct mwifiex_private *priv, * This function prepares the correct firmware command and * issues it. */ -static int mwifiex_pm_ioctl_ps_mode(struct mwifiex_private *priv, - struct mwifiex_wait_queue *wait, - u32 *ps_mode, u16 action) +int mwifiex_drv_set_power(struct mwifiex_private *priv, u32 *ps_mode) { int ret = 0; struct mwifiex_adapter *adapter = priv->adapter; u16 sub_cmd; - if (action == HostCmd_ACT_GEN_SET) { - if (*ps_mode) - adapter->ps_mode = MWIFIEX_802_11_POWER_MODE_PSP; - else - adapter->ps_mode = MWIFIEX_802_11_POWER_MODE_CAM; - sub_cmd = (*ps_mode) ? EN_AUTO_PS : DIS_AUTO_PS; - ret = mwifiex_prepare_cmd(priv, HostCmd_CMD_802_11_PS_MODE_ENH, - sub_cmd, BITMAP_STA_PS, wait, NULL); - if ((!ret) && (sub_cmd == DIS_AUTO_PS)) - ret = mwifiex_prepare_cmd(priv, - HostCmd_CMD_802_11_PS_MODE_ENH, GET_PS, - 0, NULL, NULL); - } else { - ret = mwifiex_prepare_cmd(priv, HostCmd_CMD_802_11_PS_MODE_ENH, - GET_PS, 0, wait, NULL); - } - - if (!ret) - ret = -EINPROGRESS; + if (*ps_mode) + adapter->ps_mode = MWIFIEX_802_11_POWER_MODE_PSP; + else + adapter->ps_mode = MWIFIEX_802_11_POWER_MODE_CAM; + sub_cmd = (*ps_mode) ? EN_AUTO_PS : DIS_AUTO_PS; + ret = mwifiex_send_cmd_sync(priv, HostCmd_CMD_802_11_PS_MODE_ENH, + sub_cmd, BITMAP_STA_PS, NULL); + if ((!ret) && (sub_cmd == DIS_AUTO_PS)) + ret = mwifiex_send_cmd_async(priv, + HostCmd_CMD_802_11_PS_MODE_ENH, GET_PS, + 0, NULL); return ret; } @@ -1600,18 +1086,14 @@ static int mwifiex_set_wapi_ie(struct mwifiex_private *priv, * This function prepares the correct firmware command and * issues it. */ -static int mwifiex_sec_ioctl_set_wapi_key(struct mwifiex_adapter *adapter, - struct mwifiex_wait_queue *wait, +static int mwifiex_sec_ioctl_set_wapi_key(struct mwifiex_private *priv, struct mwifiex_ds_encrypt_key *encrypt_key) { int ret = 0; - struct mwifiex_private *priv = adapter->priv[wait->bss_index]; - ret = mwifiex_prepare_cmd(priv, HostCmd_CMD_802_11_KEY_MATERIAL, - HostCmd_ACT_GEN_SET, KEY_INFO_ENABLED, - wait, encrypt_key); - if (!ret) - ret = -EINPROGRESS; + ret = mwifiex_send_cmd_sync(priv, HostCmd_CMD_802_11_KEY_MATERIAL, + HostCmd_ACT_GEN_SET, KEY_INFO_ENABLED, + encrypt_key); return ret; } @@ -1622,12 +1104,10 @@ static int mwifiex_sec_ioctl_set_wapi_key(struct mwifiex_adapter *adapter, * This function prepares the correct firmware command and * issues it, after validation checks. */ -static int mwifiex_sec_ioctl_set_wep_key(struct mwifiex_adapter *adapter, - struct mwifiex_wait_queue *wait, +static int mwifiex_sec_ioctl_set_wep_key(struct mwifiex_private *priv, struct mwifiex_ds_encrypt_key *encrypt_key) { int ret = 0; - struct mwifiex_private *priv = adapter->priv[wait->bss_index]; struct mwifiex_wep_key *wep_key = NULL; int index; @@ -1641,7 +1121,7 @@ static int mwifiex_sec_ioctl_set_wep_key(struct mwifiex_adapter *adapter, /* Copy the required key as the current key */ wep_key = &priv->wep_key[index]; if (!wep_key->key_length) { - dev_err(adapter->dev, + dev_err(priv->adapter->dev, "key not set, so cannot enable it\n"); return -1; } @@ -1661,8 +1141,9 @@ static int mwifiex_sec_ioctl_set_wep_key(struct mwifiex_adapter *adapter, } if (wep_key->key_length) { /* Send request to firmware */ - ret = mwifiex_prepare_cmd(priv, HostCmd_CMD_802_11_KEY_MATERIAL, - HostCmd_ACT_GEN_SET, 0, NULL, NULL); + ret = mwifiex_send_cmd_async(priv, + HostCmd_CMD_802_11_KEY_MATERIAL, + HostCmd_ACT_GEN_SET, 0, NULL); if (ret) return ret; } @@ -1672,11 +1153,9 @@ static int mwifiex_sec_ioctl_set_wep_key(struct mwifiex_adapter *adapter, priv->curr_pkt_filter &= ~HostCmd_ACT_MAC_WEP_ENABLE; /* Send request to firmware */ - ret = mwifiex_prepare_cmd(priv, HostCmd_CMD_MAC_CONTROL, - HostCmd_ACT_GEN_SET, 0, wait, - &priv->curr_pkt_filter); - if (!ret) - ret = -EINPROGRESS; + ret = mwifiex_send_cmd_sync(priv, HostCmd_CMD_MAC_CONTROL, + HostCmd_ACT_GEN_SET, 0, + &priv->curr_pkt_filter); return ret; } @@ -1691,18 +1170,16 @@ static int mwifiex_sec_ioctl_set_wep_key(struct mwifiex_adapter *adapter, * * This function can also be used to disable a currently set key. */ -static int mwifiex_sec_ioctl_set_wpa_key(struct mwifiex_adapter *adapter, - struct mwifiex_wait_queue *wait, +static int mwifiex_sec_ioctl_set_wpa_key(struct mwifiex_private *priv, struct mwifiex_ds_encrypt_key *encrypt_key) { int ret = 0; - struct mwifiex_private *priv = adapter->priv[wait->bss_index]; u8 remove_key = false; struct host_cmd_ds_802_11_key_material *ibss_key; /* Current driver only supports key length of up to 32 bytes */ if (encrypt_key->key_len > MWIFIEX_MAX_KEY_LENGTH) { - dev_err(adapter->dev, "key length too long\n"); + dev_err(priv->adapter->dev, "key length too long\n"); return -1; } @@ -1713,9 +1190,10 @@ static int mwifiex_sec_ioctl_set_wpa_key(struct mwifiex_adapter *adapter, */ /* Send the key as PTK to firmware */ encrypt_key->key_index = MWIFIEX_KEY_INDEX_UNICAST; - ret = mwifiex_prepare_cmd(priv, HostCmd_CMD_802_11_KEY_MATERIAL, - HostCmd_ACT_GEN_SET, KEY_INFO_ENABLED, - NULL, encrypt_key); + ret = mwifiex_send_cmd_async(priv, + HostCmd_CMD_802_11_KEY_MATERIAL, + HostCmd_ACT_GEN_SET, KEY_INFO_ENABLED, + encrypt_key); if (ret) return ret; @@ -1740,18 +1218,16 @@ static int mwifiex_sec_ioctl_set_wpa_key(struct mwifiex_adapter *adapter, if (remove_key) /* Send request to firmware */ - ret = mwifiex_prepare_cmd(priv, HostCmd_CMD_802_11_KEY_MATERIAL, - HostCmd_ACT_GEN_SET, - !(KEY_INFO_ENABLED), - wait, encrypt_key); + ret = mwifiex_send_cmd_sync(priv, + HostCmd_CMD_802_11_KEY_MATERIAL, + HostCmd_ACT_GEN_SET, !(KEY_INFO_ENABLED), + encrypt_key); else /* Send request to firmware */ - ret = mwifiex_prepare_cmd(priv, HostCmd_CMD_802_11_KEY_MATERIAL, - HostCmd_ACT_GEN_SET, KEY_INFO_ENABLED, - wait, encrypt_key); - - if (!ret) - ret = -EINPROGRESS; + ret = mwifiex_send_cmd_sync(priv, + HostCmd_CMD_802_11_KEY_MATERIAL, + HostCmd_ACT_GEN_SET, KEY_INFO_ENABLED, + encrypt_key); return ret; } @@ -1764,21 +1240,16 @@ static int mwifiex_sec_ioctl_set_wpa_key(struct mwifiex_adapter *adapter, */ static int mwifiex_sec_ioctl_encrypt_key(struct mwifiex_private *priv, - struct mwifiex_wait_queue *wait, struct mwifiex_ds_encrypt_key *encrypt_key) { int status = 0; - struct mwifiex_adapter *adapter = priv->adapter; if (encrypt_key->is_wapi_key) - status = mwifiex_sec_ioctl_set_wapi_key(adapter, wait, - encrypt_key); + status = mwifiex_sec_ioctl_set_wapi_key(priv, encrypt_key); else if (encrypt_key->key_len > WLAN_KEY_LEN_WEP104) - status = mwifiex_sec_ioctl_set_wpa_key(adapter, wait, - encrypt_key); + status = mwifiex_sec_ioctl_set_wpa_key(priv, encrypt_key); else - status = mwifiex_sec_ioctl_set_wep_key(adapter, wait, - encrypt_key); + status = mwifiex_sec_ioctl_set_wep_key(priv, encrypt_key); return status; } @@ -1806,94 +1277,31 @@ mwifiex_drv_get_driver_version(struct mwifiex_adapter *adapter, char *version, } /* - * Sends IOCTL request to set Tx power. It can be set to either auto - * or a fixed value. - * - * This function allocates the IOCTL request buffer, fills it - * with requisite parameters and calls the IOCTL handler. - */ -int -mwifiex_set_tx_power(struct mwifiex_private *priv, int type, int dbm) -{ - struct mwifiex_power_cfg power_cfg; - struct mwifiex_wait_queue *wait = NULL; - int status = 0; - int ret = 0; - - wait = mwifiex_alloc_fill_wait_queue(priv, MWIFIEX_IOCTL_WAIT); - if (!wait) - return -ENOMEM; - - if (type == NL80211_TX_POWER_FIXED) { - power_cfg.is_power_auto = 0; - power_cfg.power_level = dbm; - } else { - power_cfg.is_power_auto = 1; - } - status = mwifiex_power_ioctl_set_power(priv, wait, &power_cfg); - - ret = mwifiex_request_ioctl(priv, wait, status, MWIFIEX_IOCTL_WAIT); - - kfree(wait); - return ret; -} - -/* - * Sends IOCTL request to get scan table. - * - * This function allocates the IOCTL request buffer, fills it - * with requisite parameters and calls the IOCTL handler. - */ -int mwifiex_get_scan_table(struct mwifiex_private *priv, u8 wait_option, - struct mwifiex_scan_resp *scan_resp) -{ - struct mwifiex_wait_queue *wait = NULL; - struct mwifiex_scan_resp scan; - int status = 0; - - /* Allocate wait buffer */ - wait = mwifiex_alloc_fill_wait_queue(priv, wait_option); - if (!wait) - return -ENOMEM; - - status = mwifiex_scan_networks(priv, wait, HostCmd_ACT_GEN_GET, - NULL, &scan); - - status = mwifiex_request_ioctl(priv, wait, status, wait_option); - if (!status) { - if (scan_resp) - memcpy(scan_resp, &scan, - sizeof(struct mwifiex_scan_resp)); - } - - if (wait && (status != -EINPROGRESS)) - kfree(wait); - return status; -} - -/* * Sends IOCTL request to get signal information. * * This function allocates the IOCTL request buffer, fills it * with requisite parameters and calls the IOCTL handler. */ -int mwifiex_get_signal_info(struct mwifiex_private *priv, u8 wait_option, +int mwifiex_get_signal_info(struct mwifiex_private *priv, struct mwifiex_ds_get_signal *signal) { struct mwifiex_ds_get_signal info; - struct mwifiex_wait_queue *wait = NULL; int status = 0; - /* Allocate wait buffer */ - wait = mwifiex_alloc_fill_wait_queue(priv, wait_option); - if (!wait) - return -ENOMEM; - + memset(&info, 0, sizeof(struct mwifiex_ds_get_signal)); info.selector = ALL_RSSI_INFO_MASK; - status = mwifiex_get_info_signal(priv, wait, &info); + /* Signal info can be obtained only if connected */ + if (!priv->media_connected) { + dev_dbg(priv->adapter->dev, + "info: Can not get signal in disconnected state\n"); + return -1; + } + + /* Send request to firmware */ + status = mwifiex_send_cmd_sync(priv, HostCmd_CMD_RSSI_INFO, + HostCmd_ACT_GEN_GET, 0, signal); - status = mwifiex_request_ioctl(priv, wait, status, wait_option); if (!status) { if (signal) memcpy(signal, &info, @@ -1904,8 +1312,6 @@ int mwifiex_get_signal_info(struct mwifiex_private *priv, u8 wait_option, priv->w_stats.qual.noise = info.bcn_nf_avg; } - if (wait && (status != -EINPROGRESS)) - kfree(wait); return status; } @@ -1918,15 +1324,9 @@ int mwifiex_get_signal_info(struct mwifiex_private *priv, u8 wait_option, int mwifiex_set_encode(struct mwifiex_private *priv, const u8 *key, int key_len, u8 key_index, int disable) { - struct mwifiex_wait_queue *wait = NULL; struct mwifiex_ds_encrypt_key encrypt_key; - int status = 0; int ret = 0; - wait = mwifiex_alloc_fill_wait_queue(priv, MWIFIEX_IOCTL_WAIT); - if (!wait) - return -ENOMEM; - memset(&encrypt_key, 0, sizeof(struct mwifiex_ds_encrypt_key)); encrypt_key.key_len = key_len; if (!disable) { @@ -1937,40 +1337,8 @@ int mwifiex_set_encode(struct mwifiex_private *priv, const u8 *key, encrypt_key.key_disable = true; } - status = mwifiex_sec_ioctl_encrypt_key(priv, wait, &encrypt_key); - - if (mwifiex_request_ioctl(priv, wait, status, MWIFIEX_IOCTL_WAIT)) - ret = -EFAULT; - - kfree(wait); - return ret; -} - -/* - * Sends IOCTL request to set power management parameters. - * - * This function allocates the IOCTL request buffer, fills it - * with requisite parameters and calls the IOCTL handler. - */ -int -mwifiex_drv_set_power(struct mwifiex_private *priv, bool power_on) -{ - int ret = 0; - int status = 0; - struct mwifiex_wait_queue *wait = NULL; - u32 ps_mode; - - wait = mwifiex_alloc_fill_wait_queue(priv, MWIFIEX_IOCTL_WAIT); - if (!wait) - return -ENOMEM; - - ps_mode = power_on; - status = mwifiex_pm_ioctl_ps_mode(priv, wait, &ps_mode, - HostCmd_ACT_GEN_SET); + ret = mwifiex_sec_ioctl_encrypt_key(priv, &encrypt_key); - ret = mwifiex_request_ioctl(priv, wait, status, MWIFIEX_IOCTL_WAIT); - - kfree(wait); return ret; } @@ -1984,26 +1352,17 @@ int mwifiex_get_ver_ext(struct mwifiex_private *priv) { struct mwifiex_ver_ext ver_ext; - struct mwifiex_wait_queue *wait = NULL; - int status = 0; int ret = 0; - u8 wait_option = MWIFIEX_IOCTL_WAIT; - - /* Allocate wait buffer */ - wait = mwifiex_alloc_fill_wait_queue(priv, wait_option); - if (!wait) - return -ENOMEM; /* get fw version */ memset(&ver_ext, 0, sizeof(struct host_cmd_ds_version_ext)); - status = mwifiex_get_info_ver_ext(priv, wait, &ver_ext); - - ret = mwifiex_request_ioctl(priv, wait, status, wait_option); + /* Send request to firmware */ + ret = mwifiex_send_cmd_sync(priv, HostCmd_CMD_VERSION_EXT, + HostCmd_ACT_GEN_GET, 0, &ver_ext); if (ret) ret = -1; - kfree(wait); return ret; } @@ -2018,21 +1377,13 @@ mwifiex_get_stats_info(struct mwifiex_private *priv, struct mwifiex_ds_get_stats *log) { int ret = 0; - int status = 0; - struct mwifiex_wait_queue *wait = NULL; struct mwifiex_ds_get_stats get_log; - u8 wait_option = MWIFIEX_IOCTL_WAIT; - - /* Allocate wait buffer */ - wait = mwifiex_alloc_fill_wait_queue(priv, wait_option); - if (!wait) - return -ENOMEM; memset(&get_log, 0, sizeof(struct mwifiex_ds_get_stats)); - status = mwifiex_get_info_stats(priv, wait, &get_log); + /* Send request to firmware */ + ret = mwifiex_send_cmd_sync(priv, HostCmd_CMD_802_11_GET_LOG, + HostCmd_ACT_GEN_GET, 0, &get_log); - /* Send IOCTL request to MWIFIEX */ - ret = mwifiex_request_ioctl(priv, wait, status, wait_option); if (!ret) { if (log) memcpy(log, &get_log, sizeof(struct @@ -2042,7 +1393,6 @@ mwifiex_get_stats_info(struct mwifiex_private *priv, priv->w_stats.discard.misc = get_log.ack_failure; } - kfree(wait); return ret; } @@ -2060,7 +1410,6 @@ mwifiex_get_stats_info(struct mwifiex_private *priv, * - CAU */ static int mwifiex_reg_mem_ioctl_reg_rw(struct mwifiex_private *priv, - struct mwifiex_wait_queue *wait, struct mwifiex_ds_reg_rw *reg_rw, u16 action) { @@ -2088,10 +1437,7 @@ static int mwifiex_reg_mem_ioctl_reg_rw(struct mwifiex_private *priv, } /* Send request to firmware */ - ret = mwifiex_prepare_cmd(priv, cmd_no, action, 0, wait, reg_rw); - - if (!ret) - ret = -EINPROGRESS; + ret = mwifiex_send_cmd_sync(priv, cmd_no, action, 0, reg_rw); return ret; } @@ -2107,23 +1453,13 @@ mwifiex_reg_write(struct mwifiex_private *priv, u32 reg_type, u32 reg_offset, u32 reg_value) { int ret = 0; - int status = 0; - struct mwifiex_wait_queue *wait = NULL; struct mwifiex_ds_reg_rw reg_rw; - wait = mwifiex_alloc_fill_wait_queue(priv, MWIFIEX_IOCTL_WAIT); - if (!wait) - return -ENOMEM; - reg_rw.type = cpu_to_le32(reg_type); reg_rw.offset = cpu_to_le32(reg_offset); reg_rw.value = cpu_to_le32(reg_value); - status = mwifiex_reg_mem_ioctl_reg_rw(priv, wait, ®_rw, - HostCmd_ACT_GEN_SET); + ret = mwifiex_reg_mem_ioctl_reg_rw(priv, ®_rw, HostCmd_ACT_GEN_SET); - ret = mwifiex_request_ioctl(priv, wait, status, MWIFIEX_IOCTL_WAIT); - - kfree(wait); return ret; } @@ -2138,50 +1474,18 @@ mwifiex_reg_read(struct mwifiex_private *priv, u32 reg_type, u32 reg_offset, u32 *value) { int ret = 0; - int status = 0; - struct mwifiex_wait_queue *wait = NULL; struct mwifiex_ds_reg_rw reg_rw; - wait = mwifiex_alloc_fill_wait_queue(priv, MWIFIEX_IOCTL_WAIT); - if (!wait) - return -ENOMEM; - reg_rw.type = cpu_to_le32(reg_type); reg_rw.offset = cpu_to_le32(reg_offset); - status = mwifiex_reg_mem_ioctl_reg_rw(priv, wait, ®_rw, - HostCmd_ACT_GEN_GET); + ret = mwifiex_reg_mem_ioctl_reg_rw(priv, ®_rw, HostCmd_ACT_GEN_GET); - ret = mwifiex_request_ioctl(priv, wait, status, MWIFIEX_IOCTL_WAIT); if (ret) goto done; *value = le32_to_cpu(reg_rw.value); done: - kfree(wait); - return ret; -} - -/* - * IOCTL request handler to read EEPROM. - * - * This function prepares the correct firmware command and - * issues it. - */ -static int -mwifiex_reg_mem_ioctl_read_eeprom(struct mwifiex_private *priv, - struct mwifiex_wait_queue *wait, - struct mwifiex_ds_read_eeprom *rd_eeprom) -{ - int ret = 0; - - /* Send request to firmware */ - ret = mwifiex_prepare_cmd(priv, HostCmd_CMD_802_11_EEPROM_ACCESS, - HostCmd_ACT_GEN_GET, 0, wait, rd_eeprom); - - if (!ret) - ret = -EINPROGRESS; - return ret; } @@ -2196,25 +1500,17 @@ mwifiex_eeprom_read(struct mwifiex_private *priv, u16 offset, u16 bytes, u8 *value) { int ret = 0; - int status = 0; - struct mwifiex_wait_queue *wait = NULL; struct mwifiex_ds_read_eeprom rd_eeprom; - wait = mwifiex_alloc_fill_wait_queue(priv, MWIFIEX_IOCTL_WAIT); - if (!wait) - return -ENOMEM; - rd_eeprom.offset = cpu_to_le16((u16) offset); rd_eeprom.byte_count = cpu_to_le16((u16) bytes); - status = mwifiex_reg_mem_ioctl_read_eeprom(priv, wait, &rd_eeprom); - ret = mwifiex_request_ioctl(priv, wait, status, MWIFIEX_IOCTL_WAIT); - if (ret) - goto done; + /* Send request to firmware */ + ret = mwifiex_send_cmd_sync(priv, HostCmd_CMD_802_11_EEPROM_ACCESS, + HostCmd_ACT_GEN_GET, 0, &rd_eeprom); - memcpy(value, rd_eeprom.value, MAX_EEPROM_DATA); -done: - kfree(wait); + if (!ret) + memcpy(value, rd_eeprom.value, MAX_EEPROM_DATA); return ret; } diff --git a/drivers/net/wireless/mwifiex/sta_tx.c b/drivers/net/wireless/mwifiex/sta_tx.c index e8db6bd..b261d81 100644 --- a/drivers/net/wireless/mwifiex/sta_tx.c +++ b/drivers/net/wireless/mwifiex/sta_tx.c @@ -51,7 +51,7 @@ void *mwifiex_process_sta_txpd(struct mwifiex_private *priv, if (!skb->len) { dev_err(adapter->dev, "Tx: bad packet length: %d\n", skb->len); - tx_info->status_code = MWIFIEX_ERROR_PKT_SIZE_INVALID; + tx_info->status_code = -1; return skb->data; } diff --git a/drivers/net/wireless/mwifiex/util.c b/drivers/net/wireless/mwifiex/util.c index 205022a..9f65587 100644 --- a/drivers/net/wireless/mwifiex/util.c +++ b/drivers/net/wireless/mwifiex/util.c @@ -55,17 +55,12 @@ int mwifiex_shutdown_fw_complete(struct mwifiex_adapter *adapter) } /* - * IOCTL request handler to send function init/shutdown command + * This function sends init/shutdown command * to firmware. - * - * This function prepares the correct firmware command and - * issues it. */ -int mwifiex_misc_ioctl_init_shutdown(struct mwifiex_adapter *adapter, - struct mwifiex_wait_queue *wait, - u32 func_init_shutdown) +int mwifiex_init_shutdown_fw(struct mwifiex_private *priv, + u32 func_init_shutdown) { - struct mwifiex_private *priv = adapter->priv[wait->bss_index]; int ret; u16 cmd; @@ -74,19 +69,16 @@ int mwifiex_misc_ioctl_init_shutdown(struct mwifiex_adapter *adapter, } else if (func_init_shutdown == MWIFIEX_FUNC_SHUTDOWN) { cmd = HostCmd_CMD_FUNC_SHUTDOWN; } else { - dev_err(adapter->dev, "unsupported parameter\n"); + dev_err(priv->adapter->dev, "unsupported parameter\n"); return -1; } /* Send command to firmware */ - ret = mwifiex_prepare_cmd(priv, cmd, HostCmd_ACT_GEN_SET, - 0, wait, NULL); - - if (!ret) - ret = -EINPROGRESS; + ret = mwifiex_send_cmd_sync(priv, cmd, HostCmd_ACT_GEN_SET, 0, NULL); return ret; } +EXPORT_SYMBOL_GPL(mwifiex_init_shutdown_fw); /* * IOCTL request handler to set/get debug information. @@ -222,31 +214,18 @@ int mwifiex_recv_complete(struct mwifiex_adapter *adapter, * corresponding waiting function. Otherwise, it processes the * IOCTL response and frees the response buffer. */ -int mwifiex_ioctl_complete(struct mwifiex_adapter *adapter, - struct mwifiex_wait_queue *wait_queue, - int status) +int mwifiex_complete_cmd(struct mwifiex_adapter *adapter) { - enum mwifiex_error_code status_code = - (enum mwifiex_error_code) wait_queue->status; - - atomic_dec(&adapter->ioctl_pending); + atomic_dec(&adapter->cmd_pending); + dev_dbg(adapter->dev, "cmd completed: status=%d\n", + adapter->cmd_wait_q.status); - dev_dbg(adapter->dev, "cmd: IOCTL completed: status=%d," - " status_code=%#x\n", status, status_code); + adapter->cmd_wait_q.condition = true; - if (wait_queue->enabled) { - *wait_queue->condition = true; - wait_queue->status = status; - if (status && (status_code == MWIFIEX_ERROR_CMD_TIMEOUT)) - dev_err(adapter->dev, "cmd timeout\n"); - else - wake_up_interruptible(wait_queue->wait); - } else { - if (status) - dev_err(adapter->dev, "cmd failed: status_code=%#x\n", - status_code); - kfree(wait_queue); - } + if (adapter->cmd_wait_q.status == -ETIMEDOUT) + dev_err(adapter->dev, "cmd timeout\n"); + else + wake_up_interruptible(&adapter->cmd_wait_q.wait); return 0; } -- cgit v0.10.2 From 19a898601ad192d8c59c3a8f1a4501919f53b94d Mon Sep 17 00:00:00 2001 From: Yogesh Ashok Powar Date: Wed, 13 Apr 2011 17:27:07 -0700 Subject: mwifiex: remove redundant "return" at end of void function The return statement at the last line of a void function is not necessary. Signed-off-by: Yogesh Ashok Powar Signed-off-by: Bing Zhao Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/mwifiex/11n.c b/drivers/net/wireless/mwifiex/11n.c index edf4c27..c57107a 100644 --- a/drivers/net/wireless/mwifiex/11n.c +++ b/drivers/net/wireless/mwifiex/11n.c @@ -543,8 +543,6 @@ mwifiex_cfg_tx_buf(struct mwifiex_private *priv, if (curr_tx_buf_size != tx_buf) mwifiex_send_cmd_async(priv, HostCmd_CMD_RECONFIGURE_TX_BUFF, HostCmd_ACT_GEN_SET, 0, &tx_buf); - - return; } /* @@ -582,8 +580,6 @@ void mwifiex_11n_delete_tx_ba_stream_tbl_entry(struct mwifiex_private *priv, list_del(&tx_ba_tsr_tbl->list); kfree(tx_ba_tsr_tbl); - - return; } /* @@ -662,8 +658,6 @@ void mwifiex_11n_create_tx_ba_stream_tbl(struct mwifiex_private *priv, list_add_tail(&new_node->list, &priv->tx_ba_stream_tbl_ptr); spin_unlock_irqrestore(&priv->tx_ba_stream_tbl_lock, flags); } - - return; } /* diff --git a/drivers/net/wireless/mwifiex/11n_rxreorder.c b/drivers/net/wireless/mwifiex/11n_rxreorder.c index ef46d0a..6736fc6 100644 --- a/drivers/net/wireless/mwifiex/11n_rxreorder.c +++ b/drivers/net/wireless/mwifiex/11n_rxreorder.c @@ -309,8 +309,6 @@ mwifiex_11n_create_rx_reorder_tbl(struct mwifiex_private *priv, u8 *ta, spin_lock_irqsave(&priv->rx_reorder_tbl_lock, flags); list_add_tail(&new_node->list, &priv->rx_reorder_tbl_ptr); spin_unlock_irqrestore(&priv->rx_reorder_tbl_lock, flags); - - return; } /* @@ -610,8 +608,6 @@ void mwifiex_11n_ba_stream_timeout(struct mwifiex_private *priv, (u16) event->origninator << DELBA_INITIATOR_POS); delba.reason_code = cpu_to_le16(WLAN_REASON_QSTA_TIMEOUT); mwifiex_send_cmd_async(priv, HostCmd_CMD_11N_DELBA, 0, 0, &delba); - - return; } /* diff --git a/drivers/net/wireless/mwifiex/cfg80211.c b/drivers/net/wireless/mwifiex/cfg80211.c index a1ff490..74b6cf2 100644 --- a/drivers/net/wireless/mwifiex/cfg80211.c +++ b/drivers/net/wireless/mwifiex/cfg80211.c @@ -1428,6 +1428,4 @@ done: memset(priv->cfg_bssid, 0, ETH_ALEN); priv->disconnect = 0; } - - return; } diff --git a/drivers/net/wireless/mwifiex/cmdevt.c b/drivers/net/wireless/mwifiex/cmdevt.c index bb6fecd..776146a 100644 --- a/drivers/net/wireless/mwifiex/cmdevt.c +++ b/drivers/net/wireless/mwifiex/cmdevt.c @@ -94,8 +94,6 @@ mwifiex_clean_cmd_node(struct mwifiex_adapter *adapter, mwifiex_recv_complete(adapter, cmd_node->resp_skb, 0); cmd_node->resp_skb = NULL; } - - return; } /* @@ -536,7 +534,7 @@ mwifiex_insert_cmd_to_free_q(struct mwifiex_adapter *adapter, { unsigned long flags; - if (cmd_node == NULL) + if (!cmd_node) return; if (cmd_node->wait_q_enabled) @@ -548,8 +546,6 @@ mwifiex_insert_cmd_to_free_q(struct mwifiex_adapter *adapter, spin_lock_irqsave(&adapter->cmd_free_q_lock, flags); list_add_tail(&cmd_node->list, &adapter->cmd_free_q); spin_unlock_irqrestore(&adapter->cmd_free_q_lock, flags); - - return; } /* @@ -594,8 +590,6 @@ mwifiex_insert_cmd_to_pending_q(struct mwifiex_adapter *adapter, spin_unlock_irqrestore(&adapter->cmd_pending_q_lock, flags); dev_dbg(adapter->dev, "cmd: QUEUE_CMD: cmd=%#x is queued\n", command); - - return; } /* @@ -871,8 +865,6 @@ mwifiex_cmd_timeout_func(unsigned long function_context) } if (adapter->hw_status == MWIFIEX_HW_STATUS_INITIALIZING) mwifiex_init_fw_complete(adapter); - - return; } /* @@ -989,8 +981,6 @@ mwifiex_cancel_pending_ioctl(struct mwifiex_adapter *adapter) } adapter->cmd_wait_q.status = -1; mwifiex_complete_cmd(adapter); - - return; } /* @@ -1094,7 +1084,6 @@ mwifiex_process_hs_config(struct mwifiex_adapter *adapter) adapter->is_hs_configured = false; mwifiex_hs_activated_event(mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_ANY), false); - return; } /* diff --git a/drivers/net/wireless/mwifiex/debugfs.c b/drivers/net/wireless/mwifiex/debugfs.c index 77d7c77..7ddcb06 100644 --- a/drivers/net/wireless/mwifiex/debugfs.c +++ b/drivers/net/wireless/mwifiex/debugfs.c @@ -735,8 +735,6 @@ mwifiex_dev_debugfs_init(struct mwifiex_private *priv) MWIFIEX_DFS_ADD_FILE(getlog); MWIFIEX_DFS_ADD_FILE(regrdwr); MWIFIEX_DFS_ADD_FILE(rdeeprom); - - return; } /* @@ -749,7 +747,6 @@ mwifiex_dev_debugfs_remove(struct mwifiex_private *priv) return; debugfs_remove_recursive(priv->dfs_dev_dir); - return; } /* diff --git a/drivers/net/wireless/mwifiex/init.c b/drivers/net/wireless/mwifiex/init.c index 26931d5..1b79a5a 100644 --- a/drivers/net/wireless/mwifiex/init.c +++ b/drivers/net/wireless/mwifiex/init.c @@ -299,8 +299,6 @@ static void mwifiex_init_adapter(struct mwifiex_adapter *adapter) adapter->adhoc_awake_period = 0; memset(&adapter->arp_filter, 0, sizeof(adapter->arp_filter)); adapter->arp_filter_size = 0; - - return; } /* @@ -339,8 +337,6 @@ mwifiex_free_adapter(struct mwifiex_adapter *adapter) adapter->if_ops.cleanup_if(adapter); dev_kfree_skb_any(adapter->sleep_cfm); - - return; } /* @@ -428,8 +424,6 @@ void mwifiex_free_lock_list(struct mwifiex_adapter *adapter) list_del(&priv->rx_reorder_tbl_ptr); } } - - return; } /* diff --git a/drivers/net/wireless/mwifiex/main.c b/drivers/net/wireless/mwifiex/main.c index df665db..77abfc3 100644 --- a/drivers/net/wireless/mwifiex/main.c +++ b/drivers/net/wireless/mwifiex/main.c @@ -505,7 +505,6 @@ mwifiex_fill_buffer(struct sk_buff *skb) */ do_gettimeofday(&tv); skb->tstamp = timeval_to_ktime(tv); - return; } /* @@ -820,8 +819,6 @@ mwifiex_remove_interface(struct mwifiex_adapter *adapter, u8 bss_index) wiphy_unregister(priv->wdev->wiphy); wiphy_free(priv->wdev->wiphy); kfree(priv->wdev); - - return; } /* diff --git a/drivers/net/wireless/mwifiex/sdio.c b/drivers/net/wireless/mwifiex/sdio.c index f207756..fa46df5 100644 --- a/drivers/net/wireless/mwifiex/sdio.c +++ b/drivers/net/wireless/mwifiex/sdio.c @@ -859,8 +859,6 @@ static void mwifiex_interrupt_status(struct mwifiex_adapter *adapter) adapter->int_status |= sdio_ireg; spin_unlock_irqrestore(&adapter->int_lock, flags); } - - return; } /* @@ -891,8 +889,6 @@ mwifiex_sdio_interrupt(struct sdio_func *func) mwifiex_interrupt_status(adapter); queue_work(adapter->workqueue, &adapter->main_work); - - return; } /* diff --git a/drivers/net/wireless/mwifiex/sta_cmdresp.c b/drivers/net/wireless/mwifiex/sta_cmdresp.c index 8743c11..20ce8cb 100644 --- a/drivers/net/wireless/mwifiex/sta_cmdresp.c +++ b/drivers/net/wireless/mwifiex/sta_cmdresp.c @@ -103,8 +103,6 @@ mwifiex_process_cmdresp_error(struct mwifiex_private *priv, spin_lock_irqsave(&adapter->mwifiex_cmd_lock, flags); adapter->curr_cmd = NULL; spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock, flags); - - return; } /* diff --git a/drivers/net/wireless/mwifiex/wmm.c b/drivers/net/wireless/mwifiex/wmm.c index 1cfbc6b..6ce6f94 100644 --- a/drivers/net/wireless/mwifiex/wmm.c +++ b/drivers/net/wireless/mwifiex/wmm.c @@ -1232,6 +1232,4 @@ mwifiex_wmm_process_tx(struct mwifiex_adapter *adapter) if (mwifiex_dequeue_tx_packet(adapter)) break; } while (true); - - return; } -- cgit v0.10.2 From 572e8f3ead47ad223fb428a4f1db986317e8e0ec Mon Sep 17 00:00:00 2001 From: Amitkumar Karwar Date: Wed, 13 Apr 2011 17:27:08 -0700 Subject: mwifiex: remove unused function parameters Some function parameters become useless after previous cleanup changes. Signed-off-by: Amitkumar Karwar Signed-off-by: Bing Zhao Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/mwifiex/11n.c b/drivers/net/wireless/mwifiex/11n.c index c57107a..d64065f 100644 --- a/drivers/net/wireless/mwifiex/11n.c +++ b/drivers/net/wireless/mwifiex/11n.c @@ -242,9 +242,7 @@ int mwifiex_ret_11n_addba_req(struct mwifiex_private *priv, * * Handling includes changing the header fields into CPU format. */ -int mwifiex_ret_11n_cfg(struct mwifiex_private *priv, - struct host_cmd_ds_command *resp, - void *data_buf) +int mwifiex_ret_11n_cfg(struct host_cmd_ds_command *resp, void *data_buf) { struct mwifiex_ds_11n_tx_cfg *tx_cfg = NULL; struct host_cmd_ds_11n_cfg *htcfg = &resp->params.htcfg; @@ -298,8 +296,7 @@ int mwifiex_cmd_recfg_tx_buf(struct mwifiex_private *priv, * - Setting AMSDU control parameters (for SET only) * - Ensuring correct endian-ness */ -int mwifiex_cmd_amsdu_aggr_ctrl(struct mwifiex_private *priv, - struct host_cmd_ds_command *cmd, +int mwifiex_cmd_amsdu_aggr_ctrl(struct host_cmd_ds_command *cmd, int cmd_action, void *data_buf) { struct host_cmd_ds_amsdu_aggr_ctrl *amsdu_ctrl = @@ -331,8 +328,7 @@ int mwifiex_cmd_amsdu_aggr_ctrl(struct mwifiex_private *priv, * * Handling includes changing the header fields into CPU format. */ -int mwifiex_ret_amsdu_aggr_ctrl(struct mwifiex_private *priv, - struct host_cmd_ds_command *resp, +int mwifiex_ret_amsdu_aggr_ctrl(struct host_cmd_ds_command *resp, void *data_buf) { struct mwifiex_ds_11n_amsdu_aggr_ctrl *amsdu_aggr_ctrl = NULL; @@ -357,8 +353,7 @@ int mwifiex_ret_amsdu_aggr_ctrl(struct mwifiex_private *priv, * - Setting HT Tx capability and HT Tx information fields * - Ensuring correct endian-ness */ -int mwifiex_cmd_11n_cfg(struct mwifiex_private *priv, - struct host_cmd_ds_command *cmd, +int mwifiex_cmd_11n_cfg(struct host_cmd_ds_command *cmd, u16 cmd_action, void *data_buf) { struct host_cmd_ds_11n_cfg *htcfg = &cmd->params.htcfg; diff --git a/drivers/net/wireless/mwifiex/11n.h b/drivers/net/wireless/mwifiex/11n.h index 71a853e..9128d2c 100644 --- a/drivers/net/wireless/mwifiex/11n.h +++ b/drivers/net/wireless/mwifiex/11n.h @@ -28,15 +28,9 @@ int mwifiex_ret_11n_delba(struct mwifiex_private *priv, struct host_cmd_ds_command *resp); int mwifiex_ret_11n_addba_req(struct mwifiex_private *priv, struct host_cmd_ds_command *resp); -int mwifiex_ret_11n_cfg(struct mwifiex_private *priv, - struct host_cmd_ds_command *resp, +int mwifiex_ret_11n_cfg(struct host_cmd_ds_command *resp, void *data_buf); -int mwifiex_cmd_11n_cfg(struct mwifiex_private *priv, - struct host_cmd_ds_command *cmd, - u16 cmd_action, void *data_buf); - -int mwifiex_cmd_11n_cfg(struct mwifiex_private *priv, - struct host_cmd_ds_command *cmd, +int mwifiex_cmd_11n_cfg(struct host_cmd_ds_command *cmd, u16 cmd_action, void *data_buf); int mwifiex_cmd_append_11n_tlv(struct mwifiex_private *priv, @@ -67,24 +61,19 @@ int mwifiex_get_rx_reorder_tbl(struct mwifiex_private *priv, struct mwifiex_ds_rx_reorder_tbl *buf); int mwifiex_get_tx_ba_stream_tbl(struct mwifiex_private *priv, struct mwifiex_ds_tx_ba_stream_tbl *buf); -int mwifiex_ret_amsdu_aggr_ctrl(struct mwifiex_private *priv, - struct host_cmd_ds_command - *resp, +int mwifiex_ret_amsdu_aggr_ctrl(struct host_cmd_ds_command *resp, void *data_buf); int mwifiex_cmd_recfg_tx_buf(struct mwifiex_private *priv, struct host_cmd_ds_command *cmd, int cmd_action, void *data_buf); -int mwifiex_cmd_amsdu_aggr_ctrl(struct mwifiex_private *priv, - struct host_cmd_ds_command *cmd, - int cmd_action, - void *data_buf); +int mwifiex_cmd_amsdu_aggr_ctrl(struct host_cmd_ds_command *cmd, + int cmd_action, void *data_buf); /* * This function checks whether AMPDU is allowed or not for a particular TID. */ static inline u8 -mwifiex_is_ampdu_allowed(struct mwifiex_private *priv, - struct mwifiex_ra_list_tbl *ptr, int tid) +mwifiex_is_ampdu_allowed(struct mwifiex_private *priv, int tid) { return ((priv->aggr_prio_tbl[tid].ampdu_ap != BA_STREAM_NOT_ALLOWED) ? true : false); @@ -94,8 +83,7 @@ mwifiex_is_ampdu_allowed(struct mwifiex_private *priv, * This function checks whether AMSDU is allowed or not for a particular TID. */ static inline u8 -mwifiex_is_amsdu_allowed(struct mwifiex_private *priv, - struct mwifiex_ra_list_tbl *ptr, int tid) +mwifiex_is_amsdu_allowed(struct mwifiex_private *priv, int tid) { return (((priv->aggr_prio_tbl[tid].amsdu != BA_STREAM_NOT_ALLOWED) && ((priv->is_data_rate_auto) @@ -106,21 +94,18 @@ mwifiex_is_amsdu_allowed(struct mwifiex_private *priv, /* * This function checks whether a BA stream is available or not. */ -static inline u8 -mwifiex_is_ba_stream_avail(struct mwifiex_private *priv) +static inline u8 mwifiex_is_ba_stream_avail(struct mwifiex_adapter *adapter) { - struct mwifiex_private *pmpriv = NULL; - u8 i = 0; + struct mwifiex_private *priv; + u8 i; u32 ba_stream_num = 0; - for (i = 0; i < priv->adapter->priv_num; i++) { - pmpriv = priv->adapter->priv[i]; - if (pmpriv) - ba_stream_num += - mwifiex_wmm_list_len(priv->adapter, - (struct list_head - *) &pmpriv-> - tx_ba_stream_tbl_ptr); + for (i = 0; i < adapter->priv_num; i++) { + priv = adapter->priv[i]; + if (priv) + ba_stream_num += mwifiex_wmm_list_len( + (struct list_head *) + &priv->tx_ba_stream_tbl_ptr); } return ((ba_stream_num < @@ -133,8 +118,7 @@ mwifiex_is_ba_stream_avail(struct mwifiex_private *priv) * Upon successfully locating, both the TID and the RA are returned. */ static inline u8 -mwifiex_find_stream_to_delete(struct mwifiex_private *priv, - struct mwifiex_ra_list_tbl *ptr, int ptr_tid, +mwifiex_find_stream_to_delete(struct mwifiex_private *priv, int ptr_tid, int *ptid, u8 *ra) { int tid; diff --git a/drivers/net/wireless/mwifiex/11n_aggr.c b/drivers/net/wireless/mwifiex/11n_aggr.c index c2abced..c9fb062 100644 --- a/drivers/net/wireless/mwifiex/11n_aggr.c +++ b/drivers/net/wireless/mwifiex/11n_aggr.c @@ -44,8 +44,7 @@ * MSDU => |DA|SA|Length|SNAP|...... ..| */ static int -mwifiex_11n_form_amsdu_pkt(struct mwifiex_adapter *adapter, - struct sk_buff *skb_aggr, +mwifiex_11n_form_amsdu_pkt(struct sk_buff *skb_aggr, struct sk_buff *skb_src, int *pad) { @@ -324,7 +323,7 @@ mwifiex_11n_aggregate_pkt(struct mwifiex_private *priv, spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock, ra_list_flags); - mwifiex_11n_form_amsdu_pkt(adapter, skb_aggr, skb_src, &pad); + mwifiex_11n_form_amsdu_pkt(skb_aggr, skb_src, &pad); mwifiex_write_data_complete(adapter, skb_src, 0); diff --git a/drivers/net/wireless/mwifiex/11n_rxreorder.c b/drivers/net/wireless/mwifiex/11n_rxreorder.c index 6736fc6..755e5d5 100644 --- a/drivers/net/wireless/mwifiex/11n_rxreorder.c +++ b/drivers/net/wireless/mwifiex/11n_rxreorder.c @@ -319,8 +319,7 @@ mwifiex_11n_create_rx_reorder_tbl(struct mwifiex_private *priv, u8 *ta, * - Setting add BA request buffer * - Ensuring correct endian-ness */ -int mwifiex_cmd_11n_addba_req(struct mwifiex_private *priv, - struct host_cmd_ds_command *cmd, void *data_buf) +int mwifiex_cmd_11n_addba_req(struct host_cmd_ds_command *cmd, void *data_buf) { struct host_cmd_ds_11n_addba_req *add_ba_req = (struct host_cmd_ds_11n_addba_req *) @@ -391,8 +390,7 @@ int mwifiex_cmd_11n_addba_rsp_gen(struct mwifiex_private *priv, * - Setting del BA request buffer * - Ensuring correct endian-ness */ -int mwifiex_cmd_11n_delba(struct mwifiex_private *priv, - struct host_cmd_ds_command *cmd, void *data_buf) +int mwifiex_cmd_11n_delba(struct host_cmd_ds_command *cmd, void *data_buf) { struct host_cmd_ds_11n_delba *del_ba = (struct host_cmd_ds_11n_delba *) &cmd->params.del_ba; diff --git a/drivers/net/wireless/mwifiex/11n_rxreorder.h b/drivers/net/wireless/mwifiex/11n_rxreorder.h index 42f5690..f3ca8c8 100644 --- a/drivers/net/wireless/mwifiex/11n_rxreorder.h +++ b/drivers/net/wireless/mwifiex/11n_rxreorder.h @@ -49,14 +49,12 @@ void mwifiex_11n_ba_stream_timeout(struct mwifiex_private *priv, int mwifiex_ret_11n_addba_resp(struct mwifiex_private *priv, struct host_cmd_ds_command *resp); -int mwifiex_cmd_11n_delba(struct mwifiex_private *priv, - struct host_cmd_ds_command *cmd, +int mwifiex_cmd_11n_delba(struct host_cmd_ds_command *cmd, void *data_buf); int mwifiex_cmd_11n_addba_rsp_gen(struct mwifiex_private *priv, struct host_cmd_ds_command *cmd, void *data_buf); -int mwifiex_cmd_11n_addba_req(struct mwifiex_private *priv, - struct host_cmd_ds_command *cmd, +int mwifiex_cmd_11n_addba_req(struct host_cmd_ds_command *cmd, void *data_buf); void mwifiex_11n_cleanup_reorder_tbl(struct mwifiex_private *priv); struct mwifiex_rx_reorder_tbl *mwifiex_11n_get_rxreorder_tbl(struct diff --git a/drivers/net/wireless/mwifiex/cfp.c b/drivers/net/wireless/mwifiex/cfp.c index 07187a4..bb73cfe 100644 --- a/drivers/net/wireless/mwifiex/cfp.c +++ b/drivers/net/wireless/mwifiex/cfp.c @@ -75,8 +75,7 @@ u8 supported_rates_n[N_SUPPORTED_RATES] = { 0x02, 0x04, 0 }; * This function maps an index in supported rates table into * the corresponding data rate. */ -u32 mwifiex_index_to_data_rate(struct mwifiex_adapter *adapter, u8 index, - u8 ht_info) +u32 mwifiex_index_to_data_rate(u8 index, u8 ht_info) { u16 mcs_rate[4][8] = { {0x1b, 0x36, 0x51, 0x6c, 0xa2, 0xd8, 0xf3, 0x10e} @@ -126,7 +125,7 @@ u32 mwifiex_index_to_data_rate(struct mwifiex_adapter *adapter, u8 index, * This function maps a data rate value into corresponding index in supported * rates table. */ -u8 mwifiex_data_rate_to_index(struct mwifiex_adapter *adapter, u32 rate) +u8 mwifiex_data_rate_to_index(u32 rate) { u16 *ptr; @@ -265,9 +264,7 @@ mwifiex_is_rate_auto(struct mwifiex_private *priv) /* * This function converts rate bitmap into rate index. */ -int -mwifiex_get_rate_index(struct mwifiex_adapter *adapter, u16 *rate_bitmap, - int size) +int mwifiex_get_rate_index(u16 *rate_bitmap, int size) { int i; diff --git a/drivers/net/wireless/mwifiex/main.h b/drivers/net/wireless/mwifiex/main.h index 7ead15e..2d296dc 100644 --- a/drivers/net/wireless/mwifiex/main.h +++ b/drivers/net/wireless/mwifiex/main.h @@ -767,8 +767,7 @@ void *mwifiex_process_sta_txpd(struct mwifiex_private *, struct sk_buff *skb); int mwifiex_sta_init_cmd(struct mwifiex_private *, u8 first_sta); int mwifiex_scan_networks(struct mwifiex_private *priv, const struct mwifiex_user_scan_cfg *user_scan_in); -int mwifiex_cmd_802_11_scan(struct mwifiex_private *priv, - struct host_cmd_ds_command *cmd, +int mwifiex_cmd_802_11_scan(struct host_cmd_ds_command *cmd, void *data_buf); void mwifiex_queue_scan_cmd(struct mwifiex_private *priv, struct cmd_ctrl_node *cmd_node); @@ -806,9 +805,7 @@ int mwifiex_cmd_802_11_ad_hoc_join(struct mwifiex_private *priv, void *data_buf); int mwifiex_ret_802_11_ad_hoc(struct mwifiex_private *priv, struct host_cmd_ds_command *resp); -int mwifiex_cmd_802_11_bg_scan_query(struct mwifiex_private *priv, - struct host_cmd_ds_command *cmd, - void *data_buf); +int mwifiex_cmd_802_11_bg_scan_query(struct host_cmd_ds_command *cmd); struct mwifiex_chan_freq_power * mwifiex_get_cfp_by_band_and_channel_from_cfg80211( struct mwifiex_private *priv, @@ -816,20 +813,16 @@ struct mwifiex_chan_freq_power * struct mwifiex_chan_freq_power *mwifiex_get_cfp_by_band_and_freq_from_cfg80211( struct mwifiex_private *priv, u8 band, u32 freq); -u32 mwifiex_index_to_data_rate(struct mwifiex_adapter *adapter, u8 index, - u8 ht_info); +u32 mwifiex_index_to_data_rate(u8 index, u8 ht_info); u32 mwifiex_find_freq_from_band_chan(u8, u8); int mwifiex_cmd_append_vsie_tlv(struct mwifiex_private *priv, u16 vsie_mask, u8 **buffer); -u32 mwifiex_index_to_data_rate(struct mwifiex_adapter *adapter, u8 index, - u8 ht_info); u32 mwifiex_get_active_data_rates(struct mwifiex_private *priv, u8 *rates); u32 mwifiex_get_supported_rates(struct mwifiex_private *priv, u8 *rates); -u8 mwifiex_data_rate_to_index(struct mwifiex_adapter *adapter, u32 rate); +u8 mwifiex_data_rate_to_index(u32 rate); u8 mwifiex_is_rate_auto(struct mwifiex_private *priv); -int mwifiex_get_rate_index(struct mwifiex_adapter *adapter, - u16 *rateBitmap, int size); +int mwifiex_get_rate_index(u16 *rateBitmap, int size); extern u16 region_code_index[MWIFIEX_MAX_REGION_CODE]; void mwifiex_save_curr_bcn(struct mwifiex_private *priv); void mwifiex_free_curr_bcn(struct mwifiex_private *priv); diff --git a/drivers/net/wireless/mwifiex/scan.c b/drivers/net/wireless/mwifiex/scan.c index 12fe021..8474271 100644 --- a/drivers/net/wireless/mwifiex/scan.c +++ b/drivers/net/wireless/mwifiex/scan.c @@ -2364,8 +2364,7 @@ int mwifiex_scan_networks(struct mwifiex_private *priv, * - Setting command ID, and proper size * - Ensuring correct endian-ness */ -int mwifiex_cmd_802_11_scan(struct mwifiex_private *priv, - struct host_cmd_ds_command *cmd, void *data_buf) +int mwifiex_cmd_802_11_scan(struct host_cmd_ds_command *cmd, void *data_buf) { struct host_cmd_ds_802_11_scan *scan_cmd = &cmd->params.scan; struct mwifiex_scan_cmd_config *scan_cfg; @@ -2658,9 +2657,7 @@ done: * - Setting background scan flush parameter * - Ensuring correct endian-ness */ -int mwifiex_cmd_802_11_bg_scan_query(struct mwifiex_private *priv, - struct host_cmd_ds_command *cmd, - void *data_buf) +int mwifiex_cmd_802_11_bg_scan_query(struct host_cmd_ds_command *cmd) { struct host_cmd_ds_802_11_bg_scan_query *bg_query = &cmd->params.bg_scan_query; diff --git a/drivers/net/wireless/mwifiex/sdio.c b/drivers/net/wireless/mwifiex/sdio.c index fa46df5..41c087d 100644 --- a/drivers/net/wireless/mwifiex/sdio.c +++ b/drivers/net/wireless/mwifiex/sdio.c @@ -282,7 +282,7 @@ mwifiex_read_reg(struct mwifiex_adapter *adapter, u32 reg, u32 *data) */ static int mwifiex_write_data_sync(struct mwifiex_adapter *adapter, - u8 *buffer, u32 pkt_len, u32 port, u32 timeout) + u8 *buffer, u32 pkt_len, u32 port) { struct sdio_mmc_card *card = adapter->card; int ret = -1; @@ -314,9 +314,8 @@ mwifiex_write_data_sync(struct mwifiex_adapter *adapter, /* * This function reads multiple data from SDIO card memory. */ -static int mwifiex_read_data_sync(struct mwifiex_adapter *adapter, - u8 *buffer, u32 len, - u32 port, u32 timeout, u8 claim) +static int mwifiex_read_data_sync(struct mwifiex_adapter *adapter, u8 *buffer, + u32 len, u32 port, u8 claim) { struct sdio_mmc_card *card = adapter->card; int ret = -1; @@ -430,8 +429,7 @@ static int mwifiex_write_data_to_card(struct mwifiex_adapter *adapter, int ret = 0; do { - ret = mwifiex_write_data_sync(adapter, payload, pkt_len, - port, 0); + ret = mwifiex_write_data_sync(adapter, payload, pkt_len, port); if (ret) { i++; dev_err(adapter->dev, "host_to_card, write iomem" @@ -630,7 +628,7 @@ static int mwifiex_sdio_card_to_host(struct mwifiex_adapter *adapter, return -1; } - ret = mwifiex_read_data_sync(adapter, buffer, npayload, ioport, 0, 1); + ret = mwifiex_read_data_sync(adapter, buffer, npayload, ioport, 1); if (ret) { dev_err(adapter->dev, "%s: read iomem failed: %d\n", __func__, @@ -769,7 +767,7 @@ static int mwifiex_prog_fw_w_helper(struct mwifiex_adapter *adapter, ret = mwifiex_write_data_sync(adapter, fwbuf, tx_blocks * MWIFIEX_SDIO_BLOCK_SIZE, - adapter->ioport, 0); + adapter->ioport); if (ret) { dev_err(adapter->dev, "FW download, write iomem (%d)" " failed @ %d\n", i, offset); @@ -842,7 +840,7 @@ static void mwifiex_interrupt_status(struct mwifiex_adapter *adapter) unsigned long flags; if (mwifiex_read_data_sync(adapter, card->mp_regs, MAX_MP_REGS, - REG_PORT | MWIFIEX_SDIO_BYTE_MODE_MASK, 0, + REG_PORT | MWIFIEX_SDIO_BYTE_MODE_MASK, 0)) { dev_err(adapter->dev, "read mp_regs failed\n"); return; @@ -1050,7 +1048,7 @@ static int mwifiex_sdio_card_to_host_mp_aggr(struct mwifiex_adapter *adapter, card->mpa_rx.buf_len, (adapter->ioport | 0x1000 | (card->mpa_rx.ports << 4)) + - card->mpa_rx.start_port, 0, 1)) + card->mpa_rx.start_port, 1)) return -1; curr_ptr = card->mpa_rx.buf; diff --git a/drivers/net/wireless/mwifiex/sta_cmd.c b/drivers/net/wireless/mwifiex/sta_cmd.c index dec4963..33c8ba1 100644 --- a/drivers/net/wireless/mwifiex/sta_cmd.c +++ b/drivers/net/wireless/mwifiex/sta_cmd.c @@ -190,8 +190,7 @@ static int mwifiex_cmd_802_11_snmp_mib(struct mwifiex_private *priv, * - Ensuring correct endian-ness */ static int -mwifiex_cmd_802_11_get_log(struct mwifiex_private *priv, - struct host_cmd_ds_command *cmd) +mwifiex_cmd_802_11_get_log(struct host_cmd_ds_command *cmd) { cmd->command = cpu_to_le16(HostCmd_CMD_802_11_GET_LOG); cmd->size = cpu_to_le16(sizeof(struct host_cmd_ds_802_11_get_log) + @@ -272,8 +271,7 @@ static int mwifiex_cmd_tx_rate_cfg(struct mwifiex_private *priv, * (as required) * - Ensuring correct endian-ness */ -static int mwifiex_cmd_tx_power_cfg(struct mwifiex_private *priv, - struct host_cmd_ds_command *cmd, +static int mwifiex_cmd_tx_power_cfg(struct host_cmd_ds_command *cmd, u16 cmd_action, void *data_buf) { struct mwifiex_types_power_group *pg_tlv = NULL; @@ -407,8 +405,7 @@ static int mwifiex_cmd_802_11_mac_address(struct mwifiex_private *priv, * - Setting MAC multicast address * - Ensuring correct endian-ness */ -static int mwifiex_cmd_mac_multicast_adr(struct mwifiex_private *priv, - struct host_cmd_ds_command *cmd, +static int mwifiex_cmd_mac_multicast_adr(struct host_cmd_ds_command *cmd, u16 cmd_action, void *data_buf) { struct mwifiex_multicast_list *mcast_list = @@ -463,8 +460,7 @@ static int mwifiex_cmd_802_11_deauthenticate(struct mwifiex_private *priv, * - Setting command ID and proper size * - Ensuring correct endian-ness */ -static int mwifiex_cmd_802_11_ad_hoc_stop(struct mwifiex_private *priv, - struct host_cmd_ds_command *cmd) +static int mwifiex_cmd_802_11_ad_hoc_stop(struct host_cmd_ds_command *cmd) { cmd->command = cpu_to_le16(HostCmd_CMD_802_11_AD_HOC_STOP); cmd->size = cpu_to_le16(S_DS_GEN); @@ -777,8 +773,7 @@ static int mwifiex_cmd_802_11_rf_channel(struct mwifiex_private *priv, * - Setting status to enable or disable (for SET only) * - Ensuring correct endian-ness */ -static int mwifiex_cmd_ibss_coalescing_status(struct mwifiex_private *priv, - struct host_cmd_ds_command *cmd, +static int mwifiex_cmd_ibss_coalescing_status(struct host_cmd_ds_command *cmd, u16 cmd_action, void *data_buf) { struct host_cmd_ds_802_11_ibss_status *ibss_coal = @@ -946,7 +941,7 @@ int mwifiex_sta_prepare_cmd(struct mwifiex_private *priv, uint16_t cmd_no, cmd_action); break; case HostCmd_CMD_MAC_MULTICAST_ADR: - ret = mwifiex_cmd_mac_multicast_adr(priv, cmd_ptr, cmd_action, + ret = mwifiex_cmd_mac_multicast_adr(cmd_ptr, cmd_action, data_buf); break; case HostCmd_CMD_TX_RATE_CFG: @@ -954,7 +949,7 @@ int mwifiex_sta_prepare_cmd(struct mwifiex_private *priv, uint16_t cmd_no, data_buf); break; case HostCmd_CMD_TXPWR_CFG: - ret = mwifiex_cmd_tx_power_cfg(priv, cmd_ptr, cmd_action, + ret = mwifiex_cmd_tx_power_cfg(cmd_ptr, cmd_action, data_buf); break; case HostCmd_CMD_802_11_PS_MODE_ENH: @@ -966,11 +961,10 @@ int mwifiex_sta_prepare_cmd(struct mwifiex_private *priv, uint16_t cmd_no, (struct mwifiex_hs_config_param *) data_buf); break; case HostCmd_CMD_802_11_SCAN: - ret = mwifiex_cmd_802_11_scan(priv, cmd_ptr, data_buf); + ret = mwifiex_cmd_802_11_scan(cmd_ptr, data_buf); break; case HostCmd_CMD_802_11_BG_SCAN_QUERY: - ret = mwifiex_cmd_802_11_bg_scan_query(priv, cmd_ptr, - data_buf); + ret = mwifiex_cmd_802_11_bg_scan_query(cmd_ptr); break; case HostCmd_CMD_802_11_ASSOCIATE: ret = mwifiex_cmd_802_11_associate(priv, cmd_ptr, data_buf); @@ -984,14 +978,14 @@ int mwifiex_sta_prepare_cmd(struct mwifiex_private *priv, uint16_t cmd_no, data_buf); break; case HostCmd_CMD_802_11_GET_LOG: - ret = mwifiex_cmd_802_11_get_log(priv, cmd_ptr); + ret = mwifiex_cmd_802_11_get_log(cmd_ptr); break; case HostCmd_CMD_802_11_AD_HOC_JOIN: ret = mwifiex_cmd_802_11_ad_hoc_join(priv, cmd_ptr, data_buf); break; case HostCmd_CMD_802_11_AD_HOC_STOP: - ret = mwifiex_cmd_802_11_ad_hoc_stop(priv, cmd_ptr); + ret = mwifiex_cmd_802_11_ad_hoc_stop(cmd_ptr); break; case HostCmd_CMD_RSSI_INFO: ret = mwifiex_cmd_802_11_rssi_info(priv, cmd_ptr, cmd_action); @@ -1036,10 +1030,10 @@ int mwifiex_sta_prepare_cmd(struct mwifiex_private *priv, uint16_t cmd_no, cmd_ptr->size = cpu_to_le16(S_DS_GEN); break; case HostCmd_CMD_11N_ADDBA_REQ: - ret = mwifiex_cmd_11n_addba_req(priv, cmd_ptr, data_buf); + ret = mwifiex_cmd_11n_addba_req(cmd_ptr, data_buf); break; case HostCmd_CMD_11N_DELBA: - ret = mwifiex_cmd_11n_delba(priv, cmd_ptr, data_buf); + ret = mwifiex_cmd_11n_delba(cmd_ptr, data_buf); break; case HostCmd_CMD_11N_ADDBA_RSP: ret = mwifiex_cmd_11n_addba_rsp_gen(priv, cmd_ptr, data_buf); @@ -1058,11 +1052,11 @@ int mwifiex_sta_prepare_cmd(struct mwifiex_private *priv, uint16_t cmd_no, data_buf); break; case HostCmd_CMD_AMSDU_AGGR_CTRL: - ret = mwifiex_cmd_amsdu_aggr_ctrl(priv, cmd_ptr, cmd_action, + ret = mwifiex_cmd_amsdu_aggr_ctrl(cmd_ptr, cmd_action, data_buf); break; case HostCmd_CMD_11N_CFG: - ret = mwifiex_cmd_11n_cfg(priv, cmd_ptr, cmd_action, + ret = mwifiex_cmd_11n_cfg(cmd_ptr, cmd_action, data_buf); break; case HostCmd_CMD_WMM_GET_STATUS: @@ -1075,8 +1069,8 @@ int mwifiex_sta_prepare_cmd(struct mwifiex_private *priv, uint16_t cmd_no, ret = 0; break; case HostCmd_CMD_802_11_IBSS_COALESCING_STATUS: - ret = mwifiex_cmd_ibss_coalescing_status(priv, cmd_ptr, - cmd_action, data_buf); + ret = mwifiex_cmd_ibss_coalescing_status(cmd_ptr, cmd_action, + data_buf); break; case HostCmd_CMD_MAC_REG_ACCESS: case HostCmd_CMD_BBP_REG_ACCESS: diff --git a/drivers/net/wireless/mwifiex/sta_cmdresp.c b/drivers/net/wireless/mwifiex/sta_cmdresp.c index 20ce8cb..7f4f10b 100644 --- a/drivers/net/wireless/mwifiex/sta_cmdresp.c +++ b/drivers/net/wireless/mwifiex/sta_cmdresp.c @@ -280,7 +280,6 @@ static int mwifiex_ret_tx_rate_cfg(struct mwifiex_private *priv, struct host_cmd_ds_command *resp, void *data_buf) { - struct mwifiex_adapter *adapter = priv->adapter; struct mwifiex_rate_cfg *ds_rate = NULL; struct host_cmd_ds_tx_rate_cfg *rate_cfg = &resp->params.tx_rate_cfg; struct mwifiex_rate_scope *rate_scope; @@ -336,9 +335,7 @@ static int mwifiex_ret_tx_rate_cfg(struct mwifiex_private *priv, if (priv->is_data_rate_auto) { ds_rate->is_rate_auto = 1; } else { - ds_rate->rate = - mwifiex_get_rate_index(adapter, - priv-> + ds_rate->rate = mwifiex_get_rate_index(priv-> bitmap_rates, sizeof(priv-> bitmap_rates)); @@ -514,13 +511,11 @@ static int mwifiex_ret_mac_multicast_adr(struct mwifiex_private *priv, static int mwifiex_ret_802_11_tx_rate_query(struct mwifiex_private *priv, struct host_cmd_ds_command *resp) { - struct mwifiex_adapter *adapter = priv->adapter; - priv->tx_rate = resp->params.tx_rate.tx_rate; priv->tx_htinfo = resp->params.tx_rate.ht_info; if (!priv->is_data_rate_auto) priv->data_rate = - mwifiex_index_to_data_rate(adapter, priv->tx_rate, + mwifiex_index_to_data_rate(priv->tx_rate, priv->tx_htinfo); return 0; @@ -946,7 +941,7 @@ int mwifiex_process_sta_cmdresp(struct mwifiex_private *priv, mp_end_port)); break; case HostCmd_CMD_AMSDU_AGGR_CTRL: - ret = mwifiex_ret_amsdu_aggr_ctrl(priv, resp, data_buf); + ret = mwifiex_ret_amsdu_aggr_ctrl(resp, data_buf); break; case HostCmd_CMD_WMM_GET_STATUS: ret = mwifiex_ret_wmm_get_status(priv, resp); @@ -965,7 +960,7 @@ int mwifiex_process_sta_cmdresp(struct mwifiex_private *priv, case HostCmd_CMD_SET_BSS_MODE: break; case HostCmd_CMD_11N_CFG: - ret = mwifiex_ret_11n_cfg(priv, resp, data_buf); + ret = mwifiex_ret_11n_cfg(resp, data_buf); break; default: dev_err(adapter->dev, "CMD_RESP: unknown cmd response %#x\n", diff --git a/drivers/net/wireless/mwifiex/sta_ioctl.c b/drivers/net/wireless/mwifiex/sta_ioctl.c index 5f2ce94..6489f26 100644 --- a/drivers/net/wireless/mwifiex/sta_ioctl.c +++ b/drivers/net/wireless/mwifiex/sta_ioctl.c @@ -812,8 +812,7 @@ static int mwifiex_rate_ioctl_set_rate_value(struct mwifiex_private *priv, } memset(bitmap_rates, 0, sizeof(bitmap_rates)); - rate_index = - mwifiex_data_rate_to_index(adapter, rate_cfg->rate); + rate_index = mwifiex_data_rate_to_index(rate_cfg->rate); /* Only allow b/g rates to be set */ if (rate_index >= MWIFIEX_RATE_INDEX_HRDSSS0 && @@ -874,8 +873,8 @@ int mwifiex_drv_get_data_rate(struct mwifiex_private *priv, if (!ret) { if (rate && rate->is_rate_auto) - rate->rate = mwifiex_index_to_data_rate(priv->adapter, - priv->tx_rate, priv->tx_htinfo); + rate->rate = mwifiex_index_to_data_rate(priv->tx_rate, + priv->tx_htinfo); else if (rate) rate->rate = priv->data_rate; } else { diff --git a/drivers/net/wireless/mwifiex/wmm.c b/drivers/net/wireless/mwifiex/wmm.c index 6ce6f94..57b98c5 100644 --- a/drivers/net/wireless/mwifiex/wmm.c +++ b/drivers/net/wireless/mwifiex/wmm.c @@ -177,8 +177,7 @@ static void mwifiex_wmm_default_queue_priorities(struct mwifiex_private *priv) * This function map ACs to TIDs. */ static void -mwifiex_wmm_queue_priorities_tid(struct mwifiex_private *priv, - u8 queue_priority[]) +mwifiex_wmm_queue_priorities_tid(u8 queue_priority[]) { int i; @@ -247,7 +246,7 @@ mwifiex_wmm_setup_queue_priorities(struct mwifiex_private *priv, } } - mwifiex_wmm_queue_priorities_tid(priv, priv->wmm.queue_priority); + mwifiex_wmm_queue_priorities_tid(priv->wmm.queue_priority); } /* @@ -416,7 +415,7 @@ mwifiex_wmm_lists_empty(struct mwifiex_adapter *adapter) priv = adapter->priv[j]; if (priv) { for (i = 0; i < MAX_NUM_TID; i++) - if (!mwifiex_wmm_is_ra_list_empty(adapter, + if (!mwifiex_wmm_is_ra_list_empty( &priv->wmm.tid_tbl_ptr[i].ra_list)) return false; } @@ -1161,7 +1160,7 @@ mwifiex_dequeue_tx_packet(struct mwifiex_adapter *adapter) if (!ptr) return -1; - tid = mwifiex_get_tid(priv->adapter, ptr); + tid = mwifiex_get_tid(ptr); dev_dbg(adapter->dev, "data: tid=%d\n", tid); @@ -1186,14 +1185,14 @@ mwifiex_dequeue_tx_packet(struct mwifiex_adapter *adapter) /* ra_list_spinlock has been freed in mwifiex_send_single_packet() */ } else { - if (mwifiex_is_ampdu_allowed(priv, ptr, tid)) { - if (mwifiex_is_ba_stream_avail(priv)) { + if (mwifiex_is_ampdu_allowed(priv, tid)) { + if (mwifiex_is_ba_stream_avail(adapter)) { mwifiex_11n_create_tx_ba_stream_tbl(priv, ptr->ra, tid, BA_STREAM_SETUP_INPROGRESS); mwifiex_send_addba(priv, tid, ptr->ra); } else if (mwifiex_find_stream_to_delete - (priv, ptr, tid, &tid_del, ra)) { + (priv, tid, &tid_del, ra)) { mwifiex_11n_create_tx_ba_stream_tbl(priv, ptr->ra, tid, BA_STREAM_SETUP_INPROGRESS); @@ -1202,7 +1201,7 @@ mwifiex_dequeue_tx_packet(struct mwifiex_adapter *adapter) } /* Minimum number of AMSDU */ #define MIN_NUM_AMSDU 2 - if (mwifiex_is_amsdu_allowed(priv, ptr, tid) && + if (mwifiex_is_amsdu_allowed(priv, tid) && (mwifiex_num_pkts_in_txq(priv, ptr, adapter->tx_buf_size) >= MIN_NUM_AMSDU)) mwifiex_11n_aggregate_pkt(priv, ptr, INTF_HEADER_LEN, diff --git a/drivers/net/wireless/mwifiex/wmm.h b/drivers/net/wireless/mwifiex/wmm.h index 241f1b0..fcea1f6 100644 --- a/drivers/net/wireless/mwifiex/wmm.h +++ b/drivers/net/wireless/mwifiex/wmm.h @@ -35,8 +35,7 @@ enum ieee_types_wmm_ecw_bitmasks { * This function retrieves the TID of the given RA list. */ static inline int -mwifiex_get_tid(struct mwifiex_adapter *adapter, - struct mwifiex_ra_list_tbl *ptr) +mwifiex_get_tid(struct mwifiex_ra_list_tbl *ptr) { struct sk_buff *skb; @@ -52,7 +51,7 @@ mwifiex_get_tid(struct mwifiex_adapter *adapter, * This function gets the length of a list. */ static inline int -mwifiex_wmm_list_len(struct mwifiex_adapter *adapter, struct list_head *head) +mwifiex_wmm_list_len(struct list_head *head) { struct list_head *pos; int count = 0; @@ -67,8 +66,7 @@ mwifiex_wmm_list_len(struct mwifiex_adapter *adapter, struct list_head *head) * This function checks if a RA list is empty or not. */ static inline u8 -mwifiex_wmm_is_ra_list_empty(struct mwifiex_adapter *adapter, - struct list_head *ra_list_hhead) +mwifiex_wmm_is_ra_list_empty(struct list_head *ra_list_hhead) { struct mwifiex_ra_list_tbl *ra_list; int is_list_empty; -- cgit v0.10.2 From 53d7938e6a2ac6569476fc59b404e70c0537b42b Mon Sep 17 00:00:00 2001 From: Bing Zhao Date: Wed, 13 Apr 2011 17:27:09 -0700 Subject: mwifiex: rename function mwifiex_is_ba_stream_avail The old function name sounds like checking for existing BA stream. The function actually checks if we have room for creating new BA stream or not. Signed-off-by: Bing Zhao Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/mwifiex/11n.h b/drivers/net/wireless/mwifiex/11n.h index 9128d2c..02602ff 100644 --- a/drivers/net/wireless/mwifiex/11n.h +++ b/drivers/net/wireless/mwifiex/11n.h @@ -92,9 +92,10 @@ mwifiex_is_amsdu_allowed(struct mwifiex_private *priv, int tid) } /* - * This function checks whether a BA stream is available or not. + * This function checks whether a space is available for new BA stream or not. */ -static inline u8 mwifiex_is_ba_stream_avail(struct mwifiex_adapter *adapter) +static inline u8 mwifiex_space_avail_for_new_ba_stream( + struct mwifiex_adapter *adapter) { struct mwifiex_private *priv; u8 i; diff --git a/drivers/net/wireless/mwifiex/wmm.c b/drivers/net/wireless/mwifiex/wmm.c index 57b98c5..99e8431 100644 --- a/drivers/net/wireless/mwifiex/wmm.c +++ b/drivers/net/wireless/mwifiex/wmm.c @@ -1186,7 +1186,7 @@ mwifiex_dequeue_tx_packet(struct mwifiex_adapter *adapter) mwifiex_send_single_packet() */ } else { if (mwifiex_is_ampdu_allowed(priv, tid)) { - if (mwifiex_is_ba_stream_avail(adapter)) { + if (mwifiex_space_avail_for_new_ba_stream(adapter)) { mwifiex_11n_create_tx_ba_stream_tbl(priv, ptr->ra, tid, BA_STREAM_SETUP_INPROGRESS); -- cgit v0.10.2 From 9f219bd248d417c2144eedafdf2c683ba8baee84 Mon Sep 17 00:00:00 2001 From: Larry Finger Date: Wed, 13 Apr 2011 21:00:02 -0500 Subject: rtlwifi: Fix unitialized variable warnings In http://lkml.indiana.edu/hypermail/linux/kernel/1104.1/01955.html, Geerti Uytterhoeven reports the following warnings for the rtlwifi drivers. src/drivers/net/wireless/rtlwifi/rtl8192c/dm_common.c: warning: 'cck_index' may be used uninitialized in this function: => 637 src/drivers/net/wireless/rtlwifi/rtl8192c/dm_common.c: warning: 'cck_index_old' may be used uninitialized in this function: => 637 src/drivers/net/wireless/rtlwifi/rtl8192c/fw_common.c: warning: 'box_extreg' may be used uninitialized in this function: => 303 src/drivers/net/wireless/rtlwifi/rtl8192c/fw_common.c: warning: 'box_reg' may be used uninitialized in this function: => 303 src/drivers/net/wireless/rtlwifi/rtl8192ce/rf.c: warning: 'chnlgroup' may be used uninitialized in this function: => 205 src/drivers/net/wireless/rtlwifi/rtl8192ce/rf.c: warning: 'u4_regvalue' may be used uninitialized in this function: => 450 src/drivers/net/wireless/rtlwifi/rtl8192cu/hw.c: warning: 'hq_sele' may be used uninitialized in this function: => 924 Signed-off-by: Larry Finger Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/rtlwifi/rtl8192c/dm_common.c b/drivers/net/wireless/rtlwifi/rtl8192c/dm_common.c index bb02327..c228b9e 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192c/dm_common.c +++ b/drivers/net/wireless/rtlwifi/rtl8192c/dm_common.c @@ -634,7 +634,7 @@ static void rtl92c_dm_txpower_tracking_callback_thermalmeter(struct ieee80211_hw u8 thermalvalue, delta, delta_lck, delta_iqk; long ele_a, ele_d, temp_cck, val_x, value32; long val_y, ele_c; - u8 ofdm_index[2], cck_index, ofdm_index_old[2], cck_index_old; + u8 ofdm_index[2], cck_index = 0, ofdm_index_old[2], cck_index_old = 0; int i; bool is2t = IS_92C_SERIAL(rtlhal->version); u8 txpwr_level[2] = {0, 0}; diff --git a/drivers/net/wireless/rtlwifi/rtl8192c/fw_common.c b/drivers/net/wireless/rtlwifi/rtl8192c/fw_common.c index f107660..bc9d241 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192c/fw_common.c +++ b/drivers/net/wireless/rtlwifi/rtl8192c/fw_common.c @@ -293,7 +293,7 @@ static void _rtl92c_fill_h2c_command(struct ieee80211_hw *hw, struct rtl_priv *rtlpriv = rtl_priv(hw); struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); u8 boxnum; - u16 box_reg, box_extreg; + u16 box_reg = 0, box_extreg = 0; u8 u1b_tmp; bool isfw_read = false; bool bwrite_sucess = false; diff --git a/drivers/net/wireless/rtlwifi/rtl8192ce/rf.c b/drivers/net/wireless/rtlwifi/rtl8192ce/rf.c index 669b116..e301b12 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192ce/rf.c +++ b/drivers/net/wireless/rtlwifi/rtl8192ce/rf.c @@ -202,7 +202,7 @@ static void _rtl92c_get_txpower_writeval_by_regulatory(struct ieee80211_hw *hw, struct rtl_priv *rtlpriv = rtl_priv(hw); struct rtl_phy *rtlphy = &(rtlpriv->phy); struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw)); - u8 i, chnlgroup, pwr_diff_limit[4]; + u8 i, chnlgroup = 0, pwr_diff_limit[4]; u32 writeVal, customer_limit, rf; for (rf = 0; rf < 2; rf++) { @@ -447,7 +447,7 @@ static bool _rtl92c_phy_rf6052_config_parafile(struct ieee80211_hw *hw) { struct rtl_priv *rtlpriv = rtl_priv(hw); struct rtl_phy *rtlphy = &(rtlpriv->phy); - u32 u4_regvalue; + u32 u4_regvalue = 0; u8 rfpath; bool rtstatus; struct bb_reg_def *pphyreg; diff --git a/drivers/net/wireless/rtlwifi/rtl8192cu/hw.c b/drivers/net/wireless/rtlwifi/rtl8192cu/hw.c index 9444e76..e43be25 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192cu/hw.c +++ b/drivers/net/wireless/rtlwifi/rtl8192cu/hw.c @@ -921,7 +921,7 @@ static void _rtl92cu_init_chipT_queue_priority(struct ieee80211_hw *hw, u8 out_ep_num, u8 queue_sel) { - u8 hq_sele; + u8 hq_sele = 0; struct rtl_priv *rtlpriv = rtl_priv(hw); switch (out_ep_num) { -- cgit v0.10.2 From 34a0a2025c8bddc6505b56a58ef2e7333a4e4165 Mon Sep 17 00:00:00 2001 From: Senthil Balasubramanian Date: Thu, 14 Apr 2011 16:41:30 +0530 Subject: ath: Add a missing world regulatory domain 0x6C Some customers use 0x6C world regulatory domain and this patch adds the support. Cc: Luis R. Rodriguez Signed-off-by: Senthil Balasubramanian Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/regd.c b/drivers/net/wireless/ath/regd.c index f828f29..7e3b290 100644 --- a/drivers/net/wireless/ath/regd.c +++ b/drivers/net/wireless/ath/regd.c @@ -97,8 +97,8 @@ static const struct ieee80211_regdomain ath_world_regdom_66_69 = { } }; -/* Can be used by 0x67, 0x6A and 0x68 */ -static const struct ieee80211_regdomain ath_world_regdom_67_68_6A = { +/* Can be used by 0x67, 0x68, 0x6A and 0x6C */ +static const struct ieee80211_regdomain ath_world_regdom_67_68_6A_6C = { .n_reg_rules = 4, .alpha2 = "99", .reg_rules = { @@ -151,7 +151,8 @@ ieee80211_regdomain *ath_world_regdomain(struct ath_regulatory *reg) case 0x67: case 0x68: case 0x6A: - return &ath_world_regdom_67_68_6A; + case 0x6C: + return &ath_world_regdom_67_68_6A_6C; default: WARN_ON(1); return ath_default_world_regdomain(); diff --git a/drivers/net/wireless/ath/regd_common.h b/drivers/net/wireless/ath/regd_common.h index 5c2cfe6..24b5383 100644 --- a/drivers/net/wireless/ath/regd_common.h +++ b/drivers/net/wireless/ath/regd_common.h @@ -86,6 +86,7 @@ enum EnumRd { WOR9_WORLD = 0x69, WORA_WORLD = 0x6A, WORB_WORLD = 0x6B, + WORC_WORLD = 0x6C, MKK3_MKKB = 0x80, MKK3_MKKA2 = 0x81, @@ -282,6 +283,7 @@ static struct reg_dmn_pair_mapping regDomainPairs[] = { {WOR9_WORLD, NO_CTL, NO_CTL}, {WORA_WORLD, NO_CTL, NO_CTL}, {WORB_WORLD, NO_CTL, NO_CTL}, + {WORC_WORLD, NO_CTL, NO_CTL}, }; static struct country_code_to_enum_rd allCountries[] = { -- cgit v0.10.2 From 79ea6c8966b861f80e77a14b2acf581563f3c83e Mon Sep 17 00:00:00 2001 From: Rasesh Mody Date: Thu, 14 Apr 2011 08:05:18 +0000 Subject: bna: fix for clean fw re-initialization During a kernel crash, bna control path state machine and firmware do not get a notification and hence are not cleanly shutdown. The registers holding driver/IOC state information are not reset back to valid disabled/parking values. This causes subsequent driver initialization to hang during kdump kernel boot. This patch, during the initialization of first PCI function, resets corresponding register when unclean shutown is detect by reading chip registers. This will make sure that ioc/fw gets clean re-initialization. Signed-off-by: Debashis Dutt Signed-off-by: Rasesh Mody Signed-off-by: David S. Miller diff --git a/drivers/net/bna/bfa_ioc.c b/drivers/net/bna/bfa_ioc.c index e3de0b8..7581518ec 100644 --- a/drivers/net/bna/bfa_ioc.c +++ b/drivers/net/bna/bfa_ioc.c @@ -38,6 +38,8 @@ #define bfa_ioc_map_port(__ioc) ((__ioc)->ioc_hwif->ioc_map_port(__ioc)) #define bfa_ioc_notify_fail(__ioc) \ ((__ioc)->ioc_hwif->ioc_notify_fail(__ioc)) +#define bfa_ioc_sync_start(__ioc) \ + ((__ioc)->ioc_hwif->ioc_sync_start(__ioc)) #define bfa_ioc_sync_join(__ioc) \ ((__ioc)->ioc_hwif->ioc_sync_join(__ioc)) #define bfa_ioc_sync_leave(__ioc) \ @@ -602,7 +604,7 @@ bfa_iocpf_sm_fwcheck(struct bfa_iocpf *iocpf, enum iocpf_event event) switch (event) { case IOCPF_E_SEMLOCKED: if (bfa_ioc_firmware_lock(ioc)) { - if (bfa_ioc_sync_complete(ioc)) { + if (bfa_ioc_sync_start(ioc)) { iocpf->retry_count = 0; bfa_ioc_sync_join(ioc); bfa_fsm_set_state(iocpf, bfa_iocpf_sm_hwinit); @@ -1314,7 +1316,7 @@ bfa_nw_ioc_fwver_cmp(struct bfa_ioc *ioc, struct bfi_ioc_image_hdr *fwhdr) * execution context (driver/bios) must match. */ static bool -bfa_ioc_fwver_valid(struct bfa_ioc *ioc) +bfa_ioc_fwver_valid(struct bfa_ioc *ioc, u32 boot_env) { struct bfi_ioc_image_hdr fwhdr, *drv_fwhdr; @@ -1325,7 +1327,7 @@ bfa_ioc_fwver_valid(struct bfa_ioc *ioc) if (fwhdr.signature != drv_fwhdr->signature) return false; - if (fwhdr.exec != drv_fwhdr->exec) + if (swab32(fwhdr.param) != boot_env) return false; return bfa_nw_ioc_fwver_cmp(ioc, &fwhdr); @@ -1352,9 +1354,12 @@ bfa_ioc_hwinit(struct bfa_ioc *ioc, bool force) { enum bfi_ioc_state ioc_fwstate; bool fwvalid; + u32 boot_env; ioc_fwstate = readl(ioc->ioc_regs.ioc_fwstate); + boot_env = BFI_BOOT_LOADER_OS; + if (force) ioc_fwstate = BFI_IOC_UNINIT; @@ -1362,10 +1367,10 @@ bfa_ioc_hwinit(struct bfa_ioc *ioc, bool force) * check if firmware is valid */ fwvalid = (ioc_fwstate == BFI_IOC_UNINIT) ? - false : bfa_ioc_fwver_valid(ioc); + false : bfa_ioc_fwver_valid(ioc, boot_env); if (!fwvalid) { - bfa_ioc_boot(ioc, BFI_BOOT_TYPE_NORMAL, ioc->pcidev.device_id); + bfa_ioc_boot(ioc, BFI_BOOT_TYPE_NORMAL, boot_env); return; } @@ -1396,7 +1401,7 @@ bfa_ioc_hwinit(struct bfa_ioc *ioc, bool force) /** * Initialize the h/w for any other states. */ - bfa_ioc_boot(ioc, BFI_BOOT_TYPE_NORMAL, ioc->pcidev.device_id); + bfa_ioc_boot(ioc, BFI_BOOT_TYPE_NORMAL, boot_env); } void @@ -1506,7 +1511,7 @@ bfa_ioc_hb_stop(struct bfa_ioc *ioc) */ static void bfa_ioc_download_fw(struct bfa_ioc *ioc, u32 boot_type, - u32 boot_param) + u32 boot_env) { u32 *fwimg; u32 pgnum, pgoff; @@ -1558,10 +1563,10 @@ bfa_ioc_download_fw(struct bfa_ioc *ioc, u32 boot_type, /* * Set boot type and boot param at the end. */ - writel((swab32(swab32(boot_type))), ((ioc->ioc_regs.smem_page_start) + writel(boot_type, ((ioc->ioc_regs.smem_page_start) + (BFI_BOOT_TYPE_OFF))); - writel((swab32(swab32(boot_param))), ((ioc->ioc_regs.smem_page_start) - + (BFI_BOOT_PARAM_OFF))); + writel(boot_env, ((ioc->ioc_regs.smem_page_start) + + (BFI_BOOT_LOADER_OFF))); } static void @@ -1721,7 +1726,7 @@ bfa_ioc_pll_init(struct bfa_ioc *ioc) * as the entry vector. */ static void -bfa_ioc_boot(struct bfa_ioc *ioc, u32 boot_type, u32 boot_param) +bfa_ioc_boot(struct bfa_ioc *ioc, u32 boot_type, u32 boot_env) { void __iomem *rb; @@ -1734,7 +1739,7 @@ bfa_ioc_boot(struct bfa_ioc *ioc, u32 boot_type, u32 boot_param) * Initialize IOC state of all functions on a chip reset. */ rb = ioc->pcidev.pci_bar_kva; - if (boot_param == BFI_BOOT_TYPE_MEMTEST) { + if (boot_type == BFI_BOOT_TYPE_MEMTEST) { writel(BFI_IOC_MEMTEST, (rb + BFA_IOC0_STATE_REG)); writel(BFI_IOC_MEMTEST, (rb + BFA_IOC1_STATE_REG)); } else { @@ -1743,7 +1748,7 @@ bfa_ioc_boot(struct bfa_ioc *ioc, u32 boot_type, u32 boot_param) } bfa_ioc_msgflush(ioc); - bfa_ioc_download_fw(ioc, boot_type, boot_param); + bfa_ioc_download_fw(ioc, boot_type, boot_env); /** * Enable interrupts just before starting LPU diff --git a/drivers/net/bna/bfa_ioc.h b/drivers/net/bna/bfa_ioc.h index e4974bc..bd48abe 100644 --- a/drivers/net/bna/bfa_ioc.h +++ b/drivers/net/bna/bfa_ioc.h @@ -194,6 +194,7 @@ struct bfa_ioc_hwif { bool msix); void (*ioc_notify_fail) (struct bfa_ioc *ioc); void (*ioc_ownership_reset) (struct bfa_ioc *ioc); + bool (*ioc_sync_start) (struct bfa_ioc *ioc); void (*ioc_sync_join) (struct bfa_ioc *ioc); void (*ioc_sync_leave) (struct bfa_ioc *ioc); void (*ioc_sync_ack) (struct bfa_ioc *ioc); diff --git a/drivers/net/bna/bfa_ioc_ct.c b/drivers/net/bna/bfa_ioc_ct.c index 469997c..87aecdf 100644 --- a/drivers/net/bna/bfa_ioc_ct.c +++ b/drivers/net/bna/bfa_ioc_ct.c @@ -41,6 +41,7 @@ static void bfa_ioc_ct_map_port(struct bfa_ioc *ioc); static void bfa_ioc_ct_isr_mode_set(struct bfa_ioc *ioc, bool msix); static void bfa_ioc_ct_notify_fail(struct bfa_ioc *ioc); static void bfa_ioc_ct_ownership_reset(struct bfa_ioc *ioc); +static bool bfa_ioc_ct_sync_start(struct bfa_ioc *ioc); static void bfa_ioc_ct_sync_join(struct bfa_ioc *ioc); static void bfa_ioc_ct_sync_leave(struct bfa_ioc *ioc); static void bfa_ioc_ct_sync_ack(struct bfa_ioc *ioc); @@ -63,6 +64,7 @@ bfa_nw_ioc_set_ct_hwif(struct bfa_ioc *ioc) nw_hwif_ct.ioc_isr_mode_set = bfa_ioc_ct_isr_mode_set; nw_hwif_ct.ioc_notify_fail = bfa_ioc_ct_notify_fail; nw_hwif_ct.ioc_ownership_reset = bfa_ioc_ct_ownership_reset; + nw_hwif_ct.ioc_sync_start = bfa_ioc_ct_sync_start; nw_hwif_ct.ioc_sync_join = bfa_ioc_ct_sync_join; nw_hwif_ct.ioc_sync_leave = bfa_ioc_ct_sync_leave; nw_hwif_ct.ioc_sync_ack = bfa_ioc_ct_sync_ack; @@ -345,6 +347,32 @@ bfa_ioc_ct_ownership_reset(struct bfa_ioc *ioc) /** * Synchronized IOC failure processing routines */ +static bool +bfa_ioc_ct_sync_start(struct bfa_ioc *ioc) +{ + u32 r32 = readl(ioc->ioc_regs.ioc_fail_sync); + u32 sync_reqd = bfa_ioc_ct_get_sync_reqd(r32); + + /* + * Driver load time. If the sync required bit for this PCI fn + * is set, it is due to an unclean exit by the driver for this + * PCI fn in the previous incarnation. Whoever comes here first + * should clean it up, no matter which PCI fn. + */ + + if (sync_reqd & bfa_ioc_ct_sync_pos(ioc)) { + writel(0, ioc->ioc_regs.ioc_fail_sync); + writel(1, ioc->ioc_regs.ioc_usage_reg); + writel(BFI_IOC_UNINIT, ioc->ioc_regs.ioc_fwstate); + writel(BFI_IOC_UNINIT, ioc->ioc_regs.alt_ioc_fwstate); + return true; + } + + return bfa_ioc_ct_sync_complete(ioc); +} +/** + * Synchronized IOC failure processing routines + */ static void bfa_ioc_ct_sync_join(struct bfa_ioc *ioc) { diff --git a/drivers/net/bna/bfi.h b/drivers/net/bna/bfi.h index a973968..6050379 100644 --- a/drivers/net/bna/bfi.h +++ b/drivers/net/bna/bfi.h @@ -184,12 +184,14 @@ enum bfi_mclass { #define BFI_IOC_MSGLEN_MAX 32 /* 32 bytes */ #define BFI_BOOT_TYPE_OFF 8 -#define BFI_BOOT_PARAM_OFF 12 +#define BFI_BOOT_LOADER_OFF 12 -#define BFI_BOOT_TYPE_NORMAL 0 /* param is device id */ +#define BFI_BOOT_TYPE_NORMAL 0 #define BFI_BOOT_TYPE_FLASH 1 #define BFI_BOOT_TYPE_MEMTEST 2 +#define BFI_BOOT_LOADER_OS 0 + #define BFI_BOOT_MEMTEST_RES_ADDR 0x900 #define BFI_BOOT_MEMTEST_RES_SIG 0xA0A1A2A3 -- cgit v0.10.2 From 49b4947aae404c8c5758ffd1007d0d78c48b3643 Mon Sep 17 00:00:00 2001 From: Rasesh Mody Date: Thu, 14 Apr 2011 08:05:19 +0000 Subject: bna: fix memory leak during RX path cleanup The memory leak was caused by unintentional assignment of the Rx path destroy callback function pointer to NULL just after correct initialization. Signed-off-by: Debashis Dutt Signed-off-by: Rasesh Mody Signed-off-by: David S. Miller diff --git a/drivers/net/bna/bnad.c b/drivers/net/bna/bnad.c index 9f356d5..8e6ceab 100644 --- a/drivers/net/bna/bnad.c +++ b/drivers/net/bna/bnad.c @@ -1837,7 +1837,6 @@ bnad_setup_rx(struct bnad *bnad, uint rx_id) /* Initialize the Rx event handlers */ rx_cbfn.rcb_setup_cbfn = bnad_cb_rcb_setup; rx_cbfn.rcb_destroy_cbfn = bnad_cb_rcb_destroy; - rx_cbfn.rcb_destroy_cbfn = NULL; rx_cbfn.ccb_setup_cbfn = bnad_cb_ccb_setup; rx_cbfn.ccb_destroy_cbfn = bnad_cb_ccb_destroy; rx_cbfn.rx_cleanup_cbfn = bnad_cb_rx_cleanup; -- cgit v0.10.2 From 62f3a2cfb1891c070631e496eeea852e949ea8bb Mon Sep 17 00:00:00 2001 From: "Gustavo F. Padovan" Date: Thu, 14 Apr 2011 18:34:34 -0300 Subject: Bluetooth: Fix another locking unbalance l2cap_get_sock_by_scid was changed to not lock the socket anymore, but I forgot to change all the users of this function. Signed-off-by: Gustavo F. Padovan diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index d5db5a3..bc84ed1 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -632,6 +632,8 @@ static void l2cap_le_conn_ready(struct l2cap_conn *conn) if (!parent) return; + bh_lock_sock(parent); + /* Check for backlog size */ if (sk_acceptq_is_full(parent)) { BT_DBG("backlog full %d", parent->sk_ack_backlog); -- cgit v0.10.2 From 26954c7f26068b6ced108806fdd39aee5cd54e6f Mon Sep 17 00:00:00 2001 From: "Gustavo F. Padovan" Date: Thu, 14 Apr 2011 17:57:26 -0300 Subject: Bluetooth: Fix lockdep warning in L2CAP Fix a regression from the L2CAP "rewrite" patches. Purge the tx_q already happens on l2cap_chan_del() so we don't need it at l2cap_disconnect_req(). Signed-off-by: Gustavo F. Padovan diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index bc84ed1..d47de2b 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -477,8 +477,6 @@ void l2cap_send_disconn_req(struct l2cap_conn *conn, struct l2cap_chan *chan, in sk = chan->sk; - skb_queue_purge(&chan->tx_q); - if (l2cap_pi(sk)->mode == L2CAP_MODE_ERTM) { del_timer(&chan->retrans_timer); del_timer(&chan->monitor_timer); -- cgit v0.10.2 From 21d8c49e01a0c1c6eb6c750cd04110db4a539284 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Thu, 14 Apr 2011 14:49:37 -0700 Subject: ipv4: Call fib_select_default() only when actually necessary. fib_select_default() is a complete NOP, and completely pointless to invoke, when we have no more than 1 default route installed. And this is far and away the common case. So remember how many prefixlen==0 routes we have in the routing table, and elide the call when we have no more than one of those. This cuts output route creation time by 157 cycles on Niagara2+. In order to add the new int to fib_table, we have to correct the type of ->tb_data[] to unsigned long, otherwise the private area will be unaligned on 64-bit systems. Signed-off-by: David S. Miller Reviewed-by: Eric Dumazet diff --git a/include/net/ip_fib.h b/include/net/ip_fib.h index 514627f..10422ef 100644 --- a/include/net/ip_fib.h +++ b/include/net/ip_fib.h @@ -160,7 +160,8 @@ struct fib_table { struct hlist_node tb_hlist; u32 tb_id; int tb_default; - unsigned char tb_data[0]; + int tb_num_default; + unsigned long tb_data[0]; }; extern int fib_table_lookup(struct fib_table *tb, const struct flowi4 *flp, diff --git a/net/ipv4/fib_trie.c b/net/ipv4/fib_trie.c index bde80c4..9ac481a 100644 --- a/net/ipv4/fib_trie.c +++ b/net/ipv4/fib_trie.c @@ -1332,6 +1332,9 @@ int fib_table_insert(struct fib_table *tb, struct fib_config *cfg) } } + if (!plen) + tb->tb_num_default++; + list_add_tail_rcu(&new_fa->fa_list, (fa ? &fa->fa_list : fa_head)); @@ -1697,6 +1700,9 @@ int fib_table_delete(struct fib_table *tb, struct fib_config *cfg) list_del_rcu(&fa->fa_list); + if (!plen) + tb->tb_num_default--; + if (list_empty(fa_head)) { hlist_del_rcu(&li->hlist); free_leaf_info(li); @@ -1987,6 +1993,7 @@ struct fib_table *fib_trie_table(u32 id) tb->tb_id = id; tb->tb_default = -1; + tb->tb_num_default = 0; t = (struct trie *) tb->tb_data; memset(t, 0, sizeof(*t)); diff --git a/net/ipv4/route.c b/net/ipv4/route.c index 0e7430c..e9aee81 100644 --- a/net/ipv4/route.c +++ b/net/ipv4/route.c @@ -2615,7 +2615,9 @@ static struct rtable *ip_route_output_slow(struct net *net, fib_select_multipath(&res); else #endif - if (!res.prefixlen && res.type == RTN_UNICAST && !fl4.flowi4_oif) + if (!res.prefixlen && + res.table->tb_num_default > 1 && + res.type == RTN_UNICAST && !fl4.flowi4_oif) fib_select_default(&res); if (!fl4.saddr) -- cgit v0.10.2 From 8e461123f28e6b17456225e70eb834b3b30d28bb Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Thu, 14 Apr 2011 11:19:50 -0400 Subject: drm/radeon/kms: fix bad shift in atom iio table parser Noticed by Patrick Lowry. Signed-off-by: Alex Deucher Cc: stable@kernel.org Signed-off-by: Dave Airlie diff --git a/drivers/gpu/drm/radeon/atom.c b/drivers/gpu/drm/radeon/atom.c index d71d375..7bd7456 100644 --- a/drivers/gpu/drm/radeon/atom.c +++ b/drivers/gpu/drm/radeon/atom.c @@ -135,7 +135,7 @@ static uint32_t atom_iio_execute(struct atom_context *ctx, int base, case ATOM_IIO_MOVE_INDEX: temp &= ~((0xFFFFFFFF >> (32 - CU8(base + 1))) << - CU8(base + 2)); + CU8(base + 3)); temp |= ((index >> CU8(base + 2)) & (0xFFFFFFFF >> (32 - CU8(base + 1)))) << CU8(base + @@ -145,7 +145,7 @@ static uint32_t atom_iio_execute(struct atom_context *ctx, int base, case ATOM_IIO_MOVE_DATA: temp &= ~((0xFFFFFFFF >> (32 - CU8(base + 1))) << - CU8(base + 2)); + CU8(base + 3)); temp |= ((data >> CU8(base + 2)) & (0xFFFFFFFF >> (32 - CU8(base + 1)))) << CU8(base + @@ -155,7 +155,7 @@ static uint32_t atom_iio_execute(struct atom_context *ctx, int base, case ATOM_IIO_MOVE_ATTR: temp &= ~((0xFFFFFFFF >> (32 - CU8(base + 1))) << - CU8(base + 2)); + CU8(base + 3)); temp |= ((ctx-> io_attr >> CU8(base + 2)) & (0xFFFFFFFF >> (32 - -- cgit v0.10.2 From a70882aa3137fff9532b51ed5d6a92922e1c4c9c Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Thu, 14 Apr 2011 17:24:07 -0400 Subject: drm/radeon/kms: add connectors even if i2c fails Sometimes the i2c test in i2c_bit_add_bus fails if this happens we fail to register the i2c adapter and eventually fail to add the connector. If i2c fails, add the connector to the user can at least force it on. Note that some distros set i2c-algo-bit.bit_test to 1 by default which sometimes fails preventing the ddc i2c adapter from being added. The i2c adapter works even if the bit test fails, probably due to pre/post_xfer not getting called in the test_bit function. I have another patch to follow up on that. See: https://bugs.freedesktop.org/show_bug.cgi?id=36221 Signed-off-by: Alex Deucher Signed-off-by: Dave Airlie diff --git a/drivers/gpu/drm/radeon/radeon_connectors.c b/drivers/gpu/drm/radeon/radeon_connectors.c index 2ef6d51..5f45fa1 100644 --- a/drivers/gpu/drm/radeon/radeon_connectors.c +++ b/drivers/gpu/drm/radeon/radeon_connectors.c @@ -1199,7 +1199,7 @@ radeon_add_atom_connector(struct drm_device *dev, if (router->ddc_valid || router->cd_valid) { radeon_connector->router_bus = radeon_i2c_lookup(rdev, &router->i2c_info); if (!radeon_connector->router_bus) - goto failed; + DRM_ERROR("Failed to assign router i2c bus! Check dmesg for i2c errors.\n"); } switch (connector_type) { case DRM_MODE_CONNECTOR_VGA: @@ -1208,7 +1208,7 @@ radeon_add_atom_connector(struct drm_device *dev, if (i2c_bus->valid) { radeon_connector->ddc_bus = radeon_i2c_lookup(rdev, i2c_bus); if (!radeon_connector->ddc_bus) - goto failed; + DRM_ERROR("VGA: Failed to assign ddc bus! Check dmesg for i2c errors.\n"); } radeon_connector->dac_load_detect = true; drm_connector_attach_property(&radeon_connector->base, @@ -1226,7 +1226,7 @@ radeon_add_atom_connector(struct drm_device *dev, if (i2c_bus->valid) { radeon_connector->ddc_bus = radeon_i2c_lookup(rdev, i2c_bus); if (!radeon_connector->ddc_bus) - goto failed; + DRM_ERROR("DVIA: Failed to assign ddc bus! Check dmesg for i2c errors.\n"); } radeon_connector->dac_load_detect = true; drm_connector_attach_property(&radeon_connector->base, @@ -1249,7 +1249,7 @@ radeon_add_atom_connector(struct drm_device *dev, if (i2c_bus->valid) { radeon_connector->ddc_bus = radeon_i2c_lookup(rdev, i2c_bus); if (!radeon_connector->ddc_bus) - goto failed; + DRM_ERROR("DVI: Failed to assign ddc bus! Check dmesg for i2c errors.\n"); } subpixel_order = SubPixelHorizontalRGB; drm_connector_attach_property(&radeon_connector->base, @@ -1290,7 +1290,7 @@ radeon_add_atom_connector(struct drm_device *dev, if (i2c_bus->valid) { radeon_connector->ddc_bus = radeon_i2c_lookup(rdev, i2c_bus); if (!radeon_connector->ddc_bus) - goto failed; + DRM_ERROR("HDMI: Failed to assign ddc bus! Check dmesg for i2c errors.\n"); } drm_connector_attach_property(&radeon_connector->base, rdev->mode_info.coherent_mode_property, @@ -1329,10 +1329,10 @@ radeon_add_atom_connector(struct drm_device *dev, else radeon_dig_connector->dp_i2c_bus = radeon_i2c_create_dp(dev, i2c_bus, "DP-auxch"); if (!radeon_dig_connector->dp_i2c_bus) - goto failed; + DRM_ERROR("DP: Failed to assign dp ddc bus! Check dmesg for i2c errors.\n"); radeon_connector->ddc_bus = radeon_i2c_lookup(rdev, i2c_bus); if (!radeon_connector->ddc_bus) - goto failed; + DRM_ERROR("DP: Failed to assign ddc bus! Check dmesg for i2c errors.\n"); } subpixel_order = SubPixelHorizontalRGB; drm_connector_attach_property(&radeon_connector->base, @@ -1381,7 +1381,7 @@ radeon_add_atom_connector(struct drm_device *dev, if (i2c_bus->valid) { radeon_connector->ddc_bus = radeon_i2c_lookup(rdev, i2c_bus); if (!radeon_connector->ddc_bus) - goto failed; + DRM_ERROR("LVDS: Failed to assign ddc bus! Check dmesg for i2c errors.\n"); } drm_connector_attach_property(&radeon_connector->base, dev->mode_config.scaling_mode_property, @@ -1457,7 +1457,7 @@ radeon_add_legacy_connector(struct drm_device *dev, if (i2c_bus->valid) { radeon_connector->ddc_bus = radeon_i2c_lookup(rdev, i2c_bus); if (!radeon_connector->ddc_bus) - goto failed; + DRM_ERROR("VGA: Failed to assign ddc bus! Check dmesg for i2c errors.\n"); } radeon_connector->dac_load_detect = true; drm_connector_attach_property(&radeon_connector->base, @@ -1475,7 +1475,7 @@ radeon_add_legacy_connector(struct drm_device *dev, if (i2c_bus->valid) { radeon_connector->ddc_bus = radeon_i2c_lookup(rdev, i2c_bus); if (!radeon_connector->ddc_bus) - goto failed; + DRM_ERROR("DVIA: Failed to assign ddc bus! Check dmesg for i2c errors.\n"); } radeon_connector->dac_load_detect = true; drm_connector_attach_property(&radeon_connector->base, @@ -1493,7 +1493,7 @@ radeon_add_legacy_connector(struct drm_device *dev, if (i2c_bus->valid) { radeon_connector->ddc_bus = radeon_i2c_lookup(rdev, i2c_bus); if (!radeon_connector->ddc_bus) - goto failed; + DRM_ERROR("DVI: Failed to assign ddc bus! Check dmesg for i2c errors.\n"); } if (connector_type == DRM_MODE_CONNECTOR_DVII) { radeon_connector->dac_load_detect = true; @@ -1538,7 +1538,7 @@ radeon_add_legacy_connector(struct drm_device *dev, if (i2c_bus->valid) { radeon_connector->ddc_bus = radeon_i2c_lookup(rdev, i2c_bus); if (!radeon_connector->ddc_bus) - goto failed; + DRM_ERROR("LVDS: Failed to assign ddc bus! Check dmesg for i2c errors.\n"); } drm_connector_attach_property(&radeon_connector->base, dev->mode_config.scaling_mode_property, @@ -1567,9 +1567,4 @@ radeon_add_legacy_connector(struct drm_device *dev, radeon_legacy_backlight_init(radeon_encoder, connector); } } - return; - -failed: - drm_connector_cleanup(connector); - kfree(connector); } diff --git a/drivers/gpu/drm/radeon/radeon_i2c.c b/drivers/gpu/drm/radeon/radeon_i2c.c index ccbabf7..983cbac7 100644 --- a/drivers/gpu/drm/radeon/radeon_i2c.c +++ b/drivers/gpu/drm/radeon/radeon_i2c.c @@ -1096,6 +1096,9 @@ void radeon_router_select_ddc_port(struct radeon_connector *radeon_connector) if (!radeon_connector->router.ddc_valid) return; + if (!radeon_connector->router_bus) + return; + radeon_i2c_get_byte(radeon_connector->router_bus, radeon_connector->router.i2c_addr, 0x3, &val); @@ -1121,6 +1124,9 @@ void radeon_router_select_cd_port(struct radeon_connector *radeon_connector) if (!radeon_connector->router.cd_valid) return; + if (!radeon_connector->router_bus) + return; + radeon_i2c_get_byte(radeon_connector->router_bus, radeon_connector->router.i2c_addr, 0x3, &val); -- cgit v0.10.2 From 12dfc843f43efe14d0cfc7a52753d971a0cc759d Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Thu, 14 Apr 2011 19:07:34 -0400 Subject: drm/radeon/kms: adjust evergreen display watermark setup This patch fixes two issues: - A disabled crtc does not use any lb, so return 0 for lb size. This makes the display priority calculation more exact. - Only use 1/2 and whole lb partitions. Using smaller partitions can cause underflow to one of the displays if you have multiple large displays on the same lb. Fixes: https://bugs.freedesktop.org/show_bug.cgi?id=34534 Signed-off-by: Alex Deucher Signed-off-by: Dave Airlie diff --git a/drivers/gpu/drm/radeon/evergreen.c b/drivers/gpu/drm/radeon/evergreen.c index 3453910..43fd016 100644 --- a/drivers/gpu/drm/radeon/evergreen.c +++ b/drivers/gpu/drm/radeon/evergreen.c @@ -353,7 +353,7 @@ static u32 evergreen_line_buffer_adjust(struct radeon_device *rdev, struct drm_display_mode *mode, struct drm_display_mode *other_mode) { - u32 tmp = 0; + u32 tmp; /* * Line Buffer Setup * There are 3 line buffers, each one shared by 2 display controllers. @@ -363,64 +363,63 @@ static u32 evergreen_line_buffer_adjust(struct radeon_device *rdev, * first display controller * 0 - first half of lb (3840 * 2) * 1 - first 3/4 of lb (5760 * 2) - * 2 - whole lb (7680 * 2) + * 2 - whole lb (7680 * 2), other crtc must be disabled * 3 - first 1/4 of lb (1920 * 2) * second display controller * 4 - second half of lb (3840 * 2) * 5 - second 3/4 of lb (5760 * 2) - * 6 - whole lb (7680 * 2) + * 6 - whole lb (7680 * 2), other crtc must be disabled * 7 - last 1/4 of lb (1920 * 2) */ - if (mode && other_mode) { - if (mode->hdisplay > other_mode->hdisplay) { - if (mode->hdisplay > 2560) - tmp = 1; /* 3/4 */ - else - tmp = 0; /* 1/2 */ - } else if (other_mode->hdisplay > mode->hdisplay) { - if (other_mode->hdisplay > 2560) - tmp = 3; /* 1/4 */ - else - tmp = 0; /* 1/2 */ - } else + /* this can get tricky if we have two large displays on a paired group + * of crtcs. Ideally for multiple large displays we'd assign them to + * non-linked crtcs for maximum line buffer allocation. + */ + if (radeon_crtc->base.enabled && mode) { + if (other_mode) tmp = 0; /* 1/2 */ - } else if (mode) - tmp = 2; /* whole */ - else if (other_mode) - tmp = 3; /* 1/4 */ + else + tmp = 2; /* whole */ + } else + tmp = 0; /* second controller of the pair uses second half of the lb */ if (radeon_crtc->crtc_id % 2) tmp += 4; WREG32(DC_LB_MEMORY_SPLIT + radeon_crtc->crtc_offset, tmp); - switch (tmp) { - case 0: - case 4: - default: - if (ASIC_IS_DCE5(rdev)) - return 4096 * 2; - else - return 3840 * 2; - case 1: - case 5: - if (ASIC_IS_DCE5(rdev)) - return 6144 * 2; - else - return 5760 * 2; - case 2: - case 6: - if (ASIC_IS_DCE5(rdev)) - return 8192 * 2; - else - return 7680 * 2; - case 3: - case 7: - if (ASIC_IS_DCE5(rdev)) - return 2048 * 2; - else - return 1920 * 2; + if (radeon_crtc->base.enabled && mode) { + switch (tmp) { + case 0: + case 4: + default: + if (ASIC_IS_DCE5(rdev)) + return 4096 * 2; + else + return 3840 * 2; + case 1: + case 5: + if (ASIC_IS_DCE5(rdev)) + return 6144 * 2; + else + return 5760 * 2; + case 2: + case 6: + if (ASIC_IS_DCE5(rdev)) + return 8192 * 2; + else + return 7680 * 2; + case 3: + case 7: + if (ASIC_IS_DCE5(rdev)) + return 2048 * 2; + else + return 1920 * 2; + } } + + /* controller not enabled, so no lb used */ + return 0; } static u32 evergreen_get_number_of_dram_channels(struct radeon_device *rdev) -- cgit v0.10.2 From 140363500ddadad0c09cb512cc0c96a4d3efa053 Mon Sep 17 00:00:00 2001 From: Mike Christie Date: Thu, 14 Apr 2011 23:50:57 -0400 Subject: iscsi_ibft: search for broadcom specific ibft sign (v2) Broadcom iscsi offload firmware uses a non standard ibft sign of "BIFT". When we added support for boot, the anaconda team and I were using older firmware (I guess 4 years old), so boot does not work on current cards. This patch modifies the ibft search code to search for "BIFT" along with the other possible values. Broadcom has tested the patch and reported it works with their firmware. Mike has tested Chelsio and Intel cards. [v2: - Add ACPI_SIG_IBFT to ibft_signs - replace break with goto in find_ibft_in_mem innner loop.] Signed-off-by: Mike Christie Signed-off-by: Peter Jones Signed-off-by: Konrad Rzeszutek Wilk diff --git a/drivers/firmware/iscsi_ibft_find.c b/drivers/firmware/iscsi_ibft_find.c index 2192456..f032e44 100644 --- a/drivers/firmware/iscsi_ibft_find.c +++ b/drivers/firmware/iscsi_ibft_find.c @@ -42,7 +42,20 @@ struct acpi_table_ibft *ibft_addr; EXPORT_SYMBOL_GPL(ibft_addr); -#define IBFT_SIGN "iBFT" +static const struct { + char *sign; +} ibft_signs[] = { +#ifdef CONFIG_ACPI + /* + * One spec says "IBFT", the other says "iBFT". We have to check + * for both. + */ + { ACPI_SIG_IBFT }, +#endif + { "iBFT" }, + { "BIFT" }, /* Broadcom iSCSI Offload */ +}; + #define IBFT_SIGN_LEN 4 #define IBFT_START 0x80000 /* 512kB */ #define IBFT_END 0x100000 /* 1MB */ @@ -62,6 +75,7 @@ static int __init find_ibft_in_mem(void) unsigned long pos; unsigned int len = 0; void *virt; + int i; for (pos = IBFT_START; pos < IBFT_END; pos += 16) { /* The table can't be inside the VGA BIOS reserved space, @@ -69,18 +83,23 @@ static int __init find_ibft_in_mem(void) if (pos == VGA_MEM) pos += VGA_SIZE; virt = isa_bus_to_virt(pos); - if (memcmp(virt, IBFT_SIGN, IBFT_SIGN_LEN) == 0) { - unsigned long *addr = - (unsigned long *)isa_bus_to_virt(pos + 4); - len = *addr; - /* if the length of the table extends past 1M, - * the table cannot be valid. */ - if (pos + len <= (IBFT_END-1)) { - ibft_addr = (struct acpi_table_ibft *)virt; - break; + + for (i = 0; i < ARRAY_SIZE(ibft_signs); i++) { + if (memcmp(virt, ibft_signs[i].sign, IBFT_SIGN_LEN) == + 0) { + unsigned long *addr = + (unsigned long *)isa_bus_to_virt(pos + 4); + len = *addr; + /* if the length of the table extends past 1M, + * the table cannot be valid. */ + if (pos + len <= (IBFT_END-1)) { + ibft_addr = (struct acpi_table_ibft *)virt; + goto done; + } } } } +done: return len; } /* @@ -89,18 +108,12 @@ static int __init find_ibft_in_mem(void) */ unsigned long __init find_ibft_region(unsigned long *sizep) { - + int i; ibft_addr = NULL; #ifdef CONFIG_ACPI - /* - * One spec says "IBFT", the other says "iBFT". We have to check - * for both. - */ - if (!ibft_addr) - acpi_table_parse(ACPI_SIG_IBFT, acpi_find_ibft); - if (!ibft_addr) - acpi_table_parse(IBFT_SIGN, acpi_find_ibft); + for (i = 0; i < ARRAY_SIZE(ibft_signs) && !ibft_addr; i++) + acpi_table_parse(ibft_signs[i].sign, acpi_find_ibft); #endif /* CONFIG_ACPI */ /* iBFT 1.03 section 1.4.3.1 mandates that UEFI machines will -- cgit v0.10.2 From fce55922f5299a04c0a56b170a141fab34f13465 Mon Sep 17 00:00:00 2001 From: "Allan, Bruce W" Date: Wed, 13 Apr 2011 13:09:10 +0000 Subject: ethtool: allow custom interval for physical identification When physical identification of an adapter is done by toggling the mechanism on and off through software utilizing the set_phys_id operation, it is done with a fixed duration for both on and off states. Some drivers may want to set a custom duration for the on/off intervals. This patch changes the API so the return code from the driver's entry point when it is called with ETHTOOL_ID_ACTIVE can specify the frequency at which to cycle the on/off states, and updates the drivers that have already been converted to use the new set_phys_id and use the synchronous method for identifying an adapter. The physical identification frequency set in the updated drivers is based on how it was done prior to the introduction of set_phys_id. Compile tested only. Also fixes a compiler warning in sfc. v2: drivers do not return -EINVAL for ETHOOL_ID_ACTIVE v3: fold patchset into single patch and cleanup per Ben's feedback Signed-off-by: Bruce Allan Cc: Ben Hutchings Cc: Sathya Perla Cc: Subbu Seetharaman Cc: Ajit Khaparde Cc: Michael Chan Cc: Eilon Greenstein Cc: Divy Le Ray Cc: Don Fry Cc: Jon Mason Cc: Solarflare linux maintainers Cc: Steve Hodgson Cc: Stephen Hemminger Cc: Matt Carlson Acked-by: Jon Mason Acked-by: Ben Hutchings Signed-off-by: David S. Miller diff --git a/drivers/net/benet/be_ethtool.c b/drivers/net/benet/be_ethtool.c index 96f5502..80226e4 100644 --- a/drivers/net/benet/be_ethtool.c +++ b/drivers/net/benet/be_ethtool.c @@ -516,7 +516,7 @@ be_set_phys_id(struct net_device *netdev, case ETHTOOL_ID_ACTIVE: be_cmd_get_beacon_state(adapter, adapter->hba_port_num, &adapter->beacon_state); - return -EINVAL; + return 1; /* cycle on/off once per second */ case ETHTOOL_ID_ON: be_cmd_set_beacon_state(adapter, adapter->hba_port_num, 0, 0, diff --git a/drivers/net/bnx2.c b/drivers/net/bnx2.c index 0a52079..bf729ee 100644 --- a/drivers/net/bnx2.c +++ b/drivers/net/bnx2.c @@ -7473,7 +7473,7 @@ bnx2_set_phys_id(struct net_device *dev, enum ethtool_phys_id_state state) bp->leds_save = REG_RD(bp, BNX2_MISC_CFG); REG_WR(bp, BNX2_MISC_CFG, BNX2_MISC_CFG_LEDMODE_MAC); - return -EINVAL; + return 1; /* cycle on/off once per second */ case ETHTOOL_ID_ON: REG_WR(bp, BNX2_EMAC_LED, BNX2_EMAC_LED_OVERRIDE | diff --git a/drivers/net/bnx2x/bnx2x_ethtool.c b/drivers/net/bnx2x/bnx2x_ethtool.c index ad7d91e..0a5e88d 100644 --- a/drivers/net/bnx2x/bnx2x_ethtool.c +++ b/drivers/net/bnx2x/bnx2x_ethtool.c @@ -2025,7 +2025,7 @@ static int bnx2x_set_phys_id(struct net_device *dev, switch (state) { case ETHTOOL_ID_ACTIVE: - return -EINVAL; + return 1; /* cycle on/off once per second */ case ETHTOOL_ID_ON: bnx2x_set_led(&bp->link_params, &bp->link_vars, diff --git a/drivers/net/cxgb3/cxgb3_main.c b/drivers/net/cxgb3/cxgb3_main.c index 802c7a7..a087e06 100644 --- a/drivers/net/cxgb3/cxgb3_main.c +++ b/drivers/net/cxgb3/cxgb3_main.c @@ -1757,7 +1757,7 @@ static int set_phys_id(struct net_device *dev, switch (state) { case ETHTOOL_ID_ACTIVE: - return -EINVAL; + return 1; /* cycle on/off once per second */ case ETHTOOL_ID_OFF: t3_set_reg_field(adapter, A_T3DBG_GPIO_EN, F_GPIO0_OUT_VAL, 0); diff --git a/drivers/net/ewrk3.c b/drivers/net/ewrk3.c index c7ce443..17b6027 100644 --- a/drivers/net/ewrk3.c +++ b/drivers/net/ewrk3.c @@ -1618,7 +1618,7 @@ static int ewrk3_set_phys_id(struct net_device *dev, /* Prevent ISR from twiddling the LED */ lp->led_mask = 0; spin_unlock_irq(&lp->hw_lock); - return -EINVAL; + return 2; /* cycle on/off twice per second */ case ETHTOOL_ID_ON: cr = inb(EWRK3_CR); diff --git a/drivers/net/niu.c b/drivers/net/niu.c index 3fa1e9c..ea2272f 100644 --- a/drivers/net/niu.c +++ b/drivers/net/niu.c @@ -7896,7 +7896,7 @@ static int niu_set_phys_id(struct net_device *dev, switch (state) { case ETHTOOL_ID_ACTIVE: np->orig_led_state = niu_led_state_save(np); - return -EINVAL; + return 1; /* cycle on/off once per second */ case ETHTOOL_ID_ON: niu_force_led(np, 1); diff --git a/drivers/net/pcnet32.c b/drivers/net/pcnet32.c index e89afb9..0a1efba 100644 --- a/drivers/net/pcnet32.c +++ b/drivers/net/pcnet32.c @@ -1038,7 +1038,7 @@ static int pcnet32_set_phys_id(struct net_device *dev, for (i = 4; i < 8; i++) lp->save_regs[i - 4] = a->read_bcr(ioaddr, i); spin_unlock_irqrestore(&lp->lock, flags); - return -EINVAL; + return 2; /* cycle on/off twice per second */ case ETHTOOL_ID_ON: case ETHTOOL_ID_OFF: diff --git a/drivers/net/s2io.c b/drivers/net/s2io.c index 2d5cc61..2302d97 100644 --- a/drivers/net/s2io.c +++ b/drivers/net/s2io.c @@ -5541,7 +5541,7 @@ static int s2io_ethtool_set_led(struct net_device *dev, switch (state) { case ETHTOOL_ID_ACTIVE: sp->adapt_ctrl_org = readq(&bar0->gpio_control); - return -EINVAL; + return 1; /* cycle on/off once per second */ case ETHTOOL_ID_ON: s2io_set_led(sp, true); diff --git a/drivers/net/sfc/ethtool.c b/drivers/net/sfc/ethtool.c index 644f7c1..5d8468f 100644 --- a/drivers/net/sfc/ethtool.c +++ b/drivers/net/sfc/ethtool.c @@ -182,7 +182,7 @@ static int efx_ethtool_phys_id(struct net_device *net_dev, enum ethtool_phys_id_state state) { struct efx_nic *efx = netdev_priv(net_dev); - enum efx_led_mode mode; + enum efx_led_mode mode = EFX_LED_DEFAULT; switch (state) { case ETHTOOL_ID_ON: @@ -194,8 +194,8 @@ static int efx_ethtool_phys_id(struct net_device *net_dev, case ETHTOOL_ID_INACTIVE: mode = EFX_LED_DEFAULT; break; - default: - return -EINVAL; + case ETHTOOL_ID_ACTIVE: + return 1; /* cycle on/off once per second */ } efx->type->set_id_led(efx, mode); diff --git a/drivers/net/skge.c b/drivers/net/skge.c index 310dcbc..176d784 100644 --- a/drivers/net/skge.c +++ b/drivers/net/skge.c @@ -753,7 +753,7 @@ static int skge_set_phys_id(struct net_device *dev, switch (state) { case ETHTOOL_ID_ACTIVE: - return -EINVAL; + return 2; /* cycle on/off twice per second */ case ETHTOOL_ID_ON: skge_led(skge, LED_MODE_TST); diff --git a/drivers/net/sky2.c b/drivers/net/sky2.c index a4b8fe5..c8d0451 100644 --- a/drivers/net/sky2.c +++ b/drivers/net/sky2.c @@ -3813,7 +3813,7 @@ static int sky2_set_phys_id(struct net_device *dev, switch (state) { case ETHTOOL_ID_ACTIVE: - return -EINVAL; + return 1; /* cycle on/off once per second */ case ETHTOOL_ID_INACTIVE: sky2_led(sky2, MO_LED_NORM); break; diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index 10fa476..9915734 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -10384,7 +10384,7 @@ static int tg3_set_phys_id(struct net_device *dev, switch (state) { case ETHTOOL_ID_ACTIVE: - return -EINVAL; + return 1; /* cycle on/off once per second */ case ETHTOOL_ID_ON: tw32(MAC_LED_CTRL, LED_CTRL_LNKLED_OVERRIDE | diff --git a/include/linux/ethtool.h b/include/linux/ethtool.h index ad22a68..9de3127 100644 --- a/include/linux/ethtool.h +++ b/include/linux/ethtool.h @@ -798,8 +798,10 @@ bool ethtool_invalid_flags(struct net_device *dev, u32 data, u32 supported); * attached to it. The implementation may update the indicator * asynchronously or synchronously, but in either case it must return * quickly. It is initially called with the argument %ETHTOOL_ID_ACTIVE, - * and must either activate asynchronous updates or return -%EINVAL. - * If it returns -%EINVAL then it will be called again at intervals with + * and must either activate asynchronous updates and return zero, return + * a negative error or return a positive frequency for synchronous + * indication (e.g. 1 for one on/off cycle per second). If it returns + * a frequency then it will be called again at intervals with the * argument %ETHTOOL_ID_ON or %ETHTOOL_ID_OFF and should set the state of * the indicator accordingly. Finally, it is called with the argument * %ETHTOOL_ID_INACTIVE and must deactivate the indicator. Returns a diff --git a/net/core/ethtool.c b/net/core/ethtool.c index 41dee2d..13d79f5 100644 --- a/net/core/ethtool.c +++ b/net/core/ethtool.c @@ -1669,7 +1669,7 @@ static int ethtool_phys_id(struct net_device *dev, void __user *useraddr) return dev->ethtool_ops->phys_id(dev, id.data); rc = dev->ethtool_ops->set_phys_id(dev, ETHTOOL_ID_ACTIVE); - if (rc && rc != -EINVAL) + if (rc < 0) return rc; /* Drop the RTNL lock while waiting, but prevent reentry or @@ -1684,21 +1684,22 @@ static int ethtool_phys_id(struct net_device *dev, void __user *useraddr) schedule_timeout_interruptible( id.data ? (id.data * HZ) : MAX_SCHEDULE_TIMEOUT); } else { - /* Driver expects to be called periodically */ + /* Driver expects to be called at twice the frequency in rc */ + int n = rc * 2, i, interval = HZ / n; + + /* Count down seconds */ do { - rtnl_lock(); - rc = dev->ethtool_ops->set_phys_id(dev, ETHTOOL_ID_ON); - rtnl_unlock(); - if (rc) - break; - schedule_timeout_interruptible(HZ / 2); - - rtnl_lock(); - rc = dev->ethtool_ops->set_phys_id(dev, ETHTOOL_ID_OFF); - rtnl_unlock(); - if (rc) - break; - schedule_timeout_interruptible(HZ / 2); + /* Count down iterations per second */ + i = n; + do { + rtnl_lock(); + rc = dev->ethtool_ops->set_phys_id(dev, + (i & 1) ? ETHTOOL_ID_OFF : ETHTOOL_ID_ON); + rtnl_unlock(); + if (rc) + break; + schedule_timeout_interruptible(interval); + } while (!signal_pending(current) && --i != 0); } while (!signal_pending(current) && (id.data == 0 || --id.data != 0)); } -- cgit v0.10.2 From 44f4d5a27ee63ec80d498e0d0673605d5ce1427d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Denis-Courmont?= Date: Tue, 12 Apr 2011 23:27:36 +0000 Subject: Phonet: convert bound sockets hash list to RCU MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This gets rid of the last spinlock in the Phonet stack proper. Signed-off-by: Rémi Denis-Courmont Signed-off-by: David S. Miller diff --git a/net/phonet/socket.c b/net/phonet/socket.c index b1adafa..8c5bfce 100644 --- a/net/phonet/socket.c +++ b/net/phonet/socket.c @@ -52,7 +52,7 @@ static int pn_socket_release(struct socket *sock) static struct { struct hlist_head hlist[PN_HASHSIZE]; - spinlock_t lock; + struct mutex lock; } pnsocks; void __init pn_sock_init(void) @@ -61,7 +61,7 @@ void __init pn_sock_init(void) for (i = 0; i < PN_HASHSIZE; i++) INIT_HLIST_HEAD(pnsocks.hlist + i); - spin_lock_init(&pnsocks.lock); + mutex_init(&pnsocks.lock); } static struct hlist_head *pn_hash_list(u16 obj) @@ -82,9 +82,8 @@ struct sock *pn_find_sock_by_sa(struct net *net, const struct sockaddr_pn *spn) u8 res = spn->spn_resource; struct hlist_head *hlist = pn_hash_list(obj); - spin_lock_bh(&pnsocks.lock); - - sk_for_each(sknode, node, hlist) { + rcu_read_lock(); + sk_for_each_rcu(sknode, node, hlist) { struct pn_sock *pn = pn_sk(sknode); BUG_ON(!pn->sobject); /* unbound socket */ @@ -107,8 +106,7 @@ struct sock *pn_find_sock_by_sa(struct net *net, const struct sockaddr_pn *spn) sock_hold(sknode); break; } - - spin_unlock_bh(&pnsocks.lock); + rcu_read_unlock(); return rval; } @@ -119,7 +117,7 @@ void pn_deliver_sock_broadcast(struct net *net, struct sk_buff *skb) struct hlist_head *hlist = pnsocks.hlist; unsigned h; - spin_lock(&pnsocks.lock); + rcu_read_lock(); for (h = 0; h < PN_HASHSIZE; h++) { struct hlist_node *node; struct sock *sknode; @@ -140,25 +138,26 @@ void pn_deliver_sock_broadcast(struct net *net, struct sk_buff *skb) } hlist++; } - spin_unlock(&pnsocks.lock); + rcu_read_unlock(); } void pn_sock_hash(struct sock *sk) { struct hlist_head *hlist = pn_hash_list(pn_sk(sk)->sobject); - spin_lock_bh(&pnsocks.lock); - sk_add_node(sk, hlist); - spin_unlock_bh(&pnsocks.lock); + mutex_lock(&pnsocks.lock); + sk_add_node_rcu(sk, hlist); + mutex_unlock(&pnsocks.lock); } EXPORT_SYMBOL(pn_sock_hash); void pn_sock_unhash(struct sock *sk) { - spin_lock_bh(&pnsocks.lock); - sk_del_node_init(sk); - spin_unlock_bh(&pnsocks.lock); + mutex_lock(&pnsocks.lock); + sk_del_node_init_rcu(sk); + mutex_unlock(&pnsocks.lock); pn_sock_unbind_all_res(sk); + synchronize_rcu(); } EXPORT_SYMBOL(pn_sock_unhash); @@ -548,7 +547,7 @@ static struct sock *pn_sock_get_idx(struct seq_file *seq, loff_t pos) unsigned h; for (h = 0; h < PN_HASHSIZE; h++) { - sk_for_each(sknode, node, hlist) { + sk_for_each_rcu(sknode, node, hlist) { if (!net_eq(net, sock_net(sknode))) continue; if (!pos) @@ -572,9 +571,9 @@ static struct sock *pn_sock_get_next(struct seq_file *seq, struct sock *sk) } static void *pn_sock_seq_start(struct seq_file *seq, loff_t *pos) - __acquires(pnsocks.lock) + __acquires(rcu) { - spin_lock_bh(&pnsocks.lock); + rcu_read_lock(); return *pos ? pn_sock_get_idx(seq, *pos - 1) : SEQ_START_TOKEN; } @@ -591,9 +590,9 @@ static void *pn_sock_seq_next(struct seq_file *seq, void *v, loff_t *pos) } static void pn_sock_seq_stop(struct seq_file *seq, void *v) - __releases(pnsocks.lock) + __releases(rcu) { - spin_unlock_bh(&pnsocks.lock); + rcu_read_unlock(); } static int pn_sock_seq_show(struct seq_file *seq, void *v) @@ -721,13 +720,11 @@ void pn_sock_unbind_all_res(struct sock *sk) } mutex_unlock(&resource_mutex); - if (match == 0) - return; - synchronize_rcu(); while (match > 0) { - sock_put(sk); + __sock_put(sk); match--; } + /* Caller is responsible for RCU sync before final sock_put() */ } #ifdef CONFIG_PROC_FS -- cgit v0.10.2 From 6c8c2513c86c589a819c161c9abbdea2a3d56f5e Mon Sep 17 00:00:00 2001 From: stephen hemminger Date: Thu, 14 Apr 2011 05:50:12 +0000 Subject: sfc: make function tables const The phy, mac, and board information structures should be const. Since tables contain function pointer this improves security (at least theoretically). Compile tested only. Signed-off-by: Stephen Hemminger Acked-by: Ben Hutchings Signed-off-by: David S. Miller diff --git a/drivers/net/sfc/efx.c b/drivers/net/sfc/efx.c index db72a6e..c8871b2 100644 --- a/drivers/net/sfc/efx.c +++ b/drivers/net/sfc/efx.c @@ -2245,7 +2245,7 @@ static bool efx_port_dummy_op_poll(struct efx_nic *efx) return false; } -static struct efx_phy_operations efx_dummy_phy_operations = { +static const struct efx_phy_operations efx_dummy_phy_operations = { .init = efx_port_dummy_op_int, .reconfigure = efx_port_dummy_op_int, .poll = efx_port_dummy_op_poll, @@ -2261,7 +2261,7 @@ static struct efx_phy_operations efx_dummy_phy_operations = { /* This zeroes out and then fills in the invariants in a struct * efx_nic (including all sub-structures). */ -static int efx_init_struct(struct efx_nic *efx, struct efx_nic_type *type, +static int efx_init_struct(struct efx_nic *efx, const struct efx_nic_type *type, struct pci_dev *pci_dev, struct net_device *net_dev) { int i; @@ -2451,7 +2451,7 @@ static int efx_pci_probe_main(struct efx_nic *efx) static int __devinit efx_pci_probe(struct pci_dev *pci_dev, const struct pci_device_id *entry) { - struct efx_nic_type *type = (struct efx_nic_type *) entry->driver_data; + const struct efx_nic_type *type = (const struct efx_nic_type *) entry->driver_data; struct net_device *net_dev; struct efx_nic *efx; int i, rc; diff --git a/drivers/net/sfc/falcon.c b/drivers/net/sfc/falcon.c index d96b237..60176e8 100644 --- a/drivers/net/sfc/falcon.c +++ b/drivers/net/sfc/falcon.c @@ -1703,7 +1703,7 @@ static int falcon_set_wol(struct efx_nic *efx, u32 type) ************************************************************************** */ -struct efx_nic_type falcon_a1_nic_type = { +const struct efx_nic_type falcon_a1_nic_type = { .probe = falcon_probe_nic, .remove = falcon_remove_nic, .init = falcon_init_nic, @@ -1744,7 +1744,7 @@ struct efx_nic_type falcon_a1_nic_type = { .reset_world_flags = ETH_RESET_IRQ, }; -struct efx_nic_type falcon_b0_nic_type = { +const struct efx_nic_type falcon_b0_nic_type = { .probe = falcon_probe_nic, .remove = falcon_remove_nic, .init = falcon_init_nic, diff --git a/drivers/net/sfc/falcon_xmac.c b/drivers/net/sfc/falcon_xmac.c index 2c9ee5d..9516452 100644 --- a/drivers/net/sfc/falcon_xmac.c +++ b/drivers/net/sfc/falcon_xmac.c @@ -362,7 +362,7 @@ void falcon_poll_xmac(struct efx_nic *efx) falcon_ack_status_intr(efx); } -struct efx_mac_operations falcon_xmac_operations = { +const struct efx_mac_operations falcon_xmac_operations = { .reconfigure = falcon_reconfigure_xmac, .update_stats = falcon_update_stats_xmac, .check_fault = falcon_xmac_check_fault, diff --git a/drivers/net/sfc/mac.h b/drivers/net/sfc/mac.h index 6886cdf..d6a255d 100644 --- a/drivers/net/sfc/mac.h +++ b/drivers/net/sfc/mac.h @@ -13,8 +13,8 @@ #include "net_driver.h" -extern struct efx_mac_operations falcon_xmac_operations; -extern struct efx_mac_operations efx_mcdi_mac_operations; +extern const struct efx_mac_operations falcon_xmac_operations; +extern const struct efx_mac_operations efx_mcdi_mac_operations; extern int efx_mcdi_mac_stats(struct efx_nic *efx, dma_addr_t dma_addr, u32 dma_len, int enable, int clear); diff --git a/drivers/net/sfc/mcdi_mac.c b/drivers/net/sfc/mcdi_mac.c index 33f7294..50c2077 100644 --- a/drivers/net/sfc/mcdi_mac.c +++ b/drivers/net/sfc/mcdi_mac.c @@ -138,7 +138,7 @@ static bool efx_mcdi_mac_check_fault(struct efx_nic *efx) } -struct efx_mac_operations efx_mcdi_mac_operations = { +const struct efx_mac_operations efx_mcdi_mac_operations = { .reconfigure = efx_mcdi_mac_reconfigure, .update_stats = efx_port_dummy_op_void, .check_fault = efx_mcdi_mac_check_fault, diff --git a/drivers/net/sfc/mcdi_phy.c b/drivers/net/sfc/mcdi_phy.c index 7e3c65b..1fcda2d 100644 --- a/drivers/net/sfc/mcdi_phy.c +++ b/drivers/net/sfc/mcdi_phy.c @@ -739,7 +739,7 @@ static const char *efx_mcdi_phy_test_name(struct efx_nic *efx, return NULL; } -struct efx_phy_operations efx_mcdi_phy_ops = { +const struct efx_phy_operations efx_mcdi_phy_ops = { .probe = efx_mcdi_phy_probe, .init = efx_port_dummy_op_int, .reconfigure = efx_mcdi_phy_reconfigure, diff --git a/drivers/net/sfc/net_driver.h b/drivers/net/sfc/net_driver.h index 92a9067..ab4d05b 100644 --- a/drivers/net/sfc/net_driver.h +++ b/drivers/net/sfc/net_driver.h @@ -773,10 +773,10 @@ struct efx_nic { struct efx_buffer stats_buffer; - struct efx_mac_operations *mac_op; + const struct efx_mac_operations *mac_op; unsigned int phy_type; - struct efx_phy_operations *phy_op; + const struct efx_phy_operations *phy_op; void *phy_data; struct mdio_if_info mdio; unsigned int mdio_bus; @@ -897,7 +897,7 @@ struct efx_nic_type { void (*resume_wol)(struct efx_nic *efx); int (*test_registers)(struct efx_nic *efx); int (*test_nvram)(struct efx_nic *efx); - struct efx_mac_operations *default_mac_ops; + const struct efx_mac_operations *default_mac_ops; int revision; unsigned int mem_map_size; diff --git a/drivers/net/sfc/nic.h b/drivers/net/sfc/nic.h index d9de1b6..f7ec03c 100644 --- a/drivers/net/sfc/nic.h +++ b/drivers/net/sfc/nic.h @@ -150,9 +150,9 @@ struct siena_nic_data { int wol_filter_id; }; -extern struct efx_nic_type falcon_a1_nic_type; -extern struct efx_nic_type falcon_b0_nic_type; -extern struct efx_nic_type siena_a0_nic_type; +extern const struct efx_nic_type falcon_a1_nic_type; +extern const struct efx_nic_type falcon_b0_nic_type; +extern const struct efx_nic_type siena_a0_nic_type; /************************************************************************** * diff --git a/drivers/net/sfc/phy.h b/drivers/net/sfc/phy.h index b3b7947..11d148c 100644 --- a/drivers/net/sfc/phy.h +++ b/drivers/net/sfc/phy.h @@ -13,14 +13,14 @@ /**************************************************************************** * 10Xpress (SFX7101) PHY */ -extern struct efx_phy_operations falcon_sfx7101_phy_ops; +extern const struct efx_phy_operations falcon_sfx7101_phy_ops; extern void tenxpress_set_id_led(struct efx_nic *efx, enum efx_led_mode mode); /**************************************************************************** * AMCC/Quake QT202x PHYs */ -extern struct efx_phy_operations falcon_qt202x_phy_ops; +extern const struct efx_phy_operations falcon_qt202x_phy_ops; /* These PHYs provide various H/W control states for LEDs */ #define QUAKE_LED_LINK_INVAL (0) @@ -39,7 +39,7 @@ extern void falcon_qt202x_set_led(struct efx_nic *p, int led, int state); /**************************************************************************** * Transwitch CX4 retimer */ -extern struct efx_phy_operations falcon_txc_phy_ops; +extern const struct efx_phy_operations falcon_txc_phy_ops; #define TXC_GPIO_DIR_INPUT 0 #define TXC_GPIO_DIR_OUTPUT 1 @@ -50,7 +50,7 @@ extern void falcon_txc_set_gpio_val(struct efx_nic *efx, int pin, int val); /**************************************************************************** * Siena managed PHYs */ -extern struct efx_phy_operations efx_mcdi_phy_ops; +extern const struct efx_phy_operations efx_mcdi_phy_ops; extern int efx_mcdi_mdio_read(struct efx_nic *efx, unsigned int bus, unsigned int prtad, unsigned int devad, diff --git a/drivers/net/sfc/qt202x_phy.c b/drivers/net/sfc/qt202x_phy.c index 55f9092..7ad97e3 100644 --- a/drivers/net/sfc/qt202x_phy.c +++ b/drivers/net/sfc/qt202x_phy.c @@ -449,7 +449,7 @@ static void qt202x_phy_remove(struct efx_nic *efx) efx->phy_data = NULL; } -struct efx_phy_operations falcon_qt202x_phy_ops = { +const struct efx_phy_operations falcon_qt202x_phy_ops = { .probe = qt202x_phy_probe, .init = qt202x_phy_init, .reconfigure = qt202x_phy_reconfigure, diff --git a/drivers/net/sfc/siena.c b/drivers/net/sfc/siena.c index e4dd898..ceac1c9 100644 --- a/drivers/net/sfc/siena.c +++ b/drivers/net/sfc/siena.c @@ -581,7 +581,7 @@ static void siena_init_wol(struct efx_nic *efx) ************************************************************************** */ -struct efx_nic_type siena_a0_nic_type = { +const struct efx_nic_type siena_a0_nic_type = { .probe = siena_probe_nic, .remove = siena_remove_nic, .init = siena_init_nic, diff --git a/drivers/net/sfc/tenxpress.c b/drivers/net/sfc/tenxpress.c index efdceb3..204ecda 100644 --- a/drivers/net/sfc/tenxpress.c +++ b/drivers/net/sfc/tenxpress.c @@ -478,7 +478,7 @@ static void sfx7101_set_npage_adv(struct efx_nic *efx, u32 advertising) advertising & ADVERTISED_10000baseT_Full); } -struct efx_phy_operations falcon_sfx7101_phy_ops = { +const struct efx_phy_operations falcon_sfx7101_phy_ops = { .probe = tenxpress_phy_probe, .init = tenxpress_phy_init, .reconfigure = tenxpress_phy_reconfigure, diff --git a/drivers/net/sfc/txc43128_phy.c b/drivers/net/sfc/txc43128_phy.c index d9886ad..7c21b33 100644 --- a/drivers/net/sfc/txc43128_phy.c +++ b/drivers/net/sfc/txc43128_phy.c @@ -545,7 +545,7 @@ static void txc43128_get_settings(struct efx_nic *efx, struct ethtool_cmd *ecmd) mdio45_ethtool_gset(&efx->mdio, ecmd); } -struct efx_phy_operations falcon_txc_phy_ops = { +const struct efx_phy_operations falcon_txc_phy_ops = { .probe = txc43128_phy_probe, .init = txc43128_phy_init, .reconfigure = txc43128_phy_reconfigure, -- cgit v0.10.2 From ef9c7ab4a97d53d9cb4912d13e142f52a30ecd54 Mon Sep 17 00:00:00 2001 From: stephen hemminger Date: Thu, 14 Apr 2011 05:51:52 +0000 Subject: qlge: make nic_operations struct const The struct nic_operations is just function pointers and should be declared const for added security. Signed-off-by: Stephen Hemminger Signed-off-by: David S. Miller diff --git a/drivers/net/qlge/qlge.h b/drivers/net/qlge/qlge.h index 4757c59..d328507 100644 --- a/drivers/net/qlge/qlge.h +++ b/drivers/net/qlge/qlge.h @@ -2134,7 +2134,7 @@ struct ql_adapter { struct delayed_work mpi_idc_work; struct delayed_work mpi_core_to_log; struct completion ide_completion; - struct nic_operations *nic_ops; + const struct nic_operations *nic_ops; u16 device_id; struct timer_list timer; atomic_t lb_count; diff --git a/drivers/net/qlge/qlge_main.c b/drivers/net/qlge/qlge_main.c index 5bb3119..f61e717 100644 --- a/drivers/net/qlge/qlge_main.c +++ b/drivers/net/qlge/qlge_main.c @@ -4412,12 +4412,12 @@ error: rtnl_unlock(); } -static struct nic_operations qla8012_nic_ops = { +static const struct nic_operations qla8012_nic_ops = { .get_flash = ql_get_8012_flash_params, .port_initialize = ql_8012_port_initialize, }; -static struct nic_operations qla8000_nic_ops = { +static const struct nic_operations qla8000_nic_ops = { .get_flash = ql_get_8000_flash_params, .port_initialize = ql_8000_port_initialize, }; -- cgit v0.10.2 From d30ee670f25ea8f265a2804e2a0a53804cac5185 Mon Sep 17 00:00:00 2001 From: David Decotigny Date: Wed, 13 Apr 2011 15:22:29 +0000 Subject: net-bonding: Fix minor sparse complaints This gets rid of minor sparse complaints: drivers/net/bonding/bond_main.c:4361:4: warning: do-while statement is not a compound statement drivers/net/bonding/bond_main.c:243:12: warning: symbol 'bond_mode_name' was not declared. Should it be static? Signed-off-by: David Decotigny Signed-off-by: David S. Miller diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index b51e021..94a371c 100644 --- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c @@ -4357,9 +4357,9 @@ static u16 bond_select_queue(struct net_device *dev, struct sk_buff *skb) u16 txq = skb_rx_queue_recorded(skb) ? skb_get_rx_queue(skb) : 0; if (unlikely(txq >= dev->real_num_tx_queues)) { - do + do { txq -= dev->real_num_tx_queues; - while (txq >= dev->real_num_tx_queues); + } while (txq >= dev->real_num_tx_queues); } return txq; } diff --git a/drivers/net/bonding/bond_procfs.c b/drivers/net/bonding/bond_procfs.c index c32ff55..c97307d 100644 --- a/drivers/net/bonding/bond_procfs.c +++ b/drivers/net/bonding/bond_procfs.c @@ -4,8 +4,6 @@ #include "bonding.h" -extern const char *bond_mode_name(int mode); - static void *bond_info_seq_start(struct seq_file *seq, loff_t *pos) __acquires(RCU) __acquires(&bond->lock) diff --git a/drivers/net/bonding/bonding.h b/drivers/net/bonding/bonding.h index 90736cb..3ca503e 100644 --- a/drivers/net/bonding/bonding.h +++ b/drivers/net/bonding/bonding.h @@ -416,6 +416,7 @@ void bond_destroy_debugfs(void); void bond_debug_register(struct bonding *bond); void bond_debug_unregister(struct bonding *bond); void bond_debug_reregister(struct bonding *bond); +const char *bond_mode_name(int mode); struct bond_net { struct net * net; /* Associated network namespace */ -- cgit v0.10.2 From 65cce19c07756c2b2b51595c967dda93b0727027 Mon Sep 17 00:00:00 2001 From: David Decotigny Date: Wed, 13 Apr 2011 15:22:30 +0000 Subject: net-bonding: Fix minor/cosmetic type inconsistencies The __get_link_speed() function returns a u16 value which was stored in a u32 local variable. This patch uses the return value directly, thus fixing that minor type consistency. The 'duplex' field in struct slave being encoded on 8 bits, to be more consistent we use a u8 integer (instead of u16) whenever we copy it to local variables. Signed-off-by: David Decotigny Signed-off-by: David S. Miller diff --git a/drivers/net/bonding/bond_3ad.c b/drivers/net/bonding/bond_3ad.c index 494bf96..123dd60 100644 --- a/drivers/net/bonding/bond_3ad.c +++ b/drivers/net/bonding/bond_3ad.c @@ -716,11 +716,9 @@ static void __set_agg_ports_ready(struct aggregator *aggregator, int val) static u32 __get_agg_bandwidth(struct aggregator *aggregator) { u32 bandwidth = 0; - u32 basic_speed; if (aggregator->num_of_ports) { - basic_speed = __get_link_speed(aggregator->lag_ports); - switch (basic_speed) { + switch (__get_link_speed(aggregator->lag_ports)) { case AD_LINK_SPEED_BITMASK_1MBPS: bandwidth = aggregator->num_of_ports; break; diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index 94a371c..4df674b 100644 --- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c @@ -3340,7 +3340,7 @@ static int bond_slave_netdev_event(unsigned long event, slave = bond_get_slave_by_dev(bond, slave_dev); if (slave) { u16 old_speed = slave->speed; - u16 old_duplex = slave->duplex; + u8 old_duplex = slave->duplex; bond_update_speed_duplex(slave); -- cgit v0.10.2 From 5d30530efbb811f875786d788ae1c5d79547c3a4 Mon Sep 17 00:00:00 2001 From: David Decotigny Date: Wed, 13 Apr 2011 15:22:31 +0000 Subject: net-bonding: Adding support for throughputs larger than 65536 Mbps This updates the bonding driver to support v2.6.27-rc3 enhancements (b11f8d8c aka. "ethtool: Expand ethtool_cmd.speed to 32 bits") which allow to encode the Mbps link speed on 32-bits (Max 4 Pbps) instead of 16 (Max 65536 Mbps). This patch also attempts to compact struct slave by reordering its fields. Signed-off-by: David Decotigny Signed-off-by: David S. Miller diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index 4df674b..ca902ae 100644 --- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c @@ -631,7 +631,8 @@ down: static int bond_update_speed_duplex(struct slave *slave) { struct net_device *slave_dev = slave->dev; - struct ethtool_cmd etool; + struct ethtool_cmd etool = { .cmd = ETHTOOL_GSET }; + u32 slave_speed; int res; /* Fake speed and duplex */ @@ -645,7 +646,8 @@ static int bond_update_speed_duplex(struct slave *slave) if (res < 0) return -1; - switch (etool.speed) { + slave_speed = ethtool_cmd_speed(&etool); + switch (slave_speed) { case SPEED_10: case SPEED_100: case SPEED_1000: @@ -663,7 +665,7 @@ static int bond_update_speed_duplex(struct slave *slave) return -1; } - slave->speed = etool.speed; + slave->speed = slave_speed; slave->duplex = etool.duplex; return 0; @@ -2493,7 +2495,7 @@ static void bond_miimon_commit(struct bonding *bond) bond_update_speed_duplex(slave); - pr_info("%s: link status definitely up for interface %s, %d Mbps %s duplex.\n", + pr_info("%s: link status definitely up for interface %s, %u Mbps %s duplex.\n", bond->dev->name, slave->dev->name, slave->speed, slave->duplex ? "full" : "half"); @@ -3339,7 +3341,7 @@ static int bond_slave_netdev_event(unsigned long event, slave = bond_get_slave_by_dev(bond, slave_dev); if (slave) { - u16 old_speed = slave->speed; + u32 old_speed = slave->speed; u8 old_duplex = slave->duplex; bond_update_speed_duplex(slave); diff --git a/drivers/net/bonding/bonding.h b/drivers/net/bonding/bonding.h index 3ca503e..553c764 100644 --- a/drivers/net/bonding/bonding.h +++ b/drivers/net/bonding/bonding.h @@ -196,12 +196,12 @@ struct slave { u8 backup:1, /* indicates backup slave. Value corresponds with BOND_STATE_ACTIVE and BOND_STATE_BACKUP */ inactive:1; /* indicates inactive slave */ + u8 duplex; u32 original_mtu; u32 link_failure_count; - u8 perm_hwaddr[ETH_ALEN]; - u16 speed; - u8 duplex; + u32 speed; u16 queue_id; + u8 perm_hwaddr[ETH_ALEN]; struct ad_slave_info ad_info; /* HUGE - better to dynamically alloc */ struct tlb_slave_info tlb_info; #ifdef CONFIG_NET_POLL_CONTROLLER -- cgit v0.10.2 From eb8aa72d4e8756bde74d5f22bdd968ee6131069a Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Thu, 14 Apr 2011 23:23:45 -0700 Subject: rndis_host: Quirky devices are still 'point-to-point' My changes in commit 4d42d417be75d750b82798922b6e775915e11bce were written some time before the introduction of FLAG_POINTTOPOINT, so didn't include that flag in the new driver_info. Change the new driver_info to be consistent. Signed-off-by: Ben Hutchings Signed-off-by: David S. Miller diff --git a/drivers/net/usb/rndis_host.c b/drivers/net/usb/rndis_host.c index 6d6c1da..255d6a4 100644 --- a/drivers/net/usb/rndis_host.c +++ b/drivers/net/usb/rndis_host.c @@ -592,7 +592,7 @@ static const struct driver_info rndis_info = { static const struct driver_info rndis_poll_status_info = { .description = "RNDIS device (poll status before control)", - .flags = FLAG_ETHER | FLAG_FRAMING_RN | FLAG_NO_SETINT, + .flags = FLAG_ETHER | FLAG_POINTTOPOINT | FLAG_FRAMING_RN | FLAG_NO_SETINT, .data = RNDIS_DRIVER_DATA_POLL_STATUS, .bind = rndis_bind, .unbind = rndis_unbind, -- cgit v0.10.2 From c65353daf137dd41f3ede3baf62d561fca076228 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Thu, 14 Apr 2011 05:55:37 +0000 Subject: ip: ip_options_compile() resilient to NULL skb route Scot Doyle demonstrated ip_options_compile() could be called with an skb without an attached route, using a setup involving a bridge, netfilter, and forged IP packets. Let's make ip_options_compile() and ip_options_rcv_srr() a bit more robust, instead of changing bridge/netfilter code. With help from Hiroaki SHIMODA. Reported-by: Scot Doyle Tested-by: Scot Doyle Signed-off-by: Eric Dumazet Cc: Stephen Hemminger Acked-by: Hiroaki SHIMODA Signed-off-by: David S. Miller diff --git a/net/ipv4/ip_options.c b/net/ipv4/ip_options.c index 28a736f..2391b24 100644 --- a/net/ipv4/ip_options.c +++ b/net/ipv4/ip_options.c @@ -329,7 +329,7 @@ int ip_options_compile(struct net *net, pp_ptr = optptr + 2; goto error; } - if (skb) { + if (rt) { memcpy(&optptr[optptr[2]-1], &rt->rt_spec_dst, 4); opt->is_changed = 1; } @@ -371,7 +371,7 @@ int ip_options_compile(struct net *net, goto error; } opt->ts = optptr - iph; - if (skb) { + if (rt) { memcpy(&optptr[optptr[2]-1], &rt->rt_spec_dst, 4); timeptr = (__be32*)&optptr[optptr[2]+3]; } @@ -603,7 +603,7 @@ int ip_options_rcv_srr(struct sk_buff *skb) unsigned long orefdst; int err; - if (!opt->srr) + if (!opt->srr || !rt) return 0; if (skb->pkt_type != PACKET_HOST) -- cgit v0.10.2 From 0d58a2824d777923b2438107053c6e073c9c5ec1 Mon Sep 17 00:00:00 2001 From: Russell King Date: Fri, 15 Apr 2011 13:26:40 +0100 Subject: ARM: Add new syscalls Add syscalls for name_to_handle_at, open_by_handle_at, clock_adjtime and syncfs. Signed-off-by: Russell King diff --git a/arch/arm/include/asm/unistd.h b/arch/arm/include/asm/unistd.h index c891eb7..87dbe3e 100644 --- a/arch/arm/include/asm/unistd.h +++ b/arch/arm/include/asm/unistd.h @@ -396,6 +396,10 @@ #define __NR_fanotify_init (__NR_SYSCALL_BASE+367) #define __NR_fanotify_mark (__NR_SYSCALL_BASE+368) #define __NR_prlimit64 (__NR_SYSCALL_BASE+369) +#define __NR_name_to_handle_at (__NR_SYSCALL_BASE+370) +#define __NR_open_by_handle_at (__NR_SYSCALL_BASE+371) +#define __NR_clock_adjtime (__NR_SYSCALL_BASE+372) +#define __NR_syncfs (__NR_SYSCALL_BASE+373) /* * The following SWIs are ARM private. diff --git a/arch/arm/kernel/calls.S b/arch/arm/kernel/calls.S index 5c26ecc..7fbf28c 100644 --- a/arch/arm/kernel/calls.S +++ b/arch/arm/kernel/calls.S @@ -379,6 +379,10 @@ CALL(sys_fanotify_init) CALL(sys_fanotify_mark) CALL(sys_prlimit64) +/* 370 */ CALL(sys_name_to_handle_at) + CALL(sys_open_by_handle_at) + CALL(sys_clock_adjtime) + CALL(sys_syncfs) #ifndef syscalls_counted .equ syscalls_padding, ((NR_syscalls + 3) & ~3) - NR_syscalls #define syscalls_counted -- cgit v0.10.2 From db9a9cbc8142eed008e242e389938689c6feb1ba Mon Sep 17 00:00:00 2001 From: Lin Ming Date: Fri, 8 Apr 2011 14:31:26 +0800 Subject: perf hists browser: Fix seg fault when annotate null symbol In hists browser, press hotkey 'a' to annotate current symbol. Now it causes segment fault if 'a' is pressed on a null symbol. Here are 2 small bugs: - In perf_evsel__hists_browse, the condition check after 'a' is pressed is not correct, we should check ->sym instead of ->map. - In symbol__tui_annotate we must check whether sym is NULL or not before getting annotation structure. This patch fixes above 2 small bugs. Link: http://lkml.kernel.org/r/1302244286.4106.36.camel@minggr.sh.intel.com Signed-off-by: Lin Ming Signed-off-by: Arnaldo Carvalho de Melo diff --git a/tools/perf/util/ui/browsers/annotate.c b/tools/perf/util/ui/browsers/annotate.c index 8c17a87..15633d6 100644 --- a/tools/perf/util/ui/browsers/annotate.c +++ b/tools/perf/util/ui/browsers/annotate.c @@ -256,10 +256,9 @@ int symbol__tui_annotate(struct symbol *sym, struct map *map, int evidx, int refresh) { struct objdump_line *pos, *n; - struct annotation *notes = symbol__annotation(sym); + struct annotation *notes; struct annotate_browser browser = { .b = { - .entries = ¬es->src->source, .refresh = ui_browser__list_head_refresh, .seek = ui_browser__list_head_seek, .write = annotate_browser__write, @@ -281,6 +280,8 @@ int symbol__tui_annotate(struct symbol *sym, struct map *map, int evidx, ui_helpline__push("Press <- or ESC to exit"); + notes = symbol__annotation(sym); + list_for_each_entry(pos, ¬es->src->source, node) { struct objdump_line_rb_node *rbpos; size_t line_len = strlen(pos->line); @@ -291,6 +292,7 @@ int symbol__tui_annotate(struct symbol *sym, struct map *map, int evidx, rbpos->idx = browser.b.nr_entries++; } + browser.b.entries = ¬es->src->source, browser.b.width += 18; /* Percentage */ ret = annotate_browser__run(&browser, evidx, refresh); list_for_each_entry_safe(pos, n, ¬es->src->source, node) { diff --git a/tools/perf/util/ui/browsers/hists.c b/tools/perf/util/ui/browsers/hists.c index 798efdc..5d767c6 100644 --- a/tools/perf/util/ui/browsers/hists.c +++ b/tools/perf/util/ui/browsers/hists.c @@ -851,7 +851,7 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, goto out_free_stack; case 'a': if (browser->selection == NULL || - browser->selection->map == NULL || + browser->selection->sym == NULL || browser->selection->map->dso->annotate_warned) continue; goto do_annotate; -- cgit v0.10.2 From 5d2cd90922c778908bd0cd669e572a5b5eafd737 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Thu, 14 Apr 2011 11:20:14 -0300 Subject: perf evsel: Fix use of inherit perf stat doesn't mmap and its perfectly fine for it to use task-bound counters with inheritance. So set the attr.inherit on the caller and leave the syscall itself to validate it. When the mmap fails perf_evlist__mmap will just emit a warning if this is the failure reason. Reported-by: Peter Zijlstra Acked-by: Peter Zijlstra Cc: Frederic Weisbecker Cc: Ingo Molnar Cc: Mike Galbraith Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Stephane Eranian Cc: Tom Zanussi Link: http://lkml.kernel.org/r/20110414170121.GC3229@ghostprotocols.net Signed-off-by: Arnaldo Carvalho de Melo diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c index 17d1dcb..4165382 100644 --- a/tools/perf/builtin-record.c +++ b/tools/perf/builtin-record.c @@ -163,6 +163,7 @@ static void config_attr(struct perf_evsel *evsel, struct perf_evlist *evlist) struct perf_event_attr *attr = &evsel->attr; int track = !evsel->idx; /* only the first counter needs these */ + attr->inherit = !no_inherit; attr->read_format = PERF_FORMAT_TOTAL_TIME_ENABLED | PERF_FORMAT_TOTAL_TIME_RUNNING | PERF_FORMAT_ID; @@ -251,6 +252,9 @@ static void open_counters(struct perf_evlist *evlist) { struct perf_evsel *pos; + if (evlist->cpus->map[0] < 0) + no_inherit = true; + list_for_each_entry(pos, &evlist->entries, node) { struct perf_event_attr *attr = &pos->attr; /* @@ -271,8 +275,7 @@ static void open_counters(struct perf_evlist *evlist) retry_sample_id: attr->sample_id_all = sample_id_all_avail ? 1 : 0; try_again: - if (perf_evsel__open(pos, evlist->cpus, evlist->threads, group, - !no_inherit) < 0) { + if (perf_evsel__open(pos, evlist->cpus, evlist->threads, group) < 0) { int err = errno; if (err == EPERM || err == EACCES) { diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c index e2109f9..03f0e45 100644 --- a/tools/perf/builtin-stat.c +++ b/tools/perf/builtin-stat.c @@ -167,16 +167,17 @@ static int create_perf_stat_counter(struct perf_evsel *evsel) attr->read_format = PERF_FORMAT_TOTAL_TIME_ENABLED | PERF_FORMAT_TOTAL_TIME_RUNNING; + attr->inherit = !no_inherit; + if (system_wide) - return perf_evsel__open_per_cpu(evsel, evsel_list->cpus, false, false); + return perf_evsel__open_per_cpu(evsel, evsel_list->cpus, false); - attr->inherit = !no_inherit; if (target_pid == -1 && target_tid == -1) { attr->disabled = 1; attr->enable_on_exec = 1; } - return perf_evsel__open_per_thread(evsel, evsel_list->threads, false, false); + return perf_evsel__open_per_thread(evsel, evsel_list->threads, false); } /* diff --git a/tools/perf/builtin-test.c b/tools/perf/builtin-test.c index 1b2106c..11e3c84 100644 --- a/tools/perf/builtin-test.c +++ b/tools/perf/builtin-test.c @@ -290,7 +290,7 @@ static int test__open_syscall_event(void) goto out_thread_map_delete; } - if (perf_evsel__open_per_thread(evsel, threads, false, false) < 0) { + if (perf_evsel__open_per_thread(evsel, threads, false) < 0) { pr_debug("failed to open counter: %s, " "tweak /proc/sys/kernel/perf_event_paranoid?\n", strerror(errno)); @@ -303,7 +303,7 @@ static int test__open_syscall_event(void) } if (perf_evsel__read_on_cpu(evsel, 0, 0) < 0) { - pr_debug("perf_evsel__open_read_on_cpu\n"); + pr_debug("perf_evsel__read_on_cpu\n"); goto out_close_fd; } @@ -365,7 +365,7 @@ static int test__open_syscall_event_on_all_cpus(void) goto out_thread_map_delete; } - if (perf_evsel__open(evsel, cpus, threads, false, false) < 0) { + if (perf_evsel__open(evsel, cpus, threads, false) < 0) { pr_debug("failed to open counter: %s, " "tweak /proc/sys/kernel/perf_event_paranoid?\n", strerror(errno)); @@ -418,7 +418,7 @@ static int test__open_syscall_event_on_all_cpus(void) continue; if (perf_evsel__read_on_cpu(evsel, cpu, 0) < 0) { - pr_debug("perf_evsel__open_read_on_cpu\n"); + pr_debug("perf_evsel__read_on_cpu\n"); err = -1; break; } @@ -529,7 +529,7 @@ static int test__basic_mmap(void) perf_evlist__add(evlist, evsels[i]); - if (perf_evsel__open(evsels[i], cpus, threads, false, false) < 0) { + if (perf_evsel__open(evsels[i], cpus, threads, false) < 0) { pr_debug("failed to open counter: %s, " "tweak /proc/sys/kernel/perf_event_paranoid?\n", strerror(errno)); diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c index fc1273e..7e3d6e3 100644 --- a/tools/perf/builtin-top.c +++ b/tools/perf/builtin-top.c @@ -845,9 +845,10 @@ static void start_counters(struct perf_evlist *evlist) } attr->mmap = 1; + attr->inherit = inherit; try_again: if (perf_evsel__open(counter, top.evlist->cpus, - top.evlist->threads, group, inherit) < 0) { + top.evlist->threads, group) < 0) { int err = errno; if (err == EPERM || err == EACCES) { diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c index d852cef..45da8d1 100644 --- a/tools/perf/util/evlist.c +++ b/tools/perf/util/evlist.c @@ -12,6 +12,7 @@ #include "evlist.h" #include "evsel.h" #include "util.h" +#include "debug.h" #include @@ -250,15 +251,19 @@ int perf_evlist__alloc_mmap(struct perf_evlist *evlist) return evlist->mmap != NULL ? 0 : -ENOMEM; } -static int __perf_evlist__mmap(struct perf_evlist *evlist, int cpu, int prot, - int mask, int fd) +static int __perf_evlist__mmap(struct perf_evlist *evlist, struct perf_evsel *evsel, + int cpu, int prot, int mask, int fd) { evlist->mmap[cpu].prev = 0; evlist->mmap[cpu].mask = mask; evlist->mmap[cpu].base = mmap(NULL, evlist->mmap_len, prot, MAP_SHARED, fd, 0); - if (evlist->mmap[cpu].base == MAP_FAILED) + if (evlist->mmap[cpu].base == MAP_FAILED) { + if (evlist->cpus->map[cpu] == -1 && evsel->attr.inherit) + ui__warning("Inherit is not allowed on per-task " + "events using mmap.\n"); return -1; + } perf_evlist__add_pollfd(evlist, fd); return 0; @@ -312,7 +317,8 @@ int perf_evlist__mmap(struct perf_evlist *evlist, int pages, bool overwrite) if (ioctl(fd, PERF_EVENT_IOC_SET_OUTPUT, FD(first_evsel, cpu, 0)) != 0) goto out_unmap; - } else if (__perf_evlist__mmap(evlist, cpu, prot, mask, fd) < 0) + } else if (__perf_evlist__mmap(evlist, evsel, cpu, + prot, mask, fd) < 0) goto out_unmap; if ((evsel->attr.read_format & PERF_FORMAT_ID) && diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c index 662596a..d6fd59b 100644 --- a/tools/perf/util/evsel.c +++ b/tools/perf/util/evsel.c @@ -175,7 +175,7 @@ int __perf_evsel__read(struct perf_evsel *evsel, } static int __perf_evsel__open(struct perf_evsel *evsel, struct cpu_map *cpus, - struct thread_map *threads, bool group, bool inherit) + struct thread_map *threads, bool group) { int cpu, thread; unsigned long flags = 0; @@ -192,19 +192,6 @@ static int __perf_evsel__open(struct perf_evsel *evsel, struct cpu_map *cpus, for (cpu = 0; cpu < cpus->nr; cpu++) { int group_fd = -1; - /* - * Don't allow mmap() of inherited per-task counters. This - * would create a performance issue due to all children writing - * to the same buffer. - * - * FIXME: - * Proper fix is not to pass 'inherit' to perf_evsel__open*, - * but a 'flags' parameter, with 'group' folded there as well, - * then introduce a PERF_O_{MMAP,GROUP,INHERIT} enum, and if - * O_MMAP is set, emit a warning if cpu < 0 and O_INHERIT is - * set. Lets go for the minimal fix first tho. - */ - evsel->attr.inherit = (cpus->map[cpu] >= 0) && inherit; for (thread = 0; thread < threads->nr; thread++) { @@ -253,7 +240,7 @@ static struct { }; int perf_evsel__open(struct perf_evsel *evsel, struct cpu_map *cpus, - struct thread_map *threads, bool group, bool inherit) + struct thread_map *threads, bool group) { if (cpus == NULL) { /* Work around old compiler warnings about strict aliasing */ @@ -263,19 +250,19 @@ int perf_evsel__open(struct perf_evsel *evsel, struct cpu_map *cpus, if (threads == NULL) threads = &empty_thread_map.map; - return __perf_evsel__open(evsel, cpus, threads, group, inherit); + return __perf_evsel__open(evsel, cpus, threads, group); } int perf_evsel__open_per_cpu(struct perf_evsel *evsel, - struct cpu_map *cpus, bool group, bool inherit) + struct cpu_map *cpus, bool group) { - return __perf_evsel__open(evsel, cpus, &empty_thread_map.map, group, inherit); + return __perf_evsel__open(evsel, cpus, &empty_thread_map.map, group); } int perf_evsel__open_per_thread(struct perf_evsel *evsel, - struct thread_map *threads, bool group, bool inherit) + struct thread_map *threads, bool group) { - return __perf_evsel__open(evsel, &empty_cpu_map.map, threads, group, inherit); + return __perf_evsel__open(evsel, &empty_cpu_map.map, threads, group); } static int perf_event__parse_id_sample(const union perf_event *event, u64 type, diff --git a/tools/perf/util/evsel.h b/tools/perf/util/evsel.h index 6710ab5..f79bb2c 100644 --- a/tools/perf/util/evsel.h +++ b/tools/perf/util/evsel.h @@ -81,11 +81,11 @@ void perf_evsel__free_id(struct perf_evsel *evsel); void perf_evsel__close_fd(struct perf_evsel *evsel, int ncpus, int nthreads); int perf_evsel__open_per_cpu(struct perf_evsel *evsel, - struct cpu_map *cpus, bool group, bool inherit); + struct cpu_map *cpus, bool group); int perf_evsel__open_per_thread(struct perf_evsel *evsel, - struct thread_map *threads, bool group, bool inherit); + struct thread_map *threads, bool group); int perf_evsel__open(struct perf_evsel *evsel, struct cpu_map *cpus, - struct thread_map *threads, bool group, bool inherit); + struct thread_map *threads, bool group); #define perf_evsel__match(evsel, t, c) \ (evsel->attr.type == PERF_TYPE_##t && \ diff --git a/tools/perf/util/python.c b/tools/perf/util/python.c index a9f2d7e..f5e3845 100644 --- a/tools/perf/util/python.c +++ b/tools/perf/util/python.c @@ -498,11 +498,11 @@ static PyObject *pyrf_evsel__open(struct pyrf_evsel *pevsel, struct cpu_map *cpus = NULL; struct thread_map *threads = NULL; PyObject *pcpus = NULL, *pthreads = NULL; - int group = 0, overwrite = 0; - static char *kwlist[] = {"cpus", "threads", "group", "overwrite", NULL, NULL}; + int group = 0, inherit = 0; + static char *kwlist[] = {"cpus", "threads", "group", "inherit", NULL, NULL}; if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|OOii", kwlist, - &pcpus, &pthreads, &group, &overwrite)) + &pcpus, &pthreads, &group, &inherit)) return NULL; if (pthreads != NULL) @@ -511,7 +511,8 @@ static PyObject *pyrf_evsel__open(struct pyrf_evsel *pevsel, if (pcpus != NULL) cpus = ((struct pyrf_cpu_map *)pcpus)->cpus; - if (perf_evsel__open(evsel, cpus, threads, group, overwrite) < 0) { + evsel->attr.inherit = inherit; + if (perf_evsel__open(evsel, cpus, threads, group) < 0) { PyErr_SetFromErrno(PyExc_OSError); return NULL; } -- cgit v0.10.2 From b54cd0d5053633373cd3c374aa203024cbf125a0 Mon Sep 17 00:00:00 2001 From: Meelis Roos Date: Mon, 21 Mar 2011 22:47:15 +0200 Subject: [PARISC] fix pacache .size with new binutils Fix style of flush_user_dcache_range_asm procedure declaration in arch/parisc/kernel/pacache.s to be consistent with other assembly procedures. Signed-off-by: Meelis Roos Signed-off-by: James Bottomley diff --git a/arch/parisc/kernel/pacache.S b/arch/parisc/kernel/pacache.S index a858236..93ff3d9 100644 --- a/arch/parisc/kernel/pacache.S +++ b/arch/parisc/kernel/pacache.S @@ -817,10 +817,7 @@ ENTRY(purge_kernel_dcache_page) .procend ENDPROC(purge_kernel_dcache_page) - - .export flush_user_dcache_range_asm - -flush_user_dcache_range_asm: +ENTRY(flush_user_dcache_range_asm) .proc .callinfo NO_CALLS .entry @@ -839,6 +836,7 @@ flush_user_dcache_range_asm: .exit .procend +ENDPROC(flush_user_dcache_range_asm) ENTRY(flush_kernel_dcache_range_asm) .proc -- cgit v0.10.2 From d7dd2ff11b7fcd425aca5a875983c862d19a67ae Mon Sep 17 00:00:00 2001 From: James Bottomley Date: Thu, 14 Apr 2011 18:25:21 -0500 Subject: [PARISC] only make executable areas executable Currently parisc has the whole kernel marked as RWX, meaning any kernel page at all is eligible to be executed. This can cause a theoretical problem on systems with combined I/D TLB because the act of referencing a page causes a TLB insertion with an executable bit. This TLB entry may be used by the CPU as the basis for speculating the page into the I-Cache. If this speculated page is subsequently used for a user process, there is the possibility we will get a stale I-cache line picked up as the binary executes. As a point of good practise, only mark actual kernel text pages as executable. The same has to be done for init_text pages, but they're converted to data pages (and the I-Cache flushed) when the init memory is released. Signed-off-by: James Bottomley diff --git a/arch/parisc/include/asm/pgtable.h b/arch/parisc/include/asm/pgtable.h index 5d7b8ce..22dadeb 100644 --- a/arch/parisc/include/asm/pgtable.h +++ b/arch/parisc/include/asm/pgtable.h @@ -177,7 +177,10 @@ struct vm_area_struct; #define _PAGE_TABLE (_PAGE_PRESENT | _PAGE_READ | _PAGE_WRITE | _PAGE_DIRTY | _PAGE_ACCESSED) #define _PAGE_CHG_MASK (PAGE_MASK | _PAGE_ACCESSED | _PAGE_DIRTY) -#define _PAGE_KERNEL (_PAGE_PRESENT | _PAGE_EXEC | _PAGE_READ | _PAGE_WRITE | _PAGE_DIRTY | _PAGE_ACCESSED) +#define _PAGE_KERNEL_RO (_PAGE_PRESENT | _PAGE_READ | _PAGE_DIRTY | _PAGE_ACCESSED) +#define _PAGE_KERNEL_EXEC (_PAGE_KERNEL_RO | _PAGE_EXEC) +#define _PAGE_KERNEL_RWX (_PAGE_KERNEL_EXEC | _PAGE_WRITE) +#define _PAGE_KERNEL (_PAGE_KERNEL_RO | _PAGE_WRITE) /* The pgd/pmd contains a ptr (in phys addr space); since all pgds/pmds * are page-aligned, we don't care about the PAGE_OFFSET bits, except @@ -208,7 +211,9 @@ struct vm_area_struct; #define PAGE_COPY PAGE_EXECREAD #define PAGE_RWX __pgprot(_PAGE_PRESENT | _PAGE_USER | _PAGE_READ | _PAGE_WRITE | _PAGE_EXEC |_PAGE_ACCESSED) #define PAGE_KERNEL __pgprot(_PAGE_KERNEL) -#define PAGE_KERNEL_RO __pgprot(_PAGE_KERNEL & ~_PAGE_WRITE) +#define PAGE_KERNEL_EXEC __pgprot(_PAGE_KERNEL_EXEC) +#define PAGE_KERNEL_RWX __pgprot(_PAGE_KERNEL_RWX) +#define PAGE_KERNEL_RO __pgprot(_PAGE_KERNEL_RO) #define PAGE_KERNEL_UNC __pgprot(_PAGE_KERNEL | _PAGE_NO_CACHE) #define PAGE_GATEWAY __pgprot(_PAGE_PRESENT | _PAGE_USER | _PAGE_ACCESSED | _PAGE_GATEWAY| _PAGE_READ) diff --git a/arch/parisc/kernel/entry.S b/arch/parisc/kernel/entry.S index ead8d2a..6f05944 100644 --- a/arch/parisc/kernel/entry.S +++ b/arch/parisc/kernel/entry.S @@ -692,6 +692,9 @@ ENTRY(fault_vector_11) END(fault_vector_11) #endif + /* Fault vector is separately protected and *must* be on its own page */ + .align PAGE_SIZE +ENTRY(end_fault_vector) .import handle_interruption,code .import do_cpu_irq_mask,code diff --git a/arch/parisc/kernel/head.S b/arch/parisc/kernel/head.S index 145c5e4..37aabd7 100644 --- a/arch/parisc/kernel/head.S +++ b/arch/parisc/kernel/head.S @@ -106,8 +106,9 @@ $bss_loop: #endif - /* Now initialize the PTEs themselves */ - ldo 0+_PAGE_KERNEL(%r0),%r3 /* Hardwired 0 phys addr start */ + /* Now initialize the PTEs themselves. We use RWX for + * everything ... it will get remapped correctly later */ + ldo 0+_PAGE_KERNEL_RWX(%r0),%r3 /* Hardwired 0 phys addr start */ ldi (1<<(KERNEL_INITIAL_ORDER-PAGE_SHIFT)),%r11 /* PFN count */ load32 PA(pg0),%r1 diff --git a/arch/parisc/kernel/module.c b/arch/parisc/kernel/module.c index 6e81bb5..cedbbb8 100644 --- a/arch/parisc/kernel/module.c +++ b/arch/parisc/kernel/module.c @@ -61,8 +61,10 @@ #include #include #include +#include #include +#include #include #if 0 @@ -214,7 +216,13 @@ void *module_alloc(unsigned long size) { if (size == 0) return NULL; - return vmalloc(size); + /* using RWX means less protection for modules, but it's + * easier than trying to map the text, data, init_text and + * init_data correctly */ + return __vmalloc_node_range(size, 1, VMALLOC_START, VMALLOC_END, + GFP_KERNEL | __GFP_HIGHMEM, + PAGE_KERNEL_RWX, -1, + __builtin_return_address(0)); } #ifndef CONFIG_64BIT diff --git a/arch/parisc/kernel/vmlinux.lds.S b/arch/parisc/kernel/vmlinux.lds.S index 8f1e4ef..bf6a43a 100644 --- a/arch/parisc/kernel/vmlinux.lds.S +++ b/arch/parisc/kernel/vmlinux.lds.S @@ -134,6 +134,7 @@ SECTIONS . = ALIGN(16384); __init_begin = .; INIT_TEXT_SECTION(16384) + . = ALIGN(PAGE_SIZE); INIT_DATA_SECTION(16) /* we have to discard exit text and such at runtime, not link time */ .exit.text : diff --git a/arch/parisc/mm/init.c b/arch/parisc/mm/init.c index b7ed8d7..7e6b465 100644 --- a/arch/parisc/mm/init.c +++ b/arch/parisc/mm/init.c @@ -369,24 +369,158 @@ static void __init setup_bootmem(void) request_resource(&sysram_resources[0], &pdcdata_resource); } +static void __init map_pages(unsigned long start_vaddr, + unsigned long start_paddr, unsigned long size, + pgprot_t pgprot, int force) +{ + pgd_t *pg_dir; + pmd_t *pmd; + pte_t *pg_table; + unsigned long end_paddr; + unsigned long start_pmd; + unsigned long start_pte; + unsigned long tmp1; + unsigned long tmp2; + unsigned long address; + unsigned long vaddr; + unsigned long ro_start; + unsigned long ro_end; + unsigned long fv_addr; + unsigned long gw_addr; + extern const unsigned long fault_vector_20; + extern void * const linux_gateway_page; + + ro_start = __pa((unsigned long)_text); + ro_end = __pa((unsigned long)&data_start); + fv_addr = __pa((unsigned long)&fault_vector_20) & PAGE_MASK; + gw_addr = __pa((unsigned long)&linux_gateway_page) & PAGE_MASK; + + end_paddr = start_paddr + size; + + pg_dir = pgd_offset_k(start_vaddr); + +#if PTRS_PER_PMD == 1 + start_pmd = 0; +#else + start_pmd = ((start_vaddr >> PMD_SHIFT) & (PTRS_PER_PMD - 1)); +#endif + start_pte = ((start_vaddr >> PAGE_SHIFT) & (PTRS_PER_PTE - 1)); + + address = start_paddr; + vaddr = start_vaddr; + while (address < end_paddr) { +#if PTRS_PER_PMD == 1 + pmd = (pmd_t *)__pa(pg_dir); +#else + pmd = (pmd_t *)pgd_address(*pg_dir); + + /* + * pmd is physical at this point + */ + + if (!pmd) { + pmd = (pmd_t *) alloc_bootmem_low_pages_node(NODE_DATA(0), PAGE_SIZE << PMD_ORDER); + pmd = (pmd_t *) __pa(pmd); + } + + pgd_populate(NULL, pg_dir, __va(pmd)); +#endif + pg_dir++; + + /* now change pmd to kernel virtual addresses */ + + pmd = (pmd_t *)__va(pmd) + start_pmd; + for (tmp1 = start_pmd; tmp1 < PTRS_PER_PMD; tmp1++, pmd++) { + + /* + * pg_table is physical at this point + */ + + pg_table = (pte_t *)pmd_address(*pmd); + if (!pg_table) { + pg_table = (pte_t *) + alloc_bootmem_low_pages_node(NODE_DATA(0), PAGE_SIZE); + pg_table = (pte_t *) __pa(pg_table); + } + + pmd_populate_kernel(NULL, pmd, __va(pg_table)); + + /* now change pg_table to kernel virtual addresses */ + + pg_table = (pte_t *) __va(pg_table) + start_pte; + for (tmp2 = start_pte; tmp2 < PTRS_PER_PTE; tmp2++, pg_table++) { + pte_t pte; + + /* + * Map the fault vector writable so we can + * write the HPMC checksum. + */ + if (force) + pte = __mk_pte(address, pgprot); + else if (core_kernel_text(vaddr) && + address != fv_addr) + pte = __mk_pte(address, PAGE_KERNEL_EXEC); + else +#if defined(CONFIG_PARISC_PAGE_SIZE_4KB) + if (address >= ro_start && address < ro_end + && address != fv_addr + && address != gw_addr) + pte = __mk_pte(address, PAGE_KERNEL_RO); + else +#endif + pte = __mk_pte(address, pgprot); + + if (address >= end_paddr) { + if (force) + break; + else + pte_val(pte) = 0; + } + + set_pte(pg_table, pte); + + address += PAGE_SIZE; + vaddr += PAGE_SIZE; + } + start_pte = 0; + + if (address >= end_paddr) + break; + } + start_pmd = 0; + } +} + void free_initmem(void) { unsigned long addr; unsigned long init_begin = (unsigned long)__init_begin; unsigned long init_end = (unsigned long)__init_end; -#ifdef CONFIG_DEBUG_KERNEL + /* The init text pages are marked R-X. We have to + * flush the icache and mark them RW- + * + * This is tricky, because map_pages is in the init section. + * Do a dummy remap of the data section first (the data + * section is already PAGE_KERNEL) to pull in the TLB entries + * for map_kernel */ + map_pages(init_begin, __pa(init_begin), init_end - init_begin, + PAGE_KERNEL_RWX, 1); + /* now remap at PAGE_KERNEL since the TLB is pre-primed to execute + * map_pages */ + map_pages(init_begin, __pa(init_begin), init_end - init_begin, + PAGE_KERNEL, 1); + + /* force the kernel to see the new TLB entries */ + __flush_tlb_range(0, init_begin, init_end); /* Attempt to catch anyone trying to execute code here * by filling the page with BRK insns. */ memset((void *)init_begin, 0x00, init_end - init_begin); + /* finally dump all the instructions which were cached, since the + * pages are no-longer executable */ flush_icache_range(init_begin, init_end); -#endif - /* align __init_begin and __init_end to page size, - ignoring linker script where we might have tried to save RAM */ - init_begin = PAGE_ALIGN(init_begin); - init_end = PAGE_ALIGN(init_end); for (addr = init_begin; addr < init_end; addr += PAGE_SIZE) { ClearPageReserved(virt_to_page(addr)); init_page_count(virt_to_page(addr)); @@ -616,114 +750,6 @@ void show_mem(unsigned int filter) #endif } - -static void __init map_pages(unsigned long start_vaddr, unsigned long start_paddr, unsigned long size, pgprot_t pgprot) -{ - pgd_t *pg_dir; - pmd_t *pmd; - pte_t *pg_table; - unsigned long end_paddr; - unsigned long start_pmd; - unsigned long start_pte; - unsigned long tmp1; - unsigned long tmp2; - unsigned long address; - unsigned long ro_start; - unsigned long ro_end; - unsigned long fv_addr; - unsigned long gw_addr; - extern const unsigned long fault_vector_20; - extern void * const linux_gateway_page; - - ro_start = __pa((unsigned long)_text); - ro_end = __pa((unsigned long)&data_start); - fv_addr = __pa((unsigned long)&fault_vector_20) & PAGE_MASK; - gw_addr = __pa((unsigned long)&linux_gateway_page) & PAGE_MASK; - - end_paddr = start_paddr + size; - - pg_dir = pgd_offset_k(start_vaddr); - -#if PTRS_PER_PMD == 1 - start_pmd = 0; -#else - start_pmd = ((start_vaddr >> PMD_SHIFT) & (PTRS_PER_PMD - 1)); -#endif - start_pte = ((start_vaddr >> PAGE_SHIFT) & (PTRS_PER_PTE - 1)); - - address = start_paddr; - while (address < end_paddr) { -#if PTRS_PER_PMD == 1 - pmd = (pmd_t *)__pa(pg_dir); -#else - pmd = (pmd_t *)pgd_address(*pg_dir); - - /* - * pmd is physical at this point - */ - - if (!pmd) { - pmd = (pmd_t *) alloc_bootmem_low_pages_node(NODE_DATA(0),PAGE_SIZE << PMD_ORDER); - pmd = (pmd_t *) __pa(pmd); - } - - pgd_populate(NULL, pg_dir, __va(pmd)); -#endif - pg_dir++; - - /* now change pmd to kernel virtual addresses */ - - pmd = (pmd_t *)__va(pmd) + start_pmd; - for (tmp1 = start_pmd; tmp1 < PTRS_PER_PMD; tmp1++,pmd++) { - - /* - * pg_table is physical at this point - */ - - pg_table = (pte_t *)pmd_address(*pmd); - if (!pg_table) { - pg_table = (pte_t *) - alloc_bootmem_low_pages_node(NODE_DATA(0),PAGE_SIZE); - pg_table = (pte_t *) __pa(pg_table); - } - - pmd_populate_kernel(NULL, pmd, __va(pg_table)); - - /* now change pg_table to kernel virtual addresses */ - - pg_table = (pte_t *) __va(pg_table) + start_pte; - for (tmp2 = start_pte; tmp2 < PTRS_PER_PTE; tmp2++,pg_table++) { - pte_t pte; - - /* - * Map the fault vector writable so we can - * write the HPMC checksum. - */ -#if defined(CONFIG_PARISC_PAGE_SIZE_4KB) - if (address >= ro_start && address < ro_end - && address != fv_addr - && address != gw_addr) - pte = __mk_pte(address, PAGE_KERNEL_RO); - else -#endif - pte = __mk_pte(address, pgprot); - - if (address >= end_paddr) - pte_val(pte) = 0; - - set_pte(pg_table, pte); - - address += PAGE_SIZE; - } - start_pte = 0; - - if (address >= end_paddr) - break; - } - start_pmd = 0; - } -} - /* * pagetable_init() sets up the page tables * @@ -748,14 +774,14 @@ static void __init pagetable_init(void) size = pmem_ranges[range].pages << PAGE_SHIFT; map_pages((unsigned long)__va(start_paddr), start_paddr, - size, PAGE_KERNEL); + size, PAGE_KERNEL, 0); } #ifdef CONFIG_BLK_DEV_INITRD if (initrd_end && initrd_end > mem_limit) { printk(KERN_INFO "initrd: mapping %08lx-%08lx\n", initrd_start, initrd_end); map_pages(initrd_start, __pa(initrd_start), - initrd_end - initrd_start, PAGE_KERNEL); + initrd_end - initrd_start, PAGE_KERNEL, 0); } #endif @@ -780,7 +806,7 @@ static void __init gateway_init(void) */ map_pages(linux_gateway_page_addr, __pa(&linux_gateway_page), - PAGE_SIZE, PAGE_GATEWAY); + PAGE_SIZE, PAGE_GATEWAY, 1); } #ifdef CONFIG_HPUX -- cgit v0.10.2 From b7d45818444a31948cfc7849136013a0ea54b2fb Mon Sep 17 00:00:00 2001 From: James Bottomley Date: Fri, 15 Apr 2011 12:37:22 -0500 Subject: [PARISC] prevent speculative re-read on cache flush According to Appendix F, the TLB is the primary arbiter of speculation. Thus, if a page has a TLB entry, it may be speculatively read into the cache. On linux, this can cause us incoherencies because if we're about to do a disk read, we call get_user_pages() to do the flush/invalidate in user space, but we still potentially have the user TLB entries, and the cache could speculate the lines back into userspace (thus causing stale data to be used). This is fixed by purging the TLB entries before we flush through the tmpalias space. Now, the only way the line could be re-speculated is if the user actually tries to touch it (which is not allowed). Signed-off-by: James Bottomley diff --git a/arch/parisc/include/asm/cacheflush.h b/arch/parisc/include/asm/cacheflush.h index d18328b..da601dd 100644 --- a/arch/parisc/include/asm/cacheflush.h +++ b/arch/parisc/include/asm/cacheflush.h @@ -3,6 +3,7 @@ #include #include +#include /* The usual comment is "Caches aren't brain-dead on the ". * Unfortunately, that doesn't apply to PA-RISC. */ @@ -112,8 +113,10 @@ void flush_dcache_page_asm(unsigned long phys_addr, unsigned long vaddr); static inline void flush_anon_page(struct vm_area_struct *vma, struct page *page, unsigned long vmaddr) { - if (PageAnon(page)) + if (PageAnon(page)) { + flush_tlb_page(vma, vmaddr); flush_dcache_page_asm(page_to_phys(page), vmaddr); + } } #ifdef CONFIG_DEBUG_RODATA diff --git a/arch/parisc/kernel/cache.c b/arch/parisc/kernel/cache.c index 3f11331..83335f3 100644 --- a/arch/parisc/kernel/cache.c +++ b/arch/parisc/kernel/cache.c @@ -304,10 +304,20 @@ void flush_dcache_page(struct page *page) offset = (pgoff - mpnt->vm_pgoff) << PAGE_SHIFT; addr = mpnt->vm_start + offset; + /* The TLB is the engine of coherence on parisc: The + * CPU is entitled to speculate any page with a TLB + * mapping, so here we kill the mapping then flush the + * page along a special flush only alias mapping. + * This guarantees that the page is no-longer in the + * cache for any process and nor may it be + * speculatively read in (until the user or kernel + * specifically accesses it, of course) */ + + flush_tlb_page(mpnt, addr); if (old_addr == 0 || (old_addr & (SHMLBA - 1)) != (addr & (SHMLBA - 1))) { __flush_cache_page(mpnt, addr, page_to_phys(page)); if (old_addr) - printk(KERN_ERR "INEQUIVALENT ALIASES 0x%lx and 0x%lx in file %s\n", old_addr, addr, mpnt->vm_file ? mpnt->vm_file->f_path.dentry->d_name.name : "(null)"); + printk(KERN_ERR "INEQUIVALENT ALIASES 0x%lx and 0x%lx in file %s\n", old_addr, addr, mpnt->vm_file ? (char *)mpnt->vm_file->f_path.dentry->d_name.name : "(null)"); old_addr = addr; } } @@ -499,6 +509,7 @@ flush_cache_page(struct vm_area_struct *vma, unsigned long vmaddr, unsigned long { BUG_ON(!vma->vm_mm->context); + flush_tlb_page(vma, vmaddr); __flush_cache_page(vma, vmaddr, page_to_phys(pfn_to_page(pfn))); } -- cgit v0.10.2 From 1824074b07ee66fa0f714e08579ad85075132d7b Mon Sep 17 00:00:00 2001 From: James Bottomley Date: Fri, 15 Apr 2011 08:55:44 -0700 Subject: [PARISC] wire up fanotify syscalls Cc: stable@kernel.org Signed-off-by: James Bottomley diff --git a/arch/parisc/include/asm/unistd.h b/arch/parisc/include/asm/unistd.h index 3eb82c2a..09f62a6 100644 --- a/arch/parisc/include/asm/unistd.h +++ b/arch/parisc/include/asm/unistd.h @@ -814,8 +814,10 @@ #define __NR_recvmmsg (__NR_Linux + 319) #define __NR_accept4 (__NR_Linux + 320) #define __NR_prlimit64 (__NR_Linux + 321) +#define __NR_fanotify_init (__NR_Linux + 322) +#define __NR_fanotify_mark (__NR_Linux + 323) -#define __NR_Linux_syscalls (__NR_prlimit64 + 1) +#define __NR_Linux_syscalls (__NR_fanotify_mark + 1) #define __IGNORE_select /* newselect */ diff --git a/arch/parisc/kernel/sys_parisc32.c b/arch/parisc/kernel/sys_parisc32.c index 88a0ad1..dc9a624 100644 --- a/arch/parisc/kernel/sys_parisc32.c +++ b/arch/parisc/kernel/sys_parisc32.c @@ -228,3 +228,11 @@ asmlinkage long compat_sys_fallocate(int fd, int mode, u32 offhi, u32 offlo, return sys_fallocate(fd, mode, ((loff_t)offhi << 32) | offlo, ((loff_t)lenhi << 32) | lenlo); } + +asmlinkage long compat_sys_fanotify_mark(int fan_fd, int flags, u32 mask_hi, + u32 mask_lo, int fd, + const char __user *pathname) +{ + return sys_fanotify_mark(fan_fd, flags, ((u64)mask_hi << 32) | mask_lo, + fd, pathname); +} diff --git a/arch/parisc/kernel/syscall_table.S b/arch/parisc/kernel/syscall_table.S index 4be85ee..c5b01e8 100644 --- a/arch/parisc/kernel/syscall_table.S +++ b/arch/parisc/kernel/syscall_table.S @@ -420,6 +420,8 @@ ENTRY_COMP(recvmmsg) ENTRY_SAME(accept4) /* 320 */ ENTRY_SAME(prlimit64) + ENTRY_SAME(fanotify_init) + ENTRY_COMP(fanotify_mark) /* Nothing yet */ -- cgit v0.10.2 From c3f957a22eca106bd28136943305b390b4337ebf Mon Sep 17 00:00:00 2001 From: James Bottomley Date: Fri, 15 Apr 2011 08:55:45 -0700 Subject: [PARISC] wire up clock_adjtime syscall Cc: stable@kernel.org Signed-off-by: James Bottomley diff --git a/arch/parisc/include/asm/unistd.h b/arch/parisc/include/asm/unistd.h index 09f62a6..9af5fab 100644 --- a/arch/parisc/include/asm/unistd.h +++ b/arch/parisc/include/asm/unistd.h @@ -816,8 +816,9 @@ #define __NR_prlimit64 (__NR_Linux + 321) #define __NR_fanotify_init (__NR_Linux + 322) #define __NR_fanotify_mark (__NR_Linux + 323) +#define __NR_clock_adjtime (__NR_Linux + 324) -#define __NR_Linux_syscalls (__NR_fanotify_mark + 1) +#define __NR_Linux_syscalls (__NR_clock_adjtime + 1) #define __IGNORE_select /* newselect */ diff --git a/arch/parisc/kernel/syscall_table.S b/arch/parisc/kernel/syscall_table.S index c5b01e8..473bf41 100644 --- a/arch/parisc/kernel/syscall_table.S +++ b/arch/parisc/kernel/syscall_table.S @@ -422,6 +422,7 @@ ENTRY_SAME(prlimit64) ENTRY_SAME(fanotify_init) ENTRY_COMP(fanotify_mark) + ENTRY_COMP(clock_adjtime) /* Nothing yet */ -- cgit v0.10.2 From a71aae4cec120ee85cf32608fca40a4605461214 Mon Sep 17 00:00:00 2001 From: James Bottomley Date: Fri, 15 Apr 2011 08:55:46 -0700 Subject: [PARISC] wire up the fhandle syscalls Cc: stable@kernel.org Signed-off-by: James Bottomley diff --git a/arch/parisc/include/asm/unistd.h b/arch/parisc/include/asm/unistd.h index 9af5fab..4266e44 100644 --- a/arch/parisc/include/asm/unistd.h +++ b/arch/parisc/include/asm/unistd.h @@ -817,8 +817,10 @@ #define __NR_fanotify_init (__NR_Linux + 322) #define __NR_fanotify_mark (__NR_Linux + 323) #define __NR_clock_adjtime (__NR_Linux + 324) +#define __NR_name_to_handle_at (__NR_Linux + 325) +#define __NR_open_by_handle_at (__NR_Linux + 326) -#define __NR_Linux_syscalls (__NR_clock_adjtime + 1) +#define __NR_Linux_syscalls (__NR_open_by_handle_at + 1) #define __IGNORE_select /* newselect */ diff --git a/arch/parisc/kernel/syscall_table.S b/arch/parisc/kernel/syscall_table.S index 473bf41..b5d2982 100644 --- a/arch/parisc/kernel/syscall_table.S +++ b/arch/parisc/kernel/syscall_table.S @@ -423,6 +423,8 @@ ENTRY_SAME(fanotify_init) ENTRY_COMP(fanotify_mark) ENTRY_COMP(clock_adjtime) + ENTRY_SAME(name_to_handle_at) /* 325 */ + ENTRY_COMP(open_by_handle_at) /* Nothing yet */ -- cgit v0.10.2 From 2e7bad5f34b5beed47542490c760ed26574e38ba Mon Sep 17 00:00:00 2001 From: James Bottomley Date: Fri, 15 Apr 2011 08:55:47 -0700 Subject: [PARISC] wire up syncfs syscall Cc: stable@kernel.org Signed-off-by: James Bottomley diff --git a/arch/parisc/include/asm/unistd.h b/arch/parisc/include/asm/unistd.h index 4266e44..9cbc2c3 100644 --- a/arch/parisc/include/asm/unistd.h +++ b/arch/parisc/include/asm/unistd.h @@ -819,8 +819,9 @@ #define __NR_clock_adjtime (__NR_Linux + 324) #define __NR_name_to_handle_at (__NR_Linux + 325) #define __NR_open_by_handle_at (__NR_Linux + 326) +#define __NR_syncfs (__NR_Linux + 327) -#define __NR_Linux_syscalls (__NR_open_by_handle_at + 1) +#define __NR_Linux_syscalls (__NR_syncfs + 1) #define __IGNORE_select /* newselect */ diff --git a/arch/parisc/kernel/syscall_table.S b/arch/parisc/kernel/syscall_table.S index b5d2982..a5b02ce 100644 --- a/arch/parisc/kernel/syscall_table.S +++ b/arch/parisc/kernel/syscall_table.S @@ -425,6 +425,7 @@ ENTRY_COMP(clock_adjtime) ENTRY_SAME(name_to_handle_at) /* 325 */ ENTRY_COMP(open_by_handle_at) + ENTRY_SAME(syncfs) /* Nothing yet */ -- cgit v0.10.2 From 0e4f8f888845f9dca540ad175884244e5db5eea2 Mon Sep 17 00:00:00 2001 From: Chris Mason Date: Fri, 15 Apr 2011 16:05:44 -0400 Subject: Btrfs: don't force chunk allocation in find_free_extent find_free_extent likes to allocate in contiguous clusters, which makes writeback faster, especially on SSD storage. As the FS fragments, these clusters become harder to find and we have to decide between allocating a new chunk to make more clusters or giving up on the cluster to allocate from the free space we have. Right now it creates too many chunks, and you can end up with a whole FS that is mostly empty metadata chunks. This commit changes the allocation code to be more strict and only allocate new chunks when we've made good use of the chunks we already have. Signed-off-by: Chris Mason diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c index f619c3c..2647948 100644 --- a/fs/btrfs/extent-tree.c +++ b/fs/btrfs/extent-tree.c @@ -33,6 +33,25 @@ #include "locking.h" #include "free-space-cache.h" +/* control flags for do_chunk_alloc's force field + * CHUNK_ALLOC_NO_FORCE means to only allocate a chunk + * if we really need one. + * + * CHUNK_ALLOC_FORCE means it must try to allocate one + * + * CHUNK_ALLOC_LIMITED means to only try and allocate one + * if we have very few chunks already allocated. This is + * used as part of the clustering code to help make sure + * we have a good pool of storage to cluster in, without + * filling the FS with empty chunks + * + */ +enum { + CHUNK_ALLOC_NO_FORCE = 0, + CHUNK_ALLOC_FORCE = 1, + CHUNK_ALLOC_LIMITED = 2, +}; + static int update_block_group(struct btrfs_trans_handle *trans, struct btrfs_root *root, u64 bytenr, u64 num_bytes, int alloc); @@ -3019,7 +3038,7 @@ static int update_space_info(struct btrfs_fs_info *info, u64 flags, found->bytes_readonly = 0; found->bytes_may_use = 0; found->full = 0; - found->force_alloc = 0; + found->force_alloc = CHUNK_ALLOC_NO_FORCE; *space_info = found; list_add_rcu(&found->list, &info->space_info); atomic_set(&found->caching_threads, 0); @@ -3150,7 +3169,7 @@ again: if (!data_sinfo->full && alloc_chunk) { u64 alloc_target; - data_sinfo->force_alloc = 1; + data_sinfo->force_alloc = CHUNK_ALLOC_FORCE; spin_unlock(&data_sinfo->lock); alloc: alloc_target = btrfs_get_alloc_profile(root, 1); @@ -3160,7 +3179,8 @@ alloc: ret = do_chunk_alloc(trans, root->fs_info->extent_root, bytes + 2 * 1024 * 1024, - alloc_target, 0); + alloc_target, + CHUNK_ALLOC_NO_FORCE); btrfs_end_transaction(trans, root); if (ret < 0) { if (ret != -ENOSPC) @@ -3239,31 +3259,56 @@ static void force_metadata_allocation(struct btrfs_fs_info *info) rcu_read_lock(); list_for_each_entry_rcu(found, head, list) { if (found->flags & BTRFS_BLOCK_GROUP_METADATA) - found->force_alloc = 1; + found->force_alloc = CHUNK_ALLOC_FORCE; } rcu_read_unlock(); } static int should_alloc_chunk(struct btrfs_root *root, - struct btrfs_space_info *sinfo, u64 alloc_bytes) + struct btrfs_space_info *sinfo, u64 alloc_bytes, + int force) { u64 num_bytes = sinfo->total_bytes - sinfo->bytes_readonly; + u64 num_allocated = sinfo->bytes_used + sinfo->bytes_reserved; u64 thresh; - if (sinfo->bytes_used + sinfo->bytes_reserved + - alloc_bytes + 256 * 1024 * 1024 < num_bytes) + if (force == CHUNK_ALLOC_FORCE) + return 1; + + /* + * in limited mode, we want to have some free space up to + * about 1% of the FS size. + */ + if (force == CHUNK_ALLOC_LIMITED) { + thresh = btrfs_super_total_bytes(&root->fs_info->super_copy); + thresh = max_t(u64, 64 * 1024 * 1024, + div_factor_fine(thresh, 1)); + + if (num_bytes - num_allocated < thresh) + return 1; + } + + /* + * we have two similar checks here, one based on percentage + * and once based on a hard number of 256MB. The idea + * is that if we have a good amount of free + * room, don't allocate a chunk. A good mount is + * less than 80% utilized of the chunks we have allocated, + * or more than 256MB free + */ + if (num_allocated + alloc_bytes + 256 * 1024 * 1024 < num_bytes) return 0; - if (sinfo->bytes_used + sinfo->bytes_reserved + - alloc_bytes < div_factor(num_bytes, 8)) + if (num_allocated + alloc_bytes < div_factor(num_bytes, 8)) return 0; thresh = btrfs_super_total_bytes(&root->fs_info->super_copy); + + /* 256MB or 5% of the FS */ thresh = max_t(u64, 256 * 1024 * 1024, div_factor_fine(thresh, 5)); if (num_bytes > thresh && sinfo->bytes_used < div_factor(num_bytes, 3)) return 0; - return 1; } @@ -3289,17 +3334,17 @@ static int do_chunk_alloc(struct btrfs_trans_handle *trans, spin_lock(&space_info->lock); if (space_info->force_alloc) - force = 1; + force = space_info->force_alloc; if (space_info->full) { spin_unlock(&space_info->lock); goto out; } - if (!force && !should_alloc_chunk(extent_root, space_info, - alloc_bytes)) { + if (!should_alloc_chunk(extent_root, space_info, alloc_bytes, force)) { spin_unlock(&space_info->lock); goto out; } + spin_unlock(&space_info->lock); /* @@ -3327,7 +3372,7 @@ static int do_chunk_alloc(struct btrfs_trans_handle *trans, space_info->full = 1; else ret = 1; - space_info->force_alloc = 0; + space_info->force_alloc = CHUNK_ALLOC_NO_FORCE; spin_unlock(&space_info->lock); out: mutex_unlock(&extent_root->fs_info->chunk_mutex); @@ -5303,11 +5348,13 @@ loop: if (allowed_chunk_alloc) { ret = do_chunk_alloc(trans, root, num_bytes + - 2 * 1024 * 1024, data, 1); + 2 * 1024 * 1024, data, + CHUNK_ALLOC_LIMITED); allowed_chunk_alloc = 0; done_chunk_alloc = 1; - } else if (!done_chunk_alloc) { - space_info->force_alloc = 1; + } else if (!done_chunk_alloc && + space_info->force_alloc == CHUNK_ALLOC_NO_FORCE) { + space_info->force_alloc = CHUNK_ALLOC_LIMITED; } if (loop < LOOP_NO_EMPTY_SIZE) { @@ -5393,7 +5440,8 @@ again: */ if (empty_size || root->ref_cows) ret = do_chunk_alloc(trans, root->fs_info->extent_root, - num_bytes + 2 * 1024 * 1024, data, 0); + num_bytes + 2 * 1024 * 1024, data, + CHUNK_ALLOC_NO_FORCE); WARN_ON(num_bytes < root->sectorsize); ret = find_free_extent(trans, root, num_bytes, empty_size, @@ -5405,7 +5453,7 @@ again: num_bytes = num_bytes & ~(root->sectorsize - 1); num_bytes = max(num_bytes, min_alloc_size); do_chunk_alloc(trans, root->fs_info->extent_root, - num_bytes, data, 1); + num_bytes, data, CHUNK_ALLOC_FORCE); goto again; } if (ret == -ENOSPC && btrfs_test_opt(root, ENOSPC_DEBUG)) { @@ -8109,13 +8157,15 @@ int btrfs_set_block_group_ro(struct btrfs_root *root, alloc_flags = update_block_group_flags(root, cache->flags); if (alloc_flags != cache->flags) - do_chunk_alloc(trans, root, 2 * 1024 * 1024, alloc_flags, 1); + do_chunk_alloc(trans, root, 2 * 1024 * 1024, alloc_flags, + CHUNK_ALLOC_FORCE); ret = set_block_group_ro(cache); if (!ret) goto out; alloc_flags = get_alloc_profile(root, cache->space_info->flags); - ret = do_chunk_alloc(trans, root, 2 * 1024 * 1024, alloc_flags, 1); + ret = do_chunk_alloc(trans, root, 2 * 1024 * 1024, alloc_flags, + CHUNK_ALLOC_FORCE); if (ret < 0) goto out; ret = set_block_group_ro(cache); @@ -8128,7 +8178,8 @@ int btrfs_force_chunk_alloc(struct btrfs_trans_handle *trans, struct btrfs_root *root, u64 type) { u64 alloc_flags = get_alloc_profile(root, type); - return do_chunk_alloc(trans, root, 2 * 1024 * 1024, alloc_flags, 1); + return do_chunk_alloc(trans, root, 2 * 1024 * 1024, alloc_flags, + CHUNK_ALLOC_FORCE); } /* -- cgit v0.10.2 From deb1cb63d220fc6f24baef39a0ebb48e598f617b Mon Sep 17 00:00:00 2001 From: Shyam Iyer Date: Sat, 26 Feb 2011 01:59:44 -0500 Subject: [SCSI] Log thin provisioning threshold event At least log the message that we received a THIN PROVISIONING SOFT THRESHOLD REACHED Unit Attention. Also added it to unit attention decodes. Signed-off-by: Shyam Iyer Signed-off-by: James Bottomley diff --git a/drivers/scsi/constants.c b/drivers/scsi/constants.c index d0c8234..60d2ef2 100644 --- a/drivers/scsi/constants.c +++ b/drivers/scsi/constants.c @@ -772,6 +772,7 @@ static const struct error_info additional[] = {0x3802, "Esn - power management class event"}, {0x3804, "Esn - media class event"}, {0x3806, "Esn - device busy class event"}, + {0x3807, "Thin Provisioning soft threshold reached"}, {0x3900, "Saving parameters not supported"}, diff --git a/drivers/scsi/scsi_error.c b/drivers/scsi/scsi_error.c index 633c239..abea2cf 100644 --- a/drivers/scsi/scsi_error.c +++ b/drivers/scsi/scsi_error.c @@ -321,6 +321,12 @@ static int scsi_check_sense(struct scsi_cmnd *scmd) "changed. The Linux SCSI layer does not " "automatically adjust these parameters.\n"); + if (sshdr.asc == 0x38 && sshdr.ascq == 0x07) + scmd_printk(KERN_WARNING, scmd, + "Warning! Received an indication that the " + "LUN reached a thin provisioning soft " + "threshold.\n"); + /* * Pass the UA upwards for a determination in the completion * functions. -- cgit v0.10.2 From b4ce6a285b65be4fb858728b3bbe9011242b769f Mon Sep 17 00:00:00 2001 From: Florian Tobias Schandinat Date: Fri, 15 Apr 2011 21:35:25 +0000 Subject: viafb: fix OLPC DCON refresh rate This patch fixes a regression introduced by fd3cc69848b7e1873e5f12bbcdd572b20277ecf3a "viafb: remove duplicated clock storage" caused by an incosistent mode which pretended to have a higher refresh rate than it actually had. The wrong refresh rate resulted in a calculated higher pixclock which the OLPC DCON could not handle. By reducing the refresh rate to 50Hz we get close to the old pixclock which makes the OLPC display usable again. Minor other adjustments are needed as 60Hz is assumed to be a safe value which is not true for OLPC DCON. This is no problem as we only support 1200x900 on the OLPC. Signed-off-by: Florian Tobias Schandinat Reported-by: Daniel Drake diff --git a/drivers/video/via/hw.c b/drivers/video/via/hw.c index dc4c778..980e263 100644 --- a/drivers/video/via/hw.c +++ b/drivers/video/via/hw.c @@ -2598,8 +2598,12 @@ int viafb_get_refresh(int hres, int vres, u32 long_refresh) best = &vmode->crtc[i]; } - if (abs(best->refresh_rate - long_refresh) > 3) - return 60; + if (abs(best->refresh_rate - long_refresh) > 3) { + if (hres == 1200 && vres == 900) + return 50; /* OLPC DCON only supports 50 Hz */ + else + return 60; + } return best->refresh_rate; } diff --git a/drivers/video/via/viamode.c b/drivers/video/via/viamode.c index 8c5bc41..260d339 100644 --- a/drivers/video/via/viamode.c +++ b/drivers/video/via/viamode.c @@ -606,7 +606,7 @@ static struct crt_mode_table CRTM1200x720[] = { /* 1200x900 (DCON) */ static struct crt_mode_table DCON1200x900[] = { /* r_rate, hsp, vsp */ - {REFRESH_60, M1200X900_R60_HSP, M1200X900_R60_VSP, + {REFRESH_50, M1200X900_R60_HSP, M1200X900_R60_VSP, /* The correct htotal is 1240, but this doesn't raster on VX855. */ /* Via suggested changing to a multiple of 16, hence 1264. */ /* HT, HA, HBS, HBE, HSS, HSE, VT, VA, VBS, VBE, VSS, VSE */ -- cgit v0.10.2 From 255fa9a3cce3e344ff245cf3b4fbb738bd7e3f48 Mon Sep 17 00:00:00 2001 From: Jayamohan Kallickal Date: Fri, 25 Mar 2011 14:23:57 -0700 Subject: [SCSI] be2iscsi: change in copyright notice - Modifying copyright year to 2011 - Replacing Serverengines with Emulex as Serverengines Corp has been acquired by Emulex Corp Signed-off-by: Jayamohan Kallickal Signed-off-by: James Bottomley diff --git a/drivers/scsi/be2iscsi/be.h b/drivers/scsi/be2iscsi/be.h index 1cb8a5e..1d7b976 100644 --- a/drivers/scsi/be2iscsi/be.h +++ b/drivers/scsi/be2iscsi/be.h @@ -1,5 +1,5 @@ /** - * Copyright (C) 2005 - 2010 ServerEngines + * Copyright (C) 2005 - 2011 Emulex * All rights reserved. * * This program is free software; you can redistribute it and/or @@ -8,11 +8,11 @@ * Public License is included in this distribution in the file called COPYING. * * Contact Information: - * linux-drivers@serverengines.com + * linux-drivers@emulex.com * - * ServerEngines - * 209 N. Fair Oaks Ave - * Sunnyvale, CA 94085 + * Emulex + * 3333 Susan Street + * Costa Mesa, CA 92626 */ #ifndef BEISCSI_H diff --git a/drivers/scsi/be2iscsi/be_cmds.c b/drivers/scsi/be2iscsi/be_cmds.c index ad24636..4ffcbf7 100644 --- a/drivers/scsi/be2iscsi/be_cmds.c +++ b/drivers/scsi/be2iscsi/be_cmds.c @@ -1,5 +1,5 @@ /** - * Copyright (C) 2005 - 2010 ServerEngines + * Copyright (C) 2005 - 2011 Emulex * All rights reserved. * * This program is free software; you can redistribute it and/or @@ -8,11 +8,11 @@ * Public License is included in this distribution in the file called COPYING. * * Contact Information: - * linux-drivers@serverengines.com + * linux-drivers@emulex.com * - * ServerEngines - * 209 N. Fair Oaks Ave - * Sunnyvale, CA 94085 + * Emulex + * 3333 Susan Street + * Costa Mesa, CA 92626 */ #include "be.h" diff --git a/drivers/scsi/be2iscsi/be_cmds.h b/drivers/scsi/be2iscsi/be_cmds.h index fbd1dc2..497eb29 100644 --- a/drivers/scsi/be2iscsi/be_cmds.h +++ b/drivers/scsi/be2iscsi/be_cmds.h @@ -1,5 +1,5 @@ /** - * Copyright (C) 2005 - 2010 ServerEngines + * Copyright (C) 2005 - 2011 Emulex * All rights reserved. * * This program is free software; you can redistribute it and/or @@ -8,11 +8,11 @@ * Public License is included in this distribution in the file called COPYING. * * Contact Information: - * linux-drivers@serverengines.com + * linux-drivers@emulex.com * - * ServerEngines - * 209 N. Fair Oaks Ave - * Sunnyvale, CA 94085 + * Emulex + * 3333 Susan Street + * Costa Mesa, CA 92626 */ #ifndef BEISCSI_CMDS_H diff --git a/drivers/scsi/be2iscsi/be_iscsi.c b/drivers/scsi/be2iscsi/be_iscsi.c index 868cc55..3cad106 100644 --- a/drivers/scsi/be2iscsi/be_iscsi.c +++ b/drivers/scsi/be2iscsi/be_iscsi.c @@ -1,5 +1,5 @@ /** - * Copyright (C) 2005 - 2010 ServerEngines + * Copyright (C) 2005 - 2011 Emulex * All rights reserved. * * This program is free software; you can redistribute it and/or @@ -7,15 +7,14 @@ * as published by the Free Software Foundation. The full GNU General * Public License is included in this distribution in the file called COPYING. * - * Written by: Jayamohan Kallickal (jayamohank@serverengines.com) + * Written by: Jayamohan Kallickal (jayamohan.kallickal@emulex.com) * * Contact Information: - * linux-drivers@serverengines.com - * - * ServerEngines - * 209 N. Fair Oaks Ave - * Sunnyvale, CA 94085 + * linux-drivers@emulex.com * + * Emulex + * 3333 Susan Street + * Costa Mesa, CA 92626 */ #include diff --git a/drivers/scsi/be2iscsi/be_iscsi.h b/drivers/scsi/be2iscsi/be_iscsi.h index 9c53279..ff60b7f 100644 --- a/drivers/scsi/be2iscsi/be_iscsi.h +++ b/drivers/scsi/be2iscsi/be_iscsi.h @@ -1,5 +1,5 @@ /** - * Copyright (C) 2005 - 2010 ServerEngines + * Copyright (C) 2005 - 2011 Emulex * All rights reserved. * * This program is free software; you can redistribute it and/or @@ -7,15 +7,14 @@ * as published by the Free Software Foundation. The full GNU General * Public License is included in this distribution in the file called COPYING. * - * Written by: Jayamohan Kallickal (jayamohank@serverengines.com) + * Written by: Jayamohan Kallickal (jayamohan.kallickal@emulex.com) * * Contact Information: - * linux-drivers@serverengines.com - * - * ServerEngines - * 209 N. Fair Oaks Ave - * Sunnyvale, CA 94085 + * linux-drivers@emulex.com * + * Emulex + * 3333 Susan Street + * Costa Mesa, CA 92626 */ #ifndef _BE_ISCSI_ diff --git a/drivers/scsi/be2iscsi/be_main.c b/drivers/scsi/be2iscsi/be_main.c index 24e20ba..7fe38a4 100644 --- a/drivers/scsi/be2iscsi/be_main.c +++ b/drivers/scsi/be2iscsi/be_main.c @@ -1,5 +1,5 @@ /** - * Copyright (C) 2005 - 2010 ServerEngines + * Copyright (C) 2005 - 2011 Emulex * All rights reserved. * * This program is free software; you can redistribute it and/or @@ -7,16 +7,16 @@ * as published by the Free Software Foundation. The full GNU General * Public License is included in this distribution in the file called COPYING. * - * Written by: Jayamohan Kallickal (jayamohank@serverengines.com) + * Written by: Jayamohan Kallickal (jayamohan.kallickal@emulex.com) * * Contact Information: - * linux-drivers@serverengines.com - * - * ServerEngines - * 209 N. Fair Oaks Ave - * Sunnyvale, CA 94085 + * linux-drivers@emulex.com * + * Emulex + * 3333 Susan Street + * Costa Mesa, CA 92626 */ + #include #include #include diff --git a/drivers/scsi/be2iscsi/be_main.h b/drivers/scsi/be2iscsi/be_main.h index 90eb74f..1f7c495 100644 --- a/drivers/scsi/be2iscsi/be_main.h +++ b/drivers/scsi/be2iscsi/be_main.h @@ -1,5 +1,5 @@ /** - * Copyright (C) 2005 - 2010 ServerEngines + * Copyright (C) 2005 - 2011 Emulex * All rights reserved. * * This program is free software; you can redistribute it and/or @@ -7,15 +7,14 @@ * as published by the Free Software Foundation. The full GNU General * Public License is included in this distribution in the file called COPYING. * - * Written by: Jayamohan Kallickal (jayamohank@serverengines.com) + * Written by: Jayamohan Kallickal (jayamohan.kallickal@emulex.com) * * Contact Information: - * linux-drivers@serverengines.com - * - * ServerEngines - * 209 N. Fair Oaks Ave - * Sunnyvale, CA 94085 + * linux-drivers@emulex.com * + * Emulex + * 3333 Susan Street + * Costa Mesa, CA 92626 */ #ifndef _BEISCSI_MAIN_ diff --git a/drivers/scsi/be2iscsi/be_mgmt.c b/drivers/scsi/be2iscsi/be_mgmt.c index 877324f..65a402b 100644 --- a/drivers/scsi/be2iscsi/be_mgmt.c +++ b/drivers/scsi/be2iscsi/be_mgmt.c @@ -1,5 +1,5 @@ /** - * Copyright (C) 2005 - 2010 ServerEngines + * Copyright (C) 2005 - 2011 Emulex * All rights reserved. * * This program is free software; you can redistribute it and/or @@ -7,15 +7,14 @@ * as published by the Free Software Foundation. The full GNU General * Public License is included in this distribution in the file called COPYING. * - * Written by: Jayamohan Kallickal (jayamohank@serverengines.com) + * Written by: Jayamohan Kallickal (jayamohan.kallickal@emulex.com) * * Contact Information: - * linux-drivers@serverengines.com - * - * ServerEngines - * 209 N. Fair Oaks Ave - * Sunnyvale, CA 94085 + * linux-drivers@emulex.com * + * Emulex + * 3333 Susan Street + * Costa Mesa, CA 92626 */ #include "be_mgmt.h" diff --git a/drivers/scsi/be2iscsi/be_mgmt.h b/drivers/scsi/be2iscsi/be_mgmt.h index b9acedf..0842882 100644 --- a/drivers/scsi/be2iscsi/be_mgmt.h +++ b/drivers/scsi/be2iscsi/be_mgmt.h @@ -1,5 +1,5 @@ /** - * Copyright (C) 2005 - 2010 ServerEngines + * Copyright (C) 2005 - 2011 Emulex * All rights reserved. * * This program is free software; you can redistribute it and/or @@ -7,15 +7,14 @@ * as published by the Free Software Foundation. The full GNU General * Public License is included in this distribution in the file called COPYING. * - * Written by: Jayamohan Kallickal (jayamohank@serverengines.com) + * Written by: Jayamohan Kallickal (jayamohan.kallickal@emulex.com) * * Contact Information: - * linux-drivers@serverengines.com - * - * ServerEngines - * 209 N. Fair Oaks Ave - * Sunnyvale, CA 94085 + * linux-drivers@emulex.com * + * Emulex + * 3333 Susan Street + * Costa Mesa, CA 92626 */ #ifndef _BEISCSI_MGMT_ -- cgit v0.10.2 From 0ca43cc01ed6778ce7a870573dbbd1c6b44bbab2 Mon Sep 17 00:00:00 2001 From: Jayamohan Kallickal Date: Fri, 25 Mar 2011 14:23:58 -0700 Subject: [SCSI] be2iscsi: Modifying Maintainer's emailid - Modifying Maintainer's emailid to emulex as Emulex has acquired Serverengines Signed-off-by: Jayamohan Kallickal Signed-off-by: James Bottomley diff --git a/MAINTAINERS b/MAINTAINERS index ec36003..4f68fa7 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -5596,9 +5596,9 @@ F: include/linux/ata.h F: include/linux/libata.h SERVER ENGINES 10Gbps iSCSI - BladeEngine 2 DRIVER -M: Jayamohan Kallickal +M: Jayamohan Kallickal L: linux-scsi@vger.kernel.org -W: http://www.serverengines.com +W: http://www.emulex.com S: Supported F: drivers/scsi/be2iscsi/ -- cgit v0.10.2 From 91eefa894add1617200c70d3886773e608de7a03 Mon Sep 17 00:00:00 2001 From: Jayamohan Kallickal Date: Fri, 25 Mar 2011 14:23:59 -0700 Subject: [SCSI] be2iscsi: Set a timeout to FW Signed-off-by: Jayamohan Kallickal Signed-off-by: James Bottomley diff --git a/drivers/scsi/be2iscsi/be_cmds.c b/drivers/scsi/be2iscsi/be_cmds.c index 4ffcbf7..b8a82f2 100644 --- a/drivers/scsi/be2iscsi/be_cmds.c +++ b/drivers/scsi/be2iscsi/be_cmds.c @@ -458,6 +458,7 @@ void be_cmd_hdr_prepare(struct be_cmd_req_hdr *req_hdr, req_hdr->opcode = opcode; req_hdr->subsystem = subsystem; req_hdr->request_length = cpu_to_le32(cmd_len - sizeof(*req_hdr)); + req_hdr->timeout = 120; } static void be_cmd_page_addrs_prepare(struct phys_addr *pages, u32 max_pages, -- cgit v0.10.2 From 0b1d3cbf51f75eaaabdb904f02362368487e2aa7 Mon Sep 17 00:00:00 2001 From: Jayamohan Kallickal Date: Fri, 25 Mar 2011 14:24:00 -0700 Subject: [SCSI] be2iscsi: check boot_kset is created before destroying it Signed-off-by: Jayamohan Kallickal Signed-off-by: James Bottomley diff --git a/drivers/scsi/be2iscsi/be_main.c b/drivers/scsi/be2iscsi/be_main.c index 7fe38a4..91b354d 100644 --- a/drivers/scsi/be2iscsi/be_main.c +++ b/drivers/scsi/be2iscsi/be_main.c @@ -420,7 +420,8 @@ static int beiscsi_setup_boot_info(struct beiscsi_hba *phba) return 0; free_kset: - iscsi_boot_destroy_kset(phba->boot_kset); + if (phba->boot_kset) + iscsi_boot_destroy_kset(phba->boot_kset); return -ENOMEM; } @@ -4144,10 +4145,11 @@ static void beiscsi_remove(struct pci_dev *pcidev) phba->ctrl.mbox_mem_alloced.size, phba->ctrl.mbox_mem_alloced.va, phba->ctrl.mbox_mem_alloced.dma); + if (phba->boot_kset) + iscsi_boot_destroy_kset(phba->boot_kset); iscsi_host_remove(phba->shost); pci_dev_put(phba->pcidev); iscsi_host_free(phba->shost); - iscsi_boot_destroy_kset(phba->boot_kset); } static void beiscsi_msix_enable(struct beiscsi_hba *phba) -- cgit v0.10.2 From 1390b01b26300d42662e436d8f1d307c4e0903c7 Mon Sep 17 00:00:00 2001 From: Jayamohan Kallickal Date: Fri, 25 Mar 2011 14:24:01 -0700 Subject: [SCSI] be2iscsi: Fix for proper setting of FW There was a bug in setting up type and dmsg for FW Signed-off-by: Jayamohan Kallickal Signed-off-by: James Bottomley diff --git a/drivers/scsi/be2iscsi/be_main.c b/drivers/scsi/be2iscsi/be_main.c index 91b354d..d834136 100644 --- a/drivers/scsi/be2iscsi/be_main.c +++ b/drivers/scsi/be2iscsi/be_main.c @@ -4020,12 +4020,17 @@ static int beiscsi_mtask(struct iscsi_task *task) hwi_write_buffer(pwrb, task); break; case ISCSI_OP_NOOP_OUT: - AMAP_SET_BITS(struct amap_iscsi_wrb, type, pwrb, - INI_RD_CMD); - if (task->hdr->ttt == ISCSI_RESERVED_TAG) + if (task->hdr->ttt != ISCSI_RESERVED_TAG) { + AMAP_SET_BITS(struct amap_iscsi_wrb, type, pwrb, + TGT_DM_CMD); + AMAP_SET_BITS(struct amap_iscsi_wrb, cmdsn_itt, + pwrb, 0); AMAP_SET_BITS(struct amap_iscsi_wrb, dmsg, pwrb, 0); - else + } else { + AMAP_SET_BITS(struct amap_iscsi_wrb, type, pwrb, + INI_RD_CMD); AMAP_SET_BITS(struct amap_iscsi_wrb, dmsg, pwrb, 1); + } hwi_write_buffer(pwrb, task); break; case ISCSI_OP_TEXT: -- cgit v0.10.2 From e3b2854faabd10438f5e7e34e078b099c3375577 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Fri, 15 Apr 2011 12:58:56 -0400 Subject: SUNRPC: Fix the SUNRPC Kerberos V RPCSEC_GSS module dependencies Since kernel 2.6.35, the SUNRPC Kerberos support has had an implicit dependency on a number of additional crypto modules. The following patch makes that dependency explicit. Signed-off-by: Trond Myklebust diff --git a/net/sunrpc/Kconfig b/net/sunrpc/Kconfig index 8873fd8..b2198e6 100644 --- a/net/sunrpc/Kconfig +++ b/net/sunrpc/Kconfig @@ -18,14 +18,13 @@ config SUNRPC_XPRT_RDMA If unsure, say N. config RPCSEC_GSS_KRB5 - tristate + tristate "Secure RPC: Kerberos V mechanism" depends on SUNRPC && CRYPTO - prompt "Secure RPC: Kerberos V mechanism" if !(NFS_V4 || NFSD_V4) + depends on CRYPTO_MD5 && CRYPTO_DES && CRYPTO_CBC && CRYPTO_CTS + depends on CRYPTO_ECB && CRYPTO_HMAC && CRYPTO_SHA1 && CRYPTO_AES + depends on CRYPTO_ARC4 default y select SUNRPC_GSS - select CRYPTO_MD5 - select CRYPTO_DES - select CRYPTO_CBC help Choose Y here to enable Secure RPC using the Kerberos version 5 GSS-API mechanism (RFC 1964). -- cgit v0.10.2 From 47c2199b6eb5fbe38ddb844db7cdbd914d304f9c Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Fri, 15 Apr 2011 17:34:18 -0400 Subject: NFSv4.1: Ensure state manager thread dies on last umount Currently, the state manager may continue to try recovering state forever even after the last filesystem to reference that nfs_client has umounted. Signed-off-by: Trond Myklebust Cc: stable@kernel.org diff --git a/fs/nfs/nfs4state.c b/fs/nfs/nfs4state.c index a6804f7..4dfb34b 100644 --- a/fs/nfs/nfs4state.c +++ b/fs/nfs/nfs4state.c @@ -1607,7 +1607,7 @@ static void nfs4_state_manager(struct nfs_client *clp) int status = 0; /* Ensure exclusive access to NFSv4 state */ - for(;;) { + do { if (test_and_clear_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state)) { /* We're going to have to re-establish a clientid */ status = nfs4_reclaim_lease(clp); @@ -1691,7 +1691,7 @@ static void nfs4_state_manager(struct nfs_client *clp) break; if (test_and_set_bit(NFS4CLNT_MANAGER_RUNNING, &clp->cl_state) != 0) break; - } + } while (atomic_read(&clp->cl_count) > 1); return; out_error: printk(KERN_WARNING "Error: state manager failed on NFSv4 server %s" -- cgit v0.10.2 From bd015928bb1713691068c4d0d159afccbaf0f8c0 Mon Sep 17 00:00:00 2001 From: Daniel Walter Date: Wed, 13 Apr 2011 21:09:25 +0000 Subject: ipv6: ignore looped-back NA while dad is running [ipv6] Ignore looped-back NAs while in Duplicate Address Detection If we send an unsolicited NA shortly after bringing up an IPv6 address, the duplicate address detection algorithm fails and the ip stays in tentative mode forever. This is due a missing check if the NA is looped-back to us. Signed-off-by: Daniel Walter Signed-off-by: David S. Miller diff --git a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c index 92f952d..f057ff3 100644 --- a/net/ipv6/ndisc.c +++ b/net/ipv6/ndisc.c @@ -945,9 +945,10 @@ static void ndisc_recv_na(struct sk_buff *skb) } ifp = ipv6_get_ifaddr(dev_net(dev), &msg->target, dev, 1); if (ifp) { - if (ifp->flags & IFA_F_TENTATIVE) { - addrconf_dad_failure(ifp); - return; + if (skb->pkt_type != PACKET_LOOPBACK + && (ifp->flags & IFA_F_TENTATIVE)) { + addrconf_dad_failure(ifp); + return; } /* What should we make now? The advertisement is invalid, but ndisc specs say nothing -- cgit v0.10.2 From c3968a857a6b6c3d2ef4ead35776b055fb664d74 Mon Sep 17 00:00:00 2001 From: Daniel Walter Date: Wed, 13 Apr 2011 21:10:57 +0000 Subject: ipv6: RTA_PREFSRC support for ipv6 route source address selection [ipv6] Add support for RTA_PREFSRC This patch allows a user to select the preferred source address for a specific IPv6-Route. It can be set via a netlink message setting RTA_PREFSRC to a valid IPv6 address which must be up on the device the route will be bound to. Signed-off-by: Daniel Walter Signed-off-by: David S. Miller diff --git a/include/net/ip6_fib.h b/include/net/ip6_fib.h index bc3cde0..98348d5 100644 --- a/include/net/ip6_fib.h +++ b/include/net/ip6_fib.h @@ -42,6 +42,7 @@ struct fib6_config { struct in6_addr fc_dst; struct in6_addr fc_src; + struct in6_addr fc_prefsrc; struct in6_addr fc_gateway; unsigned long fc_expires; @@ -107,6 +108,7 @@ struct rt6_info { struct rt6key rt6i_dst ____cacheline_aligned_in_smp; u32 rt6i_flags; struct rt6key rt6i_src; + struct rt6key rt6i_prefsrc; u32 rt6i_metric; u32 rt6i_peer_genid; diff --git a/include/net/ip6_route.h b/include/net/ip6_route.h index c850e5f..86b1cb4 100644 --- a/include/net/ip6_route.h +++ b/include/net/ip6_route.h @@ -84,6 +84,12 @@ extern int ip6_route_add(struct fib6_config *cfg); extern int ip6_ins_rt(struct rt6_info *); extern int ip6_del_rt(struct rt6_info *); +extern int ip6_route_get_saddr(struct net *net, + struct rt6_info *rt, + struct in6_addr *daddr, + unsigned int prefs, + struct in6_addr *saddr); + extern struct rt6_info *rt6_lookup(struct net *net, const struct in6_addr *daddr, const struct in6_addr *saddr, @@ -141,6 +147,7 @@ struct rt6_rtnl_dump_arg { extern int rt6_dump_route(struct rt6_info *rt, void *p_arg); extern void rt6_ifdown(struct net *net, struct net_device *dev); extern void rt6_mtu_change(struct net_device *dev, unsigned mtu); +extern void rt6_remove_prefsrc(struct inet6_ifaddr *ifp); /* diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c index 1493534..129d7e1 100644 --- a/net/ipv6/addrconf.c +++ b/net/ipv6/addrconf.c @@ -825,6 +825,8 @@ static void ipv6_del_addr(struct inet6_ifaddr *ifp) dst_release(&rt->dst); } + /* clean up prefsrc entries */ + rt6_remove_prefsrc(ifp); out: in6_ifa_put(ifp); } diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c index 46cf7be..c614d02 100644 --- a/net/ipv6/ip6_output.c +++ b/net/ipv6/ip6_output.c @@ -930,10 +930,10 @@ static int ip6_dst_lookup_tail(struct sock *sk, goto out_err_release; if (ipv6_addr_any(&fl6->saddr)) { - err = ipv6_dev_get_saddr(net, ip6_dst_idev(*dst)->dev, - &fl6->daddr, - sk ? inet6_sk(sk)->srcprefs : 0, - &fl6->saddr); + struct rt6_info *rt = (struct rt6_info *) *dst; + err = ip6_route_get_saddr(net, rt, &fl6->daddr, + sk ? inet6_sk(sk)->srcprefs : 0, + &fl6->saddr); if (err) goto out_err_release; } diff --git a/net/ipv6/route.c b/net/ipv6/route.c index 843406f..af26cc10 100644 --- a/net/ipv6/route.c +++ b/net/ipv6/route.c @@ -1325,6 +1325,16 @@ int ip6_route_add(struct fib6_config *cfg) if (dev == NULL) goto out; + if (!ipv6_addr_any(&cfg->fc_prefsrc)) { + if (!ipv6_chk_addr(net, &cfg->fc_prefsrc, dev, 0)) { + err = -EINVAL; + goto out; + } + ipv6_addr_copy(&rt->rt6i_prefsrc.addr, &cfg->fc_prefsrc); + rt->rt6i_prefsrc.plen = 128; + } else + rt->rt6i_prefsrc.plen = 0; + if (cfg->fc_flags & (RTF_GATEWAY | RTF_NONEXTHOP)) { rt->rt6i_nexthop = __neigh_lookup_errno(&nd_tbl, &rt->rt6i_gateway, dev); if (IS_ERR(rt->rt6i_nexthop)) { @@ -2037,6 +2047,55 @@ struct rt6_info *addrconf_dst_alloc(struct inet6_dev *idev, return rt; } +int ip6_route_get_saddr(struct net *net, + struct rt6_info *rt, + struct in6_addr *daddr, + unsigned int prefs, + struct in6_addr *saddr) +{ + struct inet6_dev *idev = ip6_dst_idev((struct dst_entry*)rt); + int err = 0; + if (rt->rt6i_prefsrc.plen) + ipv6_addr_copy(saddr, &rt->rt6i_prefsrc.addr); + else + err = ipv6_dev_get_saddr(net, idev ? idev->dev : NULL, + daddr, prefs, saddr); + return err; +} + +/* remove deleted ip from prefsrc entries */ +struct arg_dev_net_ip { + struct net_device *dev; + struct net *net; + struct in6_addr *addr; +}; + +static int fib6_remove_prefsrc(struct rt6_info *rt, void *arg) +{ + struct net_device *dev = ((struct arg_dev_net_ip *)arg)->dev; + struct net *net = ((struct arg_dev_net_ip *)arg)->net; + struct in6_addr *addr = ((struct arg_dev_net_ip *)arg)->addr; + + if (((void *)rt->rt6i_dev == dev || dev == NULL) && + rt != net->ipv6.ip6_null_entry && + ipv6_addr_equal(addr, &rt->rt6i_prefsrc.addr)) { + /* remove prefsrc entry */ + rt->rt6i_prefsrc.plen = 0; + } + return 0; +} + +void rt6_remove_prefsrc(struct inet6_ifaddr *ifp) +{ + struct net *net = dev_net(ifp->idev->dev); + struct arg_dev_net_ip adni = { + .dev = ifp->idev->dev, + .net = net, + .addr = &ifp->addr, + }; + fib6_clean_all(net, fib6_remove_prefsrc, 0, &adni); +} + struct arg_dev_net { struct net_device *dev; struct net *net; @@ -2183,6 +2242,9 @@ static int rtm_to_fib6_config(struct sk_buff *skb, struct nlmsghdr *nlh, nla_memcpy(&cfg->fc_src, tb[RTA_SRC], plen); } + if (tb[RTA_PREFSRC]) + nla_memcpy(&cfg->fc_prefsrc, tb[RTA_PREFSRC], 16); + if (tb[RTA_OIF]) cfg->fc_ifindex = nla_get_u32(tb[RTA_OIF]); @@ -2325,13 +2387,17 @@ static int rt6_fill_node(struct net *net, #endif NLA_PUT_U32(skb, RTA_IIF, iif); } else if (dst) { - struct inet6_dev *idev = ip6_dst_idev(&rt->dst); struct in6_addr saddr_buf; - if (ipv6_dev_get_saddr(net, idev ? idev->dev : NULL, - dst, 0, &saddr_buf) == 0) + if (ip6_route_get_saddr(net, rt, dst, 0, &saddr_buf) == 0) NLA_PUT(skb, RTA_PREFSRC, 16, &saddr_buf); } + if (rt->rt6i_prefsrc.plen) { + struct in6_addr saddr_buf; + ipv6_addr_copy(&saddr_buf, &rt->rt6i_prefsrc.addr); + NLA_PUT(skb, RTA_PREFSRC, 16, &saddr_buf); + } + if (rtnetlink_put_metrics(skb, dst_metrics_ptr(&rt->dst)) < 0) goto nla_put_failure; -- cgit v0.10.2 From 911cb193f3eb0370f20fbba712211e55ffede4de Mon Sep 17 00:00:00 2001 From: Rob Landley Date: Fri, 15 Apr 2011 02:26:25 +0000 Subject: net: minor cleanup to net_namespace.c. Inline a small static function that's only ever called from one place. Signed-off-by: Rob Landley Reviewed-by: Jiri Pirko Signed-off-by: David S. Miller diff --git a/net/core/net_namespace.c b/net/core/net_namespace.c index 3f86026..1abb5084 100644 --- a/net/core/net_namespace.c +++ b/net/core/net_namespace.c @@ -216,11 +216,14 @@ static void net_free(struct net *net) kmem_cache_free(net_cachep, net); } -static struct net *net_create(void) +struct net *copy_net_ns(unsigned long flags, struct net *old_net) { struct net *net; int rv; + if (!(flags & CLONE_NEWNET)) + return get_net(old_net); + net = net_alloc(); if (!net) return ERR_PTR(-ENOMEM); @@ -239,13 +242,6 @@ static struct net *net_create(void) return net; } -struct net *copy_net_ns(unsigned long flags, struct net *old_net) -{ - if (!(flags & CLONE_NEWNET)) - return get_net(old_net); - return net_create(); -} - static DEFINE_SPINLOCK(cleanup_list_lock); static LIST_HEAD(cleanup_list); /* Must hold cleanup_list_lock to touch */ -- cgit v0.10.2 From 6de240b7f714d63ca2a53d52c7eefb37e7eb3f1b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Miros=C5=82aw?= Date: Fri, 15 Apr 2011 04:50:49 +0000 Subject: net: spider_net: convert to hw_features MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: MichaÅ‚ MirosÅ‚aw Signed-off-by: David S. Miller diff --git a/drivers/net/spider_net.c b/drivers/net/spider_net.c index cb6bcca..949f124 100644 --- a/drivers/net/spider_net.c +++ b/drivers/net/spider_net.c @@ -994,15 +994,13 @@ spider_net_pass_skb_up(struct spider_net_descr *descr, skb->protocol = eth_type_trans(skb, netdev); /* checksum offload */ - if (card->options.rx_csum) { + skb_checksum_none_assert(skb); + if (netdev->features & NETIF_F_RXCSUM) { if ( ( (data_status & SPIDER_NET_DATA_STATUS_CKSUM_MASK) == SPIDER_NET_DATA_STATUS_CKSUM_MASK) && !(data_error & SPIDER_NET_DATA_ERR_CKSUM_MASK)) skb->ip_summed = CHECKSUM_UNNECESSARY; - else - skb_checksum_none_assert(skb); - } else - skb_checksum_none_assert(skb); + } if (data_status & SPIDER_NET_VLAN_PACKET) { /* further enhancements: HW-accel VLAN @@ -2322,14 +2320,15 @@ spider_net_setup_netdev(struct spider_net_card *card) card->aneg_timer.function = spider_net_link_phy; card->aneg_timer.data = (unsigned long) card; - card->options.rx_csum = SPIDER_NET_RX_CSUM_DEFAULT; - netif_napi_add(netdev, &card->napi, spider_net_poll, SPIDER_NET_NAPI_WEIGHT); spider_net_setup_netdev_ops(netdev); - netdev->features = NETIF_F_IP_CSUM | NETIF_F_LLTX; + netdev->hw_features = NETIF_F_RXCSUM | NETIF_F_IP_CSUM; + if (SPIDER_NET_RX_CSUM_DEFAULT) + netdev->features |= NETIF_F_RXCSUM; + netdev->features |= NETIF_F_IP_CSUM | NETIF_F_LLTX; /* some time: NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX | * NETIF_F_HW_VLAN_FILTER */ diff --git a/drivers/net/spider_net.h b/drivers/net/spider_net.h index 05f74cb..020f64a 100644 --- a/drivers/net/spider_net.h +++ b/drivers/net/spider_net.h @@ -429,12 +429,6 @@ struct spider_net_descr_chain { * 701b8000 would be correct, but every packets gets that flag */ #define SPIDER_NET_DESTROY_RX_FLAGS 0x700b8000 -/* this will be bigger some time */ -struct spider_net_options { - int rx_csum; /* for rx: if 0 ip_summed=NONE, - if 1 and hw has verified, ip_summed=UNNECESSARY */ -}; - #define SPIDER_NET_DEFAULT_MSG ( NETIF_MSG_DRV | \ NETIF_MSG_PROBE | \ NETIF_MSG_LINK | \ @@ -487,7 +481,6 @@ struct spider_net_card { /* for ethtool */ int msg_enable; struct spider_net_extra_stats spider_stats; - struct spider_net_options options; /* Must be last item in struct */ struct spider_net_descr darray[0]; diff --git a/drivers/net/spider_net_ethtool.c b/drivers/net/spider_net_ethtool.c index 5bae728..d723fca 100644 --- a/drivers/net/spider_net_ethtool.c +++ b/drivers/net/spider_net_ethtool.c @@ -115,24 +115,6 @@ spider_net_ethtool_nway_reset(struct net_device *netdev) return 0; } -static u32 -spider_net_ethtool_get_rx_csum(struct net_device *netdev) -{ - struct spider_net_card *card = netdev_priv(netdev); - - return card->options.rx_csum; -} - -static int -spider_net_ethtool_set_rx_csum(struct net_device *netdev, u32 n) -{ - struct spider_net_card *card = netdev_priv(netdev); - - card->options.rx_csum = n; - return 0; -} - - static void spider_net_ethtool_get_ringparam(struct net_device *netdev, struct ethtool_ringparam *ering) @@ -189,9 +171,6 @@ const struct ethtool_ops spider_net_ethtool_ops = { .set_msglevel = spider_net_ethtool_set_msglevel, .get_link = ethtool_op_get_link, .nway_reset = spider_net_ethtool_nway_reset, - .get_rx_csum = spider_net_ethtool_get_rx_csum, - .set_rx_csum = spider_net_ethtool_set_rx_csum, - .set_tx_csum = ethtool_op_set_tx_csum, .get_ringparam = spider_net_ethtool_get_ringparam, .get_strings = spider_net_get_strings, .get_sset_count = spider_net_get_sset_count, -- cgit v0.10.2 From c88fcb3d8265cf473c73bc147a2aa21ae03abf67 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Miros=C5=82aw?= Date: Fri, 15 Apr 2011 04:50:49 +0000 Subject: net: dm9000: convert to hw_features MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: MichaÅ‚ MirosÅ‚aw Signed-off-by: David S. Miller diff --git a/drivers/net/dm9000.c b/drivers/net/dm9000.c index b7af5ba..f7bdebb 100644 --- a/drivers/net/dm9000.c +++ b/drivers/net/dm9000.c @@ -131,8 +131,6 @@ typedef struct board_info { u32 msg_enable; u32 wake_state; - int rx_csum; - int can_csum; int ip_summed; } board_info_t; @@ -470,47 +468,20 @@ static int dm9000_nway_reset(struct net_device *dev) return mii_nway_restart(&dm->mii); } -static uint32_t dm9000_get_rx_csum(struct net_device *dev) +static int dm9000_set_features(struct net_device *dev, u32 features) { board_info_t *dm = to_dm9000_board(dev); - return dm->rx_csum; -} - -static int dm9000_set_rx_csum_unlocked(struct net_device *dev, uint32_t data) -{ - board_info_t *dm = to_dm9000_board(dev); - - if (dm->can_csum) { - dm->rx_csum = data; - iow(dm, DM9000_RCSR, dm->rx_csum ? RCSR_CSUM : 0); + u32 changed = dev->features ^ features; + unsigned long flags; + if (!(changed & NETIF_F_RXCSUM)) return 0; - } - - return -EOPNOTSUPP; -} - -static int dm9000_set_rx_csum(struct net_device *dev, uint32_t data) -{ - board_info_t *dm = to_dm9000_board(dev); - unsigned long flags; - int ret; spin_lock_irqsave(&dm->lock, flags); - ret = dm9000_set_rx_csum_unlocked(dev, data); + iow(dm, DM9000_RCSR, (features & NETIF_F_RXCSUM) ? RCSR_CSUM : 0); spin_unlock_irqrestore(&dm->lock, flags); - return ret; -} - -static int dm9000_set_tx_csum(struct net_device *dev, uint32_t data) -{ - board_info_t *dm = to_dm9000_board(dev); - int ret = -EOPNOTSUPP; - - if (dm->can_csum) - ret = ethtool_op_set_tx_csum(dev, data); - return ret; + return 0; } static u32 dm9000_get_link(struct net_device *dev) @@ -643,10 +614,6 @@ static const struct ethtool_ops dm9000_ethtool_ops = { .get_eeprom_len = dm9000_get_eeprom_len, .get_eeprom = dm9000_get_eeprom, .set_eeprom = dm9000_set_eeprom, - .get_rx_csum = dm9000_get_rx_csum, - .set_rx_csum = dm9000_set_rx_csum, - .get_tx_csum = ethtool_op_get_tx_csum, - .set_tx_csum = dm9000_set_tx_csum, }; static void dm9000_show_carrier(board_info_t *db, @@ -800,7 +767,9 @@ dm9000_init_dm9000(struct net_device *dev) db->io_mode = ior(db, DM9000_ISR) >> 6; /* ISR bit7:6 keeps I/O mode */ /* Checksum mode */ - dm9000_set_rx_csum_unlocked(dev, db->rx_csum); + if (dev->hw_features & NETIF_F_RXCSUM) + iow(dm, DM9000_RCSR, + (dev->features & NETIF_F_RXCSUM) ? RCSR_CSUM : 0); iow(db, DM9000_GPCR, GPCR_GEP_CNTL); /* Let GPIO0 output */ @@ -1049,7 +1018,7 @@ dm9000_rx(struct net_device *dev) /* Pass to upper layer */ skb->protocol = eth_type_trans(skb, dev); - if (db->rx_csum) { + if (dev->features & NETIF_F_RXCSUM) { if ((((rxbyte & 0x1c) << 3) & rxbyte) == 0) skb->ip_summed = CHECKSUM_UNNECESSARY; else @@ -1358,6 +1327,7 @@ static const struct net_device_ops dm9000_netdev_ops = { .ndo_set_multicast_list = dm9000_hash_table, .ndo_do_ioctl = dm9000_ioctl, .ndo_change_mtu = eth_change_mtu, + .ndo_set_features = dm9000_set_features, .ndo_validate_addr = eth_validate_addr, .ndo_set_mac_address = eth_mac_addr, #ifdef CONFIG_NET_POLL_CONTROLLER @@ -1551,9 +1521,8 @@ dm9000_probe(struct platform_device *pdev) /* dm9000a/b are capable of hardware checksum offload */ if (db->type == TYPE_DM9000A || db->type == TYPE_DM9000B) { - db->can_csum = 1; - db->rx_csum = 1; - ndev->features |= NETIF_F_IP_CSUM; + ndev->hw_features = NETIF_F_RXCSUM | NETIF_F_IP_CSUM; + ndev->features |= ndev->hw_features; } /* from this point we assume that we have found a DM9000 */ -- cgit v0.10.2 From 569e146396cb3b378d2957b94671bf30cd777c67 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Miros=C5=82aw?= Date: Fri, 15 Apr 2011 04:50:49 +0000 Subject: net: forcedeth: convert to hw_features MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This also fixes a race around np->txrxctl_bits while changing RXCSUM offload. Signed-off-by: MichaÅ‚ MirosÅ‚aw Signed-off-by: David S. Miller diff --git a/drivers/net/forcedeth.c b/drivers/net/forcedeth.c index d5ab4da..ec9a32d 100644 --- a/drivers/net/forcedeth.c +++ b/drivers/net/forcedeth.c @@ -774,7 +774,6 @@ struct fe_priv { u32 driver_data; u32 device_id; u32 register_size; - int rx_csum; u32 mac_in_use; int mgmt_version; int mgmt_sema; @@ -4480,58 +4479,36 @@ static int nv_set_pauseparam(struct net_device *dev, struct ethtool_pauseparam* return 0; } -static u32 nv_get_rx_csum(struct net_device *dev) +static u32 nv_fix_features(struct net_device *dev, u32 features) { - struct fe_priv *np = netdev_priv(dev); - return np->rx_csum != 0; + /* vlan is dependent on rx checksum offload */ + if (features & (NETIF_F_HW_VLAN_TX|NETIF_F_HW_VLAN_RX)) + features |= NETIF_F_RXCSUM; + + return features; } -static int nv_set_rx_csum(struct net_device *dev, u32 data) +static int nv_set_features(struct net_device *dev, u32 features) { struct fe_priv *np = netdev_priv(dev); u8 __iomem *base = get_hwbase(dev); - int retcode = 0; + u32 changed = dev->features ^ features; - if (np->driver_data & DEV_HAS_CHECKSUM) { - if (data) { - np->rx_csum = 1; - np->txrxctl_bits |= NVREG_TXRXCTL_RXCHECK; - } else { - np->rx_csum = 0; - /* vlan is dependent on rx checksum offload */ - if (!(np->vlanctl_bits & NVREG_VLANCONTROL_ENABLE)) - np->txrxctl_bits &= ~NVREG_TXRXCTL_RXCHECK; - } - if (netif_running(dev)) { - spin_lock_irq(&np->lock); - writel(np->txrxctl_bits, base + NvRegTxRxControl); - spin_unlock_irq(&np->lock); - } - } else { - return -EINVAL; - } - - return retcode; -} + if (changed & NETIF_F_RXCSUM) { + spin_lock_irq(&np->lock); -static int nv_set_tx_csum(struct net_device *dev, u32 data) -{ - struct fe_priv *np = netdev_priv(dev); + if (features & NETIF_F_RXCSUM) + np->txrxctl_bits |= NVREG_TXRXCTL_RXCHECK; + else + np->txrxctl_bits &= ~NVREG_TXRXCTL_RXCHECK; - if (np->driver_data & DEV_HAS_CHECKSUM) - return ethtool_op_set_tx_csum(dev, data); - else - return -EOPNOTSUPP; -} + if (netif_running(dev)) + writel(np->txrxctl_bits, base + NvRegTxRxControl); -static int nv_set_sg(struct net_device *dev, u32 data) -{ - struct fe_priv *np = netdev_priv(dev); + spin_unlock_irq(&np->lock); + } - if (np->driver_data & DEV_HAS_CHECKSUM) - return ethtool_op_set_sg(dev, data); - else - return -EOPNOTSUPP; + return 0; } static int nv_get_sset_count(struct net_device *dev, int sset) @@ -4896,15 +4873,10 @@ static const struct ethtool_ops ops = { .get_regs_len = nv_get_regs_len, .get_regs = nv_get_regs, .nway_reset = nv_nway_reset, - .set_tso = nv_set_tso, .get_ringparam = nv_get_ringparam, .set_ringparam = nv_set_ringparam, .get_pauseparam = nv_get_pauseparam, .set_pauseparam = nv_set_pauseparam, - .get_rx_csum = nv_get_rx_csum, - .set_rx_csum = nv_set_rx_csum, - .set_tx_csum = nv_set_tx_csum, - .set_sg = nv_set_sg, .get_strings = nv_get_strings, .get_ethtool_stats = nv_get_ethtool_stats, .get_sset_count = nv_get_sset_count, @@ -5235,6 +5207,8 @@ static const struct net_device_ops nv_netdev_ops = { .ndo_start_xmit = nv_start_xmit, .ndo_tx_timeout = nv_tx_timeout, .ndo_change_mtu = nv_change_mtu, + .ndo_fix_features = nv_fix_features, + .ndo_set_features = nv_set_features, .ndo_validate_addr = eth_validate_addr, .ndo_set_mac_address = nv_set_mac_address, .ndo_set_multicast_list = nv_set_multicast, @@ -5251,6 +5225,8 @@ static const struct net_device_ops nv_netdev_ops_optimized = { .ndo_start_xmit = nv_start_xmit_optimized, .ndo_tx_timeout = nv_tx_timeout, .ndo_change_mtu = nv_change_mtu, + .ndo_fix_features = nv_fix_features, + .ndo_set_features = nv_set_features, .ndo_validate_addr = eth_validate_addr, .ndo_set_mac_address = nv_set_mac_address, .ndo_set_multicast_list = nv_set_multicast, @@ -5364,11 +5340,10 @@ static int __devinit nv_probe(struct pci_dev *pci_dev, const struct pci_device_i np->pkt_limit = NV_PKTLIMIT_2; if (id->driver_data & DEV_HAS_CHECKSUM) { - np->rx_csum = 1; np->txrxctl_bits |= NVREG_TXRXCTL_RXCHECK; - dev->features |= NETIF_F_IP_CSUM | NETIF_F_SG; - dev->features |= NETIF_F_TSO; - dev->features |= NETIF_F_GRO; + dev->hw_features |= NETIF_F_IP_CSUM | NETIF_F_SG | + NETIF_F_TSO | NETIF_F_RXCSUM; + dev->features |= dev->hw_features; } np->vlanctl_bits = 0; @@ -5384,7 +5359,6 @@ static int __devinit nv_probe(struct pci_dev *pci_dev, const struct pci_device_i np->pause_flags |= NV_PAUSEFRAME_TX_CAPABLE | NV_PAUSEFRAME_TX_REQ; } - err = -ENOMEM; np->base = ioremap(addr, np->register_size); if (!np->base) -- cgit v0.10.2 From c8c64cff2c88b17fdd7402dd06288d7415896430 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Miros=C5=82aw?= Date: Fri, 15 Apr 2011 04:50:49 +0000 Subject: net: mlx4: convert to hw_features MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: MichaÅ‚ MirosÅ‚aw Signed-off-by: David S. Miller diff --git a/drivers/net/mlx4/en_ethtool.c b/drivers/net/mlx4/en_ethtool.c index d54b7ab..da1b64d 100644 --- a/drivers/net/mlx4/en_ethtool.c +++ b/drivers/net/mlx4/en_ethtool.c @@ -57,37 +57,6 @@ mlx4_en_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *drvinfo) drvinfo->eedump_len = 0; } -static u32 mlx4_en_get_tso(struct net_device *dev) -{ - return (dev->features & NETIF_F_TSO) != 0; -} - -static int mlx4_en_set_tso(struct net_device *dev, u32 data) -{ - struct mlx4_en_priv *priv = netdev_priv(dev); - - if (data) { - if (!priv->mdev->LSO_support) - return -EPERM; - dev->features |= (NETIF_F_TSO | NETIF_F_TSO6); - } else - dev->features &= ~(NETIF_F_TSO | NETIF_F_TSO6); - return 0; -} - -static u32 mlx4_en_get_rx_csum(struct net_device *dev) -{ - struct mlx4_en_priv *priv = netdev_priv(dev); - return priv->rx_csum; -} - -static int mlx4_en_set_rx_csum(struct net_device *dev, u32 data) -{ - struct mlx4_en_priv *priv = netdev_priv(dev); - priv->rx_csum = (data != 0); - return 0; -} - static const char main_strings[][ETH_GSTRING_LEN] = { "rx_packets", "tx_packets", "rx_bytes", "tx_bytes", "rx_errors", "tx_errors", "rx_dropped", "tx_dropped", "multicast", "collisions", @@ -483,17 +452,7 @@ const struct ethtool_ops mlx4_en_ethtool_ops = { .get_drvinfo = mlx4_en_get_drvinfo, .get_settings = mlx4_en_get_settings, .set_settings = mlx4_en_set_settings, -#ifdef NETIF_F_TSO - .get_tso = mlx4_en_get_tso, - .set_tso = mlx4_en_set_tso, -#endif - .get_sg = ethtool_op_get_sg, - .set_sg = ethtool_op_set_sg, .get_link = ethtool_op_get_link, - .get_rx_csum = mlx4_en_get_rx_csum, - .set_rx_csum = mlx4_en_set_rx_csum, - .get_tx_csum = ethtool_op_get_tx_csum, - .set_tx_csum = ethtool_op_set_tx_ipv6_csum, .get_strings = mlx4_en_get_strings, .get_sset_count = mlx4_en_get_sset_count, .get_ethtool_stats = mlx4_en_get_ethtool_stats, @@ -508,7 +467,6 @@ const struct ethtool_ops mlx4_en_ethtool_ops = { .set_pauseparam = mlx4_en_set_pauseparam, .get_ringparam = mlx4_en_get_ringparam, .set_ringparam = mlx4_en_set_ringparam, - .get_flags = ethtool_op_get_flags, }; diff --git a/drivers/net/mlx4/en_netdev.c b/drivers/net/mlx4/en_netdev.c index 77063f9..61850ad 100644 --- a/drivers/net/mlx4/en_netdev.c +++ b/drivers/net/mlx4/en_netdev.c @@ -1083,7 +1083,6 @@ int mlx4_en_init_netdev(struct mlx4_en_dev *mdev, int port, priv->prof = prof; priv->port = port; priv->port_up = false; - priv->rx_csum = 1; priv->flags = prof->flags; priv->tx_ring_num = prof->tx_ring_num; priv->rx_ring_num = prof->rx_ring_num; @@ -1141,21 +1140,16 @@ int mlx4_en_init_netdev(struct mlx4_en_dev *mdev, int port, /* * Set driver features */ - dev->features |= NETIF_F_SG; - dev->vlan_features |= NETIF_F_SG; - dev->features |= NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM; - dev->vlan_features |= NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM; - dev->features |= NETIF_F_HIGHDMA; - dev->features |= NETIF_F_HW_VLAN_TX | - NETIF_F_HW_VLAN_RX | - NETIF_F_HW_VLAN_FILTER; - dev->features |= NETIF_F_GRO; - if (mdev->LSO_support) { - dev->features |= NETIF_F_TSO; - dev->features |= NETIF_F_TSO6; - dev->vlan_features |= NETIF_F_TSO; - dev->vlan_features |= NETIF_F_TSO6; - } + dev->hw_features = NETIF_F_SG | NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM; + if (mdev->LSO_support) + dev->hw_features |= NETIF_F_TSO | NETIF_F_TSO6; + + dev->vlan_features = dev->hw_features; + + dev->hw_features |= NETIF_F_RXCSUM; + dev->features = dev->hw_features | NETIF_F_HIGHDMA | + NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX | + NETIF_F_HW_VLAN_FILTER; mdev->pndev[port] = dev; diff --git a/drivers/net/mlx4/en_rx.c b/drivers/net/mlx4/en_rx.c index 62dd21b..277215f 100644 --- a/drivers/net/mlx4/en_rx.c +++ b/drivers/net/mlx4/en_rx.c @@ -584,7 +584,7 @@ int mlx4_en_process_rx_cq(struct net_device *dev, struct mlx4_en_cq *cq, int bud ring->bytes += length; ring->packets++; - if (likely(priv->rx_csum)) { + if (likely(dev->features & NETIF_F_RXCSUM)) { if ((cqe->status & cpu_to_be16(MLX4_CQE_STATUS_IPOK)) && (cqe->checksum == cpu_to_be16(0xffff))) { priv->port_stats.rx_chksum_good++; diff --git a/drivers/net/mlx4/mlx4_en.h b/drivers/net/mlx4/mlx4_en.h index e30f609..0b5150d 100644 --- a/drivers/net/mlx4/mlx4_en.h +++ b/drivers/net/mlx4/mlx4_en.h @@ -451,7 +451,6 @@ struct mlx4_en_priv { int registered; int allocated; int stride; - int rx_csum; u64 mac; int mac_index; unsigned max_mtu; -- cgit v0.10.2 From 8b3afe95e363dbd32bd9ddc6c2d562944f5350c5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Miros=C5=82aw?= Date: Fri, 15 Apr 2011 04:50:50 +0000 Subject: net: gianfar: convert to hw_features MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Note: I bet that gfar_set_features() don't really need a full reset. Signed-off-by: MichaÅ‚ MirosÅ‚aw Signed-off-by: David S. Miller diff --git a/drivers/net/gianfar.c b/drivers/net/gianfar.c index 2a0ad9a..ff60b23 100644 --- a/drivers/net/gianfar.c +++ b/drivers/net/gianfar.c @@ -365,7 +365,7 @@ static void gfar_init_mac(struct net_device *ndev) gfar_write(®s->rir0, DEFAULT_RIR0); } - if (priv->rx_csum_enable) + if (ndev->features & NETIF_F_RXCSUM) rctrl |= RCTRL_CHECKSUMMING; if (priv->extended_hash) { @@ -463,6 +463,7 @@ static const struct net_device_ops gfar_netdev_ops = { .ndo_start_xmit = gfar_start_xmit, .ndo_stop = gfar_close, .ndo_change_mtu = gfar_change_mtu, + .ndo_set_features = gfar_set_features, .ndo_set_multicast_list = gfar_set_multi, .ndo_tx_timeout = gfar_timeout, .ndo_do_ioctl = gfar_ioctl, @@ -513,7 +514,7 @@ void unlock_tx_qs(struct gfar_private *priv) /* Returns 1 if incoming frames use an FCB */ static inline int gfar_uses_fcb(struct gfar_private *priv) { - return priv->vlgrp || priv->rx_csum_enable || + return priv->vlgrp || (priv->ndev->features & NETIF_F_RXCSUM) || (priv->device_flags & FSL_GIANFAR_DEV_HAS_TIMER); } @@ -1030,10 +1031,11 @@ static int gfar_probe(struct platform_device *ofdev) netif_napi_add(dev, &priv->gfargrp[i].napi, gfar_poll, GFAR_DEV_WEIGHT); if (priv->device_flags & FSL_GIANFAR_DEV_HAS_CSUM) { - priv->rx_csum_enable = 1; - dev->features |= NETIF_F_IP_CSUM | NETIF_F_SG | NETIF_F_HIGHDMA; - } else - priv->rx_csum_enable = 0; + dev->hw_features = NETIF_F_IP_CSUM | NETIF_F_SG | + NETIF_F_RXCSUM; + dev->features |= NETIF_F_IP_CSUM | NETIF_F_SG | + NETIF_F_RXCSUM | NETIF_F_HIGHDMA; + } priv->vlgrp = NULL; @@ -2697,7 +2699,7 @@ static int gfar_process_frame(struct net_device *dev, struct sk_buff *skb, if (priv->padding) skb_pull(skb, priv->padding); - if (priv->rx_csum_enable) + if (dev->features & NETIF_F_RXCSUM) gfar_rx_checksum(skb, fcb); /* Tell the skb what kind of packet this is */ diff --git a/drivers/net/gianfar.h b/drivers/net/gianfar.h index 0438d35..fc86f51 100644 --- a/drivers/net/gianfar.h +++ b/drivers/net/gianfar.h @@ -1083,7 +1083,7 @@ struct gfar_private { struct device_node *phy_node; struct device_node *tbi_node; u32 device_flags; - unsigned char rx_csum_enable:1, + unsigned char extended_hash:1, bd_stash_en:1, rx_filer_enable:1, @@ -1153,6 +1153,7 @@ extern void gfar_phy_test(struct mii_bus *bus, struct phy_device *phydev, extern void gfar_configure_coalescing(struct gfar_private *priv, unsigned long tx_mask, unsigned long rx_mask); void gfar_init_sysfs(struct net_device *dev); +int gfar_set_features(struct net_device *dev, u32 features); extern const struct ethtool_ops gfar_ethtool_ops; diff --git a/drivers/net/gianfar_ethtool.c b/drivers/net/gianfar_ethtool.c index 0840590..493d743 100644 --- a/drivers/net/gianfar_ethtool.c +++ b/drivers/net/gianfar_ethtool.c @@ -517,15 +517,15 @@ static int gfar_sringparam(struct net_device *dev, struct ethtool_ringparam *rva return err; } -static int gfar_set_rx_csum(struct net_device *dev, uint32_t data) +int gfar_set_features(struct net_device *dev, u32 features) { struct gfar_private *priv = netdev_priv(dev); unsigned long flags; int err = 0, i = 0; + u32 changed = dev->features ^ features; - if (!(priv->device_flags & FSL_GIANFAR_DEV_HAS_CSUM)) - return -EOPNOTSUPP; - + if (!(changed & NETIF_F_RXCSUM)) + return 0; if (dev->flags & IFF_UP) { /* Halt TX and RX, and process the frames which @@ -546,58 +546,15 @@ static int gfar_set_rx_csum(struct net_device *dev, uint32_t data) /* Now we take down the rings to rebuild them */ stop_gfar(dev); - } - spin_lock_irqsave(&priv->bflock, flags); - priv->rx_csum_enable = data; - spin_unlock_irqrestore(&priv->bflock, flags); + dev->features = features; - if (dev->flags & IFF_UP) { err = startup_gfar(dev); netif_tx_wake_all_queues(dev); } return err; } -static uint32_t gfar_get_rx_csum(struct net_device *dev) -{ - struct gfar_private *priv = netdev_priv(dev); - - if (!(priv->device_flags & FSL_GIANFAR_DEV_HAS_CSUM)) - return 0; - - return priv->rx_csum_enable; -} - -static int gfar_set_tx_csum(struct net_device *dev, uint32_t data) -{ - struct gfar_private *priv = netdev_priv(dev); - - if (!(priv->device_flags & FSL_GIANFAR_DEV_HAS_CSUM)) - return -EOPNOTSUPP; - - netif_tx_lock_bh(dev); - - if (data) - dev->features |= NETIF_F_IP_CSUM; - else - dev->features &= ~NETIF_F_IP_CSUM; - - netif_tx_unlock_bh(dev); - - return 0; -} - -static uint32_t gfar_get_tx_csum(struct net_device *dev) -{ - struct gfar_private *priv = netdev_priv(dev); - - if (!(priv->device_flags & FSL_GIANFAR_DEV_HAS_CSUM)) - return 0; - - return (dev->features & NETIF_F_IP_CSUM) != 0; -} - static uint32_t gfar_get_msglevel(struct net_device *dev) { struct gfar_private *priv = netdev_priv(dev); @@ -844,11 +801,6 @@ const struct ethtool_ops gfar_ethtool_ops = { .get_strings = gfar_gstrings, .get_sset_count = gfar_sset_count, .get_ethtool_stats = gfar_fill_stats, - .get_rx_csum = gfar_get_rx_csum, - .get_tx_csum = gfar_get_tx_csum, - .set_rx_csum = gfar_set_rx_csum, - .set_tx_csum = gfar_set_tx_csum, - .set_sg = ethtool_op_set_sg, .get_msglevel = gfar_get_msglevel, .set_msglevel = gfar_set_msglevel, #ifdef CONFIG_PM -- cgit v0.10.2 From 0d399205edf3a4c290e76ebb36e541593af4a1b4 Mon Sep 17 00:00:00 2001 From: Chris Mason Date: Sat, 16 Apr 2011 06:55:39 -0400 Subject: Btrfs end_bio_extent_readpage should look for locked bits A recent commit caches the extent state in end_bio_extent_readpage, but the search it does should look for locked extents. This fixes things to make it more effective. Signed-off-by: Chris Mason diff --git a/fs/btrfs/extent_io.c b/fs/btrfs/extent_io.c index 1c462f89..5ae0bff 100644 --- a/fs/btrfs/extent_io.c +++ b/fs/btrfs/extent_io.c @@ -1761,7 +1761,7 @@ static void end_bio_extent_readpage(struct bio *bio, int err) prefetchw(&bvec->bv_page->flags); spin_lock(&tree->lock); - state = find_first_extent_bit_state(tree, start, 0); + state = find_first_extent_bit_state(tree, start, EXTENT_LOCKED); if (state && state->start == start) { /* * take a reference on the state, unlock will drop -- cgit v0.10.2 From 6d74119f1a3efad9dc7f79a16c201242324b731f Mon Sep 17 00:00:00 2001 From: Josef Bacik Date: Mon, 11 Apr 2011 20:20:11 -0400 Subject: Btrfs: avoid taking the chunk_mutex in do_chunk_alloc Everytime we try to allocate disk space we try and see if we can pre-emptively allocate a chunk, but in the common case we don't allocate anything, so there is no sense in taking the chunk_mutex at all. So instead if we are allocating a chunk, mark it in the space_info so we don't get two people trying to allocate at the same time. Thanks, Signed-off-by: Josef Bacik Reviewed-by: Liu Bo diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h index 0d00a07..2e61fe1 100644 --- a/fs/btrfs/ctree.h +++ b/fs/btrfs/ctree.h @@ -740,8 +740,10 @@ struct btrfs_space_info { */ unsigned long reservation_progress; - int full; /* indicates that we cannot allocate any more + int full:1; /* indicates that we cannot allocate any more chunks for this space */ + int chunk_alloc:1; /* set if we are allocating a chunk */ + int force_alloc; /* set if we need to force a chunk alloc for this space */ diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c index 2647948..31f33ba 100644 --- a/fs/btrfs/extent-tree.c +++ b/fs/btrfs/extent-tree.c @@ -3039,6 +3039,7 @@ static int update_space_info(struct btrfs_fs_info *info, u64 flags, found->bytes_may_use = 0; found->full = 0; found->force_alloc = CHUNK_ALLOC_NO_FORCE; + found->chunk_alloc = 0; *space_info = found; list_add_rcu(&found->list, &info->space_info); atomic_set(&found->caching_threads, 0); @@ -3318,10 +3319,9 @@ static int do_chunk_alloc(struct btrfs_trans_handle *trans, { struct btrfs_space_info *space_info; struct btrfs_fs_info *fs_info = extent_root->fs_info; + int wait_for_alloc = 0; int ret = 0; - mutex_lock(&fs_info->chunk_mutex); - flags = btrfs_reduce_alloc_profile(extent_root, flags); space_info = __find_space_info(extent_root->fs_info, flags); @@ -3332,21 +3332,40 @@ static int do_chunk_alloc(struct btrfs_trans_handle *trans, } BUG_ON(!space_info); +again: spin_lock(&space_info->lock); if (space_info->force_alloc) force = space_info->force_alloc; if (space_info->full) { spin_unlock(&space_info->lock); - goto out; + return 0; } if (!should_alloc_chunk(extent_root, space_info, alloc_bytes, force)) { spin_unlock(&space_info->lock); - goto out; + return 0; + } else if (space_info->chunk_alloc) { + wait_for_alloc = 1; + } else { + space_info->chunk_alloc = 1; } spin_unlock(&space_info->lock); + mutex_lock(&fs_info->chunk_mutex); + + /* + * The chunk_mutex is held throughout the entirety of a chunk + * allocation, so once we've acquired the chunk_mutex we know that the + * other guy is done and we need to recheck and see if we should + * allocate. + */ + if (wait_for_alloc) { + mutex_unlock(&fs_info->chunk_mutex); + wait_for_alloc = 0; + goto again; + } + /* * If we have mixed data/metadata chunks we want to make sure we keep * allocating mixed chunks instead of individual chunks. @@ -3372,9 +3391,10 @@ static int do_chunk_alloc(struct btrfs_trans_handle *trans, space_info->full = 1; else ret = 1; + space_info->force_alloc = CHUNK_ALLOC_NO_FORCE; + space_info->chunk_alloc = 0; spin_unlock(&space_info->lock); -out: mutex_unlock(&extent_root->fs_info->chunk_mutex); return ret; } -- cgit v0.10.2 From e9569c1511d2590a27b46b94bafb7acece034e5c Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Thu, 14 Apr 2011 12:11:42 +0100 Subject: ARM: 6881/1: cputype.h uses __attribute_const__ which requires including kernel.h Issue manifests as: In file included from arch/arm/mach-pxa/include/mach/hardware.h:62, from arch/arm/mach-pxa/include/mach/gpio.h:28, from /home/jic23/src/kernel/temp-remove/arch/arm/include/asm/gpio.h:5, from include/linux/gpio.h:7, from drivers/staging/iio/gyro/adis16080_core.c:8: /home/jic23/src/kernel/temp-remove/arch/arm/include/asm/cputype.h:57: error: expected '=', ',', ';', 'asm' or '__attribute__' before 'read_cpuid_id' ... Signed-off-by: Jonathan Cameron Signed-off-by: Russell King diff --git a/arch/arm/include/asm/cputype.h b/arch/arm/include/asm/cputype.h index ed5bc9e..cd4458f 100644 --- a/arch/arm/include/asm/cputype.h +++ b/arch/arm/include/asm/cputype.h @@ -2,6 +2,7 @@ #define __ASM_ARM_CPUTYPE_H #include +#include #define CPUID_ID 0 #define CPUID_CACHETYPE 1 -- cgit v0.10.2 From dd182574d86e22faaaed37db79e3d54e773f29f7 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Sun, 17 Apr 2011 00:03:38 -0700 Subject: atm: eni: Kill set-but-unused variables. The variable eni_dev is initialized but never subsequently used in these two functions. Signed-off-by: David S. Miller diff --git a/drivers/atm/eni.c b/drivers/atm/eni.c index c495fae..3230ea0 100644 --- a/drivers/atm/eni.c +++ b/drivers/atm/eni.c @@ -1469,10 +1469,7 @@ if (eni_boards) printk(KERN_INFO "loss: %ld\n",ENI_DEV(eni_boards)->lost); static void bug_int(struct atm_dev *dev,unsigned long reason) { - struct eni_dev *eni_dev; - DPRINTK(">bug_int\n"); - eni_dev = ENI_DEV(dev); if (reason & MID_DMA_ERR_ACK) printk(KERN_CRIT DEV_LABEL "(itf %d): driver error - DMA " "error\n",dev->number); @@ -1900,7 +1897,6 @@ static void eni_close(struct atm_vcc *vcc) static int eni_open(struct atm_vcc *vcc) { - struct eni_dev *eni_dev; struct eni_vcc *eni_vcc; int error; short vpi = vcc->vpi; @@ -1910,7 +1906,6 @@ static int eni_open(struct atm_vcc *vcc) EVENT("eni_open\n",0,0); if (!test_bit(ATM_VF_PARTIAL,&vcc->flags)) vcc->dev_data = NULL; - eni_dev = ENI_DEV(vcc->dev); if (vci != ATM_VPI_UNSPEC && vpi != ATM_VCI_UNSPEC) set_bit(ATM_VF_ADDR,&vcc->flags); if (vcc->qos.aal != ATM_AAL0 && vcc->qos.aal != ATM_AAL5) -- cgit v0.10.2 From e60c5e14fbfcaa54f430aad80b38763a403b2158 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Sun, 17 Apr 2011 00:07:55 -0700 Subject: atm: he: Fix undefined sequence points. GCC complains in these queue index operations because we perform operations of the form: x = some_operation(++x); which is undefined. Replace with: x = some_operation(x + 1); which is well defined and provides the intended operation. Signed-off-by: David S. Miller diff --git a/drivers/atm/he.c b/drivers/atm/he.c index 6cf59bf..9a51df4 100644 --- a/drivers/atm/he.c +++ b/drivers/atm/he.c @@ -1801,7 +1801,7 @@ return_host_buffers: next_rbrq_entry: he_dev->rbrq_head = (struct he_rbrq *) ((unsigned long) he_dev->rbrq_base | - RBRQ_MASK(++he_dev->rbrq_head)); + RBRQ_MASK(he_dev->rbrq_head + 1)); } read_unlock(&vcc_sklist_lock); @@ -1884,7 +1884,7 @@ next_tbrq_entry: pci_pool_free(he_dev->tpd_pool, tpd, TPD_ADDR(tpd->status)); he_dev->tbrq_head = (struct he_tbrq *) ((unsigned long) he_dev->tbrq_base | - TBRQ_MASK(++he_dev->tbrq_head)); + TBRQ_MASK(he_dev->tbrq_head + 1)); } if (updated) { -- cgit v0.10.2 From edb4dcb717d71f63c5147d7bef3014f96d192842 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Sun, 17 Apr 2011 00:10:17 -0700 Subject: atm: idt77252: Fix set-but-unused variables. Two cases here: 1) idt77252_rx_raw() really does not make any use of the extracted PTI field of the atm header. 2) idt77252_collect_stat() only uses the register values in code which has been compiled out by a "NOTDEF" cpp test for more than 10 years. Just kill this NOTDEF code entirely, but keep the register reads in case they have side effects. Signed-off-by: David S. Miller diff --git a/drivers/atm/idt77252.c b/drivers/atm/idt77252.c index 048f99f..1f8d724 100644 --- a/drivers/atm/idt77252.c +++ b/drivers/atm/idt77252.c @@ -1261,14 +1261,13 @@ idt77252_rx_raw(struct idt77252_dev *card) PCI_DMA_FROMDEVICE); while (head != tail) { - unsigned int vpi, vci, pti; + unsigned int vpi, vci; u32 header; header = le32_to_cpu(*(u32 *) &queue->data[0]); vpi = (header & ATM_HDR_VPI_MASK) >> ATM_HDR_VPI_SHIFT; vci = (header & ATM_HDR_VCI_MASK) >> ATM_HDR_VCI_SHIFT; - pti = (header & ATM_HDR_PTI_MASK) >> ATM_HDR_PTI_SHIFT; #ifdef CONFIG_ATM_IDT77252_DEBUG if (debug & DBG_RAW_CELL) { @@ -2709,53 +2708,10 @@ idt77252_proc_read(struct atm_dev *dev, loff_t * pos, char *page) static void idt77252_collect_stat(struct idt77252_dev *card) { - u32 cdc, vpec, icc; + (void) readl(SAR_REG_CDC); + (void) readl(SAR_REG_VPEC); + (void) readl(SAR_REG_ICC); - cdc = readl(SAR_REG_CDC); - vpec = readl(SAR_REG_VPEC); - icc = readl(SAR_REG_ICC); - -#ifdef NOTDEF - printk("%s:", card->name); - - if (cdc & 0x7f0000) { - char *s = ""; - - printk(" ["); - if (cdc & (1 << 22)) { - printk("%sRM ID", s); - s = " | "; - } - if (cdc & (1 << 21)) { - printk("%sCON TAB", s); - s = " | "; - } - if (cdc & (1 << 20)) { - printk("%sNO FB", s); - s = " | "; - } - if (cdc & (1 << 19)) { - printk("%sOAM CRC", s); - s = " | "; - } - if (cdc & (1 << 18)) { - printk("%sRM CRC", s); - s = " | "; - } - if (cdc & (1 << 17)) { - printk("%sRM FIFO", s); - s = " | "; - } - if (cdc & (1 << 16)) { - printk("%sRX FIFO", s); - s = " | "; - } - printk("]"); - } - - printk(" CDC %04x, VPEC %04x, ICC: %04x\n", - cdc & 0xffff, vpec & 0xffff, icc & 0xffff); -#endif } static irqreturn_t -- cgit v0.10.2 From 06091ed6b8ec726e6cbc7e40ee6b5aa2332cf381 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Sun, 17 Apr 2011 00:11:25 -0700 Subject: atm: solos-pci: Fix set-but-unused variable. This is just a readback to entire completion of a register write, keep the readback but kill the unused variable. Signed-off-by: David S. Miller diff --git a/drivers/atm/solos-pci.c b/drivers/atm/solos-pci.c index cd0ff66..5d1d076 100644 --- a/drivers/atm/solos-pci.c +++ b/drivers/atm/solos-pci.c @@ -527,7 +527,6 @@ static int flash_upgrade(struct solos_card *card, int chip) { const struct firmware *fw; const char *fw_name; - uint32_t data32 = 0; int blocksize = 0; int numblocks = 0; int offset; @@ -576,7 +575,7 @@ static int flash_upgrade(struct solos_card *card, int chip) dev_info(&card->dev->dev, "Changing FPGA to Update mode\n"); iowrite32(1, card->config_regs + FPGA_MODE); - data32 = ioread32(card->config_regs + FPGA_MODE); + (void) ioread32(card->config_regs + FPGA_MODE); /* Set mode to Chip Erase */ if(chip == 0 || chip == 2) -- cgit v0.10.2 From 21f825e61878db94c7093c8407602fc89fc38ad9 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Sun, 17 Apr 2011 00:13:16 -0700 Subject: pktgen: Fix set-but-unused variable. "iph" in pktgen_output_ipsec() is set but never actually used. Kill it off. Signed-off-by: David S. Miller diff --git a/net/core/pktgen.c b/net/core/pktgen.c index aeeece7..2fa6fee 100644 --- a/net/core/pktgen.c +++ b/net/core/pktgen.c @@ -2514,7 +2514,6 @@ static int pktgen_output_ipsec(struct sk_buff *skb, struct pktgen_dev *pkt_dev) { struct xfrm_state *x = pkt_dev->flows[pkt_dev->curfl].x; int err = 0; - struct iphdr *iph; if (!x) return 0; @@ -2524,7 +2523,6 @@ static int pktgen_output_ipsec(struct sk_buff *skb, struct pktgen_dev *pkt_dev) return 0; spin_lock(&x->lock); - iph = ip_hdr(skb); err = x->outer_mode->output(x, skb); if (err) -- cgit v0.10.2 From 9bf9055eb716f85372c41b3fbc51f90bc7653740 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Sun, 17 Apr 2011 00:14:09 -0700 Subject: decnet: Fix set-but-unused variable. "next" in dn_rebuild_zone() is set but not actually used, kill it off. Signed-off-by: David S. Miller diff --git a/net/decnet/dn_table.c b/net/decnet/dn_table.c index 99d8d3a..d8ea583 100644 --- a/net/decnet/dn_table.c +++ b/net/decnet/dn_table.c @@ -124,11 +124,10 @@ static inline void dn_rebuild_zone(struct dn_zone *dz, int old_divisor) { int i; - struct dn_fib_node *f, **fp, *next; + struct dn_fib_node *f, **fp; for(i = 0; i < old_divisor; i++) { for(f = old_ht[i]; f; f = f->fn_next) { - next = f->fn_next; for(fp = dn_chain_p(f->fn_key, dz); *fp && dn_key_leq((*fp)->fn_key, f->fn_key); fp = &(*fp)->fn_next) -- cgit v0.10.2 From b3b8dc51c16cdaca0d191a340022093fb5c9f003 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Sun, 17 Apr 2011 00:15:22 -0700 Subject: econet: Fix set-but-unused variable. #if 0'd out code for IP handling in aun_data_available() has been commented out since the beginning, which makes the variable "ip" set but not used. Kill it off as well as the stub code. Signed-off-by: David S. Miller diff --git a/net/econet/af_econet.c b/net/econet/af_econet.c index 116d3fd..a1d9f37 100644 --- a/net/econet/af_econet.c +++ b/net/econet/af_econet.c @@ -935,7 +935,6 @@ static void aun_data_available(struct sock *sk, int slen) struct sk_buff *skb; unsigned char *data; struct aunhdr *ah; - struct iphdr *ip; size_t len; while ((skb = skb_recv_datagram(sk, 0, 1, &err)) == NULL) { @@ -949,7 +948,6 @@ static void aun_data_available(struct sock *sk, int slen) data = skb_transport_header(skb) + sizeof(struct udphdr); ah = (struct aunhdr *)data; len = skb->len - sizeof(struct udphdr); - ip = ip_hdr(skb); switch (ah->code) { @@ -962,12 +960,6 @@ static void aun_data_available(struct sock *sk, int slen) case 4: aun_tx_ack(ah->handle, ECTYPE_TRANSMIT_NOT_LISTENING); break; -#if 0 - /* This isn't quite right yet. */ - case 5: - aun_send_response(ip->saddr, ah->handle, 6, ah->cb); - break; -#endif default: printk(KERN_DEBUG "unknown AUN packet (type %d)\n", data[0]); } -- cgit v0.10.2 From d8f969e603b85931f25a1d50f3a7a01e2712c17a Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Sun, 17 Apr 2011 00:46:45 -0700 Subject: ax25: Fix set-but-unused variable. The variable 's' is set but unused in ax25_protocol_release(). Just kill it off. Signed-off-by: David S. Miller diff --git a/net/ax25/ax25_iface.c b/net/ax25/ax25_iface.c index 5a0dda8..60b545e 100644 --- a/net/ax25/ax25_iface.c +++ b/net/ax25/ax25_iface.c @@ -58,7 +58,7 @@ EXPORT_SYMBOL_GPL(ax25_register_pid); void ax25_protocol_release(unsigned int pid) { - struct ax25_protocol *s, *protocol; + struct ax25_protocol *protocol; write_lock_bh(&protocol_list_lock); protocol = protocol_list; @@ -72,7 +72,6 @@ void ax25_protocol_release(unsigned int pid) while (protocol != NULL && protocol->next != NULL) { if (protocol->next->pid == pid) { - s = protocol->next; protocol->next = protocol->next->next; goto out; } -- cgit v0.10.2 From 9e5ebaf852b96aaf4d7f63b920d8016b6784f088 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Sun, 17 Apr 2011 00:48:01 -0700 Subject: atm: lec: Fix set-but-unused variables. The variable 'eth' is set but unused in lec_handle_bridge(). Also, the variable 'priv' is set but unused in lane_module_cleanup(). Just kill them off. Signed-off-by: David S. Miller diff --git a/net/atm/lec.c b/net/atm/lec.c index 38754fd..25073b6 100644 --- a/net/atm/lec.c +++ b/net/atm/lec.c @@ -129,7 +129,6 @@ static struct net_device *dev_lec[MAX_LEC_ITF]; #if defined(CONFIG_BRIDGE) || defined(CONFIG_BRIDGE_MODULE) static void lec_handle_bridge(struct sk_buff *skb, struct net_device *dev) { - struct ethhdr *eth; char *buff; struct lec_priv *priv; @@ -138,7 +137,6 @@ static void lec_handle_bridge(struct sk_buff *skb, struct net_device *dev) * LE_TOPOLOGY_REQUEST with the same value of Topology Change bit * as the Config BPDU has */ - eth = (struct ethhdr *)skb->data; buff = skb->data + skb->dev->hard_header_len; if (*buff++ == 0x42 && *buff++ == 0x42 && *buff++ == 0x03) { struct sock *sk; @@ -1180,7 +1178,6 @@ static int __init lane_module_init(void) static void __exit lane_module_cleanup(void) { int i; - struct lec_priv *priv; remove_proc_entry("lec", atm_proc_root); @@ -1188,7 +1185,6 @@ static void __exit lane_module_cleanup(void) for (i = 0; i < MAX_LEC_ITF; i++) { if (dev_lec[i] != NULL) { - priv = netdev_priv(dev_lec[i]); unregister_netdev(dev_lec[i]); free_netdev(dev_lec[i]); dev_lec[i] = NULL; -- cgit v0.10.2 From 7d038eb6dc0e256dbcac88d52972c4ac55a78fc5 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Sun, 17 Apr 2011 00:50:58 -0700 Subject: bonding: Fix set-but-unused variable. The variable 'vlan_dev' is set but unused in bond_send_gratuitous_arp(). Just kill it off. Signed-off-by: David S. Miller diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index ca902ae..fdf9215 100644 --- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c @@ -2763,7 +2763,6 @@ static void bond_send_gratuitous_arp(struct bonding *bond) { struct slave *slave = bond->curr_active_slave; struct vlan_entry *vlan; - struct net_device *vlan_dev; pr_debug("bond_send_grat_arp: bond %s slave %s\n", bond->dev->name, slave ? slave->dev->name : "NULL"); @@ -2783,7 +2782,6 @@ static void bond_send_gratuitous_arp(struct bonding *bond) return; list_for_each_entry(vlan, &bond->vlan_list, vlan_list) { - vlan_dev = vlan_group_get_device(bond->vlgrp, vlan->vlan_id); if (vlan->vlan_ip) { bond_arp_send(slave->dev, ARPOP_REPLY, vlan->vlan_ip, vlan->vlan_ip, vlan->vlan_id); -- cgit v0.10.2 From f8dfc4528b93ba9c9a191151f8888b4da1d1a45b Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Sun, 17 Apr 2011 00:51:40 -0700 Subject: atlx: Fix set-but-unused variable. The variable 'tpc' is set but unused in atl1_intr_tx(). Just kill it off. Signed-off-by: David S. Miller diff --git a/drivers/net/atlx/atl1.c b/drivers/net/atlx/atl1.c index 98334a1..dffa691 100644 --- a/drivers/net/atlx/atl1.c +++ b/drivers/net/atlx/atl1.c @@ -2074,9 +2074,6 @@ static void atl1_intr_tx(struct atl1_adapter *adapter) cmb_tpd_next_to_clean = le16_to_cpu(adapter->cmb.cmb->tpd_cons_idx); while (cmb_tpd_next_to_clean != sw_tpd_next_to_clean) { - struct tx_packet_desc *tpd; - - tpd = ATL1_TPD_DESC(tpd_ring, sw_tpd_next_to_clean); buffer_info = &tpd_ring->buffer_info[sw_tpd_next_to_clean]; if (buffer_info->dma) { pci_unmap_page(adapter->pdev, buffer_info->dma, -- cgit v0.10.2 From c96922c7beeb6246f36b89a1e8b61d99a435a780 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Sun, 17 Apr 2011 00:54:51 -0700 Subject: atl1e: Fix set-but-unused variable. The variable 'tx_ring' is set but unused in atl1e_init_ring_resources(). Just kill it off. Signed-off-by: David S. Miller diff --git a/drivers/net/atl1e/atl1e_main.c b/drivers/net/atl1e/atl1e_main.c index 9900ca1..86a9122 100644 --- a/drivers/net/atl1e/atl1e_main.c +++ b/drivers/net/atl1e/atl1e_main.c @@ -691,10 +691,8 @@ static void atl1e_cal_ring_size(struct atl1e_adapter *adapter, u32 *ring_size) static void atl1e_init_ring_resources(struct atl1e_adapter *adapter) { - struct atl1e_tx_ring *tx_ring = NULL; struct atl1e_rx_ring *rx_ring = NULL; - tx_ring = &adapter->tx_ring; rx_ring = &adapter->rx_ring; rx_ring->real_page_size = adapter->rx_ring.page_size -- cgit v0.10.2 From 0c78641d7f677c8f420f1c302b4848135b207eb8 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Sun, 17 Apr 2011 00:55:20 -0700 Subject: atl1c: Fix set-but-unused variable. The variable 'extra_size' is set but unused in atl1c_configure_tx(). Just kill it off. Signed-off-by: David S. Miller diff --git a/drivers/net/atl1c/atl1c_main.c b/drivers/net/atl1c/atl1c_main.c index 894d485..5c64a5d 100644 --- a/drivers/net/atl1c/atl1c_main.c +++ b/drivers/net/atl1c/atl1c_main.c @@ -1095,10 +1095,8 @@ static void atl1c_configure_tx(struct atl1c_adapter *adapter) u32 max_pay_load; u16 tx_offload_thresh; u32 txq_ctrl_data; - u32 extra_size = 0; /* Jumbo frame threshold in QWORD unit */ u32 max_pay_load_data; - extra_size = ETH_HLEN + VLAN_HLEN + ETH_FCS_LEN; tx_offload_thresh = MAX_TX_OFFLOAD_THRESH; AT_WRITE_REG(hw, REG_TX_TSO_OFFLOAD_THRESH, (tx_offload_thresh >> 3) & TX_TSO_OFFLOAD_THRESH_MASK); -- cgit v0.10.2 From f792e4f6ac12d45b0eca12f505295c48182a8fd2 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Fri, 18 Feb 2011 09:41:50 -0300 Subject: [media] omap3isp: resizer: Use 4-tap mode equations when the ratio is <= 512 As the number of phases/taps, used to select the correct equations to compute the ratio, depends on the ratio, start with the 7-tap mode equations to compute an approximation of the ratio, and switch to the 4-tap mode equations if the approximation is lower than or equal to 512. Signed-off-by: Laurent Pinchart Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/video/omap3isp/ispresizer.c b/drivers/media/video/omap3isp/ispresizer.c index 829d7bf..40b2db8 100644 --- a/drivers/media/video/omap3isp/ispresizer.c +++ b/drivers/media/video/omap3isp/ispresizer.c @@ -724,9 +724,20 @@ static void resizer_print_status(struct isp_res_device *res) * vrsz = ((ih - 7) * 256 - 32 - 64 * spv) / (oh - 1) * * The ratios are integer values, and must be rounded down to ensure that the - * cropped input size is not bigger than the uncropped input size. As the ratio - * in 7-tap mode is always smaller than the ratio in 4-tap mode, we can use the - * 7-tap mode equations to compute a ratio approximation. + * cropped input size is not bigger than the uncropped input size. + * + * As the number of phases/taps, used to select the correct equations to compute + * the ratio, depends on the ratio, we start with the 4-tap mode equations to + * compute an approximation of the ratio, and switch to the 7-tap mode equations + * if the approximation is higher than the ratio threshold. + * + * As the 7-tap mode equations will return a ratio smaller than or equal to the + * 4-tap mode equations, the resulting ratio could become lower than or equal to + * the ratio threshold. This 'equations loop' isn't an issue as long as the + * correct equations are used to compute the final input size. Starting with the + * 4-tap mode equations ensure that, in case of values resulting in a 'ratio + * loop', the smallest of the ratio values will be used, never exceeding the + * requested input size. * * We first clamp the output size according to the hardware capabilitie to avoid * auto-cropping the input more than required to satisfy the TRM equations. The @@ -788,8 +799,11 @@ static void resizer_calc_ratios(struct isp_res_device *res, max_height = min_t(unsigned int, max_height, MAX_OUT_HEIGHT); output->height = clamp(output->height, min_height, max_height); - ratio->vert = ((input->height - 7) * 256 - 32 - 64 * spv) + ratio->vert = ((input->height - 4) * 256 - 16 - 32 * spv) / (output->height - 1); + if (ratio->vert > MID_RESIZE_VALUE) + ratio->vert = ((input->height - 7) * 256 - 32 - 64 * spv) + / (output->height - 1); ratio->vert = clamp_t(unsigned int, ratio->vert, MIN_RESIZE_VALUE, MAX_RESIZE_VALUE); @@ -856,8 +870,11 @@ static void resizer_calc_ratios(struct isp_res_device *res, max_width & ~(width_alignment - 1)); output->width = ALIGN(output->width, width_alignment); - ratio->horz = ((input->width - 7) * 256 - 32 - 64 * sph) + ratio->horz = ((input->width - 7) * 256 - 16 - 32 * sph) / (output->width - 1); + if (ratio->horz > MID_RESIZE_VALUE) + ratio->horz = ((input->width - 7) * 256 - 32 - 64 * sph) + / (output->width - 1); ratio->horz = clamp_t(unsigned int, ratio->horz, MIN_RESIZE_VALUE, MAX_RESIZE_VALUE); -- cgit v0.10.2 From 8dc1e75e9dc2fa3f5fa2e98be670118366beac92 Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Fri, 18 Feb 2011 09:41:51 -0300 Subject: [media] omap3isp: resizer: Improved resizer rsz factor formula Round properly the rsz factor so that we get highest rsz so that the input width (or height) is highest possible smaller or equal to what the user asks. Signed-off-by: Sakari Ailus Signed-off-by: Laurent Pinchart Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/video/omap3isp/ispresizer.c b/drivers/media/video/omap3isp/ispresizer.c index 40b2db8..70897ce 100644 --- a/drivers/media/video/omap3isp/ispresizer.c +++ b/drivers/media/video/omap3isp/ispresizer.c @@ -714,16 +714,36 @@ static void resizer_print_status(struct isp_res_device *res) * iw and ih are the input width and height after cropping. Those equations need * to be satisfied exactly for the resizer to work correctly. * - * Reverting the equations, we can compute the resizing ratios with + * The equations can't be easily reverted, as the >> 8 operation is not linear. + * In addition, not all input sizes can be achieved for a given output size. To + * get the highest input size lower than or equal to the requested input size, + * we need to compute the highest resizing ratio that satisfies the following + * inequality (taking the 4-tap mode width equation as an example) + * + * iw >= (32 * sph + (ow - 1) * hrsz + 16) >> 8 - 7 + * + * (where iw is the requested input width) which can be rewritten as + * + * iw - 7 >= (32 * sph + (ow - 1) * hrsz + 16) >> 8 + * (iw - 7) << 8 >= 32 * sph + (ow - 1) * hrsz + 16 - b + * ((iw - 7) << 8) + b >= 32 * sph + (ow - 1) * hrsz + 16 + * + * where b is the value of the 8 least significant bits of the right hand side + * expression of the last inequality. The highest resizing ratio value will be + * achieved when b is equal to its maximum value of 255. That resizing ratio + * value will still satisfy the original inequality, as b will disappear when + * the expression will be shifted right by 8. + * + * The reverted the equations thus become * * - 8-phase, 4-tap mode - * hrsz = ((iw - 7) * 256 - 16 - 32 * sph) / (ow - 1) - * vrsz = ((ih - 4) * 256 - 16 - 32 * spv) / (oh - 1) + * hrsz = ((iw - 7) * 256 + 255 - 16 - 32 * sph) / (ow - 1) + * vrsz = ((ih - 4) * 256 + 255 - 16 - 32 * spv) / (oh - 1) * - 4-phase, 7-tap mode - * hrsz = ((iw - 7) * 256 - 32 - 64 * sph) / (ow - 1) - * vrsz = ((ih - 7) * 256 - 32 - 64 * spv) / (oh - 1) + * hrsz = ((iw - 7) * 256 + 255 - 32 - 64 * sph) / (ow - 1) + * vrsz = ((ih - 7) * 256 + 255 - 32 - 64 * spv) / (oh - 1) * - * The ratios are integer values, and must be rounded down to ensure that the + * The ratios are integer values, and are rounded down to ensure that the * cropped input size is not bigger than the uncropped input size. * * As the number of phases/taps, used to select the correct equations to compute @@ -799,10 +819,10 @@ static void resizer_calc_ratios(struct isp_res_device *res, max_height = min_t(unsigned int, max_height, MAX_OUT_HEIGHT); output->height = clamp(output->height, min_height, max_height); - ratio->vert = ((input->height - 4) * 256 - 16 - 32 * spv) + ratio->vert = ((input->height - 4) * 256 + 255 - 16 - 32 * spv) / (output->height - 1); if (ratio->vert > MID_RESIZE_VALUE) - ratio->vert = ((input->height - 7) * 256 - 32 - 64 * spv) + ratio->vert = ((input->height - 7) * 256 + 255 - 32 - 64 * spv) / (output->height - 1); ratio->vert = clamp_t(unsigned int, ratio->vert, MIN_RESIZE_VALUE, MAX_RESIZE_VALUE); @@ -870,10 +890,10 @@ static void resizer_calc_ratios(struct isp_res_device *res, max_width & ~(width_alignment - 1)); output->width = ALIGN(output->width, width_alignment); - ratio->horz = ((input->width - 7) * 256 - 16 - 32 * sph) + ratio->horz = ((input->width - 7) * 256 + 255 - 16 - 32 * sph) / (output->width - 1); if (ratio->horz > MID_RESIZE_VALUE) - ratio->horz = ((input->width - 7) * 256 - 32 - 64 * sph) + ratio->horz = ((input->width - 7) * 256 + 255 - 32 - 64 * sph) / (output->width - 1); ratio->horz = clamp_t(unsigned int, ratio->horz, MIN_RESIZE_VALUE, MAX_RESIZE_VALUE); -- cgit v0.10.2 From 2d4e9d1db22117ebcd4f3353cb45292a8704d511 Mon Sep 17 00:00:00 2001 From: Michael Jones Date: Mon, 28 Feb 2011 08:29:03 -0300 Subject: [media] omap3isp: Fix trivial typos It doesn't get more trivial than these. Signed-off-by: Michael Jones Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/video/omap3isp/isp.c b/drivers/media/video/omap3isp/isp.c index 1a9963bd..7d68b10 100644 --- a/drivers/media/video/omap3isp/isp.c +++ b/drivers/media/video/omap3isp/isp.c @@ -715,7 +715,7 @@ static int isp_pipeline_link_notify(struct media_pad *source, * Walk the entities chain starting at the pipeline output video node and start * all modules in the chain in the given mode. * - * Return 0 if successfull, or the return value of the failed video::s_stream + * Return 0 if successful, or the return value of the failed video::s_stream * operation otherwise. */ static int isp_pipeline_enable(struct isp_pipeline *pipe, @@ -883,7 +883,7 @@ static int isp_pipeline_disable(struct isp_pipeline *pipe) * Set the pipeline to the given stream state. Pipelines can be started in * single-shot or continuous mode. * - * Return 0 if successfull, or the return value of the failed video::s_stream + * Return 0 if successful, or the return value of the failed video::s_stream * operation otherwise. */ int omap3isp_pipeline_set_stream(struct isp_pipeline *pipe, diff --git a/drivers/media/video/omap3isp/ispccdc.c b/drivers/media/video/omap3isp/ispccdc.c index 5ff9d14..fd811ea 100644 --- a/drivers/media/video/omap3isp/ispccdc.c +++ b/drivers/media/video/omap3isp/ispccdc.c @@ -1338,7 +1338,7 @@ static int ccdc_sbl_wait_idle(struct isp_ccdc_device *ccdc, * @ccdc: Pointer to ISP CCDC device. * @event: Pointing which event trigger handler * - * Return 1 when the event and stopping request combination is satisfyied, + * Return 1 when the event and stopping request combination is satisfied, * zero otherwise. */ static int __ccdc_handle_stopping(struct isp_ccdc_device *ccdc, u32 event) @@ -1618,7 +1618,7 @@ static int ccdc_video_queue(struct isp_video *video, struct isp_buffer *buffer) ccdc_set_outaddr(ccdc, buffer->isp_addr); - /* We now have a buffer queued on the output, restart the pipeline in + /* We now have a buffer queued on the output, restart the pipeline * on the next CCDC interrupt if running in continuous mode (or when * starting the stream). */ diff --git a/drivers/media/video/omap3isp/isppreview.c b/drivers/media/video/omap3isp/isppreview.c index baf9374..6af0f23 100644 --- a/drivers/media/video/omap3isp/isppreview.c +++ b/drivers/media/video/omap3isp/isppreview.c @@ -755,7 +755,7 @@ static struct preview_update update_attrs[] = { * @configs - pointer to update config structure. * @config - return pointer to appropriate structure field. * @bit - for which feature to return pointers. - * Return size of coresponding prev_params member + * Return size of corresponding prev_params member */ static u32 __preview_get_ptrs(struct prev_params *params, void **param, diff --git a/drivers/media/video/omap3isp/ispqueue.c b/drivers/media/video/omap3isp/ispqueue.c index 8fddc58..c91e56a 100644 --- a/drivers/media/video/omap3isp/ispqueue.c +++ b/drivers/media/video/omap3isp/ispqueue.c @@ -408,8 +408,8 @@ done: * isp_video_buffer_prepare_vm_flags - Get VMA flags for a userspace address * * This function locates the VMAs for the buffer's userspace address and checks - * that their flags match. The onlflag that we need to care for at the moment is - * VM_PFNMAP. + * that their flags match. The only flag that we need to care for at the moment + * is VM_PFNMAP. * * The buffer vm_flags field is set to the first VMA flags. * -- cgit v0.10.2 From 7a6f0b22706e2314dbba91f53d20502050aec1d2 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Fri, 11 Mar 2011 11:34:35 -0300 Subject: [media] media: Properly handle link flags in link setup, link notify callback The link flags were not properly handled in __media_entity_setup_link which could lead to link_notify callback to be called when the flags are not modified. Fix this. Signed-off-by: Laurent Pinchart Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/media-entity.c b/drivers/media/media-entity.c index 23640ed..056138f 100644 --- a/drivers/media/media-entity.c +++ b/drivers/media/media-entity.c @@ -378,7 +378,6 @@ EXPORT_SYMBOL_GPL(media_entity_create_link); static int __media_entity_setup_link_notify(struct media_link *link, u32 flags) { - const u32 mask = MEDIA_LNK_FL_ENABLED; int ret; /* Notify both entities. */ @@ -395,7 +394,7 @@ static int __media_entity_setup_link_notify(struct media_link *link, u32 flags) return ret; } - link->flags = (link->flags & ~mask) | (flags & mask); + link->flags = flags; link->reverse->flags = link->flags; return 0; @@ -417,6 +416,7 @@ static int __media_entity_setup_link_notify(struct media_link *link, u32 flags) */ int __media_entity_setup_link(struct media_link *link, u32 flags) { + const u32 mask = MEDIA_LNK_FL_ENABLED; struct media_device *mdev; struct media_entity *source, *sink; int ret = -EBUSY; @@ -424,6 +424,10 @@ int __media_entity_setup_link(struct media_link *link, u32 flags) if (link == NULL) return -EINVAL; + /* The non-modifiable link flags must not be modified. */ + if ((link->flags & ~mask) != (flags & ~mask)) + return -EINVAL; + if (link->flags & MEDIA_LNK_FL_IMMUTABLE) return link->flags == flags ? 0 : -EINVAL; -- cgit v0.10.2 From b5feda91c1c3510f54720dd8f086653af230a0e1 Mon Sep 17 00:00:00 2001 From: David Cohen Date: Tue, 1 Mar 2011 12:17:40 -0300 Subject: [media] omap3isp: stat: update struct ispstat_generic_config's comments struct ispstat_generic_config's comments refers to isph3a_aewb_config, isph3a_af_config and isphist_config. But those structs have had their names prefixed with 'omap3'. So, let's update the comments. Signed-off-by: David Cohen Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/video/omap3isp/ispstat.h b/drivers/media/video/omap3isp/ispstat.h index 820950c..d86da94 100644 --- a/drivers/media/video/omap3isp/ispstat.h +++ b/drivers/media/video/omap3isp/ispstat.h @@ -131,9 +131,9 @@ struct ispstat { struct ispstat_generic_config { /* * Fields must be in the same order as in: - * - isph3a_aewb_config - * - isph3a_af_config - * - isphist_config + * - omap3isp_h3a_aewb_config + * - omap3isp_h3a_af_config + * - omap3isp_hist_config */ u32 buf_size; u16 config_counter; -- cgit v0.10.2 From 994d5375a246c6585d2a6751d568cc86e89aef34 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Tue, 1 Mar 2011 13:43:07 -0300 Subject: [media] omap3isp: isp: Reset the ISP when the pipeline can't be stopped When a failure to stop a module in the pipeline is detected, the only way to recover is to reset the ISP. However, as other users can be using a different pipeline with other modules, the ISP can't be reset synchronously with the error detection. Mark the ISP as needing a reset when a failure to stop a pipeline is detected, and reset the ISP when the last user releases the last reference to the ISP. Modify the omap3isp_pipeline_set_stream() function to record the new ISP pipeline state only when no error occurs, except when stopping the pipeline in which case the pipeline is still marked as stopped. Signed-off-by: Laurent Pinchart Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/video/omap3isp/isp.c b/drivers/media/video/omap3isp/isp.c index 7d68b10..f380f09 100644 --- a/drivers/media/video/omap3isp/isp.c +++ b/drivers/media/video/omap3isp/isp.c @@ -872,6 +872,9 @@ static int isp_pipeline_disable(struct isp_pipeline *pipe) } } + if (failure < 0) + isp->needs_reset = true; + return failure; } @@ -884,7 +887,8 @@ static int isp_pipeline_disable(struct isp_pipeline *pipe) * single-shot or continuous mode. * * Return 0 if successful, or the return value of the failed video::s_stream - * operation otherwise. + * operation otherwise. The pipeline state is not updated when the operation + * fails, except when stopping the pipeline. */ int omap3isp_pipeline_set_stream(struct isp_pipeline *pipe, enum isp_pipeline_stream_state state) @@ -895,7 +899,9 @@ int omap3isp_pipeline_set_stream(struct isp_pipeline *pipe, ret = isp_pipeline_disable(pipe); else ret = isp_pipeline_enable(pipe, state); - pipe->stream_state = state; + + if (ret == 0 || state == ISP_PIPELINE_STREAM_STOPPED) + pipe->stream_state = state; return ret; } @@ -1481,6 +1487,10 @@ void omap3isp_put(struct isp_device *isp) if (--isp->ref_count == 0) { isp_disable_interrupts(isp); isp_save_ctx(isp); + if (isp->needs_reset) { + isp_reset(isp); + isp->needs_reset = false; + } isp_disable_clocks(isp); } mutex_unlock(&isp->isp_mutex); diff --git a/drivers/media/video/omap3isp/isp.h b/drivers/media/video/omap3isp/isp.h index cf5214e..5f87645 100644 --- a/drivers/media/video/omap3isp/isp.h +++ b/drivers/media/video/omap3isp/isp.h @@ -262,6 +262,7 @@ struct isp_device { /* ISP Obj */ spinlock_t stat_lock; /* common lock for statistic drivers */ struct mutex isp_mutex; /* For handling ref_count field */ + bool needs_reset; int has_context; int ref_count; unsigned int autoidle; -- cgit v0.10.2 From 7c2c8f42a389d3b8acdcee19c4ecc4e9c1354d78 Mon Sep 17 00:00:00 2001 From: Stanimir Varbanov Date: Mon, 21 Mar 2011 12:22:44 -0300 Subject: [media] omap3isp: Use isp xclk defines Use isp defines for isp xclk selection in isp_set_xclk(). Signed-off-by: Stanimir Varbanov Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/video/omap3isp/isp.c b/drivers/media/video/omap3isp/isp.c index f380f09..e4fe836 100644 --- a/drivers/media/video/omap3isp/isp.c +++ b/drivers/media/video/omap3isp/isp.c @@ -215,20 +215,21 @@ static u32 isp_set_xclk(struct isp_device *isp, u32 xclk, u8 xclksel) } switch (xclksel) { - case 0: + case ISP_XCLK_A: isp_reg_clr_set(isp, OMAP3_ISP_IOMEM_MAIN, ISP_TCTRL_CTRL, ISPTCTRL_CTRL_DIVA_MASK, divisor << ISPTCTRL_CTRL_DIVA_SHIFT); dev_dbg(isp->dev, "isp_set_xclk(): cam_xclka set to %d Hz\n", currentxclk); break; - case 1: + case ISP_XCLK_B: isp_reg_clr_set(isp, OMAP3_ISP_IOMEM_MAIN, ISP_TCTRL_CTRL, ISPTCTRL_CTRL_DIVB_MASK, divisor << ISPTCTRL_CTRL_DIVB_SHIFT); dev_dbg(isp->dev, "isp_set_xclk(): cam_xclkb set to %d Hz\n", currentxclk); break; + case ISP_XCLK_NONE: default: omap3isp_put(isp); dev_dbg(isp->dev, "ISP_ERR: isp_set_xclk(): Invalid requested " @@ -237,13 +238,13 @@ static u32 isp_set_xclk(struct isp_device *isp, u32 xclk, u8 xclksel) } /* Do we go from stable whatever to clock? */ - if (divisor >= 2 && isp->xclk_divisor[xclksel] < 2) + if (divisor >= 2 && isp->xclk_divisor[xclksel - 1] < 2) omap3isp_get(isp); /* Stopping the clock. */ - else if (divisor < 2 && isp->xclk_divisor[xclksel] >= 2) + else if (divisor < 2 && isp->xclk_divisor[xclksel - 1] >= 2) omap3isp_put(isp); - isp->xclk_divisor[xclksel] = divisor; + isp->xclk_divisor[xclksel - 1] = divisor; omap3isp_put(isp); diff --git a/drivers/media/video/omap3isp/isp.h b/drivers/media/video/omap3isp/isp.h index 5f87645..00075c6 100644 --- a/drivers/media/video/omap3isp/isp.h +++ b/drivers/media/video/omap3isp/isp.h @@ -314,9 +314,9 @@ void omap3isp_configure_bridge(struct isp_device *isp, enum ccdc_input_entity input, const struct isp_parallel_platform_data *pdata); -#define ISP_XCLK_NONE -1 -#define ISP_XCLK_A 0 -#define ISP_XCLK_B 1 +#define ISP_XCLK_NONE 0 +#define ISP_XCLK_A 1 +#define ISP_XCLK_B 2 struct isp_device *omap3isp_get(struct isp_device *isp); void omap3isp_put(struct isp_device *isp); -- cgit v0.10.2 From 5a3ddcde35ecadd92d3390552d153f906b120175 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Sun, 17 Apr 2011 08:07:57 -0300 Subject: cx23885: Fix stv0367 Kconfig dependency Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/video/cx23885/Kconfig b/drivers/media/video/cx23885/Kconfig index 3b6e7f2..caab1bf 100644 --- a/drivers/media/video/cx23885/Kconfig +++ b/drivers/media/video/cx23885/Kconfig @@ -22,6 +22,7 @@ config VIDEO_CX23885 select DVB_CX24116 if !DVB_FE_CUSTOMISE select DVB_STV0900 if !DVB_FE_CUSTOMISE select DVB_DS3000 if !DVB_FE_CUSTOMISE + select DVB_STV0367 if !DVB_FE_CUSTOMISE select MEDIA_TUNER_MT2131 if !MEDIA_TUNER_CUSTOMISE select MEDIA_TUNER_XC2028 if !MEDIA_TUNER_CUSTOMISE select MEDIA_TUNER_TDA8290 if !MEDIA_TUNER_CUSTOMISE -- cgit v0.10.2 From 551586292b39da6e4fbfbb5b96b57b68decfdab9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Linus=20L=C3=BCssing?= Date: Mon, 14 Mar 2011 22:43:27 +0000 Subject: batman-adv: Move bonding / iface alternating router search to own functions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This decreases the size of find_router() by outsourcing the router search for the bonding and interface alternating modes to their own sub functions. This shall make it easier to keep track of the correct refcounting later. Signed-off-by: Linus Lüssing Signed-off-by: Marek Lindner Signed-off-by: Sven Eckelmann diff --git a/net/batman-adv/routing.c b/net/batman-adv/routing.c index c172f5d..f212abe 100644 --- a/net/batman-adv/routing.c +++ b/net/batman-adv/routing.c @@ -1092,6 +1092,106 @@ out: return ret; } +/* In the bonding case, send the packets in a round + * robin fashion over the remaining interfaces. + * + * This method rotates the bonding list and increases the + * returned router's refcount. */ +static struct neigh_node *find_bond_router(struct orig_node *primary_orig, + struct hard_iface *recv_if) +{ + struct neigh_node *tmp_neigh_node; + struct neigh_node *router = NULL, *first_candidate = NULL; + + rcu_read_lock(); + list_for_each_entry_rcu(tmp_neigh_node, &primary_orig->bond_list, + bonding_list) { + if (!first_candidate) + first_candidate = tmp_neigh_node; + + /* recv_if == NULL on the first node. */ + if (tmp_neigh_node->if_incoming == recv_if) + continue; + + if (!atomic_inc_not_zero(&tmp_neigh_node->refcount)) + continue; + + router = tmp_neigh_node; + break; + } + + /* use the first candidate if nothing was found. */ + if (!router && first_candidate && + atomic_inc_not_zero(&first_candidate->refcount)) + router = first_candidate; + + if (!router) + goto out; + + /* selected should point to the next element + * after the current router */ + spin_lock_bh(&primary_orig->neigh_list_lock); + /* this is a list_move(), which unfortunately + * does not exist as rcu version */ + list_del_rcu(&primary_orig->bond_list); + list_add_rcu(&primary_orig->bond_list, + &router->bonding_list); + spin_unlock_bh(&primary_orig->neigh_list_lock); + +out: + rcu_read_unlock(); + return router; +} + +/* Interface Alternating: Use the best of the + * remaining candidates which are not using + * this interface. + * + * Increases the returned router's refcount */ +static struct neigh_node *find_ifalter_router(struct orig_node *primary_orig, + struct hard_iface *recv_if) +{ + struct neigh_node *tmp_neigh_node; + struct neigh_node *router = NULL, *first_candidate = NULL; + + rcu_read_lock(); + list_for_each_entry_rcu(tmp_neigh_node, &primary_orig->bond_list, + bonding_list) { + if (!first_candidate) + first_candidate = tmp_neigh_node; + + /* recv_if == NULL on the first node. */ + if (tmp_neigh_node->if_incoming == recv_if) + continue; + + if (!atomic_inc_not_zero(&tmp_neigh_node->refcount)) + continue; + + /* if we don't have a router yet + * or this one is better, choose it. */ + if ((!router) || + (tmp_neigh_node->tq_avg > router->tq_avg)) { + /* decrement refcount of + * previously selected router */ + if (router) + neigh_node_free_ref(router); + + router = tmp_neigh_node; + atomic_inc_not_zero(&router->refcount); + } + + neigh_node_free_ref(tmp_neigh_node); + } + + /* use the first candidate if nothing was found. */ + if (!router && first_candidate && + atomic_inc_not_zero(&first_candidate->refcount)) + router = first_candidate; + + rcu_read_unlock(); + return router; +} + /* find a suitable router for this originator, and use * bonding if possible. increases the found neighbors * refcount.*/ @@ -1101,7 +1201,7 @@ struct neigh_node *find_router(struct bat_priv *bat_priv, { struct orig_node *primary_orig_node; struct orig_node *router_orig; - struct neigh_node *router, *first_candidate, *tmp_neigh_node; + struct neigh_node *router; static uint8_t zero_mac[ETH_ALEN] = {0, 0, 0, 0, 0, 0}; int bonding_enabled; @@ -1157,82 +1257,12 @@ struct neigh_node *find_router(struct bat_priv *bat_priv, * in. */ neigh_node_free_ref(router); - first_candidate = NULL; - router = NULL; - - if (bonding_enabled) { - /* in the bonding case, send the packets in a round - * robin fashion over the remaining interfaces. */ - - list_for_each_entry_rcu(tmp_neigh_node, - &primary_orig_node->bond_list, bonding_list) { - if (!first_candidate) - first_candidate = tmp_neigh_node; - /* recv_if == NULL on the first node. */ - if (tmp_neigh_node->if_incoming != recv_if && - atomic_inc_not_zero(&tmp_neigh_node->refcount)) { - router = tmp_neigh_node; - break; - } - } - - /* use the first candidate if nothing was found. */ - if (!router && first_candidate && - atomic_inc_not_zero(&first_candidate->refcount)) - router = first_candidate; - if (!router) { - rcu_read_unlock(); - return NULL; - } - - /* selected should point to the next element - * after the current router */ - spin_lock_bh(&primary_orig_node->neigh_list_lock); - /* this is a list_move(), which unfortunately - * does not exist as rcu version */ - list_del_rcu(&primary_orig_node->bond_list); - list_add_rcu(&primary_orig_node->bond_list, - &router->bonding_list); - spin_unlock_bh(&primary_orig_node->neigh_list_lock); - - } else { - /* if bonding is disabled, use the best of the - * remaining candidates which are not using - * this interface. */ - list_for_each_entry_rcu(tmp_neigh_node, - &primary_orig_node->bond_list, bonding_list) { - if (!first_candidate) - first_candidate = tmp_neigh_node; - - /* recv_if == NULL on the first node. */ - if (tmp_neigh_node->if_incoming == recv_if) - continue; - - if (!atomic_inc_not_zero(&tmp_neigh_node->refcount)) - continue; - - /* if we don't have a router yet - * or this one is better, choose it. */ - if ((!router) || - (tmp_neigh_node->tq_avg > router->tq_avg)) { - /* decrement refcount of - * previously selected router */ - if (router) - neigh_node_free_ref(router); - - router = tmp_neigh_node; - atomic_inc_not_zero(&router->refcount); - } - - neigh_node_free_ref(tmp_neigh_node); - } + if (bonding_enabled) + router = find_bond_router(primary_orig_node, recv_if); + else + router = find_ifalter_router(primary_orig_node, recv_if); - /* use the first candidate if nothing was found. */ - if (!router && first_candidate && - atomic_inc_not_zero(&first_candidate->refcount)) - router = first_candidate; - } return_router: rcu_read_unlock(); return router; -- cgit v0.10.2 From 4c804850572f70a2350e4d1e79d6659392b07733 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Linus=20L=C3=BCssing?= Date: Mon, 14 Mar 2011 22:43:30 +0000 Subject: batman-adv: Make gateway_get_selected type safe MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Make the return value explicit instead of (void *). Signed-off-by: Linus Lüssing Signed-off-by: Marek Lindner Signed-off-by: Sven Eckelmann diff --git a/net/batman-adv/gateway_client.c b/net/batman-adv/gateway_client.c index 3cc4355..27b87ad 100644 --- a/net/batman-adv/gateway_client.c +++ b/net/batman-adv/gateway_client.c @@ -42,7 +42,7 @@ static void gw_node_free_ref(struct gw_node *gw_node) call_rcu(&gw_node->rcu, gw_node_free_rcu); } -void *gw_get_selected(struct bat_priv *bat_priv) +struct orig_node *gw_get_selected(struct bat_priv *bat_priv) { struct gw_node *curr_gateway_tmp; struct orig_node *orig_node = NULL; diff --git a/net/batman-adv/gateway_client.h b/net/batman-adv/gateway_client.h index 2aa4391..97c31d1 100644 --- a/net/batman-adv/gateway_client.h +++ b/net/batman-adv/gateway_client.h @@ -24,7 +24,7 @@ void gw_deselect(struct bat_priv *bat_priv); void gw_election(struct bat_priv *bat_priv); -void *gw_get_selected(struct bat_priv *bat_priv); +struct orig_node *gw_get_selected(struct bat_priv *bat_priv); void gw_check_election(struct bat_priv *bat_priv, struct orig_node *orig_node); void gw_node_update(struct bat_priv *bat_priv, struct orig_node *orig_node, uint8_t new_gwflags); -- cgit v0.10.2 From 57f0c07c4d0da8bcc23e21c330fe9c7c5cf776b5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Linus=20L=C3=BCssing?= Date: Mon, 14 Mar 2011 22:43:33 +0000 Subject: batman-adv: Simplify gw_check_election(), use gw_get_selected() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit gw_get_selected() can get us the desired orig_node directly, therefore reusing that function in gw_check_election(). Signed-off-by: Linus Lüssing Signed-off-by: Marek Lindner Signed-off-by: Sven Eckelmann diff --git a/net/batman-adv/gateway_client.c b/net/batman-adv/gateway_client.c index 27b87ad..879ac15 100644 --- a/net/batman-adv/gateway_client.c +++ b/net/batman-adv/gateway_client.c @@ -23,6 +23,7 @@ #include "gateway_client.h" #include "gateway_common.h" #include "hard-interface.h" +#include "originator.h" #include #include #include @@ -203,28 +204,25 @@ void gw_election(struct bat_priv *bat_priv) void gw_check_election(struct bat_priv *bat_priv, struct orig_node *orig_node) { - struct gw_node *curr_gateway_tmp; + struct orig_node *curr_gw_orig; uint8_t gw_tq_avg, orig_tq_avg; - rcu_read_lock(); - curr_gateway_tmp = rcu_dereference(bat_priv->curr_gw); - if (!curr_gateway_tmp) - goto out_rcu; + curr_gw_orig = gw_get_selected(bat_priv); + if (!curr_gw_orig) + goto deselect; - if (!curr_gateway_tmp->orig_node) - goto deselect_rcu; - - if (!curr_gateway_tmp->orig_node->router) + rcu_read_lock(); + if (!curr_gw_orig->router) goto deselect_rcu; /* this node already is the gateway */ - if (curr_gateway_tmp->orig_node == orig_node) + if (curr_gw_orig == orig_node) goto out_rcu; if (!orig_node->router) goto out_rcu; - gw_tq_avg = curr_gateway_tmp->orig_node->router->tq_avg; + gw_tq_avg = curr_gw_orig->router->tq_avg; rcu_read_unlock(); orig_tq_avg = orig_node->router->tq_avg; @@ -255,6 +253,9 @@ deselect_rcu: deselect: gw_deselect(bat_priv); out: + if (curr_gw_orig) + orig_node_free_ref(curr_gw_orig); + return; } -- cgit v0.10.2 From e1a5382f978b67b5cc36eec65e6046730ce07714 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Linus=20L=C3=BCssing?= Date: Mon, 14 Mar 2011 22:43:37 +0000 Subject: batman-adv: Make orig_node->router an rcu protected pointer MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The rcu protected macros rcu_dereference() and rcu_assign_pointer() for the orig_node->router need to be used, as well as spin/rcu locking. Otherwise we might end up using a router pointer pointing to already freed memory. Therefore this commit introduces the safe getter method orig_node_get_router(). Signed-off-by: Linus Lüssing Signed-off-by: Marek Lindner Signed-off-by: Sven Eckelmann diff --git a/net/batman-adv/gateway_client.c b/net/batman-adv/gateway_client.c index 879ac15..42a8a7b 100644 --- a/net/batman-adv/gateway_client.c +++ b/net/batman-adv/gateway_client.c @@ -98,6 +98,7 @@ void gw_election(struct bat_priv *bat_priv) { struct hlist_node *node; struct gw_node *gw_node, *curr_gw, *curr_gw_tmp = NULL; + struct neigh_node *router; uint8_t max_tq = 0; uint32_t max_gw_factor = 0, tmp_gw_factor = 0; int down, up; @@ -133,10 +134,11 @@ void gw_election(struct bat_priv *bat_priv) } hlist_for_each_entry_rcu(gw_node, node, &bat_priv->gw_list, list) { - if (!gw_node->orig_node->router) + if (gw_node->deleted) continue; - if (gw_node->deleted) + router = orig_node_get_router(gw_node->orig_node); + if (!router) continue; switch (atomic_read(&bat_priv->gw_sel_class)) { @@ -144,15 +146,14 @@ void gw_election(struct bat_priv *bat_priv) gw_bandwidth_to_kbit(gw_node->orig_node->gw_flags, &down, &up); - tmp_gw_factor = (gw_node->orig_node->router->tq_avg * - gw_node->orig_node->router->tq_avg * + tmp_gw_factor = (router->tq_avg * router->tq_avg * down * 100 * 100) / (TQ_LOCAL_WINDOW_SIZE * TQ_LOCAL_WINDOW_SIZE * 64); if ((tmp_gw_factor > max_gw_factor) || ((tmp_gw_factor == max_gw_factor) && - (gw_node->orig_node->router->tq_avg > max_tq))) + (router->tq_avg > max_tq))) curr_gw_tmp = gw_node; break; @@ -164,19 +165,25 @@ void gw_election(struct bat_priv *bat_priv) * soon as a better gateway appears which has * $routing_class more tq points) **/ - if (gw_node->orig_node->router->tq_avg > max_tq) + if (router->tq_avg > max_tq) curr_gw_tmp = gw_node; break; } - if (gw_node->orig_node->router->tq_avg > max_tq) - max_tq = gw_node->orig_node->router->tq_avg; + if (router->tq_avg > max_tq) + max_tq = router->tq_avg; if (tmp_gw_factor > max_gw_factor) max_gw_factor = tmp_gw_factor; + + neigh_node_free_ref(router); } if (curr_gw != curr_gw_tmp) { + router = orig_node_get_router(curr_gw_tmp->orig_node); + if (!router) + goto out; + if ((curr_gw) && (!curr_gw_tmp)) bat_dbg(DBG_BATMAN, bat_priv, "Removing selected gateway - " @@ -187,45 +194,47 @@ void gw_election(struct bat_priv *bat_priv) "(gw_flags: %i, tq: %i)\n", curr_gw_tmp->orig_node->orig, curr_gw_tmp->orig_node->gw_flags, - curr_gw_tmp->orig_node->router->tq_avg); + router->tq_avg); else bat_dbg(DBG_BATMAN, bat_priv, "Changing route to gateway %pM " "(gw_flags: %i, tq: %i)\n", curr_gw_tmp->orig_node->orig, curr_gw_tmp->orig_node->gw_flags, - curr_gw_tmp->orig_node->router->tq_avg); + router->tq_avg); + neigh_node_free_ref(router); gw_select(bat_priv, curr_gw_tmp); } +out: rcu_read_unlock(); } void gw_check_election(struct bat_priv *bat_priv, struct orig_node *orig_node) { struct orig_node *curr_gw_orig; + struct neigh_node *router_gw = NULL, *router_orig = NULL; uint8_t gw_tq_avg, orig_tq_avg; curr_gw_orig = gw_get_selected(bat_priv); if (!curr_gw_orig) goto deselect; - rcu_read_lock(); - if (!curr_gw_orig->router) - goto deselect_rcu; + router_gw = orig_node_get_router(curr_gw_orig); + if (!router_gw) + goto deselect; /* this node already is the gateway */ if (curr_gw_orig == orig_node) - goto out_rcu; - - if (!orig_node->router) - goto out_rcu; + goto out; - gw_tq_avg = curr_gw_orig->router->tq_avg; - rcu_read_unlock(); + router_orig = orig_node_get_router(orig_node); + if (!router_orig) + goto out; - orig_tq_avg = orig_node->router->tq_avg; + gw_tq_avg = router_gw->tq_avg; + orig_tq_avg = router_orig->tq_avg; /* the TQ value has to be better */ if (orig_tq_avg < gw_tq_avg) @@ -243,18 +252,16 @@ void gw_check_election(struct bat_priv *bat_priv, struct orig_node *orig_node) "Restarting gateway selection: better gateway found (tq curr: " "%i, tq new: %i)\n", gw_tq_avg, orig_tq_avg); - goto deselect; -out_rcu: - rcu_read_unlock(); - goto out; -deselect_rcu: - rcu_read_unlock(); deselect: gw_deselect(bat_priv); out: if (curr_gw_orig) orig_node_free_ref(curr_gw_orig); + if (router_gw) + neigh_node_free_ref(router_gw); + if (router_orig) + neigh_node_free_ref(router_orig); return; } @@ -362,23 +369,30 @@ void gw_node_purge(struct bat_priv *bat_priv) spin_unlock_bh(&bat_priv->gw_list_lock); } +/** + * fails if orig_node has no router + */ static int _write_buffer_text(struct bat_priv *bat_priv, struct seq_file *seq, struct gw_node *gw_node) { struct gw_node *curr_gw; - int down, up, ret; + struct neigh_node *router; + int down, up, ret = -1; gw_bandwidth_to_kbit(gw_node->orig_node->gw_flags, &down, &up); + router = orig_node_get_router(gw_node->orig_node); + if (!router) + goto out; + rcu_read_lock(); curr_gw = rcu_dereference(bat_priv->curr_gw); ret = seq_printf(seq, "%s %pM (%3i) %pM [%10s]: %3i - %i%s/%i%s\n", (curr_gw == gw_node ? "=>" : " "), gw_node->orig_node->orig, - gw_node->orig_node->router->tq_avg, - gw_node->orig_node->router->addr, - gw_node->orig_node->router->if_incoming->net_dev->name, + router->tq_avg, router->addr, + router->if_incoming->net_dev->name, gw_node->orig_node->gw_flags, (down > 2048 ? down / 1024 : down), (down > 2048 ? "MBit" : "KBit"), @@ -386,6 +400,8 @@ static int _write_buffer_text(struct bat_priv *bat_priv, (up > 2048 ? "MBit" : "KBit")); rcu_read_unlock(); + neigh_node_free_ref(router); +out: return ret; } @@ -423,10 +439,10 @@ int gw_client_seq_print_text(struct seq_file *seq, void *offset) if (gw_node->deleted) continue; - if (!gw_node->orig_node->router) + /* fails if orig_node has no router */ + if (_write_buffer_text(bat_priv, seq, gw_node) < 0) continue; - _write_buffer_text(bat_priv, seq, gw_node); gw_count++; } rcu_read_unlock(); diff --git a/net/batman-adv/icmp_socket.c b/net/batman-adv/icmp_socket.c index 34ce56c..49079c2 100644 --- a/net/batman-adv/icmp_socket.c +++ b/net/batman-adv/icmp_socket.c @@ -218,23 +218,13 @@ static ssize_t bat_socket_write(struct file *file, const char __user *buff, if (atomic_read(&bat_priv->mesh_state) != MESH_ACTIVE) goto dst_unreach; - rcu_read_lock(); orig_node = orig_hash_find(bat_priv, icmp_packet->dst); - if (!orig_node) - goto unlock; - - neigh_node = orig_node->router; + goto dst_unreach; + neigh_node = orig_node_get_router(orig_node); if (!neigh_node) - goto unlock; - - if (!atomic_inc_not_zero(&neigh_node->refcount)) { - neigh_node = NULL; - goto unlock; - } - - rcu_read_unlock(); + goto dst_unreach; if (!neigh_node->if_incoming) goto dst_unreach; @@ -252,8 +242,6 @@ static ssize_t bat_socket_write(struct file *file, const char __user *buff, send_skb_packet(skb, neigh_node->if_incoming, neigh_node->addr); goto out; -unlock: - rcu_read_unlock(); dst_unreach: icmp_packet->msg_type = DESTINATION_UNREACHABLE; bat_socket_add_packet(socket_client, icmp_packet, packet_len); diff --git a/net/batman-adv/originator.c b/net/batman-adv/originator.c index 0b91330..b4cfe36 100644 --- a/net/batman-adv/originator.c +++ b/net/batman-adv/originator.c @@ -70,6 +70,21 @@ void neigh_node_free_ref(struct neigh_node *neigh_node) call_rcu(&neigh_node->rcu, neigh_node_free_rcu); } +/* increases the refcounter of a found router */ +struct neigh_node *orig_node_get_router(struct orig_node *orig_node) +{ + struct neigh_node *router; + + rcu_read_lock(); + router = rcu_dereference(orig_node->router); + + if (router && !atomic_inc_not_zero(&router->refcount)) + router = NULL; + + rcu_read_unlock(); + return router; +} + struct neigh_node *create_neighbor(struct orig_node *orig_node, struct orig_node *orig_neigh_node, uint8_t *neigh, @@ -390,7 +405,7 @@ int orig_seq_print_text(struct seq_file *seq, void *offset) struct hlist_node *node, *node_tmp; struct hlist_head *head; struct orig_node *orig_node; - struct neigh_node *neigh_node; + struct neigh_node *neigh_node, *neigh_node_tmp; int batman_count = 0; int last_seen_secs; int last_seen_msecs; @@ -421,37 +436,41 @@ int orig_seq_print_text(struct seq_file *seq, void *offset) rcu_read_lock(); hlist_for_each_entry_rcu(orig_node, node, head, hash_entry) { - if (!orig_node->router) + neigh_node = orig_node_get_router(orig_node); + if (!neigh_node) continue; - if (orig_node->router->tq_avg == 0) - continue; + if (neigh_node->tq_avg == 0) + goto next; last_seen_secs = jiffies_to_msecs(jiffies - orig_node->last_valid) / 1000; last_seen_msecs = jiffies_to_msecs(jiffies - orig_node->last_valid) % 1000; - neigh_node = orig_node->router; seq_printf(seq, "%pM %4i.%03is (%3i) %pM [%10s]:", orig_node->orig, last_seen_secs, last_seen_msecs, neigh_node->tq_avg, neigh_node->addr, neigh_node->if_incoming->net_dev->name); - hlist_for_each_entry_rcu(neigh_node, node_tmp, + hlist_for_each_entry_rcu(neigh_node_tmp, node_tmp, &orig_node->neigh_list, list) { - seq_printf(seq, " %pM (%3i)", neigh_node->addr, - neigh_node->tq_avg); + seq_printf(seq, " %pM (%3i)", + neigh_node_tmp->addr, + neigh_node_tmp->tq_avg); } seq_printf(seq, "\n"); batman_count++; + +next: + neigh_node_free_ref(neigh_node); } rcu_read_unlock(); } - if ((batman_count == 0)) + if (batman_count == 0) seq_printf(seq, "No batman nodes in range ...\n"); return 0; diff --git a/net/batman-adv/originator.h b/net/batman-adv/originator.h index 5cc0110..e1d641f 100644 --- a/net/batman-adv/originator.h +++ b/net/batman-adv/originator.h @@ -34,6 +34,7 @@ struct neigh_node *create_neighbor(struct orig_node *orig_node, uint8_t *neigh, struct hard_iface *if_incoming); void neigh_node_free_ref(struct neigh_node *neigh_node); +struct neigh_node *orig_node_get_router(struct orig_node *orig_node); int orig_seq_print_text(struct seq_file *seq, void *offset); int orig_hash_add_if(struct hard_iface *hard_iface, int max_if_num); int orig_hash_del_if(struct hard_iface *hard_iface, int max_if_num); diff --git a/net/batman-adv/routing.c b/net/batman-adv/routing.c index f212abe..b7d43ca 100644 --- a/net/batman-adv/routing.c +++ b/net/batman-adv/routing.c @@ -87,18 +87,20 @@ static void update_route(struct bat_priv *bat_priv, struct neigh_node *neigh_node, unsigned char *hna_buff, int hna_buff_len) { - struct neigh_node *neigh_node_tmp; + struct neigh_node *curr_router; + + curr_router = orig_node_get_router(orig_node); /* route deleted */ - if ((orig_node->router) && (!neigh_node)) { + if ((curr_router) && (!neigh_node)) { bat_dbg(DBG_ROUTES, bat_priv, "Deleting route towards: %pM\n", orig_node->orig); hna_global_del_orig(bat_priv, orig_node, "originator timed out"); - /* route added */ - } else if ((!orig_node->router) && (neigh_node)) { + /* route added */ + } else if ((!curr_router) && (neigh_node)) { bat_dbg(DBG_ROUTES, bat_priv, "Adding route towards: %pM (via %pM)\n", @@ -106,21 +108,29 @@ static void update_route(struct bat_priv *bat_priv, hna_global_add_orig(bat_priv, orig_node, hna_buff, hna_buff_len); - /* route changed */ + /* route changed */ } else { bat_dbg(DBG_ROUTES, bat_priv, "Changing route towards: %pM " "(now via %pM - was via %pM)\n", orig_node->orig, neigh_node->addr, - orig_node->router->addr); + curr_router->addr); } + if (curr_router) + neigh_node_free_ref(curr_router); + + /* increase refcount of new best neighbor */ if (neigh_node && !atomic_inc_not_zero(&neigh_node->refcount)) neigh_node = NULL; - neigh_node_tmp = orig_node->router; - orig_node->router = neigh_node; - if (neigh_node_tmp) - neigh_node_free_ref(neigh_node_tmp); + + spin_lock_bh(&orig_node->neigh_list_lock); + rcu_assign_pointer(orig_node->router, neigh_node); + spin_unlock_bh(&orig_node->neigh_list_lock); + + /* decrease refcount of previous best neighbor */ + if (curr_router) + neigh_node_free_ref(curr_router); } @@ -128,16 +138,23 @@ void update_routes(struct bat_priv *bat_priv, struct orig_node *orig_node, struct neigh_node *neigh_node, unsigned char *hna_buff, int hna_buff_len) { + struct neigh_node *router = NULL; if (!orig_node) - return; + goto out; + + router = orig_node_get_router(orig_node); - if (orig_node->router != neigh_node) + if (router != neigh_node) update_route(bat_priv, orig_node, neigh_node, hna_buff, hna_buff_len); /* may be just HNA changed */ else update_HNA(bat_priv, orig_node, hna_buff, hna_buff_len); + +out: + if (router) + neigh_node_free_ref(router); } static int is_bidirectional_neigh(struct orig_node *orig_node, @@ -288,8 +305,8 @@ static void bonding_candidate_add(struct orig_node *orig_node, struct neigh_node *neigh_node) { struct hlist_node *node; - struct neigh_node *tmp_neigh_node; - uint8_t best_tq, interference_candidate = 0; + struct neigh_node *tmp_neigh_node, *router = NULL; + uint8_t interference_candidate = 0; spin_lock_bh(&orig_node->neigh_list_lock); @@ -298,13 +315,12 @@ static void bonding_candidate_add(struct orig_node *orig_node, neigh_node->orig_node->primary_addr)) goto candidate_del; - if (!orig_node->router) + router = orig_node_get_router(orig_node); + if (!router) goto candidate_del; - best_tq = orig_node->router->tq_avg; - /* ... and is good enough to be considered */ - if (neigh_node->tq_avg < best_tq - BONDING_TQ_THRESHOLD) + if (neigh_node->tq_avg < router->tq_avg - BONDING_TQ_THRESHOLD) goto candidate_del; /** @@ -350,7 +366,9 @@ candidate_del: out: spin_unlock_bh(&orig_node->neigh_list_lock); - return; + + if (router) + neigh_node_free_ref(router); } /* copy primary address for bonding */ @@ -373,6 +391,7 @@ static void update_orig(struct bat_priv *bat_priv, char is_duplicate) { struct neigh_node *neigh_node = NULL, *tmp_neigh_node = NULL; + struct neigh_node *router = NULL; struct orig_node *orig_node_tmp; struct hlist_node *node; int tmp_hna_buff_len; @@ -441,19 +460,18 @@ static void update_orig(struct bat_priv *bat_priv, /* if this neighbor already is our next hop there is nothing * to change */ - if (orig_node->router == neigh_node) + router = orig_node_get_router(orig_node); + if (router == neigh_node) goto update_hna; /* if this neighbor does not offer a better TQ we won't consider it */ - if ((orig_node->router) && - (orig_node->router->tq_avg > neigh_node->tq_avg)) + if (router && (router->tq_avg > neigh_node->tq_avg)) goto update_hna; /* if the TQ is the same and the link not more symetric we * won't consider it either */ - if ((orig_node->router) && - (neigh_node->tq_avg == orig_node->router->tq_avg)) { - orig_node_tmp = orig_node->router->orig_node; + if (router && (neigh_node->tq_avg == router->tq_avg)) { + orig_node_tmp = router->orig_node; spin_lock_bh(&orig_node_tmp->ogm_cnt_lock); bcast_own_sum_orig = orig_node_tmp->bcast_own_sum[if_incoming->if_num]; @@ -474,7 +492,7 @@ static void update_orig(struct bat_priv *bat_priv, goto update_gw; update_hna: - update_routes(bat_priv, orig_node, orig_node->router, + update_routes(bat_priv, orig_node, router, hna_buff, tmp_hna_buff_len); update_gw: @@ -496,6 +514,8 @@ unlock: out: if (neigh_node) neigh_node_free_ref(neigh_node); + if (router) + neigh_node_free_ref(router); } /* checks whether the host restarted and is in the protection time. @@ -603,6 +623,8 @@ void receive_bat_packet(struct ethhdr *ethhdr, struct bat_priv *bat_priv = netdev_priv(if_incoming->soft_iface); struct hard_iface *hard_iface; struct orig_node *orig_neigh_node, *orig_node; + struct neigh_node *router = NULL, *router_router = NULL; + struct neigh_node *orig_neigh_router = NULL; char has_directlink_flag; char is_my_addr = 0, is_my_orig = 0, is_my_oldorig = 0; char is_broadcast = 0, is_bidirectional, is_single_hop_neigh; @@ -747,14 +769,15 @@ void receive_bat_packet(struct ethhdr *ethhdr, goto out; } + router = orig_node_get_router(orig_node); + if (router) + router_router = orig_node_get_router(router->orig_node); + /* avoid temporary routing loops */ - if ((orig_node->router) && - (orig_node->router->orig_node->router) && - (compare_eth(orig_node->router->addr, - batman_packet->prev_sender)) && + if (router && router_router && + (compare_eth(router->addr, batman_packet->prev_sender)) && !(compare_eth(batman_packet->orig, batman_packet->prev_sender)) && - (compare_eth(orig_node->router->addr, - orig_node->router->orig_node->router->addr))) { + (compare_eth(router->addr, router_router->addr))) { bat_dbg(DBG_BATMAN, bat_priv, "Drop packet: ignoring all rebroadcast packets that " "may make me loop (sender: %pM)\n", ethhdr->h_source); @@ -769,9 +792,11 @@ void receive_bat_packet(struct ethhdr *ethhdr, if (!orig_neigh_node) goto out; + orig_neigh_router = orig_node_get_router(orig_neigh_node); + /* drop packet if sender is not a direct neighbor and if we * don't route towards it */ - if (!is_single_hop_neigh && (!orig_neigh_node->router)) { + if (!is_single_hop_neigh && (!orig_neigh_router)) { bat_dbg(DBG_BATMAN, bat_priv, "Drop packet: OGM via unknown neighbor!\n"); goto out_neigh; @@ -825,6 +850,13 @@ out_neigh: if ((orig_neigh_node) && (!is_single_hop_neigh)) orig_node_free_ref(orig_neigh_node); out: + if (router) + neigh_node_free_ref(router); + if (router_router) + neigh_node_free_ref(router_router); + if (orig_neigh_router) + neigh_node_free_ref(orig_neigh_router); + orig_node_free_ref(orig_node); } @@ -869,7 +901,7 @@ static int recv_my_icmp_packet(struct bat_priv *bat_priv, struct sk_buff *skb, size_t icmp_len) { struct orig_node *orig_node = NULL; - struct neigh_node *neigh_node = NULL; + struct neigh_node *router = NULL; struct icmp_packet_rr *icmp_packet; int ret = NET_RX_DROP; @@ -886,23 +918,13 @@ static int recv_my_icmp_packet(struct bat_priv *bat_priv, /* answer echo request (ping) */ /* get routing information */ - rcu_read_lock(); orig_node = orig_hash_find(bat_priv, icmp_packet->orig); - if (!orig_node) - goto unlock; - - neigh_node = orig_node->router; - - if (!neigh_node) - goto unlock; - - if (!atomic_inc_not_zero(&neigh_node->refcount)) { - neigh_node = NULL; - goto unlock; - } + goto out; - rcu_read_unlock(); + router = orig_node_get_router(orig_node); + if (!router) + goto out; /* create a copy of the skb, if needed, to modify it. */ if (skb_cow(skb, sizeof(struct ethhdr)) < 0) @@ -916,15 +938,12 @@ static int recv_my_icmp_packet(struct bat_priv *bat_priv, icmp_packet->msg_type = ECHO_REPLY; icmp_packet->ttl = TTL; - send_skb_packet(skb, neigh_node->if_incoming, neigh_node->addr); + send_skb_packet(skb, router->if_incoming, router->addr); ret = NET_RX_SUCCESS; - goto out; -unlock: - rcu_read_unlock(); out: - if (neigh_node) - neigh_node_free_ref(neigh_node); + if (router) + neigh_node_free_ref(router); if (orig_node) orig_node_free_ref(orig_node); return ret; @@ -934,7 +953,7 @@ static int recv_icmp_ttl_exceeded(struct bat_priv *bat_priv, struct sk_buff *skb) { struct orig_node *orig_node = NULL; - struct neigh_node *neigh_node = NULL; + struct neigh_node *router = NULL; struct icmp_packet *icmp_packet; int ret = NET_RX_DROP; @@ -952,23 +971,13 @@ static int recv_icmp_ttl_exceeded(struct bat_priv *bat_priv, goto out; /* get routing information */ - rcu_read_lock(); orig_node = orig_hash_find(bat_priv, icmp_packet->orig); - if (!orig_node) - goto unlock; - - neigh_node = orig_node->router; - - if (!neigh_node) - goto unlock; - - if (!atomic_inc_not_zero(&neigh_node->refcount)) { - neigh_node = NULL; - goto unlock; - } + goto out; - rcu_read_unlock(); + router = orig_node_get_router(orig_node); + if (!router) + goto out; /* create a copy of the skb, if needed, to modify it. */ if (skb_cow(skb, sizeof(struct ethhdr)) < 0) @@ -982,15 +991,12 @@ static int recv_icmp_ttl_exceeded(struct bat_priv *bat_priv, icmp_packet->msg_type = TTL_EXCEEDED; icmp_packet->ttl = TTL; - send_skb_packet(skb, neigh_node->if_incoming, neigh_node->addr); + send_skb_packet(skb, router->if_incoming, router->addr); ret = NET_RX_SUCCESS; - goto out; -unlock: - rcu_read_unlock(); out: - if (neigh_node) - neigh_node_free_ref(neigh_node); + if (router) + neigh_node_free_ref(router); if (orig_node) orig_node_free_ref(orig_node); return ret; @@ -1003,7 +1009,7 @@ int recv_icmp_packet(struct sk_buff *skb, struct hard_iface *recv_if) struct icmp_packet_rr *icmp_packet; struct ethhdr *ethhdr; struct orig_node *orig_node = NULL; - struct neigh_node *neigh_node = NULL; + struct neigh_node *router = NULL; int hdr_size = sizeof(struct icmp_packet); int ret = NET_RX_DROP; @@ -1050,23 +1056,13 @@ int recv_icmp_packet(struct sk_buff *skb, struct hard_iface *recv_if) return recv_icmp_ttl_exceeded(bat_priv, skb); /* get routing information */ - rcu_read_lock(); orig_node = orig_hash_find(bat_priv, icmp_packet->dst); - if (!orig_node) - goto unlock; - - neigh_node = orig_node->router; - - if (!neigh_node) - goto unlock; - - if (!atomic_inc_not_zero(&neigh_node->refcount)) { - neigh_node = NULL; - goto unlock; - } + goto out; - rcu_read_unlock(); + router = orig_node_get_router(orig_node); + if (!router) + goto out; /* create a copy of the skb, if needed, to modify it. */ if (skb_cow(skb, sizeof(struct ethhdr)) < 0) @@ -1078,15 +1074,12 @@ int recv_icmp_packet(struct sk_buff *skb, struct hard_iface *recv_if) icmp_packet->ttl--; /* route it */ - send_skb_packet(skb, neigh_node->if_incoming, neigh_node->addr); + send_skb_packet(skb, router->if_incoming, router->addr); ret = NET_RX_SUCCESS; - goto out; -unlock: - rcu_read_unlock(); out: - if (neigh_node) - neigh_node_free_ref(neigh_node); + if (router) + neigh_node_free_ref(router); if (orig_node) orig_node_free_ref(orig_node); return ret; @@ -1208,7 +1201,8 @@ struct neigh_node *find_router(struct bat_priv *bat_priv, if (!orig_node) return NULL; - if (!orig_node->router) + router = orig_node_get_router(orig_node); + if (!router) return NULL; /* without bonding, the first node should @@ -1217,9 +1211,8 @@ struct neigh_node *find_router(struct bat_priv *bat_priv, rcu_read_lock(); /* select default router to output */ - router = orig_node->router; - router_orig = orig_node->router->orig_node; - if (!router_orig || !atomic_inc_not_zero(&router->refcount)) { + router_orig = router->orig_node; + if (!router_orig) { rcu_read_unlock(); return NULL; } @@ -1251,7 +1244,6 @@ struct neigh_node *find_router(struct bat_priv *bat_priv, if (atomic_read(&primary_orig_node->bond_candidates) < 2) goto return_router; - /* all nodes between should choose a candidate which * is is not on the interface where the packet came * in. */ diff --git a/net/batman-adv/send.c b/net/batman-adv/send.c index d49e54d..e78670c 100644 --- a/net/batman-adv/send.c +++ b/net/batman-adv/send.c @@ -308,6 +308,7 @@ void schedule_forward_packet(struct orig_node *orig_node, struct hard_iface *if_incoming) { struct bat_priv *bat_priv = netdev_priv(if_incoming->soft_iface); + struct neigh_node *router; unsigned char in_tq, in_ttl, tq_avg = 0; unsigned long send_time; @@ -316,6 +317,8 @@ void schedule_forward_packet(struct orig_node *orig_node, return; } + router = orig_node_get_router(orig_node); + in_tq = batman_packet->tq; in_ttl = batman_packet->ttl; @@ -324,20 +327,22 @@ void schedule_forward_packet(struct orig_node *orig_node, /* rebroadcast tq of our best ranking neighbor to ensure the rebroadcast * of our best tq value */ - if ((orig_node->router) && (orig_node->router->tq_avg != 0)) { + if (router && router->tq_avg != 0) { /* rebroadcast ogm of best ranking neighbor as is */ - if (!compare_eth(orig_node->router->addr, ethhdr->h_source)) { - batman_packet->tq = orig_node->router->tq_avg; + if (!compare_eth(router->addr, ethhdr->h_source)) { + batman_packet->tq = router->tq_avg; - if (orig_node->router->last_ttl) - batman_packet->ttl = orig_node->router->last_ttl - - 1; + if (router->last_ttl) + batman_packet->ttl = router->last_ttl - 1; } - tq_avg = orig_node->router->tq_avg; + tq_avg = router->tq_avg; } + if (router) + neigh_node_free_ref(router); + /* apply hop penalty */ batman_packet->tq = hop_penalty(batman_packet->tq, bat_priv); diff --git a/net/batman-adv/types.h b/net/batman-adv/types.h index 83445cf..1854cbb 100644 --- a/net/batman-adv/types.h +++ b/net/batman-adv/types.h @@ -67,7 +67,7 @@ struct hard_iface { struct orig_node { uint8_t orig[ETH_ALEN]; uint8_t primary_addr[ETH_ALEN]; - struct neigh_node *router; + struct neigh_node __rcu *router; /* rcu protected pointer */ unsigned long *bcast_own; uint8_t *bcast_own_sum; unsigned long last_valid; @@ -83,7 +83,7 @@ struct orig_node { uint32_t last_bcast_seqno; struct hlist_head neigh_list; struct list_head frag_list; - spinlock_t neigh_list_lock; /* protects neighbor list */ + spinlock_t neigh_list_lock; /* protects neigh_list and router */ atomic_t refcount; struct rcu_head rcu; struct hlist_node hash_entry; diff --git a/net/batman-adv/vis.c b/net/batman-adv/vis.c index f90212f..d4cc4f5 100644 --- a/net/batman-adv/vis.c +++ b/net/batman-adv/vis.c @@ -558,6 +558,7 @@ static int find_best_vis_server(struct bat_priv *bat_priv, struct vis_info *info) { struct hashtable_t *hash = bat_priv->orig_hash; + struct neigh_node *router; struct hlist_node *node; struct hlist_head *head; struct orig_node *orig_node; @@ -571,13 +572,17 @@ static int find_best_vis_server(struct bat_priv *bat_priv, rcu_read_lock(); hlist_for_each_entry_rcu(orig_node, node, head, hash_entry) { - if ((orig_node) && (orig_node->router) && - (orig_node->flags & VIS_SERVER) && - (orig_node->router->tq_avg > best_tq)) { - best_tq = orig_node->router->tq_avg; + router = orig_node_get_router(orig_node); + if (!router) + continue; + + if ((orig_node->flags & VIS_SERVER) && + (router->tq_avg > best_tq)) { + best_tq = router->tq_avg; memcpy(packet->target_orig, orig_node->orig, ETH_ALEN); } + neigh_node_free_ref(router); } rcu_read_unlock(); } @@ -605,7 +610,7 @@ static int generate_vis_packet(struct bat_priv *bat_priv) struct hlist_node *node; struct hlist_head *head; struct orig_node *orig_node; - struct neigh_node *neigh_node; + struct neigh_node *router; struct vis_info *info = (struct vis_info *)bat_priv->my_vis_info; struct vis_packet *packet = (struct vis_packet *)info->skb_packet->data; struct vis_info_entry *entry; @@ -633,30 +638,32 @@ static int generate_vis_packet(struct bat_priv *bat_priv) rcu_read_lock(); hlist_for_each_entry_rcu(orig_node, node, head, hash_entry) { - neigh_node = orig_node->router; - - if (!neigh_node) + router = orig_node_get_router(orig_node); + if (!router) continue; - if (!compare_eth(neigh_node->addr, orig_node->orig)) - continue; + if (!compare_eth(router->addr, orig_node->orig)) + goto next; - if (neigh_node->if_incoming->if_status != IF_ACTIVE) - continue; + if (router->if_incoming->if_status != IF_ACTIVE) + goto next; - if (neigh_node->tq_avg < 1) - continue; + if (router->tq_avg < 1) + goto next; /* fill one entry into buffer. */ entry = (struct vis_info_entry *) skb_put(info->skb_packet, sizeof(*entry)); memcpy(entry->src, - neigh_node->if_incoming->net_dev->dev_addr, + router->if_incoming->net_dev->dev_addr, ETH_ALEN); memcpy(entry->dest, orig_node->orig, ETH_ALEN); - entry->quality = neigh_node->tq_avg; + entry->quality = router->tq_avg; packet->entries++; +next: + neigh_node_free_ref(router); + if (vis_packet_full(info)) goto unlock; } @@ -725,6 +732,7 @@ static void purge_vis_packets(struct bat_priv *bat_priv) static void broadcast_vis_packet(struct bat_priv *bat_priv, struct vis_info *info) { + struct neigh_node *router; struct hashtable_t *hash = bat_priv->orig_hash; struct hlist_node *node; struct hlist_head *head; @@ -745,19 +753,26 @@ static void broadcast_vis_packet(struct bat_priv *bat_priv, rcu_read_lock(); hlist_for_each_entry_rcu(orig_node, node, head, hash_entry) { /* if it's a vis server and reachable, send it. */ - if ((!orig_node) || (!orig_node->router)) - continue; if (!(orig_node->flags & VIS_SERVER)) continue; + + router = orig_node_get_router(orig_node); + if (!router) + continue; + /* don't send it if we already received the packet from - * this node. */ + * this node. */ if (recv_list_is_in(bat_priv, &info->recv_list, - orig_node->orig)) + orig_node->orig)) { + neigh_node_free_ref(router); continue; + } memcpy(packet->target_orig, orig_node->orig, ETH_ALEN); - hard_iface = orig_node->router->if_incoming; - memcpy(dstaddr, orig_node->router->addr, ETH_ALEN); + hard_iface = router->if_incoming; + memcpy(dstaddr, router->addr, ETH_ALEN); + + neigh_node_free_ref(router); skb = skb_clone(info->skb_packet, GFP_ATOMIC); if (skb) @@ -772,45 +787,29 @@ static void unicast_vis_packet(struct bat_priv *bat_priv, struct vis_info *info) { struct orig_node *orig_node; - struct neigh_node *neigh_node = NULL; + struct neigh_node *router = NULL; struct sk_buff *skb; struct vis_packet *packet; packet = (struct vis_packet *)info->skb_packet->data; - rcu_read_lock(); orig_node = orig_hash_find(bat_priv, packet->target_orig); - if (!orig_node) - goto unlock; + goto out; - neigh_node = orig_node->router; - - if (!neigh_node) - goto unlock; - - if (!atomic_inc_not_zero(&neigh_node->refcount)) { - neigh_node = NULL; - goto unlock; - } - - rcu_read_unlock(); + router = orig_node_get_router(orig_node); + if (!router) + goto out; skb = skb_clone(info->skb_packet, GFP_ATOMIC); if (skb) - send_skb_packet(skb, neigh_node->if_incoming, - neigh_node->addr); - - goto out; + send_skb_packet(skb, router->if_incoming, router->addr); -unlock: - rcu_read_unlock(); out: - if (neigh_node) - neigh_node_free_ref(neigh_node); + if (router) + neigh_node_free_ref(router); if (orig_node) orig_node_free_ref(orig_node); - return; } /* only send one vis packet. called from send_vis_packets() */ -- cgit v0.10.2 From 68003903e4eeec5288f074ff0751a381750ceb34 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Linus=20L=C3=BCssing?= Date: Mon, 14 Mar 2011 22:43:40 +0000 Subject: batman-adv: Protect global TQ window with a spinlock MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Linus Lüssing Signed-off-by: Marek Lindner Signed-off-by: Sven Eckelmann diff --git a/net/batman-adv/originator.c b/net/batman-adv/originator.c index b4cfe36..5b8fe32 100644 --- a/net/batman-adv/originator.c +++ b/net/batman-adv/originator.c @@ -102,6 +102,7 @@ struct neigh_node *create_neighbor(struct orig_node *orig_node, INIT_HLIST_NODE(&neigh_node->list); INIT_LIST_HEAD(&neigh_node->bonding_list); + spin_lock_init(&neigh_node->tq_lock); memcpy(neigh_node->addr, neigh, ETH_ALEN); neigh_node->orig_node = orig_neigh_node; diff --git a/net/batman-adv/routing.c b/net/batman-adv/routing.c index b7d43ca..f6c6422 100644 --- a/net/batman-adv/routing.c +++ b/net/batman-adv/routing.c @@ -415,10 +415,12 @@ static void update_orig(struct bat_priv *bat_priv, if (is_duplicate) continue; + spin_lock_bh(&tmp_neigh_node->tq_lock); ring_buffer_set(tmp_neigh_node->tq_recv, &tmp_neigh_node->tq_index, 0); tmp_neigh_node->tq_avg = ring_buffer_avg(tmp_neigh_node->tq_recv); + spin_unlock_bh(&tmp_neigh_node->tq_lock); } if (!neigh_node) { @@ -443,10 +445,12 @@ static void update_orig(struct bat_priv *bat_priv, orig_node->flags = batman_packet->flags; neigh_node->last_valid = jiffies; + spin_lock_bh(&neigh_node->tq_lock); ring_buffer_set(neigh_node->tq_recv, &neigh_node->tq_index, batman_packet->tq); neigh_node->tq_avg = ring_buffer_avg(neigh_node->tq_recv); + spin_unlock_bh(&neigh_node->tq_lock); if (!is_duplicate) { orig_node->last_ttl = batman_packet->ttl; diff --git a/net/batman-adv/types.h b/net/batman-adv/types.h index 1854cbb..091476d 100644 --- a/net/batman-adv/types.h +++ b/net/batman-adv/types.h @@ -125,6 +125,7 @@ struct neigh_node { struct rcu_head rcu; struct orig_node *orig_node; struct hard_iface *if_incoming; + spinlock_t tq_lock; /* protects: tq_recv, tq_index */ }; -- cgit v0.10.2 From c4aac1ab9b973798163b34939b522f01e4d28ac9 Mon Sep 17 00:00:00 2001 From: Marek Lindner Date: Wed, 23 Mar 2011 11:24:34 +0100 Subject: batman-adv: concentrate all curr_gw related rcu operations in select/deselect functions Signed-off-by: Marek Lindner Signed-off-by: Sven Eckelmann diff --git a/net/batman-adv/gateway_client.c b/net/batman-adv/gateway_client.c index 42a8a7b..2acd7a66 100644 --- a/net/batman-adv/gateway_client.c +++ b/net/batman-adv/gateway_client.c @@ -43,61 +43,75 @@ static void gw_node_free_ref(struct gw_node *gw_node) call_rcu(&gw_node->rcu, gw_node_free_rcu); } -struct orig_node *gw_get_selected(struct bat_priv *bat_priv) +static struct gw_node *gw_get_selected_gw_node(struct bat_priv *bat_priv) { - struct gw_node *curr_gateway_tmp; - struct orig_node *orig_node = NULL; + struct gw_node *gw_node; rcu_read_lock(); - curr_gateway_tmp = rcu_dereference(bat_priv->curr_gw); - if (!curr_gateway_tmp) - goto out; - - orig_node = curr_gateway_tmp->orig_node; - if (!orig_node) + gw_node = rcu_dereference(bat_priv->curr_gw); + if (!gw_node) goto out; - if (!atomic_inc_not_zero(&orig_node->refcount)) - orig_node = NULL; + if (!atomic_inc_not_zero(&gw_node->refcount)) + gw_node = NULL; out: rcu_read_unlock(); - return orig_node; + return gw_node; } -void gw_deselect(struct bat_priv *bat_priv) +struct orig_node *gw_get_selected_orig(struct bat_priv *bat_priv) { struct gw_node *gw_node; + struct orig_node *orig_node = NULL; - spin_lock_bh(&bat_priv->gw_list_lock); - gw_node = rcu_dereference(bat_priv->curr_gw); - rcu_assign_pointer(bat_priv->curr_gw, NULL); - spin_unlock_bh(&bat_priv->gw_list_lock); + gw_node = gw_get_selected_gw_node(bat_priv); + if (!gw_node) + goto out; + + rcu_read_lock(); + orig_node = gw_node->orig_node; + if (!orig_node) + goto unlock; + + if (!atomic_inc_not_zero(&orig_node->refcount)) + orig_node = NULL; +unlock: + rcu_read_unlock(); +out: if (gw_node) gw_node_free_ref(gw_node); + return orig_node; } static void gw_select(struct bat_priv *bat_priv, struct gw_node *new_gw_node) { struct gw_node *curr_gw_node; + spin_lock_bh(&bat_priv->gw_list_lock); + if (new_gw_node && !atomic_inc_not_zero(&new_gw_node->refcount)) new_gw_node = NULL; - spin_lock_bh(&bat_priv->gw_list_lock); - curr_gw_node = rcu_dereference(bat_priv->curr_gw); + curr_gw_node = bat_priv->curr_gw; rcu_assign_pointer(bat_priv->curr_gw, new_gw_node); - spin_unlock_bh(&bat_priv->gw_list_lock); if (curr_gw_node) gw_node_free_ref(curr_gw_node); + + spin_unlock_bh(&bat_priv->gw_list_lock); +} + +void gw_deselect(struct bat_priv *bat_priv) +{ + gw_select(bat_priv, NULL); } void gw_election(struct bat_priv *bat_priv) { struct hlist_node *node; - struct gw_node *gw_node, *curr_gw, *curr_gw_tmp = NULL; + struct gw_node *gw_node, *curr_gw = NULL, *curr_gw_tmp = NULL; struct neigh_node *router; uint8_t max_tq = 0; uint32_t max_gw_factor = 0, tmp_gw_factor = 0; @@ -112,25 +126,17 @@ void gw_election(struct bat_priv *bat_priv) if (atomic_read(&bat_priv->gw_mode) != GW_MODE_CLIENT) return; - rcu_read_lock(); - curr_gw = rcu_dereference(bat_priv->curr_gw); - if (curr_gw) { - rcu_read_unlock(); - return; - } + curr_gw = gw_get_selected_gw_node(bat_priv); + if (!curr_gw) + goto out; + rcu_read_lock(); if (hlist_empty(&bat_priv->gw_list)) { - - if (curr_gw) { - rcu_read_unlock(); - bat_dbg(DBG_BATMAN, bat_priv, - "Removing selected gateway - " - "no gateway in range\n"); - gw_deselect(bat_priv); - } else - rcu_read_unlock(); - - return; + bat_dbg(DBG_BATMAN, bat_priv, + "Removing selected gateway - " + "no gateway in range\n"); + gw_deselect(bat_priv); + goto unlock; } hlist_for_each_entry_rcu(gw_node, node, &bat_priv->gw_list, list) { @@ -182,7 +188,7 @@ void gw_election(struct bat_priv *bat_priv) if (curr_gw != curr_gw_tmp) { router = orig_node_get_router(curr_gw_tmp->orig_node); if (!router) - goto out; + goto unlock; if ((curr_gw) && (!curr_gw_tmp)) bat_dbg(DBG_BATMAN, bat_priv, @@ -207,8 +213,11 @@ void gw_election(struct bat_priv *bat_priv) gw_select(bat_priv, curr_gw_tmp); } -out: +unlock: rcu_read_unlock(); +out: + if (curr_gw) + gw_node_free_ref(curr_gw); } void gw_check_election(struct bat_priv *bat_priv, struct orig_node *orig_node) @@ -217,7 +226,7 @@ void gw_check_election(struct bat_priv *bat_priv, struct orig_node *orig_node) struct neigh_node *router_gw = NULL, *router_orig = NULL; uint8_t gw_tq_avg, orig_tq_avg; - curr_gw_orig = gw_get_selected(bat_priv); + curr_gw_orig = gw_get_selected_orig(bat_priv); if (!curr_gw_orig) goto deselect; @@ -299,7 +308,11 @@ void gw_node_update(struct bat_priv *bat_priv, struct orig_node *orig_node, uint8_t new_gwflags) { struct hlist_node *node; - struct gw_node *gw_node; + struct gw_node *gw_node, *curr_gw; + + curr_gw = gw_get_selected_gw_node(bat_priv); + if (!curr_gw) + goto out; rcu_read_lock(); hlist_for_each_entry_rcu(gw_node, node, &bat_priv->gw_list, list) { @@ -320,22 +333,26 @@ void gw_node_update(struct bat_priv *bat_priv, "Gateway %pM removed from gateway list\n", orig_node->orig); - if (gw_node == rcu_dereference(bat_priv->curr_gw)) { - rcu_read_unlock(); - gw_deselect(bat_priv); - return; - } + if (gw_node == curr_gw) + goto deselect; } - rcu_read_unlock(); - return; + goto unlock; } - rcu_read_unlock(); if (new_gwflags == 0) - return; + goto unlock; gw_node_add(bat_priv, orig_node, new_gwflags); + goto unlock; + +deselect: + gw_deselect(bat_priv); +unlock: + rcu_read_unlock(); +out: + if (curr_gw) + gw_node_free_ref(curr_gw); } void gw_node_delete(struct bat_priv *bat_priv, struct orig_node *orig_node) @@ -345,9 +362,12 @@ void gw_node_delete(struct bat_priv *bat_priv, struct orig_node *orig_node) void gw_node_purge(struct bat_priv *bat_priv) { - struct gw_node *gw_node; + struct gw_node *gw_node, *curr_gw; struct hlist_node *node, *node_tmp; unsigned long timeout = 2 * PURGE_TIMEOUT * HZ; + char do_deselect = 0; + + curr_gw = gw_get_selected_gw_node(bat_priv); spin_lock_bh(&bat_priv->gw_list_lock); @@ -358,15 +378,21 @@ void gw_node_purge(struct bat_priv *bat_priv) atomic_read(&bat_priv->mesh_state) == MESH_ACTIVE) continue; - if (rcu_dereference(bat_priv->curr_gw) == gw_node) - gw_deselect(bat_priv); + if (curr_gw == gw_node) + do_deselect = 1; hlist_del_rcu(&gw_node->list); gw_node_free_ref(gw_node); } - spin_unlock_bh(&bat_priv->gw_list_lock); + + /* gw_deselect() needs to acquire the gw_list_lock */ + if (do_deselect) + gw_deselect(bat_priv); + + if (curr_gw) + gw_node_free_ref(curr_gw); } /** @@ -385,22 +411,22 @@ static int _write_buffer_text(struct bat_priv *bat_priv, if (!router) goto out; - rcu_read_lock(); - curr_gw = rcu_dereference(bat_priv->curr_gw); + curr_gw = gw_get_selected_gw_node(bat_priv); ret = seq_printf(seq, "%s %pM (%3i) %pM [%10s]: %3i - %i%s/%i%s\n", - (curr_gw == gw_node ? "=>" : " "), - gw_node->orig_node->orig, - router->tq_avg, router->addr, - router->if_incoming->net_dev->name, - gw_node->orig_node->gw_flags, - (down > 2048 ? down / 1024 : down), - (down > 2048 ? "MBit" : "KBit"), - (up > 2048 ? up / 1024 : up), - (up > 2048 ? "MBit" : "KBit")); + (curr_gw == gw_node ? "=>" : " "), + gw_node->orig_node->orig, + router->tq_avg, router->addr, + router->if_incoming->net_dev->name, + gw_node->orig_node->gw_flags, + (down > 2048 ? down / 1024 : down), + (down > 2048 ? "MBit" : "KBit"), + (up > 2048 ? up / 1024 : up), + (up > 2048 ? "MBit" : "KBit")); - rcu_read_unlock(); neigh_node_free_ref(router); + if (curr_gw) + gw_node_free_ref(curr_gw); out: return ret; } @@ -459,6 +485,7 @@ int gw_is_target(struct bat_priv *bat_priv, struct sk_buff *skb) struct iphdr *iphdr; struct ipv6hdr *ipv6hdr; struct udphdr *udphdr; + struct gw_node *curr_gw; unsigned int header_len = 0; if (atomic_read(&bat_priv->gw_mode) == GW_MODE_OFF) @@ -523,12 +550,11 @@ int gw_is_target(struct bat_priv *bat_priv, struct sk_buff *skb) if (atomic_read(&bat_priv->gw_mode) == GW_MODE_SERVER) return -1; - rcu_read_lock(); - if (!rcu_dereference(bat_priv->curr_gw)) { - rcu_read_unlock(); + curr_gw = gw_get_selected_gw_node(bat_priv); + if (!curr_gw) return 0; - } - rcu_read_unlock(); + if (curr_gw) + gw_node_free_ref(curr_gw); return 1; } diff --git a/net/batman-adv/gateway_client.h b/net/batman-adv/gateway_client.h index 97c31d1..1ce8c60 100644 --- a/net/batman-adv/gateway_client.h +++ b/net/batman-adv/gateway_client.h @@ -24,7 +24,7 @@ void gw_deselect(struct bat_priv *bat_priv); void gw_election(struct bat_priv *bat_priv); -struct orig_node *gw_get_selected(struct bat_priv *bat_priv); +struct orig_node *gw_get_selected_orig(struct bat_priv *bat_priv); void gw_check_election(struct bat_priv *bat_priv, struct orig_node *orig_node); void gw_node_update(struct bat_priv *bat_priv, struct orig_node *orig_node, uint8_t new_gwflags); diff --git a/net/batman-adv/unicast.c b/net/batman-adv/unicast.c index 19f84bd..d46acc8 100644 --- a/net/batman-adv/unicast.c +++ b/net/batman-adv/unicast.c @@ -289,7 +289,7 @@ int unicast_send_skb(struct sk_buff *skb, struct bat_priv *bat_priv) /* get routing information */ if (is_multicast_ether_addr(ethhdr->h_dest)) { - orig_node = (struct orig_node *)gw_get_selected(bat_priv); + orig_node = (struct orig_node *)gw_get_selected_orig(bat_priv); if (orig_node) goto find_router; } -- cgit v0.10.2 From ba85fac28005a59e6e03fdb13918fc6f6e69a3ca Mon Sep 17 00:00:00 2001 From: Simon Wunderlich Date: Sun, 17 Apr 2011 20:34:27 +0200 Subject: batman-adv: protect softif_neigh by rcu Add get/set wrapper functions for softif_neigh and use rcu functions to manipulate the pointers. Signed-off-by: Simon Wunderlich Signed-off-by: Marek Lindner Signed-off-by: Sven Eckelmann diff --git a/net/batman-adv/soft-interface.c b/net/batman-adv/soft-interface.c index 9ed2614..ad6da4c 100644 --- a/net/batman-adv/soft-interface.c +++ b/net/batman-adv/soft-interface.c @@ -90,10 +90,51 @@ static void softif_neigh_free_ref(struct softif_neigh *softif_neigh) call_rcu(&softif_neigh->rcu, softif_neigh_free_rcu); } +static struct softif_neigh *softif_neigh_get_selected(struct bat_priv *bat_priv) +{ + struct softif_neigh *neigh; + + rcu_read_lock(); + neigh = rcu_dereference(bat_priv->softif_neigh); + + if (neigh && !atomic_inc_not_zero(&neigh->refcount)) + neigh = NULL; + + rcu_read_unlock(); + return neigh; +} + +static void softif_neigh_select(struct bat_priv *bat_priv, + struct softif_neigh *new_neigh) +{ + struct softif_neigh *curr_neigh; + + spin_lock_bh(&bat_priv->softif_neigh_lock); + + if (new_neigh && !atomic_inc_not_zero(&new_neigh->refcount)) + new_neigh = NULL; + + curr_neigh = bat_priv->softif_neigh; + rcu_assign_pointer(bat_priv->softif_neigh, new_neigh); + + if (curr_neigh) + softif_neigh_free_ref(curr_neigh); + + spin_unlock_bh(&bat_priv->softif_neigh_lock); +} + +static void softif_neigh_deselect(struct bat_priv *bat_priv) +{ + softif_neigh_select(bat_priv, NULL); +} + void softif_neigh_purge(struct bat_priv *bat_priv) { - struct softif_neigh *softif_neigh, *softif_neigh_tmp; + struct softif_neigh *softif_neigh, *curr_softif_neigh; struct hlist_node *node, *node_tmp; + char do_deselect = 0; + + curr_softif_neigh = softif_neigh_get_selected(bat_priv); spin_lock_bh(&bat_priv->softif_neigh_lock); @@ -105,22 +146,26 @@ void softif_neigh_purge(struct bat_priv *bat_priv) (atomic_read(&bat_priv->mesh_state) == MESH_ACTIVE)) continue; - hlist_del_rcu(&softif_neigh->list); - - if (bat_priv->softif_neigh == softif_neigh) { + if (curr_softif_neigh == softif_neigh) { bat_dbg(DBG_ROUTES, bat_priv, "Current mesh exit point '%pM' vanished " "(vid: %d).\n", softif_neigh->addr, softif_neigh->vid); - softif_neigh_tmp = bat_priv->softif_neigh; - bat_priv->softif_neigh = NULL; - softif_neigh_free_ref(softif_neigh_tmp); + do_deselect = 1; } + hlist_del_rcu(&softif_neigh->list); softif_neigh_free_ref(softif_neigh); } spin_unlock_bh(&bat_priv->softif_neigh_lock); + + /* soft_neigh_deselect() needs to acquire the softif_neigh_lock */ + if (do_deselect) + softif_neigh_deselect(bat_priv); + + if (curr_softif_neigh) + softif_neigh_free_ref(curr_softif_neigh); } static struct softif_neigh *softif_neigh_get(struct bat_priv *bat_priv, @@ -171,6 +216,7 @@ int softif_neigh_seq_print_text(struct seq_file *seq, void *offset) struct bat_priv *bat_priv = netdev_priv(net_dev); struct softif_neigh *softif_neigh; struct hlist_node *node; + struct softif_neigh *curr_softif_neigh; if (!bat_priv->primary_if) { return seq_printf(seq, "BATMAN mesh %s disabled - " @@ -180,14 +226,17 @@ int softif_neigh_seq_print_text(struct seq_file *seq, void *offset) seq_printf(seq, "Softif neighbor list (%s)\n", net_dev->name); + curr_softif_neigh = softif_neigh_get_selected(bat_priv); rcu_read_lock(); hlist_for_each_entry_rcu(softif_neigh, node, &bat_priv->softif_neigh_list, list) seq_printf(seq, "%s %pM (vid: %d)\n", - bat_priv->softif_neigh == softif_neigh + curr_softif_neigh == softif_neigh ? "=>" : " ", softif_neigh->addr, softif_neigh->vid); rcu_read_unlock(); + if (curr_softif_neigh) + softif_neigh_free_ref(curr_softif_neigh); return 0; } @@ -198,7 +247,8 @@ static void softif_batman_recv(struct sk_buff *skb, struct net_device *dev, struct bat_priv *bat_priv = netdev_priv(dev); struct ethhdr *ethhdr = (struct ethhdr *)skb->data; struct batman_packet *batman_packet; - struct softif_neigh *softif_neigh, *softif_neigh_tmp; + struct softif_neigh *softif_neigh; + struct softif_neigh *curr_softif_neigh = NULL; if (ntohs(ethhdr->h_proto) == ETH_P_8021Q) batman_packet = (struct batman_packet *) @@ -223,7 +273,8 @@ static void softif_batman_recv(struct sk_buff *skb, struct net_device *dev, if (!softif_neigh) goto err; - if (bat_priv->softif_neigh == softif_neigh) + curr_softif_neigh = softif_neigh_get_selected(bat_priv); + if (curr_softif_neigh == softif_neigh) goto out; /* we got a neighbor but its mac is 'bigger' than ours */ @@ -232,38 +283,39 @@ static void softif_batman_recv(struct sk_buff *skb, struct net_device *dev, goto out; /* switch to new 'smallest neighbor' */ - if ((bat_priv->softif_neigh) && - (memcmp(softif_neigh->addr, bat_priv->softif_neigh->addr, + if ((curr_softif_neigh) && + (memcmp(softif_neigh->addr, curr_softif_neigh->addr, ETH_ALEN) < 0)) { bat_dbg(DBG_ROUTES, bat_priv, "Changing mesh exit point from %pM (vid: %d) " "to %pM (vid: %d).\n", - bat_priv->softif_neigh->addr, - bat_priv->softif_neigh->vid, + curr_softif_neigh->addr, + curr_softif_neigh->vid, softif_neigh->addr, softif_neigh->vid); - softif_neigh_tmp = bat_priv->softif_neigh; - bat_priv->softif_neigh = softif_neigh; - softif_neigh_free_ref(softif_neigh_tmp); - /* we need to hold the additional reference */ - goto err; + + softif_neigh_select(bat_priv, softif_neigh); + goto out; } /* close own batX device and use softif_neigh as exit node */ - if ((!bat_priv->softif_neigh) && + if ((!curr_softif_neigh) && (memcmp(softif_neigh->addr, bat_priv->primary_if->net_dev->dev_addr, ETH_ALEN) < 0)) { bat_dbg(DBG_ROUTES, bat_priv, "Setting mesh exit point to %pM (vid: %d).\n", softif_neigh->addr, softif_neigh->vid); - bat_priv->softif_neigh = softif_neigh; - /* we need to hold the additional reference */ - goto err; + + softif_neigh_select(bat_priv, softif_neigh); + goto out; } out: softif_neigh_free_ref(softif_neigh); err: kfree_skb(skb); + if (curr_softif_neigh) + softif_neigh_free_ref(curr_softif_neigh); + return; } @@ -321,6 +373,7 @@ int interface_tx(struct sk_buff *skb, struct net_device *soft_iface) struct bat_priv *bat_priv = netdev_priv(soft_iface); struct bcast_packet *bcast_packet; struct vlan_ethhdr *vhdr; + struct softif_neigh *curr_softif_neigh = NULL; int data_len = skb->len, ret; short vid = -1; bool do_bcast = false; @@ -348,7 +401,8 @@ int interface_tx(struct sk_buff *skb, struct net_device *soft_iface) * if we have a another chosen mesh exit node in range * it will transport the packets to the mesh */ - if ((bat_priv->softif_neigh) && (bat_priv->softif_neigh->vid == vid)) + curr_softif_neigh = softif_neigh_get_selected(bat_priv); + if ((curr_softif_neigh) && (curr_softif_neigh->vid == vid)) goto dropped; /* TODO: check this for locks */ @@ -410,6 +464,8 @@ dropped: dropped_freed: bat_priv->stats.tx_dropped++; end: + if (curr_softif_neigh) + softif_neigh_free_ref(curr_softif_neigh); return NETDEV_TX_OK; } @@ -421,6 +477,7 @@ void interface_rx(struct net_device *soft_iface, struct unicast_packet *unicast_packet; struct ethhdr *ethhdr; struct vlan_ethhdr *vhdr; + struct softif_neigh *curr_softif_neigh = NULL; short vid = -1; int ret; @@ -450,7 +507,8 @@ void interface_rx(struct net_device *soft_iface, * if we have a another chosen mesh exit node in range * it will transport the packets to the non-mesh network */ - if ((bat_priv->softif_neigh) && (bat_priv->softif_neigh->vid == vid)) { + curr_softif_neigh = softif_neigh_get_selected(bat_priv); + if (curr_softif_neigh && (curr_softif_neigh->vid == vid)) { skb_push(skb, hdr_size); unicast_packet = (struct unicast_packet *)skb->data; @@ -461,7 +519,7 @@ void interface_rx(struct net_device *soft_iface, skb_reset_mac_header(skb); memcpy(unicast_packet->dest, - bat_priv->softif_neigh->addr, ETH_ALEN); + curr_softif_neigh->addr, ETH_ALEN); ret = route_unicast_packet(skb, recv_if); if (ret == NET_RX_DROP) goto dropped; @@ -486,11 +544,13 @@ void interface_rx(struct net_device *soft_iface, soft_iface->last_rx = jiffies; netif_rx(skb); - return; + goto out; dropped: kfree_skb(skb); out: + if (curr_softif_neigh) + softif_neigh_free_ref(curr_softif_neigh); return; } diff --git a/net/batman-adv/types.h b/net/batman-adv/types.h index 091476d..75123b1 100644 --- a/net/batman-adv/types.h +++ b/net/batman-adv/types.h @@ -147,7 +147,7 @@ struct bat_priv { atomic_t batman_queue_left; char num_ifaces; struct hlist_head softif_neigh_list; - struct softif_neigh *softif_neigh; + struct softif_neigh __rcu *softif_neigh; struct debug_log *debug_log; struct hard_iface *primary_if; struct kobject *mesh_obj; -- cgit v0.10.2 From af20b710479ae662829cf739b521390daa7fcbcb Mon Sep 17 00:00:00 2001 From: Andrew Lunn Date: Sun, 17 Apr 2011 20:39:07 +0200 Subject: batman-adv: Set the txqueuelen to zero when creating soft interface MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Like other virtual interfaces, e.g. br0, we don't need a transmit queue. Packets should only be queued on real interfaces which are underneath. In practice this patch makes little difference since the virtual interfaces can accept packets as fast as they come, but the patch will avoid bufferbloat questions to the mailling lists in the future. Signed-off-by: Andrew Lunn Tested-by: Linus Lüssing Signed-off-by: Marek Lindner Signed-off-by: Sven Eckelmann diff --git a/net/batman-adv/soft-interface.c b/net/batman-adv/soft-interface.c index ad6da4c..58ce440 100644 --- a/net/batman-adv/soft-interface.c +++ b/net/batman-adv/soft-interface.c @@ -584,6 +584,7 @@ static void interface_setup(struct net_device *dev) dev->hard_start_xmit = interface_tx; #endif dev->destructor = free_netdev; + dev->tx_queue_len = 0; /** * can't call min_mtu, because the needed variables -- cgit v0.10.2 From a713c3bbb5a6736e673940eb97d9bf2c27aec4c5 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Sun, 17 Apr 2011 16:22:33 -0700 Subject: isdn: gigaset: Fix set-but-unused variable. The variable 'offset' is set but unused in write_iso_tasklet(). Just kill it off. Signed-off-by: David S. Miller diff --git a/drivers/isdn/gigaset/bas-gigaset.c b/drivers/isdn/gigaset/bas-gigaset.c index 8a3c5cf..3913f47 100644 --- a/drivers/isdn/gigaset/bas-gigaset.c +++ b/drivers/isdn/gigaset/bas-gigaset.c @@ -1157,7 +1157,6 @@ static void write_iso_tasklet(unsigned long data) struct urb *urb; int status; struct usb_iso_packet_descriptor *ifd; - int offset; unsigned long flags; int i; struct sk_buff *skb; @@ -1225,7 +1224,6 @@ static void write_iso_tasklet(unsigned long data) * successfully sent * - all following frames are not sent at all */ - offset = done->limit; /* default (no error) */ for (i = 0; i < BAS_NUMFRAMES; i++) { ifd = &urb->iso_frame_desc[i]; if (ifd->status || @@ -1235,9 +1233,6 @@ static void write_iso_tasklet(unsigned long data) i, ifd->actual_length, ifd->length, get_usb_statmsg(ifd->status)); - offset = (ifd->offset + - ifd->actual_length) - % BAS_OUTBUFSIZE; break; } } -- cgit v0.10.2 From 2d09d567127e85dddd027d049196093640025c36 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Sun, 17 Apr 2011 16:23:22 -0700 Subject: isdn: eicon: Fix set-but-unused variables. The variable 'best_id' is set but unused in diva_mnt_add_xdi_adapter(). Just kill it off. Similarly for the variable 'CIP' in connect_req(), 'Number' in sig_ind(), 'Info' in dtmf_confirmation() mixer_command() fax_connect_ack_command() fax_edata_ack_command() rtp_connect_b3_res_command() and rtp_connect_b3_res_command(), and 'a' in mixer_indication_coefs_set(), Signed-off-by: David S. Miller diff --git a/drivers/isdn/hardware/eicon/debug.c b/drivers/isdn/hardware/eicon/debug.c index 3626401..7a9894c 100644 --- a/drivers/isdn/hardware/eicon/debug.c +++ b/drivers/isdn/hardware/eicon/debug.c @@ -861,7 +861,7 @@ static int diva_get_idi_adapter_info (IDI_CALL request, dword* serial, dword* lo void diva_mnt_add_xdi_adapter (const DESCRIPTOR* d) { diva_os_spin_lock_magic_t old_irql, old_irql1; dword sec, usec, logical, serial, org_mask; - int id, best_id = 0, free_id = -1; + int id, free_id = -1; char tmp[128]; diva_dbg_entry_head_t* pmsg = NULL; int len; @@ -906,7 +906,6 @@ void diva_mnt_add_xdi_adapter (const DESCRIPTOR* d) { and slot is still free - reuse it */ free_id = id; - best_id = 1; break; } } diff --git a/drivers/isdn/hardware/eicon/message.c b/drivers/isdn/hardware/eicon/message.c index 8c5c563..a339598 100644 --- a/drivers/isdn/hardware/eicon/message.c +++ b/drivers/isdn/hardware/eicon/message.c @@ -1198,7 +1198,6 @@ static byte connect_req(dword Id, word Number, DIVA_CAPI_ADAPTER *a, word ch; word i; word Info; - word CIP; byte LinkLayer; API_PARSE * ai; API_PARSE * bp; @@ -1340,7 +1339,6 @@ static byte connect_req(dword Id, word Number, DIVA_CAPI_ADAPTER *a, add_s(plci,BC,&parms[6]); add_s(plci,LLC,&parms[7]); add_s(plci,HLC,&parms[8]); - CIP = GET_WORD(parms[0].info); if (a->Info_Mask[appl->Id-1] & 0x200) { /* early B3 connect (CIP mask bit 9) no release after a disc */ @@ -4830,7 +4828,6 @@ static void sig_ind(PLCI *plci) dword x_Id; dword Id; dword rId; - word Number = 0; word i; word cip; dword cip_mask; @@ -5106,7 +5103,7 @@ static void sig_ind(PLCI *plci) } } - if(plci->appl) Number = plci->appl->Number++; + if(plci->appl) plci->appl->Number++; switch(plci->Sig.Ind) { /* Response to Get_Supported_Services request */ @@ -5894,7 +5891,6 @@ static void sig_ind(PLCI *plci) break; case TEL_CTRL: - Number = 0; ie = multi_fac_parms[0]; /* inspect the facility hook indications */ if(plci->State==ADVANCED_VOICE_SIG && ie[0]){ switch (ie[1]&0x91) { @@ -10119,14 +10115,12 @@ static byte dtmf_request (dword Id, word Number, DIVA_CAPI_ADAPTER *a, PLCI static void dtmf_confirmation (dword Id, PLCI *plci) { - word Info; word i; byte result[4]; dbug (1, dprintf ("[%06lx] %s,%d: dtmf_confirmation", UnMapId (Id), (char *)(FILE_), __LINE__)); - Info = GOOD; result[0] = 2; PUT_WORD (&result[1], DTMF_SUCCESS); if (plci->dtmf_send_requests != 0) @@ -11520,13 +11514,12 @@ static word mixer_restore_config (dword Id, PLCI *plci, byte Rc) static void mixer_command (dword Id, PLCI *plci, byte Rc) { DIVA_CAPI_ADAPTER *a; - word i, internal_command, Info; + word i, internal_command; dbug (1, dprintf ("[%06lx] %s,%d: mixer_command %02x %04x %04x", UnMapId (Id), (char *)(FILE_), __LINE__, Rc, plci->internal_command, plci->li_cmd)); - Info = GOOD; a = plci->adapter; internal_command = plci->internal_command; plci->internal_command = 0; @@ -11550,7 +11543,6 @@ static void mixer_command (dword Id, PLCI *plci, byte Rc) { dbug (1, dprintf ("[%06lx] %s,%d: Load mixer failed", UnMapId (Id), (char *)(FILE_), __LINE__)); - Info = _FACILITY_NOT_SUPPORTED; break; } if (plci->internal_command) @@ -11592,7 +11584,6 @@ static void mixer_command (dword Id, PLCI *plci, byte Rc) } while ((plci->li_plci_b_write_pos != plci->li_plci_b_req_pos) && !(plci->li_plci_b_queue[i] & LI_PLCI_B_LAST_FLAG)); } - Info = _FACILITY_NOT_SUPPORTED; break; } if (plci->internal_command) @@ -11610,7 +11601,6 @@ static void mixer_command (dword Id, PLCI *plci, byte Rc) { dbug (1, dprintf ("[%06lx] %s,%d: Unload mixer failed", UnMapId (Id), (char *)(FILE_), __LINE__)); - Info = _FACILITY_NOT_SUPPORTED; break; } if (plci->internal_command) @@ -12448,13 +12438,11 @@ static byte mixer_request (dword Id, word Number, DIVA_CAPI_ADAPTER *a, PLCI static void mixer_indication_coefs_set (dword Id, PLCI *plci) { dword d; - DIVA_CAPI_ADAPTER *a; byte result[12]; dbug (1, dprintf ("[%06lx] %s,%d: mixer_indication_coefs_set", UnMapId (Id), (char *)(FILE_), __LINE__)); - a = plci->adapter; if (plci->li_plci_b_read_pos != plci->li_plci_b_req_pos) { do @@ -14111,13 +14099,11 @@ static void select_b_command (dword Id, PLCI *plci, byte Rc) static void fax_connect_ack_command (dword Id, PLCI *plci, byte Rc) { - word Info; word internal_command; dbug (1, dprintf ("[%06lx] %s,%d: fax_connect_ack_command %02x %04x", UnMapId (Id), (char *)(FILE_), __LINE__, Rc, plci->internal_command)); - Info = GOOD; internal_command = plci->internal_command; plci->internal_command = 0; switch (internal_command) @@ -14160,13 +14146,11 @@ static void fax_connect_ack_command (dword Id, PLCI *plci, byte Rc) static void fax_edata_ack_command (dword Id, PLCI *plci, byte Rc) { - word Info; word internal_command; dbug (1, dprintf ("[%06lx] %s,%d: fax_edata_ack_command %02x %04x", UnMapId (Id), (char *)(FILE_), __LINE__, Rc, plci->internal_command)); - Info = GOOD; internal_command = plci->internal_command; plci->internal_command = 0; switch (internal_command) @@ -14395,13 +14379,11 @@ static void rtp_connect_b3_req_command (dword Id, PLCI *plci, byte Rc) static void rtp_connect_b3_res_command (dword Id, PLCI *plci, byte Rc) { - word Info; word internal_command; dbug (1, dprintf ("[%06lx] %s,%d: rtp_connect_b3_res_command %02x %04x", UnMapId (Id), (char *)(FILE_), __LINE__, Rc, plci->internal_command)); - Info = GOOD; internal_command = plci->internal_command; plci->internal_command = 0; switch (internal_command) @@ -14423,7 +14405,6 @@ static void rtp_connect_b3_res_command (dword Id, PLCI *plci, byte Rc) { dbug (1, dprintf ("[%06lx] %s,%d: RTP setting connect resp info failed %02x", UnMapId (Id), (char *)(FILE_), __LINE__, Rc)); - Info = _WRONG_STATE; break; } if (plci_nl_busy (plci)) -- cgit v0.10.2 From a719e0a81f8ab1e96301aada203be1c43788aec7 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Sun, 17 Apr 2011 16:34:50 -0700 Subject: isdn: hfcpci: Fix set-but-unused variables. The variable 'total' is set but unused in hfcpci_empty_bfifo(). Just kill it off. Similarly for the variable 'val' in ph_state_nt(). Signed-off-by: David S. Miller diff --git a/drivers/isdn/hardware/mISDN/hfcpci.c b/drivers/isdn/hardware/mISDN/hfcpci.c index 4343aba..b01a7be 100644 --- a/drivers/isdn/hardware/mISDN/hfcpci.c +++ b/drivers/isdn/hardware/mISDN/hfcpci.c @@ -405,7 +405,7 @@ hfcpci_empty_bfifo(struct bchannel *bch, struct bzfifo *bz, u_char *bdata, int count) { u_char *ptr, *ptr1, new_f2; - int total, maxlen, new_z2; + int maxlen, new_z2; struct zt *zp; if ((bch->debug & DEBUG_HW_BCHANNEL) && !(bch->debug & DEBUG_HW_BFIFO)) @@ -431,7 +431,6 @@ hfcpci_empty_bfifo(struct bchannel *bch, struct bzfifo *bz, printk(KERN_WARNING "HFCPCI: receive out of memory\n"); return; } - total = count; count -= 3; ptr = skb_put(bch->rx_skb, count); @@ -968,7 +967,6 @@ static void ph_state_nt(struct dchannel *dch) { struct hfc_pci *hc = dch->hw; - u_char val; if (dch->debug) printk(KERN_DEBUG "%s: NT newstate %x\n", @@ -982,7 +980,7 @@ ph_state_nt(struct dchannel *dch) hc->hw.int_m1 &= ~HFCPCI_INTS_TIMER; Write_hfc(hc, HFCPCI_INT_M1, hc->hw.int_m1); /* Clear already pending ints */ - val = Read_hfc(hc, HFCPCI_INT_S1); + (void) Read_hfc(hc, HFCPCI_INT_S1); Write_hfc(hc, HFCPCI_STATES, 4 | HFCPCI_LOAD_STATE); udelay(10); Write_hfc(hc, HFCPCI_STATES, 4); -- cgit v0.10.2 From 3c76c58fca03c1162ab8592f71c996e933af3a9e Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Sun, 17 Apr 2011 16:35:27 -0700 Subject: isdn: hfcsusb: Fix set-but-unused variables. The variable 'buf' is set but unused in ctrl_complete(). Just kill it off. Similarly for the variable 'err' in setup_hfcsusb(). Signed-off-by: David S. Miller diff --git a/drivers/isdn/hardware/mISDN/hfcsusb.c b/drivers/isdn/hardware/mISDN/hfcsusb.c index 8700474..3ccbff1 100644 --- a/drivers/isdn/hardware/mISDN/hfcsusb.c +++ b/drivers/isdn/hardware/mISDN/hfcsusb.c @@ -118,14 +118,12 @@ static void ctrl_complete(struct urb *urb) { struct hfcsusb *hw = (struct hfcsusb *) urb->context; - struct ctrl_buf *buf; if (debug & DBG_HFC_CALL_TRACE) printk(KERN_DEBUG "%s: %s\n", hw->name, __func__); urb->dev = hw->dev; if (hw->ctrl_cnt) { - buf = &hw->ctrl_buff[hw->ctrl_out_idx]; hw->ctrl_cnt--; /* decrement actual count */ if (++hw->ctrl_out_idx >= HFC_CTRL_BUFSIZE) hw->ctrl_out_idx = 0; /* pointer wrap */ @@ -1726,7 +1724,6 @@ hfcsusb_stop_endpoint(struct hfcsusb *hw, int channel) static int setup_hfcsusb(struct hfcsusb *hw) { - int err; u_char b; if (debug & DBG_HFC_CALL_TRACE) @@ -1745,7 +1742,7 @@ setup_hfcsusb(struct hfcsusb *hw) } /* first set the needed config, interface and alternate */ - err = usb_set_interface(hw->dev, hw->if_used, hw->alt_used); + (void) usb_set_interface(hw->dev, hw->if_used, hw->alt_used); hw->led_state = 0; -- cgit v0.10.2 From 011bc1ef447dd6aa969d9c83a90fe3df360b5d6e Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Sun, 17 Apr 2011 16:36:28 -0700 Subject: isdn: arcofi: Fix set-but-unused variables. The variable 'val' is set but unused in send_arcofi(). Just kill it off. Signed-off-by: David S. Miller diff --git a/drivers/isdn/hisax/arcofi.c b/drivers/isdn/hisax/arcofi.c index 85a8fd8..21cbbe1 100644 --- a/drivers/isdn/hisax/arcofi.c +++ b/drivers/isdn/hisax/arcofi.c @@ -30,8 +30,6 @@ add_arcofi_timer(struct IsdnCardState *cs) { static void send_arcofi(struct IsdnCardState *cs) { - u_char val; - add_arcofi_timer(cs); cs->dc.isac.mon_txp = 0; cs->dc.isac.mon_txc = cs->dc.isac.arcofi_list->len; @@ -45,7 +43,7 @@ send_arcofi(struct IsdnCardState *cs) { cs->dc.isac.mocr &= 0x0f; cs->dc.isac.mocr |= 0xa0; cs->writeisac(cs, ISAC_MOCR, cs->dc.isac.mocr); - val = cs->readisac(cs, ISAC_MOSR); + (void) cs->readisac(cs, ISAC_MOSR); cs->writeisac(cs, ISAC_MOX1, cs->dc.isac.mon_tx[cs->dc.isac.mon_txp++]); cs->dc.isac.mocr |= 0x10; cs->writeisac(cs, ISAC_MOCR, cs->dc.isac.mocr); -- cgit v0.10.2 From 94dbe1ae44df1d22a391980eb6bd502f937b1af8 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Sun, 17 Apr 2011 16:37:11 -0700 Subject: isdn: elsa_cs: Fix set-but-unused variables. The variable 'dev' is set but unused in elsa_cs_config(). Just kill it off. Signed-off-by: David S. Miller diff --git a/drivers/isdn/hisax/elsa_cs.c b/drivers/isdn/hisax/elsa_cs.c index 496d477..9e5e87b 100644 --- a/drivers/isdn/hisax/elsa_cs.c +++ b/drivers/isdn/hisax/elsa_cs.c @@ -129,12 +129,10 @@ static int elsa_cs_configcheck(struct pcmcia_device *p_dev, void *priv_data) static int __devinit elsa_cs_config(struct pcmcia_device *link) { - local_info_t *dev; int i; IsdnCard_t icard; dev_dbg(&link->dev, "elsa_config(0x%p)\n", link); - dev = link->priv; link->config_flags |= CONF_ENABLE_IRQ | CONF_AUTO_SET_IO; -- cgit v0.10.2 From db47367451cbee4e8a3fd9389cc341f4acc43b1e Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Sun, 17 Apr 2011 16:38:33 -0700 Subject: isdn: elsa_ser: Fix set-but-unused variables. The variable 'bits' is set but unused in change_speed(). Just kill it off. Signed-off-by: David S. Miller diff --git a/drivers/isdn/hisax/elsa_ser.c b/drivers/isdn/hisax/elsa_ser.c index cbda379..3fa9f61 100644 --- a/drivers/isdn/hisax/elsa_ser.c +++ b/drivers/isdn/hisax/elsa_ser.c @@ -109,11 +109,10 @@ static void change_speed(struct IsdnCardState *cs, int baud) { int quot = 0, baud_base; unsigned cval, fcr = 0; - int bits; /* byte size and parity */ - cval = 0x03; bits = 10; + cval = 0x03; /* Determine divisor based on baud rate */ baud_base = BASE_BAUD; quot = baud_base / baud; -- cgit v0.10.2 From a1e6216d1b5035db1d4c018cf841d3267f949281 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Sun, 17 Apr 2011 16:39:18 -0700 Subject: isdn: hfc_usb: Fix set-but-unused variables. The variable 'buf' is set but unused in ctrl_complete(). Just kill it off. Similarly for 'err' in hfc_usb_init(). Signed-off-by: David S. Miller diff --git a/drivers/isdn/hisax/hfc_usb.c b/drivers/isdn/hisax/hfc_usb.c index ed9527a..f407de0 100644 --- a/drivers/isdn/hisax/hfc_usb.c +++ b/drivers/isdn/hisax/hfc_usb.c @@ -258,11 +258,9 @@ static void ctrl_complete(struct urb *urb) { hfcusb_data *hfc = (hfcusb_data *) urb->context; - ctrl_buft *buf; urb->dev = hfc->dev; if (hfc->ctrl_cnt) { - buf = &hfc->ctrl_buff[hfc->ctrl_out_idx]; hfc->ctrl_cnt--; /* decrement actual count */ if (++hfc->ctrl_out_idx >= HFC_CTRL_BUFSIZE) hfc->ctrl_out_idx = 0; /* pointer wrap */ @@ -1097,7 +1095,7 @@ static int hfc_usb_init(hfcusb_data * hfc) { usb_fifo *fifo; - int i, err; + int i; u_char b; struct hisax_b_if *p_b_if[2]; @@ -1112,7 +1110,7 @@ hfc_usb_init(hfcusb_data * hfc) } /* first set the needed config, interface and alternate */ - err = usb_set_interface(hfc->dev, hfc->if_used, hfc->alt_used); + usb_set_interface(hfc->dev, hfc->if_used, hfc->alt_used); /* do Chip reset */ write_usb(hfc, HFCUSB_CIRM, 8); -- cgit v0.10.2 From d462003ddbb28926109396b9038299fc740c2efc Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Sun, 17 Apr 2011 16:40:30 -0700 Subject: isdn: ipacx: Fix set-but-unused variables. The variable 'cda2_cr' is set but unused in ctrl_complete(). Just kill it off. Keep the cs->readisac() call just in case the register read has side effects. Signed-off-by: David S. Miller diff --git a/drivers/isdn/hisax/ipacx.c b/drivers/isdn/hisax/ipacx.c index 3321041..6908404 100644 --- a/drivers/isdn/hisax/ipacx.c +++ b/drivers/isdn/hisax/ipacx.c @@ -96,7 +96,7 @@ dch_l2l1(struct PStack *st, int pr, void *arg) { struct IsdnCardState *cs = (struct IsdnCardState *) st->l1.hardware; struct sk_buff *skb = arg; - u_char cda1_cr, cda2_cr; + u_char cda1_cr; switch (pr) { case (PH_DATA |REQUEST): @@ -163,7 +163,7 @@ dch_l2l1(struct PStack *st, int pr, void *arg) cs->writeisac(cs, IPACX_CDA_TSDP10, 0x80); // Timeslot 0 is B1 cs->writeisac(cs, IPACX_CDA_TSDP11, 0x81); // Timeslot 0 is B1 cda1_cr = cs->readisac(cs, IPACX_CDA1_CR); - cda2_cr = cs->readisac(cs, IPACX_CDA2_CR); + (void) cs->readisac(cs, IPACX_CDA2_CR); if ((long)arg &1) { // loop B1 cs->writeisac(cs, IPACX_CDA1_CR, cda1_cr |0x0a); } -- cgit v0.10.2 From f6f0e4a7a343f85dd773f6f18e553933c4367e96 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Sun, 17 Apr 2011 16:41:29 -0700 Subject: isdn: jade: Fix set-but-unused variables. The variable 'i' is set but unused in JadeVersion(). Just kill it off. Signed-off-by: David S. Miller diff --git a/drivers/isdn/hisax/jade.c b/drivers/isdn/hisax/jade.c index ea8f840..a06cea0 100644 --- a/drivers/isdn/hisax/jade.c +++ b/drivers/isdn/hisax/jade.c @@ -23,10 +23,9 @@ int JadeVersion(struct IsdnCardState *cs, char *s) { - int ver,i; + int ver; int to = 50; cs->BC_Write_Reg(cs, -1, 0x50, 0x19); - i=0; while (to) { udelay(1); ver = cs->BC_Read_Reg(cs, -1, 0x60); -- cgit v0.10.2 From cf117eafa0dc17c6f973d078d4e0bf2069f45ce7 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Sun, 17 Apr 2011 16:42:15 -0700 Subject: isdn: l3dss1: Fix set-but-unused variables. The variable 'cause' is set but unused in dss1up(). Just kill it off. Signed-off-by: David S. Miller diff --git a/drivers/isdn/hisax/l3dss1.c b/drivers/isdn/hisax/l3dss1.c index 8e2fd02..b0d9ab1 100644 --- a/drivers/isdn/hisax/l3dss1.c +++ b/drivers/isdn/hisax/l3dss1.c @@ -2943,7 +2943,7 @@ global_handler(struct PStack *st, int mt, struct sk_buff *skb) static void dss1up(struct PStack *st, int pr, void *arg) { - int i, mt, cr, cause, callState; + int i, mt, cr, callState; char *ptr; u_char *p; struct sk_buff *skb = arg; @@ -3034,12 +3034,10 @@ dss1up(struct PStack *st, int pr, void *arg) return; } } else if (mt == MT_STATUS) { - cause = 0; if ((ptr = findie(skb->data, skb->len, IE_CAUSE, 0)) != NULL) { ptr++; if (*ptr++ == 2) ptr++; - cause = *ptr & 0x7f; } callState = 0; if ((ptr = findie(skb->data, skb->len, IE_CALL_STATE, 0)) != NULL) { -- cgit v0.10.2 From 1397c5df2547f3296ad37a0c77daff3b124b98c8 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Sun, 17 Apr 2011 16:43:20 -0700 Subject: isdn: l3ni1: Fix set-but-unused variables. The variable 'cause' is set but unused in ni1up(). Just kill it off. Signed-off-by: David S. Miller diff --git a/drivers/isdn/hisax/l3ni1.c b/drivers/isdn/hisax/l3ni1.c index 7b229c0..092dcbb 100644 --- a/drivers/isdn/hisax/l3ni1.c +++ b/drivers/isdn/hisax/l3ni1.c @@ -2883,7 +2883,7 @@ global_handler(struct PStack *st, int mt, struct sk_buff *skb) static void ni1up(struct PStack *st, int pr, void *arg) { - int i, mt, cr, cause, callState; + int i, mt, cr, callState; char *ptr; u_char *p; struct sk_buff *skb = arg; @@ -2986,12 +2986,10 @@ ni1up(struct PStack *st, int pr, void *arg) return; } } else if (mt == MT_STATUS) { - cause = 0; if ((ptr = findie(skb->data, skb->len, IE_CAUSE, 0)) != NULL) { ptr++; if (*ptr++ == 2) ptr++; - cause = *ptr & 0x7f; } callState = 0; if ((ptr = findie(skb->data, skb->len, IE_CALL_STATE, 0)) != NULL) { -- cgit v0.10.2 From 8c85290d84eaa7b3ba605090987d2136a3302ca9 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Sun, 17 Apr 2011 16:44:12 -0700 Subject: isdn: teles_cs: Fix set-but-unused variables. The variable 'dev' is set but unused in teles_cs_config(). Just kill it off. Signed-off-by: David S. Miller diff --git a/drivers/isdn/hisax/teles_cs.c b/drivers/isdn/hisax/teles_cs.c index aa25e18..360f9ec 100644 --- a/drivers/isdn/hisax/teles_cs.c +++ b/drivers/isdn/hisax/teles_cs.c @@ -111,12 +111,10 @@ static int teles_cs_configcheck(struct pcmcia_device *p_dev, void *priv_data) static int __devinit teles_cs_config(struct pcmcia_device *link) { - local_info_t *dev; int i; IsdnCard_t icard; dev_dbg(&link->dev, "teles_config(0x%p)\n", link); - dev = link->priv; i = pcmcia_loop_config(link, teles_cs_configcheck, NULL); if (i != 0) -- cgit v0.10.2 From 50a7c114c2673f3fcbb0ba5d659049156e1ccd50 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Sun, 17 Apr 2011 16:45:51 -0700 Subject: isdn: i4l: isdn_common: Fix set-but-unused variables. The variable 'ch' is set but unused in isdn_capi_rec_hl_msg(). Just kill it off. Similarly for 'chidx' in isdn_ioctl() and 'di' in isdn_capi_rec_hl_msg(). Signed-off-by: David S. Miller diff --git a/drivers/isdn/i4l/isdn_common.c b/drivers/isdn/i4l/isdn_common.c index 15632bd..6ed82ad 100644 --- a/drivers/isdn/i4l/isdn_common.c +++ b/drivers/isdn/i4l/isdn_common.c @@ -399,13 +399,8 @@ isdn_all_eaz(int di, int ch) #include static int -isdn_capi_rec_hl_msg(capi_msg *cm) { - - int di; - int ch; - - di = (cm->adr.Controller & 0x7f) -1; - ch = isdn_dc2minor(di, (cm->adr.Controller>>8)& 0x7f); +isdn_capi_rec_hl_msg(capi_msg *cm) +{ switch(cm->Command) { case CAPI_FACILITY: /* in the moment only handled in tty */ @@ -1278,7 +1273,6 @@ isdn_ioctl(struct file *file, uint cmd, ulong arg) uint minor = iminor(file->f_path.dentry->d_inode); isdn_ctrl c; int drvidx; - int chidx; int ret; int i; char __user *p; @@ -1340,7 +1334,6 @@ isdn_ioctl(struct file *file, uint cmd, ulong arg) drvidx = isdn_minor2drv(minor); if (drvidx < 0) return -ENODEV; - chidx = isdn_minor2chan(minor); if (!(dev->drv[drvidx]->flags & DRV_FLAG_RUNNING)) return -ENODEV; return 0; -- cgit v0.10.2 From 07f46f80f4ca4ddb700ff40a19876ba1b3242917 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Sun, 17 Apr 2011 16:46:50 -0700 Subject: isdn: i4l: isdn_net: Fix set-but-unused variables. The variable 'unused' is set but unused in isdn_net_ciscohdlck_slarp_in(). Just kill it off. Signed-off-by: David S. Miller diff --git a/drivers/isdn/i4l/isdn_net.c b/drivers/isdn/i4l/isdn_net.c index 2a7d17c..9798811 100644 --- a/drivers/isdn/i4l/isdn_net.c +++ b/drivers/isdn/i4l/isdn_net.c @@ -1678,7 +1678,6 @@ isdn_net_ciscohdlck_slarp_in(isdn_net_local *lp, struct sk_buff *skb) u32 your_seq; __be32 local; __be32 *addr, *mask; - u16 unused; if (skb->len < 14) return; @@ -1722,7 +1721,6 @@ isdn_net_ciscohdlck_slarp_in(isdn_net_local *lp, struct sk_buff *skb) lp->cisco_last_slarp_in = jiffies; my_seq = be32_to_cpup((__be32 *)(p + 0)); your_seq = be32_to_cpup((__be32 *)(p + 4)); - unused = be16_to_cpup((__be16 *)(p + 8)); p += 10; lp->cisco_yourseq = my_seq; lp->cisco_mineseen = your_seq; -- cgit v0.10.2 From 81b424d9e2ef815b2035d4c2be0bc41dddbebc06 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Sun, 17 Apr 2011 16:48:53 -0700 Subject: isdn: mISDN: socket: Fix set-but-unused variables. The variable 'len' is set but unused in data_sock_getsockopt(). The code should use 'len' to validate that the user's socket option is indeed the right size. Signed-off-by: David S. Miller diff --git a/drivers/isdn/mISDN/socket.c b/drivers/isdn/mISDN/socket.c index 7446d8b..8e32522 100644 --- a/drivers/isdn/mISDN/socket.c +++ b/drivers/isdn/mISDN/socket.c @@ -457,6 +457,9 @@ static int data_sock_getsockopt(struct socket *sock, int level, int optname, if (get_user(len, optlen)) return -EFAULT; + if (len != sizeof(char)) + return -EINVAL; + switch (optname) { case MISDN_TIME_STAMP: if (_pms(sk)->cmask & MISDN_TIME_STAMP) -- cgit v0.10.2 From 585985429080a449e0ecf66dd485899a8765c26c Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Sun, 17 Apr 2011 16:51:36 -0700 Subject: bna: Fix set-but-unused variables. The variable 'pgoff' is set but unused in bfa_nw_ioc_fwver_get() and bfa_ioc_download_fw(). Similarly for 'cmd_h' in bna_mbox_flush_q and the entirety of bna_rit_mod_uninit() is unused since variables are purely set but no action is made using them. Same for 'bna' in bna_rit_create() and 'ret' in bna_rx_create(). Just kill them off. Signed-off-by: David S. Miller diff --git a/drivers/net/bna/bfa_ioc.c b/drivers/net/bna/bfa_ioc.c index e3de0b8..c1c9e70 100644 --- a/drivers/net/bna/bfa_ioc.c +++ b/drivers/net/bna/bfa_ioc.c @@ -1272,13 +1272,12 @@ bfa_ioc_lpu_stop(struct bfa_ioc *ioc) void bfa_nw_ioc_fwver_get(struct bfa_ioc *ioc, struct bfi_ioc_image_hdr *fwhdr) { - u32 pgnum, pgoff; + u32 pgnum; u32 loff = 0; int i; u32 *fwsig = (u32 *) fwhdr; pgnum = bfa_ioc_smem_pgnum(ioc, loff); - pgoff = bfa_ioc_smem_pgoff(ioc, loff); writel(pgnum, ioc->ioc_regs.host_page_num_fn); for (i = 0; i < (sizeof(struct bfi_ioc_image_hdr) / sizeof(u32)); @@ -1509,7 +1508,7 @@ bfa_ioc_download_fw(struct bfa_ioc *ioc, u32 boot_type, u32 boot_param) { u32 *fwimg; - u32 pgnum, pgoff; + u32 pgnum; u32 loff = 0; u32 chunkno = 0; u32 i; @@ -1522,7 +1521,6 @@ bfa_ioc_download_fw(struct bfa_ioc *ioc, u32 boot_type, fwimg = bfa_cb_image_get_chunk(BFA_IOC_FWIMG_TYPE(ioc), chunkno); pgnum = bfa_ioc_smem_pgnum(ioc, loff); - pgoff = bfa_ioc_smem_pgoff(ioc, loff); writel(pgnum, ioc->ioc_regs.host_page_num_fn); diff --git a/drivers/net/bna/bna_ctrl.c b/drivers/net/bna/bna_ctrl.c index e152747..53b1416 100644 --- a/drivers/net/bna/bna_ctrl.c +++ b/drivers/net/bna/bna_ctrl.c @@ -246,7 +246,6 @@ static void bna_mbox_flush_q(struct bna *bna, struct list_head *q) { struct bna_mbox_qe *mb_qe = NULL; - struct bfi_mhdr *cmd_h; struct list_head *mb_q; void (*cbfn)(void *arg, int status); void *cbarg; @@ -260,7 +259,6 @@ bna_mbox_flush_q(struct bna *bna, struct list_head *q) bfa_q_qe_init(mb_qe); bna->mbox_mod.msg_pending--; - cmd_h = (struct bfi_mhdr *)(&mb_qe->cmd.msg[0]); if (cbfn) cbfn(cbarg, BNA_CB_NOT_EXEC); } @@ -2774,23 +2772,6 @@ bna_rit_mod_init(struct bna_rit_mod *rit_mod, } } -static void -bna_rit_mod_uninit(struct bna_rit_mod *rit_mod) -{ - struct bna_rit_segment *rit_segment; - struct list_head *qe; - int i; - int j; - - for (i = 0; i < BFI_RIT_SEG_TOTAL_POOLS; i++) { - j = 0; - list_for_each(qe, &rit_mod->rit_seg_pool[i]) { - rit_segment = (struct bna_rit_segment *)qe; - j++; - } - } -} - /* * Public functions */ @@ -2977,8 +2958,6 @@ bna_uninit(struct bna *bna) bna_ucam_mod_uninit(&bna->ucam_mod); - bna_rit_mod_uninit(&bna->rit_mod); - bna_ib_mod_uninit(&bna->ib_mod); bna_rx_mod_uninit(&bna->rx_mod); diff --git a/drivers/net/bna/bna_txrx.c b/drivers/net/bna/bna_txrx.c index 58c7664..380085c 100644 --- a/drivers/net/bna/bna_txrx.c +++ b/drivers/net/bna/bna_txrx.c @@ -2229,14 +2229,11 @@ void bna_rit_create(struct bna_rx *rx) { struct list_head *qe_rxp; - struct bna *bna; struct bna_rxp *rxp; struct bna_rxq *q0 = NULL; struct bna_rxq *q1 = NULL; int offset; - bna = rx->bna; - offset = 0; list_for_each(qe_rxp, &rx->rxp_q) { rxp = (struct bna_rxp *)qe_rxp; @@ -2830,7 +2827,7 @@ bna_rx_create(struct bna *bna, struct bnad *bnad, struct bna_mem_descr *dsqpt_mem; /* s/w qpt for data */ struct bna_mem_descr *hpage_mem; /* hdr page mem */ struct bna_mem_descr *dpage_mem; /* data page mem */ - int i, cpage_idx = 0, dpage_idx = 0, hpage_idx = 0, ret; + int i, cpage_idx = 0, dpage_idx = 0, hpage_idx = 0; int dpage_count, hpage_count, rcb_idx; struct bna_ib_config ibcfg; /* Fail if we don't have enough RXPs, RXQs */ @@ -2924,7 +2921,7 @@ bna_rx_create(struct bna *bna, struct bnad *bnad, ibcfg.interpkt_timeo = BFI_RX_INTERPKT_TIMEO; ibcfg.ctrl_flags = BFI_IB_CF_INT_ENABLE; - ret = bna_ib_config(rxp->cq.ib, &ibcfg); + bna_ib_config(rxp->cq.ib, &ibcfg); /* Link rxqs to rxp */ _rxp_add_rxqs(rxp, q0, q1); -- cgit v0.10.2 From b8ee8328bac0d8420d2b9ef4838d0df25df100ab Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Sun, 17 Apr 2011 16:56:12 -0700 Subject: bnx2x: Fix set-but-unused variables. The variable 'rc' is set but unused in bnx2x_timer(). Similarly for 'hc_index_p' in bnx2x_init_sb(), and 'port' in bnx2x_get_hwinfo(). Just kill them off. Signed-off-by: David S. Miller diff --git a/drivers/net/bnx2x/bnx2x_main.c b/drivers/net/bnx2x/bnx2x_main.c index 696e84a..bfd7ac9 100644 --- a/drivers/net/bnx2x/bnx2x_main.c +++ b/drivers/net/bnx2x/bnx2x_main.c @@ -3904,10 +3904,9 @@ static void bnx2x_timer(unsigned long data) if (poll) { struct bnx2x_fastpath *fp = &bp->fp[0]; - int rc; bnx2x_tx_int(fp); - rc = bnx2x_rx_int(fp, 1000); + bnx2x_rx_int(fp, 1000); } if (!BP_NOMCP(bp)) { @@ -4062,7 +4061,6 @@ static void bnx2x_init_sb(struct bnx2x *bp, dma_addr_t mapping, int vfid, struct hc_status_block_data_e2 sb_data_e2; struct hc_status_block_data_e1x sb_data_e1x; struct hc_status_block_sm *hc_sm_p; - struct hc_index_data *hc_index_p; int data_size; u32 *sb_data_p; @@ -4083,7 +4081,6 @@ static void bnx2x_init_sb(struct bnx2x *bp, dma_addr_t mapping, int vfid, sb_data_e2.common.host_sb_addr.hi = U64_HI(mapping); sb_data_e2.common.host_sb_addr.lo = U64_LO(mapping); hc_sm_p = sb_data_e2.common.state_machine; - hc_index_p = sb_data_e2.index_data; sb_data_p = (u32 *)&sb_data_e2; data_size = sizeof(struct hc_status_block_data_e2)/sizeof(u32); } else { @@ -4097,7 +4094,6 @@ static void bnx2x_init_sb(struct bnx2x *bp, dma_addr_t mapping, int vfid, sb_data_e1x.common.host_sb_addr.hi = U64_HI(mapping); sb_data_e1x.common.host_sb_addr.lo = U64_LO(mapping); hc_sm_p = sb_data_e1x.common.state_machine; - hc_index_p = sb_data_e1x.index_data; sb_data_p = (u32 *)&sb_data_e1x; data_size = sizeof(struct hc_status_block_data_e1x)/sizeof(u32); } @@ -8635,7 +8631,7 @@ static void __devinit bnx2x_get_mac_hwinfo(struct bnx2x *bp) static int __devinit bnx2x_get_hwinfo(struct bnx2x *bp) { int /*abs*/func = BP_ABS_FUNC(bp); - int vn, port; + int vn; u32 val = 0; int rc = 0; @@ -8670,7 +8666,6 @@ static int __devinit bnx2x_get_hwinfo(struct bnx2x *bp) bp->mf_ov = 0; bp->mf_mode = 0; vn = BP_E1HVN(bp); - port = BP_PORT(bp); if (!CHIP_IS_E1(bp) && !BP_NOMCP(bp)) { DP(NETIF_MSG_PROBE, -- cgit v0.10.2 From 056693a38e56c520e208409d221cbc077282c19d Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Sun, 17 Apr 2011 16:57:55 -0700 Subject: caif: Fix set-but-unused variables. The variable 'caifdef' is set but unused in modemcmd(). Similarly for 'net' in receive(), and 'res' in caif_device_notify() and caif_exit_net(). Just kill them off. Signed-off-by: David S. Miller diff --git a/net/caif/caif_dev.c b/net/caif/caif_dev.c index a518fdd..75e00d5 100644 --- a/net/caif/caif_dev.c +++ b/net/caif/caif_dev.c @@ -133,9 +133,7 @@ static int transmit(struct cflayer *layer, struct cfpkt *pkt) static int modemcmd(struct cflayer *layr, enum caif_modemcmd ctrl) { struct caif_device_entry *caifd; - struct caif_dev_common *caifdev; caifd = container_of(layr, struct caif_device_entry, layer); - caifdev = netdev_priv(caifd->netdev); if (ctrl == _CAIF_MODEMCMD_PHYIF_USEFULL) { atomic_set(&caifd->in_use, 1); wake_up_interruptible(&caifd->event); @@ -154,10 +152,8 @@ static int modemcmd(struct cflayer *layr, enum caif_modemcmd ctrl) static int receive(struct sk_buff *skb, struct net_device *dev, struct packet_type *pkttype, struct net_device *orig_dev) { - struct net *net; struct cfpkt *pkt; struct caif_device_entry *caifd; - net = dev_net(dev); pkt = cfpkt_fromnative(CAIF_DIR_IN, skb); caifd = caif_get(dev); if (!caifd || !caifd->layer.up || !caifd->layer.up->receive) @@ -195,7 +191,6 @@ static int caif_device_notify(struct notifier_block *me, unsigned long what, struct caif_device_entry *caifd = NULL; struct caif_dev_common *caifdev; enum cfcnfg_phy_preference pref; - int res = -EINVAL; enum cfcnfg_phy_type phy_type; if (dev->type != ARPHRD_CAIF) @@ -210,7 +205,6 @@ static int caif_device_notify(struct notifier_block *me, unsigned long what, caifdev = netdev_priv(dev); caifdev->flowctrl = dev_flowctrl; atomic_set(&caifd->state, what); - res = 0; break; case NETDEV_UP: @@ -274,7 +268,7 @@ static int caif_device_notify(struct notifier_block *me, unsigned long what, _CAIF_CTRLCMD_PHYIF_DOWN_IND, caifd->layer.id); might_sleep(); - res = wait_event_interruptible_timeout(caifd->event, + wait_event_interruptible_timeout(caifd->event, atomic_read(&caifd->in_use) == 0, TIMEOUT); break; @@ -344,12 +338,11 @@ static int caif_init_net(struct net *net) static void caif_exit_net(struct net *net) { struct net_device *dev; - int res; rtnl_lock(); for_each_netdev(net, dev) { if (dev->type != ARPHRD_CAIF) continue; - res = dev_close(dev); + dev_close(dev); caif_device_destroy(dev); } rtnl_unlock(); -- cgit v0.10.2 From 1627ea35cb10af2f71d38a82de6f6dfb910771ed Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Sun, 17 Apr 2011 16:59:09 -0700 Subject: irda: irlap_event: Fix set-but-unused variables. The variable 'ret' is set but unused in irlap_state_sclose(). Just kill it off. Signed-off-by: David S. Miller diff --git a/net/irda/irlap_event.c b/net/irda/irlap_event.c index bb47021..ccd214f 100644 --- a/net/irda/irlap_event.c +++ b/net/irda/irlap_event.c @@ -2227,8 +2227,6 @@ static int irlap_state_nrm_s(struct irlap_cb *self, IRLAP_EVENT event, static int irlap_state_sclose(struct irlap_cb *self, IRLAP_EVENT event, struct sk_buff *skb, struct irlap_info *info) { - int ret = 0; - IRDA_DEBUG(1, "%s()\n", __func__); IRDA_ASSERT(self != NULL, return -ENODEV;); @@ -2289,7 +2287,6 @@ static int irlap_state_sclose(struct irlap_cb *self, IRLAP_EVENT event, IRDA_DEBUG(1, "%s(), Unknown event %d, (%s)\n", __func__, event, irlap_event[event]); - ret = -EINVAL; break; } -- cgit v0.10.2 From 6385969b3297287e6259a012671be09c78c20620 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Sun, 17 Apr 2011 16:59:50 -0700 Subject: irda: irproc: Fix set-but-unused variables. The variable 'd' is set but unused in irda_proc_register(). Just kill it off. Signed-off-by: David S. Miller diff --git a/net/irda/irproc.c b/net/irda/irproc.c index 318766e..b9ac598 100644 --- a/net/irda/irproc.c +++ b/net/irda/irproc.c @@ -65,15 +65,14 @@ static const struct irda_entry irda_dirs[] = { void __init irda_proc_register(void) { int i; - struct proc_dir_entry *d; proc_irda = proc_mkdir("irda", init_net.proc_net); if (proc_irda == NULL) return; for (i = 0; i < ARRAY_SIZE(irda_dirs); i++) - d = proc_create(irda_dirs[i].name, 0, proc_irda, - irda_dirs[i].fops); + (void) proc_create(irda_dirs[i].name, 0, proc_irda, + irda_dirs[i].fops); } /* -- cgit v0.10.2 From 8cb490144708ef295421d0601b0866623651a37e Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Sun, 17 Apr 2011 17:01:05 -0700 Subject: l2tp: Fix set-but-unused variables. The variable 'ret' is set but unused in l2tp_nl_register_ops(). This was obviously meant to maintain error codes which are returned to the caller, make it so. Signed-off-by: David S. Miller diff --git a/net/l2tp/l2tp_netlink.c b/net/l2tp/l2tp_netlink.c index 4c1e540..93a41a0 100644 --- a/net/l2tp/l2tp_netlink.c +++ b/net/l2tp/l2tp_netlink.c @@ -795,11 +795,12 @@ int l2tp_nl_register_ops(enum l2tp_pwtype pw_type, const struct l2tp_nl_cmd_ops goto out; l2tp_nl_cmd_ops[pw_type] = ops; + ret = 0; out: genl_unlock(); err: - return 0; + return ret; } EXPORT_SYMBOL_GPL(l2tp_nl_register_ops); -- cgit v0.10.2 From dab51d0e0718e7beef26075a9353f09ea2652a4f Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Sun, 17 Apr 2011 17:01:49 -0700 Subject: netlabel: Fix set-but-unused variables. The variable 'type_str' is set but unused in netlbl_cipsov4_add(). Just kill it off. Signed-off-by: David S. Miller diff --git a/net/netlabel/netlabel_cipso_v4.c b/net/netlabel/netlabel_cipso_v4.c index 5f14c84..bae5756 100644 --- a/net/netlabel/netlabel_cipso_v4.c +++ b/net/netlabel/netlabel_cipso_v4.c @@ -422,7 +422,6 @@ static int netlbl_cipsov4_add(struct sk_buff *skb, struct genl_info *info) { int ret_val = -EINVAL; - const char *type_str = "(unknown)"; struct netlbl_audit audit_info; if (!info->attrs[NLBL_CIPSOV4_A_DOI] || @@ -432,15 +431,12 @@ static int netlbl_cipsov4_add(struct sk_buff *skb, struct genl_info *info) netlbl_netlink_auditinfo(skb, &audit_info); switch (nla_get_u32(info->attrs[NLBL_CIPSOV4_A_MTYPE])) { case CIPSO_V4_MAP_TRANS: - type_str = "trans"; ret_val = netlbl_cipsov4_add_std(info, &audit_info); break; case CIPSO_V4_MAP_PASS: - type_str = "pass"; ret_val = netlbl_cipsov4_add_pass(info, &audit_info); break; case CIPSO_V4_MAP_LOCAL: - type_str = "local"; ret_val = netlbl_cipsov4_add_local(info, &audit_info); break; } -- cgit v0.10.2 From d87d7fb381c153f71b7cdfd37f3513edc6d0eb8f Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Sun, 17 Apr 2011 17:02:29 -0700 Subject: netfilter: nfnetlink_log: Fix set-but-unused variables. The variable 'tmp_uint' is set but unused in __build_packet_message(). Just kill it off. Signed-off-by: David S. Miller diff --git a/net/netfilter/nfnetlink_log.c b/net/netfilter/nfnetlink_log.c index 985e9b7..e0ee010 100644 --- a/net/netfilter/nfnetlink_log.c +++ b/net/netfilter/nfnetlink_log.c @@ -381,7 +381,6 @@ __build_packet_message(struct nfulnl_instance *inst, struct nfulnl_msg_packet_hdr pmsg; struct nlmsghdr *nlh; struct nfgenmsg *nfmsg; - __be32 tmp_uint; sk_buff_data_t old_tail = inst->skb->tail; nlh = NLMSG_PUT(inst->skb, 0, 0, @@ -428,7 +427,6 @@ __build_packet_message(struct nfulnl_instance *inst, } if (outdev) { - tmp_uint = htonl(outdev->ifindex); #ifndef CONFIG_BRIDGE_NETFILTER NLA_PUT_BE32(inst->skb, NFULA_IFINDEX_OUTDEV, htonl(outdev->ifindex)); -- cgit v0.10.2 From d88d7de09875e643e225a5d0883d18152ce5a89b Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Sun, 17 Apr 2011 17:03:33 -0700 Subject: netfilter: nf_conntrack_standalone: Fix set-but-unused variables. The variable 'ret' is set but unused in ct_seq_show(). This was obviously meant to be used to propagate error codes to the caller, so make it so. Signed-off-by: David S. Miller diff --git a/net/netfilter/nf_conntrack_standalone.c b/net/netfilter/nf_conntrack_standalone.c index 0ae1428..05e9feb 100644 --- a/net/netfilter/nf_conntrack_standalone.c +++ b/net/netfilter/nf_conntrack_standalone.c @@ -245,7 +245,7 @@ static int ct_seq_show(struct seq_file *s, void *v) ret = 0; release: nf_ct_put(ct); - return 0; + return ret; } static const struct seq_operations ct_seq_ops = { -- cgit v0.10.2 From f3c85dd560f26ceae1351e6f83e83f1322761ead Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Sun, 17 Apr 2011 17:04:48 -0700 Subject: netfilter: ip6_tables: Fix set-but-unused variables. The variable 'target' is set but unused in compat_copy_entry_from_user(). Just kill it off. Signed-off-by: David S. Miller diff --git a/net/ipv6/netfilter/ip6_tables.c b/net/ipv6/netfilter/ip6_tables.c index 5a1c6f2..4c1492f 100644 --- a/net/ipv6/netfilter/ip6_tables.c +++ b/net/ipv6/netfilter/ip6_tables.c @@ -1578,7 +1578,6 @@ compat_copy_entry_from_user(struct compat_ip6t_entry *e, void **dstptr, struct xt_table_info *newinfo, unsigned char *base) { struct xt_entry_target *t; - struct xt_target *target; struct ip6t_entry *de; unsigned int origsize; int ret, h; @@ -1600,7 +1599,6 @@ compat_copy_entry_from_user(struct compat_ip6t_entry *e, void **dstptr, } de->target_offset = e->target_offset - (origsize - *size); t = compat_ip6t_get_target(e); - target = t->u.kernel.target; xt_compat_target_from_user(t, dstptr, size); de->next_offset = e->next_offset - (origsize - *size); -- cgit v0.10.2 From b169f6db40605d0907458d1ff78ceac2b194a44f Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Sun, 17 Apr 2011 17:06:15 -0700 Subject: netfilter: ip6table_mangle: Fix set-but-unused variables. The variable 'flowlabel' is set but unused in ip6t_mangle_out(). The intention here was to compare this key to the header value after mangling, and trigger a route lookup on mismatch. Make it so. Signed-off-by: David S. Miller diff --git a/net/ipv6/netfilter/ip6table_mangle.c b/net/ipv6/netfilter/ip6table_mangle.c index 679a0a3..00d1917 100644 --- a/net/ipv6/netfilter/ip6table_mangle.c +++ b/net/ipv6/netfilter/ip6table_mangle.c @@ -64,7 +64,8 @@ ip6t_mangle_out(struct sk_buff *skb, const struct net_device *out) (memcmp(&ipv6_hdr(skb)->saddr, &saddr, sizeof(saddr)) || memcmp(&ipv6_hdr(skb)->daddr, &daddr, sizeof(daddr)) || skb->mark != mark || - ipv6_hdr(skb)->hop_limit != hop_limit)) + ipv6_hdr(skb)->hop_limit != hop_limit || + flowlabel != *((u_int32_t *)ipv6_hdr(skb)))) return ip6_route_me_harder(skb) == 0 ? ret : NF_DROP; return ret; -- cgit v0.10.2 From 9365f11a5321bcff5579799a071a70c5cacb5e65 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Sun, 17 Apr 2011 17:07:57 -0700 Subject: isdn: i4l: isdn_tty: Fix unused-but-set variables. The variable 'fcr' is set but not used in isdn_tty_change_speed(). Just kill it off. Signed-off-by: David S. Miller diff --git a/drivers/isdn/i4l/isdn_tty.c b/drivers/isdn/i4l/isdn_tty.c index 607d846..d850427 100644 --- a/drivers/isdn/i4l/isdn_tty.c +++ b/drivers/isdn/i4l/isdn_tty.c @@ -998,7 +998,6 @@ isdn_tty_change_speed(modem_info * info) { uint cflag, cval, - fcr, quot; int i; @@ -1037,7 +1036,6 @@ isdn_tty_change_speed(modem_info * info) cval |= UART_LCR_PARITY; if (!(cflag & PARODD)) cval |= UART_LCR_EPAR; - fcr = 0; /* CTS flow control flag and modem status interrupts */ if (cflag & CRTSCTS) { -- cgit v0.10.2 From 03746b0a02d25866a29cd8d7306d221c238d6397 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Sun, 17 Apr 2011 17:08:41 -0700 Subject: be2net: Fix unused-but-set variables. The variables 'tx_min' and 'tx_max' are set but not used in be_set_coalesce(). Similarly for 'region' in be_do_flash(). Just kill them off. Signed-off-by: David S. Miller diff --git a/drivers/net/benet/be_ethtool.c b/drivers/net/benet/be_ethtool.c index 80226e4..0f645a9 100644 --- a/drivers/net/benet/be_ethtool.c +++ b/drivers/net/benet/be_ethtool.c @@ -205,9 +205,9 @@ be_set_coalesce(struct net_device *netdev, struct ethtool_coalesce *coalesce) struct be_rx_obj *rxo; struct be_eq_obj *rx_eq; struct be_eq_obj *tx_eq = &adapter->tx_eq; - u32 tx_max, tx_min, tx_cur; u32 rx_max, rx_min, rx_cur; int status = 0, i; + u32 tx_cur; if (coalesce->use_adaptive_tx_coalesce == 1) return -EINVAL; @@ -246,8 +246,6 @@ be_set_coalesce(struct net_device *netdev, struct ethtool_coalesce *coalesce) } } - tx_max = coalesce->tx_coalesce_usecs_high; - tx_min = coalesce->tx_coalesce_usecs_low; tx_cur = coalesce->tx_coalesce_usecs; if (tx_cur > BE_MAX_EQD) @@ -664,11 +662,9 @@ be_do_flash(struct net_device *netdev, struct ethtool_flash *efl) { struct be_adapter *adapter = netdev_priv(netdev); char file_name[ETHTOOL_FLASH_MAX_FILENAME]; - u32 region; file_name[ETHTOOL_FLASH_MAX_FILENAME - 1] = 0; strcpy(file_name, efl->data); - region = efl->region; return be_load_fw(adapter, file_name); } -- cgit v0.10.2 From 391876466670988196786150fc9d9da2f3c7cecb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Miros=C5=82aw?= Date: Sun, 17 Apr 2011 00:15:46 +0000 Subject: net: macvlan: convert to hw_features MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Not much of a conversion anyway - macvlan has no way to change the offload settings independently to its base device. Signed-off-by: MichaÅ‚ MirosÅ‚aw Signed-off-by: David S. Miller diff --git a/drivers/net/macvlan.c b/drivers/net/macvlan.c index 78e34e9..3ad5425 100644 --- a/drivers/net/macvlan.c +++ b/drivers/net/macvlan.c @@ -415,7 +415,7 @@ static struct lock_class_key macvlan_netdev_addr_lock_key; #define MACVLAN_FEATURES \ (NETIF_F_SG | NETIF_F_ALL_CSUM | NETIF_F_HIGHDMA | NETIF_F_FRAGLIST | \ NETIF_F_GSO | NETIF_F_TSO | NETIF_F_UFO | NETIF_F_GSO_ROBUST | \ - NETIF_F_TSO_ECN | NETIF_F_TSO6 | NETIF_F_GRO) + NETIF_F_TSO_ECN | NETIF_F_TSO6 | NETIF_F_GRO | NETIF_F_RXCSUM) #define MACVLAN_STATE_MASK \ ((1<<__LINK_STATE_NOCARRIER) | (1<<__LINK_STATE_DORMANT)) @@ -517,12 +517,6 @@ static void macvlan_ethtool_get_drvinfo(struct net_device *dev, snprintf(drvinfo->version, 32, "0.1"); } -static u32 macvlan_ethtool_get_rx_csum(struct net_device *dev) -{ - const struct macvlan_dev *vlan = netdev_priv(dev); - return dev_ethtool_get_rx_csum(vlan->lowerdev); -} - static int macvlan_ethtool_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) { @@ -530,18 +524,10 @@ static int macvlan_ethtool_get_settings(struct net_device *dev, return dev_ethtool_get_settings(vlan->lowerdev, cmd); } -static u32 macvlan_ethtool_get_flags(struct net_device *dev) -{ - const struct macvlan_dev *vlan = netdev_priv(dev); - return dev_ethtool_get_flags(vlan->lowerdev); -} - static const struct ethtool_ops macvlan_ethtool_ops = { .get_link = ethtool_op_get_link, .get_settings = macvlan_ethtool_get_settings, - .get_rx_csum = macvlan_ethtool_get_rx_csum, .get_drvinfo = macvlan_ethtool_get_drvinfo, - .get_flags = macvlan_ethtool_get_flags, }; static const struct net_device_ops macvlan_netdev_ops = { -- cgit v0.10.2 From d2fe2755342b30bc1ee7797b9975f8626d65e485 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Miros=C5=82aw?= Date: Sun, 17 Apr 2011 00:15:46 +0000 Subject: net: cxgb3: convert to hw_features MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This removes some of the remnants of LRO -> GRO conversion. Signed-off-by: MichaÅ‚ MirosÅ‚aw Signed-off-by: David S. Miller diff --git a/drivers/net/cxgb3/adapter.h b/drivers/net/cxgb3/adapter.h index ef67be5..7300de5 100644 --- a/drivers/net/cxgb3/adapter.h +++ b/drivers/net/cxgb3/adapter.h @@ -50,11 +50,6 @@ struct adapter; struct sge_qset; struct port_info; -enum { /* rx_offload flags */ - T3_RX_CSUM = 1 << 0, - T3_LRO = 1 << 1, -}; - enum mac_idx_types { LAN_MAC_IDX = 0, SAN_MAC_IDX, @@ -74,7 +69,6 @@ struct port_info { struct vlan_group *vlan_grp; struct sge_qset *qs; u8 port_id; - u8 rx_offload; u8 nqsets; u8 first_qset; struct cphy phy; @@ -212,7 +206,6 @@ struct sge_qset { /* an SGE queue set */ struct sge_fl fl[SGE_RXQ_PER_SET]; struct sge_txq txq[SGE_TXQ_PER_SET]; int nomem; - int lro_enabled; void *lro_va; struct net_device *netdev; struct netdev_queue *tx_q; /* associated netdev TX queue */ diff --git a/drivers/net/cxgb3/common.h b/drivers/net/cxgb3/common.h index 5ccb77d..056ee8c 100644 --- a/drivers/net/cxgb3/common.h +++ b/drivers/net/cxgb3/common.h @@ -317,7 +317,6 @@ struct tp_params { struct qset_params { /* SGE queue set parameters */ unsigned int polling; /* polling/interrupt service for rspq */ - unsigned int lro; /* large receive offload */ unsigned int coalesce_usecs; /* irq coalescing timer */ unsigned int rspq_size; /* # of entries in response queue */ unsigned int fl_size; /* # of entries in regular free list */ diff --git a/drivers/net/cxgb3/cxgb3_main.c b/drivers/net/cxgb3/cxgb3_main.c index a087e06..0404918 100644 --- a/drivers/net/cxgb3/cxgb3_main.c +++ b/drivers/net/cxgb3/cxgb3_main.c @@ -644,26 +644,6 @@ static void enable_all_napi(struct adapter *adap) } /** - * set_qset_lro - Turn a queue set's LRO capability on and off - * @dev: the device the qset is attached to - * @qset_idx: the queue set index - * @val: the LRO switch - * - * Sets LRO on or off for a particular queue set. - * the device's features flag is updated to reflect the LRO - * capability when all queues belonging to the device are - * in the same state. - */ -static void set_qset_lro(struct net_device *dev, int qset_idx, int val) -{ - struct port_info *pi = netdev_priv(dev); - struct adapter *adapter = pi->adapter; - - adapter->params.sge.qset[qset_idx].lro = !!val; - adapter->sge.qs[qset_idx].lro_enabled = !!val; -} - -/** * setup_sge_qsets - configure SGE Tx/Rx/response queues * @adap: the adapter * @@ -685,7 +665,6 @@ static int setup_sge_qsets(struct adapter *adap) pi->qs = &adap->sge.qs[pi->first_qset]; for (j = 0; j < pi->nqsets; ++j, ++qset_idx) { - set_qset_lro(dev, qset_idx, pi->rx_offload & T3_LRO); err = t3_sge_alloc_qset(adap, qset_idx, 1, (adap->flags & USING_MSIX) ? qset_idx + 1 : irq_idx, @@ -1910,29 +1889,6 @@ static int set_pauseparam(struct net_device *dev, return 0; } -static u32 get_rx_csum(struct net_device *dev) -{ - struct port_info *p = netdev_priv(dev); - - return p->rx_offload & T3_RX_CSUM; -} - -static int set_rx_csum(struct net_device *dev, u32 data) -{ - struct port_info *p = netdev_priv(dev); - - if (data) { - p->rx_offload |= T3_RX_CSUM; - } else { - int i; - - p->rx_offload &= ~(T3_RX_CSUM | T3_LRO); - for (i = p->first_qset; i < p->first_qset + p->nqsets; i++) - set_qset_lro(dev, i, 0); - } - return 0; -} - static void get_sge_param(struct net_device *dev, struct ethtool_ringparam *e) { struct port_info *pi = netdev_priv(dev); @@ -2104,10 +2060,6 @@ static const struct ethtool_ops cxgb_ethtool_ops = { .set_eeprom = set_eeprom, .get_pauseparam = get_pauseparam, .set_pauseparam = set_pauseparam, - .get_rx_csum = get_rx_csum, - .set_rx_csum = set_rx_csum, - .set_tx_csum = ethtool_op_set_tx_csum, - .set_sg = ethtool_op_set_sg, .get_link = ethtool_op_get_link, .get_strings = get_strings, .set_phys_id = set_phys_id, @@ -2117,7 +2069,6 @@ static const struct ethtool_ops cxgb_ethtool_ops = { .get_regs_len = get_regs_len, .get_regs = get_regs, .get_wol = get_wol, - .set_tso = ethtool_op_set_tso, }; static int in_range(int val, int lo, int hi) @@ -2165,15 +2116,6 @@ static int cxgb_extension_ioctl(struct net_device *dev, void __user *useraddr) MAX_RSPQ_ENTRIES)) return -EINVAL; - if ((adapter->flags & FULL_INIT_DONE) && t.lro > 0) - for_each_port(adapter, i) { - pi = adap2pinfo(adapter, i); - if (t.qset_idx >= pi->first_qset && - t.qset_idx < pi->first_qset + pi->nqsets && - !(pi->rx_offload & T3_RX_CSUM)) - return -EINVAL; - } - if ((adapter->flags & FULL_INIT_DONE) && (t.rspq_size >= 0 || t.fl_size[0] >= 0 || t.fl_size[1] >= 0 || t.txq_size[0] >= 0 || @@ -2234,8 +2176,14 @@ static int cxgb_extension_ioctl(struct net_device *dev, void __user *useraddr) } } } - if (t.lro >= 0) - set_qset_lro(dev, t.qset_idx, t.lro); + + if (t.lro >= 0) { + if (t.lro) + dev->wanted_features |= NETIF_F_GRO; + else + dev->wanted_features &= ~NETIF_F_GRO; + netdev_update_features(dev); + } break; } @@ -2269,7 +2217,7 @@ static int cxgb_extension_ioctl(struct net_device *dev, void __user *useraddr) t.fl_size[0] = q->fl_size; t.fl_size[1] = q->jumbo_size; t.polling = q->polling; - t.lro = q->lro; + t.lro = !!(dev->features & NETIF_F_GRO); t.intr_lat = q->coalesce_usecs; t.cong_thres = q->cong_thres; t.qnum = q1; @@ -3307,18 +3255,18 @@ static int __devinit init_one(struct pci_dev *pdev, adapter->port[i] = netdev; pi = netdev_priv(netdev); pi->adapter = adapter; - pi->rx_offload = T3_RX_CSUM | T3_LRO; pi->port_id = i; netif_carrier_off(netdev); netdev->irq = pdev->irq; netdev->mem_start = mmio_start; netdev->mem_end = mmio_start + mmio_len - 1; - netdev->features |= NETIF_F_SG | NETIF_F_IP_CSUM | NETIF_F_TSO; - netdev->features |= NETIF_F_GRO; + netdev->hw_features = NETIF_F_SG | NETIF_F_IP_CSUM | + NETIF_F_TSO | NETIF_F_RXCSUM; + netdev->features |= netdev->hw_features | + NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX; if (pci_using_dac) netdev->features |= NETIF_F_HIGHDMA; - netdev->features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX; netdev->netdev_ops = &cxgb_netdev_ops; SET_ETHTOOL_OPS(netdev, &cxgb_ethtool_ops); } diff --git a/drivers/net/cxgb3/sge.c b/drivers/net/cxgb3/sge.c index bfa2d56..cba1401 100644 --- a/drivers/net/cxgb3/sge.c +++ b/drivers/net/cxgb3/sge.c @@ -2019,7 +2019,7 @@ static void rx_eth(struct adapter *adap, struct sge_rspq *rq, skb_pull(skb, sizeof(*p) + pad); skb->protocol = eth_type_trans(skb, adap->port[p->iff]); pi = netdev_priv(skb->dev); - if ((pi->rx_offload & T3_RX_CSUM) && p->csum_valid && + if ((skb->dev->features & NETIF_F_RXCSUM) && p->csum_valid && p->csum == htons(0xffff) && !p->fragment) { qs->port_stats[SGE_PSTAT_RX_CSUM_GOOD]++; skb->ip_summed = CHECKSUM_UNNECESSARY; @@ -2120,7 +2120,7 @@ static void lro_add_page(struct adapter *adap, struct sge_qset *qs, offset = 2 + sizeof(struct cpl_rx_pkt); cpl = qs->lro_va = sd->pg_chunk.va + 2; - if ((pi->rx_offload & T3_RX_CSUM) && + if ((qs->netdev->features & NETIF_F_RXCSUM) && cpl->csum_valid && cpl->csum == htons(0xffff)) { skb->ip_summed = CHECKSUM_UNNECESSARY; qs->port_stats[SGE_PSTAT_RX_CSUM_GOOD]++; @@ -2285,7 +2285,8 @@ static int process_responses(struct adapter *adap, struct sge_qset *qs, q->next_holdoff = q->holdoff_tmr; while (likely(budget_left && is_new_response(r, q))) { - int packet_complete, eth, ethpad = 2, lro = qs->lro_enabled; + int packet_complete, eth, ethpad = 2; + int lro = !!(qs->netdev->features & NETIF_F_GRO); struct sk_buff *skb = NULL; u32 len, flags; __be32 rss_hi, rss_lo; -- cgit v0.10.2 From c8a75b345b38a9b63ffd077c0eb71707fa194fc6 Mon Sep 17 00:00:00 2001 From: Francois Romieu Date: Sun, 17 Apr 2011 17:46:40 -0700 Subject: r8169: add Realtek as maintainer. Per Hayes's request. Signed-off-by: Francois Romieu Signed-off-by: David S. Miller diff --git a/MAINTAINERS b/MAINTAINERS index 649600c..c85368d 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -151,6 +151,7 @@ S: Maintained F: drivers/net/hamradio/6pack.c 8169 10/100/1000 GIGABIT ETHERNET DRIVER +M: Realtek linux nic maintainers M: Francois Romieu L: netdev@vger.kernel.org S: Maintained -- cgit v0.10.2 From eea3250b43fd0b4fe565409bbf2fb06514213386 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Miros=C5=82aw?= Date: Sun, 17 Apr 2011 00:15:46 +0000 Subject: net: tehuti: convert to hw_features MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit As a side effect, make TX offloads changeable. Signed-off-by: MichaÅ‚ MirosÅ‚aw Signed-off-by: David S. Miller diff --git a/drivers/net/tehuti.c b/drivers/net/tehuti.c index 8564ec5..8be71de 100644 --- a/drivers/net/tehuti.c +++ b/drivers/net/tehuti.c @@ -2017,9 +2017,11 @@ bdx_probe(struct pci_dev *pdev, const struct pci_device_id *ent) ndev->irq = pdev->irq; ndev->features = NETIF_F_IP_CSUM | NETIF_F_SG | NETIF_F_TSO | NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX | - NETIF_F_HW_VLAN_FILTER + NETIF_F_HW_VLAN_FILTER | NETIF_F_RXCSUM /*| NETIF_F_FRAGLIST */ ; + ndev->hw_features = NETIF_F_IP_CSUM | NETIF_F_SG | + NETIF_F_TSO | NETIF_F_HW_VLAN_TX; if (pci_using_dac) ndev->features |= NETIF_F_HIGHDMA; @@ -2188,24 +2190,6 @@ bdx_get_drvinfo(struct net_device *netdev, struct ethtool_drvinfo *drvinfo) } /* - * bdx_get_rx_csum - report whether receive checksums are turned on or off - * @netdev - */ -static u32 bdx_get_rx_csum(struct net_device *netdev) -{ - return 1; /* always on */ -} - -/* - * bdx_get_tx_csum - report whether transmit checksums are turned on or off - * @netdev - */ -static u32 bdx_get_tx_csum(struct net_device *netdev) -{ - return (netdev->features & NETIF_F_IP_CSUM) != 0; -} - -/* * bdx_get_coalesce - get interrupt coalescing parameters * @netdev * @ecoal @@ -2424,10 +2408,6 @@ static void bdx_set_ethtool_ops(struct net_device *netdev) .set_coalesce = bdx_set_coalesce, .get_ringparam = bdx_get_ringparam, .set_ringparam = bdx_set_ringparam, - .get_rx_csum = bdx_get_rx_csum, - .get_tx_csum = bdx_get_tx_csum, - .get_sg = ethtool_op_get_sg, - .get_tso = ethtool_op_get_tso, .get_strings = bdx_get_strings, .get_sset_count = bdx_get_sset_count, .get_ethtool_stats = bdx_get_ethtool_stats, -- cgit v0.10.2 From aad59c431b77be5cbfa01f2066a036b95981fed9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Miros=C5=82aw?= Date: Sun, 17 Apr 2011 00:15:46 +0000 Subject: net: mv643xx: convert to hw_features MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Side effect: don't reenable RXCSUM on every ifdown/ifup. Signed-off-by: MichaÅ‚ MirosÅ‚aw Signed-off-by: David S. Miller diff --git a/drivers/net/mv643xx_eth.c b/drivers/net/mv643xx_eth.c index 34425b9..29605a3 100644 --- a/drivers/net/mv643xx_eth.c +++ b/drivers/net/mv643xx_eth.c @@ -1575,18 +1575,12 @@ mv643xx_eth_set_ringparam(struct net_device *dev, struct ethtool_ringparam *er) return 0; } -static u32 -mv643xx_eth_get_rx_csum(struct net_device *dev) -{ - struct mv643xx_eth_private *mp = netdev_priv(dev); - - return !!(rdlp(mp, PORT_CONFIG) & 0x02000000); -} static int -mv643xx_eth_set_rx_csum(struct net_device *dev, u32 rx_csum) +mv643xx_eth_set_features(struct net_device *dev, u32 features) { struct mv643xx_eth_private *mp = netdev_priv(dev); + u32 rx_csum = features & NETIF_F_RXCSUM; wrlp(mp, PORT_CONFIG, rx_csum ? 0x02000000 : 0x00000000); @@ -1634,11 +1628,6 @@ static void mv643xx_eth_get_ethtool_stats(struct net_device *dev, } } -static int mv643xx_eth_set_flags(struct net_device *dev, u32 data) -{ - return ethtool_op_set_flags(dev, data, ETH_FLAG_LRO); -} - static int mv643xx_eth_get_sset_count(struct net_device *dev, int sset) { if (sset == ETH_SS_STATS) @@ -1657,14 +1646,8 @@ static const struct ethtool_ops mv643xx_eth_ethtool_ops = { .set_coalesce = mv643xx_eth_set_coalesce, .get_ringparam = mv643xx_eth_get_ringparam, .set_ringparam = mv643xx_eth_set_ringparam, - .get_rx_csum = mv643xx_eth_get_rx_csum, - .set_rx_csum = mv643xx_eth_set_rx_csum, - .set_tx_csum = ethtool_op_set_tx_csum, - .set_sg = ethtool_op_set_sg, .get_strings = mv643xx_eth_get_strings, .get_ethtool_stats = mv643xx_eth_get_ethtool_stats, - .get_flags = ethtool_op_get_flags, - .set_flags = mv643xx_eth_set_flags, .get_sset_count = mv643xx_eth_get_sset_count, }; @@ -2264,7 +2247,7 @@ static void port_start(struct mv643xx_eth_private *mp) * frames to RX queue #0, and include the pseudo-header when * calculating receive checksums. */ - wrlp(mp, PORT_CONFIG, 0x02000000); + mv643xx_eth_set_features(dev, dev->features); /* * Treat BPDUs as normal multicasts, and disable partition mode. @@ -2848,6 +2831,7 @@ static const struct net_device_ops mv643xx_eth_netdev_ops = { .ndo_validate_addr = eth_validate_addr, .ndo_do_ioctl = mv643xx_eth_ioctl, .ndo_change_mtu = mv643xx_eth_change_mtu, + .ndo_set_features = mv643xx_eth_set_features, .ndo_tx_timeout = mv643xx_eth_tx_timeout, .ndo_get_stats = mv643xx_eth_get_stats, #ifdef CONFIG_NET_POLL_CONTROLLER @@ -2930,7 +2914,9 @@ static int mv643xx_eth_probe(struct platform_device *pdev) dev->watchdog_timeo = 2 * HZ; dev->base_addr = 0; - dev->features = NETIF_F_SG | NETIF_F_IP_CSUM; + dev->hw_features = NETIF_F_SG | NETIF_F_IP_CSUM | + NETIF_F_RXCSUM | NETIF_F_LRO; + dev->features = NETIF_F_SG | NETIF_F_IP_CSUM | NETIF_F_RXCSUM; dev->vlan_features = NETIF_F_SG | NETIF_F_IP_CSUM; SET_NETDEV_DEV(dev, &pdev->dev); -- cgit v0.10.2 From 86688a8f132a7630f8610c13a349c711fe683b44 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Miros=C5=82aw?= Date: Sun, 17 Apr 2011 00:15:47 +0000 Subject: net: typhoon: convert to hw_features MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: MichaÅ‚ MirosÅ‚aw Signed-off-by: David S. Miller diff --git a/drivers/net/typhoon.c b/drivers/net/typhoon.c index 82653cb..119c394 100644 --- a/drivers/net/typhoon.c +++ b/drivers/net/typhoon.c @@ -1144,28 +1144,6 @@ typhoon_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol) return 0; } -static u32 -typhoon_get_rx_csum(struct net_device *dev) -{ - /* For now, we don't allow turning off RX checksums. - */ - return 1; -} - -static int -typhoon_set_flags(struct net_device *dev, u32 data) -{ - /* There's no way to turn off the RX VLAN offloading and stripping - * on the current 3XP firmware -- it does not respect the offload - * settings -- so we only allow the user to toggle the TX processing. - */ - if (!(data & ETH_FLAG_RXVLAN)) - return -EINVAL; - - return ethtool_op_set_flags(dev, data, - ETH_FLAG_RXVLAN | ETH_FLAG_TXVLAN); -} - static void typhoon_get_ringparam(struct net_device *dev, struct ethtool_ringparam *ering) { @@ -1187,13 +1165,7 @@ static const struct ethtool_ops typhoon_ethtool_ops = { .get_wol = typhoon_get_wol, .set_wol = typhoon_set_wol, .get_link = ethtool_op_get_link, - .get_rx_csum = typhoon_get_rx_csum, - .set_tx_csum = ethtool_op_set_tx_csum, - .set_sg = ethtool_op_set_sg, - .set_tso = ethtool_op_set_tso, .get_ringparam = typhoon_get_ringparam, - .set_flags = typhoon_set_flags, - .get_flags = ethtool_op_get_flags, }; static int @@ -2482,10 +2454,15 @@ typhoon_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) /* We can handle scatter gather, up to 16 entries, and * we can do IP checksumming (only version 4, doh...) + * + * There's no way to turn off the RX VLAN offloading and stripping + * on the current 3XP firmware -- it does not respect the offload + * settings -- so we only allow the user to toggle the TX processing. */ - dev->features |= NETIF_F_SG | NETIF_F_IP_CSUM; - dev->features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX; - dev->features |= NETIF_F_TSO; + dev->hw_features = NETIF_F_SG | NETIF_F_IP_CSUM | NETIF_F_TSO | + NETIF_F_HW_VLAN_TX; + dev->features = dev->hw_features | + NETIF_F_HW_VLAN_RX | NETIF_F_RXCSUM; if(register_netdev(dev) < 0) { err_msg = "unable to register netdev"; -- cgit v0.10.2 From 66a1c5413260a8c302b4024555c489cc6731b463 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Miros=C5=82aw?= Date: Sun, 17 Apr 2011 00:15:47 +0000 Subject: net: benet: convert to hw_features - fixup MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Remove be_set_flags() as it's already covered by hw_features. Signed-off-by: MichaÅ‚ MirosÅ‚aw Acked-by: Ajit Khaparde ajit.khaparde@emulex.com Signed-off-by: David S. Miller diff --git a/drivers/net/benet/be_ethtool.c b/drivers/net/benet/be_ethtool.c index 0f645a9..28716a6 100644 --- a/drivers/net/benet/be_ethtool.c +++ b/drivers/net/benet/be_ethtool.c @@ -712,18 +712,6 @@ be_read_eeprom(struct net_device *netdev, struct ethtool_eeprom *eeprom, return status; } -static int be_set_flags(struct net_device *netdev, u32 data) -{ - struct be_adapter *adapter = netdev_priv(netdev); - int rc = -1; - - if (be_multi_rxq(adapter)) - rc = ethtool_op_set_flags(netdev, data, ETH_FLAG_RXHASH | - ETH_FLAG_TXVLAN | ETH_FLAG_RXVLAN); - - return rc; -} - const struct ethtool_ops be_ethtool_ops = { .get_settings = be_get_settings, .get_drvinfo = be_get_drvinfo, @@ -745,5 +733,4 @@ const struct ethtool_ops be_ethtool_ops = { .get_regs = be_get_regs, .flash_device = be_do_flash, .self_test = be_self_test, - .set_flags = be_set_flags, }; -- cgit v0.10.2 From f4786a96252b97f6f05cd42ea7fe6e967048bfa3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Miros=C5=82aw?= Date: Sun, 17 Apr 2011 00:15:47 +0000 Subject: net: ehea: convert to hw_features MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: MichaÅ‚ MirosÅ‚aw Signed-off-by: David S. Miller diff --git a/drivers/net/ehea/ehea_ethtool.c b/drivers/net/ehea/ehea_ethtool.c index 3e2e734..5f13491 100644 --- a/drivers/net/ehea/ehea_ethtool.c +++ b/drivers/net/ehea/ehea_ethtool.c @@ -162,11 +162,6 @@ static void ehea_set_msglevel(struct net_device *dev, u32 value) port->msg_enable = value; } -static u32 ehea_get_rx_csum(struct net_device *dev) -{ - return 1; -} - static char ehea_ethtool_stats_keys[][ETH_GSTRING_LEN] = { {"sig_comp_iv"}, {"swqe_refill_th"}, @@ -263,34 +258,16 @@ static void ehea_get_ethtool_stats(struct net_device *dev, } -static int ehea_set_flags(struct net_device *dev, u32 data) -{ - /* Avoid changing the VLAN flags */ - if ((data & (ETH_FLAG_RXVLAN | ETH_FLAG_TXVLAN)) != - (ethtool_op_get_flags(dev) & (ETH_FLAG_RXVLAN | - ETH_FLAG_TXVLAN))){ - return -EINVAL; - } - - return ethtool_op_set_flags(dev, data, ETH_FLAG_LRO - | ETH_FLAG_TXVLAN - | ETH_FLAG_RXVLAN); -} - const struct ethtool_ops ehea_ethtool_ops = { .get_settings = ehea_get_settings, .get_drvinfo = ehea_get_drvinfo, .get_msglevel = ehea_get_msglevel, .set_msglevel = ehea_set_msglevel, .get_link = ethtool_op_get_link, - .set_tso = ethtool_op_set_tso, .get_strings = ehea_get_strings, .get_sset_count = ehea_get_sset_count, .get_ethtool_stats = ehea_get_ethtool_stats, - .get_rx_csum = ehea_get_rx_csum, .set_settings = ehea_set_settings, - .get_flags = ethtool_op_get_flags, - .set_flags = ehea_set_flags, .nway_reset = ehea_nway_reset, /* Restart autonegotiation */ }; diff --git a/drivers/net/ehea/ehea_main.c b/drivers/net/ehea/ehea_main.c index f75d314..ce2f0ca 100644 --- a/drivers/net/ehea/ehea_main.c +++ b/drivers/net/ehea/ehea_main.c @@ -3262,10 +3262,12 @@ struct ehea_port *ehea_setup_single_port(struct ehea_adapter *adapter, dev->netdev_ops = &ehea_netdev_ops; ehea_set_ethtool_ops(dev); + dev->hw_features = NETIF_F_SG | NETIF_F_FRAGLIST | NETIF_F_TSO + | NETIF_F_IP_CSUM | NETIF_F_HW_VLAN_TX | NETIF_F_LRO; dev->features = NETIF_F_SG | NETIF_F_FRAGLIST | NETIF_F_TSO | NETIF_F_HIGHDMA | NETIF_F_IP_CSUM | NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX | NETIF_F_HW_VLAN_FILTER - | NETIF_F_LLTX; + | NETIF_F_LLTX | NETIF_F_RXCSUM; dev->watchdog_timeo = EHEA_WATCH_DOG_TIMEOUT; if (use_lro) -- cgit v0.10.2 From 3cd8ef4b6071834fd432bbccbec0611591908643 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Miros=C5=82aw?= Date: Sun, 17 Apr 2011 00:15:47 +0000 Subject: net: niu: convert to hw_features MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Side effect: allow toggling of TX offloads. Signed-off-by: MichaÅ‚ MirosÅ‚aw Signed-off-by: David S. Miller diff --git a/drivers/net/niu.c b/drivers/net/niu.c index ea2272f..a707217 100644 --- a/drivers/net/niu.c +++ b/drivers/net/niu.c @@ -7913,11 +7913,6 @@ static int niu_set_phys_id(struct net_device *dev, return 0; } -static int niu_set_flags(struct net_device *dev, u32 data) -{ - return ethtool_op_set_flags(dev, data, ETH_FLAG_RXHASH); -} - static const struct ethtool_ops niu_ethtool_ops = { .get_drvinfo = niu_get_drvinfo, .get_link = ethtool_op_get_link, @@ -7934,8 +7929,6 @@ static const struct ethtool_ops niu_ethtool_ops = { .set_phys_id = niu_set_phys_id, .get_rxnfc = niu_get_nfc, .set_rxnfc = niu_set_nfc, - .set_flags = niu_set_flags, - .get_flags = ethtool_op_get_flags, }; static int niu_ldg_assign_ldn(struct niu *np, struct niu_parent *parent, @@ -9764,8 +9757,8 @@ static void __devinit niu_device_announce(struct niu *np) static void __devinit niu_set_basic_features(struct net_device *dev) { - dev->features |= (NETIF_F_SG | NETIF_F_HW_CSUM | - NETIF_F_GRO | NETIF_F_RXHASH); + dev->hw_features = NETIF_F_SG | NETIF_F_HW_CSUM | NETIF_F_RXHASH; + dev->features |= dev->hw_features | NETIF_F_RXCSUM; } static int __devinit niu_pci_init_one(struct pci_dev *pdev, -- cgit v0.10.2 From 131ae329702755d897c6072c7839086b0702fb10 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Miros=C5=82aw?= Date: Sun, 17 Apr 2011 00:15:47 +0000 Subject: net: greth: convert to hw_features MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Note: Driver modifies its struct net_device_ops. This will break if used for multiple devices that are not all the same (if that HW config is possible). Signed-off-by: MichaÅ‚ MirosÅ‚aw Signed-off-by: David S. Miller diff --git a/drivers/net/greth.c b/drivers/net/greth.c index 396ff7d..f181304 100644 --- a/drivers/net/greth.c +++ b/drivers/net/greth.c @@ -901,7 +901,7 @@ static int greth_rx_gbit(struct net_device *dev, int limit) skb_put(skb, pkt_len); - if (greth->flags & GRETH_FLAG_RX_CSUM && hw_checksummed(status)) + if (dev->features & NETIF_F_RXCSUM && hw_checksummed(status)) skb->ip_summed = CHECKSUM_UNNECESSARY; else skb_checksum_none_assert(skb); @@ -1142,41 +1142,6 @@ static void greth_get_regs(struct net_device *dev, struct ethtool_regs *regs, vo buff[i] = greth_read_bd(&greth_regs[i]); } -static u32 greth_get_rx_csum(struct net_device *dev) -{ - struct greth_private *greth = netdev_priv(dev); - return (greth->flags & GRETH_FLAG_RX_CSUM) != 0; -} - -static int greth_set_rx_csum(struct net_device *dev, u32 data) -{ - struct greth_private *greth = netdev_priv(dev); - - spin_lock_bh(&greth->devlock); - - if (data) - greth->flags |= GRETH_FLAG_RX_CSUM; - else - greth->flags &= ~GRETH_FLAG_RX_CSUM; - - spin_unlock_bh(&greth->devlock); - - return 0; -} - -static u32 greth_get_tx_csum(struct net_device *dev) -{ - return (dev->features & NETIF_F_IP_CSUM) != 0; -} - -static int greth_set_tx_csum(struct net_device *dev, u32 data) -{ - netif_tx_lock_bh(dev); - ethtool_op_set_tx_csum(dev, data); - netif_tx_unlock_bh(dev); - return 0; -} - static const struct ethtool_ops greth_ethtool_ops = { .get_msglevel = greth_get_msglevel, .set_msglevel = greth_set_msglevel, @@ -1185,10 +1150,6 @@ static const struct ethtool_ops greth_ethtool_ops = { .get_drvinfo = greth_get_drvinfo, .get_regs_len = greth_get_regs_len, .get_regs = greth_get_regs, - .get_rx_csum = greth_get_rx_csum, - .set_rx_csum = greth_set_rx_csum, - .get_tx_csum = greth_get_tx_csum, - .set_tx_csum = greth_set_tx_csum, .get_link = ethtool_op_get_link, }; @@ -1570,9 +1531,10 @@ static int __devinit greth_of_probe(struct platform_device *ofdev) GRETH_REGSAVE(regs->status, 0xFF); if (greth->gbit_mac) { - dev->features = NETIF_F_SG | NETIF_F_IP_CSUM | NETIF_F_HIGHDMA; + dev->hw_features = NETIF_F_SG | NETIF_F_IP_CSUM | + NETIF_F_RXCSUM; + dev->features = dev->hw_features | NETIF_F_HIGHDMA; greth_netdev_ops.ndo_start_xmit = greth_start_xmit_gbit; - greth->flags = GRETH_FLAG_RX_CSUM; } if (greth->multicast) { diff --git a/drivers/net/greth.h b/drivers/net/greth.h index be0f206..9a0040d 100644 --- a/drivers/net/greth.h +++ b/drivers/net/greth.h @@ -77,9 +77,6 @@ */ #define MAX_FRAME_SIZE 1520 -/* Flags */ -#define GRETH_FLAG_RX_CSUM 0x1 - /* GRETH APB registers */ struct greth_regs { u32 control; @@ -133,7 +130,6 @@ struct greth_private { unsigned int duplex; u32 msg_enable; - u32 flags; u8 phyaddr; u8 multicast; -- cgit v0.10.2 From 5e4011e2b8032cd132d9482f016558f1b27569cd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Miros=C5=82aw?= Date: Sun, 17 Apr 2011 00:15:47 +0000 Subject: net: ibm_newemac: convert to hw_features MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Side effect: allow toggling of TX offloads. Signed-off-by: MichaÅ‚ MirosÅ‚aw Signed-off-by: David S. Miller diff --git a/drivers/net/ibm_newemac/core.c b/drivers/net/ibm_newemac/core.c index 3bb990b..079450f 100644 --- a/drivers/net/ibm_newemac/core.c +++ b/drivers/net/ibm_newemac/core.c @@ -2053,13 +2053,6 @@ static void emac_ethtool_get_pauseparam(struct net_device *ndev, mutex_unlock(&dev->link_lock); } -static u32 emac_ethtool_get_rx_csum(struct net_device *ndev) -{ - struct emac_instance *dev = netdev_priv(ndev); - - return dev->tah_dev != NULL; -} - static int emac_get_regs_len(struct emac_instance *dev) { if (emac_has_feature(dev, EMAC_FTR_EMAC4)) @@ -2203,15 +2196,11 @@ static const struct ethtool_ops emac_ethtool_ops = { .get_ringparam = emac_ethtool_get_ringparam, .get_pauseparam = emac_ethtool_get_pauseparam, - .get_rx_csum = emac_ethtool_get_rx_csum, - .get_strings = emac_ethtool_get_strings, .get_sset_count = emac_ethtool_get_sset_count, .get_ethtool_stats = emac_ethtool_get_ethtool_stats, .get_link = ethtool_op_get_link, - .get_tx_csum = ethtool_op_get_tx_csum, - .get_sg = ethtool_op_get_sg, }; static int emac_ioctl(struct net_device *ndev, struct ifreq *rq, int cmd) @@ -2859,8 +2848,10 @@ static int __devinit emac_probe(struct platform_device *ofdev) if (err != 0) goto err_detach_tah; - if (dev->tah_dev) - ndev->features |= NETIF_F_IP_CSUM | NETIF_F_SG; + if (dev->tah_dev) { + ndev->hw_features = NETIF_F_IP_CSUM | NETIF_F_SG; + ndev->features |= ndev->hw_features | NETIF_F_RXCSUM; + } ndev->watchdog_timeo = 5 * HZ; if (emac_phy_supports_gige(dev->phy_mode)) { ndev->netdev_ops = &emac_gige_netdev_ops; -- cgit v0.10.2 From c582a950b1d7488750831cb4499de071781c7f45 Mon Sep 17 00:00:00 2001 From: Thiago Farina Date: Sun, 17 Apr 2011 17:49:21 -0700 Subject: drivers/net/usb/usbnet.c: Use FIELD_SIZEOF macro in usbnet_init() function. Signed-off-by: Thiago Farina Signed-off-by: David S. Miller diff --git a/drivers/net/usb/usbnet.c b/drivers/net/usb/usbnet.c index 069c1cf..7bc9852 100644 --- a/drivers/net/usb/usbnet.c +++ b/drivers/net/usb/usbnet.c @@ -1529,9 +1529,9 @@ EXPORT_SYMBOL_GPL(usbnet_resume); static int __init usbnet_init(void) { - /* compiler should optimize this out */ - BUILD_BUG_ON (sizeof (((struct sk_buff *)0)->cb) - < sizeof (struct skb_data)); + /* Compiler should optimize this out. */ + BUILD_BUG_ON( + FIELD_SIZEOF(struct sk_buff, cb) < sizeof(struct skb_data)); random_ether_addr(node_id); return 0; -- cgit v0.10.2 From 70dda99c41fc8a153e09bdba9adb7805ba2a4bb3 Mon Sep 17 00:00:00 2001 From: Yaniv Rosner Date: Sun, 17 Apr 2011 17:50:01 -0700 Subject: bnx2x: Fix port identification problem This patch fixes port identification on optic devices when there's no link on the port. Signed-off-by: Yaniv Rosner Signed-off-by: Eilon Greenstein Signed-off-by: David S. Miller diff --git a/drivers/net/bnx2x/bnx2x_ethtool.c b/drivers/net/bnx2x/bnx2x_ethtool.c index f505015..89cb977 100644 --- a/drivers/net/bnx2x/bnx2x_ethtool.c +++ b/drivers/net/bnx2x/bnx2x_ethtool.c @@ -2114,19 +2114,18 @@ static int bnx2x_phys_id(struct net_device *dev, u32 data) for (i = 0; i < (data * 2); i++) { if ((i % 2) == 0) bnx2x_set_led(&bp->link_params, &bp->link_vars, - LED_MODE_OPER, SPEED_1000); + LED_MODE_ON, SPEED_1000); else bnx2x_set_led(&bp->link_params, &bp->link_vars, - LED_MODE_OFF, 0); + LED_MODE_FRONT_PANEL_OFF, 0); msleep_interruptible(500); if (signal_pending(current)) break; } - if (bp->link_vars.link_up) - bnx2x_set_led(&bp->link_params, &bp->link_vars, LED_MODE_OPER, - bp->link_vars.line_speed); + bnx2x_set_led(&bp->link_params, &bp->link_vars, + LED_MODE_OPER, bp->link_vars.line_speed); return 0; } -- cgit v0.10.2 From 2ed28baa7076083b56c1e70ccd927b7870117c59 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Miros=C5=82aw?= Date: Sat, 16 Apr 2011 13:05:08 +0000 Subject: net: cxgb4{,vf}: convert to hw_features MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: MichaÅ‚ MirosÅ‚aw Acked-by: Dimitris Michailidis Signed-off-by: David S. Miller diff --git a/drivers/net/cxgb4/cxgb4.h b/drivers/net/cxgb4/cxgb4.h index 01d49ea..bc9982a 100644 --- a/drivers/net/cxgb4/cxgb4.h +++ b/drivers/net/cxgb4/cxgb4.h @@ -290,7 +290,6 @@ struct port_info { u8 port_id; u8 tx_chan; u8 lport; /* associated offload logical port */ - u8 rx_offload; /* CSO, etc */ u8 nqsets; /* # of qsets */ u8 first_qset; /* index of first qset */ u8 rss_mode; @@ -298,11 +297,6 @@ struct port_info { u16 *rss; }; -/* port_info.rx_offload flags */ -enum { - RX_CSO = 1 << 0, -}; - struct dentry; struct work_struct; diff --git a/drivers/net/cxgb4/cxgb4_main.c b/drivers/net/cxgb4/cxgb4_main.c index 0af9c9f..bdc868c 100644 --- a/drivers/net/cxgb4/cxgb4_main.c +++ b/drivers/net/cxgb4/cxgb4_main.c @@ -1531,24 +1531,6 @@ static int set_pauseparam(struct net_device *dev, return 0; } -static u32 get_rx_csum(struct net_device *dev) -{ - struct port_info *p = netdev_priv(dev); - - return p->rx_offload & RX_CSO; -} - -static int set_rx_csum(struct net_device *dev, u32 data) -{ - struct port_info *p = netdev_priv(dev); - - if (data) - p->rx_offload |= RX_CSO; - else - p->rx_offload &= ~RX_CSO; - return 0; -} - static void get_sge_param(struct net_device *dev, struct ethtool_ringparam *e) { const struct port_info *pi = netdev_priv(dev); @@ -1870,36 +1852,20 @@ static int set_wol(struct net_device *dev, struct ethtool_wolinfo *wol) return err; } -#define TSO_FLAGS (NETIF_F_TSO | NETIF_F_TSO6 | NETIF_F_TSO_ECN) - -static int set_tso(struct net_device *dev, u32 value) -{ - if (value) - dev->features |= TSO_FLAGS; - else - dev->features &= ~TSO_FLAGS; - return 0; -} - -static int set_flags(struct net_device *dev, u32 flags) +static int cxgb_set_features(struct net_device *dev, u32 features) { + const struct port_info *pi = netdev_priv(dev); + u32 changed = dev->features ^ features; int err; - unsigned long old_feat = dev->features; - - err = ethtool_op_set_flags(dev, flags, ETH_FLAG_RXHASH | - ETH_FLAG_RXVLAN | ETH_FLAG_TXVLAN); - if (err) - return err; - if ((old_feat ^ dev->features) & NETIF_F_HW_VLAN_RX) { - const struct port_info *pi = netdev_priv(dev); + if (!(changed & NETIF_F_HW_VLAN_RX)) + return 0; - err = t4_set_rxmode(pi->adapter, pi->adapter->fn, pi->viid, -1, - -1, -1, -1, !!(flags & ETH_FLAG_RXVLAN), - true); - if (err) - dev->features = old_feat; - } + err = t4_set_rxmode(pi->adapter, pi->adapter->fn, pi->viid, -1, + -1, -1, -1, + !!(features & NETIF_F_HW_VLAN_RX), true); + if (unlikely(err)) + dev->features = features ^ NETIF_F_HW_VLAN_RX; return err; } @@ -2010,10 +1976,6 @@ static struct ethtool_ops cxgb_ethtool_ops = { .set_eeprom = set_eeprom, .get_pauseparam = get_pauseparam, .set_pauseparam = set_pauseparam, - .get_rx_csum = get_rx_csum, - .set_rx_csum = set_rx_csum, - .set_tx_csum = ethtool_op_set_tx_ipv6_csum, - .set_sg = ethtool_op_set_sg, .get_link = ethtool_op_get_link, .get_strings = get_strings, .set_phys_id = identify_port, @@ -2024,8 +1986,6 @@ static struct ethtool_ops cxgb_ethtool_ops = { .get_regs = get_regs, .get_wol = get_wol, .set_wol = set_wol, - .set_tso = set_tso, - .set_flags = set_flags, .get_rxnfc = get_rxnfc, .get_rxfh_indir = get_rss_table, .set_rxfh_indir = set_rss_table, @@ -2882,6 +2842,7 @@ static const struct net_device_ops cxgb4_netdev_ops = { .ndo_get_stats64 = cxgb_get_stats, .ndo_set_rx_mode = cxgb_set_rxmode, .ndo_set_mac_address = cxgb_set_mac_addr, + .ndo_set_features = cxgb_set_features, .ndo_validate_addr = eth_validate_addr, .ndo_do_ioctl = cxgb_ioctl, .ndo_change_mtu = cxgb_change_mtu, @@ -3564,6 +3525,7 @@ static void free_some_resources(struct adapter *adapter) t4_fw_bye(adapter, adapter->fn); } +#define TSO_FLAGS (NETIF_F_TSO | NETIF_F_TSO6 | NETIF_F_TSO_ECN) #define VLAN_FEAT (NETIF_F_SG | NETIF_F_IP_CSUM | TSO_FLAGS | \ NETIF_F_IPV6_CSUM | NETIF_F_HIGHDMA) @@ -3665,14 +3627,14 @@ static int __devinit init_one(struct pci_dev *pdev, pi = netdev_priv(netdev); pi->adapter = adapter; pi->xact_addr_filt = -1; - pi->rx_offload = RX_CSO; pi->port_id = i; netdev->irq = pdev->irq; - netdev->features |= NETIF_F_SG | TSO_FLAGS; - netdev->features |= NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM; - netdev->features |= NETIF_F_GRO | NETIF_F_RXHASH | highdma; - netdev->features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX; + netdev->hw_features = NETIF_F_SG | TSO_FLAGS | + NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM | + NETIF_F_RXCSUM | NETIF_F_RXHASH | + NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX; + netdev->features |= netdev->hw_features | highdma; netdev->vlan_features = netdev->features & VLAN_FEAT; netdev->netdev_ops = &cxgb4_netdev_ops; diff --git a/drivers/net/cxgb4/sge.c b/drivers/net/cxgb4/sge.c index 311471b..75a4b0f 100644 --- a/drivers/net/cxgb4/sge.c +++ b/drivers/net/cxgb4/sge.c @@ -1556,7 +1556,6 @@ int t4_ethrx_handler(struct sge_rspq *q, const __be64 *rsp, { bool csum_ok; struct sk_buff *skb; - struct port_info *pi; const struct cpl_rx_pkt *pkt; struct sge_eth_rxq *rxq = container_of(q, struct sge_eth_rxq, rspq); @@ -1584,10 +1583,9 @@ int t4_ethrx_handler(struct sge_rspq *q, const __be64 *rsp, if (skb->dev->features & NETIF_F_RXHASH) skb->rxhash = (__force u32)pkt->rsshdr.hash_val; - pi = netdev_priv(skb->dev); rxq->stats.pkts++; - if (csum_ok && (pi->rx_offload & RX_CSO) && + if (csum_ok && (q->netdev->features & NETIF_F_RXCSUM) && (pkt->l2info & htonl(RXF_UDP | RXF_TCP))) { if (!pkt->ip_frag) { skb->ip_summed = CHECKSUM_UNNECESSARY; diff --git a/drivers/net/cxgb4vf/adapter.h b/drivers/net/cxgb4vf/adapter.h index 4766b41..4fd821a 100644 --- a/drivers/net/cxgb4vf/adapter.h +++ b/drivers/net/cxgb4vf/adapter.h @@ -97,17 +97,11 @@ struct port_info { u16 rss_size; /* size of VI's RSS table slice */ u8 pidx; /* index into adapter port[] */ u8 port_id; /* physical port ID */ - u8 rx_offload; /* CSO, etc. */ u8 nqsets; /* # of "Queue Sets" */ u8 first_qset; /* index of first "Queue Set" */ struct link_config link_cfg; /* physical port configuration */ }; -/* port_info.rx_offload flags */ -enum { - RX_CSO = 1 << 0, -}; - /* * Scatter Gather Engine resources for the "adapter". Our ingress and egress * queues are organized into "Queue Sets" with one ingress and one egress diff --git a/drivers/net/cxgb4vf/cxgb4vf_main.c b/drivers/net/cxgb4vf/cxgb4vf_main.c index c662679..8cf9890 100644 --- a/drivers/net/cxgb4vf/cxgb4vf_main.c +++ b/drivers/net/cxgb4vf/cxgb4vf_main.c @@ -1326,30 +1326,6 @@ static void cxgb4vf_get_pauseparam(struct net_device *dev, } /* - * Return whether RX Checksum Offloading is currently enabled for the device. - */ -static u32 cxgb4vf_get_rx_csum(struct net_device *dev) -{ - struct port_info *pi = netdev_priv(dev); - - return (pi->rx_offload & RX_CSO) != 0; -} - -/* - * Turn RX Checksum Offloading on or off for the device. - */ -static int cxgb4vf_set_rx_csum(struct net_device *dev, u32 csum) -{ - struct port_info *pi = netdev_priv(dev); - - if (csum) - pi->rx_offload |= RX_CSO; - else - pi->rx_offload &= ~RX_CSO; - return 0; -} - -/* * Identify the port by blinking the port's LED. */ static int cxgb4vf_phys_id(struct net_device *dev, @@ -1569,18 +1545,6 @@ static void cxgb4vf_get_wol(struct net_device *dev, */ #define TSO_FLAGS (NETIF_F_TSO | NETIF_F_TSO6 | NETIF_F_TSO_ECN) -/* - * Set TCP Segmentation Offloading feature capabilities. - */ -static int cxgb4vf_set_tso(struct net_device *dev, u32 tso) -{ - if (tso) - dev->features |= TSO_FLAGS; - else - dev->features &= ~TSO_FLAGS; - return 0; -} - static struct ethtool_ops cxgb4vf_ethtool_ops = { .get_settings = cxgb4vf_get_settings, .get_drvinfo = cxgb4vf_get_drvinfo, @@ -1591,10 +1555,6 @@ static struct ethtool_ops cxgb4vf_ethtool_ops = { .get_coalesce = cxgb4vf_get_coalesce, .set_coalesce = cxgb4vf_set_coalesce, .get_pauseparam = cxgb4vf_get_pauseparam, - .get_rx_csum = cxgb4vf_get_rx_csum, - .set_rx_csum = cxgb4vf_set_rx_csum, - .set_tx_csum = ethtool_op_set_tx_ipv6_csum, - .set_sg = ethtool_op_set_sg, .get_link = ethtool_op_get_link, .get_strings = cxgb4vf_get_strings, .set_phys_id = cxgb4vf_phys_id, @@ -1603,7 +1563,6 @@ static struct ethtool_ops cxgb4vf_ethtool_ops = { .get_regs_len = cxgb4vf_get_regs_len, .get_regs = cxgb4vf_get_regs, .get_wol = cxgb4vf_get_wol, - .set_tso = cxgb4vf_set_tso, }; /* @@ -2638,19 +2597,19 @@ static int __devinit cxgb4vf_pci_probe(struct pci_dev *pdev, * it. */ pi->xact_addr_filt = -1; - pi->rx_offload = RX_CSO; netif_carrier_off(netdev); netdev->irq = pdev->irq; - netdev->features = (NETIF_F_SG | TSO_FLAGS | - NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM | - NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX | - NETIF_F_GRO); + netdev->hw_features = NETIF_F_SG | TSO_FLAGS | + NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM | + NETIF_F_HW_VLAN_TX | NETIF_F_RXCSUM; + netdev->vlan_features = NETIF_F_SG | TSO_FLAGS | + NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM | + NETIF_F_HIGHDMA; + netdev->features = netdev->hw_features | + NETIF_F_HW_VLAN_RX; if (pci_using_dac) netdev->features |= NETIF_F_HIGHDMA; - netdev->vlan_features = - (netdev->features & - ~(NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX)); #ifdef HAVE_NET_DEVICE_OPS netdev->netdev_ops = &cxgb4vf_netdev_ops; diff --git a/drivers/net/cxgb4vf/sge.c b/drivers/net/cxgb4vf/sge.c index bb65121..5182960 100644 --- a/drivers/net/cxgb4vf/sge.c +++ b/drivers/net/cxgb4vf/sge.c @@ -1555,8 +1555,8 @@ int t4vf_ethrx_handler(struct sge_rspq *rspq, const __be64 *rsp, pi = netdev_priv(skb->dev); rxq->stats.pkts++; - if (csum_ok && (pi->rx_offload & RX_CSO) && !pkt->err_vec && - (be32_to_cpu(pkt->l2info) & (RXF_UDP|RXF_TCP))) { + if (csum_ok && (rspq->netdev->features & NETIF_F_RXCSUM) && + !pkt->err_vec && (be32_to_cpu(pkt->l2info) & (RXF_UDP|RXF_TCP))) { if (!pkt->ip_frag) skb->ip_summed = CHECKSUM_UNNECESSARY; else { -- cgit v0.10.2 From 28674b97cfb907b0b3de7b7fea89efda1e65f34e Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Sun, 17 Apr 2011 17:52:51 -0700 Subject: bridge: fix accidental creation of sysfs directory Commit bb900b27a2f49b37bc38c08e656ea13048fee13b ("bridge: allow creating bridge devices with netlink") introduced a bug in net-next because of a typo in notifier. Every device would have the sysfs bridge directory (and files). Signed-off-by: Stephen Hemminger Signed-off-by: David S. Miller diff --git a/net/bridge/br_notify.c b/net/bridge/br_notify.c index 7a03bb9..606b323 100644 --- a/net/bridge/br_notify.c +++ b/net/bridge/br_notify.c @@ -37,7 +37,7 @@ static int br_device_event(struct notifier_block *unused, unsigned long event, v int err; /* register of bridge completed, add sysfs entries */ - if ((dev->priv_flags && IFF_EBRIDGE) && event == NETDEV_REGISTER) { + if ((dev->priv_flags & IFF_EBRIDGE) && event == NETDEV_REGISTER) { br_sysfs_addbr(dev); return NOTIFY_DONE; } -- cgit v0.10.2 From df4511feb76173db872c8845b63179dd15f2b7da Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Sat, 16 Apr 2011 14:15:25 +0000 Subject: via_rhine: Use netdev_ and pr_ Use the more current logging styles. Add #define DEBUG to make netdev_dbg always active. Signed-off-by: Joe Perches Signed-off-by: David S. Miller diff --git a/drivers/net/via-rhine.c b/drivers/net/via-rhine.c index 0422a79..40f394c 100644 --- a/drivers/net/via-rhine.c +++ b/drivers/net/via-rhine.c @@ -29,6 +29,8 @@ */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #define DRV_NAME "via-rhine" #define DRV_VERSION "1.5.0" #define DRV_RELDATE "2010-10-09" @@ -37,6 +39,7 @@ /* A few user-configurable values. These may be modified when a driver module is loaded. */ +#define DEBUG static int debug = 1; /* 1 normal messages, 0 quiet .. 7 verbose. */ static int max_interrupt_work = 20; @@ -111,8 +114,7 @@ static const int multicast_filter_limit = 32; /* These identify the driver base version and may not be removed. */ static const char version[] __devinitconst = - KERN_INFO DRV_NAME ".c:v1.10-LK" DRV_VERSION " " DRV_RELDATE - " Written by Donald Becker\n"; + "v1.10-LK" DRV_VERSION " " DRV_RELDATE " Written by Donald Becker"; /* This driver was written to use PCI memory space. Some early versions of the Rhine may only work correctly with I/O space accesses. */ @@ -495,14 +497,15 @@ static void rhine_set_vlan_cam_mask(void __iomem *ioaddr, u32 mask); static void rhine_init_cam_filter(struct net_device *dev); static void rhine_update_vcam(struct net_device *dev); -#define RHINE_WAIT_FOR(condition) do { \ - int i=1024; \ - while (!(condition) && --i) \ - ; \ - if (debug > 1 && i < 512) \ - printk(KERN_INFO "%s: %4d cycles used @ %s:%d\n", \ - DRV_NAME, 1024-i, __func__, __LINE__); \ -} while(0) +#define RHINE_WAIT_FOR(condition) \ +do { \ + int i = 1024; \ + while (!(condition) && --i) \ + ; \ + if (debug > 1 && i < 512) \ + pr_info("%4d cycles used @ %s:%d\n", \ + 1024 - i, __func__, __LINE__); \ +} while (0) static inline u32 get_intr_status(struct net_device *dev) { @@ -571,8 +574,8 @@ static void rhine_power_init(struct net_device *dev) default: reason = "Unknown"; } - printk(KERN_INFO "%s: Woke system up. Reason: %s.\n", - DRV_NAME, reason); + netdev_info(dev, "Woke system up. Reason: %s\n", + reason); } } } @@ -586,8 +589,7 @@ static void rhine_chip_reset(struct net_device *dev) IOSYNC; if (ioread8(ioaddr + ChipCmd1) & Cmd1Reset) { - printk(KERN_INFO "%s: Reset not complete yet. " - "Trying harder.\n", DRV_NAME); + netdev_info(dev, "Reset not complete yet. Trying harder.\n"); /* Force reset */ if (rp->quirks & rqForceReset) @@ -598,9 +600,9 @@ static void rhine_chip_reset(struct net_device *dev) } if (debug > 1) - printk(KERN_INFO "%s: Reset %s.\n", dev->name, - (ioread8(ioaddr + ChipCmd1) & Cmd1Reset) ? - "failed" : "succeeded"); + netdev_info(dev, "Reset %s\n", + (ioread8(ioaddr + ChipCmd1) & Cmd1Reset) ? + "failed" : "succeeded"); } #ifdef USE_MMIO @@ -728,9 +730,7 @@ static int __devinit rhine_init_one(struct pci_dev *pdev, /* when built into the kernel, we only print version if device is found */ #ifndef MODULE - static int printed_version; - if (!printed_version++) - printk(version); + pr_info_once("%s\n", version); #endif io_size = 256; @@ -765,8 +765,8 @@ static int __devinit rhine_init_one(struct pci_dev *pdev, /* this should always be supported */ rc = pci_set_dma_mask(pdev, DMA_BIT_MASK(32)); if (rc) { - printk(KERN_ERR "32-bit PCI DMA addresses not supported by " - "the card!?\n"); + dev_err(&pdev->dev, + "32-bit PCI DMA addresses not supported by the card!?\n"); goto err_out; } @@ -774,7 +774,7 @@ static int __devinit rhine_init_one(struct pci_dev *pdev, if ((pci_resource_len(pdev, 0) < io_size) || (pci_resource_len(pdev, 1) < io_size)) { rc = -EIO; - printk(KERN_ERR "Insufficient PCI resources, aborting\n"); + dev_err(&pdev->dev, "Insufficient PCI resources, aborting\n"); goto err_out; } @@ -786,7 +786,7 @@ static int __devinit rhine_init_one(struct pci_dev *pdev, dev = alloc_etherdev(sizeof(struct rhine_private)); if (!dev) { rc = -ENOMEM; - printk(KERN_ERR "alloc_etherdev failed\n"); + dev_err(&pdev->dev, "alloc_etherdev failed\n"); goto err_out; } SET_NETDEV_DEV(dev, &pdev->dev); @@ -804,8 +804,9 @@ static int __devinit rhine_init_one(struct pci_dev *pdev, ioaddr = pci_iomap(pdev, bar, io_size); if (!ioaddr) { rc = -EIO; - printk(KERN_ERR "ioremap failed for device %s, region 0x%X " - "@ 0x%lX\n", pci_name(pdev), io_size, memaddr); + dev_err(&pdev->dev, + "ioremap failed for device %s, region 0x%X @ 0x%lX\n", + pci_name(pdev), io_size, memaddr); goto err_out_free_res; } @@ -820,8 +821,9 @@ static int __devinit rhine_init_one(struct pci_dev *pdev, unsigned char b = readb(ioaddr+reg); if (a != b) { rc = -EIO; - printk(KERN_ERR "MMIO do not match PIO [%02x] " - "(%02x != %02x)\n", reg, a, b); + dev_err(&pdev->dev, + "MMIO do not match PIO [%02x] (%02x != %02x)\n", + reg, a, b); goto err_out_unmap; } } @@ -840,7 +842,7 @@ static int __devinit rhine_init_one(struct pci_dev *pdev, if (!is_valid_ether_addr(dev->perm_addr)) { rc = -EIO; - printk(KERN_ERR "Invalid MAC address\n"); + dev_err(&pdev->dev, "Invalid MAC address\n"); goto err_out_unmap; } @@ -878,14 +880,14 @@ static int __devinit rhine_init_one(struct pci_dev *pdev, if (rc) goto err_out_unmap; - printk(KERN_INFO "%s: VIA %s at 0x%lx, %pM, IRQ %d.\n", - dev->name, name, + netdev_info(dev, "VIA %s at 0x%lx, %pM, IRQ %d\n", + name, #ifdef USE_MMIO - memaddr, + memaddr, #else - (long)ioaddr, + (long)ioaddr, #endif - dev->dev_addr, pdev->irq); + dev->dev_addr, pdev->irq); pci_set_drvdata(pdev, dev); @@ -896,11 +898,11 @@ static int __devinit rhine_init_one(struct pci_dev *pdev, mdio_write(dev, phy_id, MII_BMCR, mii_cmd); if (mii_status != 0xffff && mii_status != 0x0000) { rp->mii_if.advertising = mdio_read(dev, phy_id, 4); - printk(KERN_INFO "%s: MII PHY found at address " - "%d, status 0x%4.4x advertising %4.4x " - "Link %4.4x.\n", dev->name, phy_id, - mii_status, rp->mii_if.advertising, - mdio_read(dev, phy_id, 5)); + netdev_info(dev, + "MII PHY found at address %d, status 0x%04x advertising %04x Link %04x\n", + phy_id, + mii_status, rp->mii_if.advertising, + mdio_read(dev, phy_id, 5)); /* set IFF_RUNNING */ if (mii_status & BMSR_LSTATUS) @@ -912,8 +914,7 @@ static int __devinit rhine_init_one(struct pci_dev *pdev, } rp->mii_if.phy_id = phy_id; if (debug > 1 && avoid_D3) - printk(KERN_INFO "%s: No D3 power state at shutdown.\n", - dev->name); + netdev_info(dev, "No D3 power state at shutdown\n"); return 0; @@ -938,7 +939,7 @@ static int alloc_ring(struct net_device* dev) TX_RING_SIZE * sizeof(struct tx_desc), &ring_dma); if (!ring) { - printk(KERN_ERR "Could not allocate DMA memory.\n"); + netdev_err(dev, "Could not allocate DMA memory\n"); return -ENOMEM; } if (rp->quirks & rqRhineI) { @@ -1098,8 +1099,8 @@ static void rhine_check_media(struct net_device *dev, unsigned int init_media) iowrite8(ioread8(ioaddr + ChipCmd1) & ~Cmd1FDuplex, ioaddr + ChipCmd1); if (debug > 1) - printk(KERN_INFO "%s: force_media %d, carrier %d\n", dev->name, - rp->mii_if.force_media, netif_carrier_ok(dev)); + netdev_info(dev, "force_media %d, carrier %d\n", + rp->mii_if.force_media, netif_carrier_ok(dev)); } /* Called after status of force_media possibly changed */ @@ -1113,9 +1114,8 @@ static void rhine_set_carrier(struct mii_if_info *mii) else /* Let MMI library update carrier status */ rhine_check_media(mii->dev, 0); if (debug > 1) - printk(KERN_INFO "%s: force_media %d, carrier %d\n", - mii->dev->name, mii->force_media, - netif_carrier_ok(mii->dev)); + netdev_info(mii->dev, "force_media %d, carrier %d\n", + mii->force_media, netif_carrier_ok(mii->dev)); } /** @@ -1402,8 +1402,7 @@ static int rhine_open(struct net_device *dev) return rc; if (debug > 1) - printk(KERN_DEBUG "%s: rhine_open() irq %d.\n", - dev->name, rp->pdev->irq); + netdev_dbg(dev, "%s() irq %d\n", __func__, rp->pdev->irq); rc = alloc_ring(dev); if (rc) { @@ -1415,10 +1414,9 @@ static int rhine_open(struct net_device *dev) rhine_chip_reset(dev); init_registers(dev); if (debug > 2) - printk(KERN_DEBUG "%s: Done rhine_open(), status %4.4x " - "MII status: %4.4x.\n", - dev->name, ioread16(ioaddr + ChipCmd), - mdio_read(dev, rp->mii_if.phy_id, MII_BMSR)); + netdev_dbg(dev, "%s() Done - status %04x MII status: %04x\n", + __func__, ioread16(ioaddr + ChipCmd), + mdio_read(dev, rp->mii_if.phy_id, MII_BMSR)); netif_start_queue(dev); @@ -1461,10 +1459,9 @@ static void rhine_tx_timeout(struct net_device *dev) struct rhine_private *rp = netdev_priv(dev); void __iomem *ioaddr = rp->base; - printk(KERN_WARNING "%s: Transmit timed out, status %4.4x, PHY status " - "%4.4x, resetting...\n", - dev->name, ioread16(ioaddr + IntrStatus), - mdio_read(dev, rp->mii_if.phy_id, MII_BMSR)); + netdev_warn(dev, "Transmit timed out, status %04x, PHY status %04x, resetting...\n", + ioread16(ioaddr + IntrStatus), + mdio_read(dev, rp->mii_if.phy_id, MII_BMSR)); schedule_work(&rp->reset_task); } @@ -1551,8 +1548,8 @@ static netdev_tx_t rhine_start_tx(struct sk_buff *skb, spin_unlock_irqrestore(&rp->lock, flags); if (debug > 4) { - printk(KERN_DEBUG "%s: Transmit frame #%d queued in slot %d.\n", - dev->name, rp->cur_tx-1, entry); + netdev_dbg(dev, "Transmit frame #%d queued in slot %d\n", + rp->cur_tx-1, entry); } return NETDEV_TX_OK; } @@ -1578,8 +1575,8 @@ static irqreturn_t rhine_interrupt(int irq, void *dev_instance) IOSYNC; if (debug > 4) - printk(KERN_DEBUG "%s: Interrupt, status %8.8x.\n", - dev->name, intr_status); + netdev_dbg(dev, "Interrupt, status %08x\n", + intr_status); if (intr_status & (IntrRxDone | IntrRxErr | IntrRxDropped | IntrRxWakeUp | IntrRxEmpty | IntrRxNoBuf)) { @@ -1597,9 +1594,9 @@ static irqreturn_t rhine_interrupt(int irq, void *dev_instance) RHINE_WAIT_FOR(!(ioread8(ioaddr+ChipCmd) & CmdTxOn)); if (debug > 2 && ioread8(ioaddr+ChipCmd) & CmdTxOn) - printk(KERN_WARNING "%s: " - "rhine_interrupt() Tx engine " - "still on.\n", dev->name); + netdev_warn(dev, + "%s: Tx engine still on\n", + __func__); } rhine_tx(dev); } @@ -1611,16 +1608,15 @@ static irqreturn_t rhine_interrupt(int irq, void *dev_instance) rhine_error(dev, intr_status); if (--boguscnt < 0) { - printk(KERN_WARNING "%s: Too much work at interrupt, " - "status=%#8.8x.\n", - dev->name, intr_status); + netdev_warn(dev, "Too much work at interrupt, status=%#08x\n", + intr_status); break; } } if (debug > 3) - printk(KERN_DEBUG "%s: exiting interrupt, status=%8.8x.\n", - dev->name, ioread16(ioaddr + IntrStatus)); + netdev_dbg(dev, "exiting interrupt, status=%08x\n", + ioread16(ioaddr + IntrStatus)); return IRQ_RETVAL(handled); } @@ -1637,15 +1633,14 @@ static void rhine_tx(struct net_device *dev) while (rp->dirty_tx != rp->cur_tx) { txstatus = le32_to_cpu(rp->tx_ring[entry].tx_status); if (debug > 6) - printk(KERN_DEBUG "Tx scavenge %d status %8.8x.\n", - entry, txstatus); + netdev_dbg(dev, "Tx scavenge %d status %08x\n", + entry, txstatus); if (txstatus & DescOwn) break; if (txstatus & 0x8000) { if (debug > 1) - printk(KERN_DEBUG "%s: Transmit error, " - "Tx status %8.8x.\n", - dev->name, txstatus); + netdev_dbg(dev, "Transmit error, Tx status %08x\n", + txstatus); dev->stats.tx_errors++; if (txstatus & 0x0400) dev->stats.tx_carrier_errors++; @@ -1668,9 +1663,9 @@ static void rhine_tx(struct net_device *dev) else dev->stats.collisions += txstatus & 0x0F; if (debug > 6) - printk(KERN_DEBUG "collisions: %1.1x:%1.1x\n", - (txstatus >> 3) & 0xF, - txstatus & 0xF); + netdev_dbg(dev, "collisions: %1.1x:%1.1x\n", + (txstatus >> 3) & 0xF, + txstatus & 0xF); dev->stats.tx_bytes += rp->tx_skbuff[entry]->len; dev->stats.tx_packets++; } @@ -1714,9 +1709,9 @@ static int rhine_rx(struct net_device *dev, int limit) int entry = rp->cur_rx % RX_RING_SIZE; if (debug > 4) { - printk(KERN_DEBUG "%s: rhine_rx(), entry %d status %8.8x.\n", - dev->name, entry, - le32_to_cpu(rp->rx_head_desc->rx_status)); + netdev_dbg(dev, "%s(), entry %d status %08x\n", + __func__, entry, + le32_to_cpu(rp->rx_head_desc->rx_status)); } /* If EOP is set on the next entry, it's a new packet. Send it up. */ @@ -1730,26 +1725,26 @@ static int rhine_rx(struct net_device *dev, int limit) break; if (debug > 4) - printk(KERN_DEBUG "rhine_rx() status is %8.8x.\n", - desc_status); + netdev_dbg(dev, "%s() status is %08x\n", + __func__, desc_status); if ((desc_status & (RxWholePkt | RxErr)) != RxWholePkt) { if ((desc_status & RxWholePkt) != RxWholePkt) { - printk(KERN_WARNING "%s: Oversized Ethernet " - "frame spanned multiple buffers, entry " - "%#x length %d status %8.8x!\n", - dev->name, entry, data_size, - desc_status); - printk(KERN_WARNING "%s: Oversized Ethernet " - "frame %p vs %p.\n", dev->name, - rp->rx_head_desc, &rp->rx_ring[entry]); + netdev_warn(dev, + "Oversized Ethernet frame spanned multiple buffers, " + "entry %#x length %d status %08x!\n", + entry, data_size, + desc_status); + netdev_warn(dev, + "Oversized Ethernet frame %p vs %p\n", + rp->rx_head_desc, + &rp->rx_ring[entry]); dev->stats.rx_length_errors++; } else if (desc_status & RxErr) { /* There was a error. */ if (debug > 2) - printk(KERN_DEBUG "rhine_rx() Rx " - "error was %8.8x.\n", - desc_status); + netdev_dbg(dev, "%s() Rx error was %08x\n", + __func__, desc_status); dev->stats.rx_errors++; if (desc_status & 0x0030) dev->stats.rx_length_errors++; @@ -1791,9 +1786,7 @@ static int rhine_rx(struct net_device *dev, int limit) } else { skb = rp->rx_skbuff[entry]; if (skb == NULL) { - printk(KERN_ERR "%s: Inconsistent Rx " - "descriptor chain.\n", - dev->name); + netdev_err(dev, "Inconsistent Rx descriptor chain\n"); break; } rp->rx_skbuff[entry] = NULL; @@ -1886,9 +1879,8 @@ static void rhine_restart_tx(struct net_device *dev) { else { /* This should never happen */ if (debug > 1) - printk(KERN_WARNING "%s: rhine_restart_tx() " - "Another error occurred %8.8x.\n", - dev->name, intr_status); + netdev_warn(dev, "%s() Another error occurred %08x\n", + __func__, intr_status); } } @@ -1909,21 +1901,19 @@ static void rhine_error(struct net_device *dev, int intr_status) } if (intr_status & IntrTxAborted) { if (debug > 1) - printk(KERN_INFO "%s: Abort %8.8x, frame dropped.\n", - dev->name, intr_status); + netdev_info(dev, "Abort %08x, frame dropped\n", + intr_status); } if (intr_status & IntrTxUnderrun) { if (rp->tx_thresh < 0xE0) BYTE_REG_BITS_SET((rp->tx_thresh += 0x20), 0x80, ioaddr + TxConfig); if (debug > 1) - printk(KERN_INFO "%s: Transmitter underrun, Tx " - "threshold now %2.2x.\n", - dev->name, rp->tx_thresh); + netdev_info(dev, "Transmitter underrun, Tx threshold now %02x\n", + rp->tx_thresh); } if (intr_status & IntrTxDescRace) { if (debug > 2) - printk(KERN_INFO "%s: Tx descriptor write-back race.\n", - dev->name); + netdev_info(dev, "Tx descriptor write-back race\n"); } if ((intr_status & IntrTxError) && (intr_status & (IntrTxAborted | @@ -1932,9 +1922,8 @@ static void rhine_error(struct net_device *dev, int intr_status) BYTE_REG_BITS_SET((rp->tx_thresh += 0x20), 0x80, ioaddr + TxConfig); } if (debug > 1) - printk(KERN_INFO "%s: Unspecified error. Tx " - "threshold now %2.2x.\n", - dev->name, rp->tx_thresh); + netdev_info(dev, "Unspecified error. Tx threshold now %02x\n", + rp->tx_thresh); } if (intr_status & (IntrTxAborted | IntrTxUnderrun | IntrTxDescRace | IntrTxError)) @@ -1944,8 +1933,8 @@ static void rhine_error(struct net_device *dev, int intr_status) IntrTxError | IntrTxAborted | IntrNormalSummary | IntrTxDescRace)) { if (debug > 1) - printk(KERN_ERR "%s: Something Wicked happened! " - "%8.8x.\n", dev->name, intr_status); + netdev_err(dev, "Something Wicked happened! %08x\n", + intr_status); } spin_unlock(&rp->lock); @@ -2145,9 +2134,8 @@ static int rhine_close(struct net_device *dev) spin_lock_irq(&rp->lock); if (debug > 1) - printk(KERN_DEBUG "%s: Shutting down ethercard, " - "status was %4.4x.\n", - dev->name, ioread16(ioaddr + ChipCmd)); + netdev_dbg(dev, "Shutting down ethercard, status was %04x\n", + ioread16(ioaddr + ChipCmd)); /* Switch to loopback mode to avoid hardware races. */ iowrite8(rp->tx_thresh | 0x02, ioaddr + TxConfig); @@ -2265,12 +2253,12 @@ static int rhine_resume(struct pci_dev *pdev) return 0; if (request_irq(dev->irq, rhine_interrupt, IRQF_SHARED, dev->name, dev)) - printk(KERN_ERR "via-rhine %s: request_irq failed\n", dev->name); + netdev_err(dev, "request_irq failed\n"); ret = pci_set_power_state(pdev, PCI_D0); if (debug > 1) - printk(KERN_INFO "%s: Entering power state D0 %s (%d).\n", - dev->name, ret ? "failed" : "succeeded", ret); + netdev_info(dev, "Entering power state D0 %s (%d)\n", + ret ? "failed" : "succeeded", ret); pci_restore_state(pdev); @@ -2326,17 +2314,15 @@ static int __init rhine_init(void) { /* when a module, this is printed whether or not devices are found in probe */ #ifdef MODULE - printk(version); + pr_info("%s\n", version); #endif if (dmi_check_system(rhine_dmi_table)) { /* these BIOSes fail at PXE boot if chip is in D3 */ avoid_D3 = 1; - printk(KERN_WARNING "%s: Broken BIOS detected, avoid_D3 " - "enabled.\n", - DRV_NAME); + pr_warn("Broken BIOS detected, avoid_D3 enabled\n"); } else if (avoid_D3) - printk(KERN_INFO "%s: avoid_D3 set.\n", DRV_NAME); + pr_info("avoid_D3 set\n"); return pci_register_driver(&rhine_driver); } -- cgit v0.10.2 From 482e3febc2e7df78411005dcdd7621c16b98b088 Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Sat, 16 Apr 2011 14:15:26 +0000 Subject: via-rhine: Assign random MAC address if necessary Roger Luethi has had several reports of Rhine NICs providing an invalid MAC address. If so, assign a random MAC address so the hardware can still be used. Tested as a standalone interface, as carrier for ppp, and as a bonding slave. Original-patch-by: Alexandru Gagniuc Signed-off-by: Joe Perches Signed-off-by: David S. Miller diff --git a/drivers/net/via-rhine.c b/drivers/net/via-rhine.c index 40f394c..7f23ab9 100644 --- a/drivers/net/via-rhine.c +++ b/drivers/net/via-rhine.c @@ -838,13 +838,15 @@ static int __devinit rhine_init_one(struct pci_dev *pdev, for (i = 0; i < 6; i++) dev->dev_addr[i] = ioread8(ioaddr + StationAddr + i); - memcpy(dev->perm_addr, dev->dev_addr, dev->addr_len); - if (!is_valid_ether_addr(dev->perm_addr)) { - rc = -EIO; - dev_err(&pdev->dev, "Invalid MAC address\n"); - goto err_out_unmap; + if (!is_valid_ether_addr(dev->dev_addr)) { + /* Report it and use a random ethernet address instead */ + netdev_err(dev, "Invalid MAC address: %pM\n", dev->dev_addr); + random_ether_addr(dev->dev_addr); + netdev_info(dev, "Using random MAC address: %pM\n", + dev->dev_addr); } + memcpy(dev->perm_addr, dev->dev_addr, dev->addr_len); /* For Rhine-I/II, phy_id is loaded from EEPROM */ if (!phy_id) -- cgit v0.10.2 From 7c7a81b53e581d727d069cc45df5510516faac31 Mon Sep 17 00:00:00 2001 From: Paul Gortmaker Date: Wed, 13 Apr 2011 06:30:08 +0000 Subject: powerpc/kexec: Fix regression causing compile failure on UP Recent commit b987812b3fcaf70fdf0037589e5d2f5f2453e6ce caused a compile failure on UP because a considerably large block of the file was included within CONFIG_SMP, hence making a stub function not exposed on UP builds when it needed to be. Relocate the stub to the #else /* ! CONFIG_SMP */ section and also annotate the relevant else/endif so that nobody else falls into the same trap I did. Reported-by: Michael Guntsche Signed-off-by: Paul Gortmaker Signed-off-by: Benjamin Herrenschmidt diff --git a/arch/powerpc/kernel/crash.c b/arch/powerpc/kernel/crash.c index 3d3d416..5b5e1f0 100644 --- a/arch/powerpc/kernel/crash.c +++ b/arch/powerpc/kernel/crash.c @@ -163,7 +163,7 @@ static void crash_kexec_prepare_cpus(int cpu) } /* wait for all the CPUs to hit real mode but timeout if they don't come in */ -#if defined(CONFIG_PPC_STD_MMU_64) && defined(CONFIG_SMP) +#ifdef CONFIG_PPC_STD_MMU_64 static void crash_kexec_wait_realmode(int cpu) { unsigned int msecs; @@ -188,9 +188,7 @@ static void crash_kexec_wait_realmode(int cpu) } mb(); } -#else -static inline void crash_kexec_wait_realmode(int cpu) {} -#endif +#endif /* CONFIG_PPC_STD_MMU_64 */ /* * This function will be called by secondary cpus or by kexec cpu @@ -235,7 +233,9 @@ void crash_kexec_secondary(struct pt_regs *regs) crash_ipi_callback(regs); } -#else +#else /* ! CONFIG_SMP */ +static inline void crash_kexec_wait_realmode(int cpu) {} + static void crash_kexec_prepare_cpus(int cpu) { /* @@ -255,7 +255,7 @@ void crash_kexec_secondary(struct pt_regs *regs) { cpus_in_sr = CPU_MASK_NONE; } -#endif +#endif /* CONFIG_SMP */ /* * Register a function to be called on shutdown. Only use this if you -- cgit v0.10.2 From 127493d5dc73589cbe00ea5ec8357cc2a4c0d82a Mon Sep 17 00:00:00 2001 From: Nishanth Aravamudan Date: Wed, 13 Apr 2011 19:45:59 +0000 Subject: powerpc/pseries: Use a kmem cache for DTL buffers PAPR specifies that DTL buffers can not cross AMS environments (aka CMO in the PAPR) and can not cross a memory entitlement granule boundary (4k). This is found in section 14.11.3.2 H_REGISTER_VPA of the PAPR. kmalloc does not guarantee an alignment of the allocation, though, beyond 8 bytes (at least in my understanding). Create a special kmem cache for DTL buffers with the alignment requirement. Signed-off-by: Benjamin Herrenschmidt diff --git a/arch/powerpc/platforms/pseries/setup.c b/arch/powerpc/platforms/pseries/setup.c index 0007241..6c42cfd 100644 --- a/arch/powerpc/platforms/pseries/setup.c +++ b/arch/powerpc/platforms/pseries/setup.c @@ -287,14 +287,22 @@ static int alloc_dispatch_logs(void) int cpu, ret; struct paca_struct *pp; struct dtl_entry *dtl; + struct kmem_cache *dtl_cache; if (!firmware_has_feature(FW_FEATURE_SPLPAR)) return 0; + dtl_cache = kmem_cache_create("dtl", DISPATCH_LOG_BYTES, + DISPATCH_LOG_BYTES, 0, NULL); + if (!dtl_cache) { + pr_warn("Failed to create dispatch trace log buffer cache\n"); + pr_warn("Stolen time statistics will be unreliable\n"); + return 0; + } + for_each_possible_cpu(cpu) { pp = &paca[cpu]; - dtl = kmalloc_node(DISPATCH_LOG_BYTES, GFP_KERNEL, - cpu_to_node(cpu)); + dtl = kmem_cache_alloc(dtl_cache, GFP_KERNEL); if (!dtl) { pr_warn("Failed to allocate dispatch trace log for cpu %d\n", cpu); -- cgit v0.10.2 From 84ffae55af79d7b8834fd0c08d0d1ebf2c77f91e Mon Sep 17 00:00:00 2001 From: Anton Blanchard Date: Thu, 7 Apr 2011 21:44:21 +0000 Subject: powerpc: Fix oops if scan_dispatch_log is called too early We currently enable interrupts before the dispatch log for the boot cpu is setup. If a timer interrupt comes in early enough we oops in scan_dispatch_log: Unable to handle kernel paging request for data at address 0x00000010 ... .scan_dispatch_log+0xb0/0x170 .account_system_vtime+0xa0/0x220 .irq_enter+0x88/0xc0 .do_IRQ+0x48/0x230 The patch below adds a check to scan_dispatch_log to ensure the dispatch log has been allocated. Signed-off-by: Anton Blanchard Cc: Signed-off-by: Benjamin Herrenschmidt diff --git a/arch/powerpc/kernel/time.c b/arch/powerpc/kernel/time.c index 375480c..f33acfd 100644 --- a/arch/powerpc/kernel/time.c +++ b/arch/powerpc/kernel/time.c @@ -229,6 +229,9 @@ static u64 scan_dispatch_log(u64 stop_tb) u64 stolen = 0; u64 dtb; + if (!dtl) + return 0; + if (i == vpa->dtl_idx) return 0; while (i < vpa->dtl_idx) { -- cgit v0.10.2 From 09597cfe93d3cc2c6e064a3ead5956b882511560 Mon Sep 17 00:00:00 2001 From: Stefan Roese Date: Thu, 14 Apr 2011 23:49:53 +0000 Subject: powerpc: Don't write protect kernel text with CONFIG_DYNAMIC_FTRACE enabled This problem was noticed on an MPC855T platform. Ftrace did oops when trying to write to the kernel text segment. Many thanks to Joakim for finding the root cause of this problem. Signed-off-by: Stefan Roese Cc: Joakim Tjernlund Cc: Benjamin Herrenschmidt Cc: Steven Rostedt Signed-off-by: Benjamin Herrenschmidt diff --git a/arch/powerpc/include/asm/pte-common.h b/arch/powerpc/include/asm/pte-common.h index 811f04a..8d1569c 100644 --- a/arch/powerpc/include/asm/pte-common.h +++ b/arch/powerpc/include/asm/pte-common.h @@ -162,7 +162,7 @@ extern unsigned long bad_call_to_PMD_PAGE_SIZE(void); * on platforms where such control is possible. */ #if defined(CONFIG_KGDB) || defined(CONFIG_XMON) || defined(CONFIG_BDI_SWITCH) ||\ - defined(CONFIG_KPROBES) + defined(CONFIG_KPROBES) || defined(CONFIG_DYNAMIC_FTRACE) #define PAGE_KERNEL_TEXT PAGE_KERNEL_X #else #define PAGE_KERNEL_TEXT PAGE_KERNEL_ROX -- cgit v0.10.2 From 86c74ab317c1ef4d37325e0d7ca8a01a796b0bd7 Mon Sep 17 00:00:00 2001 From: Eric B Munson Date: Fri, 15 Apr 2011 08:12:30 +0000 Subject: powerpc/perf_event: Skip updating kernel counters if register value shrinks Because of speculative event roll back, it is possible for some event coutners to decrease between reads on POWER7. This causes a problem with the way that counters are updated. Delta calues are calculated in a 64 bit value and the top 32 bits are masked. If the register value has decreased, this leaves us with a very large positive value added to the kernel counters. This patch protects against this by skipping the update if the delta would be negative. This can lead to a lack of precision in the coutner values, but from my testing the value is typcially fewer than 10 samples at a time. Signed-off-by: Eric B Munson Cc: stable@kernel.org Signed-off-by: Benjamin Herrenschmidt diff --git a/arch/powerpc/kernel/perf_event.c b/arch/powerpc/kernel/perf_event.c index c4063b7..822f630 100644 --- a/arch/powerpc/kernel/perf_event.c +++ b/arch/powerpc/kernel/perf_event.c @@ -398,6 +398,25 @@ static int check_excludes(struct perf_event **ctrs, unsigned int cflags[], return 0; } +static u64 check_and_compute_delta(u64 prev, u64 val) +{ + u64 delta = (val - prev) & 0xfffffffful; + + /* + * POWER7 can roll back counter values, if the new value is smaller + * than the previous value it will cause the delta and the counter to + * have bogus values unless we rolled a counter over. If a coutner is + * rolled back, it will be smaller, but within 256, which is the maximum + * number of events to rollback at once. If we dectect a rollback + * return 0. This can lead to a small lack of precision in the + * counters. + */ + if (prev > val && (prev - val) < 256) + delta = 0; + + return delta; +} + static void power_pmu_read(struct perf_event *event) { s64 val, delta, prev; @@ -416,10 +435,11 @@ static void power_pmu_read(struct perf_event *event) prev = local64_read(&event->hw.prev_count); barrier(); val = read_pmc(event->hw.idx); + delta = check_and_compute_delta(prev, val); + if (!delta) + return; } while (local64_cmpxchg(&event->hw.prev_count, prev, val) != prev); - /* The counters are only 32 bits wide */ - delta = (val - prev) & 0xfffffffful; local64_add(delta, &event->count); local64_sub(delta, &event->hw.period_left); } @@ -449,8 +469,9 @@ static void freeze_limited_counters(struct cpu_hw_events *cpuhw, val = (event->hw.idx == 5) ? pmc5 : pmc6; prev = local64_read(&event->hw.prev_count); event->hw.idx = 0; - delta = (val - prev) & 0xfffffffful; - local64_add(delta, &event->count); + delta = check_and_compute_delta(prev, val); + if (delta) + local64_add(delta, &event->count); } } @@ -458,14 +479,16 @@ static void thaw_limited_counters(struct cpu_hw_events *cpuhw, unsigned long pmc5, unsigned long pmc6) { struct perf_event *event; - u64 val; + u64 val, prev; int i; for (i = 0; i < cpuhw->n_limited; ++i) { event = cpuhw->limited_counter[i]; event->hw.idx = cpuhw->limited_hwidx[i]; val = (event->hw.idx == 5) ? pmc5 : pmc6; - local64_set(&event->hw.prev_count, val); + prev = local64_read(&event->hw.prev_count); + if (check_and_compute_delta(prev, val)) + local64_set(&event->hw.prev_count, val); perf_event_update_userpage(event); } } @@ -1197,7 +1220,7 @@ static void record_and_restart(struct perf_event *event, unsigned long val, /* we don't have to worry about interrupts here */ prev = local64_read(&event->hw.prev_count); - delta = (val - prev) & 0xfffffffful; + delta = check_and_compute_delta(prev, val); local64_add(delta, &event->count); /* -- cgit v0.10.2 From a01c1335a308ee660518e33db03fb5f5e1dfc166 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Sun, 17 Apr 2011 20:47:07 -0700 Subject: decnet: Don't leak entries when rebuilding zone. As noticed by Ben Hutchings, when we move entries from one table to another we leak all except the first entry. Put back the "next" variable removed by commit 9bf9055eb716f85372c41b3fbc51f90bc7653740 ("decnet: Fix set-but-unused variable.") and use it properly. Reported-by: Ben Hutchings Signed-off-by: David S. Miller diff --git a/net/decnet/dn_table.c b/net/decnet/dn_table.c index d8ea583..bd0a52d 100644 --- a/net/decnet/dn_table.c +++ b/net/decnet/dn_table.c @@ -123,11 +123,12 @@ static inline void dn_rebuild_zone(struct dn_zone *dz, struct dn_fib_node **old_ht, int old_divisor) { + struct dn_fib_node *f, **fp, *next; int i; - struct dn_fib_node *f, **fp; for(i = 0; i < old_divisor; i++) { - for(f = old_ht[i]; f; f = f->fn_next) { + for(f = old_ht[i]; f; f = next) { + next = f->fn_next; for(fp = dn_chain_p(f->fn_key, dz); *fp && dn_key_leq((*fp)->fn_key, f->fn_key); fp = &(*fp)->fn_next) -- cgit v0.10.2 From 7b84b29b8c2711fe64e0dba4db22f02ce0f16015 Mon Sep 17 00:00:00 2001 From: Benjamin Herrenschmidt Date: Mon, 18 Apr 2011 15:46:35 +1000 Subject: powerpc/powermac: Build fix with SMP and CPU hotplug Signed-off-by: Benjamin Herrenschmidt diff --git a/arch/powerpc/platforms/powermac/smp.c b/arch/powerpc/platforms/powermac/smp.c index a830c5e..bc5f0dc 100644 --- a/arch/powerpc/platforms/powermac/smp.c +++ b/arch/powerpc/platforms/powermac/smp.c @@ -842,6 +842,7 @@ static void __devinit smp_core99_setup_cpu(int cpu_nr) mpic_setup_this_cpu(); } +#ifdef CONFIG_PPC64 #ifdef CONFIG_HOTPLUG_CPU static int smp_core99_cpu_notify(struct notifier_block *self, unsigned long action, void *hcpu) @@ -879,7 +880,6 @@ static struct notifier_block __cpuinitdata smp_core99_cpu_nb = { static void __init smp_core99_bringup_done(void) { -#ifdef CONFIG_PPC64 extern void g5_phy_disable_cpu1(void); /* Close i2c bus if it was used for tb sync */ @@ -894,14 +894,14 @@ static void __init smp_core99_bringup_done(void) set_cpu_present(1, false); g5_phy_disable_cpu1(); } -#endif /* CONFIG_PPC64 */ - #ifdef CONFIG_HOTPLUG_CPU register_cpu_notifier(&smp_core99_cpu_nb); #endif + if (ppc_md.progress) ppc_md.progress("smp_core99_bringup_done", 0x349); } +#endif /* CONFIG_PPC64 */ #ifdef CONFIG_HOTPLUG_CPU @@ -975,7 +975,9 @@ static void pmac_cpu_die(void) struct smp_ops_t core99_smp_ops = { .message_pass = smp_mpic_message_pass, .probe = smp_core99_probe, +#ifdef CONFIG_PPC64 .bringup_done = smp_core99_bringup_done, +#endif .kick_cpu = smp_core99_kick_cpu, .setup_cpu = smp_core99_setup_cpu, .give_timebase = smp_core99_give_timebase, -- cgit v0.10.2 From 0553c891fabd287726b41076cfd03fe7e5ab596f Mon Sep 17 00:00:00 2001 From: Krishna Kumar Date: Thu, 14 Apr 2011 06:07:04 +0000 Subject: ip6_pol_route panic: Do not allow VLAN on loopback Several tests in the ipv6 routing code check IFF_LOOPBACK, and allowing stacking such as VLAN'ing on top of loopback results in a netdevice which reports IFF_LOOPBACK but really isn't the loopback device. Instead of spamming the ipv6 routing code with even more special tests, simply disallow VLAN over loopback. The result of this patch is: # modprobe 8021q # vconfig add lo 43 ERROR: trying to add VLAN #43 to IF -:lo:- error: Operation not supported Signed-off-by: Krishna Kumar Signed-off-by: David S. Miller diff --git a/drivers/net/loopback.c b/drivers/net/loopback.c index ea0dc45..d70fb76 100644 --- a/drivers/net/loopback.c +++ b/drivers/net/loopback.c @@ -173,7 +173,8 @@ static void loopback_setup(struct net_device *dev) | NETIF_F_RXCSUM | NETIF_F_HIGHDMA | NETIF_F_LLTX - | NETIF_F_NETNS_LOCAL; + | NETIF_F_NETNS_LOCAL + | NETIF_F_VLAN_CHALLENGED; dev->ethtool_ops = &loopback_ethtool_ops; dev->header_ops = ð_header_ops; dev->netdev_ops = &loopback_ops; -- cgit v0.10.2 From b3337e4cea15beb167e8d3a70ca1023e39abb4e5 Mon Sep 17 00:00:00 2001 From: David Decotigny Date: Thu, 14 Apr 2011 16:11:34 +0000 Subject: bnx2x: cosmetics: Using ethtool_cmd_speed() API This updates bnx2x to use the ethtool_cmd_speed() family of functions (see b11f8d8c in 2.6.27-rc3 aka. "ethtool: Expand ethtool_cmd.speed to 32 bits") to get and set the link speed via ethtool. This allows to avoid manually accessing ethtool_cmd's speed_hi field. Signed-off-by: David Decotigny Signed-off-by: David S. Miller diff --git a/drivers/net/bnx2x/bnx2x_ethtool.c b/drivers/net/bnx2x/bnx2x_ethtool.c index 0a5e88d..e711a22 100644 --- a/drivers/net/bnx2x/bnx2x_ethtool.c +++ b/drivers/net/bnx2x/bnx2x_ethtool.c @@ -167,6 +167,7 @@ static int bnx2x_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) { struct bnx2x *bp = netdev_priv(dev); int cfg_idx = bnx2x_get_link_cfg_idx(bp); + /* Dual Media boards present all available port types */ cmd->supported = bp->port.supported[cfg_idx] | (bp->port.supported[cfg_idx ^ 1] & @@ -176,16 +177,16 @@ static int bnx2x_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) if ((bp->state == BNX2X_STATE_OPEN) && !(bp->flags & MF_FUNC_DIS) && (bp->link_vars.link_up)) { - cmd->speed = bp->link_vars.line_speed; + ethtool_cmd_speed_set(cmd, bp->link_vars.line_speed); cmd->duplex = bp->link_vars.duplex; } else { - - cmd->speed = bp->link_params.req_line_speed[cfg_idx]; + ethtool_cmd_speed_set( + cmd, bp->link_params.req_line_speed[cfg_idx]); cmd->duplex = bp->link_params.req_duplex[cfg_idx]; } if (IS_MF(bp)) - cmd->speed = bnx2x_get_mf_speed(bp); + ethtool_cmd_speed_set(cmd, bnx2x_get_mf_speed(bp)); if (bp->port.supported[cfg_idx] & SUPPORTED_TP) cmd->port = PORT_TP; @@ -206,10 +207,11 @@ static int bnx2x_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) cmd->maxrxpkt = 0; DP(NETIF_MSG_LINK, "ethtool_cmd: cmd %d\n" - DP_LEVEL " supported 0x%x advertising 0x%x speed %d\n" + DP_LEVEL " supported 0x%x advertising 0x%x speed %u\n" DP_LEVEL " duplex %d port %d phy_address %d transceiver %d\n" DP_LEVEL " autoneg %d maxtxpkt %d maxrxpkt %d\n", - cmd->cmd, cmd->supported, cmd->advertising, cmd->speed, + cmd->cmd, cmd->supported, cmd->advertising, + ethtool_cmd_speed(cmd), cmd->duplex, cmd->port, cmd->phy_address, cmd->transceiver, cmd->autoneg, cmd->maxtxpkt, cmd->maxrxpkt); @@ -226,16 +228,15 @@ static int bnx2x_set_settings(struct net_device *dev, struct ethtool_cmd *cmd) return 0; DP(NETIF_MSG_LINK, "ethtool_cmd: cmd %d\n" - " supported 0x%x advertising 0x%x speed %d speed_hi %d\n" + " supported 0x%x advertising 0x%x speed %u\n" " duplex %d port %d phy_address %d transceiver %d\n" " autoneg %d maxtxpkt %d maxrxpkt %d\n", - cmd->cmd, cmd->supported, cmd->advertising, cmd->speed, - cmd->speed_hi, + cmd->cmd, cmd->supported, cmd->advertising, + ethtool_cmd_speed(cmd), cmd->duplex, cmd->port, cmd->phy_address, cmd->transceiver, cmd->autoneg, cmd->maxtxpkt, cmd->maxrxpkt); - speed = cmd->speed; - speed |= (cmd->speed_hi << 16); + speed = ethtool_cmd_speed(cmd); if (IS_MF_SI(bp)) { u32 part; @@ -439,7 +440,7 @@ static int bnx2x_set_settings(struct net_device *dev, struct ethtool_cmd *cmd) break; default: - DP(NETIF_MSG_LINK, "Unsupported speed %d\n", speed); + DP(NETIF_MSG_LINK, "Unsupported speed %u\n", speed); return -EINVAL; } -- cgit v0.10.2 From f47b94646f30529624c82ab0f9cd5bd3f25ef9d2 Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Fri, 15 Apr 2011 13:46:02 +0000 Subject: ipv6: Send unsolicited neighbour advertismements when notified The NETDEV_NOTIFY_PEERS notifier is a request to send such advertisements following migration to a different physical link, e.g. virtual machine migration. Signed-off-by: Ben Hutchings Signed-off-by: David S. Miller diff --git a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c index f057ff3..62cbd15 100644 --- a/net/ipv6/ndisc.c +++ b/net/ipv6/ndisc.c @@ -611,6 +611,29 @@ static void ndisc_send_na(struct net_device *dev, struct neighbour *neigh, inc_opt ? ND_OPT_TARGET_LL_ADDR : 0); } +static void ndisc_send_unsol_na(struct net_device *dev) +{ + struct inet6_dev *idev; + struct inet6_ifaddr *ifa; + struct in6_addr mcaddr; + + idev = in6_dev_get(dev); + if (!idev) + return; + + read_lock_bh(&idev->lock); + list_for_each_entry(ifa, &idev->addr_list, if_list) { + addrconf_addr_solict_mult(&ifa->addr, &mcaddr); + ndisc_send_na(dev, NULL, &mcaddr, &ifa->addr, + /*router=*/ !!idev->cnf.forwarding, + /*solicited=*/ false, /*override=*/ true, + /*inc_opt=*/ true); + } + read_unlock_bh(&idev->lock); + + in6_dev_put(idev); +} + void ndisc_send_ns(struct net_device *dev, struct neighbour *neigh, const struct in6_addr *solicit, const struct in6_addr *daddr, const struct in6_addr *saddr) @@ -1723,6 +1746,9 @@ static int ndisc_netdev_event(struct notifier_block *this, unsigned long event, neigh_ifdown(&nd_tbl, dev); fib6_run_gc(~0UL, net); break; + case NETDEV_NOTIFY_PEERS: + ndisc_send_unsol_na(dev); + break; default: break; } -- cgit v0.10.2 From 99606477a5888b0ead0284fecb13417b1da8e3af Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Fri, 15 Apr 2011 13:46:49 +0000 Subject: vlan: Propagate NETDEV_NOTIFY_PEERS notifier The NETDEV_NOTIFY_PEERS notifier indicates that a device moved to a different physical link; this also applies to any VLAN devices on top of it. Signed-off-by: Ben Hutchings Signed-off-by: David S. Miller diff --git a/net/8021q/vlan.c b/net/8021q/vlan.c index 14ef5ef..b2ff70f 100644 --- a/net/8021q/vlan.c +++ b/net/8021q/vlan.c @@ -499,6 +499,17 @@ static int vlan_device_event(struct notifier_block *unused, unsigned long event, case NETDEV_PRE_TYPE_CHANGE: /* Forbid underlaying device to change its type. */ return NOTIFY_BAD; + + case NETDEV_NOTIFY_PEERS: + /* Propagate to vlan devices */ + for (i = 0; i < VLAN_N_VID; i++) { + vlandev = vlan_group_get_device(grp, i); + if (!vlandev) + continue; + + call_netdevice_notifiers(NETDEV_NOTIFY_PEERS, vlandev); + } + break; } out: -- cgit v0.10.2 From 7c89943236750537d26421d9bbb6f6575e2d1e1b Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Fri, 15 Apr 2011 13:47:51 +0000 Subject: bonding, ipv4, ipv6, vlan: Handle NETDEV_BONDING_FAILOVER like NETDEV_NOTIFY_PEERS It is undesirable for the bonding driver to be poking into higher level protocols, and notifiers provide a way to avoid that. This does mean removing the ability to configure reptitition of gratuitous ARPs and unsolicited NAs. Signed-off-by: Ben Hutchings Signed-off-by: David S. Miller diff --git a/drivers/net/bonding/Makefile b/drivers/net/bonding/Makefile index 3c5c014..4c21bf6 100644 --- a/drivers/net/bonding/Makefile +++ b/drivers/net/bonding/Makefile @@ -9,6 +9,3 @@ bonding-objs := bond_main.o bond_3ad.o bond_alb.o bond_sysfs.o bond_debugfs.o proc-$(CONFIG_PROC_FS) += bond_procfs.o bonding-objs += $(proc-y) -ipv6-$(subst m,y,$(CONFIG_IPV6)) += bond_ipv6.o -bonding-objs += $(ipv6-y) - diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index fdf9215..4ce14bd 100644 --- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c @@ -89,8 +89,6 @@ static int max_bonds = BOND_DEFAULT_MAX_BONDS; static int tx_queues = BOND_DEFAULT_TX_QUEUES; -static int num_grat_arp = 1; -static int num_unsol_na = 1; static int miimon = BOND_LINK_MON_INTERV; static int updelay; static int downdelay; @@ -113,10 +111,6 @@ module_param(max_bonds, int, 0); MODULE_PARM_DESC(max_bonds, "Max number of bonded devices"); module_param(tx_queues, int, 0); MODULE_PARM_DESC(tx_queues, "Max number of transmit queues (default = 16)"); -module_param(num_grat_arp, int, 0644); -MODULE_PARM_DESC(num_grat_arp, "Number of gratuitous ARP packets to send on failover event"); -module_param(num_unsol_na, int, 0644); -MODULE_PARM_DESC(num_unsol_na, "Number of unsolicited IPv6 Neighbor Advertisements packets to send on failover event"); module_param(miimon, int, 0); MODULE_PARM_DESC(miimon, "Link check interval in milliseconds"); module_param(updelay, int, 0); @@ -234,7 +228,6 @@ struct bond_parm_tbl ad_select_tbl[] = { /*-------------------------- Forward declarations ---------------------------*/ -static void bond_send_gratuitous_arp(struct bonding *bond); static int bond_init(struct net_device *bond_dev); static void bond_uninit(struct net_device *bond_dev); @@ -1162,14 +1155,6 @@ void bond_change_active_slave(struct bonding *bond, struct slave *new_active) bond_do_fail_over_mac(bond, new_active, old_active); - if (netif_running(bond->dev)) { - bond->send_grat_arp = bond->params.num_grat_arp; - bond_send_gratuitous_arp(bond); - - bond->send_unsol_na = bond->params.num_unsol_na; - bond_send_unsolicited_na(bond); - } - write_unlock_bh(&bond->curr_slave_lock); read_unlock(&bond->lock); @@ -2580,18 +2565,6 @@ void bond_mii_monitor(struct work_struct *work) if (bond->slave_cnt == 0) goto re_arm; - if (bond->send_grat_arp) { - read_lock(&bond->curr_slave_lock); - bond_send_gratuitous_arp(bond); - read_unlock(&bond->curr_slave_lock); - } - - if (bond->send_unsol_na) { - read_lock(&bond->curr_slave_lock); - bond_send_unsolicited_na(bond); - read_unlock(&bond->curr_slave_lock); - } - if (bond_miimon_inspect(bond)) { read_unlock(&bond->lock); rtnl_lock(); @@ -2753,42 +2726,6 @@ static void bond_arp_send_all(struct bonding *bond, struct slave *slave) } } -/* - * Kick out a gratuitous ARP for an IP on the bonding master plus one - * for each VLAN above us. - * - * Caller must hold curr_slave_lock for read or better - */ -static void bond_send_gratuitous_arp(struct bonding *bond) -{ - struct slave *slave = bond->curr_active_slave; - struct vlan_entry *vlan; - - pr_debug("bond_send_grat_arp: bond %s slave %s\n", - bond->dev->name, slave ? slave->dev->name : "NULL"); - - if (!slave || !bond->send_grat_arp || - test_bit(__LINK_STATE_LINKWATCH_PENDING, &slave->dev->state)) - return; - - bond->send_grat_arp--; - - if (bond->master_ip) { - bond_arp_send(slave->dev, ARPOP_REPLY, bond->master_ip, - bond->master_ip, 0); - } - - if (!bond->vlgrp) - return; - - list_for_each_entry(vlan, &bond->vlan_list, vlan_list) { - if (vlan->vlan_ip) { - bond_arp_send(slave->dev, ARPOP_REPLY, vlan->vlan_ip, - vlan->vlan_ip, vlan->vlan_id); - } - } -} - static void bond_validate_arp(struct bonding *bond, struct slave *slave, __be32 sip, __be32 tip) { int i; @@ -3255,18 +3192,6 @@ void bond_activebackup_arp_mon(struct work_struct *work) if (bond->slave_cnt == 0) goto re_arm; - if (bond->send_grat_arp) { - read_lock(&bond->curr_slave_lock); - bond_send_gratuitous_arp(bond); - read_unlock(&bond->curr_slave_lock); - } - - if (bond->send_unsol_na) { - read_lock(&bond->curr_slave_lock); - bond_send_unsolicited_na(bond); - read_unlock(&bond->curr_slave_lock); - } - if (bond_ab_arp_inspect(bond, delta_in_ticks)) { read_unlock(&bond->lock); rtnl_lock(); @@ -3645,9 +3570,6 @@ static int bond_close(struct net_device *bond_dev) write_lock_bh(&bond->lock); - bond->send_grat_arp = 0; - bond->send_unsol_na = 0; - /* signal timers not to re-arm */ bond->kill_timers = 1; @@ -4724,18 +4646,6 @@ static int bond_check_params(struct bond_params *params) use_carrier = 1; } - if (num_grat_arp < 0 || num_grat_arp > 255) { - pr_warning("Warning: num_grat_arp (%d) not in range 0-255 so it was reset to 1\n", - num_grat_arp); - num_grat_arp = 1; - } - - if (num_unsol_na < 0 || num_unsol_na > 255) { - pr_warning("Warning: num_unsol_na (%d) not in range 0-255 so it was reset to 1\n", - num_unsol_na); - num_unsol_na = 1; - } - /* reset values for 802.3ad */ if (bond_mode == BOND_MODE_8023AD) { if (!miimon) { @@ -4925,8 +4835,6 @@ static int bond_check_params(struct bond_params *params) params->mode = bond_mode; params->xmit_policy = xmit_hashtype; params->miimon = miimon; - params->num_grat_arp = num_grat_arp; - params->num_unsol_na = num_unsol_na; params->arp_interval = arp_interval; params->arp_validate = arp_validate_value; params->updelay = updelay; @@ -5121,7 +5029,6 @@ static int __init bonding_init(void) register_netdevice_notifier(&bond_netdev_notifier); register_inetaddr_notifier(&bond_inetaddr_notifier); - bond_register_ipv6_notifier(); out: return res; err: @@ -5136,7 +5043,6 @@ static void __exit bonding_exit(void) { unregister_netdevice_notifier(&bond_netdev_notifier); unregister_inetaddr_notifier(&bond_inetaddr_notifier); - bond_unregister_ipv6_notifier(); bond_destroy_sysfs(); bond_destroy_debugfs(); diff --git a/drivers/net/bonding/bond_sysfs.c b/drivers/net/bonding/bond_sysfs.c index de87aea..259ff32 100644 --- a/drivers/net/bonding/bond_sysfs.c +++ b/drivers/net/bonding/bond_sysfs.c @@ -874,84 +874,6 @@ static DEVICE_ATTR(ad_select, S_IRUGO | S_IWUSR, bonding_show_ad_select, bonding_store_ad_select); /* - * Show and set the number of grat ARP to send after a failover event. - */ -static ssize_t bonding_show_n_grat_arp(struct device *d, - struct device_attribute *attr, - char *buf) -{ - struct bonding *bond = to_bond(d); - - return sprintf(buf, "%d\n", bond->params.num_grat_arp); -} - -static ssize_t bonding_store_n_grat_arp(struct device *d, - struct device_attribute *attr, - const char *buf, size_t count) -{ - int new_value, ret = count; - struct bonding *bond = to_bond(d); - - if (sscanf(buf, "%d", &new_value) != 1) { - pr_err("%s: no num_grat_arp value specified.\n", - bond->dev->name); - ret = -EINVAL; - goto out; - } - if (new_value < 0 || new_value > 255) { - pr_err("%s: Invalid num_grat_arp value %d not in range 0-255; rejected.\n", - bond->dev->name, new_value); - ret = -EINVAL; - goto out; - } else { - bond->params.num_grat_arp = new_value; - } -out: - return ret; -} -static DEVICE_ATTR(num_grat_arp, S_IRUGO | S_IWUSR, - bonding_show_n_grat_arp, bonding_store_n_grat_arp); - -/* - * Show and set the number of unsolicited NA's to send after a failover event. - */ -static ssize_t bonding_show_n_unsol_na(struct device *d, - struct device_attribute *attr, - char *buf) -{ - struct bonding *bond = to_bond(d); - - return sprintf(buf, "%d\n", bond->params.num_unsol_na); -} - -static ssize_t bonding_store_n_unsol_na(struct device *d, - struct device_attribute *attr, - const char *buf, size_t count) -{ - int new_value, ret = count; - struct bonding *bond = to_bond(d); - - if (sscanf(buf, "%d", &new_value) != 1) { - pr_err("%s: no num_unsol_na value specified.\n", - bond->dev->name); - ret = -EINVAL; - goto out; - } - - if (new_value < 0 || new_value > 255) { - pr_err("%s: Invalid num_unsol_na value %d not in range 0-255; rejected.\n", - bond->dev->name, new_value); - ret = -EINVAL; - goto out; - } else - bond->params.num_unsol_na = new_value; -out: - return ret; -} -static DEVICE_ATTR(num_unsol_na, S_IRUGO | S_IWUSR, - bonding_show_n_unsol_na, bonding_store_n_unsol_na); - -/* * Show and set the MII monitor interval. There are two tricky bits * here. First, if MII monitoring is activated, then we must disable * ARP monitoring. Second, if the timer isn't running, we must @@ -1650,8 +1572,6 @@ static struct attribute *per_bond_attrs[] = { &dev_attr_lacp_rate.attr, &dev_attr_ad_select.attr, &dev_attr_xmit_hash_policy.attr, - &dev_attr_num_grat_arp.attr, - &dev_attr_num_unsol_na.attr, &dev_attr_miimon.attr, &dev_attr_primary.attr, &dev_attr_primary_reselect.attr, diff --git a/drivers/net/bonding/bonding.h b/drivers/net/bonding/bonding.h index 553c764..6126c6a 100644 --- a/drivers/net/bonding/bonding.h +++ b/drivers/net/bonding/bonding.h @@ -149,8 +149,6 @@ struct bond_params { int mode; int xmit_policy; int miimon; - int num_grat_arp; - int num_unsol_na; int arp_interval; int arp_validate; int use_carrier; @@ -178,9 +176,6 @@ struct vlan_entry { struct list_head vlan_list; __be32 vlan_ip; unsigned short vlan_id; -#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) - struct in6_addr vlan_ipv6; -#endif }; struct slave { @@ -234,8 +229,6 @@ struct bonding { rwlock_t lock; rwlock_t curr_slave_lock; s8 kill_timers; - s8 send_grat_arp; - s8 send_unsol_na; s8 setup_by_slave; s8 igmp_retrans; #ifdef CONFIG_PROC_FS @@ -260,9 +253,6 @@ struct bonding { struct delayed_work alb_work; struct delayed_work ad_work; struct delayed_work mcast_work; -#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) - struct in6_addr master_ipv6; -#endif #ifdef CONFIG_DEBUG_FS /* debugging suport via debugfs */ struct dentry *debug_dir; @@ -460,23 +450,4 @@ extern const struct bond_parm_tbl fail_over_mac_tbl[]; extern const struct bond_parm_tbl pri_reselect_tbl[]; extern struct bond_parm_tbl ad_select_tbl[]; -#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) -void bond_send_unsolicited_na(struct bonding *bond); -void bond_register_ipv6_notifier(void); -void bond_unregister_ipv6_notifier(void); -#else -static inline void bond_send_unsolicited_na(struct bonding *bond) -{ - return; -} -static inline void bond_register_ipv6_notifier(void) -{ - return; -} -static inline void bond_unregister_ipv6_notifier(void) -{ - return; -} -#endif - #endif /* _LINUX_BONDING_H */ diff --git a/net/8021q/vlan.c b/net/8021q/vlan.c index b2ff70f..969e700 100644 --- a/net/8021q/vlan.c +++ b/net/8021q/vlan.c @@ -501,13 +501,14 @@ static int vlan_device_event(struct notifier_block *unused, unsigned long event, return NOTIFY_BAD; case NETDEV_NOTIFY_PEERS: + case NETDEV_BONDING_FAILOVER: /* Propagate to vlan devices */ for (i = 0; i < VLAN_N_VID; i++) { vlandev = vlan_group_get_device(grp, i); if (!vlandev) continue; - call_netdevice_notifiers(NETDEV_NOTIFY_PEERS, vlandev); + call_netdevice_notifiers(event, vlandev); } break; } diff --git a/net/ipv4/devinet.c b/net/ipv4/devinet.c index 5345b0b..acf553f 100644 --- a/net/ipv4/devinet.c +++ b/net/ipv4/devinet.c @@ -1203,6 +1203,7 @@ static int inetdev_event(struct notifier_block *this, unsigned long event, break; /* fall through */ case NETDEV_NOTIFY_PEERS: + case NETDEV_BONDING_FAILOVER: /* Send gratuitous ARP to notify of link change */ inetdev_send_gratuitous_arp(dev, in_dev); break; diff --git a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c index 62cbd15..01a0ffc 100644 --- a/net/ipv6/ndisc.c +++ b/net/ipv6/ndisc.c @@ -1747,6 +1747,7 @@ static int ndisc_netdev_event(struct notifier_block *this, unsigned long event, fib6_run_gc(~0UL, net); break; case NETDEV_NOTIFY_PEERS: + case NETDEV_BONDING_FAILOVER: ndisc_send_unsol_na(dev); break; default: -- cgit v0.10.2 From 048c9374a749a27f16493cea033fa4a8ff492356 Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Mon, 18 Apr 2011 09:52:22 +0200 Subject: block: Enhance new plugging support to support general callbacks md/raid requires an unplug callback, but as it does not uses requests the current code cannot provide one. So allow arbitrary callbacks to be attached to the blk_plug. Signed-off-by: NeilBrown Signed-off-by: Jens Axboe diff --git a/block/blk-core.c b/block/blk-core.c index 78b7b0c..77edf05 100644 --- a/block/blk-core.c +++ b/block/blk-core.c @@ -2638,6 +2638,7 @@ void blk_start_plug(struct blk_plug *plug) plug->magic = PLUG_MAGIC; INIT_LIST_HEAD(&plug->list); + INIT_LIST_HEAD(&plug->cb_list); plug->should_sort = 0; /* @@ -2678,6 +2679,24 @@ static void queue_unplugged(struct request_queue *q, unsigned int depth, q->unplugged_fn(q); } +static void flush_plug_callbacks(struct blk_plug *plug) +{ + LIST_HEAD(callbacks); + + if (list_empty(&plug->cb_list)) + return; + + list_splice_init(&plug->cb_list, &callbacks); + + while (!list_empty(&callbacks)) { + struct blk_plug_cb *cb = list_first_entry(&callbacks, + struct blk_plug_cb, + list); + list_del(&cb->list); + cb->callback(cb); + } +} + void blk_flush_plug_list(struct blk_plug *plug, bool from_schedule) { struct request_queue *q; @@ -2688,6 +2707,7 @@ void blk_flush_plug_list(struct blk_plug *plug, bool from_schedule) BUG_ON(plug->magic != PLUG_MAGIC); + flush_plug_callbacks(plug); if (list_empty(&plug->list)) return; diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h index ec0357d..f3f7879 100644 --- a/include/linux/blkdev.h +++ b/include/linux/blkdev.h @@ -860,8 +860,13 @@ extern void blk_put_queue(struct request_queue *); struct blk_plug { unsigned long magic; struct list_head list; + struct list_head cb_list; unsigned int should_sort; }; +struct blk_plug_cb { + struct list_head list; + void (*callback)(struct blk_plug_cb *); +}; extern void blk_start_plug(struct blk_plug *); extern void blk_finish_plug(struct blk_plug *); @@ -887,7 +892,7 @@ static inline bool blk_needs_flush_plug(struct task_struct *tsk) { struct blk_plug *plug = tsk->plug; - return plug && !list_empty(&plug->list); + return plug && (!list_empty(&plug->list) || !list_empty(&plug->cb_list)); } /* -- cgit v0.10.2 From b4cb290e0a7d19235bd075c2ad4d60dbab0bac15 Mon Sep 17 00:00:00 2001 From: Jens Axboe Date: Mon, 18 Apr 2011 09:54:05 +0200 Subject: Revert "block: add callback function for unplug notification" MD can't use this since it really requires us to be able to keep more than a single piece of state for the unplug. Commit 048c9374 added the required support for MD, so get rid of this now unused code. This reverts commit f75664570d8b75469cc468f23c2b27220984983b. Conflicts: block/blk-core.c Signed-off-by: Jens Axboe diff --git a/block/blk-core.c b/block/blk-core.c index 77edf05..09b2628 100644 --- a/block/blk-core.c +++ b/block/blk-core.c @@ -2674,9 +2674,6 @@ static void queue_unplugged(struct request_queue *q, unsigned int depth, { trace_block_unplug(q, depth, !from_schedule); __blk_run_queue(q, from_schedule); - - if (q->unplugged_fn) - q->unplugged_fn(q); } static void flush_plug_callbacks(struct blk_plug *plug) diff --git a/block/blk-settings.c b/block/blk-settings.c index eb94904..1fa7692 100644 --- a/block/blk-settings.c +++ b/block/blk-settings.c @@ -790,22 +790,6 @@ void blk_queue_flush(struct request_queue *q, unsigned int flush) } EXPORT_SYMBOL_GPL(blk_queue_flush); -/** - * blk_queue_unplugged - register a callback for an unplug event - * @q: the request queue for the device - * @fn: the function to call - * - * Some stacked drivers may need to know when IO is dispatched on an - * unplug event. By registrering a callback here, they will be notified - * when someone flushes their on-stack queue plug. The function will be - * called with the queue lock held. - */ -void blk_queue_unplugged(struct request_queue *q, unplugged_fn *fn) -{ - q->unplugged_fn = fn; -} -EXPORT_SYMBOL(blk_queue_unplugged); - static int __init blk_settings_init(void) { blk_max_low_pfn = max_low_pfn - 1; diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h index f3f7879..3448d89 100644 --- a/include/linux/blkdev.h +++ b/include/linux/blkdev.h @@ -196,7 +196,6 @@ typedef void (request_fn_proc) (struct request_queue *q); typedef int (make_request_fn) (struct request_queue *q, struct bio *bio); typedef int (prep_rq_fn) (struct request_queue *, struct request *); typedef void (unprep_rq_fn) (struct request_queue *, struct request *); -typedef void (unplugged_fn) (struct request_queue *); struct bio_vec; struct bvec_merge_data { @@ -284,7 +283,6 @@ struct request_queue rq_timed_out_fn *rq_timed_out_fn; dma_drain_needed_fn *dma_drain_needed; lld_busy_fn *lld_busy_fn; - unplugged_fn *unplugged_fn; /* * Dispatch queue sorting @@ -843,7 +841,6 @@ extern void blk_queue_dma_alignment(struct request_queue *, int); extern void blk_queue_update_dma_alignment(struct request_queue *, int); extern void blk_queue_softirq_done(struct request_queue *, softirq_done_fn *); extern void blk_queue_rq_timed_out(struct request_queue *, rq_timed_out_fn *); -extern void blk_queue_unplugged(struct request_queue *, unplugged_fn *); extern void blk_queue_rq_timeout(struct request_queue *, unsigned int); extern void blk_queue_flush(struct request_queue *q, unsigned int flush); extern struct backing_dev_info *blk_get_backing_dev_info(struct block_device *bdev); -- cgit v0.10.2 From 99e22598e9a8e0a996d69c8c0f6b7027cb57720a Mon Sep 17 00:00:00 2001 From: Jens Axboe Date: Mon, 18 Apr 2011 09:59:55 +0200 Subject: block: drop queue lock before calling __blk_run_queue() for kblockd punt If we know we are going to punt to kblockd, we can drop the queue lock before calling into __blk_run_queue() since it only does a safe bit test and a workqueue call. Since kblockd needs to grab this very lock as one of the first things it does, it's a good optimization to drop the lock before waking kblockd. Signed-off-by: Jens Axboe diff --git a/block/blk-core.c b/block/blk-core.c index 09b2628..5e41393 100644 --- a/block/blk-core.c +++ b/block/blk-core.c @@ -295,7 +295,8 @@ EXPORT_SYMBOL(blk_sync_queue); * * Description: * See @blk_run_queue. This variant must be called with the queue lock - * held and interrupts disabled. + * held and interrupts disabled. If force_kblockd is true, then it is + * safe to call this without holding the queue lock. * */ void __blk_run_queue(struct request_queue *q, bool force_kblockd) @@ -2671,9 +2672,23 @@ static int plug_rq_cmp(void *priv, struct list_head *a, struct list_head *b) */ static void queue_unplugged(struct request_queue *q, unsigned int depth, bool from_schedule) + __releases(q->queue_lock) { trace_block_unplug(q, depth, !from_schedule); - __blk_run_queue(q, from_schedule); + + /* + * If we are punting this to kblockd, then we can safely drop + * the queue_lock before waking kblockd (which needs to take + * this lock). + */ + if (from_schedule) { + spin_unlock(q->queue_lock); + __blk_run_queue(q, true); + } else { + __blk_run_queue(q, false); + spin_unlock(q->queue_lock); + } + } static void flush_plug_callbacks(struct blk_plug *plug) @@ -2729,10 +2744,11 @@ void blk_flush_plug_list(struct blk_plug *plug, bool from_schedule) BUG_ON(!(rq->cmd_flags & REQ_ON_PLUG)); BUG_ON(!rq->q); if (rq->q != q) { - if (q) { + /* + * This drops the queue lock + */ + if (q) queue_unplugged(q, depth, from_schedule); - spin_unlock(q->queue_lock); - } q = rq->q; depth = 0; spin_lock(q->queue_lock); @@ -2750,10 +2766,11 @@ void blk_flush_plug_list(struct blk_plug *plug, bool from_schedule) depth++; } - if (q) { + /* + * This drops the queue lock + */ + if (q) queue_unplugged(q, depth, from_schedule); - spin_unlock(q->queue_lock); - } local_irq_restore(flags); } -- cgit v0.10.2 From e1dfa0a29737142c32f00a3bac0f609dc85b4a82 Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Mon, 18 Apr 2011 18:25:41 +1000 Subject: md: use new plugging interface for RAID IO. md/raid submits a lot of IO from the various raid threads. So adding start/finish plug calls to those so that some plugging happens. Signed-off-by: NeilBrown diff --git a/drivers/md/raid1.c b/drivers/md/raid1.c index c2a21ae5..5449cd5 100644 --- a/drivers/md/raid1.c +++ b/drivers/md/raid1.c @@ -1516,9 +1516,11 @@ static void raid1d(mddev_t *mddev) conf_t *conf = mddev->private; struct list_head *head = &conf->retry_list; mdk_rdev_t *rdev; + struct blk_plug plug; md_check_recovery(mddev); - + + blk_start_plug(&plug); for (;;) { char b[BDEVNAME_SIZE]; @@ -1593,6 +1595,7 @@ static void raid1d(mddev_t *mddev) } cond_resched(); } + blk_finish_plug(&plug); } diff --git a/drivers/md/raid10.c b/drivers/md/raid10.c index 2da83d5..c8e5dac 100644 --- a/drivers/md/raid10.c +++ b/drivers/md/raid10.c @@ -1640,9 +1640,11 @@ static void raid10d(mddev_t *mddev) conf_t *conf = mddev->private; struct list_head *head = &conf->retry_list; mdk_rdev_t *rdev; + struct blk_plug plug; md_check_recovery(mddev); + blk_start_plug(&plug); for (;;) { char b[BDEVNAME_SIZE]; @@ -1716,6 +1718,7 @@ static void raid10d(mddev_t *mddev) } cond_resched(); } + blk_finish_plug(&plug); } diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c index e867ee4..ce6960b 100644 --- a/drivers/md/raid5.c +++ b/drivers/md/raid5.c @@ -4478,11 +4478,13 @@ static void raid5d(mddev_t *mddev) struct stripe_head *sh; raid5_conf_t *conf = mddev->private; int handled; + struct blk_plug plug; pr_debug("+++ raid5d active\n"); md_check_recovery(mddev); + blk_start_plug(&plug); handled = 0; spin_lock_irq(&conf->device_lock); while (1) { @@ -4525,6 +4527,7 @@ static void raid5d(mddev_t *mddev) spin_unlock_irq(&conf->device_lock); async_tx_issue_pending_all(); + blk_finish_plug(&plug); pr_debug("--- raid5d inactive\n"); } -- cgit v0.10.2 From af1db72d8b340f97ad12b60175afdef43e6f0e60 Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Mon, 18 Apr 2011 18:25:41 +1000 Subject: md/dm - remove remains of plug_fn callback. Now that unplugging is done differently, the unplug_fn callback is never called, so it can be completely discarded. Signed-off-by: NeilBrown diff --git a/drivers/md/dm-raid.c b/drivers/md/dm-raid.c index 5ef136c..e5d8904 100644 --- a/drivers/md/dm-raid.c +++ b/drivers/md/dm-raid.c @@ -390,13 +390,6 @@ static int raid_is_congested(struct dm_target_callbacks *cb, int bits) return md_raid5_congested(&rs->md, bits); } -static void raid_unplug(struct dm_target_callbacks *cb) -{ - struct raid_set *rs = container_of(cb, struct raid_set, callbacks); - - md_raid5_kick_device(rs->md.private); -} - /* * Construct a RAID4/5/6 mapping: * Args: @@ -487,7 +480,6 @@ static int raid_ctr(struct dm_target *ti, unsigned argc, char **argv) } rs->callbacks.congested_fn = raid_is_congested; - rs->callbacks.unplug_fn = raid_unplug; dm_table_add_target_callbacks(ti->table, &rs->callbacks); return 0; diff --git a/include/linux/device-mapper.h b/include/linux/device-mapper.h index e276883..32a4423 100644 --- a/include/linux/device-mapper.h +++ b/include/linux/device-mapper.h @@ -197,7 +197,6 @@ struct dm_target { struct dm_target_callbacks { struct list_head list; int (*congested_fn) (struct dm_target_callbacks *, int); - void (*unplug_fn)(struct dm_target_callbacks *); }; int dm_register_target(struct target_type *t); -- cgit v0.10.2 From 482c083492ddaa32ef5864bae3d143dc8bcdf7d1 Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Mon, 18 Apr 2011 18:25:42 +1000 Subject: md - remove old plugging code. md has some plugging infrastructure for RAID5 to use because the normal plugging infrastructure required a 'request_queue', and when called from dm, RAID5 doesn't have one of those available. This relied on the ->unplug_fn callback which doesn't exist any more. So remove all of that code, both in md and raid5. Subsequent patches with restore the plugging functionality. Signed-off-by: NeilBrown diff --git a/drivers/md/md.c b/drivers/md/md.c index b12b377..fb11170 100644 --- a/drivers/md/md.c +++ b/drivers/md/md.c @@ -445,50 +445,6 @@ void md_flush_request(mddev_t *mddev, struct bio *bio) } EXPORT_SYMBOL(md_flush_request); -/* Support for plugging. - * This mirrors the plugging support in request_queue, but does not - * require having a whole queue - */ -static void plugger_work(struct work_struct *work) -{ - struct plug_handle *plug = - container_of(work, struct plug_handle, unplug_work); - plug->unplug_fn(plug); -} -static void plugger_timeout(unsigned long data) -{ - struct plug_handle *plug = (void *)data; - kblockd_schedule_work(NULL, &plug->unplug_work); -} -void plugger_init(struct plug_handle *plug, - void (*unplug_fn)(struct plug_handle *)) -{ - plug->unplug_flag = 0; - plug->unplug_fn = unplug_fn; - init_timer(&plug->unplug_timer); - plug->unplug_timer.function = plugger_timeout; - plug->unplug_timer.data = (unsigned long)plug; - INIT_WORK(&plug->unplug_work, plugger_work); -} -EXPORT_SYMBOL_GPL(plugger_init); - -void plugger_set_plug(struct plug_handle *plug) -{ - if (!test_and_set_bit(PLUGGED_FLAG, &plug->unplug_flag)) - mod_timer(&plug->unplug_timer, jiffies + msecs_to_jiffies(3)+1); -} -EXPORT_SYMBOL_GPL(plugger_set_plug); - -int plugger_remove_plug(struct plug_handle *plug) -{ - if (test_and_clear_bit(PLUGGED_FLAG, &plug->unplug_flag)) { - del_timer(&plug->unplug_timer); - return 1; - } else - return 0; -} -EXPORT_SYMBOL_GPL(plugger_remove_plug); - static inline mddev_t *mddev_get(mddev_t *mddev) { @@ -4723,7 +4679,6 @@ static void md_clean(mddev_t *mddev) mddev->bitmap_info.chunksize = 0; mddev->bitmap_info.daemon_sleep = 0; mddev->bitmap_info.max_write_behind = 0; - mddev->plug = NULL; } static void __md_stop_writes(mddev_t *mddev) @@ -6688,12 +6643,6 @@ int md_allow_write(mddev_t *mddev) } EXPORT_SYMBOL_GPL(md_allow_write); -void md_unplug(mddev_t *mddev) -{ - if (mddev->plug) - mddev->plug->unplug_fn(mddev->plug); -} - #define SYNC_MARKS 10 #define SYNC_MARK_STEP (3*HZ) void md_do_sync(mddev_t *mddev) diff --git a/drivers/md/md.h b/drivers/md/md.h index 52b4073..fad9022 100644 --- a/drivers/md/md.h +++ b/drivers/md/md.h @@ -29,26 +29,6 @@ typedef struct mddev_s mddev_t; typedef struct mdk_rdev_s mdk_rdev_t; -/* generic plugging support - like that provided with request_queue, - * but does not require a request_queue - */ -struct plug_handle { - void (*unplug_fn)(struct plug_handle *); - struct timer_list unplug_timer; - struct work_struct unplug_work; - unsigned long unplug_flag; -}; -#define PLUGGED_FLAG 1 -void plugger_init(struct plug_handle *plug, - void (*unplug_fn)(struct plug_handle *)); -void plugger_set_plug(struct plug_handle *plug); -int plugger_remove_plug(struct plug_handle *plug); -static inline void plugger_flush(struct plug_handle *plug) -{ - del_timer_sync(&plug->unplug_timer); - cancel_work_sync(&plug->unplug_work); -} - /* * MD's 'extended' device */ @@ -336,7 +316,6 @@ struct mddev_s struct list_head all_mddevs; struct attribute_group *to_remove; - struct plug_handle *plug; /* if used by personality */ struct bio_set *bio_set; @@ -516,7 +495,6 @@ extern int md_integrity_register(mddev_t *mddev); extern void md_integrity_add_rdev(mdk_rdev_t *rdev, mddev_t *mddev); extern int strict_strtoul_scaled(const char *cp, unsigned long *res, int scale); extern void restore_bitmap_write_access(struct file *file); -extern void md_unplug(mddev_t *mddev); extern void mddev_init(mddev_t *mddev); extern int md_run(mddev_t *mddev); diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c index ce6960b..a1755a6 100644 --- a/drivers/md/raid5.c +++ b/drivers/md/raid5.c @@ -199,14 +199,12 @@ static void __release_stripe(raid5_conf_t *conf, struct stripe_head *sh) BUG_ON(!list_empty(&sh->lru)); BUG_ON(atomic_read(&conf->active_stripes)==0); if (test_bit(STRIPE_HANDLE, &sh->state)) { - if (test_bit(STRIPE_DELAYED, &sh->state)) { + if (test_bit(STRIPE_DELAYED, &sh->state)) list_add_tail(&sh->lru, &conf->delayed_list); - plugger_set_plug(&conf->plug); - } else if (test_bit(STRIPE_BIT_DELAY, &sh->state) && - sh->bm_seq - conf->seq_write > 0) { + else if (test_bit(STRIPE_BIT_DELAY, &sh->state) && + sh->bm_seq - conf->seq_write > 0) list_add_tail(&sh->lru, &conf->bitmap_list); - plugger_set_plug(&conf->plug); - } else { + else { clear_bit(STRIPE_BIT_DELAY, &sh->state); list_add_tail(&sh->lru, &conf->handle_list); } @@ -461,7 +459,7 @@ get_active_stripe(raid5_conf_t *conf, sector_t sector, < (conf->max_nr_stripes *3/4) || !conf->inactive_blocked), conf->device_lock, - md_raid5_kick_device(conf)); + md_wakeup_thread(conf->mddev->thread)); conf->inactive_blocked = 0; } else init_stripe(sh, sector, previous); @@ -1470,7 +1468,7 @@ static int resize_stripes(raid5_conf_t *conf, int newsize) wait_event_lock_irq(conf->wait_for_stripe, !list_empty(&conf->inactive_list), conf->device_lock, - blk_flush_plug(current)); + ); osh = get_free_stripe(conf); spin_unlock_irq(&conf->device_lock); atomic_set(&nsh->count, 1); @@ -3623,8 +3621,7 @@ static void raid5_activate_delayed(raid5_conf_t *conf) atomic_inc(&conf->preread_active_stripes); list_add_tail(&sh->lru, &conf->hold_list); } - } else - plugger_set_plug(&conf->plug); + } } static void activate_bit_delay(raid5_conf_t *conf) @@ -3641,21 +3638,6 @@ static void activate_bit_delay(raid5_conf_t *conf) } } -void md_raid5_kick_device(raid5_conf_t *conf) -{ - blk_flush_plug(current); - raid5_activate_delayed(conf); - md_wakeup_thread(conf->mddev->thread); -} -EXPORT_SYMBOL_GPL(md_raid5_kick_device); - -static void raid5_unplug(struct plug_handle *plug) -{ - raid5_conf_t *conf = container_of(plug, raid5_conf_t, plug); - - md_raid5_kick_device(conf); -} - int md_raid5_congested(mddev_t *mddev, int bits) { raid5_conf_t *conf = mddev->private; @@ -4057,7 +4039,7 @@ static int make_request(mddev_t *mddev, struct bio * bi) * add failed due to overlap. Flush everything * and wait a while */ - md_raid5_kick_device(conf); + md_wakeup_thread(mddev->thread); release_stripe(sh); schedule(); goto retry; @@ -5144,8 +5126,6 @@ static int run(mddev_t *mddev) mdname(mddev)); md_set_array_sectors(mddev, raid5_size(mddev, 0, 0)); - plugger_init(&conf->plug, raid5_unplug); - mddev->plug = &conf->plug; if (mddev->queue) { int chunk_size; /* read-ahead size must cover two whole stripes, which @@ -5195,7 +5175,6 @@ static int stop(mddev_t *mddev) mddev->thread = NULL; if (mddev->queue) mddev->queue->backing_dev_info.congested_fn = NULL; - plugger_flush(&conf->plug); /* the unplug fn references 'conf'*/ free_conf(conf); mddev->private = NULL; mddev->to_remove = &raid5_attrs_group; diff --git a/drivers/md/raid5.h b/drivers/md/raid5.h index 8d563a4..3ca77a2 100644 --- a/drivers/md/raid5.h +++ b/drivers/md/raid5.h @@ -400,8 +400,6 @@ struct raid5_private_data { * Cleared when a sync completes. */ - struct plug_handle plug; - /* per cpu variables */ struct raid5_percpu { struct page *spare_page; /* Used when checking P/Q in raid6 */ -- cgit v0.10.2 From 97658cdd3af7d01461874c93b89afa4a2465e7c6 Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Mon, 18 Apr 2011 18:25:42 +1000 Subject: md: provide generic support for handling unplug callbacks. When an md device adds a request to a queue, it can call mddev_check_plugged. If this succeeds then we know that the md thread will be woken up shortly, and ->plug_cnt will be non-zero until then, so some processing can be delayed. If it fails, then no unplug callback is expected and the make_request function needs to do whatever is required to make the request happen. Signed-off-by: NeilBrown diff --git a/drivers/md/md.c b/drivers/md/md.c index fb11170..6e853c6 100644 --- a/drivers/md/md.c +++ b/drivers/md/md.c @@ -445,6 +445,61 @@ void md_flush_request(mddev_t *mddev, struct bio *bio) } EXPORT_SYMBOL(md_flush_request); +/* Support for plugging. + * This mirrors the plugging support in request_queue, but does not + * require having a whole queue or request structures. + * We allocate an md_plug_cb for each md device and each thread it gets + * plugged on. This links tot the private plug_handle structure in the + * personality data where we keep a count of the number of outstanding + * plugs so other code can see if a plug is active. + */ +struct md_plug_cb { + struct blk_plug_cb cb; + mddev_t *mddev; +}; + +static void plugger_unplug(struct blk_plug_cb *cb) +{ + struct md_plug_cb *mdcb = container_of(cb, struct md_plug_cb, cb); + if (atomic_dec_and_test(&mdcb->mddev->plug_cnt)) + md_wakeup_thread(mdcb->mddev->thread); + kfree(mdcb); +} + +/* Check that an unplug wakeup will come shortly. + * If not, wakeup the md thread immediately + */ +int mddev_check_plugged(mddev_t *mddev) +{ + struct blk_plug *plug = current->plug; + struct md_plug_cb *mdcb; + + if (!plug) + return 0; + + list_for_each_entry(mdcb, &plug->cb_list, cb.list) { + if (mdcb->cb.callback == plugger_unplug && + mdcb->mddev == mddev) { + /* Already on the list, move to top */ + if (mdcb != list_first_entry(&plug->cb_list, + struct md_plug_cb, + cb.list)) + list_move(&mdcb->cb.list, &plug->cb_list); + return 1; + } + } + /* Not currently on the callback list */ + mdcb = kmalloc(sizeof(*mdcb), GFP_ATOMIC); + if (!mdcb) + return 0; + + mdcb->mddev = mddev; + mdcb->cb.callback = plugger_unplug; + atomic_inc(&mddev->plug_cnt); + list_add(&mdcb->cb.list, &plug->cb_list); + return 1; +} +EXPORT_SYMBOL_GPL(mddev_check_plugged); static inline mddev_t *mddev_get(mddev_t *mddev) { @@ -494,6 +549,7 @@ void mddev_init(mddev_t *mddev) atomic_set(&mddev->active, 1); atomic_set(&mddev->openers, 0); atomic_set(&mddev->active_io, 0); + atomic_set(&mddev->plug_cnt, 0); spin_lock_init(&mddev->write_lock); atomic_set(&mddev->flush_pending, 0); init_waitqueue_head(&mddev->sb_wait); diff --git a/drivers/md/md.h b/drivers/md/md.h index fad9022..0b1fd3f 100644 --- a/drivers/md/md.h +++ b/drivers/md/md.h @@ -179,6 +179,9 @@ struct mddev_s int delta_disks, new_level, new_layout; int new_chunk_sectors; + atomic_t plug_cnt; /* If device is expecting + * more bios soon. + */ struct mdk_thread_s *thread; /* management thread */ struct mdk_thread_s *sync_thread; /* doing resync or reconstruct */ sector_t curr_resync; /* last block scheduled */ @@ -508,4 +511,5 @@ extern struct bio *bio_clone_mddev(struct bio *bio, gfp_t gfp_mask, mddev_t *mddev); extern struct bio *bio_alloc_mddev(gfp_t gfp_mask, int nr_iovecs, mddev_t *mddev); +extern int mddev_check_plugged(mddev_t *mddev); #endif /* _MD_MD_H */ -- cgit v0.10.2 From 7c13edc87510f665da3094174e1fd633e06649f4 Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Mon, 18 Apr 2011 18:25:43 +1000 Subject: md: incorporate new plugging into raid5. In raid5 plugging is used for 2 things: 1/ collecting writes that require a bitmap update 2/ collecting writes in the hope that we can create full stripes - or at least more-full. We now release these different sets of stripes when plug_cnt is zero. Also in make_request, we call mddev_check_plug to hopefully increase plug_cnt, and wake up the thread at the end if plugging wasn't achieved for some reason. Signed-off-by: NeilBrown diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c index a1755a6..f301e6a 100644 --- a/drivers/md/raid5.c +++ b/drivers/md/raid5.c @@ -27,12 +27,12 @@ * * We group bitmap updates into batches. Each batch has a number. * We may write out several batches at once, but that isn't very important. - * conf->bm_write is the number of the last batch successfully written. - * conf->bm_flush is the number of the last batch that was closed to + * conf->seq_write is the number of the last batch successfully written. + * conf->seq_flush is the number of the last batch that was closed to * new additions. * When we discover that we will need to write to any block in a stripe * (in add_stripe_bio) we update the in-memory bitmap and record in sh->bm_seq - * the number of the batch it will be in. This is bm_flush+1. + * the number of the batch it will be in. This is seq_flush+1. * When we are ready to do a write, if that batch hasn't been written yet, * we plug the array and queue the stripe for later. * When an unplug happens, we increment bm_flush, thus closing the current @@ -459,7 +459,7 @@ get_active_stripe(raid5_conf_t *conf, sector_t sector, < (conf->max_nr_stripes *3/4) || !conf->inactive_blocked), conf->device_lock, - md_wakeup_thread(conf->mddev->thread)); + ); conf->inactive_blocked = 0; } else init_stripe(sh, sector, previous); @@ -3927,6 +3927,7 @@ static int make_request(mddev_t *mddev, struct bio * bi) struct stripe_head *sh; const int rw = bio_data_dir(bi); int remaining; + int plugged; if (unlikely(bi->bi_rw & REQ_FLUSH)) { md_flush_request(mddev, bi); @@ -3945,6 +3946,7 @@ static int make_request(mddev_t *mddev, struct bio * bi) bi->bi_next = NULL; bi->bi_phys_segments = 1; /* over-loaded to count active stripes */ + plugged = mddev_check_plugged(mddev); for (;logical_sector < last_sector; logical_sector += STRIPE_SECTORS) { DEFINE_WAIT(w); int disks, data_disks; @@ -4059,6 +4061,9 @@ static int make_request(mddev_t *mddev, struct bio * bi) } } + if (!plugged) + md_wakeup_thread(mddev->thread); + spin_lock_irq(&conf->device_lock); remaining = raid5_dec_bi_phys_segments(bi); spin_unlock_irq(&conf->device_lock); @@ -4472,14 +4477,18 @@ static void raid5d(mddev_t *mddev) while (1) { struct bio *bio; - if (conf->seq_flush != conf->seq_write) { - int seq = conf->seq_flush; + if (atomic_read(&mddev->plug_cnt) == 0 && + !list_empty(&conf->bitmap_list)) { + /* Now is a good time to flush some bitmap updates */ + conf->seq_flush++; spin_unlock_irq(&conf->device_lock); bitmap_unplug(mddev->bitmap); spin_lock_irq(&conf->device_lock); - conf->seq_write = seq; + conf->seq_write = conf->seq_flush; activate_bit_delay(conf); } + if (atomic_read(&mddev->plug_cnt) == 0) + raid5_activate_delayed(conf); while ((bio = remove_bio_from_retry(conf))) { int ok; -- cgit v0.10.2 From c3b328ac846bcf6b9a62c5563380a81ab723006d Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Mon, 18 Apr 2011 18:25:43 +1000 Subject: md: fix up raid1/raid10 unplugging. We just need to make sure that an unplug event wakes up the md thread, which is exactly what mddev_check_plugged does. Also remove some plug-related code that is no longer needed. Signed-off-by: NeilBrown diff --git a/drivers/md/raid1.c b/drivers/md/raid1.c index 5449cd5..2b7a7ff 100644 --- a/drivers/md/raid1.c +++ b/drivers/md/raid1.c @@ -565,12 +565,6 @@ static void flush_pending_writes(conf_t *conf) spin_unlock_irq(&conf->device_lock); } -static void md_kick_device(mddev_t *mddev) -{ - blk_flush_plug(current); - md_wakeup_thread(mddev->thread); -} - /* Barriers.... * Sometimes we need to suspend IO while we do something else, * either some resync/recovery, or reconfigure the array. @@ -600,7 +594,7 @@ static void raise_barrier(conf_t *conf) /* Wait until no block IO is waiting */ wait_event_lock_irq(conf->wait_barrier, !conf->nr_waiting, - conf->resync_lock, md_kick_device(conf->mddev)); + conf->resync_lock, ); /* block any new IO from starting */ conf->barrier++; @@ -608,7 +602,7 @@ static void raise_barrier(conf_t *conf) /* Now wait for all pending IO to complete */ wait_event_lock_irq(conf->wait_barrier, !conf->nr_pending && conf->barrier < RESYNC_DEPTH, - conf->resync_lock, md_kick_device(conf->mddev)); + conf->resync_lock, ); spin_unlock_irq(&conf->resync_lock); } @@ -630,7 +624,7 @@ static void wait_barrier(conf_t *conf) conf->nr_waiting++; wait_event_lock_irq(conf->wait_barrier, !conf->barrier, conf->resync_lock, - md_kick_device(conf->mddev)); + ); conf->nr_waiting--; } conf->nr_pending++; @@ -666,8 +660,7 @@ static void freeze_array(conf_t *conf) wait_event_lock_irq(conf->wait_barrier, conf->nr_pending == conf->nr_queued+1, conf->resync_lock, - ({ flush_pending_writes(conf); - md_kick_device(conf->mddev); })); + flush_pending_writes(conf)); spin_unlock_irq(&conf->resync_lock); } static void unfreeze_array(conf_t *conf) @@ -729,6 +722,7 @@ static int make_request(mddev_t *mddev, struct bio * bio) const unsigned long do_sync = (bio->bi_rw & REQ_SYNC); const unsigned long do_flush_fua = (bio->bi_rw & (REQ_FLUSH | REQ_FUA)); mdk_rdev_t *blocked_rdev; + int plugged; /* * Register the new request and wait if the reconstruction @@ -820,6 +814,8 @@ static int make_request(mddev_t *mddev, struct bio * bio) * inc refcount on their rdev. Record them by setting * bios[x] to bio */ + plugged = mddev_check_plugged(mddev); + disks = conf->raid_disks; retry_write: blocked_rdev = NULL; @@ -925,7 +921,7 @@ static int make_request(mddev_t *mddev, struct bio * bio) /* In case raid1d snuck in to freeze_array */ wake_up(&conf->wait_barrier); - if (do_sync || !bitmap) + if (do_sync || !bitmap || !plugged) md_wakeup_thread(mddev->thread); return 0; @@ -1524,7 +1520,8 @@ static void raid1d(mddev_t *mddev) for (;;) { char b[BDEVNAME_SIZE]; - flush_pending_writes(conf); + if (atomic_read(&mddev->plug_cnt) == 0) + flush_pending_writes(conf); spin_lock_irqsave(&conf->device_lock, flags); if (list_empty(head)) { @@ -2042,7 +2039,6 @@ static int stop(mddev_t *mddev) md_unregister_thread(mddev->thread); mddev->thread = NULL; - blk_sync_queue(mddev->queue); /* the unplug fn references 'conf'*/ if (conf->r1bio_pool) mempool_destroy(conf->r1bio_pool); kfree(conf->mirrors); diff --git a/drivers/md/raid10.c b/drivers/md/raid10.c index c8e5dac..8e94626 100644 --- a/drivers/md/raid10.c +++ b/drivers/md/raid10.c @@ -634,12 +634,6 @@ static void flush_pending_writes(conf_t *conf) spin_unlock_irq(&conf->device_lock); } -static void md_kick_device(mddev_t *mddev) -{ - blk_flush_plug(current); - md_wakeup_thread(mddev->thread); -} - /* Barriers.... * Sometimes we need to suspend IO while we do something else, * either some resync/recovery, or reconfigure the array. @@ -669,15 +663,15 @@ static void raise_barrier(conf_t *conf, int force) /* Wait until no block IO is waiting (unless 'force') */ wait_event_lock_irq(conf->wait_barrier, force || !conf->nr_waiting, - conf->resync_lock, md_kick_device(conf->mddev)); + conf->resync_lock, ); /* block any new IO from starting */ conf->barrier++; - /* No wait for all pending IO to complete */ + /* Now wait for all pending IO to complete */ wait_event_lock_irq(conf->wait_barrier, !conf->nr_pending && conf->barrier < RESYNC_DEPTH, - conf->resync_lock, md_kick_device(conf->mddev)); + conf->resync_lock, ); spin_unlock_irq(&conf->resync_lock); } @@ -698,7 +692,7 @@ static void wait_barrier(conf_t *conf) conf->nr_waiting++; wait_event_lock_irq(conf->wait_barrier, !conf->barrier, conf->resync_lock, - md_kick_device(conf->mddev)); + ); conf->nr_waiting--; } conf->nr_pending++; @@ -734,8 +728,8 @@ static void freeze_array(conf_t *conf) wait_event_lock_irq(conf->wait_barrier, conf->nr_pending == conf->nr_queued+1, conf->resync_lock, - ({ flush_pending_writes(conf); - md_kick_device(conf->mddev); })); + flush_pending_writes(conf)); + spin_unlock_irq(&conf->resync_lock); } @@ -762,6 +756,7 @@ static int make_request(mddev_t *mddev, struct bio * bio) const unsigned long do_fua = (bio->bi_rw & REQ_FUA); unsigned long flags; mdk_rdev_t *blocked_rdev; + int plugged; if (unlikely(bio->bi_rw & REQ_FLUSH)) { md_flush_request(mddev, bio); @@ -870,6 +865,8 @@ static int make_request(mddev_t *mddev, struct bio * bio) * inc refcount on their rdev. Record them by setting * bios[x] to bio */ + plugged = mddev_check_plugged(mddev); + raid10_find_phys(conf, r10_bio); retry_write: blocked_rdev = NULL; @@ -946,9 +943,8 @@ static int make_request(mddev_t *mddev, struct bio * bio) /* In case raid10d snuck in to freeze_array */ wake_up(&conf->wait_barrier); - if (do_sync || !mddev->bitmap) + if (do_sync || !mddev->bitmap || !plugged) md_wakeup_thread(mddev->thread); - return 0; } -- cgit v0.10.2 From 1791f881435fab951939ad700e947b66c062e083 Mon Sep 17 00:00:00 2001 From: Richard Cochran Date: Wed, 30 Mar 2011 15:24:21 +0200 Subject: posix clocks: Replace mutex with reader/writer semaphore A dynamic posix clock is protected from asynchronous removal by a mutex. However, using a mutex has the unwanted effect that a long running clock operation in one process will unnecessarily block other processes. For example, one process might call read() to get an external time stamp coming in at one pulse per second. A second process calling clock_gettime would have to wait for almost a whole second. This patch fixes the issue by using a reader/writer semaphore instead of a mutex. Signed-off-by: Richard Cochran Cc: John Stultz Link: http://lkml.kernel.org/r/%3C20110330132421.GA31771%40riccoc20.at.omicron.at%3E Signed-off-by: Thomas Gleixner diff --git a/include/linux/posix-clock.h b/include/linux/posix-clock.h index 369e19d..7f1183dc 100644 --- a/include/linux/posix-clock.h +++ b/include/linux/posix-clock.h @@ -24,6 +24,7 @@ #include #include #include +#include struct posix_clock; @@ -104,7 +105,7 @@ struct posix_clock_operations { * @ops: Functional interface to the clock * @cdev: Character device instance for this clock * @kref: Reference count. - * @mutex: Protects the 'zombie' field from concurrent access. + * @rwsem: Protects the 'zombie' field from concurrent access. * @zombie: If 'zombie' is true, then the hardware has disappeared. * @release: A function to free the structure when the reference count reaches * zero. May be NULL if structure is statically allocated. @@ -117,7 +118,7 @@ struct posix_clock { struct posix_clock_operations ops; struct cdev cdev; struct kref kref; - struct mutex mutex; + struct rw_semaphore rwsem; bool zombie; void (*release)(struct posix_clock *clk); }; diff --git a/kernel/time/posix-clock.c b/kernel/time/posix-clock.c index 25028dd..c340ca6 100644 --- a/kernel/time/posix-clock.c +++ b/kernel/time/posix-clock.c @@ -19,7 +19,6 @@ */ #include #include -#include #include #include #include @@ -34,19 +33,19 @@ static struct posix_clock *get_posix_clock(struct file *fp) { struct posix_clock *clk = fp->private_data; - mutex_lock(&clk->mutex); + down_read(&clk->rwsem); if (!clk->zombie) return clk; - mutex_unlock(&clk->mutex); + up_read(&clk->rwsem); return NULL; } static void put_posix_clock(struct posix_clock *clk) { - mutex_unlock(&clk->mutex); + up_read(&clk->rwsem); } static ssize_t posix_clock_read(struct file *fp, char __user *buf, @@ -156,7 +155,7 @@ static int posix_clock_open(struct inode *inode, struct file *fp) struct posix_clock *clk = container_of(inode->i_cdev, struct posix_clock, cdev); - mutex_lock(&clk->mutex); + down_read(&clk->rwsem); if (clk->zombie) { err = -ENODEV; @@ -172,7 +171,7 @@ static int posix_clock_open(struct inode *inode, struct file *fp) fp->private_data = clk; } out: - mutex_unlock(&clk->mutex); + up_read(&clk->rwsem); return err; } @@ -211,25 +210,20 @@ int posix_clock_register(struct posix_clock *clk, dev_t devid) int err; kref_init(&clk->kref); - mutex_init(&clk->mutex); + init_rwsem(&clk->rwsem); cdev_init(&clk->cdev, &posix_clock_file_operations); clk->cdev.owner = clk->ops.owner; err = cdev_add(&clk->cdev, devid, 1); - if (err) - goto no_cdev; return err; -no_cdev: - mutex_destroy(&clk->mutex); - return err; } EXPORT_SYMBOL_GPL(posix_clock_register); static void delete_clock(struct kref *kref) { struct posix_clock *clk = container_of(kref, struct posix_clock, kref); - mutex_destroy(&clk->mutex); + if (clk->release) clk->release(clk); } @@ -238,9 +232,9 @@ void posix_clock_unregister(struct posix_clock *clk) { cdev_del(&clk->cdev); - mutex_lock(&clk->mutex); + down_write(&clk->rwsem); clk->zombie = true; - mutex_unlock(&clk->mutex); + up_write(&clk->rwsem); kref_put(&clk->kref, delete_clock); } -- cgit v0.10.2 From 2dd93c4f47d506c586b827d75646a4257aafa43e Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Sun, 17 Apr 2011 10:02:58 +0800 Subject: RTC: rtc-omap: Fix a leak of the IRQ during init failure In omap_rtc_probe error path, free_irq() was using NULL rather than the driver data as the data pointer so free_irq() wouldn't have matched. Signed-off-by: Axel Lin Cc: "George G. Davis" Cc: Alessandro Zummo Cc: rtc-linux@googlegroups.com Link: http://lkml.kernel.org/r/%3C1303005778.2889.2.camel%40phoenix%3E Signed-off-by: Thomas Gleixner diff --git a/drivers/rtc/rtc-omap.c b/drivers/rtc/rtc-omap.c index de0dd7b..bcae8dd 100644 --- a/drivers/rtc/rtc-omap.c +++ b/drivers/rtc/rtc-omap.c @@ -394,7 +394,7 @@ static int __init omap_rtc_probe(struct platform_device *pdev) return 0; fail2: - free_irq(omap_rtc_timer, NULL); + free_irq(omap_rtc_timer, rtc); fail1: rtc_device_unregister(rtc); fail0: -- cgit v0.10.2 From 4521cc4ed5173f92714f6999a69910c3385fed68 Mon Sep 17 00:00:00 2001 From: Jens Axboe Date: Mon, 18 Apr 2011 11:36:39 +0200 Subject: block: blk_delay_queue() should use kblockd workqueue Reported-by: Christoph Hellwig Signed-off-by: Jens Axboe diff --git a/block/blk-core.c b/block/blk-core.c index 5e41393..e2bacfa 100644 --- a/block/blk-core.c +++ b/block/blk-core.c @@ -220,7 +220,8 @@ static void blk_delay_work(struct work_struct *work) */ void blk_delay_queue(struct request_queue *q, unsigned long msecs) { - schedule_delayed_work(&q->delay_work, msecs_to_jiffies(msecs)); + queue_delayed_work(kblockd_workqueue, &q->delay_work, + msecs_to_jiffies(msecs)); } EXPORT_SYMBOL(blk_delay_queue); -- cgit v0.10.2 From 24ecfbe27f65563909b14492afda2f1c21f7c044 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Mon, 18 Apr 2011 11:41:33 +0200 Subject: block: add blk_run_queue_async Instead of overloading __blk_run_queue to force an offload to kblockd add a new blk_run_queue_async helper to do it explicitly. I've kept the blk_queue_stopped check for now, but I suspect it's not needed as the check we do when the workqueue items runs should be enough. Signed-off-by: Christoph Hellwig Signed-off-by: Jens Axboe diff --git a/block/blk-core.c b/block/blk-core.c index e2bacfa..5fa3dd2 100644 --- a/block/blk-core.c +++ b/block/blk-core.c @@ -204,7 +204,7 @@ static void blk_delay_work(struct work_struct *work) q = container_of(work, struct request_queue, delay_work.work); spin_lock_irq(q->queue_lock); - __blk_run_queue(q, false); + __blk_run_queue(q); spin_unlock_irq(q->queue_lock); } @@ -239,7 +239,7 @@ void blk_start_queue(struct request_queue *q) WARN_ON(!irqs_disabled()); queue_flag_clear(QUEUE_FLAG_STOPPED, q); - __blk_run_queue(q, false); + __blk_run_queue(q); } EXPORT_SYMBOL(blk_start_queue); @@ -296,11 +296,9 @@ EXPORT_SYMBOL(blk_sync_queue); * * Description: * See @blk_run_queue. This variant must be called with the queue lock - * held and interrupts disabled. If force_kblockd is true, then it is - * safe to call this without holding the queue lock. - * + * held and interrupts disabled. */ -void __blk_run_queue(struct request_queue *q, bool force_kblockd) +void __blk_run_queue(struct request_queue *q) { if (unlikely(blk_queue_stopped(q))) return; @@ -309,7 +307,7 @@ void __blk_run_queue(struct request_queue *q, bool force_kblockd) * Only recurse once to avoid overrunning the stack, let the unplug * handling reinvoke the handler shortly if we already got there. */ - if (!force_kblockd && !queue_flag_test_and_set(QUEUE_FLAG_REENTER, q)) { + if (!queue_flag_test_and_set(QUEUE_FLAG_REENTER, q)) { q->request_fn(q); queue_flag_clear(QUEUE_FLAG_REENTER, q); } else @@ -318,6 +316,20 @@ void __blk_run_queue(struct request_queue *q, bool force_kblockd) EXPORT_SYMBOL(__blk_run_queue); /** + * blk_run_queue_async - run a single device queue in workqueue context + * @q: The queue to run + * + * Description: + * Tells kblockd to perform the equivalent of @blk_run_queue on behalf + * of us. + */ +void blk_run_queue_async(struct request_queue *q) +{ + if (likely(!blk_queue_stopped(q))) + queue_delayed_work(kblockd_workqueue, &q->delay_work, 0); +} + +/** * blk_run_queue - run a single device queue * @q: The queue to run * @@ -330,7 +342,7 @@ void blk_run_queue(struct request_queue *q) unsigned long flags; spin_lock_irqsave(q->queue_lock, flags); - __blk_run_queue(q, false); + __blk_run_queue(q); spin_unlock_irqrestore(q->queue_lock, flags); } EXPORT_SYMBOL(blk_run_queue); @@ -979,7 +991,7 @@ void blk_insert_request(struct request_queue *q, struct request *rq, blk_queue_end_tag(q, rq); add_acct_request(q, rq, where); - __blk_run_queue(q, false); + __blk_run_queue(q); spin_unlock_irqrestore(q->queue_lock, flags); } EXPORT_SYMBOL(blk_insert_request); @@ -1323,7 +1335,7 @@ get_rq: } else { spin_lock_irq(q->queue_lock); add_acct_request(q, req, where); - __blk_run_queue(q, false); + __blk_run_queue(q); out_unlock: spin_unlock_irq(q->queue_lock); } @@ -2684,9 +2696,9 @@ static void queue_unplugged(struct request_queue *q, unsigned int depth, */ if (from_schedule) { spin_unlock(q->queue_lock); - __blk_run_queue(q, true); + blk_run_queue_async(q); } else { - __blk_run_queue(q, false); + __blk_run_queue(q); spin_unlock(q->queue_lock); } diff --git a/block/blk-exec.c b/block/blk-exec.c index 7482b7f..81e3181 100644 --- a/block/blk-exec.c +++ b/block/blk-exec.c @@ -55,7 +55,7 @@ void blk_execute_rq_nowait(struct request_queue *q, struct gendisk *bd_disk, WARN_ON(irqs_disabled()); spin_lock_irq(q->queue_lock); __elv_add_request(q, rq, where); - __blk_run_queue(q, false); + __blk_run_queue(q); /* the queue is stopped so it won't be plugged+unplugged */ if (rq->cmd_type == REQ_TYPE_PM_RESUME) q->request_fn(q); diff --git a/block/blk-flush.c b/block/blk-flush.c index eba4a27..6c9b5e1 100644 --- a/block/blk-flush.c +++ b/block/blk-flush.c @@ -218,7 +218,7 @@ static void flush_end_io(struct request *flush_rq, int error) * request_fn may confuse the driver. Always use kblockd. */ if (queued) - __blk_run_queue(q, true); + blk_run_queue_async(q); } /** @@ -274,7 +274,7 @@ static void flush_data_end_io(struct request *rq, int error) * the comment in flush_end_io(). */ if (blk_flush_complete_seq(rq, REQ_FSEQ_DATA, error)) - __blk_run_queue(q, true); + blk_run_queue_async(q); } /** diff --git a/block/blk.h b/block/blk.h index 6126346..c9df8fc 100644 --- a/block/blk.h +++ b/block/blk.h @@ -22,6 +22,7 @@ void blk_rq_timed_out_timer(unsigned long data); void blk_delete_timer(struct request *); void blk_add_timer(struct request *); void __generic_unplug_device(struct request_queue *); +void blk_run_queue_async(struct request_queue *q); /* * Internal atomic flags for request handling diff --git a/block/cfq-iosched.c b/block/cfq-iosched.c index 3be881e..46b0a1d 100644 --- a/block/cfq-iosched.c +++ b/block/cfq-iosched.c @@ -3368,7 +3368,7 @@ cfq_rq_enqueued(struct cfq_data *cfqd, struct cfq_queue *cfqq, cfqd->busy_queues > 1) { cfq_del_timer(cfqd, cfqq); cfq_clear_cfqq_wait_request(cfqq); - __blk_run_queue(cfqd->queue, false); + __blk_run_queue(cfqd->queue); } else { cfq_blkiocg_update_idle_time_stats( &cfqq->cfqg->blkg); @@ -3383,7 +3383,7 @@ cfq_rq_enqueued(struct cfq_data *cfqd, struct cfq_queue *cfqq, * this new queue is RT and the current one is BE */ cfq_preempt_queue(cfqd, cfqq); - __blk_run_queue(cfqd->queue, false); + __blk_run_queue(cfqd->queue); } } @@ -3743,7 +3743,7 @@ static void cfq_kick_queue(struct work_struct *work) struct request_queue *q = cfqd->queue; spin_lock_irq(q->queue_lock); - __blk_run_queue(cfqd->queue, false); + __blk_run_queue(cfqd->queue); spin_unlock_irq(q->queue_lock); } diff --git a/block/elevator.c b/block/elevator.c index 0cdb4e7..6f6abc0 100644 --- a/block/elevator.c +++ b/block/elevator.c @@ -642,7 +642,7 @@ void elv_quiesce_start(struct request_queue *q) */ elv_drain_elevator(q); while (q->rq.elvpriv) { - __blk_run_queue(q, false); + __blk_run_queue(q); spin_unlock_irq(q->queue_lock); msleep(10); spin_lock_irq(q->queue_lock); @@ -695,7 +695,7 @@ void __elv_add_request(struct request_queue *q, struct request *rq, int where) * with anything. There's no point in delaying queue * processing. */ - __blk_run_queue(q, false); + __blk_run_queue(q); break; case ELEVATOR_INSERT_SORT_MERGE: diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c index 6d5c7ff..ab55c2f 100644 --- a/drivers/scsi/scsi_lib.c +++ b/drivers/scsi/scsi_lib.c @@ -443,7 +443,7 @@ static void scsi_run_queue(struct request_queue *q) &sdev->request_queue->queue_flags); if (flagset) queue_flag_set(QUEUE_FLAG_REENTER, sdev->request_queue); - __blk_run_queue(sdev->request_queue, false); + __blk_run_queue(sdev->request_queue); if (flagset) queue_flag_clear(QUEUE_FLAG_REENTER, sdev->request_queue); spin_unlock(sdev->request_queue->queue_lock); diff --git a/drivers/scsi/scsi_transport_fc.c b/drivers/scsi/scsi_transport_fc.c index fdf3fa6..28c3350 100644 --- a/drivers/scsi/scsi_transport_fc.c +++ b/drivers/scsi/scsi_transport_fc.c @@ -3829,7 +3829,7 @@ fc_bsg_goose_queue(struct fc_rport *rport) !test_bit(QUEUE_FLAG_REENTER, &rport->rqst_q->queue_flags); if (flagset) queue_flag_set(QUEUE_FLAG_REENTER, rport->rqst_q); - __blk_run_queue(rport->rqst_q, false); + __blk_run_queue(rport->rqst_q); if (flagset) queue_flag_clear(QUEUE_FLAG_REENTER, rport->rqst_q); spin_unlock_irqrestore(rport->rqst_q->queue_lock, flags); diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h index 3448d89..cbbfd98 100644 --- a/include/linux/blkdev.h +++ b/include/linux/blkdev.h @@ -697,7 +697,7 @@ extern void blk_start_queue(struct request_queue *q); extern void blk_stop_queue(struct request_queue *q); extern void blk_sync_queue(struct request_queue *q); extern void __blk_stop_queue(struct request_queue *q); -extern void __blk_run_queue(struct request_queue *q, bool force_kblockd); +extern void __blk_run_queue(struct request_queue *q); extern void blk_run_queue(struct request_queue *); extern int blk_rq_map_user(struct request_queue *, struct request *, struct rq_map_data *, void __user *, unsigned long, -- cgit v0.10.2 From f65647c29b14f5a32ff6f3237b0ef3b375ed5a79 Mon Sep 17 00:00:00 2001 From: Chris Mason Date: Mon, 18 Apr 2011 08:55:34 -0400 Subject: Btrfs: fix free space cache leak The free space caching code was recently reworked to cache all the pages it needed instead of using find_get_page everywhere. One loop was missed though, so it ended up leaking pages. This fixes it to use our page array instead of find_get_page. Signed-off-by: Chris Mason diff --git a/fs/btrfs/free-space-cache.c b/fs/btrfs/free-space-cache.c index a3f420d..11d2e9c 100644 --- a/fs/btrfs/free-space-cache.c +++ b/fs/btrfs/free-space-cache.c @@ -732,7 +732,7 @@ int btrfs_write_out_cache(struct btrfs_root *root, out_of_space = true; break; } - page = find_get_page(inode->i_mapping, index); + page = pages[index]; addr = kmap(page); memcpy(addr, entry->bitmap, PAGE_CACHE_SIZE); -- cgit v0.10.2 From deab72d3797e3d4340c7ddf968234b8c3d01d7a5 Mon Sep 17 00:00:00 2001 From: Bob Peterson Date: Wed, 16 Mar 2011 16:32:39 -0400 Subject: GFS2: write_end error path fails to unlock transaction lock I did an audit of gfs2's transaction glock for bugzilla bug 658619 and ran across this: In function gfs2_write_end, in the unlikely event that gfs2_meta_inode_buffer returns an error, the code may forget to unlock the transaction lock because the "failed" label appears after the call to function gfs2_trans_end. Signed-off-by: Bob Peterson Signed-off-by: Steven Whitehouse diff --git a/fs/gfs2/aops.c b/fs/gfs2/aops.c index c71995b..0f5c4f9 100644 --- a/fs/gfs2/aops.c +++ b/fs/gfs2/aops.c @@ -884,8 +884,8 @@ static int gfs2_write_end(struct file *file, struct address_space *mapping, } brelse(dibh); - gfs2_trans_end(sdp); failed: + gfs2_trans_end(sdp); if (al) { gfs2_inplace_release(ip); gfs2_quota_unlock(ip); -- cgit v0.10.2 From 0ee532062fa7ff0795b3862c2d50efe32e552f9f Mon Sep 17 00:00:00 2001 From: Benjamin Marzinski Date: Thu, 17 Mar 2011 21:54:46 -0500 Subject: GFS2: directly write blocks past i_size GFS2 was relying on the writepage code to write out the zeroed data for fallocate. However, with FALLOC_FL_KEEP_SIZE set, this may be past i_size. If it is, it will be ignored. To work around this, gfs2 now calls write_dirty_buffer directly on the buffer_heads when FALLOC_FL_KEEP_SIZE is set, and it's writing past i_size. This version is just a cleanup of my last version Signed-off-by: Benjamin Marzinski Signed-off-by: Steven Whitehouse diff --git a/fs/gfs2/file.c b/fs/gfs2/file.c index b2682e0..e483108 100644 --- a/fs/gfs2/file.c +++ b/fs/gfs2/file.c @@ -617,18 +617,51 @@ static ssize_t gfs2_file_aio_write(struct kiocb *iocb, const struct iovec *iov, return generic_file_aio_write(iocb, iov, nr_segs, pos); } -static void empty_write_end(struct page *page, unsigned from, - unsigned to) +static int empty_write_end(struct page *page, unsigned from, + unsigned to, int mode) { - struct gfs2_inode *ip = GFS2_I(page->mapping->host); + struct inode *inode = page->mapping->host; + struct gfs2_inode *ip = GFS2_I(inode); + struct buffer_head *bh; + unsigned offset, blksize = 1 << inode->i_blkbits; + pgoff_t end_index = i_size_read(inode) >> PAGE_CACHE_SHIFT; zero_user(page, from, to-from); mark_page_accessed(page); - if (!gfs2_is_writeback(ip)) - gfs2_page_add_databufs(ip, page, from, to); + if (page->index < end_index || !(mode & FALLOC_FL_KEEP_SIZE)) { + if (!gfs2_is_writeback(ip)) + gfs2_page_add_databufs(ip, page, from, to); + + block_commit_write(page, from, to); + return 0; + } + + offset = 0; + bh = page_buffers(page); + while (offset < to) { + if (offset >= from) { + set_buffer_uptodate(bh); + mark_buffer_dirty(bh); + clear_buffer_new(bh); + write_dirty_buffer(bh, WRITE); + } + offset += blksize; + bh = bh->b_this_page; + } - block_commit_write(page, from, to); + offset = 0; + bh = page_buffers(page); + while (offset < to) { + if (offset >= from) { + wait_on_buffer(bh); + if (!buffer_uptodate(bh)) + return -EIO; + } + offset += blksize; + bh = bh->b_this_page; + } + return 0; } static int needs_empty_write(sector_t block, struct inode *inode) @@ -643,7 +676,8 @@ static int needs_empty_write(sector_t block, struct inode *inode) return !buffer_mapped(&bh_map); } -static int write_empty_blocks(struct page *page, unsigned from, unsigned to) +static int write_empty_blocks(struct page *page, unsigned from, unsigned to, + int mode) { struct inode *inode = page->mapping->host; unsigned start, end, next, blksize; @@ -668,7 +702,9 @@ static int write_empty_blocks(struct page *page, unsigned from, unsigned to) gfs2_block_map); if (unlikely(ret)) return ret; - empty_write_end(page, start, end); + ret = empty_write_end(page, start, end, mode); + if (unlikely(ret)) + return ret; end = 0; } start = next; @@ -682,7 +718,9 @@ static int write_empty_blocks(struct page *page, unsigned from, unsigned to) ret = __block_write_begin(page, start, end - start, gfs2_block_map); if (unlikely(ret)) return ret; - empty_write_end(page, start, end); + ret = empty_write_end(page, start, end, mode); + if (unlikely(ret)) + return ret; } return 0; @@ -731,7 +769,7 @@ static int fallocate_chunk(struct inode *inode, loff_t offset, loff_t len, if (curr == end) to = end_offset; - error = write_empty_blocks(page, from, to); + error = write_empty_blocks(page, from, to, mode); if (!error && offset + to > inode->i_size && !(mode & FALLOC_FL_KEEP_SIZE)) { i_size_write(inode, offset + to); -- cgit v0.10.2 From 001e8e8df4283dd4ef7a0297c012fce364c05cf1 Mon Sep 17 00:00:00 2001 From: Steven Whitehouse Date: Wed, 30 Mar 2011 14:17:51 +0100 Subject: GFS2: Don't try to deallocate unlinked inodes when mounted ro This adds a couple of missing tests to avoid read-only nodes from attempting to deallocate unlinked inodes. Signed-off-by: Steven Whitehouse Reported-by: Michel Andre de la Porte diff --git a/fs/gfs2/glops.c b/fs/gfs2/glops.c index 3754e3c..25eeb2b 100644 --- a/fs/gfs2/glops.c +++ b/fs/gfs2/glops.c @@ -385,6 +385,10 @@ static int trans_go_demote_ok(const struct gfs2_glock *gl) static void iopen_go_callback(struct gfs2_glock *gl) { struct gfs2_inode *ip = (struct gfs2_inode *)gl->gl_object; + struct gfs2_sbd *sdp = gl->gl_sbd; + + if (sdp->sd_vfs->s_flags & MS_RDONLY) + return; if (gl->gl_demote_state == LM_ST_UNLOCKED && gl->gl_state == LM_ST_SHARED && ip) { diff --git a/fs/gfs2/super.c b/fs/gfs2/super.c index a4e23d6..5b2cb81 100644 --- a/fs/gfs2/super.c +++ b/fs/gfs2/super.c @@ -1318,12 +1318,13 @@ static int gfs2_show_options(struct seq_file *s, struct vfsmount *mnt) static void gfs2_evict_inode(struct inode *inode) { - struct gfs2_sbd *sdp = inode->i_sb->s_fs_info; + struct super_block *sb = inode->i_sb; + struct gfs2_sbd *sdp = sb->s_fs_info; struct gfs2_inode *ip = GFS2_I(inode); struct gfs2_holder gh; int error; - if (inode->i_nlink) + if (inode->i_nlink || (sb->s_flags & MS_RDONLY)) goto out; error = gfs2_glock_nq_init(ip->i_gl, LM_ST_EXCLUSIVE, 0, &gh); -- cgit v0.10.2 From 44ad37d69b2cc421d5b5c7ad7fed16230685b092 Mon Sep 17 00:00:00 2001 From: Bob Peterson Date: Thu, 17 Mar 2011 16:19:58 -0400 Subject: GFS2: filesystem hang caused by incorrect lock order This patch fixes a deadlock in GFS2 where two processes are trying to reclaim an unlinked dinode: One holds the inode glock and calls gfs2_lookup_by_inum trying to look up the inode, which it can't, due to I_FREEING. The other has set I_FREEING from vfs and is at the beginning of gfs2_delete_inode waiting for the glock, which is held by the first. The solution is to add a new non_block parameter to the gfs2_iget function that causes it to return -ENOENT if the inode is being freed. Signed-off-by: Bob Peterson Signed-off-by: Steven Whitehouse diff --git a/fs/gfs2/dir.c b/fs/gfs2/dir.c index 5c356d0..f789c57 100644 --- a/fs/gfs2/dir.c +++ b/fs/gfs2/dir.c @@ -1506,7 +1506,7 @@ struct inode *gfs2_dir_search(struct inode *dir, const struct qstr *name) inode = gfs2_inode_lookup(dir->i_sb, be16_to_cpu(dent->de_type), be64_to_cpu(dent->de_inum.no_addr), - be64_to_cpu(dent->de_inum.no_formal_ino)); + be64_to_cpu(dent->de_inum.no_formal_ino), 0); brelse(bh); return inode; } diff --git a/fs/gfs2/inode.c b/fs/gfs2/inode.c index 97d54a2..9134dcb 100644 --- a/fs/gfs2/inode.c +++ b/fs/gfs2/inode.c @@ -40,37 +40,61 @@ struct gfs2_inum_range_host { u64 ir_length; }; +struct gfs2_skip_data { + u64 no_addr; + int skipped; + int non_block; +}; + static int iget_test(struct inode *inode, void *opaque) { struct gfs2_inode *ip = GFS2_I(inode); - u64 *no_addr = opaque; + struct gfs2_skip_data *data = opaque; - if (ip->i_no_addr == *no_addr) + if (ip->i_no_addr == data->no_addr) { + if (data->non_block && + inode->i_state & (I_FREEING|I_CLEAR|I_WILL_FREE)) { + data->skipped = 1; + return 0; + } return 1; - + } return 0; } static int iget_set(struct inode *inode, void *opaque) { struct gfs2_inode *ip = GFS2_I(inode); - u64 *no_addr = opaque; + struct gfs2_skip_data *data = opaque; - inode->i_ino = (unsigned long)*no_addr; - ip->i_no_addr = *no_addr; + if (data->skipped) + return -ENOENT; + inode->i_ino = (unsigned long)(data->no_addr); + ip->i_no_addr = data->no_addr; return 0; } struct inode *gfs2_ilookup(struct super_block *sb, u64 no_addr) { unsigned long hash = (unsigned long)no_addr; - return ilookup5(sb, hash, iget_test, &no_addr); + struct gfs2_skip_data data; + + data.no_addr = no_addr; + data.skipped = 0; + data.non_block = 0; + return ilookup5(sb, hash, iget_test, &data); } -static struct inode *gfs2_iget(struct super_block *sb, u64 no_addr) +static struct inode *gfs2_iget(struct super_block *sb, u64 no_addr, + int non_block) { + struct gfs2_skip_data data; unsigned long hash = (unsigned long)no_addr; - return iget5_locked(sb, hash, iget_test, iget_set, &no_addr); + + data.no_addr = no_addr; + data.skipped = 0; + data.non_block = non_block; + return iget5_locked(sb, hash, iget_test, iget_set, &data); } /** @@ -111,19 +135,20 @@ static void gfs2_set_iop(struct inode *inode) * @sb: The super block * @no_addr: The inode number * @type: The type of the inode + * non_block: Can we block on inodes that are being freed? * * Returns: A VFS inode, or an error */ struct inode *gfs2_inode_lookup(struct super_block *sb, unsigned int type, - u64 no_addr, u64 no_formal_ino) + u64 no_addr, u64 no_formal_ino, int non_block) { struct inode *inode; struct gfs2_inode *ip; struct gfs2_glock *io_gl = NULL; int error; - inode = gfs2_iget(sb, no_addr); + inode = gfs2_iget(sb, no_addr, non_block); ip = GFS2_I(inode); if (!inode) @@ -185,11 +210,12 @@ struct inode *gfs2_lookup_by_inum(struct gfs2_sbd *sdp, u64 no_addr, { struct super_block *sb = sdp->sd_vfs; struct gfs2_holder i_gh; - struct inode *inode; + struct inode *inode = NULL; int error; + /* Must not read in block until block type is verified */ error = gfs2_glock_nq_num(sdp, no_addr, &gfs2_inode_glops, - LM_ST_SHARED, LM_FLAG_ANY, &i_gh); + LM_ST_EXCLUSIVE, GL_SKIP, &i_gh); if (error) return ERR_PTR(error); @@ -197,7 +223,7 @@ struct inode *gfs2_lookup_by_inum(struct gfs2_sbd *sdp, u64 no_addr, if (error) goto fail; - inode = gfs2_inode_lookup(sb, DT_UNKNOWN, no_addr, 0); + inode = gfs2_inode_lookup(sb, DT_UNKNOWN, no_addr, 0, 1); if (IS_ERR(inode)) goto fail; @@ -843,7 +869,7 @@ struct inode *gfs2_createi(struct gfs2_holder *ghs, const struct qstr *name, goto fail_gunlock2; inode = gfs2_inode_lookup(dir->i_sb, IF2DT(mode), inum.no_addr, - inum.no_formal_ino); + inum.no_formal_ino, 0); if (IS_ERR(inode)) goto fail_gunlock2; diff --git a/fs/gfs2/inode.h b/fs/gfs2/inode.h index 3e00a66..099ca30 100644 --- a/fs/gfs2/inode.h +++ b/fs/gfs2/inode.h @@ -97,7 +97,8 @@ err: } extern struct inode *gfs2_inode_lookup(struct super_block *sb, unsigned type, - u64 no_addr, u64 no_formal_ino); + u64 no_addr, u64 no_formal_ino, + int non_block); extern struct inode *gfs2_lookup_by_inum(struct gfs2_sbd *sdp, u64 no_addr, u64 *no_formal_ino, unsigned int blktype); diff --git a/fs/gfs2/ops_fstype.c b/fs/gfs2/ops_fstype.c index 42ef243..d3c69eb 100644 --- a/fs/gfs2/ops_fstype.c +++ b/fs/gfs2/ops_fstype.c @@ -430,7 +430,7 @@ static int gfs2_lookup_root(struct super_block *sb, struct dentry **dptr, struct dentry *dentry; struct inode *inode; - inode = gfs2_inode_lookup(sb, DT_DIR, no_addr, 0); + inode = gfs2_inode_lookup(sb, DT_DIR, no_addr, 0, 0); if (IS_ERR(inode)) { fs_err(sdp, "can't read in %s inode: %ld\n", name, PTR_ERR(inode)); return PTR_ERR(inode); diff --git a/fs/gfs2/rgrp.c b/fs/gfs2/rgrp.c index cf930cd..6fcae84 100644 --- a/fs/gfs2/rgrp.c +++ b/fs/gfs2/rgrp.c @@ -945,7 +945,7 @@ static void try_rgrp_unlink(struct gfs2_rgrpd *rgd, u64 *last_unlinked, u64 skip /* rgblk_search can return a block < goal, so we need to keep it marching forward. */ no_addr = block + rgd->rd_data0; - goal++; + goal = max(block + 1, goal + 1); if (*last_unlinked != NO_BLOCK && no_addr <= *last_unlinked) continue; if (no_addr == skip) @@ -971,7 +971,7 @@ static void try_rgrp_unlink(struct gfs2_rgrpd *rgd, u64 *last_unlinked, u64 skip found++; /* Limit reclaim to sensible number of tasks */ - if (found > 2*NR_CPUS) + if (found > NR_CPUS) return; } diff --git a/fs/gfs2/super.c b/fs/gfs2/super.c index 5b2cb81..b9f28e6 100644 --- a/fs/gfs2/super.c +++ b/fs/gfs2/super.c @@ -1327,7 +1327,8 @@ static void gfs2_evict_inode(struct inode *inode) if (inode->i_nlink || (sb->s_flags & MS_RDONLY)) goto out; - error = gfs2_glock_nq_init(ip->i_gl, LM_ST_EXCLUSIVE, 0, &gh); + /* Must not read inode block until block type has been verified */ + error = gfs2_glock_nq_init(ip->i_gl, LM_ST_EXCLUSIVE, GL_SKIP, &gh); if (unlikely(error)) { gfs2_glock_dq_uninit(&ip->i_iopen_gh); goto out; @@ -1337,6 +1338,12 @@ static void gfs2_evict_inode(struct inode *inode) if (error) goto out_truncate; + if (test_bit(GIF_INVALID, &ip->i_flags)) { + error = gfs2_inode_refresh(ip); + if (error) + goto out_truncate; + } + ip->i_iopen_gh.gh_flags |= GL_NOCACHE; gfs2_glock_dq_wait(&ip->i_iopen_gh); gfs2_holder_reinit(LM_ST_EXCLUSIVE, LM_FLAG_TRY_1CB | GL_NOCACHE, &ip->i_iopen_gh); -- cgit v0.10.2 From cf8d91633ddef9e816ccbf3da833c79ce508988d Mon Sep 17 00:00:00 2001 From: Konrad Rzeszutek Wilk Date: Mon, 28 Feb 2011 17:58:48 -0500 Subject: xen/p2m/m2p/gnttab: Support GNTMAP_host_map in the M2P override. We only supported the M2P (and P2M) override only for the GNTMAP_contains_pte type mappings. Meaning that we grants operations would "contain the machine address of the PTE to update" If the flag is unset, then the grant operation is "contains a host virtual address". The latter case means that the Hypervisor takes care of updating our page table (specifically the PTE entry) with the guest's MFN. As such we should not try to do anything with the PTE. Previous to this patch we would try to clear the PTE which resulted in Xen hypervisor being upset with us: (XEN) mm.c:1066:d0 Attempt to implicitly unmap a granted PTE c0100000ccc59067 (XEN) domain_crash called from mm.c:1067 (XEN) Domain 0 (vcpu#0) crashed on cpu#3: (XEN) ----[ Xen-4.0-110228 x86_64 debug=y Not tainted ]---- and crashing us. This patch allows us to inhibit the PTE clearing in the PV guest if the GNTMAP_contains_pte is not set. On the m2p_remove_override path we provide the same parameter. Sadly in the grant-table driver we do not have a mechanism to tell m2p_remove_override whether to clear the PTE or not. Since the grant-table driver is used by user-space, we can safely assume that it operates only on PTE's. Hence the implementation for it to work on !GNTMAP_contains_pte returns -EOPNOTSUPP. In the future we can implement the support for this. It will require some extra accounting structure to keep track of the page[i], and the flag. [v1: Added documentation details, made it return -EOPNOTSUPP instead of trying to do a half-way implementation] Signed-off-by: Konrad Rzeszutek Wilk diff --git a/arch/x86/include/asm/xen/page.h b/arch/x86/include/asm/xen/page.h index c61934f..64a619d 100644 --- a/arch/x86/include/asm/xen/page.h +++ b/arch/x86/include/asm/xen/page.h @@ -47,8 +47,9 @@ extern bool __set_phys_to_machine(unsigned long pfn, unsigned long mfn); extern unsigned long set_phys_range_identity(unsigned long pfn_s, unsigned long pfn_e); -extern int m2p_add_override(unsigned long mfn, struct page *page); -extern int m2p_remove_override(struct page *page); +extern int m2p_add_override(unsigned long mfn, struct page *page, + bool clear_pte); +extern int m2p_remove_override(struct page *page, bool clear_pte); extern struct page *m2p_find_override(unsigned long mfn); extern unsigned long m2p_find_override_pfn(unsigned long mfn, unsigned long pfn); diff --git a/arch/x86/xen/p2m.c b/arch/x86/xen/p2m.c index 141eb0d..2d2b32a 100644 --- a/arch/x86/xen/p2m.c +++ b/arch/x86/xen/p2m.c @@ -650,7 +650,7 @@ static unsigned long mfn_hash(unsigned long mfn) } /* Add an MFN override for a particular page */ -int m2p_add_override(unsigned long mfn, struct page *page) +int m2p_add_override(unsigned long mfn, struct page *page, bool clear_pte) { unsigned long flags; unsigned long pfn; @@ -662,7 +662,6 @@ int m2p_add_override(unsigned long mfn, struct page *page) if (!PageHighMem(page)) { address = (unsigned long)__va(pfn << PAGE_SHIFT); ptep = lookup_address(address, &level); - if (WARN(ptep == NULL || level != PG_LEVEL_4K, "m2p_add_override: pfn %lx not mapped", pfn)) return -EINVAL; @@ -674,10 +673,9 @@ int m2p_add_override(unsigned long mfn, struct page *page) if (unlikely(!set_phys_to_machine(pfn, FOREIGN_FRAME(mfn)))) return -ENOMEM; - if (!PageHighMem(page)) + if (clear_pte && !PageHighMem(page)) /* Just zap old mapping for now */ pte_clear(&init_mm, address, ptep); - spin_lock_irqsave(&m2p_override_lock, flags); list_add(&page->lru, &m2p_overrides[mfn_hash(mfn)]); spin_unlock_irqrestore(&m2p_override_lock, flags); @@ -685,7 +683,7 @@ int m2p_add_override(unsigned long mfn, struct page *page) return 0; } -int m2p_remove_override(struct page *page) +int m2p_remove_override(struct page *page, bool clear_pte) { unsigned long flags; unsigned long mfn; @@ -713,7 +711,7 @@ int m2p_remove_override(struct page *page) spin_unlock_irqrestore(&m2p_override_lock, flags); set_phys_to_machine(pfn, page->index); - if (!PageHighMem(page)) + if (clear_pte && !PageHighMem(page)) set_pte_at(&init_mm, address, ptep, pfn_pte(pfn, PAGE_KERNEL)); /* No tlb flush necessary because the caller already diff --git a/drivers/xen/grant-table.c b/drivers/xen/grant-table.c index 3745a31..fd725cd 100644 --- a/drivers/xen/grant-table.c +++ b/drivers/xen/grant-table.c @@ -466,13 +466,30 @@ int gnttab_map_refs(struct gnttab_map_grant_ref *map_ops, if (map_ops[i].status) continue; - /* m2p override only supported for GNTMAP_contains_pte mappings */ - if (!(map_ops[i].flags & GNTMAP_contains_pte)) - continue; - pte = (pte_t *) (mfn_to_virt(PFN_DOWN(map_ops[i].host_addr)) + + if (map_ops[i].flags & GNTMAP_contains_pte) { + pte = (pte_t *) (mfn_to_virt(PFN_DOWN(map_ops[i].host_addr)) + (map_ops[i].host_addr & ~PAGE_MASK)); - mfn = pte_mfn(*pte); - ret = m2p_add_override(mfn, pages[i]); + mfn = pte_mfn(*pte); + } else { + /* If you really wanted to do this: + * mfn = PFN_DOWN(map_ops[i].dev_bus_addr); + * + * The reason we do not implement it is b/c on the + * unmap path (gnttab_unmap_refs) we have no means of + * checking whether the page is !GNTMAP_contains_pte. + * + * That is without some extra data-structure to carry + * the struct page, bool clear_pte, and list_head next + * tuples and deal with allocation/delallocation, etc. + * + * The users of this API set the GNTMAP_contains_pte + * flag so lets just return not supported until it + * becomes neccessary to implement. + */ + return -EOPNOTSUPP; + } + ret = m2p_add_override(mfn, pages[i], + map_ops[i].flags & GNTMAP_contains_pte); if (ret) return ret; } @@ -494,7 +511,7 @@ int gnttab_unmap_refs(struct gnttab_unmap_grant_ref *unmap_ops, return ret; for (i = 0; i < count; i++) { - ret = m2p_remove_override(pages[i]); + ret = m2p_remove_override(pages[i], true /* clear the PTE */); if (ret) return ret; } -- cgit v0.10.2 From 7caa2316bf0434f1150f58cb576542987a0466d7 Mon Sep 17 00:00:00 2001 From: Daniel Halperin Date: Wed, 6 Apr 2011 12:47:25 -0700 Subject: iwlwifi: fix frame injection for HT channels For some reason, sending QoS configuration causes transmission to stop after a single frame on HT channels when not associated. Removing the extra QoS configuration has no effect on station mode, and fixes injection mode. Signed-off-by: Daniel Halperin Signed-off-by: Wey-Yi Guy diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-rxon.c b/drivers/net/wireless/iwlwifi/iwl-agn-rxon.c index dfdbea6..fbbde071 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-rxon.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-rxon.c @@ -335,7 +335,6 @@ int iwlagn_mac_config(struct ieee80211_hw *hw, u32 changed) struct ieee80211_channel *channel = conf->channel; const struct iwl_channel_info *ch_info; int ret = 0; - bool ht_changed[NUM_IWL_RXON_CTX] = {}; IWL_DEBUG_MAC80211(priv, "changed %#x", changed); @@ -383,10 +382,8 @@ int iwlagn_mac_config(struct ieee80211_hw *hw, u32 changed) for_each_context(priv, ctx) { /* Configure HT40 channels */ - if (ctx->ht.enabled != conf_is_ht(conf)) { + if (ctx->ht.enabled != conf_is_ht(conf)) ctx->ht.enabled = conf_is_ht(conf); - ht_changed[ctx->ctxid] = true; - } if (ctx->ht.enabled) { if (conf_is_ht40_minus(conf)) { @@ -455,8 +452,6 @@ int iwlagn_mac_config(struct ieee80211_hw *hw, u32 changed) if (!memcmp(&ctx->staging, &ctx->active, sizeof(ctx->staging))) continue; iwlagn_commit_rxon(priv, ctx); - if (ht_changed[ctx->ctxid]) - iwlagn_update_qos(priv, ctx); } out: mutex_unlock(&priv->mutex); -- cgit v0.10.2 From e79b1ca75bb48111e8d93fc576f50e24671f5f9d Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Tue, 5 Apr 2011 08:30:43 -0700 Subject: iwlagn: use direct call for led functions After driver split, no need to call led functions through callback Signed-off-by: Wey-Yi Guy diff --git a/drivers/net/wireless/iwlwifi/Makefile b/drivers/net/wireless/iwlwifi/Makefile index 3652931..bb6a737 100644 --- a/drivers/net/wireless/iwlwifi/Makefile +++ b/drivers/net/wireless/iwlwifi/Makefile @@ -1,6 +1,6 @@ # AGN obj-$(CONFIG_IWLAGN) += iwlagn.o -iwlagn-objs := iwl-agn.o iwl-agn-rs.o iwl-agn-led.o +iwlagn-objs := iwl-agn.o iwl-agn-rs.o iwlagn-objs += iwl-agn-ucode.o iwl-agn-tx.o iwlagn-objs += iwl-agn-lib.o iwl-agn-calib.o iwl-io.o iwlagn-objs += iwl-agn-tt.o iwl-agn-sta.o iwl-agn-eeprom.o diff --git a/drivers/net/wireless/iwlwifi/iwl-1000.c b/drivers/net/wireless/iwlwifi/iwl-1000.c index d1d7852..809117d 100644 --- a/drivers/net/wireless/iwlwifi/iwl-1000.c +++ b/drivers/net/wireless/iwlwifi/iwl-1000.c @@ -45,7 +45,6 @@ #include "iwl-agn.h" #include "iwl-helpers.h" #include "iwl-agn-hw.h" -#include "iwl-agn-led.h" #include "iwl-agn-debugfs.h" /* Highest firmware API version supported */ @@ -226,7 +225,6 @@ static const struct iwl_ops iwl1000_ops = { .lib = &iwl1000_lib, .hcmd = &iwlagn_hcmd, .utils = &iwlagn_hcmd_utils, - .led = &iwlagn_led_ops, .ieee80211_ops = &iwlagn_hw_ops, }; diff --git a/drivers/net/wireless/iwlwifi/iwl-2000.c b/drivers/net/wireless/iwlwifi/iwl-2000.c index a31314f..0a330d1 100644 --- a/drivers/net/wireless/iwlwifi/iwl-2000.c +++ b/drivers/net/wireless/iwlwifi/iwl-2000.c @@ -46,7 +46,6 @@ #include "iwl-helpers.h" #include "iwl-agn-hw.h" #include "iwl-6000-hw.h" -#include "iwl-agn-led.h" #include "iwl-agn-debugfs.h" /* Highest firmware API version supported */ @@ -310,7 +309,6 @@ static const struct iwl_ops iwl2000_ops = { .lib = &iwl2000_lib, .hcmd = &iwlagn_hcmd, .utils = &iwlagn_hcmd_utils, - .led = &iwlagn_led_ops, .ieee80211_ops = &iwlagn_hw_ops, }; @@ -318,7 +316,6 @@ static const struct iwl_ops iwl2030_ops = { .lib = &iwl2000_lib, .hcmd = &iwlagn_bt_hcmd, .utils = &iwlagn_hcmd_utils, - .led = &iwlagn_led_ops, .ieee80211_ops = &iwlagn_hw_ops, }; @@ -326,7 +323,6 @@ static const struct iwl_ops iwl200_ops = { .lib = &iwl2000_lib, .hcmd = &iwlagn_hcmd, .utils = &iwlagn_hcmd_utils, - .led = &iwlagn_led_ops, .ieee80211_ops = &iwlagn_hw_ops, }; @@ -334,7 +330,6 @@ static const struct iwl_ops iwl230_ops = { .lib = &iwl2000_lib, .hcmd = &iwlagn_bt_hcmd, .utils = &iwlagn_hcmd_utils, - .led = &iwlagn_led_ops, .ieee80211_ops = &iwlagn_hw_ops, }; diff --git a/drivers/net/wireless/iwlwifi/iwl-5000.c b/drivers/net/wireless/iwlwifi/iwl-5000.c index 7c28666..79dd45c 100644 --- a/drivers/net/wireless/iwlwifi/iwl-5000.c +++ b/drivers/net/wireless/iwlwifi/iwl-5000.c @@ -45,7 +45,6 @@ #include "iwl-sta.h" #include "iwl-helpers.h" #include "iwl-agn.h" -#include "iwl-agn-led.h" #include "iwl-agn-hw.h" #include "iwl-5000-hw.h" #include "iwl-agn-debugfs.h" @@ -447,7 +446,6 @@ static const struct iwl_ops iwl5000_ops = { .lib = &iwl5000_lib, .hcmd = &iwlagn_hcmd, .utils = &iwlagn_hcmd_utils, - .led = &iwlagn_led_ops, .ieee80211_ops = &iwlagn_hw_ops, }; @@ -455,7 +453,6 @@ static const struct iwl_ops iwl5150_ops = { .lib = &iwl5150_lib, .hcmd = &iwlagn_hcmd, .utils = &iwlagn_hcmd_utils, - .led = &iwlagn_led_ops, .ieee80211_ops = &iwlagn_hw_ops, }; diff --git a/drivers/net/wireless/iwlwifi/iwl-6000.c b/drivers/net/wireless/iwlwifi/iwl-6000.c index 0649813..a35338e 100644 --- a/drivers/net/wireless/iwlwifi/iwl-6000.c +++ b/drivers/net/wireless/iwlwifi/iwl-6000.c @@ -46,7 +46,6 @@ #include "iwl-helpers.h" #include "iwl-agn-hw.h" #include "iwl-6000-hw.h" -#include "iwl-agn-led.h" #include "iwl-agn-debugfs.h" /* Highest firmware API version supported */ @@ -397,7 +396,6 @@ static const struct iwl_ops iwl6000_ops = { .lib = &iwl6000_lib, .hcmd = &iwlagn_hcmd, .utils = &iwlagn_hcmd_utils, - .led = &iwlagn_led_ops, .ieee80211_ops = &iwlagn_hw_ops, }; @@ -405,7 +403,6 @@ static const struct iwl_ops iwl6050_ops = { .lib = &iwl6000_lib, .hcmd = &iwlagn_hcmd, .utils = &iwlagn_hcmd_utils, - .led = &iwlagn_led_ops, .nic = &iwl6050_nic_ops, .ieee80211_ops = &iwlagn_hw_ops, }; @@ -414,7 +411,6 @@ static const struct iwl_ops iwl6150_ops = { .lib = &iwl6000_lib, .hcmd = &iwlagn_hcmd, .utils = &iwlagn_hcmd_utils, - .led = &iwlagn_led_ops, .nic = &iwl6150_nic_ops, .ieee80211_ops = &iwlagn_hw_ops, }; @@ -423,7 +419,6 @@ static const struct iwl_ops iwl6030_ops = { .lib = &iwl6030_lib, .hcmd = &iwlagn_bt_hcmd, .utils = &iwlagn_hcmd_utils, - .led = &iwlagn_led_ops, .ieee80211_ops = &iwlagn_hw_ops, }; diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-led.c b/drivers/net/wireless/iwlwifi/iwl-agn-led.c deleted file mode 100644 index 4bb877e..0000000 --- a/drivers/net/wireless/iwlwifi/iwl-agn-led.c +++ /dev/null @@ -1,73 +0,0 @@ -/****************************************************************************** - * - * Copyright(c) 2003 - 2011 Intel Corporation. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of version 2 of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA - * - * The full GNU General Public License is included in this distribution in the - * file called LICENSE. - * - * Contact Information: - * Intel Linux Wireless - * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 - * - *****************************************************************************/ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "iwl-commands.h" -#include "iwl-dev.h" -#include "iwl-core.h" -#include "iwl-io.h" -#include "iwl-agn-led.h" - -/* Send led command */ -static int iwl_send_led_cmd(struct iwl_priv *priv, struct iwl_led_cmd *led_cmd) -{ - struct iwl_host_cmd cmd = { - .id = REPLY_LEDS_CMD, - .len = sizeof(struct iwl_led_cmd), - .data = led_cmd, - .flags = CMD_ASYNC, - .callback = NULL, - }; - u32 reg; - - reg = iwl_read32(priv, CSR_LED_REG); - if (reg != (reg & CSR_LED_BSM_CTRL_MSK)) - iwl_write32(priv, CSR_LED_REG, reg & CSR_LED_BSM_CTRL_MSK); - - return iwl_send_cmd(priv, &cmd); -} - -/* Set led register off */ -void iwlagn_led_enable(struct iwl_priv *priv) -{ - iwl_write32(priv, CSR_LED_REG, CSR_LED_REG_TRUN_ON); -} - -const struct iwl_led_ops iwlagn_led_ops = { - .cmd = iwl_send_led_cmd, -}; diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-led.h b/drivers/net/wireless/iwlwifi/iwl-agn-led.h deleted file mode 100644 index c0b7611..0000000 --- a/drivers/net/wireless/iwlwifi/iwl-agn-led.h +++ /dev/null @@ -1,33 +0,0 @@ -/****************************************************************************** - * - * Copyright(c) 2003 - 2011 Intel Corporation. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of version 2 of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA - * - * The full GNU General Public License is included in this distribution in the - * file called LICENSE. - * - * Contact Information: - * Intel Linux Wireless - * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 - * - *****************************************************************************/ - -#ifndef __iwl_agn_led_h__ -#define __iwl_agn_led_h__ - -extern const struct iwl_led_ops iwlagn_led_ops; -void iwlagn_led_enable(struct iwl_priv *priv); - -#endif /* __iwl_agn_led_h__ */ diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index 47a4cda..b4f7510 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -59,7 +59,6 @@ #include "iwl-sta.h" #include "iwl-agn-calib.h" #include "iwl-agn.h" -#include "iwl-agn-led.h" /****************************************************************************** diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h index 6988335..240abdf 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.h +++ b/drivers/net/wireless/iwlwifi/iwl-core.h @@ -217,7 +217,6 @@ struct iwl_ops { const struct iwl_lib_ops *lib; const struct iwl_hcmd_ops *hcmd; const struct iwl_hcmd_utils_ops *utils; - const struct iwl_led_ops *led; const struct iwl_nic_ops *nic; const struct iwl_legacy_ops *legacy; const struct ieee80211_ops *ieee80211_ops; diff --git a/drivers/net/wireless/iwlwifi/iwl-led.c b/drivers/net/wireless/iwlwifi/iwl-led.c index 0d90004..d798c2a 100644 --- a/drivers/net/wireless/iwlwifi/iwl-led.c +++ b/drivers/net/wireless/iwlwifi/iwl-led.c @@ -61,6 +61,12 @@ static const struct ieee80211_tpt_blink iwl_blink[] = { { .throughput = 300 * 1024 - 1, .blink_time = 50 }, }; +/* Set led register off */ +void iwlagn_led_enable(struct iwl_priv *priv) +{ + iwl_write32(priv, CSR_LED_REG, CSR_LED_REG_TRUN_ON); +} + /* * Adjust led blink rate to compensate on a MAC Clock difference on every HW * Led blink rate analysis showed an average deviation of 20% on 5000 series @@ -84,6 +90,24 @@ static inline u8 iwl_blink_compensation(struct iwl_priv *priv, return (u8)((time * compensation) >> 6); } +static int iwl_send_led_cmd(struct iwl_priv *priv, struct iwl_led_cmd *led_cmd) +{ + struct iwl_host_cmd cmd = { + .id = REPLY_LEDS_CMD, + .len = sizeof(struct iwl_led_cmd), + .data = led_cmd, + .flags = CMD_ASYNC, + .callback = NULL, + }; + u32 reg; + + reg = iwl_read32(priv, CSR_LED_REG); + if (reg != (reg & CSR_LED_BSM_CTRL_MSK)) + iwl_write32(priv, CSR_LED_REG, reg & CSR_LED_BSM_CTRL_MSK); + + return iwl_send_cmd(priv, &cmd); +} + /* Set led pattern command */ static int iwl_led_cmd(struct iwl_priv *priv, unsigned long on, @@ -108,7 +132,7 @@ static int iwl_led_cmd(struct iwl_priv *priv, led_cmd.off = iwl_blink_compensation(priv, off, priv->cfg->base_params->led_compensation); - ret = priv->cfg->ops->led->cmd(priv, &led_cmd); + ret = iwl_send_led_cmd(priv, &led_cmd); if (!ret) { priv->blink_on = on; priv->blink_off = off; diff --git a/drivers/net/wireless/iwlwifi/iwl-led.h b/drivers/net/wireless/iwlwifi/iwl-led.h index 05b8e8f..1c93dfe 100644 --- a/drivers/net/wireless/iwlwifi/iwl-led.h +++ b/drivers/net/wireless/iwlwifi/iwl-led.h @@ -50,6 +50,7 @@ enum iwl_led_mode { IWL_LED_BLINK, }; +void iwlagn_led_enable(struct iwl_priv *priv); void iwl_leds_init(struct iwl_priv *priv); void iwl_leds_exit(struct iwl_priv *priv); -- cgit v0.10.2 From b3c27b51db9112d03864fdef44fa611dd69c1425 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Fri, 15 Apr 2011 20:17:34 +0200 Subject: ASoC: add a module alias to the FSI driver This patch enables FSI driver autoloading on sh-mobile systems. Signed-off-by: Guennadi Liakhovetski Reviewed-by: Simon Horman Signed-off-by: Mark Brown diff --git a/sound/soc/sh/fsi.c b/sound/soc/sh/fsi.c index 5843158..23c0e83 100644 --- a/sound/soc/sh/fsi.c +++ b/sound/soc/sh/fsi.c @@ -1330,3 +1330,4 @@ module_exit(fsi_mobile_exit); MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("SuperH onchip FSI audio driver"); MODULE_AUTHOR("Kuninori Morimoto "); +MODULE_ALIAS("platform:fsi-pcm-audio"); -- cgit v0.10.2 From 3e41ace5deef7af16dd277d9d17f9d36dca0a10e Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 18 Apr 2011 09:12:37 -0700 Subject: iwlagn: remove most BUG_ON instances There are a number of things in the driver that may result in a BUG(), which is suboptimal since it's hard to get debugging information out of the driver in that case and the user experience is also not good :-) Almost all BUG_ON instances can be converted to WARN_ON with a few lines of appropriate error handling, so do that instead. Signed-off-by: Johannes Berg Signed-off-by: Wey-Yi Guy diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index b4f7510..0daeded 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -394,7 +394,9 @@ int iwl_hw_txq_attach_buf_to_tfd(struct iwl_priv *priv, return -EINVAL; } - BUG_ON(addr & ~DMA_BIT_MASK(36)); + if (WARN_ON(addr & ~DMA_BIT_MASK(36))) + return -EINVAL; + if (unlikely(addr & ~IWL_TX_DMA_MASK)) IWL_ERR(priv, "Unaligned address = %llx\n", (unsigned long long)addr); @@ -718,7 +720,10 @@ static void iwl_rx_handle(struct iwl_priv *priv) /* If an RXB doesn't have a Rx queue slot associated with it, * then a bug has been introduced in the queue refilling * routines -- catch it here */ - BUG_ON(rxb == NULL); + if (WARN_ON(rxb == NULL)) { + i = (i + 1) & RX_QUEUE_MASK; + continue; + } rxq->queue[i] = NULL; diff --git a/drivers/net/wireless/iwlwifi/iwl-eeprom.c b/drivers/net/wireless/iwlwifi/iwl-eeprom.c index 859b94a..4027336 100644 --- a/drivers/net/wireless/iwlwifi/iwl-eeprom.c +++ b/drivers/net/wireless/iwlwifi/iwl-eeprom.c @@ -215,12 +215,6 @@ static int iwlcore_get_nvm_type(struct iwl_priv *priv, u32 hw_rev) return nvm_type; } -const u8 *iwlcore_eeprom_query_addr(const struct iwl_priv *priv, size_t offset) -{ - BUG_ON(offset >= priv->cfg->base_params->eeprom_size); - return &priv->eeprom[offset]; -} - static int iwl_init_otp_access(struct iwl_priv *priv) { int ret; diff --git a/drivers/net/wireless/iwlwifi/iwl-eeprom.h b/drivers/net/wireless/iwlwifi/iwl-eeprom.h index 0e9d970..9ce0525 100644 --- a/drivers/net/wireless/iwlwifi/iwl-eeprom.h +++ b/drivers/net/wireless/iwlwifi/iwl-eeprom.h @@ -309,7 +309,6 @@ int iwl_eeprom_check_sku(struct iwl_priv *priv); const u8 *iwl_eeprom_query_addr(const struct iwl_priv *priv, size_t offset); int iwlcore_eeprom_verify_signature(struct iwl_priv *priv); u16 iwl_eeprom_query16(const struct iwl_priv *priv, size_t offset); -const u8 *iwlcore_eeprom_query_addr(const struct iwl_priv *priv, size_t offset); int iwl_init_channel_map(struct iwl_priv *priv); void iwl_free_channel_map(struct iwl_priv *priv); const struct iwl_channel_info *iwl_get_channel_info( diff --git a/drivers/net/wireless/iwlwifi/iwl-hcmd.c b/drivers/net/wireless/iwlwifi/iwl-hcmd.c index 9177b55..8f0beb9 100644 --- a/drivers/net/wireless/iwlwifi/iwl-hcmd.c +++ b/drivers/net/wireless/iwlwifi/iwl-hcmd.c @@ -143,10 +143,12 @@ static int iwl_send_cmd_async(struct iwl_priv *priv, struct iwl_host_cmd *cmd) { int ret; - BUG_ON(!(cmd->flags & CMD_ASYNC)); + if (WARN_ON(!(cmd->flags & CMD_ASYNC))) + return -EINVAL; /* An asynchronous command can not expect an SKB to be set. */ - BUG_ON(cmd->flags & CMD_WANT_SKB); + if (WARN_ON(cmd->flags & CMD_WANT_SKB)) + return -EINVAL; /* Assign a generic callback if one is not provided */ if (!cmd->callback) @@ -169,10 +171,12 @@ int iwl_send_cmd_sync(struct iwl_priv *priv, struct iwl_host_cmd *cmd) int cmd_idx; int ret; - lockdep_assert_held(&priv->mutex); + if (WARN_ON(cmd->flags & CMD_ASYNC)) + return -EINVAL; /* A synchronous command can not have a callback set. */ - BUG_ON((cmd->flags & CMD_ASYNC) || cmd->callback); + if (WARN_ON(cmd->callback)) + return -EINVAL; IWL_DEBUG_INFO(priv, "Attempting to send sync command %s\n", get_cmd_string(cmd->id)); diff --git a/drivers/net/wireless/iwlwifi/iwl-power.c b/drivers/net/wireless/iwlwifi/iwl-power.c index ae176d8..b7cd958 100644 --- a/drivers/net/wireless/iwlwifi/iwl-power.c +++ b/drivers/net/wireless/iwlwifi/iwl-power.c @@ -188,9 +188,10 @@ static void iwl_static_sleep_cmd(struct iwl_priv *priv, table = range_0; } - BUG_ON(lvl < 0 || lvl >= IWL_POWER_NUM); - - *cmd = table[lvl].cmd; + if (WARN_ON(lvl < 0 || lvl >= IWL_POWER_NUM)) + memset(cmd, 0, sizeof(*cmd)); + else + *cmd = table[lvl].cmd; if (period == 0) { skip = 0; diff --git a/drivers/net/wireless/iwlwifi/iwl-sta.c b/drivers/net/wireless/iwlwifi/iwl-sta.c index c215156..3c8cebd 100644 --- a/drivers/net/wireless/iwlwifi/iwl-sta.c +++ b/drivers/net/wireless/iwlwifi/iwl-sta.c @@ -494,7 +494,8 @@ int iwl_remove_station(struct iwl_priv *priv, const u8 sta_id, priv->num_stations--; - BUG_ON(priv->num_stations < 0); + if (WARN_ON(priv->num_stations < 0)) + priv->num_stations = 0; spin_unlock_irqrestore(&priv->sta_lock, flags); @@ -679,7 +680,8 @@ void iwl_dealloc_bcast_stations(struct iwl_priv *priv) priv->stations[i].used &= ~IWL_STA_UCODE_ACTIVE; priv->num_stations--; - BUG_ON(priv->num_stations < 0); + if (WARN_ON(priv->num_stations < 0)) + priv->num_stations = 0; kfree(priv->stations[i].lq); priv->stations[i].lq = NULL; } @@ -775,7 +777,8 @@ int iwl_send_lq_cmd(struct iwl_priv *priv, struct iwl_rxon_context *ctx, spin_unlock_irqrestore(&priv->sta_lock, flags_spin); iwl_dump_lq_cmd(priv, lq); - BUG_ON(init && (cmd.flags & CMD_ASYNC)); + if (WARN_ON(init && (cmd.flags & CMD_ASYNC))) + return -EINVAL; if (is_lq_table_valid(priv, ctx, lq)) ret = iwl_send_cmd(priv, &cmd); diff --git a/drivers/net/wireless/iwlwifi/iwl-tx.c b/drivers/net/wireless/iwlwifi/iwl-tx.c index 3732380..e7faba5 100644 --- a/drivers/net/wireless/iwlwifi/iwl-tx.c +++ b/drivers/net/wireless/iwlwifi/iwl-tx.c @@ -263,11 +263,13 @@ static int iwl_queue_init(struct iwl_priv *priv, struct iwl_queue *q, /* count must be power-of-two size, otherwise iwl_queue_inc_wrap * and iwl_queue_dec_wrap are broken. */ - BUG_ON(!is_power_of_2(count)); + if (WARN_ON(!is_power_of_2(count))) + return -EINVAL; /* slots_num must be power-of-two size, otherwise * get_cmd_index is broken. */ - BUG_ON(!is_power_of_2(slots_num)); + if (WARN_ON(!is_power_of_2(slots_num))) + return -EINVAL; q->low_mark = q->n_window / 4; if (q->low_mark < 4) @@ -384,7 +386,9 @@ int iwl_tx_queue_init(struct iwl_priv *priv, struct iwl_tx_queue *txq, BUILD_BUG_ON(TFD_QUEUE_SIZE_MAX & (TFD_QUEUE_SIZE_MAX - 1)); /* Initialize queue's high/low-water marks, and head/tail indexes */ - iwl_queue_init(priv, &txq->q, TFD_QUEUE_SIZE_MAX, slots_num, txq_id); + ret = iwl_queue_init(priv, &txq->q, TFD_QUEUE_SIZE_MAX, slots_num, txq_id); + if (ret) + return ret; /* Tell device where to find queue */ priv->cfg->ops->lib->txq_init(priv, txq); @@ -446,14 +450,19 @@ int iwl_enqueue_hcmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd) cmd->len = priv->cfg->ops->utils->get_hcmd_size(cmd->id, cmd->len); fix_size = (u16)(cmd->len + sizeof(out_cmd->hdr)); - /* If any of the command structures end up being larger than + /* + * If any of the command structures end up being larger than * the TFD_MAX_PAYLOAD_SIZE, and it sent as a 'small' command then * we will need to increase the size of the TFD entries * Also, check to see if command buffer should not exceed the size - * of device_cmd and max_cmd_size. */ - BUG_ON((fix_size > TFD_MAX_PAYLOAD_SIZE) && - !(cmd->flags & CMD_SIZE_HUGE)); - BUG_ON(fix_size > IWL_MAX_CMD_SIZE); + * of device_cmd and max_cmd_size. + */ + if (WARN_ON((fix_size > TFD_MAX_PAYLOAD_SIZE) && + !(cmd->flags & CMD_SIZE_HUGE))) + return -EINVAL; + + if (WARN_ON(fix_size > IWL_MAX_CMD_SIZE)) + return -EINVAL; if (iwl_is_rfkill(priv) || iwl_is_ctkill(priv)) { IWL_WARN(priv, "Not sending command - %s KILL\n", -- cgit v0.10.2 From 7b21f00ee6073909c01adeba317af3d78c3b9d0a Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 18 Apr 2011 09:22:10 -0700 Subject: iwlagn: verify that huge commands are synchronous Since huge commands all share a single buffer, there can only be a single one in flight at a time since otherwise they'd overwrite each other. This is true in the driver now, but it seems like a possible source of bugs, so add a test to verify that huge commands are always sent synchronously. Signed-off-by: Johannes Berg Signed-off-by: Wey-Yi Guy diff --git a/drivers/net/wireless/iwlwifi/iwl-tx.c b/drivers/net/wireless/iwlwifi/iwl-tx.c index e7faba5..1b69507 100644 --- a/drivers/net/wireless/iwlwifi/iwl-tx.c +++ b/drivers/net/wireless/iwlwifi/iwl-tx.c @@ -470,6 +470,14 @@ int iwl_enqueue_hcmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd) return -EIO; } + /* + * As we only have a single huge buffer, check that the command + * is synchronous (otherwise buffers could end up being reused). + */ + + if (WARN_ON((cmd->flags & CMD_ASYNC) && (cmd->flags & CMD_SIZE_HUGE))) + return -EINVAL; + spin_lock_irqsave(&priv->hcmd_lock, flags); if (iwl_queue_space(q) < ((cmd->flags & CMD_ASYNC) ? 2 : 1)) { -- cgit v0.10.2 From b4ebd28f23e3ae00af886aff1c00f800dee3b080 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 6 Apr 2011 12:28:56 -0700 Subject: iwlagn: use huge command for beacon When testing some new P2P code, Angie found that the driver might crash because the beacon command ended up being bigger than a regular command. This is quite obvious -- a normal command is limited to roughly 360 bytes but a beacon may be much larger of course. To fix this, use the huge command buffer. Reported-by: Angie Chinchilla Signed-off-by: Johannes Berg Signed-off-by: Wey-Yi Guy diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index 0daeded..3cfd7eb 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -253,6 +253,10 @@ int iwlagn_send_beacon_cmd(struct iwl_priv *priv) struct iwl_frame *frame; unsigned int frame_size; int rc; + struct iwl_host_cmd cmd = { + .id = REPLY_TX_BEACON, + .flags = CMD_SIZE_HUGE, + }; frame = iwl_get_free_frame(priv); if (!frame) { @@ -268,8 +272,10 @@ int iwlagn_send_beacon_cmd(struct iwl_priv *priv) return -EINVAL; } - rc = iwl_send_cmd_pdu(priv, REPLY_TX_BEACON, frame_size, - &frame->u.cmd[0]); + cmd.len = frame_size; + cmd.data = &frame->u.cmd[0]; + + rc = iwl_send_cmd_sync(priv, &cmd); iwl_free_frame(priv, frame); -- cgit v0.10.2 From af289bfe15fc92ecfbf6d8312713815b33e452c0 Mon Sep 17 00:00:00 2001 From: Joerg Roedel Date: Mon, 18 Apr 2011 15:45:44 +0200 Subject: x86, gart: Convert spaces to tabs in enable_gart_translation Probably by copy&paste this function was indented by spaces. Convert this to tabs. Signed-off-by: Joerg Roedel Link: http://lkml.kernel.org/r/1303134346-5805-3-git-send-email-joerg.roedel@amd.com Signed-off-by: H. Peter Anvin diff --git a/arch/x86/include/asm/gart.h b/arch/x86/include/asm/gart.h index 43085bf..88c1ebe 100644 --- a/arch/x86/include/asm/gart.h +++ b/arch/x86/include/asm/gart.h @@ -75,17 +75,17 @@ static inline void enable_gart_translation(struct pci_dev *dev, u64 addr) { u32 tmp, ctl; - /* address of the mappings table */ - addr >>= 12; - tmp = (u32) addr<<4; - tmp &= ~0xf; - pci_write_config_dword(dev, AMD64_GARTTABLEBASE, tmp); - - /* Enable GART translation for this hammer. */ - pci_read_config_dword(dev, AMD64_GARTAPERTURECTL, &ctl); - ctl |= GARTEN; - ctl &= ~(DISGARTCPU | DISGARTIO); - pci_write_config_dword(dev, AMD64_GARTAPERTURECTL, ctl); + /* address of the mappings table */ + addr >>= 12; + tmp = (u32) addr<<4; + tmp &= ~0xf; + pci_write_config_dword(dev, AMD64_GARTTABLEBASE, tmp); + + /* Enable GART translation for this hammer. */ + pci_read_config_dword(dev, AMD64_GARTAPERTURECTL, &ctl); + ctl |= GARTEN; + ctl &= ~(DISGARTCPU | DISGARTIO); + pci_write_config_dword(dev, AMD64_GARTAPERTURECTL, ctl); } static inline int aperture_valid(u64 aper_base, u32 aper_size, u32 min_size) -- cgit v0.10.2 From c34151a742d84ae65db2088ea30495063f697fbe Mon Sep 17 00:00:00 2001 From: Joerg Roedel Date: Mon, 18 Apr 2011 15:45:45 +0200 Subject: x86, gart: Set DISTLBWALKPRB bit always The DISTLBWALKPRB bit must be set for the GART because the gatt table is mapped UC. But the current code does not set the bit at boot when the BIOS setup the aperture correctly. Fix that by setting this bit when enabling the GART instead of the other places. Cc: Cc: Borislav Petkov Signed-off-by: Joerg Roedel Link: http://lkml.kernel.org/r/1303134346-5805-4-git-send-email-joerg.roedel@amd.com Signed-off-by: H. Peter Anvin diff --git a/arch/x86/include/asm/gart.h b/arch/x86/include/asm/gart.h index 88c1ebe..156cd5d 100644 --- a/arch/x86/include/asm/gart.h +++ b/arch/x86/include/asm/gart.h @@ -66,7 +66,7 @@ static inline void gart_set_size_and_enable(struct pci_dev *dev, u32 order) * Don't enable translation but enable GART IO and CPU accesses. * Also, set DISTLBWALKPRB since GART tables memory is UC. */ - ctl = DISTLBWALKPRB | order << 1; + ctl = order << 1; pci_write_config_dword(dev, AMD64_GARTAPERTURECTL, ctl); } @@ -83,7 +83,7 @@ static inline void enable_gart_translation(struct pci_dev *dev, u64 addr) /* Enable GART translation for this hammer. */ pci_read_config_dword(dev, AMD64_GARTAPERTURECTL, &ctl); - ctl |= GARTEN; + ctl |= GARTEN | DISTLBWALKPRB; ctl &= ~(DISGARTCPU | DISGARTIO); pci_write_config_dword(dev, AMD64_GARTAPERTURECTL, ctl); } diff --git a/arch/x86/kernel/aperture_64.c b/arch/x86/kernel/aperture_64.c index 86d1ad4..73fb469 100644 --- a/arch/x86/kernel/aperture_64.c +++ b/arch/x86/kernel/aperture_64.c @@ -499,7 +499,7 @@ out: * Don't enable translation yet but enable GART IO and CPU * accesses and set DISTLBWALKPRB since GART table memory is UC. */ - u32 ctl = DISTLBWALKPRB | aper_order << 1; + u32 ctl = aper_order << 1; bus = amd_nb_bus_dev_ranges[i].bus; dev_base = amd_nb_bus_dev_ranges[i].dev_base; -- cgit v0.10.2 From 665d3e2af83c8fbd149534db8f57d82fa6fa6753 Mon Sep 17 00:00:00 2001 From: Joerg Roedel Date: Mon, 18 Apr 2011 15:45:46 +0200 Subject: x86, gart: Make sure GART does not map physmem above 1TB The GART can only map physical memory below 1TB. Make sure the gart driver in the kernel does not try to map memory above 1TB. Cc: Signed-off-by: Joerg Roedel Link: http://lkml.kernel.org/r/1303134346-5805-5-git-send-email-joerg.roedel@amd.com Signed-off-by: H. Peter Anvin diff --git a/arch/x86/kernel/pci-gart_64.c b/arch/x86/kernel/pci-gart_64.c index 82ada01..b117efd 100644 --- a/arch/x86/kernel/pci-gart_64.c +++ b/arch/x86/kernel/pci-gart_64.c @@ -81,6 +81,9 @@ static u32 gart_unmapped_entry; #define AGPEXTERN #endif +/* GART can only remap to physical addresses < 1TB */ +#define GART_MAX_PHYS_ADDR (1ULL << 40) + /* backdoor interface to AGP driver */ AGPEXTERN int agp_memory_reserved; AGPEXTERN __u32 *agp_gatt_table; @@ -212,9 +215,13 @@ static dma_addr_t dma_map_area(struct device *dev, dma_addr_t phys_mem, size_t size, int dir, unsigned long align_mask) { unsigned long npages = iommu_num_pages(phys_mem, size, PAGE_SIZE); - unsigned long iommu_page = alloc_iommu(dev, npages, align_mask); + unsigned long iommu_page; int i; + if (unlikely(phys_mem + size > GART_MAX_PHYS_ADDR)) + return bad_dma_addr; + + iommu_page = alloc_iommu(dev, npages, align_mask); if (iommu_page == -1) { if (!nonforced_iommu(dev, phys_mem, size)) return phys_mem; -- cgit v0.10.2 From b7af6a99690503a48c63ce5e587b4e4555f31cdb Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Wed, 6 Apr 2011 15:55:25 -0700 Subject: iwlagn: always support uCode trace All _agn devices support continuous uCode trace, remove checking Signed-off-by: Wey-Yi Guy diff --git a/drivers/net/wireless/iwlwifi/iwl-1000.c b/drivers/net/wireless/iwlwifi/iwl-1000.c index 809117d..e784456 100644 --- a/drivers/net/wireless/iwlwifi/iwl-1000.c +++ b/drivers/net/wireless/iwlwifi/iwl-1000.c @@ -242,7 +242,6 @@ static struct iwl_base_params iwl1000_base_params = { .chain_noise_scale = 1000, .wd_timeout = IWL_DEF_WD_TIMEOUT, .max_event_log_size = 128, - .ucode_tracing = true, }; static struct iwl_ht_params iwl1000_ht_params = { .ht_greenfield_support = true, diff --git a/drivers/net/wireless/iwlwifi/iwl-2000.c b/drivers/net/wireless/iwlwifi/iwl-2000.c index 0a330d1..dcd6608 100644 --- a/drivers/net/wireless/iwlwifi/iwl-2000.c +++ b/drivers/net/wireless/iwlwifi/iwl-2000.c @@ -348,7 +348,6 @@ static struct iwl_base_params iwl2000_base_params = { .chain_noise_scale = 1000, .wd_timeout = IWL_DEF_WD_TIMEOUT, .max_event_log_size = 512, - .ucode_tracing = true, .shadow_reg_enable = true, }; @@ -368,7 +367,6 @@ static struct iwl_base_params iwl2030_base_params = { .chain_noise_scale = 1000, .wd_timeout = IWL_LONG_WD_TIMEOUT, .max_event_log_size = 512, - .ucode_tracing = true, .shadow_reg_enable = true, }; diff --git a/drivers/net/wireless/iwlwifi/iwl-5000.c b/drivers/net/wireless/iwlwifi/iwl-5000.c index 79dd45c..14b75f1 100644 --- a/drivers/net/wireless/iwlwifi/iwl-5000.c +++ b/drivers/net/wireless/iwlwifi/iwl-5000.c @@ -467,7 +467,6 @@ static struct iwl_base_params iwl5000_base_params = { .chain_noise_scale = 1000, .wd_timeout = IWL_LONG_WD_TIMEOUT, .max_event_log_size = 512, - .ucode_tracing = true, }; static struct iwl_ht_params iwl5000_ht_params = { .ht_greenfield_support = true, diff --git a/drivers/net/wireless/iwlwifi/iwl-6000.c b/drivers/net/wireless/iwlwifi/iwl-6000.c index a35338e..81881aa 100644 --- a/drivers/net/wireless/iwlwifi/iwl-6000.c +++ b/drivers/net/wireless/iwlwifi/iwl-6000.c @@ -437,7 +437,6 @@ static struct iwl_base_params iwl6000_base_params = { .chain_noise_scale = 1000, .wd_timeout = IWL_DEF_WD_TIMEOUT, .max_event_log_size = 512, - .ucode_tracing = true, .shadow_reg_enable = true, }; @@ -456,7 +455,6 @@ static struct iwl_base_params iwl6050_base_params = { .chain_noise_scale = 1500, .wd_timeout = IWL_DEF_WD_TIMEOUT, .max_event_log_size = 1024, - .ucode_tracing = true, .shadow_reg_enable = true, }; static struct iwl_base_params iwl6000_g2_base_params = { @@ -474,7 +472,6 @@ static struct iwl_base_params iwl6000_g2_base_params = { .chain_noise_scale = 1000, .wd_timeout = IWL_LONG_WD_TIMEOUT, .max_event_log_size = 512, - .ucode_tracing = true, .shadow_reg_enable = true, }; diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h index 240abdf..2e8c936 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.h +++ b/drivers/net/wireless/iwlwifi/iwl-core.h @@ -249,7 +249,6 @@ struct iwl_mod_params { * @wd_timeout: TX queues watchdog timeout * @temperature_kelvin: temperature report by uCode in kelvin * @max_event_log_size: size of event log buffer size for ucode event logging - * @ucode_tracing: support ucode continuous tracing * @shadow_reg_enable: HW shadhow register bit */ struct iwl_base_params { @@ -271,7 +270,6 @@ struct iwl_base_params { unsigned int wd_timeout; bool temperature_kelvin; u32 max_event_log_size; - const bool ucode_tracing; const bool shadow_reg_enable; }; /* diff --git a/drivers/net/wireless/iwlwifi/iwl-debugfs.c b/drivers/net/wireless/iwlwifi/iwl-debugfs.c index 897efac..c272204 100644 --- a/drivers/net/wireless/iwlwifi/iwl-debugfs.c +++ b/drivers/net/wireless/iwlwifi/iwl-debugfs.c @@ -1749,8 +1749,7 @@ int iwl_dbgfs_register(struct iwl_priv *priv, const char *name) DEBUGFS_ADD_FILE(sensitivity, dir_debug, S_IRUSR); DEBUGFS_ADD_FILE(chain_noise, dir_debug, S_IRUSR); - if (priv->cfg->base_params->ucode_tracing) - DEBUGFS_ADD_FILE(ucode_tracing, dir_debug, S_IWUSR | S_IRUSR); + DEBUGFS_ADD_FILE(ucode_tracing, dir_debug, S_IWUSR | S_IRUSR); DEBUGFS_ADD_FILE(ucode_bt_stats, dir_debug, S_IRUSR); DEBUGFS_ADD_FILE(reply_tx_error, dir_debug, S_IRUSR); DEBUGFS_ADD_FILE(rxon_flags, dir_debug, S_IWUSR); -- cgit v0.10.2 From f42e7662815647c1a6f73e160abcdf812d3057d2 Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Mon, 18 Apr 2011 09:30:09 -0700 Subject: iwlagn: temperature should be measure for all _agn devices Thermal throttling functions are available for all _agn devices, call the functions directly. Signed-off-by: Wey-Yi Guy diff --git a/drivers/net/wireless/iwlwifi/iwl-1000.c b/drivers/net/wireless/iwlwifi/iwl-1000.c index e784456..946c7dc 100644 --- a/drivers/net/wireless/iwlwifi/iwl-1000.c +++ b/drivers/net/wireless/iwlwifi/iwl-1000.c @@ -214,11 +214,6 @@ static struct iwl_lib_ops iwl1000_lib = { }, .txfifo_flush = iwlagn_txfifo_flush, .dev_txfifo_flush = iwlagn_dev_txfifo_flush, - .tt_ops = { - .lower_power_detection = iwl_tt_is_low_power_state, - .tt_power_mode = iwl_tt_current_power_mode, - .ct_kill_check = iwl_check_for_ct_kill, - } }; static const struct iwl_ops iwl1000_ops = { diff --git a/drivers/net/wireless/iwlwifi/iwl-2000.c b/drivers/net/wireless/iwlwifi/iwl-2000.c index dcd6608..c8bb4a4 100644 --- a/drivers/net/wireless/iwlwifi/iwl-2000.c +++ b/drivers/net/wireless/iwlwifi/iwl-2000.c @@ -298,11 +298,6 @@ static struct iwl_lib_ops iwl2000_lib = { }, .txfifo_flush = iwlagn_txfifo_flush, .dev_txfifo_flush = iwlagn_dev_txfifo_flush, - .tt_ops = { - .lower_power_detection = iwl_tt_is_low_power_state, - .tt_power_mode = iwl_tt_current_power_mode, - .ct_kill_check = iwl_check_for_ct_kill, - } }; static const struct iwl_ops iwl2000_ops = { diff --git a/drivers/net/wireless/iwlwifi/iwl-5000.c b/drivers/net/wireless/iwlwifi/iwl-5000.c index 14b75f1..ced89f6 100644 --- a/drivers/net/wireless/iwlwifi/iwl-5000.c +++ b/drivers/net/wireless/iwlwifi/iwl-5000.c @@ -383,11 +383,6 @@ static struct iwl_lib_ops iwl5000_lib = { }, .txfifo_flush = iwlagn_txfifo_flush, .dev_txfifo_flush = iwlagn_dev_txfifo_flush, - .tt_ops = { - .lower_power_detection = iwl_tt_is_low_power_state, - .tt_power_mode = iwl_tt_current_power_mode, - .ct_kill_check = iwl_check_for_ct_kill, - } }; static struct iwl_lib_ops iwl5150_lib = { @@ -435,11 +430,6 @@ static struct iwl_lib_ops iwl5150_lib = { }, .txfifo_flush = iwlagn_txfifo_flush, .dev_txfifo_flush = iwlagn_dev_txfifo_flush, - .tt_ops = { - .lower_power_detection = iwl_tt_is_low_power_state, - .tt_power_mode = iwl_tt_current_power_mode, - .ct_kill_check = iwl_check_for_ct_kill, - } }; static const struct iwl_ops iwl5000_ops = { diff --git a/drivers/net/wireless/iwlwifi/iwl-6000.c b/drivers/net/wireless/iwlwifi/iwl-6000.c index 81881aa..ed6a0ed0 100644 --- a/drivers/net/wireless/iwlwifi/iwl-6000.c +++ b/drivers/net/wireless/iwlwifi/iwl-6000.c @@ -323,11 +323,6 @@ static struct iwl_lib_ops iwl6000_lib = { }, .txfifo_flush = iwlagn_txfifo_flush, .dev_txfifo_flush = iwlagn_dev_txfifo_flush, - .tt_ops = { - .lower_power_detection = iwl_tt_is_low_power_state, - .tt_power_mode = iwl_tt_current_power_mode, - .ct_kill_check = iwl_check_for_ct_kill, - } }; static struct iwl_lib_ops iwl6030_lib = { @@ -377,11 +372,6 @@ static struct iwl_lib_ops iwl6030_lib = { }, .txfifo_flush = iwlagn_txfifo_flush, .dev_txfifo_flush = iwlagn_dev_txfifo_flush, - .tt_ops = { - .lower_power_detection = iwl_tt_is_low_power_state, - .tt_power_mode = iwl_tt_current_power_mode, - .ct_kill_check = iwl_check_for_ct_kill, - } }; static struct iwl_nic_ops iwl6050_nic_ops = { diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h index 2e8c936..abee507 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.h +++ b/drivers/net/wireless/iwlwifi/iwl-core.h @@ -139,12 +139,6 @@ struct iwl_temp_ops { void (*temperature)(struct iwl_priv *priv); }; -struct iwl_tt_ops { - bool (*lower_power_detection)(struct iwl_priv *priv); - u8 (*tt_power_mode)(struct iwl_priv *priv); - bool (*ct_kill_check)(struct iwl_priv *priv); -}; - struct iwl_lib_ops { /* set hw dependent parameters */ int (*set_hw_params)(struct iwl_priv *priv); @@ -190,9 +184,6 @@ struct iwl_lib_ops { void (*dev_txfifo_flush)(struct iwl_priv *priv, u16 flush_control); struct iwl_debugfs_ops debugfs_ops; - - /* thermal throttling */ - struct iwl_tt_ops tt_ops; }; struct iwl_led_ops { diff --git a/drivers/net/wireless/iwlwifi/iwl-power.c b/drivers/net/wireless/iwlwifi/iwl-power.c index b7cd958..595c930 100644 --- a/drivers/net/wireless/iwlwifi/iwl-power.c +++ b/drivers/net/wireless/iwlwifi/iwl-power.c @@ -357,12 +357,10 @@ static void iwl_power_build_cmd(struct iwl_priv *priv, if (priv->hw->conf.flags & IEEE80211_CONF_IDLE) iwl_static_sleep_cmd(priv, cmd, IWL_POWER_INDEX_5, 20); - else if (priv->cfg->ops->lib->tt_ops.lower_power_detection && - priv->cfg->ops->lib->tt_ops.tt_power_mode && - priv->cfg->ops->lib->tt_ops.lower_power_detection(priv)) { + else if (iwl_tt_is_low_power_state(priv)) { /* in thermal throttling low power state */ iwl_static_sleep_cmd(priv, cmd, - priv->cfg->ops->lib->tt_ops.tt_power_mode(priv), dtimper); + iwl_tt_current_power_mode(priv), dtimper); } else if (!enabled) iwl_power_sleep_cam_cmd(priv, cmd); else if (priv->power_data.debug_sleep_level_override >= 0) diff --git a/drivers/net/wireless/iwlwifi/iwl-tx.c b/drivers/net/wireless/iwlwifi/iwl-tx.c index 1b69507..80c3565 100644 --- a/drivers/net/wireless/iwlwifi/iwl-tx.c +++ b/drivers/net/wireless/iwlwifi/iwl-tx.c @@ -484,10 +484,7 @@ int iwl_enqueue_hcmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd) spin_unlock_irqrestore(&priv->hcmd_lock, flags); IWL_ERR(priv, "No space in command queue\n"); - if (priv->cfg->ops->lib->tt_ops.ct_kill_check) { - is_ct_kill = - priv->cfg->ops->lib->tt_ops.ct_kill_check(priv); - } + is_ct_kill = iwl_check_for_ct_kill(priv); if (!is_ct_kill) { IWL_ERR(priv, "Restarting adapter due to queue full\n"); iwlagn_fw_error(priv, false); -- cgit v0.10.2 From 5cab35e7f4feda1a0bfd4f48b7686391004be9de Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Wed, 6 Apr 2011 15:55:27 -0700 Subject: iwlagn: no 5.2GHz/HT40 support for bgn devices For bgn devices, there were no HT40 channels value in EEPROM Signed-off-by: Wey-Yi Guy diff --git a/drivers/net/wireless/iwlwifi/iwl-1000.c b/drivers/net/wireless/iwlwifi/iwl-1000.c index 946c7dc..a018718 100644 --- a/drivers/net/wireless/iwlwifi/iwl-1000.c +++ b/drivers/net/wireless/iwlwifi/iwl-1000.c @@ -195,7 +195,7 @@ static struct iwl_lib_ops iwl1000_lib = { EEPROM_REG_BAND_4_CHANNELS, EEPROM_REG_BAND_5_CHANNELS, EEPROM_REG_BAND_24_HT40_CHANNELS, - EEPROM_REG_BAND_52_HT40_CHANNELS + EEPROM_REGULATORY_BAND_NO_HT40, }, .acquire_semaphore = iwlcore_eeprom_acquire_semaphore, .release_semaphore = iwlcore_eeprom_release_semaphore, diff --git a/drivers/net/wireless/iwlwifi/iwl-2000.c b/drivers/net/wireless/iwlwifi/iwl-2000.c index c8bb4a4..0bd9b14 100644 --- a/drivers/net/wireless/iwlwifi/iwl-2000.c +++ b/drivers/net/wireless/iwlwifi/iwl-2000.c @@ -278,7 +278,7 @@ static struct iwl_lib_ops iwl2000_lib = { EEPROM_REG_BAND_4_CHANNELS, EEPROM_REG_BAND_5_CHANNELS, EEPROM_6000_REG_BAND_24_HT40_CHANNELS, - EEPROM_REG_BAND_52_HT40_CHANNELS + EEPROM_REGULATORY_BAND_NO_HT40, }, .acquire_semaphore = iwlcore_eeprom_acquire_semaphore, .release_semaphore = iwlcore_eeprom_release_semaphore, -- cgit v0.10.2 From 119ea186cad7643ea82b7290374ebb8e780c35b6 Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Mon, 18 Apr 2011 09:34:06 -0700 Subject: iwlagn: remove un-necessary ieee80211_ops After driver split, no need to use ieee80211_ops, remove it Signed-off-by: Wey-Yi Guy diff --git a/drivers/net/wireless/iwlwifi/iwl-1000.c b/drivers/net/wireless/iwlwifi/iwl-1000.c index a018718..baf8011 100644 --- a/drivers/net/wireless/iwlwifi/iwl-1000.c +++ b/drivers/net/wireless/iwlwifi/iwl-1000.c @@ -220,7 +220,6 @@ static const struct iwl_ops iwl1000_ops = { .lib = &iwl1000_lib, .hcmd = &iwlagn_hcmd, .utils = &iwlagn_hcmd_utils, - .ieee80211_ops = &iwlagn_hw_ops, }; static struct iwl_base_params iwl1000_base_params = { diff --git a/drivers/net/wireless/iwlwifi/iwl-2000.c b/drivers/net/wireless/iwlwifi/iwl-2000.c index 0bd9b14..e76e02c 100644 --- a/drivers/net/wireless/iwlwifi/iwl-2000.c +++ b/drivers/net/wireless/iwlwifi/iwl-2000.c @@ -304,28 +304,24 @@ static const struct iwl_ops iwl2000_ops = { .lib = &iwl2000_lib, .hcmd = &iwlagn_hcmd, .utils = &iwlagn_hcmd_utils, - .ieee80211_ops = &iwlagn_hw_ops, }; static const struct iwl_ops iwl2030_ops = { .lib = &iwl2000_lib, .hcmd = &iwlagn_bt_hcmd, .utils = &iwlagn_hcmd_utils, - .ieee80211_ops = &iwlagn_hw_ops, }; static const struct iwl_ops iwl200_ops = { .lib = &iwl2000_lib, .hcmd = &iwlagn_hcmd, .utils = &iwlagn_hcmd_utils, - .ieee80211_ops = &iwlagn_hw_ops, }; static const struct iwl_ops iwl230_ops = { .lib = &iwl2000_lib, .hcmd = &iwlagn_bt_hcmd, .utils = &iwlagn_hcmd_utils, - .ieee80211_ops = &iwlagn_hw_ops, }; static struct iwl_base_params iwl2000_base_params = { diff --git a/drivers/net/wireless/iwlwifi/iwl-5000.c b/drivers/net/wireless/iwlwifi/iwl-5000.c index ced89f6..655afc1 100644 --- a/drivers/net/wireless/iwlwifi/iwl-5000.c +++ b/drivers/net/wireless/iwlwifi/iwl-5000.c @@ -436,14 +436,12 @@ static const struct iwl_ops iwl5000_ops = { .lib = &iwl5000_lib, .hcmd = &iwlagn_hcmd, .utils = &iwlagn_hcmd_utils, - .ieee80211_ops = &iwlagn_hw_ops, }; static const struct iwl_ops iwl5150_ops = { .lib = &iwl5150_lib, .hcmd = &iwlagn_hcmd, .utils = &iwlagn_hcmd_utils, - .ieee80211_ops = &iwlagn_hw_ops, }; static struct iwl_base_params iwl5000_base_params = { diff --git a/drivers/net/wireless/iwlwifi/iwl-6000.c b/drivers/net/wireless/iwlwifi/iwl-6000.c index ed6a0ed0..905eb57 100644 --- a/drivers/net/wireless/iwlwifi/iwl-6000.c +++ b/drivers/net/wireless/iwlwifi/iwl-6000.c @@ -386,7 +386,6 @@ static const struct iwl_ops iwl6000_ops = { .lib = &iwl6000_lib, .hcmd = &iwlagn_hcmd, .utils = &iwlagn_hcmd_utils, - .ieee80211_ops = &iwlagn_hw_ops, }; static const struct iwl_ops iwl6050_ops = { @@ -394,7 +393,6 @@ static const struct iwl_ops iwl6050_ops = { .hcmd = &iwlagn_hcmd, .utils = &iwlagn_hcmd_utils, .nic = &iwl6050_nic_ops, - .ieee80211_ops = &iwlagn_hw_ops, }; static const struct iwl_ops iwl6150_ops = { @@ -402,14 +400,12 @@ static const struct iwl_ops iwl6150_ops = { .hcmd = &iwlagn_hcmd, .utils = &iwlagn_hcmd_utils, .nic = &iwl6150_nic_ops, - .ieee80211_ops = &iwlagn_hw_ops, }; static const struct iwl_ops iwl6030_ops = { .lib = &iwl6030_lib, .hcmd = &iwlagn_bt_hcmd, .utils = &iwlagn_hcmd_utils, - .ieee80211_ops = &iwlagn_hw_ops, }; static struct iwl_base_params iwl6000_base_params = { diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index 3cfd7eb..cdeb09e 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -3728,6 +3728,28 @@ static const u8 iwlagn_pan_ac_to_queue[] = { 7, 6, 5, 4, }; +/* This function both allocates and initializes hw and priv. */ +static struct ieee80211_hw *iwl_alloc_all(struct iwl_cfg *cfg) +{ + struct iwl_priv *priv; + /* mac80211 allocates memory for this device instance, including + * space for this driver's private structure */ + struct ieee80211_hw *hw; + + hw = ieee80211_alloc_hw(sizeof(struct iwl_priv), &iwlagn_hw_ops); + if (hw == NULL) { + pr_err("%s: Can not allocate network device\n", + cfg->name); + goto out; + } + + priv = hw->priv; + priv->hw = hw; + +out: + return hw; +} + static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) { int err = 0, i; diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index 0e98a87..885167f 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -67,30 +67,6 @@ u32 iwl_debug_level; const u8 iwl_bcast_addr[ETH_ALEN] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; - -/* This function both allocates and initializes hw and priv. */ -struct ieee80211_hw *iwl_alloc_all(struct iwl_cfg *cfg) -{ - struct iwl_priv *priv; - /* mac80211 allocates memory for this device instance, including - * space for this driver's private structure */ - struct ieee80211_hw *hw; - - hw = ieee80211_alloc_hw(sizeof(struct iwl_priv), - cfg->ops->ieee80211_ops); - if (hw == NULL) { - pr_err("%s: Can not allocate network device\n", - cfg->name); - goto out; - } - - priv = hw->priv; - priv->hw = hw; - -out: - return hw; -} - #define MAX_BIT_RATE_40_MHZ 150 /* Mbps */ #define MAX_BIT_RATE_20_MHZ 72 /* Mbps */ static void iwlcore_init_ht_hw_capab(const struct iwl_priv *priv, diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h index abee507..0049790 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.h +++ b/drivers/net/wireless/iwlwifi/iwl-core.h @@ -210,7 +210,6 @@ struct iwl_ops { const struct iwl_hcmd_utils_ops *utils; const struct iwl_nic_ops *nic; const struct iwl_legacy_ops *legacy; - const struct ieee80211_ops *ieee80211_ops; }; struct iwl_mod_params { @@ -364,7 +363,6 @@ struct iwl_cfg { * L i b * ***************************/ -struct ieee80211_hw *iwl_alloc_all(struct iwl_cfg *cfg); int iwl_mac_conf_tx(struct ieee80211_hw *hw, u16 queue, const struct ieee80211_tx_queue_params *params); int iwl_mac_tx_last_beacon(struct ieee80211_hw *hw); -- cgit v0.10.2 From e339807d97bcb4e214c9137bb5bbb2f685054624 Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Fri, 8 Apr 2011 10:21:52 -0700 Subject: iwlagn: remove legacy ops No longer used by _agn devices, remove it Signed-off-by: Wey-Yi Guy diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h index 0049790..99a91bd 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.h +++ b/drivers/net/wireless/iwlwifi/iwl-core.h @@ -195,21 +195,11 @@ struct iwl_nic_ops { void (*additional_nic_config)(struct iwl_priv *priv); }; -struct iwl_legacy_ops { - void (*post_associate)(struct iwl_priv *priv); - void (*config_ap)(struct iwl_priv *priv); - /* station management */ - int (*update_bcast_stations)(struct iwl_priv *priv); - int (*manage_ibss_station)(struct iwl_priv *priv, - struct ieee80211_vif *vif, bool add); -}; - struct iwl_ops { const struct iwl_lib_ops *lib; const struct iwl_hcmd_ops *hcmd; const struct iwl_hcmd_utils_ops *utils; const struct iwl_nic_ops *nic; - const struct iwl_legacy_ops *legacy; }; struct iwl_mod_params { -- cgit v0.10.2 From f212b43c4e4a8f6378c50ce18f3d271983b575a7 Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Mon, 18 Apr 2011 09:36:30 -0700 Subject: iwlagn: remove led_ops No longer use, remove it Signed-off-by: Wey-Yi Guy diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h index 99a91bd..32a990f 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.h +++ b/drivers/net/wireless/iwlwifi/iwl-core.h @@ -186,10 +186,6 @@ struct iwl_lib_ops { struct iwl_debugfs_ops debugfs_ops; }; -struct iwl_led_ops { - int (*cmd)(struct iwl_priv *priv, struct iwl_led_cmd *led_cmd); -}; - /* NIC specific ops */ struct iwl_nic_ops { void (*additional_nic_config)(struct iwl_priv *priv); -- cgit v0.10.2 From 80b4895aa4578e9372d76cd4063f82d0c3994d77 Mon Sep 17 00:00:00 2001 From: Jeff Brown Date: Mon, 18 Apr 2011 10:08:02 -0700 Subject: Input: estimate number of events per packet Calculate a default based on the number of ABS axes, REL axes, and MT slots for the device during input device registration. Signed-off-by: Jeff Brown Reviewed-by: Henrik Rydberg Signed-off-by: Dmitry Torokhov diff --git a/drivers/input/input.c b/drivers/input/input.c index d6e8bd8..ebbceed 100644 --- a/drivers/input/input.c +++ b/drivers/input/input.c @@ -1746,6 +1746,42 @@ void input_set_capability(struct input_dev *dev, unsigned int type, unsigned int } EXPORT_SYMBOL(input_set_capability); +static unsigned int input_estimate_events_per_packet(struct input_dev *dev) +{ + int mt_slots; + int i; + unsigned int events; + + if (dev->mtsize) { + mt_slots = dev->mtsize; + } else if (test_bit(ABS_MT_TRACKING_ID, dev->absbit)) { + mt_slots = dev->absinfo[ABS_MT_TRACKING_ID].maximum - + dev->absinfo[ABS_MT_TRACKING_ID].minimum + 1, + clamp(mt_slots, 2, 32); + } else if (test_bit(ABS_MT_POSITION_X, dev->absbit)) { + mt_slots = 2; + } else { + mt_slots = 0; + } + + events = mt_slots + 1; /* count SYN_MT_REPORT and SYN_REPORT */ + + for (i = 0; i < ABS_CNT; i++) { + if (test_bit(i, dev->absbit)) { + if (input_is_mt_axis(i)) + events += mt_slots; + else + events++; + } + } + + for (i = 0; i < REL_CNT; i++) + if (test_bit(i, dev->relbit)) + events++; + + return events; +} + #define INPUT_CLEANSE_BITMASK(dev, type, bits) \ do { \ if (!test_bit(EV_##type, dev->evbit)) \ @@ -1793,6 +1829,10 @@ int input_register_device(struct input_dev *dev) /* Make sure that bitmasks not mentioned in dev->evbit are clean. */ input_cleanse_bitmasks(dev); + if (!dev->hint_events_per_packet) + dev->hint_events_per_packet = + input_estimate_events_per_packet(dev); + /* * If delay and period are pre-set by the driver, then autorepeating * is handled by the driver itself and we don't do it in input.c. diff --git a/include/linux/input/mt.h b/include/linux/input/mt.h index b3ac06a..318bb82 100644 --- a/include/linux/input/mt.h +++ b/include/linux/input/mt.h @@ -48,6 +48,12 @@ static inline void input_mt_slot(struct input_dev *dev, int slot) input_event(dev, EV_ABS, ABS_MT_SLOT, slot); } +static inline bool input_is_mt_axis(int axis) +{ + return axis == ABS_MT_SLOT || + (axis >= ABS_MT_FIRST && axis <= ABS_MT_LAST); +} + void input_mt_report_slot_state(struct input_dev *dev, unsigned int tool_type, bool active); -- cgit v0.10.2 From c36b58e8a9112017c2bcc322cc98e71241814303 Mon Sep 17 00:00:00 2001 From: Igor Mammedov Date: Mon, 18 Apr 2011 10:17:17 -0700 Subject: Input: xen-kbdfront - fix mouse getting stuck after save/restore Mouse gets "stuck" after restore of PV guest but buttons are in working condition. If driver has been configured for ABS coordinates at start it will get XENKBD_TYPE_POS events and then suddenly after restore it'll start getting XENKBD_TYPE_MOTION events, that will be dropped later and they won't get into user-space. Regression was introduced by hunk 5 and 6 of 5ea5254aa0ad269cfbd2875c973ef25ab5b5e9db ("Input: xen-kbdfront - advertise either absolute or relative coordinates"). Driver on restore should ask xen for request-abs-pointer again if it is available. So restore parts that did it before 5ea5254. Acked-by: Olaf Hering Signed-off-by: Igor Mammedov [v1: Expanded the commit description] Signed-off-by: Konrad Rzeszutek Wilk Signed-off-by: Dmitry Torokhov diff --git a/drivers/input/misc/xen-kbdfront.c b/drivers/input/misc/xen-kbdfront.c index 7077f9b..62bae99 100644 --- a/drivers/input/misc/xen-kbdfront.c +++ b/drivers/input/misc/xen-kbdfront.c @@ -303,7 +303,7 @@ static void xenkbd_backend_changed(struct xenbus_device *dev, enum xenbus_state backend_state) { struct xenkbd_info *info = dev_get_drvdata(&dev->dev); - int val; + int ret, val; switch (backend_state) { case XenbusStateInitialising: @@ -316,6 +316,17 @@ static void xenkbd_backend_changed(struct xenbus_device *dev, case XenbusStateInitWait: InitWait: + ret = xenbus_scanf(XBT_NIL, info->xbdev->otherend, + "feature-abs-pointer", "%d", &val); + if (ret < 0) + val = 0; + if (val) { + ret = xenbus_printf(XBT_NIL, info->xbdev->nodename, + "request-abs-pointer", "1"); + if (ret) + pr_warning("xenkbd: can't request abs-pointer"); + } + xenbus_switch_state(dev, XenbusStateConnected); break; -- cgit v0.10.2 From 4ee63624fd927376b97ead3a8d00728d437bc8e8 Mon Sep 17 00:00:00 2001 From: "J. Bruce Fields" Date: Fri, 15 Apr 2011 18:08:26 -0400 Subject: nfsd4: fix struct file leak on delegation Introduced by acfdf5c383b38f7f4dddae41b97c97f1ae058f49. Cc: stable@kernel.org Reported-by: Gerhard Heift Signed-off-by: J. Bruce Fields diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index aa309aa..c79a983 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c @@ -258,6 +258,7 @@ static void nfs4_put_deleg_lease(struct nfs4_file *fp) if (atomic_dec_and_test(&fp->fi_delegees)) { vfs_setlease(fp->fi_deleg_file, F_UNLCK, &fp->fi_lease); fp->fi_lease = NULL; + fput(fp->fi_deleg_file); fp->fi_deleg_file = NULL; } } -- cgit v0.10.2 From c387aa3a1a910ce00b86f3a85082d24f144db256 Mon Sep 17 00:00:00 2001 From: Joerg Roedel Date: Mon, 18 Apr 2011 15:45:43 +0200 Subject: x86, gart: Don't enforce GART aperture lower-bound by alignment This patch changes the allocation of the GART aperture to enforce only natural alignment instead of aligning it on 512MB. This big alignment was used to force the GART aperture to be over 512MB. This is enforced by using 512MB as the lower-bound address in the allocation range. [ hpa: The actual number 512 MiB needs to be revisited, too. ] Cc: Yinghai Lu Signed-off-by: Joerg Roedel Link: http://lkml.kernel.org/r/1303134346-5805-2-git-send-email-joerg.roedel@amd.com Signed-off-by: H. Peter Anvin diff --git a/arch/x86/kernel/aperture_64.c b/arch/x86/kernel/aperture_64.c index 73fb469..3d2661c 100644 --- a/arch/x86/kernel/aperture_64.c +++ b/arch/x86/kernel/aperture_64.c @@ -30,6 +30,22 @@ #include #include +/* + * Using 512M as goal, in case kexec will load kernel_big + * that will do the on-position decompress, and could overlap with + * with the gart aperture that is used. + * Sequence: + * kernel_small + * ==> kexec (with kdump trigger path or gart still enabled) + * ==> kernel_small (gart area become e820_reserved) + * ==> kexec (with kdump trigger path or gart still enabled) + * ==> kerne_big (uncompressed size will be big than 64M or 128M) + * So don't use 512M below as gart iommu, leave the space for kernel + * code for safe. + */ +#define GART_MIN_ADDR (512ULL << 20) +#define GART_MAX_ADDR (1ULL << 32) + int gart_iommu_aperture; int gart_iommu_aperture_disabled __initdata; int gart_iommu_aperture_allowed __initdata; @@ -70,21 +86,9 @@ static u32 __init allocate_aperture(void) * memory. Unfortunately we cannot move it up because that would * make the IOMMU useless. */ - /* - * using 512M as goal, in case kexec will load kernel_big - * that will do the on position decompress, and could overlap with - * that position with gart that is used. - * sequende: - * kernel_small - * ==> kexec (with kdump trigger path or previous doesn't shutdown gart) - * ==> kernel_small(gart area become e820_reserved) - * ==> kexec (with kdump trigger path or previous doesn't shutdown gart) - * ==> kerne_big (uncompressed size will be big than 64M or 128M) - * so don't use 512M below as gart iommu, leave the space for kernel - * code for safe - */ - addr = memblock_find_in_range(0, 1ULL<<32, aper_size, 512ULL<<20); - if (addr == MEMBLOCK_ERROR || addr + aper_size > 0xffffffff) { + addr = memblock_find_in_range(GART_MIN_ADDR, GART_MAX_ADDR, + aper_size, aper_size); + if (addr == MEMBLOCK_ERROR || addr + aper_size > GART_MAX_ADDR) { printk(KERN_ERR "Cannot allocate aperture memory hole (%lx,%uK)\n", addr, aper_size>>10); -- cgit v0.10.2 From c78193e9c7bcbf25b8237ad0dec82f805c4ea69b Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Mon, 18 Apr 2011 10:35:30 -0700 Subject: next_pidmap: fix overflow condition MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit next_pidmap() just quietly accepted whatever 'last' pid that was passed in, which is not all that safe when one of the users is /proc. Admittedly the proc code should do some sanity checking on the range (and that will be the next commit), but that doesn't mean that the helper functions should just do that pidmap pointer arithmetic without checking the range of its arguments. So clamp 'last' to PID_MAX_LIMIT. The fact that we then do "last+1" doesn't really matter, the for-loop does check against the end of the pidmap array properly (it's only the actual pointer arithmetic overflow case we need to worry about, and going one bit beyond isn't going to overflow). [ Use PID_MAX_LIMIT rather than pid_max as per Eric Biederman ] Reported-by: Tavis Ormandy Analyzed-by: Robert ÅšwiÄ™cki Cc: Eric W. Biederman Cc: Pavel Emelyanov Signed-off-by: Linus Torvalds diff --git a/include/linux/pid.h b/include/linux/pid.h index 31afb7e..cdced84 100644 --- a/include/linux/pid.h +++ b/include/linux/pid.h @@ -117,7 +117,7 @@ extern struct pid *find_vpid(int nr); */ extern struct pid *find_get_pid(int nr); extern struct pid *find_ge_pid(int nr, struct pid_namespace *); -int next_pidmap(struct pid_namespace *pid_ns, int last); +int next_pidmap(struct pid_namespace *pid_ns, unsigned int last); extern struct pid *alloc_pid(struct pid_namespace *ns); extern void free_pid(struct pid *pid); diff --git a/kernel/pid.c b/kernel/pid.c index 02f2212..57a8346 100644 --- a/kernel/pid.c +++ b/kernel/pid.c @@ -217,11 +217,14 @@ static int alloc_pidmap(struct pid_namespace *pid_ns) return -1; } -int next_pidmap(struct pid_namespace *pid_ns, int last) +int next_pidmap(struct pid_namespace *pid_ns, unsigned int last) { int offset; struct pidmap *map, *end; + if (last >= PID_MAX_LIMIT) + return -1; + offset = (last + 1) & BITS_PER_PAGE_MASK; map = &pid_ns->pidmap[(last + 1)/BITS_PER_PAGE]; end = &pid_ns->pidmap[PIDMAP_ENTRIES]; -- cgit v0.10.2 From d8bdc59f215e62098bc5b4256fd9928bf27053a1 Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Mon, 18 Apr 2011 10:36:54 -0700 Subject: proc: do proper range check on readdir offset Rather than pass in some random truncated offset to the pid-related functions, check that the offset is in range up-front. This is just cleanup, the previous commit fixed the real problem. Cc: stable@kernel.org Signed-off-by: Linus Torvalds diff --git a/fs/proc/base.c b/fs/proc/base.c index dd6628d..dfa5327 100644 --- a/fs/proc/base.c +++ b/fs/proc/base.c @@ -3124,11 +3124,16 @@ static int proc_pid_fill_cache(struct file *filp, void *dirent, filldir_t filldi /* for the /proc/ directory itself, after non-process stuff has been done */ int proc_pid_readdir(struct file * filp, void * dirent, filldir_t filldir) { - unsigned int nr = filp->f_pos - FIRST_PROCESS_ENTRY; - struct task_struct *reaper = get_proc_task(filp->f_path.dentry->d_inode); + unsigned int nr; + struct task_struct *reaper; struct tgid_iter iter; struct pid_namespace *ns; + if (filp->f_pos >= PID_MAX_LIMIT + TGID_OFFSET) + goto out_no_task; + nr = filp->f_pos - FIRST_PROCESS_ENTRY; + + reaper = get_proc_task(filp->f_path.dentry->d_inode); if (!reaper) goto out_no_task; -- cgit v0.10.2 From bcb22a94f68cde70e820dc7280d1c731e8e695f7 Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Sun, 3 Apr 2011 22:47:23 -0300 Subject: ARM: mx5/mx53_loco: Fix build warning related to gpio_keys_button structure Fix the following warning: CC arch/arm/mach-mx5/board-mx53_loco.o arch/arm/mach-mx5/board-mx53_loco.c:203: warning: initialization discards qualifiers from pointer target type Signed-off-by: Fabio Estevam Signed-off-by: Sascha Hauer diff --git a/arch/arm/mach-mx5/board-mx53_loco.c b/arch/arm/mach-mx5/board-mx53_loco.c index 10a1bea..6206b11 100644 --- a/arch/arm/mach-mx5/board-mx53_loco.c +++ b/arch/arm/mach-mx5/board-mx53_loco.c @@ -193,7 +193,7 @@ static iomux_v3_cfg_t mx53_loco_pads[] = { .wakeup = wake, \ } -static const struct gpio_keys_button loco_buttons[] __initconst = { +static struct gpio_keys_button loco_buttons[] = { GPIO_BUTTON(MX53_LOCO_POWER, KEY_POWER, 1, "power", 0), GPIO_BUTTON(MX53_LOCO_UI1, KEY_VOLUMEUP, 1, "volume-up", 0), GPIO_BUTTON(MX53_LOCO_UI2, KEY_VOLUMEDOWN, 1, "volume-down", 0), -- cgit v0.10.2 From bd900d4580107c899d43b262fbbd995f11097a43 Mon Sep 17 00:00:00 2001 From: Jens Axboe Date: Mon, 18 Apr 2011 22:06:57 +0200 Subject: block: kill blk_flush_plug_list() export With all drivers and file systems converted, we only have in-core use of this function. So remove the export. Reporteed-by: Christoph Hellwig Signed-off-by: Jens Axboe diff --git a/block/blk-core.c b/block/blk-core.c index 5fa3dd2..580eee5 100644 --- a/block/blk-core.c +++ b/block/blk-core.c @@ -2787,7 +2787,6 @@ void blk_flush_plug_list(struct blk_plug *plug, bool from_schedule) local_irq_restore(flags); } -EXPORT_SYMBOL(blk_flush_plug_list); void blk_finish_plug(struct blk_plug *plug) { -- cgit v0.10.2 From 468f86134ee515234afe5c5b3f39f266c50e61a5 Mon Sep 17 00:00:00 2001 From: Bryan Schumaker Date: Mon, 18 Apr 2011 15:57:32 -0400 Subject: NFSv4.1: Don't update sequence number if rpc_task is not sent If we fail to contact the gss upcall program, then no message will be sent to the server. The client still updated the sequence number, however, and this lead to NFS4ERR_SEQ_MISMATCH for the next several RPC calls. Signed-off-by: Bryan Schumaker Signed-off-by: Trond Myklebust diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index b8e1ac6..e7e2077 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c @@ -444,8 +444,8 @@ static int nfs41_sequence_done(struct rpc_task *task, struct nfs4_sequence_res * if (res->sr_status == 1) res->sr_status = NFS_OK; - /* -ERESTARTSYS can result in skipping nfs41_sequence_setup */ - if (!res->sr_slot) + /* don't increment the sequence number if the task wasn't sent */ + if (!RPC_WAS_SENT(task)) goto out; /* Check the SEQUENCE operation status */ diff --git a/include/linux/sunrpc/sched.h b/include/linux/sunrpc/sched.h index d81db80..3b94f80 100644 --- a/include/linux/sunrpc/sched.h +++ b/include/linux/sunrpc/sched.h @@ -127,6 +127,7 @@ struct rpc_task_setup { #define RPC_TASK_KILLED 0x0100 /* task was killed */ #define RPC_TASK_SOFT 0x0200 /* Use soft timeouts */ #define RPC_TASK_SOFTCONN 0x0400 /* Fail if can't connect */ +#define RPC_TASK_SENT 0x0800 /* message was sent */ #define RPC_IS_ASYNC(t) ((t)->tk_flags & RPC_TASK_ASYNC) #define RPC_IS_SWAPPER(t) ((t)->tk_flags & RPC_TASK_SWAPPER) @@ -134,6 +135,7 @@ struct rpc_task_setup { #define RPC_ASSASSINATED(t) ((t)->tk_flags & RPC_TASK_KILLED) #define RPC_IS_SOFT(t) ((t)->tk_flags & RPC_TASK_SOFT) #define RPC_IS_SOFTCONN(t) ((t)->tk_flags & RPC_TASK_SOFTCONN) +#define RPC_WAS_SENT(t) ((t)->tk_flags & RPC_TASK_SENT) #define RPC_TASK_RUNNING 0 #define RPC_TASK_QUEUED 1 diff --git a/net/sunrpc/xprt.c b/net/sunrpc/xprt.c index 9494c37..ce5eb68 100644 --- a/net/sunrpc/xprt.c +++ b/net/sunrpc/xprt.c @@ -906,6 +906,7 @@ void xprt_transmit(struct rpc_task *task) } dprintk("RPC: %5u xmit complete\n", task->tk_pid); + task->tk_flags |= RPC_TASK_SENT; spin_lock_bh(&xprt->transport_lock); xprt->ops->set_retrans_timeout(task); -- cgit v0.10.2 From fb8a5ba8114491467c4067ec0330e1c3dcc81d10 Mon Sep 17 00:00:00 2001 From: Bryan Schumaker Date: Mon, 18 Apr 2011 16:52:25 -0400 Subject: NFSv4: Handle NFS4ERR_WRONGSEC outside of nfs4_handle_exception() I only want to try other secflavors during an initial mount if NFS4ERR_WRONGSEC is returned. nfs4_handle_exception() could potentially map other errors to EPERM, so we should handle this error specially for correctness. Signed-off-by: Bryan Schumaker Signed-off-by: Trond Myklebust diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index e7e2077..628e35f 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c @@ -2186,9 +2186,14 @@ static int nfs4_lookup_root(struct nfs_server *server, struct nfs_fh *fhandle, struct nfs4_exception exception = { }; int err; do { - err = nfs4_handle_exception(server, - _nfs4_lookup_root(server, fhandle, info), - &exception); + err = _nfs4_lookup_root(server, fhandle, info); + switch (err) { + case 0: + case -NFS4ERR_WRONGSEC: + break; + default: + err = nfs4_handle_exception(server, err, &exception); + } } while (exception.retry); return err; } @@ -2221,10 +2226,19 @@ static int nfs4_find_root_sec(struct nfs_server *server, struct nfs_fh *fhandle, for (i = 0; i < len; i++) { status = nfs4_lookup_root_sec(server, fhandle, info, flav_array[i]); - if (status == -EPERM || status == -EACCES) + if (status == -NFS4ERR_WRONGSEC || status == -EACCES) continue; break; } + /* + * -EACCESS could mean that the user doesn't have correct permissions + * to access the mount. It could also mean that we tried to mount + * with a gss auth flavor, but rpc.gssd isn't running. Either way, + * existing mount programs don't handle -EACCES very well so it should + * be mapped to -EPERM instead. + */ + if (status == -EACCES) + status = -EPERM; return status; } @@ -2235,7 +2249,11 @@ static int nfs4_proc_get_root(struct nfs_server *server, struct nfs_fh *fhandle, struct nfs_fsinfo *info) { int status = nfs4_lookup_root(server, fhandle, info); - if ((status == -EPERM) && !(server->flags & NFS_MOUNT_SECFLAVOUR)) + if ((status == -NFS4ERR_WRONGSEC) && !(server->flags & NFS_MOUNT_SECFLAVOUR)) + /* + * A status of -NFS4ERR_WRONGSEC will be mapped to -EPERM + * by nfs4_map_errors() as this function exits. + */ status = nfs4_find_root_sec(server, fhandle, info); if (status == 0) status = nfs4_server_capabilities(server, fhandle); -- cgit v0.10.2 From 56d37f17165084e10f425e66f0bd964f06e8bd23 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Mon, 18 Apr 2011 01:04:37 +0000 Subject: net: dm9000: Fix build Commit c88fcb (net: dm9000: convert to hw_features) broke the build of the dm9000 driver since it merged functions which use different names for the board info structure used for I/O operations without updating all the references to use the same name. Fix that. Signed-off-by: Mark Brown Signed-off-by: David S. Miller diff --git a/drivers/net/dm9000.c b/drivers/net/dm9000.c index f7bdebb..fbaff35 100644 --- a/drivers/net/dm9000.c +++ b/drivers/net/dm9000.c @@ -768,7 +768,7 @@ dm9000_init_dm9000(struct net_device *dev) /* Checksum mode */ if (dev->hw_features & NETIF_F_RXCSUM) - iow(dm, DM9000_RCSR, + iow(db, DM9000_RCSR, (dev->features & NETIF_F_RXCSUM) ? RCSR_CSUM : 0); iow(db, DM9000_GPCR, GPCR_GEP_CNTL); /* Let GPIO0 output */ -- cgit v0.10.2 From 2ca6f62f595c01f689b269db6736de5544da7667 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Mon, 18 Apr 2011 23:58:59 +0200 Subject: PM: Fix error code paths executed after failing syscore_suspend() If syscore_suspend() fails in suspend_enter(), create_image() or resume_target_kernel(), it is necessary to call sysdev_resume(), because sysdev_suspend() has been called already and succeeded and we are going to abort the transition. Signed-off-by: Rafael J. Wysocki Acked-by: Greg Kroah-Hartman diff --git a/kernel/power/hibernate.c b/kernel/power/hibernate.c index aeabd26..50aae66 100644 --- a/kernel/power/hibernate.c +++ b/kernel/power/hibernate.c @@ -273,8 +273,11 @@ static int create_image(int platform_mode) local_irq_disable(); error = sysdev_suspend(PMSG_FREEZE); - if (!error) + if (!error) { error = syscore_suspend(); + if (error) + sysdev_resume(); + } if (error) { printk(KERN_ERR "PM: Some system devices failed to power down, " "aborting hibernation\n"); @@ -407,8 +410,11 @@ static int resume_target_kernel(bool platform_mode) local_irq_disable(); error = sysdev_suspend(PMSG_QUIESCE); - if (!error) + if (!error) { error = syscore_suspend(); + if (error) + sysdev_resume(); + } if (error) goto Enable_irqs; diff --git a/kernel/power/suspend.c b/kernel/power/suspend.c index 2814c32..8935369 100644 --- a/kernel/power/suspend.c +++ b/kernel/power/suspend.c @@ -164,8 +164,11 @@ static int suspend_enter(suspend_state_t state) BUG_ON(!irqs_disabled()); error = sysdev_suspend(PMSG_SUSPEND); - if (!error) + if (!error) { error = syscore_suspend(); + if (error) + sysdev_resume(); + } if (!error) { if (!(suspend_test(TEST_CORE) || pm_wakeup_pending())) { error = suspend_ops->enter(state); -- cgit v0.10.2 From 7a74aeb022b34a8fa8ef00545e66cf0568b5ddf6 Mon Sep 17 00:00:00 2001 From: Ville Tervo Date: Thu, 7 Apr 2011 14:59:50 +0300 Subject: Bluetooth: Fix refcount balance for hci connection hci_io_capa_reply_evt() holds reference for hciconnection. It's useless since hci_io_capa_request_evt()/hci_simple_pair_complete_evt() already protects the connection. In addition it leaves connection open after failed SSP pairing. Signed-off-by: Ville Tervo Signed-off-by: Gustavo F. Padovan diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index cebe7588..b257015 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -2387,8 +2387,6 @@ static inline void hci_io_capa_reply_evt(struct hci_dev *hdev, struct sk_buff *s if (!conn) goto unlock; - hci_conn_hold(conn); - conn->remote_cap = ev->capability; conn->remote_oob = ev->oob_data; conn->remote_auth = ev->authentication; -- cgit v0.10.2 From b79f44c16a4e2181b1d6423afe746745d5e949ff Mon Sep 17 00:00:00 2001 From: Vinicius Costa Gomes Date: Mon, 11 Apr 2011 18:46:55 -0300 Subject: Bluetooth: Fix keeping the command timer running In the teardown path the reset command is sent to the controller, this event causes the command timer to be reactivated. So the timer is removed in two situations, when the adapter isn't marked as UP and when we know that some command has been sent. Reported-by: Keith Packard Signed-off-by: Vinicius Costa Gomes Signed-off-by: Gustavo F. Padovan diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 2216620..e7dced9 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -587,10 +587,8 @@ static int hci_dev_do_close(struct hci_dev *hdev) hci_req_cancel(hdev, ENODEV); hci_req_lock(hdev); - /* Stop timer, it might be running */ - del_timer_sync(&hdev->cmd_timer); - if (!test_and_clear_bit(HCI_UP, &hdev->flags)) { + del_timer_sync(&hdev->cmd_timer); hci_req_unlock(hdev); return 0; } @@ -629,6 +627,7 @@ static int hci_dev_do_close(struct hci_dev *hdev) /* Drop last sent command */ if (hdev->sent_cmd) { + del_timer_sync(&hdev->cmd_timer); kfree_skb(hdev->sent_cmd); hdev->sent_cmd = NULL; } -- cgit v0.10.2 From f21ca5fff6e548833fa5ee8867239a8378623150 Mon Sep 17 00:00:00 2001 From: Luiz Augusto von Dentz Date: Fri, 8 Apr 2011 17:10:41 +0300 Subject: Bluetooth: fix shutdown on SCO sockets shutdown should wait for SCO link to be properly disconnected before detroying the socket, otherwise an application using the socket may assume link is properly disconnected before it really happens which can be a problem when e.g synchronizing profile switch. Signed-off-by: Luiz Augusto von Dentz Signed-off-by: Gustavo F. Padovan diff --git a/net/bluetooth/sco.c b/net/bluetooth/sco.c index 42fdffd..94954c7 100644 --- a/net/bluetooth/sco.c +++ b/net/bluetooth/sco.c @@ -369,6 +369,15 @@ static void __sco_sock_close(struct sock *sk) case BT_CONNECTED: case BT_CONFIG: + if (sco_pi(sk)->conn) { + sk->sk_state = BT_DISCONN; + sco_sock_set_timer(sk, SCO_DISCONN_TIMEOUT); + hci_conn_put(sco_pi(sk)->conn->hcon); + sco_pi(sk)->conn = NULL; + } else + sco_chan_del(sk, ECONNRESET); + break; + case BT_CONNECT: case BT_DISCONN: sco_chan_del(sk, ECONNRESET); -- cgit v0.10.2 From a429b51930e64dd355840c37251a563000d7c10b Mon Sep 17 00:00:00 2001 From: Ruiyi Zhang Date: Mon, 18 Apr 2011 11:04:30 +0800 Subject: Bluetooth: Only keeping SAR bits when retransmitting one frame. When retrasmitting one frame, only SAR bits in control field should be kept. Signed-off-by: Ruiyi Zhang Signed-off-by: Gustavo F. Padovan diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index ca27f3a..2c8dd44 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -1051,6 +1051,7 @@ static void l2cap_retransmit_one_frame(struct sock *sk, u8 tx_seq) tx_skb = skb_clone(skb, GFP_ATOMIC); bt_cb(skb)->retries++; control = get_unaligned_le16(tx_skb->data + L2CAP_HDR_SIZE); + control &= L2CAP_CTRL_SAR; if (pi->conn_state & L2CAP_CONN_SEND_FBIT) { control |= L2CAP_CTRL_FINAL; -- cgit v0.10.2 From b1e7734f024c9ce4393016a97c8d821e1f18d9b4 Mon Sep 17 00:00:00 2001 From: "H. Peter Anvin" Date: Mon, 18 Apr 2011 15:18:02 -0700 Subject: x86, percpu: Use ASM_NOP4 instead of hardcoding P6_NOP4 For use in assembly constants, use the ASM_NOP* defines. Signed-off-by: H. Peter Anvin Cc: Christoph Lameter Cc: Tejun Heo Link: http://lkml.kernel.org/r/1303166160-10315-2-git-send-email-hpa@linux.intel.com diff --git a/arch/x86/include/asm/percpu.h b/arch/x86/include/asm/percpu.h index d475b43..751e7f3 100644 --- a/arch/x86/include/asm/percpu.h +++ b/arch/x86/include/asm/percpu.h @@ -517,7 +517,7 @@ do { \ typeof(o2) __o2 = o2; \ typeof(o2) __n2 = n2; \ typeof(o2) __dummy; \ - alternative_io("call this_cpu_cmpxchg16b_emu\n\t" P6_NOP4, \ + alternative_io("call this_cpu_cmpxchg16b_emu\n\t" ASM_NOP4, \ "cmpxchg16b " __percpu_prefix "(%%rsi)\n\tsetz %0\n\t", \ X86_FEATURE_CX16, \ ASM_OUTPUT2("=a"(__ret), "=d"(__dummy)), \ -- cgit v0.10.2 From dc326fca2b640fc41aed7c015d0f456935a66255 Mon Sep 17 00:00:00 2001 From: "H. Peter Anvin" Date: Mon, 18 Apr 2011 15:19:51 -0700 Subject: x86, cpu: Clean up and unify the NOP selection infrastructure Clean up and unify the NOP selection infrastructure: - Make the atomic 5-byte NOP a part of the selection system. - Pick NOPs once during early boot and then be done with it. Signed-off-by: H. Peter Anvin Cc: Tejun Heo Cc: Steven Rostedt Cc: Frederic Weisbecker Cc: Jason Baron Link: http://lkml.kernel.org/r/1303166160-10315-3-git-send-email-hpa@linux.intel.com diff --git a/arch/x86/include/asm/alternative.h b/arch/x86/include/asm/alternative.h index 13009d1..7da1682 100644 --- a/arch/x86/include/asm/alternative.h +++ b/arch/x86/include/asm/alternative.h @@ -191,12 +191,4 @@ extern void *text_poke(void *addr, const void *opcode, size_t len); extern void *text_poke_smp(void *addr, const void *opcode, size_t len); extern void text_poke_smp_batch(struct text_poke_param *params, int n); -#if defined(CONFIG_DYNAMIC_FTRACE) || defined(HAVE_JUMP_LABEL) -#define IDEAL_NOP_SIZE_5 5 -extern unsigned char ideal_nop5[IDEAL_NOP_SIZE_5]; -extern void arch_init_ideal_nop5(void); -#else -static inline void arch_init_ideal_nop5(void) {} -#endif - #endif /* _ASM_X86_ALTERNATIVE_H */ diff --git a/arch/x86/include/asm/nops.h b/arch/x86/include/asm/nops.h index af78849..405b403 100644 --- a/arch/x86/include/asm/nops.h +++ b/arch/x86/include/asm/nops.h @@ -1,7 +1,13 @@ #ifndef _ASM_X86_NOPS_H #define _ASM_X86_NOPS_H -/* Define nops for use with alternative() */ +/* + * Define nops for use with alternative() and for tracing. + * + * *_NOP5_ATOMIC must be a single instruction. + */ + +#define NOP_DS_PREFIX 0x3e /* generic versions from gas 1: nop @@ -13,14 +19,15 @@ 6: leal 0x00000000(%esi),%esi 7: leal 0x00000000(,%esi,1),%esi */ -#define GENERIC_NOP1 ".byte 0x90\n" -#define GENERIC_NOP2 ".byte 0x89,0xf6\n" -#define GENERIC_NOP3 ".byte 0x8d,0x76,0x00\n" -#define GENERIC_NOP4 ".byte 0x8d,0x74,0x26,0x00\n" -#define GENERIC_NOP5 GENERIC_NOP1 GENERIC_NOP4 -#define GENERIC_NOP6 ".byte 0x8d,0xb6,0x00,0x00,0x00,0x00\n" -#define GENERIC_NOP7 ".byte 0x8d,0xb4,0x26,0x00,0x00,0x00,0x00\n" -#define GENERIC_NOP8 GENERIC_NOP1 GENERIC_NOP7 +#define GENERIC_NOP1 0x90 +#define GENERIC_NOP2 0x89,0xf6 +#define GENERIC_NOP3 0x8d,0x76,0x00 +#define GENERIC_NOP4 0x8d,0x74,0x26,0x00 +#define GENERIC_NOP5 GENERIC_NOP1,GENERIC_NOP4 +#define GENERIC_NOP6 0x8d,0xb6,0x00,0x00,0x00,0x00 +#define GENERIC_NOP7 0x8d,0xb4,0x26,0x00,0x00,0x00,0x00 +#define GENERIC_NOP8 GENERIC_NOP1,GENERIC_NOP7 +#define GENERIC_NOP5_ATOMIC NOP_DS_PREFIX,GENERIC_NOP4 /* Opteron 64bit nops 1: nop @@ -29,13 +36,14 @@ 4: osp osp osp nop */ #define K8_NOP1 GENERIC_NOP1 -#define K8_NOP2 ".byte 0x66,0x90\n" -#define K8_NOP3 ".byte 0x66,0x66,0x90\n" -#define K8_NOP4 ".byte 0x66,0x66,0x66,0x90\n" -#define K8_NOP5 K8_NOP3 K8_NOP2 -#define K8_NOP6 K8_NOP3 K8_NOP3 -#define K8_NOP7 K8_NOP4 K8_NOP3 -#define K8_NOP8 K8_NOP4 K8_NOP4 +#define K8_NOP2 0x66,K8_NOP1 +#define K8_NOP3 0x66,K8_NOP2 +#define K8_NOP4 0x66,K8_NOP3 +#define K8_NOP5 K8_NOP3,K8_NOP2 +#define K8_NOP6 K8_NOP3,K8_NOP3 +#define K8_NOP7 K8_NOP4,K8_NOP3 +#define K8_NOP8 K8_NOP4,K8_NOP4 +#define K8_NOP5_ATOMIC 0x66,K8_NOP4 /* K7 nops uses eax dependencies (arbitrary choice) @@ -47,13 +55,14 @@ 7: leal 0x00000000(,%eax,1),%eax */ #define K7_NOP1 GENERIC_NOP1 -#define K7_NOP2 ".byte 0x8b,0xc0\n" -#define K7_NOP3 ".byte 0x8d,0x04,0x20\n" -#define K7_NOP4 ".byte 0x8d,0x44,0x20,0x00\n" -#define K7_NOP5 K7_NOP4 ASM_NOP1 -#define K7_NOP6 ".byte 0x8d,0x80,0,0,0,0\n" -#define K7_NOP7 ".byte 0x8D,0x04,0x05,0,0,0,0\n" -#define K7_NOP8 K7_NOP7 ASM_NOP1 +#define K7_NOP2 0x8b,0xc0 +#define K7_NOP3 0x8d,0x04,0x20 +#define K7_NOP4 0x8d,0x44,0x20,0x00 +#define K7_NOP5 K7_NOP4,K7_NOP1 +#define K7_NOP6 0x8d,0x80,0,0,0,0 +#define K7_NOP7 0x8D,0x04,0x05,0,0,0,0 +#define K7_NOP8 K7_NOP7,K7_NOP1 +#define K7_NOP5_ATOMIC NOP_DS_PREFIX,K7_NOP4 /* P6 nops uses eax dependencies (Intel-recommended choice) @@ -69,52 +78,65 @@ There is kernel code that depends on this. */ #define P6_NOP1 GENERIC_NOP1 -#define P6_NOP2 ".byte 0x66,0x90\n" -#define P6_NOP3 ".byte 0x0f,0x1f,0x00\n" -#define P6_NOP4 ".byte 0x0f,0x1f,0x40,0\n" -#define P6_NOP5 ".byte 0x0f,0x1f,0x44,0x00,0\n" -#define P6_NOP6 ".byte 0x66,0x0f,0x1f,0x44,0x00,0\n" -#define P6_NOP7 ".byte 0x0f,0x1f,0x80,0,0,0,0\n" -#define P6_NOP8 ".byte 0x0f,0x1f,0x84,0x00,0,0,0,0\n" +#define P6_NOP2 0x66,0x90 +#define P6_NOP3 0x0f,0x1f,0x00 +#define P6_NOP4 0x0f,0x1f,0x40,0 +#define P6_NOP5 0x0f,0x1f,0x44,0x00,0 +#define P6_NOP6 0x66,0x0f,0x1f,0x44,0x00,0 +#define P6_NOP7 0x0f,0x1f,0x80,0,0,0,0 +#define P6_NOP8 0x0f,0x1f,0x84,0x00,0,0,0,0 +#define P6_NOP5_ATOMIC P6_NOP5 + +#define _ASM_MK_NOP(x) ".byte " __stringify(x) "\n" #if defined(CONFIG_MK7) -#define ASM_NOP1 K7_NOP1 -#define ASM_NOP2 K7_NOP2 -#define ASM_NOP3 K7_NOP3 -#define ASM_NOP4 K7_NOP4 -#define ASM_NOP5 K7_NOP5 -#define ASM_NOP6 K7_NOP6 -#define ASM_NOP7 K7_NOP7 -#define ASM_NOP8 K7_NOP8 +#define ASM_NOP1 _ASM_MK_NOP(K7_NOP1) +#define ASM_NOP2 _ASM_MK_NOP(K7_NOP2) +#define ASM_NOP3 _ASM_MK_NOP(K7_NOP3) +#define ASM_NOP4 _ASM_MK_NOP(K7_NOP4) +#define ASM_NOP5 _ASM_MK_NOP(K7_NOP5) +#define ASM_NOP6 _ASM_MK_NOP(K7_NOP6) +#define ASM_NOP7 _ASM_MK_NOP(K7_NOP7) +#define ASM_NOP8 _ASM_MK_NOP(K7_NOP8) +#define ASM_NOP5_ATOMIC _ASM_MK_NOP(K7_NOP5_ATOMIC) #elif defined(CONFIG_X86_P6_NOP) -#define ASM_NOP1 P6_NOP1 -#define ASM_NOP2 P6_NOP2 -#define ASM_NOP3 P6_NOP3 -#define ASM_NOP4 P6_NOP4 -#define ASM_NOP5 P6_NOP5 -#define ASM_NOP6 P6_NOP6 -#define ASM_NOP7 P6_NOP7 -#define ASM_NOP8 P6_NOP8 +#define ASM_NOP1 _ASM_MK_NOP(P6_NOP1) +#define ASM_NOP2 _ASM_MK_NOP(P6_NOP2) +#define ASM_NOP3 _ASM_MK_NOP(P6_NOP3) +#define ASM_NOP4 _ASM_MK_NOP(P6_NOP4) +#define ASM_NOP5 _ASM_MK_NOP(P6_NOP5) +#define ASM_NOP6 _ASM_MK_NOP(P6_NOP6) +#define ASM_NOP7 _ASM_MK_NOP(P6_NOP7) +#define ASM_NOP8 _ASM_MK_NOP(P6_NOP8) +#define ASM_NOP5_ATOMIC _ASM_MK_NOP(P6_NOP5_ATOMIC) #elif defined(CONFIG_X86_64) -#define ASM_NOP1 K8_NOP1 -#define ASM_NOP2 K8_NOP2 -#define ASM_NOP3 K8_NOP3 -#define ASM_NOP4 K8_NOP4 -#define ASM_NOP5 K8_NOP5 -#define ASM_NOP6 K8_NOP6 -#define ASM_NOP7 K8_NOP7 -#define ASM_NOP8 K8_NOP8 +#define ASM_NOP1 _ASM_MK_NOP(K8_NOP1) +#define ASM_NOP2 _ASM_MK_NOP(K8_NOP2) +#define ASM_NOP3 _ASM_MK_NOP(K8_NOP3) +#define ASM_NOP4 _ASM_MK_NOP(K8_NOP4) +#define ASM_NOP5 _ASM_MK_NOP(K8_NOP5) +#define ASM_NOP6 _ASM_MK_NOP(K8_NOP6) +#define ASM_NOP7 _ASM_MK_NOP(K8_NOP7) +#define ASM_NOP8 _ASM_MK_NOP(K8_NOP8) +#define ASM_NOP5_ATOMIC _ASM_MK_NOP(K8_NOP5_ATOMIC) #else -#define ASM_NOP1 GENERIC_NOP1 -#define ASM_NOP2 GENERIC_NOP2 -#define ASM_NOP3 GENERIC_NOP3 -#define ASM_NOP4 GENERIC_NOP4 -#define ASM_NOP5 GENERIC_NOP5 -#define ASM_NOP6 GENERIC_NOP6 -#define ASM_NOP7 GENERIC_NOP7 -#define ASM_NOP8 GENERIC_NOP8 +#define ASM_NOP1 _ASM_MK_NOP(GENERIC_NOP1) +#define ASM_NOP2 _ASM_MK_NOP(GENERIC_NOP2) +#define ASM_NOP3 _ASM_MK_NOP(GENERIC_NOP3) +#define ASM_NOP4 _ASM_MK_NOP(GENERIC_NOP4) +#define ASM_NOP5 _ASM_MK_NOP(GENERIC_NOP5) +#define ASM_NOP6 _ASM_MK_NOP(GENERIC_NOP6) +#define ASM_NOP7 _ASM_MK_NOP(GENERIC_NOP7) +#define ASM_NOP8 _ASM_MK_NOP(GENERIC_NOP8) +#define ASM_NOP5_ATOMIC _ASM_MK_NOP(GENERIC_NOP5_ATOMIC) #endif #define ASM_NOP_MAX 8 +#define NOP_ATOMIC5 (ASM_NOP_MAX+1) /* Entry for the 5-byte atomic NOP */ + +#ifndef __ASSEMBLY__ +extern const unsigned char * const *ideal_nops; +extern void arch_init_ideal_nops(void); +#endif #endif /* _ASM_X86_NOPS_H */ diff --git a/arch/x86/kernel/alternative.c b/arch/x86/kernel/alternative.c index 4a23467..846f61e 100644 --- a/arch/x86/kernel/alternative.c +++ b/arch/x86/kernel/alternative.c @@ -67,17 +67,30 @@ __setup("noreplace-paravirt", setup_noreplace_paravirt); #define DPRINTK(fmt, args...) if (debug_alternative) \ printk(KERN_DEBUG fmt, args) +/* + * Each GENERIC_NOPX is of X bytes, and defined as an array of bytes + * that correspond to that nop. Getting from one nop to the next, we + * add to the array the offset that is equal to the sum of all sizes of + * nops preceding the one we are after. + * + * Note: The GENERIC_NOP5_ATOMIC is at the end, as it breaks the + * nice symmetry of sizes of the previous nops. + */ #if defined(GENERIC_NOP1) && !defined(CONFIG_X86_64) -/* Use inline assembly to define this because the nops are defined - as inline assembly strings in the include files and we cannot - get them easily into strings. */ -asm("\t" __stringify(__INITRODATA_OR_MODULE) "\nintelnops: " - GENERIC_NOP1 GENERIC_NOP2 GENERIC_NOP3 GENERIC_NOP4 GENERIC_NOP5 GENERIC_NOP6 - GENERIC_NOP7 GENERIC_NOP8 - "\t.previous"); -extern const unsigned char intelnops[]; -static const unsigned char *const __initconst_or_module -intel_nops[ASM_NOP_MAX+1] = { +static const unsigned char intelnops[] = +{ + GENERIC_NOP1, + GENERIC_NOP2, + GENERIC_NOP3, + GENERIC_NOP4, + GENERIC_NOP5, + GENERIC_NOP6, + GENERIC_NOP7, + GENERIC_NOP8, + GENERIC_NOP5_ATOMIC +}; +static const unsigned char * const intel_nops[ASM_NOP_MAX+2] = +{ NULL, intelnops, intelnops + 1, @@ -87,17 +100,25 @@ intel_nops[ASM_NOP_MAX+1] = { intelnops + 1 + 2 + 3 + 4 + 5, intelnops + 1 + 2 + 3 + 4 + 5 + 6, intelnops + 1 + 2 + 3 + 4 + 5 + 6 + 7, + intelnops + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8, }; #endif #ifdef K8_NOP1 -asm("\t" __stringify(__INITRODATA_OR_MODULE) "\nk8nops: " - K8_NOP1 K8_NOP2 K8_NOP3 K8_NOP4 K8_NOP5 K8_NOP6 - K8_NOP7 K8_NOP8 - "\t.previous"); -extern const unsigned char k8nops[]; -static const unsigned char *const __initconst_or_module -k8_nops[ASM_NOP_MAX+1] = { +static const unsigned char k8nops[] = +{ + K8_NOP1, + K8_NOP2, + K8_NOP3, + K8_NOP4, + K8_NOP5, + K8_NOP6, + K8_NOP7, + K8_NOP8, + K8_NOP5_ATOMIC +}; +static const unsigned char * const k8_nops[ASM_NOP_MAX+2] = +{ NULL, k8nops, k8nops + 1, @@ -107,17 +128,25 @@ k8_nops[ASM_NOP_MAX+1] = { k8nops + 1 + 2 + 3 + 4 + 5, k8nops + 1 + 2 + 3 + 4 + 5 + 6, k8nops + 1 + 2 + 3 + 4 + 5 + 6 + 7, + k8nops + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8, }; #endif #if defined(K7_NOP1) && !defined(CONFIG_X86_64) -asm("\t" __stringify(__INITRODATA_OR_MODULE) "\nk7nops: " - K7_NOP1 K7_NOP2 K7_NOP3 K7_NOP4 K7_NOP5 K7_NOP6 - K7_NOP7 K7_NOP8 - "\t.previous"); -extern const unsigned char k7nops[]; -static const unsigned char *const __initconst_or_module -k7_nops[ASM_NOP_MAX+1] = { +static const unsigned char k7nops[] = +{ + K7_NOP1, + K7_NOP2, + K7_NOP3, + K7_NOP4, + K7_NOP5, + K7_NOP6, + K7_NOP7, + K7_NOP8, + K7_NOP5_ATOMIC +}; +static const unsigned char * const k7_nops[ASM_NOP_MAX+2] = +{ NULL, k7nops, k7nops + 1, @@ -127,17 +156,25 @@ k7_nops[ASM_NOP_MAX+1] = { k7nops + 1 + 2 + 3 + 4 + 5, k7nops + 1 + 2 + 3 + 4 + 5 + 6, k7nops + 1 + 2 + 3 + 4 + 5 + 6 + 7, + k7nops + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8, }; #endif #ifdef P6_NOP1 -asm("\t" __stringify(__INITRODATA_OR_MODULE) "\np6nops: " - P6_NOP1 P6_NOP2 P6_NOP3 P6_NOP4 P6_NOP5 P6_NOP6 - P6_NOP7 P6_NOP8 - "\t.previous"); -extern const unsigned char p6nops[]; -static const unsigned char *const __initconst_or_module -p6_nops[ASM_NOP_MAX+1] = { +static const unsigned char __initconst_or_module p6nops[] = +{ + P6_NOP1, + P6_NOP2, + P6_NOP3, + P6_NOP4, + P6_NOP5, + P6_NOP6, + P6_NOP7, + P6_NOP8, + P6_NOP5_ATOMIC +}; +static const unsigned char * const p6_nops[ASM_NOP_MAX+2] = +{ NULL, p6nops, p6nops + 1, @@ -147,47 +184,53 @@ p6_nops[ASM_NOP_MAX+1] = { p6nops + 1 + 2 + 3 + 4 + 5, p6nops + 1 + 2 + 3 + 4 + 5 + 6, p6nops + 1 + 2 + 3 + 4 + 5 + 6 + 7, + p6nops + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8, }; #endif +/* Initialize these to a safe default */ #ifdef CONFIG_X86_64 +const unsigned char * const *ideal_nops = p6_nops; +#else +const unsigned char * const *ideal_nops = intel_nops; +#endif -extern char __vsyscall_0; -static const unsigned char *const *__init_or_module find_nop_table(void) +void __init arch_init_ideal_nops(void) { - if (boot_cpu_data.x86_vendor == X86_VENDOR_INTEL && - boot_cpu_has(X86_FEATURE_NOPL)) - return p6_nops; - else - return k8_nops; -} - -#else /* CONFIG_X86_64 */ + switch (boot_cpu_data.x86_vendor) { + case X86_VENDOR_INTEL: + if (boot_cpu_has(X86_FEATURE_NOPL)) { + ideal_nops = p6_nops; + } else { +#ifdef CONFIG_X86_64 + ideal_nops = k8_nops; +#else + ideal_nops = intel_nops; +#endif + } -static const unsigned char *const *__init_or_module find_nop_table(void) -{ - if (boot_cpu_has(X86_FEATURE_K8)) - return k8_nops; - else if (boot_cpu_has(X86_FEATURE_K7)) - return k7_nops; - else if (boot_cpu_has(X86_FEATURE_NOPL)) - return p6_nops; - else - return intel_nops; + default: +#ifdef CONFIG_X86_64 + ideal_nops = k8_nops; +#else + if (boot_cpu_has(X86_FEATURE_K8)) + ideal_nops = k8_nops; + else if (boot_cpu_has(X86_FEATURE_K7)) + ideal_nops = k7_nops; + else + ideal_nops = intel_nops; +#endif + } } -#endif /* CONFIG_X86_64 */ - /* Use this to add nops to a buffer, then text_poke the whole buffer. */ static void __init_or_module add_nops(void *insns, unsigned int len) { - const unsigned char *const *noptable = find_nop_table(); - while (len > 0) { unsigned int noplen = len; if (noplen > ASM_NOP_MAX) noplen = ASM_NOP_MAX; - memcpy(insns, noptable[noplen], noplen); + memcpy(insns, ideal_nops[noplen], noplen); insns += noplen; len -= noplen; } @@ -195,6 +238,7 @@ static void __init_or_module add_nops(void *insns, unsigned int len) extern struct alt_instr __alt_instructions[], __alt_instructions_end[]; extern s32 __smp_locks[], __smp_locks_end[]; +extern char __vsyscall_0; void *text_poke_early(void *addr, const void *opcode, size_t len); /* Replace instructions with better alternatives for this CPU type. @@ -678,29 +722,3 @@ void __kprobes text_poke_smp_batch(struct text_poke_param *params, int n) wrote_text = 0; __stop_machine(stop_machine_text_poke, (void *)&tpp, NULL); } - -#if defined(CONFIG_DYNAMIC_FTRACE) || defined(HAVE_JUMP_LABEL) - -#ifdef CONFIG_X86_64 -unsigned char ideal_nop5[5] = { 0x66, 0x66, 0x66, 0x66, 0x90 }; -#else -unsigned char ideal_nop5[5] = { 0x3e, 0x8d, 0x74, 0x26, 0x00 }; -#endif - -void __init arch_init_ideal_nop5(void) -{ - /* - * There is no good nop for all x86 archs. This selection - * algorithm should be unified with the one in find_nop_table(), - * but this should be good enough for now. - * - * For cases other than the ones below, use the safe (as in - * always functional) defaults above. - */ -#ifdef CONFIG_X86_64 - /* Don't use these on 32 bits due to broken virtualizers */ - if (boot_cpu_data.x86_vendor == X86_VENDOR_INTEL) - memcpy(ideal_nop5, p6_nops[5], 5); -#endif -} -#endif diff --git a/arch/x86/kernel/ftrace.c b/arch/x86/kernel/ftrace.c index a93742a..0ba15a6 100644 --- a/arch/x86/kernel/ftrace.c +++ b/arch/x86/kernel/ftrace.c @@ -260,9 +260,9 @@ do_ftrace_mod_code(unsigned long ip, void *new_code) return mod_code_status; } -static unsigned char *ftrace_nop_replace(void) +static const unsigned char *ftrace_nop_replace(void) { - return ideal_nop5; + return ideal_nops[NOP_ATOMIC5]; } static int diff --git a/arch/x86/kernel/jump_label.c b/arch/x86/kernel/jump_label.c index 961b6b3..3fee346 100644 --- a/arch/x86/kernel/jump_label.c +++ b/arch/x86/kernel/jump_label.c @@ -34,7 +34,7 @@ void arch_jump_label_transform(struct jump_entry *entry, code.offset = entry->target - (entry->code + JUMP_LABEL_NOP_SIZE); } else - memcpy(&code, ideal_nop5, JUMP_LABEL_NOP_SIZE); + memcpy(&code, ideal_nops[NOP_ATOMIC5], JUMP_LABEL_NOP_SIZE); get_online_cpus(); mutex_lock(&text_mutex); text_poke_smp((void *)entry->code, &code, JUMP_LABEL_NOP_SIZE); @@ -44,7 +44,8 @@ void arch_jump_label_transform(struct jump_entry *entry, void arch_jump_label_text_poke_early(jump_label_t addr) { - text_poke_early((void *)addr, ideal_nop5, JUMP_LABEL_NOP_SIZE); + text_poke_early((void *)addr, ideal_nops[NOP_ATOMIC5], + JUMP_LABEL_NOP_SIZE); } #endif diff --git a/arch/x86/kernel/setup.c b/arch/x86/kernel/setup.c index 5a0484a..390a663 100644 --- a/arch/x86/kernel/setup.c +++ b/arch/x86/kernel/setup.c @@ -691,8 +691,6 @@ early_param("reservelow", parse_reservelow); void __init setup_arch(char **cmdline_p) { - unsigned long flags; - #ifdef CONFIG_X86_32 memcpy(&boot_cpu_data, &new_cpu_data, sizeof(new_cpu_data)); visws_early_detect(); @@ -1036,9 +1034,7 @@ void __init setup_arch(char **cmdline_p) mcheck_init(); - local_irq_save(flags); - arch_init_ideal_nop5(); - local_irq_restore(flags); + arch_init_ideal_nops(); } #ifdef CONFIG_X86_32 -- cgit v0.10.2 From d8d9766c8c29f71c37bc4b74cc9fcf6a192c9bfd Mon Sep 17 00:00:00 2001 From: "H. Peter Anvin" Date: Mon, 18 Apr 2011 15:31:57 -0700 Subject: x86, cpu: Change NOP selection for certain Intel CPUs Due to a decoder implementation quirk, some specific Intel CPUs actually perform better with the "k8_nops" than with the SDM-recommended NOPs. For runtime-selected NOPs, if we detect those specific CPUs then use the k8_nops instead of the ones we would normally use. Signed-off-by: H. Peter Anvin Cc: Tejun Heo Cc: Steven Rostedt Cc: Frederic Weisbecker Cc: Jason Baron Link: http://lkml.kernel.org/r/1303166160-10315-4-git-send-email-hpa@linux.intel.com diff --git a/arch/x86/kernel/alternative.c b/arch/x86/kernel/alternative.c index 846f61e..c0501ea 100644 --- a/arch/x86/kernel/alternative.c +++ b/arch/x86/kernel/alternative.c @@ -199,7 +199,19 @@ void __init arch_init_ideal_nops(void) { switch (boot_cpu_data.x86_vendor) { case X86_VENDOR_INTEL: - if (boot_cpu_has(X86_FEATURE_NOPL)) { + /* + * Due to a decoder implementation quirk, some + * specific Intel CPUs actually perform better with + * the "k8_nops" than with the SDM-recommended NOPs. + */ + if (boot_cpu_data.x86 == 6 && + boot_cpu_data.x86_model >= 0x0f && + boot_cpu_data.x86_model != 0x1c && + boot_cpu_data.x86_model != 0x26 && + boot_cpu_data.x86_model != 0x27 && + boot_cpu_data.x86_model < 0x30) { + ideal_nops = k8_nops; + } else if (boot_cpu_has(X86_FEATURE_NOPL)) { ideal_nops = p6_nops; } else { #ifdef CONFIG_X86_64 -- cgit v0.10.2 From f0e615c3cb72b42191b558c130409335812621d8 Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Mon, 18 Apr 2011 21:26:00 -0700 Subject: Linux 2.6.39-rc4 diff --git a/Makefile b/Makefile index 322e733..b967b96 100644 --- a/Makefile +++ b/Makefile @@ -1,7 +1,7 @@ VERSION = 2 PATCHLEVEL = 6 SUBLEVEL = 39 -EXTRAVERSION = -rc3 +EXTRAVERSION = -rc4 NAME = Flesh-Eating Bats with Fangs # *DOCUMENTATION* -- cgit v0.10.2 From 47c2cdf5513e86e43c799da8d5406cc9a2bf3626 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Miros=C5=82aw?= Date: Fri, 15 Apr 2011 04:50:50 +0000 Subject: net: myri10ge: convert to hw_features MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: MichaÅ‚ MirosÅ‚aw Acked-by: Jon Mason Signed-off-by: David S. Miller diff --git a/drivers/net/myri10ge/myri10ge.c b/drivers/net/myri10ge/myri10ge.c index 1446de5..e7f80164 100644 --- a/drivers/net/myri10ge/myri10ge.c +++ b/drivers/net/myri10ge/myri10ge.c @@ -205,7 +205,6 @@ struct myri10ge_priv { int tx_boundary; /* boundary transmits cannot cross */ int num_slices; int running; /* running? */ - int csum_flag; /* rx_csums? */ int small_bytes; int big_bytes; int max_intr_slots; @@ -1386,7 +1385,7 @@ myri10ge_rx_done(struct myri10ge_slice_state *ss, int len, __wsum csum, skb->protocol = eth_type_trans(skb, dev); skb_record_rx_queue(skb, ss - &mgp->ss[0]); - if (mgp->csum_flag) { + if (dev->features & NETIF_F_RXCSUM) { if ((skb->protocol == htons(ETH_P_IP)) || (skb->protocol == htons(ETH_P_IPV6))) { skb->csum = csum; @@ -1757,43 +1756,6 @@ myri10ge_get_ringparam(struct net_device *netdev, ring->tx_pending = ring->tx_max_pending; } -static u32 myri10ge_get_rx_csum(struct net_device *netdev) -{ - struct myri10ge_priv *mgp = netdev_priv(netdev); - - if (mgp->csum_flag) - return 1; - else - return 0; -} - -static int myri10ge_set_rx_csum(struct net_device *netdev, u32 csum_enabled) -{ - struct myri10ge_priv *mgp = netdev_priv(netdev); - int err = 0; - - if (csum_enabled) - mgp->csum_flag = MXGEFW_FLAGS_CKSUM; - else { - netdev->features &= ~NETIF_F_LRO; - mgp->csum_flag = 0; - - } - return err; -} - -static int myri10ge_set_tso(struct net_device *netdev, u32 tso_enabled) -{ - struct myri10ge_priv *mgp = netdev_priv(netdev); - u32 flags = mgp->features & (NETIF_F_TSO6 | NETIF_F_TSO); - - if (tso_enabled) - netdev->features |= flags; - else - netdev->features &= ~flags; - return 0; -} - static const char myri10ge_gstrings_main_stats[][ETH_GSTRING_LEN] = { "rx_packets", "tx_packets", "rx_bytes", "tx_bytes", "rx_errors", "tx_errors", "rx_dropped", "tx_dropped", "multicast", "collisions", @@ -1944,11 +1906,6 @@ static u32 myri10ge_get_msglevel(struct net_device *netdev) return mgp->msg_enable; } -static int myri10ge_set_flags(struct net_device *netdev, u32 value) -{ - return ethtool_op_set_flags(netdev, value, ETH_FLAG_LRO); -} - static const struct ethtool_ops myri10ge_ethtool_ops = { .get_settings = myri10ge_get_settings, .get_drvinfo = myri10ge_get_drvinfo, @@ -1957,19 +1914,12 @@ static const struct ethtool_ops myri10ge_ethtool_ops = { .get_pauseparam = myri10ge_get_pauseparam, .set_pauseparam = myri10ge_set_pauseparam, .get_ringparam = myri10ge_get_ringparam, - .get_rx_csum = myri10ge_get_rx_csum, - .set_rx_csum = myri10ge_set_rx_csum, - .set_tx_csum = ethtool_op_set_tx_hw_csum, - .set_sg = ethtool_op_set_sg, - .set_tso = myri10ge_set_tso, .get_link = ethtool_op_get_link, .get_strings = myri10ge_get_strings, .get_sset_count = myri10ge_get_sset_count, .get_ethtool_stats = myri10ge_get_ethtool_stats, .set_msglevel = myri10ge_set_msglevel, .get_msglevel = myri10ge_get_msglevel, - .get_flags = ethtool_op_get_flags, - .set_flags = myri10ge_set_flags }; static int myri10ge_allocate_rings(struct myri10ge_slice_state *ss) @@ -3136,6 +3086,14 @@ static int myri10ge_set_mac_address(struct net_device *dev, void *addr) return 0; } +static u32 myri10ge_fix_features(struct net_device *dev, u32 features) +{ + if (!(features & NETIF_F_RXCSUM)) + features &= ~NETIF_F_LRO; + + return features; +} + static int myri10ge_change_mtu(struct net_device *dev, int new_mtu) { struct myri10ge_priv *mgp = netdev_priv(dev); @@ -3834,6 +3792,7 @@ static const struct net_device_ops myri10ge_netdev_ops = { .ndo_get_stats = myri10ge_get_stats, .ndo_validate_addr = eth_validate_addr, .ndo_change_mtu = myri10ge_change_mtu, + .ndo_fix_features = myri10ge_fix_features, .ndo_set_multicast_list = myri10ge_set_multicast_list, .ndo_set_mac_address = myri10ge_set_mac_address, }; @@ -3860,7 +3819,6 @@ static int myri10ge_probe(struct pci_dev *pdev, const struct pci_device_id *ent) mgp = netdev_priv(netdev); mgp->dev = netdev; mgp->pdev = pdev; - mgp->csum_flag = MXGEFW_FLAGS_CKSUM; mgp->pause = myri10ge_flow_control; mgp->intr_coal_delay = myri10ge_intr_coal_delay; mgp->msg_enable = netif_msg_init(myri10ge_debug, MYRI10GE_MSG_DEFAULT); @@ -3976,11 +3934,11 @@ static int myri10ge_probe(struct pci_dev *pdev, const struct pci_device_id *ent) netdev->netdev_ops = &myri10ge_netdev_ops; netdev->mtu = myri10ge_initial_mtu; netdev->base_addr = mgp->iomem_base; - netdev->features = mgp->features; + netdev->hw_features = mgp->features | NETIF_F_LRO | NETIF_F_RXCSUM; + netdev->features = netdev->hw_features; if (dac_enabled) netdev->features |= NETIF_F_HIGHDMA; - netdev->features |= NETIF_F_LRO; netdev->vlan_features |= mgp->features; if (mgp->fw_ver_tiny < 37) -- cgit v0.10.2 From 2b7b431858c284b62c18baaf2cea571be2797d5a Mon Sep 17 00:00:00 2001 From: Francois Romieu Date: Mon, 18 Apr 2011 22:53:24 -0700 Subject: r8169: TSO fixes. - the MSS value is actually contained in a 11 bits wide (0x7ff) field. The extra bit in the former MSSMask did encompass the TSO command bit ("LargeSend") as well (0xfff). Oops. - the Tx descriptor layout is not the same through the whole chipset family. The 8169 documentation, the 8168c documentation and Realtek's drivers (8.020.00, 1.019.00, 6.014.00) highlight two layouts: 1. 8169, 8168 up to 8168b (included) and 8101 2. {8102e, 8168c} and beyond - notwithstanding the "first descriptor" and "last descriptor" bits, the same Tx descriptor content is enforced when a packet consists of several descriptors. The chipsets are documented to require it. Credits go to David Dillow for the original patch. Signed-off-by: Francois Romieu Cc: Realtek Signed-off-by: David S. Miller diff --git a/drivers/net/r8169.c b/drivers/net/r8169.c index 058524f..fb03e6f 100644 --- a/drivers/net/r8169.c +++ b/drivers/net/r8169.c @@ -134,47 +134,52 @@ enum mac_version { RTL_GIGA_MAC_VER_33 = 0x21, // 8168E }; -#define _R(NAME,MAC,MASK) \ - { .name = NAME, .mac_version = MAC, .RxConfigMask = MASK } +enum rtl_tx_desc_version { + RTL_TD_0 = 0, + RTL_TD_1 = 1, +}; + +#define _R(NAME,MAC,TD) \ + { .name = NAME, .mac_version = MAC, .txd_version = TD } static const struct { const char *name; u8 mac_version; - u32 RxConfigMask; /* Clears the bits supported by this chip */ + enum rtl_tx_desc_version txd_version; } rtl_chip_info[] = { - _R("RTL8169", RTL_GIGA_MAC_VER_01, 0xff7e1880), // 8169 - _R("RTL8169s", RTL_GIGA_MAC_VER_02, 0xff7e1880), // 8169S - _R("RTL8110s", RTL_GIGA_MAC_VER_03, 0xff7e1880), // 8110S - _R("RTL8169sb/8110sb", RTL_GIGA_MAC_VER_04, 0xff7e1880), // 8169SB - _R("RTL8169sc/8110sc", RTL_GIGA_MAC_VER_05, 0xff7e1880), // 8110SCd - _R("RTL8169sc/8110sc", RTL_GIGA_MAC_VER_06, 0xff7e1880), // 8110SCe - _R("RTL8102e", RTL_GIGA_MAC_VER_07, 0xff7e1880), // PCI-E - _R("RTL8102e", RTL_GIGA_MAC_VER_08, 0xff7e1880), // PCI-E - _R("RTL8102e", RTL_GIGA_MAC_VER_09, 0xff7e1880), // PCI-E - _R("RTL8101e", RTL_GIGA_MAC_VER_10, 0xff7e1880), // PCI-E - _R("RTL8168b/8111b", RTL_GIGA_MAC_VER_11, 0xff7e1880), // PCI-E - _R("RTL8168b/8111b", RTL_GIGA_MAC_VER_12, 0xff7e1880), // PCI-E - _R("RTL8101e", RTL_GIGA_MAC_VER_13, 0xff7e1880), // PCI-E 8139 - _R("RTL8100e", RTL_GIGA_MAC_VER_14, 0xff7e1880), // PCI-E 8139 - _R("RTL8100e", RTL_GIGA_MAC_VER_15, 0xff7e1880), // PCI-E 8139 - _R("RTL8168b/8111b", RTL_GIGA_MAC_VER_17, 0xff7e1880), // PCI-E - _R("RTL8101e", RTL_GIGA_MAC_VER_16, 0xff7e1880), // PCI-E - _R("RTL8168cp/8111cp", RTL_GIGA_MAC_VER_18, 0xff7e1880), // PCI-E - _R("RTL8168c/8111c", RTL_GIGA_MAC_VER_19, 0xff7e1880), // PCI-E - _R("RTL8168c/8111c", RTL_GIGA_MAC_VER_20, 0xff7e1880), // PCI-E - _R("RTL8168c/8111c", RTL_GIGA_MAC_VER_21, 0xff7e1880), // PCI-E - _R("RTL8168c/8111c", RTL_GIGA_MAC_VER_22, 0xff7e1880), // PCI-E - _R("RTL8168cp/8111cp", RTL_GIGA_MAC_VER_23, 0xff7e1880), // PCI-E - _R("RTL8168cp/8111cp", RTL_GIGA_MAC_VER_24, 0xff7e1880), // PCI-E - _R("RTL8168d/8111d", RTL_GIGA_MAC_VER_25, 0xff7e1880), // PCI-E - _R("RTL8168d/8111d", RTL_GIGA_MAC_VER_26, 0xff7e1880), // PCI-E - _R("RTL8168dp/8111dp", RTL_GIGA_MAC_VER_27, 0xff7e1880), // PCI-E - _R("RTL8168dp/8111dp", RTL_GIGA_MAC_VER_28, 0xff7e1880), // PCI-E - _R("RTL8105e", RTL_GIGA_MAC_VER_29, 0xff7e1880), // PCI-E - _R("RTL8105e", RTL_GIGA_MAC_VER_30, 0xff7e1880), // PCI-E - _R("RTL8168dp/8111dp", RTL_GIGA_MAC_VER_31, 0xff7e1880), // PCI-E - _R("RTL8168e/8111e", RTL_GIGA_MAC_VER_32, 0xff7e1880), // PCI-E - _R("RTL8168e/8111e", RTL_GIGA_MAC_VER_33, 0xff7e1880) // PCI-E + _R("RTL8169", RTL_GIGA_MAC_VER_01, RTL_TD_0), // 8169 + _R("RTL8169s", RTL_GIGA_MAC_VER_02, RTL_TD_0), // 8169S + _R("RTL8110s", RTL_GIGA_MAC_VER_03, RTL_TD_0), // 8110S + _R("RTL8169sb/8110sb", RTL_GIGA_MAC_VER_04, RTL_TD_0), // 8169SB + _R("RTL8169sc/8110sc", RTL_GIGA_MAC_VER_05, RTL_TD_0), // 8110SCd + _R("RTL8169sc/8110sc", RTL_GIGA_MAC_VER_06, RTL_TD_0), // 8110SCe + _R("RTL8102e", RTL_GIGA_MAC_VER_07, RTL_TD_1), // PCI-E + _R("RTL8102e", RTL_GIGA_MAC_VER_08, RTL_TD_1), // PCI-E + _R("RTL8102e", RTL_GIGA_MAC_VER_09, RTL_TD_1), // PCI-E + _R("RTL8101e", RTL_GIGA_MAC_VER_10, RTL_TD_0), // PCI-E + _R("RTL8168b/8111b", RTL_GIGA_MAC_VER_11, RTL_TD_0), // PCI-E + _R("RTL8168b/8111b", RTL_GIGA_MAC_VER_12, RTL_TD_0), // PCI-E + _R("RTL8101e", RTL_GIGA_MAC_VER_13, RTL_TD_0), // PCI-E 8139 + _R("RTL8100e", RTL_GIGA_MAC_VER_14, RTL_TD_0), // PCI-E 8139 + _R("RTL8100e", RTL_GIGA_MAC_VER_15, RTL_TD_0), // PCI-E 8139 + _R("RTL8168b/8111b", RTL_GIGA_MAC_VER_17, RTL_TD_0), // PCI-E + _R("RTL8101e", RTL_GIGA_MAC_VER_16, RTL_TD_0), // PCI-E + _R("RTL8168cp/8111cp", RTL_GIGA_MAC_VER_18, RTL_TD_1), // PCI-E + _R("RTL8168c/8111c", RTL_GIGA_MAC_VER_19, RTL_TD_1), // PCI-E + _R("RTL8168c/8111c", RTL_GIGA_MAC_VER_20, RTL_TD_1), // PCI-E + _R("RTL8168c/8111c", RTL_GIGA_MAC_VER_21, RTL_TD_1), // PCI-E + _R("RTL8168c/8111c", RTL_GIGA_MAC_VER_22, RTL_TD_1), // PCI-E + _R("RTL8168cp/8111cp", RTL_GIGA_MAC_VER_23, RTL_TD_1), // PCI-E + _R("RTL8168cp/8111cp", RTL_GIGA_MAC_VER_24, RTL_TD_1), // PCI-E + _R("RTL8168d/8111d", RTL_GIGA_MAC_VER_25, RTL_TD_1), // PCI-E + _R("RTL8168d/8111d", RTL_GIGA_MAC_VER_26, RTL_TD_1), // PCI-E + _R("RTL8168dp/8111dp", RTL_GIGA_MAC_VER_27, RTL_TD_1), // PCI-E + _R("RTL8168dp/8111dp", RTL_GIGA_MAC_VER_28, RTL_TD_1), // PCI-E + _R("RTL8105e", RTL_GIGA_MAC_VER_29, RTL_TD_1), // PCI-E + _R("RTL8105e", RTL_GIGA_MAC_VER_30, RTL_TD_1), // PCI-E + _R("RTL8168dp/8111dp", RTL_GIGA_MAC_VER_31, RTL_TD_1), // PCI-E + _R("RTL8168e/8111e", RTL_GIGA_MAC_VER_32, RTL_TD_1), // PCI-E + _R("RTL8168e/8111e", RTL_GIGA_MAC_VER_33, RTL_TD_1) // PCI-E }; #undef _R @@ -230,6 +235,9 @@ enum rtl_registers { IntrStatus = 0x3e, TxConfig = 0x40, RxConfig = 0x44, + +#define RTL_RX_CONFIG_MASK 0xff7e1880u + RxMissed = 0x4c, Cfg9346 = 0x50, Config0 = 0x51, @@ -452,21 +460,69 @@ enum rtl_register_content { CounterDump = 0x8, }; -enum desc_status_bit { +enum rtl_desc_bit { + /* First doubleword. */ DescOwn = (1 << 31), /* Descriptor is owned by NIC */ RingEnd = (1 << 30), /* End of descriptor ring */ FirstFrag = (1 << 29), /* First segment of a packet */ LastFrag = (1 << 28), /* Final segment of a packet */ +}; + +/* Generic case. */ +enum rtl_tx_desc_bit { + /* First doubleword. */ + TD_LSO = (1 << 27), /* Large Send Offload */ +#define TD_MSS_MAX 0x07ffu /* MSS value */ - /* Tx private */ - LargeSend = (1 << 27), /* TCP Large Send Offload (TSO) */ - MSSShift = 16, /* MSS value position */ - MSSMask = 0xfff, /* MSS value + LargeSend bit: 12 bits */ - IPCS = (1 << 18), /* Calculate IP checksum */ - UDPCS = (1 << 17), /* Calculate UDP/IP checksum */ - TCPCS = (1 << 16), /* Calculate TCP/IP checksum */ - TxVlanTag = (1 << 17), /* Add VLAN tag */ + /* Second doubleword. */ + TxVlanTag = (1 << 17), /* Add VLAN tag */ +}; + +/* 8169, 8168b and 810x except 8102e. */ +enum rtl_tx_desc_bit_0 { + /* First doubleword. */ +#define TD0_MSS_SHIFT 16 /* MSS position (11 bits) */ + TD0_TCP_CS = (1 << 16), /* Calculate TCP/IP checksum */ + TD0_UDP_CS = (1 << 17), /* Calculate UDP/IP checksum */ + TD0_IP_CS = (1 << 18), /* Calculate IP checksum */ +}; + +/* 8102e, 8168c and beyond. */ +enum rtl_tx_desc_bit_1 { + /* Second doubleword. */ +#define TD1_MSS_SHIFT 18 /* MSS position (11 bits) */ + TD1_IP_CS = (1 << 29), /* Calculate IP checksum */ + TD1_TCP_CS = (1 << 30), /* Calculate TCP/IP checksum */ + TD1_UDP_CS = (1 << 31), /* Calculate UDP/IP checksum */ +}; +static const struct rtl_tx_desc_info { + struct { + u32 udp; + u32 tcp; + } checksum; + u16 mss_shift; + u16 opts_offset; +} tx_desc_info [] = { + [RTL_TD_0] = { + .checksum = { + .udp = TD0_IP_CS | TD0_UDP_CS, + .tcp = TD0_IP_CS | TD0_TCP_CS + }, + .mss_shift = TD0_MSS_SHIFT, + .opts_offset = 0 + }, + [RTL_TD_1] = { + .checksum = { + .udp = TD1_IP_CS | TD1_UDP_CS, + .tcp = TD1_IP_CS | TD1_TCP_CS + }, + .mss_shift = TD1_MSS_SHIFT, + .opts_offset = 1 + } +}; + +enum rtl_rx_desc_bit { /* Rx private */ PID1 = (1 << 18), /* Protocol ID bit 1/2 */ PID0 = (1 << 17), /* Protocol ID bit 2/2 */ @@ -531,8 +587,8 @@ struct rtl8169_private { struct napi_struct napi; spinlock_t lock; /* spin lock flag */ u32 msg_enable; - int chipset; - int mac_version; + u16 txd_version; + u16 mac_version; u32 cur_rx; /* Index into the Rx descriptor buffer of next Rx pkt. */ u32 cur_tx; /* Index into the Tx descriptor buffer of next Rx pkt. */ u32 dirty_rx; @@ -1288,7 +1344,7 @@ static int rtl8169_set_settings(struct net_device *dev, struct ethtool_cmd *cmd) static u32 rtl8169_fix_features(struct net_device *dev, u32 features) { - if (dev->mtu > MSSMask) + if (dev->mtu > TD_MSS_MAX) features &= ~NETIF_F_ALL_TSO; return features; @@ -3194,7 +3250,7 @@ rtl8169_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) struct mii_if_info *mii; struct net_device *dev; void __iomem *ioaddr; - unsigned int i; + int chipset, i; int rc; if (netif_msg_drv(&debug)) { @@ -3336,7 +3392,8 @@ rtl8169_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) "driver bug, MAC version not found in rtl_chip_info\n"); goto err_out_msi_4; } - tp->chipset = i; + chipset = i; + tp->txd_version = rtl_chip_info[chipset].txd_version; RTL_W8(Cfg9346, Cfg9346_Unlock); RTL_W8(Config1, RTL_R8(Config1) | PMEnable); @@ -3413,8 +3470,7 @@ rtl8169_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) pci_set_drvdata(pdev, dev); netif_info(tp, probe, dev, "%s at 0x%lx, %pM, XID %08x IRQ %d\n", - rtl_chip_info[tp->chipset].name, - dev->base_addr, dev->dev_addr, + rtl_chip_info[chipset].name, dev->base_addr, dev->dev_addr, (u32)(RTL_R32(TxConfig) & 0x9cf0f8ff), dev->irq); if ((tp->mac_version == RTL_GIGA_MAC_VER_27) || @@ -3572,7 +3628,7 @@ static void rtl_set_rx_tx_config_registers(struct rtl8169_private *tp) void __iomem *ioaddr = tp->mmio_addr; u32 cfg = rtl8169_rx_config; - cfg |= (RTL_R32(RxConfig) & rtl_chip_info[tp->chipset].RxConfigMask); + cfg |= (RTL_R32(RxConfig) & RTL_RX_CONFIG_MASK); RTL_W32(RxConfig, cfg); /* Set DMA burst size and Interframe Gap Time */ @@ -4564,7 +4620,7 @@ static void rtl8169_tx_timeout(struct net_device *dev) } static int rtl8169_xmit_frags(struct rtl8169_private *tp, struct sk_buff *skb, - u32 opts1) + u32 *opts) { struct skb_shared_info *info = skb_shinfo(skb); unsigned int cur_frag, entry; @@ -4592,9 +4648,11 @@ static int rtl8169_xmit_frags(struct rtl8169_private *tp, struct sk_buff *skb, } /* anti gcc 2.95.3 bugware (sic) */ - status = opts1 | len | (RingEnd * !((entry + 1) % NUM_TX_DESC)); + status = opts[0] | len | + (RingEnd * !((entry + 1) % NUM_TX_DESC)); txd->opts1 = cpu_to_le32(status); + txd->opts2 = cpu_to_le32(opts[1]); txd->addr = cpu_to_le64(mapping); tp->tx_skb[entry].len = len; @@ -4612,23 +4670,26 @@ err_out: return -EIO; } -static inline u32 rtl8169_tso_csum(struct sk_buff *skb, struct net_device *dev) +static inline void rtl8169_tso_csum(struct rtl8169_private *tp, + struct sk_buff *skb, u32 *opts) { + const struct rtl_tx_desc_info *info = tx_desc_info + tp->txd_version; u32 mss = skb_shinfo(skb)->gso_size; + int offset = info->opts_offset; - if (mss) - return LargeSend | ((mss & MSSMask) << MSSShift); - - if (skb->ip_summed == CHECKSUM_PARTIAL) { + if (mss) { + opts[0] |= TD_LSO; + opts[offset] |= min(mss, TD_MSS_MAX) << info->mss_shift; + } else if (skb->ip_summed == CHECKSUM_PARTIAL) { const struct iphdr *ip = ip_hdr(skb); if (ip->protocol == IPPROTO_TCP) - return IPCS | TCPCS; + opts[offset] |= info->checksum.tcp; else if (ip->protocol == IPPROTO_UDP) - return IPCS | UDPCS; - WARN_ON(1); /* we need a WARN() */ + opts[offset] |= info->checksum.udp; + else + WARN_ON_ONCE(1); } - return 0; } static netdev_tx_t rtl8169_start_xmit(struct sk_buff *skb, @@ -4641,7 +4702,7 @@ static netdev_tx_t rtl8169_start_xmit(struct sk_buff *skb, struct device *d = &tp->pci_dev->dev; dma_addr_t mapping; u32 status, len; - u32 opts1; + u32 opts[2]; int frags; if (unlikely(TX_BUFFS_AVAIL(tp) < skb_shinfo(skb)->nr_frags)) { @@ -4662,24 +4723,28 @@ static netdev_tx_t rtl8169_start_xmit(struct sk_buff *skb, tp->tx_skb[entry].len = len; txd->addr = cpu_to_le64(mapping); - txd->opts2 = cpu_to_le32(rtl8169_tx_vlan_tag(tp, skb)); - opts1 = DescOwn | rtl8169_tso_csum(skb, dev); + opts[1] = cpu_to_le32(rtl8169_tx_vlan_tag(tp, skb)); + opts[0] = DescOwn; - frags = rtl8169_xmit_frags(tp, skb, opts1); + rtl8169_tso_csum(tp, skb, opts); + + frags = rtl8169_xmit_frags(tp, skb, opts); if (frags < 0) goto err_dma_1; else if (frags) - opts1 |= FirstFrag; + opts[0] |= FirstFrag; else { - opts1 |= FirstFrag | LastFrag; + opts[0] |= FirstFrag | LastFrag; tp->tx_skb[entry].skb = skb; } + txd->opts2 = cpu_to_le32(opts[1]); + wmb(); /* anti gcc 2.95.3 bugware (sic) */ - status = opts1 | len | (RingEnd * !((entry + 1) % NUM_TX_DESC)); + status = opts[0] | len | (RingEnd * !((entry + 1) % NUM_TX_DESC)); txd->opts1 = cpu_to_le32(status); tp->cur_tx += frags + 1; @@ -5167,7 +5232,7 @@ static void rtl_set_rx_mode(struct net_device *dev) spin_lock_irqsave(&tp->lock, flags); tmp = rtl8169_rx_config | rx_mode | - (RTL_R32(RxConfig) & rtl_chip_info[tp->chipset].RxConfigMask); + (RTL_R32(RxConfig) & RTL_RX_CONFIG_MASK); if (tp->mac_version > RTL_GIGA_MAC_VER_06) { u32 data = mc_filter[0]; -- cgit v0.10.2 From e5cb966c0838e4da43a3b0751bdcac7fe719f7b4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Miros=C5=82aw?= Date: Mon, 18 Apr 2011 13:31:20 +0000 Subject: net: fix section mismatches MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fix build warnings like the following: WARNING: drivers/net/built-in.o(.data+0x12434): Section mismatch in reference from the variable madgemc_driver to the variable .init.data:madgemc_adapter_ids And add some consts to EISA device ID tables along the way. Signed-off-by: MichaÅ‚ MirosÅ‚aw Signed-off-by: David S. Miller diff --git a/drivers/net/3c509.c b/drivers/net/3c509.c index 91abb96..cb39ded 100644 --- a/drivers/net/3c509.c +++ b/drivers/net/3c509.c @@ -185,7 +185,7 @@ static int max_interrupt_work = 10; static int nopnp; #endif -static int __devinit el3_common_init(struct net_device *dev); +static int el3_common_init(struct net_device *dev); static void el3_common_remove(struct net_device *dev); static ushort id_read_eeprom(int index); static ushort read_eeprom(int ioaddr, int index); @@ -395,7 +395,7 @@ static struct isa_driver el3_isa_driver = { static int isa_registered; #ifdef CONFIG_PNP -static struct pnp_device_id el3_pnp_ids[] = { +static const struct pnp_device_id el3_pnp_ids[] __devinitconst = { { .id = "TCM5090" }, /* 3Com Etherlink III (TP) */ { .id = "TCM5091" }, /* 3Com Etherlink III */ { .id = "TCM5094" }, /* 3Com Etherlink III (combo) */ @@ -478,7 +478,7 @@ static int pnp_registered; #endif /* CONFIG_PNP */ #ifdef CONFIG_EISA -static struct eisa_device_id el3_eisa_ids[] = { +static const struct eisa_device_id el3_eisa_ids[] __devinitconst = { { "TCM5090" }, { "TCM5091" }, { "TCM5092" }, @@ -508,7 +508,7 @@ static int eisa_registered; #ifdef CONFIG_MCA static int el3_mca_probe(struct device *dev); -static short el3_mca_adapter_ids[] __initdata = { +static const short el3_mca_adapter_ids[] __devinitconst = { 0x627c, 0x627d, 0x62db, @@ -517,7 +517,7 @@ static short el3_mca_adapter_ids[] __initdata = { 0x0000 }; -static char *el3_mca_adapter_names[] __initdata = { +static const char *const el3_mca_adapter_names[] __devinitconst = { "3Com 3c529 EtherLink III (10base2)", "3Com 3c529 EtherLink III (10baseT)", "3Com 3c529 EtherLink III (test mode)", @@ -601,7 +601,7 @@ static void el3_common_remove (struct net_device *dev) } #ifdef CONFIG_MCA -static int __init el3_mca_probe(struct device *device) +static int __devinit el3_mca_probe(struct device *device) { /* Based on Erik Nygren's (nygren@mit.edu) 3c529 patch, * heavily modified by Chris Beauregard @@ -671,7 +671,7 @@ static int __init el3_mca_probe(struct device *device) #endif /* CONFIG_MCA */ #ifdef CONFIG_EISA -static int __init el3_eisa_probe (struct device *device) +static int __devinit el3_eisa_probe (struct device *device) { short i; int ioaddr, irq, if_port; diff --git a/drivers/net/3c59x.c b/drivers/net/3c59x.c index 8cc2256..99f43d2 100644 --- a/drivers/net/3c59x.c +++ b/drivers/net/3c59x.c @@ -901,14 +901,14 @@ static const struct dev_pm_ops vortex_pm_ops = { #endif /* !CONFIG_PM */ #ifdef CONFIG_EISA -static struct eisa_device_id vortex_eisa_ids[] = { +static const struct eisa_device_id vortex_eisa_ids[] __devinitconst = { { "TCM5920", CH_3C592 }, { "TCM5970", CH_3C597 }, { "" } }; MODULE_DEVICE_TABLE(eisa, vortex_eisa_ids); -static int __init vortex_eisa_probe(struct device *device) +static int __devinit vortex_eisa_probe(struct device *device) { void __iomem *ioaddr; struct eisa_device *edev; diff --git a/drivers/net/depca.c b/drivers/net/depca.c index 8b0084d..1765405 100644 --- a/drivers/net/depca.c +++ b/drivers/net/depca.c @@ -331,18 +331,18 @@ static struct { "DE422",\ ""} -static char* __initdata depca_signature[] = DEPCA_SIGNATURE; +static const char* const depca_signature[] __devinitconst = DEPCA_SIGNATURE; enum depca_type { DEPCA, de100, de101, de200, de201, de202, de210, de212, de422, unknown }; -static char depca_string[] = "depca"; +static const char depca_string[] = "depca"; static int depca_device_remove (struct device *device); #ifdef CONFIG_EISA -static struct eisa_device_id depca_eisa_ids[] = { +static const struct eisa_device_id depca_eisa_ids[] __devinitconst = { { "DEC4220", de422 }, { "" } }; @@ -367,19 +367,19 @@ static struct eisa_driver depca_eisa_driver = { #define DE210_ID 0x628d #define DE212_ID 0x6def -static short depca_mca_adapter_ids[] = { +static const short depca_mca_adapter_ids[] __devinitconst = { DE210_ID, DE212_ID, 0x0000 }; -static char *depca_mca_adapter_name[] = { +static const char *depca_mca_adapter_name[] = { "DEC EtherWORKS MC Adapter (DE210)", "DEC EtherWORKS MC Adapter (DE212)", NULL }; -static enum depca_type depca_mca_adapter_type[] = { +static const enum depca_type depca_mca_adapter_type[] = { de210, de212, 0 @@ -541,10 +541,9 @@ static void SetMulticastFilter(struct net_device *dev); static int load_packet(struct net_device *dev, struct sk_buff *skb); static void depca_dbg_open(struct net_device *dev); -static u_char de1xx_irq[] __initdata = { 2, 3, 4, 5, 7, 9, 0 }; -static u_char de2xx_irq[] __initdata = { 5, 9, 10, 11, 15, 0 }; -static u_char de422_irq[] __initdata = { 5, 9, 10, 11, 0 }; -static u_char *depca_irq; +static const u_char de1xx_irq[] __devinitconst = { 2, 3, 4, 5, 7, 9, 0 }; +static const u_char de2xx_irq[] __devinitconst = { 5, 9, 10, 11, 15, 0 }; +static const u_char de422_irq[] __devinitconst = { 5, 9, 10, 11, 0 }; static int irq; static int io; @@ -580,7 +579,7 @@ static const struct net_device_ops depca_netdev_ops = { .ndo_validate_addr = eth_validate_addr, }; -static int __init depca_hw_init (struct net_device *dev, struct device *device) +static int __devinit depca_hw_init (struct net_device *dev, struct device *device) { struct depca_private *lp; int i, j, offset, netRAM, mem_len, status = 0; @@ -748,6 +747,7 @@ static int __init depca_hw_init (struct net_device *dev, struct device *device) if (dev->irq < 2) { unsigned char irqnum; unsigned long irq_mask, delay; + const u_char *depca_irq; irq_mask = probe_irq_on(); @@ -770,6 +770,7 @@ static int __init depca_hw_init (struct net_device *dev, struct device *device) break; default: + depca_irq = NULL; break; /* Not reached */ } @@ -1302,7 +1303,7 @@ static void SetMulticastFilter(struct net_device *dev) } } -static int __init depca_common_init (u_long ioaddr, struct net_device **devp) +static int __devinit depca_common_init (u_long ioaddr, struct net_device **devp) { int status = 0; @@ -1333,7 +1334,7 @@ static int __init depca_common_init (u_long ioaddr, struct net_device **devp) /* ** Microchannel bus I/O device probe */ -static int __init depca_mca_probe(struct device *device) +static int __devinit depca_mca_probe(struct device *device) { unsigned char pos[2]; unsigned char where; @@ -1457,7 +1458,7 @@ static int __init depca_mca_probe(struct device *device) ** ISA bus I/O device probe */ -static void __init depca_platform_probe (void) +static void __devinit depca_platform_probe (void) { int i; struct platform_device *pldev; @@ -1497,7 +1498,7 @@ static void __init depca_platform_probe (void) } } -static enum depca_type __init depca_shmem_probe (ulong *mem_start) +static enum depca_type __devinit depca_shmem_probe (ulong *mem_start) { u_long mem_base[] = DEPCA_RAM_BASE_ADDRESSES; enum depca_type adapter = unknown; @@ -1558,7 +1559,7 @@ static int __devinit depca_isa_probe (struct platform_device *device) */ #ifdef CONFIG_EISA -static int __init depca_eisa_probe (struct device *device) +static int __devinit depca_eisa_probe (struct device *device) { enum depca_type adapter = unknown; struct eisa_device *edev; @@ -1629,7 +1630,7 @@ static int __devexit depca_device_remove (struct device *device) ** and Boot (readb) ROM. This will also give us a clue to the network RAM ** base address. */ -static int __init DepcaSignature(char *name, u_long base_addr) +static int __devinit DepcaSignature(char *name, u_long base_addr) { u_int i, j, k; void __iomem *ptr; diff --git a/drivers/net/hp100.c b/drivers/net/hp100.c index 8e10d2f..c52a1df 100644 --- a/drivers/net/hp100.c +++ b/drivers/net/hp100.c @@ -188,14 +188,14 @@ struct hp100_private { * variables */ #ifdef CONFIG_ISA -static const char *hp100_isa_tbl[] = { +static const char *const hp100_isa_tbl[] __devinitconst = { "HWPF150", /* HP J2573 rev A */ "HWP1950", /* HP J2573 */ }; #endif #ifdef CONFIG_EISA -static struct eisa_device_id hp100_eisa_tbl[] = { +static const struct eisa_device_id hp100_eisa_tbl[] __devinitconst = { { "HWPF180" }, /* HP J2577 rev A */ { "HWP1920" }, /* HP 27248B */ { "HWP1940" }, /* HP J2577 */ @@ -336,7 +336,7 @@ static __devinit const char *hp100_read_id(int ioaddr) } #ifdef CONFIG_ISA -static __init int hp100_isa_probe1(struct net_device *dev, int ioaddr) +static __devinit int hp100_isa_probe1(struct net_device *dev, int ioaddr) { const char *sig; int i; @@ -372,7 +372,7 @@ static __init int hp100_isa_probe1(struct net_device *dev, int ioaddr) * EISA and PCI are handled by device infrastructure. */ -static int __init hp100_isa_probe(struct net_device *dev, int addr) +static int __devinit hp100_isa_probe(struct net_device *dev, int addr) { int err = -ENODEV; @@ -396,7 +396,7 @@ static int __init hp100_isa_probe(struct net_device *dev, int addr) #endif /* CONFIG_ISA */ #if !defined(MODULE) && defined(CONFIG_ISA) -struct net_device * __init hp100_probe(int unit) +struct net_device * __devinit hp100_probe(int unit) { struct net_device *dev = alloc_etherdev(sizeof(struct hp100_private)); int err; @@ -2843,7 +2843,7 @@ static void cleanup_dev(struct net_device *d) } #ifdef CONFIG_EISA -static int __init hp100_eisa_probe (struct device *gendev) +static int __devinit hp100_eisa_probe (struct device *gendev) { struct net_device *dev = alloc_etherdev(sizeof(struct hp100_private)); struct eisa_device *edev = to_eisa_device(gendev); diff --git a/drivers/net/ibmlana.c b/drivers/net/ibmlana.c index a7d6cad..136d754 100644 --- a/drivers/net/ibmlana.c +++ b/drivers/net/ibmlana.c @@ -895,12 +895,12 @@ static int ibmlana_irq; static int ibmlana_io; static int startslot; /* counts through slots when probing multiple devices */ -static short ibmlana_adapter_ids[] __initdata = { +static const short ibmlana_adapter_ids[] __devinitconst = { IBM_LANA_ID, 0x0000 }; -static char *ibmlana_adapter_names[] __devinitdata = { +static const char *const ibmlana_adapter_names[] __devinitconst = { "IBM LAN Adapter/A", NULL }; diff --git a/drivers/net/irda/smsc-ircc2.c b/drivers/net/irda/smsc-ircc2.c index 8800e1f..69b5707 100644 --- a/drivers/net/irda/smsc-ircc2.c +++ b/drivers/net/irda/smsc-ircc2.c @@ -222,19 +222,19 @@ static void smsc_ircc_set_transceiver_for_speed(struct smsc_ircc_cb *self, u32 s static void smsc_ircc_sir_wait_hw_transmitter_finish(struct smsc_ircc_cb *self); /* Probing */ -static int __init smsc_ircc_look_for_chips(void); -static const struct smsc_chip * __init smsc_ircc_probe(unsigned short cfg_base, u8 reg, const struct smsc_chip *chip, char *type); -static int __init smsc_superio_flat(const struct smsc_chip *chips, unsigned short cfg_base, char *type); -static int __init smsc_superio_paged(const struct smsc_chip *chips, unsigned short cfg_base, char *type); -static int __init smsc_superio_fdc(unsigned short cfg_base); -static int __init smsc_superio_lpc(unsigned short cfg_base); +static int smsc_ircc_look_for_chips(void); +static const struct smsc_chip * smsc_ircc_probe(unsigned short cfg_base, u8 reg, const struct smsc_chip *chip, char *type); +static int smsc_superio_flat(const struct smsc_chip *chips, unsigned short cfg_base, char *type); +static int smsc_superio_paged(const struct smsc_chip *chips, unsigned short cfg_base, char *type); +static int smsc_superio_fdc(unsigned short cfg_base); +static int smsc_superio_lpc(unsigned short cfg_base); #ifdef CONFIG_PCI -static int __init preconfigure_smsc_chip(struct smsc_ircc_subsystem_configuration *conf); -static int __init preconfigure_through_82801(struct pci_dev *dev, struct smsc_ircc_subsystem_configuration *conf); -static void __init preconfigure_ali_port(struct pci_dev *dev, +static int preconfigure_smsc_chip(struct smsc_ircc_subsystem_configuration *conf); +static int preconfigure_through_82801(struct pci_dev *dev, struct smsc_ircc_subsystem_configuration *conf); +static void preconfigure_ali_port(struct pci_dev *dev, unsigned short port); -static int __init preconfigure_through_ali(struct pci_dev *dev, struct smsc_ircc_subsystem_configuration *conf); -static int __init smsc_ircc_preconfigure_subsystems(unsigned short ircc_cfg, +static int preconfigure_through_ali(struct pci_dev *dev, struct smsc_ircc_subsystem_configuration *conf); +static int smsc_ircc_preconfigure_subsystems(unsigned short ircc_cfg, unsigned short ircc_fir, unsigned short ircc_sir, unsigned char ircc_dma, @@ -366,7 +366,7 @@ static inline void register_bank(int iobase, int bank) } /* PNP hotplug support */ -static const struct pnp_device_id smsc_ircc_pnp_table[] = { +static const struct pnp_device_id smsc_ircc_pnp_table[] __devinitconst = { { .id = "SMCf010", .driver_data = 0 }, /* and presumably others */ { } @@ -515,7 +515,7 @@ static const struct net_device_ops smsc_ircc_netdev_ops = { * Try to open driver instance * */ -static int __init smsc_ircc_open(unsigned int fir_base, unsigned int sir_base, u8 dma, u8 irq) +static int __devinit smsc_ircc_open(unsigned int fir_base, unsigned int sir_base, u8 dma, u8 irq) { struct smsc_ircc_cb *self; struct net_device *dev; @@ -2273,7 +2273,7 @@ static int __init smsc_superio_paged(const struct smsc_chip *chips, unsigned sho } -static int __init smsc_access(unsigned short cfg_base, unsigned char reg) +static int __devinit smsc_access(unsigned short cfg_base, unsigned char reg) { IRDA_DEBUG(1, "%s\n", __func__); @@ -2281,7 +2281,7 @@ static int __init smsc_access(unsigned short cfg_base, unsigned char reg) return inb(cfg_base) != reg ? -1 : 0; } -static const struct smsc_chip * __init smsc_ircc_probe(unsigned short cfg_base, u8 reg, const struct smsc_chip *chip, char *type) +static const struct smsc_chip * __devinit smsc_ircc_probe(unsigned short cfg_base, u8 reg, const struct smsc_chip *chip, char *type) { u8 devid, xdevid, rev; @@ -2406,7 +2406,7 @@ static int __init smsc_superio_lpc(unsigned short cfg_base) #ifdef CONFIG_PCI #define PCIID_VENDOR_INTEL 0x8086 #define PCIID_VENDOR_ALI 0x10b9 -static struct smsc_ircc_subsystem_configuration subsystem_configurations[] __initdata = { +static const struct smsc_ircc_subsystem_configuration subsystem_configurations[] __devinitconst = { /* * Subsystems needing entries: * 0x10b9:0x1533 0x103c:0x0850 HP nx9010 family @@ -2532,7 +2532,7 @@ static struct smsc_ircc_subsystem_configuration subsystem_configurations[] __ini * (FIR port, SIR port, FIR DMA, FIR IRQ) * through the chip configuration port. */ -static int __init preconfigure_smsc_chip(struct +static int __devinit preconfigure_smsc_chip(struct smsc_ircc_subsystem_configuration *conf) { @@ -2633,7 +2633,7 @@ static int __init preconfigure_smsc_chip(struct * or Intel 82801DB/DBL (ICH4/ICH4-L) LPC Interface Bridge. * They all work the same way! */ -static int __init preconfigure_through_82801(struct pci_dev *dev, +static int __devinit preconfigure_through_82801(struct pci_dev *dev, struct smsc_ircc_subsystem_configuration *conf) @@ -2786,7 +2786,7 @@ static int __init preconfigure_through_82801(struct pci_dev *dev, * This is based on reverse-engineering since ALi does not * provide any data sheet for the 1533 chip. */ -static void __init preconfigure_ali_port(struct pci_dev *dev, +static void __devinit preconfigure_ali_port(struct pci_dev *dev, unsigned short port) { unsigned char reg; @@ -2824,7 +2824,7 @@ static void __init preconfigure_ali_port(struct pci_dev *dev, IRDA_MESSAGE("Activated ALi 1533 ISA bridge port 0x%04x.\n", port); } -static int __init preconfigure_through_ali(struct pci_dev *dev, +static int __devinit preconfigure_through_ali(struct pci_dev *dev, struct smsc_ircc_subsystem_configuration *conf) @@ -2837,7 +2837,7 @@ static int __init preconfigure_through_ali(struct pci_dev *dev, return preconfigure_smsc_chip(conf); } -static int __init smsc_ircc_preconfigure_subsystems(unsigned short ircc_cfg, +static int __devinit smsc_ircc_preconfigure_subsystems(unsigned short ircc_cfg, unsigned short ircc_fir, unsigned short ircc_sir, unsigned char ircc_dma, @@ -2849,7 +2849,7 @@ static int __init smsc_ircc_preconfigure_subsystems(unsigned short ircc_cfg, int ret = 0; for_each_pci_dev(dev) { - struct smsc_ircc_subsystem_configuration *conf; + const struct smsc_ircc_subsystem_configuration *conf; /* * Cache the subsystem vendor/device: diff --git a/drivers/net/ne3210.c b/drivers/net/ne3210.c index 243ed2a..e8984b0c 100644 --- a/drivers/net/ne3210.c +++ b/drivers/net/ne3210.c @@ -80,17 +80,20 @@ static void ne3210_block_output(struct net_device *dev, int count, const unsigne #define NE3210_DEBUG 0x0 -static unsigned char irq_map[] __initdata = {15, 12, 11, 10, 9, 7, 5, 3}; -static unsigned int shmem_map[] __initdata = {0xff0, 0xfe0, 0xfff0, 0xd8, 0xffe0, 0xffc0, 0xd0, 0x0}; -static const char *ifmap[] __initdata = {"UTP", "?", "BNC", "AUI"}; -static int ifmap_val[] __initdata = { +static const unsigned char irq_map[] __devinitconst = + { 15, 12, 11, 10, 9, 7, 5, 3 }; +static const unsigned int shmem_map[] __devinitconst = + { 0xff0, 0xfe0, 0xfff0, 0xd8, 0xffe0, 0xffc0, 0xd0, 0x0 }; +static const char *const ifmap[] __devinitconst = + { "UTP", "?", "BNC", "AUI" }; +static const int ifmap_val[] __devinitconst = { IF_PORT_10BASET, IF_PORT_UNKNOWN, IF_PORT_10BASE2, IF_PORT_AUI, }; -static int __init ne3210_eisa_probe (struct device *device) +static int __devinit ne3210_eisa_probe (struct device *device) { unsigned long ioaddr, phys_mem; int i, retval, port_index; @@ -313,7 +316,7 @@ static void ne3210_block_output(struct net_device *dev, int count, memcpy_toio(shmem, buf, count); } -static struct eisa_device_id ne3210_ids[] = { +static const struct eisa_device_id ne3210_ids[] __devinitconst = { { "EGL0101" }, { "NVL1801" }, { "" }, diff --git a/drivers/net/smc-mca.c b/drivers/net/smc-mca.c index d07c39c..0f29f26 100644 --- a/drivers/net/smc-mca.c +++ b/drivers/net/smc-mca.c @@ -156,7 +156,7 @@ static const struct { { 14, 15 } }; -static short smc_mca_adapter_ids[] __initdata = { +static const short smc_mca_adapter_ids[] __devinitconst = { 0x61c8, 0x61c9, 0x6fc0, @@ -168,7 +168,7 @@ static short smc_mca_adapter_ids[] __initdata = { 0x0000 }; -static char *smc_mca_adapter_names[] __initdata = { +static const char *const smc_mca_adapter_names[] __devinitconst = { "SMC Ethercard PLUS Elite/A BNC/AUI (WD8013EP/A)", "SMC Ethercard PLUS Elite/A UTP/AUI (WD8013WP/A)", "WD Ethercard PLUS/A (WD8003E/A or WD8003ET/A)", @@ -199,7 +199,7 @@ static const struct net_device_ops ultramca_netdev_ops = { #endif }; -static int __init ultramca_probe(struct device *gen_dev) +static int __devinit ultramca_probe(struct device *gen_dev) { unsigned short ioaddr; struct net_device *dev; diff --git a/drivers/net/tokenring/madgemc.c b/drivers/net/tokenring/madgemc.c index 2bedc0a..1313aa1 100644 --- a/drivers/net/tokenring/madgemc.c +++ b/drivers/net/tokenring/madgemc.c @@ -727,7 +727,7 @@ static int __devexit madgemc_remove(struct device *device) return 0; } -static short madgemc_adapter_ids[] __initdata = { +static const short madgemc_adapter_ids[] __devinitconst = { 0x002d, 0x0000 }; diff --git a/drivers/net/tulip/de4x5.c b/drivers/net/tulip/de4x5.c index efaa1d6..45144d5 100644 --- a/drivers/net/tulip/de4x5.c +++ b/drivers/net/tulip/de4x5.c @@ -1995,7 +1995,7 @@ SetMulticastFilter(struct net_device *dev) static u_char de4x5_irq[] = EISA_ALLOWED_IRQ_LIST; -static int __init de4x5_eisa_probe (struct device *gendev) +static int __devinit de4x5_eisa_probe (struct device *gendev) { struct eisa_device *edev; u_long iobase; @@ -2097,7 +2097,7 @@ static int __devexit de4x5_eisa_remove (struct device *device) return 0; } -static struct eisa_device_id de4x5_eisa_ids[] = { +static const struct eisa_device_id de4x5_eisa_ids[] __devinitconst = { { "DEC4250", 0 }, /* 0 is the board name index... */ { "" } }; -- cgit v0.10.2 From b437a8cc7de4c9d8d0bdb37e7621c119f7640967 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Miros=C5=82aw?= Date: Mon, 18 Apr 2011 13:31:20 +0000 Subject: net: s2io: convert to hw_features MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This removes advertising HW_CSUM as driver does not support it. Note: driver advertises TSO6 but not IPV6_CSUM - bug maybe? Signed-off-by: MichaÅ‚ MirosÅ‚aw Signed-off-by: David S. Miller diff --git a/drivers/net/s2io.c b/drivers/net/s2io.c index 2302d97..58b78f4 100644 --- a/drivers/net/s2io.c +++ b/drivers/net/s2io.c @@ -6618,25 +6618,6 @@ static int s2io_ethtool_get_regs_len(struct net_device *dev) } -static u32 s2io_ethtool_get_rx_csum(struct net_device *dev) -{ - struct s2io_nic *sp = netdev_priv(dev); - - return sp->rx_csum; -} - -static int s2io_ethtool_set_rx_csum(struct net_device *dev, u32 data) -{ - struct s2io_nic *sp = netdev_priv(dev); - - if (data) - sp->rx_csum = 1; - else - sp->rx_csum = 0; - - return 0; -} - static int s2io_get_eeprom_len(struct net_device *dev) { return XENA_EEPROM_SPACE; @@ -6688,61 +6669,27 @@ static void s2io_ethtool_get_strings(struct net_device *dev, } } -static int s2io_ethtool_op_set_tx_csum(struct net_device *dev, u32 data) -{ - if (data) - dev->features |= NETIF_F_IP_CSUM; - else - dev->features &= ~NETIF_F_IP_CSUM; - - return 0; -} - -static u32 s2io_ethtool_op_get_tso(struct net_device *dev) -{ - return (dev->features & NETIF_F_TSO) != 0; -} - -static int s2io_ethtool_op_set_tso(struct net_device *dev, u32 data) -{ - if (data) - dev->features |= (NETIF_F_TSO | NETIF_F_TSO6); - else - dev->features &= ~(NETIF_F_TSO | NETIF_F_TSO6); - - return 0; -} - -static int s2io_ethtool_set_flags(struct net_device *dev, u32 data) +static int s2io_set_features(struct net_device *dev, u32 features) { struct s2io_nic *sp = netdev_priv(dev); - int rc = 0; - int changed = 0; - - if (ethtool_invalid_flags(dev, data, ETH_FLAG_LRO)) - return -EINVAL; - - if (data & ETH_FLAG_LRO) { - if (!(dev->features & NETIF_F_LRO)) { - dev->features |= NETIF_F_LRO; - changed = 1; - } - } else if (dev->features & NETIF_F_LRO) { - dev->features &= ~NETIF_F_LRO; - changed = 1; - } + u32 changed = (features ^ dev->features) & NETIF_F_LRO; if (changed && netif_running(dev)) { + int rc; + s2io_stop_all_tx_queue(sp); s2io_card_down(sp); + dev->features = features; rc = s2io_card_up(sp); if (rc) s2io_reset(sp); else s2io_start_all_tx_queue(sp); + + return rc ? rc : 1; } - return rc; + return 0; } static const struct ethtool_ops netdev_ethtool_ops = { @@ -6758,15 +6705,6 @@ static const struct ethtool_ops netdev_ethtool_ops = { .get_ringparam = s2io_ethtool_gringparam, .get_pauseparam = s2io_ethtool_getpause_data, .set_pauseparam = s2io_ethtool_setpause_data, - .get_rx_csum = s2io_ethtool_get_rx_csum, - .set_rx_csum = s2io_ethtool_set_rx_csum, - .set_tx_csum = s2io_ethtool_op_set_tx_csum, - .set_flags = s2io_ethtool_set_flags, - .get_flags = ethtool_op_get_flags, - .set_sg = ethtool_op_set_sg, - .get_tso = s2io_ethtool_op_get_tso, - .set_tso = s2io_ethtool_op_set_tso, - .set_ufo = ethtool_op_set_ufo, .self_test = s2io_ethtool_test, .get_strings = s2io_ethtool_get_strings, .set_phys_id = s2io_ethtool_set_led, @@ -7538,7 +7476,7 @@ static int rx_osm_handler(struct ring_info *ring_data, struct RxD_t * rxdp) if ((rxdp->Control_1 & TCP_OR_UDP_FRAME) && ((!ring_data->lro) || (ring_data->lro && (!(rxdp->Control_1 & RXD_FRAME_IP_FRAG)))) && - (sp->rx_csum)) { + (dev->features & NETIF_F_RXCSUM)) { l3_csum = RXD_GET_L3_CKSUM(rxdp->Control_1); l4_csum = RXD_GET_L4_CKSUM(rxdp->Control_1); if ((l3_csum == L3_CKSUM_OK) && (l4_csum == L4_CKSUM_OK)) { @@ -7799,6 +7737,7 @@ static const struct net_device_ops s2io_netdev_ops = { .ndo_do_ioctl = s2io_ioctl, .ndo_set_mac_address = s2io_set_mac_addr, .ndo_change_mtu = s2io_change_mtu, + .ndo_set_features = s2io_set_features, .ndo_vlan_rx_register = s2io_vlan_rx_register, .ndo_vlan_rx_kill_vid = s2io_vlan_rx_kill_vid, .ndo_tx_timeout = s2io_tx_watchdog, @@ -8040,17 +7979,18 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre) /* Driver entry points */ dev->netdev_ops = &s2io_netdev_ops; SET_ETHTOOL_OPS(dev, &netdev_ethtool_ops); - dev->features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX; - dev->features |= NETIF_F_LRO; - dev->features |= NETIF_F_SG | NETIF_F_IP_CSUM; + dev->hw_features = NETIF_F_SG | NETIF_F_IP_CSUM | + NETIF_F_TSO | NETIF_F_TSO6 | + NETIF_F_RXCSUM | NETIF_F_LRO; + dev->features |= dev->hw_features | + NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX; + if (sp->device_type & XFRAME_II_DEVICE) { + dev->hw_features |= NETIF_F_UFO; + if (ufo) + dev->features |= NETIF_F_UFO; + } if (sp->high_dma_flag == true) dev->features |= NETIF_F_HIGHDMA; - dev->features |= NETIF_F_TSO; - dev->features |= NETIF_F_TSO6; - if ((sp->device_type & XFRAME_II_DEVICE) && (ufo)) { - dev->features |= NETIF_F_UFO; - dev->features |= NETIF_F_HW_CSUM; - } dev->watchdog_timeo = WATCH_DOG_TIMEOUT; INIT_WORK(&sp->rst_timer_task, s2io_restart_nic); INIT_WORK(&sp->set_link_task, s2io_set_link); -- cgit v0.10.2 From 30f554f925335abad89aaa38eec6828242b27527 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Miros=C5=82aw?= Date: Mon, 18 Apr 2011 13:31:20 +0000 Subject: net: chelsio: convert to hw_features MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Also remove flags that were not used or are now redundant to hw_features bits. No device had UDP_CSUM_CAPABLE set. Signed-off-by: MichaÅ‚ MirosÅ‚aw Signed-off-by: David S. Miller diff --git a/drivers/net/chelsio/common.h b/drivers/net/chelsio/common.h index 092f31a..c26d863 100644 --- a/drivers/net/chelsio/common.h +++ b/drivers/net/chelsio/common.h @@ -264,11 +264,6 @@ struct adapter { enum { /* adapter flags */ FULL_INIT_DONE = 1 << 0, - TSO_CAPABLE = 1 << 2, - TCP_CSUM_CAPABLE = 1 << 3, - UDP_CSUM_CAPABLE = 1 << 4, - VLAN_ACCEL_CAPABLE = 1 << 5, - RX_CSUM_ENABLED = 1 << 6, }; struct mdio_ops; diff --git a/drivers/net/chelsio/cxgb2.c b/drivers/net/chelsio/cxgb2.c index 0f71304..5f82c9c 100644 --- a/drivers/net/chelsio/cxgb2.c +++ b/drivers/net/chelsio/cxgb2.c @@ -192,10 +192,8 @@ static void link_start(struct port_info *p) static void enable_hw_csum(struct adapter *adapter) { - if (adapter->flags & TSO_CAPABLE) + if (adapter->port[0].dev->hw_features & NETIF_F_TSO) t1_tp_set_ip_checksum_offload(adapter->tp, 1); /* for TSO only */ - if (adapter->flags & UDP_CSUM_CAPABLE) - t1_tp_set_udp_checksum_offload(adapter->tp, 1); t1_tp_set_tcp_checksum_offload(adapter->tp, 1); } @@ -705,33 +703,6 @@ static int set_pauseparam(struct net_device *dev, return 0; } -static u32 get_rx_csum(struct net_device *dev) -{ - struct adapter *adapter = dev->ml_priv; - - return (adapter->flags & RX_CSUM_ENABLED) != 0; -} - -static int set_rx_csum(struct net_device *dev, u32 data) -{ - struct adapter *adapter = dev->ml_priv; - - if (data) - adapter->flags |= RX_CSUM_ENABLED; - else - adapter->flags &= ~RX_CSUM_ENABLED; - return 0; -} - -static int set_tso(struct net_device *dev, u32 value) -{ - struct adapter *adapter = dev->ml_priv; - - if (!(adapter->flags & TSO_CAPABLE)) - return value ? -EOPNOTSUPP : 0; - return ethtool_op_set_tso(dev, value); -} - static void get_sge_param(struct net_device *dev, struct ethtool_ringparam *e) { struct adapter *adapter = dev->ml_priv; @@ -831,17 +802,12 @@ static const struct ethtool_ops t1_ethtool_ops = { .get_eeprom = get_eeprom, .get_pauseparam = get_pauseparam, .set_pauseparam = set_pauseparam, - .get_rx_csum = get_rx_csum, - .set_rx_csum = set_rx_csum, - .set_tx_csum = ethtool_op_set_tx_csum, - .set_sg = ethtool_op_set_sg, .get_link = ethtool_op_get_link, .get_strings = get_strings, .get_sset_count = get_sset_count, .get_ethtool_stats = get_stats, .get_regs_len = get_regs_len, .get_regs = get_regs, - .set_tso = set_tso, }; static int t1_ioctl(struct net_device *dev, struct ifreq *req, int cmd) @@ -1105,28 +1071,28 @@ static int __devinit init_one(struct pci_dev *pdev, netdev->mem_start = mmio_start; netdev->mem_end = mmio_start + mmio_len - 1; netdev->ml_priv = adapter; - netdev->features |= NETIF_F_SG | NETIF_F_IP_CSUM; - netdev->features |= NETIF_F_LLTX; + netdev->hw_features |= NETIF_F_SG | NETIF_F_IP_CSUM | + NETIF_F_RXCSUM; + netdev->features |= NETIF_F_SG | NETIF_F_IP_CSUM | + NETIF_F_RXCSUM | NETIF_F_LLTX; - adapter->flags |= RX_CSUM_ENABLED | TCP_CSUM_CAPABLE; if (pci_using_dac) netdev->features |= NETIF_F_HIGHDMA; if (vlan_tso_capable(adapter)) { #if defined(CONFIG_VLAN_8021Q) || defined(CONFIG_VLAN_8021Q_MODULE) - adapter->flags |= VLAN_ACCEL_CAPABLE; netdev->features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX; #endif /* T204: disable TSO */ if (!(is_T2(adapter)) || bi->port_number != 4) { - adapter->flags |= TSO_CAPABLE; + netdev->hw_features |= NETIF_F_TSO; netdev->features |= NETIF_F_TSO; } } netdev->netdev_ops = &cxgb_netdev_ops; - netdev->hard_header_len += (adapter->flags & TSO_CAPABLE) ? + netdev->hard_header_len += (netdev->hw_features & NETIF_F_TSO) ? sizeof(struct cpl_tx_pkt_lso) : sizeof(struct cpl_tx_pkt); netif_napi_add(netdev, &adapter->napi, t1_poll, 64); diff --git a/drivers/net/chelsio/sge.c b/drivers/net/chelsio/sge.c index 8754d44..b948ea7 100644 --- a/drivers/net/chelsio/sge.c +++ b/drivers/net/chelsio/sge.c @@ -929,7 +929,7 @@ void t1_sge_intr_enable(struct sge *sge) u32 en = SGE_INT_ENABLE; u32 val = readl(sge->adapter->regs + A_PL_ENABLE); - if (sge->adapter->flags & TSO_CAPABLE) + if (sge->adapter->port[0].dev->hw_features & NETIF_F_TSO) en &= ~F_PACKET_TOO_BIG; writel(en, sge->adapter->regs + A_SG_INT_ENABLE); writel(val | SGE_PL_INTR_MASK, sge->adapter->regs + A_PL_ENABLE); @@ -952,7 +952,7 @@ int t1_sge_intr_error_handler(struct sge *sge) struct adapter *adapter = sge->adapter; u32 cause = readl(adapter->regs + A_SG_INT_CAUSE); - if (adapter->flags & TSO_CAPABLE) + if (adapter->port[0].dev->hw_features & NETIF_F_TSO) cause &= ~F_PACKET_TOO_BIG; if (cause & F_RESPQ_EXHAUSTED) sge->stats.respQ_empty++; @@ -1369,6 +1369,7 @@ static void sge_rx(struct sge *sge, struct freelQ *fl, unsigned int len) const struct cpl_rx_pkt *p; struct adapter *adapter = sge->adapter; struct sge_port_stats *st; + struct net_device *dev; skb = get_packet(adapter->pdev, fl, len - sge->rx_pkt_pad); if (unlikely(!skb)) { @@ -1384,9 +1385,10 @@ static void sge_rx(struct sge *sge, struct freelQ *fl, unsigned int len) __skb_pull(skb, sizeof(*p)); st = this_cpu_ptr(sge->port_stats[p->iff]); + dev = adapter->port[p->iff].dev; - skb->protocol = eth_type_trans(skb, adapter->port[p->iff].dev); - if ((adapter->flags & RX_CSUM_ENABLED) && p->csum == 0xffff && + skb->protocol = eth_type_trans(skb, dev); + if ((dev->features & NETIF_F_RXCSUM) && p->csum == 0xffff && skb->protocol == htons(ETH_P_IP) && (skb->data[9] == IPPROTO_TCP || skb->data[9] == IPPROTO_UDP)) { ++st->rx_cso_good; @@ -1838,8 +1840,7 @@ netdev_tx_t t1_start_xmit(struct sk_buff *skb, struct net_device *dev) return NETDEV_TX_OK; } - if (!(adapter->flags & UDP_CSUM_CAPABLE) && - skb->ip_summed == CHECKSUM_PARTIAL && + if (skb->ip_summed == CHECKSUM_PARTIAL && ip_hdr(skb)->protocol == IPPROTO_UDP) { if (unlikely(skb_checksum_help(skb))) { pr_debug("%s: unable to do udp checksum\n", dev->name); diff --git a/drivers/net/chelsio/tp.c b/drivers/net/chelsio/tp.c index 6222d58..8bed4a5 100644 --- a/drivers/net/chelsio/tp.c +++ b/drivers/net/chelsio/tp.c @@ -152,11 +152,6 @@ void t1_tp_set_ip_checksum_offload(struct petp *tp, int enable) set_csum_offload(tp, F_IP_CSUM, enable); } -void t1_tp_set_udp_checksum_offload(struct petp *tp, int enable) -{ - set_csum_offload(tp, F_UDP_CSUM, enable); -} - void t1_tp_set_tcp_checksum_offload(struct petp *tp, int enable) { set_csum_offload(tp, F_TCP_CSUM, enable); diff --git a/drivers/net/chelsio/tp.h b/drivers/net/chelsio/tp.h index 32fc71e..dfd8ce2 100644 --- a/drivers/net/chelsio/tp.h +++ b/drivers/net/chelsio/tp.h @@ -65,7 +65,6 @@ void t1_tp_intr_clear(struct petp *tp); int t1_tp_intr_handler(struct petp *tp); void t1_tp_get_mib_statistics(adapter_t *adap, struct tp_mib_statistics *tps); -void t1_tp_set_udp_checksum_offload(struct petp *tp, int enable); void t1_tp_set_tcp_checksum_offload(struct petp *tp, int enable); void t1_tp_set_ip_checksum_offload(struct petp *tp, int enable); int t1_tp_set_coalescing_size(struct petp *tp, unsigned int size); -- cgit v0.10.2 From feb990d467f76abe90ae68437eb1db351e67c674 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Miros=C5=82aw?= Date: Mon, 18 Apr 2011 13:31:21 +0000 Subject: net: vxge: convert to hw_features MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Side effect: ->gro_enable is removed as napi_gro_receive() does the fallback itself. Signed-off-by: MichaÅ‚ MirosÅ‚aw Signed-off-by: David S. Miller diff --git a/drivers/net/vxge/vxge-ethtool.c b/drivers/net/vxge/vxge-ethtool.c index 43c4583..5aef6c8 100644 --- a/drivers/net/vxge/vxge-ethtool.c +++ b/drivers/net/vxge/vxge-ethtool.c @@ -1071,35 +1071,6 @@ static int vxge_ethtool_get_regs_len(struct net_device *dev) return sizeof(struct vxge_hw_vpath_reg) * vdev->no_of_vpath; } -static u32 vxge_get_rx_csum(struct net_device *dev) -{ - struct vxgedev *vdev = netdev_priv(dev); - - return vdev->rx_csum; -} - -static int vxge_set_rx_csum(struct net_device *dev, u32 data) -{ - struct vxgedev *vdev = netdev_priv(dev); - - if (data) - vdev->rx_csum = 1; - else - vdev->rx_csum = 0; - - return 0; -} - -static int vxge_ethtool_op_set_tso(struct net_device *dev, u32 data) -{ - if (data) - dev->features |= (NETIF_F_TSO | NETIF_F_TSO6); - else - dev->features &= ~(NETIF_F_TSO | NETIF_F_TSO6); - - return 0; -} - static int vxge_ethtool_get_sset_count(struct net_device *dev, int sset) { struct vxgedev *vdev = netdev_priv(dev); @@ -1119,40 +1090,6 @@ static int vxge_ethtool_get_sset_count(struct net_device *dev, int sset) } } -static int vxge_set_flags(struct net_device *dev, u32 data) -{ - struct vxgedev *vdev = netdev_priv(dev); - enum vxge_hw_status status; - - if (ethtool_invalid_flags(dev, data, ETH_FLAG_RXHASH)) - return -EINVAL; - - if (!!(data & ETH_FLAG_RXHASH) == vdev->devh->config.rth_en) - return 0; - - if (netif_running(dev) || (vdev->config.rth_steering == NO_STEERING)) - return -EINVAL; - - vdev->devh->config.rth_en = !!(data & ETH_FLAG_RXHASH); - - /* Enabling RTH requires some of the logic in vxge_device_register and a - * vpath reset. Due to these restrictions, only allow modification - * while the interface is down. - */ - status = vxge_reset_all_vpaths(vdev); - if (status != VXGE_HW_OK) { - vdev->devh->config.rth_en = !vdev->devh->config.rth_en; - return -EFAULT; - } - - if (vdev->devh->config.rth_en) - dev->features |= NETIF_F_RXHASH; - else - dev->features &= ~NETIF_F_RXHASH; - - return 0; -} - static int vxge_fw_flash(struct net_device *dev, struct ethtool_flash *parms) { struct vxgedev *vdev = netdev_priv(dev); @@ -1181,19 +1118,10 @@ static const struct ethtool_ops vxge_ethtool_ops = { .get_link = ethtool_op_get_link, .get_pauseparam = vxge_ethtool_getpause_data, .set_pauseparam = vxge_ethtool_setpause_data, - .get_rx_csum = vxge_get_rx_csum, - .set_rx_csum = vxge_set_rx_csum, - .get_tx_csum = ethtool_op_get_tx_csum, - .set_tx_csum = ethtool_op_set_tx_ipv6_csum, - .get_sg = ethtool_op_get_sg, - .set_sg = ethtool_op_set_sg, - .get_tso = ethtool_op_get_tso, - .set_tso = vxge_ethtool_op_set_tso, .get_strings = vxge_ethtool_get_strings, .set_phys_id = vxge_ethtool_idnic, .get_sset_count = vxge_ethtool_get_sset_count, .get_ethtool_stats = vxge_get_ethtool_stats, - .set_flags = vxge_set_flags, .flash_device = vxge_fw_flash, }; diff --git a/drivers/net/vxge/vxge-main.c b/drivers/net/vxge/vxge-main.c index d192dad..fc837cf 100644 --- a/drivers/net/vxge/vxge-main.c +++ b/drivers/net/vxge/vxge-main.c @@ -304,22 +304,14 @@ vxge_rx_complete(struct vxge_ring *ring, struct sk_buff *skb, u16 vlan, "%s: %s:%d skb protocol = %d", ring->ndev->name, __func__, __LINE__, skb->protocol); - if (ring->gro_enable) { - if (ring->vlgrp && ext_info->vlan && - (ring->vlan_tag_strip == - VXGE_HW_VPATH_RPA_STRIP_VLAN_TAG_ENABLE)) - vlan_gro_receive(ring->napi_p, ring->vlgrp, - ext_info->vlan, skb); - else - napi_gro_receive(ring->napi_p, skb); - } else { - if (ring->vlgrp && vlan && - (ring->vlan_tag_strip == - VXGE_HW_VPATH_RPA_STRIP_VLAN_TAG_ENABLE)) - vlan_hwaccel_receive_skb(skb, ring->vlgrp, vlan); - else - netif_receive_skb(skb); - } + if (ring->vlgrp && ext_info->vlan && + (ring->vlan_tag_strip == + VXGE_HW_VPATH_RPA_STRIP_VLAN_TAG_ENABLE)) + vlan_gro_receive(ring->napi_p, ring->vlgrp, + ext_info->vlan, skb); + else + napi_gro_receive(ring->napi_p, skb); + vxge_debug_entryexit(VXGE_TRACE, "%s: %s:%d Exiting...", ring->ndev->name, __func__, __LINE__); } @@ -490,7 +482,7 @@ vxge_rx_1b_compl(struct __vxge_hw_ring *ringh, void *dtr, if ((ext_info.proto & VXGE_HW_FRAME_PROTO_TCP_OR_UDP) && !(ext_info.proto & VXGE_HW_FRAME_PROTO_IP_FRAG) && - ring->rx_csum && /* Offload Rx side CSUM */ + (dev->features & NETIF_F_RXCSUM) && /* Offload Rx side CSUM */ ext_info.l3_cksum == VXGE_HW_L3_CKSUM_OK && ext_info.l4_cksum == VXGE_HW_L4_CKSUM_OK) skb->ip_summed = CHECKSUM_UNNECESSARY; @@ -2094,11 +2086,9 @@ static int vxge_open_vpaths(struct vxgedev *vdev) vdev->config.fifo_indicate_max_pkts; vpath->fifo.tx_vector_no = 0; vpath->ring.rx_vector_no = 0; - vpath->ring.rx_csum = vdev->rx_csum; vpath->ring.rx_hwts = vdev->rx_hwts; vpath->is_open = 1; vdev->vp_handles[i] = vpath->handle; - vpath->ring.gro_enable = vdev->config.gro_enable; vpath->ring.vlan_tag_strip = vdev->vlan_tag_strip; vdev->stats.vpaths_open++; } else { @@ -2670,6 +2660,40 @@ static void vxge_poll_vp_lockup(unsigned long data) mod_timer(&vdev->vp_lockup_timer, jiffies + HZ / 1000); } +static u32 vxge_fix_features(struct net_device *dev, u32 features) +{ + u32 changed = dev->features ^ features; + + /* Enabling RTH requires some of the logic in vxge_device_register and a + * vpath reset. Due to these restrictions, only allow modification + * while the interface is down. + */ + if ((changed & NETIF_F_RXHASH) && netif_running(dev)) + features ^= NETIF_F_RXHASH; + + return features; +} + +static int vxge_set_features(struct net_device *dev, u32 features) +{ + struct vxgedev *vdev = netdev_priv(dev); + u32 changed = dev->features ^ features; + + if (!(changed & NETIF_F_RXHASH)) + return 0; + + /* !netif_running() ensured by vxge_fix_features() */ + + vdev->devh->config.rth_en = !!(features & NETIF_F_RXHASH); + if (vxge_reset_all_vpaths(vdev) != VXGE_HW_OK) { + dev->features = features ^ NETIF_F_RXHASH; + vdev->devh->config.rth_en = !!(dev->features & NETIF_F_RXHASH); + return -EIO; + } + + return 0; +} + /** * vxge_open * @dev: pointer to the device structure. @@ -3369,6 +3393,8 @@ static const struct net_device_ops vxge_netdev_ops = { .ndo_do_ioctl = vxge_ioctl, .ndo_set_mac_address = vxge_set_mac_addr, .ndo_change_mtu = vxge_change_mtu, + .ndo_fix_features = vxge_fix_features, + .ndo_set_features = vxge_set_features, .ndo_vlan_rx_register = vxge_vlan_rx_register, .ndo_vlan_rx_kill_vid = vxge_vlan_rx_kill_vid, .ndo_vlan_rx_add_vid = vxge_vlan_rx_add_vid, @@ -3415,14 +3441,21 @@ static int __devinit vxge_device_register(struct __vxge_hw_device *hldev, vdev->devh = hldev; vdev->pdev = hldev->pdev; memcpy(&vdev->config, config, sizeof(struct vxge_config)); - vdev->rx_csum = 1; /* Enable Rx CSUM by default. */ vdev->rx_hwts = 0; vdev->titan1 = (vdev->pdev->revision == VXGE_HW_TITAN1_PCI_REVISION); SET_NETDEV_DEV(ndev, &vdev->pdev->dev); - ndev->features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX | - NETIF_F_HW_VLAN_FILTER; + ndev->hw_features = NETIF_F_RXCSUM | NETIF_F_SG | + NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM | + NETIF_F_TSO | NETIF_F_TSO6 | + NETIF_F_HW_VLAN_TX; + if (vdev->config.rth_steering != NO_STEERING) + ndev->hw_features |= NETIF_F_RXHASH; + + ndev->features |= ndev->hw_features | + NETIF_F_HW_VLAN_RX | NETIF_F_HW_VLAN_FILTER; + /* Driver entry points */ ndev->irq = vdev->pdev->irq; ndev->base_addr = (unsigned long) hldev->bar0; @@ -3434,11 +3467,6 @@ static int __devinit vxge_device_register(struct __vxge_hw_device *hldev, vxge_initialize_ethtool_ops(ndev); - if (vdev->config.rth_steering != NO_STEERING) { - ndev->features |= NETIF_F_RXHASH; - hldev->config.rth_en = VXGE_HW_RTH_ENABLE; - } - /* Allocate memory for vpath */ vdev->vpaths = kzalloc((sizeof(struct vxge_vpath)) * no_of_vpath, GFP_KERNEL); @@ -3450,9 +3478,6 @@ static int __devinit vxge_device_register(struct __vxge_hw_device *hldev, goto _out1; } - ndev->features |= NETIF_F_SG; - - ndev->features |= NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM; vxge_debug_init(vxge_hw_device_trace_level_get(hldev), "%s : checksuming enabled", __func__); @@ -3462,11 +3487,6 @@ static int __devinit vxge_device_register(struct __vxge_hw_device *hldev, "%s : using High DMA", __func__); } - ndev->features |= NETIF_F_TSO | NETIF_F_TSO6; - - if (vdev->config.gro_enable) - ndev->features |= NETIF_F_GRO; - ret = register_netdev(ndev); if (ret) { vxge_debug_init(vxge_hw_device_trace_level_get(hldev), @@ -3996,15 +4016,6 @@ static void __devinit vxge_print_parm(struct vxgedev *vdev, u64 vpath_mask) vdev->config.tx_steering_type = 0; } - if (vdev->config.gro_enable) { - vxge_debug_init(VXGE_ERR, - "%s: Generic receive offload enabled", - vdev->ndev->name); - } else - vxge_debug_init(VXGE_TRACE, - "%s: Generic receive offload disabled", - vdev->ndev->name); - if (vdev->config.addr_learn_en) vxge_debug_init(VXGE_TRACE, "%s: MAC Address learning enabled", vdev->ndev->name); @@ -4589,7 +4600,6 @@ vxge_probe(struct pci_dev *pdev, const struct pci_device_id *pre) /* set private device info */ pci_set_drvdata(pdev, hldev); - ll_config->gro_enable = VXGE_GRO_ALWAYS_AGGREGATE; ll_config->fifo_indicate_max_pkts = VXGE_FIFO_INDICATE_MAX_PKTS; ll_config->addr_learn_en = addr_learn_en; ll_config->rth_algorithm = RTH_ALG_JENKINS; diff --git a/drivers/net/vxge/vxge-main.h b/drivers/net/vxge/vxge-main.h index 40474f0..ed120ab 100644 --- a/drivers/net/vxge/vxge-main.h +++ b/drivers/net/vxge/vxge-main.h @@ -168,9 +168,6 @@ struct vxge_config { #define NEW_NAPI_WEIGHT 64 int napi_weight; -#define VXGE_GRO_DONOT_AGGREGATE 0 -#define VXGE_GRO_ALWAYS_AGGREGATE 1 - int gro_enable; int intr_type; #define INTA 0 #define MSI 1 @@ -290,13 +287,11 @@ struct vxge_ring { unsigned long interrupt_count; unsigned long jiffies; - /* copy of the flag indicating whether rx_csum is to be used */ - u32 rx_csum:1, - rx_hwts:1; + /* copy of the flag indicating whether rx_hwts is to be used */ + u32 rx_hwts:1; int pkts_processed; int budget; - int gro_enable; struct napi_struct napi; struct napi_struct *napi_p; @@ -369,9 +364,8 @@ struct vxgedev { */ u16 all_multi_flg; - /* A flag indicating whether rx_csum is to be used or not. */ - u32 rx_csum:1, - rx_hwts:1, + /* A flag indicating whether rx_hwts is to be used or not. */ + u32 rx_hwts:1, titan1:1; struct vxge_msix_entry *vxge_entries; -- cgit v0.10.2 From a0d2730c9571aeba793cb5d3009094ee1d8fda35 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Miros=C5=82aw?= Date: Mon, 18 Apr 2011 13:31:21 +0000 Subject: net: vmxnet3: convert to hw_features MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This also removes private feature flags that were always set to true. You may want to move vmxnet3_set_features() to vmxnet3_drv.c as a following cleanup. Signed-off-by: MichaÅ‚ MirosÅ‚aw Signed-off-by: David S. Miller diff --git a/drivers/net/vmxnet3/vmxnet3_drv.c b/drivers/net/vmxnet3/vmxnet3_drv.c index 0d47c3a..7a494f7 100644 --- a/drivers/net/vmxnet3/vmxnet3_drv.c +++ b/drivers/net/vmxnet3/vmxnet3_drv.c @@ -1082,7 +1082,7 @@ vmxnet3_rx_csum(struct vmxnet3_adapter *adapter, struct sk_buff *skb, union Vmxnet3_GenericDesc *gdesc) { - if (!gdesc->rcd.cnc && adapter->rxcsum) { + if (!gdesc->rcd.cnc && adapter->netdev->features & NETIF_F_RXCSUM) { /* typical case: TCP/UDP over IP and both csums are correct */ if ((le32_to_cpu(gdesc->dword[3]) & VMXNET3_RCD_CSUM_OK) == VMXNET3_RCD_CSUM_OK) { @@ -2081,10 +2081,10 @@ vmxnet3_setup_driver_shared(struct vmxnet3_adapter *adapter) devRead->misc.ddLen = cpu_to_le32(sizeof(struct vmxnet3_adapter)); /* set up feature flags */ - if (adapter->rxcsum) + if (adapter->netdev->features & NETIF_F_RXCSUM) devRead->misc.uptFeatures |= UPT1_F_RXCSUM; - if (adapter->lro) { + if (adapter->netdev->features & NETIF_F_LRO) { devRead->misc.uptFeatures |= UPT1_F_LRO; devRead->misc.maxNumRxSG = cpu_to_le16(1 + MAX_SKB_FRAGS); } @@ -2593,9 +2593,6 @@ vmxnet3_change_mtu(struct net_device *netdev, int new_mtu) if (new_mtu < VMXNET3_MIN_MTU || new_mtu > VMXNET3_MAX_MTU) return -EINVAL; - if (new_mtu > 1500 && !adapter->jumbo_frame) - return -EINVAL; - netdev->mtu = new_mtu; /* @@ -2641,28 +2638,18 @@ vmxnet3_declare_features(struct vmxnet3_adapter *adapter, bool dma64) { struct net_device *netdev = adapter->netdev; - netdev->features = NETIF_F_SG | - NETIF_F_HW_CSUM | - NETIF_F_HW_VLAN_TX | - NETIF_F_HW_VLAN_RX | - NETIF_F_HW_VLAN_FILTER | - NETIF_F_TSO | - NETIF_F_TSO6 | - NETIF_F_LRO; - - printk(KERN_INFO "features: sg csum vlan jf tso tsoIPv6 lro"); - - adapter->rxcsum = true; - adapter->jumbo_frame = true; - adapter->lro = true; - - if (dma64) { + netdev->hw_features = NETIF_F_SG | NETIF_F_RXCSUM | + NETIF_F_HW_CSUM | NETIF_F_HW_VLAN_TX | + NETIF_F_TSO | NETIF_F_TSO6 | NETIF_F_LRO; + if (dma64) netdev->features |= NETIF_F_HIGHDMA; - printk(" highDMA"); - } + netdev->vlan_features = netdev->hw_features & ~NETIF_F_HW_VLAN_TX; + netdev->features = netdev->hw_features | + NETIF_F_HW_VLAN_RX | NETIF_F_HW_VLAN_FILTER; - netdev->vlan_features = netdev->features; - printk("\n"); + netdev_info(adapter->netdev, + "features: sg csum vlan jf tso tsoIPv6 lro%s\n", + dma64 ? " highDMA" : ""); } @@ -2874,6 +2861,7 @@ vmxnet3_probe_device(struct pci_dev *pdev, .ndo_start_xmit = vmxnet3_xmit_frame, .ndo_set_mac_address = vmxnet3_set_mac_addr, .ndo_change_mtu = vmxnet3_change_mtu, + .ndo_set_features = vmxnet3_set_features, .ndo_get_stats = vmxnet3_get_stats, .ndo_tx_timeout = vmxnet3_tx_timeout, .ndo_set_multicast_list = vmxnet3_set_mc, diff --git a/drivers/net/vmxnet3/vmxnet3_ethtool.c b/drivers/net/vmxnet3/vmxnet3_ethtool.c index 51f2ef1..70c1ab9 100644 --- a/drivers/net/vmxnet3/vmxnet3_ethtool.c +++ b/drivers/net/vmxnet3/vmxnet3_ethtool.c @@ -33,40 +33,6 @@ struct vmxnet3_stat_desc { }; -static u32 -vmxnet3_get_rx_csum(struct net_device *netdev) -{ - struct vmxnet3_adapter *adapter = netdev_priv(netdev); - return adapter->rxcsum; -} - - -static int -vmxnet3_set_rx_csum(struct net_device *netdev, u32 val) -{ - struct vmxnet3_adapter *adapter = netdev_priv(netdev); - unsigned long flags; - - if (adapter->rxcsum != val) { - adapter->rxcsum = val; - if (netif_running(netdev)) { - if (val) - adapter->shared->devRead.misc.uptFeatures |= - UPT1_F_RXCSUM; - else - adapter->shared->devRead.misc.uptFeatures &= - ~UPT1_F_RXCSUM; - - spin_lock_irqsave(&adapter->cmd_lock, flags); - VMXNET3_WRITE_BAR1_REG(adapter, VMXNET3_REG_CMD, - VMXNET3_CMD_UPDATE_FEATURE); - spin_unlock_irqrestore(&adapter->cmd_lock, flags); - } - } - return 0; -} - - /* per tq stats maintained by the device */ static const struct vmxnet3_stat_desc vmxnet3_tq_dev_stats[] = { @@ -296,28 +262,27 @@ vmxnet3_get_strings(struct net_device *netdev, u32 stringset, u8 *buf) } } -static int -vmxnet3_set_flags(struct net_device *netdev, u32 data) +int vmxnet3_set_features(struct net_device *netdev, u32 features) { struct vmxnet3_adapter *adapter = netdev_priv(netdev); - u8 lro_requested = (data & ETH_FLAG_LRO) == 0 ? 0 : 1; - u8 lro_present = (netdev->features & NETIF_F_LRO) == 0 ? 0 : 1; unsigned long flags; + u32 changed = features ^ netdev->features; - if (ethtool_invalid_flags(netdev, data, ETH_FLAG_LRO)) - return -EINVAL; - - if (lro_requested ^ lro_present) { - /* toggle the LRO feature*/ - netdev->features ^= NETIF_F_LRO; + if (changed & (NETIF_F_RXCSUM|NETIF_F_LRO)) { + if (features & NETIF_F_RXCSUM) + adapter->shared->devRead.misc.uptFeatures |= + UPT1_F_RXCSUM; + else + adapter->shared->devRead.misc.uptFeatures &= + ~UPT1_F_RXCSUM; - /* update harware LRO capability accordingly */ - if (lro_requested) + if (features & NETIF_F_LRO) adapter->shared->devRead.misc.uptFeatures |= UPT1_F_LRO; else adapter->shared->devRead.misc.uptFeatures &= ~UPT1_F_LRO; + spin_lock_irqsave(&adapter->cmd_lock, flags); VMXNET3_WRITE_BAR1_REG(adapter, VMXNET3_REG_CMD, VMXNET3_CMD_UPDATE_FEATURE); @@ -654,17 +619,7 @@ static struct ethtool_ops vmxnet3_ethtool_ops = { .get_wol = vmxnet3_get_wol, .set_wol = vmxnet3_set_wol, .get_link = ethtool_op_get_link, - .get_rx_csum = vmxnet3_get_rx_csum, - .set_rx_csum = vmxnet3_set_rx_csum, - .get_tx_csum = ethtool_op_get_tx_csum, - .set_tx_csum = ethtool_op_set_tx_hw_csum, - .get_sg = ethtool_op_get_sg, - .set_sg = ethtool_op_set_sg, - .get_tso = ethtool_op_get_tso, - .set_tso = ethtool_op_set_tso, .get_strings = vmxnet3_get_strings, - .get_flags = ethtool_op_get_flags, - .set_flags = vmxnet3_set_flags, .get_sset_count = vmxnet3_get_sset_count, .get_ethtool_stats = vmxnet3_get_ethtool_stats, .get_ringparam = vmxnet3_get_ringparam, diff --git a/drivers/net/vmxnet3/vmxnet3_int.h b/drivers/net/vmxnet3/vmxnet3_int.h index fb5d245..8ba7b5f 100644 --- a/drivers/net/vmxnet3/vmxnet3_int.h +++ b/drivers/net/vmxnet3/vmxnet3_int.h @@ -329,10 +329,6 @@ struct vmxnet3_adapter { u8 __iomem *hw_addr0; /* for BAR 0 */ u8 __iomem *hw_addr1; /* for BAR 1 */ - /* feature control */ - bool rxcsum; - bool lro; - bool jumbo_frame; #ifdef VMXNET3_RSS struct UPT1_RSSConf *rss_conf; bool rss; @@ -404,6 +400,9 @@ void vmxnet3_rq_destroy_all(struct vmxnet3_adapter *adapter); int +vmxnet3_set_features(struct net_device *netdev, u32 features); + +int vmxnet3_create_queues(struct vmxnet3_adapter *adapter, u32 tx_ring_size, u32 rx_ring_size, u32 rx_ring2_size); -- cgit v0.10.2 From 88230fd586b4ccc5ffe6d6c2df8cdc495e89ad83 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Miros=C5=82aw?= Date: Mon, 18 Apr 2011 13:31:21 +0000 Subject: net: qlge: convert to hw_features MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Another simple conversion. Signed-off-by: MichaÅ‚ MirosÅ‚aw Signed-off-by: David S. Miller diff --git a/drivers/net/qlge/qlge_ethtool.c b/drivers/net/qlge/qlge_ethtool.c index 687754d..78dc40c 100644 --- a/drivers/net/qlge/qlge_ethtool.c +++ b/drivers/net/qlge/qlge_ethtool.c @@ -655,32 +655,6 @@ static int ql_set_pauseparam(struct net_device *netdev, return status; } -static u32 ql_get_rx_csum(struct net_device *netdev) -{ - struct ql_adapter *qdev = netdev_priv(netdev); - return qdev->rx_csum; -} - -static int ql_set_rx_csum(struct net_device *netdev, uint32_t data) -{ - struct ql_adapter *qdev = netdev_priv(netdev); - qdev->rx_csum = data; - return 0; -} - -static int ql_set_tso(struct net_device *ndev, uint32_t data) -{ - - if (data) { - ndev->features |= NETIF_F_TSO; - ndev->features |= NETIF_F_TSO6; - } else { - ndev->features &= ~NETIF_F_TSO; - ndev->features &= ~NETIF_F_TSO6; - } - return 0; -} - static u32 ql_get_msglevel(struct net_device *ndev) { struct ql_adapter *qdev = netdev_priv(ndev); @@ -707,14 +681,6 @@ const struct ethtool_ops qlge_ethtool_ops = { .self_test = ql_self_test, .get_pauseparam = ql_get_pauseparam, .set_pauseparam = ql_set_pauseparam, - .get_rx_csum = ql_get_rx_csum, - .set_rx_csum = ql_set_rx_csum, - .get_tx_csum = ethtool_op_get_tx_csum, - .set_tx_csum = ethtool_op_set_tx_csum, - .get_sg = ethtool_op_get_sg, - .set_sg = ethtool_op_set_sg, - .get_tso = ethtool_op_get_tso, - .set_tso = ql_set_tso, .get_coalesce = ql_get_coalesce, .set_coalesce = ql_set_coalesce, .get_sset_count = ql_get_sset_count, diff --git a/drivers/net/qlge/qlge_main.c b/drivers/net/qlge/qlge_main.c index f61e717..6c9d124 100644 --- a/drivers/net/qlge/qlge_main.c +++ b/drivers/net/qlge/qlge_main.c @@ -1571,7 +1571,7 @@ static void ql_process_mac_rx_page(struct ql_adapter *qdev, skb->protocol = eth_type_trans(skb, ndev); skb_checksum_none_assert(skb); - if (qdev->rx_csum && + if ((ndev->features & NETIF_F_RXCSUM) && !(ib_mac_rsp->flags1 & IB_MAC_CSUM_ERR_MASK)) { /* TCP frame. */ if (ib_mac_rsp->flags2 & IB_MAC_IOCB_RSP_T) { @@ -1684,7 +1684,7 @@ static void ql_process_mac_rx_skb(struct ql_adapter *qdev, /* If rx checksum is on, and there are no * csum or frame errors. */ - if (qdev->rx_csum && + if ((ndev->features & NETIF_F_RXCSUM) && !(ib_mac_rsp->flags1 & IB_MAC_CSUM_ERR_MASK)) { /* TCP frame. */ if (ib_mac_rsp->flags2 & IB_MAC_IOCB_RSP_T) { @@ -2004,7 +2004,7 @@ static void ql_process_mac_split_rx_intr(struct ql_adapter *qdev, /* If rx checksum is on, and there are no * csum or frame errors. */ - if (qdev->rx_csum && + if ((ndev->features & NETIF_F_RXCSUM) && !(ib_mac_rsp->flags1 & IB_MAC_CSUM_ERR_MASK)) { /* TCP frame. */ if (ib_mac_rsp->flags2 & IB_MAC_IOCB_RSP_T) { @@ -4621,7 +4621,6 @@ static int __devinit ql_init_device(struct pci_dev *pdev, /* * Set up the operating parameters. */ - qdev->rx_csum = 1; qdev->workqueue = create_singlethread_workqueue(ndev->name); INIT_DELAYED_WORK(&qdev->asic_reset_work, ql_asic_reset_work); INIT_DELAYED_WORK(&qdev->mpi_reset_work, ql_mpi_reset_work); @@ -4695,15 +4694,11 @@ static int __devinit qlge_probe(struct pci_dev *pdev, qdev = netdev_priv(ndev); SET_NETDEV_DEV(ndev, &pdev->dev); - ndev->features = (0 - | NETIF_F_IP_CSUM - | NETIF_F_SG - | NETIF_F_TSO - | NETIF_F_TSO6 - | NETIF_F_TSO_ECN - | NETIF_F_HW_VLAN_TX - | NETIF_F_HW_VLAN_RX | NETIF_F_HW_VLAN_FILTER); - ndev->features |= NETIF_F_GRO; + ndev->hw_features = NETIF_F_SG | NETIF_F_IP_CSUM | + NETIF_F_TSO | NETIF_F_TSO6 | NETIF_F_TSO_ECN | + NETIF_F_HW_VLAN_TX | NETIF_F_RXCSUM; + ndev->features = ndev->hw_features | + NETIF_F_HW_VLAN_RX | NETIF_F_HW_VLAN_FILTER; if (test_bit(QL_DMA64, &qdev->flags)) ndev->features |= NETIF_F_HIGHDMA; -- cgit v0.10.2 From 5f45c69589b7d2953584e6cd0b31e35dbe960ad0 Mon Sep 17 00:00:00 2001 From: Jens Axboe Date: Tue, 19 Apr 2011 09:10:35 +0200 Subject: cfq-iosched: read_lock() does not always imply rcu_read_lock() For some configurations of CONFIG_PREEMPT that is not true. So get rid of __call_for_each_cic() and always uses the explicitly rcu_read_lock() protected call_for_each_cic() instead. This fixes a potential bug related to IO scheduler removal or online switching. Thanks to Paul McKenney for clarifying this. Signed-off-by: Jens Axboe diff --git a/block/cfq-iosched.c b/block/cfq-iosched.c index 46b0a1d..5b52011 100644 --- a/block/cfq-iosched.c +++ b/block/cfq-iosched.c @@ -2582,28 +2582,20 @@ static void cfq_put_queue(struct cfq_queue *cfqq) } /* - * Must always be called with the rcu_read_lock() held + * Call func for each cic attached to this ioc. */ static void -__call_for_each_cic(struct io_context *ioc, - void (*func)(struct io_context *, struct cfq_io_context *)) +call_for_each_cic(struct io_context *ioc, + void (*func)(struct io_context *, struct cfq_io_context *)) { struct cfq_io_context *cic; struct hlist_node *n; + rcu_read_lock(); + hlist_for_each_entry_rcu(cic, n, &ioc->cic_list, cic_list) func(ioc, cic); -} -/* - * Call func for each cic attached to this ioc. - */ -static void -call_for_each_cic(struct io_context *ioc, - void (*func)(struct io_context *, struct cfq_io_context *)) -{ - rcu_read_lock(); - __call_for_each_cic(ioc, func); rcu_read_unlock(); } @@ -2664,7 +2656,7 @@ static void cfq_free_io_context(struct io_context *ioc) * should be ok to iterate over the known list, we will see all cic's * since no new ones are added. */ - __call_for_each_cic(ioc, cic_free_func); + call_for_each_cic(ioc, cic_free_func); } static void cfq_put_cooperator(struct cfq_queue *cfqq) -- cgit v0.10.2 From 83112e688f5f05dea1e63787db9a6c16b2887a1d Mon Sep 17 00:00:00 2001 From: Andre Przywara Date: Sat, 16 Apr 2011 02:27:53 +0200 Subject: perf, x86: Fix pre-defined cache-misses event for AMD family 15h cpus With AMD cpu family 15h a unit mask was introduced for the Data Cache Miss event (0x041/L1-dcache-load-misses). We need to enable bit 0 (first data cache miss or streaming store to a 64 B cache line) of this mask to proper count data cache misses. Now we set this bit for all families and models. In case a PMU does not implement a unit mask for event 0x041 the bit is ignored. Signed-off-by: Andre Przywara Signed-off-by: Robert Richter Signed-off-by: Peter Zijlstra Link: http://lkml.kernel.org/r/1302913676-14352-2-git-send-email-robert.richter@amd.com Signed-off-by: Ingo Molnar diff --git a/arch/x86/kernel/cpu/perf_event_amd.c b/arch/x86/kernel/cpu/perf_event_amd.c index 461f62b..4e16138 100644 --- a/arch/x86/kernel/cpu/perf_event_amd.c +++ b/arch/x86/kernel/cpu/perf_event_amd.c @@ -8,7 +8,7 @@ static __initconst const u64 amd_hw_cache_event_ids [ C(L1D) ] = { [ C(OP_READ) ] = { [ C(RESULT_ACCESS) ] = 0x0040, /* Data Cache Accesses */ - [ C(RESULT_MISS) ] = 0x0041, /* Data Cache Misses */ + [ C(RESULT_MISS) ] = 0x0141, /* Data Cache Misses */ }, [ C(OP_WRITE) ] = { [ C(RESULT_ACCESS) ] = 0x0142, /* Data Cache Refills :system */ -- cgit v0.10.2 From 855357a21744e488cbee23a47d2b124035160a87 Mon Sep 17 00:00:00 2001 From: Robert Richter Date: Sat, 16 Apr 2011 02:27:54 +0200 Subject: perf, x86: Fix AMD family 15h FPU event constraints Depending on the unit mask settings some FPU events may be scheduled only on cpu counter #3. This patch fixes this. Signed-off-by: Robert Richter Signed-off-by: Peter Zijlstra Cc: Stephane Eranian Link: http://lkml.kernel.org/r/1302913676-14352-3-git-send-email-robert.richter@amd.com Signed-off-by: Ingo Molnar diff --git a/arch/x86/kernel/cpu/perf_event_amd.c b/arch/x86/kernel/cpu/perf_event_amd.c index 4e16138..cf4e369 100644 --- a/arch/x86/kernel/cpu/perf_event_amd.c +++ b/arch/x86/kernel/cpu/perf_event_amd.c @@ -427,7 +427,9 @@ static __initconst const struct x86_pmu amd_pmu = { * * Exceptions: * + * 0x000 FP PERF_CTL[3], PERF_CTL[5:3] (*) * 0x003 FP PERF_CTL[3] + * 0x004 FP PERF_CTL[3], PERF_CTL[5:3] (*) * 0x00B FP PERF_CTL[3] * 0x00D FP PERF_CTL[3] * 0x023 DE PERF_CTL[2:0] @@ -448,6 +450,8 @@ static __initconst const struct x86_pmu amd_pmu = { * 0x0DF LS PERF_CTL[5:0] * 0x1D6 EX PERF_CTL[5:0] * 0x1D8 EX PERF_CTL[5:0] + * + * (*) depending on the umask all FPU counters may be used */ static struct event_constraint amd_f15_PMC0 = EVENT_CONSTRAINT(0, 0x01, 0); @@ -460,18 +464,28 @@ static struct event_constraint amd_f15_PMC53 = EVENT_CONSTRAINT(0, 0x38, 0); static struct event_constraint * amd_get_event_constraints_f15h(struct cpu_hw_events *cpuc, struct perf_event *event) { - unsigned int event_code = amd_get_event_code(&event->hw); + struct hw_perf_event *hwc = &event->hw; + unsigned int event_code = amd_get_event_code(hwc); switch (event_code & AMD_EVENT_TYPE_MASK) { case AMD_EVENT_FP: switch (event_code) { + case 0x000: + if (!(hwc->config & 0x0000F000ULL)) + break; + if (!(hwc->config & 0x00000F00ULL)) + break; + return &amd_f15_PMC3; + case 0x004: + if (hweight_long(hwc->config & ARCH_PERFMON_EVENTSEL_UMASK) <= 1) + break; + return &amd_f15_PMC3; case 0x003: case 0x00B: case 0x00D: return &amd_f15_PMC3; - default: - return &amd_f15_PMC53; } + return &amd_f15_PMC53; case AMD_EVENT_LS: case AMD_EVENT_DC: case AMD_EVENT_EX_LS: -- cgit v0.10.2 From c8e5910edf8bbe2e5c6c35a4ef2a578cc7893b25 Mon Sep 17 00:00:00 2001 From: Robert Richter Date: Sat, 16 Apr 2011 02:27:55 +0200 Subject: perf, x86: Use ALTERNATIVE() to check for X86_FEATURE_PERFCTR_CORE Using ALTERNATIVE() when checking for X86_FEATURE_PERFCTR_CORE avoids an extra pointer chase and data cache hit. Signed-off-by: Robert Richter Signed-off-by: Peter Zijlstra Link: http://lkml.kernel.org/r/1302913676-14352-4-git-send-email-robert.richter@amd.com Signed-off-by: Ingo Molnar diff --git a/arch/x86/kernel/cpu/perf_event.c b/arch/x86/kernel/cpu/perf_event.c index eed3673a..224a84f 100644 --- a/arch/x86/kernel/cpu/perf_event.c +++ b/arch/x86/kernel/cpu/perf_event.c @@ -31,6 +31,7 @@ #include #include #include +#include #if 0 #undef wrmsrl @@ -363,12 +364,18 @@ again: return new_raw_count; } -/* using X86_FEATURE_PERFCTR_CORE to later implement ALTERNATIVE() here */ static inline int x86_pmu_addr_offset(int index) { - if (boot_cpu_has(X86_FEATURE_PERFCTR_CORE)) - return index << 1; - return index; + int offset; + + /* offset = X86_FEATURE_PERFCTR_CORE ? index << 1 : index */ + alternative_io(ASM_NOP2, + "shll $1, %%eax", + X86_FEATURE_PERFCTR_CORE, + "=a" (offset), + "a" (index)); + + return offset; } static inline unsigned int x86_pmu_config_addr(int index) -- cgit v0.10.2 From 69c80f3e9d3c569f8a3cee94ba1a324b5a7fa6b9 Mon Sep 17 00:00:00 2001 From: Venkatesh Pallipadi Date: Wed, 13 Apr 2011 18:21:09 -0700 Subject: sched: Make set_*_buddy() work on non-task entities Make set_*_buddy() work on non-task sched_entity, to facilitate the use of next_buddy to cache a group entity in cases where one of the tasks within that entity sleeps or gets preempted. set_skip_buddy() was incorrectly comparing the policy of task that is yielding to be not equal to SCHED_IDLE. Yielding should happen even when task yielding is SCHED_IDLE. This change removes the policy check on the yielding task. Signed-off-by: Venkatesh Pallipadi Signed-off-by: Peter Zijlstra Link: http://lkml.kernel.org/r/1302744070-30079-2-git-send-email-venki@google.com Signed-off-by: Ingo Molnar diff --git a/kernel/sched_fair.c b/kernel/sched_fair.c index 8744593..501ab63 100644 --- a/kernel/sched_fair.c +++ b/kernel/sched_fair.c @@ -1846,26 +1846,26 @@ wakeup_preempt_entity(struct sched_entity *curr, struct sched_entity *se) static void set_last_buddy(struct sched_entity *se) { - if (likely(task_of(se)->policy != SCHED_IDLE)) { - for_each_sched_entity(se) - cfs_rq_of(se)->last = se; - } + if (entity_is_task(se) && unlikely(task_of(se)->policy == SCHED_IDLE)) + return; + + for_each_sched_entity(se) + cfs_rq_of(se)->last = se; } static void set_next_buddy(struct sched_entity *se) { - if (likely(task_of(se)->policy != SCHED_IDLE)) { - for_each_sched_entity(se) - cfs_rq_of(se)->next = se; - } + if (entity_is_task(se) && unlikely(task_of(se)->policy == SCHED_IDLE)) + return; + + for_each_sched_entity(se) + cfs_rq_of(se)->next = se; } static void set_skip_buddy(struct sched_entity *se) { - if (likely(task_of(se)->policy != SCHED_IDLE)) { - for_each_sched_entity(se) - cfs_rq_of(se)->skip = se; - } + for_each_sched_entity(se) + cfs_rq_of(se)->skip = se; } /* -- cgit v0.10.2 From 2f36825b176f67e5c5228aa33d828bc39718811f Mon Sep 17 00:00:00 2001 From: Venkatesh Pallipadi Date: Thu, 14 Apr 2011 10:30:53 -0700 Subject: sched: Next buddy hint on sleep and preempt path When a task in a taskgroup sleeps, pick_next_task starts all the way back at the root and picks the task/taskgroup with the min vruntime across all runnable tasks. But when there are many frequently sleeping tasks across different taskgroups, it makes better sense to stay with same taskgroup for its slice period (or until all tasks in the taskgroup sleeps) instead of switching cross taskgroup on each sleep after a short runtime. This helps specifically where taskgroups corresponds to a process with multiple threads. The change reduces the number of CR3 switches in this case. Example: Two taskgroups with 2 threads each which are running for 2ms and sleeping for 1ms. Looking at sched:sched_switch shows: BEFORE: taskgroup_1 threads [5004, 5005], taskgroup_2 threads [5016, 5017] cpu-soaker-5004 [003] 3683.391089 cpu-soaker-5016 [003] 3683.393106 cpu-soaker-5005 [003] 3683.395119 cpu-soaker-5017 [003] 3683.397130 cpu-soaker-5004 [003] 3683.399143 cpu-soaker-5016 [003] 3683.401155 cpu-soaker-5005 [003] 3683.403168 cpu-soaker-5017 [003] 3683.405170 AFTER: taskgroup_1 threads [21890, 21891], taskgroup_2 threads [21934, 21935] cpu-soaker-21890 [003] 865.895494 cpu-soaker-21935 [003] 865.897506 cpu-soaker-21934 [003] 865.899520 cpu-soaker-21935 [003] 865.901532 cpu-soaker-21934 [003] 865.903543 cpu-soaker-21935 [003] 865.905546 cpu-soaker-21891 [003] 865.907548 cpu-soaker-21890 [003] 865.909560 cpu-soaker-21891 [003] 865.911571 cpu-soaker-21890 [003] 865.913582 cpu-soaker-21891 [003] 865.915594 cpu-soaker-21934 [003] 865.917606 Similar problem is there when there are multiple taskgroups and say a task A preempts currently running task B of taskgroup_1. On schedule, pick_next_task can pick an unrelated task on taskgroup_2. Here it would be better to give some preference to task B on pick_next_task. A simple (may be extreme case) benchmark I tried was tbench with 2 tbench client processes with 2 threads each running on a single CPU. Avg throughput across 5 50 sec runs was: BEFORE: 105.84 MB/sec AFTER: 112.42 MB/sec Signed-off-by: Venkatesh Pallipadi Acked-by: Rik van Riel Signed-off-by: Peter Zijlstra Link: http://lkml.kernel.org/r/1302802253-25760-1-git-send-email-venki@google.com Signed-off-by: Ingo Molnar diff --git a/kernel/sched_fair.c b/kernel/sched_fair.c index 501ab63..5280272 100644 --- a/kernel/sched_fair.c +++ b/kernel/sched_fair.c @@ -1344,6 +1344,8 @@ enqueue_task_fair(struct rq *rq, struct task_struct *p, int flags) hrtick_update(rq); } +static void set_next_buddy(struct sched_entity *se); + /* * The dequeue_task method is called before nr_running is * decreased. We remove the task from the rbtree and @@ -1353,14 +1355,22 @@ static void dequeue_task_fair(struct rq *rq, struct task_struct *p, int flags) { struct cfs_rq *cfs_rq; struct sched_entity *se = &p->se; + int task_sleep = flags & DEQUEUE_SLEEP; for_each_sched_entity(se) { cfs_rq = cfs_rq_of(se); dequeue_entity(cfs_rq, se, flags); /* Don't dequeue parent if it has other entities besides us */ - if (cfs_rq->load.weight) + if (cfs_rq->load.weight) { + /* + * Bias pick_next to pick a task from this cfs_rq, as + * p is sleeping when it is within its sched_slice. + */ + if (task_sleep && parent_entity(se)) + set_next_buddy(parent_entity(se)); break; + } flags |= DEQUEUE_SLEEP; } @@ -1877,12 +1887,15 @@ static void check_preempt_wakeup(struct rq *rq, struct task_struct *p, int wake_ struct sched_entity *se = &curr->se, *pse = &p->se; struct cfs_rq *cfs_rq = task_cfs_rq(curr); int scale = cfs_rq->nr_running >= sched_nr_latency; + int next_buddy_marked = 0; if (unlikely(se == pse)) return; - if (sched_feat(NEXT_BUDDY) && scale && !(wake_flags & WF_FORK)) + if (sched_feat(NEXT_BUDDY) && scale && !(wake_flags & WF_FORK)) { set_next_buddy(pse); + next_buddy_marked = 1; + } /* * We can come here with TIF_NEED_RESCHED already set from new task @@ -1910,8 +1923,15 @@ static void check_preempt_wakeup(struct rq *rq, struct task_struct *p, int wake_ update_curr(cfs_rq); find_matching_se(&se, &pse); BUG_ON(!pse); - if (wakeup_preempt_entity(se, pse) == 1) + if (wakeup_preempt_entity(se, pse) == 1) { + /* + * Bias pick_next to pick the sched entity that is + * triggering this preemption. + */ + if (!next_buddy_marked) + set_next_buddy(pse); goto preempt; + } return; -- cgit v0.10.2 From 057f3fadb347e9c51b07e1b277bbdda79f976768 Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Mon, 18 Apr 2011 11:24:34 +0200 Subject: sched: Fix sched_domain iterations vs. RCU Vladis Kletnieks reported a new RCU debug warning in the scheduler. Since commit dce840a08702b ("sched: Dynamically allocate sched_domain/ sched_group data-structures") the sched_domain trees are protected by RCU instead of RCU-sched. This means that we need to include rcu_read_lock() protection when we iterate them since disabling preemption doesn't suffice anymore. Reported-by: Valdis.Kletnieks@vt.edu Signed-off-by: Peter Zijlstra Link: http://lkml.kernel.org/r/1302882741.2388.241.camel@twins Signed-off-by: Ingo Molnar diff --git a/kernel/sched.c b/kernel/sched.c index 0cfe031..27d3e73 100644 --- a/kernel/sched.c +++ b/kernel/sched.c @@ -1208,11 +1208,17 @@ int get_nohz_timer_target(void) int i; struct sched_domain *sd; + rcu_read_lock(); for_each_domain(cpu, sd) { - for_each_cpu(i, sched_domain_span(sd)) - if (!idle_cpu(i)) - return i; + for_each_cpu(i, sched_domain_span(sd)) { + if (!idle_cpu(i)) { + cpu = i; + goto unlock; + } + } } +unlock: + rcu_read_unlock(); return cpu; } /* @@ -2415,12 +2421,14 @@ ttwu_stat(struct task_struct *p, int cpu, int wake_flags) struct sched_domain *sd; schedstat_inc(p, se.statistics.nr_wakeups_remote); + rcu_read_lock(); for_each_domain(this_cpu, sd) { if (cpumask_test_cpu(cpu, sched_domain_span(sd))) { schedstat_inc(sd, ttwu_wake_remote); break; } } + rcu_read_unlock(); } #endif /* CONFIG_SMP */ -- cgit v0.10.2 From aeafcbaf4fcfeb74aeed65609ea5ead48dfc09f8 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Thu, 31 Mar 2011 10:56:28 -0300 Subject: perf symbols: Give more useful names to 'self' parameters One more installment on an area that is mostly dormant. Suggested-by: Thomas Gleixner Cc: Frederic Weisbecker Cc: Ingo Molnar Cc: Mike Galbraith Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Stephane Eranian Cc: Thomas Gleixner Cc: Tom Zanussi LKML-Reference: Signed-off-by: Arnaldo Carvalho de Melo diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c index f06c10f..516876d 100644 --- a/tools/perf/util/symbol.c +++ b/tools/perf/util/symbol.c @@ -31,13 +31,13 @@ #define NT_GNU_BUILD_ID 3 #endif -static bool dso__build_id_equal(const struct dso *self, u8 *build_id); +static bool dso__build_id_equal(const struct dso *dso, u8 *build_id); static int elf_read_build_id(Elf *elf, void *bf, size_t size); static void dsos__add(struct list_head *head, struct dso *dso); static struct map *map__new2(u64 start, struct dso *dso, enum map_type type); -static int dso__load_kernel_sym(struct dso *self, struct map *map, +static int dso__load_kernel_sym(struct dso *dso, struct map *map, symbol_filter_t filter); -static int dso__load_guest_kernel_sym(struct dso *self, struct map *map, +static int dso__load_guest_kernel_sym(struct dso *dso, struct map *map, symbol_filter_t filter); static int vmlinux_path__nr_entries; static char **vmlinux_path; @@ -49,27 +49,27 @@ struct symbol_conf symbol_conf = { .symfs = "", }; -int dso__name_len(const struct dso *self) +int dso__name_len(const struct dso *dso) { if (verbose) - return self->long_name_len; + return dso->long_name_len; - return self->short_name_len; + return dso->short_name_len; } -bool dso__loaded(const struct dso *self, enum map_type type) +bool dso__loaded(const struct dso *dso, enum map_type type) { - return self->loaded & (1 << type); + return dso->loaded & (1 << type); } -bool dso__sorted_by_name(const struct dso *self, enum map_type type) +bool dso__sorted_by_name(const struct dso *dso, enum map_type type) { - return self->sorted_by_name & (1 << type); + return dso->sorted_by_name & (1 << type); } -static void dso__set_sorted_by_name(struct dso *self, enum map_type type) +static void dso__set_sorted_by_name(struct dso *dso, enum map_type type) { - self->sorted_by_name |= (1 << type); + dso->sorted_by_name |= (1 << type); } bool symbol_type__is_a(char symbol_type, enum map_type map_type) @@ -84,9 +84,9 @@ bool symbol_type__is_a(char symbol_type, enum map_type map_type) } } -static void symbols__fixup_end(struct rb_root *self) +static void symbols__fixup_end(struct rb_root *symbols) { - struct rb_node *nd, *prevnd = rb_first(self); + struct rb_node *nd, *prevnd = rb_first(symbols); struct symbol *curr, *prev; if (prevnd == NULL) @@ -107,10 +107,10 @@ static void symbols__fixup_end(struct rb_root *self) curr->end = roundup(curr->start, 4096); } -static void __map_groups__fixup_end(struct map_groups *self, enum map_type type) +static void __map_groups__fixup_end(struct map_groups *mg, enum map_type type) { struct map *prev, *curr; - struct rb_node *nd, *prevnd = rb_first(&self->maps[type]); + struct rb_node *nd, *prevnd = rb_first(&mg->maps[type]); if (prevnd == NULL) return; @@ -130,128 +130,128 @@ static void __map_groups__fixup_end(struct map_groups *self, enum map_type type) curr->end = ~0ULL; } -static void map_groups__fixup_end(struct map_groups *self) +static void map_groups__fixup_end(struct map_groups *mg) { int i; for (i = 0; i < MAP__NR_TYPES; ++i) - __map_groups__fixup_end(self, i); + __map_groups__fixup_end(mg, i); } static struct symbol *symbol__new(u64 start, u64 len, u8 binding, const char *name) { size_t namelen = strlen(name) + 1; - struct symbol *self = calloc(1, (symbol_conf.priv_size + - sizeof(*self) + namelen)); - if (self == NULL) + struct symbol *sym = calloc(1, (symbol_conf.priv_size + + sizeof(*sym) + namelen)); + if (sym == NULL) return NULL; if (symbol_conf.priv_size) - self = ((void *)self) + symbol_conf.priv_size; - - self->start = start; - self->end = len ? start + len - 1 : start; - self->binding = binding; - self->namelen = namelen - 1; + sym = ((void *)sym) + symbol_conf.priv_size; - pr_debug4("%s: %s %#" PRIx64 "-%#" PRIx64 "\n", __func__, name, start, self->end); + sym->start = start; + sym->end = len ? start + len - 1 : start; + sym->binding = binding; + sym->namelen = namelen - 1; - memcpy(self->name, name, namelen); + pr_debug4("%s: %s %#" PRIx64 "-%#" PRIx64 "\n", + __func__, name, start, sym->end); + memcpy(sym->name, name, namelen); - return self; + return sym; } -void symbol__delete(struct symbol *self) +void symbol__delete(struct symbol *sym) { - free(((void *)self) - symbol_conf.priv_size); + free(((void *)sym) - symbol_conf.priv_size); } -static size_t symbol__fprintf(struct symbol *self, FILE *fp) +static size_t symbol__fprintf(struct symbol *sym, FILE *fp) { return fprintf(fp, " %" PRIx64 "-%" PRIx64 " %c %s\n", - self->start, self->end, - self->binding == STB_GLOBAL ? 'g' : - self->binding == STB_LOCAL ? 'l' : 'w', - self->name); + sym->start, sym->end, + sym->binding == STB_GLOBAL ? 'g' : + sym->binding == STB_LOCAL ? 'l' : 'w', + sym->name); } -void dso__set_long_name(struct dso *self, char *name) +void dso__set_long_name(struct dso *dso, char *name) { if (name == NULL) return; - self->long_name = name; - self->long_name_len = strlen(name); + dso->long_name = name; + dso->long_name_len = strlen(name); } -static void dso__set_short_name(struct dso *self, const char *name) +static void dso__set_short_name(struct dso *dso, const char *name) { if (name == NULL) return; - self->short_name = name; - self->short_name_len = strlen(name); + dso->short_name = name; + dso->short_name_len = strlen(name); } -static void dso__set_basename(struct dso *self) +static void dso__set_basename(struct dso *dso) { - dso__set_short_name(self, basename(self->long_name)); + dso__set_short_name(dso, basename(dso->long_name)); } struct dso *dso__new(const char *name) { - struct dso *self = calloc(1, sizeof(*self) + strlen(name) + 1); + struct dso *dso = calloc(1, sizeof(*dso) + strlen(name) + 1); - if (self != NULL) { + if (dso != NULL) { int i; - strcpy(self->name, name); - dso__set_long_name(self, self->name); - dso__set_short_name(self, self->name); + strcpy(dso->name, name); + dso__set_long_name(dso, dso->name); + dso__set_short_name(dso, dso->name); for (i = 0; i < MAP__NR_TYPES; ++i) - self->symbols[i] = self->symbol_names[i] = RB_ROOT; - self->symtab_type = SYMTAB__NOT_FOUND; - self->loaded = 0; - self->sorted_by_name = 0; - self->has_build_id = 0; - self->kernel = DSO_TYPE_USER; - INIT_LIST_HEAD(&self->node); + dso->symbols[i] = dso->symbol_names[i] = RB_ROOT; + dso->symtab_type = SYMTAB__NOT_FOUND; + dso->loaded = 0; + dso->sorted_by_name = 0; + dso->has_build_id = 0; + dso->kernel = DSO_TYPE_USER; + INIT_LIST_HEAD(&dso->node); } - return self; + return dso; } -static void symbols__delete(struct rb_root *self) +static void symbols__delete(struct rb_root *symbols) { struct symbol *pos; - struct rb_node *next = rb_first(self); + struct rb_node *next = rb_first(symbols); while (next) { pos = rb_entry(next, struct symbol, rb_node); next = rb_next(&pos->rb_node); - rb_erase(&pos->rb_node, self); + rb_erase(&pos->rb_node, symbols); symbol__delete(pos); } } -void dso__delete(struct dso *self) +void dso__delete(struct dso *dso) { int i; for (i = 0; i < MAP__NR_TYPES; ++i) - symbols__delete(&self->symbols[i]); - if (self->sname_alloc) - free((char *)self->short_name); - if (self->lname_alloc) - free(self->long_name); - free(self); + symbols__delete(&dso->symbols[i]); + if (dso->sname_alloc) + free((char *)dso->short_name); + if (dso->lname_alloc) + free(dso->long_name); + free(dso); } -void dso__set_build_id(struct dso *self, void *build_id) +void dso__set_build_id(struct dso *dso, void *build_id) { - memcpy(self->build_id, build_id, sizeof(self->build_id)); - self->has_build_id = 1; + memcpy(dso->build_id, build_id, sizeof(dso->build_id)); + dso->has_build_id = 1; } -static void symbols__insert(struct rb_root *self, struct symbol *sym) +static void symbols__insert(struct rb_root *symbols, struct symbol *sym) { - struct rb_node **p = &self->rb_node; + struct rb_node **p = &symbols->rb_node; struct rb_node *parent = NULL; const u64 ip = sym->start; struct symbol *s; @@ -265,17 +265,17 @@ static void symbols__insert(struct rb_root *self, struct symbol *sym) p = &(*p)->rb_right; } rb_link_node(&sym->rb_node, parent, p); - rb_insert_color(&sym->rb_node, self); + rb_insert_color(&sym->rb_node, symbols); } -static struct symbol *symbols__find(struct rb_root *self, u64 ip) +static struct symbol *symbols__find(struct rb_root *symbols, u64 ip) { struct rb_node *n; - if (self == NULL) + if (symbols == NULL) return NULL; - n = self->rb_node; + n = symbols->rb_node; while (n) { struct symbol *s = rb_entry(n, struct symbol, rb_node); @@ -296,9 +296,9 @@ struct symbol_name_rb_node { struct symbol sym; }; -static void symbols__insert_by_name(struct rb_root *self, struct symbol *sym) +static void symbols__insert_by_name(struct rb_root *symbols, struct symbol *sym) { - struct rb_node **p = &self->rb_node; + struct rb_node **p = &symbols->rb_node; struct rb_node *parent = NULL; struct symbol_name_rb_node *symn, *s; @@ -313,27 +313,29 @@ static void symbols__insert_by_name(struct rb_root *self, struct symbol *sym) p = &(*p)->rb_right; } rb_link_node(&symn->rb_node, parent, p); - rb_insert_color(&symn->rb_node, self); + rb_insert_color(&symn->rb_node, symbols); } -static void symbols__sort_by_name(struct rb_root *self, struct rb_root *source) +static void symbols__sort_by_name(struct rb_root *symbols, + struct rb_root *source) { struct rb_node *nd; for (nd = rb_first(source); nd; nd = rb_next(nd)) { struct symbol *pos = rb_entry(nd, struct symbol, rb_node); - symbols__insert_by_name(self, pos); + symbols__insert_by_name(symbols, pos); } } -static struct symbol *symbols__find_by_name(struct rb_root *self, const char *name) +static struct symbol *symbols__find_by_name(struct rb_root *symbols, + const char *name) { struct rb_node *n; - if (self == NULL) + if (symbols == NULL) return NULL; - n = self->rb_node; + n = symbols->rb_node; while (n) { struct symbol_name_rb_node *s; @@ -353,29 +355,29 @@ static struct symbol *symbols__find_by_name(struct rb_root *self, const char *na return NULL; } -struct symbol *dso__find_symbol(struct dso *self, +struct symbol *dso__find_symbol(struct dso *dso, enum map_type type, u64 addr) { - return symbols__find(&self->symbols[type], addr); + return symbols__find(&dso->symbols[type], addr); } -struct symbol *dso__find_symbol_by_name(struct dso *self, enum map_type type, +struct symbol *dso__find_symbol_by_name(struct dso *dso, enum map_type type, const char *name) { - return symbols__find_by_name(&self->symbol_names[type], name); + return symbols__find_by_name(&dso->symbol_names[type], name); } -void dso__sort_by_name(struct dso *self, enum map_type type) +void dso__sort_by_name(struct dso *dso, enum map_type type) { - dso__set_sorted_by_name(self, type); - return symbols__sort_by_name(&self->symbol_names[type], - &self->symbols[type]); + dso__set_sorted_by_name(dso, type); + return symbols__sort_by_name(&dso->symbol_names[type], + &dso->symbols[type]); } -int build_id__sprintf(const u8 *self, int len, char *bf) +int build_id__sprintf(const u8 *build_id, int len, char *bf) { char *bid = bf; - const u8 *raw = self; + const u8 *raw = build_id; int i; for (i = 0; i < len; ++i) { @@ -384,24 +386,25 @@ int build_id__sprintf(const u8 *self, int len, char *bf) bid += 2; } - return raw - self; + return raw - build_id; } -size_t dso__fprintf_buildid(struct dso *self, FILE *fp) +size_t dso__fprintf_buildid(struct dso *dso, FILE *fp) { char sbuild_id[BUILD_ID_SIZE * 2 + 1]; - build_id__sprintf(self->build_id, sizeof(self->build_id), sbuild_id); + build_id__sprintf(dso->build_id, sizeof(dso->build_id), sbuild_id); return fprintf(fp, "%s", sbuild_id); } -size_t dso__fprintf_symbols_by_name(struct dso *self, enum map_type type, FILE *fp) +size_t dso__fprintf_symbols_by_name(struct dso *dso, + enum map_type type, FILE *fp) { size_t ret = 0; struct rb_node *nd; struct symbol_name_rb_node *pos; - for (nd = rb_first(&self->symbol_names[type]); nd; nd = rb_next(nd)) { + for (nd = rb_first(&dso->symbol_names[type]); nd; nd = rb_next(nd)) { pos = rb_entry(nd, struct symbol_name_rb_node, rb_node); fprintf(fp, "%s\n", pos->sym.name); } @@ -409,18 +412,18 @@ size_t dso__fprintf_symbols_by_name(struct dso *self, enum map_type type, FILE * return ret; } -size_t dso__fprintf(struct dso *self, enum map_type type, FILE *fp) +size_t dso__fprintf(struct dso *dso, enum map_type type, FILE *fp) { struct rb_node *nd; - size_t ret = fprintf(fp, "dso: %s (", self->short_name); + size_t ret = fprintf(fp, "dso: %s (", dso->short_name); - if (self->short_name != self->long_name) - ret += fprintf(fp, "%s, ", self->long_name); + if (dso->short_name != dso->long_name) + ret += fprintf(fp, "%s, ", dso->long_name); ret += fprintf(fp, "%s, %sloaded, ", map_type__name[type], - self->loaded ? "" : "NOT "); - ret += dso__fprintf_buildid(self, fp); + dso->loaded ? "" : "NOT "); + ret += dso__fprintf_buildid(dso, fp); ret += fprintf(fp, ")\n"); - for (nd = rb_first(&self->symbols[type]); nd; nd = rb_next(nd)) { + for (nd = rb_first(&dso->symbols[type]); nd; nd = rb_next(nd)) { struct symbol *pos = rb_entry(nd, struct symbol, rb_node); ret += symbol__fprintf(pos, fp); } @@ -543,10 +546,10 @@ static int map__process_kallsym_symbol(void *arg, const char *name, * so that we can in the next step set the symbol ->end address and then * call kernel_maps__split_kallsyms. */ -static int dso__load_all_kallsyms(struct dso *self, const char *filename, +static int dso__load_all_kallsyms(struct dso *dso, const char *filename, struct map *map) { - struct process_kallsyms_args args = { .map = map, .dso = self, }; + struct process_kallsyms_args args = { .map = map, .dso = dso, }; return kallsyms__parse(filename, &args, map__process_kallsym_symbol); } @@ -555,7 +558,7 @@ static int dso__load_all_kallsyms(struct dso *self, const char *filename, * kernel range is broken in several maps, named [kernel].N, as we don't have * the original ELF section names vmlinux have. */ -static int dso__split_kallsyms(struct dso *self, struct map *map, +static int dso__split_kallsyms(struct dso *dso, struct map *map, symbol_filter_t filter) { struct map_groups *kmaps = map__kmap(map)->kmaps; @@ -563,7 +566,7 @@ static int dso__split_kallsyms(struct dso *self, struct map *map, struct map *curr_map = map; struct symbol *pos; int count = 0, moved = 0; - struct rb_root *root = &self->symbols[map->type]; + struct rb_root *root = &dso->symbols[map->type]; struct rb_node *next = rb_first(root); int kernel_range = 0; @@ -582,7 +585,7 @@ static int dso__split_kallsyms(struct dso *self, struct map *map, if (strcmp(curr_map->dso->short_name, module)) { if (curr_map != map && - self->kernel == DSO_TYPE_GUEST_KERNEL && + dso->kernel == DSO_TYPE_GUEST_KERNEL && machine__is_default_guest(machine)) { /* * We assume all symbols of a module are @@ -618,14 +621,14 @@ static int dso__split_kallsyms(struct dso *self, struct map *map, pos->end = curr_map->map_ip(curr_map, pos->end); } else if (curr_map != map) { char dso_name[PATH_MAX]; - struct dso *dso; + struct dso *ndso; if (count == 0) { curr_map = map; goto filter_symbol; } - if (self->kernel == DSO_TYPE_GUEST_KERNEL) + if (dso->kernel == DSO_TYPE_GUEST_KERNEL) snprintf(dso_name, sizeof(dso_name), "[guest.kernel].%d", kernel_range++); @@ -634,15 +637,15 @@ static int dso__split_kallsyms(struct dso *self, struct map *map, "[kernel].%d", kernel_range++); - dso = dso__new(dso_name); - if (dso == NULL) + ndso = dso__new(dso_name); + if (ndso == NULL) return -1; - dso->kernel = self->kernel; + ndso->kernel = dso->kernel; - curr_map = map__new2(pos->start, dso, map->type); + curr_map = map__new2(pos->start, ndso, map->type); if (curr_map == NULL) { - dso__delete(dso); + dso__delete(ndso); return -1; } @@ -665,7 +668,7 @@ discard_symbol: rb_erase(&pos->rb_node, root); } if (curr_map != map && - self->kernel == DSO_TYPE_GUEST_KERNEL && + dso->kernel == DSO_TYPE_GUEST_KERNEL && machine__is_default_guest(kmaps->machine)) { dso__set_loaded(curr_map->dso, curr_map->type); } @@ -673,21 +676,21 @@ discard_symbol: rb_erase(&pos->rb_node, root); return count + moved; } -int dso__load_kallsyms(struct dso *self, const char *filename, +int dso__load_kallsyms(struct dso *dso, const char *filename, struct map *map, symbol_filter_t filter) { - if (dso__load_all_kallsyms(self, filename, map) < 0) + if (dso__load_all_kallsyms(dso, filename, map) < 0) return -1; - if (self->kernel == DSO_TYPE_GUEST_KERNEL) - self->symtab_type = SYMTAB__GUEST_KALLSYMS; + if (dso->kernel == DSO_TYPE_GUEST_KERNEL) + dso->symtab_type = SYMTAB__GUEST_KALLSYMS; else - self->symtab_type = SYMTAB__KALLSYMS; + dso->symtab_type = SYMTAB__KALLSYMS; - return dso__split_kallsyms(self, map, filter); + return dso__split_kallsyms(dso, map, filter); } -static int dso__load_perf_map(struct dso *self, struct map *map, +static int dso__load_perf_map(struct dso *dso, struct map *map, symbol_filter_t filter) { char *line = NULL; @@ -695,7 +698,7 @@ static int dso__load_perf_map(struct dso *self, struct map *map, FILE *file; int nr_syms = 0; - file = fopen(self->long_name, "r"); + file = fopen(dso->long_name, "r"); if (file == NULL) goto out_failure; @@ -733,7 +736,7 @@ static int dso__load_perf_map(struct dso *self, struct map *map, if (filter && filter(map, sym)) symbol__delete(sym); else { - symbols__insert(&self->symbols[map->type], sym); + symbols__insert(&dso->symbols[map->type], sym); nr_syms++; } } @@ -752,7 +755,7 @@ out_failure: /** * elf_symtab__for_each_symbol - iterate thru all the symbols * - * @self: struct elf_symtab instance to iterate + * @syms: struct elf_symtab instance to iterate * @idx: uint32_t idx * @sym: GElf_Sym iterator */ @@ -852,7 +855,7 @@ static Elf_Scn *elf_section_by_name(Elf *elf, GElf_Ehdr *ep, * And always look at the original dso, not at debuginfo packages, that * have the PLT data stripped out (shdr_rel_plt.sh_type == SHT_NOBITS). */ -static int dso__synthesize_plt_symbols(struct dso *self, struct map *map, +static int dso__synthesize_plt_symbols(struct dso *dso, struct map *map, symbol_filter_t filter) { uint32_t nr_rel_entries, idx; @@ -871,7 +874,7 @@ static int dso__synthesize_plt_symbols(struct dso *self, struct map *map, char name[PATH_MAX]; snprintf(name, sizeof(name), "%s%s", - symbol_conf.symfs, self->long_name); + symbol_conf.symfs, dso->long_name); fd = open(name, O_RDONLY); if (fd < 0) goto out; @@ -947,7 +950,7 @@ static int dso__synthesize_plt_symbols(struct dso *self, struct map *map, if (filter && filter(map, f)) symbol__delete(f); else { - symbols__insert(&self->symbols[map->type], f); + symbols__insert(&dso->symbols[map->type], f); ++nr; } } @@ -969,7 +972,7 @@ static int dso__synthesize_plt_symbols(struct dso *self, struct map *map, if (filter && filter(map, f)) symbol__delete(f); else { - symbols__insert(&self->symbols[map->type], f); + symbols__insert(&dso->symbols[map->type], f); ++nr; } } @@ -985,29 +988,30 @@ out_close: return nr; out: pr_debug("%s: problems reading %s PLT info.\n", - __func__, self->long_name); + __func__, dso->long_name); return 0; } -static bool elf_sym__is_a(GElf_Sym *self, enum map_type type) +static bool elf_sym__is_a(GElf_Sym *sym, enum map_type type) { switch (type) { case MAP__FUNCTION: - return elf_sym__is_function(self); + return elf_sym__is_function(sym); case MAP__VARIABLE: - return elf_sym__is_object(self); + return elf_sym__is_object(sym); default: return false; } } -static bool elf_sec__is_a(GElf_Shdr *self, Elf_Data *secstrs, enum map_type type) +static bool elf_sec__is_a(GElf_Shdr *shdr, Elf_Data *secstrs, + enum map_type type) { switch (type) { case MAP__FUNCTION: - return elf_sec__is_text(self, secstrs); + return elf_sec__is_text(shdr, secstrs); case MAP__VARIABLE: - return elf_sec__is_data(self, secstrs); + return elf_sec__is_data(shdr, secstrs); default: return false; } @@ -1032,13 +1036,13 @@ static size_t elf_addr_to_index(Elf *elf, GElf_Addr addr) return -1; } -static int dso__load_sym(struct dso *self, struct map *map, const char *name, +static int dso__load_sym(struct dso *dso, struct map *map, const char *name, int fd, symbol_filter_t filter, int kmodule, int want_symtab) { - struct kmap *kmap = self->kernel ? map__kmap(map) : NULL; + struct kmap *kmap = dso->kernel ? map__kmap(map) : NULL; struct map *curr_map = map; - struct dso *curr_dso = self; + struct dso *curr_dso = dso; Elf_Data *symstrs, *secstrs; uint32_t nr_syms; int err = -1; @@ -1064,14 +1068,14 @@ static int dso__load_sym(struct dso *self, struct map *map, const char *name, } /* Always reject images with a mismatched build-id: */ - if (self->has_build_id) { + if (dso->has_build_id) { u8 build_id[BUILD_ID_SIZE]; if (elf_read_build_id(elf, build_id, BUILD_ID_SIZE) != BUILD_ID_SIZE) goto out_elf_end; - if (!dso__build_id_equal(self, build_id)) + if (!dso__build_id_equal(dso, build_id)) goto out_elf_end; } @@ -1112,13 +1116,14 @@ static int dso__load_sym(struct dso *self, struct map *map, const char *name, nr_syms = shdr.sh_size / shdr.sh_entsize; memset(&sym, 0, sizeof(sym)); - if (self->kernel == DSO_TYPE_USER) { - self->adjust_symbols = (ehdr.e_type == ET_EXEC || + if (dso->kernel == DSO_TYPE_USER) { + dso->adjust_symbols = (ehdr.e_type == ET_EXEC || elf_section_by_name(elf, &ehdr, &shdr, ".gnu.prelink_undo", NULL) != NULL); - } else self->adjust_symbols = 0; - + } else { + dso->adjust_symbols = 0; + } elf_symtab__for_each_symbol(syms, nr_syms, idx, sym) { struct symbol *f; const char *elf_name = elf_sym__name(&sym, symstrs); @@ -1168,22 +1173,22 @@ static int dso__load_sym(struct dso *self, struct map *map, const char *name, (sym.st_value & 1)) --sym.st_value; - if (self->kernel != DSO_TYPE_USER || kmodule) { + if (dso->kernel != DSO_TYPE_USER || kmodule) { char dso_name[PATH_MAX]; if (strcmp(section_name, (curr_dso->short_name + - self->short_name_len)) == 0) + dso->short_name_len)) == 0) goto new_symbol; if (strcmp(section_name, ".text") == 0) { curr_map = map; - curr_dso = self; + curr_dso = dso; goto new_symbol; } snprintf(dso_name, sizeof(dso_name), - "%s%s", self->short_name, section_name); + "%s%s", dso->short_name, section_name); curr_map = map_groups__find_by_name(kmap->kmaps, map->type, dso_name); if (curr_map == NULL) { @@ -1195,9 +1200,9 @@ static int dso__load_sym(struct dso *self, struct map *map, const char *name, curr_dso = dso__new(dso_name); if (curr_dso == NULL) goto out_elf_end; - curr_dso->kernel = self->kernel; - curr_dso->long_name = self->long_name; - curr_dso->long_name_len = self->long_name_len; + curr_dso->kernel = dso->kernel; + curr_dso->long_name = dso->long_name; + curr_dso->long_name_len = dso->long_name_len; curr_map = map__new2(start, curr_dso, map->type); if (curr_map == NULL) { @@ -1206,9 +1211,9 @@ static int dso__load_sym(struct dso *self, struct map *map, const char *name, } curr_map->map_ip = identity__map_ip; curr_map->unmap_ip = identity__map_ip; - curr_dso->symtab_type = self->symtab_type; + curr_dso->symtab_type = dso->symtab_type; map_groups__insert(kmap->kmaps, curr_map); - dsos__add(&self->node, curr_dso); + dsos__add(&dso->node, curr_dso); dso__set_loaded(curr_dso, map->type); } else curr_dso = curr_map->dso; @@ -1250,7 +1255,7 @@ new_symbol: * For misannotated, zeroed, ASM function sizes. */ if (nr > 0) { - symbols__fixup_end(&self->symbols[map->type]); + symbols__fixup_end(&dso->symbols[map->type]); if (kmap) { /* * We need to fixup this here too because we create new @@ -1266,9 +1271,9 @@ out_close: return err; } -static bool dso__build_id_equal(const struct dso *self, u8 *build_id) +static bool dso__build_id_equal(const struct dso *dso, u8 *build_id) { - return memcmp(self->build_id, build_id, sizeof(self->build_id)) == 0; + return memcmp(dso->build_id, build_id, sizeof(dso->build_id)) == 0; } bool __dsos__read_build_ids(struct list_head *head, bool with_hits) @@ -1429,7 +1434,7 @@ out: return err; } -char dso__symtab_origin(const struct dso *self) +char dso__symtab_origin(const struct dso *dso) { static const char origin[] = { [SYMTAB__KALLSYMS] = 'k', @@ -1444,12 +1449,12 @@ char dso__symtab_origin(const struct dso *self) [SYMTAB__GUEST_KMODULE] = 'G', }; - if (self == NULL || self->symtab_type == SYMTAB__NOT_FOUND) + if (dso == NULL || dso->symtab_type == SYMTAB__NOT_FOUND) return '!'; - return origin[self->symtab_type]; + return origin[dso->symtab_type]; } -int dso__load(struct dso *self, struct map *map, symbol_filter_t filter) +int dso__load(struct dso *dso, struct map *map, symbol_filter_t filter) { int size = PATH_MAX; char *name; @@ -1459,12 +1464,12 @@ int dso__load(struct dso *self, struct map *map, symbol_filter_t filter) const char *root_dir; int want_symtab; - dso__set_loaded(self, map->type); + dso__set_loaded(dso, map->type); - if (self->kernel == DSO_TYPE_KERNEL) - return dso__load_kernel_sym(self, map, filter); - else if (self->kernel == DSO_TYPE_GUEST_KERNEL) - return dso__load_guest_kernel_sym(self, map, filter); + if (dso->kernel == DSO_TYPE_KERNEL) + return dso__load_kernel_sym(dso, map, filter); + else if (dso->kernel == DSO_TYPE_GUEST_KERNEL) + return dso__load_guest_kernel_sym(dso, map, filter); if (map->groups && map->groups->machine) machine = map->groups->machine; @@ -1475,11 +1480,11 @@ int dso__load(struct dso *self, struct map *map, symbol_filter_t filter) if (!name) return -1; - self->adjust_symbols = 0; + dso->adjust_symbols = 0; - if (strncmp(self->name, "/tmp/perf-", 10) == 0) { - ret = dso__load_perf_map(self, map, filter); - self->symtab_type = ret > 0 ? SYMTAB__JAVA_JIT : + if (strncmp(dso->name, "/tmp/perf-", 10) == 0) { + ret = dso__load_perf_map(dso, map, filter); + dso->symtab_type = ret > 0 ? SYMTAB__JAVA_JIT : SYMTAB__NOT_FOUND; return ret; } @@ -1490,33 +1495,33 @@ int dso__load(struct dso *self, struct map *map, symbol_filter_t filter) */ want_symtab = 1; restart: - for (self->symtab_type = SYMTAB__BUILD_ID_CACHE; - self->symtab_type != SYMTAB__NOT_FOUND; - self->symtab_type++) { - switch (self->symtab_type) { + for (dso->symtab_type = SYMTAB__BUILD_ID_CACHE; + dso->symtab_type != SYMTAB__NOT_FOUND; + dso->symtab_type++) { + switch (dso->symtab_type) { case SYMTAB__BUILD_ID_CACHE: /* skip the locally configured cache if a symfs is given */ if (symbol_conf.symfs[0] || - (dso__build_id_filename(self, name, size) == NULL)) { + (dso__build_id_filename(dso, name, size) == NULL)) { continue; } break; case SYMTAB__FEDORA_DEBUGINFO: snprintf(name, size, "%s/usr/lib/debug%s.debug", - symbol_conf.symfs, self->long_name); + symbol_conf.symfs, dso->long_name); break; case SYMTAB__UBUNTU_DEBUGINFO: snprintf(name, size, "%s/usr/lib/debug%s", - symbol_conf.symfs, self->long_name); + symbol_conf.symfs, dso->long_name); break; case SYMTAB__BUILDID_DEBUGINFO: { char build_id_hex[BUILD_ID_SIZE * 2 + 1]; - if (!self->has_build_id) + if (!dso->has_build_id) continue; - build_id__sprintf(self->build_id, - sizeof(self->build_id), + build_id__sprintf(dso->build_id, + sizeof(dso->build_id), build_id_hex); snprintf(name, size, "%s/usr/lib/debug/.build-id/%.2s/%s.debug", @@ -1525,7 +1530,7 @@ restart: break; case SYMTAB__SYSTEM_PATH_DSO: snprintf(name, size, "%s%s", - symbol_conf.symfs, self->long_name); + symbol_conf.symfs, dso->long_name); break; case SYMTAB__GUEST_KMODULE: if (map->groups && machine) @@ -1533,12 +1538,12 @@ restart: else root_dir = ""; snprintf(name, size, "%s%s%s", symbol_conf.symfs, - root_dir, self->long_name); + root_dir, dso->long_name); break; case SYMTAB__SYSTEM_PATH_KMODULE: snprintf(name, size, "%s%s", symbol_conf.symfs, - self->long_name); + dso->long_name); break; default:; } @@ -1548,7 +1553,7 @@ restart: if (fd < 0) continue; - ret = dso__load_sym(self, map, name, fd, filter, 0, + ret = dso__load_sym(dso, map, name, fd, filter, 0, want_symtab); close(fd); @@ -1560,7 +1565,8 @@ restart: continue; if (ret > 0) { - int nr_plt = dso__synthesize_plt_symbols(self, map, filter); + int nr_plt = dso__synthesize_plt_symbols(dso, map, + filter); if (nr_plt > 0) ret += nr_plt; break; @@ -1577,17 +1583,17 @@ restart: } free(name); - if (ret < 0 && strstr(self->name, " (deleted)") != NULL) + if (ret < 0 && strstr(dso->name, " (deleted)") != NULL) return 0; return ret; } -struct map *map_groups__find_by_name(struct map_groups *self, +struct map *map_groups__find_by_name(struct map_groups *mg, enum map_type type, const char *name) { struct rb_node *nd; - for (nd = rb_first(&self->maps[type]); nd; nd = rb_next(nd)) { + for (nd = rb_first(&mg->maps[type]); nd; nd = rb_next(nd)) { struct map *map = rb_entry(nd, struct map, rb_node); if (map->dso && strcmp(map->dso->short_name, name) == 0) @@ -1597,28 +1603,28 @@ struct map *map_groups__find_by_name(struct map_groups *self, return NULL; } -static int dso__kernel_module_get_build_id(struct dso *self, - const char *root_dir) +static int dso__kernel_module_get_build_id(struct dso *dso, + const char *root_dir) { char filename[PATH_MAX]; /* * kernel module short names are of the form "[module]" and * we need just "module" here. */ - const char *name = self->short_name + 1; + const char *name = dso->short_name + 1; snprintf(filename, sizeof(filename), "%s/sys/module/%.*s/notes/.note.gnu.build-id", root_dir, (int)strlen(name) - 1, name); - if (sysfs__read_build_id(filename, self->build_id, - sizeof(self->build_id)) == 0) - self->has_build_id = true; + if (sysfs__read_build_id(filename, dso->build_id, + sizeof(dso->build_id)) == 0) + dso->has_build_id = true; return 0; } -static int map_groups__set_modules_path_dir(struct map_groups *self, +static int map_groups__set_modules_path_dir(struct map_groups *mg, const char *dir_name) { struct dirent *dent; @@ -1646,7 +1652,7 @@ static int map_groups__set_modules_path_dir(struct map_groups *self, snprintf(path, sizeof(path), "%s/%s", dir_name, dent->d_name); - ret = map_groups__set_modules_path_dir(self, path); + ret = map_groups__set_modules_path_dir(mg, path); if (ret < 0) goto out; } else { @@ -1661,7 +1667,8 @@ static int map_groups__set_modules_path_dir(struct map_groups *self, (int)(dot - dent->d_name), dent->d_name); strxfrchar(dso_name, '-', '_'); - map = map_groups__find_by_name(self, MAP__FUNCTION, dso_name); + map = map_groups__find_by_name(mg, MAP__FUNCTION, + dso_name); if (map == NULL) continue; @@ -1711,20 +1718,20 @@ static char *get_kernel_version(const char *root_dir) return strdup(name); } -static int machine__set_modules_path(struct machine *self) +static int machine__set_modules_path(struct machine *machine) { char *version; char modules_path[PATH_MAX]; - version = get_kernel_version(self->root_dir); + version = get_kernel_version(machine->root_dir); if (!version) return -1; snprintf(modules_path, sizeof(modules_path), "%s/lib/modules/%s/kernel", - self->root_dir, version); + machine->root_dir, version); free(version); - return map_groups__set_modules_path_dir(&self->kmaps, modules_path); + return map_groups__set_modules_path_dir(&machine->kmaps, modules_path); } /* @@ -1734,23 +1741,23 @@ static int machine__set_modules_path(struct machine *self) */ static struct map *map__new2(u64 start, struct dso *dso, enum map_type type) { - struct map *self = calloc(1, (sizeof(*self) + - (dso->kernel ? sizeof(struct kmap) : 0))); - if (self != NULL) { + struct map *map = calloc(1, (sizeof(*map) + + (dso->kernel ? sizeof(struct kmap) : 0))); + if (map != NULL) { /* * ->end will be filled after we load all the symbols */ - map__init(self, type, start, 0, 0, dso); + map__init(map, type, start, 0, 0, dso); } - return self; + return map; } -struct map *machine__new_module(struct machine *self, u64 start, +struct map *machine__new_module(struct machine *machine, u64 start, const char *filename) { struct map *map; - struct dso *dso = __dsos__findnew(&self->kernel_dsos, filename); + struct dso *dso = __dsos__findnew(&machine->kernel_dsos, filename); if (dso == NULL) return NULL; @@ -1759,15 +1766,15 @@ struct map *machine__new_module(struct machine *self, u64 start, if (map == NULL) return NULL; - if (machine__is_host(self)) + if (machine__is_host(machine)) dso->symtab_type = SYMTAB__SYSTEM_PATH_KMODULE; else dso->symtab_type = SYMTAB__GUEST_KMODULE; - map_groups__insert(&self->kmaps, map); + map_groups__insert(&machine->kmaps, map); return map; } -static int machine__create_modules(struct machine *self) +static int machine__create_modules(struct machine *machine) { char *line = NULL; size_t n; @@ -1776,10 +1783,10 @@ static int machine__create_modules(struct machine *self) const char *modules; char path[PATH_MAX]; - if (machine__is_default_guest(self)) + if (machine__is_default_guest(machine)) modules = symbol_conf.default_guest_modules; else { - sprintf(path, "%s/proc/modules", self->root_dir); + sprintf(path, "%s/proc/modules", machine->root_dir); modules = path; } @@ -1815,16 +1822,16 @@ static int machine__create_modules(struct machine *self) *sep = '\0'; snprintf(name, sizeof(name), "[%s]", line); - map = machine__new_module(self, start, name); + map = machine__new_module(machine, start, name); if (map == NULL) goto out_delete_line; - dso__kernel_module_get_build_id(map->dso, self->root_dir); + dso__kernel_module_get_build_id(map->dso, machine->root_dir); } free(line); fclose(file); - return machine__set_modules_path(self); + return machine__set_modules_path(machine); out_delete_line: free(line); @@ -1832,7 +1839,7 @@ out_failure: return -1; } -int dso__load_vmlinux(struct dso *self, struct map *map, +int dso__load_vmlinux(struct dso *dso, struct map *map, const char *vmlinux, symbol_filter_t filter) { int err = -1, fd; @@ -1844,9 +1851,9 @@ int dso__load_vmlinux(struct dso *self, struct map *map, if (fd < 0) return -1; - dso__set_long_name(self, (char *)vmlinux); - dso__set_loaded(self, map->type); - err = dso__load_sym(self, map, symfs_vmlinux, fd, filter, 0, 0); + dso__set_long_name(dso, (char *)vmlinux); + dso__set_loaded(dso, map->type); + err = dso__load_sym(dso, map, symfs_vmlinux, fd, filter, 0, 0); close(fd); if (err > 0) @@ -1855,7 +1862,7 @@ int dso__load_vmlinux(struct dso *self, struct map *map, return err; } -int dso__load_vmlinux_path(struct dso *self, struct map *map, +int dso__load_vmlinux_path(struct dso *dso, struct map *map, symbol_filter_t filter) { int i, err = 0; @@ -1864,20 +1871,20 @@ int dso__load_vmlinux_path(struct dso *self, struct map *map, pr_debug("Looking at the vmlinux_path (%d entries long)\n", vmlinux_path__nr_entries + 1); - filename = dso__build_id_filename(self, NULL, 0); + filename = dso__build_id_filename(dso, NULL, 0); if (filename != NULL) { - err = dso__load_vmlinux(self, map, filename, filter); + err = dso__load_vmlinux(dso, map, filename, filter); if (err > 0) { - dso__set_long_name(self, filename); + dso__set_long_name(dso, filename); goto out; } free(filename); } for (i = 0; i < vmlinux_path__nr_entries; ++i) { - err = dso__load_vmlinux(self, map, vmlinux_path[i], filter); + err = dso__load_vmlinux(dso, map, vmlinux_path[i], filter); if (err > 0) { - dso__set_long_name(self, strdup(vmlinux_path[i])); + dso__set_long_name(dso, strdup(vmlinux_path[i])); break; } } @@ -1885,7 +1892,7 @@ out: return err; } -static int dso__load_kernel_sym(struct dso *self, struct map *map, +static int dso__load_kernel_sym(struct dso *dso, struct map *map, symbol_filter_t filter) { int err; @@ -1912,10 +1919,10 @@ static int dso__load_kernel_sym(struct dso *self, struct map *map, } if (symbol_conf.vmlinux_name != NULL) { - err = dso__load_vmlinux(self, map, + err = dso__load_vmlinux(dso, map, symbol_conf.vmlinux_name, filter); if (err > 0) { - dso__set_long_name(self, + dso__set_long_name(dso, strdup(symbol_conf.vmlinux_name)); goto out_fixup; } @@ -1923,7 +1930,7 @@ static int dso__load_kernel_sym(struct dso *self, struct map *map, } if (vmlinux_path != NULL) { - err = dso__load_vmlinux_path(self, map, filter); + err = dso__load_vmlinux_path(dso, map, filter); if (err > 0) goto out_fixup; } @@ -1937,13 +1944,13 @@ static int dso__load_kernel_sym(struct dso *self, struct map *map, * we have a build-id, so check if it is the same as the running kernel, * using it if it is. */ - if (self->has_build_id) { + if (dso->has_build_id) { u8 kallsyms_build_id[BUILD_ID_SIZE]; char sbuild_id[BUILD_ID_SIZE * 2 + 1]; if (sysfs__read_build_id("/sys/kernel/notes", kallsyms_build_id, sizeof(kallsyms_build_id)) == 0) { - if (dso__build_id_equal(self, kallsyms_build_id)) { + if (dso__build_id_equal(dso, kallsyms_build_id)) { kallsyms_filename = "/proc/kallsyms"; goto do_kallsyms; } @@ -1952,7 +1959,7 @@ static int dso__load_kernel_sym(struct dso *self, struct map *map, * Now look if we have it on the build-id cache in * $HOME/.debug/[kernel.kallsyms]. */ - build_id__sprintf(self->build_id, sizeof(self->build_id), + build_id__sprintf(dso->build_id, sizeof(dso->build_id), sbuild_id); if (asprintf(&kallsyms_allocated_filename, @@ -1979,7 +1986,7 @@ static int dso__load_kernel_sym(struct dso *self, struct map *map, } do_kallsyms: - err = dso__load_kallsyms(self, kallsyms_filename, map, filter); + err = dso__load_kallsyms(dso, kallsyms_filename, map, filter); if (err > 0) pr_debug("Using %s for symbols\n", kallsyms_filename); free(kallsyms_allocated_filename); @@ -1987,7 +1994,7 @@ do_kallsyms: if (err > 0) { out_fixup: if (kallsyms_filename != NULL) - dso__set_long_name(self, strdup("[kernel.kallsyms]")); + dso__set_long_name(dso, strdup("[kernel.kallsyms]")); map__fixup_start(map); map__fixup_end(map); } @@ -1995,8 +2002,8 @@ out_fixup: return err; } -static int dso__load_guest_kernel_sym(struct dso *self, struct map *map, - symbol_filter_t filter) +static int dso__load_guest_kernel_sym(struct dso *dso, struct map *map, + symbol_filter_t filter) { int err; const char *kallsyms_filename = NULL; @@ -2016,7 +2023,7 @@ static int dso__load_guest_kernel_sym(struct dso *self, struct map *map, * Or use file guest_kallsyms inputted by user on commandline */ if (symbol_conf.default_guest_vmlinux_name != NULL) { - err = dso__load_vmlinux(self, map, + err = dso__load_vmlinux(dso, map, symbol_conf.default_guest_vmlinux_name, filter); goto out_try_fixup; } @@ -2029,7 +2036,7 @@ static int dso__load_guest_kernel_sym(struct dso *self, struct map *map, kallsyms_filename = path; } - err = dso__load_kallsyms(self, kallsyms_filename, map, filter); + err = dso__load_kallsyms(dso, kallsyms_filename, map, filter); if (err > 0) pr_debug("Using %s for symbols\n", kallsyms_filename); @@ -2037,7 +2044,7 @@ out_try_fixup: if (err > 0) { if (kallsyms_filename != NULL) { machine__mmap_name(machine, path, sizeof(path)); - dso__set_long_name(self, strdup(path)); + dso__set_long_name(dso, strdup(path)); } map__fixup_start(map); map__fixup_end(map); @@ -2090,12 +2097,12 @@ size_t __dsos__fprintf(struct list_head *head, FILE *fp) return ret; } -size_t machines__fprintf_dsos(struct rb_root *self, FILE *fp) +size_t machines__fprintf_dsos(struct rb_root *machines, FILE *fp) { struct rb_node *nd; size_t ret = 0; - for (nd = rb_first(self); nd; nd = rb_next(nd)) { + for (nd = rb_first(machines); nd; nd = rb_next(nd)) { struct machine *pos = rb_entry(nd, struct machine, rb_node); ret += __dsos__fprintf(&pos->kernel_dsos, fp); ret += __dsos__fprintf(&pos->user_dsos, fp); @@ -2119,18 +2126,20 @@ static size_t __dsos__fprintf_buildid(struct list_head *head, FILE *fp, return ret; } -size_t machine__fprintf_dsos_buildid(struct machine *self, FILE *fp, bool with_hits) +size_t machine__fprintf_dsos_buildid(struct machine *machine, FILE *fp, + bool with_hits) { - return __dsos__fprintf_buildid(&self->kernel_dsos, fp, with_hits) + - __dsos__fprintf_buildid(&self->user_dsos, fp, with_hits); + return __dsos__fprintf_buildid(&machine->kernel_dsos, fp, with_hits) + + __dsos__fprintf_buildid(&machine->user_dsos, fp, with_hits); } -size_t machines__fprintf_dsos_buildid(struct rb_root *self, FILE *fp, bool with_hits) +size_t machines__fprintf_dsos_buildid(struct rb_root *machines, + FILE *fp, bool with_hits) { struct rb_node *nd; size_t ret = 0; - for (nd = rb_first(self); nd; nd = rb_next(nd)) { + for (nd = rb_first(machines); nd; nd = rb_next(nd)) { struct machine *pos = rb_entry(nd, struct machine, rb_node); ret += machine__fprintf_dsos_buildid(pos, fp, with_hits); } @@ -2139,59 +2148,59 @@ size_t machines__fprintf_dsos_buildid(struct rb_root *self, FILE *fp, bool with_ struct dso *dso__new_kernel(const char *name) { - struct dso *self = dso__new(name ?: "[kernel.kallsyms]"); + struct dso *dso = dso__new(name ?: "[kernel.kallsyms]"); - if (self != NULL) { - dso__set_short_name(self, "[kernel]"); - self->kernel = DSO_TYPE_KERNEL; + if (dso != NULL) { + dso__set_short_name(dso, "[kernel]"); + dso->kernel = DSO_TYPE_KERNEL; } - return self; + return dso; } static struct dso *dso__new_guest_kernel(struct machine *machine, const char *name) { char bf[PATH_MAX]; - struct dso *self = dso__new(name ?: machine__mmap_name(machine, bf, sizeof(bf))); - - if (self != NULL) { - dso__set_short_name(self, "[guest.kernel]"); - self->kernel = DSO_TYPE_GUEST_KERNEL; + struct dso *dso = dso__new(name ?: machine__mmap_name(machine, bf, + sizeof(bf))); + if (dso != NULL) { + dso__set_short_name(dso, "[guest.kernel]"); + dso->kernel = DSO_TYPE_GUEST_KERNEL; } - return self; + return dso; } -void dso__read_running_kernel_build_id(struct dso *self, struct machine *machine) +void dso__read_running_kernel_build_id(struct dso *dso, struct machine *machine) { char path[PATH_MAX]; if (machine__is_default_guest(machine)) return; sprintf(path, "%s/sys/kernel/notes", machine->root_dir); - if (sysfs__read_build_id(path, self->build_id, - sizeof(self->build_id)) == 0) - self->has_build_id = true; + if (sysfs__read_build_id(path, dso->build_id, + sizeof(dso->build_id)) == 0) + dso->has_build_id = true; } -static struct dso *machine__create_kernel(struct machine *self) +static struct dso *machine__create_kernel(struct machine *machine) { const char *vmlinux_name = NULL; struct dso *kernel; - if (machine__is_host(self)) { + if (machine__is_host(machine)) { vmlinux_name = symbol_conf.vmlinux_name; kernel = dso__new_kernel(vmlinux_name); } else { - if (machine__is_default_guest(self)) + if (machine__is_default_guest(machine)) vmlinux_name = symbol_conf.default_guest_vmlinux_name; - kernel = dso__new_guest_kernel(self, vmlinux_name); + kernel = dso__new_guest_kernel(machine, vmlinux_name); } if (kernel != NULL) { - dso__read_running_kernel_build_id(kernel, self); - dsos__add(&self->kernel_dsos, kernel); + dso__read_running_kernel_build_id(kernel, machine); + dsos__add(&machine->kernel_dsos, kernel); } return kernel; } @@ -2236,41 +2245,43 @@ static u64 machine__get_kernel_start_addr(struct machine *machine) return args.start; } -int __machine__create_kernel_maps(struct machine *self, struct dso *kernel) +int __machine__create_kernel_maps(struct machine *machine, struct dso *kernel) { enum map_type type; - u64 start = machine__get_kernel_start_addr(self); + u64 start = machine__get_kernel_start_addr(machine); for (type = 0; type < MAP__NR_TYPES; ++type) { struct kmap *kmap; - self->vmlinux_maps[type] = map__new2(start, kernel, type); - if (self->vmlinux_maps[type] == NULL) + machine->vmlinux_maps[type] = map__new2(start, kernel, type); + if (machine->vmlinux_maps[type] == NULL) return -1; - self->vmlinux_maps[type]->map_ip = - self->vmlinux_maps[type]->unmap_ip = identity__map_ip; - - kmap = map__kmap(self->vmlinux_maps[type]); - kmap->kmaps = &self->kmaps; - map_groups__insert(&self->kmaps, self->vmlinux_maps[type]); + machine->vmlinux_maps[type]->map_ip = + machine->vmlinux_maps[type]->unmap_ip = + identity__map_ip; + kmap = map__kmap(machine->vmlinux_maps[type]); + kmap->kmaps = &machine->kmaps; + map_groups__insert(&machine->kmaps, + machine->vmlinux_maps[type]); } return 0; } -void machine__destroy_kernel_maps(struct machine *self) +void machine__destroy_kernel_maps(struct machine *machine) { enum map_type type; for (type = 0; type < MAP__NR_TYPES; ++type) { struct kmap *kmap; - if (self->vmlinux_maps[type] == NULL) + if (machine->vmlinux_maps[type] == NULL) continue; - kmap = map__kmap(self->vmlinux_maps[type]); - map_groups__remove(&self->kmaps, self->vmlinux_maps[type]); + kmap = map__kmap(machine->vmlinux_maps[type]); + map_groups__remove(&machine->kmaps, + machine->vmlinux_maps[type]); if (kmap->ref_reloc_sym) { /* * ref_reloc_sym is shared among all maps, so free just @@ -2284,25 +2295,25 @@ void machine__destroy_kernel_maps(struct machine *self) kmap->ref_reloc_sym = NULL; } - map__delete(self->vmlinux_maps[type]); - self->vmlinux_maps[type] = NULL; + map__delete(machine->vmlinux_maps[type]); + machine->vmlinux_maps[type] = NULL; } } -int machine__create_kernel_maps(struct machine *self) +int machine__create_kernel_maps(struct machine *machine) { - struct dso *kernel = machine__create_kernel(self); + struct dso *kernel = machine__create_kernel(machine); if (kernel == NULL || - __machine__create_kernel_maps(self, kernel) < 0) + __machine__create_kernel_maps(machine, kernel) < 0) return -1; - if (symbol_conf.use_modules && machine__create_modules(self) < 0) + if (symbol_conf.use_modules && machine__create_modules(machine) < 0) pr_debug("Problems creating module maps, continuing anyway...\n"); /* * Now that we have all the maps created, just set the ->end of them: */ - map_groups__fixup_end(&self->kmaps); + map_groups__fixup_end(&machine->kmaps); return 0; } @@ -2366,11 +2377,11 @@ out_fail: return -1; } -size_t machine__fprintf_vmlinux_path(struct machine *self, FILE *fp) +size_t machine__fprintf_vmlinux_path(struct machine *machine, FILE *fp) { int i; size_t printed = 0; - struct dso *kdso = self->vmlinux_maps[MAP__FUNCTION]->dso; + struct dso *kdso = machine->vmlinux_maps[MAP__FUNCTION]->dso; if (kdso->has_build_id) { char filename[PATH_MAX]; @@ -2467,9 +2478,9 @@ void symbol__exit(void) symbol_conf.initialized = false; } -int machines__create_kernel_maps(struct rb_root *self, pid_t pid) +int machines__create_kernel_maps(struct rb_root *machines, pid_t pid) { - struct machine *machine = machines__findnew(self, pid); + struct machine *machine = machines__findnew(machines, pid); if (machine == NULL) return -1; @@ -2520,7 +2531,7 @@ char *strxfrchar(char *s, char from, char to) return s; } -int machines__create_guest_kernel_maps(struct rb_root *self) +int machines__create_guest_kernel_maps(struct rb_root *machines) { int ret = 0; struct dirent **namelist = NULL; @@ -2531,7 +2542,7 @@ int machines__create_guest_kernel_maps(struct rb_root *self) if (symbol_conf.default_guest_vmlinux_name || symbol_conf.default_guest_modules || symbol_conf.default_guest_kallsyms) { - machines__create_kernel_maps(self, DEFAULT_GUEST_KERNEL_ID); + machines__create_kernel_maps(machines, DEFAULT_GUEST_KERNEL_ID); } if (symbol_conf.guestmount) { @@ -2552,7 +2563,7 @@ int machines__create_guest_kernel_maps(struct rb_root *self) pr_debug("Can't access file %s\n", path); goto failure; } - machines__create_kernel_maps(self, pid); + machines__create_kernel_maps(machines, pid); } failure: free(namelist); @@ -2561,23 +2572,23 @@ failure: return ret; } -void machines__destroy_guest_kernel_maps(struct rb_root *self) +void machines__destroy_guest_kernel_maps(struct rb_root *machines) { - struct rb_node *next = rb_first(self); + struct rb_node *next = rb_first(machines); while (next) { struct machine *pos = rb_entry(next, struct machine, rb_node); next = rb_next(&pos->rb_node); - rb_erase(&pos->rb_node, self); + rb_erase(&pos->rb_node, machines); machine__delete(pos); } } -int machine__load_kallsyms(struct machine *self, const char *filename, +int machine__load_kallsyms(struct machine *machine, const char *filename, enum map_type type, symbol_filter_t filter) { - struct map *map = self->vmlinux_maps[type]; + struct map *map = machine->vmlinux_maps[type]; int ret = dso__load_kallsyms(map->dso, filename, map, filter); if (ret > 0) { @@ -2587,16 +2598,16 @@ int machine__load_kallsyms(struct machine *self, const char *filename, * kernel, with modules between them, fixup the end of all * sections. */ - __map_groups__fixup_end(&self->kmaps, type); + __map_groups__fixup_end(&machine->kmaps, type); } return ret; } -int machine__load_vmlinux_path(struct machine *self, enum map_type type, +int machine__load_vmlinux_path(struct machine *machine, enum map_type type, symbol_filter_t filter) { - struct map *map = self->vmlinux_maps[type]; + struct map *map = machine->vmlinux_maps[type]; int ret = dso__load_vmlinux_path(map->dso, map, filter); if (ret > 0) { diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h index 713b0b4..242de01 100644 --- a/tools/perf/util/symbol.h +++ b/tools/perf/util/symbol.h @@ -62,7 +62,7 @@ struct symbol { char name[0]; }; -void symbol__delete(struct symbol *self); +void symbol__delete(struct symbol *sym); struct strlist; @@ -96,9 +96,9 @@ struct symbol_conf { extern struct symbol_conf symbol_conf; -static inline void *symbol__priv(struct symbol *self) +static inline void *symbol__priv(struct symbol *sym) { - return ((void *)self) - symbol_conf.priv_size; + return ((void *)sym) - symbol_conf.priv_size; } struct ref_reloc_sym { @@ -155,43 +155,45 @@ struct dso { struct dso *dso__new(const char *name); struct dso *dso__new_kernel(const char *name); -void dso__delete(struct dso *self); +void dso__delete(struct dso *dso); -int dso__name_len(const struct dso *self); +int dso__name_len(const struct dso *dso); -bool dso__loaded(const struct dso *self, enum map_type type); -bool dso__sorted_by_name(const struct dso *self, enum map_type type); +bool dso__loaded(const struct dso *dso, enum map_type type); +bool dso__sorted_by_name(const struct dso *dso, enum map_type type); -static inline void dso__set_loaded(struct dso *self, enum map_type type) +static inline void dso__set_loaded(struct dso *dso, enum map_type type) { - self->loaded |= (1 << type); + dso->loaded |= (1 << type); } -void dso__sort_by_name(struct dso *self, enum map_type type); +void dso__sort_by_name(struct dso *dso, enum map_type type); struct dso *__dsos__findnew(struct list_head *head, const char *name); -int dso__load(struct dso *self, struct map *map, symbol_filter_t filter); -int dso__load_vmlinux(struct dso *self, struct map *map, +int dso__load(struct dso *dso, struct map *map, symbol_filter_t filter); +int dso__load_vmlinux(struct dso *dso, struct map *map, const char *vmlinux, symbol_filter_t filter); -int dso__load_vmlinux_path(struct dso *self, struct map *map, +int dso__load_vmlinux_path(struct dso *dso, struct map *map, symbol_filter_t filter); -int dso__load_kallsyms(struct dso *self, const char *filename, struct map *map, +int dso__load_kallsyms(struct dso *dso, const char *filename, struct map *map, symbol_filter_t filter); -int machine__load_kallsyms(struct machine *self, const char *filename, +int machine__load_kallsyms(struct machine *machine, const char *filename, enum map_type type, symbol_filter_t filter); -int machine__load_vmlinux_path(struct machine *self, enum map_type type, +int machine__load_vmlinux_path(struct machine *machine, enum map_type type, symbol_filter_t filter); size_t __dsos__fprintf(struct list_head *head, FILE *fp); -size_t machine__fprintf_dsos_buildid(struct machine *self, FILE *fp, bool with_hits); -size_t machines__fprintf_dsos(struct rb_root *self, FILE *fp); -size_t machines__fprintf_dsos_buildid(struct rb_root *self, FILE *fp, bool with_hits); - -size_t dso__fprintf_buildid(struct dso *self, FILE *fp); -size_t dso__fprintf_symbols_by_name(struct dso *self, enum map_type type, FILE *fp); -size_t dso__fprintf(struct dso *self, enum map_type type, FILE *fp); +size_t machine__fprintf_dsos_buildid(struct machine *machine, + FILE *fp, bool with_hits); +size_t machines__fprintf_dsos(struct rb_root *machines, FILE *fp); +size_t machines__fprintf_dsos_buildid(struct rb_root *machines, + FILE *fp, bool with_hits); +size_t dso__fprintf_buildid(struct dso *dso, FILE *fp); +size_t dso__fprintf_symbols_by_name(struct dso *dso, + enum map_type type, FILE *fp); +size_t dso__fprintf(struct dso *dso, enum map_type type, FILE *fp); enum symtab_type { SYMTAB__KALLSYMS = 0, @@ -207,34 +209,36 @@ enum symtab_type { SYMTAB__NOT_FOUND, }; -char dso__symtab_origin(const struct dso *self); -void dso__set_long_name(struct dso *self, char *name); -void dso__set_build_id(struct dso *self, void *build_id); -void dso__read_running_kernel_build_id(struct dso *self, struct machine *machine); -struct symbol *dso__find_symbol(struct dso *self, enum map_type type, u64 addr); -struct symbol *dso__find_symbol_by_name(struct dso *self, enum map_type type, +char dso__symtab_origin(const struct dso *dso); +void dso__set_long_name(struct dso *dso, char *name); +void dso__set_build_id(struct dso *dso, void *build_id); +void dso__read_running_kernel_build_id(struct dso *dso, + struct machine *machine); +struct symbol *dso__find_symbol(struct dso *dso, enum map_type type, + u64 addr); +struct symbol *dso__find_symbol_by_name(struct dso *dso, enum map_type type, const char *name); int filename__read_build_id(const char *filename, void *bf, size_t size); int sysfs__read_build_id(const char *filename, void *bf, size_t size); bool __dsos__read_build_ids(struct list_head *head, bool with_hits); -int build_id__sprintf(const u8 *self, int len, char *bf); +int build_id__sprintf(const u8 *build_id, int len, char *bf); int kallsyms__parse(const char *filename, void *arg, int (*process_symbol)(void *arg, const char *name, char type, u64 start, u64 end)); -void machine__destroy_kernel_maps(struct machine *self); -int __machine__create_kernel_maps(struct machine *self, struct dso *kernel); -int machine__create_kernel_maps(struct machine *self); +void machine__destroy_kernel_maps(struct machine *machine); +int __machine__create_kernel_maps(struct machine *machine, struct dso *kernel); +int machine__create_kernel_maps(struct machine *machine); -int machines__create_kernel_maps(struct rb_root *self, pid_t pid); -int machines__create_guest_kernel_maps(struct rb_root *self); -void machines__destroy_guest_kernel_maps(struct rb_root *self); +int machines__create_kernel_maps(struct rb_root *machines, pid_t pid); +int machines__create_guest_kernel_maps(struct rb_root *machines); +void machines__destroy_guest_kernel_maps(struct rb_root *machines); int symbol__init(void); void symbol__exit(void); bool symbol_type__is_a(char symbol_type, enum map_type map_type); -size_t machine__fprintf_vmlinux_path(struct machine *self, FILE *fp); +size_t machine__fprintf_vmlinux_path(struct machine *machine, FILE *fp); #endif /* __PERF_SYMBOL */ -- cgit v0.10.2 From 3643b133f2cb8023e8cedcbef43215a99d7df561 Mon Sep 17 00:00:00 2001 From: Michael Witten Date: Sat, 9 Apr 2011 01:12:56 +0000 Subject: perf tools: Makefile: Clean up `python/perf.so' rule There is no need for a subshell or an explicit `export'; as per the POSIX Shell Command Language specification: http://pubs.opengroup.org/onlinepubs/009695399/utilities/xcu_chap02.html#tag_02_09_01 http://pubs.opengroup.org/onlinepubs/009695399/utilities/xcu_chap02.html#tag_02_10_02 It is only necessary to include the environment variable assignment just before the command to be run. Also, it is better to use single-quotes, because GNU make might expand `$(BASIC_CFLAGS)' into something that the shell could interpret within double-quotes. Acked-by: Raghavendra D Prabhu Link: http://lkml.kernel.org/n/tip-58n38o02ocuzrm9qh096hsf5@git.kernel.org Signed-off-by: Michael Witten Signed-off-by: Arnaldo Carvalho de Melo diff --git a/tools/perf/Makefile b/tools/perf/Makefile index 207dee5..aaf4dd3 100644 --- a/tools/perf/Makefile +++ b/tools/perf/Makefile @@ -165,12 +165,10 @@ grep-libs = $(filter -l%,$(1)) strip-libs = $(filter-out -l%,$(1)) $(OUTPUT)python/perf.so: $(PYRF_OBJS) - $(QUIET_GEN)( \ - export CFLAGS="$(BASIC_CFLAGS)"; \ - python util/setup.py --quiet build_ext --build-lib='$(OUTPUT)python' \ - --build-temp='$(OUTPUT)python/temp' \ - ) - + $(QUIET_GEN)CFLAGS='$(BASIC_CFLAGS)' python util/setup.py \ + --quiet build_ext \ + --build-lib='$(OUTPUT)python' \ + --build-temp='$(OUTPUT)python/temp' # # No Perl scripts right now: # -- cgit v0.10.2 From ced465c400b23656ef2c4fbfb4add0e5b92e3d97 Mon Sep 17 00:00:00 2001 From: Michael Witten Date: Sat, 2 Apr 2011 21:46:09 +0000 Subject: perf tools: Makefile: PYTHON{,_CONFIG} to bandage Python 3 incompatibility Currently, Python 3 is not supported by perf's code; this can cause the build to fail for systems that have Python 3 installed as the default python: python{,-config} The Correct Solution is to write compatibility code so that Python 3 works out-of-the-box. However, users often have an ancillary Python 2 installed: python2{,-config} Therefore, a quick fix is to allow the user to specify those ancillary paths as the python binaries that Makefile should use, thereby avoiding Python 3 altogether; as an added benefit, the Python binaries may be installed in non-standard locations without the need for updating any PATH variable. This commit adds the ability to set PYTHON and/or PYTHON_CONFIG either as environment variables or as make variables on the command line; the paths may be relative, and usually only PYTHON is necessary in order for PYTHON_CONFIG to be defined implicitly. Some rudimentary error checking is performed when the user explicitly specifies a value for any of these variables. In addition, this commit introduces significantly robust makefile infrastructure for working with paths and communicating with the shell; it's currently only used for handling Python, but I hope it will prove useful in refactoring the makefiles. Thanks to: Raghavendra D Prabhu for motivating this patch. Acked-by: Raghavendra D Prabhu Link: http://lkml.kernel.org/r/e987828e-87ec-4973-95e7-47f10f5d9bab-mfwitten@gmail.com Signed-off-by: Michael Witten Signed-off-by: Arnaldo Carvalho de Melo diff --git a/tools/perf/Makefile b/tools/perf/Makefile index aaf4dd3..b5276c7 100644 --- a/tools/perf/Makefile +++ b/tools/perf/Makefile @@ -5,6 +5,8 @@ endif # The default target of this Makefile is... all: +include config/utilities.mak + ifneq ($(OUTPUT),) # check that the output directory actually exists OUTDIR := $(shell cd $(OUTPUT) && /bin/pwd) @@ -13,6 +15,12 @@ endif # Define V to have a more verbose compile. # +# Define PYTHON to point to the python binary if the default +# `python' is not correct; for example: PYTHON=python2 +# +# Define PYTHON_CONFIG to point to the python-config binary if +# the default `$(PYTHON)-config' is not correct. +# # Define ASCIIDOC8 if you want to format documentation with AsciiDoc 8 # # Define DOCBOOK_XSL_172 if you want to format man pages with DocBook XSL v1.72. @@ -165,7 +173,7 @@ grep-libs = $(filter -l%,$(1)) strip-libs = $(filter-out -l%,$(1)) $(OUTPUT)python/perf.so: $(PYRF_OBJS) - $(QUIET_GEN)CFLAGS='$(BASIC_CFLAGS)' python util/setup.py \ + $(QUIET_GEN)CFLAGS='$(BASIC_CFLAGS)' $(PYTHON_WORD) util/setup.py \ --quiet build_ext \ --build-lib='$(OUTPUT)python' \ --build-temp='$(OUTPUT)python/temp' @@ -473,24 +481,74 @@ else endif endif -ifdef NO_LIBPYTHON - BASIC_CFLAGS += -DNO_LIBPYTHON +disable-python = $(eval $(disable-python_code)) +define disable-python_code + BASIC_CFLAGS += -DNO_LIBPYTHON + $(if $(1),$(warning No $(1) was found)) + $(warning Python support won't be built) +endef + +override PYTHON := \ + $(call get-executable-or-default,PYTHON,python) + +ifndef PYTHON + $(call disable-python,python interpreter) + python-clean := else - PYTHON_EMBED_LDOPTS = $(shell python-config --ldflags 2>/dev/null) - PYTHON_EMBED_LDFLAGS = $(call strip-libs,$(PYTHON_EMBED_LDOPTS)) - PYTHON_EMBED_LIBADD = $(call grep-libs,$(PYTHON_EMBED_LDOPTS)) - PYTHON_EMBED_CCOPTS = `python-config --cflags 2>/dev/null` - FLAGS_PYTHON_EMBED=$(PYTHON_EMBED_CCOPTS) $(PYTHON_EMBED_LDOPTS) - ifneq ($(call try-cc,$(SOURCE_PYTHON_EMBED),$(FLAGS_PYTHON_EMBED)),y) - msg := $(warning No Python.h found, install python-dev[el] to have python support in 'perf script' and to build the python bindings) - BASIC_CFLAGS += -DNO_LIBPYTHON - else - ALL_LDFLAGS += $(PYTHON_EMBED_LDFLAGS) - EXTLIBS += $(PYTHON_EMBED_LIBADD) - LIB_OBJS += $(OUTPUT)util/scripting-engines/trace-event-python.o - LIB_OBJS += $(OUTPUT)scripts/python/Perf-Trace-Util/Context.o - LANG_BINDINGS += $(OUTPUT)python/perf.so - endif + + PYTHON_WORD := $(call shell-wordify,$(PYTHON)) + + python-clean := $(PYTHON_WORD) util/setup.py clean \ + --build-lib='$(OUTPUT)python' \ + --build-temp='$(OUTPUT)python/temp' + + ifdef NO_LIBPYTHON + $(call disable-python) + else + + override PYTHON_CONFIG := \ + $(call get-executable-or-default,PYTHON_CONFIG,$(PYTHON)-config) + + ifndef PYTHON_CONFIG + $(call disable-python,python-config tool) + else + + PYTHON_CONFIG_SQ := $(call shell-sq,$(PYTHON_CONFIG)) + + PYTHON_EMBED_LDOPTS := $(shell $(PYTHON_CONFIG_SQ) --ldflags 2>/dev/null) + PYTHON_EMBED_LDFLAGS := $(call strip-libs,$(PYTHON_EMBED_LDOPTS)) + PYTHON_EMBED_LIBADD := $(call grep-libs,$(PYTHON_EMBED_LDOPTS)) + PYTHON_EMBED_CCOPTS := $(shell $(PYTHON_CONFIG_SQ) --cflags 2>/dev/null) + FLAGS_PYTHON_EMBED := $(PYTHON_EMBED_CCOPTS) $(PYTHON_EMBED_LDOPTS) + + ifneq ($(call try-cc,$(SOURCE_PYTHON_EMBED),$(FLAGS_PYTHON_EMBED)),y) + $(call disable-python,Python.h (for Python 2.x)) + else + + ifneq ($(call try-cc,$(SOURCE_PYTHON_VERSION),$(FLAGS_PYTHON_EMBED)),y) + $(warning Python 3 is not yet supported; please set) + $(warning PYTHON and/or PYTHON_CONFIG appropriately.) + $(warning If you also have Python 2 installed, then) + $(warning try something like:) + $(warning $(and ,)) + $(warning $(and ,) make PYTHON=python2) + $(warning $(and ,)) + $(warning Otherwise, disable Python support entirely:) + $(warning $(and ,)) + $(warning $(and ,) make NO_LIBPYTHON=1) + $(warning $(and ,)) + $(error $(and ,)) + else + ALL_LDFLAGS += $(PYTHON_EMBED_LDFLAGS) + EXTLIBS += $(PYTHON_EMBED_LIBADD) + LIB_OBJS += $(OUTPUT)util/scripting-engines/trace-event-python.o + LIB_OBJS += $(OUTPUT)scripts/python/Perf-Trace-Util/Context.o + LANG_BINDINGS += $(OUTPUT)python/perf.so + endif + + endif + endif + endif endif ifdef NO_DEMANGLE @@ -831,8 +889,7 @@ clean: $(RM) *.spec *.pyc *.pyo */*.pyc */*.pyo $(OUTPUT)common-cmds.h TAGS tags cscope* $(MAKE) -C Documentation/ clean $(RM) $(OUTPUT)PERF-VERSION-FILE $(OUTPUT)PERF-CFLAGS - @python util/setup.py clean --build-lib='$(OUTPUT)python' \ - --build-temp='$(OUTPUT)python/temp' + $(python-clean) .PHONY: all install clean strip .PHONY: shell_compatibility_test please_set_SHELL_PATH_to_a_more_modern_shell diff --git a/tools/perf/config/utilities.mak b/tools/perf/config/utilities.mak new file mode 100644 index 0000000..6d8ff88 --- /dev/null +++ b/tools/perf/config/utilities.mak @@ -0,0 +1,180 @@ +# This allows us to work with the newline character: +define newline + + +endef +newline := $(newline) + +# nl-escape +# +# Usage: escape = $(call nl-escape[,escape]) +# +# This is used as the common way to specify +# what should replace a newline when escaping +# newlines; the default is a bizarre string. +# +nl-escape = $(or $(1),m822df3020w6a44id34bt574ctac44eb9f4n) + +# escape-nl +# +# Usage: escaped-text = $(call escape-nl,text[,escape]) +# +# GNU make's $(shell ...) function converts to a +# single space each newline character in the output +# produced during the expansion; this may not be +# desirable. +# +# The only solution is to change each newline into +# something that won't be converted, so that the +# information can be recovered later with +# $(call unescape-nl...) +# +escape-nl = $(subst $(newline),$(call nl-escape,$(2)),$(1)) + +# unescape-nl +# +# Usage: text = $(call unescape-nl,escaped-text[,escape]) +# +# See escape-nl. +# +unescape-nl = $(subst $(call nl-escape,$(2)),$(newline),$(1)) + +# shell-escape-nl +# +# Usage: $(shell some-command | $(call shell-escape-nl[,escape])) +# +# Use this to escape newlines from within a shell call; +# the default escape is a bizarre string. +# +# NOTE: The escape is used directly as a string constant +# in an `awk' program that is delimited by shell +# single-quotes, so be wary of the characters +# that are chosen. +# +define shell-escape-nl +awk 'NR==1 {t=$$0} NR>1 {t=t "$(nl-escape)" $$0} END {printf t}' +endef + +# shell-unescape-nl +# +# Usage: $(shell some-command | $(call shell-unescape-nl[,escape])) +# +# Use this to unescape newlines from within a shell call; +# the default escape is a bizarre string. +# +# NOTE: The escape is used directly as an extended regular +# expression constant in an `awk' program that is +# delimited by shell single-quotes, so be wary +# of the characters that are chosen. +# +# (The bash shell has a bug where `{gsub(...),...}' is +# misinterpreted as a brace expansion; this can be +# overcome by putting a space between `{' and `gsub'). +# +define shell-unescape-nl +awk 'NR==1 {t=$$0} NR>1 {t=t "\n" $$0} END { gsub(/$(nl-escape)/,"\n",t); printf t }' +endef + +# escape-for-shell-sq +# +# Usage: embeddable-text = $(call escape-for-shell-sq,text) +# +# This function produces text that is suitable for +# embedding in a shell string that is delimited by +# single-quotes. +# +escape-for-shell-sq = $(subst ','\'',$(1)) + +# shell-sq +# +# Usage: single-quoted-and-escaped-text = $(call shell-sq,text) +# +shell-sq = '$(escape-for-shell-sq)' + +# shell-wordify +# +# Usage: wordified-text = $(call shell-wordify,text) +# +# For instance: +# +# |define text +# |hello +# |world +# |endef +# | +# |target: +# | echo $(call shell-wordify,$(text)) +# +# At least GNU make gets confused by expanding a newline +# within the context of a command line of a makefile rule +# (this is in constrast to a `$(shell ...)' function call, +# which can handle it just fine). +# +# This function avoids the problem by producing a string +# that works as a shell word, regardless of whether or +# not it contains a newline. +# +# If the text to be wordified contains a newline, then +# an intrictate shell command substitution is constructed +# to render the text as a single line; when the shell +# processes the resulting escaped text, it transforms +# it into the original unescaped text. +# +# If the text does not contain a newline, then this function +# produces the same results as the `$(shell-sq)' function. +# +shell-wordify = $(if $(findstring $(newline),$(1)),$(_sw-esc-nl),$(shell-sq)) +define _sw-esc-nl +"$$(echo $(call escape-nl,$(shell-sq),$(2)) | $(call shell-unescape-nl,$(2)))" +endef + +# is-absolute +# +# Usage: bool-value = $(call is-absolute,path) +# +is-absolute = $(shell echo $(shell-sq) | grep ^/ -q && echo y) + +# lookup +# +# Usage: absolute-executable-path-or-empty = $(call lookup,path) +# +# (It's necessary to use `sh -c' because GNU make messes up by +# trying too hard and getting things wrong). +# +lookup = $(call unescape-nl,$(shell sh -c $(_l-sh))) +_l-sh = $(call shell-sq,command -v $(shell-sq) | $(call shell-escape-nl,)) + +# is-executable +# +# Usage: bool-value = $(call is-executable,path) +# +# (It's necessary to use `sh -c' because GNU make messes up by +# trying too hard and getting things wrong). +# +is-executable = $(call _is-executable-helper,$(shell-sq)) +_is-executable-helper = $(shell sh -c $(_is-executable-sh)) +_is-executable-sh = $(call shell-sq,test -f $(1) -a -x $(1) && echo y) + +# get-executable +# +# Usage: absolute-executable-path-or-empty = $(call get-executable,path) +# +# The goal is to get an absolute path for an executable; +# the `command -v' is defined by POSIX, but it's not +# necessarily very portable, so it's only used if +# relative path resolution is requested, as determined +# by the presence of a leading `/'. +# +get-executable = $(if $(1),$(if $(is-absolute),$(_ge-abspath),$(lookup))) +_ge-abspath = $(if $(is-executable),$(1)) + +# get-supplied-or-default-executable +# +# Usage: absolute-executable-path-or-empty = $(call get-executable-or-default,variable,default) +# +define get-executable-or-default +$(if $($(1)),$(call _ge_attempt,$($(1)),$(1)),$(call _ge_attempt,$(2))) +endef +_ge_attempt = $(or $(get-executable),$(_gea_warn),$(call _gea_err,$(2))) +_gea_warn = $(warning The path '$(1)' is not executable.) +_gea_err = $(if $(1),$(error Please set '$(1)' appropriately)) diff --git a/tools/perf/feature-tests.mak b/tools/perf/feature-tests.mak index b041ca6..1b33420 100644 --- a/tools/perf/feature-tests.mak +++ b/tools/perf/feature-tests.mak @@ -79,9 +79,15 @@ endef endif ifndef NO_LIBPYTHON +define SOURCE_PYTHON_VERSION +#include +#if PY_VERSION_HEX >= 0x03000000 + #error +#endif +int main(void){} +endef define SOURCE_PYTHON_EMBED #include - int main(void) { Py_Initialize(); -- cgit v0.10.2 From 7fbd065f5a2b299172502f09fc3fbde02b48f591 Mon Sep 17 00:00:00 2001 From: Michael Witten Date: Tue, 12 Apr 2011 20:27:59 +0000 Subject: perf tools: Move `try-cc' The `try-cc' user-defined function was in tools/perf/feature-tests.mak; this commit moves it to tools/perf/config/utilities.mak. Signed-off-by: Michael Witten Link: http://lkml.kernel.org/n/tip-bqhwcuxsrve0iodn6q4ejaoi@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo diff --git a/tools/perf/config/utilities.mak b/tools/perf/config/utilities.mak index 6d8ff88..8046182 100644 --- a/tools/perf/config/utilities.mak +++ b/tools/perf/config/utilities.mak @@ -178,3 +178,11 @@ endef _ge_attempt = $(or $(get-executable),$(_gea_warn),$(call _gea_err,$(2))) _gea_warn = $(warning The path '$(1)' is not executable.) _gea_err = $(if $(1),$(error Please set '$(1)' appropriately)) + +# try-cc +# Usage: option = $(call try-cc, source-to-build, cc-options) +try-cc = $(shell sh -c \ + 'TMP="$(OUTPUT)$(TMPOUT).$$$$"; \ + echo "$(1)" | \ + $(CC) -x c - $(2) -o "$$TMP" > /dev/null 2>&1 && echo y; \ + rm -f "$$TMP"') diff --git a/tools/perf/feature-tests.mak b/tools/perf/feature-tests.mak index 1b33420..6170fd2 100644 --- a/tools/perf/feature-tests.mak +++ b/tools/perf/feature-tests.mak @@ -126,11 +126,3 @@ int main(void) return 0; } endef - -# try-cc -# Usage: option = $(call try-cc, source-to-build, cc-options) -try-cc = $(shell sh -c \ - 'TMP="$(OUTPUT)$(TMPOUT).$$$$"; \ - echo "$(1)" | \ - $(CC) -x c - $(2) -o "$$TMP" > /dev/null 2>&1 && echo y; \ - rm -f "$$TMP"') -- cgit v0.10.2 From f18568aae5612ab37f20e5f383d6154ea69c9dfc Mon Sep 17 00:00:00 2001 From: Michael Witten Date: Tue, 12 Apr 2011 20:30:13 +0000 Subject: perf tools: git mv tools/perf/{features-tests.mak,config/} Signed-off-by: Michael Witten Link: http://lkml.kernel.org/n/tip-a6zhefjayuounko1tk5sjji2@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo diff --git a/tools/perf/Makefile b/tools/perf/Makefile index b5276c7..91ad5cc 100644 --- a/tools/perf/Makefile +++ b/tools/perf/Makefile @@ -138,7 +138,7 @@ INSTALL = install # explicitly what architecture to check for. Fix this up for yours.. SPARSE_FLAGS = -D__BIG_ENDIAN__ -D__powerpc__ --include feature-tests.mak +-include config/feature-tests.mak ifeq ($(call try-cc,$(SOURCE_HELLO),-Werror -fstack-protector-all),y) CFLAGS := $(CFLAGS) -fstack-protector-all diff --git a/tools/perf/config/feature-tests.mak b/tools/perf/config/feature-tests.mak new file mode 100644 index 0000000..6170fd2 --- /dev/null +++ b/tools/perf/config/feature-tests.mak @@ -0,0 +1,128 @@ +define SOURCE_HELLO +#include +int main(void) +{ + return puts(\"hi\"); +} +endef + +ifndef NO_DWARF +define SOURCE_DWARF +#include +#include +#include +#ifndef _ELFUTILS_PREREQ +#error +#endif + +int main(void) +{ + Dwarf *dbg = dwarf_begin(0, DWARF_C_READ); + return (long)dbg; +} +endef +endif + +define SOURCE_LIBELF +#include + +int main(void) +{ + Elf *elf = elf_begin(0, ELF_C_READ, 0); + return (long)elf; +} +endef + +define SOURCE_GLIBC +#include + +int main(void) +{ + const char *version = gnu_get_libc_version(); + return (long)version; +} +endef + +define SOURCE_ELF_MMAP +#include +int main(void) +{ + Elf *elf = elf_begin(0, ELF_C_READ_MMAP, 0); + return (long)elf; +} +endef + +ifndef NO_NEWT +define SOURCE_NEWT +#include + +int main(void) +{ + newtInit(); + newtCls(); + return newtFinished(); +} +endef +endif + +ifndef NO_LIBPERL +define SOURCE_PERL_EMBED +#include +#include + +int main(void) +{ +perl_alloc(); +return 0; +} +endef +endif + +ifndef NO_LIBPYTHON +define SOURCE_PYTHON_VERSION +#include +#if PY_VERSION_HEX >= 0x03000000 + #error +#endif +int main(void){} +endef +define SOURCE_PYTHON_EMBED +#include +int main(void) +{ + Py_Initialize(); + return 0; +} +endef +endif + +define SOURCE_BFD +#include + +int main(void) +{ + bfd_demangle(0, 0, 0); + return 0; +} +endef + +define SOURCE_CPLUS_DEMANGLE +extern char *cplus_demangle(const char *, int); + +int main(void) +{ + cplus_demangle(0, 0); + return 0; +} +endef + +define SOURCE_STRLCPY +#include +extern size_t strlcpy(char *dest, const char *src, size_t size); + +int main(void) +{ + strlcpy(NULL, NULL, 0); + return 0; +} +endef diff --git a/tools/perf/feature-tests.mak b/tools/perf/feature-tests.mak deleted file mode 100644 index 6170fd2..0000000 --- a/tools/perf/feature-tests.mak +++ /dev/null @@ -1,128 +0,0 @@ -define SOURCE_HELLO -#include -int main(void) -{ - return puts(\"hi\"); -} -endef - -ifndef NO_DWARF -define SOURCE_DWARF -#include -#include -#include -#ifndef _ELFUTILS_PREREQ -#error -#endif - -int main(void) -{ - Dwarf *dbg = dwarf_begin(0, DWARF_C_READ); - return (long)dbg; -} -endef -endif - -define SOURCE_LIBELF -#include - -int main(void) -{ - Elf *elf = elf_begin(0, ELF_C_READ, 0); - return (long)elf; -} -endef - -define SOURCE_GLIBC -#include - -int main(void) -{ - const char *version = gnu_get_libc_version(); - return (long)version; -} -endef - -define SOURCE_ELF_MMAP -#include -int main(void) -{ - Elf *elf = elf_begin(0, ELF_C_READ_MMAP, 0); - return (long)elf; -} -endef - -ifndef NO_NEWT -define SOURCE_NEWT -#include - -int main(void) -{ - newtInit(); - newtCls(); - return newtFinished(); -} -endef -endif - -ifndef NO_LIBPERL -define SOURCE_PERL_EMBED -#include -#include - -int main(void) -{ -perl_alloc(); -return 0; -} -endef -endif - -ifndef NO_LIBPYTHON -define SOURCE_PYTHON_VERSION -#include -#if PY_VERSION_HEX >= 0x03000000 - #error -#endif -int main(void){} -endef -define SOURCE_PYTHON_EMBED -#include -int main(void) -{ - Py_Initialize(); - return 0; -} -endef -endif - -define SOURCE_BFD -#include - -int main(void) -{ - bfd_demangle(0, 0, 0); - return 0; -} -endef - -define SOURCE_CPLUS_DEMANGLE -extern char *cplus_demangle(const char *, int); - -int main(void) -{ - cplus_demangle(0, 0); - return 0; -} -endef - -define SOURCE_STRLCPY -#include -extern size_t strlcpy(char *dest, const char *src, size_t size); - -int main(void) -{ - strlcpy(NULL, NULL, 0); - return 0; -} -endef -- cgit v0.10.2 From c21e6beba8835d09bb80e34961430b13e60381c5 Mon Sep 17 00:00:00 2001 From: Jens Axboe Date: Tue, 19 Apr 2011 13:32:46 +0200 Subject: block: get rid of QUEUE_FLAG_REENTER We are currently using this flag to check whether it's safe to call into ->request_fn(). If it is set, we punt to kblockd. But we get a lot of false positives and excessive punts to kblockd, which hurts performance. The only real abuser of this infrastructure is SCSI. So export the async queue run and convert SCSI over to use that. There's room for improvement in that SCSI need not always use the async call, but this fixes our performance issue and they can fix that up in due time. Signed-off-by: Jens Axboe diff --git a/block/blk-core.c b/block/blk-core.c index 580eee5..40725b9 100644 --- a/block/blk-core.c +++ b/block/blk-core.c @@ -303,15 +303,7 @@ void __blk_run_queue(struct request_queue *q) if (unlikely(blk_queue_stopped(q))) return; - /* - * Only recurse once to avoid overrunning the stack, let the unplug - * handling reinvoke the handler shortly if we already got there. - */ - if (!queue_flag_test_and_set(QUEUE_FLAG_REENTER, q)) { - q->request_fn(q); - queue_flag_clear(QUEUE_FLAG_REENTER, q); - } else - queue_delayed_work(kblockd_workqueue, &q->delay_work, 0); + q->request_fn(q); } EXPORT_SYMBOL(__blk_run_queue); @@ -328,6 +320,7 @@ void blk_run_queue_async(struct request_queue *q) if (likely(!blk_queue_stopped(q))) queue_delayed_work(kblockd_workqueue, &q->delay_work, 0); } +EXPORT_SYMBOL(blk_run_queue_async); /** * blk_run_queue - run a single device queue diff --git a/block/blk.h b/block/blk.h index c9df8fc..6126346 100644 --- a/block/blk.h +++ b/block/blk.h @@ -22,7 +22,6 @@ void blk_rq_timed_out_timer(unsigned long data); void blk_delete_timer(struct request *); void blk_add_timer(struct request *); void __generic_unplug_device(struct request_queue *); -void blk_run_queue_async(struct request_queue *q); /* * Internal atomic flags for request handling diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c index ab55c2f..e9901b8 100644 --- a/drivers/scsi/scsi_lib.c +++ b/drivers/scsi/scsi_lib.c @@ -411,8 +411,6 @@ static void scsi_run_queue(struct request_queue *q) list_splice_init(&shost->starved_list, &starved_list); while (!list_empty(&starved_list)) { - int flagset; - /* * As long as shost is accepting commands and we have * starved queues, call blk_run_queue. scsi_request_fn @@ -435,20 +433,7 @@ static void scsi_run_queue(struct request_queue *q) continue; } - spin_unlock(shost->host_lock); - - spin_lock(sdev->request_queue->queue_lock); - flagset = test_bit(QUEUE_FLAG_REENTER, &q->queue_flags) && - !test_bit(QUEUE_FLAG_REENTER, - &sdev->request_queue->queue_flags); - if (flagset) - queue_flag_set(QUEUE_FLAG_REENTER, sdev->request_queue); - __blk_run_queue(sdev->request_queue); - if (flagset) - queue_flag_clear(QUEUE_FLAG_REENTER, sdev->request_queue); - spin_unlock(sdev->request_queue->queue_lock); - - spin_lock(shost->host_lock); + blk_run_queue_async(sdev->request_queue); } /* put any unprocessed entries back */ list_splice(&starved_list, &shost->starved_list); diff --git a/drivers/scsi/scsi_transport_fc.c b/drivers/scsi/scsi_transport_fc.c index 28c3350..815069d 100644 --- a/drivers/scsi/scsi_transport_fc.c +++ b/drivers/scsi/scsi_transport_fc.c @@ -3816,28 +3816,17 @@ fail_host_msg: static void fc_bsg_goose_queue(struct fc_rport *rport) { - int flagset; - unsigned long flags; - if (!rport->rqst_q) return; + /* + * This get/put dance makes no sense + */ get_device(&rport->dev); - - spin_lock_irqsave(rport->rqst_q->queue_lock, flags); - flagset = test_bit(QUEUE_FLAG_REENTER, &rport->rqst_q->queue_flags) && - !test_bit(QUEUE_FLAG_REENTER, &rport->rqst_q->queue_flags); - if (flagset) - queue_flag_set(QUEUE_FLAG_REENTER, rport->rqst_q); - __blk_run_queue(rport->rqst_q); - if (flagset) - queue_flag_clear(QUEUE_FLAG_REENTER, rport->rqst_q); - spin_unlock_irqrestore(rport->rqst_q->queue_lock, flags); - + blk_run_queue_async(rport->rqst_q); put_device(&rport->dev); } - /** * fc_bsg_rport_dispatch - process rport bsg requests and dispatch to LLDD * @q: rport request queue diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h index cbbfd98..2ad95fa 100644 --- a/include/linux/blkdev.h +++ b/include/linux/blkdev.h @@ -388,20 +388,19 @@ struct request_queue #define QUEUE_FLAG_SYNCFULL 3 /* read queue has been filled */ #define QUEUE_FLAG_ASYNCFULL 4 /* write queue has been filled */ #define QUEUE_FLAG_DEAD 5 /* queue being torn down */ -#define QUEUE_FLAG_REENTER 6 /* Re-entrancy avoidance */ -#define QUEUE_FLAG_ELVSWITCH 7 /* don't use elevator, just do FIFO */ -#define QUEUE_FLAG_BIDI 8 /* queue supports bidi requests */ -#define QUEUE_FLAG_NOMERGES 9 /* disable merge attempts */ -#define QUEUE_FLAG_SAME_COMP 10 /* force complete on same CPU */ -#define QUEUE_FLAG_FAIL_IO 11 /* fake timeout */ -#define QUEUE_FLAG_STACKABLE 12 /* supports request stacking */ -#define QUEUE_FLAG_NONROT 13 /* non-rotational device (SSD) */ +#define QUEUE_FLAG_ELVSWITCH 6 /* don't use elevator, just do FIFO */ +#define QUEUE_FLAG_BIDI 7 /* queue supports bidi requests */ +#define QUEUE_FLAG_NOMERGES 8 /* disable merge attempts */ +#define QUEUE_FLAG_SAME_COMP 9 /* force complete on same CPU */ +#define QUEUE_FLAG_FAIL_IO 10 /* fake timeout */ +#define QUEUE_FLAG_STACKABLE 11 /* supports request stacking */ +#define QUEUE_FLAG_NONROT 12 /* non-rotational device (SSD) */ #define QUEUE_FLAG_VIRT QUEUE_FLAG_NONROT /* paravirt device */ -#define QUEUE_FLAG_IO_STAT 15 /* do IO stats */ -#define QUEUE_FLAG_DISCARD 16 /* supports DISCARD */ -#define QUEUE_FLAG_NOXMERGES 17 /* No extended merges */ -#define QUEUE_FLAG_ADD_RANDOM 18 /* Contributes to random pool */ -#define QUEUE_FLAG_SECDISCARD 19 /* supports SECDISCARD */ +#define QUEUE_FLAG_IO_STAT 13 /* do IO stats */ +#define QUEUE_FLAG_DISCARD 14 /* supports DISCARD */ +#define QUEUE_FLAG_NOXMERGES 15 /* No extended merges */ +#define QUEUE_FLAG_ADD_RANDOM 16 /* Contributes to random pool */ +#define QUEUE_FLAG_SECDISCARD 17 /* supports SECDISCARD */ #define QUEUE_FLAG_DEFAULT ((1 << QUEUE_FLAG_IO_STAT) | \ (1 << QUEUE_FLAG_STACKABLE) | \ @@ -699,6 +698,7 @@ extern void blk_sync_queue(struct request_queue *q); extern void __blk_stop_queue(struct request_queue *q); extern void __blk_run_queue(struct request_queue *q); extern void blk_run_queue(struct request_queue *); +extern void blk_run_queue_async(struct request_queue *q); extern int blk_rq_map_user(struct request_queue *, struct request *, struct rq_map_data *, void __user *, unsigned long, gfp_t); -- cgit v0.10.2 From d350e6b6e819df0a383ff34465720bfaa0f91c79 Mon Sep 17 00:00:00 2001 From: Jens Axboe Date: Tue, 19 Apr 2011 13:34:14 +0200 Subject: block: remove stale kerneldoc member from __blk_run_queue() We don't pass in a 'force_kblockd' anymore, get rid of the stsale comment. Reported-by: Mike Snitzer Signed-off-by: Jens Axboe diff --git a/block/blk-core.c b/block/blk-core.c index 40725b9..a2e58ee 100644 --- a/block/blk-core.c +++ b/block/blk-core.c @@ -292,7 +292,6 @@ EXPORT_SYMBOL(blk_sync_queue); /** * __blk_run_queue - run a single device queue * @q: The queue to run - * @force_kblockd: Don't run @q->request_fn directly. Use kblockd. * * Description: * See @blk_run_queue. This variant must be called with the queue lock -- cgit v0.10.2 From ed5302d3c25006a9edc7a7fbea97a30483f89ef7 Mon Sep 17 00:00:00 2001 From: Liu Yuan Date: Tue, 19 Apr 2011 13:47:58 +0200 Subject: block, blk-sysfs: Fix an err return path in blk_register_queue() We do not call blk_trace_remove_sysfs() in err return path if kobject_add() fails. This path fixes it. Cc: stable@kernel.org Signed-off-by: Liu Yuan Signed-off-by: Jens Axboe diff --git a/block/blk-sysfs.c b/block/blk-sysfs.c index 6d73512..5d696ad 100644 --- a/block/blk-sysfs.c +++ b/block/blk-sysfs.c @@ -508,8 +508,10 @@ int blk_register_queue(struct gendisk *disk) return ret; ret = kobject_add(&q->kobj, kobject_get(&dev->kobj), "%s", "queue"); - if (ret < 0) + if (ret < 0) { + blk_trace_remove_sysfs(dev); return ret; + } kobject_uevent(&q->kobj, KOBJ_ADD); -- cgit v0.10.2 From 60735b6362f29b52b5635a2dfa9ab5ad39948345 Mon Sep 17 00:00:00 2001 From: Tao Ma Date: Tue, 19 Apr 2011 13:50:40 +0200 Subject: block: Remove the extra check in queue_requests_store In queue_requests_store, the code looks like if (rl->count[BLK_RW_SYNC] >= q->nr_requests) { blk_set_queue_full(q, BLK_RW_SYNC); } else if (rl->count[BLK_RW_SYNC]+1 <= q->nr_requests) { blk_clear_queue_full(q, BLK_RW_SYNC); wake_up(&rl->wait[BLK_RW_SYNC]); } If we don't satify the situation of "if", we can get that rl->count[BLK_RW_SYNC} < q->nr_quests. It is the same as rl->count[BLK_RW_SYNC]+1 <= q->nr_requests. All the "else" should satisfy the "else if" check so it isn't needed actually. Signed-off-by: Tao Ma Signed-off-by: Jens Axboe diff --git a/block/blk-sysfs.c b/block/blk-sysfs.c index 5d696ad..bd23631 100644 --- a/block/blk-sysfs.c +++ b/block/blk-sysfs.c @@ -66,14 +66,14 @@ queue_requests_store(struct request_queue *q, const char *page, size_t count) if (rl->count[BLK_RW_SYNC] >= q->nr_requests) { blk_set_queue_full(q, BLK_RW_SYNC); - } else if (rl->count[BLK_RW_SYNC]+1 <= q->nr_requests) { + } else { blk_clear_queue_full(q, BLK_RW_SYNC); wake_up(&rl->wait[BLK_RW_SYNC]); } if (rl->count[BLK_RW_ASYNC] >= q->nr_requests) { blk_set_queue_full(q, BLK_RW_ASYNC); - } else if (rl->count[BLK_RW_ASYNC]+1 <= q->nr_requests) { + } else { blk_clear_queue_full(q, BLK_RW_ASYNC); wake_up(&rl->wait[BLK_RW_ASYNC]); } -- cgit v0.10.2 From 62c7d085e1f2a1f2b4d89560551eff18d703b3b1 Mon Sep 17 00:00:00 2001 From: Luciano Coelho Date: Thu, 10 Mar 2011 16:42:47 +0200 Subject: wl12xx: add new board_tcxo_clock element to the platform data This new value is a new type of clock setting that is used by wl128x chipsets. Signed-off-by: Luciano Coelho diff --git a/include/linux/wl12xx.h b/include/linux/wl12xx.h index bebb8ef..eb8aaca 100644 --- a/include/linux/wl12xx.h +++ b/include/linux/wl12xx.h @@ -24,7 +24,7 @@ #ifndef _LINUX_WL12XX_H #define _LINUX_WL12XX_H -/* The board reference clock values */ +/* Reference clock values */ enum { WL12XX_REFCLOCK_19 = 0, /* 19.2 MHz */ WL12XX_REFCLOCK_26 = 1, /* 26 MHz */ @@ -32,12 +32,25 @@ enum { WL12XX_REFCLOCK_54 = 3, /* 54 MHz */ }; +/* TCXO clock values */ +enum { + WL12XX_TCXOCLOCK_19_2 = 0, /* 19.2MHz */ + WL12XX_TCXOCLOCK_26 = 1, /* 26 MHz */ + WL12XX_TCXOCLOCK_38_4 = 2, /* 38.4MHz */ + WL12XX_TCXOCLOCK_52 = 3, /* 52 MHz */ + WL12XX_TCXOCLOCK_16_368 = 4, /* 16.368 MHz */ + WL12XX_TCXOCLOCK_32_736 = 5, /* 32.736 MHz */ + WL12XX_TCXOCLOCK_16_8 = 6, /* 16.8 MHz */ + WL12XX_TCXOCLOCK_33_6 = 7, /* 33.6 MHz */ +}; + struct wl12xx_platform_data { void (*set_power)(bool enable); /* SDIO only: IRQ number if WLAN_IRQ line is used, 0 for SDIO IRQs */ int irq; bool use_eeprom; int board_ref_clock; + int board_tcxo_clock; }; #ifdef CONFIG_WL12XX_PLATFORM_DATA -- cgit v0.10.2 From b9b0fdead0e8d964a534e5b09f40d8bd4bf7dfe8 Mon Sep 17 00:00:00 2001 From: Shahar Levi Date: Sun, 6 Mar 2011 16:32:06 +0200 Subject: wl12xx: 1281/1283 support - move IRQ polarity In order to prevent overran of IRQ polarity via FW the polarity setting move after FW download and before IRQ enable. Signed-off-by: Shahar Levi Reviewed-by: Luciano Coelho Signed-off-by: Luciano Coelho diff --git a/drivers/net/wireless/wl12xx/boot.c b/drivers/net/wireless/wl12xx/boot.c index 6934dff..69fe870 100644 --- a/drivers/net/wireless/wl12xx/boot.c +++ b/drivers/net/wireless/wl12xx/boot.c @@ -585,13 +585,6 @@ int wl1271_load_firmware(struct wl1271 *wl) /* 6. read the EEPROM parameters */ tmp = wl1271_read32(wl, SCR_PAD2); - ret = wl1271_boot_write_irq_polarity(wl); - if (ret < 0) - goto out; - - wl1271_write32(wl, ACX_REG_INTERRUPT_MASK, - WL1271_ACX_ALL_EVENTS_VECTOR); - /* WL1271: The reference driver skips steps 7 to 10 (jumps directly * to upload_fw) */ @@ -618,6 +611,13 @@ int wl1271_boot(struct wl1271 *wl) if (ret < 0) goto out; + ret = wl1271_boot_write_irq_polarity(wl); + if (ret < 0) + goto out; + + wl1271_write32(wl, ACX_REG_INTERRUPT_MASK, + WL1271_ACX_ALL_EVENTS_VECTOR); + /* Enable firmware interrupts now */ wl1271_boot_enable_interrupts(wl); -- cgit v0.10.2 From 5aa42346bba2e385674eb1dd4019dfce4c2ef771 Mon Sep 17 00:00:00 2001 From: Shahar Levi Date: Sun, 6 Mar 2011 16:32:07 +0200 Subject: wl12xx: 1281/1283 support - Add Definitions Definitions to support wl128x: - New FW file name - Chip ID - New PLL Configuration Algorithm macros that will be used at wl128x boot stage - Rename NVS macro name: wl127x and wl128x are using the same NVS file name. However, the ini parameters between them are different. The driver will validate the correct NVS size in wl1271_boot_upload_nvs(). [Cleaned up some of the definitions. -- Luca] Signed-off-by: Shahar Levi Reviewed-by: Luciano Coelho Signed-off-by: Luciano Coelho diff --git a/drivers/net/wireless/wl12xx/boot.h b/drivers/net/wireless/wl12xx/boot.h index 17229b8..1f5ee31 100644 --- a/drivers/net/wireless/wl12xx/boot.h +++ b/drivers/net/wireless/wl12xx/boot.h @@ -74,4 +74,52 @@ struct wl1271_static_data { #define FREF_CLK_POLARITY_BITS 0xfffff8ff #define CLK_REQ_OUTN_SEL 0x700 +/* PLL configuration algorithm for wl128x */ +#define SYS_CLK_CFG_REG 0x2200 +/* Bit[0] - 0-TCXO, 1-FREF */ +#define MCS_PLL_CLK_SEL_FREF BIT(0) +/* Bit[3:2] - 01-TCXO, 10-FREF */ +#define WL_CLK_REQ_TYPE_FREF BIT(3) +#define WL_CLK_REQ_TYPE_PG2 (BIT(3) | BIT(2)) +/* Bit[4] - 0-TCXO, 1-FREF */ +#define PRCM_CM_EN_MUX_WLAN_FREF BIT(4) + +#define TCXO_ILOAD_INT_REG 0x2264 +#define TCXO_CLK_DETECT_REG 0x2266 + +#define TCXO_DET_FAILED BIT(4) + +#define FREF_ILOAD_INT_REG 0x2084 +#define FREF_CLK_DETECT_REG 0x2086 +#define FREF_CLK_DETECT_FAIL BIT(4) + +/* Use this reg for masking during driver access */ +#define WL_SPARE_REG 0x2320 +#define WL_SPARE_VAL BIT(2) +/* Bit[6:5:3] - mask wl write SYS_CLK_CFG[8:5:2:4] */ +#define WL_SPARE_MASK_8526 (BIT(6) | BIT(5) | BIT(3)) + +#define PLL_LOCK_COUNTERS_REG 0xD8C +#define PLL_LOCK_COUNTERS_COEX 0x0F +#define PLL_LOCK_COUNTERS_MCS 0xF0 +#define MCS_PLL_OVERRIDE_REG 0xD90 +#define MCS_PLL_CONFIG_REG 0xD92 +#define MCS_SEL_IN_FREQ_MASK 0x0070 +#define MCS_SEL_IN_FREQ_SHIFT 4 +#define MCS_PLL_CONFIG_REG_VAL 0x73 + +#define MCS_PLL_M_REG 0xD94 +#define MCS_PLL_N_REG 0xD96 +#define MCS_PLL_M_REG_VAL 0xC8 +#define MCS_PLL_N_REG_VAL 0x07 + +#define SDIO_IO_DS 0xd14 + +/* SDIO/wSPI DS configuration values */ +#define HCI_IO_DS_8MA 0 +#define HCI_IO_DS_4MA 1 /* default */ +#define HCI_IO_DS_6MA 2 +#define HCI_IO_DS_2MA 3 +/* end PLL configuration algorithm for wl128x */ + #endif diff --git a/drivers/net/wireless/wl12xx/conf.h b/drivers/net/wireless/wl12xx/conf.h index 856a8a2..a00f22c 100644 --- a/drivers/net/wireless/wl12xx/conf.h +++ b/drivers/net/wireless/wl12xx/conf.h @@ -1004,7 +1004,9 @@ enum { CONF_REF_CLK_19_2_E, CONF_REF_CLK_26_E, CONF_REF_CLK_38_4_E, - CONF_REF_CLK_52_E + CONF_REF_CLK_52_E, + CONF_REF_CLK_38_4_M_XTAL, + CONF_REF_CLK_26_M_XTAL, }; enum single_dual_band_enum { diff --git a/drivers/net/wireless/wl12xx/main.c b/drivers/net/wireless/wl12xx/main.c index 8b3c8d1..b0c4935 100644 --- a/drivers/net/wireless/wl12xx/main.c +++ b/drivers/net/wireless/wl12xx/main.c @@ -838,7 +838,7 @@ static int wl1271_fetch_nvs(struct wl1271 *wl) const struct firmware *fw; int ret; - ret = request_firmware(&fw, WL1271_NVS_NAME, wl1271_wl_to_dev(wl)); + ret = request_firmware(&fw, WL12XX_NVS_NAME, wl1271_wl_to_dev(wl)); if (ret < 0) { wl1271_error("could not get nvs file: %d", ret); diff --git a/drivers/net/wireless/wl12xx/reg.h b/drivers/net/wireless/wl12xx/reg.h index 9909607..440a4ee 100644 --- a/drivers/net/wireless/wl12xx/reg.h +++ b/drivers/net/wireless/wl12xx/reg.h @@ -207,6 +207,8 @@ #define CHIP_ID_1271_PG10 (0x4030101) #define CHIP_ID_1271_PG20 (0x4030111) +#define CHIP_ID_1283_PG10 (0x05030101) +#define CHIP_ID_1283_PG20 (0x05030111) #define ENABLE (REGISTERS_BASE + 0x5450) @@ -452,24 +454,11 @@ #define HI_CFG_UART_TX_OUT_GPIO_14 0x00000200 #define HI_CFG_UART_TX_OUT_GPIO_7 0x00000400 -/* - * NOTE: USE_ACTIVE_HIGH compilation flag should be defined in makefile - * for platforms using active high interrupt level - */ -#ifdef USE_ACTIVE_HIGH #define HI_CFG_DEF_VAL \ (HI_CFG_UART_ENABLE | \ HI_CFG_RST232_ENABLE | \ HI_CFG_CLOCK_REQ_SELECT | \ HI_CFG_HOST_INT_ENABLE) -#else -#define HI_CFG_DEF_VAL \ - (HI_CFG_UART_ENABLE | \ - HI_CFG_RST232_ENABLE | \ - HI_CFG_CLOCK_REQ_SELECT | \ - HI_CFG_HOST_INT_ENABLE) - -#endif #define REF_FREQ_19_2 0 #define REF_FREQ_26_0 1 diff --git a/drivers/net/wireless/wl12xx/sdio.c b/drivers/net/wireless/wl12xx/sdio.c index b1c7d03..1b6a1ad 100644 --- a/drivers/net/wireless/wl12xx/sdio.c +++ b/drivers/net/wireless/wl12xx/sdio.c @@ -343,4 +343,5 @@ MODULE_LICENSE("GPL"); MODULE_AUTHOR("Luciano Coelho "); MODULE_AUTHOR("Juuso Oikarinen "); MODULE_FIRMWARE(WL1271_FW_NAME); +MODULE_FIRMWARE(WL128X_FW_NAME); MODULE_FIRMWARE(WL1271_AP_FW_NAME); diff --git a/drivers/net/wireless/wl12xx/sdio_test.c b/drivers/net/wireless/wl12xx/sdio_test.c index 9fcbd3d..01adf1b 100644 --- a/drivers/net/wireless/wl12xx/sdio_test.c +++ b/drivers/net/wireless/wl12xx/sdio_test.c @@ -227,7 +227,7 @@ static int wl1271_fetch_nvs(struct wl1271 *wl) const struct firmware *fw; int ret; - ret = request_firmware(&fw, WL1271_NVS_NAME, wl1271_wl_to_dev(wl)); + ret = request_firmware(&fw, WL12XX_NVS_NAME, wl1271_wl_to_dev(wl)); if (ret < 0) { wl1271_error("could not get nvs file: %d", ret); diff --git a/drivers/net/wireless/wl12xx/spi.c b/drivers/net/wireless/wl12xx/spi.c index ffc745b..80295f5 100644 --- a/drivers/net/wireless/wl12xx/spi.c +++ b/drivers/net/wireless/wl12xx/spi.c @@ -490,5 +490,6 @@ MODULE_LICENSE("GPL"); MODULE_AUTHOR("Luciano Coelho "); MODULE_AUTHOR("Juuso Oikarinen "); MODULE_FIRMWARE(WL1271_FW_NAME); +MODULE_FIRMWARE(WL128X_FW_NAME); MODULE_FIRMWARE(WL1271_AP_FW_NAME); MODULE_ALIAS("spi:wl1271"); diff --git a/drivers/net/wireless/wl12xx/wl12xx.h b/drivers/net/wireless/wl12xx/wl12xx.h index 86be83e..a2e899d 100644 --- a/drivers/net/wireless/wl12xx/wl12xx.h +++ b/drivers/net/wireless/wl12xx/wl12xx.h @@ -131,9 +131,15 @@ extern u32 wl12xx_debug_level; #define WL1271_FW_NAME "ti-connectivity/wl1271-fw-2.bin" +#define WL128X_FW_NAME "ti-connectivity/wl128x-fw.bin" #define WL1271_AP_FW_NAME "ti-connectivity/wl1271-fw-ap.bin" -#define WL1271_NVS_NAME "ti-connectivity/wl1271-nvs.bin" +/* + * wl127x and wl128x are using the same NVS file name. However, the + * ini parameters between them are different. The driver validates + * the correct NVS size in wl1271_boot_upload_nvs(). + */ +#define WL12XX_NVS_NAME "ti-connectivity/wl1271-nvs.bin" #define WL1271_TX_SECURITY_LO16(s) ((u16)((s) & 0xffff)) #define WL1271_TX_SECURITY_HI32(s) ((u32)(((s) >> 16) & 0xffffffff)) -- cgit v0.10.2 From 48a61477bdc04896bd96d259388a0c42a7019943 Mon Sep 17 00:00:00 2001 From: Shahar Levi Date: Sun, 6 Mar 2011 16:32:08 +0200 Subject: wl12xx: 1281/1283 support - Add acx commands New acx command that sets: Rx fifo enable reduced bus transactions in RX path. Tx bus transactions padding to SDIO block size that improve preference in Tx and essential for working with SDIO HS (48Mhz). The max SDIO block size is 256 when working with Tx bus transactions padding to SDIO block. Add new ops to SDIO & SPI that handles the win size change in case of transactions padding (relevant only for SDIO). [Fix endianess issues; simplify sdio-specific block_size handling; minor changes in comments; use "aligned_len" in one calculation instead of "pad" to avoid confusion -- Luca] Signed-off-by: Shahar Levi Reviewed-by: Luciano Coelho Signed-off-by: Luciano Coelho diff --git a/drivers/net/wireless/wl12xx/acx.c b/drivers/net/wireless/wl12xx/acx.c index a3db755..50676b3 100644 --- a/drivers/net/wireless/wl12xx/acx.c +++ b/drivers/net/wireless/wl12xx/acx.c @@ -1019,6 +1019,32 @@ out: return ret; } +int wl1271_acx_host_if_cfg_bitmap(struct wl1271 *wl, u32 host_cfg_bitmap) +{ + struct wl1271_acx_host_config_bitmap *bitmap_conf; + int ret; + + bitmap_conf = kzalloc(sizeof(*bitmap_conf), GFP_KERNEL); + if (!bitmap_conf) { + ret = -ENOMEM; + goto out; + } + + bitmap_conf->host_cfg_bitmap = cpu_to_le32(host_cfg_bitmap); + + ret = wl1271_cmd_configure(wl, ACX_HOST_IF_CFG_BITMAP, + bitmap_conf, sizeof(*bitmap_conf)); + if (ret < 0) { + wl1271_warning("wl1271 bitmap config opt failed: %d", ret); + goto out; + } + +out: + kfree(bitmap_conf); + + return ret; +} + int wl1271_acx_init_mem_config(struct wl1271 *wl) { int ret; diff --git a/drivers/net/wireless/wl12xx/acx.h b/drivers/net/wireless/wl12xx/acx.h index dd19b01..0a40cae 100644 --- a/drivers/net/wireless/wl12xx/acx.h +++ b/drivers/net/wireless/wl12xx/acx.h @@ -939,6 +939,16 @@ struct wl1271_acx_keep_alive_config { u8 padding; } __packed; +#define HOST_IF_CFG_RX_FIFO_ENABLE BIT(0) +#define HOST_IF_CFG_TX_EXTRA_BLKS_SWAP BIT(1) +#define HOST_IF_CFG_TX_PAD_TO_SDIO_BLK BIT(3) + +struct wl1271_acx_host_config_bitmap { + struct acx_header header; + + __le32 host_cfg_bitmap; +} __packed; + enum { WL1271_ACX_TRIG_TYPE_LEVEL = 0, WL1271_ACX_TRIG_TYPE_EDGE, @@ -1275,6 +1285,7 @@ int wl1271_acx_tx_config_options(struct wl1271 *wl); int wl1271_acx_ap_mem_cfg(struct wl1271 *wl); int wl1271_acx_sta_mem_cfg(struct wl1271 *wl); int wl1271_acx_init_mem_config(struct wl1271 *wl); +int wl1271_acx_host_if_cfg_bitmap(struct wl1271 *wl, u32 host_cfg_bitmap); int wl1271_acx_init_rx_interrupt(struct wl1271 *wl); int wl1271_acx_smart_reflex(struct wl1271 *wl); int wl1271_acx_bet_enable(struct wl1271 *wl, bool enable); diff --git a/drivers/net/wireless/wl12xx/init.c b/drivers/net/wireless/wl12xx/init.c index 6072fe4..34c4108 100644 --- a/drivers/net/wireless/wl12xx/init.c +++ b/drivers/net/wireless/wl12xx/init.c @@ -31,6 +31,7 @@ #include "cmd.h" #include "reg.h" #include "tx.h" +#include "io.h" int wl1271_sta_init_templates_config(struct wl1271 *wl) { @@ -504,6 +505,27 @@ static int wl1271_set_ba_policies(struct wl1271 *wl) return ret; } +int wl1271_chip_specific_init(struct wl1271 *wl) +{ + int ret = 0; + + if (wl->chip.id == CHIP_ID_1283_PG20) { + u32 host_cfg_bitmap = HOST_IF_CFG_RX_FIFO_ENABLE; + + if (wl1271_set_block_size(wl)) + /* Enable SDIO padding */ + host_cfg_bitmap |= HOST_IF_CFG_TX_PAD_TO_SDIO_BLK; + + /* Must be before wl1271_acx_init_mem_config() */ + ret = wl1271_acx_host_if_cfg_bitmap(wl, host_cfg_bitmap); + if (ret < 0) + goto out; + } +out: + return ret; +} + + int wl1271_hw_init(struct wl1271 *wl) { struct conf_tx_ac_category *conf_ac; @@ -519,6 +541,11 @@ int wl1271_hw_init(struct wl1271 *wl) if (ret < 0) return ret; + /* Chip-specific init */ + ret = wl1271_chip_specific_init(wl); + if (ret < 0) + return ret; + /* Mode specific init */ if (is_ap) ret = wl1271_ap_hw_init(wl); diff --git a/drivers/net/wireless/wl12xx/init.h b/drivers/net/wireless/wl12xx/init.h index 3a8bd3f..4975270 100644 --- a/drivers/net/wireless/wl12xx/init.h +++ b/drivers/net/wireless/wl12xx/init.h @@ -31,6 +31,7 @@ int wl1271_sta_init_templates_config(struct wl1271 *wl); int wl1271_init_phy_config(struct wl1271 *wl); int wl1271_init_pta(struct wl1271 *wl); int wl1271_init_energy_detection(struct wl1271 *wl); +int wl1271_chip_specific_init(struct wl1271 *wl); int wl1271_hw_init(struct wl1271 *wl); #endif diff --git a/drivers/net/wireless/wl12xx/io.c b/drivers/net/wireless/wl12xx/io.c index d557f73..aa40c98 100644 --- a/drivers/net/wireless/wl12xx/io.c +++ b/drivers/net/wireless/wl12xx/io.c @@ -43,6 +43,16 @@ #define OCP_STATUS_REQ_FAILED 0x20000 #define OCP_STATUS_RESP_ERROR 0x30000 +bool wl1271_set_block_size(struct wl1271 *wl) +{ + if (wl->if_ops->set_block_size) { + wl->if_ops->set_block_size(wl); + return true; + } + + return false; +} + void wl1271_disable_interrupts(struct wl1271 *wl) { wl->if_ops->disable_irq(wl); diff --git a/drivers/net/wireless/wl12xx/io.h b/drivers/net/wireless/wl12xx/io.h index c1aac82..84454f6 100644 --- a/drivers/net/wireless/wl12xx/io.h +++ b/drivers/net/wireless/wl12xx/io.h @@ -169,5 +169,6 @@ int wl1271_init_ieee80211(struct wl1271 *wl); struct ieee80211_hw *wl1271_alloc_hw(void); int wl1271_free_hw(struct wl1271 *wl); irqreturn_t wl1271_irq(int irq, void *data); +bool wl1271_set_block_size(struct wl1271 *wl); #endif diff --git a/drivers/net/wireless/wl12xx/main.c b/drivers/net/wireless/wl12xx/main.c index b0c4935..f24906f 100644 --- a/drivers/net/wireless/wl12xx/main.c +++ b/drivers/net/wireless/wl12xx/main.c @@ -450,6 +450,11 @@ static int wl1271_plt_init(struct wl1271 *wl) if (ret < 0) return ret; + /* Chip-specific initializations */ + ret = wl1271_chip_specific_init(wl); + if (ret < 0) + return ret; + ret = wl1271_sta_init_templates_config(wl); if (ret < 0) return ret; @@ -1335,6 +1340,7 @@ static void __wl1271_op_remove_interface(struct wl1271 *wl) memset(wl->ap_hlid_map, 0, sizeof(wl->ap_hlid_map)); wl->ap_fw_ps_map = 0; wl->ap_ps_map = 0; + wl->block_size = 0; for (i = 0; i < NUM_TX_QUEUES; i++) wl->tx_blocks_freed[i] = 0; @@ -3458,6 +3464,7 @@ struct ieee80211_hw *wl1271_alloc_hw(void) wl->ap_ps_map = 0; wl->ap_fw_ps_map = 0; wl->quirks = 0; + wl->block_size = 0; memset(wl->tx_frames_map, 0, sizeof(wl->tx_frames_map)); for (i = 0; i < ACX_TX_DESCRIPTORS; i++) diff --git a/drivers/net/wireless/wl12xx/tx.c b/drivers/net/wireless/wl12xx/tx.c index 5e9ef7d..e296f0a 100644 --- a/drivers/net/wireless/wl12xx/tx.c +++ b/drivers/net/wireless/wl12xx/tx.c @@ -132,6 +132,7 @@ static int wl1271_tx_allocate(struct wl1271 *wl, struct sk_buff *skb, u32 extra, { struct wl1271_tx_hw_descr *desc; u32 total_len = skb->len + sizeof(struct wl1271_tx_hw_descr) + extra; + u32 len; u32 total_blocks; int id, ret = -EBUSY; @@ -145,14 +146,20 @@ static int wl1271_tx_allocate(struct wl1271 *wl, struct sk_buff *skb, u32 extra, /* approximate the number of blocks required for this packet in the firmware */ - total_blocks = total_len + TX_HW_BLOCK_SIZE - 1; - total_blocks = total_blocks / TX_HW_BLOCK_SIZE + TX_HW_BLOCK_SPARE; + if (wl->block_size) + len = ALIGN(total_len, wl->block_size); + else + len = total_len; + + total_blocks = (len + TX_HW_BLOCK_SIZE - 1) / TX_HW_BLOCK_SIZE + + TX_HW_BLOCK_SPARE; + if (total_blocks <= wl->tx_blocks_available) { desc = (struct wl1271_tx_hw_descr *)skb_push( skb, total_len - skb->len); - desc->extra_mem_blocks = TX_HW_BLOCK_SPARE; - desc->total_mem_blocks = total_blocks; + desc->wl127x_mem.extra_blocks = TX_HW_BLOCK_SPARE; + desc->wl127x_mem.total_mem_blocks = total_blocks; desc->id = id; wl->tx_blocks_available -= total_blocks; @@ -178,7 +185,7 @@ static void wl1271_tx_fill_hdr(struct wl1271 *wl, struct sk_buff *skb, { struct timespec ts; struct wl1271_tx_hw_descr *desc; - int pad, ac, rate_idx; + int aligned_len, ac, rate_idx; s64 hosttime; u16 tx_attr; @@ -237,20 +244,32 @@ static void wl1271_tx_fill_hdr(struct wl1271 *wl, struct sk_buff *skb, tx_attr |= rate_idx << TX_HW_ATTR_OFST_RATE_POLICY; desc->reserved = 0; - /* align the length (and store in terms of words) */ - pad = ALIGN(skb->len, WL1271_TX_ALIGN_TO); - desc->length = cpu_to_le16(pad >> 2); + if (wl->block_size) { + aligned_len = ALIGN(skb->len, wl->block_size); + + desc->wl128x_mem.extra_bytes = aligned_len - skb->len; + desc->length = cpu_to_le16(aligned_len >> 2); + } else { + int pad; + + /* align the length (and store in terms of words) */ + aligned_len = ALIGN(skb->len, WL1271_TX_ALIGN_TO); + desc->length = cpu_to_le16(aligned_len >> 2); + + /* calculate number of padding bytes */ + pad = aligned_len - skb->len; + tx_attr |= pad << TX_HW_ATTR_OFST_LAST_WORD_PAD; - /* calculate number of padding bytes */ - pad = pad - skb->len; - tx_attr |= pad << TX_HW_ATTR_OFST_LAST_WORD_PAD; + wl1271_debug(DEBUG_TX, "tx_fill_hdr: padding: %d", pad); + } desc->tx_attr = cpu_to_le16(tx_attr); - wl1271_debug(DEBUG_TX, "tx_fill_hdr: pad: %d hlid: %d " - "tx_attr: 0x%x len: %d life: %d mem: %d", pad, desc->hlid, - le16_to_cpu(desc->tx_attr), le16_to_cpu(desc->length), - le16_to_cpu(desc->life_time), desc->total_mem_blocks); + wl1271_debug(DEBUG_TX, "tx_fill_hdr: hlid: %d tx_attr: 0x%x " + "len: %d life: %d mem: %d", + desc->hlid, le16_to_cpu(desc->tx_attr), + le16_to_cpu(desc->length), le16_to_cpu(desc->life_time), + desc->wl127x_mem.total_mem_blocks); } /* caller must hold wl->mutex */ @@ -305,11 +324,18 @@ static int wl1271_prepare_tx_frame(struct wl1271 *wl, struct sk_buff *skb, wl1271_tx_fill_hdr(wl, skb, extra, info, hlid); /* - * The length of each packet is stored in terms of words. Thus, we must - * pad the skb data to make sure its length is aligned. - * The number of padding bytes is computed and set in wl1271_tx_fill_hdr + * The length of each packet is stored in terms of + * words. Thus, we must pad the skb data to make sure its + * length is aligned. The number of padding bytes is computed + * and set in wl1271_tx_fill_hdr. + * In special cases, we want to align to a specific block size + * (eg. for wl128x with SDIO we align to 256). */ - total_len = ALIGN(skb->len, WL1271_TX_ALIGN_TO); + if (wl->block_size) + total_len = ALIGN(skb->len, wl->block_size); + else + total_len = ALIGN(skb->len, WL1271_TX_ALIGN_TO); + memcpy(wl->aggr_buf + buf_offset, skb->data, skb->len); memset(wl->aggr_buf + buf_offset + skb->len, 0, total_len - skb->len); diff --git a/drivers/net/wireless/wl12xx/tx.h b/drivers/net/wireless/wl12xx/tx.h index 02f07fa..e313177 100644 --- a/drivers/net/wireless/wl12xx/tx.h +++ b/drivers/net/wireless/wl12xx/tx.h @@ -55,20 +55,48 @@ #define WL1271_TX_ALIGN_TO 4 #define WL1271_TKIP_IV_SPACE 4 +struct wl127x_tx_mem { + /* + * Number of extra memory blocks to allocate for this packet + * in addition to the number of blocks derived from the packet + * length. + */ + u8 extra_blocks; + /* + * Total number of memory blocks allocated by the host for + * this packet. Must be equal or greater than the actual + * blocks number allocated by HW. + */ + u8 total_mem_blocks; +} __packed; + +struct wl128x_tx_mem { + /* + * Total number of memory blocks allocated by the host for + * this packet. + */ + u8 total_mem_blocks; + /* + * Number of extra bytes, at the end of the frame. the host + * uses this padding to complete each frame to integer number + * of SDIO blocks. + */ + u8 extra_bytes; +} __packed; + struct wl1271_tx_hw_descr { /* Length of packet in words, including descriptor+header+data */ __le16 length; - /* Number of extra memory blocks to allocate for this packet in - addition to the number of blocks derived from the packet length */ - u8 extra_mem_blocks; - /* Total number of memory blocks allocated by the host for this packet. - Must be equal or greater than the actual blocks number allocated by - HW!! */ - u8 total_mem_blocks; + union { + struct wl127x_tx_mem wl127x_mem; + struct wl128x_tx_mem wl128x_mem; + } __packed; /* Device time (in us) when the packet arrived to the driver */ __le32 start_time; - /* Max delay in TUs until transmission. The last device time the - packet can be transmitted is: startTime+(1024*LifeTime) */ + /* + * Max delay in TUs until transmission. The last device time the + * packet can be transmitted is: start_time + (1024 * life_time) + */ __le16 life_time; /* Bitwise fields - see TX_ATTR... definitions above. */ __le16 tx_attr; diff --git a/drivers/net/wireless/wl12xx/wl12xx.h b/drivers/net/wireless/wl12xx/wl12xx.h index a2e899d..959b338 100644 --- a/drivers/net/wireless/wl12xx/wl12xx.h +++ b/drivers/net/wireless/wl12xx/wl12xx.h @@ -303,6 +303,7 @@ struct wl1271_if_operations { struct device* (*dev)(struct wl1271 *wl); void (*enable_irq)(struct wl1271 *wl); void (*disable_irq)(struct wl1271 *wl); + void (*set_block_size) (struct wl1271 *wl); }; #define MAX_NUM_KEYS 14 @@ -533,6 +534,8 @@ struct wl1271 { bool ba_support; u8 ba_rx_bitmap; + u32 block_size; + /* * AP-mode - links indexed by HLID. The global and broadcast links * are always active. -- cgit v0.10.2 From a81159edf8d64011933df177ec42f82d7896a0c7 Mon Sep 17 00:00:00 2001 From: Luciano Coelho Date: Mon, 14 Mar 2011 14:05:13 +0200 Subject: wl12xx: 1281/1283 support - add block size handling for sdio and spi Add the the set_block_size op in the SDIO and in the SPI modules. Since it is only used with SDIO, just explicitly set the op to NULL in spi.c Signed-off-by: Luciano Coelho diff --git a/drivers/net/wireless/wl12xx/sdio.c b/drivers/net/wireless/wl12xx/sdio.c index 1b6a1ad..7491b3d 100644 --- a/drivers/net/wireless/wl12xx/sdio.c +++ b/drivers/net/wireless/wl12xx/sdio.c @@ -51,6 +51,18 @@ static const struct sdio_device_id wl1271_devices[] = { }; MODULE_DEVICE_TABLE(sdio, wl1271_devices); +/* The max SDIO block size is 256 when working with tx padding to SDIO block */ +#define TX_PAD_SDIO_BLK_SIZE 256 + +static void wl1271_sdio_set_block_size(struct wl1271 *wl) +{ + wl->block_size = TX_PAD_SDIO_BLK_SIZE; + + sdio_claim_host(wl->if_priv); + sdio_set_block_size(wl->if_priv, TX_PAD_SDIO_BLK_SIZE); + sdio_release_host(wl->if_priv); +} + static inline struct sdio_func *wl_to_func(struct wl1271 *wl) { return wl->if_priv; @@ -166,6 +178,9 @@ static int wl1271_sdio_power_on(struct wl1271 *wl) sdio_claim_host(func); sdio_enable_func(func); + /* Set the default block size in case it was modified */ + sdio_set_block_size(func, 0); + out: return ret; } @@ -203,7 +218,8 @@ static struct wl1271_if_operations sdio_ops = { .power = wl1271_sdio_set_power, .dev = wl1271_sdio_wl_to_dev, .enable_irq = wl1271_sdio_enable_interrupts, - .disable_irq = wl1271_sdio_disable_interrupts + .disable_irq = wl1271_sdio_disable_interrupts, + .set_block_size = wl1271_sdio_set_block_size, }; static int __devinit wl1271_probe(struct sdio_func *func, diff --git a/drivers/net/wireless/wl12xx/spi.c b/drivers/net/wireless/wl12xx/spi.c index 80295f5..bfb1171 100644 --- a/drivers/net/wireless/wl12xx/spi.c +++ b/drivers/net/wireless/wl12xx/spi.c @@ -355,7 +355,8 @@ static struct wl1271_if_operations spi_ops = { .power = wl1271_spi_set_power, .dev = wl1271_spi_wl_to_dev, .enable_irq = wl1271_spi_enable_interrupts, - .disable_irq = wl1271_spi_disable_interrupts + .disable_irq = wl1271_spi_disable_interrupts, + .set_block_size = NULL, }; static int __devinit wl1271_probe(struct spi_device *spi) -- cgit v0.10.2 From 49d750ca14cd49e76ab039b33b5a621e0a92b9fd Mon Sep 17 00:00:00 2001 From: Shahar Levi Date: Sun, 6 Mar 2011 16:32:09 +0200 Subject: wl12xx: 1281/1283 support - New radio structs and functions New general and radio parameters structures and functions. Implemented as separate functions due to auto-detection between wl127x and wl128x. Signed-off-by: Shahar Levi Reviewed-by: Luciano Coelho Signed-off-by: Luciano Coelho diff --git a/drivers/net/wireless/wl12xx/cmd.c b/drivers/net/wireless/wl12xx/cmd.c index f0aa7ab..37eb9f3 100644 --- a/drivers/net/wireless/wl12xx/cmd.c +++ b/drivers/net/wireless/wl12xx/cmd.c @@ -110,7 +110,47 @@ out: int wl1271_cmd_general_parms(struct wl1271 *wl) { struct wl1271_general_parms_cmd *gen_parms; - struct wl1271_ini_general_params *gp = &wl->nvs->general_params; + struct wl1271_ini_general_params *gp = + &((struct wl1271_nvs_file *)wl->nvs)->general_params; + bool answer = false; + int ret; + + if (!wl->nvs) + return -ENODEV; + + gen_parms = kzalloc(sizeof(*gen_parms), GFP_KERNEL); + if (!gen_parms) + return -ENOMEM; + + gen_parms->test.id = TEST_CMD_INI_FILE_GENERAL_PARAM; + + memcpy(&gen_parms->general_params, gp, sizeof(*gp)); + + if (gp->tx_bip_fem_auto_detect) + answer = true; + + ret = wl1271_cmd_test(wl, gen_parms, sizeof(*gen_parms), answer); + if (ret < 0) { + wl1271_warning("CMD_INI_FILE_GENERAL_PARAM failed"); + goto out; + } + + gp->tx_bip_fem_manufacturer = + gen_parms->general_params.tx_bip_fem_manufacturer; + + wl1271_debug(DEBUG_CMD, "FEM autodetect: %s, manufacturer: %d\n", + answer ? "auto" : "manual", gp->tx_bip_fem_manufacturer); + +out: + kfree(gen_parms); + return ret; +} + +int wl128x_cmd_general_parms(struct wl1271 *wl) +{ + struct wl128x_general_parms_cmd *gen_parms; + struct wl128x_ini_general_params *gp = + &((struct wl128x_nvs_file *)wl->nvs)->general_params; bool answer = false; int ret; @@ -186,6 +226,50 @@ int wl1271_cmd_radio_parms(struct wl1271 *wl) return ret; } +int wl128x_cmd_radio_parms(struct wl1271 *wl) +{ + struct wl128x_nvs_file *nvs = (struct wl128x_nvs_file *)wl->nvs; + struct wl128x_radio_parms_cmd *radio_parms; + struct wl128x_ini_general_params *gp = &nvs->general_params; + int ret; + + if (!wl->nvs) + return -ENODEV; + + radio_parms = kzalloc(sizeof(*radio_parms), GFP_KERNEL); + if (!radio_parms) + return -ENOMEM; + + radio_parms->test.id = TEST_CMD_INI_FILE_RADIO_PARAM; + + /* 2.4GHz parameters */ + memcpy(&radio_parms->static_params_2, &nvs->stat_radio_params_2, + sizeof(struct wl128x_ini_band_params_2)); + memcpy(&radio_parms->dyn_params_2, + &nvs->dyn_radio_params_2[gp->tx_bip_fem_manufacturer].params, + sizeof(struct wl128x_ini_fem_params_2)); + + /* 5GHz parameters */ + memcpy(&radio_parms->static_params_5, + &nvs->stat_radio_params_5, + sizeof(struct wl128x_ini_band_params_5)); + memcpy(&radio_parms->dyn_params_5, + &nvs->dyn_radio_params_5[gp->tx_bip_fem_manufacturer].params, + sizeof(struct wl128x_ini_fem_params_5)); + + radio_parms->fem_vendor_and_options = nvs->fem_vendor_and_options; + + wl1271_dump(DEBUG_CMD, "TEST_CMD_INI_FILE_RADIO_PARAM: ", + radio_parms, sizeof(*radio_parms)); + + ret = wl1271_cmd_test(wl, radio_parms, sizeof(*radio_parms), 0); + if (ret < 0) + wl1271_warning("CMD_INI_FILE_RADIO_PARAM failed"); + + kfree(radio_parms); + return ret; +} + int wl1271_cmd_ext_radio_parms(struct wl1271 *wl) { struct wl1271_ext_radio_parms_cmd *ext_radio_parms; diff --git a/drivers/net/wireless/wl12xx/cmd.h b/drivers/net/wireless/wl12xx/cmd.h index 54c12e7..5cac95d 100644 --- a/drivers/net/wireless/wl12xx/cmd.h +++ b/drivers/net/wireless/wl12xx/cmd.h @@ -32,7 +32,9 @@ struct acx_header; int wl1271_cmd_send(struct wl1271 *wl, u16 id, void *buf, size_t len, size_t res_len); int wl1271_cmd_general_parms(struct wl1271 *wl); +int wl128x_cmd_general_parms(struct wl1271 *wl); int wl1271_cmd_radio_parms(struct wl1271 *wl); +int wl128x_cmd_radio_parms(struct wl1271 *wl); int wl1271_cmd_ext_radio_parms(struct wl1271 *wl); int wl1271_cmd_join(struct wl1271 *wl, u8 bss_type); int wl1271_cmd_test(struct wl1271 *wl, void *buf, size_t buf_len, u8 answer); @@ -415,6 +417,21 @@ struct wl1271_general_parms_cmd { u8 padding[3]; } __packed; +struct wl128x_general_parms_cmd { + struct wl1271_cmd_header header; + + struct wl1271_cmd_test_header test; + + struct wl128x_ini_general_params general_params; + + u8 sr_debug_table[WL1271_INI_MAX_SMART_REFLEX_PARAM]; + u8 sr_sen_n_p; + u8 sr_sen_n_p_gain; + u8 sr_sen_nrn; + u8 sr_sen_prn; + u8 padding[3]; +} __packed; + struct wl1271_radio_parms_cmd { struct wl1271_cmd_header header; @@ -431,6 +448,23 @@ struct wl1271_radio_parms_cmd { u8 padding3[2]; } __packed; +struct wl128x_radio_parms_cmd { + struct wl1271_cmd_header header; + + struct wl1271_cmd_test_header test; + + /* Static radio parameters */ + struct wl128x_ini_band_params_2 static_params_2; + struct wl128x_ini_band_params_5 static_params_5; + + u8 fem_vendor_and_options; + + /* Dynamic radio parameters */ + struct wl128x_ini_fem_params_2 dyn_params_2; + u8 padding2; + struct wl128x_ini_fem_params_5 dyn_params_5; +} __packed; + struct wl1271_ext_radio_parms_cmd { struct wl1271_cmd_header header; diff --git a/drivers/net/wireless/wl12xx/ini.h b/drivers/net/wireless/wl12xx/ini.h index c330a25..30efcd6 100644 --- a/drivers/net/wireless/wl12xx/ini.h +++ b/drivers/net/wireless/wl12xx/ini.h @@ -41,6 +41,28 @@ struct wl1271_ini_general_params { u8 srf3[WL1271_INI_MAX_SMART_REFLEX_PARAM]; } __packed; +#define WL128X_INI_MAX_SETTINGS_PARAM 4 + +struct wl128x_ini_general_params { + u8 ref_clock; + u8 settling_time; + u8 clk_valid_on_wakeup; + u8 tcxo_ref_clock; + u8 tcxo_settling_time; + u8 tcxo_valid_on_wakeup; + u8 tcxo_ldo_voltage; + u8 xtal_itrim_val; + u8 platform_conf; + u8 dual_mode_select; + u8 tx_bip_fem_auto_detect; + u8 tx_bip_fem_manufacturer; + u8 general_settings[WL128X_INI_MAX_SETTINGS_PARAM]; + u8 sr_state; + u8 srf1[WL1271_INI_MAX_SMART_REFLEX_PARAM]; + u8 srf2[WL1271_INI_MAX_SMART_REFLEX_PARAM]; + u8 srf3[WL1271_INI_MAX_SMART_REFLEX_PARAM]; +} __packed; + #define WL1271_INI_RSSI_PROCESS_COMPENS_SIZE 15 struct wl1271_ini_band_params_2 { @@ -49,9 +71,16 @@ struct wl1271_ini_band_params_2 { u8 rx_rssi_process_compens[WL1271_INI_RSSI_PROCESS_COMPENS_SIZE]; } __packed; -#define WL1271_INI_RATE_GROUP_COUNT 6 #define WL1271_INI_CHANNEL_COUNT_2 14 +struct wl128x_ini_band_params_2 { + u8 rx_trace_insertion_loss; + u8 tx_trace_loss[WL1271_INI_CHANNEL_COUNT_2]; + u8 rx_rssi_process_compens[WL1271_INI_RSSI_PROCESS_COMPENS_SIZE]; +} __packed; + +#define WL1271_INI_RATE_GROUP_COUNT 6 + struct wl1271_ini_fem_params_2 { __le16 tx_bip_ref_pd_voltage; u8 tx_bip_ref_power; @@ -68,6 +97,28 @@ struct wl1271_ini_fem_params_2 { u8 normal_to_degraded_high_thr; } __packed; +#define WL128X_INI_RATE_GROUP_COUNT 7 +/* low and high temperatures */ +#define WL128X_INI_PD_VS_TEMPERATURE_RANGES 2 + +struct wl128x_ini_fem_params_2 { + __le16 tx_bip_ref_pd_voltage; + u8 tx_bip_ref_power; + u8 tx_bip_ref_offset; + u8 tx_per_rate_pwr_limits_normal[WL128X_INI_RATE_GROUP_COUNT]; + u8 tx_per_rate_pwr_limits_degraded[WL128X_INI_RATE_GROUP_COUNT]; + u8 tx_per_rate_pwr_limits_extreme[WL128X_INI_RATE_GROUP_COUNT]; + u8 tx_per_chan_pwr_limits_11b[WL1271_INI_CHANNEL_COUNT_2]; + u8 tx_per_chan_pwr_limits_ofdm[WL1271_INI_CHANNEL_COUNT_2]; + u8 tx_pd_vs_rate_offsets[WL128X_INI_RATE_GROUP_COUNT]; + u8 tx_ibias[WL128X_INI_RATE_GROUP_COUNT + 1]; + u8 tx_pd_vs_chan_offsets[WL1271_INI_CHANNEL_COUNT_2]; + u8 tx_pd_vs_temperature[WL128X_INI_PD_VS_TEMPERATURE_RANGES]; + u8 rx_fem_insertion_loss; + u8 degraded_low_to_normal_thr; + u8 normal_to_degraded_high_thr; +} __packed; + #define WL1271_INI_CHANNEL_COUNT_5 35 #define WL1271_INI_SUB_BAND_COUNT_5 7 @@ -77,6 +128,12 @@ struct wl1271_ini_band_params_5 { u8 rx_rssi_process_compens[WL1271_INI_RSSI_PROCESS_COMPENS_SIZE]; } __packed; +struct wl128x_ini_band_params_5 { + u8 rx_trace_insertion_loss[WL1271_INI_SUB_BAND_COUNT_5]; + u8 tx_trace_loss[WL1271_INI_CHANNEL_COUNT_5]; + u8 rx_rssi_process_compens[WL1271_INI_RSSI_PROCESS_COMPENS_SIZE]; +} __packed; + struct wl1271_ini_fem_params_5 { __le16 tx_bip_ref_pd_voltage[WL1271_INI_SUB_BAND_COUNT_5]; u8 tx_bip_ref_power[WL1271_INI_SUB_BAND_COUNT_5]; @@ -92,6 +149,23 @@ struct wl1271_ini_fem_params_5 { u8 normal_to_degraded_high_thr; } __packed; +struct wl128x_ini_fem_params_5 { + __le16 tx_bip_ref_pd_voltage[WL1271_INI_SUB_BAND_COUNT_5]; + u8 tx_bip_ref_power[WL1271_INI_SUB_BAND_COUNT_5]; + u8 tx_bip_ref_offset[WL1271_INI_SUB_BAND_COUNT_5]; + u8 tx_per_rate_pwr_limits_normal[WL128X_INI_RATE_GROUP_COUNT]; + u8 tx_per_rate_pwr_limits_degraded[WL128X_INI_RATE_GROUP_COUNT]; + u8 tx_per_rate_pwr_limits_extreme[WL128X_INI_RATE_GROUP_COUNT]; + u8 tx_per_chan_pwr_limits_ofdm[WL1271_INI_CHANNEL_COUNT_5]; + u8 tx_pd_vs_rate_offsets[WL128X_INI_RATE_GROUP_COUNT]; + u8 tx_ibias[WL128X_INI_RATE_GROUP_COUNT]; + u8 tx_pd_vs_chan_offsets[WL1271_INI_CHANNEL_COUNT_5]; + u8 tx_pd_vs_temperature[WL1271_INI_SUB_BAND_COUNT_5 * + WL128X_INI_PD_VS_TEMPERATURE_RANGES]; + u8 rx_fem_insertion_loss[WL1271_INI_SUB_BAND_COUNT_5]; + u8 degraded_low_to_normal_thr; + u8 normal_to_degraded_high_thr; +} __packed; /* NVS data structure */ #define WL1271_INI_NVS_SECTION_SIZE 468 @@ -120,4 +194,24 @@ struct wl1271_nvs_file { } dyn_radio_params_5[WL1271_INI_FEM_MODULE_COUNT]; } __packed; +struct wl128x_nvs_file { + /* NVS section */ + u8 nvs[WL1271_INI_NVS_SECTION_SIZE]; + + /* INI section */ + struct wl128x_ini_general_params general_params; + u8 fem_vendor_and_options; + struct wl128x_ini_band_params_2 stat_radio_params_2; + u8 padding2; + struct { + struct wl128x_ini_fem_params_2 params; + u8 padding; + } dyn_radio_params_2[WL1271_INI_FEM_MODULE_COUNT]; + struct wl128x_ini_band_params_5 stat_radio_params_5; + u8 padding3; + struct { + struct wl128x_ini_fem_params_5 params; + u8 padding; + } dyn_radio_params_5[WL1271_INI_FEM_MODULE_COUNT]; +} __packed; #endif diff --git a/drivers/net/wireless/wl12xx/init.c b/drivers/net/wireless/wl12xx/init.c index 34c4108..2dbc083 100644 --- a/drivers/net/wireless/wl12xx/init.c +++ b/drivers/net/wireless/wl12xx/init.c @@ -322,9 +322,11 @@ static int wl1271_sta_hw_init(struct wl1271 *wl) { int ret; - ret = wl1271_cmd_ext_radio_parms(wl); - if (ret < 0) - return ret; + if (wl->chip.id != CHIP_ID_1283_PG20) { + ret = wl1271_cmd_ext_radio_parms(wl); + if (ret < 0) + return ret; + } /* PS config */ ret = wl1271_acx_config_ps(wl); @@ -533,11 +535,17 @@ int wl1271_hw_init(struct wl1271 *wl) int ret, i; bool is_ap = (wl->bss_type == BSS_TYPE_AP_BSS); - ret = wl1271_cmd_general_parms(wl); + if (wl->chip.id == CHIP_ID_1283_PG20) + ret = wl128x_cmd_general_parms(wl); + else + ret = wl1271_cmd_general_parms(wl); if (ret < 0) return ret; - ret = wl1271_cmd_radio_parms(wl); + if (wl->chip.id == CHIP_ID_1283_PG20) + ret = wl128x_cmd_radio_parms(wl); + else + ret = wl1271_cmd_radio_parms(wl); if (ret < 0) return ret; diff --git a/drivers/net/wireless/wl12xx/main.c b/drivers/net/wireless/wl12xx/main.c index f24906f..e1fd005 100644 --- a/drivers/net/wireless/wl12xx/main.c +++ b/drivers/net/wireless/wl12xx/main.c @@ -438,15 +438,25 @@ static int wl1271_plt_init(struct wl1271 *wl) struct conf_tx_tid *conf_tid; int ret, i; - ret = wl1271_cmd_general_parms(wl); + if (wl->chip.id == CHIP_ID_1283_PG20) + ret = wl128x_cmd_general_parms(wl); + else + ret = wl1271_cmd_general_parms(wl); if (ret < 0) return ret; - ret = wl1271_cmd_radio_parms(wl); + if (wl->chip.id == CHIP_ID_1283_PG20) + ret = wl128x_cmd_radio_parms(wl); + else + ret = wl1271_cmd_radio_parms(wl); if (ret < 0) return ret; - ret = wl1271_cmd_ext_radio_parms(wl); + if (wl->chip.id != CHIP_ID_1283_PG20) { + ret = wl1271_cmd_ext_radio_parms(wl); + if (ret < 0) + return ret; + } if (ret < 0) return ret; -- cgit v0.10.2 From bc765bf3b9a095b3e41c8cda80643901884c3dd4 Mon Sep 17 00:00:00 2001 From: Shahar Levi Date: Sun, 6 Mar 2011 16:32:10 +0200 Subject: wl12xx: 1281/1283 support - Loading FW & NVS Take care of FW & NVS with the auto-detection between wl127x and wl128x. [Moved some common code outside if statements and added notes about NVS structure assumptions; Fixed a bug when checking the nvs size: if the size was incorrect, the local nvs variable was set to NULL, it should be wl->nvs instead. -- Luca] [Merged with potential buffer overflow fix -- Luca] Signed-off-by: Shahar Levi Reviewed-by: Luciano Coelho Signed-off-by: Luciano Coelho diff --git a/drivers/net/wireless/wl12xx/boot.c b/drivers/net/wireless/wl12xx/boot.c index 69fe870..38f3e8b 100644 --- a/drivers/net/wireless/wl12xx/boot.c +++ b/drivers/net/wireless/wl12xx/boot.c @@ -243,33 +243,57 @@ static int wl1271_boot_upload_nvs(struct wl1271 *wl) if (wl->nvs == NULL) return -ENODEV; - /* - * FIXME: the LEGACY NVS image support (NVS's missing the 5GHz band - * configurations) can be removed when those NVS files stop floating - * around. - */ - if (wl->nvs_len == sizeof(struct wl1271_nvs_file) || - wl->nvs_len == WL1271_INI_LEGACY_NVS_FILE_SIZE) { - /* for now 11a is unsupported in AP mode */ - if (wl->bss_type != BSS_TYPE_AP_BSS && - wl->nvs->general_params.dual_mode_select) - wl->enable_11a = true; - } + if (wl->chip.id == CHIP_ID_1283_PG20) { + struct wl128x_nvs_file *nvs = (struct wl128x_nvs_file *)wl->nvs; + + if (wl->nvs_len == sizeof(struct wl128x_nvs_file)) { + if (nvs->general_params.dual_mode_select) + wl->enable_11a = true; + } else { + wl1271_error("nvs size is not as expected: %zu != %zu", + wl->nvs_len, + sizeof(struct wl128x_nvs_file)); + kfree(wl->nvs); + wl->nvs = NULL; + wl->nvs_len = 0; + return -EILSEQ; + } - if (wl->nvs_len != sizeof(struct wl1271_nvs_file) && - (wl->nvs_len != WL1271_INI_LEGACY_NVS_FILE_SIZE || - wl->enable_11a)) { - wl1271_error("nvs size is not as expected: %zu != %zu", - wl->nvs_len, sizeof(struct wl1271_nvs_file)); - kfree(wl->nvs); - wl->nvs = NULL; - wl->nvs_len = 0; - return -EILSEQ; - } + /* only the first part of the NVS needs to be uploaded */ + nvs_len = sizeof(nvs->nvs); + nvs_ptr = (u8 *)nvs->nvs; - /* only the first part of the NVS needs to be uploaded */ - nvs_len = sizeof(wl->nvs->nvs); - nvs_ptr = (u8 *)wl->nvs->nvs; + } else { + struct wl1271_nvs_file *nvs = + (struct wl1271_nvs_file *)wl->nvs; + /* + * FIXME: the LEGACY NVS image support (NVS's missing the 5GHz + * band configurations) can be removed when those NVS files stop + * floating around. + */ + if (wl->nvs_len == sizeof(struct wl1271_nvs_file) || + wl->nvs_len == WL1271_INI_LEGACY_NVS_FILE_SIZE) { + /* for now 11a is unsupported in AP mode */ + if (wl->bss_type != BSS_TYPE_AP_BSS && + nvs->general_params.dual_mode_select) + wl->enable_11a = true; + } + + if (wl->nvs_len != sizeof(struct wl1271_nvs_file) && + (wl->nvs_len != WL1271_INI_LEGACY_NVS_FILE_SIZE || + wl->enable_11a)) { + wl1271_error("nvs size is not as expected: %zu != %zu", + wl->nvs_len, sizeof(struct wl1271_nvs_file)); + kfree(wl->nvs); + wl->nvs = NULL; + wl->nvs_len = 0; + return -EILSEQ; + } + + /* only the first part of the NVS needs to be uploaded */ + nvs_len = sizeof(nvs->nvs); + nvs_ptr = (u8 *) nvs->nvs; + } /* update current MAC address to NVS */ nvs_ptr[11] = wl->mac_addr[0]; @@ -319,10 +343,13 @@ static int wl1271_boot_upload_nvs(struct wl1271 *wl) /* * We've reached the first zero length, the first NVS table * is located at an aligned offset which is at least 7 bytes further. + * NOTE: The wl->nvs->nvs element must be first, in order to + * simplify the casting, we assume it is at the beginning of + * the wl->nvs structure. */ - nvs_ptr = (u8 *)wl->nvs->nvs + - ALIGN(nvs_ptr - (u8 *)wl->nvs->nvs + 7, 4); - nvs_len -= nvs_ptr - (u8 *)wl->nvs->nvs; + nvs_ptr = (u8 *)wl->nvs + + ALIGN(nvs_ptr - (u8 *)wl->nvs + 7, 4); + nvs_len -= nvs_ptr - (u8 *)wl->nvs; /* Now we must set the partition correctly */ wl1271_set_partition(wl, &part_table[PART_WORK]); diff --git a/drivers/net/wireless/wl12xx/cmd.c b/drivers/net/wireless/wl12xx/cmd.c index 37eb9f3..2468044 100644 --- a/drivers/net/wireless/wl12xx/cmd.c +++ b/drivers/net/wireless/wl12xx/cmd.c @@ -187,8 +187,9 @@ out: int wl1271_cmd_radio_parms(struct wl1271 *wl) { + struct wl1271_nvs_file *nvs = (struct wl1271_nvs_file *)wl->nvs; struct wl1271_radio_parms_cmd *radio_parms; - struct wl1271_ini_general_params *gp = &wl->nvs->general_params; + struct wl1271_ini_general_params *gp = &nvs->general_params; int ret; if (!wl->nvs) @@ -201,18 +202,18 @@ int wl1271_cmd_radio_parms(struct wl1271 *wl) radio_parms->test.id = TEST_CMD_INI_FILE_RADIO_PARAM; /* 2.4GHz parameters */ - memcpy(&radio_parms->static_params_2, &wl->nvs->stat_radio_params_2, + memcpy(&radio_parms->static_params_2, &nvs->stat_radio_params_2, sizeof(struct wl1271_ini_band_params_2)); memcpy(&radio_parms->dyn_params_2, - &wl->nvs->dyn_radio_params_2[gp->tx_bip_fem_manufacturer].params, + &nvs->dyn_radio_params_2[gp->tx_bip_fem_manufacturer].params, sizeof(struct wl1271_ini_fem_params_2)); /* 5GHz parameters */ memcpy(&radio_parms->static_params_5, - &wl->nvs->stat_radio_params_5, + &nvs->stat_radio_params_5, sizeof(struct wl1271_ini_band_params_5)); memcpy(&radio_parms->dyn_params_5, - &wl->nvs->dyn_radio_params_5[gp->tx_bip_fem_manufacturer].params, + &nvs->dyn_radio_params_5[gp->tx_bip_fem_manufacturer].params, sizeof(struct wl1271_ini_fem_params_5)); wl1271_dump(DEBUG_CMD, "TEST_CMD_INI_FILE_RADIO_PARAM: ", diff --git a/drivers/net/wireless/wl12xx/ini.h b/drivers/net/wireless/wl12xx/ini.h index 30efcd6..1420c84 100644 --- a/drivers/net/wireless/wl12xx/ini.h +++ b/drivers/net/wireless/wl12xx/ini.h @@ -174,7 +174,7 @@ struct wl128x_ini_fem_params_5 { #define WL1271_INI_LEGACY_NVS_FILE_SIZE 800 struct wl1271_nvs_file { - /* NVS section */ + /* NVS section - must be first! */ u8 nvs[WL1271_INI_NVS_SECTION_SIZE]; /* INI section */ @@ -195,7 +195,7 @@ struct wl1271_nvs_file { } __packed; struct wl128x_nvs_file { - /* NVS section */ + /* NVS section - must be first! */ u8 nvs[WL1271_INI_NVS_SECTION_SIZE]; /* INI section */ diff --git a/drivers/net/wireless/wl12xx/main.c b/drivers/net/wireless/wl12xx/main.c index e1fd005..fe0cf47 100644 --- a/drivers/net/wireless/wl12xx/main.c +++ b/drivers/net/wireless/wl12xx/main.c @@ -804,7 +804,10 @@ static int wl1271_fetch_firmware(struct wl1271 *wl) break; case BSS_TYPE_IBSS: case BSS_TYPE_STA_BSS: - fw_name = WL1271_FW_NAME; + if (wl->chip.id == CHIP_ID_1283_PG20) + fw_name = WL128X_FW_NAME; + else + fw_name = WL1271_FW_NAME; break; default: wl1271_error("no compatible firmware for bss_type %d", @@ -860,7 +863,7 @@ static int wl1271_fetch_nvs(struct wl1271 *wl) return ret; } - wl->nvs = kmemdup(fw->data, sizeof(struct wl1271_nvs_file), GFP_KERNEL); + wl->nvs = kmemdup(fw->data, fw->size, GFP_KERNEL); if (!wl->nvs) { wl1271_error("could not allocate memory for the nvs file"); @@ -3289,7 +3292,11 @@ int wl1271_register_hw(struct wl1271 *wl) ret = wl1271_fetch_nvs(wl); if (ret == 0) { - u8 *nvs_ptr = (u8 *)wl->nvs->nvs; + /* NOTE: The wl->nvs->nvs element must be first, in + * order to simplify the casting, we assume it is at + * the beginning of the wl->nvs structure. + */ + u8 *nvs_ptr = (u8 *)wl->nvs; wl->mac_addr[0] = nvs_ptr[11]; wl->mac_addr[1] = nvs_ptr[10]; diff --git a/drivers/net/wireless/wl12xx/sdio_test.c b/drivers/net/wireless/wl12xx/sdio_test.c index 01adf1b..e6e2ad6 100644 --- a/drivers/net/wireless/wl12xx/sdio_test.c +++ b/drivers/net/wireless/wl12xx/sdio_test.c @@ -189,7 +189,12 @@ static int wl1271_fetch_firmware(struct wl1271 *wl) const struct firmware *fw; int ret; - ret = request_firmware(&fw, WL1271_FW_NAME, wl1271_wl_to_dev(wl)); + if (wl->chip.id == CHIP_ID_1283_PG20) + ret = request_firmware(&fw, WL128X_FW_NAME, + wl1271_wl_to_dev(wl)); + else + ret = request_firmware(&fw, WL1271_FW_NAME, + wl1271_wl_to_dev(wl)); if (ret < 0) { wl1271_error("could not get firmware: %d", ret); @@ -234,7 +239,7 @@ static int wl1271_fetch_nvs(struct wl1271 *wl) return ret; } - wl->nvs = kmemdup(fw->data, sizeof(struct wl1271_nvs_file), GFP_KERNEL); + wl->nvs = kmemdup(fw->data, fw->size, GFP_KERNEL); if (!wl->nvs) { wl1271_error("could not allocate memory for the nvs file"); diff --git a/drivers/net/wireless/wl12xx/testmode.c b/drivers/net/wireless/wl12xx/testmode.c index 6ec06a4..da351d7 100644 --- a/drivers/net/wireless/wl12xx/testmode.c +++ b/drivers/net/wireless/wl12xx/testmode.c @@ -27,6 +27,7 @@ #include "wl12xx.h" #include "acx.h" +#include "reg.h" #define WL1271_TM_MAX_DATA_LENGTH 1024 @@ -204,7 +205,10 @@ static int wl1271_tm_cmd_nvs_push(struct wl1271 *wl, struct nlattr *tb[]) kfree(wl->nvs); - if (len != sizeof(struct wl1271_nvs_file)) + if ((wl->chip.id == CHIP_ID_1283_PG20) && + (len != sizeof(struct wl128x_nvs_file))) + return -EINVAL; + else if (len != sizeof(struct wl1271_nvs_file)) return -EINVAL; wl->nvs = kzalloc(len, GFP_KERNEL); diff --git a/drivers/net/wireless/wl12xx/wl12xx.h b/drivers/net/wireless/wl12xx/wl12xx.h index 959b338..e59f539 100644 --- a/drivers/net/wireless/wl12xx/wl12xx.h +++ b/drivers/net/wireless/wl12xx/wl12xx.h @@ -378,7 +378,7 @@ struct wl1271 { u8 *fw; size_t fw_len; u8 fw_bss_type; - struct wl1271_nvs_file *nvs; + void *nvs; size_t nvs_len; s8 hw_pg_ver; -- cgit v0.10.2 From 5ea417ae7749076ddaacb5b36487cae6ac920413 Mon Sep 17 00:00:00 2001 From: Shahar Levi Date: Sun, 6 Mar 2011 16:32:11 +0200 Subject: wl12xx: 1281/1283 support - New boot sequence Boot sequence support FREF clock and TCXO clock. WL128x has two clocks input - TCXO and FREF. TCXO is the main clock of the device, while FREF is used to sync between the GPS and the cellular modem. Auto-detection checks where TCXO is 32.736MHz or 16.368MHz, in that case the FREF will be used as the WLAN/BT main clock. [Use clock enumeration as defined in linux/wl12xx.h; remove unnecessary else block in wl128x_switch_fref; remove unnecessary change in main.c; remove some unnecessary debug prints and comments; fix potential use of uninitialized value (pll_config) -- Luca] Signed-off-by: Shahar Levi Reviewed-by: Luciano Coelho Signed-off-by: Luciano Coelho diff --git a/drivers/net/wireless/wl12xx/boot.c b/drivers/net/wireless/wl12xx/boot.c index 38f3e8b..9d742c1 100644 --- a/drivers/net/wireless/wl12xx/boot.c +++ b/drivers/net/wireless/wl12xx/boot.c @@ -22,6 +22,7 @@ */ #include +#include #include "acx.h" #include "reg.h" @@ -520,24 +521,159 @@ static void wl1271_boot_hw_version(struct wl1271 *wl) wl->quirks |= WL12XX_QUIRK_END_OF_TRANSACTION; } -/* uploads NVS and firmware */ -int wl1271_load_firmware(struct wl1271 *wl) +/* + * WL128x has two clocks input - TCXO and FREF. + * TCXO is the main clock of the device, while FREF is used to sync + * between the GPS and the cellular modem. + * In cases where TCXO is 32.736MHz or 16.368MHz, the FREF will be used + * as the WLAN/BT main clock. + */ +static int wl128x_switch_fref(struct wl1271 *wl, bool *is_ref_clk) { - int ret = 0; - u32 tmp, clk, pause; + u16 sys_clk_cfg_val; + + /* if working on XTAL-only mode go directly to TCXO TO FREF SWITCH */ + if ((wl->ref_clock == CONF_REF_CLK_38_4_M_XTAL) || + (wl->ref_clock == CONF_REF_CLK_26_M_XTAL)) + return true; + + /* Read clock source FREF or TCXO */ + sys_clk_cfg_val = wl1271_top_reg_read(wl, SYS_CLK_CFG_REG); + + if (sys_clk_cfg_val & PRCM_CM_EN_MUX_WLAN_FREF) { + /* if bit 3 is set - working with FREF clock */ + wl1271_debug(DEBUG_BOOT, "working with FREF clock, skip" + " to FREF"); + + *is_ref_clk = true; + } else { + /* if bit 3 is clear - working with TCXO clock */ + wl1271_debug(DEBUG_BOOT, "working with TCXO clock"); + + /* TCXO to FREF switch, check TXCO clock config */ + if ((wl->tcxo_clock != WL12XX_TCXOCLOCK_16_368) && + (wl->tcxo_clock != WL12XX_TCXOCLOCK_32_736)) { + /* + * not 16.368Mhz and not 32.736Mhz - skip to + * configure ELP stage + */ + wl1271_debug(DEBUG_BOOT, "NEW PLL ALGO:" + " TcxoRefClk=%d - not 16.368Mhz and not" + " 32.736Mhz - skip to configure ELP" + " stage", wl->tcxo_clock); + + *is_ref_clk = false; + } else { + wl1271_debug(DEBUG_BOOT, "NEW PLL ALGO:" + "TcxoRefClk=%d - 16.368Mhz or 32.736Mhz" + " - TCXO to FREF switch", + wl->tcxo_clock); + + return true; + } + } + + return false; +} + +static int wl128x_boot_clk(struct wl1271 *wl, bool *is_ref_clk) +{ + if (wl128x_switch_fref(wl, is_ref_clk)) { + wl1271_debug(DEBUG_BOOT, "XTAL-only mode go directly to" + " TCXO TO FREF SWITCH"); + /* TCXO to FREF switch - for PG2.0 */ + wl1271_top_reg_write(wl, WL_SPARE_REG, + WL_SPARE_MASK_8526); + + wl1271_top_reg_write(wl, SYS_CLK_CFG_REG, + WL_CLK_REQ_TYPE_PG2 | MCS_PLL_CLK_SEL_FREF); + + *is_ref_clk = true; + mdelay(15); + } + + /* Set bit 2 in spare register to avoid illegal access */ + wl1271_top_reg_write(wl, WL_SPARE_REG, WL_SPARE_VAL); + + /* working with TCXO clock */ + if ((*is_ref_clk == false) && + ((wl->tcxo_clock == WL12XX_TCXOCLOCK_16_8) || + (wl->tcxo_clock == WL12XX_TCXOCLOCK_33_6))) { + wl1271_debug(DEBUG_BOOT, "16_8_M or 33_6_M TCXO detected"); + + /* Manually Configure MCS PLL settings PG2.0 Only */ + wl1271_top_reg_write(wl, MCS_PLL_M_REG, MCS_PLL_M_REG_VAL); + wl1271_top_reg_write(wl, MCS_PLL_N_REG, MCS_PLL_N_REG_VAL); + wl1271_top_reg_write(wl, MCS_PLL_CONFIG_REG, + MCS_PLL_CONFIG_REG_VAL); + } else { + int pll_config; + u16 mcs_pll_config_val; + + /* + * Configure MCS PLL settings to FREF Freq + * Set the values that determine the time elapse since the PLL's + * get their enable signal until the lock indication is set + */ + wl1271_top_reg_write(wl, PLL_LOCK_COUNTERS_REG, + PLL_LOCK_COUNTERS_COEX | PLL_LOCK_COUNTERS_MCS); + + mcs_pll_config_val = wl1271_top_reg_read(wl, + MCS_PLL_CONFIG_REG); + /* + * Set the MCS PLL input frequency value according to the + * reference clock value detected/read + */ + if (*is_ref_clk == false) { + if ((wl->tcxo_clock == WL12XX_TCXOCLOCK_19_2) || + (wl->tcxo_clock == WL12XX_TCXOCLOCK_38_4)) + pll_config = 1; + else if ((wl->tcxo_clock == WL12XX_TCXOCLOCK_26) + || + (wl->tcxo_clock == WL12XX_TCXOCLOCK_52)) + pll_config = 2; + else + return -EINVAL; + } else { + if ((wl->ref_clock == CONF_REF_CLK_19_2_E) || + (wl->ref_clock == CONF_REF_CLK_38_4_E)) + pll_config = 1; + else if ((wl->ref_clock == CONF_REF_CLK_26_E) || + (wl->ref_clock == CONF_REF_CLK_52_E)) + pll_config = 2; + else + return -EINVAL; + } + + mcs_pll_config_val |= (pll_config << (MCS_SEL_IN_FREQ_SHIFT)) & + (MCS_SEL_IN_FREQ_MASK); + wl1271_top_reg_write(wl, MCS_PLL_CONFIG_REG, + mcs_pll_config_val); + } + + return 0; +} + +static int wl127x_boot_clk(struct wl1271 *wl) +{ + u32 pause; + u32 clk; wl1271_boot_hw_version(wl); - if (wl->ref_clock == 0 || wl->ref_clock == 2 || wl->ref_clock == 4) + if (wl->ref_clock == CONF_REF_CLK_19_2_E || + wl->ref_clock == CONF_REF_CLK_38_4_E || + wl->ref_clock == CONF_REF_CLK_38_4_M_XTAL) /* ref clk: 19.2/38.4/38.4-XTAL */ clk = 0x3; - else if (wl->ref_clock == 1 || wl->ref_clock == 3) + else if (wl->ref_clock == CONF_REF_CLK_26_E || + wl->ref_clock == CONF_REF_CLK_52_E) /* ref clk: 26/52 */ clk = 0x5; else return -EINVAL; - if (wl->ref_clock != 0) { + if (wl->ref_clock != CONF_REF_CLK_19_2_E) { u16 val; /* Set clock type (open drain) */ val = wl1271_top_reg_read(wl, OCP_REG_CLK_TYPE); @@ -567,6 +703,26 @@ int wl1271_load_firmware(struct wl1271 *wl) pause |= WU_COUNTER_PAUSE_VAL; wl1271_write32(wl, WU_COUNTER_PAUSE, pause); + return 0; +} + +/* uploads NVS and firmware */ +int wl1271_load_firmware(struct wl1271 *wl) +{ + int ret = 0; + u32 tmp, clk; + bool is_ref_clk = false; + + if (wl->chip.id == CHIP_ID_1283_PG20) { + ret = wl128x_boot_clk(wl, &is_ref_clk); + if (ret < 0) + goto out; + } else { + ret = wl127x_boot_clk(wl); + if (ret < 0) + goto out; + } + /* Continue the ELP wake up sequence */ wl1271_write32(wl, WELP_ARM_COMMAND, WELP_ARM_COMMAND_VAL); udelay(500); @@ -582,7 +738,15 @@ int wl1271_load_firmware(struct wl1271 *wl) wl1271_debug(DEBUG_BOOT, "clk2 0x%x", clk); - clk |= (wl->ref_clock << 1) << 4; + if (wl->chip.id == CHIP_ID_1283_PG20) { + if (is_ref_clk == false) + clk |= ((wl->tcxo_clock & 0x3) << 1) << 4; + else + clk |= ((wl->ref_clock & 0x3) << 1) << 4; + } else { + clk |= (wl->ref_clock << 1) << 4; + } + wl1271_write32(wl, DRPW_SCRATCH_START, clk); wl1271_set_partition(wl, &part_table[PART_WORK]); @@ -615,6 +779,9 @@ int wl1271_load_firmware(struct wl1271 *wl) /* WL1271: The reference driver skips steps 7 to 10 (jumps directly * to upload_fw) */ + if (wl->chip.id == CHIP_ID_1283_PG20) + wl1271_top_reg_write(wl, SDIO_IO_DS, HCI_IO_DS_6MA); + ret = wl1271_boot_upload_firmware(wl); if (ret < 0) goto out; diff --git a/drivers/net/wireless/wl12xx/sdio.c b/drivers/net/wireless/wl12xx/sdio.c index 7491b3d..f6dd3de 100644 --- a/drivers/net/wireless/wl12xx/sdio.c +++ b/drivers/net/wireless/wl12xx/sdio.c @@ -255,6 +255,7 @@ static int __devinit wl1271_probe(struct sdio_func *func, wl->irq = wlan_data->irq; wl->ref_clock = wlan_data->board_ref_clock; + wl->tcxo_clock = wlan_data->board_tcxo_clock; ret = request_threaded_irq(wl->irq, wl1271_hardirq, wl1271_irq, IRQF_TRIGGER_HIGH | IRQF_ONESHOT, diff --git a/drivers/net/wireless/wl12xx/sdio_test.c b/drivers/net/wireless/wl12xx/sdio_test.c index e6e2ad6..c02c870 100644 --- a/drivers/net/wireless/wl12xx/sdio_test.c +++ b/drivers/net/wireless/wl12xx/sdio_test.c @@ -421,6 +421,7 @@ static int __devinit wl1271_probe(struct sdio_func *func, wl->irq = wlan_data->irq; wl->ref_clock = wlan_data->board_ref_clock; + wl->tcxo_clock = wlan_data->board_tcxo_clock; sdio_set_drvdata(func, wl_test); diff --git a/drivers/net/wireless/wl12xx/spi.c b/drivers/net/wireless/wl12xx/spi.c index bfb1171..f552536 100644 --- a/drivers/net/wireless/wl12xx/spi.c +++ b/drivers/net/wireless/wl12xx/spi.c @@ -401,6 +401,7 @@ static int __devinit wl1271_probe(struct spi_device *spi) } wl->ref_clock = pdata->board_ref_clock; + wl->tcxo_clock = pdata->board_tcxo_clock; wl->irq = spi->irq; if (wl->irq < 0) { diff --git a/drivers/net/wireless/wl12xx/wl12xx.h b/drivers/net/wireless/wl12xx/wl12xx.h index e59f539..4b55677 100644 --- a/drivers/net/wireless/wl12xx/wl12xx.h +++ b/drivers/net/wireless/wl12xx/wl12xx.h @@ -535,6 +535,7 @@ struct wl1271 { u8 ba_rx_bitmap; u32 block_size; + int tcxo_clock; /* * AP-mode - links indexed by HLID. The global and broadcast links -- cgit v0.10.2 From 13b107dd9808343d05627f0fba7fbc764c86738e Mon Sep 17 00:00:00 2001 From: Shahar Levi Date: Sun, 6 Mar 2011 16:32:12 +0200 Subject: wl12xx: 1281/1283 support - use dynamic memory for the RX/TX pools Separate the memory configuration to chip-specific structures and implement dynamic memory for wl128x. This feature allows us to move TX memory blocks to the RX pool when the RX path is overloaded. Thanks for Arik Nemtsov for helping simplify the wl1271_fw_status() code. [Rewrote the commit subject and message for clarity; improved some comments and changed "spare" to "padding" for consistency; added a FIXME for the AP memory configuration -- Luca] Signed-off-by: Shahar Levi Reviewed-by: Luciano Coelho Signed-off-by: Luciano Coelho diff --git a/drivers/net/wireless/wl12xx/acx.c b/drivers/net/wireless/wl12xx/acx.c index 50676b3..e005aa4 100644 --- a/drivers/net/wireless/wl12xx/acx.c +++ b/drivers/net/wireless/wl12xx/acx.c @@ -965,10 +965,13 @@ int wl1271_acx_ap_mem_cfg(struct wl1271 *wl) } /* memory config */ - mem_conf->num_stations = wl->conf.mem.num_stations; - mem_conf->rx_mem_block_num = wl->conf.mem.rx_block_num; - mem_conf->tx_min_mem_block_num = wl->conf.mem.tx_min_block_num; - mem_conf->num_ssid_profiles = wl->conf.mem.ssid_profiles; + /* FIXME: for now we always use mem_wl127x for AP, because it + * doesn't support dynamic memory and we don't have the + * optimal values for wl128x without dynamic memory yet */ + mem_conf->num_stations = wl->conf.mem_wl127x.num_stations; + mem_conf->rx_mem_block_num = wl->conf.mem_wl127x.rx_block_num; + mem_conf->tx_min_mem_block_num = wl->conf.mem_wl127x.tx_min_block_num; + mem_conf->num_ssid_profiles = wl->conf.mem_wl127x.ssid_profiles; mem_conf->total_tx_descriptors = cpu_to_le32(ACX_TX_DESCRIPTORS); ret = wl1271_cmd_configure(wl, ACX_MEM_CFG, mem_conf, @@ -986,6 +989,7 @@ out: int wl1271_acx_sta_mem_cfg(struct wl1271 *wl) { struct wl1271_acx_sta_config_memory *mem_conf; + struct conf_memory_settings *mem; int ret; wl1271_debug(DEBUG_ACX, "wl1271 mem cfg"); @@ -996,16 +1000,21 @@ int wl1271_acx_sta_mem_cfg(struct wl1271 *wl) goto out; } + if (wl->chip.id == CHIP_ID_1283_PG20) + mem = &wl->conf.mem_wl128x; + else + mem = &wl->conf.mem_wl127x; + /* memory config */ - mem_conf->num_stations = wl->conf.mem.num_stations; - mem_conf->rx_mem_block_num = wl->conf.mem.rx_block_num; - mem_conf->tx_min_mem_block_num = wl->conf.mem.tx_min_block_num; - mem_conf->num_ssid_profiles = wl->conf.mem.ssid_profiles; + mem_conf->num_stations = mem->num_stations; + mem_conf->rx_mem_block_num = mem->rx_block_num; + mem_conf->tx_min_mem_block_num = mem->tx_min_block_num; + mem_conf->num_ssid_profiles = mem->ssid_profiles; mem_conf->total_tx_descriptors = cpu_to_le32(ACX_TX_DESCRIPTORS); - mem_conf->dyn_mem_enable = wl->conf.mem.dynamic_memory; - mem_conf->tx_free_req = wl->conf.mem.min_req_tx_blocks; - mem_conf->rx_free_req = wl->conf.mem.min_req_rx_blocks; - mem_conf->tx_min = wl->conf.mem.tx_min; + mem_conf->dyn_mem_enable = mem->dynamic_memory; + mem_conf->tx_free_req = mem->min_req_tx_blocks; + mem_conf->rx_free_req = mem->min_req_rx_blocks; + mem_conf->tx_min = mem->tx_min; ret = wl1271_cmd_configure(wl, ACX_MEM_CFG, mem_conf, sizeof(*mem_conf)); @@ -1072,6 +1081,8 @@ int wl1271_acx_init_mem_config(struct wl1271 *wl) wl1271_debug(DEBUG_TX, "available tx blocks: %d", wl->tx_blocks_available); + wl->tx_new_total = wl->tx_blocks_available; + return 0; } diff --git a/drivers/net/wireless/wl12xx/conf.h b/drivers/net/wireless/wl12xx/conf.h index a00f22c..743bd0b 100644 --- a/drivers/net/wireless/wl12xx/conf.h +++ b/drivers/net/wireless/wl12xx/conf.h @@ -1204,7 +1204,8 @@ struct conf_drv_settings { struct conf_scan_settings scan; struct conf_rf_settings rf; struct conf_ht_setting ht; - struct conf_memory_settings mem; + struct conf_memory_settings mem_wl127x; + struct conf_memory_settings mem_wl128x; }; #endif diff --git a/drivers/net/wireless/wl12xx/main.c b/drivers/net/wireless/wl12xx/main.c index fe0cf47..3c381ce 100644 --- a/drivers/net/wireless/wl12xx/main.c +++ b/drivers/net/wireless/wl12xx/main.c @@ -298,7 +298,7 @@ static struct conf_drv_settings default_conf = { .tx_ba_win_size = 64, .inactivity_timeout = 10000, }, - .mem = { + .mem_wl127x = { .num_stations = 1, .ssid_profiles = 1, .rx_block_num = 70, @@ -307,7 +307,17 @@ static struct conf_drv_settings default_conf = { .min_req_tx_blocks = 100, .min_req_rx_blocks = 22, .tx_min = 27, - } + }, + .mem_wl128x = { + .num_stations = 1, + .ssid_profiles = 1, + .rx_block_num = 40, + .tx_min_block_num = 40, + .dynamic_memory = 1, + .min_req_tx_blocks = 45, + .min_req_rx_blocks = 22, + .tx_min = 27, + }, }; static void __wl1271_op_remove_interface(struct wl1271 *wl); @@ -608,16 +618,27 @@ static void wl1271_fw_status(struct wl1271 *wl, { struct wl1271_fw_common_status *status = &full_status->common; struct timespec ts; + u32 old_tx_blk_count = wl->tx_blocks_available; u32 total = 0; int i; - if (wl->bss_type == BSS_TYPE_AP_BSS) + if (wl->bss_type == BSS_TYPE_AP_BSS) { wl1271_raw_read(wl, FW_STATUS_ADDR, status, sizeof(struct wl1271_fw_ap_status), false); - else + } else { wl1271_raw_read(wl, FW_STATUS_ADDR, status, sizeof(struct wl1271_fw_sta_status), false); + /* Update tx total blocks change */ + wl->tx_total_diff += + ((struct wl1271_fw_sta_status *)status)->tx_total - + wl->tx_new_total; + + /* Update total tx blocks */ + wl->tx_new_total = + ((struct wl1271_fw_sta_status *)status)->tx_total; + } + wl1271_debug(DEBUG_IRQ, "intr: 0x%x (fw_rx_counter = %d, " "drv_rx_counter = %d, tx_results_counter = %d)", status->intr, @@ -627,17 +648,28 @@ static void wl1271_fw_status(struct wl1271 *wl, /* update number of available TX blocks */ for (i = 0; i < NUM_TX_QUEUES; i++) { - u32 cnt = le32_to_cpu(status->tx_released_blks[i]) - + total += le32_to_cpu(status->tx_released_blks[i]) - wl->tx_blocks_freed[i]; wl->tx_blocks_freed[i] = le32_to_cpu(status->tx_released_blks[i]); - wl->tx_blocks_available += cnt; - total += cnt; + + } + + /* + * By adding the freed blocks to tx_total_diff we are actually + * moving them to the RX pool. + */ + wl->tx_total_diff += total; + + /* if we have positive difference, add the blocks to the TX pool */ + if (wl->tx_total_diff >= 0) { + wl->tx_blocks_available += wl->tx_total_diff; + wl->tx_total_diff = 0; } /* if more blocks are available now, tx work can be scheduled */ - if (total) + if (wl->tx_blocks_available > old_tx_blk_count) clear_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags); /* for AP update num of allocated TX blocks per link and ps status */ diff --git a/drivers/net/wireless/wl12xx/wl12xx.h b/drivers/net/wireless/wl12xx/wl12xx.h index 4b55677..ad04b83 100644 --- a/drivers/net/wireless/wl12xx/wl12xx.h +++ b/drivers/net/wireless/wl12xx/wl12xx.h @@ -267,6 +267,8 @@ struct wl1271_fw_sta_status { u8 tx_total; u8 reserved1; __le16 reserved2; + /* Total structure size is 68 bytes */ + u32 padding; } __packed; struct wl1271_fw_full_status { @@ -397,6 +399,9 @@ struct wl1271 { u32 tx_blocks_freed[NUM_TX_QUEUES]; u32 tx_blocks_available; u32 tx_results_count; + /* Indicates how many memory blocks should be moved to the RX pool */ + int tx_total_diff; + u32 tx_new_total; /* Transmitted TX packets counter for chipset interface */ u32 tx_packets_count; -- cgit v0.10.2 From ae77eccf04f8c36769bdba334e1bbcc7bb9d3644 Mon Sep 17 00:00:00 2001 From: Shahar Levi Date: Sun, 6 Mar 2011 16:32:13 +0200 Subject: wl12xx: 1281/1283 support - Improve Tx & Rx path Reduced bus transactions in the Tx & Rx path. [Removed unnecessary check wl->chip.id != CHIP_ID_1283_PG20 when checking the quirk -- Luca] Signed-off-by: Shahar Levi Reviewed-by: Luciano Coelho Signed-off-by: Luciano Coelho diff --git a/drivers/net/wireless/wl12xx/rx.c b/drivers/net/wireless/wl12xx/rx.c index 919b59f..132b0ca 100644 --- a/drivers/net/wireless/wl12xx/rx.c +++ b/drivers/net/wireless/wl12xx/rx.c @@ -163,18 +163,25 @@ void wl1271_rx(struct wl1271 *wl, struct wl1271_fw_common_status *status) break; } - /* - * Choose the block we want to read - * For aggregated packets, only the first memory block should - * be retrieved. The FW takes care of the rest. - */ - mem_block = wl1271_rx_get_mem_block(status, drv_rx_counter); - wl->rx_mem_pool_addr.addr = (mem_block << 8) + - le32_to_cpu(wl_mem_map->packet_memory_pool_start); - wl->rx_mem_pool_addr.addr_extra = - wl->rx_mem_pool_addr.addr + 4; - wl1271_write(wl, WL1271_SLV_REG_DATA, &wl->rx_mem_pool_addr, - sizeof(wl->rx_mem_pool_addr), false); + if (wl->chip.id != CHIP_ID_1283_PG20) { + /* + * Choose the block we want to read + * For aggregated packets, only the first memory block + * should be retrieved. The FW takes care of the rest. + */ + mem_block = wl1271_rx_get_mem_block(status, + drv_rx_counter); + + wl->rx_mem_pool_addr.addr = (mem_block << 8) + + le32_to_cpu(wl_mem_map->packet_memory_pool_start); + + wl->rx_mem_pool_addr.addr_extra = + wl->rx_mem_pool_addr.addr + 4; + + wl1271_write(wl, WL1271_SLV_REG_DATA, + &wl->rx_mem_pool_addr, + sizeof(wl->rx_mem_pool_addr), false); + } /* Read all available packets at once */ wl1271_read(wl, WL1271_SLV_MEM_DATA, wl->aggr_buf, diff --git a/drivers/net/wireless/wl12xx/tx.c b/drivers/net/wireless/wl12xx/tx.c index e296f0a..afc8505 100644 --- a/drivers/net/wireless/wl12xx/tx.c +++ b/drivers/net/wireless/wl12xx/tx.c @@ -158,8 +158,14 @@ static int wl1271_tx_allocate(struct wl1271 *wl, struct sk_buff *skb, u32 extra, desc = (struct wl1271_tx_hw_descr *)skb_push( skb, total_len - skb->len); - desc->wl127x_mem.extra_blocks = TX_HW_BLOCK_SPARE; - desc->wl127x_mem.total_mem_blocks = total_blocks; + /* HW descriptor fields change between wl127x and wl128x */ + if (wl->chip.id == CHIP_ID_1283_PG20) { + desc->wl128x_mem.total_mem_blocks = total_blocks; + } else { + desc->wl127x_mem.extra_blocks = TX_HW_BLOCK_SPARE; + desc->wl127x_mem.total_mem_blocks = total_blocks; + } + desc->id = id; wl->tx_blocks_available -= total_blocks; @@ -249,6 +255,13 @@ static void wl1271_tx_fill_hdr(struct wl1271 *wl, struct sk_buff *skb, desc->wl128x_mem.extra_bytes = aligned_len - skb->len; desc->length = cpu_to_le16(aligned_len >> 2); + + wl1271_debug(DEBUG_TX, "tx_fill_hdr: hlid: %d " + "tx_attr: 0x%x len: %d life: %d mem: %d", + desc->hlid, tx_attr, + le16_to_cpu(desc->length), + le16_to_cpu(desc->life_time), + desc->wl128x_mem.total_mem_blocks); } else { int pad; @@ -260,16 +273,15 @@ static void wl1271_tx_fill_hdr(struct wl1271 *wl, struct sk_buff *skb, pad = aligned_len - skb->len; tx_attr |= pad << TX_HW_ATTR_OFST_LAST_WORD_PAD; - wl1271_debug(DEBUG_TX, "tx_fill_hdr: padding: %d", pad); + wl1271_debug(DEBUG_TX, "tx_fill_hdr: pad: %d hlid: %d " + "tx_attr: 0x%x len: %d life: %d mem: %d", pad, + desc->hlid, tx_attr, + le16_to_cpu(desc->length), + le16_to_cpu(desc->life_time), + desc->wl127x_mem.total_mem_blocks); } desc->tx_attr = cpu_to_le16(tx_attr); - - wl1271_debug(DEBUG_TX, "tx_fill_hdr: hlid: %d tx_attr: 0x%x " - "len: %d life: %d mem: %d", - desc->hlid, le16_to_cpu(desc->tx_attr), - le16_to_cpu(desc->length), le16_to_cpu(desc->life_time), - desc->wl127x_mem.total_mem_blocks); } /* caller must hold wl->mutex */ -- cgit v0.10.2 From ae47c45fd02fdf88d57adc370e78e7a01e2bfcbc Mon Sep 17 00:00:00 2001 From: Shahar Levi Date: Sun, 6 Mar 2011 16:32:14 +0200 Subject: wl12xx: 1281/1283 support - Add dummy packet support Support sending dummy packet to wl128x FW as results of dummy packet event. That is part of dynamic TX mem blocks mechanism. Only send dummy packet when not in AP mode. [Even though the DUMMY_PACKET_EVENT_ID and the STA_REMOVE_COMPLETE_EVENT_ID events are defined to the same value, we need to treat them separately in the code. Keep the check and enable STA_REMOVE_COMPLETE_EVENT_ID for AP mode and DUMMY_PACKET_EVENT_ID for STA. Moved one warning to a cleaner place. Use WL1271_TID_MGMT for dummy packets -- Luca] Signed-off-by: Shahar Levi Reviewed-by: Luciano Coelho Signed-off-by: Luciano Coelho diff --git a/drivers/net/wireless/wl12xx/boot.c b/drivers/net/wireless/wl12xx/boot.c index 9d742c1..34bf2fe 100644 --- a/drivers/net/wireless/wl12xx/boot.c +++ b/drivers/net/wireless/wl12xx/boot.c @@ -482,6 +482,8 @@ static int wl1271_boot_run_firmware(struct wl1271 *wl) if (wl->bss_type == BSS_TYPE_AP_BSS) wl->event_mask |= STA_REMOVE_COMPLETE_EVENT_ID; + else + wl->event_mask |= DUMMY_PACKET_EVENT_ID; ret = wl1271_event_unmask(wl); if (ret < 0) { diff --git a/drivers/net/wireless/wl12xx/event.c b/drivers/net/wireless/wl12xx/event.c index 1b170c5..413d901 100644 --- a/drivers/net/wireless/wl12xx/event.c +++ b/drivers/net/wireless/wl12xx/event.c @@ -228,6 +228,12 @@ static int wl1271_event_process(struct wl1271 *wl, struct event_mailbox *mbox) wl1271_event_rssi_trigger(wl, mbox); } + if ((vector & DUMMY_PACKET_EVENT_ID) && !is_ap) { + wl1271_debug(DEBUG_EVENT, "DUMMY_PACKET_ID_EVENT_ID"); + if (wl->vif) + wl1271_tx_dummy_packet(wl); + } + if (wl->vif && beacon_loss) ieee80211_connection_loss(wl->vif); diff --git a/drivers/net/wireless/wl12xx/event.h b/drivers/net/wireless/wl12xx/event.h index 0e80886..b6cf06e 100644 --- a/drivers/net/wireless/wl12xx/event.h +++ b/drivers/net/wireless/wl12xx/event.h @@ -59,7 +59,10 @@ enum { BSS_LOSE_EVENT_ID = BIT(18), REGAINED_BSS_EVENT_ID = BIT(19), ROAMING_TRIGGER_MAX_TX_RETRY_EVENT_ID = BIT(20), - STA_REMOVE_COMPLETE_EVENT_ID = BIT(21), /* AP */ + /* STA: dummy paket for dynamic mem blocks */ + DUMMY_PACKET_EVENT_ID = BIT(21), + /* AP: STA remove complete */ + STA_REMOVE_COMPLETE_EVENT_ID = BIT(21), SOFT_GEMINI_SENSE_EVENT_ID = BIT(22), SOFT_GEMINI_PREDICTION_EVENT_ID = BIT(23), SOFT_GEMINI_AVALANCHE_EVENT_ID = BIT(24), diff --git a/drivers/net/wireless/wl12xx/io.h b/drivers/net/wireless/wl12xx/io.h index 84454f6..e6199eb 100644 --- a/drivers/net/wireless/wl12xx/io.h +++ b/drivers/net/wireless/wl12xx/io.h @@ -170,5 +170,6 @@ struct ieee80211_hw *wl1271_alloc_hw(void); int wl1271_free_hw(struct wl1271 *wl); irqreturn_t wl1271_irq(int irq, void *data); bool wl1271_set_block_size(struct wl1271 *wl); +int wl1271_tx_dummy_packet(struct wl1271 *wl); #endif diff --git a/drivers/net/wireless/wl12xx/main.c b/drivers/net/wireless/wl12xx/main.c index 3c381ce..54ac675 100644 --- a/drivers/net/wireless/wl12xx/main.c +++ b/drivers/net/wireless/wl12xx/main.c @@ -1174,6 +1174,48 @@ static void wl1271_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb) spin_unlock_irqrestore(&wl->wl_lock, flags); } +#define TX_DUMMY_PACKET_SIZE 1400 +int wl1271_tx_dummy_packet(struct wl1271 *wl) +{ + struct sk_buff *skb = NULL; + struct ieee80211_hdr_3addr *hdr; + int ret = 0; + + skb = dev_alloc_skb( + sizeof(struct wl1271_tx_hw_descr) + sizeof(*hdr) + + TX_DUMMY_PACKET_SIZE); + if (!skb) { + wl1271_warning("failed to allocate buffer for dummy packet"); + ret = -ENOMEM; + goto out; + } + + skb_reserve(skb, sizeof(struct wl1271_tx_hw_descr)); + + hdr = (struct ieee80211_hdr_3addr *) skb_put(skb, sizeof(*hdr)); + memset(hdr, 0, sizeof(*hdr)); + hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_DATA | + IEEE80211_FCTL_TODS | + IEEE80211_STYPE_NULLFUNC); + + memcpy(hdr->addr1, wl->bssid, ETH_ALEN); + memcpy(hdr->addr2, wl->mac_addr, ETH_ALEN); + memcpy(hdr->addr3, wl->bssid, ETH_ALEN); + + skb_put(skb, TX_DUMMY_PACKET_SIZE); + + memset(skb->data, 0, TX_DUMMY_PACKET_SIZE); + + skb->pkt_type = TX_PKT_TYPE_DUMMY_REQ; + /* CONF_TX_AC_VO */ + skb->queue_mapping = 0; + + wl1271_op_tx(wl->hw, skb); + +out: + return ret; +} + static struct notifier_block wl1271_dev_notifier = { .notifier_call = wl1271_dev_notify, }; diff --git a/drivers/net/wireless/wl12xx/tx.c b/drivers/net/wireless/wl12xx/tx.c index afc8505..75222a6 100644 --- a/drivers/net/wireless/wl12xx/tx.c +++ b/drivers/net/wireless/wl12xx/tx.c @@ -215,13 +215,29 @@ static void wl1271_tx_fill_hdr(struct wl1271 *wl, struct sk_buff *skb, else desc->life_time = cpu_to_le16(TX_HW_AP_MODE_PKT_LIFETIME_TU); - /* configure the tx attributes */ - tx_attr = wl->session_counter << TX_HW_ATTR_OFST_SESSION_COUNTER; - /* queue (we use same identifiers for tid's and ac's */ ac = wl1271_tx_get_queue(skb_get_queue_mapping(skb)); desc->tid = ac; + if (skb->pkt_type == TX_PKT_TYPE_DUMMY_REQ) { + /* + * FW expects the dummy packet to have an invalid session id - + * any session id that is different than the one set in the join + */ + tx_attr = ((~wl->session_counter) << + TX_HW_ATTR_OFST_SESSION_COUNTER) & + TX_HW_ATTR_SESSION_COUNTER; + + tx_attr |= TX_HW_ATTR_TX_DUMMY_REQ; + + /* Dummy packets require the TID to be management */ + desc->tid = WL1271_TID_MGMT; + } else { + /* configure the tx attributes */ + tx_attr = + wl->session_counter << TX_HW_ATTR_OFST_SESSION_COUNTER; + } + if (wl->bss_type != BSS_TYPE_AP_BSS) { desc->aid = hlid; @@ -587,6 +603,12 @@ static void wl1271_tx_complete_packet(struct wl1271 *wl, skb = wl->tx_frames[id]; info = IEEE80211_SKB_CB(skb); + if (skb->pkt_type == TX_PKT_TYPE_DUMMY_REQ) { + dev_kfree_skb(skb); + wl1271_free_tx_id(wl, id); + return; + } + /* update the TX status info */ if (result->status == TX_SUCCESS) { if (!(info->flags & IEEE80211_TX_CTL_NO_ACK)) @@ -716,10 +738,15 @@ void wl1271_tx_reset(struct wl1271 *wl) while ((skb = skb_dequeue(&wl->tx_queue[i]))) { wl1271_debug(DEBUG_TX, "freeing skb 0x%p", skb); - info = IEEE80211_SKB_CB(skb); - info->status.rates[0].idx = -1; - info->status.rates[0].count = 0; - ieee80211_tx_status(wl->hw, skb); + + if (skb->pkt_type == TX_PKT_TYPE_DUMMY_REQ) { + dev_kfree_skb(skb); + } else { + info = IEEE80211_SKB_CB(skb); + info->status.rates[0].idx = -1; + info->status.rates[0].count = 0; + ieee80211_tx_status(wl->hw, skb); + } } } } @@ -740,21 +767,29 @@ void wl1271_tx_reset(struct wl1271 *wl) wl1271_free_tx_id(wl, i); wl1271_debug(DEBUG_TX, "freeing skb 0x%p", skb); - /* Remove private headers before passing the skb to mac80211 */ - info = IEEE80211_SKB_CB(skb); - skb_pull(skb, sizeof(struct wl1271_tx_hw_descr)); - if (info->control.hw_key && - info->control.hw_key->cipher == WLAN_CIPHER_SUITE_TKIP) { - int hdrlen = ieee80211_get_hdrlen_from_skb(skb); - memmove(skb->data + WL1271_TKIP_IV_SPACE, skb->data, - hdrlen); - skb_pull(skb, WL1271_TKIP_IV_SPACE); - } + if (skb->pkt_type == TX_PKT_TYPE_DUMMY_REQ) { + dev_kfree_skb(skb); + } else { + /* + * Remove private headers before passing the skb to + * mac80211 + */ + info = IEEE80211_SKB_CB(skb); + skb_pull(skb, sizeof(struct wl1271_tx_hw_descr)); + if (info->control.hw_key && + info->control.hw_key->cipher == + WLAN_CIPHER_SUITE_TKIP) { + int hdrlen = ieee80211_get_hdrlen_from_skb(skb); + memmove(skb->data + WL1271_TKIP_IV_SPACE, + skb->data, hdrlen); + skb_pull(skb, WL1271_TKIP_IV_SPACE); + } - info->status.rates[0].idx = -1; - info->status.rates[0].count = 0; + info->status.rates[0].idx = -1; + info->status.rates[0].count = 0; - ieee80211_tx_status(wl->hw, skb); + ieee80211_tx_status(wl->hw, skb); + } } } diff --git a/drivers/net/wireless/wl12xx/tx.h b/drivers/net/wireless/wl12xx/tx.h index e313177..6f45e91 100644 --- a/drivers/net/wireless/wl12xx/tx.h +++ b/drivers/net/wireless/wl12xx/tx.h @@ -41,6 +41,9 @@ BIT(8) | BIT(9)) #define TX_HW_ATTR_LAST_WORD_PAD (BIT(10) | BIT(11)) #define TX_HW_ATTR_TX_CMPLT_REQ BIT(12) +#define TX_HW_ATTR_TX_DUMMY_REQ BIT(13) + +#define TX_PKT_TYPE_DUMMY_REQ 5 #define TX_HW_ATTR_OFST_SAVE_RETRIES 0 #define TX_HW_ATTR_OFST_HEADER_PAD 1 @@ -55,6 +58,9 @@ #define WL1271_TX_ALIGN_TO 4 #define WL1271_TKIP_IV_SPACE 4 +/* Used for management frames and dummy packets */ +#define WL1271_TID_MGMT 7 + struct wl127x_tx_mem { /* * Number of extra memory blocks to allocate for this packet -- cgit v0.10.2 From 1aed55fd784d000fb6741cefb68712d64817bd68 Mon Sep 17 00:00:00 2001 From: Arik Nemtsov Date: Sun, 6 Mar 2011 16:32:18 +0200 Subject: wl12xx: 1281/1283 support - Use different FW file for AP mode wl127x/wl128x chips Choose a different FW for AP-mode wl127x and wl128x chips, base on chip ID at boot time. Signed-off-by: Arik Nemtsov Reviewed-by: Luciano Coelho Signed-off-by: Luciano Coelho diff --git a/drivers/net/wireless/wl12xx/main.c b/drivers/net/wireless/wl12xx/main.c index 54ac675..9a7ca65 100644 --- a/drivers/net/wireless/wl12xx/main.c +++ b/drivers/net/wireless/wl12xx/main.c @@ -832,7 +832,10 @@ static int wl1271_fetch_firmware(struct wl1271 *wl) switch (wl->bss_type) { case BSS_TYPE_AP_BSS: - fw_name = WL1271_AP_FW_NAME; + if (wl->chip.id == CHIP_ID_1283_PG20) + fw_name = WL128X_AP_FW_NAME; + else + fw_name = WL127X_AP_FW_NAME; break; case BSS_TYPE_IBSS: case BSS_TYPE_STA_BSS: diff --git a/drivers/net/wireless/wl12xx/sdio.c b/drivers/net/wireless/wl12xx/sdio.c index f6dd3de..5a2951e 100644 --- a/drivers/net/wireless/wl12xx/sdio.c +++ b/drivers/net/wireless/wl12xx/sdio.c @@ -361,4 +361,5 @@ MODULE_AUTHOR("Luciano Coelho "); MODULE_AUTHOR("Juuso Oikarinen "); MODULE_FIRMWARE(WL1271_FW_NAME); MODULE_FIRMWARE(WL128X_FW_NAME); -MODULE_FIRMWARE(WL1271_AP_FW_NAME); +MODULE_FIRMWARE(WL127X_AP_FW_NAME); +MODULE_FIRMWARE(WL128X_AP_FW_NAME); diff --git a/drivers/net/wireless/wl12xx/spi.c b/drivers/net/wireless/wl12xx/spi.c index f552536..7b82b5f 100644 --- a/drivers/net/wireless/wl12xx/spi.c +++ b/drivers/net/wireless/wl12xx/spi.c @@ -493,5 +493,6 @@ MODULE_AUTHOR("Luciano Coelho "); MODULE_AUTHOR("Juuso Oikarinen "); MODULE_FIRMWARE(WL1271_FW_NAME); MODULE_FIRMWARE(WL128X_FW_NAME); -MODULE_FIRMWARE(WL1271_AP_FW_NAME); +MODULE_FIRMWARE(WL127X_AP_FW_NAME); +MODULE_FIRMWARE(WL128X_AP_FW_NAME); MODULE_ALIAS("spi:wl1271"); diff --git a/drivers/net/wireless/wl12xx/wl12xx.h b/drivers/net/wireless/wl12xx/wl12xx.h index ad04b83..890c1a5 100644 --- a/drivers/net/wireless/wl12xx/wl12xx.h +++ b/drivers/net/wireless/wl12xx/wl12xx.h @@ -132,7 +132,8 @@ extern u32 wl12xx_debug_level; #define WL1271_FW_NAME "ti-connectivity/wl1271-fw-2.bin" #define WL128X_FW_NAME "ti-connectivity/wl128x-fw.bin" -#define WL1271_AP_FW_NAME "ti-connectivity/wl1271-fw-ap.bin" +#define WL127X_AP_FW_NAME "ti-connectivity/wl1271-fw-ap.bin" +#define WL128X_AP_FW_NAME "ti-connectivity/wl128x-fw-ap.bin" /* * wl127x and wl128x are using the same NVS file name. However, the -- cgit v0.10.2 From 0830ceedbfde20c9110c59597fdffbf51886565a Mon Sep 17 00:00:00 2001 From: Shahar Levi Date: Sun, 6 Mar 2011 16:32:20 +0200 Subject: wl12xx: 1281/1283 support - enable chip support Add support to wl128x chip via chip id Signed-off-by: Shahar Levi Reviewed-by: Luciano Coelho Signed-off-by: Luciano Coelho diff --git a/drivers/net/wireless/wl12xx/Kconfig b/drivers/net/wireless/wl12xx/Kconfig index 692ebff..35ce7b0 100644 --- a/drivers/net/wireless/wl12xx/Kconfig +++ b/drivers/net/wireless/wl12xx/Kconfig @@ -3,7 +3,7 @@ menuconfig WL12XX_MENU depends on MAC80211 && EXPERIMENTAL ---help--- This will enable TI wl12xx driver support for the following chips: - wl1271 and wl1273. + wl1271, wl1273, wl1281 and wl1283. The drivers make use of the mac80211 stack. config WL12XX diff --git a/drivers/net/wireless/wl12xx/main.c b/drivers/net/wireless/wl12xx/main.c index 9a7ca65..0b9d41f 100644 --- a/drivers/net/wireless/wl12xx/main.c +++ b/drivers/net/wireless/wl12xx/main.c @@ -1007,6 +1007,15 @@ static int wl1271_chip_wakeup(struct wl1271 *wl) if (ret < 0) goto out; break; + case CHIP_ID_1283_PG20: + wl1271_debug(DEBUG_BOOT, "chip id 0x%x (1283 PG20)", + wl->chip.id); + + ret = wl1271_setup(wl); + if (ret < 0) + goto out; + break; + case CHIP_ID_1283_PG10: default: wl1271_warning("unsupported chip id: 0x%x", wl->chip.id); ret = -ENODEV; diff --git a/drivers/net/wireless/wl12xx/sdio_test.c b/drivers/net/wireless/wl12xx/sdio_test.c index c02c870..968249a 100644 --- a/drivers/net/wireless/wl12xx/sdio_test.c +++ b/drivers/net/wireless/wl12xx/sdio_test.c @@ -293,6 +293,11 @@ static int wl1271_chip_wakeup(struct wl1271 *wl) wl1271_notice("chip id 0x%x (1271 PG20)", wl->chip.id); break; + case CHIP_ID_1283_PG20: + wl1271_notice("chip id 0x%x (1283 PG20)", + wl->chip.id); + break; + case CHIP_ID_1283_PG10: default: wl1271_warning("unsupported chip id: 0x%x", wl->chip.id); return -ENODEV; -- cgit v0.10.2 From e7ddf549f3f2da156f5c12921e6699024e80a3f4 Mon Sep 17 00:00:00 2001 From: Luciano Coelho Date: Thu, 10 Mar 2011 15:24:57 +0200 Subject: wl12xx: use 1 spare TX block instead of two All the new firmware versions (>=6.1.3.50.58 for STA and >=6.2.0.0.47 for AP) use 1 spare TX block. We still want to support older firmwares that require 2 spare blocks, so added a quirk to handle the difference. Also implemented a generic way of setting quirks that depend on the firmware revision. Signed-off-by: Luciano Coelho diff --git a/drivers/net/wireless/wl12xx/main.c b/drivers/net/wireless/wl12xx/main.c index 0b9d41f..db7ab85 100644 --- a/drivers/net/wireless/wl12xx/main.c +++ b/drivers/net/wireless/wl12xx/main.c @@ -1040,6 +1040,24 @@ out: return ret; } +static unsigned int wl1271_get_fw_ver_quirks(struct wl1271 *wl) +{ + unsigned int quirks = 0; + unsigned int *fw_ver = wl->chip.fw_ver; + + /* Only for wl127x */ + if ((fw_ver[FW_VER_CHIP] == FW_VER_CHIP_WL127X) && + /* Check STA version */ + (((fw_ver[FW_VER_IF_TYPE] == FW_VER_IF_TYPE_STA) && + (fw_ver[FW_VER_MINOR] < FW_VER_MINOR_1_SPARE_STA_MIN)) || + /* Check AP version */ + ((fw_ver[FW_VER_IF_TYPE] == FW_VER_IF_TYPE_AP) && + (fw_ver[FW_VER_MINOR] < FW_VER_MINOR_1_SPARE_AP_MIN)))) + quirks |= WL12XX_QUIRK_USE_2_SPARE_BLOCKS; + + return quirks; +} + int wl1271_plt_start(struct wl1271 *wl) { int retries = WL1271_BOOT_RETRIES; @@ -1075,6 +1093,9 @@ int wl1271_plt_start(struct wl1271 *wl) wl->state = WL1271_STATE_PLT; wl1271_notice("firmware booted in PLT mode (%s)", wl->chip.fw_ver_str); + + /* Check if any quirks are needed with older fw versions */ + wl->quirks |= wl1271_get_fw_ver_quirks(wl); goto out; irq_disable: @@ -1353,6 +1374,9 @@ power_off: strncpy(wiphy->fw_version, wl->chip.fw_ver_str, sizeof(wiphy->fw_version)); + /* Check if any quirks are needed with older fw versions */ + wl->quirks |= wl1271_get_fw_ver_quirks(wl); + /* * Now we know if 11a is supported (info from the NVS), so disable * 11a channels if not supported diff --git a/drivers/net/wireless/wl12xx/tx.c b/drivers/net/wireless/wl12xx/tx.c index 75222a6..109878c 100644 --- a/drivers/net/wireless/wl12xx/tx.c +++ b/drivers/net/wireless/wl12xx/tx.c @@ -135,6 +135,12 @@ static int wl1271_tx_allocate(struct wl1271 *wl, struct sk_buff *skb, u32 extra, u32 len; u32 total_blocks; int id, ret = -EBUSY; + u32 spare_blocks; + + if (unlikely(wl->quirks & WL12XX_QUIRK_USE_2_SPARE_BLOCKS)) + spare_blocks = 2; + else + spare_blocks = 1; if (buf_offset + total_len > WL1271_AGGR_BUFFER_SIZE) return -EAGAIN; @@ -152,7 +158,7 @@ static int wl1271_tx_allocate(struct wl1271 *wl, struct sk_buff *skb, u32 extra, len = total_len; total_blocks = (len + TX_HW_BLOCK_SIZE - 1) / TX_HW_BLOCK_SIZE + - TX_HW_BLOCK_SPARE; + spare_blocks; if (total_blocks <= wl->tx_blocks_available) { desc = (struct wl1271_tx_hw_descr *)skb_push( @@ -162,7 +168,7 @@ static int wl1271_tx_allocate(struct wl1271 *wl, struct sk_buff *skb, u32 extra, if (wl->chip.id == CHIP_ID_1283_PG20) { desc->wl128x_mem.total_mem_blocks = total_blocks; } else { - desc->wl127x_mem.extra_blocks = TX_HW_BLOCK_SPARE; + desc->wl127x_mem.extra_blocks = spare_blocks; desc->wl127x_mem.total_mem_blocks = total_blocks; } diff --git a/drivers/net/wireless/wl12xx/tx.h b/drivers/net/wireless/wl12xx/tx.h index 6f45e91..a3877ba 100644 --- a/drivers/net/wireless/wl12xx/tx.h +++ b/drivers/net/wireless/wl12xx/tx.h @@ -25,7 +25,6 @@ #ifndef __TX_H__ #define __TX_H__ -#define TX_HW_BLOCK_SPARE 2 #define TX_HW_BLOCK_SIZE 252 #define TX_HW_MGMT_PKT_LIFETIME_TU 2000 diff --git a/drivers/net/wireless/wl12xx/wl12xx.h b/drivers/net/wireless/wl12xx/wl12xx.h index 890c1a5..b04481a 100644 --- a/drivers/net/wireless/wl12xx/wl12xx.h +++ b/drivers/net/wireless/wl12xx/wl12xx.h @@ -207,13 +207,29 @@ struct wl1271_partition_set { struct wl1271; -#define WL12XX_NUM_FW_VER 5 +enum { + FW_VER_CHIP, + FW_VER_IF_TYPE, + FW_VER_MAJOR, + FW_VER_SUBTYPE, + FW_VER_MINOR, + + NUM_FW_VER +}; + +#define FW_VER_CHIP_WL127X 6 +#define FW_VER_CHIP_WL128X 7 + +#define FW_VER_IF_TYPE_STA 1 +#define FW_VER_IF_TYPE_AP 2 + +#define FW_VER_MINOR_1_SPARE_STA_MIN 58 +#define FW_VER_MINOR_1_SPARE_AP_MIN 47 -/* FIXME: I'm not sure about this structure name */ struct wl1271_chip { u32 id; char fw_ver_str[ETHTOOL_BUSINFO_LEN]; - unsigned int fw_ver[WL12XX_NUM_FW_VER]; + unsigned int fw_ver[NUM_FW_VER]; }; struct wl1271_stats { @@ -594,4 +610,10 @@ int wl1271_plt_stop(struct wl1271 *wl); /* Each RX/TX transaction requires an end-of-transaction transfer */ #define WL12XX_QUIRK_END_OF_TRANSACTION BIT(0) +/* + * Older firmwares use 2 spare TX blocks + * (for STA < 6.1.3.50.58 or for AP < 6.2.0.0.47) + */ +#define WL12XX_QUIRK_USE_2_SPARE_BLOCKS BIT(1) + #endif -- cgit v0.10.2 From 0af0467f09207cbbeb387d2e09ea539534c6655c Mon Sep 17 00:00:00 2001 From: Juuso Oikarinen Date: Thu, 10 Mar 2011 10:01:43 +0200 Subject: wl12xx: Fix potential incorrect band in rx-status The rx-status passed to mac80211 along with each received frame contains the band on which the frame was received. Under certain circumstances, this band information may be incorrect, causing in worst case a WARNING from mac80211, and causes the received frame to be dropped. This scenario mainly occurs when performing connected-mode scans, when the received scan results are from the other band than the one currently associated to. [Since desc_band doesn't exist anymore, use status->band in the later call to ieee80211_channel_to_frequency() to fix compilation -- Luca] Signed-off-by: Juuso Oikarinen Reviewed-by: Luciano Coelho Signed-off-by: Luciano Coelho diff --git a/drivers/net/wireless/wl12xx/rx.c b/drivers/net/wireless/wl12xx/rx.c index 132b0ca..2a58149 100644 --- a/drivers/net/wireless/wl12xx/rx.c +++ b/drivers/net/wireless/wl12xx/rx.c @@ -48,18 +48,14 @@ static void wl1271_rx_status(struct wl1271 *wl, struct ieee80211_rx_status *status, u8 beacon) { - enum ieee80211_band desc_band; - memset(status, 0, sizeof(struct ieee80211_rx_status)); - status->band = wl->band; - if ((desc->flags & WL1271_RX_DESC_BAND_MASK) == WL1271_RX_DESC_BAND_BG) - desc_band = IEEE80211_BAND_2GHZ; + status->band = IEEE80211_BAND_2GHZ; else - desc_band = IEEE80211_BAND_5GHZ; + status->band = IEEE80211_BAND_5GHZ; - status->rate_idx = wl1271_rate_to_idx(desc->rate, desc_band); + status->rate_idx = wl1271_rate_to_idx(desc->rate, status->band); #ifdef CONFIG_WL12XX_HT /* 11n support */ @@ -76,7 +72,8 @@ static void wl1271_rx_status(struct wl1271 *wl, */ wl->noise = desc->rssi - (desc->snr >> 1); - status->freq = ieee80211_channel_to_frequency(desc->channel, desc_band); + status->freq = ieee80211_channel_to_frequency(desc->channel, + status->band); if (desc->flags & WL1271_RX_DESC_ENCRYPT_MASK) { status->flag |= RX_FLAG_IV_STRIPPED | RX_FLAG_MMIC_STRIPPED; -- cgit v0.10.2 From 871d0c3ba32c2d2e1e7d9ac0d231a440d2653fc5 Mon Sep 17 00:00:00 2001 From: Shahar Levi Date: Sun, 13 Mar 2011 11:24:40 +0200 Subject: wl12xx: Add support for 11n Rx STBC one spatial stream The wl12xx chip supports one Rx STBC spatial stream. Announce this in the HT capabilities info field. Signed-off-by: Shahar Levi Signed-off-by: Luciano Coelho diff --git a/drivers/net/wireless/wl12xx/main.c b/drivers/net/wireless/wl12xx/main.c index db7ab85..2804847 100644 --- a/drivers/net/wireless/wl12xx/main.c +++ b/drivers/net/wireless/wl12xx/main.c @@ -3132,7 +3132,8 @@ static const u8 wl1271_rate_to_idx_2ghz[] = { #ifdef CONFIG_WL12XX_HT #define WL12XX_HT_CAP { \ - .cap = IEEE80211_HT_CAP_GRN_FLD | IEEE80211_HT_CAP_SGI_20, \ + .cap = IEEE80211_HT_CAP_GRN_FLD | IEEE80211_HT_CAP_SGI_20 | \ + (1 << IEEE80211_HT_CAP_RX_STBC_SHIFT), \ .ht_supported = true, \ .ampdu_factor = IEEE80211_HT_MAX_AMPDU_8K, \ .ampdu_density = IEEE80211_HT_MPDU_DENSITY_8, \ -- cgit v0.10.2 From 958b20e068be2c6267c2b5764babf15b0d4f5c69 Mon Sep 17 00:00:00 2001 From: Ohad Ben-Cohen Date: Mon, 14 Mar 2011 18:53:10 +0200 Subject: wl12xx: update bet_max_consecutive Allow early termination of 50 consecutive beacons. This value is the recommended one by the 12xx's system/RF team, and tests show that power consumption is improved as expected. Reported-by: Ruthy Zaphir Tested-by: Danil Shalumov Signed-off-by: Ohad Ben-Cohen Signed-off-by: Luciano Coelho diff --git a/drivers/net/wireless/wl12xx/main.c b/drivers/net/wireless/wl12xx/main.c index 2804847..dd49b22 100644 --- a/drivers/net/wireless/wl12xx/main.c +++ b/drivers/net/wireless/wl12xx/main.c @@ -254,7 +254,7 @@ static struct conf_drv_settings default_conf = { .ps_poll_threshold = 10, .ps_poll_recovery_period = 700, .bet_enable = CONF_BET_MODE_ENABLE, - .bet_max_consecutive = 10, + .bet_max_consecutive = 50, .psm_entry_retries = 5, .psm_exit_retries = 255, .psm_entry_nullfunc_retries = 3, -- cgit v0.10.2 From 1d732e8cf3dcc09d7c862b6c12f876533529073d Mon Sep 17 00:00:00 2001 From: Arik Nemtsov Date: Fri, 18 Mar 2011 14:49:57 +0200 Subject: wl12xx: Clamp byte mode transfers for 128x chips On wl128x based devices, when TX packets are aggregated, each packet size must be aligned to the SDIO block size, and sent using block mode transfers. The block size is set to 256 bytes, which is less than the maximum possible byte transfer. Thus, if two small packets (< 256 bytes) are aggregated, the aggregation buffer size would be 512, and will be sent using byte mode transfers. This can have undesired side effects. Fix this by setting the MMC_QUIRK_BLKSZ_FOR_BYTE_MODE mmc card quirk. For 127x chips this has no effect, as the block size is set to 512 bytes. Signed-off-by: Arik Nemtsov Signed-off-by: Ido Yariv Signed-off-by: Luciano Coelho diff --git a/drivers/net/wireless/wl12xx/sdio.c b/drivers/net/wireless/wl12xx/sdio.c index 5a2951e..2ade222 100644 --- a/drivers/net/wireless/wl12xx/sdio.c +++ b/drivers/net/wireless/wl12xx/sdio.c @@ -246,6 +246,9 @@ static int __devinit wl1271_probe(struct sdio_func *func, /* Grab access to FN0 for ELP reg. */ func->card->quirks |= MMC_QUIRK_LENIENT_FN0; + /* Use block mode for transferring over one block size of data */ + func->card->quirks |= MMC_QUIRK_BLKSZ_FOR_BYTE_MODE; + wlan_data = wl12xx_get_platform_data(); if (IS_ERR(wlan_data)) { ret = PTR_ERR(wlan_data); diff --git a/drivers/net/wireless/wl12xx/sdio_test.c b/drivers/net/wireless/wl12xx/sdio_test.c index 968249a..f289153 100644 --- a/drivers/net/wireless/wl12xx/sdio_test.c +++ b/drivers/net/wireless/wl12xx/sdio_test.c @@ -417,6 +417,9 @@ static int __devinit wl1271_probe(struct sdio_func *func, /* Grab access to FN0 for ELP reg. */ func->card->quirks |= MMC_QUIRK_LENIENT_FN0; + /* Use block mode for transferring over one block size of data */ + func->card->quirks |= MMC_QUIRK_BLKSZ_FOR_BYTE_MODE; + wlan_data = wl12xx_get_platform_data(); if (IS_ERR(wlan_data)) { ret = PTR_ERR(wlan_data); -- cgit v0.10.2 From f9f774c17e19da6f98bd7b57527f55d0ec920fce Mon Sep 17 00:00:00 2001 From: Juuso Oikarinen Date: Mon, 21 Mar 2011 10:43:36 +0200 Subject: wl12xx: Add mutex protection for interface list The interface list maintained in main.c is not mutex protected. This could cause issues, as the list is accessed from notifier chains. Signed-off-by: Juuso Oikarinen Reviewed-by: Luciano Coelho Signed-off-by: Luciano Coelho diff --git a/drivers/net/wireless/wl12xx/main.c b/drivers/net/wireless/wl12xx/main.c index dd49b22..72e84a2 100644 --- a/drivers/net/wireless/wl12xx/main.c +++ b/drivers/net/wireless/wl12xx/main.c @@ -339,6 +339,7 @@ static struct platform_device wl1271_device = { }, }; +static DEFINE_MUTEX(wl_list_mutex); static LIST_HEAD(wl_list); static int wl1271_dev_notify(struct notifier_block *me, unsigned long what, @@ -369,10 +370,12 @@ static int wl1271_dev_notify(struct notifier_block *me, unsigned long what, return NOTIFY_DONE; wl_temp = hw->priv; + mutex_lock(&wl_list_mutex); list_for_each_entry(wl, &wl_list, list) { if (wl == wl_temp) break; } + mutex_unlock(&wl_list_mutex); if (wl != wl_temp) return NOTIFY_DONE; @@ -1390,8 +1393,10 @@ power_off: out: mutex_unlock(&wl->mutex); + mutex_lock(&wl_list_mutex); if (!ret) list_add(&wl->list, &wl_list); + mutex_unlock(&wl_list_mutex); return ret; } @@ -1404,7 +1409,9 @@ static void __wl1271_op_remove_interface(struct wl1271 *wl) wl1271_info("down"); + mutex_lock(&wl_list_mutex); list_del(&wl->list); + mutex_unlock(&wl_list_mutex); WARN_ON(wl->state != WL1271_STATE_ON); -- cgit v0.10.2 From db674d249c1fa20fd6731048f41646b3a2e8bdf5 Mon Sep 17 00:00:00 2001 From: Eliad Peller Date: Wed, 16 Mar 2011 23:03:54 +0200 Subject: wl12xx: set the actual tid instead of the ac When passing a tx frame, the driver incorrectly set desc->tid with the ac instead of the actual tid. It has some serious implications when using 802.11n + QoS, as the fw starts a BlockAck with the wrong tid (which finally cause beacon loss and disconnection / some fw crash) Fix it by using the actual tid stored in skb->priority. Reported-by: Shahar Levi Signed-off-by: Eliad Peller Reviewed-by: Juuso Oikarinen Signed-off-by: Luciano Coelho diff --git a/drivers/net/wireless/wl12xx/tx.c b/drivers/net/wireless/wl12xx/tx.c index 109878c..f3031cd 100644 --- a/drivers/net/wireless/wl12xx/tx.c +++ b/drivers/net/wireless/wl12xx/tx.c @@ -221,9 +221,9 @@ static void wl1271_tx_fill_hdr(struct wl1271 *wl, struct sk_buff *skb, else desc->life_time = cpu_to_le16(TX_HW_AP_MODE_PKT_LIFETIME_TU); - /* queue (we use same identifiers for tid's and ac's */ + /* queue */ ac = wl1271_tx_get_queue(skb_get_queue_mapping(skb)); - desc->tid = ac; + desc->tid = skb->priority; if (skb->pkt_type == TX_PKT_TYPE_DUMMY_REQ) { /* -- cgit v0.10.2 From 18b92ffaf33c862e852992e82e17b9fffca8d5a4 Mon Sep 17 00:00:00 2001 From: Luciano Coelho Date: Mon, 21 Mar 2011 16:35:21 +0200 Subject: wl12xx: set the skbuff priority for dummy packets The firmware requires dummy packets to be sent using TID 7 (WL1271_TID_MGMT). Instead of hardcoding it in the tx_fill_hdr() function, set it when creating the packet itself. This requires Eliad's fix to set the actual TID in the TX descriptor. Cc: Ido Yariv Signed-off-by: Luciano Coelho diff --git a/drivers/net/wireless/wl12xx/main.c b/drivers/net/wireless/wl12xx/main.c index 72e84a2..59e0f79 100644 --- a/drivers/net/wireless/wl12xx/main.c +++ b/drivers/net/wireless/wl12xx/main.c @@ -1243,6 +1243,8 @@ int wl1271_tx_dummy_packet(struct wl1271 *wl) memset(skb->data, 0, TX_DUMMY_PACKET_SIZE); skb->pkt_type = TX_PKT_TYPE_DUMMY_REQ; + /* Dummy packets require the TID to be management */ + skb->priority = WL1271_TID_MGMT; /* CONF_TX_AC_VO */ skb->queue_mapping = 0; diff --git a/drivers/net/wireless/wl12xx/tx.c b/drivers/net/wireless/wl12xx/tx.c index f3031cd..db9e47e 100644 --- a/drivers/net/wireless/wl12xx/tx.c +++ b/drivers/net/wireless/wl12xx/tx.c @@ -235,9 +235,6 @@ static void wl1271_tx_fill_hdr(struct wl1271 *wl, struct sk_buff *skb, TX_HW_ATTR_SESSION_COUNTER; tx_attr |= TX_HW_ATTR_TX_DUMMY_REQ; - - /* Dummy packets require the TID to be management */ - desc->tid = WL1271_TID_MGMT; } else { /* configure the tx attributes */ tx_attr = -- cgit v0.10.2 From d9482e2b5132fd40f8de528af6bb715accbab11d Mon Sep 17 00:00:00 2001 From: Luciano Coelho Date: Mon, 21 Mar 2011 17:58:32 +0200 Subject: wl12xx: fix SG BT load value to reflect its new meaning The Soft Gemini BT load ratio value has changed its meaning with FW version 6.1.0.0.310. It now means the passive scan compensation percentage during A2DP EDR. Instead of 50, we need to use 200. Fix the SG configuration accordingly. Signed-off-by: Luciano Coelho diff --git a/drivers/net/wireless/wl12xx/main.c b/drivers/net/wireless/wl12xx/main.c index 59e0f79..916ebd1 100644 --- a/drivers/net/wireless/wl12xx/main.c +++ b/drivers/net/wireless/wl12xx/main.c @@ -54,7 +54,7 @@ static struct conf_drv_settings default_conf = { [CONF_SG_BT_PER_THRESHOLD] = 7500, [CONF_SG_HV3_MAX_OVERRIDE] = 0, [CONF_SG_BT_NFS_SAMPLE_INTERVAL] = 400, - [CONF_SG_BT_LOAD_RATIO] = 50, + [CONF_SG_BT_LOAD_RATIO] = 200, [CONF_SG_AUTO_PS_MODE] = 1, [CONF_SG_AUTO_SCAN_PROBE_REQ] = 170, [CONF_SG_ACTIVE_SCAN_DURATION_FACTOR_HV3] = 50, -- cgit v0.10.2 From 4623ec7d97afaf7a8489036e2c2e71e8349716b4 Mon Sep 17 00:00:00 2001 From: Luciano Coelho Date: Mon, 21 Mar 2011 19:26:41 +0200 Subject: wl12xx: fix a couple of sparse warnings about undeclared functions Fix the following sparse warnings: drivers/net/wireless/wl12xx/main.c:1129:5: warning: symbol '__wl1271_plt_stop' was not declared. Should it be static? drivers/net/wireless/wl12xx/main.c:2988:5: warning: symbol 'wl1271_op_ampdu_action' was not declared. Should it be static? Both functions should be static. Signed-off-by: Luciano Coelho diff --git a/drivers/net/wireless/wl12xx/main.c b/drivers/net/wireless/wl12xx/main.c index 916ebd1..85cb4da 100644 --- a/drivers/net/wireless/wl12xx/main.c +++ b/drivers/net/wireless/wl12xx/main.c @@ -1126,7 +1126,7 @@ out: return ret; } -int __wl1271_plt_stop(struct wl1271 *wl) +static int __wl1271_plt_stop(struct wl1271 *wl) { int ret = 0; @@ -2985,10 +2985,11 @@ out: return ret; } -int wl1271_op_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif, - enum ieee80211_ampdu_mlme_action action, - struct ieee80211_sta *sta, u16 tid, u16 *ssn, - u8 buf_size) +static int wl1271_op_ampdu_action(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + enum ieee80211_ampdu_mlme_action action, + struct ieee80211_sta *sta, u16 tid, u16 *ssn, + u8 buf_size) { struct wl1271 *wl = hw->priv; int ret; -- cgit v0.10.2 From 4a31c11c7d8c482598754a577a8fb71abb61ffa0 Mon Sep 17 00:00:00 2001 From: Luciano Coelho Date: Mon, 21 Mar 2011 23:16:14 +0200 Subject: wl12xx: use a bitmask instead of list of booleans in scanned_ch We were using an array of booleans to mark the channels we had already scanned. This was causing a sparse error, because bool is not a type with defined size. To fix this, use bitmasks instead, which is much cleaner anyway. Thanks Johannes Berg for the idea. Signed-off-by: Luciano Coelho diff --git a/drivers/net/wireless/wl12xx/main.c b/drivers/net/wireless/wl12xx/main.c index 85cb4da..9663326 100644 --- a/drivers/net/wireless/wl12xx/main.c +++ b/drivers/net/wireless/wl12xx/main.c @@ -1423,8 +1423,7 @@ static void __wl1271_op_remove_interface(struct wl1271 *wl) if (wl->scan.state != WL1271_SCAN_STATE_IDLE) { wl->scan.state = WL1271_SCAN_STATE_IDLE; - kfree(wl->scan.scanned_ch); - wl->scan.scanned_ch = NULL; + memset(wl->scan.scanned_ch, 0, sizeof(wl->scan.scanned_ch)); wl->scan.req = NULL; ieee80211_scan_completed(wl->hw, true); } @@ -3502,6 +3501,10 @@ int wl1271_init_ieee80211(struct wl1271 *wl) wl->hw->wiphy->max_scan_ie_len = WL1271_CMD_TEMPL_MAX_SIZE - sizeof(struct ieee80211_header); + /* make sure all our channels fit in the scanned_ch bitmask */ + BUILD_BUG_ON(ARRAY_SIZE(wl1271_channels) + + ARRAY_SIZE(wl1271_channels_5ghz) > + WL1271_MAX_CHANNELS); /* * We keep local copies of the band structs because we need to * modify them on a per-device basis. diff --git a/drivers/net/wireless/wl12xx/scan.c b/drivers/net/wireless/wl12xx/scan.c index 420653a..5d0544c 100644 --- a/drivers/net/wireless/wl12xx/scan.c +++ b/drivers/net/wireless/wl12xx/scan.c @@ -48,8 +48,7 @@ void wl1271_scan_complete_work(struct work_struct *work) goto out; wl->scan.state = WL1271_SCAN_STATE_IDLE; - kfree(wl->scan.scanned_ch); - wl->scan.scanned_ch = NULL; + memset(wl->scan.scanned_ch, 0, sizeof(wl->scan.scanned_ch)); wl->scan.req = NULL; ieee80211_scan_completed(wl->hw, false); @@ -87,7 +86,7 @@ static int wl1271_get_scan_channels(struct wl1271 *wl, flags = req->channels[i]->flags; - if (!wl->scan.scanned_ch[i] && + if (!test_bit(i, wl->scan.scanned_ch) && !(flags & IEEE80211_CHAN_DISABLED) && ((!!(flags & IEEE80211_CHAN_PASSIVE_SCAN)) == passive) && (req->channels[i]->band == band)) { @@ -124,7 +123,7 @@ static int wl1271_get_scan_channels(struct wl1271 *wl, memset(&channels[j].bssid_msb, 0xff, 2); /* Mark the channels we already used */ - wl->scan.scanned_ch[i] = true; + set_bit(i, wl->scan.scanned_ch); j++; } @@ -291,6 +290,12 @@ void wl1271_scan_stm(struct wl1271 *wl) int wl1271_scan(struct wl1271 *wl, const u8 *ssid, size_t ssid_len, struct cfg80211_scan_request *req) { + /* + * cfg80211 should guarantee that we don't get more channels + * than what we have registered. + */ + BUG_ON(req->n_channels > WL1271_MAX_CHANNELS); + if (wl->scan.state != WL1271_SCAN_STATE_IDLE) return -EBUSY; @@ -304,10 +309,8 @@ int wl1271_scan(struct wl1271 *wl, const u8 *ssid, size_t ssid_len, } wl->scan.req = req; + memset(wl->scan.scanned_ch, 0, sizeof(wl->scan.scanned_ch)); - wl->scan.scanned_ch = kcalloc(req->n_channels, - sizeof(*wl->scan.scanned_ch), - GFP_KERNEL); /* we assume failure so that timeout scenarios are handled correctly */ wl->scan.failed = true; ieee80211_queue_delayed_work(wl->hw, &wl->scan_complete_work, diff --git a/drivers/net/wireless/wl12xx/wl12xx.h b/drivers/net/wireless/wl12xx/wl12xx.h index b04481a..ba98e18 100644 --- a/drivers/net/wireless/wl12xx/wl12xx.h +++ b/drivers/net/wireless/wl12xx/wl12xx.h @@ -302,9 +302,10 @@ struct wl1271_rx_mem_pool_addr { u32 addr_extra; }; +#define WL1271_MAX_CHANNELS 64 struct wl1271_scan { struct cfg80211_scan_request *req; - bool *scanned_ch; + unsigned long scanned_ch[BITS_TO_LONGS(WL1271_MAX_CHANNELS)]; bool failed; u8 state; u8 ssid[IW_ESSID_MAX_SIZE+1]; -- cgit v0.10.2 From 17e672d6e4b5a8a3f330a70dfd58d25a2cb497b5 Mon Sep 17 00:00:00 2001 From: Arik Nemtsov Date: Tue, 22 Mar 2011 10:07:47 +0200 Subject: wl12xx: configure channel/band while FW is off Initialize the channel and band from mac80211 conf even when the FW is not yet loaded. This mitigates a bug in AP-mode where the channel was never changed from its initial setting after FW boot and was therefore never configured to FW. Reported-by: Alexander Boukaty Signed-off-by: Arik Nemtsov Signed-off-by: Luciano Coelho diff --git a/drivers/net/wireless/wl12xx/main.c b/drivers/net/wireless/wl12xx/main.c index 9663326..5545c3b 100644 --- a/drivers/net/wireless/wl12xx/main.c +++ b/drivers/net/wireless/wl12xx/main.c @@ -1706,7 +1706,12 @@ static int wl1271_op_config(struct ieee80211_hw *hw, u32 changed) mutex_lock(&wl->mutex); if (unlikely(wl->state == WL1271_STATE_OFF)) { - ret = -EAGAIN; + /* we support configuring the channel and band while off */ + if ((changed & IEEE80211_CONF_CHANGE_CHANNEL)) { + wl->band = conf->channel->band; + wl->channel = channel; + } + goto out; } -- cgit v0.10.2 From c1b193eb6557279d037ab18c00ab628c6c78847f Mon Sep 17 00:00:00 2001 From: Eliad Peller Date: Wed, 23 Mar 2011 22:22:15 +0200 Subject: wl12xx: rearrange some ELP wake_up/sleep calls ELP (Extremely/Enhanced Low Power, or something like that ;)) refers to the powerstate of the 12xx chip, in which very low power is consumed, and no commands (from the host) can be issued until the chip is woken up. Wakeup/sleep commands must be protected by a wl->mutex, so it's generally a good idea to call wakeup/sleep along with the mutex lock/unlock (where needed). However, in some places the wl12xx driver calls wakeup/sleep in some "inner" functions. This result in some "nested" wakeup/sleep calls which might end up letting the chip go to sleep prematurely (e.g. during event handling). Fix it by rearranging the elp calls to come along with mutex_lock/unlock. Signed-off-by: Eliad Peller Signed-off-by: Ido Yariv Signed-off-by: Luciano Coelho diff --git a/drivers/net/wireless/wl12xx/event.c b/drivers/net/wireless/wl12xx/event.c index 413d901..ae69330 100644 --- a/drivers/net/wireless/wl12xx/event.c +++ b/drivers/net/wireless/wl12xx/event.c @@ -33,6 +33,7 @@ void wl1271_pspoll_work(struct work_struct *work) { struct delayed_work *dwork; struct wl1271 *wl; + int ret; dwork = container_of(work, struct delayed_work, work); wl = container_of(dwork, struct wl1271, pspoll_work); @@ -55,8 +56,13 @@ void wl1271_pspoll_work(struct work_struct *work) * delivery failure occurred, and no-one changed state since, so * we should go back to powersave. */ + ret = wl1271_ps_elp_wakeup(wl); + if (ret < 0) + goto out; + wl1271_ps_set_mode(wl, STATION_POWER_SAVE_MODE, wl->basic_rate, true); + wl1271_ps_elp_sleep(wl); out: mutex_unlock(&wl->mutex); }; @@ -129,11 +135,6 @@ static int wl1271_event_ps_report(struct wl1271 *wl, /* enable beacon early termination */ ret = wl1271_acx_bet_enable(wl, true); - if (ret < 0) - break; - - /* go to extremely low power mode */ - wl1271_ps_elp_sleep(wl); break; default: break; diff --git a/drivers/net/wireless/wl12xx/main.c b/drivers/net/wireless/wl12xx/main.c index 5545c3b..3f6517d 100644 --- a/drivers/net/wireless/wl12xx/main.c +++ b/drivers/net/wireless/wl12xx/main.c @@ -2792,32 +2792,31 @@ static int wl1271_op_conf_tx(struct ieee80211_hw *hw, u16 queue, conf_tid->ack_policy = CONF_ACK_POLICY_LEGACY; conf_tid->apsd_conf[0] = 0; conf_tid->apsd_conf[1] = 0; - } else { - ret = wl1271_ps_elp_wakeup(wl); - if (ret < 0) - goto out; + goto out; + } - /* - * the txop is confed in units of 32us by the mac80211, - * we need us - */ - ret = wl1271_acx_ac_cfg(wl, wl1271_tx_get_queue(queue), - params->cw_min, params->cw_max, - params->aifs, params->txop << 5); - if (ret < 0) - goto out_sleep; + ret = wl1271_ps_elp_wakeup(wl); + if (ret < 0) + goto out; - ret = wl1271_acx_tid_cfg(wl, wl1271_tx_get_queue(queue), - CONF_CHANNEL_TYPE_EDCF, - wl1271_tx_get_queue(queue), - ps_scheme, CONF_ACK_POLICY_LEGACY, - 0, 0); - if (ret < 0) - goto out_sleep; + /* + * the txop is confed in units of 32us by the mac80211, + * we need us + */ + ret = wl1271_acx_ac_cfg(wl, wl1271_tx_get_queue(queue), + params->cw_min, params->cw_max, + params->aifs, params->txop << 5); + if (ret < 0) + goto out_sleep; + + ret = wl1271_acx_tid_cfg(wl, wl1271_tx_get_queue(queue), + CONF_CHANNEL_TYPE_EDCF, + wl1271_tx_get_queue(queue), + ps_scheme, CONF_ACK_POLICY_LEGACY, + 0, 0); out_sleep: - wl1271_ps_elp_sleep(wl); - } + wl1271_ps_elp_sleep(wl); out: mutex_unlock(&wl->mutex); diff --git a/drivers/net/wireless/wl12xx/ps.c b/drivers/net/wireless/wl12xx/ps.c index 971f13e..b8deada 100644 --- a/drivers/net/wireless/wl12xx/ps.c +++ b/drivers/net/wireless/wl12xx/ps.c @@ -149,9 +149,6 @@ int wl1271_ps_set_mode(struct wl1271 *wl, enum wl1271_cmd_ps_mode mode, case STATION_ACTIVE_MODE: default: wl1271_debug(DEBUG_PSM, "leaving psm"); - ret = wl1271_ps_elp_wakeup(wl); - if (ret < 0) - return ret; /* disable beacon early termination */ ret = wl1271_acx_bet_enable(wl, false); diff --git a/drivers/net/wireless/wl12xx/tx.c b/drivers/net/wireless/wl12xx/tx.c index db9e47e..2019ed9 100644 --- a/drivers/net/wireless/wl12xx/tx.c +++ b/drivers/net/wireless/wl12xx/tx.c @@ -511,22 +511,14 @@ static void wl1271_skb_queue_head(struct wl1271 *wl, struct sk_buff *skb) void wl1271_tx_work_locked(struct wl1271 *wl) { struct sk_buff *skb; - bool woken_up = false; u32 buf_offset = 0; bool sent_packets = false; int ret; if (unlikely(wl->state == WL1271_STATE_OFF)) - goto out; + return; while ((skb = wl1271_skb_dequeue(wl))) { - if (!woken_up) { - ret = wl1271_ps_elp_wakeup(wl); - if (ret < 0) - goto out_ack; - woken_up = true; - } - ret = wl1271_prepare_tx_frame(wl, skb, buf_offset); if (ret == -EAGAIN) { /* @@ -573,18 +565,22 @@ out_ack: wl1271_handle_tx_low_watermark(wl); } - -out: - if (woken_up) - wl1271_ps_elp_sleep(wl); } void wl1271_tx_work(struct work_struct *work) { struct wl1271 *wl = container_of(work, struct wl1271, tx_work); + int ret; mutex_lock(&wl->mutex); + ret = wl1271_ps_elp_wakeup(wl); + if (ret < 0) + goto out; + wl1271_tx_work_locked(wl); + + wl1271_ps_elp_wakeup(wl); +out: mutex_unlock(&wl->mutex); } -- cgit v0.10.2 From 13026decf7b74d0908df034dc6dc86c2caaec939 Mon Sep 17 00:00:00 2001 From: Juuso Oikarinen Date: Tue, 29 Mar 2011 16:43:50 +0300 Subject: wl12xx: Handle duplicate calling of remove interface Because of the hardware recovery mechanism, its possible the __wl1271_op_remove_interface is called twice. Currently, this leads to a kernel crash even before a kernel WARNing can be issued. Fix this. Signed-off-by: Juuso Oikarinen Signed-off-by: Luciano Coelho diff --git a/drivers/net/wireless/wl12xx/main.c b/drivers/net/wireless/wl12xx/main.c index 3f6517d..57d0af6 100644 --- a/drivers/net/wireless/wl12xx/main.c +++ b/drivers/net/wireless/wl12xx/main.c @@ -1304,6 +1304,16 @@ static int wl1271_op_add_interface(struct ieee80211_hw *hw, goto out; } + /* + * in some very corner case HW recovery scenarios its possible to + * get here before __wl1271_op_remove_interface is complete, so + * opt out if that is the case. + */ + if (test_bit(WL1271_FLAG_IF_INITIALIZED, &wl->flags)) { + ret = -EBUSY; + goto out; + } + switch (vif->type) { case NL80211_IFTYPE_STATION: wl->bss_type = BSS_TYPE_STA_BSS; @@ -1372,6 +1382,7 @@ power_off: wl->vif = vif; wl->state = WL1271_STATE_ON; + set_bit(WL1271_FLAG_IF_INITIALIZED, &wl->flags); wl1271_info("firmware booted (%s)", wl->chip.fw_ver_str); /* update hw/fw version info in wiphy struct */ @@ -1409,14 +1420,16 @@ static void __wl1271_op_remove_interface(struct wl1271 *wl) wl1271_debug(DEBUG_MAC80211, "mac80211 remove interface"); + /* because of hardware recovery, we may get here twice */ + if (wl->state != WL1271_STATE_ON) + return; + wl1271_info("down"); mutex_lock(&wl_list_mutex); list_del(&wl->list); mutex_unlock(&wl_list_mutex); - WARN_ON(wl->state != WL1271_STATE_ON); - /* enable dyn ps just in case (if left on due to fw crash etc) */ if (wl->bss_type == BSS_TYPE_STA_BSS) ieee80211_enable_dyn_ps(wl->vif); @@ -1428,6 +1441,10 @@ static void __wl1271_op_remove_interface(struct wl1271 *wl) ieee80211_scan_completed(wl->hw, true); } + /* + * this must be before the cancel_work calls below, so that the work + * functions don't perform further work. + */ wl->state = WL1271_STATE_OFF; mutex_unlock(&wl->mutex); @@ -1464,7 +1481,6 @@ static void __wl1271_op_remove_interface(struct wl1271 *wl) wl->time_offset = 0; wl->session_counter = 0; wl->rate_set = CONF_TX_RATE_MASK_BASIC; - wl->flags = 0; wl->vif = NULL; wl->filters = 0; wl1271_free_ap_keys(wl); @@ -1473,6 +1489,13 @@ static void __wl1271_op_remove_interface(struct wl1271 *wl) wl->ap_ps_map = 0; wl->block_size = 0; + /* + * this is performed after the cancel_work calls and the associated + * mutex_lock, so that wl1271_op_add_interface does not accidentally + * get executed before all these vars have been reset. + */ + wl->flags = 0; + for (i = 0; i < NUM_TX_QUEUES; i++) wl->tx_blocks_freed[i] = 0; diff --git a/drivers/net/wireless/wl12xx/wl12xx.h b/drivers/net/wireless/wl12xx/wl12xx.h index ba98e18..c129459 100644 --- a/drivers/net/wireless/wl12xx/wl12xx.h +++ b/drivers/net/wireless/wl12xx/wl12xx.h @@ -354,7 +354,8 @@ enum wl12xx_flags { WL1271_FLAG_PSPOLL_FAILURE, WL1271_FLAG_STA_STATE_SENT, WL1271_FLAG_FW_TX_BUSY, - WL1271_FLAG_AP_STARTED + WL1271_FLAG_AP_STARTED, + WL1271_FLAG_IF_INITIALIZED, }; struct wl1271_link { -- cgit v0.10.2 From c5745187a4812f2991a58e469a866582a7326d91 Mon Sep 17 00:00:00 2001 From: Ohad Ben-Cohen Date: Wed, 30 Mar 2011 16:35:59 +0200 Subject: wl12xx: fix roaming The wl12xx device normally drops all frames coming from BSSID it is not joined with. This behavior is configured today by the wl12xx driver in response to a handful of ieee80211_bss_change and ieee80211_conf_changed notification flags, such as BSS_CHANGED_ASSOC, BSS_CHANGED_BSSID, IEEE80211_CONF_CHANGE_IDLE, etc.. This breaks when we roam to a new BSSID, where authentication frames are sent before any BSS_CHANGED/CONF_CHANGED flags are received. When this happens the hardware silently drops the authentication responses, and the roaming fails. Ideally this aggressive filtering behavior of the device should be disabled upon a notification from mac80211. Such notification will take place after multi-channel support will be added: mac80211 will likely send a remain-on-channel notification to drivers when entering sensitive states (like authentication), otherwise the firmware might jump to different channels (to serve a different role). Until those notifications materialize, disable the hw BSSID filter when authentication requests are sent, so roaming would work. Signed-off-by: Ohad Ben-Cohen Reviewed-by: Luciano Coelho Signed-off-by: Luciano Coelho diff --git a/drivers/net/wireless/wl12xx/io.h b/drivers/net/wireless/wl12xx/io.h index e6199eb..36e1855 100644 --- a/drivers/net/wireless/wl12xx/io.h +++ b/drivers/net/wireless/wl12xx/io.h @@ -171,5 +171,6 @@ int wl1271_free_hw(struct wl1271 *wl); irqreturn_t wl1271_irq(int irq, void *data); bool wl1271_set_block_size(struct wl1271 *wl); int wl1271_tx_dummy_packet(struct wl1271 *wl); +void wl1271_configure_filters(struct wl1271 *wl, unsigned int filters); #endif diff --git a/drivers/net/wireless/wl12xx/main.c b/drivers/net/wireless/wl12xx/main.c index 57d0af6..0efa7a0 100644 --- a/drivers/net/wireless/wl12xx/main.c +++ b/drivers/net/wireless/wl12xx/main.c @@ -1528,7 +1528,7 @@ static void wl1271_op_remove_interface(struct ieee80211_hw *hw, cancel_work_sync(&wl->recovery_work); } -static void wl1271_configure_filters(struct wl1271 *wl, unsigned int filters) +void wl1271_configure_filters(struct wl1271 *wl, unsigned int filters) { wl1271_set_default_filters(wl); @@ -1650,7 +1650,7 @@ static int wl1271_unjoin(struct wl1271 *wl) clear_bit(WL1271_FLAG_JOINED, &wl->flags); memset(wl->bssid, 0, ETH_ALEN); - /* stop filterting packets based on bssid */ + /* stop filtering packets based on bssid */ wl1271_configure_filters(wl, FIF_OTHER_BSS); out: diff --git a/drivers/net/wireless/wl12xx/tx.c b/drivers/net/wireless/wl12xx/tx.c index 2019ed9..7686bc1 100644 --- a/drivers/net/wireless/wl12xx/tx.c +++ b/drivers/net/wireless/wl12xx/tx.c @@ -70,6 +70,28 @@ static void wl1271_free_tx_id(struct wl1271 *wl, int id) } } +static int wl1271_tx_update_filters(struct wl1271 *wl, + struct sk_buff *skb) +{ + struct ieee80211_hdr *hdr; + + hdr = (struct ieee80211_hdr *)(skb->data + + sizeof(struct wl1271_tx_hw_descr)); + + /* + * stop bssid-based filtering before transmitting authentication + * requests. this way the hw will never drop authentication + * responses coming from BSSIDs it isn't familiar with (e.g. on + * roaming) + */ + if (!ieee80211_is_auth(hdr->frame_control)) + return 0; + + wl1271_configure_filters(wl, FIF_OTHER_BSS); + + return wl1271_acx_rx_config(wl, wl->rx_config, wl->rx_filter); +} + static void wl1271_tx_ap_update_inconnection_sta(struct wl1271 *wl, struct sk_buff *skb) { @@ -350,6 +372,8 @@ static int wl1271_prepare_tx_frame(struct wl1271 *wl, struct sk_buff *skb, if (wl->bss_type == BSS_TYPE_AP_BSS) { wl1271_tx_ap_update_inconnection_sta(wl, skb); wl1271_tx_regulate_link(wl, hlid); + } else { + wl1271_tx_update_filters(wl, skb); } wl1271_tx_fill_hdr(wl, skb, extra, info, hlid); -- cgit v0.10.2 From 8bf69aae4cb9b196ba5ac386f83a1ca3865af11f Mon Sep 17 00:00:00 2001 From: Ohad Ben-Cohen Date: Wed, 30 Mar 2011 19:18:31 +0200 Subject: wl12xx: fix "JOIN while associated" commentary Issuing multiple JOIN commands to the wl12xx's firmware, while we're associated, might have undesired implications, so the driver prints a message when that happens, and warn developers who check out the source. Update the commentary in order to consider the one valid scenario where this can happen: roaming. Cautiously keep the message for now, until we either gain confidence there are no unintentional JOIN-while-associated events, or until we move to the new multi-role fw who solves this multiple-join issue for good. Signed-off-by: Ohad Ben-Cohen Signed-off-by: Luciano Coelho diff --git a/drivers/net/wireless/wl12xx/main.c b/drivers/net/wireless/wl12xx/main.c index 0efa7a0..01205ea 100644 --- a/drivers/net/wireless/wl12xx/main.c +++ b/drivers/net/wireless/wl12xx/main.c @@ -1591,10 +1591,10 @@ static int wl1271_join(struct wl1271 *wl, bool set_assoc) * One of the side effects of the JOIN command is that is clears * WPA/WPA2 keys from the chipset. Performing a JOIN while associated * to a WPA/WPA2 access point will therefore kill the data-path. - * Currently there is no supported scenario for JOIN during - * association - if it becomes a supported scenario, the WPA/WPA2 keys - * must be handled somehow. - * + * Currently the only valid scenario for JOIN during association + * is on roaming, in which case we will also be given new keys. + * Keep the below message for now, unless it starts bothering + * users who really like to roam a lot :) */ if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags)) wl1271_info("JOIN while associated."); -- cgit v0.10.2 From d29633b40e6afc6b4276a4e381bc532cc84be104 Mon Sep 17 00:00:00 2001 From: Ido Yariv Date: Thu, 31 Mar 2011 10:06:57 +0200 Subject: wl12xx: Clean up and fix the 128x boot sequence Clean up the boot sequence code & fix the following issues: 1. Always read the registers' values and set the relevant bits instead of zeroing all other bits 2. Handle cases where wl1271_top_reg_read returns an error 3. Verify that the HW can detect the selected clock source 4. Remove 128x PG10 initialization code 5. Configure the MCS PLL to work in HP mode Signed-off-by: Ido Yariv Reviewed-by: Luciano Coelho Signed-off-by: Luciano Coelho diff --git a/drivers/net/wireless/wl12xx/boot.c b/drivers/net/wireless/wl12xx/boot.c index 34bf2fe..b5ec2c2 100644 --- a/drivers/net/wireless/wl12xx/boot.c +++ b/drivers/net/wireless/wl12xx/boot.c @@ -523,137 +523,137 @@ static void wl1271_boot_hw_version(struct wl1271 *wl) wl->quirks |= WL12XX_QUIRK_END_OF_TRANSACTION; } -/* - * WL128x has two clocks input - TCXO and FREF. - * TCXO is the main clock of the device, while FREF is used to sync - * between the GPS and the cellular modem. - * In cases where TCXO is 32.736MHz or 16.368MHz, the FREF will be used - * as the WLAN/BT main clock. - */ -static int wl128x_switch_fref(struct wl1271 *wl, bool *is_ref_clk) +static int wl128x_switch_tcxo_to_fref(struct wl1271 *wl) { - u16 sys_clk_cfg_val; + u16 spare_reg; - /* if working on XTAL-only mode go directly to TCXO TO FREF SWITCH */ - if ((wl->ref_clock == CONF_REF_CLK_38_4_M_XTAL) || - (wl->ref_clock == CONF_REF_CLK_26_M_XTAL)) - return true; + /* Mask bits [2] & [8:4] in the sys_clk_cfg register */ + spare_reg = wl1271_top_reg_read(wl, WL_SPARE_REG); + if (spare_reg == 0xFFFF) + return -EFAULT; + spare_reg |= (BIT(3) | BIT(5) | BIT(6)); + wl1271_top_reg_write(wl, WL_SPARE_REG, spare_reg); - /* Read clock source FREF or TCXO */ - sys_clk_cfg_val = wl1271_top_reg_read(wl, SYS_CLK_CFG_REG); + /* Enable FREF_CLK_REQ & mux MCS and coex PLLs to FREF */ + wl1271_top_reg_write(wl, SYS_CLK_CFG_REG, + WL_CLK_REQ_TYPE_PG2 | MCS_PLL_CLK_SEL_FREF); - if (sys_clk_cfg_val & PRCM_CM_EN_MUX_WLAN_FREF) { - /* if bit 3 is set - working with FREF clock */ - wl1271_debug(DEBUG_BOOT, "working with FREF clock, skip" - " to FREF"); + /* Delay execution for 15msec, to let the HW settle */ + mdelay(15); - *is_ref_clk = true; - } else { - /* if bit 3 is clear - working with TCXO clock */ - wl1271_debug(DEBUG_BOOT, "working with TCXO clock"); - - /* TCXO to FREF switch, check TXCO clock config */ - if ((wl->tcxo_clock != WL12XX_TCXOCLOCK_16_368) && - (wl->tcxo_clock != WL12XX_TCXOCLOCK_32_736)) { - /* - * not 16.368Mhz and not 32.736Mhz - skip to - * configure ELP stage - */ - wl1271_debug(DEBUG_BOOT, "NEW PLL ALGO:" - " TcxoRefClk=%d - not 16.368Mhz and not" - " 32.736Mhz - skip to configure ELP" - " stage", wl->tcxo_clock); - - *is_ref_clk = false; - } else { - wl1271_debug(DEBUG_BOOT, "NEW PLL ALGO:" - "TcxoRefClk=%d - 16.368Mhz or 32.736Mhz" - " - TCXO to FREF switch", - wl->tcxo_clock); + return 0; +} - return true; - } - } +static bool wl128x_is_tcxo_valid(struct wl1271 *wl) +{ + u16 tcxo_detection; + + tcxo_detection = wl1271_top_reg_read(wl, TCXO_CLK_DETECT_REG); + if (tcxo_detection & TCXO_DET_FAILED) + return false; - return false; + return true; } -static int wl128x_boot_clk(struct wl1271 *wl, bool *is_ref_clk) +static bool wl128x_is_fref_valid(struct wl1271 *wl) { - if (wl128x_switch_fref(wl, is_ref_clk)) { - wl1271_debug(DEBUG_BOOT, "XTAL-only mode go directly to" - " TCXO TO FREF SWITCH"); - /* TCXO to FREF switch - for PG2.0 */ - wl1271_top_reg_write(wl, WL_SPARE_REG, - WL_SPARE_MASK_8526); - - wl1271_top_reg_write(wl, SYS_CLK_CFG_REG, - WL_CLK_REQ_TYPE_PG2 | MCS_PLL_CLK_SEL_FREF); - - *is_ref_clk = true; - mdelay(15); - } + u16 fref_detection; - /* Set bit 2 in spare register to avoid illegal access */ - wl1271_top_reg_write(wl, WL_SPARE_REG, WL_SPARE_VAL); + fref_detection = wl1271_top_reg_read(wl, FREF_CLK_DETECT_REG); + if (fref_detection & FREF_CLK_DETECT_FAIL) + return false; - /* working with TCXO clock */ - if ((*is_ref_clk == false) && - ((wl->tcxo_clock == WL12XX_TCXOCLOCK_16_8) || - (wl->tcxo_clock == WL12XX_TCXOCLOCK_33_6))) { - wl1271_debug(DEBUG_BOOT, "16_8_M or 33_6_M TCXO detected"); + return true; +} - /* Manually Configure MCS PLL settings PG2.0 Only */ - wl1271_top_reg_write(wl, MCS_PLL_M_REG, MCS_PLL_M_REG_VAL); - wl1271_top_reg_write(wl, MCS_PLL_N_REG, MCS_PLL_N_REG_VAL); - wl1271_top_reg_write(wl, MCS_PLL_CONFIG_REG, - MCS_PLL_CONFIG_REG_VAL); - } else { - int pll_config; - u16 mcs_pll_config_val; +static int wl128x_manually_configure_mcs_pll(struct wl1271 *wl) +{ + wl1271_top_reg_write(wl, MCS_PLL_M_REG, MCS_PLL_M_REG_VAL); + wl1271_top_reg_write(wl, MCS_PLL_N_REG, MCS_PLL_N_REG_VAL); + wl1271_top_reg_write(wl, MCS_PLL_CONFIG_REG, MCS_PLL_CONFIG_REG_VAL); - /* - * Configure MCS PLL settings to FREF Freq - * Set the values that determine the time elapse since the PLL's - * get their enable signal until the lock indication is set - */ - wl1271_top_reg_write(wl, PLL_LOCK_COUNTERS_REG, - PLL_LOCK_COUNTERS_COEX | PLL_LOCK_COUNTERS_MCS); + return 0; +} - mcs_pll_config_val = wl1271_top_reg_read(wl, - MCS_PLL_CONFIG_REG); - /* - * Set the MCS PLL input frequency value according to the - * reference clock value detected/read - */ - if (*is_ref_clk == false) { - if ((wl->tcxo_clock == WL12XX_TCXOCLOCK_19_2) || - (wl->tcxo_clock == WL12XX_TCXOCLOCK_38_4)) - pll_config = 1; - else if ((wl->tcxo_clock == WL12XX_TCXOCLOCK_26) - || - (wl->tcxo_clock == WL12XX_TCXOCLOCK_52)) - pll_config = 2; - else - return -EINVAL; - } else { - if ((wl->ref_clock == CONF_REF_CLK_19_2_E) || - (wl->ref_clock == CONF_REF_CLK_38_4_E)) - pll_config = 1; - else if ((wl->ref_clock == CONF_REF_CLK_26_E) || - (wl->ref_clock == CONF_REF_CLK_52_E)) - pll_config = 2; - else - return -EINVAL; - } +static int wl128x_configure_mcs_pll(struct wl1271 *wl, int clk) +{ + u16 spare_reg; + u16 pll_config; + u8 input_freq; + + /* Mask bits [3:1] in the sys_clk_cfg register */ + spare_reg = wl1271_top_reg_read(wl, WL_SPARE_REG); + if (spare_reg == 0xFFFF) + return -EFAULT; + spare_reg |= BIT(2); + wl1271_top_reg_write(wl, WL_SPARE_REG, spare_reg); + + /* Handle special cases of the TCXO clock */ + if (wl->tcxo_clock == WL12XX_TCXOCLOCK_16_8 || + wl->tcxo_clock == WL12XX_TCXOCLOCK_33_6) + return wl128x_manually_configure_mcs_pll(wl); + + /* Set the input frequency according to the selected clock source */ + input_freq = (clk & 1) + 1; + + pll_config = wl1271_top_reg_read(wl, MCS_PLL_CONFIG_REG); + if (pll_config == 0xFFFF) + return -EFAULT; + pll_config |= (input_freq << MCS_SEL_IN_FREQ_SHIFT); + pll_config |= MCS_PLL_ENABLE_HP; + wl1271_top_reg_write(wl, MCS_PLL_CONFIG_REG, pll_config); - mcs_pll_config_val |= (pll_config << (MCS_SEL_IN_FREQ_SHIFT)) & - (MCS_SEL_IN_FREQ_MASK); - wl1271_top_reg_write(wl, MCS_PLL_CONFIG_REG, - mcs_pll_config_val); + return 0; +} + +/* + * WL128x has two clocks input - TCXO and FREF. + * TCXO is the main clock of the device, while FREF is used to sync + * between the GPS and the cellular modem. + * In cases where TCXO is 32.736MHz or 16.368MHz, the FREF will be used + * as the WLAN/BT main clock. + */ +static int wl128x_boot_clk(struct wl1271 *wl, int *selected_clock) +{ + u16 sys_clk_cfg; + + /* For XTAL-only modes, FREF will be used after switching from TCXO */ + if (wl->ref_clock == WL12XX_REFCLOCK_26_XTAL || + wl->ref_clock == WL12XX_REFCLOCK_38_XTAL) { + if (!wl128x_switch_tcxo_to_fref(wl)) + return -EINVAL; + goto fref_clk; } - return 0; + /* Query the HW, to determine which clock source we should use */ + sys_clk_cfg = wl1271_top_reg_read(wl, SYS_CLK_CFG_REG); + if (sys_clk_cfg == 0xFFFF) + return -EINVAL; + if (sys_clk_cfg & PRCM_CM_EN_MUX_WLAN_FREF) + goto fref_clk; + + /* If TCXO is either 32.736MHz or 16.368MHz, switch to FREF */ + if (wl->tcxo_clock == WL12XX_TCXOCLOCK_16_368 || + wl->tcxo_clock == WL12XX_TCXOCLOCK_32_736) { + if (!wl128x_switch_tcxo_to_fref(wl)) + return -EINVAL; + goto fref_clk; + } + + /* TCXO clock is selected */ + if (!wl128x_is_tcxo_valid(wl)) + return -EINVAL; + *selected_clock = wl->tcxo_clock; + goto config_mcs_pll; + +fref_clk: + /* FREF clock is selected */ + if (!wl128x_is_fref_valid(wl)) + return -EINVAL; + *selected_clock = wl->ref_clock; + +config_mcs_pll: + return wl128x_configure_mcs_pll(wl, *selected_clock); } static int wl127x_boot_clk(struct wl1271 *wl) @@ -713,10 +713,10 @@ int wl1271_load_firmware(struct wl1271 *wl) { int ret = 0; u32 tmp, clk; - bool is_ref_clk = false; + int selected_clock = -1; if (wl->chip.id == CHIP_ID_1283_PG20) { - ret = wl128x_boot_clk(wl, &is_ref_clk); + ret = wl128x_boot_clk(wl, &selected_clock); if (ret < 0) goto out; } else { @@ -741,10 +741,7 @@ int wl1271_load_firmware(struct wl1271 *wl) wl1271_debug(DEBUG_BOOT, "clk2 0x%x", clk); if (wl->chip.id == CHIP_ID_1283_PG20) { - if (is_ref_clk == false) - clk |= ((wl->tcxo_clock & 0x3) << 1) << 4; - else - clk |= ((wl->ref_clock & 0x3) << 1) << 4; + clk |= ((selected_clock & 0x3) << 1) << 4; } else { clk |= (wl->ref_clock << 1) << 4; } diff --git a/drivers/net/wireless/wl12xx/boot.h b/drivers/net/wireless/wl12xx/boot.h index 1f5ee31..d9de64a 100644 --- a/drivers/net/wireless/wl12xx/boot.h +++ b/drivers/net/wireless/wl12xx/boot.h @@ -107,6 +107,7 @@ struct wl1271_static_data { #define MCS_SEL_IN_FREQ_MASK 0x0070 #define MCS_SEL_IN_FREQ_SHIFT 4 #define MCS_PLL_CONFIG_REG_VAL 0x73 +#define MCS_PLL_ENABLE_HP (BIT(0) | BIT(1)) #define MCS_PLL_M_REG 0xD94 #define MCS_PLL_N_REG 0xD96 diff --git a/include/linux/wl12xx.h b/include/linux/wl12xx.h index eb8aaca..c1a743e 100644 --- a/include/linux/wl12xx.h +++ b/include/linux/wl12xx.h @@ -26,10 +26,12 @@ /* Reference clock values */ enum { - WL12XX_REFCLOCK_19 = 0, /* 19.2 MHz */ - WL12XX_REFCLOCK_26 = 1, /* 26 MHz */ - WL12XX_REFCLOCK_38 = 2, /* 38.4 MHz */ - WL12XX_REFCLOCK_54 = 3, /* 54 MHz */ + WL12XX_REFCLOCK_19 = 0, /* 19.2 MHz */ + WL12XX_REFCLOCK_26 = 1, /* 26 MHz */ + WL12XX_REFCLOCK_38 = 2, /* 38.4 MHz */ + WL12XX_REFCLOCK_52 = 3, /* 52 MHz */ + WL12XX_REFCLOCK_38_XTAL = 4, /* 38.4 MHz, XTAL */ + WL12XX_REFCLOCK_26_XTAL = 5, /* 26 MHz, XTAL */ }; /* TCXO clock values */ -- cgit v0.10.2 From 0da13da767cd568c1fe2a7b5b936e86e521b5ae7 Mon Sep 17 00:00:00 2001 From: Ido Yariv Date: Thu, 31 Mar 2011 10:06:58 +0200 Subject: wl12xx: Clean up the block size alignment code Simplify and clean up the block size alignment code: 1. Set the block size according to the padding field type, as it cannot exceed the maximum value this field can hold. 2. Move the alignment code into a function instead of duplicating it in multiple places. 3. In the current implementation, the block_size member can be misleading because a zero value actually means that there's no need to align. Declare a block size alignment quirk instead. Signed-off-by: Ido Yariv Signed-off-by: Luciano Coelho diff --git a/drivers/net/wireless/wl12xx/init.c b/drivers/net/wireless/wl12xx/init.c index 2dbc083..cf46607 100644 --- a/drivers/net/wireless/wl12xx/init.c +++ b/drivers/net/wireless/wl12xx/init.c @@ -514,7 +514,7 @@ int wl1271_chip_specific_init(struct wl1271 *wl) if (wl->chip.id == CHIP_ID_1283_PG20) { u32 host_cfg_bitmap = HOST_IF_CFG_RX_FIFO_ENABLE; - if (wl1271_set_block_size(wl)) + if (wl->quirks & WL12XX_QUIRK_BLOCKSIZE_ALIGNMENT) /* Enable SDIO padding */ host_cfg_bitmap |= HOST_IF_CFG_TX_PAD_TO_SDIO_BLK; diff --git a/drivers/net/wireless/wl12xx/io.c b/drivers/net/wireless/wl12xx/io.c index aa40c98..da5c1ad 100644 --- a/drivers/net/wireless/wl12xx/io.c +++ b/drivers/net/wireless/wl12xx/io.c @@ -29,6 +29,7 @@ #include "wl12xx.h" #include "wl12xx_80211.h" #include "io.h" +#include "tx.h" #define OCP_CMD_LOOP 32 @@ -46,7 +47,7 @@ bool wl1271_set_block_size(struct wl1271 *wl) { if (wl->if_ops->set_block_size) { - wl->if_ops->set_block_size(wl); + wl->if_ops->set_block_size(wl, WL12XX_BUS_BLOCK_SIZE); return true; } diff --git a/drivers/net/wireless/wl12xx/main.c b/drivers/net/wireless/wl12xx/main.c index 01205ea..1cd3963 100644 --- a/drivers/net/wireless/wl12xx/main.c +++ b/drivers/net/wireless/wl12xx/main.c @@ -1017,6 +1017,8 @@ static int wl1271_chip_wakeup(struct wl1271 *wl) ret = wl1271_setup(wl); if (ret < 0) goto out; + if (wl1271_set_block_size(wl)) + wl->quirks |= WL12XX_QUIRK_BLOCKSIZE_ALIGNMENT; break; case CHIP_ID_1283_PG10: default: @@ -1487,7 +1489,6 @@ static void __wl1271_op_remove_interface(struct wl1271 *wl) memset(wl->ap_hlid_map, 0, sizeof(wl->ap_hlid_map)); wl->ap_fw_ps_map = 0; wl->ap_ps_map = 0; - wl->block_size = 0; /* * this is performed after the cancel_work calls and the associated @@ -3632,7 +3633,6 @@ struct ieee80211_hw *wl1271_alloc_hw(void) wl->ap_ps_map = 0; wl->ap_fw_ps_map = 0; wl->quirks = 0; - wl->block_size = 0; memset(wl->tx_frames_map, 0, sizeof(wl->tx_frames_map)); for (i = 0; i < ACX_TX_DESCRIPTORS; i++) diff --git a/drivers/net/wireless/wl12xx/sdio.c b/drivers/net/wireless/wl12xx/sdio.c index 2ade222..8246e9d 100644 --- a/drivers/net/wireless/wl12xx/sdio.c +++ b/drivers/net/wireless/wl12xx/sdio.c @@ -51,15 +51,10 @@ static const struct sdio_device_id wl1271_devices[] = { }; MODULE_DEVICE_TABLE(sdio, wl1271_devices); -/* The max SDIO block size is 256 when working with tx padding to SDIO block */ -#define TX_PAD_SDIO_BLK_SIZE 256 - -static void wl1271_sdio_set_block_size(struct wl1271 *wl) +static void wl1271_sdio_set_block_size(struct wl1271 *wl, unsigned int blksz) { - wl->block_size = TX_PAD_SDIO_BLK_SIZE; - sdio_claim_host(wl->if_priv); - sdio_set_block_size(wl->if_priv, TX_PAD_SDIO_BLK_SIZE); + sdio_set_block_size(wl->if_priv, blksz); sdio_release_host(wl->if_priv); } @@ -178,9 +173,6 @@ static int wl1271_sdio_power_on(struct wl1271 *wl) sdio_claim_host(func); sdio_enable_func(func); - /* Set the default block size in case it was modified */ - sdio_set_block_size(func, 0); - out: return ret; } diff --git a/drivers/net/wireless/wl12xx/tx.c b/drivers/net/wireless/wl12xx/tx.c index 7686bc1..ba69ba7 100644 --- a/drivers/net/wireless/wl12xx/tx.c +++ b/drivers/net/wireless/wl12xx/tx.c @@ -149,6 +149,15 @@ u8 wl1271_tx_get_hlid(struct sk_buff *skb) } } +static unsigned int wl12xx_calc_packet_alignment(struct wl1271 *wl, + unsigned int packet_length) +{ + if (wl->quirks & WL12XX_QUIRK_BLOCKSIZE_ALIGNMENT) + return ALIGN(packet_length, WL12XX_BUS_BLOCK_SIZE); + else + return ALIGN(packet_length, WL1271_TX_ALIGN_TO); +} + static int wl1271_tx_allocate(struct wl1271 *wl, struct sk_buff *skb, u32 extra, u32 buf_offset, u8 hlid) { @@ -174,10 +183,7 @@ static int wl1271_tx_allocate(struct wl1271 *wl, struct sk_buff *skb, u32 extra, /* approximate the number of blocks required for this packet in the firmware */ - if (wl->block_size) - len = ALIGN(total_len, wl->block_size); - else - len = total_len; + len = wl12xx_calc_packet_alignment(wl, total_len); total_blocks = (len + TX_HW_BLOCK_SIZE - 1) / TX_HW_BLOCK_SIZE + spare_blocks; @@ -291,9 +297,9 @@ static void wl1271_tx_fill_hdr(struct wl1271 *wl, struct sk_buff *skb, tx_attr |= rate_idx << TX_HW_ATTR_OFST_RATE_POLICY; desc->reserved = 0; - if (wl->block_size) { - aligned_len = ALIGN(skb->len, wl->block_size); + aligned_len = wl12xx_calc_packet_alignment(wl, skb->len); + if (wl->chip.id == CHIP_ID_1283_PG20) { desc->wl128x_mem.extra_bytes = aligned_len - skb->len; desc->length = cpu_to_le16(aligned_len >> 2); @@ -306,8 +312,7 @@ static void wl1271_tx_fill_hdr(struct wl1271 *wl, struct sk_buff *skb, } else { int pad; - /* align the length (and store in terms of words) */ - aligned_len = ALIGN(skb->len, WL1271_TX_ALIGN_TO); + /* Store the aligned length in terms of words */ desc->length = cpu_to_le16(aligned_len >> 2); /* calculate number of padding bytes */ @@ -386,10 +391,7 @@ static int wl1271_prepare_tx_frame(struct wl1271 *wl, struct sk_buff *skb, * In special cases, we want to align to a specific block size * (eg. for wl128x with SDIO we align to 256). */ - if (wl->block_size) - total_len = ALIGN(skb->len, wl->block_size); - else - total_len = ALIGN(skb->len, WL1271_TX_ALIGN_TO); + total_len = wl12xx_calc_packet_alignment(wl, skb->len); memcpy(wl->aggr_buf + buf_offset, skb->data, skb->len); memset(wl->aggr_buf + buf_offset + skb->len, 0, total_len - skb->len); diff --git a/drivers/net/wireless/wl12xx/tx.h b/drivers/net/wireless/wl12xx/tx.h index a3877ba..d6b05d9 100644 --- a/drivers/net/wireless/wl12xx/tx.h +++ b/drivers/net/wireless/wl12xx/tx.h @@ -89,6 +89,15 @@ struct wl128x_tx_mem { u8 extra_bytes; } __packed; +/* + * On wl128x based devices, when TX packets are aggregated, each packet + * size must be aligned to the SDIO block size. The maximum block size + * is bounded by the type of the padded bytes field that is sent to the + * FW. Currently the type is u8, so the maximum block size is 256 bytes. + */ +#define WL12XX_BUS_BLOCK_SIZE min(512u, \ + (1u << (8 * sizeof(((struct wl128x_tx_mem *) 0)->extra_bytes)))) + struct wl1271_tx_hw_descr { /* Length of packet in words, including descriptor+header+data */ __le16 length; diff --git a/drivers/net/wireless/wl12xx/wl12xx.h b/drivers/net/wireless/wl12xx/wl12xx.h index c129459..c7c42b6 100644 --- a/drivers/net/wireless/wl12xx/wl12xx.h +++ b/drivers/net/wireless/wl12xx/wl12xx.h @@ -323,7 +323,7 @@ struct wl1271_if_operations { struct device* (*dev)(struct wl1271 *wl); void (*enable_irq)(struct wl1271 *wl); void (*disable_irq)(struct wl1271 *wl); - void (*set_block_size) (struct wl1271 *wl); + void (*set_block_size) (struct wl1271 *wl, unsigned int blksz); }; #define MAX_NUM_KEYS 14 @@ -558,7 +558,6 @@ struct wl1271 { bool ba_support; u8 ba_rx_bitmap; - u32 block_size; int tcxo_clock; /* @@ -610,12 +609,15 @@ int wl1271_plt_stop(struct wl1271 *wl); /* Quirks */ /* Each RX/TX transaction requires an end-of-transaction transfer */ -#define WL12XX_QUIRK_END_OF_TRANSACTION BIT(0) +#define WL12XX_QUIRK_END_OF_TRANSACTION BIT(0) /* * Older firmwares use 2 spare TX blocks * (for STA < 6.1.3.50.58 or for AP < 6.2.0.0.47) */ -#define WL12XX_QUIRK_USE_2_SPARE_BLOCKS BIT(1) +#define WL12XX_QUIRK_USE_2_SPARE_BLOCKS BIT(1) + +/* WL128X requires aggregated packets to be aligned to the SDIO block size */ +#define WL12XX_QUIRK_BLOCKSIZE_ALIGNMENT BIT(2) #endif -- cgit v0.10.2 From 990f5de7384f9e5922e4c7c7572cbf4f29a9441e Mon Sep 17 00:00:00 2001 From: Ido Yariv Date: Thu, 31 Mar 2011 10:06:59 +0200 Subject: wl12xx: Clean up the dummy packet mechanism The current implementation allocates a skb each time one is requested by the firmware. Since dummy packets are handled differently than regular packets, the skb needs to be marked. Currently, this is done by setting the pkt_type member to 5. This might not be safe, as we cannot be sure that there won't be any other packets with this pkt_type value. Since the packet does not change from one request to another, we can simply allocate a dummy packet template and always send it. All changes to the skb done during packet preparation must be reverted, so the same skb can be reused. The dummy packets are not transmitted, therefore there's no need to set the BSSID or our own MAC address. In addition, the header portion of the packet was zeroed by mistake, so fix that as well. Signed-off-by: Ido Yariv Signed-off-by: Luciano Coelho diff --git a/drivers/net/wireless/wl12xx/main.c b/drivers/net/wireless/wl12xx/main.c index 1cd3963..7dce24c 100644 --- a/drivers/net/wireless/wl12xx/main.c +++ b/drivers/net/wireless/wl12xx/main.c @@ -1212,20 +1212,46 @@ static void wl1271_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb) spin_unlock_irqrestore(&wl->wl_lock, flags); } -#define TX_DUMMY_PACKET_SIZE 1400 int wl1271_tx_dummy_packet(struct wl1271 *wl) { - struct sk_buff *skb = NULL; + unsigned long flags; + + spin_lock_irqsave(&wl->wl_lock, flags); + set_bit(WL1271_FLAG_DUMMY_PACKET_PENDING, &wl->flags); + wl->tx_queue_count++; + spin_unlock_irqrestore(&wl->wl_lock, flags); + + /* The FW is low on RX memory blocks, so send the dummy packet asap */ + if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags)) + wl1271_tx_work_locked(wl); + + /* + * If the FW TX is busy, TX work will be scheduled by the threaded + * interrupt handler function + */ + return 0; +} + +/* + * The size of the dummy packet should be at least 1400 bytes. However, in + * order to minimize the number of bus transactions, aligning it to 512 bytes + * boundaries could be beneficial, performance wise + */ +#define TOTAL_TX_DUMMY_PACKET_SIZE (ALIGN(1400, 512)) + +struct sk_buff *wl12xx_alloc_dummy_packet(struct wl1271 *wl) +{ + struct sk_buff *skb; struct ieee80211_hdr_3addr *hdr; - int ret = 0; + unsigned int dummy_packet_size; + + dummy_packet_size = TOTAL_TX_DUMMY_PACKET_SIZE - + sizeof(struct wl1271_tx_hw_descr) - sizeof(*hdr); - skb = dev_alloc_skb( - sizeof(struct wl1271_tx_hw_descr) + sizeof(*hdr) + - TX_DUMMY_PACKET_SIZE); + skb = dev_alloc_skb(TOTAL_TX_DUMMY_PACKET_SIZE); if (!skb) { - wl1271_warning("failed to allocate buffer for dummy packet"); - ret = -ENOMEM; - goto out; + wl1271_warning("Failed to allocate a dummy packet skb"); + return NULL; } skb_reserve(skb, sizeof(struct wl1271_tx_hw_descr)); @@ -1233,29 +1259,22 @@ int wl1271_tx_dummy_packet(struct wl1271 *wl) hdr = (struct ieee80211_hdr_3addr *) skb_put(skb, sizeof(*hdr)); memset(hdr, 0, sizeof(*hdr)); hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_DATA | - IEEE80211_FCTL_TODS | - IEEE80211_STYPE_NULLFUNC); - - memcpy(hdr->addr1, wl->bssid, ETH_ALEN); - memcpy(hdr->addr2, wl->mac_addr, ETH_ALEN); - memcpy(hdr->addr3, wl->bssid, ETH_ALEN); + IEEE80211_STYPE_NULLFUNC | + IEEE80211_FCTL_TODS); - skb_put(skb, TX_DUMMY_PACKET_SIZE); + memset(skb_put(skb, dummy_packet_size), 0, dummy_packet_size); - memset(skb->data, 0, TX_DUMMY_PACKET_SIZE); - - skb->pkt_type = TX_PKT_TYPE_DUMMY_REQ; /* Dummy packets require the TID to be management */ skb->priority = WL1271_TID_MGMT; - /* CONF_TX_AC_VO */ - skb->queue_mapping = 0; - wl1271_op_tx(wl->hw, skb); + /* Initialize all fields that might be used */ + skb->queue_mapping = 0; + memset(IEEE80211_SKB_CB(skb), 0, sizeof(struct ieee80211_tx_info)); -out: - return ret; + return skb; } + static struct notifier_block wl1271_dev_notifier = { .notifier_call = wl1271_dev_notify, }; @@ -3653,11 +3672,17 @@ struct ieee80211_hw *wl1271_alloc_hw(void) goto err_hw; } + wl->dummy_packet = wl12xx_alloc_dummy_packet(wl); + if (!wl->dummy_packet) { + ret = -ENOMEM; + goto err_aggr; + } + /* Register platform device */ ret = platform_device_register(wl->plat_dev); if (ret) { wl1271_error("couldn't register platform device"); - goto err_aggr; + goto err_dummy_packet; } dev_set_drvdata(&wl->plat_dev->dev, wl); @@ -3683,6 +3708,9 @@ err_bt_coex_state: err_platform: platform_device_unregister(wl->plat_dev); +err_dummy_packet: + dev_kfree_skb(wl->dummy_packet); + err_aggr: free_pages((unsigned long)wl->aggr_buf, order); @@ -3702,6 +3730,7 @@ EXPORT_SYMBOL_GPL(wl1271_alloc_hw); int wl1271_free_hw(struct wl1271 *wl) { platform_device_unregister(wl->plat_dev); + dev_kfree_skb(wl->dummy_packet); free_pages((unsigned long)wl->aggr_buf, get_order(WL1271_AGGR_BUFFER_SIZE)); kfree(wl->plat_dev); diff --git a/drivers/net/wireless/wl12xx/tx.c b/drivers/net/wireless/wl12xx/tx.c index ba69ba7..67245ad 100644 --- a/drivers/net/wireless/wl12xx/tx.c +++ b/drivers/net/wireless/wl12xx/tx.c @@ -219,6 +219,11 @@ static int wl1271_tx_allocate(struct wl1271 *wl, struct sk_buff *skb, u32 extra, return ret; } +static bool wl12xx_is_dummy_packet(struct wl1271 *wl, struct sk_buff *skb) +{ + return wl->dummy_packet == skb; +} + static void wl1271_tx_fill_hdr(struct wl1271 *wl, struct sk_buff *skb, u32 extra, struct ieee80211_tx_info *control, u8 hlid) @@ -253,7 +258,7 @@ static void wl1271_tx_fill_hdr(struct wl1271 *wl, struct sk_buff *skb, ac = wl1271_tx_get_queue(skb_get_queue_mapping(skb)); desc->tid = skb->priority; - if (skb->pkt_type == TX_PKT_TYPE_DUMMY_REQ) { + if (wl12xx_is_dummy_packet(wl, skb)) { /* * FW expects the dummy packet to have an invalid session id - * any session id that is different than the one set in the join @@ -396,6 +401,10 @@ static int wl1271_prepare_tx_frame(struct wl1271 *wl, struct sk_buff *skb, memcpy(wl->aggr_buf + buf_offset, skb->data, skb->len); memset(wl->aggr_buf + buf_offset + skb->len, 0, total_len - skb->len); + /* Revert side effects in the dummy packet skb, so it can be reused */ + if (wl12xx_is_dummy_packet(wl, skb)) + skb_pull(skb, sizeof(struct wl1271_tx_hw_descr)); + return total_len; } @@ -508,10 +517,23 @@ out: static struct sk_buff *wl1271_skb_dequeue(struct wl1271 *wl) { + unsigned long flags; + struct sk_buff *skb = NULL; + if (wl->bss_type == BSS_TYPE_AP_BSS) - return wl1271_ap_skb_dequeue(wl); + skb = wl1271_ap_skb_dequeue(wl); + else + skb = wl1271_sta_skb_dequeue(wl); - return wl1271_sta_skb_dequeue(wl); + if (!skb && + test_and_clear_bit(WL1271_FLAG_DUMMY_PACKET_PENDING, &wl->flags)) { + skb = wl->dummy_packet; + spin_lock_irqsave(&wl->wl_lock, flags); + wl->tx_queue_count--; + spin_unlock_irqrestore(&wl->wl_lock, flags); + } + + return skb; } static void wl1271_skb_queue_head(struct wl1271 *wl, struct sk_buff *skb) @@ -519,7 +541,9 @@ static void wl1271_skb_queue_head(struct wl1271 *wl, struct sk_buff *skb) unsigned long flags; int q = wl1271_tx_get_queue(skb_get_queue_mapping(skb)); - if (wl->bss_type == BSS_TYPE_AP_BSS) { + if (wl12xx_is_dummy_packet(wl, skb)) { + set_bit(WL1271_FLAG_DUMMY_PACKET_PENDING, &wl->flags); + } else if (wl->bss_type == BSS_TYPE_AP_BSS) { u8 hlid = wl1271_tx_get_hlid(skb); skb_queue_head(&wl->links[hlid].tx_queue[q], skb); @@ -628,8 +652,7 @@ static void wl1271_tx_complete_packet(struct wl1271 *wl, skb = wl->tx_frames[id]; info = IEEE80211_SKB_CB(skb); - if (skb->pkt_type == TX_PKT_TYPE_DUMMY_REQ) { - dev_kfree_skb(skb); + if (wl12xx_is_dummy_packet(wl, skb)) { wl1271_free_tx_id(wl, id); return; } @@ -764,9 +787,7 @@ void wl1271_tx_reset(struct wl1271 *wl) wl1271_debug(DEBUG_TX, "freeing skb 0x%p", skb); - if (skb->pkt_type == TX_PKT_TYPE_DUMMY_REQ) { - dev_kfree_skb(skb); - } else { + if (!wl12xx_is_dummy_packet(wl, skb)) { info = IEEE80211_SKB_CB(skb); info->status.rates[0].idx = -1; info->status.rates[0].count = 0; @@ -792,9 +813,7 @@ void wl1271_tx_reset(struct wl1271 *wl) wl1271_free_tx_id(wl, i); wl1271_debug(DEBUG_TX, "freeing skb 0x%p", skb); - if (skb->pkt_type == TX_PKT_TYPE_DUMMY_REQ) { - dev_kfree_skb(skb); - } else { + if (!wl12xx_is_dummy_packet(wl, skb)) { /* * Remove private headers before passing the skb to * mac80211 diff --git a/drivers/net/wireless/wl12xx/tx.h b/drivers/net/wireless/wl12xx/tx.h index d6b05d9..fc7835c 100644 --- a/drivers/net/wireless/wl12xx/tx.h +++ b/drivers/net/wireless/wl12xx/tx.h @@ -42,8 +42,6 @@ #define TX_HW_ATTR_TX_CMPLT_REQ BIT(12) #define TX_HW_ATTR_TX_DUMMY_REQ BIT(13) -#define TX_PKT_TYPE_DUMMY_REQ 5 - #define TX_HW_ATTR_OFST_SAVE_RETRIES 0 #define TX_HW_ATTR_OFST_HEADER_PAD 1 #define TX_HW_ATTR_OFST_SESSION_COUNTER 2 diff --git a/drivers/net/wireless/wl12xx/wl12xx.h b/drivers/net/wireless/wl12xx/wl12xx.h index c7c42b6..1b430d2 100644 --- a/drivers/net/wireless/wl12xx/wl12xx.h +++ b/drivers/net/wireless/wl12xx/wl12xx.h @@ -356,6 +356,7 @@ enum wl12xx_flags { WL1271_FLAG_FW_TX_BUSY, WL1271_FLAG_AP_STARTED, WL1271_FLAG_IF_INITIALIZED, + WL1271_FLAG_DUMMY_PACKET_PENDING, }; struct wl1271_link { @@ -461,6 +462,9 @@ struct wl1271 { /* Intermediate buffer, used for packet aggregation */ u8 *aggr_buf; + /* Reusable dummy packet template */ + struct sk_buff *dummy_packet; + /* Network stack work */ struct work_struct netstack_work; -- cgit v0.10.2 From d2f4d47d84f8c665ab9babb2cc84d2e7872a96e1 Mon Sep 17 00:00:00 2001 From: Ido Yariv Date: Thu, 31 Mar 2011 10:07:00 +0200 Subject: wl12xx: Simplify TX blocks accounting The total number of TX memory blocks may change when the dynamic memory option is enabled. The current implementation only tracks the available memory blocks, which over-complicates TX blocks accounting. By tracking the number of allocated blocks, calculation of the number of available blocks becomes simpler and cleaner. It simply equals the total number of TX memory blocks minus the allocated ones. Also, remove some unnecessary castings and use union member accesses instead. Signed-off-by: Ido Yariv Signed-off-by: Arik Nemtsov Signed-off-by: Luciano Coelho diff --git a/drivers/net/wireless/wl12xx/acx.c b/drivers/net/wireless/wl12xx/acx.c index e005aa4..b277947 100644 --- a/drivers/net/wireless/wl12xx/acx.c +++ b/drivers/net/wireless/wl12xx/acx.c @@ -1081,8 +1081,6 @@ int wl1271_acx_init_mem_config(struct wl1271 *wl) wl1271_debug(DEBUG_TX, "available tx blocks: %d", wl->tx_blocks_available); - wl->tx_new_total = wl->tx_blocks_available; - return 0; } diff --git a/drivers/net/wireless/wl12xx/main.c b/drivers/net/wireless/wl12xx/main.c index 7dce24c..1feb955 100644 --- a/drivers/net/wireless/wl12xx/main.c +++ b/drivers/net/wireless/wl12xx/main.c @@ -622,7 +622,7 @@ static void wl1271_fw_status(struct wl1271 *wl, struct wl1271_fw_common_status *status = &full_status->common; struct timespec ts; u32 old_tx_blk_count = wl->tx_blocks_available; - u32 total = 0; + u32 freed_blocks = 0; int i; if (wl->bss_type == BSS_TYPE_AP_BSS) { @@ -631,15 +631,6 @@ static void wl1271_fw_status(struct wl1271 *wl, } else { wl1271_raw_read(wl, FW_STATUS_ADDR, status, sizeof(struct wl1271_fw_sta_status), false); - - /* Update tx total blocks change */ - wl->tx_total_diff += - ((struct wl1271_fw_sta_status *)status)->tx_total - - wl->tx_new_total; - - /* Update total tx blocks */ - wl->tx_new_total = - ((struct wl1271_fw_sta_status *)status)->tx_total; } wl1271_debug(DEBUG_IRQ, "intr: 0x%x (fw_rx_counter = %d, " @@ -651,34 +642,38 @@ static void wl1271_fw_status(struct wl1271 *wl, /* update number of available TX blocks */ for (i = 0; i < NUM_TX_QUEUES; i++) { - total += le32_to_cpu(status->tx_released_blks[i]) - - wl->tx_blocks_freed[i]; + freed_blocks += le32_to_cpu(status->tx_released_blks[i]) - + wl->tx_blocks_freed[i]; wl->tx_blocks_freed[i] = le32_to_cpu(status->tx_released_blks[i]); - } - /* - * By adding the freed blocks to tx_total_diff we are actually - * moving them to the RX pool. - */ - wl->tx_total_diff += total; + wl->tx_allocated_blocks -= freed_blocks; + + if (wl->bss_type == BSS_TYPE_AP_BSS) { + /* Update num of allocated TX blocks per link and ps status */ + wl1271_irq_update_links_status(wl, &full_status->ap); + wl->tx_blocks_available += freed_blocks; + } else { + int avail = full_status->sta.tx_total - wl->tx_allocated_blocks; - /* if we have positive difference, add the blocks to the TX pool */ - if (wl->tx_total_diff >= 0) { - wl->tx_blocks_available += wl->tx_total_diff; - wl->tx_total_diff = 0; + /* + * The FW might change the total number of TX memblocks before + * we get a notification about blocks being released. Thus, the + * available blocks calculation might yield a temporary result + * which is lower than the actual available blocks. Keeping in + * mind that only blocks that were allocated can be moved from + * TX to RX, tx_blocks_available should never decrease here. + */ + wl->tx_blocks_available = max((int)wl->tx_blocks_available, + avail); } /* if more blocks are available now, tx work can be scheduled */ if (wl->tx_blocks_available > old_tx_blk_count) clear_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags); - /* for AP update num of allocated TX blocks per link and ps status */ - if (wl->bss_type == BSS_TYPE_AP_BSS) - wl1271_irq_update_links_status(wl, &full_status->ap); - /* update the host-chipset time offset */ getnstimeofday(&ts); wl->time_offset = (timespec_to_ns(&ts) >> 10) - @@ -1495,6 +1490,7 @@ static void __wl1271_op_remove_interface(struct wl1271 *wl) wl->psm_entry_retry = 0; wl->power_level = WL1271_DEFAULT_POWER_LEVEL; wl->tx_blocks_available = 0; + wl->tx_allocated_blocks = 0; wl->tx_results_count = 0; wl->tx_packets_count = 0; wl->tx_security_last_seq = 0; diff --git a/drivers/net/wireless/wl12xx/tx.c b/drivers/net/wireless/wl12xx/tx.c index 67245ad..7a3339f 100644 --- a/drivers/net/wireless/wl12xx/tx.c +++ b/drivers/net/wireless/wl12xx/tx.c @@ -203,6 +203,7 @@ static int wl1271_tx_allocate(struct wl1271 *wl, struct sk_buff *skb, u32 extra, desc->id = id; wl->tx_blocks_available -= total_blocks; + wl->tx_allocated_blocks += total_blocks; if (wl->bss_type == BSS_TYPE_AP_BSS) wl->links[hlid].allocated_blks += total_blocks; diff --git a/drivers/net/wireless/wl12xx/wl12xx.h b/drivers/net/wireless/wl12xx/wl12xx.h index 1b430d2..9ccbcfd 100644 --- a/drivers/net/wireless/wl12xx/wl12xx.h +++ b/drivers/net/wireless/wl12xx/wl12xx.h @@ -418,10 +418,8 @@ struct wl1271 { /* Accounting for allocated / available TX blocks on HW */ u32 tx_blocks_freed[NUM_TX_QUEUES]; u32 tx_blocks_available; + u32 tx_allocated_blocks; u32 tx_results_count; - /* Indicates how many memory blocks should be moved to the RX pool */ - int tx_total_diff; - u32 tx_new_total; /* Transmitted TX packets counter for chipset interface */ u32 tx_packets_count; -- cgit v0.10.2 From 341b7cde6ccc60672fcd7fc84dd24a1b7c0b8d94 Mon Sep 17 00:00:00 2001 From: Ido Yariv Date: Thu, 31 Mar 2011 10:07:01 +0200 Subject: wl12xx: Handle platforms without level trigger interrupts Some platforms are incapable of triggering on level interrupts. Add a platform quirks member in the platform data structure, as well as an edge interrupt quirk which can be set on such platforms. When the interrupt is requested with IRQF_TRIGGER_RISING, IRQF_ONESHOT cannot be used, as we might miss interrupts that occur after the FW status is cleared and before the threaded interrupt handler exits. Moreover, when IRQF_ONESHOT is not set, iterating more than once in the threaded interrupt handler introduces a few race conditions between this handler and the hardirq handler. Currently this is worked around by limiting the loop to one iteration only. This workaround has an impact on performance. To remove to this restriction, the race conditions will need to be addressed. Signed-off-by: Ido Yariv Signed-off-by: Luciano Coelho diff --git a/drivers/net/wireless/wl12xx/main.c b/drivers/net/wireless/wl12xx/main.c index 1feb955..7126506 100644 --- a/drivers/net/wireless/wl12xx/main.c +++ b/drivers/net/wireless/wl12xx/main.c @@ -30,6 +30,7 @@ #include #include #include +#include #include "wl12xx.h" #include "wl12xx_80211.h" @@ -719,6 +720,13 @@ irqreturn_t wl1271_irq(int irq, void *cookie) set_bit(WL1271_FLAG_TX_PENDING, &wl->flags); cancel_work_sync(&wl->tx_work); + /* + * In case edge triggered interrupt must be used, we cannot iterate + * more than once without introducing race conditions with the hardirq. + */ + if (wl->platform_quirks & WL12XX_PLATFORM_QUIRK_EDGE_IRQ) + loopcount = 1; + mutex_lock(&wl->mutex); wl1271_debug(DEBUG_IRQ, "IRQ work"); @@ -3648,6 +3656,7 @@ struct ieee80211_hw *wl1271_alloc_hw(void) wl->ap_ps_map = 0; wl->ap_fw_ps_map = 0; wl->quirks = 0; + wl->platform_quirks = 0; memset(wl->tx_frames_map, 0, sizeof(wl->tx_frames_map)); for (i = 0; i < ACX_TX_DESCRIPTORS; i++) diff --git a/drivers/net/wireless/wl12xx/sdio.c b/drivers/net/wireless/wl12xx/sdio.c index 8246e9d..bcd4ad7 100644 --- a/drivers/net/wireless/wl12xx/sdio.c +++ b/drivers/net/wireless/wl12xx/sdio.c @@ -220,6 +220,7 @@ static int __devinit wl1271_probe(struct sdio_func *func, struct ieee80211_hw *hw; const struct wl12xx_platform_data *wlan_data; struct wl1271 *wl; + unsigned long irqflags; int ret; /* We are only able to handle the wlan function */ @@ -251,9 +252,15 @@ static int __devinit wl1271_probe(struct sdio_func *func, wl->irq = wlan_data->irq; wl->ref_clock = wlan_data->board_ref_clock; wl->tcxo_clock = wlan_data->board_tcxo_clock; + wl->platform_quirks = wlan_data->platform_quirks; + + if (wl->platform_quirks & WL12XX_PLATFORM_QUIRK_EDGE_IRQ) + irqflags = IRQF_TRIGGER_RISING; + else + irqflags = IRQF_TRIGGER_HIGH | IRQF_ONESHOT; ret = request_threaded_irq(wl->irq, wl1271_hardirq, wl1271_irq, - IRQF_TRIGGER_HIGH | IRQF_ONESHOT, + irqflags, DRIVER_NAME, wl); if (ret < 0) { wl1271_error("request_irq() failed: %d", ret); diff --git a/drivers/net/wireless/wl12xx/spi.c b/drivers/net/wireless/wl12xx/spi.c index 7b82b5f..51662bb 100644 --- a/drivers/net/wireless/wl12xx/spi.c +++ b/drivers/net/wireless/wl12xx/spi.c @@ -364,6 +364,7 @@ static int __devinit wl1271_probe(struct spi_device *spi) struct wl12xx_platform_data *pdata; struct ieee80211_hw *hw; struct wl1271 *wl; + unsigned long irqflags; int ret; pdata = spi->dev.platform_data; @@ -402,6 +403,12 @@ static int __devinit wl1271_probe(struct spi_device *spi) wl->ref_clock = pdata->board_ref_clock; wl->tcxo_clock = pdata->board_tcxo_clock; + wl->platform_quirks = pdata->platform_quirks; + + if (wl->platform_quirks & WL12XX_PLATFORM_QUIRK_EDGE_IRQ) + irqflags = IRQF_TRIGGER_RISING; + else + irqflags = IRQF_TRIGGER_HIGH | IRQF_ONESHOT; wl->irq = spi->irq; if (wl->irq < 0) { @@ -411,7 +418,7 @@ static int __devinit wl1271_probe(struct spi_device *spi) } ret = request_threaded_irq(wl->irq, wl1271_hardirq, wl1271_irq, - IRQF_TRIGGER_HIGH | IRQF_ONESHOT, + irqflags, DRIVER_NAME, wl); if (ret < 0) { wl1271_error("request_irq() failed: %d", ret); diff --git a/drivers/net/wireless/wl12xx/wl12xx.h b/drivers/net/wireless/wl12xx/wl12xx.h index 9ccbcfd..fb2b79f 100644 --- a/drivers/net/wireless/wl12xx/wl12xx.h +++ b/drivers/net/wireless/wl12xx/wl12xx.h @@ -579,6 +579,9 @@ struct wl1271 { /* Quirks of specific hardware revisions */ unsigned int quirks; + + /* Platform limitations */ + unsigned int platform_quirks; }; struct wl1271_station { diff --git a/include/linux/wl12xx.h b/include/linux/wl12xx.h index c1a743e..4b69739 100644 --- a/include/linux/wl12xx.h +++ b/include/linux/wl12xx.h @@ -53,8 +53,12 @@ struct wl12xx_platform_data { bool use_eeprom; int board_ref_clock; int board_tcxo_clock; + unsigned long platform_quirks; }; +/* Platform does not support level trigger interrupts */ +#define WL12XX_PLATFORM_QUIRK_EDGE_IRQ BIT(0) + #ifdef CONFIG_WL12XX_PLATFORM_DATA int wl12xx_set_platform_data(const struct wl12xx_platform_data *data); -- cgit v0.10.2 From 6277ed65704d19377b0874618e5f23d64c9e71a6 Mon Sep 17 00:00:00 2001 From: Luciano Coelho Date: Fri, 1 Apr 2011 17:49:54 +0300 Subject: wl12xx: use kstrtoul functions Use the new kstrtoul functions instead of the deprecated strict_strtoul(). Signed-off-by: Luciano Coelho diff --git a/drivers/net/wireless/wl12xx/debugfs.c b/drivers/net/wireless/wl12xx/debugfs.c index 8e75b09..70ab198 100644 --- a/drivers/net/wireless/wl12xx/debugfs.c +++ b/drivers/net/wireless/wl12xx/debugfs.c @@ -267,7 +267,7 @@ static ssize_t gpio_power_write(struct file *file, } buf[len] = '\0'; - ret = strict_strtoul(buf, 0, &value); + ret = kstrtoul(buf, 0, &value); if (ret < 0) { wl1271_warning("illegal value in gpio_power"); return -EINVAL; diff --git a/drivers/net/wireless/wl12xx/main.c b/drivers/net/wireless/wl12xx/main.c index 7126506..a5a5d01 100644 --- a/drivers/net/wireless/wl12xx/main.c +++ b/drivers/net/wireless/wl12xx/main.c @@ -3397,8 +3397,7 @@ static ssize_t wl1271_sysfs_store_bt_coex_state(struct device *dev, unsigned long res; int ret; - ret = strict_strtoul(buf, 10, &res); - + ret = kstrtoul(buf, 10, &res); if (ret < 0) { wl1271_warning("incorrect value written to bt_coex_mode"); return count; -- cgit v0.10.2 From afb7d3cd805df7a206439a7e7b5d1167d2bb06f6 Mon Sep 17 00:00:00 2001 From: Luciano Coelho Date: Fri, 1 Apr 2011 20:48:02 +0300 Subject: wl12xx: move hardcoded hci_io_ds value into the conf struct Instead of hardcoding the hci_io_ds configuration that we write to the SDIO_IO_DS top registed, read it from the default configuration so that it's easier to change for different platforms. Reported-by: Ido Yariv Signed-off-by: Luciano Coelho diff --git a/drivers/net/wireless/wl12xx/boot.c b/drivers/net/wireless/wl12xx/boot.c index b5ec2c2..2b0cf85 100644 --- a/drivers/net/wireless/wl12xx/boot.c +++ b/drivers/net/wireless/wl12xx/boot.c @@ -779,7 +779,7 @@ int wl1271_load_firmware(struct wl1271 *wl) * to upload_fw) */ if (wl->chip.id == CHIP_ID_1283_PG20) - wl1271_top_reg_write(wl, SDIO_IO_DS, HCI_IO_DS_6MA); + wl1271_top_reg_write(wl, SDIO_IO_DS, wl->conf.hci_io_ds); ret = wl1271_boot_upload_firmware(wl); if (ret < 0) diff --git a/drivers/net/wireless/wl12xx/boot.h b/drivers/net/wireless/wl12xx/boot.h index d9de64a..e8f8255 100644 --- a/drivers/net/wireless/wl12xx/boot.h +++ b/drivers/net/wireless/wl12xx/boot.h @@ -117,10 +117,13 @@ struct wl1271_static_data { #define SDIO_IO_DS 0xd14 /* SDIO/wSPI DS configuration values */ -#define HCI_IO_DS_8MA 0 -#define HCI_IO_DS_4MA 1 /* default */ -#define HCI_IO_DS_6MA 2 -#define HCI_IO_DS_2MA 3 +enum { + HCI_IO_DS_8MA = 0, + HCI_IO_DS_4MA = 1, /* default */ + HCI_IO_DS_6MA = 2, + HCI_IO_DS_2MA = 3, +}; + /* end PLL configuration algorithm for wl128x */ #endif diff --git a/drivers/net/wireless/wl12xx/conf.h b/drivers/net/wireless/wl12xx/conf.h index 743bd0b..52269d4 100644 --- a/drivers/net/wireless/wl12xx/conf.h +++ b/drivers/net/wireless/wl12xx/conf.h @@ -1206,6 +1206,7 @@ struct conf_drv_settings { struct conf_ht_setting ht; struct conf_memory_settings mem_wl127x; struct conf_memory_settings mem_wl128x; + u8 hci_io_ds; }; #endif diff --git a/drivers/net/wireless/wl12xx/main.c b/drivers/net/wireless/wl12xx/main.c index a5a5d01..732fd21 100644 --- a/drivers/net/wireless/wl12xx/main.c +++ b/drivers/net/wireless/wl12xx/main.c @@ -319,6 +319,7 @@ static struct conf_drv_settings default_conf = { .min_req_rx_blocks = 22, .tx_min = 27, }, + .hci_io_ds = HCI_IO_DS_6MA, }; static void __wl1271_op_remove_interface(struct wl1271 *wl); -- cgit v0.10.2 From 4ec23d6e136c890806f0e00bcf24e2e3a242b30a Mon Sep 17 00:00:00 2001 From: Luciano Coelho Date: Fri, 1 Apr 2011 20:55:01 +0300 Subject: wl12xx: remove unused conf_radio_params structure This structure has not been used anymore since commit e6b190ff3c2f4e4859502c41fa17b5c595e82000. Signed-off-by: Luciano Coelho diff --git a/drivers/net/wireless/wl12xx/conf.h b/drivers/net/wireless/wl12xx/conf.h index 52269d4..6c9e3a6 100644 --- a/drivers/net/wireless/wl12xx/conf.h +++ b/drivers/net/wireless/wl12xx/conf.h @@ -1020,15 +1020,6 @@ enum single_dual_band_enum { #define CONF_NUMBER_OF_CHANNELS_2_4 14 #define CONF_NUMBER_OF_CHANNELS_5 35 -struct conf_radio_parms { - /* - * FEM parameter set to use - * - * Range: 0 or 1 - */ - u8 fem; -}; - struct conf_itrim_settings { /* enable dco itrim */ u8 enable; -- cgit v0.10.2 From cf27d8677515441602f5e4e40f90448e964504b8 Mon Sep 17 00:00:00 2001 From: Luciano Coelho Date: Fri, 1 Apr 2011 21:08:23 +0300 Subject: wl12xx: fix sparse warning about undeclared wl12xx_alloc_dummy_packet Fix sparse warning: CHECK drivers/net/wireless/wl12xx/main.c drivers/net/wireless/wl12xx/main.c:1246:17: warning: symbol 'wl12xx_alloc_dummy_packet' was not declared. Should it be static? Signed-off-by: Luciano Coelho diff --git a/drivers/net/wireless/wl12xx/main.c b/drivers/net/wireless/wl12xx/main.c index 732fd21..866453b 100644 --- a/drivers/net/wireless/wl12xx/main.c +++ b/drivers/net/wireless/wl12xx/main.c @@ -1243,7 +1243,7 @@ int wl1271_tx_dummy_packet(struct wl1271 *wl) */ #define TOTAL_TX_DUMMY_PACKET_SIZE (ALIGN(1400, 512)) -struct sk_buff *wl12xx_alloc_dummy_packet(struct wl1271 *wl) +static struct sk_buff *wl12xx_alloc_dummy_packet(struct wl1271 *wl) { struct sk_buff *skb; struct ieee80211_hdr_3addr *hdr; -- cgit v0.10.2 From a8a8a0937e22a5fd55aeb22586724ba6bb70aadd Mon Sep 17 00:00:00 2001 From: Jozsef Kadlecsik Date: Tue, 19 Apr 2011 15:59:15 +0200 Subject: netfilter: ipset: Fix the order of listing of sets A restoreable saving of sets requires that list:set type of sets come last and the code part which should have taken into account the ordering was broken. The patch fixes the listing order. Signed-off-by: Jozsef Kadlecsik Signed-off-by: Patrick McHardy diff --git a/net/netfilter/ipset/ip_set_core.c b/net/netfilter/ipset/ip_set_core.c index e88ac3c..d87e03b 100644 --- a/net/netfilter/ipset/ip_set_core.c +++ b/net/netfilter/ipset/ip_set_core.c @@ -1022,8 +1022,9 @@ ip_set_dump_start(struct sk_buff *skb, struct netlink_callback *cb) if (cb->args[1] >= ip_set_max) goto out; - pr_debug("args[0]: %ld args[1]: %ld\n", cb->args[0], cb->args[1]); max = cb->args[0] == DUMP_ONE ? cb->args[1] + 1 : ip_set_max; +dump_last: + pr_debug("args[0]: %ld args[1]: %ld\n", cb->args[0], cb->args[1]); for (; cb->args[1] < max; cb->args[1]++) { index = (ip_set_id_t) cb->args[1]; set = ip_set_list[index]; @@ -1038,8 +1039,8 @@ ip_set_dump_start(struct sk_buff *skb, struct netlink_callback *cb) * so that lists (unions of sets) are dumped last. */ if (cb->args[0] != DUMP_ONE && - !((cb->args[0] == DUMP_ALL) ^ - (set->type->features & IPSET_DUMP_LAST))) + ((cb->args[0] == DUMP_ALL) == + !!(set->type->features & IPSET_DUMP_LAST))) continue; pr_debug("List set: %s\n", set->name); if (!cb->args[2]) { @@ -1083,6 +1084,12 @@ ip_set_dump_start(struct sk_buff *skb, struct netlink_callback *cb) goto release_refcount; } } + /* If we dump all sets, continue with dumping last ones */ + if (cb->args[0] == DUMP_ALL) { + cb->args[0] = DUMP_LAST; + cb->args[1] = 0; + goto dump_last; + } goto out; nla_put_failure: @@ -1093,11 +1100,6 @@ release_refcount: pr_debug("release set %s\n", ip_set_list[index]->name); ip_set_put_byindex(index); } - - /* If we dump all sets, continue with dumping last ones */ - if (cb->args[0] == DUMP_ALL && cb->args[1] >= max && !cb->args[2]) - cb->args[0] = DUMP_LAST; - out: if (nlh) { nlmsg_end(skb, nlh); -- cgit v0.10.2 From 0817a6a3a4fc7c069111083351ca33a78da2a0c9 Mon Sep 17 00:00:00 2001 From: Arun Sharma Date: Thu, 14 Apr 2011 10:38:18 -0700 Subject: perf script: Add support for PERF_TYPE_RAW Useful for getting stack traces for hardware events not handled by PERF_TYPE_HARDWARE. Cc: Frederic Weisbecker Cc: Ingo Molnar Cc: Mike Galbraith Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Stephane Eranian Cc: Thomas Gleixner Cc: Tom Zanussi Signed-off-by: Arun Sharma Link: http://lkml.kernel.org/n/tip-qimdcdpekjqxuyqovy4kjusx@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo diff --git a/tools/perf/builtin-script.c b/tools/perf/builtin-script.c index 6cf811a..b3012c4 100644 --- a/tools/perf/builtin-script.c +++ b/tools/perf/builtin-script.c @@ -82,6 +82,16 @@ static struct { PERF_OUTPUT_CPU | PERF_OUTPUT_TIME | PERF_OUTPUT_EVNAME | PERF_OUTPUT_TRACE, }, + + [PERF_TYPE_RAW] = { + .user_set = false, + + .fields = PERF_OUTPUT_COMM | PERF_OUTPUT_TID | + PERF_OUTPUT_CPU | PERF_OUTPUT_TIME | + PERF_OUTPUT_EVNAME | PERF_OUTPUT_SYM, + + .invalid_fields = PERF_OUTPUT_TRACE, + }, }; static bool output_set_by_user(void) @@ -502,6 +512,8 @@ static int parse_output_fields(const struct option *opt __used, type = PERF_TYPE_SOFTWARE; else if (!strcmp(str, "trace")) type = PERF_TYPE_TRACEPOINT; + else if (!strcmp(str, "raw")) + type = PERF_TYPE_RAW; else { fprintf(stderr, "Invalid event type in field string.\n"); return -EINVAL; @@ -902,7 +914,7 @@ static const struct option options[] = { OPT_STRING(0, "symfs", &symbol_conf.symfs, "directory", "Look for files with symbols relative to this directory"), OPT_CALLBACK('f', "fields", NULL, "str", - "comma separated output fields prepend with 'type:'. Valid types: hw,sw,trace. Fields: comm,tid,pid,time,cpu,event,trace,sym", + "comma separated output fields prepend with 'type:'. Valid types: hw,sw,trace,raw. Fields: comm,tid,pid,time,cpu,event,trace,sym", parse_output_fields), OPT_END() -- cgit v0.10.2 From d924de09cac6e18bdfbe9461a2ab2adeb36e77b0 Mon Sep 17 00:00:00 2001 From: Michael Jones Date: Tue, 29 Mar 2011 05:19:06 -0300 Subject: [media] v4l: add V4L2_PIX_FMT_Y12 format Y12 is a grey-scale format with a depth of 12 bits per pixel stored in 16-bit words. Signed-off-by: Michael Jones Acked-by: Laurent Pinchart Signed-off-by: Mauro Carvalho Chehab diff --git a/Documentation/DocBook/media-entities.tmpl b/Documentation/DocBook/media-entities.tmpl index 5d259c6..fea63b4 100644 --- a/Documentation/DocBook/media-entities.tmpl +++ b/Documentation/DocBook/media-entities.tmpl @@ -294,6 +294,7 @@ + diff --git a/Documentation/DocBook/v4l/pixfmt-y12.xml b/Documentation/DocBook/v4l/pixfmt-y12.xml new file mode 100644 index 0000000..ff417b8 --- /dev/null +++ b/Documentation/DocBook/v4l/pixfmt-y12.xml @@ -0,0 +1,79 @@ + + + V4L2_PIX_FMT_Y12 ('Y12 ') + &manvol; + + + V4L2_PIX_FMT_Y12 + Grey-scale image + + + Description + + This is a grey-scale image with a depth of 12 bits per pixel. Pixels +are stored in 16-bit words with unused high bits padded with 0. The least +significant byte is stored at lower memory addresses (little-endian). + + + <constant>V4L2_PIX_FMT_Y12</constant> 4 × 4 +pixel image + + + Byte Order. + Each cell is one byte. + + + + + + start + 0: + Y'00low + Y'00high + Y'01low + Y'01high + Y'02low + Y'02high + Y'03low + Y'03high + + + start + 8: + Y'10low + Y'10high + Y'11low + Y'11high + Y'12low + Y'12high + Y'13low + Y'13high + + + start + 16: + Y'20low + Y'20high + Y'21low + Y'21high + Y'22low + Y'22high + Y'23low + Y'23high + + + start + 24: + Y'30low + Y'30high + Y'31low + Y'31high + Y'32low + Y'32high + Y'33low + Y'33high + + + + + + + + + diff --git a/Documentation/DocBook/v4l/pixfmt.xml b/Documentation/DocBook/v4l/pixfmt.xml index c6fdcbb..40af4be 100644 --- a/Documentation/DocBook/v4l/pixfmt.xml +++ b/Documentation/DocBook/v4l/pixfmt.xml @@ -696,6 +696,7 @@ information. &sub-packed-yuv; &sub-grey; &sub-y10; + &sub-y12; &sub-y16; &sub-yuyv; &sub-uyvy; diff --git a/include/linux/videodev2.h b/include/linux/videodev2.h index aa6c393..be82c8e 100644 --- a/include/linux/videodev2.h +++ b/include/linux/videodev2.h @@ -308,6 +308,7 @@ struct v4l2_pix_format { #define V4L2_PIX_FMT_Y4 v4l2_fourcc('Y', '0', '4', ' ') /* 4 Greyscale */ #define V4L2_PIX_FMT_Y6 v4l2_fourcc('Y', '0', '6', ' ') /* 6 Greyscale */ #define V4L2_PIX_FMT_Y10 v4l2_fourcc('Y', '1', '0', ' ') /* 10 Greyscale */ +#define V4L2_PIX_FMT_Y12 v4l2_fourcc('Y', '1', '2', ' ') /* 12 Greyscale */ #define V4L2_PIX_FMT_Y16 v4l2_fourcc('Y', '1', '6', ' ') /* 16 Greyscale */ /* Palette formats */ -- cgit v0.10.2 From cbbc69a4a98081740f0e3d7717fbfa0b584b983d Mon Sep 17 00:00:00 2001 From: Michael Jones Date: Tue, 29 Mar 2011 05:19:07 -0300 Subject: [media] media: add missing 8-bit bayer formats and Y12 8-bit SGBRG and SRGGB media bus formats are missing, as well as the 12-bit grey format. Add them. Signed-off-by: Michael Jones Acked-by: Laurent Pinchart Signed-off-by: Mauro Carvalho Chehab diff --git a/Documentation/DocBook/v4l/subdev-formats.xml b/Documentation/DocBook/v4l/subdev-formats.xml index 7041127..d7ccd25 100644 --- a/Documentation/DocBook/v4l/subdev-formats.xml +++ b/Documentation/DocBook/v4l/subdev-formats.xml @@ -456,6 +456,23 @@ b1 b0 + + V4L2_MBUS_FMT_SGBRG8_1X8 + 0x3013 + + - + - + - + - + g7 + g6 + g5 + g4 + g3 + g2 + g1 + g0 + V4L2_MBUS_FMT_SGRBG8_1X8 0x3002 @@ -473,6 +490,23 @@ g1 g0 + + V4L2_MBUS_FMT_SRGGB8_1X8 + 0x3014 + + - + - + - + - + r7 + r6 + r5 + r4 + r3 + r2 + r1 + r0 + V4L2_MBUS_FMT_SBGGR10_DPCM8_1X8 0x300b @@ -2159,6 +2193,31 @@ u1 u0 + + V4L2_MBUS_FMT_Y12_1X12 + 0x2013 + + - + - + - + - + - + - + - + - + y11 + y10 + y9 + y8 + y7 + y6 + y5 + y4 + y3 + y2 + y1 + y0 + V4L2_MBUS_FMT_UYVY8_1X16 0x200f diff --git a/include/linux/v4l2-mediabus.h b/include/linux/v4l2-mediabus.h index 7054a7a..de5c159 100644 --- a/include/linux/v4l2-mediabus.h +++ b/include/linux/v4l2-mediabus.h @@ -47,7 +47,7 @@ enum v4l2_mbus_pixelcode { V4L2_MBUS_FMT_RGB565_2X8_BE = 0x1007, V4L2_MBUS_FMT_RGB565_2X8_LE = 0x1008, - /* YUV (including grey) - next is 0x2013 */ + /* YUV (including grey) - next is 0x2014 */ V4L2_MBUS_FMT_Y8_1X8 = 0x2001, V4L2_MBUS_FMT_UYVY8_1_5X8 = 0x2002, V4L2_MBUS_FMT_VYUY8_1_5X8 = 0x2003, @@ -60,6 +60,7 @@ enum v4l2_mbus_pixelcode { V4L2_MBUS_FMT_Y10_1X10 = 0x200a, V4L2_MBUS_FMT_YUYV10_2X10 = 0x200b, V4L2_MBUS_FMT_YVYU10_2X10 = 0x200c, + V4L2_MBUS_FMT_Y12_1X12 = 0x2013, V4L2_MBUS_FMT_UYVY8_1X16 = 0x200f, V4L2_MBUS_FMT_VYUY8_1X16 = 0x2010, V4L2_MBUS_FMT_YUYV8_1X16 = 0x2011, @@ -67,9 +68,11 @@ enum v4l2_mbus_pixelcode { V4L2_MBUS_FMT_YUYV10_1X20 = 0x200d, V4L2_MBUS_FMT_YVYU10_1X20 = 0x200e, - /* Bayer - next is 0x3013 */ + /* Bayer - next is 0x3015 */ V4L2_MBUS_FMT_SBGGR8_1X8 = 0x3001, + V4L2_MBUS_FMT_SGBRG8_1X8 = 0x3013, V4L2_MBUS_FMT_SGRBG8_1X8 = 0x3002, + V4L2_MBUS_FMT_SRGGB8_1X8 = 0x3014, V4L2_MBUS_FMT_SBGGR10_DPCM8_1X8 = 0x300b, V4L2_MBUS_FMT_SGBRG10_DPCM8_1X8 = 0x300c, V4L2_MBUS_FMT_SGRBG10_DPCM8_1X8 = 0x3009, -- cgit v0.10.2 From 5782f97b55a0cf8ef66dff045f1beafcdaf40dda Mon Sep 17 00:00:00 2001 From: Michael Jones Date: Tue, 29 Mar 2011 05:19:08 -0300 Subject: [media] omap3isp: ccdc: support Y10/12, 8-bit bayer fmts Add support for 8-bit bayer and 10- and 12-bit grey formats at the CCDC input. Y12 is truncated to Y10 at the CCDC output. Signed-off-by: Michael Jones Acked-by: Laurent Pinchart Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/video/omap3isp/ispccdc.c b/drivers/media/video/omap3isp/ispccdc.c index fd811ea..68941ed 100644 --- a/drivers/media/video/omap3isp/ispccdc.c +++ b/drivers/media/video/omap3isp/ispccdc.c @@ -43,6 +43,12 @@ __ccdc_get_format(struct isp_ccdc_device *ccdc, struct v4l2_subdev_fh *fh, static const unsigned int ccdc_fmts[] = { V4L2_MBUS_FMT_Y8_1X8, + V4L2_MBUS_FMT_Y10_1X10, + V4L2_MBUS_FMT_Y12_1X12, + V4L2_MBUS_FMT_SGRBG8_1X8, + V4L2_MBUS_FMT_SRGGB8_1X8, + V4L2_MBUS_FMT_SBGGR8_1X8, + V4L2_MBUS_FMT_SGBRG8_1X8, V4L2_MBUS_FMT_SGRBG10_1X10, V4L2_MBUS_FMT_SRGGB10_1X10, V4L2_MBUS_FMT_SBGGR10_1X10, diff --git a/drivers/media/video/omap3isp/ispvideo.c b/drivers/media/video/omap3isp/ispvideo.c index a0bb5db..9ade735 100644 --- a/drivers/media/video/omap3isp/ispvideo.c +++ b/drivers/media/video/omap3isp/ispvideo.c @@ -48,6 +48,18 @@ static struct isp_format_info formats[] = { { V4L2_MBUS_FMT_Y8_1X8, V4L2_MBUS_FMT_Y8_1X8, V4L2_MBUS_FMT_Y8_1X8, V4L2_PIX_FMT_GREY, 8, }, + { V4L2_MBUS_FMT_Y10_1X10, V4L2_MBUS_FMT_Y10_1X10, + V4L2_MBUS_FMT_Y10_1X10, V4L2_PIX_FMT_Y10, 10, }, + { V4L2_MBUS_FMT_Y12_1X12, V4L2_MBUS_FMT_Y10_1X10, + V4L2_MBUS_FMT_Y12_1X12, V4L2_PIX_FMT_Y12, 12, }, + { V4L2_MBUS_FMT_SBGGR8_1X8, V4L2_MBUS_FMT_SBGGR8_1X8, + V4L2_MBUS_FMT_SBGGR8_1X8, V4L2_PIX_FMT_SBGGR8, 8, }, + { V4L2_MBUS_FMT_SGBRG8_1X8, V4L2_MBUS_FMT_SGBRG8_1X8, + V4L2_MBUS_FMT_SGBRG8_1X8, V4L2_PIX_FMT_SGBRG8, 8, }, + { V4L2_MBUS_FMT_SGRBG8_1X8, V4L2_MBUS_FMT_SGRBG8_1X8, + V4L2_MBUS_FMT_SGRBG8_1X8, V4L2_PIX_FMT_SGRBG8, 8, }, + { V4L2_MBUS_FMT_SRGGB8_1X8, V4L2_MBUS_FMT_SRGGB8_1X8, + V4L2_MBUS_FMT_SRGGB8_1X8, V4L2_PIX_FMT_SRGGB8, 8, }, { V4L2_MBUS_FMT_SGRBG10_DPCM8_1X8, V4L2_MBUS_FMT_SGRBG10_DPCM8_1X8, V4L2_MBUS_FMT_SGRBG10_1X10, V4L2_PIX_FMT_SGRBG10DPCM8, 8, }, { V4L2_MBUS_FMT_SBGGR10_1X10, V4L2_MBUS_FMT_SBGGR10_1X10, -- cgit v0.10.2 From c09af044db91bf0f8ca5073f5863c7280de39cc1 Mon Sep 17 00:00:00 2001 From: Michael Jones Date: Tue, 29 Mar 2011 05:19:09 -0300 Subject: [media] omap3isp: lane shifter support To use the lane shifter, set different pixel formats at each end of the link at the CCDC input. Signed-off-by: Michael Jones Acked-by: Laurent Pinchart Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/video/omap3isp/isp.c b/drivers/media/video/omap3isp/isp.c index e4fe836..5d8e1ce 100644 --- a/drivers/media/video/omap3isp/isp.c +++ b/drivers/media/video/omap3isp/isp.c @@ -286,7 +286,8 @@ static void isp_power_settings(struct isp_device *isp, int idle) */ void omap3isp_configure_bridge(struct isp_device *isp, enum ccdc_input_entity input, - const struct isp_parallel_platform_data *pdata) + const struct isp_parallel_platform_data *pdata, + unsigned int shift) { u32 ispctrl_val; @@ -299,9 +300,9 @@ void omap3isp_configure_bridge(struct isp_device *isp, switch (input) { case CCDC_INPUT_PARALLEL: ispctrl_val |= ISPCTRL_PAR_SER_CLK_SEL_PARALLEL; - ispctrl_val |= pdata->data_lane_shift << ISPCTRL_SHIFT_SHIFT; ispctrl_val |= pdata->clk_pol << ISPCTRL_PAR_CLK_POL_SHIFT; ispctrl_val |= pdata->bridge << ISPCTRL_PAR_BRIDGE_SHIFT; + shift += pdata->data_lane_shift * 2; break; case CCDC_INPUT_CSI2A: @@ -320,6 +321,8 @@ void omap3isp_configure_bridge(struct isp_device *isp, return; } + ispctrl_val |= ((shift/2) << ISPCTRL_SHIFT_SHIFT) & ISPCTRL_SHIFT_MASK; + ispctrl_val &= ~ISPCTRL_SYNC_DETECT_MASK; ispctrl_val |= ISPCTRL_SYNC_DETECT_VSRISE; diff --git a/drivers/media/video/omap3isp/isp.h b/drivers/media/video/omap3isp/isp.h index 00075c6..2620c40 100644 --- a/drivers/media/video/omap3isp/isp.h +++ b/drivers/media/video/omap3isp/isp.h @@ -132,7 +132,6 @@ struct isp_reg { /** * struct isp_parallel_platform_data - Parallel interface platform data - * @width: Parallel bus width in bits (8, 10, 11 or 12) * @data_lane_shift: Data lane shifter * 0 - CAMEXT[13:0] -> CAM[13:0] * 1 - CAMEXT[13:2] -> CAM[11:0] @@ -146,7 +145,6 @@ struct isp_reg { * ISPCTRL_PAR_BRIDGE_BENDIAN - Big endian */ struct isp_parallel_platform_data { - unsigned int width; unsigned int data_lane_shift:2; unsigned int clk_pol:1; unsigned int bridge:4; @@ -312,7 +310,8 @@ int omap3isp_pipeline_set_stream(struct isp_pipeline *pipe, enum isp_pipeline_stream_state state); void omap3isp_configure_bridge(struct isp_device *isp, enum ccdc_input_entity input, - const struct isp_parallel_platform_data *pdata); + const struct isp_parallel_platform_data *pdata, + unsigned int shift); #define ISP_XCLK_NONE 0 #define ISP_XCLK_A 1 diff --git a/drivers/media/video/omap3isp/ispccdc.c b/drivers/media/video/omap3isp/ispccdc.c index 68941ed..39d501b 100644 --- a/drivers/media/video/omap3isp/ispccdc.c +++ b/drivers/media/video/omap3isp/ispccdc.c @@ -1116,21 +1116,38 @@ static void ccdc_configure(struct isp_ccdc_device *ccdc) struct isp_parallel_platform_data *pdata = NULL; struct v4l2_subdev *sensor; struct v4l2_mbus_framefmt *format; + const struct isp_format_info *fmt_info; + struct v4l2_subdev_format fmt_src; + unsigned int depth_out; + unsigned int depth_in = 0; struct media_pad *pad; unsigned long flags; + unsigned int shift; u32 syn_mode; u32 ccdc_pattern; - if (ccdc->input == CCDC_INPUT_PARALLEL) { - pad = media_entity_remote_source(&ccdc->pads[CCDC_PAD_SINK]); - sensor = media_entity_to_v4l2_subdev(pad->entity); + pad = media_entity_remote_source(&ccdc->pads[CCDC_PAD_SINK]); + sensor = media_entity_to_v4l2_subdev(pad->entity); + if (ccdc->input == CCDC_INPUT_PARALLEL) pdata = &((struct isp_v4l2_subdevs_group *)sensor->host_priv) ->bus.parallel; + + /* Compute shift value for lane shifter to configure the bridge. */ + fmt_src.pad = pad->index; + fmt_src.which = V4L2_SUBDEV_FORMAT_ACTIVE; + if (!v4l2_subdev_call(sensor, pad, get_fmt, NULL, &fmt_src)) { + fmt_info = omap3isp_video_format_info(fmt_src.format.code); + depth_in = fmt_info->bpp; } - omap3isp_configure_bridge(isp, ccdc->input, pdata); + fmt_info = omap3isp_video_format_info + (isp->isp_ccdc.formats[CCDC_PAD_SINK].code); + depth_out = fmt_info->bpp; + + shift = depth_in - depth_out; + omap3isp_configure_bridge(isp, ccdc->input, pdata, shift); - ccdc->syncif.datsz = pdata ? pdata->width : 10; + ccdc->syncif.datsz = depth_out; ccdc_config_sync_if(ccdc, &ccdc->syncif); /* CCDC_PAD_SINK */ diff --git a/drivers/media/video/omap3isp/ispvideo.c b/drivers/media/video/omap3isp/ispvideo.c index 9ade735..6e18cee 100644 --- a/drivers/media/video/omap3isp/ispvideo.c +++ b/drivers/media/video/omap3isp/ispvideo.c @@ -47,41 +47,59 @@ static struct isp_format_info formats[] = { { V4L2_MBUS_FMT_Y8_1X8, V4L2_MBUS_FMT_Y8_1X8, - V4L2_MBUS_FMT_Y8_1X8, V4L2_PIX_FMT_GREY, 8, }, + V4L2_MBUS_FMT_Y8_1X8, V4L2_MBUS_FMT_Y8_1X8, + V4L2_PIX_FMT_GREY, 8, }, { V4L2_MBUS_FMT_Y10_1X10, V4L2_MBUS_FMT_Y10_1X10, - V4L2_MBUS_FMT_Y10_1X10, V4L2_PIX_FMT_Y10, 10, }, + V4L2_MBUS_FMT_Y10_1X10, V4L2_MBUS_FMT_Y8_1X8, + V4L2_PIX_FMT_Y10, 10, }, { V4L2_MBUS_FMT_Y12_1X12, V4L2_MBUS_FMT_Y10_1X10, - V4L2_MBUS_FMT_Y12_1X12, V4L2_PIX_FMT_Y12, 12, }, + V4L2_MBUS_FMT_Y12_1X12, V4L2_MBUS_FMT_Y8_1X8, + V4L2_PIX_FMT_Y12, 12, }, { V4L2_MBUS_FMT_SBGGR8_1X8, V4L2_MBUS_FMT_SBGGR8_1X8, - V4L2_MBUS_FMT_SBGGR8_1X8, V4L2_PIX_FMT_SBGGR8, 8, }, + V4L2_MBUS_FMT_SBGGR8_1X8, V4L2_MBUS_FMT_SBGGR8_1X8, + V4L2_PIX_FMT_SBGGR8, 8, }, { V4L2_MBUS_FMT_SGBRG8_1X8, V4L2_MBUS_FMT_SGBRG8_1X8, - V4L2_MBUS_FMT_SGBRG8_1X8, V4L2_PIX_FMT_SGBRG8, 8, }, + V4L2_MBUS_FMT_SGBRG8_1X8, V4L2_MBUS_FMT_SGBRG8_1X8, + V4L2_PIX_FMT_SGBRG8, 8, }, { V4L2_MBUS_FMT_SGRBG8_1X8, V4L2_MBUS_FMT_SGRBG8_1X8, - V4L2_MBUS_FMT_SGRBG8_1X8, V4L2_PIX_FMT_SGRBG8, 8, }, + V4L2_MBUS_FMT_SGRBG8_1X8, V4L2_MBUS_FMT_SGRBG8_1X8, + V4L2_PIX_FMT_SGRBG8, 8, }, { V4L2_MBUS_FMT_SRGGB8_1X8, V4L2_MBUS_FMT_SRGGB8_1X8, - V4L2_MBUS_FMT_SRGGB8_1X8, V4L2_PIX_FMT_SRGGB8, 8, }, + V4L2_MBUS_FMT_SRGGB8_1X8, V4L2_MBUS_FMT_SRGGB8_1X8, + V4L2_PIX_FMT_SRGGB8, 8, }, { V4L2_MBUS_FMT_SGRBG10_DPCM8_1X8, V4L2_MBUS_FMT_SGRBG10_DPCM8_1X8, - V4L2_MBUS_FMT_SGRBG10_1X10, V4L2_PIX_FMT_SGRBG10DPCM8, 8, }, + V4L2_MBUS_FMT_SGRBG10_1X10, 0, + V4L2_PIX_FMT_SGRBG10DPCM8, 8, }, { V4L2_MBUS_FMT_SBGGR10_1X10, V4L2_MBUS_FMT_SBGGR10_1X10, - V4L2_MBUS_FMT_SBGGR10_1X10, V4L2_PIX_FMT_SBGGR10, 10, }, + V4L2_MBUS_FMT_SBGGR10_1X10, V4L2_MBUS_FMT_SBGGR8_1X8, + V4L2_PIX_FMT_SBGGR10, 10, }, { V4L2_MBUS_FMT_SGBRG10_1X10, V4L2_MBUS_FMT_SGBRG10_1X10, - V4L2_MBUS_FMT_SGBRG10_1X10, V4L2_PIX_FMT_SGBRG10, 10, }, + V4L2_MBUS_FMT_SGBRG10_1X10, V4L2_MBUS_FMT_SGBRG8_1X8, + V4L2_PIX_FMT_SGBRG10, 10, }, { V4L2_MBUS_FMT_SGRBG10_1X10, V4L2_MBUS_FMT_SGRBG10_1X10, - V4L2_MBUS_FMT_SGRBG10_1X10, V4L2_PIX_FMT_SGRBG10, 10, }, + V4L2_MBUS_FMT_SGRBG10_1X10, V4L2_MBUS_FMT_SGRBG8_1X8, + V4L2_PIX_FMT_SGRBG10, 10, }, { V4L2_MBUS_FMT_SRGGB10_1X10, V4L2_MBUS_FMT_SRGGB10_1X10, - V4L2_MBUS_FMT_SRGGB10_1X10, V4L2_PIX_FMT_SRGGB10, 10, }, + V4L2_MBUS_FMT_SRGGB10_1X10, V4L2_MBUS_FMT_SRGGB8_1X8, + V4L2_PIX_FMT_SRGGB10, 10, }, { V4L2_MBUS_FMT_SBGGR12_1X12, V4L2_MBUS_FMT_SBGGR10_1X10, - V4L2_MBUS_FMT_SBGGR12_1X12, V4L2_PIX_FMT_SBGGR12, 12, }, + V4L2_MBUS_FMT_SBGGR12_1X12, V4L2_MBUS_FMT_SBGGR8_1X8, + V4L2_PIX_FMT_SBGGR12, 12, }, { V4L2_MBUS_FMT_SGBRG12_1X12, V4L2_MBUS_FMT_SGBRG10_1X10, - V4L2_MBUS_FMT_SGBRG12_1X12, V4L2_PIX_FMT_SGBRG12, 12, }, + V4L2_MBUS_FMT_SGBRG12_1X12, V4L2_MBUS_FMT_SGBRG8_1X8, + V4L2_PIX_FMT_SGBRG12, 12, }, { V4L2_MBUS_FMT_SGRBG12_1X12, V4L2_MBUS_FMT_SGRBG10_1X10, - V4L2_MBUS_FMT_SGRBG12_1X12, V4L2_PIX_FMT_SGRBG12, 12, }, + V4L2_MBUS_FMT_SGRBG12_1X12, V4L2_MBUS_FMT_SGRBG8_1X8, + V4L2_PIX_FMT_SGRBG12, 12, }, { V4L2_MBUS_FMT_SRGGB12_1X12, V4L2_MBUS_FMT_SRGGB10_1X10, - V4L2_MBUS_FMT_SRGGB12_1X12, V4L2_PIX_FMT_SRGGB12, 12, }, + V4L2_MBUS_FMT_SRGGB12_1X12, V4L2_MBUS_FMT_SRGGB8_1X8, + V4L2_PIX_FMT_SRGGB12, 12, }, { V4L2_MBUS_FMT_UYVY8_1X16, V4L2_MBUS_FMT_UYVY8_1X16, - V4L2_MBUS_FMT_UYVY8_1X16, V4L2_PIX_FMT_UYVY, 16, }, + V4L2_MBUS_FMT_UYVY8_1X16, 0, + V4L2_PIX_FMT_UYVY, 16, }, { V4L2_MBUS_FMT_YUYV8_1X16, V4L2_MBUS_FMT_YUYV8_1X16, - V4L2_MBUS_FMT_YUYV8_1X16, V4L2_PIX_FMT_YUYV, 16, }, + V4L2_MBUS_FMT_YUYV8_1X16, 0, + V4L2_PIX_FMT_YUYV, 16, }, }; const struct isp_format_info * @@ -98,6 +116,37 @@ omap3isp_video_format_info(enum v4l2_mbus_pixelcode code) } /* + * Decide whether desired output pixel code can be obtained with + * the lane shifter by shifting the input pixel code. + * @in: input pixelcode to shifter + * @out: output pixelcode from shifter + * @additional_shift: # of bits the sensor's LSB is offset from CAMEXT[0] + * + * return true if the combination is possible + * return false otherwise + */ +static bool isp_video_is_shiftable(enum v4l2_mbus_pixelcode in, + enum v4l2_mbus_pixelcode out, + unsigned int additional_shift) +{ + const struct isp_format_info *in_info, *out_info; + + if (in == out) + return true; + + in_info = omap3isp_video_format_info(in); + out_info = omap3isp_video_format_info(out); + + if ((in_info->flavor == 0) || (out_info->flavor == 0)) + return false; + + if (in_info->flavor != out_info->flavor) + return false; + + return in_info->bpp - out_info->bpp + additional_shift <= 6; +} + +/* * isp_video_mbus_to_pix - Convert v4l2_mbus_framefmt to v4l2_pix_format * @video: ISP video instance * @mbus: v4l2_mbus_framefmt format (input) @@ -247,6 +296,7 @@ static int isp_video_validate_pipeline(struct isp_pipeline *pipe) return -EPIPE; while (1) { + unsigned int shifter_link; /* Retrieve the sink format */ pad = &subdev->entity.pads[0]; if (!(pad->flags & MEDIA_PAD_FL_SINK)) @@ -275,6 +325,10 @@ static int isp_video_validate_pipeline(struct isp_pipeline *pipe) return -ENOSPC; } + /* If sink pad is on CCDC, the link has the lane shifter + * in the middle of it. */ + shifter_link = subdev == &isp->isp_ccdc.subdev; + /* Retrieve the source format */ pad = media_entity_remote_source(pad); if (pad == NULL || @@ -290,10 +344,24 @@ static int isp_video_validate_pipeline(struct isp_pipeline *pipe) return -EPIPE; /* Check if the two ends match */ - if (fmt_source.format.code != fmt_sink.format.code || - fmt_source.format.width != fmt_sink.format.width || + if (fmt_source.format.width != fmt_sink.format.width || fmt_source.format.height != fmt_sink.format.height) return -EPIPE; + + if (shifter_link) { + unsigned int parallel_shift = 0; + if (isp->isp_ccdc.input == CCDC_INPUT_PARALLEL) { + struct isp_parallel_platform_data *pdata = + &((struct isp_v4l2_subdevs_group *) + subdev->host_priv)->bus.parallel; + parallel_shift = pdata->data_lane_shift * 2; + } + if (!isp_video_is_shiftable(fmt_source.format.code, + fmt_sink.format.code, + parallel_shift)) + return -EPIPE; + } else if (fmt_source.format.code != fmt_sink.format.code) + return -EPIPE; } return 0; diff --git a/drivers/media/video/omap3isp/ispvideo.h b/drivers/media/video/omap3isp/ispvideo.h index 524a1acd..911bea6 100644 --- a/drivers/media/video/omap3isp/ispvideo.h +++ b/drivers/media/video/omap3isp/ispvideo.h @@ -49,6 +49,8 @@ struct v4l2_pix_format; * bits. Identical to @code if the format is 10 bits wide or less. * @uncompressed: V4L2 media bus format code for the corresponding uncompressed * format. Identical to @code if the format is not DPCM compressed. + * @flavor: V4L2 media bus format code for the same pixel layout but + * shifted to be 8 bits per pixel. =0 if format is not shiftable. * @pixelformat: V4L2 pixel format FCC identifier * @bpp: Bits per pixel */ @@ -56,6 +58,7 @@ struct isp_format_info { enum v4l2_mbus_pixelcode code; enum v4l2_mbus_pixelcode truncated; enum v4l2_mbus_pixelcode uncompressed; + enum v4l2_mbus_pixelcode flavor; u32 pixelformat; unsigned int bpp; }; -- cgit v0.10.2 From e2241531a5d015b55cdddd488f6f3477c785f34e Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Fri, 1 Apr 2011 09:12:54 -0300 Subject: [media] omap3isp: Don't increment node entity use count when poweron fails When open a device node, all entities part of the same pipeline are powered on. If one of the entities fails to be powered on, the open operations fails. In that case the device node entity use count must not be incremented. Signed-off-by: Laurent Pinchart Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/video/omap3isp/isp.c b/drivers/media/video/omap3isp/isp.c index 5d8e1ce..de2dec5 100644 --- a/drivers/media/video/omap3isp/isp.c +++ b/drivers/media/video/omap3isp/isp.c @@ -662,6 +662,8 @@ int omap3isp_pipeline_pm_use(struct media_entity *entity, int use) /* Apply power change to connected non-nodes. */ ret = isp_pipeline_pm_power(entity, change); + if (ret < 0) + entity->use_count -= change; mutex_unlock(&entity->parent->graph_mutex); -- cgit v0.10.2 From c4f0b78ad5d0e76caaeb5c2349c2613728c816bc Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Fri, 8 Apr 2011 09:04:06 -0300 Subject: [media] v4l: Don't register media entities for subdev device nodes Subdevs already have their own entity, don't register as second one when registering the subdev device node. Signed-off-by: Laurent Pinchart Acked-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/video/v4l2-dev.c b/drivers/media/video/v4l2-dev.c index 498e674..6dc7196 100644 --- a/drivers/media/video/v4l2-dev.c +++ b/drivers/media/video/v4l2-dev.c @@ -389,7 +389,8 @@ static int v4l2_open(struct inode *inode, struct file *filp) video_get(vdev); mutex_unlock(&videodev_lock); #if defined(CONFIG_MEDIA_CONTROLLER) - if (vdev->v4l2_dev && vdev->v4l2_dev->mdev) { + if (vdev->v4l2_dev && vdev->v4l2_dev->mdev && + vdev->vfl_type != VFL_TYPE_SUBDEV) { entity = media_entity_get(&vdev->entity); if (!entity) { ret = -EBUSY; @@ -415,7 +416,8 @@ err: /* decrease the refcount in case of an error */ if (ret) { #if defined(CONFIG_MEDIA_CONTROLLER) - if (vdev->v4l2_dev && vdev->v4l2_dev->mdev) + if (vdev->v4l2_dev && vdev->v4l2_dev->mdev && + vdev->vfl_type != VFL_TYPE_SUBDEV) media_entity_put(entity); #endif video_put(vdev); @@ -437,7 +439,8 @@ static int v4l2_release(struct inode *inode, struct file *filp) mutex_unlock(vdev->lock); } #if defined(CONFIG_MEDIA_CONTROLLER) - if (vdev->v4l2_dev && vdev->v4l2_dev->mdev) + if (vdev->v4l2_dev && vdev->v4l2_dev->mdev && + vdev->vfl_type != VFL_TYPE_SUBDEV) media_entity_put(&vdev->entity); #endif /* decrease the refcount unconditionally since the release() @@ -686,7 +689,8 @@ int __video_register_device(struct video_device *vdev, int type, int nr, #if defined(CONFIG_MEDIA_CONTROLLER) /* Part 5: Register the entity. */ - if (vdev->v4l2_dev && vdev->v4l2_dev->mdev) { + if (vdev->v4l2_dev && vdev->v4l2_dev->mdev && + vdev->vfl_type != VFL_TYPE_SUBDEV) { vdev->entity.type = MEDIA_ENT_T_DEVNODE_V4L; vdev->entity.name = vdev->name; vdev->entity.v4l.major = VIDEO_MAJOR; @@ -733,7 +737,8 @@ void video_unregister_device(struct video_device *vdev) return; #if defined(CONFIG_MEDIA_CONTROLLER) - if (vdev->v4l2_dev && vdev->v4l2_dev->mdev) + if (vdev->v4l2_dev && vdev->v4l2_dev->mdev && + vdev->vfl_type != VFL_TYPE_SUBDEV) media_device_unregister_entity(&vdev->entity); #endif -- cgit v0.10.2 From 2578dfb7f767076baf04eaf5fbf35a75afb9a1a7 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Thu, 7 Apr 2011 13:30:14 -0300 Subject: [media] omap3isp: queue: Don't corrupt buf->npages when get_user_pages() fails get_user_pages() can return a negative error code when it fails. Set buf->npages to 0 in that case, to prevent isp_video_buffer_cleanup() from releasing invalid pages. Signed-off-by: Laurent Pinchart Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/video/omap3isp/ispqueue.c b/drivers/media/video/omap3isp/ispqueue.c index c91e56a..9c31714 100644 --- a/drivers/media/video/omap3isp/ispqueue.c +++ b/drivers/media/video/omap3isp/ispqueue.c @@ -339,7 +339,7 @@ static int isp_video_buffer_prepare_user(struct isp_video_buffer *buf) up_read(¤t->mm->mmap_sem); if (ret != buf->npages) { - buf->npages = ret; + buf->npages = ret < 0 ? 0 : ret; isp_video_buffer_cleanup(buf); return -EFAULT; } -- cgit v0.10.2 From f78028b68f01925b826979627a2498111ea11bed Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Sat, 16 Apr 2011 13:22:10 -0300 Subject: [media] tda18271: fix calculation bug in tda18271_rf_tracking_filters_init Misplaced parenthesis cause a calculation bug in tda18271_rf_tracking_filters_init Thanks to Stefan Sibiga for pointing this out. Cc: Stefan Sibiga Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/common/tuners/tda18271-fe.c b/drivers/media/common/tuners/tda18271-fe.c index 9ad4454..42105d1 100644 --- a/drivers/media/common/tuners/tda18271-fe.c +++ b/drivers/media/common/tuners/tda18271-fe.c @@ -616,15 +616,15 @@ static int tda18271_rf_tracking_filters_init(struct dvb_frontend *fe, u32 freq) map[i].rf1 = rf_freq[RF1] / 1000; break; case RF2: - dividend = (s32)(prog_cal[RF2] - prog_tab[RF2]) - - (s32)(prog_cal[RF1] + prog_tab[RF1]); + dividend = (s32)(prog_cal[RF2] - prog_tab[RF2] - + prog_cal[RF1] + prog_tab[RF1]); divisor = (s32)(rf_freq[RF2] - rf_freq[RF1]) / 1000; map[i].rf_a1 = (dividend / divisor); map[i].rf2 = rf_freq[RF2] / 1000; break; case RF3: - dividend = (s32)(prog_cal[RF3] - prog_tab[RF3]) - - (s32)(prog_cal[RF2] + prog_tab[RF2]); + dividend = (s32)(prog_cal[RF3] - prog_tab[RF3] - + prog_cal[RF2] + prog_tab[RF2]); divisor = (s32)(rf_freq[RF3] - rf_freq[RF2]) / 1000; map[i].rf_a2 = (dividend / divisor); map[i].rf_b2 = (s32)(prog_cal[RF2] - prog_tab[RF2]); -- cgit v0.10.2 From 381ad0ea146465406a0740f437e9971ceb6465a9 Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Sat, 16 Apr 2011 13:22:10 -0300 Subject: [media] tda18271: prog_cal and prog_tab variables should be s32, not u8 Fix type of prog_cal and prog_tab variables to avoid any possible calculation errors. Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/common/tuners/tda18271-fe.c b/drivers/media/common/tuners/tda18271-fe.c index 42105d1..d884f5e 100644 --- a/drivers/media/common/tuners/tda18271-fe.c +++ b/drivers/media/common/tuners/tda18271-fe.c @@ -579,8 +579,8 @@ static int tda18271_rf_tracking_filters_init(struct dvb_frontend *fe, u32 freq) #define RF3 2 u32 rf_default[3]; u32 rf_freq[3]; - u8 prog_cal[3]; - u8 prog_tab[3]; + s32 prog_cal[3]; + s32 prog_tab[3]; i = tda18271_lookup_rf_band(fe, &freq, NULL); @@ -602,32 +602,33 @@ static int tda18271_rf_tracking_filters_init(struct dvb_frontend *fe, u32 freq) return bcal; tda18271_calc_rf_cal(fe, &rf_freq[rf]); - prog_tab[rf] = regs[R_EB14]; + prog_tab[rf] = (s32)regs[R_EB14]; if (1 == bcal) - prog_cal[rf] = tda18271_calibrate_rf(fe, rf_freq[rf]); + prog_cal[rf] = + (s32)tda18271_calibrate_rf(fe, rf_freq[rf]); else prog_cal[rf] = prog_tab[rf]; switch (rf) { case RF1: map[i].rf_a1 = 0; - map[i].rf_b1 = (s32)(prog_cal[RF1] - prog_tab[RF1]); + map[i].rf_b1 = (prog_cal[RF1] - prog_tab[RF1]); map[i].rf1 = rf_freq[RF1] / 1000; break; case RF2: - dividend = (s32)(prog_cal[RF2] - prog_tab[RF2] - - prog_cal[RF1] + prog_tab[RF1]); + dividend = (prog_cal[RF2] - prog_tab[RF2] - + prog_cal[RF1] + prog_tab[RF1]); divisor = (s32)(rf_freq[RF2] - rf_freq[RF1]) / 1000; map[i].rf_a1 = (dividend / divisor); map[i].rf2 = rf_freq[RF2] / 1000; break; case RF3: - dividend = (s32)(prog_cal[RF3] - prog_tab[RF3] - - prog_cal[RF2] + prog_tab[RF2]); + dividend = (prog_cal[RF3] - prog_tab[RF3] - + prog_cal[RF2] + prog_tab[RF2]); divisor = (s32)(rf_freq[RF3] - rf_freq[RF2]) / 1000; map[i].rf_a2 = (dividend / divisor); - map[i].rf_b2 = (s32)(prog_cal[RF2] - prog_tab[RF2]); + map[i].rf_b2 = (prog_cal[RF2] - prog_tab[RF2]); map[i].rf3 = rf_freq[RF3] / 1000; break; default: -- cgit v0.10.2 From 3f688e8c62fb69ff65bc9325831b5b3d3f5ef8ed Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Sat, 16 Apr 2011 13:22:10 -0300 Subject: [media] tda18271: fix bad calculation of main post divider byte R_MPD bit 3 does not depend on analog vs. digital. Just use (0x7f & pd) directly from the values in the main pll table. Thanks to Stefan Sibiga for pointing this out. Cc: Stefan Sibiga Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/common/tuners/tda18271-common.c b/drivers/media/common/tuners/tda18271-common.c index 5466d47..aae40e5 100644 --- a/drivers/media/common/tuners/tda18271-common.c +++ b/drivers/media/common/tuners/tda18271-common.c @@ -533,16 +533,7 @@ int tda18271_calc_main_pll(struct dvb_frontend *fe, u32 freq) if (tda_fail(ret)) goto fail; - regs[R_MPD] = (0x77 & pd); - - switch (priv->mode) { - case TDA18271_ANALOG: - regs[R_MPD] &= ~0x08; - break; - case TDA18271_DIGITAL: - regs[R_MPD] |= 0x08; - break; - } + regs[R_MPD] = (0x7f & pd); div = ((d * (freq / 1000)) << 7) / 125; -- cgit v0.10.2 From 786e86ae5efff8552f5ae07977324c226e0fcfe7 Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Sat, 16 Apr 2011 13:22:10 -0300 Subject: [media] tda18271: update tda18271_rf_band as per NXP's rev.04 datasheet Cc: Stefan Sibiga Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/common/tuners/tda18271-maps.c b/drivers/media/common/tuners/tda18271-maps.c index e7f84c7..2fef126 100644 --- a/drivers/media/common/tuners/tda18271-maps.c +++ b/drivers/media/common/tuners/tda18271-maps.c @@ -229,8 +229,7 @@ static struct tda18271_map tda18271c2_km[] = { static struct tda18271_map tda18271_rf_band[] = { { .rfmax = 47900, .val = 0x00 }, { .rfmax = 61100, .val = 0x01 }, -/* { .rfmax = 152600, .val = 0x02 }, */ - { .rfmax = 121200, .val = 0x02 }, + { .rfmax = 152600, .val = 0x02 }, { .rfmax = 164700, .val = 0x03 }, { .rfmax = 203500, .val = 0x04 }, { .rfmax = 457800, .val = 0x05 }, -- cgit v0.10.2 From 5b9a81d14fcf0bf166f73bc3b31463efbdb2660a Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Sat, 16 Apr 2011 13:22:10 -0300 Subject: [media] tda18271: update tda18271c2_rf_cal as per NXP's rev.04 datasheet Cc: Stefan Sibiga Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/common/tuners/tda18271-maps.c b/drivers/media/common/tuners/tda18271-maps.c index 2fef126..3d5b6ab 100644 --- a/drivers/media/common/tuners/tda18271-maps.c +++ b/drivers/media/common/tuners/tda18271-maps.c @@ -447,7 +447,7 @@ static struct tda18271_map tda18271c2_rf_cal[] = { { .rfmax = 150000, .val = 0xb0 }, { .rfmax = 151000, .val = 0xb1 }, { .rfmax = 152000, .val = 0xb7 }, - { .rfmax = 153000, .val = 0xbd }, + { .rfmax = 152600, .val = 0xbd }, { .rfmax = 154000, .val = 0x20 }, { .rfmax = 155000, .val = 0x22 }, { .rfmax = 156000, .val = 0x24 }, @@ -458,7 +458,7 @@ static struct tda18271_map tda18271c2_rf_cal[] = { { .rfmax = 161000, .val = 0x2d }, { .rfmax = 163000, .val = 0x2e }, { .rfmax = 164000, .val = 0x2f }, - { .rfmax = 165000, .val = 0x30 }, + { .rfmax = 164700, .val = 0x30 }, { .rfmax = 166000, .val = 0x11 }, { .rfmax = 167000, .val = 0x12 }, { .rfmax = 168000, .val = 0x13 }, @@ -509,7 +509,8 @@ static struct tda18271_map tda18271c2_rf_cal[] = { { .rfmax = 236000, .val = 0x1b }, { .rfmax = 237000, .val = 0x1c }, { .rfmax = 240000, .val = 0x1d }, - { .rfmax = 242000, .val = 0x1f }, + { .rfmax = 242000, .val = 0x1e }, + { .rfmax = 244000, .val = 0x1f }, { .rfmax = 247000, .val = 0x20 }, { .rfmax = 249000, .val = 0x21 }, { .rfmax = 252000, .val = 0x22 }, @@ -623,7 +624,7 @@ static struct tda18271_map tda18271c2_rf_cal[] = { { .rfmax = 453000, .val = 0x93 }, { .rfmax = 454000, .val = 0x94 }, { .rfmax = 456000, .val = 0x96 }, - { .rfmax = 457000, .val = 0x98 }, + { .rfmax = 457800, .val = 0x98 }, { .rfmax = 461000, .val = 0x11 }, { .rfmax = 468000, .val = 0x12 }, { .rfmax = 472000, .val = 0x13 }, -- cgit v0.10.2 From 6981d184376e74391c23c116a068f8d1305f0e57 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 15 Apr 2011 10:11:12 +0200 Subject: ALSA: hda - Add a fix-up for Acer dmic with ALC271x codec Acer laptops with ALC271x needs a magic initialization for digital-mic to make it working with mono streams (and PulseAudio). Added a fix-up applied to Acer with ALC271x generically. Cc: Signed-off-by: Takashi Iwai diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index d9f1ef7..30c4409 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -14868,6 +14868,23 @@ static void alc269_fixup_hweq(struct hda_codec *codec, alc_write_coef_idx(codec, 0x1e, coef | 0x80); } +static void alc271_fixup_dmic(struct hda_codec *codec, + const struct alc_fixup *fix, int action) +{ + static struct hda_verb verbs[] = { + {0x20, AC_VERB_SET_COEF_INDEX, 0x0d}, + {0x20, AC_VERB_SET_PROC_COEF, 0x4000}, + {} + }; + unsigned int cfg; + + if (strcmp(codec->chip_name, "ALC271X")) + return; + cfg = snd_hda_codec_get_pincfg(codec, 0x12); + if (get_defcfg_connect(cfg) == AC_JACK_PORT_FIXED) + snd_hda_sequence_write(codec, verbs); +} + enum { ALC269_FIXUP_SONY_VAIO, ALC275_FIXUP_SONY_VAIO_GPIO2, @@ -14876,6 +14893,7 @@ enum { ALC269_FIXUP_ASUS_G73JW, ALC269_FIXUP_LENOVO_EAPD, ALC275_FIXUP_SONY_HWEQ, + ALC271_FIXUP_DMIC, }; static const struct alc_fixup alc269_fixups[] = { @@ -14929,7 +14947,11 @@ static const struct alc_fixup alc269_fixups[] = { .v.func = alc269_fixup_hweq, .chained = true, .chain_id = ALC275_FIXUP_SONY_VAIO_GPIO2 - } + }, + [ALC271_FIXUP_DMIC] = { + .type = ALC_FIXUP_FUNC, + .v.func = alc271_fixup_dmic, + }, }; static struct snd_pci_quirk alc269_fixup_tbl[] = { @@ -14938,6 +14960,7 @@ static struct snd_pci_quirk alc269_fixup_tbl[] = { SND_PCI_QUIRK(0x104d, 0x9084, "Sony VAIO", ALC275_FIXUP_SONY_HWEQ), SND_PCI_QUIRK_VENDOR(0x104d, "Sony VAIO", ALC269_FIXUP_SONY_VAIO), SND_PCI_QUIRK(0x1028, 0x0470, "Dell M101z", ALC269_FIXUP_DELL_M101Z), + SND_PCI_QUIRK_VENDOR(0x1025, "Acer Aspire", ALC271_FIXUP_DMIC), SND_PCI_QUIRK(0x17aa, 0x20f2, "Thinkpad SL410/510", ALC269_FIXUP_SKU_IGNORE), SND_PCI_QUIRK(0x17aa, 0x215e, "Thinkpad L512", ALC269_FIXUP_SKU_IGNORE), SND_PCI_QUIRK(0x17aa, 0x21b8, "Thinkpad Edge 14", ALC269_FIXUP_SKU_IGNORE), -- cgit v0.10.2 From c3a2f0ad4917c678fcd828f16102518c33d8393c Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Sat, 2 Apr 2011 08:26:34 -0700 Subject: hwmon: Add submitting-patches checklist to documentation When writing hardware monitoring drivers, there are some common pitfalls which keep coming up in code reviews. This patch provides a document describing all those pitfalls and how to avoid them. Signed-off-by: Guenter Roeck Acked-by: Jean Delvare diff --git a/Documentation/hwmon/submitting-patches b/Documentation/hwmon/submitting-patches new file mode 100644 index 0000000..86f42e8 --- /dev/null +++ b/Documentation/hwmon/submitting-patches @@ -0,0 +1,109 @@ + How to Get Your Patch Accepted Into the Hwmon Subsystem + ------------------------------------------------------- + +This text is is a collection of suggestions for people writing patches or +drivers for the hwmon subsystem. Following these suggestions will greatly +increase the chances of your change being accepted. + + +1. General +---------- + +* It should be unnecessary to mention, but please read and follow + Documentation/SubmitChecklist + Documentation/SubmittingDrivers + Documentation/SubmittingPatches + Documentation/CodingStyle + +* If your patch generates checkpatch warnings, please refrain from explanations + such as "I don't like that coding style". Keep in mind that each unnecessary + warning helps hiding a real problem. If you don't like the kernel coding + style, don't write kernel drivers. + +* Please test your patch thoroughly. We are not your test group. + Sometimes a patch can not or not completely be tested because of missing + hardware. In such cases, you should test-build the code on at least one + architecture. If run-time testing was not achieved, it should be written + explicitly below the patch header. + +* If your patch (or the driver) is affected by configuration options such as + CONFIG_SMP or CONFIG_HOTPLUG, make sure it compiles for all configuration + variants. + + +2. Adding functionality to existing drivers +------------------------------------------- + +* Make sure the documentation in Documentation/hwmon/ is up to + date. + +* Make sure the information in Kconfig is up to date. + +* If the added functionality requires some cleanup or structural changes, split + your patch into a cleanup part and the actual addition. This makes it easier + to review your changes, and to bisect any resulting problems. + +* Never mix bug fixes, cleanup, and functional enhancements in a single patch. + + +3. New drivers +-------------- + +* Running your patch or driver file(s) through checkpatch does not mean its + formatting is clean. If unsure about formatting in your new driver, run it + through Lindent. Lindent is not perfect, and you may have to do some minor + cleanup, but it is a good start. + +* Consider adding yourself to MAINTAINERS. + +* Document the driver in Documentation/hwmon/. + +* Add the driver to Kconfig and Makefile in alphabetical order. + +* Make sure that all dependencies are listed in Kconfig. For new drivers, it + is most likely prudent to add a dependency on EXPERIMENTAL. + +* Avoid forward declarations if you can. Rearrange the code if necessary. + +* Avoid calculations in macros and macro-generated functions. While such macros + may save a line or so in the source, it obfuscates the code and makes code + review more difficult. It may also result in code which is more complicated + than necessary. Use inline functions or just regular functions instead. + +* If the driver has a detect function, make sure it is silent. Debug messages + and messages printed after a successful detection are acceptable, but it + must not print messages such as "Chip XXX not found/supported". + + Keep in mind that the detect function will run for all drivers supporting an + address if a chip is detected on that address. Unnecessary messages will just + pollute the kernel log and not provide any value. + +* Provide a detect function if and only if a chip can be detected reliably. + +* Avoid writing to chip registers in the detect function. If you have to write, + only do it after you have already gathered enough data to be certain that the + detection is going to be successful. + + Keep in mind that the chip might not be what your driver believes it is, and + writing to it might cause a bad misconfiguration. + +* Make sure there are no race conditions in the probe function. Specifically, + completely initialize your chip first, then create sysfs entries and register + with the hwmon subsystem. + +* Do not provide support for deprecated sysfs attributes. + +* Do not create non-standard attributes unless really needed. If you have to use + non-standard attributes, or you believe you do, discuss it on the mailing list + first. Either case, provide a detailed explanation why you need the + non-standard attribute(s). + Standard attributes are specified in Documentation/hwmon/sysfs-interface. + +* When deciding which sysfs attributes to support, look at the chip's + capabilities. While we do not expect your driver to support everything the + chip may offer, it should at least support all limits and alarms. + +* Last but not least, please check if a driver for your chip already exists + before starting to write a new driver. Especially for temperature sensors, + new chips are often variants of previously released chips. In some cases, + a presumably new chip may simply have been relabeled. -- cgit v0.10.2 From 3b17857dfbcb698c2dd0b4c38775ab04cf643d1a Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Mon, 14 Mar 2011 17:54:25 -0700 Subject: hwmon: (pmbus) Removed unused variable from struct pmbus_data struct pmbus_data included an unused variable named status_bits. Remove it. Signed-off-by: Guenter Roeck Reviewed-by: Tom Grennan diff --git a/drivers/hwmon/pmbus_core.c b/drivers/hwmon/pmbus_core.c index edfb92e..196ffaf 100644 --- a/drivers/hwmon/pmbus_core.c +++ b/drivers/hwmon/pmbus_core.c @@ -139,7 +139,6 @@ struct pmbus_data { * A single status register covers multiple attributes, * so we keep them all together. */ - u8 status_bits; u8 status[PB_NUM_STATUS_REG]; u8 currpage; -- cgit v0.10.2 From c1a76b47419ebb143559feaedfb35e4f285095b9 Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Mon, 18 Apr 2011 09:43:22 -0700 Subject: hwmon: (smm665) Fix spelling error in driver documentation tempererature may sound interesting, but temperature is still preferred. Signed-off-by: Guenter Roeck Acked-by: Jean Delvare diff --git a/Documentation/hwmon/smm665 b/Documentation/hwmon/smm665 index 3820fc9..59e3161 100644 --- a/Documentation/hwmon/smm665 +++ b/Documentation/hwmon/smm665 @@ -150,8 +150,8 @@ in8_crit_alarm Channel F critical alarm in9_crit_alarm AIN1 critical alarm in10_crit_alarm AIN2 critical alarm -temp1_input Chip tempererature -temp1_min Mimimum chip tempererature -temp1_max Maximum chip tempererature -temp1_crit Critical chip tempererature +temp1_input Chip temperature +temp1_min Mimimum chip temperature +temp1_max Maximum chip temperature +temp1_crit Critical chip temperature temp1_crit_alarm Temperature critical alarm -- cgit v0.10.2 From 180b3d889c85ce25d080997cc0c6cee4e46eed54 Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Mon, 18 Apr 2011 09:48:58 -0700 Subject: hwmon: (pmbus) Documentation updates Fix spelling, correct label name error, and add missing attribute to PMBus driver documentation. Signed-off-by: Guenter Roeck Reviewed-by: Tom Grennan diff --git a/Documentation/hwmon/pmbus b/Documentation/hwmon/pmbus index dc4933e..852d9eb 100644 --- a/Documentation/hwmon/pmbus +++ b/Documentation/hwmon/pmbus @@ -175,11 +175,13 @@ currX_crit Critical maximum current. From IIN_OC_FAULT_LIMIT or IOUT_OC_FAULT_LIMIT register. currX_alarm Current high alarm. From IIN_OC_WARNING or IOUT_OC_WARNING status. +currX_max_alarm Current high alarm. + From IIN_OC_WARN_LIMIT or IOUT_OC_WARN_LIMIT status. currX_lcrit_alarm Output current critical low alarm. From IOUT_UC_FAULT status. currX_crit_alarm Current critical high alarm. From IIN_OC_FAULT or IOUT_OC_FAULT status. -currX_label "iin" or "vinY" +currX_label "iin" or "ioutY" powerX_input Measured power. From READ_PIN or READ_POUT register. powerX_cap Output power cap. From POUT_MAX register. @@ -193,13 +195,13 @@ powerX_crit_alarm Output power critical high alarm. From POUT_OP_FAULT status. powerX_label "pin" or "poutY" -tempX_input Measured tempererature. +tempX_input Measured temperature. From READ_TEMPERATURE_X register. -tempX_min Mimimum tempererature. From UT_WARN_LIMIT register. -tempX_max Maximum tempererature. From OT_WARN_LIMIT register. -tempX_lcrit Critical low tempererature. +tempX_min Mimimum temperature. From UT_WARN_LIMIT register. +tempX_max Maximum temperature. From OT_WARN_LIMIT register. +tempX_lcrit Critical low temperature. From UT_FAULT_LIMIT register. -tempX_crit Critical high tempererature. +tempX_crit Critical high temperature. From OT_FAULT_LIMIT register. tempX_min_alarm Chip temperature low alarm. Set by comparing READ_TEMPERATURE_X with UT_WARN_LIMIT if -- cgit v0.10.2 From 2669d9f542b7eecb327d2bd3b7ee1d9eb46307b4 Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Mon, 18 Apr 2011 09:51:04 -0700 Subject: hwmon: (max8688) Add driver documentation MAX8688 has its own driver, thus should have its own documentation instead of being mentioned in the generic PMBus driver documentation. Signed-off-by: Guenter Roeck Reviewed-by: Tom Grennan diff --git a/Documentation/hwmon/max8688 b/Documentation/hwmon/max8688 new file mode 100644 index 0000000..0ddd3a4 --- /dev/null +++ b/Documentation/hwmon/max8688 @@ -0,0 +1,69 @@ +Kernel driver max8688 +===================== + +Supported chips: + * Maxim MAX8688 + Prefix: 'max8688' + Addresses scanned: - + Datasheet: http://datasheets.maxim-ic.com/en/ds/MAX8688.pdf + +Author: Guenter Roeck + + +Description +----------- + +This driver supports hardware montoring for Maxim MAX8688 Digital Power-Supply +Controller/Monitor with PMBus Interface. + +The driver is a client driver to the core PMBus driver. Please see +Documentation/hwmon/pmbus for details on PMBus client drivers. + + +Usage Notes +----------- + +This driver does not auto-detect devices. You will have to instantiate the +devices explicitly. Please see Documentation/i2c/instantiating-devices for +details. + + +Platform data support +--------------------- + +The driver supports standard PMBus driver platform data. + + +Sysfs entries +------------- + +The following attributes are supported. Limits are read-write; all other +attributes are read-only. + +in1_label "vout1" +in1_input Measured voltage. From READ_VOUT register. +in1_min Minumum Voltage. From VOUT_UV_WARN_LIMIT register. +in1_max Maximum voltage. From VOUT_OV_WARN_LIMIT register. +in1_lcrit Critical minumum Voltage. VOUT_UV_FAULT_LIMIT register. +in1_crit Critical maximum voltage. From VOUT_OV_FAULT_LIMIT register. +in1_min_alarm Voltage low alarm. From VOLTAGE_UV_WARNING status. +in1_max_alarm Voltage high alarm. From VOLTAGE_OV_WARNING status. +in1_lcrit_alarm Voltage critical low alarm. From VOLTAGE_UV_FAULT status. +in1_crit_alarm Voltage critical high alarm. From VOLTAGE_OV_FAULT status. + +curr1_label "iout1" +curr1_input Measured current. From READ_IOUT register. +curr1_max Maximum current. From IOUT_OC_WARN_LIMIT register. +curr1_crit Critical maximum current. From IOUT_OC_FAULT_LIMIT register. +curr1_max_alarm Current high alarm. From IOUT_OC_WARN_LIMIT register. +curr1_crit_alarm Current critical high alarm. From IOUT_OC_FAULT status. + +temp1_input Measured temperature. From READ_TEMPERATURE_1 register. +temp1_max Maximum temperature. From OT_WARN_LIMIT register. +temp1_crit Critical high temperature. From OT_FAULT_LIMIT register. +temp1_max_alarm Chip temperature high alarm. Set by comparing + READ_TEMPERATURE_1 with OT_WARN_LIMIT if TEMP_OT_WARNING + status is set. +temp1_crit_alarm Chip temperature critical high alarm. Set by comparing + READ_TEMPERATURE_1 with OT_FAULT_LIMIT if TEMP_OT_FAULT + status is set. diff --git a/Documentation/hwmon/pmbus b/Documentation/hwmon/pmbus index 852d9eb..0740a6c 100644 --- a/Documentation/hwmon/pmbus +++ b/Documentation/hwmon/pmbus @@ -28,11 +28,6 @@ Supported chips: Prefixes: 'max34441' Addresses scanned: - Datasheet: http://datasheets.maxim-ic.com/en/ds/MAX34441.pdf - * Maxim MAX8688 - Digital Power-Supply Controller/Monitor - Prefix: 'max8688' - Addresses scanned: - - Datasheet: http://datasheets.maxim-ic.com/en/ds/MAX8688.pdf * Generic PMBus devices Prefix: 'pmbus' Addresses scanned: - -- cgit v0.10.2 From 4af33f1726b03997f70180466769cf28ddcaef85 Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Mon, 18 Apr 2011 09:53:54 -0700 Subject: hwmon: (max16064) Add driver documentation MAX16064 has its own driver, thus should have its own documentation instead of being mentioned in the generic PMBus driver documentation. Signed-off-by: Guenter Roeck Reviewed-by: Tom Grennan diff --git a/Documentation/hwmon/max16064 b/Documentation/hwmon/max16064 new file mode 100644 index 0000000..4172899 --- /dev/null +++ b/Documentation/hwmon/max16064 @@ -0,0 +1,62 @@ +Kernel driver max16064 +====================== + +Supported chips: + * Maxim MAX16064 + Prefix: 'max16064' + Addresses scanned: - + Datasheet: http://datasheets.maxim-ic.com/en/ds/MAX16064.pdf + +Author: Guenter Roeck + + +Description +----------- + +This driver supports hardware montoring for Maxim MAX16064 Quad Power-Supply +Controller with Active-Voltage Output Control and PMBus Interface. + +The driver is a client driver to the core PMBus driver. +Please see Documentation/hwmon/pmbus for details on PMBus client drivers. + + +Usage Notes +----------- + +This driver does not auto-detect devices. You will have to instantiate the +devices explicitly. Please see Documentation/i2c/instantiating-devices for +details. + + +Platform data support +--------------------- + +The driver supports standard PMBus driver platform data. + + +Sysfs entries +------------- + +The following attributes are supported. Limits are read-write; all other +attributes are read-only. + +in[1-4]_label "vout[1-4]" +in[1-4]_input Measured voltage. From READ_VOUT register. +in[1-4]_min Minumum Voltage. From VOUT_UV_WARN_LIMIT register. +in[1-4]_max Maximum voltage. From VOUT_OV_WARN_LIMIT register. +in[1-4]_lcrit Critical minumum Voltage. VOUT_UV_FAULT_LIMIT register. +in[1-4]_crit Critical maximum voltage. From VOUT_OV_FAULT_LIMIT register. +in[1-4]_min_alarm Voltage low alarm. From VOLTAGE_UV_WARNING status. +in[1-4]_max_alarm Voltage high alarm. From VOLTAGE_OV_WARNING status. +in[1-4]_lcrit_alarm Voltage critical low alarm. From VOLTAGE_UV_FAULT status. +in[1-4]_crit_alarm Voltage critical high alarm. From VOLTAGE_OV_FAULT status. + +temp1_input Measured temperature. From READ_TEMPERATURE_1 register. +temp1_max Maximum temperature. From OT_WARN_LIMIT register. +temp1_crit Critical high temperature. From OT_FAULT_LIMIT register. +temp1_max_alarm Chip temperature high alarm. Set by comparing + READ_TEMPERATURE_1 with OT_WARN_LIMIT if TEMP_OT_WARNING + status is set. +temp1_crit_alarm Chip temperature critical high alarm. Set by comparing + READ_TEMPERATURE_1 with OT_FAULT_LIMIT if TEMP_OT_FAULT + status is set. diff --git a/Documentation/hwmon/pmbus b/Documentation/hwmon/pmbus index 0740a6c..e3c527a 100644 --- a/Documentation/hwmon/pmbus +++ b/Documentation/hwmon/pmbus @@ -13,11 +13,6 @@ Supported chips: Prefix: 'ltc2978' Addresses scanned: - Datasheet: http://cds.linear.com/docs/Datasheet/2978fa.pdf - * Maxim MAX16064 - Quad Power-Supply Controller - Prefix: 'max16064' - Addresses scanned: - - Datasheet: http://datasheets.maxim-ic.com/en/ds/MAX16064.pdf * Maxim MAX34440 PMBus 6-Channel Power-Supply Manager Prefixes: 'max34440' -- cgit v0.10.2 From e428d8d3bd164ad36fb545b2162bdfcb8100dc08 Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Mon, 18 Apr 2011 09:55:59 -0700 Subject: hwmon: (max34440) Add driver documentation MAX34440 and MAX34441 have their own driver, thus there should be explicit documentation instead of mentioning the chips in the generic PMBus driver documentation. Signed-off-by: Guenter Roeck Reviewed-by: Tom Grennan diff --git a/Documentation/hwmon/max34440 b/Documentation/hwmon/max34440 new file mode 100644 index 0000000..6c525dd --- /dev/null +++ b/Documentation/hwmon/max34440 @@ -0,0 +1,79 @@ +Kernel driver max34440 +====================== + +Supported chips: + * Maxim MAX34440 + Prefixes: 'max34440' + Addresses scanned: - + Datasheet: http://datasheets.maxim-ic.com/en/ds/MAX34440.pdf + * Maxim MAX34441 + PMBus 5-Channel Power-Supply Manager and Intelligent Fan Controller + Prefixes: 'max34441' + Addresses scanned: - + Datasheet: http://datasheets.maxim-ic.com/en/ds/MAX34441.pdf + +Author: Guenter Roeck + + +Description +----------- + +This driver supports hardware montoring for Maxim MAX34440 PMBus 6-Channel +Power-Supply Manager and MAX34441 PMBus 5-Channel Power-Supply Manager +and Intelligent Fan Controller. + +The driver is a client driver to the core PMBus driver. Please see +Documentation/hwmon/pmbus for details on PMBus client drivers. + + +Usage Notes +----------- + +This driver does not auto-detect devices. You will have to instantiate the +devices explicitly. Please see Documentation/i2c/instantiating-devices for +details. + + +Platform data support +--------------------- + +The driver supports standard PMBus driver platform data. + + +Sysfs entries +------------- + +The following attributes are supported. Limits are read-write; all other +attributes are read-only. + +in[1-6]_label "vout[1-6]". +in[1-6]_input Measured voltage. From READ_VOUT register. +in[1-6]_min Minumum Voltage. From VOUT_UV_WARN_LIMIT register. +in[1-6]_max Maximum voltage. From VOUT_OV_WARN_LIMIT register. +in[1-6]_lcrit Critical minumum Voltage. VOUT_UV_FAULT_LIMIT register. +in[1-6]_crit Critical maximum voltage. From VOUT_OV_FAULT_LIMIT register. +in[1-6]_min_alarm Voltage low alarm. From VOLTAGE_UV_WARNING status. +in[1-6]_max_alarm Voltage high alarm. From VOLTAGE_OV_WARNING status. +in[1-6]_lcrit_alarm Voltage critical low alarm. From VOLTAGE_UV_FAULT status. +in[1-6]_crit_alarm Voltage critical high alarm. From VOLTAGE_OV_FAULT status. + +curr[1-6]_label "iout[1-6]". +curr[1-6]_input Measured current. From READ_IOUT register. +curr[1-6]_max Maximum current. From IOUT_OC_WARN_LIMIT register. +curr[1-6]_crit Critical maximum current. From IOUT_OC_FAULT_LIMIT register. +curr[1-6]_max_alarm Current high alarm. From IOUT_OC_WARNING status. +curr[1-6]_crit_alarm Current critical high alarm. From IOUT_OC_FAULT status. + + in6 and curr6 attributes only exist for MAX34440. + +temp[1-8]_input Measured temperatures. From READ_TEMPERATURE_1 register. + temp1 is the chip's internal temperature. temp2..temp5 + are remote I2C temperature sensors. For MAX34441, temp6 + is a remote thermal-diode sensor. For MAX34440, temp6..8 + are remote I2C temperature sensors. +temp[1-8]_max Maximum temperature. From OT_WARN_LIMIT register. +temp[1-8]_crit Critical high temperature. From OT_FAULT_LIMIT register. +temp[1-8]_max_alarm Temperature high alarm. +temp[1-8]_crit_alarm Temperature critical high alarm. + + temp7 and temp8 attributes only exist for MAX34440. diff --git a/Documentation/hwmon/pmbus b/Documentation/hwmon/pmbus index e3c527a..5e462fc 100644 --- a/Documentation/hwmon/pmbus +++ b/Documentation/hwmon/pmbus @@ -13,16 +13,6 @@ Supported chips: Prefix: 'ltc2978' Addresses scanned: - Datasheet: http://cds.linear.com/docs/Datasheet/2978fa.pdf - * Maxim MAX34440 - PMBus 6-Channel Power-Supply Manager - Prefixes: 'max34440' - Addresses scanned: - - Datasheet: http://datasheets.maxim-ic.com/en/ds/MAX34440.pdf - * Maxim MAX34441 - PMBus 5-Channel Power-Supply Manager and Intelligent Fan Controller - Prefixes: 'max34441' - Addresses scanned: - - Datasheet: http://datasheets.maxim-ic.com/en/ds/MAX34441.pdf * Generic PMBus devices Prefix: 'pmbus' Addresses scanned: - -- cgit v0.10.2 From 1286eeb2fd22ddb4c56390f957e854ec06bab9fd Mon Sep 17 00:00:00 2001 From: Benoit Cousson Date: Tue, 19 Apr 2011 10:15:36 -0600 Subject: OMAP2+: hwmod data: Fix wrong dma_system end address OMAP2420, 2430 and 3xxx were using the OMAP4 end address that unfortunately is not located at the same base address. Moreover the OMAP4 size was set to 256 instead of 4096. Change all .pa_end to set them to .pa_start + 0xfff Cc: "G, Manjunath Kondaiah" Cc: Benoit Cousson Reported-by: Michael Fillinger Signed-off-by: Benoit Cousson Signed-off-by: Paul Walmsley diff --git a/arch/arm/mach-omap2/omap_hwmod_2420_data.c b/arch/arm/mach-omap2/omap_hwmod_2420_data.c index 8eb3ce1..f50e56a 100644 --- a/arch/arm/mach-omap2/omap_hwmod_2420_data.c +++ b/arch/arm/mach-omap2/omap_hwmod_2420_data.c @@ -1782,7 +1782,7 @@ static struct omap_hwmod_irq_info omap2420_dma_system_irqs[] = { static struct omap_hwmod_addr_space omap2420_dma_system_addrs[] = { { .pa_start = 0x48056000, - .pa_end = 0x4a0560ff, + .pa_end = 0x48056fff, .flags = ADDR_TYPE_RT }, }; diff --git a/arch/arm/mach-omap2/omap_hwmod_2430_data.c b/arch/arm/mach-omap2/omap_hwmod_2430_data.c index e6e3810..96753f7 100644 --- a/arch/arm/mach-omap2/omap_hwmod_2430_data.c +++ b/arch/arm/mach-omap2/omap_hwmod_2430_data.c @@ -1915,7 +1915,7 @@ static struct omap_hwmod_irq_info omap2430_dma_system_irqs[] = { static struct omap_hwmod_addr_space omap2430_dma_system_addrs[] = { { .pa_start = 0x48056000, - .pa_end = 0x4a0560ff, + .pa_end = 0x48056fff, .flags = ADDR_TYPE_RT }, }; diff --git a/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c b/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c index b98e2dfc..9bee155 100644 --- a/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c +++ b/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c @@ -2386,7 +2386,7 @@ static struct omap_hwmod_irq_info omap3xxx_dma_system_irqs[] = { static struct omap_hwmod_addr_space omap3xxx_dma_system_addrs[] = { { .pa_start = 0x48056000, - .pa_end = 0x4a0560ff, + .pa_end = 0x48056fff, .flags = ADDR_TYPE_RT }, }; diff --git a/arch/arm/mach-omap2/omap_hwmod_44xx_data.c b/arch/arm/mach-omap2/omap_hwmod_44xx_data.c index 3e88dd3..abc548a 100644 --- a/arch/arm/mach-omap2/omap_hwmod_44xx_data.c +++ b/arch/arm/mach-omap2/omap_hwmod_44xx_data.c @@ -885,7 +885,7 @@ static struct omap_hwmod_ocp_if *omap44xx_dma_system_masters[] = { static struct omap_hwmod_addr_space omap44xx_dma_system_addrs[] = { { .pa_start = 0x4a056000, - .pa_end = 0x4a0560ff, + .pa_end = 0x4a056fff, .flags = ADDR_TYPE_RT }, }; -- cgit v0.10.2 From 2b398bd9f8f73be706b41adcbb240ce95793049a Mon Sep 17 00:00:00 2001 From: Youquan Song Date: Thu, 14 Apr 2011 14:36:08 +0800 Subject: x86, apic: Print verbose error interrupt reason on apic=debug End users worry about the error interrupt printout we generate currently: pr_debug("APIC error on CPU%d: %02x(%02x)\n", smp_processor_id(), v , v1); ... and would like to know the reason why error interrupts are generated. This patch prints out more detailed debug information. Another practical problem is that dynamic debug is not initialized yet when the APIC initializes, so the pr_debug() will not output the error interrupt debug information on bootup. In this patch, we use apic_printk(APIC_DEBUG, ...), so the apic=debug boot option will print verbose error interupts during bootup. Signed-off-by: Youquan Song Cc: Joe Perches Cc: hpa@linux.intel.com Cc: suresh.b.siddha@intel.com Cc: yong.y.wang@linux.intel.com Cc: jbaron@redhat.com Cc: trenn@suse.de Cc: kent.liu@intel.com Cc: chaohong.guo@intel.com Link: http://lkml.kernel.org/r/1302762968-24380-2-git-send-email-youquan.song@intel.com Signed-off-by: Ingo Molnar diff --git a/arch/x86/kernel/apic/apic.c b/arch/x86/kernel/apic/apic.c index fabf01e..ae14712 100644 --- a/arch/x86/kernel/apic/apic.c +++ b/arch/x86/kernel/apic/apic.c @@ -1812,30 +1812,41 @@ void smp_spurious_interrupt(struct pt_regs *regs) */ void smp_error_interrupt(struct pt_regs *regs) { - u32 v, v1; + u32 v0, v1; + u32 i = 0; + static const char * const error_interrupt_reason[] = { + "Send CS error", /* APIC Error Bit 0 */ + "Receive CS error", /* APIC Error Bit 1 */ + "Send accept error", /* APIC Error Bit 2 */ + "Receive accept error", /* APIC Error Bit 3 */ + "Redirectable IPI", /* APIC Error Bit 4 */ + "Send illegal vector", /* APIC Error Bit 5 */ + "Received illegal vector", /* APIC Error Bit 6 */ + "Illegal register address", /* APIC Error Bit 7 */ + }; exit_idle(); irq_enter(); /* First tickle the hardware, only then report what went on. -- REW */ - v = apic_read(APIC_ESR); + v0 = apic_read(APIC_ESR); apic_write(APIC_ESR, 0); v1 = apic_read(APIC_ESR); ack_APIC_irq(); atomic_inc(&irq_err_count); - /* - * Here is what the APIC error bits mean: - * 0: Send CS error - * 1: Receive CS error - * 2: Send accept error - * 3: Receive accept error - * 4: Reserved - * 5: Send illegal vector - * 6: Received illegal vector - * 7: Illegal register address - */ - pr_debug("APIC error on CPU%d: %02x(%02x)\n", - smp_processor_id(), v , v1); + apic_printk(APIC_DEBUG, KERN_DEBUG "APIC error on CPU%d: %02x(%02x)", + smp_processor_id(), v0 , v1); + + v1 = v1 & 0xff; + while (v1) { + if (v1 & 0x1) + apic_printk(APIC_DEBUG, KERN_CONT " : %s", error_interrupt_reason[i]); + i++; + v1 >>= 1; + }; + + apic_printk(APIC_DEBUG, KERN_CONT "\n"); + irq_exit(); } -- cgit v0.10.2 From 7b70bd3441437b7bc04fc9d321e17c8ed0e8f958 Mon Sep 17 00:00:00 2001 From: Borislav Petkov Date: Mon, 18 Apr 2011 16:00:21 +0200 Subject: x86, MCE: Do not taint when handling correctable errors Correctable errors are considered something rather normal on modern hardware these days. Even more importantly, correctable errors mean exactly that - they've been corrected by the hardware - and there's no need to taint the kernel since execution hasn't been compromised so far. Also, drop tainting in the thermal throttling code for a similar reason: crossing a thermal threshold does not mean corruption. Signed-off-by: Borislav Petkov Acked-by: Tony Luck Acked-by: Nagananda Chumbalkar Cc: Prarit Bhargava Cc: Russ Anderson Cc: Linus Torvalds Cc: Andrew Morton Link: http://lkml.kernel.org/r/1303135222-17118-1-git-send-email-bp@amd64.org Signed-off-by: Ingo Molnar diff --git a/arch/x86/kernel/cpu/mcheck/mce.c b/arch/x86/kernel/cpu/mcheck/mce.c index 3385ea2..68e2303 100644 --- a/arch/x86/kernel/cpu/mcheck/mce.c +++ b/arch/x86/kernel/cpu/mcheck/mce.c @@ -590,7 +590,6 @@ void machine_check_poll(enum mcp_flags flags, mce_banks_t *b) if (!(flags & MCP_DONTLOG) && !mce_dont_log_ce) { mce_log(&m); atomic_notifier_call_chain(&x86_mce_decoder_chain, 0, &m); - add_taint(TAINT_MACHINE_CHECK); } /* diff --git a/arch/x86/kernel/cpu/mcheck/therm_throt.c b/arch/x86/kernel/cpu/mcheck/therm_throt.c index 6f8c5e9..5846a79 100644 --- a/arch/x86/kernel/cpu/mcheck/therm_throt.c +++ b/arch/x86/kernel/cpu/mcheck/therm_throt.c @@ -187,8 +187,6 @@ static int therm_throt_process(bool new_event, int event, int level) this_cpu, level == CORE_LEVEL ? "Core" : "Package", state->count); - - add_taint(TAINT_MACHINE_CHECK); return 1; } if (old_event) { @@ -393,7 +391,6 @@ static void unexpected_thermal_interrupt(void) { printk(KERN_ERR "CPU%d: Unexpected LVT thermal interrupt!\n", smp_processor_id()); - add_taint(TAINT_MACHINE_CHECK); } static void (*smp_thermal_vector)(void) = unexpected_thermal_interrupt; -- cgit v0.10.2 From 71460af58f8565110160283849db4d6bf7e1efa1 Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Tue, 19 Apr 2011 10:54:44 -0700 Subject: Revert "[media] V4L: videobuf, don't use dma addr as physical" This reverts commit 35d9f510b67b10338161aba6229d4f55b4000f5b. Quoth Jiri Slaby: "It fixes mmap when IOMMU is used on x86 only, but breaks architectures like ARM or PPC where virt_to_phys(dma_alloc_coherent) doesn't work. We need there dma_mmap_coherent or similar (the trickery what snd_pcm_default_mmap does but in some saner way). But this cannot be done at this phase." Requested-by: Jiri Slaby Cc: Russell King - ARM Linux Cc: Janusz Krzysztofik Acked-by: Mauro Carvalho Chehab Signed-off-by: Linus Torvalds diff --git a/drivers/media/video/videobuf-dma-contig.c b/drivers/media/video/videobuf-dma-contig.c index c4742fc..c969111 100644 --- a/drivers/media/video/videobuf-dma-contig.c +++ b/drivers/media/video/videobuf-dma-contig.c @@ -300,7 +300,7 @@ static int __videobuf_mmap_mapper(struct videobuf_queue *q, vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); retval = remap_pfn_range(vma, vma->vm_start, - PFN_DOWN(virt_to_phys(mem->vaddr)), + mem->dma_handle >> PAGE_SHIFT, size, vma->vm_page_prot); if (retval) { dev_err(q->dev, "mmap: remap failed with error %d. ", retval); -- cgit v0.10.2 From ecf8328e59447b83a1f79628487e0e9f8801db84 Mon Sep 17 00:00:00 2001 From: Clemens Ladisch Date: Mon, 11 Apr 2011 09:56:12 +0200 Subject: firewire: ohci: do not start DMA contexts before link is enabled OHCI 1.1 5.7.3 not only forbids enabling or starting any DMA contexts before the linkEnable bit is set, but also explicitly warns of undefined behaviour if this order is violated. Don't violate it then. Signed-off-by: Clemens Ladisch Signed-off-by: Stefan Richter diff --git a/drivers/firewire/ohci.c b/drivers/firewire/ohci.c index f903d7b6..dfb3cb7 100644 --- a/drivers/firewire/ohci.c +++ b/drivers/firewire/ohci.c @@ -2066,8 +2066,6 @@ static int ohci_enable(struct fw_card *card, reg_write(ohci, OHCI1394_SelfIDBuffer, ohci->self_id_bus); reg_write(ohci, OHCI1394_LinkControlSet, - OHCI1394_LinkControl_rcvSelfID | - OHCI1394_LinkControl_rcvPhyPkt | OHCI1394_LinkControl_cycleTimerEnable | OHCI1394_LinkControl_cycleMaster); @@ -2094,9 +2092,6 @@ static int ohci_enable(struct fw_card *card, reg_write(ohci, OHCI1394_FairnessControl, 0); card->priority_budget_implemented = ohci->pri_req_max != 0; - ar_context_run(&ohci->ar_request_ctx); - ar_context_run(&ohci->ar_response_ctx); - reg_write(ohci, OHCI1394_PhyUpperBound, 0x00010000); reg_write(ohci, OHCI1394_IntEventClear, ~0); reg_write(ohci, OHCI1394_IntMaskClear, ~0); @@ -2186,7 +2181,13 @@ static int ohci_enable(struct fw_card *card, reg_write(ohci, OHCI1394_HCControlSet, OHCI1394_HCControl_linkEnable | OHCI1394_HCControl_BIBimageValid); - flush_writes(ohci); + + reg_write(ohci, OHCI1394_LinkControlSet, + OHCI1394_LinkControl_rcvSelfID | + OHCI1394_LinkControl_rcvPhyPkt); + + ar_context_run(&ohci->ar_request_ctx); + ar_context_run(&ohci->ar_response_ctx); /* also flushes writes */ /* We are ready to go, reset bus to finish initialization. */ fw_schedule_bus_reset(&ohci->card, false, true); -- cgit v0.10.2 From da28947e7e3602669e27d5e9ce787436ed662fa4 Mon Sep 17 00:00:00 2001 From: Clemens Ladisch Date: Mon, 11 Apr 2011 09:57:54 +0200 Subject: firewire: ohci: avoid separate DMA mapping for small AT payloads For AT packet payloads of up to eight bytes, we have enough unused space in the DMA descriptors list so that we can put a copy of the payload there and thus avoid having to create a separate streaming DMA mapping for the payload buffer. In a CPU-bound microbenchmark that just sends 8-byte packets, bandwidth was measured to increase by 5.7 %, from 1009 KB/s to 1067 KB/s. In practice, the only performance-sensitive usage of small asynchronous packets is the SBP-2 driver's write to the ORB_POINTER register during SCSI command submission. Signed-off-by: Clemens Ladisch Signed-off-by: Stefan Richter diff --git a/drivers/firewire/ohci.c b/drivers/firewire/ohci.c index dfb3cb7..435ed80 100644 --- a/drivers/firewire/ohci.c +++ b/drivers/firewire/ohci.c @@ -1218,6 +1218,7 @@ static void context_stop(struct context *ctx) } struct driver_data { + u8 inline_data[8]; struct fw_packet *packet; }; @@ -1301,20 +1302,28 @@ static int at_context_queue_packet(struct context *ctx, return -1; } + BUILD_BUG_ON(sizeof(struct driver_data) > sizeof(struct descriptor)); driver_data = (struct driver_data *) &d[3]; driver_data->packet = packet; packet->driver_data = driver_data; if (packet->payload_length > 0) { - payload_bus = - dma_map_single(ohci->card.device, packet->payload, - packet->payload_length, DMA_TO_DEVICE); - if (dma_mapping_error(ohci->card.device, payload_bus)) { - packet->ack = RCODE_SEND_ERROR; - return -1; + if (packet->payload_length > sizeof(driver_data->inline_data)) { + payload_bus = dma_map_single(ohci->card.device, + packet->payload, + packet->payload_length, + DMA_TO_DEVICE); + if (dma_mapping_error(ohci->card.device, payload_bus)) { + packet->ack = RCODE_SEND_ERROR; + return -1; + } + packet->payload_bus = payload_bus; + packet->payload_mapped = true; + } else { + memcpy(driver_data->inline_data, packet->payload, + packet->payload_length); + payload_bus = d_bus + 3 * sizeof(*d); } - packet->payload_bus = payload_bus; - packet->payload_mapped = true; d[2].req_count = cpu_to_le16(packet->payload_length); d[2].data_address = cpu_to_le32(payload_bus); -- cgit v0.10.2 From 0ff8fbc61727c926883eec381fbd3d32d1fab504 Mon Sep 17 00:00:00 2001 From: Clemens Ladisch Date: Tue, 12 Apr 2011 07:54:59 +0200 Subject: firewire: ohci: optimize find_branch_descriptor() When z==2, the condition "key == 2" is superfluous because it cannot occur without "b == 3", as a descriptor with b!=3 and key==2 would be an OUTPUT_MORE_IMMEDIATE descriptor which cannot be used alone. Also remove magic numbers and needless computations on the b field. Signed-off-by: Clemens Ladisch Signed-off-by: Stefan Richter diff --git a/drivers/firewire/ohci.c b/drivers/firewire/ohci.c index 435ed80..ce767a4 100644 --- a/drivers/firewire/ohci.c +++ b/drivers/firewire/ohci.c @@ -1006,13 +1006,12 @@ static void ar_context_run(struct ar_context *ctx) static struct descriptor *find_branch_descriptor(struct descriptor *d, int z) { - int b, key; + __le16 branch; - b = (le16_to_cpu(d->control) & DESCRIPTOR_BRANCH_ALWAYS) >> 2; - key = (le16_to_cpu(d->control) & DESCRIPTOR_KEY_IMMEDIATE) >> 8; + branch = d->control & cpu_to_le16(DESCRIPTOR_BRANCH_ALWAYS); /* figure out which descriptor the branch address goes in */ - if (z == 2 && (b == 3 || key == 2)) + if (z == 2 && branch == cpu_to_le16(DESCRIPTOR_BRANCH_ALWAYS)) return d; else return d + z - 1; -- cgit v0.10.2 From 25b9875fb4880efabb79d6a35c92cc7287fcaccd Mon Sep 17 00:00:00 2001 From: Sylwester Nawrocki Date: Fri, 8 Apr 2011 09:08:52 -0300 Subject: [media] s5p-fimc: Fix FIMC3 pixel limits on Exynos4 Correct pixel limits for the fourth FIMC entity on Exynos4 SoCs. FIMC3 only supports the writeback input from the LCD mixer. Also rename s5pv310 variant to exynos4 which is needed after renaming s5pv310 series to Exynos4. Signed-off-by: Sylwester Nawrocki Signed-off-by: Kyungmin Park Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/video/s5p-fimc/fimc-core.c b/drivers/media/video/s5p-fimc/fimc-core.c index 6c919b3..d54e6d85 100644 --- a/drivers/media/video/s5p-fimc/fimc-core.c +++ b/drivers/media/video/s5p-fimc/fimc-core.c @@ -1750,7 +1750,7 @@ static int __devexit fimc_remove(struct platform_device *pdev) } /* Image pixel limits, similar across several FIMC HW revisions. */ -static struct fimc_pix_limit s5p_pix_limit[3] = { +static struct fimc_pix_limit s5p_pix_limit[4] = { [0] = { .scaler_en_w = 3264, .scaler_dis_w = 8192, @@ -1775,6 +1775,14 @@ static struct fimc_pix_limit s5p_pix_limit[3] = { .out_rot_en_w = 1280, .out_rot_dis_w = 1920, }, + [3] = { + .scaler_en_w = 1920, + .scaler_dis_w = 8192, + .in_rot_en_h = 1366, + .in_rot_dis_w = 8192, + .out_rot_en_w = 1366, + .out_rot_dis_w = 1920, + }, }; static struct samsung_fimc_variant fimc0_variant_s5p = { @@ -1827,7 +1835,7 @@ static struct samsung_fimc_variant fimc2_variant_s5pv210 = { .pix_limit = &s5p_pix_limit[2], }; -static struct samsung_fimc_variant fimc0_variant_s5pv310 = { +static struct samsung_fimc_variant fimc0_variant_exynos4 = { .pix_hoff = 1, .has_inp_rot = 1, .has_out_rot = 1, @@ -1840,7 +1848,7 @@ static struct samsung_fimc_variant fimc0_variant_s5pv310 = { .pix_limit = &s5p_pix_limit[1], }; -static struct samsung_fimc_variant fimc2_variant_s5pv310 = { +static struct samsung_fimc_variant fimc2_variant_exynos4 = { .pix_hoff = 1, .has_cistatus2 = 1, .has_mainscaler_ext = 1, @@ -1848,7 +1856,7 @@ static struct samsung_fimc_variant fimc2_variant_s5pv310 = { .min_out_pixsize = 16, .hor_offs_align = 1, .out_buf_count = 32, - .pix_limit = &s5p_pix_limit[2], + .pix_limit = &s5p_pix_limit[3], }; /* S5PC100 */ @@ -1874,12 +1882,12 @@ static struct samsung_fimc_driverdata fimc_drvdata_s5pv210 = { }; /* S5PV310, S5PC210 */ -static struct samsung_fimc_driverdata fimc_drvdata_s5pv310 = { +static struct samsung_fimc_driverdata fimc_drvdata_exynos4 = { .variant = { - [0] = &fimc0_variant_s5pv310, - [1] = &fimc0_variant_s5pv310, - [2] = &fimc0_variant_s5pv310, - [3] = &fimc2_variant_s5pv310, + [0] = &fimc0_variant_exynos4, + [1] = &fimc0_variant_exynos4, + [2] = &fimc0_variant_exynos4, + [3] = &fimc2_variant_exynos4, }, .num_entities = 4, .lclk_frequency = 166000000UL, @@ -1893,8 +1901,8 @@ static struct platform_device_id fimc_driver_ids[] = { .name = "s5pv210-fimc", .driver_data = (unsigned long)&fimc_drvdata_s5pv210, }, { - .name = "s5pv310-fimc", - .driver_data = (unsigned long)&fimc_drvdata_s5pv310, + .name = "exynos4-fimc", + .driver_data = (unsigned long)&fimc_drvdata_exynos4, }, {}, }; -- cgit v0.10.2 From c4a627333f0d952c5e10c02609493fa63b5c7b28 Mon Sep 17 00:00:00 2001 From: Sylwester Nawrocki Date: Tue, 15 Mar 2011 14:50:52 -0300 Subject: [media] s5p-fimc: Do not allow changing format after REQBUFS Protecting the color format with vb2_is_streaming() is not sufficient as this prevents changing the format only after VIDIOC_STREAMON. To prevent the color format reconfiguration as soon as buffers are allocated use vb2_is_busy() instead. Also make the videobuf queue ops structure static. Signed-off-by: Sylwester Nawrocki Signed-off-by: Kyungmin Park Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/video/s5p-fimc/fimc-capture.c b/drivers/media/video/s5p-fimc/fimc-capture.c index 95f8b4e1..00c561c 100644 --- a/drivers/media/video/s5p-fimc/fimc-capture.c +++ b/drivers/media/video/s5p-fimc/fimc-capture.c @@ -527,7 +527,7 @@ static int fimc_cap_s_fmt_mplane(struct file *file, void *priv, if (ret) return ret; - if (vb2_is_streaming(&fimc->vid_cap.vbq) || fimc_capture_active(fimc)) + if (vb2_is_busy(&fimc->vid_cap.vbq) || fimc_capture_active(fimc)) return -EBUSY; frame = &ctx->d_frame; diff --git a/drivers/media/video/s5p-fimc/fimc-core.c b/drivers/media/video/s5p-fimc/fimc-core.c index d54e6d85..115a1e0 100644 --- a/drivers/media/video/s5p-fimc/fimc-core.c +++ b/drivers/media/video/s5p-fimc/fimc-core.c @@ -758,7 +758,7 @@ static void fimc_unlock(struct vb2_queue *vq) mutex_unlock(&ctx->fimc_dev->lock); } -struct vb2_ops fimc_qops = { +static struct vb2_ops fimc_qops = { .queue_setup = fimc_queue_setup, .buf_prepare = fimc_buf_prepare, .buf_queue = fimc_buf_queue, @@ -965,7 +965,7 @@ static int fimc_m2m_s_fmt_mplane(struct file *file, void *priv, vq = v4l2_m2m_get_vq(ctx->m2m_ctx, f->type); - if (vb2_is_streaming(vq)) { + if (vb2_is_busy(vq)) { v4l2_err(&fimc->m2m.v4l2_dev, "queue (%d) busy\n", f->type); return -EBUSY; } -- cgit v0.10.2 From 045030fa16648449b416d4fc8dcc54bfefd6f4aa Mon Sep 17 00:00:00 2001 From: Sylwester Nawrocki Date: Fri, 8 Apr 2011 09:11:43 -0300 Subject: [media] s5p-fimc: Fix bytesperline and plane payload setup Make sure the sizeimage for 3-planar color formats is width * height * 3/2 and the bytesperline is same for each plane in case of a multi-planar format. Signed-off-by: Sylwester Nawrocki Signed-off-by: Kyungmin Park Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/video/s5p-fimc/fimc-capture.c b/drivers/media/video/s5p-fimc/fimc-capture.c index 00c561c..d142b40 100644 --- a/drivers/media/video/s5p-fimc/fimc-capture.c +++ b/drivers/media/video/s5p-fimc/fimc-capture.c @@ -539,8 +539,10 @@ static int fimc_cap_s_fmt_mplane(struct file *file, void *priv, return -EINVAL; } - for (i = 0; i < frame->fmt->colplanes; i++) - frame->payload[i] = pix->plane_fmt[i].bytesperline * pix->height; + for (i = 0; i < frame->fmt->colplanes; i++) { + frame->payload[i] = + (pix->width * pix->height * frame->fmt->depth[i]) >> 3; + } /* Output DMA frame pixel size and offsets. */ frame->f_width = pix->plane_fmt[0].bytesperline * 8 diff --git a/drivers/media/video/s5p-fimc/fimc-core.c b/drivers/media/video/s5p-fimc/fimc-core.c index 115a1e0..ef4e3f6 100644 --- a/drivers/media/video/s5p-fimc/fimc-core.c +++ b/drivers/media/video/s5p-fimc/fimc-core.c @@ -927,23 +927,23 @@ int fimc_vidioc_try_fmt_mplane(struct file *file, void *priv, pix->num_planes = fmt->memplanes; pix->colorspace = V4L2_COLORSPACE_JPEG; - for (i = 0; i < pix->num_planes; ++i) { - int bpl = pix->plane_fmt[i].bytesperline; - dbg("[%d] bpl: %d, depth: %d, w: %d, h: %d", - i, bpl, fmt->depth[i], pix->width, pix->height); + for (i = 0; i < pix->num_planes; ++i) { + u32 bpl = pix->plane_fmt[i].bytesperline; + u32 *sizeimage = &pix->plane_fmt[i].sizeimage; - if (!bpl || (bpl * 8 / fmt->depth[i]) > pix->width) - bpl = (pix->width * fmt->depth[0]) >> 3; + if (fmt->colplanes > 1 && (bpl == 0 || bpl < pix->width)) + bpl = pix->width; /* Planar */ - if (!pix->plane_fmt[i].sizeimage) - pix->plane_fmt[i].sizeimage = pix->height * bpl; + if (fmt->colplanes == 1 && /* Packed */ + (bpl == 0 || ((bpl * 8) / fmt->depth[i]) < pix->width)) + bpl = (pix->width * fmt->depth[0]) / 8; - pix->plane_fmt[i].bytesperline = bpl; + if (i == 0) /* Same bytesperline for each plane. */ + mod_x = bpl; - dbg("[%d]: bpl: %d, sizeimage: %d", - i, pix->plane_fmt[i].bytesperline, - pix->plane_fmt[i].sizeimage); + pix->plane_fmt[i].bytesperline = mod_x; + *sizeimage = (pix->width * pix->height * fmt->depth[i]) / 8; } return 0; @@ -985,8 +985,10 @@ static int fimc_m2m_s_fmt_mplane(struct file *file, void *priv, if (!frame->fmt) return -EINVAL; - for (i = 0; i < frame->fmt->colplanes; i++) - frame->payload[i] = pix->plane_fmt[i].bytesperline * pix->height; + for (i = 0; i < frame->fmt->colplanes; i++) { + frame->payload[i] = + (pix->width * pix->height * frame->fmt->depth[i]) / 8; + } frame->f_width = pix->plane_fmt[0].bytesperline * 8 / frame->fmt->depth[0]; -- cgit v0.10.2 From 89582654ee3d1d76e153212c88daa6aa6c024fec Mon Sep 17 00:00:00 2001 From: Sylwester Nawrocki Date: Fri, 11 Mar 2011 12:33:44 -0300 Subject: [media] s5p-fimc: Add support for the buffer timestamps and sequence Add support for buffer timestamps and the sequence number in the video capture driver. Signed-off-by: Sylwester Nawrocki Signed-off-by: Kyungmin Park Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/video/s5p-fimc/fimc-core.c b/drivers/media/video/s5p-fimc/fimc-core.c index ef4e3f6..dc91a85 100644 --- a/drivers/media/video/s5p-fimc/fimc-core.c +++ b/drivers/media/video/s5p-fimc/fimc-core.c @@ -361,10 +361,20 @@ static void fimc_capture_irq_handler(struct fimc_dev *fimc) { struct fimc_vid_cap *cap = &fimc->vid_cap; struct fimc_vid_buffer *v_buf; + struct timeval *tv; + struct timespec ts; if (!list_empty(&cap->active_buf_q) && test_bit(ST_CAPT_RUN, &fimc->state)) { + ktime_get_real_ts(&ts); + v_buf = active_queue_pop(cap); + + tv = &v_buf->vb.v4l2_buf.timestamp; + tv->tv_sec = ts.tv_sec; + tv->tv_usec = ts.tv_nsec / NSEC_PER_USEC; + v_buf->vb.v4l2_buf.sequence = cap->frame_count++; + vb2_buffer_done(&v_buf->vb, VB2_BUF_STATE_DONE); } -- cgit v0.10.2 From ea42c8ecb2ff998b8f71e0a5f9d2748a65cb8f04 Mon Sep 17 00:00:00 2001 From: Marek Szyprowski Date: Tue, 12 Apr 2011 10:14:13 -0300 Subject: [media] media: vb2: fix incorrect v4l2_buffer->flags handling Videobuf2 core assumes that driver doesn't set any buffer flags. This is correct for buffer state flags that videobuf2 manages, but the other flags like V4L2_BUF_FLAG_{KEY,P,B}FRAME, V4L2_BUF_FLAG_TIMECODE and V4L2_BUF_FLAG_INPUT should be passed from or to the driver. Reported-by: Jonghun Han Signed-off-by: Marek Szyprowski Signed-off-by: Kyungmin Park CC: Pawel Osciak Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/video/videobuf2-core.c b/drivers/media/video/videobuf2-core.c index 71734a4..09d792d 100644 --- a/drivers/media/video/videobuf2-core.c +++ b/drivers/media/video/videobuf2-core.c @@ -37,6 +37,9 @@ module_param(debug, int, 0644); #define call_qop(q, op, args...) \ (((q)->ops->op) ? ((q)->ops->op(args)) : 0) +#define V4L2_BUFFER_STATE_FLAGS (V4L2_BUF_FLAG_MAPPED | V4L2_BUF_FLAG_QUEUED | \ + V4L2_BUF_FLAG_DONE | V4L2_BUF_FLAG_ERROR) + /** * __vb2_buf_mem_alloc() - allocate video memory for the given buffer */ @@ -284,7 +287,7 @@ static int __fill_v4l2_buffer(struct vb2_buffer *vb, struct v4l2_buffer *b) struct vb2_queue *q = vb->vb2_queue; int ret = 0; - /* Copy back data such as timestamp, input, etc. */ + /* Copy back data such as timestamp, flags, input, etc. */ memcpy(b, &vb->v4l2_buf, offsetof(struct v4l2_buffer, m)); b->input = vb->v4l2_buf.input; b->reserved = vb->v4l2_buf.reserved; @@ -313,7 +316,10 @@ static int __fill_v4l2_buffer(struct vb2_buffer *vb, struct v4l2_buffer *b) b->m.userptr = vb->v4l2_planes[0].m.userptr; } - b->flags = 0; + /* + * Clear any buffer state related flags. + */ + b->flags &= ~V4L2_BUFFER_STATE_FLAGS; switch (vb->state) { case VB2_BUF_STATE_QUEUED: @@ -715,6 +721,8 @@ static int __fill_vb2_buffer(struct vb2_buffer *vb, struct v4l2_buffer *b, vb->v4l2_buf.field = b->field; vb->v4l2_buf.timestamp = b->timestamp; + vb->v4l2_buf.input = b->input; + vb->v4l2_buf.flags = b->flags & ~V4L2_BUFFER_STATE_FLAGS; return 0; } -- cgit v0.10.2 From 13b140953ab4fd86e2065adfef892fe833986ffa Mon Sep 17 00:00:00 2001 From: Marek Szyprowski Date: Thu, 14 Apr 2011 07:17:44 -0300 Subject: [media] media: vb2: correct queue initialization order q->memory entry is initialized to late, so if allocation of memory buffers fails, the buffers might not be freed correctly (q->memory is tested in __vb2_free_mem, which can be called before setting q->memory). Reported-by: Kamil Debski Signed-off-by: Marek Szyprowski Signed-off-by: Kyungmin Park CC: Pawel Osciak Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/video/videobuf2-core.c b/drivers/media/video/videobuf2-core.c index 09d792d..6ba1461 100644 --- a/drivers/media/video/videobuf2-core.c +++ b/drivers/media/video/videobuf2-core.c @@ -525,6 +525,7 @@ int vb2_reqbufs(struct vb2_queue *q, struct v4l2_requestbuffers *req) num_buffers = min_t(unsigned int, req->count, VIDEO_MAX_FRAME); memset(plane_sizes, 0, sizeof(plane_sizes)); memset(q->alloc_ctx, 0, sizeof(q->alloc_ctx)); + q->memory = req->memory; /* * Ask the driver how many buffers and planes per buffer it requires. @@ -566,8 +567,6 @@ int vb2_reqbufs(struct vb2_queue *q, struct v4l2_requestbuffers *req) ret = num_buffers; } - q->memory = req->memory; - /* * Return the number of successfully allocated buffers * to the userspace. -- cgit v0.10.2 From 2232d31bf18ba02f5cd632bbfc3466aeca394c75 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Fri, 15 Apr 2011 00:41:43 +0200 Subject: ath9k: fix the return value of ath_stoprecv The patch 'ath9k_hw: fix stopping rx DMA during resets' added code to detect a condition where rx DMA was stopped, but the MAC failed to enter the idle state. This condition requires a hardware reset, however the return value of ath_stoprecv was 'true' in that case, which allowed it to skip the reset when issuing a fast channel change. Signed-off-by: Felix Fietkau Reported-by: Paul Stewart Cc: stable@kernel.org Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/recv.c b/drivers/net/wireless/ath/ath9k/recv.c index dcd19bc..b29c80d 100644 --- a/drivers/net/wireless/ath/ath9k/recv.c +++ b/drivers/net/wireless/ath/ath9k/recv.c @@ -506,7 +506,7 @@ bool ath_stoprecv(struct ath_softc *sc) "confusing the DMA engine when we start RX up\n"); ATH_DBG_WARN_ON_ONCE(!stopped); } - return stopped || reset; + return stopped && !reset; } void ath_flushrecv(struct ath_softc *sc) -- cgit v0.10.2 From cbc6a6ed0900aed789b5ca77192845f2f987af70 Mon Sep 17 00:00:00 2001 From: Antonio Ospite Date: Wed, 13 Apr 2011 21:40:45 +0200 Subject: rfkill: Regulator consumer driver for rfkill Add a regulator consumer driver for rfkill to enable controlling radio transmitters connected to voltage regulators using the regulator framework. A new "vrfkill" virtual supply is provided to use in platform code. Signed-off-by: Guiming Zhuo Signed-off-by: Antonio Ospite Reviewed-by: Johannes Berg Signed-off-by: John W. Linville diff --git a/include/linux/rfkill-regulator.h b/include/linux/rfkill-regulator.h new file mode 100644 index 0000000..aca36bc --- /dev/null +++ b/include/linux/rfkill-regulator.h @@ -0,0 +1,48 @@ +/* + * rfkill-regulator.c - Regulator consumer driver for rfkill + * + * Copyright (C) 2009 Guiming Zhuo + * Copyright (C) 2011 Antonio Ospite + * + * 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 __LINUX_RFKILL_REGULATOR_H +#define __LINUX_RFKILL_REGULATOR_H + +/* + * Use "vrfkill" as supply id when declaring the regulator consumer: + * + * static struct regulator_consumer_supply pcap_regulator_V6_consumers [] = { + * { .dev_name = "rfkill-regulator.0", .supply = "vrfkill" }, + * }; + * + * If you have several regulator driven rfkill, you can append a numerical id to + * .dev_name as done above, and use the same id when declaring the platform + * device: + * + * static struct rfkill_regulator_platform_data ezx_rfkill_bt_data = { + * .name = "ezx-bluetooth", + * .type = RFKILL_TYPE_BLUETOOTH, + * }; + * + * static struct platform_device a910_rfkill = { + * .name = "rfkill-regulator", + * .id = 0, + * .dev = { + * .platform_data = &ezx_rfkill_bt_data, + * }, + * }; + */ + +#include + +struct rfkill_regulator_platform_data { + char *name; /* the name for the rfkill switch */ + enum rfkill_type type; /* the type as specified in rfkill.h */ +}; + +#endif /* __LINUX_RFKILL_REGULATOR_H */ diff --git a/net/rfkill/Kconfig b/net/rfkill/Kconfig index 7fce6df..48464ca 100644 --- a/net/rfkill/Kconfig +++ b/net/rfkill/Kconfig @@ -22,3 +22,14 @@ config RFKILL_INPUT depends on RFKILL depends on INPUT = y || RFKILL = INPUT default y if !EXPERT + +config RFKILL_REGULATOR + tristate "Generic rfkill regulator driver" + depends on RFKILL || !RFKILL + depends on REGULATOR + help + This options enable controlling radio transmitters connected to + voltage regulator using the regulator framework. + + To compile this driver as a module, choose M here: the module will + be called rfkill-regulator. diff --git a/net/rfkill/Makefile b/net/rfkill/Makefile index 6621053..d9a5a58 100644 --- a/net/rfkill/Makefile +++ b/net/rfkill/Makefile @@ -5,3 +5,4 @@ rfkill-y += core.o rfkill-$(CONFIG_RFKILL_INPUT) += input.o obj-$(CONFIG_RFKILL) += rfkill.o +obj-$(CONFIG_RFKILL_REGULATOR) += rfkill-regulator.o diff --git a/net/rfkill/rfkill-regulator.c b/net/rfkill/rfkill-regulator.c new file mode 100644 index 0000000..18dc512 --- /dev/null +++ b/net/rfkill/rfkill-regulator.c @@ -0,0 +1,164 @@ +/* + * rfkill-regulator.c - Regulator consumer driver for rfkill + * + * Copyright (C) 2009 Guiming Zhuo + * Copyright (C) 2011 Antonio Ospite + * + * Implementation inspired by leds-regulator driver. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + */ + +#include +#include +#include +#include +#include +#include +#include + +struct rfkill_regulator_data { + struct rfkill *rf_kill; + bool reg_enabled; + + struct regulator *vcc; +}; + +static int rfkill_regulator_set_block(void *data, bool blocked) +{ + struct rfkill_regulator_data *rfkill_data = data; + + pr_debug("%s: blocked: %d\n", __func__, blocked); + + if (blocked) { + if (rfkill_data->reg_enabled) { + regulator_disable(rfkill_data->vcc); + rfkill_data->reg_enabled = 0; + } + } else { + if (!rfkill_data->reg_enabled) { + regulator_enable(rfkill_data->vcc); + rfkill_data->reg_enabled = 1; + } + } + + pr_debug("%s: regulator_is_enabled after set_block: %d\n", __func__, + regulator_is_enabled(rfkill_data->vcc)); + + return 0; +} + +struct rfkill_ops rfkill_regulator_ops = { + .set_block = rfkill_regulator_set_block, +}; + +static int __devinit rfkill_regulator_probe(struct platform_device *pdev) +{ + struct rfkill_regulator_platform_data *pdata = pdev->dev.platform_data; + struct rfkill_regulator_data *rfkill_data; + struct regulator *vcc; + struct rfkill *rf_kill; + int ret = 0; + + if (pdata == NULL) { + dev_err(&pdev->dev, "no platform data\n"); + return -ENODEV; + } + + if (pdata->name == NULL || pdata->type == 0) { + dev_err(&pdev->dev, "invalid name or type in platform data\n"); + return -EINVAL; + } + + vcc = regulator_get_exclusive(&pdev->dev, "vrfkill"); + if (IS_ERR(vcc)) { + dev_err(&pdev->dev, "Cannot get vcc for %s\n", pdata->name); + ret = PTR_ERR(vcc); + goto out; + } + + rfkill_data = kzalloc(sizeof(*rfkill_data), GFP_KERNEL); + if (rfkill_data == NULL) { + ret = -ENOMEM; + goto err_data_alloc; + } + + rf_kill = rfkill_alloc(pdata->name, &pdev->dev, + pdata->type, + &rfkill_regulator_ops, rfkill_data); + if (rf_kill == NULL) { + dev_err(&pdev->dev, "Cannot alloc rfkill device\n"); + ret = -ENOMEM; + goto err_rfkill_alloc; + } + + if (regulator_is_enabled(vcc)) { + dev_dbg(&pdev->dev, "Regulator already enabled\n"); + rfkill_data->reg_enabled = 1; + } + rfkill_data->vcc = vcc; + rfkill_data->rf_kill = rf_kill; + + ret = rfkill_register(rf_kill); + if (ret) { + dev_err(&pdev->dev, "Cannot register rfkill device\n"); + goto err_rfkill_register; + } + + platform_set_drvdata(pdev, rfkill_data); + dev_info(&pdev->dev, "%s initialized\n", pdata->name); + + return 0; + +err_rfkill_register: + rfkill_destroy(rf_kill); +err_rfkill_alloc: + kfree(rfkill_data); +err_data_alloc: + regulator_put(vcc); +out: + return ret; +} + +static int __devexit rfkill_regulator_remove(struct platform_device *pdev) +{ + struct rfkill_regulator_data *rfkill_data = platform_get_drvdata(pdev); + struct rfkill *rf_kill = rfkill_data->rf_kill; + + rfkill_unregister(rf_kill); + rfkill_destroy(rf_kill); + regulator_put(rfkill_data->vcc); + kfree(rfkill_data); + + return 0; +} + +static struct platform_driver rfkill_regulator_driver = { + .probe = rfkill_regulator_probe, + .remove = __devexit_p(rfkill_regulator_remove), + .driver = { + .name = "rfkill-regulator", + .owner = THIS_MODULE, + }, +}; + +static int __init rfkill_regulator_init(void) +{ + return platform_driver_register(&rfkill_regulator_driver); +} +module_init(rfkill_regulator_init); + +static void __exit rfkill_regulator_exit(void) +{ + platform_driver_unregister(&rfkill_regulator_driver); +} +module_exit(rfkill_regulator_exit); + +MODULE_AUTHOR("Guiming Zhuo "); +MODULE_AUTHOR("Antonio Ospite "); +MODULE_DESCRIPTION("Regulator consumer driver for rfkill"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:rfkill-regulator"); -- cgit v0.10.2 From 2290a9c35df271cc33601b69e7836fa288e2fc7d Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Thu, 14 Apr 2011 14:55:36 -0700 Subject: ath: fix 0x6C for beaconing/passive scan flags based on country IE The 0x6C regulatory domain is just like the 0x6A regulatory domain but differs in that 0x6C will allow adhoc and active scan on its channels only if we are associated to an AP with a country IE that allows those channels. The ath_reg_apply_beaconing_flags() does just this -- we respect the manufacturer's intent on only enabling beaconing modes of operation if and only if blessed by the country IE. Cc: David Quan Cc: Senthil Balasubramanian Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/regd.c b/drivers/net/wireless/ath/regd.c index 7e3b290..02b8962 100644 --- a/drivers/net/wireless/ath/regd.c +++ b/drivers/net/wireless/ath/regd.c @@ -334,6 +334,7 @@ static void ath_reg_apply_world_flags(struct wiphy *wiphy, case 0x63: case 0x66: case 0x67: + case 0x6C: ath_reg_apply_beaconing_flags(wiphy, initiator); break; case 0x68: -- cgit v0.10.2 From 00bca7e2f2b58b93ce408e92d18a8c42bbe8d6e5 Mon Sep 17 00:00:00 2001 From: Rajkumar Manoharan Date: Fri, 15 Apr 2011 12:28:52 +0530 Subject: ath9k_htc: Add debugfs support to change debug mask Signed-off-by: Rajkumar Manoharan Acked-by: Sujith Manoharan Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/htc.h b/drivers/net/wireless/ath/ath9k/htc.h index cc5d0a4..852cdcf 100644 --- a/drivers/net/wireless/ath/ath9k/htc.h +++ b/drivers/net/wireless/ath/ath9k/htc.h @@ -366,6 +366,7 @@ struct ath9k_debug { struct dentry *debugfs_recv; struct dentry *debugfs_slot; struct dentry *debugfs_queue; + struct dentry *debugfs_debug; struct ath_tx_stats tx_stats; struct ath_rx_stats rx_stats; }; diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_debug.c b/drivers/net/wireless/ath/ath9k/htc_drv_debug.c index 8d0de60..7394a1b 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_debug.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_debug.c @@ -435,6 +435,47 @@ static const struct file_operations fops_queue = { .llseek = default_llseek, }; +static ssize_t read_file_debug(struct file *file, char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct ath9k_htc_priv *priv = file->private_data; + struct ath_common *common = ath9k_hw_common(priv->ah); + char buf[32]; + unsigned int len; + + len = sprintf(buf, "0x%08x\n", common->debug_mask); + return simple_read_from_buffer(user_buf, count, ppos, buf, len); +} + +static ssize_t write_file_debug(struct file *file, const char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct ath9k_htc_priv *priv = file->private_data; + struct ath_common *common = ath9k_hw_common(priv->ah); + unsigned long mask; + char buf[32]; + ssize_t len; + + len = min(count, sizeof(buf) - 1); + if (copy_from_user(buf, user_buf, len)) + return -EFAULT; + + buf[len] = '\0'; + if (strict_strtoul(buf, 0, &mask)) + return -EINVAL; + + common->debug_mask = mask; + return count; +} + +static const struct file_operations fops_debug = { + .read = read_file_debug, + .write = write_file_debug, + .open = ath9k_debugfs_open, + .owner = THIS_MODULE, + .llseek = default_llseek, +}; + int ath9k_htc_init_debug(struct ath_hw *ah) { struct ath_common *common = ath9k_hw_common(ah); @@ -493,6 +534,13 @@ int ath9k_htc_init_debug(struct ath_hw *ah) if (!priv->debug.debugfs_queue) goto err; + priv->debug.debugfs_debug = debugfs_create_file("debug", + S_IRUSR | S_IWUSR, + priv->debug.debugfs_phy, + priv, &fops_debug); + if (!priv->debug.debugfs_debug) + goto err; + return 0; err: @@ -512,6 +560,7 @@ void ath9k_htc_exit_debug(struct ath_hw *ah) debugfs_remove(priv->debug.debugfs_tgt_int_stats); debugfs_remove(priv->debug.debugfs_tgt_tx_stats); debugfs_remove(priv->debug.debugfs_tgt_rx_stats); + debugfs_remove(priv->debug.debugfs_debug); debugfs_remove(priv->debug.debugfs_phy); } -- cgit v0.10.2 From e5facc75fa9104f074c4610437a9c717c9e5ecde Mon Sep 17 00:00:00 2001 From: Rajkumar Manoharan Date: Fri, 15 Apr 2011 15:42:24 +0530 Subject: ath9k_htc: Cleanup HTC debugfs Move the ath9k_htc debugfs under ieee80211 to be inline with ath9k driver and it also helps to simplify debug code. Signed-off-by: Rajkumar Manoharan Acked-by: Sujith Manoharan Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/htc.h b/drivers/net/wireless/ath/ath9k/htc.h index 852cdcf..48a8855 100644 --- a/drivers/net/wireless/ath/ath9k/htc.h +++ b/drivers/net/wireless/ath/ath9k/htc.h @@ -359,14 +359,6 @@ struct ath_rx_stats { struct ath9k_debug { struct dentry *debugfs_phy; - struct dentry *debugfs_tgt_int_stats; - struct dentry *debugfs_tgt_tx_stats; - struct dentry *debugfs_tgt_rx_stats; - struct dentry *debugfs_xmit; - struct dentry *debugfs_recv; - struct dentry *debugfs_slot; - struct dentry *debugfs_queue; - struct dentry *debugfs_debug; struct ath_tx_stats tx_stats; struct ath_rx_stats rx_stats; }; @@ -613,15 +605,9 @@ void ath9k_htc_suspend(struct htc_target *htc_handle); int ath9k_htc_resume(struct htc_target *htc_handle); #endif #ifdef CONFIG_ATH9K_HTC_DEBUGFS -int ath9k_htc_debug_create_root(void); -void ath9k_htc_debug_remove_root(void); int ath9k_htc_init_debug(struct ath_hw *ah); -void ath9k_htc_exit_debug(struct ath_hw *ah); #else -static inline int ath9k_htc_debug_create_root(void) { return 0; }; -static inline void ath9k_htc_debug_remove_root(void) {}; static inline int ath9k_htc_init_debug(struct ath_hw *ah) { return 0; }; -static inline void ath9k_htc_exit_debug(struct ath_hw *ah) {}; #endif /* CONFIG_ATH9K_HTC_DEBUGFS */ #endif /* HTC_H */ diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_debug.c b/drivers/net/wireless/ath/ath9k/htc_drv_debug.c index 7394a1b..eca7774 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_debug.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_debug.c @@ -16,8 +16,6 @@ #include "htc.h" -static struct dentry *ath9k_debugfs_root; - static int ath9k_debugfs_open(struct inode *inode, struct file *file) { file->private_data = inode->i_private; @@ -481,100 +479,27 @@ int ath9k_htc_init_debug(struct ath_hw *ah) struct ath_common *common = ath9k_hw_common(ah); struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *) common->priv; - if (!ath9k_debugfs_root) - return -ENOENT; - - priv->debug.debugfs_phy = debugfs_create_dir(wiphy_name(priv->hw->wiphy), - ath9k_debugfs_root); + priv->debug.debugfs_phy = debugfs_create_dir(KBUILD_MODNAME, + priv->hw->wiphy->debugfsdir); if (!priv->debug.debugfs_phy) - goto err; - - priv->debug.debugfs_tgt_int_stats = debugfs_create_file("tgt_int_stats", - S_IRUSR, - priv->debug.debugfs_phy, - priv, &fops_tgt_int_stats); - if (!priv->debug.debugfs_tgt_int_stats) - goto err; - - priv->debug.debugfs_tgt_tx_stats = debugfs_create_file("tgt_tx_stats", - S_IRUSR, - priv->debug.debugfs_phy, - priv, &fops_tgt_tx_stats); - if (!priv->debug.debugfs_tgt_tx_stats) - goto err; - - priv->debug.debugfs_tgt_rx_stats = debugfs_create_file("tgt_rx_stats", - S_IRUSR, - priv->debug.debugfs_phy, - priv, &fops_tgt_rx_stats); - if (!priv->debug.debugfs_tgt_rx_stats) - goto err; - - priv->debug.debugfs_xmit = debugfs_create_file("xmit", S_IRUSR, - priv->debug.debugfs_phy, - priv, &fops_xmit); - if (!priv->debug.debugfs_xmit) - goto err; - - priv->debug.debugfs_recv = debugfs_create_file("recv", S_IRUSR, - priv->debug.debugfs_phy, - priv, &fops_recv); - if (!priv->debug.debugfs_recv) - goto err; - - priv->debug.debugfs_slot = debugfs_create_file("slot", S_IRUSR, - priv->debug.debugfs_phy, - priv, &fops_slot); - if (!priv->debug.debugfs_slot) - goto err; - - priv->debug.debugfs_queue = debugfs_create_file("queue", S_IRUSR, - priv->debug.debugfs_phy, - priv, &fops_queue); - if (!priv->debug.debugfs_queue) - goto err; - - priv->debug.debugfs_debug = debugfs_create_file("debug", - S_IRUSR | S_IWUSR, - priv->debug.debugfs_phy, - priv, &fops_debug); - if (!priv->debug.debugfs_debug) - goto err; - - return 0; - -err: - ath9k_htc_exit_debug(ah); - return -ENOMEM; -} - -void ath9k_htc_exit_debug(struct ath_hw *ah) -{ - struct ath_common *common = ath9k_hw_common(ah); - struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *) common->priv; - - debugfs_remove(priv->debug.debugfs_queue); - debugfs_remove(priv->debug.debugfs_slot); - debugfs_remove(priv->debug.debugfs_recv); - debugfs_remove(priv->debug.debugfs_xmit); - debugfs_remove(priv->debug.debugfs_tgt_int_stats); - debugfs_remove(priv->debug.debugfs_tgt_tx_stats); - debugfs_remove(priv->debug.debugfs_tgt_rx_stats); - debugfs_remove(priv->debug.debugfs_debug); - debugfs_remove(priv->debug.debugfs_phy); -} + return -ENOMEM; -int ath9k_htc_debug_create_root(void) -{ - ath9k_debugfs_root = debugfs_create_dir(KBUILD_MODNAME, NULL); - if (!ath9k_debugfs_root) - return -ENOENT; + debugfs_create_file("tgt_int_stats", S_IRUSR, priv->debug.debugfs_phy, + priv, &fops_tgt_int_stats); + debugfs_create_file("tgt_tx_stats", S_IRUSR, priv->debug.debugfs_phy, + priv, &fops_tgt_tx_stats); + debugfs_create_file("tgt_rx_stats", S_IRUSR, priv->debug.debugfs_phy, + priv, &fops_tgt_rx_stats); + debugfs_create_file("xmit", S_IRUSR, priv->debug.debugfs_phy, + priv, &fops_xmit); + debugfs_create_file("recv", S_IRUSR, priv->debug.debugfs_phy, + priv, &fops_recv); + debugfs_create_file("slot", S_IRUSR, priv->debug.debugfs_phy, + priv, &fops_slot); + debugfs_create_file("queue", S_IRUSR, priv->debug.debugfs_phy, + priv, &fops_queue); + debugfs_create_file("debug", S_IRUSR | S_IWUSR, priv->debug.debugfs_phy, + priv, &fops_debug); return 0; } - -void ath9k_htc_debug_remove_root(void) -{ - debugfs_remove(ath9k_debugfs_root); - ath9k_debugfs_root = NULL; -} diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_init.c b/drivers/net/wireless/ath/ath9k/htc_drv_init.c index 22736eb..06e043b 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_init.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_init.c @@ -140,7 +140,6 @@ static int ath9k_htc_wait_for_target(struct ath9k_htc_priv *priv) static void ath9k_deinit_priv(struct ath9k_htc_priv *priv) { - ath9k_htc_exit_debug(priv->ah); ath9k_hw_deinit(priv->ah); kfree(priv->ah); priv->ah = NULL; @@ -700,12 +699,6 @@ static int ath9k_init_priv(struct ath9k_htc_priv *priv, goto err_hw; } - ret = ath9k_htc_init_debug(ah); - if (ret) { - ath_err(common, "Unable to create debugfs files\n"); - goto err_debug; - } - ret = ath9k_init_queues(priv); if (ret) goto err_queues; @@ -725,8 +718,6 @@ static int ath9k_init_priv(struct ath9k_htc_priv *priv, return 0; err_queues: - ath9k_htc_exit_debug(ah); -err_debug: ath9k_hw_deinit(ah); err_hw: @@ -867,6 +858,12 @@ static int ath9k_init_device(struct ath9k_htc_priv *priv, goto err_world; } + error = ath9k_htc_init_debug(priv->ah); + if (error) { + ath_err(common, "Unable to create debugfs files\n"); + goto err_world; + } + ath_dbg(common, ATH_DBG_CONFIG, "WMI:%d, BCN:%d, CAB:%d, UAPSD:%d, MGMT:%d, " "BE:%d, BK:%d, VI:%d, VO:%d\n", @@ -987,38 +984,20 @@ int ath9k_htc_resume(struct htc_target *htc_handle) static int __init ath9k_htc_init(void) { - int error; - - error = ath9k_htc_debug_create_root(); - if (error < 0) { - printk(KERN_ERR - "ath9k_htc: Unable to create debugfs root: %d\n", - error); - goto err_dbg; - } - - error = ath9k_hif_usb_init(); - if (error < 0) { + if (ath9k_hif_usb_init() < 0) { printk(KERN_ERR "ath9k_htc: No USB devices found," " driver not installed.\n"); - error = -ENODEV; - goto err_usb; + return -ENODEV; } return 0; - -err_usb: - ath9k_htc_debug_remove_root(); -err_dbg: - return error; } module_init(ath9k_htc_init); static void __exit ath9k_htc_exit(void) { ath9k_hif_usb_exit(); - ath9k_htc_debug_remove_root(); printk(KERN_INFO "ath9k_htc: Driver unloaded\n"); } module_exit(ath9k_htc_exit); -- cgit v0.10.2 From 0477ad72a12d4ee3f588de9349012948ea25702b Mon Sep 17 00:00:00 2001 From: Sergei Shtylyov Date: Fri, 15 Apr 2011 19:23:11 +0400 Subject: iwlegacy: use pci_dev->revision Commit be663ab67077fac8e23eb8e231a8c1c94cb32e54 (iwlwifi: split the drivers for agn and legacy devices 3945/4965) added code to read the 4965's revision ID from the PCI configuration register while it's already stored by PCI subsystem in the 'revision' field of 'struct pci_dev'... Signed-off-by: Sergei Shtylyov Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwlegacy/iwl4965-base.c b/drivers/net/wireless/iwlegacy/iwl4965-base.c index 91b3d8b..dd90619 100644 --- a/drivers/net/wireless/iwlegacy/iwl4965-base.c +++ b/drivers/net/wireless/iwlegacy/iwl4965-base.c @@ -3179,7 +3179,7 @@ static void iwl4965_hw_detect(struct iwl_priv *priv) { priv->hw_rev = _iwl_legacy_read32(priv, CSR_HW_REV); priv->hw_wa_rev = _iwl_legacy_read32(priv, CSR_HW_REV_WA_REG); - pci_read_config_byte(priv->pci_dev, PCI_REVISION_ID, &priv->rev_id); + priv->rev_id = priv->pci_dev->revision; IWL_DEBUG_INFO(priv, "HW Revision ID = 0x%X\n", priv->rev_id); } -- cgit v0.10.2 From 7762bb02ce13c191e0a2da159bcb8d9b374b88c4 Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Fri, 15 Apr 2011 16:20:05 -0700 Subject: mac80211: fix debugfs printk format warning Fix printf() format warning (tm_year is long int): net/mac80211/debugfs_sta.c:113: warning: format '%d' expects type 'int', but argument 4 has type 'long int' Signed-off-by: Randy Dunlap Signed-off-by: John W. Linville diff --git a/net/mac80211/debugfs_sta.c b/net/mac80211/debugfs_sta.c index c008232..a01d213 100644 --- a/net/mac80211/debugfs_sta.c +++ b/net/mac80211/debugfs_sta.c @@ -108,7 +108,7 @@ static ssize_t sta_connected_time_read(struct file *file, char __user *userbuf, result.tm_year -= 70; result.tm_mday -= 1; res = scnprintf(buf, sizeof(buf), - "years - %d\nmonths - %d\ndays - %d\nclock - %d:%d:%d\n\n", + "years - %ld\nmonths - %d\ndays - %d\nclock - %d:%d:%d\n\n", result.tm_year, result.tm_mon, result.tm_mday, result.tm_hour, result.tm_min, result.tm_sec); return simple_read_from_buffer(userbuf, count, ppos, buf, res); -- cgit v0.10.2 From 636c4598499eeacce0893dc8d91113b904bd531e Mon Sep 17 00:00:00 2001 From: Yogesh Ashok Powar Date: Fri, 15 Apr 2011 20:50:40 -0700 Subject: mwifiex: remove redundant local variables and comments Remove some local variables (mainly function return values) that are used only once. Also, one dummy function and some wordy comments are removed. Signed-off-by: Yogesh Ashok Powar Signed-off-by: Kiran Divekar Signed-off-by: Bing Zhao Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/mwifiex/11n_rxreorder.c b/drivers/net/wireless/mwifiex/11n_rxreorder.c index 755e5d5..a93c03f 100644 --- a/drivers/net/wireless/mwifiex/11n_rxreorder.c +++ b/drivers/net/wireless/mwifiex/11n_rxreorder.c @@ -27,19 +27,6 @@ #include "11n_rxreorder.h" /* - * This function processes a received packet and forwards - * it to the kernel/upper layer. - */ -static int mwifiex_11n_dispatch_pkt(struct mwifiex_private *priv, void *payload) -{ - int ret = 0; - struct mwifiex_adapter *adapter = priv->adapter; - - ret = mwifiex_process_rx_packet(adapter, (struct sk_buff *) payload); - return ret; -} - -/* * This function dispatches all packets in the Rx reorder table. * * There could be holes in the buffer, which are skipped by the function. @@ -51,7 +38,7 @@ mwifiex_11n_dispatch_pkt_until_start_win(struct mwifiex_private *priv, struct mwifiex_rx_reorder_tbl *rx_reor_tbl_ptr, int start_win) { - int no_pkt_to_send, i, xchg; + int no_pkt_to_send, i; void *rx_tmp_ptr = NULL; unsigned long flags; @@ -68,7 +55,7 @@ mwifiex_11n_dispatch_pkt_until_start_win(struct mwifiex_private *priv, } spin_unlock_irqrestore(&priv->rx_pkt_lock, flags); if (rx_tmp_ptr) - mwifiex_11n_dispatch_pkt(priv, rx_tmp_ptr); + mwifiex_process_rx_packet(priv->adapter, rx_tmp_ptr); } spin_lock_irqsave(&priv->rx_pkt_lock, flags); @@ -76,8 +63,7 @@ mwifiex_11n_dispatch_pkt_until_start_win(struct mwifiex_private *priv, * We don't have a circular buffer, hence use rotation to simulate * circular buffer */ - xchg = rx_reor_tbl_ptr->win_size - no_pkt_to_send; - for (i = 0; i < xchg; ++i) { + for (i = 0; i < rx_reor_tbl_ptr->win_size - no_pkt_to_send; ++i) { rx_reor_tbl_ptr->rx_reorder_ptr[i] = rx_reor_tbl_ptr->rx_reorder_ptr[no_pkt_to_send + i]; rx_reor_tbl_ptr->rx_reorder_ptr[no_pkt_to_send + i] = NULL; @@ -114,7 +100,7 @@ mwifiex_11n_scan_and_dispatch(struct mwifiex_private *priv, rx_tmp_ptr = rx_reor_tbl_ptr->rx_reorder_ptr[i]; rx_reor_tbl_ptr->rx_reorder_ptr[i] = NULL; spin_unlock_irqrestore(&priv->rx_pkt_lock, flags); - mwifiex_11n_dispatch_pkt(priv, rx_tmp_ptr); + mwifiex_process_rx_packet(priv->adapter, rx_tmp_ptr); } spin_lock_irqsave(&priv->rx_pkt_lock, flags); @@ -429,7 +415,7 @@ int mwifiex_11n_rx_reorder_pkt(struct mwifiex_private *priv, tid, ta); if (!rx_reor_tbl_ptr) { if (pkt_type != PKT_TYPE_BAR) - mwifiex_11n_dispatch_pkt(priv, payload); + mwifiex_process_rx_packet(priv->adapter, payload); return 0; } start_win = rx_reor_tbl_ptr->start_win; diff --git a/drivers/net/wireless/mwifiex/cfg80211.c b/drivers/net/wireless/mwifiex/cfg80211.c index 74b6cf2..b99ae26 100644 --- a/drivers/net/wireless/mwifiex/cfg80211.c +++ b/drivers/net/wireless/mwifiex/cfg80211.c @@ -34,22 +34,17 @@ static int mwifiex_cfg80211_channel_type_to_mwifiex_channels(enum nl80211_channel_type channel_type) { - int channel; switch (channel_type) { case NL80211_CHAN_NO_HT: case NL80211_CHAN_HT20: - channel = NO_SEC_CHANNEL; - break; + return NO_SEC_CHANNEL; case NL80211_CHAN_HT40PLUS: - channel = SEC_CHANNEL_ABOVE; - break; + return SEC_CHANNEL_ABOVE; case NL80211_CHAN_HT40MINUS: - channel = SEC_CHANNEL_BELOW; - break; + return SEC_CHANNEL_BELOW; default: - channel = NO_SEC_CHANNEL; + return NO_SEC_CHANNEL; } - return channel; } /* @@ -64,21 +59,16 @@ mwifiex_cfg80211_channel_type_to_mwifiex_channels(enum nl80211_channel_type static enum nl80211_channel_type mwifiex_channels_to_cfg80211_channel_type(int channel_type) { - int channel; switch (channel_type) { case NO_SEC_CHANNEL: - channel = NL80211_CHAN_HT20; - break; + return NL80211_CHAN_HT20; case SEC_CHANNEL_ABOVE: - channel = NL80211_CHAN_HT40PLUS; - break; + return NL80211_CHAN_HT40PLUS; case SEC_CHANNEL_BELOW: - channel = NL80211_CHAN_HT40MINUS; - break; + return NL80211_CHAN_HT40MINUS; default: - channel = NL80211_CHAN_HT20; + return NL80211_CHAN_HT20; } - return channel; } /* @@ -117,10 +107,8 @@ mwifiex_cfg80211_del_key(struct wiphy *wiphy, struct net_device *netdev, u8 key_index, bool pairwise, const u8 *mac_addr) { struct mwifiex_private *priv = mwifiex_cfg80211_get_priv(wiphy); - int ret = 0; - ret = mwifiex_set_encode(priv, NULL, 0, key_index, 1); - if (ret) { + if (mwifiex_set_encode(priv, NULL, 0, key_index, 1)) { wiphy_err(wiphy, "deleting the crypto keys\n"); return -EFAULT; } @@ -137,7 +125,6 @@ mwifiex_cfg80211_set_tx_power(struct wiphy *wiphy, enum nl80211_tx_power_setting type, int dbm) { - int ret = 0; struct mwifiex_private *priv = mwifiex_cfg80211_get_priv(wiphy); struct mwifiex_power_cfg power_cfg; @@ -148,9 +135,7 @@ mwifiex_cfg80211_set_tx_power(struct wiphy *wiphy, power_cfg.is_power_auto = 1; } - ret = mwifiex_set_tx_power(priv, &power_cfg); - - return ret; + return mwifiex_set_tx_power(priv, &power_cfg); } /* @@ -163,7 +148,6 @@ mwifiex_cfg80211_set_power_mgmt(struct wiphy *wiphy, struct net_device *dev, bool enabled, int timeout) { - int ret = 0; struct mwifiex_private *priv = mwifiex_cfg80211_get_priv(wiphy); u32 ps_mode; @@ -173,9 +157,8 @@ mwifiex_cfg80211_set_power_mgmt(struct wiphy *wiphy, " for IEEE power save\n"); ps_mode = enabled; - ret = mwifiex_drv_set_power(priv, &ps_mode); - return ret; + return mwifiex_drv_set_power(priv, &ps_mode); } /* @@ -187,18 +170,15 @@ mwifiex_cfg80211_set_default_key(struct wiphy *wiphy, struct net_device *netdev, bool multicast) { struct mwifiex_private *priv = mwifiex_cfg80211_get_priv(wiphy); - int ret; /* Return if WEP key not configured */ if (priv->sec_info.wep_status == MWIFIEX_802_11_WEP_DISABLED) return 0; - ret = mwifiex_set_encode(priv, NULL, 0, key_index, 0); - - wiphy_dbg(wiphy, "info: set default Tx key index\n"); - - if (ret) + if (mwifiex_set_encode(priv, NULL, 0, key_index, 0)) { + wiphy_err(wiphy, "set default Tx key index\n"); return -EFAULT; + } return 0; } @@ -212,15 +192,12 @@ mwifiex_cfg80211_add_key(struct wiphy *wiphy, struct net_device *netdev, struct key_params *params) { struct mwifiex_private *priv = mwifiex_cfg80211_get_priv(wiphy); - int ret = 0; - ret = mwifiex_set_encode(priv, params->key, params->key_len, - key_index, 0); - - wiphy_dbg(wiphy, "info: crypto keys added\n"); - - if (ret) + if (mwifiex_set_encode(priv, params->key, params->key_len, + key_index, 0)) { + wiphy_err(wiphy, "crypto keys added\n"); return -EFAULT; + } return 0; } @@ -245,7 +222,6 @@ static int mwifiex_send_domain_info_cmd_fw(struct wiphy *wiphy) struct mwifiex_private *priv = mwifiex_cfg80211_get_priv(wiphy); struct mwifiex_adapter *adapter = priv->adapter; struct mwifiex_802_11d_domain_reg *domain_info = &adapter->domain_reg; - int ret = 0; /* Set country code */ domain_info->country_code[0] = priv->country_code[0]; @@ -300,13 +276,14 @@ static int mwifiex_send_domain_info_cmd_fw(struct wiphy *wiphy) } domain_info->no_of_triplet = no_of_triplet; - /* Send cmd to FW to set domain info */ - ret = mwifiex_send_cmd_async(priv, HostCmd_CMD_802_11D_DOMAIN_INFO, - HostCmd_ACT_GEN_SET, 0, NULL); - if (ret) + + if (mwifiex_send_cmd_async(priv, HostCmd_CMD_802_11D_DOMAIN_INFO, + HostCmd_ACT_GEN_SET, 0, NULL)) { wiphy_err(wiphy, "11D: setting domain info in FW\n"); + return -1; + } - return ret; + return 0; } /* @@ -356,7 +333,6 @@ mwifiex_set_rf_channel(struct mwifiex_private *priv, enum nl80211_channel_type channel_type) { struct mwifiex_chan_freq_power cfp; - int ret = 0; struct mwifiex_ds_band_cfg band_cfg; u32 config_bands = 0; struct wiphy *wiphy = priv->wdev->wiphy; @@ -375,14 +351,14 @@ mwifiex_set_rf_channel(struct mwifiex_private *priv, band_cfg.config_bands = config_bands; band_cfg.adhoc_start_band = config_bands; } - /* Set channel offset */ + band_cfg.sec_chan_offset = mwifiex_cfg80211_channel_type_to_mwifiex_channels (channel_type); - ret = mwifiex_set_radio_band_cfg(priv, &band_cfg); - if (ret) + if (mwifiex_set_radio_band_cfg(priv, &band_cfg)) return -EFAULT; + mwifiex_send_domain_info_cmd_fw(wiphy); } @@ -390,20 +366,16 @@ mwifiex_set_rf_channel(struct mwifiex_private *priv, "mode %d\n", config_bands, band_cfg.sec_chan_offset, priv->bss_mode); if (!chan) - return ret; + return 0; memset(&cfp, 0, sizeof(cfp)); cfp.freq = chan->center_freq; - /* Convert frequency to channel */ cfp.channel = ieee80211_frequency_to_channel(chan->center_freq); - ret = mwifiex_bss_set_channel(priv, &cfp); - if (ret) + if (mwifiex_bss_set_channel(priv, &cfp)) return -EFAULT; - ret = mwifiex_drv_change_adhoc_chan(priv, cfp.channel); - - return ret; + return mwifiex_drv_change_adhoc_chan(priv, cfp.channel); } /* @@ -459,17 +431,12 @@ mwifiex_set_frag(struct mwifiex_private *priv, u32 frag_thr) static int mwifiex_set_rts(struct mwifiex_private *priv, u32 rts_thr) { - int ret = 0; - if (rts_thr < MWIFIEX_RTS_MIN_VALUE || rts_thr > MWIFIEX_RTS_MAX_VALUE) rts_thr = MWIFIEX_RTS_MAX_VALUE; - /* Send request to firmware */ - ret = mwifiex_send_cmd_sync(priv, HostCmd_CMD_802_11_SNMP_MIB, + return mwifiex_send_cmd_sync(priv, HostCmd_CMD_802_11_SNMP_MIB, HostCmd_ACT_GEN_SET, RTS_THRESH_I, &rts_thr); - - return ret; } /* @@ -485,8 +452,11 @@ mwifiex_cfg80211_set_wiphy_params(struct wiphy *wiphy, u32 changed) int ret = 0; - if (changed & WIPHY_PARAM_RTS_THRESHOLD) + if (changed & WIPHY_PARAM_RTS_THRESHOLD) { ret = mwifiex_set_rts(priv, wiphy->rts_threshold); + if (ret) + return ret; + } if (changed & WIPHY_PARAM_FRAG_THRESHOLD) ret = mwifiex_set_frag(priv, wiphy->frag_threshold); @@ -598,7 +568,6 @@ mwifiex_cfg80211_get_station(struct wiphy *wiphy, struct net_device *dev, u8 *mac, struct station_info *sinfo) { struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev); - int ret = 0; mwifiex_dump_station_info(priv, sinfo); @@ -607,10 +576,7 @@ mwifiex_cfg80211_get_station(struct wiphy *wiphy, struct net_device *dev, if (memcmp(mac, priv->cfg_bssid, ETH_ALEN)) return -ENOENT; - - ret = mwifiex_dump_station_info(priv, sinfo); - - return ret; + return mwifiex_dump_station_info(priv, sinfo); } /* Supported rates to be advertised to the cfg80211 */ @@ -749,15 +715,13 @@ mwifiex_cfg80211_disconnect(struct wiphy *wiphy, struct net_device *dev, */ static int mwifiex_cfg80211_inform_ibss_bss(struct mwifiex_private *priv) { - int ret = 0; struct ieee80211_channel *chan; struct mwifiex_bss_info bss_info; int ie_len = 0; u8 ie_buf[IEEE80211_MAX_SSID_LEN + sizeof(struct ieee_types_header)]; - ret = mwifiex_get_bss_info(priv, &bss_info); - if (ret) - return ret; + if (mwifiex_get_bss_info(priv, &bss_info)) + return -1; ie_buf[0] = WLAN_EID_SSID; ie_buf[1] = bss_info.ssid.ssid_len; @@ -776,7 +740,7 @@ static int mwifiex_cfg80211_inform_ibss_bss(struct mwifiex_private *priv) 0, ie_buf, ie_len, 0, GFP_KERNEL); memcpy(priv->cfg_bssid, bss_info.bssid, ETH_ALEN); - return ret; + return 0; } /* @@ -805,9 +769,8 @@ static int mwifiex_inform_bss_from_scan_result(struct mwifiex_private *priv, struct mwifiex_bssdescriptor *scan_table; int i, j; struct ieee80211_channel *chan; - u8 *ie, *tmp, *ie_buf; + u8 *ie, *ie_buf; u32 ie_len; - u64 ts = 0; u8 *beacon; int beacon_size; u8 element_id, element_len; @@ -889,9 +852,9 @@ static int mwifiex_inform_bss_from_scan_result(struct mwifiex_private *priv, case WLAN_EID_BSS_AC_ACCESS_DELAY: ie[0] = element_id; ie[1] = element_len; - tmp = (u8 *) beacon; memcpy(&ie[sizeof(struct ieee_types_header)], - tmp + sizeof(struct ieee_types_header), + (u8 *) beacon + + sizeof(struct ieee_types_header), element_len); ie_len += ie[1] + sizeof(struct ieee_types_header); @@ -908,7 +871,7 @@ static int mwifiex_inform_bss_from_scan_result(struct mwifiex_private *priv, scan_table[i].freq); cfg80211_inform_bss(priv->wdev->wiphy, chan, scan_table[i].mac_address, - ts, scan_table[i].cap_info_bitmap, + 0, scan_table[i].cap_info_bitmap, scan_table[i].beacon_period, ie_buf, ie_len, scan_table[i].rssi, GFP_KERNEL); @@ -941,9 +904,7 @@ mwifiex_cfg80211_assoc(struct mwifiex_private *priv, size_t ssid_len, u8 *ssid, struct mwifiex_802_11_ssid req_ssid; struct mwifiex_ssid_bssid ssid_bssid; int ret = 0; - int auth_type = 0, pairwise_encrypt_mode = 0; - int group_encrypt_mode = 0; - int alg_is_wep = 0; + int auth_type = 0; memset(&req_ssid, 0, sizeof(struct mwifiex_802_11_ssid)); memset(&ssid_bssid, 0, sizeof(struct mwifiex_ssid_bssid)); @@ -1009,9 +970,7 @@ mwifiex_cfg80211_assoc(struct mwifiex_private *priv, size_t ssid_len, u8 *ssid, ret = mwifiex_set_gen_ie(priv, sme->ie, sme->ie_len); if (sme->key) { - alg_is_wep = mwifiex_is_alg_wep(pairwise_encrypt_mode) - | mwifiex_is_alg_wep(group_encrypt_mode); - if (alg_is_wep) { + if (mwifiex_is_alg_wep(0) | mwifiex_is_alg_wep(0)) { dev_dbg(priv->adapter->dev, "info: setting wep encryption" " with key len %d\n", sme->key_len); diff --git a/drivers/net/wireless/mwifiex/cfp.c b/drivers/net/wireless/mwifiex/cfp.c index bb73cfe..d0cada5 100644 --- a/drivers/net/wireless/mwifiex/cfp.c +++ b/drivers/net/wireless/mwifiex/cfp.c @@ -145,16 +145,12 @@ u8 mwifiex_data_rate_to_index(u32 rate) */ u32 mwifiex_get_active_data_rates(struct mwifiex_private *priv, u8 *rates) { - u32 k; - if (!priv->media_connected) - k = mwifiex_get_supported_rates(priv, rates); + return mwifiex_get_supported_rates(priv, rates); else - k = mwifiex_copy_rates(rates, 0, + return mwifiex_copy_rates(rates, 0, priv->curr_bss_params.data_rates, priv->curr_bss_params.num_of_rates); - - return k; } /* diff --git a/drivers/net/wireless/mwifiex/init.c b/drivers/net/wireless/mwifiex/init.c index 1b79a5a..fc2c0c5 100644 --- a/drivers/net/wireless/mwifiex/init.c +++ b/drivers/net/wireless/mwifiex/init.c @@ -71,7 +71,6 @@ static int mwifiex_add_bss_prio_tbl(struct mwifiex_private *priv) static int mwifiex_init_priv(struct mwifiex_private *priv) { u32 i; - int ret = 0; priv->media_connected = false; memset(priv->curr_addr, 0xff, ETH_ALEN); @@ -139,9 +138,7 @@ static int mwifiex_init_priv(struct mwifiex_private *priv) priv->scan_block = false; - ret = mwifiex_add_bss_prio_tbl(priv); - - return ret; + return mwifiex_add_bss_prio_tbl(priv); } /* diff --git a/drivers/net/wireless/mwifiex/join.c b/drivers/net/wireless/mwifiex/join.c index 60d25c6..8e1cb4b 100644 --- a/drivers/net/wireless/mwifiex/join.c +++ b/drivers/net/wireless/mwifiex/join.c @@ -749,7 +749,7 @@ int mwifiex_cmd_802_11_ad_hoc_start(struct mwifiex_private *priv, struct host_cmd_ds_command *cmd, void *data_buf) { - int ret = 0, rsn_ie_len = 0; + int rsn_ie_len = 0; struct mwifiex_adapter *adapter = priv->adapter; struct host_cmd_ds_802_11_ad_hoc_start *adhoc_start = &cmd->params.adhoc_start; @@ -879,11 +879,9 @@ mwifiex_cmd_802_11_ad_hoc_start(struct mwifiex_private *priv, mwifiex_get_active_data_rates(priv, adhoc_start->DataRate); if ((adapter->adhoc_start_band & BAND_G) && (priv->curr_pkt_filter & HostCmd_ACT_MAC_ADHOC_G_PROTECTION_ON)) { - ret = mwifiex_send_cmd_async(priv, HostCmd_CMD_MAC_CONTROL, + if (mwifiex_send_cmd_async(priv, HostCmd_CMD_MAC_CONTROL, HostCmd_ACT_GEN_SET, 0, - &priv->curr_pkt_filter); - - if (ret) { + &priv->curr_pkt_filter)) { dev_err(adapter->dev, "ADHOC_S_CMD: G Protection config failed\n"); return -1; @@ -1039,7 +1037,7 @@ int mwifiex_cmd_802_11_ad_hoc_join(struct mwifiex_private *priv, struct host_cmd_ds_command *cmd, void *data_buf) { - int ret = 0, rsn_ie_len = 0; + int rsn_ie_len = 0; struct host_cmd_ds_802_11_ad_hoc_join *adhoc_join = &cmd->params.adhoc_join; struct mwifiex_bssdescriptor *bss_desc = @@ -1060,10 +1058,9 @@ mwifiex_cmd_802_11_ad_hoc_join(struct mwifiex_private *priv, priv-> curr_pkt_filter | HostCmd_ACT_MAC_ADHOC_G_PROTECTION_ON; - ret = mwifiex_send_cmd_async(priv, HostCmd_CMD_MAC_CONTROL, + if (mwifiex_send_cmd_async(priv, HostCmd_CMD_MAC_CONTROL, HostCmd_ACT_GEN_SET, 0, - &curr_pkt_filter); - if (ret) { + &curr_pkt_filter)) { dev_err(priv->adapter->dev, "ADHOC_J_CMD: G Protection config failed\n"); return -1; @@ -1174,7 +1171,7 @@ mwifiex_cmd_802_11_ad_hoc_join(struct mwifiex_private *priv, adhoc_join->bss_descriptor.cap_info_bitmap = cpu_to_le16(tmp_cap); - return ret; + return 0; } /* @@ -1192,15 +1189,13 @@ int mwifiex_ret_802_11_ad_hoc(struct mwifiex_private *priv, struct mwifiex_adapter *adapter = priv->adapter; struct host_cmd_ds_802_11_ad_hoc_result *adhoc_result; struct mwifiex_bssdescriptor *bss_desc; - u16 command = le16_to_cpu(resp->command); - u16 result = le16_to_cpu(resp->result); adhoc_result = &resp->params.adhoc_result; bss_desc = priv->attempted_bss_desc; /* Join result code 0 --> SUCCESS */ - if (result) { + if (le16_to_cpu(resp->result)) { dev_err(priv->adapter->dev, "ADHOC_RESP: failed\n"); if (priv->media_connected) mwifiex_reset_connect_state(priv); @@ -1215,7 +1210,7 @@ int mwifiex_ret_802_11_ad_hoc(struct mwifiex_private *priv, /* Send a Media Connected event, according to the Spec */ priv->media_connected = true; - if (command == HostCmd_CMD_802_11_AD_HOC_START) { + if (le16_to_cpu(resp->command) == HostCmd_CMD_802_11_AD_HOC_START) { dev_dbg(priv->adapter->dev, "info: ADHOC_S_RESP %s\n", bss_desc->ssid.ssid); @@ -1278,7 +1273,6 @@ done: int mwifiex_associate(struct mwifiex_private *priv, struct mwifiex_bssdescriptor *bss_desc) { - int ret = 0; u8 current_bssid[ETH_ALEN]; /* Return error if the adapter or table entry is not marked as infra */ @@ -1294,10 +1288,8 @@ int mwifiex_associate(struct mwifiex_private *priv, retrieval */ priv->assoc_rsp_size = 0; - ret = mwifiex_send_cmd_sync(priv, HostCmd_CMD_802_11_ASSOCIATE, + return mwifiex_send_cmd_sync(priv, HostCmd_CMD_802_11_ASSOCIATE, HostCmd_ACT_GEN_SET, 0, bss_desc); - - return ret; } /* @@ -1309,8 +1301,6 @@ int mwifiex_adhoc_start(struct mwifiex_private *priv, struct mwifiex_802_11_ssid *adhoc_ssid) { - int ret = 0; - dev_dbg(priv->adapter->dev, "info: Adhoc Channel = %d\n", priv->adhoc_channel); dev_dbg(priv->adapter->dev, "info: curr_bss_params.channel = %d\n", @@ -1318,10 +1308,8 @@ mwifiex_adhoc_start(struct mwifiex_private *priv, dev_dbg(priv->adapter->dev, "info: curr_bss_params.band = %d\n", priv->curr_bss_params.band); - ret = mwifiex_send_cmd_sync(priv, HostCmd_CMD_802_11_AD_HOC_START, + return mwifiex_send_cmd_sync(priv, HostCmd_CMD_802_11_AD_HOC_START, HostCmd_ACT_GEN_SET, 0, adhoc_ssid); - - return ret; } /* @@ -1333,8 +1321,6 @@ mwifiex_adhoc_start(struct mwifiex_private *priv, int mwifiex_adhoc_join(struct mwifiex_private *priv, struct mwifiex_bssdescriptor *bss_desc) { - int ret = 0; - dev_dbg(priv->adapter->dev, "info: adhoc join: curr_bss ssid =%s\n", priv->curr_bss_params.bss_descriptor.ssid.ssid); dev_dbg(priv->adapter->dev, "info: adhoc join: curr_bss ssid_len =%u\n", @@ -1360,10 +1346,8 @@ int mwifiex_adhoc_join(struct mwifiex_private *priv, dev_dbg(priv->adapter->dev, "info: curr_bss_params.band = %c\n", priv->curr_bss_params.band); - ret = mwifiex_send_cmd_sync(priv, HostCmd_CMD_802_11_AD_HOC_JOIN, + return mwifiex_send_cmd_sync(priv, HostCmd_CMD_802_11_AD_HOC_JOIN, HostCmd_ACT_GEN_SET, 0, bss_desc); - - return ret; } /* @@ -1424,21 +1408,15 @@ EXPORT_SYMBOL_GPL(mwifiex_deauthenticate); u8 mwifiex_band_to_radio_type(u8 band) { - u8 ret_radio_type; - switch (band) { case BAND_A: case BAND_AN: case BAND_A | BAND_AN: - ret_radio_type = HostCmd_SCAN_RADIO_TYPE_A; - break; + return HostCmd_SCAN_RADIO_TYPE_A; case BAND_B: case BAND_G: case BAND_B | BAND_G: default: - ret_radio_type = HostCmd_SCAN_RADIO_TYPE_BG; - break; + return HostCmd_SCAN_RADIO_TYPE_BG; } - - return ret_radio_type; } diff --git a/drivers/net/wireless/mwifiex/main.c b/drivers/net/wireless/mwifiex/main.c index 77abfc3..2c376dd 100644 --- a/drivers/net/wireless/mwifiex/main.c +++ b/drivers/net/wireless/mwifiex/main.c @@ -68,7 +68,6 @@ static struct mwifiex_drv_mode mwifiex_drv_mode_tbl[] = { static int mwifiex_register(void *card, struct mwifiex_if_ops *if_ops, struct mwifiex_device *mdevice, void **padapter) { - int ret = 0; struct mwifiex_adapter *adapter = NULL; u8 i = 0; @@ -84,8 +83,7 @@ static int mwifiex_register(void *card, struct mwifiex_if_ops *if_ops, memmove(&adapter->if_ops, if_ops, sizeof(struct mwifiex_if_ops)); /* card specific initialization has been deferred until now .. */ - ret = adapter->if_ops.init_if(adapter); - if (ret) + if (adapter->if_ops.init_if(adapter)) goto error; adapter->priv_num = 0; @@ -893,7 +891,6 @@ int mwifiex_add_card(void *card, struct semaphore *sem, struct mwifiex_if_ops *if_ops) { - int status = 0; int i; struct mwifiex_adapter *adapter = NULL; struct mwifiex_drv_mode *drv_mode_info = &mwifiex_drv_mode_tbl[0]; @@ -943,12 +940,9 @@ mwifiex_add_card(void *card, struct semaphore *sem, for (i = 0; i < drv_mode_info->intf_num; i++) { if (!mwifiex_add_interface(adapter, i, adapter->drv_mode->bss_attr[i].bss_type)) { - status = -1; - break; + goto err_add_intf; } } - if (status) - goto err_add_intf; up(sem); @@ -969,8 +963,8 @@ err_kmalloc: (adapter->hw_status == MWIFIEX_HW_STATUS_READY)) { pr_debug("info: %s: shutdown mwifiex\n", __func__); adapter->init_wait_q_woken = false; - status = mwifiex_shutdown_drv(adapter); - if (status == -EINPROGRESS) + + if (mwifiex_shutdown_drv(adapter) == -EINPROGRESS) wait_event_interruptible(adapter->init_wait_q, adapter->init_wait_q_woken); } @@ -999,7 +993,6 @@ EXPORT_SYMBOL_GPL(mwifiex_add_card); int mwifiex_remove_card(struct mwifiex_adapter *adapter, struct semaphore *sem) { struct mwifiex_private *priv = NULL; - int status; int i; if (down_interruptible(sem)) @@ -1023,8 +1016,8 @@ int mwifiex_remove_card(struct mwifiex_adapter *adapter, struct semaphore *sem) dev_dbg(adapter->dev, "cmd: calling mwifiex_shutdown_drv...\n"); adapter->init_wait_q_woken = false; - status = mwifiex_shutdown_drv(adapter); - if (status == -EINPROGRESS) + + if (mwifiex_shutdown_drv(adapter) == -EINPROGRESS) wait_event_interruptible(adapter->init_wait_q, adapter->init_wait_q_woken); dev_dbg(adapter->dev, "cmd: mwifiex_shutdown_drv done\n"); diff --git a/drivers/net/wireless/mwifiex/scan.c b/drivers/net/wireless/mwifiex/scan.c index 8474271..68d905d 100644 --- a/drivers/net/wireless/mwifiex/scan.c +++ b/drivers/net/wireless/mwifiex/scan.c @@ -181,7 +181,6 @@ int mwifiex_find_best_bss(struct mwifiex_private *priv, struct mwifiex_ssid_bssid *ssid_bssid) { struct mwifiex_ssid_bssid tmp_ssid_bssid; - int ret = 0; u8 *mac = NULL; if (!ssid_bssid) @@ -189,17 +188,17 @@ int mwifiex_find_best_bss(struct mwifiex_private *priv, memcpy(&tmp_ssid_bssid, ssid_bssid, sizeof(struct mwifiex_ssid_bssid)); - ret = mwifiex_bss_ioctl_find_bss(priv, &tmp_ssid_bssid); - if (!ret) { + if (!mwifiex_bss_ioctl_find_bss(priv, &tmp_ssid_bssid)) { memcpy(ssid_bssid, &tmp_ssid_bssid, sizeof(struct mwifiex_ssid_bssid)); mac = (u8 *) &ssid_bssid->bssid; dev_dbg(priv->adapter->dev, "cmd: found network: ssid=%s," " %pM\n", ssid_bssid->ssid.ssid, mac); + return 0; } - return ret; + return -1; } /* @@ -2061,19 +2060,13 @@ mwifiex_process_scan_results(struct mwifiex_private *priv) static u8 mwifiex_radio_type_to_band(u8 radio_type) { - u8 ret_band; - switch (radio_type) { case HostCmd_SCAN_RADIO_TYPE_A: - ret_band = BAND_A; - break; + return BAND_A; case HostCmd_SCAN_RADIO_TYPE_BG: default: - ret_band = BAND_G; - break; + return BAND_G; } - - return ret_band; } /* @@ -2226,8 +2219,7 @@ static int mwifiex_scan_delete_ssid_table_entry(struct mwifiex_private *priv, struct mwifiex_802_11_ssid *del_ssid) { - int ret = -1; - s32 table_idx; + s32 table_idx = -1; dev_dbg(priv->adapter->dev, "info: scan: delete ssid entry: %-32s\n", del_ssid->ssid); @@ -2240,11 +2232,10 @@ mwifiex_scan_delete_ssid_table_entry(struct mwifiex_private *priv, dev_dbg(priv->adapter->dev, "info: Scan: Delete SSID Entry: Found Idx = %d\n", table_idx); - ret = 0; mwifiex_scan_delete_table_entry(priv, table_idx); } - return ret; + return table_idx == -1 ? -1 : 0; } /* diff --git a/drivers/net/wireless/mwifiex/sdio.c b/drivers/net/wireless/mwifiex/sdio.c index 41c087d..5148d0e 100644 --- a/drivers/net/wireless/mwifiex/sdio.c +++ b/drivers/net/wireless/mwifiex/sdio.c @@ -347,12 +347,9 @@ static int mwifiex_read_data_sync(struct mwifiex_adapter *adapter, u8 *buffer, */ static int mwifiex_pm_wakeup_card(struct mwifiex_adapter *adapter) { - int ret; - dev_dbg(adapter->dev, "event: wakeup device...\n"); - ret = mwifiex_write_reg(adapter, CONFIGURATION_REG, HOST_POWER_UP); - return ret; + return mwifiex_write_reg(adapter, CONFIGURATION_REG, HOST_POWER_UP); } /* @@ -362,12 +359,9 @@ static int mwifiex_pm_wakeup_card(struct mwifiex_adapter *adapter) */ static int mwifiex_pm_wakeup_card_complete(struct mwifiex_adapter *adapter) { - int ret; - dev_dbg(adapter->dev, "cmd: wakeup device completed\n"); - ret = mwifiex_write_reg(adapter, CONFIGURATION_REG, 0); - return ret; + return mwifiex_write_reg(adapter, CONFIGURATION_REG, 0); } /* @@ -1703,13 +1697,9 @@ static struct mwifiex_if_ops sdio_ops = { static int mwifiex_sdio_init_module(void) { - int ret; - sema_init(&add_remove_card_sem, 1); - ret = sdio_register_driver(&mwifiex_sdio); - - return ret; + return sdio_register_driver(&mwifiex_sdio); } /* diff --git a/drivers/net/wireless/mwifiex/sta_ioctl.c b/drivers/net/wireless/mwifiex/sta_ioctl.c index 6489f26..03085a3 100644 --- a/drivers/net/wireless/mwifiex/sta_ioctl.c +++ b/drivers/net/wireless/mwifiex/sta_ioctl.c @@ -216,7 +216,7 @@ int mwifiex_bss_start(struct mwifiex_private *priv, ret = mwifiex_adhoc_join(priv, &adapter->scan_table[i]); if (ret) return ret; - } else { /* i >= 0 */ + } else { dev_dbg(adapter->dev, "info: Network not found in " "the list, creating adhoc with ssid = %s\n", ssid_bssid->ssid.ssid); @@ -320,16 +320,13 @@ int mwifiex_set_hs_params(struct mwifiex_private *priv, u16 action, */ int mwifiex_cancel_hs(struct mwifiex_private *priv, int cmd_type) { - int ret = 0; struct mwifiex_ds_hs_cfg hscfg; - /* Cancel Host Sleep */ hscfg.conditions = HOST_SLEEP_CFG_CANCEL; hscfg.is_invoke_hostcmd = true; - ret = mwifiex_set_hs_params(priv, HostCmd_ACT_GEN_SET, - cmd_type, &hscfg); - return ret; + return mwifiex_set_hs_params(priv, HostCmd_ACT_GEN_SET, + cmd_type, &hscfg); } EXPORT_SYMBOL_GPL(mwifiex_cancel_hs); @@ -348,7 +345,6 @@ int mwifiex_enable_hs(struct mwifiex_adapter *adapter) return true; } - /* Enable Host Sleep */ adapter->hs_activate_wait_q_woken = false; memset(&hscfg, 0, sizeof(struct mwifiex_hs_config_param)); @@ -385,23 +381,17 @@ int mwifiex_get_bss_info(struct mwifiex_private *priv, if (!info) return -1; - /* Get current BSS info */ bss_desc = &priv->curr_bss_params.bss_descriptor; - /* BSS mode */ info->bss_mode = priv->bss_mode; - /* SSID */ memcpy(&info->ssid, &bss_desc->ssid, sizeof(struct mwifiex_802_11_ssid)); - /* BSSID */ memcpy(&info->bssid, &bss_desc->mac_address, ETH_ALEN); - /* Channel */ info->bss_chan = bss_desc->channel; - /* Region code */ info->region_code = adapter->region_code; /* Scan table index if connected */ @@ -415,20 +405,15 @@ int mwifiex_get_bss_info(struct mwifiex_private *priv, info->scan_table_idx = tbl_idx; } - /* Connection status */ info->media_connected = priv->media_connected; - /* Tx power information */ info->max_power_level = priv->max_tx_power_level; info->min_power_level = priv->min_tx_power_level; - /* AdHoc state */ info->adhoc_state = priv->adhoc_state; - /* Last beacon NF */ info->bcn_nf_last = priv->bcn_nf_last; - /* wep status */ if (priv->sec_info.wep_status == MWIFIEX_802_11_WEP_ENABLED) info->wep_status = true; else @@ -574,22 +559,17 @@ int mwifiex_bss_set_channel(struct mwifiex_private *priv, static int mwifiex_bss_ioctl_ibss_channel(struct mwifiex_private *priv, u16 action, u16 *channel) { - int ret = 0; - if (action == HostCmd_ACT_GEN_GET) { if (!priv->media_connected) { *channel = priv->adhoc_channel; - return ret; + return 0; } } else { priv->adhoc_channel = (u8) *channel; } - /* Send request to firmware */ - ret = mwifiex_send_cmd_sync(priv, HostCmd_CMD_802_11_RF_CHANNEL, + return mwifiex_send_cmd_sync(priv, HostCmd_CMD_802_11_RF_CHANNEL, action, 0, channel); - - return ret; } /* @@ -602,7 +582,6 @@ int mwifiex_bss_ioctl_find_bss(struct mwifiex_private *priv, struct mwifiex_ssid_bssid *ssid_bssid) { struct mwifiex_adapter *adapter = priv->adapter; - int ret = 0; struct mwifiex_bssdescriptor *bss_desc; u8 zero_mac[ETH_ALEN] = { 0, 0, 0, 0, 0, 0 }; u8 mac[ETH_ALEN]; @@ -631,10 +610,10 @@ int mwifiex_bss_ioctl_find_bss(struct mwifiex_private *priv, bss_desc = &adapter->scan_table[i]; memcpy(ssid_bssid->bssid, bss_desc->mac_address, ETH_ALEN); } else { - ret = mwifiex_find_best_network(priv, ssid_bssid); + return mwifiex_find_best_network(priv, ssid_bssid); } - return ret; + return 0; } /* @@ -718,7 +697,6 @@ static int mwifiex_rate_ioctl_get_rate_value(struct mwifiex_private *priv, struct mwifiex_rate_cfg *rate_cfg) { struct mwifiex_adapter *adapter = priv->adapter; - int ret = 0; rate_cfg->is_rate_auto = priv->is_data_rate_auto; if (!priv->media_connected) { @@ -757,13 +735,12 @@ static int mwifiex_rate_ioctl_get_rate_value(struct mwifiex_private *priv, break; } } else { - /* Send request to firmware */ - ret = mwifiex_send_cmd_sync(priv, + return mwifiex_send_cmd_sync(priv, HostCmd_CMD_802_11_TX_RATE_QUERY, HostCmd_ACT_GEN_GET, 0, NULL); } - return ret; + return 0; } /* @@ -827,7 +804,6 @@ static int mwifiex_rate_ioctl_set_rate_value(struct mwifiex_private *priv, } } - /* Send request to firmware */ ret = mwifiex_send_cmd_sync(priv, HostCmd_CMD_TX_RATE_CFG, HostCmd_ACT_GEN_SET, 0, bitmap_rates); @@ -969,7 +945,6 @@ int mwifiex_set_tx_power(struct mwifiex_private *priv, pg->power_max = (s8) dbm; pg->ht_bandwidth = HT_BW_40; } - /* Send request to firmware */ ret = mwifiex_send_cmd_sync(priv, HostCmd_CMD_TXPWR_CFG, HostCmd_ACT_GEN_SET, 0, buf); @@ -1088,13 +1063,10 @@ static int mwifiex_set_wapi_ie(struct mwifiex_private *priv, static int mwifiex_sec_ioctl_set_wapi_key(struct mwifiex_private *priv, struct mwifiex_ds_encrypt_key *encrypt_key) { - int ret = 0; - ret = mwifiex_send_cmd_sync(priv, HostCmd_CMD_802_11_KEY_MATERIAL, + return mwifiex_send_cmd_sync(priv, HostCmd_CMD_802_11_KEY_MATERIAL, HostCmd_ACT_GEN_SET, KEY_INFO_ENABLED, encrypt_key); - - return ret; } /* @@ -1128,7 +1100,6 @@ static int mwifiex_sec_ioctl_set_wep_key(struct mwifiex_private *priv, priv->sec_info.wep_status = MWIFIEX_802_11_WEP_ENABLED; } else { wep_key = &priv->wep_key[index]; - /* Cleanup */ memset(wep_key, 0, sizeof(struct mwifiex_wep_key)); /* Copy the key in the driver */ memcpy(wep_key->key_material, @@ -1151,7 +1122,6 @@ static int mwifiex_sec_ioctl_set_wep_key(struct mwifiex_private *priv, else priv->curr_pkt_filter &= ~HostCmd_ACT_MAC_WEP_ENABLE; - /* Send request to firmware */ ret = mwifiex_send_cmd_sync(priv, HostCmd_CMD_MAC_CONTROL, HostCmd_ACT_GEN_SET, 0, &priv->curr_pkt_filter); @@ -1216,13 +1186,11 @@ static int mwifiex_sec_ioctl_set_wpa_key(struct mwifiex_private *priv, encrypt_key->key_index = MWIFIEX_KEY_INDEX_UNICAST; if (remove_key) - /* Send request to firmware */ ret = mwifiex_send_cmd_sync(priv, HostCmd_CMD_802_11_KEY_MATERIAL, HostCmd_ACT_GEN_SET, !(KEY_INFO_ENABLED), encrypt_key); else - /* Send request to firmware */ ret = mwifiex_send_cmd_sync(priv, HostCmd_CMD_802_11_KEY_MATERIAL, HostCmd_ACT_GEN_SET, KEY_INFO_ENABLED, @@ -1297,7 +1265,6 @@ int mwifiex_get_signal_info(struct mwifiex_private *priv, return -1; } - /* Send request to firmware */ status = mwifiex_send_cmd_sync(priv, HostCmd_CMD_RSSI_INFO, HostCmd_ACT_GEN_GET, 0, signal); @@ -1324,7 +1291,6 @@ int mwifiex_set_encode(struct mwifiex_private *priv, const u8 *key, int key_len, u8 key_index, int disable) { struct mwifiex_ds_encrypt_key encrypt_key; - int ret = 0; memset(&encrypt_key, 0, sizeof(struct mwifiex_ds_encrypt_key)); encrypt_key.key_len = key_len; @@ -1336,9 +1302,7 @@ int mwifiex_set_encode(struct mwifiex_private *priv, const u8 *key, encrypt_key.key_disable = true; } - ret = mwifiex_sec_ioctl_encrypt_key(priv, &encrypt_key); - - return ret; + return mwifiex_sec_ioctl_encrypt_key(priv, &encrypt_key); } /* @@ -1351,18 +1315,13 @@ int mwifiex_get_ver_ext(struct mwifiex_private *priv) { struct mwifiex_ver_ext ver_ext; - int ret = 0; - /* get fw version */ memset(&ver_ext, 0, sizeof(struct host_cmd_ds_version_ext)); - /* Send request to firmware */ - ret = mwifiex_send_cmd_sync(priv, HostCmd_CMD_VERSION_EXT, - HostCmd_ACT_GEN_GET, 0, &ver_ext); - - if (ret) - ret = -1; + if (mwifiex_send_cmd_sync(priv, HostCmd_CMD_VERSION_EXT, + HostCmd_ACT_GEN_GET, 0, &ver_ext)) + return -1; - return ret; + return 0; } /* @@ -1379,7 +1338,6 @@ mwifiex_get_stats_info(struct mwifiex_private *priv, struct mwifiex_ds_get_stats get_log; memset(&get_log, 0, sizeof(struct mwifiex_ds_get_stats)); - /* Send request to firmware */ ret = mwifiex_send_cmd_sync(priv, HostCmd_CMD_802_11_GET_LOG, HostCmd_ACT_GEN_GET, 0, &get_log); @@ -1412,7 +1370,6 @@ static int mwifiex_reg_mem_ioctl_reg_rw(struct mwifiex_private *priv, struct mwifiex_ds_reg_rw *reg_rw, u16 action) { - int ret = 0; u16 cmd_no; switch (le32_to_cpu(reg_rw->type)) { @@ -1435,10 +1392,8 @@ static int mwifiex_reg_mem_ioctl_reg_rw(struct mwifiex_private *priv, return -1; } - /* Send request to firmware */ - ret = mwifiex_send_cmd_sync(priv, cmd_no, action, 0, reg_rw); + return mwifiex_send_cmd_sync(priv, cmd_no, action, 0, reg_rw); - return ret; } /* @@ -1451,15 +1406,13 @@ int mwifiex_reg_write(struct mwifiex_private *priv, u32 reg_type, u32 reg_offset, u32 reg_value) { - int ret = 0; struct mwifiex_ds_reg_rw reg_rw; reg_rw.type = cpu_to_le32(reg_type); reg_rw.offset = cpu_to_le32(reg_offset); reg_rw.value = cpu_to_le32(reg_value); - ret = mwifiex_reg_mem_ioctl_reg_rw(priv, ®_rw, HostCmd_ACT_GEN_SET); - return ret; + return mwifiex_reg_mem_ioctl_reg_rw(priv, ®_rw, HostCmd_ACT_GEN_SET); } /* @@ -1638,7 +1591,6 @@ int mwifiex_set_gen_ie(struct mwifiex_private *priv, u8 *ie, int ie_len) { struct mwifiex_ds_misc_gen_ie gen_ie; - int status = 0; if (ie_len > IW_CUSTOM_MAX) return -EFAULT; @@ -1646,8 +1598,7 @@ mwifiex_set_gen_ie(struct mwifiex_private *priv, u8 *ie, int ie_len) gen_ie.type = MWIFIEX_IE_TYPE_GEN_IE; gen_ie.len = ie_len; memcpy(gen_ie.ie_data, ie, ie_len); - status = mwifiex_misc_ioctl_gen_ie(priv, &gen_ie, HostCmd_ACT_GEN_SET); - if (status) + if (mwifiex_misc_ioctl_gen_ie(priv, &gen_ie, HostCmd_ACT_GEN_SET)) return -EFAULT; return 0; diff --git a/drivers/net/wireless/mwifiex/sta_tx.c b/drivers/net/wireless/mwifiex/sta_tx.c index b261d81..5d37ef1 100644 --- a/drivers/net/wireless/mwifiex/sta_tx.c +++ b/drivers/net/wireless/mwifiex/sta_tx.c @@ -180,15 +180,11 @@ mwifiex_check_last_packet_indication(struct mwifiex_private *priv) { struct mwifiex_adapter *adapter = priv->adapter; u8 ret = false; - u8 prop_ps = true; if (!adapter->sleep_period.period) return ret; - if (mwifiex_wmm_lists_empty(adapter)) { - if ((priv->curr_bss_params.wmm_uapsd_enabled && - priv->wmm_qosinfo) || prop_ps) + if (mwifiex_wmm_lists_empty(adapter)) ret = true; - } if (ret && !adapter->cmd_sent && !adapter->curr_cmd && !is_command_pending(adapter)) { diff --git a/drivers/net/wireless/mwifiex/txrx.c b/drivers/net/wireless/mwifiex/txrx.c index f06923c..ce772e0 100644 --- a/drivers/net/wireless/mwifiex/txrx.c +++ b/drivers/net/wireless/mwifiex/txrx.c @@ -36,7 +36,6 @@ int mwifiex_handle_rx_packet(struct mwifiex_adapter *adapter, struct sk_buff *skb) { - int ret = 0; struct mwifiex_private *priv = mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_ANY); struct rxpd *local_rx_pd; @@ -50,9 +49,8 @@ int mwifiex_handle_rx_packet(struct mwifiex_adapter *adapter, priv = mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_ANY); rx_info->bss_index = priv->bss_index; - ret = mwifiex_process_sta_rx_packet(adapter, skb); - return ret; + return mwifiex_process_sta_rx_packet(adapter, skb); } EXPORT_SYMBOL_GPL(mwifiex_handle_rx_packet); diff --git a/drivers/net/wireless/mwifiex/util.c b/drivers/net/wireless/mwifiex/util.c index 9f65587..7ab4fb2 100644 --- a/drivers/net/wireless/mwifiex/util.c +++ b/drivers/net/wireless/mwifiex/util.c @@ -61,7 +61,6 @@ int mwifiex_shutdown_fw_complete(struct mwifiex_adapter *adapter) int mwifiex_init_shutdown_fw(struct mwifiex_private *priv, u32 func_init_shutdown) { - int ret; u16 cmd; if (func_init_shutdown == MWIFIEX_FUNC_INIT) { @@ -73,10 +72,7 @@ int mwifiex_init_shutdown_fw(struct mwifiex_private *priv, return -1; } - /* Send command to firmware */ - ret = mwifiex_send_cmd_sync(priv, cmd, HostCmd_ACT_GEN_SET, 0, NULL); - - return ret; + return mwifiex_send_cmd_sync(priv, cmd, HostCmd_ACT_GEN_SET, 0, NULL); } EXPORT_SYMBOL_GPL(mwifiex_init_shutdown_fw); diff --git a/drivers/net/wireless/mwifiex/wmm.c b/drivers/net/wireless/mwifiex/wmm.c index 99e8431..c009370 100644 --- a/drivers/net/wireless/mwifiex/wmm.c +++ b/drivers/net/wireless/mwifiex/wmm.c @@ -973,7 +973,6 @@ mwifiex_send_single_packet(struct mwifiex_private *priv, struct sk_buff *skb, *skb_next; struct mwifiex_tx_param tx_param; struct mwifiex_adapter *adapter = priv->adapter; - int status = 0; struct mwifiex_txinfo *tx_info; if (skb_queue_empty(&ptr->skb_head)) { @@ -1000,9 +999,7 @@ mwifiex_send_single_packet(struct mwifiex_private *priv, tx_param.next_pkt_len = ((skb_next) ? skb_next->len + sizeof(struct txpd) : 0); - status = mwifiex_process_tx(priv, skb, &tx_param); - - if (status == -EBUSY) { + if (mwifiex_process_tx(priv, skb, &tx_param) == -EBUSY) { /* Queue the packet back at the head */ spin_lock_irqsave(&priv->wmm.ra_list_spinlock, ra_list_flags); -- cgit v0.10.2 From a37316586d926a10d66b5585c5d91683d6468f68 Mon Sep 17 00:00:00 2001 From: Amitkumar Karwar Date: Fri, 15 Apr 2011 20:50:41 -0700 Subject: mwifiex: remove some macro definitions use corresponding macros defined in include/linux/ieee80211.h Signed-off-by: Amitkumar Karwar Signed-off-by: Bing Zhao Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/mwifiex/11n.c b/drivers/net/wireless/mwifiex/11n.c index d64065f..e22d761 100644 --- a/drivers/net/wireless/mwifiex/11n.c +++ b/drivers/net/wireless/mwifiex/11n.c @@ -115,7 +115,7 @@ mwifiex_fill_cap_info(struct mwifiex_private *priv, SETHT_MCS32(ht_cap->ht_cap.mcs.rx_mask); /* Clear RD responder bit */ - RESETHT_EXTCAP_RDG(ht_ext_cap); + ht_ext_cap &= ~IEEE80211_HT_EXT_CAP_RD_RESPONDER; ht_cap->ht_cap.cap_info = cpu_to_le16(ht_cap_info); ht_cap->ht_cap.extended_ht_cap_info = cpu_to_le16(ht_ext_cap); diff --git a/drivers/net/wireless/mwifiex/fw.h b/drivers/net/wireless/mwifiex/fw.h index f8c008f..6d1c454 100644 --- a/drivers/net/wireless/mwifiex/fw.h +++ b/drivers/net/wireless/mwifiex/fw.h @@ -134,7 +134,6 @@ enum MWIFIEX_802_11_WEP_STATUS { #define MWIFIEX_TX_DATA_BUF_SIZE_4K 4096 #define MWIFIEX_TX_DATA_BUF_SIZE_8K 8192 -#define NON_GREENFIELD_STAS 0x04 #define ISSUPP_11NENABLED(FwCapInfo) (FwCapInfo & BIT(11)) @@ -159,7 +158,6 @@ enum MWIFIEX_802_11_WEP_STATUS { #define ISSUPP_GREENFIELD(Dot11nDevCap) (Dot11nDevCap & BIT(29)) #define GET_RXMCSSUPP(DevMCSSupported) (DevMCSSupported & 0x0f) -#define RESETHT_EXTCAP_RDG(HTExtCap) (HTExtCap &= ~BIT(11)) #define SETHT_MCS32(x) (x[4] |= 1) #define SET_SECONDARYCHAN(RadioType, SECCHAN) (RadioType |= (SECCHAN << 4)) diff --git a/drivers/net/wireless/mwifiex/ioctl.h b/drivers/net/wireless/mwifiex/ioctl.h index 703a6d1..5488e11 100644 --- a/drivers/net/wireless/mwifiex/ioctl.h +++ b/drivers/net/wireless/mwifiex/ioctl.h @@ -268,14 +268,13 @@ struct mwifiex_debug_info { }; #define MWIFIEX_KEY_INDEX_UNICAST 0x40000000 -#define MWIFIEX_MAX_KEY_LENGTH 32 #define WAPI_RXPN_LEN 16 struct mwifiex_ds_encrypt_key { u32 key_disable; u32 key_index; u32 key_len; - u8 key_material[MWIFIEX_MAX_KEY_LENGTH]; + u8 key_material[WLAN_MAX_KEY_LEN]; u8 mac_addr[ETH_ALEN]; u32 is_wapi_key; u8 wapi_rxpn[WAPI_RXPN_LEN]; diff --git a/drivers/net/wireless/mwifiex/join.c b/drivers/net/wireless/mwifiex/join.c index 8e1cb4b..23d2d0b 100644 --- a/drivers/net/wireless/mwifiex/join.c +++ b/drivers/net/wireless/mwifiex/join.c @@ -995,7 +995,7 @@ mwifiex_cmd_802_11_ad_hoc_start(struct mwifiex_private *priv, IEEE80211_HT_PARAM_CHAN_WIDTH_ANY; } ht_info->ht_info.operation_mode = - cpu_to_le16(NON_GREENFIELD_STAS); + cpu_to_le16(IEEE80211_HT_OP_MODE_NON_GF_STA_PRSNT); ht_info->ht_info.basic_set[0] = 0xff; pos += sizeof(struct mwifiex_ie_types_htinfo); cmd_append_size += diff --git a/drivers/net/wireless/mwifiex/sta_ioctl.c b/drivers/net/wireless/mwifiex/sta_ioctl.c index 03085a3..e7adaab 100644 --- a/drivers/net/wireless/mwifiex/sta_ioctl.c +++ b/drivers/net/wireless/mwifiex/sta_ioctl.c @@ -1147,7 +1147,7 @@ static int mwifiex_sec_ioctl_set_wpa_key(struct mwifiex_private *priv, struct host_cmd_ds_802_11_key_material *ibss_key; /* Current driver only supports key length of up to 32 bytes */ - if (encrypt_key->key_len > MWIFIEX_MAX_KEY_LENGTH) { + if (encrypt_key->key_len > WLAN_MAX_KEY_LEN) { dev_err(priv->adapter->dev, "key length too long\n"); return -1; } -- cgit v0.10.2 From 2be7859f41e9bcef5b15bd23d63e01536344e3df Mon Sep 17 00:00:00 2001 From: Amitkumar Karwar Date: Fri, 15 Apr 2011 20:50:42 -0700 Subject: mwifiex: optimize driver initialization code 1) removal of unnecessary mwifiex_device structure 2) avoid passing adapter pointer to mwifiex_init_sw() 3) remove local variable drv_mode_info in mwifiex_add_card() 4) type change in mwifiex_bss_attr to match mwifiex_private 5) removal of more wordy comments Signed-off-by: Amitkumar Karwar Signed-off-by: Bing Zhao Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/mwifiex/decl.h b/drivers/net/wireless/mwifiex/decl.h index 8364b62..0e90b09 100644 --- a/drivers/net/wireless/mwifiex/decl.h +++ b/drivers/net/wireless/mwifiex/decl.h @@ -113,11 +113,11 @@ struct mwifiex_txinfo { }; struct mwifiex_bss_attr { - u32 bss_type; - u32 frame_type; - u32 active; - u32 bss_priority; - u32 bss_num; + u8 bss_type; + u8 frame_type; + u8 active; + u8 bss_priority; + u8 bss_num; }; enum mwifiex_wmm_ac_e { @@ -126,8 +126,4 @@ enum mwifiex_wmm_ac_e { WMM_AC_VI, WMM_AC_VO } __packed; - -struct mwifiex_device { - struct mwifiex_bss_attr bss_attr[MWIFIEX_MAX_BSS_NUM]; -}; #endif /* !_MWIFIEX_DECL_H_ */ diff --git a/drivers/net/wireless/mwifiex/main.c b/drivers/net/wireless/mwifiex/main.c index 2c376dd..c597188 100644 --- a/drivers/net/wireless/mwifiex/main.c +++ b/drivers/net/wireless/mwifiex/main.c @@ -40,14 +40,10 @@ static char fw_name[32] = DEFAULT_FW_NAME; /* Supported drv_mode table */ static struct mwifiex_drv_mode mwifiex_drv_mode_tbl[] = { { - /* drv_mode */ - .drv_mode = DRV_MODE_STA, - /* intf number */ - .intf_num = ARRAY_SIZE(mwifiex_bss_sta), - /* bss_attr */ - .bss_attr = mwifiex_bss_sta, - } - , + .drv_mode = DRV_MODE_STA, + .intf_num = ARRAY_SIZE(mwifiex_bss_sta), + .bss_attr = mwifiex_bss_sta, + }, }; /* @@ -66,13 +62,12 @@ static struct mwifiex_drv_mode mwifiex_drv_mode_tbl[] = { * proper cleanup before exiting. */ static int mwifiex_register(void *card, struct mwifiex_if_ops *if_ops, - struct mwifiex_device *mdevice, void **padapter) + struct mwifiex_drv_mode *drv_mode_ptr) { - struct mwifiex_adapter *adapter = NULL; - u8 i = 0; + struct mwifiex_adapter *adapter; + int i; adapter = kzalloc(sizeof(struct mwifiex_adapter), GFP_KERNEL); - /* Allocate memory for adapter structure */ if (!adapter) return -1; @@ -87,14 +82,13 @@ static int mwifiex_register(void *card, struct mwifiex_if_ops *if_ops, goto error; adapter->priv_num = 0; - for (i = 0; i < MWIFIEX_MAX_BSS_NUM; i++) { + for (i = 0; i < drv_mode_ptr->intf_num; i++) { adapter->priv[i] = NULL; - if (!mdevice->bss_attr[i].active) + if (!drv_mode_ptr->bss_attr[i].active) continue; - /* For valid bss_attr, - allocate memory for private structure */ + /* Allocate memory for private structure */ adapter->priv[i] = kzalloc(sizeof(struct mwifiex_private), GFP_KERNEL); if (!adapter->priv[i]) { @@ -104,26 +98,26 @@ static int mwifiex_register(void *card, struct mwifiex_if_ops *if_ops, } adapter->priv_num++; - memset(adapter->priv[i], 0, - sizeof(struct mwifiex_private)); adapter->priv[i]->adapter = adapter; /* Save bss_type, frame_type & bss_priority */ - adapter->priv[i]->bss_type = (u8) mdevice->bss_attr[i].bss_type; + adapter->priv[i]->bss_type = drv_mode_ptr->bss_attr[i].bss_type; adapter->priv[i]->frame_type = - (u8) mdevice->bss_attr[i].frame_type; + drv_mode_ptr->bss_attr[i].frame_type; adapter->priv[i]->bss_priority = - (u8) mdevice->bss_attr[i].bss_priority; - if (mdevice->bss_attr[i].bss_type == MWIFIEX_BSS_TYPE_STA) + drv_mode_ptr->bss_attr[i].bss_priority; + + if (drv_mode_ptr->bss_attr[i].bss_type == MWIFIEX_BSS_TYPE_STA) adapter->priv[i]->bss_role = MWIFIEX_BSS_ROLE_STA; - else if (mdevice->bss_attr[i].bss_type == MWIFIEX_BSS_TYPE_UAP) + else if (drv_mode_ptr->bss_attr[i].bss_type == + MWIFIEX_BSS_TYPE_UAP) adapter->priv[i]->bss_role = MWIFIEX_BSS_ROLE_UAP; /* Save bss_index & bss_num */ adapter->priv[i]->bss_index = i; - adapter->priv[i]->bss_num = mdevice->bss_attr[i].bss_num; + adapter->priv[i]->bss_num = drv_mode_ptr->bss_attr[i].bss_num; } + adapter->drv_mode = drv_mode_ptr; - /* Initialize lock variables */ if (mwifiex_init_lock_list(adapter)) goto error; @@ -131,16 +125,13 @@ static int mwifiex_register(void *card, struct mwifiex_if_ops *if_ops, adapter->cmd_timer.function = mwifiex_cmd_timeout_func; adapter->cmd_timer.data = (unsigned long) adapter; - /* Return pointer of struct mwifiex_adapter */ - *padapter = adapter; return 0; error: dev_dbg(adapter->dev, "info: leave mwifiex_register with error\n"); - /* Free lock variables */ mwifiex_free_lock_list(adapter); - for (i = 0; i < MWIFIEX_MAX_BSS_NUM; i++) + for (i = 0; i < drv_mode_ptr->intf_num; i++) kfree(adapter->priv[i]); kfree(adapter); @@ -335,10 +326,9 @@ exit_main_proc: * and initializing the private structures. */ static int -mwifiex_init_sw(void *card, struct mwifiex_if_ops *if_ops, void **pmwifiex) +mwifiex_init_sw(void *card, struct mwifiex_if_ops *if_ops) { int i; - struct mwifiex_device device; struct mwifiex_drv_mode *drv_mode_ptr; /* find mwifiex_drv_mode entry from mwifiex_drv_mode_tbl */ @@ -355,20 +345,7 @@ mwifiex_init_sw(void *card, struct mwifiex_if_ops *if_ops, void **pmwifiex) return -1; } - memset(&device, 0, sizeof(struct mwifiex_device)); - - for (i = 0; i < drv_mode_ptr->intf_num; i++) { - device.bss_attr[i].bss_type = - drv_mode_ptr->bss_attr[i].bss_type; - device.bss_attr[i].frame_type = - drv_mode_ptr->bss_attr[i].frame_type; - device.bss_attr[i].active = drv_mode_ptr->bss_attr[i].active; - device.bss_attr[i].bss_priority = - drv_mode_ptr->bss_attr[i].bss_priority; - device.bss_attr[i].bss_num = drv_mode_ptr->bss_attr[i].bss_num; - } - - if (mwifiex_register(card, if_ops, &device, pmwifiex)) + if (mwifiex_register(card, if_ops, drv_mode_ptr)) return -1; return 0; @@ -892,21 +869,19 @@ mwifiex_add_card(void *card, struct semaphore *sem, struct mwifiex_if_ops *if_ops) { int i; - struct mwifiex_adapter *adapter = NULL; - struct mwifiex_drv_mode *drv_mode_info = &mwifiex_drv_mode_tbl[0]; + struct mwifiex_adapter *adapter; if (down_interruptible(sem)) goto exit_sem_err; - if (mwifiex_init_sw(card, if_ops, (void **) &adapter)) { + if (mwifiex_init_sw(card, if_ops)) { pr_err("%s: software init failed\n", __func__); goto err_init_sw; } - adapter->drv_mode = drv_mode_info; + adapter = g_adapter; adapter->hw_status = MWIFIEX_HW_STATUS_INITIALIZING; - /* PnP and power profile */ adapter->surprise_removed = false; init_waitqueue_head(&adapter->init_wait_q); adapter->is_suspended = false; @@ -917,7 +892,6 @@ mwifiex_add_card(void *card, struct semaphore *sem, adapter->cmd_wait_q.condition = false; adapter->cmd_wait_q.status = 0; - /* Create workqueue */ adapter->workqueue = create_workqueue("MWIFIEX_WORK_QUEUE"); if (!adapter->workqueue) goto err_kmalloc; @@ -931,13 +905,13 @@ mwifiex_add_card(void *card, struct semaphore *sem, goto err_registerdev; } - /* Init FW and HW */ if (mwifiex_init_hw_fw(adapter)) { pr_err("%s: firmware init failed\n", __func__); goto err_init_fw; } + /* Add interfaces */ - for (i = 0; i < drv_mode_info->intf_num; i++) { + for (i = 0; i < adapter->drv_mode->intf_num; i++) { if (!mwifiex_add_interface(adapter, i, adapter->drv_mode->bss_attr[i].bss_type)) { goto err_add_intf; @@ -952,7 +926,6 @@ err_add_intf: for (i = 0; i < adapter->priv_num; i++) mwifiex_remove_interface(adapter, i); err_init_fw: - /* Unregister device */ pr_debug("info: %s: unregister device\n", __func__); adapter->if_ops.unregister_dev(adapter); err_registerdev: diff --git a/drivers/net/wireless/mwifiex/main.h b/drivers/net/wireless/mwifiex/main.h index 2d296dc..1b50303 100644 --- a/drivers/net/wireless/mwifiex/main.h +++ b/drivers/net/wireless/mwifiex/main.h @@ -872,7 +872,7 @@ mwifiex_copy_rates(u8 *dest, u32 pos, u8 *src, int len) */ static inline struct mwifiex_private * mwifiex_get_priv_by_id(struct mwifiex_adapter *adapter, - u32 bss_num, u32 bss_type) + u8 bss_num, u8 bss_type) { int i; -- cgit v0.10.2 From cea3235cf578b5e952f5a0cec9bc6c2e862eb697 Mon Sep 17 00:00:00 2001 From: Rajkumar Manoharan Date: Sat, 16 Apr 2011 14:17:39 +0530 Subject: ath9k_htc: Fix free slot value for cab queue ath9k_htc_tx_get_slot can return zero as valid index. Signed-off-by: Rajkumar Manoharan Acked-by: Sujith Manoharan Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c b/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c index bf7ef1b..a157107 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c @@ -322,7 +322,7 @@ static void ath9k_htc_send_buffered(struct ath9k_htc_priv *priv, } tx_slot = ath9k_htc_tx_get_slot(priv); - if (tx_slot != 0) { + if (tx_slot < 0) { ath_dbg(common, ATH_DBG_XMIT, "No free CAB slot\n"); dev_kfree_skb_any(skb); goto next; -- cgit v0.10.2 From dcf55fb5d43bd82e1e3bf94f065cfe8f75a4bc5a Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Sun, 17 Apr 2011 17:45:00 +0200 Subject: mac80211: add a function for setting the TIM bit for a specific station This allows a driver to buffer frames for a PS station and tell mac80211 to wake it up even though mac80211 does not have any buffered frames for it. This is necessary for properly handling aggregation related buffering, in ath9k, because the driver needs to keep its frames in order to keep track of the Block-ACK window. Signed-off-by: Felix Fietkau Signed-off-by: John W. Linville diff --git a/include/net/mac80211.h b/include/net/mac80211.h index 361bc5d..162363b 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -2227,6 +2227,18 @@ static inline int ieee80211_sta_ps_transition_ni(struct ieee80211_sta *sta, #define IEEE80211_TX_STATUS_HEADROOM 13 /** + * ieee80211_sta_set_tim - set the TIM bit for a sleeping station + * + * If a driver buffers frames for a powersave station instead of passing + * them back to mac80211 for retransmission, the station needs to be told + * to wake up using the TIM bitmap in the beacon. + * + * This function sets the station's TIM bit - it will be cleared when the + * station wakes up. + */ +void ieee80211_sta_set_tim(struct ieee80211_sta *sta); + +/** * ieee80211_tx_status - transmit status callback * * Call this function for all transmitted frames after they have been diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c index 8a9068a..7c5c6da 100644 --- a/net/mac80211/sta_info.c +++ b/net/mac80211/sta_info.c @@ -612,7 +612,8 @@ static bool sta_info_cleanup_expire_buffered(struct ieee80211_local *local, #endif dev_kfree_skb(skb); - if (skb_queue_empty(&sta->ps_tx_buf)) + if (skb_queue_empty(&sta->ps_tx_buf) && + !test_sta_flags(sta, WLAN_STA_PS_DRIVER_BUF)) sta_info_clear_tim_bit(sta); } @@ -896,6 +897,7 @@ void ieee80211_sta_ps_deliver_wakeup(struct sta_info *sta) struct ieee80211_local *local = sdata->local; int sent, buffered; + clear_sta_flags(sta, WLAN_STA_PS_DRIVER_BUF); if (!(local->hw.flags & IEEE80211_HW_AP_LINK_PS)) drv_sta_notify(local, sdata, STA_NOTIFY_AWAKE, &sta->sta); @@ -988,3 +990,12 @@ void ieee80211_sta_block_awake(struct ieee80211_hw *hw, ieee80211_queue_work(hw, &sta->drv_unblock_wk); } EXPORT_SYMBOL(ieee80211_sta_block_awake); + +void ieee80211_sta_set_tim(struct ieee80211_sta *pubsta) +{ + struct sta_info *sta = container_of(pubsta, struct sta_info, sta); + + set_sta_flags(sta, WLAN_STA_PS_DRIVER_BUF); + sta_info_set_tim_bit(sta); +} +EXPORT_SYMBOL(ieee80211_sta_set_tim); diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h index 984a03d..af1a7f8 100644 --- a/net/mac80211/sta_info.h +++ b/net/mac80211/sta_info.h @@ -43,6 +43,8 @@ * be in the queues * @WLAN_STA_PSPOLL: Station sent PS-poll while driver was keeping * station in power-save mode, reply when the driver unblocks. + * @WLAN_STA_PS_DRIVER_BUF: Station has frames pending in driver internal + * buffers. Automatically cleared on station wake-up. */ enum ieee80211_sta_info_flags { WLAN_STA_AUTH = 1<<0, @@ -58,6 +60,7 @@ enum ieee80211_sta_info_flags { WLAN_STA_BLOCK_BA = 1<<11, WLAN_STA_PS_DRIVER = 1<<12, WLAN_STA_PSPOLL = 1<<13, + WLAN_STA_PS_DRIVER_BUF = 1<<14, }; #define STA_TID_NUM 16 -- cgit v0.10.2 From 8e22ad323fb5b7cefb572bd8730e3abef95cdf90 Mon Sep 17 00:00:00 2001 From: Rajkumar Manoharan Date: Sun, 17 Apr 2011 21:38:10 +0530 Subject: ath9k: Fix beacon generation on foreign channel While leaving the oper channel, beacon generation is stopped by mac80211 and beacon slots are marked as inactive. During the scan, ath9k configures beacon timers based on IEEE80211_CONF_OFFCHANNEL which inturn generates beacon alert even though bslot is inactive. ath9k fails to disable beacon alert while moving to offchannel if none of the beacon slot is active. This is causing beacon transmission on foreign channel. This patch enables swba based on active bslots. This issue was reported with two vifs (AP+STA) and triggered scan in STA vif in unassociated state. Signed-off-by: Rajkumar Manoharan Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/beacon.c b/drivers/net/wireless/ath/ath9k/beacon.c index 9193a38..24f565b 100644 --- a/drivers/net/wireless/ath/ath9k/beacon.c +++ b/drivers/net/wireless/ath/ath9k/beacon.c @@ -746,6 +746,25 @@ void ath_beacon_config(struct ath_softc *sc, struct ieee80211_vif *vif) ath_set_beacon(sc); } +static bool ath_has_valid_bslot(struct ath_softc *sc) +{ + struct ath_vif *avp; + int slot; + bool found = false; + + for (slot = 0; slot < ATH_BCBUF; slot++) { + if (sc->beacon.bslot[slot]) { + avp = (void *)sc->beacon.bslot[slot]->drv_priv; + if (avp->is_bslot_active) { + found = true; + break; + } + } + } + return found; +} + + void ath_set_beacon(struct ath_softc *sc) { struct ath_common *common = ath9k_hw_common(sc->sc_ah); @@ -753,7 +772,8 @@ void ath_set_beacon(struct ath_softc *sc) switch (sc->sc_ah->opmode) { case NL80211_IFTYPE_AP: - ath_beacon_config_ap(sc, cur_conf); + if (ath_has_valid_bslot(sc)) + ath_beacon_config_ap(sc, cur_conf); break; case NL80211_IFTYPE_ADHOC: case NL80211_IFTYPE_MESH_POINT: @@ -780,20 +800,8 @@ void ath_set_beacon(struct ath_softc *sc) void ath9k_set_beaconing_status(struct ath_softc *sc, bool status) { struct ath_hw *ah = sc->sc_ah; - struct ath_vif *avp; - int slot; - bool found = false; - for (slot = 0; slot < ATH_BCBUF; slot++) { - if (sc->beacon.bslot[slot]) { - avp = (void *)sc->beacon.bslot[slot]->drv_priv; - if (avp->is_bslot_active) { - found = true; - break; - } - } - } - if (!found) + if (!ath_has_valid_bslot(sc)) return; ath9k_ps_wakeup(sc); -- cgit v0.10.2 From 5519541d5a5f19893546883547e2f0f2e5934df7 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Sun, 17 Apr 2011 23:28:09 +0200 Subject: ath9k: fix powersave frame filtering/buffering in AP mode This patch fixes a long standing issue of pending packets in the queue being sent (and retransmitted many times) to sleeping stations. This was made worse by aggregation through driver-internal retransmitting of A-MDPU subframes. Previously the hardware tx filter was cleared unconditionally for every single packet - with this patch it uses the IEEE80211_TX_CTL_CLEAR_PS_FILT for unaggregated frames. A sta_notify driver op is added to stop aggregation for stations when they enter powersave mode. Subframes stay buffered inside the driver, to ensure that the BlockAck window keeps a sane state. Since the driver uses software aggregation, the clearing of the tx filter needs to be handled by the driver instead of mac80211 for aggregated frames. Signed-off-by: Felix Fietkau Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/ar9002_mac.c b/drivers/net/wireless/ath/ath9k/ar9002_mac.c index 8dd8f63..c338efb 100644 --- a/drivers/net/wireless/ath/ath9k/ar9002_mac.c +++ b/drivers/net/wireless/ath/ath9k/ar9002_mac.c @@ -290,7 +290,6 @@ static void ar9002_hw_set11n_txdesc(struct ath_hw *ah, void *ds, | (flags & ATH9K_TXDESC_VMF ? AR_VirtMoreFrag : 0) | SM(txPower, AR_XmitPower) | (flags & ATH9K_TXDESC_VEOL ? AR_VEOL : 0) - | (flags & ATH9K_TXDESC_CLRDMASK ? AR_ClrDestMask : 0) | (flags & ATH9K_TXDESC_INTREQ ? AR_TxIntrReq : 0) | (keyIx != ATH9K_TXKEYIX_INVALID ? AR_DestIdxValid : 0); @@ -311,6 +310,16 @@ static void ar9002_hw_set11n_txdesc(struct ath_hw *ah, void *ds, } } +static void ar9002_hw_set_clrdmask(struct ath_hw *ah, void *ds, bool val) +{ + struct ar5416_desc *ads = AR5416DESC(ds); + + if (val) + ads->ds_ctl0 |= AR_ClrDestMask; + else + ads->ds_ctl0 &= ~AR_ClrDestMask; +} + static void ar9002_hw_set11n_ratescenario(struct ath_hw *ah, void *ds, void *lastds, u32 durUpdateEn, u32 rtsctsRate, @@ -448,4 +457,5 @@ void ar9002_hw_attach_mac_ops(struct ath_hw *ah) ops->set11n_aggr_last = ar9002_hw_set11n_aggr_last; ops->clr11n_aggr = ar9002_hw_clr11n_aggr; ops->set11n_burstduration = ar9002_hw_set11n_burstduration; + ops->set_clrdmask = ar9002_hw_set_clrdmask; } diff --git a/drivers/net/wireless/ath/ath9k/ar9003_mac.c b/drivers/net/wireless/ath/ath9k/ar9003_mac.c index 724ac24..c1264d6 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_mac.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_mac.c @@ -329,7 +329,6 @@ static void ar9003_hw_set11n_txdesc(struct ath_hw *ah, void *ds, | (flags & ATH9K_TXDESC_VMF ? AR_VirtMoreFrag : 0) | SM(txpower, AR_XmitPower) | (flags & ATH9K_TXDESC_VEOL ? AR_VEOL : 0) - | (flags & ATH9K_TXDESC_CLRDMASK ? AR_ClrDestMask : 0) | (keyIx != ATH9K_TXKEYIX_INVALID ? AR_DestIdxValid : 0) | (flags & ATH9K_TXDESC_LOWRXCHAIN ? AR_LowRxChain : 0); @@ -350,6 +349,16 @@ static void ar9003_hw_set11n_txdesc(struct ath_hw *ah, void *ds, ads->ctl22 = 0; } +static void ar9003_hw_set_clrdmask(struct ath_hw *ah, void *ds, bool val) +{ + struct ar9003_txc *ads = (struct ar9003_txc *) ds; + + if (val) + ads->ctl11 |= AR_ClrDestMask; + else + ads->ctl11 &= ~AR_ClrDestMask; +} + static void ar9003_hw_set11n_ratescenario(struct ath_hw *ah, void *ds, void *lastds, u32 durUpdateEn, u32 rtsctsRate, @@ -510,6 +519,7 @@ void ar9003_hw_attach_mac_ops(struct ath_hw *hw) ops->set11n_aggr_last = ar9003_hw_set11n_aggr_last; ops->clr11n_aggr = ar9003_hw_clr11n_aggr; ops->set11n_burstduration = ar9003_hw_set11n_burstduration; + ops->set_clrdmask = ar9003_hw_set_clrdmask; } void ath9k_hw_set_rx_bufsize(struct ath_hw *ah, u16 buf_size) diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h index 77ad407..a2ddabf 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h @@ -200,6 +200,7 @@ struct ath_atx_ac { int sched; struct list_head list; struct list_head tid_q; + bool clear_ps_filter; }; struct ath_frame_info { @@ -257,6 +258,8 @@ struct ath_node { struct ath_atx_ac ac[WME_NUM_AC]; u16 maxampdu; u8 mpdudensity; + + bool sleeping; }; #define AGGR_CLEANUP BIT(1) @@ -338,6 +341,9 @@ int ath_tx_aggr_start(struct ath_softc *sc, struct ieee80211_sta *sta, void ath_tx_aggr_stop(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid); void ath_tx_aggr_resume(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid); +void ath_tx_aggr_wakeup(struct ath_softc *sc, struct ath_node *an); +bool ath_tx_aggr_sleep(struct ath_softc *sc, struct ath_node *an); + /********/ /* VIFs */ /********/ diff --git a/drivers/net/wireless/ath/ath9k/hw-ops.h b/drivers/net/wireless/ath/ath9k/hw-ops.h index 22ee888..9dd90a8 100644 --- a/drivers/net/wireless/ath/ath9k/hw-ops.h +++ b/drivers/net/wireless/ath/ath9k/hw-ops.h @@ -122,6 +122,11 @@ static inline void ath9k_hw_set11n_burstduration(struct ath_hw *ah, void *ds, ath9k_hw_ops(ah)->set11n_burstduration(ah, ds, burstDuration); } +static inline void ath9k_hw_set_clrdmask(struct ath_hw *ah, void *ds, bool val) +{ + ath9k_hw_ops(ah)->set_clrdmask(ah, ds, val); +} + /* Private hardware call ops */ /* PHY ops */ diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h index 073bc9e..1018d6c 100644 --- a/drivers/net/wireless/ath/ath9k/hw.h +++ b/drivers/net/wireless/ath/ath9k/hw.h @@ -626,6 +626,7 @@ struct ath_hw_ops { void (*clr11n_aggr)(struct ath_hw *ah, void *ds); void (*set11n_burstduration)(struct ath_hw *ah, void *ds, u32 burstDuration); + void (*set_clrdmask)(struct ath_hw *ah, void *ds, bool val); }; struct ath_nf_limits { diff --git a/drivers/net/wireless/ath/ath9k/mac.h b/drivers/net/wireless/ath/ath9k/mac.h index b2b2ff8..a60edb4 100644 --- a/drivers/net/wireless/ath/ath9k/mac.h +++ b/drivers/net/wireless/ath/ath9k/mac.h @@ -239,7 +239,6 @@ struct ath_desc { void *ds_vdata; } __packed __aligned(4); -#define ATH9K_TXDESC_CLRDMASK 0x0001 #define ATH9K_TXDESC_NOACK 0x0002 #define ATH9K_TXDESC_RTSENA 0x0004 #define ATH9K_TXDESC_CTSENA 0x0008 diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index a55a892..01df587 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -1749,6 +1749,27 @@ static int ath9k_sta_remove(struct ieee80211_hw *hw, return 0; } +static void ath9k_sta_notify(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + enum sta_notify_cmd cmd, + struct ieee80211_sta *sta) +{ + struct ath_softc *sc = hw->priv; + struct ath_node *an = (struct ath_node *) sta->drv_priv; + + switch (cmd) { + case STA_NOTIFY_SLEEP: + an->sleeping = true; + if (ath_tx_aggr_sleep(sc, an)) + ieee80211_sta_set_tim(sta); + break; + case STA_NOTIFY_AWAKE: + an->sleeping = false; + ath_tx_aggr_wakeup(sc, an); + break; + } +} + static int ath9k_conf_tx(struct ieee80211_hw *hw, u16 queue, const struct ieee80211_tx_queue_params *params) { @@ -2230,6 +2251,7 @@ struct ieee80211_ops ath9k_ops = { .configure_filter = ath9k_configure_filter, .sta_add = ath9k_sta_add, .sta_remove = ath9k_sta_remove, + .sta_notify = ath9k_sta_notify, .conf_tx = ath9k_conf_tx, .bss_info_changed = ath9k_bss_info_changed, .set_key = ath9k_set_key, diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c index 5943bdc..48ff8c2 100644 --- a/drivers/net/wireless/ath/ath9k/xmit.c +++ b/drivers/net/wireless/ath/ath9k/xmit.c @@ -357,6 +357,7 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq, struct ath_frame_info *fi; int nframes; u8 tidno; + bool clear_filter; skb = bf->bf_mpdu; hdr = (struct ieee80211_hdr *)skb->data; @@ -441,22 +442,24 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq, /* transmit completion */ acked_cnt++; } else { - if (!(tid->state & AGGR_CLEANUP) && retry) { - if (fi->retries < ATH_MAX_SW_RETRIES) { - ath_tx_set_retry(sc, txq, bf->bf_mpdu); - txpending = 1; - } else { - bf->bf_state.bf_type |= BUF_XRETRY; - txfail = 1; - sendbar = 1; - txfail_cnt++; - } - } else { + if ((tid->state & AGGR_CLEANUP) || !retry) { /* * cleanup in progress, just fail * the un-acked sub-frames */ txfail = 1; + } else if (fi->retries < ATH_MAX_SW_RETRIES) { + if (!(ts->ts_status & ATH9K_TXERR_FILT) || + !an->sleeping) + ath_tx_set_retry(sc, txq, bf->bf_mpdu); + + clear_filter = true; + txpending = 1; + } else { + bf->bf_state.bf_type |= BUF_XRETRY; + txfail = 1; + sendbar = 1; + txfail_cnt++; } } @@ -496,6 +499,7 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq, !txfail, sendbar); } else { /* retry the un-acked ones */ + ath9k_hw_set_clrdmask(sc->sc_ah, bf->bf_desc, false); if (!(sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA)) { if (bf->bf_next == NULL && bf_last->bf_stale) { struct ath_buf *tbf; @@ -546,7 +550,12 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq, /* prepend un-acked frames to the beginning of the pending frame queue */ if (!list_empty(&bf_pending)) { + if (an->sleeping) + ieee80211_sta_set_tim(sta); + spin_lock_bh(&txq->axq_lock); + if (clear_filter) + tid->ac->clear_ps_filter = true; list_splice(&bf_pending, &tid->buf_q); ath_tx_queue_tid(txq, tid); spin_unlock_bh(&txq->axq_lock); @@ -816,6 +825,11 @@ static void ath_tx_sched_aggr(struct ath_softc *sc, struct ath_txq *txq, bf = list_first_entry(&bf_q, struct ath_buf, list); bf->bf_lastbf = list_entry(bf_q.prev, struct ath_buf, list); + if (tid->ac->clear_ps_filter) { + tid->ac->clear_ps_filter = false; + ath9k_hw_set_clrdmask(sc->sc_ah, bf->bf_desc, true); + } + /* if only one frame, send as non-aggregate */ if (bf == bf->bf_lastbf) { fi = get_frame_info(bf->bf_mpdu); @@ -896,6 +910,67 @@ void ath_tx_aggr_stop(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid) ath_tx_flush_tid(sc, txtid); } +bool ath_tx_aggr_sleep(struct ath_softc *sc, struct ath_node *an) +{ + struct ath_atx_tid *tid; + struct ath_atx_ac *ac; + struct ath_txq *txq; + bool buffered = false; + int tidno; + + for (tidno = 0, tid = &an->tid[tidno]; + tidno < WME_NUM_TID; tidno++, tid++) { + + if (!tid->sched) + continue; + + ac = tid->ac; + txq = ac->txq; + + spin_lock_bh(&txq->axq_lock); + + if (!list_empty(&tid->buf_q)) + buffered = true; + + tid->sched = false; + list_del(&tid->list); + + if (ac->sched) { + ac->sched = false; + list_del(&ac->list); + } + + spin_unlock_bh(&txq->axq_lock); + } + + return buffered; +} + +void ath_tx_aggr_wakeup(struct ath_softc *sc, struct ath_node *an) +{ + struct ath_atx_tid *tid; + struct ath_atx_ac *ac; + struct ath_txq *txq; + int tidno; + + for (tidno = 0, tid = &an->tid[tidno]; + tidno < WME_NUM_TID; tidno++, tid++) { + + ac = tid->ac; + txq = ac->txq; + + spin_lock_bh(&txq->axq_lock); + ac->clear_ps_filter = true; + + if (!list_empty(&tid->buf_q) && !tid->paused) { + ath_tx_queue_tid(txq, tid); + ath_txq_schedule(sc, txq); + } + + spin_unlock_bh(&txq->axq_lock); + } +} + void ath_tx_aggr_resume(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid) { struct ath_atx_tid *txtid; @@ -1491,7 +1566,6 @@ static int setup_tx_flags(struct sk_buff *skb) struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); int flags = 0; - flags |= ATH9K_TXDESC_CLRDMASK; /* needed for crypto errors */ flags |= ATH9K_TXDESC_INTREQ; if (tx_info->flags & IEEE80211_TX_CTL_NO_ACK) @@ -1754,6 +1828,9 @@ static void ath_tx_start_dma(struct ath_softc *sc, struct ath_buf *bf, if (txctl->paprd) bf->bf_state.bfs_paprd_timestamp = jiffies; + if (tx_info->flags & IEEE80211_TX_CTL_CLEAR_PS_FILT) + ath9k_hw_set_clrdmask(sc->sc_ah, bf->bf_desc, true); + ath_tx_send_normal(sc, txctl->txq, tid, &bf_head); } -- cgit v0.10.2 From 93ae2dd2230393566738a5f211ffbaa33b056d56 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Sun, 17 Apr 2011 23:28:10 +0200 Subject: ath9k: assign keycache slots to unencrypted stations Frame filtering relies on having a valid destination index (keycache slot), to keep track of the destination. Assigning a keycache slot (configured to unencrypted, with no key data attached) improves powersave handling in AP mode with no encryption. The dummy keycache entry for a station is cleared, when a real key gets added. Signed-off-by: Felix Fietkau Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h index a2ddabf..a6b5388 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h @@ -256,6 +256,8 @@ struct ath_node { #endif struct ath_atx_tid tid[WME_NUM_TID]; struct ath_atx_ac ac[WME_NUM_AC]; + int ps_key; + u16 maxampdu; u8 mpdudensity; diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index 01df587..e7d6d98 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -1732,18 +1732,37 @@ static int ath9k_sta_add(struct ieee80211_hw *hw, struct ieee80211_sta *sta) { struct ath_softc *sc = hw->priv; + struct ath_common *common = ath9k_hw_common(sc->sc_ah); + struct ath_node *an = (struct ath_node *) sta->drv_priv; + struct ieee80211_key_conf ps_key = { }; ath_node_attach(sc, sta); + an->ps_key = ath_key_config(common, vif, sta, &ps_key); return 0; } +static void ath9k_del_ps_key(struct ath_softc *sc, + struct ieee80211_vif *vif, + struct ieee80211_sta *sta) +{ + struct ath_common *common = ath9k_hw_common(sc->sc_ah); + struct ath_node *an = (struct ath_node *) sta->drv_priv; + struct ieee80211_key_conf ps_key = { .hw_key_idx = an->ps_key }; + + if (!an->ps_key) + return; + + ath_key_delete(common, &ps_key); +} + static int ath9k_sta_remove(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_sta *sta) { struct ath_softc *sc = hw->priv; + ath9k_del_ps_key(sc, vif, sta); ath_node_detach(sc, sta); return 0; @@ -1844,6 +1863,9 @@ static int ath9k_set_key(struct ieee80211_hw *hw, switch (cmd) { case SET_KEY: + if (sta) + ath9k_del_ps_key(sc, vif, sta); + ret = ath_key_config(common, vif, sta, key); if (ret >= 0) { key->hw_key_idx = ret; diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c index 48ff8c2..65d46c6 100644 --- a/drivers/net/wireless/ath/ath9k/xmit.c +++ b/drivers/net/wireless/ath/ath9k/xmit.c @@ -1526,7 +1526,7 @@ static void setup_frame_info(struct ieee80211_hw *hw, struct sk_buff *skb, struct ieee80211_key_conf *hw_key = tx_info->control.hw_key; struct ieee80211_hdr *hdr; struct ath_frame_info *fi = get_frame_info(skb); - struct ath_node *an; + struct ath_node *an = NULL; struct ath_atx_tid *tid; enum ath9k_key_type keytype; u16 seqno = 0; @@ -1534,11 +1534,13 @@ static void setup_frame_info(struct ieee80211_hw *hw, struct sk_buff *skb, keytype = ath9k_cmn_get_hw_crypto_keytype(skb); + if (sta) + an = (struct ath_node *) sta->drv_priv; + hdr = (struct ieee80211_hdr *)skb->data; - if (sta && ieee80211_is_data_qos(hdr->frame_control) && + if (an && ieee80211_is_data_qos(hdr->frame_control) && conf_is_ht(&hw->conf) && (sc->sc_flags & SC_OP_TXAGGR)) { - an = (struct ath_node *) sta->drv_priv; tidno = ieee80211_get_qos_ctl(hdr)[0] & IEEE80211_QOS_CTL_TID_MASK; /* @@ -1554,6 +1556,8 @@ static void setup_frame_info(struct ieee80211_hw *hw, struct sk_buff *skb, memset(fi, 0, sizeof(*fi)); if (hw_key) fi->keyix = hw_key->hw_key_idx; + else if (an && ieee80211_is_data(hdr->frame_control) && an->ps_key > 0) + fi->keyix = an->ps_key; else fi->keyix = ATH9K_TXKEYIX_INVALID; fi->keytype = keytype; diff --git a/drivers/net/wireless/ath/key.c b/drivers/net/wireless/ath/key.c index 0d4f39c..a61ef3d6 100644 --- a/drivers/net/wireless/ath/key.c +++ b/drivers/net/wireless/ath/key.c @@ -483,6 +483,9 @@ int ath_key_config(struct ath_common *common, memset(&hk, 0, sizeof(hk)); switch (key->cipher) { + case 0: + hk.kv_type = ATH_CIPHER_CLR; + break; case WLAN_CIPHER_SUITE_WEP40: case WLAN_CIPHER_SUITE_WEP104: hk.kv_type = ATH_CIPHER_WEP; @@ -498,7 +501,8 @@ int ath_key_config(struct ath_common *common, } hk.kv_len = key->keylen; - memcpy(hk.kv_val, key->key, key->keylen); + if (key->keylen) + memcpy(hk.kv_val, key->key, key->keylen); if (!(key->flags & IEEE80211_KEY_FLAG_PAIRWISE)) { switch (vif->type) { -- cgit v0.10.2 From 44704e5d7d56625ff93d5a119ca846ae4de9061c Mon Sep 17 00:00:00 2001 From: Layne Edwards Date: Mon, 18 Apr 2011 15:26:00 +0200 Subject: rt2x00: Enable WLAN LED on Ralink SoC (rt305x) devices This patch adds WLAN LED support to the mac80211 rt2x00 driver for Ralink SoC (rt305x) devices. The current WLAN LED drivers in rt2800lib.c set the LED brightness via an MCU request, but do nothing for SoC. This patch checks for SoC and sets the register to enable the WLAN LED (instead of an MCU request). This enables the WLAN LED for RT305x devices. Signed-off-by: Layne Edwards Signed-off-by: Ivo van Doorn Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/rt2x00/rt2800lib.c b/drivers/net/wireless/rt2x00/rt2800lib.c index 769c05c..13ccc1b 100644 --- a/drivers/net/wireless/rt2x00/rt2800lib.c +++ b/drivers/net/wireless/rt2x00/rt2800lib.c @@ -949,25 +949,49 @@ static void rt2800_brightness_set(struct led_classdev *led_cdev, unsigned int ledmode = rt2x00_get_field16(led->rt2x00dev->led_mcu_reg, EEPROM_FREQ_LED_MODE); + u32 reg; - if (led->type == LED_TYPE_RADIO) { - rt2800_mcu_request(led->rt2x00dev, MCU_LED, 0xff, ledmode, - enabled ? 0x20 : 0); - } else if (led->type == LED_TYPE_ASSOC) { - rt2800_mcu_request(led->rt2x00dev, MCU_LED, 0xff, ledmode, - enabled ? (bg_mode ? 0x60 : 0xa0) : 0x20); - } else if (led->type == LED_TYPE_QUALITY) { - /* - * The brightness is divided into 6 levels (0 - 5), - * The specs tell us the following levels: - * 0, 1 ,3, 7, 15, 31 - * to determine the level in a simple way we can simply - * work with bitshifting: - * (1 << level) - 1 - */ - rt2800_mcu_request(led->rt2x00dev, MCU_LED_STRENGTH, 0xff, - (1 << brightness / (LED_FULL / 6)) - 1, - polarity); + /* Check for SoC (SOC devices don't support MCU requests) */ + if (rt2x00_is_soc(led->rt2x00dev)) { + rt2800_register_read(led->rt2x00dev, LED_CFG, ®); + + /* Set LED Polarity */ + rt2x00_set_field32(®, LED_CFG_LED_POLAR, polarity); + + /* Set LED Mode */ + if (led->type == LED_TYPE_RADIO) { + rt2x00_set_field32(®, LED_CFG_G_LED_MODE, + enabled ? 3 : 0); + } else if (led->type == LED_TYPE_ASSOC) { + rt2x00_set_field32(®, LED_CFG_Y_LED_MODE, + enabled ? 3 : 0); + } else if (led->type == LED_TYPE_QUALITY) { + rt2x00_set_field32(®, LED_CFG_R_LED_MODE, + enabled ? 3 : 0); + } + + rt2800_register_write(led->rt2x00dev, LED_CFG, reg); + + } else { + if (led->type == LED_TYPE_RADIO) { + rt2800_mcu_request(led->rt2x00dev, MCU_LED, 0xff, ledmode, + enabled ? 0x20 : 0); + } else if (led->type == LED_TYPE_ASSOC) { + rt2800_mcu_request(led->rt2x00dev, MCU_LED, 0xff, ledmode, + enabled ? (bg_mode ? 0x60 : 0xa0) : 0x20); + } else if (led->type == LED_TYPE_QUALITY) { + /* + * The brightness is divided into 6 levels (0 - 5), + * The specs tell us the following levels: + * 0, 1 ,3, 7, 15, 31 + * to determine the level in a simple way we can simply + * work with bitshifting: + * (1 << level) - 1 + */ + rt2800_mcu_request(led->rt2x00dev, MCU_LED_STRENGTH, 0xff, + (1 << brightness / (LED_FULL / 6)) - 1, + polarity); + } } } -- cgit v0.10.2 From 62fe778412b36791b7897cfa139342906fbbf07b Mon Sep 17 00:00:00 2001 From: Helmut Schaa Date: Mon, 18 Apr 2011 15:26:37 +0200 Subject: rt2x00: Fix stuck queue in tx failure case Since commit 0b7fde54f94979edc67bbf86b5adba702ebfefe8 "rt2x00: Protect queue control with mutex" rt2x00 used rt2x00queue_pause_queue for stopping a tx queue in mac80211. But in case of a failure in the tx path rt2x00 still called ieee80211_stop_queue which stopped the queue but prevented rt2x00queue_unpause_queue to wake the queue up again resulting in a stuck tx queue. Fix this by also using rt2x00queue_pause_queue in case of tx failures. Signed-off-by: Helmut Schaa Signed-off-by: Ivo van Doorn Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/rt2x00/rt2x00mac.c b/drivers/net/wireless/rt2x00/rt2x00mac.c index 661c6ba..4a1c41b 100644 --- a/drivers/net/wireless/rt2x00/rt2x00mac.c +++ b/drivers/net/wireless/rt2x00/rt2x00mac.c @@ -158,7 +158,7 @@ void rt2x00mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb) return; exit_fail: - ieee80211_stop_queue(rt2x00dev->hw, qid); + rt2x00queue_pause_queue(queue); dev_kfree_skb_any(skb); } EXPORT_SYMBOL_GPL(rt2x00mac_tx); -- cgit v0.10.2 From 7dab73b37f5e8885cb73efd25e73861f9b4f0246 Mon Sep 17 00:00:00 2001 From: Ivo van Doorn Date: Mon, 18 Apr 2011 15:27:06 +0200 Subject: rt2x00: Split rt2x00dev->flags The number of flags defined for the rt2x00dev->flags field, has been growing over the years. Currently we are approaching the maximum number of bits which are available in the field. A secondary problem, is that one part of the field are initialized only during boot, because the driver requirements are initialized or device requirements are loaded from the EEPROM. In both cases, the flags are fixed and will not change during device operation. The other flags are the device state, and will change frequently. So far this resulted in the fact that for some flags, the atomic bit accessors are used, while for the others the non-atomic variants are used. By splitting the flags up into a "flags" and "cap_flags" we can put all flags which are fixed inside "cap_flags". This field can then be read non-atomically. In the "flags" field we keep the device state, which is going to be read atomically. This adds more room for more flags in the future, and sanitizes the field access methods. Signed-off-by: Ivo van Doorn Acked-by: Helmut Schaa Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/rt2x00/rt2400pci.c b/drivers/net/wireless/rt2x00/rt2400pci.c index 137a24e..5d1654a 100644 --- a/drivers/net/wireless/rt2x00/rt2400pci.c +++ b/drivers/net/wireless/rt2x00/rt2400pci.c @@ -1536,13 +1536,13 @@ static int rt2400pci_init_eeprom(struct rt2x00_dev *rt2x00dev) * Detect if this device has an hardware controlled radio. */ if (rt2x00_get_field16(eeprom, EEPROM_ANTENNA_HARDWARE_RADIO)) - __set_bit(CONFIG_SUPPORT_HW_BUTTON, &rt2x00dev->flags); + __set_bit(CAPABILITY_HW_BUTTON, &rt2x00dev->cap_flags); /* * Check if the BBP tuning should be enabled. */ if (rt2x00_get_field16(eeprom, EEPROM_ANTENNA_RX_AGCVGC_TUNING)) - __set_bit(DRIVER_SUPPORT_LINK_TUNING, &rt2x00dev->flags); + __set_bit(CAPABILITY_LINK_TUNING, &rt2x00dev->cap_flags); return 0; } @@ -1640,9 +1640,9 @@ static int rt2400pci_probe_hw(struct rt2x00_dev *rt2x00dev) /* * This device requires the atim queue and DMA-mapped skbs. */ - __set_bit(DRIVER_REQUIRE_ATIM_QUEUE, &rt2x00dev->flags); - __set_bit(DRIVER_REQUIRE_DMA, &rt2x00dev->flags); - __set_bit(DRIVER_REQUIRE_SW_SEQNO, &rt2x00dev->flags); + __set_bit(REQUIRE_ATIM_QUEUE, &rt2x00dev->cap_flags); + __set_bit(REQUIRE_DMA, &rt2x00dev->cap_flags); + __set_bit(REQUIRE_SW_SEQNO, &rt2x00dev->cap_flags); /* * Set the rssi offset. diff --git a/drivers/net/wireless/rt2x00/rt2500pci.c b/drivers/net/wireless/rt2x00/rt2500pci.c index 198fc0a..3da954e 100644 --- a/drivers/net/wireless/rt2x00/rt2500pci.c +++ b/drivers/net/wireless/rt2x00/rt2500pci.c @@ -1687,14 +1687,14 @@ static int rt2500pci_init_eeprom(struct rt2x00_dev *rt2x00dev) * Detect if this device has an hardware controlled radio. */ if (rt2x00_get_field16(eeprom, EEPROM_ANTENNA_HARDWARE_RADIO)) - __set_bit(CONFIG_SUPPORT_HW_BUTTON, &rt2x00dev->flags); + __set_bit(CAPABILITY_HW_BUTTON, &rt2x00dev->cap_flags); /* * Check if the BBP tuning should be enabled. */ rt2x00_eeprom_read(rt2x00dev, EEPROM_NIC, &eeprom); if (!rt2x00_get_field16(eeprom, EEPROM_NIC_DYN_BBP_TUNE)) - __set_bit(DRIVER_SUPPORT_LINK_TUNING, &rt2x00dev->flags); + __set_bit(CAPABILITY_LINK_TUNING, &rt2x00dev->cap_flags); /* * Read the RSSI <-> dBm offset information. @@ -1958,9 +1958,9 @@ static int rt2500pci_probe_hw(struct rt2x00_dev *rt2x00dev) /* * This device requires the atim queue and DMA-mapped skbs. */ - __set_bit(DRIVER_REQUIRE_ATIM_QUEUE, &rt2x00dev->flags); - __set_bit(DRIVER_REQUIRE_DMA, &rt2x00dev->flags); - __set_bit(DRIVER_REQUIRE_SW_SEQNO, &rt2x00dev->flags); + __set_bit(REQUIRE_ATIM_QUEUE, &rt2x00dev->cap_flags); + __set_bit(REQUIRE_DMA, &rt2x00dev->cap_flags); + __set_bit(REQUIRE_SW_SEQNO, &rt2x00dev->cap_flags); /* * Set the rssi offset. diff --git a/drivers/net/wireless/rt2x00/rt2500usb.c b/drivers/net/wireless/rt2x00/rt2500usb.c index eac7881..dbbd8bc 100644 --- a/drivers/net/wireless/rt2x00/rt2500usb.c +++ b/drivers/net/wireless/rt2x00/rt2500usb.c @@ -1519,7 +1519,7 @@ static int rt2500usb_init_eeprom(struct rt2x00_dev *rt2x00dev) * Detect if this device has an hardware controlled radio. */ if (rt2x00_get_field16(eeprom, EEPROM_ANTENNA_HARDWARE_RADIO)) - __set_bit(CONFIG_SUPPORT_HW_BUTTON, &rt2x00dev->flags); + __set_bit(CAPABILITY_HW_BUTTON, &rt2x00dev->cap_flags); /* * Read the RSSI <-> dBm offset information. @@ -1790,13 +1790,13 @@ static int rt2500usb_probe_hw(struct rt2x00_dev *rt2x00dev) /* * This device requires the atim queue */ - __set_bit(DRIVER_REQUIRE_ATIM_QUEUE, &rt2x00dev->flags); - __set_bit(DRIVER_REQUIRE_BEACON_GUARD, &rt2x00dev->flags); + __set_bit(REQUIRE_ATIM_QUEUE, &rt2x00dev->cap_flags); + __set_bit(REQUIRE_BEACON_GUARD, &rt2x00dev->cap_flags); if (!modparam_nohwcrypt) { - __set_bit(CONFIG_SUPPORT_HW_CRYPTO, &rt2x00dev->flags); - __set_bit(DRIVER_REQUIRE_COPY_IV, &rt2x00dev->flags); + __set_bit(CAPABILITY_HW_CRYPTO, &rt2x00dev->cap_flags); + __set_bit(REQUIRE_COPY_IV, &rt2x00dev->cap_flags); } - __set_bit(DRIVER_REQUIRE_SW_SEQNO, &rt2x00dev->flags); + __set_bit(REQUIRE_SW_SEQNO, &rt2x00dev->cap_flags); /* * Set the rssi offset. diff --git a/drivers/net/wireless/rt2x00/rt2800lib.c b/drivers/net/wireless/rt2x00/rt2800lib.c index 13ccc1b..c6f5584 100644 --- a/drivers/net/wireless/rt2x00/rt2800lib.c +++ b/drivers/net/wireless/rt2x00/rt2800lib.c @@ -1763,8 +1763,8 @@ static void rt2800_config_channel(struct rt2x00_dev *rt2x00dev, if (rf->channel <= 14) { if (!rt2x00_rt(rt2x00dev, RT5390)) { - if (test_bit(CONFIG_EXTERNAL_LNA_BG, - &rt2x00dev->flags)) { + if (test_bit(CAPABILITY_EXTERNAL_LNA_BG, + &rt2x00dev->cap_flags)) { rt2800_bbp_write(rt2x00dev, 82, 0x62); rt2800_bbp_write(rt2x00dev, 75, 0x46); } else { @@ -1775,7 +1775,7 @@ static void rt2800_config_channel(struct rt2x00_dev *rt2x00dev, } else { rt2800_bbp_write(rt2x00dev, 82, 0xf2); - if (test_bit(CONFIG_EXTERNAL_LNA_A, &rt2x00dev->flags)) + if (test_bit(CAPABILITY_EXTERNAL_LNA_A, &rt2x00dev->cap_flags)) rt2800_bbp_write(rt2x00dev, 75, 0x46); else rt2800_bbp_write(rt2x00dev, 75, 0x50); @@ -2008,7 +2008,7 @@ static u8 rt2800_compensate_txpower(struct rt2x00_dev *rt2x00dev, int is_rate_b, if (!((band == IEEE80211_BAND_5GHZ) && is_rate_b)) return txpower; - if (test_bit(CONFIG_SUPPORT_POWER_LIMIT, &rt2x00dev->flags)) { + if (test_bit(CAPABILITY_POWER_LIMIT, &rt2x00dev->cap_flags)) { /* * Check if eirp txpower exceed txpower_limit. * We use OFDM 6M as criterion and its eirp txpower @@ -3309,8 +3309,8 @@ static int rt2800_init_rfcsr(struct rt2x00_dev *rt2x00dev) rt2x00_rt_rev_lt(rt2x00dev, RT3071, REV_RT3071E) || rt2x00_rt_rev_lt(rt2x00dev, RT3090, REV_RT3090E) || rt2x00_rt_rev_lt(rt2x00dev, RT3390, REV_RT3390E)) { - if (!test_bit(CONFIG_EXTERNAL_LNA_BG, - &rt2x00dev->flags)) + if (!test_bit(CAPABILITY_EXTERNAL_LNA_BG, + &rt2x00dev->cap_flags)) rt2x00_set_field8(&rfcsr, RFCSR17_R, 1); } rt2x00_eeprom_read(rt2x00dev, EEPROM_TXMIXER_GAIN_BG, &eeprom); @@ -3733,15 +3733,15 @@ int rt2800_init_eeprom(struct rt2x00_dev *rt2x00dev) rt2x00_eeprom_read(rt2x00dev, EEPROM_NIC_CONF1, &eeprom); if (rt2x00_get_field16(eeprom, EEPROM_NIC_CONF1_EXTERNAL_LNA_5G)) - __set_bit(CONFIG_EXTERNAL_LNA_A, &rt2x00dev->flags); + __set_bit(CAPABILITY_EXTERNAL_LNA_A, &rt2x00dev->cap_flags); if (rt2x00_get_field16(eeprom, EEPROM_NIC_CONF1_EXTERNAL_LNA_2G)) - __set_bit(CONFIG_EXTERNAL_LNA_BG, &rt2x00dev->flags); + __set_bit(CAPABILITY_EXTERNAL_LNA_BG, &rt2x00dev->cap_flags); /* * Detect if this device has an hardware controlled radio. */ if (rt2x00_get_field16(eeprom, EEPROM_NIC_CONF1_HW_RADIO)) - __set_bit(CONFIG_SUPPORT_HW_BUTTON, &rt2x00dev->flags); + __set_bit(CAPABILITY_HW_BUTTON, &rt2x00dev->cap_flags); /* * Store led settings, for correct led behaviour. @@ -3761,7 +3761,7 @@ int rt2800_init_eeprom(struct rt2x00_dev *rt2x00dev) if (rt2x00_get_field16(eeprom, EEPROM_EIRP_MAX_TX_POWER_2GHZ) < EIRP_MAX_TX_POWER_LIMIT) - __set_bit(CONFIG_SUPPORT_POWER_LIMIT, &rt2x00dev->flags); + __set_bit(CAPABILITY_POWER_LIMIT, &rt2x00dev->cap_flags); return 0; } diff --git a/drivers/net/wireless/rt2x00/rt2800pci.c b/drivers/net/wireless/rt2x00/rt2800pci.c index adc3534..4241f19 100644 --- a/drivers/net/wireless/rt2x00/rt2800pci.c +++ b/drivers/net/wireless/rt2x00/rt2800pci.c @@ -966,28 +966,28 @@ static int rt2800pci_probe_hw(struct rt2x00_dev *rt2x00dev) * This device has multiple filters for control frames * and has a separate filter for PS Poll frames. */ - __set_bit(DRIVER_SUPPORT_CONTROL_FILTERS, &rt2x00dev->flags); - __set_bit(DRIVER_SUPPORT_CONTROL_FILTER_PSPOLL, &rt2x00dev->flags); + __set_bit(CAPABILITY_CONTROL_FILTERS, &rt2x00dev->cap_flags); + __set_bit(CAPABILITY_CONTROL_FILTER_PSPOLL, &rt2x00dev->cap_flags); /* * This device has a pre tbtt interrupt and thus fetches * a new beacon directly prior to transmission. */ - __set_bit(DRIVER_SUPPORT_PRE_TBTT_INTERRUPT, &rt2x00dev->flags); + __set_bit(CAPABILITY_PRE_TBTT_INTERRUPT, &rt2x00dev->cap_flags); /* * This device requires firmware. */ if (!rt2x00_is_soc(rt2x00dev)) - __set_bit(DRIVER_REQUIRE_FIRMWARE, &rt2x00dev->flags); - __set_bit(DRIVER_REQUIRE_DMA, &rt2x00dev->flags); - __set_bit(DRIVER_REQUIRE_L2PAD, &rt2x00dev->flags); - __set_bit(DRIVER_REQUIRE_TXSTATUS_FIFO, &rt2x00dev->flags); - __set_bit(DRIVER_REQUIRE_TASKLET_CONTEXT, &rt2x00dev->flags); + __set_bit(REQUIRE_FIRMWARE, &rt2x00dev->cap_flags); + __set_bit(REQUIRE_DMA, &rt2x00dev->cap_flags); + __set_bit(REQUIRE_L2PAD, &rt2x00dev->cap_flags); + __set_bit(REQUIRE_TXSTATUS_FIFO, &rt2x00dev->cap_flags); + __set_bit(REQUIRE_TASKLET_CONTEXT, &rt2x00dev->cap_flags); if (!modparam_nohwcrypt) - __set_bit(CONFIG_SUPPORT_HW_CRYPTO, &rt2x00dev->flags); - __set_bit(DRIVER_SUPPORT_LINK_TUNING, &rt2x00dev->flags); - __set_bit(DRIVER_REQUIRE_HT_TX_DESC, &rt2x00dev->flags); + __set_bit(CAPABILITY_HW_CRYPTO, &rt2x00dev->cap_flags); + __set_bit(CAPABILITY_LINK_TUNING, &rt2x00dev->cap_flags); + __set_bit(REQUIRE_HT_TX_DESC, &rt2x00dev->cap_flags); /* * Set the rssi offset. diff --git a/drivers/net/wireless/rt2x00/rt2800usb.c b/drivers/net/wireless/rt2x00/rt2800usb.c index d2f5c87..f3ce5e8 100644 --- a/drivers/net/wireless/rt2x00/rt2800usb.c +++ b/drivers/net/wireless/rt2x00/rt2800usb.c @@ -553,18 +553,18 @@ static int rt2800usb_probe_hw(struct rt2x00_dev *rt2x00dev) * This device has multiple filters for control frames * and has a separate filter for PS Poll frames. */ - __set_bit(DRIVER_SUPPORT_CONTROL_FILTERS, &rt2x00dev->flags); - __set_bit(DRIVER_SUPPORT_CONTROL_FILTER_PSPOLL, &rt2x00dev->flags); + __set_bit(CAPABILITY_CONTROL_FILTERS, &rt2x00dev->cap_flags); + __set_bit(CAPABILITY_CONTROL_FILTER_PSPOLL, &rt2x00dev->cap_flags); /* * This device requires firmware. */ - __set_bit(DRIVER_REQUIRE_FIRMWARE, &rt2x00dev->flags); - __set_bit(DRIVER_REQUIRE_L2PAD, &rt2x00dev->flags); + __set_bit(REQUIRE_FIRMWARE, &rt2x00dev->cap_flags); + __set_bit(REQUIRE_L2PAD, &rt2x00dev->cap_flags); if (!modparam_nohwcrypt) - __set_bit(CONFIG_SUPPORT_HW_CRYPTO, &rt2x00dev->flags); - __set_bit(DRIVER_SUPPORT_LINK_TUNING, &rt2x00dev->flags); - __set_bit(DRIVER_REQUIRE_HT_TX_DESC, &rt2x00dev->flags); + __set_bit(CAPABILITY_HW_CRYPTO, &rt2x00dev->cap_flags); + __set_bit(CAPABILITY_LINK_TUNING, &rt2x00dev->cap_flags); + __set_bit(REQUIRE_HT_TX_DESC, &rt2x00dev->cap_flags); /* * Set the rssi offset. diff --git a/drivers/net/wireless/rt2x00/rt2x00.h b/drivers/net/wireless/rt2x00/rt2x00.h index dd0f66a..79c385a 100644 --- a/drivers/net/wireless/rt2x00/rt2x00.h +++ b/drivers/net/wireless/rt2x00/rt2x00.h @@ -643,11 +643,11 @@ struct rt2x00_ops { }; /* - * rt2x00 device flags + * rt2x00 state flags */ -enum rt2x00_flags { +enum rt2x00_state_flags { /* - * Device state flags + * Device flags */ DEVICE_STATE_PRESENT, DEVICE_STATE_REGISTERED_HW, @@ -657,42 +657,47 @@ enum rt2x00_flags { DEVICE_STATE_SCANNING, /* - * Driver requirements - */ - DRIVER_REQUIRE_FIRMWARE, - DRIVER_REQUIRE_BEACON_GUARD, - DRIVER_REQUIRE_ATIM_QUEUE, - DRIVER_REQUIRE_DMA, - DRIVER_REQUIRE_COPY_IV, - DRIVER_REQUIRE_L2PAD, - DRIVER_REQUIRE_TXSTATUS_FIFO, - DRIVER_REQUIRE_TASKLET_CONTEXT, - DRIVER_REQUIRE_SW_SEQNO, - DRIVER_REQUIRE_HT_TX_DESC, - - /* - * Driver features - */ - CONFIG_SUPPORT_HW_BUTTON, - CONFIG_SUPPORT_HW_CRYPTO, - CONFIG_SUPPORT_POWER_LIMIT, - DRIVER_SUPPORT_CONTROL_FILTERS, - DRIVER_SUPPORT_CONTROL_FILTER_PSPOLL, - DRIVER_SUPPORT_PRE_TBTT_INTERRUPT, - DRIVER_SUPPORT_LINK_TUNING, - - /* * Driver configuration */ - CONFIG_FRAME_TYPE, - CONFIG_RF_SEQUENCE, - CONFIG_EXTERNAL_LNA_A, - CONFIG_EXTERNAL_LNA_BG, - CONFIG_DOUBLE_ANTENNA, CONFIG_CHANNEL_HT40, }; /* + * rt2x00 capability flags + */ +enum rt2x00_capability_flags { + /* + * Requirements + */ + REQUIRE_FIRMWARE, + REQUIRE_BEACON_GUARD, + REQUIRE_ATIM_QUEUE, + REQUIRE_DMA, + REQUIRE_COPY_IV, + REQUIRE_L2PAD, + REQUIRE_TXSTATUS_FIFO, + REQUIRE_TASKLET_CONTEXT, + REQUIRE_SW_SEQNO, + REQUIRE_HT_TX_DESC, + + /* + * Capabilities + */ + CAPABILITY_HW_BUTTON, + CAPABILITY_HW_CRYPTO, + CAPABILITY_POWER_LIMIT, + CAPABILITY_CONTROL_FILTERS, + CAPABILITY_CONTROL_FILTER_PSPOLL, + CAPABILITY_PRE_TBTT_INTERRUPT, + CAPABILITY_LINK_TUNING, + CAPABILITY_FRAME_TYPE, + CAPABILITY_RF_SEQUENCE, + CAPABILITY_EXTERNAL_LNA_A, + CAPABILITY_EXTERNAL_LNA_BG, + CAPABILITY_DOUBLE_ANTENNA, +}; + +/* * rt2x00 device structure. */ struct rt2x00_dev { @@ -738,13 +743,20 @@ struct rt2x00_dev { #endif /* CONFIG_RT2X00_LIB_LEDS */ /* - * Device flags. - * In these flags the current status and some - * of the device capabilities are stored. + * Device state flags. + * In these flags the current status is stored. + * Access to these flags should occur atomically. */ unsigned long flags; /* + * Device capabiltiy flags. + * In these flags the device/driver capabilities are stored. + * Access to these flags should occur non-atomically. + */ + unsigned long cap_flags; + + /* * Device information, Bus IRQ and name (PCI, SoC) */ int irq; diff --git a/drivers/net/wireless/rt2x00/rt2x00config.c b/drivers/net/wireless/rt2x00/rt2x00config.c index e7f67d5..e225a66 100644 --- a/drivers/net/wireless/rt2x00/rt2x00config.c +++ b/drivers/net/wireless/rt2x00/rt2x00config.c @@ -176,10 +176,10 @@ void rt2x00lib_config(struct rt2x00_dev *rt2x00dev, if (ieee80211_flags & IEEE80211_CONF_CHANGE_CHANNEL) { if (conf_is_ht40(conf)) { - __set_bit(CONFIG_CHANNEL_HT40, &rt2x00dev->flags); + set_bit(CONFIG_CHANNEL_HT40, &rt2x00dev->flags); hw_value = rt2x00ht_center_channel(rt2x00dev, conf); } else { - __clear_bit(CONFIG_CHANNEL_HT40, &rt2x00dev->flags); + clear_bit(CONFIG_CHANNEL_HT40, &rt2x00dev->flags); hw_value = conf->channel->hw_value; } diff --git a/drivers/net/wireless/rt2x00/rt2x00crypto.c b/drivers/net/wireless/rt2x00/rt2x00crypto.c index 5e9074b..e1e0c51 100644 --- a/drivers/net/wireless/rt2x00/rt2x00crypto.c +++ b/drivers/net/wireless/rt2x00/rt2x00crypto.c @@ -52,7 +52,7 @@ void rt2x00crypto_create_tx_descriptor(struct queue_entry *entry, struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(entry->skb); struct ieee80211_key_conf *hw_key = tx_info->control.hw_key; - if (!test_bit(CONFIG_SUPPORT_HW_CRYPTO, &rt2x00dev->flags) || !hw_key) + if (!test_bit(CAPABILITY_HW_CRYPTO, &rt2x00dev->cap_flags) || !hw_key) return; __set_bit(ENTRY_TXD_ENCRYPT, &txdesc->flags); @@ -80,7 +80,7 @@ unsigned int rt2x00crypto_tx_overhead(struct rt2x00_dev *rt2x00dev, struct ieee80211_key_conf *key = tx_info->control.hw_key; unsigned int overhead = 0; - if (!test_bit(CONFIG_SUPPORT_HW_CRYPTO, &rt2x00dev->flags) || !key) + if (!test_bit(CAPABILITY_HW_CRYPTO, &rt2x00dev->cap_flags) || !key) return overhead; /* diff --git a/drivers/net/wireless/rt2x00/rt2x00debug.c b/drivers/net/wireless/rt2x00/rt2x00debug.c index 66166ef..78787fc 100644 --- a/drivers/net/wireless/rt2x00/rt2x00debug.c +++ b/drivers/net/wireless/rt2x00/rt2x00debug.c @@ -63,7 +63,8 @@ struct rt2x00debug_intf { * - driver folder * - driver file * - chipset file - * - device flags file + * - device state flags file + * - device capability flags file * - register folder * - csr offset/value files * - eeprom offset/value files @@ -78,6 +79,7 @@ struct rt2x00debug_intf { struct dentry *driver_entry; struct dentry *chipset_entry; struct dentry *dev_flags; + struct dentry *cap_flags; struct dentry *register_folder; struct dentry *csr_off_entry; struct dentry *csr_val_entry; @@ -553,6 +555,35 @@ static const struct file_operations rt2x00debug_fop_dev_flags = { .llseek = default_llseek, }; +static ssize_t rt2x00debug_read_cap_flags(struct file *file, + char __user *buf, + size_t length, + loff_t *offset) +{ + struct rt2x00debug_intf *intf = file->private_data; + char line[16]; + size_t size; + + if (*offset) + return 0; + + size = sprintf(line, "0x%.8x\n", (unsigned int)intf->rt2x00dev->cap_flags); + + if (copy_to_user(buf, line, size)) + return -EFAULT; + + *offset += size; + return size; +} + +static const struct file_operations rt2x00debug_fop_cap_flags = { + .owner = THIS_MODULE, + .read = rt2x00debug_read_cap_flags, + .open = rt2x00debug_file_open, + .release = rt2x00debug_file_release, + .llseek = default_llseek, +}; + static struct dentry *rt2x00debug_create_file_driver(const char *name, struct rt2x00debug_intf *intf, @@ -652,6 +683,12 @@ void rt2x00debug_register(struct rt2x00_dev *rt2x00dev) if (IS_ERR(intf->dev_flags) || !intf->dev_flags) goto exit; + intf->cap_flags = debugfs_create_file("cap_flags", S_IRUSR, + intf->driver_folder, intf, + &rt2x00debug_fop_cap_flags); + if (IS_ERR(intf->cap_flags) || !intf->cap_flags) + goto exit; + intf->register_folder = debugfs_create_dir("register", intf->driver_folder); if (IS_ERR(intf->register_folder) || !intf->register_folder) @@ -705,7 +742,7 @@ void rt2x00debug_register(struct rt2x00_dev *rt2x00dev) intf, &rt2x00debug_fop_queue_stats); #ifdef CONFIG_RT2X00_LIB_CRYPTO - if (test_bit(CONFIG_SUPPORT_HW_CRYPTO, &rt2x00dev->flags)) + if (test_bit(CAPABILITY_HW_CRYPTO, &rt2x00dev->cap_flags)) intf->crypto_stats_entry = debugfs_create_file("crypto", S_IRUGO, intf->queue_folder, intf, &rt2x00debug_fop_crypto_stats); @@ -743,6 +780,7 @@ void rt2x00debug_deregister(struct rt2x00_dev *rt2x00dev) debugfs_remove(intf->csr_off_entry); debugfs_remove(intf->register_folder); debugfs_remove(intf->dev_flags); + debugfs_remove(intf->cap_flags); debugfs_remove(intf->chipset_entry); debugfs_remove(intf->driver_entry); debugfs_remove(intf->driver_folder); diff --git a/drivers/net/wireless/rt2x00/rt2x00dev.c b/drivers/net/wireless/rt2x00/rt2x00dev.c index 9bffe84..af25b01 100644 --- a/drivers/net/wireless/rt2x00/rt2x00dev.c +++ b/drivers/net/wireless/rt2x00/rt2x00dev.c @@ -200,7 +200,7 @@ void rt2x00lib_beacondone(struct rt2x00_dev *rt2x00dev) * here as they will fetch the next beacon directly prior to * transmission. */ - if (test_bit(DRIVER_SUPPORT_PRE_TBTT_INTERRUPT, &rt2x00dev->flags)) + if (test_bit(CAPABILITY_PRE_TBTT_INTERRUPT, &rt2x00dev->cap_flags)) return; /* fetch next beacon */ @@ -271,7 +271,7 @@ void rt2x00lib_txdone(struct queue_entry *entry, /* * Remove L2 padding which was added during */ - if (test_bit(DRIVER_REQUIRE_L2PAD, &rt2x00dev->flags)) + if (test_bit(REQUIRE_L2PAD, &rt2x00dev->cap_flags)) rt2x00queue_remove_l2pad(entry->skb, header_length); /* @@ -280,7 +280,7 @@ void rt2x00lib_txdone(struct queue_entry *entry, * mac80211 will expect the same data to be present it the * frame as it was passed to us. */ - if (test_bit(CONFIG_SUPPORT_HW_CRYPTO, &rt2x00dev->flags)) + if (test_bit(CAPABILITY_HW_CRYPTO, &rt2x00dev->cap_flags)) rt2x00crypto_tx_insert_iv(entry->skb, header_length); /* @@ -377,7 +377,7 @@ void rt2x00lib_txdone(struct queue_entry *entry, * send the status report back. */ if (!(skbdesc_flags & SKBDESC_NOT_MAC80211)) { - if (test_bit(DRIVER_REQUIRE_TASKLET_CONTEXT, &rt2x00dev->flags)) + if (test_bit(REQUIRE_TASKLET_CONTEXT, &rt2x00dev->cap_flags)) ieee80211_tx_status(rt2x00dev->hw, entry->skb); else ieee80211_tx_status_ni(rt2x00dev->hw, entry->skb); @@ -806,15 +806,15 @@ static int rt2x00lib_probe_hw(struct rt2x00_dev *rt2x00dev) /* * Take TX headroom required for alignment into account. */ - if (test_bit(DRIVER_REQUIRE_L2PAD, &rt2x00dev->flags)) + if (test_bit(REQUIRE_L2PAD, &rt2x00dev->cap_flags)) rt2x00dev->hw->extra_tx_headroom += RT2X00_L2PAD_SIZE; - else if (test_bit(DRIVER_REQUIRE_DMA, &rt2x00dev->flags)) + else if (test_bit(REQUIRE_DMA, &rt2x00dev->cap_flags)) rt2x00dev->hw->extra_tx_headroom += RT2X00_ALIGN_SIZE; /* * Allocate tx status FIFO for driver use. */ - if (test_bit(DRIVER_REQUIRE_TXSTATUS_FIFO, &rt2x00dev->flags)) { + if (test_bit(REQUIRE_TXSTATUS_FIFO, &rt2x00dev->cap_flags)) { /* * Allocate the txstatus fifo. In the worst case the tx * status fifo has to hold the tx status of all entries diff --git a/drivers/net/wireless/rt2x00/rt2x00firmware.c b/drivers/net/wireless/rt2x00/rt2x00firmware.c index be0ff78..f316aad 100644 --- a/drivers/net/wireless/rt2x00/rt2x00firmware.c +++ b/drivers/net/wireless/rt2x00/rt2x00firmware.c @@ -99,7 +99,7 @@ int rt2x00lib_load_firmware(struct rt2x00_dev *rt2x00dev) { int retval; - if (!test_bit(DRIVER_REQUIRE_FIRMWARE, &rt2x00dev->flags)) + if (!test_bit(REQUIRE_FIRMWARE, &rt2x00dev->cap_flags)) return 0; if (!rt2x00dev->fw) { diff --git a/drivers/net/wireless/rt2x00/rt2x00lib.h b/drivers/net/wireless/rt2x00/rt2x00lib.h index 88f2f92..bbee2cd 100644 --- a/drivers/net/wireless/rt2x00/rt2x00lib.h +++ b/drivers/net/wireless/rt2x00/rt2x00lib.h @@ -416,13 +416,13 @@ static inline u16 rt2x00ht_center_channel(struct rt2x00_dev *rt2x00dev, */ static inline void rt2x00rfkill_register(struct rt2x00_dev *rt2x00dev) { - if (test_bit(CONFIG_SUPPORT_HW_BUTTON, &rt2x00dev->flags)) + if (test_bit(CAPABILITY_HW_BUTTON, &rt2x00dev->cap_flags)) wiphy_rfkill_start_polling(rt2x00dev->hw->wiphy); } static inline void rt2x00rfkill_unregister(struct rt2x00_dev *rt2x00dev) { - if (test_bit(CONFIG_SUPPORT_HW_BUTTON, &rt2x00dev->flags)) + if (test_bit(CAPABILITY_HW_BUTTON, &rt2x00dev->cap_flags)) wiphy_rfkill_stop_polling(rt2x00dev->hw->wiphy); } diff --git a/drivers/net/wireless/rt2x00/rt2x00link.c b/drivers/net/wireless/rt2x00/rt2x00link.c index 128b361..ba0bb76 100644 --- a/drivers/net/wireless/rt2x00/rt2x00link.c +++ b/drivers/net/wireless/rt2x00/rt2x00link.c @@ -383,7 +383,7 @@ static void rt2x00link_tuner(struct work_struct *work) * do not support link tuning at all, while other devices can disable * the feature from the EEPROM. */ - if (test_bit(DRIVER_SUPPORT_LINK_TUNING, &rt2x00dev->flags)) + if (test_bit(CAPABILITY_LINK_TUNING, &rt2x00dev->cap_flags)) rt2x00dev->ops->lib->link_tuner(rt2x00dev, qual, link->count); /* diff --git a/drivers/net/wireless/rt2x00/rt2x00mac.c b/drivers/net/wireless/rt2x00/rt2x00mac.c index 4a1c41b..4770156d 100644 --- a/drivers/net/wireless/rt2x00/rt2x00mac.c +++ b/drivers/net/wireless/rt2x00/rt2x00mac.c @@ -119,7 +119,7 @@ void rt2x00mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb) * Use the ATIM queue if appropriate and present. */ if (tx_info->flags & IEEE80211_TX_CTL_SEND_AFTER_DTIM && - test_bit(DRIVER_REQUIRE_ATIM_QUEUE, &rt2x00dev->flags)) + test_bit(REQUIRE_ATIM_QUEUE, &rt2x00dev->cap_flags)) qid = QID_ATIM; queue = rt2x00queue_get_tx_queue(rt2x00dev, qid); @@ -411,11 +411,11 @@ void rt2x00mac_configure_filter(struct ieee80211_hw *hw, * of different types, but has no a separate filter for PS Poll frames, * FIF_CONTROL flag implies FIF_PSPOLL. */ - if (!test_bit(DRIVER_SUPPORT_CONTROL_FILTERS, &rt2x00dev->flags)) { + if (!test_bit(CAPABILITY_CONTROL_FILTERS, &rt2x00dev->cap_flags)) { if (*total_flags & FIF_CONTROL || *total_flags & FIF_PSPOLL) *total_flags |= FIF_CONTROL | FIF_PSPOLL; } - if (!test_bit(DRIVER_SUPPORT_CONTROL_FILTER_PSPOLL, &rt2x00dev->flags)) { + if (!test_bit(CAPABILITY_CONTROL_FILTER_PSPOLL, &rt2x00dev->cap_flags)) { if (*total_flags & FIF_CONTROL) *total_flags |= FIF_PSPOLL; } @@ -496,7 +496,7 @@ int rt2x00mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, if (!test_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags)) return 0; - else if (!test_bit(CONFIG_SUPPORT_HW_CRYPTO, &rt2x00dev->flags)) + else if (!test_bit(CAPABILITY_HW_CRYPTO, &rt2x00dev->cap_flags)) return -EOPNOTSUPP; else if (key->keylen > 32) return -ENOSPC; @@ -562,7 +562,7 @@ EXPORT_SYMBOL_GPL(rt2x00mac_set_key); void rt2x00mac_sw_scan_start(struct ieee80211_hw *hw) { struct rt2x00_dev *rt2x00dev = hw->priv; - __set_bit(DEVICE_STATE_SCANNING, &rt2x00dev->flags); + set_bit(DEVICE_STATE_SCANNING, &rt2x00dev->flags); rt2x00link_stop_tuner(rt2x00dev); } EXPORT_SYMBOL_GPL(rt2x00mac_sw_scan_start); @@ -570,7 +570,7 @@ EXPORT_SYMBOL_GPL(rt2x00mac_sw_scan_start); void rt2x00mac_sw_scan_complete(struct ieee80211_hw *hw) { struct rt2x00_dev *rt2x00dev = hw->priv; - __clear_bit(DEVICE_STATE_SCANNING, &rt2x00dev->flags); + clear_bit(DEVICE_STATE_SCANNING, &rt2x00dev->flags); rt2x00link_start_tuner(rt2x00dev); } EXPORT_SYMBOL_GPL(rt2x00mac_sw_scan_complete); diff --git a/drivers/net/wireless/rt2x00/rt2x00queue.c b/drivers/net/wireless/rt2x00/rt2x00queue.c index 9fc4a1e..d03eef2 100644 --- a/drivers/net/wireless/rt2x00/rt2x00queue.c +++ b/drivers/net/wireless/rt2x00/rt2x00queue.c @@ -60,7 +60,7 @@ struct sk_buff *rt2x00queue_alloc_rxskb(struct queue_entry *entry) * at least 8 bytes bytes available in headroom for IV/EIV * and 8 bytes for ICV data as tailroon. */ - if (test_bit(CONFIG_SUPPORT_HW_CRYPTO, &rt2x00dev->flags)) { + if (test_bit(CAPABILITY_HW_CRYPTO, &rt2x00dev->cap_flags)) { head_size += 8; tail_size += 8; } @@ -86,7 +86,7 @@ struct sk_buff *rt2x00queue_alloc_rxskb(struct queue_entry *entry) memset(skbdesc, 0, sizeof(*skbdesc)); skbdesc->entry = entry; - if (test_bit(DRIVER_REQUIRE_DMA, &rt2x00dev->flags)) { + if (test_bit(REQUIRE_DMA, &rt2x00dev->cap_flags)) { skbdesc->skb_dma = dma_map_single(rt2x00dev->dev, skb->data, skb->len, @@ -213,7 +213,7 @@ static void rt2x00queue_create_tx_descriptor_seq(struct queue_entry *entry, __set_bit(ENTRY_TXD_GENERATE_SEQ, &txdesc->flags); - if (!test_bit(DRIVER_REQUIRE_SW_SEQNO, &entry->queue->rt2x00dev->flags)) + if (!test_bit(REQUIRE_SW_SEQNO, &entry->queue->rt2x00dev->cap_flags)) return; /* @@ -396,7 +396,7 @@ static void rt2x00queue_create_tx_descriptor(struct queue_entry *entry, rt2x00crypto_create_tx_descriptor(entry, txdesc); rt2x00queue_create_tx_descriptor_seq(entry, txdesc); - if (test_bit(DRIVER_REQUIRE_HT_TX_DESC, &rt2x00dev->flags)) + if (test_bit(REQUIRE_HT_TX_DESC, &rt2x00dev->cap_flags)) rt2x00ht_create_tx_descriptor(entry, txdesc, hwrate); else rt2x00queue_create_tx_descriptor_plcp(entry, txdesc, hwrate); @@ -436,7 +436,7 @@ static int rt2x00queue_write_tx_data(struct queue_entry *entry, /* * Map the skb to DMA. */ - if (test_bit(DRIVER_REQUIRE_DMA, &rt2x00dev->flags)) + if (test_bit(REQUIRE_DMA, &rt2x00dev->cap_flags)) rt2x00queue_map_txskb(entry); return 0; @@ -529,7 +529,7 @@ int rt2x00queue_write_tx_frame(struct data_queue *queue, struct sk_buff *skb, */ if (test_bit(ENTRY_TXD_ENCRYPT, &txdesc.flags) && !test_bit(ENTRY_TXD_ENCRYPT_IV, &txdesc.flags)) { - if (test_bit(DRIVER_REQUIRE_COPY_IV, &queue->rt2x00dev->flags)) + if (test_bit(REQUIRE_COPY_IV, &queue->rt2x00dev->cap_flags)) rt2x00crypto_tx_copy_iv(skb, &txdesc); else rt2x00crypto_tx_remove_iv(skb, &txdesc); @@ -543,9 +543,9 @@ int rt2x00queue_write_tx_frame(struct data_queue *queue, struct sk_buff *skb, * PCI and USB devices, while header alignment only is valid * for PCI devices. */ - if (test_bit(DRIVER_REQUIRE_L2PAD, &queue->rt2x00dev->flags)) + if (test_bit(REQUIRE_L2PAD, &queue->rt2x00dev->cap_flags)) rt2x00queue_insert_l2pad(entry->skb, txdesc.header_length); - else if (test_bit(DRIVER_REQUIRE_DMA, &queue->rt2x00dev->flags)) + else if (test_bit(REQUIRE_DMA, &queue->rt2x00dev->cap_flags)) rt2x00queue_align_frame(entry->skb); /* @@ -1069,7 +1069,7 @@ int rt2x00queue_initialize(struct rt2x00_dev *rt2x00dev) if (status) goto exit; - if (test_bit(DRIVER_REQUIRE_ATIM_QUEUE, &rt2x00dev->flags)) { + if (test_bit(REQUIRE_ATIM_QUEUE, &rt2x00dev->cap_flags)) { status = rt2x00queue_alloc_entries(rt2x00dev->atim, rt2x00dev->ops->atim); if (status) @@ -1121,7 +1121,7 @@ int rt2x00queue_allocate(struct rt2x00_dev *rt2x00dev) struct data_queue *queue; enum data_queue_qid qid; unsigned int req_atim = - !!test_bit(DRIVER_REQUIRE_ATIM_QUEUE, &rt2x00dev->flags); + !!test_bit(REQUIRE_ATIM_QUEUE, &rt2x00dev->cap_flags); /* * We need the following queues: diff --git a/drivers/net/wireless/rt2x00/rt2x00usb.c b/drivers/net/wireless/rt2x00/rt2x00usb.c index fbe735f..94047e9 100644 --- a/drivers/net/wireless/rt2x00/rt2x00usb.c +++ b/drivers/net/wireless/rt2x00/rt2x00usb.c @@ -387,7 +387,7 @@ static void rt2x00usb_flush_entry(struct queue_entry *entry) * Kill guardian urb (if required by driver). */ if ((entry->queue->qid == QID_BEACON) && - (test_bit(DRIVER_REQUIRE_BEACON_GUARD, &rt2x00dev->flags))) + (test_bit(REQUIRE_BEACON_GUARD, &rt2x00dev->cap_flags))) usb_kill_urb(bcn_priv->guardian_urb); } @@ -583,7 +583,7 @@ static int rt2x00usb_alloc_entries(struct data_queue *queue) * then we are done. */ if (queue->qid != QID_BEACON || - !test_bit(DRIVER_REQUIRE_BEACON_GUARD, &rt2x00dev->flags)) + !test_bit(REQUIRE_BEACON_GUARD, &rt2x00dev->cap_flags)) return 0; for (i = 0; i < queue->limit; i++) { @@ -618,7 +618,7 @@ static void rt2x00usb_free_entries(struct data_queue *queue) * then we are done. */ if (queue->qid != QID_BEACON || - !test_bit(DRIVER_REQUIRE_BEACON_GUARD, &rt2x00dev->flags)) + !test_bit(REQUIRE_BEACON_GUARD, &rt2x00dev->cap_flags)) return; for (i = 0; i < queue->limit; i++) { diff --git a/drivers/net/wireless/rt2x00/rt61pci.c b/drivers/net/wireless/rt2x00/rt61pci.c index 8ee1514..c16c150 100644 --- a/drivers/net/wireless/rt2x00/rt61pci.c +++ b/drivers/net/wireless/rt2x00/rt61pci.c @@ -683,7 +683,7 @@ static void rt61pci_config_antenna_2x(struct rt2x00_dev *rt2x00dev, rt2x00_set_field8(&r3, BBP_R3_SMART_MODE, rt2x00_rf(rt2x00dev, RF2529)); rt2x00_set_field8(&r4, BBP_R4_RX_FRAME_END, - !test_bit(CONFIG_FRAME_TYPE, &rt2x00dev->flags)); + !test_bit(CAPABILITY_FRAME_TYPE, &rt2x00dev->cap_flags)); /* * Configure the RX antenna. @@ -811,10 +811,10 @@ static void rt61pci_config_ant(struct rt2x00_dev *rt2x00dev, if (rt2x00dev->curr_band == IEEE80211_BAND_5GHZ) { sel = antenna_sel_a; - lna = test_bit(CONFIG_EXTERNAL_LNA_A, &rt2x00dev->flags); + lna = test_bit(CAPABILITY_EXTERNAL_LNA_A, &rt2x00dev->cap_flags); } else { sel = antenna_sel_bg; - lna = test_bit(CONFIG_EXTERNAL_LNA_BG, &rt2x00dev->flags); + lna = test_bit(CAPABILITY_EXTERNAL_LNA_BG, &rt2x00dev->cap_flags); } for (i = 0; i < ARRAY_SIZE(antenna_sel_a); i++) @@ -834,7 +834,7 @@ static void rt61pci_config_ant(struct rt2x00_dev *rt2x00dev, else if (rt2x00_rf(rt2x00dev, RF2527)) rt61pci_config_antenna_2x(rt2x00dev, ant); else if (rt2x00_rf(rt2x00dev, RF2529)) { - if (test_bit(CONFIG_DOUBLE_ANTENNA, &rt2x00dev->flags)) + if (test_bit(CAPABILITY_DOUBLE_ANTENNA, &rt2x00dev->cap_flags)) rt61pci_config_antenna_2x(rt2x00dev, ant); else rt61pci_config_antenna_2529(rt2x00dev, ant); @@ -848,13 +848,13 @@ static void rt61pci_config_lna_gain(struct rt2x00_dev *rt2x00dev, short lna_gain = 0; if (libconf->conf->channel->band == IEEE80211_BAND_2GHZ) { - if (test_bit(CONFIG_EXTERNAL_LNA_BG, &rt2x00dev->flags)) + if (test_bit(CAPABILITY_EXTERNAL_LNA_BG, &rt2x00dev->cap_flags)) lna_gain += 14; rt2x00_eeprom_read(rt2x00dev, EEPROM_RSSI_OFFSET_BG, &eeprom); lna_gain -= rt2x00_get_field16(eeprom, EEPROM_RSSI_OFFSET_BG_1); } else { - if (test_bit(CONFIG_EXTERNAL_LNA_A, &rt2x00dev->flags)) + if (test_bit(CAPABILITY_EXTERNAL_LNA_A, &rt2x00dev->cap_flags)) lna_gain += 14; rt2x00_eeprom_read(rt2x00dev, EEPROM_RSSI_OFFSET_A, &eeprom); @@ -1050,14 +1050,14 @@ static void rt61pci_link_tuner(struct rt2x00_dev *rt2x00dev, if (rt2x00dev->curr_band == IEEE80211_BAND_5GHZ) { low_bound = 0x28; up_bound = 0x48; - if (test_bit(CONFIG_EXTERNAL_LNA_A, &rt2x00dev->flags)) { + if (test_bit(CAPABILITY_EXTERNAL_LNA_A, &rt2x00dev->cap_flags)) { low_bound += 0x10; up_bound += 0x10; } } else { low_bound = 0x20; up_bound = 0x40; - if (test_bit(CONFIG_EXTERNAL_LNA_BG, &rt2x00dev->flags)) { + if (test_bit(CAPABILITY_EXTERNAL_LNA_BG, &rt2x00dev->cap_flags)) { low_bound += 0x10; up_bound += 0x10; } @@ -2537,7 +2537,7 @@ static int rt61pci_init_eeprom(struct rt2x00_dev *rt2x00dev) * Determine number of antennas. */ if (rt2x00_get_field16(eeprom, EEPROM_ANTENNA_NUM) == 2) - __set_bit(CONFIG_DOUBLE_ANTENNA, &rt2x00dev->flags); + __set_bit(CAPABILITY_DOUBLE_ANTENNA, &rt2x00dev->cap_flags); /* * Identify default antenna configuration. @@ -2551,20 +2551,20 @@ static int rt61pci_init_eeprom(struct rt2x00_dev *rt2x00dev) * Read the Frame type. */ if (rt2x00_get_field16(eeprom, EEPROM_ANTENNA_FRAME_TYPE)) - __set_bit(CONFIG_FRAME_TYPE, &rt2x00dev->flags); + __set_bit(CAPABILITY_FRAME_TYPE, &rt2x00dev->cap_flags); /* * Detect if this device has a hardware controlled radio. */ if (rt2x00_get_field16(eeprom, EEPROM_ANTENNA_HARDWARE_RADIO)) - __set_bit(CONFIG_SUPPORT_HW_BUTTON, &rt2x00dev->flags); + __set_bit(CAPABILITY_HW_BUTTON, &rt2x00dev->cap_flags); /* * Read frequency offset and RF programming sequence. */ rt2x00_eeprom_read(rt2x00dev, EEPROM_FREQ, &eeprom); if (rt2x00_get_field16(eeprom, EEPROM_FREQ_SEQ)) - __set_bit(CONFIG_RF_SEQUENCE, &rt2x00dev->flags); + __set_bit(CAPABILITY_RF_SEQUENCE, &rt2x00dev->cap_flags); rt2x00dev->freq_offset = rt2x00_get_field16(eeprom, EEPROM_FREQ_OFFSET); @@ -2574,9 +2574,9 @@ static int rt61pci_init_eeprom(struct rt2x00_dev *rt2x00dev) rt2x00_eeprom_read(rt2x00dev, EEPROM_NIC, &eeprom); if (rt2x00_get_field16(eeprom, EEPROM_NIC_EXTERNAL_LNA_A)) - __set_bit(CONFIG_EXTERNAL_LNA_A, &rt2x00dev->flags); + __set_bit(CAPABILITY_EXTERNAL_LNA_A, &rt2x00dev->cap_flags); if (rt2x00_get_field16(eeprom, EEPROM_NIC_EXTERNAL_LNA_BG)) - __set_bit(CONFIG_EXTERNAL_LNA_BG, &rt2x00dev->flags); + __set_bit(CAPABILITY_EXTERNAL_LNA_BG, &rt2x00dev->cap_flags); /* * When working with a RF2529 chip without double antenna, @@ -2584,7 +2584,7 @@ static int rt61pci_init_eeprom(struct rt2x00_dev *rt2x00dev) * eeprom word. */ if (rt2x00_rf(rt2x00dev, RF2529) && - !test_bit(CONFIG_DOUBLE_ANTENNA, &rt2x00dev->flags)) { + !test_bit(CAPABILITY_DOUBLE_ANTENNA, &rt2x00dev->cap_flags)) { rt2x00dev->default_ant.rx = ANTENNA_A + rt2x00_get_field16(eeprom, EEPROM_NIC_RX_FIXED); rt2x00dev->default_ant.tx = @@ -2799,7 +2799,7 @@ static int rt61pci_probe_hw_mode(struct rt2x00_dev *rt2x00dev) spec->supported_bands = SUPPORT_BAND_2GHZ; spec->supported_rates = SUPPORT_RATE_CCK | SUPPORT_RATE_OFDM; - if (!test_bit(CONFIG_RF_SEQUENCE, &rt2x00dev->flags)) { + if (!test_bit(CAPABILITY_RF_SEQUENCE, &rt2x00dev->cap_flags)) { spec->num_channels = 14; spec->channels = rf_vals_noseq; } else { @@ -2869,16 +2869,16 @@ static int rt61pci_probe_hw(struct rt2x00_dev *rt2x00dev) * This device has multiple filters for control frames, * but has no a separate filter for PS Poll frames. */ - __set_bit(DRIVER_SUPPORT_CONTROL_FILTERS, &rt2x00dev->flags); + __set_bit(CAPABILITY_CONTROL_FILTERS, &rt2x00dev->cap_flags); /* * This device requires firmware and DMA mapped skbs. */ - __set_bit(DRIVER_REQUIRE_FIRMWARE, &rt2x00dev->flags); - __set_bit(DRIVER_REQUIRE_DMA, &rt2x00dev->flags); + __set_bit(REQUIRE_FIRMWARE, &rt2x00dev->cap_flags); + __set_bit(REQUIRE_DMA, &rt2x00dev->cap_flags); if (!modparam_nohwcrypt) - __set_bit(CONFIG_SUPPORT_HW_CRYPTO, &rt2x00dev->flags); - __set_bit(DRIVER_SUPPORT_LINK_TUNING, &rt2x00dev->flags); + __set_bit(CAPABILITY_HW_CRYPTO, &rt2x00dev->cap_flags); + __set_bit(CAPABILITY_LINK_TUNING, &rt2x00dev->cap_flags); /* * Set the rssi offset. diff --git a/drivers/net/wireless/rt2x00/rt73usb.c b/drivers/net/wireless/rt2x00/rt73usb.c index 6593059..cdb026d 100644 --- a/drivers/net/wireless/rt2x00/rt73usb.c +++ b/drivers/net/wireless/rt2x00/rt73usb.c @@ -595,7 +595,7 @@ static void rt73usb_config_antenna_5x(struct rt2x00_dev *rt2x00dev, switch (ant->rx) { case ANTENNA_HW_DIVERSITY: rt2x00_set_field8(&r4, BBP_R4_RX_ANTENNA_CONTROL, 2); - temp = !test_bit(CONFIG_FRAME_TYPE, &rt2x00dev->flags) + temp = !test_bit(CAPABILITY_FRAME_TYPE, &rt2x00dev->cap_flags) && (rt2x00dev->curr_band != IEEE80211_BAND_5GHZ); rt2x00_set_field8(&r4, BBP_R4_RX_FRAME_END, temp); break; @@ -636,7 +636,7 @@ static void rt73usb_config_antenna_2x(struct rt2x00_dev *rt2x00dev, rt2x00_set_field8(&r3, BBP_R3_SMART_MODE, 0); rt2x00_set_field8(&r4, BBP_R4_RX_FRAME_END, - !test_bit(CONFIG_FRAME_TYPE, &rt2x00dev->flags)); + !test_bit(CAPABILITY_FRAME_TYPE, &rt2x00dev->cap_flags)); /* * Configure the RX antenna. @@ -709,10 +709,10 @@ static void rt73usb_config_ant(struct rt2x00_dev *rt2x00dev, if (rt2x00dev->curr_band == IEEE80211_BAND_5GHZ) { sel = antenna_sel_a; - lna = test_bit(CONFIG_EXTERNAL_LNA_A, &rt2x00dev->flags); + lna = test_bit(CAPABILITY_EXTERNAL_LNA_A, &rt2x00dev->cap_flags); } else { sel = antenna_sel_bg; - lna = test_bit(CONFIG_EXTERNAL_LNA_BG, &rt2x00dev->flags); + lna = test_bit(CAPABILITY_EXTERNAL_LNA_BG, &rt2x00dev->cap_flags); } for (i = 0; i < ARRAY_SIZE(antenna_sel_a); i++) @@ -740,7 +740,7 @@ static void rt73usb_config_lna_gain(struct rt2x00_dev *rt2x00dev, short lna_gain = 0; if (libconf->conf->channel->band == IEEE80211_BAND_2GHZ) { - if (test_bit(CONFIG_EXTERNAL_LNA_BG, &rt2x00dev->flags)) + if (test_bit(CAPABILITY_EXTERNAL_LNA_BG, &rt2x00dev->cap_flags)) lna_gain += 14; rt2x00_eeprom_read(rt2x00dev, EEPROM_RSSI_OFFSET_BG, &eeprom); @@ -930,7 +930,7 @@ static void rt73usb_link_tuner(struct rt2x00_dev *rt2x00dev, low_bound = 0x28; up_bound = 0x48; - if (test_bit(CONFIG_EXTERNAL_LNA_A, &rt2x00dev->flags)) { + if (test_bit(CAPABILITY_EXTERNAL_LNA_A, &rt2x00dev->cap_flags)) { low_bound += 0x10; up_bound += 0x10; } @@ -946,7 +946,7 @@ static void rt73usb_link_tuner(struct rt2x00_dev *rt2x00dev, up_bound = 0x1c; } - if (test_bit(CONFIG_EXTERNAL_LNA_BG, &rt2x00dev->flags)) { + if (test_bit(CAPABILITY_EXTERNAL_LNA_BG, &rt2x00dev->cap_flags)) { low_bound += 0x14; up_bound += 0x10; } @@ -1661,7 +1661,7 @@ static int rt73usb_agc_to_rssi(struct rt2x00_dev *rt2x00dev, int rxd_w1) } if (rt2x00dev->curr_band == IEEE80211_BAND_5GHZ) { - if (test_bit(CONFIG_EXTERNAL_LNA_A, &rt2x00dev->flags)) { + if (test_bit(CAPABILITY_EXTERNAL_LNA_A, &rt2x00dev->cap_flags)) { if (lna == 3 || lna == 2) offset += 10; } else { @@ -1899,13 +1899,13 @@ static int rt73usb_init_eeprom(struct rt2x00_dev *rt2x00dev) * Read the Frame type. */ if (rt2x00_get_field16(eeprom, EEPROM_ANTENNA_FRAME_TYPE)) - __set_bit(CONFIG_FRAME_TYPE, &rt2x00dev->flags); + __set_bit(CAPABILITY_FRAME_TYPE, &rt2x00dev->cap_flags); /* * Detect if this device has an hardware controlled radio. */ if (rt2x00_get_field16(eeprom, EEPROM_ANTENNA_HARDWARE_RADIO)) - __set_bit(CONFIG_SUPPORT_HW_BUTTON, &rt2x00dev->flags); + __set_bit(CAPABILITY_HW_BUTTON, &rt2x00dev->cap_flags); /* * Read frequency offset. @@ -1919,8 +1919,8 @@ static int rt73usb_init_eeprom(struct rt2x00_dev *rt2x00dev) rt2x00_eeprom_read(rt2x00dev, EEPROM_NIC, &eeprom); if (rt2x00_get_field16(eeprom, EEPROM_NIC_EXTERNAL_LNA)) { - __set_bit(CONFIG_EXTERNAL_LNA_A, &rt2x00dev->flags); - __set_bit(CONFIG_EXTERNAL_LNA_BG, &rt2x00dev->flags); + __set_bit(CAPABILITY_EXTERNAL_LNA_A, &rt2x00dev->cap_flags); + __set_bit(CAPABILITY_EXTERNAL_LNA_BG, &rt2x00dev->cap_flags); } /* @@ -2200,15 +2200,15 @@ static int rt73usb_probe_hw(struct rt2x00_dev *rt2x00dev) * This device has multiple filters for control frames, * but has no a separate filter for PS Poll frames. */ - __set_bit(DRIVER_SUPPORT_CONTROL_FILTERS, &rt2x00dev->flags); + __set_bit(CAPABILITY_CONTROL_FILTERS, &rt2x00dev->cap_flags); /* * This device requires firmware. */ - __set_bit(DRIVER_REQUIRE_FIRMWARE, &rt2x00dev->flags); + __set_bit(REQUIRE_FIRMWARE, &rt2x00dev->cap_flags); if (!modparam_nohwcrypt) - __set_bit(CONFIG_SUPPORT_HW_CRYPTO, &rt2x00dev->flags); - __set_bit(DRIVER_SUPPORT_LINK_TUNING, &rt2x00dev->flags); + __set_bit(CAPABILITY_HW_CRYPTO, &rt2x00dev->cap_flags); + __set_bit(CAPABILITY_LINK_TUNING, &rt2x00dev->cap_flags); /* * Set the rssi offset. -- cgit v0.10.2 From 10e11568ca8b8a15f7478f6a4ceebabcbdba1018 Mon Sep 17 00:00:00 2001 From: Helmut Schaa Date: Mon, 18 Apr 2011 15:27:43 +0200 Subject: rt2x00: Make rt2x00_queue_entry_for_each more flexible Allow passing a void pointer to rt2x00_queue_entry_for_each which in turn in provided to the callback function. Furthermore, allow the callback function to stop processing by returning true. And also notify the caller of rt2x00_queue_entry_for_each if the loop was canceled by the callback. No functional changes, just preparation for an upcoming patch. Signed-off-by: Helmut Schaa Signed-off-by: Ivo van Doorn Acked-by: Gertjan van Wingerde Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/rt2x00/rt2x00queue.c b/drivers/net/wireless/rt2x00/rt2x00queue.c index d03eef2..458bb48 100644 --- a/drivers/net/wireless/rt2x00/rt2x00queue.c +++ b/drivers/net/wireless/rt2x00/rt2x00queue.c @@ -650,10 +650,12 @@ int rt2x00queue_update_beacon(struct rt2x00_dev *rt2x00dev, return ret; } -void rt2x00queue_for_each_entry(struct data_queue *queue, +bool rt2x00queue_for_each_entry(struct data_queue *queue, enum queue_index start, enum queue_index end, - void (*fn)(struct queue_entry *entry)) + void *data, + bool (*fn)(struct queue_entry *entry, + void *data)) { unsigned long irqflags; unsigned int index_start; @@ -664,7 +666,7 @@ void rt2x00queue_for_each_entry(struct data_queue *queue, ERROR(queue->rt2x00dev, "Entry requested from invalid index range (%d - %d)\n", start, end); - return; + return true; } /* @@ -683,15 +685,23 @@ void rt2x00queue_for_each_entry(struct data_queue *queue, * send out all frames in the correct order. */ if (index_start < index_end) { - for (i = index_start; i < index_end; i++) - fn(&queue->entries[i]); + for (i = index_start; i < index_end; i++) { + if (fn(&queue->entries[i], data)) + return true; + } } else { - for (i = index_start; i < queue->limit; i++) - fn(&queue->entries[i]); + for (i = index_start; i < queue->limit; i++) { + if (fn(&queue->entries[i], data)) + return true; + } - for (i = 0; i < index_end; i++) - fn(&queue->entries[i]); + for (i = 0; i < index_end; i++) { + if (fn(&queue->entries[i], data)) + return true; + } } + + return false; } EXPORT_SYMBOL_GPL(rt2x00queue_for_each_entry); diff --git a/drivers/net/wireless/rt2x00/rt2x00queue.h b/drivers/net/wireless/rt2x00/rt2x00queue.h index 6ae8200..6b66452 100644 --- a/drivers/net/wireless/rt2x00/rt2x00queue.h +++ b/drivers/net/wireless/rt2x00/rt2x00queue.h @@ -580,16 +580,22 @@ struct data_queue_desc { * @queue: Pointer to @data_queue * @start: &enum queue_index Pointer to start index * @end: &enum queue_index Pointer to end index + * @data: Data to pass to the callback function * @fn: The function to call for each &struct queue_entry * * This will walk through all entries in the queue, in chronological * order. This means it will start at the current @start pointer * and will walk through the queue until it reaches the @end pointer. + * + * If fn returns true for an entry rt2x00queue_for_each_entry will stop + * processing and return true as well. */ -void rt2x00queue_for_each_entry(struct data_queue *queue, +bool rt2x00queue_for_each_entry(struct data_queue *queue, enum queue_index start, enum queue_index end, - void (*fn)(struct queue_entry *entry)); + void *data, + bool (*fn)(struct queue_entry *entry, + void *data)); /** * rt2x00queue_empty - Check if the queue is empty. diff --git a/drivers/net/wireless/rt2x00/rt2x00usb.c b/drivers/net/wireless/rt2x00/rt2x00usb.c index 94047e9..0bc8dcc 100644 --- a/drivers/net/wireless/rt2x00/rt2x00usb.c +++ b/drivers/net/wireless/rt2x00/rt2x00usb.c @@ -230,7 +230,7 @@ static void rt2x00usb_interrupt_txdone(struct urb *urb) queue_work(rt2x00dev->workqueue, &rt2x00dev->txdone_work); } -static void rt2x00usb_kick_tx_entry(struct queue_entry *entry) +static bool rt2x00usb_kick_tx_entry(struct queue_entry *entry, void* data) { struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev; struct usb_device *usb_dev = to_usb_device_intf(rt2x00dev->dev); @@ -240,7 +240,7 @@ static void rt2x00usb_kick_tx_entry(struct queue_entry *entry) if (!test_and_clear_bit(ENTRY_DATA_PENDING, &entry->flags) || test_bit(ENTRY_DATA_STATUS_PENDING, &entry->flags)) - return; + return true; /* * USB devices cannot blindly pass the skb->len as the @@ -261,6 +261,8 @@ static void rt2x00usb_kick_tx_entry(struct queue_entry *entry) set_bit(ENTRY_DATA_IO_FAILED, &entry->flags); rt2x00lib_dmadone(entry); } + + return false; } /* @@ -323,7 +325,7 @@ static void rt2x00usb_interrupt_rxdone(struct urb *urb) queue_work(rt2x00dev->workqueue, &rt2x00dev->rxdone_work); } -static void rt2x00usb_kick_rx_entry(struct queue_entry *entry) +static bool rt2x00usb_kick_rx_entry(struct queue_entry *entry, void* data) { struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev; struct usb_device *usb_dev = to_usb_device_intf(rt2x00dev->dev); @@ -332,7 +334,7 @@ static void rt2x00usb_kick_rx_entry(struct queue_entry *entry) if (test_and_set_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags) || test_bit(ENTRY_DATA_STATUS_PENDING, &entry->flags)) - return; + return true; rt2x00lib_dmastart(entry); @@ -348,6 +350,8 @@ static void rt2x00usb_kick_rx_entry(struct queue_entry *entry) set_bit(ENTRY_DATA_IO_FAILED, &entry->flags); rt2x00lib_dmadone(entry); } + + return false; } void rt2x00usb_kick_queue(struct data_queue *queue) @@ -358,12 +362,18 @@ void rt2x00usb_kick_queue(struct data_queue *queue) case QID_AC_BE: case QID_AC_BK: if (!rt2x00queue_empty(queue)) - rt2x00queue_for_each_entry(queue, Q_INDEX_DONE, Q_INDEX, + rt2x00queue_for_each_entry(queue, + Q_INDEX_DONE, + Q_INDEX, + NULL, rt2x00usb_kick_tx_entry); break; case QID_RX: if (!rt2x00queue_full(queue)) - rt2x00queue_for_each_entry(queue, Q_INDEX_DONE, Q_INDEX, + rt2x00queue_for_each_entry(queue, + Q_INDEX_DONE, + Q_INDEX, + NULL, rt2x00usb_kick_rx_entry); break; default: @@ -372,14 +382,14 @@ void rt2x00usb_kick_queue(struct data_queue *queue) } EXPORT_SYMBOL_GPL(rt2x00usb_kick_queue); -static void rt2x00usb_flush_entry(struct queue_entry *entry) +static bool rt2x00usb_flush_entry(struct queue_entry *entry, void* data) { struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev; struct queue_entry_priv_usb *entry_priv = entry->priv_data; struct queue_entry_priv_usb_bcn *bcn_priv = entry->priv_data; if (!test_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags)) - return; + return true; usb_kill_urb(entry_priv->urb); @@ -389,6 +399,8 @@ static void rt2x00usb_flush_entry(struct queue_entry *entry) if ((entry->queue->qid == QID_BEACON) && (test_bit(REQUIRE_BEACON_GUARD, &rt2x00dev->cap_flags))) usb_kill_urb(bcn_priv->guardian_urb); + + return false; } void rt2x00usb_flush_queue(struct data_queue *queue) @@ -396,7 +408,7 @@ void rt2x00usb_flush_queue(struct data_queue *queue) struct work_struct *completion; unsigned int i; - rt2x00queue_for_each_entry(queue, Q_INDEX_DONE, Q_INDEX, + rt2x00queue_for_each_entry(queue, Q_INDEX_DONE, Q_INDEX, NULL, rt2x00usb_flush_entry); /* @@ -489,7 +501,7 @@ void rt2x00usb_clear_entry(struct queue_entry *entry) entry->flags = 0; if (entry->queue->qid == QID_RX) - rt2x00usb_kick_rx_entry(entry); + rt2x00usb_kick_rx_entry(entry, NULL); } EXPORT_SYMBOL_GPL(rt2x00usb_clear_entry); -- cgit v0.10.2 From 15a533c47f9ebb8dec8e440275136cbf9c493a1f Mon Sep 17 00:00:00 2001 From: Helmut Schaa Date: Mon, 18 Apr 2011 15:28:04 +0200 Subject: rt2x00: Use correct TBTT_SYNC config in AP mode This seems to fix problems with some powersaving clients since a positive value in TBTT_SYNC_CFG_TBTT_ADJUST introduces beacon skew, which is not wanted in AP mode. Also update the rest of the TBTT_SYNC config according to the legacy drivers in AP mode. Signed-off-by: Helmut Schaa Signed-off-by: Ivo van Doorn Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/rt2x00/rt2800lib.c b/drivers/net/wireless/rt2x00/rt2800lib.c index c6f5584..e0fa559 100644 --- a/drivers/net/wireless/rt2x00/rt2800lib.c +++ b/drivers/net/wireless/rt2x00/rt2800lib.c @@ -1245,6 +1245,25 @@ void rt2800_config_intf(struct rt2x00_dev *rt2x00dev, struct rt2x00_intf *intf, rt2800_register_read(rt2x00dev, BCN_TIME_CFG, ®); rt2x00_set_field32(®, BCN_TIME_CFG_TSF_SYNC, conf->sync); rt2800_register_write(rt2x00dev, BCN_TIME_CFG, reg); + + if (conf->sync == TSF_SYNC_AP_NONE) { + /* + * Tune beacon queue transmit parameters for AP mode + */ + rt2800_register_read(rt2x00dev, TBTT_SYNC_CFG, ®); + rt2x00_set_field32(®, TBTT_SYNC_CFG_BCN_CWMIN, 0); + rt2x00_set_field32(®, TBTT_SYNC_CFG_BCN_AIFSN, 1); + rt2x00_set_field32(®, TBTT_SYNC_CFG_BCN_EXP_WIN, 32); + rt2x00_set_field32(®, TBTT_SYNC_CFG_TBTT_ADJUST, 0); + rt2800_register_write(rt2x00dev, TBTT_SYNC_CFG, reg); + } else { + rt2800_register_read(rt2x00dev, TBTT_SYNC_CFG, ®); + rt2x00_set_field32(®, TBTT_SYNC_CFG_BCN_CWMIN, 4); + rt2x00_set_field32(®, TBTT_SYNC_CFG_BCN_AIFSN, 2); + rt2x00_set_field32(®, TBTT_SYNC_CFG_BCN_EXP_WIN, 32); + rt2x00_set_field32(®, TBTT_SYNC_CFG_TBTT_ADJUST, 16); + rt2800_register_write(rt2x00dev, TBTT_SYNC_CFG, reg); + } } if (flags & CONFIG_UPDATE_MAC) { -- cgit v0.10.2 From 961636ba17fa45b27ee4674430e1e775b8966b0e Mon Sep 17 00:00:00 2001 From: Helmut Schaa Date: Mon, 18 Apr 2011 15:28:27 +0200 Subject: rt2x00: Update TX_SW_CFG2 init value Bring the TX_SW_CFG2 initialisation for rt305x devices in sync with the ralink legacy drivers. Signed-off-by: Helmut Schaa Acked-by: Gertjan van Wingerde Signed-off-by: Ivo van Doorn Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/rt2x00/rt2800lib.c b/drivers/net/wireless/rt2x00/rt2800lib.c index e0fa559..0e2c006 100644 --- a/drivers/net/wireless/rt2x00/rt2800lib.c +++ b/drivers/net/wireless/rt2x00/rt2800lib.c @@ -2427,7 +2427,7 @@ static int rt2800_init_registers(struct rt2x00_dev *rt2x00dev) } else if (rt2800_is_305x_soc(rt2x00dev)) { rt2800_register_write(rt2x00dev, TX_SW_CFG0, 0x00000400); rt2800_register_write(rt2x00dev, TX_SW_CFG1, 0x00000000); - rt2800_register_write(rt2x00dev, TX_SW_CFG2, 0x0000001f); + rt2800_register_write(rt2x00dev, TX_SW_CFG2, 0x00000030); } else if (rt2x00_rt(rt2x00dev, RT5390)) { rt2800_register_write(rt2x00dev, TX_SW_CFG0, 0x00000404); rt2800_register_write(rt2x00dev, TX_SW_CFG1, 0x00080606); -- cgit v0.10.2 From 8da3efbb4a18be30ed03dd05af18d0b026b15173 Mon Sep 17 00:00:00 2001 From: Helmut Schaa Date: Mon, 18 Apr 2011 15:28:50 +0200 Subject: rt2x00: Use TXOP_HTTXOP for beacons Use TXOP_HTTXOP for beacons to stay in sync with the legacy drivers. Signed-off-by: Helmut Schaa Acked-by: Gertjan van Wingerde Signed-off-by: Ivo van Doorn Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/rt2x00/rt2x00ht.c b/drivers/net/wireless/rt2x00/rt2x00ht.c index e8c0c3e..a30f68c 100644 --- a/drivers/net/wireless/rt2x00/rt2x00ht.c +++ b/drivers/net/wireless/rt2x00/rt2x00ht.c @@ -92,14 +92,15 @@ void rt2x00ht_create_tx_descriptor(struct queue_entry *entry, /* * Determine IFS values - * - Use TXOP_BACKOFF for management frames + * - Use TXOP_BACKOFF for management frames except beacons * - Use TXOP_SIFS for fragment bursts * - Use TXOP_HTTXOP for everything else * * Note: rt2800 devices won't use CTS protection (if used) * for frames not transmitted with TXOP_HTTXOP */ - if (ieee80211_is_mgmt(hdr->frame_control)) + if (ieee80211_is_mgmt(hdr->frame_control) && + !ieee80211_is_beacon(hdr->frame_control)) txdesc->u.ht.txop = TXOP_BACKOFF; else if (!(tx_info->flags & IEEE80211_TX_CTL_FIRST_FRAGMENT)) txdesc->u.ht.txop = TXOP_SIFS; -- cgit v0.10.2 From 0e0d39e5f3a3e59c8513b59d4feeeadcb93b707d Mon Sep 17 00:00:00 2001 From: Johannes Stezenbach Date: Mon, 18 Apr 2011 15:29:12 +0200 Subject: rt2800usb: read TX_STA_FIFO asynchronously Trying to fix the "TX status report missed" warnings by reading the TX_STA_FIFO entries as quickly as possible. The TX_STA_FIFO is too small in hardware, thus reading it only from the workqueue is too slow and entries get lost. Start an asynchronous read of the TX_STA_FIFO directly from the TX URB completion callback (atomic context, thus it cannot use the blocking rt2800_register_read()). If the async read returns a valid FIFO entry, it is pushed into a larger FIFO inside struct rt2x00_dev, until rt2800_txdone() picks it up. A .tx_dma_done callback is added to struct rt2x00lib_ops to trigger the async read from the URB completion callback. Signed-off-by: Johannes Stezenbach Signed-off-by: Ivo van Doorn Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/rt2x00/rt2800lib.c b/drivers/net/wireless/rt2x00/rt2800lib.c index 0e2c006..d79c8fd 100644 --- a/drivers/net/wireless/rt2x00/rt2800lib.c +++ b/drivers/net/wireless/rt2x00/rt2800lib.c @@ -730,34 +730,20 @@ void rt2800_txdone(struct rt2x00_dev *rt2x00dev) struct data_queue *queue; struct queue_entry *entry; u32 reg; - u8 pid; - int i; + u8 qid; - /* - * TX_STA_FIFO is a stack of X entries, hence read TX_STA_FIFO - * at most X times and also stop processing once the TX_STA_FIFO_VALID - * flag is not set anymore. - * - * The legacy drivers use X=TX_RING_SIZE but state in a comment - * that the TX_STA_FIFO stack has a size of 16. We stick to our - * tx ring size for now. - */ - for (i = 0; i < rt2x00dev->ops->tx->entry_num; i++) { - rt2800_register_read(rt2x00dev, TX_STA_FIFO, ®); - if (!rt2x00_get_field32(reg, TX_STA_FIFO_VALID)) - break; + while (kfifo_get(&rt2x00dev->txstatus_fifo, ®)) { - /* - * Skip this entry when it contains an invalid - * queue identication number. + /* TX_STA_FIFO_PID_QUEUE is a 2-bit field, thus + * qid is guaranteed to be one of the TX QIDs */ - pid = rt2x00_get_field32(reg, TX_STA_FIFO_PID_QUEUE); - if (pid >= QID_RX) - continue; - - queue = rt2x00queue_get_tx_queue(rt2x00dev, pid); - if (unlikely(!queue)) + qid = rt2x00_get_field32(reg, TX_STA_FIFO_PID_QUEUE); + queue = rt2x00queue_get_tx_queue(rt2x00dev, qid); + if (unlikely(!queue)) { + WARNING(rt2x00dev, "Got TX status for an unavailable " + "queue %u, dropping\n", qid); continue; + } /* * Inside each queue, we process each entry in a chronological diff --git a/drivers/net/wireless/rt2x00/rt2800usb.c b/drivers/net/wireless/rt2x00/rt2800usb.c index f3ce5e8..862430e 100644 --- a/drivers/net/wireless/rt2x00/rt2800usb.c +++ b/drivers/net/wireless/rt2x00/rt2800usb.c @@ -98,6 +98,35 @@ static void rt2800usb_stop_queue(struct data_queue *queue) } } +static void rt2800usb_tx_sta_fifo_read_completed(struct rt2x00_dev *rt2x00dev, + int urb_status, u32 tx_status) +{ + if (urb_status) { + WARNING(rt2x00dev, "rt2x00usb_register_read_async failed: %d\n", urb_status); + return; + } + + /* try to read all TX_STA_FIFO entries before scheduling txdone_work */ + if (rt2x00_get_field32(tx_status, TX_STA_FIFO_VALID)) { + if (!kfifo_put(&rt2x00dev->txstatus_fifo, &tx_status)) { + WARNING(rt2x00dev, "TX status FIFO overrun, " + "drop tx status report.\n"); + queue_work(rt2x00dev->workqueue, &rt2x00dev->txdone_work); + } else + rt2x00usb_register_read_async(rt2x00dev, TX_STA_FIFO, + rt2800usb_tx_sta_fifo_read_completed); + } else if (!kfifo_is_empty(&rt2x00dev->txstatus_fifo)) + queue_work(rt2x00dev->workqueue, &rt2x00dev->txdone_work); +} + +static void rt2800usb_tx_dma_done(struct queue_entry *entry) +{ + struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev; + + rt2x00usb_register_read_async(rt2x00dev, TX_STA_FIFO, + rt2800usb_tx_sta_fifo_read_completed); +} + /* * Firmware functions */ @@ -565,6 +594,7 @@ static int rt2800usb_probe_hw(struct rt2x00_dev *rt2x00dev) __set_bit(CAPABILITY_HW_CRYPTO, &rt2x00dev->cap_flags); __set_bit(CAPABILITY_LINK_TUNING, &rt2x00dev->cap_flags); __set_bit(REQUIRE_HT_TX_DESC, &rt2x00dev->cap_flags); + __set_bit(REQUIRE_TXSTATUS_FIFO, &rt2x00dev->cap_flags); /* * Set the rssi offset. @@ -635,6 +665,7 @@ static const struct rt2x00lib_ops rt2800usb_rt2x00_ops = { .kick_queue = rt2x00usb_kick_queue, .stop_queue = rt2800usb_stop_queue, .flush_queue = rt2x00usb_flush_queue, + .tx_dma_done = rt2800usb_tx_dma_done, .write_tx_desc = rt2800usb_write_tx_desc, .write_tx_data = rt2800usb_write_tx_data, .write_beacon = rt2800_write_beacon, diff --git a/drivers/net/wireless/rt2x00/rt2x00.h b/drivers/net/wireless/rt2x00/rt2x00.h index 79c385a..e3b9b51 100644 --- a/drivers/net/wireless/rt2x00/rt2x00.h +++ b/drivers/net/wireless/rt2x00/rt2x00.h @@ -571,6 +571,7 @@ struct rt2x00lib_ops { void (*kick_queue) (struct data_queue *queue); void (*stop_queue) (struct data_queue *queue); void (*flush_queue) (struct data_queue *queue); + void (*tx_dma_done) (struct queue_entry *entry); /* * TX control handlers diff --git a/drivers/net/wireless/rt2x00/rt2x00usb.c b/drivers/net/wireless/rt2x00/rt2x00usb.c index 0bc8dcc..5fbab6f 100644 --- a/drivers/net/wireless/rt2x00/rt2x00usb.c +++ b/drivers/net/wireless/rt2x00/rt2x00usb.c @@ -165,6 +165,56 @@ int rt2x00usb_regbusy_read(struct rt2x00_dev *rt2x00dev, } EXPORT_SYMBOL_GPL(rt2x00usb_regbusy_read); + +struct rt2x00_async_read_data { + __le32 reg; + struct usb_ctrlrequest cr; + struct rt2x00_dev *rt2x00dev; + void (*callback)(struct rt2x00_dev *,int,u32); +}; + +static void rt2x00usb_register_read_async_cb(struct urb *urb) +{ + struct rt2x00_async_read_data *rd = urb->context; + rd->callback(rd->rt2x00dev, urb->status, le32_to_cpu(rd->reg)); + kfree(urb->context); +} + +void rt2x00usb_register_read_async(struct rt2x00_dev *rt2x00dev, + const unsigned int offset, + void (*callback)(struct rt2x00_dev*,int,u32)) +{ + struct usb_device *usb_dev = to_usb_device_intf(rt2x00dev->dev); + struct urb *urb; + struct rt2x00_async_read_data *rd; + + rd = kmalloc(sizeof(*rd), GFP_ATOMIC); + if (!rd) + return; + + urb = usb_alloc_urb(0, GFP_ATOMIC); + if (!urb) { + kfree(rd); + return; + } + + rd->rt2x00dev = rt2x00dev; + rd->callback = callback; + rd->cr.bRequestType = USB_VENDOR_REQUEST_IN; + rd->cr.bRequest = USB_MULTI_READ; + rd->cr.wValue = 0; + rd->cr.wIndex = cpu_to_le16(offset); + rd->cr.wLength = cpu_to_le16(sizeof(u32)); + + usb_fill_control_urb(urb, usb_dev, usb_rcvctrlpipe(usb_dev, 0), + (unsigned char *)(&rd->cr), &rd->reg, sizeof(rd->reg), + rt2x00usb_register_read_async_cb, rd); + if (usb_submit_urb(urb, GFP_ATOMIC) < 0) + kfree(rd); + usb_free_urb(urb); +} +EXPORT_SYMBOL_GPL(rt2x00usb_register_read_async); + /* * TX data handlers. */ @@ -212,6 +262,9 @@ static void rt2x00usb_interrupt_txdone(struct urb *urb) if (!test_and_clear_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags)) return; + if (rt2x00dev->ops->lib->tx_dma_done) + rt2x00dev->ops->lib->tx_dma_done(entry); + /* * Report the frame as DMA done */ diff --git a/drivers/net/wireless/rt2x00/rt2x00usb.h b/drivers/net/wireless/rt2x00/rt2x00usb.h index 6aaf51f..e3faca6 100644 --- a/drivers/net/wireless/rt2x00/rt2x00usb.h +++ b/drivers/net/wireless/rt2x00/rt2x00usb.h @@ -345,6 +345,21 @@ int rt2x00usb_regbusy_read(struct rt2x00_dev *rt2x00dev, const struct rt2x00_field32 field, u32 *reg); +/** + * rt2x00usb_register_read_async - Asynchronously read 32bit register word + * @rt2x00dev: Device pointer, see &struct rt2x00_dev. + * @offset: Register offset + * @callback: Functon to call when read completes. + * + * Submit a control URB to read a 32bit register. This safe to + * be called from atomic context. The callback will be called + * when the URB completes. Otherwise the function is similar + * to rt2x00usb_register_read(). + */ +void rt2x00usb_register_read_async(struct rt2x00_dev *rt2x00dev, + const unsigned int offset, + void (*callback)(struct rt2x00_dev*,int,u32)); + /* * Radio handlers */ -- cgit v0.10.2 From 75256f0348d38f414b7ac50ac78d4a4532bb6762 Mon Sep 17 00:00:00 2001 From: Johannes Stezenbach Date: Mon, 18 Apr 2011 15:29:38 +0200 Subject: rt2x00: fix queue timeout checks Add a timestamp to each queue entry which is updated whenever the status of the entry changes, and remove the per-queue timestamps. The previous check was incorrect and caused both false positives and false negatives. With the corrected check it comes apparent that the TX status usually times out on rt2800usb unless there is sufficient traffic (i.e. the next TX will complete the previous TX status). Signed-off-by: Johannes Stezenbach Signed-off-by: Ivo van Doorn Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/rt2x00/rt2x00dev.c b/drivers/net/wireless/rt2x00/rt2x00dev.c index af25b01..2e490e0 100644 --- a/drivers/net/wireless/rt2x00/rt2x00dev.c +++ b/drivers/net/wireless/rt2x00/rt2x00dev.c @@ -225,7 +225,7 @@ EXPORT_SYMBOL_GPL(rt2x00lib_pretbtt); void rt2x00lib_dmastart(struct queue_entry *entry) { set_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags); - rt2x00queue_index_inc(entry->queue, Q_INDEX); + rt2x00queue_index_inc(entry, Q_INDEX); } EXPORT_SYMBOL_GPL(rt2x00lib_dmastart); @@ -233,7 +233,7 @@ void rt2x00lib_dmadone(struct queue_entry *entry) { set_bit(ENTRY_DATA_STATUS_PENDING, &entry->flags); clear_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags); - rt2x00queue_index_inc(entry->queue, Q_INDEX_DMA_DONE); + rt2x00queue_index_inc(entry, Q_INDEX_DMA_DONE); } EXPORT_SYMBOL_GPL(rt2x00lib_dmadone); @@ -392,7 +392,7 @@ void rt2x00lib_txdone(struct queue_entry *entry, rt2x00dev->ops->lib->clear_entry(entry); - rt2x00queue_index_inc(entry->queue, Q_INDEX_DONE); + rt2x00queue_index_inc(entry, Q_INDEX_DONE); /* * If the data queue was below the threshold before the txdone @@ -559,7 +559,7 @@ void rt2x00lib_rxdone(struct queue_entry *entry) submit_entry: entry->flags = 0; - rt2x00queue_index_inc(entry->queue, Q_INDEX_DONE); + rt2x00queue_index_inc(entry, Q_INDEX_DONE); if (test_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags) && test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags)) rt2x00dev->ops->lib->clear_entry(entry); diff --git a/drivers/net/wireless/rt2x00/rt2x00lib.h b/drivers/net/wireless/rt2x00/rt2x00lib.h index bbee2cd..57ede6c 100644 --- a/drivers/net/wireless/rt2x00/rt2x00lib.h +++ b/drivers/net/wireless/rt2x00/rt2x00lib.h @@ -175,14 +175,14 @@ int rt2x00queue_clear_beacon(struct rt2x00_dev *rt2x00dev, /** * rt2x00queue_index_inc - Index incrementation function - * @queue: Queue (&struct data_queue) to perform the action on. + * @entry: Queue entry (&struct queue_entry) to perform the action on. * @index: Index type (&enum queue_index) to perform the action on. * - * This function will increase the requested index on the queue, + * This function will increase the requested index on the entry's queue, * it will grab the appropriate locks and handle queue overflow events by * resetting the index to the start of the queue. */ -void rt2x00queue_index_inc(struct data_queue *queue, enum queue_index index); +void rt2x00queue_index_inc(struct queue_entry *entry, enum queue_index index); /** * rt2x00queue_init_queues - Initialize all data queues diff --git a/drivers/net/wireless/rt2x00/rt2x00queue.c b/drivers/net/wireless/rt2x00/rt2x00queue.c index 458bb48..df8817f 100644 --- a/drivers/net/wireless/rt2x00/rt2x00queue.c +++ b/drivers/net/wireless/rt2x00/rt2x00queue.c @@ -561,7 +561,7 @@ int rt2x00queue_write_tx_frame(struct data_queue *queue, struct sk_buff *skb, set_bit(ENTRY_DATA_PENDING, &entry->flags); - rt2x00queue_index_inc(queue, Q_INDEX); + rt2x00queue_index_inc(entry, Q_INDEX); rt2x00queue_write_tx_descriptor(entry, &txdesc); rt2x00queue_kick_tx_queue(queue, &txdesc); @@ -727,8 +727,9 @@ struct queue_entry *rt2x00queue_get_entry(struct data_queue *queue, } EXPORT_SYMBOL_GPL(rt2x00queue_get_entry); -void rt2x00queue_index_inc(struct data_queue *queue, enum queue_index index) +void rt2x00queue_index_inc(struct queue_entry *entry, enum queue_index index) { + struct data_queue *queue = entry->queue; unsigned long irqflags; if (unlikely(index >= Q_INDEX_MAX)) { @@ -743,7 +744,7 @@ void rt2x00queue_index_inc(struct data_queue *queue, enum queue_index index) if (queue->index[index] >= queue->limit) queue->index[index] = 0; - queue->last_action[index] = jiffies; + entry->last_action = jiffies; if (index == Q_INDEX) { queue->length++; @@ -969,10 +970,8 @@ static void rt2x00queue_reset(struct data_queue *queue) queue->count = 0; queue->length = 0; - for (i = 0; i < Q_INDEX_MAX; i++) { + for (i = 0; i < Q_INDEX_MAX; i++) queue->index[i] = 0; - queue->last_action[i] = jiffies; - } spin_unlock_irqrestore(&queue->index_lock, irqflags); } diff --git a/drivers/net/wireless/rt2x00/rt2x00queue.h b/drivers/net/wireless/rt2x00/rt2x00queue.h index 6b66452..36f4d03 100644 --- a/drivers/net/wireless/rt2x00/rt2x00queue.h +++ b/drivers/net/wireless/rt2x00/rt2x00queue.h @@ -364,6 +364,7 @@ enum queue_entry_flags { * struct queue_entry: Entry inside the &struct data_queue * * @flags: Entry flags, see &enum queue_entry_flags. + * @last_action: Timestamp of last change. * @queue: The data queue (&struct data_queue) to which this entry belongs. * @skb: The buffer which is currently being transmitted (for TX queue), * or used to directly recieve data in (for RX queue). @@ -373,6 +374,7 @@ enum queue_entry_flags { */ struct queue_entry { unsigned long flags; + unsigned long last_action; struct data_queue *queue; @@ -463,7 +465,6 @@ struct data_queue { unsigned short threshold; unsigned short length; unsigned short index[Q_INDEX_MAX]; - unsigned long last_action[Q_INDEX_MAX]; unsigned short txop; unsigned short aifs; @@ -635,22 +636,24 @@ static inline int rt2x00queue_threshold(struct data_queue *queue) /** * rt2x00queue_status_timeout - Check if a timeout occured for STATUS reports - * @queue: Queue to check. + * @entry: Queue entry to check. */ -static inline int rt2x00queue_status_timeout(struct data_queue *queue) +static inline int rt2x00queue_status_timeout(struct queue_entry *entry) { - return time_after(queue->last_action[Q_INDEX_DMA_DONE], - queue->last_action[Q_INDEX_DONE] + (HZ / 10)); + if (!test_bit(ENTRY_DATA_STATUS_PENDING, &entry->flags)) + return false; + return time_after(jiffies, entry->last_action + msecs_to_jiffies(100)); } /** - * rt2x00queue_timeout - Check if a timeout occured for DMA transfers - * @queue: Queue to check. + * rt2x00queuedma__timeout - Check if a timeout occured for DMA transfers + * @entry: Queue entry to check. */ -static inline int rt2x00queue_dma_timeout(struct data_queue *queue) +static inline int rt2x00queue_dma_timeout(struct queue_entry *entry) { - return time_after(queue->last_action[Q_INDEX], - queue->last_action[Q_INDEX_DMA_DONE] + (HZ / 10)); + if (!test_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags)) + return false; + return time_after(jiffies, entry->last_action + msecs_to_jiffies(100)); } /** diff --git a/drivers/net/wireless/rt2x00/rt2x00usb.c b/drivers/net/wireless/rt2x00/rt2x00usb.c index 5fbab6f..14736e2 100644 --- a/drivers/net/wireless/rt2x00/rt2x00usb.c +++ b/drivers/net/wireless/rt2x00/rt2x00usb.c @@ -521,15 +521,31 @@ static void rt2x00usb_watchdog_tx_status(struct data_queue *queue) queue_work(queue->rt2x00dev->workqueue, &queue->rt2x00dev->txdone_work); } +static int rt2x00usb_status_timeout(struct data_queue *queue) +{ + struct queue_entry *entry; + + entry = rt2x00queue_get_entry(queue, Q_INDEX_DONE); + return rt2x00queue_status_timeout(entry); +} + +static int rt2x00usb_dma_timeout(struct data_queue *queue) +{ + struct queue_entry *entry; + + entry = rt2x00queue_get_entry(queue, Q_INDEX_DMA_DONE); + return rt2x00queue_dma_timeout(entry); +} + void rt2x00usb_watchdog(struct rt2x00_dev *rt2x00dev) { struct data_queue *queue; tx_queue_for_each(rt2x00dev, queue) { if (!rt2x00queue_empty(queue)) { - if (rt2x00queue_dma_timeout(queue)) + if (rt2x00usb_dma_timeout(queue)) rt2x00usb_watchdog_tx_dma(queue); - if (rt2x00queue_status_timeout(queue)) + if (rt2x00usb_status_timeout(queue)) rt2x00usb_watchdog_tx_status(queue); } } -- cgit v0.10.2 From 6e6d6932a3f525d734f6c2f5845e9cadfaeddce9 Mon Sep 17 00:00:00 2001 From: Johannes Stezenbach Date: Mon, 18 Apr 2011 15:30:01 +0200 Subject: rt2800usb: handle TX status timeouts The watchdog just triggers rt2800usb_work_txdone() when it detects a TX status timeout, thus rt2800usb_work_txdone() needs to handle this case. Signed-off-by: Johannes Stezenbach Signed-off-by: Ivo van Doorn Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/rt2x00/rt2800usb.c b/drivers/net/wireless/rt2x00/rt2800usb.c index 862430e..69004b9 100644 --- a/drivers/net/wireless/rt2x00/rt2800usb.c +++ b/drivers/net/wireless/rt2x00/rt2800usb.c @@ -449,11 +449,14 @@ static void rt2800usb_work_txdone(struct work_struct *work) while (!rt2x00queue_empty(queue)) { entry = rt2x00queue_get_entry(queue, Q_INDEX_DONE); - if (test_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags) || - !test_bit(ENTRY_DATA_IO_FAILED, &entry->flags)) + if (test_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags)) + break; + if (test_bit(ENTRY_DATA_IO_FAILED, &entry->flags)) + rt2x00lib_txdone_noinfo(entry, TXDONE_FAILURE); + else if (rt2x00queue_status_timeout(entry)) + rt2x00lib_txdone_noinfo(entry, TXDONE_UNKNOWN); + else break; - - rt2x00lib_txdone_noinfo(entry, TXDONE_FAILURE); } } } -- cgit v0.10.2 From f0187a1987ed6524518ff2a533eaf8394ac1a500 Mon Sep 17 00:00:00 2001 From: Johannes Stezenbach Date: Mon, 18 Apr 2011 15:30:36 +0200 Subject: rt2800usb: add timer to handle TX_STA_FIFO TX status is reported by the hardware when a packet has been sent (or after TX failed after possible retries), which is some time after the DMA completion. Since the rt2800usb hardware can not signal interrupts we have to use a timer, otherwise the TX status would only be read by the next packet's TX DMA completion, or by the watchdog thread. Signed-off-by: Johannes Stezenbach Signed-off-by: Ivo van Doorn Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/rt2x00/rt2800usb.c b/drivers/net/wireless/rt2x00/rt2800usb.c index 69004b9..2005972 100644 --- a/drivers/net/wireless/rt2x00/rt2800usb.c +++ b/drivers/net/wireless/rt2x00/rt2800usb.c @@ -98,6 +98,22 @@ static void rt2800usb_stop_queue(struct data_queue *queue) } } +/* + * test if there is an entry in any TX queue for which DMA is done + * but the TX status has not been returned yet + */ +static bool rt2800usb_txstatus_pending(struct rt2x00_dev *rt2x00dev) +{ + struct data_queue *queue; + + tx_queue_for_each(rt2x00dev, queue) { + if (rt2x00queue_get_entry(queue, Q_INDEX_DMA_DONE) != + rt2x00queue_get_entry(queue, Q_INDEX_DONE)) + return true; + } + return false; +} + static void rt2800usb_tx_sta_fifo_read_completed(struct rt2x00_dev *rt2x00dev, int urb_status, u32 tx_status) { @@ -115,8 +131,11 @@ static void rt2800usb_tx_sta_fifo_read_completed(struct rt2x00_dev *rt2x00dev, } else rt2x00usb_register_read_async(rt2x00dev, TX_STA_FIFO, rt2800usb_tx_sta_fifo_read_completed); - } else if (!kfifo_is_empty(&rt2x00dev->txstatus_fifo)) + } else if (!kfifo_is_empty(&rt2x00dev->txstatus_fifo)) { queue_work(rt2x00dev->workqueue, &rt2x00dev->txdone_work); + } else if (rt2800usb_txstatus_pending(rt2x00dev)) { + mod_timer(&rt2x00dev->txstatus_timer, jiffies + msecs_to_jiffies(20)); + } } static void rt2800usb_tx_dma_done(struct queue_entry *entry) @@ -127,6 +146,14 @@ static void rt2800usb_tx_dma_done(struct queue_entry *entry) rt2800usb_tx_sta_fifo_read_completed); } +static void rt2800usb_tx_sta_fifo_timeout(unsigned long data) +{ + struct rt2x00_dev *rt2x00dev = (struct rt2x00_dev *)data; + + rt2x00usb_register_read_async(rt2x00dev, TX_STA_FIFO, + rt2800usb_tx_sta_fifo_read_completed); +} + /* * Firmware functions */ @@ -459,6 +486,14 @@ static void rt2800usb_work_txdone(struct work_struct *work) break; } } + + /* + * The hw may delay sending the packet after DMA complete + * if the medium is busy, thus the TX_STA_FIFO entry is + * also delayed -> use a timer to retrieve it. + */ + if (rt2800usb_txstatus_pending(rt2x00dev)) + mod_timer(&rt2x00dev->txstatus_timer, jiffies + msecs_to_jiffies(20)); } /* @@ -599,6 +634,10 @@ static int rt2800usb_probe_hw(struct rt2x00_dev *rt2x00dev) __set_bit(REQUIRE_HT_TX_DESC, &rt2x00dev->cap_flags); __set_bit(REQUIRE_TXSTATUS_FIFO, &rt2x00dev->cap_flags); + setup_timer(&rt2x00dev->txstatus_timer, + rt2800usb_tx_sta_fifo_timeout, + (unsigned long) rt2x00dev); + /* * Set the rssi offset. */ diff --git a/drivers/net/wireless/rt2x00/rt2x00.h b/drivers/net/wireless/rt2x00/rt2x00.h index e3b9b51..8f37121 100644 --- a/drivers/net/wireless/rt2x00/rt2x00.h +++ b/drivers/net/wireless/rt2x00/rt2x00.h @@ -37,6 +37,7 @@ #include #include #include +#include #include @@ -924,6 +925,11 @@ struct rt2x00_dev { DECLARE_KFIFO_PTR(txstatus_fifo, u32); /* + * Timer to ensure tx status reports are read (rt2800usb). + */ + struct timer_list txstatus_timer; + + /* * Tasklet for processing tx status reports (rt2800pci). */ struct tasklet_struct txstatus_tasklet; diff --git a/drivers/net/wireless/rt2x00/rt2x00dev.c b/drivers/net/wireless/rt2x00/rt2x00dev.c index 2e490e0..7776d9f 100644 --- a/drivers/net/wireless/rt2x00/rt2x00dev.c +++ b/drivers/net/wireless/rt2x00/rt2x00dev.c @@ -1071,6 +1071,7 @@ void rt2x00lib_remove_dev(struct rt2x00_dev *rt2x00dev) /* * Stop all work. */ + del_timer_sync(&rt2x00dev->txstatus_timer); cancel_work_sync(&rt2x00dev->intf_work); if (rt2x00_is_usb(rt2x00dev)) { cancel_work_sync(&rt2x00dev->rxdone_work); diff --git a/drivers/net/wireless/rt2x00/rt2x00usb.c b/drivers/net/wireless/rt2x00/rt2x00usb.c index 14736e2..34b8a88 100644 --- a/drivers/net/wireless/rt2x00/rt2x00usb.c +++ b/drivers/net/wireless/rt2x00/rt2x00usb.c @@ -280,7 +280,9 @@ static void rt2x00usb_interrupt_txdone(struct urb *urb) * Schedule the delayed work for reading the TX status * from the device. */ - queue_work(rt2x00dev->workqueue, &rt2x00dev->txdone_work); + if (!test_bit(REQUIRE_TXSTATUS_FIFO, &rt2x00dev->cap_flags) || + !kfifo_is_empty(&rt2x00dev->txstatus_fifo)) + queue_work(rt2x00dev->workqueue, &rt2x00dev->txdone_work); } static bool rt2x00usb_kick_tx_entry(struct queue_entry *entry, void* data) @@ -816,6 +818,7 @@ int rt2x00usb_probe(struct usb_interface *usb_intf, INIT_WORK(&rt2x00dev->rxdone_work, rt2x00usb_work_rxdone); INIT_WORK(&rt2x00dev->txdone_work, rt2x00usb_work_txdone); + init_timer(&rt2x00dev->txstatus_timer); retval = rt2x00usb_alloc_reg(rt2x00dev); if (retval) -- cgit v0.10.2 From 152a599274b15028604e24ae2d9c9d7f49853977 Mon Sep 17 00:00:00 2001 From: Ivo van Doorn Date: Mon, 18 Apr 2011 15:31:02 +0200 Subject: rt2x00: Decrease association time for USB devices When powersaving is enabled, assocaition times are very high (for WPA2 networks, the time can easily be around the 3 seconds). This is caused, because the flushing of the queues takes too much time. Without the flushing callback mac80211 assumes a timeout of 100ms while scanning. Limit all flush waiting loops to the same maximum. We can apply this maximum by passing the drop status to the driver, which makes sure the driver performs extra actions during the waiting for the queue to become empty. After these changes, association times fall within the healthy range of ~0.6 seconds with powersaving enabled. The difference between association time between powersaving enabled and disabled is now only ~0.1 second (which can also be due to the measuring method). Signed-off-by: Ivo van Doorn Acked-by: Gertjan van Wingerde Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/rt2x00/rt2400pci.c b/drivers/net/wireless/rt2x00/rt2400pci.c index 5d1654a..6b7206e 100644 --- a/drivers/net/wireless/rt2x00/rt2400pci.c +++ b/drivers/net/wireless/rt2x00/rt2400pci.c @@ -1740,6 +1740,7 @@ static const struct rt2x00lib_ops rt2400pci_rt2x00_ops = { .start_queue = rt2400pci_start_queue, .kick_queue = rt2400pci_kick_queue, .stop_queue = rt2400pci_stop_queue, + .flush_queue = rt2x00pci_flush_queue, .write_tx_desc = rt2400pci_write_tx_desc, .write_beacon = rt2400pci_write_beacon, .fill_rxdone = rt2400pci_fill_rxdone, diff --git a/drivers/net/wireless/rt2x00/rt2500pci.c b/drivers/net/wireless/rt2x00/rt2500pci.c index 3da954e..82e8012 100644 --- a/drivers/net/wireless/rt2x00/rt2500pci.c +++ b/drivers/net/wireless/rt2x00/rt2500pci.c @@ -2033,6 +2033,7 @@ static const struct rt2x00lib_ops rt2500pci_rt2x00_ops = { .start_queue = rt2500pci_start_queue, .kick_queue = rt2500pci_kick_queue, .stop_queue = rt2500pci_stop_queue, + .flush_queue = rt2x00pci_flush_queue, .write_tx_desc = rt2500pci_write_tx_desc, .write_beacon = rt2500pci_write_beacon, .fill_rxdone = rt2500pci_fill_rxdone, diff --git a/drivers/net/wireless/rt2x00/rt2800pci.c b/drivers/net/wireless/rt2x00/rt2800pci.c index 4241f19..d2fe5fd 100644 --- a/drivers/net/wireless/rt2x00/rt2800pci.c +++ b/drivers/net/wireless/rt2x00/rt2800pci.c @@ -1057,6 +1057,7 @@ static const struct rt2x00lib_ops rt2800pci_rt2x00_ops = { .start_queue = rt2800pci_start_queue, .kick_queue = rt2800pci_kick_queue, .stop_queue = rt2800pci_stop_queue, + .flush_queue = rt2x00pci_flush_queue, .write_tx_desc = rt2800pci_write_tx_desc, .write_tx_data = rt2800_write_tx_data, .write_beacon = rt2800_write_beacon, diff --git a/drivers/net/wireless/rt2x00/rt2x00.h b/drivers/net/wireless/rt2x00/rt2x00.h index 8f37121..dcdc50d 100644 --- a/drivers/net/wireless/rt2x00/rt2x00.h +++ b/drivers/net/wireless/rt2x00/rt2x00.h @@ -571,7 +571,7 @@ struct rt2x00lib_ops { void (*start_queue) (struct data_queue *queue); void (*kick_queue) (struct data_queue *queue); void (*stop_queue) (struct data_queue *queue); - void (*flush_queue) (struct data_queue *queue); + void (*flush_queue) (struct data_queue *queue, bool drop); void (*tx_dma_done) (struct queue_entry *entry); /* diff --git a/drivers/net/wireless/rt2x00/rt2x00pci.c b/drivers/net/wireless/rt2x00/rt2x00pci.c index 9649bd0..695aecf 100644 --- a/drivers/net/wireless/rt2x00/rt2x00pci.c +++ b/drivers/net/wireless/rt2x00/rt2x00pci.c @@ -99,6 +99,15 @@ bool rt2x00pci_rxdone(struct rt2x00_dev *rt2x00dev) } EXPORT_SYMBOL_GPL(rt2x00pci_rxdone); +void rt2x00pci_flush_queue(struct data_queue *queue, bool drop) +{ + unsigned int i; + + for (i = 0; !rt2x00queue_empty(queue) && i < 10; i++) + msleep(10); +} +EXPORT_SYMBOL_GPL(rt2x00pci_flush_queue); + /* * Device initialization handlers. */ diff --git a/drivers/net/wireless/rt2x00/rt2x00pci.h b/drivers/net/wireless/rt2x00/rt2x00pci.h index 07961b8..5d58874 100644 --- a/drivers/net/wireless/rt2x00/rt2x00pci.h +++ b/drivers/net/wireless/rt2x00/rt2x00pci.h @@ -107,6 +107,16 @@ struct queue_entry_priv_pci { */ bool rt2x00pci_rxdone(struct rt2x00_dev *rt2x00dev); +/** + * rt2x00pci_flush_queue - Flush data queue + * @queue: Data queue to stop + * @drop: True to drop all pending frames. + * + * This will wait for a maximum of 100ms, waiting for the queues + * to become empty. + */ +void rt2x00pci_flush_queue(struct data_queue *queue, bool drop); + /* * Device initialization handlers. */ diff --git a/drivers/net/wireless/rt2x00/rt2x00queue.c b/drivers/net/wireless/rt2x00/rt2x00queue.c index df8817f..0d79278 100644 --- a/drivers/net/wireless/rt2x00/rt2x00queue.c +++ b/drivers/net/wireless/rt2x00/rt2x00queue.c @@ -849,7 +849,6 @@ EXPORT_SYMBOL_GPL(rt2x00queue_stop_queue); void rt2x00queue_flush_queue(struct data_queue *queue, bool drop) { - unsigned int i; bool started; bool tx_queue = (queue->qid == QID_AC_VO) || @@ -884,20 +883,12 @@ void rt2x00queue_flush_queue(struct data_queue *queue, bool drop) } /* - * Check if driver supports flushing, we can only guarentee - * full support for flushing if the driver is able - * to cancel all pending frames (drop = true). - */ - if (drop && queue->rt2x00dev->ops->lib->flush_queue) - queue->rt2x00dev->ops->lib->flush_queue(queue); - - /* - * When we don't want to drop any frames, or when - * the driver doesn't fully flush the queue correcly, - * we must wait for the queue to become empty. + * Check if driver supports flushing, if that is the case we can + * defer the flushing to the driver. Otherwise we must use the + * alternative which just waits for the queue to become empty. */ - for (i = 0; !rt2x00queue_empty(queue) && i < 100; i++) - msleep(10); + if (likely(queue->rt2x00dev->ops->lib->flush_queue)) + queue->rt2x00dev->ops->lib->flush_queue(queue, drop); /* * The queue flush has failed... diff --git a/drivers/net/wireless/rt2x00/rt2x00usb.c b/drivers/net/wireless/rt2x00/rt2x00usb.c index 34b8a88..9957579 100644 --- a/drivers/net/wireless/rt2x00/rt2x00usb.c +++ b/drivers/net/wireless/rt2x00/rt2x00usb.c @@ -458,13 +458,14 @@ static bool rt2x00usb_flush_entry(struct queue_entry *entry, void* data) return false; } -void rt2x00usb_flush_queue(struct data_queue *queue) +void rt2x00usb_flush_queue(struct data_queue *queue, bool drop) { struct work_struct *completion; unsigned int i; - rt2x00queue_for_each_entry(queue, Q_INDEX_DONE, Q_INDEX, NULL, - rt2x00usb_flush_entry); + if (drop) + rt2x00queue_for_each_entry(queue, Q_INDEX_DONE, Q_INDEX, NULL, + rt2x00usb_flush_entry); /* * Obtain the queue completion handler @@ -483,7 +484,7 @@ void rt2x00usb_flush_queue(struct data_queue *queue) return; } - for (i = 0; i < 20; i++) { + for (i = 0; i < 10; i++) { /* * Check if the driver is already done, otherwise we * have to sleep a little while to give the driver/hw diff --git a/drivers/net/wireless/rt2x00/rt2x00usb.h b/drivers/net/wireless/rt2x00/rt2x00usb.h index e3faca6..6aeba71 100644 --- a/drivers/net/wireless/rt2x00/rt2x00usb.h +++ b/drivers/net/wireless/rt2x00/rt2x00usb.h @@ -404,11 +404,13 @@ void rt2x00usb_kick_queue(struct data_queue *queue); /** * rt2x00usb_flush_queue - Flush data queue * @queue: Data queue to stop + * @drop: True to drop all pending frames. * - * This will walk through all entries of the queue and kill all - * URB's which were send to the device. + * This will walk through all entries of the queue and will optionally + * kill all URB's which were send to the device, or at least wait until + * they have been returned from the device.. */ -void rt2x00usb_flush_queue(struct data_queue *queue); +void rt2x00usb_flush_queue(struct data_queue *queue, bool drop); /** * rt2x00usb_watchdog - Watchdog for USB communication diff --git a/drivers/net/wireless/rt2x00/rt61pci.c b/drivers/net/wireless/rt2x00/rt61pci.c index c16c150..35c5d20 100644 --- a/drivers/net/wireless/rt2x00/rt61pci.c +++ b/drivers/net/wireless/rt2x00/rt61pci.c @@ -3003,6 +3003,7 @@ static const struct rt2x00lib_ops rt61pci_rt2x00_ops = { .start_queue = rt61pci_start_queue, .kick_queue = rt61pci_kick_queue, .stop_queue = rt61pci_stop_queue, + .flush_queue = rt2x00pci_flush_queue, .write_tx_desc = rt61pci_write_tx_desc, .write_beacon = rt61pci_write_beacon, .clear_beacon = rt61pci_clear_beacon, -- cgit v0.10.2 From 7a5a681a7df7d844b52f82a4388e078071eb883e Mon Sep 17 00:00:00 2001 From: Helmut Schaa Date: Mon, 18 Apr 2011 15:31:31 +0200 Subject: rt2x00: Always inline rt2x00pci_enable_interrupt This allows the compiler to perform the necessary bitfield calculations during compile time instead of run time and thus reduces the number of instructions to run during each tasklet invocation. This should improve performance in the RX hotpath. This comes at the cost of a slight increase in the module size (for example rt2800pci): Before: text data bss dec hex filename 14133 832 4 14969 3a79 drivers/net/wireless/rt2x00/rt2800pci.ko After: text data bss dec hex filename 14149 832 4 14985 3a89 drivers/net/wireless/rt2x00/rt2800pci.ko Signed-off-by: Helmut Schaa Acked-by: Gertjan van Wingerde Signed-off-by: Ivo van Doorn Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/rt2x00/rt2400pci.c b/drivers/net/wireless/rt2x00/rt2400pci.c index 6b7206e..01e9517 100644 --- a/drivers/net/wireless/rt2x00/rt2400pci.c +++ b/drivers/net/wireless/rt2x00/rt2400pci.c @@ -1314,8 +1314,8 @@ static void rt2400pci_txdone(struct rt2x00_dev *rt2x00dev, } } -static void rt2400pci_enable_interrupt(struct rt2x00_dev *rt2x00dev, - struct rt2x00_field32 irq_field) +static inline void rt2400pci_enable_interrupt(struct rt2x00_dev *rt2x00dev, + struct rt2x00_field32 irq_field) { u32 reg; diff --git a/drivers/net/wireless/rt2x00/rt2500pci.c b/drivers/net/wireless/rt2x00/rt2500pci.c index 82e8012..c8deeeb 100644 --- a/drivers/net/wireless/rt2x00/rt2500pci.c +++ b/drivers/net/wireless/rt2x00/rt2500pci.c @@ -1446,8 +1446,8 @@ static void rt2500pci_txdone(struct rt2x00_dev *rt2x00dev, } } -static void rt2500pci_enable_interrupt(struct rt2x00_dev *rt2x00dev, - struct rt2x00_field32 irq_field) +static inline void rt2500pci_enable_interrupt(struct rt2x00_dev *rt2x00dev, + struct rt2x00_field32 irq_field) { u32 reg; diff --git a/drivers/net/wireless/rt2x00/rt2800pci.c b/drivers/net/wireless/rt2x00/rt2800pci.c index d2fe5fd..46c3e3c83 100644 --- a/drivers/net/wireless/rt2x00/rt2800pci.c +++ b/drivers/net/wireless/rt2x00/rt2800pci.c @@ -768,8 +768,8 @@ static bool rt2800pci_txdone(struct rt2x00_dev *rt2x00dev) return !max_tx_done; } -static void rt2800pci_enable_interrupt(struct rt2x00_dev *rt2x00dev, - struct rt2x00_field32 irq_field) +static inline void rt2800pci_enable_interrupt(struct rt2x00_dev *rt2x00dev, + struct rt2x00_field32 irq_field) { u32 reg; diff --git a/drivers/net/wireless/rt2x00/rt61pci.c b/drivers/net/wireless/rt2x00/rt61pci.c index 35c5d20..264508f 100644 --- a/drivers/net/wireless/rt2x00/rt61pci.c +++ b/drivers/net/wireless/rt2x00/rt61pci.c @@ -2260,8 +2260,8 @@ static void rt61pci_wakeup(struct rt2x00_dev *rt2x00dev) rt61pci_config(rt2x00dev, &libconf, IEEE80211_CONF_CHANGE_PS); } -static void rt61pci_enable_interrupt(struct rt2x00_dev *rt2x00dev, - struct rt2x00_field32 irq_field) +static inline void rt61pci_enable_interrupt(struct rt2x00_dev *rt2x00dev, + struct rt2x00_field32 irq_field) { u32 reg; -- cgit v0.10.2 From ce2919c9fffe2aa52f9c3e327176d03764dbf9b5 Mon Sep 17 00:00:00 2001 From: Gertjan van Wingerde Date: Mon, 18 Apr 2011 15:31:50 +0200 Subject: rt2x00: Linksys WUSB600N rev2 is a RT3572 device. Move the USB ID entry from the unknown devices to the list of RT35xx based devices. Signed-off-by: Gertjan van Wingerde Signed-off-by: Ivo van Doorn Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/rt2x00/rt2800usb.c b/drivers/net/wireless/rt2x00/rt2800usb.c index 2005972..1bb9a7d 100644 --- a/drivers/net/wireless/rt2x00/rt2800usb.c +++ b/drivers/net/wireless/rt2x00/rt2800usb.c @@ -983,6 +983,7 @@ static struct usb_device_id rt2800usb_device_table[] = { { USB_DEVICE(0x04bb, 0x0944), USB_DEVICE_DATA(&rt2800usb_ops) }, /* Linksys */ { USB_DEVICE(0x13b1, 0x002f), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x1737, 0x0079), USB_DEVICE_DATA(&rt2800usb_ops) }, /* Ralink */ { USB_DEVICE(0x148f, 0x3572), USB_DEVICE_DATA(&rt2800usb_ops) }, /* Sitecom */ @@ -1041,7 +1042,6 @@ static struct usb_device_id rt2800usb_device_table[] = { /* Linksys */ { USB_DEVICE(0x1737, 0x0077), USB_DEVICE_DATA(&rt2800usb_ops) }, { USB_DEVICE(0x1737, 0x0078), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x1737, 0x0079), USB_DEVICE_DATA(&rt2800usb_ops) }, /* Motorola */ { USB_DEVICE(0x100d, 0x9032), USB_DEVICE_DATA(&rt2800usb_ops) }, /* Ovislink */ -- cgit v0.10.2 From e01ae27f8ce6bd3ee26ef33c704f62449ce8233b Mon Sep 17 00:00:00 2001 From: Gertjan van Wingerde Date: Mon, 18 Apr 2011 15:32:13 +0200 Subject: rt2x00: Allow dynamic addition of PCI/USB IDs. Both USB and PCI drivers allow a system administrator to dynamically add USB/PCI IDs to the device table that a driver supports via the /sys/bus/{usb,pci,pci_express}/drivers//new_id files. However, for the rt2x00 drivers using this method currently crashes the system with a NULL pointer failure. This is due to the set-up of rt2x00 where the probe functions require a rt2x00_ops structure in the driver_info field of the probed device. As this field is empty for the dynamically added devices this fails for these devices. Fix this by introducing driver-specific probe wrappers that do nothing but calling the bus-specific probe functions with the rt2x00_ops structure as an argument, rather than depending on the driver_info field. Signed-off-by: Gertjan van Wingerde Signed-off-by: Ivo van Doorn Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/rt2x00/rt2400pci.c b/drivers/net/wireless/rt2x00/rt2400pci.c index 01e9517..d4acdde 100644 --- a/drivers/net/wireless/rt2x00/rt2400pci.c +++ b/drivers/net/wireless/rt2x00/rt2400pci.c @@ -1802,10 +1802,11 @@ static const struct rt2x00_ops rt2400pci_ops = { * RT2400pci module information. */ static DEFINE_PCI_DEVICE_TABLE(rt2400pci_device_table) = { - { PCI_DEVICE(0x1814, 0x0101), PCI_DEVICE_DATA(&rt2400pci_ops) }, + { PCI_DEVICE(0x1814, 0x0101) }, { 0, } }; + MODULE_AUTHOR(DRV_PROJECT); MODULE_VERSION(DRV_VERSION); MODULE_DESCRIPTION("Ralink RT2400 PCI & PCMCIA Wireless LAN driver."); @@ -1813,10 +1814,16 @@ MODULE_SUPPORTED_DEVICE("Ralink RT2460 PCI & PCMCIA chipset based cards"); MODULE_DEVICE_TABLE(pci, rt2400pci_device_table); MODULE_LICENSE("GPL"); +static int rt2400pci_probe(struct pci_dev *pci_dev, + const struct pci_device_id *id) +{ + return rt2x00pci_probe(pci_dev, &rt2400pci_ops); +} + static struct pci_driver rt2400pci_driver = { .name = KBUILD_MODNAME, .id_table = rt2400pci_device_table, - .probe = rt2x00pci_probe, + .probe = rt2400pci_probe, .remove = __devexit_p(rt2x00pci_remove), .suspend = rt2x00pci_suspend, .resume = rt2x00pci_resume, diff --git a/drivers/net/wireless/rt2x00/rt2500pci.c b/drivers/net/wireless/rt2x00/rt2500pci.c index c8deeeb..15f5649 100644 --- a/drivers/net/wireless/rt2x00/rt2500pci.c +++ b/drivers/net/wireless/rt2x00/rt2500pci.c @@ -2095,7 +2095,7 @@ static const struct rt2x00_ops rt2500pci_ops = { * RT2500pci module information. */ static DEFINE_PCI_DEVICE_TABLE(rt2500pci_device_table) = { - { PCI_DEVICE(0x1814, 0x0201), PCI_DEVICE_DATA(&rt2500pci_ops) }, + { PCI_DEVICE(0x1814, 0x0201) }, { 0, } }; @@ -2106,10 +2106,16 @@ MODULE_SUPPORTED_DEVICE("Ralink RT2560 PCI & PCMCIA chipset based cards"); MODULE_DEVICE_TABLE(pci, rt2500pci_device_table); MODULE_LICENSE("GPL"); +static int rt2500pci_probe(struct pci_dev *pci_dev, + const struct pci_device_id *id) +{ + return rt2x00pci_probe(pci_dev, &rt2500pci_ops); +} + static struct pci_driver rt2500pci_driver = { .name = KBUILD_MODNAME, .id_table = rt2500pci_device_table, - .probe = rt2x00pci_probe, + .probe = rt2500pci_probe, .remove = __devexit_p(rt2x00pci_remove), .suspend = rt2x00pci_suspend, .resume = rt2x00pci_resume, diff --git a/drivers/net/wireless/rt2x00/rt2500usb.c b/drivers/net/wireless/rt2x00/rt2500usb.c index dbbd8bc..d88c367 100644 --- a/drivers/net/wireless/rt2x00/rt2500usb.c +++ b/drivers/net/wireless/rt2x00/rt2500usb.c @@ -1904,54 +1904,54 @@ static const struct rt2x00_ops rt2500usb_ops = { */ static struct usb_device_id rt2500usb_device_table[] = { /* ASUS */ - { USB_DEVICE(0x0b05, 0x1706), USB_DEVICE_DATA(&rt2500usb_ops) }, - { USB_DEVICE(0x0b05, 0x1707), USB_DEVICE_DATA(&rt2500usb_ops) }, + { USB_DEVICE(0x0b05, 0x1706) }, + { USB_DEVICE(0x0b05, 0x1707) }, /* Belkin */ - { USB_DEVICE(0x050d, 0x7050), USB_DEVICE_DATA(&rt2500usb_ops) }, - { USB_DEVICE(0x050d, 0x7051), USB_DEVICE_DATA(&rt2500usb_ops) }, + { USB_DEVICE(0x050d, 0x7050) }, + { USB_DEVICE(0x050d, 0x7051) }, /* Cisco Systems */ - { USB_DEVICE(0x13b1, 0x000d), USB_DEVICE_DATA(&rt2500usb_ops) }, - { USB_DEVICE(0x13b1, 0x0011), USB_DEVICE_DATA(&rt2500usb_ops) }, - { USB_DEVICE(0x13b1, 0x001a), USB_DEVICE_DATA(&rt2500usb_ops) }, + { USB_DEVICE(0x13b1, 0x000d) }, + { USB_DEVICE(0x13b1, 0x0011) }, + { USB_DEVICE(0x13b1, 0x001a) }, /* Conceptronic */ - { USB_DEVICE(0x14b2, 0x3c02), USB_DEVICE_DATA(&rt2500usb_ops) }, + { USB_DEVICE(0x14b2, 0x3c02) }, /* D-LINK */ - { USB_DEVICE(0x2001, 0x3c00), USB_DEVICE_DATA(&rt2500usb_ops) }, + { USB_DEVICE(0x2001, 0x3c00) }, /* Gigabyte */ - { USB_DEVICE(0x1044, 0x8001), USB_DEVICE_DATA(&rt2500usb_ops) }, - { USB_DEVICE(0x1044, 0x8007), USB_DEVICE_DATA(&rt2500usb_ops) }, + { USB_DEVICE(0x1044, 0x8001) }, + { USB_DEVICE(0x1044, 0x8007) }, /* Hercules */ - { USB_DEVICE(0x06f8, 0xe000), USB_DEVICE_DATA(&rt2500usb_ops) }, + { USB_DEVICE(0x06f8, 0xe000) }, /* Melco */ - { USB_DEVICE(0x0411, 0x005e), USB_DEVICE_DATA(&rt2500usb_ops) }, - { USB_DEVICE(0x0411, 0x0066), USB_DEVICE_DATA(&rt2500usb_ops) }, - { USB_DEVICE(0x0411, 0x0067), USB_DEVICE_DATA(&rt2500usb_ops) }, - { USB_DEVICE(0x0411, 0x008b), USB_DEVICE_DATA(&rt2500usb_ops) }, - { USB_DEVICE(0x0411, 0x0097), USB_DEVICE_DATA(&rt2500usb_ops) }, + { USB_DEVICE(0x0411, 0x005e) }, + { USB_DEVICE(0x0411, 0x0066) }, + { USB_DEVICE(0x0411, 0x0067) }, + { USB_DEVICE(0x0411, 0x008b) }, + { USB_DEVICE(0x0411, 0x0097) }, /* MSI */ - { USB_DEVICE(0x0db0, 0x6861), USB_DEVICE_DATA(&rt2500usb_ops) }, - { USB_DEVICE(0x0db0, 0x6865), USB_DEVICE_DATA(&rt2500usb_ops) }, - { USB_DEVICE(0x0db0, 0x6869), USB_DEVICE_DATA(&rt2500usb_ops) }, + { USB_DEVICE(0x0db0, 0x6861) }, + { USB_DEVICE(0x0db0, 0x6865) }, + { USB_DEVICE(0x0db0, 0x6869) }, /* Ralink */ - { USB_DEVICE(0x148f, 0x1706), USB_DEVICE_DATA(&rt2500usb_ops) }, - { USB_DEVICE(0x148f, 0x2570), USB_DEVICE_DATA(&rt2500usb_ops) }, - { USB_DEVICE(0x148f, 0x9020), USB_DEVICE_DATA(&rt2500usb_ops) }, + { USB_DEVICE(0x148f, 0x1706) }, + { USB_DEVICE(0x148f, 0x2570) }, + { USB_DEVICE(0x148f, 0x9020) }, /* Sagem */ - { USB_DEVICE(0x079b, 0x004b), USB_DEVICE_DATA(&rt2500usb_ops) }, + { USB_DEVICE(0x079b, 0x004b) }, /* Siemens */ - { USB_DEVICE(0x0681, 0x3c06), USB_DEVICE_DATA(&rt2500usb_ops) }, + { USB_DEVICE(0x0681, 0x3c06) }, /* SMC */ - { USB_DEVICE(0x0707, 0xee13), USB_DEVICE_DATA(&rt2500usb_ops) }, + { USB_DEVICE(0x0707, 0xee13) }, /* Spairon */ - { USB_DEVICE(0x114b, 0x0110), USB_DEVICE_DATA(&rt2500usb_ops) }, + { USB_DEVICE(0x114b, 0x0110) }, /* SURECOM */ - { USB_DEVICE(0x0769, 0x11f3), USB_DEVICE_DATA(&rt2500usb_ops) }, + { USB_DEVICE(0x0769, 0x11f3) }, /* Trust */ - { USB_DEVICE(0x0eb0, 0x9020), USB_DEVICE_DATA(&rt2500usb_ops) }, + { USB_DEVICE(0x0eb0, 0x9020) }, /* VTech */ - { USB_DEVICE(0x0f88, 0x3012), USB_DEVICE_DATA(&rt2500usb_ops) }, + { USB_DEVICE(0x0f88, 0x3012) }, /* Zinwell */ - { USB_DEVICE(0x5a57, 0x0260), USB_DEVICE_DATA(&rt2500usb_ops) }, + { USB_DEVICE(0x5a57, 0x0260) }, { 0, } }; @@ -1962,10 +1962,16 @@ MODULE_SUPPORTED_DEVICE("Ralink RT2570 USB chipset based cards"); MODULE_DEVICE_TABLE(usb, rt2500usb_device_table); MODULE_LICENSE("GPL"); +static int rt2500usb_probe(struct usb_interface *usb_intf, + const struct usb_device_id *id) +{ + return rt2x00usb_probe(usb_intf, &rt2500usb_ops); +} + static struct usb_driver rt2500usb_driver = { .name = KBUILD_MODNAME, .id_table = rt2500usb_device_table, - .probe = rt2x00usb_probe, + .probe = rt2500usb_probe, .disconnect = rt2x00usb_disconnect, .suspend = rt2x00usb_suspend, .resume = rt2x00usb_resume, diff --git a/drivers/net/wireless/rt2x00/rt2800pci.c b/drivers/net/wireless/rt2x00/rt2800pci.c index 46c3e3c83..6f91a9a 100644 --- a/drivers/net/wireless/rt2x00/rt2800pci.c +++ b/drivers/net/wireless/rt2x00/rt2800pci.c @@ -1117,36 +1117,36 @@ static const struct rt2x00_ops rt2800pci_ops = { */ #ifdef CONFIG_PCI static DEFINE_PCI_DEVICE_TABLE(rt2800pci_device_table) = { - { PCI_DEVICE(0x1814, 0x0601), PCI_DEVICE_DATA(&rt2800pci_ops) }, - { PCI_DEVICE(0x1814, 0x0681), PCI_DEVICE_DATA(&rt2800pci_ops) }, - { PCI_DEVICE(0x1814, 0x0701), PCI_DEVICE_DATA(&rt2800pci_ops) }, - { PCI_DEVICE(0x1814, 0x0781), PCI_DEVICE_DATA(&rt2800pci_ops) }, - { PCI_DEVICE(0x1814, 0x3090), PCI_DEVICE_DATA(&rt2800pci_ops) }, - { PCI_DEVICE(0x1814, 0x3091), PCI_DEVICE_DATA(&rt2800pci_ops) }, - { PCI_DEVICE(0x1814, 0x3092), PCI_DEVICE_DATA(&rt2800pci_ops) }, - { PCI_DEVICE(0x1432, 0x7708), PCI_DEVICE_DATA(&rt2800pci_ops) }, - { PCI_DEVICE(0x1432, 0x7727), PCI_DEVICE_DATA(&rt2800pci_ops) }, - { PCI_DEVICE(0x1432, 0x7728), PCI_DEVICE_DATA(&rt2800pci_ops) }, - { PCI_DEVICE(0x1432, 0x7738), PCI_DEVICE_DATA(&rt2800pci_ops) }, - { PCI_DEVICE(0x1432, 0x7748), PCI_DEVICE_DATA(&rt2800pci_ops) }, - { PCI_DEVICE(0x1432, 0x7758), PCI_DEVICE_DATA(&rt2800pci_ops) }, - { PCI_DEVICE(0x1432, 0x7768), PCI_DEVICE_DATA(&rt2800pci_ops) }, - { PCI_DEVICE(0x1462, 0x891a), PCI_DEVICE_DATA(&rt2800pci_ops) }, - { PCI_DEVICE(0x1a3b, 0x1059), PCI_DEVICE_DATA(&rt2800pci_ops) }, + { PCI_DEVICE(0x1814, 0x0601) }, + { PCI_DEVICE(0x1814, 0x0681) }, + { PCI_DEVICE(0x1814, 0x0701) }, + { PCI_DEVICE(0x1814, 0x0781) }, + { PCI_DEVICE(0x1814, 0x3090) }, + { PCI_DEVICE(0x1814, 0x3091) }, + { PCI_DEVICE(0x1814, 0x3092) }, + { PCI_DEVICE(0x1432, 0x7708) }, + { PCI_DEVICE(0x1432, 0x7727) }, + { PCI_DEVICE(0x1432, 0x7728) }, + { PCI_DEVICE(0x1432, 0x7738) }, + { PCI_DEVICE(0x1432, 0x7748) }, + { PCI_DEVICE(0x1432, 0x7758) }, + { PCI_DEVICE(0x1432, 0x7768) }, + { PCI_DEVICE(0x1462, 0x891a) }, + { PCI_DEVICE(0x1a3b, 0x1059) }, #ifdef CONFIG_RT2800PCI_RT33XX - { PCI_DEVICE(0x1814, 0x3390), PCI_DEVICE_DATA(&rt2800pci_ops) }, + { PCI_DEVICE(0x1814, 0x3390) }, #endif #ifdef CONFIG_RT2800PCI_RT35XX - { PCI_DEVICE(0x1432, 0x7711), PCI_DEVICE_DATA(&rt2800pci_ops) }, - { PCI_DEVICE(0x1432, 0x7722), PCI_DEVICE_DATA(&rt2800pci_ops) }, - { PCI_DEVICE(0x1814, 0x3060), PCI_DEVICE_DATA(&rt2800pci_ops) }, - { PCI_DEVICE(0x1814, 0x3062), PCI_DEVICE_DATA(&rt2800pci_ops) }, - { PCI_DEVICE(0x1814, 0x3562), PCI_DEVICE_DATA(&rt2800pci_ops) }, - { PCI_DEVICE(0x1814, 0x3592), PCI_DEVICE_DATA(&rt2800pci_ops) }, - { PCI_DEVICE(0x1814, 0x3593), PCI_DEVICE_DATA(&rt2800pci_ops) }, + { PCI_DEVICE(0x1432, 0x7711) }, + { PCI_DEVICE(0x1432, 0x7722) }, + { PCI_DEVICE(0x1814, 0x3060) }, + { PCI_DEVICE(0x1814, 0x3062) }, + { PCI_DEVICE(0x1814, 0x3562) }, + { PCI_DEVICE(0x1814, 0x3592) }, + { PCI_DEVICE(0x1814, 0x3593) }, #endif #ifdef CONFIG_RT2800PCI_RT53XX - { PCI_DEVICE(0x1814, 0x5390), PCI_DEVICE_DATA(&rt2800pci_ops) }, + { PCI_DEVICE(0x1814, 0x5390) }, #endif { 0, } }; @@ -1182,10 +1182,16 @@ static struct platform_driver rt2800soc_driver = { #endif /* CONFIG_RALINK_RT288X || CONFIG_RALINK_RT305X */ #ifdef CONFIG_PCI +static int rt2800pci_probe(struct pci_dev *pci_dev, + const struct pci_device_id *id) +{ + return rt2x00pci_probe(pci_dev, &rt2800pci_ops); +} + static struct pci_driver rt2800pci_driver = { .name = KBUILD_MODNAME, .id_table = rt2800pci_device_table, - .probe = rt2x00pci_probe, + .probe = rt2800pci_probe, .remove = __devexit_p(rt2x00pci_remove), .suspend = rt2x00pci_suspend, .resume = rt2x00pci_resume, diff --git a/drivers/net/wireless/rt2x00/rt2800usb.c b/drivers/net/wireless/rt2x00/rt2800usb.c index 1bb9a7d..6f7c161 100644 --- a/drivers/net/wireless/rt2x00/rt2800usb.c +++ b/drivers/net/wireless/rt2x00/rt2800usb.c @@ -768,230 +768,230 @@ static const struct rt2x00_ops rt2800usb_ops = { */ static struct usb_device_id rt2800usb_device_table[] = { /* Abocom */ - { USB_DEVICE(0x07b8, 0x2870), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x07b8, 0x2770), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x07b8, 0x3070), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x07b8, 0x3071), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x07b8, 0x3072), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x1482, 0x3c09), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x07b8, 0x2870) }, + { USB_DEVICE(0x07b8, 0x2770) }, + { USB_DEVICE(0x07b8, 0x3070) }, + { USB_DEVICE(0x07b8, 0x3071) }, + { USB_DEVICE(0x07b8, 0x3072) }, + { USB_DEVICE(0x1482, 0x3c09) }, /* AirTies */ - { USB_DEVICE(0x1eda, 0x2310), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x1eda, 0x2310) }, /* Allwin */ - { USB_DEVICE(0x8516, 0x2070), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x8516, 0x2770), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x8516, 0x2870), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x8516, 0x3070), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x8516, 0x3071), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x8516, 0x3072), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x8516, 0x2070) }, + { USB_DEVICE(0x8516, 0x2770) }, + { USB_DEVICE(0x8516, 0x2870) }, + { USB_DEVICE(0x8516, 0x3070) }, + { USB_DEVICE(0x8516, 0x3071) }, + { USB_DEVICE(0x8516, 0x3072) }, /* Alpha Networks */ - { USB_DEVICE(0x14b2, 0x3c06), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x14b2, 0x3c07), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x14b2, 0x3c09), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x14b2, 0x3c12), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x14b2, 0x3c23), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x14b2, 0x3c25), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x14b2, 0x3c27), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x14b2, 0x3c28), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x14b2, 0x3c2c), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x14b2, 0x3c06) }, + { USB_DEVICE(0x14b2, 0x3c07) }, + { USB_DEVICE(0x14b2, 0x3c09) }, + { USB_DEVICE(0x14b2, 0x3c12) }, + { USB_DEVICE(0x14b2, 0x3c23) }, + { USB_DEVICE(0x14b2, 0x3c25) }, + { USB_DEVICE(0x14b2, 0x3c27) }, + { USB_DEVICE(0x14b2, 0x3c28) }, + { USB_DEVICE(0x14b2, 0x3c2c) }, /* Amit */ - { USB_DEVICE(0x15c5, 0x0008), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x15c5, 0x0008) }, /* Askey */ - { USB_DEVICE(0x1690, 0x0740), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x1690, 0x0740) }, /* ASUS */ - { USB_DEVICE(0x0b05, 0x1731), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x0b05, 0x1732), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x0b05, 0x1742), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x0b05, 0x1784), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x1761, 0x0b05), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x0b05, 0x1731) }, + { USB_DEVICE(0x0b05, 0x1732) }, + { USB_DEVICE(0x0b05, 0x1742) }, + { USB_DEVICE(0x0b05, 0x1784) }, + { USB_DEVICE(0x1761, 0x0b05) }, /* AzureWave */ - { USB_DEVICE(0x13d3, 0x3247), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x13d3, 0x3273), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x13d3, 0x3305), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x13d3, 0x3307), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x13d3, 0x3321), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x13d3, 0x3247) }, + { USB_DEVICE(0x13d3, 0x3273) }, + { USB_DEVICE(0x13d3, 0x3305) }, + { USB_DEVICE(0x13d3, 0x3307) }, + { USB_DEVICE(0x13d3, 0x3321) }, /* Belkin */ - { USB_DEVICE(0x050d, 0x8053), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x050d, 0x805c), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x050d, 0x815c), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x050d, 0x825b), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x050d, 0x935a), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x050d, 0x935b), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x050d, 0x8053) }, + { USB_DEVICE(0x050d, 0x805c) }, + { USB_DEVICE(0x050d, 0x815c) }, + { USB_DEVICE(0x050d, 0x825b) }, + { USB_DEVICE(0x050d, 0x935a) }, + { USB_DEVICE(0x050d, 0x935b) }, /* Buffalo */ - { USB_DEVICE(0x0411, 0x00e8), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x0411, 0x016f), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x0411, 0x01a2), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x0411, 0x00e8) }, + { USB_DEVICE(0x0411, 0x016f) }, + { USB_DEVICE(0x0411, 0x01a2) }, /* Corega */ - { USB_DEVICE(0x07aa, 0x002f), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x07aa, 0x003c), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x07aa, 0x003f), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x18c5, 0x0012), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x07aa, 0x002f) }, + { USB_DEVICE(0x07aa, 0x003c) }, + { USB_DEVICE(0x07aa, 0x003f) }, + { USB_DEVICE(0x18c5, 0x0012) }, /* D-Link */ - { USB_DEVICE(0x07d1, 0x3c09), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x07d1, 0x3c0a), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x07d1, 0x3c0d), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x07d1, 0x3c0e), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x07d1, 0x3c0f), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x07d1, 0x3c11), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x07d1, 0x3c16), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x07d1, 0x3c09) }, + { USB_DEVICE(0x07d1, 0x3c0a) }, + { USB_DEVICE(0x07d1, 0x3c0d) }, + { USB_DEVICE(0x07d1, 0x3c0e) }, + { USB_DEVICE(0x07d1, 0x3c0f) }, + { USB_DEVICE(0x07d1, 0x3c11) }, + { USB_DEVICE(0x07d1, 0x3c16) }, /* Draytek */ - { USB_DEVICE(0x07fa, 0x7712), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x07fa, 0x7712) }, /* Edimax */ - { USB_DEVICE(0x7392, 0x7711), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x7392, 0x7717), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x7392, 0x7718), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x7392, 0x7711) }, + { USB_DEVICE(0x7392, 0x7717) }, + { USB_DEVICE(0x7392, 0x7718) }, /* Encore */ - { USB_DEVICE(0x203d, 0x1480), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x203d, 0x14a9), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x203d, 0x1480) }, + { USB_DEVICE(0x203d, 0x14a9) }, /* EnGenius */ - { USB_DEVICE(0x1740, 0x9701), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x1740, 0x9702), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x1740, 0x9703), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x1740, 0x9705), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x1740, 0x9706), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x1740, 0x9707), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x1740, 0x9708), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x1740, 0x9709), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x1740, 0x9701) }, + { USB_DEVICE(0x1740, 0x9702) }, + { USB_DEVICE(0x1740, 0x9703) }, + { USB_DEVICE(0x1740, 0x9705) }, + { USB_DEVICE(0x1740, 0x9706) }, + { USB_DEVICE(0x1740, 0x9707) }, + { USB_DEVICE(0x1740, 0x9708) }, + { USB_DEVICE(0x1740, 0x9709) }, /* Gemtek */ - { USB_DEVICE(0x15a9, 0x0012), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x15a9, 0x0012) }, /* Gigabyte */ - { USB_DEVICE(0x1044, 0x800b), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x1044, 0x800d), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x1044, 0x800b) }, + { USB_DEVICE(0x1044, 0x800d) }, /* Hawking */ - { USB_DEVICE(0x0e66, 0x0001), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x0e66, 0x0003), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x0e66, 0x0009), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x0e66, 0x000b), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x0e66, 0x0013), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x0e66, 0x0017), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x0e66, 0x0018), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x0e66, 0x0001) }, + { USB_DEVICE(0x0e66, 0x0003) }, + { USB_DEVICE(0x0e66, 0x0009) }, + { USB_DEVICE(0x0e66, 0x000b) }, + { USB_DEVICE(0x0e66, 0x0013) }, + { USB_DEVICE(0x0e66, 0x0017) }, + { USB_DEVICE(0x0e66, 0x0018) }, /* I-O DATA */ - { USB_DEVICE(0x04bb, 0x0945), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x04bb, 0x0947), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x04bb, 0x0948), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x04bb, 0x0945) }, + { USB_DEVICE(0x04bb, 0x0947) }, + { USB_DEVICE(0x04bb, 0x0948) }, /* Linksys */ - { USB_DEVICE(0x13b1, 0x0031), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x1737, 0x0070), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x1737, 0x0071), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x13b1, 0x0031) }, + { USB_DEVICE(0x1737, 0x0070) }, + { USB_DEVICE(0x1737, 0x0071) }, /* Logitec */ - { USB_DEVICE(0x0789, 0x0162), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x0789, 0x0163), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x0789, 0x0164), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x0789, 0x0166), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x0789, 0x0162) }, + { USB_DEVICE(0x0789, 0x0163) }, + { USB_DEVICE(0x0789, 0x0164) }, + { USB_DEVICE(0x0789, 0x0166) }, /* Motorola */ - { USB_DEVICE(0x100d, 0x9031), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x100d, 0x9031) }, /* MSI */ - { USB_DEVICE(0x0db0, 0x3820), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x0db0, 0x3821), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x0db0, 0x3822), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x0db0, 0x3870), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x0db0, 0x3871), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x0db0, 0x6899), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x0db0, 0x821a), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x0db0, 0x822a), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x0db0, 0x822b), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x0db0, 0x822c), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x0db0, 0x870a), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x0db0, 0x871a), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x0db0, 0x871b), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x0db0, 0x871c), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x0db0, 0x899a), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x0db0, 0x3820) }, + { USB_DEVICE(0x0db0, 0x3821) }, + { USB_DEVICE(0x0db0, 0x3822) }, + { USB_DEVICE(0x0db0, 0x3870) }, + { USB_DEVICE(0x0db0, 0x3871) }, + { USB_DEVICE(0x0db0, 0x6899) }, + { USB_DEVICE(0x0db0, 0x821a) }, + { USB_DEVICE(0x0db0, 0x822a) }, + { USB_DEVICE(0x0db0, 0x822b) }, + { USB_DEVICE(0x0db0, 0x822c) }, + { USB_DEVICE(0x0db0, 0x870a) }, + { USB_DEVICE(0x0db0, 0x871a) }, + { USB_DEVICE(0x0db0, 0x871b) }, + { USB_DEVICE(0x0db0, 0x871c) }, + { USB_DEVICE(0x0db0, 0x899a) }, /* Para */ - { USB_DEVICE(0x20b8, 0x8888), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x20b8, 0x8888) }, /* Pegatron */ - { USB_DEVICE(0x1d4d, 0x000c), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x1d4d, 0x000e), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x1d4d, 0x0011), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x1d4d, 0x000c) }, + { USB_DEVICE(0x1d4d, 0x000e) }, + { USB_DEVICE(0x1d4d, 0x0011) }, /* Philips */ - { USB_DEVICE(0x0471, 0x200f), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x0471, 0x200f) }, /* Planex */ - { USB_DEVICE(0x2019, 0xab25), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x2019, 0xed06), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x2019, 0xab25) }, + { USB_DEVICE(0x2019, 0xed06) }, /* Quanta */ - { USB_DEVICE(0x1a32, 0x0304), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x1a32, 0x0304) }, /* Ralink */ - { USB_DEVICE(0x148f, 0x2070), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x148f, 0x2770), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x148f, 0x2870), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x148f, 0x3070), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x148f, 0x3071), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x148f, 0x3072), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x148f, 0x2070) }, + { USB_DEVICE(0x148f, 0x2770) }, + { USB_DEVICE(0x148f, 0x2870) }, + { USB_DEVICE(0x148f, 0x3070) }, + { USB_DEVICE(0x148f, 0x3071) }, + { USB_DEVICE(0x148f, 0x3072) }, /* Samsung */ - { USB_DEVICE(0x04e8, 0x2018), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x04e8, 0x2018) }, /* Siemens */ - { USB_DEVICE(0x129b, 0x1828), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x129b, 0x1828) }, /* Sitecom */ - { USB_DEVICE(0x0df6, 0x0017), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x0df6, 0x002b), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x0df6, 0x002c), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x0df6, 0x002d), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x0df6, 0x0039), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x0df6, 0x003b), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x0df6, 0x003d), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x0df6, 0x003e), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x0df6, 0x003f), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x0df6, 0x0040), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x0df6, 0x0042), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x0df6, 0x0047), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x0df6, 0x0048), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x0df6, 0x0017) }, + { USB_DEVICE(0x0df6, 0x002b) }, + { USB_DEVICE(0x0df6, 0x002c) }, + { USB_DEVICE(0x0df6, 0x002d) }, + { USB_DEVICE(0x0df6, 0x0039) }, + { USB_DEVICE(0x0df6, 0x003b) }, + { USB_DEVICE(0x0df6, 0x003d) }, + { USB_DEVICE(0x0df6, 0x003e) }, + { USB_DEVICE(0x0df6, 0x003f) }, + { USB_DEVICE(0x0df6, 0x0040) }, + { USB_DEVICE(0x0df6, 0x0042) }, + { USB_DEVICE(0x0df6, 0x0047) }, + { USB_DEVICE(0x0df6, 0x0048) }, /* SMC */ - { USB_DEVICE(0x083a, 0x6618), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x083a, 0x7511), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x083a, 0x7512), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x083a, 0x7522), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x083a, 0x8522), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x083a, 0xa618), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x083a, 0xa701), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x083a, 0xa702), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x083a, 0xa703), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x083a, 0xb522), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x083a, 0x6618) }, + { USB_DEVICE(0x083a, 0x7511) }, + { USB_DEVICE(0x083a, 0x7512) }, + { USB_DEVICE(0x083a, 0x7522) }, + { USB_DEVICE(0x083a, 0x8522) }, + { USB_DEVICE(0x083a, 0xa618) }, + { USB_DEVICE(0x083a, 0xa701) }, + { USB_DEVICE(0x083a, 0xa702) }, + { USB_DEVICE(0x083a, 0xa703) }, + { USB_DEVICE(0x083a, 0xb522) }, /* Sparklan */ - { USB_DEVICE(0x15a9, 0x0006), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x15a9, 0x0006) }, /* Sweex */ - { USB_DEVICE(0x177f, 0x0302), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x177f, 0x0302) }, /* U-Media */ - { USB_DEVICE(0x157e, 0x300e), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x157e, 0x3013), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x157e, 0x300e) }, + { USB_DEVICE(0x157e, 0x3013) }, /* ZCOM */ - { USB_DEVICE(0x0cde, 0x0022), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x0cde, 0x0025), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x0cde, 0x0022) }, + { USB_DEVICE(0x0cde, 0x0025) }, /* Zinwell */ - { USB_DEVICE(0x5a57, 0x0280), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x5a57, 0x0282), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x5a57, 0x0283), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x5a57, 0x5257), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x5a57, 0x0280) }, + { USB_DEVICE(0x5a57, 0x0282) }, + { USB_DEVICE(0x5a57, 0x0283) }, + { USB_DEVICE(0x5a57, 0x5257) }, /* Zyxel */ - { USB_DEVICE(0x0586, 0x3416), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x0586, 0x3418), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x0586, 0x341e), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x0586, 0x3416) }, + { USB_DEVICE(0x0586, 0x3418) }, + { USB_DEVICE(0x0586, 0x341e) }, #ifdef CONFIG_RT2800USB_RT33XX /* Ralink */ - { USB_DEVICE(0x148f, 0x3370), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x148f, 0x8070), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x148f, 0x3370) }, + { USB_DEVICE(0x148f, 0x8070) }, /* Sitecom */ - { USB_DEVICE(0x0df6, 0x0050), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x0df6, 0x0050) }, #endif #ifdef CONFIG_RT2800USB_RT35XX /* Allwin */ - { USB_DEVICE(0x8516, 0x3572), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x8516, 0x3572) }, /* Askey */ - { USB_DEVICE(0x1690, 0x0744), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x1690, 0x0744) }, /* Cisco */ - { USB_DEVICE(0x167b, 0x4001), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x167b, 0x4001) }, /* EnGenius */ - { USB_DEVICE(0x1740, 0x9801), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x1740, 0x9801) }, /* I-O DATA */ - { USB_DEVICE(0x04bb, 0x0944), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x04bb, 0x0944) }, /* Linksys */ - { USB_DEVICE(0x13b1, 0x002f), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x1737, 0x0079), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x13b1, 0x002f) }, + { USB_DEVICE(0x1737, 0x0079) }, /* Ralink */ - { USB_DEVICE(0x148f, 0x3572), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x148f, 0x3572) }, /* Sitecom */ - { USB_DEVICE(0x0df6, 0x0041), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x0df6, 0x0041) }, /* Toshiba */ - { USB_DEVICE(0x0930, 0x0a07), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x0930, 0x0a07) }, /* Zinwell */ - { USB_DEVICE(0x5a57, 0x0284), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x5a57, 0x0284) }, #endif #ifdef CONFIG_RT2800USB_UNKNOWN /* @@ -999,73 +999,73 @@ static struct usb_device_id rt2800usb_device_table[] = { * vendor linux driver). */ /* Alpha Networks */ - { USB_DEVICE(0x14b2, 0x3c08), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x14b2, 0x3c11), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x14b2, 0x3c08) }, + { USB_DEVICE(0x14b2, 0x3c11) }, /* Amigo */ - { USB_DEVICE(0x0e0b, 0x9031), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x0e0b, 0x9041), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x0e0b, 0x9031) }, + { USB_DEVICE(0x0e0b, 0x9041) }, /* ASUS */ - { USB_DEVICE(0x0b05, 0x1760), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x0b05, 0x1761), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x0b05, 0x1790), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x0b05, 0x1760) }, + { USB_DEVICE(0x0b05, 0x1761) }, + { USB_DEVICE(0x0b05, 0x1790) }, /* AzureWave */ - { USB_DEVICE(0x13d3, 0x3262), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x13d3, 0x3284), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x13d3, 0x3322), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x13d3, 0x3262) }, + { USB_DEVICE(0x13d3, 0x3284) }, + { USB_DEVICE(0x13d3, 0x3322) }, /* Belkin */ - { USB_DEVICE(0x050d, 0x825a), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x050d, 0x825a) }, /* Buffalo */ - { USB_DEVICE(0x0411, 0x012e), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x0411, 0x0148), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x0411, 0x0150), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x0411, 0x015d), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x0411, 0x012e) }, + { USB_DEVICE(0x0411, 0x0148) }, + { USB_DEVICE(0x0411, 0x0150) }, + { USB_DEVICE(0x0411, 0x015d) }, /* Corega */ - { USB_DEVICE(0x07aa, 0x0041), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x07aa, 0x0042), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x18c5, 0x0008), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x07aa, 0x0041) }, + { USB_DEVICE(0x07aa, 0x0042) }, + { USB_DEVICE(0x18c5, 0x0008) }, /* D-Link */ - { USB_DEVICE(0x07d1, 0x3c0b), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x07d1, 0x3c13), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x07d1, 0x3c15), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x07d1, 0x3c17), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x07d1, 0x3c0b) }, + { USB_DEVICE(0x07d1, 0x3c13) }, + { USB_DEVICE(0x07d1, 0x3c15) }, + { USB_DEVICE(0x07d1, 0x3c17) }, /* Edimax */ - { USB_DEVICE(0x7392, 0x4085), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x7392, 0x4085) }, /* Encore */ - { USB_DEVICE(0x203d, 0x14a1), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x203d, 0x14a1) }, /* Gemtek */ - { USB_DEVICE(0x15a9, 0x0010), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x15a9, 0x0010) }, /* Gigabyte */ - { USB_DEVICE(0x1044, 0x800c), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x1044, 0x800c) }, /* LevelOne */ - { USB_DEVICE(0x1740, 0x0605), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x1740, 0x0615), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x1740, 0x0605) }, + { USB_DEVICE(0x1740, 0x0615) }, /* Linksys */ - { USB_DEVICE(0x1737, 0x0077), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x1737, 0x0078), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x1737, 0x0077) }, + { USB_DEVICE(0x1737, 0x0078) }, /* Motorola */ - { USB_DEVICE(0x100d, 0x9032), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x100d, 0x9032) }, /* Ovislink */ - { USB_DEVICE(0x1b75, 0x3071), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x1b75, 0x3072), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x1b75, 0x3071) }, + { USB_DEVICE(0x1b75, 0x3072) }, /* Pegatron */ - { USB_DEVICE(0x05a6, 0x0101), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x1d4d, 0x0002), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x1d4d, 0x0010), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x05a6, 0x0101) }, + { USB_DEVICE(0x1d4d, 0x0002) }, + { USB_DEVICE(0x1d4d, 0x0010) }, /* Planex */ - { USB_DEVICE(0x2019, 0x5201), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x2019, 0xab24), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x2019, 0x5201) }, + { USB_DEVICE(0x2019, 0xab24) }, /* Qcom */ - { USB_DEVICE(0x18e8, 0x6259), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x18e8, 0x6259) }, /* SMC */ - { USB_DEVICE(0x083a, 0xa512), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x083a, 0xc522), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x083a, 0xd522), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x083a, 0xf511), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x083a, 0xa512) }, + { USB_DEVICE(0x083a, 0xc522) }, + { USB_DEVICE(0x083a, 0xd522) }, + { USB_DEVICE(0x083a, 0xf511) }, /* Sweex */ - { USB_DEVICE(0x177f, 0x0153), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x177f, 0x0313), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x177f, 0x0153) }, + { USB_DEVICE(0x177f, 0x0313) }, /* Zyxel */ - { USB_DEVICE(0x0586, 0x341a), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x0586, 0x341a) }, #endif { 0, } }; @@ -1078,10 +1078,16 @@ MODULE_DEVICE_TABLE(usb, rt2800usb_device_table); MODULE_FIRMWARE(FIRMWARE_RT2870); MODULE_LICENSE("GPL"); +static int rt2800usb_probe(struct usb_interface *usb_intf, + const struct usb_device_id *id) +{ + return rt2x00usb_probe(usb_intf, &rt2800usb_ops); +} + static struct usb_driver rt2800usb_driver = { .name = KBUILD_MODNAME, .id_table = rt2800usb_device_table, - .probe = rt2x00usb_probe, + .probe = rt2800usb_probe, .disconnect = rt2x00usb_disconnect, .suspend = rt2x00usb_suspend, .resume = rt2x00usb_resume, diff --git a/drivers/net/wireless/rt2x00/rt2x00pci.c b/drivers/net/wireless/rt2x00/rt2x00pci.c index 695aecf..17148bb 100644 --- a/drivers/net/wireless/rt2x00/rt2x00pci.c +++ b/drivers/net/wireless/rt2x00/rt2x00pci.c @@ -251,9 +251,8 @@ exit: return -ENOMEM; } -int rt2x00pci_probe(struct pci_dev *pci_dev, const struct pci_device_id *id) +int rt2x00pci_probe(struct pci_dev *pci_dev, const struct rt2x00_ops *ops) { - struct rt2x00_ops *ops = (struct rt2x00_ops *)id->driver_data; struct ieee80211_hw *hw; struct rt2x00_dev *rt2x00dev; int retval; diff --git a/drivers/net/wireless/rt2x00/rt2x00pci.h b/drivers/net/wireless/rt2x00/rt2x00pci.h index 5d58874..e2c99f2 100644 --- a/drivers/net/wireless/rt2x00/rt2x00pci.h +++ b/drivers/net/wireless/rt2x00/rt2x00pci.h @@ -126,7 +126,7 @@ void rt2x00pci_uninitialize(struct rt2x00_dev *rt2x00dev); /* * PCI driver handlers. */ -int rt2x00pci_probe(struct pci_dev *pci_dev, const struct pci_device_id *id); +int rt2x00pci_probe(struct pci_dev *pci_dev, const struct rt2x00_ops *ops); void rt2x00pci_remove(struct pci_dev *pci_dev); #ifdef CONFIG_PM int rt2x00pci_suspend(struct pci_dev *pci_dev, pm_message_t state); diff --git a/drivers/net/wireless/rt2x00/rt2x00usb.c b/drivers/net/wireless/rt2x00/rt2x00usb.c index 9957579..570184e 100644 --- a/drivers/net/wireless/rt2x00/rt2x00usb.c +++ b/drivers/net/wireless/rt2x00/rt2x00usb.c @@ -791,10 +791,9 @@ exit: } int rt2x00usb_probe(struct usb_interface *usb_intf, - const struct usb_device_id *id) + const struct rt2x00_ops *ops) { struct usb_device *usb_dev = interface_to_usbdev(usb_intf); - struct rt2x00_ops *ops = (struct rt2x00_ops *)id->driver_info; struct ieee80211_hw *hw; struct rt2x00_dev *rt2x00dev; int retval; diff --git a/drivers/net/wireless/rt2x00/rt2x00usb.h b/drivers/net/wireless/rt2x00/rt2x00usb.h index 6aeba71..52b09d2 100644 --- a/drivers/net/wireless/rt2x00/rt2x00usb.h +++ b/drivers/net/wireless/rt2x00/rt2x00usb.h @@ -35,12 +35,6 @@ }) /* - * This variable should be used with the - * usb_driver structure initialization. - */ -#define USB_DEVICE_DATA(__ops) .driver_info = (kernel_ulong_t)(__ops) - -/* * For USB vendor requests we need to pass a timeout * time in ms, for this we use the REGISTER_TIMEOUT, * however when loading firmware a higher value is @@ -433,7 +427,7 @@ void rt2x00usb_uninitialize(struct rt2x00_dev *rt2x00dev); * USB driver handlers. */ int rt2x00usb_probe(struct usb_interface *usb_intf, - const struct usb_device_id *id); + const struct rt2x00_ops *ops); void rt2x00usb_disconnect(struct usb_interface *usb_intf); #ifdef CONFIG_PM int rt2x00usb_suspend(struct usb_interface *usb_intf, pm_message_t state); diff --git a/drivers/net/wireless/rt2x00/rt61pci.c b/drivers/net/wireless/rt2x00/rt61pci.c index 264508f..c5dccdb 100644 --- a/drivers/net/wireless/rt2x00/rt61pci.c +++ b/drivers/net/wireless/rt2x00/rt61pci.c @@ -3061,11 +3061,11 @@ static const struct rt2x00_ops rt61pci_ops = { */ static DEFINE_PCI_DEVICE_TABLE(rt61pci_device_table) = { /* RT2561s */ - { PCI_DEVICE(0x1814, 0x0301), PCI_DEVICE_DATA(&rt61pci_ops) }, + { PCI_DEVICE(0x1814, 0x0301) }, /* RT2561 v2 */ - { PCI_DEVICE(0x1814, 0x0302), PCI_DEVICE_DATA(&rt61pci_ops) }, + { PCI_DEVICE(0x1814, 0x0302) }, /* RT2661 */ - { PCI_DEVICE(0x1814, 0x0401), PCI_DEVICE_DATA(&rt61pci_ops) }, + { PCI_DEVICE(0x1814, 0x0401) }, { 0, } }; @@ -3080,10 +3080,16 @@ MODULE_FIRMWARE(FIRMWARE_RT2561s); MODULE_FIRMWARE(FIRMWARE_RT2661); MODULE_LICENSE("GPL"); +static int rt61pci_probe(struct pci_dev *pci_dev, + const struct pci_device_id *id) +{ + return rt2x00pci_probe(pci_dev, &rt61pci_ops); +} + static struct pci_driver rt61pci_driver = { .name = KBUILD_MODNAME, .id_table = rt61pci_device_table, - .probe = rt2x00pci_probe, + .probe = rt61pci_probe, .remove = __devexit_p(rt2x00pci_remove), .suspend = rt2x00pci_suspend, .resume = rt2x00pci_resume, diff --git a/drivers/net/wireless/rt2x00/rt73usb.c b/drivers/net/wireless/rt2x00/rt73usb.c index cdb026d..be3eb5e 100644 --- a/drivers/net/wireless/rt2x00/rt73usb.c +++ b/drivers/net/wireless/rt2x00/rt73usb.c @@ -2388,113 +2388,113 @@ static const struct rt2x00_ops rt73usb_ops = { */ static struct usb_device_id rt73usb_device_table[] = { /* AboCom */ - { USB_DEVICE(0x07b8, 0xb21b), USB_DEVICE_DATA(&rt73usb_ops) }, - { USB_DEVICE(0x07b8, 0xb21c), USB_DEVICE_DATA(&rt73usb_ops) }, - { USB_DEVICE(0x07b8, 0xb21d), USB_DEVICE_DATA(&rt73usb_ops) }, - { USB_DEVICE(0x07b8, 0xb21e), USB_DEVICE_DATA(&rt73usb_ops) }, - { USB_DEVICE(0x07b8, 0xb21f), USB_DEVICE_DATA(&rt73usb_ops) }, + { USB_DEVICE(0x07b8, 0xb21b) }, + { USB_DEVICE(0x07b8, 0xb21c) }, + { USB_DEVICE(0x07b8, 0xb21d) }, + { USB_DEVICE(0x07b8, 0xb21e) }, + { USB_DEVICE(0x07b8, 0xb21f) }, /* AL */ - { USB_DEVICE(0x14b2, 0x3c10), USB_DEVICE_DATA(&rt73usb_ops) }, + { USB_DEVICE(0x14b2, 0x3c10) }, /* Amigo */ - { USB_DEVICE(0x148f, 0x9021), USB_DEVICE_DATA(&rt73usb_ops) }, - { USB_DEVICE(0x0eb0, 0x9021), USB_DEVICE_DATA(&rt73usb_ops) }, + { USB_DEVICE(0x148f, 0x9021) }, + { USB_DEVICE(0x0eb0, 0x9021) }, /* AMIT */ - { USB_DEVICE(0x18c5, 0x0002), USB_DEVICE_DATA(&rt73usb_ops) }, + { USB_DEVICE(0x18c5, 0x0002) }, /* Askey */ - { USB_DEVICE(0x1690, 0x0722), USB_DEVICE_DATA(&rt73usb_ops) }, + { USB_DEVICE(0x1690, 0x0722) }, /* ASUS */ - { USB_DEVICE(0x0b05, 0x1723), USB_DEVICE_DATA(&rt73usb_ops) }, - { USB_DEVICE(0x0b05, 0x1724), USB_DEVICE_DATA(&rt73usb_ops) }, + { USB_DEVICE(0x0b05, 0x1723) }, + { USB_DEVICE(0x0b05, 0x1724) }, /* Belkin */ - { USB_DEVICE(0x050d, 0x705a), USB_DEVICE_DATA(&rt73usb_ops) }, - { USB_DEVICE(0x050d, 0x905b), USB_DEVICE_DATA(&rt73usb_ops) }, - { USB_DEVICE(0x050d, 0x905c), USB_DEVICE_DATA(&rt73usb_ops) }, + { USB_DEVICE(0x050d, 0x705a) }, + { USB_DEVICE(0x050d, 0x905b) }, + { USB_DEVICE(0x050d, 0x905c) }, /* Billionton */ - { USB_DEVICE(0x1631, 0xc019), USB_DEVICE_DATA(&rt73usb_ops) }, - { USB_DEVICE(0x08dd, 0x0120), USB_DEVICE_DATA(&rt73usb_ops) }, + { USB_DEVICE(0x1631, 0xc019) }, + { USB_DEVICE(0x08dd, 0x0120) }, /* Buffalo */ - { USB_DEVICE(0x0411, 0x00d8), USB_DEVICE_DATA(&rt73usb_ops) }, - { USB_DEVICE(0x0411, 0x00d9), USB_DEVICE_DATA(&rt73usb_ops) }, - { USB_DEVICE(0x0411, 0x00f4), USB_DEVICE_DATA(&rt73usb_ops) }, - { USB_DEVICE(0x0411, 0x0116), USB_DEVICE_DATA(&rt73usb_ops) }, - { USB_DEVICE(0x0411, 0x0119), USB_DEVICE_DATA(&rt73usb_ops) }, - { USB_DEVICE(0x0411, 0x0137), USB_DEVICE_DATA(&rt73usb_ops) }, + { USB_DEVICE(0x0411, 0x00d8) }, + { USB_DEVICE(0x0411, 0x00d9) }, + { USB_DEVICE(0x0411, 0x00f4) }, + { USB_DEVICE(0x0411, 0x0116) }, + { USB_DEVICE(0x0411, 0x0119) }, + { USB_DEVICE(0x0411, 0x0137) }, /* CEIVA */ - { USB_DEVICE(0x178d, 0x02be), USB_DEVICE_DATA(&rt73usb_ops) }, + { USB_DEVICE(0x178d, 0x02be) }, /* CNet */ - { USB_DEVICE(0x1371, 0x9022), USB_DEVICE_DATA(&rt73usb_ops) }, - { USB_DEVICE(0x1371, 0x9032), USB_DEVICE_DATA(&rt73usb_ops) }, + { USB_DEVICE(0x1371, 0x9022) }, + { USB_DEVICE(0x1371, 0x9032) }, /* Conceptronic */ - { USB_DEVICE(0x14b2, 0x3c22), USB_DEVICE_DATA(&rt73usb_ops) }, + { USB_DEVICE(0x14b2, 0x3c22) }, /* Corega */ - { USB_DEVICE(0x07aa, 0x002e), USB_DEVICE_DATA(&rt73usb_ops) }, + { USB_DEVICE(0x07aa, 0x002e) }, /* D-Link */ - { USB_DEVICE(0x07d1, 0x3c03), USB_DEVICE_DATA(&rt73usb_ops) }, - { USB_DEVICE(0x07d1, 0x3c04), USB_DEVICE_DATA(&rt73usb_ops) }, - { USB_DEVICE(0x07d1, 0x3c06), USB_DEVICE_DATA(&rt73usb_ops) }, - { USB_DEVICE(0x07d1, 0x3c07), USB_DEVICE_DATA(&rt73usb_ops) }, + { USB_DEVICE(0x07d1, 0x3c03) }, + { USB_DEVICE(0x07d1, 0x3c04) }, + { USB_DEVICE(0x07d1, 0x3c06) }, + { USB_DEVICE(0x07d1, 0x3c07) }, /* Edimax */ - { USB_DEVICE(0x7392, 0x7318), USB_DEVICE_DATA(&rt73usb_ops) }, - { USB_DEVICE(0x7392, 0x7618), USB_DEVICE_DATA(&rt73usb_ops) }, + { USB_DEVICE(0x7392, 0x7318) }, + { USB_DEVICE(0x7392, 0x7618) }, /* EnGenius */ - { USB_DEVICE(0x1740, 0x3701), USB_DEVICE_DATA(&rt73usb_ops) }, + { USB_DEVICE(0x1740, 0x3701) }, /* Gemtek */ - { USB_DEVICE(0x15a9, 0x0004), USB_DEVICE_DATA(&rt73usb_ops) }, + { USB_DEVICE(0x15a9, 0x0004) }, /* Gigabyte */ - { USB_DEVICE(0x1044, 0x8008), USB_DEVICE_DATA(&rt73usb_ops) }, - { USB_DEVICE(0x1044, 0x800a), USB_DEVICE_DATA(&rt73usb_ops) }, + { USB_DEVICE(0x1044, 0x8008) }, + { USB_DEVICE(0x1044, 0x800a) }, /* Huawei-3Com */ - { USB_DEVICE(0x1472, 0x0009), USB_DEVICE_DATA(&rt73usb_ops) }, + { USB_DEVICE(0x1472, 0x0009) }, /* Hercules */ - { USB_DEVICE(0x06f8, 0xe002), USB_DEVICE_DATA(&rt73usb_ops) }, - { USB_DEVICE(0x06f8, 0xe010), USB_DEVICE_DATA(&rt73usb_ops) }, - { USB_DEVICE(0x06f8, 0xe020), USB_DEVICE_DATA(&rt73usb_ops) }, + { USB_DEVICE(0x06f8, 0xe002) }, + { USB_DEVICE(0x06f8, 0xe010) }, + { USB_DEVICE(0x06f8, 0xe020) }, /* Linksys */ - { USB_DEVICE(0x13b1, 0x0020), USB_DEVICE_DATA(&rt73usb_ops) }, - { USB_DEVICE(0x13b1, 0x0023), USB_DEVICE_DATA(&rt73usb_ops) }, - { USB_DEVICE(0x13b1, 0x0028), USB_DEVICE_DATA(&rt73usb_ops) }, + { USB_DEVICE(0x13b1, 0x0020) }, + { USB_DEVICE(0x13b1, 0x0023) }, + { USB_DEVICE(0x13b1, 0x0028) }, /* MSI */ - { USB_DEVICE(0x0db0, 0x4600), USB_DEVICE_DATA(&rt73usb_ops) }, - { USB_DEVICE(0x0db0, 0x6877), USB_DEVICE_DATA(&rt73usb_ops) }, - { USB_DEVICE(0x0db0, 0x6874), USB_DEVICE_DATA(&rt73usb_ops) }, - { USB_DEVICE(0x0db0, 0xa861), USB_DEVICE_DATA(&rt73usb_ops) }, - { USB_DEVICE(0x0db0, 0xa874), USB_DEVICE_DATA(&rt73usb_ops) }, + { USB_DEVICE(0x0db0, 0x4600) }, + { USB_DEVICE(0x0db0, 0x6877) }, + { USB_DEVICE(0x0db0, 0x6874) }, + { USB_DEVICE(0x0db0, 0xa861) }, + { USB_DEVICE(0x0db0, 0xa874) }, /* Ovislink */ - { USB_DEVICE(0x1b75, 0x7318), USB_DEVICE_DATA(&rt73usb_ops) }, + { USB_DEVICE(0x1b75, 0x7318) }, /* Ralink */ - { USB_DEVICE(0x04bb, 0x093d), USB_DEVICE_DATA(&rt73usb_ops) }, - { USB_DEVICE(0x148f, 0x2573), USB_DEVICE_DATA(&rt73usb_ops) }, - { USB_DEVICE(0x148f, 0x2671), USB_DEVICE_DATA(&rt73usb_ops) }, - { USB_DEVICE(0x0812, 0x3101), USB_DEVICE_DATA(&rt73usb_ops) }, + { USB_DEVICE(0x04bb, 0x093d) }, + { USB_DEVICE(0x148f, 0x2573) }, + { USB_DEVICE(0x148f, 0x2671) }, + { USB_DEVICE(0x0812, 0x3101) }, /* Qcom */ - { USB_DEVICE(0x18e8, 0x6196), USB_DEVICE_DATA(&rt73usb_ops) }, - { USB_DEVICE(0x18e8, 0x6229), USB_DEVICE_DATA(&rt73usb_ops) }, - { USB_DEVICE(0x18e8, 0x6238), USB_DEVICE_DATA(&rt73usb_ops) }, + { USB_DEVICE(0x18e8, 0x6196) }, + { USB_DEVICE(0x18e8, 0x6229) }, + { USB_DEVICE(0x18e8, 0x6238) }, /* Samsung */ - { USB_DEVICE(0x04e8, 0x4471), USB_DEVICE_DATA(&rt73usb_ops) }, + { USB_DEVICE(0x04e8, 0x4471) }, /* Senao */ - { USB_DEVICE(0x1740, 0x7100), USB_DEVICE_DATA(&rt73usb_ops) }, + { USB_DEVICE(0x1740, 0x7100) }, /* Sitecom */ - { USB_DEVICE(0x0df6, 0x0024), USB_DEVICE_DATA(&rt73usb_ops) }, - { USB_DEVICE(0x0df6, 0x0027), USB_DEVICE_DATA(&rt73usb_ops) }, - { USB_DEVICE(0x0df6, 0x002f), USB_DEVICE_DATA(&rt73usb_ops) }, - { USB_DEVICE(0x0df6, 0x90ac), USB_DEVICE_DATA(&rt73usb_ops) }, - { USB_DEVICE(0x0df6, 0x9712), USB_DEVICE_DATA(&rt73usb_ops) }, + { USB_DEVICE(0x0df6, 0x0024) }, + { USB_DEVICE(0x0df6, 0x0027) }, + { USB_DEVICE(0x0df6, 0x002f) }, + { USB_DEVICE(0x0df6, 0x90ac) }, + { USB_DEVICE(0x0df6, 0x9712) }, /* Surecom */ - { USB_DEVICE(0x0769, 0x31f3), USB_DEVICE_DATA(&rt73usb_ops) }, + { USB_DEVICE(0x0769, 0x31f3) }, /* Tilgin */ - { USB_DEVICE(0x6933, 0x5001), USB_DEVICE_DATA(&rt73usb_ops) }, + { USB_DEVICE(0x6933, 0x5001) }, /* Philips */ - { USB_DEVICE(0x0471, 0x200a), USB_DEVICE_DATA(&rt73usb_ops) }, + { USB_DEVICE(0x0471, 0x200a) }, /* Planex */ - { USB_DEVICE(0x2019, 0xab01), USB_DEVICE_DATA(&rt73usb_ops) }, - { USB_DEVICE(0x2019, 0xab50), USB_DEVICE_DATA(&rt73usb_ops) }, + { USB_DEVICE(0x2019, 0xab01) }, + { USB_DEVICE(0x2019, 0xab50) }, /* WideTell */ - { USB_DEVICE(0x7167, 0x3840), USB_DEVICE_DATA(&rt73usb_ops) }, + { USB_DEVICE(0x7167, 0x3840) }, /* Zcom */ - { USB_DEVICE(0x0cde, 0x001c), USB_DEVICE_DATA(&rt73usb_ops) }, + { USB_DEVICE(0x0cde, 0x001c) }, /* ZyXEL */ - { USB_DEVICE(0x0586, 0x3415), USB_DEVICE_DATA(&rt73usb_ops) }, + { USB_DEVICE(0x0586, 0x3415) }, { 0, } }; @@ -2506,10 +2506,16 @@ MODULE_DEVICE_TABLE(usb, rt73usb_device_table); MODULE_FIRMWARE(FIRMWARE_RT2571); MODULE_LICENSE("GPL"); +static int rt73usb_probe(struct usb_interface *usb_intf, + const struct usb_device_id *id) +{ + return rt2x00usb_probe(usb_intf, &rt73usb_ops); +} + static struct usb_driver rt73usb_driver = { .name = KBUILD_MODNAME, .id_table = rt73usb_device_table, - .probe = rt2x00usb_probe, + .probe = rt73usb_probe, .disconnect = rt2x00usb_disconnect, .suspend = rt2x00usb_suspend, .resume = rt2x00usb_resume, -- cgit v0.10.2 From 87a3b89f34fb20f644b42fa57d579b1f2833fd4d Mon Sep 17 00:00:00 2001 From: Gertjan van Wingerde Date: Mon, 18 Apr 2011 15:32:33 +0200 Subject: rt2x00: Add USB IDs. Add USB IDs that are listed in the latest Ralink Windows and/or Linux drivers. Signed-off-by: Gertjan van Wingerde Signed-off-by: Ivo van Doorn Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/rt2x00/rt2800usb.c b/drivers/net/wireless/rt2x00/rt2800usb.c index 6f7c161..fd8aa99 100644 --- a/drivers/net/wireless/rt2x00/rt2800usb.c +++ b/drivers/net/wireless/rt2x00/rt2800usb.c @@ -775,6 +775,7 @@ static struct usb_device_id rt2800usb_device_table[] = { { USB_DEVICE(0x07b8, 0x3072) }, { USB_DEVICE(0x1482, 0x3c09) }, /* AirTies */ + { USB_DEVICE(0x1eda, 0x2012) }, { USB_DEVICE(0x1eda, 0x2310) }, /* Allwin */ { USB_DEVICE(0x8516, 0x2070) }, @@ -933,6 +934,8 @@ static struct usb_device_id rt2800usb_device_table[] = { { USB_DEVICE(0x0df6, 0x0042) }, { USB_DEVICE(0x0df6, 0x0047) }, { USB_DEVICE(0x0df6, 0x0048) }, + { USB_DEVICE(0x0df6, 0x0051) }, + { USB_DEVICE(0x0df6, 0x005f) }, /* SMC */ { USB_DEVICE(0x083a, 0x6618) }, { USB_DEVICE(0x083a, 0x7511) }, @@ -963,6 +966,7 @@ static struct usb_device_id rt2800usb_device_table[] = { { USB_DEVICE(0x0586, 0x3416) }, { USB_DEVICE(0x0586, 0x3418) }, { USB_DEVICE(0x0586, 0x341e) }, + { USB_DEVICE(0x0586, 0x343e) }, #ifdef CONFIG_RT2800USB_RT33XX /* Ralink */ { USB_DEVICE(0x148f, 0x3370) }, @@ -998,6 +1002,9 @@ static struct usb_device_id rt2800usb_device_table[] = { * Unclear what kind of devices these are (they aren't supported by the * vendor linux driver). */ + /* Abocom */ + { USB_DEVICE(0x07b8, 0x3073) }, + { USB_DEVICE(0x07b8, 0x3074) }, /* Alpha Networks */ { USB_DEVICE(0x14b2, 0x3c08) }, { USB_DEVICE(0x14b2, 0x3c11) }, @@ -1005,14 +1012,17 @@ static struct usb_device_id rt2800usb_device_table[] = { { USB_DEVICE(0x0e0b, 0x9031) }, { USB_DEVICE(0x0e0b, 0x9041) }, /* ASUS */ + { USB_DEVICE(0x0b05, 0x166a) }, { USB_DEVICE(0x0b05, 0x1760) }, { USB_DEVICE(0x0b05, 0x1761) }, { USB_DEVICE(0x0b05, 0x1790) }, + { USB_DEVICE(0x0b05, 0x179d) }, /* AzureWave */ { USB_DEVICE(0x13d3, 0x3262) }, { USB_DEVICE(0x13d3, 0x3284) }, { USB_DEVICE(0x13d3, 0x3322) }, /* Belkin */ + { USB_DEVICE(0x050d, 0x1003) }, { USB_DEVICE(0x050d, 0x825a) }, /* Buffalo */ { USB_DEVICE(0x0411, 0x012e) }, @@ -1028,20 +1038,29 @@ static struct usb_device_id rt2800usb_device_table[] = { { USB_DEVICE(0x07d1, 0x3c13) }, { USB_DEVICE(0x07d1, 0x3c15) }, { USB_DEVICE(0x07d1, 0x3c17) }, + { USB_DEVICE(0x2001, 0x3c17) }, /* Edimax */ { USB_DEVICE(0x7392, 0x4085) }, + { USB_DEVICE(0x7392, 0x7722) }, /* Encore */ { USB_DEVICE(0x203d, 0x14a1) }, /* Gemtek */ { USB_DEVICE(0x15a9, 0x0010) }, /* Gigabyte */ { USB_DEVICE(0x1044, 0x800c) }, + /* Huawei */ + { USB_DEVICE(0x148f, 0xf101) }, + /* I-O DATA */ + { USB_DEVICE(0x04bb, 0x094b) }, /* LevelOne */ { USB_DEVICE(0x1740, 0x0605) }, { USB_DEVICE(0x1740, 0x0615) }, /* Linksys */ { USB_DEVICE(0x1737, 0x0077) }, { USB_DEVICE(0x1737, 0x0078) }, + /* Logitec */ + { USB_DEVICE(0x0789, 0x0168) }, + { USB_DEVICE(0x0789, 0x0169) }, /* Motorola */ { USB_DEVICE(0x100d, 0x9032) }, /* Ovislink */ @@ -1056,6 +1075,15 @@ static struct usb_device_id rt2800usb_device_table[] = { { USB_DEVICE(0x2019, 0xab24) }, /* Qcom */ { USB_DEVICE(0x18e8, 0x6259) }, + /* RadioShack */ + { USB_DEVICE(0x08b9, 0x1197) }, + /* Sitecom */ + { USB_DEVICE(0x0df6, 0x003c) }, + { USB_DEVICE(0x0df6, 0x004a) }, + { USB_DEVICE(0x0df6, 0x004d) }, + { USB_DEVICE(0x0df6, 0x0053) }, + { USB_DEVICE(0x0df6, 0x0060) }, + { USB_DEVICE(0x0df6, 0x0062) }, /* SMC */ { USB_DEVICE(0x083a, 0xa512) }, { USB_DEVICE(0x083a, 0xc522) }, -- cgit v0.10.2 From ccd3caa4516c56540017d1af6c810940eff6afb8 Mon Sep 17 00:00:00 2001 From: Gertjan van Wingerde Date: Mon, 18 Apr 2011 15:33:00 +0200 Subject: rt2x00: RT33xx device support is no longer experimental. The rt33xx devices support for both PCI and USB devices has been in the tree for a couple of months now, and seems to be functional and not in a worse shape than the support for rt28xx and rt30xx devices. No longer mark it as experimental and enable the support for these devices by default. Signed-off-by: Gertjan van Wingerde Signed-off-by: Ivo van Doorn Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/rt2x00/Kconfig b/drivers/net/wireless/rt2x00/Kconfig index f630552..e7e361e 100644 --- a/drivers/net/wireless/rt2x00/Kconfig +++ b/drivers/net/wireless/rt2x00/Kconfig @@ -74,17 +74,13 @@ config RT2800PCI if RT2800PCI config RT2800PCI_RT33XX - bool "rt2800pci - Include support for rt33xx devices (EXPERIMENTAL)" - depends on EXPERIMENTAL - default n + bool "rt2800pci - Include support for rt33xx devices" + default y ---help--- This adds support for rt33xx wireless chipset family to the rt2800pci driver. Supported chips: RT3390 - Support for these devices is non-functional at the moment and is - intended for testers and developers. - config RT2800PCI_RT35XX bool "rt2800pci - Include support for rt35xx devices (EXPERIMENTAL)" depends on EXPERIMENTAL @@ -153,17 +149,13 @@ config RT2800USB if RT2800USB config RT2800USB_RT33XX - bool "rt2800usb - Include support for rt33xx devices (EXPERIMENTAL)" - depends on EXPERIMENTAL - default n + bool "rt2800usb - Include support for rt33xx devices" + default y ---help--- This adds support for rt33xx wireless chipset family to the rt2800usb driver. Supported chips: RT3370 - Support for these devices is non-functional at the moment and is - intended for testers and developers. - config RT2800USB_RT35XX bool "rt2800usb - Include support for rt35xx devices (EXPERIMENTAL)" depends on EXPERIMENTAL -- cgit v0.10.2 From ea81966ccc2edd324c1fa382260a62a4400a032a Mon Sep 17 00:00:00 2001 From: Gertjan van Wingerde Date: Mon, 18 Apr 2011 15:33:20 +0200 Subject: rt2x00: Enable support for RT53xx PCI devices by default. Code seems to be feature-complete, so no reason to not enable these devices by default. Also, remove the sentence about the support for these devices being non-functional. Signed-off-by: Gertjan van Wingerde Signed-off-by: Ivo van Doorn Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/rt2x00/Kconfig b/drivers/net/wireless/rt2x00/Kconfig index e7e361e..d7e27b3 100644 --- a/drivers/net/wireless/rt2x00/Kconfig +++ b/drivers/net/wireless/rt2x00/Kconfig @@ -96,15 +96,12 @@ config RT2800PCI_RT35XX config RT2800PCI_RT53XX bool "rt2800-pci - Include support for rt53xx devices (EXPERIMENTAL)" depends on EXPERIMENTAL - default n + default y ---help--- This adds support for rt53xx wireless chipset family to the rt2800pci driver. Supported chips: RT5390 - Support for these devices is non-functional at the moment and is - intended for testers and developers. - endif config RT2500USB -- cgit v0.10.2 From 46a01ec00d05581c5bd0c37e680d5b37af4953b4 Mon Sep 17 00:00:00 2001 From: Gertjan van Wingerde Date: Mon, 18 Apr 2011 15:33:41 +0200 Subject: rt2x00: Merge rt2x00ht.c contents in other files. The two functions that are in rt2x00ht.c can be much better placed closer to the places where the call-sites of these functions are (one in rt2x00config.c and one in rt2x00queue.c) allowing us to make these functions static. Also, conditional compilations doesn't seem to be necessary anymore as 802.11n support is quite common nowadays. This makes the code a bit easier readable and searchable. Signed-off-by: Gertjan van Wingerde Signed-off-by: Ivo van Doorn Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/rt2x00/Kconfig b/drivers/net/wireless/rt2x00/Kconfig index d7e27b3..c457731 100644 --- a/drivers/net/wireless/rt2x00/Kconfig +++ b/drivers/net/wireless/rt2x00/Kconfig @@ -59,7 +59,6 @@ config RT2800PCI select RT2800_LIB select RT2X00_LIB_PCI if PCI select RT2X00_LIB_SOC if RALINK_RT288X || RALINK_RT305X - select RT2X00_LIB_HT select RT2X00_LIB_FIRMWARE select RT2X00_LIB_CRYPTO select CRC_CCITT @@ -133,7 +132,6 @@ config RT2800USB depends on USB select RT2800_LIB select RT2X00_LIB_USB - select RT2X00_LIB_HT select RT2X00_LIB_FIRMWARE select RT2X00_LIB_CRYPTO select CRC_CCITT @@ -196,9 +194,6 @@ config RT2X00_LIB_USB config RT2X00_LIB tristate -config RT2X00_LIB_HT - boolean - config RT2X00_LIB_FIRMWARE boolean select FW_LOADER diff --git a/drivers/net/wireless/rt2x00/Makefile b/drivers/net/wireless/rt2x00/Makefile index 9713398..349d5b8 100644 --- a/drivers/net/wireless/rt2x00/Makefile +++ b/drivers/net/wireless/rt2x00/Makefile @@ -7,7 +7,6 @@ rt2x00lib-$(CONFIG_RT2X00_LIB_DEBUGFS) += rt2x00debug.o rt2x00lib-$(CONFIG_RT2X00_LIB_CRYPTO) += rt2x00crypto.o rt2x00lib-$(CONFIG_RT2X00_LIB_FIRMWARE) += rt2x00firmware.o rt2x00lib-$(CONFIG_RT2X00_LIB_LEDS) += rt2x00leds.o -rt2x00lib-$(CONFIG_RT2X00_LIB_HT) += rt2x00ht.o obj-$(CONFIG_RT2X00_LIB) += rt2x00lib.o obj-$(CONFIG_RT2X00_LIB_PCI) += rt2x00pci.o diff --git a/drivers/net/wireless/rt2x00/rt2x00config.c b/drivers/net/wireless/rt2x00/rt2x00config.c index e225a66..f70a2b4 100644 --- a/drivers/net/wireless/rt2x00/rt2x00config.c +++ b/drivers/net/wireless/rt2x00/rt2x00config.c @@ -163,6 +163,34 @@ void rt2x00lib_config_antenna(struct rt2x00_dev *rt2x00dev, rt2x00queue_start_queue(rt2x00dev->rx); } +static u16 rt2x00ht_center_channel(struct rt2x00_dev *rt2x00dev, + struct ieee80211_conf *conf) +{ + struct hw_mode_spec *spec = &rt2x00dev->spec; + int center_channel; + u16 i; + + /* + * Initialize center channel to current channel. + */ + center_channel = spec->channels[conf->channel->hw_value].channel; + + /* + * Adjust center channel to HT40+ and HT40- operation. + */ + if (conf_is_ht40_plus(conf)) + center_channel += 2; + else if (conf_is_ht40_minus(conf)) + center_channel -= (center_channel == 14) ? 1 : 2; + + for (i = 0; i < spec->num_channels; i++) + if (spec->channels[i].channel == center_channel) + return i; + + WARN_ON(1); + return conf->channel->hw_value; +} + void rt2x00lib_config(struct rt2x00_dev *rt2x00dev, struct ieee80211_conf *conf, unsigned int ieee80211_flags) diff --git a/drivers/net/wireless/rt2x00/rt2x00ht.c b/drivers/net/wireless/rt2x00/rt2x00ht.c deleted file mode 100644 index a30f68c..0000000 --- a/drivers/net/wireless/rt2x00/rt2x00ht.c +++ /dev/null @@ -1,137 +0,0 @@ -/* - Copyright (C) 2004 - 2009 Ivo van Doorn - - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the - Free Software Foundation, Inc., - 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -/* - Module: rt2x00lib - Abstract: rt2x00 HT specific routines. - */ - -#include -#include - -#include "rt2x00.h" -#include "rt2x00lib.h" - -void rt2x00ht_create_tx_descriptor(struct queue_entry *entry, - struct txentry_desc *txdesc, - const struct rt2x00_rate *hwrate) -{ - struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(entry->skb); - struct ieee80211_tx_rate *txrate = &tx_info->control.rates[0]; - struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)entry->skb->data; - - if (tx_info->control.sta) - txdesc->u.ht.mpdu_density = - tx_info->control.sta->ht_cap.ampdu_density; - - txdesc->u.ht.ba_size = 7; /* FIXME: What value is needed? */ - - /* - * Only one STBC stream is supported for now. - */ - if (tx_info->flags & IEEE80211_TX_CTL_STBC) - txdesc->u.ht.stbc = 1; - - /* - * If IEEE80211_TX_RC_MCS is set txrate->idx just contains the - * mcs rate to be used - */ - if (txrate->flags & IEEE80211_TX_RC_MCS) { - txdesc->u.ht.mcs = txrate->idx; - - /* - * MIMO PS should be set to 1 for STA's using dynamic SM PS - * when using more then one tx stream (>MCS7). - */ - if (tx_info->control.sta && txdesc->u.ht.mcs > 7 && - ((tx_info->control.sta->ht_cap.cap & - IEEE80211_HT_CAP_SM_PS) >> - IEEE80211_HT_CAP_SM_PS_SHIFT) == - WLAN_HT_CAP_SM_PS_DYNAMIC) - __set_bit(ENTRY_TXD_HT_MIMO_PS, &txdesc->flags); - } else { - txdesc->u.ht.mcs = rt2x00_get_rate_mcs(hwrate->mcs); - if (txrate->flags & IEEE80211_TX_RC_USE_SHORT_PREAMBLE) - txdesc->u.ht.mcs |= 0x08; - } - - /* - * This frame is eligible for an AMPDU, however, don't aggregate - * frames that are intended to probe a specific tx rate. - */ - if (tx_info->flags & IEEE80211_TX_CTL_AMPDU && - !(tx_info->flags & IEEE80211_TX_CTL_RATE_CTRL_PROBE)) - __set_bit(ENTRY_TXD_HT_AMPDU, &txdesc->flags); - - /* - * Set 40Mhz mode if necessary (for legacy rates this will - * duplicate the frame to both channels). - */ - if (txrate->flags & IEEE80211_TX_RC_40_MHZ_WIDTH || - txrate->flags & IEEE80211_TX_RC_DUP_DATA) - __set_bit(ENTRY_TXD_HT_BW_40, &txdesc->flags); - if (txrate->flags & IEEE80211_TX_RC_SHORT_GI) - __set_bit(ENTRY_TXD_HT_SHORT_GI, &txdesc->flags); - - /* - * Determine IFS values - * - Use TXOP_BACKOFF for management frames except beacons - * - Use TXOP_SIFS for fragment bursts - * - Use TXOP_HTTXOP for everything else - * - * Note: rt2800 devices won't use CTS protection (if used) - * for frames not transmitted with TXOP_HTTXOP - */ - if (ieee80211_is_mgmt(hdr->frame_control) && - !ieee80211_is_beacon(hdr->frame_control)) - txdesc->u.ht.txop = TXOP_BACKOFF; - else if (!(tx_info->flags & IEEE80211_TX_CTL_FIRST_FRAGMENT)) - txdesc->u.ht.txop = TXOP_SIFS; - else - txdesc->u.ht.txop = TXOP_HTTXOP; -} - -u16 rt2x00ht_center_channel(struct rt2x00_dev *rt2x00dev, - struct ieee80211_conf *conf) -{ - struct hw_mode_spec *spec = &rt2x00dev->spec; - int center_channel; - u16 i; - - /* - * Initialize center channel to current channel. - */ - center_channel = spec->channels[conf->channel->hw_value].channel; - - /* - * Adjust center channel to HT40+ and HT40- operation. - */ - if (conf_is_ht40_plus(conf)) - center_channel += 2; - else if (conf_is_ht40_minus(conf)) - center_channel -= (center_channel == 14) ? 1 : 2; - - for (i = 0; i < spec->num_channels; i++) - if (spec->channels[i].channel == center_channel) - return i; - - WARN_ON(1); - return conf->channel->hw_value; -} diff --git a/drivers/net/wireless/rt2x00/rt2x00lib.h b/drivers/net/wireless/rt2x00/rt2x00lib.h index 57ede6c..322cc4f 100644 --- a/drivers/net/wireless/rt2x00/rt2x00lib.h +++ b/drivers/net/wireless/rt2x00/rt2x00lib.h @@ -388,30 +388,6 @@ static inline void rt2x00crypto_rx_insert_iv(struct sk_buff *skb, #endif /* CONFIG_RT2X00_LIB_CRYPTO */ /* - * HT handlers. - */ -#ifdef CONFIG_RT2X00_LIB_HT -void rt2x00ht_create_tx_descriptor(struct queue_entry *entry, - struct txentry_desc *txdesc, - const struct rt2x00_rate *hwrate); - -u16 rt2x00ht_center_channel(struct rt2x00_dev *rt2x00dev, - struct ieee80211_conf *conf); -#else -static inline void rt2x00ht_create_tx_descriptor(struct queue_entry *entry, - struct txentry_desc *txdesc, - const struct rt2x00_rate *hwrate) -{ -} - -static inline u16 rt2x00ht_center_channel(struct rt2x00_dev *rt2x00dev, - struct ieee80211_conf *conf) -{ - return conf->channel->hw_value; -} -#endif /* CONFIG_RT2X00_LIB_HT */ - -/* * RFkill handlers. */ static inline void rt2x00rfkill_register(struct rt2x00_dev *rt2x00dev) diff --git a/drivers/net/wireless/rt2x00/rt2x00queue.c b/drivers/net/wireless/rt2x00/rt2x00queue.c index 0d79278..56f9d0d 100644 --- a/drivers/net/wireless/rt2x00/rt2x00queue.c +++ b/drivers/net/wireless/rt2x00/rt2x00queue.c @@ -302,6 +302,85 @@ static void rt2x00queue_create_tx_descriptor_plcp(struct queue_entry *entry, } } +static void rt2x00queue_create_tx_descriptor_ht(struct queue_entry *entry, + struct txentry_desc *txdesc, + const struct rt2x00_rate *hwrate) +{ + struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(entry->skb); + struct ieee80211_tx_rate *txrate = &tx_info->control.rates[0]; + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)entry->skb->data; + + if (tx_info->control.sta) + txdesc->u.ht.mpdu_density = + tx_info->control.sta->ht_cap.ampdu_density; + + txdesc->u.ht.ba_size = 7; /* FIXME: What value is needed? */ + + /* + * Only one STBC stream is supported for now. + */ + if (tx_info->flags & IEEE80211_TX_CTL_STBC) + txdesc->u.ht.stbc = 1; + + /* + * If IEEE80211_TX_RC_MCS is set txrate->idx just contains the + * mcs rate to be used + */ + if (txrate->flags & IEEE80211_TX_RC_MCS) { + txdesc->u.ht.mcs = txrate->idx; + + /* + * MIMO PS should be set to 1 for STA's using dynamic SM PS + * when using more then one tx stream (>MCS7). + */ + if (tx_info->control.sta && txdesc->u.ht.mcs > 7 && + ((tx_info->control.sta->ht_cap.cap & + IEEE80211_HT_CAP_SM_PS) >> + IEEE80211_HT_CAP_SM_PS_SHIFT) == + WLAN_HT_CAP_SM_PS_DYNAMIC) + __set_bit(ENTRY_TXD_HT_MIMO_PS, &txdesc->flags); + } else { + txdesc->u.ht.mcs = rt2x00_get_rate_mcs(hwrate->mcs); + if (txrate->flags & IEEE80211_TX_RC_USE_SHORT_PREAMBLE) + txdesc->u.ht.mcs |= 0x08; + } + + /* + * This frame is eligible for an AMPDU, however, don't aggregate + * frames that are intended to probe a specific tx rate. + */ + if (tx_info->flags & IEEE80211_TX_CTL_AMPDU && + !(tx_info->flags & IEEE80211_TX_CTL_RATE_CTRL_PROBE)) + __set_bit(ENTRY_TXD_HT_AMPDU, &txdesc->flags); + + /* + * Set 40Mhz mode if necessary (for legacy rates this will + * duplicate the frame to both channels). + */ + if (txrate->flags & IEEE80211_TX_RC_40_MHZ_WIDTH || + txrate->flags & IEEE80211_TX_RC_DUP_DATA) + __set_bit(ENTRY_TXD_HT_BW_40, &txdesc->flags); + if (txrate->flags & IEEE80211_TX_RC_SHORT_GI) + __set_bit(ENTRY_TXD_HT_SHORT_GI, &txdesc->flags); + + /* + * Determine IFS values + * - Use TXOP_BACKOFF for management frames except beacons + * - Use TXOP_SIFS for fragment bursts + * - Use TXOP_HTTXOP for everything else + * + * Note: rt2800 devices won't use CTS protection (if used) + * for frames not transmitted with TXOP_HTTXOP + */ + if (ieee80211_is_mgmt(hdr->frame_control) && + !ieee80211_is_beacon(hdr->frame_control)) + txdesc->u.ht.txop = TXOP_BACKOFF; + else if (!(tx_info->flags & IEEE80211_TX_CTL_FIRST_FRAGMENT)) + txdesc->u.ht.txop = TXOP_SIFS; + else + txdesc->u.ht.txop = TXOP_HTTXOP; +} + static void rt2x00queue_create_tx_descriptor(struct queue_entry *entry, struct txentry_desc *txdesc) { @@ -397,7 +476,7 @@ static void rt2x00queue_create_tx_descriptor(struct queue_entry *entry, rt2x00queue_create_tx_descriptor_seq(entry, txdesc); if (test_bit(REQUIRE_HT_TX_DESC, &rt2x00dev->cap_flags)) - rt2x00ht_create_tx_descriptor(entry, txdesc, hwrate); + rt2x00queue_create_tx_descriptor_ht(entry, txdesc, hwrate); else rt2x00queue_create_tx_descriptor_plcp(entry, txdesc, hwrate); } -- cgit v0.10.2 From 9a8199961b22e61221a6114b8bbbc26ddcc243f7 Mon Sep 17 00:00:00 2001 From: Helmut Schaa Date: Mon, 18 Apr 2011 15:34:01 +0200 Subject: rt2x00: Optimize register access in rt2800pci All register reads/writes in rt2800pci were previously done with rt2800_register_read/rt2800_register_write. These however indirectly call rt2x00pci_register_read/rt2x00pci_register_write which adds an additional overhead of at least one call and several move instructions to each register access. Replacing the calls to rt2800_register_read/rt2800_register_write with direct calls to rt2x00pci_register_read/rt2x00pci_register_write gets rid of quite a number of instructions in the drivers hotpaths (IRQ handling and txdone handling). For consistency replace all references to rt2800_register_read/write with the rt2x00pci_register_read/write variants. Signed-off-by: Helmut Schaa Signed-off-by: Ivo van Doorn Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/rt2x00/rt2800pci.c b/drivers/net/wireless/rt2x00/rt2800pci.c index 6f91a9a..b0c729b 100644 --- a/drivers/net/wireless/rt2x00/rt2800pci.c +++ b/drivers/net/wireless/rt2x00/rt2800pci.c @@ -66,7 +66,7 @@ static void rt2800pci_mcu_status(struct rt2x00_dev *rt2x00dev, const u8 token) return; for (i = 0; i < 200; i++) { - rt2800_register_read(rt2x00dev, H2M_MAILBOX_CID, ®); + rt2x00pci_register_read(rt2x00dev, H2M_MAILBOX_CID, ®); if ((rt2x00_get_field32(reg, H2M_MAILBOX_CID_CMD0) == token) || (rt2x00_get_field32(reg, H2M_MAILBOX_CID_CMD1) == token) || @@ -80,8 +80,8 @@ static void rt2800pci_mcu_status(struct rt2x00_dev *rt2x00dev, const u8 token) if (i == 200) ERROR(rt2x00dev, "MCU request failed, no response from hardware\n"); - rt2800_register_write(rt2x00dev, H2M_MAILBOX_STATUS, ~0); - rt2800_register_write(rt2x00dev, H2M_MAILBOX_CID, ~0); + rt2x00pci_register_write(rt2x00dev, H2M_MAILBOX_STATUS, ~0); + rt2x00pci_register_write(rt2x00dev, H2M_MAILBOX_CID, ~0); } #if defined(CONFIG_RALINK_RT288X) || defined(CONFIG_RALINK_RT305X) @@ -105,7 +105,7 @@ static void rt2800pci_eepromregister_read(struct eeprom_93cx6 *eeprom) struct rt2x00_dev *rt2x00dev = eeprom->data; u32 reg; - rt2800_register_read(rt2x00dev, E2PROM_CSR, ®); + rt2x00pci_register_read(rt2x00dev, E2PROM_CSR, ®); eeprom->reg_data_in = !!rt2x00_get_field32(reg, E2PROM_CSR_DATA_IN); eeprom->reg_data_out = !!rt2x00_get_field32(reg, E2PROM_CSR_DATA_OUT); @@ -127,7 +127,7 @@ static void rt2800pci_eepromregister_write(struct eeprom_93cx6 *eeprom) rt2x00_set_field32(®, E2PROM_CSR_CHIP_SELECT, !!eeprom->reg_chip_select); - rt2800_register_write(rt2x00dev, E2PROM_CSR, reg); + rt2x00pci_register_write(rt2x00dev, E2PROM_CSR, reg); } static void rt2800pci_read_eeprom_pci(struct rt2x00_dev *rt2x00dev) @@ -135,7 +135,7 @@ static void rt2800pci_read_eeprom_pci(struct rt2x00_dev *rt2x00dev) struct eeprom_93cx6 eeprom; u32 reg; - rt2800_register_read(rt2x00dev, E2PROM_CSR, ®); + rt2x00pci_register_read(rt2x00dev, E2PROM_CSR, ®); eeprom.data = rt2x00dev; eeprom.register_read = rt2800pci_eepromregister_read; @@ -195,9 +195,9 @@ static void rt2800pci_start_queue(struct data_queue *queue) switch (queue->qid) { case QID_RX: - rt2800_register_read(rt2x00dev, MAC_SYS_CTRL, ®); + rt2x00pci_register_read(rt2x00dev, MAC_SYS_CTRL, ®); rt2x00_set_field32(®, MAC_SYS_CTRL_ENABLE_RX, 1); - rt2800_register_write(rt2x00dev, MAC_SYS_CTRL, reg); + rt2x00pci_register_write(rt2x00dev, MAC_SYS_CTRL, reg); break; case QID_BEACON: /* @@ -207,15 +207,15 @@ static void rt2800pci_start_queue(struct data_queue *queue) tasklet_enable(&rt2x00dev->tbtt_tasklet); tasklet_enable(&rt2x00dev->pretbtt_tasklet); - rt2800_register_read(rt2x00dev, BCN_TIME_CFG, ®); + rt2x00pci_register_read(rt2x00dev, BCN_TIME_CFG, ®); rt2x00_set_field32(®, BCN_TIME_CFG_TSF_TICKING, 1); rt2x00_set_field32(®, BCN_TIME_CFG_TBTT_ENABLE, 1); rt2x00_set_field32(®, BCN_TIME_CFG_BEACON_GEN, 1); - rt2800_register_write(rt2x00dev, BCN_TIME_CFG, reg); + rt2x00pci_register_write(rt2x00dev, BCN_TIME_CFG, reg); - rt2800_register_read(rt2x00dev, INT_TIMER_EN, ®); + rt2x00pci_register_read(rt2x00dev, INT_TIMER_EN, ®); rt2x00_set_field32(®, INT_TIMER_EN_PRE_TBTT_TIMER, 1); - rt2800_register_write(rt2x00dev, INT_TIMER_EN, reg); + rt2x00pci_register_write(rt2x00dev, INT_TIMER_EN, reg); break; default: break; @@ -233,11 +233,13 @@ static void rt2800pci_kick_queue(struct data_queue *queue) case QID_AC_BE: case QID_AC_BK: entry = rt2x00queue_get_entry(queue, Q_INDEX); - rt2800_register_write(rt2x00dev, TX_CTX_IDX(queue->qid), entry->entry_idx); + rt2x00pci_register_write(rt2x00dev, TX_CTX_IDX(queue->qid), + entry->entry_idx); break; case QID_MGMT: entry = rt2x00queue_get_entry(queue, Q_INDEX); - rt2800_register_write(rt2x00dev, TX_CTX_IDX(5), entry->entry_idx); + rt2x00pci_register_write(rt2x00dev, TX_CTX_IDX(5), + entry->entry_idx); break; default: break; @@ -251,20 +253,20 @@ static void rt2800pci_stop_queue(struct data_queue *queue) switch (queue->qid) { case QID_RX: - rt2800_register_read(rt2x00dev, MAC_SYS_CTRL, ®); + rt2x00pci_register_read(rt2x00dev, MAC_SYS_CTRL, ®); rt2x00_set_field32(®, MAC_SYS_CTRL_ENABLE_RX, 0); - rt2800_register_write(rt2x00dev, MAC_SYS_CTRL, reg); + rt2x00pci_register_write(rt2x00dev, MAC_SYS_CTRL, reg); break; case QID_BEACON: - rt2800_register_read(rt2x00dev, BCN_TIME_CFG, ®); + rt2x00pci_register_read(rt2x00dev, BCN_TIME_CFG, ®); rt2x00_set_field32(®, BCN_TIME_CFG_TSF_TICKING, 0); rt2x00_set_field32(®, BCN_TIME_CFG_TBTT_ENABLE, 0); rt2x00_set_field32(®, BCN_TIME_CFG_BEACON_GEN, 0); - rt2800_register_write(rt2x00dev, BCN_TIME_CFG, reg); + rt2x00pci_register_write(rt2x00dev, BCN_TIME_CFG, reg); - rt2800_register_read(rt2x00dev, INT_TIMER_EN, ®); + rt2x00pci_register_read(rt2x00dev, INT_TIMER_EN, ®); rt2x00_set_field32(®, INT_TIMER_EN_PRE_TBTT_TIMER, 0); - rt2800_register_write(rt2x00dev, INT_TIMER_EN, reg); + rt2x00pci_register_write(rt2x00dev, INT_TIMER_EN, reg); /* * Wait for tbtt tasklets to finish. @@ -295,7 +297,7 @@ static int rt2800pci_write_firmware(struct rt2x00_dev *rt2x00dev, */ reg = 0; rt2x00_set_field32(®, PBF_SYS_CTRL_HOST_RAM_WRITE, 1); - rt2800_register_write(rt2x00dev, PBF_SYS_CTRL, reg); + rt2x00pci_register_write(rt2x00dev, PBF_SYS_CTRL, reg); /* * Write firmware to device. @@ -303,11 +305,11 @@ static int rt2800pci_write_firmware(struct rt2x00_dev *rt2x00dev, rt2800_register_multiwrite(rt2x00dev, FIRMWARE_IMAGE_BASE, data, len); - rt2800_register_write(rt2x00dev, PBF_SYS_CTRL, 0x00000); - rt2800_register_write(rt2x00dev, PBF_SYS_CTRL, 0x00001); + rt2x00pci_register_write(rt2x00dev, PBF_SYS_CTRL, 0x00000); + rt2x00pci_register_write(rt2x00dev, PBF_SYS_CTRL, 0x00001); - rt2800_register_write(rt2x00dev, H2M_BBP_AGENT, 0); - rt2800_register_write(rt2x00dev, H2M_MAILBOX_CSR, 0); + rt2x00pci_register_write(rt2x00dev, H2M_BBP_AGENT, 0); + rt2x00pci_register_write(rt2x00dev, H2M_MAILBOX_CSR, 0); return 0; } @@ -351,7 +353,7 @@ static void rt2800pci_clear_entry(struct queue_entry *entry) * Set RX IDX in register to inform hardware that we have * handled this entry and it is available for reuse again. */ - rt2800_register_write(rt2x00dev, RX_CRX_IDX, + rt2x00pci_register_write(rt2x00dev, RX_CRX_IDX, entry->entry_idx); } else { rt2x00_desc_read(entry_priv->desc, 1, &word); @@ -369,45 +371,51 @@ static int rt2800pci_init_queues(struct rt2x00_dev *rt2x00dev) * Initialize registers. */ entry_priv = rt2x00dev->tx[0].entries[0].priv_data; - rt2800_register_write(rt2x00dev, TX_BASE_PTR0, entry_priv->desc_dma); - rt2800_register_write(rt2x00dev, TX_MAX_CNT0, rt2x00dev->tx[0].limit); - rt2800_register_write(rt2x00dev, TX_CTX_IDX0, 0); - rt2800_register_write(rt2x00dev, TX_DTX_IDX0, 0); + rt2x00pci_register_write(rt2x00dev, TX_BASE_PTR0, entry_priv->desc_dma); + rt2x00pci_register_write(rt2x00dev, TX_MAX_CNT0, + rt2x00dev->tx[0].limit); + rt2x00pci_register_write(rt2x00dev, TX_CTX_IDX0, 0); + rt2x00pci_register_write(rt2x00dev, TX_DTX_IDX0, 0); entry_priv = rt2x00dev->tx[1].entries[0].priv_data; - rt2800_register_write(rt2x00dev, TX_BASE_PTR1, entry_priv->desc_dma); - rt2800_register_write(rt2x00dev, TX_MAX_CNT1, rt2x00dev->tx[1].limit); - rt2800_register_write(rt2x00dev, TX_CTX_IDX1, 0); - rt2800_register_write(rt2x00dev, TX_DTX_IDX1, 0); + rt2x00pci_register_write(rt2x00dev, TX_BASE_PTR1, entry_priv->desc_dma); + rt2x00pci_register_write(rt2x00dev, TX_MAX_CNT1, + rt2x00dev->tx[1].limit); + rt2x00pci_register_write(rt2x00dev, TX_CTX_IDX1, 0); + rt2x00pci_register_write(rt2x00dev, TX_DTX_IDX1, 0); entry_priv = rt2x00dev->tx[2].entries[0].priv_data; - rt2800_register_write(rt2x00dev, TX_BASE_PTR2, entry_priv->desc_dma); - rt2800_register_write(rt2x00dev, TX_MAX_CNT2, rt2x00dev->tx[2].limit); - rt2800_register_write(rt2x00dev, TX_CTX_IDX2, 0); - rt2800_register_write(rt2x00dev, TX_DTX_IDX2, 0); + rt2x00pci_register_write(rt2x00dev, TX_BASE_PTR2, entry_priv->desc_dma); + rt2x00pci_register_write(rt2x00dev, TX_MAX_CNT2, + rt2x00dev->tx[2].limit); + rt2x00pci_register_write(rt2x00dev, TX_CTX_IDX2, 0); + rt2x00pci_register_write(rt2x00dev, TX_DTX_IDX2, 0); entry_priv = rt2x00dev->tx[3].entries[0].priv_data; - rt2800_register_write(rt2x00dev, TX_BASE_PTR3, entry_priv->desc_dma); - rt2800_register_write(rt2x00dev, TX_MAX_CNT3, rt2x00dev->tx[3].limit); - rt2800_register_write(rt2x00dev, TX_CTX_IDX3, 0); - rt2800_register_write(rt2x00dev, TX_DTX_IDX3, 0); + rt2x00pci_register_write(rt2x00dev, TX_BASE_PTR3, entry_priv->desc_dma); + rt2x00pci_register_write(rt2x00dev, TX_MAX_CNT3, + rt2x00dev->tx[3].limit); + rt2x00pci_register_write(rt2x00dev, TX_CTX_IDX3, 0); + rt2x00pci_register_write(rt2x00dev, TX_DTX_IDX3, 0); entry_priv = rt2x00dev->rx->entries[0].priv_data; - rt2800_register_write(rt2x00dev, RX_BASE_PTR, entry_priv->desc_dma); - rt2800_register_write(rt2x00dev, RX_MAX_CNT, rt2x00dev->rx[0].limit); - rt2800_register_write(rt2x00dev, RX_CRX_IDX, rt2x00dev->rx[0].limit - 1); - rt2800_register_write(rt2x00dev, RX_DRX_IDX, 0); + rt2x00pci_register_write(rt2x00dev, RX_BASE_PTR, entry_priv->desc_dma); + rt2x00pci_register_write(rt2x00dev, RX_MAX_CNT, + rt2x00dev->rx[0].limit); + rt2x00pci_register_write(rt2x00dev, RX_CRX_IDX, + rt2x00dev->rx[0].limit - 1); + rt2x00pci_register_write(rt2x00dev, RX_DRX_IDX, 0); /* * Enable global DMA configuration */ - rt2800_register_read(rt2x00dev, WPDMA_GLO_CFG, ®); + rt2x00pci_register_read(rt2x00dev, WPDMA_GLO_CFG, ®); rt2x00_set_field32(®, WPDMA_GLO_CFG_ENABLE_TX_DMA, 0); rt2x00_set_field32(®, WPDMA_GLO_CFG_ENABLE_RX_DMA, 0); rt2x00_set_field32(®, WPDMA_GLO_CFG_TX_WRITEBACK_DONE, 1); - rt2800_register_write(rt2x00dev, WPDMA_GLO_CFG, reg); + rt2x00pci_register_write(rt2x00dev, WPDMA_GLO_CFG, reg); - rt2800_register_write(rt2x00dev, DELAY_INT_CFG, 0); + rt2x00pci_register_write(rt2x00dev, DELAY_INT_CFG, 0); return 0; } @@ -427,8 +435,8 @@ static void rt2800pci_toggle_irq(struct rt2x00_dev *rt2x00dev, * should clear the register to assure a clean state. */ if (state == STATE_RADIO_IRQ_ON) { - rt2800_register_read(rt2x00dev, INT_SOURCE_CSR, ®); - rt2800_register_write(rt2x00dev, INT_SOURCE_CSR, reg); + rt2x00pci_register_read(rt2x00dev, INT_SOURCE_CSR, ®); + rt2x00pci_register_write(rt2x00dev, INT_SOURCE_CSR, reg); /* * Enable tasklets. The beacon related tasklets are @@ -440,7 +448,7 @@ static void rt2800pci_toggle_irq(struct rt2x00_dev *rt2x00dev, } spin_lock_irqsave(&rt2x00dev->irqmask_lock, flags); - rt2800_register_read(rt2x00dev, INT_MASK_CSR, ®); + rt2x00pci_register_read(rt2x00dev, INT_MASK_CSR, ®); rt2x00_set_field32(®, INT_MASK_CSR_RXDELAYINT, 0); rt2x00_set_field32(®, INT_MASK_CSR_TXDELAYINT, 0); rt2x00_set_field32(®, INT_MASK_CSR_RX_DONE, mask); @@ -459,7 +467,7 @@ static void rt2800pci_toggle_irq(struct rt2x00_dev *rt2x00dev, rt2x00_set_field32(®, INT_MASK_CSR_GPTIMER, 0); rt2x00_set_field32(®, INT_MASK_CSR_RX_COHERENT, 0); rt2x00_set_field32(®, INT_MASK_CSR_TX_COHERENT, 0); - rt2800_register_write(rt2x00dev, INT_MASK_CSR, reg); + rt2x00pci_register_write(rt2x00dev, INT_MASK_CSR, reg); spin_unlock_irqrestore(&rt2x00dev->irqmask_lock, flags); if (state == STATE_RADIO_IRQ_OFF) { @@ -480,7 +488,7 @@ static int rt2800pci_init_registers(struct rt2x00_dev *rt2x00dev) /* * Reset DMA indexes */ - rt2800_register_read(rt2x00dev, WPDMA_RST_IDX, ®); + rt2x00pci_register_read(rt2x00dev, WPDMA_RST_IDX, ®); rt2x00_set_field32(®, WPDMA_RST_IDX_DTX_IDX0, 1); rt2x00_set_field32(®, WPDMA_RST_IDX_DTX_IDX1, 1); rt2x00_set_field32(®, WPDMA_RST_IDX_DTX_IDX2, 1); @@ -488,26 +496,26 @@ static int rt2800pci_init_registers(struct rt2x00_dev *rt2x00dev) rt2x00_set_field32(®, WPDMA_RST_IDX_DTX_IDX4, 1); rt2x00_set_field32(®, WPDMA_RST_IDX_DTX_IDX5, 1); rt2x00_set_field32(®, WPDMA_RST_IDX_DRX_IDX0, 1); - rt2800_register_write(rt2x00dev, WPDMA_RST_IDX, reg); + rt2x00pci_register_write(rt2x00dev, WPDMA_RST_IDX, reg); - rt2800_register_write(rt2x00dev, PBF_SYS_CTRL, 0x00000e1f); - rt2800_register_write(rt2x00dev, PBF_SYS_CTRL, 0x00000e00); + rt2x00pci_register_write(rt2x00dev, PBF_SYS_CTRL, 0x00000e1f); + rt2x00pci_register_write(rt2x00dev, PBF_SYS_CTRL, 0x00000e00); if (rt2x00_rt(rt2x00dev, RT5390)) { - rt2800_register_read(rt2x00dev, AUX_CTRL, ®); + rt2x00pci_register_read(rt2x00dev, AUX_CTRL, ®); rt2x00_set_field32(®, AUX_CTRL_FORCE_PCIE_CLK, 1); rt2x00_set_field32(®, AUX_CTRL_WAKE_PCIE_EN, 1); - rt2800_register_write(rt2x00dev, AUX_CTRL, reg); + rt2x00pci_register_write(rt2x00dev, AUX_CTRL, reg); } - rt2800_register_write(rt2x00dev, PWR_PIN_CFG, 0x00000003); + rt2x00pci_register_write(rt2x00dev, PWR_PIN_CFG, 0x00000003); - rt2800_register_read(rt2x00dev, MAC_SYS_CTRL, ®); + rt2x00pci_register_read(rt2x00dev, MAC_SYS_CTRL, ®); rt2x00_set_field32(®, MAC_SYS_CTRL_RESET_CSR, 1); rt2x00_set_field32(®, MAC_SYS_CTRL_RESET_BBP, 1); - rt2800_register_write(rt2x00dev, MAC_SYS_CTRL, reg); + rt2x00pci_register_write(rt2x00dev, MAC_SYS_CTRL, reg); - rt2800_register_write(rt2x00dev, MAC_SYS_CTRL, 0x00000000); + rt2x00pci_register_write(rt2x00dev, MAC_SYS_CTRL, 0x00000000); return 0; } @@ -525,8 +533,8 @@ static void rt2800pci_disable_radio(struct rt2x00_dev *rt2x00dev) { if (rt2x00_is_soc(rt2x00dev)) { rt2800_disable_radio(rt2x00dev); - rt2800_register_write(rt2x00dev, PWR_PIN_CFG, 0); - rt2800_register_write(rt2x00dev, TX_PIN_CFG, 0); + rt2x00pci_register_write(rt2x00dev, PWR_PIN_CFG, 0); + rt2x00pci_register_write(rt2x00dev, TX_PIN_CFG, 0); } } @@ -537,8 +545,10 @@ static int rt2800pci_set_state(struct rt2x00_dev *rt2x00dev, rt2800_mcu_request(rt2x00dev, MCU_WAKEUP, TOKEN_WAKUP, 0, 0x02); rt2800pci_mcu_status(rt2x00dev, TOKEN_WAKUP); } else if (state == STATE_SLEEP) { - rt2800_register_write(rt2x00dev, H2M_MAILBOX_STATUS, 0xffffffff); - rt2800_register_write(rt2x00dev, H2M_MAILBOX_CID, 0xffffffff); + rt2x00pci_register_write(rt2x00dev, H2M_MAILBOX_STATUS, + 0xffffffff); + rt2x00pci_register_write(rt2x00dev, H2M_MAILBOX_CID, + 0xffffffff); rt2800_mcu_request(rt2x00dev, MCU_SLEEP, 0x01, 0xff, 0x01); } @@ -778,9 +788,9 @@ static inline void rt2800pci_enable_interrupt(struct rt2x00_dev *rt2x00dev, * access needs locking. */ spin_lock_irq(&rt2x00dev->irqmask_lock); - rt2800_register_read(rt2x00dev, INT_MASK_CSR, ®); + rt2x00pci_register_read(rt2x00dev, INT_MASK_CSR, ®); rt2x00_set_field32(®, irq_field, 1); - rt2800_register_write(rt2x00dev, INT_MASK_CSR, reg); + rt2x00pci_register_write(rt2x00dev, INT_MASK_CSR, reg); spin_unlock_irq(&rt2x00dev->irqmask_lock); } @@ -851,7 +861,7 @@ static void rt2800pci_txstatus_interrupt(struct rt2x00_dev *rt2x00dev) * need to lock the kfifo. */ for (i = 0; i < rt2x00dev->ops->tx->entry_num; i++) { - rt2800_register_read(rt2x00dev, TX_STA_FIFO, &status); + rt2x00pci_register_read(rt2x00dev, TX_STA_FIFO, &status); if (!rt2x00_get_field32(status, TX_STA_FIFO_VALID)) break; @@ -873,8 +883,8 @@ static irqreturn_t rt2800pci_interrupt(int irq, void *dev_instance) u32 reg, mask; /* Read status and ACK all interrupts */ - rt2800_register_read(rt2x00dev, INT_SOURCE_CSR, ®); - rt2800_register_write(rt2x00dev, INT_SOURCE_CSR, reg); + rt2x00pci_register_read(rt2x00dev, INT_SOURCE_CSR, ®); + rt2x00pci_register_write(rt2x00dev, INT_SOURCE_CSR, reg); if (!reg) return IRQ_NONE; @@ -914,9 +924,9 @@ static irqreturn_t rt2800pci_interrupt(int irq, void *dev_instance) * the tasklet will reenable the appropriate interrupts. */ spin_lock(&rt2x00dev->irqmask_lock); - rt2800_register_read(rt2x00dev, INT_MASK_CSR, ®); + rt2x00pci_register_read(rt2x00dev, INT_MASK_CSR, ®); reg &= mask; - rt2800_register_write(rt2x00dev, INT_MASK_CSR, reg); + rt2x00pci_register_write(rt2x00dev, INT_MASK_CSR, reg); spin_unlock(&rt2x00dev->irqmask_lock); return IRQ_HANDLED; -- cgit v0.10.2 From 8d0a2dcfb6f965781cde6d9dfbd4540ab22a0eb9 Mon Sep 17 00:00:00 2001 From: Ivo van Doorn Date: Mon, 18 Apr 2011 15:34:22 +0200 Subject: rt2x00: Optimize register access in rt2800usb All register reads/writes in rt2800usb were previously done with rt2800_register_read/rt2800_register_write. These however indirectly call rt2x00usb_register_read/rt2x00usb_register_write which adds an additional overhead of at least one call and several move instructions to each register access. Replacing the calls to rt2800_register_read/rt2800_register_write with direct calls to rt2x00usb_register_read/rt2x00usb_register_write gets rid of quite a number of instructions in the drivers hotpaths (IRQ handling and txdone handling). For consistency replace all references to rt2800_register_read/write with the rt2x00usb_register_read/write variants. Signed-off-by: Ivo van Doorn Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/rt2x00/rt2800usb.c b/drivers/net/wireless/rt2x00/rt2800usb.c index fd8aa99..44ead75 100644 --- a/drivers/net/wireless/rt2x00/rt2800usb.c +++ b/drivers/net/wireless/rt2x00/rt2800usb.c @@ -59,16 +59,16 @@ static void rt2800usb_start_queue(struct data_queue *queue) switch (queue->qid) { case QID_RX: - rt2800_register_read(rt2x00dev, MAC_SYS_CTRL, ®); + rt2x00usb_register_read(rt2x00dev, MAC_SYS_CTRL, ®); rt2x00_set_field32(®, MAC_SYS_CTRL_ENABLE_RX, 1); - rt2800_register_write(rt2x00dev, MAC_SYS_CTRL, reg); + rt2x00usb_register_write(rt2x00dev, MAC_SYS_CTRL, reg); break; case QID_BEACON: - rt2800_register_read(rt2x00dev, BCN_TIME_CFG, ®); + rt2x00usb_register_read(rt2x00dev, BCN_TIME_CFG, ®); rt2x00_set_field32(®, BCN_TIME_CFG_TSF_TICKING, 1); rt2x00_set_field32(®, BCN_TIME_CFG_TBTT_ENABLE, 1); rt2x00_set_field32(®, BCN_TIME_CFG_BEACON_GEN, 1); - rt2800_register_write(rt2x00dev, BCN_TIME_CFG, reg); + rt2x00usb_register_write(rt2x00dev, BCN_TIME_CFG, reg); break; default: break; @@ -82,16 +82,16 @@ static void rt2800usb_stop_queue(struct data_queue *queue) switch (queue->qid) { case QID_RX: - rt2800_register_read(rt2x00dev, MAC_SYS_CTRL, ®); + rt2x00usb_register_read(rt2x00dev, MAC_SYS_CTRL, ®); rt2x00_set_field32(®, MAC_SYS_CTRL_ENABLE_RX, 0); - rt2800_register_write(rt2x00dev, MAC_SYS_CTRL, reg); + rt2x00usb_register_write(rt2x00dev, MAC_SYS_CTRL, reg); break; case QID_BEACON: - rt2800_register_read(rt2x00dev, BCN_TIME_CFG, ®); + rt2x00usb_register_read(rt2x00dev, BCN_TIME_CFG, ®); rt2x00_set_field32(®, BCN_TIME_CFG_TSF_TICKING, 0); rt2x00_set_field32(®, BCN_TIME_CFG_TBTT_ENABLE, 0); rt2x00_set_field32(®, BCN_TIME_CFG_BEACON_GEN, 0); - rt2800_register_write(rt2x00dev, BCN_TIME_CFG, reg); + rt2x00usb_register_write(rt2x00dev, BCN_TIME_CFG, reg); break; default: break; @@ -185,11 +185,11 @@ static int rt2800usb_write_firmware(struct rt2x00_dev *rt2x00dev, /* * Write firmware to device. */ - rt2800_register_multiwrite(rt2x00dev, FIRMWARE_IMAGE_BASE, - data + offset, length); + rt2x00usb_register_multiwrite(rt2x00dev, FIRMWARE_IMAGE_BASE, + data + offset, length); - rt2800_register_write(rt2x00dev, H2M_MAILBOX_CID, ~0); - rt2800_register_write(rt2x00dev, H2M_MAILBOX_STATUS, ~0); + rt2x00usb_register_write(rt2x00dev, H2M_MAILBOX_CID, ~0); + rt2x00usb_register_write(rt2x00dev, H2M_MAILBOX_STATUS, ~0); /* * Send firmware request to device to load firmware, @@ -204,7 +204,7 @@ static int rt2800usb_write_firmware(struct rt2x00_dev *rt2x00dev, } msleep(10); - rt2800_register_write(rt2x00dev, H2M_MAILBOX_CSR, 0); + rt2x00usb_register_write(rt2x00dev, H2M_MAILBOX_CSR, 0); return 0; } @@ -222,22 +222,22 @@ static int rt2800usb_init_registers(struct rt2x00_dev *rt2x00dev) if (rt2800_wait_csr_ready(rt2x00dev)) return -EBUSY; - rt2800_register_read(rt2x00dev, PBF_SYS_CTRL, ®); - rt2800_register_write(rt2x00dev, PBF_SYS_CTRL, reg & ~0x00002000); + rt2x00usb_register_read(rt2x00dev, PBF_SYS_CTRL, ®); + rt2x00usb_register_write(rt2x00dev, PBF_SYS_CTRL, reg & ~0x00002000); - rt2800_register_write(rt2x00dev, PWR_PIN_CFG, 0x00000003); + rt2x00usb_register_write(rt2x00dev, PWR_PIN_CFG, 0x00000003); - rt2800_register_read(rt2x00dev, MAC_SYS_CTRL, ®); + rt2x00usb_register_read(rt2x00dev, MAC_SYS_CTRL, ®); rt2x00_set_field32(®, MAC_SYS_CTRL_RESET_CSR, 1); rt2x00_set_field32(®, MAC_SYS_CTRL_RESET_BBP, 1); - rt2800_register_write(rt2x00dev, MAC_SYS_CTRL, reg); + rt2x00usb_register_write(rt2x00dev, MAC_SYS_CTRL, reg); - rt2800_register_write(rt2x00dev, USB_DMA_CFG, 0x00000000); + rt2x00usb_register_write(rt2x00dev, USB_DMA_CFG, 0x00000000); rt2x00usb_vendor_request_sw(rt2x00dev, USB_DEVICE_MODE, 0, USB_MODE_RESET, REGISTER_TIMEOUT); - rt2800_register_write(rt2x00dev, MAC_SYS_CTRL, 0x00000000); + rt2x00usb_register_write(rt2x00dev, MAC_SYS_CTRL, 0x00000000); return 0; } @@ -249,7 +249,7 @@ static int rt2800usb_enable_radio(struct rt2x00_dev *rt2x00dev) if (unlikely(rt2800_wait_wpdma_ready(rt2x00dev))) return -EIO; - rt2800_register_read(rt2x00dev, USB_DMA_CFG, ®); + rt2x00usb_register_read(rt2x00dev, USB_DMA_CFG, ®); rt2x00_set_field32(®, USB_DMA_CFG_PHY_CLEAR, 0); rt2x00_set_field32(®, USB_DMA_CFG_RX_BULK_AGG_EN, 0); rt2x00_set_field32(®, USB_DMA_CFG_RX_BULK_AGG_TIMEOUT, 128); @@ -262,7 +262,7 @@ static int rt2800usb_enable_radio(struct rt2x00_dev *rt2x00dev) / 1024) - 3); rt2x00_set_field32(®, USB_DMA_CFG_RX_BULK_EN, 1); rt2x00_set_field32(®, USB_DMA_CFG_TX_BULK_EN, 1); - rt2800_register_write(rt2x00dev, USB_DMA_CFG, reg); + rt2x00usb_register_write(rt2x00dev, USB_DMA_CFG, reg); return rt2800_enable_radio(rt2x00dev); } @@ -338,12 +338,12 @@ static void rt2800usb_watchdog(struct rt2x00_dev *rt2x00dev) unsigned int i; u32 reg; - rt2800_register_read(rt2x00dev, TXRXQ_PCNT, ®); + rt2x00usb_register_read(rt2x00dev, TXRXQ_PCNT, ®); if (rt2x00_get_field32(reg, TXRXQ_PCNT_TX0Q)) { WARNING(rt2x00dev, "TX HW queue 0 timed out," " invoke forced kick\n"); - rt2800_register_write(rt2x00dev, PBF_CFG, 0xf40012); + rt2x00usb_register_write(rt2x00dev, PBF_CFG, 0xf40012); for (i = 0; i < 10; i++) { udelay(10); @@ -351,15 +351,15 @@ static void rt2800usb_watchdog(struct rt2x00_dev *rt2x00dev) break; } - rt2800_register_write(rt2x00dev, PBF_CFG, 0xf40006); + rt2x00usb_register_write(rt2x00dev, PBF_CFG, 0xf40006); } - rt2800_register_read(rt2x00dev, TXRXQ_PCNT, ®); + rt2x00usb_register_read(rt2x00dev, TXRXQ_PCNT, ®); if (rt2x00_get_field32(reg, TXRXQ_PCNT_TX1Q)) { WARNING(rt2x00dev, "TX HW queue 1 timed out," " invoke forced kick\n"); - rt2800_register_write(rt2x00dev, PBF_CFG, 0xf4000a); + rt2x00usb_register_write(rt2x00dev, PBF_CFG, 0xf4000a); for (i = 0; i < 10; i++) { udelay(10); @@ -367,7 +367,7 @@ static void rt2800usb_watchdog(struct rt2x00_dev *rt2x00dev) break; } - rt2800_register_write(rt2x00dev, PBF_CFG, 0xf40006); + rt2x00usb_register_write(rt2x00dev, PBF_CFG, 0xf40006); } rt2x00usb_watchdog(rt2x00dev); -- cgit v0.10.2 From e7dee444263a103a9a2ac5fd5d0b5e9dc177d57c Mon Sep 17 00:00:00 2001 From: Ivo van Doorn Date: Mon, 18 Apr 2011 15:34:41 +0200 Subject: rt2x00: Implement get_ringparam callback function With the get_ringparam callback function we can export ring parameters to ethtool through the mac80211 interface. Signed-off-by: Ivo van Doorn Acked-by: Gertjan van Wingerde Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/rt2x00/rt2400pci.c b/drivers/net/wireless/rt2x00/rt2400pci.c index d4acdde..bbe76f7 100644 --- a/drivers/net/wireless/rt2x00/rt2400pci.c +++ b/drivers/net/wireless/rt2x00/rt2400pci.c @@ -1720,6 +1720,7 @@ static const struct ieee80211_ops rt2400pci_mac80211_ops = { .tx_last_beacon = rt2400pci_tx_last_beacon, .rfkill_poll = rt2x00mac_rfkill_poll, .flush = rt2x00mac_flush, + .get_ringparam = rt2x00mac_get_ringparam, }; static const struct rt2x00lib_ops rt2400pci_rt2x00_ops = { diff --git a/drivers/net/wireless/rt2x00/rt2500pci.c b/drivers/net/wireless/rt2x00/rt2500pci.c index 15f5649..6f48996 100644 --- a/drivers/net/wireless/rt2x00/rt2500pci.c +++ b/drivers/net/wireless/rt2x00/rt2500pci.c @@ -2013,6 +2013,7 @@ static const struct ieee80211_ops rt2500pci_mac80211_ops = { .tx_last_beacon = rt2500pci_tx_last_beacon, .rfkill_poll = rt2x00mac_rfkill_poll, .flush = rt2x00mac_flush, + .get_ringparam = rt2x00mac_get_ringparam, }; static const struct rt2x00lib_ops rt2500pci_rt2x00_ops = { diff --git a/drivers/net/wireless/rt2x00/rt2500usb.c b/drivers/net/wireless/rt2x00/rt2500usb.c index d88c367..5ef3386 100644 --- a/drivers/net/wireless/rt2x00/rt2500usb.c +++ b/drivers/net/wireless/rt2x00/rt2500usb.c @@ -1823,6 +1823,7 @@ static const struct ieee80211_ops rt2500usb_mac80211_ops = { .conf_tx = rt2x00mac_conf_tx, .rfkill_poll = rt2x00mac_rfkill_poll, .flush = rt2x00mac_flush, + .get_ringparam = rt2x00mac_get_ringparam, }; static const struct rt2x00lib_ops rt2500usb_rt2x00_ops = { diff --git a/drivers/net/wireless/rt2x00/rt2800pci.c b/drivers/net/wireless/rt2x00/rt2800pci.c index b0c729b..08d3947 100644 --- a/drivers/net/wireless/rt2x00/rt2800pci.c +++ b/drivers/net/wireless/rt2x00/rt2800pci.c @@ -1028,6 +1028,7 @@ static const struct ieee80211_ops rt2800pci_mac80211_ops = { .ampdu_action = rt2800_ampdu_action, .flush = rt2x00mac_flush, .get_survey = rt2800_get_survey, + .get_ringparam = rt2x00mac_get_ringparam, }; static const struct rt2800_ops rt2800pci_rt2800_ops = { diff --git a/drivers/net/wireless/rt2x00/rt2800usb.c b/drivers/net/wireless/rt2x00/rt2800usb.c index 44ead75..0d4e8fa 100644 --- a/drivers/net/wireless/rt2x00/rt2800usb.c +++ b/drivers/net/wireless/rt2x00/rt2800usb.c @@ -673,6 +673,7 @@ static const struct ieee80211_ops rt2800usb_mac80211_ops = { .ampdu_action = rt2800_ampdu_action, .flush = rt2x00mac_flush, .get_survey = rt2800_get_survey, + .get_ringparam = rt2x00mac_get_ringparam, }; static const struct rt2800_ops rt2800usb_rt2800_ops = { diff --git a/drivers/net/wireless/rt2x00/rt2x00.h b/drivers/net/wireless/rt2x00/rt2x00.h index dcdc50d..f1d8f55 100644 --- a/drivers/net/wireless/rt2x00/rt2x00.h +++ b/drivers/net/wireless/rt2x00/rt2x00.h @@ -1254,6 +1254,8 @@ int rt2x00mac_conf_tx(struct ieee80211_hw *hw, u16 queue, const struct ieee80211_tx_queue_params *params); void rt2x00mac_rfkill_poll(struct ieee80211_hw *hw); void rt2x00mac_flush(struct ieee80211_hw *hw, bool drop); +void rt2x00mac_get_ringparam(struct ieee80211_hw *hw, + u32 *tx, u32 *tx_max, u32 *rx, u32 *rx_max); /* * Driver allocation handlers. diff --git a/drivers/net/wireless/rt2x00/rt2x00mac.c b/drivers/net/wireless/rt2x00/rt2x00mac.c index 4770156d..6d1d383 100644 --- a/drivers/net/wireless/rt2x00/rt2x00mac.c +++ b/drivers/net/wireless/rt2x00/rt2x00mac.c @@ -737,3 +737,19 @@ void rt2x00mac_flush(struct ieee80211_hw *hw, bool drop) rt2x00queue_flush_queue(queue, drop); } EXPORT_SYMBOL_GPL(rt2x00mac_flush); + +void rt2x00mac_get_ringparam(struct ieee80211_hw *hw, + u32 *tx, u32 *tx_max, u32 *rx, u32 *rx_max) +{ + struct rt2x00_dev *rt2x00dev = hw->priv; + struct data_queue *queue; + + tx_queue_for_each(rt2x00dev, queue) { + *tx += queue->length; + *tx_max += queue->limit; + } + + *rx = rt2x00dev->rx->length; + *rx_max = rt2x00dev->rx->limit; +} +EXPORT_SYMBOL_GPL(rt2x00mac_get_ringparam); diff --git a/drivers/net/wireless/rt2x00/rt61pci.c b/drivers/net/wireless/rt2x00/rt61pci.c index c5dccdb..eb54031 100644 --- a/drivers/net/wireless/rt2x00/rt61pci.c +++ b/drivers/net/wireless/rt2x00/rt61pci.c @@ -2979,6 +2979,7 @@ static const struct ieee80211_ops rt61pci_mac80211_ops = { .get_tsf = rt61pci_get_tsf, .rfkill_poll = rt2x00mac_rfkill_poll, .flush = rt2x00mac_flush, + .get_ringparam = rt2x00mac_get_ringparam, }; static const struct rt2x00lib_ops rt61pci_rt2x00_ops = { diff --git a/drivers/net/wireless/rt2x00/rt73usb.c b/drivers/net/wireless/rt2x00/rt73usb.c index be3eb5e..bf7fea4 100644 --- a/drivers/net/wireless/rt2x00/rt73usb.c +++ b/drivers/net/wireless/rt2x00/rt73usb.c @@ -2310,6 +2310,7 @@ static const struct ieee80211_ops rt73usb_mac80211_ops = { .get_tsf = rt73usb_get_tsf, .rfkill_poll = rt2x00mac_rfkill_poll, .flush = rt2x00mac_flush, + .get_ringparam = rt2x00mac_get_ringparam, }; static const struct rt2x00lib_ops rt73usb_rt2x00_ops = { -- cgit v0.10.2 From 0ed7b3c04434788ef03d267190c5e9e6e3f8e9ce Mon Sep 17 00:00:00 2001 From: Ivo van Doorn Date: Mon, 18 Apr 2011 15:35:12 +0200 Subject: rt2x00: Implement get_antenna and set_antenna callback functions Implement the get_antenna and set_antenna callback functions, which will allow clients to control the antenna for all non-11n hardware (Antenna handling in rt2800 is still a bit magical, so we can't use the set_antenna for those drivers yet). To best support the set_antenna callback some modifications are needed in the diversity handling. We should never look at the default antenna settings to determine if software diversity is enabled. Instead we should set the diversity flag when possible, which will allow the link_tuner to automatically pick up the tuning. Signed-off-by: Ivo van Doorn Acked-by: Gertjan van Wingerde Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/rt2x00/rt2400pci.c b/drivers/net/wireless/rt2x00/rt2400pci.c index bbe76f7..937f9e8 100644 --- a/drivers/net/wireless/rt2x00/rt2400pci.c +++ b/drivers/net/wireless/rt2x00/rt2400pci.c @@ -1720,6 +1720,8 @@ static const struct ieee80211_ops rt2400pci_mac80211_ops = { .tx_last_beacon = rt2400pci_tx_last_beacon, .rfkill_poll = rt2x00mac_rfkill_poll, .flush = rt2x00mac_flush, + .set_antenna = rt2x00mac_set_antenna, + .get_antenna = rt2x00mac_get_antenna, .get_ringparam = rt2x00mac_get_ringparam, }; diff --git a/drivers/net/wireless/rt2x00/rt2500pci.c b/drivers/net/wireless/rt2x00/rt2500pci.c index 6f48996..d27d7b8 100644 --- a/drivers/net/wireless/rt2x00/rt2500pci.c +++ b/drivers/net/wireless/rt2x00/rt2500pci.c @@ -2013,6 +2013,8 @@ static const struct ieee80211_ops rt2500pci_mac80211_ops = { .tx_last_beacon = rt2500pci_tx_last_beacon, .rfkill_poll = rt2x00mac_rfkill_poll, .flush = rt2x00mac_flush, + .set_antenna = rt2x00mac_set_antenna, + .get_antenna = rt2x00mac_get_antenna, .get_ringparam = rt2x00mac_get_ringparam, }; diff --git a/drivers/net/wireless/rt2x00/rt2500usb.c b/drivers/net/wireless/rt2x00/rt2500usb.c index 5ef3386..b21f8123 100644 --- a/drivers/net/wireless/rt2x00/rt2500usb.c +++ b/drivers/net/wireless/rt2x00/rt2500usb.c @@ -1823,6 +1823,8 @@ static const struct ieee80211_ops rt2500usb_mac80211_ops = { .conf_tx = rt2x00mac_conf_tx, .rfkill_poll = rt2x00mac_rfkill_poll, .flush = rt2x00mac_flush, + .set_antenna = rt2x00mac_set_antenna, + .get_antenna = rt2x00mac_get_antenna, .get_ringparam = rt2x00mac_get_ringparam, }; diff --git a/drivers/net/wireless/rt2x00/rt2x00.h b/drivers/net/wireless/rt2x00/rt2x00.h index f1d8f55..acf561f 100644 --- a/drivers/net/wireless/rt2x00/rt2x00.h +++ b/drivers/net/wireless/rt2x00/rt2x00.h @@ -1254,6 +1254,8 @@ int rt2x00mac_conf_tx(struct ieee80211_hw *hw, u16 queue, const struct ieee80211_tx_queue_params *params); void rt2x00mac_rfkill_poll(struct ieee80211_hw *hw); void rt2x00mac_flush(struct ieee80211_hw *hw, bool drop); +int rt2x00mac_set_antenna(struct ieee80211_hw *hw, u32 tx_ant, u32 rx_ant); +int rt2x00mac_get_antenna(struct ieee80211_hw *hw, u32 *tx_ant, u32 *rx_ant); void rt2x00mac_get_ringparam(struct ieee80211_hw *hw, u32 *tx, u32 *tx_max, u32 *rx, u32 *rx_max); diff --git a/drivers/net/wireless/rt2x00/rt2x00config.c b/drivers/net/wireless/rt2x00/rt2x00config.c index f70a2b4..2a313b6 100644 --- a/drivers/net/wireless/rt2x00/rt2x00config.c +++ b/drivers/net/wireless/rt2x00/rt2x00config.c @@ -109,15 +109,6 @@ void rt2x00lib_config_erp(struct rt2x00_dev *rt2x00dev, rt2x00dev->ops->lib->config_erp(rt2x00dev, &erp, changed); } -static inline -enum antenna rt2x00lib_config_antenna_check(enum antenna current_ant, - enum antenna default_ant) -{ - if (current_ant != ANTENNA_SW_DIVERSITY) - return current_ant; - return (default_ant != ANTENNA_SW_DIVERSITY) ? default_ant : ANTENNA_B; -} - void rt2x00lib_config_antenna(struct rt2x00_dev *rt2x00dev, struct antenna_setup config) { @@ -126,19 +117,35 @@ void rt2x00lib_config_antenna(struct rt2x00_dev *rt2x00dev, struct antenna_setup *active = &rt2x00dev->link.ant.active; /* - * Failsafe: Make sure we are not sending the - * ANTENNA_SW_DIVERSITY state to the driver. - * If that happens, fallback to hardware defaults, - * or our own default. + * When the caller tries to send the SW diversity, + * we must update the ANTENNA_RX_DIVERSITY flag to + * enable the antenna diversity in the link tuner. + * + * Secondly, we must guarentee we never send the + * software antenna diversity command to the driver. */ - if (!(ant->flags & ANTENNA_RX_DIVERSITY)) - config.rx = rt2x00lib_config_antenna_check(config.rx, def->rx); - else if (config.rx == ANTENNA_SW_DIVERSITY) + if (!(ant->flags & ANTENNA_RX_DIVERSITY)) { + if (config.rx == ANTENNA_SW_DIVERSITY) { + ant->flags |= ANTENNA_RX_DIVERSITY; + + if (def->rx == ANTENNA_SW_DIVERSITY) + config.rx = ANTENNA_B; + else + config.rx = def->rx; + } + } else if (config.rx == ANTENNA_SW_DIVERSITY) config.rx = active->rx; - if (!(ant->flags & ANTENNA_TX_DIVERSITY)) - config.tx = rt2x00lib_config_antenna_check(config.tx, def->tx); - else if (config.tx == ANTENNA_SW_DIVERSITY) + if (!(ant->flags & ANTENNA_TX_DIVERSITY)) { + if (config.tx == ANTENNA_SW_DIVERSITY) { + ant->flags |= ANTENNA_TX_DIVERSITY; + + if (def->tx == ANTENNA_SW_DIVERSITY) + config.tx = ANTENNA_B; + else + config.tx = def->tx; + } + } else if (config.tx == ANTENNA_SW_DIVERSITY) config.tx = active->tx; /* diff --git a/drivers/net/wireless/rt2x00/rt2x00link.c b/drivers/net/wireless/rt2x00/rt2x00link.c index ba0bb76..fa55399 100644 --- a/drivers/net/wireless/rt2x00/rt2x00link.c +++ b/drivers/net/wireless/rt2x00/rt2x00link.c @@ -192,17 +192,7 @@ static bool rt2x00lib_antenna_diversity(struct rt2x00_dev *rt2x00dev) /* * Determine if software diversity is enabled for * either the TX or RX antenna (or both). - * Always perform this check since within the link - * tuner interval the configuration might have changed. */ - ant->flags &= ~ANTENNA_RX_DIVERSITY; - ant->flags &= ~ANTENNA_TX_DIVERSITY; - - if (rt2x00dev->default_ant.rx == ANTENNA_SW_DIVERSITY) - ant->flags |= ANTENNA_RX_DIVERSITY; - if (rt2x00dev->default_ant.tx == ANTENNA_SW_DIVERSITY) - ant->flags |= ANTENNA_TX_DIVERSITY; - if (!(ant->flags & ANTENNA_RX_DIVERSITY) && !(ant->flags & ANTENNA_TX_DIVERSITY)) { ant->flags = 0; diff --git a/drivers/net/wireless/rt2x00/rt2x00mac.c b/drivers/net/wireless/rt2x00/rt2x00mac.c index 6d1d383..93bec14 100644 --- a/drivers/net/wireless/rt2x00/rt2x00mac.c +++ b/drivers/net/wireless/rt2x00/rt2x00mac.c @@ -738,6 +738,71 @@ void rt2x00mac_flush(struct ieee80211_hw *hw, bool drop) } EXPORT_SYMBOL_GPL(rt2x00mac_flush); +int rt2x00mac_set_antenna(struct ieee80211_hw *hw, u32 tx_ant, u32 rx_ant) +{ + struct rt2x00_dev *rt2x00dev = hw->priv; + struct link_ant *ant = &rt2x00dev->link.ant; + struct antenna_setup *def = &rt2x00dev->default_ant; + struct antenna_setup setup; + + // The antenna value is not supposed to be 0, + // or exceed the maximum number of antenna's. + if (!tx_ant || (tx_ant & ~3) || !rx_ant || (rx_ant & ~3)) + return -EINVAL; + + // When the client tried to configure the antenna to or from + // diversity mode, we must reset the default antenna as well + // as that controls the diversity switch. + if (ant->flags & ANTENNA_TX_DIVERSITY && tx_ant != 3) + ant->flags &= ~ANTENNA_TX_DIVERSITY; + if (ant->flags & ANTENNA_RX_DIVERSITY && rx_ant != 3) + ant->flags &= ~ANTENNA_RX_DIVERSITY; + + // If diversity is being enabled, check if we need hardware + // or software diversity. In the latter case, reset the value, + // and make sure we update the antenna flags to have the + // link tuner pick up the diversity tuning. + if (tx_ant == 3 && def->tx == ANTENNA_SW_DIVERSITY) { + tx_ant = ANTENNA_SW_DIVERSITY; + ant->flags |= ANTENNA_TX_DIVERSITY; + } + + if (rx_ant == 3 && def->rx == ANTENNA_SW_DIVERSITY) { + rx_ant = ANTENNA_SW_DIVERSITY; + ant->flags |= ANTENNA_RX_DIVERSITY; + } + + setup.tx = tx_ant; + setup.rx = rx_ant; + + rt2x00lib_config_antenna(rt2x00dev, setup); + + return 0; +} +EXPORT_SYMBOL_GPL(rt2x00mac_set_antenna); + +int rt2x00mac_get_antenna(struct ieee80211_hw *hw, u32 *tx_ant, u32 *rx_ant) +{ + struct rt2x00_dev *rt2x00dev = hw->priv; + struct link_ant *ant = &rt2x00dev->link.ant; + struct antenna_setup *active = &rt2x00dev->link.ant.active; + + // When software diversity is active, we must report this to the + // client and not the current active antenna state. + if (ant->flags & ANTENNA_TX_DIVERSITY) + *tx_ant = ANTENNA_HW_DIVERSITY; + else + *tx_ant = active->tx; + + if (ant->flags & ANTENNA_RX_DIVERSITY) + *rx_ant = ANTENNA_HW_DIVERSITY; + else + *rx_ant = active->rx; + + return 0; +} +EXPORT_SYMBOL_GPL(rt2x00mac_get_antenna); + void rt2x00mac_get_ringparam(struct ieee80211_hw *hw, u32 *tx, u32 *tx_max, u32 *rx, u32 *rx_max) { diff --git a/drivers/net/wireless/rt2x00/rt61pci.c b/drivers/net/wireless/rt2x00/rt61pci.c index eb54031..9d35ec1 100644 --- a/drivers/net/wireless/rt2x00/rt61pci.c +++ b/drivers/net/wireless/rt2x00/rt61pci.c @@ -2979,6 +2979,8 @@ static const struct ieee80211_ops rt61pci_mac80211_ops = { .get_tsf = rt61pci_get_tsf, .rfkill_poll = rt2x00mac_rfkill_poll, .flush = rt2x00mac_flush, + .set_antenna = rt2x00mac_set_antenna, + .get_antenna = rt2x00mac_get_antenna, .get_ringparam = rt2x00mac_get_ringparam, }; diff --git a/drivers/net/wireless/rt2x00/rt73usb.c b/drivers/net/wireless/rt2x00/rt73usb.c index bf7fea4..a6ce7d6 100644 --- a/drivers/net/wireless/rt2x00/rt73usb.c +++ b/drivers/net/wireless/rt2x00/rt73usb.c @@ -2310,6 +2310,8 @@ static const struct ieee80211_ops rt73usb_mac80211_ops = { .get_tsf = rt73usb_get_tsf, .rfkill_poll = rt2x00mac_rfkill_poll, .flush = rt2x00mac_flush, + .set_antenna = rt2x00mac_set_antenna, + .get_antenna = rt2x00mac_get_antenna, .get_ringparam = rt2x00mac_get_ringparam, }; -- cgit v0.10.2 From 73b48099cc265f88fa1255f3f43e52fe6a94fd5c Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 18 Apr 2011 17:05:21 +0200 Subject: mac80211: explain padding in place of rate field Apparently this was confusing still ... add a note that the byte is needed as padding. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index 54858a6..1f06b31 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -143,7 +143,8 @@ ieee80211_add_rx_radiotap_header(struct ieee80211_local *local, if (status->flag & RX_FLAG_HT) { /* * MCS information is a separate field in radiotap, - * added below. + * added below. The byte here is needed as padding + * for the channel though, so initialise it to 0. */ *pos = 0; } else { -- cgit v0.10.2 From a96e5b90804be8b540d30f4a1453fc87f95b3149 Mon Sep 17 00:00:00 2001 From: OGAWA Hirofumi Date: Mon, 18 Apr 2011 11:48:55 -0400 Subject: nfsd4: Fix filp leak 23fcf2ec93fb8573a653408316af599939ff9a8e (nfsd4: fix oops on lock failure) The above patch breaks free path for stp->st_file. If stp was inserted into sop->so_stateids, we have to free stp->st_file refcount. Because stp->st_file refcount itself is taken whether or not any refcounts are taken on the stp->st_file->fi_fds[]. Signed-off-by: OGAWA Hirofumi Cc: stable@kernel.org Signed-off-by: J. Bruce Fields diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index c79a983..4cf04e1 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c @@ -403,8 +403,8 @@ static void free_generic_stateid(struct nfs4_stateid *stp) if (stp->st_access_bmap) { oflag = nfs4_access_bmap_to_omode(stp); nfs4_file_put_access(stp->st_file, oflag); - put_nfs4_file(stp->st_file); } + put_nfs4_file(stp->st_file); kmem_cache_free(stateid_slab, stp); } -- cgit v0.10.2 From 2ea4db65be3c4027ed39da73e1b6a59c8aa6c7c9 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Tue, 19 Apr 2011 22:52:58 +0200 Subject: xtensa: Fixup irq conversion fallout and nmi_count Some unnamed moron fatfingered the arguments of the irq chip callbacks to irq_chip instead of irq_data. While at it remove the nmi_count() print in arch_show_interrupts() which has been broken before the irq conversion already. Signed-off-by: Thomas Gleixner diff --git a/arch/xtensa/kernel/irq.c b/arch/xtensa/kernel/irq.c index d77089d..4340ee0 100644 --- a/arch/xtensa/kernel/irq.c +++ b/arch/xtensa/kernel/irq.c @@ -64,47 +64,41 @@ asmlinkage void do_IRQ(int irq, struct pt_regs *regs) int arch_show_interrupts(struct seq_file *p, int prec) { - int j; - - seq_printf(p, "%*s: ", prec, "NMI"); - for_each_online_cpu(j) - seq_printf(p, "%10u ", nmi_count(j)); - seq_putc(p, '\n'); seq_printf(p, "%*s: ", prec, "ERR"); seq_printf(p, "%10u\n", atomic_read(&irq_err_count)); return 0; } -static void xtensa_irq_mask(struct irq_chip *d) +static void xtensa_irq_mask(struct irq_data *d) { cached_irq_mask &= ~(1 << d->irq); set_sr (cached_irq_mask, INTENABLE); } -static void xtensa_irq_unmask(struct irq_chip *d) +static void xtensa_irq_unmask(struct irq_data *d) { cached_irq_mask |= 1 << d->irq; set_sr (cached_irq_mask, INTENABLE); } -static void xtensa_irq_enable(struct irq_chip *d) +static void xtensa_irq_enable(struct irq_data *d) { variant_irq_enable(d->irq); xtensa_irq_unmask(d->irq); } -static void xtensa_irq_disable(struct irq_chip *d) +static void xtensa_irq_disable(struct irq_data *d) { xtensa_irq_mask(d->irq); variant_irq_disable(d->irq); } -static void xtensa_irq_ack(struct irq_chip *d) +static void xtensa_irq_ack(struct irq_data *d) { set_sr(1 << d->irq, INTCLEAR); } -static int xtensa_irq_retrigger(struct irq_chip *d) +static int xtensa_irq_retrigger(struct irq_data *d) { set_sr (1 << d->irq, INTSET); return 1; -- cgit v0.10.2 From 19234c0819da0e043a02710488dfd9b242b42eba Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Wed, 20 Apr 2011 00:36:11 +0200 Subject: PM: Add missing syscore_suspend() and syscore_resume() calls Device suspend/resume infrastructure is used not only by the suspend and hibernate code in kernel/power, but also by APM, Xen and the kexec jump feature. However, commit 40dc166cb5dddbd36aa4ad11c03915ea (PM / Core: Introduce struct syscore_ops for core subsystems PM) failed to add syscore_suspend() and syscore_resume() calls to that code, which generally leads to breakage when the features in question are used. To fix this problem, add the missing syscore_suspend() and syscore_resume() calls to arch/x86/kernel/apm_32.c, kernel/kexec.c and drivers/xen/manage.c. Signed-off-by: Rafael J. Wysocki Acked-by: Greg Kroah-Hartman Acked-by: Ian Campbell diff --git a/arch/x86/kernel/apm_32.c b/arch/x86/kernel/apm_32.c index 0b4be43..adee12e 100644 --- a/arch/x86/kernel/apm_32.c +++ b/arch/x86/kernel/apm_32.c @@ -228,6 +228,7 @@ #include #include #include +#include #include #include @@ -1238,6 +1239,7 @@ static int suspend(int vetoable) local_irq_disable(); sysdev_suspend(PMSG_SUSPEND); + syscore_suspend(); local_irq_enable(); @@ -1255,6 +1257,7 @@ static int suspend(int vetoable) apm_error("suspend", err); err = (err == APM_SUCCESS) ? 0 : -EIO; + syscore_resume(); sysdev_resume(); local_irq_enable(); @@ -1280,6 +1283,7 @@ static void standby(void) local_irq_disable(); sysdev_suspend(PMSG_SUSPEND); + syscore_suspend(); local_irq_enable(); err = set_system_power_state(APM_STATE_STANDBY); @@ -1287,6 +1291,7 @@ static void standby(void) apm_error("standby", err); local_irq_disable(); + syscore_resume(); sysdev_resume(); local_irq_enable(); diff --git a/drivers/base/syscore.c b/drivers/base/syscore.c index 90af294..c126db3 100644 --- a/drivers/base/syscore.c +++ b/drivers/base/syscore.c @@ -73,6 +73,7 @@ int syscore_suspend(void) return ret; } +EXPORT_SYMBOL_GPL(syscore_suspend); /** * syscore_resume - Execute all the registered system core resume callbacks. @@ -95,6 +96,7 @@ void syscore_resume(void) "Interrupts enabled after %pF\n", ops->resume); } } +EXPORT_SYMBOL_GPL(syscore_resume); #endif /* CONFIG_PM_SLEEP */ /** diff --git a/drivers/xen/manage.c b/drivers/xen/manage.c index 1ac9412..a2eee57 100644 --- a/drivers/xen/manage.c +++ b/drivers/xen/manage.c @@ -8,6 +8,7 @@ #include #include #include +#include #include #include @@ -70,8 +71,13 @@ static int xen_suspend(void *data) BUG_ON(!irqs_disabled()); err = sysdev_suspend(PMSG_FREEZE); + if (!err) { + err = syscore_suspend(); + if (err) + sysdev_resume(); + } if (err) { - printk(KERN_ERR "xen_suspend: sysdev_suspend failed: %d\n", + printk(KERN_ERR "xen_suspend: system core suspend failed: %d\n", err); return err; } @@ -95,6 +101,7 @@ static int xen_suspend(void *data) xen_timer_resume(); } + syscore_resume(); sysdev_resume(); return 0; diff --git a/kernel/kexec.c b/kernel/kexec.c index 55936f9..87b77de 100644 --- a/kernel/kexec.c +++ b/kernel/kexec.c @@ -33,6 +33,7 @@ #include #include #include +#include #include #include @@ -1532,6 +1533,11 @@ int kernel_kexec(void) local_irq_disable(); /* Suspend system devices */ error = sysdev_suspend(PMSG_FREEZE); + if (!error) { + error = syscore_suspend(); + if (error) + sysdev_resume(); + } if (error) goto Enable_irqs; } else @@ -1546,6 +1552,7 @@ int kernel_kexec(void) #ifdef CONFIG_KEXEC_JUMP if (kexec_image->preserve_context) { + syscore_resume(); sysdev_resume(); Enable_irqs: local_irq_enable(); -- cgit v0.10.2 From 04eb34a43ce5168e05e2748bd46a62a09289cdde Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Wed, 6 Apr 2011 13:28:35 +1000 Subject: drm/nouveau: split ramin_lock into two locks, one hardirq safe Fixes a possible lock ordering reversal between context_switch_lock and ramin_lock. Signed-off-by: Ben Skeggs Reviewed-by: Francisco Jerez diff --git a/drivers/gpu/drm/nouveau/nouveau_drv.h b/drivers/gpu/drm/nouveau/nouveau_drv.h index 856d56a..a76514a 100644 --- a/drivers/gpu/drm/nouveau/nouveau_drv.h +++ b/drivers/gpu/drm/nouveau/nouveau_drv.h @@ -682,6 +682,9 @@ struct drm_nouveau_private { /* For PFIFO and PGRAPH. */ spinlock_t context_switch_lock; + /* VM/PRAMIN flush, legacy PRAMIN aperture */ + spinlock_t vm_lock; + /* RAMIN configuration, RAMFC, RAMHT and RAMRO offsets */ struct nouveau_ramht *ramht; struct nouveau_gpuobj *ramfc; diff --git a/drivers/gpu/drm/nouveau/nouveau_object.c b/drivers/gpu/drm/nouveau/nouveau_object.c index 4f00c87..67a16e0 100644 --- a/drivers/gpu/drm/nouveau/nouveau_object.c +++ b/drivers/gpu/drm/nouveau/nouveau_object.c @@ -1039,19 +1039,20 @@ nv_ro32(struct nouveau_gpuobj *gpuobj, u32 offset) { struct drm_nouveau_private *dev_priv = gpuobj->dev->dev_private; struct drm_device *dev = gpuobj->dev; + unsigned long flags; if (gpuobj->pinst == ~0 || !dev_priv->ramin_available) { u64 ptr = gpuobj->vinst + offset; u32 base = ptr >> 16; u32 val; - spin_lock(&dev_priv->ramin_lock); + spin_lock_irqsave(&dev_priv->vm_lock, flags); if (dev_priv->ramin_base != base) { dev_priv->ramin_base = base; nv_wr32(dev, 0x001700, dev_priv->ramin_base); } val = nv_rd32(dev, 0x700000 + (ptr & 0xffff)); - spin_unlock(&dev_priv->ramin_lock); + spin_unlock_irqrestore(&dev_priv->vm_lock, flags); return val; } @@ -1063,18 +1064,19 @@ nv_wo32(struct nouveau_gpuobj *gpuobj, u32 offset, u32 val) { struct drm_nouveau_private *dev_priv = gpuobj->dev->dev_private; struct drm_device *dev = gpuobj->dev; + unsigned long flags; if (gpuobj->pinst == ~0 || !dev_priv->ramin_available) { u64 ptr = gpuobj->vinst + offset; u32 base = ptr >> 16; - spin_lock(&dev_priv->ramin_lock); + spin_lock_irqsave(&dev_priv->vm_lock, flags); if (dev_priv->ramin_base != base) { dev_priv->ramin_base = base; nv_wr32(dev, 0x001700, dev_priv->ramin_base); } nv_wr32(dev, 0x700000 + (ptr & 0xffff), val); - spin_unlock(&dev_priv->ramin_lock); + spin_unlock_irqrestore(&dev_priv->vm_lock, flags); return; } diff --git a/drivers/gpu/drm/nouveau/nouveau_state.c b/drivers/gpu/drm/nouveau/nouveau_state.c index 6e2b1a6..a30adec 100644 --- a/drivers/gpu/drm/nouveau/nouveau_state.c +++ b/drivers/gpu/drm/nouveau/nouveau_state.c @@ -608,6 +608,7 @@ nouveau_card_init(struct drm_device *dev) spin_lock_init(&dev_priv->channels.lock); spin_lock_init(&dev_priv->tile.lock); spin_lock_init(&dev_priv->context_switch_lock); + spin_lock_init(&dev_priv->vm_lock); /* Make the CRTCs and I2C buses accessible */ ret = engine->display.early_init(dev); diff --git a/drivers/gpu/drm/nouveau/nv50_instmem.c b/drivers/gpu/drm/nouveau/nv50_instmem.c index a6f8aa6..4f95a1e 100644 --- a/drivers/gpu/drm/nouveau/nv50_instmem.c +++ b/drivers/gpu/drm/nouveau/nv50_instmem.c @@ -404,23 +404,25 @@ void nv50_instmem_flush(struct drm_device *dev) { struct drm_nouveau_private *dev_priv = dev->dev_private; + unsigned long flags; - spin_lock(&dev_priv->ramin_lock); + spin_lock_irqsave(&dev_priv->vm_lock, flags); nv_wr32(dev, 0x00330c, 0x00000001); if (!nv_wait(dev, 0x00330c, 0x00000002, 0x00000000)) NV_ERROR(dev, "PRAMIN flush timeout\n"); - spin_unlock(&dev_priv->ramin_lock); + spin_unlock_irqrestore(&dev_priv->vm_lock, flags); } void nv84_instmem_flush(struct drm_device *dev) { struct drm_nouveau_private *dev_priv = dev->dev_private; + unsigned long flags; - spin_lock(&dev_priv->ramin_lock); + spin_lock_irqsave(&dev_priv->vm_lock, flags); nv_wr32(dev, 0x070000, 0x00000001); if (!nv_wait(dev, 0x070000, 0x00000002, 0x00000000)) NV_ERROR(dev, "PRAMIN flush timeout\n"); - spin_unlock(&dev_priv->ramin_lock); + spin_unlock_irqrestore(&dev_priv->vm_lock, flags); } diff --git a/drivers/gpu/drm/nouveau/nv50_vm.c b/drivers/gpu/drm/nouveau/nv50_vm.c index 4fd3432..6c26944 100644 --- a/drivers/gpu/drm/nouveau/nv50_vm.c +++ b/drivers/gpu/drm/nouveau/nv50_vm.c @@ -174,10 +174,11 @@ void nv50_vm_flush_engine(struct drm_device *dev, int engine) { struct drm_nouveau_private *dev_priv = dev->dev_private; + unsigned long flags; - spin_lock(&dev_priv->ramin_lock); + spin_lock_irqsave(&dev_priv->vm_lock, flags); nv_wr32(dev, 0x100c80, (engine << 16) | 1); if (!nv_wait(dev, 0x100c80, 0x00000001, 0x00000000)) NV_ERROR(dev, "vm flush timeout: engine %d\n", engine); - spin_unlock(&dev_priv->ramin_lock); + spin_unlock_irqrestore(&dev_priv->vm_lock, flags); } diff --git a/drivers/gpu/drm/nouveau/nvc0_vm.c b/drivers/gpu/drm/nouveau/nvc0_vm.c index a0a2a02..a179e6c 100644 --- a/drivers/gpu/drm/nouveau/nvc0_vm.c +++ b/drivers/gpu/drm/nouveau/nvc0_vm.c @@ -104,11 +104,12 @@ nvc0_vm_flush(struct nouveau_vm *vm) struct nouveau_instmem_engine *pinstmem = &dev_priv->engine.instmem; struct drm_device *dev = vm->dev; struct nouveau_vm_pgd *vpgd; + unsigned long flags; u32 engine = (dev_priv->chan_vm == vm) ? 1 : 5; pinstmem->flush(vm->dev); - spin_lock(&dev_priv->ramin_lock); + spin_lock_irqsave(&dev_priv->vm_lock, flags); list_for_each_entry(vpgd, &vm->pgd_list, head) { /* looks like maybe a "free flush slots" counter, the * faster you write to 0x100cbc to more it decreases @@ -125,5 +126,5 @@ nvc0_vm_flush(struct nouveau_vm *vm) nv_rd32(dev, 0x100c80), engine); } } - spin_unlock(&dev_priv->ramin_lock); + spin_unlock_irqrestore(&dev_priv->vm_lock, flags); } -- cgit v0.10.2 From 01d153326ecd81ed77395f1699a30af416cf77ab Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Fri, 8 Apr 2011 10:07:34 +1000 Subject: drm/nouveau: fix nv30 pcie boards Wasn't aware they even existed, apparently they do! They're actually AGP chips with a bridge as far as I can tell, which puts them in the same boat as nv40/nv45. Signed-off-by: Ben Skeggs diff --git a/drivers/gpu/drm/nouveau/nouveau_mem.c b/drivers/gpu/drm/nouveau/nouveau_mem.c index 78f467f..5045f8b 100644 --- a/drivers/gpu/drm/nouveau/nouveau_mem.c +++ b/drivers/gpu/drm/nouveau/nouveau_mem.c @@ -398,7 +398,7 @@ nouveau_mem_vram_init(struct drm_device *dev) dma_bits = 40; } else if (drm_pci_device_is_pcie(dev) && - dev_priv->chipset != 0x40 && + dev_priv->chipset > 0x40 && dev_priv->chipset != 0x45) { if (pci_dma_supported(dev->pdev, DMA_BIT_MASK(39))) dma_bits = 39; diff --git a/drivers/gpu/drm/nouveau/nouveau_sgdma.c b/drivers/gpu/drm/nouveau/nouveau_sgdma.c index a33fe40..fc29244 100644 --- a/drivers/gpu/drm/nouveau/nouveau_sgdma.c +++ b/drivers/gpu/drm/nouveau/nouveau_sgdma.c @@ -427,7 +427,7 @@ nouveau_sgdma_init(struct drm_device *dev) u32 aper_size, align; int ret; - if (dev_priv->card_type >= NV_50 || drm_pci_device_is_pcie(dev)) + if (dev_priv->card_type >= NV_40 && drm_pci_device_is_pcie(dev)) aper_size = 512 * 1024 * 1024; else aper_size = 64 * 1024 * 1024; @@ -457,7 +457,7 @@ nouveau_sgdma_init(struct drm_device *dev) dev_priv->gart_info.func = &nv50_sgdma_backend; } else if (drm_pci_device_is_pcie(dev) && - dev_priv->chipset != 0x40 && dev_priv->chipset != 0x45) { + dev_priv->chipset > 0x40 && dev_priv->chipset != 0x45) { if (nv44_graph_class(dev)) { dev_priv->gart_info.func = &nv44_sgdma_backend; align = 512 * 1024; -- cgit v0.10.2 From 8706398bf8841868d4e56fc924a5edcd3f156243 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Mon, 11 Apr 2011 16:37:44 +1000 Subject: drm/nouveau: populate ttm_alloced with false, when it's not Caught with kmemcheck on unrelated business. Signed-off-by: Ben Skeggs diff --git a/drivers/gpu/drm/nouveau/nouveau_sgdma.c b/drivers/gpu/drm/nouveau/nouveau_sgdma.c index fc29244..4bce801 100644 --- a/drivers/gpu/drm/nouveau/nouveau_sgdma.c +++ b/drivers/gpu/drm/nouveau/nouveau_sgdma.c @@ -55,6 +55,7 @@ nouveau_sgdma_populate(struct ttm_backend *be, unsigned long num_pages, be->func->clear(be); return -EFAULT; } + nvbe->ttm_alloced[nvbe->nr_pages] = false; } nvbe->nr_pages++; -- cgit v0.10.2 From 11dea1a2144f24216551fbeddacbde0980ae8a55 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Mon, 18 Apr 2011 09:12:25 +1000 Subject: drm/nouveau: fix pinning of notifier block Problem introduced with commit 6ba9a68317781537d6184d3fdb2d0f20c97da3a4 Reported-by: Bob Gleitsmann Signed-off-by: Ben Skeggs diff --git a/drivers/gpu/drm/nouveau/nouveau_notifier.c b/drivers/gpu/drm/nouveau/nouveau_notifier.c index 7ba3fc0..5b39718 100644 --- a/drivers/gpu/drm/nouveau/nouveau_notifier.c +++ b/drivers/gpu/drm/nouveau/nouveau_notifier.c @@ -35,19 +35,22 @@ nouveau_notifier_init_channel(struct nouveau_channel *chan) { struct drm_device *dev = chan->dev; struct nouveau_bo *ntfy = NULL; - uint32_t flags; + uint32_t flags, ttmpl; int ret; - if (nouveau_vram_notify) + if (nouveau_vram_notify) { flags = NOUVEAU_GEM_DOMAIN_VRAM; - else + ttmpl = TTM_PL_FLAG_VRAM; + } else { flags = NOUVEAU_GEM_DOMAIN_GART; + ttmpl = TTM_PL_FLAG_TT; + } ret = nouveau_gem_new(dev, NULL, PAGE_SIZE, 0, flags, 0, 0, &ntfy); if (ret) return ret; - ret = nouveau_bo_pin(ntfy, flags); + ret = nouveau_bo_pin(ntfy, ttmpl); if (ret) goto out_err; -- cgit v0.10.2 From a18d89ca026140eb8ac4459bf70a01c571dd9a32 Mon Sep 17 00:00:00 2001 From: Marcin Slusarz Date: Tue, 19 Apr 2011 23:50:48 +0200 Subject: drm/nouveau: fix notifier memory corruption bug nouveau_bo_wr32 expects offset to be in words, but we pass value in bytes, so after commit 73412c3854c877e5f37ad944ee8977addde4d35a ("drm/nouveau: allocate kernel's notifier object at end of block") we started to overwrite some memory after notifier buffer object (previously m2mf_ntfy was always 0, so it didn't matter it was a value in bytes). Reported-by: Dominik Brodowski Reported-by: Nigel Cunningham Signed-off-by: Marcin Slusarz Cc: Ben Skeggs Cc: Pekka Paalanen Cc: stable@kernel.org [2.6.38] Signed-off-by: Ben Skeggs diff --git a/drivers/gpu/drm/nouveau/nouveau_fbcon.c b/drivers/gpu/drm/nouveau/nouveau_fbcon.c index 889c445..39aee6d 100644 --- a/drivers/gpu/drm/nouveau/nouveau_fbcon.c +++ b/drivers/gpu/drm/nouveau/nouveau_fbcon.c @@ -181,13 +181,13 @@ nouveau_fbcon_sync(struct fb_info *info) OUT_RING (chan, 0); } - nouveau_bo_wr32(chan->notifier_bo, chan->m2mf_ntfy + 3, 0xffffffff); + nouveau_bo_wr32(chan->notifier_bo, chan->m2mf_ntfy/4 + 3, 0xffffffff); FIRE_RING(chan); mutex_unlock(&chan->mutex); ret = -EBUSY; for (i = 0; i < 100000; i++) { - if (!nouveau_bo_rd32(chan->notifier_bo, chan->m2mf_ntfy + 3)) { + if (!nouveau_bo_rd32(chan->notifier_bo, chan->m2mf_ntfy/4 + 3)) { ret = 0; break; } -- cgit v0.10.2 From e4ac93bf3c05bbe9fed1498a1461a8cdaf4b944d Mon Sep 17 00:00:00 2001 From: Marcin Slusarz Date: Tue, 19 Apr 2011 23:52:42 +0200 Subject: drm/nouveau: fix allocation of notifier object Commit 73412c3854c877e5f37ad944ee8977addde4d35a ("drm/nouveau: allocate kernel's notifier object at end of block") intended to align end of notifier block to page boundary, but start of block was miscalculated to be off by -16 bytes. Fix it. Signed-off-by: Marcin Slusarz Cc: Ben Skeggs Signed-off-by: Ben Skeggs diff --git a/drivers/gpu/drm/nouveau/nouveau_dma.c b/drivers/gpu/drm/nouveau/nouveau_dma.c index ce38e97..568caed 100644 --- a/drivers/gpu/drm/nouveau/nouveau_dma.c +++ b/drivers/gpu/drm/nouveau/nouveau_dma.c @@ -83,7 +83,7 @@ nouveau_dma_init(struct nouveau_channel *chan) return ret; /* NV_MEMORY_TO_MEMORY_FORMAT requires a notifier object */ - ret = nouveau_notifier_alloc(chan, NvNotify0, 32, 0xfd0, 0x1000, + ret = nouveau_notifier_alloc(chan, NvNotify0, 32, 0xfe0, 0x1000, &chan->m2mf_ntfy); if (ret) return ret; -- cgit v0.10.2 From 0f6db2172ffa478409b5facd06bcd38a03b504f7 Mon Sep 17 00:00:00 2001 From: Niels de Vos Date: Mon, 18 Apr 2011 15:26:03 +0100 Subject: parport_pc.c: correctly release the requested region for the IT887x Replace release_resource() by release_region() and also fix the inconsistency in the size of the requested/released region. The size of the resource should be 32, not 0x8 like it was corrected in commit e7c310c36e5fdf1b83a459e5db167bfbd86137db already. CC: linux-serial@vger.kernel.org Reported-by: Julia Lawall Signed-off-by: Niels de Vos Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/parport/parport_pc.c b/drivers/parport/parport_pc.c index a3755ff..bc8ce48 100644 --- a/drivers/parport/parport_pc.c +++ b/drivers/parport/parport_pc.c @@ -2550,7 +2550,6 @@ static int __devinit sio_ite_8872_probe(struct pci_dev *pdev, int autoirq, const struct parport_pc_via_data *via) { short inta_addr[6] = { 0x2A0, 0x2C0, 0x220, 0x240, 0x1E0 }; - struct resource *base_res; u32 ite8872set; u32 ite8872_lpt, ite8872_lpthi; u8 ite8872_irq, type; @@ -2561,8 +2560,7 @@ static int __devinit sio_ite_8872_probe(struct pci_dev *pdev, int autoirq, /* make sure which one chip */ for (i = 0; i < 5; i++) { - base_res = request_region(inta_addr[i], 32, "it887x"); - if (base_res) { + if (request_region(inta_addr[i], 32, "it887x")) { int test; pci_write_config_dword(pdev, 0x60, 0xe5000000 | inta_addr[i]); @@ -2571,7 +2569,7 @@ static int __devinit sio_ite_8872_probe(struct pci_dev *pdev, int autoirq, test = inb(inta_addr[i]); if (test != 0xff) break; - release_region(inta_addr[i], 0x8); + release_region(inta_addr[i], 32); } } if (i >= 5) { @@ -2635,7 +2633,7 @@ static int __devinit sio_ite_8872_probe(struct pci_dev *pdev, int autoirq, /* * Release the resource so that parport_pc_probe_port can get it. */ - release_resource(base_res); + release_region(inta_addr[i], 32); if (parport_pc_probe_port(ite8872_lpt, ite8872_lpthi, irq, PARPORT_DMA_NONE, &pdev->dev, 0)) { printk(KERN_INFO -- cgit v0.10.2 From 5680e94148a86e8c31fdc5cb0ea0d5c6810c05b0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Mon, 11 Apr 2011 10:59:09 +0200 Subject: serial/imx: read cts state only after acking cts change irq MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit If cts changes between reading the level at the cts input (USR1_RTSS) and acking the irq (USR1_RTSD) the last edge doesn't generate an irq and uart_handle_cts_change is called with a outdated value for cts. The race was introduced by commit ceca629 ([ARM] 2971/1: i.MX uart handle rts irq) Reported-by: Arwed Springer Tested-by: Arwed Springer Cc: stable@kernel.org # 2.6.14+ Signed-off-by: Uwe Kleine-König Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/tty/serial/imx.c b/drivers/tty/serial/imx.c index cb36b0d..62df72d 100644 --- a/drivers/tty/serial/imx.c +++ b/drivers/tty/serial/imx.c @@ -382,12 +382,13 @@ static void imx_start_tx(struct uart_port *port) static irqreturn_t imx_rtsint(int irq, void *dev_id) { struct imx_port *sport = dev_id; - unsigned int val = readl(sport->port.membase + USR1) & USR1_RTSS; + unsigned int val; unsigned long flags; spin_lock_irqsave(&sport->port.lock, flags); writel(USR1_RTSD, sport->port.membase + USR1); + val = readl(sport->port.membase + USR1) & USR1_RTSS; uart_handle_cts_change(&sport->port, !!val); wake_up_interruptible(&sport->port.state->port.delta_msr_wait); -- cgit v0.10.2 From 9db4e4381a8e881ff65a5d3400bfa471f84217e7 Mon Sep 17 00:00:00 2001 From: Mikhail Kshevetskiy Date: Sun, 27 Mar 2011 04:05:00 +0400 Subject: tty/n_gsm: fix bug in CRC calculation for gsm1 mode Problem description: gsm_queue() calculate a CRC for arrived frames. As a last step of CRC calculation it call gsm->fcs = gsm_fcs_add(gsm->fcs, gsm->received_fcs); This work perfectly for the case of GSM0 mode as gsm->received_fcs contain the last piece of data required to generate final CRC. gsm->received_fcs is not used for GSM1 mode. Thus we put an additional byte to CRC calculation. As result we get a wrong CRC and reject incoming frame. Signed-off-by: Mikhail Kshevetskiy Acked-by: Alan Cox Cc: stable Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/tty/n_gsm.c b/drivers/tty/n_gsm.c index 47f8cdb..74273e6 100644 --- a/drivers/tty/n_gsm.c +++ b/drivers/tty/n_gsm.c @@ -1658,8 +1658,12 @@ static void gsm_queue(struct gsm_mux *gsm) if ((gsm->control & ~PF) == UI) gsm->fcs = gsm_fcs_add_block(gsm->fcs, gsm->buf, gsm->len); - /* generate final CRC with received FCS */ - gsm->fcs = gsm_fcs_add(gsm->fcs, gsm->received_fcs); + if (gsm->encoding == 0){ + /* WARNING: gsm->received_fcs is used for gsm->encoding = 0 only. + In this case it contain the last piece of data + required to generate final CRC */ + gsm->fcs = gsm_fcs_add(gsm->fcs, gsm->received_fcs); + } if (gsm->fcs != GOOD_FCS) { gsm->bad_fcs++; if (debug & 4) -- cgit v0.10.2 From 5785e53ffa73f77fb19e378c899027afc07272bc Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Tue, 19 Apr 2011 15:24:59 -0400 Subject: drm/radeon/kms: pll tweaks for r7xx Prefer min m to max p only on pre-r7xx asics. Fixes: https://bugs.freedesktop.org/show_bug.cgi?id=36197 Signed-off-by: Alex Deucher Cc: stable@kernel.org Signed-off-by: Dave Airlie diff --git a/drivers/gpu/drm/radeon/atombios_crtc.c b/drivers/gpu/drm/radeon/atombios_crtc.c index 9d516a8..529a3a7 100644 --- a/drivers/gpu/drm/radeon/atombios_crtc.c +++ b/drivers/gpu/drm/radeon/atombios_crtc.c @@ -532,10 +532,7 @@ static u32 atombios_adjust_pll(struct drm_crtc *crtc, else pll->flags |= RADEON_PLL_PREFER_LOW_REF_DIV; - if ((rdev->family == CHIP_R600) || - (rdev->family == CHIP_RV610) || - (rdev->family == CHIP_RV630) || - (rdev->family == CHIP_RV670)) + if (rdev->family < CHIP_RV770) pll->flags |= RADEON_PLL_PREFER_MINM_OVER_MAXP; } else { pll->flags |= RADEON_PLL_LEGACY; @@ -565,7 +562,6 @@ static u32 atombios_adjust_pll(struct drm_crtc *crtc, if (radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT)) { if (ss_enabled) { if (ss->refdiv) { - pll->flags |= RADEON_PLL_PREFER_MINM_OVER_MAXP; pll->flags |= RADEON_PLL_USE_REF_DIV; pll->reference_div = ss->refdiv; if (ASIC_IS_AVIVO(rdev)) -- cgit v0.10.2 From bcdd323b893ad3c9b7ef26b5e4a0bef974238501 Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Wed, 16 Mar 2011 15:59:35 +0200 Subject: device: add dev_WARN_ONCE it's quite useful to print the device name on the stack dump caused by WARN(), but there are other cases where we might want to use WARN_ONCE. Introduce a helper similar to dev_WARN() for that case too. Signed-off-by: Felipe Balbi Signed-off-by: Greg Kroah-Hartman diff --git a/include/linux/device.h b/include/linux/device.h index ab8dfc0..d484051 100644 --- a/include/linux/device.h +++ b/include/linux/device.h @@ -742,13 +742,17 @@ do { \ #endif /* - * dev_WARN() acts like dev_printk(), but with the key difference + * dev_WARN*() acts like dev_printk(), but with the key difference * of using a WARN/WARN_ON to get the message out, including the * file/line information and a backtrace. */ #define dev_WARN(dev, format, arg...) \ WARN(1, "Device: %s\n" format, dev_driver_string(dev), ## arg); +#define dev_WARN_ONCE(dev, condition, format, arg...) \ + WARN_ONCE(condition, "Device %s\n" format, \ + dev_driver_string(dev), ## arg) + /* Create alias, so I can be autoloaded. */ #define MODULE_ALIAS_CHARDEV(major,minor) \ MODULE_ALIAS("char-major-" __stringify(major) "-" __stringify(minor)) -- cgit v0.10.2 From 051d51bc6a867d9466a975e4d7ca51b21a9c2c4e Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Fri, 18 Mar 2011 10:12:14 +0300 Subject: efivars: memory leak on error in create_efivars_bin_attributes() This is a cut and paste bug. We intended to free ->del_var and ->new_var but we only free ->new_var. Signed-off-by: Dan Carpenter Acked-by: Mike Waychison Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/firmware/efivars.c b/drivers/firmware/efivars.c index ff0c373..ff2fe40 100644 --- a/drivers/firmware/efivars.c +++ b/drivers/firmware/efivars.c @@ -677,8 +677,8 @@ create_efivars_bin_attributes(struct efivars *efivars) return 0; out_free: - kfree(efivars->new_var); - efivars->new_var = NULL; + kfree(efivars->del_var); + efivars->del_var = NULL; kfree(efivars->new_var); efivars->new_var = NULL; return error; -- cgit v0.10.2 From 3116aabc81ccfeeb73f183ed8b1e3031520d1e59 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Fri, 18 Mar 2011 10:12:38 +0300 Subject: efivars: handle errors from register_efivars() We should unwind and return an error if register_efivars() fails. Signed-off-by: Dan Carpenter Acked-by: Mike Waychison Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/firmware/efivars.c b/drivers/firmware/efivars.c index ff2fe40..5d1ec68 100644 --- a/drivers/firmware/efivars.c +++ b/drivers/firmware/efivars.c @@ -803,6 +803,8 @@ efivars_init(void) ops.set_variable = efi.set_variable; ops.get_next_variable = efi.get_next_variable; error = register_efivars(&__efivars, &ops, efi_kobj); + if (error) + goto err_put; /* Don't forget the systab entry */ error = sysfs_create_group(efi_kobj, &efi_subsys_attr_group); @@ -810,10 +812,15 @@ efivars_init(void) printk(KERN_ERR "efivars: Sysfs attribute export failed with error %d.\n", error); - unregister_efivars(&__efivars); - kobject_put(efi_kobj); + goto err_unregister; } + return 0; + +err_unregister: + unregister_efivars(&__efivars); +err_put: + kobject_put(efi_kobj); return error; } -- cgit v0.10.2 From 695cca8763078c743417886e80af8ccb78bec9f2 Mon Sep 17 00:00:00 2001 From: Mike Waychison Date: Fri, 18 Mar 2011 16:50:03 -0700 Subject: firmware: Fix grammar in sysfs-firmware-dmi doc Fix the grammar in describing the position attribute of DMI entries in the dmi-sysfs module. While here, make a couple other small clarifying fixups to the docs. Reported-by: Signed-off-by: Mike Waychison Signed-off-by: Greg Kroah-Hartman diff --git a/Documentation/ABI/testing/sysfs-firmware-dmi b/Documentation/ABI/testing/sysfs-firmware-dmi index ba9da95..c78f9ab 100644 --- a/Documentation/ABI/testing/sysfs-firmware-dmi +++ b/Documentation/ABI/testing/sysfs-firmware-dmi @@ -14,14 +14,15 @@ Description: DMI is structured as a large table of entries, where each entry has a common header indicating the type and - length of the entry, as well as 'handle' that is - supposed to be unique amongst all entries. + length of the entry, as well as a firmware-provided + 'handle' that is supposed to be unique amongst all + entries. Some entries are required by the specification, but many others are optional. In general though, users should never expect to find a specific entry type on their system unless they know for certain what their firmware - is doing. Machine to machine will vary. + is doing. Machine to machine experiences will vary. Multiple entries of the same type are allowed. In order to handle these duplicate entry types, each entry is @@ -67,25 +68,24 @@ Description: and the two terminating nul characters. type : The type of the entry. This value is the same as found in the directory name. It indicates - how the rest of the entry should be - interpreted. + how the rest of the entry should be interpreted. instance: The instance ordinal of the entry for the given type. This value is the same as found in the parent directory name. - position: The position of the entry within the entirety - of the entirety. + position: The ordinal position (zero-based) of the entry + within the entirety of the DMI entry table. === Entry Specialization === Some entry types may have other information available in - sysfs. + sysfs. Not all types are specialized. --- Type 15 - System Event Log --- This entry allows the firmware to export a log of events the system has taken. This information is typically backed by nvram, but the implementation - details are abstracted by this table. This entries data + details are abstracted by this table. This entry's data is exported in the directory: /sys/firmware/dmi/entries/15-0/system_event_log -- cgit v0.10.2 From aed65af1cc2f6fc9ded5a8158f1405a02cf6d2ff Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Mon, 28 Mar 2011 09:12:52 -0700 Subject: drivers: make device_type const The device_type structure does not contain data that changes during usage and should be const. This allows devices to declare the struct const. I have patches to change all the subsystems, but need the infra structure change first. Signed-off-by: Stephen Hemminger Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/base/core.c b/drivers/base/core.c index 81b78ed..fb8130c 100644 --- a/drivers/base/core.c +++ b/drivers/base/core.c @@ -400,7 +400,7 @@ static void device_remove_groups(struct device *dev, static int device_add_attrs(struct device *dev) { struct class *class = dev->class; - struct device_type *type = dev->type; + const struct device_type *type = dev->type; int error; if (class) { @@ -440,7 +440,7 @@ static int device_add_attrs(struct device *dev) static void device_remove_attrs(struct device *dev) { struct class *class = dev->class; - struct device_type *type = dev->type; + const struct device_type *type = dev->type; device_remove_groups(dev, dev->groups); diff --git a/include/linux/device.h b/include/linux/device.h index d484051..350ceda 100644 --- a/include/linux/device.h +++ b/include/linux/device.h @@ -408,7 +408,7 @@ struct device { struct kobject kobj; const char *init_name; /* initial name of the device */ - struct device_type *type; + const struct device_type *type; struct mutex mutex; /* mutex to synchronize calls to * its driver. -- cgit v0.10.2 From 088ab0b4d855d68a0f0c16b72fb8e492a533aaa1 Mon Sep 17 00:00:00 2001 From: Ludwig Nussel Date: Mon, 28 Feb 2011 15:57:17 +0100 Subject: kernel/ksysfs.c: expose file_caps_enabled in sysfs A kernel booted with no_file_caps allows to install fscaps on a binary but doesn't actually honor the fscaps when running the binary. Userspace currently has no sane way to determine whether installing fscaps actually has any effect. Since parsing /proc/cmdline is fragile this patch exposes the current setting (1 or 0) via /sys/kernel/fscaps Signed-off-by: Ludwig Nussel Signed-off-by: Greg Kroah-Hartman diff --git a/Documentation/ABI/testing/sysfs-kernel-fscaps b/Documentation/ABI/testing/sysfs-kernel-fscaps new file mode 100644 index 0000000..50a3033 --- /dev/null +++ b/Documentation/ABI/testing/sysfs-kernel-fscaps @@ -0,0 +1,8 @@ +What: /sys/kernel/fscaps +Date: February 2011 +KernelVersion: 2.6.38 +Contact: Ludwig Nussel +Description + Shows whether file system capabilities are honored + when executing a binary + diff --git a/kernel/ksysfs.c b/kernel/ksysfs.c index 0b624e7..3b053c0 100644 --- a/kernel/ksysfs.c +++ b/kernel/ksysfs.c @@ -16,6 +16,7 @@ #include #include #include +#include #define KERNEL_ATTR_RO(_name) \ static struct kobj_attribute _name##_attr = __ATTR_RO(_name) @@ -131,6 +132,14 @@ KERNEL_ATTR_RO(vmcoreinfo); #endif /* CONFIG_KEXEC */ +/* whether file capabilities are enabled */ +static ssize_t fscaps_show(struct kobject *kobj, + struct kobj_attribute *attr, char *buf) +{ + return sprintf(buf, "%d\n", file_caps_enabled); +} +KERNEL_ATTR_RO(fscaps); + /* * Make /sys/kernel/notes give the raw contents of our kernel .notes section. */ @@ -158,6 +167,7 @@ struct kobject *kernel_kobj; EXPORT_SYMBOL_GPL(kernel_kobj); static struct attribute * kernel_attrs[] = { + &fscaps_attr.attr, #if defined(CONFIG_HOTPLUG) &uevent_seqnum_attr.attr, &uevent_helper_attr.attr, -- cgit v0.10.2 From 5934b5f3b0116858a5f950abcac344ddee054b69 Mon Sep 17 00:00:00 2001 From: Tsugikazu Shibata Date: Mon, 4 Apr 2011 11:47:36 +0900 Subject: HOWTO: sync up Documentaion/ja_JP/HOWTO Signed-off-by: Tsugikazu Shibata Signed-off-by: Greg Kroah-Hartman diff --git a/Documentation/ja_JP/HOWTO b/Documentation/ja_JP/HOWTO index b63301a..050d37f 100644 --- a/Documentation/ja_JP/HOWTO +++ b/Documentation/ja_JP/HOWTO @@ -11,14 +11,14 @@ for non English (read: Japanese) speakers and is not intended as a fork. So if you have any comments or updates for this file, please try to update the original English file first. -Last Updated: 2008/10/24 +Last Updated: 2011/03/31 ================================== ã“ã‚Œã¯ã€ -linux-2.6.28/Documentation/HOWTO +linux-2.6.38/Documentation/HOWTO ã®å’Œè¨³ã§ã™ã€‚ 翻訳団体: JF プロジェクト < http://www.linux.or.jp/JF/ > -翻訳日: 2008/10/24 +翻訳日: 2011/3/28 翻訳者: Tsugikazu Shibata 校正者: æ¾å€‰ã•ã‚“ å°æž— é›…å…¸ã•ã‚“ (Masanori Kobayasi) @@ -256,8 +256,8 @@ Linux カーãƒãƒ«ã®é–‹ç™ºãƒ—ロセスã¯ç¾åœ¨å¹¾ã¤ã‹ã®ç•°ãªã‚‹ãƒ¡ã‚¤ãƒ³ - メイン㮠2.6.x カーãƒãƒ«ãƒ„リー - 2.6.x.y -stable カーãƒãƒ«ãƒ„リー - 2.6.x -git カーãƒãƒ«ãƒ‘ッム- - 2.6.x -mm カーãƒãƒ«ãƒ‘ッム- サブシステム毎ã®ã‚«ãƒ¼ãƒãƒ«ãƒ„リーã¨ãƒ‘ッム+ - çµ±åˆãƒ†ã‚¹ãƒˆã®ãŸã‚ã® 2.6.x -next カーãƒãƒ«ãƒ„リー 2.6.x カーãƒãƒ«ãƒ„リー ----------------- @@ -268,9 +268,9 @@ Linux カーãƒãƒ«ã®é–‹ç™ºãƒ—ロセスã¯ç¾åœ¨å¹¾ã¤ã‹ã®ç•°ãªã‚‹ãƒ¡ã‚¤ãƒ³ - æ–°ã—ã„カーãƒãƒ«ãŒãƒªãƒªãƒ¼ã‚¹ã•ã‚ŒãŸç›´å¾Œã«ã€2週間ã®ç‰¹åˆ¥æœŸé–“ãŒè¨­ã‘られ〠ã“ã®æœŸé–“中ã«ã€ãƒ¡ãƒ³ãƒ†ãƒŠé”㯠Linus ã«å¤§ããªå·®åˆ†ã‚’é€ã‚‹ã“ã¨ãŒã§ãã¾ã™ã€‚ - ã“ã®ã‚ˆã†ãªå·®åˆ†ã¯é€šå¸¸ -mm カーãƒãƒ«ã«æ•°é€±é–“å«ã¾ã‚Œã¦ããŸãƒ‘ッãƒã§ã™ã€‚ + ã“ã®ã‚ˆã†ãªå·®åˆ†ã¯é€šå¸¸ -next カーãƒãƒ«ã«æ•°é€±é–“å«ã¾ã‚Œã¦ããŸãƒ‘ッãƒã§ã™ã€‚ 大ããªå¤‰æ›´ã¯ git(カーãƒãƒ«ã®ã‚½ãƒ¼ã‚¹ç®¡ç†ãƒ„ールã€è©³ç´°ã¯ - http://git.or.cz/ å‚ç…§) を使ã£ã¦é€ã‚‹ã®ãŒå¥½ã¾ã—ã„ã‚„ã‚Šæ–¹ã§ã™ãŒã€ãƒ‘ッ + http://git-scm.com/ å‚ç…§) を使ã£ã¦é€ã‚‹ã®ãŒå¥½ã¾ã—ã„ã‚„ã‚Šæ–¹ã§ã™ãŒã€ãƒ‘ッ ãƒãƒ•ã‚¡ã‚¤ãƒ«ã®å½¢å¼ã®ã¾ã¾é€ã‚‹ã®ã§ã‚‚å分ã§ã™ã€‚ - 2週間後ã€-rc1 カーãƒãƒ«ãŒãƒªãƒªãƒ¼ã‚¹ã•ã‚Œã€ã“ã®å¾Œã«ã¯ã‚«ãƒ¼ãƒãƒ«å…¨ä½“ã®å®‰å®š @@ -333,86 +333,44 @@ git リãƒã‚¸ãƒˆãƒªã§ç®¡ç†ã•ã‚Œã¦ã„ã‚‹Linus ã®ã‚«ãƒ¼ãƒãƒ«ãƒ„リーã®æ¯Ž れ㯠-rc カーãƒãƒ«ã¨æ¯”ã¹ã¦ã€ãƒ‘ッãƒãŒå¤§ä¸ˆå¤«ã‹ã©ã†ã‹ã‚‚確èªã—ãªã„ã§è‡ªå‹•çš„ ã«ç”Ÿæˆã•ã‚Œã‚‹ã®ã§ã€ã‚ˆã‚Šå®Ÿé¨“çš„ã§ã™ã€‚ -2.6.x -mm カーãƒãƒ«ãƒ‘ッム------------------------- - -Andrew Morton ã«ã‚ˆã£ã¦ãƒªãƒªãƒ¼ã‚¹ã•ã‚Œã‚‹å®Ÿé¨“çš„ãªã‚«ãƒ¼ãƒãƒ«ãƒ‘ッãƒç¾¤ã§ã™ã€‚ -Andrew ã¯å€‹åˆ¥ã®ã‚µãƒ–システムカーãƒãƒ«ãƒ„リーã¨ãƒ‘ッãƒã‚’å…¨ã¦é›†ã‚ã¦ã㦠-linux-kernel メーリングリストã§åŽé›†ã•ã‚ŒãŸå¤šæ•°ã®ãƒ‘ッãƒã¨åŒæ™‚ã«ä¸€ã¤ã«ã¾ -ã¨ã‚ã¾ã™ã€‚ -ã“ã®ãƒ„リーã¯æ–°æ©Ÿèƒ½ã¨ãƒ‘ッãƒãŒæ¤œè¨¼ã•ã‚Œã‚‹å ´ã¨ãªã‚Šã¾ã™ã€‚ã‚る期間ã®é–“パッム-㌠-mm ã«å…¥ã£ã¦ä¾¡å€¤ã‚’証明ã•ã‚ŒãŸã‚‰ã€Andrew やサブシステムメンテナãŒã€ -メインラインã¸å…¥ã‚Œã‚‹ã‚ˆã†ã« Linus ã«ãƒ—ッシュã—ã¾ã™ã€‚ - -メインカーãƒãƒ«ãƒ„リーã«å«ã‚ã‚‹ãŸã‚ã« Linus ã«é€ã‚‹å‰ã«ã€ã™ã¹ã¦ã®æ–°ã—ã„パッ -ãƒãŒ -mm ツリーã§ãƒ†ã‚¹ãƒˆã•ã‚Œã‚‹ã“ã¨ãŒå¼·ã推奨ã•ã‚Œã¦ã„ã¾ã™ã€‚マージウィン -ドウãŒé–‹ãå‰ã« -mm ツリーã«ç¾ã‚Œãªã‹ã£ãŸãƒ‘ッãƒã¯ãƒ¡ã‚¤ãƒ³ãƒ©ã‚¤ãƒ³ã«ãƒžãƒ¼ã‚¸ã• -れるã“ã¨ã¯å›°é›£ã«ãªã‚Šã¾ã™ã€‚ - -ã“れらã®ã‚«ãƒ¼ãƒãƒ«ã¯å®‰å®šã—ã¦å‹•ä½œã™ã¹ãシステムã¨ã—ã¦ä½¿ã†ã®ã«ã¯é©åˆ‡ã§ã¯ã‚ -ã‚Šã¾ã›ã‚“ã—ã€ã‚«ãƒ¼ãƒãƒ«ãƒ–ランãƒã®ä¸­ã§ã‚‚ã‚‚ã£ã¨ã‚‚動作ã«ãƒªã‚¹ã‚¯ãŒé«˜ã„ã‚‚ã®ã§ã™ã€‚ - -ã‚‚ã—ã‚ãªãŸãŒã€ã‚«ãƒ¼ãƒãƒ«é–‹ç™ºãƒ—ロセスã®æ”¯æ´ã‚’ã—ãŸã„ã¨æ€ã£ã¦ã„ã‚‹ã®ã§ã‚ã‚Œã°ã€ -ã©ã†ãžã“れらã®ã‚«ãƒ¼ãƒãƒ«ãƒªãƒªãƒ¼ã‚¹ã‚’テストã«ä½¿ã£ã¦ã¿ã¦ã€ãã—ã¦ã‚‚ã—å•é¡ŒãŒã‚ -ã‚Œã°ã€ã¾ãŸã‚‚ã—å…¨ã¦ãŒæ­£ã—ã動作ã—ãŸã¨ã—ã¦ã‚‚ã€linux-kernel メーリングリ -ストã«ãƒ•ã‚£ãƒ¼ãƒ‰ãƒãƒƒã‚¯ã‚’æä¾›ã—ã¦ãã ã•ã„。 - -ã™ã¹ã¦ã®ä»–ã®å®Ÿé¨“的パッãƒã«åŠ ãˆã¦ã€ã“れらã®ã‚«ãƒ¼ãƒãƒ«ã¯é€šå¸¸ãƒªãƒªãƒ¼ã‚¹æ™‚点㧠-メインライン㮠-git カーãƒãƒ«ã«å«ã¾ã‚Œã‚‹å…¨ã¦ã®å¤‰æ›´ã‚‚å«ã‚“ã§ã„ã¾ã™ã€‚ - --mm カーãƒãƒ«ã¯æ±ºã¾ã£ãŸã‚¹ã‚±ã‚¸ãƒ¥ãƒ¼ãƒ«ã§ã¯ãƒªãƒªãƒ¼ã‚¹ã•ã‚Œã¾ã›ã‚“ã€ã—ã‹ã—通常幾 -ã¤ã‹ã® -mm カーãƒãƒ« (1 ã‹ã‚‰ 3 ãŒæ™®é€šï¼‰ãŒå„-rc カーãƒãƒ«ã®é–“ã«ãƒªãƒªãƒ¼ã‚¹ã• -ã‚Œã¾ã™ã€‚ - サブシステム毎ã®ã‚«ãƒ¼ãƒãƒ«ãƒ„リーã¨ãƒ‘ッム------------------------------------------- -カーãƒãƒ«ã®æ§˜ã€…ãªé ˜åŸŸã§ä½•ãŒèµ·ãã¦ã„ã‚‹ã‹ã‚’見られるよã†ã«ã™ã‚‹ãŸã‚ã€å¤šãã® -カーãƒãƒ«ã‚µãƒ–システム開発者ã¯å½¼ã‚‰ã®é–‹ç™ºãƒ„リーを公開ã—ã¦ã„ã¾ã™ã€‚ã“れら㮠-ツリーã¯èª¬æ˜Žã—ãŸã‚ˆã†ã« -mm カーãƒãƒ«ãƒªãƒªãƒ¼ã‚¹ã«å…¥ã‚Œè¾¼ã¾ã‚Œã¾ã™ã€‚ - -以下ã¯ã•ã¾ã–ã¾ãªã‚«ãƒ¼ãƒãƒ«ãƒ„リーã®ä¸­ã®ã„ãã¤ã‹ã®ãƒªã‚¹ãƒˆ- - - git ツリー- - - Kbuild ã®é–‹ç™ºãƒ„リーã€Sam Ravnborg - git.kernel.org:/pub/scm/linux/kernel/git/sam/kbuild.git - - - ACPI ã®é–‹ç™ºãƒ„リー〠Len Brown - git.kernel.org:/pub/scm/linux/kernel/git/lenb/linux-acpi-2.6.git - - - Block ã®é–‹ç™ºãƒ„リーã€Jens Axboe - git.kernel.org:/pub/scm/linux/kernel/git/axboe/linux-2.6-block.git - - - DRM ã®é–‹ç™ºãƒ„リーã€Dave Airlie - git.kernel.org:/pub/scm/linux/kernel/git/airlied/drm-2.6.git - - - ia64 ã®é–‹ç™ºãƒ„リーã€Tony Luck - git.kernel.org:/pub/scm/linux/kernel/git/aegl/linux-2.6.git - - - infiniband, Roland Dreier - git.kernel.org:/pub/scm/linux/kernel/git/roland/infiniband.git - - - libata, Jeff Garzik - git.kernel.org:/pub/scm/linux/kernel/git/jgarzik/libata-dev.git - - - ãƒãƒƒãƒˆãƒ¯ãƒ¼ã‚¯ãƒ‰ãƒ©ã‚¤ãƒ, Jeff Garzik - git.kernel.org:/pub/scm/linux/kernel/git/jgarzik/netdev-2.6.git - - - pcmcia, Dominik Brodowski - git.kernel.org:/pub/scm/linux/kernel/git/brodo/pcmcia-2.6.git - - - SCSI, James Bottomley - git.kernel.org:/pub/scm/linux/kernel/git/jejb/scsi-misc-2.6.git - - - x86, Ingo Molnar - git://git.kernel.org/pub/scm/linux/kernel/git/x86/linux-2.6-x86.git - - quilt ツリー- - - USB, ドライãƒã‚³ã‚¢ã¨ I2C, Greg Kroah-Hartman - kernel.org/pub/linux/kernel/people/gregkh/gregkh-2.6/ +ãã‚Œãžã‚Œã®ã‚«ãƒ¼ãƒãƒ«ã‚µãƒ–システムã®ãƒ¡ãƒ³ãƒ†ãƒŠé”㯠--- ãã—ã¦å¤šãã®ã‚«ãƒ¼ãƒãƒ« +サブシステムã®é–‹ç™ºè€…é”ã‚‚ --- å„自ã®æœ€æ–°ã®é–‹ç™ºçŠ¶æ³ã‚’ソースリãƒã‚¸ãƒˆãƒªã« +公開ã—ã¦ã„ã¾ã™ã€‚ãã®ãŸã‚ã€è‡ªåˆ†ã¨ã¯ç•°ãªã‚‹é ˜åŸŸã®ã‚«ãƒ¼ãƒãƒ«ã§ä½•ãŒèµ·ãã¦ã„ã‚‹ +ã‹ã‚’ä»–ã®äººãŒè¦‹ã‚‰ã‚Œã‚‹ã‚ˆã†ã«ãªã£ã¦ã„ã¾ã™ã€‚開発ãŒæ—©ã進んã§ã„る領域ã§ã¯ã€ +開発者ã¯è‡ªèº«ã®æŠ•ç¨¿ãŒã©ã®ã‚µãƒ–システムカーãƒãƒ«ãƒ„リーを元ã«ã—ã¦ã„ã‚‹ã‹è³ªå• +ã•ã‚Œã‚‹ã®ã§ã€ãã®æŠ•ç¨¿ã¨ã™ã§ã«é€²è¡Œä¸­ã®ä»–ã®ä½œæ¥­ã¨ã®è¡çªãŒé¿ã‘られã¾ã™ã€‚ + +大部分ã®ã“れらã®ãƒªãƒã‚¸ãƒˆãƒªã¯ git ツリーã§ã™ã€‚ã—ã‹ã—ãã®ä»–ã® SCM ã‚„ +quilt シリーズã¨ã—ã¦å…¬é–‹ã•ã‚Œã¦ã„るパッãƒã‚­ãƒ¥ãƒ¼ã‚‚使ã‚ã‚Œã¦ã„ã¾ã™ã€‚ã“れら +ã®ã‚µãƒ–システムリãƒã‚¸ãƒˆãƒªã®ã‚¢ãƒ‰ãƒ¬ã‚¹ã¯ MAINTAINERS ファイルã«ãƒªã‚¹ãƒˆã•ã‚Œ +ã¦ã„ã¾ã™ã€‚ã“れらã®å¤šã㯠http://git.kernel.org/ ã§å‚ç…§ã™ã‚‹ã“ã¨ãŒã§ãã¾ +ã™ã€‚ - ãã®ä»–ã®ã‚«ãƒ¼ãƒãƒ«ãƒ„リー㯠http://git.kernel.org/ 㨠MAINTAINERS ファ - イルã«ä¸€è¦§è¡¨ãŒã‚ã‚Šã¾ã™ã€‚ +æ案ã•ã‚ŒãŸãƒ‘ッãƒãŒã“ã®ã‚ˆã†ãªã‚µãƒ–システムツリーã«ã‚³ãƒŸãƒƒãƒˆã•ã‚Œã‚‹å‰ã«ã€ãƒ¡ãƒ¼ +リングリストã§äº‹å‰ã«ãƒ¬ãƒ“ューã«ã‹ã‘られã¾ã™ï¼ˆä»¥ä¸‹ã®å¯¾å¿œã™ã‚‹ã‚»ã‚¯ã‚·ãƒ§ãƒ³ã‚’ +å‚照)。ã„ãã¤ã‹ã®ã‚«ãƒ¼ãƒãƒ«ã‚µãƒ–システムã§ã¯ã€ã“ã®ãƒ¬ãƒ“ュー㯠patchwork +ã¨ã„ã†ãƒ„ールã«ã‚ˆã£ã¦è¿½è·¡ã•ã‚Œã¾ã™ã€‚Patchwork 㯠web インターフェイス㫠+よã£ã¦ãƒ‘ッãƒæŠ•ç¨¿ã®è¡¨ç¤ºã€ãƒ‘ッãƒã¸ã®ã‚³ãƒ¡ãƒ³ãƒˆä»˜ã‘や改訂ãªã©ãŒã§ãã€ãã—㦠+メンテナã¯ãƒ‘ッãƒã«å¯¾ã—ã¦ã€ãƒ¬ãƒ“ュー中ã€å—付済ã¿ã€æ‹’å¦ã¨ã„ã†ã‚ˆã†ãªãƒžãƒ¼ã‚¯ +ã‚’ã¤ã‘ã‚‹ã“ã¨ãŒã§ãã¾ã™ã€‚大部分ã®ã“れら㮠patchwork ã®ã‚µã‚¤ãƒˆã¯ +http://patchwork.kernel.org/ ã§ãƒªã‚¹ãƒˆã•ã‚Œã¦ã„ã¾ã™ã€‚ + +çµ±åˆãƒ†ã‚¹ãƒˆã®ãŸã‚ã® 2.6.x -next カーãƒãƒ«ãƒ„リー +--------------------------------------------- + +サブシステムツリーã®æ›´æ–°å†…容ãŒãƒ¡ã‚¤ãƒ³ãƒ©ã‚¤ãƒ³ã® 2.6.x ツリーã«ãƒžãƒ¼ã‚¸ã•ã‚Œ +ã‚‹å‰ã«ã€ãれらã¯çµ±åˆãƒ†ã‚¹ãƒˆã•ã‚Œã‚‹å¿…è¦ãŒã‚ã‚Šã¾ã™ã€‚ã“ã®ç›®çš„ã®ãŸã‚ã€å®Ÿè³ªçš„ +ã«å…¨ã‚µãƒ–システムツリーã‹ã‚‰ã»ã¼æ¯Žæ—¥ãƒ—ルã•ã‚Œã¦ã§ãる特別ãªãƒ†ã‚¹ãƒˆç”¨ã®ãƒª +ãƒã‚¸ãƒˆãƒªãŒå­˜åœ¨ã—ã¾ã™- + http://git.kernel.org/?p=linux/kernel/git/sfr/linux-next.git + http://linux.f-seidel.de/linux-next/pmwiki/ + +ã“ã®ã‚„ã‚Šæ–¹ã«ã‚ˆã£ã¦ã€-next カーãƒãƒ«ã¯æ¬¡ã®ãƒžãƒ¼ã‚¸æ©Ÿä¼šã§ã©ã‚“ãªã‚‚ã®ãŒãƒ¡ã‚¤ãƒ³ +ラインカーãƒãƒ«ã«ãƒžãƒ¼ã‚¸ã•ã‚Œã‚‹ã‹ã€ãŠãŠã¾ã‹ãªã®å±•æœ›ã‚’æä¾›ã—ã¾ã™ã€‚-next +カーãƒãƒ«ã®å®Ÿè¡Œãƒ†ã‚¹ãƒˆã‚’è¡Œã†å†’険好ããªãƒ†ã‚¹ã‚¿ãƒ¼ã¯å¤§ã„ã«æ­“è¿Žã•ã‚Œã¾ã™ ãƒã‚°ãƒ¬ãƒãƒ¼ãƒˆ ------------- @@ -673,10 +631,9 @@ Linux カーãƒãƒ«ã‚³ãƒŸãƒ¥ãƒ‹ãƒ†ã‚£ã¯ã€ä¸€åº¦ã«å¤§é‡ã®ã‚³ãƒ¼ãƒ‰ã®å¡Šã‚’ ã˜ã¨ã“ã‚ã‹ã‚‰ã‚¹ã‚¿ãƒ¼ãƒˆã—ãŸã®ã§ã™ã‹ã‚‰ã€‚ Paolo Ciarrocchi ã«æ„Ÿè¬ã€å½¼ã¯å½¼ã®æ›¸ã„㟠"Development Process" -(http://linux.tar.bz/articles/2.6-development_process)セクショ -ンをã“ã®ãƒ†ã‚­ã‚¹ãƒˆã®åŽŸåž‹ã«ã™ã‚‹ã“ã¨ã‚’許å¯ã—ã¦ãã‚Œã¾ã—ãŸã€‚ -Rundy Dunlap 㨠Gerrit Huizenga ã¯ãƒ¡ãƒ¼ãƒªãƒ³ã‚°ãƒªã‚¹ãƒˆã§ã‚„ã‚‹ã¹ãã“ã¨ã¨ã‚„㣠-ã¦ã¯ã„ã‘ãªã„ã“ã¨ã®ãƒªã‚¹ãƒˆã‚’æä¾›ã—ã¦ãã‚Œã¾ã—ãŸã€‚ +(http://lwn.net/Articles/94386/) セクションをã“ã®ãƒ†ã‚­ã‚¹ãƒˆã®åŽŸåž‹ã«ã™ã‚‹ +ã“ã¨ã‚’許å¯ã—ã¦ãã‚Œã¾ã—ãŸã€‚Rundy Dunlap 㨠Gerrit Huizenga ã¯ãƒ¡ãƒ¼ãƒªãƒ³ã‚° +リストã§ã‚„ã‚‹ã¹ãã“ã¨ã¨ã‚„ã£ã¦ã¯ã„ã‘ãªã„ã“ã¨ã®ãƒªã‚¹ãƒˆã‚’æä¾›ã—ã¦ãã‚Œã¾ã—ãŸã€‚ 以下ã®äººã€…ã®ãƒ¬ãƒ“ューã€ã‚³ãƒ¡ãƒ³ãƒˆã€è²¢çŒ®ã«æ„Ÿè¬ã€‚ Pat Mochel, Hanna Linder, Randy Dunlap, Kay Sievers, Vojtech Pavlik, Jan Kara, Josh Boyer, Kees Cook, Andrew Morton, Andi -- cgit v0.10.2 From 5cf4c80a145d79db928ff55226e731de55c87644 Mon Sep 17 00:00:00 2001 From: Kevin Hilman Date: Tue, 19 Apr 2011 16:52:56 -0700 Subject: davinci: fix DEBUG_LL code for p2v changes Fixup davinci UART low-level debug code for new ARM generic p2v changes. Based on OMAP changes by Tony Lindgren Cc: Tony Lindgren Signed-off-by: Kevin Hilman diff --git a/arch/arm/mach-davinci/include/mach/debug-macro.S b/arch/arm/mach-davinci/include/mach/debug-macro.S index 9f1befc..f8b7ea4 100644 --- a/arch/arm/mach-davinci/include/mach/debug-macro.S +++ b/arch/arm/mach-davinci/include/mach/debug-macro.S @@ -24,6 +24,9 @@ #define UART_SHIFT 2 +#define davinci_uart_v2p(x) ((x) - PAGE_OFFSET + PLAT_PHYS_OFFSET) +#define davinci_uart_p2v(x) ((x) - PLAT_PHYS_OFFSET + PAGE_OFFSET) + .pushsection .data davinci_uart_phys: .word 0 davinci_uart_virt: .word 0 @@ -34,7 +37,7 @@ davinci_uart_virt: .word 0 /* Use davinci_uart_phys/virt if already configured */ 10: mrc p15, 0, \rp, c1, c0 tst \rp, #1 @ MMU enabled? - ldreq \rp, =__virt_to_phys(davinci_uart_phys) + ldreq \rp, =davinci_uart_v2p(davinci_uart_phys) ldrne \rp, =davinci_uart_phys add \rv, \rp, #4 @ davinci_uart_virt ldr \rp, [\rp, #0] @@ -48,18 +51,18 @@ davinci_uart_virt: .word 0 tst \rp, #1 @ MMU enabled? /* Copy uart phys address from decompressor uart info */ - ldreq \rv, =__virt_to_phys(davinci_uart_phys) + ldreq \rv, =davinci_uart_v2p(davinci_uart_phys) ldrne \rv, =davinci_uart_phys ldreq \rp, =DAVINCI_UART_INFO - ldrne \rp, =__phys_to_virt(DAVINCI_UART_INFO) + ldrne \rp, =davinci_uart_p2v(DAVINCI_UART_INFO) ldr \rp, [\rp, #0] str \rp, [\rv] /* Copy uart virt address from decompressor uart info */ - ldreq \rv, =__virt_to_phys(davinci_uart_virt) + ldreq \rv, =davinci_uart_v2p(davinci_uart_virt) ldrne \rv, =davinci_uart_virt ldreq \rp, =DAVINCI_UART_INFO - ldrne \rp, =__phys_to_virt(DAVINCI_UART_INFO) + ldrne \rp, =davinci_uart_p2v(DAVINCI_UART_INFO) ldr \rp, [\rp, #4] str \rp, [\rv] diff --git a/arch/arm/mach-davinci/include/mach/serial.h b/arch/arm/mach-davinci/include/mach/serial.h index 8051110..c9e6ce1 100644 --- a/arch/arm/mach-davinci/include/mach/serial.h +++ b/arch/arm/mach-davinci/include/mach/serial.h @@ -22,7 +22,7 @@ * * This area sits just below the page tables (see arch/arm/kernel/head.S). */ -#define DAVINCI_UART_INFO (PHYS_OFFSET + 0x3ff8) +#define DAVINCI_UART_INFO (PLAT_PHYS_OFFSET + 0x3ff8) #define DAVINCI_UART0_BASE (IO_PHYS + 0x20000) #define DAVINCI_UART1_BASE (IO_PHYS + 0x20400) -- cgit v0.10.2 From d8408aef910b5d538ae07218992b270a9e01067f Mon Sep 17 00:00:00 2001 From: Daniel Trautmann Date: Mon, 21 Mar 2011 15:36:35 +0100 Subject: uio_netx: Add support for netPLC cards This patch adds support for Hilscher / IBHsoftec netPLC cards to uio_netx userspace IO driver. Changes from v1 -> v2: Fixed whitespace errors reported by scripts/checkpatch.pl which were caused by email client. Signed-off-by: Daniel Trautmann Signed-off-by: "Hans J. Koch" Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/uio/uio_netx.c b/drivers/uio/uio_netx.c index 5ffdb48..a879fd5 100644 --- a/drivers/uio/uio_netx.c +++ b/drivers/uio/uio_netx.c @@ -18,6 +18,9 @@ #define PCI_VENDOR_ID_HILSCHER 0x15CF #define PCI_DEVICE_ID_HILSCHER_NETX 0x0000 +#define PCI_DEVICE_ID_HILSCHER_NETPLC 0x0010 +#define PCI_SUBDEVICE_ID_NETPLC_RAM 0x0000 +#define PCI_SUBDEVICE_ID_NETPLC_FLASH 0x0001 #define PCI_SUBDEVICE_ID_NXSB_PCA 0x3235 #define PCI_SUBDEVICE_ID_NXPCA 0x3335 @@ -66,6 +69,10 @@ static int __devinit netx_pci_probe(struct pci_dev *dev, bar = 0; info->name = "netx"; break; + case PCI_DEVICE_ID_HILSCHER_NETPLC: + bar = 0; + info->name = "netplc"; + break; default: bar = 2; info->name = "netx_plx"; @@ -134,6 +141,18 @@ static struct pci_device_id netx_pci_ids[] = { .subdevice = 0, }, { + .vendor = PCI_VENDOR_ID_HILSCHER, + .device = PCI_DEVICE_ID_HILSCHER_NETPLC, + .subvendor = PCI_VENDOR_ID_HILSCHER, + .subdevice = PCI_SUBDEVICE_ID_NETPLC_RAM, + }, + { + .vendor = PCI_VENDOR_ID_HILSCHER, + .device = PCI_DEVICE_ID_HILSCHER_NETPLC, + .subvendor = PCI_VENDOR_ID_HILSCHER, + .subdevice = PCI_SUBDEVICE_ID_NETPLC_FLASH, + }, + { .vendor = PCI_VENDOR_ID_PLX, .device = PCI_DEVICE_ID_PLX_9030, .subvendor = PCI_VENDOR_ID_PLX, -- cgit v0.10.2 From f0c554fddd3be561542cd37acdb3adc9ec5483ee Mon Sep 17 00:00:00 2001 From: Hillf Danton Date: Mon, 28 Mar 2011 23:33:26 +0200 Subject: uio: fix finding mm index for vma When finding mm index for vma it looks more flexible that the mm could be sparse, and both the size of mm and the pgoff of vma could give correct selection. Signed-off-by: Hillf Danton Signed-off-by: Hans J. Koch Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/uio/uio.c b/drivers/uio/uio.c index 51fe179..10a029b 100644 --- a/drivers/uio/uio.c +++ b/drivers/uio/uio.c @@ -587,14 +587,12 @@ static ssize_t uio_write(struct file *filep, const char __user *buf, static int uio_find_mem_index(struct vm_area_struct *vma) { - int mi; struct uio_device *idev = vma->vm_private_data; - for (mi = 0; mi < MAX_UIO_MAPS; mi++) { - if (idev->info->mem[mi].size == 0) + if (vma->vm_pgoff < MAX_UIO_MAPS) { + if (idev->info->mem[vma->vm_pgoff].size == 0) return -1; - if (vma->vm_pgoff == mi) - return mi; + return (int)vma->vm_pgoff; } return -1; } -- cgit v0.10.2 From c6edc42fe1b5562abae22beabbebd9e557527ae3 Mon Sep 17 00:00:00 2001 From: Hillf Danton Date: Thu, 31 Mar 2011 20:38:47 +0800 Subject: uio: fix allocating minor id for uio device The number of uio devices that could be used should be less than UIO_MAX_DEVICES by design, and this work guards any cases in which id more than UIO_MAX_DEVICES is utilized. Signed-off-by: Hillf Danton Signed-off-by: Hans J. Koch Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/uio/uio.c b/drivers/uio/uio.c index 10a029b..d2efe82 100644 --- a/drivers/uio/uio.c +++ b/drivers/uio/uio.c @@ -381,7 +381,13 @@ static int uio_get_minor(struct uio_device *idev) retval = -ENOMEM; goto exit; } - idev->minor = id & MAX_ID_MASK; + if (id < UIO_MAX_DEVICES) { + idev->minor = id; + } else { + dev_err(idev->dev, "too many uio devices\n"); + retval = -EINVAL; + idr_remove(&uio_idr, id); + } exit: mutex_unlock(&minor_lock); return retval; -- cgit v0.10.2 From 47296b1962ead8301488f0dbe8424c7db7eac635 Mon Sep 17 00:00:00 2001 From: Jie Zhou Date: Wed, 6 Apr 2011 14:42:40 +0800 Subject: uio: clean uioinfo when uninstall uio driver The uioinfo should be cleaned up when uninstall, otherwise re-install failure of uio_pdrv_genirq.ko will happen. Signed-off-by: Jie Zhou Signed-off-by: Aisheng Dong Signed-off-by: Hans J. Koch Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/uio/uio_pdrv_genirq.c b/drivers/uio/uio_pdrv_genirq.c index 7174d51..0f424af 100644 --- a/drivers/uio/uio_pdrv_genirq.c +++ b/drivers/uio/uio_pdrv_genirq.c @@ -189,6 +189,10 @@ static int uio_pdrv_genirq_remove(struct platform_device *pdev) uio_unregister_device(priv->uioinfo); pm_runtime_disable(&pdev->dev); + + priv->uioinfo->handler = NULL; + priv->uioinfo->irqcontrol = NULL; + kfree(priv); return 0; } -- cgit v0.10.2 From 7e5b58bcbcb3d7518389c1d82fb6e926f5a9f72c Mon Sep 17 00:00:00 2001 From: Kay Sievers Date: Thu, 7 Apr 2011 04:29:20 +0200 Subject: printk: /dev/kmsg - properly support writev() to avoid interleaved printk() lines printk: /dev/kmsg - properly support writev() to avoid interleaved printk lines We should avoid calling printk() in a loop, when we pass a single string to /dev/kmsg with writev(). Cc: Lennart Poettering Signed-off-by: Kay Sievers Cc: Andrew Morton Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/char/mem.c b/drivers/char/mem.c index 436a990..78923a9 100644 --- a/drivers/char/mem.c +++ b/drivers/char/mem.c @@ -806,29 +806,40 @@ static const struct file_operations oldmem_fops = { }; #endif -static ssize_t kmsg_write(struct file *file, const char __user *buf, - size_t count, loff_t *ppos) +static ssize_t kmsg_writev(struct kiocb *iocb, const struct iovec *iv, + unsigned long count, loff_t pos) { - char *tmp; - ssize_t ret; + char *line, *p; + int len, i; + ssize_t ret = -EFAULT; - tmp = kmalloc(count + 1, GFP_KERNEL); - if (tmp == NULL) + len = iov_length(iv, count); + line = p = kmalloc(len + 1, GFP_KERNEL); + if (line == NULL) return -ENOMEM; - ret = -EFAULT; - if (!copy_from_user(tmp, buf, count)) { - tmp[count] = 0; - ret = printk("%s", tmp); - if (ret > count) - /* printk can add a prefix */ - ret = count; + + /* + * copy all vectors into a single string, to ensure we do + * not interleave our log line with other printk calls + */ + for (i = 0; i < count; i++) { + if (copy_from_user(p, iv[i].iov_base, iv[i].iov_len)) + goto out; + p += iv[i].iov_len; } - kfree(tmp); + p[0] = '\0'; + + ret = printk("%s", line); + /* printk can add a prefix */ + if (ret > len) + ret = len; +out: + kfree(line); return ret; } static const struct file_operations kmsg_fops = { - .write = kmsg_write, + .aio_write = kmsg_writev, .llseek = noop_llseek, }; -- cgit v0.10.2 From 70a5f52165bd04cf3b33f30d5d234be28dcf29d4 Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Tue, 12 Apr 2011 16:13:31 -0700 Subject: kmsg: properly support writev to avoid interleaved printk lines fix make `len' size_t, avoid multiple-assignments. Cc: Kay Sievers Cc: Lennart Poettering Signed-off-by: Andrew Morton Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/char/mem.c b/drivers/char/mem.c index 78923a9..8fc04b4 100644 --- a/drivers/char/mem.c +++ b/drivers/char/mem.c @@ -810,11 +810,11 @@ static ssize_t kmsg_writev(struct kiocb *iocb, const struct iovec *iv, unsigned long count, loff_t pos) { char *line, *p; - int len, i; + int i; ssize_t ret = -EFAULT; + size_t len = iov_length(iv, count); - len = iov_length(iv, count); - line = p = kmalloc(len + 1, GFP_KERNEL); + line = kmalloc(len + 1, GFP_KERNEL); if (line == NULL) return -ENOMEM; @@ -822,6 +822,7 @@ static ssize_t kmsg_writev(struct kiocb *iocb, const struct iovec *iv, * copy all vectors into a single string, to ensure we do * not interleave our log line with other printk calls */ + p = line; for (i = 0; i < count; i++) { if (copy_from_user(p, iv[i].iov_base, iv[i].iov_len)) goto out; -- cgit v0.10.2 From 211588ad1902df57beeeadc9b44546540fa4bd81 Mon Sep 17 00:00:00 2001 From: Chris Mason Date: Tue, 19 Apr 2011 20:12:40 -0400 Subject: Btrfs: do some plugging in the submit_bio threads The Btrfs submit bio threads have a small number of threads responsible for pushing down bios we've collected for a large number of devices. Since we do all the bios for a single device at once, we want to make sure we unplug and send down the bios for each device as we're done processing them. The new plugging API removed the btrfs code to unplug while processing bios, this adds it back with the new API. Signed-off-by: Chris Mason diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c index 309a57b..c7367ae 100644 --- a/fs/btrfs/volumes.c +++ b/fs/btrfs/volumes.c @@ -155,6 +155,15 @@ static noinline int run_scheduled_bios(struct btrfs_device *device) unsigned long limit; unsigned long last_waited = 0; int force_reg = 0; + struct blk_plug plug; + + /* + * this function runs all the bios we've collected for + * a particular device. We don't want to wander off to + * another device without first sending all of these down. + * So, setup a plug here and finish it off before we return + */ + blk_start_plug(&plug); bdi = blk_get_backing_dev_info(device->bdev); fs_info = device->dev_root->fs_info; @@ -294,6 +303,7 @@ loop_lock: spin_unlock(&device->io_lock); done: + blk_finish_plug(&plug); return 0; } -- cgit v0.10.2 From 204ae24dc71f794aaad4df48a0083dfedc711afb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Cano?= Date: Tue, 19 Apr 2011 11:07:13 -0400 Subject: drm/radeon/kms: fix IH writeback on r6xx+ on big endian machines MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit agd5f: fix commit message. Signed-off-by: Cedric Cano Reviewed-by: Michel Dänzer Signed-off-by: Alex Deucher Signed-off-by: Dave Airlie diff --git a/drivers/gpu/drm/radeon/evergreen.c b/drivers/gpu/drm/radeon/evergreen.c index 43fd016..e9bc135 100644 --- a/drivers/gpu/drm/radeon/evergreen.c +++ b/drivers/gpu/drm/radeon/evergreen.c @@ -2580,7 +2580,7 @@ static inline u32 evergreen_get_ih_wptr(struct radeon_device *rdev) u32 wptr, tmp; if (rdev->wb.enabled) - wptr = rdev->wb.wb[R600_WB_IH_WPTR_OFFSET/4]; + wptr = le32_to_cpu(rdev->wb.wb[R600_WB_IH_WPTR_OFFSET/4]); else wptr = RREG32(IH_RB_WPTR); diff --git a/drivers/gpu/drm/radeon/r600.c b/drivers/gpu/drm/radeon/r600.c index 15d5829..6f27593 100644 --- a/drivers/gpu/drm/radeon/r600.c +++ b/drivers/gpu/drm/radeon/r600.c @@ -3231,7 +3231,7 @@ static inline u32 r600_get_ih_wptr(struct radeon_device *rdev) u32 wptr, tmp; if (rdev->wb.enabled) - wptr = rdev->wb.wb[R600_WB_IH_WPTR_OFFSET/4]; + wptr = le32_to_cpu(rdev->wb.wb[R600_WB_IH_WPTR_OFFSET/4]); else wptr = RREG32(IH_RB_WPTR); -- cgit v0.10.2 From 0b05ac6e24807f0c26f763b3a546c0bcbf84125f Mon Sep 17 00:00:00 2001 From: Benjamin Herrenschmidt Date: Mon, 4 Apr 2011 13:46:58 +1000 Subject: powerpc/xics: Rewrite XICS driver This is a significant rework of the XICS driver, too significant to conveniently break it up into a series of smaller patches to be honest. The driver is moved to a more generic location to allow new platforms to use it, and is broken up into separate ICP and ICS "backends". For now we have the native and "hypervisor" ICP backends and one common RTAS ICS backend. The driver supports one ICP backend instanciation, and many ICS ones, in order to accomodate future platforms with multiple possibly different interrupt "sources" mechanisms. Signed-off-by: Benjamin Herrenschmidt diff --git a/arch/powerpc/include/asm/irq.h b/arch/powerpc/include/asm/irq.h index 67ab5fb..47b7905 100644 --- a/arch/powerpc/include/asm/irq.h +++ b/arch/powerpc/include/asm/irq.h @@ -142,6 +142,12 @@ extern struct irq_map_entry irq_map[NR_IRQS]; extern irq_hw_number_t virq_to_hw(unsigned int virq); +/* This will eventually -replace- virq_to_hw if/when we stash the + * HW number in the irq_data itself. We use a macro so we can inline + * it as irq_data isn't defined yet + */ +#define irq_data_to_hw(d) (irq_map[(d)->irq].hwirq) + /** * irq_alloc_host - Allocate a new irq_host data structure * @of_node: optional device-tree node of the interrupt controller diff --git a/arch/powerpc/include/asm/xics.h b/arch/powerpc/include/asm/xics.h new file mode 100644 index 0000000..146aad8 --- /dev/null +++ b/arch/powerpc/include/asm/xics.h @@ -0,0 +1,139 @@ +/* + * Common definitions accross all variants of ICP and ICS interrupt + * controllers. + */ + +#ifndef _XICS_H +#define _XICS_H + +#define XICS_IPI 2 +#define XICS_IRQ_SPURIOUS 0 + +/* Want a priority other than 0. Various HW issues require this. */ +#define DEFAULT_PRIORITY 5 + +/* + * Mark IPIs as higher priority so we can take them inside interrupts that + * arent marked IRQF_DISABLED + */ +#define IPI_PRIORITY 4 + +/* The least favored priority */ +#define LOWEST_PRIORITY 0xFF + +/* The number of priorities defined above */ +#define MAX_NUM_PRIORITIES 3 + +/* Native ICP */ +extern int icp_native_init(void); + +/* PAPR ICP */ +extern int icp_hv_init(void); + +/* ICP ops */ +struct icp_ops { + unsigned int (*get_irq)(void); + void (*eoi)(struct irq_data *d); + void (*set_priority)(unsigned char prio); + void (*teardown_cpu)(void); + void (*flush_ipi)(void); +#ifdef CONFIG_SMP + void (*message_pass)(int target, int msg); + irq_handler_t ipi_action; +#endif +}; + +extern const struct icp_ops *icp_ops; + +/* Native ICS */ +extern int ics_native_init(void); + +/* RTAS ICS */ +extern int ics_rtas_init(void); + +/* ICS instance, hooked up to chip_data of an irq */ +struct ics { + struct list_head link; + int (*map)(struct ics *ics, unsigned int virq); + void (*mask_unknown)(struct ics *ics, unsigned long vec); + long (*get_server)(struct ics *ics, unsigned long vec); + char data[]; +}; + +/* Commons */ +extern unsigned int xics_default_server; +extern unsigned int xics_default_distrib_server; +extern unsigned int xics_interrupt_server_size; +extern struct irq_host *xics_host; + +struct xics_cppr { + unsigned char stack[MAX_NUM_PRIORITIES]; + int index; +}; + +DECLARE_PER_CPU(struct xics_cppr, xics_cppr); + +static inline void xics_push_cppr(unsigned int vec) +{ + struct xics_cppr *os_cppr = &__get_cpu_var(xics_cppr); + + if (WARN_ON(os_cppr->index >= MAX_NUM_PRIORITIES - 1)) + return; + + if (vec == XICS_IPI) + os_cppr->stack[++os_cppr->index] = IPI_PRIORITY; + else + os_cppr->stack[++os_cppr->index] = DEFAULT_PRIORITY; +} + +static inline unsigned char xics_pop_cppr(void) +{ + struct xics_cppr *os_cppr = &__get_cpu_var(xics_cppr); + + if (WARN_ON(os_cppr->index < 1)) + return LOWEST_PRIORITY; + + return os_cppr->stack[--os_cppr->index]; +} + +static inline void xics_set_base_cppr(unsigned char cppr) +{ + struct xics_cppr *os_cppr = &__get_cpu_var(xics_cppr); + + /* we only really want to set the priority when there's + * just one cppr value on the stack + */ + WARN_ON(os_cppr->index != 0); + + os_cppr->stack[0] = cppr; +} + +static inline unsigned char xics_cppr_top(void) +{ + struct xics_cppr *os_cppr = &__get_cpu_var(xics_cppr); + + return os_cppr->stack[os_cppr->index]; +} + +DECLARE_PER_CPU_SHARED_ALIGNED(unsigned long, xics_ipi_message); + +extern void xics_init(void); +extern void xics_setup_cpu(void); +extern void xics_update_irq_servers(void); +extern void xics_set_cpu_giq(unsigned int gserver, unsigned int join); +extern void xics_mask_unknown_vec(unsigned int vec); +extern irqreturn_t xics_ipi_dispatch(int cpu); +extern int xics_smp_probe(void); +extern void xics_register_ics(struct ics *ics); +extern void xics_teardown_cpu(void); +extern void xics_kexec_teardown_cpu(int secondary); +extern void xics_migrate_irqs_away(void); +#ifdef CONFIG_SMP +extern int xics_get_irq_server(unsigned int virq, const struct cpumask *cpumask, + unsigned int strict_check); +#else +#define xics_get_irq_server(virq, cpumask, strict_check) (xics_default_server) +#endif + + +#endif /* _XICS_H */ diff --git a/arch/powerpc/platforms/pseries/Kconfig b/arch/powerpc/platforms/pseries/Kconfig index 5b3da4b..b044922 100644 --- a/arch/powerpc/platforms/pseries/Kconfig +++ b/arch/powerpc/platforms/pseries/Kconfig @@ -3,7 +3,10 @@ config PPC_PSERIES bool "IBM pSeries & new (POWER5-based) iSeries" select MPIC select PCI_MSI - select XICS + select PPC_XICS + select PPC_ICP_NATIVE + select PPC_ICP_HV + select PPC_ICS_RTAS select PPC_I8259 select PPC_RTAS select PPC_RTAS_DAEMON diff --git a/arch/powerpc/platforms/pseries/Makefile b/arch/powerpc/platforms/pseries/Makefile index fc52378..4cfefba 100644 --- a/arch/powerpc/platforms/pseries/Makefile +++ b/arch/powerpc/platforms/pseries/Makefile @@ -5,7 +5,6 @@ obj-y := lpar.o hvCall.o nvram.o reconfig.o \ setup.o iommu.o event_sources.o ras.o \ firmware.o power.o dlpar.o mobility.o obj-$(CONFIG_SMP) += smp.o -obj-$(CONFIG_XICS) += xics.o obj-$(CONFIG_SCANLOG) += scanlog.o obj-$(CONFIG_EEH) += eeh.o eeh_cache.o eeh_driver.o eeh_event.o eeh_sysfs.o obj-$(CONFIG_KEXEC) += kexec.o diff --git a/arch/powerpc/platforms/pseries/hotplug-cpu.c b/arch/powerpc/platforms/pseries/hotplug-cpu.c index ef8c454..ae6c27d 100644 --- a/arch/powerpc/platforms/pseries/hotplug-cpu.c +++ b/arch/powerpc/platforms/pseries/hotplug-cpu.c @@ -19,6 +19,7 @@ */ #include +#include #include #include #include @@ -28,7 +29,7 @@ #include #include #include -#include "xics.h" +#include #include "plpar_wrappers.h" #include "offline_states.h" diff --git a/arch/powerpc/platforms/pseries/kexec.c b/arch/powerpc/platforms/pseries/kexec.c index 77d38a5..54cf3a4 100644 --- a/arch/powerpc/platforms/pseries/kexec.c +++ b/arch/powerpc/platforms/pseries/kexec.c @@ -7,15 +7,18 @@ * 2 of the License, or (at your option) any later version. */ +#include +#include + #include #include #include #include #include +#include #include #include "pseries.h" -#include "xics.h" #include "plpar_wrappers.h" static void pseries_kexec_cpu_down(int crash_shutdown, int secondary) diff --git a/arch/powerpc/platforms/pseries/plpar_wrappers.h b/arch/powerpc/platforms/pseries/plpar_wrappers.h index d980111..4bf2120 100644 --- a/arch/powerpc/platforms/pseries/plpar_wrappers.h +++ b/arch/powerpc/platforms/pseries/plpar_wrappers.h @@ -270,31 +270,4 @@ static inline long plpar_put_term_char(unsigned long termno, unsigned long len, lbuf[1]); } -static inline long plpar_eoi(unsigned long xirr) -{ - return plpar_hcall_norets(H_EOI, xirr); -} - -static inline long plpar_cppr(unsigned long cppr) -{ - return plpar_hcall_norets(H_CPPR, cppr); -} - -static inline long plpar_ipi(unsigned long servernum, unsigned long mfrr) -{ - return plpar_hcall_norets(H_IPI, servernum, mfrr); -} - -static inline long plpar_xirr(unsigned long *xirr_ret, unsigned char cppr) -{ - long rc; - unsigned long retbuf[PLPAR_HCALL_BUFSIZE]; - - rc = plpar_hcall(H_XIRR, retbuf, cppr); - - *xirr_ret = retbuf[0]; - - return rc; -} - #endif /* _PSERIES_PLPAR_WRAPPERS_H */ diff --git a/arch/powerpc/platforms/pseries/setup.c b/arch/powerpc/platforms/pseries/setup.c index 6c42cfd..ab73ad2 100644 --- a/arch/powerpc/platforms/pseries/setup.c +++ b/arch/powerpc/platforms/pseries/setup.c @@ -53,9 +53,9 @@ #include #include #include -#include "xics.h" #include #include +#include #include #include #include @@ -205,6 +205,9 @@ static void __init pseries_mpic_init_IRQ(void) mpic_assign_isu(mpic, n, isuaddr); } + /* Setup top-level get_irq */ + ppc_md.get_irq = mpic_get_irq; + /* All ISUs are setup, complete initialization */ mpic_init(mpic); @@ -214,7 +217,7 @@ static void __init pseries_mpic_init_IRQ(void) static void __init pseries_xics_init_IRQ(void) { - xics_init_IRQ(); + xics_init(); pseries_setup_i8259_cascade(); } @@ -238,7 +241,6 @@ static void __init pseries_discover_pic(void) if (strstr(typep, "open-pic")) { pSeries_mpic_node = of_node_get(np); ppc_md.init_IRQ = pseries_mpic_init_IRQ; - ppc_md.get_irq = mpic_get_irq; setup_kexec_cpu_down_mpic(); smp_init_pseries_mpic(); return; diff --git a/arch/powerpc/platforms/pseries/smp.c b/arch/powerpc/platforms/pseries/smp.c index a509c52..fc72bfc 100644 --- a/arch/powerpc/platforms/pseries/smp.c +++ b/arch/powerpc/platforms/pseries/smp.c @@ -44,10 +44,11 @@ #include #include #include +#include +#include #include "plpar_wrappers.h" #include "pseries.h" -#include "xics.h" #include "offline_states.h" @@ -136,7 +137,6 @@ out: return 1; } -#ifdef CONFIG_XICS static void __devinit smp_xics_setup_cpu(int cpu) { if (cpu != boot_cpuid) @@ -151,7 +151,6 @@ static void __devinit smp_xics_setup_cpu(int cpu) set_default_offline_state(cpu); #endif } -#endif /* CONFIG_XICS */ static void __devinit smp_pSeries_kick_cpu(int nr) { @@ -197,23 +196,21 @@ static int smp_pSeries_cpu_bootable(unsigned int nr) return 1; } -#ifdef CONFIG_MPIC + static struct smp_ops_t pSeries_mpic_smp_ops = { .message_pass = smp_mpic_message_pass, .probe = smp_mpic_probe, .kick_cpu = smp_pSeries_kick_cpu, .setup_cpu = smp_mpic_setup_cpu, }; -#endif -#ifdef CONFIG_XICS + static struct smp_ops_t pSeries_xics_smp_ops = { - .message_pass = smp_xics_message_pass, - .probe = smp_xics_probe, + .message_pass = NULL, /* Filled at runtime by xics_smp_probe() */ + .probe = xics_smp_probe, .kick_cpu = smp_pSeries_kick_cpu, .setup_cpu = smp_xics_setup_cpu, .cpu_bootable = smp_pSeries_cpu_bootable, }; -#endif /* This is called very early */ static void __init smp_init_pseries(void) @@ -245,14 +242,12 @@ static void __init smp_init_pseries(void) pr_debug(" <- smp_init_pSeries()\n"); } -#ifdef CONFIG_MPIC void __init smp_init_pseries_mpic(void) { smp_ops = &pSeries_mpic_smp_ops; smp_init_pseries(); } -#endif void __init smp_init_pseries_xics(void) { diff --git a/arch/powerpc/platforms/pseries/xics.c b/arch/powerpc/platforms/pseries/xics.c deleted file mode 100644 index d690133..0000000 --- a/arch/powerpc/platforms/pseries/xics.c +++ /dev/null @@ -1,949 +0,0 @@ -/* - * arch/powerpc/platforms/pseries/xics.c - * - * Copyright 2000 IBM Corporation. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include - -#include "xics.h" -#include "plpar_wrappers.h" - -static struct irq_host *xics_host; - -#define XICS_IPI 2 -#define XICS_IRQ_SPURIOUS 0 - -/* Want a priority other than 0. Various HW issues require this. */ -#define DEFAULT_PRIORITY 5 - -/* - * Mark IPIs as higher priority so we can take them inside interrupts that - * arent marked IRQF_DISABLED - */ -#define IPI_PRIORITY 4 - -/* The least favored priority */ -#define LOWEST_PRIORITY 0xFF - -/* The number of priorities defined above */ -#define MAX_NUM_PRIORITIES 3 - -static unsigned int default_server = 0xFF; -static unsigned int default_distrib_server = 0; -static unsigned int interrupt_server_size = 8; - -/* RTAS service tokens */ -static int ibm_get_xive; -static int ibm_set_xive; -static int ibm_int_on; -static int ibm_int_off; - -struct xics_cppr { - unsigned char stack[MAX_NUM_PRIORITIES]; - int index; -}; - -static DEFINE_PER_CPU(struct xics_cppr, xics_cppr); - -/* Direct hardware low level accessors */ - -/* The part of the interrupt presentation layer that we care about */ -struct xics_ipl { - union { - u32 word; - u8 bytes[4]; - } xirr_poll; - union { - u32 word; - u8 bytes[4]; - } xirr; - u32 dummy; - union { - u32 word; - u8 bytes[4]; - } qirr; -}; - -static struct xics_ipl __iomem *xics_per_cpu[NR_CPUS]; - -static inline unsigned int direct_xirr_info_get(void) -{ - int cpu = smp_processor_id(); - - return in_be32(&xics_per_cpu[cpu]->xirr.word); -} - -static inline void direct_xirr_info_set(unsigned int value) -{ - int cpu = smp_processor_id(); - - out_be32(&xics_per_cpu[cpu]->xirr.word, value); -} - -static inline void direct_cppr_info(u8 value) -{ - int cpu = smp_processor_id(); - - out_8(&xics_per_cpu[cpu]->xirr.bytes[0], value); -} - -static inline void direct_qirr_info(int n_cpu, u8 value) -{ - out_8(&xics_per_cpu[n_cpu]->qirr.bytes[0], value); -} - - -/* LPAR low level accessors */ - -static inline unsigned int lpar_xirr_info_get(unsigned char cppr) -{ - unsigned long lpar_rc; - unsigned long return_value; - - lpar_rc = plpar_xirr(&return_value, cppr); - if (lpar_rc != H_SUCCESS) - panic(" bad return code xirr - rc = %lx\n", lpar_rc); - return (unsigned int)return_value; -} - -static inline void lpar_xirr_info_set(unsigned int value) -{ - unsigned long lpar_rc; - - lpar_rc = plpar_eoi(value); - if (lpar_rc != H_SUCCESS) - panic("bad return code EOI - rc = %ld, value=%x\n", lpar_rc, - value); -} - -static inline void lpar_cppr_info(u8 value) -{ - unsigned long lpar_rc; - - lpar_rc = plpar_cppr(value); - if (lpar_rc != H_SUCCESS) - panic("bad return code cppr - rc = %lx\n", lpar_rc); -} - -static inline void lpar_qirr_info(int n_cpu , u8 value) -{ - unsigned long lpar_rc; - - lpar_rc = plpar_ipi(get_hard_smp_processor_id(n_cpu), value); - if (lpar_rc != H_SUCCESS) - panic("bad return code qirr - rc = %lx\n", lpar_rc); -} - - -/* Interface to generic irq subsystem */ - -#ifdef CONFIG_SMP -/* - * For the moment we only implement delivery to all cpus or one cpu. - * - * If the requested affinity is cpu_all_mask, we set global affinity. - * If not we set it to the first cpu in the mask, even if multiple cpus - * are set. This is so things like irqbalance (which set core and package - * wide affinities) do the right thing. - */ -static int get_irq_server(unsigned int virq, const struct cpumask *cpumask, - unsigned int strict_check) -{ - - if (!distribute_irqs) - return default_server; - - if (!cpumask_subset(cpu_possible_mask, cpumask)) { - int server = cpumask_first_and(cpu_online_mask, cpumask); - - if (server < nr_cpu_ids) - return get_hard_smp_processor_id(server); - - if (strict_check) - return -1; - } - - /* - * Workaround issue with some versions of JS20 firmware that - * deliver interrupts to cpus which haven't been started. This - * happens when using the maxcpus= boot option. - */ - if (cpumask_equal(cpu_online_mask, cpu_present_mask)) - return default_distrib_server; - - return default_server; -} -#else -#define get_irq_server(virq, cpumask, strict_check) (default_server) -#endif - -static void xics_unmask_irq(struct irq_data *d) -{ - unsigned int hwirq; - int call_status; - int server; - - pr_devel("xics: unmask virq %d\n", d->irq); - - hwirq = (unsigned int)irq_map[d->irq].hwirq; - pr_devel(" -> map to hwirq 0x%x\n", hwirq); - if (hwirq == XICS_IPI || hwirq == XICS_IRQ_SPURIOUS) - return; - - server = get_irq_server(d->irq, d->affinity, 0); - - call_status = rtas_call(ibm_set_xive, 3, 1, NULL, hwirq, server, - DEFAULT_PRIORITY); - if (call_status != 0) { - printk(KERN_ERR - "%s: ibm_set_xive irq %u server %x returned %d\n", - __func__, hwirq, server, call_status); - return; - } - - /* Now unmask the interrupt (often a no-op) */ - call_status = rtas_call(ibm_int_on, 1, 1, NULL, hwirq); - if (call_status != 0) { - printk(KERN_ERR "%s: ibm_int_on irq=%u returned %d\n", - __func__, hwirq, call_status); - return; - } -} - -static unsigned int xics_startup(struct irq_data *d) -{ - /* - * The generic MSI code returns with the interrupt disabled on the - * card, using the MSI mask bits. Firmware doesn't appear to unmask - * at that level, so we do it here by hand. - */ - if (d->msi_desc) - unmask_msi_irq(d); - - /* unmask it */ - xics_unmask_irq(d); - return 0; -} - -static void xics_mask_real_irq(unsigned int hwirq) -{ - int call_status; - - if (hwirq == XICS_IPI) - return; - - call_status = rtas_call(ibm_int_off, 1, 1, NULL, hwirq); - if (call_status != 0) { - printk(KERN_ERR "%s: ibm_int_off irq=%u returned %d\n", - __func__, hwirq, call_status); - return; - } - - /* Have to set XIVE to 0xff to be able to remove a slot */ - call_status = rtas_call(ibm_set_xive, 3, 1, NULL, hwirq, - default_server, 0xff); - if (call_status != 0) { - printk(KERN_ERR "%s: ibm_set_xive(0xff) irq=%u returned %d\n", - __func__, hwirq, call_status); - return; - } -} - -static void xics_mask_irq(struct irq_data *d) -{ - unsigned int hwirq; - - pr_devel("xics: mask virq %d\n", d->irq); - - hwirq = (unsigned int)irq_map[d->irq].hwirq; - if (hwirq == XICS_IPI || hwirq == XICS_IRQ_SPURIOUS) - return; - xics_mask_real_irq(hwirq); -} - -static void xics_mask_unknown_vec(unsigned int vec) -{ - printk(KERN_ERR "Interrupt %u (real) is invalid, disabling it.\n", vec); - xics_mask_real_irq(vec); -} - -static inline unsigned int xics_xirr_vector(unsigned int xirr) -{ - /* - * The top byte is the old cppr, to be restored on EOI. - * The remaining 24 bits are the vector. - */ - return xirr & 0x00ffffff; -} - -static void push_cppr(unsigned int vec) -{ - struct xics_cppr *os_cppr = &__get_cpu_var(xics_cppr); - - if (WARN_ON(os_cppr->index >= MAX_NUM_PRIORITIES - 1)) - return; - - if (vec == XICS_IPI) - os_cppr->stack[++os_cppr->index] = IPI_PRIORITY; - else - os_cppr->stack[++os_cppr->index] = DEFAULT_PRIORITY; -} - -static unsigned int xics_get_irq_direct(void) -{ - unsigned int xirr = direct_xirr_info_get(); - unsigned int vec = xics_xirr_vector(xirr); - unsigned int irq; - - if (vec == XICS_IRQ_SPURIOUS) - return NO_IRQ; - - irq = irq_radix_revmap_lookup(xics_host, vec); - if (likely(irq != NO_IRQ)) { - push_cppr(vec); - return irq; - } - - /* We don't have a linux mapping, so have rtas mask it. */ - xics_mask_unknown_vec(vec); - - /* We might learn about it later, so EOI it */ - direct_xirr_info_set(xirr); - return NO_IRQ; -} - -static unsigned int xics_get_irq_lpar(void) -{ - struct xics_cppr *os_cppr = &__get_cpu_var(xics_cppr); - unsigned int xirr = lpar_xirr_info_get(os_cppr->stack[os_cppr->index]); - unsigned int vec = xics_xirr_vector(xirr); - unsigned int irq; - - if (vec == XICS_IRQ_SPURIOUS) - return NO_IRQ; - - irq = irq_radix_revmap_lookup(xics_host, vec); - if (likely(irq != NO_IRQ)) { - push_cppr(vec); - return irq; - } - - /* We don't have a linux mapping, so have RTAS mask it. */ - xics_mask_unknown_vec(vec); - - /* We might learn about it later, so EOI it */ - lpar_xirr_info_set(xirr); - return NO_IRQ; -} - -static unsigned char pop_cppr(void) -{ - struct xics_cppr *os_cppr = &__get_cpu_var(xics_cppr); - - if (WARN_ON(os_cppr->index < 1)) - return LOWEST_PRIORITY; - - return os_cppr->stack[--os_cppr->index]; -} - -static void xics_eoi_direct(struct irq_data *d) -{ - unsigned int hwirq = (unsigned int)irq_map[d->irq].hwirq; - - iosync(); - direct_xirr_info_set((pop_cppr() << 24) | hwirq); -} - -static void xics_eoi_lpar(struct irq_data *d) -{ - unsigned int hwirq = (unsigned int)irq_map[d->irq].hwirq; - - iosync(); - lpar_xirr_info_set((pop_cppr() << 24) | hwirq); -} - -static int -xics_set_affinity(struct irq_data *d, const struct cpumask *cpumask, bool force) -{ - unsigned int hwirq; - int status; - int xics_status[2]; - int irq_server; - - hwirq = (unsigned int)irq_map[d->irq].hwirq; - if (hwirq == XICS_IPI || hwirq == XICS_IRQ_SPURIOUS) - return -1; - - status = rtas_call(ibm_get_xive, 1, 3, xics_status, hwirq); - - if (status) { - printk(KERN_ERR "%s: ibm,get-xive irq=%u returns %d\n", - __func__, hwirq, status); - return -1; - } - - irq_server = get_irq_server(d->irq, cpumask, 1); - if (irq_server == -1) { - char cpulist[128]; - cpumask_scnprintf(cpulist, sizeof(cpulist), cpumask); - printk(KERN_WARNING - "%s: No online cpus in the mask %s for irq %d\n", - __func__, cpulist, d->irq); - return -1; - } - - status = rtas_call(ibm_set_xive, 3, 1, NULL, - hwirq, irq_server, xics_status[1]); - - if (status) { - printk(KERN_ERR "%s: ibm,set-xive irq=%u returns %d\n", - __func__, hwirq, status); - return -1; - } - - return 0; -} - -static struct irq_chip xics_pic_direct = { - .name = "XICS", - .irq_startup = xics_startup, - .irq_mask = xics_mask_irq, - .irq_unmask = xics_unmask_irq, - .irq_eoi = xics_eoi_direct, - .irq_set_affinity = xics_set_affinity -}; - -static struct irq_chip xics_pic_lpar = { - .name = "XICS", - .irq_startup = xics_startup, - .irq_mask = xics_mask_irq, - .irq_unmask = xics_unmask_irq, - .irq_eoi = xics_eoi_lpar, - .irq_set_affinity = xics_set_affinity -}; - - -/* Interface to arch irq controller subsystem layer */ - -/* Points to the irq_chip we're actually using */ -static struct irq_chip *xics_irq_chip; - -static int xics_host_match(struct irq_host *h, struct device_node *node) -{ - /* IBM machines have interrupt parents of various funky types for things - * like vdevices, events, etc... The trick we use here is to match - * everything here except the legacy 8259 which is compatible "chrp,iic" - */ - return !of_device_is_compatible(node, "chrp,iic"); -} - -static int xics_host_map(struct irq_host *h, unsigned int virq, - irq_hw_number_t hw) -{ - pr_devel("xics: map virq %d, hwirq 0x%lx\n", virq, hw); - - /* Insert the interrupt mapping into the radix tree for fast lookup */ - irq_radix_revmap_insert(xics_host, virq, hw); - - irq_set_status_flags(virq, IRQ_LEVEL); - irq_set_chip_and_handler(virq, xics_irq_chip, handle_fasteoi_irq); - return 0; -} - -static int xics_host_xlate(struct irq_host *h, struct device_node *ct, - const u32 *intspec, unsigned int intsize, - irq_hw_number_t *out_hwirq, unsigned int *out_flags) - -{ - /* Current xics implementation translates everything - * to level. It is not technically right for MSIs but this - * is irrelevant at this point. We might get smarter in the future - */ - *out_hwirq = intspec[0]; - *out_flags = IRQ_TYPE_LEVEL_LOW; - - return 0; -} - -static struct irq_host_ops xics_host_ops = { - .match = xics_host_match, - .map = xics_host_map, - .xlate = xics_host_xlate, -}; - -static void __init xics_init_host(void) -{ - if (firmware_has_feature(FW_FEATURE_LPAR)) - xics_irq_chip = &xics_pic_lpar; - else - xics_irq_chip = &xics_pic_direct; - - xics_host = irq_alloc_host(NULL, IRQ_HOST_MAP_TREE, 0, &xics_host_ops, - XICS_IRQ_SPURIOUS); - BUG_ON(xics_host == NULL); - irq_set_default_host(xics_host); -} - - -/* Inter-processor interrupt support */ - -#ifdef CONFIG_SMP -/* - * XICS only has a single IPI, so encode the messages per CPU - */ -static DEFINE_PER_CPU_SHARED_ALIGNED(unsigned long, xics_ipi_message); - -static inline void smp_xics_do_message(int cpu, int msg) -{ - unsigned long *tgt = &per_cpu(xics_ipi_message, cpu); - - set_bit(msg, tgt); - mb(); - if (firmware_has_feature(FW_FEATURE_LPAR)) - lpar_qirr_info(cpu, IPI_PRIORITY); - else - direct_qirr_info(cpu, IPI_PRIORITY); -} - -void smp_xics_message_pass(int target, int msg) -{ - unsigned int i; - - if (target < NR_CPUS) { - smp_xics_do_message(target, msg); - } else { - for_each_online_cpu(i) { - if (target == MSG_ALL_BUT_SELF - && i == smp_processor_id()) - continue; - smp_xics_do_message(i, msg); - } - } -} - -static irqreturn_t xics_ipi_dispatch(int cpu) -{ - unsigned long *tgt = &per_cpu(xics_ipi_message, cpu); - - mb(); /* order mmio clearing qirr */ - while (*tgt) { - if (test_and_clear_bit(PPC_MSG_CALL_FUNCTION, tgt)) { - smp_message_recv(PPC_MSG_CALL_FUNCTION); - } - if (test_and_clear_bit(PPC_MSG_RESCHEDULE, tgt)) { - smp_message_recv(PPC_MSG_RESCHEDULE); - } - if (test_and_clear_bit(PPC_MSG_CALL_FUNC_SINGLE, tgt)) { - smp_message_recv(PPC_MSG_CALL_FUNC_SINGLE); - } -#if defined(CONFIG_DEBUGGER) || defined(CONFIG_KEXEC) - if (test_and_clear_bit(PPC_MSG_DEBUGGER_BREAK, tgt)) { - smp_message_recv(PPC_MSG_DEBUGGER_BREAK); - } -#endif - } - return IRQ_HANDLED; -} - -static irqreturn_t xics_ipi_action_direct(int irq, void *dev_id) -{ - int cpu = smp_processor_id(); - - direct_qirr_info(cpu, 0xff); - - return xics_ipi_dispatch(cpu); -} - -static irqreturn_t xics_ipi_action_lpar(int irq, void *dev_id) -{ - int cpu = smp_processor_id(); - - lpar_qirr_info(cpu, 0xff); - - return xics_ipi_dispatch(cpu); -} - -static void xics_request_ipi(void) -{ - unsigned int ipi; - int rc; - - ipi = irq_create_mapping(xics_host, XICS_IPI); - BUG_ON(ipi == NO_IRQ); - - /* - * IPIs are marked IRQF_DISABLED as they must run with irqs - * disabled - */ - irq_set_handler(ipi, handle_percpu_irq); - if (firmware_has_feature(FW_FEATURE_LPAR)) - rc = request_irq(ipi, xics_ipi_action_lpar, - IRQF_DISABLED|IRQF_PERCPU, "IPI", NULL); - else - rc = request_irq(ipi, xics_ipi_action_direct, - IRQF_DISABLED|IRQF_PERCPU, "IPI", NULL); - BUG_ON(rc); -} - -int __init smp_xics_probe(void) -{ - xics_request_ipi(); - - return cpumask_weight(cpu_possible_mask); -} - -#endif /* CONFIG_SMP */ - - -/* Initialization */ - -static void xics_update_irq_servers(void) -{ - int i, j; - struct device_node *np; - u32 ilen; - const u32 *ireg; - u32 hcpuid; - - /* Find the server numbers for the boot cpu. */ - np = of_get_cpu_node(boot_cpuid, NULL); - BUG_ON(!np); - - ireg = of_get_property(np, "ibm,ppc-interrupt-gserver#s", &ilen); - if (!ireg) { - of_node_put(np); - return; - } - - i = ilen / sizeof(int); - hcpuid = get_hard_smp_processor_id(boot_cpuid); - - /* Global interrupt distribution server is specified in the last - * entry of "ibm,ppc-interrupt-gserver#s" property. Get the last - * entry fom this property for current boot cpu id and use it as - * default distribution server - */ - for (j = 0; j < i; j += 2) { - if (ireg[j] == hcpuid) { - default_server = hcpuid; - default_distrib_server = ireg[j+1]; - } - } - - of_node_put(np); -} - -static void __init xics_map_one_cpu(int hw_id, unsigned long addr, - unsigned long size) -{ - int i; - - /* This may look gross but it's good enough for now, we don't quite - * have a hard -> linux processor id matching. - */ - for_each_possible_cpu(i) { - if (!cpu_present(i)) - continue; - if (hw_id == get_hard_smp_processor_id(i)) { - xics_per_cpu[i] = ioremap(addr, size); - return; - } - } -} - -static void __init xics_init_one_node(struct device_node *np, - unsigned int *indx) -{ - unsigned int ilen; - const u32 *ireg; - - /* This code does the theorically broken assumption that the interrupt - * server numbers are the same as the hard CPU numbers. - * This happens to be the case so far but we are playing with fire... - * should be fixed one of these days. -BenH. - */ - ireg = of_get_property(np, "ibm,interrupt-server-ranges", NULL); - - /* Do that ever happen ? we'll know soon enough... but even good'old - * f80 does have that property .. - */ - WARN_ON(ireg == NULL); - if (ireg) { - /* - * set node starting index for this node - */ - *indx = *ireg; - } - ireg = of_get_property(np, "reg", &ilen); - if (!ireg) - panic("xics_init_IRQ: can't find interrupt reg property"); - - while (ilen >= (4 * sizeof(u32))) { - unsigned long addr, size; - - /* XXX Use proper OF parsing code here !!! */ - addr = (unsigned long)*ireg++ << 32; - ilen -= sizeof(u32); - addr |= *ireg++; - ilen -= sizeof(u32); - size = (unsigned long)*ireg++ << 32; - ilen -= sizeof(u32); - size |= *ireg++; - ilen -= sizeof(u32); - xics_map_one_cpu(*indx, addr, size); - (*indx)++; - } -} - -void __init xics_init_IRQ(void) -{ - struct device_node *np; - u32 indx = 0; - int found = 0; - const u32 *isize; - - ppc64_boot_msg(0x20, "XICS Init"); - - ibm_get_xive = rtas_token("ibm,get-xive"); - ibm_set_xive = rtas_token("ibm,set-xive"); - ibm_int_on = rtas_token("ibm,int-on"); - ibm_int_off = rtas_token("ibm,int-off"); - - for_each_node_by_type(np, "PowerPC-External-Interrupt-Presentation") { - found = 1; - if (firmware_has_feature(FW_FEATURE_LPAR)) { - of_node_put(np); - break; - } - xics_init_one_node(np, &indx); - } - if (found == 0) - return; - - /* get the bit size of server numbers */ - found = 0; - - for_each_compatible_node(np, NULL, "ibm,ppc-xics") { - isize = of_get_property(np, "ibm,interrupt-server#-size", NULL); - - if (!isize) - continue; - - if (!found) { - interrupt_server_size = *isize; - found = 1; - } else if (*isize != interrupt_server_size) { - printk(KERN_WARNING "XICS: " - "mismatched ibm,interrupt-server#-size\n"); - interrupt_server_size = max(*isize, - interrupt_server_size); - } - } - - xics_update_irq_servers(); - xics_init_host(); - - if (firmware_has_feature(FW_FEATURE_LPAR)) - ppc_md.get_irq = xics_get_irq_lpar; - else - ppc_md.get_irq = xics_get_irq_direct; - - xics_setup_cpu(); - - ppc64_boot_msg(0x21, "XICS Done"); -} - -/* Cpu startup, shutdown, and hotplug */ - -static void xics_set_cpu_priority(unsigned char cppr) -{ - struct xics_cppr *os_cppr = &__get_cpu_var(xics_cppr); - - /* - * we only really want to set the priority when there's - * just one cppr value on the stack - */ - WARN_ON(os_cppr->index != 0); - - os_cppr->stack[0] = cppr; - - if (firmware_has_feature(FW_FEATURE_LPAR)) - lpar_cppr_info(cppr); - else - direct_cppr_info(cppr); - iosync(); -} - -/* Have the calling processor join or leave the specified global queue */ -static void xics_set_cpu_giq(unsigned int gserver, unsigned int join) -{ - int index; - int status; - - if (!rtas_indicator_present(GLOBAL_INTERRUPT_QUEUE, NULL)) - return; - - index = (1UL << interrupt_server_size) - 1 - gserver; - - status = rtas_set_indicator_fast(GLOBAL_INTERRUPT_QUEUE, index, join); - - WARN(status < 0, "set-indicator(%d, %d, %u) returned %d\n", - GLOBAL_INTERRUPT_QUEUE, index, join, status); -} - -void xics_setup_cpu(void) -{ - xics_set_cpu_priority(LOWEST_PRIORITY); - - xics_set_cpu_giq(default_distrib_server, 1); -} - -void xics_teardown_cpu(void) -{ - struct xics_cppr *os_cppr = &__get_cpu_var(xics_cppr); - int cpu = smp_processor_id(); - - /* - * we have to reset the cppr index to 0 because we're - * not going to return from the IPI - */ - os_cppr->index = 0; - xics_set_cpu_priority(0); - - /* Clear any pending IPI request */ - if (firmware_has_feature(FW_FEATURE_LPAR)) - lpar_qirr_info(cpu, 0xff); - else - direct_qirr_info(cpu, 0xff); -} - -void xics_kexec_teardown_cpu(int secondary) -{ - xics_teardown_cpu(); - - /* - * we take the ipi irq but and never return so we - * need to EOI the IPI, but want to leave our priority 0 - * - * should we check all the other interrupts too? - * should we be flagging idle loop instead? - * or creating some task to be scheduled? - */ - - if (firmware_has_feature(FW_FEATURE_LPAR)) - lpar_xirr_info_set((0x00 << 24) | XICS_IPI); - else - direct_xirr_info_set((0x00 << 24) | XICS_IPI); - - /* - * Some machines need to have at least one cpu in the GIQ, - * so leave the master cpu in the group. - */ - if (secondary) - xics_set_cpu_giq(default_distrib_server, 0); -} - -#ifdef CONFIG_HOTPLUG_CPU - -/* Interrupts are disabled. */ -void xics_migrate_irqs_away(void) -{ - int cpu = smp_processor_id(), hw_cpu = hard_smp_processor_id(); - int virq; - - /* If we used to be the default server, move to the new "boot_cpuid" */ - if (hw_cpu == default_server) - xics_update_irq_servers(); - - /* Reject any interrupt that was queued to us... */ - xics_set_cpu_priority(0); - - /* Remove ourselves from the global interrupt queue */ - xics_set_cpu_giq(default_distrib_server, 0); - - /* Allow IPIs again... */ - xics_set_cpu_priority(DEFAULT_PRIORITY); - - for_each_irq(virq) { - struct irq_desc *desc; - struct irq_chip *chip; - unsigned int hwirq; - int xics_status[2]; - int status; - unsigned long flags; - - /* We can't set affinity on ISA interrupts */ - if (virq < NUM_ISA_INTERRUPTS) - continue; - if (irq_map[virq].host != xics_host) - continue; - hwirq = (unsigned int)irq_map[virq].hwirq; - /* We need to get IPIs still. */ - if (hwirq == XICS_IPI || hwirq == XICS_IRQ_SPURIOUS) - continue; - - desc = irq_to_desc(virq); - - /* We only need to migrate enabled IRQS */ - if (desc == NULL || desc->action == NULL) - continue; - - chip = irq_desc_get_chip(desc); - if (chip == NULL || chip->irq_set_affinity == NULL) - continue; - - raw_spin_lock_irqsave(&desc->lock, flags); - - status = rtas_call(ibm_get_xive, 1, 3, xics_status, hwirq); - if (status) { - printk(KERN_ERR "%s: ibm,get-xive irq=%u returns %d\n", - __func__, hwirq, status); - goto unlock; - } - - /* - * We only support delivery to all cpus or to one cpu. - * The irq has to be migrated only in the single cpu - * case. - */ - if (xics_status[0] != hw_cpu) - goto unlock; - - /* This is expected during cpu offline. */ - if (cpu_online(cpu)) - printk(KERN_WARNING "IRQ %u affinity broken off cpu %u\n", - virq, cpu); - - /* Reset affinity to all cpus */ - cpumask_setall(desc->irq_data.affinity); - chip->irq_set_affinity(&desc->irq_data, cpu_all_mask, true); -unlock: - raw_spin_unlock_irqrestore(&desc->lock, flags); - } -} -#endif diff --git a/arch/powerpc/platforms/pseries/xics.h b/arch/powerpc/platforms/pseries/xics.h deleted file mode 100644 index d1d5a83..0000000 --- a/arch/powerpc/platforms/pseries/xics.h +++ /dev/null @@ -1,23 +0,0 @@ -/* - * arch/powerpc/platforms/pseries/xics.h - * - * Copyright 2000 IBM Corporation. - * - * 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 _POWERPC_KERNEL_XICS_H -#define _POWERPC_KERNEL_XICS_H - -extern void xics_init_IRQ(void); -extern void xics_setup_cpu(void); -extern void xics_teardown_cpu(void); -extern void xics_kexec_teardown_cpu(int secondary); -extern void xics_migrate_irqs_away(void); -extern int smp_xics_probe(void); -extern void smp_xics_message_pass(int target, int msg); - -#endif /* _POWERPC_KERNEL_XICS_H */ diff --git a/arch/powerpc/sysdev/Kconfig b/arch/powerpc/sysdev/Kconfig index 3965828..cfc1877 100644 --- a/arch/powerpc/sysdev/Kconfig +++ b/arch/powerpc/sysdev/Kconfig @@ -12,3 +12,6 @@ config PPC_MSI_BITMAP depends on PCI_MSI default y if MPIC default y if FSL_PCI + +source "arch/powerpc/sysdev/xics/Kconfig" + diff --git a/arch/powerpc/sysdev/Makefile b/arch/powerpc/sysdev/Makefile index 1e0c933..9516e75 100644 --- a/arch/powerpc/sysdev/Makefile +++ b/arch/powerpc/sysdev/Makefile @@ -57,3 +57,7 @@ obj-$(CONFIG_PPC_MPC52xx) += mpc5xxx_clocks.o ifeq ($(CONFIG_SUSPEND),y) obj-$(CONFIG_6xx) += 6xx-suspend.o endif + +subdir-ccflags-$(CONFIG_PPC_WERROR) := -Werror + +obj-$(CONFIG_PPC_XICS) += xics/ diff --git a/arch/powerpc/sysdev/xics/Kconfig b/arch/powerpc/sysdev/xics/Kconfig new file mode 100644 index 0000000..123b8dd --- /dev/null +++ b/arch/powerpc/sysdev/xics/Kconfig @@ -0,0 +1,12 @@ +config PPC_XICS + def_bool n + +config PPC_ICP_NATIVE + def_bool n + +config PPC_ICP_HV + def_bool n + +config PPC_ICS_RTAS + def_bool n + diff --git a/arch/powerpc/sysdev/xics/Makefile b/arch/powerpc/sysdev/xics/Makefile new file mode 100644 index 0000000..b75a605 --- /dev/null +++ b/arch/powerpc/sysdev/xics/Makefile @@ -0,0 +1,6 @@ +subdir-ccflags-$(CONFIG_PPC_WERROR) := -Werror + +obj-y += xics-common.o +obj-$(CONFIG_PPC_ICP_NATIVE) += icp-native.o +obj-$(CONFIG_PPC_ICP_HV) += icp-hv.o +obj-$(CONFIG_PPC_ICS_RTAS) += ics-rtas.o diff --git a/arch/powerpc/sysdev/xics/icp-hv.c b/arch/powerpc/sysdev/xics/icp-hv.c new file mode 100644 index 0000000..b03d348 --- /dev/null +++ b/arch/powerpc/sysdev/xics/icp-hv.c @@ -0,0 +1,184 @@ +/* + * Copyright 2011 IBM Corporation. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + * + */ +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +static inline unsigned int icp_hv_get_xirr(unsigned char cppr) +{ + unsigned long retbuf[PLPAR_HCALL_BUFSIZE]; + long rc; + + rc = plpar_hcall(H_XIRR, retbuf, cppr); + if (rc != H_SUCCESS) + panic(" bad return code xirr - rc = %lx\n", rc); + return (unsigned int)retbuf[0]; +} + +static inline void icp_hv_set_xirr(unsigned int value) +{ + long rc = plpar_hcall_norets(H_EOI, value); + if (rc != H_SUCCESS) + panic("bad return code EOI - rc = %ld, value=%x\n", rc, value); +} + +static inline void icp_hv_set_cppr(u8 value) +{ + long rc = plpar_hcall_norets(H_CPPR, value); + if (rc != H_SUCCESS) + panic("bad return code cppr - rc = %lx\n", rc); +} + +static inline void icp_hv_set_qirr(int n_cpu , u8 value) +{ + long rc = plpar_hcall_norets(H_IPI, get_hard_smp_processor_id(n_cpu), + value); + if (rc != H_SUCCESS) + panic("bad return code qirr - rc = %lx\n", rc); +} + +static void icp_hv_eoi(struct irq_data *d) +{ + unsigned int hw_irq = (unsigned int)irq_data_to_hw(d); + + iosync(); + icp_hv_set_xirr((xics_pop_cppr() << 24) | hw_irq); +} + +static void icp_hv_teardown_cpu(void) +{ + int cpu = smp_processor_id(); + + /* Clear any pending IPI */ + icp_hv_set_qirr(cpu, 0xff); +} + +static void icp_hv_flush_ipi(void) +{ + /* We take the ipi irq but and never return so we + * need to EOI the IPI, but want to leave our priority 0 + * + * should we check all the other interrupts too? + * should we be flagging idle loop instead? + * or creating some task to be scheduled? + */ + + icp_hv_set_xirr((0x00 << 24) | XICS_IPI); +} + +static unsigned int icp_hv_get_irq(void) +{ + unsigned int xirr = icp_hv_get_xirr(xics_cppr_top()); + unsigned int vec = xirr & 0x00ffffff; + unsigned int irq; + + if (vec == XICS_IRQ_SPURIOUS) + return NO_IRQ; + + irq = irq_radix_revmap_lookup(xics_host, vec); + if (likely(irq != NO_IRQ)) { + xics_push_cppr(vec); + return irq; + } + + /* We don't have a linux mapping, so have rtas mask it. */ + xics_mask_unknown_vec(vec); + + /* We might learn about it later, so EOI it */ + icp_hv_set_xirr(xirr); + + return NO_IRQ; +} + +static void icp_hv_set_cpu_priority(unsigned char cppr) +{ + xics_set_base_cppr(cppr); + icp_hv_set_cppr(cppr); + iosync(); +} + +#ifdef CONFIG_SMP + +static inline void icp_hv_do_message(int cpu, int msg) +{ + unsigned long *tgt = &per_cpu(xics_ipi_message, cpu); + + set_bit(msg, tgt); + mb(); + icp_hv_set_qirr(cpu, IPI_PRIORITY); +} + +static void icp_hv_message_pass(int target, int msg) +{ + unsigned int i; + + if (target < NR_CPUS) { + icp_hv_do_message(target, msg); + } else { + for_each_online_cpu(i) { + if (target == MSG_ALL_BUT_SELF + && i == smp_processor_id()) + continue; + icp_hv_do_message(i, msg); + } + } +} + +static irqreturn_t icp_hv_ipi_action(int irq, void *dev_id) +{ + int cpu = smp_processor_id(); + + icp_hv_set_qirr(cpu, 0xff); + + return xics_ipi_dispatch(cpu); +} + +#endif /* CONFIG_SMP */ + +static const struct icp_ops icp_hv_ops = { + .get_irq = icp_hv_get_irq, + .eoi = icp_hv_eoi, + .set_priority = icp_hv_set_cpu_priority, + .teardown_cpu = icp_hv_teardown_cpu, + .flush_ipi = icp_hv_flush_ipi, +#ifdef CONFIG_SMP + .ipi_action = icp_hv_ipi_action, + .message_pass = icp_hv_message_pass, +#endif +}; + +int icp_hv_init(void) +{ + struct device_node *np; + + np = of_find_compatible_node(NULL, NULL, "ibm,ppc-xicp"); + if (!np) + np = of_find_node_by_type(NULL, + "PowerPC-External-Interrupt-Presentation"); + if (!np) + return -ENODEV; + + icp_ops = &icp_hv_ops; + + return 0; +} + diff --git a/arch/powerpc/sysdev/xics/icp-native.c b/arch/powerpc/sysdev/xics/icp-native.c new file mode 100644 index 0000000..be5e3d7 --- /dev/null +++ b/arch/powerpc/sysdev/xics/icp-native.c @@ -0,0 +1,312 @@ +/* + * Copyright 2011 IBM Corporation. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + * + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +struct icp_ipl { + union { + u32 word; + u8 bytes[4]; + } xirr_poll; + union { + u32 word; + u8 bytes[4]; + } xirr; + u32 dummy; + union { + u32 word; + u8 bytes[4]; + } qirr; + u32 link_a; + u32 link_b; + u32 link_c; +}; + +static struct icp_ipl __iomem *icp_native_regs[NR_CPUS]; + +static inline unsigned int icp_native_get_xirr(void) +{ + int cpu = smp_processor_id(); + + return in_be32(&icp_native_regs[cpu]->xirr.word); +} + +static inline void icp_native_set_xirr(unsigned int value) +{ + int cpu = smp_processor_id(); + + out_be32(&icp_native_regs[cpu]->xirr.word, value); +} + +static inline void icp_native_set_cppr(u8 value) +{ + int cpu = smp_processor_id(); + + out_8(&icp_native_regs[cpu]->xirr.bytes[0], value); +} + +static inline void icp_native_set_qirr(int n_cpu, u8 value) +{ + out_8(&icp_native_regs[n_cpu]->qirr.bytes[0], value); +} + +static void icp_native_set_cpu_priority(unsigned char cppr) +{ + xics_set_base_cppr(cppr); + icp_native_set_cppr(cppr); + iosync(); +} + +static void icp_native_eoi(struct irq_data *d) +{ + unsigned int hw_irq = (unsigned int)irq_data_to_hw(d); + + iosync(); + icp_native_set_xirr((xics_pop_cppr() << 24) | hw_irq); +} + +static void icp_native_teardown_cpu(void) +{ + int cpu = smp_processor_id(); + + /* Clear any pending IPI */ + icp_native_set_qirr(cpu, 0xff); +} + +static void icp_native_flush_ipi(void) +{ + /* We take the ipi irq but and never return so we + * need to EOI the IPI, but want to leave our priority 0 + * + * should we check all the other interrupts too? + * should we be flagging idle loop instead? + * or creating some task to be scheduled? + */ + + icp_native_set_xirr((0x00 << 24) | XICS_IPI); +} + +static unsigned int icp_native_get_irq(void) +{ + unsigned int xirr = icp_native_get_xirr(); + unsigned int vec = xirr & 0x00ffffff; + unsigned int irq; + + if (vec == XICS_IRQ_SPURIOUS) + return NO_IRQ; + + irq = irq_radix_revmap_lookup(xics_host, vec); + if (likely(irq != NO_IRQ)) { + xics_push_cppr(vec); + return irq; + } + + /* We don't have a linux mapping, so have rtas mask it. */ + xics_mask_unknown_vec(vec); + + /* We might learn about it later, so EOI it */ + icp_native_set_xirr(xirr); + + return NO_IRQ; +} + +#ifdef CONFIG_SMP + +static inline void icp_native_do_message(int cpu, int msg) +{ + unsigned long *tgt = &per_cpu(xics_ipi_message, cpu); + + set_bit(msg, tgt); + mb(); + icp_native_set_qirr(cpu, IPI_PRIORITY); +} + +static void icp_native_message_pass(int target, int msg) +{ + unsigned int i; + + if (target < NR_CPUS) { + icp_native_do_message(target, msg); + } else { + for_each_online_cpu(i) { + if (target == MSG_ALL_BUT_SELF + && i == smp_processor_id()) + continue; + icp_native_do_message(i, msg); + } + } +} + +static irqreturn_t icp_native_ipi_action(int irq, void *dev_id) +{ + int cpu = smp_processor_id(); + + icp_native_set_qirr(cpu, 0xff); + + return xics_ipi_dispatch(cpu); +} + +#endif /* CONFIG_SMP */ + +static int __init icp_native_map_one_cpu(int hw_id, unsigned long addr, + unsigned long size) +{ + char *rname; + int i, cpu = -1; + + /* This may look gross but it's good enough for now, we don't quite + * have a hard -> linux processor id matching. + */ + for_each_possible_cpu(i) { + if (!cpu_present(i)) + continue; + if (hw_id == get_hard_smp_processor_id(i)) { + cpu = i; + break; + } + } + + /* Fail, skip that CPU. Don't print, it's normal, some XICS come up + * with way more entries in there than you have CPUs + */ + if (cpu == -1) + return 0; + + rname = kasprintf(GFP_KERNEL, "CPU %d [0x%x] Interrupt Presentation", + cpu, hw_id); + + if (!request_mem_region(addr, size, rname)) { + pr_warning("icp_native: Could not reserve ICP MMIO" + " for CPU %d, interrupt server #0x%x\n", + cpu, hw_id); + return -EBUSY; + } + + icp_native_regs[cpu] = ioremap(addr, size); + if (!icp_native_regs[cpu]) { + pr_warning("icp_native: Failed ioremap for CPU %d, " + "interrupt server #0x%x, addr %#lx\n", + cpu, hw_id, addr); + release_mem_region(addr, size); + return -ENOMEM; + } + return 0; +} + +static int __init icp_native_init_one_node(struct device_node *np, + unsigned int *indx) +{ + unsigned int ilen; + const u32 *ireg; + int i; + int reg_tuple_size; + int num_servers = 0; + + /* This code does the theorically broken assumption that the interrupt + * server numbers are the same as the hard CPU numbers. + * This happens to be the case so far but we are playing with fire... + * should be fixed one of these days. -BenH. + */ + ireg = of_get_property(np, "ibm,interrupt-server-ranges", &ilen); + + /* Do that ever happen ? we'll know soon enough... but even good'old + * f80 does have that property .. + */ + WARN_ON((ireg == NULL) || (ilen != 2*sizeof(u32))); + + if (ireg) { + *indx = of_read_number(ireg, 1); + if (ilen >= 2*sizeof(u32)) + num_servers = of_read_number(ireg + 1, 1); + } + + ireg = of_get_property(np, "reg", &ilen); + if (!ireg) { + pr_err("icp_native: Can't find interrupt reg property"); + return -1; + } + + reg_tuple_size = (of_n_addr_cells(np) + of_n_size_cells(np)) * 4; + if (((ilen % reg_tuple_size) != 0) + || (num_servers && (num_servers != (ilen / reg_tuple_size)))) { + pr_err("icp_native: ICP reg len (%d) != num servers (%d)", + ilen / reg_tuple_size, num_servers); + return -1; + } + + for (i = 0; i < (ilen / reg_tuple_size); i++) { + struct resource r; + int err; + + err = of_address_to_resource(np, i, &r); + if (err) { + pr_err("icp_native: Could not translate ICP MMIO" + " for interrupt server 0x%x (%d)\n", *indx, err); + return -1; + } + + if (icp_native_map_one_cpu(*indx, r.start, r.end - r.start)) + return -1; + + (*indx)++; + } + return 0; +} + +static const struct icp_ops icp_native_ops = { + .get_irq = icp_native_get_irq, + .eoi = icp_native_eoi, + .set_priority = icp_native_set_cpu_priority, + .teardown_cpu = icp_native_teardown_cpu, + .flush_ipi = icp_native_flush_ipi, +#ifdef CONFIG_SMP + .ipi_action = icp_native_ipi_action, + .message_pass = icp_native_message_pass, +#endif +}; + +int icp_native_init(void) +{ + struct device_node *np; + u32 indx = 0; + int found = 0; + + for_each_compatible_node(np, NULL, "ibm,ppc-xicp") + if (icp_native_init_one_node(np, &indx) == 0) + found = 1; + if (!found) { + for_each_node_by_type(np, + "PowerPC-External-Interrupt-Presentation") { + if (icp_native_init_one_node(np, &indx) == 0) + found = 1; + } + } + + if (found == 0) + return -ENODEV; + + icp_ops = &icp_native_ops; + + return 0; +} diff --git a/arch/powerpc/sysdev/xics/ics-rtas.c b/arch/powerpc/sysdev/xics/ics-rtas.c new file mode 100644 index 0000000..5b3ee38 --- /dev/null +++ b/arch/powerpc/sysdev/xics/ics-rtas.c @@ -0,0 +1,229 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +/* RTAS service tokens */ +static int ibm_get_xive; +static int ibm_set_xive; +static int ibm_int_on; +static int ibm_int_off; + +static int ics_rtas_map(struct ics *ics, unsigned int virq); +static void ics_rtas_mask_unknown(struct ics *ics, unsigned long vec); +static long ics_rtas_get_server(struct ics *ics, unsigned long vec); + +/* Only one global & state struct ics */ +static struct ics ics_rtas = { + .map = ics_rtas_map, + .mask_unknown = ics_rtas_mask_unknown, + .get_server = ics_rtas_get_server, +}; + +static void ics_rtas_unmask_irq(struct irq_data *d) +{ + unsigned int hw_irq = (unsigned int)irq_data_to_hw(d); + int call_status; + int server; + + pr_devel("xics: unmask virq %d [hw 0x%x]\n", d->irq, hw_irq); + + if (hw_irq == XICS_IPI || hw_irq == XICS_IRQ_SPURIOUS) + return; + + server = xics_get_irq_server(d->irq, d->affinity, 0); + + call_status = rtas_call(ibm_set_xive, 3, 1, NULL, hw_irq, server, + DEFAULT_PRIORITY); + if (call_status != 0) { + printk(KERN_ERR + "%s: ibm_set_xive irq %u server %x returned %d\n", + __func__, hw_irq, server, call_status); + return; + } + + /* Now unmask the interrupt (often a no-op) */ + call_status = rtas_call(ibm_int_on, 1, 1, NULL, hw_irq); + if (call_status != 0) { + printk(KERN_ERR "%s: ibm_int_on irq=%u returned %d\n", + __func__, hw_irq, call_status); + return; + } +} + +static unsigned int ics_rtas_startup(struct irq_data *d) +{ +#ifdef CONFIG_PCI_MSI + /* + * The generic MSI code returns with the interrupt disabled on the + * card, using the MSI mask bits. Firmware doesn't appear to unmask + * at that level, so we do it here by hand. + */ + if (d->msi_desc) + unmask_msi_irq(d); +#endif + /* unmask it */ + ics_rtas_unmask_irq(d); + return 0; +} + +static void ics_rtas_mask_real_irq(unsigned int hw_irq) +{ + int call_status; + + if (hw_irq == XICS_IPI) + return; + + call_status = rtas_call(ibm_int_off, 1, 1, NULL, hw_irq); + if (call_status != 0) { + printk(KERN_ERR "%s: ibm_int_off irq=%u returned %d\n", + __func__, hw_irq, call_status); + return; + } + + /* Have to set XIVE to 0xff to be able to remove a slot */ + call_status = rtas_call(ibm_set_xive, 3, 1, NULL, hw_irq, + xics_default_server, 0xff); + if (call_status != 0) { + printk(KERN_ERR "%s: ibm_set_xive(0xff) irq=%u returned %d\n", + __func__, hw_irq, call_status); + return; + } +} + +static void ics_rtas_mask_irq(struct irq_data *d) +{ + unsigned int hw_irq = (unsigned int)irq_data_to_hw(d); + + pr_devel("xics: mask virq %d [hw 0x%x]\n", d->irq, hw_irq); + + if (hw_irq == XICS_IPI || hw_irq == XICS_IRQ_SPURIOUS) + return; + ics_rtas_mask_real_irq(hw_irq); +} + +static int ics_rtas_set_affinity(struct irq_data *d, + const struct cpumask *cpumask, + bool force) +{ + unsigned int hw_irq = (unsigned int)irq_data_to_hw(d); + int status; + int xics_status[2]; + int irq_server; + + if (hw_irq == XICS_IPI || hw_irq == XICS_IRQ_SPURIOUS) + return -1; + + status = rtas_call(ibm_get_xive, 1, 3, xics_status, hw_irq); + + if (status) { + printk(KERN_ERR "%s: ibm,get-xive irq=%u returns %d\n", + __func__, hw_irq, status); + return -1; + } + + irq_server = xics_get_irq_server(d->irq, cpumask, 1); + if (irq_server == -1) { + char cpulist[128]; + cpumask_scnprintf(cpulist, sizeof(cpulist), cpumask); + printk(KERN_WARNING + "%s: No online cpus in the mask %s for irq %d\n", + __func__, cpulist, d->irq); + return -1; + } + + status = rtas_call(ibm_set_xive, 3, 1, NULL, + hw_irq, irq_server, xics_status[1]); + + if (status) { + printk(KERN_ERR "%s: ibm,set-xive irq=%u returns %d\n", + __func__, hw_irq, status); + return -1; + } + + return IRQ_SET_MASK_OK; +} + +static struct irq_chip ics_rtas_irq_chip = { + .name = "XICS", + .irq_startup = ics_rtas_startup, + .irq_mask = ics_rtas_mask_irq, + .irq_unmask = ics_rtas_unmask_irq, + .irq_eoi = NULL, /* Patched at init time */ + .irq_set_affinity = ics_rtas_set_affinity +}; + +static int ics_rtas_map(struct ics *ics, unsigned int virq) +{ + unsigned int hw_irq = (unsigned int)irq_map[virq].hwirq; + int status[2]; + int rc; + + if (WARN_ON(hw_irq == XICS_IPI || hw_irq == XICS_IRQ_SPURIOUS)) + return -EINVAL; + + /* Check if RTAS knows about this interrupt */ + rc = rtas_call(ibm_get_xive, 1, 3, status, hw_irq); + if (rc) + return -ENXIO; + + irq_set_chip_and_handler(virq, &ics_rtas_irq_chip, handle_fasteoi_irq); + irq_set_chip_data(virq, &ics_rtas); + + return 0; +} + +static void ics_rtas_mask_unknown(struct ics *ics, unsigned long vec) +{ + ics_rtas_mask_real_irq(vec); +} + +static long ics_rtas_get_server(struct ics *ics, unsigned long vec) +{ + int rc, status[2]; + + rc = rtas_call(ibm_get_xive, 1, 3, status, vec); + if (rc) + return -1; + return status[0]; +} + +int ics_rtas_init(void) +{ + ibm_get_xive = rtas_token("ibm,get-xive"); + ibm_set_xive = rtas_token("ibm,set-xive"); + ibm_int_on = rtas_token("ibm,int-on"); + ibm_int_off = rtas_token("ibm,int-off"); + + /* We enable the RTAS "ICS" if RTAS is present with the + * appropriate tokens + */ + if (ibm_get_xive == RTAS_UNKNOWN_SERVICE || + ibm_set_xive == RTAS_UNKNOWN_SERVICE) + return -ENODEV; + + /* We need to patch our irq chip's EOI to point to the + * right ICP + */ + ics_rtas_irq_chip.irq_eoi = icp_ops->eoi; + + /* Register ourselves */ + xics_register_ics(&ics_rtas); + + return 0; +} + diff --git a/arch/powerpc/sysdev/xics/xics-common.c b/arch/powerpc/sysdev/xics/xics-common.c new file mode 100644 index 0000000..a2be84d --- /dev/null +++ b/arch/powerpc/sysdev/xics/xics-common.c @@ -0,0 +1,461 @@ +/* + * Copyright 2011 IBM Corporation. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + * + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* Globals common to all ICP/ICS implementations */ +const struct icp_ops *icp_ops; + +unsigned int xics_default_server = 0xff; +unsigned int xics_default_distrib_server = 0; +unsigned int xics_interrupt_server_size = 8; + +DEFINE_PER_CPU(struct xics_cppr, xics_cppr); + +struct irq_host *xics_host; + +static LIST_HEAD(ics_list); + +void xics_update_irq_servers(void) +{ + int i, j; + struct device_node *np; + u32 ilen; + const u32 *ireg; + u32 hcpuid; + + /* Find the server numbers for the boot cpu. */ + np = of_get_cpu_node(boot_cpuid, NULL); + BUG_ON(!np); + + hcpuid = get_hard_smp_processor_id(boot_cpuid); + xics_default_server = hcpuid; + + ireg = of_get_property(np, "ibm,ppc-interrupt-gserver#s", &ilen); + if (!ireg) { + of_node_put(np); + return; + } + + i = ilen / sizeof(int); + + /* Global interrupt distribution server is specified in the last + * entry of "ibm,ppc-interrupt-gserver#s" property. Get the last + * entry fom this property for current boot cpu id and use it as + * default distribution server + */ + for (j = 0; j < i; j += 2) { + if (ireg[j] == hcpuid) { + xics_default_distrib_server = ireg[j+1]; + } + } + + of_node_put(np); +} + +/* GIQ stuff, currently only supported on RTAS setups, will have + * to be sorted properly for bare metal + */ +void xics_set_cpu_giq(unsigned int gserver, unsigned int join) +{ +#ifdef CONFIG_PPC_RTAS + int index; + int status; + + if (!rtas_indicator_present(GLOBAL_INTERRUPT_QUEUE, NULL)) + return; + + index = (1UL << xics_interrupt_server_size) - 1 - gserver; + + status = rtas_set_indicator_fast(GLOBAL_INTERRUPT_QUEUE, index, join); + + WARN(status < 0, "set-indicator(%d, %d, %u) returned %d\n", + GLOBAL_INTERRUPT_QUEUE, index, join, status); +#endif +} + +void xics_setup_cpu(void) +{ + icp_ops->set_priority(LOWEST_PRIORITY); + + xics_set_cpu_giq(xics_default_distrib_server, 1); +} + +void xics_mask_unknown_vec(unsigned int vec) +{ + struct ics *ics; + + pr_err("Interrupt %u (real) is invalid, disabling it.\n", vec); + + list_for_each_entry(ics, &ics_list, link) + ics->mask_unknown(ics, vec); +} + + +#ifdef CONFIG_SMP + +DEFINE_PER_CPU_SHARED_ALIGNED(unsigned long, xics_ipi_message); + +irqreturn_t xics_ipi_dispatch(int cpu) +{ + unsigned long *tgt = &per_cpu(xics_ipi_message, cpu); + + mb(); /* order mmio clearing qirr */ + while (*tgt) { + if (test_and_clear_bit(PPC_MSG_CALL_FUNCTION, tgt)) { + smp_message_recv(PPC_MSG_CALL_FUNCTION); + } + if (test_and_clear_bit(PPC_MSG_RESCHEDULE, tgt)) { + smp_message_recv(PPC_MSG_RESCHEDULE); + } + if (test_and_clear_bit(PPC_MSG_CALL_FUNC_SINGLE, tgt)) { + smp_message_recv(PPC_MSG_CALL_FUNC_SINGLE); + } +#if defined(CONFIG_DEBUGGER) || defined(CONFIG_KEXEC) + if (test_and_clear_bit(PPC_MSG_DEBUGGER_BREAK, tgt)) { + smp_message_recv(PPC_MSG_DEBUGGER_BREAK); + } +#endif + } + return IRQ_HANDLED; +} + +static void xics_request_ipi(void) +{ + unsigned int ipi; + + ipi = irq_create_mapping(xics_host, XICS_IPI); + BUG_ON(ipi == NO_IRQ); + + /* + * IPIs are marked IRQF_DISABLED as they must run with irqs + * disabled + */ + irq_set_handler(ipi, handle_percpu_irq); + BUG_ON(request_irq(ipi, icp_ops->ipi_action, + IRQF_DISABLED|IRQF_PERCPU, "IPI", NULL)); +} + +int __init xics_smp_probe(void) +{ + /* Setup message_pass callback based on which ICP is used */ + smp_ops->message_pass = icp_ops->message_pass; + + /* Register all the IPIs */ + xics_request_ipi(); + + return cpumask_weight(cpu_possible_mask); +} + +#endif /* CONFIG_SMP */ + +void xics_teardown_cpu(void) +{ + struct xics_cppr *os_cppr = &__get_cpu_var(xics_cppr); + + /* + * we have to reset the cppr index to 0 because we're + * not going to return from the IPI + */ + os_cppr->index = 0; + icp_ops->set_priority(0); + icp_ops->teardown_cpu(); +} + +void xics_kexec_teardown_cpu(int secondary) +{ + xics_teardown_cpu(); + + icp_ops->flush_ipi(); + + /* + * Some machines need to have at least one cpu in the GIQ, + * so leave the master cpu in the group. + */ + if (secondary) + xics_set_cpu_giq(xics_default_distrib_server, 0); +} + + +#ifdef CONFIG_HOTPLUG_CPU + +/* Interrupts are disabled. */ +void xics_migrate_irqs_away(void) +{ + int cpu = smp_processor_id(), hw_cpu = hard_smp_processor_id(); + unsigned int irq, virq; + + /* If we used to be the default server, move to the new "boot_cpuid" */ + if (hw_cpu == xics_default_server) + xics_update_irq_servers(); + + /* Reject any interrupt that was queued to us... */ + icp_ops->set_priority(0); + + /* Remove ourselves from the global interrupt queue */ + xics_set_cpu_giq(xics_default_distrib_server, 0); + + /* Allow IPIs again... */ + icp_ops->set_priority(DEFAULT_PRIORITY); + + for_each_irq(virq) { + struct irq_desc *desc; + struct irq_chip *chip; + long server; + unsigned long flags; + struct ics *ics; + + /* We can't set affinity on ISA interrupts */ + if (virq < NUM_ISA_INTERRUPTS) + continue; + if (irq_map[virq].host != xics_host) + continue; + irq = (unsigned int)irq_map[virq].hwirq; + /* We need to get IPIs still. */ + if (irq == XICS_IPI || irq == XICS_IRQ_SPURIOUS) + continue; + desc = irq_to_desc(virq); + /* We only need to migrate enabled IRQS */ + if (!desc || !desc->action) + continue; + chip = irq_desc_get_chip(desc); + if (!chip || !chip->irq_set_affinity) + continue; + + raw_spin_lock_irqsave(&desc->lock, flags); + + /* Locate interrupt server */ + server = -1; + ics = irq_get_chip_data(virq); + if (ics) + server = ics->get_server(ics, irq); + if (server < 0) { + printk(KERN_ERR "%s: Can't find server for irq %d\n", + __func__, irq); + goto unlock; + } + + /* We only support delivery to all cpus or to one cpu. + * The irq has to be migrated only in the single cpu + * case. + */ + if (server != hw_cpu) + goto unlock; + + /* This is expected during cpu offline. */ + if (cpu_online(cpu)) + pr_warning("IRQ %u affinity broken off cpu %u\n", + virq, cpu); + + /* Reset affinity to all cpus */ + raw_spin_unlock_irqrestore(&desc->lock, flags); + irq_set_affinity(virq, cpu_all_mask); + continue; +unlock: + raw_spin_unlock_irqrestore(&desc->lock, flags); + } +} +#endif /* CONFIG_HOTPLUG_CPU */ + +#ifdef CONFIG_SMP +/* + * For the moment we only implement delivery to all cpus or one cpu. + * + * If the requested affinity is cpu_all_mask, we set global affinity. + * If not we set it to the first cpu in the mask, even if multiple cpus + * are set. This is so things like irqbalance (which set core and package + * wide affinities) do the right thing. + */ +int xics_get_irq_server(unsigned int virq, const struct cpumask *cpumask, + unsigned int strict_check) +{ + + if (!distribute_irqs) + return xics_default_server; + + if (!cpumask_subset(cpu_possible_mask, cpumask)) { + int server = cpumask_first_and(cpu_online_mask, cpumask); + + if (server < nr_cpu_ids) + return get_hard_smp_processor_id(server); + + if (strict_check) + return -1; + } + + /* + * Workaround issue with some versions of JS20 firmware that + * deliver interrupts to cpus which haven't been started. This + * happens when using the maxcpus= boot option. + */ + if (cpumask_equal(cpu_online_mask, cpu_present_mask)) + return xics_default_distrib_server; + + return xics_default_server; +} +#endif /* CONFIG_SMP */ + +static int xics_host_match(struct irq_host *h, struct device_node *node) +{ + /* IBM machines have interrupt parents of various funky types for things + * like vdevices, events, etc... The trick we use here is to match + * everything here except the legacy 8259 which is compatible "chrp,iic" + */ + return !of_device_is_compatible(node, "chrp,iic"); +} + +/* Dummies */ +static void xics_ipi_unmask(struct irq_data *d) { } +static void xics_ipi_mask(struct irq_data *d) { } + +static struct irq_chip xics_ipi_chip = { + .name = "XICS", + .irq_eoi = NULL, /* Patched at init time */ + .irq_mask = xics_ipi_mask, + .irq_unmask = xics_ipi_unmask, +}; + +static int xics_host_map(struct irq_host *h, unsigned int virq, + irq_hw_number_t hw) +{ + struct ics *ics; + + pr_devel("xics: map virq %d, hwirq 0x%lx\n", virq, hw); + + /* Insert the interrupt mapping into the radix tree for fast lookup */ + irq_radix_revmap_insert(xics_host, virq, hw); + + /* They aren't all level sensitive but we just don't really know */ + irq_set_status_flags(virq, IRQ_LEVEL); + + /* Don't call into ICS for IPIs */ + if (hw == XICS_IPI) { + irq_set_chip_and_handler(virq, &xics_ipi_chip, + handle_fasteoi_irq); + return 0; + } + + /* Let the ICS setup the chip data */ + list_for_each_entry(ics, &ics_list, link) + if (ics->map(ics, virq) == 0) + break; + return 0; +} + +static int xics_host_xlate(struct irq_host *h, struct device_node *ct, + const u32 *intspec, unsigned int intsize, + irq_hw_number_t *out_hwirq, unsigned int *out_flags) + +{ + /* Current xics implementation translates everything + * to level. It is not technically right for MSIs but this + * is irrelevant at this point. We might get smarter in the future + */ + *out_hwirq = intspec[0]; + *out_flags = IRQ_TYPE_LEVEL_LOW; + + return 0; +} + +static struct irq_host_ops xics_host_ops = { + .match = xics_host_match, + .map = xics_host_map, + .xlate = xics_host_xlate, +}; + +static void __init xics_init_host(void) +{ + xics_host = irq_alloc_host(NULL, IRQ_HOST_MAP_TREE, 0, &xics_host_ops, + XICS_IRQ_SPURIOUS); + BUG_ON(xics_host == NULL); + irq_set_default_host(xics_host); +} + +void __init xics_register_ics(struct ics *ics) +{ + list_add(&ics->link, &ics_list); +} + +static void __init xics_get_server_size(void) +{ + struct device_node *np; + const u32 *isize; + + /* We fetch the interrupt server size from the first ICS node + * we find if any + */ + np = of_find_compatible_node(NULL, NULL, "ibm,ppc-xics"); + if (!np) + return; + isize = of_get_property(np, "ibm,interrupt-server#-size", NULL); + if (!isize) + return; + xics_interrupt_server_size = *isize; + of_node_put(np); +} + +void __init xics_init(void) +{ + int rc = -1; + + /* Fist locate ICP */ +#ifdef CONFIG_PPC_ICP_HV + if (firmware_has_feature(FW_FEATURE_LPAR)) + rc = icp_hv_init(); +#endif +#ifdef CONFIG_PPC_ICP_NATIVE + if (rc < 0) + rc = icp_native_init(); +#endif + if (rc < 0) { + pr_warning("XICS: Cannot find a Presentation Controller !\n"); + return; + } + + /* Copy get_irq callback over to ppc_md */ + ppc_md.get_irq = icp_ops->get_irq; + + /* Patch up IPI chip EOI */ + xics_ipi_chip.irq_eoi = icp_ops->eoi; + + /* Now locate ICS */ +#ifdef CONFIG_PPC_ICS_RTAS + rc = ics_rtas_init(); +#endif + if (rc < 0) + pr_warning("XICS: Cannot find a Source Controller !\n"); + + /* Initialize common bits */ + xics_get_server_size(); + xics_update_irq_servers(); + xics_init_host(); + xics_setup_cpu(); +} -- cgit v0.10.2 From 50fb8ebe7c4ad60d147700d253f78bd1e615a526 Mon Sep 17 00:00:00 2001 From: Benjamin Herrenschmidt Date: Wed, 12 Jan 2011 17:41:28 +1100 Subject: powerpc: Add more Power7 specific definitions This adds more SPR definitions used on newer processors when running in hypervisor mode. Along with some other P7 specific bits and pieces Signed-off-by: Benjamin Herrenschmidt diff --git a/arch/powerpc/include/asm/ppc_asm.h b/arch/powerpc/include/asm/ppc_asm.h index 9821006..1b42238 100644 --- a/arch/powerpc/include/asm/ppc_asm.h +++ b/arch/powerpc/include/asm/ppc_asm.h @@ -170,6 +170,7 @@ END_FW_FTR_SECTION_IFSET(FW_FEATURE_SPLPAR) #define HMT_MEDIUM or 2,2,2 #define HMT_MEDIUM_HIGH or 5,5,5 # medium high priority #define HMT_HIGH or 3,3,3 +#define HMT_EXTRA_HIGH or 7,7,7 # power7 only #ifdef __KERNEL__ #ifdef CONFIG_PPC64 diff --git a/arch/powerpc/include/asm/reg.h b/arch/powerpc/include/asm/reg.h index 7e4abeb..6eb1d77 100644 --- a/arch/powerpc/include/asm/reg.h +++ b/arch/powerpc/include/asm/reg.h @@ -210,8 +210,43 @@ #define SPRN_TBWL 0x11C /* Time Base Lower Register (super, R/W) */ #define SPRN_TBWU 0x11D /* Time Base Upper Register (super, R/W) */ #define SPRN_SPURR 0x134 /* Scaled PURR */ +#define SPRN_HSPRG0 0x130 /* Hypervisor Scratch 0 */ +#define SPRN_HSPRG1 0x131 /* Hypervisor Scratch 1 */ +#define SPRN_HDSISR 0x132 +#define SPRN_HDAR 0x133 +#define SPRN_HDEC 0x136 /* Hypervisor Decrementer */ #define SPRN_HIOR 0x137 /* 970 Hypervisor interrupt offset */ +#define SPRN_RMOR 0x138 /* Real mode offset register */ +#define SPRN_HRMOR 0x139 /* Real mode offset register */ +#define SPRN_HSRR0 0x13A /* Hypervisor Save/Restore 0 */ +#define SPRN_HSRR1 0x13B /* Hypervisor Save/Restore 1 */ #define SPRN_LPCR 0x13E /* LPAR Control Register */ +#define LPCR_VPM0 (1ul << (63-0)) +#define LPCR_VPM1 (1ul << (63-1)) +#define LPCR_ISL (1ul << (63-2)) +#define LPCR_DPFD_SH (63-11) +#define LPCR_VRMA_L (1ul << (63-12)) +#define LPCR_VRMA_LP0 (1ul << (63-15)) +#define LPCR_VRMA_LP1 (1ul << (63-16)) +#define LPCR_RMLS 0x1C000000 /* impl dependent rmo limit sel */ +#define LPCR_ILE 0x02000000 /* !HV irqs set MSR:LE */ +#define LPCR_PECE 0x00007000 /* powersave exit cause enable */ +#define LPCR_PECE0 0x00004000 /* ext. exceptions can cause exit */ +#define LPCR_PECE1 0x00002000 /* decrementer can cause exit */ +#define LPCR_PECE2 0x00001000 /* machine check etc can cause exit */ +#define LPCR_MER 0x00000800 /* Mediated External Exception */ +#define LPCR_LPES0 0x00000008 /* LPAR Env selector 0 */ +#define LPCR_LPES1 0x00000004 /* LPAR Env selector 1 */ +#define LPCR_RMI 0x00000002 /* real mode is cache inhibit */ +#define LPCR_HDICE 0x00000001 /* Hyp Decr enable (HV,PR,EE) */ +#define SPRN_LPID 0x13F /* Logical Partition Identifier */ +#define SPRN_HMER 0x150 /* Hardware m? error recovery */ +#define SPRN_HMEER 0x151 /* Hardware m? enable error recovery */ +#define SPRN_HEIR 0x153 /* Hypervisor Emulated Instruction Register */ +#define SPRN_TLBINDEXR 0x154 /* P7 TLB control register */ +#define SPRN_TLBVPNR 0x155 /* P7 TLB control register */ +#define SPRN_TLBRPNR 0x156 /* P7 TLB control register */ +#define SPRN_TLBLPIDR 0x157 /* P7 TLB control register */ #define SPRN_DBAT0L 0x219 /* Data BAT 0 Lower Register */ #define SPRN_DBAT0U 0x218 /* Data BAT 0 Upper Register */ #define SPRN_DBAT1L 0x21B /* Data BAT 1 Lower Register */ @@ -434,16 +469,23 @@ #define SPRN_SRR0 0x01A /* Save/Restore Register 0 */ #define SPRN_SRR1 0x01B /* Save/Restore Register 1 */ #define SRR1_WAKEMASK 0x00380000 /* reason for wakeup */ -#define SRR1_WAKERESET 0x00380000 /* System reset */ #define SRR1_WAKESYSERR 0x00300000 /* System error */ #define SRR1_WAKEEE 0x00200000 /* External interrupt */ #define SRR1_WAKEMT 0x00280000 /* mtctrl */ +#define SRR1_WAKEHMI 0x00280000 /* Hypervisor maintenance */ #define SRR1_WAKEDEC 0x00180000 /* Decrementer interrupt */ #define SRR1_WAKETHERM 0x00100000 /* Thermal management interrupt */ +#define SRR1_WAKERESET 0x00100000 /* System reset */ +#define SRR1_WAKESTATE 0x00030000 /* Powersave exit mask [46:47] */ +#define SRR1_WS_DEEPEST 0x00030000 /* Some resources not maintained, + * may not be recoverable */ +#define SRR1_WS_DEEPER 0x00020000 /* Some resources not maintained */ +#define SRR1_WS_DEEP 0x00010000 /* All resources maintained */ #define SRR1_PROGFPE 0x00100000 /* Floating Point Enabled */ #define SRR1_PROGPRIV 0x00040000 /* Privileged instruction */ #define SRR1_PROGTRAP 0x00020000 /* Trap */ #define SRR1_PROGADDR 0x00010000 /* SRR0 contains subsequent addr */ + #define SPRN_HSRR0 0x13A /* Save/Restore Register 0 */ #define SPRN_HSRR1 0x13B /* Save/Restore Register 1 */ @@ -894,6 +936,8 @@ #define PV_POWER5p 0x003B #define PV_POWER7 0x003F #define PV_970FX 0x003C +#define PV_POWER6 0x003E +#define PV_POWER7 0x003F #define PV_630 0x0040 #define PV_630p 0x0041 #define PV_970MP 0x0044 -- cgit v0.10.2 From f6e17f9b0bf172a5813dfef0c03d0a25ba83b0de Mon Sep 17 00:00:00 2001 From: Benjamin Herrenschmidt Date: Fri, 4 Mar 2011 18:25:55 +1100 Subject: powerpc/xics: Make sure we have a sensible default distribution server Even when nothing is specified in the device tree, and despite the fact that we don't setup links properly yet, we still need a reasonable value in there or some interrupts won't be setup properly to point to an existing processor. Signed-off-by: Benjamin Herrenschmidt diff --git a/arch/powerpc/sysdev/xics/xics-common.c b/arch/powerpc/sysdev/xics/xics-common.c index a2be84d..e70175d 100644 --- a/arch/powerpc/sysdev/xics/xics-common.c +++ b/arch/powerpc/sysdev/xics/xics-common.c @@ -57,7 +57,9 @@ void xics_update_irq_servers(void) BUG_ON(!np); hcpuid = get_hard_smp_processor_id(boot_cpuid); - xics_default_server = hcpuid; + xics_default_server = xics_default_distrib_server = hcpuid; + + pr_devel("xics: xics_default_server = 0x%x\n", xics_default_server); ireg = of_get_property(np, "ibm,ppc-interrupt-gserver#s", &ilen); if (!ireg) { @@ -75,9 +77,11 @@ void xics_update_irq_servers(void) for (j = 0; j < i; j += 2) { if (ireg[j] == hcpuid) { xics_default_distrib_server = ireg[j+1]; + break; } } - + pr_devel("xics: xics_default_distrib_server = 0x%x\n", + xics_default_distrib_server); of_node_put(np); } @@ -113,7 +117,7 @@ void xics_mask_unknown_vec(unsigned int vec) { struct ics *ics; - pr_err("Interrupt %u (real) is invalid, disabling it.\n", vec); + pr_err("Interrupt 0x%x (real) is invalid, disabling it.\n", vec); list_for_each_entry(ics, &ics_list, link) ics->mask_unknown(ics, vec); @@ -293,6 +297,8 @@ unlock: * If not we set it to the first cpu in the mask, even if multiple cpus * are set. This is so things like irqbalance (which set core and package * wide affinities) do the right thing. + * + * We need to fix this to implement support for the links */ int xics_get_irq_server(unsigned int virq, const struct cpumask *cpumask, unsigned int strict_check) -- cgit v0.10.2 From 24cc67de62eebbda3ce0c46bdd56582c00dccd03 Mon Sep 17 00:00:00 2001 From: Benjamin Herrenschmidt Date: Thu, 20 Jan 2011 18:50:55 +1100 Subject: powerpc: Define CPU feature for Architected 2.06 HV mode This bit indicates that we are operating in hypervisor mode on a CPU compliant to architecture 2.06 or later (currently server only). We set it on POWER7 and have a boot-time CPU setup function that clears it if MSR:HV isn't set (booting under a hypervisor). Signed-off-by: Benjamin Herrenschmidt diff --git a/arch/powerpc/include/asm/cputable.h b/arch/powerpc/include/asm/cputable.h index 1833d1a..2fe37d7 100644 --- a/arch/powerpc/include/asm/cputable.h +++ b/arch/powerpc/include/asm/cputable.h @@ -181,6 +181,7 @@ extern const char *powerpc_base_platform; #define CPU_FTR_SLB LONG_ASM_CONST(0x0000000100000000) #define CPU_FTR_16M_PAGE LONG_ASM_CONST(0x0000000200000000) #define CPU_FTR_TLBIEL LONG_ASM_CONST(0x0000000400000000) +#define CPU_FTR_HVMODE_206 LONG_ASM_CONST(0x0000000800000000) #define CPU_FTR_IABR LONG_ASM_CONST(0x0000002000000000) #define CPU_FTR_MMCRA LONG_ASM_CONST(0x0000004000000000) #define CPU_FTR_CTRL LONG_ASM_CONST(0x0000008000000000) @@ -418,7 +419,7 @@ extern const char *powerpc_base_platform; CPU_FTR_DSCR | CPU_FTR_UNALIGNED_LD_STD | \ CPU_FTR_STCX_CHECKS_ADDRESS | CPU_FTR_POPCNTB) #define CPU_FTRS_POWER7 (CPU_FTR_USE_TB | CPU_FTR_LWSYNC | \ - CPU_FTR_PPCAS_ARCH_V2 | CPU_FTR_CTRL | \ + CPU_FTR_PPCAS_ARCH_V2 | CPU_FTR_CTRL | CPU_FTR_HVMODE_206 |\ CPU_FTR_MMCRA | CPU_FTR_SMT | \ CPU_FTR_COHERENT_ICACHE | CPU_FTR_LOCKLESS_TLBIE | \ CPU_FTR_PURR | CPU_FTR_SPURR | CPU_FTR_REAL_LE | \ diff --git a/arch/powerpc/kernel/Makefile b/arch/powerpc/kernel/Makefile index 3bb2a3e..7c6eb49 100644 --- a/arch/powerpc/kernel/Makefile +++ b/arch/powerpc/kernel/Makefile @@ -38,6 +38,7 @@ obj-$(CONFIG_PPC64) += setup_64.o sys_ppc32.o \ paca.o nvram_64.o firmware.o obj-$(CONFIG_HAVE_HW_BREAKPOINT) += hw_breakpoint.o obj-$(CONFIG_PPC_BOOK3S_64) += cpu_setup_ppc970.o cpu_setup_pa6t.o +obj-$(CONFIG_PPC_BOOK3S_64) += cpu_setup_power7.o obj64-$(CONFIG_RELOCATABLE) += reloc_64.o obj-$(CONFIG_PPC_BOOK3E_64) += exceptions-64e.o idle_book3e.o obj-$(CONFIG_PPC64) += vdso64/ diff --git a/arch/powerpc/kernel/cpu_setup_power7.S b/arch/powerpc/kernel/cpu_setup_power7.S new file mode 100644 index 0000000..f2b3178 --- /dev/null +++ b/arch/powerpc/kernel/cpu_setup_power7.S @@ -0,0 +1,65 @@ +/* + * This file contains low level CPU setup functions. + * Copyright (C) 2003 Benjamin Herrenschmidt (benh@kernel.crashing.org) + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + * + */ + +#include +#include +#include +#include +#include +#include + +/* Entry: r3 = crap, r4 = ptr to cputable entry + * + * Note that we can be called twice for pseudo-PVRs + */ +_GLOBAL(__setup_cpu_power7) + mflr r11 + bl __init_hvmode_206 + mtlr r11 + beqlr + bl __init_LPCR + mtlr r11 + blr + +_GLOBAL(__restore_cpu_power7) + mflr r11 + mfmsr r3 + rldicl. r0,r3,4,63 + beqlr + bl __init_LPCR + mtlr r11 + blr + +__init_hvmode_206: + /* Disable CPU_FTR_HVMODE_206 and exit if MSR:HV is not set */ + mfmsr r3 + rldicl. r0,r3,4,63 + bnelr + ld r5,CPU_SPEC_FEATURES(r4) + LOAD_REG_IMMEDIATE(r6,CPU_FTR_HVMODE_206) + xor r5,r5,r6 + std r5,CPU_SPEC_FEATURES(r4) + blr + +__init_LPCR: + /* Setup a sane LPCR: + * + * LPES = 0b11 (SRR0/1 used for 0x500) + * PECE = 0b111 + * + * Other bits untouched for now + */ + mfspr r3,SPRN_LPCR + ori r3,r3,(LPCR_LPES0|LPCR_LPES1) + ori r3,r3,(LPCR_PECE0|LPCR_PECE1|LPCR_PECE2) + mtspr SPRN_LPCR,r3 + isync + blr diff --git a/arch/powerpc/kernel/cputable.c b/arch/powerpc/kernel/cputable.c index b9602ee..b65b490 100644 --- a/arch/powerpc/kernel/cputable.c +++ b/arch/powerpc/kernel/cputable.c @@ -423,6 +423,8 @@ static struct cpu_spec __initdata cpu_specs[] = { .dcache_bsize = 128, .oprofile_type = PPC_OPROFILE_POWER4, .oprofile_cpu_type = "ppc64/ibm-compat-v1", + .cpu_setup = __setup_cpu_power7, + .cpu_restore = __restore_cpu_power7, .platform = "power7", }, { /* Power7 */ @@ -439,6 +441,8 @@ static struct cpu_spec __initdata cpu_specs[] = { .pmc_type = PPC_PMC_IBM, .oprofile_cpu_type = "ppc64/power7", .oprofile_type = PPC_OPROFILE_POWER4, + .cpu_setup = __setup_cpu_power7, + .cpu_restore = __restore_cpu_power7, .platform = "power7", }, { /* Power7+ */ @@ -455,6 +459,8 @@ static struct cpu_spec __initdata cpu_specs[] = { .pmc_type = PPC_PMC_IBM, .oprofile_cpu_type = "ppc64/power7", .oprofile_type = PPC_OPROFILE_POWER4, + .cpu_setup = __setup_cpu_power7, + .cpu_restore = __restore_cpu_power7, .platform = "power7+", }, { /* Cell Broadband Engine */ -- cgit v0.10.2 From 2dd60d79e0202628a47af9812a84d502cc63628c Mon Sep 17 00:00:00 2001 From: Benjamin Herrenschmidt Date: Thu, 20 Jan 2011 17:50:21 +1100 Subject: powerpc: In HV mode, use HSPRG0 for PACA When running in Hypervisor mode (arch 2.06 or later), we store the PACA in HSPRG0 instead of SPRG1. The architecture specifies that SPRGs may be lost during a "nap" power management operation (though they aren't currently on POWER7) and this enables use of SPRG1 by KVM guests. Signed-off-by: Benjamin Herrenschmidt diff --git a/arch/powerpc/include/asm/exception-64s.h b/arch/powerpc/include/asm/exception-64s.h index 7778d6f..337b6fa 100644 --- a/arch/powerpc/include/asm/exception-64s.h +++ b/arch/powerpc/include/asm/exception-64s.h @@ -56,8 +56,8 @@ #define LOAD_HANDLER(reg, label) \ addi reg,reg,(label)-_stext; /* virt addr of handler ... */ -#define EXCEPTION_PROLOG_1(area) \ - mfspr r13,SPRN_SPRG_PACA; /* get paca address into r13 */ \ +#define EXCEPTION_PROLOG_1(area) \ + GET_PACA(r13); \ std r9,area+EX_R9(r13); /* save r9 - r12 */ \ std r10,area+EX_R10(r13); \ std r11,area+EX_R11(r13); \ @@ -174,7 +174,7 @@ label##_pSeries: \ HMT_MEDIUM; \ DO_KVM n; \ mtspr SPRN_SPRG_SCRATCH0,r13; /* save r13 */ \ - mfspr r13,SPRN_SPRG_PACA; /* get paca address into r13 */ \ + GET_PACA(r13); \ std r9,PACA_EXGEN+EX_R9(r13); /* save r9, r10 */ \ std r10,PACA_EXGEN+EX_R10(r13); \ lbz r10,PACASOFTIRQEN(r13); \ diff --git a/arch/powerpc/include/asm/reg.h b/arch/powerpc/include/asm/reg.h index 6eb1d77..13429a0 100644 --- a/arch/powerpc/include/asm/reg.h +++ b/arch/powerpc/include/asm/reg.h @@ -715,12 +715,15 @@ * SPRG usage: * * All 64-bit: - * - SPRG1 stores PACA pointer + * - SPRG1 stores PACA pointer except 64-bit server in + * HV mode in which case it is HSPRG0 * * 64-bit server: * - SPRG0 unused (reserved for HV on Power4) * - SPRG2 scratch for exception vectors * - SPRG3 unused (user visible) + * - HSPRG0 stores PACA in HV mode + * - HSPRG1 scratch for "HV" exceptions * * 64-bit embedded * - SPRG0 generic exception scratch @@ -783,6 +786,22 @@ #ifdef CONFIG_PPC_BOOK3S_64 #define SPRN_SPRG_SCRATCH0 SPRN_SPRG2 +#define SPRN_SPRG_HPACA SPRN_HSPRG0 +#define SPRN_SPRG_HSCRATCH0 SPRN_HSPRG1 + +#define GET_PACA(rX) \ + BEGIN_FTR_SECTION_NESTED(66); \ + mfspr rX,SPRN_SPRG_PACA; \ + FTR_SECTION_ELSE_NESTED(66); \ + mfspr rX,SPRN_SPRG_HPACA; \ + ALT_FTR_SECTION_END_NESTED_IFCLR(CPU_FTR_HVMODE_206, 66) + +#define SET_PACA(rX) \ + BEGIN_FTR_SECTION_NESTED(66); \ + mtspr SPRN_SPRG_PACA,rX; \ + FTR_SECTION_ELSE_NESTED(66); \ + mtspr SPRN_SPRG_HPACA,rX; \ + ALT_FTR_SECTION_END_NESTED_IFCLR(CPU_FTR_HVMODE_206, 66) #endif #ifdef CONFIG_PPC_BOOK3E_64 @@ -792,6 +811,10 @@ #define SPRN_SPRG_TLB_EXFRAME SPRN_SPRG2 #define SPRN_SPRG_TLB_SCRATCH SPRN_SPRG6 #define SPRN_SPRG_GEN_SCRATCH SPRN_SPRG0 + +#define SET_PACA(rX) mtspr SPRN_SPRG_PACA,rX +#define GET_PACA(rX) mfspr rX,SPRN_SPRG_PACA + #endif #ifdef CONFIG_PPC_BOOK3S_32 @@ -842,6 +865,8 @@ #define SPRN_SPRG_SCRATCH1 SPRN_SPRG1 #endif + + /* * An mtfsf instruction with the L bit set. On CPUs that support this a * full 64bits of FPSCR is restored and on other CPUs the L bit is ignored. diff --git a/arch/powerpc/kernel/entry_64.S b/arch/powerpc/kernel/entry_64.S index d82878c..dbf5bfa 100644 --- a/arch/powerpc/kernel/entry_64.S +++ b/arch/powerpc/kernel/entry_64.S @@ -838,7 +838,7 @@ _GLOBAL(enter_rtas) _STATIC(rtas_return_loc) /* relocation is off at this point */ - mfspr r4,SPRN_SPRG_PACA /* Get PACA */ + GET_PACA(r4) clrldi r4,r4,2 /* convert to realmode address */ bcl 20,31,$+4 @@ -869,7 +869,7 @@ _STATIC(rtas_restore_regs) REST_8GPRS(14, r1) /* Restore the non-volatiles */ REST_10GPRS(22, r1) /* ditto */ - mfspr r13,SPRN_SPRG_PACA + GET_PACA(r13) ld r4,_CCR(r1) mtcr r4 diff --git a/arch/powerpc/kernel/exceptions-64s.S b/arch/powerpc/kernel/exceptions-64s.S index aeb739e..6784bf7 100644 --- a/arch/powerpc/kernel/exceptions-64s.S +++ b/arch/powerpc/kernel/exceptions-64s.S @@ -53,7 +53,7 @@ data_access_pSeries: DO_KVM 0x300 mtspr SPRN_SPRG_SCRATCH0,r13 BEGIN_FTR_SECTION - mfspr r13,SPRN_SPRG_PACA + GET_PACA(r13) std r9,PACA_EXSLB+EX_R9(r13) std r10,PACA_EXSLB+EX_R10(r13) mfspr r10,SPRN_DAR @@ -82,7 +82,7 @@ data_access_slb_pSeries: HMT_MEDIUM DO_KVM 0x380 mtspr SPRN_SPRG_SCRATCH0,r13 - mfspr r13,SPRN_SPRG_PACA /* get paca address into r13 */ + GET_PACA(r13) std r3,PACA_EXSLB+EX_R3(r13) mfspr r3,SPRN_DAR std r9,PACA_EXSLB+EX_R9(r13) /* save r9 - r12 */ @@ -121,7 +121,7 @@ instruction_access_slb_pSeries: HMT_MEDIUM DO_KVM 0x480 mtspr SPRN_SPRG_SCRATCH0,r13 - mfspr r13,SPRN_SPRG_PACA /* get paca address into r13 */ + GET_PACA(r13) std r3,PACA_EXSLB+EX_R3(r13) mfspr r3,SPRN_SRR0 /* SRR0 is faulting address */ std r9,PACA_EXSLB+EX_R9(r13) /* save r9 - r12 */ @@ -165,7 +165,7 @@ BEGIN_FTR_SECTION beq- 1f END_FTR_SECTION_IFSET(CPU_FTR_REAL_LE) mr r9,r13 - mfspr r13,SPRN_SPRG_PACA + GET_PACA(r13) mfspr r11,SPRN_SRR0 ld r12,PACAKBASE(r13) ld r10,PACAKMSR(r13) diff --git a/arch/powerpc/kernel/head_64.S b/arch/powerpc/kernel/head_64.S index 3a319f9..39a4040 100644 --- a/arch/powerpc/kernel/head_64.S +++ b/arch/powerpc/kernel/head_64.S @@ -228,7 +228,7 @@ generic_secondary_common_init: mr r3,r24 /* not found, copy phys to r3 */ b .kexec_wait /* next kernel might do better */ -2: mtspr SPRN_SPRG_PACA,r13 /* Save vaddr of paca in an SPRG */ +2: SET_PACA(r13) #ifdef CONFIG_PPC_BOOK3E addi r12,r13,PACA_EXTLB /* and TLB exc frame in another */ mtspr SPRN_SPRG_TLB_EXFRAME,r12 @@ -534,7 +534,7 @@ _GLOBAL(pmac_secondary_start) ld r4,0(r4) /* Get base vaddr of paca array */ mulli r13,r24,PACA_SIZE /* Calculate vaddr of right paca */ add r13,r13,r4 /* for this processor. */ - mtspr SPRN_SPRG_PACA,r13 /* Save vaddr of paca in an SPRG*/ + SET_PACA(r13) /* Save vaddr of paca in an SPRG*/ /* Mark interrupts soft and hard disabled (they might be enabled * in the PACA when doing hotplug) diff --git a/arch/powerpc/kernel/paca.c b/arch/powerpc/kernel/paca.c index 10f0aad..102244e 100644 --- a/arch/powerpc/kernel/paca.c +++ b/arch/powerpc/kernel/paca.c @@ -156,11 +156,22 @@ void __init initialise_paca(struct paca_struct *new_paca, int cpu) /* Put the paca pointer into r13 and SPRG_PACA */ void setup_paca(struct paca_struct *new_paca) { + /* Setup r13 */ local_paca = new_paca; - mtspr(SPRN_SPRG_PACA, local_paca); + #ifdef CONFIG_PPC_BOOK3E + /* On Book3E, initialize the TLB miss exception frames */ mtspr(SPRN_SPRG_TLB_EXFRAME, local_paca->extlb); +#else + /* In HV mode, we setup both HPACA and PACA to avoid problems + * if we do a GET_PACA() before the feature fixups have been + * applied + */ + if (cpu_has_feature(CPU_FTR_HVMODE_206)) + mtspr(SPRN_SPRG_HPACA, local_paca); #endif + mtspr(SPRN_SPRG_PACA, local_paca); + } static int __initdata paca_size; diff --git a/arch/powerpc/kvm/book3s_rmhandlers.S b/arch/powerpc/kvm/book3s_rmhandlers.S index 2b9c908..b0ff5ff 100644 --- a/arch/powerpc/kvm/book3s_rmhandlers.S +++ b/arch/powerpc/kvm/book3s_rmhandlers.S @@ -35,9 +35,7 @@ #if defined(CONFIG_PPC_BOOK3S_64) -#define LOAD_SHADOW_VCPU(reg) \ - mfspr reg, SPRN_SPRG_PACA - +#define LOAD_SHADOW_VCPU(reg) GET_PACA(reg) #define SHADOW_VCPU_OFF PACA_KVM_SVCPU #define MSR_NOIRQ MSR_KERNEL & ~(MSR_IR | MSR_DR) #define FUNC(name) GLUE(.,name) -- cgit v0.10.2 From a5d4f3ad3a28cf046836b9bfae61d532b8f77036 Mon Sep 17 00:00:00 2001 From: Benjamin Herrenschmidt Date: Tue, 5 Apr 2011 14:20:31 +1000 Subject: powerpc: Base support for exceptions using HSRR0/1 Pass the register type to the prolog, also provides alternate "HV" version of hardware interrupt (0x500) and adjust LPES accordingly We tag those interrupts by setting bit 0x2 in the trap number Signed-off-by: Benjamin Herrenschmidt diff --git a/arch/powerpc/include/asm/exception-64s.h b/arch/powerpc/include/asm/exception-64s.h index 337b6fa..1d98e05 100644 --- a/arch/powerpc/include/asm/exception-64s.h +++ b/arch/powerpc/include/asm/exception-64s.h @@ -56,30 +56,37 @@ #define LOAD_HANDLER(reg, label) \ addi reg,reg,(label)-_stext; /* virt addr of handler ... */ -#define EXCEPTION_PROLOG_1(area) \ +/* Exception register prefixes */ +#define EXC_HV H +#define EXC_STD + +#define __EXCEPTION_PROLOG_1(area, h) \ GET_PACA(r13); \ std r9,area+EX_R9(r13); /* save r9 - r12 */ \ std r10,area+EX_R10(r13); \ std r11,area+EX_R11(r13); \ std r12,area+EX_R12(r13); \ - mfspr r9,SPRN_SPRG_SCRATCH0; \ + mfspr r9,SPRN_SPRG_##h##SCRATCH0; \ std r9,area+EX_R13(r13); \ mfcr r9 +#define EXCEPTION_PROLOG_1(area, h) __EXCEPTION_PROLOG_1(area, h) -#define EXCEPTION_PROLOG_PSERIES_1(label) \ +#define __EXCEPTION_PROLOG_PSERIES_1(label, h) \ ld r12,PACAKBASE(r13); /* get high part of &label */ \ ld r10,PACAKMSR(r13); /* get MSR value for kernel */ \ - mfspr r11,SPRN_SRR0; /* save SRR0 */ \ + mfspr r11,SPRN_##h##SRR0; /* save SRR0 */ \ LOAD_HANDLER(r12,label) \ - mtspr SPRN_SRR0,r12; \ - mfspr r12,SPRN_SRR1; /* and SRR1 */ \ - mtspr SPRN_SRR1,r10; \ - rfid; \ + mtspr SPRN_##h##SRR0,r12; \ + mfspr r12,SPRN_##h##SRR1; /* and SRR1 */ \ + mtspr SPRN_##h##SRR1,r10; \ + h##rfid; \ b . /* prevent speculative execution */ +#define EXCEPTION_PROLOG_PSERIES_1(label, h) \ + __EXCEPTION_PROLOG_PSERIES_1(label, h) -#define EXCEPTION_PROLOG_PSERIES(area, label) \ - EXCEPTION_PROLOG_1(area); \ - EXCEPTION_PROLOG_PSERIES_1(label); +#define EXCEPTION_PROLOG_PSERIES(area, label, h) \ + EXCEPTION_PROLOG_1(area, h); \ + EXCEPTION_PROLOG_PSERIES_1(label, h); /* * The common exception prolog is used for all except a few exceptions @@ -150,50 +157,44 @@ label##_pSeries: \ HMT_MEDIUM; \ DO_KVM n; \ mtspr SPRN_SPRG_SCRATCH0,r13; /* save r13 */ \ - EXCEPTION_PROLOG_PSERIES(PACA_EXGEN, label##_common) + EXCEPTION_PROLOG_PSERIES(PACA_EXGEN, label##_common, EXC_STD) #define HSTD_EXCEPTION_PSERIES(n, label) \ . = n; \ .globl label##_pSeries; \ label##_pSeries: \ HMT_MEDIUM; \ - mtspr SPRN_SPRG_SCRATCH0,r20; /* save r20 */ \ - mfspr r20,SPRN_HSRR0; /* copy HSRR0 to SRR0 */ \ - mtspr SPRN_SRR0,r20; \ - mfspr r20,SPRN_HSRR1; /* copy HSRR0 to SRR0 */ \ - mtspr SPRN_SRR1,r20; \ - mfspr r20,SPRN_SPRG_SCRATCH0; /* restore r20 */ \ - mtspr SPRN_SPRG_SCRATCH0,r13; /* save r13 */ \ - EXCEPTION_PROLOG_PSERIES(PACA_EXGEN, label##_common) + DO_KVM n; \ + mtspr SPRN_SPRG_HSCRATCH0,r13;/* save r13 */ \ + EXCEPTION_PROLOG_PSERIES(PACA_EXGEN, label##_common, EXC_HV) -#define MASKABLE_EXCEPTION_PSERIES(n, label) \ - . = n; \ - .globl label##_pSeries; \ -label##_pSeries: \ +#define __MASKABLE_EXCEPTION_PSERIES(n, label, h) \ HMT_MEDIUM; \ DO_KVM n; \ - mtspr SPRN_SPRG_SCRATCH0,r13; /* save r13 */ \ + mtspr SPRN_SPRG_##h##SCRATCH0,r13; /* save r13 */ \ GET_PACA(r13); \ std r9,PACA_EXGEN+EX_R9(r13); /* save r9, r10 */ \ std r10,PACA_EXGEN+EX_R10(r13); \ lbz r10,PACASOFTIRQEN(r13); \ mfcr r9; \ cmpwi r10,0; \ - beq masked_interrupt; \ - mfspr r10,SPRN_SPRG_SCRATCH0; \ + beq masked_##h##interrupt; \ + mfspr r10,SPRN_SPRG_##h##SCRATCH0; \ std r10,PACA_EXGEN+EX_R13(r13); \ std r11,PACA_EXGEN+EX_R11(r13); \ std r12,PACA_EXGEN+EX_R12(r13); \ ld r12,PACAKBASE(r13); /* get high part of &label */ \ ld r10,PACAKMSR(r13); /* get MSR value for kernel */ \ - mfspr r11,SPRN_SRR0; /* save SRR0 */ \ + mfspr r11,SPRN_##h##SRR0; /* save SRR0 */ \ LOAD_HANDLER(r12,label##_common) \ - mtspr SPRN_SRR0,r12; \ - mfspr r12,SPRN_SRR1; /* and SRR1 */ \ - mtspr SPRN_SRR1,r10; \ - rfid; \ + mtspr SPRN_##h##SRR0,r12; \ + mfspr r12,SPRN_##h##SRR1; /* and SRR1 */ \ + mtspr SPRN_##h##SRR1,r10; \ + h##rfid; \ b . /* prevent speculative execution */ +#define MASKABLE_EXCEPTION_PSERIES(n, label, h) \ + __MASKABLE_EXCEPTION_PSERIES(n, label, h) #ifdef CONFIG_PPC_ISERIES #define DISABLE_INTS \ diff --git a/arch/powerpc/include/asm/kvm_asm.h b/arch/powerpc/include/asm/kvm_asm.h index 5b75046..0951b17 100644 --- a/arch/powerpc/include/asm/kvm_asm.h +++ b/arch/powerpc/include/asm/kvm_asm.h @@ -59,6 +59,7 @@ #define BOOK3S_INTERRUPT_INST_SEGMENT 0x480 #define BOOK3S_INTERRUPT_EXTERNAL 0x500 #define BOOK3S_INTERRUPT_EXTERNAL_LEVEL 0x501 +#define BOOK3S_INTERRUPT_EXTERNAL_HV 0x502 #define BOOK3S_INTERRUPT_ALIGNMENT 0x600 #define BOOK3S_INTERRUPT_PROGRAM 0x700 #define BOOK3S_INTERRUPT_FP_UNAVAIL 0x800 diff --git a/arch/powerpc/include/asm/kvm_book3s_asm.h b/arch/powerpc/include/asm/kvm_book3s_asm.h index 36fdb3a..d5a8a38 100644 --- a/arch/powerpc/include/asm/kvm_book3s_asm.h +++ b/arch/powerpc/include/asm/kvm_book3s_asm.h @@ -34,6 +34,7 @@ (\intno == BOOK3S_INTERRUPT_DATA_SEGMENT) || \ (\intno == BOOK3S_INTERRUPT_INST_SEGMENT) || \ (\intno == BOOK3S_INTERRUPT_EXTERNAL) || \ + (\intno == BOOK3S_INTERRUPT_EXTERNAL_HV) || \ (\intno == BOOK3S_INTERRUPT_ALIGNMENT) || \ (\intno == BOOK3S_INTERRUPT_PROGRAM) || \ (\intno == BOOK3S_INTERRUPT_FP_UNAVAIL) || \ diff --git a/arch/powerpc/kernel/cpu_setup_power7.S b/arch/powerpc/kernel/cpu_setup_power7.S index f2b3178..e801ef1 100644 --- a/arch/powerpc/kernel/cpu_setup_power7.S +++ b/arch/powerpc/kernel/cpu_setup_power7.S @@ -52,13 +52,14 @@ __init_hvmode_206: __init_LPCR: /* Setup a sane LPCR: * - * LPES = 0b11 (SRR0/1 used for 0x500) + * LPES = 0b01 (HSRR0/1 used for 0x500) * PECE = 0b111 * * Other bits untouched for now */ mfspr r3,SPRN_LPCR ori r3,r3,(LPCR_LPES0|LPCR_LPES1) + xori r3,r3, LPCR_LPES0 ori r3,r3,(LPCR_PECE0|LPCR_PECE1|LPCR_PECE2) mtspr SPRN_LPCR,r3 isync diff --git a/arch/powerpc/kernel/exceptions-64s.S b/arch/powerpc/kernel/exceptions-64s.S index 6784bf7..17f1d66 100644 --- a/arch/powerpc/kernel/exceptions-64s.S +++ b/arch/powerpc/kernel/exceptions-64s.S @@ -44,7 +44,7 @@ _machine_check_pSeries: HMT_MEDIUM DO_KVM 0x200 mtspr SPRN_SPRG_SCRATCH0,r13 /* save r13 */ - EXCEPTION_PROLOG_PSERIES(PACA_EXMC, machine_check_common) + EXCEPTION_PROLOG_PSERIES(PACA_EXMC, machine_check_common, EXC_STD) . = 0x300 .globl data_access_pSeries @@ -71,9 +71,9 @@ BEGIN_FTR_SECTION std r10,PACA_EXGEN+EX_R10(r13) std r11,PACA_EXGEN+EX_R9(r13) std r12,PACA_EXGEN+EX_R13(r13) - EXCEPTION_PROLOG_PSERIES_1(data_access_common) + EXCEPTION_PROLOG_PSERIES_1(data_access_common, EXC_STD) FTR_SECTION_ELSE - EXCEPTION_PROLOG_PSERIES(PACA_EXGEN, data_access_common) + EXCEPTION_PROLOG_PSERIES(PACA_EXGEN, data_access_common, EXC_STD) ALT_FTR_SECTION_END_IFCLR(CPU_FTR_SLB) . = 0x380 @@ -147,11 +147,24 @@ instruction_access_slb_pSeries: bctr #endif - MASKABLE_EXCEPTION_PSERIES(0x500, hardware_interrupt) + . = 0x500; + .globl hardware_interrupt_pSeries +hardware_interrupt_pSeries: + BEGIN_FTR_SECTION + MASKABLE_EXCEPTION_PSERIES(0x500, hardware_interrupt, EXC_STD) + FTR_SECTION_ELSE + MASKABLE_EXCEPTION_PSERIES(0x502, hardware_interrupt, EXC_HV) + ALT_FTR_SECTION_END_IFCLR(CPU_FTR_HVMODE_206) + STD_EXCEPTION_PSERIES(0x600, alignment) STD_EXCEPTION_PSERIES(0x700, program_check) STD_EXCEPTION_PSERIES(0x800, fp_unavailable) - MASKABLE_EXCEPTION_PSERIES(0x900, decrementer) + + . = 0x900; + .globl decrementer_pSeries +decrementer_pSeries: + MASKABLE_EXCEPTION_PSERIES(0x900, decrementer, EXC_STD) + STD_EXCEPTION_PSERIES(0xa00, trap_0a) STD_EXCEPTION_PSERIES(0xb00, trap_0b) @@ -207,15 +220,15 @@ vsx_unavailable_pSeries_1: b vsx_unavailable_pSeries #ifdef CONFIG_CBE_RAS - HSTD_EXCEPTION_PSERIES(0x1200, cbe_system_error) + HSTD_EXCEPTION_PSERIES(0x1202, cbe_system_error) #endif /* CONFIG_CBE_RAS */ STD_EXCEPTION_PSERIES(0x1300, instruction_breakpoint) #ifdef CONFIG_CBE_RAS - HSTD_EXCEPTION_PSERIES(0x1600, cbe_maintenance) + HSTD_EXCEPTION_PSERIES(0x1602, cbe_maintenance) #endif /* CONFIG_CBE_RAS */ STD_EXCEPTION_PSERIES(0x1700, altivec_assist) #ifdef CONFIG_CBE_RAS - HSTD_EXCEPTION_PSERIES(0x1800, cbe_thermal) + HSTD_EXCEPTION_PSERIES(0x1802, cbe_thermal) #endif /* CONFIG_CBE_RAS */ . = 0x3000 @@ -244,13 +257,26 @@ masked_interrupt: rfid b . +masked_Hinterrupt: + stb r10,PACAHARDIRQEN(r13) + mtcrf 0x80,r9 + ld r9,PACA_EXGEN+EX_R9(r13) + mfspr r10,SPRN_HSRR1 + rldicl r10,r10,48,1 /* clear MSR_EE */ + rotldi r10,r10,16 + mtspr SPRN_HSRR1,r10 + ld r10,PACA_EXGEN+EX_R10(r13) + mfspr r13,SPRN_SPRG_HSCRATCH0 + hrfid + b . + .align 7 do_stab_bolted_pSeries: std r11,PACA_EXSLB+EX_R11(r13) std r12,PACA_EXSLB+EX_R12(r13) mfspr r10,SPRN_SPRG_SCRATCH0 std r10,PACA_EXSLB+EX_R13(r13) - EXCEPTION_PROLOG_PSERIES_1(.do_stab_bolted) + EXCEPTION_PROLOG_PSERIES_1(.do_stab_bolted, EXC_STD) #ifdef CONFIG_PPC_PSERIES /* @@ -261,14 +287,14 @@ do_stab_bolted_pSeries: system_reset_fwnmi: HMT_MEDIUM mtspr SPRN_SPRG_SCRATCH0,r13 /* save r13 */ - EXCEPTION_PROLOG_PSERIES(PACA_EXGEN, system_reset_common) + EXCEPTION_PROLOG_PSERIES(PACA_EXGEN, system_reset_common, EXC_STD) .globl machine_check_fwnmi .align 7 machine_check_fwnmi: HMT_MEDIUM mtspr SPRN_SPRG_SCRATCH0,r13 /* save r13 */ - EXCEPTION_PROLOG_PSERIES(PACA_EXMC, machine_check_common) + EXCEPTION_PROLOG_PSERIES(PACA_EXMC, machine_check_common, EXC_STD) #endif /* CONFIG_PPC_PSERIES */ diff --git a/arch/powerpc/kvm/book3s_rmhandlers.S b/arch/powerpc/kvm/book3s_rmhandlers.S index b0ff5ff..046e1f3 100644 --- a/arch/powerpc/kvm/book3s_rmhandlers.S +++ b/arch/powerpc/kvm/book3s_rmhandlers.S @@ -112,6 +112,7 @@ INTERRUPT_TRAMPOLINE BOOK3S_INTERRUPT_MACHINE_CHECK INTERRUPT_TRAMPOLINE BOOK3S_INTERRUPT_DATA_STORAGE INTERRUPT_TRAMPOLINE BOOK3S_INTERRUPT_INST_STORAGE INTERRUPT_TRAMPOLINE BOOK3S_INTERRUPT_EXTERNAL +INTERRUPT_TRAMPOLINE BOOK3S_INTERRUPT_EXTERNAL_HV INTERRUPT_TRAMPOLINE BOOK3S_INTERRUPT_ALIGNMENT INTERRUPT_TRAMPOLINE BOOK3S_INTERRUPT_PROGRAM INTERRUPT_TRAMPOLINE BOOK3S_INTERRUPT_FP_UNAVAIL diff --git a/arch/powerpc/kvm/book3s_segment.S b/arch/powerpc/kvm/book3s_segment.S index 7c52ed0..d842795 100644 --- a/arch/powerpc/kvm/book3s_segment.S +++ b/arch/powerpc/kvm/book3s_segment.S @@ -155,9 +155,15 @@ kvmppc_handler_trampoline_exit: PPC_LL r2, (SHADOW_VCPU_OFF + SVCPU_HOST_R2)(r13) /* Save guest PC and MSR */ - mfsrr0 r3 + andi. r0,r12,0x2 + beq 1f + mfspr r3,SPRN_HSRR0 + mfspr r4,SPRN_HSRR1 + andi. r12,r12,0x3ffd + b 2f +1: mfsrr0 r3 mfsrr1 r4 - +2: PPC_STL r3, (SHADOW_VCPU_OFF + SVCPU_PC)(r13) PPC_STL r4, (SHADOW_VCPU_OFF + SVCPU_SHADOW_SRR1)(r13) diff --git a/arch/powerpc/platforms/iseries/exception.S b/arch/powerpc/platforms/iseries/exception.S index 32a56c6..f7a4872 100644 --- a/arch/powerpc/platforms/iseries/exception.S +++ b/arch/powerpc/platforms/iseries/exception.S @@ -155,7 +155,7 @@ BEGIN_FTR_SECTION std r12,PACA_EXGEN+EX_R13(r13) EXCEPTION_PROLOG_ISERIES_1 FTR_SECTION_ELSE - EXCEPTION_PROLOG_1(PACA_EXGEN) + EXCEPTION_PROLOG_1(PACA_EXGEN, EXC_STD) EXCEPTION_PROLOG_ISERIES_1 ALT_FTR_SECTION_END_IFCLR(CPU_FTR_SLB) b data_access_common diff --git a/arch/powerpc/platforms/iseries/exception.h b/arch/powerpc/platforms/iseries/exception.h index bae3fba..57127d8 100644 --- a/arch/powerpc/platforms/iseries/exception.h +++ b/arch/powerpc/platforms/iseries/exception.h @@ -39,7 +39,7 @@ label##_iSeries: \ HMT_MEDIUM; \ mtspr SPRN_SPRG_SCRATCH0,r13; /* save r13 */ \ - EXCEPTION_PROLOG_1(area); \ + EXCEPTION_PROLOG_1(area, EXC_STD); \ EXCEPTION_PROLOG_ISERIES_1; \ b label##_common @@ -48,7 +48,7 @@ label##_iSeries: \ label##_iSeries: \ HMT_MEDIUM; \ mtspr SPRN_SPRG_SCRATCH0,r13; /* save r13 */ \ - EXCEPTION_PROLOG_1(PACA_EXGEN); \ + EXCEPTION_PROLOG_1(PACA_EXGEN, EXC_STD); \ lbz r10,PACASOFTIRQEN(r13); \ cmpwi 0,r10,0; \ beq- label##_iSeries_masked; \ -- cgit v0.10.2 From b3e6b5dfcf0974069a8ddcce7dd071120d20d79c Mon Sep 17 00:00:00 2001 From: Benjamin Herrenschmidt Date: Tue, 5 Apr 2011 14:27:11 +1000 Subject: powerpc: More work to support HV exceptions Rework exception macros a bit to split offset from vector and add some basic support for HDEC, HDSI, HISI and a few more. Signed-off-by: Benjamin Herrenschmidt diff --git a/arch/powerpc/include/asm/exception-64s.h b/arch/powerpc/include/asm/exception-64s.h index 1d98e05..fb5b0af 100644 --- a/arch/powerpc/include/asm/exception-64s.h +++ b/arch/powerpc/include/asm/exception-64s.h @@ -150,28 +150,27 @@ /* * Exception vectors. */ -#define STD_EXCEPTION_PSERIES(n, label) \ - . = n; \ +#define STD_EXCEPTION_PSERIES(loc, vec, label) \ + . = loc; \ .globl label##_pSeries; \ label##_pSeries: \ HMT_MEDIUM; \ - DO_KVM n; \ + DO_KVM vec; \ mtspr SPRN_SPRG_SCRATCH0,r13; /* save r13 */ \ EXCEPTION_PROLOG_PSERIES(PACA_EXGEN, label##_common, EXC_STD) -#define HSTD_EXCEPTION_PSERIES(n, label) \ - . = n; \ - .globl label##_pSeries; \ -label##_pSeries: \ +#define STD_EXCEPTION_HV(loc, vec, label) \ + . = loc; \ + .globl label##_hv; \ +label##_hv: \ HMT_MEDIUM; \ - DO_KVM n; \ + DO_KVM vec; \ mtspr SPRN_SPRG_HSCRATCH0,r13;/* save r13 */ \ EXCEPTION_PROLOG_PSERIES(PACA_EXGEN, label##_common, EXC_HV) - -#define __MASKABLE_EXCEPTION_PSERIES(n, label, h) \ +#define __MASKABLE_EXCEPTION_PSERIES(vec, label, h) \ HMT_MEDIUM; \ - DO_KVM n; \ + DO_KVM vec; \ mtspr SPRN_SPRG_##h##SCRATCH0,r13; /* save r13 */ \ GET_PACA(r13); \ std r9,PACA_EXGEN+EX_R9(r13); /* save r9, r10 */ \ @@ -193,8 +192,20 @@ label##_pSeries: \ mtspr SPRN_##h##SRR1,r10; \ h##rfid; \ b . /* prevent speculative execution */ -#define MASKABLE_EXCEPTION_PSERIES(n, label, h) \ - __MASKABLE_EXCEPTION_PSERIES(n, label, h) +#define _MASKABLE_EXCEPTION_PSERIES(vec, label, h) \ + __MASKABLE_EXCEPTION_PSERIES(vec, label, h) + +#define MASKABLE_EXCEPTION_PSERIES(loc, vec, label) \ + . = loc; \ + .globl label##_pSeries; \ +label##_pSeries: \ + _MASKABLE_EXCEPTION_PSERIES(vec, label, EXC_STD) + +#define MASKABLE_EXCEPTION_HV(loc, vec, label) \ + . = loc; \ + .globl label##_hv; \ +label##_hv: \ + _MASKABLE_EXCEPTION_PSERIES(vec, label, EXC_HV) #ifdef CONFIG_PPC_ISERIES #define DISABLE_INTS \ diff --git a/arch/powerpc/include/asm/feature-fixups.h b/arch/powerpc/include/asm/feature-fixups.h index 921a847..bdc0d68 100644 --- a/arch/powerpc/include/asm/feature-fixups.h +++ b/arch/powerpc/include/asm/feature-fixups.h @@ -49,7 +49,7 @@ label##5: \ FTR_ENTRY_OFFSET label##2b-label##5b; \ FTR_ENTRY_OFFSET label##3b-label##5b; \ FTR_ENTRY_OFFSET label##4b-label##5b; \ - .ifgt (label##4b-label##3b)-(label##2b-label##1b); \ + .ifgt (label##4b- label##3b)-(label##2b- label##1b); \ .error "Feature section else case larger than body"; \ .endif; \ .popsection; diff --git a/arch/powerpc/kernel/exceptions-64s.S b/arch/powerpc/kernel/exceptions-64s.S index 17f1d66..805e206 100644 --- a/arch/powerpc/kernel/exceptions-64s.S +++ b/arch/powerpc/kernel/exceptions-64s.S @@ -37,7 +37,7 @@ .globl __start_interrupts __start_interrupts: - STD_EXCEPTION_PSERIES(0x100, system_reset) + STD_EXCEPTION_PSERIES(0x100, 0x100, system_reset) . = 0x200 _machine_check_pSeries: @@ -113,7 +113,7 @@ data_access_slb_pSeries: bctr #endif - STD_EXCEPTION_PSERIES(0x400, instruction_access) + STD_EXCEPTION_PSERIES(0x400, 0x400, instruction_access) . = 0x480 .globl instruction_access_slb_pSeries @@ -147,26 +147,29 @@ instruction_access_slb_pSeries: bctr #endif + /* We open code these as we can't have a ". = x" (even with + * x = "." within a feature section + */ . = 0x500; - .globl hardware_interrupt_pSeries + .globl hardware_interrupt_pSeries; + .globl hardware_interrupt_hv; hardware_interrupt_pSeries: +hardware_interrupt_hv: BEGIN_FTR_SECTION - MASKABLE_EXCEPTION_PSERIES(0x500, hardware_interrupt, EXC_STD) + _MASKABLE_EXCEPTION_PSERIES(0x500, hardware_interrupt, EXC_STD) FTR_SECTION_ELSE - MASKABLE_EXCEPTION_PSERIES(0x502, hardware_interrupt, EXC_HV) + _MASKABLE_EXCEPTION_PSERIES(0x502, hardware_interrupt, EXC_HV) ALT_FTR_SECTION_END_IFCLR(CPU_FTR_HVMODE_206) - STD_EXCEPTION_PSERIES(0x600, alignment) - STD_EXCEPTION_PSERIES(0x700, program_check) - STD_EXCEPTION_PSERIES(0x800, fp_unavailable) + STD_EXCEPTION_PSERIES(0x600, 0x600, alignment) + STD_EXCEPTION_PSERIES(0x700, 0x700, program_check) + STD_EXCEPTION_PSERIES(0x800, 0x800, fp_unavailable) - . = 0x900; - .globl decrementer_pSeries -decrementer_pSeries: - MASKABLE_EXCEPTION_PSERIES(0x900, decrementer, EXC_STD) + MASKABLE_EXCEPTION_PSERIES(0x900, 0x900, decrementer) + MASKABLE_EXCEPTION_HV(0x980, 0x980, decrementer) - STD_EXCEPTION_PSERIES(0xa00, trap_0a) - STD_EXCEPTION_PSERIES(0xb00, trap_0b) + STD_EXCEPTION_PSERIES(0xa00, 0xa00, trap_0a) + STD_EXCEPTION_PSERIES(0xb00, 0xb00, trap_0b) . = 0xc00 .globl system_call_pSeries @@ -196,8 +199,21 @@ END_FTR_SECTION_IFSET(CPU_FTR_REAL_LE) rfid /* return to userspace */ b . - STD_EXCEPTION_PSERIES(0xd00, single_step) - STD_EXCEPTION_PSERIES(0xe00, trap_0e) + STD_EXCEPTION_PSERIES(0xd00, 0xd00, single_step) + + /* At 0xe??? we have a bunch of hypervisor exceptions, we branch + * out of line to handle them + */ + . = 0xe00 + b h_data_storage_hv + . = 0xe20 + b h_instr_storage_hv + . = 0xe40 + b emulation_assist_hv + . = 0xe50 + b hmi_exception_hv + . = 0xe60 + b hmi_exception_hv /* We need to deal with the Altivec unavailable exception * here which is at 0xf20, thus in the middle of the @@ -206,39 +222,42 @@ END_FTR_SECTION_IFSET(CPU_FTR_REAL_LE) */ performance_monitor_pSeries_1: . = 0xf00 - DO_KVM 0xf00 b performance_monitor_pSeries altivec_unavailable_pSeries_1: . = 0xf20 - DO_KVM 0xf20 b altivec_unavailable_pSeries vsx_unavailable_pSeries_1: . = 0xf40 - DO_KVM 0xf40 b vsx_unavailable_pSeries #ifdef CONFIG_CBE_RAS - HSTD_EXCEPTION_PSERIES(0x1202, cbe_system_error) + STD_EXCEPTION_HV(0x1200, 0x1202, cbe_system_error) #endif /* CONFIG_CBE_RAS */ - STD_EXCEPTION_PSERIES(0x1300, instruction_breakpoint) + STD_EXCEPTION_PSERIES(0x1300, 0x1300, instruction_breakpoint) #ifdef CONFIG_CBE_RAS - HSTD_EXCEPTION_PSERIES(0x1602, cbe_maintenance) + STD_EXCEPTION_HV(0x1600, 0x1602, cbe_maintenance) #endif /* CONFIG_CBE_RAS */ - STD_EXCEPTION_PSERIES(0x1700, altivec_assist) + STD_EXCEPTION_PSERIES(0x1700, 0x1700, altivec_assist) #ifdef CONFIG_CBE_RAS - HSTD_EXCEPTION_PSERIES(0x1802, cbe_thermal) + STD_EXCEPTION_HV(0x1800, 0x1802, cbe_thermal) #endif /* CONFIG_CBE_RAS */ . = 0x3000 -/*** pSeries interrupt support ***/ +/*** Out of line interrupts support ***/ + + /* moved from 0xe00 */ + STD_EXCEPTION_HV(., 0xe00, h_data_storage) + STD_EXCEPTION_HV(., 0xe20, h_instr_storage) + STD_EXCEPTION_HV(., 0xe40, emulation_assist) + STD_EXCEPTION_HV(., 0xe60, hmi_exception) /* need to flush cache ? */ /* moved from 0xf00 */ - STD_EXCEPTION_PSERIES(., performance_monitor) - STD_EXCEPTION_PSERIES(., altivec_unavailable) - STD_EXCEPTION_PSERIES(., vsx_unavailable) + STD_EXCEPTION_PSERIES(., 0xf00, performance_monitor) + STD_EXCEPTION_PSERIES(., 0xf20, altivec_unavailable) + STD_EXCEPTION_PSERIES(., 0xf40, vsx_unavailable) /* * An interrupt came in while soft-disabled; clear EE in SRR1, @@ -368,6 +387,8 @@ machine_check_common: STD_EXCEPTION_COMMON(0xb00, trap_0b, .unknown_exception) STD_EXCEPTION_COMMON(0xd00, single_step, .single_step_exception) STD_EXCEPTION_COMMON(0xe00, trap_0e, .unknown_exception) + STD_EXCEPTION_COMMON(0xe40, emulation_assist, .program_check_exception) + STD_EXCEPTION_COMMON(0xe60, hmi_exception, .unknown_exception) STD_EXCEPTION_COMMON_IDLE(0xf00, performance_monitor, .performance_monitor_exception) STD_EXCEPTION_COMMON(0x1300, instruction_breakpoint, .instruction_breakpoint_exception) #ifdef CONFIG_ALTIVEC @@ -445,6 +466,19 @@ data_access_common: li r5,0x300 b .do_hash_page /* Try to handle as hpte fault */ + .align 7 + .globl h_data_storage_common +h_data_storage_common: + mfspr r10,SPRN_HDAR + std r10,PACA_EXGEN+EX_DAR(r13) + mfspr r10,SPRN_HDSISR + stw r10,PACA_EXGEN+EX_DSISR(r13) + EXCEPTION_PROLOG_COMMON(0xe00, PACA_EXGEN) + bl .save_nvgprs + addi r3,r1,STACK_FRAME_OVERHEAD + bl .unknown_exception + b .ret_from_except + .align 7 .globl instruction_access_common instruction_access_common: @@ -454,6 +488,8 @@ instruction_access_common: li r5,0x400 b .do_hash_page /* Try to handle as hpte fault */ + STD_EXCEPTION_COMMON(0xe20, h_instr_storage, .unknown_exception) + /* * Here is the common SLB miss user that is used when going to virtual * mode for SLB misses, that is currently not used -- cgit v0.10.2 From 673b189a2e3353061fa8c49515d1014dab6ad9b9 Mon Sep 17 00:00:00 2001 From: Paul Mackerras Date: Tue, 5 Apr 2011 13:59:58 +1000 Subject: powerpc: Always use SPRN_SPRG_HSCRATCH0 when running in HV mode This uses feature sections to arrange that we always use HSPRG1 as the scratch register in the interrupt entry code rather than SPRG2 when we're running in hypervisor mode on POWER7. This will ensure that we don't trash the guest's SPRG2 when we are running KVM guests. To simplify the code, we define GET_SCRATCH0() and SET_SCRATCH0() macros like the GET_PACA/SET_PACA macros. Signed-off-by: Paul Mackerras Signed-off-by: Benjamin Herrenschmidt diff --git a/arch/powerpc/include/asm/exception-64s.h b/arch/powerpc/include/asm/exception-64s.h index fb5b0af..d6b4849 100644 --- a/arch/powerpc/include/asm/exception-64s.h +++ b/arch/powerpc/include/asm/exception-64s.h @@ -60,16 +60,15 @@ #define EXC_HV H #define EXC_STD -#define __EXCEPTION_PROLOG_1(area, h) \ +#define EXCEPTION_PROLOG_1(area) \ GET_PACA(r13); \ std r9,area+EX_R9(r13); /* save r9 - r12 */ \ std r10,area+EX_R10(r13); \ std r11,area+EX_R11(r13); \ std r12,area+EX_R12(r13); \ - mfspr r9,SPRN_SPRG_##h##SCRATCH0; \ + GET_SCRATCH0(r9); \ std r9,area+EX_R13(r13); \ mfcr r9 -#define EXCEPTION_PROLOG_1(area, h) __EXCEPTION_PROLOG_1(area, h) #define __EXCEPTION_PROLOG_PSERIES_1(label, h) \ ld r12,PACAKBASE(r13); /* get high part of &label */ \ @@ -85,7 +84,7 @@ __EXCEPTION_PROLOG_PSERIES_1(label, h) #define EXCEPTION_PROLOG_PSERIES(area, label, h) \ - EXCEPTION_PROLOG_1(area, h); \ + EXCEPTION_PROLOG_1(area); \ EXCEPTION_PROLOG_PSERIES_1(label, h); /* @@ -156,7 +155,7 @@ label##_pSeries: \ HMT_MEDIUM; \ DO_KVM vec; \ - mtspr SPRN_SPRG_SCRATCH0,r13; /* save r13 */ \ + SET_SCRATCH0(r13); /* save r13 */ \ EXCEPTION_PROLOG_PSERIES(PACA_EXGEN, label##_common, EXC_STD) #define STD_EXCEPTION_HV(loc, vec, label) \ @@ -165,13 +164,13 @@ label##_pSeries: \ label##_hv: \ HMT_MEDIUM; \ DO_KVM vec; \ - mtspr SPRN_SPRG_HSCRATCH0,r13;/* save r13 */ \ + SET_SCRATCH0(r13); /* save r13 */ \ EXCEPTION_PROLOG_PSERIES(PACA_EXGEN, label##_common, EXC_HV) #define __MASKABLE_EXCEPTION_PSERIES(vec, label, h) \ HMT_MEDIUM; \ DO_KVM vec; \ - mtspr SPRN_SPRG_##h##SCRATCH0,r13; /* save r13 */ \ + SET_SCRATCH0(r13); /* save r13 */ \ GET_PACA(r13); \ std r9,PACA_EXGEN+EX_R9(r13); /* save r9, r10 */ \ std r10,PACA_EXGEN+EX_R10(r13); \ @@ -179,7 +178,7 @@ label##_hv: \ mfcr r9; \ cmpwi r10,0; \ beq masked_##h##interrupt; \ - mfspr r10,SPRN_SPRG_##h##SCRATCH0; \ + GET_SCRATCH0(r10); \ std r10,PACA_EXGEN+EX_R13(r13); \ std r11,PACA_EXGEN+EX_R11(r13); \ std r12,PACA_EXGEN+EX_R12(r13); \ diff --git a/arch/powerpc/include/asm/reg.h b/arch/powerpc/include/asm/reg.h index 13429a0..76d7d5f 100644 --- a/arch/powerpc/include/asm/reg.h +++ b/arch/powerpc/include/asm/reg.h @@ -802,6 +802,20 @@ FTR_SECTION_ELSE_NESTED(66); \ mtspr SPRN_SPRG_HPACA,rX; \ ALT_FTR_SECTION_END_NESTED_IFCLR(CPU_FTR_HVMODE_206, 66) + +#define GET_SCRATCH0(rX) \ + BEGIN_FTR_SECTION_NESTED(66); \ + mfspr rX,SPRN_SPRG_SCRATCH0; \ + FTR_SECTION_ELSE_NESTED(66); \ + mfspr rX,SPRN_SPRG_HSCRATCH0; \ + ALT_FTR_SECTION_END_NESTED_IFCLR(CPU_FTR_HVMODE_206, 66) + +#define SET_SCRATCH0(rX) \ + BEGIN_FTR_SECTION_NESTED(66); \ + mtspr SPRN_SPRG_SCRATCH0,rX; \ + FTR_SECTION_ELSE_NESTED(66); \ + mtspr SPRN_SPRG_HSCRATCH0,rX; \ + ALT_FTR_SECTION_END_NESTED_IFCLR(CPU_FTR_HVMODE_206, 66) #endif #ifdef CONFIG_PPC_BOOK3E_64 diff --git a/arch/powerpc/kernel/exceptions-64s.S b/arch/powerpc/kernel/exceptions-64s.S index 805e206..e513c1d 100644 --- a/arch/powerpc/kernel/exceptions-64s.S +++ b/arch/powerpc/kernel/exceptions-64s.S @@ -43,7 +43,7 @@ __start_interrupts: _machine_check_pSeries: HMT_MEDIUM DO_KVM 0x200 - mtspr SPRN_SPRG_SCRATCH0,r13 /* save r13 */ + SET_SCRATCH0(r13) EXCEPTION_PROLOG_PSERIES(PACA_EXMC, machine_check_common, EXC_STD) . = 0x300 @@ -51,7 +51,7 @@ _machine_check_pSeries: data_access_pSeries: HMT_MEDIUM DO_KVM 0x300 - mtspr SPRN_SPRG_SCRATCH0,r13 + SET_SCRATCH0(r13) BEGIN_FTR_SECTION GET_PACA(r13) std r9,PACA_EXSLB+EX_R9(r13) @@ -67,7 +67,7 @@ BEGIN_FTR_SECTION std r11,PACA_EXGEN+EX_R11(r13) ld r11,PACA_EXSLB+EX_R9(r13) std r12,PACA_EXGEN+EX_R12(r13) - mfspr r12,SPRN_SPRG_SCRATCH0 + GET_SCRATCH0(r12) std r10,PACA_EXGEN+EX_R10(r13) std r11,PACA_EXGEN+EX_R9(r13) std r12,PACA_EXGEN+EX_R13(r13) @@ -81,7 +81,7 @@ ALT_FTR_SECTION_END_IFCLR(CPU_FTR_SLB) data_access_slb_pSeries: HMT_MEDIUM DO_KVM 0x380 - mtspr SPRN_SPRG_SCRATCH0,r13 + SET_SCRATCH0(r13) GET_PACA(r13) std r3,PACA_EXSLB+EX_R3(r13) mfspr r3,SPRN_DAR @@ -95,7 +95,7 @@ data_access_slb_pSeries: std r10,PACA_EXSLB+EX_R10(r13) std r11,PACA_EXSLB+EX_R11(r13) std r12,PACA_EXSLB+EX_R12(r13) - mfspr r10,SPRN_SPRG_SCRATCH0 + GET_SCRATCH0(r10) std r10,PACA_EXSLB+EX_R13(r13) mfspr r12,SPRN_SRR1 /* and SRR1 */ #ifndef CONFIG_RELOCATABLE @@ -120,7 +120,7 @@ data_access_slb_pSeries: instruction_access_slb_pSeries: HMT_MEDIUM DO_KVM 0x480 - mtspr SPRN_SPRG_SCRATCH0,r13 + SET_SCRATCH0(r13) GET_PACA(r13) std r3,PACA_EXSLB+EX_R3(r13) mfspr r3,SPRN_SRR0 /* SRR0 is faulting address */ @@ -134,7 +134,7 @@ instruction_access_slb_pSeries: std r10,PACA_EXSLB+EX_R10(r13) std r11,PACA_EXSLB+EX_R11(r13) std r12,PACA_EXSLB+EX_R12(r13) - mfspr r10,SPRN_SPRG_SCRATCH0 + GET_SCRATCH0(r10) std r10,PACA_EXSLB+EX_R13(r13) mfspr r12,SPRN_SRR1 /* and SRR1 */ #ifndef CONFIG_RELOCATABLE @@ -272,7 +272,7 @@ masked_interrupt: rotldi r10,r10,16 mtspr SPRN_SRR1,r10 ld r10,PACA_EXGEN+EX_R10(r13) - mfspr r13,SPRN_SPRG_SCRATCH0 + GET_SCRATCH0(r13) rfid b . @@ -285,7 +285,7 @@ masked_Hinterrupt: rotldi r10,r10,16 mtspr SPRN_HSRR1,r10 ld r10,PACA_EXGEN+EX_R10(r13) - mfspr r13,SPRN_SPRG_HSCRATCH0 + GET_SCRATCH0(r13) hrfid b . @@ -293,7 +293,7 @@ masked_Hinterrupt: do_stab_bolted_pSeries: std r11,PACA_EXSLB+EX_R11(r13) std r12,PACA_EXSLB+EX_R12(r13) - mfspr r10,SPRN_SPRG_SCRATCH0 + GET_SCRATCH0(r10) std r10,PACA_EXSLB+EX_R13(r13) EXCEPTION_PROLOG_PSERIES_1(.do_stab_bolted, EXC_STD) @@ -305,14 +305,14 @@ do_stab_bolted_pSeries: .align 7 system_reset_fwnmi: HMT_MEDIUM - mtspr SPRN_SPRG_SCRATCH0,r13 /* save r13 */ + SET_SCRATCH0(r13) /* save r13 */ EXCEPTION_PROLOG_PSERIES(PACA_EXGEN, system_reset_common, EXC_STD) .globl machine_check_fwnmi .align 7 machine_check_fwnmi: HMT_MEDIUM - mtspr SPRN_SPRG_SCRATCH0,r13 /* save r13 */ + SET_SCRATCH0(r13) /* save r13 */ EXCEPTION_PROLOG_PSERIES(PACA_EXMC, machine_check_common, EXC_STD) #endif /* CONFIG_PPC_PSERIES */ @@ -327,7 +327,7 @@ slb_miss_user_pseries: std r10,PACA_EXGEN+EX_R10(r13) std r11,PACA_EXGEN+EX_R11(r13) std r12,PACA_EXGEN+EX_R12(r13) - mfspr r10,SPRG_SCRATCH0 + GET_SCRATCH0(r10) ld r11,PACA_EXSLB+EX_R9(r13) ld r12,PACA_EXSLB+EX_R3(r13) std r10,PACA_EXGEN+EX_R13(r13) diff --git a/arch/powerpc/kvm/book3s_rmhandlers.S b/arch/powerpc/kvm/book3s_rmhandlers.S index 046e1f3..ae99af6 100644 --- a/arch/powerpc/kvm/book3s_rmhandlers.S +++ b/arch/powerpc/kvm/book3s_rmhandlers.S @@ -70,7 +70,7 @@ .global kvmppc_trampoline_\intno kvmppc_trampoline_\intno: - mtspr SPRN_SPRG_SCRATCH0, r13 /* Save r13 */ + SET_SCRATCH0(r13) /* Save r13 */ /* * First thing to do is to find out if we're coming @@ -89,7 +89,7 @@ kvmppc_trampoline_\intno: lwz r12, (SHADOW_VCPU_OFF + SVCPU_SCRATCH1)(r13) mtcr r12 PPC_LL r12, (SHADOW_VCPU_OFF + SVCPU_SCRATCH0)(r13) - mfspr r13, SPRN_SPRG_SCRATCH0 /* r13 = original r13 */ + GET_SCRATCH0(r13) /* r13 = original r13 */ b kvmppc_resume_\intno /* Get back original handler */ /* Now we know we're handling a KVM guest */ @@ -157,7 +157,7 @@ kvmppc_handler_skip_ins: lwz r12, (SHADOW_VCPU_OFF + SVCPU_SCRATCH1)(r13) mtcr r12 PPC_LL r12, (SHADOW_VCPU_OFF + SVCPU_SCRATCH0)(r13) - mfspr r13, SPRN_SPRG_SCRATCH0 + GET_SCRATCH0(r13) /* And get back into the code */ RFI diff --git a/arch/powerpc/kvm/book3s_segment.S b/arch/powerpc/kvm/book3s_segment.S index d842795..4512642 100644 --- a/arch/powerpc/kvm/book3s_segment.S +++ b/arch/powerpc/kvm/book3s_segment.S @@ -168,7 +168,7 @@ kvmppc_handler_trampoline_exit: PPC_STL r4, (SHADOW_VCPU_OFF + SVCPU_SHADOW_SRR1)(r13) /* Get scratch'ed off registers */ - mfspr r9, SPRN_SPRG_SCRATCH0 + GET_SCRATCH0(r9) PPC_LL r8, (SHADOW_VCPU_OFF + SVCPU_SCRATCH0)(r13) lwz r7, (SHADOW_VCPU_OFF + SVCPU_SCRATCH1)(r13) diff --git a/arch/powerpc/platforms/iseries/exception.S b/arch/powerpc/platforms/iseries/exception.S index f7a4872..32a56c6 100644 --- a/arch/powerpc/platforms/iseries/exception.S +++ b/arch/powerpc/platforms/iseries/exception.S @@ -155,7 +155,7 @@ BEGIN_FTR_SECTION std r12,PACA_EXGEN+EX_R13(r13) EXCEPTION_PROLOG_ISERIES_1 FTR_SECTION_ELSE - EXCEPTION_PROLOG_1(PACA_EXGEN, EXC_STD) + EXCEPTION_PROLOG_1(PACA_EXGEN) EXCEPTION_PROLOG_ISERIES_1 ALT_FTR_SECTION_END_IFCLR(CPU_FTR_SLB) b data_access_common diff --git a/arch/powerpc/platforms/iseries/exception.h b/arch/powerpc/platforms/iseries/exception.h index 57127d8..bae3fba 100644 --- a/arch/powerpc/platforms/iseries/exception.h +++ b/arch/powerpc/platforms/iseries/exception.h @@ -39,7 +39,7 @@ label##_iSeries: \ HMT_MEDIUM; \ mtspr SPRN_SPRG_SCRATCH0,r13; /* save r13 */ \ - EXCEPTION_PROLOG_1(area, EXC_STD); \ + EXCEPTION_PROLOG_1(area); \ EXCEPTION_PROLOG_ISERIES_1; \ b label##_common @@ -48,7 +48,7 @@ label##_iSeries: \ label##_iSeries: \ HMT_MEDIUM; \ mtspr SPRN_SPRG_SCRATCH0,r13; /* save r13 */ \ - EXCEPTION_PROLOG_1(PACA_EXGEN, EXC_STD); \ + EXCEPTION_PROLOG_1(PACA_EXGEN); \ lbz r10,PACASOFTIRQEN(r13); \ cmpwi 0,r10,0; \ beq- label##_iSeries_masked; \ -- cgit v0.10.2 From 895796a8ab548fe03b6fea410dcb1b86e1913708 Mon Sep 17 00:00:00 2001 From: Benjamin Herrenschmidt Date: Mon, 24 Jan 2011 13:25:55 +1100 Subject: powerpc: Initialize LPCR:DPFD on power7 to a sane default This sets the default data stream prefetch size for operating systems that don't set their own value in DSCR. We use 4 which is "medium". Signed-off-by: Benjamin Herrenschmidt diff --git a/arch/powerpc/kernel/cpu_setup_power7.S b/arch/powerpc/kernel/cpu_setup_power7.S index e801ef1..2390f6f 100644 --- a/arch/powerpc/kernel/cpu_setup_power7.S +++ b/arch/powerpc/kernel/cpu_setup_power7.S @@ -54,6 +54,7 @@ __init_LPCR: * * LPES = 0b01 (HSRR0/1 used for 0x500) * PECE = 0b111 + * DPFD = 4 * * Other bits untouched for now */ @@ -61,6 +62,12 @@ __init_LPCR: ori r3,r3,(LPCR_LPES0|LPCR_LPES1) xori r3,r3, LPCR_LPES0 ori r3,r3,(LPCR_PECE0|LPCR_PECE1|LPCR_PECE2) + li r5,7 + sldi r5,r5,LPCR_DPFD_SH + andc r3,r3,r5 + li r5,4 + sldi r5,r5,LPCR_DPFD_SH + or r3,r3,r5 mtspr SPRN_LPCR,r3 isync blr -- cgit v0.10.2 From b144871cb5f2c268e94258ae8f1ec810db2e1120 Mon Sep 17 00:00:00 2001 From: Benjamin Herrenschmidt Date: Tue, 1 Mar 2011 15:46:09 +1100 Subject: powerpc: Initialize TLB and LPID register on HV mode Power7 In case entry from the bootloader isn't "clean" Signed-off-by: Benjamin Herrenschmidt diff --git a/arch/powerpc/kernel/cpu_setup_power7.S b/arch/powerpc/kernel/cpu_setup_power7.S index 2390f6f..4f9a93f 100644 --- a/arch/powerpc/kernel/cpu_setup_power7.S +++ b/arch/powerpc/kernel/cpu_setup_power7.S @@ -25,7 +25,10 @@ _GLOBAL(__setup_cpu_power7) bl __init_hvmode_206 mtlr r11 beqlr + li r0,0 + mtspr SPRN_LPID,r0 bl __init_LPCR + bl __init_TLB mtlr r11 blr @@ -34,7 +37,10 @@ _GLOBAL(__restore_cpu_power7) mfmsr r3 rldicl. r0,r3,4,63 beqlr + li r0,0 + mtspr SPRN_LPID,r0 bl __init_LPCR + bl __init_TLB mtlr r11 blr @@ -71,3 +77,15 @@ __init_LPCR: mtspr SPRN_LPCR,r3 isync blr + +__init_TLB: + /* Clear the TLB */ + li r6,128 + mtctr r6 + li r7,0xc00 /* IS field = 0b11 */ + ptesync +2: tlbiel r7 + addi r7,r7,0x1000 + bdnz 2b + ptesync +1: blr -- cgit v0.10.2 From ad0693ee722b93b63a89c845e99513f242e43aa6 Mon Sep 17 00:00:00 2001 From: Benjamin Herrenschmidt Date: Tue, 1 Feb 2011 12:13:09 +1100 Subject: powerpc: Call CPU ->restore callback earlier on secondary CPUs We do it before we loop on the PACA start flag. This way, we get a chance to set critical SPRs on all CPUs before Linux tries to start them up, which avoids problems when changing some bits such as LPCR bits that need to be identical on all threads of a core or similar things like that. Ideally, some of that should also be done before the MMU is enabled, but that's a separate issue which would require moving some of the SMP startup code earlier, let's not get there for now, it works with that change alone. Signed-off-by: Benjamin Herrenschmidt diff --git a/arch/powerpc/kernel/head_64.S b/arch/powerpc/kernel/head_64.S index 39a4040..9594427 100644 --- a/arch/powerpc/kernel/head_64.S +++ b/arch/powerpc/kernel/head_64.S @@ -236,17 +236,6 @@ generic_secondary_common_init: /* From now on, r24 is expected to be logical cpuid */ mr r24,r5 -3: HMT_LOW - lbz r23,PACAPROCSTART(r13) /* Test if this processor should */ - /* start. */ - -#ifndef CONFIG_SMP - b 3b /* Never go on non-SMP */ -#else - cmpwi 0,r23,0 - beq 3b /* Loop until told to go */ - - sync /* order paca.run and cur_cpu_spec */ /* See if we need to call a cpu state restore handler */ LOAD_REG_ADDR(r23, cur_cpu_spec) @@ -258,6 +247,17 @@ generic_secondary_common_init: mtctr r23 bctrl +3: HMT_LOW + lbz r23,PACAPROCSTART(r13) /* Test if this processor should */ + /* start. */ +#ifndef CONFIG_SMP + b 3b /* Never go on non-SMP */ +#else + cmpwi 0,r23,0 + beq 3b /* Loop until told to go */ + + sync /* order paca.run and cur_cpu_spec */ + 4: /* Create a temp kernel stack for use before relocation is on. */ ld r1,PACAEMERGSP(r13) subi r1,r1,STACK_FRAME_OVERHEAD -- cgit v0.10.2 From 9d07bc841c9779b4d7902e417f4e509996ce805d Mon Sep 17 00:00:00 2001 From: Benjamin Herrenschmidt Date: Wed, 16 Mar 2011 14:54:35 +1100 Subject: powerpc: Properly handshake CPUs going out of boot spin loop We need to wait a bit for them to have done their CPU setup or we might end up with translation and EE on with different LPCR values between threads Signed-off-by: Benjamin Herrenschmidt diff --git a/arch/powerpc/include/asm/smp.h b/arch/powerpc/include/asm/smp.h index a902a0d..bb4c033 100644 --- a/arch/powerpc/include/asm/smp.h +++ b/arch/powerpc/include/asm/smp.h @@ -29,6 +29,7 @@ #include extern int boot_cpuid; +extern int boot_cpu_count; extern void cpu_die(void); diff --git a/arch/powerpc/kernel/head_64.S b/arch/powerpc/kernel/head_64.S index 9594427..0700e11 100644 --- a/arch/powerpc/kernel/head_64.S +++ b/arch/powerpc/kernel/head_64.S @@ -242,23 +242,31 @@ generic_secondary_common_init: ld r23,0(r23) ld r23,CPU_SPEC_RESTORE(r23) cmpdi 0,r23,0 - beq 4f + beq 3f ld r23,0(r23) mtctr r23 bctrl -3: HMT_LOW +3: LOAD_REG_ADDR(r3, boot_cpu_count) /* Decrement boot_cpu_count */ + lwarx r4,0,r3 + subi r4,r4,1 + stwcx. r4,0,r3 + bne 3b + isync + +4: HMT_LOW lbz r23,PACAPROCSTART(r13) /* Test if this processor should */ /* start. */ #ifndef CONFIG_SMP - b 3b /* Never go on non-SMP */ + b 4b /* Never go on non-SMP */ #else cmpwi 0,r23,0 - beq 3b /* Loop until told to go */ + beq 4b /* Loop until told to go */ sync /* order paca.run and cur_cpu_spec */ + isync /* In case code patching happened */ -4: /* Create a temp kernel stack for use before relocation is on. */ + /* Create a temp kernel stack for use before relocation is on. */ ld r1,PACAEMERGSP(r13) subi r1,r1,STACK_FRAME_OVERHEAD diff --git a/arch/powerpc/kernel/prom.c b/arch/powerpc/kernel/prom.c index e74fa12..c391dc4 100644 --- a/arch/powerpc/kernel/prom.c +++ b/arch/powerpc/kernel/prom.c @@ -268,13 +268,12 @@ static int __init early_init_dt_scan_cpus(unsigned long node, const char *uname, int depth, void *data) { - static int logical_cpuid = 0; char *type = of_get_flat_dt_prop(node, "device_type", NULL); const u32 *prop; const u32 *intserv; int i, nthreads; unsigned long len; - int found = 0; + int found = -1; /* We are scanning "cpu" nodes only */ if (type == NULL || strcmp(type, "cpu") != 0) @@ -299,11 +298,8 @@ static int __init early_init_dt_scan_cpus(unsigned long node, * booted proc. */ if (initial_boot_params && initial_boot_params->version >= 2) { - if (intserv[i] == - initial_boot_params->boot_cpuid_phys) { - found = 1; - break; - } + if (intserv[i] == initial_boot_params->boot_cpuid_phys) + found = boot_cpu_count; } else { /* * Check if it's the boot-cpu, set it's hw index now, @@ -311,23 +307,20 @@ static int __init early_init_dt_scan_cpus(unsigned long node, * off secondary threads. */ if (of_get_flat_dt_prop(node, - "linux,boot-cpu", NULL) != NULL) { - found = 1; - break; - } + "linux,boot-cpu", NULL) != NULL) + found = boot_cpu_count; } - #ifdef CONFIG_SMP /* logical cpu id is always 0 on UP kernels */ - logical_cpuid++; + boot_cpu_count++; #endif } - if (found) { - DBG("boot cpu: logical %d physical %d\n", logical_cpuid, + if (found >= 0) { + DBG("boot cpu: logical %d physical %d\n", found, intserv[i]); - boot_cpuid = logical_cpuid; - set_hard_smp_processor_id(boot_cpuid, intserv[i]); + boot_cpuid = found; + set_hard_smp_processor_id(found, intserv[i]); /* * PAPR defines "logical" PVR values for cpus that diff --git a/arch/powerpc/kernel/setup_32.c b/arch/powerpc/kernel/setup_32.c index 1d2fbc9..620d792 100644 --- a/arch/powerpc/kernel/setup_32.c +++ b/arch/powerpc/kernel/setup_32.c @@ -48,6 +48,7 @@ extern void bootx_init(unsigned long r4, unsigned long phys); int boot_cpuid = -1; EXPORT_SYMBOL_GPL(boot_cpuid); +int __initdata boot_cpu_count; int boot_cpuid_phys; int smp_hw_index[NR_CPUS]; diff --git a/arch/powerpc/kernel/setup_64.c b/arch/powerpc/kernel/setup_64.c index 5a0401f..91a5cc5 100644 --- a/arch/powerpc/kernel/setup_64.c +++ b/arch/powerpc/kernel/setup_64.c @@ -72,6 +72,7 @@ #endif int boot_cpuid = 0; +int __initdata boot_cpu_count; u64 ppc64_pft_size; /* Pick defaults since we might want to patch instructions @@ -233,6 +234,7 @@ void early_setup_secondary(void) void smp_release_cpus(void) { unsigned long *ptr; + int i; DBG(" -> smp_release_cpus()\n"); @@ -245,7 +247,16 @@ void smp_release_cpus(void) ptr = (unsigned long *)((unsigned long)&__secondary_hold_spinloop - PHYSICAL_START); *ptr = __pa(generic_secondary_smp_init); - mb(); + + /* And wait a bit for them to catch up */ + for (i = 0; i < 100000; i++) { + mb(); + HMT_low(); + if (boot_cpu_count == 0) + break; + udelay(1); + } + DBG("boot_cpu_count = %d\n", boot_cpu_count); DBG(" <- smp_release_cpus()\n"); } -- cgit v0.10.2 From 948cf67c4726cca2fc57533dccadfb54d890689d Mon Sep 17 00:00:00 2001 From: Benjamin Herrenschmidt Date: Mon, 24 Jan 2011 18:42:41 +1100 Subject: powerpc: Add NAP mode support on Power7 in HV mode Wakeup comes from the system reset handler with a potential loss of the non-hypervisor CPU state. We save the non-volatile state on the stack and a pointer to it in the PACA, which the system reset handler uses to restore things Signed-off-by: Benjamin Herrenschmidt diff --git a/arch/powerpc/include/asm/machdep.h b/arch/powerpc/include/asm/machdep.h index e4f0191..493dbb3 100644 --- a/arch/powerpc/include/asm/machdep.h +++ b/arch/powerpc/include/asm/machdep.h @@ -267,6 +267,7 @@ struct machdep_calls { extern void e500_idle(void); extern void power4_idle(void); +extern void power7_idle(void); extern void ppc6xx_idle(void); extern void book3e_idle(void); diff --git a/arch/powerpc/include/asm/paca.h b/arch/powerpc/include/asm/paca.h index ec57540..f6da4f5 100644 --- a/arch/powerpc/include/asm/paca.h +++ b/arch/powerpc/include/asm/paca.h @@ -125,7 +125,7 @@ struct paca_struct { struct task_struct *__current; /* Pointer to current */ u64 kstack; /* Saved Kernel stack addr */ u64 stab_rr; /* stab/slb round-robin counter */ - u64 saved_r1; /* r1 save for RTAS calls */ + u64 saved_r1; /* r1 save for RTAS calls or PM */ u64 saved_msr; /* MSR saved here by enter_rtas */ u16 trap_save; /* Used when bad stack is encountered */ u8 soft_enabled; /* irq soft-enable flag */ diff --git a/arch/powerpc/include/asm/ppc-opcode.h b/arch/powerpc/include/asm/ppc-opcode.h index 1255569..384a96d 100644 --- a/arch/powerpc/include/asm/ppc-opcode.h +++ b/arch/powerpc/include/asm/ppc-opcode.h @@ -56,6 +56,9 @@ #define PPC_INST_TLBSRX_DOT 0x7c0006a5 #define PPC_INST_XXLOR 0xf0000510 +#define PPC_INST_NAP 0x4c000364 +#define PPC_INST_SLEEP 0x4c0003a4 + /* macros to insert fields into opcodes */ #define __PPC_RA(a) (((a) & 0x1f) << 16) #define __PPC_RB(b) (((b) & 0x1f) << 11) @@ -126,4 +129,7 @@ #define XXLOR(t, a, b) stringify_in_c(.long PPC_INST_XXLOR | \ VSX_XX3((t), (a), (b))) +#define PPC_NAP stringify_in_c(.long PPC_INST_NAP) +#define PPC_SLEEP stringify_in_c(.long PPC_INST_SLEEP) + #endif /* _ASM_POWERPC_PPC_OPCODE_H */ diff --git a/arch/powerpc/kernel/Makefile b/arch/powerpc/kernel/Makefile index 7c6eb49..0fd6273 100644 --- a/arch/powerpc/kernel/Makefile +++ b/arch/powerpc/kernel/Makefile @@ -44,6 +44,7 @@ obj-$(CONFIG_PPC_BOOK3E_64) += exceptions-64e.o idle_book3e.o obj-$(CONFIG_PPC64) += vdso64/ obj-$(CONFIG_ALTIVEC) += vecemu.o obj-$(CONFIG_PPC_970_NAP) += idle_power4.o +obj-$(CONFIG_PPC_P7_NAP) += idle_power7.o obj-$(CONFIG_PPC_OF) += of_platform.o prom_parse.o obj-$(CONFIG_PPC_CLOCK) += clock.o procfs-y := proc_powerpc.o diff --git a/arch/powerpc/kernel/exceptions-64s.S b/arch/powerpc/kernel/exceptions-64s.S index e513c1d..ad06333 100644 --- a/arch/powerpc/kernel/exceptions-64s.S +++ b/arch/powerpc/kernel/exceptions-64s.S @@ -37,7 +37,35 @@ .globl __start_interrupts __start_interrupts: - STD_EXCEPTION_PSERIES(0x100, 0x100, system_reset) + .globl system_reset_pSeries; +system_reset_pSeries: + HMT_MEDIUM; + DO_KVM 0x100; + SET_SCRATCH0(r13) +#ifdef CONFIG_PPC_P7_NAP +BEGIN_FTR_SECTION + /* Running native on arch 2.06 or later, check if we are + * waking up from nap. We only handle no state loss and + * supervisor state loss. We do -not- handle hypervisor + * state loss at this time. + */ + mfspr r13,SPRN_SRR1 + rlwinm r13,r13,47-31,30,31 + cmpwi cr0,r13,1 + bne 1f + b .power7_wakeup_noloss +1: cmpwi cr0,r13,2 + bne 1f + b .power7_wakeup_loss + /* Total loss of HV state is fatal, we could try to use the + * PIR to locate a PACA, then use an emergency stack etc... + * but for now, let's just stay stuck here + */ +1: cmpwi cr0,r13,3 + beq . +END_FTR_SECTION_IFSET(CPU_FTR_HVMODE_206) +#endif /* CONFIG_PPC_P7_NAP */ + EXCEPTION_PROLOG_PSERIES(PACA_EXGEN, system_reset_common, EXC_STD) . = 0x200 _machine_check_pSeries: diff --git a/arch/powerpc/kernel/idle_power7.S b/arch/powerpc/kernel/idle_power7.S new file mode 100644 index 0000000..f8f0bc7 --- /dev/null +++ b/arch/powerpc/kernel/idle_power7.S @@ -0,0 +1,97 @@ +/* + * This file contains the power_save function for 970-family CPUs. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#undef DEBUG + + .text + +_GLOBAL(power7_idle) + /* Now check if user or arch enabled NAP mode */ + LOAD_REG_ADDRBASE(r3,powersave_nap) + lwz r4,ADDROFF(powersave_nap)(r3) + cmpwi 0,r4,0 + beqlr + + /* NAP is a state loss, we create a regs frame on the + * stack, fill it up with the state we care about and + * stick a pointer to it in PACAR1. We really only + * need to save PC, some CR bits and the NV GPRs, + * but for now an interrupt frame will do. + */ + mflr r0 + std r0,16(r1) + stdu r1,-INT_FRAME_SIZE(r1) + std r0,_LINK(r1) + std r0,_NIP(r1) + +#ifndef CONFIG_SMP + /* Make sure FPU, VSX etc... are flushed as we may lose + * state when going to nap mode + */ + bl .discard_lazy_cpu_state +#endif /* CONFIG_SMP */ + + /* Hard disable interrupts */ + mfmsr r9 + rldicl r9,r9,48,1 + rotldi r9,r9,16 + mtmsrd r9,1 /* hard-disable interrupts */ + li r0,0 + stb r0,PACASOFTIRQEN(r13) /* we'll hard-enable shortly */ + stb r0,PACAHARDIRQEN(r13) + + /* Continue saving state */ + SAVE_GPR(2, r1) + SAVE_NVGPRS(r1) + mfcr r3 + std r3,_CCR(r1) + std r9,_MSR(r1) + std r1,PACAR1(r13) + + /* Magic NAP mode enter sequence */ + std r0,0(r1) + ptesync + ld r0,0(r1) +1: cmp cr0,r0,r0 + bne 1b + PPC_NAP + b . + +_GLOBAL(power7_wakeup_loss) + GET_PACA(r13) + ld r1,PACAR1(r13) + REST_NVGPRS(r1) + REST_GPR(2, r1) + ld r3,_CCR(r1) + ld r4,_MSR(r1) + ld r5,_NIP(r1) + addi r1,r1,INT_FRAME_SIZE + mtcr r3 + mtspr SPRN_SRR1,r4 + mtspr SPRN_SRR0,r5 + rfid + +_GLOBAL(power7_wakeup_noloss) + GET_PACA(r13) + ld r1,PACAR1(r13) + ld r4,_MSR(r1) + ld r5,_NIP(r1) + addi r1,r1,INT_FRAME_SIZE + mtspr SPRN_SRR1,r4 + mtspr SPRN_SRR0,r5 + rfid diff --git a/arch/powerpc/platforms/Kconfig b/arch/powerpc/platforms/Kconfig index f7b0772..658ffc5 100644 --- a/arch/powerpc/platforms/Kconfig +++ b/arch/powerpc/platforms/Kconfig @@ -147,6 +147,10 @@ config PPC_970_NAP bool default n +config PPC_P7_NAP + bool + default n + config PPC_INDIRECT_IO bool select GENERIC_IOMAP -- cgit v0.10.2 From dd797738643cd3c2dd9cdff7e4c3a04d318ab23a Mon Sep 17 00:00:00 2001 From: Benjamin Herrenschmidt Date: Tue, 5 Apr 2011 14:34:58 +1000 Subject: powerpc: Perform an isync to synchronize CPUs coming out of secondary_hold We need to do that to guarantee they see any code change done by dynamic patching during boot. Signed-off-by: Benjamin Herrenschmidt diff --git a/arch/powerpc/kernel/head_64.S b/arch/powerpc/kernel/head_64.S index 0700e11..6d17c37 100644 --- a/arch/powerpc/kernel/head_64.S +++ b/arch/powerpc/kernel/head_64.S @@ -147,6 +147,8 @@ __secondary_hold: mtctr r4 mr r3,r24 li r4,0 + /* Make sure that patched code is visible */ + isync bctr #else BUG_OPCODE -- cgit v0.10.2 From af2771493a1bf79cd9a1ab4f30327c428b5bd67c Mon Sep 17 00:00:00 2001 From: Benjamin Herrenschmidt Date: Wed, 6 Apr 2011 10:51:17 +1000 Subject: powerpc: Improve prom_printf() Adds the ability to print decimal numbers and adds some more format string variants Signed-off-by: Benjamin Herrenschmidt diff --git a/arch/powerpc/kernel/prom_init.c b/arch/powerpc/kernel/prom_init.c index 941ff4d..7839bd7 100644 --- a/arch/powerpc/kernel/prom_init.c +++ b/arch/powerpc/kernel/prom_init.c @@ -335,6 +335,7 @@ static void __init prom_printf(const char *format, ...) const char *p, *q, *s; va_list args; unsigned long v; + long vs; struct prom_t *_prom = &RELOC(prom); va_start(args, format); @@ -368,12 +369,35 @@ static void __init prom_printf(const char *format, ...) v = va_arg(args, unsigned long); prom_print_hex(v); break; + case 'd': + ++q; + vs = va_arg(args, int); + if (vs < 0) { + prom_print(RELOC("-")); + vs = -vs; + } + prom_print_dec(vs); + break; case 'l': ++q; - if (*q == 'u') { /* '%lu' */ + if (*q == 0) + break; + else if (*q == 'x') { + ++q; + v = va_arg(args, unsigned long); + prom_print_hex(v); + } else if (*q == 'u') { /* '%lu' */ ++q; v = va_arg(args, unsigned long); prom_print_dec(v); + } else if (*q == 'd') { /* %ld */ + ++q; + vs = va_arg(args, long); + if (vs < 0) { + prom_print(RELOC("-")); + vs = -vs; + } + prom_print_dec(vs); } break; } -- cgit v0.10.2 From 985762b2df4bcb4accc29fda76fc863dd79b8b58 Mon Sep 17 00:00:00 2001 From: Shan Wei Date: Tue, 19 Apr 2011 15:31:20 +0000 Subject: net: forcedeth: fix compile warning of not used nv_set_tso function MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fix the below compile warning: drivers/net/forcedeth.c:4266: warning: ‘nv_set_tso’ defined but not used commit 569e146 converts forcedeth driver to use hw_features. So, implement function of .set_tso is abandoned. Signed-off-by: Shan Wei Signed-off-by: David S. Miller diff --git a/drivers/net/forcedeth.c b/drivers/net/forcedeth.c index ec9a32d..0e1c76a 100644 --- a/drivers/net/forcedeth.c +++ b/drivers/net/forcedeth.c @@ -4263,16 +4263,6 @@ static int nv_nway_reset(struct net_device *dev) return ret; } -static int nv_set_tso(struct net_device *dev, u32 value) -{ - struct fe_priv *np = netdev_priv(dev); - - if ((np->driver_data & DEV_HAS_CHECKSUM)) - return ethtool_op_set_tso(dev, value); - else - return -EOPNOTSUPP; -} - static void nv_get_ringparam(struct net_device *dev, struct ethtool_ringparam* ring) { struct fe_priv *np = netdev_priv(dev); -- cgit v0.10.2 From ce45ee955ff53255993c9300344e6437761ce2b2 Mon Sep 17 00:00:00 2001 From: Shan Wei Date: Tue, 19 Apr 2011 15:38:06 +0000 Subject: =?UTF-8?q?net:bna:=20fix=20compile=20warning=20of=20=E2=80=98bfa?= =?UTF-8?q?=5Fioc=5Fsmem=5Fpgoff=E2=80=99=20defined=20but=20not=20used?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fix the below compile warning: drivers/net/bna/bfa_ioc.c:1922: warning: ‘bfa_ioc_smem_pgoff’ defined but not used Signed-off-by: Shan Wei Signed-off-by: David S. Miller diff --git a/drivers/net/bna/bfa_ioc.c b/drivers/net/bna/bfa_ioc.c index ba2a4e1..fcb9bb3 100644 --- a/drivers/net/bna/bfa_ioc.c +++ b/drivers/net/bna/bfa_ioc.c @@ -82,7 +82,6 @@ static void bfa_ioc_pf_fwmismatch(struct bfa_ioc *ioc); static void bfa_ioc_boot(struct bfa_ioc *ioc, u32 boot_type, u32 boot_param); static u32 bfa_ioc_smem_pgnum(struct bfa_ioc *ioc, u32 fmaddr); -static u32 bfa_ioc_smem_pgoff(struct bfa_ioc *ioc, u32 fmaddr); static void bfa_ioc_get_adapter_serial_num(struct bfa_ioc *ioc, char *serial_num); static void bfa_ioc_get_adapter_fw_ver(struct bfa_ioc *ioc, @@ -1923,12 +1922,6 @@ bfa_ioc_smem_pgnum(struct bfa_ioc *ioc, u32 fmaddr) return PSS_SMEM_PGNUM(ioc->ioc_regs.smem_pg0, fmaddr); } -static u32 -bfa_ioc_smem_pgoff(struct bfa_ioc *ioc, u32 fmaddr) -{ - return PSS_SMEM_PGOFF(fmaddr); -} - /** * Register mailbox message handler function, to be called by common modules */ -- cgit v0.10.2 From 16a871ef552ff55c80b6d8d895e371ea07c58281 Mon Sep 17 00:00:00 2001 From: Ajit Khaparde Date: Tue, 19 Apr 2011 12:10:43 +0000 Subject: be2net: allow register dump only for PFs Signed-off-by: Ajit Khaparde Signed-off-by: David S. Miller diff --git a/drivers/net/benet/be_ethtool.c b/drivers/net/benet/be_ethtool.c index 28716a6..22523b9 100644 --- a/drivers/net/benet/be_ethtool.c +++ b/drivers/net/benet/be_ethtool.c @@ -161,7 +161,9 @@ be_get_reg_len(struct net_device *netdev) struct be_adapter *adapter = netdev_priv(netdev); u32 log_size = 0; - be_cmd_get_reg_len(adapter, &log_size); + if (be_physfn(adapter)) + be_cmd_get_reg_len(adapter, &log_size); + return log_size; } @@ -170,8 +172,10 @@ be_get_regs(struct net_device *netdev, struct ethtool_regs *regs, void *buf) { struct be_adapter *adapter = netdev_priv(netdev); - memset(buf, 0, regs->len); - be_cmd_get_regs(adapter, regs->len, buf); + if (be_physfn(adapter)) { + memset(buf, 0, regs->len); + be_cmd_get_regs(adapter, regs->len, buf); + } } static int -- cgit v0.10.2 From 4fa9ed07e3965a809fa309a769675ac1c6dc692b Mon Sep 17 00:00:00 2001 From: Ajit Khaparde Date: Tue, 19 Apr 2011 12:10:53 +0000 Subject: be2net: Add code to display nic speeds other than 1Gbps/10Gbps Signed-off-by: Ajit Khaparde Signed-off-by: David S. Miller diff --git a/drivers/net/benet/be_ethtool.c b/drivers/net/benet/be_ethtool.c index 22523b9..33c2bec 100644 --- a/drivers/net/benet/be_ethtool.c +++ b/drivers/net/benet/be_ethtool.c @@ -384,12 +384,21 @@ static int be_get_settings(struct net_device *netdev, struct ethtool_cmd *ecmd) ecmd->speed = link_speed*10; } else { switch (mac_speed) { + case PHY_LINK_SPEED_10MBPS: + ecmd->speed = SPEED_10; + break; + case PHY_LINK_SPEED_100MBPS: + ecmd->speed = SPEED_100; + break; case PHY_LINK_SPEED_1GBPS: ecmd->speed = SPEED_1000; break; case PHY_LINK_SPEED_10GBPS: ecmd->speed = SPEED_10000; break; + case PHY_LINK_SPEED_ZERO: + ecmd->speed = 0; + break; } } -- cgit v0.10.2 From 6349935bdfa4a210fb557e7541caad1d41925ccc Mon Sep 17 00:00:00 2001 From: Ajit Khaparde Date: Tue, 19 Apr 2011 12:11:02 +0000 Subject: be2net: fix be_mcc_compl_process to identify eth_get_stat command eth_get_statistics and vlan_config command have same opcode. Use opcode subsystem id to differentiate one from other. Signed-off-by: Ajit Khaparde Signed-off-by: David S. Miller diff --git a/drivers/net/benet/be_cmds.c b/drivers/net/benet/be_cmds.c index 11b774a..a94e980 100644 --- a/drivers/net/benet/be_cmds.c +++ b/drivers/net/benet/be_cmds.c @@ -78,7 +78,8 @@ static int be_mcc_compl_process(struct be_adapter *adapter, } if (compl_status == MCC_STATUS_SUCCESS) { - if (compl->tag0 == OPCODE_ETH_GET_STATISTICS) { + if ((compl->tag0 == OPCODE_ETH_GET_STATISTICS) && + (compl->tag1 == CMD_SUBSYSTEM_ETH)) { struct be_cmd_resp_get_stats *resp = adapter->stats_cmd.va; be_dws_le_to_cpu(&resp->hw_stats, @@ -1096,6 +1097,7 @@ int be_cmd_get_stats(struct be_adapter *adapter, struct be_dma_mem *nonemb_cmd) be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_ETH, OPCODE_ETH_GET_STATISTICS, sizeof(*req)); + wrb->tag1 = CMD_SUBSYSTEM_ETH; sge->pa_hi = cpu_to_le32(upper_32_bits(nonemb_cmd->dma)); sge->pa_lo = cpu_to_le32(nonemb_cmd->dma & 0xFFFFFFFF); sge->len = cpu_to_le32(nonemb_cmd->size); -- cgit v0.10.2 From 187e87566d22b0d0e99b5ae7c6e18569ab5f6aee Mon Sep 17 00:00:00 2001 From: Ajit Khaparde Date: Tue, 19 Apr 2011 12:11:46 +0000 Subject: be2net: pass domain id to be_cmd_link_status_query Signed-off-by: Ajit Khaparde Signed-off-by: David S. Miller diff --git a/drivers/net/benet/be_cmds.c b/drivers/net/benet/be_cmds.c index a94e980..af8cf3d 100644 --- a/drivers/net/benet/be_cmds.c +++ b/drivers/net/benet/be_cmds.c @@ -1112,7 +1112,7 @@ err: /* Uses synchronous mcc */ int be_cmd_link_status_query(struct be_adapter *adapter, - bool *link_up, u8 *mac_speed, u16 *link_speed) + bool *link_up, u8 *mac_speed, u16 *link_speed, u32 dom) { struct be_mcc_wrb *wrb; struct be_cmd_req_link_status *req; diff --git a/drivers/net/benet/be_cmds.h b/drivers/net/benet/be_cmds.h index 3fb6e0a..af4bbff 100644 --- a/drivers/net/benet/be_cmds.h +++ b/drivers/net/benet/be_cmds.h @@ -1112,7 +1112,7 @@ extern int be_cmd_rxq_create(struct be_adapter *adapter, extern int be_cmd_q_destroy(struct be_adapter *adapter, struct be_queue_info *q, int type); extern int be_cmd_link_status_query(struct be_adapter *adapter, - bool *link_up, u8 *mac_speed, u16 *link_speed); + bool *link_up, u8 *mac_speed, u16 *link_speed, u32 dom); extern int be_cmd_reset(struct be_adapter *adapter); extern int be_cmd_get_stats(struct be_adapter *adapter, struct be_dma_mem *nonemb_cmd); diff --git a/drivers/net/benet/be_ethtool.c b/drivers/net/benet/be_ethtool.c index 33c2bec..6565f3e 100644 --- a/drivers/net/benet/be_ethtool.c +++ b/drivers/net/benet/be_ethtool.c @@ -376,7 +376,7 @@ static int be_get_settings(struct net_device *netdev, struct ethtool_cmd *ecmd) if ((adapter->link_speed < 0) || (!(netdev->flags & IFF_UP))) { status = be_cmd_link_status_query(adapter, &link_up, - &mac_speed, &link_speed); + &mac_speed, &link_speed, 0); be_link_status_update(adapter, link_up); /* link_speed is in units of 10 Mbps */ @@ -661,7 +661,7 @@ be_self_test(struct net_device *netdev, struct ethtool_test *test, u64 *data) } if (be_cmd_link_status_query(adapter, &link_up, &mac_speed, - &qos_link_speed) != 0) { + &qos_link_speed, 0) != 0) { test->flags |= ETH_TEST_FL_FAILED; data[4] = -1; } else if (!mac_speed) { diff --git a/drivers/net/benet/be_main.c b/drivers/net/benet/be_main.c index 1bb763c..77a6e7e 100644 --- a/drivers/net/benet/be_main.c +++ b/drivers/net/benet/be_main.c @@ -2171,7 +2171,7 @@ static int be_open(struct net_device *netdev) be_async_mcc_enable(adapter); status = be_cmd_link_status_query(adapter, &link_up, &mac_speed, - &link_speed); + &link_speed, 0); if (status) goto err; be_link_status_update(adapter, link_up); -- cgit v0.10.2 From d0381c42aabdbd9402501d08ea44a89695ad58b4 Mon Sep 17 00:00:00 2001 From: Ajit Khaparde Date: Tue, 19 Apr 2011 12:11:55 +0000 Subject: be2net: add code to display default value of tx rate for VFs This change will allow the default value of tx rate to be displayed when ip link show is called on a PF interface. Signed-off-by: Ajit Khaparde Signed-off-by: David S. Miller diff --git a/drivers/net/benet/be_main.c b/drivers/net/benet/be_main.c index 77a6e7e..3529400 100644 --- a/drivers/net/benet/be_main.c +++ b/drivers/net/benet/be_main.c @@ -3082,9 +3082,22 @@ static int __devinit be_probe(struct pci_dev *pdev, netif_carrier_off(netdev); if (be_physfn(adapter) && adapter->sriov_enabled) { + u8 mac_speed; + bool link_up; + u16 vf, lnk_speed; + status = be_vf_eth_addr_config(adapter); if (status) goto unreg_netdev; + + for (vf = 0; vf < num_vfs; vf++) { + status = be_cmd_link_status_query(adapter, &link_up, + &mac_speed, &lnk_speed, vf + 1); + if (!status) + adapter->vf_cfg[vf].vf_tx_rate = lnk_speed * 10; + else + goto unreg_netdev; + } } dev_info(&pdev->dev, "%s port %d\n", nic_name(pdev), adapter->port_num); -- cgit v0.10.2 From c6914a6f261aca0c9f715f883a353ae7ff51fe83 Mon Sep 17 00:00:00 2001 From: Dave Jones Date: Tue, 19 Apr 2011 20:36:59 -0700 Subject: can: Add missing socket check in can/bcm release. We can get here with a NULL socket argument passed from userspace, so we need to handle it accordingly. Signed-off-by: Dave Jones Signed-off-by: David S. Miller diff --git a/net/can/bcm.c b/net/can/bcm.c index 57b1aed..8a6a05e 100644 --- a/net/can/bcm.c +++ b/net/can/bcm.c @@ -1427,9 +1427,14 @@ static int bcm_init(struct sock *sk) static int bcm_release(struct socket *sock) { struct sock *sk = sock->sk; - struct bcm_sock *bo = bcm_sk(sk); + struct bcm_sock *bo; struct bcm_op *op, *next; + if (sk == NULL) + return 0; + + bo = bcm_sk(sk); + /* remove bcm_ops, timer, rx_unregister(), etc. */ unregister_netdevice_notifier(&bo->notifier); -- cgit v0.10.2 From 709d38714eff234432956931437457e0de806784 Mon Sep 17 00:00:00 2001 From: Shan Wei Date: Mon, 18 Apr 2011 19:19:29 +0000 Subject: sctp: delete unused macro definition of sctp_chunk_is_control The macro never be used. And if needed, can use !sctp_chunk_is_data instead of. Signed-off-by: Shan Wei Signed-off-by: Vlad Yasevich Signed-off-by: Wei Yongjun Signed-off-by: David S. Miller diff --git a/include/net/sctp/constants.h b/include/net/sctp/constants.h index c70d8cc..deac13d 100644 --- a/include/net/sctp/constants.h +++ b/include/net/sctp/constants.h @@ -150,7 +150,6 @@ SCTP_SUBTYPE_CONSTRUCTOR(OTHER, sctp_event_other_t, other) SCTP_SUBTYPE_CONSTRUCTOR(PRIMITIVE, sctp_event_primitive_t, primitive) -#define sctp_chunk_is_control(a) (a->chunk_hdr->type != SCTP_CID_DATA) #define sctp_chunk_is_data(a) (a->chunk_hdr->type == SCTP_CID_DATA) /* Calculate the actual data size in a data chunk */ -- cgit v0.10.2 From 33c7cfdbb0d2bc021979e4947c7030c30d572532 Mon Sep 17 00:00:00 2001 From: Shan Wei Date: Mon, 18 Apr 2011 19:11:01 +0000 Subject: sctp: fix the comment of sctp_sf_violation_paramlen() Update the comment about sctp_sf_violation_paramlen() to be more precise. Signed-off-by: Shan Wei Signed-off-by: Vlad Yasevich Signed-off-by: Wei Yongjun Signed-off-by: David S. Miller diff --git a/net/sctp/sm_statefuns.c b/net/sctp/sm_statefuns.c index 7679208..c085472 100644 --- a/net/sctp/sm_statefuns.c +++ b/net/sctp/sm_statefuns.c @@ -4343,8 +4343,9 @@ static sctp_disposition_t sctp_sf_violation_chunklen( /* * Handle a protocol violation when the parameter length is invalid. - * "Invalid" length is identified as smaller than the minimal length a - * given parameter can be. + * If the length is smaller than the minimum length of a given parameter, + * or accumulated length in multi parameters exceeds the end of the chunk, + * the length is considered as invalid. */ static sctp_disposition_t sctp_sf_violation_paramlen( const struct sctp_endpoint *ep, -- cgit v0.10.2 From 6a435732accd9e3f4a8d9c320fabe578b1bf5add Mon Sep 17 00:00:00 2001 From: Shan Wei Date: Mon, 18 Apr 2011 19:11:47 +0000 Subject: sctp: use common head of addr parameter to access member in addr-unrelated code The 'p' member of struct sctp_paramhdr is common part for IPv4 addr parameter and IPv6 addr parameter in union sctp_addr_param. For addr-related code, use specified addr parameter. Otherwise, use common header to access type/length member. Signed-off-by: Shan Wei Signed-off-by: Vlad Yasevich Signed-off-by: Wei Yongjun Signed-off-by: David S. Miller diff --git a/net/sctp/input.c b/net/sctp/input.c index 5436c69..30cec77 100644 --- a/net/sctp/input.c +++ b/net/sctp/input.c @@ -1017,7 +1017,7 @@ static struct sctp_association *__sctp_rcv_asconf_lookup( /* Skip over the ADDIP header and find the Address parameter */ param = (union sctp_addr_param *)(asconf + 1); - af = sctp_get_af_specific(param_type2af(param->v4.param_hdr.type)); + af = sctp_get_af_specific(param_type2af(param->p.type)); if (unlikely(!af)) return NULL; diff --git a/net/sctp/sm_make_chunk.c b/net/sctp/sm_make_chunk.c index b3434cc..844adfd 100644 --- a/net/sctp/sm_make_chunk.c +++ b/net/sctp/sm_make_chunk.c @@ -2923,7 +2923,7 @@ static __be16 sctp_process_asconf_param(struct sctp_association *asoc, asconf_param->param_hdr.type != SCTP_PARAM_SET_PRIMARY) return SCTP_ERROR_UNKNOWN_PARAM; - switch (addr_param->v4.param_hdr.type) { + switch (addr_param->p.type) { case SCTP_PARAM_IPV6_ADDRESS: if (!asoc->peer.ipv6_address) return SCTP_ERROR_DNS_FAILED; @@ -2936,7 +2936,7 @@ static __be16 sctp_process_asconf_param(struct sctp_association *asoc, return SCTP_ERROR_DNS_FAILED; } - af = sctp_get_af_specific(param_type2af(addr_param->v4.param_hdr.type)); + af = sctp_get_af_specific(param_type2af(addr_param->p.type)); if (unlikely(!af)) return SCTP_ERROR_DNS_FAILED; @@ -3100,7 +3100,7 @@ struct sctp_chunk *sctp_process_asconf(struct sctp_association *asoc, /* Skip the address parameter and store a pointer to the first * asconf parameter. */ - length = ntohs(addr_param->v4.param_hdr.length); + length = ntohs(addr_param->p.length); asconf_param = (sctp_addip_param_t *)((void *)addr_param + length); chunk_len -= length; @@ -3177,7 +3177,7 @@ static void sctp_asconf_param_success(struct sctp_association *asoc, ((void *)asconf_param + sizeof(sctp_addip_param_t)); /* We have checked the packet before, so we do not check again. */ - af = sctp_get_af_specific(param_type2af(addr_param->v4.param_hdr.type)); + af = sctp_get_af_specific(param_type2af(addr_param->p.type)); af->from_addr_param(&addr, addr_param, htons(bp->port), 0); switch (asconf_param->param_hdr.type) { @@ -3304,7 +3304,7 @@ int sctp_process_asconf_ack(struct sctp_association *asoc, /* Skip the address parameter in the last asconf sent and store a * pointer to the first asconf parameter. */ - length = ntohs(addr_param->v4.param_hdr.length); + length = ntohs(addr_param->p.length); asconf_param = (sctp_addip_param_t *)((void *)addr_param + length); asconf_len -= length; -- cgit v0.10.2 From 66009927f1e7374afdc6f9fdd25c493ee4eadf7c Mon Sep 17 00:00:00 2001 From: Shan Wei Date: Mon, 18 Apr 2011 19:12:40 +0000 Subject: sctp: kill abandoned SCTP_CMD_TRANSMIT command Remove SCTP_CMD_TRANSMIT command as it never be used. Signed-off-by: Shan Wei Signed-off-by: Vlad Yasevich Signed-off-by: Wei Yongjun Signed-off-by: David S. Miller diff --git a/include/net/sctp/command.h b/include/net/sctp/command.h index c01dc99..2b44764 100644 --- a/include/net/sctp/command.h +++ b/include/net/sctp/command.h @@ -73,7 +73,6 @@ typedef enum { SCTP_CMD_INIT_FAILED, /* High level, do init failure work. */ SCTP_CMD_REPORT_DUP, /* Report a duplicate TSN. */ SCTP_CMD_STRIKE, /* Mark a strike against a transport. */ - SCTP_CMD_TRANSMIT, /* Transmit the outqueue. */ SCTP_CMD_HB_TIMERS_START, /* Start the heartbeat timers. */ SCTP_CMD_HB_TIMER_UPDATE, /* Update a heartbeat timers. */ SCTP_CMD_HB_TIMERS_STOP, /* Stop the heartbeat timers. */ diff --git a/net/sctp/sm_sideeffect.c b/net/sctp/sm_sideeffect.c index 5f86ee4b..3b80fe2 100644 --- a/net/sctp/sm_sideeffect.c +++ b/net/sctp/sm_sideeffect.c @@ -1415,12 +1415,6 @@ static int sctp_cmd_interpreter(sctp_event_t event_type, SCTP_RTXR_T3_RTX); break; - case SCTP_CMD_TRANSMIT: - /* Kick start transmission. */ - error = sctp_outq_uncork(&asoc->outqueue); - local_cork = 0; - break; - case SCTP_CMD_ECN_CE: /* Do delayed CE processing. */ sctp_do_ecn_ce_work(asoc, cmd->obj.u32); -- cgit v0.10.2 From 934253a7b4ab4151037ea9532552628723a14442 Mon Sep 17 00:00:00 2001 From: Shan Wei Date: Mon, 18 Apr 2011 19:13:18 +0000 Subject: sctp: use memdup_user to copy data from userspace Use common function to simply code. Signed-off-by: Shan Wei Signed-off-by: Vlad Yasevich Signed-off-by: Wei Yongjun Signed-off-by: David S. Miller diff --git a/net/sctp/socket.c b/net/sctp/socket.c index deb82e3..5c9980a 100644 --- a/net/sctp/socket.c +++ b/net/sctp/socket.c @@ -3215,14 +3215,9 @@ static int sctp_setsockopt_hmac_ident(struct sock *sk, if (optlen < sizeof(struct sctp_hmacalgo)) return -EINVAL; - hmacs = kmalloc(optlen, GFP_KERNEL); - if (!hmacs) - return -ENOMEM; - - if (copy_from_user(hmacs, optval, optlen)) { - err = -EFAULT; - goto out; - } + hmacs= memdup_user(optval, optlen); + if (IS_ERR(hmacs)) + return PTR_ERR(hmacs); idents = hmacs->shmac_num_idents; if (idents == 0 || idents > SCTP_AUTH_NUM_HMACS || @@ -3257,14 +3252,9 @@ static int sctp_setsockopt_auth_key(struct sock *sk, if (optlen <= sizeof(struct sctp_authkey)) return -EINVAL; - authkey = kmalloc(optlen, GFP_KERNEL); - if (!authkey) - return -ENOMEM; - - if (copy_from_user(authkey, optval, optlen)) { - ret = -EFAULT; - goto out; - } + authkey= memdup_user(optval, optlen); + if (IS_ERR(authkey)) + return PTR_ERR(authkey); if (authkey->sca_keylength > optlen - sizeof(struct sctp_authkey)) { ret = -EINVAL; -- cgit v0.10.2 From f246a7b7c5b9df0ea0f0807a7101995af5e83213 Mon Sep 17 00:00:00 2001 From: Vlad Yasevich Date: Mon, 18 Apr 2011 19:13:56 +0000 Subject: sctp: teach CACC algorithm about removed transports When we have have to remove a transport due to ASCONF, we move the data to a new active path. This can trigger CACC algorithm to not mark that data as missing when SACKs arrive. This is because the transport passed to the CACC algorithm is the one this data is sitting on, not the one it was sent on (that one may be gone). So, by sending the original transport (even if it's NULL), we may start marking data as missing. Signed-off-by: Vlad Yasevich Signed-off-by: Wei Yongjun Signed-off-by: David S. Miller diff --git a/net/sctp/outqueue.c b/net/sctp/outqueue.c index bf92a5b..7812772 100644 --- a/net/sctp/outqueue.c +++ b/net/sctp/outqueue.c @@ -131,7 +131,8 @@ static inline int sctp_cacc_skip_3_1_d(struct sctp_transport *primary, static inline int sctp_cacc_skip_3_1_f(struct sctp_transport *transport, int count_of_newacks) { - if (count_of_newacks < 2 && !transport->cacc.cacc_saw_newack) + if (count_of_newacks < 2 && + (transport && !transport->cacc.cacc_saw_newack)) return 1; return 0; } @@ -618,9 +619,12 @@ redo: /* If we are retransmitting, we should only * send a single packet. + * Otherwise, try appending this chunk again. */ if (rtx_timeout || fast_rtx) done = 1; + else + goto redo; /* Bundle next chunk in the next round. */ break; @@ -1683,8 +1687,9 @@ static void sctp_mark_missing(struct sctp_outq *q, /* SFR-CACC may require us to skip marking * this chunk as missing. */ - if (!transport || !sctp_cacc_skip(primary, transport, - count_of_newacks, tsn)) { + if (!transport || !sctp_cacc_skip(primary, + chunk->transport, + count_of_newacks, tsn)) { chunk->tsn_missing_report++; SCTP_DEBUG_PRINTK( -- cgit v0.10.2 From ee9cbaca7d73ea0098f00ecd10fe6e4a4792e32c Mon Sep 17 00:00:00 2001 From: Vlad Yasevich Date: Mon, 18 Apr 2011 19:14:47 +0000 Subject: sctp: Allow bindx_del to accept 0 port We allow 0 port when adding new addresses. It only makes sence to allow 0 port when removing addresses. When removing the currently bound port will be used when the port in the address is set to 0. Signed-off-by: Vlad Yasevich Signed-off-by: Wei Yongjun Signed-off-by: David S. Miller diff --git a/net/sctp/socket.c b/net/sctp/socket.c index 5c9980a..431b890 100644 --- a/net/sctp/socket.c +++ b/net/sctp/socket.c @@ -658,11 +658,15 @@ static int sctp_bindx_rem(struct sock *sk, struct sockaddr *addrs, int addrcnt) goto err_bindx_rem; } - if (sa_addr->v4.sin_port != htons(bp->port)) { + if (sa_addr->v4.sin_port && + sa_addr->v4.sin_port != htons(bp->port)) { retval = -EINVAL; goto err_bindx_rem; } + if (!sa_addr->v4.sin_port) + sa_addr->v4.sin_port = htons(bp->port); + /* FIXME - There is probably a need to check if sk->sk_saddr and * sk->sk_rcv_addr are currently set to one of the addresses to * be removed. This is something which needs to be looked into -- cgit v0.10.2 From c6ef006bf57fb6a8a0b134928b5c5606090ef0a0 Mon Sep 17 00:00:00 2001 From: Vlad Yasevich Date: Mon, 18 Apr 2011 19:15:22 +0000 Subject: sctp: Release all routes when processing acks ADD_IP or DEL_IP When processing an ACK for ADD_IP parameter, we only release the routes on non-active transports. This can cause a wrong source address to be used. We can release the routes and cause new route lookups and source address selection so that new addresses can be used as source. Additionally, we don't need to lookup routes for all transports at the same time. We can let the transmit code path update the cached route when the transport actually sends something. Signed-off-by: Vlad Yasevich Signed-off-by: Wei Yongjun Signed-off-by: David S. Miller diff --git a/net/sctp/sm_make_chunk.c b/net/sctp/sm_make_chunk.c index 844adfd..f87ccb1 100644 --- a/net/sctp/sm_make_chunk.c +++ b/net/sctp/sm_make_chunk.c @@ -3193,11 +3193,8 @@ static void sctp_asconf_param_success(struct sctp_association *asoc, local_bh_enable(); list_for_each_entry(transport, &asoc->peer.transport_addr_list, transports) { - if (transport->state == SCTP_ACTIVE) - continue; dst_release(transport->dst); - sctp_transport_route(transport, NULL, - sctp_sk(asoc->base.sk)); + transport->dst = NULL; } break; case SCTP_PARAM_DEL_IP: @@ -3207,8 +3204,7 @@ static void sctp_asconf_param_success(struct sctp_association *asoc, list_for_each_entry(transport, &asoc->peer.transport_addr_list, transports) { dst_release(transport->dst); - sctp_transport_route(transport, NULL, - sctp_sk(asoc->base.sk)); + transport->dst = NULL; } break; default: -- cgit v0.10.2 From 2b7da309ffe602d222558cee4d7e407b96e34b3a Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Wed, 20 Apr 2011 15:38:07 +1000 Subject: md/raid5: remove setting of ->queue_lock We previously needed to set ->queue_lock to match the raid5 device_lock so we could safely use queue_flag_* operations (e.g. for plugging). which test the ->queue_lock is in fact locked. However that need has completely gone away and is unlikely to come back to remove this now-pointless setting. Signed-off-by: NeilBrown diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c index f301e6a..179bdfc 100644 --- a/drivers/md/raid5.c +++ b/drivers/md/raid5.c @@ -5151,7 +5151,6 @@ static int run(mddev_t *mddev) mddev->queue->backing_dev_info.congested_data = mddev; mddev->queue->backing_dev_info.congested_fn = raid5_congested; - mddev->queue->queue_lock = &conf->device_lock; chunk_size = mddev->chunk_sectors << 9; blk_queue_io_min(mddev->queue, chunk_size); -- cgit v0.10.2 From 3b71bd9337b404baab5c894e066be6b6bf51b1c3 Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Wed, 20 Apr 2011 15:38:18 +1000 Subject: md: Fix dev_sectors on takeover from raid0 to raid4/5 A raid0 array doesn't set 'dev_sectors' as each device might contribute a different number of sectors. So when converting to a RAID4 or RAID5 we need to set dev_sectors as they need the number. We have already verified that in fact all devices do contribute the same number of sectors, so use that number. Signed-off-by: NeilBrown diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c index 179bdfc..fd50011 100644 --- a/drivers/md/raid5.c +++ b/drivers/md/raid5.c @@ -5678,6 +5678,7 @@ static void raid5_quiesce(mddev_t *mddev, int state) static void *raid45_takeover_raid0(mddev_t *mddev, int level) { struct raid0_private_data *raid0_priv = mddev->private; + unsigned long long sectors; /* for raid0 takeover only one zone is supported */ if (raid0_priv->nr_strip_zones > 1) { @@ -5686,6 +5687,9 @@ static void *raid45_takeover_raid0(mddev_t *mddev, int level) return ERR_PTR(-EINVAL); } + sectors = raid0_priv->strip_zone[0].zone_end; + sector_div(sectors, raid0_priv->strip_zone[0].nb_dev); + mddev->dev_sectors = sectors; mddev->new_level = level; mddev->new_layout = ALGORITHM_PARITY_N; mddev->new_chunk_sectors = mddev->chunk_sectors; -- cgit v0.10.2 From fee68723cf6ae00082f70f3eff17fceab2a4f7d7 Mon Sep 17 00:00:00 2001 From: Krzysztof Wojcik Date: Wed, 20 Apr 2011 15:39:53 +1000 Subject: md: Cleanup after raid45->raid0 takeover Problem: After raid4->raid0 takeover operation, another takeover operation (e.g raid0->raid10) results "kernel oops". Root cause: Variables 'degraded' in mddev structure is not cleared on raid45->raid0 takeover. This patch reset this variable. Signed-off-by: Krzysztof Wojcik Signed-off-by: NeilBrown diff --git a/drivers/md/md.c b/drivers/md/md.c index 6e853c6..7d6f7f1 100644 --- a/drivers/md/md.c +++ b/drivers/md/md.c @@ -3170,6 +3170,7 @@ level_store(mddev_t *mddev, const char *buf, size_t len) mddev->layout = mddev->new_layout; mddev->chunk_sectors = mddev->new_chunk_sectors; mddev->delta_disks = 0; + mddev->degraded = 0; if (mddev->pers->sync_request == NULL) { /* this is now an array without redundancy, so * it must always be in_sync -- cgit v0.10.2 From 28a8397852011e323d16a1eecd4787d72b7b9a9e Mon Sep 17 00:00:00 2001 From: CoolCold Date: Wed, 20 Apr 2011 15:40:01 +1000 Subject: md: Update documentation for sync_min and sync_max entries linux/Documentation/md.txt is missing description for sync_min and sync_max entries. This patch adds description for sync_min and sync_max entries. Signed-off-by: Roman Ovchinnikov Signed-off-by: NeilBrown diff --git a/Documentation/md.txt b/Documentation/md.txt index a81c7b4..2366b1c 100644 --- a/Documentation/md.txt +++ b/Documentation/md.txt @@ -552,6 +552,16 @@ also have within the array where IO will be blocked. This is currently only supported for raid4/5/6. + sync_min + sync_max + The two values, given as numbers of sectors, indicate a range + withing the array where 'check'/'repair' will operate. Must be + a multiple of chunk_size. When it reaches "sync_max" it will + pause, rather than complete. + You can use 'select' or 'poll' on "sync_completed" to wait for + that number to reach sync_max. Then you can either increase + "sync_max", or can write 'idle' to "sync_action". + Each active md device may also have attributes specific to the personality module that manages it. -- cgit v0.10.2 From 5e8e7b404ac965be45e25d5538676151de89aefb Mon Sep 17 00:00:00 2001 From: Michael Ellerman Date: Tue, 12 Apr 2011 19:00:04 +0000 Subject: powerpc/mm: Standardise on MMU_NO_CONTEXT Use MMU_NO_CONTEXT as the initialiser for mm_context.id on nohash and hash64. Signed-off-by: Michael Ellerman Signed-off-by: Benjamin Herrenschmidt diff --git a/arch/powerpc/include/asm/tlbflush.h b/arch/powerpc/include/asm/tlbflush.h index d50a380..81143fc 100644 --- a/arch/powerpc/include/asm/tlbflush.h +++ b/arch/powerpc/include/asm/tlbflush.h @@ -79,6 +79,8 @@ static inline void local_flush_tlb_mm(struct mm_struct *mm) #elif defined(CONFIG_PPC_STD_MMU_64) +#define MMU_NO_CONTEXT 0 + /* * TLB flushing for 64-bit hash-MMU CPUs */ diff --git a/arch/powerpc/mm/mmu_context_hash64.c b/arch/powerpc/mm/mmu_context_hash64.c index 2535828..c585944 100644 --- a/arch/powerpc/mm/mmu_context_hash64.c +++ b/arch/powerpc/mm/mmu_context_hash64.c @@ -31,7 +31,6 @@ static DEFINE_IDA(mmu_context_ida); * Each segment contains 2^28 bytes. Each context maps 2^44 bytes, * so we can support 2^19-1 contexts (19 == 35 + 28 - 44). */ -#define NO_CONTEXT 0 #define MAX_CONTEXT ((1UL << 19) - 1) int __init_new_context(void) @@ -95,5 +94,5 @@ void destroy_context(struct mm_struct *mm) { __destroy_context(mm->context.id); subpage_prot_free(mm); - mm->context.id = NO_CONTEXT; + mm->context.id = MMU_NO_CONTEXT; } -- cgit v0.10.2 From ee7a2aa3d3fd10a7157dd19f737b2bafdea0458f Mon Sep 17 00:00:00 2001 From: Michael Ellerman Date: Tue, 12 Apr 2011 19:00:05 +0000 Subject: powerpc/mm: Fix slice state initialization for Book3E On Book3E, MMU_NO_CONTEXT != 0, but the slice_mm_new_context() macro assumes that it is. This means that the map of the page sizes for each slice is always initialized to zeroes (which happens to be 4k pages), rather than to the correct default base page size value - which might be 64k. This patch corrects the problem. Signed-off-by: David Gibson Signed-off-by: Michael Ellerman Signed-off-by: Benjamin Herrenschmidt diff --git a/arch/powerpc/include/asm/page_64.h b/arch/powerpc/include/asm/page_64.h index 812b2cd..488c52e 100644 --- a/arch/powerpc/include/asm/page_64.h +++ b/arch/powerpc/include/asm/page_64.h @@ -130,7 +130,7 @@ extern void slice_set_user_psize(struct mm_struct *mm, unsigned int psize); extern void slice_set_range_psize(struct mm_struct *mm, unsigned long start, unsigned long len, unsigned int psize); -#define slice_mm_new_context(mm) ((mm)->context.id == 0) +#define slice_mm_new_context(mm) ((mm)->context.id == MMU_NO_CONTEXT) #endif /* __ASSEMBLY__ */ #else -- cgit v0.10.2 From 6975a783d7b40c79be4b7a7ea450e023ff7e5e02 Mon Sep 17 00:00:00 2001 From: Michael Ellerman Date: Tue, 12 Apr 2011 20:38:55 +0000 Subject: powerpc/boot: Allow building the zImage wrapper as a relocatable ET_DYN This patch adds code, linker script and makefile support to allow building the zImage wrapper around the kernel as a position independent executable. This results in an ET_DYN instead of an ET_EXEC ELF output file, which can be loaded at any location by the firmware and will process its own relocations to work correctly at the loaded address. This is of interest particularly since the standard ePAPR image format must be an ET_DYN (although this patch alone is not sufficient to produce a fully ePAPR compliant boot image). Note for now we don't enable building with -pie for anything. Signed-off-by: Paul Mackerras Signed-off-by: David Gibson Signed-off-by: Michael Ellerman Signed-off-by: Benjamin Herrenschmidt diff --git a/arch/powerpc/boot/crt0.S b/arch/powerpc/boot/crt0.S index f1c4dfc..0f7428a 100644 --- a/arch/powerpc/boot/crt0.S +++ b/arch/powerpc/boot/crt0.S @@ -6,16 +6,28 @@ * as published by the Free Software Foundation; either version * 2 of the License, or (at your option) any later version. * - * NOTE: this code runs in 32 bit mode and is packaged as ELF32. + * NOTE: this code runs in 32 bit mode, is position-independent, + * and is packaged as ELF32. */ #include "ppc_asm.h" .text - /* a procedure descriptor used when booting this as a COFF file */ + /* A procedure descriptor used when booting this as a COFF file. + * When making COFF, this comes first in the link and we're + * linked at 0x500000. + */ .globl _zimage_start_opd _zimage_start_opd: - .long _zimage_start, 0, 0, 0 + .long 0x500000, 0, 0, 0 + +p_start: .long _start +p_etext: .long _etext +p_bss_start: .long __bss_start +p_end: .long _end + + .weak _platform_stack_top +p_pstack: .long _platform_stack_top .weak _zimage_start .globl _zimage_start @@ -24,37 +36,65 @@ _zimage_start: _zimage_start_lib: /* Work out the offset between the address we were linked at and the address where we're running. */ - bl 1f -1: mflr r0 - lis r9,1b@ha - addi r9,r9,1b@l - subf. r0,r9,r0 - beq 3f /* if running at same address as linked */ + bl .+4 +p_base: mflr r10 /* r10 now points to runtime addr of p_base */ + /* grab the link address of the dynamic section in r11 */ + addis r11,r10,(_GLOBAL_OFFSET_TABLE_-p_base)@ha + lwz r11,(_GLOBAL_OFFSET_TABLE_-p_base)@l(r11) + cmpwi r11,0 + beq 3f /* if not linked -pie */ + /* get the runtime address of the dynamic section in r12 */ + .weak __dynamic_start + addis r12,r10,(__dynamic_start-p_base)@ha + addi r12,r12,(__dynamic_start-p_base)@l + subf r11,r11,r12 /* runtime - linktime offset */ + + /* The dynamic section contains a series of tagged entries. + * We need the RELA and RELACOUNT entries. */ +RELA = 7 +RELACOUNT = 0x6ffffff9 + li r9,0 + li r0,0 +9: lwz r8,0(r12) /* get tag */ + cmpwi r8,0 + beq 10f /* end of list */ + cmpwi r8,RELA + bne 11f + lwz r9,4(r12) /* get RELA pointer in r9 */ + b 12f +11: addis r8,r8,(-RELACOUNT)@ha + cmpwi r8,RELACOUNT@l + bne 12f + lwz r0,4(r12) /* get RELACOUNT value in r0 */ +12: addi r12,r12,8 + b 9b - /* The .got2 section contains a list of addresses, so add - the address offset onto each entry. */ - lis r9,__got2_start@ha - addi r9,r9,__got2_start@l - lis r8,__got2_end@ha - addi r8,r8,__got2_end@l - subf. r8,r9,r8 + /* The relocation section contains a list of relocations. + * We now do the R_PPC_RELATIVE ones, which point to words + * which need to be initialized with addend + offset. + * The R_PPC_RELATIVE ones come first and there are RELACOUNT + * of them. */ +10: /* skip relocation if we don't have both */ + cmpwi r0,0 beq 3f - srwi. r8,r8,2 - mtctr r8 - add r9,r0,r9 -2: lwz r8,0(r9) - add r8,r8,r0 - stw r8,0(r9) - addi r9,r9,4 + cmpwi r9,0 + beq 3f + + add r9,r9,r11 /* Relocate RELA pointer */ + mtctr r0 +2: lbz r0,4+3(r9) /* ELF32_R_INFO(reloc->r_info) */ + cmpwi r0,22 /* R_PPC_RELATIVE */ + bne 3f + lwz r12,0(r9) /* reloc->r_offset */ + lwz r0,8(r9) /* reloc->r_addend */ + add r0,r0,r11 + stwx r0,r11,r12 + addi r9,r9,12 bdnz 2b /* Do a cache flush for our text, in case the loader didn't */ -3: lis r9,_start@ha - addi r9,r9,_start@l - add r9,r0,r9 - lis r8,_etext@ha - addi r8,r8,_etext@l - add r8,r0,r8 +3: lwz r9,p_start-p_base(r10) /* note: these are relocated now */ + lwz r8,p_etext-p_base(r10) 4: dcbf r0,r9 icbi r0,r9 addi r9,r9,0x20 @@ -64,27 +104,19 @@ _zimage_start_lib: isync /* Clear the BSS */ - lis r9,__bss_start@ha - addi r9,r9,__bss_start@l - add r9,r0,r9 - lis r8,_end@ha - addi r8,r8,_end@l - add r8,r0,r8 - li r10,0 -5: stw r10,0(r9) + lwz r9,p_bss_start-p_base(r10) + lwz r8,p_end-p_base(r10) + li r0,0 +5: stw r0,0(r9) addi r9,r9,4 cmplw cr0,r9,r8 blt 5b /* Possibly set up a custom stack */ -.weak _platform_stack_top - lis r8,_platform_stack_top@ha - addi r8,r8,_platform_stack_top@l + lwz r8,p_pstack-p_base(r10) cmpwi r8,0 beq 6f - add r8,r0,r8 lwz r1,0(r8) - add r1,r0,r1 li r0,0 stwu r0,-16(r1) /* establish a stack frame */ 6: diff --git a/arch/powerpc/boot/wrapper b/arch/powerpc/boot/wrapper index cb97e75..fef5278 100755 --- a/arch/powerpc/boot/wrapper +++ b/arch/powerpc/boot/wrapper @@ -39,6 +39,7 @@ dts= cacheit= binary= gzip=.gz +pie= # cross-compilation prefix CROSS= @@ -157,9 +158,10 @@ pmac|chrp) platformo=$object/of.o ;; coff) - platformo=$object/of.o + platformo="$object/crt0.o $object/of.o" lds=$object/zImage.coff.lds link_address='0x500000' + pie= ;; miboot|uboot) # miboot and U-boot want just the bare bits, not an ELF binary @@ -208,6 +210,7 @@ ps3) ksection=.kernel:vmlinux.bin isection=.kernel:initrd link_address='' + pie= ;; ep88xc|ep405|ep8248e) platformo="$object/fixed-head.o $object/$platform.o" @@ -310,9 +313,9 @@ fi if [ "$platform" != "miboot" ]; then if [ -n "$link_address" ] ; then - text_start="-Ttext $link_address --defsym _start=$link_address" + text_start="-Ttext $link_address" fi - ${CROSS}ld -m elf32ppc -T $lds $text_start -o "$ofile" \ + ${CROSS}ld -m elf32ppc -T $lds $text_start $pie -o "$ofile" \ $platformo $tmp $object/wrapper.a rm $tmp fi diff --git a/arch/powerpc/boot/zImage.coff.lds.S b/arch/powerpc/boot/zImage.coff.lds.S index 856dc78..de4c9e3 100644 --- a/arch/powerpc/boot/zImage.coff.lds.S +++ b/arch/powerpc/boot/zImage.coff.lds.S @@ -3,13 +3,13 @@ ENTRY(_zimage_start_opd) EXTERN(_zimage_start_opd) SECTIONS { - _start = .; .text : { + _start = .; *(.text) *(.fixup) + _etext = .; } - _etext = .; . = ALIGN(4096); .data : { @@ -17,9 +17,7 @@ SECTIONS *(.data*) *(__builtin_*) *(.sdata*) - __got2_start = .; *(.got2) - __got2_end = .; _dtb_start = .; *(.kernel:dtb) diff --git a/arch/powerpc/boot/zImage.lds.S b/arch/powerpc/boot/zImage.lds.S index 0962d62..2bd8731 100644 --- a/arch/powerpc/boot/zImage.lds.S +++ b/arch/powerpc/boot/zImage.lds.S @@ -3,49 +3,64 @@ ENTRY(_zimage_start) EXTERN(_zimage_start) SECTIONS { - _start = .; .text : { + _start = .; *(.text) *(.fixup) + _etext = .; } - _etext = .; . = ALIGN(4096); .data : { *(.rodata*) *(.data*) *(.sdata*) - __got2_start = .; *(.got2) - __got2_end = .; } + .dynsym : { *(.dynsym) } + .dynstr : { *(.dynstr) } + .dynamic : + { + __dynamic_start = .; + *(.dynamic) + } + .hash : { *(.hash) } + .interp : { *(.interp) } + .rela.dyn : { *(.rela*) } . = ALIGN(8); - _dtb_start = .; - .kernel:dtb : { *(.kernel:dtb) } - _dtb_end = .; - - . = ALIGN(4096); - _vmlinux_start = .; - .kernel:vmlinux.strip : { *(.kernel:vmlinux.strip) } - _vmlinux_end = .; + .kernel:dtb : + { + _dtb_start = .; + *(.kernel:dtb) + _dtb_end = .; + } . = ALIGN(4096); - _initrd_start = .; - .kernel:initrd : { *(.kernel:initrd) } - _initrd_end = .; + .kernel:vmlinux.strip : + { + _vmlinux_start = .; + *(.kernel:vmlinux.strip) + _vmlinux_end = .; + } . = ALIGN(4096); - _edata = .; + .kernel:initrd : + { + _initrd_start = .; + *(.kernel:initrd) + _initrd_end = .; + } . = ALIGN(4096); - __bss_start = .; .bss : { - *(.sbss) - *(.bss) + _edata = .; + __bss_start = .; + *(.sbss) + *(.bss) + *(COMMON) + _end = . ; } - . = ALIGN(4096); - _end = . ; } -- cgit v0.10.2 From 6c5b59b913874cae535a324a671b7ed4f17e6397 Mon Sep 17 00:00:00 2001 From: David Gibson Date: Thu, 14 Apr 2011 18:29:16 +0000 Subject: powerpc/boot: Add an ePAPR compliant boot wrapper This is a first cut at making bootwrapper code which will produce a zImage compliant with the requirements set down by ePAPR. This is a very simple bootwrapper, taking the device tree blob supplied by the ePAPR boot program and passing it on to the kernel. It builds on the earlier patch to build a relocatable ET_DYN zImage to meet the other ePAPR image requirements. For good measure we have some paranoid checks which will generate warnings if some of the ePAPR entry condition guarantees are not met. Signed-off-by: David Gibson Signed-off-by: Michael Ellerman Signed-off-by: Benjamin Herrenschmidt diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig index 8f4d50b..a3128ca 100644 --- a/arch/powerpc/Kconfig +++ b/arch/powerpc/Kconfig @@ -193,6 +193,12 @@ config SYS_SUPPORTS_APM_EMULATION default y if PMAC_APM_EMU bool +config EPAPR_BOOT + bool + help + Used to allow a board to specify it wants an ePAPR compliant wrapper. + default n + config DEFAULT_UIMAGE bool help diff --git a/arch/powerpc/boot/Makefile b/arch/powerpc/boot/Makefile index 8917816..0e2a152 100644 --- a/arch/powerpc/boot/Makefile +++ b/arch/powerpc/boot/Makefile @@ -69,7 +69,8 @@ src-wlib := string.S crt0.S crtsavres.S stdio.c main.c \ cpm-serial.c stdlib.c mpc52xx-psc.c planetcore.c uartlite.c \ fsl-soc.c mpc8xx.c pq2.c ugecon.c src-plat := of.c cuboot-52xx.c cuboot-824x.c cuboot-83xx.c cuboot-85xx.c holly.c \ - cuboot-ebony.c cuboot-hotfoot.c treeboot-ebony.c prpmc2800.c \ + cuboot-ebony.c cuboot-hotfoot.c epapr.c treeboot-ebony.c \ + prpmc2800.c \ ps3-head.S ps3-hvcall.S ps3.c treeboot-bamboo.c cuboot-8xx.c \ cuboot-pq2.c cuboot-sequoia.c treeboot-walnut.c \ cuboot-bamboo.c cuboot-mpc7448hpc2.c cuboot-taishan.c \ @@ -182,6 +183,7 @@ image-$(CONFIG_PPC_HOLLY) += dtbImage.holly image-$(CONFIG_PPC_PRPMC2800) += dtbImage.prpmc2800 image-$(CONFIG_PPC_ISERIES) += zImage.iseries image-$(CONFIG_DEFAULT_UIMAGE) += uImage +image-$(CONFIG_EPAPR_BOOT) += zImage.epapr # # Targets which embed a device tree blob diff --git a/arch/powerpc/boot/epapr.c b/arch/powerpc/boot/epapr.c new file mode 100644 index 0000000..06c1961 --- /dev/null +++ b/arch/powerpc/boot/epapr.c @@ -0,0 +1,66 @@ +/* + * Bootwrapper for ePAPR compliant firmwares + * + * Copyright 2010 David Gibson , IBM Corporation. + * + * Based on earlier bootwrappers by: + * (c) Benjamin Herrenschmidt , IBM Corp,\ + * and + * Scott Wood + * Copyright (c) 2007 Freescale Semiconductor, Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published + * by the Free Software Foundation. + */ + +#include "ops.h" +#include "stdio.h" +#include "io.h" +#include + +BSS_STACK(4096); + +#define EPAPR_SMAGIC 0x65504150 +#define EPAPR_EMAGIC 0x45504150 + +static unsigned epapr_magic; +static unsigned long ima_size; +static unsigned long fdt_addr; + +static void platform_fixups(void) +{ + if ((epapr_magic != EPAPR_EMAGIC) + && (epapr_magic != EPAPR_SMAGIC)) + fatal("r6 contained 0x%08x instead of ePAPR magic number\n", + epapr_magic); + + if (ima_size < (unsigned long)_end) + printf("WARNING: Image loaded outside IMA!" + " (_end=%p, ima_size=0x%lx)\n", _end, ima_size); + if (ima_size < fdt_addr) + printf("WARNING: Device tree address is outside IMA!" + "(fdt_addr=0x%lx, ima_size=0x%lx)\n", fdt_addr, + ima_size); + if (ima_size < fdt_addr + fdt_totalsize((void *)fdt_addr)) + printf("WARNING: Device tree extends outside IMA!" + " (fdt_addr=0x%lx, size=0x%x, ima_size=0x%lx\n", + fdt_addr, fdt_totalsize((void *)fdt_addr), ima_size); +} + +void platform_init(unsigned long r3, unsigned long r4, unsigned long r5, + unsigned long r6, unsigned long r7) +{ + epapr_magic = r6; + ima_size = r7; + fdt_addr = r3; + + /* FIXME: we should process reserve entries */ + + simple_alloc_init(_end, ima_size - (unsigned long)_end, 32, 64); + + fdt_init((void *)fdt_addr); + + serial_console_init(); + platform_ops.fixups = platform_fixups; +} diff --git a/arch/powerpc/boot/wrapper b/arch/powerpc/boot/wrapper index fef5278..dfa29cb 100755 --- a/arch/powerpc/boot/wrapper +++ b/arch/powerpc/boot/wrapper @@ -247,6 +247,10 @@ gamecube|wii) treeboot-iss4xx-mpic) platformo="$object/treeboot-iss4xx.o" ;; +epapr) + link_address='0x20000000' + pie=-pie + ;; esac vmz="$tmpdir/`basename \"$kernel\"`.$ext" -- cgit v0.10.2 From de300974761d92f71cb583730ac9e1d4eb1b7156 Mon Sep 17 00:00:00 2001 From: Michael Ellerman Date: Mon, 11 Apr 2011 21:46:19 +0000 Subject: powerpc/smp: smp_ops->kick_cpu() should be able to fail When we start a cpu we use smp_ops->kick_cpu(), which currently returns void, it should be able to fail. Convert it to return int, and update all uses. Convert all the current error cases to return -ENOENT, which is what would eventually be returned by __cpu_up() currently when it doesn't detect the cpu as coming up in time. Signed-off-by: Michael Ellerman Signed-off-by: Benjamin Herrenschmidt diff --git a/arch/powerpc/include/asm/machdep.h b/arch/powerpc/include/asm/machdep.h index 493dbb3..c6345ac 100644 --- a/arch/powerpc/include/asm/machdep.h +++ b/arch/powerpc/include/asm/machdep.h @@ -33,7 +33,7 @@ struct kimage; struct smp_ops_t { void (*message_pass)(int target, int msg); int (*probe)(void); - void (*kick_cpu)(int nr); + int (*kick_cpu)(int nr); void (*setup_cpu)(int nr); void (*bringup_done)(void); void (*take_timebase)(void); diff --git a/arch/powerpc/include/asm/smp.h b/arch/powerpc/include/asm/smp.h index bb4c033..5087349 100644 --- a/arch/powerpc/include/asm/smp.h +++ b/arch/powerpc/include/asm/smp.h @@ -150,7 +150,7 @@ extern int smt_enabled_at_boot; extern int smp_mpic_probe(void); extern void smp_mpic_setup_cpu(int cpu); -extern void smp_generic_kick_cpu(int nr); +extern int smp_generic_kick_cpu(int nr); extern void smp_generic_give_timebase(void); extern void smp_generic_take_timebase(void); diff --git a/arch/powerpc/kernel/smp.c b/arch/powerpc/kernel/smp.c index cbdbb14..b6083f4 100644 --- a/arch/powerpc/kernel/smp.c +++ b/arch/powerpc/kernel/smp.c @@ -95,7 +95,7 @@ int smt_enabled_at_boot = 1; static void (*crash_ipi_function_ptr)(struct pt_regs *) = NULL; #ifdef CONFIG_PPC64 -void __devinit smp_generic_kick_cpu(int nr) +int __devinit smp_generic_kick_cpu(int nr) { BUG_ON(nr < 0 || nr >= NR_CPUS); @@ -106,6 +106,8 @@ void __devinit smp_generic_kick_cpu(int nr) */ paca[nr].cpu_start = 1; smp_mb(); + + return 0; } #endif @@ -434,7 +436,11 @@ int __cpuinit __cpu_up(unsigned int cpu) /* wake up cpus */ DBG("smp: kicking cpu %d\n", cpu); - smp_ops->kick_cpu(cpu); + rc = smp_ops->kick_cpu(cpu); + if (rc) { + pr_err("smp: failed starting cpu %d (rc %d)\n", cpu, rc); + return rc; + } /* * wait to see if the cpu made a callin (is actually up). diff --git a/arch/powerpc/platforms/44x/iss4xx.c b/arch/powerpc/platforms/44x/iss4xx.c index aa46e9d..19395f1 100644 --- a/arch/powerpc/platforms/44x/iss4xx.c +++ b/arch/powerpc/platforms/44x/iss4xx.c @@ -87,7 +87,7 @@ static void __cpuinit smp_iss4xx_setup_cpu(int cpu) mpic_setup_this_cpu(); } -static void __cpuinit smp_iss4xx_kick_cpu(int cpu) +static int __cpuinit smp_iss4xx_kick_cpu(int cpu) { struct device_node *cpunode = of_get_cpu_node(cpu, NULL); const u64 *spin_table_addr_prop; @@ -104,7 +104,7 @@ static void __cpuinit smp_iss4xx_kick_cpu(int cpu) NULL); if (spin_table_addr_prop == NULL) { pr_err("CPU%d: Can't start, missing cpu-release-addr !\n", cpu); - return; + return -ENOENT; } /* Assume it's mapped as part of the linear mapping. This is a bit @@ -117,6 +117,8 @@ static void __cpuinit smp_iss4xx_kick_cpu(int cpu) smp_wmb(); spin_table[1] = __pa(start_secondary_47x); mb(); + + return 0; } static struct smp_ops_t iss_smp_ops = { diff --git a/arch/powerpc/platforms/85xx/smp.c b/arch/powerpc/platforms/85xx/smp.c index 0d00ff9..fe3f6a3 100644 --- a/arch/powerpc/platforms/85xx/smp.c +++ b/arch/powerpc/platforms/85xx/smp.c @@ -41,7 +41,7 @@ extern void __early_start(void); #define NUM_BOOT_ENTRY 8 #define SIZE_BOOT_ENTRY (NUM_BOOT_ENTRY * sizeof(u32)) -static void __init +static int __init smp_85xx_kick_cpu(int nr) { unsigned long flags; @@ -60,7 +60,7 @@ smp_85xx_kick_cpu(int nr) if (cpu_rel_addr == NULL) { printk(KERN_ERR "No cpu-release-addr for cpu %d\n", nr); - return; + return -ENOENT; } /* @@ -107,6 +107,8 @@ smp_85xx_kick_cpu(int nr) iounmap(bptr_vaddr); pr_debug("waited %d msecs for CPU #%d.\n", n, nr); + + return 0; } static void __init diff --git a/arch/powerpc/platforms/86xx/mpc86xx_smp.c b/arch/powerpc/platforms/86xx/mpc86xx_smp.c index eacea0e..af09bae 100644 --- a/arch/powerpc/platforms/86xx/mpc86xx_smp.c +++ b/arch/powerpc/platforms/86xx/mpc86xx_smp.c @@ -56,7 +56,7 @@ smp_86xx_release_core(int nr) } -static void __init +static int __init smp_86xx_kick_cpu(int nr) { unsigned int save_vector; @@ -65,7 +65,7 @@ smp_86xx_kick_cpu(int nr) unsigned int *vector = (unsigned int *)(KERNELBASE + 0x100); if (nr < 0 || nr >= NR_CPUS) - return; + return -ENOENT; pr_debug("smp_86xx_kick_cpu: kick CPU #%d\n", nr); @@ -92,6 +92,8 @@ smp_86xx_kick_cpu(int nr) local_irq_restore(flags); pr_debug("wait CPU #%d for %d msecs.\n", nr, n); + + return 0; } diff --git a/arch/powerpc/platforms/cell/beat_smp.c b/arch/powerpc/platforms/cell/beat_smp.c index 26efc20..996df33 100644 --- a/arch/powerpc/platforms/cell/beat_smp.c +++ b/arch/powerpc/platforms/cell/beat_smp.c @@ -93,12 +93,11 @@ static void __devinit smp_beatic_setup_cpu(int cpu) beatic_setup_cpu(cpu); } -static void __devinit smp_celleb_kick_cpu(int nr) +static int __devinit smp_celleb_kick_cpu(int nr) { BUG_ON(nr < 0 || nr >= NR_CPUS); - if (!smp_startup_cpu(nr)) - return; + return smp_startup_cpu(nr); } static int smp_celleb_cpu_bootable(unsigned int nr) diff --git a/arch/powerpc/platforms/cell/smp.c b/arch/powerpc/platforms/cell/smp.c index f774530..03d638e 100644 --- a/arch/powerpc/platforms/cell/smp.c +++ b/arch/powerpc/platforms/cell/smp.c @@ -137,12 +137,12 @@ static void __devinit smp_cell_setup_cpu(int cpu) mtspr(SPRN_DABRX, DABRX_KERNEL | DABRX_USER); } -static void __devinit smp_cell_kick_cpu(int nr) +static int __devinit smp_cell_kick_cpu(int nr) { BUG_ON(nr < 0 || nr >= NR_CPUS); if (!smp_startup_cpu(nr)) - return; + return -ENOENT; /* * The processor is currently spinning, waiting for the @@ -150,6 +150,8 @@ static void __devinit smp_cell_kick_cpu(int nr) * the processor will continue on to secondary_start */ paca[nr].cpu_start = 1; + + return 0; } static int smp_cell_cpu_bootable(unsigned int nr) diff --git a/arch/powerpc/platforms/chrp/smp.c b/arch/powerpc/platforms/chrp/smp.c index 02cafec..a800122 100644 --- a/arch/powerpc/platforms/chrp/smp.c +++ b/arch/powerpc/platforms/chrp/smp.c @@ -30,10 +30,12 @@ #include #include -static void __devinit smp_chrp_kick_cpu(int nr) +static int __devinit smp_chrp_kick_cpu(int nr) { *(unsigned long *)KERNELBASE = nr; asm volatile("dcbf 0,%0"::"r"(KERNELBASE):"memory"); + + return 0; } static void __devinit smp_chrp_setup_cpu(int cpu_nr) diff --git a/arch/powerpc/platforms/iseries/smp.c b/arch/powerpc/platforms/iseries/smp.c index 6c60299..02a677a 100644 --- a/arch/powerpc/platforms/iseries/smp.c +++ b/arch/powerpc/platforms/iseries/smp.c @@ -86,13 +86,13 @@ static int smp_iSeries_probe(void) return cpumask_weight(cpu_possible_mask); } -static void smp_iSeries_kick_cpu(int nr) +static int smp_iSeries_kick_cpu(int nr) { BUG_ON((nr < 0) || (nr >= NR_CPUS)); /* Verify that our partition has a processor nr */ if (lppaca_of(nr).dyn_proc_status >= 2) - return; + return -ENOENT; /* The processor is currently spinning, waiting * for the cpu_start field to become non-zero @@ -100,6 +100,8 @@ static void smp_iSeries_kick_cpu(int nr) * continue on to secondary_start in iSeries_head.S */ paca[nr].cpu_start = 1; + + return 0; } static void __devinit smp_iSeries_setup_cpu(int nr) diff --git a/arch/powerpc/platforms/powermac/smp.c b/arch/powerpc/platforms/powermac/smp.c index bc5f0dc..621d4b7 100644 --- a/arch/powerpc/platforms/powermac/smp.c +++ b/arch/powerpc/platforms/powermac/smp.c @@ -329,7 +329,7 @@ static int __init smp_psurge_probe(void) return ncpus; } -static void __init smp_psurge_kick_cpu(int nr) +static int __init smp_psurge_kick_cpu(int nr) { unsigned long start = __pa(__secondary_start_pmac_0) + nr * 8; unsigned long a, flags; @@ -394,6 +394,8 @@ static void __init smp_psurge_kick_cpu(int nr) psurge_set_ipi(1); if (ppc_md.progress) ppc_md.progress("smp_psurge_kick_cpu - done", 0x354); + + return 0; } static struct irqaction psurge_irqaction = { @@ -791,14 +793,14 @@ static int __init smp_core99_probe(void) return ncpus; } -static void __devinit smp_core99_kick_cpu(int nr) +static int __devinit smp_core99_kick_cpu(int nr) { unsigned int save_vector; unsigned long target, flags; unsigned int *vector = (unsigned int *)(PAGE_OFFSET+0x100); if (nr < 0 || nr > 3) - return; + return -ENOENT; if (ppc_md.progress) ppc_md.progress("smp_core99_kick_cpu", 0x346); @@ -830,6 +832,8 @@ static void __devinit smp_core99_kick_cpu(int nr) local_irq_restore(flags); if (ppc_md.progress) ppc_md.progress("smp_core99_kick_cpu done", 0x347); + + return 0; } static void __devinit smp_core99_setup_cpu(int cpu_nr) diff --git a/arch/powerpc/platforms/pseries/smp.c b/arch/powerpc/platforms/pseries/smp.c index fc72bfc..95f5781 100644 --- a/arch/powerpc/platforms/pseries/smp.c +++ b/arch/powerpc/platforms/pseries/smp.c @@ -152,12 +152,12 @@ static void __devinit smp_xics_setup_cpu(int cpu) #endif } -static void __devinit smp_pSeries_kick_cpu(int nr) +static int __devinit smp_pSeries_kick_cpu(int nr) { BUG_ON(nr < 0 || nr >= NR_CPUS); if (!smp_startup_cpu(nr)) - return; + return -ENOENT; /* * The processor is currently spinning, waiting for the @@ -179,6 +179,8 @@ static void __devinit smp_pSeries_kick_cpu(int nr) "Ret= %ld\n", nr, rc); } #endif + + return 0; } static int smp_pSeries_cpu_bootable(unsigned int nr) -- cgit v0.10.2 From f5be2dc0bd8d27a39d84a89e4ff90ba38cd2b285 Mon Sep 17 00:00:00 2001 From: Michael Ellerman Date: Mon, 4 Apr 2011 20:57:27 +0000 Subject: powerpc/nohash: Allocate stale_map[cpu] on CPU_UP_PREPARE not CPU_ONLINE Currently we allocate the stale_map for a cpu when it comes online, this leaves open a small window where a process can be scheduled on the cpu before the stale_map is allocated. Instead allocate the stale_map at CPU_UP_PREPARE time, that way it will be always available before tasks start running. It is possible the cpu fails to come up, in which case we should free the stale_map, so add a CPU_UP_CANCELED case to do that. Signed-off-by: Michael Ellerman Signed-off-by: Benjamin Herrenschmidt diff --git a/arch/powerpc/mm/mmu_context_nohash.c b/arch/powerpc/mm/mmu_context_nohash.c index c0aab52..4d8fa91 100644 --- a/arch/powerpc/mm/mmu_context_nohash.c +++ b/arch/powerpc/mm/mmu_context_nohash.c @@ -338,12 +338,14 @@ static int __cpuinit mmu_context_cpu_notify(struct notifier_block *self, return NOTIFY_OK; switch (action) { - case CPU_ONLINE: - case CPU_ONLINE_FROZEN: + case CPU_UP_PREPARE: + case CPU_UP_PREPARE_FROZEN: pr_devel("MMU: Allocating stale context map for CPU %d\n", cpu); stale_map[cpu] = kzalloc(CTX_MAP_SIZE, GFP_KERNEL); break; #ifdef CONFIG_HOTPLUG_CPU + case CPU_UP_CANCELED: + case CPU_UP_CANCELED_FROZEN: case CPU_DEAD: case CPU_DEAD_FROZEN: pr_devel("MMU: Freeing stale context map for CPU %d\n", cpu); -- cgit v0.10.2 From b68a70c49686db0bff4637995d91b4db8abe5281 Mon Sep 17 00:00:00 2001 From: Anton Blanchard Date: Mon, 4 Apr 2011 23:56:18 +0000 Subject: powerpc: Replace open coded instruction patching with patch_instruction/patch_branch There are a few places we patch instructions without using patch_instruction and patch_branch, probably because they predated it. Fix it. Signed-off-by: Anton Blanchard Signed-off-by: Benjamin Herrenschmidt diff --git a/arch/powerpc/mm/hash_utils_64.c b/arch/powerpc/mm/hash_utils_64.c index 58a022d..d95d8f4 100644 --- a/arch/powerpc/mm/hash_utils_64.c +++ b/arch/powerpc/mm/hash_utils_64.c @@ -53,6 +53,7 @@ #include #include #include +#include #ifdef DEBUG #define DBG(fmt...) udbg_printf(fmt) @@ -547,15 +548,7 @@ int remove_section_mapping(unsigned long start, unsigned long end) } #endif /* CONFIG_MEMORY_HOTPLUG */ -static inline void make_bl(unsigned int *insn_addr, void *func) -{ - unsigned long funcp = *((unsigned long *)func); - int offset = funcp - (unsigned long)insn_addr; - - *insn_addr = (unsigned int)(0x48000001 | (offset & 0x03fffffc)); - flush_icache_range((unsigned long)insn_addr, 4+ - (unsigned long)insn_addr); -} +#define FUNCTION_TEXT(A) ((*(unsigned long *)(A))) static void __init htab_finish_init(void) { @@ -570,16 +563,33 @@ static void __init htab_finish_init(void) extern unsigned int *ht64_call_hpte_remove; extern unsigned int *ht64_call_hpte_updatepp; - make_bl(ht64_call_hpte_insert1, ppc_md.hpte_insert); - make_bl(ht64_call_hpte_insert2, ppc_md.hpte_insert); - make_bl(ht64_call_hpte_remove, ppc_md.hpte_remove); - make_bl(ht64_call_hpte_updatepp, ppc_md.hpte_updatepp); + patch_branch(ht64_call_hpte_insert1, + FUNCTION_TEXT(ppc_md.hpte_insert), + BRANCH_SET_LINK); + patch_branch(ht64_call_hpte_insert2, + FUNCTION_TEXT(ppc_md.hpte_insert), + BRANCH_SET_LINK); + patch_branch(ht64_call_hpte_remove, + FUNCTION_TEXT(ppc_md.hpte_remove), + BRANCH_SET_LINK); + patch_branch(ht64_call_hpte_updatepp, + FUNCTION_TEXT(ppc_md.hpte_updatepp), + BRANCH_SET_LINK); + #endif /* CONFIG_PPC_HAS_HASH_64K */ - make_bl(htab_call_hpte_insert1, ppc_md.hpte_insert); - make_bl(htab_call_hpte_insert2, ppc_md.hpte_insert); - make_bl(htab_call_hpte_remove, ppc_md.hpte_remove); - make_bl(htab_call_hpte_updatepp, ppc_md.hpte_updatepp); + patch_branch(htab_call_hpte_insert1, + FUNCTION_TEXT(ppc_md.hpte_insert), + BRANCH_SET_LINK); + patch_branch(htab_call_hpte_insert2, + FUNCTION_TEXT(ppc_md.hpte_insert), + BRANCH_SET_LINK); + patch_branch(htab_call_hpte_remove, + FUNCTION_TEXT(ppc_md.hpte_remove), + BRANCH_SET_LINK); + patch_branch(htab_call_hpte_updatepp, + FUNCTION_TEXT(ppc_md.hpte_updatepp), + BRANCH_SET_LINK); } static void __init htab_initialize(void) diff --git a/arch/powerpc/mm/slb.c b/arch/powerpc/mm/slb.c index 1d98ecc..5500712 100644 --- a/arch/powerpc/mm/slb.c +++ b/arch/powerpc/mm/slb.c @@ -24,6 +24,7 @@ #include #include #include +#include extern void slb_allocate_realmode(unsigned long ea); @@ -249,9 +250,8 @@ void switch_slb(struct task_struct *tsk, struct mm_struct *mm) static inline void patch_slb_encoding(unsigned int *insn_addr, unsigned int immed) { - *insn_addr = (*insn_addr & 0xffff0000) | immed; - flush_icache_range((unsigned long)insn_addr, 4+ - (unsigned long)insn_addr); + int insn = (*insn_addr & 0xffff0000) | immed; + patch_instruction(insn_addr, insn); } void slb_set_size(u16 size) -- cgit v0.10.2 From 931e1241a266e701157d3478d0d44fc58d6e84b4 Mon Sep 17 00:00:00 2001 From: Benjamin Herrenschmidt Date: Thu, 14 Apr 2011 22:31:56 +0000 Subject: powerpc/a2: Add some #defines for A2 specific instructions Signed-off-by: Benjamin Herrenschmidt Signed-off-by: Michael Ellerman Signed-off-by: Benjamin Herrenschmidt diff --git a/arch/powerpc/include/asm/ppc-opcode.h b/arch/powerpc/include/asm/ppc-opcode.h index 384a96d..3e25b25 100644 --- a/arch/powerpc/include/asm/ppc-opcode.h +++ b/arch/powerpc/include/asm/ppc-opcode.h @@ -59,6 +59,14 @@ #define PPC_INST_NAP 0x4c000364 #define PPC_INST_SLEEP 0x4c0003a4 +/* A2 specific instructions */ +#define PPC_INST_ERATWE 0x7c0001a6 +#define PPC_INST_ERATRE 0x7c000166 +#define PPC_INST_ERATILX 0x7c000066 +#define PPC_INST_ERATIVAX 0x7c000666 +#define PPC_INST_ERATSX 0x7c000126 +#define PPC_INST_ERATSX_DOT 0x7c000127 + /* macros to insert fields into opcodes */ #define __PPC_RA(a) (((a) & 0x1f) << 16) #define __PPC_RB(b) (((b) & 0x1f) << 11) @@ -70,6 +78,8 @@ #define __PPC_XT(s) __PPC_XS(s) #define __PPC_T_TLB(t) (((t) & 0x3) << 21) #define __PPC_WC(w) (((w) & 0x3) << 21) +#define __PPC_WS(w) (((w) & 0x1f) << 11) + /* * Only use the larx hint bit on 64bit CPUs. e500v1/v2 based CPUs will treat a * larx with EH set as an illegal instruction. @@ -116,6 +126,21 @@ #define PPC_TLBIVAX(a,b) stringify_in_c(.long PPC_INST_TLBIVAX | \ __PPC_RA(a) | __PPC_RB(b)) +#define PPC_ERATWE(s, a, w) stringify_in_c(.long PPC_INST_ERATWE | \ + __PPC_RS(s) | __PPC_RA(a) | __PPC_WS(w)) +#define PPC_ERATRE(s, a, w) stringify_in_c(.long PPC_INST_ERATRE | \ + __PPC_RS(s) | __PPC_RA(a) | __PPC_WS(w)) +#define PPC_ERATILX(t, a, b) stringify_in_c(.long PPC_INST_ERATILX | \ + __PPC_T_TLB(t) | __PPC_RA(a) | \ + __PPC_RB(b)) +#define PPC_ERATIVAX(s, a, b) stringify_in_c(.long PPC_INST_ERATIVAX | \ + __PPC_RS(s) | __PPC_RA(a) | __PPC_RB(b)) +#define PPC_ERATSX(t, a, w) stringify_in_c(.long PPC_INST_ERATSX | \ + __PPC_RS(t) | __PPC_RA(a) | __PPC_RB(b)) +#define PPC_ERATSX_DOT(t, a, w) stringify_in_c(.long PPC_INST_ERATSX_DOT | \ + __PPC_RS(t) | __PPC_RA(a) | __PPC_RB(b)) + + /* * Define what the VSX XX1 form instructions will look like, then add * the 128 bit load store instructions based on that. -- cgit v0.10.2 From 0b2e9a8e10ad2d191e5c37e77f1ce23e148e7a0b Mon Sep 17 00:00:00 2001 From: Michael Ellerman Date: Thu, 14 Apr 2011 22:31:57 +0000 Subject: of: Export of_irq_find_parent() We have platform code that needs to find a node's interrupt parent, so export of_irq_find_parent() so we can use it. Signed-off-by: Michael Ellerman Signed-off-by: Benjamin Herrenschmidt diff --git a/drivers/of/irq.c b/drivers/of/irq.c index 75b0d3c..9f689f1d 100644 --- a/drivers/of/irq.c +++ b/drivers/of/irq.c @@ -56,7 +56,7 @@ EXPORT_SYMBOL_GPL(irq_of_parse_and_map); * Returns a pointer to the interrupt parent node, or NULL if the interrupt * parent could not be determined. */ -static struct device_node *of_irq_find_parent(struct device_node *child) +struct device_node *of_irq_find_parent(struct device_node *child) { struct device_node *p; const __be32 *parp; diff --git a/include/linux/of_irq.h b/include/linux/of_irq.h index 109e013..e6955f5 100644 --- a/include/linux/of_irq.h +++ b/include/linux/of_irq.h @@ -68,6 +68,7 @@ extern int of_irq_to_resource(struct device_node *dev, int index, extern int of_irq_count(struct device_node *dev); extern int of_irq_to_resource_table(struct device_node *dev, struct resource *res, int nr_irqs); +extern struct device_node *of_irq_find_parent(struct device_node *child); #endif /* CONFIG_OF_IRQ */ #endif /* CONFIG_OF */ -- cgit v0.10.2 From cd852579055bd8ad848415aaabb78b65d522fce0 Mon Sep 17 00:00:00 2001 From: Michael Ellerman Date: Thu, 14 Apr 2011 22:31:58 +0000 Subject: powerpc/xics: xics.h relies on linux/interrupt.h Signed-off-by: Michael Ellerman Signed-off-by: Benjamin Herrenschmidt diff --git a/arch/powerpc/include/asm/xics.h b/arch/powerpc/include/asm/xics.h index 146aad8..c4ed4c5 100644 --- a/arch/powerpc/include/asm/xics.h +++ b/arch/powerpc/include/asm/xics.h @@ -6,6 +6,8 @@ #ifndef _XICS_H #define _XICS_H +#include + #define XICS_IPI 2 #define XICS_IRQ_SPURIOUS 0 -- cgit v0.10.2 From ab814b938d1d372bd2ac6268c15d4e0e6a5245c4 Mon Sep 17 00:00:00 2001 From: Benjamin Herrenschmidt Date: Thu, 14 Apr 2011 22:31:58 +0000 Subject: powerpc: Add SCOM infrastructure SCOM is a side-band configuration bus implemented on some processors. This code provides a way for code to map and operate on devices via SCOM, while the details of how that is implemented is left up to a SCOM "controller" in the platform code. Signed-off-by: Benjamin Herrenschmidt Signed-off-by: Michael Ellerman Signed-off-by: Benjamin Herrenschmidt diff --git a/arch/powerpc/include/asm/scom.h b/arch/powerpc/include/asm/scom.h new file mode 100644 index 0000000..0cabfd7 --- /dev/null +++ b/arch/powerpc/include/asm/scom.h @@ -0,0 +1,156 @@ +/* + * Copyright 2010 Benjamin Herrenschmidt, IBM Corp + * + * and David Gibson, IBM Corporation. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + * the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef _ASM_POWERPC_SCOM_H +#define _ASM_POWERPC_SCOM_H + +#ifdef __KERNEL__ +#ifndef __ASSEMBLY__ +#ifdef CONFIG_PPC_SCOM + +/* + * The SCOM bus is a sideband bus used for accessing various internal + * registers of the processor or the chipset. The implementation details + * differ between processors and platforms, and the access method as + * well. + * + * This API allows to "map" ranges of SCOM register numbers associated + * with a given SCOM controller. The later must be represented by a + * device node, though some implementations might support NULL if there + * is no possible ambiguity + * + * Then, scom_read/scom_write can be used to accesses registers inside + * that range. The argument passed is a register number relative to + * the beginning of the range mapped. + */ + +typedef void *scom_map_t; + +/* Value for an invalid SCOM map */ +#define SCOM_MAP_INVALID (NULL) + +/* The scom_controller data structure is what the platform passes + * to the core code in scom_init, it provides the actual implementation + * of all the SCOM functions + */ +struct scom_controller { + scom_map_t (*map)(struct device_node *ctrl_dev, u64 reg, u64 count); + void (*unmap)(scom_map_t map); + + u64 (*read)(scom_map_t map, u32 reg); + void (*write)(scom_map_t map, u32 reg, u64 value); +}; + +extern const struct scom_controller *scom_controller; + +/** + * scom_init - Initialize the SCOM backend, called by the platform + * @controller: The platform SCOM controller + */ +static inline void scom_init(const struct scom_controller *controller) +{ + scom_controller = controller; +} + +/** + * scom_map_ok - Test is a SCOM mapping is successful + * @map: The result of scom_map to test + */ +static inline int scom_map_ok(scom_map_t map) +{ + return map != SCOM_MAP_INVALID; +} + +/** + * scom_map - Map a block of SCOM registers + * @ctrl_dev: Device node of the SCOM controller + * some implementations allow NULL here + * @reg: first SCOM register to map + * @count: Number of SCOM registers to map + */ + +static inline scom_map_t scom_map(struct device_node *ctrl_dev, + u64 reg, u64 count) +{ + return scom_controller->map(ctrl_dev, reg, count); +} + +/** + * scom_find_parent - Find the SCOM controller for a device + * @dev: OF node of the device + * + * This is not meant for general usage, but in combination with + * scom_map() allows to map registers not represented by the + * device own scom-reg property. Useful for applying HW workarounds + * on things not properly represented in the device-tree for example. + */ +struct device_node *scom_find_parent(struct device_node *dev); + + +/** + * scom_map_device - Map a device's block of SCOM registers + * @dev: OF node of the device + * @index: Register bank index (index in "scom-reg" property) + * + * This function will use the device-tree binding for SCOM which + * is to follow "scom-parent" properties until it finds a node with + * a "scom-controller" property to find the controller. It will then + * use the "scom-reg" property which is made of reg/count pairs, + * each of them having a size defined by the controller's #scom-cells + * property + */ +extern scom_map_t scom_map_device(struct device_node *dev, int index); + + +/** + * scom_unmap - Unmap a block of SCOM registers + * @map: Result of scom_map is to be unmapped + */ +static inline void scom_unmap(scom_map_t map) +{ + if (scom_map_ok(map)) + scom_controller->unmap(map); +} + +/** + * scom_read - Read a SCOM register + * @map: Result of scom_map + * @reg: Register index within that map + */ +static inline u64 scom_read(scom_map_t map, u32 reg) +{ + return scom_controller->read(map, reg); +} + +/** + * scom_write - Write to a SCOM register + * @map: Result of scom_map + * @reg: Register index within that map + * @value: Value to write + */ +static inline void scom_write(scom_map_t map, u32 reg, u64 value) +{ + scom_controller->write(map, reg, value); +} + +#endif /* CONFIG_PPC_SCOM */ +#endif /* __ASSEMBLY__ */ +#endif /* __KERNEL__ */ +#endif /* _ASM_POWERPC_SCOM_H */ diff --git a/arch/powerpc/sysdev/Kconfig b/arch/powerpc/sysdev/Kconfig index cfc1877..d775fd1 100644 --- a/arch/powerpc/sysdev/Kconfig +++ b/arch/powerpc/sysdev/Kconfig @@ -15,3 +15,10 @@ config PPC_MSI_BITMAP source "arch/powerpc/sysdev/xics/Kconfig" +config PPC_SCOM + bool + +config SCOM_DEBUGFS + bool "Expose SCOM controllers via debugfs" + depends on PPC_SCOM + default n diff --git a/arch/powerpc/sysdev/Makefile b/arch/powerpc/sysdev/Makefile index 9516e75..6076e00 100644 --- a/arch/powerpc/sysdev/Makefile +++ b/arch/powerpc/sysdev/Makefile @@ -58,6 +58,8 @@ ifeq ($(CONFIG_SUSPEND),y) obj-$(CONFIG_6xx) += 6xx-suspend.o endif +obj-$(CONFIG_PPC_SCOM) += scom.o + subdir-ccflags-$(CONFIG_PPC_WERROR) := -Werror obj-$(CONFIG_PPC_XICS) += xics/ diff --git a/arch/powerpc/sysdev/scom.c b/arch/powerpc/sysdev/scom.c new file mode 100644 index 0000000..b2593ce --- /dev/null +++ b/arch/powerpc/sysdev/scom.c @@ -0,0 +1,192 @@ +/* + * Copyright 2010 Benjamin Herrenschmidt, IBM Corp + * + * and David Gibson, IBM Corporation. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + * the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include +#include +#include +#include + +const struct scom_controller *scom_controller; +EXPORT_SYMBOL_GPL(scom_controller); + +struct device_node *scom_find_parent(struct device_node *node) +{ + struct device_node *par, *tmp; + const u32 *p; + + for (par = of_node_get(node); par;) { + if (of_get_property(par, "scom-controller", NULL)) + break; + p = of_get_property(par, "scom-parent", NULL); + tmp = par; + if (p == NULL) + par = of_get_parent(par); + else + par = of_find_node_by_phandle(*p); + of_node_put(tmp); + } + return par; +} +EXPORT_SYMBOL_GPL(scom_find_parent); + +scom_map_t scom_map_device(struct device_node *dev, int index) +{ + struct device_node *parent; + unsigned int cells, size; + const u32 *prop; + u64 reg, cnt; + scom_map_t ret; + + parent = scom_find_parent(dev); + + if (parent == NULL) + return 0; + + prop = of_get_property(parent, "#scom-cells", NULL); + cells = prop ? *prop : 1; + + prop = of_get_property(dev, "scom-reg", &size); + if (!prop) + return 0; + size >>= 2; + + if (index >= (size / (2*cells))) + return 0; + + reg = of_read_number(&prop[index * cells * 2], cells); + cnt = of_read_number(&prop[index * cells * 2 + cells], cells); + + ret = scom_map(parent, reg, cnt); + of_node_put(parent); + + return ret; +} +EXPORT_SYMBOL_GPL(scom_map_device); + +#ifdef CONFIG_SCOM_DEBUGFS +struct scom_debug_entry { + struct device_node *dn; + unsigned long addr; + scom_map_t map; + spinlock_t lock; + char name[8]; + struct debugfs_blob_wrapper blob; +}; + +static int scom_addr_set(void *data, u64 val) +{ + struct scom_debug_entry *ent = data; + + ent->addr = 0; + scom_unmap(ent->map); + + ent->map = scom_map(ent->dn, val, 1); + if (scom_map_ok(ent->map)) + ent->addr = val; + else + return -EFAULT; + + return 0; +} + +static int scom_addr_get(void *data, u64 *val) +{ + struct scom_debug_entry *ent = data; + *val = ent->addr; + return 0; +} +DEFINE_SIMPLE_ATTRIBUTE(scom_addr_fops, scom_addr_get, scom_addr_set, + "0x%llx\n"); + +static int scom_val_set(void *data, u64 val) +{ + struct scom_debug_entry *ent = data; + + if (!scom_map_ok(ent->map)) + return -EFAULT; + + scom_write(ent->map, 0, val); + + return 0; +} + +static int scom_val_get(void *data, u64 *val) +{ + struct scom_debug_entry *ent = data; + + if (!scom_map_ok(ent->map)) + return -EFAULT; + + *val = scom_read(ent->map, 0); + return 0; +} +DEFINE_SIMPLE_ATTRIBUTE(scom_val_fops, scom_val_get, scom_val_set, + "0x%llx\n"); + +static int scom_debug_init_one(struct dentry *root, struct device_node *dn, + int i) +{ + struct scom_debug_entry *ent; + struct dentry *dir; + + ent = kzalloc(sizeof(*ent), GFP_KERNEL); + if (!ent) + return -ENOMEM; + + ent->dn = of_node_get(dn); + ent->map = SCOM_MAP_INVALID; + spin_lock_init(&ent->lock); + snprintf(ent->name, 8, "scom%d", i); + ent->blob.data = dn->full_name; + ent->blob.size = strlen(dn->full_name); + + dir = debugfs_create_dir(ent->name, root); + if (!dir) { + of_node_put(dn); + kfree(ent); + return -1; + } + + debugfs_create_file("addr", 0600, dir, ent, &scom_addr_fops); + debugfs_create_file("value", 0600, dir, ent, &scom_val_fops); + debugfs_create_blob("path", 0400, dir, &ent->blob); + + return 0; +} + +static int scom_debug_init(void) +{ + struct device_node *dn; + struct dentry *root; + int i, rc; + + root = debugfs_create_dir("scom", powerpc_debugfs_root); + if (!root) + return -1; + + i = rc = 0; + for_each_node_with_property(dn, "scom-controller") + rc |= scom_debug_init_one(root, dn, i++); + + return rc; +} +device_initcall(scom_debug_init); +#endif /* CONFIG_SCOM_DEBUGFS */ -- cgit v0.10.2 From 5ca123760177ed16cbd9bab609bff69eb8fc45bd Mon Sep 17 00:00:00 2001 From: Michael Ellerman Date: Thu, 14 Apr 2011 22:31:59 +0000 Subject: powerpc/xics: Move irq_host matching into the ics backend An upcoming new ics backend will need to implement different matching semantics to the current ones, which are essentially the RTAS ics backends. So move the current match into the RTAS backend, and allow other ics backends to override. Signed-off-by: Michael Ellerman Signed-off-by: Benjamin Herrenschmidt diff --git a/arch/powerpc/include/asm/xics.h b/arch/powerpc/include/asm/xics.h index c4ed4c5..6c06306 100644 --- a/arch/powerpc/include/asm/xics.h +++ b/arch/powerpc/include/asm/xics.h @@ -59,6 +59,7 @@ struct ics { int (*map)(struct ics *ics, unsigned int virq); void (*mask_unknown)(struct ics *ics, unsigned long vec); long (*get_server)(struct ics *ics, unsigned long vec); + int (*host_match)(struct ics *ics, struct device_node *node); char data[]; }; diff --git a/arch/powerpc/sysdev/xics/ics-rtas.c b/arch/powerpc/sysdev/xics/ics-rtas.c index 5b3ee38..610c148 100644 --- a/arch/powerpc/sysdev/xics/ics-rtas.c +++ b/arch/powerpc/sysdev/xics/ics-rtas.c @@ -26,12 +26,14 @@ static int ibm_int_off; static int ics_rtas_map(struct ics *ics, unsigned int virq); static void ics_rtas_mask_unknown(struct ics *ics, unsigned long vec); static long ics_rtas_get_server(struct ics *ics, unsigned long vec); +static int ics_rtas_host_match(struct ics *ics, struct device_node *node); /* Only one global & state struct ics */ static struct ics ics_rtas = { .map = ics_rtas_map, .mask_unknown = ics_rtas_mask_unknown, .get_server = ics_rtas_get_server, + .host_match = ics_rtas_host_match, }; static void ics_rtas_unmask_irq(struct irq_data *d) @@ -202,6 +204,15 @@ static long ics_rtas_get_server(struct ics *ics, unsigned long vec) return status[0]; } +static int ics_rtas_host_match(struct ics *ics, struct device_node *node) +{ + /* IBM machines have interrupt parents of various funky types for things + * like vdevices, events, etc... The trick we use here is to match + * everything here except the legacy 8259 which is compatible "chrp,iic" + */ + return !of_device_is_compatible(node, "chrp,iic"); +} + int ics_rtas_init(void) { ibm_get_xive = rtas_token("ibm,get-xive"); diff --git a/arch/powerpc/sysdev/xics/xics-common.c b/arch/powerpc/sysdev/xics/xics-common.c index e70175d..c58844d 100644 --- a/arch/powerpc/sysdev/xics/xics-common.c +++ b/arch/powerpc/sysdev/xics/xics-common.c @@ -331,11 +331,13 @@ int xics_get_irq_server(unsigned int virq, const struct cpumask *cpumask, static int xics_host_match(struct irq_host *h, struct device_node *node) { - /* IBM machines have interrupt parents of various funky types for things - * like vdevices, events, etc... The trick we use here is to match - * everything here except the legacy 8259 which is compatible "chrp,iic" - */ - return !of_device_is_compatible(node, "chrp,iic"); + struct ics *ics; + + list_for_each_entry(ics, &ics_list, link) + if (ics->host_match(ics, node)) + return 1; + + return 0; } /* Dummies */ -- cgit v0.10.2 From 411e689d929d5fc2e9066e30de55e8bcdbd573ad Mon Sep 17 00:00:00 2001 From: Benjamin Herrenschmidt Date: Thu, 14 Apr 2011 22:32:00 +0000 Subject: powerpc/nvram: Search for nvram using compatible As well as searching for nodes with type = "nvram", search for nodes that have compatible = "nvram". This can't be converted into a single call to of_find_compatible_node() with a non-NULL type, because that searches for a node that has _both_ type & compatible = "nvram". Signed-off-by: Benjamin Herrenschmidt Signed-off-by: Michael Ellerman Signed-off-by: Benjamin Herrenschmidt diff --git a/arch/powerpc/sysdev/mmio_nvram.c b/arch/powerpc/sysdev/mmio_nvram.c index 2073242..ddc877a 100644 --- a/arch/powerpc/sysdev/mmio_nvram.c +++ b/arch/powerpc/sysdev/mmio_nvram.c @@ -115,6 +115,8 @@ int __init mmio_nvram_init(void) int ret; nvram_node = of_find_node_by_type(NULL, "nvram"); + if (!nvram_node) + nvram_node = of_find_compatible_node(NULL, NULL, "nvram"); if (!nvram_node) { printk(KERN_WARNING "nvram: no node found in device-tree\n"); return -ENODEV; -- cgit v0.10.2 From 95c8e17f2f00f6af7474fac0e4050a79db6c3cea Mon Sep 17 00:00:00 2001 From: Bob Peterson Date: Tue, 22 Mar 2011 10:49:12 -0400 Subject: GFS2: Dump better debug info if a bitmap inconsistency is detected On rare occasions we encounter gfs2 problems where an invalid bitmap state transition is attempted. For example, trying to "unlink" a free block. In these cases, there is really no useful information logged to debug the problem. This patch adds more debug details that should allow us to more closely examine the problem and possibly solve it. Signed-off-by: Bob Peterson Signed-off-by: Steven Whitehouse diff --git a/fs/gfs2/rgrp.c b/fs/gfs2/rgrp.c index 6fcae84..b643c14 100644 --- a/fs/gfs2/rgrp.c +++ b/fs/gfs2/rgrp.c @@ -78,10 +78,11 @@ static u32 rgblk_search(struct gfs2_rgrpd *rgd, u32 goal, static inline void gfs2_setbit(struct gfs2_rgrpd *rgd, unsigned char *buf1, unsigned char *buf2, unsigned int offset, - unsigned int buflen, u32 block, + struct gfs2_bitmap *bi, u32 block, unsigned char new_state) { unsigned char *byte1, *byte2, *end, cur_state; + unsigned int buflen = bi->bi_len; const unsigned int bit = (block % GFS2_NBBY) * GFS2_BIT_SIZE; byte1 = buf1 + offset + (block / GFS2_NBBY); @@ -92,6 +93,16 @@ static inline void gfs2_setbit(struct gfs2_rgrpd *rgd, unsigned char *buf1, cur_state = (*byte1 >> bit) & GFS2_BIT_MASK; if (unlikely(!valid_change[new_state * 4 + cur_state])) { + printk(KERN_WARNING "GFS2: buf_blk = 0x%llx old_state=%d, " + "new_state=%d\n", + (unsigned long long)block, cur_state, new_state); + printk(KERN_WARNING "GFS2: rgrp=0x%llx bi_start=0x%lx\n", + (unsigned long long)rgd->rd_addr, + (unsigned long)bi->bi_start); + printk(KERN_WARNING "GFS2: bi_offset=0x%lx bi_len=0x%lx\n", + (unsigned long)bi->bi_offset, + (unsigned long)bi->bi_len); + dump_stack(); gfs2_consist_rgrpd(rgd); return; } @@ -1365,7 +1376,7 @@ skip: gfs2_trans_add_bh(rgd->rd_gl, bi->bi_bh, 1); gfs2_setbit(rgd, bi->bi_bh->b_data, bi->bi_clone, bi->bi_offset, - bi->bi_len, blk, new_state); + bi, blk, new_state); goal = blk; while (*n < elen) { goal++; @@ -1375,7 +1386,7 @@ skip: GFS2_BLKST_FREE) break; gfs2_setbit(rgd, bi->bi_bh->b_data, bi->bi_clone, bi->bi_offset, - bi->bi_len, goal, new_state); + bi, goal, new_state); (*n)++; } out: @@ -1432,7 +1443,7 @@ static struct gfs2_rgrpd *rgblk_free(struct gfs2_sbd *sdp, u64 bstart, } gfs2_trans_add_bh(rgd->rd_gl, bi->bi_bh, 1); gfs2_setbit(rgd, bi->bi_bh->b_data, NULL, bi->bi_offset, - bi->bi_len, buf_blk, new_state); + bi, buf_blk, new_state); } return rgd; -- cgit v0.10.2 From 0d95326d9bd39f6eae80b91392b308c5fa8b1a0f Mon Sep 17 00:00:00 2001 From: Bob Peterson Date: Tue, 22 Mar 2011 13:52:44 -0400 Subject: GFS2: remove *leaf_call_t and simplify leaf_dealloc Since foreach_leaf is only called with leaf_dealloc as its only possible call function, we can simplify the code by making it call leaf_dealloc directly. This simplifies the code and eliminates the need for leaf_call_t, the generic call method. This is a first small step in simplifying the directory leaf deallocation code. Signed-off-by: Bob Peterson Signed-off-by: Steven Whitehouse diff --git a/fs/gfs2/dir.c b/fs/gfs2/dir.c index f789c57..0bb5f6b 100644 --- a/fs/gfs2/dir.c +++ b/fs/gfs2/dir.c @@ -82,11 +82,11 @@ struct qstr gfs2_qdot __read_mostly; struct qstr gfs2_qdotdot __read_mostly; -typedef int (*leaf_call_t) (struct gfs2_inode *dip, u32 index, u32 len, - u64 leaf_no, void *data); typedef int (*gfs2_dscan_t)(const struct gfs2_dirent *dent, const struct qstr *name, void *opaque); +static int leaf_dealloc(struct gfs2_inode *dip, u32 index, u32 len, + u64 leaf_no); int gfs2_dir_get_new_buffer(struct gfs2_inode *ip, u64 block, struct buffer_head **bhp) @@ -1770,13 +1770,11 @@ int gfs2_dir_mvino(struct gfs2_inode *dip, const struct qstr *filename, /** * foreach_leaf - call a function for each leaf in a directory * @dip: the directory - * @lc: the function to call for each each - * @data: private data to pass to it * * Returns: errno */ -static int foreach_leaf(struct gfs2_inode *dip, leaf_call_t lc, void *data) +static int foreach_leaf(struct gfs2_inode *dip) { struct gfs2_sbd *sdp = GFS2_SB(&dip->i_inode); struct buffer_head *bh; @@ -1823,7 +1821,7 @@ static int foreach_leaf(struct gfs2_inode *dip, leaf_call_t lc, void *data) len = 1 << (dip->i_depth - be16_to_cpu(leaf->lf_depth)); brelse(bh); - error = lc(dip, index, len, leaf_no, data); + error = leaf_dealloc(dip, index, len, leaf_no); if (error) goto out; @@ -1855,7 +1853,7 @@ out: */ static int leaf_dealloc(struct gfs2_inode *dip, u32 index, u32 len, - u64 leaf_no, void *data) + u64 leaf_no) { struct gfs2_sbd *sdp = GFS2_SB(&dip->i_inode); struct gfs2_leaf *tmp_leaf; @@ -1978,7 +1976,7 @@ int gfs2_dir_exhash_dealloc(struct gfs2_inode *dip) int error; /* Dealloc on-disk leaves to FREEMETA state */ - error = foreach_leaf(dip, leaf_dealloc, NULL); + error = foreach_leaf(dip); if (error) return error; -- cgit v0.10.2 From d24a7a439a329b60f8e168c03e80566519e09be2 Mon Sep 17 00:00:00 2001 From: Bob Peterson Date: Tue, 22 Mar 2011 13:54:03 -0400 Subject: GFS2: Combine transaction from gfs2_dir_exhash_dealloc At the end of function gfs2_dir_exhash_dealloc, it was setting the dinode type to "file" to prevent directory corruption in case of a crash. It was doing so in its own journal transaction. This patch makes the change occur when the last call is make to leaf_dealloc, since it needs to rewrite the directory dinode at that time anyway. Signed-off-by: Bob Peterson Signed-off-by: Steven Whitehouse diff --git a/fs/gfs2/dir.c b/fs/gfs2/dir.c index 0bb5f6b..bd57587 100644 --- a/fs/gfs2/dir.c +++ b/fs/gfs2/dir.c @@ -86,7 +86,7 @@ typedef int (*gfs2_dscan_t)(const struct gfs2_dirent *dent, const struct qstr *name, void *opaque); static int leaf_dealloc(struct gfs2_inode *dip, u32 index, u32 len, - u64 leaf_no); + u64 leaf_no, int last_dealloc); int gfs2_dir_get_new_buffer(struct gfs2_inode *ip, u64 block, struct buffer_head **bhp) @@ -1781,10 +1781,10 @@ static int foreach_leaf(struct gfs2_inode *dip) struct gfs2_leaf *leaf; u32 hsize, len; u32 ht_offset, lp_offset, ht_offset_cur = -1; - u32 index = 0; + u32 index = 0, next_index; __be64 *lp; u64 leaf_no; - int error = 0; + int error = 0, last; hsize = 1 << dip->i_depth; if (hsize * sizeof(u64) != i_size_read(&dip->i_inode)) { @@ -1819,13 +1819,13 @@ static int foreach_leaf(struct gfs2_inode *dip) goto out; leaf = (struct gfs2_leaf *)bh->b_data; len = 1 << (dip->i_depth - be16_to_cpu(leaf->lf_depth)); + next_index = (index & ~(len - 1)) + len; + last = ((next_index >= hsize) ? 1 : 0); brelse(bh); - - error = leaf_dealloc(dip, index, len, leaf_no); + error = leaf_dealloc(dip, index, len, leaf_no, last); if (error) goto out; - - index = (index & ~(len - 1)) + len; + index = next_index; } else index++; } @@ -1847,13 +1847,13 @@ out: * @index: the hash table offset in the directory * @len: the number of pointers to this leaf * @leaf_no: the leaf number - * @data: not used + * last_dealloc: 1 if this is the final dealloc for the leaf, else 0 * * Returns: errno */ static int leaf_dealloc(struct gfs2_inode *dip, u32 index, u32 len, - u64 leaf_no) + u64 leaf_no, int last_dealloc) { struct gfs2_sbd *sdp = GFS2_SB(&dip->i_inode); struct gfs2_leaf *tmp_leaf; @@ -1940,6 +1940,10 @@ static int leaf_dealloc(struct gfs2_inode *dip, u32 index, u32 len, goto out_end_trans; gfs2_trans_add_bh(dip->i_gl, dibh, 1); + /* On the last dealloc, make this a regular file in case we crash. + (We don't want to free these blocks a second time.) */ + if (last_dealloc) + dip->i_inode.i_mode = S_IFREG; gfs2_dinode_out(dip, dibh->b_data); brelse(dibh); @@ -1971,33 +1975,8 @@ out: int gfs2_dir_exhash_dealloc(struct gfs2_inode *dip) { - struct gfs2_sbd *sdp = GFS2_SB(&dip->i_inode); - struct buffer_head *bh; - int error; - /* Dealloc on-disk leaves to FREEMETA state */ - error = foreach_leaf(dip); - if (error) - return error; - - /* Make this a regular file in case we crash. - (We don't want to free these blocks a second time.) */ - - error = gfs2_trans_begin(sdp, RES_DINODE, 0); - if (error) - return error; - - error = gfs2_meta_inode_buffer(dip, &bh); - if (!error) { - gfs2_trans_add_bh(dip->i_gl, bh, 1); - ((struct gfs2_dinode *)bh->b_data)->di_mode = - cpu_to_be32(S_IFREG); - brelse(bh); - } - - gfs2_trans_end(sdp); - - return error; + return foreach_leaf(dip); } /** -- cgit v0.10.2 From ec038c826b5c3c163ad1673390f10e869020c28c Mon Sep 17 00:00:00 2001 From: Bob Peterson Date: Tue, 22 Mar 2011 13:55:23 -0400 Subject: GFS2: pass leaf_bh into leaf_dealloc Function foreach_leaf used to look up the leaf block address and get a buffer_head. Then it would call leaf_dealloc which did the same lookup. This patch combines the two operations by making foreach_leaf pass the leaf bh to leaf_dealloc. Signed-off-by: Bob Peterson Signed-off-by: Steven Whitehouse diff --git a/fs/gfs2/dir.c b/fs/gfs2/dir.c index bd57587..1f5a7ac 100644 --- a/fs/gfs2/dir.c +++ b/fs/gfs2/dir.c @@ -86,7 +86,8 @@ typedef int (*gfs2_dscan_t)(const struct gfs2_dirent *dent, const struct qstr *name, void *opaque); static int leaf_dealloc(struct gfs2_inode *dip, u32 index, u32 len, - u64 leaf_no, int last_dealloc); + u64 leaf_no, struct buffer_head *leaf_bh, + int last_dealloc); int gfs2_dir_get_new_buffer(struct gfs2_inode *ip, u64 block, struct buffer_head **bhp) @@ -1821,8 +1822,9 @@ static int foreach_leaf(struct gfs2_inode *dip) len = 1 << (dip->i_depth - be16_to_cpu(leaf->lf_depth)); next_index = (index & ~(len - 1)) + len; last = ((next_index >= hsize) ? 1 : 0); + error = leaf_dealloc(dip, index, len, leaf_no, bh, + last); brelse(bh); - error = leaf_dealloc(dip, index, len, leaf_no, last); if (error) goto out; index = next_index; @@ -1847,13 +1849,15 @@ out: * @index: the hash table offset in the directory * @len: the number of pointers to this leaf * @leaf_no: the leaf number + * @leaf_bh: buffer_head for the starting leaf * last_dealloc: 1 if this is the final dealloc for the leaf, else 0 * * Returns: errno */ static int leaf_dealloc(struct gfs2_inode *dip, u32 index, u32 len, - u64 leaf_no, int last_dealloc) + u64 leaf_no, struct buffer_head *leaf_bh, + int last_dealloc) { struct gfs2_sbd *sdp = GFS2_SB(&dip->i_inode); struct gfs2_leaf *tmp_leaf; @@ -1885,14 +1889,18 @@ static int leaf_dealloc(struct gfs2_inode *dip, u32 index, u32 len, goto out_qs; /* Count the number of leaves */ + bh = leaf_bh; for (blk = leaf_no; blk; blk = nblk) { - error = get_leaf(dip, blk, &bh); - if (error) - goto out_rlist; + if (blk != leaf_no) { + error = get_leaf(dip, blk, &bh); + if (error) + goto out_rlist; + } tmp_leaf = (struct gfs2_leaf *)bh->b_data; nblk = be64_to_cpu(tmp_leaf->lf_next); - brelse(bh); + if (blk != leaf_no) + brelse(bh); gfs2_rlist_add(sdp, &rlist, blk); l_blocks++; @@ -1916,13 +1924,18 @@ static int leaf_dealloc(struct gfs2_inode *dip, u32 index, u32 len, if (error) goto out_rg_gunlock; + bh = leaf_bh; + for (blk = leaf_no; blk; blk = nblk) { - error = get_leaf(dip, blk, &bh); - if (error) - goto out_end_trans; + if (blk != leaf_no) { + error = get_leaf(dip, blk, &bh); + if (error) + goto out_end_trans; + } tmp_leaf = (struct gfs2_leaf *)bh->b_data; nblk = be64_to_cpu(tmp_leaf->lf_next); - brelse(bh); + if (blk != leaf_no) + brelse(bh); gfs2_free_meta(dip, blk, 1); gfs2_add_inode_blocks(&dip->i_inode, -1); -- cgit v0.10.2 From 556bb17998a37dabf7e9e96aa545bcea899be745 Mon Sep 17 00:00:00 2001 From: Bob Peterson Date: Tue, 22 Mar 2011 13:56:37 -0400 Subject: GFS2: move function foreach_leaf to gfs2_dir_exhash_dealloc The previous patches made function gfs2_dir_exhash_dealloc do nothing but call function foreach_leaf. This patch simplifies the code by moving the entire function foreach_leaf into gfs2_dir_exhash_dealloc. Signed-off-by: Bob Peterson Signed-off-by: Steven Whitehouse diff --git a/fs/gfs2/dir.c b/fs/gfs2/dir.c index 1f5a7ac..f7a3137 100644 --- a/fs/gfs2/dir.c +++ b/fs/gfs2/dir.c @@ -85,10 +85,6 @@ struct qstr gfs2_qdotdot __read_mostly; typedef int (*gfs2_dscan_t)(const struct gfs2_dirent *dent, const struct qstr *name, void *opaque); -static int leaf_dealloc(struct gfs2_inode *dip, u32 index, u32 len, - u64 leaf_no, struct buffer_head *leaf_bh, - int last_dealloc); - int gfs2_dir_get_new_buffer(struct gfs2_inode *ip, u64 block, struct buffer_head **bhp) { @@ -1769,81 +1765,6 @@ int gfs2_dir_mvino(struct gfs2_inode *dip, const struct qstr *filename, } /** - * foreach_leaf - call a function for each leaf in a directory - * @dip: the directory - * - * Returns: errno - */ - -static int foreach_leaf(struct gfs2_inode *dip) -{ - struct gfs2_sbd *sdp = GFS2_SB(&dip->i_inode); - struct buffer_head *bh; - struct gfs2_leaf *leaf; - u32 hsize, len; - u32 ht_offset, lp_offset, ht_offset_cur = -1; - u32 index = 0, next_index; - __be64 *lp; - u64 leaf_no; - int error = 0, last; - - hsize = 1 << dip->i_depth; - if (hsize * sizeof(u64) != i_size_read(&dip->i_inode)) { - gfs2_consist_inode(dip); - return -EIO; - } - - lp = kmalloc(sdp->sd_hash_bsize, GFP_NOFS); - if (!lp) - return -ENOMEM; - - while (index < hsize) { - lp_offset = index & (sdp->sd_hash_ptrs - 1); - ht_offset = index - lp_offset; - - if (ht_offset_cur != ht_offset) { - error = gfs2_dir_read_data(dip, (char *)lp, - ht_offset * sizeof(__be64), - sdp->sd_hash_bsize, 1); - if (error != sdp->sd_hash_bsize) { - if (error >= 0) - error = -EIO; - goto out; - } - ht_offset_cur = ht_offset; - } - - leaf_no = be64_to_cpu(lp[lp_offset]); - if (leaf_no) { - error = get_leaf(dip, leaf_no, &bh); - if (error) - goto out; - leaf = (struct gfs2_leaf *)bh->b_data; - len = 1 << (dip->i_depth - be16_to_cpu(leaf->lf_depth)); - next_index = (index & ~(len - 1)) + len; - last = ((next_index >= hsize) ? 1 : 0); - error = leaf_dealloc(dip, index, len, leaf_no, bh, - last); - brelse(bh); - if (error) - goto out; - index = next_index; - } else - index++; - } - - if (index != hsize) { - gfs2_consist_inode(dip); - error = -EIO; - } - -out: - kfree(lp); - - return error; -} - -/** * leaf_dealloc - Deallocate a directory leaf * @dip: the directory * @index: the hash table offset in the directory @@ -1988,8 +1909,71 @@ out: int gfs2_dir_exhash_dealloc(struct gfs2_inode *dip) { - /* Dealloc on-disk leaves to FREEMETA state */ - return foreach_leaf(dip); + struct gfs2_sbd *sdp = GFS2_SB(&dip->i_inode); + struct buffer_head *bh; + struct gfs2_leaf *leaf; + u32 hsize, len; + u32 ht_offset, lp_offset, ht_offset_cur = -1; + u32 index = 0, next_index; + __be64 *lp; + u64 leaf_no; + int error = 0, last; + + hsize = 1 << dip->i_depth; + if (hsize * sizeof(u64) != i_size_read(&dip->i_inode)) { + gfs2_consist_inode(dip); + return -EIO; + } + + lp = kmalloc(sdp->sd_hash_bsize, GFP_NOFS); + if (!lp) + return -ENOMEM; + + while (index < hsize) { + lp_offset = index & (sdp->sd_hash_ptrs - 1); + ht_offset = index - lp_offset; + + if (ht_offset_cur != ht_offset) { + error = gfs2_dir_read_data(dip, (char *)lp, + ht_offset * sizeof(__be64), + sdp->sd_hash_bsize, 1); + if (error != sdp->sd_hash_bsize) { + if (error >= 0) + error = -EIO; + goto out; + } + ht_offset_cur = ht_offset; + } + + leaf_no = be64_to_cpu(lp[lp_offset]); + if (leaf_no) { + error = get_leaf(dip, leaf_no, &bh); + if (error) + goto out; + leaf = (struct gfs2_leaf *)bh->b_data; + len = 1 << (dip->i_depth - be16_to_cpu(leaf->lf_depth)); + + next_index = (index & ~(len - 1)) + len; + last = ((next_index >= hsize) ? 1 : 0); + error = leaf_dealloc(dip, index, len, leaf_no, bh, + last); + brelse(bh); + if (error) + goto out; + index = next_index; + } else + index++; + } + + if (index != hsize) { + gfs2_consist_inode(dip); + error = -EIO; + } + +out: + kfree(lp); + + return error; } /** -- cgit v0.10.2 From 1027efaa238e1b65c07b6c2d9e270e548c2bdb07 Mon Sep 17 00:00:00 2001 From: Steven Whitehouse Date: Wed, 30 Mar 2011 16:13:25 +0100 Subject: GFS2: Make ->write_inode() really write The GFS2 ->write_inode function should be more aggressive at writing back to the filesystem. This adopts the XFS system of returning -EAGAIN when the writeback has not been completely done. Also, we now kick off in-place writeback when called with WB_SYNC_NONE, but we only wait for it and flush the log when WB_SYNC_ALL is requested. Signed-off-by: Steven Whitehouse diff --git a/fs/gfs2/super.c b/fs/gfs2/super.c index b9f28e6..d827b93 100644 --- a/fs/gfs2/super.c +++ b/fs/gfs2/super.c @@ -704,7 +704,7 @@ void gfs2_unfreeze_fs(struct gfs2_sbd *sdp) /** * gfs2_write_inode - Make sure the inode is stable on the disk * @inode: The inode - * @sync: synchronous write flag + * @wbc: The writeback control structure * * Returns: errno */ @@ -713,15 +713,16 @@ static int gfs2_write_inode(struct inode *inode, struct writeback_control *wbc) { struct gfs2_inode *ip = GFS2_I(inode); struct gfs2_sbd *sdp = GFS2_SB(inode); + struct address_space *metamapping = gfs2_glock2aspace(ip->i_gl); struct gfs2_holder gh; struct buffer_head *bh; struct timespec atime; struct gfs2_dinode *di; - int ret = 0; + int ret = -EAGAIN; - /* Check this is a "normal" inode, etc */ + /* Skip timestamp update, if this is from a memalloc */ if (current->flags & PF_MEMALLOC) - return 0; + goto do_flush; ret = gfs2_glock_nq_init(ip->i_gl, LM_ST_EXCLUSIVE, 0, &gh); if (ret) goto do_flush; @@ -745,6 +746,11 @@ do_unlock: do_flush: if (wbc->sync_mode == WB_SYNC_ALL) gfs2_log_flush(GFS2_SB(inode), ip->i_gl); + filemap_fdatawrite(metamapping); + if (!ret && (wbc->sync_mode == WB_SYNC_ALL)) + ret = filemap_fdatawait(metamapping); + if (ret) + mark_inode_dirty_sync(inode); return ret; } @@ -874,8 +880,9 @@ restart: static int gfs2_sync_fs(struct super_block *sb, int wait) { - if (wait && sb->s_fs_info) - gfs2_log_flush(sb->s_fs_info, NULL); + struct gfs2_sbd *sdp = sb->s_fs_info; + if (wait && sdp) + gfs2_log_flush(sdp, NULL); return 0; } -- cgit v0.10.2 From 5ac048bb7ea6e87b06504b999017cfa1f38f4092 Mon Sep 17 00:00:00 2001 From: Steven Whitehouse Date: Wed, 30 Mar 2011 16:25:51 +0100 Subject: GFS2: Use filemap_fdatawrite() to write back the AIL In order to ensure that the mapping stats (and thus the bdi) are correctly updated, this patch changes the AIL writeback to use the filemap_datawrite function. This helps prevent stalls in balance_dirty_pages() due to large amounts of dirty metadata when there is little or no dirty data around. Signed-off-by: Steven Whitehouse diff --git a/fs/gfs2/log.c b/fs/gfs2/log.c index 5b102c1..3ebafa1 100644 --- a/fs/gfs2/log.c +++ b/fs/gfs2/log.c @@ -91,6 +91,7 @@ static void gfs2_ail1_start_one(struct gfs2_sbd *sdp, struct gfs2_ail *ai) __releases(&sdp->sd_ail_lock) __acquires(&sdp->sd_ail_lock) { + struct gfs2_glock *gl = NULL; struct gfs2_bufdata *bd, *s; struct buffer_head *bh; int retry; @@ -113,19 +114,13 @@ __acquires(&sdp->sd_ail_lock) if (!buffer_dirty(bh)) continue; - + if (gl == bd->bd_gl) + continue; + gl = bd->bd_gl; list_move(&bd->bd_ail_st_list, &ai->ai_ail1_list); - get_bh(bh); spin_unlock(&sdp->sd_ail_lock); - lock_buffer(bh); - if (test_clear_buffer_dirty(bh)) { - bh->b_end_io = end_buffer_write_sync; - submit_bh(WRITE_SYNC, bh); - } else { - unlock_buffer(bh); - brelse(bh); - } + filemap_fdatawrite(gfs2_glock2aspace(gl)); spin_lock(&sdp->sd_ail_lock); retry = 1; -- cgit v0.10.2 From 29687a2ac8dfcd5363e515ea715ec226aef8c26b Mon Sep 17 00:00:00 2001 From: Steven Whitehouse Date: Wed, 30 Mar 2011 16:33:25 +0100 Subject: GFS2: Alter point of entry to glock lru list for glocks with an address_space Rather than allowing the glocks to be scheduled for possible reclaim as soon as they have exited the journal, this patch delays their entry to the list until the glocks in question are no longer in use. This means that we will rely on the vm for writeback of all dirty data and metadata from now on. When glocks are added to the lru list they should be freeable much faster since all the I/O required to free them should have already been completed. This should lead to much better I/O patterns under low memory conditions. Signed-off-by: Steven Whitehouse diff --git a/fs/gfs2/glock.c b/fs/gfs2/glock.c index f07643e..1019183 100644 --- a/fs/gfs2/glock.c +++ b/fs/gfs2/glock.c @@ -160,6 +160,19 @@ static int demote_ok(const struct gfs2_glock *gl) } +void gfs2_glock_add_to_lru(struct gfs2_glock *gl) +{ + spin_lock(&lru_lock); + + if (!list_empty(&gl->gl_lru)) + list_del_init(&gl->gl_lru); + else + atomic_inc(&lru_count); + + list_add_tail(&gl->gl_lru, &lru_list); + spin_unlock(&lru_lock); +} + /** * __gfs2_glock_schedule_for_reclaim - Add a glock to the reclaim list * @gl: the glock @@ -170,24 +183,8 @@ static int demote_ok(const struct gfs2_glock *gl) static void __gfs2_glock_schedule_for_reclaim(struct gfs2_glock *gl) { - if (demote_ok(gl)) { - spin_lock(&lru_lock); - - if (!list_empty(&gl->gl_lru)) - list_del_init(&gl->gl_lru); - else - atomic_inc(&lru_count); - - list_add_tail(&gl->gl_lru, &lru_list); - spin_unlock(&lru_lock); - } -} - -void gfs2_glock_schedule_for_reclaim(struct gfs2_glock *gl) -{ - spin_lock(&gl->gl_spin); - __gfs2_glock_schedule_for_reclaim(gl); - spin_unlock(&gl->gl_spin); + if (demote_ok(gl)) + gfs2_glock_add_to_lru(gl); } /** diff --git a/fs/gfs2/glock.h b/fs/gfs2/glock.h index aea1606..6b2f757 100644 --- a/fs/gfs2/glock.h +++ b/fs/gfs2/glock.h @@ -225,11 +225,10 @@ static inline int gfs2_glock_nq_init(struct gfs2_glock *gl, extern void gfs2_glock_cb(struct gfs2_glock *gl, unsigned int state); extern void gfs2_glock_complete(struct gfs2_glock *gl, int ret); -extern void gfs2_reclaim_glock(struct gfs2_sbd *sdp); extern void gfs2_gl_hash_clear(struct gfs2_sbd *sdp); extern void gfs2_glock_finish_truncate(struct gfs2_inode *ip); extern void gfs2_glock_thaw(struct gfs2_sbd *sdp); -extern void gfs2_glock_schedule_for_reclaim(struct gfs2_glock *gl); +extern void gfs2_glock_add_to_lru(struct gfs2_glock *gl); extern void gfs2_glock_free(struct gfs2_glock *gl); extern int __init gfs2_glock_init(void); diff --git a/fs/gfs2/lops.c b/fs/gfs2/lops.c index 51d27f0..611a51d 100644 --- a/fs/gfs2/lops.c +++ b/fs/gfs2/lops.c @@ -40,7 +40,7 @@ static void gfs2_pin(struct gfs2_sbd *sdp, struct buffer_head *bh) { struct gfs2_bufdata *bd; - gfs2_assert_withdraw(sdp, test_bit(SDF_JOURNAL_LIVE, &sdp->sd_flags)); + BUG_ON(!current->journal_info); clear_buffer_dirty(bh); if (test_set_buffer_pinned(bh)) @@ -65,6 +65,7 @@ static void gfs2_pin(struct gfs2_sbd *sdp, struct buffer_head *bh) * @sdp: the filesystem the buffer belongs to * @bh: The buffer to unpin * @ai: + * @flags: The inode dirty flags * */ @@ -73,10 +74,8 @@ static void gfs2_unpin(struct gfs2_sbd *sdp, struct buffer_head *bh, { struct gfs2_bufdata *bd = bh->b_private; - gfs2_assert_withdraw(sdp, buffer_uptodate(bh)); - - if (!buffer_pinned(bh)) - gfs2_assert_withdraw(sdp, 0); + BUG_ON(!buffer_uptodate(bh)); + BUG_ON(!buffer_pinned(bh)); lock_buffer(bh); mark_buffer_dirty(bh); @@ -95,8 +94,7 @@ static void gfs2_unpin(struct gfs2_sbd *sdp, struct buffer_head *bh, list_add(&bd->bd_ail_st_list, &ai->ai_ail1_list); spin_unlock(&sdp->sd_ail_lock); - if (test_and_clear_bit(GLF_LFLUSH, &bd->bd_gl->gl_flags)) - gfs2_glock_schedule_for_reclaim(bd->bd_gl); + clear_bit(GLF_LFLUSH, &bd->bd_gl->gl_flags); trace_gfs2_pin(bd, 0); unlock_buffer(bh); atomic_dec(&sdp->sd_log_pinned); diff --git a/fs/gfs2/rgrp.c b/fs/gfs2/rgrp.c index b643c14..7273ad3 100644 --- a/fs/gfs2/rgrp.c +++ b/fs/gfs2/rgrp.c @@ -392,6 +392,7 @@ static void clear_rgrpdi(struct gfs2_sbd *sdp) if (gl) { gl->gl_object = NULL; + gfs2_glock_add_to_lru(gl); gfs2_glock_put(gl); } diff --git a/fs/gfs2/super.c b/fs/gfs2/super.c index d827b93..b62c842 100644 --- a/fs/gfs2/super.c +++ b/fs/gfs2/super.c @@ -1401,6 +1401,7 @@ out: end_writeback(inode); ip->i_gl->gl_object = NULL; + gfs2_glock_add_to_lru(ip->i_gl); gfs2_glock_put(ip->i_gl); ip->i_gl = NULL; if (ip->i_iopen_gh.gh_gl) { -- cgit v0.10.2 From efc1a9c2a70e4e49f4cf179a7ed8064b7a406e4a Mon Sep 17 00:00:00 2001 From: Steven Whitehouse Date: Wed, 13 Apr 2011 13:03:34 +0100 Subject: GFS2: Remove unused macro The buffer_in_io() macro has been unused for some time, so remove it. Signed-off-by: Steven Whitehouse diff --git a/fs/gfs2/meta_io.h b/fs/gfs2/meta_io.h index 6a1d9ba..22c5265 100644 --- a/fs/gfs2/meta_io.h +++ b/fs/gfs2/meta_io.h @@ -77,8 +77,6 @@ struct buffer_head *gfs2_meta_ra(struct gfs2_glock *gl, u64 dblock, u32 extlen); #define buffer_busy(bh) \ ((bh)->b_state & ((1ul << BH_Dirty) | (1ul << BH_Lock) | (1ul << BH_Pinned))) -#define buffer_in_io(bh) \ -((bh)->b_state & ((1ul << BH_Dirty) | (1ul << BH_Lock))) #endif /* __DIO_DOT_H__ */ -- cgit v0.10.2 From dba898b02defa66e5fe493d58ec0293a940f9c93 Mon Sep 17 00:00:00 2001 From: Steven Whitehouse Date: Thu, 14 Apr 2011 09:54:02 +0100 Subject: GFS2: Clean up fsync() This patch is designed to clean up GFS2's fsync implementation and ensure that it really does get everything on disk. Since ->write_inode() has been updated, we can call that via the vfs library function sync_inode_metadata() and the only remaining thing that has to be done is to ensure that we get any revoke records in the log after the inode has been written back. Signed-off-by: Steven Whitehouse diff --git a/fs/gfs2/file.c b/fs/gfs2/file.c index e483108..23eab47 100644 --- a/fs/gfs2/file.c +++ b/fs/gfs2/file.c @@ -545,18 +545,10 @@ static int gfs2_close(struct inode *inode, struct file *file) /** * gfs2_fsync - sync the dirty data for a file (across the cluster) * @file: the file that points to the dentry (we ignore this) - * @dentry: the dentry that points to the inode to sync + * @datasync: set if we can ignore timestamp changes * - * The VFS will flush "normal" data for us. We only need to worry - * about metadata here. For journaled data, we just do a log flush - * as we can't avoid it. Otherwise we can just bale out if datasync - * is set. For stuffed inodes we must flush the log in order to - * ensure that all data is on disk. - * - * The call to write_inode_now() is there to write back metadata and - * the inode itself. It does also try and write the data, but thats - * (hopefully) a no-op due to the VFS having already called filemap_fdatawrite() - * for us. + * The VFS will flush data for us. We only need to worry + * about metadata here. * * Returns: errno */ @@ -565,22 +557,20 @@ static int gfs2_fsync(struct file *file, int datasync) { struct inode *inode = file->f_mapping->host; int sync_state = inode->i_state & (I_DIRTY_SYNC|I_DIRTY_DATASYNC); - int ret = 0; - - if (gfs2_is_jdata(GFS2_I(inode))) { - gfs2_log_flush(GFS2_SB(inode), GFS2_I(inode)->i_gl); - return 0; - } + struct gfs2_inode *ip = GFS2_I(inode); + int ret; - if (sync_state != 0) { - if (!datasync) - ret = write_inode_now(inode, 0); + if (datasync) + sync_state &= ~I_DIRTY_SYNC; - if (gfs2_is_stuffed(GFS2_I(inode))) - gfs2_log_flush(GFS2_SB(inode), GFS2_I(inode)->i_gl); + if (sync_state) { + ret = sync_inode_metadata(inode, 1); + if (ret) + return ret; + gfs2_ail_flush(ip->i_gl); } - return ret; + return 0; } /** diff --git a/fs/gfs2/glops.c b/fs/gfs2/glops.c index 25eeb2b..7c1b08f 100644 --- a/fs/gfs2/glops.c +++ b/fs/gfs2/glops.c @@ -28,33 +28,18 @@ #include "trans.h" /** - * ail_empty_gl - remove all buffers for a given lock from the AIL + * __gfs2_ail_flush - remove all buffers for a given lock from the AIL * @gl: the glock * * None of the buffers should be dirty, locked, or pinned. */ -static void gfs2_ail_empty_gl(struct gfs2_glock *gl) +static void __gfs2_ail_flush(struct gfs2_glock *gl) { struct gfs2_sbd *sdp = gl->gl_sbd; struct list_head *head = &gl->gl_ail_list; struct gfs2_bufdata *bd; struct buffer_head *bh; - struct gfs2_trans tr; - - memset(&tr, 0, sizeof(tr)); - tr.tr_revokes = atomic_read(&gl->gl_ail_count); - - if (!tr.tr_revokes) - return; - - /* A shortened, inline version of gfs2_trans_begin() */ - tr.tr_reserved = 1 + gfs2_struct2blk(sdp, tr.tr_revokes, sizeof(u64)); - tr.tr_ip = (unsigned long)__builtin_return_address(0); - INIT_LIST_HEAD(&tr.tr_list_buf); - gfs2_log_reserve(sdp, tr.tr_reserved); - BUG_ON(current->journal_info); - current->journal_info = &tr; spin_lock(&sdp->sd_ail_lock); while (!list_empty(head)) { @@ -76,7 +61,47 @@ static void gfs2_ail_empty_gl(struct gfs2_glock *gl) } gfs2_assert_withdraw(sdp, !atomic_read(&gl->gl_ail_count)); spin_unlock(&sdp->sd_ail_lock); +} + + +static void gfs2_ail_empty_gl(struct gfs2_glock *gl) +{ + struct gfs2_sbd *sdp = gl->gl_sbd; + struct gfs2_trans tr; + + memset(&tr, 0, sizeof(tr)); + tr.tr_revokes = atomic_read(&gl->gl_ail_count); + + if (!tr.tr_revokes) + return; + + /* A shortened, inline version of gfs2_trans_begin() */ + tr.tr_reserved = 1 + gfs2_struct2blk(sdp, tr.tr_revokes, sizeof(u64)); + tr.tr_ip = (unsigned long)__builtin_return_address(0); + INIT_LIST_HEAD(&tr.tr_list_buf); + gfs2_log_reserve(sdp, tr.tr_reserved); + BUG_ON(current->journal_info); + current->journal_info = &tr; + + __gfs2_ail_flush(gl); + + gfs2_trans_end(sdp); + gfs2_log_flush(sdp, NULL); +} +void gfs2_ail_flush(struct gfs2_glock *gl) +{ + struct gfs2_sbd *sdp = gl->gl_sbd; + unsigned int revokes = atomic_read(&gl->gl_ail_count); + int ret; + + if (!revokes) + return; + + ret = gfs2_trans_begin(sdp, 0, revokes); + if (ret) + return; + __gfs2_ail_flush(gl); gfs2_trans_end(sdp); gfs2_log_flush(sdp, NULL); } diff --git a/fs/gfs2/glops.h b/fs/gfs2/glops.h index b3aa2e3..6fce409 100644 --- a/fs/gfs2/glops.h +++ b/fs/gfs2/glops.h @@ -23,4 +23,6 @@ extern const struct gfs2_glock_operations gfs2_quota_glops; extern const struct gfs2_glock_operations gfs2_journal_glops; extern const struct gfs2_glock_operations *gfs2_glops_list[]; +extern void gfs2_ail_flush(struct gfs2_glock *gl); + #endif /* __GLOPS_DOT_H__ */ -- cgit v0.10.2 From 627c10b7e471b5dcfb7101d6cc74d219619c9bc4 Mon Sep 17 00:00:00 2001 From: Steven Whitehouse Date: Thu, 14 Apr 2011 14:09:52 +0100 Subject: GFS2: Improve tracing support (adds two flags) This adds support for two new flags. One keeps track of whether the glock is on the LRU list or not. The other isn't really a flag as such, but an indication of whether the glock has an attached object or not. This indication is reported without any locking, which is ok since we do not dereference the object pointer but merely report whether it is NULL or not. Also, this fixes one place where a tracepoint was missing, which was at the point we remove deallocated blocks from the journal. Signed-off-by: Steven Whitehouse diff --git a/fs/gfs2/glock.c b/fs/gfs2/glock.c index 1019183..0c6c690 100644 --- a/fs/gfs2/glock.c +++ b/fs/gfs2/glock.c @@ -170,6 +170,7 @@ void gfs2_glock_add_to_lru(struct gfs2_glock *gl) atomic_inc(&lru_count); list_add_tail(&gl->gl_lru, &lru_list); + set_bit(GLF_LRU, &gl->gl_flags); spin_unlock(&lru_lock); } @@ -1364,6 +1365,7 @@ static int gfs2_shrink_glock_memory(struct shrinker *shrink, int nr, gfp_t gfp_m while(nr && !list_empty(&lru_list)) { gl = list_entry(lru_list.next, struct gfs2_glock, gl_lru); list_del_init(&gl->gl_lru); + clear_bit(GLF_LRU, &gl->gl_flags); atomic_dec(&lru_count); /* Test for being demotable */ @@ -1386,6 +1388,7 @@ static int gfs2_shrink_glock_memory(struct shrinker *shrink, int nr, gfp_t gfp_m } nr_skipped++; list_add(&gl->gl_lru, &skipped); + set_bit(GLF_LRU, &gl->gl_flags); } list_splice(&skipped, &lru_list); atomic_add(nr_skipped, &lru_count); @@ -1598,9 +1601,11 @@ static int dump_holder(struct seq_file *seq, const struct gfs2_holder *gh) return 0; } -static const char *gflags2str(char *buf, const unsigned long *gflags) +static const char *gflags2str(char *buf, const struct gfs2_glock *gl) { + const unsigned long *gflags = &gl->gl_flags; char *p = buf; + if (test_bit(GLF_LOCK, gflags)) *p++ = 'l'; if (test_bit(GLF_DEMOTE, gflags)) @@ -1623,6 +1628,10 @@ static const char *gflags2str(char *buf, const unsigned long *gflags) *p++ = 'F'; if (test_bit(GLF_QUEUED, gflags)) *p++ = 'q'; + if (test_bit(GLF_LRU, gflags)) + *p++ = 'L'; + if (gl->gl_object) + *p++ = 'o'; *p = 0; return buf; } @@ -1661,7 +1670,7 @@ static int __dump_glock(struct seq_file *seq, const struct gfs2_glock *gl) state2str(gl->gl_state), gl->gl_name.ln_type, (unsigned long long)gl->gl_name.ln_number, - gflags2str(gflags_buf, &gl->gl_flags), + gflags2str(gflags_buf, gl), state2str(gl->gl_target), state2str(gl->gl_demote_state), dtime, atomic_read(&gl->gl_ail_count), diff --git a/fs/gfs2/incore.h b/fs/gfs2/incore.h index 870a89d..48eb1ee 100644 --- a/fs/gfs2/incore.h +++ b/fs/gfs2/incore.h @@ -200,6 +200,8 @@ enum { GLF_INITIAL = 10, GLF_FROZEN = 11, GLF_QUEUED = 12, + GLF_LRU = 13, + GLF_OBJECT = 14, /* Used only for tracing */ }; struct gfs2_glock { diff --git a/fs/gfs2/meta_io.c b/fs/gfs2/meta_io.c index 675349b..747238c 100644 --- a/fs/gfs2/meta_io.c +++ b/fs/gfs2/meta_io.c @@ -31,6 +31,7 @@ #include "rgrp.h" #include "trans.h" #include "util.h" +#include "trace_gfs2.h" static int gfs2_aspace_writepage(struct page *page, struct writeback_control *wbc) { @@ -310,6 +311,7 @@ void gfs2_remove_from_journal(struct buffer_head *bh, struct gfs2_trans *tr, int struct gfs2_bufdata *bd = bh->b_private; if (test_clear_buffer_pinned(bh)) { + trace_gfs2_pin(bd, 0); atomic_dec(&sdp->sd_log_pinned); list_del_init(&bd->bd_le.le_list); if (meta) { diff --git a/fs/gfs2/trace_gfs2.h b/fs/gfs2/trace_gfs2.h index cedb0bb..9133d0a 100644 --- a/fs/gfs2/trace_gfs2.h +++ b/fs/gfs2/trace_gfs2.h @@ -40,7 +40,9 @@ {(1UL << GLF_REPLY_PENDING), "r" }, \ {(1UL << GLF_INITIAL), "I" }, \ {(1UL << GLF_FROZEN), "F" }, \ - {(1UL << GLF_QUEUED), "q" }) + {(1UL << GLF_QUEUED), "q" }, \ + {(1UL << GLF_LRU), "L" }, \ + {(1UL << GLF_OBJECT), "o" }) #ifndef NUMPTY #define NUMPTY @@ -94,7 +96,7 @@ TRACE_EVENT(gfs2_glock_state_change, __entry->new_state = glock_trace_state(new_state); __entry->tgt_state = glock_trace_state(gl->gl_target); __entry->dmt_state = glock_trace_state(gl->gl_demote_state); - __entry->flags = gl->gl_flags; + __entry->flags = gl->gl_flags | (gl->gl_object ? (1UL<gltype = gl->gl_name.ln_type; __entry->glnum = gl->gl_name.ln_number; __entry->cur_state = glock_trace_state(gl->gl_state); - __entry->flags = gl->gl_flags; + __entry->flags = gl->gl_flags | (gl->gl_object ? (1UL< %s flags:%s", @@ -161,7 +163,7 @@ TRACE_EVENT(gfs2_demote_rq, __entry->glnum = gl->gl_name.ln_number; __entry->cur_state = glock_trace_state(gl->gl_state); __entry->dmt_state = glock_trace_state(gl->gl_demote_state); - __entry->flags = gl->gl_flags; + __entry->flags = gl->gl_flags | (gl->gl_object ? (1UL< Date: Thu, 14 Apr 2011 16:50:31 +0100 Subject: GFS2: Optimise glock lru and end of life inodes The GLF_LRU flag introduced in the previous patch can be used to check if a glock is on the lru list when a new holder is queued and if so remove it, without having first to get the lru_lock. The main purpose of this patch however is to optimise the glocks left over when an inode at end of life is being evicted. Previously such glocks were left with the GLF_LFLUSH flag set, so that when reclaimed, each one required a log flush. This patch resets the GLF_LFLUSH flag when there is nothing left to flush thus preventing later log flushes as glocks are reused or demoted. In order to do this, we need to keep track of the number of revokes which are outstanding, and also to clear the GLF_LFLUSH bit after a log commit when only revokes have been processed. Signed-off-by: Steven Whitehouse diff --git a/fs/gfs2/glock.c b/fs/gfs2/glock.c index 0c6c690..cb8776f 100644 --- a/fs/gfs2/glock.c +++ b/fs/gfs2/glock.c @@ -145,14 +145,9 @@ static int demote_ok(const struct gfs2_glock *gl) { const struct gfs2_glock_operations *glops = gl->gl_ops; - /* assert_spin_locked(&gl->gl_spin); */ - if (gl->gl_state == LM_ST_UNLOCKED) return 0; - if (test_bit(GLF_LFLUSH, &gl->gl_flags)) - return 0; - if ((gl->gl_name.ln_type != LM_TYPE_INODE) && - !list_empty(&gl->gl_holders)) + if (!list_empty(&gl->gl_holders)) return 0; if (glops->go_demote_ok) return glops->go_demote_ok(gl); @@ -174,6 +169,17 @@ void gfs2_glock_add_to_lru(struct gfs2_glock *gl) spin_unlock(&lru_lock); } +static void gfs2_glock_remove_from_lru(struct gfs2_glock *gl) +{ + spin_lock(&lru_lock); + if (!list_empty(&gl->gl_lru)) { + list_del_init(&gl->gl_lru); + atomic_dec(&lru_count); + clear_bit(GLF_LRU, &gl->gl_flags); + } + spin_unlock(&lru_lock); +} + /** * __gfs2_glock_schedule_for_reclaim - Add a glock to the reclaim list * @gl: the glock @@ -217,12 +223,7 @@ void gfs2_glock_put(struct gfs2_glock *gl) spin_lock_bucket(gl->gl_hash); hlist_bl_del_rcu(&gl->gl_list); spin_unlock_bucket(gl->gl_hash); - spin_lock(&lru_lock); - if (!list_empty(&gl->gl_lru)) { - list_del_init(&gl->gl_lru); - atomic_dec(&lru_count); - } - spin_unlock(&lru_lock); + gfs2_glock_remove_from_lru(gl); GLOCK_BUG_ON(gl, !list_empty(&gl->gl_holders)); GLOCK_BUG_ON(gl, mapping && mapping->nrpages); trace_gfs2_glock_put(gl); @@ -1025,6 +1026,9 @@ int gfs2_glock_nq(struct gfs2_holder *gh) if (unlikely(test_bit(SDF_SHUTDOWN, &sdp->sd_flags))) return -EIO; + if (test_bit(GLF_LRU, &gl->gl_flags)) + gfs2_glock_remove_from_lru(gl); + spin_lock(&gl->gl_spin); add_to_queue(gh); if ((LM_FLAG_NOEXP & gh->gh_flags) && @@ -1082,7 +1086,8 @@ void gfs2_glock_dq(struct gfs2_holder *gh) !test_bit(GLF_DEMOTE, &gl->gl_flags)) fast_path = 1; } - __gfs2_glock_schedule_for_reclaim(gl); + if (!test_bit(GLF_LFLUSH, &gl->gl_flags)) + __gfs2_glock_schedule_for_reclaim(gl); trace_gfs2_glock_queue(gh, 0); spin_unlock(&gl->gl_spin); if (likely(fast_path)) @@ -1461,12 +1466,7 @@ static void thaw_glock(struct gfs2_glock *gl) static void clear_glock(struct gfs2_glock *gl) { - spin_lock(&lru_lock); - if (!list_empty(&gl->gl_lru)) { - list_del_init(&gl->gl_lru); - atomic_dec(&lru_count); - } - spin_unlock(&lru_lock); + gfs2_glock_remove_from_lru(gl); spin_lock(&gl->gl_spin); if (gl->gl_state != LM_ST_UNLOCKED) @@ -1666,7 +1666,7 @@ static int __dump_glock(struct seq_file *seq, const struct gfs2_glock *gl) dtime *= 1000000/HZ; /* demote time in uSec */ if (!test_bit(GLF_DEMOTE, &gl->gl_flags)) dtime = 0; - gfs2_print_dbg(seq, "G: s:%s n:%u/%llx f:%s t:%s d:%s/%llu a:%d r:%d\n", + gfs2_print_dbg(seq, "G: s:%s n:%u/%llx f:%s t:%s d:%s/%llu a:%d v:%d r:%d\n", state2str(gl->gl_state), gl->gl_name.ln_type, (unsigned long long)gl->gl_name.ln_number, @@ -1674,6 +1674,7 @@ static int __dump_glock(struct seq_file *seq, const struct gfs2_glock *gl) state2str(gl->gl_target), state2str(gl->gl_demote_state), dtime, atomic_read(&gl->gl_ail_count), + atomic_read(&gl->gl_revokes), atomic_read(&gl->gl_ref)); list_for_each_entry(gh, &gl->gl_holders, gh_list) { diff --git a/fs/gfs2/incore.h b/fs/gfs2/incore.h index 48eb1ee..5067bea 100644 --- a/fs/gfs2/incore.h +++ b/fs/gfs2/incore.h @@ -236,6 +236,7 @@ struct gfs2_glock { struct list_head gl_ail_list; atomic_t gl_ail_count; + atomic_t gl_revokes; struct delayed_work gl_work; struct work_struct gl_delete; struct rcu_head gl_rcu; diff --git a/fs/gfs2/inode.c b/fs/gfs2/inode.c index 9134dcb..9b7b9e4 100644 --- a/fs/gfs2/inode.c +++ b/fs/gfs2/inode.c @@ -341,65 +341,6 @@ int gfs2_inode_refresh(struct gfs2_inode *ip) return error; } -int gfs2_dinode_dealloc(struct gfs2_inode *ip) -{ - struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode); - struct gfs2_alloc *al; - struct gfs2_rgrpd *rgd; - int error; - - if (gfs2_get_inode_blocks(&ip->i_inode) != 1) { - if (gfs2_consist_inode(ip)) - gfs2_dinode_print(ip); - return -EIO; - } - - al = gfs2_alloc_get(ip); - if (!al) - return -ENOMEM; - - error = gfs2_quota_hold(ip, NO_QUOTA_CHANGE, NO_QUOTA_CHANGE); - if (error) - goto out; - - error = gfs2_rindex_hold(sdp, &al->al_ri_gh); - if (error) - goto out_qs; - - rgd = gfs2_blk2rgrpd(sdp, ip->i_no_addr); - if (!rgd) { - gfs2_consist_inode(ip); - error = -EIO; - goto out_rindex_relse; - } - - error = gfs2_glock_nq_init(rgd->rd_gl, LM_ST_EXCLUSIVE, 0, - &al->al_rgd_gh); - if (error) - goto out_rindex_relse; - - error = gfs2_trans_begin(sdp, RES_RG_BIT + RES_STATFS + RES_QUOTA, 1); - if (error) - goto out_rg_gunlock; - - set_bit(GLF_DIRTY, &ip->i_gl->gl_flags); - set_bit(GLF_LFLUSH, &ip->i_gl->gl_flags); - - gfs2_free_di(rgd, ip); - - gfs2_trans_end(sdp); - -out_rg_gunlock: - gfs2_glock_dq_uninit(&al->al_rgd_gh); -out_rindex_relse: - gfs2_glock_dq_uninit(&al->al_ri_gh); -out_qs: - gfs2_quota_unhold(ip); -out: - gfs2_alloc_put(ip); - return error; -} - /** * gfs2_change_nlink - Change nlink count on inode * @ip: The GFS2 inode diff --git a/fs/gfs2/inode.h b/fs/gfs2/inode.h index 099ca30..842346e 100644 --- a/fs/gfs2/inode.h +++ b/fs/gfs2/inode.h @@ -106,7 +106,6 @@ extern struct inode *gfs2_ilookup(struct super_block *sb, u64 no_addr); extern int gfs2_inode_refresh(struct gfs2_inode *ip); -extern int gfs2_dinode_dealloc(struct gfs2_inode *inode); extern int gfs2_change_nlink(struct gfs2_inode *ip, int diff); extern struct inode *gfs2_lookupi(struct inode *dir, const struct qstr *name, int is_root); diff --git a/fs/gfs2/lops.c b/fs/gfs2/lops.c index 611a51d..05bbb12 100644 --- a/fs/gfs2/lops.c +++ b/fs/gfs2/lops.c @@ -320,12 +320,16 @@ static void buf_lo_after_scan(struct gfs2_jdesc *jd, int error, int pass) static void revoke_lo_add(struct gfs2_sbd *sdp, struct gfs2_log_element *le) { + struct gfs2_bufdata *bd = container_of(le, struct gfs2_bufdata, bd_le); + struct gfs2_glock *gl = bd->bd_gl; struct gfs2_trans *tr; tr = current->journal_info; tr->tr_touched = 1; tr->tr_num_revoke++; sdp->sd_log_num_revoke++; + atomic_inc(&gl->gl_revokes); + set_bit(GLF_LFLUSH, &gl->gl_flags); list_add(&le->le_list, &sdp->sd_log_le_revoke); } @@ -348,9 +352,7 @@ static void revoke_lo_before_commit(struct gfs2_sbd *sdp) ld->ld_data1 = cpu_to_be32(sdp->sd_log_num_revoke); offset = sizeof(struct gfs2_log_descriptor); - while (!list_empty(head)) { - bd = list_entry(head->next, struct gfs2_bufdata, bd_le.le_list); - list_del_init(&bd->bd_le.le_list); + list_for_each_entry(bd, head, bd_le.le_list) { sdp->sd_log_num_revoke--; if (offset + sizeof(u64) > sdp->sd_sb.sb_bsize) { @@ -365,8 +367,6 @@ static void revoke_lo_before_commit(struct gfs2_sbd *sdp) } *(__be64 *)(bh->b_data + offset) = cpu_to_be64(bd->bd_blkno); - kmem_cache_free(gfs2_bufdata_cachep, bd); - offset += sizeof(u64); } gfs2_assert_withdraw(sdp, !sdp->sd_log_num_revoke); @@ -374,6 +374,22 @@ static void revoke_lo_before_commit(struct gfs2_sbd *sdp) submit_bh(WRITE_SYNC, bh); } +static void revoke_lo_after_commit(struct gfs2_sbd *sdp, struct gfs2_ail *ai) +{ + struct list_head *head = &sdp->sd_log_le_revoke; + struct gfs2_bufdata *bd; + struct gfs2_glock *gl; + + while (!list_empty(head)) { + bd = list_entry(head->next, struct gfs2_bufdata, bd_le.le_list); + list_del_init(&bd->bd_le.le_list); + gl = bd->bd_gl; + atomic_dec(&gl->gl_revokes); + clear_bit(GLF_LFLUSH, &gl->gl_flags); + kmem_cache_free(gfs2_bufdata_cachep, bd); + } +} + static void revoke_lo_before_scan(struct gfs2_jdesc *jd, struct gfs2_log_header_host *head, int pass) { @@ -747,6 +763,7 @@ const struct gfs2_log_operations gfs2_buf_lops = { const struct gfs2_log_operations gfs2_revoke_lops = { .lo_add = revoke_lo_add, .lo_before_commit = revoke_lo_before_commit, + .lo_after_commit = revoke_lo_after_commit, .lo_before_scan = revoke_lo_before_scan, .lo_scan_elements = revoke_lo_scan_elements, .lo_after_scan = revoke_lo_after_scan, diff --git a/fs/gfs2/main.c b/fs/gfs2/main.c index 888a5f5..cfa327d 100644 --- a/fs/gfs2/main.c +++ b/fs/gfs2/main.c @@ -53,6 +53,7 @@ static void gfs2_init_glock_once(void *foo) INIT_LIST_HEAD(&gl->gl_lru); INIT_LIST_HEAD(&gl->gl_ail_list); atomic_set(&gl->gl_ail_count, 0); + atomic_set(&gl->gl_revokes, 0); } static void gfs2_init_gl_aspace_once(void *foo) diff --git a/fs/gfs2/super.c b/fs/gfs2/super.c index b62c842..215c37b 100644 --- a/fs/gfs2/super.c +++ b/fs/gfs2/super.c @@ -1315,6 +1315,78 @@ static int gfs2_show_options(struct seq_file *s, struct vfsmount *mnt) return 0; } +static void gfs2_final_release_pages(struct gfs2_inode *ip) +{ + struct inode *inode = &ip->i_inode; + struct gfs2_glock *gl = ip->i_gl; + + truncate_inode_pages(gfs2_glock2aspace(ip->i_gl), 0); + truncate_inode_pages(&inode->i_data, 0); + + if (atomic_read(&gl->gl_revokes) == 0) { + clear_bit(GLF_LFLUSH, &gl->gl_flags); + clear_bit(GLF_DIRTY, &gl->gl_flags); + } +} + +static int gfs2_dinode_dealloc(struct gfs2_inode *ip) +{ + struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode); + struct gfs2_alloc *al; + struct gfs2_rgrpd *rgd; + int error; + + if (gfs2_get_inode_blocks(&ip->i_inode) != 1) { + if (gfs2_consist_inode(ip)) + gfs2_dinode_print(ip); + return -EIO; + } + + al = gfs2_alloc_get(ip); + if (!al) + return -ENOMEM; + + error = gfs2_quota_hold(ip, NO_QUOTA_CHANGE, NO_QUOTA_CHANGE); + if (error) + goto out; + + error = gfs2_rindex_hold(sdp, &al->al_ri_gh); + if (error) + goto out_qs; + + rgd = gfs2_blk2rgrpd(sdp, ip->i_no_addr); + if (!rgd) { + gfs2_consist_inode(ip); + error = -EIO; + goto out_rindex_relse; + } + + error = gfs2_glock_nq_init(rgd->rd_gl, LM_ST_EXCLUSIVE, 0, + &al->al_rgd_gh); + if (error) + goto out_rindex_relse; + + error = gfs2_trans_begin(sdp, RES_RG_BIT + RES_STATFS + RES_QUOTA, 1); + if (error) + goto out_rg_gunlock; + + gfs2_free_di(rgd, ip); + + gfs2_final_release_pages(ip); + + gfs2_trans_end(sdp); + +out_rg_gunlock: + gfs2_glock_dq_uninit(&al->al_rgd_gh); +out_rindex_relse: + gfs2_glock_dq_uninit(&al->al_ri_gh); +out_qs: + gfs2_quota_unhold(ip); +out: + gfs2_alloc_put(ip); + return error; +} + /* * We have to (at the moment) hold the inodes main lock to cover * the gap between unlocking the shared lock on the iopen lock and @@ -1378,15 +1450,13 @@ static void gfs2_evict_inode(struct inode *inode) } error = gfs2_dinode_dealloc(ip); - if (error) - goto out_unlock; + goto out_unlock; out_truncate: error = gfs2_trans_begin(sdp, 0, sdp->sd_jdesc->jd_blocks); if (error) goto out_unlock; - /* Needs to be done before glock release & also in a transaction */ - truncate_inode_pages(&inode->i_data, 0); + gfs2_final_release_pages(ip); gfs2_trans_end(sdp); out_unlock: -- cgit v0.10.2 From 4667a0ec32867865fd4deccf834594b3ea831baf Mon Sep 17 00:00:00 2001 From: Steven Whitehouse Date: Mon, 18 Apr 2011 14:18:09 +0100 Subject: GFS2: Make writeback more responsive to system conditions This patch adds writeback_control to writing back the AIL list. This means that we can then take advantage of the information we get in ->write_inode() in order to set off some pre-emptive writeback. In addition, the AIL code is cleaned up a bit to make it a bit simpler to understand. There is still more which can usefully be done in this area, but this is a good start at least. Signed-off-by: Steven Whitehouse diff --git a/fs/gfs2/export.c b/fs/gfs2/export.c index b5a5e60..fe9945f 100644 --- a/fs/gfs2/export.c +++ b/fs/gfs2/export.c @@ -139,7 +139,7 @@ static struct dentry *gfs2_get_dentry(struct super_block *sb, struct gfs2_sbd *sdp = sb->s_fs_info; struct inode *inode; - inode = gfs2_ilookup(sb, inum->no_addr); + inode = gfs2_ilookup(sb, inum->no_addr, 0); if (inode) { if (GFS2_I(inode)->i_no_formal_ino != inum->no_formal_ino) { iput(inode); diff --git a/fs/gfs2/glock.c b/fs/gfs2/glock.c index cb8776f..eed4b68 100644 --- a/fs/gfs2/glock.c +++ b/fs/gfs2/glock.c @@ -649,7 +649,7 @@ static void delete_work_func(struct work_struct *work) /* Note: Unsafe to dereference ip as we don't hold right refs/locks */ if (ip) - inode = gfs2_ilookup(sdp->sd_vfs, no_addr); + inode = gfs2_ilookup(sdp->sd_vfs, no_addr, 1); else inode = gfs2_lookup_by_inum(sdp, no_addr, NULL, GFS2_BLKST_UNLINKED); if (inode && !IS_ERR(inode)) { diff --git a/fs/gfs2/incore.h b/fs/gfs2/incore.h index 5067bea..69a6382 100644 --- a/fs/gfs2/incore.h +++ b/fs/gfs2/incore.h @@ -20,7 +20,6 @@ #define DIO_WAIT 0x00000010 #define DIO_METADATA 0x00000020 -#define DIO_ALL 0x00000100 struct gfs2_log_operations; struct gfs2_log_element; @@ -377,8 +376,6 @@ struct gfs2_ail { unsigned int ai_first; struct list_head ai_ail1_list; struct list_head ai_ail2_list; - - u64 ai_sync_gen; }; struct gfs2_journal_extent { @@ -657,7 +654,6 @@ struct gfs2_sbd { spinlock_t sd_ail_lock; struct list_head sd_ail1_list; struct list_head sd_ail2_list; - u64 sd_ail_sync_gen; /* Replay stuff */ diff --git a/fs/gfs2/inode.c b/fs/gfs2/inode.c index 9b7b9e4..94c3a7d 100644 --- a/fs/gfs2/inode.c +++ b/fs/gfs2/inode.c @@ -74,14 +74,14 @@ static int iget_set(struct inode *inode, void *opaque) return 0; } -struct inode *gfs2_ilookup(struct super_block *sb, u64 no_addr) +struct inode *gfs2_ilookup(struct super_block *sb, u64 no_addr, int non_block) { unsigned long hash = (unsigned long)no_addr; struct gfs2_skip_data data; data.no_addr = no_addr; data.skipped = 0; - data.non_block = 0; + data.non_block = non_block; return ilookup5(sb, hash, iget_test, &data); } diff --git a/fs/gfs2/inode.h b/fs/gfs2/inode.h index 842346e..8d1344a 100644 --- a/fs/gfs2/inode.h +++ b/fs/gfs2/inode.h @@ -102,7 +102,7 @@ extern struct inode *gfs2_inode_lookup(struct super_block *sb, unsigned type, extern struct inode *gfs2_lookup_by_inum(struct gfs2_sbd *sdp, u64 no_addr, u64 *no_formal_ino, unsigned int blktype); -extern struct inode *gfs2_ilookup(struct super_block *sb, u64 no_addr); +extern struct inode *gfs2_ilookup(struct super_block *sb, u64 no_addr, int nonblock); extern int gfs2_inode_refresh(struct gfs2_inode *ip); diff --git a/fs/gfs2/log.c b/fs/gfs2/log.c index 3ebafa1..03e0041 100644 --- a/fs/gfs2/log.c +++ b/fs/gfs2/log.c @@ -18,6 +18,7 @@ #include #include #include +#include #include "gfs2.h" #include "incore.h" @@ -83,50 +84,90 @@ void gfs2_remove_from_ail(struct gfs2_bufdata *bd) /** * gfs2_ail1_start_one - Start I/O on a part of the AIL * @sdp: the filesystem - * @tr: the part of the AIL + * @wbc: The writeback control structure + * @ai: The ail structure * */ -static void gfs2_ail1_start_one(struct gfs2_sbd *sdp, struct gfs2_ail *ai) +static void gfs2_ail1_start_one(struct gfs2_sbd *sdp, + struct writeback_control *wbc, + struct gfs2_ail *ai) __releases(&sdp->sd_ail_lock) __acquires(&sdp->sd_ail_lock) { struct gfs2_glock *gl = NULL; + struct address_space *mapping; struct gfs2_bufdata *bd, *s; struct buffer_head *bh; - int retry; - do { - retry = 0; +restart: + list_for_each_entry_safe_reverse(bd, s, &ai->ai_ail1_list, bd_ail_st_list) { + bh = bd->bd_bh; - list_for_each_entry_safe_reverse(bd, s, &ai->ai_ail1_list, - bd_ail_st_list) { - bh = bd->bd_bh; + gfs2_assert(sdp, bd->bd_ail == ai); - gfs2_assert(sdp, bd->bd_ail == ai); + if (!buffer_busy(bh)) { + if (!buffer_uptodate(bh)) + gfs2_io_error_bh(sdp, bh); + list_move(&bd->bd_ail_st_list, &ai->ai_ail2_list); + continue; + } + + if (!buffer_dirty(bh)) + continue; + if (gl == bd->bd_gl) + continue; + gl = bd->bd_gl; + list_move(&bd->bd_ail_st_list, &ai->ai_ail1_list); + mapping = bh->b_page->mapping; + spin_unlock(&sdp->sd_ail_lock); + generic_writepages(mapping, wbc); + spin_lock(&sdp->sd_ail_lock); + if (wbc->nr_to_write <= 0) + break; + goto restart; + } +} - if (!buffer_busy(bh)) { - if (!buffer_uptodate(bh)) - gfs2_io_error_bh(sdp, bh); - list_move(&bd->bd_ail_st_list, &ai->ai_ail2_list); - continue; - } - if (!buffer_dirty(bh)) - continue; - if (gl == bd->bd_gl) - continue; - gl = bd->bd_gl; - list_move(&bd->bd_ail_st_list, &ai->ai_ail1_list); +/** + * gfs2_ail1_flush - start writeback of some ail1 entries + * @sdp: The super block + * @wbc: The writeback control structure + * + * Writes back some ail1 entries, according to the limits in the + * writeback control structure + */ - spin_unlock(&sdp->sd_ail_lock); - filemap_fdatawrite(gfs2_glock2aspace(gl)); - spin_lock(&sdp->sd_ail_lock); +void gfs2_ail1_flush(struct gfs2_sbd *sdp, struct writeback_control *wbc) +{ + struct list_head *head = &sdp->sd_ail1_list; + struct gfs2_ail *ai; - retry = 1; + spin_lock(&sdp->sd_ail_lock); + list_for_each_entry_reverse(ai, head, ai_list) { + if (wbc->nr_to_write <= 0) break; - } - } while (retry); + gfs2_ail1_start_one(sdp, wbc, ai); /* This may drop ail lock */ + } + spin_unlock(&sdp->sd_ail_lock); +} + +/** + * gfs2_ail1_start - start writeback of all ail1 entries + * @sdp: The superblock + */ + +static void gfs2_ail1_start(struct gfs2_sbd *sdp) +{ + struct writeback_control wbc = { + .sync_mode = WB_SYNC_NONE, + .nr_to_write = LONG_MAX, + .range_start = 0, + .range_end = LLONG_MAX, + }; + + return gfs2_ail1_flush(sdp, &wbc); } /** @@ -136,7 +177,7 @@ __acquires(&sdp->sd_ail_lock) * */ -static int gfs2_ail1_empty_one(struct gfs2_sbd *sdp, struct gfs2_ail *ai, int flags) +static void gfs2_ail1_empty_one(struct gfs2_sbd *sdp, struct gfs2_ail *ai) { struct gfs2_bufdata *bd, *s; struct buffer_head *bh; @@ -144,71 +185,37 @@ static int gfs2_ail1_empty_one(struct gfs2_sbd *sdp, struct gfs2_ail *ai, int fl list_for_each_entry_safe_reverse(bd, s, &ai->ai_ail1_list, bd_ail_st_list) { bh = bd->bd_bh; - gfs2_assert(sdp, bd->bd_ail == ai); - - if (buffer_busy(bh)) { - if (flags & DIO_ALL) - continue; - else - break; - } - + if (buffer_busy(bh)) + continue; if (!buffer_uptodate(bh)) gfs2_io_error_bh(sdp, bh); - list_move(&bd->bd_ail_st_list, &ai->ai_ail2_list); } - return list_empty(&ai->ai_ail1_list); } -static void gfs2_ail1_start(struct gfs2_sbd *sdp) -{ - struct list_head *head; - u64 sync_gen; - struct gfs2_ail *ai; - int done = 0; - - spin_lock(&sdp->sd_ail_lock); - head = &sdp->sd_ail1_list; - if (list_empty(head)) { - spin_unlock(&sdp->sd_ail_lock); - return; - } - sync_gen = sdp->sd_ail_sync_gen++; - - while(!done) { - done = 1; - list_for_each_entry_reverse(ai, head, ai_list) { - if (ai->ai_sync_gen >= sync_gen) - continue; - ai->ai_sync_gen = sync_gen; - gfs2_ail1_start_one(sdp, ai); /* This may drop ail lock */ - done = 0; - break; - } - } - - spin_unlock(&sdp->sd_ail_lock); -} +/** + * gfs2_ail1_empty - Try to empty the ail1 lists + * @sdp: The superblock + * + * Tries to empty the ail1 lists, starting with the oldest first + */ -static int gfs2_ail1_empty(struct gfs2_sbd *sdp, int flags) +static int gfs2_ail1_empty(struct gfs2_sbd *sdp) { struct gfs2_ail *ai, *s; int ret; spin_lock(&sdp->sd_ail_lock); - list_for_each_entry_safe_reverse(ai, s, &sdp->sd_ail1_list, ai_list) { - if (gfs2_ail1_empty_one(sdp, ai, flags)) + gfs2_ail1_empty_one(sdp, ai); + if (list_empty(&ai->ai_ail1_list)) list_move(&ai->ai_list, &sdp->sd_ail2_list); - else if (!(flags & DIO_ALL)) + else break; } - ret = list_empty(&sdp->sd_ail1_list); - spin_unlock(&sdp->sd_ail_lock); return ret; @@ -569,7 +576,7 @@ static void log_write_header(struct gfs2_sbd *sdp, u32 flags, int pull) set_buffer_uptodate(bh); clear_buffer_dirty(bh); - gfs2_ail1_empty(sdp, 0); + gfs2_ail1_empty(sdp); tail = current_tail(sdp); lh = (struct gfs2_log_header *)bh->b_data; @@ -864,7 +871,7 @@ void gfs2_meta_syncfs(struct gfs2_sbd *sdp) gfs2_log_flush(sdp, NULL); for (;;) { gfs2_ail1_start(sdp); - if (gfs2_ail1_empty(sdp, DIO_ALL)) + if (gfs2_ail1_empty(sdp)) break; msleep(10); } @@ -900,17 +907,15 @@ int gfs2_logd(void *data) preflush = atomic_read(&sdp->sd_log_pinned); if (gfs2_jrnl_flush_reqd(sdp) || t == 0) { - gfs2_ail1_empty(sdp, DIO_ALL); + gfs2_ail1_empty(sdp); gfs2_log_flush(sdp, NULL); - gfs2_ail1_empty(sdp, DIO_ALL); } if (gfs2_ail_flush_reqd(sdp)) { gfs2_ail1_start(sdp); io_schedule(); - gfs2_ail1_empty(sdp, 0); + gfs2_ail1_empty(sdp); gfs2_log_flush(sdp, NULL); - gfs2_ail1_empty(sdp, DIO_ALL); } wake_up(&sdp->sd_log_waitq); diff --git a/fs/gfs2/log.h b/fs/gfs2/log.h index 0d007f9..ab06216 100644 --- a/fs/gfs2/log.h +++ b/fs/gfs2/log.h @@ -12,6 +12,7 @@ #include #include +#include #include "incore.h" /** @@ -59,6 +60,7 @@ extern struct buffer_head *gfs2_log_fake_buf(struct gfs2_sbd *sdp, extern void gfs2_log_flush(struct gfs2_sbd *sdp, struct gfs2_glock *gl); extern void gfs2_log_commit(struct gfs2_sbd *sdp, struct gfs2_trans *trans); extern void gfs2_remove_from_ail(struct gfs2_bufdata *bd); +extern void gfs2_ail1_flush(struct gfs2_sbd *sdp, struct writeback_control *wbc); extern void gfs2_log_shutdown(struct gfs2_sbd *sdp); extern void gfs2_meta_syncfs(struct gfs2_sbd *sdp); diff --git a/fs/gfs2/super.c b/fs/gfs2/super.c index 215c37b..58fe3a4 100644 --- a/fs/gfs2/super.c +++ b/fs/gfs2/super.c @@ -23,6 +23,7 @@ #include #include #include +#include #include "gfs2.h" #include "incore.h" @@ -714,6 +715,7 @@ static int gfs2_write_inode(struct inode *inode, struct writeback_control *wbc) struct gfs2_inode *ip = GFS2_I(inode); struct gfs2_sbd *sdp = GFS2_SB(inode); struct address_space *metamapping = gfs2_glock2aspace(ip->i_gl); + struct backing_dev_info *bdi = metamapping->backing_dev_info; struct gfs2_holder gh; struct buffer_head *bh; struct timespec atime; @@ -747,6 +749,8 @@ do_flush: if (wbc->sync_mode == WB_SYNC_ALL) gfs2_log_flush(GFS2_SB(inode), ip->i_gl); filemap_fdatawrite(metamapping); + if (bdi->dirty_exceeded) + gfs2_ail1_flush(sdp, wbc); if (!ret && (wbc->sync_mode == WB_SYNC_ALL)) ret = filemap_fdatawait(metamapping); if (ret) @@ -1366,7 +1370,8 @@ static int gfs2_dinode_dealloc(struct gfs2_inode *ip) if (error) goto out_rindex_relse; - error = gfs2_trans_begin(sdp, RES_RG_BIT + RES_STATFS + RES_QUOTA, 1); + error = gfs2_trans_begin(sdp, RES_RG_BIT + RES_STATFS + RES_QUOTA, + sdp->sd_jdesc->jd_blocks); if (error) goto out_rg_gunlock; -- cgit v0.10.2 From c83ae9cad8776bab153a05cc466be39f14011091 Mon Sep 17 00:00:00 2001 From: Steven Whitehouse Date: Mon, 18 Apr 2011 14:18:38 +0100 Subject: GFS2: Add an AIL writeback tracepoint Add a tracepoint for monitoring writeback of the AIL. Signed-off-by: Steven Whitehouse diff --git a/fs/gfs2/log.c b/fs/gfs2/log.c index 03e0041..ad1f188 100644 --- a/fs/gfs2/log.c +++ b/fs/gfs2/log.c @@ -144,6 +144,7 @@ void gfs2_ail1_flush(struct gfs2_sbd *sdp, struct writeback_control *wbc) struct list_head *head = &sdp->sd_ail1_list; struct gfs2_ail *ai; + trace_gfs2_ail_flush(sdp, wbc, 1); spin_lock(&sdp->sd_ail_lock); list_for_each_entry_reverse(ai, head, ai_list) { if (wbc->nr_to_write <= 0) @@ -151,6 +152,7 @@ void gfs2_ail1_flush(struct gfs2_sbd *sdp, struct writeback_control *wbc) gfs2_ail1_start_one(sdp, wbc, ai); /* This may drop ail lock */ } spin_unlock(&sdp->sd_ail_lock); + trace_gfs2_ail_flush(sdp, wbc, 0); } /** diff --git a/fs/gfs2/trace_gfs2.h b/fs/gfs2/trace_gfs2.h index 9133d0a..5d07609 100644 --- a/fs/gfs2/trace_gfs2.h +++ b/fs/gfs2/trace_gfs2.h @@ -10,6 +10,7 @@ #include #include #include +#include #include "incore.h" #include "glock.h" @@ -320,6 +321,33 @@ TRACE_EVENT(gfs2_log_blocks, MINOR(__entry->dev), __entry->blocks) ); +/* Writing back the AIL */ +TRACE_EVENT(gfs2_ail_flush, + + TP_PROTO(const struct gfs2_sbd *sdp, const struct writeback_control *wbc, int start), + + TP_ARGS(sdp, wbc, start), + + TP_STRUCT__entry( + __field( dev_t, dev ) + __field( int, start ) + __field( int, sync_mode ) + __field( long, nr_to_write ) + ), + + TP_fast_assign( + __entry->dev = sdp->sd_vfs->s_dev; + __entry->start = start; + __entry->sync_mode = wbc->sync_mode; + __entry->nr_to_write = wbc->nr_to_write; + ), + + TP_printk("%u,%u ail flush %s %s %ld", MAJOR(__entry->dev), + MINOR(__entry->dev), __entry->start ? "start" : "end", + __entry->sync_mode == WB_SYNC_ALL ? "all" : "none", + __entry->nr_to_write) +); + /* Section 3 - bmap * * Objectives: -- cgit v0.10.2 From 65f8da475995f667af5298c644707dbd9d646ca6 Mon Sep 17 00:00:00 2001 From: Stefan Weinhuber Date: Wed, 20 Apr 2011 10:15:30 +0200 Subject: [S390] dasd: fix race between open and offline The dasd_open function uses the private_data pointer of the gendisk to find the dasd_block structure that matches the gendisk. When a DASD device is set offline, we set the private_data pointer of the gendisk to NULL and later remove the dasd_block structure, but there is still a small race window, in which dasd_open could first read a pointer from the private_data field and then try to use it, after the structure has already been freed. To close this race window, we will store a pointer to the dasd_devmap structure of the base device in the private_data field. The devmap entries are not deleted, and we already have proper locking and reference counting in place, so that we can safely get from a devmap pointer to the dasd_device and dasd_block structures of the device. Signed-off-by: Stefan Weinhuber Signed-off-by: Martin Schwidefsky diff --git a/drivers/s390/block/dasd.c b/drivers/s390/block/dasd.c index 4d2df2f..475e603 100644 --- a/drivers/s390/block/dasd.c +++ b/drivers/s390/block/dasd.c @@ -2314,15 +2314,14 @@ static void dasd_flush_request_queue(struct dasd_block *block) static int dasd_open(struct block_device *bdev, fmode_t mode) { - struct dasd_block *block = bdev->bd_disk->private_data; struct dasd_device *base; int rc; - if (!block) + base = dasd_device_from_gendisk(bdev->bd_disk); + if (!base) return -ENODEV; - base = block->base; - atomic_inc(&block->open_count); + atomic_inc(&base->block->open_count); if (test_bit(DASD_FLAG_OFFLINE, &base->flags)) { rc = -ENODEV; goto unlock; @@ -2355,21 +2354,28 @@ static int dasd_open(struct block_device *bdev, fmode_t mode) goto out; } + dasd_put_device(base); return 0; out: module_put(base->discipline->owner); unlock: - atomic_dec(&block->open_count); + atomic_dec(&base->block->open_count); + dasd_put_device(base); return rc; } static int dasd_release(struct gendisk *disk, fmode_t mode) { - struct dasd_block *block = disk->private_data; + struct dasd_device *base; - atomic_dec(&block->open_count); - module_put(block->base->discipline->owner); + base = dasd_device_from_gendisk(disk); + if (!base) + return -ENODEV; + + atomic_dec(&base->block->open_count); + module_put(base->discipline->owner); + dasd_put_device(base); return 0; } @@ -2378,20 +2384,20 @@ static int dasd_release(struct gendisk *disk, fmode_t mode) */ static int dasd_getgeo(struct block_device *bdev, struct hd_geometry *geo) { - struct dasd_block *block; struct dasd_device *base; - block = bdev->bd_disk->private_data; - if (!block) + base = dasd_device_from_gendisk(bdev->bd_disk); + if (!base) return -ENODEV; - base = block->base; if (!base->discipline || - !base->discipline->fill_geometry) + !base->discipline->fill_geometry) { + dasd_put_device(base); return -EINVAL; - - base->discipline->fill_geometry(block, geo); - geo->start = get_start_sect(bdev) >> block->s2b_shift; + } + base->discipline->fill_geometry(base->block, geo); + geo->start = get_start_sect(bdev) >> base->block->s2b_shift; + dasd_put_device(base); return 0; } @@ -2528,7 +2534,6 @@ void dasd_generic_remove(struct ccw_device *cdev) dasd_set_target_state(device, DASD_STATE_NEW); /* dasd_delete_device destroys the device reference. */ block = device->block; - device->block = NULL; dasd_delete_device(device); /* * life cycle of block is bound to device, so delete it after @@ -2650,7 +2655,6 @@ int dasd_generic_set_offline(struct ccw_device *cdev) dasd_set_target_state(device, DASD_STATE_NEW); /* dasd_delete_device destroys the device reference. */ block = device->block; - device->block = NULL; dasd_delete_device(device); /* * life cycle of block is bound to device, so delete it after diff --git a/drivers/s390/block/dasd_devmap.c b/drivers/s390/block/dasd_devmap.c index 42e1bf3..d71511c 100644 --- a/drivers/s390/block/dasd_devmap.c +++ b/drivers/s390/block/dasd_devmap.c @@ -674,6 +674,36 @@ dasd_device_from_cdev(struct ccw_device *cdev) return device; } +void dasd_add_link_to_gendisk(struct gendisk *gdp, struct dasd_device *device) +{ + struct dasd_devmap *devmap; + + devmap = dasd_find_busid(dev_name(&device->cdev->dev)); + if (IS_ERR(devmap)) + return; + spin_lock(&dasd_devmap_lock); + gdp->private_data = devmap; + spin_unlock(&dasd_devmap_lock); +} + +struct dasd_device *dasd_device_from_gendisk(struct gendisk *gdp) +{ + struct dasd_device *device; + struct dasd_devmap *devmap; + + if (!gdp->private_data) + return NULL; + device = NULL; + spin_lock(&dasd_devmap_lock); + devmap = gdp->private_data; + if (devmap && devmap->device) { + device = devmap->device; + dasd_get_device(device); + } + spin_unlock(&dasd_devmap_lock); + return device; +} + /* * SECTION: files in sysfs */ diff --git a/drivers/s390/block/dasd_genhd.c b/drivers/s390/block/dasd_genhd.c index 5505bc0..19a1ff0 100644 --- a/drivers/s390/block/dasd_genhd.c +++ b/drivers/s390/block/dasd_genhd.c @@ -73,7 +73,7 @@ int dasd_gendisk_alloc(struct dasd_block *block) if (base->features & DASD_FEATURE_READONLY || test_bit(DASD_FLAG_DEVICE_RO, &base->flags)) set_disk_ro(gdp, 1); - gdp->private_data = block; + dasd_add_link_to_gendisk(gdp, base); gdp->queue = block->request_queue; block->gdp = gdp; set_capacity(block->gdp, 0); diff --git a/drivers/s390/block/dasd_int.h b/drivers/s390/block/dasd_int.h index df9f699..d1e4f2c 100644 --- a/drivers/s390/block/dasd_int.h +++ b/drivers/s390/block/dasd_int.h @@ -686,6 +686,9 @@ struct dasd_device *dasd_device_from_cdev(struct ccw_device *); struct dasd_device *dasd_device_from_cdev_locked(struct ccw_device *); struct dasd_device *dasd_device_from_devindex(int); +void dasd_add_link_to_gendisk(struct gendisk *, struct dasd_device *); +struct dasd_device *dasd_device_from_gendisk(struct gendisk *); + int dasd_parse(void); int dasd_busid_known(const char *); diff --git a/drivers/s390/block/dasd_ioctl.c b/drivers/s390/block/dasd_ioctl.c index 26075e9..72261e4 100644 --- a/drivers/s390/block/dasd_ioctl.c +++ b/drivers/s390/block/dasd_ioctl.c @@ -42,16 +42,22 @@ dasd_ioctl_api_version(void __user *argp) static int dasd_ioctl_enable(struct block_device *bdev) { - struct dasd_block *block = bdev->bd_disk->private_data; + struct dasd_device *base; if (!capable(CAP_SYS_ADMIN)) return -EACCES; - dasd_enable_device(block->base); + base = dasd_device_from_gendisk(bdev->bd_disk); + if (!base) + return -ENODEV; + + dasd_enable_device(base); /* Formatting the dasd device can change the capacity. */ mutex_lock(&bdev->bd_mutex); - i_size_write(bdev->bd_inode, (loff_t)get_capacity(block->gdp) << 9); + i_size_write(bdev->bd_inode, + (loff_t)get_capacity(base->block->gdp) << 9); mutex_unlock(&bdev->bd_mutex); + dasd_put_device(base); return 0; } @@ -62,11 +68,14 @@ dasd_ioctl_enable(struct block_device *bdev) static int dasd_ioctl_disable(struct block_device *bdev) { - struct dasd_block *block = bdev->bd_disk->private_data; + struct dasd_device *base; if (!capable(CAP_SYS_ADMIN)) return -EACCES; + base = dasd_device_from_gendisk(bdev->bd_disk); + if (!base) + return -ENODEV; /* * Man this is sick. We don't do a real disable but only downgrade * the device to DASD_STATE_BASIC. The reason is that dasdfmt uses @@ -75,7 +84,7 @@ dasd_ioctl_disable(struct block_device *bdev) * using the BIODASDFMT ioctl. Therefore the correct state for the * device is DASD_STATE_BASIC that allows to do basic i/o. */ - dasd_set_target_state(block->base, DASD_STATE_BASIC); + dasd_set_target_state(base, DASD_STATE_BASIC); /* * Set i_size to zero, since read, write, etc. check against this * value. @@ -83,6 +92,7 @@ dasd_ioctl_disable(struct block_device *bdev) mutex_lock(&bdev->bd_mutex); i_size_write(bdev->bd_inode, 0); mutex_unlock(&bdev->bd_mutex); + dasd_put_device(base); return 0; } @@ -191,26 +201,36 @@ static int dasd_format(struct dasd_block *block, struct format_data_t *fdata) static int dasd_ioctl_format(struct block_device *bdev, void __user *argp) { - struct dasd_block *block = bdev->bd_disk->private_data; + struct dasd_device *base; struct format_data_t fdata; + int rc; if (!capable(CAP_SYS_ADMIN)) return -EACCES; if (!argp) return -EINVAL; - - if (block->base->features & DASD_FEATURE_READONLY || - test_bit(DASD_FLAG_DEVICE_RO, &block->base->flags)) + base = dasd_device_from_gendisk(bdev->bd_disk); + if (!base) + return -ENODEV; + if (base->features & DASD_FEATURE_READONLY || + test_bit(DASD_FLAG_DEVICE_RO, &base->flags)) { + dasd_put_device(base); return -EROFS; - if (copy_from_user(&fdata, argp, sizeof(struct format_data_t))) + } + if (copy_from_user(&fdata, argp, sizeof(struct format_data_t))) { + dasd_put_device(base); return -EFAULT; + } if (bdev != bdev->bd_contains) { pr_warning("%s: The specified DASD is a partition and cannot " "be formatted\n", - dev_name(&block->base->cdev->dev)); + dev_name(&base->cdev->dev)); + dasd_put_device(base); return -EINVAL; } - return dasd_format(block, &fdata); + rc = dasd_format(base->block, &fdata); + dasd_put_device(base); + return rc; } #ifdef CONFIG_DASD_PROFILE @@ -340,8 +360,8 @@ static int dasd_ioctl_information(struct dasd_block *block, static int dasd_ioctl_set_ro(struct block_device *bdev, void __user *argp) { - struct dasd_block *block = bdev->bd_disk->private_data; - int intval; + struct dasd_device *base; + int intval, rc; if (!capable(CAP_SYS_ADMIN)) return -EACCES; @@ -350,10 +370,17 @@ dasd_ioctl_set_ro(struct block_device *bdev, void __user *argp) return -EINVAL; if (get_user(intval, (int __user *)argp)) return -EFAULT; - if (!intval && test_bit(DASD_FLAG_DEVICE_RO, &block->base->flags)) + base = dasd_device_from_gendisk(bdev->bd_disk); + if (!base) + return -ENODEV; + if (!intval && test_bit(DASD_FLAG_DEVICE_RO, &base->flags)) { + dasd_put_device(base); return -EROFS; + } set_disk_ro(bdev->bd_disk, intval); - return dasd_set_feature(block->base->cdev, DASD_FEATURE_READONLY, intval); + rc = dasd_set_feature(base->cdev, DASD_FEATURE_READONLY, intval); + dasd_put_device(base); + return rc; } static int dasd_ioctl_readall_cmb(struct dasd_block *block, unsigned int cmd, @@ -372,59 +399,78 @@ static int dasd_ioctl_readall_cmb(struct dasd_block *block, unsigned int cmd, int dasd_ioctl(struct block_device *bdev, fmode_t mode, unsigned int cmd, unsigned long arg) { - struct dasd_block *block = bdev->bd_disk->private_data; + struct dasd_block *block; + struct dasd_device *base; void __user *argp; + int rc; if (is_compat_task()) argp = compat_ptr(arg); else argp = (void __user *)arg; - if (!block) - return -ENODEV; - if ((_IOC_DIR(cmd) != _IOC_NONE) && !arg) { PRINT_DEBUG("empty data ptr"); return -EINVAL; } + base = dasd_device_from_gendisk(bdev->bd_disk); + if (!base) + return -ENODEV; + block = base->block; + rc = 0; switch (cmd) { case BIODASDDISABLE: - return dasd_ioctl_disable(bdev); + rc = dasd_ioctl_disable(bdev); + break; case BIODASDENABLE: - return dasd_ioctl_enable(bdev); + rc = dasd_ioctl_enable(bdev); + break; case BIODASDQUIESCE: - return dasd_ioctl_quiesce(block); + rc = dasd_ioctl_quiesce(block); + break; case BIODASDRESUME: - return dasd_ioctl_resume(block); + rc = dasd_ioctl_resume(block); + break; case BIODASDFMT: - return dasd_ioctl_format(bdev, argp); + rc = dasd_ioctl_format(bdev, argp); + break; case BIODASDINFO: - return dasd_ioctl_information(block, cmd, argp); + rc = dasd_ioctl_information(block, cmd, argp); + break; case BIODASDINFO2: - return dasd_ioctl_information(block, cmd, argp); + rc = dasd_ioctl_information(block, cmd, argp); + break; case BIODASDPRRD: - return dasd_ioctl_read_profile(block, argp); + rc = dasd_ioctl_read_profile(block, argp); + break; case BIODASDPRRST: - return dasd_ioctl_reset_profile(block); + rc = dasd_ioctl_reset_profile(block); + break; case BLKROSET: - return dasd_ioctl_set_ro(bdev, argp); + rc = dasd_ioctl_set_ro(bdev, argp); + break; case DASDAPIVER: - return dasd_ioctl_api_version(argp); + rc = dasd_ioctl_api_version(argp); + break; case BIODASDCMFENABLE: - return enable_cmf(block->base->cdev); + rc = enable_cmf(base->cdev); + break; case BIODASDCMFDISABLE: - return disable_cmf(block->base->cdev); + rc = disable_cmf(base->cdev); + break; case BIODASDREADALLCMB: - return dasd_ioctl_readall_cmb(block, cmd, argp); + rc = dasd_ioctl_readall_cmb(block, cmd, argp); + break; default: /* if the discipline has an ioctl method try it. */ - if (block->base->discipline->ioctl) { - int rval = block->base->discipline->ioctl(block, cmd, argp); - if (rval != -ENOIOCTLCMD) - return rval; - } - - return -EINVAL; + if (base->discipline->ioctl) { + rc = base->discipline->ioctl(block, cmd, argp); + if (rc == -ENOIOCTLCMD) + rc = -EINVAL; + } else + rc = -EINVAL; } + dasd_put_device(base); + return rc; } -- cgit v0.10.2 From c708c57e247775928b9a6bce7b4d8d14883bf39b Mon Sep 17 00:00:00 2001 From: Jan Glauber Date: Wed, 20 Apr 2011 10:15:31 +0200 Subject: [S390] prng: prevent access beyond end of stack While initializing the state of the prng only the first 8 bytes of random data where used, the second 8 bytes were read from the memory after the stack. If only 64 bytes of the kernel stack are used and CONFIG_DEBUG_PAGEALLOC is enabled a kernel panic may occur because of the invalid page access. Use the correct multiplicator to stay within the random data buffer. Signed-off-by: Jan Glauber Signed-off-by: Martin Schwidefsky diff --git a/arch/s390/crypto/prng.c b/arch/s390/crypto/prng.c index 975e3ab..44bca3f 100644 --- a/arch/s390/crypto/prng.c +++ b/arch/s390/crypto/prng.c @@ -76,7 +76,7 @@ static void prng_seed(int nbytes) /* Add the entropy */ while (nbytes >= 8) { - *((__u64 *)parm_block) ^= *((__u64 *)buf+i*8); + *((__u64 *)parm_block) ^= *((__u64 *)buf+i); prng_add_entropy(); i += 8; nbytes -= 8; -- cgit v0.10.2 From e4c031b4f2515e9531d71c8aa779799231dbcd0c Mon Sep 17 00:00:00 2001 From: Jan Glauber Date: Wed, 20 Apr 2011 10:15:32 +0200 Subject: [S390] fix page table walk for changing page attributes The page table walk for changing page attributes used the wrong address for pgd/pud/pmd lookups if the range was bigger than a pmd entry. Fix the lookup by using the correct address. Signed-off-by: Jan Glauber Signed-off-by: Martin Schwidefsky diff --git a/arch/s390/mm/pageattr.c b/arch/s390/mm/pageattr.c index 122ffbd..0607e4b 100644 --- a/arch/s390/mm/pageattr.c +++ b/arch/s390/mm/pageattr.c @@ -24,12 +24,13 @@ static void change_page_attr(unsigned long addr, int numpages, WARN_ON_ONCE(1); continue; } - ptep = pte_offset_kernel(pmdp, addr + i * PAGE_SIZE); + ptep = pte_offset_kernel(pmdp, addr); pte = *ptep; pte = set(pte); - ptep_invalidate(&init_mm, addr + i * PAGE_SIZE, ptep); + ptep_invalidate(&init_mm, addr, ptep); *ptep = pte; + addr += PAGE_SIZE; } } -- cgit v0.10.2 From bffbbd2df4196a73ffdc16709866dd96eb66aad8 Mon Sep 17 00:00:00 2001 From: Jan Glauber Date: Wed, 20 Apr 2011 10:15:33 +0200 Subject: [S390] qdio: reset error states immediately The qdio hardware may surpress further interrupts as long as a SBAL is in the error state. That can lead to unnotified data in the SBALs following the error state. To prevent this behaviour change the SBAL[s] in error state immediately to another program owned state so interrupts are again received for further traffic on the device. Signed-off-by: Jan Glauber Signed-off-by: Martin Schwidefsky diff --git a/drivers/s390/cio/qdio_main.c b/drivers/s390/cio/qdio_main.c index c532ba9..e8f267e 100644 --- a/drivers/s390/cio/qdio_main.c +++ b/drivers/s390/cio/qdio_main.c @@ -407,8 +407,11 @@ static inline void account_sbals(struct qdio_q *q, int count) q->q_stats.nr_sbals[pos]++; } -static void announce_buffer_error(struct qdio_q *q, int count) +static void process_buffer_error(struct qdio_q *q, int count) { + unsigned char state = (q->is_input_q) ? SLSB_P_INPUT_NOT_INIT : + SLSB_P_OUTPUT_NOT_INIT; + q->qdio_error |= QDIO_ERROR_SLSB_STATE; /* special handling for no target buffer empty */ @@ -426,6 +429,12 @@ static void announce_buffer_error(struct qdio_q *q, int count) DBF_ERROR("F14:%2x F15:%2x", q->sbal[q->first_to_check]->element[14].flags & 0xff, q->sbal[q->first_to_check]->element[15].flags & 0xff); + + /* + * Interrupts may be avoided as long as the error is present + * so change the buffer state immediately to avoid starvation. + */ + set_buf_states(q, q->first_to_check, state, count); } static inline void inbound_primed(struct qdio_q *q, int count) @@ -506,8 +515,7 @@ static int get_inbound_buffer_frontier(struct qdio_q *q) account_sbals(q, count); break; case SLSB_P_INPUT_ERROR: - announce_buffer_error(q, count); - /* process the buffer, the upper layer will take care of it */ + process_buffer_error(q, count); q->first_to_check = add_buf(q->first_to_check, count); atomic_sub(count, &q->nr_buf_used); if (q->irq_ptr->perf_stat_enabled) @@ -677,8 +685,7 @@ static int get_outbound_buffer_frontier(struct qdio_q *q) account_sbals(q, count); break; case SLSB_P_OUTPUT_ERROR: - announce_buffer_error(q, count); - /* process the buffer, the upper layer will take care of it */ + process_buffer_error(q, count); q->first_to_check = add_buf(q->first_to_check, count); atomic_sub(count, &q->nr_buf_used); if (q->irq_ptr->perf_stat_enabled) -- cgit v0.10.2 From e35c76cd47c244eaa7a74adaabde4d0a1cadb907 Mon Sep 17 00:00:00 2001 From: Heiko Carstens Date: Wed, 20 Apr 2011 10:15:34 +0200 Subject: [S390] pfault: fix token handling f6649a7e "[S390] cleanup lowcore access from external interrupts" changed handling of external interrupts. Instead of letting the external interrupt handlers accessing the per cpu lowcore the entry code of the kernel reads already all fields that are necessary and passes them to the handlers. The pfault interrupt handler was incorrectly converted. It tries to dereference a value which used to be a pointer to a lowcore field. After the conversion however it is not anymore the pointer to the field but its content. So instead of a dereference only a cast is needed to get the task pointer that caused the pfault. Fixes a NULL pointer dereference and a subsequent kernel crash: Unable to handle kernel pointer dereference at virtual kernel address (null) Oops: 0004 [#1] SMP Modules linked in: nfsd exportfs nfs lockd fscache nfs_acl auth_rpcgss sunrpc loop qeth_l3 qeth vmur ccwgroup ext3 jbd mbcache dm_mod dasd_eckd_mod dasd_diag_mod dasd_mod CPU: 0 Not tainted 2.6.38-2-s390x #1 Process cron (pid: 1106, task: 000000001f962f78, ksp: 000000001fa0f9d0) Krnl PSW : 0404200180000000 000000000002c03e (pfault_interrupt+0xa2/0x138) R:0 T:1 IO:0 EX:0 Key:0 M:1 W:0 P:0 AS:0 CC:2 PM:0 EA:3 Krnl GPRS: 0000000000000000 0000000000000001 0000000000000000 0000000000000001 000000001f962f78 0000000000518968 0000000090000002 000000001ff03280 0000000000000000 000000000064f000 000000001f962f78 0000000000002603 0000000006002603 0000000000000000 000000001ff7fe68 000000001ff7fe48 Krnl Code: 000000000002c036: 5820d010 l %r2,16(%r13) 000000000002c03a: 1832 lr %r3,%r2 000000000002c03c: 1a31 ar %r3,%r1 >000000000002c03e: ba23d010 cs %r2,%r3,16(%r13) 000000000002c042: a744fffc brc 4,2c03a 000000000002c046: a7290002 lghi %r2,2 000000000002c04a: e320d0000024 stg %r2,0(%r13) 000000000002c050: 07f0 bcr 15,%r0 Call Trace: ([<000000001f962f78>] 0x1f962f78) [<000000000001acda>] do_extint+0xf6/0x138 [<000000000039b6ca>] ext_no_vtime+0x30/0x34 [<000000007d706e04>] 0x7d706e04 Last Breaking-Event-Address: [<0000000000000000>] 0x0 For stable maintainers: the first kernel which contains this bug is 2.6.37. Reported-by: Stephen Powell Cc: Jonathan Nieder Cc: stable@kernel.org Signed-off-by: Heiko Carstens Signed-off-by: Martin Schwidefsky diff --git a/arch/s390/mm/fault.c b/arch/s390/mm/fault.c index 9217e33..4cf85fe 100644 --- a/arch/s390/mm/fault.c +++ b/arch/s390/mm/fault.c @@ -558,9 +558,9 @@ static void pfault_interrupt(unsigned int ext_int_code, * Get the token (= address of the task structure of the affected task). */ #ifdef CONFIG_64BIT - tsk = *(struct task_struct **) param64; + tsk = (struct task_struct *) param64; #else - tsk = *(struct task_struct **) param32; + tsk = (struct task_struct *) param32; #endif if (subcode & 0x0080) { -- cgit v0.10.2 From c7a29e56f0a3526b71e9694b403b8e2cbe9c31e5 Mon Sep 17 00:00:00 2001 From: Stefan Weinhuber Date: Wed, 20 Apr 2011 10:15:35 +0200 Subject: [S390] dasd: check sense type in device change handler When evaluating sense data in dasd_eckd_check_for_device_change, we must always check for the type of sense data in byte 27, bit 0, to make sure that the rest of the sense data is interpreted correctly. Signed-off-by: Stefan Weinhuber Signed-off-by: Martin Schwidefsky diff --git a/drivers/s390/block/dasd_eckd.c b/drivers/s390/block/dasd_eckd.c index db8005d..3ebdf5f 100644 --- a/drivers/s390/block/dasd_eckd.c +++ b/drivers/s390/block/dasd_eckd.c @@ -2037,7 +2037,7 @@ static void dasd_eckd_check_for_device_change(struct dasd_device *device, return; /* summary unit check */ - if ((sense[7] == 0x0D) && + if ((sense[27] & DASD_SENSE_BIT_0) && (sense[7] == 0x0D) && (scsw_dstat(&irb->scsw) & DEV_STAT_UNIT_CHECK)) { dasd_alias_handle_summary_unit_check(device, irb); return; @@ -2053,7 +2053,8 @@ static void dasd_eckd_check_for_device_change(struct dasd_device *device, /* loss of device reservation is handled via base devices only * as alias devices may be used with several bases */ - if (device->block && (sense[7] == 0x3F) && + if (device->block && (sense[27] & DASD_SENSE_BIT_0) && + (sense[7] == 0x3F) && (scsw_dstat(&irb->scsw) & DEV_STAT_UNIT_CHECK) && test_bit(DASD_FLAG_IS_RESERVED, &device->flags)) { if (device->features & DASD_FEATURE_FAILONSLCK) -- cgit v0.10.2 From 9ff4cfb3fcfd48b49fdd9be7381b3be340853aa4 Mon Sep 17 00:00:00 2001 From: Carsten Otte Date: Wed, 20 Apr 2011 10:15:36 +0200 Subject: [S390] kvm-390: Let kernel exit SIE instruction on work From: Christian Borntraeger This patch fixes the sie exit on interrupts. The low level interrupt handler returns to the PSW address in pt_regs and not to the PSW address in the lowcore. Without this fix a cpu bound guest might never leave guest state since the host interrupt handler would blindly return to the SIE instruction, even on need_resched and friends. Cc: stable@kernel.org Signed-off-by: Carsten Otte Signed-off-by: Christian Borntraeger Signed-off-by: Martin Schwidefsky diff --git a/arch/s390/kvm/sie64a.S b/arch/s390/kvm/sie64a.S index 7e9d30d..ab0e041 100644 --- a/arch/s390/kvm/sie64a.S +++ b/arch/s390/kvm/sie64a.S @@ -48,10 +48,10 @@ sie_irq_handler: tm __TI_flags+7(%r2),_TIF_EXIT_SIE jz 0f larl %r2,sie_exit # work pending, leave sie - stg %r2,__LC_RETURN_PSW+8 + stg %r2,SPI_PSW+8(0,%r15) br %r14 0: larl %r2,sie_reenter # re-enter with guest id - stg %r2,__LC_RETURN_PSW+8 + stg %r2,SPI_PSW+8(0,%r15) 1: br %r14 /* -- cgit v0.10.2 From 290129f9880302d4fa468f7ff2f72de4b4d418ae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Miros=C5=82aw?= Date: Tue, 19 Apr 2011 00:43:19 +0000 Subject: net: dsa: remove ethtool_ops->set_sg MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Remove set_sg from DSA slave ethtool_ops. Features inheritance looks broken/not fully implemented anyway. Signed-off-by: MichaÅ‚ MirosÅ‚aw Signed-off-by: David S. Miller diff --git a/net/dsa/slave.c b/net/dsa/slave.c index 64ca2a6..0a47b6c 100644 --- a/net/dsa/slave.c +++ b/net/dsa/slave.c @@ -288,7 +288,6 @@ static const struct ethtool_ops dsa_slave_ethtool_ops = { .get_drvinfo = dsa_slave_get_drvinfo, .nway_reset = dsa_slave_nway_reset, .get_link = dsa_slave_get_link, - .set_sg = ethtool_op_set_sg, .get_strings = dsa_slave_get_strings, .get_ethtool_stats = dsa_slave_get_ethtool_stats, .get_sset_count = dsa_slave_get_sset_count, -- cgit v0.10.2 From 97dbee73978497c615a46d324e4f5629b9772f86 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Miros=C5=82aw?= Date: Tue, 19 Apr 2011 00:43:20 +0000 Subject: net: batman-adv: remove rx_csum ethtool_ops MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: MichaÅ‚ MirosÅ‚aw Signed-off-by: David S. Miller diff --git a/net/batman-adv/soft-interface.c b/net/batman-adv/soft-interface.c index 1f6f756..f4d80ad 100644 --- a/net/batman-adv/soft-interface.c +++ b/net/batman-adv/soft-interface.c @@ -43,8 +43,6 @@ static void bat_get_drvinfo(struct net_device *dev, static u32 bat_get_msglevel(struct net_device *dev); static void bat_set_msglevel(struct net_device *dev, u32 value); static u32 bat_get_link(struct net_device *dev); -static u32 bat_get_rx_csum(struct net_device *dev); -static int bat_set_rx_csum(struct net_device *dev, u32 data); static const struct ethtool_ops bat_ethtool_ops = { .get_settings = bat_get_settings, @@ -52,8 +50,6 @@ static const struct ethtool_ops bat_ethtool_ops = { .get_msglevel = bat_get_msglevel, .set_msglevel = bat_set_msglevel, .get_link = bat_get_link, - .get_rx_csum = bat_get_rx_csum, - .set_rx_csum = bat_set_rx_csum }; int my_skb_head_push(struct sk_buff *skb, unsigned int len) @@ -736,12 +732,3 @@ static u32 bat_get_link(struct net_device *dev) return 1; } -static u32 bat_get_rx_csum(struct net_device *dev) -{ - return 0; -} - -static int bat_set_rx_csum(struct net_device *dev, u32 data) -{ - return -EOPNOTSUPP; -} -- cgit v0.10.2 From 8727bfaa8a723009e9c6eb1bb57b90ebdb0a4126 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Miros=C5=82aw?= Date: Tue, 19 Apr 2011 00:43:20 +0000 Subject: Staging: convert hv network driver to hw_features MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: MichaÅ‚ MirosÅ‚aw Signed-off-by: David S. Miller diff --git a/drivers/staging/hv/netvsc_drv.c b/drivers/staging/hv/netvsc_drv.c index 3397356..aaa81883 100644 --- a/drivers/staging/hv/netvsc_drv.c +++ b/drivers/staging/hv/netvsc_drv.c @@ -317,8 +317,6 @@ static void netvsc_get_drvinfo(struct net_device *net, static const struct ethtool_ops ethtool_ops = { .get_drvinfo = netvsc_get_drvinfo, - .get_sg = ethtool_op_get_sg, - .set_sg = ethtool_op_set_sg, .get_link = ethtool_op_get_link, }; @@ -406,6 +404,7 @@ static int netvsc_probe(struct device *device) net->netdev_ops = &device_ops; /* TODO: Add GSO and Checksum offload */ + net->hw_features = NETIF_F_SG; net->features = NETIF_F_SG; SET_ETHTOOL_OPS(net, ðtool_ops); -- cgit v0.10.2 From dd6f6d024906b8f05a0832c78c16a1e818958321 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Miros=C5=82aw?= Date: Tue, 19 Apr 2011 00:43:20 +0000 Subject: net: infiniband/hw/nes: convert to hw_features MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: MichaÅ‚ MirosÅ‚aw Signed-off-by: David S. Miller diff --git a/drivers/infiniband/hw/nes/nes_hw.c b/drivers/infiniband/hw/nes/nes_hw.c index 10d0a5e..96fa9a4 100644 --- a/drivers/infiniband/hw/nes/nes_hw.c +++ b/drivers/infiniband/hw/nes/nes_hw.c @@ -2885,9 +2885,8 @@ void nes_nic_ce_handler(struct nes_device *nesdev, struct nes_hw_nic_cq *cq) if ((cqe_errv & (NES_NIC_ERRV_BITS_IPV4_CSUM_ERR | NES_NIC_ERRV_BITS_TCPUDP_CSUM_ERR | NES_NIC_ERRV_BITS_IPH_ERR | NES_NIC_ERRV_BITS_WQE_OVERRUN)) == 0) { - if (nesvnic->rx_checksum_disabled == 0) { + if (nesvnic->netdev->features & NETIF_F_RXCSUM) rx_skb->ip_summed = CHECKSUM_UNNECESSARY; - } } else nes_debug(NES_DBG_CQ, "%s: unsuccessfully checksummed TCP or UDP packet." " errv = 0x%X, pkt_type = 0x%X.\n", @@ -2897,7 +2896,7 @@ void nes_nic_ce_handler(struct nes_device *nesdev, struct nes_hw_nic_cq *cq) if ((cqe_errv & (NES_NIC_ERRV_BITS_IPV4_CSUM_ERR | NES_NIC_ERRV_BITS_IPH_ERR | NES_NIC_ERRV_BITS_WQE_OVERRUN)) == 0) { - if (nesvnic->rx_checksum_disabled == 0) { + if (nesvnic->netdev->features & NETIF_F_RXCSUM) { rx_skb->ip_summed = CHECKSUM_UNNECESSARY; /* nes_debug(NES_DBG_CQ, "%s: Reporting successfully checksummed IPv4 packet.\n", nesvnic->netdev->name); */ diff --git a/drivers/infiniband/hw/nes/nes_hw.h b/drivers/infiniband/hw/nes/nes_hw.h index d2abe07..9159411 100644 --- a/drivers/infiniband/hw/nes/nes_hw.h +++ b/drivers/infiniband/hw/nes/nes_hw.h @@ -1245,7 +1245,6 @@ struct nes_vnic { u8 next_qp_nic_index; u8 of_device_registered; u8 rdma_enabled; - u8 rx_checksum_disabled; u32 lro_max_aggr; struct net_lro_mgr lro_mgr; struct net_lro_desc lro_desc[NES_MAX_LRO_DESCRIPTORS]; diff --git a/drivers/infiniband/hw/nes/nes_nic.c b/drivers/infiniband/hw/nes/nes_nic.c index e96b8fb..d2e67c4 100644 --- a/drivers/infiniband/hw/nes/nes_nic.c +++ b/drivers/infiniband/hw/nes/nes_nic.c @@ -1093,34 +1093,6 @@ static const char nes_ethtool_stringset[][ETH_GSTRING_LEN] = { }; #define NES_ETHTOOL_STAT_COUNT ARRAY_SIZE(nes_ethtool_stringset) -/** - * nes_netdev_get_rx_csum - */ -static u32 nes_netdev_get_rx_csum (struct net_device *netdev) -{ - struct nes_vnic *nesvnic = netdev_priv(netdev); - - if (nesvnic->rx_checksum_disabled) - return 0; - else - return 1; -} - - -/** - * nes_netdev_set_rc_csum - */ -static int nes_netdev_set_rx_csum(struct net_device *netdev, u32 enable) -{ - struct nes_vnic *nesvnic = netdev_priv(netdev); - - if (enable) - nesvnic->rx_checksum_disabled = 0; - else - nesvnic->rx_checksum_disabled = 1; - return 0; -} - /** * nes_netdev_get_sset_count @@ -1598,19 +1570,10 @@ static int nes_netdev_set_settings(struct net_device *netdev, struct ethtool_cmd } -static int nes_netdev_set_flags(struct net_device *netdev, u32 flags) -{ - return ethtool_op_set_flags(netdev, flags, ETH_FLAG_LRO); -} - - static const struct ethtool_ops nes_ethtool_ops = { .get_link = ethtool_op_get_link, .get_settings = nes_netdev_get_settings, .set_settings = nes_netdev_set_settings, - .get_tx_csum = ethtool_op_get_tx_csum, - .get_rx_csum = nes_netdev_get_rx_csum, - .get_sg = ethtool_op_get_sg, .get_strings = nes_netdev_get_strings, .get_sset_count = nes_netdev_get_sset_count, .get_ethtool_stats = nes_netdev_get_ethtool_stats, @@ -1619,13 +1582,6 @@ static const struct ethtool_ops nes_ethtool_ops = { .set_coalesce = nes_netdev_set_coalesce, .get_pauseparam = nes_netdev_get_pauseparam, .set_pauseparam = nes_netdev_set_pauseparam, - .set_tx_csum = ethtool_op_set_tx_csum, - .set_rx_csum = nes_netdev_set_rx_csum, - .set_sg = ethtool_op_set_sg, - .get_tso = ethtool_op_get_tso, - .set_tso = ethtool_op_set_tso, - .get_flags = ethtool_op_get_flags, - .set_flags = nes_netdev_set_flags, }; @@ -1727,12 +1683,11 @@ struct net_device *nes_netdev_init(struct nes_device *nesdev, netdev->dev_addr[5] = (u8)u64temp; memcpy(netdev->perm_addr, netdev->dev_addr, 6); - if ((nesvnic->logical_port < 2) || (nesdev->nesadapter->hw_rev != NE020_REV)) { - netdev->features |= NETIF_F_TSO | NETIF_F_SG | NETIF_F_IP_CSUM; - netdev->features |= NETIF_F_GSO | NETIF_F_TSO | NETIF_F_SG | NETIF_F_IP_CSUM; - } else { - netdev->features |= NETIF_F_SG | NETIF_F_IP_CSUM; - } + netdev->hw_features = NETIF_F_RXCSUM | NETIF_F_SG | NETIF_F_IP_CSUM; + if ((nesvnic->logical_port < 2) || (nesdev->nesadapter->hw_rev != NE020_REV)) + netdev->hw_features |= NETIF_F_TSO; + netdev->features |= netdev->hw_features; + netdev->hw_features |= NETIF_F_LRO; nes_debug(NES_DBG_INIT, "nesvnic = %p, reported features = 0x%lX, QPid = %d," " nic_index = %d, logical_port = %d, mac_index = %d.\n", -- cgit v0.10.2 From 6204b47ec4394f7e472885c8d05d9cda96d97a25 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Miros=C5=82aw?= Date: Tue, 19 Apr 2011 00:43:20 +0000 Subject: net: s390: convert to hw_features MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit options.large_send was easy to get rid of. options.checksum_type has deeper roots so is left for later cleanup. Signed-off-by: MichaÅ‚ MirosÅ‚aw Signed-off-by: David S. Miller diff --git a/drivers/s390/net/qeth_core.h b/drivers/s390/net/qeth_core.h index af3f7b0..8d6146a 100644 --- a/drivers/s390/net/qeth_core.h +++ b/drivers/s390/net/qeth_core.h @@ -407,12 +407,6 @@ struct qeth_qdio_q { int next_buf_to_init; } __attribute__ ((aligned(256))); -/* possible types of qeth large_send support */ -enum qeth_large_send_types { - QETH_LARGE_SEND_NO, - QETH_LARGE_SEND_TSO, -}; - struct qeth_qdio_out_buffer { struct qdio_buffer *buffer; atomic_t state; @@ -651,7 +645,6 @@ struct qeth_card_options { int fake_broadcast; int add_hhlen; int layer2; - enum qeth_large_send_types large_send; int performance_stats; int rx_sg_cb; enum qeth_ipa_isolation_modes isolation; diff --git a/drivers/s390/net/qeth_l3_main.c b/drivers/s390/net/qeth_l3_main.c index 142e5f6..1496661 100644 --- a/drivers/s390/net/qeth_l3_main.c +++ b/drivers/s390/net/qeth_l3_main.c @@ -43,33 +43,6 @@ static int qeth_l3_deregister_addr_entry(struct qeth_card *, static int __qeth_l3_set_online(struct ccwgroup_device *, int); static int __qeth_l3_set_offline(struct ccwgroup_device *, int); -int qeth_l3_set_large_send(struct qeth_card *card, - enum qeth_large_send_types type) -{ - int rc = 0; - - card->options.large_send = type; - if (card->dev == NULL) - return 0; - - if (card->options.large_send == QETH_LARGE_SEND_TSO) { - if (qeth_is_supported(card, IPA_OUTBOUND_TSO)) { - card->dev->features |= NETIF_F_TSO | NETIF_F_SG | - NETIF_F_IP_CSUM; - } else { - card->dev->features &= ~(NETIF_F_TSO | NETIF_F_SG | - NETIF_F_IP_CSUM); - card->options.large_send = QETH_LARGE_SEND_NO; - rc = -EOPNOTSUPP; - } - } else { - card->dev->features &= ~(NETIF_F_TSO | NETIF_F_SG | - NETIF_F_IP_CSUM); - card->options.large_send = QETH_LARGE_SEND_NO; - } - return rc; -} - static int qeth_l3_isxdigit(char *buf) { while (*buf) { @@ -1485,6 +1458,7 @@ int qeth_l3_set_rx_csum(struct qeth_card *card, if (rc) return -EIO; } + card->dev->features |= NETIF_F_RXCSUM; } else { if (csum_type == HW_CHECKSUMMING) { if (card->state != CARD_STATE_DOWN) { @@ -1496,6 +1470,7 @@ int qeth_l3_set_rx_csum(struct qeth_card *card, return -EIO; } } + card->dev->features &= ~NETIF_F_RXCSUM; } card->options.checksum_type = csum_type; return rc; @@ -1580,10 +1555,8 @@ static int qeth_l3_start_ipa_tso(struct qeth_card *card) dev_info(&card->gdev->dev, "Outbound TSO enabled\n"); } - if (rc && (card->options.large_send == QETH_LARGE_SEND_TSO)) { - card->options.large_send = QETH_LARGE_SEND_NO; - card->dev->features &= ~(NETIF_F_TSO | NETIF_F_SG); - } + if (rc) + card->dev->features &= ~NETIF_F_TSO; return rc; } @@ -3024,7 +2997,7 @@ static int qeth_l3_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) struct qeth_qdio_out_q *queue = card->qdio.out_qs [qeth_get_priority_queue(card, skb, ipv, cast_type)]; int tx_bytes = skb->len; - enum qeth_large_send_types large_send = QETH_LARGE_SEND_NO; + bool large_send; int data_offset = -1; int nr_frags; @@ -3046,8 +3019,7 @@ static int qeth_l3_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) card->perf_stats.outbound_start_time = qeth_get_micros(); } - if (skb_is_gso(skb)) - large_send = card->options.large_send; + large_send = skb_is_gso(skb); if ((card->info.type == QETH_CARD_TYPE_IQD) && (!large_send) && (skb_shinfo(skb)->nr_frags == 0)) { @@ -3096,7 +3068,7 @@ static int qeth_l3_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) /* fix hardware limitation: as long as we do not have sbal * chaining we can not send long frag lists */ - if (large_send == QETH_LARGE_SEND_TSO) { + if (large_send) { if (qeth_l3_tso_elements(new_skb) + 1 > 16) { if (skb_linearize(new_skb)) goto tx_drop; @@ -3105,8 +3077,7 @@ static int qeth_l3_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) } } - if ((large_send == QETH_LARGE_SEND_TSO) && - (cast_type == RTN_UNSPEC)) { + if (large_send && (cast_type == RTN_UNSPEC)) { hdr = (struct qeth_hdr *)skb_push(new_skb, sizeof(struct qeth_hdr_tso)); memset(hdr, 0, sizeof(struct qeth_hdr_tso)); @@ -3141,7 +3112,7 @@ static int qeth_l3_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) if (card->info.type != QETH_CARD_TYPE_IQD) { int len; - if (large_send == QETH_LARGE_SEND_TSO) + if (large_send) len = ((unsigned long)tcp_hdr(new_skb) + tcp_hdr(new_skb)->doff * 4) - (unsigned long)new_skb->data; @@ -3162,7 +3133,7 @@ static int qeth_l3_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) if (new_skb != skb) dev_kfree_skb_any(skb); if (card->options.performance_stats) { - if (large_send != QETH_LARGE_SEND_NO) { + if (large_send) { card->perf_stats.large_send_bytes += tx_bytes; card->perf_stats.large_send_cnt++; } @@ -3248,65 +3219,40 @@ static int qeth_l3_stop(struct net_device *dev) return 0; } -static u32 qeth_l3_ethtool_get_rx_csum(struct net_device *dev) +static u32 qeth_l3_fix_features(struct net_device *dev, u32 features) { struct qeth_card *card = dev->ml_priv; - return (card->options.checksum_type == HW_CHECKSUMMING); + if (!qeth_is_supported(card, IPA_OUTBOUND_CHECKSUM)) + features &= ~NETIF_F_IP_CSUM; + if (!qeth_is_supported(card, IPA_OUTBOUND_TSO)) + features &= ~NETIF_F_TSO; + if (!qeth_is_supported(card, IPA_INBOUND_CHECKSUM)) + features &= ~NETIF_F_RXCSUM; + + return features; } -static int qeth_l3_ethtool_set_rx_csum(struct net_device *dev, u32 data) +static int qeth_l3_set_features(struct net_device *dev, u32 features) { - struct qeth_card *card = dev->ml_priv; enum qeth_checksum_types csum_type; + struct qeth_card *card = dev->ml_priv; + u32 changed = dev->features ^ features; - if (data) + if (!(changed & NETIF_F_RXCSUM)) + return 0; + + if (features & NETIF_F_RXCSUM) csum_type = HW_CHECKSUMMING; else csum_type = SW_CHECKSUMMING; + dev->features = features ^ NETIF_F_RXCSUM; return qeth_l3_set_rx_csum(card, csum_type); } -static int qeth_l3_ethtool_set_tso(struct net_device *dev, u32 data) -{ - struct qeth_card *card = dev->ml_priv; - int rc = 0; - - if (data) { - rc = qeth_l3_set_large_send(card, QETH_LARGE_SEND_TSO); - } else { - dev->features &= ~NETIF_F_TSO; - card->options.large_send = QETH_LARGE_SEND_NO; - } - return rc; -} - -static int qeth_l3_ethtool_set_tx_csum(struct net_device *dev, u32 data) -{ - struct qeth_card *card = dev->ml_priv; - - if (data) { - if (qeth_is_supported(card, IPA_OUTBOUND_CHECKSUM)) - dev->features |= NETIF_F_IP_CSUM; - else - return -EPERM; - } else - dev->features &= ~NETIF_F_IP_CSUM; - - return 0; -} - static const struct ethtool_ops qeth_l3_ethtool_ops = { .get_link = ethtool_op_get_link, - .get_tx_csum = ethtool_op_get_tx_csum, - .set_tx_csum = qeth_l3_ethtool_set_tx_csum, - .get_rx_csum = qeth_l3_ethtool_get_rx_csum, - .set_rx_csum = qeth_l3_ethtool_set_rx_csum, - .get_sg = ethtool_op_get_sg, - .set_sg = ethtool_op_set_sg, - .get_tso = ethtool_op_get_tso, - .set_tso = qeth_l3_ethtool_set_tso, .get_strings = qeth_core_get_strings, .get_ethtool_stats = qeth_core_get_ethtool_stats, .get_sset_count = qeth_core_get_sset_count, @@ -3347,6 +3293,8 @@ static const struct net_device_ops qeth_l3_netdev_ops = { .ndo_set_multicast_list = qeth_l3_set_multicast_list, .ndo_do_ioctl = qeth_l3_do_ioctl, .ndo_change_mtu = qeth_change_mtu, + .ndo_fix_features = qeth_l3_fix_features, + .ndo_set_features = qeth_l3_set_features, .ndo_vlan_rx_register = qeth_l3_vlan_rx_register, .ndo_vlan_rx_add_vid = qeth_l3_vlan_rx_add_vid, .ndo_vlan_rx_kill_vid = qeth_l3_vlan_rx_kill_vid, @@ -3362,6 +3310,8 @@ static const struct net_device_ops qeth_l3_osa_netdev_ops = { .ndo_set_multicast_list = qeth_l3_set_multicast_list, .ndo_do_ioctl = qeth_l3_do_ioctl, .ndo_change_mtu = qeth_change_mtu, + .ndo_fix_features = qeth_l3_fix_features, + .ndo_set_features = qeth_l3_set_features, .ndo_vlan_rx_register = qeth_l3_vlan_rx_register, .ndo_vlan_rx_add_vid = qeth_l3_vlan_rx_add_vid, .ndo_vlan_rx_kill_vid = qeth_l3_vlan_rx_kill_vid, @@ -3392,8 +3342,6 @@ static int qeth_l3_setup_netdev(struct qeth_card *card) if (!(card->info.unique_id & UNIQUE_ID_NOT_BY_CARD)) card->dev->dev_id = card->info.unique_id & 0xffff; - if (!card->info.guestlan) - card->dev->features |= NETIF_F_GRO; } } else if (card->info.type == QETH_CARD_TYPE_IQD) { card->dev = alloc_netdev(0, "hsi%d", ether_setup); @@ -3409,6 +3357,8 @@ static int qeth_l3_setup_netdev(struct qeth_card *card) card->dev->watchdog_timeo = QETH_TX_TIMEOUT; card->dev->mtu = card->info.initial_mtu; SET_ETHTOOL_OPS(card->dev, &qeth_l3_ethtool_ops); + card->dev->hw_features = NETIF_F_SG | NETIF_F_RXCSUM | + NETIF_F_IP_CSUM | NETIF_F_TSO; card->dev->features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX | NETIF_F_HW_VLAN_FILTER; @@ -3516,7 +3466,6 @@ contin: rc = qeth_l3_start_ipassists(card); if (rc) QETH_DBF_TEXT_(SETUP, 2, "3err%d", rc); - qeth_l3_set_large_send(card, card->options.large_send); rc = qeth_l3_setrouting_v4(card); if (rc) QETH_DBF_TEXT_(SETUP, 2, "4err%d", rc); diff --git a/drivers/s390/net/qeth_l3_sys.c b/drivers/s390/net/qeth_l3_sys.c index 67cfa68..bf9f003 100644 --- a/drivers/s390/net/qeth_l3_sys.c +++ b/drivers/s390/net/qeth_l3_sys.c @@ -410,39 +410,42 @@ static ssize_t qeth_l3_dev_large_send_show(struct device *dev, if (!card) return -EINVAL; - switch (card->options.large_send) { - case QETH_LARGE_SEND_NO: + if (!(card->dev->features & NETIF_F_TSO)) return sprintf(buf, "%s\n", "no"); - case QETH_LARGE_SEND_TSO: + else return sprintf(buf, "%s\n", "TSO"); - default: - return sprintf(buf, "%s\n", "N/A"); - } } static ssize_t qeth_l3_dev_large_send_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { - struct qeth_card *card = dev_get_drvdata(dev); - enum qeth_large_send_types type; - int rc = 0; + struct qeth_card *card; char *tmp; + int enable; if (!card) return -EINVAL; tmp = strsep((char **) &buf, "\n"); if (!strcmp(tmp, "no")) - type = QETH_LARGE_SEND_NO; + enable = 0; else if (!strcmp(tmp, "TSO")) - type = QETH_LARGE_SEND_TSO; + enable = 1; else return -EINVAL; - mutex_lock(&card->conf_mutex); - if (card->options.large_send != type) - rc = qeth_l3_set_large_send(card, type); - mutex_unlock(&card->conf_mutex); - return rc ? rc : count; + rtnl_lock(); + + card = dev_get_drvdata(dev); + + if (enable) + card->dev->wanted_features |= NETIF_F_TSO; + else + card->dev->wanted_features &= ~NETIF_F_TSO; + netdev_update_features(card->dev); + + rtnl_unlock(); + + return count; } static DEVICE_ATTR(large_send, 0644, qeth_l3_dev_large_send_show, -- cgit v0.10.2 From 3d96c74d8983b16bc7ecb196e61a2173fcc3f09f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Miros=C5=82aw?= Date: Tue, 19 Apr 2011 00:43:20 +0000 Subject: net: infiniband/ulp/ipoib: convert to hw_features MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: MichaÅ‚ MirosÅ‚aw Signed-off-by: David S. Miller diff --git a/drivers/infiniband/ulp/ipoib/ipoib.h b/drivers/infiniband/ulp/ipoib/ipoib.h index ab97f92..7b6985a 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib.h +++ b/drivers/infiniband/ulp/ipoib/ipoib.h @@ -91,7 +91,6 @@ enum { IPOIB_STOP_REAPER = 7, IPOIB_FLAG_ADMIN_CM = 9, IPOIB_FLAG_UMCAST = 10, - IPOIB_FLAG_CSUM = 11, IPOIB_MAX_BACKOFF_SECONDS = 16, diff --git a/drivers/infiniband/ulp/ipoib/ipoib_cm.c b/drivers/infiniband/ulp/ipoib/ipoib_cm.c index 93d5580..39913a0 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib_cm.c +++ b/drivers/infiniband/ulp/ipoib/ipoib_cm.c @@ -1463,8 +1463,7 @@ static ssize_t set_mode(struct device *d, struct device_attribute *attr, set_bit(IPOIB_FLAG_ADMIN_CM, &priv->flags); ipoib_warn(priv, "enabling connected mode " "will cause multicast packet drops\n"); - - dev->features &= ~(NETIF_F_IP_CSUM | NETIF_F_SG | NETIF_F_TSO); + netdev_update_features(dev); rtnl_unlock(); priv->tx_wr.send_flags &= ~IB_SEND_IP_CSUM; @@ -1474,13 +1473,7 @@ static ssize_t set_mode(struct device *d, struct device_attribute *attr, if (!strcmp(buf, "datagram\n")) { clear_bit(IPOIB_FLAG_ADMIN_CM, &priv->flags); - - if (test_bit(IPOIB_FLAG_CSUM, &priv->flags)) { - dev->features |= NETIF_F_IP_CSUM | NETIF_F_SG; - priv->dev->features |= NETIF_F_GRO; - if (priv->hca_caps & IB_DEVICE_UD_TSO) - dev->features |= NETIF_F_TSO; - } + netdev_update_features(dev); dev_set_mtu(dev, min(priv->mcast_mtu, dev->mtu)); rtnl_unlock(); ipoib_flush_paths(dev); diff --git a/drivers/infiniband/ulp/ipoib/ipoib_ethtool.c b/drivers/infiniband/ulp/ipoib/ipoib_ethtool.c index 19f7f52..29bc7b5 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib_ethtool.c +++ b/drivers/infiniband/ulp/ipoib/ipoib_ethtool.c @@ -42,32 +42,6 @@ static void ipoib_get_drvinfo(struct net_device *netdev, strncpy(drvinfo->driver, "ipoib", sizeof(drvinfo->driver) - 1); } -static u32 ipoib_get_rx_csum(struct net_device *dev) -{ - struct ipoib_dev_priv *priv = netdev_priv(dev); - return test_bit(IPOIB_FLAG_CSUM, &priv->flags) && - !test_bit(IPOIB_FLAG_ADMIN_CM, &priv->flags); -} - -static int ipoib_set_tso(struct net_device *dev, u32 data) -{ - struct ipoib_dev_priv *priv = netdev_priv(dev); - - if (data) { - if (!test_bit(IPOIB_FLAG_ADMIN_CM, &priv->flags) && - (dev->features & NETIF_F_SG) && - (priv->hca_caps & IB_DEVICE_UD_TSO)) { - dev->features |= NETIF_F_TSO; - } else { - ipoib_warn(priv, "can't set TSO on\n"); - return -EOPNOTSUPP; - } - } else - dev->features &= ~NETIF_F_TSO; - - return 0; -} - static int ipoib_get_coalesce(struct net_device *dev, struct ethtool_coalesce *coal) { @@ -108,8 +82,6 @@ static int ipoib_set_coalesce(struct net_device *dev, static const struct ethtool_ops ipoib_ethtool_ops = { .get_drvinfo = ipoib_get_drvinfo, - .get_rx_csum = ipoib_get_rx_csum, - .set_tso = ipoib_set_tso, .get_coalesce = ipoib_get_coalesce, .set_coalesce = ipoib_set_coalesce, }; diff --git a/drivers/infiniband/ulp/ipoib/ipoib_ib.c b/drivers/infiniband/ulp/ipoib/ipoib_ib.c index 806d029..81ae61d 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib_ib.c +++ b/drivers/infiniband/ulp/ipoib/ipoib_ib.c @@ -292,7 +292,7 @@ static void ipoib_ib_handle_rx_wc(struct net_device *dev, struct ib_wc *wc) dev->stats.rx_bytes += skb->len; skb->dev = dev; - if (test_bit(IPOIB_FLAG_CSUM, &priv->flags) && likely(wc->csum_ok)) + if ((dev->features & NETIF_F_RXCSUM) && likely(wc->csum_ok)) skb->ip_summed = CHECKSUM_UNNECESSARY; napi_gro_receive(&priv->napi, skb); diff --git a/drivers/infiniband/ulp/ipoib/ipoib_main.c b/drivers/infiniband/ulp/ipoib/ipoib_main.c index aca3b44..86addca 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib_main.c +++ b/drivers/infiniband/ulp/ipoib/ipoib_main.c @@ -171,6 +171,16 @@ static int ipoib_stop(struct net_device *dev) return 0; } +static u32 ipoib_fix_features(struct net_device *dev, u32 features) +{ + struct ipoib_dev_priv *priv = netdev_priv(dev); + + if (test_bit(IPOIB_FLAG_ADMIN_CM, &priv->flags)) + features &= ~(NETIF_F_SG | NETIF_F_IP_CSUM | NETIF_F_TSO); + + return features; +} + static int ipoib_change_mtu(struct net_device *dev, int new_mtu) { struct ipoib_dev_priv *priv = netdev_priv(dev); @@ -970,6 +980,7 @@ static const struct net_device_ops ipoib_netdev_ops = { .ndo_open = ipoib_open, .ndo_stop = ipoib_stop, .ndo_change_mtu = ipoib_change_mtu, + .ndo_fix_features = ipoib_fix_features, .ndo_start_xmit = ipoib_start_xmit, .ndo_tx_timeout = ipoib_timeout, .ndo_set_multicast_list = ipoib_set_mcast_list, @@ -1154,19 +1165,18 @@ int ipoib_set_dev_features(struct ipoib_dev_priv *priv, struct ib_device *hca) kfree(device_attr); if (priv->hca_caps & IB_DEVICE_UD_IP_CSUM) { - set_bit(IPOIB_FLAG_CSUM, &priv->flags); - priv->dev->features |= NETIF_F_SG | NETIF_F_IP_CSUM; - } + priv->dev->hw_features = NETIF_F_SG | + NETIF_F_IP_CSUM | NETIF_F_RXCSUM; - priv->dev->features |= NETIF_F_GRO; + if (priv->hca_caps & IB_DEVICE_UD_TSO) + priv->dev->hw_features |= NETIF_F_TSO; - if (priv->dev->features & NETIF_F_SG && priv->hca_caps & IB_DEVICE_UD_TSO) - priv->dev->features |= NETIF_F_TSO; + priv->dev->features |= priv->dev->hw_features; + } return 0; } - static struct net_device *ipoib_add_port(const char *format, struct ib_device *hca, u8 port) { -- cgit v0.10.2 From 756a6b03da98903fa22ad7f10752de11782249fc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Miros=C5=82aw?= Date: Tue, 19 Apr 2011 01:56:12 +0000 Subject: net: pch_gbe: convert to hw_features MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This also fixes bug in xmit path, where TX checksum offload state was used instead of skb->ip_summed to decide if the offload was needed. Signed-off-by: MichaÅ‚ MirosÅ‚aw Signed-off-by: David S. Miller diff --git a/drivers/net/pch_gbe/pch_gbe.h b/drivers/net/pch_gbe/pch_gbe.h index bf126e7..59fac77 100644 --- a/drivers/net/pch_gbe/pch_gbe.h +++ b/drivers/net/pch_gbe/pch_gbe.h @@ -597,8 +597,6 @@ struct pch_gbe_hw_stats { * @rx_ring: Pointer of Rx descriptor ring structure * @rx_buffer_len: Receive buffer length * @tx_queue_len: Transmit queue length - * @rx_csum: Receive TCP/IP checksum enable/disable - * @tx_csum: Transmit TCP/IP checksum enable/disable * @have_msi: PCI MSI mode flag */ @@ -623,8 +621,6 @@ struct pch_gbe_adapter { struct pch_gbe_rx_ring *rx_ring; unsigned long rx_buffer_len; unsigned long tx_queue_len; - bool rx_csum; - bool tx_csum; bool have_msi; }; diff --git a/drivers/net/pch_gbe/pch_gbe_ethtool.c b/drivers/net/pch_gbe/pch_gbe_ethtool.c index d2174a4..c35d105 100644 --- a/drivers/net/pch_gbe/pch_gbe_ethtool.c +++ b/drivers/net/pch_gbe/pch_gbe_ethtool.c @@ -434,57 +434,6 @@ static int pch_gbe_set_pauseparam(struct net_device *netdev, } /** - * pch_gbe_get_rx_csum - Report whether receive checksums are turned on or off - * @netdev: Network interface device structure - * Returns - * true(1): Checksum On - * false(0): Checksum Off - */ -static u32 pch_gbe_get_rx_csum(struct net_device *netdev) -{ - struct pch_gbe_adapter *adapter = netdev_priv(netdev); - - return adapter->rx_csum; -} - -/** - * pch_gbe_set_rx_csum - Turn receive checksum on or off - * @netdev: Network interface device structure - * @data: Checksum On[true] or Off[false] - * Returns - * 0: Successful. - * Negative value: Failed. - */ -static int pch_gbe_set_rx_csum(struct net_device *netdev, u32 data) -{ - struct pch_gbe_adapter *adapter = netdev_priv(netdev); - - adapter->rx_csum = data; - if ((netif_running(netdev))) - pch_gbe_reinit_locked(adapter); - else - pch_gbe_reset(adapter); - - return 0; -} - -/** - * pch_gbe_set_tx_csum - Turn transmit checksums on or off - * @netdev: Network interface device structure - * @data: Checksum on[true] or off[false] - * Returns - * 0: Successful. - * Negative value: Failed. - */ -static int pch_gbe_set_tx_csum(struct net_device *netdev, u32 data) -{ - struct pch_gbe_adapter *adapter = netdev_priv(netdev); - - adapter->tx_csum = data; - return ethtool_op_set_tx_ipv6_csum(netdev, data); -} - -/** * pch_gbe_get_strings - Return a set of strings that describe the requested * objects * @netdev: Network interface device structure @@ -554,9 +503,6 @@ static const struct ethtool_ops pch_gbe_ethtool_ops = { .set_ringparam = pch_gbe_set_ringparam, .get_pauseparam = pch_gbe_get_pauseparam, .set_pauseparam = pch_gbe_set_pauseparam, - .get_rx_csum = pch_gbe_get_rx_csum, - .set_rx_csum = pch_gbe_set_rx_csum, - .set_tx_csum = pch_gbe_set_tx_csum, .get_strings = pch_gbe_get_strings, .get_ethtool_stats = pch_gbe_get_ethtool_stats, .get_sset_count = pch_gbe_get_sset_count, diff --git a/drivers/net/pch_gbe/pch_gbe_main.c b/drivers/net/pch_gbe/pch_gbe_main.c index 2ef2f9c..4cc9872 100644 --- a/drivers/net/pch_gbe/pch_gbe_main.c +++ b/drivers/net/pch_gbe/pch_gbe_main.c @@ -656,6 +656,7 @@ static void pch_gbe_configure_tx(struct pch_gbe_adapter *adapter) */ static void pch_gbe_setup_rctl(struct pch_gbe_adapter *adapter) { + struct net_device *netdev = adapter->netdev; struct pch_gbe_hw *hw = &adapter->hw; u32 rx_mode, tcpip; @@ -666,7 +667,7 @@ static void pch_gbe_setup_rctl(struct pch_gbe_adapter *adapter) tcpip = ioread32(&hw->reg->TCPIP_ACC); - if (adapter->rx_csum) { + if (netdev->features & NETIF_F_RXCSUM) { tcpip &= ~PCH_GBE_RX_TCPIPACC_OFF; tcpip |= PCH_GBE_RX_TCPIPACC_EN; } else { @@ -950,7 +951,7 @@ static void pch_gbe_tx_queue(struct pch_gbe_adapter *adapter, frame_ctrl = 0; if (unlikely(skb->len < PCH_GBE_SHORT_PKT)) frame_ctrl |= PCH_GBE_TXD_CTRL_APAD; - if (unlikely(!adapter->tx_csum)) + if (skb->ip_summed == CHECKSUM_NONE) frame_ctrl |= PCH_GBE_TXD_CTRL_TCPIP_ACC_OFF; /* Performs checksum processing */ @@ -958,7 +959,7 @@ static void pch_gbe_tx_queue(struct pch_gbe_adapter *adapter, * It is because the hardware accelerator does not support a checksum, * when the received data size is less than 64 bytes. */ - if ((skb->len < PCH_GBE_SHORT_PKT) && (adapter->tx_csum)) { + if (skb->len < PCH_GBE_SHORT_PKT && skb->ip_summed != CHECKSUM_NONE) { frame_ctrl |= PCH_GBE_TXD_CTRL_APAD | PCH_GBE_TXD_CTRL_TCPIP_ACC_OFF; if (skb->protocol == htons(ETH_P_IP)) { @@ -1426,7 +1427,7 @@ pch_gbe_clean_rx(struct pch_gbe_adapter *adapter, length = (rx_desc->rx_words_eob) - 3; /* Decide the data conversion method */ - if (!adapter->rx_csum) { + if (!(netdev->features & NETIF_F_RXCSUM)) { /* [Header:14][payload] */ if (NET_IP_ALIGN) { /* Because alignment differs, @@ -2030,6 +2031,29 @@ static int pch_gbe_change_mtu(struct net_device *netdev, int new_mtu) } /** + * pch_gbe_set_features - Reset device after features changed + * @netdev: Network interface device structure + * @features: New features + * Returns + * 0: HW state updated successfully + */ +static int pch_gbe_set_features(struct net_device *netdev, u32 features) +{ + struct pch_gbe_adapter *adapter = netdev_priv(netdev); + u32 changed = features ^ netdev->features; + + if (!(changed & NETIF_F_RXCSUM)) + return 0; + + if (netif_running(netdev)) + pch_gbe_reinit_locked(adapter); + else + pch_gbe_reset(adapter); + + return 0; +} + +/** * pch_gbe_ioctl - Controls register through a MII interface * @netdev: Network interface device structure * @ifr: Pointer to ifr structure @@ -2129,6 +2153,7 @@ static const struct net_device_ops pch_gbe_netdev_ops = { .ndo_set_mac_address = pch_gbe_set_mac, .ndo_tx_timeout = pch_gbe_tx_timeout, .ndo_change_mtu = pch_gbe_change_mtu, + .ndo_set_features = pch_gbe_set_features, .ndo_do_ioctl = pch_gbe_ioctl, .ndo_set_multicast_list = &pch_gbe_set_multi, #ifdef CONFIG_NET_POLL_CONTROLLER @@ -2334,7 +2359,9 @@ static int pch_gbe_probe(struct pci_dev *pdev, netdev->watchdog_timeo = PCH_GBE_WATCHDOG_PERIOD; netif_napi_add(netdev, &adapter->napi, pch_gbe_napi_poll, PCH_GBE_RX_WEIGHT); - netdev->features = NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM | NETIF_F_GRO; + netdev->hw_features = NETIF_F_RXCSUM | + NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM; + netdev->features = netdev->hw_features; pch_gbe_set_ethtool_ops(netdev); pch_gbe_mac_load_mac_addr(&adapter->hw); @@ -2373,11 +2400,6 @@ static int pch_gbe_probe(struct pci_dev *pdev, pch_gbe_check_options(adapter); - if (adapter->tx_csum) - netdev->features |= NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM; - else - netdev->features &= ~(NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM); - /* initialize the wol settings based on the eeprom settings */ adapter->wake_up_evt = PCH_GBE_WL_INIT_SETTING; dev_info(&pdev->dev, "MAC address : %pM\n", netdev->dev_addr); diff --git a/drivers/net/pch_gbe/pch_gbe_param.c b/drivers/net/pch_gbe/pch_gbe_param.c index ef0996a..5b5d90a 100644 --- a/drivers/net/pch_gbe/pch_gbe_param.c +++ b/drivers/net/pch_gbe/pch_gbe_param.c @@ -426,6 +426,8 @@ full_duplex_only: void pch_gbe_check_options(struct pch_gbe_adapter *adapter) { struct pch_gbe_hw *hw = &adapter->hw; + struct net_device *dev = adapter->netdev; + int val; { /* Transmit Descriptor Count */ static const struct pch_gbe_option opt = { @@ -466,9 +468,10 @@ void pch_gbe_check_options(struct pch_gbe_adapter *adapter) .err = "defaulting to Enabled", .def = PCH_GBE_DEFAULT_RX_CSUM }; - adapter->rx_csum = XsumRX; - pch_gbe_validate_option((int *)(&adapter->rx_csum), - &opt, adapter); + val = XsumRX; + pch_gbe_validate_option(&val, &opt, adapter); + if (!val) + dev->features &= ~NETIF_F_RXCSUM; } { /* Checksum Offload Enable/Disable */ static const struct pch_gbe_option opt = { @@ -477,9 +480,10 @@ void pch_gbe_check_options(struct pch_gbe_adapter *adapter) .err = "defaulting to Enabled", .def = PCH_GBE_DEFAULT_TX_CSUM }; - adapter->tx_csum = XsumTX; - pch_gbe_validate_option((int *)(&adapter->tx_csum), - &opt, adapter); + val = XsumTX; + pch_gbe_validate_option(&val, &opt, adapter); + if (!val) + dev->features &= ~NETIF_F_ALL_CSUM; } { /* Flow Control */ static const struct pch_gbe_option opt = { -- cgit v0.10.2 From b9367bf3ee6da380e0c338bd75bb8e8e4e0b981b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Miros=C5=82aw?= Date: Tue, 19 Apr 2011 02:14:25 +0000 Subject: net: ibmveth: convert to hw_features MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A minimal conversion. ibmveth_set_csum_offload() can be folded into ibmveth_set_features() and adapter->rx_csum removed - left for later cleanup. Signed-off-by: MichaÅ‚ MirosÅ‚aw Signed-off-by: David S. Miller diff --git a/drivers/net/ibmveth.c b/drivers/net/ibmveth.c index 5522d45..4855f1f 100644 --- a/drivers/net/ibmveth.c +++ b/drivers/net/ibmveth.c @@ -729,45 +729,24 @@ static void netdev_get_drvinfo(struct net_device *dev, sizeof(info->version) - 1); } -static void ibmveth_set_rx_csum_flags(struct net_device *dev, u32 data) +static u32 ibmveth_fix_features(struct net_device *dev, u32 features) { - struct ibmveth_adapter *adapter = netdev_priv(dev); - - if (data) { - adapter->rx_csum = 1; - } else { - /* - * Since the ibmveth firmware interface does not have the - * concept of separate tx/rx checksum offload enable, if rx - * checksum is disabled we also have to disable tx checksum - * offload. Once we disable rx checksum offload, we are no - * longer allowed to send tx buffers that are not properly - * checksummed. - */ - adapter->rx_csum = 0; - dev->features &= ~NETIF_F_IP_CSUM; - dev->features &= ~NETIF_F_IPV6_CSUM; - } -} + /* + * Since the ibmveth firmware interface does not have the + * concept of separate tx/rx checksum offload enable, if rx + * checksum is disabled we also have to disable tx checksum + * offload. Once we disable rx checksum offload, we are no + * longer allowed to send tx buffers that are not properly + * checksummed. + */ -static void ibmveth_set_tx_csum_flags(struct net_device *dev, u32 data) -{ - struct ibmveth_adapter *adapter = netdev_priv(dev); + if (!(features & NETIF_F_RXCSUM)) + features &= ~NETIF_F_ALL_CSUM; - if (data) { - if (adapter->fw_ipv4_csum_support) - dev->features |= NETIF_F_IP_CSUM; - if (adapter->fw_ipv6_csum_support) - dev->features |= NETIF_F_IPV6_CSUM; - adapter->rx_csum = 1; - } else { - dev->features &= ~NETIF_F_IP_CSUM; - dev->features &= ~NETIF_F_IPV6_CSUM; - } + return features; } -static int ibmveth_set_csum_offload(struct net_device *dev, u32 data, - void (*done) (struct net_device *, u32)) +static int ibmveth_set_csum_offload(struct net_device *dev, u32 data) { struct ibmveth_adapter *adapter = netdev_priv(dev); unsigned long set_attr, clr_attr, ret_attr; @@ -827,8 +806,8 @@ static int ibmveth_set_csum_offload(struct net_device *dev, u32 data, } else adapter->fw_ipv6_csum_support = data; - if (ret == H_SUCCESS || ret6 == H_SUCCESS) - done(dev, data); + if (ret != H_SUCCESS || ret6 != H_SUCCESS) + adapter->rx_csum = data; else rc1 = -EIO; } else { @@ -844,41 +823,22 @@ static int ibmveth_set_csum_offload(struct net_device *dev, u32 data, return rc1 ? rc1 : rc2; } -static int ibmveth_set_rx_csum(struct net_device *dev, u32 data) +static int ibmveth_set_features(struct net_device *dev, u32 features) { struct ibmveth_adapter *adapter = netdev_priv(dev); + int rx_csum = !!(features & NETIF_F_RXCSUM); + int rc; - if ((data && adapter->rx_csum) || (!data && !adapter->rx_csum)) - return 0; - - return ibmveth_set_csum_offload(dev, data, ibmveth_set_rx_csum_flags); -} - -static int ibmveth_set_tx_csum(struct net_device *dev, u32 data) -{ - struct ibmveth_adapter *adapter = netdev_priv(dev); - int rc = 0; - - if (data && (dev->features & (NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM))) - return 0; - if (!data && !(dev->features & (NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM))) + if (rx_csum == adapter->rx_csum) return 0; - if (data && !adapter->rx_csum) - rc = ibmveth_set_csum_offload(dev, data, - ibmveth_set_tx_csum_flags); - else - ibmveth_set_tx_csum_flags(dev, data); + rc = ibmveth_set_csum_offload(dev, rx_csum); + if (rc && !adapter->rx_csum) + dev->features = features & ~(NETIF_F_ALL_CSUM | NETIF_F_RXCSUM); return rc; } -static u32 ibmveth_get_rx_csum(struct net_device *dev) -{ - struct ibmveth_adapter *adapter = netdev_priv(dev); - return adapter->rx_csum; -} - static void ibmveth_get_strings(struct net_device *dev, u32 stringset, u8 *data) { int i; @@ -914,13 +874,9 @@ static const struct ethtool_ops netdev_ethtool_ops = { .get_drvinfo = netdev_get_drvinfo, .get_settings = netdev_get_settings, .get_link = ethtool_op_get_link, - .set_tx_csum = ibmveth_set_tx_csum, - .get_rx_csum = ibmveth_get_rx_csum, - .set_rx_csum = ibmveth_set_rx_csum, .get_strings = ibmveth_get_strings, .get_sset_count = ibmveth_get_sset_count, .get_ethtool_stats = ibmveth_get_ethtool_stats, - .set_sg = ethtool_op_set_sg, }; static int ibmveth_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) @@ -1345,6 +1301,8 @@ static const struct net_device_ops ibmveth_netdev_ops = { .ndo_set_multicast_list = ibmveth_set_multicast_list, .ndo_do_ioctl = ibmveth_ioctl, .ndo_change_mtu = ibmveth_change_mtu, + .ndo_fix_features = ibmveth_fix_features, + .ndo_set_features = ibmveth_set_features, .ndo_validate_addr = eth_validate_addr, .ndo_set_mac_address = eth_mac_addr, #ifdef CONFIG_NET_POLL_CONTROLLER @@ -1412,7 +1370,9 @@ static int __devinit ibmveth_probe(struct vio_dev *dev, netdev->netdev_ops = &ibmveth_netdev_ops; netdev->ethtool_ops = &netdev_ethtool_ops; SET_NETDEV_DEV(netdev, &dev->dev); - netdev->features |= NETIF_F_SG; + netdev->hw_features = NETIF_F_SG | NETIF_F_RXCSUM | + NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM; + netdev->features |= netdev->hw_features; memcpy(netdev->dev_addr, &adapter->mac_addr, netdev->addr_len); @@ -1437,8 +1397,6 @@ static int __devinit ibmveth_probe(struct vio_dev *dev, netdev_dbg(netdev, "registering netdev...\n"); - ibmveth_set_csum_offload(netdev, 1, ibmveth_set_tx_csum_flags); - rc = register_netdev(netdev); if (rc) { -- cgit v0.10.2 From 135d84a9f28854f875f32f97485737b0013c99d6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Miros=C5=82aw?= Date: Tue, 19 Apr 2011 03:03:57 +0000 Subject: net: qlcnic: convert to hw_features MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bit more than minimal conversion. There might be some issues because of qlcnic_set_netdev_features() if it's called after netdev init. Signed-off-by: MichaÅ‚ MirosÅ‚aw Signed-off-by: David S. Miller diff --git a/drivers/net/qlcnic/qlcnic.h b/drivers/net/qlcnic/qlcnic.h index e5d30538..fa5b15c 100644 --- a/drivers/net/qlcnic/qlcnic.h +++ b/drivers/net/qlcnic/qlcnic.h @@ -926,7 +926,6 @@ struct qlcnic_adapter { u8 max_rds_rings; u8 max_sds_rings; u8 msix_supported; - u8 rx_csum; u8 portnum; u8 physical_port; u8 reset_context; @@ -1247,6 +1246,8 @@ void qlcnic_advert_link_change(struct qlcnic_adapter *adapter, int linkup); int qlcnic_fw_cmd_set_mtu(struct qlcnic_adapter *adapter, int mtu); int qlcnic_change_mtu(struct net_device *netdev, int new_mtu); +u32 qlcnic_fix_features(struct net_device *netdev, u32 features); +int qlcnic_set_features(struct net_device *netdev, u32 features); int qlcnic_config_hw_lro(struct qlcnic_adapter *adapter, int enable); int qlcnic_config_bridged_mode(struct qlcnic_adapter *adapter, u32 enable); int qlcnic_send_lro_cleanup(struct qlcnic_adapter *adapter); diff --git a/drivers/net/qlcnic/qlcnic_ethtool.c b/drivers/net/qlcnic/qlcnic_ethtool.c index 3cd8a16..615a5ab 100644 --- a/drivers/net/qlcnic/qlcnic_ethtool.c +++ b/drivers/net/qlcnic/qlcnic_ethtool.c @@ -764,73 +764,6 @@ qlcnic_get_ethtool_stats(struct net_device *dev, qlcnic_fill_device_stats(&index, data, &port_stats.tx); } -static int qlcnic_set_tx_csum(struct net_device *dev, u32 data) -{ - struct qlcnic_adapter *adapter = netdev_priv(dev); - - if ((adapter->flags & QLCNIC_ESWITCH_ENABLED)) - return -EOPNOTSUPP; - if (data) - dev->features |= (NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM); - else - dev->features &= ~(NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM); - - return 0; - -} -static u32 qlcnic_get_tx_csum(struct net_device *dev) -{ - return dev->features & NETIF_F_IP_CSUM; -} - -static u32 qlcnic_get_rx_csum(struct net_device *dev) -{ - struct qlcnic_adapter *adapter = netdev_priv(dev); - return adapter->rx_csum; -} - -static int qlcnic_set_rx_csum(struct net_device *dev, u32 data) -{ - struct qlcnic_adapter *adapter = netdev_priv(dev); - - if ((adapter->flags & QLCNIC_ESWITCH_ENABLED)) - return -EOPNOTSUPP; - if (!!data) { - adapter->rx_csum = !!data; - return 0; - } - - if (dev->features & NETIF_F_LRO) { - if (qlcnic_config_hw_lro(adapter, QLCNIC_LRO_DISABLED)) - return -EIO; - - dev->features &= ~NETIF_F_LRO; - qlcnic_send_lro_cleanup(adapter); - dev_info(&adapter->pdev->dev, - "disabling LRO as rx_csum is off\n"); - } - adapter->rx_csum = !!data; - return 0; -} - -static u32 qlcnic_get_tso(struct net_device *dev) -{ - return (dev->features & (NETIF_F_TSO | NETIF_F_TSO6)) != 0; -} - -static int qlcnic_set_tso(struct net_device *dev, u32 data) -{ - struct qlcnic_adapter *adapter = netdev_priv(dev); - if (!(adapter->capabilities & QLCNIC_FW_CAPABILITY_TSO)) - return -EOPNOTSUPP; - if (data) - dev->features |= (NETIF_F_TSO | NETIF_F_TSO6); - else - dev->features &= ~(NETIF_F_TSO | NETIF_F_TSO6); - - return 0; -} - static int qlcnic_set_led(struct net_device *dev, enum ethtool_phys_id_state state) { @@ -993,50 +926,6 @@ static int qlcnic_get_intr_coalesce(struct net_device *netdev, return 0; } -static int qlcnic_set_flags(struct net_device *netdev, u32 data) -{ - struct qlcnic_adapter *adapter = netdev_priv(netdev); - int hw_lro; - - if (ethtool_invalid_flags(netdev, data, ETH_FLAG_LRO)) - return -EINVAL; - - if (data & ETH_FLAG_LRO) { - - if (netdev->features & NETIF_F_LRO) - return 0; - - if (!(adapter->capabilities & QLCNIC_FW_CAPABILITY_HW_LRO)) - return -EINVAL; - - if (!adapter->rx_csum) { - dev_info(&adapter->pdev->dev, "rx csum is off, " - "cannot toggle lro\n"); - return -EINVAL; - } - - hw_lro = QLCNIC_LRO_ENABLED; - netdev->features |= NETIF_F_LRO; - - } else { - - if (!(netdev->features & NETIF_F_LRO)) - return 0; - - hw_lro = 0; - netdev->features &= ~NETIF_F_LRO; - } - - if (qlcnic_config_hw_lro(adapter, hw_lro)) - return -EIO; - - if ((hw_lro == 0) && qlcnic_send_lro_cleanup(adapter)) - return -EIO; - - - return 0; -} - static u32 qlcnic_get_msglevel(struct net_device *netdev) { struct qlcnic_adapter *adapter = netdev_priv(netdev); @@ -1064,23 +953,14 @@ const struct ethtool_ops qlcnic_ethtool_ops = { .set_ringparam = qlcnic_set_ringparam, .get_pauseparam = qlcnic_get_pauseparam, .set_pauseparam = qlcnic_set_pauseparam, - .get_tx_csum = qlcnic_get_tx_csum, - .set_tx_csum = qlcnic_set_tx_csum, - .set_sg = ethtool_op_set_sg, - .get_tso = qlcnic_get_tso, - .set_tso = qlcnic_set_tso, .get_wol = qlcnic_get_wol, .set_wol = qlcnic_set_wol, .self_test = qlcnic_diag_test, .get_strings = qlcnic_get_strings, .get_ethtool_stats = qlcnic_get_ethtool_stats, .get_sset_count = qlcnic_get_sset_count, - .get_rx_csum = qlcnic_get_rx_csum, - .set_rx_csum = qlcnic_set_rx_csum, .get_coalesce = qlcnic_get_intr_coalesce, .set_coalesce = qlcnic_set_intr_coalesce, - .get_flags = ethtool_op_get_flags, - .set_flags = qlcnic_set_flags, .set_phys_id = qlcnic_set_led, .set_msglevel = qlcnic_set_msglevel, .get_msglevel = qlcnic_get_msglevel, diff --git a/drivers/net/qlcnic/qlcnic_hw.c b/drivers/net/qlcnic/qlcnic_hw.c index 498cca9..cbb27f2 100644 --- a/drivers/net/qlcnic/qlcnic_hw.c +++ b/drivers/net/qlcnic/qlcnic_hw.c @@ -758,6 +758,43 @@ int qlcnic_change_mtu(struct net_device *netdev, int mtu) return rc; } + +u32 qlcnic_fix_features(struct net_device *netdev, u32 features) +{ + struct qlcnic_adapter *adapter = netdev_priv(netdev); + + if ((adapter->flags & QLCNIC_ESWITCH_ENABLED)) { + u32 changed = features ^ netdev->features; + features ^= changed & (NETIF_F_ALL_CSUM | NETIF_F_RXCSUM); + } + + if (!(features & NETIF_F_RXCSUM)) + features &= ~NETIF_F_LRO; + + return features; +} + + +int qlcnic_set_features(struct net_device *netdev, u32 features) +{ + struct qlcnic_adapter *adapter = netdev_priv(netdev); + u32 changed = netdev->features ^ features; + int hw_lro = (features & NETIF_F_LRO) ? QLCNIC_LRO_ENABLED : 0; + + if (!(changed & NETIF_F_LRO)) + return 0; + + netdev->features = features ^ NETIF_F_LRO; + + if (qlcnic_config_hw_lro(adapter, hw_lro)) + return -EIO; + + if ((hw_lro == 0) && qlcnic_send_lro_cleanup(adapter)) + return -EIO; + + return 0; +} + /* * Changes the CRB window to the specified window. */ diff --git a/drivers/net/qlcnic/qlcnic_init.c b/drivers/net/qlcnic/qlcnic_init.c index 4ec0eeb..d0f338b 100644 --- a/drivers/net/qlcnic/qlcnic_init.c +++ b/drivers/net/qlcnic/qlcnic_init.c @@ -1390,8 +1390,8 @@ static struct sk_buff *qlcnic_process_rxbuf(struct qlcnic_adapter *adapter, skb = buffer->skb; - if (likely(adapter->rx_csum && (cksum == STATUS_CKSUM_OK || - cksum == STATUS_CKSUM_LOOP))) { + if (likely((adapter->netdev->features & NETIF_F_RXCSUM) && + (cksum == STATUS_CKSUM_OK || cksum == STATUS_CKSUM_LOOP))) { adapter->stats.csummed++; skb->ip_summed = CHECKSUM_UNNECESSARY; } else { diff --git a/drivers/net/qlcnic/qlcnic_main.c b/drivers/net/qlcnic/qlcnic_main.c index e9e9ba6..6e61951 100644 --- a/drivers/net/qlcnic/qlcnic_main.c +++ b/drivers/net/qlcnic/qlcnic_main.c @@ -328,6 +328,8 @@ static const struct net_device_ops qlcnic_netdev_ops = { .ndo_set_multicast_list = qlcnic_set_multi, .ndo_set_mac_address = qlcnic_set_mac, .ndo_change_mtu = qlcnic_change_mtu, + .ndo_fix_features = qlcnic_fix_features, + .ndo_set_features = qlcnic_set_features, .ndo_tx_timeout = qlcnic_tx_timeout, .ndo_vlan_rx_add_vid = qlcnic_vlan_rx_add, .ndo_vlan_rx_kill_vid = qlcnic_vlan_rx_del, @@ -764,7 +766,7 @@ qlcnic_set_netdev_features(struct qlcnic_adapter *adapter, struct net_device *netdev = adapter->netdev; unsigned long features, vlan_features; - features = (NETIF_F_SG | NETIF_F_IP_CSUM | + features = (NETIF_F_SG | NETIF_F_IP_CSUM | NETIF_F_RXCSUM | NETIF_F_IPV6_CSUM | NETIF_F_GRO); vlan_features = (NETIF_F_SG | NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM | NETIF_F_HW_VLAN_FILTER); @@ -779,14 +781,12 @@ qlcnic_set_netdev_features(struct qlcnic_adapter *adapter, if (esw_cfg->offload_flags & BIT_0) { netdev->features |= features; - adapter->rx_csum = 1; if (!(esw_cfg->offload_flags & BIT_1)) netdev->features &= ~NETIF_F_TSO; if (!(esw_cfg->offload_flags & BIT_2)) netdev->features &= ~NETIF_F_TSO6; } else { netdev->features &= ~features; - adapter->rx_csum = 0; } netdev->vlan_features = (features & vlan_features); @@ -1436,7 +1436,6 @@ qlcnic_setup_netdev(struct qlcnic_adapter *adapter, int err; struct pci_dev *pdev = adapter->pdev; - adapter->rx_csum = 1; adapter->mc_enabled = 0; adapter->max_mc_count = 38; @@ -1447,26 +1446,24 @@ qlcnic_setup_netdev(struct qlcnic_adapter *adapter, SET_ETHTOOL_OPS(netdev, &qlcnic_ethtool_ops); - netdev->features |= (NETIF_F_SG | NETIF_F_IP_CSUM | - NETIF_F_IPV6_CSUM | NETIF_F_GRO | NETIF_F_HW_VLAN_RX); - netdev->vlan_features |= (NETIF_F_SG | NETIF_F_IP_CSUM | - NETIF_F_IPV6_CSUM | NETIF_F_HW_VLAN_FILTER); + netdev->hw_features = NETIF_F_SG | NETIF_F_IP_CSUM | + NETIF_F_IPV6_CSUM | NETIF_F_RXCSUM; - if (adapter->capabilities & QLCNIC_FW_CAPABILITY_TSO) { - netdev->features |= (NETIF_F_TSO | NETIF_F_TSO6); - netdev->vlan_features |= (NETIF_F_TSO | NETIF_F_TSO6); - } + if (adapter->capabilities & QLCNIC_FW_CAPABILITY_TSO) + netdev->hw_features |= NETIF_F_TSO | NETIF_F_TSO6; + if (pci_using_dac) + netdev->hw_features |= NETIF_F_HIGHDMA; - if (pci_using_dac) { - netdev->features |= NETIF_F_HIGHDMA; - netdev->vlan_features |= NETIF_F_HIGHDMA; - } + netdev->vlan_features = netdev->hw_features; if (adapter->capabilities & QLCNIC_FW_CAPABILITY_FVLANTX) - netdev->features |= (NETIF_F_HW_VLAN_TX); - + netdev->hw_features |= NETIF_F_HW_VLAN_TX; if (adapter->capabilities & QLCNIC_FW_CAPABILITY_HW_LRO) - netdev->features |= NETIF_F_LRO; + netdev->hw_features |= NETIF_F_LRO; + + netdev->features |= netdev->hw_features | + NETIF_F_HW_VLAN_RX | NETIF_F_HW_VLAN_FILTER; + netdev->irq = adapter->msix_entries[0].vector; netif_carrier_off(netdev); -- cgit v0.10.2 From 47103041e91794acdbc6165da0ae288d844c820b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Miros=C5=82aw?= Date: Tue, 19 Apr 2011 03:35:06 +0000 Subject: net: xen-netback: convert to hw_features MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: MichaÅ‚ MirosÅ‚aw Acked-by: Ian Campbell Signed-off-by: David S. Miller diff --git a/drivers/net/xen-netback/common.h b/drivers/net/xen-netback/common.h index 5d7bbf2..8753e6d 100644 --- a/drivers/net/xen-netback/common.h +++ b/drivers/net/xen-netback/common.h @@ -73,9 +73,6 @@ struct xenvif { struct vm_struct *tx_comms_area; struct vm_struct *rx_comms_area; - /* Flags that must not be set in dev->features */ - u32 features_disabled; - /* Frontend feature information. */ u8 can_sg:1; u8 gso:1; diff --git a/drivers/net/xen-netback/interface.c b/drivers/net/xen-netback/interface.c index de569cc..0ca86f9 100644 --- a/drivers/net/xen-netback/interface.c +++ b/drivers/net/xen-netback/interface.c @@ -165,69 +165,18 @@ static int xenvif_change_mtu(struct net_device *dev, int mtu) return 0; } -static void xenvif_set_features(struct xenvif *vif) -{ - struct net_device *dev = vif->dev; - u32 features = dev->features; - - if (vif->can_sg) - features |= NETIF_F_SG; - if (vif->gso || vif->gso_prefix) - features |= NETIF_F_TSO; - if (vif->csum) - features |= NETIF_F_IP_CSUM; - - features &= ~(vif->features_disabled); - - if (!(features & NETIF_F_SG) && dev->mtu > ETH_DATA_LEN) - dev->mtu = ETH_DATA_LEN; - - dev->features = features; -} - -static int xenvif_set_tx_csum(struct net_device *dev, u32 data) -{ - struct xenvif *vif = netdev_priv(dev); - if (data) { - if (!vif->csum) - return -EOPNOTSUPP; - vif->features_disabled &= ~NETIF_F_IP_CSUM; - } else { - vif->features_disabled |= NETIF_F_IP_CSUM; - } - - xenvif_set_features(vif); - return 0; -} - -static int xenvif_set_sg(struct net_device *dev, u32 data) +static u32 xenvif_fix_features(struct net_device *dev, u32 features) { struct xenvif *vif = netdev_priv(dev); - if (data) { - if (!vif->can_sg) - return -EOPNOTSUPP; - vif->features_disabled &= ~NETIF_F_SG; - } else { - vif->features_disabled |= NETIF_F_SG; - } - xenvif_set_features(vif); - return 0; -} + if (!vif->can_sg) + features &= ~NETIF_F_SG; + if (!vif->gso && !vif->gso_prefix) + features &= ~NETIF_F_TSO; + if (!vif->csum) + features &= ~NETIF_F_IP_CSUM; -static int xenvif_set_tso(struct net_device *dev, u32 data) -{ - struct xenvif *vif = netdev_priv(dev); - if (data) { - if (!vif->gso && !vif->gso_prefix) - return -EOPNOTSUPP; - vif->features_disabled &= ~NETIF_F_TSO; - } else { - vif->features_disabled |= NETIF_F_TSO; - } - - xenvif_set_features(vif); - return 0; + return features; } static const struct xenvif_stat { @@ -274,12 +223,6 @@ static void xenvif_get_strings(struct net_device *dev, u32 stringset, u8 * data) } static struct ethtool_ops xenvif_ethtool_ops = { - .get_tx_csum = ethtool_op_get_tx_csum, - .set_tx_csum = xenvif_set_tx_csum, - .get_sg = ethtool_op_get_sg, - .set_sg = xenvif_set_sg, - .get_tso = ethtool_op_get_tso, - .set_tso = xenvif_set_tso, .get_link = ethtool_op_get_link, .get_sset_count = xenvif_get_sset_count, @@ -293,6 +236,7 @@ static struct net_device_ops xenvif_netdev_ops = { .ndo_open = xenvif_open, .ndo_stop = xenvif_close, .ndo_change_mtu = xenvif_change_mtu, + .ndo_fix_features = xenvif_fix_features, }; struct xenvif *xenvif_alloc(struct device *parent, domid_t domid, @@ -331,7 +275,8 @@ struct xenvif *xenvif_alloc(struct device *parent, domid_t domid, vif->credit_timeout.expires = jiffies; dev->netdev_ops = &xenvif_netdev_ops; - xenvif_set_features(vif); + dev->hw_features = NETIF_F_SG | NETIF_F_IP_CSUM | NETIF_F_TSO; + dev->features = dev->hw_features; SET_ETHTOOL_OPS(dev, &xenvif_ethtool_ops); dev->tx_queue_len = XENVIF_QUEUE_LENGTH; @@ -367,8 +312,6 @@ int xenvif_connect(struct xenvif *vif, unsigned long tx_ring_ref, if (vif->irq) return 0; - xenvif_set_features(vif); - err = xen_netbk_map_frontend_rings(vif, tx_ring_ref, rx_ring_ref); if (err < 0) goto err; @@ -384,9 +327,12 @@ int xenvif_connect(struct xenvif *vif, unsigned long tx_ring_ref, xenvif_get(vif); rtnl_lock(); - netif_carrier_on(vif->dev); if (netif_running(vif->dev)) xenvif_up(vif); + if (!vif->can_sg && vif->dev->mtu > ETH_DATA_LEN) + dev_set_mtu(vif->dev, ETH_DATA_LEN); + netdev_update_features(vif->dev); + netif_carrier_on(vif->dev); rtnl_unlock(); return 0; -- cgit v0.10.2 From 882553752196605bf27057e7adb298ecae8058c4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Miros=C5=82aw?= Date: Tue, 19 Apr 2011 06:13:10 +0000 Subject: net: tun: convert to hw_features MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This changes offload setting behaviour to what I think is correct: - offloads set via ethtool mean what admin wants to use (by default he wants 'em all) - offloads set via ioctl() mean what userspace is expecting to get (this limits which admin wishes are granted) - TUN_NOCHECKSUM is ignored, as it might cause broken packets when forwarded (ip_summed == CHECKSUM_UNNECESSARY means that checksum was verified, not that it can be ignored) If TUN_NOCHECKSUM is implemented, it should set skb->csum_* and skb->ip_summed (= CHECKSUM_PARTIAL) for known protocols and let others be verified by kernel when necessary. TUN_NOCHECKSUM handling was introduced by commit f43798c27684ab925adde7d8acc34c78c6e50df8: tun: Allow GSO using virtio_net_hdr Signed-off-by: MichaÅ‚ MirosÅ‚aw Signed-off-by: David S. Miller diff --git a/drivers/net/tun.c b/drivers/net/tun.c index f5e9ac0..ade3cf9 100644 --- a/drivers/net/tun.c +++ b/drivers/net/tun.c @@ -123,6 +123,9 @@ struct tun_struct { gid_t group; struct net_device *dev; + u32 set_features; +#define TUN_USER_FEATURES (NETIF_F_HW_CSUM|NETIF_F_TSO_ECN|NETIF_F_TSO| \ + NETIF_F_TSO6|NETIF_F_UFO) struct fasync_struct *fasync; struct tap_filter txflt; @@ -451,12 +454,20 @@ tun_net_change_mtu(struct net_device *dev, int new_mtu) return 0; } +static u32 tun_net_fix_features(struct net_device *dev, u32 features) +{ + struct tun_struct *tun = netdev_priv(dev); + + return (features & tun->set_features) | (features & ~TUN_USER_FEATURES); +} + static const struct net_device_ops tun_netdev_ops = { .ndo_uninit = tun_net_uninit, .ndo_open = tun_net_open, .ndo_stop = tun_net_close, .ndo_start_xmit = tun_net_xmit, .ndo_change_mtu = tun_net_change_mtu, + .ndo_fix_features = tun_net_fix_features, }; static const struct net_device_ops tap_netdev_ops = { @@ -465,6 +476,7 @@ static const struct net_device_ops tap_netdev_ops = { .ndo_stop = tun_net_close, .ndo_start_xmit = tun_net_xmit, .ndo_change_mtu = tun_net_change_mtu, + .ndo_fix_features = tun_net_fix_features, .ndo_set_multicast_list = tun_net_mclist, .ndo_set_mac_address = eth_mac_addr, .ndo_validate_addr = eth_validate_addr, @@ -628,8 +640,7 @@ static __inline__ ssize_t tun_get_user(struct tun_struct *tun, kfree_skb(skb); return -EINVAL; } - } else if (tun->flags & TUN_NOCHECKSUM) - skb->ip_summed = CHECKSUM_UNNECESSARY; + } switch (tun->flags & TUN_TYPE_MASK) { case TUN_TUN_DEV: @@ -1094,6 +1105,10 @@ static int tun_set_iff(struct net *net, struct file *file, struct ifreq *ifr) goto err_free_sk; } + dev->hw_features = NETIF_F_SG | NETIF_F_FRAGLIST | + TUN_USER_FEATURES; + dev->features = dev->hw_features; + err = register_netdevice(tun->dev); if (err < 0) goto err_free_sk; @@ -1158,18 +1173,12 @@ static int tun_get_iff(struct net *net, struct tun_struct *tun, /* This is like a cut-down ethtool ops, except done via tun fd so no * privs required. */ -static int set_offload(struct net_device *dev, unsigned long arg) +static int set_offload(struct tun_struct *tun, unsigned long arg) { - u32 old_features, features; - - old_features = dev->features; - /* Unset features, set them as we chew on the arg. */ - features = (old_features & ~(NETIF_F_HW_CSUM|NETIF_F_SG|NETIF_F_FRAGLIST - |NETIF_F_TSO_ECN|NETIF_F_TSO|NETIF_F_TSO6 - |NETIF_F_UFO)); + u32 features = 0; if (arg & TUN_F_CSUM) { - features |= NETIF_F_HW_CSUM|NETIF_F_SG|NETIF_F_FRAGLIST; + features |= NETIF_F_HW_CSUM; arg &= ~TUN_F_CSUM; if (arg & (TUN_F_TSO4|TUN_F_TSO6)) { @@ -1195,9 +1204,8 @@ static int set_offload(struct net_device *dev, unsigned long arg) if (arg) return -EINVAL; - dev->features = features; - if (old_features != dev->features) - netdev_features_change(dev); + tun->set_features = features; + netdev_update_features(tun->dev); return 0; } @@ -1262,12 +1270,9 @@ static long __tun_chr_ioctl(struct file *file, unsigned int cmd, case TUNSETNOCSUM: /* Disable/Enable checksum */ - if (arg) - tun->flags |= TUN_NOCHECKSUM; - else - tun->flags &= ~TUN_NOCHECKSUM; - tun_debug(KERN_INFO, tun, "checksum %s\n", + /* [unimplemented] */ + tun_debug(KERN_INFO, tun, "ignored: set checksum %s\n", arg ? "disabled" : "enabled"); break; @@ -1316,7 +1321,7 @@ static long __tun_chr_ioctl(struct file *file, unsigned int cmd, break; #endif case TUNSETOFFLOAD: - ret = set_offload(tun->dev, arg); + ret = set_offload(tun, arg); break; case TUNSETTXFILTER: @@ -1595,30 +1600,12 @@ static void tun_set_msglevel(struct net_device *dev, u32 value) #endif } -static u32 tun_get_rx_csum(struct net_device *dev) -{ - struct tun_struct *tun = netdev_priv(dev); - return (tun->flags & TUN_NOCHECKSUM) == 0; -} - -static int tun_set_rx_csum(struct net_device *dev, u32 data) -{ - struct tun_struct *tun = netdev_priv(dev); - if (data) - tun->flags &= ~TUN_NOCHECKSUM; - else - tun->flags |= TUN_NOCHECKSUM; - return 0; -} - static const struct ethtool_ops tun_ethtool_ops = { .get_settings = tun_get_settings, .get_drvinfo = tun_get_drvinfo, .get_msglevel = tun_get_msglevel, .set_msglevel = tun_set_msglevel, .get_link = ethtool_op_get_link, - .get_rx_csum = tun_get_rx_csum, - .set_rx_csum = tun_set_rx_csum }; -- cgit v0.10.2 From 6f4d6dc167a001267eeff18bdea0ce3e9108c662 Mon Sep 17 00:00:00 2001 From: Breno Leitao Date: Tue, 19 Apr 2011 09:39:22 +0000 Subject: ehea: Fix a DLPAR bug on ehea_rereg_mrs(). We are currently continuing if ehea_restart_qps() fails, when we do a memory DLPAR (remove or add more memory to the system). This patch just let the NAPI disabled if the ehea_restart_qps() fails. Signed-off-by: Breno Leitao Signed-off-by: David S. Miller diff --git a/drivers/net/ehea/ehea_main.c b/drivers/net/ehea/ehea_main.c index f75d314..53c0f04 100644 --- a/drivers/net/ehea/ehea_main.c +++ b/drivers/net/ehea/ehea_main.c @@ -3040,11 +3040,14 @@ static void ehea_rereg_mrs(void) if (dev->flags & IFF_UP) { mutex_lock(&port->port_lock); - port_napi_enable(port); ret = ehea_restart_qps(dev); - check_sqs(port); - if (!ret) + if (!ret) { + check_sqs(port); + port_napi_enable(port); netif_wake_queue(dev); + } else { + netdev_err(dev, "Unable to restart QPS\n"); + } mutex_unlock(&port->port_lock); } } -- cgit v0.10.2 From 2430af8b7fa37ac0be102c77f9dc6ee669d24ba9 Mon Sep 17 00:00:00 2001 From: Jiri Bohac Date: Tue, 19 Apr 2011 02:09:55 +0000 Subject: bonding: 802.3ad - fix agg_device_up The slave member of struct aggregator does not necessarily point to a slave which is part of the aggregator. It points to the slave structure containing the aggregator structure, while completely different slaves (or no slaves at all) may be part of the aggregator. The agg_device_up() function wrongly uses agg->slave to find the state of the aggregator. Use agg->lag_ports->slave instead. The bug has been introduced by commit 4cd6fe1c6483cde93e2ec91f58b7af9c9eea51ad ("bonding: fix link down handling in 802.3ad mode"). Signed-off-by: Jiri Bohac Signed-off-by: Jay Vosburgh Signed-off-by: David S. Miller diff --git a/drivers/net/bonding/bond_3ad.c b/drivers/net/bonding/bond_3ad.c index 494bf96..31912f1 100644 --- a/drivers/net/bonding/bond_3ad.c +++ b/drivers/net/bonding/bond_3ad.c @@ -1482,8 +1482,11 @@ static struct aggregator *ad_agg_selection_test(struct aggregator *best, static int agg_device_up(const struct aggregator *agg) { - return (netif_running(agg->slave->dev) && - netif_carrier_ok(agg->slave->dev)); + struct port *port = agg->lag_ports; + if (!port) + return 0; + return (netif_running(port->slave->dev) && + netif_carrier_ok(port->slave->dev)); } /** -- cgit v0.10.2 From 8a00be1c89cc17fda5f438794ff27449af6f00f1 Mon Sep 17 00:00:00 2001 From: Shan Wei Date: Tue, 19 Apr 2011 21:25:40 +0000 Subject: sctp: check parameter value of length in ERROR chunk When an endpoint receives ERROR that parameter value is invalid, send an ABORT to peer with a Protocol Violation error code. Signed-off-by: Shan Wei Signed-off-by: Vlad Yasevich Signed-off-by: Wei Yongjun Signed-off-by: David S. Miller diff --git a/net/sctp/sm_statefuns.c b/net/sctp/sm_statefuns.c index c085472..fe2036d 100644 --- a/net/sctp/sm_statefuns.c +++ b/net/sctp/sm_statefuns.c @@ -3204,6 +3204,7 @@ sctp_disposition_t sctp_sf_operr_notify(const struct sctp_endpoint *ep, sctp_cmd_seq_t *commands) { struct sctp_chunk *chunk = arg; + sctp_errhdr_t *err; if (!sctp_vtag_verify(chunk, asoc)) return sctp_sf_pdiscard(ep, asoc, type, arg, commands); @@ -3212,6 +3213,10 @@ sctp_disposition_t sctp_sf_operr_notify(const struct sctp_endpoint *ep, if (!sctp_chunk_length_valid(chunk, sizeof(sctp_operr_chunk_t))) return sctp_sf_violation_chunklen(ep, asoc, type, arg, commands); + sctp_walk_errors(err, chunk->chunk_hdr); + if ((void *)err != (void *)chunk->chunk_end) + return sctp_sf_violation_paramlen(ep, asoc, type, arg, + (void *)err, commands); sctp_add_cmd_sf(commands, SCTP_CMD_PROCESS_OPERR, SCTP_CHUNK(chunk)); -- cgit v0.10.2 From 96ca468b86b09aa6a001ac65dba93a6c4a3692a5 Mon Sep 17 00:00:00 2001 From: Shan Wei Date: Tue, 19 Apr 2011 21:26:26 +0000 Subject: sctp: check invalid value of length parameter in error cause RFC4960, section 3.3.7 said: If an endpoint receives an ABORT with a format error or no TCB is found, it MUST silently discard it. When an endpoint receives ABORT that parameter value is invalid, drop it. Signed-off-by: Shan Wei Signed-off-by: Vlad Yasevich Signed-off-by: Wei Yongjun Signed-off-by: David S. Miller diff --git a/net/sctp/sm_statefuns.c b/net/sctp/sm_statefuns.c index fe2036d..194d5ec 100644 --- a/net/sctp/sm_statefuns.c +++ b/net/sctp/sm_statefuns.c @@ -2412,8 +2412,15 @@ static sctp_disposition_t __sctp_sf_do_9_1_abort(const struct sctp_endpoint *ep, /* See if we have an error cause code in the chunk. */ len = ntohs(chunk->chunk_hdr->length); - if (len >= sizeof(struct sctp_chunkhdr) + sizeof(struct sctp_errhdr)) + if (len >= sizeof(struct sctp_chunkhdr) + sizeof(struct sctp_errhdr)) { + + sctp_errhdr_t *err; + sctp_walk_errors(err, chunk->chunk_hdr); + if ((void *)err != (void *)chunk->chunk_end) + return sctp_sf_pdiscard(ep, asoc, type, arg, commands); + error = ((sctp_errhdr_t *)chunk->skb->data)->cause; + } sctp_add_cmd_sf(commands, SCTP_CMD_SET_SK_ERR, SCTP_ERROR(ECONNRESET)); /* ASSOC_FAILED will DELETE_TCB. */ -- cgit v0.10.2 From 48669698c23339e0fa31753f04e77648fc210339 Mon Sep 17 00:00:00 2001 From: Shan Wei Date: Tue, 19 Apr 2011 21:27:07 +0000 Subject: sctp: remove redundant check when walking through a list of TLV parameters When pos.v <= (void *)chunk + end - ntohs(pos.p->length) and ntohs(pos.p->length) >= sizeof(sctp_paramhdr_t) these two expressions are all true, pos.v <= (void *)chunk + end - sizeof(sctp_paramhdr_t) *must* be true. This patch removes this kind of redundant check. It's same to _sctp_walk_errors macro. Signed-off-by: Shan Wei Signed-off-by: Vlad Yasevich Signed-off-by: Wei Yongjun Signed-off-by: David S. Miller diff --git a/include/net/sctp/sctp.h b/include/net/sctp/sctp.h index 505845d..7e8e34c 100644 --- a/include/net/sctp/sctp.h +++ b/include/net/sctp/sctp.h @@ -531,7 +531,6 @@ _sctp_walk_params((pos), (chunk), ntohs((chunk)->chunk_hdr.length), member) #define _sctp_walk_params(pos, chunk, end, member)\ for (pos.v = chunk->member;\ - pos.v <= (void *)chunk + end - sizeof(sctp_paramhdr_t) &&\ pos.v <= (void *)chunk + end - ntohs(pos.p->length) &&\ ntohs(pos.p->length) >= sizeof(sctp_paramhdr_t);\ pos.v += WORD_ROUND(ntohs(pos.p->length))) @@ -542,7 +541,6 @@ _sctp_walk_errors((err), (chunk_hdr), ntohs((chunk_hdr)->length)) #define _sctp_walk_errors(err, chunk_hdr, end)\ for (err = (sctp_errhdr_t *)((void *)chunk_hdr + \ sizeof(sctp_chunkhdr_t));\ - (void *)err <= (void *)chunk_hdr + end - sizeof(sctp_errhdr_t) &&\ (void *)err <= (void *)chunk_hdr + end - ntohs(err->length) &&\ ntohs(err->length) >= sizeof(sctp_errhdr_t); \ err = (sctp_errhdr_t *)((void *)err + WORD_ROUND(ntohs(err->length)))) -- cgit v0.10.2 From 0b8f9e25b0aaf5a5d9fd844a97e5c17746b865d4 Mon Sep 17 00:00:00 2001 From: Vlad Yasevich Date: Tue, 19 Apr 2011 21:28:26 +0000 Subject: sctp: remove completely unsed EMPTY state SCTP does not SCTP_STATE_EMPTY and we can never be in that state. Remove useless code. Signed-off-by: Vlad Yasevich Signed-off-by: Wei Yongjun Signed-off-by: David S. Miller diff --git a/include/net/sctp/constants.h b/include/net/sctp/constants.h index deac13d..942b864 100644 --- a/include/net/sctp/constants.h +++ b/include/net/sctp/constants.h @@ -187,15 +187,14 @@ typedef enum { /* SCTP state defines for internal state machine */ typedef enum { - SCTP_STATE_EMPTY = 0, - SCTP_STATE_CLOSED = 1, - SCTP_STATE_COOKIE_WAIT = 2, - SCTP_STATE_COOKIE_ECHOED = 3, - SCTP_STATE_ESTABLISHED = 4, - SCTP_STATE_SHUTDOWN_PENDING = 5, - SCTP_STATE_SHUTDOWN_SENT = 6, - SCTP_STATE_SHUTDOWN_RECEIVED = 7, - SCTP_STATE_SHUTDOWN_ACK_SENT = 8, + SCTP_STATE_CLOSED = 0, + SCTP_STATE_COOKIE_WAIT = 1, + SCTP_STATE_COOKIE_ECHOED = 2, + SCTP_STATE_ESTABLISHED = 3, + SCTP_STATE_SHUTDOWN_PENDING = 4, + SCTP_STATE_SHUTDOWN_SENT = 5, + SCTP_STATE_SHUTDOWN_RECEIVED = 6, + SCTP_STATE_SHUTDOWN_ACK_SENT = 7, } sctp_state_t; diff --git a/net/sctp/debug.c b/net/sctp/debug.c index bf24fa6..ec997cf 100644 --- a/net/sctp/debug.c +++ b/net/sctp/debug.c @@ -98,7 +98,6 @@ const char *sctp_cname(const sctp_subtype_t cid) /* These are printable forms of the states. */ const char *const sctp_state_tbl[SCTP_STATE_NUM_STATES] = { - "STATE_EMPTY", "STATE_CLOSED", "STATE_COOKIE_WAIT", "STATE_COOKIE_ECHOED", diff --git a/net/sctp/outqueue.c b/net/sctp/outqueue.c index 7812772..3e9d8d2 100644 --- a/net/sctp/outqueue.c +++ b/net/sctp/outqueue.c @@ -320,7 +320,6 @@ int sctp_outq_tail(struct sctp_outq *q, struct sctp_chunk *chunk) * chunk. */ switch (q->asoc->state) { - case SCTP_STATE_EMPTY: case SCTP_STATE_CLOSED: case SCTP_STATE_SHUTDOWN_PENDING: case SCTP_STATE_SHUTDOWN_SENT: diff --git a/net/sctp/sm_statetable.c b/net/sctp/sm_statetable.c index 546d4387..881196b 100644 --- a/net/sctp/sm_statetable.c +++ b/net/sctp/sm_statetable.c @@ -107,8 +107,6 @@ const sctp_sm_table_entry_t *sctp_sm_lookup_event(sctp_event_t event_type, #define TYPE_SCTP_FUNC(func) {.fn = func, .name = #func} #define TYPE_SCTP_DATA { \ - /* SCTP_STATE_EMPTY */ \ - TYPE_SCTP_FUNC(sctp_sf_ootb), \ /* SCTP_STATE_CLOSED */ \ TYPE_SCTP_FUNC(sctp_sf_ootb), \ /* SCTP_STATE_COOKIE_WAIT */ \ @@ -128,8 +126,6 @@ const sctp_sm_table_entry_t *sctp_sm_lookup_event(sctp_event_t event_type, } /* TYPE_SCTP_DATA */ #define TYPE_SCTP_INIT { \ - /* SCTP_STATE_EMPTY */ \ - TYPE_SCTP_FUNC(sctp_sf_bug), \ /* SCTP_STATE_CLOSED */ \ TYPE_SCTP_FUNC(sctp_sf_do_5_1B_init), \ /* SCTP_STATE_COOKIE_WAIT */ \ @@ -149,8 +145,6 @@ const sctp_sm_table_entry_t *sctp_sm_lookup_event(sctp_event_t event_type, } /* TYPE_SCTP_INIT */ #define TYPE_SCTP_INIT_ACK { \ - /* SCTP_STATE_EMPTY */ \ - TYPE_SCTP_FUNC(sctp_sf_ootb), \ /* SCTP_STATE_CLOSED */ \ TYPE_SCTP_FUNC(sctp_sf_do_5_2_3_initack), \ /* SCTP_STATE_COOKIE_WAIT */ \ @@ -170,8 +164,6 @@ const sctp_sm_table_entry_t *sctp_sm_lookup_event(sctp_event_t event_type, } /* TYPE_SCTP_INIT_ACK */ #define TYPE_SCTP_SACK { \ - /* SCTP_STATE_EMPTY */ \ - TYPE_SCTP_FUNC(sctp_sf_ootb), \ /* SCTP_STATE_CLOSED */ \ TYPE_SCTP_FUNC(sctp_sf_ootb), \ /* SCTP_STATE_COOKIE_WAIT */ \ @@ -191,8 +183,6 @@ const sctp_sm_table_entry_t *sctp_sm_lookup_event(sctp_event_t event_type, } /* TYPE_SCTP_SACK */ #define TYPE_SCTP_HEARTBEAT { \ - /* SCTP_STATE_EMPTY */ \ - TYPE_SCTP_FUNC(sctp_sf_ootb), \ /* SCTP_STATE_CLOSED */ \ TYPE_SCTP_FUNC(sctp_sf_ootb), \ /* SCTP_STATE_COOKIE_WAIT */ \ @@ -213,8 +203,6 @@ const sctp_sm_table_entry_t *sctp_sm_lookup_event(sctp_event_t event_type, } /* TYPE_SCTP_HEARTBEAT */ #define TYPE_SCTP_HEARTBEAT_ACK { \ - /* SCTP_STATE_EMPTY */ \ - TYPE_SCTP_FUNC(sctp_sf_ootb), \ /* SCTP_STATE_CLOSED */ \ TYPE_SCTP_FUNC(sctp_sf_ootb), \ /* SCTP_STATE_COOKIE_WAIT */ \ @@ -234,8 +222,6 @@ const sctp_sm_table_entry_t *sctp_sm_lookup_event(sctp_event_t event_type, } /* TYPE_SCTP_HEARTBEAT_ACK */ #define TYPE_SCTP_ABORT { \ - /* SCTP_STATE_EMPTY */ \ - TYPE_SCTP_FUNC(sctp_sf_ootb), \ /* SCTP_STATE_CLOSED */ \ TYPE_SCTP_FUNC(sctp_sf_pdiscard), \ /* SCTP_STATE_COOKIE_WAIT */ \ @@ -255,8 +241,6 @@ const sctp_sm_table_entry_t *sctp_sm_lookup_event(sctp_event_t event_type, } /* TYPE_SCTP_ABORT */ #define TYPE_SCTP_SHUTDOWN { \ - /* SCTP_STATE_EMPTY */ \ - TYPE_SCTP_FUNC(sctp_sf_ootb), \ /* SCTP_STATE_CLOSED */ \ TYPE_SCTP_FUNC(sctp_sf_ootb), \ /* SCTP_STATE_COOKIE_WAIT */ \ @@ -276,8 +260,6 @@ const sctp_sm_table_entry_t *sctp_sm_lookup_event(sctp_event_t event_type, } /* TYPE_SCTP_SHUTDOWN */ #define TYPE_SCTP_SHUTDOWN_ACK { \ - /* SCTP_STATE_EMPTY */ \ - TYPE_SCTP_FUNC(sctp_sf_ootb), \ /* SCTP_STATE_CLOSED */ \ TYPE_SCTP_FUNC(sctp_sf_ootb), \ /* SCTP_STATE_COOKIE_WAIT */ \ @@ -297,8 +279,6 @@ const sctp_sm_table_entry_t *sctp_sm_lookup_event(sctp_event_t event_type, } /* TYPE_SCTP_SHUTDOWN_ACK */ #define TYPE_SCTP_ERROR { \ - /* SCTP_STATE_EMPTY */ \ - TYPE_SCTP_FUNC(sctp_sf_ootb), \ /* SCTP_STATE_CLOSED */ \ TYPE_SCTP_FUNC(sctp_sf_ootb), \ /* SCTP_STATE_COOKIE_WAIT */ \ @@ -318,8 +298,6 @@ const sctp_sm_table_entry_t *sctp_sm_lookup_event(sctp_event_t event_type, } /* TYPE_SCTP_ERROR */ #define TYPE_SCTP_COOKIE_ECHO { \ - /* SCTP_STATE_EMPTY */ \ - TYPE_SCTP_FUNC(sctp_sf_bug), \ /* SCTP_STATE_CLOSED */ \ TYPE_SCTP_FUNC(sctp_sf_do_5_1D_ce), \ /* SCTP_STATE_COOKIE_WAIT */ \ @@ -339,8 +317,6 @@ const sctp_sm_table_entry_t *sctp_sm_lookup_event(sctp_event_t event_type, } /* TYPE_SCTP_COOKIE_ECHO */ #define TYPE_SCTP_COOKIE_ACK { \ - /* SCTP_STATE_EMPTY */ \ - TYPE_SCTP_FUNC(sctp_sf_ootb), \ /* SCTP_STATE_CLOSED */ \ TYPE_SCTP_FUNC(sctp_sf_discard_chunk), \ /* SCTP_STATE_COOKIE_WAIT */ \ @@ -360,8 +336,6 @@ const sctp_sm_table_entry_t *sctp_sm_lookup_event(sctp_event_t event_type, } /* TYPE_SCTP_COOKIE_ACK */ #define TYPE_SCTP_ECN_ECNE { \ - /* SCTP_STATE_EMPTY */ \ - TYPE_SCTP_FUNC(sctp_sf_ootb), \ /* SCTP_STATE_CLOSED */ \ TYPE_SCTP_FUNC(sctp_sf_discard_chunk), \ /* SCTP_STATE_COOKIE_WAIT */ \ @@ -381,8 +355,6 @@ const sctp_sm_table_entry_t *sctp_sm_lookup_event(sctp_event_t event_type, } /* TYPE_SCTP_ECN_ECNE */ #define TYPE_SCTP_ECN_CWR { \ - /* SCTP_STATE_EMPTY */ \ - TYPE_SCTP_FUNC(sctp_sf_ootb), \ /* SCTP_STATE_CLOSED */ \ TYPE_SCTP_FUNC(sctp_sf_discard_chunk), \ /* SCTP_STATE_COOKIE_WAIT */ \ @@ -402,8 +374,6 @@ const sctp_sm_table_entry_t *sctp_sm_lookup_event(sctp_event_t event_type, } /* TYPE_SCTP_ECN_CWR */ #define TYPE_SCTP_SHUTDOWN_COMPLETE { \ - /* SCTP_STATE_EMPTY */ \ - TYPE_SCTP_FUNC(sctp_sf_ootb), \ /* SCTP_STATE_CLOSED */ \ TYPE_SCTP_FUNC(sctp_sf_discard_chunk), \ /* SCTP_STATE_COOKIE_WAIT */ \ @@ -446,8 +416,6 @@ static const sctp_sm_table_entry_t chunk_event_table[SCTP_NUM_BASE_CHUNK_TYPES][ }; /* state_fn_t chunk_event_table[][] */ #define TYPE_SCTP_ASCONF { \ - /* SCTP_STATE_EMPTY */ \ - TYPE_SCTP_FUNC(sctp_sf_ootb), \ /* SCTP_STATE_CLOSED */ \ TYPE_SCTP_FUNC(sctp_sf_discard_chunk), \ /* SCTP_STATE_COOKIE_WAIT */ \ @@ -467,8 +435,6 @@ static const sctp_sm_table_entry_t chunk_event_table[SCTP_NUM_BASE_CHUNK_TYPES][ } /* TYPE_SCTP_ASCONF */ #define TYPE_SCTP_ASCONF_ACK { \ - /* SCTP_STATE_EMPTY */ \ - TYPE_SCTP_FUNC(sctp_sf_ootb), \ /* SCTP_STATE_CLOSED */ \ TYPE_SCTP_FUNC(sctp_sf_discard_chunk), \ /* SCTP_STATE_COOKIE_WAIT */ \ @@ -496,8 +462,6 @@ static const sctp_sm_table_entry_t addip_chunk_event_table[SCTP_NUM_ADDIP_CHUNK_ }; /*state_fn_t addip_chunk_event_table[][] */ #define TYPE_SCTP_FWD_TSN { \ - /* SCTP_STATE_EMPTY */ \ - TYPE_SCTP_FUNC(sctp_sf_ootb), \ /* SCTP_STATE_CLOSED */ \ TYPE_SCTP_FUNC(sctp_sf_ootb), \ /* SCTP_STATE_COOKIE_WAIT */ \ @@ -524,8 +488,6 @@ static const sctp_sm_table_entry_t prsctp_chunk_event_table[SCTP_NUM_PRSCTP_CHUN }; /*state_fn_t prsctp_chunk_event_table[][] */ #define TYPE_SCTP_AUTH { \ - /* SCTP_STATE_EMPTY */ \ - TYPE_SCTP_FUNC(sctp_sf_ootb), \ /* SCTP_STATE_CLOSED */ \ TYPE_SCTP_FUNC(sctp_sf_ootb), \ /* SCTP_STATE_COOKIE_WAIT */ \ @@ -553,8 +515,6 @@ static const sctp_sm_table_entry_t auth_chunk_event_table[SCTP_NUM_AUTH_CHUNK_TY static const sctp_sm_table_entry_t chunk_event_table_unknown[SCTP_STATE_NUM_STATES] = { - /* SCTP_STATE_EMPTY */ - TYPE_SCTP_FUNC(sctp_sf_ootb), /* SCTP_STATE_CLOSED */ TYPE_SCTP_FUNC(sctp_sf_ootb), /* SCTP_STATE_COOKIE_WAIT */ @@ -575,8 +535,6 @@ chunk_event_table_unknown[SCTP_STATE_NUM_STATES] = { #define TYPE_SCTP_PRIMITIVE_ASSOCIATE { \ - /* SCTP_STATE_EMPTY */ \ - TYPE_SCTP_FUNC(sctp_sf_bug), \ /* SCTP_STATE_CLOSED */ \ TYPE_SCTP_FUNC(sctp_sf_do_prm_asoc), \ /* SCTP_STATE_COOKIE_WAIT */ \ @@ -596,8 +554,6 @@ chunk_event_table_unknown[SCTP_STATE_NUM_STATES] = { } /* TYPE_SCTP_PRIMITIVE_ASSOCIATE */ #define TYPE_SCTP_PRIMITIVE_SHUTDOWN { \ - /* SCTP_STATE_EMPTY */ \ - TYPE_SCTP_FUNC(sctp_sf_bug), \ /* SCTP_STATE_CLOSED */ \ TYPE_SCTP_FUNC(sctp_sf_error_closed), \ /* SCTP_STATE_COOKIE_WAIT */ \ @@ -617,8 +573,6 @@ chunk_event_table_unknown[SCTP_STATE_NUM_STATES] = { } /* TYPE_SCTP_PRIMITIVE_SHUTDOWN */ #define TYPE_SCTP_PRIMITIVE_ABORT { \ - /* SCTP_STATE_EMPTY */ \ - TYPE_SCTP_FUNC(sctp_sf_bug), \ /* SCTP_STATE_CLOSED */ \ TYPE_SCTP_FUNC(sctp_sf_error_closed), \ /* SCTP_STATE_COOKIE_WAIT */ \ @@ -638,8 +592,6 @@ chunk_event_table_unknown[SCTP_STATE_NUM_STATES] = { } /* TYPE_SCTP_PRIMITIVE_ABORT */ #define TYPE_SCTP_PRIMITIVE_SEND { \ - /* SCTP_STATE_EMPTY */ \ - TYPE_SCTP_FUNC(sctp_sf_bug), \ /* SCTP_STATE_CLOSED */ \ TYPE_SCTP_FUNC(sctp_sf_error_closed), \ /* SCTP_STATE_COOKIE_WAIT */ \ @@ -659,8 +611,6 @@ chunk_event_table_unknown[SCTP_STATE_NUM_STATES] = { } /* TYPE_SCTP_PRIMITIVE_SEND */ #define TYPE_SCTP_PRIMITIVE_REQUESTHEARTBEAT { \ - /* SCTP_STATE_EMPTY */ \ - TYPE_SCTP_FUNC(sctp_sf_bug), \ /* SCTP_STATE_CLOSED */ \ TYPE_SCTP_FUNC(sctp_sf_error_closed), \ /* SCTP_STATE_COOKIE_WAIT */ \ @@ -680,8 +630,6 @@ chunk_event_table_unknown[SCTP_STATE_NUM_STATES] = { } /* TYPE_SCTP_PRIMITIVE_REQUESTHEARTBEAT */ #define TYPE_SCTP_PRIMITIVE_ASCONF { \ - /* SCTP_STATE_EMPTY */ \ - TYPE_SCTP_FUNC(sctp_sf_bug), \ /* SCTP_STATE_CLOSED */ \ TYPE_SCTP_FUNC(sctp_sf_error_closed), \ /* SCTP_STATE_COOKIE_WAIT */ \ @@ -713,8 +661,6 @@ static const sctp_sm_table_entry_t primitive_event_table[SCTP_NUM_PRIMITIVE_TYPE }; #define TYPE_SCTP_OTHER_NO_PENDING_TSN { \ - /* SCTP_STATE_EMPTY */ \ - TYPE_SCTP_FUNC(sctp_sf_bug), \ /* SCTP_STATE_CLOSED */ \ TYPE_SCTP_FUNC(sctp_sf_ignore_other), \ /* SCTP_STATE_COOKIE_WAIT */ \ @@ -734,8 +680,6 @@ static const sctp_sm_table_entry_t primitive_event_table[SCTP_NUM_PRIMITIVE_TYPE } #define TYPE_SCTP_OTHER_ICMP_PROTO_UNREACH { \ - /* SCTP_STATE_EMPTY */ \ - TYPE_SCTP_FUNC(sctp_sf_bug), \ /* SCTP_STATE_CLOSED */ \ TYPE_SCTP_FUNC(sctp_sf_ignore_other), \ /* SCTP_STATE_COOKIE_WAIT */ \ @@ -760,8 +704,6 @@ static const sctp_sm_table_entry_t other_event_table[SCTP_NUM_OTHER_TYPES][SCTP_ }; #define TYPE_SCTP_EVENT_TIMEOUT_NONE { \ - /* SCTP_STATE_EMPTY */ \ - TYPE_SCTP_FUNC(sctp_sf_bug), \ /* SCTP_STATE_CLOSED */ \ TYPE_SCTP_FUNC(sctp_sf_bug), \ /* SCTP_STATE_COOKIE_WAIT */ \ @@ -781,8 +723,6 @@ static const sctp_sm_table_entry_t other_event_table[SCTP_NUM_OTHER_TYPES][SCTP_ } #define TYPE_SCTP_EVENT_TIMEOUT_T1_COOKIE { \ - /* SCTP_STATE_EMPTY */ \ - TYPE_SCTP_FUNC(sctp_sf_bug), \ /* SCTP_STATE_CLOSED */ \ TYPE_SCTP_FUNC(sctp_sf_timer_ignore), \ /* SCTP_STATE_COOKIE_WAIT */ \ @@ -802,8 +742,6 @@ static const sctp_sm_table_entry_t other_event_table[SCTP_NUM_OTHER_TYPES][SCTP_ } #define TYPE_SCTP_EVENT_TIMEOUT_T1_INIT { \ - /* SCTP_STATE_EMPTY */ \ - TYPE_SCTP_FUNC(sctp_sf_bug), \ /* SCTP_STATE_CLOSED */ \ TYPE_SCTP_FUNC(sctp_sf_timer_ignore), \ /* SCTP_STATE_COOKIE_WAIT */ \ @@ -823,8 +761,6 @@ static const sctp_sm_table_entry_t other_event_table[SCTP_NUM_OTHER_TYPES][SCTP_ } #define TYPE_SCTP_EVENT_TIMEOUT_T2_SHUTDOWN { \ - /* SCTP_STATE_EMPTY */ \ - TYPE_SCTP_FUNC(sctp_sf_bug), \ /* SCTP_STATE_CLOSED */ \ TYPE_SCTP_FUNC(sctp_sf_timer_ignore), \ /* SCTP_STATE_COOKIE_WAIT */ \ @@ -844,8 +780,6 @@ static const sctp_sm_table_entry_t other_event_table[SCTP_NUM_OTHER_TYPES][SCTP_ } #define TYPE_SCTP_EVENT_TIMEOUT_T3_RTX { \ - /* SCTP_STATE_EMPTY */ \ - TYPE_SCTP_FUNC(sctp_sf_bug), \ /* SCTP_STATE_CLOSED */ \ TYPE_SCTP_FUNC(sctp_sf_timer_ignore), \ /* SCTP_STATE_COOKIE_WAIT */ \ @@ -865,8 +799,6 @@ static const sctp_sm_table_entry_t other_event_table[SCTP_NUM_OTHER_TYPES][SCTP_ } #define TYPE_SCTP_EVENT_TIMEOUT_T4_RTO { \ - /* SCTP_STATE_EMPTY */ \ - TYPE_SCTP_FUNC(sctp_sf_bug), \ /* SCTP_STATE_CLOSED */ \ TYPE_SCTP_FUNC(sctp_sf_timer_ignore), \ /* SCTP_STATE_COOKIE_WAIT */ \ @@ -886,8 +818,6 @@ static const sctp_sm_table_entry_t other_event_table[SCTP_NUM_OTHER_TYPES][SCTP_ } #define TYPE_SCTP_EVENT_TIMEOUT_T5_SHUTDOWN_GUARD { \ - /* SCTP_STATE_EMPTY */ \ - TYPE_SCTP_FUNC(sctp_sf_bug), \ /* SCTP_STATE_CLOSED */ \ TYPE_SCTP_FUNC(sctp_sf_timer_ignore), \ /* SCTP_STATE_COOKIE_WAIT */ \ @@ -907,8 +837,6 @@ static const sctp_sm_table_entry_t other_event_table[SCTP_NUM_OTHER_TYPES][SCTP_ } #define TYPE_SCTP_EVENT_TIMEOUT_HEARTBEAT { \ - /* SCTP_STATE_EMPTY */ \ - TYPE_SCTP_FUNC(sctp_sf_bug), \ /* SCTP_STATE_CLOSED */ \ TYPE_SCTP_FUNC(sctp_sf_timer_ignore), \ /* SCTP_STATE_COOKIE_WAIT */ \ @@ -928,8 +856,6 @@ static const sctp_sm_table_entry_t other_event_table[SCTP_NUM_OTHER_TYPES][SCTP_ } #define TYPE_SCTP_EVENT_TIMEOUT_SACK { \ - /* SCTP_STATE_EMPTY */ \ - TYPE_SCTP_FUNC(sctp_sf_bug), \ /* SCTP_STATE_CLOSED */ \ TYPE_SCTP_FUNC(sctp_sf_timer_ignore), \ /* SCTP_STATE_COOKIE_WAIT */ \ @@ -949,8 +875,6 @@ static const sctp_sm_table_entry_t other_event_table[SCTP_NUM_OTHER_TYPES][SCTP_ } #define TYPE_SCTP_EVENT_TIMEOUT_AUTOCLOSE { \ - /* SCTP_STATE_EMPTY */ \ - TYPE_SCTP_FUNC(sctp_sf_timer_ignore), \ /* SCTP_STATE_CLOSED */ \ TYPE_SCTP_FUNC(sctp_sf_timer_ignore), \ /* SCTP_STATE_COOKIE_WAIT */ \ -- cgit v0.10.2 From deb85a6ecc432a4f342004a6ac2a0dad7cba6846 Mon Sep 17 00:00:00 2001 From: Vlad Yasevich Date: Tue, 19 Apr 2011 21:29:23 +0000 Subject: sctp: bail from sctp_endpoint_lookup_assoc() if not bound The sctp_endpoint_lookup_assoc() function uses a port hash to lookup the association and then checks to see if any of them are on the current endpoint. However, if the current endpoint is not bound, there can't be any associations on it, thus we can bail early. Signed-off-by: Vlad Yasevich Signed-off-by: Wei Yongjun Signed-off-by: David S. Miller diff --git a/net/sctp/endpointola.c b/net/sctp/endpointola.c index e10acc0..c8cc24e 100644 --- a/net/sctp/endpointola.c +++ b/net/sctp/endpointola.c @@ -325,6 +325,7 @@ static struct sctp_association *__sctp_endpoint_lookup_assoc( struct sctp_transport **transport) { struct sctp_association *asoc = NULL; + struct sctp_association *tmp; struct sctp_transport *t = NULL; struct sctp_hashbucket *head; struct sctp_ep_common *epb; @@ -333,25 +334,32 @@ static struct sctp_association *__sctp_endpoint_lookup_assoc( int rport; *transport = NULL; + + /* If the local port is not set, there can't be any associations + * on this endpoint. + */ + if (!ep->base.bind_addr.port) + goto out; + rport = ntohs(paddr->v4.sin_port); hash = sctp_assoc_hashfn(ep->base.bind_addr.port, rport); head = &sctp_assoc_hashtable[hash]; read_lock(&head->lock); sctp_for_each_hentry(epb, node, &head->chain) { - asoc = sctp_assoc(epb); - if (asoc->ep != ep || rport != asoc->peer.port) - goto next; + tmp = sctp_assoc(epb); + if (tmp->ep != ep || rport != tmp->peer.port) + continue; - t = sctp_assoc_lookup_paddr(asoc, paddr); + t = sctp_assoc_lookup_paddr(tmp, paddr); if (t) { + asoc = tmp; *transport = t; break; } -next: - asoc = NULL; } read_unlock(&head->lock); +out: return asoc; } -- cgit v0.10.2 From 85c5ed4e44a262344ce43b4bf23204107923ca95 Mon Sep 17 00:00:00 2001 From: Shan Wei Date: Tue, 19 Apr 2011 21:30:01 +0000 Subject: sctp: handle ootb packet in chunk order as defined Changed the order of processing SHUTDOWN ACK and COOKIE ACK refer to section 8.4:Handle "Out of the Blue" Packets. SHUTDOWN ACK chunk should be processed before processing "Stale Cookie" ERROR or a COOKIE ACK. Signed-off-by: Wei Yongjun Signed-off-by: Shan Wei Signed-off-by: Vlad Yasevich Signed-off-by: David S. Miller diff --git a/net/sctp/input.c b/net/sctp/input.c index 30cec77..3a8eb79 100644 --- a/net/sctp/input.c +++ b/net/sctp/input.c @@ -661,7 +661,6 @@ static int sctp_rcv_ootb(struct sk_buff *skb) { sctp_chunkhdr_t *ch; __u8 *ch_end; - sctp_errhdr_t *err; ch = (sctp_chunkhdr_t *) skb->data; @@ -697,20 +696,6 @@ static int sctp_rcv_ootb(struct sk_buff *skb) if (SCTP_CID_INIT == ch->type && (void *)ch != skb->data) goto discard; - /* RFC 8.4, 7) If the packet contains a "Stale cookie" ERROR - * or a COOKIE ACK the SCTP Packet should be silently - * discarded. - */ - if (SCTP_CID_COOKIE_ACK == ch->type) - goto discard; - - if (SCTP_CID_ERROR == ch->type) { - sctp_walk_errors(err, ch) { - if (SCTP_ERROR_STALE_COOKIE == err->cause) - goto discard; - } - } - ch = (sctp_chunkhdr_t *) ch_end; } while (ch_end < skb_tail_pointer(skb)); diff --git a/net/sctp/sm_statefuns.c b/net/sctp/sm_statefuns.c index 194d5ec..ad3b43b 100644 --- a/net/sctp/sm_statefuns.c +++ b/net/sctp/sm_statefuns.c @@ -3332,8 +3332,10 @@ sctp_disposition_t sctp_sf_ootb(const struct sctp_endpoint *ep, struct sctp_chunk *chunk = arg; struct sk_buff *skb = chunk->skb; sctp_chunkhdr_t *ch; + sctp_errhdr_t *err; __u8 *ch_end; int ootb_shut_ack = 0; + int ootb_cookie_ack = 0; SCTP_INC_STATS(SCTP_MIB_OUTOFBLUES); @@ -3358,6 +3360,23 @@ sctp_disposition_t sctp_sf_ootb(const struct sctp_endpoint *ep, if (SCTP_CID_ABORT == ch->type) return sctp_sf_pdiscard(ep, asoc, type, arg, commands); + /* RFC 8.4, 7) If the packet contains a "Stale cookie" ERROR + * or a COOKIE ACK the SCTP Packet should be silently + * discarded. + */ + + if (SCTP_CID_COOKIE_ACK == ch->type) + ootb_cookie_ack = 1; + + if (SCTP_CID_ERROR == ch->type) { + sctp_walk_errors(err, ch) { + if (SCTP_ERROR_STALE_COOKIE == err->cause) { + ootb_cookie_ack = 1; + break; + } + } + } + /* Report violation if chunk len overflows */ ch_end = ((__u8 *)ch) + WORD_ROUND(ntohs(ch->length)); if (ch_end > skb_tail_pointer(skb)) @@ -3369,6 +3388,8 @@ sctp_disposition_t sctp_sf_ootb(const struct sctp_endpoint *ep, if (ootb_shut_ack) return sctp_sf_shut_8_4_5(ep, asoc, type, arg, commands); + else if (ootb_cookie_ack) + return sctp_sf_pdiscard(ep, asoc, type, arg, commands); else return sctp_sf_tabort_8_4_8(ep, asoc, type, arg, commands); } -- cgit v0.10.2 From de6becdc0844ff92b38ffd9f0c4db1d3de02835f Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Tue, 19 Apr 2011 21:30:51 +0000 Subject: sctp: fix to check the source address of COOKIE-ECHO chunk SCTP does not check whether the source address of COOKIE-ECHO chunk is the original address of INIT chunk or part of the any address parameters saved in COOKIE in CLOSED state. So even if the COOKIE-ECHO chunk is from any address but with correct COOKIE, the COOKIE-ECHO chunk still be accepted. If the COOKIE is not from a valid address, the assoc should not be established. Signed-off-by: Wei Yongjun Signed-off-by: Vlad Yasevich Signed-off-by: David S. Miller diff --git a/include/net/sctp/structs.h b/include/net/sctp/structs.h index 0f6e60a..5c9bada 100644 --- a/include/net/sctp/structs.h +++ b/include/net/sctp/structs.h @@ -1400,7 +1400,7 @@ int sctp_has_association(const union sctp_addr *laddr, int sctp_verify_init(const struct sctp_association *asoc, sctp_cid_t, sctp_init_chunk_t *peer_init, struct sctp_chunk *chunk, struct sctp_chunk **err_chunk); -int sctp_process_init(struct sctp_association *, sctp_cid_t cid, +int sctp_process_init(struct sctp_association *, struct sctp_chunk *chunk, const union sctp_addr *peer, sctp_init_chunk_t *init, gfp_t gfp); __u32 sctp_generate_tag(const struct sctp_endpoint *); diff --git a/net/sctp/sm_make_chunk.c b/net/sctp/sm_make_chunk.c index f87ccb1..a7b65e9 100644 --- a/net/sctp/sm_make_chunk.c +++ b/net/sctp/sm_make_chunk.c @@ -2242,14 +2242,17 @@ int sctp_verify_init(const struct sctp_association *asoc, * Returns 0 on failure, else success. * FIXME: This is an association method. */ -int sctp_process_init(struct sctp_association *asoc, sctp_cid_t cid, +int sctp_process_init(struct sctp_association *asoc, struct sctp_chunk *chunk, const union sctp_addr *peer_addr, sctp_init_chunk_t *peer_init, gfp_t gfp) { union sctp_params param; struct sctp_transport *transport; struct list_head *pos, *temp; + struct sctp_af *af; + union sctp_addr addr; char *cookie; + int src_match = 0; /* We must include the address that the INIT packet came from. * This is the only address that matters for an INIT packet. @@ -2261,18 +2264,31 @@ int sctp_process_init(struct sctp_association *asoc, sctp_cid_t cid, * added as the primary transport. The source address seems to * be a a better choice than any of the embedded addresses. */ - if (peer_addr) { - if(!sctp_assoc_add_peer(asoc, peer_addr, gfp, SCTP_ACTIVE)) - goto nomem; - } + if(!sctp_assoc_add_peer(asoc, peer_addr, gfp, SCTP_ACTIVE)) + goto nomem; + + if (sctp_cmp_addr_exact(sctp_source(chunk), peer_addr)) + src_match = 1; /* Process the initialization parameters. */ sctp_walk_params(param, peer_init, init_hdr.params) { + if (!src_match && (param.p->type == SCTP_PARAM_IPV4_ADDRESS || + param.p->type == SCTP_PARAM_IPV6_ADDRESS)) { + af = sctp_get_af_specific(param_type2af(param.p->type)); + af->from_addr_param(&addr, param.addr, + chunk->sctp_hdr->source, 0); + if (sctp_cmp_addr_exact(sctp_source(chunk), &addr)) + src_match = 1; + } if (!sctp_process_param(asoc, param, peer_addr, gfp)) goto clean_up; } + /* source address of chunk may not match any valid address */ + if (!src_match) + goto clean_up; + /* AUTH: After processing the parameters, make sure that we * have all the required info to potentially do authentications. */ diff --git a/net/sctp/sm_sideeffect.c b/net/sctp/sm_sideeffect.c index 3b80fe2..d612ca1 100644 --- a/net/sctp/sm_sideeffect.c +++ b/net/sctp/sm_sideeffect.c @@ -595,8 +595,7 @@ static int sctp_cmd_process_init(sctp_cmd_seq_t *commands, * fail during INIT processing (due to malloc problems), * just return the error and stop processing the stack. */ - if (!sctp_process_init(asoc, chunk->chunk_hdr->type, - sctp_source(chunk), peer_init, gfp)) + if (!sctp_process_init(asoc, chunk, sctp_source(chunk), peer_init, gfp)) error = -ENOMEM; else error = 0; diff --git a/net/sctp/sm_statefuns.c b/net/sctp/sm_statefuns.c index ad3b43b..ab94932 100644 --- a/net/sctp/sm_statefuns.c +++ b/net/sctp/sm_statefuns.c @@ -393,8 +393,7 @@ sctp_disposition_t sctp_sf_do_5_1B_init(const struct sctp_endpoint *ep, goto nomem_init; /* The call, sctp_process_init(), can fail on memory allocation. */ - if (!sctp_process_init(new_asoc, chunk->chunk_hdr->type, - sctp_source(chunk), + if (!sctp_process_init(new_asoc, chunk, sctp_source(chunk), (sctp_init_chunk_t *)chunk->chunk_hdr, GFP_ATOMIC)) goto nomem_init; @@ -725,7 +724,7 @@ sctp_disposition_t sctp_sf_do_5_1D_ce(const struct sctp_endpoint *ep, */ peer_init = &chunk->subh.cookie_hdr->c.peer_init[0]; - if (!sctp_process_init(new_asoc, chunk->chunk_hdr->type, + if (!sctp_process_init(new_asoc, chunk, &chunk->subh.cookie_hdr->c.peer_addr, peer_init, GFP_ATOMIC)) goto nomem_init; @@ -1464,8 +1463,7 @@ static sctp_disposition_t sctp_sf_do_unexpected_init( * Verification Tag and Peers Verification tag into a reserved * place (local tie-tag and per tie-tag) within the state cookie. */ - if (!sctp_process_init(new_asoc, chunk->chunk_hdr->type, - sctp_source(chunk), + if (!sctp_process_init(new_asoc, chunk, sctp_source(chunk), (sctp_init_chunk_t *)chunk->chunk_hdr, GFP_ATOMIC)) goto nomem; @@ -1694,8 +1692,7 @@ static sctp_disposition_t sctp_sf_do_dupcook_a(const struct sctp_endpoint *ep, */ peer_init = &chunk->subh.cookie_hdr->c.peer_init[0]; - if (!sctp_process_init(new_asoc, chunk->chunk_hdr->type, - sctp_source(chunk), peer_init, + if (!sctp_process_init(new_asoc, chunk, sctp_source(chunk), peer_init, GFP_ATOMIC)) goto nomem; @@ -1780,8 +1777,7 @@ static sctp_disposition_t sctp_sf_do_dupcook_b(const struct sctp_endpoint *ep, * side effects--it is safe to run them here. */ peer_init = &chunk->subh.cookie_hdr->c.peer_init[0]; - if (!sctp_process_init(new_asoc, chunk->chunk_hdr->type, - sctp_source(chunk), peer_init, + if (!sctp_process_init(new_asoc, chunk, sctp_source(chunk), peer_init, GFP_ATOMIC)) goto nomem; -- cgit v0.10.2 From 92c73af58e9f1b487322ce25a7a67889c9d91343 Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Tue, 19 Apr 2011 21:31:47 +0000 Subject: sctp: make heartbeat information in sctp_make_heartbeat() Make heartbeat information in sctp_make_heartbeat() instead of make it in sctp_sf_heartbeat() directly for common using. Signed-off-by: Wei Yongjun Signed-off-by: Vlad Yasevich Signed-off-by: David S. Miller diff --git a/include/net/sctp/sm.h b/include/net/sctp/sm.h index 9352d12..652f09b 100644 --- a/include/net/sctp/sm.h +++ b/include/net/sctp/sm.h @@ -232,9 +232,7 @@ struct sctp_chunk *sctp_make_violation_paramlen(const struct sctp_association *, const struct sctp_chunk *, struct sctp_paramhdr *); struct sctp_chunk *sctp_make_heartbeat(const struct sctp_association *, - const struct sctp_transport *, - const void *payload, - const size_t paylen); + const struct sctp_transport *); struct sctp_chunk *sctp_make_heartbeat_ack(const struct sctp_association *, const struct sctp_chunk *, const void *payload, diff --git a/net/sctp/sm_make_chunk.c b/net/sctp/sm_make_chunk.c index a7b65e9..58eb27f 100644 --- a/net/sctp/sm_make_chunk.c +++ b/net/sctp/sm_make_chunk.c @@ -1075,20 +1075,28 @@ nodata: /* Make a HEARTBEAT chunk. */ struct sctp_chunk *sctp_make_heartbeat(const struct sctp_association *asoc, - const struct sctp_transport *transport, - const void *payload, const size_t paylen) + const struct sctp_transport *transport) { - struct sctp_chunk *retval = sctp_make_chunk(asoc, SCTP_CID_HEARTBEAT, - 0, paylen); + struct sctp_chunk *retval; + sctp_sender_hb_info_t hbinfo; + + retval = sctp_make_chunk(asoc, SCTP_CID_HEARTBEAT, 0, sizeof(hbinfo)); if (!retval) goto nodata; + hbinfo.param_hdr.type = SCTP_PARAM_HEARTBEAT_INFO; + hbinfo.param_hdr.length = htons(sizeof(sctp_sender_hb_info_t)); + hbinfo.daddr = transport->ipaddr; + hbinfo.sent_at = jiffies; + hbinfo.hb_nonce = transport->hb_nonce; + /* Cast away the 'const', as this is just telling the chunk * what transport it belongs to. */ retval->transport = (struct sctp_transport *) transport; - retval->subh.hbs_hdr = sctp_addto_chunk(retval, paylen, payload); + retval->subh.hbs_hdr = sctp_addto_chunk(retval, sizeof(hbinfo), + &hbinfo); nodata: return retval; diff --git a/net/sctp/sm_statefuns.c b/net/sctp/sm_statefuns.c index ab94932..736847e4 100644 --- a/net/sctp/sm_statefuns.c +++ b/net/sctp/sm_statefuns.c @@ -941,18 +941,9 @@ static sctp_disposition_t sctp_sf_heartbeat(const struct sctp_endpoint *ep, { struct sctp_transport *transport = (struct sctp_transport *) arg; struct sctp_chunk *reply; - sctp_sender_hb_info_t hbinfo; - size_t paylen = 0; - - hbinfo.param_hdr.type = SCTP_PARAM_HEARTBEAT_INFO; - hbinfo.param_hdr.length = htons(sizeof(sctp_sender_hb_info_t)); - hbinfo.daddr = transport->ipaddr; - hbinfo.sent_at = jiffies; - hbinfo.hb_nonce = transport->hb_nonce; /* Send a heartbeat to our peer. */ - paylen = sizeof(sctp_sender_hb_info_t); - reply = sctp_make_heartbeat(asoc, transport, &hbinfo, paylen); + reply = sctp_make_heartbeat(asoc, transport); if (!reply) return SCTP_DISPOSITION_NOMEM; -- cgit v0.10.2 From 4c6a6f42131dd750dcfe3c71e63bfc046e5a227e Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Tue, 19 Apr 2011 21:32:28 +0000 Subject: sctp: move chunk from retransmit queue to abandoned list If there is still data waiting to retransmit and remain in retransmit queue, while doing the next retransmit, if the chunk is abandoned, we should move it to abandoned list. Signed-off-by: Wei Yongjun Signed-off-by: Vlad Yasevich Signed-off-by: David S. Miller diff --git a/net/sctp/outqueue.c b/net/sctp/outqueue.c index 3e9d8d2..1c88c89 100644 --- a/net/sctp/outqueue.c +++ b/net/sctp/outqueue.c @@ -577,6 +577,13 @@ static int sctp_outq_flush_rtx(struct sctp_outq *q, struct sctp_packet *pkt, * try to send as much as possible. */ list_for_each_entry_safe(chunk, chunk1, lqueue, transmitted_list) { + /* If the chunk is abandoned, move it to abandoned list. */ + if (sctp_chunk_abandoned(chunk)) { + list_del_init(&chunk->transmitted_list); + sctp_insert_list(&q->abandoned, + &chunk->transmitted_list); + continue; + } /* Make sure that Gap Acked TSNs are not retransmitted. A * simple approach is just to move such TSNs out of the -- cgit v0.10.2 From 9cbdb702092a2d82f909312f4ec3eeded77bb82e Mon Sep 17 00:00:00 2001 From: David Ahern Date: Wed, 6 Apr 2011 21:54:20 -0600 Subject: perf script: improve validation of sample attributes for output fields Check for required sample attributes using evsel rather than sample_type in the session header. If the attribute for a default field is not present for the event type (e.g., new command operating on file from older kernel) the field is removed from the output list. Expected event types must exist. For example, if a user specifies -f trace:time,trace -f sw:time,cpu,sym the perf.data file must contain both tracepoints and software events (ie., it is an error if either does not exist in the file). Attribute checking is done once at the beginning of perf-script rather than for each sample. v1 -> v2: - addressed comments from acme Cc: Frederic Weisbecker Cc: Ingo Molnar Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/1302148460-570-1-git-send-email-daahern@cisco.com Signed-off-by: David Ahern Signed-off-by: Arnaldo Carvalho de Melo diff --git a/tools/perf/builtin-script.c b/tools/perf/builtin-script.c index b3012c4..974f6d3 100644 --- a/tools/perf/builtin-script.c +++ b/tools/perf/builtin-script.c @@ -51,6 +51,7 @@ struct output_option { /* default set to maintain compatibility with current format */ static struct { bool user_set; + bool wildcard_set; u64 fields; u64 invalid_fields; } output[PERF_TYPE_MAX] = { @@ -104,41 +105,113 @@ static bool output_set_by_user(void) return false; } +static const char *output_field2str(enum perf_output_field field) +{ + int i, imax = ARRAY_SIZE(all_output_options); + const char *str = ""; + + for (i = 0; i < imax; ++i) { + if (all_output_options[i].field == field) { + str = all_output_options[i].str; + break; + } + } + return str; +} + #define PRINT_FIELD(x) (output[attr->type].fields & PERF_OUTPUT_##x) -static int perf_session__check_attr(struct perf_session *session, - struct perf_event_attr *attr) +static int perf_event_attr__check_stype(struct perf_event_attr *attr, + u64 sample_type, const char *sample_msg, + enum perf_output_field field) { + int type = attr->type; + const char *evname; + + if (attr->sample_type & sample_type) + return 0; + + if (output[type].user_set) { + evname = __event_name(attr->type, attr->config); + pr_err("Samples for '%s' event do not have %s attribute set. " + "Cannot print '%s' field.\n", + evname, sample_msg, output_field2str(field)); + return -1; + } + + /* user did not ask for it explicitly so remove from the default list */ + output[type].fields &= ~field; + evname = __event_name(attr->type, attr->config); + pr_debug("Samples for '%s' event do not have %s attribute set. " + "Skipping '%s' field.\n", + evname, sample_msg, output_field2str(field)); + + return 0; +} + +static int perf_evsel__check_attr(struct perf_evsel *evsel, + struct perf_session *session) +{ + struct perf_event_attr *attr = &evsel->attr; + if (PRINT_FIELD(TRACE) && !perf_session__has_traces(session, "record -R")) return -EINVAL; if (PRINT_FIELD(SYM)) { - if (!(session->sample_type & PERF_SAMPLE_IP)) { - pr_err("Samples do not contain IP data.\n"); + if (perf_event_attr__check_stype(attr, PERF_SAMPLE_IP, "IP", + PERF_OUTPUT_SYM)) return -EINVAL; - } + if (!no_callchain && - !(session->sample_type & PERF_SAMPLE_CALLCHAIN)) + !(attr->sample_type & PERF_SAMPLE_CALLCHAIN)) symbol_conf.use_callchain = false; } if ((PRINT_FIELD(PID) || PRINT_FIELD(TID)) && - !(session->sample_type & PERF_SAMPLE_TID)) { - pr_err("Samples do not contain TID/PID data.\n"); + perf_event_attr__check_stype(attr, PERF_SAMPLE_TID, "TID", + PERF_OUTPUT_TID|PERF_OUTPUT_PID)) return -EINVAL; - } if (PRINT_FIELD(TIME) && - !(session->sample_type & PERF_SAMPLE_TIME)) { - pr_err("Samples do not contain timestamps.\n"); + perf_event_attr__check_stype(attr, PERF_SAMPLE_TIME, "TIME", + PERF_OUTPUT_TIME)) return -EINVAL; - } if (PRINT_FIELD(CPU) && - !(session->sample_type & PERF_SAMPLE_CPU)) { - pr_err("Samples do not contain cpu.\n"); + perf_event_attr__check_stype(attr, PERF_SAMPLE_CPU, "CPU", + PERF_OUTPUT_CPU)) return -EINVAL; + + return 0; +} + +/* + * verify all user requested events exist and the samples + * have the expected data + */ +static int perf_session__check_output_opt(struct perf_session *session) +{ + int j; + struct perf_evsel *evsel; + + for (j = 0; j < PERF_TYPE_MAX; ++j) { + evsel = perf_session__find_first_evtype(session, j); + + /* + * even if fields is set to 0 (ie., show nothing) event must + * exist if user explicitly includes it on the command line + */ + if (!evsel && output[j].user_set && !output[j].wildcard_set) { + pr_err("%s events do not exist. " + "Remove corresponding -f option to proceed.\n", + event_type(j)); + return -1; + } + + if (evsel && output[j].fields && + perf_evsel__check_attr(evsel, session)) + return -1; } return 0; @@ -210,9 +283,6 @@ static void process_event(union perf_event *event __unused, if (output[attr->type].fields == 0) return; - if (perf_session__check_attr(session, attr) < 0) - return; - print_sample_start(sample, thread, attr); if (PRINT_FIELD(TRACE)) @@ -525,6 +595,7 @@ static int parse_output_fields(const struct option *opt __used, output[type].fields = 0; output[type].user_set = true; + output[type].wildcard_set = false; } else { tok = str; @@ -541,6 +612,7 @@ static int parse_output_fields(const struct option *opt __used, for (j = 0; j < PERF_TYPE_MAX; ++j) { output[j].fields = 0; output[j].user_set = true; + output[j].wildcard_set = true; } } @@ -1145,6 +1217,11 @@ int cmd_script(int argc, const char **argv, const char *prefix __used) pr_debug("perf script started with script %s\n\n", script_name); } + + err = perf_session__check_output_opt(session); + if (err < 0) + goto out; + err = __cmd_script(session); perf_session__delete(session); diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c index caa2245..fff6674 100644 --- a/tools/perf/util/session.c +++ b/tools/perf/util/session.c @@ -1156,6 +1156,18 @@ size_t perf_session__fprintf_nr_events(struct perf_session *session, FILE *fp) return ret; } +struct perf_evsel *perf_session__find_first_evtype(struct perf_session *session, + unsigned int type) +{ + struct perf_evsel *pos; + + list_for_each_entry(pos, &session->evlist->entries, node) { + if (pos->attr.type == type) + return pos; + } + return NULL; +} + void perf_session__print_symbols(union perf_event *event, struct perf_sample *sample, struct perf_session *session) diff --git a/tools/perf/util/session.h b/tools/perf/util/session.h index 1ac481f..8daaa2d 100644 --- a/tools/perf/util/session.h +++ b/tools/perf/util/session.h @@ -162,6 +162,9 @@ static inline int perf_session__parse_sample(struct perf_session *session, session->sample_id_all, sample); } +struct perf_evsel *perf_session__find_first_evtype(struct perf_session *session, + unsigned int type); + void perf_session__print_symbols(union perf_event *event, struct perf_sample *sample, struct perf_session *session); -- cgit v0.10.2 From 24bdb0b62cc82120924762ae6bc85afc8c3f2b26 Mon Sep 17 00:00:00 2001 From: Stefano Stabellini Date: Tue, 12 Apr 2011 12:19:52 +0100 Subject: xen: do not create the extra e820 region at an addr lower than 4G Do not add the extra e820 region at a physical address lower than 4G because it breaks e820_end_of_low_ram_pfn(). It is OK for us to move the xen_extra_mem_start up and down because this is the index of the memory that can be ballooned in/out - it is memory not available to the kernel during bootup. Signed-off-by: Stefano Stabellini Signed-off-by: Konrad Rzeszutek Wilk diff --git a/arch/x86/xen/setup.c b/arch/x86/xen/setup.c index fa0269a..90bac0a 100644 --- a/arch/x86/xen/setup.c +++ b/arch/x86/xen/setup.c @@ -227,7 +227,7 @@ char * __init xen_memory_setup(void) memcpy(map_raw, map, sizeof(map)); e820.nr_map = 0; - xen_extra_mem_start = mem_end; + xen_extra_mem_start = max((1ULL << 32), mem_end); for (i = 0; i < memmap.nr_entries; i++) { unsigned long long end; -- cgit v0.10.2 From ee176455e28469e2420032aab3db11ac2ae3eaa8 Mon Sep 17 00:00:00 2001 From: Stefano Stabellini Date: Tue, 19 Apr 2011 14:47:31 +0100 Subject: xen: mask_rw_pte: do not apply the early_ioremap checks on x86_32 The two "is_early_ioremap_ptep" checks in mask_rw_pte are only used on x86_64, in fact early_ioremap is not used at all to setup the initial pagetable on x86_32. Moreover on x86_32 the two checks are wrong because the range pgt_buf_start..pgt_buf_end initially should be mapped RW because the pages in the range are not pagetable pages yet and haven't been cleared yet. Afterwards considering the pgt_buf_start..pgt_buf_end is part of the initial mapping, xen_alloc_pte is capable of turning the ptes RO when they become pagetable pages. Fix the issue and improve the readability of the code providing two different implementation of mask_rw_pte for x86_32 and x86_64. Signed-off-by: Stefano Stabellini Signed-off-by: Konrad Rzeszutek Wilk diff --git a/arch/x86/xen/mmu.c b/arch/x86/xen/mmu.c index a991b57..aef7af9 100644 --- a/arch/x86/xen/mmu.c +++ b/arch/x86/xen/mmu.c @@ -1473,16 +1473,20 @@ static void xen_pgd_free(struct mm_struct *mm, pgd_t *pgd) #endif } +#ifdef CONFIG_X86_32 static __init pte_t mask_rw_pte(pte_t *ptep, pte_t pte) { - unsigned long pfn = pte_pfn(pte); - -#ifdef CONFIG_X86_32 /* If there's an existing pte, then don't allow _PAGE_RW to be set */ if (pte_val_ma(*ptep) & _PAGE_PRESENT) pte = __pte_ma(((pte_val_ma(*ptep) & _PAGE_RW) | ~_PAGE_RW) & pte_val_ma(pte)); -#endif + + return pte; +} +#else /* CONFIG_X86_64 */ +static __init pte_t mask_rw_pte(pte_t *ptep, pte_t pte) +{ + unsigned long pfn = pte_pfn(pte); /* * If the new pfn is within the range of the newly allocated @@ -1497,6 +1501,7 @@ static __init pte_t mask_rw_pte(pte_t *ptep, pte_t pte) return pte; } +#endif /* CONFIG_X86_64 */ /* Init-time set_pte while constructing initial pagetables, which doesn't allow RO pagetable pages to be remapped RW */ -- cgit v0.10.2 From 1574dff8996ab1ed92c09012f8038b5566fce313 Mon Sep 17 00:00:00 2001 From: Sachin Prabhu Date: Wed, 20 Apr 2011 13:09:35 +0100 Subject: Open with O_CREAT flag set fails to open existing files on non writable directories An open on a NFS4 share using the O_CREAT flag on an existing file for which we have permissions to open but contained in a directory with no write permissions will fail with EACCES. A tcpdump shows that the client had set the open mode to UNCHECKED which indicates that the file should be created if it doesn't exist and encountering an existing flag is not an error. Since in this case the file exists and can be opened by the user, the NFS server is wrong in attempting to check create permissions on the parent directory. The patch adds a conditional statement to check for create permissions only if the file doesn't exist. Signed-off-by: Sachin S. Prabhu Signed-off-by: J. Bruce Fields diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c index 2e1cebd..129f3c9 100644 --- a/fs/nfsd/vfs.c +++ b/fs/nfsd/vfs.c @@ -1363,7 +1363,7 @@ nfsd_create_v3(struct svc_rqst *rqstp, struct svc_fh *fhp, goto out; if (!(iap->ia_valid & ATTR_MODE)) iap->ia_mode = 0; - err = fh_verify(rqstp, fhp, S_IFDIR, NFSD_MAY_CREATE); + err = fh_verify(rqstp, fhp, S_IFDIR, NFSD_MAY_EXEC); if (err) goto out; @@ -1385,6 +1385,13 @@ nfsd_create_v3(struct svc_rqst *rqstp, struct svc_fh *fhp, if (IS_ERR(dchild)) goto out_nfserr; + /* If file doesn't exist, check for permissions to create one */ + if (!dchild->d_inode) { + err = fh_verify(rqstp, fhp, S_IFDIR, NFSD_MAY_CREATE); + if (err) + goto out; + } + err = fh_compose(resfhp, fhp->fh_export, dchild, fhp); if (err) goto out; -- cgit v0.10.2 From 8c230d9a5b5ec7970139acb7e2d165d7a3fe9f9e Mon Sep 17 00:00:00 2001 From: Artem Bityutskiy Date: Wed, 20 Apr 2011 18:02:45 +0300 Subject: UBIFS: fix false space checking failure This patch fixes UBIFS mount failure when the debugging support is enabled, we are recovering from a power cut, we were first mounter R/O and we are re-mounting R/W. In this case we should not assume that the amount of free space before we have re-mounted R/W and after are equivalent, because when we have mounted R/O the file-system is in a non-committed state so the amount of free space is slightly smaller, due to the fact that we cannot predict the amount of free space precisely before we commit. This patch fixes the issue by skipping the debugging check in case of recovery. This issue was reported by Caizhiyong here: http://thread.gmane.org/gmane.linux.drivers.mtd/34350/focus=34387 Signed-off-by: Artem Bityutskiy Reported-by: Caizhiyong Cc: stable@kernel.org [2.6.30+] diff --git a/fs/ubifs/super.c b/fs/ubifs/super.c index c75f613..ec33b06 100644 --- a/fs/ubifs/super.c +++ b/fs/ubifs/super.c @@ -1671,14 +1671,25 @@ static int ubifs_remount_rw(struct ubifs_info *c) if (err) goto out; + dbg_gen("re-mounted read-write"); + c->remounting_rw = 0; + if (c->need_recovery) { c->need_recovery = 0; ubifs_msg("deferred recovery completed"); + } else { + /* + * Do not run the debugging space check if the were doing + * recovery, because when we saved the information we had the + * file-system in a state where the TNC and lprops has been + * modified in memory, but all the I/O operations (including a + * commit) were deferred. So the file-system was in + * "non-committed" state. Now the file-system is in committed + * state, and of course the amount of free space will change + * because, for example, the old index size was imprecise. + */ + err = dbg_check_space_info(c); } - - dbg_gen("re-mounted read-write"); - c->remounting_rw = 0; - err = dbg_check_space_info(c); mutex_unlock(&c->umount_mutex); return err; -- cgit v0.10.2 From 8a91707d0a1a49193e23cb2d243632f2289feb24 Mon Sep 17 00:00:00 2001 From: Konrad Rzeszutek Wilk Date: Wed, 20 Apr 2011 11:54:10 -0400 Subject: xen/p2m: Add EXPORT_SYMBOL_GPL to the M2P override functions. If the backends, which use these two functions, are compiled as a module we need these two functions to be exported. Signed-off-by: Konrad Rzeszutek Wilk diff --git a/arch/x86/xen/p2m.c b/arch/x86/xen/p2m.c index 2d2b32a..c851397 100644 --- a/arch/x86/xen/p2m.c +++ b/arch/x86/xen/p2m.c @@ -682,7 +682,7 @@ int m2p_add_override(unsigned long mfn, struct page *page, bool clear_pte) return 0; } - +EXPORT_SYMBOL_GPL(m2p_add_override); int m2p_remove_override(struct page *page, bool clear_pte) { unsigned long flags; @@ -719,6 +719,7 @@ int m2p_remove_override(struct page *page, bool clear_pte) return 0; } +EXPORT_SYMBOL_GPL(m2p_remove_override); struct page *m2p_find_override(unsigned long mfn) { -- cgit v0.10.2 From 3eff1268994f72266b660782e87f215720c29639 Mon Sep 17 00:00:00 2001 From: Dave Chinner Date: Tue, 12 Apr 2011 13:34:20 +0000 Subject: xfs: fix duplicate message output Commit 957935dc ("xfs: fix xfs_debug warnings" broke the logic in __xfs_printk(). Instead of only printing one of two possible output strings based on whether the fs has a name or not, it outputs both. Fix it to only output one message again. Signed-off-by: Dave Chinner Reviewed-by: Christoph Hellwig Signed-off-by: Alex Elder diff --git a/fs/xfs/linux-2.6/xfs_message.c b/fs/xfs/linux-2.6/xfs_message.c index 3ca7956..9f76cce 100644 --- a/fs/xfs/linux-2.6/xfs_message.c +++ b/fs/xfs/linux-2.6/xfs_message.c @@ -34,8 +34,10 @@ __xfs_printk( const struct xfs_mount *mp, struct va_format *vaf) { - if (mp && mp->m_fsname) + if (mp && mp->m_fsname) { printk("%sXFS (%s): %pV\n", level, mp->m_fsname, vaf); + return; + } printk("%sXFS: %pV\n", level, vaf); } -- cgit v0.10.2 From cf568c58eb192368f5e796df935704535b54f451 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Wed, 30 Mar 2011 14:31:42 +0200 Subject: mach-ux500: fix i2c0 device setup regression Adding two sets of I2C devices to the same bus doesn't quite work, atleast not anymore. Stash one array and determine how much of it shall be added instead. Signed-off-by: Linus Walleij diff --git a/arch/arm/mach-ux500/board-mop500.c b/arch/arm/mach-ux500/board-mop500.c index af91374..6e1907fa 100644 --- a/arch/arm/mach-ux500/board-mop500.c +++ b/arch/arm/mach-ux500/board-mop500.c @@ -178,16 +178,15 @@ static struct i2c_board_info __initdata mop500_i2c0_devices[] = { .irq = NOMADIK_GPIO_TO_IRQ(217), .platform_data = &mop500_tc35892_data, }, -}; - -/* I2C0 devices only available prior to HREFv60 */ -static struct i2c_board_info __initdata mop500_i2c0_old_devices[] = { + /* I2C0 devices only available prior to HREFv60 */ { I2C_BOARD_INFO("tps61052", 0x33), .platform_data = &mop500_tps61052_data, }, }; +#define NUM_PRE_V60_I2C0_DEVICES 1 + static struct i2c_board_info __initdata mop500_i2c2_devices[] = { { /* lp5521 LED driver, 1st device */ @@ -425,6 +424,8 @@ static void __init mop500_uart_init(void) static void __init mop500_init_machine(void) { + int i2c0_devs; + /* * The HREFv60 board removed a GPIO expander and routed * all these GPIO pins to the internal GPIO controller @@ -448,11 +449,11 @@ static void __init mop500_init_machine(void) platform_device_register(&ab8500_device); - i2c_register_board_info(0, mop500_i2c0_devices, - ARRAY_SIZE(mop500_i2c0_devices)); - if (!machine_is_hrefv60()) - i2c_register_board_info(0, mop500_i2c0_old_devices, - ARRAY_SIZE(mop500_i2c0_old_devices)); + i2c0_devs = ARRAY_SIZE(mop500_i2c0_devices); + if (machine_is_hrefv60()) + i2c0_devs -= NUM_PRE_V60_I2C0_DEVICES; + + i2c_register_board_info(0, mop500_i2c0_devices, i2c0_devs); i2c_register_board_info(2, mop500_i2c2_devices, ARRAY_SIZE(mop500_i2c2_devices)); } -- cgit v0.10.2 From 9cf3b5fa6f7b246784d62a2a7637a871290c9ab9 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Sun, 17 Apr 2011 20:32:19 +0200 Subject: rtc: fix coh901331 startup crash The rtc_device_register() call has changed semantics so that it will immediately call out to rtc_read_alarm() and since the callbacks require the drvdata to be set, we need to set it before the registration call to avoid NULL dereference. Signed-off-by: Linus Walleij diff --git a/drivers/rtc/rtc-coh901331.c b/drivers/rtc/rtc-coh901331.c index 316f484..80f9c88 100644 --- a/drivers/rtc/rtc-coh901331.c +++ b/drivers/rtc/rtc-coh901331.c @@ -220,6 +220,7 @@ static int __init coh901331_probe(struct platform_device *pdev) } clk_disable(rtap->clk); + platform_set_drvdata(pdev, rtap); rtap->rtc = rtc_device_register("coh901331", &pdev->dev, &coh901331_ops, THIS_MODULE); if (IS_ERR(rtap->rtc)) { @@ -227,11 +228,10 @@ static int __init coh901331_probe(struct platform_device *pdev) goto out_no_rtc; } - platform_set_drvdata(pdev, rtap); - return 0; out_no_rtc: + platform_set_drvdata(pdev, NULL); out_no_clk_enable: clk_put(rtap->clk); out_no_clk: -- cgit v0.10.2 From 2df122f52fd31c327e0aa05caf6017ecd7867d5f Mon Sep 17 00:00:00 2001 From: Tomi Valkeinen Date: Mon, 4 Apr 2011 09:26:19 +0300 Subject: OMAP4: clock data: Change DSS clock aliases MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit DSS driver has used fck and ick clocks on OMAP2/3 to get DSS HW up and running, and also to get the pixel clock's source clock rate from the fck. On OMAP4 the clock data is set up in a different way, as there's no ick, dss_fck points to a fake clock which just affects DSS's MODULEMODE, and dss_dss_clk if the DSS_FCK. >From DSS driver's point of view the dss_fck sounds like an ick, and dss_dss_clk is the fck. While this is not entirely correct from HW point of view, especially for the ick, configuring the clock aliases that way makes DSS "just work" with OMAP4's clock setup. In the (hopefully near) future DSS driver will be reworked to use pm_runtime support which should clean up the clock code. Signed-off-by: Tomi Valkeinen Cc: Benoît Cousson Signed-off-by: Paul Walmsley diff --git a/arch/arm/mach-omap2/clock44xx_data.c b/arch/arm/mach-omap2/clock44xx_data.c index 276992d..8c96567 100644 --- a/arch/arm/mach-omap2/clock44xx_data.c +++ b/arch/arm/mach-omap2/clock44xx_data.c @@ -3116,14 +3116,9 @@ static struct omap_clk omap44xx_clks[] = { CLK(NULL, "dsp_fck", &dsp_fck, CK_443X), CLK("omapdss_dss", "sys_clk", &dss_sys_clk, CK_443X), CLK("omapdss_dss", "tv_clk", &dss_tv_clk, CK_443X), - CLK("omapdss_dss", "dss_clk", &dss_dss_clk, CK_443X), CLK("omapdss_dss", "video_clk", &dss_48mhz_clk, CK_443X), - CLK("omapdss_dss", "fck", &dss_fck, CK_443X), - /* - * On OMAP4, DSS ick is a dummy clock; this is needed for compatibility - * with OMAP2/3. - */ - CLK("omapdss_dss", "ick", &dummy_ck, CK_443X), + CLK("omapdss_dss", "fck", &dss_dss_clk, CK_443X), + CLK("omapdss_dss", "ick", &dss_fck, CK_443X), CLK(NULL, "efuse_ctrl_cust_fck", &efuse_ctrl_cust_fck, CK_443X), CLK(NULL, "emif1_fck", &emif1_fck, CK_443X), CLK(NULL, "emif2_fck", &emif2_fck, CK_443X), -- cgit v0.10.2 From 8bc2e98bcb280009cb0f85ce64e5f79b1669f9ff Mon Sep 17 00:00:00 2001 From: Eduardo Valentin Date: Wed, 13 Apr 2011 18:21:06 +0300 Subject: OMAP2+: PM: Fix the saving of CM_AUTOIDLE_PLL register on scratchpad area The saving of CCR.CM_AUTOIDLE_PLL is done in scratchpad area. However, in current code, the saving is done for CM_AUTOIDLE2_PLL (offset 0x34) instead of CM_AUTOIDLE_PLL (offset 0x30). This patch changes the code to save the correct register. Signed-off-by: Eduardo Valentin Signed-off-by: Paul Walmsley diff --git a/arch/arm/mach-omap2/control.c b/arch/arm/mach-omap2/control.c index 6952794..df0c75c 100644 --- a/arch/arm/mach-omap2/control.c +++ b/arch/arm/mach-omap2/control.c @@ -317,7 +317,7 @@ void omap3_save_scratchpad_contents(void) prcm_block_contents.cm_clken_pll = omap2_cm_read_mod_reg(PLL_MOD, CM_CLKEN); prcm_block_contents.cm_autoidle_pll = - omap2_cm_read_mod_reg(PLL_MOD, OMAP3430_CM_AUTOIDLE_PLL); + omap2_cm_read_mod_reg(PLL_MOD, CM_AUTOIDLE); prcm_block_contents.cm_clksel1_pll = omap2_cm_read_mod_reg(PLL_MOD, OMAP3430_CM_CLKSEL1_PLL); prcm_block_contents.cm_clksel2_pll = -- cgit v0.10.2 From a8ae645c014bc01090367de84f7601ad11628971 Mon Sep 17 00:00:00 2001 From: Eduardo Valentin Date: Wed, 13 Apr 2011 18:21:07 +0300 Subject: OMAP3: PM: Do not rely on ROM code to restore CM_AUTOIDLE_PLL.AUTO_PERIPH_DPLL As per OMAP3 erratum (i671), ROM code adds extra latencies while restoring CM_AUTOIDLE_PLL register, if AUTO_PERIPH_DPLL is equal to 1. This patch stores 0's in scratchpad content area corresponding to AUTO_PERIPH_DPLL, to prevent ROM code to try to lock per DPLL, since it won't respect proper programing scheme. This register is then stored in prcm context. The saving and restore is now done by kernel side. Here follow the erratum description DESCRIPTION After OFF mode transition, among many restorations, the ROM Code restores the CM_AUTOIDLE_PLL register, and after that, it tries to relock the PER DPLL. In case the restoration data stored in scratchpad memory contains a field CM_AUTOIDLE_PLL.AUTO_PERIPH_DPLL = 1, then the way the ROM Code restores and locks the PER DPLL does not respect the PER DPLL programming scheme. In that case, the DPLL might not lock. Meanwhile, when trying to lock the PER DPLL, the ROM Code does not hang. Only extra latencies are introduced at wake-up. WORKAROUND When saving the context-restore structure in scratchpad memory, in order to respect the PER DPLL programming scheme, it is advised to store 0 in the CM_AUTOIDLE_PLL.AUTO_PERIPH_DPLL field of the saved structure. After wake-up, the application should store in CM_AUTOIDLE_PLL register the right desired value. Signed-off-by: Eduardo Valentin Signed-off-by: Paul Walmsley diff --git a/arch/arm/mach-omap2/cm2xxx_3xxx.c b/arch/arm/mach-omap2/cm2xxx_3xxx.c index 9d0dec8..38830d8 100644 --- a/arch/arm/mach-omap2/cm2xxx_3xxx.c +++ b/arch/arm/mach-omap2/cm2xxx_3xxx.c @@ -247,6 +247,7 @@ struct omap3_cm_regs { u32 per_cm_clksel; u32 emu_cm_clksel; u32 emu_cm_clkstctrl; + u32 pll_cm_autoidle; u32 pll_cm_autoidle2; u32 pll_cm_clksel4; u32 pll_cm_clksel5; @@ -319,6 +320,15 @@ void omap3_cm_save_context(void) omap2_cm_read_mod_reg(OMAP3430_EMU_MOD, CM_CLKSEL1); cm_context.emu_cm_clkstctrl = omap2_cm_read_mod_reg(OMAP3430_EMU_MOD, OMAP2_CM_CLKSTCTRL); + /* + * As per erratum i671, ROM code does not respect the PER DPLL + * programming scheme if CM_AUTOIDLE_PLL.AUTO_PERIPH_DPLL == 1. + * In this case, even though this register has been saved in + * scratchpad contents, we need to restore AUTO_PERIPH_DPLL + * by ourselves. So, we need to save it anyway. + */ + cm_context.pll_cm_autoidle = + omap2_cm_read_mod_reg(PLL_MOD, CM_AUTOIDLE); cm_context.pll_cm_autoidle2 = omap2_cm_read_mod_reg(PLL_MOD, CM_AUTOIDLE2); cm_context.pll_cm_clksel4 = @@ -441,6 +451,13 @@ void omap3_cm_restore_context(void) CM_CLKSEL1); omap2_cm_write_mod_reg(cm_context.emu_cm_clkstctrl, OMAP3430_EMU_MOD, OMAP2_CM_CLKSTCTRL); + /* + * As per erratum i671, ROM code does not respect the PER DPLL + * programming scheme if CM_AUTOIDLE_PLL.AUTO_PERIPH_DPLL == 1. + * In this case, we need to restore AUTO_PERIPH_DPLL by ourselves. + */ + omap2_cm_write_mod_reg(cm_context.pll_cm_autoidle, PLL_MOD, + CM_AUTOIDLE); omap2_cm_write_mod_reg(cm_context.pll_cm_autoidle2, PLL_MOD, CM_AUTOIDLE2); omap2_cm_write_mod_reg(cm_context.pll_cm_clksel4, PLL_MOD, diff --git a/arch/arm/mach-omap2/control.c b/arch/arm/mach-omap2/control.c index df0c75c..da53ba3 100644 --- a/arch/arm/mach-omap2/control.c +++ b/arch/arm/mach-omap2/control.c @@ -316,8 +316,14 @@ void omap3_save_scratchpad_contents(void) omap2_cm_read_mod_reg(WKUP_MOD, CM_CLKSEL); prcm_block_contents.cm_clken_pll = omap2_cm_read_mod_reg(PLL_MOD, CM_CLKEN); + /* + * As per erratum i671, ROM code does not respect the PER DPLL + * programming scheme if CM_AUTOIDLE_PLL..AUTO_PERIPH_DPLL == 1. + * Then, in anycase, clear these bits to avoid extra latencies. + */ prcm_block_contents.cm_autoidle_pll = - omap2_cm_read_mod_reg(PLL_MOD, CM_AUTOIDLE); + omap2_cm_read_mod_reg(PLL_MOD, CM_AUTOIDLE) & + ~OMAP3430_AUTO_PERIPH_DPLL_MASK; prcm_block_contents.cm_clksel1_pll = omap2_cm_read_mod_reg(PLL_MOD, OMAP3430_CM_CLKSEL1_PLL); prcm_block_contents.cm_clksel2_pll = -- cgit v0.10.2 From f95440ca5bdd3ed3e31c2fbad07b9056b31ad18c Mon Sep 17 00:00:00 2001 From: "Avinash.H.M" Date: Tue, 5 Apr 2011 21:10:15 +0530 Subject: OMAP2/3: hwmod: fix gpio-reset timeouts seen during bootup. GPIO module expects the debounce clocks to be enabled during reset. It doesn't reset properly and timeouts are seen, if this clock isn't enabled during reset. Add the HWMOD_CONTROL_OPT_CLKS_IN_RESET flags to the GPIO HWMODs, with which the debounce clocks are enabled during reset. Cc: Rajendra Nayak Cc: Paul Walmsley Cc: Benoit Cousson Cc: Kevin Hilman Signed-off-by: Avinash.H.M Signed-off-by: Paul Walmsley diff --git a/arch/arm/mach-omap2/omap_hwmod_2420_data.c b/arch/arm/mach-omap2/omap_hwmod_2420_data.c index f50e56a..c4d0ae87 100644 --- a/arch/arm/mach-omap2/omap_hwmod_2420_data.c +++ b/arch/arm/mach-omap2/omap_hwmod_2420_data.c @@ -1639,6 +1639,7 @@ static struct omap_hwmod_ocp_if *omap2420_gpio1_slaves[] = { static struct omap_hwmod omap2420_gpio1_hwmod = { .name = "gpio1", + .flags = HWMOD_CONTROL_OPT_CLKS_IN_RESET, .mpu_irqs = omap242x_gpio1_irqs, .mpu_irqs_cnt = ARRAY_SIZE(omap242x_gpio1_irqs), .main_clk = "gpios_fck", @@ -1669,6 +1670,7 @@ static struct omap_hwmod_ocp_if *omap2420_gpio2_slaves[] = { static struct omap_hwmod omap2420_gpio2_hwmod = { .name = "gpio2", + .flags = HWMOD_CONTROL_OPT_CLKS_IN_RESET, .mpu_irqs = omap242x_gpio2_irqs, .mpu_irqs_cnt = ARRAY_SIZE(omap242x_gpio2_irqs), .main_clk = "gpios_fck", @@ -1699,6 +1701,7 @@ static struct omap_hwmod_ocp_if *omap2420_gpio3_slaves[] = { static struct omap_hwmod omap2420_gpio3_hwmod = { .name = "gpio3", + .flags = HWMOD_CONTROL_OPT_CLKS_IN_RESET, .mpu_irqs = omap242x_gpio3_irqs, .mpu_irqs_cnt = ARRAY_SIZE(omap242x_gpio3_irqs), .main_clk = "gpios_fck", @@ -1729,6 +1732,7 @@ static struct omap_hwmod_ocp_if *omap2420_gpio4_slaves[] = { static struct omap_hwmod omap2420_gpio4_hwmod = { .name = "gpio4", + .flags = HWMOD_CONTROL_OPT_CLKS_IN_RESET, .mpu_irqs = omap242x_gpio4_irqs, .mpu_irqs_cnt = ARRAY_SIZE(omap242x_gpio4_irqs), .main_clk = "gpios_fck", diff --git a/arch/arm/mach-omap2/omap_hwmod_2430_data.c b/arch/arm/mach-omap2/omap_hwmod_2430_data.c index 96753f7..9682dd5 100644 --- a/arch/arm/mach-omap2/omap_hwmod_2430_data.c +++ b/arch/arm/mach-omap2/omap_hwmod_2430_data.c @@ -1742,6 +1742,7 @@ static struct omap_hwmod_ocp_if *omap2430_gpio1_slaves[] = { static struct omap_hwmod omap2430_gpio1_hwmod = { .name = "gpio1", + .flags = HWMOD_CONTROL_OPT_CLKS_IN_RESET, .mpu_irqs = omap243x_gpio1_irqs, .mpu_irqs_cnt = ARRAY_SIZE(omap243x_gpio1_irqs), .main_clk = "gpios_fck", @@ -1772,6 +1773,7 @@ static struct omap_hwmod_ocp_if *omap2430_gpio2_slaves[] = { static struct omap_hwmod omap2430_gpio2_hwmod = { .name = "gpio2", + .flags = HWMOD_CONTROL_OPT_CLKS_IN_RESET, .mpu_irqs = omap243x_gpio2_irqs, .mpu_irqs_cnt = ARRAY_SIZE(omap243x_gpio2_irqs), .main_clk = "gpios_fck", @@ -1802,6 +1804,7 @@ static struct omap_hwmod_ocp_if *omap2430_gpio3_slaves[] = { static struct omap_hwmod omap2430_gpio3_hwmod = { .name = "gpio3", + .flags = HWMOD_CONTROL_OPT_CLKS_IN_RESET, .mpu_irqs = omap243x_gpio3_irqs, .mpu_irqs_cnt = ARRAY_SIZE(omap243x_gpio3_irqs), .main_clk = "gpios_fck", @@ -1832,6 +1835,7 @@ static struct omap_hwmod_ocp_if *omap2430_gpio4_slaves[] = { static struct omap_hwmod omap2430_gpio4_hwmod = { .name = "gpio4", + .flags = HWMOD_CONTROL_OPT_CLKS_IN_RESET, .mpu_irqs = omap243x_gpio4_irqs, .mpu_irqs_cnt = ARRAY_SIZE(omap243x_gpio4_irqs), .main_clk = "gpios_fck", @@ -1862,6 +1866,7 @@ static struct omap_hwmod_ocp_if *omap2430_gpio5_slaves[] = { static struct omap_hwmod omap2430_gpio5_hwmod = { .name = "gpio5", + .flags = HWMOD_CONTROL_OPT_CLKS_IN_RESET, .mpu_irqs = omap243x_gpio5_irqs, .mpu_irqs_cnt = ARRAY_SIZE(omap243x_gpio5_irqs), .main_clk = "gpio5_fck", diff --git a/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c b/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c index 9bee155..909a84d 100644 --- a/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c +++ b/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c @@ -2141,6 +2141,7 @@ static struct omap_hwmod_ocp_if *omap3xxx_gpio1_slaves[] = { static struct omap_hwmod omap3xxx_gpio1_hwmod = { .name = "gpio1", + .flags = HWMOD_CONTROL_OPT_CLKS_IN_RESET, .mpu_irqs = omap3xxx_gpio1_irqs, .mpu_irqs_cnt = ARRAY_SIZE(omap3xxx_gpio1_irqs), .main_clk = "gpio1_ick", @@ -2177,6 +2178,7 @@ static struct omap_hwmod_ocp_if *omap3xxx_gpio2_slaves[] = { static struct omap_hwmod omap3xxx_gpio2_hwmod = { .name = "gpio2", + .flags = HWMOD_CONTROL_OPT_CLKS_IN_RESET, .mpu_irqs = omap3xxx_gpio2_irqs, .mpu_irqs_cnt = ARRAY_SIZE(omap3xxx_gpio2_irqs), .main_clk = "gpio2_ick", @@ -2213,6 +2215,7 @@ static struct omap_hwmod_ocp_if *omap3xxx_gpio3_slaves[] = { static struct omap_hwmod omap3xxx_gpio3_hwmod = { .name = "gpio3", + .flags = HWMOD_CONTROL_OPT_CLKS_IN_RESET, .mpu_irqs = omap3xxx_gpio3_irqs, .mpu_irqs_cnt = ARRAY_SIZE(omap3xxx_gpio3_irqs), .main_clk = "gpio3_ick", @@ -2249,6 +2252,7 @@ static struct omap_hwmod_ocp_if *omap3xxx_gpio4_slaves[] = { static struct omap_hwmod omap3xxx_gpio4_hwmod = { .name = "gpio4", + .flags = HWMOD_CONTROL_OPT_CLKS_IN_RESET, .mpu_irqs = omap3xxx_gpio4_irqs, .mpu_irqs_cnt = ARRAY_SIZE(omap3xxx_gpio4_irqs), .main_clk = "gpio4_ick", @@ -2285,6 +2289,7 @@ static struct omap_hwmod_ocp_if *omap3xxx_gpio5_slaves[] = { static struct omap_hwmod omap3xxx_gpio5_hwmod = { .name = "gpio5", + .flags = HWMOD_CONTROL_OPT_CLKS_IN_RESET, .mpu_irqs = omap3xxx_gpio5_irqs, .mpu_irqs_cnt = ARRAY_SIZE(omap3xxx_gpio5_irqs), .main_clk = "gpio5_ick", @@ -2321,6 +2326,7 @@ static struct omap_hwmod_ocp_if *omap3xxx_gpio6_slaves[] = { static struct omap_hwmod omap3xxx_gpio6_hwmod = { .name = "gpio6", + .flags = HWMOD_CONTROL_OPT_CLKS_IN_RESET, .mpu_irqs = omap3xxx_gpio6_irqs, .mpu_irqs_cnt = ARRAY_SIZE(omap3xxx_gpio6_irqs), .main_clk = "gpio6_ick", -- cgit v0.10.2 From 1c7276cfc04b1a5b296b691c2e07297a4f6c19aa Mon Sep 17 00:00:00 2001 From: Mike Waychison Date: Wed, 20 Apr 2011 12:04:36 -0700 Subject: ALSA: hda - Fix unused warnings when !SND_HDA_NEEDS_RESUME When SND_HDA_NEEDS_RESUME is not defined, the compiler identifies that the following symbols are static but not used: restore_shutup_pins hda_cleanup_all_streams Fix warnings by adding SND_HDA_NEEDS_RESUME guards. Signed-off-by: Mike Waychison Signed-off-by: Takashi Iwai diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index 2c79e96..d7d9446 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c @@ -937,6 +937,7 @@ void snd_hda_shutup_pins(struct hda_codec *codec) } EXPORT_SYMBOL_HDA(snd_hda_shutup_pins); +#ifdef SND_HDA_NEEDS_RESUME /* Restore the pin controls cleared previously via snd_hda_shutup_pins() */ static void restore_shutup_pins(struct hda_codec *codec) { @@ -953,6 +954,7 @@ static void restore_shutup_pins(struct hda_codec *codec) } codec->pins_shutup = 0; } +#endif static void init_hda_cache(struct hda_cache_rec *cache, unsigned int record_size); @@ -1329,6 +1331,7 @@ static void purify_inactive_streams(struct hda_codec *codec) } } +#ifdef SND_HDA_NEEDS_RESUME /* clean up all streams; called from suspend */ static void hda_cleanup_all_streams(struct hda_codec *codec) { @@ -1340,6 +1343,7 @@ static void hda_cleanup_all_streams(struct hda_codec *codec) really_cleanup_stream(codec, p); } } +#endif /* * amp access functions -- cgit v0.10.2 From 10022a6c66e199d8f61d9044543f38785713cbbd Mon Sep 17 00:00:00 2001 From: Oliver Hartkopp Date: Wed, 20 Apr 2011 01:57:15 +0000 Subject: can: add missing socket check in can/raw release v2: added space after 'if' according code style. We can get here with a NULL socket argument passed from userspace, so we need to handle it accordingly. Thanks to Dave Jones pointing at this issue in net/can/bcm.c Signed-off-by: Oliver Hartkopp Signed-off-by: David S. Miller diff --git a/net/can/raw.c b/net/can/raw.c index 649acfa..0eb39a7 100644 --- a/net/can/raw.c +++ b/net/can/raw.c @@ -305,7 +305,12 @@ static int raw_init(struct sock *sk) static int raw_release(struct socket *sock) { struct sock *sk = sock->sk; - struct raw_sock *ro = raw_sk(sk); + struct raw_sock *ro; + + if (!sk) + return 0; + + ro = raw_sk(sk); unregister_netdevice_notifier(&ro->notifier); -- cgit v0.10.2 From 243e6df4ed919880d079d717641ad699c6530a03 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 19 Apr 2011 20:44:04 +0200 Subject: mac80211: fix SMPS debugfs locking The locking with SMPS requests means that the debugs file should lock the mgd mutex, not the iflist mutex. Calls to __ieee80211_request_smps() need to hold that mutex, so add an assertion. This has always been wrong, but for some reason never been noticed, probably because the locking error only happens while unassociated. Cc: stable@kernel.org [2.6.34+] Signed-off-by: Johannes Berg Signed-off-by: John W. Linville diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index 3342135..4404973 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -1504,6 +1504,8 @@ int __ieee80211_request_smps(struct ieee80211_sub_if_data *sdata, enum ieee80211_smps_mode old_req; int err; + lockdep_assert_held(&sdata->u.mgd.mtx); + old_req = sdata->u.mgd.req_smps; sdata->u.mgd.req_smps = smps_mode; diff --git a/net/mac80211/debugfs_netdev.c b/net/mac80211/debugfs_netdev.c index dacace6..9ea7c0d 100644 --- a/net/mac80211/debugfs_netdev.c +++ b/net/mac80211/debugfs_netdev.c @@ -177,9 +177,9 @@ static int ieee80211_set_smps(struct ieee80211_sub_if_data *sdata, if (sdata->vif.type != NL80211_IFTYPE_STATION) return -EOPNOTSUPP; - mutex_lock(&local->iflist_mtx); + mutex_lock(&sdata->u.mgd.mtx); err = __ieee80211_request_smps(sdata, smps_mode); - mutex_unlock(&local->iflist_mtx); + mutex_unlock(&sdata->u.mgd.mtx); return err; } -- cgit v0.10.2 From b25026981aecde3685dd0e45ad980fff9f528daa Mon Sep 17 00:00:00 2001 From: Stanislaw Gruszka Date: Wed, 20 Apr 2011 15:57:14 +0200 Subject: iwlwifi: fix skb usage after free Since commit a120e912eb51e347f36c71b60a1d13af74d30e83 Author: Stanislaw Gruszka Date: Fri Feb 19 15:47:33 2010 -0800 iwlwifi: sanity check before counting number of tfds can be free we use skb->data after calling ieee80211_tx_status_irqsafe(), which could free skb instantly. On current kernels I do not observe practical problems related with bug, but on 2.6.35.y it cause random system hangs when stressing wireless link. Cc: stable@kernel.org # 2.6.32+ Signed-off-by: Stanislaw Gruszka Acked-by: Wey-Yi Guy Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-tx.c b/drivers/net/wireless/iwlwifi/iwl-agn-tx.c index a709d05..2dd7d54 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-tx.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-tx.c @@ -1224,12 +1224,16 @@ int iwlagn_tx_queue_reclaim(struct iwl_priv *priv, int txq_id, int index) q->read_ptr = iwl_queue_inc_wrap(q->read_ptr, q->n_bd)) { tx_info = &txq->txb[txq->q.read_ptr]; - iwlagn_tx_status(priv, tx_info, - txq_id >= IWLAGN_FIRST_AMPDU_QUEUE); + + if (WARN_ON_ONCE(tx_info->skb == NULL)) + continue; hdr = (struct ieee80211_hdr *)tx_info->skb->data; - if (hdr && ieee80211_is_data_qos(hdr->frame_control)) + if (ieee80211_is_data_qos(hdr->frame_control)) nfreed++; + + iwlagn_tx_status(priv, tx_info, + txq_id >= IWLAGN_FIRST_AMPDU_QUEUE); tx_info->skb = NULL; if (priv->cfg->ops->lib->txq_inval_byte_cnt_tbl) -- cgit v0.10.2 From 069f40fc07f6df3da325e7ea1698a0d6247983d5 Mon Sep 17 00:00:00 2001 From: Stanislaw Gruszka Date: Wed, 20 Apr 2011 16:01:46 +0200 Subject: iwl4965: fix skb usage after free Since commit a120e912eb51e347f36c71b60a1d13af74d30e83 Author: Stanislaw Gruszka Date: Fri Feb 19 15:47:33 2010 -0800 iwlwifi: sanity check before counting number of tfds can be free we use skb->data after calling ieee80211_tx_status_irqsafe(), which could free skb instantly. On current kernels I do not observe practical problems related with bug, but on 2.6.35.y it cause random system hangs when stressing wireless link, making bisection of other problems impossible. Signed-off-by: Stanislaw Gruszka Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwlegacy/iwl-4965-tx.c b/drivers/net/wireless/iwlegacy/iwl-4965-tx.c index 5c40502f..fbec88d 100644 --- a/drivers/net/wireless/iwlegacy/iwl-4965-tx.c +++ b/drivers/net/wireless/iwlegacy/iwl-4965-tx.c @@ -1127,12 +1127,16 @@ int iwl4965_tx_queue_reclaim(struct iwl_priv *priv, int txq_id, int index) q->read_ptr = iwl_legacy_queue_inc_wrap(q->read_ptr, q->n_bd)) { tx_info = &txq->txb[txq->q.read_ptr]; - iwl4965_tx_status(priv, tx_info, - txq_id >= IWL4965_FIRST_AMPDU_QUEUE); + + if (WARN_ON_ONCE(tx_info->skb == NULL)) + continue; hdr = (struct ieee80211_hdr *)tx_info->skb->data; - if (hdr && ieee80211_is_data_qos(hdr->frame_control)) + if (ieee80211_is_data_qos(hdr->frame_control)) nfreed++; + + iwl4965_tx_status(priv, tx_info, + txq_id >= IWL4965_FIRST_AMPDU_QUEUE); tx_info->skb = NULL; priv->cfg->ops->lib->txq_free_tfd(priv, txq); -- cgit v0.10.2 From b522f02184b413955f3bc952e3776ce41edc6355 Mon Sep 17 00:00:00 2001 From: Vasiliy Kulikov Date: Thu, 14 Apr 2011 20:55:19 +0400 Subject: agp: fix OOM and buffer overflow page_count is copied from userspace. agp_allocate_memory() tries to check whether this number is too big, but doesn't take into account the wrap case. Also agp_create_user_memory() doesn't check whether alloc_size is calculated from num_agp_pages variable without overflow. This may lead to allocation of too small buffer with following buffer overflow. Another problem in agp code is not addressed in the patch - kernel memory exhaustion (AGPIOC_RESERVE and AGPIOC_ALLOCATE ioctls). It is not checked whether requested pid is a pid of the caller (no check in agpioc_reserve_wrap()). Each allocation is limited to 16KB, though, there is no per-process limit. This might lead to OOM situation, which is not even solved in case of the caller death by OOM killer - the memory is allocated for another (faked) process. Signed-off-by: Vasiliy Kulikov Signed-off-by: Dave Airlie diff --git a/drivers/char/agp/generic.c b/drivers/char/agp/generic.c index 012cba0..850a643 100644 --- a/drivers/char/agp/generic.c +++ b/drivers/char/agp/generic.c @@ -115,6 +115,9 @@ static struct agp_memory *agp_create_user_memory(unsigned long num_agp_pages) struct agp_memory *new; unsigned long alloc_size = num_agp_pages*sizeof(struct page *); + if (INT_MAX/sizeof(struct page *) < num_agp_pages) + return NULL; + new = kzalloc(sizeof(struct agp_memory), GFP_KERNEL); if (new == NULL) return NULL; @@ -234,11 +237,14 @@ struct agp_memory *agp_allocate_memory(struct agp_bridge_data *bridge, int scratch_pages; struct agp_memory *new; size_t i; + int cur_memory; if (!bridge) return NULL; - if ((atomic_read(&bridge->current_memory_agp) + page_count) > bridge->max_memory_agp) + cur_memory = atomic_read(&bridge->current_memory_agp); + if ((cur_memory + page_count > bridge->max_memory_agp) || + (cur_memory + page_count < page_count)) return NULL; if (type >= AGP_USER_TYPES) { -- cgit v0.10.2 From 194b3da873fd334ef183806db751473512af29ce Mon Sep 17 00:00:00 2001 From: Vasiliy Kulikov Date: Thu, 14 Apr 2011 20:55:16 +0400 Subject: agp: fix arbitrary kernel memory writes pg_start is copied from userspace on AGPIOC_BIND and AGPIOC_UNBIND ioctl cmds of agp_ioctl() and passed to agpioc_bind_wrap(). As said in the comment, (pg_start + mem->page_count) may wrap in case of AGPIOC_BIND, and it is not checked at all in case of AGPIOC_UNBIND. As a result, user with sufficient privileges (usually "video" group) may generate either local DoS or privilege escalation. Signed-off-by: Vasiliy Kulikov Signed-off-by: Dave Airlie diff --git a/drivers/char/agp/generic.c b/drivers/char/agp/generic.c index 850a643..b072648 100644 --- a/drivers/char/agp/generic.c +++ b/drivers/char/agp/generic.c @@ -1095,8 +1095,8 @@ int agp_generic_insert_memory(struct agp_memory * mem, off_t pg_start, int type) return -EINVAL; } - /* AK: could wrap */ - if ((pg_start + mem->page_count) > num_entries) + if (((pg_start + mem->page_count) > num_entries) || + ((pg_start + mem->page_count) < pg_start)) return -EINVAL; j = pg_start; @@ -1130,7 +1130,7 @@ int agp_generic_remove_memory(struct agp_memory *mem, off_t pg_start, int type) { size_t i; struct agp_bridge_data *bridge; - int mask_type; + int mask_type, num_entries; bridge = mem->bridge; if (!bridge) @@ -1142,6 +1142,11 @@ int agp_generic_remove_memory(struct agp_memory *mem, off_t pg_start, int type) if (type != mem->type) return -EINVAL; + num_entries = agp_num_entries(); + if (((pg_start + mem->page_count) > num_entries) || + ((pg_start + mem->page_count) < pg_start)) + return -EINVAL; + mask_type = bridge->driver->agp_type_to_mask_type(bridge, type); if (mask_type != 0) { /* The generic routines know nothing of memory types */ -- cgit v0.10.2 From 358b1361bed42f4e6cbf8956a73aebf193957d4a Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Thu, 21 Apr 2011 10:55:07 +0200 Subject: netfilter: ctnetlink: fix timestamp support for new conntracks This patch fixes the missing initialization of the start time if the timestamp support is enabled. libnetfilter_conntrack/utils# conntrack -E & libnetfilter_conntrack/utils# ./conntrack_create tcp 6 109 ESTABLISHED src=1.1.1.1 dst=2.2.2.2 sport=1025 dport=21 packets=0 bytes=0 [UNREPLIED] src=2.2.2.2 dst=1.1.1.1 sport=21 dport=1025 packets=0 bytes=0 mark=0 delta-time=1303296401 use=2 Signed-off-by: Pablo Neira Ayuso Signed-off-by: Patrick McHardy diff --git a/net/netfilter/nf_conntrack_netlink.c b/net/netfilter/nf_conntrack_netlink.c index 30bf8a1..482e90c 100644 --- a/net/netfilter/nf_conntrack_netlink.c +++ b/net/netfilter/nf_conntrack_netlink.c @@ -1334,6 +1334,7 @@ ctnetlink_create_conntrack(struct net *net, u16 zone, struct nf_conn *ct; int err = -EINVAL; struct nf_conntrack_helper *helper; + struct nf_conn_tstamp *tstamp; ct = nf_conntrack_alloc(net, zone, otuple, rtuple, GFP_ATOMIC); if (IS_ERR(ct)) @@ -1451,6 +1452,9 @@ ctnetlink_create_conntrack(struct net *net, u16 zone, __set_bit(IPS_EXPECTED_BIT, &ct->status); ct->master = master_ct; } + tstamp = nf_conn_tstamp_find(ct); + if (tstamp) + tstamp->start = ktime_to_ns(ktime_get_real()); add_timer(&ct->timeout); nf_conntrack_hash_insert(ct); -- cgit v0.10.2 From 954d70388307eb1ccb328d9f960657022a316243 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Thu, 21 Apr 2011 10:57:21 +0200 Subject: netfilter: fix ebtables compat support commit 255d0dc34068a976 (netfilter: x_table: speedup compat operations) made ebtables not working anymore. 1) xt_compat_calc_jump() is not an exact match lookup 2) compat_table_info() has a typo in xt_compat_init_offsets() call 3) compat_do_replace() misses a xt_compat_init_offsets() call Reported-by: dann frazier Signed-off-by: Eric Dumazet Signed-off-by: Patrick McHardy diff --git a/net/bridge/netfilter/ebtables.c b/net/bridge/netfilter/ebtables.c index 893669c..9707079 100644 --- a/net/bridge/netfilter/ebtables.c +++ b/net/bridge/netfilter/ebtables.c @@ -1766,7 +1766,7 @@ static int compat_table_info(const struct ebt_table_info *info, newinfo->entries_size = size; - xt_compat_init_offsets(AF_INET, info->nentries); + xt_compat_init_offsets(NFPROTO_BRIDGE, info->nentries); return EBT_ENTRY_ITERATE(entries, size, compat_calc_entry, info, entries, newinfo); } @@ -2240,6 +2240,7 @@ static int compat_do_replace(struct net *net, void __user *user, xt_compat_lock(NFPROTO_BRIDGE); + xt_compat_init_offsets(NFPROTO_BRIDGE, tmp.nentries); ret = compat_copy_entries(entries_tmp, tmp.entries_size, &state); if (ret < 0) goto out_unlock; diff --git a/net/netfilter/x_tables.c b/net/netfilter/x_tables.c index a9adf4c..8a025a5 100644 --- a/net/netfilter/x_tables.c +++ b/net/netfilter/x_tables.c @@ -455,6 +455,7 @@ void xt_compat_flush_offsets(u_int8_t af) vfree(xt[af].compat_tab); xt[af].compat_tab = NULL; xt[af].number = 0; + xt[af].cur = 0; } } EXPORT_SYMBOL_GPL(xt_compat_flush_offsets); @@ -473,8 +474,7 @@ int xt_compat_calc_jump(u_int8_t af, unsigned int offset) else return mid ? tmp[mid - 1].delta : 0; } - WARN_ON_ONCE(1); - return 0; + return left ? tmp[left - 1].delta : 0; } EXPORT_SYMBOL_GPL(xt_compat_calc_jump); -- cgit v0.10.2 From e31b2b228439eee23b8ccc186d3c0e77bd69123b Mon Sep 17 00:00:00 2001 From: Florian Westphal Date: Thu, 21 Apr 2011 10:58:25 +0200 Subject: netfilter: ebtables: only call xt_compat_add_offset once per rule The optimizations in commit 255d0dc34068a976 (netfilter: x_table: speedup compat operations) assume that xt_compat_add_offset is called once per rule. ebtables however called it for each match/target found in a rule. The match/watcher/target parser already returns the needed delta, so it is sufficient to move the xt_compat_add_offset call to a more reasonable location. While at it, also get rid of the unused COMPAT iterator macros. Signed-off-by: Florian Westphal Signed-off-by: Patrick McHardy diff --git a/net/bridge/netfilter/ebtables.c b/net/bridge/netfilter/ebtables.c index 9707079..1a92b36 100644 --- a/net/bridge/netfilter/ebtables.c +++ b/net/bridge/netfilter/ebtables.c @@ -1882,7 +1882,7 @@ static int compat_mtw_from_user(struct compat_ebt_entry_mwt *mwt, struct xt_match *match; struct xt_target *wt; void *dst = NULL; - int off, pad = 0, ret = 0; + int off, pad = 0; unsigned int size_kern, entry_offset, match_size = mwt->match_size; strlcpy(name, mwt->u.name, sizeof(name)); @@ -1935,13 +1935,6 @@ static int compat_mtw_from_user(struct compat_ebt_entry_mwt *mwt, break; } - if (!dst) { - ret = xt_compat_add_offset(NFPROTO_BRIDGE, entry_offset, - off + ebt_compat_entry_padsize()); - if (ret < 0) - return ret; - } - state->buf_kern_offset += match_size + off; state->buf_user_offset += match_size; pad = XT_ALIGN(size_kern) - size_kern; @@ -2016,50 +2009,6 @@ static int ebt_size_mwt(struct compat_ebt_entry_mwt *match32, return growth; } -#define EBT_COMPAT_WATCHER_ITERATE(e, fn, args...) \ -({ \ - unsigned int __i; \ - int __ret = 0; \ - struct compat_ebt_entry_mwt *__watcher; \ - \ - for (__i = e->watchers_offset; \ - __i < (e)->target_offset; \ - __i += __watcher->watcher_size + \ - sizeof(struct compat_ebt_entry_mwt)) { \ - __watcher = (void *)(e) + __i; \ - __ret = fn(__watcher , ## args); \ - if (__ret != 0) \ - break; \ - } \ - if (__ret == 0) { \ - if (__i != (e)->target_offset) \ - __ret = -EINVAL; \ - } \ - __ret; \ -}) - -#define EBT_COMPAT_MATCH_ITERATE(e, fn, args...) \ -({ \ - unsigned int __i; \ - int __ret = 0; \ - struct compat_ebt_entry_mwt *__match; \ - \ - for (__i = sizeof(struct ebt_entry); \ - __i < (e)->watchers_offset; \ - __i += __match->match_size + \ - sizeof(struct compat_ebt_entry_mwt)) { \ - __match = (void *)(e) + __i; \ - __ret = fn(__match , ## args); \ - if (__ret != 0) \ - break; \ - } \ - if (__ret == 0) { \ - if (__i != (e)->watchers_offset) \ - __ret = -EINVAL; \ - } \ - __ret; \ -}) - /* called for all ebt_entry structures. */ static int size_entry_mwt(struct ebt_entry *entry, const unsigned char *base, unsigned int *total, @@ -2132,6 +2081,14 @@ static int size_entry_mwt(struct ebt_entry *entry, const unsigned char *base, } } + if (state->buf_kern_start == NULL) { + unsigned int offset = buf_start - (char *) base; + + ret = xt_compat_add_offset(NFPROTO_BRIDGE, offset, new_offset); + if (ret < 0) + return ret; + } + startoff = state->buf_user_offset - startoff; BUG_ON(*total < startoff); -- cgit v0.10.2 From 37f8527dbfd05af0f670aa02370d0c4cca7fbda6 Mon Sep 17 00:00:00 2001 From: David Rientjes Date: Wed, 20 Apr 2011 19:19:10 -0700 Subject: Revert "x86, NUMA: Fix fakenuma boot failure" Andreas Herrmann reported that 7d6b46707f24 ("x86, NUMA: Fix fakenuma boot failure") causes certain physical NUMA topologies (for example AMD Magny-Cours) to move sibling cpus to a single node when in reality they are in separate domains. This may result in some nodes being completely void of cpus, which doesn't accurately represent the correct topology. The system will boot, but will have suboptimal NUMA performance. This commit was intended as a fix for NUMA emulation, but should not cause a regression for real NUMA machines as a side effect. ( There will be a separate fix for the numa-debug code, which will not affect physical topologies. ) Reported-by: Andreas Herrmann Signed-off-by: David Rientjes Acked-by: KOSAKI Motohiro Cc: Tejun Heo Cc: Linus Torvalds Link: http://lkml.kernel.org/r/alpine.DEB.2.00.1104201918110.12634@chino.kir.corp.google.com Signed-off-by: Ingo Molnar diff --git a/arch/x86/kernel/smpboot.c b/arch/x86/kernel/smpboot.c index 8ed8908..c2871d3 100644 --- a/arch/x86/kernel/smpboot.c +++ b/arch/x86/kernel/smpboot.c @@ -312,26 +312,6 @@ void __cpuinit smp_store_cpu_info(int id) identify_secondary_cpu(c); } -static void __cpuinit check_cpu_siblings_on_same_node(int cpu1, int cpu2) -{ - int node1 = early_cpu_to_node(cpu1); - int node2 = early_cpu_to_node(cpu2); - - /* - * Our CPU scheduler assumes all logical cpus in the same physical cpu - * share the same node. But, buggy ACPI or NUMA emulation might assign - * them to different node. Fix it. - */ - if (node1 != node2) { - pr_warning("CPU %d in node %d and CPU %d in node %d are in the same physical CPU. forcing same node %d\n", - cpu1, node1, cpu2, node2, node2); - - numa_remove_cpu(cpu1); - numa_set_node(cpu1, node2); - numa_add_cpu(cpu1); - } -} - static void __cpuinit link_thread_siblings(int cpu1, int cpu2) { cpumask_set_cpu(cpu1, cpu_sibling_mask(cpu2)); @@ -340,7 +320,6 @@ static void __cpuinit link_thread_siblings(int cpu1, int cpu2) cpumask_set_cpu(cpu2, cpu_core_mask(cpu1)); cpumask_set_cpu(cpu1, cpu_llc_shared_mask(cpu2)); cpumask_set_cpu(cpu2, cpu_llc_shared_mask(cpu1)); - check_cpu_siblings_on_same_node(cpu1, cpu2); } @@ -382,12 +361,10 @@ void __cpuinit set_cpu_sibling_map(int cpu) per_cpu(cpu_llc_id, cpu) == per_cpu(cpu_llc_id, i)) { cpumask_set_cpu(i, cpu_llc_shared_mask(cpu)); cpumask_set_cpu(cpu, cpu_llc_shared_mask(i)); - check_cpu_siblings_on_same_node(cpu, i); } if (c->phys_proc_id == cpu_data(i).phys_proc_id) { cpumask_set_cpu(i, cpu_core_mask(cpu)); cpumask_set_cpu(cpu, cpu_core_mask(i)); - check_cpu_siblings_on_same_node(cpu, i); /* * Does this new cpu bringup a new core? */ -- cgit v0.10.2 From 7a6c6547825a2324faa76cff856db11d78de075e Mon Sep 17 00:00:00 2001 From: David Rientjes Date: Wed, 20 Apr 2011 19:19:13 -0700 Subject: x86, numa: Fix cpu nodemasks for NUMA emulation and CONFIG_DEBUG_PER_CPU_MAPS The cpu<->node mappings under CONFIG_DEBUG_PER_CPU_MAPS=y when NUMA emulation is enabled is currently broken because it does not iterate through every emulated node and bind cpus that have affinity to it. NUMA emulation should bind each cpu to every local node to accurately represent the true NUMA topology of the underlying machine. debug_cpumask_set_cpu() needs to be fixed at the same time so that the debugging information that it emits shows the new cpumask of the node being assigned when the cpu is being added or removed. It can now take responsibility of setting or clearing the cpu itself to remove the need for duplicate code. Also change its last parameter, "enable", to have the correct bool type since it can only be true or false. -v2: Fix the return statements, by Kosaki Motohiro Acked-and-Tested-by: KOSAKI Motohiro Signed-off-by: David Rientjes Cc: Andreas Herrmann Cc: Tejun Heo Cc: Linus Torvalds Link: http://lkml.kernel.org/r/alpine.DEB.2.00.1104201918470.12634@chino.kir.corp.google.com Signed-off-by: Ingo Molnar diff --git a/arch/x86/include/asm/numa.h b/arch/x86/include/asm/numa.h index 3d4dab4..a50fc9f 100644 --- a/arch/x86/include/asm/numa.h +++ b/arch/x86/include/asm/numa.h @@ -51,7 +51,7 @@ static inline void numa_remove_cpu(int cpu) { } #endif /* CONFIG_NUMA */ #ifdef CONFIG_DEBUG_PER_CPU_MAPS -struct cpumask __cpuinit *debug_cpumask_set_cpu(int cpu, int enable); +void debug_cpumask_set_cpu(int cpu, int node, bool enable); #endif #endif /* _ASM_X86_NUMA_H */ diff --git a/arch/x86/mm/numa.c b/arch/x86/mm/numa.c index 9559d36..745258d 100644 --- a/arch/x86/mm/numa.c +++ b/arch/x86/mm/numa.c @@ -213,53 +213,48 @@ int early_cpu_to_node(int cpu) return per_cpu(x86_cpu_to_node_map, cpu); } -struct cpumask __cpuinit *debug_cpumask_set_cpu(int cpu, int enable) +void debug_cpumask_set_cpu(int cpu, int node, bool enable) { - int node = early_cpu_to_node(cpu); struct cpumask *mask; char buf[64]; if (node == NUMA_NO_NODE) { /* early_cpu_to_node() already emits a warning and trace */ - return NULL; + return; } mask = node_to_cpumask_map[node]; if (!mask) { pr_err("node_to_cpumask_map[%i] NULL\n", node); dump_stack(); - return NULL; + return; } + if (enable) + cpumask_set_cpu(cpu, mask); + else + cpumask_clear_cpu(cpu, mask); + cpulist_scnprintf(buf, sizeof(buf), mask); printk(KERN_DEBUG "%s cpu %d node %d: mask now %s\n", enable ? "numa_add_cpu" : "numa_remove_cpu", cpu, node, buf); - return mask; + return; } # ifndef CONFIG_NUMA_EMU -static void __cpuinit numa_set_cpumask(int cpu, int enable) +static void __cpuinit numa_set_cpumask(int cpu, bool enable) { - struct cpumask *mask; - - mask = debug_cpumask_set_cpu(cpu, enable); - if (!mask) - return; - - if (enable) - cpumask_set_cpu(cpu, mask); - else - cpumask_clear_cpu(cpu, mask); + debug_cpumask_set_cpu(cpu, early_cpu_to_node(cpu), enable); } void __cpuinit numa_add_cpu(int cpu) { - numa_set_cpumask(cpu, 1); + numa_set_cpumask(cpu, true); } void __cpuinit numa_remove_cpu(int cpu) { - numa_set_cpumask(cpu, 0); + numa_set_cpumask(cpu, false); } # endif /* !CONFIG_NUMA_EMU */ diff --git a/arch/x86/mm/numa_emulation.c b/arch/x86/mm/numa_emulation.c index ad091e4..de84cc1 100644 --- a/arch/x86/mm/numa_emulation.c +++ b/arch/x86/mm/numa_emulation.c @@ -454,10 +454,9 @@ void __cpuinit numa_remove_cpu(int cpu) cpumask_clear_cpu(cpu, node_to_cpumask_map[i]); } #else /* !CONFIG_DEBUG_PER_CPU_MAPS */ -static void __cpuinit numa_set_cpumask(int cpu, int enable) +static void __cpuinit numa_set_cpumask(int cpu, bool enable) { - struct cpumask *mask; - int nid, physnid, i; + int nid, physnid; nid = early_cpu_to_node(cpu); if (nid == NUMA_NO_NODE) { @@ -467,28 +466,21 @@ static void __cpuinit numa_set_cpumask(int cpu, int enable) physnid = emu_nid_to_phys[nid]; - for_each_online_node(i) { + for_each_online_node(nid) { if (emu_nid_to_phys[nid] != physnid) continue; - mask = debug_cpumask_set_cpu(cpu, enable); - if (!mask) - return; - - if (enable) - cpumask_set_cpu(cpu, mask); - else - cpumask_clear_cpu(cpu, mask); + debug_cpumask_set_cpu(cpu, nid, enable); } } void __cpuinit numa_add_cpu(int cpu) { - numa_set_cpumask(cpu, 1); + numa_set_cpumask(cpu, true); } void __cpuinit numa_remove_cpu(int cpu) { - numa_set_cpumask(cpu, 0); + numa_set_cpumask(cpu, false); } #endif /* !CONFIG_DEBUG_PER_CPU_MAPS */ -- cgit v0.10.2 From dffa4b2f62ff28c982144c7033001b1ece4d3532 Mon Sep 17 00:00:00 2001 From: Borislav Petkov Date: Wed, 20 Apr 2011 12:23:49 +0200 Subject: x86, mce: Drop the default decoding notifier The default notifier doesn't make a lot of sense to call in the correctable errors case. Drop it and emit the mcelog decoding hint only in the uncorrectable errors case and when no notifier is registered. Also, limit issuing the "mcelog --ascii" message in the rare case when we dump unreported CEs before panicking. While at it, remove unused old x86_mce_decode_callback from the header. Signed-off-by: Borislav Petkov Signed-off-by: Prarit Bhargava Cc: Tony Luck Cc: Nagananda Chumbalkar Cc: Russ Anderson Link: http://lkml.kernel.org/r/20110420102349.GB1361@aftab Signed-off-by: Ingo Molnar diff --git a/arch/x86/include/asm/mce.h b/arch/x86/include/asm/mce.h index eb16e94..021979a6 100644 --- a/arch/x86/include/asm/mce.h +++ b/arch/x86/include/asm/mce.h @@ -142,8 +142,6 @@ static inline void winchip_mcheck_init(struct cpuinfo_x86 *c) {} static inline void enable_p5_mce(void) {} #endif -extern void (*x86_mce_decode_callback)(struct mce *m); - void mce_setup(struct mce *m); void mce_log(struct mce *m); DECLARE_PER_CPU(struct sys_device, mce_dev); diff --git a/arch/x86/kernel/cpu/mcheck/mce.c b/arch/x86/kernel/cpu/mcheck/mce.c index 68e2303..ff1ae9b 100644 --- a/arch/x86/kernel/cpu/mcheck/mce.c +++ b/arch/x86/kernel/cpu/mcheck/mce.c @@ -105,20 +105,6 @@ static int cpu_missing; ATOMIC_NOTIFIER_HEAD(x86_mce_decoder_chain); EXPORT_SYMBOL_GPL(x86_mce_decoder_chain); -static int default_decode_mce(struct notifier_block *nb, unsigned long val, - void *data) -{ - pr_emerg(HW_ERR "No human readable MCE decoding support on this CPU type.\n"); - pr_emerg(HW_ERR "Run the message through 'mcelog --ascii' to decode.\n"); - - return NOTIFY_STOP; -} - -static struct notifier_block mce_dec_nb = { - .notifier_call = default_decode_mce, - .priority = -1, -}; - /* MCA banks polled by the period polling timer for corrected events */ DEFINE_PER_CPU(mce_banks_t, mce_poll_banks) = { [0 ... BITS_TO_LONGS(MAX_NR_BANKS)-1] = ~0UL @@ -212,6 +198,8 @@ void mce_log(struct mce *mce) static void print_mce(struct mce *m) { + int ret = 0; + pr_emerg(HW_ERR "CPU %d: Machine Check Exception: %Lx Bank %d: %016Lx\n", m->extcpu, m->mcgstatus, m->bank, m->status); @@ -239,7 +227,11 @@ static void print_mce(struct mce *m) * Print out human-readable details about the MCE error, * (if the CPU has an implementation for that) */ - atomic_notifier_call_chain(&x86_mce_decoder_chain, 0, m); + ret = atomic_notifier_call_chain(&x86_mce_decoder_chain, 0, m); + if (ret == NOTIFY_STOP) + return; + + pr_emerg_ratelimited(HW_ERR "Run the above through 'mcelog --ascii'\n"); } #define PANIC_TIMEOUT 5 /* 5 seconds */ @@ -1721,8 +1713,6 @@ __setup("mce", mcheck_enable); int __init mcheck_init(void) { - atomic_notifier_chain_register(&x86_mce_decoder_chain, &mce_dec_nb); - mcheck_intel_therm_init(); return 0; -- cgit v0.10.2 From d3bf52e998056a6002b2aecfe1d25486376382ac Mon Sep 17 00:00:00 2001 From: Rakib Mullick Date: Wed, 20 Apr 2011 21:27:32 +0600 Subject: sched: Remove obsolete comment from scheduler_tick() scheduler_tick() is no longer called by fork code - this got discarded a long time ago by commit bc947631d1d532 ("sched: improve efficiency of sched_fork()"). So, remove the comment which still claims otherwise. Signed-off-by: Rakib Mullick Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/BANLkTimO4iGP0QpaHO1HHF1QOnVcQpc0cw@mail.gmail.com Signed-off-by: Ingo Molnar diff --git a/kernel/sched.c b/kernel/sched.c index 30a29ad..8cb0a57 100644 --- a/kernel/sched.c +++ b/kernel/sched.c @@ -4002,9 +4002,6 @@ void thread_group_times(struct task_struct *p, cputime_t *ut, cputime_t *st) /* * This function gets called by the timer code, with HZ frequency. * We call it with interrupts disabled. - * - * It also gets called by the fork code, when changing the parent's - * timeslices. */ void scheduler_tick(void) { -- cgit v0.10.2 From 4949603a6fabf3a54cbd7be6df1681789abfca7d Mon Sep 17 00:00:00 2001 From: Markus Trippelsdorf Date: Wed, 20 Apr 2011 14:28:45 -0400 Subject: EDAC: Remove debugging output in scrub rate handling This patch removes superfluous debugging output in the sysfs scrub rate handler. It also consolidates the error handling in the scrub rate accessors. Signed-off-by: Markus Trippelsdorf Signed-off-by: Borislav Petkov diff --git a/drivers/edac/amd64_edac.c b/drivers/edac/amd64_edac.c index 31e71c4f..4b4071e 100644 --- a/drivers/edac/amd64_edac.c +++ b/drivers/edac/amd64_edac.c @@ -211,8 +211,6 @@ static int amd64_get_scrub_rate(struct mem_ctl_info *mci) scrubval = scrubval & 0x001F; - amd64_debug("pci-read, sdram scrub control value: %d\n", scrubval); - for (i = 0; i < ARRAY_SIZE(scrubrates); i++) { if (scrubrates[i].scrubval == scrubval) { retval = scrubrates[i].bandwidth; diff --git a/drivers/edac/edac_mc_sysfs.c b/drivers/edac/edac_mc_sysfs.c index 26343fd..29ffa35 100644 --- a/drivers/edac/edac_mc_sysfs.c +++ b/drivers/edac/edac_mc_sysfs.c @@ -458,13 +458,13 @@ static ssize_t mci_sdram_scrub_rate_store(struct mem_ctl_info *mci, return -EINVAL; new_bw = mci->set_sdram_scrub_rate(mci, bandwidth); - if (new_bw >= 0) { - edac_printk(KERN_DEBUG, EDAC_MC, "Scrub rate set to %d\n", new_bw); - return count; + if (new_bw < 0) { + edac_printk(KERN_WARNING, EDAC_MC, + "Error setting scrub rate to: %lu\n", bandwidth); + return -EINVAL; } - edac_printk(KERN_DEBUG, EDAC_MC, "Error setting scrub rate to: %lu\n", bandwidth); - return -EINVAL; + return count; } /* @@ -483,7 +483,6 @@ static ssize_t mci_sdram_scrub_rate_show(struct mem_ctl_info *mci, char *data) return bandwidth; } - edac_printk(KERN_DEBUG, EDAC_MC, "Read scrub rate: %d\n", bandwidth); return sprintf(data, "%d\n", bandwidth); } -- cgit v0.10.2 From 1a067a22e466d2910d10d47a7125bf7ced943165 Mon Sep 17 00:00:00 2001 From: Artem Bityutskiy Date: Thu, 21 Apr 2011 10:39:54 +0300 Subject: UBIFS: fix false assertion warning in case of I/O failures When UBIFS switches to R/O mode because it detects I/O failures, then when we unmount, we still may have allocated budget, and the assertions which verify that we have not budget will fire. But it is expected to have the budget in case of I/O failures, so the assertion warnings will be false. Suppress them for the I/O failure case. Signed-off-by: Artem Bityutskiy diff --git a/fs/ubifs/super.c b/fs/ubifs/super.c index ec33b06..be6c7b0 100644 --- a/fs/ubifs/super.c +++ b/fs/ubifs/super.c @@ -1772,10 +1772,12 @@ static void ubifs_put_super(struct super_block *sb) * of the media. For example, there will be dirty inodes if we failed * to write them back because of I/O errors. */ - ubifs_assert(atomic_long_read(&c->dirty_pg_cnt) == 0); - ubifs_assert(c->budg_idx_growth == 0); - ubifs_assert(c->budg_dd_growth == 0); - ubifs_assert(c->budg_data_growth == 0); + if (!c->ro_error) { + ubifs_assert(atomic_long_read(&c->dirty_pg_cnt) == 0); + ubifs_assert(c->budg_idx_growth == 0); + ubifs_assert(c->budg_dd_growth == 0); + ubifs_assert(c->budg_data_growth == 0); + } /* * The 'c->umount_lock' prevents races between UBIFS memory shrinker -- cgit v0.10.2 From 6e0d9fd38b750d678bf9fd07db23582f52fafa55 Mon Sep 17 00:00:00 2001 From: Artem Bityutskiy Date: Thu, 21 Apr 2011 14:49:55 +0300 Subject: UBIFS: fix master node recovery This patch fixes the following symptoms: 1. Unmount UBIFS cleanly. 2. Start mounting UBIFS R/W and have a power cut immediately 3. Start mounting UBIFS R/O, this succeeds 4. Try to re-mount UBIFS R/W - this fails immediately or later on, because UBIFS will write the master node to the flash area which has been written before. The analysis of the problem: 1. UBIFS is unmounted cleanly, both copies of the master node are clean. 2. UBIFS is being mounter R/W, starts changing master node copy 1, and a power cut happens. The copy N1 becomes corrupted. 3. UBIFS is being mounted R/O. It notices the copy N1 is corrupted and reads copy N2. Copy N2 is clean. 4. Because of R/O mode, UBIFS cannot recover copy 1. 5. The mount code (ubifs_mount()) sees that the master node is clean, so it decides that no recovery is needed. 6. We are re-mounting R/W. UBIFS believes no recovery is needed and starts updating the master node, but copy N1 is still corrupted and was not recovered! Fix this problem by marking the master node as dirty every time we recover it and we are in R/O mode. This forces further recovery and the UBIFS cleans-up the corruptions and recovers the copy N1 when re-mounting R/W later. Signed-off-by: Artem Bityutskiy Cc: stable@kernel.org diff --git a/fs/ubifs/recovery.c b/fs/ubifs/recovery.c index 936f2cb..3dbad6f 100644 --- a/fs/ubifs/recovery.c +++ b/fs/ubifs/recovery.c @@ -317,6 +317,32 @@ int ubifs_recover_master_node(struct ubifs_info *c) goto out_free; } memcpy(c->rcvrd_mst_node, c->mst_node, UBIFS_MST_NODE_SZ); + + /* + * We had to recover the master node, which means there was an + * unclean reboot. However, it is possible that the master node + * is clean at this point, i.e., %UBIFS_MST_DIRTY is not set. + * E.g., consider the following chain of events: + * + * 1. UBIFS was cleanly unmounted, so the master node is clean + * 2. UBIFS is being mounted R/W and starts changing the master + * node in the first (%UBIFS_MST_LNUM). A power cut happens, + * so this LEB ends up with some amount of garbage at the + * end. + * 3. UBIFS is being mounted R/O. We reach this place and + * recover the master node from the second LEB + * (%UBIFS_MST_LNUM + 1). But we cannot update the media + * because we are being mounted R/O. We have to defer the + * operation. + * 4. However, this master node (@c->mst_node) is marked as + * clean (since the step 1). And if we just return, the + * mount code will be confused and won't recover the master + * node when it is re-mounter R/W later. + * + * Thus, to force the recovery by marking the master node as + * dirty. + */ + c->mst_node->flags |= cpu_to_le32(UBIFS_MST_DIRTY); } else { /* Write the recovered master node */ c->max_sqnum = le64_to_cpu(mst->ch.sqnum) - 1; -- cgit v0.10.2 From 51a63e67da6056c13b5b597dcc9e1b3bd7ceaa55 Mon Sep 17 00:00:00 2001 From: Joseph Cihula Date: Mon, 21 Mar 2011 11:04:24 -0700 Subject: intel_iommu: disable all VT-d PMRs when TXT launched Intel VT-d Protected Memory Regions (PMRs) are supposed to be disabled, on each VT-d engine, after DMA remapping is enabled on the engines. This is because the behavior of having both enabled is not deterministic and because, if TXT has been used to launch the kernel, the PMRs may be programmed to cover memory regions that will be used for DMA. Under some circumstances (certain quirks detected, lack of multiple devices, etc.), the current code does not set up DMA remapping on some VT-d engines. In such cases it also skips disabling the PMRs. This causes failures when the kernel is launched with TXT (most often this occurs on the graphics engine and results in colored vertical bars on the display). This patch detects when the kernel has been launched with TXT and then disables the PMRs on all VT-d engines. In some cases where the reason that remapping is not being enabled is due to possible ACPI DMAR table errors, the VT-d engine addresses may not be correct and thus not able to be safely programmed even to disable PMRs. Because part of the TXT launch process is the verification of these addresses, it will always be safe to disable PMRs if the TXT launch has succeeded and hence only doing this in such cases. Signed-off-by: Joseph Cihula Signed-off-by: David Woodhouse diff --git a/drivers/pci/intel-iommu.c b/drivers/pci/intel-iommu.c index 5dc5d3e..cdded1e 100644 --- a/drivers/pci/intel-iommu.c +++ b/drivers/pci/intel-iommu.c @@ -1299,7 +1299,7 @@ static void iommu_detach_domain(struct dmar_domain *domain, static struct iova_domain reserved_iova_list; static struct lock_class_key reserved_rbtree_key; -static void dmar_init_reserved_ranges(void) +static int dmar_init_reserved_ranges(void) { struct pci_dev *pdev = NULL; struct iova *iova; @@ -1313,8 +1313,10 @@ static void dmar_init_reserved_ranges(void) /* IOAPIC ranges shouldn't be accessed by DMA */ iova = reserve_iova(&reserved_iova_list, IOVA_PFN(IOAPIC_RANGE_START), IOVA_PFN(IOAPIC_RANGE_END)); - if (!iova) + if (!iova) { printk(KERN_ERR "Reserve IOAPIC range failed\n"); + return -ENODEV; + } /* Reserve all PCI MMIO to avoid peer-to-peer access */ for_each_pci_dev(pdev) { @@ -1327,11 +1329,13 @@ static void dmar_init_reserved_ranges(void) iova = reserve_iova(&reserved_iova_list, IOVA_PFN(r->start), IOVA_PFN(r->end)); - if (!iova) + if (!iova) { printk(KERN_ERR "Reserve iova failed\n"); + return -ENODEV; + } } } - + return 0; } static void domain_reserve_special_ranges(struct dmar_domain *domain) @@ -2213,7 +2217,7 @@ static int __init iommu_prepare_static_identity_mapping(int hw) return 0; } -int __init init_dmars(void) +static int __init init_dmars(int force_on) { struct dmar_drhd_unit *drhd; struct dmar_rmrr_unit *rmrr; @@ -2393,8 +2397,15 @@ int __init init_dmars(void) * enable translation */ for_each_drhd_unit(drhd) { - if (drhd->ignored) + if (drhd->ignored) { + /* + * we always have to disable PMRs or DMA may fail on + * this device + */ + if (force_on) + iommu_disable_protect_mem_regions(drhd->iommu); continue; + } iommu = drhd->iommu; iommu_flush_write_buffer(iommu); @@ -3303,12 +3314,21 @@ int __init intel_iommu_init(void) if (no_iommu || dmar_disabled) return -ENODEV; - iommu_init_mempool(); - dmar_init_reserved_ranges(); + if (iommu_init_mempool()) { + if (force_on) + panic("tboot: Failed to initialize iommu memory\n"); + return -ENODEV; + } + + if (dmar_init_reserved_ranges()) { + if (force_on) + panic("tboot: Failed to reserve iommu ranges\n"); + return -ENODEV; + } init_no_remapping_devices(); - ret = init_dmars(); + ret = init_dmars(force_on); if (ret) { if (force_on) panic("tboot: Failed to initialize DMARs\n"); -- cgit v0.10.2 From d20ac252821ab9780ddf00b95629547d3cebc857 Mon Sep 17 00:00:00 2001 From: Michal Simek Date: Mon, 4 Apr 2011 11:20:12 +0200 Subject: ftrace: Build without frame pointers on Microblaze Microblaze doesn't need/support FRAME_POINTERS in order to have a working function tracer. The patch remove Kconfig warning. Warning log: warning: (LOCKDEP && FAULT_INJECTION_STACKTRACE_FILTER && LATENCYTOP && FUNCTION_TRACER && KMEMCHECK) selects FRAME_POINTER which has unmet direct dependencies (DEBUG_KERNEL && (CRIS || M68K || FRV || UML || AVR32 || SUPERH || BLACKFIN || MN10300) || ARCH_WANT_FRAME_POINTERS) Signed-off-by: Michal Simek Link: http://lkml.kernel.org/r/1301908812-8119-2-git-send-email-monstr@monstr.eu CC: Frederic Weisbecker CC: Ingo Molnar Signed-off-by: Steven Rostedt diff --git a/kernel/trace/Kconfig b/kernel/trace/Kconfig index 61d7d59f..2ad39e5 100644 --- a/kernel/trace/Kconfig +++ b/kernel/trace/Kconfig @@ -141,7 +141,7 @@ if FTRACE config FUNCTION_TRACER bool "Kernel Function Tracer" depends on HAVE_FUNCTION_TRACER - select FRAME_POINTER if !ARM_UNWIND && !S390 + select FRAME_POINTER if !ARM_UNWIND && !S390 && !MICROBLAZE select KALLSYMS select GENERIC_TRACER select CONTEXT_SWITCH_TRACER -- cgit v0.10.2 From b3258ff1d6086bd2b9eeb556844a868ad7d49bc8 Mon Sep 17 00:00:00 2001 From: Amit Shah Date: Wed, 16 Mar 2011 19:12:10 +0530 Subject: virtio: Decrement avail idx on buffer detach When detaching a buffer from a vq, the avail.idx value should be decremented as well. This was noticed by hot-unplugging a virtio console port and then plugging in a new one on the same number (re-using the vqs which were just 'disowned'). qemu reported 'Guest moved used index from 0 to 256' when any IO was attempted on the new port. CC: stable@kernel.org Reported-by: juzhang Signed-off-by: Amit Shah Signed-off-by: Rusty Russell diff --git a/drivers/virtio/virtio_ring.c b/drivers/virtio/virtio_ring.c index cc2f73e..b0043fb 100644 --- a/drivers/virtio/virtio_ring.c +++ b/drivers/virtio/virtio_ring.c @@ -371,6 +371,7 @@ void *virtqueue_detach_unused_buf(struct virtqueue *_vq) /* detach_buf clears data, so grab it now. */ buf = vq->data[i]; detach_buf(vq, i); + vq->vring.avail->idx--; END_USE(vq); return buf; } -- cgit v0.10.2 From 31a3ddda166cda86d2b5111e09ba4bda5239fae6 Mon Sep 17 00:00:00 2001 From: Amit Shah Date: Mon, 14 Mar 2011 17:45:02 +0530 Subject: virtio_pci: Prevent double-free of pci regions after device hot-unplug In the case where a virtio-console port is in use (opened by a program) and a virtio-console device is removed, the port is kept around but all the virtio-related state is assumed to be gone. When the port is finally released (close() called), we call device_destroy() on the port's device. This results in the parent device's structures to be freed as well. This includes the PCI regions for the virtio-console PCI device. Once this is done, however, virtio_pci_release_dev() kicks in, as the last ref to the virtio device is now gone, and attempts to do pci_iounmap(pci_dev, vp_dev->ioaddr); pci_release_regions(pci_dev); pci_disable_device(pci_dev); which results in a double-free warning. Move the code that releases regions, etc., to the virtio_pci_remove() function, and all that's now left in release_dev is the final freeing of the vp_dev. Signed-off-by: Amit Shah Signed-off-by: Rusty Russell diff --git a/drivers/virtio/virtio_pci.c b/drivers/virtio/virtio_pci.c index 4fb5b2b..4bcc8b8 100644 --- a/drivers/virtio/virtio_pci.c +++ b/drivers/virtio/virtio_pci.c @@ -590,15 +590,10 @@ static struct virtio_config_ops virtio_pci_config_ops = { static void virtio_pci_release_dev(struct device *_d) { - struct virtio_device *dev = container_of(_d, struct virtio_device, dev); + struct virtio_device *dev = container_of(_d, struct virtio_device, + dev); struct virtio_pci_device *vp_dev = to_vp_device(dev); - struct pci_dev *pci_dev = vp_dev->pci_dev; - vp_del_vqs(dev); - pci_set_drvdata(pci_dev, NULL); - pci_iounmap(pci_dev, vp_dev->ioaddr); - pci_release_regions(pci_dev); - pci_disable_device(pci_dev); kfree(vp_dev); } @@ -681,6 +676,12 @@ static void __devexit virtio_pci_remove(struct pci_dev *pci_dev) struct virtio_pci_device *vp_dev = pci_get_drvdata(pci_dev); unregister_virtio_device(&vp_dev->vdev); + + vp_del_vqs(&vp_dev->vdev); + pci_set_drvdata(pci_dev, NULL); + pci_iounmap(pci_dev, vp_dev->ioaddr); + pci_release_regions(pci_dev); + pci_disable_device(pci_dev); } #ifdef CONFIG_PM -- cgit v0.10.2 From afa2689e19073cd2e762d0f2c1358fab1ab9f18c Mon Sep 17 00:00:00 2001 From: Amit Shah Date: Mon, 14 Mar 2011 17:45:48 +0530 Subject: virtio: console: Enable call to hvc_remove() on console port remove This call was disabled as hot-unplugging one virtconsole port led to another virtconsole port freezing. Upon testing it again, this now works, so enable it. In addition, a bug was found in qemu wherein removing a port of one type caused the guest output from another port to stop working. I doubt it was just this bug that caused it (since disabling the hvc_remove() call did allow other ports to continue working), but since it's all solved now, we're fine with hot-unplugging of virtconsole ports. Signed-off-by: Amit Shah Signed-off-by: Rusty Russell diff --git a/drivers/char/virtio_console.c b/drivers/char/virtio_console.c index 84b164d..838568a 100644 --- a/drivers/char/virtio_console.c +++ b/drivers/char/virtio_console.c @@ -1280,18 +1280,7 @@ static void unplug_port(struct port *port) spin_lock_irq(&pdrvdata_lock); list_del(&port->cons.list); spin_unlock_irq(&pdrvdata_lock); -#if 0 - /* - * hvc_remove() not called as removing one hvc port - * results in other hvc ports getting frozen. - * - * Once this is resolved in hvc, this functionality - * will be enabled. Till that is done, the -EPIPE - * return from get_chars() above will help - * hvc_console.c to clean up on ports we remove here. - */ hvc_remove(port->cons.hvc); -#endif } /* Remove unused data this port might have received. */ -- cgit v0.10.2 From d9b41e0b54fd7e164daf1e9c539c1070398aa02e Mon Sep 17 00:00:00 2001 From: David Rientjes Date: Wed, 20 Apr 2011 19:27:13 -0700 Subject: [PARISC] set memory ranges in N_NORMAL_MEMORY when onlined When a DISCONTIGMEM memory range is brought online as a NUMA node, it also needs to have its bet set in N_NORMAL_MEMORY. This is necessary for generic kernel code that utilizes N_NORMAL_MEMORY as a subset of N_ONLINE for memory savings. These types of hacks can hopefully be removed once DISCONTIGMEM is either removed or abstracted away from CONFIG_NUMA. Fixes a panic in the slub code which only initializes structures for N_NORMAL_MEMORY to save memory: Backtrace: [<000000004021c938>] add_partial+0x28/0x98 [<000000004021faa0>] __slab_free+0x1d0/0x1d8 [<000000004021fd04>] kmem_cache_free+0xc4/0x128 [<000000004033bf9c>] ida_get_new_above+0x21c/0x2c0 [<00000000402a8980>] sysfs_new_dirent+0xd0/0x238 [<00000000402a974c>] create_dir+0x5c/0x168 [<00000000402a9ab0>] sysfs_create_dir+0x98/0x128 [<000000004033d6c4>] kobject_add_internal+0x114/0x258 [<000000004033d9ac>] kobject_add_varg+0x7c/0xa0 [<000000004033df20>] kobject_add+0x50/0x90 [<000000004033dfb4>] kobject_create_and_add+0x54/0xc8 [<00000000407862a0>] cgroup_init+0x138/0x1f0 [<000000004077ce50>] start_kernel+0x5a0/0x840 [<000000004011fa3c>] start_parisc+0xa4/0xb8 [<00000000404bb034>] packet_ioctl+0x16c/0x208 [<000000004049ac30>] ip_mroute_setsockopt+0x260/0xf20 Signed-off-by: David Rientjes Cc: stable@kernel.org Signed-off-by: James Bottomley diff --git a/arch/parisc/mm/init.c b/arch/parisc/mm/init.c index b7ed8d7..b1d1262 100644 --- a/arch/parisc/mm/init.c +++ b/arch/parisc/mm/init.c @@ -266,8 +266,10 @@ static void __init setup_bootmem(void) } memset(pfnnid_map, 0xff, sizeof(pfnnid_map)); - for (i = 0; i < npmem_ranges; i++) + for (i = 0; i < npmem_ranges; i++) { + node_set_state(i, N_NORMAL_MEMORY); node_set_online(i); + } #endif /* -- cgit v0.10.2 From df7e130384efd1c732aa08648dad46687fee3d96 Mon Sep 17 00:00:00 2001 From: Jan Kara Date: Wed, 20 Apr 2011 20:30:40 +0200 Subject: vfs: Pass setxattr(2) flags properly For some reason generic_setxattr() did not pass flags (XATTR_CREATE, XATTR_REPLACE) to the filesystem specific helper. This caused that setxattr(2) syscall just ignored these flags. Fix the bug by passing flags correctly. Signed-off-by: Jan Kara Acked-by: Christoph Hellwig Signed-off-by: Linus Torvalds diff --git a/fs/xattr.c b/fs/xattr.c index a19acdb..f1ef949 100644 --- a/fs/xattr.c +++ b/fs/xattr.c @@ -666,7 +666,7 @@ generic_setxattr(struct dentry *dentry, const char *name, const void *value, siz handler = xattr_resolve_name(dentry->d_sb->s_xattr, &name); if (!handler) return -EOPNOTSUPP; - return handler->set(dentry, name, value, size, 0, handler->flags); + return handler->set(dentry, name, value, size, flags, handler->flags); } /* -- cgit v0.10.2 From d76c8420c3cf8e468901b0bd58306637335c98ea Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Thu, 21 Apr 2011 09:07:26 -0700 Subject: raid5: fix build error, sector_t usage Change from unsigned long long to sector_t. This matches its source field. ERROR: "__udivdi3" [drivers/md/raid456.ko] undefined! Signed-off-by: Randy Dunlap Signed-off-by: Linus Torvalds diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c index fd50011..49bf5f8 100644 --- a/drivers/md/raid5.c +++ b/drivers/md/raid5.c @@ -5678,7 +5678,7 @@ static void raid5_quiesce(mddev_t *mddev, int state) static void *raid45_takeover_raid0(mddev_t *mddev, int level) { struct raid0_private_data *raid0_priv = mddev->private; - unsigned long long sectors; + sector_t sectors; /* for raid0 takeover only one zone is supported */ if (raid0_priv->nr_strip_zones > 1) { -- cgit v0.10.2 From 4906e50b37e6f6c264e7ee4237343eb2b7f8d16d Mon Sep 17 00:00:00 2001 From: Pavel Shilovsky Date: Thu, 14 Apr 2011 22:00:56 +0400 Subject: CIFS: Fix memory over bound bug in cifs_parse_mount_options While password processing we can get out of options array bound if the next character after array is delimiter. The patch adds a check if we reach the end. Signed-off-by: Pavel Shilovsky Reviewed-by: Jeff Layton Signed-off-by: Steve French diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index db9d55b..4bc862a 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c @@ -807,8 +807,7 @@ static int cifs_parse_mount_options(char *options, const char *devname, struct smb_vol *vol) { - char *value; - char *data; + char *value, *data, *end; unsigned int temp_len, i, j; char separator[2]; short int override_uid = -1; @@ -851,6 +850,7 @@ cifs_parse_mount_options(char *options, const char *devname, if (!options) return 1; + end = options + strlen(options); if (strncmp(options, "sep=", 4) == 0) { if (options[4] != 0) { separator[0] = options[4]; @@ -916,6 +916,7 @@ cifs_parse_mount_options(char *options, const char *devname, the only illegal character in a password is null */ if ((value[temp_len] == 0) && + (value + temp_len < end) && (value[temp_len+1] == separator[0])) { /* reinsert comma */ value[temp_len] = separator[0]; -- cgit v0.10.2 From 3aa72873ffdcc2f7919743efbbefc351ec73f5cb Mon Sep 17 00:00:00 2001 From: Jens Axboe Date: Thu, 21 Apr 2011 19:28:35 +0200 Subject: elevator: check for ELEVATOR_INSERT_SORT_MERGE in !elvpriv case too The sort insert is the one that goes to the IO scheduler. With the SORT_MERGE addition, we could bypass IO scheduler setup but still ask the IO scheduler to insert the request. This would cause an oops on switching IO schedulers through the sysfs interface, unless the disk just happened to be idle while it occured. Signed-off-by: Jens Axboe diff --git a/block/elevator.c b/block/elevator.c index 6f6abc0..45ca1e3 100644 --- a/block/elevator.c +++ b/block/elevator.c @@ -671,7 +671,8 @@ void __elv_add_request(struct request_queue *q, struct request *rq, int where) q->boundary_rq = rq; } } else if (!(rq->cmd_flags & REQ_ELVPRIV) && - where == ELEVATOR_INSERT_SORT) + (where == ELEVATOR_INSERT_SORT || + where == ELEVATOR_INSERT_SORT_MERGE)) where = ELEVATOR_INSERT_BACK; switch (where) { -- cgit v0.10.2 From 209ba424c2c6e5ff4dd0ff79bb23659aa6048eac Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Sun, 17 Apr 2011 17:27:08 +0000 Subject: sctp: implement socket option SCTP_GET_ASSOC_ID_LIST This patch Implement socket option SCTP_GET_ASSOC_ID_LIST. SCTP Socket API Extension: 8.2.6. Get the Current Identifiers of Associations (SCTP_GET_ASSOC_ID_LIST) This option gets the current list of SCTP association identifiers of the SCTP associations handled by a one-to-many style socket. Signed-off-by: Wei Yongjun Signed-off-by: Vlad Yasevich Signed-off-by: David S. Miller diff --git a/include/net/sctp/user.h b/include/net/sctp/user.h index e73ebda..793617e 100644 --- a/include/net/sctp/user.h +++ b/include/net/sctp/user.h @@ -91,6 +91,7 @@ typedef __s32 sctp_assoc_t; #define SCTP_PEER_AUTH_CHUNKS 26 /* Read only */ #define SCTP_LOCAL_AUTH_CHUNKS 27 /* Read only */ #define SCTP_GET_ASSOC_NUMBER 28 /* Read only */ +#define SCTP_GET_ASSOC_ID_LIST 29 /* Read only */ /* Internal Socket Options. Some of the sctp library functions are * implemented using these socket options. @@ -669,6 +670,18 @@ struct sctp_authchunks { }; /* + * 8.2.6. Get the Current Identifiers of Associations + * (SCTP_GET_ASSOC_ID_LIST) + * + * This option gets the current list of SCTP association identifiers of + * the SCTP associations handled by a one-to-many style socket. + */ +struct sctp_assoc_ids { + __u32 gaids_number_of_ids; + sctp_assoc_t gaids_assoc_id[]; +}; + +/* * 8.3, 8.5 get all peer/local addresses in an association. * This parameter struct is used by SCTP_GET_PEER_ADDRS and * SCTP_GET_LOCAL_ADDRS socket options used internally to implement diff --git a/net/sctp/socket.c b/net/sctp/socket.c index 431b890..f694ee1 100644 --- a/net/sctp/socket.c +++ b/net/sctp/socket.c @@ -5277,6 +5277,55 @@ static int sctp_getsockopt_assoc_number(struct sock *sk, int len, return 0; } +/* + * 8.2.6. Get the Current Identifiers of Associations + * (SCTP_GET_ASSOC_ID_LIST) + * + * This option gets the current list of SCTP association identifiers of + * the SCTP associations handled by a one-to-many style socket. + */ +static int sctp_getsockopt_assoc_ids(struct sock *sk, int len, + char __user *optval, int __user *optlen) +{ + struct sctp_sock *sp = sctp_sk(sk); + struct sctp_association *asoc; + struct sctp_assoc_ids *ids; + u32 num = 0; + + if (sctp_style(sk, TCP)) + return -EOPNOTSUPP; + + if (len < sizeof(struct sctp_assoc_ids)) + return -EINVAL; + + list_for_each_entry(asoc, &(sp->ep->asocs), asocs) { + num++; + } + + if (len < sizeof(struct sctp_assoc_ids) + sizeof(sctp_assoc_t) * num) + return -EINVAL; + + len = sizeof(struct sctp_assoc_ids) + sizeof(sctp_assoc_t) * num; + + ids = kmalloc(len, GFP_KERNEL); + if (unlikely(!ids)) + return -ENOMEM; + + ids->gaids_number_of_ids = num; + num = 0; + list_for_each_entry(asoc, &(sp->ep->asocs), asocs) { + ids->gaids_assoc_id[num++] = asoc->assoc_id; + } + + if (put_user(len, optlen) || copy_to_user(optval, ids, len)) { + kfree(ids); + return -EFAULT; + } + + kfree(ids); + return 0; +} + SCTP_STATIC int sctp_getsockopt(struct sock *sk, int level, int optname, char __user *optval, int __user *optlen) { @@ -5409,6 +5458,9 @@ SCTP_STATIC int sctp_getsockopt(struct sock *sk, int level, int optname, case SCTP_GET_ASSOC_NUMBER: retval = sctp_getsockopt_assoc_number(sk, len, optval, optlen); break; + case SCTP_GET_ASSOC_ID_LIST: + retval = sctp_getsockopt_assoc_ids(sk, len, optval, optlen); + break; default: retval = -ENOPROTOOPT; break; -- cgit v0.10.2 From ee916fd0fdb8f43dacaab431de3e1f7225039d72 Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Sun, 17 Apr 2011 17:28:01 +0000 Subject: sctp: change auth event type name to SCTP_AUTHENTICATION_EVENT This patch change the auth event type name to SCTP_AUTHENTICATION_EVENT, which is based on API extension compliance. Signed-off-by: Wei Yongjun Signed-off-by: Vlad Yasevich Signed-off-by: David S. Miller diff --git a/include/net/sctp/user.h b/include/net/sctp/user.h index 793617e..4525d8c 100644 --- a/include/net/sctp/user.h +++ b/include/net/sctp/user.h @@ -408,7 +408,8 @@ enum sctp_sn_type { SCTP_SHUTDOWN_EVENT, SCTP_PARTIAL_DELIVERY_EVENT, SCTP_ADAPTATION_INDICATION, - SCTP_AUTHENTICATION_INDICATION, + SCTP_AUTHENTICATION_EVENT, +#define SCTP_AUTHENTICATION_INDICATION SCTP_AUTHENTICATION_EVENT }; /* Notification error codes used to fill up the error fields in some diff --git a/net/sctp/ulpevent.c b/net/sctp/ulpevent.c index dff27d5..62d4a7b 100644 --- a/net/sctp/ulpevent.c +++ b/net/sctp/ulpevent.c @@ -843,7 +843,7 @@ struct sctp_ulpevent *sctp_ulpevent_make_authkey( ak = (struct sctp_authkey_event *) skb_put(skb, sizeof(struct sctp_authkey_event)); - ak->auth_type = SCTP_AUTHENTICATION_INDICATION; + ak->auth_type = SCTP_AUTHENTICATION_EVENT; ak->auth_flags = 0; ak->auth_length = sizeof(struct sctp_authkey_event); -- cgit v0.10.2 From e1cdd553d482ceb083fac5e544e8702fccefbfd6 Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Sun, 17 Apr 2011 17:29:03 +0000 Subject: sctp: implement event notification SCTP_SENDER_DRY_EVENT This patch implement event notification SCTP_SENDER_DRY_EVENT. SCTP Socket API Extensions: 6.1.9. SCTP_SENDER_DRY_EVENT When the SCTP stack has no more user data to send or retransmit, this notification is given to the user. Also, at the time when a user app subscribes to this event, if there is no data to be sent or retransmit, the stack will immediately send up this notification. Signed-off-by: Wei Yongjun Signed-off-by: Vlad Yasevich Signed-off-by: David S. Miller diff --git a/include/net/sctp/sm.h b/include/net/sctp/sm.h index 652f09b..9148632 100644 --- a/include/net/sctp/sm.h +++ b/include/net/sctp/sm.h @@ -165,6 +165,7 @@ sctp_state_fn_t sctp_sf_do_prm_requestheartbeat; sctp_state_fn_t sctp_sf_do_prm_asconf; /* Prototypes for other event state functions. */ +sctp_state_fn_t sctp_sf_do_no_pending_tsn; sctp_state_fn_t sctp_sf_do_9_2_start_shutdown; sctp_state_fn_t sctp_sf_do_9_2_shutdown_ack; sctp_state_fn_t sctp_sf_ignore_other; diff --git a/include/net/sctp/ulpevent.h b/include/net/sctp/ulpevent.h index 7ea12e8..99b027b 100644 --- a/include/net/sctp/ulpevent.h +++ b/include/net/sctp/ulpevent.h @@ -132,6 +132,9 @@ struct sctp_ulpevent *sctp_ulpevent_make_authkey( const struct sctp_association *asoc, __u16 key_id, __u32 indication, gfp_t gfp); +struct sctp_ulpevent *sctp_ulpevent_make_sender_dry_event( + const struct sctp_association *asoc, gfp_t gfp); + void sctp_ulpevent_read_sndrcvinfo(const struct sctp_ulpevent *event, struct msghdr *); __u16 sctp_ulpevent_get_notification_type(const struct sctp_ulpevent *event); diff --git a/include/net/sctp/user.h b/include/net/sctp/user.h index 4525d8c..32fd512 100644 --- a/include/net/sctp/user.h +++ b/include/net/sctp/user.h @@ -354,6 +354,20 @@ struct sctp_authkey_event { enum { SCTP_AUTH_NEWKEY = 0, }; +/* + * 6.1.9. SCTP_SENDER_DRY_EVENT + * + * When the SCTP stack has no more user data to send or retransmit, this + * notification is given to the user. Also, at the time when a user app + * subscribes to this event, if there is no data to be sent or + * retransmit, the stack will immediately send up this notification. + */ +struct sctp_sender_dry_event { + __u16 sender_dry_type; + __u16 sender_dry_flags; + __u32 sender_dry_length; + sctp_assoc_t sender_dry_assoc_id; +}; /* * Described in Section 7.3 @@ -369,6 +383,7 @@ struct sctp_event_subscribe { __u8 sctp_partial_delivery_event; __u8 sctp_adaptation_layer_event; __u8 sctp_authentication_event; + __u8 sctp_sender_dry_event; }; /* @@ -392,6 +407,7 @@ union sctp_notification { struct sctp_adaptation_event sn_adaptation_event; struct sctp_pdapi_event sn_pdapi_event; struct sctp_authkey_event sn_authkey_event; + struct sctp_sender_dry_event sn_sender_dry_event; }; /* Section 5.3.1 @@ -410,6 +426,7 @@ enum sctp_sn_type { SCTP_ADAPTATION_INDICATION, SCTP_AUTHENTICATION_EVENT, #define SCTP_AUTHENTICATION_INDICATION SCTP_AUTHENTICATION_EVENT + SCTP_SENDER_DRY_EVENT, }; /* Notification error codes used to fill up the error fields in some diff --git a/net/sctp/sm_statefuns.c b/net/sctp/sm_statefuns.c index 736847e4..7f4a4f8 100644 --- a/net/sctp/sm_statefuns.c +++ b/net/sctp/sm_statefuns.c @@ -5077,6 +5077,30 @@ sctp_disposition_t sctp_sf_ignore_primitive( ***************************************************************************/ /* + * When the SCTP stack has no more user data to send or retransmit, this + * notification is given to the user. Also, at the time when a user app + * subscribes to this event, if there is no data to be sent or + * retransmit, the stack will immediately send up this notification. + */ +sctp_disposition_t sctp_sf_do_no_pending_tsn( + const struct sctp_endpoint *ep, + const struct sctp_association *asoc, + const sctp_subtype_t type, + void *arg, + sctp_cmd_seq_t *commands) +{ + struct sctp_ulpevent *event; + + event = sctp_ulpevent_make_sender_dry_event(asoc, GFP_ATOMIC); + if (!event) + return SCTP_DISPOSITION_NOMEM; + + sctp_add_cmd_sf(commands, SCTP_CMD_EVENT_ULP, SCTP_ULPEVENT(event)); + + return SCTP_DISPOSITION_CONSUME; +} + +/* * Start the shutdown negotiation. * * From Section 9.2: diff --git a/net/sctp/sm_statetable.c b/net/sctp/sm_statetable.c index 881196b..0338dc6 100644 --- a/net/sctp/sm_statetable.c +++ b/net/sctp/sm_statetable.c @@ -668,7 +668,7 @@ static const sctp_sm_table_entry_t primitive_event_table[SCTP_NUM_PRIMITIVE_TYPE /* SCTP_STATE_COOKIE_ECHOED */ \ TYPE_SCTP_FUNC(sctp_sf_ignore_other), \ /* SCTP_STATE_ESTABLISHED */ \ - TYPE_SCTP_FUNC(sctp_sf_ignore_other), \ + TYPE_SCTP_FUNC(sctp_sf_do_no_pending_tsn), \ /* SCTP_STATE_SHUTDOWN_PENDING */ \ TYPE_SCTP_FUNC(sctp_sf_do_9_2_start_shutdown), \ /* SCTP_STATE_SHUTDOWN_SENT */ \ diff --git a/net/sctp/ulpevent.c b/net/sctp/ulpevent.c index 62d4a7b..c962c60 100644 --- a/net/sctp/ulpevent.c +++ b/net/sctp/ulpevent.c @@ -862,6 +862,34 @@ fail: return NULL; } +/* + * Socket Extensions for SCTP + * 6.3.10. SCTP_SENDER_DRY_EVENT + */ +struct sctp_ulpevent *sctp_ulpevent_make_sender_dry_event( + const struct sctp_association *asoc, gfp_t gfp) +{ + struct sctp_ulpevent *event; + struct sctp_sender_dry_event *sdry; + struct sk_buff *skb; + + event = sctp_ulpevent_new(sizeof(struct sctp_sender_dry_event), + MSG_NOTIFICATION, gfp); + if (!event) + return NULL; + + skb = sctp_event2skb(event); + sdry = (struct sctp_sender_dry_event *) + skb_put(skb, sizeof(struct sctp_sender_dry_event)); + + sdry->sender_dry_type = SCTP_SENDER_DRY_EVENT; + sdry->sender_dry_flags = 0; + sdry->sender_dry_length = sizeof(struct sctp_sender_dry_event); + sctp_ulpevent_set_owner(event, asoc); + sdry->sender_dry_assoc_id = sctp_assoc2id(asoc); + + return event; +} /* Return the notification type, assuming this is a notification * event. -- cgit v0.10.2 From a9cf73ea7ff78f52662c8658d93c226effbbedde Mon Sep 17 00:00:00 2001 From: Shan Wei Date: Tue, 19 Apr 2011 22:52:49 +0000 Subject: ipv6: udp: fix the wrong headroom check At this point, skb->data points to skb_transport_header. So, headroom check is wrong. For some case:bridge(UFO is on) + eth device(UFO is off), there is no enough headroom for IPv6 frag head. But headroom check is always false. This will bring about data be moved to there prior to skb->head, when adding IPv6 frag header to skb. Signed-off-by: Shan Wei Acked-by: Herbert Xu Signed-off-by: David S. Miller diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c index 15c3774..9e305d74 100644 --- a/net/ipv6/udp.c +++ b/net/ipv6/udp.c @@ -1335,7 +1335,7 @@ static struct sk_buff *udp6_ufo_fragment(struct sk_buff *skb, u32 features) skb->ip_summed = CHECKSUM_NONE; /* Check if there is enough headroom to insert fragment header. */ - if ((skb_headroom(skb) < frag_hdr_sz) && + if ((skb_mac_header(skb) < skb->head + frag_hdr_sz) && pskb_expand_head(skb, frag_hdr_sz, 0, GFP_ATOMIC)) goto out; -- cgit v0.10.2 From 7c88a168da8003fd4d8fb6ae103c4ecf29cb1130 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Thu, 21 Apr 2011 19:43:58 +0200 Subject: block: don't propagate unlisted DISK_EVENTs to userland DISK_EVENT_MEDIA_CHANGE is used for both userland visible event and internal event for revalidation of removeable devices. Some legacy drivers don't implement proper event detection and continuously generate events under certain circumstances. For example, ide-cd generates media changed continuously if there's no media in the drive, which can lead to infinite loop of events jumping back and forth between the driver and userland event handler. This patch updates disk event infrastructure such that it never propagates events not listed in disk->events to userland. Those events are processed the same for internal purposes but uevent generation is suppressed. This also ensures that userland only gets events which are advertised in the @events sysfs node lowering risk of confusion. Signed-off-by: Tejun Heo Signed-off-by: Jens Axboe diff --git a/block/genhd.c b/block/genhd.c index b364bd0..2dd9887 100644 --- a/block/genhd.c +++ b/block/genhd.c @@ -1588,9 +1588,13 @@ static void disk_events_workfn(struct work_struct *work) spin_unlock_irq(&ev->lock); - /* tell userland about new events */ + /* + * Tell userland about new events. Only the events listed in + * @disk->events are reported. Unlisted events are processed the + * same internally but never get reported to userland. + */ for (i = 0; i < ARRAY_SIZE(disk_uevents); i++) - if (events & (1 << i)) + if (events & disk->events & (1 << i)) envp[nr_events++] = disk_uevents[i]; if (nr_events) -- cgit v0.10.2 From 7eec77a1816a7042591a6cbdb4820e9e7ebffe0e Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Thu, 21 Apr 2011 19:43:59 +0200 Subject: ide: unexport DISK_EVENT_MEDIA_CHANGE for ide-gd and ide-cd check_events() implementations in both ide-gd and ide-cd are inadequate for in-kernel event polling. Both generate media change events continuously when certain conditions are met causing infinite event loop between the driver and userland event handler. As disk event now supports suppression of unlisted events, simply de-listing DISK_EVENT_MEDIA_CHANGE from disk->events resolves the problem. Internal handling around media revalidation will behave the same while userland will fall back to userland event polling after detecting the device doesn't support disk events. Signed-off-by: Tejun Heo Reported-by: Jens Axboe Acked-by: "David S. Miller" Signed-off-by: Jens Axboe diff --git a/drivers/ide/ide-cd.c b/drivers/ide/ide-cd.c index fd1e117..a5ec5a7 100644 --- a/drivers/ide/ide-cd.c +++ b/drivers/ide/ide-cd.c @@ -1782,7 +1782,6 @@ static int ide_cd_probe(ide_drive_t *drive) ide_cd_read_toc(drive, &sense); g->fops = &idecd_ops; g->flags |= GENHD_FL_REMOVABLE; - g->events = DISK_EVENT_MEDIA_CHANGE; add_disk(g); return 0; diff --git a/drivers/ide/ide-cd_ioctl.c b/drivers/ide/ide-cd_ioctl.c index 2a6bc50..02caa7d 100644 --- a/drivers/ide/ide-cd_ioctl.c +++ b/drivers/ide/ide-cd_ioctl.c @@ -79,6 +79,12 @@ int ide_cdrom_drive_status(struct cdrom_device_info *cdi, int slot_nr) return CDS_DRIVE_NOT_READY; } +/* + * ide-cd always generates media changed event if media is missing, which + * makes it impossible to use for proper event reporting, so disk->events + * is cleared to 0 and the following function is used only to trigger + * revalidation and never propagated to userland. + */ unsigned int ide_cdrom_check_events_real(struct cdrom_device_info *cdi, unsigned int clearing, int slot_nr) { diff --git a/drivers/ide/ide-gd.c b/drivers/ide/ide-gd.c index c4ffd48..70ea876 100644 --- a/drivers/ide/ide-gd.c +++ b/drivers/ide/ide-gd.c @@ -298,6 +298,12 @@ static unsigned int ide_gd_check_events(struct gendisk *disk, return 0; } + /* + * The following is used to force revalidation on the first open on + * removeable devices, and never gets reported to userland as + * genhd->events is 0. This is intended as removeable ide disk + * can't really detect MEDIA_CHANGE events. + */ ret = drive->dev_flags & IDE_DFLAG_MEDIA_CHANGED; drive->dev_flags &= ~IDE_DFLAG_MEDIA_CHANGED; @@ -413,7 +419,6 @@ static int ide_gd_probe(ide_drive_t *drive) if (drive->dev_flags & IDE_DFLAG_REMOVABLE) g->flags = GENHD_FL_REMOVABLE; g->fops = &ide_gd_ops; - g->events = DISK_EVENT_MEDIA_CHANGE; add_disk(g); return 0; -- cgit v0.10.2 From 9fd097b14918875bd6f125ed699d7bbbba5893ee Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Thu, 21 Apr 2011 21:32:55 +0200 Subject: block: unexport DISK_EVENT_MEDIA_CHANGE for legacy/fringe drivers In-kernel disk event polling doesn't matter for legacy/fringe drivers and may lead to infinite event loop if ->check_events() implementation generates events on level condition instead of edge. Now that block layer supports suppressing exporting unlisted events, simply leaving disk->events cleared allows these drivers to keep the internal revalidation behavior intact while avoiding weird interactions with userland event handler. Signed-off-by: Tejun Heo Cc: Kay Sievers Signed-off-by: Jens Axboe diff --git a/drivers/block/DAC960.c b/drivers/block/DAC960.c index 8066d08..e086fbb 100644 --- a/drivers/block/DAC960.c +++ b/drivers/block/DAC960.c @@ -2547,7 +2547,6 @@ static bool DAC960_RegisterBlockDevice(DAC960_Controller_T *Controller) disk->major = MajorNumber; disk->first_minor = n << DAC960_MaxPartitionsBits; disk->fops = &DAC960_BlockDeviceOperations; - disk->events = DISK_EVENT_MEDIA_CHANGE; } /* Indicate the Block Device Registration completed successfully, diff --git a/drivers/block/amiflop.c b/drivers/block/amiflop.c index 456c0cc..8eba86b 100644 --- a/drivers/block/amiflop.c +++ b/drivers/block/amiflop.c @@ -1736,7 +1736,6 @@ static int __init fd_probe_drives(void) disk->major = FLOPPY_MAJOR; disk->first_minor = drive; disk->fops = &floppy_fops; - disk->events = DISK_EVENT_MEDIA_CHANGE; sprintf(disk->disk_name, "fd%d", drive); disk->private_data = &unit[drive]; set_capacity(disk, 880*2); diff --git a/drivers/block/ataflop.c b/drivers/block/ataflop.c index c871eae..ede16c6 100644 --- a/drivers/block/ataflop.c +++ b/drivers/block/ataflop.c @@ -1964,7 +1964,6 @@ static int __init atari_floppy_init (void) unit[i].disk->first_minor = i; sprintf(unit[i].disk->disk_name, "fd%d", i); unit[i].disk->fops = &floppy_fops; - unit[i].disk->events = DISK_EVENT_MEDIA_CHANGE; unit[i].disk->private_data = &unit[i]; unit[i].disk->queue = blk_init_queue(do_fd_request, &ataflop_lock); diff --git a/drivers/block/floppy.c b/drivers/block/floppy.c index 301d7a9..db8f885 100644 --- a/drivers/block/floppy.c +++ b/drivers/block/floppy.c @@ -4205,7 +4205,6 @@ static int __init floppy_init(void) disks[dr]->major = FLOPPY_MAJOR; disks[dr]->first_minor = TOMINOR(dr); disks[dr]->fops = &floppy_fops; - disks[dr]->events = DISK_EVENT_MEDIA_CHANGE; sprintf(disks[dr]->disk_name, "fd%d", dr); init_timer(&motor_off_timer[dr]); diff --git a/drivers/block/paride/pcd.c b/drivers/block/paride/pcd.c index 2f2ccf6..8690e31 100644 --- a/drivers/block/paride/pcd.c +++ b/drivers/block/paride/pcd.c @@ -320,7 +320,6 @@ static void pcd_init_units(void) disk->first_minor = unit; strcpy(disk->disk_name, cd->name); /* umm... */ disk->fops = &pcd_bdops; - disk->events = DISK_EVENT_MEDIA_CHANGE; } } diff --git a/drivers/block/paride/pd.c b/drivers/block/paride/pd.c index 21dfdb77..869e767 100644 --- a/drivers/block/paride/pd.c +++ b/drivers/block/paride/pd.c @@ -837,7 +837,6 @@ static void pd_probe_drive(struct pd_unit *disk) p->fops = &pd_fops; p->major = major; p->first_minor = (disk - pd) << PD_BITS; - p->events = DISK_EVENT_MEDIA_CHANGE; disk->gd = p; p->private_data = disk; p->queue = pd_queue; diff --git a/drivers/block/paride/pf.c b/drivers/block/paride/pf.c index 7adeb1e..f21b520 100644 --- a/drivers/block/paride/pf.c +++ b/drivers/block/paride/pf.c @@ -294,7 +294,6 @@ static void __init pf_init_units(void) disk->first_minor = unit; strcpy(disk->disk_name, pf->name); disk->fops = &pf_fops; - disk->events = DISK_EVENT_MEDIA_CHANGE; if (!(*drives[unit])[D_PRT]) pf_drive_count++; } diff --git a/drivers/block/swim.c b/drivers/block/swim.c index 24a482f..fd5adcd 100644 --- a/drivers/block/swim.c +++ b/drivers/block/swim.c @@ -858,7 +858,6 @@ static int __devinit swim_floppy_init(struct swim_priv *swd) swd->unit[drive].disk->first_minor = drive; sprintf(swd->unit[drive].disk->disk_name, "fd%d", drive); swd->unit[drive].disk->fops = &floppy_fops; - swd->unit[drive].disk->events = DISK_EVENT_MEDIA_CHANGE; swd->unit[drive].disk->private_data = &swd->unit[drive]; swd->unit[drive].disk->queue = swd->queue; set_capacity(swd->unit[drive].disk, 2880); diff --git a/drivers/block/swim3.c b/drivers/block/swim3.c index 4c10f56..773bfa7 100644 --- a/drivers/block/swim3.c +++ b/drivers/block/swim3.c @@ -1163,7 +1163,6 @@ static int __devinit swim3_attach(struct macio_dev *mdev, const struct of_device disk->major = FLOPPY_MAJOR; disk->first_minor = i; disk->fops = &floppy_fops; - disk->events = DISK_EVENT_MEDIA_CHANGE; disk->private_data = &floppy_states[i]; disk->queue = swim3_queue; disk->flags |= GENHD_FL_REMOVABLE; diff --git a/drivers/block/ub.c b/drivers/block/ub.c index 68b9430..0e376d4 100644 --- a/drivers/block/ub.c +++ b/drivers/block/ub.c @@ -2334,7 +2334,6 @@ static int ub_probe_lun(struct ub_dev *sc, int lnum) disk->major = UB_MAJOR; disk->first_minor = lun->id * UB_PARTS_PER_LUN; disk->fops = &ub_bd_fops; - disk->events = DISK_EVENT_MEDIA_CHANGE; disk->private_data = lun; disk->driverfs_dev = &sc->intf->dev; diff --git a/drivers/block/xsysace.c b/drivers/block/xsysace.c index 645ff76..6c7fd7d 100644 --- a/drivers/block/xsysace.c +++ b/drivers/block/xsysace.c @@ -1005,7 +1005,6 @@ static int __devinit ace_setup(struct ace_device *ace) ace->gd->major = ace_major; ace->gd->first_minor = ace->id * ACE_NUM_MINORS; ace->gd->fops = &ace_fops; - ace->gd->events = DISK_EVENT_MEDIA_CHANGE; ace->gd->queue = ace->queue; ace->gd->private_data = ace; snprintf(ace->gd->disk_name, 32, "xs%c", ace->id + 'a'); diff --git a/drivers/cdrom/gdrom.c b/drivers/cdrom/gdrom.c index b2b034f..3ceaf00 100644 --- a/drivers/cdrom/gdrom.c +++ b/drivers/cdrom/gdrom.c @@ -803,7 +803,6 @@ static int __devinit probe_gdrom(struct platform_device *devptr) goto probe_fail_cdrom_register; } gd.disk->fops = &gdrom_bdops; - gd.disk->events = DISK_EVENT_MEDIA_CHANGE; /* latch on to the interrupt */ err = gdrom_set_interrupt_handlers(); if (err) diff --git a/drivers/cdrom/viocd.c b/drivers/cdrom/viocd.c index 4e874c5..e427fbe 100644 --- a/drivers/cdrom/viocd.c +++ b/drivers/cdrom/viocd.c @@ -626,7 +626,6 @@ static int viocd_probe(struct vio_dev *vdev, const struct vio_device_id *id) gendisk->queue = q; gendisk->fops = &viocd_fops; gendisk->flags = GENHD_FL_CD|GENHD_FL_REMOVABLE; - gendisk->events = DISK_EVENT_MEDIA_CHANGE; set_capacity(gendisk, 0); gendisk->private_data = d; d->viocd_disk = gendisk; diff --git a/drivers/message/i2o/i2o_block.c b/drivers/message/i2o/i2o_block.c index 643ad52..4796bbf 100644 --- a/drivers/message/i2o/i2o_block.c +++ b/drivers/message/i2o/i2o_block.c @@ -1000,7 +1000,6 @@ static struct i2o_block_device *i2o_block_device_alloc(void) gd->major = I2O_MAJOR; gd->queue = queue; gd->fops = &i2o_block_fops; - gd->events = DISK_EVENT_MEDIA_CHANGE; gd->private_data = dev; dev->gd = gd; diff --git a/drivers/s390/char/tape_block.c b/drivers/s390/char/tape_block.c index 83cea9a55..1b3924c 100644 --- a/drivers/s390/char/tape_block.c +++ b/drivers/s390/char/tape_block.c @@ -236,7 +236,6 @@ tapeblock_setup_device(struct tape_device * device) disk->major = tapeblock_major; disk->first_minor = device->first_minor; disk->fops = &tapeblock_fops; - disk->events = DISK_EVENT_MEDIA_CHANGE; disk->private_data = tape_get_device(device); disk->queue = blkdat->request_queue; set_capacity(disk, 0); -- cgit v0.10.2 From e138f96bf5142c400b6b00f4cf69031bccc48f32 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Thu, 21 Apr 2011 15:19:02 -0700 Subject: mv643xx_eth: Fix build regression. From Stephen Rothwell: -------------------- After merging the final tree, today's linux-next build (powerpc chrp32_defconfig) failed like this: drivers/net/mv643xx_eth.c: In function 'port_start': drivers/net/mv643xx_eth.c:2250: error: 'dev' undeclared (first use in this function) Caused by commit aad59c431b77 ("net: mv643xx: convert to hw_features"). -------------------- Reported-by: Stephen Rothwell Signed-off-by: David S. Miller diff --git a/drivers/net/mv643xx_eth.c b/drivers/net/mv643xx_eth.c index 29605a3..57c2ac0 100644 --- a/drivers/net/mv643xx_eth.c +++ b/drivers/net/mv643xx_eth.c @@ -2247,7 +2247,7 @@ static void port_start(struct mv643xx_eth_private *mp) * frames to RX queue #0, and include the pseudo-header when * calculating receive checksums. */ - mv643xx_eth_set_features(dev, dev->features); + mv643xx_eth_set_features(mp->dev, mp->dev->features); /* * Treat BPDUs as normal multicasts, and disable partition mode. -- cgit v0.10.2 From 505d9147a72d4e14323af9581dde066bd5fc439c Mon Sep 17 00:00:00 2001 From: Sam Ravnborg Date: Thu, 21 Apr 2011 15:37:20 -0700 Subject: sparc32: fix section mismatch warnings in apc, pmc and time_32 In all cases there were a struct of_device_id variable defined __initdata. But it was referenced from struct platform_driver.of_match_table which is not guaranteed to be used during init only. So drop the __initdata annotation. This fixes following warnings: WARNING: arch/sparc/kernel/built-in.o(.data+0x810): Section mismatch in reference from the variable clock_driver to the variable .init.data:clock_match The variable clock_driver references the variable __initdata clock_match If the reference is valid then annotate the variable with __init* or __refdata (see linux/init.h) or name the variable: *_template, *_timer, *_sht, *_ops, *_probe, *_probe_one, *_console WARNING: arch/sparc/kernel/built-in.o(.data+0xcec): Section mismatch in reference from the variable apc_driver to the variable .init.data:apc_match The variable apc_driver references the variable __initdata apc_match If the reference is valid then annotate the variable with __init* or __refdata (see linux/init.h) or name the variable: *_template, *_timer, *_sht, *_ops, *_probe, *_probe_one, *_console WARNING: arch/sparc/kernel/built-in.o(.data+0xd60): Section mismatch in reference from the variable pmc_driver to the variable .init.data:pmc_match The variable pmc_driver references the variable __initdata pmc_match If the reference is valid then annotate the variable with __init* or __refdata (see linux/init.h) or name the variable: *_template, *_timer, *_sht, *_ops, *_probe, *_probe_one, *_console Signed-off-by: Sam Ravnborg Signed-off-by: David S. Miller diff --git a/arch/sparc/kernel/apc.c b/arch/sparc/kernel/apc.c index f679c57..1e34f29 100644 --- a/arch/sparc/kernel/apc.c +++ b/arch/sparc/kernel/apc.c @@ -165,7 +165,7 @@ static int __devinit apc_probe(struct platform_device *op) return 0; } -static struct of_device_id __initdata apc_match[] = { +static struct of_device_id apc_match[] = { { .name = APC_OBPNAME, }, diff --git a/arch/sparc/kernel/pmc.c b/arch/sparc/kernel/pmc.c index 93d7b44..6a585d3 100644 --- a/arch/sparc/kernel/pmc.c +++ b/arch/sparc/kernel/pmc.c @@ -69,7 +69,7 @@ static int __devinit pmc_probe(struct platform_device *op) return 0; } -static struct of_device_id __initdata pmc_match[] = { +static struct of_device_id pmc_match[] = { { .name = PMC_OBPNAME, }, diff --git a/arch/sparc/kernel/time_32.c b/arch/sparc/kernel/time_32.c index 4e23639..96046a4 100644 --- a/arch/sparc/kernel/time_32.c +++ b/arch/sparc/kernel/time_32.c @@ -168,7 +168,7 @@ static int __devinit clock_probe(struct platform_device *op) return 0; } -static struct of_device_id __initdata clock_match[] = { +static struct of_device_id clock_match[] = { { .name = "eeprom", }, -- cgit v0.10.2 From f486b3dc2d048e7309a733f97eb9f9f83d586df2 Mon Sep 17 00:00:00 2001 From: Sam Ravnborg Date: Thu, 21 Apr 2011 16:35:46 -0700 Subject: sparc32: fix sparcstation 5 boot The sparcstation 5 I have available has no MID property for the CPU. This resulted in a panic when booting a SMP kernel on this box. The assigned field in cpu_data is never used, so if we fail to read the MID property then inform user and continue booting. Signed-off-by: Sam Ravnborg Signed-off-by: David S. Miller diff --git a/arch/sparc/kernel/smp_32.c b/arch/sparc/kernel/smp_32.c index 91c10fb..850a136 100644 --- a/arch/sparc/kernel/smp_32.c +++ b/arch/sparc/kernel/smp_32.c @@ -53,6 +53,7 @@ cpumask_t smp_commenced_mask = CPU_MASK_NONE; void __cpuinit smp_store_cpu_info(int id) { int cpu_node; + int mid; cpu_data(id).udelay_val = loops_per_jiffy; @@ -60,10 +61,13 @@ void __cpuinit smp_store_cpu_info(int id) cpu_data(id).clock_tick = prom_getintdefault(cpu_node, "clock-frequency", 0); cpu_data(id).prom_node = cpu_node; - cpu_data(id).mid = cpu_get_hwmid(cpu_node); + mid = cpu_get_hwmid(cpu_node); - if (cpu_data(id).mid < 0) - panic("No MID found for CPU%d at node 0x%08d", id, cpu_node); + if (mid < 0) { + printk(KERN_NOTICE "No MID found for CPU%d at node 0x%08d", id, cpu_node); + mid = 0; + } + cpu_data(id).mid = mid; } void __init smp_cpus_done(unsigned int max_cpus) -- cgit v0.10.2 From e2a85aecebc03d165bc2dcd233deadd5dd97ea9f Mon Sep 17 00:00:00 2001 From: Andrea Galbusera Date: Thu, 21 Apr 2011 02:21:21 +0000 Subject: powerpc: Fix multicast problem in fs_enet driver mac-fec.c was setting individual UDP address registers instead of multicast group address registers when joining a multicast group. This prevented from correctly receiving UDP multicast packets. According to datasheet, replaced hash_table_high and hash_table_low with grp_hash_table_high and grp_hash_table_low respectively. Also renamed hash_table_* with grp_hash_table_* in struct fec declaration for 8xx: these registers are used only for multicast there. Tested on a MPC5121 based board. Build tested also against mpc866_ads_defconfig. Signed-off-by: Andrea Galbusera Signed-off-by: David S. Miller diff --git a/arch/powerpc/include/asm/8xx_immap.h b/arch/powerpc/include/asm/8xx_immap.h index 6b6dc20..bdf0563 100644 --- a/arch/powerpc/include/asm/8xx_immap.h +++ b/arch/powerpc/include/asm/8xx_immap.h @@ -393,8 +393,8 @@ typedef struct fec { uint fec_addr_low; /* lower 32 bits of station address */ ushort fec_addr_high; /* upper 16 bits of station address */ ushort res1; /* reserved */ - uint fec_hash_table_high; /* upper 32-bits of hash table */ - uint fec_hash_table_low; /* lower 32-bits of hash table */ + uint fec_grp_hash_table_high; /* upper 32-bits of hash table */ + uint fec_grp_hash_table_low; /* lower 32-bits of hash table */ uint fec_r_des_start; /* beginning of Rx descriptor ring */ uint fec_x_des_start; /* beginning of Tx descriptor ring */ uint fec_r_buff_size; /* Rx buffer size */ diff --git a/drivers/net/fs_enet/mac-fec.c b/drivers/net/fs_enet/mac-fec.c index 61035fc..b9fbc83 100644 --- a/drivers/net/fs_enet/mac-fec.c +++ b/drivers/net/fs_enet/mac-fec.c @@ -226,8 +226,8 @@ static void set_multicast_finish(struct net_device *dev) } FC(fecp, r_cntrl, FEC_RCNTRL_PROM); - FW(fecp, hash_table_high, fep->fec.hthi); - FW(fecp, hash_table_low, fep->fec.htlo); + FW(fecp, grp_hash_table_high, fep->fec.hthi); + FW(fecp, grp_hash_table_low, fep->fec.htlo); } static void set_multicast_list(struct net_device *dev) @@ -273,8 +273,8 @@ static void restart(struct net_device *dev) /* * Reset all multicast. */ - FW(fecp, hash_table_high, fep->fec.hthi); - FW(fecp, hash_table_low, fep->fec.htlo); + FW(fecp, grp_hash_table_high, fep->fec.hthi); + FW(fecp, grp_hash_table_low, fep->fec.htlo); /* * Set maximum receive buffer size. -- cgit v0.10.2 From 4d95847381228639844c7197deb8b2211274ef22 Mon Sep 17 00:00:00 2001 From: Matt Carlson Date: Wed, 20 Apr 2011 07:57:35 +0000 Subject: tg3: Workaround rx_discards stat bug The 5717, 5718, 5719 A0, and 5720 A0 has a bug where the rx_discards statistic counter will increment when dropping unwanted multicast frames. This patch works around the problem by attempting to recreate the data using other means. The resulting value will not be accurate, but it can still serve as a problem indicator. Signed-off-by: Matt Carlson Signed-off-by: Michael Chan Signed-off-by: David S. Miller diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index 9915734..58787ea 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -339,6 +339,7 @@ static const struct { { "dma_write_prioq_full" }, { "rxbds_empty" }, { "rx_discards" }, + { "mbuf_lwm_thresh_hit" }, { "rx_errors" }, { "rx_threshold_hit" }, @@ -8207,6 +8208,10 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy) val = BUFMGR_MODE_ENABLE | BUFMGR_MODE_ATTN_ENABLE; if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5719) val |= BUFMGR_MODE_NO_TX_UNDERRUN; + if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5717 || + tp->pci_chip_rev_id == CHIPREV_ID_5719_A0 || + tp->pci_chip_rev_id == CHIPREV_ID_5720_A0) + val |= BUFMGR_MODE_MBLOW_ATTN_ENAB; tw32(BUFMGR_MODE, val); for (i = 0; i < 2000; i++) { if (tr32(BUFMGR_MODE) & BUFMGR_MODE_ENABLE) @@ -8870,7 +8875,19 @@ static void tg3_periodic_fetch_stats(struct tg3 *tp) TG3_STAT_ADD32(&sp->rx_undersize_packets, MAC_RX_STATS_UNDERSIZE); TG3_STAT_ADD32(&sp->rxbds_empty, RCVLPC_NO_RCV_BD_CNT); - TG3_STAT_ADD32(&sp->rx_discards, RCVLPC_IN_DISCARDS_CNT); + if (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5717) { + TG3_STAT_ADD32(&sp->rx_discards, RCVLPC_IN_DISCARDS_CNT); + } else { + u32 val = tr32(HOSTCC_FLOW_ATTN); + val = (val & HOSTCC_FLOW_ATTN_MBUF_LWM) ? 1 : 0; + if (val) { + tw32(HOSTCC_FLOW_ATTN, HOSTCC_FLOW_ATTN_MBUF_LWM); + sp->rx_discards.low += val; + if (sp->rx_discards.low < val) + sp->rx_discards.high += 1; + } + sp->mbuf_lwm_thresh_hit = sp->rx_discards; + } TG3_STAT_ADD32(&sp->rx_errors, RCVLPC_IN_ERRORS_CNT); } @@ -13973,6 +13990,14 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) GET_CHIP_REV(tp->pci_chip_rev_id) != CHIPREV_5700_BX) tp->coalesce_mode |= HOSTCC_MODE_32BYTE; + /* Set these bits to enable statistics workaround. */ + if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5717 || + tp->pci_chip_rev_id == CHIPREV_ID_5719_A0 || + tp->pci_chip_rev_id == CHIPREV_ID_5720_A0) { + tp->coalesce_mode |= HOSTCC_MODE_ATTN; + tp->grc_mode |= GRC_MODE_IRQ_ON_FLOW_ATTN; + } + if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5785 || GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57780) tp->tg3_flags3 |= TG3_FLG3_USE_PHYLIB; diff --git a/drivers/net/tg3.h b/drivers/net/tg3.h index 224c3e0..db50bfe 100644 --- a/drivers/net/tg3.h +++ b/drivers/net/tg3.h @@ -147,6 +147,7 @@ #define CHIPREV_ID_5717_A0 0x05717000 #define CHIPREV_ID_57765_A0 0x57785000 #define CHIPREV_ID_5719_A0 0x05719000 +#define CHIPREV_ID_5720_A0 0x05720000 #define GET_ASIC_REV(CHIP_REV_ID) ((CHIP_REV_ID) >> 12) #define ASIC_REV_5700 0x07 #define ASIC_REV_5701 0x00 @@ -2602,6 +2603,7 @@ struct tg3_hw_stats { tg3_stat64_t dma_write_prioq_full; tg3_stat64_t rxbds_empty; tg3_stat64_t rx_discards; + tg3_stat64_t mbuf_lwm_thresh_hit; tg3_stat64_t rx_errors; tg3_stat64_t rx_threshold_hit; -- cgit v0.10.2 From eb07a9408e05f67caa671bdf2a509a4d2bd05abf Mon Sep 17 00:00:00 2001 From: Matt Carlson Date: Wed, 20 Apr 2011 07:57:36 +0000 Subject: tg3: Adjust rx prod ring bd replenish thresholds The oldest tg3 devices had large rx producer ring BD caches. Back then, it made sense to make the BD cache replenish threshold only a function of the number of rx buffers posted by the driver. Since then, the BD cache sizes have shrunk to 25% of their original size and, in some cases, the ring sizes have quadrupled in size. Under such conditions, static BD cache replenish thresholds no longer match the hardware constraints. This patch attempts to factor in the BD cache size into the bd cache replenish strategy, taking the existing hardware bugs into account. Signed-off-by: Matt Carlson Reviewed-by: Michael Chan Signed-off-by: David S. Miller diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index 58787ea..4aecb0a 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -7952,6 +7952,48 @@ static void tg3_rings_reset(struct tg3 *tp) } } +static void tg3_setup_rxbd_thresholds(struct tg3 *tp) +{ + u32 val, bdcache_maxcnt, host_rep_thresh, nic_rep_thresh; + + if (!(tp->tg3_flags2 & TG3_FLG2_5750_PLUS) || + (tp->tg3_flags2 & TG3_FLG2_5780_CLASS) || + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5750 || + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5752) + bdcache_maxcnt = TG3_SRAM_RX_STD_BDCACHE_SIZE_5700; + else if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5755 || + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5787) + bdcache_maxcnt = TG3_SRAM_RX_STD_BDCACHE_SIZE_5755; + else + bdcache_maxcnt = TG3_SRAM_RX_STD_BDCACHE_SIZE_5906; + + nic_rep_thresh = min(bdcache_maxcnt / 2, tp->rx_std_max_post); + host_rep_thresh = max_t(u32, tp->rx_pending / 8, 1); + + val = min(nic_rep_thresh, host_rep_thresh); + tw32(RCVBDI_STD_THRESH, val); + + if (tp->tg3_flags3 & TG3_FLG3_57765_PLUS) + tw32(STD_REPLENISH_LWM, bdcache_maxcnt); + + if (!(tp->tg3_flags & TG3_FLAG_JUMBO_CAPABLE) || + (tp->tg3_flags2 & TG3_FLG2_5780_CLASS)) + return; + + if (!(tp->tg3_flags2 & TG3_FLG2_5705_PLUS)) + bdcache_maxcnt = TG3_SRAM_RX_JMB_BDCACHE_SIZE_5700; + else + bdcache_maxcnt = TG3_SRAM_RX_JMB_BDCACHE_SIZE_5717; + + host_rep_thresh = max_t(u32, tp->rx_jumbo_pending / 8, 1); + + val = min(bdcache_maxcnt / 2, host_rep_thresh); + tw32(RCVBDI_JUMBO_THRESH, val); + + if (tp->tg3_flags3 & TG3_FLG3_57765_PLUS) + tw32(JMB_REPLENISH_LWM, bdcache_maxcnt); +} + /* tp->lock is held. */ static int tg3_reset_hw(struct tg3 *tp, int reset_phy) { @@ -8223,21 +8265,10 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy) return -ENODEV; } - /* Setup replenish threshold. */ - val = tp->rx_pending / 8; - if (val == 0) - val = 1; - else if (val > tp->rx_std_max_post) - val = tp->rx_std_max_post; - else if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906) { - if (tp->pci_chip_rev_id == CHIPREV_ID_5906_A1) - tw32(ISO_PKT_TX, (tr32(ISO_PKT_TX) & ~0x3) | 0x2); + if (tp->pci_chip_rev_id == CHIPREV_ID_5906_A1) + tw32(ISO_PKT_TX, (tr32(ISO_PKT_TX) & ~0x3) | 0x2); - if (val > (TG3_RX_INTERNAL_RING_SZ_5906 / 2)) - val = TG3_RX_INTERNAL_RING_SZ_5906 / 2; - } - - tw32(RCVBDI_STD_THRESH, val); + tg3_setup_rxbd_thresholds(tp); /* Initialize TG3_BDINFO's at: * RCVDBDI_STD_BD: standard eth size rx ring @@ -8275,8 +8306,6 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy) if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5719 || ((tp->tg3_flags & TG3_FLAG_JUMBO_CAPABLE) && !(tp->tg3_flags2 & TG3_FLG2_5780_CLASS))) { - /* Setup replenish threshold. */ - tw32(RCVBDI_JUMBO_THRESH, tp->rx_jumbo_pending / 8); if (tp->tg3_flags & TG3_FLAG_JUMBO_RING_ENABLE) { tw32(RCVDBDI_JUMBO_BD + TG3_BDINFO_HOST_ADDR + TG3_64BIT_REG_HIGH, @@ -8317,11 +8346,6 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy) tp->rx_jumbo_pending : 0; tw32_rx_mbox(TG3_RX_JMB_PROD_IDX_REG, tpr->rx_jmb_prod_idx); - if (tp->tg3_flags3 & TG3_FLG3_57765_PLUS) { - tw32(STD_REPLENISH_LWM, 32); - tw32(JMB_REPLENISH_LWM, 16); - } - tg3_rings_reset(tp); /* Initialize MAC address and backoff seed. */ @@ -13599,6 +13623,7 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) (tp->tg3_flags2 & TG3_FLG2_5780_CLASS)) tp->tg3_flags2 |= TG3_FLG2_5750_PLUS; + if ((GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5705) || (tp->tg3_flags2 & TG3_FLG2_5750_PLUS)) tp->tg3_flags2 |= TG3_FLG2_5705_PLUS; diff --git a/drivers/net/tg3.h b/drivers/net/tg3.h index db50bfe..dd331f8 100644 --- a/drivers/net/tg3.h +++ b/drivers/net/tg3.h @@ -23,8 +23,6 @@ #define TG3_BDINFO_NIC_ADDR 0xcUL /* 32-bit */ #define TG3_BDINFO_SIZE 0x10UL -#define TG3_RX_INTERNAL_RING_SZ_5906 32 - #define TG3_RX_STD_MAX_SIZE_5700 512 #define TG3_RX_STD_MAX_SIZE_5717 2048 #define TG3_RX_JMB_MAX_SIZE_5700 256 @@ -2136,6 +2134,13 @@ #define NIC_SRAM_MBUF_POOL_BASE5705 0x00010000 #define NIC_SRAM_MBUF_POOL_SIZE5705 0x0000e000 +#define TG3_SRAM_RX_STD_BDCACHE_SIZE_5700 128 +#define TG3_SRAM_RX_STD_BDCACHE_SIZE_5755 64 +#define TG3_SRAM_RX_STD_BDCACHE_SIZE_5906 32 + +#define TG3_SRAM_RX_JMB_BDCACHE_SIZE_5700 64 +#define TG3_SRAM_RX_JMB_BDCACHE_SIZE_5717 16 + /* Currently this is fixed. */ #define TG3_PHY_MII_ADDR 0x01 -- cgit v0.10.2 From 4a85f09831329bc5a5e4b9bca3f3ecbffb78f858 Mon Sep 17 00:00:00 2001 From: Matt Carlson Date: Wed, 20 Apr 2011 07:57:37 +0000 Subject: tg3: Nullify RSS for loopback test The loopback test assumes all traffic goes to the first rx queue. There is a 1 in 4 chance this won't be true if RSS is enabled though. This patch reprograms the RSS indirection table to route all rx packets to the first queue. Signed-off-by: Matt Carlson Reviewed-by: Michael Chan Signed-off-by: David S. Miller diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index 4aecb0a..1f233c4 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -11269,6 +11269,15 @@ static int tg3_test_loopback(struct tg3 *tp) goto done; } + if (tp->tg3_flags3 & TG3_FLG3_ENABLE_RSS) { + int i; + + /* Reroute all rx packets to the 1st queue */ + for (i = MAC_RSS_INDIR_TBL_0; + i < MAC_RSS_INDIR_TBL_0 + TG3_RSS_INDIR_TBL_SIZE; i += 4) + tw32(i, 0x0); + } + /* Turn off gphy autopowerdown. */ if (tp->phy_flags & TG3_PHYFLG_ENABLE_APD) tg3_phy_toggle_apd(tp, false); -- cgit v0.10.2 From 34eea5ac214353ccd93ef7dd8dbd10aed87f5f46 Mon Sep 17 00:00:00 2001 From: Matt Carlson Date: Wed, 20 Apr 2011 07:57:38 +0000 Subject: tg3: Only allow phy ioctls while netif_running When tg3 was new, phy accesses through ioctl were allowable at any time. Then, the driver started shutting down the phy when the device was closed. Phy accesses would be allowed when the driver first attached to the device, but then would be forbidden after the device had been up'd and down'd. After that, management firmware made it illegal to access the phy unless the driver "owned" the device. Now that most firmware is being moved over to the APE, it is less clear when phy accesses are safe. While it is possible to attempt to identify these conditions and code the driver to navigate through the pitfalls, it could be perplexing to the admin why phy accesses work in some cases and not others. This patch brings some uniformity to the problem by only allowing phy accesses while the driver has control of the device. Signed-off-by: Matt Carlson Reviewed-by: Michael Chan Signed-off-by: David S. Miller diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index 1f233c4..e134e48 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -11444,9 +11444,7 @@ static int tg3_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) if (tp->phy_flags & TG3_PHYFLG_PHY_SERDES) break; /* We have no PHY */ - if ((tp->phy_flags & TG3_PHYFLG_IS_LOW_POWER) || - ((tp->tg3_flags & TG3_FLAG_ENABLE_ASF) && - !netif_running(dev))) + if (!netif_running(dev)) return -EAGAIN; spin_lock_bh(&tp->lock); @@ -11462,9 +11460,7 @@ static int tg3_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) if (tp->phy_flags & TG3_PHYFLG_PHY_SERDES) break; /* We have no PHY */ - if ((tp->phy_flags & TG3_PHYFLG_IS_LOW_POWER) || - ((tp->tg3_flags & TG3_FLAG_ENABLE_ASF) && - !netif_running(dev))) + if (!netif_running(dev)) return -EAGAIN; spin_lock_bh(&tp->lock); -- cgit v0.10.2 From b0988c15c12c40b9680730f55a8351f30ec7a564 Mon Sep 17 00:00:00 2001 From: Matt Carlson Date: Wed, 20 Apr 2011 07:57:39 +0000 Subject: tg3: Move phy accessor functions higher Phy accessor functions should live closer to where the base phy read / write routines are. Signed-off-by: Matt Carlson Reviewed-by: Michael Chan Signed-off-by: David S. Miller diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index e134e48..ea41d76 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -881,6 +881,74 @@ static int tg3_writephy(struct tg3 *tp, int reg, u32 val) return ret; } +static int tg3_phy_cl45_write(struct tg3 *tp, u32 devad, u32 addr, u32 val) +{ + int err; + + err = tg3_writephy(tp, MII_TG3_MMD_CTRL, devad); + if (err) + goto done; + + err = tg3_writephy(tp, MII_TG3_MMD_ADDRESS, addr); + if (err) + goto done; + + err = tg3_writephy(tp, MII_TG3_MMD_CTRL, + MII_TG3_MMD_CTRL_DATA_NOINC | devad); + if (err) + goto done; + + err = tg3_writephy(tp, MII_TG3_MMD_ADDRESS, val); + +done: + return err; +} + +static int tg3_phy_cl45_read(struct tg3 *tp, u32 devad, u32 addr, u32 *val) +{ + int err; + + err = tg3_writephy(tp, MII_TG3_MMD_CTRL, devad); + if (err) + goto done; + + err = tg3_writephy(tp, MII_TG3_MMD_ADDRESS, addr); + if (err) + goto done; + + err = tg3_writephy(tp, MII_TG3_MMD_CTRL, + MII_TG3_MMD_CTRL_DATA_NOINC | devad); + if (err) + goto done; + + err = tg3_readphy(tp, MII_TG3_MMD_ADDRESS, val); + +done: + return err; +} + +static int tg3_phydsp_read(struct tg3 *tp, u32 reg, u32 *val) +{ + int err; + + err = tg3_writephy(tp, MII_TG3_DSP_ADDRESS, reg); + if (!err) + err = tg3_readphy(tp, MII_TG3_DSP_RW_PORT, val); + + return err; +} + +static int tg3_phydsp_write(struct tg3 *tp, u32 reg, u32 val) +{ + int err; + + err = tg3_writephy(tp, MII_TG3_DSP_ADDRESS, reg); + if (!err) + err = tg3_writephy(tp, MII_TG3_DSP_RW_PORT, val); + + return err; +} + static int tg3_bmcr_reset(struct tg3 *tp) { u32 phy_control; @@ -1154,52 +1222,6 @@ static void tg3_mdio_fini(struct tg3 *tp) } } -static int tg3_phy_cl45_write(struct tg3 *tp, u32 devad, u32 addr, u32 val) -{ - int err; - - err = tg3_writephy(tp, MII_TG3_MMD_CTRL, devad); - if (err) - goto done; - - err = tg3_writephy(tp, MII_TG3_MMD_ADDRESS, addr); - if (err) - goto done; - - err = tg3_writephy(tp, MII_TG3_MMD_CTRL, - MII_TG3_MMD_CTRL_DATA_NOINC | devad); - if (err) - goto done; - - err = tg3_writephy(tp, MII_TG3_MMD_ADDRESS, val); - -done: - return err; -} - -static int tg3_phy_cl45_read(struct tg3 *tp, u32 devad, u32 addr, u32 *val) -{ - int err; - - err = tg3_writephy(tp, MII_TG3_MMD_CTRL, devad); - if (err) - goto done; - - err = tg3_writephy(tp, MII_TG3_MMD_ADDRESS, addr); - if (err) - goto done; - - err = tg3_writephy(tp, MII_TG3_MMD_CTRL, - MII_TG3_MMD_CTRL_DATA_NOINC | devad); - if (err) - goto done; - - err = tg3_readphy(tp, MII_TG3_MMD_ADDRESS, val); - -done: - return err; -} - /* tp->lock is held. */ static inline void tg3_generate_fw_event(struct tg3 *tp) { @@ -1576,28 +1598,6 @@ static void tg3_phy_fini(struct tg3 *tp) } } -static int tg3_phydsp_read(struct tg3 *tp, u32 reg, u32 *val) -{ - int err; - - err = tg3_writephy(tp, MII_TG3_DSP_ADDRESS, reg); - if (!err) - err = tg3_readphy(tp, MII_TG3_DSP_RW_PORT, val); - - return err; -} - -static int tg3_phydsp_write(struct tg3 *tp, u32 reg, u32 val) -{ - int err; - - err = tg3_writephy(tp, MII_TG3_DSP_ADDRESS, reg); - if (!err) - err = tg3_writephy(tp, MII_TG3_DSP_RW_PORT, val); - - return err; -} - static void tg3_phy_fet_toggle_apd(struct tg3 *tp, bool enable) { u32 phytest; -- cgit v0.10.2 From 15ee95c36d355a9f47746eaa4ae8cc0ecafec550 Mon Sep 17 00:00:00 2001 From: Matt Carlson Date: Wed, 20 Apr 2011 07:57:40 +0000 Subject: tg3: Add read accessor for AUX CTRL phy reg This patch adds a read accessor for the aux ctrl register. Signed-off-by: Matt Carlson Reviewed-by: Michael Chan Signed-off-by: David S. Miller diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index ea41d76..7be10cf 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -949,6 +949,19 @@ static int tg3_phydsp_write(struct tg3 *tp, u32 reg, u32 val) return err; } +static int tg3_phy_auxctl_read(struct tg3 *tp, int reg, u32 *val) +{ + int err; + + err = tg3_writephy(tp, MII_TG3_AUX_CTRL, + (reg << MII_TG3_AUXCTL_MISC_RDSEL_SHIFT) | + MII_TG3_AUXCTL_SHDWSEL_MISC); + if (!err) + err = tg3_readphy(tp, MII_TG3_AUX_CTRL, val); + + return err; +} + static int tg3_bmcr_reset(struct tg3 *tp) { u32 phy_control; @@ -1679,10 +1692,11 @@ static void tg3_phy_toggle_automdix(struct tg3 *tp, int enable) tg3_writephy(tp, MII_TG3_FET_TEST, ephy); } } else { - phy = MII_TG3_AUXCTL_MISC_RDSEL_MISC | - MII_TG3_AUXCTL_SHDWSEL_MISC; - if (!tg3_writephy(tp, MII_TG3_AUX_CTRL, phy) && - !tg3_readphy(tp, MII_TG3_AUX_CTRL, &phy)) { + int ret; + + ret = tg3_phy_auxctl_read(tp, + MII_TG3_AUXCTL_SHDWSEL_MISC, &phy); + if (!ret) { if (enable) phy |= MII_TG3_AUXCTL_MISC_FORCE_AMDIX; else @@ -1695,13 +1709,14 @@ static void tg3_phy_toggle_automdix(struct tg3 *tp, int enable) static void tg3_phy_set_wirespeed(struct tg3 *tp) { + int ret; u32 val; if (tp->phy_flags & TG3_PHYFLG_NO_ETH_WIRE_SPEED) return; - if (!tg3_writephy(tp, MII_TG3_AUX_CTRL, 0x7007) && - !tg3_readphy(tp, MII_TG3_AUX_CTRL, &val)) + ret = tg3_phy_auxctl_read(tp, MII_TG3_AUXCTL_SHDWSEL_MISC, &val); + if (!ret) tg3_writephy(tp, MII_TG3_AUX_CTRL, (val | (1 << 15) | (1 << 4))); } @@ -2092,8 +2107,9 @@ out: tg3_writephy(tp, MII_TG3_AUX_CTRL, 0x4c20); } else if (tp->tg3_flags & TG3_FLAG_JUMBO_CAPABLE) { /* Set bit 14 with read-modify-write to preserve other bits */ - if (!tg3_writephy(tp, MII_TG3_AUX_CTRL, 0x0007) && - !tg3_readphy(tp, MII_TG3_AUX_CTRL, &val)) + err = tg3_phy_auxctl_read(tp, + MII_TG3_AUXCTL_SHDWSEL_AUXCTL, &val); + if (!err) tg3_writephy(tp, MII_TG3_AUX_CTRL, val | 0x4000); } @@ -3263,9 +3279,10 @@ static int tg3_setup_copper_phy(struct tg3 *tp, int force_reset) current_duplex = DUPLEX_INVALID; if (tp->phy_flags & TG3_PHYFLG_CAPACITIVE_COUPLING) { - tg3_writephy(tp, MII_TG3_AUX_CTRL, 0x4007); - tg3_readphy(tp, MII_TG3_AUX_CTRL, &val); - if (!(val & (1 << 10))) { + err = tg3_phy_auxctl_read(tp, + MII_TG3_AUXCTL_SHDWSEL_MISCTEST, + &val); + if (!err && !(val & (1 << 10))) { val |= (1 << 10); tg3_writephy(tp, MII_TG3_AUX_CTRL, val); goto relink; diff --git a/drivers/net/tg3.h b/drivers/net/tg3.h index dd331f8..b9382f1 100644 --- a/drivers/net/tg3.h +++ b/drivers/net/tg3.h @@ -2194,19 +2194,22 @@ #define MII_TG3_AUX_CTRL 0x18 /* auxiliary control register */ +#define MII_TG3_AUXCTL_SHDWSEL_AUXCTL 0x0000 +#define MII_TG3_AUXCTL_ACTL_TX_6DB 0x0400 +#define MII_TG3_AUXCTL_ACTL_SMDSP_ENA 0x0800 + +#define MII_TG3_AUXCTL_SHDWSEL_PWRCTL 0x0002 #define MII_TG3_AUXCTL_PCTL_100TX_LPWR 0x0010 #define MII_TG3_AUXCTL_PCTL_SPR_ISOLATE 0x0020 #define MII_TG3_AUXCTL_PCTL_VREG_11V 0x0180 -#define MII_TG3_AUXCTL_SHDWSEL_PWRCTL 0x0002 -#define MII_TG3_AUXCTL_MISC_WREN 0x8000 -#define MII_TG3_AUXCTL_MISC_FORCE_AMDIX 0x0200 -#define MII_TG3_AUXCTL_MISC_RDSEL_MISC 0x7000 +#define MII_TG3_AUXCTL_SHDWSEL_MISCTEST 0x0004 + #define MII_TG3_AUXCTL_SHDWSEL_MISC 0x0007 +#define MII_TG3_AUXCTL_MISC_FORCE_AMDIX 0x0200 +#define MII_TG3_AUXCTL_MISC_RDSEL_SHIFT 12 +#define MII_TG3_AUXCTL_MISC_WREN 0x8000 -#define MII_TG3_AUXCTL_ACTL_SMDSP_ENA 0x0800 -#define MII_TG3_AUXCTL_ACTL_TX_6DB 0x0400 -#define MII_TG3_AUXCTL_SHDWSEL_AUXCTL 0x0000 #define MII_TG3_AUX_STAT 0x19 /* auxiliary status register */ #define MII_TG3_AUX_STAT_LPASS 0x0004 -- cgit v0.10.2 From b4bd292933537e19107c3e151b27a15fefa5f8d0 Mon Sep 17 00:00:00 2001 From: Matt Carlson Date: Wed, 20 Apr 2011 07:57:41 +0000 Subject: tg3: Add write accessor for AUX CTRL phy reg This patch adds a write accessor for the aux ctrl phy register. Signed-off-by: Matt Carlson Reviewed-by: Michael Chan Signed-off-by: David S. Miller diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index 7be10cf..69cd7cf 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -962,6 +962,14 @@ static int tg3_phy_auxctl_read(struct tg3 *tp, int reg, u32 *val) return err; } +static int tg3_phy_auxctl_write(struct tg3 *tp, int reg, u32 set) +{ + if (reg == MII_TG3_AUXCTL_SHDWSEL_MISC) + set |= MII_TG3_AUXCTL_MISC_WREN; + + return tg3_writephy(tp, MII_TG3_AUX_CTRL, set | reg); +} + static int tg3_bmcr_reset(struct tg3 *tp) { u32 phy_control; @@ -1701,8 +1709,8 @@ static void tg3_phy_toggle_automdix(struct tg3 *tp, int enable) phy |= MII_TG3_AUXCTL_MISC_FORCE_AMDIX; else phy &= ~MII_TG3_AUXCTL_MISC_FORCE_AMDIX; - phy |= MII_TG3_AUXCTL_MISC_WREN; - tg3_writephy(tp, MII_TG3_AUX_CTRL, phy); + tg3_phy_auxctl_write(tp, + MII_TG3_AUXCTL_SHDWSEL_MISC, phy); } } } @@ -1717,8 +1725,8 @@ static void tg3_phy_set_wirespeed(struct tg3 *tp) ret = tg3_phy_auxctl_read(tp, MII_TG3_AUXCTL_SHDWSEL_MISC, &val); if (!ret) - tg3_writephy(tp, MII_TG3_AUX_CTRL, - (val | (1 << 15) | (1 << 4))); + tg3_phy_auxctl_write(tp, MII_TG3_AUXCTL_SHDWSEL_MISC, + val | MII_TG3_AUXCTL_MISC_WIRESPD_EN); } static void tg3_phy_apply_otp(struct tg3 *tp) @@ -2104,13 +2112,14 @@ out: /* support jumbo frames */ if ((tp->phy_id & TG3_PHY_ID_MASK) == TG3_PHY_ID_BCM5401) { /* Cannot do read-modify-write on 5401 */ - tg3_writephy(tp, MII_TG3_AUX_CTRL, 0x4c20); + tg3_phy_auxctl_write(tp, MII_TG3_AUXCTL_SHDWSEL_AUXCTL, 0x4c20); } else if (tp->tg3_flags & TG3_FLAG_JUMBO_CAPABLE) { /* Set bit 14 with read-modify-write to preserve other bits */ err = tg3_phy_auxctl_read(tp, MII_TG3_AUXCTL_SHDWSEL_AUXCTL, &val); if (!err) - tg3_writephy(tp, MII_TG3_AUX_CTRL, val | 0x4000); + tg3_phy_auxctl_write(tp, MII_TG3_AUXCTL_SHDWSEL_AUXCTL, + val | MII_TG3_AUXCTL_ACTL_EXTPKTLEN); } /* Set phy register 0x10 bit 0 to high fifo elasticity to support @@ -2319,11 +2328,10 @@ static void tg3_power_down_phy(struct tg3 *tp, bool do_low_power) tg3_writephy(tp, MII_TG3_EXT_CTRL, MII_TG3_EXT_CTRL_FORCE_LED_OFF); - tg3_writephy(tp, MII_TG3_AUX_CTRL, - MII_TG3_AUXCTL_SHDWSEL_PWRCTL | - MII_TG3_AUXCTL_PCTL_100TX_LPWR | - MII_TG3_AUXCTL_PCTL_SPR_ISOLATE | - MII_TG3_AUXCTL_PCTL_VREG_11V); + val = MII_TG3_AUXCTL_PCTL_100TX_LPWR | + MII_TG3_AUXCTL_PCTL_SPR_ISOLATE | + MII_TG3_AUXCTL_PCTL_VREG_11V; + tg3_phy_auxctl_write(tp, MII_TG3_AUXCTL_SHDWSEL_PWRCTL, val); } /* The PHY should not be powered down on some chips because @@ -2717,8 +2725,13 @@ static int tg3_power_down_prepare(struct tg3 *tp) u32 mac_mode; if (!(tp->phy_flags & TG3_PHYFLG_PHY_SERDES)) { - if (do_low_power) { - tg3_writephy(tp, MII_TG3_AUX_CTRL, 0x5a); + if (do_low_power && + !(tp->phy_flags & TG3_PHYFLG_IS_FET)) { + tg3_phy_auxctl_write(tp, + MII_TG3_AUXCTL_SHDWSEL_PWRCTL, + MII_TG3_AUXCTL_PCTL_WOL_EN | + MII_TG3_AUXCTL_PCTL_100TX_LPWR | + MII_TG3_AUXCTL_PCTL_CL_AB_TXDAC); udelay(40); } @@ -3092,7 +3105,7 @@ static int tg3_init_5401phy_dsp(struct tg3 *tp) /* Turn off tap power management. */ /* Set Extended packet length bit */ - err = tg3_writephy(tp, MII_TG3_AUX_CTRL, 0x4c20); + err = tg3_phy_auxctl_write(tp, MII_TG3_AUXCTL_SHDWSEL_AUXCTL, 0x4c20); err |= tg3_phydsp_write(tp, 0x0012, 0x1804); err |= tg3_phydsp_write(tp, 0x0013, 0x1204); @@ -3198,7 +3211,7 @@ static int tg3_setup_copper_phy(struct tg3 *tp, int force_reset) udelay(80); } - tg3_writephy(tp, MII_TG3_AUX_CTRL, 0x02); + tg3_phy_auxctl_write(tp, MII_TG3_AUXCTL_SHDWSEL_PWRCTL, 0); /* Some third-party PHYs need to be reset on link going * down. @@ -3283,8 +3296,9 @@ static int tg3_setup_copper_phy(struct tg3 *tp, int force_reset) MII_TG3_AUXCTL_SHDWSEL_MISCTEST, &val); if (!err && !(val & (1 << 10))) { - val |= (1 << 10); - tg3_writephy(tp, MII_TG3_AUX_CTRL, val); + tg3_phy_auxctl_write(tp, + MII_TG3_AUXCTL_SHDWSEL_MISCTEST, + val | (1 << 10)); goto relink; } } diff --git a/drivers/net/tg3.h b/drivers/net/tg3.h index b9382f1..eaa7669 100644 --- a/drivers/net/tg3.h +++ b/drivers/net/tg3.h @@ -2197,15 +2197,19 @@ #define MII_TG3_AUXCTL_SHDWSEL_AUXCTL 0x0000 #define MII_TG3_AUXCTL_ACTL_TX_6DB 0x0400 #define MII_TG3_AUXCTL_ACTL_SMDSP_ENA 0x0800 +#define MII_TG3_AUXCTL_ACTL_EXTPKTLEN 0x4000 #define MII_TG3_AUXCTL_SHDWSEL_PWRCTL 0x0002 +#define MII_TG3_AUXCTL_PCTL_WOL_EN 0x0008 #define MII_TG3_AUXCTL_PCTL_100TX_LPWR 0x0010 #define MII_TG3_AUXCTL_PCTL_SPR_ISOLATE 0x0020 +#define MII_TG3_AUXCTL_PCTL_CL_AB_TXDAC 0x0040 #define MII_TG3_AUXCTL_PCTL_VREG_11V 0x0180 #define MII_TG3_AUXCTL_SHDWSEL_MISCTEST 0x0004 #define MII_TG3_AUXCTL_SHDWSEL_MISC 0x0007 +#define MII_TG3_AUXCTL_MISC_WIRESPD_EN 0x0010 #define MII_TG3_AUXCTL_MISC_FORCE_AMDIX 0x0200 #define MII_TG3_AUXCTL_MISC_RDSEL_SHIFT 12 #define MII_TG3_AUXCTL_MISC_WREN 0x8000 -- cgit v0.10.2 From 1d36ba450bf8c88eda57deb028370880d09a14bc Mon Sep 17 00:00:00 2001 From: Matt Carlson Date: Wed, 20 Apr 2011 07:57:42 +0000 Subject: tg3: Add macro for SMDSP toggling A common AUX CTRL operation in the driver is to enable and disable the SMDSP. This patch consolidates the code so that the details of the operation are in one place. This patch also adds code to make sure the SMDSP is enabled before executing code that relies on it. Signed-off-by: Matt Carlson Reviewed-by: Michael Chan Signed-off-by: David S. Miller diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index 69cd7cf..9ed6bfb 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -970,6 +970,15 @@ static int tg3_phy_auxctl_write(struct tg3 *tp, int reg, u32 set) return tg3_writephy(tp, MII_TG3_AUX_CTRL, set | reg); } +#define TG3_PHY_AUXCTL_SMDSP_ENABLE(tp) \ + tg3_phy_auxctl_write((tp), MII_TG3_AUXCTL_SHDWSEL_AUXCTL, \ + MII_TG3_AUXCTL_ACTL_SMDSP_ENA | \ + MII_TG3_AUXCTL_ACTL_TX_6DB) + +#define TG3_PHY_AUXCTL_SMDSP_DISABLE(tp) \ + tg3_phy_auxctl_write((tp), MII_TG3_AUXCTL_SHDWSEL_AUXCTL, \ + MII_TG3_AUXCTL_ACTL_TX_6DB); + static int tg3_bmcr_reset(struct tg3 *tp) { u32 phy_control; @@ -1738,11 +1747,8 @@ static void tg3_phy_apply_otp(struct tg3 *tp) otp = tp->phy_otp; - /* Enable SM_DSP clock and tx 6dB coding. */ - phy = MII_TG3_AUXCTL_SHDWSEL_AUXCTL | - MII_TG3_AUXCTL_ACTL_SMDSP_ENA | - MII_TG3_AUXCTL_ACTL_TX_6DB; - tg3_writephy(tp, MII_TG3_AUX_CTRL, phy); + if (TG3_PHY_AUXCTL_SMDSP_ENABLE(tp)) + return; phy = ((otp & TG3_OTP_AGCTGT_MASK) >> TG3_OTP_AGCTGT_SHIFT); phy |= MII_TG3_DSP_TAP1_AGCTGT_DFLT; @@ -1766,10 +1772,7 @@ static void tg3_phy_apply_otp(struct tg3 *tp) ((otp & TG3_OTP_RCOFF_MASK) >> TG3_OTP_RCOFF_SHIFT); tg3_phydsp_write(tp, MII_TG3_DSP_EXP97, phy); - /* Turn off SM_DSP clock. */ - phy = MII_TG3_AUXCTL_SHDWSEL_AUXCTL | - MII_TG3_AUXCTL_ACTL_TX_6DB; - tg3_writephy(tp, MII_TG3_AUX_CTRL, phy); + TG3_PHY_AUXCTL_SMDSP_DISABLE(tp); } static void tg3_phy_eee_adjust(struct tg3 *tp, u32 current_link_up) @@ -1804,18 +1807,11 @@ static void tg3_phy_eee_adjust(struct tg3 *tp, u32 current_link_up) case ASIC_REV_5717: case ASIC_REV_5719: case ASIC_REV_57765: - /* Enable SM_DSP clock and tx 6dB coding. */ - val = MII_TG3_AUXCTL_SHDWSEL_AUXCTL | - MII_TG3_AUXCTL_ACTL_SMDSP_ENA | - MII_TG3_AUXCTL_ACTL_TX_6DB; - tg3_writephy(tp, MII_TG3_AUX_CTRL, val); - - tg3_phydsp_write(tp, MII_TG3_DSP_TAP26, 0x0000); - - /* Turn off SM_DSP clock. */ - val = MII_TG3_AUXCTL_SHDWSEL_AUXCTL | - MII_TG3_AUXCTL_ACTL_TX_6DB; - tg3_writephy(tp, MII_TG3_AUX_CTRL, val); + if (!TG3_PHY_AUXCTL_SMDSP_ENABLE(tp)) { + tg3_phydsp_write(tp, MII_TG3_DSP_TAP26, + 0x0000); + TG3_PHY_AUXCTL_SMDSP_DISABLE(tp); + } } /* Fallthrough */ case TG3_CL45_D7_EEERES_STAT_LP_100TX: @@ -1967,8 +1963,9 @@ static int tg3_phy_reset_5703_4_5(struct tg3 *tp) (MII_TG3_CTRL_AS_MASTER | MII_TG3_CTRL_ENABLE_AS_MASTER)); - /* Enable SM_DSP_CLOCK and 6dB. */ - tg3_writephy(tp, MII_TG3_AUX_CTRL, 0x0c00); + err = TG3_PHY_AUXCTL_SMDSP_ENABLE(tp); + if (err) + return err; /* Block the PHY control access. */ tg3_phydsp_write(tp, 0x8005, 0x0800); @@ -1987,13 +1984,7 @@ static int tg3_phy_reset_5703_4_5(struct tg3 *tp) tg3_writephy(tp, MII_TG3_DSP_ADDRESS, 0x8200); tg3_writephy(tp, MII_TG3_DSP_CONTROL, 0x0000); - if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5703 || - GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5704) { - /* Set Extended packet length bit for jumbo frames */ - tg3_writephy(tp, MII_TG3_AUX_CTRL, 0x4400); - } else { - tg3_writephy(tp, MII_TG3_AUX_CTRL, 0x0400); - } + TG3_PHY_AUXCTL_SMDSP_DISABLE(tp); tg3_writephy(tp, MII_TG3_CTRL, phy9_orig); @@ -2081,33 +2072,39 @@ static int tg3_phy_reset(struct tg3 *tp) tg3_phy_toggle_apd(tp, false); out: - if (tp->phy_flags & TG3_PHYFLG_ADC_BUG) { - tg3_writephy(tp, MII_TG3_AUX_CTRL, 0x0c00); + if ((tp->phy_flags & TG3_PHYFLG_ADC_BUG) && + !TG3_PHY_AUXCTL_SMDSP_ENABLE(tp)) { tg3_phydsp_write(tp, 0x201f, 0x2aaa); tg3_phydsp_write(tp, 0x000a, 0x0323); - tg3_writephy(tp, MII_TG3_AUX_CTRL, 0x0400); + TG3_PHY_AUXCTL_SMDSP_DISABLE(tp); } + if (tp->phy_flags & TG3_PHYFLG_5704_A0_BUG) { tg3_writephy(tp, MII_TG3_MISC_SHDW, 0x8d68); tg3_writephy(tp, MII_TG3_MISC_SHDW, 0x8d68); } + if (tp->phy_flags & TG3_PHYFLG_BER_BUG) { - tg3_writephy(tp, MII_TG3_AUX_CTRL, 0x0c00); - tg3_phydsp_write(tp, 0x000a, 0x310b); - tg3_phydsp_write(tp, 0x201f, 0x9506); - tg3_phydsp_write(tp, 0x401f, 0x14e2); - tg3_writephy(tp, MII_TG3_AUX_CTRL, 0x0400); + if (!TG3_PHY_AUXCTL_SMDSP_ENABLE(tp)) { + tg3_phydsp_write(tp, 0x000a, 0x310b); + tg3_phydsp_write(tp, 0x201f, 0x9506); + tg3_phydsp_write(tp, 0x401f, 0x14e2); + TG3_PHY_AUXCTL_SMDSP_DISABLE(tp); + } } else if (tp->phy_flags & TG3_PHYFLG_JITTER_BUG) { - tg3_writephy(tp, MII_TG3_AUX_CTRL, 0x0c00); - tg3_writephy(tp, MII_TG3_DSP_ADDRESS, 0x000a); - if (tp->phy_flags & TG3_PHYFLG_ADJUST_TRIM) { - tg3_writephy(tp, MII_TG3_DSP_RW_PORT, 0x110b); - tg3_writephy(tp, MII_TG3_TEST1, - MII_TG3_TEST1_TRIM_EN | 0x4); - } else - tg3_writephy(tp, MII_TG3_DSP_RW_PORT, 0x010b); - tg3_writephy(tp, MII_TG3_AUX_CTRL, 0x0400); + if (!TG3_PHY_AUXCTL_SMDSP_ENABLE(tp)) { + tg3_writephy(tp, MII_TG3_DSP_ADDRESS, 0x000a); + if (tp->phy_flags & TG3_PHYFLG_ADJUST_TRIM) { + tg3_writephy(tp, MII_TG3_DSP_RW_PORT, 0x110b); + tg3_writephy(tp, MII_TG3_TEST1, + MII_TG3_TEST1_TRIM_EN | 0x4); + } else + tg3_writephy(tp, MII_TG3_DSP_RW_PORT, 0x010b); + + TG3_PHY_AUXCTL_SMDSP_DISABLE(tp); + } } + /* Set Extended packet length bit (bit 14) on all chips that */ /* support jumbo frames */ if ((tp->phy_id & TG3_PHY_ID_MASK) == TG3_PHY_ID_BCM5401) { @@ -3011,11 +3008,7 @@ static void tg3_phy_copper_begin(struct tg3 *tp) tw32(TG3_CPMU_EEE_MODE, tr32(TG3_CPMU_EEE_MODE) & ~TG3_CPMU_EEEMD_LPI_ENABLE); - /* Enable SM_DSP clock and tx 6dB coding. */ - val = MII_TG3_AUXCTL_SHDWSEL_AUXCTL | - MII_TG3_AUXCTL_ACTL_SMDSP_ENA | - MII_TG3_AUXCTL_ACTL_TX_6DB; - tg3_writephy(tp, MII_TG3_AUX_CTRL, val); + TG3_PHY_AUXCTL_SMDSP_ENABLE(tp); switch (GET_ASIC_REV(tp->pci_chip_rev_id)) { case ASIC_REV_5717: @@ -3044,10 +3037,7 @@ static void tg3_phy_copper_begin(struct tg3 *tp) } tg3_phy_cl45_write(tp, MDIO_MMD_AN, MDIO_AN_EEE_ADV, val); - /* Turn off SM_DSP clock. */ - val = MII_TG3_AUXCTL_SHDWSEL_AUXCTL | - MII_TG3_AUXCTL_ACTL_TX_6DB; - tg3_writephy(tp, MII_TG3_AUX_CTRL, val); + TG3_PHY_AUXCTL_SMDSP_DISABLE(tp); } if (tp->link_config.autoneg == AUTONEG_DISABLE && -- cgit v0.10.2 From 470078312515f12e7cd916f1bd002acad313b9c8 Mon Sep 17 00:00:00 2001 From: Matt Carlson Date: Wed, 20 Apr 2011 07:57:43 +0000 Subject: tg3: Add additional EEE messaging This patch adds link messages and an item to the sign-on banner to make EEE status more visible. Signed-off-by: Matt Carlson Reviewed-by: Michael Chan Signed-off-by: David S. Miller diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index 9ed6bfb..693f36e 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -1360,6 +1360,11 @@ static void tg3_link_report(struct tg3 *tp) "on" : "off", (tp->link_config.active_flowctrl & FLOW_CTRL_RX) ? "on" : "off"); + + if (tp->phy_flags & TG3_PHYFLG_EEE_CAP) + netdev_info(tp->dev, "EEE is %s\n", + tp->setlpicnt ? "enabled" : "disabled"); + tg3_ump_link_report(tp); } } @@ -15278,8 +15283,10 @@ static int __devinit tg3_init_one(struct pci_dev *pdev, ethtype = "10/100/1000Base-T"; netdev_info(dev, "attached PHY is %s (%s Ethernet) " - "(WireSpeed[%d])\n", tg3_phy_string(tp), ethtype, - (tp->phy_flags & TG3_PHYFLG_NO_ETH_WIRE_SPEED) == 0); + "(WireSpeed[%d], EEE[%d])\n", + tg3_phy_string(tp), ethtype, + (tp->phy_flags & TG3_PHYFLG_NO_ETH_WIRE_SPEED) == 0, + (tp->phy_flags & TG3_PHYFLG_EEE_CAP) != 0); } netdev_info(dev, "RXcsums[%d] LinkChgREG[%d] MIirq[%d] ASF[%d] TSOcap[%d]\n", -- cgit v0.10.2 From 5f8629c526b4f7e529a6d27bbd802c0dc7fcc357 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Miros=C5=82aw?= Date: Thu, 21 Apr 2011 13:59:21 +0000 Subject: net: fix hw_features ethtool_ops->set_flags compatibility MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit __ethtool_set_flags() was not taking into account features set but not user-toggleable. Since GFLAGS returns masked dev->features, EINVAL is returned when passed flags differ to it, and not to wanted_features. Signed-off-by: MichaÅ‚ MirosÅ‚aw Signed-off-by: David S. Miller diff --git a/net/core/ethtool.c b/net/core/ethtool.c index 13d79f5..d8b1a8d 100644 --- a/net/core/ethtool.c +++ b/net/core/ethtool.c @@ -546,12 +546,12 @@ int __ethtool_set_flags(struct net_device *dev, u32 data) } /* allow changing only bits set in hw_features */ - changed = (data ^ dev->wanted_features) & flags_dup_features; + changed = (data ^ dev->features) & flags_dup_features; if (changed & ~dev->hw_features) return (changed & dev->hw_features) ? -EINVAL : -EOPNOTSUPP; dev->wanted_features = - (dev->wanted_features & ~changed) | data; + (dev->wanted_features & ~changed) | (data & dev->hw_features); __netdev_update_features(dev); -- cgit v0.10.2 From e965c05dabdabb85af0187952ccd75e43995c4b3 Mon Sep 17 00:00:00 2001 From: Thomas Egerer Date: Wed, 20 Apr 2011 22:56:02 +0000 Subject: ipv6: Remove hoplimit initialization to -1 The changes introduced with git-commit a02e4b7d ("ipv6: Demark default hoplimit as zero.") missed to remove the hoplimit initialization. As a result, ipv6_get_mtu interprets the return value of dst_metric_raw (-1) as 255 and answers ping6 with this hoplimit. This patche removes the line such that ping6 is answered with the hoplimit value configured via sysctl. Signed-off-by: Thomas Egerer Signed-off-by: David S. Miller diff --git a/net/ipv6/route.c b/net/ipv6/route.c index 843406f..0a5d02a 100644 --- a/net/ipv6/route.c +++ b/net/ipv6/route.c @@ -2012,7 +2012,6 @@ struct rt6_info *addrconf_dst_alloc(struct inet6_dev *idev, rt->dst.output = ip6_output; rt->rt6i_dev = net->loopback_dev; rt->rt6i_idev = idev; - dst_metric_set(&rt->dst, RTAX_HOPLIMIT, -1); rt->dst.obsolete = -1; rt->rt6i_flags = RTF_UP | RTF_NONEXTHOP; -- cgit v0.10.2 From e74fbd030223e29d269f4be17e3dce6de38f4c28 Mon Sep 17 00:00:00 2001 From: Ivan Vecera Date: Thu, 21 Apr 2011 00:20:04 +0000 Subject: be2net: increment work_counter in be_worker The commit 609ff3b ("be2net: add code to display temperature of ASIC") adds support to display temperature of ASIC but there is missing increment of work_counter in be_worker. Because of this 1) the function be_cmd_get_die_temperature is called every 1 second instead of every 32 seconds 2) be_cmd_get_die_temperature is called, although it is not supported. This patch fixes this bug. Signed-off-by: Ivan Vecera Signed-off-by: David S. Miller diff --git a/drivers/net/benet/be_main.c b/drivers/net/benet/be_main.c index 7cb5a11..02a0443 100644 --- a/drivers/net/benet/be_main.c +++ b/drivers/net/benet/be_main.c @@ -1873,6 +1873,7 @@ static void be_worker(struct work_struct *work) be_detect_dump_ue(adapter); reschedule: + adapter->work_counter++; schedule_delayed_work(&adapter->work, msecs_to_jiffies(1000)); } -- cgit v0.10.2 From cb771838715b1c470bc5735bdae709b33b18e0ad Mon Sep 17 00:00:00 2001 From: Tim Gardner Date: Wed, 20 Apr 2011 09:00:49 +0000 Subject: atl1c: Fix work event interrupt/task races The mechanism used to initiate work events from the interrupt handler has a classic read/modify/write race between the interrupt handler that sets the condition, and the worker task that reads and clears the condition. Close these races by using atomic bit fields. Cc: stable@kernel.org Cc: Jie Yang Signed-off-by: Tim Gardner Signed-off-by: David S. Miller diff --git a/drivers/net/atl1c/atl1c.h b/drivers/net/atl1c/atl1c.h index 7cb375e..925929d 100644 --- a/drivers/net/atl1c/atl1c.h +++ b/drivers/net/atl1c/atl1c.h @@ -566,9 +566,9 @@ struct atl1c_adapter { #define __AT_TESTING 0x0001 #define __AT_RESETTING 0x0002 #define __AT_DOWN 0x0003 - u8 work_event; -#define ATL1C_WORK_EVENT_RESET 0x01 -#define ATL1C_WORK_EVENT_LINK_CHANGE 0x02 + unsigned long work_event; +#define ATL1C_WORK_EVENT_RESET 0 +#define ATL1C_WORK_EVENT_LINK_CHANGE 1 u32 msg_enable; bool have_msi; diff --git a/drivers/net/atl1c/atl1c_main.c b/drivers/net/atl1c/atl1c_main.c index 7d9d506..a6e1c36 100644 --- a/drivers/net/atl1c/atl1c_main.c +++ b/drivers/net/atl1c/atl1c_main.c @@ -325,7 +325,7 @@ static void atl1c_link_chg_event(struct atl1c_adapter *adapter) } } - adapter->work_event |= ATL1C_WORK_EVENT_LINK_CHANGE; + set_bit(ATL1C_WORK_EVENT_LINK_CHANGE, &adapter->work_event); schedule_work(&adapter->common_task); } @@ -337,20 +337,16 @@ static void atl1c_common_task(struct work_struct *work) adapter = container_of(work, struct atl1c_adapter, common_task); netdev = adapter->netdev; - if (adapter->work_event & ATL1C_WORK_EVENT_RESET) { - adapter->work_event &= ~ATL1C_WORK_EVENT_RESET; + if (test_and_clear_bit(ATL1C_WORK_EVENT_RESET, &adapter->work_event)) { netif_device_detach(netdev); atl1c_down(adapter); atl1c_up(adapter); netif_device_attach(netdev); - return; } - if (adapter->work_event & ATL1C_WORK_EVENT_LINK_CHANGE) { - adapter->work_event &= ~ATL1C_WORK_EVENT_LINK_CHANGE; + if (test_and_clear_bit(ATL1C_WORK_EVENT_LINK_CHANGE, + &adapter->work_event)) atl1c_check_link_status(adapter); - } - return; } @@ -369,7 +365,7 @@ static void atl1c_tx_timeout(struct net_device *netdev) struct atl1c_adapter *adapter = netdev_priv(netdev); /* Do the reset outside of interrupt context */ - adapter->work_event |= ATL1C_WORK_EVENT_RESET; + set_bit(ATL1C_WORK_EVENT_RESET, &adapter->work_event); schedule_work(&adapter->common_task); } -- cgit v0.10.2 From f01cb5fbea1c1613621f9f32f385e12c1a29dde0 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Thu, 21 Apr 2011 21:17:25 -0700 Subject: Revert "bridge: Forward reserved group addresses if !STP" This reverts commit 1e253c3b8a1aeed51eef6fc366812f219b97de65. It breaks 802.3ad bonding inside of a bridge. The commit was meant to support transport bridging, and specifically virtual machines bridged to an ethernet interface connected to a switch port wiht 802.1x enabled. But this isn't the way to do it, it breaks too many other things. Signed-off-by: David S. Miller diff --git a/net/bridge/br_input.c b/net/bridge/br_input.c index e216079..0c7bada 100644 --- a/net/bridge/br_input.c +++ b/net/bridge/br_input.c @@ -164,7 +164,7 @@ rx_handler_result_t br_handle_frame(struct sk_buff **pskb) goto drop; /* If STP is turned off, then forward */ - if (p->br->stp_enabled == BR_NO_STP) + if (p->br->stp_enabled == BR_NO_STP && dest[5] == 0) goto forward; if (NF_HOOK(NFPROTO_BRIDGE, NF_BR_LOCAL_IN, skb, skb->dev, -- cgit v0.10.2 From b2508e828d71baacd9a743dd48dcbf85d96affdd Mon Sep 17 00:00:00 2001 From: Andi Kleen Date: Thu, 21 Apr 2011 16:48:35 -0700 Subject: perf: Support Xeon E7's via the Westmere PMU driver There's a new model number public, 47, for Xeon E7 (aka Westmere EX). Signed-off-by: Andi Kleen Cc: a.p.zijlstra@chello.nl Link: http://lkml.kernel.org/r/1303429715-10202-1-git-send-email-andi@firstfloor.org Signed-off-by: Ingo Molnar diff --git a/arch/x86/kernel/cpu/perf_event_intel.c b/arch/x86/kernel/cpu/perf_event_intel.c index 8fc2b2c..586cced 100644 --- a/arch/x86/kernel/cpu/perf_event_intel.c +++ b/arch/x86/kernel/cpu/perf_event_intel.c @@ -1425,6 +1425,7 @@ static __init int intel_pmu_init(void) case 37: /* 32 nm nehalem, "Clarkdale" */ case 44: /* 32 nm nehalem, "Gulftown" */ + case 47: /* 32 nm Xeon E7 */ memcpy(hw_cache_event_ids, westmere_hw_cache_event_ids, sizeof(hw_cache_event_ids)); memcpy(hw_cache_extra_regs, nehalem_hw_cache_extra_regs, -- cgit v0.10.2 From b52c55c6a25e4515b5e075a989ff346fc251ed09 Mon Sep 17 00:00:00 2001 From: Ingo Molnar Date: Fri, 22 Apr 2011 08:44:38 +0200 Subject: x86, perf event: Turn off unstructured raw event access to offcore registers Andi Kleen pointed out that the Intel offcore support patches were merged without user-space tool support to the functionality: | | The offcore_msr perf kernel code was merged into 2.6.39-rc*, but the | user space bits were not. This made it impossible to set the extra mask | and actually do the OFFCORE profiling | Andi submitted a preliminary patch for user-space support, as an extension to perf's raw event syntax: | | Some raw events -- like the Intel OFFCORE events -- support additional | parameters. These can be appended after a ':'. | | For example on a multi socket Intel Nehalem: | | perf stat -e r1b7:20ff -a sleep 1 | | Profile the OFFCORE_RESPONSE.ANY_REQUEST with event mask REMOTE_DRAM_0 | that measures any access to DRAM on another socket. | But this kind of usability is absolutely unacceptable - users should not be expected to type in magic, CPU and model specific incantations to get access to useful hardware functionality. The proper solution is to expose useful offcore functionality via generalized events - that way users do not have to care which specific CPU model they are using, they can use the conceptual event and not some model specific quirky hexa number. We already have such generalization in place for CPU cache events, and it's all very extensible. "Offcore" events measure general DRAM access patters along various parameters. They are particularly useful in NUMA systems. We want to support them via generalized DRAM events: either as the fourth level of cache (after the last-level cache), or as a separate generalization category. That way user-space support would be very obvious, memory access profiling could be done via self-explanatory commands like: perf record -e dram ./myapp perf record -e dram-remote ./myapp ... to measure DRAM accesses or more expensive cross-node NUMA DRAM accesses. These generalized events would work on all CPUs and architectures that have comparable PMU features. ( Note, these are just examples: actual implementation could have more sophistication and more parameter - as long as they center around similarly simple usecases. ) Now we do not want to revert *all* of the current offcore bits, as they are still somewhat useful for generic last-level-cache events, implemented in this commit: e994d7d23a0b: perf: Fix LLC-* events on Intel Nehalem/Westmere But we definitely do not yet want to expose the unstructured raw events to user-space, until better generalization and usability is implemented for these hardware event features. ( Note: after generalization has been implemented raw offcore events can be supported as well: there can always be an odd event that is marginally useful but not useful enough to generalize. DRAM profiling is definitely *not* such a category so generalization must be done first. ) Furthermore, PERF_TYPE_RAW access to these registers was not intended to go upstream without proper support - it was a side-effect of the above e994d7d23a0b commit, not mentioned in the changelog. As v2.6.39 is nearing release we go for the simplest approach: disable the PERF_TYPE_RAW offcore hack for now, before it escapes into a released kernel and becomes an ABI. Once proper structure is implemented for these hardware events and users are offered usable solutions we can revisit this issue. Reported-by: Andi Kleen Acked-by: Peter Zijlstra Cc: Arnaldo Carvalho de Melo Cc: Frederic Weisbecker Cc: Thomas Gleixner Cc: Linus Torvalds Link: http://lkml.kernel.org/r/1302658203-4239-1-git-send-email-andi@firstfloor.org Signed-off-by: Ingo Molnar diff --git a/arch/x86/kernel/cpu/perf_event.c b/arch/x86/kernel/cpu/perf_event.c index eed3673a..632e5dc 100644 --- a/arch/x86/kernel/cpu/perf_event.c +++ b/arch/x86/kernel/cpu/perf_event.c @@ -586,8 +586,12 @@ static int x86_setup_perfctr(struct perf_event *event) return -EOPNOTSUPP; } + /* + * Do not allow config1 (extended registers) to propagate, + * there's no sane user-space generalization yet: + */ if (attr->type == PERF_TYPE_RAW) - return x86_pmu_extra_regs(event->attr.config, event); + return 0; if (attr->type == PERF_TYPE_HW_CACHE) return set_ext_hw_attr(hwc, event); -- cgit v0.10.2 From 103b3934817a7c42fba6e1ef76ecb390a2837d40 Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Thu, 21 Apr 2011 11:03:20 -0400 Subject: perf, x86: P4 PMU -- Use perf_sample_data_init helper Instead of opencoded assignments better to use perf_sample_data_init helper. Tested-by: Lin Ming Signed-off-by: Cyrill Gorcunov Signed-off-by: Don Zickus Cc: Cyrill Gorcunov Link: http://lkml.kernel.org/r/1303398203-2918-2-git-send-email-dzickus@redhat.com Signed-off-by: Ingo Molnar diff --git a/arch/x86/kernel/cpu/perf_event_p4.c b/arch/x86/kernel/cpu/perf_event_p4.c index 8ff882f..ae31e96 100644 --- a/arch/x86/kernel/cpu/perf_event_p4.c +++ b/arch/x86/kernel/cpu/perf_event_p4.c @@ -912,8 +912,7 @@ static int p4_pmu_handle_irq(struct pt_regs *regs) int idx, handled = 0; u64 val; - data.addr = 0; - data.raw = NULL; + perf_sample_data_init(&data, 0); cpuc = &__get_cpu_var(cpu_hw_events); -- cgit v0.10.2 From 1ea5a6afd95a4803900c97ed63a47a883ebe7b3e Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Thu, 21 Apr 2011 11:03:21 -0400 Subject: perf, x86: P4 PMU - Don't forget to clear cpuc->active_mask on overflow It's not enough to simply disable event on overflow the cpuc->active_mask should be cleared as well otherwise counter may stall in "active" even in real being already disabled (which potentially may lead to the situation that user may not use this counter further). Don pointed out that: " I also noticed this patch fixed some unknown NMIs on a P4 when I stressed the box". Tested-by: Lin Ming Signed-off-by: Cyrill Gorcunov Acked-by: Don Zickus Signed-off-by: Don Zickus Cc: Cyrill Gorcunov Link: http://lkml.kernel.org/r/1303398203-2918-3-git-send-email-dzickus@redhat.com Signed-off-by: Ingo Molnar diff --git a/arch/x86/kernel/cpu/perf_event_p4.c b/arch/x86/kernel/cpu/perf_event_p4.c index c2520e1..d1f77e2 100644 --- a/arch/x86/kernel/cpu/perf_event_p4.c +++ b/arch/x86/kernel/cpu/perf_event_p4.c @@ -947,7 +947,7 @@ static int p4_pmu_handle_irq(struct pt_regs *regs) if (!x86_perf_event_set_period(event)) continue; if (perf_event_overflow(event, 1, &data, regs)) - p4_pmu_disable_event(event); + x86_pmu_stop(event, 0); } if (handled) { -- cgit v0.10.2 From 3003eba313dd0e0502dd71548c36fe7c19801ce5 Mon Sep 17 00:00:00 2001 From: Steven Rostedt Date: Wed, 20 Apr 2011 21:41:54 -0400 Subject: lockdep: Print a nicer description for irq lock inversions Locking order inversion due to interrupts is a subtle problem. When an irq lockiinversion discovered by lockdep it currently reports something like: [ INFO: HARDIRQ-safe -> HARDIRQ-unsafe lock order detected ] ... and then prints out the locks that are involved, as back traces. Judging by lkml feedback developers were routinely confused by what a HARDIRQ->safe to unsafe issue is all about, and sometimes even blew it off as a bug in lockdep. It is not obvious when lockdep prints this message about a lock that is never taken in interrupt context. After explaining the problems that lockdep is reporting, I decided to add a description of the problem in visual form. Now the following is shown: --- other info that might help us debug this: Possible interrupt unsafe locking scenario: CPU0 CPU1 ---- ---- lock(lockA); local_irq_disable(); lock(&rq->lock); lock(lockA); lock(&rq->lock); *** DEADLOCK *** --- The above is the case when the unsafe lock is taken while holding a lock taken in irq context. But when a lock is taken that also grabs a unsafe lock, the call chain is shown: --- other info that might help us debug this: Chain exists of: &rq->lock --> lockA --> lockC Possible interrupt unsafe locking scenario: CPU0 CPU1 ---- ---- lock(lockC); local_irq_disable(); lock(&rq->lock); lock(lockA); lock(&rq->lock); *** DEADLOCK *** Signed-off-by: Steven Rostedt Acked-by: Peter Zijlstra Cc: Frederic Weisbecker Cc: Linus Torvalds Cc: Andrew Morton Link: http://lkml.kernel.org/r/20110421014259.132728798@goodmis.org Signed-off-by: Ingo Molnar diff --git a/kernel/lockdep.c b/kernel/lockdep.c index 53a6895..7b2ffee 100644 --- a/kernel/lockdep.c +++ b/kernel/lockdep.c @@ -490,6 +490,18 @@ void get_usage_chars(struct lock_class *class, char usage[LOCK_USAGE_CHARS]) usage[i] = '\0'; } +static int __print_lock_name(struct lock_class *class) +{ + char str[KSYM_NAME_LEN]; + const char *name; + + name = class->name; + if (!name) + name = __get_key_name(class->key, str); + + return printk("%s", name); +} + static void print_lock_name(struct lock_class *class) { char str[KSYM_NAME_LEN], usage[LOCK_USAGE_CHARS]; @@ -1325,6 +1337,62 @@ print_shortest_lock_dependencies(struct lock_list *leaf, return; } +static void +print_irq_lock_scenario(struct lock_list *safe_entry, + struct lock_list *unsafe_entry, + struct held_lock *prev, + struct held_lock *next) +{ + struct lock_class *safe_class = safe_entry->class; + struct lock_class *unsafe_class = unsafe_entry->class; + struct lock_class *middle_class = hlock_class(prev); + + if (middle_class == safe_class) + middle_class = hlock_class(next); + + /* + * A direct locking problem where unsafe_class lock is taken + * directly by safe_class lock, then all we need to show + * is the deadlock scenario, as it is obvious that the + * unsafe lock is taken under the safe lock. + * + * But if there is a chain instead, where the safe lock takes + * an intermediate lock (middle_class) where this lock is + * not the same as the safe lock, then the lock chain is + * used to describe the problem. Otherwise we would need + * to show a different CPU case for each link in the chain + * from the safe_class lock to the unsafe_class lock. + */ + if (middle_class != unsafe_class) { + printk("Chain exists of:\n "); + __print_lock_name(safe_class); + printk(" --> "); + __print_lock_name(middle_class); + printk(" --> "); + __print_lock_name(unsafe_class); + printk("\n\n"); + } + + printk(" Possible interrupt unsafe locking scenario:\n\n"); + printk(" CPU0 CPU1\n"); + printk(" ---- ----\n"); + printk(" lock("); + __print_lock_name(unsafe_class); + printk(");\n"); + printk(" local_irq_disable();\n"); + printk(" lock("); + __print_lock_name(safe_class); + printk(");\n"); + printk(" lock("); + __print_lock_name(middle_class); + printk(");\n"); + printk(" \n"); + printk(" lock("); + __print_lock_name(safe_class); + printk(");\n"); + printk("\n *** DEADLOCK ***\n\n"); +} + static int print_bad_irq_dependency(struct task_struct *curr, struct lock_list *prev_root, @@ -1376,6 +1444,8 @@ print_bad_irq_dependency(struct task_struct *curr, print_stack_trace(forwards_entry->class->usage_traces + bit2, 1); printk("\nother info that might help us debug this:\n\n"); + print_irq_lock_scenario(backwards_entry, forwards_entry, prev, next); + lockdep_print_held_locks(curr); printk("\nthe dependencies between %s-irq-safe lock", irqclass); -- cgit v0.10.2 From f4185812aa046ecb97e8817e10148cacdd7a6baa Mon Sep 17 00:00:00 2001 From: Steven Rostedt Date: Wed, 20 Apr 2011 21:41:55 -0400 Subject: lockdep: Print a nicer description for normal deadlocks The lockdep output can be pretty cryptic, having nicer output can save a lot of head scratching. When a normal deadlock scenario is detected by lockdep (lock A -> lock B and there exists a place where lock B -> lock A) we now get the following new output: other info that might help us debug this: Possible unsafe locking scenario: CPU0 CPU1 ---- ---- lock(lockB); lock(lockA); lock(lockB); lock(lockA); *** DEADLOCK *** On cases where there's a deeper chair, it shows the partial chain that can cause the issue: Chain exists of: lockC --> lockA --> lockB Possible unsafe locking scenario: CPU0 CPU1 ---- ---- lock(lockB); lock(lockA); lock(lockB); lock(lockC); *** DEADLOCK *** Signed-off-by: Steven Rostedt Acked-by: Peter Zijlstra Cc: Frederic Weisbecker Cc: Linus Torvalds Cc: Andrew Morton Link: http://lkml.kernel.org/r/20110421014259.380621789@goodmis.org Signed-off-by: Ingo Molnar diff --git a/kernel/lockdep.c b/kernel/lockdep.c index 7b2ffee..73cebd7 100644 --- a/kernel/lockdep.c +++ b/kernel/lockdep.c @@ -1065,6 +1065,56 @@ print_circular_bug_entry(struct lock_list *target, int depth) return 0; } +static void +print_circular_lock_scenario(struct held_lock *src, + struct held_lock *tgt, + struct lock_list *prt) +{ + struct lock_class *source = hlock_class(src); + struct lock_class *target = hlock_class(tgt); + struct lock_class *parent = prt->class; + + /* + * A direct locking problem where unsafe_class lock is taken + * directly by safe_class lock, then all we need to show + * is the deadlock scenario, as it is obvious that the + * unsafe lock is taken under the safe lock. + * + * But if there is a chain instead, where the safe lock takes + * an intermediate lock (middle_class) where this lock is + * not the same as the safe lock, then the lock chain is + * used to describe the problem. Otherwise we would need + * to show a different CPU case for each link in the chain + * from the safe_class lock to the unsafe_class lock. + */ + if (parent != source) { + printk("Chain exists of:\n "); + __print_lock_name(source); + printk(" --> "); + __print_lock_name(parent); + printk(" --> "); + __print_lock_name(target); + printk("\n\n"); + } + + printk(" Possible unsafe locking scenario:\n\n"); + printk(" CPU0 CPU1\n"); + printk(" ---- ----\n"); + printk(" lock("); + __print_lock_name(target); + printk(");\n"); + printk(" lock("); + __print_lock_name(parent); + printk(");\n"); + printk(" lock("); + __print_lock_name(target); + printk(");\n"); + printk(" lock("); + __print_lock_name(source); + printk(");\n"); + printk("\n *** DEADLOCK ***\n\n"); +} + /* * When a circular dependency is detected, print the * header first: @@ -1108,6 +1158,7 @@ static noinline int print_circular_bug(struct lock_list *this, { struct task_struct *curr = current; struct lock_list *parent; + struct lock_list *first_parent; int depth; if (!debug_locks_off_graph_unlock() || debug_locks_silent) @@ -1121,6 +1172,7 @@ static noinline int print_circular_bug(struct lock_list *this, print_circular_bug_header(target, depth, check_src, check_tgt); parent = get_lock_parent(target); + first_parent = parent; while (parent) { print_circular_bug_entry(parent, --depth); @@ -1128,6 +1180,9 @@ static noinline int print_circular_bug(struct lock_list *this, } printk("\nother info that might help us debug this:\n\n"); + print_circular_lock_scenario(check_src, check_tgt, + first_parent); + lockdep_print_held_locks(curr); printk("\nstack backtrace:\n"); -- cgit v0.10.2 From 48702ecf308e53f176c1f6fdc193d622ded54ac0 Mon Sep 17 00:00:00 2001 From: Steven Rostedt Date: Wed, 20 Apr 2011 21:41:56 -0400 Subject: lockdep: Print a nicer description for simple deadlocks Lockdep output can be pretty cryptic, having nicer output can save a lot of head scratching. When a simple deadlock scenario is detected by lockdep (lock A -> lock A) we now get the following new output: other info that might help us debug this: Possible unsafe locking scenario: CPU0 ---- lock(&(lock)->rlock); lock(&(lock)->rlock); *** DEADLOCK *** Signed-off-by: Steven Rostedt Acked-by: Peter Zijlstra Cc: Frederic Weisbecker Cc: Linus Torvalds Cc: Andrew Morton Link: http://lkml.kernel.org/r/20110421014259.643930104@goodmis.org Signed-off-by: Ingo Molnar diff --git a/kernel/lockdep.c b/kernel/lockdep.c index 73cebd7..c4cc5d1 100644 --- a/kernel/lockdep.c +++ b/kernel/lockdep.c @@ -1664,6 +1664,26 @@ static inline void inc_chains(void) #endif +static void +print_deadlock_scenario(struct held_lock *nxt, + struct held_lock *prv) +{ + struct lock_class *next = hlock_class(nxt); + struct lock_class *prev = hlock_class(prv); + + printk(" Possible unsafe locking scenario:\n\n"); + printk(" CPU0\n"); + printk(" ----\n"); + printk(" lock("); + __print_lock_name(prev); + printk(");\n"); + printk(" lock("); + __print_lock_name(next); + printk(");\n"); + printk("\n *** DEADLOCK ***\n\n"); + printk(" May be due to missing lock nesting notation\n\n"); +} + static int print_deadlock_bug(struct task_struct *curr, struct held_lock *prev, struct held_lock *next) @@ -1682,6 +1702,7 @@ print_deadlock_bug(struct task_struct *curr, struct held_lock *prev, print_lock(prev); printk("\nother info that might help us debug this:\n"); + print_deadlock_scenario(next, prev); lockdep_print_held_locks(curr); printk("\nstack backtrace:\n"); -- cgit v0.10.2 From dad3d7435e1d8c254d6877dc06852dc00c5da812 Mon Sep 17 00:00:00 2001 From: Steven Rostedt Date: Wed, 20 Apr 2011 21:41:57 -0400 Subject: lockdep: Print a nicer description for irq inversion bugs Irq inversion and irq dependency bugs are only subtly different. The diffenerence lies where the interrupt occurred. For irq dependency: irq_disable lock(A) lock(B) unlock(B) unlock(A) irq_enable lock(B) unlock(B) lock(A) The interrupt comes in after it has been established that lock A can be held when taking an irq unsafe lock. Lockdep detects the problem when taking lock A in interrupt context. With the irq_inversion the irq happens before it is established and lockdep detects the problem with the taking of lock B: lock(A) irq_disable lock(A) lock(B) unlock(B) unlock(A) irq_enable lock(B) unlock(B) Since the problem with the locking logic for both of these issues is in actuality the same, they both should report the same scenario. This patch implements that and prints this: other info that might help us debug this: Chain exists of: &rq->lock --> lockA --> lockC Possible interrupt unsafe locking scenario: CPU0 CPU1 ---- ---- lock(lockC); local_irq_disable(); lock(&rq->lock); lock(lockA); lock(&rq->lock); *** DEADLOCK *** Signed-off-by: Steven Rostedt Acked-by: Peter Zijlstra Cc: Frederic Weisbecker Cc: Linus Torvalds Cc: Andrew Morton Link: http://lkml.kernel.org/r/20110421014259.910720381@goodmis.org Signed-off-by: Ingo Molnar diff --git a/kernel/lockdep.c b/kernel/lockdep.c index c4cc5d1..0b497dd 100644 --- a/kernel/lockdep.c +++ b/kernel/lockdep.c @@ -1395,15 +1395,15 @@ print_shortest_lock_dependencies(struct lock_list *leaf, static void print_irq_lock_scenario(struct lock_list *safe_entry, struct lock_list *unsafe_entry, - struct held_lock *prev, - struct held_lock *next) + struct lock_class *prev_class, + struct lock_class *next_class) { struct lock_class *safe_class = safe_entry->class; struct lock_class *unsafe_class = unsafe_entry->class; - struct lock_class *middle_class = hlock_class(prev); + struct lock_class *middle_class = prev_class; if (middle_class == safe_class) - middle_class = hlock_class(next); + middle_class = next_class; /* * A direct locking problem where unsafe_class lock is taken @@ -1499,7 +1499,8 @@ print_bad_irq_dependency(struct task_struct *curr, print_stack_trace(forwards_entry->class->usage_traces + bit2, 1); printk("\nother info that might help us debug this:\n\n"); - print_irq_lock_scenario(backwards_entry, forwards_entry, prev, next); + print_irq_lock_scenario(backwards_entry, forwards_entry, + hlock_class(prev), hlock_class(next)); lockdep_print_held_locks(curr); @@ -2219,6 +2220,10 @@ print_irq_inversion_bug(struct task_struct *curr, struct held_lock *this, int forwards, const char *irqclass) { + struct lock_list *entry = other; + struct lock_list *middle = NULL; + int depth; + if (!debug_locks_off_graph_unlock() || debug_locks_silent) return 0; @@ -2237,6 +2242,25 @@ print_irq_inversion_bug(struct task_struct *curr, printk("\n\nand interrupts could create inverse lock ordering between them.\n\n"); printk("\nother info that might help us debug this:\n"); + + /* Find a middle lock (if one exists) */ + depth = get_lock_depth(other); + do { + if (depth == 0 && (entry != root)) { + printk("lockdep:%s bad path found in chain graph\n", __func__); + break; + } + middle = entry; + entry = get_lock_parent(entry); + depth--; + } while (entry && entry != root && (depth >= 0)); + if (forwards) + print_irq_lock_scenario(root, other, + middle ? middle->class : root->class, other->class); + else + print_irq_lock_scenario(other, root, + middle ? middle->class : other->class, root->class); + lockdep_print_held_locks(curr); printk("\nthe shortest dependencies between 2nd lock and 1st lock:\n"); -- cgit v0.10.2 From 6be8c3935b914dfbc24b27c91c2b6d583645e61a Mon Sep 17 00:00:00 2001 From: Steven Rostedt Date: Wed, 20 Apr 2011 21:41:58 -0400 Subject: lockdep: Replace "Bad BFS generated tree" message with something less cryptic The message of "Bad BFS generated tree" is a bit confusing. Replace it with a more sane error message. Thanks to Peter Zijlstra for helping me come up with a better message. Signed-off-by: Steven Rostedt Acked-by: Peter Zijlstra Cc: Frederic Weisbecker Cc: Linus Torvalds Cc: Andrew Morton Link: http://lkml.kernel.org/r/20110421014300.135521252@goodmis.org Signed-off-by: Ingo Molnar diff --git a/kernel/lockdep.c b/kernel/lockdep.c index 0b497dd..270cfa4 100644 --- a/kernel/lockdep.c +++ b/kernel/lockdep.c @@ -1381,7 +1381,7 @@ print_shortest_lock_dependencies(struct lock_list *leaf, printk("\n"); if (depth == 0 && (entry != root)) { - printk("lockdep:%s bad BFS generated tree\n", __func__); + printk("lockdep:%s bad path found in chain graph\n", __func__); break; } -- cgit v0.10.2 From 282b5c2f6f663c008444321fd8fcdd374596046b Mon Sep 17 00:00:00 2001 From: Steven Rostedt Date: Wed, 20 Apr 2011 21:41:59 -0400 Subject: lockdep: Print a nicer description for simple irq lock inversions Lockdep output can be pretty cryptic, having nicer output can save a lot of head scratching. When a simple irq inversion scenario is detected by lockdep (lock A taken in interrupt context but also in thread context without disabling interrupts) we now get the following (hopefully more informative) output: other info that might help us debug this: Possible unsafe locking scenario: CPU0 ---- lock(lockA); lock(lockA); *** DEADLOCK *** Signed-off-by: Steven Rostedt Acked-by: Peter Zijlstra Cc: Frederic Weisbecker Cc: Linus Torvalds Cc: Andrew Morton Link: http://lkml.kernel.org/r/20110421014300.436140880@goodmis.org Signed-off-by: Ingo Molnar diff --git a/kernel/lockdep.c b/kernel/lockdep.c index 270cfa4..27c609f 100644 --- a/kernel/lockdep.c +++ b/kernel/lockdep.c @@ -2158,6 +2158,24 @@ static void check_chain_key(struct task_struct *curr) #endif } +static void +print_usage_bug_scenario(struct held_lock *lock) +{ + struct lock_class *class = hlock_class(lock); + + printk(" Possible unsafe locking scenario:\n\n"); + printk(" CPU0\n"); + printk(" ----\n"); + printk(" lock("); + __print_lock_name(class); + printk(");\n"); + printk(" \n"); + printk(" lock("); + __print_lock_name(class); + printk(");\n"); + printk("\n *** DEADLOCK ***\n\n"); +} + static int print_usage_bug(struct task_struct *curr, struct held_lock *this, enum lock_usage_bit prev_bit, enum lock_usage_bit new_bit) @@ -2186,6 +2204,8 @@ print_usage_bug(struct task_struct *curr, struct held_lock *this, print_irqtrace_events(curr); printk("\nother info that might help us debug this:\n"); + print_usage_bug_scenario(this); + lockdep_print_held_locks(curr); printk("\nstack backtrace:\n"); -- cgit v0.10.2 From e0944ee63f7249802be74454cef81c97630ae1cd Mon Sep 17 00:00:00 2001 From: Steven Rostedt Date: Wed, 20 Apr 2011 21:42:00 -0400 Subject: lockdep: Remove cmpxchg to update nr_chain_hlocks For some reason nr_chain_hlocks is updated with cmpxchg, but this is performed inside of the lockdep global "grab_lock()", which also makes simple modification of this variable atomic. Remove the cmpxchg logic for updating nr_chain_hlocks and simplify the code. Signed-off-by: Steven Rostedt Acked-by: Peter Zijlstra Cc: Frederic Weisbecker Cc: Linus Torvalds Cc: Andrew Morton Link: http://lkml.kernel.org/r/20110421014300.727863282@goodmis.org Signed-off-by: Ingo Molnar diff --git a/kernel/lockdep.c b/kernel/lockdep.c index 27c609f..63437d0 100644 --- a/kernel/lockdep.c +++ b/kernel/lockdep.c @@ -1973,7 +1973,7 @@ static inline int lookup_chain_cache(struct task_struct *curr, struct list_head *hash_head = chainhashentry(chain_key); struct lock_chain *chain; struct held_lock *hlock_curr, *hlock_next; - int i, j, n, cn; + int i, j; if (DEBUG_LOCKS_WARN_ON(!irqs_disabled())) return 0; @@ -2033,15 +2033,9 @@ cache_hit: } i++; chain->depth = curr->lockdep_depth + 1 - i; - cn = nr_chain_hlocks; - while (cn + chain->depth <= MAX_LOCKDEP_CHAIN_HLOCKS) { - n = cmpxchg(&nr_chain_hlocks, cn, cn + chain->depth); - if (n == cn) - break; - cn = n; - } - if (likely(cn + chain->depth <= MAX_LOCKDEP_CHAIN_HLOCKS)) { - chain->base = cn; + if (likely(nr_chain_hlocks + chain->depth <= MAX_LOCKDEP_CHAIN_HLOCKS)) { + chain->base = nr_chain_hlocks; + nr_chain_hlocks += chain->depth; for (j = 0; j < chain->depth - 1; j++, i++) { int lock_id = curr->held_locks[i].class_idx - 1; chain_hlocks[chain->base + j] = lock_id; -- cgit v0.10.2 From f4929bd37208540c2c6f416e9035ff1938f2dbc6 Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Fri, 22 Apr 2011 13:39:56 +0200 Subject: perf, x86: Update/fix Intel Nehalem cache events Change the Nehalem cache events to use retired memory instruction counters (similar to Westmere), this greatly improves the provided stats. Using: main () { int i; for (i = 0; i < 1000000000; i++) { asm("mov (%%rsp), %%rbx;" "mov %%rbx, (%%rsp);" : : : "rbx"); } } We find: $ perf stat --repeat 10 -e instructions:u -e l1-dcache-loads:u -e l1-dcache-stores:u ./loop_1b_loads+stores Performance counter stats for './loop_1b_loads+stores' (10 runs): 4,000,081,056 instructions:u # 0.000 IPC ( +- 0.000% ) 4,999,502,846 l1-dcache-loads:u ( +- 0.008% ) 1,000,034,832 l1-dcache-stores:u ( +- 0.000% ) 1.565184942 seconds time elapsed ( +- 0.005% ) The 5b is surprising - we'd expect 1b: $ perf stat --repeat 10 -e instructions:u -e r10b:u -e l1-dcache-stores:u ./loop_1b_loads+stores Performance counter stats for './loop_1b_loads+stores' (10 runs): 4,000,081,054 instructions:u # 0.000 IPC ( +- 0.000% ) 1,000,021,961 r10b:u ( +- 0.000% ) 1,000,030,951 l1-dcache-stores:u ( +- 0.000% ) 1.565055422 seconds time elapsed ( +- 0.003% ) Which this patch thus fixes. Signed-off-by: Peter Zijlstra Cc: Peter Zijlstra Cc: Arnaldo Carvalho de Melo Cc: Frederic Weisbecker Cc: Paul Mackerras Cc: Mike Galbraith Cc: Steven Rostedt Cc: Stephane Eranian Cc: Lin Ming Cc: Cyrill Gorcunov Link: http://lkml.kernel.org/n/tip-q9rtru7b7840tws75xzboapv@git.kernel.org Signed-off-by: Ingo Molnar diff --git a/arch/x86/kernel/cpu/perf_event_intel.c b/arch/x86/kernel/cpu/perf_event_intel.c index 586cced..43fa20b 100644 --- a/arch/x86/kernel/cpu/perf_event_intel.c +++ b/arch/x86/kernel/cpu/perf_event_intel.c @@ -391,12 +391,12 @@ static __initconst const u64 nehalem_hw_cache_event_ids { [ C(L1D) ] = { [ C(OP_READ) ] = { - [ C(RESULT_ACCESS) ] = 0x0f40, /* L1D_CACHE_LD.MESI */ - [ C(RESULT_MISS) ] = 0x0140, /* L1D_CACHE_LD.I_STATE */ + [ C(RESULT_ACCESS) ] = 0x010b, /* MEM_INST_RETIRED.LOADS */ + [ C(RESULT_MISS) ] = 0x0151, /* L1D.REPL */ }, [ C(OP_WRITE) ] = { - [ C(RESULT_ACCESS) ] = 0x0f41, /* L1D_CACHE_ST.MESI */ - [ C(RESULT_MISS) ] = 0x0141, /* L1D_CACHE_ST.I_STATE */ + [ C(RESULT_ACCESS) ] = 0x020b, /* MEM_INST_RETURED.STORES */ + [ C(RESULT_MISS) ] = 0x0251, /* L1D.M_REPL */ }, [ C(OP_PREFETCH) ] = { [ C(RESULT_ACCESS) ] = 0x014e, /* L1D_PREFETCH.REQUESTS */ -- cgit v0.10.2 From e46f6538c24f01bb68dc374358ce85a0af666682 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 13 Apr 2011 03:14:43 -0700 Subject: iwlagn: simplify error table reading The current code to read the error table header just hardcodes all the offsets, which is a bit hard to understand. We can read in the entire header (as much as we need) into a structure, and then take the data from there, which makes it easier to understand. To read a bigger blob we also don't need to grab NIC access for each word read, making the code more efficient. Signed-off-by: Johannes Berg Signed-off-by: Wey-Yi Guy diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index cdeb09e..f8559cc 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -1878,6 +1878,7 @@ void iwl_dump_nic_error_log(struct iwl_priv *priv) u32 desc, time, count, base, data1; u32 blink1, blink2, ilink1, ilink2; u32 pc, hcmd; + struct iwl_error_event_table table; base = priv->device_pointers.error_event_table; if (priv->ucode_type == UCODE_INIT) { @@ -1895,7 +1896,9 @@ void iwl_dump_nic_error_log(struct iwl_priv *priv) return; } - count = iwl_read_targ_mem(priv, base); + iwl_read_targ_mem_words(priv, base, &table, sizeof(table)); + + count = table.valid; if (ERROR_START_OFFSET <= count * ERROR_ELEM_SIZE) { IWL_ERR(priv, "Start IWL Error Log Dump:\n"); @@ -1903,18 +1906,18 @@ void iwl_dump_nic_error_log(struct iwl_priv *priv) priv->status, count); } - desc = iwl_read_targ_mem(priv, base + 1 * sizeof(u32)); + desc = table.error_id; priv->isr_stats.err_code = desc; - pc = iwl_read_targ_mem(priv, base + 2 * sizeof(u32)); - blink1 = iwl_read_targ_mem(priv, base + 3 * sizeof(u32)); - blink2 = iwl_read_targ_mem(priv, base + 4 * sizeof(u32)); - ilink1 = iwl_read_targ_mem(priv, base + 5 * sizeof(u32)); - ilink2 = iwl_read_targ_mem(priv, base + 6 * sizeof(u32)); - data1 = iwl_read_targ_mem(priv, base + 7 * sizeof(u32)); - data2 = iwl_read_targ_mem(priv, base + 8 * sizeof(u32)); - line = iwl_read_targ_mem(priv, base + 9 * sizeof(u32)); - time = iwl_read_targ_mem(priv, base + 11 * sizeof(u32)); - hcmd = iwl_read_targ_mem(priv, base + 22 * sizeof(u32)); + pc = table.pc; + blink1 = table.blink1; + blink2 = table.blink2; + ilink1 = table.ilink1; + ilink2 = table.ilink2; + data1 = table.data1; + data2 = table.data2; + line = table.line; + time = table.tsf_low; + hcmd = table.hcmd; trace_iwlwifi_dev_ucode_error(priv, desc, time, data1, data2, line, blink1, blink2, ilink1, ilink2); diff --git a/drivers/net/wireless/iwlwifi/iwl-commands.h b/drivers/net/wireless/iwlwifi/iwl-commands.h index 0edba8a..7aea7b3 100644 --- a/drivers/net/wireless/iwlwifi/iwl-commands.h +++ b/drivers/net/wireless/iwlwifi/iwl-commands.h @@ -422,49 +422,61 @@ struct iwl_tx_ant_config_cmd { * * 2) error_event_table_ptr indicates base of the error log. This contains * information about any uCode error that occurs. For agn, the format - * of the error log is: - * - * __le32 valid; (nonzero) valid, (0) log is empty - * __le32 error_id; type of error - * __le32 pc; program counter - * __le32 blink1; branch link - * __le32 blink2; branch link - * __le32 ilink1; interrupt link - * __le32 ilink2; interrupt link - * __le32 data1; error-specific data - * __le32 data2; error-specific data - * __le32 line; source code line of error - * __le32 bcon_time; beacon timer - * __le32 tsf_low; network timestamp function timer - * __le32 tsf_hi; network timestamp function timer - * __le32 gp1; GP1 timer register - * __le32 gp2; GP2 timer register - * __le32 gp3; GP3 timer register - * __le32 ucode_ver; uCode version - * __le32 hw_ver; HW Silicon version - * __le32 brd_ver; HW board version - * __le32 log_pc; log program counter - * __le32 frame_ptr; frame pointer - * __le32 stack_ptr; stack pointer - * __le32 hcmd; last host command - * __le32 isr0; isr status register LMPM_NIC_ISR0: rxtx_flag - * __le32 isr1; isr status register LMPM_NIC_ISR1: host_flag - * __le32 isr2; isr status register LMPM_NIC_ISR2: enc_flag - * __le32 isr3; isr status register LMPM_NIC_ISR3: time_flag - * __le32 isr4; isr status register LMPM_NIC_ISR4: wico interrupt - * __le32 isr_pref; isr status register LMPM_NIC_PREF_STAT - * __le32 wait_event; wait event() caller address - * __le32 l2p_control; L2pControlField - * __le32 l2p_duration; L2pDurationField - * __le32 l2p_mhvalid; L2pMhValidBits - * __le32 l2p_addr_match; L2pAddrMatchStat - * __le32 lmpm_pmg_sel; indicate which clocks are turned on (LMPM_PMG_SEL) - * __le32 u_timestamp; indicate when the date and time of the compilation - * __le32 reserved; + * of the error log is defined by struct iwl_error_event_table. * * The Linux driver can print both logs to the system log when a uCode error * occurs. */ + +/* + * Note: This structure is read from the device with IO accesses, + * and the reading already does the endian conversion. As it is + * read with u32-sized accesses, any members with a different size + * need to be ordered correctly though! + */ +struct iwl_error_event_table { + u32 valid; /* (nonzero) valid, (0) log is empty */ + u32 error_id; /* type of error */ + u32 pc; /* program counter */ + u32 blink1; /* branch link */ + u32 blink2; /* branch link */ + u32 ilink1; /* interrupt link */ + u32 ilink2; /* interrupt link */ + u32 data1; /* error-specific data */ + u32 data2; /* error-specific data */ + u32 line; /* source code line of error */ + u32 bcon_time; /* beacon timer */ + u32 tsf_low; /* network timestamp function timer */ + u32 tsf_hi; /* network timestamp function timer */ + u32 gp1; /* GP1 timer register */ + u32 gp2; /* GP2 timer register */ + u32 gp3; /* GP3 timer register */ + u32 ucode_ver; /* uCode version */ + u32 hw_ver; /* HW Silicon version */ + u32 brd_ver; /* HW board version */ + u32 log_pc; /* log program counter */ + u32 frame_ptr; /* frame pointer */ + u32 stack_ptr; /* stack pointer */ + u32 hcmd; /* last host command header */ +#if 0 + /* no need to read the remainder, we don't use the values */ + u32 isr0; /* isr status register LMPM_NIC_ISR0: rxtx_flag */ + u32 isr1; /* isr status register LMPM_NIC_ISR1: host_flag */ + u32 isr2; /* isr status register LMPM_NIC_ISR2: enc_flag */ + u32 isr3; /* isr status register LMPM_NIC_ISR3: time_flag */ + u32 isr4; /* isr status register LMPM_NIC_ISR4: wico interrupt */ + u32 isr_pref; /* isr status register LMPM_NIC_PREF_STAT */ + u32 wait_event; /* wait event() caller address */ + u32 l2p_control; /* L2pControlField */ + u32 l2p_duration; /* L2pDurationField */ + u32 l2p_mhvalid; /* L2pMhValidBits */ + u32 l2p_addr_match; /* L2pAddrMatchStat */ + u32 lmpm_pmg_sel; /* indicate which clocks are turned on (LMPM_PMG_SEL) */ + u32 u_timestamp; /* indicate when the date and time of the compilation */ + u32 flow_handler; /* FH read/write pointers, RX credit */ +#endif +} __packed; + struct iwl_alive_resp { u8 ucode_minor; u8 ucode_major; diff --git a/drivers/net/wireless/iwlwifi/iwl-io.c b/drivers/net/wireless/iwlwifi/iwl-io.c index 5133741..993b3df 100644 --- a/drivers/net/wireless/iwlwifi/iwl-io.c +++ b/drivers/net/wireless/iwlwifi/iwl-io.c @@ -242,20 +242,32 @@ void iwl_clear_bits_prph(struct iwl_priv *priv, u32 reg, u32 mask) spin_unlock_irqrestore(&priv->reg_lock, flags); } -u32 iwl_read_targ_mem(struct iwl_priv *priv, u32 addr) +void _iwl_read_targ_mem_words(struct iwl_priv *priv, u32 addr, + void *buf, int words) { unsigned long flags; - u32 value; + int offs; + u32 *vals = buf; spin_lock_irqsave(&priv->reg_lock, flags); iwl_grab_nic_access(priv); iwl_write32(priv, HBUS_TARG_MEM_RADDR, addr); rmb(); - value = iwl_read32(priv, HBUS_TARG_MEM_RDAT); + + for (offs = 0; offs < words; offs++) + vals[offs] = iwl_read32(priv, HBUS_TARG_MEM_RDAT); iwl_release_nic_access(priv); spin_unlock_irqrestore(&priv->reg_lock, flags); +} + +u32 iwl_read_targ_mem(struct iwl_priv *priv, u32 addr) +{ + u32 value; + + _iwl_read_targ_mem_words(priv, addr, &value, 1); + return value; } diff --git a/drivers/net/wireless/iwlwifi/iwl-io.h b/drivers/net/wireless/iwlwifi/iwl-io.h index ab632ba..262e026 100644 --- a/drivers/net/wireless/iwlwifi/iwl-io.h +++ b/drivers/net/wireless/iwlwifi/iwl-io.h @@ -76,6 +76,16 @@ void iwl_set_bits_mask_prph(struct iwl_priv *priv, u32 reg, u32 bits, u32 mask); void iwl_clear_bits_prph(struct iwl_priv *priv, u32 reg, u32 mask); +void _iwl_read_targ_mem_words(struct iwl_priv *priv, u32 addr, + void *buf, int words); + +#define iwl_read_targ_mem_words(priv, addr, buf, bufsize) \ + do { \ + BUILD_BUG_ON((bufsize) % sizeof(u32)); \ + _iwl_read_targ_mem_words(priv, addr, buf, \ + (bufsize) / sizeof(u32));\ + } while (0) + u32 iwl_read_targ_mem(struct iwl_priv *priv, u32 addr); void iwl_write_targ_mem(struct iwl_priv *priv, u32 addr, u32 val); #endif -- cgit v0.10.2 From 1a10f43313481b99154b3b1ce6863742475422e0 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 13 Apr 2011 03:14:44 -0700 Subject: iwlagn: clean up some exit code There's no point in running through iwl_down() when we never registered with mac80211, as it just cleans up internal structures that were never initialised in this case. Therefore we can also remove the special handling for this case from __iwl_down(). Signed-off-by: Johannes Berg Signed-off-by: Wey-Yi Guy diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index f8559cc..2845f63 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -2382,20 +2382,7 @@ static void __iwl_down(struct iwl_priv *priv) if (priv->mac80211_registered) ieee80211_stop_queues(priv->hw); - /* If we have not previously called iwl_init() then - * clear all bits but the RF Kill bit and return */ - if (!iwl_is_init(priv)) { - priv->status = test_bit(STATUS_RF_KILL_HW, &priv->status) << - STATUS_RF_KILL_HW | - test_bit(STATUS_GEO_CONFIGURED, &priv->status) << - STATUS_GEO_CONFIGURED | - test_bit(STATUS_EXIT_PENDING, &priv->status) << - STATUS_EXIT_PENDING; - goto exit; - } - - /* ...otherwise clear out all the status bits but the RF Kill - * bit and continue taking the NIC down. */ + /* Clear out all status bits but a few that are stable across reset */ priv->status &= test_bit(STATUS_RF_KILL_HW, &priv->status) << STATUS_RF_KILL_HW | test_bit(STATUS_GEO_CONFIGURED, &priv->status) << @@ -2421,7 +2408,6 @@ static void __iwl_down(struct iwl_priv *priv) /* Stop the device, and put it in low power state */ iwl_apm_stop(priv); - exit: dev_kfree_skb(priv->beacon_skb); priv->beacon_skb = NULL; @@ -4072,17 +4058,9 @@ static void __devexit iwl_pci_remove(struct pci_dev *pdev) if (priv->mac80211_registered) { ieee80211_unregister_hw(priv->hw); priv->mac80211_registered = 0; - } else { - iwl_down(priv); } - /* - * Make sure device is reset to low power before unloading driver. - * This may be redundant with iwl_down(), but there are paths to - * run iwl_down() without calling apm_ops.stop(), and there are - * paths to avoid running iwl_down() at all before leaving driver. - * This (inexpensive) call *makes sure* device is reset. - */ + /* Reset to low power before unloading driver. */ iwl_apm_stop(priv); iwl_tt_exit(priv); -- cgit v0.10.2 From bc4f8adac6b30ee5f03dad267896add7e58db729 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 13 Apr 2011 03:14:45 -0700 Subject: iwlagn: refactor down path The iwl_down path really consists of multiple things, refactor out the hardware resetting (including, of course, related software state like irqs). Signed-off-by: Johannes Berg Signed-off-by: Wey-Yi Guy diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-lib.c b/drivers/net/wireless/iwlwifi/iwl-agn-lib.c index e741128..5c7eeac 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-lib.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-lib.c @@ -2293,3 +2293,33 @@ void iwlagn_remove_notification(struct iwl_priv *priv, list_del(&wait_entry->list); spin_unlock_bh(&priv->_agn.notif_wait_lock); } + +void iwlagn_stop_device(struct iwl_priv *priv) +{ + unsigned long flags; + + /* stop and reset the on-board processor */ + iwl_write32(priv, CSR_RESET, CSR_RESET_REG_FLAG_NEVO_RESET); + + /* tell the device to stop sending interrupts */ + spin_lock_irqsave(&priv->lock, flags); + iwl_disable_interrupts(priv); + spin_unlock_irqrestore(&priv->lock, flags); + iwl_synchronize_irq(priv); + + /* device going down, Stop using ICT table */ + iwl_disable_ict(priv); + + iwlagn_txq_ctx_stop(priv); + iwlagn_rxq_stop(priv); + + /* Power-down device's busmaster DMA clocks */ + iwl_write_prph(priv, APMG_CLK_DIS_REG, APMG_CLK_VAL_DMA_CLK_RQT); + udelay(5); + + /* Make sure (redundant) we've released our request to stay awake */ + iwl_clear_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ); + + /* Stop the device, and put it in low power state */ + iwl_apm_stop(priv); +} diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index 2845f63..f3d9055 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -846,14 +846,6 @@ static void iwl_rx_handle(struct iwl_priv *priv) iwlagn_rx_queue_restock(priv); } -/* call this function to flush any scheduled tasklet */ -static inline void iwl_synchronize_irq(struct iwl_priv *priv) -{ - /* wait to make sure we flush pending tasklet*/ - synchronize_irq(priv->pci_dev->irq); - tasklet_kill(&priv->irq_tasklet); -} - /* tasklet for iwlagn interrupt */ static void iwl_irq_tasklet(struct iwl_priv *priv) { @@ -2338,7 +2330,6 @@ static void iwl_cancel_deferred_work(struct iwl_priv *priv); static void __iwl_down(struct iwl_priv *priv) { - unsigned long flags; int exit_pending; IWL_DEBUG_INFO(priv, DRV_NAME " is going down\n"); @@ -2370,15 +2361,6 @@ static void __iwl_down(struct iwl_priv *priv) if (!exit_pending) clear_bit(STATUS_EXIT_PENDING, &priv->status); - /* stop and reset the on-board processor */ - iwl_write32(priv, CSR_RESET, CSR_RESET_REG_FLAG_NEVO_RESET); - - /* tell the device to stop sending interrupts */ - spin_lock_irqsave(&priv->lock, flags); - iwl_disable_interrupts(priv); - spin_unlock_irqrestore(&priv->lock, flags); - iwl_synchronize_irq(priv); - if (priv->mac80211_registered) ieee80211_stop_queues(priv->hw); @@ -2392,21 +2374,7 @@ static void __iwl_down(struct iwl_priv *priv) test_bit(STATUS_EXIT_PENDING, &priv->status) << STATUS_EXIT_PENDING; - /* device going down, Stop using ICT table */ - iwl_disable_ict(priv); - - iwlagn_txq_ctx_stop(priv); - iwlagn_rxq_stop(priv); - - /* Power-down device's busmaster DMA clocks */ - iwl_write_prph(priv, APMG_CLK_DIS_REG, APMG_CLK_VAL_DMA_CLK_RQT); - udelay(5); - - /* Make sure (redundant) we've released our request to stay awake */ - iwl_clear_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ); - - /* Stop the device, and put it in low power state */ - iwl_apm_stop(priv); + iwlagn_stop_device(priv); dev_kfree_skb(priv->beacon_skb); priv->beacon_skb = NULL; diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.h b/drivers/net/wireless/iwlwifi/iwl-agn.h index 078a23e..1211f45 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.h +++ b/drivers/net/wireless/iwlwifi/iwl-agn.h @@ -120,6 +120,17 @@ int iwl_alloc_isr_ict(struct iwl_priv *priv); void iwl_free_isr_ict(struct iwl_priv *priv); irqreturn_t iwl_isr_ict(int irq, void *data); +/* call this function to flush any scheduled tasklet */ +static inline void iwl_synchronize_irq(struct iwl_priv *priv) +{ + /* wait to make sure we flush pending tasklet*/ + synchronize_irq(priv->pci_dev->irq); + tasklet_kill(&priv->irq_tasklet); +} + + +void iwlagn_stop_device(struct iwl_priv *priv); + /* tx queue */ void iwlagn_set_wr_ptrs(struct iwl_priv *priv, int txq_id, u32 index); -- cgit v0.10.2 From 3e14c1fd75d909bfcc6caab79c544921fd02bf73 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 13 Apr 2011 03:14:46 -0700 Subject: iwlagn: refactor up path Starting the device consists of many things, refactor out enabling the hardware and also return -ERFKILL when the rfkill signal is found to be asserted (which makes more sense anyway, but is also required now to make the __iwl_up function return right away.) Signed-off-by: Johannes Berg Signed-off-by: Wey-Yi Guy diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-lib.c b/drivers/net/wireless/iwlwifi/iwl-agn-lib.c index 5c7eeac..5e62a08 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-lib.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-lib.c @@ -2294,6 +2294,52 @@ void iwlagn_remove_notification(struct iwl_priv *priv, spin_unlock_bh(&priv->_agn.notif_wait_lock); } +int iwlagn_start_device(struct iwl_priv *priv) +{ + int ret; + + iwl_prepare_card_hw(priv); + if (!priv->hw_ready) { + IWL_WARN(priv, "Exit HW not ready\n"); + return -EIO; + } + + /* If platform's RF_KILL switch is NOT set to KILL */ + if (iwl_read32(priv, CSR_GP_CNTRL) & CSR_GP_CNTRL_REG_FLAG_HW_RF_KILL_SW) + clear_bit(STATUS_RF_KILL_HW, &priv->status); + else + set_bit(STATUS_RF_KILL_HW, &priv->status); + + if (iwl_is_rfkill(priv)) { + wiphy_rfkill_set_hw_state(priv->hw->wiphy, true); + iwl_enable_interrupts(priv); + return -ERFKILL; + } + + iwl_write32(priv, CSR_INT, 0xFFFFFFFF); + + ret = iwlagn_hw_nic_init(priv); + if (ret) { + IWL_ERR(priv, "Unable to init nic\n"); + return ret; + } + + /* make sure rfkill handshake bits are cleared */ + iwl_write32(priv, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL); + iwl_write32(priv, CSR_UCODE_DRV_GP1_CLR, + CSR_UCODE_DRV_GP1_BIT_CMD_BLOCKED); + + /* clear (again), then enable host interrupts */ + iwl_write32(priv, CSR_INT, 0xFFFFFFFF); + iwl_enable_interrupts(priv); + + /* really make sure rfkill handshake bits are cleared */ + iwl_write32(priv, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL); + iwl_write32(priv, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL); + + return 0; +} + void iwlagn_stop_device(struct iwl_priv *priv) { unsigned long flags; diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index f3d9055..e99cd94 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -2416,7 +2416,7 @@ static int iwl_set_hw_ready(struct iwl_priv *priv) return ret; } -static int iwl_prepare_card_hw(struct iwl_priv *priv) +int iwl_prepare_card_hw(struct iwl_priv *priv) { int ret = 0; @@ -2462,47 +2462,9 @@ static int __iwl_up(struct iwl_priv *priv) } } - iwl_prepare_card_hw(priv); - - if (!priv->hw_ready) { - IWL_WARN(priv, "Exit HW not ready\n"); - return -EIO; - } - - /* If platform's RF_KILL switch is NOT set to KILL */ - if (iwl_read32(priv, CSR_GP_CNTRL) & CSR_GP_CNTRL_REG_FLAG_HW_RF_KILL_SW) - clear_bit(STATUS_RF_KILL_HW, &priv->status); - else - set_bit(STATUS_RF_KILL_HW, &priv->status); - - if (iwl_is_rfkill(priv)) { - wiphy_rfkill_set_hw_state(priv->hw->wiphy, true); - - iwl_enable_interrupts(priv); - IWL_WARN(priv, "Radio disabled by HW RF Kill switch\n"); - return 0; - } - - iwl_write32(priv, CSR_INT, 0xFFFFFFFF); - - ret = iwlagn_hw_nic_init(priv); - if (ret) { - IWL_ERR(priv, "Unable to init nic\n"); + ret = iwlagn_start_device(priv); + if (ret) return ret; - } - - /* make sure rfkill handshake bits are cleared */ - iwl_write32(priv, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL); - iwl_write32(priv, CSR_UCODE_DRV_GP1_CLR, - CSR_UCODE_DRV_GP1_BIT_CMD_BLOCKED); - - /* clear (again), then enable host interrupts */ - iwl_write32(priv, CSR_INT, 0xFFFFFFFF); - iwl_enable_interrupts(priv); - - /* really make sure rfkill handshake bits are cleared */ - iwl_write32(priv, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL); - iwl_write32(priv, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL); for (i = 0; i < MAX_HW_RESTARTS; i++) { diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.h b/drivers/net/wireless/iwlwifi/iwl-agn.h index 1211f45..ef1bbd4 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.h +++ b/drivers/net/wireless/iwlwifi/iwl-agn.h @@ -128,7 +128,9 @@ static inline void iwl_synchronize_irq(struct iwl_priv *priv) tasklet_kill(&priv->irq_tasklet); } +int iwl_prepare_card_hw(struct iwl_priv *priv); +int iwlagn_start_device(struct iwl_priv *priv); void iwlagn_stop_device(struct iwl_priv *priv); /* tx queue */ -- cgit v0.10.2 From 09f18afe766ea3f2c749e3af195bf65fde71b62e Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 13 Apr 2011 03:14:47 -0700 Subject: iwlagn: extend notification wait function A notification wait function is called with the command, but currently has no way of passing data back to the caller -- fix that by adding a void pointer to the function that can be used between the caller and the function. Signed-off-by: Johannes Berg Signed-off-by: Wey-Yi Guy diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-lib.c b/drivers/net/wireless/iwlwifi/iwl-agn-lib.c index 5e62a08..486a8d3 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-lib.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-lib.c @@ -2256,11 +2256,14 @@ int iwl_dump_fh(struct iwl_priv *priv, char **buf, bool display) /* notification wait support */ void iwlagn_init_notification_wait(struct iwl_priv *priv, struct iwl_notification_wait *wait_entry, + u8 cmd, void (*fn)(struct iwl_priv *priv, - struct iwl_rx_packet *pkt), - u8 cmd) + struct iwl_rx_packet *pkt, + void *data), + void *fn_data) { wait_entry->fn = fn; + wait_entry->fn_data = fn_data; wait_entry->cmd = cmd; wait_entry->triggered = false; diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-rxon.c b/drivers/net/wireless/iwlwifi/iwl-agn-rxon.c index 56f46ee..ee7c5ba 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-rxon.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-rxon.c @@ -58,8 +58,9 @@ static int iwlagn_disable_pan(struct iwl_priv *priv, u8 old_dev_type = send->dev_type; int ret; - iwlagn_init_notification_wait(priv, &disable_wait, NULL, - REPLY_WIPAN_DEACTIVATION_COMPLETE); + iwlagn_init_notification_wait(priv, &disable_wait, + REPLY_WIPAN_DEACTIVATION_COMPLETE, + NULL, NULL); send->filter_flags &= ~RXON_FILTER_ASSOC_MSK; send->dev_type = RXON_DEV_TYPE_P2P; diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index e99cd94..a9204db 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -769,7 +769,7 @@ static void iwl_rx_handle(struct iwl_priv *priv) if (w->cmd == pkt->hdr.cmd) { w->triggered = true; if (w->fn) - w->fn(priv, pkt); + w->fn(priv, pkt, w->fn_data); } } spin_unlock(&priv->_agn.notif_wait_lock); diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.h b/drivers/net/wireless/iwlwifi/iwl-agn.h index ef1bbd4..b9871c4 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.h +++ b/drivers/net/wireless/iwlwifi/iwl-agn.h @@ -338,9 +338,11 @@ void iwlcore_eeprom_release_semaphore(struct iwl_priv *priv); void __acquires(wait_entry) iwlagn_init_notification_wait(struct iwl_priv *priv, struct iwl_notification_wait *wait_entry, + u8 cmd, void (*fn)(struct iwl_priv *priv, - struct iwl_rx_packet *pkt), - u8 cmd); + struct iwl_rx_packet *pkt, + void *data), + void *fn_data); signed long __releases(wait_entry) iwlagn_wait_notification(struct iwl_priv *priv, struct iwl_notification_wait *wait_entry, diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index e84534c..d8bf117 100644 --- a/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h @@ -1105,7 +1105,9 @@ struct iwl_force_reset { struct iwl_notification_wait { struct list_head list; - void (*fn)(struct iwl_priv *priv, struct iwl_rx_packet *pkt); + void (*fn)(struct iwl_priv *priv, struct iwl_rx_packet *pkt, + void *data); + void *fn_data; u8 cmd; bool triggered; -- cgit v0.10.2 From a8674a1efca60d863d4caa47e102cc4d70d5ff9b Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 13 Apr 2011 03:14:48 -0700 Subject: iwlagn: make iwlagn_wait_notification return error code We're unlikely to care about the actual time spent waiting, so make the function return an error code which is less error prone in coding new uses. Also, while at it, mark __must_check. Signed-off-by: Johannes Berg Signed-off-by: Wey-Yi Guy diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-lib.c b/drivers/net/wireless/iwlwifi/iwl-agn-lib.c index 486a8d3..8284168 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-lib.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-lib.c @@ -2272,9 +2272,9 @@ void iwlagn_init_notification_wait(struct iwl_priv *priv, spin_unlock_bh(&priv->_agn.notif_wait_lock); } -signed long iwlagn_wait_notification(struct iwl_priv *priv, - struct iwl_notification_wait *wait_entry, - unsigned long timeout) +int iwlagn_wait_notification(struct iwl_priv *priv, + struct iwl_notification_wait *wait_entry, + unsigned long timeout) { int ret; @@ -2286,7 +2286,10 @@ signed long iwlagn_wait_notification(struct iwl_priv *priv, list_del(&wait_entry->list); spin_unlock_bh(&priv->_agn.notif_wait_lock); - return ret; + /* return value is always >= 0 */ + if (ret <= 0) + return -ETIMEDOUT; + return 0; } void iwlagn_remove_notification(struct iwl_priv *priv, diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-rxon.c b/drivers/net/wireless/iwlwifi/iwl-agn-rxon.c index ee7c5ba..435dd2d 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-rxon.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-rxon.c @@ -73,13 +73,9 @@ static int iwlagn_disable_pan(struct iwl_priv *priv, IWL_ERR(priv, "Error disabling PAN (%d)\n", ret); iwlagn_remove_notification(priv, &disable_wait); } else { - signed long wait_res; - - wait_res = iwlagn_wait_notification(priv, &disable_wait, HZ); - if (wait_res == 0) { + ret = iwlagn_wait_notification(priv, &disable_wait, HZ); + if (ret) IWL_ERR(priv, "Timed out waiting for PAN disable\n"); - ret = -EIO; - } } return ret; diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.h b/drivers/net/wireless/iwlwifi/iwl-agn.h index b9871c4..ba90aa4 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.h +++ b/drivers/net/wireless/iwlwifi/iwl-agn.h @@ -343,7 +343,7 @@ iwlagn_init_notification_wait(struct iwl_priv *priv, struct iwl_rx_packet *pkt, void *data), void *fn_data); -signed long __releases(wait_entry) +int __must_check __releases(wait_entry) iwlagn_wait_notification(struct iwl_priv *priv, struct iwl_notification_wait *wait_entry, unsigned long timeout); -- cgit v0.10.2 From e74fe2330a5a721610b2b69652d2ec2ebbd302e0 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 13 Apr 2011 03:14:49 -0700 Subject: iwlagn: leave notification waits on firmware errors When the firmware encounters an error while the driver is waiting for a notification, it will never get that notification. Therefore, instead of timing out, bail out on errors when waiting for notifications. Signed-off-by: Johannes Berg Signed-off-by: Wey-Yi Guy diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-lib.c b/drivers/net/wireless/iwlwifi/iwl-agn-lib.c index 8284168..a29e2e2 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-lib.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-lib.c @@ -2266,6 +2266,7 @@ void iwlagn_init_notification_wait(struct iwl_priv *priv, wait_entry->fn_data = fn_data; wait_entry->cmd = cmd; wait_entry->triggered = false; + wait_entry->aborted = false; spin_lock_bh(&priv->_agn.notif_wait_lock); list_add(&wait_entry->list, &priv->_agn.notif_waits); @@ -2279,13 +2280,16 @@ int iwlagn_wait_notification(struct iwl_priv *priv, int ret; ret = wait_event_timeout(priv->_agn.notif_waitq, - wait_entry->triggered, + wait_entry->triggered || wait_entry->aborted, timeout); spin_lock_bh(&priv->_agn.notif_wait_lock); list_del(&wait_entry->list); spin_unlock_bh(&priv->_agn.notif_wait_lock); + if (wait_entry->aborted) + return -EIO; + /* return value is always >= 0 */ if (ret <= 0) return -ETIMEDOUT; diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index 885167f..46d6965 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -867,6 +867,19 @@ void iwl_print_rx_config_cmd(struct iwl_priv *priv, } #endif +static void iwlagn_abort_notification_waits(struct iwl_priv *priv) +{ + unsigned long flags; + struct iwl_notification_wait *wait_entry; + + spin_lock_irqsave(&priv->_agn.notif_wait_lock, flags); + list_for_each_entry(wait_entry, &priv->_agn.notif_waits, list) + wait_entry->aborted = true; + spin_unlock_irqrestore(&priv->_agn.notif_wait_lock, flags); + + wake_up_all(&priv->_agn.notif_waitq); +} + void iwlagn_fw_error(struct iwl_priv *priv, bool ondemand) { unsigned int reload_msec; @@ -878,6 +891,8 @@ void iwlagn_fw_error(struct iwl_priv *priv, bool ondemand) /* Cancel currently queued command. */ clear_bit(STATUS_HCMD_ACTIVE, &priv->status); + iwlagn_abort_notification_waits(priv); + /* Keep the restart process from trying to send host * commands by clearing the ready bit */ clear_bit(STATUS_READY, &priv->status); diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index d8bf117..0345292 100644 --- a/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h @@ -1110,7 +1110,7 @@ struct iwl_notification_wait { void *fn_data; u8 cmd; - bool triggered; + bool triggered, aborted; }; enum iwl_rxon_context_id { -- cgit v0.10.2 From ca7966c88e44233fac113579071a6f55e00ef5ac Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 22 Apr 2011 10:15:23 -0700 Subject: iwlagn: implement synchronous firmware load The current firmware loading mechanism in iwlwifi is very hard to follow, and thus hard to maintain. To make it easier, make the firmware loading synchronous. For now, as a side effect, this removes a number of retry possibilities we had. It isn't typical for this to fail, but if it does happen we restart from scratch which this also makes easier to do should it be necessary. Signed-off-by: Johannes Berg Signed-off-by: Wey-Yi Guy diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-lib.c b/drivers/net/wireless/iwlwifi/iwl-agn-lib.c index a29e2e2..8216e5c 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-lib.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-lib.c @@ -483,8 +483,6 @@ void iwlagn_rx_handler_setup(struct iwl_priv *priv) /* init calibration handlers */ priv->rx_handlers[CALIBRATION_RES_NOTIFICATION] = iwlagn_rx_calib_result; - priv->rx_handlers[CALIBRATION_COMPLETE_NOTIFICATION] = - iwlagn_rx_calib_complete; priv->rx_handlers[REPLY_TX] = iwlagn_rx_reply_tx; /* set up notification wait support */ diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-ucode.c b/drivers/net/wireless/iwlwifi/iwl-agn-ucode.c index 5c30f6b..56dc771 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-ucode.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-ucode.c @@ -161,8 +161,8 @@ static int iwlagn_load_section(struct iwl_priv *priv, const char *name, } static int iwlagn_load_given_ucode(struct iwl_priv *priv, - struct fw_desc *inst_image, - struct fw_desc *data_image) + struct fw_desc *inst_image, + struct fw_desc *data_image) { int ret = 0; @@ -175,33 +175,6 @@ static int iwlagn_load_given_ucode(struct iwl_priv *priv, IWLAGN_RTC_DATA_LOWER_BOUND); } -int iwlagn_load_ucode(struct iwl_priv *priv) -{ - int ret = 0; - - /* check whether init ucode should be loaded, or rather runtime ucode */ - if (priv->ucode_init.len && (priv->ucode_type == UCODE_NONE)) { - IWL_DEBUG_INFO(priv, "Init ucode found. Loading init ucode...\n"); - ret = iwlagn_load_given_ucode(priv, - &priv->ucode_init, &priv->ucode_init_data); - if (!ret) { - IWL_DEBUG_INFO(priv, "Init ucode load complete.\n"); - priv->ucode_type = UCODE_INIT; - } - } else { - IWL_DEBUG_INFO(priv, "Init ucode not found, or already loaded. " - "Loading runtime ucode...\n"); - ret = iwlagn_load_given_ucode(priv, - &priv->ucode_code, &priv->ucode_data); - if (!ret) { - IWL_DEBUG_INFO(priv, "Runtime ucode load complete.\n"); - priv->ucode_type = UCODE_RT; - } - } - - return ret; -} - /* * Calibration */ @@ -297,33 +270,9 @@ void iwlagn_rx_calib_result(struct iwl_priv *priv, iwl_calib_set(&priv->calib_results[index], pkt->u.raw, len); } -void iwlagn_rx_calib_complete(struct iwl_priv *priv, - struct iwl_rx_mem_buffer *rxb) +static int iwlagn_init_alive_start(struct iwl_priv *priv) { - IWL_DEBUG_INFO(priv, "Init. calibration is completed, restarting fw.\n"); - queue_work(priv->workqueue, &priv->restart); -} - -void iwlagn_init_alive_start(struct iwl_priv *priv) -{ - int ret = 0; - - /* initialize uCode was loaded... verify inst image. - * This is a paranoid check, because we would not have gotten the - * "initialize" alive if code weren't properly loaded. */ - if (iwl_verify_ucode(priv, &priv->ucode_init)) { - /* Runtime instruction load was bad; - * take it all the way back down so we can try again */ - IWL_DEBUG_INFO(priv, "Bad \"initialize\" uCode load.\n"); - goto restart; - } - - ret = iwlagn_alive_notify(priv); - if (ret) { - IWL_WARN(priv, - "Could not complete ALIVE transition: %d\n", ret); - goto restart; - } + int ret; if (priv->cfg->bt_params && priv->cfg->bt_params->advanced_bt_coexist) { @@ -333,24 +282,25 @@ void iwlagn_init_alive_start(struct iwl_priv *priv) * no need to close the envlope since we are going * to load the runtime uCode later. */ - iwlagn_send_bt_env(priv, IWL_BT_COEX_ENV_OPEN, + ret = iwlagn_send_bt_env(priv, IWL_BT_COEX_ENV_OPEN, BT_COEX_PRIO_TBL_EVT_INIT_CALIB2); + if (ret) + return ret; } - iwlagn_send_calib_cfg(priv); + + ret = iwlagn_send_calib_cfg(priv); + if (ret) + return ret; /** * temperature offset calibration is only needed for runtime ucode, * so prepare the value now. */ if (priv->cfg->need_temp_offset_calib) - iwlagn_set_temperature_offset_calib(priv); - - return; + return iwlagn_set_temperature_offset_calib(priv); -restart: - /* real restart (first load init_ucode) */ - queue_work(priv->workqueue, &priv->restart); + return 0; } static int iwlagn_send_wimax_coex(struct iwl_priv *priv) @@ -413,19 +363,22 @@ void iwlagn_send_prio_tbl(struct iwl_priv *priv) IWL_ERR(priv, "failed to send BT prio tbl command\n"); } -void iwlagn_send_bt_env(struct iwl_priv *priv, u8 action, u8 type) +int iwlagn_send_bt_env(struct iwl_priv *priv, u8 action, u8 type) { struct iwl_bt_coex_prot_env_cmd env_cmd; + int ret; env_cmd.action = action; env_cmd.type = type; - if (iwl_send_cmd_pdu(priv, REPLY_BT_COEX_PROT_ENV, - sizeof(env_cmd), &env_cmd)) + ret = iwl_send_cmd_pdu(priv, REPLY_BT_COEX_PROT_ENV, + sizeof(env_cmd), &env_cmd); + if (ret) IWL_ERR(priv, "failed to send BT env command\n"); + return ret; } -int iwlagn_alive_notify(struct iwl_priv *priv) +static int iwlagn_alive_notify(struct iwl_priv *priv) { const struct queue_to_fifo_ac *queue_to_fifo; struct iwl_rxon_context *ctx; @@ -604,7 +557,7 @@ static void iwl_print_mismatch_inst(struct iwl_priv *priv, * iwl_verify_ucode - determine which instruction image is in SRAM, * and verify its contents */ -int iwl_verify_ucode(struct iwl_priv *priv, struct fw_desc *fw_desc) +static int iwl_verify_ucode(struct iwl_priv *priv, struct fw_desc *fw_desc) { if (!iwlcore_verify_inst_sparse(priv, fw_desc)) { IWL_DEBUG_INFO(priv, "uCode is good in inst SRAM\n"); @@ -616,3 +569,154 @@ int iwl_verify_ucode(struct iwl_priv *priv, struct fw_desc *fw_desc) iwl_print_mismatch_inst(priv, fw_desc); return -EIO; } + +struct iwlagn_alive_data { + bool valid; + u8 subtype; +}; + +static void iwlagn_alive_fn(struct iwl_priv *priv, + struct iwl_rx_packet *pkt, + void *data) +{ + struct iwlagn_alive_data *alive_data = data; + struct iwl_alive_resp *palive; + + palive = &pkt->u.alive_frame; + + IWL_DEBUG_INFO(priv, "Alive ucode status 0x%08X revision " + "0x%01X 0x%01X\n", + palive->is_valid, palive->ver_type, + palive->ver_subtype); + + priv->device_pointers.error_event_table = + le32_to_cpu(palive->error_event_table_ptr); + priv->device_pointers.log_event_table = + le32_to_cpu(palive->log_event_table_ptr); + + alive_data->subtype = palive->ver_subtype; + alive_data->valid = palive->is_valid == UCODE_VALID_OK; +} + +#define UCODE_ALIVE_TIMEOUT HZ +#define UCODE_CALIB_TIMEOUT (2*HZ) + +int iwlagn_load_ucode_wait_alive(struct iwl_priv *priv, + struct fw_desc *inst_image, + struct fw_desc *data_image, + int subtype, int alternate_subtype) +{ + struct iwl_notification_wait alive_wait; + struct iwlagn_alive_data alive_data; + int ret; + enum iwlagn_ucode_subtype old_type; + + ret = iwlagn_start_device(priv); + if (ret) + return ret; + + iwlagn_init_notification_wait(priv, &alive_wait, REPLY_ALIVE, + iwlagn_alive_fn, &alive_data); + + old_type = priv->ucode_type; + priv->ucode_type = subtype; + + ret = iwlagn_load_given_ucode(priv, inst_image, data_image); + if (ret) { + priv->ucode_type = old_type; + iwlagn_remove_notification(priv, &alive_wait); + return ret; + } + + /* Remove all resets to allow NIC to operate */ + iwl_write32(priv, CSR_RESET, 0); + + /* + * Some things may run in the background now, but we + * just wait for the ALIVE notification here. + */ + ret = iwlagn_wait_notification(priv, &alive_wait, UCODE_ALIVE_TIMEOUT); + if (ret) { + priv->ucode_type = old_type; + return ret; + } + + if (!alive_data.valid) { + IWL_ERR(priv, "Loaded ucode is not valid!\n"); + priv->ucode_type = old_type; + return -EIO; + } + + if (alive_data.subtype != subtype && + alive_data.subtype != alternate_subtype) { + IWL_ERR(priv, + "Loaded ucode is not expected type (got %d, expected %d)!\n", + alive_data.subtype, subtype); + priv->ucode_type = old_type; + return -EIO; + } + + ret = iwl_verify_ucode(priv, inst_image); + if (ret) { + priv->ucode_type = old_type; + return ret; + } + + /* delay a bit to give rfkill time to run */ + msleep(5); + + ret = iwlagn_alive_notify(priv); + if (ret) { + IWL_WARN(priv, + "Could not complete ALIVE transition: %d\n", ret); + priv->ucode_type = old_type; + return ret; + } + + return 0; +} + +int iwlagn_run_init_ucode(struct iwl_priv *priv) +{ + struct iwl_notification_wait calib_wait; + int ret; + + lockdep_assert_held(&priv->mutex); + + /* No init ucode required? Curious, but maybe ok */ + if (!priv->ucode_init.len) + return 0; + + if (priv->ucode_type != UCODE_SUBTYPE_NONE_LOADED) + return 0; + + iwlagn_init_notification_wait(priv, &calib_wait, + CALIBRATION_COMPLETE_NOTIFICATION, + NULL, NULL); + + /* Will also start the device */ + ret = iwlagn_load_ucode_wait_alive(priv, &priv->ucode_init, + &priv->ucode_init_data, + UCODE_SUBTYPE_INIT, -1); + if (ret) + goto error; + + ret = iwlagn_init_alive_start(priv); + if (ret) + goto error; + + /* + * Some things may run in the background now, but we + * just wait for the calibration complete notification. + */ + ret = iwlagn_wait_notification(priv, &calib_wait, UCODE_CALIB_TIMEOUT); + + goto out; + + error: + iwlagn_remove_notification(priv, &calib_wait); + out: + /* Whatever happened, stop the device */ + iwlagn_stop_device(priv); + return ret; +} diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index a9204db..12cd5e0 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -1181,12 +1181,6 @@ static void iwl_dealloc_ucode_pci(struct iwl_priv *priv) iwl_free_fw_desc(priv->pci_dev, &priv->ucode_init_data); } -static void iwl_nic_start(struct iwl_priv *priv) -{ - /* Remove all resets to allow NIC to operate */ - iwl_write32(priv, CSR_RESET, 0); -} - struct iwlagn_ucode_capabilities { u32 max_probe_length; u32 standard_phy_calibration_size; @@ -1873,7 +1867,7 @@ void iwl_dump_nic_error_log(struct iwl_priv *priv) struct iwl_error_event_table table; base = priv->device_pointers.error_event_table; - if (priv->ucode_type == UCODE_INIT) { + if (priv->ucode_type == UCODE_SUBTYPE_INIT) { if (!base) base = priv->_agn.init_errlog_ptr; } else { @@ -1884,7 +1878,9 @@ void iwl_dump_nic_error_log(struct iwl_priv *priv) if (!priv->cfg->ops->lib->is_valid_rtc_data_addr(base)) { IWL_ERR(priv, "Not valid error log pointer 0x%08X for %s uCode\n", - base, (priv->ucode_type == UCODE_INIT) ? "Init" : "RT"); + base, + (priv->ucode_type == UCODE_SUBTYPE_INIT) + ? "Init" : "RT"); return; } @@ -1944,7 +1940,7 @@ static int iwl_print_event_log(struct iwl_priv *priv, u32 start_idx, return pos; base = priv->device_pointers.log_event_table; - if (priv->ucode_type == UCODE_INIT) { + if (priv->ucode_type == UCODE_SUBTYPE_INIT) { if (!base) base = priv->_agn.init_evtlog_ptr; } else { @@ -2057,7 +2053,7 @@ int iwl_dump_nic_event_log(struct iwl_priv *priv, bool full_log, size_t bufsz = 0; base = priv->device_pointers.log_event_table; - if (priv->ucode_type == UCODE_INIT) { + if (priv->ucode_type == UCODE_SUBTYPE_INIT) { logsize = priv->_agn.init_evtlog_size; if (!base) base = priv->_agn.init_evtlog_ptr; @@ -2070,7 +2066,9 @@ int iwl_dump_nic_event_log(struct iwl_priv *priv, bool full_log, if (!priv->cfg->ops->lib->is_valid_rtc_data_addr(base)) { IWL_ERR(priv, "Invalid event log pointer 0x%08X for %s uCode\n", - base, (priv->ucode_type == UCODE_INIT) ? "Init" : "RT"); + base, + (priv->ucode_type == UCODE_SUBTYPE_INIT) + ? "Init" : "RT"); return -EINVAL; } @@ -2217,30 +2215,14 @@ static int iwlagn_send_calib_cfg_rt(struct iwl_priv *priv, u32 cfg) * from protocol/runtime uCode (initialization uCode's * Alive gets handled by iwl_init_alive_start()). */ -static void iwl_alive_start(struct iwl_priv *priv) +static int iwl_alive_start(struct iwl_priv *priv) { int ret = 0; struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS]; - IWL_DEBUG_INFO(priv, "Runtime Alive received.\n"); - - /* Initialize uCode has loaded Runtime uCode ... verify inst image. - * This is a paranoid check, because we would not have gotten the - * "runtime" alive if code weren't properly loaded. */ - if (iwl_verify_ucode(priv, &priv->ucode_code)) { - /* Runtime instruction load was bad; - * take it all the way back down so we can try again */ - IWL_DEBUG_INFO(priv, "Bad runtime uCode load.\n"); - goto restart; - } - - ret = iwlagn_alive_notify(priv); - if (ret) { - IWL_WARN(priv, - "Could not complete ALIVE transition [ntf]: %d\n", ret); - goto restart; - } + iwl_reset_ict(priv); + IWL_DEBUG_INFO(priv, "Runtime Alive received.\n"); /* After the ALIVE response, we can send host commands to the uCode */ set_bit(STATUS_ALIVE, &priv->status); @@ -2249,7 +2231,7 @@ static void iwl_alive_start(struct iwl_priv *priv) iwl_setup_watchdog(priv); if (iwl_is_rfkill(priv)) - return; + return -ERFKILL; /* download priority table before any calibration request */ if (priv->cfg->bt_params && @@ -2263,10 +2245,14 @@ static void iwl_alive_start(struct iwl_priv *priv) iwlagn_send_prio_tbl(priv); /* FIXME: w/a to force change uCode BT state machine */ - iwlagn_send_bt_env(priv, IWL_BT_COEX_ENV_OPEN, - BT_COEX_PRIO_TBL_EVT_INIT_CALIB2); - iwlagn_send_bt_env(priv, IWL_BT_COEX_ENV_CLOSE, - BT_COEX_PRIO_TBL_EVT_INIT_CALIB2); + ret = iwlagn_send_bt_env(priv, IWL_BT_COEX_ENV_OPEN, + BT_COEX_PRIO_TBL_EVT_INIT_CALIB2); + if (ret) + return ret; + ret = iwlagn_send_bt_env(priv, IWL_BT_COEX_ENV_CLOSE, + BT_COEX_PRIO_TBL_EVT_INIT_CALIB2); + if (ret) + return ret; } if (priv->hw_params.calib_rt_cfg) iwlagn_send_calib_cfg_rt(priv, priv->hw_params.calib_rt_cfg); @@ -2308,22 +2294,16 @@ static void iwl_alive_start(struct iwl_priv *priv) set_bit(STATUS_READY, &priv->status); /* Configure the adapter for unassociated operation */ - iwlcore_commit_rxon(priv, ctx); + ret = iwlcore_commit_rxon(priv, ctx); + if (ret) + return ret; /* At this point, the NIC is initialized and operational */ iwl_rf_kill_ct_config(priv); IWL_DEBUG_INFO(priv, "ALIVE processing complete.\n"); - wake_up_interruptible(&priv->wait_command_queue); - - iwl_power_update_mode(priv, true); - IWL_DEBUG_INFO(priv, "Updated power mode\n"); - - return; - - restart: - queue_work(priv->workqueue, &priv->restart); + return iwl_power_update_mode(priv, true); } static void iwl_cancel_deferred_work(struct iwl_priv *priv); @@ -2446,9 +2426,10 @@ int iwl_prepare_card_hw(struct iwl_priv *priv) static int __iwl_up(struct iwl_priv *priv) { struct iwl_rxon_context *ctx; - int i; int ret; + lockdep_assert_held(&priv->mutex); + if (test_bit(STATUS_EXIT_PENDING, &priv->status)) { IWL_WARN(priv, "Exit pending; will not bring the NIC up\n"); return -EIO; @@ -2462,39 +2443,34 @@ static int __iwl_up(struct iwl_priv *priv) } } - ret = iwlagn_start_device(priv); - if (ret) - return ret; - - for (i = 0; i < MAX_HW_RESTARTS; i++) { - - /* load bootstrap state machine, - * load bootstrap program into processor's memory, - * prepare to load the "initialize" uCode */ - ret = iwlagn_load_ucode(priv); - - if (ret) { - IWL_ERR(priv, "Unable to set up bootstrap uCode: %d\n", - ret); - continue; - } - - /* start card; "initialize" will load runtime ucode */ - iwl_nic_start(priv); - - IWL_DEBUG_INFO(priv, DRV_NAME " is coming up\n"); + ret = iwlagn_run_init_ucode(priv); + if (ret) { + IWL_ERR(priv, "Failed to run INIT ucode: %d\n", ret); + goto error; + } - return 0; + ret = iwlagn_load_ucode_wait_alive(priv, + &priv->ucode_code, + &priv->ucode_data, + UCODE_SUBTYPE_REGULAR, + UCODE_SUBTYPE_REGULAR_NEW); + if (ret) { + IWL_ERR(priv, "Failed to start RT ucode: %d\n", ret); + goto error; } + ret = iwl_alive_start(priv); + if (ret) + goto error; + return 0; + + error: set_bit(STATUS_EXIT_PENDING, &priv->status); __iwl_down(priv); clear_bit(STATUS_EXIT_PENDING, &priv->status); - /* tried to restart and config the device for as long as our - * patience could withstand */ - IWL_ERR(priv, "Unable to initialize device after %d attempts.\n", i); - return -EIO; + IWL_ERR(priv, "Unable to initialize device.\n"); + return ret; } @@ -2504,39 +2480,6 @@ static int __iwl_up(struct iwl_priv *priv) * *****************************************************************************/ -static void iwl_bg_init_alive_start(struct work_struct *data) -{ - struct iwl_priv *priv = - container_of(data, struct iwl_priv, init_alive_start.work); - - mutex_lock(&priv->mutex); - - if (test_bit(STATUS_EXIT_PENDING, &priv->status)) { - mutex_unlock(&priv->mutex); - return; - } - - iwlagn_init_alive_start(priv); - mutex_unlock(&priv->mutex); -} - -static void iwl_bg_alive_start(struct work_struct *data) -{ - struct iwl_priv *priv = - container_of(data, struct iwl_priv, alive_start.work); - - mutex_lock(&priv->mutex); - if (test_bit(STATUS_EXIT_PENDING, &priv->status)) - goto unlock; - - /* enable dram interrupt */ - iwl_reset_ict(priv); - - iwl_alive_start(priv); -unlock: - mutex_unlock(&priv->mutex); -} - static void iwl_bg_run_time_calib_work(struct work_struct *work) { struct iwl_priv *priv = container_of(work, struct iwl_priv, @@ -2602,14 +2545,7 @@ static void iwl_bg_restart(struct work_struct *data) iwl_cancel_deferred_work(priv); ieee80211_restart_hw(priv->hw); } else { - iwl_down(priv); - - if (test_bit(STATUS_EXIT_PENDING, &priv->status)) - return; - - mutex_lock(&priv->mutex); - __iwl_up(priv); - mutex_unlock(&priv->mutex); + WARN_ON(1); } } @@ -2720,8 +2656,6 @@ unlock: * *****************************************************************************/ -#define UCODE_READY_TIMEOUT (4 * HZ) - /* * Not a mac80211 entry point function, but it fits in with all the * other mac80211 functions grouped here. @@ -2814,31 +2748,17 @@ static int iwlagn_mac_start(struct ieee80211_hw *hw) mutex_lock(&priv->mutex); ret = __iwl_up(priv); mutex_unlock(&priv->mutex); - if (ret) return ret; - if (iwl_is_rfkill(priv)) - goto out; - IWL_DEBUG_INFO(priv, "Start UP work done.\n"); - /* Wait for START_ALIVE from Run Time ucode. Otherwise callbacks from - * mac80211 will not be run successfully. */ - ret = wait_event_interruptible_timeout(priv->wait_command_queue, - test_bit(STATUS_READY, &priv->status), - UCODE_READY_TIMEOUT); - if (!ret) { - if (!test_bit(STATUS_READY, &priv->status)) { - IWL_ERR(priv, "START_ALIVE timeout after %dms.\n", - jiffies_to_msecs(UCODE_READY_TIMEOUT)); - return -ETIMEDOUT; - } - } + /* Now we should be done, and the READY bit should be set. */ + if (WARN_ON(!test_bit(STATUS_READY, &priv->status))) + ret = -EIO; iwlagn_led_enable(priv); -out: priv->is_open = 1; IWL_DEBUG_MAC80211(priv, "leave\n"); return 0; @@ -3425,8 +3345,6 @@ static void iwl_setup_deferred_work(struct iwl_priv *priv) INIT_WORK(&priv->tx_flush, iwl_bg_tx_flush); INIT_WORK(&priv->bt_full_concurrency, iwl_bg_bt_full_concurrency); INIT_WORK(&priv->bt_runtime_config, iwl_bg_bt_runtime_config); - INIT_DELAYED_WORK(&priv->init_alive_start, iwl_bg_init_alive_start); - INIT_DELAYED_WORK(&priv->alive_start, iwl_bg_alive_start); INIT_DELAYED_WORK(&priv->_agn.hw_roc_work, iwlagn_bg_roc_done); iwl_setup_scan_deferred_work(priv); @@ -3455,8 +3373,6 @@ static void iwl_cancel_deferred_work(struct iwl_priv *priv) if (priv->cfg->ops->lib->cancel_deferred_work) priv->cfg->ops->lib->cancel_deferred_work(priv); - cancel_delayed_work_sync(&priv->init_alive_start); - cancel_delayed_work(&priv->alive_start); cancel_work_sync(&priv->run_time_calib_work); cancel_work_sync(&priv->beacon_update); @@ -3691,6 +3607,8 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) priv = hw->priv; /* At this point both hw and priv are allocated. */ + priv->ucode_type = UCODE_SUBTYPE_NONE_LOADED; + /* * The default context is always valid, * more may be discovered when firmware diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.h b/drivers/net/wireless/iwlwifi/iwl-agn.h index ba90aa4..cf05f87 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.h +++ b/drivers/net/wireless/iwlwifi/iwl-agn.h @@ -158,16 +158,15 @@ void iwlagn_bss_info_changed(struct ieee80211_hw *hw, u32 changes); /* uCode */ -int iwlagn_load_ucode(struct iwl_priv *priv); void iwlagn_rx_calib_result(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb); -void iwlagn_rx_calib_complete(struct iwl_priv *priv, - struct iwl_rx_mem_buffer *rxb); -void iwlagn_init_alive_start(struct iwl_priv *priv); -int iwlagn_alive_notify(struct iwl_priv *priv); -int iwl_verify_ucode(struct iwl_priv *priv, struct fw_desc *fw_desc); -void iwlagn_send_bt_env(struct iwl_priv *priv, u8 action, u8 type); +int iwlagn_send_bt_env(struct iwl_priv *priv, u8 action, u8 type); void iwlagn_send_prio_tbl(struct iwl_priv *priv); +int iwlagn_run_init_ucode(struct iwl_priv *priv); +int iwlagn_load_ucode_wait_alive(struct iwl_priv *priv, + struct fw_desc *inst_image, + struct fw_desc *data_image, + int subtype, int alternate_subtype); /* lib */ void iwl_check_abort_status(struct iwl_priv *priv, diff --git a/drivers/net/wireless/iwlwifi/iwl-commands.h b/drivers/net/wireless/iwlwifi/iwl-commands.h index 7aea7b3..e125896 100644 --- a/drivers/net/wireless/iwlwifi/iwl-commands.h +++ b/drivers/net/wireless/iwlwifi/iwl-commands.h @@ -386,7 +386,18 @@ struct iwl_tx_ant_config_cmd { *****************************************************************************/ #define UCODE_VALID_OK cpu_to_le32(0x1) -#define INITIALIZE_SUBTYPE (9) + +enum iwlagn_ucode_subtype { + UCODE_SUBTYPE_REGULAR = 0, + UCODE_SUBTYPE_REGULAR_NEW = 1, + UCODE_SUBTYPE_INIT = 9, + + /* + * Not a valid subtype, the ucode has just a u8, so + * we can use something > 0xff for this value. + */ + UCODE_SUBTYPE_NONE_LOADED = 0x100, +}; /** * REPLY_ALIVE = 0x1 (response only, not a command) diff --git a/drivers/net/wireless/iwlwifi/iwl-debugfs.c b/drivers/net/wireless/iwlwifi/iwl-debugfs.c index c272204..2b60688 100644 --- a/drivers/net/wireless/iwlwifi/iwl-debugfs.c +++ b/drivers/net/wireless/iwlwifi/iwl-debugfs.c @@ -226,7 +226,7 @@ static ssize_t iwl_dbgfs_sram_read(struct file *file, /* default is to dump the entire data segment */ if (!priv->dbgfs_sram_offset && !priv->dbgfs_sram_len) { priv->dbgfs_sram_offset = 0x800000; - if (priv->ucode_type == UCODE_INIT) + if (priv->ucode_type == UCODE_SUBTYPE_INIT) priv->dbgfs_sram_len = priv->ucode_init_data.len; else priv->dbgfs_sram_len = priv->ucode_data.len; diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index 0345292..414968c 100644 --- a/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h @@ -794,12 +794,6 @@ struct iwl_calib_result { size_t buf_len; }; -enum ucode_type { - UCODE_NONE = 0, - UCODE_INIT, - UCODE_RT -}; - /* Sensitivity calib data */ struct iwl_sensitivity_data { u32 auto_corr_ofdm; @@ -1276,7 +1270,7 @@ struct iwl_priv { struct fw_desc ucode_data; /* runtime data original */ struct fw_desc ucode_init; /* initialization inst */ struct fw_desc ucode_init_data; /* initialization data */ - enum ucode_type ucode_type; + enum iwlagn_ucode_subtype ucode_type; u8 ucode_write_complete; /* the image write is complete */ char firmware_name[25]; @@ -1474,8 +1468,6 @@ struct iwl_priv { struct tasklet_struct irq_tasklet; - struct delayed_work init_alive_start; - struct delayed_work alive_start; struct delayed_work scan_check; /* TX Power */ diff --git a/drivers/net/wireless/iwlwifi/iwl-rx.c b/drivers/net/wireless/iwlwifi/iwl-rx.c index b49819c..aca9a1d 100644 --- a/drivers/net/wireless/iwlwifi/iwl-rx.c +++ b/drivers/net/wireless/iwlwifi/iwl-rx.c @@ -225,55 +225,6 @@ err_bd: * ******************************************************************************/ -static void iwl_rx_reply_alive(struct iwl_priv *priv, - struct iwl_rx_mem_buffer *rxb) -{ - struct iwl_rx_packet *pkt = rxb_addr(rxb); - struct iwl_alive_resp *palive; - struct delayed_work *pwork; - - palive = &pkt->u.alive_frame; - - IWL_DEBUG_INFO(priv, "Alive ucode status 0x%08X revision " - "0x%01X 0x%01X\n", - palive->is_valid, palive->ver_type, - palive->ver_subtype); - - priv->device_pointers.log_event_table = - le32_to_cpu(palive->log_event_table_ptr); - priv->device_pointers.error_event_table = - le32_to_cpu(palive->error_event_table_ptr); - - if (palive->ver_subtype == INITIALIZE_SUBTYPE) { - IWL_DEBUG_INFO(priv, "Initialization Alive received.\n"); - pwork = &priv->init_alive_start; - } else { - IWL_DEBUG_INFO(priv, "Runtime Alive received.\n"); - pwork = &priv->alive_start; - } - - /* We delay the ALIVE response by 5ms to - * give the HW RF Kill time to activate... */ - if (palive->is_valid == UCODE_VALID_OK) - queue_delayed_work(priv->workqueue, pwork, - msecs_to_jiffies(5)); - else { - IWL_WARN(priv, "%s uCode did not respond OK.\n", - (palive->ver_subtype == INITIALIZE_SUBTYPE) ? - "init" : "runtime"); - /* - * If fail to load init uCode, - * let's try to load the init uCode again. - * We should not get into this situation, but if it - * does happen, we should not move on and loading "runtime" - * without proper calibrate the device. - */ - if (palive->ver_subtype == INITIALIZE_SUBTYPE) - priv->ucode_type = UCODE_NONE; - queue_work(priv->workqueue, &priv->restart); - } -} - static void iwl_rx_reply_error(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb) { @@ -1125,7 +1076,6 @@ void iwl_setup_rx_handlers(struct iwl_priv *priv) handlers = priv->rx_handlers; - handlers[REPLY_ALIVE] = iwl_rx_reply_alive; handlers[REPLY_ERROR] = iwl_rx_reply_error; handlers[CHANNEL_SWITCH_NOTIFICATION] = iwl_rx_csa; handlers[SPECTRUM_MEASURE_NOTIFICATION] = iwl_rx_spectrum_measure_notif; -- cgit v0.10.2 From dbf28e21ca391110e90ccad05dda79d2e2f60e0e Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Sat, 16 Apr 2011 08:29:24 -0700 Subject: iwlagn: combine firmware code/data On new hardware, ucode images always come in pairs: code and data. Therefore, combine the variables into an appropriate struct and use that when both code and data are needed. Also, combine allocation and copying so that we have less code in total. Signed-off-by: Johannes Berg Signed-off-by: Wey-Yi Guy diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-ucode.c b/drivers/net/wireless/iwlwifi/iwl-agn-ucode.c index 56dc771..c3ae2e4 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-ucode.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-ucode.c @@ -161,17 +161,16 @@ static int iwlagn_load_section(struct iwl_priv *priv, const char *name, } static int iwlagn_load_given_ucode(struct iwl_priv *priv, - struct fw_desc *inst_image, - struct fw_desc *data_image) + struct fw_img *image) { int ret = 0; - ret = iwlagn_load_section(priv, "INST", inst_image, + ret = iwlagn_load_section(priv, "INST", &image->code, IWLAGN_RTC_INST_LOWER_BOUND); if (ret) return ret; - return iwlagn_load_section(priv, "DATA", data_image, + return iwlagn_load_section(priv, "DATA", &image->data, IWLAGN_RTC_DATA_LOWER_BOUND); } @@ -557,16 +556,16 @@ static void iwl_print_mismatch_inst(struct iwl_priv *priv, * iwl_verify_ucode - determine which instruction image is in SRAM, * and verify its contents */ -static int iwl_verify_ucode(struct iwl_priv *priv, struct fw_desc *fw_desc) +static int iwl_verify_ucode(struct iwl_priv *priv, struct fw_img *img) { - if (!iwlcore_verify_inst_sparse(priv, fw_desc)) { + if (!iwlcore_verify_inst_sparse(priv, &img->code)) { IWL_DEBUG_INFO(priv, "uCode is good in inst SRAM\n"); return 0; } IWL_ERR(priv, "UCODE IMAGE IN INSTRUCTION SRAM NOT VALID!!\n"); - iwl_print_mismatch_inst(priv, fw_desc); + iwl_print_mismatch_inst(priv, &img->code); return -EIO; } @@ -602,8 +601,7 @@ static void iwlagn_alive_fn(struct iwl_priv *priv, #define UCODE_CALIB_TIMEOUT (2*HZ) int iwlagn_load_ucode_wait_alive(struct iwl_priv *priv, - struct fw_desc *inst_image, - struct fw_desc *data_image, + struct fw_img *image, int subtype, int alternate_subtype) { struct iwl_notification_wait alive_wait; @@ -621,7 +619,7 @@ int iwlagn_load_ucode_wait_alive(struct iwl_priv *priv, old_type = priv->ucode_type; priv->ucode_type = subtype; - ret = iwlagn_load_given_ucode(priv, inst_image, data_image); + ret = iwlagn_load_given_ucode(priv, image); if (ret) { priv->ucode_type = old_type; iwlagn_remove_notification(priv, &alive_wait); @@ -656,7 +654,7 @@ int iwlagn_load_ucode_wait_alive(struct iwl_priv *priv, return -EIO; } - ret = iwl_verify_ucode(priv, inst_image); + ret = iwl_verify_ucode(priv, image); if (ret) { priv->ucode_type = old_type; return ret; @@ -684,7 +682,7 @@ int iwlagn_run_init_ucode(struct iwl_priv *priv) lockdep_assert_held(&priv->mutex); /* No init ucode required? Curious, but maybe ok */ - if (!priv->ucode_init.len) + if (!priv->ucode_init.code.len) return 0; if (priv->ucode_type != UCODE_SUBTYPE_NONE_LOADED) @@ -696,7 +694,6 @@ int iwlagn_run_init_ucode(struct iwl_priv *priv) /* Will also start the device */ ret = iwlagn_load_ucode_wait_alive(priv, &priv->ucode_init, - &priv->ucode_init_data, UCODE_SUBTYPE_INIT, -1); if (ret) goto error; diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index 12cd5e0..f30735b 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -1173,12 +1173,42 @@ static struct attribute_group iwl_attribute_group = { * ******************************************************************************/ +static void iwl_free_fw_desc(struct pci_dev *pci_dev, struct fw_desc *desc) +{ + if (desc->v_addr) + dma_free_coherent(&pci_dev->dev, desc->len, + desc->v_addr, desc->p_addr); + desc->v_addr = NULL; + desc->len = 0; +} + +static void iwl_free_fw_img(struct pci_dev *pci_dev, struct fw_img *img) +{ + iwl_free_fw_desc(pci_dev, &img->code); + iwl_free_fw_desc(pci_dev, &img->data); +} + +static int iwl_alloc_fw_desc(struct pci_dev *pci_dev, struct fw_desc *desc, + const void *data, size_t len) +{ + if (!len) { + desc->v_addr = NULL; + return -EINVAL; + } + + desc->v_addr = dma_alloc_coherent(&pci_dev->dev, len, + &desc->p_addr, GFP_KERNEL); + if (!desc->v_addr) + return -ENOMEM; + desc->len = len; + memcpy(desc->v_addr, data, len); + return 0; +} + static void iwl_dealloc_ucode_pci(struct iwl_priv *priv) { - iwl_free_fw_desc(priv->pci_dev, &priv->ucode_code); - iwl_free_fw_desc(priv->pci_dev, &priv->ucode_data); - iwl_free_fw_desc(priv->pci_dev, &priv->ucode_init); - iwl_free_fw_desc(priv->pci_dev, &priv->ucode_init_data); + iwl_free_fw_img(priv->pci_dev, &priv->ucode_rt); + iwl_free_fw_img(priv->pci_dev, &priv->ucode_init); } struct iwlagn_ucode_capabilities { @@ -1647,24 +1677,20 @@ static void iwl_ucode_callback(const struct firmware *ucode_raw, void *context) /* Runtime instructions and 2 copies of data: * 1) unmodified from disk * 2) backup cache for save/restore during power-downs */ - priv->ucode_code.len = pieces.inst_size; - iwl_alloc_fw_desc(priv->pci_dev, &priv->ucode_code); - - priv->ucode_data.len = pieces.data_size; - iwl_alloc_fw_desc(priv->pci_dev, &priv->ucode_data); - - if (!priv->ucode_code.v_addr || !priv->ucode_data.v_addr) + if (iwl_alloc_fw_desc(priv->pci_dev, &priv->ucode_rt.code, + pieces.inst, pieces.inst_size)) + goto err_pci_alloc; + if (iwl_alloc_fw_desc(priv->pci_dev, &priv->ucode_rt.data, + pieces.data, pieces.data_size)) goto err_pci_alloc; /* Initialization instructions and data */ if (pieces.init_size && pieces.init_data_size) { - priv->ucode_init.len = pieces.init_size; - iwl_alloc_fw_desc(priv->pci_dev, &priv->ucode_init); - - priv->ucode_init_data.len = pieces.init_data_size; - iwl_alloc_fw_desc(priv->pci_dev, &priv->ucode_init_data); - - if (!priv->ucode_init.v_addr || !priv->ucode_init_data.v_addr) + if (iwl_alloc_fw_desc(priv->pci_dev, &priv->ucode_init.code, + pieces.init, pieces.init_size)) + goto err_pci_alloc; + if (iwl_alloc_fw_desc(priv->pci_dev, &priv->ucode_init.data, + pieces.init_data, pieces.init_data_size)) goto err_pci_alloc; } @@ -1701,39 +1727,6 @@ static void iwl_ucode_callback(const struct firmware *ucode_raw, void *context) else priv->cmd_queue = IWL_DEFAULT_CMD_QUEUE_NUM; - /* Copy images into buffers for card's bus-master reads ... */ - - /* Runtime instructions (first block of data in file) */ - IWL_DEBUG_INFO(priv, "Copying (but not loading) uCode instr len %Zd\n", - pieces.inst_size); - memcpy(priv->ucode_code.v_addr, pieces.inst, pieces.inst_size); - - IWL_DEBUG_INFO(priv, "uCode instr buf vaddr = 0x%p, paddr = 0x%08x\n", - priv->ucode_code.v_addr, (u32)priv->ucode_code.p_addr); - - /* - * Runtime data - * NOTE: Copy into backup buffer will be done in iwl_up() - */ - IWL_DEBUG_INFO(priv, "Copying (but not loading) uCode data len %Zd\n", - pieces.data_size); - memcpy(priv->ucode_data.v_addr, pieces.data, pieces.data_size); - - /* Initialization instructions */ - if (pieces.init_size) { - IWL_DEBUG_INFO(priv, "Copying (but not loading) init instr len %Zd\n", - pieces.init_size); - memcpy(priv->ucode_init.v_addr, pieces.init, pieces.init_size); - } - - /* Initialization data */ - if (pieces.init_data_size) { - IWL_DEBUG_INFO(priv, "Copying (but not loading) init data len %Zd\n", - pieces.init_data_size); - memcpy(priv->ucode_init_data.v_addr, pieces.init_data, - pieces.init_data_size); - } - /* * figure out the offset of chain noise reset and gain commands * base on the size of standard phy calibration commands table size @@ -2450,8 +2443,7 @@ static int __iwl_up(struct iwl_priv *priv) } ret = iwlagn_load_ucode_wait_alive(priv, - &priv->ucode_code, - &priv->ucode_data, + &priv->ucode_rt, UCODE_SUBTYPE_REGULAR, UCODE_SUBTYPE_REGULAR_NEW); if (ret) { diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.h b/drivers/net/wireless/iwlwifi/iwl-agn.h index cf05f87..c475ac4 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.h +++ b/drivers/net/wireless/iwlwifi/iwl-agn.h @@ -164,8 +164,7 @@ int iwlagn_send_bt_env(struct iwl_priv *priv, u8 action, u8 type); void iwlagn_send_prio_tbl(struct iwl_priv *priv); int iwlagn_run_init_ucode(struct iwl_priv *priv); int iwlagn_load_ucode_wait_alive(struct iwl_priv *priv, - struct fw_desc *inst_image, - struct fw_desc *data_image, + struct fw_img *image, int subtype, int alternate_subtype); /* lib */ diff --git a/drivers/net/wireless/iwlwifi/iwl-debugfs.c b/drivers/net/wireless/iwlwifi/iwl-debugfs.c index 2b60688..7bd4f5a 100644 --- a/drivers/net/wireless/iwlwifi/iwl-debugfs.c +++ b/drivers/net/wireless/iwlwifi/iwl-debugfs.c @@ -227,9 +227,9 @@ static ssize_t iwl_dbgfs_sram_read(struct file *file, if (!priv->dbgfs_sram_offset && !priv->dbgfs_sram_len) { priv->dbgfs_sram_offset = 0x800000; if (priv->ucode_type == UCODE_SUBTYPE_INIT) - priv->dbgfs_sram_len = priv->ucode_init_data.len; + priv->dbgfs_sram_len = priv->ucode_init.data.len; else - priv->dbgfs_sram_len = priv->ucode_data.len; + priv->dbgfs_sram_len = priv->ucode_rt.data.len; } len = priv->dbgfs_sram_len; diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index 414968c..857eb0e 100644 --- a/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h @@ -479,6 +479,10 @@ struct fw_desc { u32 len; /* bytes */ }; +struct fw_img { + struct fw_desc code, data; +}; + /* v1/v2 uCode file layout */ struct iwl_ucode_header { __le32 ver; /* major/minor/API/serial */ @@ -1266,10 +1270,9 @@ struct iwl_priv { int fw_index; /* firmware we're trying to load */ u32 ucode_ver; /* version of ucode, copy of iwl_ucode.ver */ - struct fw_desc ucode_code; /* runtime inst */ - struct fw_desc ucode_data; /* runtime data original */ - struct fw_desc ucode_init; /* initialization inst */ - struct fw_desc ucode_init_data; /* initialization data */ + struct fw_img ucode_rt; + struct fw_img ucode_init; + enum iwlagn_ucode_subtype ucode_type; u8 ucode_write_complete; /* the image write is complete */ char firmware_name[25]; diff --git a/drivers/net/wireless/iwlwifi/iwl-helpers.h b/drivers/net/wireless/iwlwifi/iwl-helpers.h index 9309ff2..41207a3 100644 --- a/drivers/net/wireless/iwlwifi/iwl-helpers.h +++ b/drivers/net/wireless/iwlwifi/iwl-helpers.h @@ -64,30 +64,6 @@ static inline int iwl_queue_dec_wrap(int index, int n_bd) return --index & (n_bd - 1); } -/* TODO: Move fw_desc functions to iwl-pci.ko */ -static inline void iwl_free_fw_desc(struct pci_dev *pci_dev, - struct fw_desc *desc) -{ - if (desc->v_addr) - dma_free_coherent(&pci_dev->dev, desc->len, - desc->v_addr, desc->p_addr); - desc->v_addr = NULL; - desc->len = 0; -} - -static inline int iwl_alloc_fw_desc(struct pci_dev *pci_dev, - struct fw_desc *desc) -{ - if (!desc->len) { - desc->v_addr = NULL; - return -EINVAL; - } - - desc->v_addr = dma_alloc_coherent(&pci_dev->dev, desc->len, - &desc->p_addr, GFP_KERNEL); - return (desc->v_addr != NULL) ? 0 : -ENOMEM; -} - /* * we have 8 bits used like this: * -- cgit v0.10.2 From 4cd2bf76a40a148bc92f4a3d17bc7f94277b0410 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 13 Apr 2011 03:14:52 -0700 Subject: iwlagn: remove hw_ready variable This variable is only ever checked right after the function that sets it, but the same function will also return the status, so we can pass it through instead of checking hw_ready later. Signed-off-by: Johannes Berg Signed-off-by: Wey-Yi Guy diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-lib.c b/drivers/net/wireless/iwlwifi/iwl-agn-lib.c index 8216e5c..e202a40 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-lib.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-lib.c @@ -2306,8 +2306,7 @@ int iwlagn_start_device(struct iwl_priv *priv) { int ret; - iwl_prepare_card_hw(priv); - if (!priv->hw_ready) { + if (iwl_prepare_card_hw(priv)) { IWL_WARN(priv, "Exit HW not ready\n"); return -EIO; } diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index f30735b..a4f1009 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -2367,9 +2367,10 @@ static void iwl_down(struct iwl_priv *priv) #define HW_READY_TIMEOUT (50) +/* Note: returns poll_bit return value, which is >= 0 if success */ static int iwl_set_hw_ready(struct iwl_priv *priv) { - int ret = 0; + int ret; iwl_set_bit(priv, CSR_HW_IF_CONFIG_REG, CSR_HW_IF_CONFIG_REG_BIT_NIC_READY); @@ -2379,25 +2380,21 @@ static int iwl_set_hw_ready(struct iwl_priv *priv) CSR_HW_IF_CONFIG_REG_BIT_NIC_READY, CSR_HW_IF_CONFIG_REG_BIT_NIC_READY, HW_READY_TIMEOUT); - if (ret != -ETIMEDOUT) - priv->hw_ready = true; - else - priv->hw_ready = false; - IWL_DEBUG_INFO(priv, "hardware %s\n", - (priv->hw_ready == 1) ? "ready" : "not ready"); + IWL_DEBUG_INFO(priv, "hardware%s ready\n", ret < 0 ? " not" : ""); return ret; } +/* Note: returns standard 0/-ERROR code */ int iwl_prepare_card_hw(struct iwl_priv *priv) { - int ret = 0; + int ret; IWL_DEBUG_INFO(priv, "iwl_prepare_card_hw enter\n"); ret = iwl_set_hw_ready(priv); - if (priv->hw_ready) - return ret; + if (ret >= 0) + return 0; /* If HW is not ready, prepare the conditions to check again */ iwl_set_bit(priv, CSR_HW_IF_CONFIG_REG, @@ -2407,10 +2404,13 @@ int iwl_prepare_card_hw(struct iwl_priv *priv) ~CSR_HW_IF_CONFIG_REG_BIT_NIC_PREPARE_DONE, CSR_HW_IF_CONFIG_REG_BIT_NIC_PREPARE_DONE, 150000); - /* HW should be ready by now, check again. */ - if (ret != -ETIMEDOUT) - iwl_set_hw_ready(priv); + if (ret < 0) + return ret; + /* HW should be ready by now, check again. */ + ret = iwl_set_hw_ready(priv); + if (ret >= 0) + return 0; return ret; } @@ -3741,8 +3741,7 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) * PCI Tx retries from interfering with C3 CPU state */ pci_write_config_byte(pdev, PCI_CFG_RETRY_TIMEOUT, 0x00); - iwl_prepare_card_hw(priv); - if (!priv->hw_ready) { + if (iwl_prepare_card_hw(priv)) { IWL_WARN(priv, "Failed, HW not ready\n"); goto out_iounmap; } diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index 857eb0e..197fa74 100644 --- a/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h @@ -1503,7 +1503,6 @@ struct iwl_priv { struct timer_list statistics_periodic; struct timer_list ucode_trace; struct timer_list watchdog; - bool hw_ready; struct iwl_event_log event_log; -- cgit v0.10.2 From b71d1d426d263b0b6cb5760322efebbfc89d4463 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Fri, 22 Apr 2011 04:53:02 +0000 Subject: inet: constify ip headers and in6_addr Add const qualifiers to structs iphdr, ipv6hdr and in6_addr pointers where possible, to make code intention more obvious. Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller diff --git a/include/net/addrconf.h b/include/net/addrconf.h index 23710aa..7c4d92c 100644 --- a/include/net/addrconf.h +++ b/include/net/addrconf.h @@ -61,16 +61,16 @@ extern int addrconf_set_dstaddr(struct net *net, void __user *arg); extern int ipv6_chk_addr(struct net *net, - struct in6_addr *addr, + const struct in6_addr *addr, struct net_device *dev, int strict); #if defined(CONFIG_IPV6_MIP6) || defined(CONFIG_IPV6_MIP6_MODULE) extern int ipv6_chk_home_addr(struct net *net, - struct in6_addr *addr); + const struct in6_addr *addr); #endif -extern int ipv6_chk_prefix(struct in6_addr *addr, +extern int ipv6_chk_prefix(const struct in6_addr *addr, struct net_device *dev); extern struct inet6_ifaddr *ipv6_get_ifaddr(struct net *net, @@ -89,9 +89,9 @@ extern int ipv6_get_lladdr(struct net_device *dev, extern int ipv6_rcv_saddr_equal(const struct sock *sk, const struct sock *sk2); extern void addrconf_join_solict(struct net_device *dev, - struct in6_addr *addr); + const struct in6_addr *addr); extern void addrconf_leave_solict(struct inet6_dev *idev, - struct in6_addr *addr); + const struct in6_addr *addr); static inline unsigned long addrconf_timeout_fixup(u32 timeout, unsigned unit) @@ -158,15 +158,15 @@ extern void addrconf_prefix_rcv(struct net_device *dev, u8 *opt, int len); /* * anycast prototypes (anycast.c) */ -extern int ipv6_sock_ac_join(struct sock *sk,int ifindex,struct in6_addr *addr); -extern int ipv6_sock_ac_drop(struct sock *sk,int ifindex,struct in6_addr *addr); +extern int ipv6_sock_ac_join(struct sock *sk,int ifindex, const struct in6_addr *addr); +extern int ipv6_sock_ac_drop(struct sock *sk,int ifindex, const struct in6_addr *addr); extern void ipv6_sock_ac_close(struct sock *sk); -extern int inet6_ac_check(struct sock *sk, struct in6_addr *addr, int ifindex); +extern int inet6_ac_check(struct sock *sk, const struct in6_addr *addr, int ifindex); -extern int ipv6_dev_ac_inc(struct net_device *dev, struct in6_addr *addr); -extern int __ipv6_dev_ac_dec(struct inet6_dev *idev, struct in6_addr *addr); +extern int ipv6_dev_ac_inc(struct net_device *dev, const struct in6_addr *addr); +extern int __ipv6_dev_ac_dec(struct inet6_dev *idev, const struct in6_addr *addr); extern int ipv6_chk_acast_addr(struct net *net, struct net_device *dev, - struct in6_addr *addr); + const struct in6_addr *addr); /* Device notifier */ diff --git a/include/net/if_inet6.h b/include/net/if_inet6.h index fccc218..3d982f7 100644 --- a/include/net/if_inet6.h +++ b/include/net/if_inet6.h @@ -196,7 +196,7 @@ struct inet6_dev { struct rcu_head rcu; }; -static inline void ipv6_eth_mc_map(struct in6_addr *addr, char *buf) +static inline void ipv6_eth_mc_map(const struct in6_addr *addr, char *buf) { /* * +-------+-------+-------+-------+-------+-------+ @@ -210,7 +210,7 @@ static inline void ipv6_eth_mc_map(struct in6_addr *addr, char *buf) memcpy(buf + 2, &addr->s6_addr32[3], sizeof(__u32)); } -static inline void ipv6_tr_mc_map(struct in6_addr *addr, char *buf) +static inline void ipv6_tr_mc_map(const struct in6_addr *addr, char *buf) { /* All nodes FF01::1, FF02::1, FF02::1:FFxx:xxxx */ diff --git a/include/net/inetpeer.h b/include/net/inetpeer.h index e6dd8da6..8a159cc 100644 --- a/include/net/inetpeer.h +++ b/include/net/inetpeer.h @@ -80,7 +80,7 @@ static inline struct inet_peer *inet_getpeer_v4(__be32 v4daddr, int create) return inet_getpeer(&daddr, create); } -static inline struct inet_peer *inet_getpeer_v6(struct in6_addr *v6daddr, int create) +static inline struct inet_peer *inet_getpeer_v6(const struct in6_addr *v6daddr, int create) { struct inetpeer_addr daddr; diff --git a/include/net/ip6_fib.h b/include/net/ip6_fib.h index 98348d5..aca8ef4 100644 --- a/include/net/ip6_fib.h +++ b/include/net/ip6_fib.h @@ -198,12 +198,12 @@ extern struct dst_entry *fib6_rule_lookup(struct net *net, pol_lookup_t lookup); extern struct fib6_node *fib6_lookup(struct fib6_node *root, - struct in6_addr *daddr, - struct in6_addr *saddr); + const struct in6_addr *daddr, + const struct in6_addr *saddr); struct fib6_node *fib6_locate(struct fib6_node *root, - struct in6_addr *daddr, int dst_len, - struct in6_addr *saddr, int src_len); + const struct in6_addr *daddr, int dst_len, + const struct in6_addr *saddr, int src_len); extern void fib6_clean_all(struct net *net, int (*func)(struct rt6_info *, void *arg), diff --git a/include/net/ip6_route.h b/include/net/ip6_route.h index 86b1cb4..d5c21d4 100644 --- a/include/net/ip6_route.h +++ b/include/net/ip6_route.h @@ -86,7 +86,7 @@ extern int ip6_del_rt(struct rt6_info *); extern int ip6_route_get_saddr(struct net *net, struct rt6_info *rt, - struct in6_addr *daddr, + const struct in6_addr *daddr, unsigned int prefs, struct in6_addr *saddr); @@ -112,9 +112,9 @@ extern int ip6_dst_hoplimit(struct dst_entry *dst); * support functions for ND * */ -extern struct rt6_info * rt6_get_dflt_router(struct in6_addr *addr, +extern struct rt6_info * rt6_get_dflt_router(const struct in6_addr *addr, struct net_device *dev); -extern struct rt6_info * rt6_add_dflt_router(struct in6_addr *gwaddr, +extern struct rt6_info * rt6_add_dflt_router(const struct in6_addr *gwaddr, struct net_device *dev, unsigned int pref); @@ -122,17 +122,17 @@ extern void rt6_purge_dflt_routers(struct net *net); extern int rt6_route_rcv(struct net_device *dev, u8 *opt, int len, - struct in6_addr *gwaddr); + const struct in6_addr *gwaddr); -extern void rt6_redirect(struct in6_addr *dest, - struct in6_addr *src, - struct in6_addr *saddr, +extern void rt6_redirect(const struct in6_addr *dest, + const struct in6_addr *src, + const struct in6_addr *saddr, struct neighbour *neigh, u8 *lladdr, int on_link); -extern void rt6_pmtu_discovery(struct in6_addr *daddr, - struct in6_addr *saddr, +extern void rt6_pmtu_discovery(const struct in6_addr *daddr, + const struct in6_addr *saddr, struct net_device *dev, u32 pmtu); diff --git a/include/net/ipv6.h b/include/net/ipv6.h index 34200f9..5da1926 100644 --- a/include/net/ipv6.h +++ b/include/net/ipv6.h @@ -376,8 +376,8 @@ enum ip6_defrag_users { struct ip6_create_arg { __be32 id; u32 user; - struct in6_addr *src; - struct in6_addr *dst; + const struct in6_addr *src; + const struct in6_addr *dst; }; void ip6_frag_init(struct inet_frag_queue *q, void *a); diff --git a/include/net/ndisc.h b/include/net/ndisc.h index e0e594f..6144685 100644 --- a/include/net/ndisc.h +++ b/include/net/ndisc.h @@ -102,7 +102,8 @@ extern void ndisc_send_redirect(struct sk_buff *skb, struct neighbour *neigh, const struct in6_addr *target); -extern int ndisc_mc_map(struct in6_addr *addr, char *buf, struct net_device *dev, int dir); +extern int ndisc_mc_map(const struct in6_addr *addr, char *buf, + struct net_device *dev, int dir); extern struct sk_buff *ndisc_build_skb(struct net_device *dev, const struct in6_addr *daddr, diff --git a/include/net/route.h b/include/net/route.h index 3782cdd..b3962e2 100644 --- a/include/net/route.h +++ b/include/net/route.h @@ -191,7 +191,8 @@ static inline int ip_route_input_noref(struct sk_buff *skb, __be32 dst, __be32 s return ip_route_input_common(skb, dst, src, tos, devin, true); } -extern unsigned short ip_rt_frag_needed(struct net *net, struct iphdr *iph, unsigned short new_mtu, struct net_device *dev); +extern unsigned short ip_rt_frag_needed(struct net *net, const struct iphdr *iph, + unsigned short new_mtu, struct net_device *dev); extern void ip_rt_send_redirect(struct sk_buff *skb); extern unsigned inet_addr_type(struct net *net, __be32 addr); diff --git a/include/net/xfrm.h b/include/net/xfrm.h index 65ea313..1cdd4b7 100644 --- a/include/net/xfrm.h +++ b/include/net/xfrm.h @@ -1475,7 +1475,7 @@ extern int xfrm6_input_addr(struct sk_buff *skb, xfrm_address_t *daddr, extern int xfrm6_tunnel_register(struct xfrm6_tunnel *handler, unsigned short family); extern int xfrm6_tunnel_deregister(struct xfrm6_tunnel *handler, unsigned short family); extern __be32 xfrm6_tunnel_alloc_spi(struct net *net, xfrm_address_t *saddr); -extern __be32 xfrm6_tunnel_spi_lookup(struct net *net, xfrm_address_t *saddr); +extern __be32 xfrm6_tunnel_spi_lookup(struct net *net, const xfrm_address_t *saddr); extern int xfrm6_extract_output(struct xfrm_state *x, struct sk_buff *skb); extern int xfrm6_prepare_output(struct xfrm_state *x, struct sk_buff *skb); extern int xfrm6_output(struct sk_buff *skb); @@ -1569,8 +1569,8 @@ static inline int xfrm_addr_cmp(const xfrm_address_t *a, case AF_INET: return (__force u32)a->a4 - (__force u32)b->a4; case AF_INET6: - return ipv6_addr_cmp((struct in6_addr *)a, - (struct in6_addr *)b); + return ipv6_addr_cmp((const struct in6_addr *)a, + (const struct in6_addr *)b); } } diff --git a/net/bridge/br_multicast.c b/net/bridge/br_multicast.c index 59660c9..2f14eaf 100644 --- a/net/bridge/br_multicast.c +++ b/net/bridge/br_multicast.c @@ -413,7 +413,7 @@ out: #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) static struct sk_buff *br_ip6_multicast_alloc_query(struct net_bridge *br, - struct in6_addr *group) + const struct in6_addr *group) { struct sk_buff *skb; struct ipv6hdr *ip6h; @@ -1115,7 +1115,7 @@ static int br_ip4_multicast_query(struct net_bridge *br, struct net_bridge_port *port, struct sk_buff *skb) { - struct iphdr *iph = ip_hdr(skb); + const struct iphdr *iph = ip_hdr(skb); struct igmphdr *ih = igmp_hdr(skb); struct net_bridge_mdb_entry *mp; struct igmpv3_query *ih3; @@ -1190,7 +1190,7 @@ static int br_ip6_multicast_query(struct net_bridge *br, struct net_bridge_port *port, struct sk_buff *skb) { - struct ipv6hdr *ip6h = ipv6_hdr(skb); + const struct ipv6hdr *ip6h = ipv6_hdr(skb); struct mld_msg *mld = (struct mld_msg *) icmp6_hdr(skb); struct net_bridge_mdb_entry *mp; struct mld2_query *mld2q; @@ -1198,7 +1198,7 @@ static int br_ip6_multicast_query(struct net_bridge *br, struct net_bridge_port_group __rcu **pp; unsigned long max_delay; unsigned long now = jiffies; - struct in6_addr *group = NULL; + const struct in6_addr *group = NULL; int err = 0; spin_lock(&br->multicast_lock); @@ -1356,7 +1356,7 @@ static int br_multicast_ipv4_rcv(struct net_bridge *br, struct sk_buff *skb) { struct sk_buff *skb2 = skb; - struct iphdr *iph; + const struct iphdr *iph; struct igmphdr *ih; unsigned len; unsigned offset; @@ -1452,7 +1452,7 @@ static int br_multicast_ipv6_rcv(struct net_bridge *br, struct sk_buff *skb) { struct sk_buff *skb2; - struct ipv6hdr *ip6h; + const struct ipv6hdr *ip6h; struct icmp6hdr *icmp6h; u8 nexthdr; unsigned len; diff --git a/net/bridge/br_netfilter.c b/net/bridge/br_netfilter.c index f3bc322..5614907 100644 --- a/net/bridge/br_netfilter.c +++ b/net/bridge/br_netfilter.c @@ -219,7 +219,7 @@ static inline void nf_bridge_update_protocol(struct sk_buff *skb) static int br_parse_ip_options(struct sk_buff *skb) { struct ip_options *opt; - struct iphdr *iph; + const struct iphdr *iph; struct net_device *dev = skb->dev; u32 len; @@ -554,7 +554,7 @@ static unsigned int br_nf_pre_routing_ipv6(unsigned int hook, const struct net_device *out, int (*okfn)(struct sk_buff *)) { - struct ipv6hdr *hdr; + const struct ipv6hdr *hdr; u32 pkt_len; if (skb->len < sizeof(struct ipv6hdr)) diff --git a/net/core/dev.c b/net/core/dev.c index 3871bf6..379c993 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -2502,8 +2502,8 @@ static inline void ____napi_schedule(struct softnet_data *sd, __u32 __skb_get_rxhash(struct sk_buff *skb) { int nhoff, hash = 0, poff; - struct ipv6hdr *ip6; - struct iphdr *ip; + const struct ipv6hdr *ip6; + const struct iphdr *ip; u8 ip_proto; u32 addr1, addr2, ihl; union { @@ -2518,7 +2518,7 @@ __u32 __skb_get_rxhash(struct sk_buff *skb) if (!pskb_may_pull(skb, sizeof(*ip) + nhoff)) goto done; - ip = (struct iphdr *) (skb->data + nhoff); + ip = (const struct iphdr *) (skb->data + nhoff); if (ip->frag_off & htons(IP_MF | IP_OFFSET)) ip_proto = 0; else @@ -2531,7 +2531,7 @@ __u32 __skb_get_rxhash(struct sk_buff *skb) if (!pskb_may_pull(skb, sizeof(*ip6) + nhoff)) goto done; - ip6 = (struct ipv6hdr *) (skb->data + nhoff); + ip6 = (const struct ipv6hdr *) (skb->data + nhoff); ip_proto = ip6->nexthdr; addr1 = (__force u32) ip6->saddr.s6_addr32[3]; addr2 = (__force u32) ip6->daddr.s6_addr32[3]; diff --git a/net/core/netpoll.c b/net/core/netpoll.c index 06be243..46d9c3a 100644 --- a/net/core/netpoll.c +++ b/net/core/netpoll.c @@ -539,7 +539,7 @@ int __netpoll_rx(struct sk_buff *skb) { int proto, len, ulen; int hits = 0; - struct iphdr *iph; + const struct iphdr *iph; struct udphdr *uh; struct netpoll_info *npinfo = skb->dev->npinfo; struct netpoll *np, *tmp; diff --git a/net/dccp/ipv6.c b/net/dccp/ipv6.c index de1b7e3..73add23 100644 --- a/net/dccp/ipv6.c +++ b/net/dccp/ipv6.c @@ -54,8 +54,8 @@ static void dccp_v6_hash(struct sock *sk) /* add pseudo-header to DCCP checksum stored in skb->csum */ static inline __sum16 dccp_v6_csum_finish(struct sk_buff *skb, - struct in6_addr *saddr, - struct in6_addr *daddr) + const struct in6_addr *saddr, + const struct in6_addr *daddr) { return csum_ipv6_magic(saddr, daddr, skb->len, IPPROTO_DCCP, skb->csum); } @@ -87,7 +87,7 @@ static inline __u32 dccp_v6_init_sequence(struct sk_buff *skb) static void dccp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, u8 type, u8 code, int offset, __be32 info) { - struct ipv6hdr *hdr = (struct ipv6hdr *)skb->data; + const struct ipv6hdr *hdr = (const struct ipv6hdr *)skb->data; const struct dccp_hdr *dh = (struct dccp_hdr *)(skb->data + offset); struct dccp_sock *dp; struct ipv6_pinfo *np; @@ -296,7 +296,7 @@ static void dccp_v6_reqsk_destructor(struct request_sock *req) static void dccp_v6_ctl_send_reset(struct sock *sk, struct sk_buff *rxskb) { - struct ipv6hdr *rxip6h; + const struct ipv6hdr *rxip6h; struct sk_buff *skb; struct flowi6 fl6; struct net *net = dev_net(skb_dst(rxskb)->dev); diff --git a/net/ipv4/af_inet.c b/net/ipv4/af_inet.c index 807d83c..cae75ef 100644 --- a/net/ipv4/af_inet.c +++ b/net/ipv4/af_inet.c @@ -1186,7 +1186,7 @@ EXPORT_SYMBOL(inet_sk_rebuild_header); static int inet_gso_send_check(struct sk_buff *skb) { - struct iphdr *iph; + const struct iphdr *iph; const struct net_protocol *ops; int proto; int ihl; @@ -1293,7 +1293,7 @@ static struct sk_buff **inet_gro_receive(struct sk_buff **head, const struct net_protocol *ops; struct sk_buff **pp = NULL; struct sk_buff *p; - struct iphdr *iph; + const struct iphdr *iph; unsigned int hlen; unsigned int off; unsigned int id; diff --git a/net/ipv4/ah4.c b/net/ipv4/ah4.c index 4286fd3..c1f4154 100644 --- a/net/ipv4/ah4.c +++ b/net/ipv4/ah4.c @@ -73,7 +73,7 @@ static inline struct scatterlist *ah_req_sg(struct crypto_ahash *ahash, * into IP header for icv calculation. Options are already checked * for validity, so paranoia is not required. */ -static int ip_clear_mutable_options(struct iphdr *iph, __be32 *daddr) +static int ip_clear_mutable_options(const struct iphdr *iph, __be32 *daddr) { unsigned char * optptr = (unsigned char*)(iph+1); int l = iph->ihl*4 - sizeof(struct iphdr); @@ -396,7 +396,7 @@ out: static void ah4_err(struct sk_buff *skb, u32 info) { struct net *net = dev_net(skb->dev); - struct iphdr *iph = (struct iphdr *)skb->data; + const struct iphdr *iph = (const struct iphdr *)skb->data; struct ip_auth_hdr *ah = (struct ip_auth_hdr *)(skb->data+(iph->ihl<<2)); struct xfrm_state *x; @@ -404,7 +404,8 @@ static void ah4_err(struct sk_buff *skb, u32 info) icmp_hdr(skb)->code != ICMP_FRAG_NEEDED) return; - x = xfrm_state_lookup(net, skb->mark, (xfrm_address_t *)&iph->daddr, ah->spi, IPPROTO_AH, AF_INET); + x = xfrm_state_lookup(net, skb->mark, (const xfrm_address_t *)&iph->daddr, + ah->spi, IPPROTO_AH, AF_INET); if (!x) return; printk(KERN_DEBUG "pmtu discovery on SA AH/%08x/%08x\n", diff --git a/net/ipv4/esp4.c b/net/ipv4/esp4.c index 03f994b..a5b4134 100644 --- a/net/ipv4/esp4.c +++ b/net/ipv4/esp4.c @@ -276,7 +276,7 @@ error: static int esp_input_done2(struct sk_buff *skb, int err) { - struct iphdr *iph; + const struct iphdr *iph; struct xfrm_state *x = xfrm_input_state(skb); struct esp_data *esp = x->data; struct crypto_aead *aead = esp->aead; @@ -484,7 +484,7 @@ static u32 esp4_get_mtu(struct xfrm_state *x, int mtu) static void esp4_err(struct sk_buff *skb, u32 info) { struct net *net = dev_net(skb->dev); - struct iphdr *iph = (struct iphdr *)skb->data; + const struct iphdr *iph = (const struct iphdr *)skb->data; struct ip_esp_hdr *esph = (struct ip_esp_hdr *)(skb->data+(iph->ihl<<2)); struct xfrm_state *x; @@ -492,7 +492,8 @@ static void esp4_err(struct sk_buff *skb, u32 info) icmp_hdr(skb)->code != ICMP_FRAG_NEEDED) return; - x = xfrm_state_lookup(net, skb->mark, (xfrm_address_t *)&iph->daddr, esph->spi, IPPROTO_ESP, AF_INET); + x = xfrm_state_lookup(net, skb->mark, (const xfrm_address_t *)&iph->daddr, + esph->spi, IPPROTO_ESP, AF_INET); if (!x) return; NETDEBUG(KERN_DEBUG "pmtu discovery on SA ESP/%08x/%08x\n", diff --git a/net/ipv4/icmp.c b/net/ipv4/icmp.c index e5f8a71..74e35e5 100644 --- a/net/ipv4/icmp.c +++ b/net/ipv4/icmp.c @@ -373,7 +373,7 @@ out_unlock: } static struct rtable *icmp_route_lookup(struct net *net, struct sk_buff *skb_in, - struct iphdr *iph, + const struct iphdr *iph, __be32 saddr, u8 tos, int type, int code, struct icmp_bxm *param) @@ -637,7 +637,7 @@ EXPORT_SYMBOL(icmp_send); static void icmp_unreach(struct sk_buff *skb) { - struct iphdr *iph; + const struct iphdr *iph; struct icmphdr *icmph; int hash, protocol; const struct net_protocol *ipprot; @@ -656,7 +656,7 @@ static void icmp_unreach(struct sk_buff *skb) goto out_err; icmph = icmp_hdr(skb); - iph = (struct iphdr *)skb->data; + iph = (const struct iphdr *)skb->data; if (iph->ihl < 5) /* Mangled header, drop. */ goto out_err; @@ -729,7 +729,7 @@ static void icmp_unreach(struct sk_buff *skb) if (!pskb_may_pull(skb, iph->ihl * 4 + 8)) goto out; - iph = (struct iphdr *)skb->data; + iph = (const struct iphdr *)skb->data; protocol = iph->protocol; /* @@ -758,7 +758,7 @@ out_err: static void icmp_redirect(struct sk_buff *skb) { - struct iphdr *iph; + const struct iphdr *iph; if (skb->len < sizeof(struct iphdr)) goto out_err; @@ -769,7 +769,7 @@ static void icmp_redirect(struct sk_buff *skb) if (!pskb_may_pull(skb, sizeof(struct iphdr))) goto out; - iph = (struct iphdr *)skb->data; + iph = (const struct iphdr *)skb->data; switch (icmp_hdr(skb)->code & 7) { case ICMP_REDIR_NET: diff --git a/net/ipv4/inet_diag.c b/net/ipv4/inet_diag.c index 2ada171..6ffe94c 100644 --- a/net/ipv4/inet_diag.c +++ b/net/ipv4/inet_diag.c @@ -124,7 +124,7 @@ static int inet_csk_diag_fill(struct sock *sk, #if defined(CONFIG_IPV6) || defined (CONFIG_IPV6_MODULE) if (r->idiag_family == AF_INET6) { - struct ipv6_pinfo *np = inet6_sk(sk); + const struct ipv6_pinfo *np = inet6_sk(sk); ipv6_addr_copy((struct in6_addr *)r->id.idiag_src, &np->rcv_saddr); diff --git a/net/ipv4/inet_lro.c b/net/ipv4/inet_lro.c index 47038cb..85a0f75 100644 --- a/net/ipv4/inet_lro.c +++ b/net/ipv4/inet_lro.c @@ -51,8 +51,8 @@ MODULE_DESCRIPTION("Large Receive Offload (ipv4 / tcp)"); * Basic tcp checks whether packet is suitable for LRO */ -static int lro_tcp_ip_check(struct iphdr *iph, struct tcphdr *tcph, - int len, struct net_lro_desc *lro_desc) +static int lro_tcp_ip_check(const struct iphdr *iph, const struct tcphdr *tcph, + int len, const struct net_lro_desc *lro_desc) { /* check ip header: don't aggregate padded frames */ if (ntohs(iph->tot_len) != len) diff --git a/net/ipv4/ip_gre.c b/net/ipv4/ip_gre.c index da5941f..24efd35 100644 --- a/net/ipv4/ip_gre.c +++ b/net/ipv4/ip_gre.c @@ -462,7 +462,7 @@ static void ipgre_err(struct sk_buff *skb, u32 info) by themself??? */ - struct iphdr *iph = (struct iphdr *)skb->data; + const struct iphdr *iph = (const struct iphdr *)skb->data; __be16 *p = (__be16*)(skb->data+(iph->ihl<<2)); int grehlen = (iph->ihl<<2) + 4; const int type = icmp_hdr(skb)->type; @@ -534,7 +534,7 @@ out: rcu_read_unlock(); } -static inline void ipgre_ecn_decapsulate(struct iphdr *iph, struct sk_buff *skb) +static inline void ipgre_ecn_decapsulate(const struct iphdr *iph, struct sk_buff *skb) { if (INET_ECN_is_ce(iph->tos)) { if (skb->protocol == htons(ETH_P_IP)) { @@ -546,19 +546,19 @@ static inline void ipgre_ecn_decapsulate(struct iphdr *iph, struct sk_buff *skb) } static inline u8 -ipgre_ecn_encapsulate(u8 tos, struct iphdr *old_iph, struct sk_buff *skb) +ipgre_ecn_encapsulate(u8 tos, const struct iphdr *old_iph, struct sk_buff *skb) { u8 inner = 0; if (skb->protocol == htons(ETH_P_IP)) inner = old_iph->tos; else if (skb->protocol == htons(ETH_P_IPV6)) - inner = ipv6_get_dsfield((struct ipv6hdr *)old_iph); + inner = ipv6_get_dsfield((const struct ipv6hdr *)old_iph); return INET_ECN_encapsulate(tos, inner); } static int ipgre_rcv(struct sk_buff *skb) { - struct iphdr *iph; + const struct iphdr *iph; u8 *h; __be16 flags; __sum16 csum = 0; @@ -697,8 +697,8 @@ static netdev_tx_t ipgre_tunnel_xmit(struct sk_buff *skb, struct net_device *dev { struct ip_tunnel *tunnel = netdev_priv(dev); struct pcpu_tstats *tstats; - struct iphdr *old_iph = ip_hdr(skb); - struct iphdr *tiph; + const struct iphdr *old_iph = ip_hdr(skb); + const struct iphdr *tiph; u8 tos; __be16 df; struct rtable *rt; /* Route to the other host */ @@ -714,7 +714,7 @@ static netdev_tx_t ipgre_tunnel_xmit(struct sk_buff *skb, struct net_device *dev if (dev->header_ops && dev->type == ARPHRD_IPGRE) { gre_hlen = 0; - tiph = (struct iphdr *)skb->data; + tiph = (const struct iphdr *)skb->data; } else { gre_hlen = tunnel->hlen; tiph = &tunnel->parms.iph; @@ -735,14 +735,14 @@ static netdev_tx_t ipgre_tunnel_xmit(struct sk_buff *skb, struct net_device *dev } #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) else if (skb->protocol == htons(ETH_P_IPV6)) { - struct in6_addr *addr6; + const struct in6_addr *addr6; int addr_type; struct neighbour *neigh = skb_dst(skb)->neighbour; if (neigh == NULL) goto tx_error; - addr6 = (struct in6_addr *)&neigh->primary_key; + addr6 = (const struct in6_addr *)&neigh->primary_key; addr_type = ipv6_addr_type(addr6); if (addr_type == IPV6_ADDR_ANY) { @@ -766,7 +766,7 @@ static netdev_tx_t ipgre_tunnel_xmit(struct sk_buff *skb, struct net_device *dev if (skb->protocol == htons(ETH_P_IP)) tos = old_iph->tos; else if (skb->protocol == htons(ETH_P_IPV6)) - tos = ipv6_get_dsfield((struct ipv6hdr *)old_iph); + tos = ipv6_get_dsfield((const struct ipv6hdr *)old_iph); } rt = ip_route_output_gre(dev_net(dev), dst, tiph->saddr, @@ -881,7 +881,7 @@ static netdev_tx_t ipgre_tunnel_xmit(struct sk_buff *skb, struct net_device *dev iph->ttl = old_iph->ttl; #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) else if (skb->protocol == htons(ETH_P_IPV6)) - iph->ttl = ((struct ipv6hdr *)old_iph)->hop_limit; + iph->ttl = ((const struct ipv6hdr *)old_iph)->hop_limit; #endif else iph->ttl = ip4_dst_hoplimit(&rt->dst); @@ -927,7 +927,7 @@ static int ipgre_tunnel_bind_dev(struct net_device *dev) { struct net_device *tdev = NULL; struct ip_tunnel *tunnel; - struct iphdr *iph; + const struct iphdr *iph; int hlen = LL_MAX_HEADER; int mtu = ETH_DATA_LEN; int addend = sizeof(struct iphdr) + 4; @@ -1180,7 +1180,7 @@ static int ipgre_header(struct sk_buff *skb, struct net_device *dev, static int ipgre_header_parse(const struct sk_buff *skb, unsigned char *haddr) { - struct iphdr *iph = (struct iphdr *) skb_mac_header(skb); + const struct iphdr *iph = (const struct iphdr *) skb_mac_header(skb); memcpy(haddr, &iph->saddr, 4); return 4; } diff --git a/net/ipv4/ip_input.c b/net/ipv4/ip_input.c index d7b2b09..c8f48ef 100644 --- a/net/ipv4/ip_input.c +++ b/net/ipv4/ip_input.c @@ -268,7 +268,7 @@ int ip_local_deliver(struct sk_buff *skb) static inline int ip_rcv_options(struct sk_buff *skb) { struct ip_options *opt; - struct iphdr *iph; + const struct iphdr *iph; struct net_device *dev = skb->dev; /* It looks as overkill, because not all @@ -374,7 +374,7 @@ drop: */ int ip_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt, struct net_device *orig_dev) { - struct iphdr *iph; + const struct iphdr *iph; u32 len; /* When the interface is in promisc. mode, drop all the crap diff --git a/net/ipv4/ip_sockglue.c b/net/ipv4/ip_sockglue.c index 3948c86..9640900 100644 --- a/net/ipv4/ip_sockglue.c +++ b/net/ipv4/ip_sockglue.c @@ -131,7 +131,7 @@ static void ip_cmsg_recv_security(struct msghdr *msg, struct sk_buff *skb) static void ip_cmsg_recv_dstaddr(struct msghdr *msg, struct sk_buff *skb) { struct sockaddr_in sin; - struct iphdr *iph = ip_hdr(skb); + const struct iphdr *iph = ip_hdr(skb); __be16 *ports = (__be16 *)skb_transport_header(skb); if (skb_transport_offset(skb) + 4 > skb->len) diff --git a/net/ipv4/ipcomp.c b/net/ipv4/ipcomp.c index 6290675..c857f6f 100644 --- a/net/ipv4/ipcomp.c +++ b/net/ipv4/ipcomp.c @@ -27,7 +27,7 @@ static void ipcomp4_err(struct sk_buff *skb, u32 info) { struct net *net = dev_net(skb->dev); __be32 spi; - struct iphdr *iph = (struct iphdr *)skb->data; + const struct iphdr *iph = (const struct iphdr *)skb->data; struct ip_comp_hdr *ipch = (struct ip_comp_hdr *)(skb->data+(iph->ihl<<2)); struct xfrm_state *x; @@ -36,7 +36,7 @@ static void ipcomp4_err(struct sk_buff *skb, u32 info) return; spi = htonl(ntohs(ipch->cpi)); - x = xfrm_state_lookup(net, skb->mark, (xfrm_address_t *)&iph->daddr, + x = xfrm_state_lookup(net, skb->mark, (const xfrm_address_t *)&iph->daddr, spi, IPPROTO_COMP, AF_INET); if (!x) return; diff --git a/net/ipv4/ipip.c b/net/ipv4/ipip.c index bfc17c5..ef16377 100644 --- a/net/ipv4/ipip.c +++ b/net/ipv4/ipip.c @@ -319,7 +319,7 @@ static int ipip_err(struct sk_buff *skb, u32 info) 8 bytes of packet payload. It means, that precise relaying of ICMP in the real Internet is absolutely infeasible. */ - struct iphdr *iph = (struct iphdr *)skb->data; + const struct iphdr *iph = (const struct iphdr *)skb->data; const int type = icmp_hdr(skb)->type; const int code = icmp_hdr(skb)->code; struct ip_tunnel *t; @@ -433,12 +433,12 @@ static netdev_tx_t ipip_tunnel_xmit(struct sk_buff *skb, struct net_device *dev) { struct ip_tunnel *tunnel = netdev_priv(dev); struct pcpu_tstats *tstats; - struct iphdr *tiph = &tunnel->parms.iph; + const struct iphdr *tiph = &tunnel->parms.iph; u8 tos = tunnel->parms.iph.tos; __be16 df = tiph->frag_off; struct rtable *rt; /* Route to the other host */ struct net_device *tdev; /* Device to other host */ - struct iphdr *old_iph = ip_hdr(skb); + const struct iphdr *old_iph = ip_hdr(skb); struct iphdr *iph; /* Our new IP header */ unsigned int max_headroom; /* The extra header space needed */ __be32 dst = tiph->daddr; @@ -572,7 +572,7 @@ static void ipip_tunnel_bind_dev(struct net_device *dev) { struct net_device *tdev = NULL; struct ip_tunnel *tunnel; - struct iphdr *iph; + const struct iphdr *iph; tunnel = netdev_priv(dev); iph = &tunnel->parms.iph; diff --git a/net/ipv4/ipmr.c b/net/ipv4/ipmr.c index 1f62eae..c81b9b6 100644 --- a/net/ipv4/ipmr.c +++ b/net/ipv4/ipmr.c @@ -1549,7 +1549,7 @@ static struct notifier_block ip_mr_notifier = { static void ip_encap(struct sk_buff *skb, __be32 saddr, __be32 daddr) { struct iphdr *iph; - struct iphdr *old_iph = ip_hdr(skb); + const struct iphdr *old_iph = ip_hdr(skb); skb_push(skb, sizeof(struct iphdr)); skb->transport_header = skb->network_header; diff --git a/net/ipv4/netfilter/nf_nat_helper.c b/net/ipv4/netfilter/nf_nat_helper.c index 31427fb..99cfa28 100644 --- a/net/ipv4/netfilter/nf_nat_helper.c +++ b/net/ipv4/netfilter/nf_nat_helper.c @@ -153,7 +153,7 @@ void nf_nat_set_seq_adjust(struct nf_conn *ct, enum ip_conntrack_info ctinfo, } EXPORT_SYMBOL_GPL(nf_nat_set_seq_adjust); -static void nf_nat_csum(struct sk_buff *skb, struct iphdr *iph, void *data, +static void nf_nat_csum(struct sk_buff *skb, const struct iphdr *iph, void *data, int datalen, __sum16 *check, int oldlen) { struct rtable *rt = skb_rtable(skb); diff --git a/net/ipv4/raw.c b/net/ipv4/raw.c index 2b50cc2..abf14db 100644 --- a/net/ipv4/raw.c +++ b/net/ipv4/raw.c @@ -154,7 +154,7 @@ static __inline__ int icmp_filter(struct sock *sk, struct sk_buff *skb) * RFC 1122: SHOULD pass TOS value up to the transport layer. * -> It does. And not only TOS, but all IP header. */ -static int raw_v4_input(struct sk_buff *skb, struct iphdr *iph, int hash) +static int raw_v4_input(struct sk_buff *skb, const struct iphdr *iph, int hash) { struct sock *sk; struct hlist_head *head; @@ -247,7 +247,7 @@ static void raw_err(struct sock *sk, struct sk_buff *skb, u32 info) } if (inet->recverr) { - struct iphdr *iph = (struct iphdr *)skb->data; + const struct iphdr *iph = (const struct iphdr *)skb->data; u8 *payload = skb->data + (iph->ihl << 2); if (inet->hdrincl) @@ -265,7 +265,7 @@ void raw_icmp_error(struct sk_buff *skb, int protocol, u32 info) { int hash; struct sock *raw_sk; - struct iphdr *iph; + const struct iphdr *iph; struct net *net; hash = protocol & (RAW_HTABLE_SIZE - 1); @@ -273,7 +273,7 @@ void raw_icmp_error(struct sk_buff *skb, int protocol, u32 info) read_lock(&raw_v4_hashinfo.lock); raw_sk = sk_head(&raw_v4_hashinfo.ht[hash]); if (raw_sk != NULL) { - iph = (struct iphdr *)skb->data; + iph = (const struct iphdr *)skb->data; net = dev_net(skb->dev); while ((raw_sk = __raw_v4_lookup(net, raw_sk, protocol, @@ -281,7 +281,7 @@ void raw_icmp_error(struct sk_buff *skb, int protocol, u32 info) skb->dev->ifindex)) != NULL) { raw_err(raw_sk, skb, info); raw_sk = sk_next(raw_sk); - iph = (struct iphdr *)skb->data; + iph = (const struct iphdr *)skb->data; } } read_unlock(&raw_v4_hashinfo.lock); diff --git a/net/ipv4/route.c b/net/ipv4/route.c index e9aee81..f4b7f80 100644 --- a/net/ipv4/route.c +++ b/net/ipv4/route.c @@ -1507,7 +1507,7 @@ static inline unsigned short guess_mtu(unsigned short old_mtu) return 68; } -unsigned short ip_rt_frag_needed(struct net *net, struct iphdr *iph, +unsigned short ip_rt_frag_needed(struct net *net, const struct iphdr *iph, unsigned short new_mtu, struct net_device *dev) { diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c index f7e6c2c..edf18bd 100644 --- a/net/ipv4/tcp_ipv4.c +++ b/net/ipv4/tcp_ipv4.c @@ -279,7 +279,7 @@ EXPORT_SYMBOL(tcp_v4_connect); /* * This routine does path mtu discovery as defined in RFC1191. */ -static void do_pmtu_discovery(struct sock *sk, struct iphdr *iph, u32 mtu) +static void do_pmtu_discovery(struct sock *sk, const struct iphdr *iph, u32 mtu) { struct dst_entry *dst; struct inet_sock *inet = inet_sk(sk); @@ -341,7 +341,7 @@ static void do_pmtu_discovery(struct sock *sk, struct iphdr *iph, u32 mtu) void tcp_v4_err(struct sk_buff *icmp_skb, u32 info) { - struct iphdr *iph = (struct iphdr *)icmp_skb->data; + const struct iphdr *iph = (const struct iphdr *)icmp_skb->data; struct tcphdr *th = (struct tcphdr *)(icmp_skb->data + (iph->ihl << 2)); struct inet_connection_sock *icsk; struct tcp_sock *tp; @@ -2527,7 +2527,7 @@ void tcp4_proc_exit(void) struct sk_buff **tcp4_gro_receive(struct sk_buff **head, struct sk_buff *skb) { - struct iphdr *iph = skb_gro_network_header(skb); + const struct iphdr *iph = skb_gro_network_header(skb); switch (skb->ip_summed) { case CHECKSUM_COMPLETE: @@ -2548,7 +2548,7 @@ struct sk_buff **tcp4_gro_receive(struct sk_buff **head, struct sk_buff *skb) int tcp4_gro_complete(struct sk_buff *skb) { - struct iphdr *iph = ip_hdr(skb); + const struct iphdr *iph = ip_hdr(skb); struct tcphdr *th = tcp_hdr(skb); th->check = ~tcp_v4_check(skb->len - skb_transport_offset(skb), diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c index a15c8fb..bc0dab2 100644 --- a/net/ipv4/udp.c +++ b/net/ipv4/udp.c @@ -578,7 +578,7 @@ found: void __udp4_lib_err(struct sk_buff *skb, u32 info, struct udp_table *udptable) { struct inet_sock *inet; - struct iphdr *iph = (struct iphdr *)skb->data; + const struct iphdr *iph = (const struct iphdr *)skb->data; struct udphdr *uh = (struct udphdr *)(skb->data+(iph->ihl<<2)); const int type = icmp_hdr(skb)->type; const int code = icmp_hdr(skb)->code; diff --git a/net/ipv4/xfrm4_policy.c b/net/ipv4/xfrm4_policy.c index d20a05e..59b1340 100644 --- a/net/ipv4/xfrm4_policy.c +++ b/net/ipv4/xfrm4_policy.c @@ -102,7 +102,7 @@ static int xfrm4_fill_dst(struct xfrm_dst *xdst, struct net_device *dev, static void _decode_session4(struct sk_buff *skb, struct flowi *fl, int reverse) { - struct iphdr *iph = ip_hdr(skb); + const struct iphdr *iph = ip_hdr(skb); u8 *xprth = skb_network_header(skb) + iph->ihl * 4; struct flowi4 *fl4 = &fl->u.ip4; diff --git a/net/ipv4/xfrm4_state.c b/net/ipv4/xfrm4_state.c index 1717c64..ea983ae 100644 --- a/net/ipv4/xfrm4_state.c +++ b/net/ipv4/xfrm4_state.c @@ -55,7 +55,7 @@ xfrm4_init_temprop(struct xfrm_state *x, const struct xfrm_tmpl *tmpl, int xfrm4_extract_header(struct sk_buff *skb) { - struct iphdr *iph = ip_hdr(skb); + const struct iphdr *iph = ip_hdr(skb); XFRM_MODE_SKB_CB(skb)->ihl = sizeof(*iph); XFRM_MODE_SKB_CB(skb)->id = iph->id; diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c index 129d7e1..c663a3b 100644 --- a/net/ipv6/addrconf.c +++ b/net/ipv6/addrconf.c @@ -1283,7 +1283,7 @@ static int ipv6_count_addresses(struct inet6_dev *idev) return cnt; } -int ipv6_chk_addr(struct net *net, struct in6_addr *addr, +int ipv6_chk_addr(struct net *net, const struct in6_addr *addr, struct net_device *dev, int strict) { struct inet6_ifaddr *ifp; @@ -1326,7 +1326,7 @@ static bool ipv6_chk_same_addr(struct net *net, const struct in6_addr *addr, return false; } -int ipv6_chk_prefix(struct in6_addr *addr, struct net_device *dev) +int ipv6_chk_prefix(const struct in6_addr *addr, struct net_device *dev) { struct inet6_dev *idev; struct inet6_ifaddr *ifa; @@ -1457,7 +1457,7 @@ void addrconf_dad_failure(struct inet6_ifaddr *ifp) /* Join to solicited addr multicast group. */ -void addrconf_join_solict(struct net_device *dev, struct in6_addr *addr) +void addrconf_join_solict(struct net_device *dev, const struct in6_addr *addr) { struct in6_addr maddr; @@ -1468,7 +1468,7 @@ void addrconf_join_solict(struct net_device *dev, struct in6_addr *addr) ipv6_dev_mc_inc(dev, &maddr); } -void addrconf_leave_solict(struct inet6_dev *idev, struct in6_addr *addr) +void addrconf_leave_solict(struct inet6_dev *idev, const struct in6_addr *addr) { struct in6_addr maddr; @@ -2113,7 +2113,7 @@ err_exit: /* * Manual configuration of address on an interface */ -static int inet6_addr_add(struct net *net, int ifindex, struct in6_addr *pfx, +static int inet6_addr_add(struct net *net, int ifindex, const struct in6_addr *pfx, unsigned int plen, __u8 ifa_flags, __u32 prefered_lft, __u32 valid_lft) { @@ -2187,7 +2187,7 @@ static int inet6_addr_add(struct net *net, int ifindex, struct in6_addr *pfx, return PTR_ERR(ifp); } -static int inet6_addr_del(struct net *net, int ifindex, struct in6_addr *pfx, +static int inet6_addr_del(struct net *net, int ifindex, const struct in6_addr *pfx, unsigned int plen) { struct inet6_ifaddr *ifp; @@ -2350,7 +2350,7 @@ static void init_loopback(struct net_device *dev) add_addr(idev, &in6addr_loopback, 128, IFA_HOST); } -static void addrconf_add_linklocal(struct inet6_dev *idev, struct in6_addr *addr) +static void addrconf_add_linklocal(struct inet6_dev *idev, const struct in6_addr *addr) { struct inet6_ifaddr * ifp; u32 addr_flags = IFA_F_PERMANENT; @@ -3121,7 +3121,7 @@ void if6_proc_exit(void) #if defined(CONFIG_IPV6_MIP6) || defined(CONFIG_IPV6_MIP6_MODULE) /* Check if address is a home address configured on any interface. */ -int ipv6_chk_home_addr(struct net *net, struct in6_addr *addr) +int ipv6_chk_home_addr(struct net *net, const struct in6_addr *addr) { int ret = 0; struct inet6_ifaddr *ifp = NULL; diff --git a/net/ipv6/af_inet6.c b/net/ipv6/af_inet6.c index afcc709..b7919f9 100644 --- a/net/ipv6/af_inet6.c +++ b/net/ipv6/af_inet6.c @@ -740,7 +740,7 @@ static int ipv6_gso_pull_exthdrs(struct sk_buff *skb, int proto) static int ipv6_gso_send_check(struct sk_buff *skb) { - struct ipv6hdr *ipv6h; + const struct ipv6hdr *ipv6h; const struct inet6_protocol *ops; int err = -EINVAL; diff --git a/net/ipv6/anycast.c b/net/ipv6/anycast.c index 0e5e943..674255f 100644 --- a/net/ipv6/anycast.c +++ b/net/ipv6/anycast.c @@ -44,7 +44,7 @@ #include -static int ipv6_dev_ac_dec(struct net_device *dev, struct in6_addr *addr); +static int ipv6_dev_ac_dec(struct net_device *dev, const struct in6_addr *addr); /* Big ac list lock for all the sockets */ static DEFINE_RWLOCK(ipv6_sk_ac_lock); @@ -54,7 +54,7 @@ static DEFINE_RWLOCK(ipv6_sk_ac_lock); * socket join an anycast group */ -int ipv6_sock_ac_join(struct sock *sk, int ifindex, struct in6_addr *addr) +int ipv6_sock_ac_join(struct sock *sk, int ifindex, const struct in6_addr *addr) { struct ipv6_pinfo *np = inet6_sk(sk); struct net_device *dev = NULL; @@ -145,7 +145,7 @@ error: /* * socket leave an anycast group */ -int ipv6_sock_ac_drop(struct sock *sk, int ifindex, struct in6_addr *addr) +int ipv6_sock_ac_drop(struct sock *sk, int ifindex, const struct in6_addr *addr) { struct ipv6_pinfo *np = inet6_sk(sk); struct net_device *dev; @@ -252,7 +252,7 @@ static void aca_put(struct ifacaddr6 *ac) /* * device anycast group inc (add if not found) */ -int ipv6_dev_ac_inc(struct net_device *dev, struct in6_addr *addr) +int ipv6_dev_ac_inc(struct net_device *dev, const struct in6_addr *addr) { struct ifacaddr6 *aca; struct inet6_dev *idev; @@ -324,7 +324,7 @@ out: /* * device anycast group decrement */ -int __ipv6_dev_ac_dec(struct inet6_dev *idev, struct in6_addr *addr) +int __ipv6_dev_ac_dec(struct inet6_dev *idev, const struct in6_addr *addr) { struct ifacaddr6 *aca, *prev_aca; @@ -358,7 +358,7 @@ int __ipv6_dev_ac_dec(struct inet6_dev *idev, struct in6_addr *addr) } /* called with rcu_read_lock() */ -static int ipv6_dev_ac_dec(struct net_device *dev, struct in6_addr *addr) +static int ipv6_dev_ac_dec(struct net_device *dev, const struct in6_addr *addr) { struct inet6_dev *idev = __in6_dev_get(dev); @@ -371,7 +371,7 @@ static int ipv6_dev_ac_dec(struct net_device *dev, struct in6_addr *addr) * check if the interface has this anycast address * called with rcu_read_lock() */ -static int ipv6_chk_acast_dev(struct net_device *dev, struct in6_addr *addr) +static int ipv6_chk_acast_dev(struct net_device *dev, const struct in6_addr *addr) { struct inet6_dev *idev; struct ifacaddr6 *aca; @@ -392,7 +392,7 @@ static int ipv6_chk_acast_dev(struct net_device *dev, struct in6_addr *addr) * check if given interface (or any, if dev==0) has this anycast address */ int ipv6_chk_acast_addr(struct net *net, struct net_device *dev, - struct in6_addr *addr) + const struct in6_addr *addr) { int found = 0; diff --git a/net/ipv6/esp6.c b/net/ipv6/esp6.c index 5aa8ec8..e97b4b7 100644 --- a/net/ipv6/esp6.c +++ b/net/ipv6/esp6.c @@ -430,7 +430,7 @@ static void esp6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, u8 type, u8 code, int offset, __be32 info) { struct net *net = dev_net(skb->dev); - struct ipv6hdr *iph = (struct ipv6hdr*)skb->data; + const struct ipv6hdr *iph = (const struct ipv6hdr *)skb->data; struct ip_esp_hdr *esph = (struct ip_esp_hdr *)(skb->data + offset); struct xfrm_state *x; @@ -438,7 +438,8 @@ static void esp6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, type != ICMPV6_PKT_TOOBIG) return; - x = xfrm_state_lookup(net, skb->mark, (xfrm_address_t *)&iph->daddr, esph->spi, IPPROTO_ESP, AF_INET6); + x = xfrm_state_lookup(net, skb->mark, (const xfrm_address_t *)&iph->daddr, + esph->spi, IPPROTO_ESP, AF_INET6); if (!x) return; printk(KERN_DEBUG "pmtu discovery on SA ESP/%08x/%pI6\n", diff --git a/net/ipv6/icmp.c b/net/ipv6/icmp.c index 83cb4f9..1190041 100644 --- a/net/ipv6/icmp.c +++ b/net/ipv6/icmp.c @@ -372,7 +372,7 @@ void icmpv6_send(struct sk_buff *skb, u8 type, u8 code, __u32 info) struct ipv6hdr *hdr = ipv6_hdr(skb); struct sock *sk; struct ipv6_pinfo *np; - struct in6_addr *saddr = NULL; + const struct in6_addr *saddr = NULL; struct dst_entry *dst; struct icmp6hdr tmp_hdr; struct flowi6 fl6; @@ -521,7 +521,7 @@ static void icmpv6_echo_reply(struct sk_buff *skb) struct sock *sk; struct inet6_dev *idev; struct ipv6_pinfo *np; - struct in6_addr *saddr = NULL; + const struct in6_addr *saddr = NULL; struct icmp6hdr *icmph = icmp6_hdr(skb); struct icmp6hdr tmp_hdr; struct flowi6 fl6; @@ -645,8 +645,8 @@ static int icmpv6_rcv(struct sk_buff *skb) { struct net_device *dev = skb->dev; struct inet6_dev *idev = __in6_dev_get(dev); - struct in6_addr *saddr, *daddr; - struct ipv6hdr *orig_hdr; + const struct in6_addr *saddr, *daddr; + const struct ipv6hdr *orig_hdr; struct icmp6hdr *hdr; u8 type; diff --git a/net/ipv6/ip6_fib.c b/net/ipv6/ip6_fib.c index 7548905..dd88df0 100644 --- a/net/ipv6/ip6_fib.c +++ b/net/ipv6/ip6_fib.c @@ -134,9 +134,9 @@ static __inline__ u32 fib6_new_sernum(void) # define BITOP_BE32_SWIZZLE 0 #endif -static __inline__ __be32 addr_bit_set(void *token, int fn_bit) +static __inline__ __be32 addr_bit_set(const void *token, int fn_bit) { - __be32 *addr = token; + const __be32 *addr = token; /* * Here, * 1 << ((~fn_bit ^ BITOP_BE32_SWIZZLE) & 0x1f) @@ -822,7 +822,7 @@ st_failure: struct lookup_args { int offset; /* key offset on rt6_info */ - struct in6_addr *addr; /* search key */ + const struct in6_addr *addr; /* search key */ }; static struct fib6_node * fib6_lookup_1(struct fib6_node *root, @@ -881,8 +881,8 @@ static struct fib6_node * fib6_lookup_1(struct fib6_node *root, return NULL; } -struct fib6_node * fib6_lookup(struct fib6_node *root, struct in6_addr *daddr, - struct in6_addr *saddr) +struct fib6_node * fib6_lookup(struct fib6_node *root, const struct in6_addr *daddr, + const struct in6_addr *saddr) { struct fib6_node *fn; struct lookup_args args[] = { @@ -916,7 +916,7 @@ struct fib6_node * fib6_lookup(struct fib6_node *root, struct in6_addr *daddr, static struct fib6_node * fib6_locate_1(struct fib6_node *root, - struct in6_addr *addr, + const struct in6_addr *addr, int plen, int offset) { struct fib6_node *fn; @@ -946,8 +946,8 @@ static struct fib6_node * fib6_locate_1(struct fib6_node *root, } struct fib6_node * fib6_locate(struct fib6_node *root, - struct in6_addr *daddr, int dst_len, - struct in6_addr *saddr, int src_len) + const struct in6_addr *daddr, int dst_len, + const struct in6_addr *saddr, int src_len) { struct fib6_node *fn; diff --git a/net/ipv6/ip6_input.c b/net/ipv6/ip6_input.c index a83e920..027c7ff 100644 --- a/net/ipv6/ip6_input.c +++ b/net/ipv6/ip6_input.c @@ -57,7 +57,7 @@ inline int ip6_rcv_finish( struct sk_buff *skb) int ipv6_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt, struct net_device *orig_dev) { - struct ipv6hdr *hdr; + const struct ipv6hdr *hdr; u32 pkt_len; struct inet6_dev *idev; struct net *net = dev_net(skb->dev); @@ -186,7 +186,7 @@ resubmit: int ret; if (ipprot->flags & INET6_PROTO_FINAL) { - struct ipv6hdr *hdr; + const struct ipv6hdr *hdr; /* Free reference early: we don't need it any more, and it may hold ip_conntrack module loaded @@ -242,7 +242,7 @@ int ip6_input(struct sk_buff *skb) int ip6_mc_input(struct sk_buff *skb) { - struct ipv6hdr *hdr; + const struct ipv6hdr *hdr; int deliver; IP6_UPD_PO_STATS_BH(dev_net(skb_dst(skb)->dev), diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c index c614d02..4cfbb24 100644 --- a/net/ipv6/ip6_output.c +++ b/net/ipv6/ip6_output.c @@ -869,9 +869,9 @@ fail: return err; } -static inline int ip6_rt_check(struct rt6key *rt_key, - struct in6_addr *fl_addr, - struct in6_addr *addr_cache) +static inline int ip6_rt_check(const struct rt6key *rt_key, + const struct in6_addr *fl_addr, + const struct in6_addr *addr_cache) { return (rt_key->plen != 128 || !ipv6_addr_equal(fl_addr, &rt_key->addr)) && (addr_cache == NULL || !ipv6_addr_equal(fl_addr, addr_cache)); @@ -879,7 +879,7 @@ static inline int ip6_rt_check(struct rt6key *rt_key, static struct dst_entry *ip6_sk_dst_check(struct sock *sk, struct dst_entry *dst, - struct flowi6 *fl6) + const struct flowi6 *fl6) { struct ipv6_pinfo *np = inet6_sk(sk); struct rt6_info *rt = (struct rt6_info *)dst; diff --git a/net/ipv6/ip6_tunnel.c b/net/ipv6/ip6_tunnel.c index c1b1bd3..9dd0e96 100644 --- a/net/ipv6/ip6_tunnel.c +++ b/net/ipv6/ip6_tunnel.c @@ -162,7 +162,7 @@ static inline void ip6_tnl_dst_store(struct ip6_tnl *t, struct dst_entry *dst) for (t = rcu_dereference(start); t; t = rcu_dereference(t->next)) static struct ip6_tnl * -ip6_tnl_lookup(struct net *net, struct in6_addr *remote, struct in6_addr *local) +ip6_tnl_lookup(struct net *net, const struct in6_addr *remote, const struct in6_addr *local) { unsigned int h0 = HASH(remote); unsigned int h1 = HASH(local); @@ -194,10 +194,10 @@ ip6_tnl_lookup(struct net *net, struct in6_addr *remote, struct in6_addr *local) **/ static struct ip6_tnl __rcu ** -ip6_tnl_bucket(struct ip6_tnl_net *ip6n, struct ip6_tnl_parm *p) +ip6_tnl_bucket(struct ip6_tnl_net *ip6n, const struct ip6_tnl_parm *p) { - struct in6_addr *remote = &p->raddr; - struct in6_addr *local = &p->laddr; + const struct in6_addr *remote = &p->raddr; + const struct in6_addr *local = &p->laddr; unsigned h = 0; int prio = 0; @@ -321,8 +321,8 @@ failed: static struct ip6_tnl *ip6_tnl_locate(struct net *net, struct ip6_tnl_parm *p, int create) { - struct in6_addr *remote = &p->raddr; - struct in6_addr *local = &p->laddr; + const struct in6_addr *remote = &p->raddr; + const struct in6_addr *local = &p->laddr; struct ip6_tnl __rcu **tp; struct ip6_tnl *t; struct ip6_tnl_net *ip6n = net_generic(net, ip6_tnl_net_id); @@ -374,7 +374,7 @@ ip6_tnl_dev_uninit(struct net_device *dev) static __u16 parse_tlv_tnl_enc_lim(struct sk_buff *skb, __u8 * raw) { - struct ipv6hdr *ipv6h = (struct ipv6hdr *) raw; + const struct ipv6hdr *ipv6h = (const struct ipv6hdr *) raw; __u8 nexthdr = ipv6h->nexthdr; __u16 off = sizeof (*ipv6h); @@ -435,7 +435,7 @@ static int ip6_tnl_err(struct sk_buff *skb, __u8 ipproto, struct inet6_skb_parm *opt, u8 *type, u8 *code, int *msg, __u32 *info, int offset) { - struct ipv6hdr *ipv6h = (struct ipv6hdr *) skb->data; + const struct ipv6hdr *ipv6h = (const struct ipv6hdr *) skb->data; struct ip6_tnl *t; int rel_msg = 0; u8 rel_type = ICMPV6_DEST_UNREACH; @@ -535,7 +535,7 @@ ip4ip6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, __u32 rel_info = ntohl(info); int err; struct sk_buff *skb2; - struct iphdr *eiph; + const struct iphdr *eiph; struct rtable *rt; err = ip6_tnl_err(skb, IPPROTO_IPIP, opt, &rel_type, &rel_code, @@ -669,8 +669,8 @@ ip6ip6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, return 0; } -static void ip4ip6_dscp_ecn_decapsulate(struct ip6_tnl *t, - struct ipv6hdr *ipv6h, +static void ip4ip6_dscp_ecn_decapsulate(const struct ip6_tnl *t, + const struct ipv6hdr *ipv6h, struct sk_buff *skb) { __u8 dsfield = ipv6_get_dsfield(ipv6h) & ~INET_ECN_MASK; @@ -682,8 +682,8 @@ static void ip4ip6_dscp_ecn_decapsulate(struct ip6_tnl *t, IP_ECN_set_ce(ip_hdr(skb)); } -static void ip6ip6_dscp_ecn_decapsulate(struct ip6_tnl *t, - struct ipv6hdr *ipv6h, +static void ip6ip6_dscp_ecn_decapsulate(const struct ip6_tnl *t, + const struct ipv6hdr *ipv6h, struct sk_buff *skb) { if (t->parms.flags & IP6_TNL_F_RCV_DSCP_COPY) @@ -726,12 +726,12 @@ static inline int ip6_tnl_rcv_ctl(struct ip6_tnl *t) static int ip6_tnl_rcv(struct sk_buff *skb, __u16 protocol, __u8 ipproto, - void (*dscp_ecn_decapsulate)(struct ip6_tnl *t, - struct ipv6hdr *ipv6h, + void (*dscp_ecn_decapsulate)(const struct ip6_tnl *t, + const struct ipv6hdr *ipv6h, struct sk_buff *skb)) { struct ip6_tnl *t; - struct ipv6hdr *ipv6h = ipv6_hdr(skb); + const struct ipv6hdr *ipv6h = ipv6_hdr(skb); rcu_read_lock(); @@ -828,7 +828,7 @@ static void init_tel_txopt(struct ipv6_tel_txoption *opt, __u8 encap_limit) **/ static inline int -ip6_tnl_addr_conflict(struct ip6_tnl *t, struct ipv6hdr *hdr) +ip6_tnl_addr_conflict(const struct ip6_tnl *t, const struct ipv6hdr *hdr) { return ipv6_addr_equal(&t->parms.raddr, &hdr->saddr); } @@ -1005,7 +1005,7 @@ static inline int ip4ip6_tnl_xmit(struct sk_buff *skb, struct net_device *dev) { struct ip6_tnl *t = netdev_priv(dev); - struct iphdr *iph = ip_hdr(skb); + const struct iphdr *iph = ip_hdr(skb); int encap_limit = -1; struct flowi6 fl6; __u8 dsfield; diff --git a/net/ipv6/ip6mr.c b/net/ipv6/ip6mr.c index 29e4859..82a8099 100644 --- a/net/ipv6/ip6mr.c +++ b/net/ipv6/ip6mr.c @@ -989,8 +989,8 @@ static int mif6_add(struct net *net, struct mr6_table *mrt, } static struct mfc6_cache *ip6mr_cache_find(struct mr6_table *mrt, - struct in6_addr *origin, - struct in6_addr *mcastgrp) + const struct in6_addr *origin, + const struct in6_addr *mcastgrp) { int line = MFC6_HASH(mcastgrp, origin); struct mfc6_cache *c; diff --git a/net/ipv6/ipcomp6.c b/net/ipv6/ipcomp6.c index 85cccd6..bba658d 100644 --- a/net/ipv6/ipcomp6.c +++ b/net/ipv6/ipcomp6.c @@ -55,7 +55,7 @@ static void ipcomp6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, { struct net *net = dev_net(skb->dev); __be32 spi; - struct ipv6hdr *iph = (struct ipv6hdr*)skb->data; + const struct ipv6hdr *iph = (const struct ipv6hdr *)skb->data; struct ip_comp_hdr *ipcomph = (struct ip_comp_hdr *)(skb->data + offset); struct xfrm_state *x; @@ -64,7 +64,8 @@ static void ipcomp6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, return; spi = htonl(ntohs(ipcomph->cpi)); - x = xfrm_state_lookup(net, skb->mark, (xfrm_address_t *)&iph->daddr, spi, IPPROTO_COMP, AF_INET6); + x = xfrm_state_lookup(net, skb->mark, (const xfrm_address_t *)&iph->daddr, + spi, IPPROTO_COMP, AF_INET6); if (!x) return; diff --git a/net/ipv6/mcast.c b/net/ipv6/mcast.c index 76b8937..ff62e33 100644 --- a/net/ipv6/mcast.c +++ b/net/ipv6/mcast.c @@ -92,16 +92,16 @@ static void mld_gq_timer_expire(unsigned long data); static void mld_ifc_timer_expire(unsigned long data); static void mld_ifc_event(struct inet6_dev *idev); static void mld_add_delrec(struct inet6_dev *idev, struct ifmcaddr6 *pmc); -static void mld_del_delrec(struct inet6_dev *idev, struct in6_addr *addr); +static void mld_del_delrec(struct inet6_dev *idev, const struct in6_addr *addr); static void mld_clear_delrec(struct inet6_dev *idev); static int sf_setstate(struct ifmcaddr6 *pmc); static void sf_markstate(struct ifmcaddr6 *pmc); static void ip6_mc_clear_src(struct ifmcaddr6 *pmc); -static int ip6_mc_del_src(struct inet6_dev *idev, struct in6_addr *pmca, - int sfmode, int sfcount, struct in6_addr *psfsrc, +static int ip6_mc_del_src(struct inet6_dev *idev, const struct in6_addr *pmca, + int sfmode, int sfcount, const struct in6_addr *psfsrc, int delta); -static int ip6_mc_add_src(struct inet6_dev *idev, struct in6_addr *pmca, - int sfmode, int sfcount, struct in6_addr *psfsrc, +static int ip6_mc_add_src(struct inet6_dev *idev, const struct in6_addr *pmca, + int sfmode, int sfcount, const struct in6_addr *psfsrc, int delta); static int ip6_mc_leave_src(struct sock *sk, struct ipv6_mc_socklist *iml, struct inet6_dev *idev); @@ -250,7 +250,7 @@ int ipv6_sock_mc_drop(struct sock *sk, int ifindex, const struct in6_addr *addr) /* called with rcu_read_lock() */ static struct inet6_dev *ip6_mc_find_dev_rcu(struct net *net, - struct in6_addr *group, + const struct in6_addr *group, int ifindex) { struct net_device *dev = NULL; @@ -451,7 +451,7 @@ done: int ip6_mc_msfilter(struct sock *sk, struct group_filter *gsf) { - struct in6_addr *group; + const struct in6_addr *group; struct ipv6_mc_socklist *pmc; struct inet6_dev *idev; struct ipv6_pinfo *inet6 = inet6_sk(sk); @@ -542,7 +542,7 @@ int ip6_mc_msfget(struct sock *sk, struct group_filter *gsf, struct group_filter __user *optval, int __user *optlen) { int err, i, count, copycount; - struct in6_addr *group; + const struct in6_addr *group; struct ipv6_mc_socklist *pmc; struct inet6_dev *idev; struct ipv6_pinfo *inet6 = inet6_sk(sk); @@ -752,7 +752,7 @@ static void mld_add_delrec(struct inet6_dev *idev, struct ifmcaddr6 *im) spin_unlock_bh(&idev->mc_lock); } -static void mld_del_delrec(struct inet6_dev *idev, struct in6_addr *pmca) +static void mld_del_delrec(struct inet6_dev *idev, const struct in6_addr *pmca) { struct ifmcaddr6 *pmc, *pmc_prev; struct ip6_sf_list *psf, *psf_next; @@ -1052,7 +1052,7 @@ static void igmp6_group_queried(struct ifmcaddr6 *ma, unsigned long resptime) /* mark EXCLUDE-mode sources */ static int mld_xmarksources(struct ifmcaddr6 *pmc, int nsrcs, - struct in6_addr *srcs) + const struct in6_addr *srcs) { struct ip6_sf_list *psf; int i, scount; @@ -1080,7 +1080,7 @@ static int mld_xmarksources(struct ifmcaddr6 *pmc, int nsrcs, } static int mld_marksources(struct ifmcaddr6 *pmc, int nsrcs, - struct in6_addr *srcs) + const struct in6_addr *srcs) { struct ip6_sf_list *psf; int i, scount; @@ -1115,7 +1115,7 @@ int igmp6_event_query(struct sk_buff *skb) { struct mld2_query *mlh2 = NULL; struct ifmcaddr6 *ma; - struct in6_addr *group; + const struct in6_addr *group; unsigned long max_delay; struct inet6_dev *idev; struct mld_msg *mld; @@ -1821,7 +1821,7 @@ err_out: } static int ip6_mc_del1_src(struct ifmcaddr6 *pmc, int sfmode, - struct in6_addr *psfsrc) + const struct in6_addr *psfsrc) { struct ip6_sf_list *psf, *psf_prev; int rv = 0; @@ -1857,8 +1857,8 @@ static int ip6_mc_del1_src(struct ifmcaddr6 *pmc, int sfmode, return rv; } -static int ip6_mc_del_src(struct inet6_dev *idev, struct in6_addr *pmca, - int sfmode, int sfcount, struct in6_addr *psfsrc, +static int ip6_mc_del_src(struct inet6_dev *idev, const struct in6_addr *pmca, + int sfmode, int sfcount, const struct in6_addr *psfsrc, int delta) { struct ifmcaddr6 *pmc; @@ -1918,7 +1918,7 @@ static int ip6_mc_del_src(struct inet6_dev *idev, struct in6_addr *pmca, * Add multicast single-source filter to the interface list */ static int ip6_mc_add1_src(struct ifmcaddr6 *pmc, int sfmode, - struct in6_addr *psfsrc, int delta) + const struct in6_addr *psfsrc, int delta) { struct ip6_sf_list *psf, *psf_prev; @@ -2021,8 +2021,8 @@ static int sf_setstate(struct ifmcaddr6 *pmc) /* * Add multicast source filter list to the interface list */ -static int ip6_mc_add_src(struct inet6_dev *idev, struct in6_addr *pmca, - int sfmode, int sfcount, struct in6_addr *psfsrc, +static int ip6_mc_add_src(struct inet6_dev *idev, const struct in6_addr *pmca, + int sfmode, int sfcount, const struct in6_addr *psfsrc, int delta) { struct ifmcaddr6 *pmc; diff --git a/net/ipv6/mip6.c b/net/ipv6/mip6.c index 9b21048..43242e6 100644 --- a/net/ipv6/mip6.c +++ b/net/ipv6/mip6.c @@ -126,7 +126,7 @@ static struct mip6_report_rate_limiter mip6_report_rl = { static int mip6_destopt_input(struct xfrm_state *x, struct sk_buff *skb) { - struct ipv6hdr *iph = ipv6_hdr(skb); + const struct ipv6hdr *iph = ipv6_hdr(skb); struct ipv6_destopt_hdr *destopt = (struct ipv6_destopt_hdr *)skb->data; int err = destopt->nexthdr; @@ -181,8 +181,8 @@ static int mip6_destopt_output(struct xfrm_state *x, struct sk_buff *skb) } static inline int mip6_report_rl_allow(struct timeval *stamp, - struct in6_addr *dst, - struct in6_addr *src, int iif) + const struct in6_addr *dst, + const struct in6_addr *src, int iif) { int allow = 0; @@ -349,7 +349,7 @@ static const struct xfrm_type mip6_destopt_type = static int mip6_rthdr_input(struct xfrm_state *x, struct sk_buff *skb) { - struct ipv6hdr *iph = ipv6_hdr(skb); + const struct ipv6hdr *iph = ipv6_hdr(skb); struct rt2_hdr *rt2 = (struct rt2_hdr *)skb->data; int err = rt2->rt_hdr.nexthdr; diff --git a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c index 01a0ffc..69aacd1 100644 --- a/net/ipv6/ndisc.c +++ b/net/ipv6/ndisc.c @@ -324,7 +324,7 @@ static inline u8 *ndisc_opt_addr_data(struct nd_opt_hdr *p, return lladdr + prepad; } -int ndisc_mc_map(struct in6_addr *addr, char *buf, struct net_device *dev, int dir) +int ndisc_mc_map(const struct in6_addr *addr, char *buf, struct net_device *dev, int dir) { switch (dev->type) { case ARPHRD_ETHER: @@ -748,8 +748,8 @@ static int pndisc_is_router(const void *pkey, static void ndisc_recv_ns(struct sk_buff *skb) { struct nd_msg *msg = (struct nd_msg *)skb_transport_header(skb); - struct in6_addr *saddr = &ipv6_hdr(skb)->saddr; - struct in6_addr *daddr = &ipv6_hdr(skb)->daddr; + const struct in6_addr *saddr = &ipv6_hdr(skb)->saddr; + const struct in6_addr *daddr = &ipv6_hdr(skb)->daddr; u8 *lladdr = NULL; u32 ndoptlen = skb->tail - (skb->transport_header + offsetof(struct nd_msg, opt)); @@ -924,8 +924,8 @@ out: static void ndisc_recv_na(struct sk_buff *skb) { struct nd_msg *msg = (struct nd_msg *)skb_transport_header(skb); - struct in6_addr *saddr = &ipv6_hdr(skb)->saddr; - struct in6_addr *daddr = &ipv6_hdr(skb)->daddr; + const struct in6_addr *saddr = &ipv6_hdr(skb)->saddr; + const struct in6_addr *daddr = &ipv6_hdr(skb)->daddr; u8 *lladdr = NULL; u32 ndoptlen = skb->tail - (skb->transport_header + offsetof(struct nd_msg, opt)); @@ -1038,7 +1038,7 @@ static void ndisc_recv_rs(struct sk_buff *skb) unsigned long ndoptlen = skb->len - sizeof(*rs_msg); struct neighbour *neigh; struct inet6_dev *idev; - struct in6_addr *saddr = &ipv6_hdr(skb)->saddr; + const struct in6_addr *saddr = &ipv6_hdr(skb)->saddr; struct ndisc_options ndopts; u8 *lladdr = NULL; @@ -1435,8 +1435,8 @@ static void ndisc_redirect_rcv(struct sk_buff *skb) { struct inet6_dev *in6_dev; struct icmp6hdr *icmph; - struct in6_addr *dest; - struct in6_addr *target; /* new first hop to destination */ + const struct in6_addr *dest; + const struct in6_addr *target; /* new first hop to destination */ struct neighbour *neigh; int on_link = 0; struct ndisc_options ndopts; @@ -1469,7 +1469,7 @@ static void ndisc_redirect_rcv(struct sk_buff *skb) } icmph = icmp6_hdr(skb); - target = (struct in6_addr *) (icmph + 1); + target = (const struct in6_addr *) (icmph + 1); dest = target + 1; if (ipv6_addr_is_multicast(dest)) { diff --git a/net/ipv6/netfilter.c b/net/ipv6/netfilter.c index 28bc1f6..30fcee4 100644 --- a/net/ipv6/netfilter.c +++ b/net/ipv6/netfilter.c @@ -13,7 +13,7 @@ int ip6_route_me_harder(struct sk_buff *skb) { struct net *net = dev_net(skb_dst(skb)->dev); - struct ipv6hdr *iph = ipv6_hdr(skb); + const struct ipv6hdr *iph = ipv6_hdr(skb); struct dst_entry *dst; struct flowi6 fl6 = { .flowi6_oif = skb->sk ? skb->sk->sk_bound_dev_if : 0, @@ -67,7 +67,7 @@ static void nf_ip6_saveroute(const struct sk_buff *skb, struct ip6_rt_info *rt_info = nf_queue_entry_reroute(entry); if (entry->hook == NF_INET_LOCAL_OUT) { - struct ipv6hdr *iph = ipv6_hdr(skb); + const struct ipv6hdr *iph = ipv6_hdr(skb); rt_info->daddr = iph->daddr; rt_info->saddr = iph->saddr; @@ -81,7 +81,7 @@ static int nf_ip6_reroute(struct sk_buff *skb, struct ip6_rt_info *rt_info = nf_queue_entry_reroute(entry); if (entry->hook == NF_INET_LOCAL_OUT) { - struct ipv6hdr *iph = ipv6_hdr(skb); + const struct ipv6hdr *iph = ipv6_hdr(skb); if (!ipv6_addr_equal(&iph->daddr, &rt_info->daddr) || !ipv6_addr_equal(&iph->saddr, &rt_info->saddr) || skb->mark != rt_info->mark) @@ -108,7 +108,7 @@ static int nf_ip6_route(struct net *net, struct dst_entry **dst, __sum16 nf_ip6_checksum(struct sk_buff *skb, unsigned int hook, unsigned int dataoff, u_int8_t protocol) { - struct ipv6hdr *ip6h = ipv6_hdr(skb); + const struct ipv6hdr *ip6h = ipv6_hdr(skb); __sum16 csum = 0; switch (skb->ip_summed) { @@ -142,7 +142,7 @@ static __sum16 nf_ip6_checksum_partial(struct sk_buff *skb, unsigned int hook, unsigned int dataoff, unsigned int len, u_int8_t protocol) { - struct ipv6hdr *ip6h = ipv6_hdr(skb); + const struct ipv6hdr *ip6h = ipv6_hdr(skb); __wsum hsum; __sum16 csum = 0; diff --git a/net/ipv6/raw.c b/net/ipv6/raw.c index 4a1c3b4..e5e5425 100644 --- a/net/ipv6/raw.c +++ b/net/ipv6/raw.c @@ -67,8 +67,8 @@ static struct raw_hashinfo raw_v6_hashinfo = { }; static struct sock *__raw_v6_lookup(struct net *net, struct sock *sk, - unsigned short num, struct in6_addr *loc_addr, - struct in6_addr *rmt_addr, int dif) + unsigned short num, const struct in6_addr *loc_addr, + const struct in6_addr *rmt_addr, int dif) { struct hlist_node *node; int is_multicast = ipv6_addr_is_multicast(loc_addr); @@ -154,8 +154,8 @@ EXPORT_SYMBOL(rawv6_mh_filter_unregister); */ static int ipv6_raw_deliver(struct sk_buff *skb, int nexthdr) { - struct in6_addr *saddr; - struct in6_addr *daddr; + const struct in6_addr *saddr; + const struct in6_addr *daddr; struct sock *sk; int delivered = 0; __u8 hash; @@ -348,7 +348,7 @@ void raw6_icmp_error(struct sk_buff *skb, int nexthdr, { struct sock *sk; int hash; - struct in6_addr *saddr, *daddr; + const struct in6_addr *saddr, *daddr; struct net *net; hash = nexthdr & (RAW_HTABLE_SIZE - 1); @@ -357,7 +357,7 @@ void raw6_icmp_error(struct sk_buff *skb, int nexthdr, sk = sk_head(&raw_v6_hashinfo.ht[hash]); if (sk != NULL) { /* Note: ipv6_hdr(skb) != skb->data */ - struct ipv6hdr *ip6h = (struct ipv6hdr *)skb->data; + const struct ipv6hdr *ip6h = (const struct ipv6hdr *)skb->data; saddr = &ip6h->saddr; daddr = &ip6h->daddr; net = dev_net(skb->dev); @@ -1231,7 +1231,7 @@ struct proto rawv6_prot = { static void raw6_sock_seq_show(struct seq_file *seq, struct sock *sp, int i) { struct ipv6_pinfo *np = inet6_sk(sp); - struct in6_addr *dest, *src; + const struct in6_addr *dest, *src; __u16 destp, srcp; dest = &np->daddr; diff --git a/net/ipv6/reassembly.c b/net/ipv6/reassembly.c index 07beeb0..7b954e2 100644 --- a/net/ipv6/reassembly.c +++ b/net/ipv6/reassembly.c @@ -224,7 +224,7 @@ out: } static __inline__ struct frag_queue * -fq_find(struct net *net, __be32 id, struct in6_addr *src, struct in6_addr *dst) +fq_find(struct net *net, __be32 id, const struct in6_addr *src, const struct in6_addr *dst) { struct inet_frag_queue *q; struct ip6_create_arg arg; @@ -535,7 +535,7 @@ static int ipv6_frag_rcv(struct sk_buff *skb) { struct frag_hdr *fhdr; struct frag_queue *fq; - struct ipv6hdr *hdr = ipv6_hdr(skb); + const struct ipv6hdr *hdr = ipv6_hdr(skb); struct net *net = dev_net(skb_dst(skb)->dev); IP6_INC_STATS_BH(net, ip6_dst_idev(skb_dst(skb)), IPSTATS_MIB_REASMREQDS); diff --git a/net/ipv6/route.c b/net/ipv6/route.c index af26cc10..852fc28 100644 --- a/net/ipv6/route.c +++ b/net/ipv6/route.c @@ -89,12 +89,12 @@ static void ip6_rt_update_pmtu(struct dst_entry *dst, u32 mtu); #ifdef CONFIG_IPV6_ROUTE_INFO static struct rt6_info *rt6_add_route_info(struct net *net, - struct in6_addr *prefix, int prefixlen, - struct in6_addr *gwaddr, int ifindex, + const struct in6_addr *prefix, int prefixlen, + const struct in6_addr *gwaddr, int ifindex, unsigned pref); static struct rt6_info *rt6_get_route_info(struct net *net, - struct in6_addr *prefix, int prefixlen, - struct in6_addr *gwaddr, int ifindex); + const struct in6_addr *prefix, int prefixlen, + const struct in6_addr *gwaddr, int ifindex); #endif static u32 *ipv6_cow_metrics(struct dst_entry *dst, unsigned long old) @@ -283,7 +283,7 @@ static __inline__ int rt6_check_expired(const struct rt6_info *rt) time_after(jiffies, rt->rt6i_expires); } -static inline int rt6_need_strict(struct in6_addr *daddr) +static inline int rt6_need_strict(const struct in6_addr *daddr) { return ipv6_addr_type(daddr) & (IPV6_ADDR_MULTICAST | IPV6_ADDR_LINKLOCAL | IPV6_ADDR_LOOPBACK); @@ -295,7 +295,7 @@ static inline int rt6_need_strict(struct in6_addr *daddr) static inline struct rt6_info *rt6_device_match(struct net *net, struct rt6_info *rt, - struct in6_addr *saddr, + const struct in6_addr *saddr, int oif, int flags) { @@ -507,7 +507,7 @@ static struct rt6_info *rt6_select(struct fib6_node *fn, int oif, int strict) #ifdef CONFIG_IPV6_ROUTE_INFO int rt6_route_rcv(struct net_device *dev, u8 *opt, int len, - struct in6_addr *gwaddr) + const struct in6_addr *gwaddr) { struct net *net = dev_net(dev); struct route_info *rinfo = (struct route_info *) opt; @@ -670,8 +670,8 @@ int ip6_ins_rt(struct rt6_info *rt) return __ip6_ins_rt(rt, &info); } -static struct rt6_info *rt6_alloc_cow(struct rt6_info *ort, struct in6_addr *daddr, - struct in6_addr *saddr) +static struct rt6_info *rt6_alloc_cow(struct rt6_info *ort, const struct in6_addr *daddr, + const struct in6_addr *saddr) { struct rt6_info *rt; @@ -739,7 +739,7 @@ static struct rt6_info *rt6_alloc_cow(struct rt6_info *ort, struct in6_addr *dad return rt; } -static struct rt6_info *rt6_alloc_clone(struct rt6_info *ort, struct in6_addr *daddr) +static struct rt6_info *rt6_alloc_clone(struct rt6_info *ort, const struct in6_addr *daddr) { struct rt6_info *rt = ip6_rt_copy(ort); if (rt) { @@ -830,7 +830,7 @@ static struct rt6_info *ip6_pol_route_input(struct net *net, struct fib6_table * void ip6_route_input(struct sk_buff *skb) { - struct ipv6hdr *iph = ipv6_hdr(skb); + const struct ipv6hdr *iph = ipv6_hdr(skb); struct net *net = dev_net(skb->dev); int flags = RT6_LOOKUP_F_HAS_SADDR; struct flowi6 fl6 = { @@ -1272,7 +1272,7 @@ int ip6_route_add(struct fib6_config *cfg) } if (cfg->fc_flags & RTF_GATEWAY) { - struct in6_addr *gw_addr; + const struct in6_addr *gw_addr; int gwa_type; gw_addr = &cfg->fc_gateway; @@ -1512,9 +1512,9 @@ out: return rt; }; -static struct rt6_info *ip6_route_redirect(struct in6_addr *dest, - struct in6_addr *src, - struct in6_addr *gateway, +static struct rt6_info *ip6_route_redirect(const struct in6_addr *dest, + const struct in6_addr *src, + const struct in6_addr *gateway, struct net_device *dev) { int flags = RT6_LOOKUP_F_HAS_SADDR; @@ -1536,8 +1536,8 @@ static struct rt6_info *ip6_route_redirect(struct in6_addr *dest, flags, __ip6_route_redirect); } -void rt6_redirect(struct in6_addr *dest, struct in6_addr *src, - struct in6_addr *saddr, +void rt6_redirect(const struct in6_addr *dest, const struct in6_addr *src, + const struct in6_addr *saddr, struct neighbour *neigh, u8 *lladdr, int on_link) { struct rt6_info *rt, *nrt = NULL; @@ -1611,7 +1611,7 @@ out: * i.e. Path MTU discovery */ -static void rt6_do_pmtu_disc(struct in6_addr *daddr, struct in6_addr *saddr, +static void rt6_do_pmtu_disc(const struct in6_addr *daddr, const struct in6_addr *saddr, struct net *net, u32 pmtu, int ifindex) { struct rt6_info *rt, *nrt; @@ -1696,7 +1696,7 @@ out: dst_release(&rt->dst); } -void rt6_pmtu_discovery(struct in6_addr *daddr, struct in6_addr *saddr, +void rt6_pmtu_discovery(const struct in6_addr *daddr, const struct in6_addr *saddr, struct net_device *dev, u32 pmtu) { struct net *net = dev_net(dev); @@ -1756,8 +1756,8 @@ static struct rt6_info * ip6_rt_copy(struct rt6_info *ort) #ifdef CONFIG_IPV6_ROUTE_INFO static struct rt6_info *rt6_get_route_info(struct net *net, - struct in6_addr *prefix, int prefixlen, - struct in6_addr *gwaddr, int ifindex) + const struct in6_addr *prefix, int prefixlen, + const struct in6_addr *gwaddr, int ifindex) { struct fib6_node *fn; struct rt6_info *rt = NULL; @@ -1788,8 +1788,8 @@ out: } static struct rt6_info *rt6_add_route_info(struct net *net, - struct in6_addr *prefix, int prefixlen, - struct in6_addr *gwaddr, int ifindex, + const struct in6_addr *prefix, int prefixlen, + const struct in6_addr *gwaddr, int ifindex, unsigned pref) { struct fib6_config cfg = { @@ -1817,7 +1817,7 @@ static struct rt6_info *rt6_add_route_info(struct net *net, } #endif -struct rt6_info *rt6_get_dflt_router(struct in6_addr *addr, struct net_device *dev) +struct rt6_info *rt6_get_dflt_router(const struct in6_addr *addr, struct net_device *dev) { struct rt6_info *rt; struct fib6_table *table; @@ -1839,7 +1839,7 @@ struct rt6_info *rt6_get_dflt_router(struct in6_addr *addr, struct net_device *d return rt; } -struct rt6_info *rt6_add_dflt_router(struct in6_addr *gwaddr, +struct rt6_info *rt6_add_dflt_router(const struct in6_addr *gwaddr, struct net_device *dev, unsigned int pref) { @@ -2049,7 +2049,7 @@ struct rt6_info *addrconf_dst_alloc(struct inet6_dev *idev, int ip6_route_get_saddr(struct net *net, struct rt6_info *rt, - struct in6_addr *daddr, + const struct in6_addr *daddr, unsigned int prefs, struct in6_addr *saddr) { diff --git a/net/ipv6/sit.c b/net/ipv6/sit.c index 43b3337..34d8964 100644 --- a/net/ipv6/sit.c +++ b/net/ipv6/sit.c @@ -452,7 +452,7 @@ out: } static int -isatap_chksrc(struct sk_buff *skb, struct iphdr *iph, struct ip_tunnel *t) +isatap_chksrc(struct sk_buff *skb, const struct iphdr *iph, struct ip_tunnel *t) { struct ip_tunnel_prl_entry *p; int ok = 1; @@ -465,7 +465,8 @@ isatap_chksrc(struct sk_buff *skb, struct iphdr *iph, struct ip_tunnel *t) else skb->ndisc_nodetype = NDISC_NODETYPE_NODEFAULT; } else { - struct in6_addr *addr6 = &ipv6_hdr(skb)->saddr; + const struct in6_addr *addr6 = &ipv6_hdr(skb)->saddr; + if (ipv6_addr_is_isatap(addr6) && (addr6->s6_addr32[3] == iph->saddr) && ipv6_chk_prefix(addr6, t->dev)) @@ -499,7 +500,7 @@ static int ipip6_err(struct sk_buff *skb, u32 info) 8 bytes of packet payload. It means, that precise relaying of ICMP in the real Internet is absolutely infeasible. */ - struct iphdr *iph = (struct iphdr*)skb->data; + const struct iphdr *iph = (const struct iphdr *)skb->data; const int type = icmp_hdr(skb)->type; const int code = icmp_hdr(skb)->code; struct ip_tunnel *t; @@ -557,7 +558,7 @@ out: return err; } -static inline void ipip6_ecn_decapsulate(struct iphdr *iph, struct sk_buff *skb) +static inline void ipip6_ecn_decapsulate(const struct iphdr *iph, struct sk_buff *skb) { if (INET_ECN_is_ce(iph->tos)) IP6_ECN_set_ce(ipv6_hdr(skb)); @@ -565,7 +566,7 @@ static inline void ipip6_ecn_decapsulate(struct iphdr *iph, struct sk_buff *skb) static int ipip6_rcv(struct sk_buff *skb) { - struct iphdr *iph; + const struct iphdr *iph; struct ip_tunnel *tunnel; if (!pskb_may_pull(skb, sizeof(struct ipv6hdr))) @@ -621,7 +622,7 @@ out: * comes from 6rd / 6to4 (RFC 3056) addr space. */ static inline -__be32 try_6rd(struct in6_addr *v6dst, struct ip_tunnel *tunnel) +__be32 try_6rd(const struct in6_addr *v6dst, struct ip_tunnel *tunnel) { __be32 dst = 0; @@ -664,8 +665,8 @@ static netdev_tx_t ipip6_tunnel_xmit(struct sk_buff *skb, { struct ip_tunnel *tunnel = netdev_priv(dev); struct pcpu_tstats *tstats; - struct iphdr *tiph = &tunnel->parms.iph; - struct ipv6hdr *iph6 = ipv6_hdr(skb); + const struct iphdr *tiph = &tunnel->parms.iph; + const struct ipv6hdr *iph6 = ipv6_hdr(skb); u8 tos = tunnel->parms.iph.tos; __be16 df = tiph->frag_off; struct rtable *rt; /* Route to the other host */ @@ -674,7 +675,7 @@ static netdev_tx_t ipip6_tunnel_xmit(struct sk_buff *skb, unsigned int max_headroom; /* The extra header space needed */ __be32 dst = tiph->daddr; int mtu; - struct in6_addr *addr6; + const struct in6_addr *addr6; int addr_type; if (skb->protocol != htons(ETH_P_IPV6)) @@ -693,7 +694,7 @@ static netdev_tx_t ipip6_tunnel_xmit(struct sk_buff *skb, goto tx_error; } - addr6 = (struct in6_addr*)&neigh->primary_key; + addr6 = (const struct in6_addr*)&neigh->primary_key; addr_type = ipv6_addr_type(addr6); if ((addr_type & IPV6_ADDR_UNICAST) && @@ -718,7 +719,7 @@ static netdev_tx_t ipip6_tunnel_xmit(struct sk_buff *skb, goto tx_error; } - addr6 = (struct in6_addr*)&neigh->primary_key; + addr6 = (const struct in6_addr*)&neigh->primary_key; addr_type = ipv6_addr_type(addr6); if (addr_type == IPV6_ADDR_ANY) { @@ -849,7 +850,7 @@ static void ipip6_tunnel_bind_dev(struct net_device *dev) { struct net_device *tdev = NULL; struct ip_tunnel *tunnel; - struct iphdr *iph; + const struct iphdr *iph; tunnel = netdev_priv(dev); iph = &tunnel->parms.iph; diff --git a/net/ipv6/syncookies.c b/net/ipv6/syncookies.c index 352c260..8b9644a 100644 --- a/net/ipv6/syncookies.c +++ b/net/ipv6/syncookies.c @@ -66,7 +66,7 @@ static inline struct sock *get_cookie_sock(struct sock *sk, struct sk_buff *skb, static DEFINE_PER_CPU(__u32 [16 + 5 + SHA_WORKSPACE_WORDS], ipv6_cookie_scratch); -static u32 cookie_hash(struct in6_addr *saddr, struct in6_addr *daddr, +static u32 cookie_hash(const struct in6_addr *saddr, const struct in6_addr *daddr, __be16 sport, __be16 dport, u32 count, int c) { __u32 *tmp = __get_cpu_var(ipv6_cookie_scratch); @@ -86,7 +86,8 @@ static u32 cookie_hash(struct in6_addr *saddr, struct in6_addr *daddr, return tmp[17]; } -static __u32 secure_tcp_syn_cookie(struct in6_addr *saddr, struct in6_addr *daddr, +static __u32 secure_tcp_syn_cookie(const struct in6_addr *saddr, + const struct in6_addr *daddr, __be16 sport, __be16 dport, __u32 sseq, __u32 count, __u32 data) { @@ -96,8 +97,8 @@ static __u32 secure_tcp_syn_cookie(struct in6_addr *saddr, struct in6_addr *dadd & COOKIEMASK)); } -static __u32 check_tcp_syn_cookie(__u32 cookie, struct in6_addr *saddr, - struct in6_addr *daddr, __be16 sport, +static __u32 check_tcp_syn_cookie(__u32 cookie, const struct in6_addr *saddr, + const struct in6_addr *daddr, __be16 sport, __be16 dport, __u32 sseq, __u32 count, __u32 maxdiff) { @@ -116,7 +117,7 @@ static __u32 check_tcp_syn_cookie(__u32 cookie, struct in6_addr *saddr, __u32 cookie_v6_init_sequence(struct sock *sk, struct sk_buff *skb, __u16 *mssp) { - struct ipv6hdr *iph = ipv6_hdr(skb); + const struct ipv6hdr *iph = ipv6_hdr(skb); const struct tcphdr *th = tcp_hdr(skb); int mssind; const __u16 mss = *mssp; @@ -138,7 +139,7 @@ __u32 cookie_v6_init_sequence(struct sock *sk, struct sk_buff *skb, __u16 *mssp) static inline int cookie_check(struct sk_buff *skb, __u32 cookie) { - struct ipv6hdr *iph = ipv6_hdr(skb); + const struct ipv6hdr *iph = ipv6_hdr(skb); const struct tcphdr *th = tcp_hdr(skb); __u32 seq = ntohl(th->seq) - 1; __u32 mssind = check_tcp_syn_cookie(cookie, &iph->saddr, &iph->daddr, diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c index 4f49e5d..cb7658a 100644 --- a/net/ipv6/tcp_ipv6.c +++ b/net/ipv6/tcp_ipv6.c @@ -76,8 +76,8 @@ static void tcp_v6_reqsk_send_ack(struct sock *sk, struct sk_buff *skb, static int tcp_v6_do_rcv(struct sock *sk, struct sk_buff *skb); static void __tcp_v6_send_check(struct sk_buff *skb, - struct in6_addr *saddr, - struct in6_addr *daddr); + const struct in6_addr *saddr, + const struct in6_addr *daddr); static const struct inet_connection_sock_af_ops ipv6_mapped; static const struct inet_connection_sock_af_ops ipv6_specific; @@ -86,7 +86,7 @@ static const struct tcp_sock_af_ops tcp_sock_ipv6_specific; static const struct tcp_sock_af_ops tcp_sock_ipv6_mapped_specific; #else static struct tcp_md5sig_key *tcp_v6_md5_do_lookup(struct sock *sk, - struct in6_addr *addr) + const struct in6_addr *addr) { return NULL; } @@ -106,8 +106,8 @@ static void tcp_v6_hash(struct sock *sk) } static __inline__ __sum16 tcp_v6_check(int len, - struct in6_addr *saddr, - struct in6_addr *daddr, + const struct in6_addr *saddr, + const struct in6_addr *daddr, __wsum base) { return csum_ipv6_magic(saddr, daddr, len, IPPROTO_TCP, base); @@ -331,7 +331,7 @@ failure: static void tcp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, u8 type, u8 code, int offset, __be32 info) { - struct ipv6hdr *hdr = (struct ipv6hdr*)skb->data; + const struct ipv6hdr *hdr = (const struct ipv6hdr*)skb->data; const struct tcphdr *th = (struct tcphdr *)(skb->data+offset); struct ipv6_pinfo *np; struct sock *sk; @@ -551,7 +551,7 @@ static void tcp_v6_reqsk_destructor(struct request_sock *req) #ifdef CONFIG_TCP_MD5SIG static struct tcp_md5sig_key *tcp_v6_md5_do_lookup(struct sock *sk, - struct in6_addr *addr) + const struct in6_addr *addr) { struct tcp_sock *tp = tcp_sk(sk); int i; @@ -580,7 +580,7 @@ static struct tcp_md5sig_key *tcp_v6_reqsk_md5_lookup(struct sock *sk, return tcp_v6_md5_do_lookup(sk, &inet6_rsk(req)->rmt_addr); } -static int tcp_v6_md5_do_add(struct sock *sk, struct in6_addr *peer, +static int tcp_v6_md5_do_add(struct sock *sk, const struct in6_addr *peer, char *newkey, u8 newkeylen) { /* Add key to the list */ @@ -645,7 +645,7 @@ static int tcp_v6_md5_add_func(struct sock *sk, struct sock *addr_sk, newkey, newkeylen); } -static int tcp_v6_md5_do_del(struct sock *sk, struct in6_addr *peer) +static int tcp_v6_md5_do_del(struct sock *sk, const struct in6_addr *peer) { struct tcp_sock *tp = tcp_sk(sk); int i; @@ -753,8 +753,8 @@ static int tcp_v6_parse_md5_keys (struct sock *sk, char __user *optval, } static int tcp_v6_md5_hash_pseudoheader(struct tcp_md5sig_pool *hp, - struct in6_addr *daddr, - struct in6_addr *saddr, int nbytes) + const struct in6_addr *daddr, + const struct in6_addr *saddr, int nbytes) { struct tcp6_pseudohdr *bp; struct scatterlist sg; @@ -771,7 +771,7 @@ static int tcp_v6_md5_hash_pseudoheader(struct tcp_md5sig_pool *hp, } static int tcp_v6_md5_hash_hdr(char *md5_hash, struct tcp_md5sig_key *key, - struct in6_addr *daddr, struct in6_addr *saddr, + const struct in6_addr *daddr, struct in6_addr *saddr, struct tcphdr *th) { struct tcp_md5sig_pool *hp; @@ -807,7 +807,7 @@ static int tcp_v6_md5_hash_skb(char *md5_hash, struct tcp_md5sig_key *key, struct sock *sk, struct request_sock *req, struct sk_buff *skb) { - struct in6_addr *saddr, *daddr; + const struct in6_addr *saddr, *daddr; struct tcp_md5sig_pool *hp; struct hash_desc *desc; struct tcphdr *th = tcp_hdr(skb); @@ -819,7 +819,7 @@ static int tcp_v6_md5_hash_skb(char *md5_hash, struct tcp_md5sig_key *key, saddr = &inet6_rsk(req)->loc_addr; daddr = &inet6_rsk(req)->rmt_addr; } else { - struct ipv6hdr *ip6h = ipv6_hdr(skb); + const struct ipv6hdr *ip6h = ipv6_hdr(skb); saddr = &ip6h->saddr; daddr = &ip6h->daddr; } @@ -857,7 +857,7 @@ static int tcp_v6_inbound_md5_hash (struct sock *sk, struct sk_buff *skb) { __u8 *hash_location = NULL; struct tcp_md5sig_key *hash_expected; - struct ipv6hdr *ip6h = ipv6_hdr(skb); + const struct ipv6hdr *ip6h = ipv6_hdr(skb); struct tcphdr *th = tcp_hdr(skb); int genhash; u8 newhash[16]; @@ -915,7 +915,7 @@ static const struct tcp_request_sock_ops tcp_request_sock_ipv6_ops = { #endif static void __tcp_v6_send_check(struct sk_buff *skb, - struct in6_addr *saddr, struct in6_addr *daddr) + const struct in6_addr *saddr, const struct in6_addr *daddr) { struct tcphdr *th = tcp_hdr(skb); @@ -939,7 +939,7 @@ static void tcp_v6_send_check(struct sock *sk, struct sk_buff *skb) static int tcp_v6_gso_send_check(struct sk_buff *skb) { - struct ipv6hdr *ipv6h; + const struct ipv6hdr *ipv6h; struct tcphdr *th; if (!pskb_may_pull(skb, sizeof(*th))) @@ -957,7 +957,7 @@ static int tcp_v6_gso_send_check(struct sk_buff *skb) static struct sk_buff **tcp6_gro_receive(struct sk_buff **head, struct sk_buff *skb) { - struct ipv6hdr *iph = skb_gro_network_header(skb); + const struct ipv6hdr *iph = skb_gro_network_header(skb); switch (skb->ip_summed) { case CHECKSUM_COMPLETE: @@ -978,7 +978,7 @@ static struct sk_buff **tcp6_gro_receive(struct sk_buff **head, static int tcp6_gro_complete(struct sk_buff *skb) { - struct ipv6hdr *iph = ipv6_hdr(skb); + const struct ipv6hdr *iph = ipv6_hdr(skb); struct tcphdr *th = tcp_hdr(skb); th->check = ~tcp_v6_check(skb->len - skb_transport_offset(skb), @@ -1702,7 +1702,7 @@ ipv6_pktoptions: static int tcp_v6_rcv(struct sk_buff *skb) { struct tcphdr *th; - struct ipv6hdr *hdr; + const struct ipv6hdr *hdr; struct sock *sk; int ret; struct net *net = dev_net(skb->dev); @@ -2028,8 +2028,8 @@ static void get_openreq6(struct seq_file *seq, struct sock *sk, struct request_sock *req, int i, int uid) { int ttd = req->expires - jiffies; - struct in6_addr *src = &inet6_rsk(req)->loc_addr; - struct in6_addr *dest = &inet6_rsk(req)->rmt_addr; + const struct in6_addr *src = &inet6_rsk(req)->loc_addr; + const struct in6_addr *dest = &inet6_rsk(req)->rmt_addr; if (ttd < 0) ttd = 0; @@ -2057,7 +2057,7 @@ static void get_openreq6(struct seq_file *seq, static void get_tcp6_sock(struct seq_file *seq, struct sock *sp, int i) { - struct in6_addr *dest, *src; + const struct in6_addr *dest, *src; __u16 destp, srcp; int timer_active; unsigned long timer_expires; @@ -2114,7 +2114,7 @@ static void get_tcp6_sock(struct seq_file *seq, struct sock *sp, int i) static void get_timewait6_sock(struct seq_file *seq, struct inet_timewait_sock *tw, int i) { - struct in6_addr *dest, *src; + const struct in6_addr *dest, *src; __u16 destp, srcp; struct inet6_timewait_sock *tw6 = inet6_twsk((struct sock *)tw); int ttd = tw->tw_ttd - jiffies; diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c index 15c3774..1bdc5f0 100644 --- a/net/ipv6/udp.c +++ b/net/ipv6/udp.c @@ -311,7 +311,7 @@ static struct sock *__udp6_lib_lookup_skb(struct sk_buff *skb, struct udp_table *udptable) { struct sock *sk; - struct ipv6hdr *iph = ipv6_hdr(skb); + const struct ipv6hdr *iph = ipv6_hdr(skb); if (unlikely(sk = skb_steal_sock(skb))) return sk; @@ -463,9 +463,9 @@ void __udp6_lib_err(struct sk_buff *skb, struct inet6_skb_parm *opt, struct udp_table *udptable) { struct ipv6_pinfo *np; - struct ipv6hdr *hdr = (struct ipv6hdr*)skb->data; - struct in6_addr *saddr = &hdr->saddr; - struct in6_addr *daddr = &hdr->daddr; + const struct ipv6hdr *hdr = (const struct ipv6hdr *)skb->data; + const struct in6_addr *saddr = &hdr->saddr; + const struct in6_addr *daddr = &hdr->daddr; struct udphdr *uh = (struct udphdr*)(skb->data+offset); struct sock *sk; int err; @@ -553,8 +553,8 @@ drop_no_sk_drops_inc: } static struct sock *udp_v6_mcast_next(struct net *net, struct sock *sk, - __be16 loc_port, struct in6_addr *loc_addr, - __be16 rmt_port, struct in6_addr *rmt_addr, + __be16 loc_port, const struct in6_addr *loc_addr, + __be16 rmt_port, const struct in6_addr *rmt_addr, int dif) { struct hlist_nulls_node *node; @@ -633,7 +633,7 @@ drop: * so we don't need to lock the hashes. */ static int __udp6_lib_mcast_deliver(struct net *net, struct sk_buff *skb, - struct in6_addr *saddr, struct in6_addr *daddr, + const struct in6_addr *saddr, const struct in6_addr *daddr, struct udp_table *udptable) { struct sock *sk, *stack[256 / sizeof(struct sock *)]; @@ -716,7 +716,7 @@ int __udp6_lib_rcv(struct sk_buff *skb, struct udp_table *udptable, struct net *net = dev_net(skb->dev); struct sock *sk; struct udphdr *uh; - struct in6_addr *saddr, *daddr; + const struct in6_addr *saddr, *daddr; u32 ulen = 0; if (!pskb_may_pull(skb, sizeof(struct udphdr))) @@ -1278,7 +1278,7 @@ int compat_udpv6_getsockopt(struct sock *sk, int level, int optname, static int udp6_ufo_send_check(struct sk_buff *skb) { - struct ipv6hdr *ipv6h; + const struct ipv6hdr *ipv6h; struct udphdr *uh; if (!pskb_may_pull(skb, sizeof(*uh))) @@ -1382,7 +1382,7 @@ static void udp6_sock_seq_show(struct seq_file *seq, struct sock *sp, int bucket { struct inet_sock *inet = inet_sk(sp); struct ipv6_pinfo *np = inet6_sk(sp); - struct in6_addr *dest, *src; + const struct in6_addr *dest, *src; __u16 destp, srcp; dest = &np->daddr; diff --git a/net/ipv6/xfrm6_mode_beet.c b/net/ipv6/xfrm6_mode_beet.c index bbd48b1..3437d7d 100644 --- a/net/ipv6/xfrm6_mode_beet.c +++ b/net/ipv6/xfrm6_mode_beet.c @@ -41,10 +41,8 @@ static int xfrm6_beet_output(struct xfrm_state *x, struct sk_buff *skb) { struct ipv6hdr *top_iph; struct ip_beet_phdr *ph; - struct iphdr *iphv4; int optlen, hdr_len; - iphv4 = ip_hdr(skb); hdr_len = 0; optlen = XFRM_MODE_SKB_CB(skb)->optlen; if (unlikely(optlen)) diff --git a/net/ipv6/xfrm6_mode_tunnel.c b/net/ipv6/xfrm6_mode_tunnel.c index 645cb96..4d6edff 100644 --- a/net/ipv6/xfrm6_mode_tunnel.c +++ b/net/ipv6/xfrm6_mode_tunnel.c @@ -20,7 +20,7 @@ static inline void ipip6_ecn_decapsulate(struct sk_buff *skb) { - struct ipv6hdr *outer_iph = ipv6_hdr(skb); + const struct ipv6hdr *outer_iph = ipv6_hdr(skb); struct ipv6hdr *inner_iph = ipipv6_hdr(skb); if (INET_ECN_is_ce(ipv6_get_dsfield(outer_iph))) @@ -55,8 +55,8 @@ static int xfrm6_mode_tunnel_output(struct xfrm_state *x, struct sk_buff *skb) dsfield &= ~INET_ECN_MASK; ipv6_change_dsfield(top_iph, 0, dsfield); top_iph->hop_limit = ip6_dst_hoplimit(dst->child); - ipv6_addr_copy(&top_iph->saddr, (struct in6_addr *)&x->props.saddr); - ipv6_addr_copy(&top_iph->daddr, (struct in6_addr *)&x->id.daddr); + ipv6_addr_copy(&top_iph->saddr, (const struct in6_addr *)&x->props.saddr); + ipv6_addr_copy(&top_iph->daddr, (const struct in6_addr *)&x->id.daddr); return 0; } diff --git a/net/ipv6/xfrm6_policy.c b/net/ipv6/xfrm6_policy.c index 05e34c8..d879f7e 100644 --- a/net/ipv6/xfrm6_policy.c +++ b/net/ipv6/xfrm6_policy.c @@ -124,7 +124,7 @@ _decode_session6(struct sk_buff *skb, struct flowi *fl, int reverse) struct flowi6 *fl6 = &fl->u.ip6; int onlyproto = 0; u16 offset = skb_network_header_len(skb); - struct ipv6hdr *hdr = ipv6_hdr(skb); + const struct ipv6hdr *hdr = ipv6_hdr(skb); struct ipv6_opt_hdr *exthdr; const unsigned char *nh = skb_network_header(skb); u8 nexthdr = nh[IP6CB(skb)->nhoff]; diff --git a/net/ipv6/xfrm6_tunnel.c b/net/ipv6/xfrm6_tunnel.c index 2969cad..a6770a0 100644 --- a/net/ipv6/xfrm6_tunnel.c +++ b/net/ipv6/xfrm6_tunnel.c @@ -68,7 +68,7 @@ static DEFINE_SPINLOCK(xfrm6_tunnel_spi_lock); static struct kmem_cache *xfrm6_tunnel_spi_kmem __read_mostly; -static inline unsigned xfrm6_tunnel_spi_hash_byaddr(xfrm_address_t *addr) +static inline unsigned xfrm6_tunnel_spi_hash_byaddr(const xfrm_address_t *addr) { unsigned h; @@ -85,7 +85,7 @@ static inline unsigned xfrm6_tunnel_spi_hash_byspi(u32 spi) return spi % XFRM6_TUNNEL_SPI_BYSPI_HSIZE; } -static struct xfrm6_tunnel_spi *__xfrm6_tunnel_spi_lookup(struct net *net, xfrm_address_t *saddr) +static struct xfrm6_tunnel_spi *__xfrm6_tunnel_spi_lookup(struct net *net, const xfrm_address_t *saddr) { struct xfrm6_tunnel_net *xfrm6_tn = xfrm6_tunnel_pernet(net); struct xfrm6_tunnel_spi *x6spi; @@ -101,7 +101,7 @@ static struct xfrm6_tunnel_spi *__xfrm6_tunnel_spi_lookup(struct net *net, xfrm_ return NULL; } -__be32 xfrm6_tunnel_spi_lookup(struct net *net, xfrm_address_t *saddr) +__be32 xfrm6_tunnel_spi_lookup(struct net *net, const xfrm_address_t *saddr) { struct xfrm6_tunnel_spi *x6spi; u32 spi; @@ -237,10 +237,10 @@ static int xfrm6_tunnel_input(struct xfrm_state *x, struct sk_buff *skb) static int xfrm6_tunnel_rcv(struct sk_buff *skb) { struct net *net = dev_net(skb->dev); - struct ipv6hdr *iph = ipv6_hdr(skb); + const struct ipv6hdr *iph = ipv6_hdr(skb); __be32 spi; - spi = xfrm6_tunnel_spi_lookup(net, (xfrm_address_t *)&iph->saddr); + spi = xfrm6_tunnel_spi_lookup(net, (const xfrm_address_t *)&iph->saddr); return xfrm6_rcv_spi(skb, IPPROTO_IPV6, spi) > 0 ? : 0; } diff --git a/net/key/af_key.c b/net/key/af_key.c index 7db86ff..d62401c 100644 --- a/net/key/af_key.c +++ b/net/key/af_key.c @@ -712,7 +712,7 @@ static unsigned int pfkey_sockaddr_fill(const xfrm_address_t *xaddr, __be16 port sin6->sin6_family = AF_INET6; sin6->sin6_port = port; sin6->sin6_flowinfo = 0; - ipv6_addr_copy(&sin6->sin6_addr, (struct in6_addr *)xaddr->a6); + ipv6_addr_copy(&sin6->sin6_addr, (const struct in6_addr *)xaddr->a6); sin6->sin6_scope_id = 0; return 128; } diff --git a/net/sched/sch_sfq.c b/net/sched/sch_sfq.c index c2e628d..7ef87f9 100644 --- a/net/sched/sch_sfq.c +++ b/net/sched/sch_sfq.c @@ -169,7 +169,7 @@ static unsigned int sfq_hash(struct sfq_sched_data *q, struct sk_buff *skb) } case htons(ETH_P_IPV6): { - struct ipv6hdr *iph; + const struct ipv6hdr *iph; int poff; if (!pskb_network_may_pull(skb, sizeof(*iph))) diff --git a/net/sctp/input.c b/net/sctp/input.c index 3a8eb79..741ed16 100644 --- a/net/sctp/input.c +++ b/net/sctp/input.c @@ -565,7 +565,7 @@ void sctp_err_finish(struct sock *sk, struct sctp_association *asoc) */ void sctp_v4_err(struct sk_buff *skb, __u32 info) { - struct iphdr *iph = (struct iphdr *)skb->data; + const struct iphdr *iph = (const struct iphdr *)skb->data; const int ihlen = iph->ihl * 4; const int type = icmp_hdr(skb)->type; const int code = icmp_hdr(skb)->code; diff --git a/net/sctp/ipv6.c b/net/sctp/ipv6.c index 865ce7b..321f175 100644 --- a/net/sctp/ipv6.c +++ b/net/sctp/ipv6.c @@ -531,7 +531,7 @@ static int sctp_v6_is_any(const union sctp_addr *addr) static int sctp_v6_available(union sctp_addr *addr, struct sctp_sock *sp) { int type; - struct in6_addr *in6 = (struct in6_addr *)&addr->v6.sin6_addr; + const struct in6_addr *in6 = (const struct in6_addr *)&addr->v6.sin6_addr; type = ipv6_addr_type(in6); if (IPV6_ADDR_ANY == type) diff --git a/net/xfrm/xfrm_state.c b/net/xfrm/xfrm_state.c index dd78536..d70f85e 100644 --- a/net/xfrm/xfrm_state.c +++ b/net/xfrm/xfrm_state.c @@ -1036,15 +1036,15 @@ static struct xfrm_state *__find_acq_core(struct net *net, struct xfrm_mark *m, case AF_INET6: ipv6_addr_copy((struct in6_addr *)x->sel.daddr.a6, - (struct in6_addr *)daddr); + (const struct in6_addr *)daddr); ipv6_addr_copy((struct in6_addr *)x->sel.saddr.a6, - (struct in6_addr *)saddr); + (const struct in6_addr *)saddr); x->sel.prefixlen_d = 128; x->sel.prefixlen_s = 128; ipv6_addr_copy((struct in6_addr *)x->props.saddr.a6, - (struct in6_addr *)saddr); + (const struct in6_addr *)saddr); ipv6_addr_copy((struct in6_addr *)x->id.daddr.a6, - (struct in6_addr *)daddr); + (const struct in6_addr *)daddr); break; } @@ -2092,8 +2092,8 @@ static void xfrm_audit_helper_sainfo(struct xfrm_state *x, static void xfrm_audit_helper_pktinfo(struct sk_buff *skb, u16 family, struct audit_buffer *audit_buf) { - struct iphdr *iph4; - struct ipv6hdr *iph6; + const struct iphdr *iph4; + const struct ipv6hdr *iph6; switch (family) { case AF_INET: -- cgit v0.10.2 From 4a5fa3590f09999f6db41bc386bce40848fa9f63 Mon Sep 17 00:00:00 2001 From: James Bottomley Date: Tue, 19 Apr 2011 16:29:36 -0500 Subject: [PARISC] slub: fix panic with DISCONTIGMEM Slub makes assumptions about page_to_nid() which are violated by DISCONTIGMEM and !NUMA. This violation results in a panic because page_to_nid() can be non-zero for pages in the discontiguous ranges and this leads to a null return by get_node(). The assertion by the maintainer is that DISCONTIGMEM should only be allowed when NUMA is also defined. However, at least six architectures: alpha, ia64, m32r, m68k, mips, parisc violate this. The panic is a regression against slab, so just mark slub broken in the problem configuration to prevent users reporting these panics. Cc: stable@kernel.org Acked-by: David Rientjes Acked-by: Pekka Enberg Signed-off-by: James Bottomley diff --git a/init/Kconfig b/init/Kconfig index 56240e7..a7ad8fb 100644 --- a/init/Kconfig +++ b/init/Kconfig @@ -1226,6 +1226,7 @@ config SLAB per cpu and per node queues. config SLUB + depends on BROKEN || NUMA || !DISCONTIGMEM bool "SLUB (Unqueued Allocator)" help SLUB is a slab allocator that minimizes cache line usage -- cgit v0.10.2 From 13f172ff26563995049abe73f6eeba828de3c09d Mon Sep 17 00:00:00 2001 From: Neil Horman Date: Fri, 22 Apr 2011 08:10:59 +0000 Subject: netconsole: fix deadlock when removing net driver that netconsole is using (v2) A deadlock was reported to me recently that occured when netconsole was being used in a virtual guest. If the virtio_net driver was removed while netconsole was setup to use an interface that was driven by that driver, the guest deadlocked. No backtrace was provided because netconsole was the only console configured, but it became clear pretty quickly what the problem was. In netconsole_netdev_event, if we get an unregister event, we call __netpoll_cleanup with the target_list_lock held and irqs disabled. __netpoll_cleanup can, if pending netpoll packets are waiting call cancel_delayed_work_sync, which is a sleeping path. the might_sleep call in that path gets triggered, causing a console warning to be issued. The netconsole write handler of course tries to take the target_list_lock again, which we already hold, causing deadlock. The fix is pretty striaghtforward. Simply drop the target_list_lock and re-enable irqs prior to calling __netpoll_cleanup, the re-acquire the lock, and restart the loop. Confirmed by myself to fix the problem reported. Signed-off-by: Neil Horman CC: "David S. Miller" Signed-off-by: David S. Miller diff --git a/drivers/net/netconsole.c b/drivers/net/netconsole.c index dfb67eb..eb41e44 100644 --- a/drivers/net/netconsole.c +++ b/drivers/net/netconsole.c @@ -671,6 +671,7 @@ static int netconsole_netdev_event(struct notifier_block *this, goto done; spin_lock_irqsave(&target_list_lock, flags); +restart: list_for_each_entry(nt, &target_list, list) { netconsole_target_get(nt); if (nt->np.dev == dev) { @@ -683,9 +684,16 @@ static int netconsole_netdev_event(struct notifier_block *this, * rtnl_lock already held */ if (nt->np.dev) { + spin_unlock_irqrestore( + &target_list_lock, + flags); __netpoll_cleanup(&nt->np); + spin_lock_irqsave(&target_list_lock, + flags); dev_put(nt->np.dev); nt->np.dev = NULL; + netconsole_target_put(nt); + goto restart; } /* Fall through */ case NETDEV_GOING_DOWN: -- cgit v0.10.2 From 8c9e80ed276fc4b9c9fadf29d8bf6b3576112f1a Mon Sep 17 00:00:00 2001 From: Andi Kleen Date: Thu, 21 Apr 2011 17:23:19 -0700 Subject: SECURITY: Move exec_permission RCU checks into security modules Right now all RCU walks fall back to reference walk when CONFIG_SECURITY is enabled, even though just the standard capability module is active. This is because security_inode_exec_permission unconditionally fails RCU walks. Move this decision to the low level security module. This requires passing the RCU flags down the security hook. This way at least the capability module and a few easy cases in selinux/smack work with RCU walks with CONFIG_SECURITY=y Signed-off-by: Andi Kleen Acked-by: Eric Paris Signed-off-by: Linus Torvalds diff --git a/include/linux/security.h b/include/linux/security.h index ca02f17..8ce59ef 100644 --- a/include/linux/security.h +++ b/include/linux/security.h @@ -1456,7 +1456,7 @@ struct security_operations { struct inode *new_dir, struct dentry *new_dentry); int (*inode_readlink) (struct dentry *dentry); int (*inode_follow_link) (struct dentry *dentry, struct nameidata *nd); - int (*inode_permission) (struct inode *inode, int mask); + int (*inode_permission) (struct inode *inode, int mask, unsigned flags); int (*inode_setattr) (struct dentry *dentry, struct iattr *attr); int (*inode_getattr) (struct vfsmount *mnt, struct dentry *dentry); int (*inode_setxattr) (struct dentry *dentry, const char *name, diff --git a/security/capability.c b/security/capability.c index 2984ea4..bbb5115 100644 --- a/security/capability.c +++ b/security/capability.c @@ -181,7 +181,7 @@ static int cap_inode_follow_link(struct dentry *dentry, return 0; } -static int cap_inode_permission(struct inode *inode, int mask) +static int cap_inode_permission(struct inode *inode, int mask, unsigned flags) { return 0; } diff --git a/security/security.c b/security/security.c index 1011423..4ba6d4c 100644 --- a/security/security.c +++ b/security/security.c @@ -518,16 +518,14 @@ int security_inode_permission(struct inode *inode, int mask) { if (unlikely(IS_PRIVATE(inode))) return 0; - return security_ops->inode_permission(inode, mask); + return security_ops->inode_permission(inode, mask, 0); } int security_inode_exec_permission(struct inode *inode, unsigned int flags) { if (unlikely(IS_PRIVATE(inode))) return 0; - if (flags) - return -ECHILD; - return security_ops->inode_permission(inode, MAY_EXEC); + return security_ops->inode_permission(inode, MAY_EXEC, flags); } int security_inode_setattr(struct dentry *dentry, struct iattr *attr) diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index f9c3764..a73f4e4 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c @@ -2635,7 +2635,7 @@ static int selinux_inode_follow_link(struct dentry *dentry, struct nameidata *na return dentry_has_perm(cred, NULL, dentry, FILE__READ); } -static int selinux_inode_permission(struct inode *inode, int mask) +static int selinux_inode_permission(struct inode *inode, int mask, unsigned flags) { const struct cred *cred = current_cred(); struct common_audit_data ad; @@ -2649,6 +2649,10 @@ static int selinux_inode_permission(struct inode *inode, int mask) if (!mask) return 0; + /* May be droppable after audit */ + if (flags & IPERM_FLAG_RCU) + return -ECHILD; + COMMON_AUDIT_DATA_INIT(&ad, FS); ad.u.fs.inode = inode; diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c index c6f8fca..400a5d5 100644 --- a/security/smack/smack_lsm.c +++ b/security/smack/smack_lsm.c @@ -686,7 +686,7 @@ static int smack_inode_rename(struct inode *old_inode, * * Returns 0 if access is permitted, -EACCES otherwise */ -static int smack_inode_permission(struct inode *inode, int mask) +static int smack_inode_permission(struct inode *inode, int mask, unsigned flags) { struct smk_audit_info ad; @@ -696,6 +696,10 @@ static int smack_inode_permission(struct inode *inode, int mask) */ if (mask == 0) return 0; + + /* May be droppable after audit */ + if (flags & IPERM_FLAG_RCU) + return -ECHILD; smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_FS); smk_ad_setfield_u_fs_inode(&ad, inode); return smk_curacc(smk_of_inode(inode), mask, &ad); -- cgit v0.10.2 From 764b0c4b3256ad4431cb52eaf99c0abe6df0a085 Mon Sep 17 00:00:00 2001 From: Pavan Savoy Date: Fri, 8 Apr 2011 04:57:42 -0500 Subject: drivers:misc:ti-st: handle delayed tty receive When certain technologies shutdown their interface without waiting for the acknowledgement from the chip. The receive_buf from the TTY would be invoked a while after the relevant technology is unregistered. This patch introduces a new flag "is_registered" which maintains the state of protocols BT, FM or GPS and thereby removes the need to clear the protocol data from ST when protocols gets unregistered. This fixes corner cases when HCI RESET is sent down from bluetooth stack and the receive_buf is called from tty after 250ms before which bluetooth would have unregistered from the system. OR - when FM application decides to close down the device without sending a power-off FM command resulting in some RDS data or interrupt data coming in after the driver is unregistered. Signed-off-by: Pavan Savoy Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/misc/ti-st/st_core.c b/drivers/misc/ti-st/st_core.c index 486117f..f91f82e 100644 --- a/drivers/misc/ti-st/st_core.c +++ b/drivers/misc/ti-st/st_core.c @@ -43,13 +43,15 @@ static void add_channel_to_table(struct st_data_s *st_gdata, pr_info("%s: id %d\n", __func__, new_proto->chnl_id); /* list now has the channel id as index itself */ st_gdata->list[new_proto->chnl_id] = new_proto; + st_gdata->is_registered[new_proto->chnl_id] = true; } static void remove_channel_from_table(struct st_data_s *st_gdata, struct st_proto_s *proto) { pr_info("%s: id %d\n", __func__, proto->chnl_id); - st_gdata->list[proto->chnl_id] = NULL; +/* st_gdata->list[proto->chnl_id] = NULL; */ + st_gdata->is_registered[proto->chnl_id] = false; } /* @@ -104,7 +106,7 @@ void st_send_frame(unsigned char chnl_id, struct st_data_s *st_gdata) if (unlikely (st_gdata == NULL || st_gdata->rx_skb == NULL - || st_gdata->list[chnl_id] == NULL)) { + || st_gdata->is_registered[chnl_id] == false)) { pr_err("chnl_id %d not registered, no data to send?", chnl_id); kfree_skb(st_gdata->rx_skb); @@ -141,14 +143,15 @@ void st_reg_complete(struct st_data_s *st_gdata, char err) unsigned char i = 0; pr_info(" %s ", __func__); for (i = 0; i < ST_MAX_CHANNELS; i++) { - if (likely(st_gdata != NULL && st_gdata->list[i] != NULL && - st_gdata->list[i]->reg_complete_cb != NULL)) { + if (likely(st_gdata != NULL && + st_gdata->is_registered[i] == true && + st_gdata->list[i]->reg_complete_cb != NULL)) { st_gdata->list[i]->reg_complete_cb (st_gdata->list[i]->priv_data, err); pr_info("protocol %d's cb sent %d\n", i, err); if (err) { /* cleanup registered protocol */ st_gdata->protos_registered--; - st_gdata->list[i] = NULL; + st_gdata->is_registered[i] = false; } } } @@ -475,9 +478,9 @@ void kim_st_list_protocols(struct st_data_s *st_gdata, void *buf) { seq_printf(buf, "[%d]\nBT=%c\nFM=%c\nGPS=%c\n", st_gdata->protos_registered, - st_gdata->list[0x04] != NULL ? 'R' : 'U', - st_gdata->list[0x08] != NULL ? 'R' : 'U', - st_gdata->list[0x09] != NULL ? 'R' : 'U'); + st_gdata->is_registered[0x04] == true ? 'R' : 'U', + st_gdata->is_registered[0x08] == true ? 'R' : 'U', + st_gdata->is_registered[0x09] == true ? 'R' : 'U'); } /********************************************************************/ @@ -504,7 +507,7 @@ long st_register(struct st_proto_s *new_proto) return -EPROTONOSUPPORT; } - if (st_gdata->list[new_proto->chnl_id] != NULL) { + if (st_gdata->is_registered[new_proto->chnl_id] == true) { pr_err("chnl_id %d already registered", new_proto->chnl_id); return -EALREADY; } @@ -563,7 +566,7 @@ long st_register(struct st_proto_s *new_proto) /* check for already registered once more, * since the above check is old */ - if (st_gdata->list[new_proto->chnl_id] != NULL) { + if (st_gdata->is_registered[new_proto->chnl_id] == true) { pr_err(" proto %d already registered ", new_proto->chnl_id); return -EALREADY; diff --git a/include/linux/ti_wilink_st.h b/include/linux/ti_wilink_st.h index 7071ec5..b004e55 100644 --- a/include/linux/ti_wilink_st.h +++ b/include/linux/ti_wilink_st.h @@ -140,12 +140,12 @@ extern long st_unregister(struct st_proto_s *); */ struct st_data_s { unsigned long st_state; - struct tty_struct *tty; struct sk_buff *tx_skb; #define ST_TX_SENDING 1 #define ST_TX_WAKEUP 2 unsigned long tx_state; struct st_proto_s *list[ST_MAX_CHANNELS]; + bool is_registered[ST_MAX_CHANNELS]; unsigned long rx_state; unsigned long rx_count; struct sk_buff *rx_skb; @@ -155,6 +155,7 @@ struct st_data_s { unsigned char protos_registered; unsigned long ll_state; void *kim_data; + struct tty_struct *tty; }; /* -- cgit v0.10.2 From fc2711992b8601c20b7cc078f533e55c3106fbd4 Mon Sep 17 00:00:00 2001 From: Pavan Savoy Date: Fri, 8 Apr 2011 04:57:43 -0500 Subject: drivers:misc:ti-st: remove rfkill dependency rfkill is no longer used by Texas Instruments shared transport driver to communicate with user-space. This patch removes the dependency of rfkill to be enabled to build shared transport driver in the Kconfig. Signed-off-by: Pavan Savoy Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/misc/ti-st/Kconfig b/drivers/misc/ti-st/Kconfig index 2c8c3f39..7c3e106 100644 --- a/drivers/misc/ti-st/Kconfig +++ b/drivers/misc/ti-st/Kconfig @@ -5,7 +5,6 @@ menu "Texas Instruments shared transport line discipline" config TI_ST tristate "Shared transport core driver" - depends on RFKILL select FW_LOADER help This enables the shared transport core driver for TI -- cgit v0.10.2 From 8497d6a21c4b17052e868bd53a74c82b557a6c46 Mon Sep 17 00:00:00 2001 From: Sebastian Ott Date: Tue, 12 Apr 2011 19:05:37 +0200 Subject: driver-core: fix race between device_register and driver_register When a device is registered to a bus it will be a) added to the list of devices of the bus and b) bind to a driver (if one matches). As a result of a driver being registered at this bus between a) and b) this device could already be bound to a driver. This leads to a warning and incorrect refcounting. To fix this add a check to device_attach to identify an already bound device. Signed-off-by: Sebastian Ott Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/base/dd.c b/drivers/base/dd.c index da57ee9..7e9219b 100644 --- a/drivers/base/dd.c +++ b/drivers/base/dd.c @@ -245,6 +245,10 @@ int device_attach(struct device *dev) device_lock(dev); if (dev->driver) { + if (klist_node_attached(&dev->p->knode_driver)) { + ret = 1; + goto out_unlock; + } ret = device_bind_driver(dev); if (ret == 0) ret = 1; @@ -257,6 +261,7 @@ int device_attach(struct device *dev) ret = bus_for_each_drv(dev->bus, NULL, dev, __device_attach); pm_runtime_put_sync(dev); } +out_unlock: device_unlock(dev); return ret; } -- cgit v0.10.2 From 7f100d1566d6ee353a43be92599511fc438ec281 Mon Sep 17 00:00:00 2001 From: Karthigan Srinivasan Date: Mon, 18 Apr 2011 16:16:52 -0500 Subject: drivers/base/core.c: Fixed brace coding style issue. Fixed brace coding style issue. Signed-off-by: Karthigan Srinivasan Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/base/core.c b/drivers/base/core.c index fb8130c..bc8729d 100644 --- a/drivers/base/core.c +++ b/drivers/base/core.c @@ -1314,8 +1314,7 @@ EXPORT_SYMBOL_GPL(put_device); EXPORT_SYMBOL_GPL(device_create_file); EXPORT_SYMBOL_GPL(device_remove_file); -struct root_device -{ +struct root_device { struct device dev; struct module *owner; }; -- cgit v0.10.2 From 27a33f9e8fb203e71925257cf039fe6ec623c5d1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Wed, 20 Apr 2011 09:44:42 +0200 Subject: driver core/platform_device_add_data: set platform_data to NULL if !data MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This makes the data = NULL case more consistent to the data != NULL case. The functional change is that now platform_device_add_data(somepdev, NULL, somesize) sets pdev->dev.platform_data to NULL instead of not touching it. Reviewed-by: Viresh Kumar Signed-off-by: Uwe Kleine-König Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/base/platform.c b/drivers/base/platform.c index 9e0e4fc..65cb4c3 100644 --- a/drivers/base/platform.c +++ b/drivers/base/platform.c @@ -220,17 +220,16 @@ EXPORT_SYMBOL_GPL(platform_device_add_resources); int platform_device_add_data(struct platform_device *pdev, const void *data, size_t size) { - void *d; + void *d = NULL; - if (!data) - return 0; - - d = kmemdup(data, size, GFP_KERNEL); - if (d) { - pdev->dev.platform_data = d; - return 0; + if (data) { + d = kmemdup(data, size, GFP_KERNEL); + if (!d) + return -ENOMEM; } - return -ENOMEM; + + pdev->dev.platform_data = d; + return 0; } EXPORT_SYMBOL_GPL(platform_device_add_data); -- cgit v0.10.2 From 251e031d132ea3d03e0a32f2240c67f449979c5d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Wed, 20 Apr 2011 09:44:43 +0200 Subject: driver core/platform_device_add_data: free platform data before overwriting MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reviewed-by: Viresh Kumar Signed-off-by: Uwe Kleine-König Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/base/platform.c b/drivers/base/platform.c index 65cb4c3..58ad8e8 100644 --- a/drivers/base/platform.c +++ b/drivers/base/platform.c @@ -228,6 +228,7 @@ int platform_device_add_data(struct platform_device *pdev, const void *data, return -ENOMEM; } + kfree(pdev->dev.platform_data); pdev->dev.platform_data = d; return 0; } -- cgit v0.10.2 From cea896238fbfdbce254f51fc8fd78c59df50081f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Wed, 20 Apr 2011 09:44:44 +0200 Subject: driver core/platform_device_add_resources: set resource to NULL if !res MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This makes the res = NULL case more consistant to the res != NULL case as now both overwrite pdev->resource. Reviewed-by: Viresh Kumar Signed-off-by: Uwe Kleine-König Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/base/platform.c b/drivers/base/platform.c index 58ad8e8..667f282 100644 --- a/drivers/base/platform.c +++ b/drivers/base/platform.c @@ -192,18 +192,17 @@ EXPORT_SYMBOL_GPL(platform_device_alloc); int platform_device_add_resources(struct platform_device *pdev, const struct resource *res, unsigned int num) { - struct resource *r; + struct resource *r = NULL; - if (!res) - return 0; - - r = kmemdup(res, sizeof(struct resource) * num, GFP_KERNEL); - if (r) { - pdev->resource = r; - pdev->num_resources = num; - return 0; + if (res) { + r = kmemdup(res, sizeof(struct resource) * num, GFP_KERNEL); + if (!r) + return -ENOMEM; } - return -ENOMEM; + + pdev->resource = r; + pdev->num_resources = num; + return 0; } EXPORT_SYMBOL_GPL(platform_device_add_resources); -- cgit v0.10.2 From 4a03d6f7c863a039b937649a93341615f531358e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Wed, 20 Apr 2011 09:44:45 +0200 Subject: driver core/platform_device_add_resources: free resource before overwriting MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reviewed-by: Viresh Kumar Signed-off-by: Uwe Kleine-König Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/base/platform.c b/drivers/base/platform.c index 667f282..7d4bdaf 100644 --- a/drivers/base/platform.c +++ b/drivers/base/platform.c @@ -200,6 +200,7 @@ int platform_device_add_resources(struct platform_device *pdev, return -ENOMEM; } + kfree(pdev->resource); pdev->resource = r; pdev->num_resources = num; return 0; -- cgit v0.10.2 From c8705082404823a5bb3e02a32ba0764399b9e6f2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Wed, 20 Apr 2011 09:44:46 +0200 Subject: driver core: let dev_set_drvdata return int instead of void as it can fail MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Before commit b402843 (Driver core: move dev_get/set_drvdata to drivers/base/dd.c) calling dev_set_drvdata with dev=NULL was an unchecked error. After some discussion about what to return in this case removing the check (and so producing a null pointer exception) seems fine. Signed-off-by: Uwe Kleine-König Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/base/dd.c b/drivers/base/dd.c index 7e9219b..e3a3eff 100644 --- a/drivers/base/dd.c +++ b/drivers/base/dd.c @@ -413,17 +413,16 @@ void *dev_get_drvdata(const struct device *dev) } EXPORT_SYMBOL(dev_get_drvdata); -void dev_set_drvdata(struct device *dev, void *data) +int dev_set_drvdata(struct device *dev, void *data) { int error; - if (!dev) - return; if (!dev->p) { error = device_private_init(dev); if (error) - return; + return error; } dev->p->driver_data = data; + return 0; } EXPORT_SYMBOL(dev_set_drvdata); diff --git a/include/linux/device.h b/include/linux/device.h index 350ceda..2215d01 100644 --- a/include/linux/device.h +++ b/include/linux/device.h @@ -557,7 +557,7 @@ extern int device_move(struct device *dev, struct device *new_parent, extern const char *device_get_devnode(struct device *dev, mode_t *mode, const char **tmp); extern void *dev_get_drvdata(const struct device *dev); -extern void dev_set_drvdata(struct device *dev, void *data); +extern int dev_set_drvdata(struct device *dev, void *data); /* * Root device objects for grouping under /sys/devices -- cgit v0.10.2 From 568aa7508c99952ef18e4bfed87545e66f9e042f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Tue, 19 Apr 2011 10:21:20 +0200 Subject: ARM: at91: AT91CAP9 has a macb device MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit ee621dd (net: atmel_macb Kconfig: remove long dependency line) replaced a list of several explicit machines in the dependencies of MACB by a single symbol that is selected by the respective machines. ee621dd missed to let ARCH_AT91CAP9 select HAVE_NET_MACB though which is fixed here. Signed-off-by: Uwe Kleine-König Acked-by: Andrew Victor Signed-off-by: Jean-Christophe PLAGNIOL-VILLARD diff --git a/arch/arm/mach-at91/Kconfig b/arch/arm/mach-at91/Kconfig index 1939023..2d299bf 100644 --- a/arch/arm/mach-at91/Kconfig +++ b/arch/arm/mach-at91/Kconfig @@ -83,6 +83,7 @@ config ARCH_AT91CAP9 select CPU_ARM926T select GENERIC_CLOCKEVENTS select HAVE_FB_ATMEL + select HAVE_NET_MACB config ARCH_AT572D940HF bool "AT572D940HF" -- cgit v0.10.2 From 0312e826a48168761dbbe10a1e8cbc22ebc99767 Mon Sep 17 00:00:00 2001 From: Greg Ungerer Date: Wed, 30 Mar 2011 22:31:15 +1000 Subject: arm: at91: minimal defconfig for at91x40 SoC A minimal defconfig for build testing the AT91x40 SoC. Signed-off-by: Greg Ungerer Signed-off-by: Jean-Christophe PLAGNIOL-VILLARD diff --git a/arch/arm/configs/at91x40_defconfig b/arch/arm/configs/at91x40_defconfig new file mode 100644 index 0000000..c55e921 --- /dev/null +++ b/arch/arm/configs/at91x40_defconfig @@ -0,0 +1,48 @@ +CONFIG_EXPERIMENTAL=y +CONFIG_LOG_BUF_SHIFT=14 +CONFIG_EMBEDDED=y +# CONFIG_HOTPLUG is not set +# CONFIG_ELF_CORE is not set +# CONFIG_FUTEX is not set +# CONFIG_TIMERFD is not set +# CONFIG_VM_EVENT_COUNTERS is not set +# CONFIG_COMPAT_BRK is not set +CONFIG_SLAB=y +# CONFIG_LBDAF is not set +# CONFIG_BLK_DEV_BSG is not set +# CONFIG_IOSCHED_DEADLINE is not set +# CONFIG_IOSCHED_CFQ is not set +# CONFIG_MMU is not set +CONFIG_ARCH_AT91=y +CONFIG_ARCH_AT91X40=y +CONFIG_MACH_AT91EB01=y +CONFIG_AT91_EARLY_USART0=y +CONFIG_CPU_ARM7TDMI=y +CONFIG_SET_MEM_PARAM=y +CONFIG_DRAM_BASE=0x01000000 +CONFIG_DRAM_SIZE=0x00400000 +CONFIG_FLASH_MEM_BASE=0x01400000 +CONFIG_PROCESSOR_ID=0x14000040 +CONFIG_ZBOOT_ROM_TEXT=0x0 +CONFIG_ZBOOT_ROM_BSS=0x0 +CONFIG_BINFMT_FLAT=y +# CONFIG_SUSPEND is not set +# CONFIG_FW_LOADER is not set +CONFIG_MTD=y +CONFIG_MTD_PARTITIONS=y +CONFIG_MTD_CHAR=y +CONFIG_MTD_BLOCK=y +CONFIG_MTD_RAM=y +CONFIG_MTD_ROM=y +CONFIG_BLK_DEV_RAM=y +# CONFIG_INPUT is not set +# CONFIG_SERIO is not set +# CONFIG_VT is not set +# CONFIG_DEVKMEM is not set +# CONFIG_HW_RANDOM is not set +# CONFIG_HWMON is not set +# CONFIG_USB_SUPPORT is not set +CONFIG_EXT2_FS=y +# CONFIG_DNOTIFY is not set +CONFIG_ROMFS_FS=y +# CONFIG_ENABLE_MUST_CHECK is not set -- cgit v0.10.2 From 91a2f4d3cd2a2f1a2c6830896bd2403ca0130137 Mon Sep 17 00:00:00 2001 From: Greg Ungerer Date: Wed, 30 Mar 2011 14:43:32 +1000 Subject: arm: at91: fix compiler warning for eb01 board build Fix compiler warning when building for AT91EB01 board: arch/arm/mach-at91/board-eb01.c:41: warning: initialisation from incompatible pointer type Signed-off-by: Greg Ungerer Signed-off-by: Jean-Christophe PLAGNIOL-VILLARD diff --git a/arch/arm/mach-at91/board-eb01.c b/arch/arm/mach-at91/board-eb01.c index 1f9d3cb..d8df59a 100644 --- a/arch/arm/mach-at91/board-eb01.c +++ b/arch/arm/mach-at91/board-eb01.c @@ -30,6 +30,11 @@ #include #include "generic.h" +static void __init at91eb01_init_irq(void) +{ + at91x40_init_interrupts(NULL); +} + static void __init at91eb01_map_io(void) { at91x40_initialize(40000000); @@ -38,7 +43,7 @@ static void __init at91eb01_map_io(void) MACHINE_START(AT91EB01, "Atmel AT91 EB01") /* Maintainer: Greg Ungerer */ .timer = &at91x40_timer, - .init_irq = at91x40_init_interrupts, + .init_irq = at91eb01_init_irq, .map_io = at91eb01_map_io, MACHINE_END -- cgit v0.10.2 From 9baeb7e47aed8e399d15d2ea8c032efe3680f20b Mon Sep 17 00:00:00 2001 From: Jean-Christophe PLAGNIOL-VILLARD Date: Sat, 23 Apr 2011 10:52:16 +0800 Subject: at91: Add ARCH_ID and basic cpu macros definition for 5series chips family. Signed-off-by: Jean-Christophe PLAGNIOL-VILLARD Signed-off-by: Nicolas Ferre diff --git a/arch/arm/mach-at91/include/mach/cpu.h b/arch/arm/mach-at91/include/mach/cpu.h index 3bef931..0700f21 100644 --- a/arch/arm/mach-at91/include/mach/cpu.h +++ b/arch/arm/mach-at91/include/mach/cpu.h @@ -27,6 +27,7 @@ #define ARCH_ID_AT91SAM9G45 0x819b05a0 #define ARCH_ID_AT91SAM9G45MRL 0x819b05a2 /* aka 9G45-ES2 & non ES lots */ #define ARCH_ID_AT91SAM9G45ES 0x819b05a1 /* 9G45-ES (Engineering Sample) */ +#define ARCH_ID_AT91SAM9X5 0x819a05a0 #define ARCH_ID_AT91CAP9 0x039A03A0 #define ARCH_ID_AT91SAM9XE128 0x329973a0 @@ -55,6 +56,12 @@ static inline unsigned long at91_cpu_fully_identify(void) #define ARCH_EXID_AT91SAM9G46 0x00000003 #define ARCH_EXID_AT91SAM9G45 0x00000004 +#define ARCH_EXID_AT91SAM9G15 0x00000000 +#define ARCH_EXID_AT91SAM9G35 0x00000001 +#define ARCH_EXID_AT91SAM9X35 0x00000002 +#define ARCH_EXID_AT91SAM9G25 0x00000003 +#define ARCH_EXID_AT91SAM9X25 0x00000004 + static inline unsigned long at91_exid_identify(void) { return at91_sys_read(AT91_DBGU_EXID); @@ -143,6 +150,27 @@ static inline unsigned long at91cap9_rev_identify(void) #define cpu_is_at91sam9m11() (0) #endif +#ifdef CONFIG_ARCH_AT91SAM9X5 +#define cpu_is_at91sam9x5() (at91_cpu_identify() == ARCH_ID_AT91SAM9X5) +#define cpu_is_at91sam9g15() (cpu_is_at91sam9x5() && \ + (at91_exid_identify() == ARCH_EXID_AT91SAM9G15)) +#define cpu_is_at91sam9g35() (cpu_is_at91sam9x5() && \ + (at91_exid_identify() == ARCH_EXID_AT91SAM9G35)) +#define cpu_is_at91sam9x35() (cpu_is_at91sam9x5() && \ + (at91_exid_identify() == ARCH_EXID_AT91SAM9X35)) +#define cpu_is_at91sam9g25() (cpu_is_at91sam9x5() && \ + (at91_exid_identify() == ARCH_EXID_AT91SAM9G25)) +#define cpu_is_at91sam9x25() (cpu_is_at91sam9x5() && \ + (at91_exid_identify() == ARCH_EXID_AT91SAM9X25)) +#else +#define cpu_is_at91sam9x5() (0) +#define cpu_is_at91sam9g15() (0) +#define cpu_is_at91sam9g35() (0) +#define cpu_is_at91sam9x35() (0) +#define cpu_is_at91sam9g25() (0) +#define cpu_is_at91sam9x25() (0) +#endif + #ifdef CONFIG_ARCH_AT91CAP9 #define cpu_is_at91cap9() (at91_cpu_identify() == ARCH_ID_AT91CAP9) #define cpu_is_at91cap9_revB() (at91cap9_rev_identify() == ARCH_REVISION_CAP9_B) -- cgit v0.10.2 From 0911f124bf55357803d53197cc1ae5479f5e37e2 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Sun, 10 Apr 2011 11:01:51 +0200 Subject: genirq: Forgotten updates/deletions after removal of compat code commit 0c6f8a8b917ad361319c8ace3e9f28e69bfdb4c1 ("genirq: Remove compat code") removed the compat code, but forgot to update some references in comments and delete some of its documentation. Signed-off-by: Geert Uytterhoeven Link: http://lkml.kernel.org/r/%3C1302426113-13808-1-git-send-email-geert%40linux-m68k.org%3E Signed-off-by: Thomas Gleixner diff --git a/include/linux/irq.h b/include/linux/irq.h index 09a3080..a71dd18 100644 --- a/include/linux/irq.h +++ b/include/linux/irq.h @@ -53,7 +53,7 @@ typedef void (*irq_preflow_handler_t)(struct irq_data *data); * Bits which can be modified via irq_set/clear/modify_status_flags() * IRQ_LEVEL - Interrupt is level type. Will be also * updated in the code when the above trigger - * bits are modified via set_irq_type() + * bits are modified via irq_set_irq_type() * IRQ_PER_CPU - Mark an interrupt PER_CPU. Will protect * it from affinity setting * IRQ_NOPROBE - Interrupt cannot be probed by autoprobing @@ -261,23 +261,6 @@ static inline void irqd_clr_chained_irq_inprogress(struct irq_data *d) * struct irq_chip - hardware interrupt chip descriptor * * @name: name for /proc/interrupts - * @startup: deprecated, replaced by irq_startup - * @shutdown: deprecated, replaced by irq_shutdown - * @enable: deprecated, replaced by irq_enable - * @disable: deprecated, replaced by irq_disable - * @ack: deprecated, replaced by irq_ack - * @mask: deprecated, replaced by irq_mask - * @mask_ack: deprecated, replaced by irq_mask_ack - * @unmask: deprecated, replaced by irq_unmask - * @eoi: deprecated, replaced by irq_eoi - * @end: deprecated, will go away with __do_IRQ() - * @set_affinity: deprecated, replaced by irq_set_affinity - * @retrigger: deprecated, replaced by irq_retrigger - * @set_type: deprecated, replaced by irq_set_type - * @set_wake: deprecated, replaced by irq_wake - * @bus_lock: deprecated, replaced by irq_bus_lock - * @bus_sync_unlock: deprecated, replaced by irq_bus_sync_unlock - * * @irq_startup: start up the interrupt (defaults to ->enable if NULL) * @irq_shutdown: shut down the interrupt (defaults to ->disable if NULL) * @irq_enable: enable the interrupt (defaults to chip->unmask if NULL) diff --git a/include/linux/irqdesc.h b/include/linux/irqdesc.h index a082905..8e1dc8e 100644 --- a/include/linux/irqdesc.h +++ b/include/linux/irqdesc.h @@ -21,7 +21,7 @@ struct timer_rand_state; * @status: status information * @core_internal_state__do_not_mess_with_it: core internal status information * @depth: disable-depth, for nested irq_disable() calls - * @wake_depth: enable depth, for multiple set_irq_wake() callers + * @wake_depth: enable depth, for multiple irq_set_irq_wake() callers * @irq_count: stats field to detect stalled irqs * @last_unhandled: aging timer for unhandled count * @irqs_unhandled: stats field for spurious unhandled interrupts -- cgit v0.10.2 From ee430599bf63c13ee521a352f562a4281cba5e61 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Sun, 10 Apr 2011 11:01:53 +0200 Subject: genirq: Update DocBook comments Fix some parts to match the actual code. [ tglx: Resolved the FIXMEs Gerd put in ] Signed-off-by: Geert Uytterhoeven Link: http://lkml.kernel.org/r/%3C1302426113-13808-3-git-send-email-geert%40linux-m68k.org%3E Signed-off-by: Thomas Gleixner Cc: linux-doc@vger.kernel.org diff --git a/Documentation/DocBook/genericirq.tmpl b/Documentation/DocBook/genericirq.tmpl index fb10fd0..b342234 100644 --- a/Documentation/DocBook/genericirq.tmpl +++ b/Documentation/DocBook/genericirq.tmpl @@ -191,8 +191,8 @@ Whenever an interrupt triggers, the lowlevel arch code calls into the generic interrupt code by calling desc->handle_irq(). - This highlevel IRQ handling function only uses desc->chip primitives - referenced by the assigned chip descriptor structure. + This highlevel IRQ handling function only uses desc->irq_data.chip + primitives referenced by the assigned chip descriptor structure. @@ -206,11 +206,11 @@ enable_irq() disable_irq_nosync() (SMP only) synchronize_irq() (SMP only) - set_irq_type() - set_irq_wake() - set_irq_data() - set_irq_chip() - set_irq_chip_data() + irq_set_irq_type() + irq_set_irq_wake() + irq_set_handler_data() + irq_set_chip() + irq_set_chip_data() See the autogenerated function documentation for details. @@ -225,6 +225,8 @@ handle_fasteoi_irq handle_simple_irq handle_percpu_irq + handle_edge_eoi_irq + handle_bad_irq The interrupt flow handlers (either predefined or architecture specific) are assigned to specific interrupts by the architecture @@ -241,13 +243,13 @@ default_enable(struct irq_data *data) { - desc->chip->irq_unmask(data); + desc->irq_data.chip->irq_unmask(data); } default_disable(struct irq_data *data) { if (!delay_disable(data)) - desc->chip->irq_mask(data); + desc->irq_data.chip->irq_mask(data); } default_ack(struct irq_data *data) @@ -284,9 +286,9 @@ noop(struct irq_data *data)) The following control flow is implemented (simplified excerpt): -desc->chip->irq_mask(); -handle_IRQ_event(desc->action); -desc->chip->irq_unmask(); +desc->irq_data.chip->irq_mask_ack(); +handle_irq_event(desc->action); +desc->irq_data.chip->irq_unmask(); @@ -300,8 +302,8 @@ desc->chip->irq_unmask(); The following control flow is implemented (simplified excerpt): -handle_IRQ_event(desc->action); -desc->chip->irq_eoi(); +handle_irq_event(desc->action); +desc->irq_data.chip->irq_eoi(); @@ -315,17 +317,17 @@ desc->chip->irq_eoi(); The following control flow is implemented (simplified excerpt): if (desc->status & running) { - desc->chip->irq_mask(); + desc->irq_data.chip->irq_mask_ack(); desc->status |= pending | masked; return; } -desc->chip->irq_ack(); +desc->irq_data.chip->irq_ack(); desc->status |= running; do { if (desc->status & masked) - desc->chip->irq_unmask(); + desc->irq_data.chip->irq_unmask(); desc->status &= ~pending; - handle_IRQ_event(desc->action); + handle_irq_event(desc->action); } while (status & pending); desc->status &= ~running; @@ -344,7 +346,7 @@ desc->status &= ~running; The following control flow is implemented (simplified excerpt): -handle_IRQ_event(desc->action); +handle_irq_event(desc->action); @@ -362,12 +364,29 @@ handle_IRQ_event(desc->action); The following control flow is implemented (simplified excerpt): -handle_IRQ_event(desc->action); -if (desc->chip->irq_eoi) - desc->chip->irq_eoi(); +if (desc->irq_data.chip->irq_ack) + desc->irq_data.chip->irq_ack(); +handle_irq_event(desc->action); +if (desc->irq_data.chip->irq_eoi) + desc->irq_data.chip->irq_eoi(); + + EOI Edge IRQ flow handler + + handle_edge_eoi_irq provides an abnomination of the edge + handler which is solely used to tame a badly wreckaged + irq controller on powerpc/cell. + + + + Bad IRQ flow handler + + handle_bad_irq is used for spurious interrupts which + have no real handler assigned.. + + Quirks and optimizations @@ -410,6 +429,7 @@ if (desc->chip->irq_eoi) irq_mask_ack() - Optional, recommended for performance irq_mask() irq_unmask() + irq_eoi() - Optional, required for eoi flow handlers irq_retrigger() - Optional irq_set_type() - Optional irq_set_wake() - Optional @@ -424,32 +444,24 @@ if (desc->chip->irq_eoi) __do_IRQ entry point - The original implementation __do_IRQ() is an alternative entry - point for all types of interrupts. + The original implementation __do_IRQ() was an alternative entry + point for all types of interrupts. It not longer exists. This handler turned out to be not suitable for all interrupt hardware and was therefore reimplemented with split - functionality for egde/level/simple/percpu interrupts. This is not + functionality for edge/level/simple/percpu interrupts. This is not only a functional optimization. It also shortens code paths for interrupts. - - To make use of the split implementation, replace the call to - __do_IRQ by a call to desc->handle_irq() and associate - the appropriate handler function to desc->handle_irq(). - In most cases the generic handler implementations should - be sufficient. - Locking on SMP The locking of chip registers is up to the architecture that - defines the chip primitives. There is a chip->lock field that can be used - for serialization, but the generic layer does not touch it. The per-irq - structure is protected via desc->lock, by the generic layer. + defines the chip primitives. The per-irq structure is + protected via desc->lock, by the generic layer. -- cgit v0.10.2 From 770767787c23040dc152e7ae230597ff55b39470 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Sun, 10 Apr 2011 11:01:52 +0200 Subject: genirq: irq_desc: Document preflow_handler and affinity_hint [ tglx: Filled in the FIXME place holders ] Signed-off-by: Geert Uytterhoeven Link: http://lkml.kernel.org/r/%3C1302426113-13808-2-git-send-email-geert%40linux-m68k.org%3E Signed-off-by: Thomas Gleixner diff --git a/include/linux/irqdesc.h b/include/linux/irqdesc.h index 8e1dc8e..c70b1aa 100644 --- a/include/linux/irqdesc.h +++ b/include/linux/irqdesc.h @@ -16,7 +16,8 @@ struct timer_rand_state; * @irq_data: per irq and chip data passed down to chip functions * @timer_rand_state: pointer to timer rand state struct * @kstat_irqs: irq stats per cpu - * @handle_irq: highlevel irq-events handler [if NULL, __do_IRQ()] + * @handle_irq: highlevel irq-events handler + * @preflow_handler: handler called before the flow handler (currently used by sparc) * @action: the irq action chain * @status: status information * @core_internal_state__do_not_mess_with_it: core internal status information @@ -26,6 +27,7 @@ struct timer_rand_state; * @last_unhandled: aging timer for unhandled count * @irqs_unhandled: stats field for spurious unhandled interrupts * @lock: locking for SMP + * @affinity_hint: hint to user space for preferred irq affinity * @affinity_notify: context for notification of affinity changes * @pending_mask: pending rebalanced interrupts * @threads_oneshot: bitfield to handle shared oneshot threads -- cgit v0.10.2 From 7f1b1244e159a8490d7fb13667c6cb7e1e75046b Mon Sep 17 00:00:00 2001 From: Paul Mundt Date: Thu, 7 Apr 2011 06:01:44 +0900 Subject: genirq: Support per-IRQ thread disabling. This adds support for disabling threading on a per-IRQ basis via the IRQ status instead of the IRQ flow, which is necessary for interrupts that don't follow the natural IRQ flow channels, such as those that are virtually created. The new APIs added are simply: irq_set_thread() irq_set_nothread() which follow the rest of the IRQ status routines. Chained handlers also have IRQ_NOTHREAD set on them automatically, making the lack of threading explicit rather than implicit. Subsequently, the nothread flag can be viewed through the standard genirq debugging facilities. [ tglx: Fixed cleanup fallout ] Signed-off-by: Paul Mundt Link: http://lkml.kernel.org/r/%3C20110406210135.GF18426%40linux-sh.org%3E Signed-off-by: Thomas Gleixner diff --git a/include/linux/irq.h b/include/linux/irq.h index a71dd18..39c2378 100644 --- a/include/linux/irq.h +++ b/include/linux/irq.h @@ -59,6 +59,7 @@ typedef void (*irq_preflow_handler_t)(struct irq_data *data); * IRQ_NOPROBE - Interrupt cannot be probed by autoprobing * IRQ_NOREQUEST - Interrupt cannot be requested via * request_irq() + * IRQ_NOTHREAD - Interrupt cannot be threaded * IRQ_NOAUTOEN - Interrupt is not automatically enabled in * request/setup_irq() * IRQ_NO_BALANCING - Interrupt cannot be balanced (affinity set) @@ -85,6 +86,7 @@ enum { IRQ_NO_BALANCING = (1 << 13), IRQ_MOVE_PCNTXT = (1 << 14), IRQ_NESTED_THREAD = (1 << 15), + IRQ_NOTHREAD = (1 << 16), }; #define IRQF_MODIFY_MASK \ @@ -422,7 +424,7 @@ irq_set_handler(unsigned int irq, irq_flow_handler_t handle) /* * Set a highlevel chained flow handler for a given IRQ. * (a chained handler is automatically enabled and set to - * IRQ_NOREQUEST and IRQ_NOPROBE) + * IRQ_NOREQUEST, IRQ_NOPROBE, and IRQ_NOTHREAD) */ static inline void irq_set_chained_handler(unsigned int irq, irq_flow_handler_t handle) @@ -452,6 +454,16 @@ static inline void irq_set_probe(unsigned int irq) irq_modify_status(irq, IRQ_NOPROBE, 0); } +static inline void irq_set_nothread(unsigned int irq) +{ + irq_modify_status(irq, 0, IRQ_NOTHREAD); +} + +static inline void irq_set_thread(unsigned int irq) +{ + irq_modify_status(irq, IRQ_NOTHREAD, 0); +} + static inline void irq_set_nested_thread(unsigned int irq, bool nest) { if (nest) diff --git a/kernel/irq/chip.c b/kernel/irq/chip.c index 4af1e2b..52d856d 100644 --- a/kernel/irq/chip.c +++ b/kernel/irq/chip.c @@ -573,6 +573,7 @@ __irq_set_handler(unsigned int irq, irq_flow_handler_t handle, int is_chained, if (handle != handle_bad_irq && is_chained) { irq_settings_set_noprobe(desc); irq_settings_set_norequest(desc); + irq_settings_set_nothread(desc); irq_startup(desc); } out: diff --git a/kernel/irq/debug.h b/kernel/irq/debug.h index 306cba3..97a8bfa 100644 --- a/kernel/irq/debug.h +++ b/kernel/irq/debug.h @@ -27,6 +27,7 @@ static inline void print_irq_desc(unsigned int irq, struct irq_desc *desc) P(IRQ_PER_CPU); P(IRQ_NOPROBE); P(IRQ_NOREQUEST); + P(IRQ_NOTHREAD); P(IRQ_NOAUTOEN); PS(IRQS_AUTODETECT); diff --git a/kernel/irq/manage.c b/kernel/irq/manage.c index 07c1611..f7ce002 100644 --- a/kernel/irq/manage.c +++ b/kernel/irq/manage.c @@ -900,7 +900,8 @@ __setup_irq(unsigned int irq, struct irq_desc *desc, struct irqaction *new) */ new->handler = irq_nested_primary_handler; } else { - irq_setup_forced_threading(new); + if (irq_settings_can_thread(desc)) + irq_setup_forced_threading(new); } /* diff --git a/kernel/irq/settings.h b/kernel/irq/settings.h index 0d91730..f166783 100644 --- a/kernel/irq/settings.h +++ b/kernel/irq/settings.h @@ -8,6 +8,7 @@ enum { _IRQ_LEVEL = IRQ_LEVEL, _IRQ_NOPROBE = IRQ_NOPROBE, _IRQ_NOREQUEST = IRQ_NOREQUEST, + _IRQ_NOTHREAD = IRQ_NOTHREAD, _IRQ_NOAUTOEN = IRQ_NOAUTOEN, _IRQ_MOVE_PCNTXT = IRQ_MOVE_PCNTXT, _IRQ_NO_BALANCING = IRQ_NO_BALANCING, @@ -20,6 +21,7 @@ enum { #define IRQ_LEVEL GOT_YOU_MORON #define IRQ_NOPROBE GOT_YOU_MORON #define IRQ_NOREQUEST GOT_YOU_MORON +#define IRQ_NOTHREAD GOT_YOU_MORON #define IRQ_NOAUTOEN GOT_YOU_MORON #define IRQ_NESTED_THREAD GOT_YOU_MORON #undef IRQF_MODIFY_MASK @@ -94,6 +96,21 @@ static inline void irq_settings_set_norequest(struct irq_desc *desc) desc->status_use_accessors |= _IRQ_NOREQUEST; } +static inline bool irq_settings_can_thread(struct irq_desc *desc) +{ + return !(desc->status_use_accessors & _IRQ_NOTHREAD); +} + +static inline void irq_settings_clr_nothread(struct irq_desc *desc) +{ + desc->status_use_accessors &= ~_IRQ_NOTHREAD; +} + +static inline void irq_settings_set_nothread(struct irq_desc *desc) +{ + desc->status_use_accessors |= _IRQ_NOTHREAD; +} + static inline bool irq_settings_can_probe(struct irq_desc *desc) { return !(desc->status_use_accessors & _IRQ_NOPROBE); -- cgit v0.10.2 From 7d8280624797bbe2f5170bd3c85c75a8c9c74242 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Sun, 3 Apr 2011 11:42:53 +0200 Subject: genirq: Implement a generic interrupt chip Implement a generic interrupt chip, which is configurable and is able to handle the most common irq chip implementations. Signed-off-by: Thomas Gleixner Cc: linux-arm-kernel@lists.infradead.org Tested-by: H Hartley Sweeten Tested-by: Tony Lindgren Tested-by; Kevin Hilman diff --git a/include/linux/irq.h b/include/linux/irq.h index 39c2378..2ba2f12 100644 --- a/include/linux/irq.h +++ b/include/linux/irq.h @@ -568,6 +568,141 @@ static inline int irq_reserve_irq(unsigned int irq) return irq_reserve_irqs(irq, 1); } +#ifndef irq_reg_writel +# define irq_reg_writel(val, addr) writel(val, addr) +#endif +#ifndef irq_reg_readl +# define irq_reg_readl(addr) readl(addr) +#endif + +/** + * struct irq_chip_regs - register offsets for struct irq_gci + * @enable: Enable register offset to reg_base + * @disable: Disable register offset to reg_base + * @mask: Mask register offset to reg_base + * @ack: Ack register offset to reg_base + * @eoi: Eoi register offset to reg_base + * @type: Type configuration register offset to reg_base + * @polarity: Polarity configuration register offset to reg_base + */ +struct irq_chip_regs { + unsigned long enable; + unsigned long disable; + unsigned long mask; + unsigned long ack; + unsigned long eoi; + unsigned long type; + unsigned long polarity; +}; + +/** + * struct irq_chip_type - Generic interrupt chip instance for a flow type + * @chip: The real interrupt chip which provides the callbacks + * @regs: Register offsets for this chip + * @handler: Flow handler associated with this chip + * @type: Chip can handle these flow types + * + * A irq_generic_chip can have several instances of irq_chip_type when + * it requires different functions and register offsets for different + * flow types. + */ +struct irq_chip_type { + struct irq_chip chip; + struct irq_chip_regs regs; + irq_flow_handler_t handler; + u32 type; +}; + +/** + * struct irq_chip_generic - Generic irq chip data structure + * @lock: Lock to protect register and cache data access + * @reg_base: Register base address (virtual) + * @irq_base: Interrupt base nr for this chip + * @irq_cnt: Number of interrupts handled by this chip + * @mask_cache: Cached mask register + * @type_cache: Cached type register + * @polarity_cache: Cached polarity register + * @wake_enabled: Interrupt can wakeup from suspend + * @wake_active: Interrupt is marked as an wakeup from suspend source + * @num_ct: Number of available irq_chip_type instances (usually 1) + * @private: Private data for non generic chip callbacks + * @chip_types: Array of interrupt irq_chip_types + * + * Note, that irq_chip_generic can have multiple irq_chip_type + * implementations which can be associated to a particular irq line of + * an irq_chip_generic instance. That allows to share and protect + * state in an irq_chip_generic instance when we need to implement + * different flow mechanisms (level/edge) for it. + */ +struct irq_chip_generic { + raw_spinlock_t lock; + void __iomem *reg_base; + unsigned int irq_base; + unsigned int irq_cnt; + u32 mask_cache; + u32 type_cache; + u32 polarity_cache; + u32 wake_enabled; + u32 wake_active; + unsigned int num_ct; + void *private; + struct irq_chip_type chip_types[0]; +}; + +/** + * enum irq_gc_flags - Initialization flags for generic irq chips + * @IRQ_GC_INIT_MASK_CACHE: Initialize the mask_cache by reading mask reg + * @IRQ_GC_INIT_NESTED_LOCK: Set the lock class of the irqs to nested for + * irq chips which need to call irq_set_wake() on + * the parent irq. Usually GPIO implementations + */ +enum irq_gc_flags { + IRQ_GC_INIT_MASK_CACHE = 1 << 0, + IRQ_GC_INIT_NESTED_LOCK = 1 << 1, +}; + +/* Generic chip callback functions */ +void irq_gc_noop(struct irq_data *d); +void irq_gc_mask_disable_reg(struct irq_data *d); +void irq_gc_mask_set_bit(struct irq_data *d); +void irq_gc_mask_clr_bit(struct irq_data *d); +void irq_gc_unmask_enable_reg(struct irq_data *d); +void irq_gc_ack(struct irq_data *d); +void irq_gc_mask_disable_reg_and_ack(struct irq_data *d); +void irq_gc_eoi(struct irq_data *d); +int irq_gc_set_wake(struct irq_data *d, unsigned int on); + +/* Setup functions for irq_chip_generic */ +struct irq_chip_generic * +irq_alloc_generic_chip(const char *name, int nr_ct, unsigned int irq_base, + void __iomem *reg_base, irq_flow_handler_t handler); +void irq_setup_generic_chip(struct irq_chip_generic *gc, u32 msk, + enum irq_gc_flags flags, unsigned int clr, + unsigned int set); +int irq_setup_alt_chip(struct irq_data *d, unsigned int type); + +static inline struct irq_chip_type *irq_data_get_chip_type(struct irq_data *d) +{ + return container_of(d->chip, struct irq_chip_type, chip); +} + +#define IRQ_MSK(n) (u32)((n) < 32 ? ((1 << (n)) - 1) : UINT_MAX) + +#ifdef CONFIG_SMP +static inline void irq_gc_lock(struct irq_chip_generic *gc) +{ + raw_spin_lock(&gc->lock); +} + +static inline void irq_gc_unlock(struct irq_chip_generic *gc) +{ + raw_spin_unlock(&gc->lock); +} +#else +static inline void irq_gc_lock(struct irq_chip_generic *gc) { } +static inline void irq_gc_unlock(struct irq_chip_generic *gc) { } +#endif + #endif /* CONFIG_GENERIC_HARDIRQS */ #endif /* !CONFIG_S390 */ diff --git a/kernel/irq/Makefile b/kernel/irq/Makefile index 54329cd..e7a13bd 100644 --- a/kernel/irq/Makefile +++ b/kernel/irq/Makefile @@ -1,5 +1,6 @@ obj-y := irqdesc.o handle.o manage.o spurious.o resend.o chip.o dummychip.o devres.o +obj-y += generic-chip.o obj-$(CONFIG_GENERIC_IRQ_PROBE) += autoprobe.o obj-$(CONFIG_PROC_FS) += proc.o obj-$(CONFIG_GENERIC_PENDING_IRQ) += migration.o diff --git a/kernel/irq/generic-chip.c b/kernel/irq/generic-chip.c new file mode 100644 index 0000000..eb23e59 --- /dev/null +++ b/kernel/irq/generic-chip.c @@ -0,0 +1,261 @@ +/* + * Library implementing the most common irq chip callback functions + * + * Copyright (C) 2011, Thomas Gleixner + */ +#include +#include +#include +#include +#include + +#include "internals.h" + +static inline struct irq_chip_regs *cur_regs(struct irq_data *d) +{ + return &container_of(d->chip, struct irq_chip_type, chip)->regs; +} + +/** + * irq_gc_noop - NOOP function + * @d: irq_data + */ +void irq_gc_noop(struct irq_data *d) +{ +} + +/** + * irq_gc_mask_disable_reg - Mask chip via disable register + * @d: irq_data + * + * Chip has separate enable/disable registers instead of a single mask + * register. + */ +void irq_gc_mask_disable_reg(struct irq_data *d) +{ + struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d); + u32 mask = 1 << (d->irq - gc->irq_base); + + irq_gc_lock(gc); + irq_reg_writel(mask, gc->reg_base + cur_regs(d)->disable); + gc->mask_cache &= ~mask; + irq_gc_unlock(gc); +} + +/** + * irq_gc_mask_set_mask_bit - Mask chip via setting bit in mask register + * @d: irq_data + * + * Chip has a single mask register. Values of this register are cached + * and protected by gc->lock + */ +void irq_gc_mask_set_bit(struct irq_data *d) +{ + struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d); + u32 mask = 1 << (d->irq - gc->irq_base); + + irq_gc_lock(gc); + gc->mask_cache |= mask; + irq_reg_writel(gc->mask_cache, gc->reg_base + cur_regs(d)->mask); + irq_gc_unlock(gc); +} + +/** + * irq_gc_mask_set_mask_bit - Mask chip via clearing bit in mask register + * @d: irq_data + * + * Chip has a single mask register. Values of this register are cached + * and protected by gc->lock + */ +void irq_gc_mask_clr_bit(struct irq_data *d) +{ + struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d); + u32 mask = 1 << (d->irq - gc->irq_base); + + irq_gc_lock(gc); + gc->mask_cache &= ~mask; + irq_reg_writel(gc->mask_cache, gc->reg_base + cur_regs(d)->mask); + irq_gc_unlock(gc); +} + +/** + * irq_gc_unmask_enable_reg - Unmask chip via enable register + * @d: irq_data + * + * Chip has separate enable/disable registers instead of a single mask + * register. + */ +void irq_gc_unmask_enable_reg(struct irq_data *d) +{ + struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d); + u32 mask = 1 << (d->irq - gc->irq_base); + + irq_gc_lock(gc); + irq_reg_writel(mask, gc->reg_base + cur_regs(d)->enable); + gc->mask_cache |= mask; + irq_gc_unlock(gc); +} + +/** + * irq_gc_ack - Ack pending interrupt + * @d: irq_data + */ +void irq_gc_ack(struct irq_data *d) +{ + struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d); + u32 mask = 1 << (d->irq - gc->irq_base); + + irq_gc_lock(gc); + irq_reg_writel(mask, gc->reg_base + cur_regs(d)->ack); + irq_gc_unlock(gc); +} + +/** + * irq_gc_mask_disable_reg_and_ack- Mask and ack pending interrupt + * @d: irq_data + */ +void irq_gc_mask_disable_reg_and_ack(struct irq_data *d) +{ + struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d); + u32 mask = 1 << (d->irq - gc->irq_base); + + irq_gc_lock(gc); + irq_reg_writel(mask, gc->reg_base + cur_regs(d)->mask); + irq_reg_writel(mask, gc->reg_base + cur_regs(d)->ack); + irq_gc_unlock(gc); +} + +/** + * irq_gc_eoi - EOI interrupt + * @d: irq_data + */ +void irq_gc_eoi(struct irq_data *d) +{ + struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d); + u32 mask = 1 << (d->irq - gc->irq_base); + + irq_gc_lock(gc); + irq_reg_writel(mask, gc->reg_base + cur_regs(d)->eoi); + irq_gc_unlock(gc); +} + +/** + * irq_gc_set_wake - Set/clr wake bit for an interrupt + * @d: irq_data + * + * For chips where the wake from suspend functionality is not + * configured in a separate register and the wakeup active state is + * just stored in a bitmask. + */ +int irq_gc_set_wake(struct irq_data *d, unsigned int on) +{ + struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d); + u32 mask = 1 << (d->irq - gc->irq_base); + + if (!(mask & gc->wake_enabled)) + return -EINVAL; + + irq_gc_lock(gc); + if (on) + gc->wake_active |= mask; + else + gc->wake_active &= ~mask; + irq_gc_unlock(gc); + return 0; +} + +/** + * irq_alloc_generic_chip - Allocate a generic chip and initialize it + * @name: Name of the irq chip + * @num_ct: Number of irq_chip_type instances associated with this + * @irq_base: Interrupt base nr for this chip + * @reg_base: Register base address (virtual) + * @handler: Default flow handler associated with this chip + * + * Returns an initialized irq_chip_generic structure. The chip defaults + * to the primary (index 0) irq_chip_type and @handler + */ +struct irq_chip_generic * +irq_alloc_generic_chip(const char *name, int num_ct, unsigned int irq_base, + void __iomem *reg_base, irq_flow_handler_t handler) +{ + struct irq_chip_generic *gc; + unsigned long sz = sizeof(*gc) + num_ct * sizeof(struct irq_chip_type); + + gc = kzalloc(sz, GFP_KERNEL); + if (gc) { + raw_spin_lock_init(&gc->lock); + gc->num_ct = num_ct; + gc->irq_base = irq_base; + gc->reg_base = reg_base; + gc->chip_types->chip.name = name; + gc->chip_types->handler = handler; + } + return gc; +} + +/* + * Separate lockdep class for interrupt chip which can nest irq_desc + * lock. + */ +static struct lock_class_key irq_nested_lock_class; + +/** + * irq_setup_generic_chip - Setup a range of interrupts with a generic chip + * @gc: Generic irq chip holding all data + * @msk: Bitmask holding the irqs to initialize relative to gc->irq_base + * @flags: Flags for initialization + * @clr: IRQ_* bits to clear + * @set: IRQ_* bits to set + * + * Set up max. 32 interrupts starting from gc->irq_base. Note, this + * initializes all interrupts to the primary irq_chip_type and its + * associated handler. + */ +void irq_setup_generic_chip(struct irq_chip_generic *gc, u32 msk, + enum irq_gc_flags flags, unsigned int clr, + unsigned int set) +{ + struct irq_chip_type *ct = gc->chip_types; + unsigned int i; + + /* Init mask cache ? */ + if (flags & IRQ_GC_INIT_MASK_CACHE) + gc->mask_cache = irq_reg_readl(gc->reg_base + ct->regs.mask); + + for (i = gc->irq_base; msk; msk >>= 1, i++) { + if (!msk & 0x01) + continue; + + if (flags & IRQ_GC_INIT_NESTED_LOCK) + irq_set_lockdep_class(i, &irq_nested_lock_class); + + irq_set_chip_and_handler(i, &ct->chip, ct->handler); + irq_set_chip_data(i, gc); + irq_modify_status(i, clr, set); + } + gc->irq_cnt = i - gc->irq_base; +} + +/** + * irq_setup_alt_chip - Switch to alternative chip + * @d: irq_data for this interrupt + * @type Flow type to be initialized + * + * Only to be called from chip->irq_set_type() callbacks. + */ +int irq_setup_alt_chip(struct irq_data *d, unsigned int type) +{ + struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d); + struct irq_chip_type *ct = gc->chip_types; + unsigned int i; + + for (i = 0; i < gc->num_ct; i++, ct++) { + if (ct->type & type) { + d->chip = &ct->chip; + irq_data_to_desc(d)->handle_irq = ct->handler; + return 0; + } + } + return -EINVAL; +} -- cgit v0.10.2 From cfefd21e693dca791bf9ecfc9dd3794facad533c Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Fri, 15 Apr 2011 22:36:08 +0200 Subject: genirq: Add chip suspend and resume callbacks These callbacks are only called in the syscore suspend/resume code on interrupt chips which have been registered via the generic irq chip mechanism. Calling those callbacks per irq would be rather icky, but with the generic irq chip mechanism we can call this per registered chip. Signed-off-by: Thomas Gleixner Cc: linux-arm-kernel@lists.infradead.org diff --git a/include/linux/irq.h b/include/linux/irq.h index 2ba2f12..8b45384 100644 --- a/include/linux/irq.h +++ b/include/linux/irq.h @@ -280,6 +280,9 @@ static inline void irqd_clr_chained_irq_inprogress(struct irq_data *d) * @irq_bus_sync_unlock:function to sync and unlock slow bus (i2c) chips * @irq_cpu_online: configure an interrupt source for a secondary CPU * @irq_cpu_offline: un-configure an interrupt source for a secondary CPU + * @irq_suspend: function called from core code on suspend once per chip + * @irq_resume: function called from core code on resume once per chip + * @irq_pm_shutdown: function called from core code on shutdown once per chip * @irq_print_chip: optional to print special chip info in show_interrupts * @flags: chip specific flags * @@ -309,6 +312,10 @@ struct irq_chip { void (*irq_cpu_online)(struct irq_data *data); void (*irq_cpu_offline)(struct irq_data *data); + void (*irq_suspend)(struct irq_data *data); + void (*irq_resume)(struct irq_data *data); + void (*irq_pm_shutdown)(struct irq_data *data); + void (*irq_print_chip)(struct irq_data *data, struct seq_file *p); unsigned long flags; @@ -626,6 +633,7 @@ struct irq_chip_type { * @wake_active: Interrupt is marked as an wakeup from suspend source * @num_ct: Number of available irq_chip_type instances (usually 1) * @private: Private data for non generic chip callbacks + * @list: List head for keeping track of instances * @chip_types: Array of interrupt irq_chip_types * * Note, that irq_chip_generic can have multiple irq_chip_type @@ -646,6 +654,7 @@ struct irq_chip_generic { u32 wake_active; unsigned int num_ct; void *private; + struct list_head list; struct irq_chip_type chip_types[0]; }; @@ -680,6 +689,8 @@ void irq_setup_generic_chip(struct irq_chip_generic *gc, u32 msk, enum irq_gc_flags flags, unsigned int clr, unsigned int set); int irq_setup_alt_chip(struct irq_data *d, unsigned int type); +void irq_remove_generic_chip(struct irq_chip_generic *gc, u32 msk, + unsigned int clr, unsigned int set); static inline struct irq_chip_type *irq_data_get_chip_type(struct irq_data *d) { diff --git a/kernel/irq/generic-chip.c b/kernel/irq/generic-chip.c index eb23e59..31a9db7 100644 --- a/kernel/irq/generic-chip.c +++ b/kernel/irq/generic-chip.c @@ -8,9 +8,13 @@ #include #include #include +#include #include "internals.h" +static LIST_HEAD(gc_list); +static DEFINE_RAW_SPINLOCK(gc_lock); + static inline struct irq_chip_regs *cur_regs(struct irq_data *d) { return &container_of(d->chip, struct irq_chip_type, chip)->regs; @@ -219,6 +223,10 @@ void irq_setup_generic_chip(struct irq_chip_generic *gc, u32 msk, struct irq_chip_type *ct = gc->chip_types; unsigned int i; + raw_spin_lock(&gc_lock); + list_add_tail(&gc->list, &gc_list); + raw_spin_unlock(&gc_lock); + /* Init mask cache ? */ if (flags & IRQ_GC_INIT_MASK_CACHE) gc->mask_cache = irq_reg_readl(gc->reg_base + ct->regs.mask); @@ -259,3 +267,88 @@ int irq_setup_alt_chip(struct irq_data *d, unsigned int type) } return -EINVAL; } + +/** + * irq_remove_generic_chip - Remove a chip + * @gc: Generic irq chip holding all data + * @msk: Bitmask holding the irqs to initialize relative to gc->irq_base + * @clr: IRQ_* bits to clear + * @set: IRQ_* bits to set + * + * Remove up to 32 interrupts starting from gc->irq_base. + */ +void irq_remove_generic_chip(struct irq_chip_generic *gc, u32 msk, + unsigned int clr, unsigned int set) +{ + unsigned int i = gc->irq_base; + + raw_spin_lock(&gc_lock); + list_del(&gc->list); + raw_spin_unlock(&gc_lock); + + for (; msk; msk >>= 1, i++) { + if (!msk & 0x01) + continue; + + /* Remove handler first. That will mask the irq line */ + irq_set_handler(i, NULL); + irq_set_chip(i, &no_irq_chip); + irq_set_chip_data(i, NULL); + irq_modify_status(i, clr, set); + } +} + +#ifdef CONFIG_PM +static int irq_gc_suspend(void) +{ + struct irq_chip_generic *gc; + + list_for_each_entry(gc, &gc_list, list) { + struct irq_chip_type *ct = gc->chip_types; + + if (ct->chip.irq_suspend) + ct->chip.irq_suspend(irq_get_irq_data(gc->irq_base)); + } + return 0; +} + +static void irq_gc_resume(void) +{ + struct irq_chip_generic *gc; + + list_for_each_entry(gc, &gc_list, list) { + struct irq_chip_type *ct = gc->chip_types; + + if (ct->chip.irq_resume) + ct->chip.irq_resume(irq_get_irq_data(gc->irq_base)); + } +} +#else +#define irq_gc_suspend NULL +#define irq_gc_resume NULL +#endif + +static void irq_gc_shutdown(void) +{ + struct irq_chip_generic *gc; + + list_for_each_entry(gc, &gc_list, list) { + struct irq_chip_type *ct = gc->chip_types; + + if (ct->chip.irq_pm_shutdown) + ct->chip.irq_pm_shutdown(irq_get_irq_data(gc->irq_base)); + } +} + +static struct syscore_ops irq_gc_syscore_ops = { + .suspend = irq_gc_suspend, + .resume = irq_gc_resume, + .shutdown = irq_gc_shutdown, +}; + +static int __init irq_gc_init_ops(void) +{ + register_syscore_ops(&irq_gc_syscore_ops); + return 0; +} +device_initcall(irq_gc_init_ops); -- cgit v0.10.2 From 32fab7bcc79ee0b97277627f456c94202858d851 Mon Sep 17 00:00:00 2001 From: Florian Tobias Schandinat Date: Sat, 23 Apr 2011 22:06:18 +0000 Subject: viafb: fix OLPC XO 1.5 device connection This patch fixes the devices connected on OLPC. The OLPC panel seems to be connected to DVP1 and LVDS2 for some reasons and if not both are handled correct the display does not work correct or not at all. This patch prevents regressions on the OLPC where it worked by accident but would break in future as the driver did not know the correct devices connected. This might also fix hardware scaling. Hopefully the OLPC is the only device with such a requirement but it will be certainly better to actually know what devices are actually connected and to not work by accident. Signed-off-by: Florian Tobias Schandinat diff --git a/drivers/video/via/hw.c b/drivers/video/via/hw.c index 980e263..b8f0110 100644 --- a/drivers/video/via/hw.c +++ b/drivers/video/via/hw.c @@ -20,6 +20,7 @@ */ #include +#include #include "global.h" static struct pll_config cle266_pll_config[] = { @@ -875,6 +876,10 @@ void viafb_set_iga_path(void) viaparinfo->chip_info-> lvds_chip_info2.output_interface); } + + /* looks like the OLPC has its display wired to DVP1 and LVDS2 */ + if (machine_is_olpc()) + viaparinfo->shared->iga2_devices = VIA_DVP1 | VIA_LVDS2; } static void set_color_register(u8 index, u8 red, u8 green, u8 blue) -- cgit v0.10.2 From e39aece7d41119c3d63f390420e00ab4d2a526a9 Mon Sep 17 00:00:00 2001 From: Vladislav Zolotarov Date: Sat, 23 Apr 2011 07:44:46 +0000 Subject: bnx2x: fix UDP csum offload Fixed packets parameters for FW in UDP checksum offload flow. Do not dereference TCP headers on non TCP frames. Reported-by: Eric Dumazet Signed-off-by: Dmitry Kravkov Signed-off-by: Eilon Greenstein Signed-off-by: David S. Miller diff --git a/drivers/net/bnx2x/bnx2x_cmn.c b/drivers/net/bnx2x/bnx2x_cmn.c index e83ac6d..16581df 100644 --- a/drivers/net/bnx2x/bnx2x_cmn.c +++ b/drivers/net/bnx2x/bnx2x_cmn.c @@ -2019,15 +2019,23 @@ static inline void bnx2x_set_pbd_gso(struct sk_buff *skb, static inline u8 bnx2x_set_pbd_csum_e2(struct bnx2x *bp, struct sk_buff *skb, u32 *parsing_data, u32 xmit_type) { - *parsing_data |= ((tcp_hdrlen(skb)/4) << - ETH_TX_PARSE_BD_E2_TCP_HDR_LENGTH_DW_SHIFT) & - ETH_TX_PARSE_BD_E2_TCP_HDR_LENGTH_DW; + *parsing_data |= + ((((u8 *)skb_transport_header(skb) - skb->data) >> 1) << + ETH_TX_PARSE_BD_E2_TCP_HDR_START_OFFSET_W_SHIFT) & + ETH_TX_PARSE_BD_E2_TCP_HDR_START_OFFSET_W; - *parsing_data |= ((((u8 *)tcp_hdr(skb) - skb->data) / 2) << - ETH_TX_PARSE_BD_E2_TCP_HDR_START_OFFSET_W_SHIFT) & - ETH_TX_PARSE_BD_E2_TCP_HDR_START_OFFSET_W; + if (xmit_type & XMIT_CSUM_TCP) { + *parsing_data |= ((tcp_hdrlen(skb) / 4) << + ETH_TX_PARSE_BD_E2_TCP_HDR_LENGTH_DW_SHIFT) & + ETH_TX_PARSE_BD_E2_TCP_HDR_LENGTH_DW; - return skb_transport_header(skb) + tcp_hdrlen(skb) - skb->data; + return skb_transport_header(skb) + tcp_hdrlen(skb) - skb->data; + } else + /* We support checksum offload for TCP and UDP only. + * No need to pass the UDP header length - it's a constant. + */ + return skb_transport_header(skb) + + sizeof(struct udphdr) - skb->data; } /** @@ -2043,7 +2051,7 @@ static inline u8 bnx2x_set_pbd_csum(struct bnx2x *bp, struct sk_buff *skb, struct eth_tx_parse_bd_e1x *pbd, u32 xmit_type) { - u8 hlen = (skb_network_header(skb) - skb->data) / 2; + u8 hlen = (skb_network_header(skb) - skb->data) >> 1; /* for now NS flag is not used in Linux */ pbd->global_data = @@ -2051,9 +2059,15 @@ static inline u8 bnx2x_set_pbd_csum(struct bnx2x *bp, struct sk_buff *skb, ETH_TX_PARSE_BD_E1X_LLC_SNAP_EN_SHIFT)); pbd->ip_hlen_w = (skb_transport_header(skb) - - skb_network_header(skb)) / 2; + skb_network_header(skb)) >> 1; - hlen += pbd->ip_hlen_w + tcp_hdrlen(skb) / 2; + hlen += pbd->ip_hlen_w; + + /* We support checksum offload for TCP and UDP only */ + if (xmit_type & XMIT_CSUM_TCP) + hlen += tcp_hdrlen(skb) / 2; + else + hlen += sizeof(struct udphdr) / 2; pbd->total_hlen_w = cpu_to_le16(hlen); hlen = hlen*2; -- cgit v0.10.2 From c5a4e6d725654045e548b1a1f33059a44a06910f Mon Sep 17 00:00:00 2001 From: Florian Tobias Schandinat Date: Sat, 23 Apr 2011 22:24:52 +0000 Subject: viafb: reduce OLPC refresh a bit When allowing some PLL calculation we get a frequency that seems to be a bit higher than what the OLPC DCON likes resulting in a still readable but not so good image. We don't really know whether this is a problem with the calculation formula or the OLPC but as other displays seem to be happy with the other modes adjusting the OLPC refresh looks like the better thing. This patch prevents a regression when dynamic PLL calculation is allowed. Signed-off-by: Florian Tobias Schandinat diff --git a/drivers/video/via/hw.c b/drivers/video/via/hw.c index b8f0110..56ad185 100644 --- a/drivers/video/via/hw.c +++ b/drivers/video/via/hw.c @@ -2605,7 +2605,7 @@ int viafb_get_refresh(int hres, int vres, u32 long_refresh) if (abs(best->refresh_rate - long_refresh) > 3) { if (hres == 1200 && vres == 900) - return 50; /* OLPC DCON only supports 50 Hz */ + return 49; /* OLPC DCON only supports 50 Hz */ else return 60; } diff --git a/drivers/video/via/share.h b/drivers/video/via/share.h index 4b7831f..62bed2b 100644 --- a/drivers/video/via/share.h +++ b/drivers/video/via/share.h @@ -290,6 +290,7 @@ #define HW_LAYOUT_LCD_EXTERNAL_LCD2 0x10 /* Definition Refresh Rate */ +#define REFRESH_49 49 #define REFRESH_50 50 #define REFRESH_60 60 #define REFRESH_75 75 diff --git a/drivers/video/via/viamode.c b/drivers/video/via/viamode.c index 260d339..ccb5eec 100644 --- a/drivers/video/via/viamode.c +++ b/drivers/video/via/viamode.c @@ -606,7 +606,7 @@ static struct crt_mode_table CRTM1200x720[] = { /* 1200x900 (DCON) */ static struct crt_mode_table DCON1200x900[] = { /* r_rate, hsp, vsp */ - {REFRESH_50, M1200X900_R60_HSP, M1200X900_R60_VSP, + {REFRESH_49, M1200X900_R60_HSP, M1200X900_R60_VSP, /* The correct htotal is 1240, but this doesn't raster on VX855. */ /* Via suggested changing to a multiple of 16, hence 1264. */ /* HT, HA, HBS, HBE, HSS, HSE, VT, VA, VBS, VBE, VSS, VSE */ -- cgit v0.10.2 From 2946294f9aa734efc5873ea2f34131d0a8c0f89a Mon Sep 17 00:00:00 2001 From: Florian Tobias Schandinat Date: Sat, 23 Apr 2011 23:52:45 +0000 Subject: viafb: add X server compatibility mode This patch adds a config option to be compatible with X servers like OpenChrome. This is required as for example the X server does not handle things like disabled IGAs/PLLs resulting in a potential freeze on X startup. With this option disabled we can provide some nice features like power management and not reinitializing the hardware on every mode switch (taking long time, causing flickering). Signed-off-by: Florian Tobias Schandinat diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig index 6bafb51b..4923b5e 100644 --- a/drivers/video/Kconfig +++ b/drivers/video/Kconfig @@ -1607,6 +1607,17 @@ config FB_VIA_DIRECT_PROCFS correct output device configuration. Its use is strongly discouraged. +config FB_VIA_X_COMPATIBILITY + bool "X server compatibility" + depends on FB_VIA + default n + help + This option reduces the functionality (power saving, ...) of the + framebuffer to avoid negative impact on the OpenChrome X server. + If you use any X server other than fbdev you should enable this + otherwise it should be safe to disable it and allow using all + features. + endif config FB_NEOMAGIC diff --git a/drivers/video/via/hw.c b/drivers/video/via/hw.c index e531147..104f3e1 100644 --- a/drivers/video/via/hw.c +++ b/drivers/video/via/hw.c @@ -2293,6 +2293,12 @@ int viafb_setmode(struct VideoModeTable *vmode_tbl, int video_bpp, clock.set_primary_clock_source(VIA_CLKSRC_X1, true); clock.set_secondary_clock_source(VIA_CLKSRC_X1, true); +#ifdef CONFIG_FB_VIA_X_COMPATIBILITY + clock.set_primary_pll_state(VIA_STATE_ON); + clock.set_primary_clock_state(VIA_STATE_ON); + clock.set_secondary_pll_state(VIA_STATE_ON); + clock.set_secondary_clock_state(VIA_STATE_ON); +#else if (viaparinfo->shared->iga1_devices) { clock.set_primary_pll_state(VIA_STATE_ON); clock.set_primary_clock_state(VIA_STATE_ON); @@ -2308,6 +2314,7 @@ int viafb_setmode(struct VideoModeTable *vmode_tbl, int video_bpp, clock.set_secondary_pll_state(VIA_STATE_OFF); clock.set_secondary_clock_state(VIA_STATE_OFF); } +#endif /*CONFIG_FB_VIA_X_COMPATIBILITY*/ via_set_state(devices, VIA_STATE_ON); device_screen_on(); -- cgit v0.10.2 From b07ad9967f40b164af77205027352ba53729cf5a Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Sat, 23 Apr 2011 22:32:03 -0700 Subject: vfs: get rid of 'struct dcache_hash_bucket' abstraction It's a useless abstraction for 'hlist_bl_head', and it doesn't actually help anything - quite the reverse. All the users end up having to know about the hlist_bl_head details anyway, using 'struct hlist_bl_node *' etc. So it just makes the code look confusing. And the cost of it is extra '&b->head' syntactic noise, but more importantly it spuriously makes the hash table dentry list look different from the per-superblock DCACHE_DISCONNECTED dentry list. As a result, the code ended up using ad-hoc locking for one case and special helper functions for what is really another totally identical case in the very same function. Make it all look and work the same. Signed-off-by: Linus Torvalds diff --git a/fs/dcache.c b/fs/dcache.c index 129a357..7108c15 100644 --- a/fs/dcache.c +++ b/fs/dcache.c @@ -99,12 +99,9 @@ static struct kmem_cache *dentry_cache __read_mostly; static unsigned int d_hash_mask __read_mostly; static unsigned int d_hash_shift __read_mostly; -struct dcache_hash_bucket { - struct hlist_bl_head head; -}; -static struct dcache_hash_bucket *dentry_hashtable __read_mostly; +static struct hlist_bl_head *dentry_hashtable __read_mostly; -static inline struct dcache_hash_bucket *d_hash(struct dentry *parent, +static inline struct hlist_bl_head *d_hash(struct dentry *parent, unsigned long hash) { hash += ((unsigned long) parent ^ GOLDEN_RATIO_PRIME) / L1_CACHE_BYTES; @@ -112,14 +109,14 @@ static inline struct dcache_hash_bucket *d_hash(struct dentry *parent, return dentry_hashtable + (hash & D_HASHMASK); } -static inline void spin_lock_bucket(struct dcache_hash_bucket *b) +static inline void spin_lock_bucket(struct hlist_bl_head *b) { - bit_spin_lock(0, (unsigned long *)&b->head.first); + bit_spin_lock(0, (unsigned long *)&b->first); } -static inline void spin_unlock_bucket(struct dcache_hash_bucket *b) +static inline void spin_unlock_bucket(struct hlist_bl_head *b) { - __bit_spin_unlock(0, (unsigned long *)&b->head.first); + __bit_spin_unlock(0, (unsigned long *)&b->first); } /* Statistics gathering. */ @@ -331,15 +328,15 @@ static struct dentry *d_kill(struct dentry *dentry, struct dentry *parent) void __d_drop(struct dentry *dentry) { if (!(dentry->d_flags & DCACHE_UNHASHED)) { + struct hlist_bl_head *b; if (unlikely(dentry->d_flags & DCACHE_DISCONNECTED)) { - bit_spin_lock(0, - (unsigned long *)&dentry->d_sb->s_anon.first); + b = &dentry->d_sb->s_anon; + spin_lock_bucket(b); dentry->d_flags |= DCACHE_UNHASHED; hlist_bl_del_init(&dentry->d_hash); - __bit_spin_unlock(0, - (unsigned long *)&dentry->d_sb->s_anon.first); + spin_unlock_bucket(b); } else { - struct dcache_hash_bucket *b; + struct hlist_bl_head *b; b = d_hash(dentry->d_parent, dentry->d_name.hash); spin_lock_bucket(b); /* @@ -1789,7 +1786,7 @@ struct dentry *__d_lookup_rcu(struct dentry *parent, struct qstr *name, unsigned int len = name->len; unsigned int hash = name->hash; const unsigned char *str = name->name; - struct dcache_hash_bucket *b = d_hash(parent, hash); + struct hlist_bl_head *b = d_hash(parent, hash); struct hlist_bl_node *node; struct dentry *dentry; @@ -1813,7 +1810,7 @@ struct dentry *__d_lookup_rcu(struct dentry *parent, struct qstr *name, * * See Documentation/filesystems/path-lookup.txt for more details. */ - hlist_bl_for_each_entry_rcu(dentry, node, &b->head, d_hash) { + hlist_bl_for_each_entry_rcu(dentry, node, b, d_hash) { struct inode *i; const char *tname; int tlen; @@ -1908,7 +1905,7 @@ struct dentry *__d_lookup(struct dentry *parent, struct qstr *name) unsigned int len = name->len; unsigned int hash = name->hash; const unsigned char *str = name->name; - struct dcache_hash_bucket *b = d_hash(parent, hash); + struct hlist_bl_head *b = d_hash(parent, hash); struct hlist_bl_node *node; struct dentry *found = NULL; struct dentry *dentry; @@ -1935,7 +1932,7 @@ struct dentry *__d_lookup(struct dentry *parent, struct qstr *name) */ rcu_read_lock(); - hlist_bl_for_each_entry_rcu(dentry, node, &b->head, d_hash) { + hlist_bl_for_each_entry_rcu(dentry, node, b, d_hash) { const char *tname; int tlen; @@ -2086,12 +2083,12 @@ again: } EXPORT_SYMBOL(d_delete); -static void __d_rehash(struct dentry * entry, struct dcache_hash_bucket *b) +static void __d_rehash(struct dentry * entry, struct hlist_bl_head *b) { BUG_ON(!d_unhashed(entry)); spin_lock_bucket(b); entry->d_flags &= ~DCACHE_UNHASHED; - hlist_bl_add_head_rcu(&entry->d_hash, &b->head); + hlist_bl_add_head_rcu(&entry->d_hash, b); spin_unlock_bucket(b); } @@ -3025,7 +3022,7 @@ static void __init dcache_init_early(void) dentry_hashtable = alloc_large_system_hash("Dentry cache", - sizeof(struct dcache_hash_bucket), + sizeof(struct hlist_bl_head), dhash_entries, 13, HASH_EARLY, @@ -3034,7 +3031,7 @@ static void __init dcache_init_early(void) 0); for (loop = 0; loop < (1 << d_hash_shift); loop++) - INIT_HLIST_BL_HEAD(&dentry_hashtable[loop].head); + INIT_HLIST_BL_HEAD(dentry_hashtable + loop); } static void __init dcache_init(void) @@ -3057,7 +3054,7 @@ static void __init dcache_init(void) dentry_hashtable = alloc_large_system_hash("Dentry cache", - sizeof(struct dcache_hash_bucket), + sizeof(struct hlist_bl_head), dhash_entries, 13, 0, @@ -3066,7 +3063,7 @@ static void __init dcache_init(void) 0); for (loop = 0; loop < (1 << d_hash_shift); loop++) - INIT_HLIST_BL_HEAD(&dentry_hashtable[loop].head); + INIT_HLIST_BL_HEAD(dentry_hashtable + loop); } /* SLAB cache for __getname() consumers */ -- cgit v0.10.2 From fa7b69475a6c192853949ba496dd9c37b497b548 Mon Sep 17 00:00:00 2001 From: "Justin P. Mattock" Date: Fri, 22 Apr 2011 10:08:52 -0700 Subject: perf events, x86, P4: Fix typo in comment Signed-off-by: Justin P. Mattock Acked-by: Cyrill Gorcunov Cc: trivial@kernel.org Link: http://lkml.kernel.org/r/1303492132-3004-1-git-send-email-justinmattock@gmail.com Signed-off-by: Ingo Molnar diff --git a/arch/x86/kernel/cpu/perf_event_p4.c b/arch/x86/kernel/cpu/perf_event_p4.c index ae31e96..f4c1da2 100644 --- a/arch/x86/kernel/cpu/perf_event_p4.c +++ b/arch/x86/kernel/cpu/perf_event_p4.c @@ -1187,7 +1187,7 @@ static __init int p4_pmu_init(void) { unsigned int low, high; - /* If we get stripped -- indexig fails */ + /* If we get stripped -- indexing fails */ BUILD_BUG_ON(ARCH_P4_MAX_CCCR > X86_PMC_MAX_GENERIC); rdmsr(MSR_IA32_MISC_ENABLE, low, high); -- cgit v0.10.2 From 625f2a378e5a10f45fdc37932fc9f8a21676de9e Mon Sep 17 00:00:00 2001 From: Jonathan Corbet Date: Fri, 22 Apr 2011 11:19:10 -0600 Subject: sched: Get rid of lock_depth Neil Brown pointed out that lock_depth somehow escaped the BKL removal work. Let's get rid of it now. Note that the perf scripting utilities still have a bunch of code for dealing with common_lock_depth in tracepoints; I have left that in place in case anybody wants to use that code with older kernels. Suggested-by: Neil Brown Signed-off-by: Jonathan Corbet Cc: Arnd Bergmann Cc: Peter Zijlstra Cc: Thomas Gleixner Cc: Linus Torvalds Cc: Andrew Morton Link: http://lkml.kernel.org/r/20110422111910.456c0e84@bike.lwn.net Signed-off-by: Ingo Molnar diff --git a/Documentation/trace/kprobetrace.txt b/Documentation/trace/kprobetrace.txt index 6d27ab8..c83bd6b 100644 --- a/Documentation/trace/kprobetrace.txt +++ b/Documentation/trace/kprobetrace.txt @@ -120,7 +120,6 @@ format: field:unsigned char common_flags; offset:2; size:1; signed:0; field:unsigned char common_preempt_count; offset:3; size:1;signed:0; field:int common_pid; offset:4; size:4; signed:1; - field:int common_lock_depth; offset:8; size:4; signed:1; field:unsigned long __probe_ip; offset:12; size:4; signed:0; field:int __probe_nargs; offset:16; size:4; signed:1; diff --git a/include/linux/init_task.h b/include/linux/init_task.h index caa151f..689496b 100644 --- a/include/linux/init_task.h +++ b/include/linux/init_task.h @@ -134,7 +134,6 @@ extern struct cred init_cred; .stack = &init_thread_info, \ .usage = ATOMIC_INIT(2), \ .flags = PF_KTHREAD, \ - .lock_depth = -1, \ .prio = MAX_PRIO-20, \ .static_prio = MAX_PRIO-20, \ .normal_prio = MAX_PRIO-20, \ diff --git a/include/linux/sched.h b/include/linux/sched.h index 171ba24..013314a 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h @@ -731,10 +731,6 @@ struct sched_info { /* timestamps */ unsigned long long last_arrival,/* when we last ran on a cpu */ last_queued; /* when we were last queued to run */ -#ifdef CONFIG_SCHEDSTATS - /* BKL stats */ - unsigned int bkl_count; -#endif }; #endif /* defined(CONFIG_SCHEDSTATS) || defined(CONFIG_TASK_DELAY_ACCT) */ @@ -1190,8 +1186,6 @@ struct task_struct { unsigned int flags; /* per process flags, defined below */ unsigned int ptrace; - int lock_depth; /* BKL lock depth */ - #ifdef CONFIG_SMP struct task_struct *wake_entry; int on_cpu; diff --git a/kernel/fork.c b/kernel/fork.c index e7548de..aca6287 100644 --- a/kernel/fork.c +++ b/kernel/fork.c @@ -1103,7 +1103,6 @@ static struct task_struct *copy_process(unsigned long clone_flags, posix_cpu_timers_init(p); - p->lock_depth = -1; /* -1 = no lock */ do_posix_clock_monotonic_gettime(&p->start_time); p->real_start_time = p->start_time; monotonic_to_bootbased(&p->real_start_time); diff --git a/kernel/mutex.c b/kernel/mutex.c index fe4706c..2c938e2 100644 --- a/kernel/mutex.c +++ b/kernel/mutex.c @@ -163,13 +163,6 @@ __mutex_lock_common(struct mutex *lock, long state, unsigned int subclass, struct task_struct *owner; /* - * If we own the BKL, then don't spin. The owner of - * the mutex might be waiting on us to release the BKL. - */ - if (unlikely(current->lock_depth >= 0)) - break; - - /* * If there's an owner, wait for it to either * release the lock or go to sleep. */ diff --git a/kernel/sched.c b/kernel/sched.c index 8cb0a57..9cde2dd 100644 --- a/kernel/sched.c +++ b/kernel/sched.c @@ -4121,12 +4121,6 @@ static inline void schedule_debug(struct task_struct *prev) profile_hit(SCHED_PROFILING, __builtin_return_address(0)); schedstat_inc(this_rq(), sched_count); -#ifdef CONFIG_SCHEDSTATS - if (unlikely(prev->lock_depth >= 0)) { - schedstat_inc(this_rq(), rq_sched_info.bkl_count); - schedstat_inc(prev, sched_info.bkl_count); - } -#endif } static void put_prev_task(struct rq *rq, struct task_struct *prev) @@ -5852,11 +5846,8 @@ void __cpuinit init_idle(struct task_struct *idle, int cpu) raw_spin_unlock_irqrestore(&rq->lock, flags); /* Set the preempt count _outside_ the spinlocks! */ -#if defined(CONFIG_PREEMPT) - task_thread_info(idle)->preempt_count = (idle->lock_depth >= 0); -#else task_thread_info(idle)->preempt_count = 0; -#endif + /* * The idle tasks have their own, simple scheduling class: */ diff --git a/kernel/sched_debug.c b/kernel/sched_debug.c index 3669bec6..a6710a1 100644 --- a/kernel/sched_debug.c +++ b/kernel/sched_debug.c @@ -296,9 +296,6 @@ static void print_cpu(struct seq_file *m, int cpu) P(ttwu_count); P(ttwu_local); - SEQ_printf(m, " .%-30s: %d\n", "bkl_count", - rq->rq_sched_info.bkl_count); - #undef P #undef P64 #endif @@ -441,7 +438,6 @@ void proc_sched_show_task(struct task_struct *p, struct seq_file *m) P(se.statistics.wait_count); PN(se.statistics.iowait_sum); P(se.statistics.iowait_count); - P(sched_info.bkl_count); P(se.nr_migrations); P(se.statistics.nr_migrations_cold); P(se.statistics.nr_failed_migrations_affine); diff --git a/kernel/trace/trace_kprobe.c b/kernel/trace/trace_kprobe.c index 35d55a3..f925c45 100644 --- a/kernel/trace/trace_kprobe.c +++ b/kernel/trace/trace_kprobe.c @@ -53,7 +53,6 @@ const char *reserved_field_names[] = { "common_preempt_count", "common_pid", "common_tgid", - "common_lock_depth", FIELD_STRING_IP, FIELD_STRING_RETIP, FIELD_STRING_FUNC, diff --git a/tools/perf/Documentation/perf-script-perl.txt b/tools/perf/Documentation/perf-script-perl.txt index 5bb41e5..3152cca 100644 --- a/tools/perf/Documentation/perf-script-perl.txt +++ b/tools/perf/Documentation/perf-script-perl.txt @@ -63,7 +63,6 @@ The format file for the sched_wakep event defines the following fields field:unsigned char common_flags; field:unsigned char common_preempt_count; field:int common_pid; - field:int common_lock_depth; field:char comm[TASK_COMM_LEN]; field:pid_t pid; diff --git a/tools/perf/Documentation/perf-script-python.txt b/tools/perf/Documentation/perf-script-python.txt index 36b3827..4710220 100644 --- a/tools/perf/Documentation/perf-script-python.txt +++ b/tools/perf/Documentation/perf-script-python.txt @@ -463,7 +463,6 @@ The format file for the sched_wakep event defines the following fields field:unsigned char common_flags; field:unsigned char common_preempt_count; field:int common_pid; - field:int common_lock_depth; field:char comm[TASK_COMM_LEN]; field:pid_t pid; -- cgit v0.10.2 From 15d6aba24d88231415f4e7e091c0f1e60c3e6fd5 Mon Sep 17 00:00:00 2001 From: Avi Kivity Date: Sun, 24 Apr 2011 11:11:51 +0300 Subject: x86: Demacro CONFIG_PARAVIRT cpu accessors Recently, we had a build failure on !CONFIG_PARAVIRT due to a callback ->wbinvd() clashing with a macro wbinvd(). While we worked around the issue, avoid it in the future by changing the macro (and a few surrounding ones) to an inline function. Signed-off-by: Avi Kivity Cc: "H. Peter Anvin" Link: http://lkml.kernel.org/r/1303632711-21662-1-git-send-email-avi@redhat.com Signed-off-by: Ingo Molnar diff --git a/arch/x86/include/asm/system.h b/arch/x86/include/asm/system.h index 12569e6..c2ff2a1 100644 --- a/arch/x86/include/asm/system.h +++ b/arch/x86/include/asm/system.h @@ -303,24 +303,81 @@ static inline void native_wbinvd(void) #ifdef CONFIG_PARAVIRT #include #else -#define read_cr0() (native_read_cr0()) -#define write_cr0(x) (native_write_cr0(x)) -#define read_cr2() (native_read_cr2()) -#define write_cr2(x) (native_write_cr2(x)) -#define read_cr3() (native_read_cr3()) -#define write_cr3(x) (native_write_cr3(x)) -#define read_cr4() (native_read_cr4()) -#define read_cr4_safe() (native_read_cr4_safe()) -#define write_cr4(x) (native_write_cr4(x)) -#define wbinvd() (native_wbinvd()) + +static inline unsigned long read_cr0(void) +{ + return native_read_cr0(); +} + +static inline void write_cr0(unsigned long x) +{ + native_write_cr0(x); +} + +static inline unsigned long read_cr2(void) +{ + return native_read_cr2(); +} + +static inline void write_cr2(unsigned long x) +{ + native_write_cr2(x); +} + +static inline unsigned long read_cr3(void) +{ + return native_read_cr3(); +} + +static inline void write_cr3(unsigned long x) +{ + native_write_cr3(x); +} + +static inline unsigned long read_cr4(void) +{ + return native_read_cr4(); +} + +static inline unsigned long read_cr4_safe(void) +{ + return native_read_cr4_safe(); +} + +static inline void write_cr4(unsigned long x) +{ + native_write_cr4(x); +} + +static inline void wbinvd(void) +{ + native_wbinvd(); +} + #ifdef CONFIG_X86_64 -#define read_cr8() (native_read_cr8()) -#define write_cr8(x) (native_write_cr8(x)) -#define load_gs_index native_load_gs_index + +static inline unsigned long read_cr8(void) +{ + return native_read_cr8(); +} + +static inline void write_cr8(unsigned long x) +{ + native_write_cr8(x); +} + +static inline void load_gs_index(unsigned selector) +{ + native_load_gs_index(selector); +} + #endif /* Clear the 'TS' bit */ -#define clts() (native_clts()) +static inline void clts(void) +{ + native_clts(); +} #endif/* CONFIG_PARAVIRT */ -- cgit v0.10.2 From dea3667bc3c2a0521e8d8855e407a49d9d70028c Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Sun, 24 Apr 2011 07:58:46 -0700 Subject: vfs: get rid of insane dentry hashing rules The dentry hashing rules have been really quite complicated for a long while, in odd ways. That made functions like __d_drop() very fragile and non-obvious. In particular, whether a dentry was hashed or not was indicated with an explicit DCACHE_UNHASHED bit. That's despite the fact that the hash abstraction that the dentries use actually have a 'is this entry hashed or not' model (which is a simple test of the 'pprev' pointer). The reason that was done is because we used the normal 'is this entry unhashed' model to mark whether the dentry had _ever_ been hashed in the dentry hash tables, and that logic goes back many years (commit b3423415fbc2: "dcache: avoid RCU for never-hashed dentries"). That, in turn, meant that __d_drop had totally different unhashing logic for the dentry hash table case and for the anonymous dcache case, because in order to use the "is this dentry hashed" logic as a flag for whether it had ever been on the RCU hash table, we had to unhash such a dentry differently so that we'd never think that it wasn't 'unhashed' and wouldn't be free'd correctly. That's just insane. It made the logic really hard to follow, when there were two different kinds of "unhashed" states, and one of them (the one that used "list_bl_unhashed()") really had nothing at all to do with being unhashed per se, but with a very subtle lifetime rule instead. So turn all of it around, and make it logical. Instead of having a DENTRY_UNHASHED bit in d_flags to indicate whether the dentry is on the hash chains or not, use the hash chain unhashed logic for that. Suddenly "d_unhashed()" just uses "list_bl_unhashed()", and everything makes sense. And for the lifetime rule, just use an explicit DENTRY_RCUACCEES bit. If we ever insert the dentry into the dentry hash table so that it is visible to RCU lookup, we mark it DENTRY_RCUACCESS to show that it now needs the RCU lifetime rules. Now suddently that test at dentry free time makes sense too. And because unhashing now is sane and doesn't depend on where the dentry got unhashed from (because the dentry hash chain details doesn't have some subtle side effects), we can re-unify the __d_drop() logic and use common code for the unhashing. Also fix one more open-coded hash chain bit_spin_lock() that I missed in the previous chain locking cleanup commit. Signed-off-by: Linus Torvalds diff --git a/fs/dcache.c b/fs/dcache.c index 7108c15..d600a0a 100644 --- a/fs/dcache.c +++ b/fs/dcache.c @@ -164,8 +164,8 @@ static void d_free(struct dentry *dentry) if (dentry->d_op && dentry->d_op->d_release) dentry->d_op->d_release(dentry); - /* if dentry was never inserted into hash, immediate free is OK */ - if (hlist_bl_unhashed(&dentry->d_hash)) + /* if dentry was never visible to RCU, immediate free is OK */ + if (!(dentry->d_flags & DCACHE_RCUACCESS)) __d_free(&dentry->d_u.d_rcu); else call_rcu(&dentry->d_u.d_rcu, __d_free); @@ -327,28 +327,19 @@ static struct dentry *d_kill(struct dentry *dentry, struct dentry *parent) */ void __d_drop(struct dentry *dentry) { - if (!(dentry->d_flags & DCACHE_UNHASHED)) { + if (!d_unhashed(dentry)) { struct hlist_bl_head *b; - if (unlikely(dentry->d_flags & DCACHE_DISCONNECTED)) { + if (unlikely(dentry->d_flags & DCACHE_DISCONNECTED)) b = &dentry->d_sb->s_anon; - spin_lock_bucket(b); - dentry->d_flags |= DCACHE_UNHASHED; - hlist_bl_del_init(&dentry->d_hash); - spin_unlock_bucket(b); - } else { - struct hlist_bl_head *b; + else b = d_hash(dentry->d_parent, dentry->d_name.hash); - spin_lock_bucket(b); - /* - * We may not actually need to put DCACHE_UNHASHED - * manipulations under the hash lock, but follow - * the principle of least surprise. - */ - dentry->d_flags |= DCACHE_UNHASHED; - hlist_bl_del_rcu(&dentry->d_hash); - spin_unlock_bucket(b); - dentry_rcuwalk_barrier(dentry); - } + + spin_lock_bucket(b); + __hlist_bl_del(&dentry->d_hash); + dentry->d_hash.pprev = NULL; + spin_unlock_bucket(b); + + dentry_rcuwalk_barrier(dentry); } } EXPORT_SYMBOL(__d_drop); @@ -1301,7 +1292,7 @@ struct dentry *d_alloc(struct dentry * parent, const struct qstr *name) dname[name->len] = 0; dentry->d_count = 1; - dentry->d_flags = DCACHE_UNHASHED; + dentry->d_flags = 0; spin_lock_init(&dentry->d_lock); seqcount_init(&dentry->d_seq); dentry->d_inode = NULL; @@ -1603,10 +1594,9 @@ struct dentry *d_obtain_alias(struct inode *inode) tmp->d_inode = inode; tmp->d_flags |= DCACHE_DISCONNECTED; list_add(&tmp->d_alias, &inode->i_dentry); - bit_spin_lock(0, (unsigned long *)&tmp->d_sb->s_anon.first); - tmp->d_flags &= ~DCACHE_UNHASHED; + spin_lock_bucket(&tmp->d_sb->s_anon); hlist_bl_add_head(&tmp->d_hash, &tmp->d_sb->s_anon); - __bit_spin_unlock(0, (unsigned long *)&tmp->d_sb->s_anon.first); + spin_unlock_bucket(&tmp->d_sb->s_anon); spin_unlock(&tmp->d_lock); spin_unlock(&inode->i_lock); security_d_instantiate(tmp, inode); @@ -2087,7 +2077,7 @@ static void __d_rehash(struct dentry * entry, struct hlist_bl_head *b) { BUG_ON(!d_unhashed(entry)); spin_lock_bucket(b); - entry->d_flags &= ~DCACHE_UNHASHED; + entry->d_flags |= DCACHE_RCUACCESS; hlist_bl_add_head_rcu(&entry->d_hash, b); spin_unlock_bucket(b); } diff --git a/include/linux/dcache.h b/include/linux/dcache.h index f2afed4..19d90a5 100644 --- a/include/linux/dcache.h +++ b/include/linux/dcache.h @@ -197,7 +197,7 @@ struct dentry_operations { * typically using d_splice_alias. */ #define DCACHE_REFERENCED 0x0008 /* Recently used, don't discard. */ -#define DCACHE_UNHASHED 0x0010 +#define DCACHE_RCUACCESS 0x0010 /* Entry has ever been RCU-visible */ #define DCACHE_INOTIFY_PARENT_WATCHED 0x0020 /* Parent inode is watched by inotify */ @@ -384,7 +384,7 @@ extern struct dentry *dget_parent(struct dentry *dentry); static inline int d_unhashed(struct dentry *dentry) { - return (dentry->d_flags & DCACHE_UNHASHED); + return hlist_bl_unhashed(&dentry->d_hash); } static inline int d_unlinked(struct dentry *dentry) -- cgit v0.10.2 From 3ba41621156681afcdbcd624e3191cbc65eb94f4 Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Sat, 23 Apr 2011 18:42:56 +0100 Subject: kconfig: Avoid buffer underrun in choice input Commit 40aee729b350 ('kconfig: fix default value for choice input') fixed some cases where kconfig would select the wrong option from a choice with a single valid option and thus enter an infinite loop. However, this broke the test for user input of the form 'N?', because when kconfig selects the single valid option the input is zero-length and the test will read the byte before the input buffer. If this happens to contain '?' (as it will in a mips build on Debian unstable today) then kconfig again enters an infinite loop. Signed-off-by: Ben Hutchings Cc: stable@kernel.org [2.6.17+] Signed-off-by: Linus Torvalds diff --git a/scripts/kconfig/conf.c b/scripts/kconfig/conf.c index 659326c..006ad81 100644 --- a/scripts/kconfig/conf.c +++ b/scripts/kconfig/conf.c @@ -332,7 +332,7 @@ static int conf_choice(struct menu *menu) } if (!child) continue; - if (line[strlen(line) - 1] == '?') { + if (line[0] && line[strlen(line) - 1] == '?') { print_help(child); continue; } -- cgit v0.10.2 From 6e5fe5b12cfcd9ed4303c9a4f4a22a694104d28f Mon Sep 17 00:00:00 2001 From: Hannes Reinecke Date: Fri, 4 Mar 2011 09:54:52 +0100 Subject: ahci: EM supported message type sysfs attribute This patch adds an sysfs attribute 'em_message_supported' to the ahci host device which prints out the supported enclosure management message types. Signed-off-by: Hannes Reinecke Signed-off-by: Jeff Garzik diff --git a/drivers/ata/ahci.h b/drivers/ata/ahci.h index 3986500..12c5282 100644 --- a/drivers/ata/ahci.h +++ b/drivers/ata/ahci.h @@ -229,6 +229,10 @@ enum { EM_CTL_ALHD = (1 << 26), /* Activity LED */ EM_CTL_XMT = (1 << 25), /* Transmit Only */ EM_CTL_SMB = (1 << 24), /* Single Message Buffer */ + EM_CTL_SGPIO = (1 << 19), /* SGPIO messages supported */ + EM_CTL_SES = (1 << 18), /* SES-2 messages supported */ + EM_CTL_SAFTE = (1 << 17), /* SAF-TE messages supported */ + EM_CTL_LED = (1 << 16), /* LED messages supported */ /* em message type */ EM_MSG_TYPE_LED = (1 << 0), /* LED */ diff --git a/drivers/ata/libahci.c b/drivers/ata/libahci.c index 26d4523..633159b 100644 --- a/drivers/ata/libahci.c +++ b/drivers/ata/libahci.c @@ -109,6 +109,8 @@ static ssize_t ahci_read_em_buffer(struct device *dev, static ssize_t ahci_store_em_buffer(struct device *dev, struct device_attribute *attr, const char *buf, size_t size); +static ssize_t ahci_show_em_supported(struct device *dev, + struct device_attribute *attr, char *buf); static DEVICE_ATTR(ahci_host_caps, S_IRUGO, ahci_show_host_caps, NULL); static DEVICE_ATTR(ahci_host_cap2, S_IRUGO, ahci_show_host_cap2, NULL); @@ -116,6 +118,7 @@ static DEVICE_ATTR(ahci_host_version, S_IRUGO, ahci_show_host_version, NULL); static DEVICE_ATTR(ahci_port_cmd, S_IRUGO, ahci_show_port_cmd, NULL); static DEVICE_ATTR(em_buffer, S_IWUSR | S_IRUGO, ahci_read_em_buffer, ahci_store_em_buffer); +static DEVICE_ATTR(em_message_supported, S_IRUGO, ahci_show_em_supported, NULL); struct device_attribute *ahci_shost_attrs[] = { &dev_attr_link_power_management_policy, @@ -126,6 +129,7 @@ struct device_attribute *ahci_shost_attrs[] = { &dev_attr_ahci_host_version, &dev_attr_ahci_port_cmd, &dev_attr_em_buffer, + &dev_attr_em_message_supported, NULL }; EXPORT_SYMBOL_GPL(ahci_shost_attrs); @@ -343,6 +347,24 @@ static ssize_t ahci_store_em_buffer(struct device *dev, return size; } +static ssize_t ahci_show_em_supported(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct Scsi_Host *shost = class_to_shost(dev); + struct ata_port *ap = ata_shost_to_port(shost); + struct ahci_host_priv *hpriv = ap->host->private_data; + void __iomem *mmio = hpriv->mmio; + u32 em_ctl; + + em_ctl = readl(mmio + HOST_EM_CTL); + + return sprintf(buf, "%s%s%s%s\n", + em_ctl & EM_CTL_LED ? "led " : "", + em_ctl & EM_CTL_SAFTE ? "saf-te " : "", + em_ctl & EM_CTL_SES ? "ses-2 " : "", + em_ctl & EM_CTL_SGPIO ? "sgpio " : ""); +} + /** * ahci_save_initial_config - Save and fixup initial config values * @dev: target AHCI device -- cgit v0.10.2 From 3f7ac1d6671ebca7a955853f7127c937f7befbd3 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Wed, 16 Mar 2011 11:14:25 +0100 Subject: libata: Kill unused ATA_DFLAG_{H|D}IPM flags ATA_DFLAG_{H|D}IPM flags are no longer used. Kill them. Signed-off-by: Tejun Heo Signed-off-by: Jeff Garzik diff --git a/include/linux/libata.h b/include/linux/libata.h index 7f675aa..3b4d223 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -137,8 +137,6 @@ enum { ATA_DFLAG_ACPI_PENDING = (1 << 5), /* ACPI resume action pending */ ATA_DFLAG_ACPI_FAILED = (1 << 6), /* ACPI on devcfg has failed */ ATA_DFLAG_AN = (1 << 7), /* AN configured */ - ATA_DFLAG_HIPM = (1 << 8), /* device supports HIPM */ - ATA_DFLAG_DIPM = (1 << 9), /* device supports DIPM */ ATA_DFLAG_DMADIR = (1 << 10), /* device requires DMADIR */ ATA_DFLAG_CFG_MASK = (1 << 12) - 1, -- cgit v0.10.2 From ae01b2493c3bf03c504c32ac4ebb01d528508db3 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Wed, 16 Mar 2011 11:14:55 +0100 Subject: libata: Implement ATA_FLAG_NO_DIPM and apply it to mcp65 NVIDIA mcp65 familiy of controllers cause command timeouts when DIPM is used. Implement ATA_FLAG_NO_DIPM and apply it. This problem was reported by Stefan Bader in the following thread. http://thread.gmane.org/gmane.linux.ide/48841 stable: applicable to 2.6.37 and 38. Signed-off-by: Tejun Heo Reported-by: Stefan Bader Cc: stable@kernel.org Signed-off-by: Jeff Garzik diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c index 39d829c..cbd38e1 100644 --- a/drivers/ata/ahci.c +++ b/drivers/ata/ahci.c @@ -150,7 +150,7 @@ static const struct ata_port_info ahci_port_info[] = { { AHCI_HFLAGS (AHCI_HFLAG_NO_FPDMA_AA | AHCI_HFLAG_NO_PMP | AHCI_HFLAG_YES_NCQ), - .flags = AHCI_FLAG_COMMON, + .flags = AHCI_FLAG_COMMON | ATA_FLAG_NO_DIPM, .pio_mask = ATA_PIO4, .udma_mask = ATA_UDMA6, .port_ops = &ahci_ops, diff --git a/drivers/ata/libata-eh.c b/drivers/ata/libata-eh.c index 88cd22f..f26f2fe 100644 --- a/drivers/ata/libata-eh.c +++ b/drivers/ata/libata-eh.c @@ -3316,6 +3316,7 @@ static int ata_eh_set_lpm(struct ata_link *link, enum ata_lpm_policy policy, struct ata_eh_context *ehc = &link->eh_context; struct ata_device *dev, *link_dev = NULL, *lpm_dev = NULL; enum ata_lpm_policy old_policy = link->lpm_policy; + bool no_dipm = ap->flags & ATA_FLAG_NO_DIPM; unsigned int hints = ATA_LPM_EMPTY | ATA_LPM_HIPM; unsigned int err_mask; int rc; @@ -3332,7 +3333,7 @@ static int ata_eh_set_lpm(struct ata_link *link, enum ata_lpm_policy policy, */ ata_for_each_dev(dev, link, ENABLED) { bool hipm = ata_id_has_hipm(dev->id); - bool dipm = ata_id_has_dipm(dev->id); + bool dipm = ata_id_has_dipm(dev->id) && !no_dipm; /* find the first enabled and LPM enabled devices */ if (!link_dev) @@ -3389,7 +3390,8 @@ static int ata_eh_set_lpm(struct ata_link *link, enum ata_lpm_policy policy, /* host config updated, enable DIPM if transitioning to MIN_POWER */ ata_for_each_dev(dev, link, ENABLED) { - if (policy == ATA_LPM_MIN_POWER && ata_id_has_dipm(dev->id)) { + if (policy == ATA_LPM_MIN_POWER && !no_dipm && + ata_id_has_dipm(dev->id)) { err_mask = ata_dev_set_feature(dev, SETFEATURES_SATA_ENABLE, SATA_DIPM); if (err_mask && err_mask != AC_ERR_DEV) { diff --git a/include/linux/libata.h b/include/linux/libata.h index 3b4d223..04f32a3 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -196,6 +196,7 @@ enum { * management */ ATA_FLAG_SW_ACTIVITY = (1 << 22), /* driver supports sw activity * led */ + ATA_FLAG_NO_DIPM = (1 << 23), /* host not happy with DIPM */ /* bits 24:31 of ap->flags are reserved for LLD specific flags */ -- cgit v0.10.2 From 7b3a24c57d2eeda8dba9c205342b12689c4679f9 Mon Sep 17 00:00:00 2001 From: Maxime Bizon Date: Wed, 16 Mar 2011 14:58:32 +0100 Subject: ahci: don't enable port irq before handler is registered The ahci_pmp_attach() & ahci_pmp_detach() unmask port irqs, but they are also called during port initialization, before ahci host irq handler is registered. On ce4100 platform, this sometimes triggers "irq 4: nobody cared" message when loading driver. Fixed this by not touching the register if the port is in frozen state, and mark all uninitialized port as frozen. Signed-off-by: Maxime Bizon Acked-by: Tejun Heo Cc: stable@kernel.org Signed-off-by: Jeff Garzik diff --git a/drivers/ata/libahci.c b/drivers/ata/libahci.c index 633159b..d38c40f 100644 --- a/drivers/ata/libahci.c +++ b/drivers/ata/libahci.c @@ -1919,7 +1919,17 @@ static void ahci_pmp_attach(struct ata_port *ap) ahci_enable_fbs(ap); pp->intr_mask |= PORT_IRQ_BAD_PMP; - writel(pp->intr_mask, port_mmio + PORT_IRQ_MASK); + + /* + * We must not change the port interrupt mask register if the + * port is marked frozen, the value in pp->intr_mask will be + * restored later when the port is thawed. + * + * Note that during initialization, the port is marked as + * frozen since the irq handler is not yet registered. + */ + if (!(ap->pflags & ATA_PFLAG_FROZEN)) + writel(pp->intr_mask, port_mmio + PORT_IRQ_MASK); } static void ahci_pmp_detach(struct ata_port *ap) @@ -1935,7 +1945,10 @@ static void ahci_pmp_detach(struct ata_port *ap) writel(cmd, port_mmio + PORT_CMD); pp->intr_mask &= ~PORT_IRQ_BAD_PMP; - writel(pp->intr_mask, port_mmio + PORT_IRQ_MASK); + + /* see comment above in ahci_pmp_attach() */ + if (!(ap->pflags & ATA_PFLAG_FROZEN)) + writel(pp->intr_mask, port_mmio + PORT_IRQ_MASK); } int ahci_port_resume(struct ata_port *ap) diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index 423c0a6..5096b2a 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -5480,7 +5480,7 @@ struct ata_port *ata_port_alloc(struct ata_host *host) if (!ap) return NULL; - ap->pflags |= ATA_PFLAG_INITIALIZING; + ap->pflags |= ATA_PFLAG_INITIALIZING | ATA_PFLAG_FROZEN; ap->lock = &host->lock; ap->print_id = -1; ap->host = host; -- cgit v0.10.2 From d69cf28cd2f85c3086fac5ea39aa1d5ba65546b1 Mon Sep 17 00:00:00 2001 From: Jeff Mahoney Date: Tue, 19 Apr 2011 11:13:32 -0400 Subject: libata: Pioneer DVR-216D can't do SETXFER Commit 4a5610a04d415ed94af75bb1159d2621d62c8328 fixed an issue with the Pioneer DVR-212D not handling SETXFER correctly. An openSUSE user reported a similar issue with his DVR-216D that the NOSETXFER horkage worked around for him as well. This patch adds the DVR-216D (1.08) to the horkage list for NOSETXFER. The issue was reported at: https://bugzilla.novell.com/show_bug.cgi?id=679143 Reported-by: Volodymyr Kyrychenko Signed-off-by: Jeff Mahoney Signed-off-by: Jeff Garzik diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index 5096b2a..76c3c15 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -4139,6 +4139,7 @@ static const struct ata_blacklist_entry ata_device_blacklist [] = { */ { "PIONEER DVD-RW DVRTD08", "1.00", ATA_HORKAGE_NOSETXFER }, { "PIONEER DVD-RW DVR-212D", "1.28", ATA_HORKAGE_NOSETXFER }, + { "PIONEER DVD-RW DVR-216D", "1.08", ATA_HORKAGE_NOSETXFER }, /* End Marker */ { } -- cgit v0.10.2 From 4a836c701a0f68e5a028113c176413e9b72c4c7c Mon Sep 17 00:00:00 2001 From: Seth Heasley Date: Wed, 20 Apr 2011 08:43:37 -0700 Subject: ata_piix: IDE-mode SATA patch for Intel Panther Point DeviceIDs The previously submitted patch was word-wrapped. This patch adds the IDE-mode SATA DeviceIDs for the Intel Panther Point PCH. Signed-off-by: Seth Heasley Signed-off-by: Jeff Garzik diff --git a/drivers/ata/ata_piix.c b/drivers/ata/ata_piix.c index 0bc3fd6..6f6e771 100644 --- a/drivers/ata/ata_piix.c +++ b/drivers/ata/ata_piix.c @@ -309,6 +309,14 @@ static const struct pci_device_id piix_pci_tbl[] = { { 0x8086, 0x1d00, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_sata }, /* SATA Controller IDE (PBG) */ { 0x8086, 0x1d08, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_2port_sata }, + /* SATA Controller IDE (Panther Point) */ + { 0x8086, 0x1e00, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_sata }, + /* SATA Controller IDE (Panther Point) */ + { 0x8086, 0x1e01, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_sata }, + /* SATA Controller IDE (Panther Point) */ + { 0x8086, 0x1e08, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_2port_sata }, + /* SATA Controller IDE (Panther Point) */ + { 0x8086, 0x1e09, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_2port_sata }, { } /* terminate list */ }; -- cgit v0.10.2 From 181e3ceaba761d35d96d791d5031b1e51abec46c Mon Sep 17 00:00:00 2001 From: Seth Heasley Date: Wed, 20 Apr 2011 08:45:20 -0700 Subject: ahci: AHCI-mode SATA patch for Intel Panther Point DeviceIDs The previously submitted patch was word-wrapped. This patch adds the AHCI-mode SATA DeviceIDs for the Intel Panther Point PCH. Signed-off-by: Seth Heasley Signed-off-by: Jeff Garzik diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c index cbd38e1..71afe03 100644 --- a/drivers/ata/ahci.c +++ b/drivers/ata/ahci.c @@ -261,6 +261,12 @@ static const struct pci_device_id ahci_pci_tbl[] = { { PCI_VDEVICE(INTEL, 0x1d06), board_ahci }, /* PBG RAID */ { PCI_VDEVICE(INTEL, 0x2826), board_ahci }, /* PBG RAID */ { PCI_VDEVICE(INTEL, 0x2323), board_ahci }, /* DH89xxCC AHCI */ + { PCI_VDEVICE(INTEL, 0x1e02), board_ahci }, /* Panther Point AHCI */ + { PCI_VDEVICE(INTEL, 0x1e03), board_ahci }, /* Panther Point AHCI */ + { PCI_VDEVICE(INTEL, 0x1e04), board_ahci }, /* Panther Point RAID */ + { PCI_VDEVICE(INTEL, 0x1e05), board_ahci }, /* Panther Point RAID */ + { PCI_VDEVICE(INTEL, 0x1e06), board_ahci }, /* Panther Point RAID */ + { PCI_VDEVICE(INTEL, 0x1e07), board_ahci }, /* Panther Point RAID */ /* JMicron 360/1/3/5/6, match class to avoid IDE function */ { PCI_VENDOR_ID_JMICRON, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, -- cgit v0.10.2 From 9719b8f5bc35664a23de1ddfbc85217398af0df8 Mon Sep 17 00:00:00 2001 From: Igor Plyatov Date: Mon, 28 Mar 2011 16:56:15 +0400 Subject: ata: pata_at91.c bugfix for high master clock The AT91SAM9 microcontrollers with master clock higher then 105 MHz and PIO0, have overflow of the NCS_RD_PULSE value in the MSB. This lead to "NCS_RD_PULSE" pulse longer then "NRD_CYCLE" pulse and driver does not detect ATA device. Signed-off-by: Igor Plyatov Signed-off-by: Jeff Garzik diff --git a/drivers/ata/pata_at91.c b/drivers/ata/pata_at91.c index 0da0dcc..a9a066a 100644 --- a/drivers/ata/pata_at91.c +++ b/drivers/ata/pata_at91.c @@ -33,11 +33,12 @@ #define DRV_NAME "pata_at91" -#define DRV_VERSION "0.1" +#define DRV_VERSION "0.2" #define CF_IDE_OFFSET 0x00c00000 #define CF_ALT_IDE_OFFSET 0x00e00000 #define CF_IDE_RES_SIZE 0x08 +#define NCS_RD_PULSE_LIMIT 0x3f /* maximal value for pulse bitfields */ struct at91_ide_info { unsigned long mode; @@ -109,6 +110,11 @@ static void set_smc_timing(struct device *dev, /* (CS0, CS1, DIR, OE) <= (CFCE1, CFCE2, CFRNW, NCSX) timings */ ncs_read_setup = 1; ncs_read_pulse = read_cycle - 2; + if (ncs_read_pulse > NCS_RD_PULSE_LIMIT) { + ncs_read_pulse = NCS_RD_PULSE_LIMIT; + dev_warn(dev, "ncs_read_pulse limited to maximal value %lu\n", + ncs_read_pulse); + } /* Write timings same as read timings */ write_cycle = read_cycle; -- cgit v0.10.2 From 792d37af35386466cf5dda51d6b710fa1dd9aad1 Mon Sep 17 00:00:00 2001 From: Igor Plyatov Date: Mon, 28 Mar 2011 16:56:14 +0400 Subject: ata: pata_at91.c bugfix for initial_timing initialisation The "struct ata_timing" must contain 10 members, but ".dmack_hold" member was forgotten for "initial_timing" initialisation. This patch fixes such a problem. Signed-off-by: Igor Plyatov Signed-off-by: Jeff Garzik diff --git a/drivers/ata/pata_at91.c b/drivers/ata/pata_at91.c index a9a066a..a5fdbdc 100644 --- a/drivers/ata/pata_at91.c +++ b/drivers/ata/pata_at91.c @@ -50,8 +50,18 @@ struct at91_ide_info { void __iomem *alt_addr; }; -static const struct ata_timing initial_timing = - {XFER_PIO_0, 70, 290, 240, 600, 165, 150, 600, 0}; +static const struct ata_timing initial_timing = { + .mode = XFER_PIO_0, + .setup = 70, + .act8b = 290, + .rec8b = 240, + .cyc8b = 600, + .active = 165, + .recover = 150, + .dmack_hold = 0, + .cycle = 600, + .udma = 0 +}; static unsigned long calc_mck_cycles(unsigned long ns, unsigned long mck_hz) { -- cgit v0.10.2 From 270dac35c26433d06a89150c51e75ca0181ca7e4 Mon Sep 17 00:00:00 2001 From: Jian Peng Date: Fri, 22 Apr 2011 23:58:10 -0700 Subject: libata: ahci_start_engine compliant to AHCI spec At the end of section 10.1 of AHCI spec (rev 1.3), it states Software shall not set PxCMD.ST to 1 until it is determined that a functoinal device is present on the port as determined by PxTFD.STS.BSY=0, PxTFD.STS.DRQ=0 and PxSSTS.DET=3h Even though most AHCI host controller works without this check, specific controller will fail under this condition. Signed-off-by: Jian Peng Signed-off-by: Jeff Garzik diff --git a/drivers/ata/libahci.c b/drivers/ata/libahci.c index d38c40f..ff9d832 100644 --- a/drivers/ata/libahci.c +++ b/drivers/ata/libahci.c @@ -561,6 +561,27 @@ void ahci_start_engine(struct ata_port *ap) { void __iomem *port_mmio = ahci_port_base(ap); u32 tmp; + u8 status; + + status = readl(port_mmio + PORT_TFDATA) & 0xFF; + + /* + * At end of section 10.1 of AHCI spec (rev 1.3), it states + * Software shall not set PxCMD.ST to 1 until it is determined + * that a functoinal device is present on the port as determined by + * PxTFD.STS.BSY=0, PxTFD.STS.DRQ=0 and PxSSTS.DET=3h + * + * Even though most AHCI host controllers work without this check, + * specific controller will fail under this condition + */ + if (status & (ATA_BUSY | ATA_DRQ)) + return; + else { + ahci_scr_read(&ap->link, SCR_STATUS, &tmp); + + if ((tmp & 0xf) != 0x3) + return; + } /* start DMA */ tmp = readl(port_mmio + PORT_CMD); -- cgit v0.10.2 From 953a12cc2889d1be92e80a2d0bab5ffef4942300 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Romieu?= Date: Sun, 24 Apr 2011 17:38:48 +0200 Subject: r8169: don't request firmware when there's no userspace. The firmware is cached during the first successfull call to open() and released once the network device is unregistered. The driver uses the cached firmware between open() and unregister_netdev(). So far the firmware is optional : a failure to load the firmware does not prevent open() to success. It is thus necessary to 1) unregister all 816x / 810[23] devices and 2) force a driver probe to issue a new firmware load. Signed-off-by: Francois Romieu Fixed-by: Ciprian Docan Cc: Realtek linux nic maintainers diff --git a/drivers/net/r8169.c b/drivers/net/r8169.c index 493b0de..397c368 100644 --- a/drivers/net/r8169.c +++ b/drivers/net/r8169.c @@ -170,6 +170,16 @@ static const struct { }; #undef _R +static const struct rtl_firmware_info { + int mac_version; + const char *fw_name; +} rtl_firmware_infos[] = { + { .mac_version = RTL_GIGA_MAC_VER_25, .fw_name = FIRMWARE_8168D_1 }, + { .mac_version = RTL_GIGA_MAC_VER_26, .fw_name = FIRMWARE_8168D_2 }, + { .mac_version = RTL_GIGA_MAC_VER_29, .fw_name = FIRMWARE_8105E_1 }, + { .mac_version = RTL_GIGA_MAC_VER_30, .fw_name = FIRMWARE_8105E_1 } +}; + enum cfg_version { RTL_CFG_0 = 0x00, RTL_CFG_1, @@ -565,6 +575,7 @@ struct rtl8169_private { u32 saved_wolopts; const struct firmware *fw; +#define RTL_FIRMWARE_UNKNOWN ERR_PTR(-EAGAIN); }; MODULE_AUTHOR("Realtek and the Linux r8169 crew "); @@ -1789,25 +1800,26 @@ rtl_phy_write_fw(struct rtl8169_private *tp, const struct firmware *fw) static void rtl_release_firmware(struct rtl8169_private *tp) { - release_firmware(tp->fw); - tp->fw = NULL; + if (!IS_ERR_OR_NULL(tp->fw)) + release_firmware(tp->fw); + tp->fw = RTL_FIRMWARE_UNKNOWN; } -static int rtl_apply_firmware(struct rtl8169_private *tp, const char *fw_name) +static void rtl_apply_firmware(struct rtl8169_private *tp) { - const struct firmware **fw = &tp->fw; - int rc = !*fw; - - if (rc) { - rc = request_firmware(fw, fw_name, &tp->pci_dev->dev); - if (rc < 0) - goto out; - } + const struct firmware *fw = tp->fw; /* TODO: release firmware once rtl_phy_write_fw signals failures. */ - rtl_phy_write_fw(tp, *fw); -out: - return rc; + if (!IS_ERR_OR_NULL(fw)) + rtl_phy_write_fw(tp, fw); +} + +static void rtl_apply_firmware_cond(struct rtl8169_private *tp, u8 reg, u16 val) +{ + if (rtl_readphy(tp, reg) != val) + netif_warn(tp, hw, tp->dev, "chipset not ready for firmware\n"); + else + rtl_apply_firmware(tp); } static void rtl8169s_hw_phy_config(struct rtl8169_private *tp) @@ -2246,10 +2258,8 @@ static void rtl8168d_1_hw_phy_config(struct rtl8169_private *tp) rtl_writephy(tp, 0x1f, 0x0005); rtl_writephy(tp, 0x05, 0x001b); - if ((rtl_readphy(tp, 0x06) != 0xbf00) || - (rtl_apply_firmware(tp, FIRMWARE_8168D_1) < 0)) { - netif_warn(tp, probe, tp->dev, "unable to apply firmware patch\n"); - } + + rtl_apply_firmware_cond(tp, MII_EXPANSION, 0xbf00); rtl_writephy(tp, 0x1f, 0x0000); } @@ -2351,10 +2361,8 @@ static void rtl8168d_2_hw_phy_config(struct rtl8169_private *tp) rtl_writephy(tp, 0x1f, 0x0005); rtl_writephy(tp, 0x05, 0x001b); - if ((rtl_readphy(tp, 0x06) != 0xb300) || - (rtl_apply_firmware(tp, FIRMWARE_8168D_2) < 0)) { - netif_warn(tp, probe, tp->dev, "unable to apply firmware patch\n"); - } + + rtl_apply_firmware_cond(tp, MII_EXPANSION, 0xb300); rtl_writephy(tp, 0x1f, 0x0000); } @@ -2474,8 +2482,7 @@ static void rtl8105e_hw_phy_config(struct rtl8169_private *tp) rtl_writephy(tp, 0x18, 0x0310); msleep(100); - if (rtl_apply_firmware(tp, FIRMWARE_8105E_1) < 0) - netif_warn(tp, probe, tp->dev, "unable to apply firmware patch\n"); + rtl_apply_firmware(tp); rtl_writephy_batch(tp, phy_reg_init, ARRAY_SIZE(phy_reg_init)); } @@ -3237,6 +3244,8 @@ rtl8169_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) tp->timer.data = (unsigned long) dev; tp->timer.function = rtl8169_phy_timer; + tp->fw = RTL_FIRMWARE_UNKNOWN; + rc = register_netdev(dev); if (rc < 0) goto err_out_msi_4; @@ -3288,10 +3297,10 @@ static void __devexit rtl8169_remove_one(struct pci_dev *pdev) cancel_delayed_work_sync(&tp->task); - rtl_release_firmware(tp); - unregister_netdev(dev); + rtl_release_firmware(tp); + if (pci_dev_run_wake(pdev)) pm_runtime_get_noresume(&pdev->dev); @@ -3303,6 +3312,37 @@ static void __devexit rtl8169_remove_one(struct pci_dev *pdev) pci_set_drvdata(pdev, NULL); } +static void rtl_request_firmware(struct rtl8169_private *tp) +{ + int i; + + /* Return early if the firmware is already loaded / cached. */ + if (!IS_ERR(tp->fw)) + goto out; + + for (i = 0; i < ARRAY_SIZE(rtl_firmware_infos); i++) { + const struct rtl_firmware_info *info = rtl_firmware_infos + i; + + if (info->mac_version == tp->mac_version) { + const char *name = info->fw_name; + int rc; + + rc = request_firmware(&tp->fw, name, &tp->pci_dev->dev); + if (rc < 0) { + netif_warn(tp, ifup, tp->dev, "unable to load " + "firmware patch %s (%d)\n", name, rc); + goto out_disable_request_firmware; + } + goto out; + } + } + +out_disable_request_firmware: + tp->fw = NULL; +out: + return; +} + static int rtl8169_open(struct net_device *dev) { struct rtl8169_private *tp = netdev_priv(dev); @@ -3334,11 +3374,13 @@ static int rtl8169_open(struct net_device *dev) smp_mb(); + rtl_request_firmware(tp); + retval = request_irq(dev->irq, rtl8169_interrupt, (tp->features & RTL_FEATURE_MSI) ? 0 : IRQF_SHARED, dev->name, dev); if (retval < 0) - goto err_release_ring_2; + goto err_release_fw_2; napi_enable(&tp->napi); @@ -3359,7 +3401,8 @@ static int rtl8169_open(struct net_device *dev) out: return retval; -err_release_ring_2: +err_release_fw_2: + rtl_release_firmware(tp); rtl8169_rx_clear(tp); err_free_rx_1: dma_free_coherent(&pdev->dev, R8169_RX_RING_BYTES, tp->RxDescArray, -- cgit v0.10.2 From a1f74ae82d133ebb2aabb19d181944b4e83e9960 Mon Sep 17 00:00:00 2001 From: Dan Rosenberg Date: Tue, 5 Apr 2011 12:45:59 -0400 Subject: [SCSI] mpt2sas: prevent heap overflows and unchecked reads At two points in handling device ioctls via /dev/mpt2ctl, user-supplied length values are used to copy data from userspace into heap buffers without bounds checking, allowing controllable heap corruption and subsequently privilege escalation. Additionally, user-supplied values are used to determine the size of a copy_to_user() as well as the offset into the buffer to be read, with no bounds checking, allowing users to read arbitrary kernel memory. Signed-off-by: Dan Rosenberg Cc: stable@kernel.org Acked-by: Eric Moore Signed-off-by: James Bottomley diff --git a/drivers/scsi/mpt2sas/mpt2sas_ctl.c b/drivers/scsi/mpt2sas/mpt2sas_ctl.c index 1c6d2b4..d72f1f2 100644 --- a/drivers/scsi/mpt2sas/mpt2sas_ctl.c +++ b/drivers/scsi/mpt2sas/mpt2sas_ctl.c @@ -688,6 +688,13 @@ _ctl_do_mpt_command(struct MPT2SAS_ADAPTER *ioc, goto out; } + /* Check for overflow and wraparound */ + if (karg.data_sge_offset * 4 > ioc->request_sz || + karg.data_sge_offset > (UINT_MAX / 4)) { + ret = -EINVAL; + goto out; + } + /* copy in request message frame from user */ if (copy_from_user(mpi_request, mf, karg.data_sge_offset*4)) { printk(KERN_ERR "failure at %s:%d/%s()!\n", __FILE__, __LINE__, @@ -1963,7 +1970,7 @@ _ctl_diag_read_buffer(void __user *arg, enum block_state state) Mpi2DiagBufferPostReply_t *mpi_reply; int rc, i; u8 buffer_type; - unsigned long timeleft; + unsigned long timeleft, request_size, copy_size; u16 smid; u16 ioc_status; u8 issue_reset = 0; @@ -1999,6 +2006,8 @@ _ctl_diag_read_buffer(void __user *arg, enum block_state state) return -ENOMEM; } + request_size = ioc->diag_buffer_sz[buffer_type]; + if ((karg.starting_offset % 4) || (karg.bytes_to_read % 4)) { printk(MPT2SAS_ERR_FMT "%s: either the starting_offset " "or bytes_to_read are not 4 byte aligned\n", ioc->name, @@ -2006,13 +2015,23 @@ _ctl_diag_read_buffer(void __user *arg, enum block_state state) return -EINVAL; } + if (karg.starting_offset > request_size) + return -EINVAL; + diag_data = (void *)(request_data + karg.starting_offset); dctlprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: diag_buffer(%p), " "offset(%d), sz(%d)\n", ioc->name, __func__, diag_data, karg.starting_offset, karg.bytes_to_read)); + /* Truncate data on requests that are too large */ + if ((diag_data + karg.bytes_to_read < diag_data) || + (diag_data + karg.bytes_to_read > request_data + request_size)) + copy_size = request_size - karg.starting_offset; + else + copy_size = karg.bytes_to_read; + if (copy_to_user((void __user *)uarg->diagnostic_data, - diag_data, karg.bytes_to_read)) { + diag_data, copy_size)) { printk(MPT2SAS_ERR_FMT "%s: Unable to write " "mpt_diag_read_buffer_t data @ %p\n", ioc->name, __func__, diag_data); -- cgit v0.10.2 From 0b8393578c70bc1f09790eeae7d918f38da2e010 Mon Sep 17 00:00:00 2001 From: Mike Snitzer Date: Fri, 8 Apr 2011 15:05:36 -0400 Subject: [SCSI] scsi_dh: fix reference counting in scsi_dh_activate error path Commit db422318cbca55168cf965f655471dbf8be82433 ([SCSI] scsi_dh: propagate SCSI device deletion) introduced a regression where the device reference is not dropped prior to scsi_dh_activate's early return from the error path. Signed-off-by: Mike Snitzer Cc: stable@kernel.org # 2.6.38 Reviewed-by: Mike Christie Signed-off-by: James Bottomley diff --git a/drivers/scsi/device_handler/scsi_dh.c b/drivers/scsi/device_handler/scsi_dh.c index 564e6ec..0119b81 100644 --- a/drivers/scsi/device_handler/scsi_dh.c +++ b/drivers/scsi/device_handler/scsi_dh.c @@ -394,12 +394,14 @@ int scsi_dh_activate(struct request_queue *q, activate_complete fn, void *data) unsigned long flags; struct scsi_device *sdev; struct scsi_device_handler *scsi_dh = NULL; + struct device *dev = NULL; spin_lock_irqsave(q->queue_lock, flags); sdev = q->queuedata; if (sdev && sdev->scsi_dh_data) scsi_dh = sdev->scsi_dh_data->scsi_dh; - if (!scsi_dh || !get_device(&sdev->sdev_gendev) || + dev = get_device(&sdev->sdev_gendev); + if (!scsi_dh || !dev || sdev->sdev_state == SDEV_CANCEL || sdev->sdev_state == SDEV_DEL) err = SCSI_DH_NOSYS; @@ -410,12 +412,13 @@ int scsi_dh_activate(struct request_queue *q, activate_complete fn, void *data) if (err) { if (fn) fn(data, err); - return err; + goto out; } if (scsi_dh->activate) err = scsi_dh->activate(sdev, fn, data); - put_device(&sdev->sdev_gendev); +out: + put_device(dev); return err; } EXPORT_SYMBOL_GPL(scsi_dh_activate); -- cgit v0.10.2 From 86cbfb5607d4b81b1a993ff689bbd2addd5d3a9b Mon Sep 17 00:00:00 2001 From: James Bottomley Date: Fri, 22 Apr 2011 10:39:59 -0500 Subject: [SCSI] put stricter guards on queue dead checks SCSI uses request_queue->queuedata == NULL as a signal that the queue is dying. We set this state in the sdev release function. However, this allows a small window where we release the last reference but haven't quite got to this stage yet and so something will try to take a reference in scsi_request_fn and oops. It's very rare, but we had a report here, so we're pushing this as a bug fix The actual fix is to set request_queue->queuedata to NULL in scsi_remove_device() before we drop the reference. This causes correct automatic rejects from scsi_request_fn as people who hold additional references try to submit work and prevents anything from getting a new reference to the sdev that way. Cc: stable@kernel.org Signed-off-by: James Bottomley diff --git a/drivers/scsi/scsi_sysfs.c b/drivers/scsi/scsi_sysfs.c index e44ff64..e639125 100644 --- a/drivers/scsi/scsi_sysfs.c +++ b/drivers/scsi/scsi_sysfs.c @@ -322,14 +322,8 @@ static void scsi_device_dev_release_usercontext(struct work_struct *work) kfree(evt); } - if (sdev->request_queue) { - sdev->request_queue->queuedata = NULL; - /* user context needed to free queue */ - scsi_free_queue(sdev->request_queue); - /* temporary expedient, try to catch use of queue lock - * after free of sdev */ - sdev->request_queue = NULL; - } + /* NULL queue means the device can't be used */ + sdev->request_queue = NULL; scsi_target_reap(scsi_target(sdev)); @@ -937,6 +931,12 @@ void __scsi_remove_device(struct scsi_device *sdev) if (sdev->host->hostt->slave_destroy) sdev->host->hostt->slave_destroy(sdev); transport_destroy_device(dev); + + /* cause the request function to reject all I/O requests */ + sdev->request_queue->queuedata = NULL; + + /* Freeing the queue signals to block that we're done */ + scsi_free_queue(sdev->request_queue); put_device(dev); } -- cgit v0.10.2 From cace71b318aa0126e7cfe49fe5e9133e0395c478 Mon Sep 17 00:00:00 2001 From: Florian Tobias Schandinat Date: Sun, 24 Apr 2011 17:08:44 +0000 Subject: viafb: use write combining for video ram This can give a speed up of factor 6-9, which is quite notable. Signed-off-by: Florian Tobias Schandinat diff --git a/drivers/video/via/via-core.c b/drivers/video/via/via-core.c index 6723d69..5b0129b 100644 --- a/drivers/video/via/via-core.c +++ b/drivers/video/via/via-core.c @@ -505,7 +505,7 @@ static int __devinit via_pci_setup_mmio(struct viafb_dev *vdev) ret = vdev->fbmem_len = viafb_get_fb_size_from_pci(vdev->chip_type); if (ret < 0) goto out_unmap; - vdev->fbmem = ioremap_nocache(vdev->fbmem_start, vdev->fbmem_len); + vdev->fbmem = ioremap_wc(vdev->fbmem_start, vdev->fbmem_len); if (vdev->fbmem == NULL) { ret = -ENOMEM; goto out_unmap; -- cgit v0.10.2 From 5f6279da3760ce48f478f2856aacebe0c59a39f3 Mon Sep 17 00:00:00 2001 From: Dan Rosenberg Date: Tue, 5 Apr 2011 13:27:31 -0400 Subject: [SCSI] pmcraid: reject negative request size There's a code path in pmcraid that can be reached via device ioctl that causes all sorts of ugliness, including heap corruption or triggering the OOM killer due to consecutive allocation of large numbers of pages. Not especially relevant from a security perspective, since users must have CAP_SYS_ADMIN to open the character device. First, the user can call pmcraid_chr_ioctl() with a type PMCRAID_PASSTHROUGH_IOCTL. A pmcraid_passthrough_ioctl_buffer is copied in, and the request_size variable is set to buffer->ioarcb.data_transfer_length, which is an arbitrary 32-bit signed value provided by the user. If a negative value is provided here, bad things can happen. For example, pmcraid_build_passthrough_ioadls() is called with this request_size, which immediately calls pmcraid_alloc_sglist() with a negative size. The resulting math on allocating a scatter list can result in an overflow in the kzalloc() call (if num_elem is 0, the sglist will be smaller than expected), or if num_elem is unexpectedly large the subsequent loop will call alloc_pages() repeatedly, a high number of pages will be allocated and the OOM killer might be invoked. Prevent this value from being negative in pmcraid_ioctl_passthrough(). Signed-off-by: Dan Rosenberg Cc: stable@kernel.org Cc: Anil Ravindranath Signed-off-by: James Bottomley diff --git a/drivers/scsi/pmcraid.c b/drivers/scsi/pmcraid.c index 96d5ad0..7f636b1 100644 --- a/drivers/scsi/pmcraid.c +++ b/drivers/scsi/pmcraid.c @@ -3814,6 +3814,9 @@ static long pmcraid_ioctl_passthrough( rc = -EFAULT; goto out_free_buffer; } + } else if (request_size < 0) { + rc = -EINVAL; + goto out_free_buffer; } /* check if we have any additional command parameters */ -- cgit v0.10.2 From 328f5cc30290a92ea3ca62b2a63d2b9ebcb0d334 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Fri, 22 Apr 2011 22:02:33 +0200 Subject: ARM: Use struct syscore_ops instead of sysdevs for PM in common code Convert some ARM architecture's common code to using struct syscore_ops objects for power management instead of sysdev classes and sysdevs. This simplifies the code and reduces the kernel's memory footprint. It also is necessary for removing sysdevs from the kernel entirely in the future. Signed-off-by: Rafael J. Wysocki Acked-by: Greg Kroah-Hartman diff --git a/arch/arm/common/vic.c b/arch/arm/common/vic.c index 113085a..7aa4262 100644 --- a/arch/arm/common/vic.c +++ b/arch/arm/common/vic.c @@ -22,17 +22,16 @@ #include #include #include -#include +#include #include #include #include #include -#if defined(CONFIG_PM) +#ifdef CONFIG_PM /** * struct vic_device - VIC PM device - * @sysdev: The system device which is registered. * @irq: The IRQ number for the base of the VIC. * @base: The register base for the VIC. * @resume_sources: A bitmask of interrupts for resume. @@ -43,8 +42,6 @@ * @protect: Save for VIC_PROTECT. */ struct vic_device { - struct sys_device sysdev; - void __iomem *base; int irq; u32 resume_sources; @@ -59,11 +56,6 @@ struct vic_device { static struct vic_device vic_devices[CONFIG_ARM_VIC_NR]; static int vic_id; - -static inline struct vic_device *to_vic(struct sys_device *sys) -{ - return container_of(sys, struct vic_device, sysdev); -} #endif /* CONFIG_PM */ /** @@ -85,10 +77,9 @@ static void vic_init2(void __iomem *base) writel(32, base + VIC_PL190_DEF_VECT_ADDR); } -#if defined(CONFIG_PM) -static int vic_class_resume(struct sys_device *dev) +#ifdef CONFIG_PM +static void resume_one_vic(struct vic_device *vic) { - struct vic_device *vic = to_vic(dev); void __iomem *base = vic->base; printk(KERN_DEBUG "%s: resuming vic at %p\n", __func__, base); @@ -107,13 +98,18 @@ static int vic_class_resume(struct sys_device *dev) writel(vic->soft_int, base + VIC_INT_SOFT); writel(~vic->soft_int, base + VIC_INT_SOFT_CLEAR); +} - return 0; +static void vic_resume(void) +{ + int id; + + for (id = vic_id - 1; id >= 0; id--) + resume_one_vic(vic_devices + id); } -static int vic_class_suspend(struct sys_device *dev, pm_message_t state) +static void suspend_one_vic(struct vic_device *vic) { - struct vic_device *vic = to_vic(dev); void __iomem *base = vic->base; printk(KERN_DEBUG "%s: suspending vic at %p\n", __func__, base); @@ -128,14 +124,21 @@ static int vic_class_suspend(struct sys_device *dev, pm_message_t state) writel(vic->resume_irqs, base + VIC_INT_ENABLE); writel(~vic->resume_irqs, base + VIC_INT_ENABLE_CLEAR); +} + +static int vic_suspend(void) +{ + int id; + + for (id = 0; id < vic_id; id++) + suspend_one_vic(vic_devices + id); return 0; } -struct sysdev_class vic_class = { - .name = "vic", - .suspend = vic_class_suspend, - .resume = vic_class_resume, +struct syscore_ops vic_syscore_ops = { + .suspend = vic_suspend, + .resume = vic_resume, }; /** @@ -147,30 +150,8 @@ struct sysdev_class vic_class = { */ static int __init vic_pm_init(void) { - struct vic_device *dev = vic_devices; - int err; - int id; - - if (vic_id == 0) - return 0; - - err = sysdev_class_register(&vic_class); - if (err) { - printk(KERN_ERR "%s: cannot register class\n", __func__); - return err; - } - - for (id = 0; id < vic_id; id++, dev++) { - dev->sysdev.id = id; - dev->sysdev.cls = &vic_class; - - err = sysdev_register(&dev->sysdev); - if (err) { - printk(KERN_ERR "%s: failed to register device\n", - __func__); - return err; - } - } + if (vic_id > 0) + register_syscore_ops(&vic_syscore_ops); return 0; } diff --git a/arch/arm/include/asm/mach/time.h b/arch/arm/include/asm/mach/time.h index 883f6be..d5adaae 100644 --- a/arch/arm/include/asm/mach/time.h +++ b/arch/arm/include/asm/mach/time.h @@ -34,7 +34,6 @@ * timer interrupt which may be pending. */ struct sys_timer { - struct sys_device dev; void (*init)(void); void (*suspend)(void); void (*resume)(void); diff --git a/arch/arm/kernel/leds.c b/arch/arm/kernel/leds.c index 31a316c..0f107dc 100644 --- a/arch/arm/kernel/leds.c +++ b/arch/arm/kernel/leds.c @@ -10,6 +10,7 @@ #include #include #include +#include #include @@ -69,36 +70,37 @@ static ssize_t leds_store(struct sys_device *dev, static SYSDEV_ATTR(event, 0200, NULL, leds_store); -static int leds_suspend(struct sys_device *dev, pm_message_t state) +static struct sysdev_class leds_sysclass = { + .name = "leds", +}; + +static struct sys_device leds_device = { + .id = 0, + .cls = &leds_sysclass, +}; + +static int leds_suspend(void) { leds_event(led_stop); return 0; } -static int leds_resume(struct sys_device *dev) +static void leds_resume(void) { leds_event(led_start); - return 0; } -static int leds_shutdown(struct sys_device *dev) +static void leds_shutdown(void) { leds_event(led_halted); - return 0; } -static struct sysdev_class leds_sysclass = { - .name = "leds", +static struct syscore_ops leds_syscore_ops = { .shutdown = leds_shutdown, .suspend = leds_suspend, .resume = leds_resume, }; -static struct sys_device leds_device = { - .id = 0, - .cls = &leds_sysclass, -}; - static int __init leds_init(void) { int ret; @@ -107,6 +109,8 @@ static int __init leds_init(void) ret = sysdev_register(&leds_device); if (ret == 0) ret = sysdev_create_file(&leds_device, &attr_event); + if (ret == 0) + register_syscore_ops(&leds_syscore_ops); return ret; } diff --git a/arch/arm/kernel/time.c b/arch/arm/kernel/time.c index 1ff46ca..cb634c3 100644 --- a/arch/arm/kernel/time.c +++ b/arch/arm/kernel/time.c @@ -21,7 +21,7 @@ #include #include #include -#include +#include #include #include @@ -115,48 +115,37 @@ void timer_tick(void) #endif #if defined(CONFIG_PM) && !defined(CONFIG_GENERIC_CLOCKEVENTS) -static int timer_suspend(struct sys_device *dev, pm_message_t state) +static int timer_suspend(void) { - struct sys_timer *timer = container_of(dev, struct sys_timer, dev); - - if (timer->suspend != NULL) - timer->suspend(); + if (system_timer->suspend) + system_timer->suspend(); return 0; } -static int timer_resume(struct sys_device *dev) +static void timer_resume(void) { - struct sys_timer *timer = container_of(dev, struct sys_timer, dev); - - if (timer->resume != NULL) - timer->resume(); - - return 0; + if (system_timer->resume) + system_timer->resume(); } #else #define timer_suspend NULL #define timer_resume NULL #endif -static struct sysdev_class timer_sysclass = { - .name = "timer", +static struct syscore_ops timer_syscore_ops = { .suspend = timer_suspend, .resume = timer_resume, }; -static int __init timer_init_sysfs(void) +static int __init timer_init_syscore_ops(void) { - int ret = sysdev_class_register(&timer_sysclass); - if (ret == 0) { - system_timer->dev.cls = &timer_sysclass; - ret = sysdev_register(&system_timer->dev); - } + register_syscore_ops(&timer_syscore_ops); - return ret; + return 0; } -device_initcall(timer_init_sysfs); +device_initcall(timer_init_syscore_ops); void __init time_init(void) { diff --git a/arch/arm/vfp/vfpmodule.c b/arch/arm/vfp/vfpmodule.c index f746950..f25e7ec 100644 --- a/arch/arm/vfp/vfpmodule.c +++ b/arch/arm/vfp/vfpmodule.c @@ -398,9 +398,9 @@ static void vfp_enable(void *unused) } #ifdef CONFIG_PM -#include +#include -static int vfp_pm_suspend(struct sys_device *dev, pm_message_t state) +static int vfp_pm_suspend(void) { struct thread_info *ti = current_thread_info(); u32 fpexc = fmrx(FPEXC); @@ -420,34 +420,25 @@ static int vfp_pm_suspend(struct sys_device *dev, pm_message_t state) return 0; } -static int vfp_pm_resume(struct sys_device *dev) +static void vfp_pm_resume(void) { /* ensure we have access to the vfp */ vfp_enable(NULL); /* and disable it to ensure the next usage restores the state */ fmxr(FPEXC, fmrx(FPEXC) & ~FPEXC_EN); - - return 0; } -static struct sysdev_class vfp_pm_sysclass = { - .name = "vfp", +static struct syscore_ops vfp_pm_syscore_ops = { .suspend = vfp_pm_suspend, .resume = vfp_pm_resume, }; -static struct sys_device vfp_pm_sysdev = { - .cls = &vfp_pm_sysclass, -}; - static void vfp_pm_init(void) { - sysdev_class_register(&vfp_pm_sysclass); - sysdev_register(&vfp_pm_sysdev); + register_syscore_ops(&vfp_pm_syscore_ops); } - #else static inline void vfp_pm_init(void) { } #endif /* CONFIG_PM */ -- cgit v0.10.2 From 3c437ffd20329619672b12a97bee944bccdd4ec9 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Fri, 22 Apr 2011 22:02:46 +0200 Subject: ARM / OMAP: Use struct syscore_ops for "core" power management Replace the sysdev class and struct sys_device used for power management in the OMAP's GPIO code with a struct syscore_ops object which is simpler. Signed-off-by: Rafael J. Wysocki Acked-by: Kevin Hilman Acked-by: Greg Kroah-Hartman diff --git a/arch/arm/plat-omap/gpio.c b/arch/arm/plat-omap/gpio.c index d2adcdd..bd9e321 100644 --- a/arch/arm/plat-omap/gpio.c +++ b/arch/arm/plat-omap/gpio.c @@ -17,7 +17,7 @@ #include #include #include -#include +#include #include #include #include @@ -1372,9 +1372,7 @@ static const struct dev_pm_ops omap_mpuio_dev_pm_ops = { .resume_noirq = omap_mpuio_resume_noirq, }; -/* use platform_driver for this, now that there's no longer any - * point to sys_device (other than not disturbing old code). - */ +/* use platform_driver for this. */ static struct platform_driver omap_mpuio_driver = { .driver = { .name = "mpuio", @@ -1745,7 +1743,7 @@ static int __devinit omap_gpio_probe(struct platform_device *pdev) } #if defined(CONFIG_ARCH_OMAP16XX) || defined(CONFIG_ARCH_OMAP2PLUS) -static int omap_gpio_suspend(struct sys_device *dev, pm_message_t mesg) +static int omap_gpio_suspend(void) { int i; @@ -1795,12 +1793,12 @@ static int omap_gpio_suspend(struct sys_device *dev, pm_message_t mesg) return 0; } -static int omap_gpio_resume(struct sys_device *dev) +static void omap_gpio_resume(void) { int i; if (!cpu_class_is_omap2() && !cpu_is_omap16xx()) - return 0; + return; for (i = 0; i < gpio_bank_count; i++) { struct gpio_bank *bank = &gpio_bank[i]; @@ -1836,21 +1834,13 @@ static int omap_gpio_resume(struct sys_device *dev) __raw_writel(bank->saved_wakeup, wake_set); spin_unlock_irqrestore(&bank->lock, flags); } - - return 0; } -static struct sysdev_class omap_gpio_sysclass = { - .name = "gpio", +static struct syscore_ops omap_gpio_syscore_ops = { .suspend = omap_gpio_suspend, .resume = omap_gpio_resume, }; -static struct sys_device omap_gpio_device = { - .id = 0, - .cls = &omap_gpio_sysclass, -}; - #endif #ifdef CONFIG_ARCH_OMAP2PLUS @@ -2108,21 +2098,14 @@ postcore_initcall(omap_gpio_drv_reg); static int __init omap_gpio_sysinit(void) { - int ret = 0; - mpuio_init(); #if defined(CONFIG_ARCH_OMAP16XX) || defined(CONFIG_ARCH_OMAP2PLUS) - if (cpu_is_omap16xx() || cpu_class_is_omap2()) { - if (ret == 0) { - ret = sysdev_class_register(&omap_gpio_sysclass); - if (ret == 0) - ret = sysdev_register(&omap_gpio_device); - } - } + if (cpu_is_omap16xx() || cpu_class_is_omap2()) + register_syscore_ops(&omap_gpio_syscore_ops); #endif - return ret; + return 0; } arch_initcall(omap_gpio_sysinit); -- cgit v0.10.2 From b7808056141bc4d67213036921a5a685ebec0274 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Fri, 22 Apr 2011 22:02:55 +0200 Subject: ARM / Integrator: Use struct syscore_ops for core PM Replace the sysdev class and struct sys_device used for power management by the Integrator interrupt-handling code with a struct syscore_ops object which is simpler. Signed-off-by: Rafael J. Wysocki Acked-by: Greg Kroah-Hartman diff --git a/arch/arm/mach-integrator/integrator_ap.c b/arch/arm/mach-integrator/integrator_ap.c index 980803f..d3e9645 100644 --- a/arch/arm/mach-integrator/integrator_ap.c +++ b/arch/arm/mach-integrator/integrator_ap.c @@ -24,7 +24,7 @@ #include #include #include -#include +#include #include #include #include @@ -180,13 +180,13 @@ static void __init ap_init_irq(void) #ifdef CONFIG_PM static unsigned long ic_irq_enable; -static int irq_suspend(struct sys_device *dev, pm_message_t state) +static int irq_suspend(void) { ic_irq_enable = readl(VA_IC_BASE + IRQ_ENABLE); return 0; } -static int irq_resume(struct sys_device *dev) +static void irq_resume(void) { /* disable all irq sources */ writel(-1, VA_CMIC_BASE + IRQ_ENABLE_CLEAR); @@ -194,33 +194,25 @@ static int irq_resume(struct sys_device *dev) writel(-1, VA_IC_BASE + FIQ_ENABLE_CLEAR); writel(ic_irq_enable, VA_IC_BASE + IRQ_ENABLE_SET); - return 0; } #else #define irq_suspend NULL #define irq_resume NULL #endif -static struct sysdev_class irq_class = { - .name = "irq", +static struct syscore_ops irq_syscore_ops = { .suspend = irq_suspend, .resume = irq_resume, }; -static struct sys_device irq_device = { - .id = 0, - .cls = &irq_class, -}; - -static int __init irq_init_sysfs(void) +static int __init irq_syscore_init(void) { - int ret = sysdev_class_register(&irq_class); - if (ret == 0) - ret = sysdev_register(&irq_device); - return ret; + register_syscore_ops(&irq_syscore_ops); + + return 0; } -device_initcall(irq_init_sysfs); +device_initcall(irq_syscore_init); /* * Flash handling. -- cgit v0.10.2 From 905339807bde7bb726001b69fbdf69ab0cf69a9e Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Fri, 22 Apr 2011 22:03:03 +0200 Subject: ARM / SA1100: Use struct syscore_ops for "core" power management Replace the sysdev class and struct sys_device used for power management by the SA1100 interrupt-handling code with a struct syscore_ops object which is simpler. Signed-off-by: Rafael J. Wysocki Acked-by: Greg Kroah-Hartman diff --git a/arch/arm/mach-sa1100/irq.c b/arch/arm/mach-sa1100/irq.c index 423ddb3..dfbf824 100644 --- a/arch/arm/mach-sa1100/irq.c +++ b/arch/arm/mach-sa1100/irq.c @@ -14,7 +14,7 @@ #include #include #include -#include +#include #include #include @@ -234,7 +234,7 @@ static struct sa1100irq_state { unsigned int iccr; } sa1100irq_state; -static int sa1100irq_suspend(struct sys_device *dev, pm_message_t state) +static int sa1100irq_suspend(void) { struct sa1100irq_state *st = &sa1100irq_state; @@ -264,7 +264,7 @@ static int sa1100irq_suspend(struct sys_device *dev, pm_message_t state) return 0; } -static int sa1100irq_resume(struct sys_device *dev) +static void sa1100irq_resume(void) { struct sa1100irq_state *st = &sa1100irq_state; @@ -277,24 +277,17 @@ static int sa1100irq_resume(struct sys_device *dev) ICMR = st->icmr; } - return 0; } -static struct sysdev_class sa1100irq_sysclass = { - .name = "sa11x0-irq", +static struct syscore_ops sa1100irq_syscore_ops = { .suspend = sa1100irq_suspend, .resume = sa1100irq_resume, }; -static struct sys_device sa1100irq_device = { - .id = 0, - .cls = &sa1100irq_sysclass, -}; - static int __init sa1100irq_init_devicefs(void) { - sysdev_class_register(&sa1100irq_sysclass); - return sysdev_register(&sa1100irq_device); + register_syscore_ops(&sa1100irq_syscore_ops); + return 0; } device_initcall(sa1100irq_init_devicefs); -- cgit v0.10.2 From 2eaa03b5bebd1e80014f780d7bf27c3e66daefd6 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Fri, 22 Apr 2011 22:03:11 +0200 Subject: ARM / PXA: Use struct syscore_ops for "core" power management Replace sysdev classes and struct sys_device objects used for "core" power management by the PXA platform code with struct syscore_ops objects that are simpler. This reduces the code size and the kernel memory footprint. It also is necessary for removing sysdevs entirely from the kernel in the future. Signed-off-by: Rafael J. Wysocki Acked-by: Greg Kroah-Hartman diff --git a/arch/arm/mach-pxa/balloon3.c b/arch/arm/mach-pxa/balloon3.c index bfbecec..810a982 100644 --- a/arch/arm/mach-pxa/balloon3.c +++ b/arch/arm/mach-pxa/balloon3.c @@ -15,7 +15,6 @@ #include #include -#include #include #include #include diff --git a/arch/arm/mach-pxa/clock-pxa2xx.c b/arch/arm/mach-pxa/clock-pxa2xx.c index 1ce0904..1d5859d 100644 --- a/arch/arm/mach-pxa/clock-pxa2xx.c +++ b/arch/arm/mach-pxa/clock-pxa2xx.c @@ -9,7 +9,7 @@ #include #include #include -#include +#include #include @@ -33,32 +33,22 @@ const struct clkops clk_pxa2xx_cken_ops = { #ifdef CONFIG_PM static uint32_t saved_cken; -static int pxa2xx_clock_suspend(struct sys_device *d, pm_message_t state) +static int pxa2xx_clock_suspend(void) { saved_cken = CKEN; return 0; } -static int pxa2xx_clock_resume(struct sys_device *d) +static void pxa2xx_clock_resume(void) { CKEN = saved_cken; - return 0; } #else #define pxa2xx_clock_suspend NULL #define pxa2xx_clock_resume NULL #endif -struct sysdev_class pxa2xx_clock_sysclass = { - .name = "pxa2xx-clock", +struct syscore_ops pxa2xx_clock_syscore_ops = { .suspend = pxa2xx_clock_suspend, .resume = pxa2xx_clock_resume, }; - -static int __init pxa2xx_clock_init(void) -{ - if (cpu_is_pxa2xx()) - return sysdev_class_register(&pxa2xx_clock_sysclass); - return 0; -} -postcore_initcall(pxa2xx_clock_init); diff --git a/arch/arm/mach-pxa/clock-pxa3xx.c b/arch/arm/mach-pxa/clock-pxa3xx.c index 3f864cd..2a37a9a 100644 --- a/arch/arm/mach-pxa/clock-pxa3xx.c +++ b/arch/arm/mach-pxa/clock-pxa3xx.c @@ -10,6 +10,7 @@ #include #include #include +#include #include #include @@ -182,7 +183,7 @@ const struct clkops clk_pxa3xx_pout_ops = { static uint32_t cken[2]; static uint32_t accr; -static int pxa3xx_clock_suspend(struct sys_device *d, pm_message_t state) +static int pxa3xx_clock_suspend(void) { cken[0] = CKENA; cken[1] = CKENB; @@ -190,28 +191,18 @@ static int pxa3xx_clock_suspend(struct sys_device *d, pm_message_t state) return 0; } -static int pxa3xx_clock_resume(struct sys_device *d) +static void pxa3xx_clock_resume(void) { ACCR = accr; CKENA = cken[0]; CKENB = cken[1]; - return 0; } #else #define pxa3xx_clock_suspend NULL #define pxa3xx_clock_resume NULL #endif -struct sysdev_class pxa3xx_clock_sysclass = { - .name = "pxa3xx-clock", +struct syscore_ops pxa3xx_clock_syscore_ops = { .suspend = pxa3xx_clock_suspend, .resume = pxa3xx_clock_resume, }; - -static int __init pxa3xx_clock_init(void) -{ - if (cpu_is_pxa3xx() || cpu_is_pxa95x()) - return sysdev_class_register(&pxa3xx_clock_sysclass); - return 0; -} -postcore_initcall(pxa3xx_clock_init); diff --git a/arch/arm/mach-pxa/clock.h b/arch/arm/mach-pxa/clock.h index f9f349a..1f2fb9c 100644 --- a/arch/arm/mach-pxa/clock.h +++ b/arch/arm/mach-pxa/clock.h @@ -1,5 +1,5 @@ #include -#include +#include struct clkops { void (*enable)(struct clk *); @@ -54,7 +54,7 @@ extern const struct clkops clk_pxa2xx_cken_ops; void clk_pxa2xx_cken_enable(struct clk *clk); void clk_pxa2xx_cken_disable(struct clk *clk); -extern struct sysdev_class pxa2xx_clock_sysclass; +extern struct syscore_ops pxa2xx_clock_syscore_ops; #if defined(CONFIG_PXA3xx) || defined(CONFIG_PXA95x) #define DEFINE_PXA3_CKEN(_name, _cken, _rate, _delay) \ @@ -74,5 +74,6 @@ extern const struct clkops clk_pxa3xx_smemc_ops; extern void clk_pxa3xx_cken_enable(struct clk *); extern void clk_pxa3xx_cken_disable(struct clk *); -extern struct sysdev_class pxa3xx_clock_sysclass; +extern struct syscore_ops pxa3xx_clock_syscore_ops; + #endif diff --git a/arch/arm/mach-pxa/cm-x270.c b/arch/arm/mach-pxa/cm-x270.c index b88d601a..13518a7 100644 --- a/arch/arm/mach-pxa/cm-x270.c +++ b/arch/arm/mach-pxa/cm-x270.c @@ -10,7 +10,6 @@ */ #include -#include #include #include #include diff --git a/arch/arm/mach-pxa/cm-x2xx.c b/arch/arm/mach-pxa/cm-x2xx.c index 8225e2e..a109967 100644 --- a/arch/arm/mach-pxa/cm-x2xx.c +++ b/arch/arm/mach-pxa/cm-x2xx.c @@ -10,7 +10,7 @@ */ #include -#include +#include #include #include @@ -388,7 +388,7 @@ static inline void cmx2xx_init_display(void) {} #ifdef CONFIG_PM static unsigned long sleep_save_msc[10]; -static int cmx2xx_suspend(struct sys_device *dev, pm_message_t state) +static int cmx2xx_suspend(void) { cmx2xx_pci_suspend(); @@ -412,7 +412,7 @@ static int cmx2xx_suspend(struct sys_device *dev, pm_message_t state) return 0; } -static int cmx2xx_resume(struct sys_device *dev) +static void cmx2xx_resume(void) { cmx2xx_pci_resume(); @@ -420,27 +420,18 @@ static int cmx2xx_resume(struct sys_device *dev) __raw_writel(sleep_save_msc[0], MSC0); __raw_writel(sleep_save_msc[1], MSC1); __raw_writel(sleep_save_msc[2], MSC2); - - return 0; } -static struct sysdev_class cmx2xx_pm_sysclass = { - .name = "pm", +static struct syscore_ops cmx2xx_pm_syscore_ops = { .resume = cmx2xx_resume, .suspend = cmx2xx_suspend, }; -static struct sys_device cmx2xx_pm_device = { - .cls = &cmx2xx_pm_sysclass, -}; - static int __init cmx2xx_pm_init(void) { - int error; - error = sysdev_class_register(&cmx2xx_pm_sysclass); - if (error == 0) - error = sysdev_register(&cmx2xx_pm_device); - return error; + register_syscore_ops(&cmx2xx_pm_syscore_ops); + + return 0; } #else static int __init cmx2xx_pm_init(void) { return 0; } diff --git a/arch/arm/mach-pxa/colibri-evalboard.c b/arch/arm/mach-pxa/colibri-evalboard.c index 81c3c43..d28e802 100644 --- a/arch/arm/mach-pxa/colibri-evalboard.c +++ b/arch/arm/mach-pxa/colibri-evalboard.c @@ -13,7 +13,6 @@ #include #include #include -#include #include #include #include diff --git a/arch/arm/mach-pxa/colibri-pxa270-income.c b/arch/arm/mach-pxa/colibri-pxa270-income.c index 44c1b77..80538b8 100644 --- a/arch/arm/mach-pxa/colibri-pxa270-income.c +++ b/arch/arm/mach-pxa/colibri-pxa270-income.c @@ -22,7 +22,6 @@ #include #include #include -#include #include #include diff --git a/arch/arm/mach-pxa/colibri-pxa270.c b/arch/arm/mach-pxa/colibri-pxa270.c index 6fc5d32..7545a48 100644 --- a/arch/arm/mach-pxa/colibri-pxa270.c +++ b/arch/arm/mach-pxa/colibri-pxa270.c @@ -17,7 +17,6 @@ #include #include #include -#include #include #include diff --git a/arch/arm/mach-pxa/generic.h b/arch/arm/mach-pxa/generic.h index a079d8b..e6c9344 100644 --- a/arch/arm/mach-pxa/generic.h +++ b/arch/arm/mach-pxa/generic.h @@ -61,10 +61,10 @@ extern unsigned pxa3xx_get_clk_frequency_khz(int); #define pxa3xx_get_clk_frequency_khz(x) (0) #endif -extern struct sysdev_class pxa_irq_sysclass; -extern struct sysdev_class pxa_gpio_sysclass; -extern struct sysdev_class pxa2xx_mfp_sysclass; -extern struct sysdev_class pxa3xx_mfp_sysclass; +extern struct syscore_ops pxa_irq_syscore_ops; +extern struct syscore_ops pxa_gpio_syscore_ops; +extern struct syscore_ops pxa2xx_mfp_syscore_ops; +extern struct syscore_ops pxa3xx_mfp_syscore_ops; void __init pxa_set_ffuart_info(void *info); void __init pxa_set_btuart_info(void *info); diff --git a/arch/arm/mach-pxa/irq.c b/arch/arm/mach-pxa/irq.c index 6251e3f..32ed551 100644 --- a/arch/arm/mach-pxa/irq.c +++ b/arch/arm/mach-pxa/irq.c @@ -15,7 +15,7 @@ #include #include #include -#include +#include #include #include @@ -183,7 +183,7 @@ void __init pxa_init_irq(int irq_nr, set_wake_t fn) static unsigned long saved_icmr[MAX_INTERNAL_IRQS/32]; static unsigned long saved_ipr[MAX_INTERNAL_IRQS]; -static int pxa_irq_suspend(struct sys_device *dev, pm_message_t state) +static int pxa_irq_suspend(void) { int i; @@ -202,7 +202,7 @@ static int pxa_irq_suspend(struct sys_device *dev, pm_message_t state) return 0; } -static int pxa_irq_resume(struct sys_device *dev) +static void pxa_irq_resume(void) { int i; @@ -218,22 +218,13 @@ static int pxa_irq_resume(struct sys_device *dev) __raw_writel(saved_ipr[i], IRQ_BASE + IPR(i)); __raw_writel(1, IRQ_BASE + ICCR); - return 0; } #else #define pxa_irq_suspend NULL #define pxa_irq_resume NULL #endif -struct sysdev_class pxa_irq_sysclass = { - .name = "irq", +struct syscore_ops pxa_irq_syscore_ops = { .suspend = pxa_irq_suspend, .resume = pxa_irq_resume, }; - -static int __init pxa_irq_init(void) -{ - return sysdev_class_register(&pxa_irq_sysclass); -} - -core_initcall(pxa_irq_init); diff --git a/arch/arm/mach-pxa/lpd270.c b/arch/arm/mach-pxa/lpd270.c index f5de541..6cf8180 100644 --- a/arch/arm/mach-pxa/lpd270.c +++ b/arch/arm/mach-pxa/lpd270.c @@ -15,7 +15,7 @@ #include #include -#include +#include #include #include #include @@ -159,30 +159,22 @@ static void __init lpd270_init_irq(void) #ifdef CONFIG_PM -static int lpd270_irq_resume(struct sys_device *dev) +static void lpd270_irq_resume(void) { __raw_writew(lpd270_irq_enabled, LPD270_INT_MASK); - return 0; } -static struct sysdev_class lpd270_irq_sysclass = { - .name = "cpld_irq", +static struct syscore_ops lpd270_irq_syscore_ops = { .resume = lpd270_irq_resume, }; -static struct sys_device lpd270_irq_device = { - .cls = &lpd270_irq_sysclass, -}; - static int __init lpd270_irq_device_init(void) { - int ret = -ENODEV; if (machine_is_logicpd_pxa270()) { - ret = sysdev_class_register(&lpd270_irq_sysclass); - if (ret == 0) - ret = sysdev_register(&lpd270_irq_device); + register_syscore_ops(&lpd270_irq_syscore_ops); + return 0; } - return ret; + return -ENODEV; } device_initcall(lpd270_irq_device_init); diff --git a/arch/arm/mach-pxa/lubbock.c b/arch/arm/mach-pxa/lubbock.c index 3ede978..e10ddb8 100644 --- a/arch/arm/mach-pxa/lubbock.c +++ b/arch/arm/mach-pxa/lubbock.c @@ -15,7 +15,7 @@ #include #include #include -#include +#include #include #include #include @@ -176,31 +176,22 @@ static void __init lubbock_init_irq(void) #ifdef CONFIG_PM -static int lubbock_irq_resume(struct sys_device *dev) +static void lubbock_irq_resume(void) { LUB_IRQ_MASK_EN = lubbock_irq_enabled; - return 0; } -static struct sysdev_class lubbock_irq_sysclass = { - .name = "cpld_irq", +static struct syscore_ops lubbock_irq_syscore_ops = { .resume = lubbock_irq_resume, }; -static struct sys_device lubbock_irq_device = { - .cls = &lubbock_irq_sysclass, -}; - static int __init lubbock_irq_device_init(void) { - int ret = -ENODEV; - if (machine_is_lubbock()) { - ret = sysdev_class_register(&lubbock_irq_sysclass); - if (ret == 0) - ret = sysdev_register(&lubbock_irq_device); + register_syscore_ops(&lubbock_irq_syscore_ops); + return 0; } - return ret; + return -ENODEV; } device_initcall(lubbock_irq_device_init); diff --git a/arch/arm/mach-pxa/mainstone.c b/arch/arm/mach-pxa/mainstone.c index 95163ba..3479e2b 100644 --- a/arch/arm/mach-pxa/mainstone.c +++ b/arch/arm/mach-pxa/mainstone.c @@ -15,7 +15,7 @@ #include #include -#include +#include #include #include #include @@ -185,31 +185,21 @@ static void __init mainstone_init_irq(void) #ifdef CONFIG_PM -static int mainstone_irq_resume(struct sys_device *dev) +static void mainstone_irq_resume(void) { MST_INTMSKENA = mainstone_irq_enabled; - return 0; } -static struct sysdev_class mainstone_irq_sysclass = { - .name = "cpld_irq", +static struct syscore_ops mainstone_irq_syscore_ops = { .resume = mainstone_irq_resume, }; -static struct sys_device mainstone_irq_device = { - .cls = &mainstone_irq_sysclass, -}; - static int __init mainstone_irq_device_init(void) { - int ret = -ENODEV; + if (machine_is_mainstone()) + register_syscore_ops(&mainstone_irq_syscore_ops); - if (machine_is_mainstone()) { - ret = sysdev_class_register(&mainstone_irq_sysclass); - if (ret == 0) - ret = sysdev_register(&mainstone_irq_device); - } - return ret; + return 0; } device_initcall(mainstone_irq_device_init); diff --git a/arch/arm/mach-pxa/mfp-pxa2xx.c b/arch/arm/mach-pxa/mfp-pxa2xx.c index 1d1419b..87ae312 100644 --- a/arch/arm/mach-pxa/mfp-pxa2xx.c +++ b/arch/arm/mach-pxa/mfp-pxa2xx.c @@ -16,7 +16,7 @@ #include #include #include -#include +#include #include #include @@ -338,7 +338,7 @@ static unsigned long saved_gafr[2][4]; static unsigned long saved_gpdr[4]; static unsigned long saved_pgsr[4]; -static int pxa2xx_mfp_suspend(struct sys_device *d, pm_message_t state) +static int pxa2xx_mfp_suspend(void) { int i; @@ -365,7 +365,7 @@ static int pxa2xx_mfp_suspend(struct sys_device *d, pm_message_t state) return 0; } -static int pxa2xx_mfp_resume(struct sys_device *d) +static void pxa2xx_mfp_resume(void) { int i; @@ -376,15 +376,13 @@ static int pxa2xx_mfp_resume(struct sys_device *d) PGSR(i) = saved_pgsr[i]; } PSSR = PSSR_RDH | PSSR_PH; - return 0; } #else #define pxa2xx_mfp_suspend NULL #define pxa2xx_mfp_resume NULL #endif -struct sysdev_class pxa2xx_mfp_sysclass = { - .name = "mfp", +struct syscore_ops pxa2xx_mfp_syscore_ops = { .suspend = pxa2xx_mfp_suspend, .resume = pxa2xx_mfp_resume, }; @@ -409,6 +407,6 @@ static int __init pxa2xx_mfp_init(void) for (i = 0; i <= gpio_to_bank(pxa_last_gpio); i++) gpdr_lpm[i] = GPDR(i * 32); - return sysdev_class_register(&pxa2xx_mfp_sysclass); + return 0; } postcore_initcall(pxa2xx_mfp_init); diff --git a/arch/arm/mach-pxa/mfp-pxa3xx.c b/arch/arm/mach-pxa/mfp-pxa3xx.c index 7a270ee..89863a0 100644 --- a/arch/arm/mach-pxa/mfp-pxa3xx.c +++ b/arch/arm/mach-pxa/mfp-pxa3xx.c @@ -17,7 +17,7 @@ #include #include #include -#include +#include #include #include @@ -31,13 +31,13 @@ * a pull-down mode if they're an active low chip select, and we're * just entering standby. */ -static int pxa3xx_mfp_suspend(struct sys_device *d, pm_message_t state) +static int pxa3xx_mfp_suspend(void) { mfp_config_lpm(); return 0; } -static int pxa3xx_mfp_resume(struct sys_device *d) +static void pxa3xx_mfp_resume(void) { mfp_config_run(); @@ -47,24 +47,13 @@ static int pxa3xx_mfp_resume(struct sys_device *d) * preserve them here in case they will be referenced later */ ASCR &= ~(ASCR_RDH | ASCR_D1S | ASCR_D2S | ASCR_D3S); - return 0; } #else #define pxa3xx_mfp_suspend NULL #define pxa3xx_mfp_resume NULL #endif -struct sysdev_class pxa3xx_mfp_sysclass = { - .name = "mfp", +struct syscore_ops pxa3xx_mfp_syscore_ops = { .suspend = pxa3xx_mfp_suspend, - .resume = pxa3xx_mfp_resume, + .resume = pxa3xx_mfp_resume, }; - -static int __init mfp_init_devicefs(void) -{ - if (cpu_is_pxa3xx()) - return sysdev_class_register(&pxa3xx_mfp_sysclass); - - return 0; -} -postcore_initcall(mfp_init_devicefs); diff --git a/arch/arm/mach-pxa/mioa701.c b/arch/arm/mach-pxa/mioa701.c index 23925db..e347013 100644 --- a/arch/arm/mach-pxa/mioa701.c +++ b/arch/arm/mach-pxa/mioa701.c @@ -22,7 +22,7 @@ #include #include #include -#include +#include #include #include #include @@ -488,7 +488,7 @@ static void install_bootstrap(void) } -static int mioa701_sys_suspend(struct sys_device *sysdev, pm_message_t state) +static int mioa701_sys_suspend(void) { int i = 0, is_bt_on; u32 *mem_resume_vector = phys_to_virt(RESUME_VECTOR_ADDR); @@ -514,7 +514,7 @@ static int mioa701_sys_suspend(struct sys_device *sysdev, pm_message_t state) return 0; } -static int mioa701_sys_resume(struct sys_device *sysdev) +static void mioa701_sys_resume(void) { int i = 0; u32 *mem_resume_vector = phys_to_virt(RESUME_VECTOR_ADDR); @@ -527,43 +527,18 @@ static int mioa701_sys_resume(struct sys_device *sysdev) *mem_resume_enabler = save_buffer[i++]; *mem_resume_bt = save_buffer[i++]; *mem_resume_unknown = save_buffer[i++]; - - return 0; } -static struct sysdev_class mioa701_sysclass = { - .name = "mioa701", -}; - -static struct sys_device sysdev_bootstrap = { - .cls = &mioa701_sysclass, -}; - -static struct sysdev_driver driver_bootstrap = { - .suspend = &mioa701_sys_suspend, - .resume = &mioa701_sys_resume, +static struct syscore_ops mioa701_syscore_ops = { + .suspend = mioa701_sys_suspend, + .resume = mioa701_sys_resume, }; static int __init bootstrap_init(void) { - int rc; int save_size = mioa701_bootstrap_lg + (sizeof(u32) * 3); - rc = sysdev_class_register(&mioa701_sysclass); - if (rc) { - printk(KERN_ERR "Failed registering mioa701 sys class\n"); - return -ENODEV; - } - rc = sysdev_register(&sysdev_bootstrap); - if (rc) { - printk(KERN_ERR "Failed registering mioa701 sys device\n"); - return -ENODEV; - } - rc = sysdev_driver_register(&mioa701_sysclass, &driver_bootstrap); - if (rc) { - printk(KERN_ERR "Failed registering PMU sys driver\n"); - return -ENODEV; - } + register_syscore_ops(&mioa701_syscore_ops); save_buffer = kmalloc(save_size, GFP_KERNEL); if (!save_buffer) @@ -576,9 +551,7 @@ static int __init bootstrap_init(void) static void bootstrap_exit(void) { kfree(save_buffer); - sysdev_driver_unregister(&mioa701_sysclass, &driver_bootstrap); - sysdev_unregister(&sysdev_bootstrap); - sysdev_class_unregister(&mioa701_sysclass); + unregister_syscore_ops(&mioa701_syscore_ops); printk(KERN_CRIT "Unregistering mioa701 suspend will hang next" "resume !!!\n"); diff --git a/arch/arm/mach-pxa/palmld.c b/arch/arm/mach-pxa/palmld.c index a6f898c..4061ecd 100644 --- a/arch/arm/mach-pxa/palmld.c +++ b/arch/arm/mach-pxa/palmld.c @@ -24,7 +24,6 @@ #include #include #include -#include #include #include #include diff --git a/arch/arm/mach-pxa/palmtreo.c b/arch/arm/mach-pxa/palmtreo.c index 8aadad5..20d1b18 100644 --- a/arch/arm/mach-pxa/palmtreo.c +++ b/arch/arm/mach-pxa/palmtreo.c @@ -25,7 +25,6 @@ #include #include #include -#include #include #include diff --git a/arch/arm/mach-pxa/palmz72.c b/arch/arm/mach-pxa/palmz72.c index 3b8a4f3..65f24f0 100644 --- a/arch/arm/mach-pxa/palmz72.c +++ b/arch/arm/mach-pxa/palmz72.c @@ -19,7 +19,7 @@ */ #include -#include +#include #include #include #include @@ -233,9 +233,9 @@ static struct palmz72_resume_info palmz72_resume_info = { static unsigned long store_ptr; -/* sys_device for Palm Zire 72 PM */ +/* syscore_ops for Palm Zire 72 PM */ -static int palmz72_pm_suspend(struct sys_device *dev, pm_message_t msg) +static int palmz72_pm_suspend(void) { /* setup the resume_info struct for the original bootloader */ palmz72_resume_info.resume_addr = (u32) cpu_resume; @@ -249,31 +249,23 @@ static int palmz72_pm_suspend(struct sys_device *dev, pm_message_t msg) return 0; } -static int palmz72_pm_resume(struct sys_device *dev) +static void palmz72_pm_resume(void) { *PALMZ72_SAVE_DWORD = store_ptr; - return 0; } -static struct sysdev_class palmz72_pm_sysclass = { - .name = "palmz72_pm", +static struct syscore_ops palmz72_pm_syscore_ops = { .suspend = palmz72_pm_suspend, .resume = palmz72_pm_resume, }; -static struct sys_device palmz72_pm_device = { - .cls = &palmz72_pm_sysclass, -}; - static int __init palmz72_pm_init(void) { - int ret = -ENODEV; if (machine_is_palmz72()) { - ret = sysdev_class_register(&palmz72_pm_sysclass); - if (ret == 0) - ret = sysdev_register(&palmz72_pm_device); + register_syscore_ops(&palmz72_pm_syscore_ops); + return 0; } - return ret; + return -ENODEV; } device_initcall(palmz72_pm_init); diff --git a/arch/arm/mach-pxa/pxa25x.c b/arch/arm/mach-pxa/pxa25x.c index a4af8c5..fed363c 100644 --- a/arch/arm/mach-pxa/pxa25x.c +++ b/arch/arm/mach-pxa/pxa25x.c @@ -21,7 +21,7 @@ #include #include #include -#include +#include #include #include @@ -350,21 +350,9 @@ static struct platform_device *pxa25x_devices[] __initdata = { &pxa_device_asoc_platform, }; -static struct sys_device pxa25x_sysdev[] = { - { - .cls = &pxa_irq_sysclass, - }, { - .cls = &pxa2xx_mfp_sysclass, - }, { - .cls = &pxa_gpio_sysclass, - }, { - .cls = &pxa2xx_clock_sysclass, - } -}; - static int __init pxa25x_init(void) { - int i, ret = 0; + int ret = 0; if (cpu_is_pxa25x()) { @@ -377,11 +365,10 @@ static int __init pxa25x_init(void) pxa25x_init_pm(); - for (i = 0; i < ARRAY_SIZE(pxa25x_sysdev); i++) { - ret = sysdev_register(&pxa25x_sysdev[i]); - if (ret) - pr_err("failed to register sysdev[%d]\n", i); - } + register_syscore_ops(&pxa_irq_syscore_ops); + register_syscore_ops(&pxa2xx_mfp_syscore_ops); + register_syscore_ops(&pxa_gpio_syscore_ops); + register_syscore_ops(&pxa2xx_clock_syscore_ops); ret = platform_add_devices(pxa25x_devices, ARRAY_SIZE(pxa25x_devices)); diff --git a/arch/arm/mach-pxa/pxa27x.c b/arch/arm/mach-pxa/pxa27x.c index 909756e..2fecbec 100644 --- a/arch/arm/mach-pxa/pxa27x.c +++ b/arch/arm/mach-pxa/pxa27x.c @@ -16,7 +16,7 @@ #include #include #include -#include +#include #include #include #include @@ -428,21 +428,9 @@ static struct platform_device *devices[] __initdata = { &pxa27x_device_pwm1, }; -static struct sys_device pxa27x_sysdev[] = { - { - .cls = &pxa_irq_sysclass, - }, { - .cls = &pxa2xx_mfp_sysclass, - }, { - .cls = &pxa_gpio_sysclass, - }, { - .cls = &pxa2xx_clock_sysclass, - } -}; - static int __init pxa27x_init(void) { - int i, ret = 0; + int ret = 0; if (cpu_is_pxa27x()) { @@ -455,11 +443,10 @@ static int __init pxa27x_init(void) pxa27x_init_pm(); - for (i = 0; i < ARRAY_SIZE(pxa27x_sysdev); i++) { - ret = sysdev_register(&pxa27x_sysdev[i]); - if (ret) - pr_err("failed to register sysdev[%d]\n", i); - } + register_syscore_ops(&pxa_irq_syscore_ops); + register_syscore_ops(&pxa2xx_mfp_syscore_ops); + register_syscore_ops(&pxa_gpio_syscore_ops); + register_syscore_ops(&pxa2xx_clock_syscore_ops); ret = platform_add_devices(devices, ARRAY_SIZE(devices)); } diff --git a/arch/arm/mach-pxa/pxa3xx.c b/arch/arm/mach-pxa/pxa3xx.c index 8dd1073..8521d7d 100644 --- a/arch/arm/mach-pxa/pxa3xx.c +++ b/arch/arm/mach-pxa/pxa3xx.c @@ -20,7 +20,7 @@ #include #include #include -#include +#include #include #include @@ -427,21 +427,9 @@ static struct platform_device *devices[] __initdata = { &pxa27x_device_pwm1, }; -static struct sys_device pxa3xx_sysdev[] = { - { - .cls = &pxa_irq_sysclass, - }, { - .cls = &pxa3xx_mfp_sysclass, - }, { - .cls = &pxa_gpio_sysclass, - }, { - .cls = &pxa3xx_clock_sysclass, - } -}; - static int __init pxa3xx_init(void) { - int i, ret = 0; + int ret = 0; if (cpu_is_pxa3xx()) { @@ -462,11 +450,10 @@ static int __init pxa3xx_init(void) pxa3xx_init_pm(); - for (i = 0; i < ARRAY_SIZE(pxa3xx_sysdev); i++) { - ret = sysdev_register(&pxa3xx_sysdev[i]); - if (ret) - pr_err("failed to register sysdev[%d]\n", i); - } + register_syscore_ops(&pxa_irq_syscore_ops); + register_syscore_ops(&pxa3xx_mfp_syscore_ops); + register_syscore_ops(&pxa_gpio_syscore_ops); + register_syscore_ops(&pxa3xx_clock_syscore_ops); ret = platform_add_devices(devices, ARRAY_SIZE(devices)); } diff --git a/arch/arm/mach-pxa/pxa95x.c b/arch/arm/mach-pxa/pxa95x.c index 23b229b..ecc82a3 100644 --- a/arch/arm/mach-pxa/pxa95x.c +++ b/arch/arm/mach-pxa/pxa95x.c @@ -18,7 +18,7 @@ #include #include #include -#include +#include #include #include @@ -260,16 +260,6 @@ static struct platform_device *devices[] __initdata = { &pxa27x_device_pwm1, }; -static struct sys_device pxa95x_sysdev[] = { - { - .cls = &pxa_irq_sysclass, - }, { - .cls = &pxa_gpio_sysclass, - }, { - .cls = &pxa3xx_clock_sysclass, - } -}; - static int __init pxa95x_init(void) { int ret = 0, i; @@ -293,11 +283,9 @@ static int __init pxa95x_init(void) if ((ret = pxa_init_dma(IRQ_DMA, 32))) return ret; - for (i = 0; i < ARRAY_SIZE(pxa95x_sysdev); i++) { - ret = sysdev_register(&pxa95x_sysdev[i]); - if (ret) - pr_err("failed to register sysdev[%d]\n", i); - } + register_syscore_ops(&pxa_irq_syscore_ops); + register_syscore_ops(&pxa_gpio_syscore_ops); + register_syscore_ops(&pxa3xx_clock_syscore_ops); ret = platform_add_devices(devices, ARRAY_SIZE(devices)); } diff --git a/arch/arm/mach-pxa/raumfeld.c b/arch/arm/mach-pxa/raumfeld.c index cd18613..d130f77 100644 --- a/arch/arm/mach-pxa/raumfeld.c +++ b/arch/arm/mach-pxa/raumfeld.c @@ -18,7 +18,6 @@ #include #include -#include #include #include #include diff --git a/arch/arm/mach-pxa/smemc.c b/arch/arm/mach-pxa/smemc.c index 232b731..7992305 100644 --- a/arch/arm/mach-pxa/smemc.c +++ b/arch/arm/mach-pxa/smemc.c @@ -6,7 +6,7 @@ #include #include #include -#include +#include #include #include @@ -16,7 +16,7 @@ static unsigned long msc[2]; static unsigned long sxcnfg, memclkcfg; static unsigned long csadrcfg[4]; -static int pxa3xx_smemc_suspend(struct sys_device *dev, pm_message_t state) +static int pxa3xx_smemc_suspend(void) { msc[0] = __raw_readl(MSC0); msc[1] = __raw_readl(MSC1); @@ -30,7 +30,7 @@ static int pxa3xx_smemc_suspend(struct sys_device *dev, pm_message_t state) return 0; } -static int pxa3xx_smemc_resume(struct sys_device *dev) +static void pxa3xx_smemc_resume(void) { __raw_writel(msc[0], MSC0); __raw_writel(msc[1], MSC1); @@ -40,34 +40,19 @@ static int pxa3xx_smemc_resume(struct sys_device *dev) __raw_writel(csadrcfg[1], CSADRCFG1); __raw_writel(csadrcfg[2], CSADRCFG2); __raw_writel(csadrcfg[3], CSADRCFG3); - - return 0; } -static struct sysdev_class smemc_sysclass = { - .name = "smemc", +static struct syscore_ops smemc_syscore_ops = { .suspend = pxa3xx_smemc_suspend, .resume = pxa3xx_smemc_resume, }; -static struct sys_device smemc_sysdev = { - .id = 0, - .cls = &smemc_sysclass, -}; - static int __init smemc_init(void) { - int ret = 0; + if (cpu_is_pxa3xx()) + register_syscore_ops(&smemc_syscore_ops); - if (cpu_is_pxa3xx()) { - ret = sysdev_class_register(&smemc_sysclass); - if (ret) - return ret; - - ret = sysdev_register(&smemc_sysdev); - } - - return ret; + return 0; } subsys_initcall(smemc_init); #endif diff --git a/arch/arm/mach-pxa/trizeps4.c b/arch/arm/mach-pxa/trizeps4.c index b9cfbeb..687417a 100644 --- a/arch/arm/mach-pxa/trizeps4.c +++ b/arch/arm/mach-pxa/trizeps4.c @@ -15,7 +15,6 @@ #include #include #include -#include #include #include #include diff --git a/arch/arm/mach-pxa/viper.c b/arch/arm/mach-pxa/viper.c index b523f11..903218e 100644 --- a/arch/arm/mach-pxa/viper.c +++ b/arch/arm/mach-pxa/viper.c @@ -44,6 +44,7 @@ #include #include #include +#include #include #include @@ -130,20 +131,19 @@ static u8 viper_hw_version(void) return v1; } -/* CPU sysdev */ -static int viper_cpu_suspend(struct sys_device *sysdev, pm_message_t state) +/* CPU system core operations. */ +static int viper_cpu_suspend(void) { viper_icr_set_bit(VIPER_ICR_R_DIS); return 0; } -static int viper_cpu_resume(struct sys_device *sysdev) +static void viper_cpu_resume(void) { viper_icr_clear_bit(VIPER_ICR_R_DIS); - return 0; } -static struct sysdev_driver viper_cpu_sysdev_driver = { +static struct syscore_ops viper_cpu_syscore_ops = { .suspend = viper_cpu_suspend, .resume = viper_cpu_resume, }; @@ -945,7 +945,7 @@ static void __init viper_init(void) viper_init_vcore_gpios(); viper_init_cpufreq(); - sysdev_driver_register(&cpu_sysdev_class, &viper_cpu_sysdev_driver); + register_syscore_ops(&viper_cpu_syscore_ops); if (version) { pr_info("viper: hardware v%di%d detected. " diff --git a/arch/arm/mach-pxa/vpac270.c b/arch/arm/mach-pxa/vpac270.c index f71d377..67bd414 100644 --- a/arch/arm/mach-pxa/vpac270.c +++ b/arch/arm/mach-pxa/vpac270.c @@ -16,7 +16,6 @@ #include #include #include -#include #include #include #include diff --git a/arch/arm/plat-pxa/gpio.c b/arch/arm/plat-pxa/gpio.c index dce088f..48ebb94 100644 --- a/arch/arm/plat-pxa/gpio.c +++ b/arch/arm/plat-pxa/gpio.c @@ -15,7 +15,7 @@ #include #include #include -#include +#include #include #include @@ -295,7 +295,7 @@ void __init pxa_init_gpio(int mux_irq, int start, int end, set_wake_t fn) } #ifdef CONFIG_PM -static int pxa_gpio_suspend(struct sys_device *dev, pm_message_t state) +static int pxa_gpio_suspend(void) { struct pxa_gpio_chip *c; int gpio; @@ -312,7 +312,7 @@ static int pxa_gpio_suspend(struct sys_device *dev, pm_message_t state) return 0; } -static int pxa_gpio_resume(struct sys_device *dev) +static void pxa_gpio_resume(void) { struct pxa_gpio_chip *c; int gpio; @@ -326,22 +326,13 @@ static int pxa_gpio_resume(struct sys_device *dev) __raw_writel(c->saved_gfer, c->regbase + GFER_OFFSET); __raw_writel(c->saved_gpdr, c->regbase + GPDR_OFFSET); } - return 0; } #else #define pxa_gpio_suspend NULL #define pxa_gpio_resume NULL #endif -struct sysdev_class pxa_gpio_sysclass = { - .name = "gpio", +struct syscore_ops pxa_gpio_syscore_ops = { .suspend = pxa_gpio_suspend, .resume = pxa_gpio_resume, }; - -static int __init pxa_gpio_init(void) -{ - return sysdev_class_register(&pxa_gpio_sysclass); -} - -core_initcall(pxa_gpio_init); diff --git a/arch/arm/plat-pxa/mfp.c b/arch/arm/plat-pxa/mfp.c index a9aa5ad..be12ead 100644 --- a/arch/arm/plat-pxa/mfp.c +++ b/arch/arm/plat-pxa/mfp.c @@ -17,7 +17,6 @@ #include #include #include -#include #include -- cgit v0.10.2 From bb072c3cf21d1c9a5a2eeb5a00679ee7bf39675b Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Fri, 22 Apr 2011 22:03:21 +0200 Subject: ARM / Samsung: Use struct syscore_ops for "core" power management Replace sysdev classes and struct sys_device objects used for "core" power management by Samsung platforms with struct syscore_ops objects that are simpler. This generally reduces the code size and the kernel memory footprint. It also is necessary for removing sysdevs entirely from the kernel in the future. Signed-off-by: Rafael J. Wysocki Acked-by: Greg Kroah-Hartman Acked-by: Kukjin Kim diff --git a/arch/arm/mach-exynos4/pm.c b/arch/arm/mach-exynos4/pm.c index 10d917d..8755ca8 100644 --- a/arch/arm/mach-exynos4/pm.c +++ b/arch/arm/mach-exynos4/pm.c @@ -16,6 +16,7 @@ #include #include +#include #include #include @@ -372,7 +373,27 @@ void exynos4_scu_enable(void __iomem *scu_base) flush_cache_all(); } -static int exynos4_pm_resume(struct sys_device *dev) +static struct sysdev_driver exynos4_pm_driver = { + .add = exynos4_pm_add, +}; + +static __init int exynos4_pm_drvinit(void) +{ + unsigned int tmp; + + s3c_pm_init(); + + /* All wakeup disable */ + + tmp = __raw_readl(S5P_WAKEUP_MASK); + tmp |= ((0xFF << 8) | (0x1F << 1)); + __raw_writel(tmp, S5P_WAKEUP_MASK); + + return sysdev_driver_register(&exynos4_sysclass, &exynos4_pm_driver); +} +arch_initcall(exynos4_pm_drvinit); + +static void exynos4_pm_resume(void) { /* For release retention */ @@ -394,27 +415,15 @@ static int exynos4_pm_resume(struct sys_device *dev) /* enable L2X0*/ writel_relaxed(1, S5P_VA_L2CC + L2X0_CTRL); #endif - - return 0; } -static struct sysdev_driver exynos4_pm_driver = { - .add = exynos4_pm_add, +static struct syscore_ops exynos4_pm_syscore_ops = { .resume = exynos4_pm_resume, }; -static __init int exynos4_pm_drvinit(void) +static __init int exynos4_pm_syscore_init(void) { - unsigned int tmp; - - s3c_pm_init(); - - /* All wakeup disable */ - - tmp = __raw_readl(S5P_WAKEUP_MASK); - tmp |= ((0xFF << 8) | (0x1F << 1)); - __raw_writel(tmp, S5P_WAKEUP_MASK); - - return sysdev_driver_register(&exynos4_sysclass, &exynos4_pm_driver); + register_syscore_ops(&exynos4_pm_syscore_ops); + return 0; } -arch_initcall(exynos4_pm_drvinit); +arch_initcall(exynos4_pm_syscore_init); diff --git a/arch/arm/mach-s3c2410/irq.c b/arch/arm/mach-s3c2410/irq.c index 5e2f353..2854129 100644 --- a/arch/arm/mach-s3c2410/irq.c +++ b/arch/arm/mach-s3c2410/irq.c @@ -23,38 +23,12 @@ #include #include #include -#include +#include #include #include -static int s3c2410_irq_add(struct sys_device *sysdev) -{ - return 0; -} - -static struct sysdev_driver s3c2410_irq_driver = { - .add = s3c2410_irq_add, +struct syscore_ops s3c24xx_irq_syscore_ops = { .suspend = s3c24xx_irq_suspend, .resume = s3c24xx_irq_resume, }; - -static int __init s3c2410_irq_init(void) -{ - return sysdev_driver_register(&s3c2410_sysclass, &s3c2410_irq_driver); -} - -arch_initcall(s3c2410_irq_init); - -static struct sysdev_driver s3c2410a_irq_driver = { - .add = s3c2410_irq_add, - .suspend = s3c24xx_irq_suspend, - .resume = s3c24xx_irq_resume, -}; - -static int __init s3c2410a_irq_init(void) -{ - return sysdev_driver_register(&s3c2410a_sysclass, &s3c2410a_irq_driver); -} - -arch_initcall(s3c2410a_irq_init); diff --git a/arch/arm/mach-s3c2410/mach-bast.c b/arch/arm/mach-s3c2410/mach-bast.c index 2970ea9..1e2d536 100644 --- a/arch/arm/mach-s3c2410/mach-bast.c +++ b/arch/arm/mach-s3c2410/mach-bast.c @@ -17,7 +17,7 @@ #include #include #include -#include +#include #include #include #include @@ -214,17 +214,16 @@ static struct s3c2410_uartcfg bast_uartcfgs[] __initdata = { /* NAND Flash on BAST board */ #ifdef CONFIG_PM -static int bast_pm_suspend(struct sys_device *sd, pm_message_t state) +static int bast_pm_suspend(void) { /* ensure that an nRESET is not generated on resume. */ gpio_direction_output(S3C2410_GPA(21), 1); return 0; } -static int bast_pm_resume(struct sys_device *sd) +static void bast_pm_resume(void) { s3c_gpio_cfgpin(S3C2410_GPA(21), S3C2410_GPA21_nRSTOUT); - return 0; } #else @@ -232,16 +231,11 @@ static int bast_pm_resume(struct sys_device *sd) #define bast_pm_resume NULL #endif -static struct sysdev_class bast_pm_sysclass = { - .name = "mach-bast", +static struct syscore_ops bast_pm_syscore_ops = { .suspend = bast_pm_suspend, .resume = bast_pm_resume, }; -static struct sys_device bast_pm_sysdev = { - .cls = &bast_pm_sysclass, -}; - static int smartmedia_map[] = { 0 }; static int chip0_map[] = { 1 }; static int chip1_map[] = { 2 }; @@ -642,8 +636,7 @@ static void __init bast_map_io(void) static void __init bast_init(void) { - sysdev_class_register(&bast_pm_sysclass); - sysdev_register(&bast_pm_sysdev); + register_syscore_ops(&bast_pm_syscore_ops); s3c_i2c0_set_platdata(&bast_i2c_info); s3c_nand_set_platdata(&bast_nand_info); diff --git a/arch/arm/mach-s3c2410/pm.c b/arch/arm/mach-s3c2410/pm.c index 725636f..4728f9a 100644 --- a/arch/arm/mach-s3c2410/pm.c +++ b/arch/arm/mach-s3c2410/pm.c @@ -25,6 +25,7 @@ #include #include #include +#include #include #include @@ -92,7 +93,7 @@ static void s3c2410_pm_prepare(void) } } -static int s3c2410_pm_resume(struct sys_device *dev) +static void s3c2410_pm_resume(void) { unsigned long tmp; @@ -104,10 +105,12 @@ static int s3c2410_pm_resume(struct sys_device *dev) if ( machine_is_aml_m5900() ) s3c2410_gpio_setpin(S3C2410_GPF(2), 0); - - return 0; } +struct syscore_ops s3c2410_pm_syscore_ops = { + .resume = s3c2410_pm_resume, +}; + static int s3c2410_pm_add(struct sys_device *dev) { pm_cpu_prep = s3c2410_pm_prepare; @@ -119,7 +122,6 @@ static int s3c2410_pm_add(struct sys_device *dev) #if defined(CONFIG_CPU_S3C2410) static struct sysdev_driver s3c2410_pm_driver = { .add = s3c2410_pm_add, - .resume = s3c2410_pm_resume, }; /* register ourselves */ @@ -133,7 +135,6 @@ arch_initcall(s3c2410_pm_drvinit); static struct sysdev_driver s3c2410a_pm_driver = { .add = s3c2410_pm_add, - .resume = s3c2410_pm_resume, }; static int __init s3c2410a_pm_drvinit(void) @@ -147,7 +148,6 @@ arch_initcall(s3c2410a_pm_drvinit); #if defined(CONFIG_CPU_S3C2440) static struct sysdev_driver s3c2440_pm_driver = { .add = s3c2410_pm_add, - .resume = s3c2410_pm_resume, }; static int __init s3c2440_pm_drvinit(void) @@ -161,7 +161,6 @@ arch_initcall(s3c2440_pm_drvinit); #if defined(CONFIG_CPU_S3C2442) static struct sysdev_driver s3c2442_pm_driver = { .add = s3c2410_pm_add, - .resume = s3c2410_pm_resume, }; static int __init s3c2442_pm_drvinit(void) diff --git a/arch/arm/mach-s3c2410/s3c2410.c b/arch/arm/mach-s3c2410/s3c2410.c index adc90a3..f1d3bd8 100644 --- a/arch/arm/mach-s3c2410/s3c2410.c +++ b/arch/arm/mach-s3c2410/s3c2410.c @@ -19,6 +19,7 @@ #include #include #include +#include #include #include #include @@ -40,6 +41,7 @@ #include #include #include +#include #include #include @@ -168,6 +170,9 @@ int __init s3c2410_init(void) { printk("S3C2410: Initialising architecture\n"); + register_syscore_ops(&s3c2410_pm_syscore_ops); + register_syscore_ops(&s3c24xx_irq_syscore_ops); + return sysdev_register(&s3c2410_sysdev); } diff --git a/arch/arm/mach-s3c2412/irq.c b/arch/arm/mach-s3c2412/irq.c index f3355d2..1a1aa22 100644 --- a/arch/arm/mach-s3c2412/irq.c +++ b/arch/arm/mach-s3c2412/irq.c @@ -202,8 +202,6 @@ static int s3c2412_irq_add(struct sys_device *sysdev) static struct sysdev_driver s3c2412_irq_driver = { .add = s3c2412_irq_add, - .suspend = s3c24xx_irq_suspend, - .resume = s3c24xx_irq_resume, }; static int s3c2412_irq_init(void) diff --git a/arch/arm/mach-s3c2412/mach-jive.c b/arch/arm/mach-s3c2412/mach-jive.c index 923e01b..85dcaeb 100644 --- a/arch/arm/mach-s3c2412/mach-jive.c +++ b/arch/arm/mach-s3c2412/mach-jive.c @@ -17,7 +17,7 @@ #include #include #include -#include +#include #include #include #include @@ -486,7 +486,7 @@ static struct s3c2410_udc_mach_info jive_udc_cfg __initdata = { /* Jive power management device */ #ifdef CONFIG_PM -static int jive_pm_suspend(struct sys_device *sd, pm_message_t state) +static int jive_pm_suspend(void) { /* Write the magic value u-boot uses to check for resume into * the INFORM0 register, and ensure INFORM1 is set to the @@ -498,10 +498,9 @@ static int jive_pm_suspend(struct sys_device *sd, pm_message_t state) return 0; } -static int jive_pm_resume(struct sys_device *sd) +static void jive_pm_resume(void) { __raw_writel(0x0, S3C2412_INFORM0); - return 0; } #else @@ -509,16 +508,11 @@ static int jive_pm_resume(struct sys_device *sd) #define jive_pm_resume NULL #endif -static struct sysdev_class jive_pm_sysclass = { - .name = "jive-pm", +static struct syscore_ops jive_pm_syscore_ops = { .suspend = jive_pm_suspend, .resume = jive_pm_resume, }; -static struct sys_device jive_pm_sysdev = { - .cls = &jive_pm_sysclass, -}; - static void __init jive_map_io(void) { s3c24xx_init_io(jive_iodesc, ARRAY_SIZE(jive_iodesc)); @@ -536,10 +530,9 @@ static void jive_power_off(void) static void __init jive_machine_init(void) { - /* register system devices for managing low level suspend */ + /* register system core operations for managing low level suspend */ - sysdev_class_register(&jive_pm_sysclass); - sysdev_register(&jive_pm_sysdev); + register_syscore_ops(&jive_pm_syscore_ops); /* write our sleep configurations for the IO. Pull down all unused * IO, ensure that we have turned off all peripherals we do not diff --git a/arch/arm/mach-s3c2412/pm.c b/arch/arm/mach-s3c2412/pm.c index a7417c4..752b13a 100644 --- a/arch/arm/mach-s3c2412/pm.c +++ b/arch/arm/mach-s3c2412/pm.c @@ -17,6 +17,7 @@ #include #include #include +#include #include #include @@ -86,13 +87,24 @@ static struct sleep_save s3c2412_sleep[] = { SAVE_ITEM(S3C2413_GPJSLPCON), }; -static int s3c2412_pm_suspend(struct sys_device *dev, pm_message_t state) +static struct sysdev_driver s3c2412_pm_driver = { + .add = s3c2412_pm_add, +}; + +static __init int s3c2412_pm_init(void) +{ + return sysdev_driver_register(&s3c2412_sysclass, &s3c2412_pm_driver); +} + +arch_initcall(s3c2412_pm_init); + +static int s3c2412_pm_suspend(void) { s3c_pm_do_save(s3c2412_sleep, ARRAY_SIZE(s3c2412_sleep)); return 0; } -static int s3c2412_pm_resume(struct sys_device *dev) +static void s3c2412_pm_resume(void) { unsigned long tmp; @@ -102,18 +114,9 @@ static int s3c2412_pm_resume(struct sys_device *dev) __raw_writel(tmp, S3C2412_PWRCFG); s3c_pm_do_restore(s3c2412_sleep, ARRAY_SIZE(s3c2412_sleep)); - return 0; } -static struct sysdev_driver s3c2412_pm_driver = { - .add = s3c2412_pm_add, +struct syscore_ops s3c2412_pm_syscore_ops = { .suspend = s3c2412_pm_suspend, .resume = s3c2412_pm_resume, }; - -static __init int s3c2412_pm_init(void) -{ - return sysdev_driver_register(&s3c2412_sysclass, &s3c2412_pm_driver); -} - -arch_initcall(s3c2412_pm_init); diff --git a/arch/arm/mach-s3c2412/s3c2412.c b/arch/arm/mach-s3c2412/s3c2412.c index 4c6df51..ef0958d 100644 --- a/arch/arm/mach-s3c2412/s3c2412.c +++ b/arch/arm/mach-s3c2412/s3c2412.c @@ -19,6 +19,7 @@ #include #include #include +#include #include #include #include @@ -244,5 +245,8 @@ int __init s3c2412_init(void) { printk("S3C2412: Initialising architecture\n"); + register_syscore_ops(&s3c2412_pm_syscore_ops); + register_syscore_ops(&s3c24xx_irq_syscore_ops); + return sysdev_register(&s3c2412_sysdev); } diff --git a/arch/arm/mach-s3c2416/irq.c b/arch/arm/mach-s3c2416/irq.c index 77b38f2..28ad20d 100644 --- a/arch/arm/mach-s3c2416/irq.c +++ b/arch/arm/mach-s3c2416/irq.c @@ -236,8 +236,6 @@ static int __init s3c2416_irq_add(struct sys_device *sysdev) static struct sysdev_driver s3c2416_irq_driver = { .add = s3c2416_irq_add, - .suspend = s3c24xx_irq_suspend, - .resume = s3c24xx_irq_resume, }; static int __init s3c2416_irq_init(void) diff --git a/arch/arm/mach-s3c2416/pm.c b/arch/arm/mach-s3c2416/pm.c index 4a04205..41db2b2 100644 --- a/arch/arm/mach-s3c2416/pm.c +++ b/arch/arm/mach-s3c2416/pm.c @@ -11,6 +11,7 @@ */ #include +#include #include #include @@ -55,30 +56,26 @@ static int s3c2416_pm_add(struct sys_device *sysdev) return 0; } -static int s3c2416_pm_suspend(struct sys_device *dev, pm_message_t state) +static struct sysdev_driver s3c2416_pm_driver = { + .add = s3c2416_pm_add, +}; + +static __init int s3c2416_pm_init(void) { - return 0; + return sysdev_driver_register(&s3c2416_sysclass, &s3c2416_pm_driver); } -static int s3c2416_pm_resume(struct sys_device *dev) +arch_initcall(s3c2416_pm_init); + + +static void s3c2416_pm_resume(void) { /* unset the return-from-sleep amd inform flags */ __raw_writel(0x0, S3C2443_PWRMODE); __raw_writel(0x0, S3C2412_INFORM0); __raw_writel(0x0, S3C2412_INFORM1); - - return 0; } -static struct sysdev_driver s3c2416_pm_driver = { - .add = s3c2416_pm_add, - .suspend = s3c2416_pm_suspend, +struct syscore_ops s3c2416_pm_syscore_ops = { .resume = s3c2416_pm_resume, }; - -static __init int s3c2416_pm_init(void) -{ - return sysdev_driver_register(&s3c2416_sysclass, &s3c2416_pm_driver); -} - -arch_initcall(s3c2416_pm_init); diff --git a/arch/arm/mach-s3c2416/s3c2416.c b/arch/arm/mach-s3c2416/s3c2416.c index ba7fd87..494ce91 100644 --- a/arch/arm/mach-s3c2416/s3c2416.c +++ b/arch/arm/mach-s3c2416/s3c2416.c @@ -32,6 +32,7 @@ #include #include #include +#include #include #include @@ -54,6 +55,7 @@ #include #include #include +#include #include #include @@ -95,6 +97,9 @@ int __init s3c2416_init(void) s3c_fb_setname("s3c2443-fb"); + register_syscore_ops(&s3c2416_pm_syscore_ops); + register_syscore_ops(&s3c24xx_irq_syscore_ops); + return sysdev_register(&s3c2416_sysdev); } diff --git a/arch/arm/mach-s3c2440/mach-osiris.c b/arch/arm/mach-s3c2440/mach-osiris.c index 14dc678..d885363 100644 --- a/arch/arm/mach-s3c2440/mach-osiris.c +++ b/arch/arm/mach-s3c2440/mach-osiris.c @@ -17,7 +17,7 @@ #include #include #include -#include +#include #include #include #include @@ -284,7 +284,7 @@ static struct platform_device osiris_pcmcia = { #ifdef CONFIG_PM static unsigned char pm_osiris_ctrl0; -static int osiris_pm_suspend(struct sys_device *sd, pm_message_t state) +static int osiris_pm_suspend(void) { unsigned int tmp; @@ -304,7 +304,7 @@ static int osiris_pm_suspend(struct sys_device *sd, pm_message_t state) return 0; } -static int osiris_pm_resume(struct sys_device *sd) +static void osiris_pm_resume(void) { if (pm_osiris_ctrl0 & OSIRIS_CTRL0_FIX8) __raw_writeb(OSIRIS_CTRL1_FIX8, OSIRIS_VA_CTRL1); @@ -312,8 +312,6 @@ static int osiris_pm_resume(struct sys_device *sd) __raw_writeb(pm_osiris_ctrl0, OSIRIS_VA_CTRL0); s3c_gpio_cfgpin(S3C2410_GPA(21), S3C2410_GPA21_nRSTOUT); - - return 0; } #else @@ -321,16 +319,11 @@ static int osiris_pm_resume(struct sys_device *sd) #define osiris_pm_resume NULL #endif -static struct sysdev_class osiris_pm_sysclass = { - .name = "mach-osiris", +static struct syscore_ops osiris_pm_syscore_ops = { .suspend = osiris_pm_suspend, .resume = osiris_pm_resume, }; -static struct sys_device osiris_pm_sysdev = { - .cls = &osiris_pm_sysclass, -}; - /* Link for DVS driver to TPS65011 */ static void osiris_tps_release(struct device *dev) @@ -439,8 +432,7 @@ static void __init osiris_map_io(void) static void __init osiris_init(void) { - sysdev_class_register(&osiris_pm_sysclass); - sysdev_register(&osiris_pm_sysdev); + register_syscore_ops(&osiris_pm_syscore_ops); s3c_i2c0_set_platdata(NULL); s3c_nand_set_platdata(&osiris_nand_info); diff --git a/arch/arm/mach-s3c2440/s3c2440.c b/arch/arm/mach-s3c2440/s3c2440.c index f7663f7..ce99ff7 100644 --- a/arch/arm/mach-s3c2440/s3c2440.c +++ b/arch/arm/mach-s3c2440/s3c2440.c @@ -19,6 +19,7 @@ #include #include #include +#include #include #include #include @@ -33,6 +34,7 @@ #include #include #include +#include #include #include @@ -51,6 +53,12 @@ int __init s3c2440_init(void) s3c_device_wdt.resource[1].start = IRQ_S3C2440_WDT; s3c_device_wdt.resource[1].end = IRQ_S3C2440_WDT; + /* register suspend/resume handlers */ + + register_syscore_ops(&s3c2410_pm_syscore_ops); + register_syscore_ops(&s3c244x_pm_syscore_ops); + register_syscore_ops(&s3c24xx_irq_syscore_ops); + /* register our system device for everything else */ return sysdev_register(&s3c2440_sysdev); diff --git a/arch/arm/mach-s3c2440/s3c2442.c b/arch/arm/mach-s3c2440/s3c2442.c index ecf8135..6224bad 100644 --- a/arch/arm/mach-s3c2440/s3c2442.c +++ b/arch/arm/mach-s3c2440/s3c2442.c @@ -29,6 +29,7 @@ #include #include #include +#include #include #include #include @@ -45,6 +46,7 @@ #include #include #include +#include #include #include @@ -167,6 +169,10 @@ int __init s3c2442_init(void) { printk("S3C2442: Initialising architecture\n"); + register_syscore_ops(&s3c2410_pm_syscore_ops); + register_syscore_ops(&s3c244x_pm_syscore_ops); + register_syscore_ops(&s3c24xx_irq_syscore_ops); + return sysdev_register(&s3c2442_sysdev); } diff --git a/arch/arm/mach-s3c2440/s3c244x-irq.c b/arch/arm/mach-s3c2440/s3c244x-irq.c index de07c2f..c63e8f2 100644 --- a/arch/arm/mach-s3c2440/s3c244x-irq.c +++ b/arch/arm/mach-s3c2440/s3c244x-irq.c @@ -116,8 +116,6 @@ static int s3c244x_irq_add(struct sys_device *sysdev) static struct sysdev_driver s3c2440_irq_driver = { .add = s3c244x_irq_add, - .suspend = s3c24xx_irq_suspend, - .resume = s3c24xx_irq_resume, }; static int s3c2440_irq_init(void) @@ -129,8 +127,6 @@ arch_initcall(s3c2440_irq_init); static struct sysdev_driver s3c2442_irq_driver = { .add = s3c244x_irq_add, - .suspend = s3c24xx_irq_suspend, - .resume = s3c24xx_irq_resume, }; diff --git a/arch/arm/mach-s3c2440/s3c244x.c b/arch/arm/mach-s3c2440/s3c244x.c index 90c1707..7e8a23d 100644 --- a/arch/arm/mach-s3c2440/s3c244x.c +++ b/arch/arm/mach-s3c2440/s3c244x.c @@ -19,6 +19,7 @@ #include #include #include +#include #include #include @@ -134,45 +135,14 @@ void __init s3c244x_init_clocks(int xtal) s3c2410_baseclk_add(); } -#ifdef CONFIG_PM - -static struct sleep_save s3c244x_sleep[] = { - SAVE_ITEM(S3C2440_DSC0), - SAVE_ITEM(S3C2440_DSC1), - SAVE_ITEM(S3C2440_GPJDAT), - SAVE_ITEM(S3C2440_GPJCON), - SAVE_ITEM(S3C2440_GPJUP) -}; - -static int s3c244x_suspend(struct sys_device *dev, pm_message_t state) -{ - s3c_pm_do_save(s3c244x_sleep, ARRAY_SIZE(s3c244x_sleep)); - return 0; -} - -static int s3c244x_resume(struct sys_device *dev) -{ - s3c_pm_do_restore(s3c244x_sleep, ARRAY_SIZE(s3c244x_sleep)); - return 0; -} - -#else -#define s3c244x_suspend NULL -#define s3c244x_resume NULL -#endif - /* Since the S3C2442 and S3C2440 share items, put both sysclasses here */ struct sysdev_class s3c2440_sysclass = { .name = "s3c2440-core", - .suspend = s3c244x_suspend, - .resume = s3c244x_resume }; struct sysdev_class s3c2442_sysclass = { .name = "s3c2442-core", - .suspend = s3c244x_suspend, - .resume = s3c244x_resume }; /* need to register class before we actually register the device, and @@ -194,3 +164,33 @@ static int __init s3c2442_core_init(void) } core_initcall(s3c2442_core_init); + + +#ifdef CONFIG_PM +static struct sleep_save s3c244x_sleep[] = { + SAVE_ITEM(S3C2440_DSC0), + SAVE_ITEM(S3C2440_DSC1), + SAVE_ITEM(S3C2440_GPJDAT), + SAVE_ITEM(S3C2440_GPJCON), + SAVE_ITEM(S3C2440_GPJUP) +}; + +static int s3c244x_suspend(void) +{ + s3c_pm_do_save(s3c244x_sleep, ARRAY_SIZE(s3c244x_sleep)); + return 0; +} + +static void s3c244x_resume(void) +{ + s3c_pm_do_restore(s3c244x_sleep, ARRAY_SIZE(s3c244x_sleep)); +} +#else +#define s3c244x_suspend NULL +#define s3c244x_resume NULL +#endif + +struct syscore_ops s3c244x_pm_syscore_ops = { + .suspend = s3c244x_suspend, + .resume = s3c244x_resume, +}; diff --git a/arch/arm/mach-s3c64xx/irq-pm.c b/arch/arm/mach-s3c64xx/irq-pm.c index da1bec6..8bec61e 100644 --- a/arch/arm/mach-s3c64xx/irq-pm.c +++ b/arch/arm/mach-s3c64xx/irq-pm.c @@ -13,7 +13,7 @@ */ #include -#include +#include #include #include #include @@ -54,7 +54,7 @@ static struct irq_grp_save { static u32 irq_uart_mask[CONFIG_SERIAL_SAMSUNG_UARTS]; -static int s3c64xx_irq_pm_suspend(struct sys_device *dev, pm_message_t state) +static int s3c64xx_irq_pm_suspend(void) { struct irq_grp_save *grp = eint_grp_save; int i; @@ -75,7 +75,7 @@ static int s3c64xx_irq_pm_suspend(struct sys_device *dev, pm_message_t state) return 0; } -static int s3c64xx_irq_pm_resume(struct sys_device *dev) +static void s3c64xx_irq_pm_resume(void) { struct irq_grp_save *grp = eint_grp_save; int i; @@ -94,18 +94,18 @@ static int s3c64xx_irq_pm_resume(struct sys_device *dev) } S3C_PMDBG("%s: IRQ configuration restored\n", __func__); - return 0; } -static struct sysdev_driver s3c64xx_irq_driver = { +struct syscore_ops s3c64xx_irq_syscore_ops = { .suspend = s3c64xx_irq_pm_suspend, .resume = s3c64xx_irq_pm_resume, }; -static int __init s3c64xx_irq_pm_init(void) +static __init int s3c64xx_syscore_init(void) { - return sysdev_driver_register(&s3c64xx_sysclass, &s3c64xx_irq_driver); -} + register_syscore_ops(&s3c64xx_irq_syscore_ops); -arch_initcall(s3c64xx_irq_pm_init); + return 0; +} +core_initcall(s3c64xx_syscore_init); diff --git a/arch/arm/mach-s5pv210/pm.c b/arch/arm/mach-s5pv210/pm.c index 549d792..24febae 100644 --- a/arch/arm/mach-s5pv210/pm.c +++ b/arch/arm/mach-s5pv210/pm.c @@ -16,6 +16,7 @@ #include #include +#include #include #include @@ -140,7 +141,17 @@ static int s5pv210_pm_add(struct sys_device *sysdev) return 0; } -static int s5pv210_pm_resume(struct sys_device *dev) +static struct sysdev_driver s5pv210_pm_driver = { + .add = s5pv210_pm_add, +}; + +static __init int s5pv210_pm_drvinit(void) +{ + return sysdev_driver_register(&s5pv210_sysclass, &s5pv210_pm_driver); +} +arch_initcall(s5pv210_pm_drvinit); + +static void s5pv210_pm_resume(void) { u32 tmp; @@ -150,17 +161,15 @@ static int s5pv210_pm_resume(struct sys_device *dev) __raw_writel(tmp , S5P_OTHERS); s3c_pm_do_restore_core(s5pv210_core_save, ARRAY_SIZE(s5pv210_core_save)); - - return 0; } -static struct sysdev_driver s5pv210_pm_driver = { - .add = s5pv210_pm_add, +static struct syscore_ops s5pv210_pm_syscore_ops = { .resume = s5pv210_pm_resume, }; -static __init int s5pv210_pm_drvinit(void) +static __init int s5pv210_pm_syscore_init(void) { - return sysdev_driver_register(&s5pv210_sysclass, &s5pv210_pm_driver); + register_syscore_ops(&s5pv210_pm_syscore_ops); + return 0; } -arch_initcall(s5pv210_pm_drvinit); +arch_initcall(s5pv210_pm_syscore_init); diff --git a/arch/arm/plat-s3c24xx/dma.c b/arch/arm/plat-s3c24xx/dma.c index 27ea852..c10d10c 100644 --- a/arch/arm/plat-s3c24xx/dma.c +++ b/arch/arm/plat-s3c24xx/dma.c @@ -22,7 +22,7 @@ #include #include #include -#include +#include #include #include #include @@ -1195,19 +1195,12 @@ int s3c2410_dma_getposition(unsigned int channel, dma_addr_t *src, dma_addr_t *d EXPORT_SYMBOL(s3c2410_dma_getposition); -static inline struct s3c2410_dma_chan *to_dma_chan(struct sys_device *dev) -{ - return container_of(dev, struct s3c2410_dma_chan, dev); -} - -/* system device class */ +/* system core operations */ #ifdef CONFIG_PM -static int s3c2410_dma_suspend(struct sys_device *dev, pm_message_t state) +static void s3c2410_dma_suspend_chan(s3c2410_dma_chan *cp) { - struct s3c2410_dma_chan *cp = to_dma_chan(dev); - printk(KERN_DEBUG "suspending dma channel %d\n", cp->number); if (dma_rdreg(cp, S3C2410_DMA_DMASKTRIG) & S3C2410_DMASKTRIG_ON) { @@ -1222,13 +1215,21 @@ static int s3c2410_dma_suspend(struct sys_device *dev, pm_message_t state) s3c2410_dma_dostop(cp); } +} + +static int s3c2410_dma_suspend(void) +{ + struct s3c2410_dma_chan *cp = s3c2410_chans; + int channel; + + for (channel = 0; channel < dma_channels; cp++, channel++) + s3c2410_dma_suspend_chan(cp); return 0; } -static int s3c2410_dma_resume(struct sys_device *dev) +static void s3c2410_dma_resume_chan(struct s3c2410_dma_chan *cp) { - struct s3c2410_dma_chan *cp = to_dma_chan(dev); unsigned int no = cp->number | DMACH_LOW_LEVEL; /* restore channel's hardware configuration */ @@ -1249,13 +1250,21 @@ static int s3c2410_dma_resume(struct sys_device *dev) return 0; } +static void s3c2410_dma_resume(void) +{ + struct s3c2410_dma_chan *cp = s3c2410_chans + dma_channels - 1; + int channel; + + for (channel = dma_channels - 1; channel >= 0; cp++, channel--) + s3c2410_dma_resume_chan(cp); +} + #else #define s3c2410_dma_suspend NULL #define s3c2410_dma_resume NULL #endif /* CONFIG_PM */ -struct sysdev_class dma_sysclass = { - .name = "s3c24xx-dma", +struct syscore_ops dma_syscore_ops = { .suspend = s3c2410_dma_suspend, .resume = s3c2410_dma_resume, }; @@ -1269,39 +1278,14 @@ static void s3c2410_dma_cache_ctor(void *p) /* initialisation code */ -static int __init s3c24xx_dma_sysclass_init(void) +static int __init s3c24xx_dma_syscore_init(void) { - int ret = sysdev_class_register(&dma_sysclass); - - if (ret != 0) - printk(KERN_ERR "dma sysclass registration failed\n"); - - return ret; -} - -core_initcall(s3c24xx_dma_sysclass_init); - -static int __init s3c24xx_dma_sysdev_register(void) -{ - struct s3c2410_dma_chan *cp = s3c2410_chans; - int channel, ret; - - for (channel = 0; channel < dma_channels; cp++, channel++) { - cp->dev.cls = &dma_sysclass; - cp->dev.id = channel; - ret = sysdev_register(&cp->dev); - - if (ret) { - printk(KERN_ERR "error registering dev for dma %d\n", - channel); - return ret; - } - } + register_syscore_ops(&dma_syscore_ops); return 0; } -late_initcall(s3c24xx_dma_sysdev_register); +late_initcall(s3c24xx_dma_syscore_init); int __init s3c24xx_dma_init(unsigned int channels, unsigned int irq, unsigned int stride) diff --git a/arch/arm/plat-s3c24xx/irq-pm.c b/arch/arm/plat-s3c24xx/irq-pm.c index c3624d8..0efb2e2 100644 --- a/arch/arm/plat-s3c24xx/irq-pm.c +++ b/arch/arm/plat-s3c24xx/irq-pm.c @@ -14,7 +14,6 @@ #include #include #include -#include #include #include @@ -65,7 +64,7 @@ static unsigned long save_extint[3]; static unsigned long save_eintflt[4]; static unsigned long save_eintmask; -int s3c24xx_irq_suspend(struct sys_device *dev, pm_message_t state) +int s3c24xx_irq_suspend(void) { unsigned int i; @@ -81,7 +80,7 @@ int s3c24xx_irq_suspend(struct sys_device *dev, pm_message_t state) return 0; } -int s3c24xx_irq_resume(struct sys_device *dev) +void s3c24xx_irq_resume(void) { unsigned int i; @@ -93,6 +92,4 @@ int s3c24xx_irq_resume(struct sys_device *dev) s3c_pm_do_restore(irq_save, ARRAY_SIZE(irq_save)); __raw_writel(save_eintmask, S3C24XX_EINTMASK); - - return 0; } diff --git a/arch/arm/plat-s5p/irq-pm.c b/arch/arm/plat-s5p/irq-pm.c index 5259ad4..327acb3 100644 --- a/arch/arm/plat-s5p/irq-pm.c +++ b/arch/arm/plat-s5p/irq-pm.c @@ -16,7 +16,6 @@ #include #include #include -#include #include #include @@ -77,17 +76,15 @@ static struct sleep_save eint_save[] = { SAVE_ITEM(S5P_EINT_MASK(3)), }; -int s3c24xx_irq_suspend(struct sys_device *dev, pm_message_t state) +int s3c24xx_irq_suspend(void) { s3c_pm_do_save(eint_save, ARRAY_SIZE(eint_save)); return 0; } -int s3c24xx_irq_resume(struct sys_device *dev) +void s3c24xx_irq_resume(void) { s3c_pm_do_restore(eint_save, ARRAY_SIZE(eint_save)); - - return 0; } diff --git a/arch/arm/plat-samsung/include/plat/cpu.h b/arch/arm/plat-samsung/include/plat/cpu.h index cedfff5..3aedac0 100644 --- a/arch/arm/plat-samsung/include/plat/cpu.h +++ b/arch/arm/plat-samsung/include/plat/cpu.h @@ -68,6 +68,12 @@ extern void s3c24xx_init_uartdevs(char *name, struct sys_timer; extern struct sys_timer s3c24xx_timer; +extern struct syscore_ops s3c2410_pm_syscore_ops; +extern struct syscore_ops s3c2412_pm_syscore_ops; +extern struct syscore_ops s3c2416_pm_syscore_ops; +extern struct syscore_ops s3c244x_pm_syscore_ops; +extern struct syscore_ops s3c64xx_irq_syscore_ops; + /* system device classes */ extern struct sysdev_class s3c2410_sysclass; diff --git a/arch/arm/plat-samsung/include/plat/pm.h b/arch/arm/plat-samsung/include/plat/pm.h index 937cc2a..7fb6f6b 100644 --- a/arch/arm/plat-samsung/include/plat/pm.h +++ b/arch/arm/plat-samsung/include/plat/pm.h @@ -103,14 +103,16 @@ extern void s3c_pm_do_restore_core(struct sleep_save *ptr, int count); #ifdef CONFIG_PM extern int s3c_irqext_wake(struct irq_data *data, unsigned int state); -extern int s3c24xx_irq_suspend(struct sys_device *dev, pm_message_t state); -extern int s3c24xx_irq_resume(struct sys_device *dev); +extern int s3c24xx_irq_suspend(void); +extern void s3c24xx_irq_resume(void); #else #define s3c_irqext_wake NULL #define s3c24xx_irq_suspend NULL #define s3c24xx_irq_resume NULL #endif +extern struct syscore_ops s3c24xx_irq_syscore_ops; + /* PM debug functions */ #ifdef CONFIG_SAMSUNG_PM_DEBUG -- cgit v0.10.2 From 67f9cbf9affe39f67cd3f1d2e2a2a43089d9ab3a Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Fri, 22 Apr 2011 22:03:31 +0200 Subject: PM / Blackfin: Use struct syscore_ops instead of sysdevs for PM Convert some Blackfin architecture's code to using struct syscore_ops objects for power management instead of sysdev classes and sysdevs. This simplifies the code and reduces the kernel's memory footprint. It also is necessary for removing sysdevs from the kernel entirely in the future. Signed-off-by: Rafael J. Wysocki Acked-by: Greg Kroah-Hartman Acked-by: Mike Frysinger diff --git a/arch/blackfin/kernel/nmi.c b/arch/blackfin/kernel/nmi.c index 0b5f72f..401eb1d 100644 --- a/arch/blackfin/kernel/nmi.c +++ b/arch/blackfin/kernel/nmi.c @@ -12,7 +12,7 @@ #include #include -#include +#include #include #include #include @@ -196,43 +196,31 @@ void touch_nmi_watchdog(void) /* Suspend/resume support */ #ifdef CONFIG_PM -static int nmi_wdt_suspend(struct sys_device *dev, pm_message_t state) +static int nmi_wdt_suspend(void) { nmi_wdt_stop(); return 0; } -static int nmi_wdt_resume(struct sys_device *dev) +static void nmi_wdt_resume(void) { if (nmi_active) nmi_wdt_start(); - return 0; } -static struct sysdev_class nmi_sysclass = { - .name = DRV_NAME, +static struct syscore_ops nmi_syscore_ops = { .resume = nmi_wdt_resume, .suspend = nmi_wdt_suspend, }; -static struct sys_device device_nmi_wdt = { - .id = 0, - .cls = &nmi_sysclass, -}; - -static int __init init_nmi_wdt_sysfs(void) +static int __init init_nmi_wdt_syscore(void) { - int error; - - if (!nmi_active) - return 0; + if (nmi_active) + register_syscore_ops(&nmi_syscore_ops); - error = sysdev_class_register(&nmi_sysclass); - if (!error) - error = sysdev_register(&device_nmi_wdt); - return error; + return 0; } -late_initcall(init_nmi_wdt_sysfs); +late_initcall(init_nmi_wdt_syscore); #endif /* CONFIG_PM */ -- cgit v0.10.2 From 2a9e9507011440a57d6356ded630ba0c0f5d4b77 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Sun, 24 Apr 2011 10:54:56 -0700 Subject: net: Remove __KERNEL__ cpp checks from include/net These header files are never installed to user consumption, so any __KERNEL__ cpp checks are superfluous. Projects should also not copy these files into their userland utility sources and try to use them there. If they insist on doing so, the onus is on them to sanitize the headers as needed. Signed-off-by: David S. Miller diff --git a/include/net/addrconf.h b/include/net/addrconf.h index 7c4d92c..582e4ae 100644 --- a/include/net/addrconf.h +++ b/include/net/addrconf.h @@ -42,8 +42,6 @@ struct prefix_info { }; -#ifdef __KERNEL__ - #include #include #include @@ -285,4 +283,3 @@ extern void if6_proc_exit(void); #endif #endif -#endif diff --git a/include/net/af_rxrpc.h b/include/net/af_rxrpc.h index 00c2eaa..03e6e94 100644 --- a/include/net/af_rxrpc.h +++ b/include/net/af_rxrpc.h @@ -12,8 +12,6 @@ #ifndef _NET_RXRPC_H #define _NET_RXRPC_H -#ifdef __KERNEL__ - #include struct rxrpc_call; @@ -53,5 +51,4 @@ extern struct rxrpc_call *rxrpc_kernel_accept_call(struct socket *, unsigned long); extern int rxrpc_kernel_reject_call(struct socket *); -#endif /* __KERNEL__ */ #endif /* _NET_RXRPC_H */ diff --git a/include/net/af_unix.h b/include/net/af_unix.h index 18e5c3f..91ab5b0 100644 --- a/include/net/af_unix.h +++ b/include/net/af_unix.h @@ -41,7 +41,6 @@ struct unix_skb_parms { spin_lock_nested(&unix_sk(s)->lock, \ SINGLE_DEPTH_NESTING) -#ifdef __KERNEL__ /* The AF_UNIX socket */ struct unix_sock { /* WARNING: sk has to be the first member */ @@ -72,4 +71,3 @@ static inline int unix_sysctl_register(struct net *net) { return 0; } static inline void unix_sysctl_unregister(struct net *net) {} #endif #endif -#endif diff --git a/include/net/atmclip.h b/include/net/atmclip.h index 467c531..497ef64 100644 --- a/include/net/atmclip.h +++ b/include/net/atmclip.h @@ -54,8 +54,6 @@ struct clip_priv { }; -#ifdef __KERNEL__ extern struct neigh_table *clip_tbl_hook; -#endif #endif diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h index 6138e31..499b7b7 100644 --- a/include/net/bluetooth/hci.h +++ b/include/net/bluetooth/hci.h @@ -1067,7 +1067,6 @@ struct hci_sco_hdr { __u8 dlen; } __packed; -#ifdef __KERNEL__ #include static inline struct hci_event_hdr *hci_event_hdr(const struct sk_buff *skb) { @@ -1083,7 +1082,6 @@ static inline struct hci_sco_hdr *hci_sco_hdr(const struct sk_buff *skb) { return (struct hci_sco_hdr *) skb->data; } -#endif /* Command opcode pack/unpack */ #define hci_opcode_pack(ogf, ocf) (__u16) ((ocf & 0x03ff)|(ogf << 10)) diff --git a/include/net/dst.h b/include/net/dst.h index 75b95df..d7bb740 100644 --- a/include/net/dst.h +++ b/include/net/dst.h @@ -92,8 +92,6 @@ struct dst_entry { }; }; -#ifdef __KERNEL__ - extern u32 *dst_cow_metrics_generic(struct dst_entry *dst, unsigned long old); extern const u32 dst_default_metrics[RTAX_MAX]; @@ -438,6 +436,5 @@ extern struct dst_entry *xfrm_lookup(struct net *net, struct dst_entry *dst_orig const struct flowi *fl, struct sock *sk, int flags); #endif -#endif #endif /* _NET_DST_H */ diff --git a/include/net/if_inet6.h b/include/net/if_inet6.h index 3d982f7..0c603fe 100644 --- a/include/net/if_inet6.h +++ b/include/net/if_inet6.h @@ -30,8 +30,6 @@ #define IF_PREFIX_ONLINK 0x01 #define IF_PREFIX_AUTOCONF 0x02 -#ifdef __KERNEL__ - enum { INET6_IFADDR_STATE_DAD, INET6_IFADDR_STATE_POSTDAD, @@ -303,4 +301,3 @@ static inline int ipv6_ipgre_mc_map(const struct in6_addr *addr, } #endif -#endif diff --git a/include/net/ip6_fib.h b/include/net/ip6_fib.h index aca8ef4..477ef75 100644 --- a/include/net/ip6_fib.h +++ b/include/net/ip6_fib.h @@ -13,8 +13,6 @@ #ifndef _IP6_FIB_H #define _IP6_FIB_H -#ifdef __KERNEL__ - #include #include #include @@ -240,4 +238,3 @@ static inline void fib6_rules_cleanup(void) } #endif #endif -#endif diff --git a/include/net/ip6_route.h b/include/net/ip6_route.h index d5c21d4..5e91b72 100644 --- a/include/net/ip6_route.h +++ b/include/net/ip6_route.h @@ -21,8 +21,6 @@ struct route_info { __u8 prefix[0]; /* 0,8 or 16 */ }; -#ifdef __KERNEL__ - #include #include #include @@ -193,4 +191,3 @@ static inline int ip6_skb_dst_mtu(struct sk_buff *skb) } #endif -#endif diff --git a/include/net/ip_vs.h b/include/net/ip_vs.h index d516f00..e0b7f13 100644 --- a/include/net/ip_vs.h +++ b/include/net/ip_vs.h @@ -8,9 +8,6 @@ #include /* definitions shared with userland */ -/* old ipvsadm versions still include this file directly */ -#ifdef __KERNEL__ - #include /* for __uXX types */ #include /* for ctl_path */ @@ -1415,6 +1412,4 @@ ip_vs_dest_conn_overhead(struct ip_vs_dest *dest) atomic_read(&dest->inactconns); } -#endif /* __KERNEL__ */ - #endif /* _NET_IP_VS_H */ diff --git a/include/net/ipv6.h b/include/net/ipv6.h index 5da1926..e1c60b4 100644 --- a/include/net/ipv6.h +++ b/include/net/ipv6.h @@ -77,11 +77,9 @@ /* * Addr scopes */ -#ifdef __KERNEL__ #define IPV6_ADDR_MC_SCOPE(a) \ ((a)->s6_addr[1] & 0x0f) /* nonstandard */ #define __IPV6_ADDR_SCOPE_INVALID -1 -#endif #define IPV6_ADDR_SCOPE_NODELOCAL 0x01 #define IPV6_ADDR_SCOPE_LINKLOCAL 0x02 #define IPV6_ADDR_SCOPE_SITELOCAL 0x05 @@ -91,14 +89,12 @@ /* * Addr flags */ -#ifdef __KERNEL__ #define IPV6_ADDR_MC_FLAG_TRANSIENT(a) \ ((a)->s6_addr[1] & 0x10) #define IPV6_ADDR_MC_FLAG_PREFIX(a) \ ((a)->s6_addr[1] & 0x20) #define IPV6_ADDR_MC_FLAG_RENDEZVOUS(a) \ ((a)->s6_addr[1] & 0x40) -#endif /* * fragmentation header @@ -113,8 +109,6 @@ struct frag_hdr { #define IP6_MF 0x0001 -#ifdef __KERNEL__ - #include /* sysctls */ @@ -667,5 +661,4 @@ extern int ipv6_static_sysctl_register(void); extern void ipv6_static_sysctl_unregister(void); #endif -#endif /* __KERNEL__ */ #endif /* _NET_IPV6_H */ diff --git a/include/net/ipx.h b/include/net/ipx.h index 05d7e4a..c1fec6b 100644 --- a/include/net/ipx.h +++ b/include/net/ipx.h @@ -80,7 +80,6 @@ struct ipx_route { atomic_t refcnt; }; -#ifdef __KERNEL__ struct ipx_cb { u8 ipx_tctrl; __be32 ipx_dest_net; @@ -116,7 +115,6 @@ static inline struct ipx_sock *ipx_sk(struct sock *sk) } #define IPX_SKB_CB(__skb) ((struct ipx_cb *)&((__skb)->cb[0])) -#endif #define IPX_MIN_EPHEMERAL_SOCKET 0x4000 #define IPX_MAX_EPHEMERAL_SOCKET 0x7fff diff --git a/include/net/ndisc.h b/include/net/ndisc.h index 6144685..62beeb9 100644 --- a/include/net/ndisc.h +++ b/include/net/ndisc.h @@ -42,8 +42,6 @@ enum { #define ND_REACHABLE_TIME (30*HZ) #define ND_RETRANS_TIMER HZ -#ifdef __KERNEL__ - #include #include #include @@ -156,8 +154,4 @@ static inline struct neighbour * ndisc_get_neigh(struct net_device *dev, const s return ERR_PTR(-ENODEV); } - -#endif /* __KERNEL__ */ - - #endif diff --git a/include/net/netevent.h b/include/net/netevent.h index 22b239c..086f8a5 100644 --- a/include/net/netevent.h +++ b/include/net/netevent.h @@ -10,7 +10,6 @@ * * Changes: */ -#ifdef __KERNEL__ struct dst_entry; @@ -29,4 +28,3 @@ extern int unregister_netevent_notifier(struct notifier_block *nb); extern int call_netevent_notifiers(unsigned long val, void *v); #endif -#endif diff --git a/include/net/netfilter/nf_conntrack.h b/include/net/netfilter/nf_conntrack.h index d0d1337..c7c42e7 100644 --- a/include/net/netfilter/nf_conntrack.h +++ b/include/net/netfilter/nf_conntrack.h @@ -14,7 +14,6 @@ #include -#ifdef __KERNEL__ #include #include #include @@ -326,5 +325,4 @@ do { \ #define MODULE_ALIAS_NFCT_HELPER(helper) \ MODULE_ALIAS("nfct-helper-" helper) -#endif /* __KERNEL__ */ #endif /* _NF_CONNTRACK_H */ diff --git a/include/net/netfilter/nf_conntrack_tuple.h b/include/net/netfilter/nf_conntrack_tuple.h index 4ee44c8..7ca6bdd 100644 --- a/include/net/netfilter/nf_conntrack_tuple.h +++ b/include/net/netfilter/nf_conntrack_tuple.h @@ -104,8 +104,6 @@ struct nf_conntrack_tuple_mask { } src; }; -#ifdef __KERNEL__ - static inline void nf_ct_dump_tuple_ip(const struct nf_conntrack_tuple *t) { #ifdef DEBUG @@ -148,8 +146,6 @@ struct nf_conntrack_tuple_hash { struct nf_conntrack_tuple tuple; }; -#endif /* __KERNEL__ */ - static inline bool __nf_ct_tuple_src_equal(const struct nf_conntrack_tuple *t1, const struct nf_conntrack_tuple *t2) { diff --git a/include/net/netfilter/nf_nat.h b/include/net/netfilter/nf_nat.h index aff80b1..0346b00 100644 --- a/include/net/netfilter/nf_nat.h +++ b/include/net/netfilter/nf_nat.h @@ -48,7 +48,6 @@ struct nf_nat_multi_range_compat { struct nf_nat_range range[1]; }; -#ifdef __KERNEL__ #include #include #include @@ -93,7 +92,4 @@ static inline struct nf_conn_nat *nfct_nat(const struct nf_conn *ct) #endif } -#else /* !__KERNEL__: iptables wants this to compile. */ -#define nf_nat_multi_range nf_nat_multi_range_compat -#endif /*__KERNEL__*/ #endif diff --git a/include/net/rawv6.h b/include/net/rawv6.h index f6b9b83..cf75772 100644 --- a/include/net/rawv6.h +++ b/include/net/rawv6.h @@ -1,8 +1,6 @@ #ifndef _NET_RAWV6_H #define _NET_RAWV6_H -#ifdef __KERNEL__ - #include void raw6_icmp_error(struct sk_buff *, int nexthdr, @@ -20,5 +18,3 @@ int rawv6_mh_filter_unregister(int (*filter)(struct sock *sock, #endif #endif - -#endif diff --git a/include/net/route.h b/include/net/route.h index b3962e2..3684c3e 100644 --- a/include/net/route.h +++ b/include/net/route.h @@ -35,10 +35,6 @@ #include #include -#ifndef __KERNEL__ -#warning This file is not supposed to be used outside of kernel. -#endif - #define RTO_ONLINK 0x01 #define RTO_CONN 0 diff --git a/include/net/transp_v6.h b/include/net/transp_v6.h index a8122dc..5271a74 100644 --- a/include/net/transp_v6.h +++ b/include/net/transp_v6.h @@ -7,8 +7,6 @@ * IPv6 transport protocols */ -#ifdef __KERNEL__ - extern struct proto rawv6_prot; extern struct proto udpv6_prot; extern struct proto udplitev6_prot; @@ -57,5 +55,3 @@ extern const struct inet_connection_sock_af_ops ipv4_specific; extern void inet6_destroy_sock(struct sock *sk); #endif - -#endif diff --git a/include/net/wimax.h b/include/net/wimax.h index c799ba7..7328d50 100644 --- a/include/net/wimax.h +++ b/include/net/wimax.h @@ -250,7 +250,6 @@ #ifndef __NET__WIMAX_H__ #define __NET__WIMAX_H__ -#ifdef __KERNEL__ #include #include @@ -518,8 +517,4 @@ extern ssize_t wimax_msg_len(struct sk_buff *); extern int wimax_rfkill(struct wimax_dev *, enum wimax_rf_state); extern int wimax_reset(struct wimax_dev *); -#else -/* You might be looking for linux/wimax.h */ -#error This file should not be included from user space. -#endif /* #ifdef __KERNEL__ */ #endif /* #ifndef __NET__WIMAX_H__ */ -- cgit v0.10.2 From fd954ae124e8a866e9cc1bc3de9a07be5492f608 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Sun, 24 Apr 2011 14:28:18 -0400 Subject: NFSv4.1: Don't loop forever in nfs4_proc_create_session If a server for some reason keeps sending NFS4ERR_DELAY errors, we can end up looping forever inside nfs4_proc_create_session, and so the usual mechanisms for detecting if the nfs_client is dead don't work. Fix this by ensuring that we loop inside the nfs4_state_manager thread instead. Signed-off-by: Trond Myklebust diff --git a/fs/nfs/nfs4_fs.h b/fs/nfs/nfs4_fs.h index e1c261d..c4a6983 100644 --- a/fs/nfs/nfs4_fs.h +++ b/fs/nfs/nfs4_fs.h @@ -47,6 +47,7 @@ enum nfs4_client_state { NFS4CLNT_LAYOUTRECALL, NFS4CLNT_SESSION_RESET, NFS4CLNT_RECALL_SLOT, + NFS4CLNT_LEASE_CONFIRM, }; enum nfs4_session_state { diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index 628e35f..50c8148 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c @@ -3754,18 +3754,17 @@ int nfs4_proc_setclientid(struct nfs_client *clp, u32 program, status = rpc_call_sync(clp->cl_rpcclient, &msg, 0); if (status != -NFS4ERR_CLID_INUSE) break; - if (signalled()) + if (loop != 0) { + ++clp->cl_id_uniquifier; break; - if (loop++ & 1) - ssleep(clp->cl_lease_time / HZ + 1); - else - if (++clp->cl_id_uniquifier == 0) - break; + } + ++loop; + ssleep(clp->cl_lease_time / HZ + 1); } return status; } -static int _nfs4_proc_setclientid_confirm(struct nfs_client *clp, +int nfs4_proc_setclientid_confirm(struct nfs_client *clp, struct nfs4_setclientid_res *arg, struct rpc_cred *cred) { @@ -3790,26 +3789,6 @@ static int _nfs4_proc_setclientid_confirm(struct nfs_client *clp, return status; } -int nfs4_proc_setclientid_confirm(struct nfs_client *clp, - struct nfs4_setclientid_res *arg, - struct rpc_cred *cred) -{ - long timeout = 0; - int err; - do { - err = _nfs4_proc_setclientid_confirm(clp, arg, cred); - switch (err) { - case 0: - return err; - case -NFS4ERR_RESOURCE: - /* The IBM lawyers misread another document! */ - case -NFS4ERR_DELAY: - err = nfs4_delay(clp->cl_rpcclient, &timeout); - } - } while (err == 0); - return err; -} - struct nfs4_delegreturndata { struct nfs4_delegreturnargs args; struct nfs4_delegreturnres res; @@ -5222,20 +5201,10 @@ int nfs4_proc_create_session(struct nfs_client *clp) int status; unsigned *ptr; struct nfs4_session *session = clp->cl_session; - long timeout = 0; - int err; dprintk("--> %s clp=%p session=%p\n", __func__, clp, session); - do { - status = _nfs4_proc_create_session(clp); - if (status == -NFS4ERR_DELAY) { - err = nfs4_delay(clp->cl_rpcclient, &timeout); - if (err) - status = err; - } - } while (status == -NFS4ERR_DELAY); - + status = _nfs4_proc_create_session(clp); if (status) goto out; diff --git a/fs/nfs/nfs4state.c b/fs/nfs/nfs4state.c index 4dfb34b..4a810c8 100644 --- a/fs/nfs/nfs4state.c +++ b/fs/nfs/nfs4state.c @@ -64,10 +64,15 @@ static LIST_HEAD(nfs4_clientid_list); int nfs4_init_clientid(struct nfs_client *clp, struct rpc_cred *cred) { - struct nfs4_setclientid_res clid; + struct nfs4_setclientid_res clid = { + .clientid = clp->cl_clientid, + .confirm = clp->cl_confirm, + }; unsigned short port; int status; + if (test_bit(NFS4CLNT_LEASE_CONFIRM, &clp->cl_state)) + goto do_confirm; port = nfs_callback_tcpport; if (clp->cl_addr.ss_family == AF_INET6) port = nfs_callback_tcpport6; @@ -75,10 +80,14 @@ int nfs4_init_clientid(struct nfs_client *clp, struct rpc_cred *cred) status = nfs4_proc_setclientid(clp, NFS4_CALLBACK, port, cred, &clid); if (status != 0) goto out; + clp->cl_clientid = clid.clientid; + clp->cl_confirm = clid.confirm; + set_bit(NFS4CLNT_LEASE_CONFIRM, &clp->cl_state); +do_confirm: status = nfs4_proc_setclientid_confirm(clp, &clid, cred); if (status != 0) goto out; - clp->cl_clientid = clid.clientid; + clear_bit(NFS4CLNT_LEASE_CONFIRM, &clp->cl_state); nfs4_schedule_state_renewal(clp); out: return status; @@ -230,13 +239,18 @@ int nfs41_init_clientid(struct nfs_client *clp, struct rpc_cred *cred) { int status; + if (test_bit(NFS4CLNT_LEASE_CONFIRM, &clp->cl_state)) + goto do_confirm; nfs4_begin_drain_session(clp); status = nfs4_proc_exchange_id(clp, cred); if (status != 0) goto out; + set_bit(NFS4CLNT_LEASE_CONFIRM, &clp->cl_state); +do_confirm: status = nfs4_proc_create_session(clp); if (status != 0) goto out; + clear_bit(NFS4CLNT_LEASE_CONFIRM, &clp->cl_state); nfs41_setup_state_renewal(clp); nfs_mark_client_ready(clp, NFS_CS_READY); out: @@ -1584,20 +1598,22 @@ static int nfs4_recall_slot(struct nfs_client *clp) { return 0; } */ static void nfs4_set_lease_expired(struct nfs_client *clp, int status) { - if (nfs4_has_session(clp)) { - switch (status) { - case -NFS4ERR_DELAY: - case -NFS4ERR_CLID_INUSE: - case -EAGAIN: - break; + switch (status) { + case -NFS4ERR_CLID_INUSE: + case -NFS4ERR_STALE_CLIENTID: + clear_bit(NFS4CLNT_LEASE_CONFIRM, &clp->cl_state); + break; + case -NFS4ERR_DELAY: + case -EAGAIN: + ssleep(1); + break; - case -EKEYEXPIRED: - nfs4_warn_keyexpired(clp->cl_hostname); - case -NFS4ERR_NOT_SAME: /* FixMe: implement recovery - * in nfs4_exchange_id */ - default: - return; - } + case -EKEYEXPIRED: + nfs4_warn_keyexpired(clp->cl_hostname); + case -NFS4ERR_NOT_SAME: /* FixMe: implement recovery + * in nfs4_exchange_id */ + default: + return; } set_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state); } diff --git a/include/linux/nfs_fs_sb.h b/include/linux/nfs_fs_sb.h index 216cea5..87694ca 100644 --- a/include/linux/nfs_fs_sb.h +++ b/include/linux/nfs_fs_sb.h @@ -47,6 +47,7 @@ struct nfs_client { #ifdef CONFIG_NFS_V4 u64 cl_clientid; /* constant */ + nfs4_verifier cl_confirm; /* Clientid verifier */ unsigned long cl_state; spinlock_t cl_lock; -- cgit v0.10.2 From 7494d00c7b826b6ceb79ec33892bd0ef59be5614 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Sun, 24 Apr 2011 14:28:45 -0400 Subject: SUNRPC: Allow RPC calls to return ETIMEDOUT instead of EIO On occasion, it is useful for the NFS layer to distinguish between soft timeouts and other EIO errors due to (say) encoding errors, or authentication errors. The following patch ensures that the default behaviour of the RPC layer remains to return EIO on soft timeouts (until we have audited all the callers). Signed-off-by: Trond Myklebust diff --git a/include/linux/sunrpc/sched.h b/include/linux/sunrpc/sched.h index 3b94f80..f73c482 100644 --- a/include/linux/sunrpc/sched.h +++ b/include/linux/sunrpc/sched.h @@ -128,12 +128,13 @@ struct rpc_task_setup { #define RPC_TASK_SOFT 0x0200 /* Use soft timeouts */ #define RPC_TASK_SOFTCONN 0x0400 /* Fail if can't connect */ #define RPC_TASK_SENT 0x0800 /* message was sent */ +#define RPC_TASK_TIMEOUT 0x1000 /* fail with ETIMEDOUT on timeout */ #define RPC_IS_ASYNC(t) ((t)->tk_flags & RPC_TASK_ASYNC) #define RPC_IS_SWAPPER(t) ((t)->tk_flags & RPC_TASK_SWAPPER) #define RPC_DO_ROOTOVERRIDE(t) ((t)->tk_flags & RPC_TASK_ROOTCREDS) #define RPC_ASSASSINATED(t) ((t)->tk_flags & RPC_TASK_KILLED) -#define RPC_IS_SOFT(t) ((t)->tk_flags & RPC_TASK_SOFT) +#define RPC_IS_SOFT(t) ((t)->tk_flags & (RPC_TASK_SOFT|RPC_TASK_TIMEOUT)) #define RPC_IS_SOFTCONN(t) ((t)->tk_flags & RPC_TASK_SOFTCONN) #define RPC_WAS_SENT(t) ((t)->tk_flags & RPC_TASK_SENT) diff --git a/net/sunrpc/clnt.c b/net/sunrpc/clnt.c index e7a96e4..8d83f9d 100644 --- a/net/sunrpc/clnt.c +++ b/net/sunrpc/clnt.c @@ -1508,7 +1508,10 @@ call_timeout(struct rpc_task *task) if (clnt->cl_chatty) printk(KERN_NOTICE "%s: server %s not responding, timed out\n", clnt->cl_protname, clnt->cl_server); - rpc_exit(task, -EIO); + if (task->tk_flags & RPC_TASK_TIMEOUT) + rpc_exit(task, -ETIMEDOUT); + else + rpc_exit(task, -EIO); return; } -- cgit v0.10.2 From 1bd714f2a14aa4d6a5570956fcec64530b007e4a Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Sun, 24 Apr 2011 14:29:33 -0400 Subject: NFSv4: Ensure that clientid and session establishment can time out The following patch ensures that we do not get permanently trapped in the RPC layer when trying to establish a new client id or session. This again ensures that the state manager can finish in a timely fashion when the last filesystem to reference the nfs_client exits. Signed-off-by: Trond Myklebust diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index 50c8148..69c0f3c 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c @@ -3751,7 +3751,7 @@ int nfs4_proc_setclientid(struct nfs_client *clp, u32 program, sizeof(setclientid.sc_uaddr), "%s.%u.%u", clp->cl_ipaddr, port >> 8, port & 255); - status = rpc_call_sync(clp->cl_rpcclient, &msg, 0); + status = rpc_call_sync(clp->cl_rpcclient, &msg, RPC_TASK_TIMEOUT); if (status != -NFS4ERR_CLID_INUSE) break; if (loop != 0) { @@ -3779,7 +3779,7 @@ int nfs4_proc_setclientid_confirm(struct nfs_client *clp, int status; now = jiffies; - status = rpc_call_sync(clp->cl_rpcclient, &msg, 0); + status = rpc_call_sync(clp->cl_rpcclient, &msg, RPC_TASK_TIMEOUT); if (status == 0) { spin_lock(&clp->cl_lock); clp->cl_lease_time = fsinfo.lease_time * HZ; @@ -4793,7 +4793,7 @@ int nfs4_proc_exchange_id(struct nfs_client *clp, struct rpc_cred *cred) init_utsname()->domainname, clp->cl_rpcclient->cl_auth->au_flavor); - status = rpc_call_sync(clp->cl_rpcclient, &msg, 0); + status = rpc_call_sync(clp->cl_rpcclient, &msg, RPC_TASK_TIMEOUT); if (!status) status = nfs4_check_cl_exchange_flags(clp->cl_exchange_flags); dprintk("<-- %s status= %d\n", __func__, status); @@ -4876,7 +4876,8 @@ int nfs4_proc_get_lease_time(struct nfs_client *clp, struct nfs_fsinfo *fsinfo) .rpc_client = clp->cl_rpcclient, .rpc_message = &msg, .callback_ops = &nfs4_get_lease_time_ops, - .callback_data = &data + .callback_data = &data, + .flags = RPC_TASK_TIMEOUT, }; int status; @@ -5178,7 +5179,7 @@ static int _nfs4_proc_create_session(struct nfs_client *clp) nfs4_init_channel_attrs(&args); args.flags = (SESSION4_PERSIST | SESSION4_BACK_CHAN); - status = rpc_call_sync(session->clp->cl_rpcclient, &msg, 0); + status = rpc_call_sync(session->clp->cl_rpcclient, &msg, RPC_TASK_TIMEOUT); if (!status) /* Verify the session's negotiated channel_attrs values */ @@ -5245,7 +5246,7 @@ int nfs4_proc_destroy_session(struct nfs4_session *session) msg.rpc_argp = session; msg.rpc_resp = NULL; msg.rpc_cred = NULL; - status = rpc_call_sync(session->clp->cl_rpcclient, &msg, 0); + status = rpc_call_sync(session->clp->cl_rpcclient, &msg, RPC_TASK_TIMEOUT); if (status) printk(KERN_WARNING diff --git a/fs/nfs/nfs4state.c b/fs/nfs/nfs4state.c index 4a810c8..036f5ad 100644 --- a/fs/nfs/nfs4state.c +++ b/fs/nfs/nfs4state.c @@ -1604,6 +1604,7 @@ static void nfs4_set_lease_expired(struct nfs_client *clp, int status) clear_bit(NFS4CLNT_LEASE_CONFIRM, &clp->cl_state); break; case -NFS4ERR_DELAY: + case -ETIMEDOUT: case -EAGAIN: ssleep(1); break; -- cgit v0.10.2 From 745b1f4f62852340e97a67d8c414d52fa1529185 Mon Sep 17 00:00:00 2001 From: Paul Parsons Date: Fri, 15 Apr 2011 14:39:27 +0000 Subject: ARM: pxa/hx4700: bq24022 regulator needs to be enabled Add REGULATOR_CHANGE_STATUS flag to hx4700 bq24022 regulator. Without this flag the bq24022 cannot be enabled and the battery will not charge. Signed-off-by: Paul Parsons Cc: Philipp Zabel Tested-by: Dmitry Artamonow Signed-off-by: Eric Miao diff --git a/arch/arm/mach-pxa/hx4700.c b/arch/arm/mach-pxa/hx4700.c index 6de0ad0..9cdcca5 100644 --- a/arch/arm/mach-pxa/hx4700.c +++ b/arch/arm/mach-pxa/hx4700.c @@ -711,7 +711,7 @@ static struct regulator_consumer_supply bq24022_consumers[] = { static struct regulator_init_data bq24022_init_data = { .constraints = { .max_uA = 500000, - .valid_ops_mask = REGULATOR_CHANGE_CURRENT, + .valid_ops_mask = REGULATOR_CHANGE_CURRENT|REGULATOR_CHANGE_STATUS, }, .num_consumer_supplies = ARRAY_SIZE(bq24022_consumers), .consumer_supplies = bq24022_consumers, -- cgit v0.10.2 From e454d1632000b6e86003209811bda1186b34f8f3 Mon Sep 17 00:00:00 2001 From: Philipp Zabel Date: Wed, 20 Apr 2011 15:41:29 +0200 Subject: ARM: pxa/magician: bq24022 regulator needs to be enabled Add REGULATOR_CHANGE_STATUS flag to magician bq24022 regulator to enable charging. Signed-off-by: Philipp Zabel Signed-off-by: Eric Miao diff --git a/arch/arm/mach-pxa/magician.c b/arch/arm/mach-pxa/magician.c index a72993d..9984ef7 100644 --- a/arch/arm/mach-pxa/magician.c +++ b/arch/arm/mach-pxa/magician.c @@ -599,7 +599,7 @@ static struct regulator_consumer_supply bq24022_consumers[] = { static struct regulator_init_data bq24022_init_data = { .constraints = { .max_uA = 500000, - .valid_ops_mask = REGULATOR_CHANGE_CURRENT, + .valid_ops_mask = REGULATOR_CHANGE_CURRENT | REGULATOR_CHANGE_STATUS, }, .num_consumer_supplies = ARRAY_SIZE(bq24022_consumers), .consumer_supplies = bq24022_consumers, -- cgit v0.10.2 From 8c61d9d611cb5b290f1b4ac57c4631acfd6e3b5a Mon Sep 17 00:00:00 2001 From: Hans Petter Selasky Date: Sun, 24 Apr 2011 22:35:19 -0700 Subject: cdc_ncm: fix short packet issue on some devices The default maximum transmit length for NCM USB frames should be so that a short packet happens at the end if the device supports a length greater than the defined maximum. This is achieved by adding 4 bytes to the maximum length so that the existing logic can fit a short packet there. Signed-off-by: Hans Petter Selasky Signed-off-by: Greg Kroah-Hartman Signed-off-by: David S. Miller diff --git a/drivers/net/usb/cdc_ncm.c b/drivers/net/usb/cdc_ncm.c index 967371f..1033ef6 100644 --- a/drivers/net/usb/cdc_ncm.c +++ b/drivers/net/usb/cdc_ncm.c @@ -54,13 +54,13 @@ #include #include -#define DRIVER_VERSION "7-Feb-2011" +#define DRIVER_VERSION "23-Apr-2011" /* CDC NCM subclass 3.2.1 */ #define USB_CDC_NCM_NDP16_LENGTH_MIN 0x10 /* Maximum NTB length */ -#define CDC_NCM_NTB_MAX_SIZE_TX 16384 /* bytes */ +#define CDC_NCM_NTB_MAX_SIZE_TX (16384 + 4) /* bytes, must be short terminated */ #define CDC_NCM_NTB_MAX_SIZE_RX 16384 /* bytes */ /* Minimum value for MaxDatagramSize, ch. 6.2.9 */ -- cgit v0.10.2 From ad10e1051ec97a7e56e001eb1e9721b3d883e030 Mon Sep 17 00:00:00 2001 From: Michael Williamson Date: Wed, 23 Mar 2011 12:15:41 +0000 Subject: davinci: mityomapl138: Use correct id for NAND controller For the MityDSP-L138/MityARM-1808 SOMS, the NAND controller id (which needs to correspond to the chipselect, and is used for controlling the HW ECC computation) is not correct. Fix it. Signed-off-by: Michael Williamson Signed-off-by: Sekhar Nori diff --git a/arch/arm/mach-davinci/board-mityomapl138.c b/arch/arm/mach-davinci/board-mityomapl138.c index 2aa79c5..e5d554c 100644 --- a/arch/arm/mach-davinci/board-mityomapl138.c +++ b/arch/arm/mach-davinci/board-mityomapl138.c @@ -414,7 +414,7 @@ static struct resource mityomapl138_nandflash_resource[] = { static struct platform_device mityomapl138_nandflash_device = { .name = "davinci_nand", - .id = 0, + .id = 1, .dev = { .platform_data = &mityomapl138_nandflash_data, }, -- cgit v0.10.2 From 336f402790defe4c4d33838b41bcd239537a5431 Mon Sep 17 00:00:00 2001 From: Michael Williamson Date: Wed, 23 Mar 2011 12:15:42 +0000 Subject: davinci: mityomapl138: Use auto-probe to determine attached PHY ID Current board configurations involving the MityDSP-L138 and MityARM-1808 only have one attached PHY, but it's address may not be the same. Default the behavior to auto-probe for the PHY and use the first one found. Signed-off-by: Michael Williamson Signed-off-by: Sekhar Nori diff --git a/arch/arm/mach-davinci/board-mityomapl138.c b/arch/arm/mach-davinci/board-mityomapl138.c index e5d554c..606a6f2 100644 --- a/arch/arm/mach-davinci/board-mityomapl138.c +++ b/arch/arm/mach-davinci/board-mityomapl138.c @@ -29,7 +29,7 @@ #include #include -#define MITYOMAPL138_PHY_ID "0:03" +#define MITYOMAPL138_PHY_ID "" #define FACTORY_CONFIG_MAGIC 0x012C0138 #define FACTORY_CONFIG_VERSION 0x00010001 -- cgit v0.10.2 From 9e7d24f622fc57ff5d58af3d44ba503430148354 Mon Sep 17 00:00:00 2001 From: Sergei Shtylyov Date: Wed, 6 Apr 2011 17:17:21 +0000 Subject: DA830: fix SPI1 base address Commit 54ce6883d29630ff334bee4256a25e3f8719a181 (davinci: da8xx: add spi resources and registration routine) wrongly assumed that SPI1 is mapped at the same address on DA830/OMAP-L137 and DA850/OMAP-L138; actually, the base address was valid only for the latter SoC. Teach the code to pass the correct SPI1 memory resource for both SoCs... Signed-off-by: Sergei Shtylyov Signed-off-by: Sekhar Nori diff --git a/arch/arm/mach-davinci/devices-da8xx.c b/arch/arm/mach-davinci/devices-da8xx.c index 625d4b6..58a02dc 100644 --- a/arch/arm/mach-davinci/devices-da8xx.c +++ b/arch/arm/mach-davinci/devices-da8xx.c @@ -39,7 +39,8 @@ #define DA8XX_GPIO_BASE 0x01e26000 #define DA8XX_I2C1_BASE 0x01e28000 #define DA8XX_SPI0_BASE 0x01c41000 -#define DA8XX_SPI1_BASE 0x01f0e000 +#define DA830_SPI1_BASE 0x01e12000 +#define DA850_SPI1_BASE 0x01f0e000 #define DA8XX_EMAC_CTRL_REG_OFFSET 0x3000 #define DA8XX_EMAC_MOD_REG_OFFSET 0x2000 @@ -762,8 +763,8 @@ static struct resource da8xx_spi0_resources[] = { static struct resource da8xx_spi1_resources[] = { [0] = { - .start = DA8XX_SPI1_BASE, - .end = DA8XX_SPI1_BASE + SZ_4K - 1, + .start = DA830_SPI1_BASE, + .end = DA830_SPI1_BASE + SZ_4K - 1, .flags = IORESOURCE_MEM, }, [1] = { @@ -832,5 +833,10 @@ int __init da8xx_register_spi(int instance, struct spi_board_info *info, da8xx_spi_pdata[instance].num_chipselect = len; + if (instance == 1 && cpu_is_davinci_da850()) { + da8xx_spi1_resources[0].start = DA850_SPI1_BASE; + da8xx_spi1_resources[0].end = DA850_SPI1_BASE + SZ_4K - 1; + } + return platform_device_register(&da8xx_spi_device[instance]); } -- cgit v0.10.2 From 45b146d746ea1b7f87b023a79d5186d0e87793eb Mon Sep 17 00:00:00 2001 From: Russell King - ARM Linux Date: Fri, 15 Apr 2011 12:32:40 +0000 Subject: ARM: Davinci: Fix I2C build errors Several Davinci platforms select the I2C EEPROM support, but don't select I2C support. This causes I2C EEPROM support to be built into the kernel, but I2C support may not be configured to be built in. This leads to linker errors due to missing I2C symbols. Arrange for I2C to be selected whenever EEPROM_AT24 is selected. Signed-off-by: Russell King Signed-off-by: Sekhar Nori diff --git a/arch/arm/mach-davinci/Kconfig b/arch/arm/mach-davinci/Kconfig index 32f1479..c0deaca 100644 --- a/arch/arm/mach-davinci/Kconfig +++ b/arch/arm/mach-davinci/Kconfig @@ -63,6 +63,7 @@ config MACH_DAVINCI_EVM depends on ARCH_DAVINCI_DM644x select MISC_DEVICES select EEPROM_AT24 + select I2C help Configure this option to specify the whether the board used for development is a DM644x EVM @@ -72,6 +73,7 @@ config MACH_SFFSDR depends on ARCH_DAVINCI_DM644x select MISC_DEVICES select EEPROM_AT24 + select I2C help Say Y here to select the Lyrtech Small Form Factor Software Defined Radio (SFFSDR) board. @@ -105,6 +107,7 @@ config MACH_DAVINCI_DM6467_EVM select MACH_DAVINCI_DM6467TEVM select MISC_DEVICES select EEPROM_AT24 + select I2C help Configure this option to specify the whether the board used for development is a DM6467 EVM @@ -118,6 +121,7 @@ config MACH_DAVINCI_DM365_EVM depends on ARCH_DAVINCI_DM365 select MISC_DEVICES select EEPROM_AT24 + select I2C help Configure this option to specify whether the board used for development is a DM365 EVM @@ -129,6 +133,7 @@ config MACH_DAVINCI_DA830_EVM select GPIO_PCF857X select MISC_DEVICES select EEPROM_AT24 + select I2C help Say Y here to select the TI DA830/OMAP-L137/AM17x Evaluation Module. @@ -205,6 +210,7 @@ config MACH_MITYOMAPL138 depends on ARCH_DAVINCI_DA850 select MISC_DEVICES select EEPROM_AT24 + select I2C help Say Y here to select the Critical Link MityDSP-L138/MityARM-1808 System on Module. Information on this SoM may be found at -- cgit v0.10.2 From bf26c018490c2fce7fe9b629083b96ce0e6ad019 Mon Sep 17 00:00:00 2001 From: Frederic Weisbecker Date: Thu, 7 Apr 2011 16:53:20 +0200 Subject: ptrace: Prepare to fix racy accesses on task breakpoints When a task is traced and is in a stopped state, the tracer may execute a ptrace request to examine the tracee state and get its task struct. Right after, the tracee can be killed and thus its breakpoints released. This can happen concurrently when the tracer is in the middle of reading or modifying these breakpoints, leading to dereferencing a freed pointer. Hence, to prepare the fix, create a generic breakpoint reference holding API. When a reference on the breakpoints of a task is held, the breakpoints won't be released until the last reference is dropped. After that, no more ptrace request on the task's breakpoints can be serviced for the tracer. Reported-by: Oleg Nesterov Signed-off-by: Frederic Weisbecker Cc: Ingo Molnar Cc: Peter Zijlstra Cc: Will Deacon Cc: Prasad Cc: Paul Mundt Cc: v2.6.33.. Link: http://lkml.kernel.org/r/1302284067-7860-2-git-send-email-fweisbec@gmail.com diff --git a/include/linux/ptrace.h b/include/linux/ptrace.h index a1147e5..9178d5c 100644 --- a/include/linux/ptrace.h +++ b/include/linux/ptrace.h @@ -189,6 +189,10 @@ static inline void ptrace_init_task(struct task_struct *child, bool ptrace) child->ptrace = current->ptrace; __ptrace_link(child, current->parent); } + +#ifdef CONFIG_HAVE_HW_BREAKPOINT + atomic_set(&child->ptrace_bp_refcnt, 1); +#endif } /** @@ -350,6 +354,13 @@ extern int task_current_syscall(struct task_struct *target, long *callno, unsigned long args[6], unsigned int maxargs, unsigned long *sp, unsigned long *pc); -#endif +#ifdef CONFIG_HAVE_HW_BREAKPOINT +extern int ptrace_get_breakpoints(struct task_struct *tsk); +extern void ptrace_put_breakpoints(struct task_struct *tsk); +#else +static inline void ptrace_put_breakpoints(struct task_struct *tsk) { } +#endif /* CONFIG_HAVE_HW_BREAKPOINT */ + +#endif /* __KERNEL */ #endif diff --git a/include/linux/sched.h b/include/linux/sched.h index 18d63ce..781abd1 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h @@ -1537,6 +1537,9 @@ struct task_struct { unsigned long memsw_nr_pages; /* uncharged mem+swap usage */ } memcg_batch; #endif +#ifdef CONFIG_HAVE_HW_BREAKPOINT + atomic_t ptrace_bp_refcnt; +#endif }; /* Future-safe accessor for struct task_struct's cpus_allowed. */ diff --git a/kernel/exit.c b/kernel/exit.c index f5d2f63..8dd8741 100644 --- a/kernel/exit.c +++ b/kernel/exit.c @@ -1016,7 +1016,7 @@ NORET_TYPE void do_exit(long code) /* * FIXME: do that only when needed, using sched_exit tracepoint */ - flush_ptrace_hw_breakpoint(tsk); + ptrace_put_breakpoints(tsk); exit_notify(tsk, group_dead); #ifdef CONFIG_NUMA diff --git a/kernel/ptrace.c b/kernel/ptrace.c index 0fc1eed..dc7ab65 100644 --- a/kernel/ptrace.c +++ b/kernel/ptrace.c @@ -22,6 +22,7 @@ #include #include #include +#include /* @@ -879,3 +880,19 @@ asmlinkage long compat_sys_ptrace(compat_long_t request, compat_long_t pid, return ret; } #endif /* CONFIG_COMPAT */ + +#ifdef CONFIG_HAVE_HW_BREAKPOINT +int ptrace_get_breakpoints(struct task_struct *tsk) +{ + if (atomic_inc_not_zero(&tsk->ptrace_bp_refcnt)) + return 0; + + return -1; +} + +void ptrace_put_breakpoints(struct task_struct *tsk) +{ + if (atomic_dec_and_test(&tsk->ptrace_bp_refcnt)) + flush_ptrace_hw_breakpoint(tsk); +} +#endif /* CONFIG_HAVE_HW_BREAKPOINT */ -- cgit v0.10.2 From 87dc669ba25777b67796d7262c569429e58b1ed4 Mon Sep 17 00:00:00 2001 From: Frederic Weisbecker Date: Fri, 8 Apr 2011 17:29:36 +0200 Subject: x86, hw_breakpoints: Fix racy access to ptrace breakpoints While the tracer accesses ptrace breakpoints, the child task may concurrently exit due to a SIGKILL and thus release its breakpoints at the same time. We can then dereference some freed pointers. To fix this, hold a reference on the child breakpoints before manipulating them. Reported-by: Oleg Nesterov Signed-off-by: Frederic Weisbecker Cc: Ingo Molnar Cc: Peter Zijlstra Cc: Will Deacon Cc: Prasad Cc: Paul Mundt Cc: v2.6.33.. Link: http://lkml.kernel.org/r/1302284067-7860-3-git-send-email-fweisbec@gmail.com diff --git a/arch/x86/kernel/ptrace.c b/arch/x86/kernel/ptrace.c index 45892dc..f65e5b5 100644 --- a/arch/x86/kernel/ptrace.c +++ b/arch/x86/kernel/ptrace.c @@ -608,6 +608,9 @@ static int ptrace_write_dr7(struct task_struct *tsk, unsigned long data) unsigned len, type; struct perf_event *bp; + if (ptrace_get_breakpoints(tsk) < 0) + return -ESRCH; + data &= ~DR_CONTROL_RESERVED; old_dr7 = ptrace_get_dr7(thread->ptrace_bps); restore: @@ -655,6 +658,9 @@ restore: } goto restore; } + + ptrace_put_breakpoints(tsk); + return ((orig_ret < 0) ? orig_ret : rc); } @@ -668,10 +674,17 @@ static unsigned long ptrace_get_debugreg(struct task_struct *tsk, int n) if (n < HBP_NUM) { struct perf_event *bp; + + if (ptrace_get_breakpoints(tsk) < 0) + return -ESRCH; + bp = thread->ptrace_bps[n]; if (!bp) - return 0; - val = bp->hw.info.address; + val = 0; + else + val = bp->hw.info.address; + + ptrace_put_breakpoints(tsk); } else if (n == 6) { val = thread->debugreg6; } else if (n == 7) { @@ -686,6 +699,10 @@ static int ptrace_set_breakpoint_addr(struct task_struct *tsk, int nr, struct perf_event *bp; struct thread_struct *t = &tsk->thread; struct perf_event_attr attr; + int err = 0; + + if (ptrace_get_breakpoints(tsk) < 0) + return -ESRCH; if (!t->ptrace_bps[nr]) { ptrace_breakpoint_init(&attr); @@ -709,24 +726,23 @@ static int ptrace_set_breakpoint_addr(struct task_struct *tsk, int nr, * writing for the user. And anyway this is the previous * behaviour. */ - if (IS_ERR(bp)) - return PTR_ERR(bp); + if (IS_ERR(bp)) { + err = PTR_ERR(bp); + goto put; + } t->ptrace_bps[nr] = bp; } else { - int err; - bp = t->ptrace_bps[nr]; attr = bp->attr; attr.bp_addr = addr; err = modify_user_hw_breakpoint(bp, &attr); - if (err) - return err; } - - return 0; +put: + ptrace_put_breakpoints(tsk); + return err; } /* -- cgit v0.10.2 From 07fa7a0a8a586c01a8b416358c7012dcb9dc688d Mon Sep 17 00:00:00 2001 From: Frederic Weisbecker Date: Fri, 8 Apr 2011 17:29:36 +0200 Subject: powerpc, hw_breakpoints: Fix racy access to ptrace breakpoints While the tracer accesses ptrace breakpoints, the child task may concurrently exit due to a SIGKILL and thus release its breakpoints at the same time. We can then dereference some freed pointers. To fix this, hold a reference on the child breakpoints before manipulating them. Reported-by: Oleg Nesterov Signed-off-by: Frederic Weisbecker Acked-by: Prasad Cc: Ingo Molnar Cc: Peter Zijlstra Cc: Will Deacon Cc: Paul Mundt Cc: v2.6.33.. Link: http://lkml.kernel.org/r/1302284067-7860-4-git-send-email-fweisbec@gmail.com diff --git a/arch/powerpc/kernel/ptrace.c b/arch/powerpc/kernel/ptrace.c index 55613e3..4edeeb3 100644 --- a/arch/powerpc/kernel/ptrace.c +++ b/arch/powerpc/kernel/ptrace.c @@ -1591,7 +1591,10 @@ long arch_ptrace(struct task_struct *child, long request, } case PTRACE_SET_DEBUGREG: + if (ptrace_get_breakpoints(child) < 0) + return -ESRCH; ret = ptrace_set_debugreg(child, addr, data); + ptrace_put_breakpoints(child); break; #ifdef CONFIG_PPC64 -- cgit v0.10.2 From bf0b8f4b55e591ba417c2dbaff42769e1fc773b0 Mon Sep 17 00:00:00 2001 From: Frederic Weisbecker Date: Fri, 8 Apr 2011 17:29:36 +0200 Subject: arm, hw_breakpoints: Fix racy access to ptrace breakpoints While the tracer accesses ptrace breakpoints, the child task may concurrently exit due to a SIGKILL and thus release its breakpoints at the same time. We can then dereference some freed pointers. To fix this, hold a reference on the child breakpoints before manipulating them. Reported-by: Oleg Nesterov Signed-off-by: Frederic Weisbecker Acked-by: Will Deacon Cc: Ingo Molnar Cc: Peter Zijlstra Cc: Prasad Cc: Paul Mundt Link: http://lkml.kernel.org/r/1302284067-7860-5-git-send-email-fweisbec@gmail.com diff --git a/arch/arm/kernel/ptrace.c b/arch/arm/kernel/ptrace.c index 2bf27f3..8182f45 100644 --- a/arch/arm/kernel/ptrace.c +++ b/arch/arm/kernel/ptrace.c @@ -767,12 +767,20 @@ long arch_ptrace(struct task_struct *child, long request, #ifdef CONFIG_HAVE_HW_BREAKPOINT case PTRACE_GETHBPREGS: + if (ptrace_get_breakpoints(child) < 0) + return -ESRCH; + ret = ptrace_gethbpregs(child, addr, (unsigned long __user *)data); + ptrace_put_breakpoints(child); break; case PTRACE_SETHBPREGS: + if (ptrace_get_breakpoints(child) < 0) + return -ESRCH; + ret = ptrace_sethbpregs(child, addr, (unsigned long __user *)data); + ptrace_put_breakpoints(child); break; #endif -- cgit v0.10.2 From e0ac8457d020c0289ea566917267da9e5e6d9865 Mon Sep 17 00:00:00 2001 From: Frederic Weisbecker Date: Fri, 8 Apr 2011 17:29:36 +0200 Subject: sh, hw_breakpoints: Fix racy access to ptrace breakpoints While the tracer accesses ptrace breakpoints, the child task may concurrently exit due to a SIGKILL and thus release its breakpoints at the same time. We can then dereference some freed pointers. To fix this, hold a reference on the child breakpoints before manipulating them. Reported-by: Oleg Nesterov Signed-off-by: Frederic Weisbecker Acked-by: Paul Mundt Cc: Ingo Molnar Cc: Peter Zijlstra Cc: Will Deacon Cc: Prasad Link: http://lkml.kernel.org/r/1302284067-7860-6-git-send-email-fweisbec@gmail.com diff --git a/arch/sh/kernel/ptrace_32.c b/arch/sh/kernel/ptrace_32.c index 2130ca6..3d7b209 100644 --- a/arch/sh/kernel/ptrace_32.c +++ b/arch/sh/kernel/ptrace_32.c @@ -117,7 +117,11 @@ void user_enable_single_step(struct task_struct *child) set_tsk_thread_flag(child, TIF_SINGLESTEP); + if (ptrace_get_breakpoints(child) < 0) + return; + set_single_step(child, pc); + ptrace_put_breakpoints(child); } void user_disable_single_step(struct task_struct *child) -- cgit v0.10.2 From b99a7be47dc37c60b6524d761ecfce432de84c01 Mon Sep 17 00:00:00 2001 From: Vasanthakumar Thiagarajan Date: Tue, 19 Apr 2011 19:28:59 +0530 Subject: ath9k_hw: Define devid and mac version for AR9340 Signed-off-by: Vasanthakumar Thiagarajan Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index 3a8c41c..d98b4c6 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c @@ -552,7 +552,7 @@ static int __ath9k_hw_init(struct ath_hw *ah) return -EOPNOTSUPP; } - if (AR_SREV_9271(ah) || AR_SREV_9100(ah)) + if (AR_SREV_9271(ah) || AR_SREV_9100(ah) || AR_SREV_9340(ah)) ah->is_pciexpress = false; ah->hw_version.phyRev = REG_READ(ah, AR_PHY_CHIP_ID); diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h index 1018d6c..450b642 100644 --- a/drivers/net/wireless/ath/ath9k/hw.h +++ b/drivers/net/wireless/ath/ath9k/hw.h @@ -43,6 +43,7 @@ #define AR9287_DEVID_PCI 0x002d #define AR9287_DEVID_PCIE 0x002e #define AR9300_DEVID_PCIE 0x0030 +#define AR9300_DEVID_AR9340 0x0031 #define AR9300_DEVID_AR9485_PCIE 0x0032 #define AR5416_AR9100_DEVID 0x000b diff --git a/drivers/net/wireless/ath/ath9k/reg.h b/drivers/net/wireless/ath/ath9k/reg.h index 6acbf0e..1bf5405 100644 --- a/drivers/net/wireless/ath/ath9k/reg.h +++ b/drivers/net/wireless/ath/ath9k/reg.h @@ -790,6 +790,7 @@ #define AR_SREV_VERSION_9485 0x240 #define AR_SREV_REVISION_9485_10 0 #define AR_SREV_REVISION_9485_11 1 +#define AR_SREV_VERSION_9340 0x300 #define AR_SREV_5416(_ah) \ (((_ah)->hw_version.macVersion == AR_SREV_VERSION_5416_PCI) || \ @@ -869,6 +870,9 @@ (AR_SREV_9485(_ah) && \ ((_ah)->hw_version.macRev == AR_SREV_REVISION_9485_11)) +#define AR_SREV_9340(_ah) \ + (((_ah)->hw_version.macVersion == AR_SREV_VERSION_9340)) + #define AR_SREV_9285E_20(_ah) \ (AR_SREV_9285_12_OR_LATER(_ah) && \ ((REG_READ(_ah, AR_AN_SYNTH9) & 0x7) == 0x1)) -- cgit v0.10.2 From 35d5f56125aba8667ac12277dff02ce51efbee16 Mon Sep 17 00:00:00 2001 From: Vasanthakumar Thiagarajan Date: Tue, 19 Apr 2011 19:29:00 +0530 Subject: ath9k_hw: Take care of few host interface register changes for AR9340 Signed-off-by: Vasanthakumar Thiagarajan Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/reg.h b/drivers/net/wireless/ath/ath9k/reg.h index 1bf5405..42d9f1b 100644 --- a/drivers/net/wireless/ath/ath9k/reg.h +++ b/drivers/net/wireless/ath/ath9k/reg.h @@ -693,7 +693,7 @@ #define AR_RC_APB 0x00000002 #define AR_RC_HOSTIF 0x00000100 -#define AR_WA 0x4004 +#define AR_WA (AR_SREV_9340(ah) ? 0x40c4 : 0x4004) #define AR_WA_BIT6 (1 << 6) #define AR_WA_BIT7 (1 << 7) #define AR_WA_BIT23 (1 << 23) @@ -712,7 +712,7 @@ #define AR_PM_STATE 0x4008 #define AR_PM_STATE_PME_D3COLD_VAUX 0x00100000 -#define AR_HOST_TIMEOUT 0x4018 +#define AR_HOST_TIMEOUT (AR_SREV_9340(ah) ? 0x4008 : 0x4018) #define AR_HOST_TIMEOUT_APB_CNTR 0x0000FFFF #define AR_HOST_TIMEOUT_APB_CNTR_S 0 #define AR_HOST_TIMEOUT_LCL_CNTR 0xFFFF0000 @@ -742,7 +742,8 @@ #define EEPROM_PROTECT_WP_1024_2047 0x8000 #define AR_SREV \ - ((AR_SREV_9100(ah)) ? 0x0600 : 0x4020) + ((AR_SREV_9100(ah)) ? 0x0600 : (AR_SREV_9340(ah) \ + ? 0x400c : 0x4020)) #define AR_SREV_ID \ ((AR_SREV_9100(ah)) ? 0x00000FFF : 0x000000FF) @@ -914,11 +915,11 @@ enum ath_usb_dev { #define AR_INTR_SPURIOUS 0xFFFFFFFF -#define AR_INTR_SYNC_CAUSE_CLR 0x4028 +#define AR_INTR_SYNC_CAUSE (AR_SREV_9340(ah) ? 0x4010 : 0x4028) +#define AR_INTR_SYNC_CAUSE_CLR (AR_SREV_9340(ah) ? 0x4010 : 0x4028) -#define AR_INTR_SYNC_CAUSE 0x4028 -#define AR_INTR_SYNC_ENABLE 0x402c +#define AR_INTR_SYNC_ENABLE (AR_SREV_9340(ah) ? 0x4014 : 0x402c) #define AR_INTR_SYNC_ENABLE_GPIO 0xFFFC0000 #define AR_INTR_SYNC_ENABLE_GPIO_S 18 @@ -958,24 +959,24 @@ enum { }; -#define AR_INTR_ASYNC_MASK 0x4030 +#define AR_INTR_ASYNC_MASK (AR_SREV_9340(ah) ? 0x4018 : 0x4030) #define AR_INTR_ASYNC_MASK_GPIO 0xFFFC0000 #define AR_INTR_ASYNC_MASK_GPIO_S 18 -#define AR_INTR_SYNC_MASK 0x4034 +#define AR_INTR_SYNC_MASK (AR_SREV_9340(ah) ? 0x401c : 0x4034) #define AR_INTR_SYNC_MASK_GPIO 0xFFFC0000 #define AR_INTR_SYNC_MASK_GPIO_S 18 -#define AR_INTR_ASYNC_CAUSE_CLR 0x4038 -#define AR_INTR_ASYNC_CAUSE 0x4038 +#define AR_INTR_ASYNC_CAUSE_CLR (AR_SREV_9340(ah) ? 0x4020 : 0x4038) +#define AR_INTR_ASYNC_CAUSE (AR_SREV_9340(ah) ? 0x4020 : 0x4038) -#define AR_INTR_ASYNC_ENABLE 0x403c +#define AR_INTR_ASYNC_ENABLE (AR_SREV_9340(ah) ? 0x4024 : 0x403c) #define AR_INTR_ASYNC_ENABLE_GPIO 0xFFFC0000 #define AR_INTR_ASYNC_ENABLE_GPIO_S 18 #define AR_PCIE_SERDES 0x4040 #define AR_PCIE_SERDES2 0x4044 -#define AR_PCIE_PM_CTRL 0x4014 +#define AR_PCIE_PM_CTRL (AR_SREV_9340(ah) ? 0x4004 : 0x4014) #define AR_PCIE_PM_CTRL_ENA 0x00080000 #define AR_NUM_GPIO 14 @@ -986,7 +987,7 @@ enum { #define AR9300_NUM_GPIO 17 #define AR7010_NUM_GPIO 16 -#define AR_GPIO_IN_OUT 0x4048 +#define AR_GPIO_IN_OUT (AR_SREV_9340(ah) ? 0x4028 : 0x4048) #define AR_GPIO_IN_VAL 0x0FFFC000 #define AR_GPIO_IN_VAL_S 14 #define AR928X_GPIO_IN_VAL 0x000FFC00 @@ -1000,11 +1001,12 @@ enum { #define AR7010_GPIO_IN_VAL 0x0000FFFF #define AR7010_GPIO_IN_VAL_S 0 -#define AR_GPIO_IN 0x404c +#define AR_GPIO_IN (AR_SREV_9340(ah) ? 0x402c : 0x404c) #define AR9300_GPIO_IN_VAL 0x0001FFFF #define AR9300_GPIO_IN_VAL_S 0 -#define AR_GPIO_OE_OUT (AR_SREV_9300_20_OR_LATER(ah) ? 0x4050 : 0x404c) +#define AR_GPIO_OE_OUT (AR_SREV_9340(ah) ? 0x4030 : \ + (AR_SREV_9300_20_OR_LATER(ah) ? 0x4050 : 0x404c)) #define AR_GPIO_OE_OUT_DRV 0x3 #define AR_GPIO_OE_OUT_DRV_NO 0x0 #define AR_GPIO_OE_OUT_DRV_LOW 0x1 @@ -1026,11 +1028,13 @@ enum { #define AR7010_GPIO_INT_MASK 0x52024 #define AR7010_GPIO_FUNCTION 0x52028 -#define AR_GPIO_INTR_POL (AR_SREV_9300_20_OR_LATER(ah) ? 0x4058 : 0x4050) +#define AR_GPIO_INTR_POL (AR_SREV_9340(ah) ? 0x4038 : \ + (AR_SREV_9300_20_OR_LATER(ah) ? 0x4058 : 0x4050)) #define AR_GPIO_INTR_POL_VAL 0x0001FFFF #define AR_GPIO_INTR_POL_VAL_S 0 -#define AR_GPIO_INPUT_EN_VAL (AR_SREV_9300_20_OR_LATER(ah) ? 0x405c : 0x4054) +#define AR_GPIO_INPUT_EN_VAL (AR_SREV_9340(ah) ? 0x403c : \ + (AR_SREV_9300_20_OR_LATER(ah) ? 0x405c : 0x4054)) #define AR_GPIO_INPUT_EN_VAL_BT_PRIORITY_DEF 0x00000004 #define AR_GPIO_INPUT_EN_VAL_BT_PRIORITY_S 2 #define AR_GPIO_INPUT_EN_VAL_BT_FREQUENCY_DEF 0x00000008 @@ -1048,13 +1052,15 @@ enum { #define AR_GPIO_RTC_RESET_OVERRIDE_ENABLE 0x00010000 #define AR_GPIO_JTAG_DISABLE 0x00020000 -#define AR_GPIO_INPUT_MUX1 (AR_SREV_9300_20_OR_LATER(ah) ? 0x4060 : 0x4058) +#define AR_GPIO_INPUT_MUX1 (AR_SREV_9340(ah) ? 0x4040 : \ + (AR_SREV_9300_20_OR_LATER(ah) ? 0x4060 : 0x4058)) #define AR_GPIO_INPUT_MUX1_BT_ACTIVE 0x000f0000 #define AR_GPIO_INPUT_MUX1_BT_ACTIVE_S 16 #define AR_GPIO_INPUT_MUX1_BT_PRIORITY 0x00000f00 #define AR_GPIO_INPUT_MUX1_BT_PRIORITY_S 8 -#define AR_GPIO_INPUT_MUX2 (AR_SREV_9300_20_OR_LATER(ah) ? 0x4064 : 0x405c) +#define AR_GPIO_INPUT_MUX2 (AR_SREV_9340(ah) ? 0x4044 : \ + (AR_SREV_9300_20_OR_LATER(ah) ? 0x4064 : 0x405c)) #define AR_GPIO_INPUT_MUX2_CLK25 0x0000000f #define AR_GPIO_INPUT_MUX2_CLK25_S 0 #define AR_GPIO_INPUT_MUX2_RFSILENT 0x000000f0 @@ -1062,13 +1068,18 @@ enum { #define AR_GPIO_INPUT_MUX2_RTC_RESET 0x00000f00 #define AR_GPIO_INPUT_MUX2_RTC_RESET_S 8 -#define AR_GPIO_OUTPUT_MUX1 (AR_SREV_9300_20_OR_LATER(ah) ? 0x4068 : 0x4060) -#define AR_GPIO_OUTPUT_MUX2 (AR_SREV_9300_20_OR_LATER(ah) ? 0x406c : 0x4064) -#define AR_GPIO_OUTPUT_MUX3 (AR_SREV_9300_20_OR_LATER(ah) ? 0x4070 : 0x4068) +#define AR_GPIO_OUTPUT_MUX1 (AR_SREV_9340(ah) ? 0x4048 : \ + (AR_SREV_9300_20_OR_LATER(ah) ? 0x4068 : 0x4060)) +#define AR_GPIO_OUTPUT_MUX2 (AR_SREV_9340(ah) ? 0x404c : \ + (AR_SREV_9300_20_OR_LATER(ah) ? 0x406c : 0x4064)) +#define AR_GPIO_OUTPUT_MUX3 (AR_SREV_9340(ah) ? 0x4050 : \ + (AR_SREV_9300_20_OR_LATER(ah) ? 0x4070 : 0x4068)) -#define AR_INPUT_STATE (AR_SREV_9300_20_OR_LATER(ah) ? 0x4074 : 0x406c) +#define AR_INPUT_STATE (AR_SREV_9340(ah) ? 0x4054 : \ + (AR_SREV_9300_20_OR_LATER(ah) ? 0x4074 : 0x406c)) -#define AR_EEPROM_STATUS_DATA (AR_SREV_9300_20_OR_LATER(ah) ? 0x4084 : 0x407c) +#define AR_EEPROM_STATUS_DATA (AR_SREV_9340(ah) ? 0x40c8 : \ + (AR_SREV_9300_20_OR_LATER(ah) ? 0x4084 : 0x407c)) #define AR_EEPROM_STATUS_DATA_VAL 0x0000ffff #define AR_EEPROM_STATUS_DATA_VAL_S 0 #define AR_EEPROM_STATUS_DATA_BUSY 0x00010000 @@ -1076,17 +1087,19 @@ enum { #define AR_EEPROM_STATUS_DATA_PROT_ACCESS 0x00040000 #define AR_EEPROM_STATUS_DATA_ABSENT_ACCESS 0x00080000 -#define AR_OBS (AR_SREV_9300_20_OR_LATER(ah) ? 0x4088 : 0x4080) +#define AR_OBS (AR_SREV_9340(ah) ? 0x405c : \ + (AR_SREV_9300_20_OR_LATER(ah) ? 0x4088 : 0x4080)) #define AR_GPIO_PDPU (AR_SREV_9300_20_OR_LATER(ah) ? 0x4090 : 0x4088) -#define AR_PCIE_MSI (AR_SREV_9300_20_OR_LATER(ah) ? 0x40a4 : 0x4094) +#define AR_PCIE_MSI (AR_SREV_9340(ah) ? 0x40d8 : \ + (AR_SREV_9300_20_OR_LATER(ah) ? 0x40a4 : 0x4094)) #define AR_PCIE_MSI_ENABLE 0x00000001 -#define AR_INTR_PRIO_SYNC_ENABLE 0x40c4 -#define AR_INTR_PRIO_ASYNC_MASK 0x40c8 -#define AR_INTR_PRIO_SYNC_MASK 0x40cc -#define AR_INTR_PRIO_ASYNC_ENABLE 0x40d4 +#define AR_INTR_PRIO_SYNC_ENABLE (AR_SREV_9340(ah) ? 0x4088 : 0x40c4) +#define AR_INTR_PRIO_ASYNC_MASK (AR_SREV_9340(ah) ? 0x408c : 0x40c8) +#define AR_INTR_PRIO_SYNC_MASK (AR_SREV_9340(ah) ? 0x4090 : 0x40cc) +#define AR_INTR_PRIO_ASYNC_ENABLE (AR_SREV_9340(ah) ? 0x4094 : 0x40d4) #define AR_ENT_OTP 0x40d8 #define AR_ENT_OTP_CHAIN2_DISABLE 0x00020000 #define AR_ENT_OTP_MPSD 0x00800000 -- cgit v0.10.2 From f2f5f2a1cedc803a5a517557d436e6cb10c007de Mon Sep 17 00:00:00 2001 From: Vasanthakumar Thiagarajan Date: Tue, 19 Apr 2011 19:29:01 +0530 Subject: ath9k_hw: Get AHB clock information from ath9k_platform_data Add a bool in ath9k_platform_data to pass AHB clock speed information. Driver needs this to configure PLL on some SOCs. Signed-off-by: Vasanthakumar Thiagarajan Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h index 450b642..5a4ba09 100644 --- a/drivers/net/wireless/ath/ath9k/hw.h +++ b/drivers/net/wireless/ath/ath9k/hw.h @@ -846,6 +846,8 @@ struct ath_hw { /* Enterprise mode cap */ u32 ent_mode; + + bool is_clk_25mhz; }; struct ath_bus_ops { diff --git a/drivers/net/wireless/ath/ath9k/init.c b/drivers/net/wireless/ath/ath9k/init.c index 1ac8318..e78b6ae 100644 --- a/drivers/net/wireless/ath/ath9k/init.c +++ b/drivers/net/wireless/ath/ath9k/init.c @@ -574,6 +574,7 @@ static int ath9k_init_softc(u16 devid, struct ath_softc *sc, u16 subsysid, sc->sc_ah->gpio_mask = pdata->gpio_mask; sc->sc_ah->gpio_val = pdata->gpio_val; sc->sc_ah->led_pin = pdata->led_pin; + ah->is_clk_25mhz = pdata->is_clk_25mhz; } common = ath9k_hw_common(ah); diff --git a/include/linux/ath9k_platform.h b/include/linux/ath9k_platform.h index 020387a..60a7c49 100644 --- a/include/linux/ath9k_platform.h +++ b/include/linux/ath9k_platform.h @@ -28,6 +28,8 @@ struct ath9k_platform_data { int led_pin; u32 gpio_mask; u32 gpio_val; + + bool is_clk_25mhz; }; #endif /* _LINUX_ATH9K_PLATFORM_H */ -- cgit v0.10.2 From 0b488ac6ece598fda69b5f3348015994129c48b9 Mon Sep 17 00:00:00 2001 From: Vasanthakumar Thiagarajan Date: Wed, 20 Apr 2011 10:26:15 +0530 Subject: ath9k_hw: Configure pll control register accordingly for AR9340 Signed-off-by: Vasanthakumar Thiagarajan Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index d98b4c6..a1eaace 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c @@ -716,13 +716,48 @@ static void ath9k_hw_init_pll(struct ath_hw *ah, REG_RMW_FIELD(ah, AR_CH0_BB_DPLL3, AR_CH0_DPLL3_PHASE_SHIFT, DPLL3_PHASE_SHIFT_VAL); + } else if (AR_SREV_9340(ah)) { + u32 regval, pll2_divint, pll2_divfrac, refdiv; + + REG_WRITE(ah, AR_RTC_PLL_CONTROL, 0x1142c); + udelay(1000); + + REG_SET_BIT(ah, AR_PHY_PLL_MODE, 0x1 << 16); + udelay(100); + + if (ah->is_clk_25mhz) { + pll2_divint = 0x54; + pll2_divfrac = 0x1eb85; + refdiv = 3; + } else { + pll2_divint = 88; + pll2_divfrac = 0; + refdiv = 5; + } + + regval = REG_READ(ah, AR_PHY_PLL_MODE); + regval |= (0x1 << 16); + REG_WRITE(ah, AR_PHY_PLL_MODE, regval); + udelay(100); + + REG_WRITE(ah, AR_PHY_PLL_CONTROL, (refdiv << 27) | + (pll2_divint << 18) | pll2_divfrac); + udelay(100); + + regval = REG_READ(ah, AR_PHY_PLL_MODE); + regval = (regval & 0x80071fff) | (0x1 << 30) | (0x1 << 13) | + (0x4 << 26) | (0x18 << 19); + REG_WRITE(ah, AR_PHY_PLL_MODE, regval); + REG_WRITE(ah, AR_PHY_PLL_MODE, + REG_READ(ah, AR_PHY_PLL_MODE) & 0xfffeffff); + udelay(1000); } pll = ath9k_hw_compute_pll_control(ah, chan); REG_WRITE(ah, AR_RTC_PLL_CONTROL, pll); - if (AR_SREV_9485(ah)) + if (AR_SREV_9485(ah) || AR_SREV_9340(ah)) udelay(1000); /* Switch the core clock for ar9271 to 117Mhz */ @@ -734,6 +769,19 @@ static void ath9k_hw_init_pll(struct ath_hw *ah, udelay(RTC_PLL_SETTLE_DELAY); REG_WRITE(ah, AR_RTC_SLEEP_CLK, AR_RTC_FORCE_DERIVED_CLK); + + if (AR_SREV_9340(ah)) { + if (ah->is_clk_25mhz) { + REG_WRITE(ah, AR_RTC_DERIVED_CLK, 0x17c << 1); + REG_WRITE(ah, AR_SLP32_MODE, 0x0010f3d7); + REG_WRITE(ah, AR_SLP32_INC, 0x0001e7ae); + } else { + REG_WRITE(ah, AR_RTC_DERIVED_CLK, 0x261 << 1); + REG_WRITE(ah, AR_SLP32_MODE, 0x0010f400); + REG_WRITE(ah, AR_SLP32_INC, 0x0001e800); + } + udelay(100); + } } static void ath9k_hw_init_interrupt_masks(struct ath_hw *ah, diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h index 5a4ba09..9b1f415 100644 --- a/drivers/net/wireless/ath/ath9k/hw.h +++ b/drivers/net/wireless/ath/ath9k/hw.h @@ -122,7 +122,7 @@ #define AR_GPIO_BIT(_gpio) (1 << (_gpio)) #define BASE_ACTIVATE_DELAY 100 -#define RTC_PLL_SETTLE_DELAY 100 +#define RTC_PLL_SETTLE_DELAY (AR_SREV_9340(ah) ? 1000 : 100) #define COEF_SCALE_S 24 #define HT40_CHANNEL_CENTER_SHIFT 10 diff --git a/drivers/net/wireless/ath/ath9k/phy.h b/drivers/net/wireless/ath/ath9k/phy.h index 8e5fe9d..9441bf8 100644 --- a/drivers/net/wireless/ath/ath9k/phy.h +++ b/drivers/net/wireless/ath/ath9k/phy.h @@ -45,4 +45,7 @@ #define AR_PHY_TIMING11_SPUR_FREQ_SD 0x3FF00000 #define AR_PHY_TIMING11_SPUR_FREQ_SD_S 20 +#define AR_PHY_PLL_CONTROL 0x16180 +#define AR_PHY_PLL_MODE 0x16184 + #endif diff --git a/drivers/net/wireless/ath/ath9k/reg.h b/drivers/net/wireless/ath/ath9k/reg.h index 42d9f1b..b42e36c 100644 --- a/drivers/net/wireless/ath/ath9k/reg.h +++ b/drivers/net/wireless/ath/ath9k/reg.h @@ -1180,6 +1180,7 @@ enum { #define AR_RTC_PLL_REFDIV_5 0x000000c0 #define AR_RTC_PLL_CLKSEL 0x00000300 #define AR_RTC_PLL_CLKSEL_S 8 +#define AR_RTC_PLL_BYPASS 0x00010000 #define PLL3 0x16188 #define PLL3_DO_MEAS_MASK 0x40000000 @@ -1226,7 +1227,8 @@ enum { /* RTC_DERIVED_* - only for AR9100 */ -#define AR_RTC_DERIVED_CLK (AR_RTC_BASE + 0x0038) +#define AR_RTC_DERIVED_CLK \ + (AR_SREV_9100(ah) ? (AR_RTC_BASE + 0x0038) : 0x7038) #define AR_RTC_DERIVED_CLK_PERIOD 0x0000fffe #define AR_RTC_DERIVED_CLK_PERIOD_S 1 -- cgit v0.10.2 From 9aa5a8d5fd519d61a947c797cb917b38fd156cff Mon Sep 17 00:00:00 2001 From: Vasanthakumar Thiagarajan Date: Tue, 19 Apr 2011 19:29:03 +0530 Subject: ath9k_hw: Add initvals.h for ar9340 Signed-off-by: Vasanthakumar Thiagarajan Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/ar9340_initvals.h b/drivers/net/wireless/ath/ath9k/ar9340_initvals.h new file mode 100644 index 0000000..815a8af --- /dev/null +++ b/drivers/net/wireless/ath/ath9k/ar9340_initvals.h @@ -0,0 +1,1525 @@ +/* + * Copyright (c) 2011 Atheros Communications Inc. + * + * 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. + */ + +#ifndef INITVALS_9340_H +#define INITVALS_9340_H + +static const u32 ar9340_1p0_radio_postamble[][5] = { + /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ + {0x000160ac, 0xa4646800, 0xa4646800, 0xa4646800, 0xa4646800}, + {0x0001610c, 0x08000000, 0x08000000, 0x00000000, 0x00000000}, + {0x00016140, 0x10804000, 0x10804000, 0x50804000, 0x50804000}, + {0x0001650c, 0x08000000, 0x08000000, 0x00000000, 0x00000000}, + {0x00016540, 0x10804000, 0x10804000, 0x50804000, 0x50804000}, +}; + +static const u32 ar9340Modes_lowest_ob_db_tx_gain_table_1p0[][5] = { + /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ + {0x0000a410, 0x000050d9, 0x000050d9, 0x000050d9, 0x000050d9}, + {0x0000a500, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000a504, 0x06000003, 0x06000003, 0x04000002, 0x04000002}, + {0x0000a508, 0x0a000020, 0x0a000020, 0x08000004, 0x08000004}, + {0x0000a50c, 0x10000023, 0x10000023, 0x0b000200, 0x0b000200}, + {0x0000a510, 0x16000220, 0x16000220, 0x0f000202, 0x0f000202}, + {0x0000a514, 0x1c000223, 0x1c000223, 0x12000400, 0x12000400}, + {0x0000a518, 0x21020220, 0x21020220, 0x16000402, 0x16000402}, + {0x0000a51c, 0x27020223, 0x27020223, 0x19000404, 0x19000404}, + {0x0000a520, 0x2b022220, 0x2b022220, 0x1c000603, 0x1c000603}, + {0x0000a524, 0x2f022222, 0x2f022222, 0x21000a02, 0x21000a02}, + {0x0000a528, 0x34022225, 0x34022225, 0x25000a04, 0x25000a04}, + {0x0000a52c, 0x3a02222a, 0x3a02222a, 0x28000a20, 0x28000a20}, + {0x0000a530, 0x3e02222c, 0x3e02222c, 0x2c000e20, 0x2c000e20}, + {0x0000a534, 0x4202242a, 0x4202242a, 0x30000e22, 0x30000e22}, + {0x0000a538, 0x4702244a, 0x4702244a, 0x34000e24, 0x34000e24}, + {0x0000a53c, 0x4b02244c, 0x4b02244c, 0x38001640, 0x38001640}, + {0x0000a540, 0x4e02246c, 0x4e02246c, 0x3c001660, 0x3c001660}, + {0x0000a544, 0x5302266c, 0x5302266c, 0x3f001861, 0x3f001861}, + {0x0000a548, 0x5702286c, 0x5702286c, 0x43001a81, 0x43001a81}, + {0x0000a54c, 0x5c04286b, 0x5c04286b, 0x47001a83, 0x47001a83}, + {0x0000a550, 0x61042a6c, 0x61042a6c, 0x4a001c84, 0x4a001c84}, + {0x0000a554, 0x66062a6c, 0x66062a6c, 0x4e001ce3, 0x4e001ce3}, + {0x0000a558, 0x6b062e6c, 0x6b062e6c, 0x52001ce5, 0x52001ce5}, + {0x0000a55c, 0x7006308c, 0x7006308c, 0x56001ce9, 0x56001ce9}, + {0x0000a560, 0x730a308a, 0x730a308a, 0x5a001ceb, 0x5a001ceb}, + {0x0000a564, 0x770a308c, 0x770a308c, 0x5d001eec, 0x5d001eec}, + {0x0000a568, 0x770a308c, 0x770a308c, 0x5d001eec, 0x5d001eec}, + {0x0000a56c, 0x770a308c, 0x770a308c, 0x5d001eec, 0x5d001eec}, + {0x0000a570, 0x770a308c, 0x770a308c, 0x5d001eec, 0x5d001eec}, + {0x0000a574, 0x770a308c, 0x770a308c, 0x5d001eec, 0x5d001eec}, + {0x0000a578, 0x770a308c, 0x770a308c, 0x5d001eec, 0x5d001eec}, + {0x0000a57c, 0x770a308c, 0x770a308c, 0x5d001eec, 0x5d001eec}, + {0x0000a580, 0x00800000, 0x00800000, 0x00800000, 0x00800000}, + {0x0000a584, 0x06800003, 0x06800003, 0x04800002, 0x04800002}, + {0x0000a588, 0x0a800020, 0x0a800020, 0x08800004, 0x08800004}, + {0x0000a58c, 0x10800023, 0x10800023, 0x0b800200, 0x0b800200}, + {0x0000a590, 0x16800220, 0x16800220, 0x0f800202, 0x0f800202}, + {0x0000a594, 0x1c800223, 0x1c800223, 0x12800400, 0x12800400}, + {0x0000a598, 0x21820220, 0x21820220, 0x16800402, 0x16800402}, + {0x0000a59c, 0x27820223, 0x27820223, 0x19800404, 0x19800404}, + {0x0000a5a0, 0x2b822220, 0x2b822220, 0x1c800603, 0x1c800603}, + {0x0000a5a4, 0x2f822222, 0x2f822222, 0x21800a02, 0x21800a02}, + {0x0000a5a8, 0x34822225, 0x34822225, 0x25800a04, 0x25800a04}, + {0x0000a5ac, 0x3a82222a, 0x3a82222a, 0x28800a20, 0x28800a20}, + {0x0000a5b0, 0x3e82222c, 0x3e82222c, 0x2c800e20, 0x2c800e20}, + {0x0000a5b4, 0x4282242a, 0x4282242a, 0x30800e22, 0x30800e22}, + {0x0000a5b8, 0x4782244a, 0x4782244a, 0x34800e24, 0x34800e24}, + {0x0000a5bc, 0x4b82244c, 0x4b82244c, 0x38801640, 0x38801640}, + {0x0000a5c0, 0x4e82246c, 0x4e82246c, 0x3c801660, 0x3c801660}, + {0x0000a5c4, 0x5382266c, 0x5382266c, 0x3f801861, 0x3f801861}, + {0x0000a5c8, 0x5782286c, 0x5782286c, 0x43801a81, 0x43801a81}, + {0x0000a5cc, 0x5c84286b, 0x5c84286b, 0x47801a83, 0x47801a83}, + {0x0000a5d0, 0x61842a6c, 0x61842a6c, 0x4a801c84, 0x4a801c84}, + {0x0000a5d4, 0x66862a6c, 0x66862a6c, 0x4e801ce3, 0x4e801ce3}, + {0x0000a5d8, 0x6b862e6c, 0x6b862e6c, 0x52801ce5, 0x52801ce5}, + {0x0000a5dc, 0x7086308c, 0x7086308c, 0x56801ce9, 0x56801ce9}, + {0x0000a5e0, 0x738a308a, 0x738a308a, 0x5a801ceb, 0x5a801ceb}, + {0x0000a5e4, 0x778a308c, 0x778a308c, 0x5d801eec, 0x5d801eec}, + {0x0000a5e8, 0x778a308c, 0x778a308c, 0x5d801eec, 0x5d801eec}, + {0x0000a5ec, 0x778a308c, 0x778a308c, 0x5d801eec, 0x5d801eec}, + {0x0000a5f0, 0x778a308c, 0x778a308c, 0x5d801eec, 0x5d801eec}, + {0x0000a5f4, 0x778a308c, 0x778a308c, 0x5d801eec, 0x5d801eec}, + {0x0000a5f8, 0x778a308c, 0x778a308c, 0x5d801eec, 0x5d801eec}, + {0x0000a5fc, 0x778a308c, 0x778a308c, 0x5d801eec, 0x5d801eec}, + {0x00016044, 0x056db2db, 0x056db2db, 0x056db2db, 0x056db2db}, + {0x00016048, 0x24925266, 0x24925266, 0x24925266, 0x24925266}, + {0x00016444, 0x056db2db, 0x056db2db, 0x056db2db, 0x056db2db}, + {0x00016448, 0x24925266, 0x24925266, 0x24925266, 0x24925266}, +}; + +static const u32 ar9340Modes_fast_clock_1p0[][3] = { + /* Addr 5G_HT20 5G_HT40 */ + {0x00001030, 0x00000268, 0x000004d0}, + {0x00001070, 0x0000018c, 0x00000318}, + {0x000010b0, 0x00000fd0, 0x00001fa0}, + {0x00008014, 0x044c044c, 0x08980898}, + {0x0000801c, 0x148ec02b, 0x148ec057}, + {0x00008318, 0x000044c0, 0x00008980}, + {0x00009e00, 0x03721821, 0x03721821}, + {0x0000a230, 0x0000000b, 0x00000016}, + {0x0000a254, 0x00000898, 0x00001130}, +}; + +static const u32 ar9340_1p0_radio_core[][2] = { + /* Addr allmodes */ + {0x00016000, 0x36db6db6}, + {0x00016004, 0x6db6db40}, + {0x00016008, 0x73f00000}, + {0x0001600c, 0x00000000}, + {0x00016040, 0x7f80fff8}, + {0x00016044, 0x03b6d2db}, + {0x00016048, 0x24925266}, + {0x0001604c, 0x000f0278}, + {0x00016050, 0x6db6db6c}, + {0x00016054, 0x6db60000}, + {0x00016080, 0x00080000}, + {0x00016084, 0x0e48048c}, + {0x00016088, 0x14214514}, + {0x0001608c, 0x119f081c}, + {0x00016090, 0x24926490}, + {0x00016094, 0x00000000}, + {0x00016098, 0xd411eb84}, + {0x0001609c, 0x03e47f32}, + {0x000160a0, 0xc2108ffe}, + {0x000160a4, 0x812fc370}, + {0x000160a8, 0x423c8000}, + {0x000160ac, 0xa4646800}, + {0x000160b0, 0x00fe7f46}, + {0x000160b4, 0x92480000}, + {0x000160c0, 0x006db6db}, + {0x000160c4, 0x6db6db60}, + {0x000160c8, 0x6db6db6c}, + {0x000160cc, 0x6de6db6c}, + {0x000160d0, 0xb6da4924}, + {0x00016100, 0x04cb0001}, + {0x00016104, 0xfff80000}, + {0x00016108, 0x00080010}, + {0x0001610c, 0x00000000}, + {0x00016140, 0x50804008}, + {0x00016144, 0x01884080}, + {0x00016148, 0x000080c0}, + {0x00016280, 0x01000015}, + {0x00016284, 0x05530000}, + {0x00016288, 0x00318000}, + {0x0001628c, 0x50000000}, + {0x00016290, 0x4080294f}, + {0x00016380, 0x00000000}, + {0x00016384, 0x00000000}, + {0x00016388, 0x00800700}, + {0x0001638c, 0x00800700}, + {0x00016390, 0x00800700}, + {0x00016394, 0x00000000}, + {0x00016398, 0x00000000}, + {0x0001639c, 0x00000000}, + {0x000163a0, 0x00000001}, + {0x000163a4, 0x00000001}, + {0x000163a8, 0x00000000}, + {0x000163ac, 0x00000000}, + {0x000163b0, 0x00000000}, + {0x000163b4, 0x00000000}, + {0x000163b8, 0x00000000}, + {0x000163bc, 0x00000000}, + {0x000163c0, 0x000000a0}, + {0x000163c4, 0x000c0000}, + {0x000163c8, 0x14021402}, + {0x000163cc, 0x00001402}, + {0x000163d0, 0x00000000}, + {0x000163d4, 0x00000000}, + {0x00016400, 0x36db6db6}, + {0x00016404, 0x6db6db40}, + {0x00016408, 0x73f00000}, + {0x0001640c, 0x00000000}, + {0x00016440, 0x7f80fff8}, + {0x00016444, 0x03b6d2db}, + {0x00016448, 0x24927266}, + {0x0001644c, 0x000f0278}, + {0x00016450, 0x6db6db6c}, + {0x00016454, 0x6db60000}, + {0x00016500, 0x04cb0001}, + {0x00016504, 0xfff80000}, + {0x00016508, 0x00080010}, + {0x0001650c, 0x00000000}, + {0x00016540, 0x50804008}, + {0x00016544, 0x01884080}, + {0x00016548, 0x000080c0}, + {0x00016780, 0x00000000}, + {0x00016784, 0x00000000}, + {0x00016788, 0x00800700}, + {0x0001678c, 0x00800700}, + {0x00016790, 0x00800700}, + {0x00016794, 0x00000000}, + {0x00016798, 0x00000000}, + {0x0001679c, 0x00000000}, + {0x000167a0, 0x00000001}, + {0x000167a4, 0x00000001}, + {0x000167a8, 0x00000000}, + {0x000167ac, 0x00000000}, + {0x000167b0, 0x00000000}, + {0x000167b4, 0x00000000}, + {0x000167b8, 0x00000000}, + {0x000167bc, 0x00000000}, + {0x000167c0, 0x000000a0}, + {0x000167c4, 0x000c0000}, + {0x000167c8, 0x14021402}, + {0x000167cc, 0x00001402}, + {0x000167d0, 0x00000000}, + {0x000167d4, 0x00000000}, +}; + +static const u32 ar9340_1p0_radio_core_40M[][2] = { + {0x0001609c, 0x02566f3a}, + {0x000160ac, 0xa4647c00}, + {0x000160b0, 0x01885f5a}, +}; + +static const u32 ar9340_1p0_mac_postamble[][5] = { + /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ + {0x00001030, 0x00000230, 0x00000460, 0x000002c0, 0x00000160}, + {0x00001070, 0x00000168, 0x000002d0, 0x00000318, 0x0000018c}, + {0x000010b0, 0x00000e60, 0x00001cc0, 0x00007c70, 0x00003e38}, + {0x00008014, 0x03e803e8, 0x07d007d0, 0x10801600, 0x08400b00}, + {0x0000801c, 0x128d8027, 0x128d804f, 0x12e00057, 0x12e0002b}, + {0x00008120, 0x08f04800, 0x08f04800, 0x08f04810, 0x08f04810}, + {0x000081d0, 0x00003210, 0x00003210, 0x0000320a, 0x0000320a}, + {0x00008318, 0x00003e80, 0x00007d00, 0x00006880, 0x00003440}, +}; + +static const u32 ar9340_1p0_soc_postamble[][5] = { + /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ + {0x00007010, 0x00000023, 0x00000023, 0x00000023, 0x00000023}, +}; + +static const u32 ar9340_1p0_baseband_postamble[][5] = { + /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ + {0x00009810, 0xd00a8005, 0xd00a8005, 0xd00a8011, 0xd00a8011}, + {0x00009820, 0x206a022e, 0x206a022e, 0x206a022e, 0x206a022e}, + {0x00009824, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0}, + {0x00009828, 0x06903081, 0x06903081, 0x06903881, 0x06903881}, + {0x0000982c, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4}, + {0x00009830, 0x0000059c, 0x0000059c, 0x0000119c, 0x0000119c}, + {0x00009c00, 0x00000044, 0x000000c4, 0x000000c4, 0x00000044}, + {0x00009e00, 0x0372161e, 0x0372161e, 0x037216a0, 0x037216a0}, + {0x00009e04, 0x00182020, 0x00182020, 0x00182020, 0x00182020}, + {0x00009e0c, 0x6c4000e2, 0x6d4000e2, 0x6d4000e2, 0x6c4000e2}, + {0x00009e10, 0x7ec88d2e, 0x7ec88d2e, 0x7ec88d2e, 0x7ec88d2e}, + {0x00009e14, 0x31395d5e, 0x3139605e, 0x3139605e, 0x31395d5e}, + {0x00009e18, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x00009e1c, 0x0001cf9c, 0x0001cf9c, 0x00021f9c, 0x00021f9c}, + {0x00009e20, 0x000003b5, 0x000003b5, 0x000003ce, 0x000003ce}, + {0x00009e2c, 0x0000001c, 0x0000001c, 0x00000021, 0x00000021}, + {0x00009e44, 0x02321e27, 0x02321e27, 0x02291e27, 0x02291e27}, + {0x00009e48, 0x5030201a, 0x5030201a, 0x50302012, 0x50302012}, + {0x00009fc8, 0x0003f000, 0x0003f000, 0x0001a000, 0x0001a000}, + {0x0000a204, 0x00003fc0, 0x00003fc4, 0x00003fc4, 0x00003fc0}, + {0x0000a208, 0x00000104, 0x00000104, 0x00000004, 0x00000004}, + {0x0000a230, 0x0000000a, 0x00000014, 0x00000016, 0x0000000b}, + {0x0000a238, 0xffb81018, 0xffb81018, 0xffb81018, 0xffb81018}, + {0x0000a250, 0x00000000, 0x00000000, 0x00000210, 0x00000108}, + {0x0000a254, 0x000007d0, 0x00000fa0, 0x00001130, 0x00000898}, + {0x0000a258, 0x02020002, 0x02020002, 0x02020002, 0x02020002}, + {0x0000a25c, 0x01000e0e, 0x01000e0e, 0x01000e0e, 0x01000e0e}, + {0x0000a260, 0x0a021501, 0x0a021501, 0x3a021501, 0x3a021501}, + {0x0000a264, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e}, + {0x0000a280, 0x00000007, 0x00000007, 0x0000000b, 0x0000000b}, + {0x0000a284, 0x00000000, 0x00000000, 0x00000150, 0x00000150}, + {0x0000a288, 0x00000220, 0x00000220, 0x00000110, 0x00000110}, + {0x0000a28c, 0x00011111, 0x00011111, 0x00022222, 0x00022222}, + {0x0000a2c4, 0x00158d18, 0x00158d18, 0x00158d18, 0x00158d18}, + {0x0000a2d0, 0x00071981, 0x00071981, 0x00071981, 0x00071982}, + {0x0000a2d8, 0xf999a83a, 0xf999a83a, 0xf999a83a, 0xf999a83a}, + {0x0000a358, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000a830, 0x0000019c, 0x0000019c, 0x0000019c, 0x0000019c}, + {0x0000ae04, 0x00180000, 0x00180000, 0x00180000, 0x00180000}, + {0x0000ae18, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000ae1c, 0x0000019c, 0x0000019c, 0x0000019c, 0x0000019c}, + {0x0000ae20, 0x000001b5, 0x000001b5, 0x000001ce, 0x000001ce}, + {0x0000b284, 0x00000000, 0x00000000, 0x00000150, 0x00000150}, +}; + +static const u32 ar9340_1p0_baseband_core[][2] = { + /* Addr allmodes */ + {0x00009800, 0xafe68e30}, + {0x00009804, 0xfd14e000}, + {0x00009808, 0x9c0a9f6b}, + {0x0000980c, 0x04900000}, + {0x00009814, 0xb280c00a}, + {0x00009818, 0x00000000}, + {0x0000981c, 0x00020028}, + {0x00009834, 0x5f3ca3de}, + {0x00009838, 0x0108ecff}, + {0x0000983c, 0x14750600}, + {0x00009880, 0x201fff00}, + {0x00009884, 0x00001042}, + {0x000098a4, 0x00200400}, + {0x000098b0, 0x52440bbe}, + {0x000098d0, 0x004b6a8e}, + {0x000098d4, 0x00000820}, + {0x000098dc, 0x00000000}, + {0x000098f0, 0x00000000}, + {0x000098f4, 0x00000000}, + {0x00009c04, 0xff55ff55}, + {0x00009c08, 0x0320ff55}, + {0x00009c0c, 0x00000000}, + {0x00009c10, 0x00000000}, + {0x00009c14, 0x00046384}, + {0x00009c18, 0x05b6b440}, + {0x00009c1c, 0x00b6b440}, + {0x00009d00, 0xc080a333}, + {0x00009d04, 0x40206c10}, + {0x00009d08, 0x009c4060}, + {0x00009d0c, 0x9883800a}, + {0x00009d10, 0x01834061}, + {0x00009d14, 0x00c0040b}, + {0x00009d18, 0x00000000}, + {0x00009e08, 0x0038230c}, + {0x00009e24, 0x990bb515}, + {0x00009e28, 0x0c6f0000}, + {0x00009e30, 0x06336f77}, + {0x00009e34, 0x6af6532f}, + {0x00009e38, 0x0cc80c00}, + {0x00009e3c, 0xcf946222}, + {0x00009e40, 0x0d261820}, + {0x00009e4c, 0x00001004}, + {0x00009e50, 0x00ff03f1}, + {0x00009e54, 0x00000000}, + {0x00009fc0, 0x803e4788}, + {0x00009fc4, 0x0001efb5}, + {0x00009fcc, 0x40000014}, + {0x00009fd0, 0x01193b93}, + {0x0000a20c, 0x00000000}, + {0x0000a220, 0x00000000}, + {0x0000a224, 0x00000000}, + {0x0000a228, 0x10002310}, + {0x0000a22c, 0x01036a1e}, + {0x0000a234, 0x10000fff}, + {0x0000a23c, 0x00000000}, + {0x0000a244, 0x0c000000}, + {0x0000a2a0, 0x00000001}, + {0x0000a2c0, 0x00000001}, + {0x0000a2c8, 0x00000000}, + {0x0000a2cc, 0x18c43433}, + {0x0000a2d4, 0x00000000}, + {0x0000a2dc, 0x00000000}, + {0x0000a2e0, 0x00000000}, + {0x0000a2e4, 0x00000000}, + {0x0000a2e8, 0x00000000}, + {0x0000a2ec, 0x00000000}, + {0x0000a2f0, 0x00000000}, + {0x0000a2f4, 0x00000000}, + {0x0000a2f8, 0x00000000}, + {0x0000a344, 0x00000000}, + {0x0000a34c, 0x00000000}, + {0x0000a350, 0x0000a000}, + {0x0000a364, 0x00000000}, + {0x0000a370, 0x00000000}, + {0x0000a390, 0x00000001}, + {0x0000a394, 0x00000444}, + {0x0000a398, 0x001f0e0f}, + {0x0000a39c, 0x0075393f}, + {0x0000a3a0, 0xb79f6427}, + {0x0000a3a4, 0x00000000}, + {0x0000a3a8, 0xaaaaaaaa}, + {0x0000a3ac, 0x3c466478}, + {0x0000a3c0, 0x20202020}, + {0x0000a3c4, 0x22222220}, + {0x0000a3c8, 0x20200020}, + {0x0000a3cc, 0x20202020}, + {0x0000a3d0, 0x20202020}, + {0x0000a3d4, 0x20202020}, + {0x0000a3d8, 0x20202020}, + {0x0000a3dc, 0x20202020}, + {0x0000a3e0, 0x20202020}, + {0x0000a3e4, 0x20202020}, + {0x0000a3e8, 0x20202020}, + {0x0000a3ec, 0x20202020}, + {0x0000a3f0, 0x00000000}, + {0x0000a3f4, 0x00000246}, + {0x0000a3f8, 0x0cdbd380}, + {0x0000a3fc, 0x000f0f01}, + {0x0000a400, 0x8fa91f01}, + {0x0000a404, 0x00000000}, + {0x0000a408, 0x0e79e5c6}, + {0x0000a40c, 0x00820820}, + {0x0000a414, 0x1ce739ce}, + {0x0000a418, 0x2d001dce}, + {0x0000a41c, 0x1ce739ce}, + {0x0000a420, 0x000001ce}, + {0x0000a424, 0x1ce739ce}, + {0x0000a428, 0x000001ce}, + {0x0000a42c, 0x1ce739ce}, + {0x0000a430, 0x1ce739ce}, + {0x0000a434, 0x00000000}, + {0x0000a438, 0x00001801}, + {0x0000a43c, 0x00000000}, + {0x0000a440, 0x00000000}, + {0x0000a444, 0x00000000}, + {0x0000a448, 0x04000080}, + {0x0000a44c, 0x00000001}, + {0x0000a450, 0x00010000}, + {0x0000a458, 0x00000000}, + {0x0000a600, 0x00000000}, + {0x0000a604, 0x00000000}, + {0x0000a608, 0x00000000}, + {0x0000a60c, 0x00000000}, + {0x0000a610, 0x00000000}, + {0x0000a614, 0x00000000}, + {0x0000a618, 0x00000000}, + {0x0000a61c, 0x00000000}, + {0x0000a620, 0x00000000}, + {0x0000a624, 0x00000000}, + {0x0000a628, 0x00000000}, + {0x0000a62c, 0x00000000}, + {0x0000a630, 0x00000000}, + {0x0000a634, 0x00000000}, + {0x0000a638, 0x00000000}, + {0x0000a63c, 0x00000000}, + {0x0000a640, 0x00000000}, + {0x0000a644, 0x3fad9d74}, + {0x0000a648, 0x0048060a}, + {0x0000a64c, 0x00000637}, + {0x0000a670, 0x03020100}, + {0x0000a674, 0x09080504}, + {0x0000a678, 0x0d0c0b0a}, + {0x0000a67c, 0x13121110}, + {0x0000a680, 0x31301514}, + {0x0000a684, 0x35343332}, + {0x0000a688, 0x00000036}, + {0x0000a690, 0x00000838}, + {0x0000a7c0, 0x00000000}, + {0x0000a7c4, 0xfffffffc}, + {0x0000a7c8, 0x00000000}, + {0x0000a7cc, 0x00000000}, + {0x0000a7d0, 0x00000000}, + {0x0000a7d4, 0x00000004}, + {0x0000a7dc, 0x00000000}, + {0x0000a8d0, 0x004b6a8e}, + {0x0000a8d4, 0x00000820}, + {0x0000a8dc, 0x00000000}, + {0x0000a8f0, 0x00000000}, + {0x0000a8f4, 0x00000000}, + {0x0000b2d0, 0x00000080}, + {0x0000b2d4, 0x00000000}, + {0x0000b2dc, 0x00000000}, + {0x0000b2e0, 0x00000000}, + {0x0000b2e4, 0x00000000}, + {0x0000b2e8, 0x00000000}, + {0x0000b2ec, 0x00000000}, + {0x0000b2f0, 0x00000000}, + {0x0000b2f4, 0x00000000}, + {0x0000b2f8, 0x00000000}, + {0x0000b408, 0x0e79e5c0}, + {0x0000b40c, 0x00820820}, + {0x0000b420, 0x00000000}, +}; + +static const u32 ar9340Modes_high_power_tx_gain_table_1p0[][5] = { + /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ + {0x0000a410, 0x000050d8, 0x000050d8, 0x000050d9, 0x000050d9}, + {0x0000a500, 0x00002220, 0x00002220, 0x00000000, 0x00000000}, + {0x0000a504, 0x04002222, 0x04002222, 0x04000002, 0x04000002}, + {0x0000a508, 0x09002421, 0x09002421, 0x08000004, 0x08000004}, + {0x0000a50c, 0x0d002621, 0x0d002621, 0x0b000200, 0x0b000200}, + {0x0000a510, 0x13004620, 0x13004620, 0x0f000202, 0x0f000202}, + {0x0000a514, 0x19004a20, 0x19004a20, 0x11000400, 0x11000400}, + {0x0000a518, 0x1d004e20, 0x1d004e20, 0x15000402, 0x15000402}, + {0x0000a51c, 0x21005420, 0x21005420, 0x19000404, 0x19000404}, + {0x0000a520, 0x26005e20, 0x26005e20, 0x1b000603, 0x1b000603}, + {0x0000a524, 0x2b005e40, 0x2b005e40, 0x1f000a02, 0x1f000a02}, + {0x0000a528, 0x2f005e42, 0x2f005e42, 0x23000a04, 0x23000a04}, + {0x0000a52c, 0x33005e44, 0x33005e44, 0x26000a20, 0x26000a20}, + {0x0000a530, 0x38005e65, 0x38005e65, 0x2a000e20, 0x2a000e20}, + {0x0000a534, 0x3c005e69, 0x3c005e69, 0x2e000e22, 0x2e000e22}, + {0x0000a538, 0x40005e6b, 0x40005e6b, 0x31000e24, 0x31000e24}, + {0x0000a53c, 0x44005e6d, 0x44005e6d, 0x34001640, 0x34001640}, + {0x0000a540, 0x49005e72, 0x49005e72, 0x38001660, 0x38001660}, + {0x0000a544, 0x4e005eb2, 0x4e005eb2, 0x3b001861, 0x3b001861}, + {0x0000a548, 0x53005f12, 0x53005f12, 0x3e001a81, 0x3e001a81}, + {0x0000a54c, 0x59025eb5, 0x59025eb5, 0x42001a83, 0x42001a83}, + {0x0000a550, 0x5e025f12, 0x5e025f12, 0x44001c84, 0x44001c84}, + {0x0000a554, 0x61027f12, 0x61027f12, 0x48001ce3, 0x48001ce3}, + {0x0000a558, 0x6702bf12, 0x6702bf12, 0x4c001ce5, 0x4c001ce5}, + {0x0000a55c, 0x6b02bf14, 0x6b02bf14, 0x50001ce9, 0x50001ce9}, + {0x0000a560, 0x6f02bf16, 0x6f02bf16, 0x54001ceb, 0x54001ceb}, + {0x0000a564, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec}, + {0x0000a568, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec}, + {0x0000a56c, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec}, + {0x0000a570, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec}, + {0x0000a574, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec}, + {0x0000a578, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec}, + {0x0000a57c, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec}, + {0x0000a580, 0x00802220, 0x00802220, 0x00800000, 0x00800000}, + {0x0000a584, 0x04802222, 0x04802222, 0x04800002, 0x04800002}, + {0x0000a588, 0x09802421, 0x09802421, 0x08800004, 0x08800004}, + {0x0000a58c, 0x0d802621, 0x0d802621, 0x0b800200, 0x0b800200}, + {0x0000a590, 0x13804620, 0x13804620, 0x0f800202, 0x0f800202}, + {0x0000a594, 0x19804a20, 0x19804a20, 0x11800400, 0x11800400}, + {0x0000a598, 0x1d804e20, 0x1d804e20, 0x15800402, 0x15800402}, + {0x0000a59c, 0x21805420, 0x21805420, 0x19800404, 0x19800404}, + {0x0000a5a0, 0x26805e20, 0x26805e20, 0x1b800603, 0x1b800603}, + {0x0000a5a4, 0x2b805e40, 0x2b805e40, 0x1f800a02, 0x1f800a02}, + {0x0000a5a8, 0x2f805e42, 0x2f805e42, 0x23800a04, 0x23800a04}, + {0x0000a5ac, 0x33805e44, 0x33805e44, 0x26800a20, 0x26800a20}, + {0x0000a5b0, 0x38805e65, 0x38805e65, 0x2a800e20, 0x2a800e20}, + {0x0000a5b4, 0x3c805e69, 0x3c805e69, 0x2e800e22, 0x2e800e22}, + {0x0000a5b8, 0x40805e6b, 0x40805e6b, 0x31800e24, 0x31800e24}, + {0x0000a5bc, 0x44805e6d, 0x44805e6d, 0x34801640, 0x34801640}, + {0x0000a5c0, 0x49805e72, 0x49805e72, 0x38801660, 0x38801660}, + {0x0000a5c4, 0x4e805eb2, 0x4e805eb2, 0x3b801861, 0x3b801861}, + {0x0000a5c8, 0x53805f12, 0x53805f12, 0x3e801a81, 0x3e801a81}, + {0x0000a5cc, 0x59825eb2, 0x59825eb2, 0x42801a83, 0x42801a83}, + {0x0000a5d0, 0x5e825f12, 0x5e825f12, 0x44801c84, 0x44801c84}, + {0x0000a5d4, 0x61827f12, 0x61827f12, 0x48801ce3, 0x48801ce3}, + {0x0000a5d8, 0x6782bf12, 0x6782bf12, 0x4c801ce5, 0x4c801ce5}, + {0x0000a5dc, 0x6b82bf14, 0x6b82bf14, 0x50801ce9, 0x50801ce9}, + {0x0000a5e0, 0x6f82bf16, 0x6f82bf16, 0x54801ceb, 0x54801ceb}, + {0x0000a5e4, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec}, + {0x0000a5e8, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec}, + {0x0000a5ec, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec}, + {0x0000a5f0, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec}, + {0x0000a5f4, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec}, + {0x0000a5f8, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec}, + {0x0000a5fc, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec}, + {0x00016044, 0x056db2db, 0x056db2db, 0x056db2db, 0x056db2db}, + {0x00016048, 0x24925266, 0x24925266, 0x24925266, 0x24925266}, + {0x00016444, 0x056db2db, 0x056db2db, 0x056db2db, 0x056db2db}, + {0x00016448, 0x24925266, 0x24925266, 0x24925266, 0x24925266}, +}; + +static const u32 ar9340Modes_high_ob_db_tx_gain_table_1p0[][5] = { + /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ + {0x0000a410, 0x000050d8, 0x000050d8, 0x000050d9, 0x000050d9}, + {0x0000a500, 0x00002220, 0x00002220, 0x00000000, 0x00000000}, + {0x0000a504, 0x04002222, 0x04002222, 0x04000002, 0x04000002}, + {0x0000a508, 0x09002421, 0x09002421, 0x08000004, 0x08000004}, + {0x0000a50c, 0x0d002621, 0x0d002621, 0x0b000200, 0x0b000200}, + {0x0000a510, 0x13004620, 0x13004620, 0x0f000202, 0x0f000202}, + {0x0000a514, 0x19004a20, 0x19004a20, 0x11000400, 0x11000400}, + {0x0000a518, 0x1d004e20, 0x1d004e20, 0x15000402, 0x15000402}, + {0x0000a51c, 0x21005420, 0x21005420, 0x19000404, 0x19000404}, + {0x0000a520, 0x26005e20, 0x26005e20, 0x1b000603, 0x1b000603}, + {0x0000a524, 0x2b005e40, 0x2b005e40, 0x1f000a02, 0x1f000a02}, + {0x0000a528, 0x2f005e42, 0x2f005e42, 0x23000a04, 0x23000a04}, + {0x0000a52c, 0x33005e44, 0x33005e44, 0x26000a20, 0x26000a20}, + {0x0000a530, 0x38005e65, 0x38005e65, 0x2a000e20, 0x2a000e20}, + {0x0000a534, 0x3c005e69, 0x3c005e69, 0x2e000e22, 0x2e000e22}, + {0x0000a538, 0x40005e6b, 0x40005e6b, 0x31000e24, 0x31000e24}, + {0x0000a53c, 0x44005e6d, 0x44005e6d, 0x34001640, 0x34001640}, + {0x0000a540, 0x49005e72, 0x49005e72, 0x38001660, 0x38001660}, + {0x0000a544, 0x4e005eb2, 0x4e005eb2, 0x3b001861, 0x3b001861}, + {0x0000a548, 0x53005f12, 0x53005f12, 0x3e001a81, 0x3e001a81}, + {0x0000a54c, 0x59025eb5, 0x59025eb5, 0x42001a83, 0x42001a83}, + {0x0000a550, 0x5e025f12, 0x5e025f12, 0x44001c84, 0x44001c84}, + {0x0000a554, 0x61027f12, 0x61027f12, 0x48001ce3, 0x48001ce3}, + {0x0000a558, 0x6702bf12, 0x6702bf12, 0x4c001ce5, 0x4c001ce5}, + {0x0000a55c, 0x6b02bf14, 0x6b02bf14, 0x50001ce9, 0x50001ce9}, + {0x0000a560, 0x6f02bf16, 0x6f02bf16, 0x54001ceb, 0x54001ceb}, + {0x0000a564, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec}, + {0x0000a568, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec}, + {0x0000a56c, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec}, + {0x0000a570, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec}, + {0x0000a574, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec}, + {0x0000a578, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec}, + {0x0000a57c, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec}, + {0x0000a580, 0x00802220, 0x00802220, 0x00800000, 0x00800000}, + {0x0000a584, 0x04802222, 0x04802222, 0x04800002, 0x04800002}, + {0x0000a588, 0x09802421, 0x09802421, 0x08800004, 0x08800004}, + {0x0000a58c, 0x0d802621, 0x0d802621, 0x0b800200, 0x0b800200}, + {0x0000a590, 0x13804620, 0x13804620, 0x0f800202, 0x0f800202}, + {0x0000a594, 0x19804a20, 0x19804a20, 0x11800400, 0x11800400}, + {0x0000a598, 0x1d804e20, 0x1d804e20, 0x15800402, 0x15800402}, + {0x0000a59c, 0x21805420, 0x21805420, 0x19800404, 0x19800404}, + {0x0000a5a0, 0x26805e20, 0x26805e20, 0x1b800603, 0x1b800603}, + {0x0000a5a4, 0x2b805e40, 0x2b805e40, 0x1f800a02, 0x1f800a02}, + {0x0000a5a8, 0x2f805e42, 0x2f805e42, 0x23800a04, 0x23800a04}, + {0x0000a5ac, 0x33805e44, 0x33805e44, 0x26800a20, 0x26800a20}, + {0x0000a5b0, 0x38805e65, 0x38805e65, 0x2a800e20, 0x2a800e20}, + {0x0000a5b4, 0x3c805e69, 0x3c805e69, 0x2e800e22, 0x2e800e22}, + {0x0000a5b8, 0x40805e6b, 0x40805e6b, 0x31800e24, 0x31800e24}, + {0x0000a5bc, 0x44805e6d, 0x44805e6d, 0x34801640, 0x34801640}, + {0x0000a5c0, 0x49805e72, 0x49805e72, 0x38801660, 0x38801660}, + {0x0000a5c4, 0x4e805eb2, 0x4e805eb2, 0x3b801861, 0x3b801861}, + {0x0000a5c8, 0x53805f12, 0x53805f12, 0x3e801a81, 0x3e801a81}, + {0x0000a5cc, 0x59825eb2, 0x59825eb2, 0x42801a83, 0x42801a83}, + {0x0000a5d0, 0x5e825f12, 0x5e825f12, 0x44801c84, 0x44801c84}, + {0x0000a5d4, 0x61827f12, 0x61827f12, 0x48801ce3, 0x48801ce3}, + {0x0000a5d8, 0x6782bf12, 0x6782bf12, 0x4c801ce5, 0x4c801ce5}, + {0x0000a5dc, 0x6b82bf14, 0x6b82bf14, 0x50801ce9, 0x50801ce9}, + {0x0000a5e0, 0x6f82bf16, 0x6f82bf16, 0x54801ceb, 0x54801ceb}, + {0x0000a5e4, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec}, + {0x0000a5e8, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec}, + {0x0000a5ec, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec}, + {0x0000a5f0, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec}, + {0x0000a5f4, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec}, + {0x0000a5f8, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec}, + {0x0000a5fc, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec}, + {0x00016044, 0x03b6d2e4, 0x03b6d2e4, 0x03b6d2e4, 0x03b6d2e4}, + {0x00016048, 0x8e481266, 0x8e481266, 0x8e481266, 0x8e481266}, + {0x00016444, 0x03b6d2e4, 0x03b6d2e4, 0x03b6d2e4, 0x03b6d2e4}, + {0x00016448, 0x8e481266, 0x8e481266, 0x8e481266, 0x8e481266}, +}; +static const u32 ar9340Modes_ub124_tx_gain_table_1p0[][5] = { + /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ + {0x0000a410, 0x000050d8, 0x000050d8, 0x000050d9, 0x000050d9}, + {0x0000a500, 0x00002220, 0x00002220, 0x00000000, 0x00000000}, + {0x0000a504, 0x04002222, 0x04002222, 0x04000002, 0x04000002}, + {0x0000a508, 0x09002421, 0x09002421, 0x08000004, 0x08000004}, + {0x0000a50c, 0x0d002621, 0x0d002621, 0x0b000200, 0x0b000200}, + {0x0000a510, 0x13004620, 0x13004620, 0x0f000202, 0x0f000202}, + {0x0000a514, 0x19004a20, 0x19004a20, 0x11000400, 0x11000400}, + {0x0000a518, 0x1d004e20, 0x1d004e20, 0x15000402, 0x15000402}, + {0x0000a51c, 0x21005420, 0x21005420, 0x19000404, 0x19000404}, + {0x0000a520, 0x26005e20, 0x26005e20, 0x1b000603, 0x1b000603}, + {0x0000a524, 0x2b005e40, 0x2b005e40, 0x1f000a02, 0x1f000a02}, + {0x0000a528, 0x2f005e42, 0x2f005e42, 0x23000a04, 0x23000a04}, + {0x0000a52c, 0x33005e44, 0x33005e44, 0x26000a20, 0x26000a20}, + {0x0000a530, 0x38005e65, 0x38005e65, 0x2a000e20, 0x2a000e20}, + {0x0000a534, 0x3c005e69, 0x3c005e69, 0x2e000e22, 0x2e000e22}, + {0x0000a538, 0x40005e6b, 0x40005e6b, 0x31000e24, 0x31000e24}, + {0x0000a53c, 0x44005e6d, 0x44005e6d, 0x34001640, 0x34001640}, + {0x0000a540, 0x49005e72, 0x49005e72, 0x38001660, 0x38001660}, + {0x0000a544, 0x4e005eb2, 0x4e005eb2, 0x3b001861, 0x3b001861}, + {0x0000a548, 0x53005f12, 0x53005f12, 0x3e001a81, 0x3e001a81}, + {0x0000a54c, 0x59025eb5, 0x59025eb5, 0x42001a83, 0x42001a83}, + {0x0000a550, 0x5e025f12, 0x5e025f12, 0x44001c84, 0x44001c84}, + {0x0000a554, 0x61027f12, 0x61027f12, 0x48001ce3, 0x48001ce3}, + {0x0000a558, 0x6702bf12, 0x6702bf12, 0x4c001ce5, 0x4c001ce5}, + {0x0000a55c, 0x6b02bf14, 0x6b02bf14, 0x50001ce9, 0x50001ce9}, + {0x0000a560, 0x6f02bf16, 0x6f02bf16, 0x54001ceb, 0x54001ceb}, + {0x0000a564, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec}, + {0x0000a568, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec}, + {0x0000a56c, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec}, + {0x0000a570, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec}, + {0x0000a574, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec}, + {0x0000a578, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec}, + {0x0000a57c, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec}, + {0x0000a580, 0x00802220, 0x00802220, 0x00800000, 0x00800000}, + {0x0000a584, 0x04802222, 0x04802222, 0x04800002, 0x04800002}, + {0x0000a588, 0x09802421, 0x09802421, 0x08800004, 0x08800004}, + {0x0000a58c, 0x0d802621, 0x0d802621, 0x0b800200, 0x0b800200}, + {0x0000a590, 0x13804620, 0x13804620, 0x0f800202, 0x0f800202}, + {0x0000a594, 0x19804a20, 0x19804a20, 0x11800400, 0x11800400}, + {0x0000a598, 0x1d804e20, 0x1d804e20, 0x15800402, 0x15800402}, + {0x0000a59c, 0x21805420, 0x21805420, 0x19800404, 0x19800404}, + {0x0000a5a0, 0x26805e20, 0x26805e20, 0x1b800603, 0x1b800603}, + {0x0000a5a4, 0x2b805e40, 0x2b805e40, 0x1f800a02, 0x1f800a02}, + {0x0000a5a8, 0x2f805e42, 0x2f805e42, 0x23800a04, 0x23800a04}, + {0x0000a5ac, 0x33805e44, 0x33805e44, 0x26800a20, 0x26800a20}, + {0x0000a5b0, 0x38805e65, 0x38805e65, 0x2a800e20, 0x2a800e20}, + {0x0000a5b4, 0x3c805e69, 0x3c805e69, 0x2e800e22, 0x2e800e22}, + {0x0000a5b8, 0x40805e6b, 0x40805e6b, 0x31800e24, 0x31800e24}, + {0x0000a5bc, 0x44805e6d, 0x44805e6d, 0x34801640, 0x34801640}, + {0x0000a5c0, 0x49805e72, 0x49805e72, 0x38801660, 0x38801660}, + {0x0000a5c4, 0x4e805eb2, 0x4e805eb2, 0x3b801861, 0x3b801861}, + {0x0000a5c8, 0x53805f12, 0x53805f12, 0x3e801a81, 0x3e801a81}, + {0x0000a5cc, 0x59825eb2, 0x59825eb2, 0x42801a83, 0x42801a83}, + {0x0000a5d0, 0x5e825f12, 0x5e825f12, 0x44801c84, 0x44801c84}, + {0x0000a5d4, 0x61827f12, 0x61827f12, 0x48801ce3, 0x48801ce3}, + {0x0000a5d8, 0x6782bf12, 0x6782bf12, 0x4c801ce5, 0x4c801ce5}, + {0x0000a5dc, 0x6b82bf14, 0x6b82bf14, 0x50801ce9, 0x50801ce9}, + {0x0000a5e0, 0x6f82bf16, 0x6f82bf16, 0x54801ceb, 0x54801ceb}, + {0x0000a5e4, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec}, + {0x0000a5e8, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec}, + {0x0000a5ec, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec}, + {0x0000a5f0, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec}, + {0x0000a5f4, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec}, + {0x0000a5f8, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec}, + {0x0000a5fc, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec}, + {0x00016044, 0x036db2db, 0x036db2db, 0x036db2db, 0x036db2db}, + {0x00016048, 0x69b65266, 0x69b65266, 0x69b65266, 0x69b65266}, + {0x00016444, 0x036db2db, 0x036db2db, 0x036db2db, 0x036db2db}, + {0x00016448, 0x69b65266, 0x69b65266, 0x69b65266, 0x69b65266}, +}; + + +static const u32 ar9340Common_rx_gain_table_1p0[][2] = { + /* Addr allmodes */ + {0x0000a000, 0x00010000}, + {0x0000a004, 0x00030002}, + {0x0000a008, 0x00050004}, + {0x0000a00c, 0x00810080}, + {0x0000a010, 0x00830082}, + {0x0000a014, 0x01810180}, + {0x0000a018, 0x01830182}, + {0x0000a01c, 0x01850184}, + {0x0000a020, 0x01890188}, + {0x0000a024, 0x018b018a}, + {0x0000a028, 0x018d018c}, + {0x0000a02c, 0x01910190}, + {0x0000a030, 0x01930192}, + {0x0000a034, 0x01950194}, + {0x0000a038, 0x038a0196}, + {0x0000a03c, 0x038c038b}, + {0x0000a040, 0x0390038d}, + {0x0000a044, 0x03920391}, + {0x0000a048, 0x03940393}, + {0x0000a04c, 0x03960395}, + {0x0000a050, 0x00000000}, + {0x0000a054, 0x00000000}, + {0x0000a058, 0x00000000}, + {0x0000a05c, 0x00000000}, + {0x0000a060, 0x00000000}, + {0x0000a064, 0x00000000}, + {0x0000a068, 0x00000000}, + {0x0000a06c, 0x00000000}, + {0x0000a070, 0x00000000}, + {0x0000a074, 0x00000000}, + {0x0000a078, 0x00000000}, + {0x0000a07c, 0x00000000}, + {0x0000a080, 0x22222229}, + {0x0000a084, 0x1d1d1d1d}, + {0x0000a088, 0x1d1d1d1d}, + {0x0000a08c, 0x1d1d1d1d}, + {0x0000a090, 0x171d1d1d}, + {0x0000a094, 0x11111717}, + {0x0000a098, 0x00030311}, + {0x0000a09c, 0x00000000}, + {0x0000a0a0, 0x00000000}, + {0x0000a0a4, 0x00000000}, + {0x0000a0a8, 0x00000000}, + {0x0000a0ac, 0x00000000}, + {0x0000a0b0, 0x00000000}, + {0x0000a0b4, 0x00000000}, + {0x0000a0b8, 0x00000000}, + {0x0000a0bc, 0x00000000}, + {0x0000a0c0, 0x001f0000}, + {0x0000a0c4, 0x01000101}, + {0x0000a0c8, 0x011e011f}, + {0x0000a0cc, 0x011c011d}, + {0x0000a0d0, 0x02030204}, + {0x0000a0d4, 0x02010202}, + {0x0000a0d8, 0x021f0200}, + {0x0000a0dc, 0x0302021e}, + {0x0000a0e0, 0x03000301}, + {0x0000a0e4, 0x031e031f}, + {0x0000a0e8, 0x0402031d}, + {0x0000a0ec, 0x04000401}, + {0x0000a0f0, 0x041e041f}, + {0x0000a0f4, 0x0502041d}, + {0x0000a0f8, 0x05000501}, + {0x0000a0fc, 0x051e051f}, + {0x0000a100, 0x06010602}, + {0x0000a104, 0x061f0600}, + {0x0000a108, 0x061d061e}, + {0x0000a10c, 0x07020703}, + {0x0000a110, 0x07000701}, + {0x0000a114, 0x00000000}, + {0x0000a118, 0x00000000}, + {0x0000a11c, 0x00000000}, + {0x0000a120, 0x00000000}, + {0x0000a124, 0x00000000}, + {0x0000a128, 0x00000000}, + {0x0000a12c, 0x00000000}, + {0x0000a130, 0x00000000}, + {0x0000a134, 0x00000000}, + {0x0000a138, 0x00000000}, + {0x0000a13c, 0x00000000}, + {0x0000a140, 0x001f0000}, + {0x0000a144, 0x01000101}, + {0x0000a148, 0x011e011f}, + {0x0000a14c, 0x011c011d}, + {0x0000a150, 0x02030204}, + {0x0000a154, 0x02010202}, + {0x0000a158, 0x021f0200}, + {0x0000a15c, 0x0302021e}, + {0x0000a160, 0x03000301}, + {0x0000a164, 0x031e031f}, + {0x0000a168, 0x0402031d}, + {0x0000a16c, 0x04000401}, + {0x0000a170, 0x041e041f}, + {0x0000a174, 0x0502041d}, + {0x0000a178, 0x05000501}, + {0x0000a17c, 0x051e051f}, + {0x0000a180, 0x06010602}, + {0x0000a184, 0x061f0600}, + {0x0000a188, 0x061d061e}, + {0x0000a18c, 0x07020703}, + {0x0000a190, 0x07000701}, + {0x0000a194, 0x00000000}, + {0x0000a198, 0x00000000}, + {0x0000a19c, 0x00000000}, + {0x0000a1a0, 0x00000000}, + {0x0000a1a4, 0x00000000}, + {0x0000a1a8, 0x00000000}, + {0x0000a1ac, 0x00000000}, + {0x0000a1b0, 0x00000000}, + {0x0000a1b4, 0x00000000}, + {0x0000a1b8, 0x00000000}, + {0x0000a1bc, 0x00000000}, + {0x0000a1c0, 0x00000000}, + {0x0000a1c4, 0x00000000}, + {0x0000a1c8, 0x00000000}, + {0x0000a1cc, 0x00000000}, + {0x0000a1d0, 0x00000000}, + {0x0000a1d4, 0x00000000}, + {0x0000a1d8, 0x00000000}, + {0x0000a1dc, 0x00000000}, + {0x0000a1e0, 0x00000000}, + {0x0000a1e4, 0x00000000}, + {0x0000a1e8, 0x00000000}, + {0x0000a1ec, 0x00000000}, + {0x0000a1f0, 0x00000396}, + {0x0000a1f4, 0x00000396}, + {0x0000a1f8, 0x00000396}, + {0x0000a1fc, 0x00000196}, + {0x0000b000, 0x00010000}, + {0x0000b004, 0x00030002}, + {0x0000b008, 0x00050004}, + {0x0000b00c, 0x00810080}, + {0x0000b010, 0x00830082}, + {0x0000b014, 0x01810180}, + {0x0000b018, 0x01830182}, + {0x0000b01c, 0x01850184}, + {0x0000b020, 0x02810280}, + {0x0000b024, 0x02830282}, + {0x0000b028, 0x02850284}, + {0x0000b02c, 0x02890288}, + {0x0000b030, 0x028b028a}, + {0x0000b034, 0x0388028c}, + {0x0000b038, 0x038a0389}, + {0x0000b03c, 0x038c038b}, + {0x0000b040, 0x0390038d}, + {0x0000b044, 0x03920391}, + {0x0000b048, 0x03940393}, + {0x0000b04c, 0x03960395}, + {0x0000b050, 0x00000000}, + {0x0000b054, 0x00000000}, + {0x0000b058, 0x00000000}, + {0x0000b05c, 0x00000000}, + {0x0000b060, 0x00000000}, + {0x0000b064, 0x00000000}, + {0x0000b068, 0x00000000}, + {0x0000b06c, 0x00000000}, + {0x0000b070, 0x00000000}, + {0x0000b074, 0x00000000}, + {0x0000b078, 0x00000000}, + {0x0000b07c, 0x00000000}, + {0x0000b080, 0x32323232}, + {0x0000b084, 0x2f2f3232}, + {0x0000b088, 0x23282a2d}, + {0x0000b08c, 0x1c1e2123}, + {0x0000b090, 0x14171919}, + {0x0000b094, 0x0e0e1214}, + {0x0000b098, 0x03050707}, + {0x0000b09c, 0x00030303}, + {0x0000b0a0, 0x00000000}, + {0x0000b0a4, 0x00000000}, + {0x0000b0a8, 0x00000000}, + {0x0000b0ac, 0x00000000}, + {0x0000b0b0, 0x00000000}, + {0x0000b0b4, 0x00000000}, + {0x0000b0b8, 0x00000000}, + {0x0000b0bc, 0x00000000}, + {0x0000b0c0, 0x003f0020}, + {0x0000b0c4, 0x00400041}, + {0x0000b0c8, 0x0140005f}, + {0x0000b0cc, 0x0160015f}, + {0x0000b0d0, 0x017e017f}, + {0x0000b0d4, 0x02410242}, + {0x0000b0d8, 0x025f0240}, + {0x0000b0dc, 0x027f0260}, + {0x0000b0e0, 0x0341027e}, + {0x0000b0e4, 0x035f0340}, + {0x0000b0e8, 0x037f0360}, + {0x0000b0ec, 0x04400441}, + {0x0000b0f0, 0x0460045f}, + {0x0000b0f4, 0x0541047f}, + {0x0000b0f8, 0x055f0540}, + {0x0000b0fc, 0x057f0560}, + {0x0000b100, 0x06400641}, + {0x0000b104, 0x0660065f}, + {0x0000b108, 0x067e067f}, + {0x0000b10c, 0x07410742}, + {0x0000b110, 0x075f0740}, + {0x0000b114, 0x077f0760}, + {0x0000b118, 0x07800781}, + {0x0000b11c, 0x07a0079f}, + {0x0000b120, 0x07c107bf}, + {0x0000b124, 0x000007c0}, + {0x0000b128, 0x00000000}, + {0x0000b12c, 0x00000000}, + {0x0000b130, 0x00000000}, + {0x0000b134, 0x00000000}, + {0x0000b138, 0x00000000}, + {0x0000b13c, 0x00000000}, + {0x0000b140, 0x003f0020}, + {0x0000b144, 0x00400041}, + {0x0000b148, 0x0140005f}, + {0x0000b14c, 0x0160015f}, + {0x0000b150, 0x017e017f}, + {0x0000b154, 0x02410242}, + {0x0000b158, 0x025f0240}, + {0x0000b15c, 0x027f0260}, + {0x0000b160, 0x0341027e}, + {0x0000b164, 0x035f0340}, + {0x0000b168, 0x037f0360}, + {0x0000b16c, 0x04400441}, + {0x0000b170, 0x0460045f}, + {0x0000b174, 0x0541047f}, + {0x0000b178, 0x055f0540}, + {0x0000b17c, 0x057f0560}, + {0x0000b180, 0x06400641}, + {0x0000b184, 0x0660065f}, + {0x0000b188, 0x067e067f}, + {0x0000b18c, 0x07410742}, + {0x0000b190, 0x075f0740}, + {0x0000b194, 0x077f0760}, + {0x0000b198, 0x07800781}, + {0x0000b19c, 0x07a0079f}, + {0x0000b1a0, 0x07c107bf}, + {0x0000b1a4, 0x000007c0}, + {0x0000b1a8, 0x00000000}, + {0x0000b1ac, 0x00000000}, + {0x0000b1b0, 0x00000000}, + {0x0000b1b4, 0x00000000}, + {0x0000b1b8, 0x00000000}, + {0x0000b1bc, 0x00000000}, + {0x0000b1c0, 0x00000000}, + {0x0000b1c4, 0x00000000}, + {0x0000b1c8, 0x00000000}, + {0x0000b1cc, 0x00000000}, + {0x0000b1d0, 0x00000000}, + {0x0000b1d4, 0x00000000}, + {0x0000b1d8, 0x00000000}, + {0x0000b1dc, 0x00000000}, + {0x0000b1e0, 0x00000000}, + {0x0000b1e4, 0x00000000}, + {0x0000b1e8, 0x00000000}, + {0x0000b1ec, 0x00000000}, + {0x0000b1f0, 0x00000396}, + {0x0000b1f4, 0x00000396}, + {0x0000b1f8, 0x00000396}, + {0x0000b1fc, 0x00000196}, +}; + +static const u32 ar9340Modes_low_ob_db_tx_gain_table_1p0[][5] = { + /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ + {0x0000a410, 0x000050d9, 0x000050d9, 0x000050d9, 0x000050d9}, + {0x0000a500, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000a504, 0x06000003, 0x06000003, 0x04000002, 0x04000002}, + {0x0000a508, 0x0a000020, 0x0a000020, 0x08000004, 0x08000004}, + {0x0000a50c, 0x10000023, 0x10000023, 0x0b000200, 0x0b000200}, + {0x0000a510, 0x16000220, 0x16000220, 0x0f000202, 0x0f000202}, + {0x0000a514, 0x1c000223, 0x1c000223, 0x12000400, 0x12000400}, + {0x0000a518, 0x21020220, 0x21020220, 0x16000402, 0x16000402}, + {0x0000a51c, 0x27020223, 0x27020223, 0x19000404, 0x19000404}, + {0x0000a520, 0x2b022220, 0x2b022220, 0x1c000603, 0x1c000603}, + {0x0000a524, 0x2f022222, 0x2f022222, 0x21000a02, 0x21000a02}, + {0x0000a528, 0x34022225, 0x34022225, 0x25000a04, 0x25000a04}, + {0x0000a52c, 0x3a02222a, 0x3a02222a, 0x28000a20, 0x28000a20}, + {0x0000a530, 0x3e02222c, 0x3e02222c, 0x2c000e20, 0x2c000e20}, + {0x0000a534, 0x4202242a, 0x4202242a, 0x30000e22, 0x30000e22}, + {0x0000a538, 0x4702244a, 0x4702244a, 0x34000e24, 0x34000e24}, + {0x0000a53c, 0x4b02244c, 0x4b02244c, 0x38001640, 0x38001640}, + {0x0000a540, 0x4e02246c, 0x4e02246c, 0x3c001660, 0x3c001660}, + {0x0000a544, 0x5302266c, 0x5302266c, 0x3f001861, 0x3f001861}, + {0x0000a548, 0x5702286c, 0x5702286c, 0x43001a81, 0x43001a81}, + {0x0000a54c, 0x5c04286b, 0x5c04286b, 0x47001a83, 0x47001a83}, + {0x0000a550, 0x61042a6c, 0x61042a6c, 0x4a001c84, 0x4a001c84}, + {0x0000a554, 0x66062a6c, 0x66062a6c, 0x4e001ce3, 0x4e001ce3}, + {0x0000a558, 0x6b062e6c, 0x6b062e6c, 0x52001ce5, 0x52001ce5}, + {0x0000a55c, 0x7006308c, 0x7006308c, 0x56001ce9, 0x56001ce9}, + {0x0000a560, 0x730a308a, 0x730a308a, 0x5a001ceb, 0x5a001ceb}, + {0x0000a564, 0x770a308c, 0x770a308c, 0x5d001eec, 0x5d001eec}, + {0x0000a568, 0x770a308c, 0x770a308c, 0x5d001eec, 0x5d001eec}, + {0x0000a56c, 0x770a308c, 0x770a308c, 0x5d001eec, 0x5d001eec}, + {0x0000a570, 0x770a308c, 0x770a308c, 0x5d001eec, 0x5d001eec}, + {0x0000a574, 0x770a308c, 0x770a308c, 0x5d001eec, 0x5d001eec}, + {0x0000a578, 0x770a308c, 0x770a308c, 0x5d001eec, 0x5d001eec}, + {0x0000a57c, 0x770a308c, 0x770a308c, 0x5d001eec, 0x5d001eec}, + {0x0000a580, 0x00800000, 0x00800000, 0x00800000, 0x00800000}, + {0x0000a584, 0x06800003, 0x06800003, 0x04800002, 0x04800002}, + {0x0000a588, 0x0a800020, 0x0a800020, 0x08800004, 0x08800004}, + {0x0000a58c, 0x10800023, 0x10800023, 0x0b800200, 0x0b800200}, + {0x0000a590, 0x16800220, 0x16800220, 0x0f800202, 0x0f800202}, + {0x0000a594, 0x1c800223, 0x1c800223, 0x12800400, 0x12800400}, + {0x0000a598, 0x21820220, 0x21820220, 0x16800402, 0x16800402}, + {0x0000a59c, 0x27820223, 0x27820223, 0x19800404, 0x19800404}, + {0x0000a5a0, 0x2b822220, 0x2b822220, 0x1c800603, 0x1c800603}, + {0x0000a5a4, 0x2f822222, 0x2f822222, 0x21800a02, 0x21800a02}, + {0x0000a5a8, 0x34822225, 0x34822225, 0x25800a04, 0x25800a04}, + {0x0000a5ac, 0x3a82222a, 0x3a82222a, 0x28800a20, 0x28800a20}, + {0x0000a5b0, 0x3e82222c, 0x3e82222c, 0x2c800e20, 0x2c800e20}, + {0x0000a5b4, 0x4282242a, 0x4282242a, 0x30800e22, 0x30800e22}, + {0x0000a5b8, 0x4782244a, 0x4782244a, 0x34800e24, 0x34800e24}, + {0x0000a5bc, 0x4b82244c, 0x4b82244c, 0x38801640, 0x38801640}, + {0x0000a5c0, 0x4e82246c, 0x4e82246c, 0x3c801660, 0x3c801660}, + {0x0000a5c4, 0x5382266c, 0x5382266c, 0x3f801861, 0x3f801861}, + {0x0000a5c8, 0x5782286c, 0x5782286c, 0x43801a81, 0x43801a81}, + {0x0000a5cc, 0x5c84286b, 0x5c84286b, 0x47801a83, 0x47801a83}, + {0x0000a5d0, 0x61842a6c, 0x61842a6c, 0x4a801c84, 0x4a801c84}, + {0x0000a5d4, 0x66862a6c, 0x66862a6c, 0x4e801ce3, 0x4e801ce3}, + {0x0000a5d8, 0x6b862e6c, 0x6b862e6c, 0x52801ce5, 0x52801ce5}, + {0x0000a5dc, 0x7086308c, 0x7086308c, 0x56801ce9, 0x56801ce9}, + {0x0000a5e0, 0x738a308a, 0x738a308a, 0x5a801ceb, 0x5a801ceb}, + {0x0000a5e4, 0x778a308c, 0x778a308c, 0x5d801eec, 0x5d801eec}, + {0x0000a5e8, 0x778a308c, 0x778a308c, 0x5d801eec, 0x5d801eec}, + {0x0000a5ec, 0x778a308c, 0x778a308c, 0x5d801eec, 0x5d801eec}, + {0x0000a5f0, 0x778a308c, 0x778a308c, 0x5d801eec, 0x5d801eec}, + {0x0000a5f4, 0x778a308c, 0x778a308c, 0x5d801eec, 0x5d801eec}, + {0x0000a5f8, 0x778a308c, 0x778a308c, 0x5d801eec, 0x5d801eec}, + {0x0000a5fc, 0x778a308c, 0x778a308c, 0x5d801eec, 0x5d801eec}, + {0x00016044, 0x056db2db, 0x056db2db, 0x056db2db, 0x056db2db}, + {0x00016048, 0x24925266, 0x24925266, 0x24925266, 0x24925266}, + {0x00016444, 0x056db2db, 0x056db2db, 0x056db2db, 0x056db2db}, + {0x00016448, 0x24925266, 0x24925266, 0x24925266, 0x24925266}, +}; + +static const u32 ar9340Modes_mixed_ob_db_tx_gain_table_1p0[][5] = { + /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ + {0x0000a410, 0x000050d9, 0x000050d9, 0x000050d9, 0x000050d9}, + {0x0000a500, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000a504, 0x06000003, 0x06000003, 0x04000002, 0x04000002}, + {0x0000a508, 0x0a000020, 0x0a000020, 0x08000004, 0x08000004}, + {0x0000a50c, 0x10000023, 0x10000023, 0x0b000200, 0x0b000200}, + {0x0000a510, 0x16000220, 0x16000220, 0x0f000202, 0x0f000202}, + {0x0000a514, 0x1c000223, 0x1c000223, 0x11000400, 0x11000400}, + {0x0000a518, 0x21020220, 0x21020220, 0x15000402, 0x15000402}, + {0x0000a51c, 0x27020223, 0x27020223, 0x19000404, 0x19000404}, + {0x0000a520, 0x2b022220, 0x2b022220, 0x1b000603, 0x1b000603}, + {0x0000a524, 0x2f022222, 0x2f022222, 0x1f000a02, 0x1f000a02}, + {0x0000a528, 0x34022225, 0x34022225, 0x23000a04, 0x23000a04}, + {0x0000a52c, 0x3a02222a, 0x3a02222a, 0x26000a20, 0x26000a20}, + {0x0000a530, 0x3e02222c, 0x3e02222c, 0x2a000e20, 0x2a000e20}, + {0x0000a534, 0x4202242a, 0x4202242a, 0x2e000e22, 0x2e000e22}, + {0x0000a538, 0x4702244a, 0x4702244a, 0x31000e24, 0x31000e24}, + {0x0000a53c, 0x4b02244c, 0x4b02244c, 0x34001640, 0x34001640}, + {0x0000a540, 0x4e02246c, 0x4e02246c, 0x38001660, 0x38001660}, + {0x0000a544, 0x5302266c, 0x5302266c, 0x3b001861, 0x3b001861}, + {0x0000a548, 0x5702286c, 0x5702286c, 0x3e001a81, 0x3e001a81}, + {0x0000a54c, 0x5c04286b, 0x5c04286b, 0x42001a83, 0x42001a83}, + {0x0000a550, 0x61042a6c, 0x61042a6c, 0x44001c84, 0x44001c84}, + {0x0000a554, 0x66062a6c, 0x66062a6c, 0x48001ce3, 0x48001ce3}, + {0x0000a558, 0x6b062e6c, 0x6b062e6c, 0x4c001ce5, 0x4c001ce5}, + {0x0000a55c, 0x7006308c, 0x7006308c, 0x50001ce9, 0x50001ce9}, + {0x0000a560, 0x730a308a, 0x730a308a, 0x54001ceb, 0x54001ceb}, + {0x0000a564, 0x770a308c, 0x770a308c, 0x56001eec, 0x56001eec}, + {0x0000a568, 0x770a308c, 0x770a308c, 0x56001eec, 0x56001eec}, + {0x0000a56c, 0x770a308c, 0x770a308c, 0x56001eec, 0x56001eec}, + {0x0000a570, 0x770a308c, 0x770a308c, 0x56001eec, 0x56001eec}, + {0x0000a574, 0x770a308c, 0x770a308c, 0x56001eec, 0x56001eec}, + {0x0000a578, 0x770a308c, 0x770a308c, 0x56001eec, 0x56001eec}, + {0x0000a57c, 0x770a308c, 0x770a308c, 0x56001eec, 0x56001eec}, + {0x0000a580, 0x00800000, 0x00800000, 0x00800000, 0x00800000}, + {0x0000a584, 0x06800003, 0x06800003, 0x04800002, 0x04800002}, + {0x0000a588, 0x0a800020, 0x0a800020, 0x08800004, 0x08800004}, + {0x0000a58c, 0x10800023, 0x10800023, 0x0b800200, 0x0b800200}, + {0x0000a590, 0x16800220, 0x16800220, 0x0f800202, 0x0f800202}, + {0x0000a594, 0x1c800223, 0x1c800223, 0x11800400, 0x11800400}, + {0x0000a598, 0x21820220, 0x21820220, 0x15800402, 0x15800402}, + {0x0000a59c, 0x27820223, 0x27820223, 0x19800404, 0x19800404}, + {0x0000a5a0, 0x2b822220, 0x2b822220, 0x1b800603, 0x1b800603}, + {0x0000a5a4, 0x2f822222, 0x2f822222, 0x1f800a02, 0x1f800a02}, + {0x0000a5a8, 0x34822225, 0x34822225, 0x23800a04, 0x23800a04}, + {0x0000a5ac, 0x3a82222a, 0x3a82222a, 0x26800a20, 0x26800a20}, + {0x0000a5b0, 0x3e82222c, 0x3e82222c, 0x2a800e20, 0x2a800e20}, + {0x0000a5b4, 0x4282242a, 0x4282242a, 0x2e800e22, 0x2e800e22}, + {0x0000a5b8, 0x4782244a, 0x4782244a, 0x31800e24, 0x31800e24}, + {0x0000a5bc, 0x4b82244c, 0x4b82244c, 0x34801640, 0x34801640}, + {0x0000a5c0, 0x4e82246c, 0x4e82246c, 0x38801660, 0x38801660}, + {0x0000a5c4, 0x5382266c, 0x5382266c, 0x3b801861, 0x3b801861}, + {0x0000a5c8, 0x5782286c, 0x5782286c, 0x3e801a81, 0x3e801a81}, + {0x0000a5cc, 0x5c84286b, 0x5c84286b, 0x42801a83, 0x42801a83}, + {0x0000a5d0, 0x61842a6c, 0x61842a6c, 0x44801c84, 0x44801c84}, + {0x0000a5d4, 0x66862a6c, 0x66862a6c, 0x48801ce3, 0x48801ce3}, + {0x0000a5d8, 0x6b862e6c, 0x6b862e6c, 0x4c801ce5, 0x4c801ce5}, + {0x0000a5dc, 0x7086308c, 0x7086308c, 0x50801ce9, 0x50801ce9}, + {0x0000a5e0, 0x738a308a, 0x738a308a, 0x54801ceb, 0x54801ceb}, + {0x0000a5e4, 0x778a308c, 0x778a308c, 0x56801eec, 0x56801eec}, + {0x0000a5e8, 0x778a308c, 0x778a308c, 0x56801eec, 0x56801eec}, + {0x0000a5ec, 0x778a308c, 0x778a308c, 0x56801eec, 0x56801eec}, + {0x0000a5f0, 0x778a308c, 0x778a308c, 0x56801eec, 0x56801eec}, + {0x0000a5f4, 0x778a308c, 0x778a308c, 0x56801eec, 0x56801eec}, + {0x0000a5f8, 0x778a308c, 0x778a308c, 0x56801eec, 0x56801eec}, + {0x0000a5fc, 0x778a308c, 0x778a308c, 0x56801eec, 0x56801eec}, + {0x00016044, 0x056db2db, 0x056db2db, 0x03b6d2e4, 0x03b6d2e4}, + {0x00016048, 0x24927266, 0x24927266, 0x8e483266, 0x8e483266}, + {0x00016444, 0x056db2db, 0x056db2db, 0x03b6d2e4, 0x03b6d2e4}, + {0x00016448, 0x24927266, 0x24927266, 0x8e482266, 0x8e482266}, +}; + +static const u32 ar9340_1p0_mac_core[][2] = { + /* Addr allmodes */ + {0x00000008, 0x00000000}, + {0x00000030, 0x00020085}, + {0x00000034, 0x00000005}, + {0x00000040, 0x00000000}, + {0x00000044, 0x00000000}, + {0x00000048, 0x00000008}, + {0x0000004c, 0x00000010}, + {0x00000050, 0x00000000}, + {0x00001040, 0x002ffc0f}, + {0x00001044, 0x002ffc0f}, + {0x00001048, 0x002ffc0f}, + {0x0000104c, 0x002ffc0f}, + {0x00001050, 0x002ffc0f}, + {0x00001054, 0x002ffc0f}, + {0x00001058, 0x002ffc0f}, + {0x0000105c, 0x002ffc0f}, + {0x00001060, 0x002ffc0f}, + {0x00001064, 0x002ffc0f}, + {0x000010f0, 0x00000100}, + {0x00001270, 0x00000000}, + {0x000012b0, 0x00000000}, + {0x000012f0, 0x00000000}, + {0x0000143c, 0x00000000}, + {0x0000147c, 0x00000000}, + {0x00008000, 0x00000000}, + {0x00008004, 0x00000000}, + {0x00008008, 0x00000000}, + {0x0000800c, 0x00000000}, + {0x00008018, 0x00000000}, + {0x00008020, 0x00000000}, + {0x00008038, 0x00000000}, + {0x0000803c, 0x00000000}, + {0x00008040, 0x00000000}, + {0x00008044, 0x00000000}, + {0x00008048, 0x00000000}, + {0x0000804c, 0xffffffff}, + {0x00008054, 0x00000000}, + {0x00008058, 0x00000000}, + {0x0000805c, 0x000fc78f}, + {0x00008060, 0x0000000f}, + {0x00008064, 0x00000000}, + {0x00008070, 0x00000310}, + {0x00008074, 0x00000020}, + {0x00008078, 0x00000000}, + {0x0000809c, 0x0000000f}, + {0x000080a0, 0x00000000}, + {0x000080a4, 0x02ff0000}, + {0x000080a8, 0x0e070605}, + {0x000080ac, 0x0000000d}, + {0x000080b0, 0x00000000}, + {0x000080b4, 0x00000000}, + {0x000080b8, 0x00000000}, + {0x000080bc, 0x00000000}, + {0x000080c0, 0x2a800000}, + {0x000080c4, 0x06900168}, + {0x000080c8, 0x13881c20}, + {0x000080cc, 0x01f40000}, + {0x000080d0, 0x00252500}, + {0x000080d4, 0x00a00000}, + {0x000080d8, 0x00400000}, + {0x000080dc, 0x00000000}, + {0x000080e0, 0xffffffff}, + {0x000080e4, 0x0000ffff}, + {0x000080e8, 0x3f3f3f3f}, + {0x000080ec, 0x00000000}, + {0x000080f0, 0x00000000}, + {0x000080f4, 0x00000000}, + {0x000080fc, 0x00020000}, + {0x00008100, 0x00000000}, + {0x00008108, 0x00000052}, + {0x0000810c, 0x00000000}, + {0x00008110, 0x00000000}, + {0x00008114, 0x000007ff}, + {0x00008118, 0x000000aa}, + {0x0000811c, 0x00003210}, + {0x00008124, 0x00000000}, + {0x00008128, 0x00000000}, + {0x0000812c, 0x00000000}, + {0x00008130, 0x00000000}, + {0x00008134, 0x00000000}, + {0x00008138, 0x00000000}, + {0x0000813c, 0x0000ffff}, + {0x00008144, 0xffffffff}, + {0x00008168, 0x00000000}, + {0x0000816c, 0x00000000}, + {0x00008170, 0x18486200}, + {0x00008174, 0x33332210}, + {0x00008178, 0x00000000}, + {0x0000817c, 0x00020000}, + {0x000081c0, 0x00000000}, + {0x000081c4, 0x33332210}, + {0x000081c8, 0x00000000}, + {0x000081cc, 0x00000000}, + {0x000081d4, 0x00000000}, + {0x000081ec, 0x00000000}, + {0x000081f0, 0x00000000}, + {0x000081f4, 0x00000000}, + {0x000081f8, 0x00000000}, + {0x000081fc, 0x00000000}, + {0x00008240, 0x00100000}, + {0x00008244, 0x0010f424}, + {0x00008248, 0x00000800}, + {0x0000824c, 0x0001e848}, + {0x00008250, 0x00000000}, + {0x00008254, 0x00000000}, + {0x00008258, 0x00000000}, + {0x0000825c, 0x40000000}, + {0x00008260, 0x00080922}, + {0x00008264, 0x9d400010}, + {0x00008268, 0xffffffff}, + {0x0000826c, 0x0000ffff}, + {0x00008270, 0x00000000}, + {0x00008274, 0x40000000}, + {0x00008278, 0x003e4180}, + {0x0000827c, 0x00000004}, + {0x00008284, 0x0000002c}, + {0x00008288, 0x0000002c}, + {0x0000828c, 0x000000ff}, + {0x00008294, 0x00000000}, + {0x00008298, 0x00000000}, + {0x0000829c, 0x00000000}, + {0x00008300, 0x00000140}, + {0x00008314, 0x00000000}, + {0x0000831c, 0x0000010d}, + {0x00008328, 0x00000000}, + {0x0000832c, 0x00000007}, + {0x00008330, 0x00000302}, + {0x00008334, 0x00000700}, + {0x00008338, 0x00ff0000}, + {0x0000833c, 0x02400000}, + {0x00008340, 0x000107ff}, + {0x00008344, 0xaa48105b}, + {0x00008348, 0x008f0000}, + {0x0000835c, 0x00000000}, + {0x00008360, 0xffffffff}, + {0x00008364, 0xffffffff}, + {0x00008368, 0x00000000}, + {0x00008370, 0x00000000}, + {0x00008374, 0x000000ff}, + {0x00008378, 0x00000000}, + {0x0000837c, 0x00000000}, + {0x00008380, 0xffffffff}, + {0x00008384, 0xffffffff}, + {0x00008390, 0xffffffff}, + {0x00008394, 0xffffffff}, + {0x00008398, 0x00000000}, + {0x0000839c, 0x00000000}, + {0x000083a0, 0x00000000}, + {0x000083a4, 0x0000fa14}, + {0x000083a8, 0x000f0c00}, + {0x000083ac, 0x33332210}, + {0x000083b0, 0x33332210}, + {0x000083b4, 0x33332210}, + {0x000083b8, 0x33332210}, + {0x000083bc, 0x00000000}, + {0x000083c0, 0x00000000}, + {0x000083c4, 0x00000000}, + {0x000083c8, 0x00000000}, + {0x000083cc, 0x00000200}, + {0x000083d0, 0x000301ff}, +}; + +static const u32 ar9340Common_wo_xlna_rx_gain_table_1p0[][2] = { + /* Addr allmodes */ + {0x0000a000, 0x00010000}, + {0x0000a004, 0x00030002}, + {0x0000a008, 0x00050004}, + {0x0000a00c, 0x00810080}, + {0x0000a010, 0x00830082}, + {0x0000a014, 0x01810180}, + {0x0000a018, 0x01830182}, + {0x0000a01c, 0x01850184}, + {0x0000a020, 0x01890188}, + {0x0000a024, 0x018b018a}, + {0x0000a028, 0x018d018c}, + {0x0000a02c, 0x03820190}, + {0x0000a030, 0x03840383}, + {0x0000a034, 0x03880385}, + {0x0000a038, 0x038a0389}, + {0x0000a03c, 0x038c038b}, + {0x0000a040, 0x0390038d}, + {0x0000a044, 0x03920391}, + {0x0000a048, 0x03940393}, + {0x0000a04c, 0x03960395}, + {0x0000a050, 0x00000000}, + {0x0000a054, 0x00000000}, + {0x0000a058, 0x00000000}, + {0x0000a05c, 0x00000000}, + {0x0000a060, 0x00000000}, + {0x0000a064, 0x00000000}, + {0x0000a068, 0x00000000}, + {0x0000a06c, 0x00000000}, + {0x0000a070, 0x00000000}, + {0x0000a074, 0x00000000}, + {0x0000a078, 0x00000000}, + {0x0000a07c, 0x00000000}, + {0x0000a080, 0x29292929}, + {0x0000a084, 0x29292929}, + {0x0000a088, 0x29292929}, + {0x0000a08c, 0x29292929}, + {0x0000a090, 0x22292929}, + {0x0000a094, 0x1d1d2222}, + {0x0000a098, 0x0c111117}, + {0x0000a09c, 0x00030303}, + {0x0000a0a0, 0x00000000}, + {0x0000a0a4, 0x00000000}, + {0x0000a0a8, 0x00000000}, + {0x0000a0ac, 0x00000000}, + {0x0000a0b0, 0x00000000}, + {0x0000a0b4, 0x00000000}, + {0x0000a0b8, 0x00000000}, + {0x0000a0bc, 0x00000000}, + {0x0000a0c0, 0x001f0000}, + {0x0000a0c4, 0x01000101}, + {0x0000a0c8, 0x011e011f}, + {0x0000a0cc, 0x011c011d}, + {0x0000a0d0, 0x02030204}, + {0x0000a0d4, 0x02010202}, + {0x0000a0d8, 0x021f0200}, + {0x0000a0dc, 0x0302021e}, + {0x0000a0e0, 0x03000301}, + {0x0000a0e4, 0x031e031f}, + {0x0000a0e8, 0x0402031d}, + {0x0000a0ec, 0x04000401}, + {0x0000a0f0, 0x041e041f}, + {0x0000a0f4, 0x0502041d}, + {0x0000a0f8, 0x05000501}, + {0x0000a0fc, 0x051e051f}, + {0x0000a100, 0x06010602}, + {0x0000a104, 0x061f0600}, + {0x0000a108, 0x061d061e}, + {0x0000a10c, 0x07020703}, + {0x0000a110, 0x07000701}, + {0x0000a114, 0x00000000}, + {0x0000a118, 0x00000000}, + {0x0000a11c, 0x00000000}, + {0x0000a120, 0x00000000}, + {0x0000a124, 0x00000000}, + {0x0000a128, 0x00000000}, + {0x0000a12c, 0x00000000}, + {0x0000a130, 0x00000000}, + {0x0000a134, 0x00000000}, + {0x0000a138, 0x00000000}, + {0x0000a13c, 0x00000000}, + {0x0000a140, 0x001f0000}, + {0x0000a144, 0x01000101}, + {0x0000a148, 0x011e011f}, + {0x0000a14c, 0x011c011d}, + {0x0000a150, 0x02030204}, + {0x0000a154, 0x02010202}, + {0x0000a158, 0x021f0200}, + {0x0000a15c, 0x0302021e}, + {0x0000a160, 0x03000301}, + {0x0000a164, 0x031e031f}, + {0x0000a168, 0x0402031d}, + {0x0000a16c, 0x04000401}, + {0x0000a170, 0x041e041f}, + {0x0000a174, 0x0502041d}, + {0x0000a178, 0x05000501}, + {0x0000a17c, 0x051e051f}, + {0x0000a180, 0x06010602}, + {0x0000a184, 0x061f0600}, + {0x0000a188, 0x061d061e}, + {0x0000a18c, 0x07020703}, + {0x0000a190, 0x07000701}, + {0x0000a194, 0x00000000}, + {0x0000a198, 0x00000000}, + {0x0000a19c, 0x00000000}, + {0x0000a1a0, 0x00000000}, + {0x0000a1a4, 0x00000000}, + {0x0000a1a8, 0x00000000}, + {0x0000a1ac, 0x00000000}, + {0x0000a1b0, 0x00000000}, + {0x0000a1b4, 0x00000000}, + {0x0000a1b8, 0x00000000}, + {0x0000a1bc, 0x00000000}, + {0x0000a1c0, 0x00000000}, + {0x0000a1c4, 0x00000000}, + {0x0000a1c8, 0x00000000}, + {0x0000a1cc, 0x00000000}, + {0x0000a1d0, 0x00000000}, + {0x0000a1d4, 0x00000000}, + {0x0000a1d8, 0x00000000}, + {0x0000a1dc, 0x00000000}, + {0x0000a1e0, 0x00000000}, + {0x0000a1e4, 0x00000000}, + {0x0000a1e8, 0x00000000}, + {0x0000a1ec, 0x00000000}, + {0x0000a1f0, 0x00000396}, + {0x0000a1f4, 0x00000396}, + {0x0000a1f8, 0x00000396}, + {0x0000a1fc, 0x00000196}, + {0x0000b000, 0x00010000}, + {0x0000b004, 0x00030002}, + {0x0000b008, 0x00050004}, + {0x0000b00c, 0x00810080}, + {0x0000b010, 0x00830082}, + {0x0000b014, 0x01810180}, + {0x0000b018, 0x01830182}, + {0x0000b01c, 0x01850184}, + {0x0000b020, 0x02810280}, + {0x0000b024, 0x02830282}, + {0x0000b028, 0x02850284}, + {0x0000b02c, 0x02890288}, + {0x0000b030, 0x028b028a}, + {0x0000b034, 0x0388028c}, + {0x0000b038, 0x038a0389}, + {0x0000b03c, 0x038c038b}, + {0x0000b040, 0x0390038d}, + {0x0000b044, 0x03920391}, + {0x0000b048, 0x03940393}, + {0x0000b04c, 0x03960395}, + {0x0000b050, 0x00000000}, + {0x0000b054, 0x00000000}, + {0x0000b058, 0x00000000}, + {0x0000b05c, 0x00000000}, + {0x0000b060, 0x00000000}, + {0x0000b064, 0x00000000}, + {0x0000b068, 0x00000000}, + {0x0000b06c, 0x00000000}, + {0x0000b070, 0x00000000}, + {0x0000b074, 0x00000000}, + {0x0000b078, 0x00000000}, + {0x0000b07c, 0x00000000}, + {0x0000b080, 0x32323232}, + {0x0000b084, 0x2f2f3232}, + {0x0000b088, 0x23282a2d}, + {0x0000b08c, 0x1c1e2123}, + {0x0000b090, 0x14171919}, + {0x0000b094, 0x0e0e1214}, + {0x0000b098, 0x03050707}, + {0x0000b09c, 0x00030303}, + {0x0000b0a0, 0x00000000}, + {0x0000b0a4, 0x00000000}, + {0x0000b0a8, 0x00000000}, + {0x0000b0ac, 0x00000000}, + {0x0000b0b0, 0x00000000}, + {0x0000b0b4, 0x00000000}, + {0x0000b0b8, 0x00000000}, + {0x0000b0bc, 0x00000000}, + {0x0000b0c0, 0x003f0020}, + {0x0000b0c4, 0x00400041}, + {0x0000b0c8, 0x0140005f}, + {0x0000b0cc, 0x0160015f}, + {0x0000b0d0, 0x017e017f}, + {0x0000b0d4, 0x02410242}, + {0x0000b0d8, 0x025f0240}, + {0x0000b0dc, 0x027f0260}, + {0x0000b0e0, 0x0341027e}, + {0x0000b0e4, 0x035f0340}, + {0x0000b0e8, 0x037f0360}, + {0x0000b0ec, 0x04400441}, + {0x0000b0f0, 0x0460045f}, + {0x0000b0f4, 0x0541047f}, + {0x0000b0f8, 0x055f0540}, + {0x0000b0fc, 0x057f0560}, + {0x0000b100, 0x06400641}, + {0x0000b104, 0x0660065f}, + {0x0000b108, 0x067e067f}, + {0x0000b10c, 0x07410742}, + {0x0000b110, 0x075f0740}, + {0x0000b114, 0x077f0760}, + {0x0000b118, 0x07800781}, + {0x0000b11c, 0x07a0079f}, + {0x0000b120, 0x07c107bf}, + {0x0000b124, 0x000007c0}, + {0x0000b128, 0x00000000}, + {0x0000b12c, 0x00000000}, + {0x0000b130, 0x00000000}, + {0x0000b134, 0x00000000}, + {0x0000b138, 0x00000000}, + {0x0000b13c, 0x00000000}, + {0x0000b140, 0x003f0020}, + {0x0000b144, 0x00400041}, + {0x0000b148, 0x0140005f}, + {0x0000b14c, 0x0160015f}, + {0x0000b150, 0x017e017f}, + {0x0000b154, 0x02410242}, + {0x0000b158, 0x025f0240}, + {0x0000b15c, 0x027f0260}, + {0x0000b160, 0x0341027e}, + {0x0000b164, 0x035f0340}, + {0x0000b168, 0x037f0360}, + {0x0000b16c, 0x04400441}, + {0x0000b170, 0x0460045f}, + {0x0000b174, 0x0541047f}, + {0x0000b178, 0x055f0540}, + {0x0000b17c, 0x057f0560}, + {0x0000b180, 0x06400641}, + {0x0000b184, 0x0660065f}, + {0x0000b188, 0x067e067f}, + {0x0000b18c, 0x07410742}, + {0x0000b190, 0x075f0740}, + {0x0000b194, 0x077f0760}, + {0x0000b198, 0x07800781}, + {0x0000b19c, 0x07a0079f}, + {0x0000b1a0, 0x07c107bf}, + {0x0000b1a4, 0x000007c0}, + {0x0000b1a8, 0x00000000}, + {0x0000b1ac, 0x00000000}, + {0x0000b1b0, 0x00000000}, + {0x0000b1b4, 0x00000000}, + {0x0000b1b8, 0x00000000}, + {0x0000b1bc, 0x00000000}, + {0x0000b1c0, 0x00000000}, + {0x0000b1c4, 0x00000000}, + {0x0000b1c8, 0x00000000}, + {0x0000b1cc, 0x00000000}, + {0x0000b1d0, 0x00000000}, + {0x0000b1d4, 0x00000000}, + {0x0000b1d8, 0x00000000}, + {0x0000b1dc, 0x00000000}, + {0x0000b1e0, 0x00000000}, + {0x0000b1e4, 0x00000000}, + {0x0000b1e8, 0x00000000}, + {0x0000b1ec, 0x00000000}, + {0x0000b1f0, 0x00000396}, + {0x0000b1f4, 0x00000396}, + {0x0000b1f8, 0x00000396}, + {0x0000b1fc, 0x00000196}, +}; + +static const u32 ar9340_1p0_soc_preamble[][2] = { + /* Addr allmodes */ + {0x000040a4, 0x00a0c1c9}, + {0x00007008, 0x00000000}, + {0x00007020, 0x00000000}, + {0x00007034, 0x00000002}, + {0x00007038, 0x000004c2}, +}; + +#endif -- cgit v0.10.2 From d89baac8b477d8f9eca72d186863a554d7137b40 Mon Sep 17 00:00:00 2001 From: Vasanthakumar Thiagarajan Date: Tue, 19 Apr 2011 19:29:04 +0530 Subject: ath9k_hw: Initialize mode registers from initvals.h for AR9340 Signed-off-by: Vasanthakumar Thiagarajan Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/ar9003_hw.c b/drivers/net/wireless/ath/ath9k/ar9003_hw.c index aebaad9..37af721 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_hw.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_hw.c @@ -18,6 +18,7 @@ #include "ar9003_mac.h" #include "ar9003_2p2_initvals.h" #include "ar9485_initvals.h" +#include "ar9340_initvals.h" /* General hardware code for the AR9003 hadware family */ @@ -28,7 +29,63 @@ */ static void ar9003_hw_init_mode_regs(struct ath_hw *ah) { - if (AR_SREV_9485_11(ah)) { + if (AR_SREV_9340(ah)) { + /* mac */ + INIT_INI_ARRAY(&ah->iniMac[ATH_INI_PRE], NULL, 0, 0); + INIT_INI_ARRAY(&ah->iniMac[ATH_INI_CORE], + ar9340_1p0_mac_core, + ARRAY_SIZE(ar9340_1p0_mac_core), 2); + INIT_INI_ARRAY(&ah->iniMac[ATH_INI_POST], + ar9340_1p0_mac_postamble, + ARRAY_SIZE(ar9340_1p0_mac_postamble), 5); + + /* bb */ + INIT_INI_ARRAY(&ah->iniBB[ATH_INI_PRE], NULL, 0, 0); + INIT_INI_ARRAY(&ah->iniBB[ATH_INI_CORE], + ar9340_1p0_baseband_core, + ARRAY_SIZE(ar9340_1p0_baseband_core), 2); + INIT_INI_ARRAY(&ah->iniBB[ATH_INI_POST], + ar9340_1p0_baseband_postamble, + ARRAY_SIZE(ar9340_1p0_baseband_postamble), 5); + + /* radio */ + INIT_INI_ARRAY(&ah->iniRadio[ATH_INI_PRE], NULL, 0, 0); + INIT_INI_ARRAY(&ah->iniRadio[ATH_INI_CORE], + ar9340_1p0_radio_core, + ARRAY_SIZE(ar9340_1p0_radio_core), 2); + INIT_INI_ARRAY(&ah->iniRadio[ATH_INI_POST], + ar9340_1p0_radio_postamble, + ARRAY_SIZE(ar9340_1p0_radio_postamble), 5); + + /* soc */ + INIT_INI_ARRAY(&ah->iniSOC[ATH_INI_PRE], + ar9340_1p0_soc_preamble, + ARRAY_SIZE(ar9340_1p0_soc_preamble), 2); + INIT_INI_ARRAY(&ah->iniSOC[ATH_INI_CORE], NULL, 0, 0); + INIT_INI_ARRAY(&ah->iniSOC[ATH_INI_POST], + ar9340_1p0_soc_postamble, + ARRAY_SIZE(ar9340_1p0_soc_postamble), 5); + + /* rx/tx gain */ + INIT_INI_ARRAY(&ah->iniModesRxGain, + ar9340Common_wo_xlna_rx_gain_table_1p0, + ARRAY_SIZE(ar9340Common_wo_xlna_rx_gain_table_1p0), + 5); + INIT_INI_ARRAY(&ah->iniModesTxGain, + ar9340Modes_high_ob_db_tx_gain_table_1p0, + ARRAY_SIZE(ar9340Modes_high_ob_db_tx_gain_table_1p0), + 5); + + INIT_INI_ARRAY(&ah->iniModesAdditional, + ar9340Modes_fast_clock_1p0, + ARRAY_SIZE(ar9340Modes_fast_clock_1p0), + 3); + + INIT_INI_ARRAY(&ah->iniModesAdditional_40M, + ar9340_1p0_radio_core_40M, + ARRAY_SIZE(ar9340_1p0_radio_core_40M), + 2); + } else if (AR_SREV_9485_11(ah)) { /* mac */ INIT_INI_ARRAY(&ah->iniMac[ATH_INI_PRE], NULL, 0, 0); INIT_INI_ARRAY(&ah->iniMac[ATH_INI_CORE], diff --git a/drivers/net/wireless/ath/ath9k/ar9003_phy.c b/drivers/net/wireless/ath/ath9k/ar9003_phy.c index 1bc33f5..c4d0805 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_phy.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_phy.c @@ -646,6 +646,9 @@ static int ar9003_hw_process_ini(struct ath_hw *ah, REG_WRITE_ARRAY(&ah->iniModesAdditional, modesIndex, regWrites); + if (AR_SREV_9340(ah) && !ah->is_clk_25mhz) + REG_WRITE_ARRAY(&ah->iniModesAdditional_40M, 1, regWrites); + ar9003_hw_override_ini(ah); ar9003_hw_set_channel_regs(ah, chan); ar9003_hw_set_chain_masks(ah, ah->rxchainmask, ah->txchainmask); diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h index 9b1f415..29a745c 100644 --- a/drivers/net/wireless/ath/ath9k/hw.h +++ b/drivers/net/wireless/ath/ath9k/hw.h @@ -800,6 +800,7 @@ struct ath_hw { struct ar5416IniArray iniPcieSerdes; struct ar5416IniArray iniPcieSerdesLowPower; struct ar5416IniArray iniModesAdditional; + struct ar5416IniArray iniModesAdditional_40M; struct ar5416IniArray iniModesRxGain; struct ar5416IniArray iniModesTxGain; struct ar5416IniArray iniModes_9271_1_0_only; -- cgit v0.10.2 From 070c4d509b1edcd0b8a40177a02e4302416c56d7 Mon Sep 17 00:00:00 2001 From: Vasanthakumar Thiagarajan Date: Tue, 19 Apr 2011 19:29:05 +0530 Subject: ath9k_hw: Don't do ani initialization for AR9340 Signed-off-by: Vasanthakumar Thiagarajan Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index a1eaace..72631b1 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c @@ -462,7 +462,7 @@ static int ath9k_hw_post_init(struct ath_hw *ah) return ecode; } - if (!AR_SREV_9100(ah)) { + if (!AR_SREV_9100(ah) && !AR_SREV_9340(ah)) { ath9k_hw_ani_setup(ah); ath9k_hw_ani_init(ah); } -- cgit v0.10.2 From d7fd52a80f9537970da1f80d785cac67375c05df Mon Sep 17 00:00:00 2001 From: Vasanthakumar Thiagarajan Date: Tue, 19 Apr 2011 19:29:06 +0530 Subject: ath9k_hw: Initialize tx and rx gain table from initvals.h for ar9340 Signed-off-by: Vasanthakumar Thiagarajan Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/ar9003_hw.c b/drivers/net/wireless/ath/ath9k/ar9003_hw.c index 37af721..a55eddb 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_hw.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_hw.c @@ -220,7 +220,12 @@ static void ar9003_tx_gain_table_apply(struct ath_hw *ah) switch (ar9003_hw_get_tx_gain_idx(ah)) { case 0: default: - if (AR_SREV_9485_11(ah)) + if (AR_SREV_9340(ah)) + INIT_INI_ARRAY(&ah->iniModesTxGain, + ar9340Modes_lowest_ob_db_tx_gain_table_1p0, + ARRAY_SIZE(ar9340Modes_lowest_ob_db_tx_gain_table_1p0), + 5); + else if (AR_SREV_9485_11(ah)) INIT_INI_ARRAY(&ah->iniModesTxGain, ar9485_modes_lowest_ob_db_tx_gain_1_1, ARRAY_SIZE(ar9485_modes_lowest_ob_db_tx_gain_1_1), @@ -232,7 +237,12 @@ static void ar9003_tx_gain_table_apply(struct ath_hw *ah) 5); break; case 1: - if (AR_SREV_9485_11(ah)) + if (AR_SREV_9340(ah)) + INIT_INI_ARRAY(&ah->iniModesTxGain, + ar9340Modes_lowest_ob_db_tx_gain_table_1p0, + ARRAY_SIZE(ar9340Modes_lowest_ob_db_tx_gain_table_1p0), + 5); + else if (AR_SREV_9485_11(ah)) INIT_INI_ARRAY(&ah->iniModesTxGain, ar9485Modes_high_ob_db_tx_gain_1_1, ARRAY_SIZE(ar9485Modes_high_ob_db_tx_gain_1_1), @@ -244,7 +254,12 @@ static void ar9003_tx_gain_table_apply(struct ath_hw *ah) 5); break; case 2: - if (AR_SREV_9485_11(ah)) + if (AR_SREV_9340(ah)) + INIT_INI_ARRAY(&ah->iniModesTxGain, + ar9340Modes_lowest_ob_db_tx_gain_table_1p0, + ARRAY_SIZE(ar9340Modes_lowest_ob_db_tx_gain_table_1p0), + 5); + else if (AR_SREV_9485_11(ah)) INIT_INI_ARRAY(&ah->iniModesTxGain, ar9485Modes_low_ob_db_tx_gain_1_1, ARRAY_SIZE(ar9485Modes_low_ob_db_tx_gain_1_1), @@ -256,7 +271,12 @@ static void ar9003_tx_gain_table_apply(struct ath_hw *ah) 5); break; case 3: - if (AR_SREV_9485_11(ah)) + if (AR_SREV_9340(ah)) + INIT_INI_ARRAY(&ah->iniModesTxGain, + ar9340Modes_lowest_ob_db_tx_gain_table_1p0, + ARRAY_SIZE(ar9340Modes_lowest_ob_db_tx_gain_table_1p0), + 5); + else if (AR_SREV_9485_11(ah)) INIT_INI_ARRAY(&ah->iniModesTxGain, ar9485Modes_high_power_tx_gain_1_1, ARRAY_SIZE(ar9485Modes_high_power_tx_gain_1_1), @@ -275,7 +295,12 @@ static void ar9003_rx_gain_table_apply(struct ath_hw *ah) switch (ar9003_hw_get_rx_gain_idx(ah)) { case 0: default: - if (AR_SREV_9485_11(ah)) + if (AR_SREV_9340(ah)) + INIT_INI_ARRAY(&ah->iniModesRxGain, + ar9340Common_rx_gain_table_1p0, + ARRAY_SIZE(ar9340Common_rx_gain_table_1p0), + 2); + else if (AR_SREV_9485_11(ah)) INIT_INI_ARRAY(&ah->iniModesRxGain, ar9485Common_wo_xlna_rx_gain_1_1, ARRAY_SIZE(ar9485Common_wo_xlna_rx_gain_1_1), @@ -287,7 +312,12 @@ static void ar9003_rx_gain_table_apply(struct ath_hw *ah) 2); break; case 1: - if (AR_SREV_9485_11(ah)) + if (AR_SREV_9340(ah)) + INIT_INI_ARRAY(&ah->iniModesRxGain, + ar9340Common_wo_xlna_rx_gain_table_1p0, + ARRAY_SIZE(ar9340Common_wo_xlna_rx_gain_table_1p0), + 2); + else if (AR_SREV_9485_11(ah)) INIT_INI_ARRAY(&ah->iniModesRxGain, ar9485Common_wo_xlna_rx_gain_1_1, ARRAY_SIZE(ar9485Common_wo_xlna_rx_gain_1_1), -- cgit v0.10.2 From d1395d85fa58438c70b77185b7c5780b94046348 Mon Sep 17 00:00:00 2001 From: Vasanthakumar Thiagarajan Date: Tue, 19 Apr 2011 19:29:07 +0530 Subject: ath9k_hw: Read spur frequency information from eeprom for AR9340 Signed-off-by: Vasanthakumar Thiagarajan Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/ar9003_phy.c b/drivers/net/wireless/ath/ath9k/ar9003_phy.c index c4d0805..0b999f9 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_phy.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_phy.c @@ -151,7 +151,7 @@ static void ar9003_hw_spur_mitigate_mrc_cck(struct ath_hw *ah, * is out-of-band and can be ignored. */ - if (AR_SREV_9485(ah)) { + if (AR_SREV_9485(ah) || AR_SREV_9340(ah)) { spur_fbin_ptr = ar9003_get_spur_chan_ptr(ah, IS_CHAN_2GHZ(chan)); if (spur_fbin_ptr[0] == 0) /* No spur */ @@ -176,7 +176,7 @@ static void ar9003_hw_spur_mitigate_mrc_cck(struct ath_hw *ah, for (i = 0; i < max_spur_cnts; i++) { negative = 0; - if (AR_SREV_9485(ah)) + if (AR_SREV_9485(ah) || AR_SREV_9340(ah)) cur_bb_spur = FBIN2FREQ(spur_fbin_ptr[i], IS_CHAN_2GHZ(chan)) - synth_freq; else -- cgit v0.10.2 From 17869f4fe940407b5b80039110c0257c90e18a99 Mon Sep 17 00:00:00 2001 From: Vasanthakumar Thiagarajan Date: Tue, 19 Apr 2011 19:29:08 +0530 Subject: ath9k_hw: Configure RF channel freqency for AR9340 Signed-off-by: Vasanthakumar Thiagarajan Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/ar9003_phy.c b/drivers/net/wireless/ath/ath9k/ar9003_phy.c index 0b999f9..ea2f60c 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_phy.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_phy.c @@ -86,14 +86,31 @@ static int ar9003_hw_set_channel(struct ath_hw *ah, struct ath9k_channel *chan) channelSel = (freq * 4) / 120; chan_frac = (((freq * 4) % 120) * 0x20000) / 120; channelSel = (channelSel << 17) | chan_frac; + } else if (AR_SREV_9340(ah)) { + if (ah->is_clk_25mhz) { + u32 chan_frac; + + channelSel = (freq * 2) / 75; + chan_frac = (((freq * 2) % 75) * 0x20000) / 75; + channelSel = (channelSel << 17) | chan_frac; + } else + channelSel = CHANSEL_2G(freq) >> 1; } else channelSel = CHANSEL_2G(freq); /* Set to 2G mode */ bMode = 1; } else { - channelSel = CHANSEL_5G(freq); - /* Doubler is ON, so, divide channelSel by 2. */ - channelSel >>= 1; + if (AR_SREV_9340(ah) && ah->is_clk_25mhz) { + u32 chan_frac; + + channelSel = (freq * 2) / 75; + chan_frac = ((freq % 75) * 0x20000) / 75; + channelSel = (channelSel << 17) | chan_frac; + } else { + channelSel = CHANSEL_5G(freq); + /* Doubler is ON, so, divide channelSel by 2. */ + channelSel >>= 1; + } /* Set to 5G mode */ bMode = 0; } -- cgit v0.10.2 From e758ff8f7fc9ce96e94131b13e70af2c197fa05e Mon Sep 17 00:00:00 2001 From: Vasanthakumar Thiagarajan Date: Tue, 19 Apr 2011 19:29:09 +0530 Subject: ath9k_hw: Clean up rx/tx chain configuration before AGC/IQ cal Use hw supported chains instead of hard coded values. Signed-off-by: Vasanthakumar Thiagarajan Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/ar9003_calib.c b/drivers/net/wireless/ath/ath9k/ar9003_calib.c index 4a4cd88..09f3aa7 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_calib.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_calib.c @@ -940,21 +940,18 @@ static bool ar9003_hw_init_cal(struct ath_hw *ah, struct ath9k_channel *chan) { struct ath_common *common = ath9k_hw_common(ah); + struct ath9k_hw_capabilities *pCap = &ah->caps; int val; val = REG_READ(ah, AR_ENT_OTP); ath_dbg(common, ATH_DBG_CALIBRATE, "ath9k: AR_ENT_OTP 0x%x\n", val); - if (AR_SREV_9485(ah)) - ar9003_hw_set_chain_masks(ah, 0x1, 0x1); - else if (val & AR_ENT_OTP_CHAIN2_DISABLE) + /* Configure rx/tx chains before running AGC/TxiQ cals */ + if (val & AR_ENT_OTP_CHAIN2_DISABLE) ar9003_hw_set_chain_masks(ah, 0x3, 0x3); else - /* - * 0x7 = 0b111 , AR9003 needs to be configured for 3-chain - * mode before running AGC/TxIQ cals - */ - ar9003_hw_set_chain_masks(ah, 0x7, 0x7); + ar9003_hw_set_chain_masks(ah, pCap->rx_chainmask, + pCap->tx_chainmask); /* Do Tx IQ Calibration */ if (AR_SREV_9485(ah)) -- cgit v0.10.2 From 66953d438576938b02e6ff0ade1958f3e90af4a9 Mon Sep 17 00:00:00 2001 From: Vasanthakumar Thiagarajan Date: Tue, 19 Apr 2011 19:29:10 +0530 Subject: ath9k_hw: Fix register offset AR_PHY_65NM_CH0_THERM for AR9340 Signed-off-by: Vasanthakumar Thiagarajan Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/ar9003_phy.h b/drivers/net/wireless/ath/ath9k/ar9003_phy.h index 8bdda2c..d133ee8 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_phy.h +++ b/drivers/net/wireless/ath/ath9k/ar9003_phy.h @@ -588,7 +588,7 @@ #define AR_PHY_65NM_CH0_BIAS2 0x160c4 #define AR_PHY_65NM_CH0_BIAS4 0x160cc #define AR_PHY_65NM_CH0_RXTX4 0x1610c -#define AR_PHY_65NM_CH0_THERM (AR_SREV_9485(ah) ? 0x1628c : 0x16290) +#define AR_PHY_65NM_CH0_THERM (AR_SREV_9300(ah) ? 0x16290 : 0x1628c) #define AR_PHY_65NM_CH0_THERM_LOCAL 0x80000000 #define AR_PHY_65NM_CH0_THERM_LOCAL_S 31 -- cgit v0.10.2 From 160b7fb4a07f52a6ba883b52fbb992f0086f99f6 Mon Sep 17 00:00:00 2001 From: Vasanthakumar Thiagarajan Date: Tue, 19 Apr 2011 19:29:11 +0530 Subject: ath9k_hw: Don't configure AR_CH0_THERM for AR9340 Signed-off-by: Vasanthakumar Thiagarajan Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c b/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c index 4a92718..685ce91 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c @@ -3448,9 +3448,13 @@ static void ar9003_hw_xpa_bias_level_apply(struct ath_hw *ah, bool is2ghz) REG_RMW_FIELD(ah, AR_CH0_TOP2, AR_CH0_TOP2_XPABIASLVL, bias); else { REG_RMW_FIELD(ah, AR_CH0_TOP, AR_CH0_TOP_XPABIASLVL, bias); - REG_RMW_FIELD(ah, AR_CH0_THERM, AR_CH0_THERM_XPABIASLVL_MSB, - bias >> 2); - REG_RMW_FIELD(ah, AR_CH0_THERM, AR_CH0_THERM_XPASHORT2GND, 1); + if (!AR_SREV_9340(ah)) { + REG_RMW_FIELD(ah, AR_CH0_THERM, + AR_CH0_THERM_XPABIASLVL_MSB, + bias >> 2); + REG_RMW_FIELD(ah, AR_CH0_THERM, + AR_CH0_THERM_XPASHORT2GND, 1); + } } } -- cgit v0.10.2 From 3594beae705523982823f84bf4997f680b2cf75f Mon Sep 17 00:00:00 2001 From: Vasanthakumar Thiagarajan Date: Tue, 19 Apr 2011 19:29:12 +0530 Subject: ath9k_hw: Skip internal regulator configuration for AR9340 Signed-off-by: Vasanthakumar Thiagarajan Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c b/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c index 685ce91..6e5baa7 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c @@ -3753,7 +3753,8 @@ static void ath9k_hw_ar9300_set_board_values(struct ath_hw *ah, ar9003_hw_ant_ctrl_apply(ah, IS_CHAN_2GHZ(chan)); ar9003_hw_drive_strength_apply(ah); ar9003_hw_atten_apply(ah, chan); - ar9003_hw_internal_regulator_apply(ah); + if (!AR_SREV_9340(ah)) + ar9003_hw_internal_regulator_apply(ah); if (AR_SREV_9485(ah)) ar9003_hw_apply_tuning_caps(ah); } -- cgit v0.10.2 From a969c09184e7cb7d14838598b54c6effbef8b584 Mon Sep 17 00:00:00 2001 From: Vasanthakumar Thiagarajan Date: Tue, 19 Apr 2011 19:29:13 +0530 Subject: ath9k_hw: Configure tuning capacitance value for AR9340 as well Signed-off-by: Vasanthakumar Thiagarajan Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c b/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c index 6e5baa7..262fb62 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c @@ -3755,7 +3755,7 @@ static void ath9k_hw_ar9300_set_board_values(struct ath_hw *ah, ar9003_hw_atten_apply(ah, chan); if (!AR_SREV_9340(ah)) ar9003_hw_internal_regulator_apply(ah); - if (AR_SREV_9485(ah)) + if (AR_SREV_9485(ah) || AR_SREV_9340(ah)) ar9003_hw_apply_tuning_caps(ah); } -- cgit v0.10.2 From 2be7bfe0b454bc7c60ede777907ec817baa6196e Mon Sep 17 00:00:00 2001 From: Vasanthakumar Thiagarajan Date: Tue, 19 Apr 2011 19:29:14 +0530 Subject: ath9k_hw: Enable byte Tx/Rx data swap for AR9340 Signed-off-by: Vasanthakumar Thiagarajan Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index 72631b1..39dd901 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c @@ -1544,7 +1544,9 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan, REG_WRITE(ah, AR_CFG, AR_CFG_SWTD | AR_CFG_SWRD); } #ifdef __BIG_ENDIAN - else + else if (AR_SREV_9340(ah)) + REG_RMW(ah, AR_CFG, AR_CFG_SWRB | AR_CFG_SWTB, 0); + else REG_WRITE(ah, AR_CFG, AR_CFG_SWTD | AR_CFG_SWRD); #endif } -- cgit v0.10.2 From 2976bc5ebfb6c6dd37b4513540e567de0a2313f7 Mon Sep 17 00:00:00 2001 From: Vasanthakumar Thiagarajan Date: Tue, 19 Apr 2011 19:29:15 +0530 Subject: ath9k_hw: Configure chain switch table and attenuation control only for active chains Signed-off-by: Vasanthakumar Thiagarajan Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c b/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c index 262fb62..fd9b8c4 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c @@ -3501,23 +3501,28 @@ static u16 ar9003_hw_ant_ctrl_chain_get(struct ath_hw *ah, static void ar9003_hw_ant_ctrl_apply(struct ath_hw *ah, bool is2ghz) { + int chain; + static const u32 switch_chain_reg[AR9300_MAX_CHAINS] = { + AR_PHY_SWITCH_CHAIN_0, + AR_PHY_SWITCH_CHAIN_1, + AR_PHY_SWITCH_CHAIN_2, + }; + u32 value = ar9003_hw_ant_ctrl_common_get(ah, is2ghz); + REG_RMW_FIELD(ah, AR_PHY_SWITCH_COM, AR_SWITCH_TABLE_COM_ALL, value); value = ar9003_hw_ant_ctrl_common_2_get(ah, is2ghz); REG_RMW_FIELD(ah, AR_PHY_SWITCH_COM_2, AR_SWITCH_TABLE_COM2_ALL, value); - value = ar9003_hw_ant_ctrl_chain_get(ah, 0, is2ghz); - REG_RMW_FIELD(ah, AR_PHY_SWITCH_CHAIN_0, AR_SWITCH_TABLE_ALL, value); - - if (!AR_SREV_9485(ah)) { - value = ar9003_hw_ant_ctrl_chain_get(ah, 1, is2ghz); - REG_RMW_FIELD(ah, AR_PHY_SWITCH_CHAIN_1, AR_SWITCH_TABLE_ALL, - value); - - value = ar9003_hw_ant_ctrl_chain_get(ah, 2, is2ghz); - REG_RMW_FIELD(ah, AR_PHY_SWITCH_CHAIN_2, AR_SWITCH_TABLE_ALL, - value); + for (chain = 0; chain < AR9300_MAX_CHAINS; chain++) { + if ((ah->rxchainmask & BIT(chain)) || + (ah->txchainmask & BIT(chain))) { + value = ar9003_hw_ant_ctrl_chain_get(ah, chain, + is2ghz); + REG_RMW_FIELD(ah, switch_chain_reg[chain], + AR_SWITCH_TABLE_ALL, value); + } } if (AR_SREV_9485(ah)) { @@ -3638,13 +3643,16 @@ static void ar9003_hw_atten_apply(struct ath_hw *ah, struct ath9k_channel *chan) /* Test value. if 0 then attenuation is unused. Don't load anything. */ for (i = 0; i < 3; i++) { - value = ar9003_hw_atten_chain_get(ah, i, chan); - REG_RMW_FIELD(ah, ext_atten_reg[i], - AR_PHY_EXT_ATTEN_CTL_XATTEN1_DB, value); - - value = ar9003_hw_atten_chain_get_margin(ah, i, chan); - REG_RMW_FIELD(ah, ext_atten_reg[i], - AR_PHY_EXT_ATTEN_CTL_XATTEN1_MARGIN, value); + if (ah->txchainmask & BIT(i)) { + value = ar9003_hw_atten_chain_get(ah, i, chan); + REG_RMW_FIELD(ah, ext_atten_reg[i], + AR_PHY_EXT_ATTEN_CTL_XATTEN1_DB, value); + + value = ar9003_hw_atten_chain_get_margin(ah, i, chan); + REG_RMW_FIELD(ah, ext_atten_reg[i], + AR_PHY_EXT_ATTEN_CTL_XATTEN1_MARGIN, + value); + } } } -- cgit v0.10.2 From 5d48ae78cf81b4006ee1b7690b850db84820dc14 Mon Sep 17 00:00:00 2001 From: Vasanthakumar Thiagarajan Date: Tue, 19 Apr 2011 19:29:16 +0530 Subject: ath9k_hw: Read iq calibration data only for active chains Signed-off-by: Vasanthakumar Thiagarajan Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/ar9003_calib.c b/drivers/net/wireless/ath/ath9k/ar9003_calib.c index 09f3aa7..bceff49 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_calib.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_calib.c @@ -185,17 +185,19 @@ static void ar9003_hw_iqcal_collect(struct ath_hw *ah) /* Accumulate IQ cal measures for active chains */ for (i = 0; i < AR5416_MAX_CHAINS; i++) { - ah->totalPowerMeasI[i] += - REG_READ(ah, AR_PHY_CAL_MEAS_0(i)); - ah->totalPowerMeasQ[i] += - REG_READ(ah, AR_PHY_CAL_MEAS_1(i)); - ah->totalIqCorrMeas[i] += - (int32_t) REG_READ(ah, AR_PHY_CAL_MEAS_2(i)); - ath_dbg(ath9k_hw_common(ah), ATH_DBG_CALIBRATE, - "%d: Chn %d pmi=0x%08x;pmq=0x%08x;iqcm=0x%08x;\n", - ah->cal_samples, i, ah->totalPowerMeasI[i], - ah->totalPowerMeasQ[i], - ah->totalIqCorrMeas[i]); + if (ah->txchainmask & BIT(i)) { + ah->totalPowerMeasI[i] += + REG_READ(ah, AR_PHY_CAL_MEAS_0(i)); + ah->totalPowerMeasQ[i] += + REG_READ(ah, AR_PHY_CAL_MEAS_1(i)); + ah->totalIqCorrMeas[i] += + (int32_t) REG_READ(ah, AR_PHY_CAL_MEAS_2(i)); + ath_dbg(ath9k_hw_common(ah), ATH_DBG_CALIBRATE, + "%d: Chn %d pmi=0x%08x;pmq=0x%08x;iqcm=0x%08x;\n", + ah->cal_samples, i, ah->totalPowerMeasI[i], + ah->totalPowerMeasQ[i], + ah->totalIqCorrMeas[i]); + } } } -- cgit v0.10.2 From 247eee0e4ee3e23fd4f2918cdffa1e20d2261fa8 Mon Sep 17 00:00:00 2001 From: Vasanthakumar Thiagarajan Date: Tue, 19 Apr 2011 19:29:17 +0530 Subject: ath9k: Add AR9340 platform id to id table Signed-off-by: Vasanthakumar Thiagarajan Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/ahb.c b/drivers/net/wireless/ath/ath9k/ahb.c index 5193ed5..090f314 100644 --- a/drivers/net/wireless/ath/ath9k/ahb.c +++ b/drivers/net/wireless/ath/ath9k/ahb.c @@ -26,6 +26,10 @@ const struct platform_device_id ath9k_platform_id_table[] = { .name = "ath9k", .driver_data = AR5416_AR9100_DEVID, }, + { + .name = "ar934x_wmac", + .driver_data = AR9300_DEVID_AR9340, + }, {}, }; -- cgit v0.10.2 From ecb1d385ad61001ff85407e5370a40934a1cc50b Mon Sep 17 00:00:00 2001 From: Vasanthakumar Thiagarajan Date: Tue, 19 Apr 2011 19:29:18 +0530 Subject: ath9k_hw: Assign macversion based on devid for built-in wmac Signed-off-by: Vasanthakumar Thiagarajan Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index 39dd901..2807608 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c @@ -247,6 +247,17 @@ static void ath9k_hw_read_revisions(struct ath_hw *ah) { u32 val; + switch (ah->hw_version.devid) { + case AR5416_AR9100_DEVID: + ah->hw_version.macVersion = AR_SREV_VERSION_9100; + break; + case AR9300_DEVID_AR9340: + ah->hw_version.macVersion = AR_SREV_VERSION_9340; + val = REG_READ(ah, AR_SREV); + ah->hw_version.macRev = MS(val, AR_SREV_REVISION2); + return; + } + val = REG_READ(ah, AR_SREV) & AR_SREV_ID; if (val == 0xFF) { @@ -484,9 +495,6 @@ static int __ath9k_hw_init(struct ath_hw *ah) struct ath_common *common = ath9k_hw_common(ah); int r = 0; - if (ah->hw_version.devid == AR5416_AR9100_DEVID) - ah->hw_version.macVersion = AR_SREV_VERSION_9100; - ath9k_hw_read_revisions(ah); /* -- cgit v0.10.2 From 79d1d2b8a34fd36e63cc7f5267cf79217a44edcc Mon Sep 17 00:00:00 2001 From: Vasanthakumar Thiagarajan Date: Tue, 19 Apr 2011 19:29:19 +0530 Subject: ath9k_hw: Disable INTR_HOST1_FATAL to avoid interrupt strom with ar9430 Signed-off-by: Vasanthakumar Thiagarajan Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index 2807608..66566ef 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c @@ -795,12 +795,16 @@ static void ath9k_hw_init_pll(struct ath_hw *ah, static void ath9k_hw_init_interrupt_masks(struct ath_hw *ah, enum nl80211_iftype opmode) { + u32 sync_default = AR_INTR_SYNC_DEFAULT; u32 imr_reg = AR_IMR_TXERR | AR_IMR_TXURN | AR_IMR_RXERR | AR_IMR_RXORN | AR_IMR_BCNMISC; + if (AR_SREV_9340(ah)) + sync_default &= ~AR_INTR_SYNC_HOST1_FATAL; + if (AR_SREV_9300_20_OR_LATER(ah)) { imr_reg |= AR_IMR_RXOK_HP; if (ah->config.rx_intr_mitigation) @@ -831,7 +835,7 @@ static void ath9k_hw_init_interrupt_masks(struct ath_hw *ah, if (!AR_SREV_9100(ah)) { REG_WRITE(ah, AR_INTR_SYNC_CAUSE, 0xFFFFFFFF); - REG_WRITE(ah, AR_INTR_SYNC_ENABLE, AR_INTR_SYNC_DEFAULT); + REG_WRITE(ah, AR_INTR_SYNC_ENABLE, sync_default); REG_WRITE(ah, AR_INTR_SYNC_MASK, 0); } diff --git a/drivers/net/wireless/ath/ath9k/mac.c b/drivers/net/wireless/ath/ath9k/mac.c index 6f431cb..d86b839 100644 --- a/drivers/net/wireless/ath/ath9k/mac.c +++ b/drivers/net/wireless/ath/ath9k/mac.c @@ -793,10 +793,14 @@ EXPORT_SYMBOL(ath9k_hw_disable_interrupts); void ath9k_hw_enable_interrupts(struct ath_hw *ah) { struct ath_common *common = ath9k_hw_common(ah); + u32 sync_default = AR_INTR_SYNC_DEFAULT; if (!(ah->imask & ATH9K_INT_GLOBAL)) return; + if (AR_SREV_9340(ah)) + sync_default &= ~AR_INTR_SYNC_HOST1_FATAL; + ath_dbg(common, ATH_DBG_INTERRUPT, "enable IER\n"); REG_WRITE(ah, AR_IER, AR_IER_ENABLE); if (!AR_SREV_9100(ah)) { @@ -805,10 +809,8 @@ void ath9k_hw_enable_interrupts(struct ath_hw *ah) REG_WRITE(ah, AR_INTR_ASYNC_MASK, AR_INTR_MAC_IRQ); - REG_WRITE(ah, AR_INTR_SYNC_ENABLE, - AR_INTR_SYNC_DEFAULT); - REG_WRITE(ah, AR_INTR_SYNC_MASK, - AR_INTR_SYNC_DEFAULT); + REG_WRITE(ah, AR_INTR_SYNC_ENABLE, sync_default); + REG_WRITE(ah, AR_INTR_SYNC_MASK, sync_default); } ath_dbg(common, ATH_DBG_INTERRUPT, "AR_IMR 0x%x IER 0x%x\n", REG_READ(ah, AR_IMR), REG_READ(ah, AR_IER)); -- cgit v0.10.2 From bca04689a2260ca4da227e7f7fa35f28f40e6a00 Mon Sep 17 00:00:00 2001 From: Vasanthakumar Thiagarajan Date: Tue, 19 Apr 2011 19:29:20 +0530 Subject: ath9k_hw: Enable AR9340 support AR9340 is a AR9003 family built-in 2x2 wmac of ar934x SOCs. It is single band in ar9341 SOC and dual band in ar9344/ar9342 SOCs. Signed-off-by: Vasanthakumar Thiagarajan Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index 66566ef..b7eb793 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c @@ -552,6 +552,7 @@ static int __ath9k_hw_init(struct ath_hw *ah) case AR_SREV_VERSION_9271: case AR_SREV_VERSION_9300: case AR_SREV_VERSION_9485: + case AR_SREV_VERSION_9340: break; default: ath_err(common, @@ -629,6 +630,7 @@ int ath9k_hw_init(struct ath_hw *ah) case AR2427_DEVID_PCIE: case AR9300_DEVID_PCIE: case AR9300_DEVID_AR9485_PCIE: + case AR9300_DEVID_AR9340: break; default: if (common->bus_ops->ath_bus_type == ATH_USB) -- cgit v0.10.2 From 9be1cb39c6551231a4f210097685da11aa6a537b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= Date: Tue, 19 Apr 2011 22:40:22 +0200 Subject: ssb: pci: trivial: correct amount of maximum retries 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 diff --git a/drivers/ssb/driver_pcicore.c b/drivers/ssb/driver_pcicore.c index 1ba9f0e..dbda168 100644 --- a/drivers/ssb/driver_pcicore.c +++ b/drivers/ssb/driver_pcicore.c @@ -522,7 +522,7 @@ static u16 ssb_pcie_mdio_read(struct ssb_pcicore *pc, u8 device, u8 address) pcicore_write32(pc, mdio_data, v); /* Wait for the device to complete the transaction */ udelay(10); - for (i = 0; i < 200; i++) { + for (i = 0; i < max_retries; i++) { v = pcicore_read32(pc, mdio_control); if (v & 0x100 /* Trans complete */) { udelay(10); -- cgit v0.10.2 From 3c35c84a70fc7d76cf7d975481fcb30468c68818 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= Date: Tue, 19 Apr 2011 22:40:23 +0200 Subject: ssb: cc: use correct min_msk for 0x4312 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Default min_msk on my 0x4312 is 0x80000CBB, not 0xCBB. Now we follow specs and wl (noticed in MMIO dumps). Signed-off-by: RafaÅ‚ MiÅ‚ecki Signed-off-by: John W. Linville diff --git a/drivers/ssb/driver_chipcommon_pmu.c b/drivers/ssb/driver_chipcommon_pmu.c index 5732bb2..305ade7 100644 --- a/drivers/ssb/driver_chipcommon_pmu.c +++ b/drivers/ssb/driver_chipcommon_pmu.c @@ -423,6 +423,8 @@ static void ssb_pmu_resources_init(struct ssb_chipcommon *cc) switch (bus->chip_id) { case 0x4312: + min_msk = 0xCBB; + break; case 0x4322: /* We keep the default settings: * min_msk = 0xCBB -- cgit v0.10.2 From 0ff2b5c05d4dd84222a8e163335c5b550e2ca195 Mon Sep 17 00:00:00 2001 From: Sujith Manoharan Date: Wed, 20 Apr 2011 11:00:34 +0530 Subject: ath9k: Fix warnings from -Wunused-but-set-variable Signed-off-by: Sujith Manoharan Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/ani.c b/drivers/net/wireless/ath/ath9k/ani.c index 2e31c77..5a1f4f5 100644 --- a/drivers/net/wireless/ath/ath9k/ani.c +++ b/drivers/net/wireless/ath/ath9k/ani.c @@ -899,12 +899,6 @@ void ath9k_hw_ani_init(struct ath_hw *ah) * check here default level should not modify INI setting. */ if (use_new_ani(ah)) { - const struct ani_ofdm_level_entry *entry_ofdm; - const struct ani_cck_level_entry *entry_cck; - - entry_ofdm = &ofdm_level_table[ATH9K_ANI_OFDM_DEF_LEVEL]; - entry_cck = &cck_level_table[ATH9K_ANI_CCK_DEF_LEVEL]; - ah->aniperiod = ATH9K_ANI_PERIOD_NEW; ah->config.ani_poll_interval = ATH9K_ANI_POLLINTERVAL_NEW; } else { diff --git a/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c b/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c index fd9b8c4..97f970c 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c @@ -3217,7 +3217,6 @@ static int ar9300_compress_decision(struct ath_hw *ah, u8 *word, int length, int mdata_size) { struct ath_common *common = ath9k_hw_common(ah); - u8 *dptr; const struct ar9300_eeprom *eep = NULL; switch (code) { @@ -3235,7 +3234,6 @@ static int ar9300_compress_decision(struct ath_hw *ah, break; case _CompressBlock: if (reference == 0) { - dptr = mptr; } else { eep = ar9003_eeprom_struct_find_by_id(reference); if (eep == NULL) { diff --git a/drivers/net/wireless/ath/ath9k/ar9003_phy.c b/drivers/net/wireless/ath/ath9k/ar9003_phy.c index ea2f60c..c83be2d 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_phy.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_phy.c @@ -616,29 +616,25 @@ static int ar9003_hw_process_ini(struct ath_hw *ah, struct ath_regulatory *regulatory = ath9k_hw_regulatory(ah); unsigned int regWrites = 0, i; struct ieee80211_channel *channel = chan->chan; - u32 modesIndex, freqIndex; + u32 modesIndex; switch (chan->chanmode) { case CHANNEL_A: case CHANNEL_A_HT20: modesIndex = 1; - freqIndex = 1; break; case CHANNEL_A_HT40PLUS: case CHANNEL_A_HT40MINUS: modesIndex = 2; - freqIndex = 1; break; case CHANNEL_G: case CHANNEL_G_HT20: case CHANNEL_B: modesIndex = 4; - freqIndex = 2; break; case CHANNEL_G_HT40PLUS: case CHANNEL_G_HT40MINUS: modesIndex = 3; - freqIndex = 2; break; default: diff --git a/drivers/net/wireless/ath/ath9k/eeprom_9287.c b/drivers/net/wireless/ath/ath9k/eeprom_9287.c index 1357975..b87db47 100644 --- a/drivers/net/wireless/ath/ath9k/eeprom_9287.c +++ b/drivers/net/wireless/ath/ath9k/eeprom_9287.c @@ -319,10 +319,9 @@ static void ath9k_hw_set_ar9287_power_cal_table(struct ath_hw *ah, u16 numXpdGain, xpdMask; u16 xpdGainValues[AR5416_NUM_PD_GAINS] = {0, 0, 0, 0}; u32 reg32, regOffset, regChainOffset, regval; - int16_t modalIdx, diff = 0; + int16_t diff = 0; struct ar9287_eeprom *pEepData = &ah->eeprom.map9287; - modalIdx = IS_CHAN_2GHZ(chan) ? 1 : 0; xpdMask = pEepData->modalHeader.xpdGain; if ((pEepData->baseEepHeader.version & AR9287_EEP_VER_MINOR_MASK) >= diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c b/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c index a157107..0ded2c6 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c @@ -74,7 +74,7 @@ static void ath9k_htc_beacon_config_sta(struct ath9k_htc_priv *priv, __be32 htc_imask = 0; u64 tsf; int num_beacons, offset, dtim_dec_count, cfp_dec_count; - int ret; + int ret __attribute__ ((unused)); u8 cmd_rsp; memset(&bs, 0, sizeof(bs)); @@ -190,7 +190,7 @@ static void ath9k_htc_beacon_config_ap(struct ath9k_htc_priv *priv, enum ath9k_int imask = 0; u32 nexttbtt, intval, tsftu; __be32 htc_imask = 0; - int ret; + int ret __attribute__ ((unused)); u8 cmd_rsp; u64 tsf; @@ -246,7 +246,7 @@ static void ath9k_htc_beacon_config_adhoc(struct ath9k_htc_priv *priv, enum ath9k_int imask = 0; u32 nexttbtt, intval, tsftu; __be32 htc_imask = 0; - int ret; + int ret __attribute__ ((unused)); u8 cmd_rsp; u64 tsf; diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_gpio.c b/drivers/net/wireless/ath/ath9k/htc_drv_gpio.c index dc0b33d..138f8e1 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_gpio.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_gpio.c @@ -74,6 +74,10 @@ static void ath_btcoex_period_work(struct work_struct *work) aggr = priv->op_flags & OP_BT_PRIORITY_DETECTED; WMI_CMD_BUF(WMI_AGGR_LIMIT_CMD, &aggr); + if (ret) { + ath_err(common, "Unable to set BTCOEX parameters\n"); + return; + } ath9k_cmn_btcoex_bt_stomp(common, is_btscan ? ATH_BTCOEX_STOMP_ALL : btcoex->bt_stomp_type); diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_main.c b/drivers/net/wireless/ath/ath9k/htc_drv_main.c index 4de3864..7cff554 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_main.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_main.c @@ -332,6 +332,11 @@ static void __ath9k_htc_remove_monitor_interface(struct ath9k_htc_priv *priv) memcpy(&hvif.myaddr, common->macaddr, ETH_ALEN); hvif.index = priv->mon_vif_idx; WMI_CMD_BUF(WMI_VAP_REMOVE_CMDID, &hvif); + if (ret) { + ath_err(common, "Unable to remove monitor interface at idx: %d\n", + priv->mon_vif_idx); + } + priv->nvifs--; priv->vif_slot &= ~(1 << priv->mon_vif_idx); } @@ -964,7 +969,7 @@ static void ath9k_htc_stop(struct ieee80211_hw *hw) struct ath9k_htc_priv *priv = hw->priv; struct ath_hw *ah = priv->ah; struct ath_common *common = ath9k_hw_common(ah); - int ret = 0; + int ret __attribute__ ((unused)); u8 cmd_rsp; mutex_lock(&priv->mutex); @@ -1135,6 +1140,10 @@ static void ath9k_htc_remove_interface(struct ieee80211_hw *hw, memcpy(&hvif.myaddr, vif->addr, ETH_ALEN); hvif.index = avp->index; WMI_CMD_BUF(WMI_VAP_REMOVE_CMDID, &hvif); + if (ret) { + ath_err(common, "Unable to remove interface at idx: %d\n", + avp->index); + } priv->nvifs--; priv->vif_slot &= ~(1 << avp->index); diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c b/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c index 723a3a9..a898dac 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c @@ -446,7 +446,6 @@ static void ath9k_htc_tx_process(struct ath9k_htc_priv *priv, struct ieee80211_tx_info *tx_info; struct ieee80211_tx_rate *rate; struct ieee80211_conf *cur_conf = &priv->hw->conf; - struct ieee80211_supported_band *sband; bool txok; int slot; @@ -461,7 +460,6 @@ static void ath9k_htc_tx_process(struct ath9k_htc_priv *priv, tx_info = IEEE80211_SKB_CB(skb); vif = tx_info->control.vif; rate = &tx_info->status.rates[0]; - sband = priv->hw->wiphy->bands[cur_conf->channel->band]; memset(&tx_info->status, 0, sizeof(tx_info->status)); diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index b7eb793..0fcfa59 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c @@ -1866,7 +1866,7 @@ int ath9k_hw_fill_cap_info(struct ath_hw *ah) struct ath_common *common = ath9k_hw_common(ah); struct ath_btcoex_hw *btcoex_hw = &ah->btcoex_hw; - u16 capField = 0, eeval; + u16 eeval; u8 ant_div_ctl1, tx_chainmask, rx_chainmask; eeval = ah->eep_ops->get_eeprom(ah, EEP_REG_0); @@ -1877,8 +1877,6 @@ int ath9k_hw_fill_cap_info(struct ath_hw *ah) eeval |= AR9285_RDEXT_DEFAULT; regulatory->current_rd_ext = eeval; - capField = ah->eep_ops->get_eeprom(ah, EEP_OP_CAP); - if (ah->opmode != NL80211_IFTYPE_AP && ah->hw_version.subvendorid == AR_SUBVENDOR_ID_NEW_A) { if (regulatory->current_rd == 0x64 || diff --git a/drivers/net/wireless/ath/ath9k/rc.c b/drivers/net/wireless/ath/ath9k/rc.c index 2a40532..b877d96 100644 --- a/drivers/net/wireless/ath/ath9k/rc.c +++ b/drivers/net/wireless/ath/ath9k/rc.c @@ -854,14 +854,13 @@ static void ath_get_rate(void *priv, struct ieee80211_sta *sta, void *priv_sta, ath_rc_rate_set_rtscts(sc, rate_table, tx_info); } -static bool ath_rc_update_per(struct ath_softc *sc, +static void ath_rc_update_per(struct ath_softc *sc, const struct ath_rate_table *rate_table, struct ath_rate_priv *ath_rc_priv, struct ieee80211_tx_info *tx_info, int tx_rate, int xretries, int retries, u32 now_msec) { - bool state_change = false; int count, n_bad_frames; u8 last_per; static const u32 nretry_to_per_lookup[10] = { @@ -992,8 +991,6 @@ static bool ath_rc_update_per(struct ath_softc *sc, } } - - return state_change; } static void ath_debug_stat_retries(struct ath_rate_priv *rc, int rix, @@ -1017,7 +1014,6 @@ static void ath_rc_update_ht(struct ath_softc *sc, u32 now_msec = jiffies_to_msecs(jiffies); int rate; u8 last_per; - bool state_change = false; const struct ath_rate_table *rate_table = ath_rc_priv->rate_table; int size = ath_rc_priv->rate_table_size; @@ -1027,9 +1023,9 @@ static void ath_rc_update_ht(struct ath_softc *sc, last_per = ath_rc_priv->per[tx_rate]; /* Update PER first */ - state_change = ath_rc_update_per(sc, rate_table, ath_rc_priv, - tx_info, tx_rate, xretries, - retries, now_msec); + ath_rc_update_per(sc, rate_table, ath_rc_priv, + tx_info, tx_rate, xretries, + retries, now_msec); /* * If this rate looks bad (high PER) then stop using it for diff --git a/drivers/net/wireless/ath/ath9k/recv.c b/drivers/net/wireless/ath/ath9k/recv.c index b81bfc4..abff2d5 100644 --- a/drivers/net/wireless/ath/ath9k/recv.c +++ b/drivers/net/wireless/ath/ath9k/recv.c @@ -1339,7 +1339,7 @@ static void ath_ant_comb_scan(struct ath_softc *sc, struct ath_rx_status *rs) struct ath_hw_antcomb_conf div_ant_conf; struct ath_ant_comb *antcomb = &sc->ant_comb; int alt_ratio = 0, alt_rssi_avg = 0, main_rssi_avg = 0, curr_alt_set; - int curr_main_set, curr_bias; + int curr_main_set; int main_rssi = rs->rs_rssi_ctl0; int alt_rssi = rs->rs_rssi_ctl1; int rx_ant_conf, main_ant_conf; @@ -1393,7 +1393,6 @@ static void ath_ant_comb_scan(struct ath_softc *sc, struct ath_rx_status *rs) ath9k_hw_antdiv_comb_conf_get(sc->sc_ah, &div_ant_conf); curr_alt_set = div_ant_conf.alt_lna_conf; curr_main_set = div_ant_conf.main_lna_conf; - curr_bias = div_ant_conf.fast_div_bias; antcomb->count++; -- cgit v0.10.2 From 3a0593efd191c7eb13c79179c4c5ddbc519b2510 Mon Sep 17 00:00:00 2001 From: Sujith Manoharan Date: Wed, 20 Apr 2011 14:33:28 +0530 Subject: ath9k_htc: Fix AMPDU subframe handling * Register the driver's maximum ampdu subframe limit to mac80211. * Cleanup the target capabilities structure and fix an endian issue. * Fix BTCOEX by sending a command to the target when the BT priority changes. * Bump the required firmware version to 1.1 Signed-off-by: Sujith Manoharan Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/hif_usb.h b/drivers/net/wireless/ath/ath9k/hif_usb.h index f59df48..9a52ccc 100644 --- a/drivers/net/wireless/ath/ath9k/hif_usb.h +++ b/drivers/net/wireless/ath/ath9k/hif_usb.h @@ -17,6 +17,9 @@ #ifndef HTC_USB_H #define HTC_USB_H +#define MAJOR_VERSION_REQ 1 +#define MINOR_VERSION_REQ 1 + #define IS_AR7010_DEVICE(_v) (((_v) == AR9280_USB) || ((_v) == AR9287_USB)) #define AR9271_FIRMWARE 0x501000 diff --git a/drivers/net/wireless/ath/ath9k/htc.h b/drivers/net/wireless/ath/ath9k/htc.h index 48a8855..af90829 100644 --- a/drivers/net/wireless/ath/ath9k/htc.h +++ b/drivers/net/wireless/ath/ath9k/htc.h @@ -106,15 +106,14 @@ struct tx_beacon_header { u16 rev; } __packed; +#define MAX_TX_AMPDU_SUBFRAMES_9271 17 +#define MAX_TX_AMPDU_SUBFRAMES_7010 22 + struct ath9k_htc_cap_target { - u32 flags; - u32 flags_ext; - u32 ampdu_limit; + __be32 ampdu_limit; u8 ampdu_subframes; + u8 enable_coex; u8 tx_chainmask; - u8 tx_chainmask_legacy; - u8 rtscts_ratecode; - u8 protmode; u8 pad; } __packed; @@ -551,7 +550,8 @@ void ath9k_htc_txep(void *priv, struct sk_buff *skb, enum htc_endpoint_id ep_id, void ath9k_htc_beaconep(void *drv_priv, struct sk_buff *skb, enum htc_endpoint_id ep_id, bool txok); -int ath9k_htc_update_cap_target(struct ath9k_htc_priv *priv); +int ath9k_htc_update_cap_target(struct ath9k_htc_priv *priv, + u8 enable_coex); void ath9k_htc_station_work(struct work_struct *work); void ath9k_htc_aggr_work(struct work_struct *work); void ath9k_htc_ani_work(struct work_struct *work); diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_gpio.c b/drivers/net/wireless/ath/ath9k/htc_drv_gpio.c index 138f8e1..d051a42 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_gpio.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_gpio.c @@ -65,15 +65,13 @@ static void ath_btcoex_period_work(struct work_struct *work) u32 timer_period; bool is_btscan; int ret; - u8 cmd_rsp, aggr; ath_detect_bt_priority(priv); is_btscan = !!(priv->op_flags & OP_BT_SCAN); - aggr = priv->op_flags & OP_BT_PRIORITY_DETECTED; - - WMI_CMD_BUF(WMI_AGGR_LIMIT_CMD, &aggr); + ret = ath9k_htc_update_cap_target(priv, + !!(priv->op_flags & OP_BT_PRIORITY_DETECTED)); if (ret) { ath_err(common, "Unable to set BTCOEX parameters\n"); return; diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_init.c b/drivers/net/wireless/ath/ath9k/htc_drv_init.c index 06e043b..dbf5f95 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_init.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_init.c @@ -753,6 +753,12 @@ static void ath9k_set_hw_capab(struct ath9k_htc_priv *priv, hw->queues = 4; hw->channel_change_time = 5000; hw->max_listen_interval = 10; + + if (AR_SREV_9271(priv->ah)) + hw->max_tx_aggregation_subframes = MAX_TX_AMPDU_SUBFRAMES_9271; + else + hw->max_tx_aggregation_subframes = MAX_TX_AMPDU_SUBFRAMES_7010; + hw->vif_data_size = sizeof(struct ath9k_htc_vif); hw->sta_data_size = sizeof(struct ath9k_htc_sta); @@ -802,6 +808,17 @@ static int ath9k_init_firmware_version(struct ath9k_htc_priv *priv) priv->fw_version_major, priv->fw_version_minor); + /* + * Check if the available FW matches the driver's + * required version. + */ + if (priv->fw_version_major != MAJOR_VERSION_REQ || + priv->fw_version_minor != MINOR_VERSION_REQ) { + dev_err(priv->dev, "ath9k_htc: Please upgrade to FW version %d.%d\n", + MAJOR_VERSION_REQ, MINOR_VERSION_REQ); + return -EINVAL; + } + return 0; } diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_main.c b/drivers/net/wireless/ath/ath9k/htc_drv_main.c index 7cff554..a640268 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_main.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_main.c @@ -563,7 +563,8 @@ static int ath9k_htc_remove_station(struct ath9k_htc_priv *priv, return 0; } -int ath9k_htc_update_cap_target(struct ath9k_htc_priv *priv) +int ath9k_htc_update_cap_target(struct ath9k_htc_priv *priv, + u8 enable_coex) { struct ath9k_htc_cap_target tcap; int ret; @@ -571,13 +572,9 @@ int ath9k_htc_update_cap_target(struct ath9k_htc_priv *priv) memset(&tcap, 0, sizeof(struct ath9k_htc_cap_target)); - /* FIXME: Values are hardcoded */ - tcap.flags = 0x240c40; - tcap.flags_ext = 0x80601000; - tcap.ampdu_limit = 0xffff0000; - tcap.ampdu_subframes = 20; - tcap.tx_chainmask_legacy = priv->ah->caps.tx_chainmask; - tcap.protmode = 1; + tcap.ampdu_limit = cpu_to_be32(0xffff); + tcap.ampdu_subframes = priv->hw->max_tx_aggregation_subframes; + tcap.enable_coex = enable_coex; tcap.tx_chainmask = priv->ah->caps.tx_chainmask; WMI_CMD_BUF(WMI_TARGET_IC_UPDATE_CMDID, &tcap); @@ -936,7 +933,7 @@ static int ath9k_htc_start(struct ieee80211_hw *hw) ath9k_host_rx_init(priv); - ret = ath9k_htc_update_cap_target(priv); + ret = ath9k_htc_update_cap_target(priv, 0); if (ret) ath_dbg(common, ATH_DBG_CONFIG, "Failed to update capability in target\n"); -- cgit v0.10.2 From f0dd49803b0c0f3a002f073ec1a82cac5795af2d Mon Sep 17 00:00:00 2001 From: Sujith Manoharan Date: Wed, 20 Apr 2011 11:01:00 +0530 Subject: ath9k_htc: Fix max A-MPDU size handling Set the maximum ampdu size of a station correctly in the target by using the ampdu_factor. Signed-off-by: Sujith Manoharan Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_main.c b/drivers/net/wireless/ath/ath9k/htc_drv_main.c index a640268..fbc238a 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_main.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_main.c @@ -467,6 +467,7 @@ static int ath9k_htc_add_station(struct ath9k_htc_priv *priv, struct ath9k_htc_sta *ista; int ret, sta_idx; u8 cmd_rsp; + u16 maxampdu; if (priv->nstations >= ATH9K_HTC_MAX_STA) return -ENOBUFS; @@ -490,7 +491,15 @@ static int ath9k_htc_add_station(struct ath9k_htc_priv *priv, tsta.sta_index = sta_idx; tsta.vif_index = avp->index; - tsta.maxampdu = cpu_to_be16(0xffff); + + if (!sta) { + tsta.maxampdu = cpu_to_be16(0xffff); + } else { + maxampdu = 1 << (IEEE80211_HT_MAX_AMPDU_FACTOR + + sta->ht_cap.ampdu_factor); + tsta.maxampdu = cpu_to_be16(maxampdu); + } + if (sta && sta->ht_cap.ht_supported) tsta.flags = cpu_to_be16(ATH_HTC_STA_HT); -- cgit v0.10.2 From c58ca5b5083befda31009a64abd95ae6ac315265 Mon Sep 17 00:00:00 2001 From: Sujith Manoharan Date: Wed, 20 Apr 2011 11:01:10 +0530 Subject: ath9k_htc: Use power save wrappers when accessing HW Signed-off-by: Sujith Manoharan Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_debug.c b/drivers/net/wireless/ath/ath9k/htc_drv_debug.c index eca7774..894e5ef 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_debug.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_debug.c @@ -33,9 +33,15 @@ static ssize_t read_file_tgt_int_stats(struct file *file, char __user *user_buf, memset(&cmd_rsp, 0, sizeof(cmd_rsp)); + ath9k_htc_ps_wakeup(priv); + WMI_CMD(WMI_INT_STATS_CMDID); - if (ret) + if (ret) { + ath9k_htc_ps_restore(priv); return -EINVAL; + } + + ath9k_htc_ps_restore(priv); len += snprintf(buf + len, sizeof(buf) - len, "%20s : %10u\n", "RX", @@ -85,9 +91,15 @@ static ssize_t read_file_tgt_tx_stats(struct file *file, char __user *user_buf, memset(&cmd_rsp, 0, sizeof(cmd_rsp)); + ath9k_htc_ps_wakeup(priv); + WMI_CMD(WMI_TX_STATS_CMDID); - if (ret) + if (ret) { + ath9k_htc_ps_restore(priv); return -EINVAL; + } + + ath9k_htc_ps_restore(priv); len += snprintf(buf + len, sizeof(buf) - len, "%20s : %10u\n", "Xretries", @@ -149,9 +161,15 @@ static ssize_t read_file_tgt_rx_stats(struct file *file, char __user *user_buf, memset(&cmd_rsp, 0, sizeof(cmd_rsp)); + ath9k_htc_ps_wakeup(priv); + WMI_CMD(WMI_RX_STATS_CMDID); - if (ret) + if (ret) { + ath9k_htc_ps_restore(priv); return -EINVAL; + } + + ath9k_htc_ps_restore(priv); len += snprintf(buf + len, sizeof(buf) - len, "%20s : %10u\n", "NoBuf", diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_main.c b/drivers/net/wireless/ath/ath9k/htc_drv_main.c index fbc238a..c8577d5 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_main.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_main.c @@ -1582,6 +1582,7 @@ static int ath9k_htc_ampdu_action(struct ieee80211_hw *hw, int ret = 0; mutex_lock(&priv->mutex); + ath9k_htc_ps_wakeup(priv); switch (action) { case IEEE80211_AMPDU_RX_START: @@ -1607,6 +1608,7 @@ static int ath9k_htc_ampdu_action(struct ieee80211_hw *hw, ath_err(ath9k_hw_common(priv->ah), "Unknown AMPDU action\n"); } + ath9k_htc_ps_restore(priv); mutex_unlock(&priv->mutex); return ret; -- cgit v0.10.2 From 767ad6a0a2342d42f6f03b50198418b1475e0a7b Mon Sep 17 00:00:00 2001 From: Sujith Manoharan Date: Wed, 20 Apr 2011 11:01:25 +0530 Subject: ath9k_htc: Remove unused macros and structures Signed-off-by: Sujith Manoharan Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/htc.h b/drivers/net/wireless/ath/ath9k/htc.h index af90829..55f4bb3 100644 --- a/drivers/net/wireless/ath/ath9k/htc.h +++ b/drivers/net/wireless/ath/ath9k/htc.h @@ -66,8 +66,6 @@ enum htc_opmode { HTC_M_WDS = 2 }; -#define ATH9K_HTC_HDRSPACE sizeof(struct htc_frame_hdr) - #define ATH9K_HTC_AMPDU 1 #define ATH9K_HTC_NORMAL 2 #define ATH9K_HTC_BEACON 3 @@ -75,7 +73,6 @@ enum htc_opmode { #define ATH9K_HTC_TX_CTSONLY 0x1 #define ATH9K_HTC_TX_RTSCTS 0x2 -#define ATH9K_HTC_TX_USE_MIN_RATE 0x100 struct tx_frame_hdr { u8 data_type; diff --git a/drivers/net/wireless/ath/ath9k/htc_hst.h b/drivers/net/wireless/ath/ath9k/htc_hst.h index cb9174a..91a5305 100644 --- a/drivers/net/wireless/ath/ath9k/htc_hst.h +++ b/drivers/net/wireless/ath/ath9k/htc_hst.h @@ -83,21 +83,10 @@ struct htc_ep_callbacks { void (*rx) (void *, struct sk_buff *, enum htc_endpoint_id); }; -#define HTC_TX_QUEUE_SIZE 256 - -struct htc_txq { - struct sk_buff *buf[HTC_TX_QUEUE_SIZE]; - u32 txqdepth; - u16 txbuf_cnt; - u16 txq_head; - u16 txq_tail; -}; - struct htc_endpoint { u16 service_id; struct htc_ep_callbacks ep_callbacks; - struct htc_txq htc_txq; u32 max_txqdepth; int max_msglen; -- cgit v0.10.2 From 9f2e731d1d278d853def1567735d8a823668a3c8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= Date: Wed, 20 Apr 2011 11:12:30 +0200 Subject: ssb: cc: add & fix defines MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We probably got false positive results for checking PLL being down. Signed-off-by: RafaÅ‚ MiÅ‚ecki Signed-off-by: John W. Linville diff --git a/include/linux/ssb/ssb_driver_chipcommon.h b/include/linux/ssb/ssb_driver_chipcommon.h index 2cdf249..4f2d77a 100644 --- a/include/linux/ssb/ssb_driver_chipcommon.h +++ b/include/linux/ssb/ssb_driver_chipcommon.h @@ -131,6 +131,9 @@ #define SSB_CHIPCO_GPIOIRQ 0x0074 #define SSB_CHIPCO_WATCHDOG 0x0080 #define SSB_CHIPCO_GPIOTIMER 0x0088 /* LED powersave (corerev >= 16) */ +#define SSB_CHIPCO_GPIOTIMER_OFFTIME 0x0000FFFF +#define SSB_CHIPCO_GPIOTIMER_OFFTIME_SHIFT 0 +#define SSB_CHIPCO_GPIOTIMER_ONTIME 0xFFFF0000 #define SSB_CHIPCO_GPIOTIMER_ONTIME_SHIFT 16 #define SSB_CHIPCO_GPIOTOUTM 0x008C /* LED powersave (corerev >= 16) */ #define SSB_CHIPCO_CLOCK_N 0x0090 @@ -189,8 +192,10 @@ #define SSB_CHIPCO_CLKCTLST_HAVEALPREQ 0x00000008 /* ALP available request */ #define SSB_CHIPCO_CLKCTLST_HAVEHTREQ 0x00000010 /* HT available request */ #define SSB_CHIPCO_CLKCTLST_HWCROFF 0x00000020 /* Force HW clock request off */ -#define SSB_CHIPCO_CLKCTLST_HAVEHT 0x00010000 /* HT available */ -#define SSB_CHIPCO_CLKCTLST_HAVEALP 0x00020000 /* APL available */ +#define SSB_CHIPCO_CLKCTLST_HAVEALP 0x00010000 /* ALP available */ +#define SSB_CHIPCO_CLKCTLST_HAVEHT 0x00020000 /* HT available */ +#define SSB_CHIPCO_CLKCTLST_4328A0_HAVEHT 0x00010000 /* 4328a0 has reversed bits */ +#define SSB_CHIPCO_CLKCTLST_4328A0_HAVEALP 0x00020000 /* 4328a0 has reversed bits */ #define SSB_CHIPCO_HW_WORKAROUND 0x01E4 /* Hardware workaround (rev >= 20) */ #define SSB_CHIPCO_UART0_DATA 0x0300 #define SSB_CHIPCO_UART0_IMR 0x0304 -- cgit v0.10.2 From 2624e96ce16bacae0e422d5775eac6d4fc33239a Mon Sep 17 00:00:00 2001 From: Stanislaw Gruszka Date: Wed, 20 Apr 2011 16:02:58 +0200 Subject: iwlwifi: fix possible data overwrite in hcmd callback My commit 3598e1774c94e55c71b585340e7dc4538f310e3f "iwlwifi: fix enqueue hcmd race conditions" move hcmd callback after command queue reclaim, to avoid call it with hcmd_lock. But since queue read index was updated, cmd data can be overwritten. Fix problem by calling callback before taking hcmd_lock and queue reclaim. Signed-off-by: Stanislaw Gruszka Acked-by: Wey-Yi Guy Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwlwifi/iwl-tx.c b/drivers/net/wireless/iwlwifi/iwl-tx.c index 80c3565..52b1b66 100644 --- a/drivers/net/wireless/iwlwifi/iwl-tx.c +++ b/drivers/net/wireless/iwlwifi/iwl-tx.c @@ -621,9 +621,6 @@ void iwl_tx_cmd_complete(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb) struct iwl_cmd_meta *meta; struct iwl_tx_queue *txq = &priv->txq[priv->cmd_queue]; unsigned long flags; - void (*callback) (struct iwl_priv *priv, struct iwl_device_cmd *cmd, - struct iwl_rx_packet *pkt); - /* If a Tx command is being handled and it isn't in the actual * command queue then there a command routing bug has been introduced @@ -637,8 +634,6 @@ void iwl_tx_cmd_complete(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb) return; } - spin_lock_irqsave(&priv->hcmd_lock, flags); - cmd_index = get_cmd_index(&txq->q, index, huge); cmd = txq->cmd[cmd_index]; meta = &txq->meta[cmd_index]; @@ -648,13 +643,14 @@ void iwl_tx_cmd_complete(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb) dma_unmap_len(meta, len), PCI_DMA_BIDIRECTIONAL); - callback = NULL; /* Input error checking is done when commands are added to queue. */ if (meta->flags & CMD_WANT_SKB) { meta->source->reply_page = (unsigned long)rxb_addr(rxb); rxb->page = NULL; - } else - callback = meta->callback; + } else if (meta->callback) + meta->callback(priv, cmd, pkt); + + spin_lock_irqsave(&priv->hcmd_lock, flags); iwl_hcmd_queue_reclaim(priv, txq_id, index, cmd_index); @@ -669,7 +665,4 @@ void iwl_tx_cmd_complete(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb) meta->flags = 0; spin_unlock_irqrestore(&priv->hcmd_lock, flags); - - if (callback) - callback(priv, cmd, pkt); } -- cgit v0.10.2 From 3a7dbc3b2ac545efac75d4145839eaa7b59d9741 Mon Sep 17 00:00:00 2001 From: Pradeep Nemavat Date: Thu, 21 Apr 2011 16:34:56 +0530 Subject: mwl8k: Do not stop tx queues This is in preparation to support life time expiry of packets in the hardware to avoid head-of-line blocking where a slow client can hog a tx queue and affect the traffic to a faster client from the same queue. Time stamp the packets in driver to allow dropping them in the hardware if they are queued for more than 500ms. If queues are stopped, packets will be queued up outside the driver. Since we will be able to timestamp the packets only after they hit the driver, the timestamp will be less accurate since we cannot consider the time the packets spent in queues outside the driver. With this commit, to achieve accurate timestamping, the tx queues will not be stopped in normal conditions. The only scenarios where the queues will be stopped are when firmware commands are executing or if the interface is brought down. Now, we need to be prepared for a situation where packets hit the driver even after the tx queues are full. Drop all such packets in the driver itself. Signed-off-by: Pradeep Nemavat Signed-off-by: Nishant Sarmukadam Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c index 28ebaec..33da25a 100644 --- a/drivers/net/wireless/mwl8k.c +++ b/drivers/net/wireless/mwl8k.c @@ -1666,10 +1666,6 @@ mwl8k_txq_reclaim(struct ieee80211_hw *hw, int index, int limit, int force) processed++; } - if (index < MWL8K_TX_WMM_QUEUES && processed && priv->radio_on && - !mutex_is_locked(&priv->fw_mutex)) - ieee80211_wake_queue(hw, index); - return processed; } @@ -1951,13 +1947,14 @@ mwl8k_txq_xmit(struct ieee80211_hw *hw, int index, struct sk_buff *skb) txq = priv->txq + index; - if (index >= MWL8K_TX_WMM_QUEUES && txq->len >= MWL8K_TX_DESCS) { - /* This is the case in which the tx packet is destined for an - * AMPDU queue and that AMPDU queue is full. Because we don't - * start and stop the AMPDU queues, we must drop these packets. - */ - dev_kfree_skb(skb); + if (txq->len >= MWL8K_TX_DESCS) { + if (start_ba_session) { + spin_lock(&priv->stream_lock); + mwl8k_remove_stream(hw, stream); + spin_unlock(&priv->stream_lock); + } spin_unlock_bh(&priv->tx_lock); + dev_kfree_skb(skb); return; } @@ -1985,9 +1982,6 @@ mwl8k_txq_xmit(struct ieee80211_hw *hw, int index, struct sk_buff *skb) if (txq->tail == MWL8K_TX_DESCS) txq->tail = 0; - if (txq->head == txq->tail && index < MWL8K_TX_WMM_QUEUES) - ieee80211_stop_queue(hw, index); - mwl8k_tx_start(priv); spin_unlock_bh(&priv->tx_lock); -- cgit v0.10.2 From 566875db5058f582ea56da891f9c3cabc01efff5 Mon Sep 17 00:00:00 2001 From: Pradeep Nemavat Date: Thu, 21 Apr 2011 16:34:57 +0530 Subject: mwl8k: Add timestamp information for tx packets Timestamp tx packets using a HW micro-second timer. This timestamp will be compared to the current timestamp in the hardware and if the difference is greater than 500ms, the packet will be dropped. Signed-off-by: Pradeep Nemavat Signed-off-by: Nishant Sarmukadam Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c index 33da25a..93fe1bd 100644 --- a/drivers/net/wireless/mwl8k.c +++ b/drivers/net/wireless/mwl8k.c @@ -74,6 +74,14 @@ MODULE_PARM_DESC(ap_mode_default, #define MWL8K_A2H_INT_RX_READY (1 << 1) #define MWL8K_A2H_INT_TX_DONE (1 << 0) +/* HW micro second timer register + * located at offset 0xA600. This + * will be used to timestamp tx + * packets. + */ + +#define MWL8K_HW_TIMER_REGISTER 0x0000a600 + #define MWL8K_A2H_EVENTS (MWL8K_A2H_INT_DUMMY | \ MWL8K_A2H_INT_CHNL_SWITCHED | \ MWL8K_A2H_INT_QUEUE_EMPTY | \ @@ -1972,6 +1980,11 @@ mwl8k_txq_xmit(struct ieee80211_hw *hw, int index, struct sk_buff *skb) tx->peer_id = MWL8K_STA(tx_info->control.sta)->peer_id; else tx->peer_id = 0; + + if (priv->ap_fw) + tx->timestamp = cpu_to_le32(ioread32(priv->regs + + MWL8K_HW_TIMER_REGISTER)); + wmb(); tx->status = cpu_to_le32(MWL8K_TXD_STATUS_FW_OWNED | txstatus); -- cgit v0.10.2 From 3a769888797b7117005e9c60d4cd73a2efc92f8d Mon Sep 17 00:00:00 2001 From: Nishant Sarmukadam Date: Thu, 21 Apr 2011 16:34:58 +0530 Subject: mwl8k: Reserve buffers for tx management frames Since queues are not stopped anymore, management frames would be dropped if the corresponding tx queue is full. This can cause issues say when we want to setup an ampdu stream and action frames i.e addba requests keep getting dropped frequently. Fix this by reserving some buffers to allow management frames to go through in queue full conditions. Signed-off-by: Nishant Sarmukadam Signed-off-by: Pradeep Nemavat Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c index 93fe1bd..63ee8cf 100644 --- a/drivers/net/wireless/mwl8k.c +++ b/drivers/net/wireless/mwl8k.c @@ -1818,6 +1818,7 @@ mwl8k_txq_xmit(struct ieee80211_hw *hw, int index, struct sk_buff *skb) u8 tid = 0; struct mwl8k_ampdu_stream *stream = NULL; bool start_ba_session = false; + bool mgmtframe = false; struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)skb->data; wh = (struct ieee80211_hdr *)skb->data; @@ -1826,6 +1827,9 @@ mwl8k_txq_xmit(struct ieee80211_hw *hw, int index, struct sk_buff *skb) else qos = 0; + if (ieee80211_is_mgmt(wh->frame_control)) + mgmtframe = true; + if (priv->ap_fw) mwl8k_encapsulate_tx_frame(skb); else @@ -1955,15 +1959,26 @@ mwl8k_txq_xmit(struct ieee80211_hw *hw, int index, struct sk_buff *skb) txq = priv->txq + index; - if (txq->len >= MWL8K_TX_DESCS) { - if (start_ba_session) { - spin_lock(&priv->stream_lock); - mwl8k_remove_stream(hw, stream); - spin_unlock(&priv->stream_lock); + /* Mgmt frames that go out frequently are probe + * responses. Other mgmt frames got out relatively + * infrequently. Hence reserve 2 buffers so that + * other mgmt frames do not get dropped due to an + * already queued probe response in one of the + * reserved buffers. + */ + + if (txq->len >= MWL8K_TX_DESCS - 2) { + if (mgmtframe == false || + txq->len == MWL8K_TX_DESCS) { + if (start_ba_session) { + spin_lock(&priv->stream_lock); + mwl8k_remove_stream(hw, stream); + spin_unlock(&priv->stream_lock); + } + spin_unlock_bh(&priv->tx_lock); + dev_kfree_skb(skb); + return; } - spin_unlock_bh(&priv->tx_lock); - dev_kfree_skb(skb); - return; } BUG_ON(txq->skb[txq->tail] != NULL); -- cgit v0.10.2 From 31d291a769b4318cbf7943ca149e04d201e2c931 Mon Sep 17 00:00:00 2001 From: Nishant Sarmukadam Date: Thu, 21 Apr 2011 16:34:59 +0530 Subject: mwl8k: Enable life time expiry for tx packets in the hardware Tell the firmware to enable the life time expiry of tx packets in the hardware. The hardware will now refer to the timestamp in every tx packet and decide whether the packet needs to be dropped or transmitted. Signed-off-by: Nishant Sarmukadam Signed-off-by: Pradeep Nemavat Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c index 63ee8cf..b8f2b12 100644 --- a/drivers/net/wireless/mwl8k.c +++ b/drivers/net/wireless/mwl8k.c @@ -2504,7 +2504,8 @@ static int mwl8k_cmd_set_hw_spec(struct ieee80211_hw *hw) cmd->flags = cpu_to_le32(MWL8K_SET_HW_SPEC_FLAG_HOST_DECR_MGMT | MWL8K_SET_HW_SPEC_FLAG_HOSTFORM_PROBERESP | - MWL8K_SET_HW_SPEC_FLAG_HOSTFORM_BEACON); + MWL8K_SET_HW_SPEC_FLAG_HOSTFORM_BEACON | + MWL8K_SET_HW_SPEC_FLAG_ENABLE_LIFE_TIME_EXPIRY); cmd->num_tx_desc_per_queue = cpu_to_le32(MWL8K_TX_DESCS); cmd->total_rxd = cpu_to_le32(MWL8K_RX_DESCS); -- cgit v0.10.2 From ca45de77ad706e86b135b8564e21aa2c8a63f09b Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 21 Apr 2011 13:38:00 +0200 Subject: mac80211: tear down BA sessions properly on suspend Currently, the code to tear down BA sessions will execute after queues are stopped, but attempt to send frames, so those frames will just get queued, which isn't intended. Move this code to before to tear down the sessions properly. Additionally, after stopping queues, flush the TX queues in the driver driver to make sure all the frames went out. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville diff --git a/net/mac80211/pm.c b/net/mac80211/pm.c index e373551..0424617 100644 --- a/net/mac80211/pm.c +++ b/net/mac80211/pm.c @@ -14,12 +14,23 @@ int __ieee80211_suspend(struct ieee80211_hw *hw) ieee80211_scan_cancel(local); + if (hw->flags & IEEE80211_HW_AMPDU_AGGREGATION) { + mutex_lock(&local->sta_mtx); + list_for_each_entry(sta, &local->sta_list, list) { + set_sta_flags(sta, WLAN_STA_BLOCK_BA); + ieee80211_sta_tear_down_BA_sessions(sta, true); + } + mutex_unlock(&local->sta_mtx); + } + ieee80211_stop_queues_by_reason(hw, IEEE80211_QUEUE_STOP_REASON_SUSPEND); /* flush out all packets */ synchronize_net(); + drv_flush(local, false); + local->quiescing = true; /* make quiescing visible to timers everywhere */ mb(); @@ -43,11 +54,6 @@ int __ieee80211_suspend(struct ieee80211_hw *hw) /* tear down aggregation sessions and remove STAs */ mutex_lock(&local->sta_mtx); list_for_each_entry(sta, &local->sta_list, list) { - if (hw->flags & IEEE80211_HW_AMPDU_AGGREGATION) { - set_sta_flags(sta, WLAN_STA_BLOCK_BA); - ieee80211_sta_tear_down_BA_sessions(sta, true); - } - if (sta->uploaded) { sdata = sta->sdata; if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN) -- cgit v0.10.2 From 788f6875fcf5d2bce221fbfd2318ac48df299031 Mon Sep 17 00:00:00 2001 From: Vasanthakumar Thiagarajan Date: Thu, 21 Apr 2011 18:33:27 +0530 Subject: ath9k: Fix bug in configuring hw timer Hw next tigger time is configured as current_tsf + (timer_period * 10) which is wrong, it should be current_tsf + timer_period. The wrong hw timer configuration would cause btcoex related issues. Signed-off-by: Vasanthakumar Thiagarajan Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/gpio.c b/drivers/net/wireless/ath/ath9k/gpio.c index 44a0a88..cc5fad6 100644 --- a/drivers/net/wireless/ath/ath9k/gpio.c +++ b/drivers/net/wireless/ath/ath9k/gpio.c @@ -138,10 +138,10 @@ static void ath_detect_bt_priority(struct ath_softc *sc) static void ath9k_gen_timer_start(struct ath_hw *ah, struct ath_gen_timer *timer, - u32 timer_next, + u32 trig_timeout, u32 timer_period) { - ath9k_hw_gen_timer_start(ah, timer, timer_next, timer_period); + ath9k_hw_gen_timer_start(ah, timer, trig_timeout, timer_period); if ((ah->imask & ATH9K_INT_GENTIMER) == 0) { ath9k_hw_disable_interrupts(ah); @@ -195,7 +195,7 @@ static void ath_btcoex_period_timer(unsigned long data) timer_period = is_btscan ? btcoex->btscan_no_stomp : btcoex->btcoex_no_stomp; - ath9k_gen_timer_start(ah, btcoex->no_stomp_timer, 0, + ath9k_gen_timer_start(ah, btcoex->no_stomp_timer, timer_period, timer_period * 10); btcoex->hw_timer_enabled = true; } diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index 0fcfa59..577ca59 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c @@ -2430,11 +2430,11 @@ EXPORT_SYMBOL(ath_gen_timer_alloc); void ath9k_hw_gen_timer_start(struct ath_hw *ah, struct ath_gen_timer *timer, - u32 timer_next, + u32 trig_timeout, u32 timer_period) { struct ath_gen_timer_table *timer_table = &ah->hw_gen_timers; - u32 tsf; + u32 tsf, timer_next; BUG_ON(!timer_period); @@ -2442,18 +2442,13 @@ void ath9k_hw_gen_timer_start(struct ath_hw *ah, tsf = ath9k_hw_gettsf32(ah); + timer_next = tsf + trig_timeout; + ath_dbg(ath9k_hw_common(ah), ATH_DBG_HWTIMER, "current tsf %x period %x timer_next %x\n", tsf, timer_period, timer_next); /* - * Pull timer_next forward if the current TSF already passed it - * because of software latency - */ - if (timer_next < tsf) - timer_next = tsf + timer_period; - - /* * Program generic timer registers */ REG_WRITE(ah, gen_tmr_configuration[timer->index].next_addr, -- cgit v0.10.2 From 0a6c9b1b666671a22905d38bc41ec1a04b85832f Mon Sep 17 00:00:00 2001 From: Vasanthakumar Thiagarajan Date: Thu, 21 Apr 2011 18:33:28 +0530 Subject: ath9k: Fix warning: symbol 'ath9k_platform_id_table' was not declared. Should it be static? Signed-off-by: Vasanthakumar Thiagarajan Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/ahb.c b/drivers/net/wireless/ath/ath9k/ahb.c index 090f314..6195639 100644 --- a/drivers/net/wireless/ath/ath9k/ahb.c +++ b/drivers/net/wireless/ath/ath9k/ahb.c @@ -21,7 +21,7 @@ #include #include "ath9k.h" -const struct platform_device_id ath9k_platform_id_table[] = { +static const struct platform_device_id ath9k_platform_id_table[] = { { .name = "ath9k", .driver_data = AR5416_AR9100_DEVID, -- cgit v0.10.2 From 40db6c77ab48c3f3240422ff92fd6da222e2eb95 Mon Sep 17 00:00:00 2001 From: Amitkumar Karwar Date: Thu, 21 Apr 2011 14:10:27 -0700 Subject: cfg80211: module_param to disable HT40 in 2.4GHz band Currently mac80211 uses ieee80211_disable_40mhz_24ghz module parameter to allow disabling 40MHz operation in the 2.4GHz band. Move this handling from mac80211 to cfg80211 so that the feature will be more generic. Signed-off-by: Amitkumar Karwar Signed-off-by: Bing Zhao Reviewed-by: Johannes Berg Signed-off-by: John W. Linville diff --git a/net/mac80211/main.c b/net/mac80211/main.c index 0ab2a8d..6187766 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c @@ -33,12 +33,6 @@ #include "cfg.h" #include "debugfs.h" - -static bool ieee80211_disable_40mhz_24ghz; -module_param(ieee80211_disable_40mhz_24ghz, bool, 0644); -MODULE_PARM_DESC(ieee80211_disable_40mhz_24ghz, - "Disable 40MHz support in the 2.4GHz band"); - static struct lock_class_key ieee80211_rx_skb_queue_class; void ieee80211_configure_filter(struct ieee80211_local *local) @@ -728,18 +722,6 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) } channels += sband->n_channels; - /* - * Since ieee80211_disable_40mhz_24ghz is global, we can - * modify the sband's ht data even if the driver uses a - * global structure for that. - */ - if (ieee80211_disable_40mhz_24ghz && - band == IEEE80211_BAND_2GHZ && - sband->ht_cap.ht_supported) { - sband->ht_cap.cap &= ~IEEE80211_HT_CAP_SUP_WIDTH_20_40; - sband->ht_cap.cap &= ~IEEE80211_HT_CAP_SGI_40; - } - if (max_bitrates < sband->n_bitrates) max_bitrates = sband->n_bitrates; supp_ht = supp_ht || sband->ht_cap.ht_supported; diff --git a/net/wireless/core.c b/net/wireless/core.c index fe01de2..bbf1fa1 100644 --- a/net/wireless/core.c +++ b/net/wireless/core.c @@ -46,6 +46,11 @@ static struct dentry *ieee80211_debugfs_dir; /* for the cleanup, scan and event works */ struct workqueue_struct *cfg80211_wq; +static bool cfg80211_disable_40mhz_24ghz; +module_param(cfg80211_disable_40mhz_24ghz, bool, 0644); +MODULE_PARM_DESC(cfg80211_disable_40mhz_24ghz, + "Disable 40MHz support in the 2.4GHz band"); + /* requires cfg80211_mutex to be held! */ struct cfg80211_registered_device *cfg80211_rdev_by_wiphy_idx(int wiphy_idx) { @@ -451,6 +456,18 @@ int wiphy_register(struct wiphy *wiphy) return -EINVAL; /* + * Since cfg80211_disable_40mhz_24ghz is global, we can + * modify the sband's ht data even if the driver uses a + * global structure for that. + */ + if (cfg80211_disable_40mhz_24ghz && + band == IEEE80211_BAND_2GHZ && + sband->ht_cap.ht_supported) { + sband->ht_cap.cap &= ~IEEE80211_HT_CAP_SUP_WIDTH_20_40; + sband->ht_cap.cap &= ~IEEE80211_HT_CAP_SGI_40; + } + + /* * Since we use a u32 for rate bitmaps in * ieee80211_get_response_rate, we cannot * have more than 32 legacy rates. -- cgit v0.10.2 From 353e5019e048562dc8f434c6237d41ef5e758922 Mon Sep 17 00:00:00 2001 From: Senthil Balasubramanian Date: Fri, 22 Apr 2011 11:32:08 +0530 Subject: ath9k: Fix LED gpio for AR93xx chipsets. The LED gpio is incorrectly programmed for AR9300 and so the led is not working propelry. AR93xx uses gpio 10 for LED and not the default. Signed-off-by: Senthil Balasubramanian Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h index a6b5388..5ebfc57 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h @@ -453,6 +453,7 @@ void ath9k_btcoex_timer_pause(struct ath_softc *sc); #define ATH_LED_PIN_DEF 1 #define ATH_LED_PIN_9287 8 +#define ATH_LED_PIN_9300 10 #define ATH_LED_PIN_9485 6 #ifdef CONFIG_MAC80211_LEDS diff --git a/drivers/net/wireless/ath/ath9k/gpio.c b/drivers/net/wireless/ath/ath9k/gpio.c index cc5fad6..2c59452 100644 --- a/drivers/net/wireless/ath/ath9k/gpio.c +++ b/drivers/net/wireless/ath/ath9k/gpio.c @@ -46,6 +46,8 @@ void ath_init_leds(struct ath_softc *sc) sc->sc_ah->led_pin = ATH_LED_PIN_9287; else if (AR_SREV_9485(sc->sc_ah)) sc->sc_ah->led_pin = ATH_LED_PIN_9485; + else if (AR_SREV_9300(sc->sc_ah)) + sc->sc_ah->led_pin = ATH_LED_PIN_9300; else sc->sc_ah->led_pin = ATH_LED_PIN_DEF; } -- cgit v0.10.2 From d1c038d620c45fbbc65bcadf813a86bca686dd31 Mon Sep 17 00:00:00 2001 From: Senthil Balasubramanian Date: Fri, 22 Apr 2011 11:32:09 +0530 Subject: ath9k_hw: Fix incorrect baseband PLL phase shift for AR9485 we should program the AR9485 baseband PLL phase shift to 6 and a redundant setting overwrites the correct value. Remove the incorrect and unwnated register setting. Signed-off-by: Senthil Balasubramanian Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index 577ca59..6166ba0 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c @@ -686,7 +686,6 @@ unsigned long ar9003_get_pll_sqsum_dvc(struct ath_hw *ah) } EXPORT_SYMBOL(ar9003_get_pll_sqsum_dvc); -#define DPLL3_PHASE_SHIFT_VAL 0x1 static void ath9k_hw_init_pll(struct ath_hw *ah, struct ath9k_channel *chan) { @@ -723,9 +722,6 @@ static void ath9k_hw_init_pll(struct ath_hw *ah, REG_RMW_FIELD(ah, AR_CH0_BB_DPLL2, AR_CH0_BB_DPLL2_PLL_PWD, 0x0); udelay(1000); - - REG_RMW_FIELD(ah, AR_CH0_BB_DPLL3, - AR_CH0_DPLL3_PHASE_SHIFT, DPLL3_PHASE_SHIFT_VAL); } else if (AR_SREV_9340(ah)) { u32 regval, pll2_divint, pll2_divfrac, refdiv; -- cgit v0.10.2 From 515139066928da040d1482f201ef1b769bc29aa0 Mon Sep 17 00:00:00 2001 From: Senthil Balasubramanian Date: Fri, 22 Apr 2011 11:32:10 +0530 Subject: ath9k: optimize the usage of power save wrappers. We need not wake up the chip even before mutex lock is acquired and also that it is required only if we are going to drain the txq. So place the wrappers accordingly and this change is also useful when there are no pending frames in the txq as we do not wake up the chip unnecessarily. Signed-off-by: Senthil Balasubramanian Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index e7d6d98..dd2fffb 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -2211,9 +2211,7 @@ static void ath9k_flush(struct ieee80211_hw *hw, bool drop) int timeout = 200; /* ms */ int i, j; - ath9k_ps_wakeup(sc); mutex_lock(&sc->mutex); - cancel_delayed_work_sync(&sc->tx_complete_work); if (drop) @@ -2236,15 +2234,15 @@ static void ath9k_flush(struct ieee80211_hw *hw, bool drop) goto out; } + ath9k_ps_wakeup(sc); if (!ath_drain_all_txq(sc, false)) ath_reset(sc, false); - + ath9k_ps_restore(sc); ieee80211_wake_queues(hw); out: ieee80211_queue_delayed_work(hw, &sc->tx_complete_work, 0); mutex_unlock(&sc->mutex); - ath9k_ps_restore(sc); } static bool ath9k_tx_frames_pending(struct ieee80211_hw *hw) -- cgit v0.10.2 From 9eab61c2bff2f769ee771a7a9301fb720cec9b56 Mon Sep 17 00:00:00 2001 From: Senthil Balasubramanian Date: Fri, 22 Apr 2011 11:32:11 +0530 Subject: ath9k: cleanup hw pll work handler There is no reason why pll work handler should be part of xmit file. move it to main.c so that reading hw check routines are all in the same place. Signed-off-by: Senthil Balasubramanian Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h index 5ebfc57..0312aa0 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h @@ -423,6 +423,7 @@ void ath9k_set_beaconing_status(struct ath_softc *sc, bool status); #define ATH_PAPRD_TIMEOUT 100 /* msecs */ void ath_hw_check(struct work_struct *work); +void ath_hw_pll_work(struct work_struct *work); void ath_paprd_calibrate(struct work_struct *work); void ath_ani_calibrate(unsigned long data); diff --git a/drivers/net/wireless/ath/ath9k/init.c b/drivers/net/wireless/ath/ath9k/init.c index e78b6ae..b172d15 100644 --- a/drivers/net/wireless/ath/ath9k/init.c +++ b/drivers/net/wireless/ath/ath9k/init.c @@ -801,6 +801,7 @@ int ath9k_init_device(u16 devid, struct ath_softc *sc, u16 subsysid, INIT_WORK(&sc->hw_check_work, ath_hw_check); INIT_WORK(&sc->paprd_work, ath_paprd_calibrate); + INIT_DELAYED_WORK(&sc->hw_pll_work, ath_hw_pll_work); sc->last_rssi = ATH_RSSI_DUMMY_MARKER; ath_init_leds(sc); diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index dd2fffb..94d73c3 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -624,6 +624,29 @@ out: ath9k_ps_restore(sc); } +void ath_hw_pll_work(struct work_struct *work) +{ + struct ath_softc *sc = container_of(work, struct ath_softc, + hw_pll_work.work); + static int count; + + if (AR_SREV_9485(sc->sc_ah)) { + if (ar9003_get_pll_sqsum_dvc(sc->sc_ah) >= 0x40000) { + count++; + + if (count == 3) { + /* Rx is hung for more than 500ms. Reset it */ + ath_reset(sc, true); + count = 0; + } + } else + count = 0; + + ieee80211_queue_delayed_work(sc->hw, &sc->hw_pll_work, HZ/5); + } +} + + void ath9k_tasklet(unsigned long data) { struct ath_softc *sc = (struct ath_softc *)data; diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c index 65d46c6..55960fa 100644 --- a/drivers/net/wireless/ath/ath9k/xmit.c +++ b/drivers/net/wireless/ath/ath9k/xmit.c @@ -2180,28 +2180,6 @@ static void ath_tx_processq(struct ath_softc *sc, struct ath_txq *txq) } } -static void ath_hw_pll_work(struct work_struct *work) -{ - struct ath_softc *sc = container_of(work, struct ath_softc, - hw_pll_work.work); - static int count; - - if (AR_SREV_9485(sc->sc_ah)) { - if (ar9003_get_pll_sqsum_dvc(sc->sc_ah) >= 0x40000) { - count++; - - if (count == 3) { - /* Rx is hung for more than 500ms. Reset it */ - ath_reset(sc, true); - count = 0; - } - } else - count = 0; - - ieee80211_queue_delayed_work(sc->hw, &sc->hw_pll_work, HZ/5); - } -} - static void ath_tx_complete_poll_work(struct work_struct *work) { struct ath_softc *sc = container_of(work, struct ath_softc, @@ -2396,7 +2374,6 @@ int ath_tx_init(struct ath_softc *sc, int nbufs) } INIT_DELAYED_WORK(&sc->tx_complete_work, ath_tx_complete_poll_work); - INIT_DELAYED_WORK(&sc->hw_pll_work, ath_hw_pll_work); if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) { error = ath_tx_edma_init(sc); -- cgit v0.10.2 From b84628eb574f04db714d34276383edbe6d8bfd96 Mon Sep 17 00:00:00 2001 From: Senthil Balasubramanian Date: Fri, 22 Apr 2011 11:32:12 +0530 Subject: ath9k: Add power save wrappers and modularize hw_pll handler We should protect hw_pll handler with power save wrappers and also modularize hw_pll handler properly for better readability. Also add a debug message to track chip resets on pll hang condition. Signed-off-by: Senthil Balasubramanian Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index 6166ba0..2b4e7c0 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c @@ -673,7 +673,7 @@ static void ath9k_hw_init_qos(struct ath_hw *ah) REGWRITE_BUFFER_FLUSH(ah); } -unsigned long ar9003_get_pll_sqsum_dvc(struct ath_hw *ah) +u32 ar9003_get_pll_sqsum_dvc(struct ath_hw *ah) { REG_CLR_BIT(ah, PLL3, PLL3_DO_MEAS_MASK); udelay(100); diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h index 29a745c..6a028bd 100644 --- a/drivers/net/wireless/ath/ath9k/hw.h +++ b/drivers/net/wireless/ath/ath9k/hw.h @@ -932,7 +932,7 @@ void ath9k_hw_settsf64(struct ath_hw *ah, u64 tsf64); void ath9k_hw_reset_tsf(struct ath_hw *ah); void ath9k_hw_set_tsfadjust(struct ath_hw *ah, u32 setting); void ath9k_hw_init_global_settings(struct ath_hw *ah); -unsigned long ar9003_get_pll_sqsum_dvc(struct ath_hw *ah); +u32 ar9003_get_pll_sqsum_dvc(struct ath_hw *ah); void ath9k_hw_set11nmac2040(struct ath_hw *ah); void ath9k_hw_beaconinit(struct ath_hw *ah, u32 next_beacon, u32 beacon_period); void ath9k_hw_set_sta_beacon_timers(struct ath_hw *ah, diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index 94d73c3..20a2cf7 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -624,23 +624,37 @@ out: ath9k_ps_restore(sc); } +static void ath_hw_pll_rx_hang_check(struct ath_softc *sc, u32 pll_sqsum) +{ + static int count; + struct ath_common *common = ath9k_hw_common(sc->sc_ah); + + if (pll_sqsum >= 0x40000) { + count++; + if (count == 3) { + /* Rx is hung for more than 500ms. Reset it */ + ath_dbg(common, ATH_DBG_RESET, + "Possible RX hang, resetting"); + ath_reset(sc, true); + count = 0; + } + } else + count = 0; +} + void ath_hw_pll_work(struct work_struct *work) { struct ath_softc *sc = container_of(work, struct ath_softc, hw_pll_work.work); - static int count; + u32 pll_sqsum; if (AR_SREV_9485(sc->sc_ah)) { - if (ar9003_get_pll_sqsum_dvc(sc->sc_ah) >= 0x40000) { - count++; - if (count == 3) { - /* Rx is hung for more than 500ms. Reset it */ - ath_reset(sc, true); - count = 0; - } - } else - count = 0; + ath9k_ps_wakeup(sc); + pll_sqsum = ar9003_get_pll_sqsum_dvc(sc->sc_ah); + ath9k_ps_restore(sc); + + ath_hw_pll_rx_hang_check(sc, pll_sqsum); ieee80211_queue_delayed_work(sc->hw, &sc->hw_pll_work, HZ/5); } -- cgit v0.10.2 From cedc7e3d0c847d602d2970120d0e4cca72f364a4 Mon Sep 17 00:00:00 2001 From: Mohammed Shafi Shajakhan Date: Fri, 22 Apr 2011 13:12:23 +0530 Subject: ath9k: remove the unlikely check for autosleep newer chipsets support auto sleep feature, so remove the unlikely check which does not seems to help anything Signed-off-by: Mohammed Shafi Shajakhan Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/recv.c b/drivers/net/wireless/ath/ath9k/recv.c index abff2d5..916b340 100644 --- a/drivers/net/wireless/ath/ath9k/recv.c +++ b/drivers/net/wireless/ath/ath9k/recv.c @@ -1742,7 +1742,7 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush, bool hp) if ((sc->ps_flags & (PS_WAIT_FOR_BEACON | PS_WAIT_FOR_CAB | PS_WAIT_FOR_PSPOLL_DATA)) || - unlikely(ath9k_check_auto_sleep(sc))) + ath9k_check_auto_sleep(sc)) ath_rx_ps(sc, skb); spin_unlock_irqrestore(&sc->sc_pm_lock, flags); -- cgit v0.10.2 From 6dde1aabf6759848512f19d76b89ee473584c46a Mon Sep 17 00:00:00 2001 From: Mohammed Shafi Shajakhan Date: Fri, 22 Apr 2011 17:27:01 +0530 Subject: ath9k: Add TSFOOR interrupt stats in debug info This helped the developers to fix an issue of chip not entering network sleep during idle state, previously this was only available as a debug message Signed-off-by: Mohammed Shafi Shajakhan Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/debug.c b/drivers/net/wireless/ath/ath9k/debug.c index 34f191e..bad1a87 100644 --- a/drivers/net/wireless/ath/ath9k/debug.c +++ b/drivers/net/wireless/ath/ath9k/debug.c @@ -326,6 +326,8 @@ void ath_debug_stat_interrupt(struct ath_softc *sc, enum ath9k_int status) sc->debug.stats.istats.dtimsync++; if (status & ATH9K_INT_DTIM) sc->debug.stats.istats.dtim++; + if (status & ATH9K_INT_TSFOOR) + sc->debug.stats.istats.tsfoor++; } static ssize_t read_file_interrupt(struct file *file, char __user *user_buf, @@ -380,8 +382,11 @@ static ssize_t read_file_interrupt(struct file *file, char __user *user_buf, len += snprintf(buf + len, sizeof(buf) - len, "%8s: %10u\n", "DTIM", sc->debug.stats.istats.dtim); len += snprintf(buf + len, sizeof(buf) - len, + "%8s: %10u\n", "TSFOOR", sc->debug.stats.istats.tsfoor); + len += snprintf(buf + len, sizeof(buf) - len, "%8s: %10u\n", "TOTAL", sc->debug.stats.istats.total); + if (len > sizeof(buf)) len = sizeof(buf); diff --git a/drivers/net/wireless/ath/ath9k/debug.h b/drivers/net/wireless/ath/ath9k/debug.h index 1f9f8ea..5488a32 100644 --- a/drivers/net/wireless/ath/ath9k/debug.h +++ b/drivers/net/wireless/ath/ath9k/debug.h @@ -54,6 +54,9 @@ struct ath_buf; * @dtimsync: DTIM sync lossage * @dtim: RX Beacon with DTIM * @bb_watchdog: Baseband watchdog + * @tsfoor: TSF out of range, indicates that the corrected TSF received + * from a beacon differs from the PCU's internal TSF by more than a + * (programmable) threshold */ struct ath_interrupt_stats { u32 total; @@ -78,6 +81,7 @@ struct ath_interrupt_stats { u32 dtimsync; u32 dtim; u32 bb_watchdog; + u32 tsfoor; }; /** -- cgit v0.10.2 From 9835a30e980561082beb02ce724f6e555787bc19 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= Date: Sun, 24 Apr 2011 11:04:19 +0200 Subject: ssb: cc: clear GPIOPULL registers on init 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 diff --git a/drivers/ssb/driver_chipcommon.c b/drivers/ssb/driver_chipcommon.c index 7c031fd..b4b3733 100644 --- a/drivers/ssb/driver_chipcommon.c +++ b/drivers/ssb/driver_chipcommon.c @@ -260,6 +260,12 @@ void ssb_chipcommon_init(struct ssb_chipcommon *cc) if (cc->dev->id.revision >= 11) cc->status = chipco_read32(cc, SSB_CHIPCO_CHIPSTAT); ssb_dprintk(KERN_INFO PFX "chipcommon status is 0x%x\n", cc->status); + + if (cc->dev->id.revision >= 20) { + chipco_write32(cc, SSB_CHIPCO_GPIOPULLUP, 0); + chipco_write32(cc, SSB_CHIPCO_GPIOPULLDOWN, 0); + } + ssb_pmu_init(cc); chipco_powercontrol_init(cc); ssb_chipco_set_clockmode(cc, SSB_CLKMODE_FAST); diff --git a/include/linux/ssb/ssb_driver_chipcommon.h b/include/linux/ssb/ssb_driver_chipcommon.h index 4f2d77a..a08d693 100644 --- a/include/linux/ssb/ssb_driver_chipcommon.h +++ b/include/linux/ssb/ssb_driver_chipcommon.h @@ -123,6 +123,8 @@ #define SSB_CHIPCO_FLASHDATA 0x0048 #define SSB_CHIPCO_BCAST_ADDR 0x0050 #define SSB_CHIPCO_BCAST_DATA 0x0054 +#define SSB_CHIPCO_GPIOPULLUP 0x0058 /* Rev >= 20 only */ +#define SSB_CHIPCO_GPIOPULLDOWN 0x005C /* Rev >= 20 only */ #define SSB_CHIPCO_GPIOIN 0x0060 #define SSB_CHIPCO_GPIOOUT 0x0064 #define SSB_CHIPCO_GPIOOUTEN 0x0068 -- cgit v0.10.2 From 0972ddb2373d5e127aabdcabd8305eff0242cd0b Mon Sep 17 00:00:00 2001 From: Held Bernhard Date: Sun, 24 Apr 2011 22:07:32 +0000 Subject: net: provide cow_metrics() methods to blackhole dst_ops Since commit 62fa8a846d7d (net: Implement read-only protection and COW'ing of metrics.) the kernel throws an oops. [ 101.620985] BUG: unable to handle kernel NULL pointer dereference at (null) [ 101.621050] IP: [< (null)>] (null) [ 101.621084] PGD 6e53c067 PUD 3dd6a067 PMD 0 [ 101.621122] Oops: 0010 [#1] SMP [ 101.621153] last sysfs file: /sys/devices/virtual/ppp/ppp/uevent [ 101.621192] CPU 2 [ 101.621206] Modules linked in: l2tp_ppp pppox ppp_generic slhc l2tp_netlink l2tp_core deflate zlib_deflate twofish_x86_64 twofish_common des_generic cbc ecb sha1_generic hmac af_key iptable_filter snd_pcm_oss snd_mixer_oss snd_seq snd_seq_device loop snd_hda_codec_hdmi snd_hda_codec_realtek snd_hda_intel snd_hda_codec snd_pcm snd_timer snd i2c_i801 iTCO_wdt psmouse soundcore snd_page_alloc evdev uhci_hcd ehci_hcd thermal [ 101.621552] [ 101.621567] Pid: 5129, comm: openl2tpd Not tainted 2.6.39-rc4-Quad #3 Gigabyte Technology Co., Ltd. G33-DS3R/G33-DS3R [ 101.621637] RIP: 0010:[<0000000000000000>] [< (null)>] (null) [ 101.621684] RSP: 0018:ffff88003ddeba60 EFLAGS: 00010202 [ 101.621716] RAX: ffff88003ddb5600 RBX: ffff88003ddb5600 RCX: 0000000000000020 [ 101.621758] RDX: ffffffff81a69a00 RSI: ffffffff81b7ee61 RDI: ffff88003ddb5600 [ 101.621800] RBP: ffff8800537cd900 R08: 0000000000000000 R09: ffff88003ddb5600 [ 101.621840] R10: 0000000000000005 R11: 0000000000014b38 R12: ffff88003ddb5600 [ 101.621881] R13: ffffffff81b7e480 R14: ffffffff81b7e8b8 R15: ffff88003ddebad8 [ 101.621924] FS: 00007f06e4182700(0000) GS:ffff88007fd00000(0000) knlGS:0000000000000000 [ 101.621971] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 [ 101.622005] CR2: 0000000000000000 CR3: 0000000045274000 CR4: 00000000000006e0 [ 101.622046] DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000 [ 101.622087] DR3: 0000000000000000 DR6: 00000000ffff0ff0 DR7: 0000000000000400 [ 101.622129] Process openl2tpd (pid: 5129, threadinfo ffff88003ddea000, task ffff88003de9a280) [ 101.622177] Stack: [ 101.622191] ffffffff81447efa ffff88007d3ded80 ffff88003de9a280 ffff88007d3ded80 [ 101.622245] 0000000000000001 ffff88003ddebbb8 ffffffff8148d5a7 0000000000000212 [ 101.622299] ffff88003dcea000 ffff88003dcea188 ffffffff00000001 ffffffff81b7e480 [ 101.622353] Call Trace: [ 101.622374] [] ? ipv4_blackhole_route+0x1ba/0x210 [ 101.622415] [] ? xfrm_lookup+0x417/0x510 [ 101.622450] [] ? extract_buf+0x9a/0x140 [ 101.622485] [] ? __ip_flush_pending_frames+0x70/0x70 [ 101.622526] [] ? udp_sendmsg+0x62f/0x810 [ 101.622562] [] ? sock_sendmsg+0x116/0x130 [ 101.622599] [] ? find_get_page+0x18/0x90 [ 101.622633] [] ? filemap_fault+0x12a/0x4b0 [ 101.622668] [] ? move_addr_to_kernel+0x64/0x90 [ 101.622706] [] ? verify_iovec+0x7a/0xf0 [ 101.622739] [] ? sys_sendmsg+0x292/0x420 [ 101.622774] [] ? handle_pte_fault+0x8a/0x7c0 [ 101.622810] [] ? __pte_alloc+0xae/0x130 [ 101.622844] [] ? handle_mm_fault+0x138/0x380 [ 101.622880] [] ? do_page_fault+0x189/0x410 [ 101.622915] [] ? sys_getsockname+0xf3/0x110 [ 101.622952] [] ? ip_setsockopt+0x4d/0xa0 [ 101.622986] [] ? sockfd_lookup_light+0x22/0x90 [ 101.623024] [] ? system_call_fastpath+0x16/0x1b [ 101.623060] Code: Bad RIP value. [ 101.623090] RIP [< (null)>] (null) [ 101.623125] RSP [ 101.623146] CR2: 0000000000000000 [ 101.650871] ---[ end trace ca3856a7d8e8dad4 ]--- [ 101.651011] __sk_free: optmem leakage (160 bytes) detected. The oops happens in dst_metrics_write_ptr() include/net/dst.h:124: return dst->ops->cow_metrics(dst, p); dst->ops->cow_metrics is NULL and causes the oops. Provide cow_metrics() methods, like we did in commit 214f45c91bb (net: provide default_advmss() methods to blackhole dst_ops) Signed-off-by: Held Bernhard Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller diff --git a/net/ipv4/route.c b/net/ipv4/route.c index c1acf69..99e6e4b 100644 --- a/net/ipv4/route.c +++ b/net/ipv4/route.c @@ -2690,6 +2690,12 @@ static void ipv4_rt_blackhole_update_pmtu(struct dst_entry *dst, u32 mtu) { } +static u32 *ipv4_rt_blackhole_cow_metrics(struct dst_entry *dst, + unsigned long old) +{ + return NULL; +} + static struct dst_ops ipv4_dst_blackhole_ops = { .family = AF_INET, .protocol = cpu_to_be16(ETH_P_IP), @@ -2698,6 +2704,7 @@ static struct dst_ops ipv4_dst_blackhole_ops = { .default_mtu = ipv4_blackhole_default_mtu, .default_advmss = ipv4_default_advmss, .update_pmtu = ipv4_rt_blackhole_update_pmtu, + .cow_metrics = ipv4_rt_blackhole_cow_metrics, }; struct dst_entry *ipv4_blackhole_route(struct net *net, struct dst_entry *dst_orig) diff --git a/net/ipv6/route.c b/net/ipv6/route.c index 0a5d02a..fd0eec6 100644 --- a/net/ipv6/route.c +++ b/net/ipv6/route.c @@ -153,6 +153,12 @@ static void ip6_rt_blackhole_update_pmtu(struct dst_entry *dst, u32 mtu) { } +static u32 *ip6_rt_blackhole_cow_metrics(struct dst_entry *dst, + unsigned long old) +{ + return NULL; +} + static struct dst_ops ip6_dst_blackhole_ops = { .family = AF_INET6, .protocol = cpu_to_be16(ETH_P_IPV6), @@ -161,6 +167,7 @@ static struct dst_ops ip6_dst_blackhole_ops = { .default_mtu = ip6_blackhole_default_mtu, .default_advmss = ip6_default_advmss, .update_pmtu = ip6_rt_blackhole_update_pmtu, + .cow_metrics = ip6_rt_blackhole_cow_metrics, }; static const u32 ip6_template_metrics[RTAX_MAX] = { -- cgit v0.10.2 From 22d5969fb450afd3a4aff606360f7d52c5a3a628 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Miros=C5=82aw?= Date: Thu, 21 Apr 2011 12:42:15 +0000 Subject: net: make WARN_ON in dev_disable_lro() useful MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: MichaÅ‚ MirosÅ‚aw Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller diff --git a/net/core/dev.c b/net/core/dev.c index 379c993..541f22a 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -1315,7 +1315,8 @@ void dev_disable_lro(struct net_device *dev) return; __ethtool_set_flags(dev, flags & ~ETH_FLAG_LRO); - WARN_ON(dev->features & NETIF_F_LRO); + if (unlikely(dev->features & NETIF_F_LRO)) + netdev_WARN(dev, "failed to disable LRO!\n"); } EXPORT_SYMBOL(dev_disable_lro); -- cgit v0.10.2 From 3aba891dde3842d89ad022237b99c1ed308040b0 Mon Sep 17 00:00:00 2001 From: Jiri Pirko Date: Tue, 19 Apr 2011 03:48:16 +0000 Subject: bonding: move processing of recv handlers into handle_frame() Since now when bonding uses rx_handler, all traffic going into bond device goes thru bond_handle_frame. So there's no need to go back into bonding code later via ptype handlers. This patch converts original ptype handlers into "bonding receive probes". These functions are called from bond_handle_frame and they are registered per-mode. Note that vlan packets are also handled because they are always untagged thanks to vlan_untag() Note that this also allows arpmon for eth-bond-bridge-vlan topology. Signed-off-by: Jiri Pirko Signed-off-by: David S. Miller diff --git a/drivers/net/bonding/bond_3ad.c b/drivers/net/bonding/bond_3ad.c index 123dd60..d0981c2 100644 --- a/drivers/net/bonding/bond_3ad.c +++ b/drivers/net/bonding/bond_3ad.c @@ -2465,35 +2465,16 @@ out: return NETDEV_TX_OK; } -int bond_3ad_lacpdu_recv(struct sk_buff *skb, struct net_device *dev, struct packet_type* ptype, struct net_device *orig_dev) +void bond_3ad_lacpdu_recv(struct sk_buff *skb, struct bonding *bond, + struct slave *slave) { - struct bonding *bond = netdev_priv(dev); - struct slave *slave = NULL; - int ret = NET_RX_DROP; - - if (!(dev->flags & IFF_MASTER)) - goto out; - - skb = skb_share_check(skb, GFP_ATOMIC); - if (!skb) - goto out; + if (skb->protocol != PKT_TYPE_LACPDU) + return; if (!pskb_may_pull(skb, sizeof(struct lacpdu))) - goto out; + return; read_lock(&bond->lock); - slave = bond_get_slave_by_dev(netdev_priv(dev), orig_dev); - if (!slave) - goto out_unlock; - bond_3ad_rx_indication((struct lacpdu *) skb->data, slave, skb->len); - - ret = NET_RX_SUCCESS; - -out_unlock: read_unlock(&bond->lock); -out: - dev_kfree_skb(skb); - - return ret; } diff --git a/drivers/net/bonding/bond_3ad.h b/drivers/net/bonding/bond_3ad.h index b28baff..291dbd4 100644 --- a/drivers/net/bonding/bond_3ad.h +++ b/drivers/net/bonding/bond_3ad.h @@ -258,7 +258,6 @@ struct ad_bond_info { * requested */ struct timer_list ad_timer; - struct packet_type ad_pkt_type; }; struct ad_slave_info { @@ -280,7 +279,8 @@ void bond_3ad_adapter_duplex_changed(struct slave *slave); void bond_3ad_handle_link_change(struct slave *slave, char link); int bond_3ad_get_active_agg_info(struct bonding *bond, struct ad_info *ad_info); int bond_3ad_xmit_xor(struct sk_buff *skb, struct net_device *dev); -int bond_3ad_lacpdu_recv(struct sk_buff *skb, struct net_device *dev, struct packet_type* ptype, struct net_device *orig_dev); +void bond_3ad_lacpdu_recv(struct sk_buff *skb, struct bonding *bond, + struct slave *slave); int bond_3ad_set_carrier(struct bonding *bond); #endif //__BOND_3AD_H__ diff --git a/drivers/net/bonding/bond_alb.c b/drivers/net/bonding/bond_alb.c index ba71582..3b7b040 100644 --- a/drivers/net/bonding/bond_alb.c +++ b/drivers/net/bonding/bond_alb.c @@ -308,49 +308,33 @@ static void rlb_update_entry_from_arp(struct bonding *bond, struct arp_pkt *arp) _unlock_rx_hashtbl(bond); } -static int rlb_arp_recv(struct sk_buff *skb, struct net_device *bond_dev, struct packet_type *ptype, struct net_device *orig_dev) +static void rlb_arp_recv(struct sk_buff *skb, struct bonding *bond, + struct slave *slave) { - struct bonding *bond; - struct arp_pkt *arp = (struct arp_pkt *)skb->data; - int res = NET_RX_DROP; + struct arp_pkt *arp; - while (bond_dev->priv_flags & IFF_802_1Q_VLAN) - bond_dev = vlan_dev_real_dev(bond_dev); - - if (!(bond_dev->priv_flags & IFF_BONDING) || - !(bond_dev->flags & IFF_MASTER)) - goto out; + if (skb->protocol != cpu_to_be16(ETH_P_ARP)) + return; + arp = (struct arp_pkt *) skb->data; if (!arp) { pr_debug("Packet has no ARP data\n"); - goto out; + return; } - skb = skb_share_check(skb, GFP_ATOMIC); - if (!skb) - goto out; - - if (!pskb_may_pull(skb, arp_hdr_len(bond_dev))) - goto out; + if (!pskb_may_pull(skb, arp_hdr_len(bond->dev))) + return; if (skb->len < sizeof(struct arp_pkt)) { pr_debug("Packet is too small to be an ARP\n"); - goto out; + return; } if (arp->op_code == htons(ARPOP_REPLY)) { /* update rx hash table for this ARP */ - bond = netdev_priv(bond_dev); rlb_update_entry_from_arp(bond, arp); pr_debug("Server received an ARP Reply from client\n"); } - - res = NET_RX_SUCCESS; - -out: - dev_kfree_skb(skb); - - return res; } /* Caller must hold bond lock for read */ @@ -759,7 +743,6 @@ static void rlb_init_table_entry(struct rlb_client_info *entry) static int rlb_initialize(struct bonding *bond) { struct alb_bond_info *bond_info = &(BOND_ALB_INFO(bond)); - struct packet_type *pk_type = &(BOND_ALB_INFO(bond).rlb_pkt_type); struct rlb_client_info *new_hashtbl; int size = RLB_HASH_TABLE_SIZE * sizeof(struct rlb_client_info); int i; @@ -784,13 +767,8 @@ static int rlb_initialize(struct bonding *bond) _unlock_rx_hashtbl(bond); - /*initialize packet type*/ - pk_type->type = cpu_to_be16(ETH_P_ARP); - pk_type->dev = bond->dev; - pk_type->func = rlb_arp_recv; - /* register to receive ARPs */ - dev_add_pack(pk_type); + bond->recv_probe = rlb_arp_recv; return 0; } @@ -799,8 +777,6 @@ static void rlb_deinitialize(struct bonding *bond) { struct alb_bond_info *bond_info = &(BOND_ALB_INFO(bond)); - dev_remove_pack(&(bond_info->rlb_pkt_type)); - _lock_rx_hashtbl(bond); kfree(bond_info->rx_hashtbl); diff --git a/drivers/net/bonding/bond_alb.h b/drivers/net/bonding/bond_alb.h index 8ca7158..90f140a 100644 --- a/drivers/net/bonding/bond_alb.h +++ b/drivers/net/bonding/bond_alb.h @@ -129,7 +129,6 @@ struct alb_bond_info { int lp_counter; /* -------- rlb parameters -------- */ int rlb_enabled; - struct packet_type rlb_pkt_type; struct rlb_client_info *rx_hashtbl; /* Receive hash table */ spinlock_t rx_hashtbl_lock; u32 rx_hashtbl_head; diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index 4ce14bd..66d9dc6 100644 --- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c @@ -1439,27 +1439,17 @@ static void bond_setup_by_slave(struct net_device *bond_dev, } /* On bonding slaves other than the currently active slave, suppress - * duplicates except for 802.3ad ETH_P_SLOW, alb non-mcast/bcast, and - * ARP on active-backup slaves with arp_validate enabled. + * duplicates except for alb non-mcast/bcast. */ static bool bond_should_deliver_exact_match(struct sk_buff *skb, struct slave *slave, struct bonding *bond) { if (bond_is_slave_inactive(slave)) { - if (slave_do_arp_validate(bond, slave) && - skb->protocol == __cpu_to_be16(ETH_P_ARP)) - return false; - if (bond->params.mode == BOND_MODE_ALB && skb->pkt_type != PACKET_BROADCAST && skb->pkt_type != PACKET_MULTICAST) - return false; - - if (bond->params.mode == BOND_MODE_8023AD && - skb->protocol == __cpu_to_be16(ETH_P_SLOW)) return false; - return true; } return false; @@ -1483,6 +1473,15 @@ static rx_handler_result_t bond_handle_frame(struct sk_buff **pskb) if (bond->params.arp_interval) slave->dev->last_rx = jiffies; + if (bond->recv_probe) { + struct sk_buff *nskb = skb_clone(skb, GFP_ATOMIC); + + if (likely(nskb)) { + bond->recv_probe(nskb, bond, slave); + dev_kfree_skb(nskb); + } + } + if (bond_should_deliver_exact_match(skb, slave, bond)) { return RX_HANDLER_EXACT; } @@ -2743,48 +2742,26 @@ static void bond_validate_arp(struct bonding *bond, struct slave *slave, __be32 } } -static int bond_arp_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt, struct net_device *orig_dev) +static void bond_arp_rcv(struct sk_buff *skb, struct bonding *bond, + struct slave *slave) { struct arphdr *arp; - struct slave *slave; - struct bonding *bond; unsigned char *arp_ptr; __be32 sip, tip; - if (dev->priv_flags & IFF_802_1Q_VLAN) { - /* - * When using VLANS and bonding, dev and oriv_dev may be - * incorrect if the physical interface supports VLAN - * acceleration. With this change ARP validation now - * works for hosts only reachable on the VLAN interface. - */ - dev = vlan_dev_real_dev(dev); - orig_dev = dev_get_by_index_rcu(dev_net(skb->dev),skb->skb_iif); - } - - if (!(dev->priv_flags & IFF_BONDING) || !(dev->flags & IFF_MASTER)) - goto out; + if (skb->protocol != __cpu_to_be16(ETH_P_ARP)) + return; - bond = netdev_priv(dev); read_lock(&bond->lock); - pr_debug("bond_arp_rcv: bond %s skb->dev %s orig_dev %s\n", - bond->dev->name, skb->dev ? skb->dev->name : "NULL", - orig_dev ? orig_dev->name : "NULL"); + pr_debug("bond_arp_rcv: bond %s skb->dev %s\n", + bond->dev->name, skb->dev->name); - slave = bond_get_slave_by_dev(bond, orig_dev); - if (!slave || !slave_do_arp_validate(bond, slave)) - goto out_unlock; - - skb = skb_share_check(skb, GFP_ATOMIC); - if (!skb) - goto out_unlock; - - if (!pskb_may_pull(skb, arp_hdr_len(dev))) + if (!pskb_may_pull(skb, arp_hdr_len(bond->dev))) goto out_unlock; arp = arp_hdr(skb); - if (arp->ar_hln != dev->addr_len || + if (arp->ar_hln != bond->dev->addr_len || skb->pkt_type == PACKET_OTHERHOST || skb->pkt_type == PACKET_LOOPBACK || arp->ar_hrd != htons(ARPHRD_ETHER) || @@ -2793,9 +2770,9 @@ static int bond_arp_rcv(struct sk_buff *skb, struct net_device *dev, struct pack goto out_unlock; arp_ptr = (unsigned char *)(arp + 1); - arp_ptr += dev->addr_len; + arp_ptr += bond->dev->addr_len; memcpy(&sip, arp_ptr, 4); - arp_ptr += 4 + dev->addr_len; + arp_ptr += 4 + bond->dev->addr_len; memcpy(&tip, arp_ptr, 4); pr_debug("bond_arp_rcv: %s %s/%d av %d sv %d sip %pI4 tip %pI4\n", @@ -2818,9 +2795,6 @@ static int bond_arp_rcv(struct sk_buff *skb, struct net_device *dev, struct pack out_unlock: read_unlock(&bond->lock); -out: - dev_kfree_skb(skb); - return NET_RX_SUCCESS; } /* @@ -3407,48 +3381,6 @@ static struct notifier_block bond_inetaddr_notifier = { .notifier_call = bond_inetaddr_event, }; -/*-------------------------- Packet type handling ---------------------------*/ - -/* register to receive lacpdus on a bond */ -static void bond_register_lacpdu(struct bonding *bond) -{ - struct packet_type *pk_type = &(BOND_AD_INFO(bond).ad_pkt_type); - - /* initialize packet type */ - pk_type->type = PKT_TYPE_LACPDU; - pk_type->dev = bond->dev; - pk_type->func = bond_3ad_lacpdu_recv; - - dev_add_pack(pk_type); -} - -/* unregister to receive lacpdus on a bond */ -static void bond_unregister_lacpdu(struct bonding *bond) -{ - dev_remove_pack(&(BOND_AD_INFO(bond).ad_pkt_type)); -} - -void bond_register_arp(struct bonding *bond) -{ - struct packet_type *pt = &bond->arp_mon_pt; - - if (pt->type) - return; - - pt->type = htons(ETH_P_ARP); - pt->dev = bond->dev; - pt->func = bond_arp_rcv; - dev_add_pack(pt); -} - -void bond_unregister_arp(struct bonding *bond) -{ - struct packet_type *pt = &bond->arp_mon_pt; - - dev_remove_pack(pt); - pt->type = 0; -} - /*---------------------------- Hashing Policies -----------------------------*/ /* @@ -3542,14 +3474,14 @@ static int bond_open(struct net_device *bond_dev) queue_delayed_work(bond->wq, &bond->arp_work, 0); if (bond->params.arp_validate) - bond_register_arp(bond); + bond->recv_probe = bond_arp_rcv; } if (bond->params.mode == BOND_MODE_8023AD) { INIT_DELAYED_WORK(&bond->ad_work, bond_3ad_state_machine_handler); queue_delayed_work(bond->wq, &bond->ad_work, 0); /* register to receive LACPDUs */ - bond_register_lacpdu(bond); + bond->recv_probe = bond_3ad_lacpdu_recv; bond_3ad_initiate_agg_selection(bond, 1); } @@ -3560,14 +3492,6 @@ static int bond_close(struct net_device *bond_dev) { struct bonding *bond = netdev_priv(bond_dev); - if (bond->params.mode == BOND_MODE_8023AD) { - /* Unregister the receive of LACPDUs */ - bond_unregister_lacpdu(bond); - } - - if (bond->params.arp_validate) - bond_unregister_arp(bond); - write_lock_bh(&bond->lock); /* signal timers not to re-arm */ @@ -3604,6 +3528,7 @@ static int bond_close(struct net_device *bond_dev) */ bond_alb_deinitialize(bond); } + bond->recv_probe = NULL; return 0; } diff --git a/drivers/net/bonding/bond_sysfs.c b/drivers/net/bonding/bond_sysfs.c index 259ff32..935406a 100644 --- a/drivers/net/bonding/bond_sysfs.c +++ b/drivers/net/bonding/bond_sysfs.c @@ -422,11 +422,6 @@ static ssize_t bonding_store_arp_validate(struct device *d, bond->dev->name, arp_validate_tbl[new_value].modename, new_value); - if (!bond->params.arp_validate && new_value) - bond_register_arp(bond); - else if (bond->params.arp_validate && !new_value) - bond_unregister_arp(bond); - bond->params.arp_validate = new_value; return count; @@ -923,7 +918,6 @@ static ssize_t bonding_store_miimon(struct device *d, bond->dev->name); bond->params.arp_interval = 0; if (bond->params.arp_validate) { - bond_unregister_arp(bond); bond->params.arp_validate = BOND_ARP_VALIDATE_NONE; } diff --git a/drivers/net/bonding/bonding.h b/drivers/net/bonding/bonding.h index 6126c6a..85fb822 100644 --- a/drivers/net/bonding/bonding.h +++ b/drivers/net/bonding/bonding.h @@ -226,6 +226,8 @@ struct bonding { struct slave *primary_slave; bool force_primary; s32 slave_cnt; /* never change this value outside the attach/detach wrappers */ + void (*recv_probe)(struct sk_buff *, struct bonding *, + struct slave *); rwlock_t lock; rwlock_t curr_slave_lock; s8 kill_timers; @@ -399,8 +401,6 @@ void bond_set_mode_ops(struct bonding *bond, int mode); int bond_parse_parm(const char *mode_arg, const struct bond_parm_tbl *tbl); void bond_select_active_slave(struct bonding *bond); void bond_change_active_slave(struct bonding *bond, struct slave *new_active); -void bond_register_arp(struct bonding *); -void bond_unregister_arp(struct bonding *); void bond_create_debugfs(void); void bond_destroy_debugfs(void); void bond_debug_register(struct bonding *bond); diff --git a/net/core/dev.c b/net/core/dev.c index 541f22a..3bbb4c2 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -3077,25 +3077,6 @@ void netdev_rx_handler_unregister(struct net_device *dev) } EXPORT_SYMBOL_GPL(netdev_rx_handler_unregister); -static void vlan_on_bond_hook(struct sk_buff *skb) -{ - /* - * Make sure ARP frames received on VLAN interfaces stacked on - * bonding interfaces still make their way to any base bonding - * device that may have registered for a specific ptype. - */ - if (skb->dev->priv_flags & IFF_802_1Q_VLAN && - vlan_dev_real_dev(skb->dev)->priv_flags & IFF_BONDING && - skb->protocol == htons(ETH_P_ARP)) { - struct sk_buff *skb2 = skb_clone(skb, GFP_ATOMIC); - - if (!skb2) - return; - skb2->dev = vlan_dev_real_dev(skb->dev); - netif_rx(skb2); - } -} - static int __netif_receive_skb(struct sk_buff *skb) { struct packet_type *ptype, *pt_prev; @@ -3191,8 +3172,6 @@ ncls: goto out; } - vlan_on_bond_hook(skb); - /* deliver only exact match when indicated */ null_or_dev = deliver_exact ? skb->dev : NULL; -- cgit v0.10.2 From fe2a70eefa18a3e419dd9a23e16af14258b7cc20 Mon Sep 17 00:00:00 2001 From: Somnath Kotur Date: Thu, 21 Apr 2011 03:18:12 +0000 Subject: be2net: Fixed a bug in be_cmd_get_regs(). Same WRB entry was being reused over different iterations of a loop while issuing non-embedded IOCTL requests.Fixed couple of minor bugs in this path as well. Re-factored code to alloc/free memory for DMA outside of loop Signed-off-by: Somnath Kotur Signed-off-by: David S. Miller diff --git a/drivers/net/benet/be_cmds.c b/drivers/net/benet/be_cmds.c index af8cf3d..0fc06d3 100644 --- a/drivers/net/benet/be_cmds.c +++ b/drivers/net/benet/be_cmds.c @@ -1214,8 +1214,8 @@ int be_cmd_get_reg_len(struct be_adapter *adapter, u32 *log_size) if (!status) { struct be_cmd_resp_get_fat *resp = embedded_payload(wrb); if (log_size && resp->log_size) - *log_size = le32_to_cpu(resp->log_size - - sizeof(u32)); + *log_size = le32_to_cpu(resp->log_size) - + sizeof(u32); } err: spin_unlock_bh(&adapter->mcc_lock); @@ -1228,7 +1228,8 @@ void be_cmd_get_regs(struct be_adapter *adapter, u32 buf_len, void *buf) struct be_mcc_wrb *wrb; struct be_cmd_req_get_fat *req; struct be_sge *sge; - u32 offset = 0, total_size, buf_size, log_offset = sizeof(u32); + u32 offset = 0, total_size, buf_size, + log_offset = sizeof(u32), payload_len; int status; if (buf_len == 0) @@ -1236,37 +1237,39 @@ void be_cmd_get_regs(struct be_adapter *adapter, u32 buf_len, void *buf) total_size = buf_len; + get_fat_cmd.size = sizeof(struct be_cmd_req_get_fat) + 60*1024; + get_fat_cmd.va = pci_alloc_consistent(adapter->pdev, + get_fat_cmd.size, + &get_fat_cmd.dma); + if (!get_fat_cmd.va) { + status = -ENOMEM; + dev_err(&adapter->pdev->dev, + "Memory allocation failure while retrieving FAT data\n"); + return; + } + spin_lock_bh(&adapter->mcc_lock); - wrb = wrb_from_mccq(adapter); - if (!wrb) { - status = -EBUSY; - goto err; - } while (total_size) { buf_size = min(total_size, (u32)60*1024); total_size -= buf_size; - get_fat_cmd.size = sizeof(struct be_cmd_req_get_fat) + buf_size; - get_fat_cmd.va = pci_alloc_consistent(adapter->pdev, - get_fat_cmd.size, - &get_fat_cmd.dma); - if (!get_fat_cmd.va) { - status = -ENOMEM; - dev_err(&adapter->pdev->dev, - "Memory allocation failure while retrieving FAT data\n"); + wrb = wrb_from_mccq(adapter); + if (!wrb) { + status = -EBUSY; goto err; } req = get_fat_cmd.va; sge = nonembedded_sgl(wrb); - be_wrb_hdr_prepare(wrb, get_fat_cmd.size, false, 1, + payload_len = sizeof(struct be_cmd_req_get_fat) + buf_size; + be_wrb_hdr_prepare(wrb, payload_len, false, 1, OPCODE_COMMON_MANAGE_FAT); be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON, - OPCODE_COMMON_MANAGE_FAT, get_fat_cmd.size); + OPCODE_COMMON_MANAGE_FAT, payload_len); - sge->pa_hi = cpu_to_le32(upper_32_bits(get_fat_cmd.size)); + sge->pa_hi = cpu_to_le32(upper_32_bits(get_fat_cmd.dma)); sge->pa_lo = cpu_to_le32(get_fat_cmd.dma & 0xFFFFFFFF); sge->len = cpu_to_le32(get_fat_cmd.size); @@ -1281,17 +1284,17 @@ void be_cmd_get_regs(struct be_adapter *adapter, u32 buf_len, void *buf) memcpy(buf + offset, resp->data_buffer, resp->read_log_length); - } - pci_free_consistent(adapter->pdev, get_fat_cmd.size, - get_fat_cmd.va, - get_fat_cmd.dma); - if (status) + } else { dev_err(&adapter->pdev->dev, "FAT Table Retrieve error\n"); - + goto err; + } offset += buf_size; log_offset += buf_size; } err: + pci_free_consistent(adapter->pdev, get_fat_cmd.size, + get_fat_cmd.va, + get_fat_cmd.dma); spin_unlock_bh(&adapter->mcc_lock); } -- cgit v0.10.2 From 9d5f96f61837b1242dd8c576c6110593475fcf86 Mon Sep 17 00:00:00 2001 From: Florian Tobias Schandinat Date: Mon, 25 Apr 2011 20:01:46 +0000 Subject: viafb: try to map less memory in case of failure The current code might result in trying to remap 512MB video ram on a 32 bit system which is quite likely to fail. This patch tries to map less of it down to 8MB as this should still be enough to get a reasonably well working framebuffer. This should make viafb work for many people without requiring them to manually allocate more space. Signed-off-by: Florian Tobias Schandinat diff --git a/drivers/video/via/via-core.c b/drivers/video/via/via-core.c index 5b0129b..eb112b6 100644 --- a/drivers/video/via/via-core.c +++ b/drivers/video/via/via-core.c @@ -505,7 +505,14 @@ static int __devinit via_pci_setup_mmio(struct viafb_dev *vdev) ret = vdev->fbmem_len = viafb_get_fb_size_from_pci(vdev->chip_type); if (ret < 0) goto out_unmap; - vdev->fbmem = ioremap_wc(vdev->fbmem_start, vdev->fbmem_len); + + /* try to map less memory on failure, 8 MB should be still enough */ + for (; vdev->fbmem_len >= 8 << 20; vdev->fbmem_len /= 2) { + vdev->fbmem = ioremap_wc(vdev->fbmem_start, vdev->fbmem_len); + if (vdev->fbmem) + break; + } + if (vdev->fbmem == NULL) { ret = -ENOMEM; goto out_unmap; -- cgit v0.10.2 From bf734843120b905bacc3d24c88d7455ae70bf6e1 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Mon, 25 Apr 2011 13:03:02 -0700 Subject: bluetooth: Fix use-before-initiailized var. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit net/bluetooth/l2cap_core.c: In function ‘l2cap_recv_frame’: net/bluetooth/l2cap_core.c:3612:15: warning: ‘sk’ may be used uninitialized in this function net/bluetooth/l2cap_core.c:3612:15: note: ‘sk’ was declared here Actually the problem is in the inline function l2cap_data_channel(), we branch to the label 'done' which tests 'sk' before we set it to anything. Initialize it to NULL to fix this. Signed-off-by: David S. Miller diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index d47de2b..8cfa2a6 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -3609,7 +3609,7 @@ drop: static inline int l2cap_data_channel(struct l2cap_conn *conn, u16 cid, struct sk_buff *skb) { struct l2cap_chan *chan; - struct sock *sk; + struct sock *sk = NULL; struct l2cap_pinfo *pi; u16 control; u8 tx_seq; -- cgit v0.10.2 From 39b68976ac653cfdc7f872a293e8b7928de2dcc6 Mon Sep 17 00:00:00 2001 From: "H. Peter Anvin" Date: Mon, 25 Apr 2011 14:52:37 -0700 Subject: x86, setup: When probing memory with e801, use ax/bx as a pair When we use BIOS function e801 to probe memory, we should use ax/bx (or cx/dx) as a pair, not mix and match. This was a typo during the translation from assembly code, and breaks at least one set of machines in the field (which return cx = dx = 0). Reported-and-tested-by: Chris Samuel Fix-proposed-by: Thomas Meyer Link: http://lkml.kernel.org/r/1303566747.12067.10.camel@localhost.localdomain diff --git a/arch/x86/boot/memory.c b/arch/x86/boot/memory.c index cae3feb..db75d07 100644 --- a/arch/x86/boot/memory.c +++ b/arch/x86/boot/memory.c @@ -91,7 +91,7 @@ static int detect_memory_e801(void) if (oreg.ax > 15*1024) { return -1; /* Bogus! */ } else if (oreg.ax == 15*1024) { - boot_params.alt_mem_k = (oreg.dx << 6) + oreg.ax; + boot_params.alt_mem_k = (oreg.bx << 6) + oreg.ax; } else { /* * This ignores memory above 16MB if we have a memory -- cgit v0.10.2 From 85723943537bf6a73bdf1140b2088fbe0c17c3c2 Mon Sep 17 00:00:00 2001 From: Wanlong Gao Date: Sat, 23 Apr 2011 22:18:26 +0800 Subject: drivers:base:fix the coding format of memory.c Fix the line longer than 80 of memory_uevent function . Signed-off-by: Wanlong Gao Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/base/memory.c b/drivers/base/memory.c index 3da6a43..3e9aa3d 100644 --- a/drivers/base/memory.c +++ b/drivers/base/memory.c @@ -48,7 +48,8 @@ static const char *memory_uevent_name(struct kset *kset, struct kobject *kobj) return MEMORY_CLASS_NAME; } -static int memory_uevent(struct kset *kset, struct kobject *obj, struct kobj_uevent_env *env) +static int memory_uevent(struct kset *kset, struct kobject *obj, + struct kobj_uevent_env *env) { int retval = 0; -- cgit v0.10.2 From ad58671cf32c74a8d6e8f51e63e9cf4e7a73bf1e Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Tue, 19 Apr 2011 12:43:45 +0100 Subject: Add a strtobool function matching semantics of existing in kernel equivalents This is a rename of the usr_strtobool proposal, which was a renamed, relocated and fixed version of previous kstrtobool RFC Signed-off-by: Jonathan Cameron Signed-off-by: Greg Kroah-Hartman diff --git a/include/linux/string.h b/include/linux/string.h index a716ee2..a176db2 100644 --- a/include/linux/string.h +++ b/include/linux/string.h @@ -123,6 +123,7 @@ extern char **argv_split(gfp_t gfp, const char *str, int *argcp); extern void argv_free(char **argv); extern bool sysfs_streq(const char *s1, const char *s2); +extern int strtobool(const char *s, bool *res); #ifdef CONFIG_BINARY_PRINTF int vbin_printf(u32 *bin_buf, size_t size, const char *fmt, va_list args); diff --git a/lib/string.c b/lib/string.c index f71bead..01fad9b 100644 --- a/lib/string.c +++ b/lib/string.c @@ -535,6 +535,35 @@ bool sysfs_streq(const char *s1, const char *s2) } EXPORT_SYMBOL(sysfs_streq); +/** + * strtobool - convert common user inputs into boolean values + * @s: input string + * @res: result + * + * This routine returns 0 iff the first character is one of 'Yy1Nn0'. + * Otherwise it will return -EINVAL. Value pointed to by res is + * updated upon finding a match. + */ +int strtobool(const char *s, bool *res) +{ + switch (s[0]) { + case 'y': + case 'Y': + case '1': + *res = true; + break; + case 'n': + case 'N': + case '0': + *res = false; + break; + default: + return -EINVAL; + } + return 0; +} +EXPORT_SYMBOL(strtobool); + #ifndef __HAVE_ARCH_MEMSET /** * memset - Fill a region of memory with the given value -- cgit v0.10.2 From 8705b48e7159655c116154928fe104fd6561fa94 Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Tue, 19 Apr 2011 12:43:46 +0100 Subject: debugfs: move to new strtobool No functional changes requires that we eat errors from strtobool. If people want to not do this, then it should be fixed at a later date. V2: Simplification suggested by Rusty Russell removes the need for additional variable ret. Signed-off-by: Jonathan Cameron Signed-off-by: Greg Kroah-Hartman diff --git a/fs/debugfs/file.c b/fs/debugfs/file.c index 89d394d..568304d 100644 --- a/fs/debugfs/file.c +++ b/fs/debugfs/file.c @@ -429,25 +429,16 @@ static ssize_t write_file_bool(struct file *file, const char __user *user_buf, { char buf[32]; int buf_size; + bool bv; u32 *val = file->private_data; buf_size = min(count, (sizeof(buf)-1)); if (copy_from_user(buf, user_buf, buf_size)) return -EFAULT; - switch (buf[0]) { - case 'y': - case 'Y': - case '1': - *val = 1; - break; - case 'n': - case 'N': - case '0': - *val = 0; - break; - } - + if (strtobool(buf, &bv) == 0) + *val = bv; + return count; } -- cgit v0.10.2 From e7e09cd667a43d8287f85d453a16fc0ec1e2c7b7 Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Tue, 19 Apr 2011 12:43:47 +0100 Subject: params.c: Use new strtobool function to process boolean inputs No functional changes. Signed-off-by: Jonathan Cameron Signed-off-by: Greg Kroah-Hartman diff --git a/kernel/params.c b/kernel/params.c index 7ab388a..6888761 100644 --- a/kernel/params.c +++ b/kernel/params.c @@ -297,21 +297,15 @@ EXPORT_SYMBOL(param_ops_charp); int param_set_bool(const char *val, const struct kernel_param *kp) { bool v; + int ret; /* No equals means "set"... */ if (!val) val = "1"; /* One of =[yYnN01] */ - switch (val[0]) { - case 'y': case 'Y': case '1': - v = true; - break; - case 'n': case 'N': case '0': - v = false; - break; - default: - return -EINVAL; - } + ret = strtobool(val, &v); + if (ret) + return ret; if (kp->flags & KPARAM_ISBOOL) *(bool *)kp->arg = v; -- cgit v0.10.2 From 35ffa948b2f7bdf79e488cd496232935d095087a Mon Sep 17 00:00:00 2001 From: Tyler Hicks Date: Tue, 12 Apr 2011 11:21:36 -0500 Subject: eCryptfs: Remove extra d_delete in ecryptfs_rmdir vfs_rmdir() already calls d_delete() on the lower dentry. That was being duplicated in ecryptfs_rmdir() and caused a NULL pointer dereference when NFSv3 was the lower filesystem. Signed-off-by: Tyler Hicks diff --git a/fs/ecryptfs/inode.c b/fs/ecryptfs/inode.c index f99051b..9c3c2f5 100644 --- a/fs/ecryptfs/inode.c +++ b/fs/ecryptfs/inode.c @@ -538,8 +538,6 @@ static int ecryptfs_rmdir(struct inode *dir, struct dentry *dentry) dget(lower_dentry); rc = vfs_rmdir(lower_dir_dentry->d_inode, lower_dentry); dput(lower_dentry); - if (!rc) - d_delete(lower_dentry); fsstack_copy_attr_times(dir, lower_dir_dentry->d_inode); dir->i_nlink = lower_dir_dentry->d_inode->i_nlink; unlock_dir(lower_dir_dentry); -- cgit v0.10.2 From dd55c89852481a0708c3fd4b48f3081f4280d9d3 Mon Sep 17 00:00:00 2001 From: Tyler Hicks Date: Tue, 12 Apr 2011 11:23:09 -0500 Subject: eCryptfs: dput dentries returned from dget_parent Call dput on the dentries previously returned by dget_parent() in ecryptfs_rename(). This is needed for supported eCryptfs mounts on top of the NFSv3 client. Signed-off-by: Tyler Hicks diff --git a/fs/ecryptfs/inode.c b/fs/ecryptfs/inode.c index 9c3c2f5..72d3576 100644 --- a/fs/ecryptfs/inode.c +++ b/fs/ecryptfs/inode.c @@ -608,8 +608,8 @@ ecryptfs_rename(struct inode *old_dir, struct dentry *old_dentry, fsstack_copy_attr_all(old_dir, lower_old_dir_dentry->d_inode); out_lock: unlock_rename(lower_old_dir_dentry, lower_new_dir_dentry); - dput(lower_new_dentry->d_parent); - dput(lower_old_dentry->d_parent); + dput(lower_new_dir_dentry); + dput(lower_old_dir_dentry); dput(lower_new_dentry); dput(lower_old_dentry); return rc; -- cgit v0.10.2 From 332ab16f830f59e7621ae8eb2c353dc135a316f6 Mon Sep 17 00:00:00 2001 From: Tyler Hicks Date: Thu, 14 Apr 2011 15:35:11 -0500 Subject: eCryptfs: Add reference counting to lower files For any given lower inode, eCryptfs keeps only one lower file open and multiplexes all eCryptfs file operations through that lower file. The lower file was considered "persistent" and stayed open from the first lookup through the lifetime of the inode. This patch keeps the notion of a single, per-inode lower file, but adds reference counting around the lower file so that it is closed when not currently in use. If the reference count is at 0 when an operation (such as open, create, etc.) needs to use the lower file, a new lower file is opened. Since the file is no longer persistent, all references to the term persistent file are changed to lower file. Locking is added around the sections of code that opens the lower file and assign the pointer in the inode info, as well as the code the fputs the lower file when all eCryptfs users are done with it. This patch is needed to fix issues, when mounted on top of the NFSv3 client, where the lower file is left silly renamed until the eCryptfs inode is destroyed. Signed-off-by: Tyler Hicks diff --git a/fs/ecryptfs/ecryptfs_kernel.h b/fs/ecryptfs/ecryptfs_kernel.h index bd3cafd..380bee1 100644 --- a/fs/ecryptfs/ecryptfs_kernel.h +++ b/fs/ecryptfs/ecryptfs_kernel.h @@ -295,6 +295,8 @@ struct ecryptfs_crypt_stat { struct ecryptfs_inode_info { struct inode vfs_inode; struct inode *wii_inode; + struct mutex lower_file_mutex; + atomic_t lower_file_count; struct file *lower_file; struct ecryptfs_crypt_stat crypt_stat; }; @@ -757,7 +759,8 @@ int ecryptfs_privileged_open(struct file **lower_file, struct dentry *lower_dentry, struct vfsmount *lower_mnt, const struct cred *cred); -int ecryptfs_init_persistent_file(struct dentry *ecryptfs_dentry); +int ecryptfs_get_lower_file(struct dentry *ecryptfs_dentry); +void ecryptfs_put_lower_file(struct inode *inode); int ecryptfs_write_tag_70_packet(char *dest, size_t *remaining_bytes, size_t *packet_size, diff --git a/fs/ecryptfs/file.c b/fs/ecryptfs/file.c index cedc913..146c4ed 100644 --- a/fs/ecryptfs/file.c +++ b/fs/ecryptfs/file.c @@ -191,10 +191,10 @@ static int ecryptfs_open(struct inode *inode, struct file *file) | ECRYPTFS_ENCRYPTED); } mutex_unlock(&crypt_stat->cs_mutex); - rc = ecryptfs_init_persistent_file(ecryptfs_dentry); + rc = ecryptfs_get_lower_file(ecryptfs_dentry); if (rc) { printk(KERN_ERR "%s: Error attempting to initialize " - "the persistent file for the dentry with name " + "the lower file for the dentry with name " "[%s]; rc = [%d]\n", __func__, ecryptfs_dentry->d_name.name, rc); goto out_free; @@ -202,9 +202,9 @@ static int ecryptfs_open(struct inode *inode, struct file *file) if ((ecryptfs_inode_to_private(inode)->lower_file->f_flags & O_ACCMODE) == O_RDONLY && (file->f_flags & O_ACCMODE) != O_RDONLY) { rc = -EPERM; - printk(KERN_WARNING "%s: Lower persistent file is RO; eCryptfs " + printk(KERN_WARNING "%s: Lower file is RO; eCryptfs " "file must hence be opened RO\n", __func__); - goto out_free; + goto out_put; } ecryptfs_set_file_lower( file, ecryptfs_inode_to_private(inode)->lower_file); @@ -232,7 +232,7 @@ static int ecryptfs_open(struct inode *inode, struct file *file) "Plaintext passthrough mode is not " "enabled; returning -EIO\n"); mutex_unlock(&crypt_stat->cs_mutex); - goto out_free; + goto out_put; } rc = 0; crypt_stat->flags &= ~(ECRYPTFS_ENCRYPTED); @@ -245,6 +245,8 @@ static int ecryptfs_open(struct inode *inode, struct file *file) "[0x%.16lx] size: [0x%.16llx]\n", inode, inode->i_ino, (unsigned long long)i_size_read(inode)); goto out; +out_put: + ecryptfs_put_lower_file(inode); out_free: kmem_cache_free(ecryptfs_file_info_cache, ecryptfs_file_to_private(file)); @@ -254,17 +256,13 @@ out: static int ecryptfs_flush(struct file *file, fl_owner_t td) { - int rc = 0; - struct file *lower_file = NULL; - - lower_file = ecryptfs_file_to_lower(file); - if (lower_file->f_op && lower_file->f_op->flush) - rc = lower_file->f_op->flush(lower_file, td); - return rc; + return file->f_mode & FMODE_WRITE + ? filemap_write_and_wait(file->f_mapping) : 0; } static int ecryptfs_release(struct inode *inode, struct file *file) { + ecryptfs_put_lower_file(inode); kmem_cache_free(ecryptfs_file_info_cache, ecryptfs_file_to_private(file)); return 0; diff --git a/fs/ecryptfs/inode.c b/fs/ecryptfs/inode.c index 72d3576..f6b3886 100644 --- a/fs/ecryptfs/inode.c +++ b/fs/ecryptfs/inode.c @@ -168,19 +168,18 @@ static int ecryptfs_initialize_file(struct dentry *ecryptfs_dentry) "context; rc = [%d]\n", rc); goto out; } - rc = ecryptfs_init_persistent_file(ecryptfs_dentry); + rc = ecryptfs_get_lower_file(ecryptfs_dentry); if (rc) { printk(KERN_ERR "%s: Error attempting to initialize " - "the persistent file for the dentry with name " + "the lower file for the dentry with name " "[%s]; rc = [%d]\n", __func__, ecryptfs_dentry->d_name.name, rc); goto out; } rc = ecryptfs_write_metadata(ecryptfs_dentry); - if (rc) { + if (rc) printk(KERN_ERR "Error writing headers; rc = [%d]\n", rc); - goto out; - } + ecryptfs_put_lower_file(ecryptfs_dentry->d_inode); out: return rc; } @@ -230,7 +229,7 @@ int ecryptfs_lookup_and_interpose_lower(struct dentry *ecryptfs_dentry, struct ecryptfs_crypt_stat *crypt_stat; char *page_virt = NULL; u64 file_size; - int rc = 0; + int put_lower = 0, rc = 0; lower_dir_dentry = lower_dentry->d_parent; lower_mnt = mntget(ecryptfs_dentry_to_lower_mnt( @@ -277,14 +276,15 @@ int ecryptfs_lookup_and_interpose_lower(struct dentry *ecryptfs_dentry, rc = -ENOMEM; goto out; } - rc = ecryptfs_init_persistent_file(ecryptfs_dentry); + rc = ecryptfs_get_lower_file(ecryptfs_dentry); if (rc) { printk(KERN_ERR "%s: Error attempting to initialize " - "the persistent file for the dentry with name " + "the lower file for the dentry with name " "[%s]; rc = [%d]\n", __func__, ecryptfs_dentry->d_name.name, rc); goto out_free_kmem; } + put_lower = 1; crypt_stat = &ecryptfs_inode_to_private( ecryptfs_dentry->d_inode)->crypt_stat; /* TODO: lock for crypt_stat comparison */ @@ -322,6 +322,8 @@ out_put: mntput(lower_mnt); d_drop(ecryptfs_dentry); out: + if (put_lower) + ecryptfs_put_lower_file(ecryptfs_dentry->d_inode); return rc; } @@ -757,8 +759,11 @@ static int truncate_upper(struct dentry *dentry, struct iattr *ia, if (unlikely((ia->ia_size == i_size))) { lower_ia->ia_valid &= ~ATTR_SIZE; - goto out; + return 0; } + rc = ecryptfs_get_lower_file(dentry); + if (rc) + return rc; crypt_stat = &ecryptfs_inode_to_private(dentry->d_inode)->crypt_stat; /* Switch on growing or shrinking file */ if (ia->ia_size > i_size) { @@ -836,6 +841,7 @@ static int truncate_upper(struct dentry *dentry, struct iattr *ia, lower_ia->ia_valid &= ~ATTR_SIZE; } out: + ecryptfs_put_lower_file(inode); return rc; } @@ -911,7 +917,13 @@ static int ecryptfs_setattr(struct dentry *dentry, struct iattr *ia) mount_crypt_stat = &ecryptfs_superblock_to_private( dentry->d_sb)->mount_crypt_stat; + rc = ecryptfs_get_lower_file(dentry); + if (rc) { + mutex_unlock(&crypt_stat->cs_mutex); + goto out; + } rc = ecryptfs_read_metadata(dentry); + ecryptfs_put_lower_file(inode); if (rc) { if (!(mount_crypt_stat->flags & ECRYPTFS_PLAINTEXT_PASSTHROUGH_ENABLED)) { diff --git a/fs/ecryptfs/kthread.c b/fs/ecryptfs/kthread.c index 0851ab6..69f994a 100644 --- a/fs/ecryptfs/kthread.c +++ b/fs/ecryptfs/kthread.c @@ -44,7 +44,7 @@ static struct task_struct *ecryptfs_kthread; * @ignored: ignored * * The eCryptfs kernel thread that has the responsibility of getting - * the lower persistent file with RW permissions. + * the lower file with RW permissions. * * Returns zero on success; non-zero otherwise */ @@ -141,8 +141,8 @@ int ecryptfs_privileged_open(struct file **lower_file, int rc = 0; /* Corresponding dput() and mntput() are done when the - * persistent file is fput() when the eCryptfs inode is - * destroyed. */ + * lower file is fput() when all eCryptfs files for the inode are + * released. */ dget(lower_dentry); mntget(lower_mnt); flags |= IS_RDONLY(lower_dentry->d_inode) ? O_RDONLY : O_RDWR; diff --git a/fs/ecryptfs/main.c b/fs/ecryptfs/main.c index fdb2eb0..89b9338 100644 --- a/fs/ecryptfs/main.c +++ b/fs/ecryptfs/main.c @@ -96,7 +96,7 @@ void __ecryptfs_printk(const char *fmt, ...) } /** - * ecryptfs_init_persistent_file + * ecryptfs_init_lower_file * @ecryptfs_dentry: Fully initialized eCryptfs dentry object, with * the lower dentry and the lower mount set * @@ -104,42 +104,70 @@ void __ecryptfs_printk(const char *fmt, ...) * inode. All I/O operations to the lower inode occur through that * file. When the first eCryptfs dentry that interposes with the first * lower dentry for that inode is created, this function creates the - * persistent file struct and associates it with the eCryptfs - * inode. When the eCryptfs inode is destroyed, the file is closed. + * lower file struct and associates it with the eCryptfs + * inode. When all eCryptfs files associated with the inode are released, the + * file is closed. * - * The persistent file will be opened with read/write permissions, if + * The lower file will be opened with read/write permissions, if * possible. Otherwise, it is opened read-only. * - * This function does nothing if a lower persistent file is already + * This function does nothing if a lower file is already * associated with the eCryptfs inode. * * Returns zero on success; non-zero otherwise */ -int ecryptfs_init_persistent_file(struct dentry *ecryptfs_dentry) +static int ecryptfs_init_lower_file(struct dentry *dentry, + struct file **lower_file) { const struct cred *cred = current_cred(); - struct ecryptfs_inode_info *inode_info = - ecryptfs_inode_to_private(ecryptfs_dentry->d_inode); - int rc = 0; + struct dentry *lower_dentry = ecryptfs_dentry_to_lower(dentry); + struct vfsmount *lower_mnt = ecryptfs_dentry_to_lower_mnt(dentry); + int rc; - if (!inode_info->lower_file) { - struct dentry *lower_dentry; - struct vfsmount *lower_mnt = - ecryptfs_dentry_to_lower_mnt(ecryptfs_dentry); + rc = ecryptfs_privileged_open(lower_file, lower_dentry, lower_mnt, + cred); + if (rc) { + printk(KERN_ERR "Error opening lower file " + "for lower_dentry [0x%p] and lower_mnt [0x%p]; " + "rc = [%d]\n", lower_dentry, lower_mnt, rc); + (*lower_file) = NULL; + } + return rc; +} - lower_dentry = ecryptfs_dentry_to_lower(ecryptfs_dentry); - rc = ecryptfs_privileged_open(&inode_info->lower_file, - lower_dentry, lower_mnt, cred); - if (rc) { - printk(KERN_ERR "Error opening lower persistent file " - "for lower_dentry [0x%p] and lower_mnt [0x%p]; " - "rc = [%d]\n", lower_dentry, lower_mnt, rc); - inode_info->lower_file = NULL; - } +int ecryptfs_get_lower_file(struct dentry *dentry) +{ + struct ecryptfs_inode_info *inode_info = + ecryptfs_inode_to_private(dentry->d_inode); + int count, rc = 0; + + mutex_lock(&inode_info->lower_file_mutex); + count = atomic_inc_return(&inode_info->lower_file_count); + if (WARN_ON_ONCE(count < 1)) + rc = -EINVAL; + else if (count == 1) { + rc = ecryptfs_init_lower_file(dentry, + &inode_info->lower_file); + if (rc) + atomic_set(&inode_info->lower_file_count, 0); } + mutex_unlock(&inode_info->lower_file_mutex); return rc; } +void ecryptfs_put_lower_file(struct inode *inode) +{ + struct ecryptfs_inode_info *inode_info; + + inode_info = ecryptfs_inode_to_private(inode); + if (atomic_dec_and_mutex_lock(&inode_info->lower_file_count, + &inode_info->lower_file_mutex)) { + fput(inode_info->lower_file); + inode_info->lower_file = NULL; + mutex_unlock(&inode_info->lower_file_mutex); + } +} + static struct inode *ecryptfs_get_inode(struct inode *lower_inode, struct super_block *sb) { diff --git a/fs/ecryptfs/super.c b/fs/ecryptfs/super.c index bacc882..245b517 100644 --- a/fs/ecryptfs/super.c +++ b/fs/ecryptfs/super.c @@ -55,6 +55,8 @@ static struct inode *ecryptfs_alloc_inode(struct super_block *sb) if (unlikely(!inode_info)) goto out; ecryptfs_init_crypt_stat(&inode_info->crypt_stat); + mutex_init(&inode_info->lower_file_mutex); + atomic_set(&inode_info->lower_file_count, 0); inode_info->lower_file = NULL; inode = &inode_info->vfs_inode; out: @@ -77,8 +79,7 @@ static void ecryptfs_i_callback(struct rcu_head *head) * * This is used during the final destruction of the inode. All * allocation of memory related to the inode, including allocated - * memory in the crypt_stat struct, will be released here. This - * function also fput()'s the persistent file for the lower inode. + * memory in the crypt_stat struct, will be released here. * There should be no chance that this deallocation will be missed. */ static void ecryptfs_destroy_inode(struct inode *inode) @@ -86,16 +87,7 @@ static void ecryptfs_destroy_inode(struct inode *inode) struct ecryptfs_inode_info *inode_info; inode_info = ecryptfs_inode_to_private(inode); - if (inode_info->lower_file) { - struct dentry *lower_dentry = - inode_info->lower_file->f_dentry; - - BUG_ON(!lower_dentry); - if (lower_dentry->d_inode) { - fput(inode_info->lower_file); - inode_info->lower_file = NULL; - } - } + BUG_ON(inode_info->lower_file); ecryptfs_destroy_crypt_stat(&inode_info->crypt_stat); call_rcu(&inode->i_rcu, ecryptfs_i_callback); } -- cgit v0.10.2 From a62f44a5f47ce45e524b55f91542dc386c6de7ef Mon Sep 17 00:00:00 2001 From: Tsutomu Itoh Date: Mon, 25 Apr 2011 19:43:51 -0400 Subject: Btrfs: fix missing mutex_unlock in btrfs_del_dir_entries_in_log() It is necessary to unlock mutex_lock before it return an error when btrfs_alloc_path() fails. Signed-off-by: Tsutomu Itoh Signed-off-by: Chris Mason diff --git a/fs/btrfs/tree-log.c b/fs/btrfs/tree-log.c index c50271a..f997ec0 100644 --- a/fs/btrfs/tree-log.c +++ b/fs/btrfs/tree-log.c @@ -2209,8 +2209,10 @@ int btrfs_del_dir_entries_in_log(struct btrfs_trans_handle *trans, log = root->log_root; path = btrfs_alloc_path(); - if (!path) - return -ENOMEM; + if (!path) { + err = -ENOMEM; + goto out_unlock; + } di = btrfs_lookup_dir_item(trans, log, path, dir->i_ino, name, name_len, -1); @@ -2271,6 +2273,7 @@ int btrfs_del_dir_entries_in_log(struct btrfs_trans_handle *trans, } fail: btrfs_free_path(path); +out_unlock: mutex_unlock(&BTRFS_I(dir)->log_mutex); if (ret == -ENOSPC) { root->fs_info->last_trans_log_full_commit = trans->transid; -- cgit v0.10.2 From 43e817a1fdda17f3357602ed7964c248c8c53ae0 Mon Sep 17 00:00:00 2001 From: Itaru Kitayama Date: Mon, 25 Apr 2011 19:43:51 -0400 Subject: btrfs: fix wrong allocating flag when reading page the space cache use extent_readpages() to read free space information, so we can not use GFP_KERNEL flag to allocate memory, or it may lead to deadlock. Signed-off-by: Itaru Kitayama Signed-off-by: Miao Xie Signed-off-by: Chris Mason diff --git a/fs/btrfs/extent_io.c b/fs/btrfs/extent_io.c index 5ae0bff..0d1196d 100644 --- a/fs/btrfs/extent_io.c +++ b/fs/btrfs/extent_io.c @@ -2681,7 +2681,7 @@ int extent_readpages(struct extent_io_tree *tree, prefetchw(&page->flags); list_del(&page->lru); if (!add_to_page_cache_lru(page, mapping, - page->index, GFP_KERNEL)) { + page->index, GFP_NOFS)) { __extent_read_full_page(tree, page, get_extent, &bio, 0, &bio_flags); } -- cgit v0.10.2 From 8d413713ca744fa00cf4e05d4054d80727b84789 Mon Sep 17 00:00:00 2001 From: Tsutomu Itoh Date: Mon, 25 Apr 2011 19:43:52 -0400 Subject: Btrfs: check return value of kmalloc() The check on the return value of kmalloc() is added to some places. Signed-off-by: Tsutomu Itoh Signed-off-by: Chris Mason diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c index 31f33ba..cd52f7f 100644 --- a/fs/btrfs/extent-tree.c +++ b/fs/btrfs/extent-tree.c @@ -8059,6 +8059,10 @@ static noinline int relocate_one_extent(struct btrfs_root *extent_root, u64 group_start = group->key.objectid; new_extents = kmalloc(sizeof(*new_extents), GFP_NOFS); + if (!new_extents) { + ret = -ENOMEM; + goto out; + } nr_extents = 1; ret = get_new_locations(reloc_inode, extent_key, diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c index a4157cf..c718d27 100644 --- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c @@ -953,6 +953,7 @@ static int cow_file_range_async(struct inode *inode, struct page *locked_page, 1, 0, NULL, GFP_NOFS); while (start < end) { async_cow = kmalloc(sizeof(*async_cow), GFP_NOFS); + BUG_ON(!async_cow); async_cow->inode = inode; async_cow->root = root; async_cow->locked_page = locked_page; @@ -5001,6 +5002,8 @@ static noinline int uncompress_inline(struct btrfs_path *path, inline_size = btrfs_file_extent_inline_item_len(leaf, btrfs_item_nr(leaf, path->slots[0])); tmp = kmalloc(inline_size, GFP_NOFS); + if (!tmp) + return -ENOMEM; ptr = btrfs_file_extent_inline_start(item); read_extent_buffer(leaf, tmp, ptr, inline_size); -- cgit v0.10.2 From cfece4db110dacfd6b4b87b912c59e77e6846fc0 Mon Sep 17 00:00:00 2001 From: David Sterba Date: Mon, 25 Apr 2011 19:43:52 -0400 Subject: btrfs: add missing spin_unlock to a rare exit path Signed-off-by: David Sterba Signed-off-by: Chris Mason diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c index ef6865c..fe5aec9 100644 --- a/fs/btrfs/disk-io.c +++ b/fs/btrfs/disk-io.c @@ -2903,6 +2903,7 @@ static int btrfs_destroy_delayed_refs(struct btrfs_transaction *trans, spin_lock(&delayed_refs->lock); if (delayed_refs->num_entries == 0) { + spin_unlock(&delayed_refs->lock); printk(KERN_INFO "delayed_refs has NO entry\n"); return ret; } -- cgit v0.10.2 From f789b684bdb96e7ec2fce79445555d4fd55fb94c Mon Sep 17 00:00:00 2001 From: Li Zefan Date: Mon, 25 Apr 2011 19:43:52 -0400 Subject: Btrfs: Free free_space item properly in btrfs_trim_block_group() Since commit dc89e9824464e91fa0b06267864ceabe3186fd8b, we've changed to use a specific slab for alocation of free_space items. Signed-off-by: Li Zefan Signed-off-by: Chris Mason diff --git a/fs/btrfs/free-space-cache.c b/fs/btrfs/free-space-cache.c index 11d2e9c..13c29b1 100644 --- a/fs/btrfs/free-space-cache.c +++ b/fs/btrfs/free-space-cache.c @@ -2301,7 +2301,7 @@ int btrfs_trim_block_group(struct btrfs_block_group_cache *block_group, start = entry->offset; bytes = min(entry->bytes, end - start); unlink_free_space(block_group, entry); - kfree(entry); + kmem_cache_free(btrfs_free_space_cachep, entry); } spin_unlock(&block_group->tree_lock); -- cgit v0.10.2 From a4f0162fd4490daf2c823c185fff79080d266a7c Mon Sep 17 00:00:00 2001 From: Josef Bacik Date: Mon, 25 Apr 2011 19:43:52 -0400 Subject: Btrfs: free bitmaps properly when evicting the cache If our space cache is wrong, we do the right thing and free up everything that we loaded, however we don't reset the total_bitmaps counter or the thresholds or anything. So in btrfs_remove_free_space_cache make sure to call free_bitmap() if it's a bitmap, this will keep us from panicing when we check to make sure we don't have too many bitmaps. Thanks, Signed-off-by: Josef Bacik Signed-off-by: Chris Mason diff --git a/fs/btrfs/free-space-cache.c b/fs/btrfs/free-space-cache.c index 13c29b1..63731a1 100644 --- a/fs/btrfs/free-space-cache.c +++ b/fs/btrfs/free-space-cache.c @@ -1768,10 +1768,13 @@ void btrfs_remove_free_space_cache(struct btrfs_block_group_cache *block_group) while ((node = rb_last(&block_group->free_space_offset)) != NULL) { info = rb_entry(node, struct btrfs_free_space, offset_index); - unlink_free_space(block_group, info); - if (info->bitmap) - kfree(info->bitmap); - kmem_cache_free(btrfs_free_space_cachep, info); + if (!info->bitmap) { + unlink_free_space(block_group, info); + kmem_cache_free(btrfs_free_space_cachep, info); + } else { + free_bitmap(block_group, info); + } + if (need_resched()) { spin_unlock(&block_group->tree_lock); cond_resched(); -- cgit v0.10.2 From 64728bbbf892ea7a4aba502c436afbe362217fb9 Mon Sep 17 00:00:00 2001 From: Josef Bacik Date: Mon, 25 Apr 2011 19:43:52 -0400 Subject: Btrfs: put the right bio if we have an error In btrfs_submit_direct_hook if the first btrfs_map_block fails we need to put the orig_bio, not bio. Signed-off-by: Josef Bacik Signed-off-by: Chris Mason diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c index c718d27..ad6b515 100644 --- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c @@ -6041,7 +6041,7 @@ static int btrfs_submit_direct_hook(int rw, struct btrfs_dio_private *dip, ret = btrfs_map_block(map_tree, READ, start_sector << 9, &map_length, NULL, 0); if (ret) { - bio_put(bio); + bio_put(orig_bio); return -EIO; } -- cgit v0.10.2 From 7cf96da3ec7ca225acf4f284b0e904a1f5f98821 Mon Sep 17 00:00:00 2001 From: Tsutomu Itoh Date: Mon, 25 Apr 2011 19:43:53 -0400 Subject: Btrfs: cleanup error handling in inode.c The error processing of several places is changed like setting the error number only at the error. Signed-off-by: Tsutomu Itoh Signed-off-by: Chris Mason diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c index ad6b515..870869a 100644 --- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c @@ -4731,9 +4731,10 @@ static int btrfs_mknod(struct inode *dir, struct dentry *dentry, inode = btrfs_new_inode(trans, root, dir, dentry->d_name.name, dentry->d_name.len, dir->i_ino, objectid, BTRFS_I(dir)->block_group, mode, &index); - err = PTR_ERR(inode); - if (IS_ERR(inode)) + if (IS_ERR(inode)) { + err = PTR_ERR(inode); goto out_unlock; + } err = btrfs_init_inode_security(trans, inode, dir); if (err) { @@ -4792,9 +4793,10 @@ static int btrfs_create(struct inode *dir, struct dentry *dentry, inode = btrfs_new_inode(trans, root, dir, dentry->d_name.name, dentry->d_name.len, dir->i_ino, objectid, BTRFS_I(dir)->block_group, mode, &index); - err = PTR_ERR(inode); - if (IS_ERR(inode)) + if (IS_ERR(inode)) { + err = PTR_ERR(inode); goto out_unlock; + } err = btrfs_init_inode_security(trans, inode, dir); if (err) { @@ -7278,9 +7280,10 @@ static int btrfs_symlink(struct inode *dir, struct dentry *dentry, dentry->d_name.len, dir->i_ino, objectid, BTRFS_I(dir)->block_group, S_IFLNK|S_IRWXUGO, &index); - err = PTR_ERR(inode); - if (IS_ERR(inode)) + if (IS_ERR(inode)) { + err = PTR_ERR(inode); goto out_unlock; + } err = btrfs_init_inode_security(trans, inode, dir); if (err) { -- cgit v0.10.2 From 3aeb86ea4cd15f728147a3bd5469a205ada8c767 Mon Sep 17 00:00:00 2001 From: Tyler Hicks Date: Tue, 15 Mar 2011 14:54:00 -0500 Subject: eCryptfs: Handle failed metadata read in lookup When failing to read the lower file's crypto metadata during a lookup, eCryptfs must continue on without throwing an error. For example, there may be a plaintext file in the lower mount point that the user wants to delete through the eCryptfs mount. If an error is encountered while reading the metadata in lookup(), the eCryptfs inode's size could be incorrect. We must be sure to reread the plaintext inode size from the metadata when performing an open() or setattr(). The metadata is already being read in those paths, so this adds minimal performance overhead. This patch introduces a flag which will track whether or not the plaintext inode size has been read so that an incorrect i_size can be fixed in the open() or setattr() paths. https://bugs.launchpad.net/bugs/509180 Cc: Signed-off-by: Tyler Hicks diff --git a/fs/ecryptfs/crypto.c b/fs/ecryptfs/crypto.c index d2a70a4..b8d5c80 100644 --- a/fs/ecryptfs/crypto.c +++ b/fs/ecryptfs/crypto.c @@ -1452,6 +1452,25 @@ static void set_default_header_data(struct ecryptfs_crypt_stat *crypt_stat) crypt_stat->metadata_size = ECRYPTFS_MINIMUM_HEADER_EXTENT_SIZE; } +void ecryptfs_i_size_init(const char *page_virt, struct inode *inode) +{ + struct ecryptfs_mount_crypt_stat *mount_crypt_stat; + struct ecryptfs_crypt_stat *crypt_stat; + u64 file_size; + + crypt_stat = &ecryptfs_inode_to_private(inode)->crypt_stat; + mount_crypt_stat = + &ecryptfs_superblock_to_private(inode->i_sb)->mount_crypt_stat; + if (mount_crypt_stat->flags & ECRYPTFS_ENCRYPTED_VIEW_ENABLED) { + file_size = i_size_read(ecryptfs_inode_to_lower(inode)); + if (crypt_stat->flags & ECRYPTFS_METADATA_IN_XATTR) + file_size += crypt_stat->metadata_size; + } else + file_size = get_unaligned_be64(page_virt); + i_size_write(inode, (loff_t)file_size); + crypt_stat->flags |= ECRYPTFS_I_SIZE_INITIALIZED; +} + /** * ecryptfs_read_headers_virt * @page_virt: The virtual address into which to read the headers @@ -1482,6 +1501,8 @@ static int ecryptfs_read_headers_virt(char *page_virt, rc = -EINVAL; goto out; } + if (!(crypt_stat->flags & ECRYPTFS_I_SIZE_INITIALIZED)) + ecryptfs_i_size_init(page_virt, ecryptfs_dentry->d_inode); offset += MAGIC_ECRYPTFS_MARKER_SIZE_BYTES; rc = ecryptfs_process_flags(crypt_stat, (page_virt + offset), &bytes_read); diff --git a/fs/ecryptfs/ecryptfs_kernel.h b/fs/ecryptfs/ecryptfs_kernel.h index 380bee1..e702827 100644 --- a/fs/ecryptfs/ecryptfs_kernel.h +++ b/fs/ecryptfs/ecryptfs_kernel.h @@ -269,6 +269,7 @@ struct ecryptfs_crypt_stat { #define ECRYPTFS_ENCFN_USE_MOUNT_FNEK 0x00000800 #define ECRYPTFS_ENCFN_USE_FEK 0x00001000 #define ECRYPTFS_UNLINK_SIGS 0x00002000 +#define ECRYPTFS_I_SIZE_INITIALIZED 0x00004000 u32 flags; unsigned int file_version; size_t iv_bytes; @@ -628,6 +629,7 @@ struct ecryptfs_open_req { int ecryptfs_interpose(struct dentry *hidden_dentry, struct dentry *this_dentry, struct super_block *sb, u32 flags); +void ecryptfs_i_size_init(const char *page_virt, struct inode *inode); int ecryptfs_lookup_and_interpose_lower(struct dentry *ecryptfs_dentry, struct dentry *lower_dentry, struct inode *ecryptfs_dir_inode); diff --git a/fs/ecryptfs/file.c b/fs/ecryptfs/file.c index 146c4ed..566e547 100644 --- a/fs/ecryptfs/file.c +++ b/fs/ecryptfs/file.c @@ -235,7 +235,8 @@ static int ecryptfs_open(struct inode *inode, struct file *file) goto out_put; } rc = 0; - crypt_stat->flags &= ~(ECRYPTFS_ENCRYPTED); + crypt_stat->flags &= ~(ECRYPTFS_I_SIZE_INITIALIZED + | ECRYPTFS_ENCRYPTED); mutex_unlock(&crypt_stat->cs_mutex); goto out; } diff --git a/fs/ecryptfs/inode.c b/fs/ecryptfs/inode.c index f6b3886..2c19d36 100644 --- a/fs/ecryptfs/inode.c +++ b/fs/ecryptfs/inode.c @@ -225,10 +225,8 @@ int ecryptfs_lookup_and_interpose_lower(struct dentry *ecryptfs_dentry, struct dentry *lower_dir_dentry; struct vfsmount *lower_mnt; struct inode *lower_inode; - struct ecryptfs_mount_crypt_stat *mount_crypt_stat; struct ecryptfs_crypt_stat *crypt_stat; char *page_virt = NULL; - u64 file_size; int put_lower = 0, rc = 0; lower_dir_dentry = lower_dentry->d_parent; @@ -302,18 +300,7 @@ int ecryptfs_lookup_and_interpose_lower(struct dentry *ecryptfs_dentry, } crypt_stat->flags |= ECRYPTFS_METADATA_IN_XATTR; } - mount_crypt_stat = &ecryptfs_superblock_to_private( - ecryptfs_dentry->d_sb)->mount_crypt_stat; - if (mount_crypt_stat->flags & ECRYPTFS_ENCRYPTED_VIEW_ENABLED) { - if (crypt_stat->flags & ECRYPTFS_METADATA_IN_XATTR) - file_size = (crypt_stat->metadata_size - + i_size_read(lower_dentry->d_inode)); - else - file_size = i_size_read(lower_dentry->d_inode); - } else { - file_size = get_unaligned_be64(page_virt); - } - i_size_write(ecryptfs_dentry->d_inode, (loff_t)file_size); + ecryptfs_i_size_init(page_virt, ecryptfs_dentry->d_inode); out_free_kmem: kmem_cache_free(ecryptfs_header_cache_2, page_virt); goto out; @@ -937,7 +924,8 @@ static int ecryptfs_setattr(struct dentry *dentry, struct iattr *ia) goto out; } rc = 0; - crypt_stat->flags &= ~(ECRYPTFS_ENCRYPTED); + crypt_stat->flags &= ~(ECRYPTFS_I_SIZE_INITIALIZED + | ECRYPTFS_ENCRYPTED); } } mutex_unlock(&crypt_stat->cs_mutex); -- cgit v0.10.2 From 5be79de2e1ffa19d871a494697cf76cddee93384 Mon Sep 17 00:00:00 2001 From: Tyler Hicks Date: Fri, 22 Apr 2011 13:08:00 -0500 Subject: eCryptfs: Flush dirty pages in setattr After 57db4e8d73ef2b5e94a3f412108dff2576670a8a changed eCryptfs to write-back caching, eCryptfs page writeback updates the lower inode times due to the use of vfs_write() on the lower file. To preserve inode metadata changes, such as 'cp -p' does with utimensat(), we need to flush all dirty pages early in ecryptfs_setattr() so that the user-updated lower inode metadata isn't clobbered later in writeback. https://bugzilla.kernel.org/show_bug.cgi?id=33372 Reported-by: Rocko Signed-off-by: Tyler Hicks diff --git a/fs/ecryptfs/inode.c b/fs/ecryptfs/inode.c index 2c19d36..4d4cc6a 100644 --- a/fs/ecryptfs/inode.c +++ b/fs/ecryptfs/inode.c @@ -929,6 +929,12 @@ static int ecryptfs_setattr(struct dentry *dentry, struct iattr *ia) } } mutex_unlock(&crypt_stat->cs_mutex); + if (S_ISREG(inode->i_mode)) { + rc = filemap_write_and_wait(inode->i_mapping); + if (rc) + goto out; + fsstack_copy_attr_all(inode, lower_inode); + } memcpy(&lower_ia, ia, sizeof(lower_ia)); if (ia->ia_valid & ATTR_FILE) lower_ia.ia_file = ecryptfs_file_to_lower(ia->ia_file); -- cgit v0.10.2 From 97232fd666f27d1a1cc560adaac446b0bb57f578 Mon Sep 17 00:00:00 2001 From: Jeff Mahoney Date: Tue, 12 Apr 2011 14:55:11 -0400 Subject: staging: olpc: Add The olpc dcon xo1 driver uses udelay() without including . This patch adds it. Signed-off-by: Jeff Mahoney Signed-off-by: Randy Dunlap Cc: Andres Salomon Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/staging/olpc_dcon/olpc_dcon_xo_1.c b/drivers/staging/olpc_dcon/olpc_dcon_xo_1.c index b5d21f6..22c04ea 100644 --- a/drivers/staging/olpc_dcon/olpc_dcon_xo_1.c +++ b/drivers/staging/olpc_dcon/olpc_dcon_xo_1.c @@ -12,6 +12,7 @@ */ #include #include +#include #include #include "olpc_dcon.h" -- cgit v0.10.2 From 4f80494daa1f9705c3717a02e7d713ea2f874bd0 Mon Sep 17 00:00:00 2001 From: Jeff Mahoney Date: Tue, 12 Apr 2011 15:32:36 -0400 Subject: staging: gma500: Depend on X86 The gma500 driver calls set_pages_uc, which is an x86 pageattr call. Since this driver is only used with Intel x86 motherboard chipsets, make the driver depend on X86. Signed-off-by: Jeff Mahoney Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/staging/gma500/Kconfig b/drivers/staging/gma500/Kconfig index 5501eb9..ce8beda 100644 --- a/drivers/staging/gma500/Kconfig +++ b/drivers/staging/gma500/Kconfig @@ -1,6 +1,6 @@ config DRM_PSB tristate "Intel GMA500 KMS Framebuffer" - depends on DRM && PCI + depends on DRM && PCI && X86 select FB_CFB_COPYAREA select FB_CFB_FILLRECT select FB_CFB_IMAGEBLIT -- cgit v0.10.2 From c6cdaded146875e2e47e946f6592c1775eaee849 Mon Sep 17 00:00:00 2001 From: Jeff Mahoney Date: Tue, 12 Apr 2011 21:05:07 -0400 Subject: staging: rts_pstor: Add There are a few files in the rts_pstor driver that use vmalloc/vfree without including the header for it. This patch adds to those files. Signed-off-by: Jeff Mahoney Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/staging/rts_pstor/ms.c b/drivers/staging/rts_pstor/ms.c index 810e170..d89795c 100644 --- a/drivers/staging/rts_pstor/ms.c +++ b/drivers/staging/rts_pstor/ms.c @@ -23,6 +23,7 @@ #include #include #include +#include #include "rtsx.h" #include "rtsx_transport.h" diff --git a/drivers/staging/rts_pstor/rtsx_chip.c b/drivers/staging/rts_pstor/rtsx_chip.c index d2f1c71..755be43 100644 --- a/drivers/staging/rts_pstor/rtsx_chip.c +++ b/drivers/staging/rts_pstor/rtsx_chip.c @@ -24,6 +24,7 @@ #include #include #include +#include #include "rtsx.h" #include "rtsx_transport.h" diff --git a/drivers/staging/rts_pstor/rtsx_scsi.c b/drivers/staging/rts_pstor/rtsx_scsi.c index 20c2464..7de1fae 100644 --- a/drivers/staging/rts_pstor/rtsx_scsi.c +++ b/drivers/staging/rts_pstor/rtsx_scsi.c @@ -23,6 +23,7 @@ #include #include #include +#include #include "rtsx.h" #include "rtsx_transport.h" diff --git a/drivers/staging/rts_pstor/xd.c b/drivers/staging/rts_pstor/xd.c index 7bcd468..9f3add1 100644 --- a/drivers/staging/rts_pstor/xd.c +++ b/drivers/staging/rts_pstor/xd.c @@ -23,6 +23,7 @@ #include #include #include +#include #include "rtsx.h" #include "rtsx_transport.h" -- cgit v0.10.2 From 1035117d2a47583f9539c28bf6ce5f677946e172 Mon Sep 17 00:00:00 2001 From: Jeff Mahoney Date: Tue, 12 Apr 2011 21:05:33 -0400 Subject: staging: rts_pstor: use #ifdef instead of #if This patch fixes a number of the following warnings: warning: "CONFIG_RTS_PSTOR_DEBUG" is not defined The code uses '#if CONFIG_RTS_PSTOR_DEBUG' when it should be using '#ifdef' Signed-off-by: Jeff Mahoney Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/staging/rts_pstor/debug.h b/drivers/staging/rts_pstor/debug.h index e1408b0..ab305be 100644 --- a/drivers/staging/rts_pstor/debug.h +++ b/drivers/staging/rts_pstor/debug.h @@ -28,7 +28,7 @@ #define RTSX_STOR "rts_pstor: " -#if CONFIG_RTS_PSTOR_DEBUG +#ifdef CONFIG_RTS_PSTOR_DEBUG #define RTSX_DEBUGP(x...) printk(KERN_DEBUG RTSX_STOR x) #define RTSX_DEBUGPN(x...) printk(KERN_DEBUG x) #define RTSX_DEBUGPX(x...) printk(x) diff --git a/drivers/staging/rts_pstor/rtsx_chip.c b/drivers/staging/rts_pstor/rtsx_chip.c index 755be43..4e60780 100644 --- a/drivers/staging/rts_pstor/rtsx_chip.c +++ b/drivers/staging/rts_pstor/rtsx_chip.c @@ -1312,11 +1312,11 @@ void rtsx_polling_func(struct rtsx_chip *chip) #ifdef SUPPORT_OCP if (CHECK_LUN_MODE(chip, SD_MS_2LUN)) { - #if CONFIG_RTS_PSTOR_DEBUG +#ifdef CONFIG_RTS_PSTOR_DEBUG if (chip->ocp_stat & (SD_OC_NOW | SD_OC_EVER | MS_OC_NOW | MS_OC_EVER)) { RTSX_DEBUGP("Over current, OCPSTAT is 0x%x\n", chip->ocp_stat); } - #endif +#endif if (chip->ocp_stat & (SD_OC_NOW | SD_OC_EVER)) { if (chip->card_exist & SD_CARD) { diff --git a/drivers/staging/rts_pstor/sd.c b/drivers/staging/rts_pstor/sd.c index 8d066bd..b1277a6 100644 --- a/drivers/staging/rts_pstor/sd.c +++ b/drivers/staging/rts_pstor/sd.c @@ -909,7 +909,7 @@ static int sd_change_phase(struct rtsx_chip *chip, u8 sample_point, u8 tune_dir) RTSX_WRITE_REG(chip, SD_VPCLK0_CTL, PHASE_NOT_RESET, PHASE_NOT_RESET); RTSX_WRITE_REG(chip, CLK_CTL, CHANGE_CLK, 0); } else { -#if CONFIG_RTS_PSTOR_DEBUG +#ifdef CONFIG_RTS_PSTOR_DEBUG rtsx_read_register(chip, SD_VP_CTL, &val); RTSX_DEBUGP("SD_VP_CTL: 0x%x\n", val); rtsx_read_register(chip, SD_DCMPS_CTL, &val); @@ -958,7 +958,7 @@ static int sd_change_phase(struct rtsx_chip *chip, u8 sample_point, u8 tune_dir) return STATUS_SUCCESS; Fail: -#if CONFIG_RTS_PSTOR_DEBUG +#ifdef CONFIG_RTS_PSTOR_DEBUG rtsx_read_register(chip, SD_VP_CTL, &val); RTSX_DEBUGP("SD_VP_CTL: 0x%x\n", val); rtsx_read_register(chip, SD_DCMPS_CTL, &val); diff --git a/drivers/staging/rts_pstor/trace.h b/drivers/staging/rts_pstor/trace.h index 2c668ba..bc83b49 100644 --- a/drivers/staging/rts_pstor/trace.h +++ b/drivers/staging/rts_pstor/trace.h @@ -82,7 +82,7 @@ do { \ #define TRACE_GOTO(chip, label) goto label #endif -#if CONFIG_RTS_PSTOR_DEBUG +#ifdef CONFIG_RTS_PSTOR_DEBUG static inline void rtsx_dump(u8 *buf, int buf_len) { int i; -- cgit v0.10.2 From 9f908a9eaa94f07265811c59b740a4608d3dfc96 Mon Sep 17 00:00:00 2001 From: Jeff Mahoney Date: Tue, 12 Apr 2011 22:57:57 -0400 Subject: staging: ft1000: Remove unnecessary EXPORT_SYMBOLs ft1000-pcmcia uses EXPORT_SYMBOL unnecessarily for sharing symbols inside the same module. For some reason, this is causing section conflicts on ia64 as well, even though neither are static. error: __ksymtab_stop_ft1000_card causes a section type conflict error: __ksymtab_init_ft1000_card causes a section type conflict Signed-off-by: Jeff Mahoney Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/staging/ft1000/ft1000-pcmcia/ft1000_hw.c b/drivers/staging/ft1000/ft1000-pcmcia/ft1000_hw.c index eeb7dd4..830822f 100644 --- a/drivers/staging/ft1000/ft1000-pcmcia/ft1000_hw.c +++ b/drivers/staging/ft1000/ft1000-pcmcia/ft1000_hw.c @@ -2288,7 +2288,3 @@ err_dev: free_netdev(dev); return NULL; } - -EXPORT_SYMBOL(init_ft1000_card); -EXPORT_SYMBOL(stop_ft1000_card); -EXPORT_SYMBOL(flarion_ft1000_cnt); diff --git a/drivers/staging/ft1000/ft1000-pcmcia/ft1000_proc.c b/drivers/staging/ft1000/ft1000-pcmcia/ft1000_proc.c index 935608e..bdfb1ae 100644 --- a/drivers/staging/ft1000/ft1000-pcmcia/ft1000_proc.c +++ b/drivers/staging/ft1000/ft1000-pcmcia/ft1000_proc.c @@ -214,6 +214,3 @@ void ft1000CleanupProc(struct net_device *dev) remove_proc_entry(FT1000_PROC, init_net.proc_net); unregister_netdevice_notifier(&ft1000_netdev_notifier); } - -EXPORT_SYMBOL(ft1000InitProc); -EXPORT_SYMBOL(ft1000CleanupProc); -- cgit v0.10.2 From d1b2e95ab016a0c5b01748986f6ce42e9d11cab2 Mon Sep 17 00:00:00 2001 From: Max Vozeler Date: Mon, 18 Apr 2011 21:44:10 +0200 Subject: staging: usbip: vhci: fix oops on subsequent attach vhci_rx/vhci_tx threads are created once but stopped each time the vdev is shut down. On subsequent attach wake_up_process() oopses trying to access the stopped threads. This patch does as before the kthread conversion which is to create the threads each time a device is attached and stop the threads when the device is shut down. Signed-off-by: Max Vozeler Cc: Arnd Bergmann Cc: Takahiro Hirofuchi Cc: Arjan Mels Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/staging/usbip/vhci_hcd.c b/drivers/staging/usbip/vhci_hcd.c index 0f02a4b..14caae2 100644 --- a/drivers/staging/usbip/vhci_hcd.c +++ b/drivers/staging/usbip/vhci_hcd.c @@ -876,8 +876,10 @@ static void vhci_shutdown_connection(struct usbip_device *ud) } /* kill threads related to this sdev, if v.c. exists */ - kthread_stop(vdev->ud.tcp_rx); - kthread_stop(vdev->ud.tcp_tx); + if (vdev->ud.tcp_rx) + kthread_stop(vdev->ud.tcp_rx); + if (vdev->ud.tcp_tx) + kthread_stop(vdev->ud.tcp_tx); usbip_uinfo("stop threads\n"); @@ -949,9 +951,6 @@ static void vhci_device_init(struct vhci_device *vdev) { memset(vdev, 0, sizeof(*vdev)); - vdev->ud.tcp_rx = kthread_create(vhci_rx_loop, &vdev->ud, "vhci_rx"); - vdev->ud.tcp_tx = kthread_create(vhci_tx_loop, &vdev->ud, "vhci_tx"); - vdev->ud.side = USBIP_VHCI; vdev->ud.status = VDEV_ST_NULL; /* vdev->ud.lock = SPIN_LOCK_UNLOCKED; */ diff --git a/drivers/staging/usbip/vhci_sysfs.c b/drivers/staging/usbip/vhci_sysfs.c index 3f2459f..e2dadbd 100644 --- a/drivers/staging/usbip/vhci_sysfs.c +++ b/drivers/staging/usbip/vhci_sysfs.c @@ -21,6 +21,7 @@ #include "vhci.h" #include +#include /* TODO: refine locking ?*/ @@ -220,13 +221,13 @@ static ssize_t store_attach(struct device *dev, struct device_attribute *attr, vdev->ud.tcp_socket = socket; vdev->ud.status = VDEV_ST_NOTASSIGNED; - wake_up_process(vdev->ud.tcp_rx); - wake_up_process(vdev->ud.tcp_tx); - spin_unlock(&vdev->ud.lock); spin_unlock(&the_controller->lock); /* end the lock */ + vdev->ud.tcp_rx = kthread_run(vhci_rx_loop, &vdev->ud, "vhci_rx"); + vdev->ud.tcp_tx = kthread_run(vhci_tx_loop, &vdev->ud, "vhci_tx"); + rh_port_connect(rhport, speed); return count; -- cgit v0.10.2 From 95c2b71b7b7422749950e3d497a894957d724b16 Mon Sep 17 00:00:00 2001 From: Peter Foley Date: Sun, 24 Apr 2011 17:15:09 -0400 Subject: staging: solo6x10: add select SND_PCM to fix build error This patch fixes a build error when SND_PCM is not set by adding a select statment. Signed-off-by: Peter Foley Acked-By: Ben Collins Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/staging/solo6x10/Kconfig b/drivers/staging/solo6x10/Kconfig index 2cf77c9..03dcac4 100644 --- a/drivers/staging/solo6x10/Kconfig +++ b/drivers/staging/solo6x10/Kconfig @@ -2,6 +2,7 @@ config SOLO6X10 tristate "Softlogic 6x10 MPEG codec cards" depends on PCI && VIDEO_DEV && SND && I2C select VIDEOBUF_DMA_SG + select SND_PCM ---help--- This driver supports the Softlogic based MPEG-4 and h.264 codec codec cards. -- cgit v0.10.2 From b27b8ea853c4c1c1d5d95448cf69b3f10a9558d4 Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Tue, 19 Apr 2011 11:26:35 -0700 Subject: staging: intel_sst: intelmid needs delay.h intel_sst drivers need to #include so that they build cleanly: drivers/staging/intel_sst/intelmid_v1_control.c:188: error: implicit declaration of function 'msleep' drivers/staging/intel_sst/intelmid_v2_control.c:172: error: implicit declaration of function 'msleep' Signed-off-by: Randy Dunlap Cc: Vinod Koul Cc: Harsha Priya Cc: KP Jeeja Cc: Dharageswari R Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/staging/intel_sst/intelmid_v1_control.c b/drivers/staging/intel_sst/intelmid_v1_control.c index 9cc15c1..1ea8142 100644 --- a/drivers/staging/intel_sst/intelmid_v1_control.c +++ b/drivers/staging/intel_sst/intelmid_v1_control.c @@ -28,6 +28,7 @@ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt #include +#include #include #include #include diff --git a/drivers/staging/intel_sst/intelmid_v2_control.c b/drivers/staging/intel_sst/intelmid_v2_control.c index 26d815a6..3c6b3ab 100644 --- a/drivers/staging/intel_sst/intelmid_v2_control.c +++ b/drivers/staging/intel_sst/intelmid_v2_control.c @@ -29,6 +29,7 @@ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt #include +#include #include #include "intel_sst.h" #include "intelmid_snd_control.h" -- cgit v0.10.2 From 3dd2ee4824b668a635d6d2bb6bc73f33708cab9f Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Mon, 25 Apr 2011 18:10:58 -0700 Subject: bit_spinlock: don't play preemption games inside the busy loop When we are waiting for the bit-lock to be released, and are looping over the 'cpu_relax()' should not be doing anything else - otherwise we miss the point of trying to do the whole 'cpu_relax()'. Do the preemption enable/disable around the loop, rather than inside of it. Noticed when I was looking at the code generation for the dcache __d_drop usage, and the code just looked very odd. Signed-off-by: Linus Torvalds diff --git a/include/linux/bit_spinlock.h b/include/linux/bit_spinlock.h index e612575..b4326bf 100644 --- a/include/linux/bit_spinlock.h +++ b/include/linux/bit_spinlock.h @@ -23,11 +23,11 @@ static inline void bit_spin_lock(int bitnum, unsigned long *addr) preempt_disable(); #if defined(CONFIG_SMP) || defined(CONFIG_DEBUG_SPINLOCK) while (unlikely(test_and_set_bit_lock(bitnum, addr))) { - while (test_bit(bitnum, addr)) { - preempt_enable(); + preempt_enable(); + do { cpu_relax(); - preempt_disable(); - } + } while (test_bit(bitnum, addr)); + preempt_disable(); } #endif __acquire(bitlock); -- cgit v0.10.2 From 1879fd6a26571fd4e8e1f4bb3e7537bc936b1fe7 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Mon, 25 Apr 2011 14:01:36 -0400 Subject: add hlist_bl_lock/unlock helpers Now that the whole dcache_hash_bucket crap is gone, go all the way and also remove the weird locking layering violations for locking the hash buckets. Add hlist_bl_lock/unlock helpers to move the locking into the list abstraction instead of requiring each caller to open code it. After all allowing for the bit locks is the whole point of these helpers over the plain hlist variant. Signed-off-by: Christoph Hellwig Signed-off-by: Linus Torvalds diff --git a/fs/dcache.c b/fs/dcache.c index d600a0a..22a0ef4 100644 --- a/fs/dcache.c +++ b/fs/dcache.c @@ -109,16 +109,6 @@ static inline struct hlist_bl_head *d_hash(struct dentry *parent, return dentry_hashtable + (hash & D_HASHMASK); } -static inline void spin_lock_bucket(struct hlist_bl_head *b) -{ - bit_spin_lock(0, (unsigned long *)&b->first); -} - -static inline void spin_unlock_bucket(struct hlist_bl_head *b) -{ - __bit_spin_unlock(0, (unsigned long *)&b->first); -} - /* Statistics gathering. */ struct dentry_stat_t dentry_stat = { .age_limit = 45, @@ -334,10 +324,10 @@ void __d_drop(struct dentry *dentry) else b = d_hash(dentry->d_parent, dentry->d_name.hash); - spin_lock_bucket(b); + hlist_bl_lock(b); __hlist_bl_del(&dentry->d_hash); dentry->d_hash.pprev = NULL; - spin_unlock_bucket(b); + hlist_bl_unlock(b); dentry_rcuwalk_barrier(dentry); } @@ -1594,9 +1584,9 @@ struct dentry *d_obtain_alias(struct inode *inode) tmp->d_inode = inode; tmp->d_flags |= DCACHE_DISCONNECTED; list_add(&tmp->d_alias, &inode->i_dentry); - spin_lock_bucket(&tmp->d_sb->s_anon); + hlist_bl_lock(&tmp->d_sb->s_anon); hlist_bl_add_head(&tmp->d_hash, &tmp->d_sb->s_anon); - spin_unlock_bucket(&tmp->d_sb->s_anon); + hlist_bl_unlock(&tmp->d_sb->s_anon); spin_unlock(&tmp->d_lock); spin_unlock(&inode->i_lock); security_d_instantiate(tmp, inode); @@ -2076,10 +2066,10 @@ EXPORT_SYMBOL(d_delete); static void __d_rehash(struct dentry * entry, struct hlist_bl_head *b) { BUG_ON(!d_unhashed(entry)); - spin_lock_bucket(b); + hlist_bl_lock(b); entry->d_flags |= DCACHE_RCUACCESS; hlist_bl_add_head_rcu(&entry->d_hash, b); - spin_unlock_bucket(b); + hlist_bl_unlock(b); } static void _d_rehash(struct dentry * entry) diff --git a/fs/gfs2/glock.c b/fs/gfs2/glock.c index f07643e..7a4fb63 100644 --- a/fs/gfs2/glock.c +++ b/fs/gfs2/glock.c @@ -93,14 +93,12 @@ static unsigned int gl_hash(const struct gfs2_sbd *sdp, static inline void spin_lock_bucket(unsigned int hash) { - struct hlist_bl_head *bl = &gl_hash_table[hash]; - bit_spin_lock(0, (unsigned long *)bl); + hlist_bl_lock(&gl_hash_table[hash]); } static inline void spin_unlock_bucket(unsigned int hash) { - struct hlist_bl_head *bl = &gl_hash_table[hash]; - __bit_spin_unlock(0, (unsigned long *)bl); + hlist_bl_unlock(&gl_hash_table[hash]); } static void gfs2_glock_dealloc(struct rcu_head *rcu) diff --git a/include/linux/list_bl.h b/include/linux/list_bl.h index 5bad17d1..31f9d75 100644 --- a/include/linux/list_bl.h +++ b/include/linux/list_bl.h @@ -2,6 +2,7 @@ #define _LINUX_LIST_BL_H #include +#include /* * Special version of lists, where head of the list has a lock in the lowest @@ -114,6 +115,16 @@ static inline void hlist_bl_del_init(struct hlist_bl_node *n) } } +static inline void hlist_bl_lock(struct hlist_bl_head *b) +{ + bit_spin_lock(0, (unsigned long *)b); +} + +static inline void hlist_bl_unlock(struct hlist_bl_head *b) +{ + __bit_spin_unlock(0, (unsigned long *)b); +} + /** * hlist_bl_for_each_entry - iterate over list of given type * @tpos: the type * to use as a loop cursor. -- cgit v0.10.2 From 9ade0cf440a1e5800dc68eef2e77b8d9d83a6dff Mon Sep 17 00:00:00 2001 From: Eric Paris Date: Mon, 25 Apr 2011 16:26:29 -0400 Subject: SELINUX: Make selinux cache VFS RCU walks safe Now that the security modules can decide whether they support the dcache RCU walk or not it's possible to make selinux a bit more RCU friendly. The SELinux AVC and security server access decision code is RCU safe. A specific piece of the LSM audit code may not be RCU safe. This patch makes the VFS RCU walk retry if it would hit the non RCU safe chunk of code. It will normally just work under RCU. This is done simply by passing the VFS RCU state as a flag down into the avc_audit() code and returning ECHILD there if it would have an issue. Based-on-patch-by: Andi Kleen Signed-off-by: Eric Paris Signed-off-by: Linus Torvalds diff --git a/security/selinux/avc.c b/security/selinux/avc.c index 9da6420..1d027e2 100644 --- a/security/selinux/avc.c +++ b/security/selinux/avc.c @@ -471,6 +471,7 @@ static void avc_audit_post_callback(struct audit_buffer *ab, void *a) * @avd: access vector decisions * @result: result from avc_has_perm_noaudit * @a: auxiliary audit data + * @flags: VFS walk flags * * Audit the granting or denial of permissions in accordance * with the policy. This function is typically called by @@ -481,9 +482,10 @@ static void avc_audit_post_callback(struct audit_buffer *ab, void *a) * be performed under a lock, to allow the lock to be released * before calling the auditing code. */ -void avc_audit(u32 ssid, u32 tsid, +int avc_audit(u32 ssid, u32 tsid, u16 tclass, u32 requested, - struct av_decision *avd, int result, struct common_audit_data *a) + struct av_decision *avd, int result, struct common_audit_data *a, + unsigned flags) { struct common_audit_data stack_data; u32 denied, audited; @@ -515,11 +517,24 @@ void avc_audit(u32 ssid, u32 tsid, else audited = requested & avd->auditallow; if (!audited) - return; + return 0; + if (!a) { a = &stack_data; COMMON_AUDIT_DATA_INIT(a, NONE); } + + /* + * When in a RCU walk do the audit on the RCU retry. This is because + * the collection of the dname in an inode audit message is not RCU + * safe. Note this may drop some audits when the situation changes + * during retry. However this is logically just as if the operation + * happened a little later. + */ + if ((a->type == LSM_AUDIT_DATA_FS) && + (flags & IPERM_FLAG_RCU)) + return -ECHILD; + a->selinux_audit_data.tclass = tclass; a->selinux_audit_data.requested = requested; a->selinux_audit_data.ssid = ssid; @@ -529,6 +544,7 @@ void avc_audit(u32 ssid, u32 tsid, a->lsm_pre_audit = avc_audit_pre_callback; a->lsm_post_audit = avc_audit_post_callback; common_lsm_audit(a); + return 0; } /** @@ -793,6 +809,7 @@ int avc_has_perm_noaudit(u32 ssid, u32 tsid, * @tclass: target security class * @requested: requested permissions, interpreted based on @tclass * @auditdata: auxiliary audit data + * @flags: VFS walk flags * * Check the AVC to determine whether the @requested permissions are granted * for the SID pair (@ssid, @tsid), interpreting the permissions @@ -802,14 +819,19 @@ int avc_has_perm_noaudit(u32 ssid, u32 tsid, * permissions are granted, -%EACCES if any permissions are denied, or * another -errno upon other errors. */ -int avc_has_perm(u32 ssid, u32 tsid, u16 tclass, - u32 requested, struct common_audit_data *auditdata) +int avc_has_perm_flags(u32 ssid, u32 tsid, u16 tclass, + u32 requested, struct common_audit_data *auditdata, + unsigned flags) { struct av_decision avd; - int rc; + int rc, rc2; rc = avc_has_perm_noaudit(ssid, tsid, tclass, requested, 0, &avd); - avc_audit(ssid, tsid, tclass, requested, &avd, rc, auditdata); + + rc2 = avc_audit(ssid, tsid, tclass, requested, &avd, rc, auditdata, + flags); + if (rc2) + return rc2; return rc; } diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index a73f4e4..f7cf0ea 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c @@ -1446,8 +1446,11 @@ static int task_has_capability(struct task_struct *tsk, } rc = avc_has_perm_noaudit(sid, sid, sclass, av, 0, &avd); - if (audit == SECURITY_CAP_AUDIT) - avc_audit(sid, sid, sclass, av, &avd, rc, &ad); + if (audit == SECURITY_CAP_AUDIT) { + int rc2 = avc_audit(sid, sid, sclass, av, &avd, rc, &ad, 0); + if (rc2) + return rc2; + } return rc; } @@ -1467,7 +1470,8 @@ static int task_has_system(struct task_struct *tsk, static int inode_has_perm(const struct cred *cred, struct inode *inode, u32 perms, - struct common_audit_data *adp) + struct common_audit_data *adp, + unsigned flags) { struct inode_security_struct *isec; struct common_audit_data ad; @@ -1487,7 +1491,7 @@ static int inode_has_perm(const struct cred *cred, ad.u.fs.inode = inode; } - return avc_has_perm(sid, isec->sid, isec->sclass, perms, adp); + return avc_has_perm_flags(sid, isec->sid, isec->sclass, perms, adp, flags); } /* Same as inode_has_perm, but pass explicit audit data containing @@ -1504,7 +1508,7 @@ static inline int dentry_has_perm(const struct cred *cred, COMMON_AUDIT_DATA_INIT(&ad, FS); ad.u.fs.path.mnt = mnt; ad.u.fs.path.dentry = dentry; - return inode_has_perm(cred, inode, av, &ad); + return inode_has_perm(cred, inode, av, &ad, 0); } /* Check whether a task can use an open file descriptor to @@ -1540,7 +1544,7 @@ static int file_has_perm(const struct cred *cred, /* av is zero if only checking access to the descriptor. */ rc = 0; if (av) - rc = inode_has_perm(cred, inode, av, &ad); + rc = inode_has_perm(cred, inode, av, &ad, 0); out: return rc; @@ -2103,7 +2107,7 @@ static inline void flush_unauthorized_files(const struct cred *cred, file = file_priv->file; inode = file->f_path.dentry->d_inode; if (inode_has_perm(cred, inode, - FILE__READ | FILE__WRITE, NULL)) { + FILE__READ | FILE__WRITE, NULL, 0)) { drop_tty = 1; } } @@ -2649,10 +2653,6 @@ static int selinux_inode_permission(struct inode *inode, int mask, unsigned flag if (!mask) return 0; - /* May be droppable after audit */ - if (flags & IPERM_FLAG_RCU) - return -ECHILD; - COMMON_AUDIT_DATA_INIT(&ad, FS); ad.u.fs.inode = inode; @@ -2661,7 +2661,7 @@ static int selinux_inode_permission(struct inode *inode, int mask, unsigned flag perms = file_mask_to_av(inode->i_mode, mask); - return inode_has_perm(cred, inode, perms, &ad); + return inode_has_perm(cred, inode, perms, &ad, flags); } static int selinux_inode_setattr(struct dentry *dentry, struct iattr *iattr) @@ -3209,7 +3209,7 @@ static int selinux_dentry_open(struct file *file, const struct cred *cred) * new inode label or new policy. * This check is not redundant - do not remove. */ - return inode_has_perm(cred, inode, open_file_to_av(file), NULL); + return inode_has_perm(cred, inode, open_file_to_av(file), NULL, 0); } /* task security operations */ diff --git a/security/selinux/include/avc.h b/security/selinux/include/avc.h index 5615081..e77b2ac 100644 --- a/security/selinux/include/avc.h +++ b/security/selinux/include/avc.h @@ -54,11 +54,11 @@ struct avc_cache_stats { void __init avc_init(void); -void avc_audit(u32 ssid, u32 tsid, +int avc_audit(u32 ssid, u32 tsid, u16 tclass, u32 requested, struct av_decision *avd, int result, - struct common_audit_data *a); + struct common_audit_data *a, unsigned flags); #define AVC_STRICT 1 /* Ignore permissive mode. */ int avc_has_perm_noaudit(u32 ssid, u32 tsid, @@ -66,9 +66,17 @@ int avc_has_perm_noaudit(u32 ssid, u32 tsid, unsigned flags, struct av_decision *avd); -int avc_has_perm(u32 ssid, u32 tsid, - u16 tclass, u32 requested, - struct common_audit_data *auditdata); +int avc_has_perm_flags(u32 ssid, u32 tsid, + u16 tclass, u32 requested, + struct common_audit_data *auditdata, + unsigned); + +static inline int avc_has_perm(u32 ssid, u32 tsid, + u16 tclass, u32 requested, + struct common_audit_data *auditdata) +{ + return avc_has_perm_flags(ssid, tsid, tclass, requested, auditdata, 0); +} u32 avc_policy_seqno(void); -- cgit v0.10.2 From 455e33898e65108b379e74bcc3c9d6d2b50da9a6 Mon Sep 17 00:00:00 2001 From: Markku Kylanpaa Date: Wed, 20 Apr 2011 13:34:55 +0300 Subject: crypto: omap-sham - fix concurrent sha1 calculations SHA1 accelerator can also be busy. Add -EBUSY status return option and return busy status from omap_sham_finup(). Signed-off-by: Markku Kylanpaa Signed-off-by: Herbert Xu diff --git a/drivers/crypto/omap-sham.c b/drivers/crypto/omap-sham.c index 465cde3..e36032b 100644 --- a/drivers/crypto/omap-sham.c +++ b/drivers/crypto/omap-sham.c @@ -835,7 +835,7 @@ static int omap_sham_finup(struct ahash_request *req) ctx->flags |= FLAGS_FINUP; err1 = omap_sham_update(req); - if (err1 == -EINPROGRESS) + if (err1 == -EINPROGRESS || err1 == -EBUSY) return err1; /* * final() has to be always called to cleanup resources -- cgit v0.10.2 From 07aab762feb6b49e8004bfba2659db17f7b64e35 Mon Sep 17 00:00:00 2001 From: Dmitry Kasatkin Date: Wed, 20 Apr 2011 13:34:56 +0300 Subject: crypto: omap-sham - remove debug print Signed-off-by: Dmitry Kasatkin Signed-off-by: Herbert Xu diff --git a/drivers/crypto/omap-sham.c b/drivers/crypto/omap-sham.c index e36032b..50aca41 100644 --- a/drivers/crypto/omap-sham.c +++ b/drivers/crypto/omap-sham.c @@ -890,8 +890,6 @@ static int omap_sham_cra_init_alg(struct crypto_tfm *tfm, const char *alg_base) struct omap_sham_ctx *tctx = crypto_tfm_ctx(tfm); const char *alg_name = crypto_tfm_alg_name(tfm); - pr_info("enter\n"); - /* Allocate a fallback and abort if it failed. */ tctx->fallback = crypto_alloc_shash(alg_name, 0, CRYPTO_ALG_NEED_FALLBACK); -- cgit v0.10.2 From 528d26f57acd112fef78cd455db78e69a1ac39fd Mon Sep 17 00:00:00 2001 From: Dmitry Kasatkin Date: Wed, 20 Apr 2011 13:34:57 +0300 Subject: crypto: omap-sham - enable driver for EMU chips EMU chips also have crypto HW as HS chips. Signed-off-by: Dmitry Kasatkin Signed-off-by: Herbert Xu diff --git a/drivers/crypto/omap-sham.c b/drivers/crypto/omap-sham.c index 50aca41..f5c01dc 100644 --- a/drivers/crypto/omap-sham.c +++ b/drivers/crypto/omap-sham.c @@ -1295,7 +1295,8 @@ static int __init omap_sham_mod_init(void) pr_info("loading %s driver\n", "omap-sham"); if (!cpu_class_is_omap2() || - omap_type() != OMAP2_DEVICE_TYPE_SEC) { + (omap_type() != OMAP2_DEVICE_TYPE_SEC && + omap_type() != OMAP2_DEVICE_TYPE_EMU)) { pr_err("Unsupported cpu\n"); return -ENODEV; } -- cgit v0.10.2 From bf362759034cf208966dff262c7d740a6b1b3edd Mon Sep 17 00:00:00 2001 From: Dmitry Kasatkin Date: Wed, 20 Apr 2011 13:34:58 +0300 Subject: crypto: omap-sham - hmac calculation bug fix for sha1 base hash This patch fixes 2 hmac inter-dependent bugs. 1. "omap-sham: hash-in-progress is stored in hw format" commit introduced optimization where temporary hash had been stored in OMAP specific format (big endian). For SHA1 it is different to real hash format, which is little endian. Final HMAC value was calculated using incorrect hash. Because CONFIG_CRYPTO_MANAGER_TESTS was disabled this error remained unnoticed. After enabling this option, bug has been found. 2. HMAC was calculated using temporrary hash value. For a single-request updates, temporary hash was the final one and HMAC result was correct. But in fact only the final hash had to be used. All crypto tests for HMAC produces only single request and could not catch the problem. This problem is fixed here. Signed-off-by: Dmitry Kasatkin Signed-off-by: Herbert Xu diff --git a/drivers/crypto/omap-sham.c b/drivers/crypto/omap-sham.c index f5c01dc..ba8f1ea 100644 --- a/drivers/crypto/omap-sham.c +++ b/drivers/crypto/omap-sham.c @@ -78,7 +78,6 @@ #define FLAGS_SHA1 0x0010 #define FLAGS_DMA_ACTIVE 0x0020 #define FLAGS_OUTPUT_READY 0x0040 -#define FLAGS_CLEAN 0x0080 #define FLAGS_INIT 0x0100 #define FLAGS_CPU 0x0200 #define FLAGS_HMAC 0x0400 @@ -511,26 +510,6 @@ static int omap_sham_update_dma_stop(struct omap_sham_dev *dd) return 0; } -static void omap_sham_cleanup(struct ahash_request *req) -{ - struct omap_sham_reqctx *ctx = ahash_request_ctx(req); - struct omap_sham_dev *dd = ctx->dd; - unsigned long flags; - - spin_lock_irqsave(&dd->lock, flags); - if (ctx->flags & FLAGS_CLEAN) { - spin_unlock_irqrestore(&dd->lock, flags); - return; - } - ctx->flags |= FLAGS_CLEAN; - spin_unlock_irqrestore(&dd->lock, flags); - - if (ctx->digcnt) - omap_sham_copy_ready_hash(req); - - dev_dbg(dd->dev, "digcnt: %d, bufcnt: %d\n", ctx->digcnt, ctx->bufcnt); -} - static int omap_sham_init(struct ahash_request *req) { struct crypto_ahash *tfm = crypto_ahash_reqtfm(req); @@ -618,9 +597,8 @@ static int omap_sham_final_req(struct omap_sham_dev *dd) return err; } -static int omap_sham_finish_req_hmac(struct ahash_request *req) +static int omap_sham_finish_hmac(struct ahash_request *req) { - struct omap_sham_reqctx *ctx = ahash_request_ctx(req); struct omap_sham_ctx *tctx = crypto_tfm_ctx(req->base.tfm); struct omap_sham_hmac_ctx *bctx = tctx->base; int bs = crypto_shash_blocksize(bctx->shash); @@ -635,7 +613,24 @@ static int omap_sham_finish_req_hmac(struct ahash_request *req) return crypto_shash_init(&desc.shash) ?: crypto_shash_update(&desc.shash, bctx->opad, bs) ?: - crypto_shash_finup(&desc.shash, ctx->digest, ds, ctx->digest); + crypto_shash_finup(&desc.shash, req->result, ds, req->result); +} + +static int omap_sham_finish(struct ahash_request *req) +{ + struct omap_sham_reqctx *ctx = ahash_request_ctx(req); + struct omap_sham_dev *dd = ctx->dd; + int err = 0; + + if (ctx->digcnt) { + omap_sham_copy_ready_hash(req); + if (ctx->flags & FLAGS_HMAC) + err = omap_sham_finish_hmac(req); + } + + dev_dbg(dd->dev, "digcnt: %d, bufcnt: %d\n", ctx->digcnt, ctx->bufcnt); + + return err; } static void omap_sham_finish_req(struct ahash_request *req, int err) @@ -645,15 +640,12 @@ static void omap_sham_finish_req(struct ahash_request *req, int err) if (!err) { omap_sham_copy_hash(ctx->dd->req, 1); - if (ctx->flags & FLAGS_HMAC) - err = omap_sham_finish_req_hmac(req); + if (ctx->flags & FLAGS_FINAL) + err = omap_sham_finish(req); } else { ctx->flags |= FLAGS_ERROR; } - if ((ctx->flags & FLAGS_FINAL) || err) - omap_sham_cleanup(req); - clk_disable(dd->iclk); dd->flags &= ~FLAGS_BUSY; @@ -809,22 +801,21 @@ static int omap_sham_final_shash(struct ahash_request *req) static int omap_sham_final(struct ahash_request *req) { struct omap_sham_reqctx *ctx = ahash_request_ctx(req); - int err = 0; ctx->flags |= FLAGS_FINUP; - if (!(ctx->flags & FLAGS_ERROR)) { - /* OMAP HW accel works only with buffers >= 9 */ - /* HMAC is always >= 9 because of ipad */ - if ((ctx->digcnt + ctx->bufcnt) < 9) - err = omap_sham_final_shash(req); - else if (ctx->bufcnt) - return omap_sham_enqueue(req, OP_FINAL); - } + if (ctx->flags & FLAGS_ERROR) + return 0; /* uncompleted hash is not needed */ - omap_sham_cleanup(req); + /* OMAP HW accel works only with buffers >= 9 */ + /* HMAC is always >= 9 because ipad == block size */ + if ((ctx->digcnt + ctx->bufcnt) < 9) + return omap_sham_final_shash(req); + else if (ctx->bufcnt) + return omap_sham_enqueue(req, OP_FINAL); - return err; + /* copy ready hash (+ finalize hmac) */ + return omap_sham_finish(req); } static int omap_sham_finup(struct ahash_request *req) -- cgit v0.10.2 From 0aebff4871d26410ae485b521870bb0ffe1736f0 Mon Sep 17 00:00:00 2001 From: Matt Carlson Date: Mon, 25 Apr 2011 12:42:45 +0000 Subject: tg3: Fix int generation hw bug for 5719 / 5720 On the 5719 and 5720, there is a bug where the hardware will misinterpret a status tag update and leave interrupts permanently disabled. This patch enables a hardware fix that works around the issue. Signed-off-by: Matt Carlson Reviewed-by: Michael Chan Reviewed-by: Benjamin Li Signed-off-by: David S. Miller diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index 693f36e..a72d031 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -8198,6 +8198,9 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy) ~DMA_RWCTRL_DIS_CACHE_ALIGNMENT; if (tp->pci_chip_rev_id == CHIPREV_ID_57765_A0) val &= ~DMA_RWCTRL_CRDRDR_RDMA_MRRS_MSK; + if (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_57765 && + GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5717) + val |= DMA_RWCTRL_TAGGED_STAT_WA; tw32(TG3PCI_DMA_RW_CTRL, val | tp->dma_rwctrl); } else if (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5784 && GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5761) { diff --git a/drivers/net/tg3.h b/drivers/net/tg3.h index eaa7669..6f37d2a 100644 --- a/drivers/net/tg3.h +++ b/drivers/net/tg3.h @@ -188,6 +188,7 @@ #define METAL_REV_B2 0x02 #define TG3PCI_DMA_RW_CTRL 0x0000006c #define DMA_RWCTRL_DIS_CACHE_ALIGNMENT 0x00000001 +#define DMA_RWCTRL_TAGGED_STAT_WA 0x00000080 #define DMA_RWCTRL_CRDRDR_RDMA_MRRS_MSK 0x00000380 #define DMA_RWCTRL_READ_BNDRY_MASK 0x00000700 #define DMA_RWCTRL_READ_BNDRY_DISAB 0x00000000 -- cgit v0.10.2 From 00c266b794d589dcf7d280926dfc27c5896a410a Mon Sep 17 00:00:00 2001 From: Matt Carlson Date: Mon, 25 Apr 2011 12:42:46 +0000 Subject: tg3: Organize loopback test failure flags As more test modes are added to each loopback mode, the need to organise the results increases. This patch groups the results by loopback mode, and then by test mode. Signed-off-by: Matt Carlson Reviewed-by: Michael Chan Reviewed-by: Benjamin Li Signed-off-by: David S. Miller diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index a72d031..88cd231 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -11276,10 +11276,12 @@ out: return err; } -#define TG3_MAC_LOOPBACK_FAILED 1 -#define TG3_PHY_LOOPBACK_FAILED 2 -#define TG3_LOOPBACK_FAILED (TG3_MAC_LOOPBACK_FAILED | \ - TG3_PHY_LOOPBACK_FAILED) +#define TG3_STD_LOOPBACK_FAILED 1 +#define TG3_JMB_LOOPBACK_FAILED 2 + +#define TG3_MAC_LOOPBACK_SHIFT 0 +#define TG3_PHY_LOOPBACK_SHIFT 4 +#define TG3_LOOPBACK_FAILED 0x00000033 static int tg3_test_loopback(struct tg3 *tp) { @@ -11338,11 +11340,11 @@ static int tg3_test_loopback(struct tg3 *tp) } if (tg3_run_loopback(tp, ETH_FRAME_LEN, TG3_MAC_LOOPBACK)) - err |= TG3_MAC_LOOPBACK_FAILED; + err |= TG3_STD_LOOPBACK_FAILED << TG3_MAC_LOOPBACK_SHIFT; if ((tp->tg3_flags & TG3_FLAG_JUMBO_RING_ENABLE) && tg3_run_loopback(tp, 9000 + ETH_HLEN, TG3_MAC_LOOPBACK)) - err |= (TG3_MAC_LOOPBACK_FAILED << 2); + err |= TG3_JMB_LOOPBACK_FAILED << TG3_MAC_LOOPBACK_SHIFT; if (tp->tg3_flags & TG3_FLAG_CPMU_PRESENT) { tw32(TG3_CPMU_CTRL, cpmuctrl); @@ -11354,10 +11356,12 @@ static int tg3_test_loopback(struct tg3 *tp) if (!(tp->phy_flags & TG3_PHYFLG_PHY_SERDES) && !(tp->tg3_flags3 & TG3_FLG3_USE_PHYLIB)) { if (tg3_run_loopback(tp, ETH_FRAME_LEN, TG3_PHY_LOOPBACK)) - err |= TG3_PHY_LOOPBACK_FAILED; + err |= TG3_STD_LOOPBACK_FAILED << + TG3_PHY_LOOPBACK_SHIFT; if ((tp->tg3_flags & TG3_FLAG_JUMBO_RING_ENABLE) && tg3_run_loopback(tp, 9000 + ETH_HLEN, TG3_PHY_LOOPBACK)) - err |= (TG3_PHY_LOOPBACK_FAILED << 2); + err |= TG3_JMB_LOOPBACK_FAILED << + TG3_PHY_LOOPBACK_SHIFT; } /* Re-enable gphy autopowerdown. */ -- cgit v0.10.2 From bb158d696489244f79fd4c3abd47968a06b48c79 Mon Sep 17 00:00:00 2001 From: Matt Carlson Date: Mon, 25 Apr 2011 12:42:47 +0000 Subject: tg3: Add TSO loopback test This patch adds code to exercise the TSO portion of the device through a phy loopback test. Signed-off-by: Matt Carlson Signed-off-by: Benjamin Li Signed-off-by: Michael Chan Signed-off-by: David S. Miller diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index 88cd231..fb2139a 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -11076,11 +11076,35 @@ static int tg3_test_memory(struct tg3 *tp) #define TG3_MAC_LOOPBACK 0 #define TG3_PHY_LOOPBACK 1 +#define TG3_TSO_LOOPBACK 2 + +#define TG3_TSO_MSS 500 + +#define TG3_TSO_IP_HDR_LEN 20 +#define TG3_TSO_TCP_HDR_LEN 20 +#define TG3_TSO_TCP_OPT_LEN 12 + +static const u8 tg3_tso_header[] = { +0x08, 0x00, +0x45, 0x00, 0x00, 0x00, +0x00, 0x00, 0x40, 0x00, +0x40, 0x06, 0x00, 0x00, +0x0a, 0x00, 0x00, 0x01, +0x0a, 0x00, 0x00, 0x02, +0x0d, 0x00, 0xe0, 0x00, +0x00, 0x00, 0x01, 0x00, +0x00, 0x00, 0x02, 0x00, +0x80, 0x10, 0x10, 0x00, +0x14, 0x09, 0x00, 0x00, +0x01, 0x01, 0x08, 0x0a, +0x11, 0x11, 0x11, 0x11, +0x11, 0x11, 0x11, 0x11, +}; static int tg3_run_loopback(struct tg3 *tp, u32 pktsz, int loopback_mode) { u32 mac_mode, rx_start_idx, rx_idx, tx_idx, opaque_key; - u32 desc_idx, coal_now; + u32 base_flags = 0, mss = 0, desc_idx, coal_now, data_off, val; struct sk_buff *skb, *rx_skb; u8 *tx_data; dma_addr_t map; @@ -11119,9 +11143,7 @@ static int tg3_run_loopback(struct tg3 *tp, u32 pktsz, int loopback_mode) else mac_mode |= MAC_MODE_PORT_MODE_GMII; tw32(MAC_MODE, mac_mode); - } else if (loopback_mode == TG3_PHY_LOOPBACK) { - u32 val; - + } else { if (tp->phy_flags & TG3_PHYFLG_IS_FET) { tg3_phy_fet_toggle_apd(tp, false); val = BMCR_LOOPBACK | BMCR_FULLDPLX | BMCR_SPEED100; @@ -11169,8 +11191,6 @@ static int tg3_run_loopback(struct tg3 *tp, u32 pktsz, int loopback_mode) break; mdelay(1); } - } else { - return -EINVAL; } err = -EIO; @@ -11186,7 +11206,54 @@ static int tg3_run_loopback(struct tg3 *tp, u32 pktsz, int loopback_mode) tw32(MAC_RX_MTU_SIZE, tx_len + ETH_FCS_LEN); - for (i = 14; i < tx_len; i++) + if (loopback_mode == TG3_TSO_LOOPBACK) { + struct iphdr *iph = (struct iphdr *)&tx_data[ETH_HLEN]; + + u32 hdr_len = TG3_TSO_IP_HDR_LEN + TG3_TSO_TCP_HDR_LEN + + TG3_TSO_TCP_OPT_LEN; + + memcpy(tx_data + ETH_ALEN * 2, tg3_tso_header, + sizeof(tg3_tso_header)); + mss = TG3_TSO_MSS; + + val = tx_len - ETH_ALEN * 2 - sizeof(tg3_tso_header); + num_pkts = DIV_ROUND_UP(val, TG3_TSO_MSS); + + /* Set the total length field in the IP header */ + iph->tot_len = htons((u16)(mss + hdr_len)); + + base_flags = (TXD_FLAG_CPU_PRE_DMA | + TXD_FLAG_CPU_POST_DMA); + + if (tp->tg3_flags2 & TG3_FLG2_HW_TSO) { + struct tcphdr *th; + val = ETH_HLEN + TG3_TSO_IP_HDR_LEN; + th = (struct tcphdr *)&tx_data[val]; + th->check = 0; + } else + base_flags |= TXD_FLAG_TCPUDP_CSUM; + + if (tp->tg3_flags2 & TG3_FLG2_HW_TSO_3) { + mss |= (hdr_len & 0xc) << 12; + if (hdr_len & 0x10) + base_flags |= 0x00000010; + base_flags |= (hdr_len & 0x3e0) << 5; + } else if (tp->tg3_flags2 & TG3_FLG2_HW_TSO_2) + mss |= hdr_len << 9; + else if ((tp->tg3_flags2 & TG3_FLG2_HW_TSO_1) || + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5705) { + mss |= (TG3_TSO_TCP_OPT_LEN << 9); + } else { + base_flags |= (TG3_TSO_TCP_OPT_LEN << 10); + } + + data_off = ETH_ALEN * 2 + sizeof(tg3_tso_header); + } else { + num_pkts = 1; + data_off = ETH_HLEN; + } + + for (i = data_off; i < tx_len; i++) tx_data[i] = (u8) (i & 0xff); map = pci_map_single(tp->pdev, skb->data, tx_len, PCI_DMA_TODEVICE); @@ -11202,12 +11269,10 @@ static int tg3_run_loopback(struct tg3 *tp, u32 pktsz, int loopback_mode) rx_start_idx = rnapi->hw_status->idx[0].rx_producer; - num_pkts = 0; - - tg3_set_txd(tnapi, tnapi->tx_prod, map, tx_len, 0, 1); + tg3_set_txd(tnapi, tnapi->tx_prod, map, tx_len, + base_flags, (mss << 1) | 1); tnapi->tx_prod++; - num_pkts++; tw32_tx_mbox(tnapi->prodmbox, tnapi->tx_prod); tr32_mailbox(tnapi->prodmbox); @@ -11237,38 +11302,56 @@ static int tg3_run_loopback(struct tg3 *tp, u32 pktsz, int loopback_mode) if (rx_idx != rx_start_idx + num_pkts) goto out; - desc = &rnapi->rx_rcb[rx_start_idx]; - desc_idx = desc->opaque & RXD_OPAQUE_INDEX_MASK; - opaque_key = desc->opaque & RXD_OPAQUE_RING_MASK; + val = data_off; + while (rx_idx != rx_start_idx) { + desc = &rnapi->rx_rcb[rx_start_idx++]; + desc_idx = desc->opaque & RXD_OPAQUE_INDEX_MASK; + opaque_key = desc->opaque & RXD_OPAQUE_RING_MASK; - if ((desc->err_vlan & RXD_ERR_MASK) != 0 && - (desc->err_vlan != RXD_ERR_ODD_NIBBLE_RCVD_MII)) - goto out; + if ((desc->err_vlan & RXD_ERR_MASK) != 0 && + (desc->err_vlan != RXD_ERR_ODD_NIBBLE_RCVD_MII)) + goto out; - rx_len = ((desc->idx_len & RXD_LEN_MASK) >> RXD_LEN_SHIFT) - 4; - if (rx_len != tx_len) - goto out; + rx_len = ((desc->idx_len & RXD_LEN_MASK) >> RXD_LEN_SHIFT) + - ETH_FCS_LEN; - if (pktsz <= TG3_RX_STD_DMA_SZ - ETH_FCS_LEN) { - if (opaque_key != RXD_OPAQUE_RING_STD) - goto out; + if (loopback_mode != TG3_TSO_LOOPBACK) { + if (rx_len != tx_len) + goto out; - rx_skb = tpr->rx_std_buffers[desc_idx].skb; - map = dma_unmap_addr(&tpr->rx_std_buffers[desc_idx], mapping); - } else { - if (opaque_key != RXD_OPAQUE_RING_JUMBO) + if (pktsz <= TG3_RX_STD_DMA_SZ - ETH_FCS_LEN) { + if (opaque_key != RXD_OPAQUE_RING_STD) + goto out; + } else { + if (opaque_key != RXD_OPAQUE_RING_JUMBO) + goto out; + } + } else if ((desc->type_flags & RXD_FLAG_TCPUDP_CSUM) && + (desc->ip_tcp_csum & RXD_TCPCSUM_MASK) + >> RXD_TCPCSUM_SHIFT == 0xffff) { goto out; + } - rx_skb = tpr->rx_jmb_buffers[desc_idx].skb; - map = dma_unmap_addr(&tpr->rx_jmb_buffers[desc_idx], mapping); - } + if (opaque_key == RXD_OPAQUE_RING_STD) { + rx_skb = tpr->rx_std_buffers[desc_idx].skb; + map = dma_unmap_addr(&tpr->rx_std_buffers[desc_idx], + mapping); + } else if (opaque_key == RXD_OPAQUE_RING_JUMBO) { + rx_skb = tpr->rx_jmb_buffers[desc_idx].skb; + map = dma_unmap_addr(&tpr->rx_jmb_buffers[desc_idx], + mapping); + } else + goto out; - pci_dma_sync_single_for_cpu(tp->pdev, map, rx_len, PCI_DMA_FROMDEVICE); + pci_dma_sync_single_for_cpu(tp->pdev, map, rx_len, + PCI_DMA_FROMDEVICE); - for (i = 14; i < tx_len; i++) { - if (*(rx_skb->data + i) != (u8) (i & 0xff)) - goto out; + for (i = data_off; i < rx_len; i++, val++) { + if (*(rx_skb->data + i) != (u8) (val & 0xff)) + goto out; + } } + err = 0; /* tg3_free_rings will unmap and free the rx_skb */ @@ -11278,10 +11361,11 @@ out: #define TG3_STD_LOOPBACK_FAILED 1 #define TG3_JMB_LOOPBACK_FAILED 2 +#define TG3_TSO_LOOPBACK_FAILED 4 #define TG3_MAC_LOOPBACK_SHIFT 0 #define TG3_PHY_LOOPBACK_SHIFT 4 -#define TG3_LOOPBACK_FAILED 0x00000033 +#define TG3_LOOPBACK_FAILED 0x00000077 static int tg3_test_loopback(struct tg3 *tp) { @@ -11358,6 +11442,10 @@ static int tg3_test_loopback(struct tg3 *tp) if (tg3_run_loopback(tp, ETH_FRAME_LEN, TG3_PHY_LOOPBACK)) err |= TG3_STD_LOOPBACK_FAILED << TG3_PHY_LOOPBACK_SHIFT; + if ((tp->tg3_flags2 & TG3_FLG2_TSO_CAPABLE) && + tg3_run_loopback(tp, ETH_FRAME_LEN, TG3_TSO_LOOPBACK)) + err |= TG3_TSO_LOOPBACK_FAILED << + TG3_PHY_LOOPBACK_SHIFT; if ((tp->tg3_flags & TG3_FLAG_JUMBO_RING_ENABLE) && tg3_run_loopback(tp, 9000 + ETH_HLEN, TG3_PHY_LOOPBACK)) err |= TG3_JMB_LOOPBACK_FAILED << -- cgit v0.10.2 From b45aa2f6192e34a837ebdbb3548039c24440bc04 Mon Sep 17 00:00:00 2001 From: Matt Carlson Date: Mon, 25 Apr 2011 12:42:48 +0000 Subject: tg3: Add EEH support This patch adds EEH support to the tg3 driver. Signed-off-by: Matt Carlson Reviewed-by: Michael Chan Reviewed-by: Benjamin Li Signed-off-by: David S. Miller diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index fb2139a..6bc43ed 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -15395,6 +15395,8 @@ static int __devinit tg3_init_one(struct pci_dev *pdev, pdev->dma_mask == DMA_BIT_MASK(32) ? 32 : ((u64)pdev->dma_mask) == DMA_BIT_MASK(40) ? 40 : 64); + pci_save_state(pdev); + return 0; err_out_apeunmap: @@ -15551,11 +15553,156 @@ static SIMPLE_DEV_PM_OPS(tg3_pm_ops, tg3_suspend, tg3_resume); #endif /* CONFIG_PM_SLEEP */ +/** + * tg3_io_error_detected - called when PCI error is detected + * @pdev: Pointer to PCI device + * @state: The current pci connection state + * + * This function is called after a PCI bus error affecting + * this device has been detected. + */ +static pci_ers_result_t tg3_io_error_detected(struct pci_dev *pdev, + pci_channel_state_t state) +{ + struct net_device *netdev = pci_get_drvdata(pdev); + struct tg3 *tp = netdev_priv(netdev); + pci_ers_result_t err = PCI_ERS_RESULT_NEED_RESET; + + netdev_info(netdev, "PCI I/O error detected\n"); + + rtnl_lock(); + + if (!netif_running(netdev)) + goto done; + + tg3_phy_stop(tp); + + tg3_netif_stop(tp); + + del_timer_sync(&tp->timer); + tp->tg3_flags2 &= ~TG3_FLG2_RESTART_TIMER; + + /* Want to make sure that the reset task doesn't run */ + cancel_work_sync(&tp->reset_task); + tp->tg3_flags &= ~TG3_FLAG_TX_RECOVERY_PENDING; + tp->tg3_flags2 &= ~TG3_FLG2_RESTART_TIMER; + + netif_device_detach(netdev); + + /* Clean up software state, even if MMIO is blocked */ + tg3_full_lock(tp, 0); + tg3_halt(tp, RESET_KIND_SHUTDOWN, 0); + tg3_full_unlock(tp); + +done: + if (state == pci_channel_io_perm_failure) + err = PCI_ERS_RESULT_DISCONNECT; + else + pci_disable_device(pdev); + + rtnl_unlock(); + + return err; +} + +/** + * tg3_io_slot_reset - called after the pci bus has been reset. + * @pdev: Pointer to PCI device + * + * Restart the card from scratch, as if from a cold-boot. + * At this point, the card has exprienced a hard reset, + * followed by fixups by BIOS, and has its config space + * set up identically to what it was at cold boot. + */ +static pci_ers_result_t tg3_io_slot_reset(struct pci_dev *pdev) +{ + struct net_device *netdev = pci_get_drvdata(pdev); + struct tg3 *tp = netdev_priv(netdev); + pci_ers_result_t rc = PCI_ERS_RESULT_DISCONNECT; + int err; + + rtnl_lock(); + + if (pci_enable_device(pdev)) { + netdev_err(netdev, "Cannot re-enable PCI device after reset.\n"); + goto done; + } + + pci_set_master(pdev); + pci_restore_state(pdev); + pci_save_state(pdev); + + if (!netif_running(netdev)) { + rc = PCI_ERS_RESULT_RECOVERED; + goto done; + } + + err = tg3_power_up(tp); + if (err) { + netdev_err(netdev, "Failed to restore register access.\n"); + goto done; + } + + rc = PCI_ERS_RESULT_RECOVERED; + +done: + rtnl_unlock(); + + return rc; +} + +/** + * tg3_io_resume - called when traffic can start flowing again. + * @pdev: Pointer to PCI device + * + * This callback is called when the error recovery driver tells + * us that its OK to resume normal operation. + */ +static void tg3_io_resume(struct pci_dev *pdev) +{ + struct net_device *netdev = pci_get_drvdata(pdev); + struct tg3 *tp = netdev_priv(netdev); + int err; + + rtnl_lock(); + + if (!netif_running(netdev)) + goto done; + + tg3_full_lock(tp, 0); + tp->tg3_flags |= TG3_FLAG_INIT_COMPLETE; + err = tg3_restart_hw(tp, 1); + tg3_full_unlock(tp); + if (err) { + netdev_err(netdev, "Cannot restart hardware after reset.\n"); + goto done; + } + + netif_device_attach(netdev); + + tp->timer.expires = jiffies + tp->timer_offset; + add_timer(&tp->timer); + + tg3_netif_start(tp); + + tg3_phy_start(tp); + +done: + rtnl_unlock(); +} + +static struct pci_error_handlers tg3_err_handler = { + .error_detected = tg3_io_error_detected, + .slot_reset = tg3_io_slot_reset, + .resume = tg3_io_resume +}; + static struct pci_driver tg3_driver = { .name = DRV_MODULE_NAME, .id_table = tg3_pci_tbl, .probe = tg3_init_one, .remove = __devexit_p(tg3_remove_one), + .err_handler = &tg3_err_handler, .driver.pm = TG3_PM_OPS, }; -- cgit v0.10.2 From bea8a63b27eb8e705a957938aadeb975178c5ea6 Mon Sep 17 00:00:00 2001 From: Matt Carlson Date: Mon, 25 Apr 2011 12:42:49 +0000 Subject: tg3: Whitespace cleanups This patch gets rid of some harmless whitespace errors. Signed-off-by: Matt Carlson Reviewed-by: Michael Chan Reviewed-by: Benjamin Li Signed-off-by: David S. Miller diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index 6bc43ed..696be59 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -7666,8 +7666,6 @@ static int tg3_load_5701_a0_firmware_fix(struct tg3 *tp) return 0; } -/* 5705 needs a special version of the TSO firmware. */ - /* tp->lock is held. */ static int tg3_load_tso_firmware(struct tg3 *tp) { @@ -10179,7 +10177,6 @@ static int tg3_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol) tp->tg3_flags &= ~TG3_FLAG_WOL_ENABLE; spin_unlock_bh(&tp->lock); - return 0; } @@ -12925,7 +12922,7 @@ static void __devinit tg3_get_eeprom_hw_cfg(struct tg3 *tp) done: if (tp->tg3_flags & TG3_FLAG_WOL_CAP) device_set_wakeup_enable(&tp->pdev->dev, - tp->tg3_flags & TG3_FLAG_WOL_ENABLE); + tp->tg3_flags & TG3_FLAG_WOL_ENABLE); else device_set_wakeup_capable(&tp->pdev->dev, false); } @@ -13749,7 +13746,6 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) (tp->tg3_flags2 & TG3_FLG2_5780_CLASS)) tp->tg3_flags2 |= TG3_FLG2_5750_PLUS; - if ((GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5705) || (tp->tg3_flags2 & TG3_FLG2_5750_PLUS)) tp->tg3_flags2 |= TG3_FLG2_5705_PLUS; @@ -14034,7 +14030,7 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) (tp->tg3_flags3 & TG3_FLG3_57765_PLUS)) tp->tg3_flags |= TG3_FLAG_CPMU_PRESENT; - /* Set up tp->grc_local_ctrl before calling tg_power_up(). + /* Set up tp->grc_local_ctrl before calling tg3_power_up(). * GPIO1 driven high will bring 5700's external PHY out of reset. * It is also used as eeprom write protect on LOMs. */ @@ -14829,7 +14825,6 @@ static int __devinit tg3_test_dma(struct tg3 *tp) } if ((tp->dma_rwctrl & DMA_RWCTRL_WRITE_BNDRY_MASK) != DMA_RWCTRL_WRITE_BNDRY_16) { - /* DMA test passed without adjusting DMA boundary, * now look for chipsets that are known to expose the * DMA bug without failing the test. -- cgit v0.10.2 From 64cad2ade1e6f890531a58318ca9ee013f92ef2f Mon Sep 17 00:00:00 2001 From: Matt Carlson Date: Mon, 25 Apr 2011 12:42:50 +0000 Subject: tg3: Update version to 3.118 This patch updates the tg3 version to 3.118. Signed-off-by: Matt Carlson Reviewed-by: Michael Chan Reviewed-by: Benjamin Li Signed-off-by: David S. Miller diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index 696be59..b20538a 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -64,10 +64,10 @@ #define DRV_MODULE_NAME "tg3" #define TG3_MAJ_NUM 3 -#define TG3_MIN_NUM 117 +#define TG3_MIN_NUM 118 #define DRV_MODULE_VERSION \ __stringify(TG3_MAJ_NUM) "." __stringify(TG3_MIN_NUM) -#define DRV_MODULE_RELDATE "January 25, 2011" +#define DRV_MODULE_RELDATE "April 22, 2011" #define TG3_DEF_MAC_MODE 0 #define TG3_DEF_RX_MODE 0 -- cgit v0.10.2 From e01255d698ad00a6f4c6b3e0bf061e27ab238969 Mon Sep 17 00:00:00 2001 From: Florian Tobias Schandinat Date: Tue, 26 Apr 2011 08:10:33 +0000 Subject: viafb: remove unused CEA mode This trivial patch removes unused mode tables. Signed-off-by: Florian Tobias Schandinat diff --git a/drivers/video/via/share.h b/drivers/video/via/share.h index 8b93e2f..61b0bd5 100644 --- a/drivers/video/via/share.h +++ b/drivers/video/via/share.h @@ -568,10 +568,6 @@ #define M1280X720_R50_HSP NEGATIVE #define M1280X720_R50_VSP POSITIVE -/* 1280x720@60 Sync Polarity (CEA Mode) */ -#define M1280X720_CEA_R60_HSP POSITIVE -#define M1280X720_CEA_R60_VSP POSITIVE - /* 1440x900@60 Sync Polarity (CVT Mode) */ #define M1440X900_R60_HSP NEGATIVE #define M1440X900_R60_VSP POSITIVE @@ -612,10 +608,6 @@ #define M1920X1200_RB_R60_HSP POSITIVE #define M1920X1200_RB_R60_VSP NEGATIVE -/* 1920x1080@60 Sync Polarity (CEA Mode) */ -#define M1920X1080_CEA_R60_HSP POSITIVE -#define M1920X1080_CEA_R60_VSP POSITIVE - /* 2048x1536@60 Sync Polarity (CVT Mode) */ #define M2048x1536_R60_HSP NEGATIVE #define M2048x1536_R60_VSP POSITIVE diff --git a/drivers/video/via/viamode.c b/drivers/video/via/viamode.c index 50de07f..58df74e 100644 --- a/drivers/video/via/viamode.c +++ b/drivers/video/via/viamode.c @@ -854,23 +854,6 @@ static struct VideoModeTable viafb_rb_modes[] = { {CRTM1920x1200_RB, ARRAY_SIZE(CRTM1920x1200_RB)} }; -struct crt_mode_table CEAM1280x720[] = { - {REFRESH_60, M1280X720_CEA_R60_HSP, M1280X720_CEA_R60_VSP, - /* HT, HA, HBS, HBE, HSS, HSE, VT, VA, VBS, VBE, VSS, VSE */ - {1650, 1280, 1280, 370, 1390, 40, 750, 720, 720, 30, 725, 5} } -}; -struct crt_mode_table CEAM1920x1080[] = { - {REFRESH_60, M1920X1080_CEA_R60_HSP, M1920X1080_CEA_R60_VSP, - /* HT, HA, HBS, HBE, HSS, HSE, VT, VA, VBS, VBE, VSS, VSE */ - {2200, 1920, 1920, 300, 2008, 44, 1125, 1080, 1080, 45, 1084, 5} } -}; -struct VideoModeTable CEA_HDMI_Modes[] = { - /* Display : 1280x720 */ - {CEAM1280x720, ARRAY_SIZE(CEAM1280x720)}, - {CEAM1920x1080, ARRAY_SIZE(CEAM1920x1080)} -}; - -int NUM_TOTAL_CEA_MODES = ARRAY_SIZE(CEA_HDMI_Modes); int NUM_TOTAL_CN400_ModeXregs = ARRAY_SIZE(CN400_ModeXregs); int NUM_TOTAL_CN700_ModeXregs = ARRAY_SIZE(CN700_ModeXregs); int NUM_TOTAL_KM400_ModeXregs = ARRAY_SIZE(KM400_ModeXregs); diff --git a/drivers/video/via/viamode.h b/drivers/video/via/viamode.h index 8a67ea1..3751289 100644 --- a/drivers/video/via/viamode.h +++ b/drivers/video/via/viamode.h @@ -41,7 +41,6 @@ struct patch_table { struct io_reg *io_reg_table; }; -extern int NUM_TOTAL_CEA_MODES; extern int NUM_TOTAL_CN400_ModeXregs; extern int NUM_TOTAL_CN700_ModeXregs; extern int NUM_TOTAL_KM400_ModeXregs; @@ -50,14 +49,6 @@ extern int NUM_TOTAL_VX855_ModeXregs; extern int NUM_TOTAL_CLE266_ModeXregs; extern int NUM_TOTAL_PATCH_MODE; -/********************/ -/* Mode Table */ -/********************/ - -extern struct crt_mode_table CEAM1280x720[]; -extern struct crt_mode_table CEAM1920x1080[]; -extern struct VideoModeTable CEA_HDMI_Modes[]; - extern struct io_reg CN400_ModeXregs[]; extern struct io_reg CN700_ModeXregs[]; extern struct io_reg KM400_ModeXregs[]; -- cgit v0.10.2 From 6ba5932ca4b610d036cb89d0ce2a465d06504c4d Mon Sep 17 00:00:00 2001 From: Oskar Andero Date: Tue, 26 Apr 2011 02:24:50 -0700 Subject: arm: omap2: enable smc instruction for sleep34xx This fixes broken build when using binutils 2.21. Signed-off-by: Oskar Andero Signed-off-by: Tony Lindgren diff --git a/arch/arm/mach-omap2/Makefile b/arch/arm/mach-omap2/Makefile index a45cd64..512b152 100644 --- a/arch/arm/mach-omap2/Makefile +++ b/arch/arm/mach-omap2/Makefile @@ -68,7 +68,7 @@ obj-$(CONFIG_OMAP_SMARTREFLEX) += sr_device.o smartreflex.o obj-$(CONFIG_OMAP_SMARTREFLEX_CLASS3) += smartreflex-class3.o AFLAGS_sleep24xx.o :=-Wa,-march=armv6 -AFLAGS_sleep34xx.o :=-Wa,-march=armv7-a +AFLAGS_sleep34xx.o :=-Wa,-march=armv7-a$(plus_sec) ifeq ($(CONFIG_PM_VERBOSE),y) CFLAGS_pm_bus.o += -DDEBUG -- cgit v0.10.2 From bc16b3777ec3749c086a17f81c99f8643f4a6576 Mon Sep 17 00:00:00 2001 From: omar ramirez Date: Tue, 26 Apr 2011 02:24:50 -0700 Subject: OMAP3: l3: fix for "irq 10: nobody cared" message If an error occurs in the L3 on any other initiator than MPU, the interrupt goes unhandled given that the 'base' register was calculated with the initialized err_source value (which coincidentally points to MPU) and not with the actual source of the error. Removed parenthesis that are not needed for the touched lines. Signed-off-by: Omar Ramirez Luna Acked-by: Santosh Shilimkar Signed-off-by: Tony Lindgren diff --git a/arch/arm/mach-omap2/omap_l3_smx.c b/arch/arm/mach-omap2/omap_l3_smx.c index 5f2da756..4321e79 100644 --- a/arch/arm/mach-omap2/omap_l3_smx.c +++ b/arch/arm/mach-omap2/omap_l3_smx.c @@ -196,11 +196,11 @@ static irqreturn_t omap3_l3_app_irq(int irq, void *_l3) /* No timeout error for debug sources */ } - base = ((l3->rt) + (*(omap3_l3_bases[int_type] + err_source))); - /* identify the error source */ for (err_source = 0; !(status & (1 << err_source)); err_source++) ; + + base = l3->rt + *(omap3_l3_bases[int_type] + err_source); error = omap3_l3_readll(base, L3_ERROR_LOG); if (error) { -- cgit v0.10.2 From 22110faf8c8e980013790e6a5214de32b3303730 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Tue, 26 Apr 2011 11:33:09 +0200 Subject: PM / Wakeup: Fix initialization of wakeup-related device sysfs files It turns out that some PCI devices are only found to be wakeup-capable during registration, in which case, when device_set_wakeup_capable() is called, device_is_registered() already returns 'true' for the given device, but dpm_sysfs_add() hasn't been called for it yet. This leads to situations in which the device's power.can_wakeup flag is not set as requested because of failing wakeup_sysfs_add() and its wakeup-related sysfs files are not created, although they should be present. This is a post-2.6.38 regression introduced by commit cb8f51bdadb7969139c2e39c2defd4cde98c1 (PM: Do not create wakeup sysfs files for devices that cannot wake up). To work around this problem initialize the device's power.entry field to an empty list head and make device_set_wakeup_capable() check if it is still empty before attempting to add the devices wakeup-related sysfs files with wakeup_sysfs_add(). Namely, if power.entry is still empty at this point, device_pm_add() hasn't been called yet for the device and its wakeup-related files will be created later, so device_set_wakeup_capable() doesn't have to create them. Reported-and-tested-by: Tino Keitel Signed-off-by: Rafael J. Wysocki Acked-by: Greg Kroah-Hartman diff --git a/drivers/base/power/main.c b/drivers/base/power/main.c index fbc5b6e..abe3ab7 100644 --- a/drivers/base/power/main.c +++ b/drivers/base/power/main.c @@ -63,6 +63,7 @@ void device_pm_init(struct device *dev) dev->power.wakeup = NULL; spin_lock_init(&dev->power.lock); pm_runtime_init(dev); + INIT_LIST_HEAD(&dev->power.entry); } /** diff --git a/drivers/base/power/wakeup.c b/drivers/base/power/wakeup.c index 4573c83..abbbd33 100644 --- a/drivers/base/power/wakeup.c +++ b/drivers/base/power/wakeup.c @@ -258,7 +258,7 @@ void device_set_wakeup_capable(struct device *dev, bool capable) if (!!dev->power.can_wakeup == !!capable) return; - if (device_is_registered(dev)) { + if (device_is_registered(dev) && !list_empty(&dev->power.entry)) { if (capable) { if (wakeup_sysfs_add(dev)) return; -- cgit v0.10.2 From 7bed50c5edf5cba8dd515a31191cbfb6065ddc85 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Tue, 26 Apr 2011 11:33:18 +0200 Subject: ACPI / PM: Avoid infinite recurrence while registering power resources There is at least one BIOS with a DSDT containing a power resource object with a _PR0 entry pointing back to that power resource. In consequence, while registering that power resource acpi_bus_get_power_flags() sees that it depends on itself and tries to register it again, which leads to an infinitely deep recurrence. This problem was introduced by commit bf325f9538d8c89312be305b9779e (ACPI / PM: Register power resource devices as soon as they are needed). To fix this problem use the observation that power resources cannot be power manageable and prevent acpi_bus_get_power_flags() from being called for power resource objects. References: https://bugzilla.kernel.org/show_bug.cgi?id=31872 Reported-and-tested-by: Pascal Dormeau Signed-off-by: Rafael J. Wysocki Acked-by: Len Brown Cc: stable@kernel.org diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c index b136c9c..449c556 100644 --- a/drivers/acpi/scan.c +++ b/drivers/acpi/scan.c @@ -943,6 +943,10 @@ static int acpi_bus_get_flags(struct acpi_device *device) if (ACPI_SUCCESS(status)) device->flags.lockable = 1; + /* Power resources cannot be power manageable. */ + if (device->device_type == ACPI_BUS_TYPE_POWER) + return 0; + /* Presence of _PS0|_PR0 indicates 'power manageable' */ status = acpi_get_handle(device->handle, "_PS0", &temp); if (ACPI_FAILURE(status)) -- cgit v0.10.2 From 26a064d5246e8ac51241d6ec2792aebf24f3b41a Mon Sep 17 00:00:00 2001 From: Felipe Contreras Date: Tue, 26 Apr 2011 02:45:28 -0700 Subject: omap: rx51: mark reserved memory earlier So that omap_vram_set_sdram_vram() is called before omap_vram_reserve_sdram_memblock(). Signed-off-by: Felipe Contreras Acked-by: Tomi Valkeinen Signed-off-by: Tony Lindgren diff --git a/arch/arm/mach-omap2/board-rx51.c b/arch/arm/mach-omap2/board-rx51.c index e964895..f8ba20a 100644 --- a/arch/arm/mach-omap2/board-rx51.c +++ b/arch/arm/mach-omap2/board-rx51.c @@ -141,14 +141,19 @@ static void __init rx51_init(void) static void __init rx51_map_io(void) { omap2_set_globals_3xxx(); - rx51_video_mem_init(); omap34xx_map_common_io(); } +static void __init rx51_reserve(void) +{ + rx51_video_mem_init(); + omap_reserve(); +} + MACHINE_START(NOKIA_RX51, "Nokia RX-51 board") /* Maintainer: Lauri Leukkunen */ .boot_params = 0x80000100, - .reserve = omap_reserve, + .reserve = rx51_reserve, .map_io = rx51_map_io, .init_early = rx51_init_early, .init_irq = omap_init_irq, -- cgit v0.10.2 From 919686458fabc67a13ffa412f9e5a8fed46d10b8 Mon Sep 17 00:00:00 2001 From: Shweta Gulati Date: Tue, 26 Apr 2011 02:32:26 -0700 Subject: OMAP4: Intialize IVA Device in addition to DSP device. OMAP4 has two different Devices IVA and DSP. DSP is bound with IVA for DVFS. The registration of IVA dev in API 'omap2_init_processor_devices' was missing. Init dev for 'iva_dev' is added. This also fixes the following error seen during boot as omap2_set_init_voltage can now find the iva device omap2_set_init_voltage: Invalid parameters! omap2_set_init_voltage: Unable to put vdd_iva to its init voltage Signed-off-by: Shweta Gulati Acked-by: Nishanth Menon Signed-off-by: Tony Lindgren diff --git a/arch/arm/mach-omap2/pm.c b/arch/arm/mach-omap2/pm.c index 30af335..49486f5 100644 --- a/arch/arm/mach-omap2/pm.c +++ b/arch/arm/mach-omap2/pm.c @@ -89,6 +89,7 @@ static void omap2_init_processor_devices(void) if (cpu_is_omap44xx()) { _init_omap_device("l3_main_1", &l3_dev); _init_omap_device("dsp", &dsp_dev); + _init_omap_device("iva", &iva_dev); } else { _init_omap_device("l3_main", &l3_dev); } -- cgit v0.10.2 From 3f126087ee143775961947b39416aad03044c988 Mon Sep 17 00:00:00 2001 From: Nishanth Menon Date: Tue, 26 Apr 2011 02:33:10 -0700 Subject: OMAP3+: voltage: remove initial voltage Blindly setting 1.2V in the initial structure may not even match the default voltages stored in the voltage table which are supported for the domain. For example, OMAP3430 core domain does not use 1.2V and ends up generating a warning on the first transition. Further, since omap2_set_init_voltage is called as part of the pm framework's initialization sequence to configure the voltage required for the current OPP, the call does(and has to) setup the system voltage(curr_volt as a result) using the right mechanisms appropriate for the system at that point of time. This also overrides initialization we are currently doing in voltage.c making it redundant. So, remove the wrong and redundant initialization. Signed-off-by: Nishanth Menon Signed-off-by: Kevin Hilman Signed-off-by: Tony Lindgren diff --git a/arch/arm/mach-omap2/voltage.c b/arch/arm/mach-omap2/voltage.c index 6fb5209..0c1552d 100644 --- a/arch/arm/mach-omap2/voltage.c +++ b/arch/arm/mach-omap2/voltage.c @@ -114,7 +114,6 @@ static int __init _config_common_vdd_data(struct omap_vdd_info *vdd) sys_clk_speed /= 1000; /* Generic voltage parameters */ - vdd->curr_volt = 1200000; vdd->volt_scale = vp_forceupdate_scale_voltage; vdd->vp_enabled = false; -- cgit v0.10.2 From 049cfaaa47cb9b796bbc298869c0a27d434bb766 Mon Sep 17 00:00:00 2001 From: Ben Gardiner Date: Thu, 21 Apr 2011 14:19:01 -0400 Subject: ASoC: davinci-mcasp: correct tdm_slots limit The current check for the number of tdm-slots specified by platform data is always true (x >= 2 || x <= 32); therefore the else branch that warns of an incorrect number of slots can never be taken. Check that the number of tdm slots specified by platform data is between 2 and 32, inclusive. Signed-off-by: Ben Gardiner Reviewed-by: James Nuss Acked-by: Liam Girdwood Signed-off-by: Mark Brown diff --git a/sound/soc/davinci/davinci-mcasp.c b/sound/soc/davinci/davinci-mcasp.c index a5af834..1456a17 100644 --- a/sound/soc/davinci/davinci-mcasp.c +++ b/sound/soc/davinci/davinci-mcasp.c @@ -644,7 +644,7 @@ static void davinci_hw_param(struct davinci_audio_dev *dev, int stream) mcasp_set_reg(dev->base + DAVINCI_MCASP_TXTDM_REG, mask); mcasp_set_bits(dev->base + DAVINCI_MCASP_TXFMT_REG, TXORD); - if ((dev->tdm_slots >= 2) || (dev->tdm_slots <= 32)) + if ((dev->tdm_slots >= 2) && (dev->tdm_slots <= 32)) mcasp_mod_bits(dev->base + DAVINCI_MCASP_TXFMCTL_REG, FSXMOD(dev->tdm_slots), FSXMOD(0x1FF)); else @@ -660,7 +660,7 @@ static void davinci_hw_param(struct davinci_audio_dev *dev, int stream) AHCLKRE); mcasp_set_reg(dev->base + DAVINCI_MCASP_RXTDM_REG, mask); - if ((dev->tdm_slots >= 2) || (dev->tdm_slots <= 32)) + if ((dev->tdm_slots >= 2) && (dev->tdm_slots <= 32)) mcasp_mod_bits(dev->base + DAVINCI_MCASP_RXFMCTL_REG, FSRMOD(dev->tdm_slots), FSRMOD(0x1FF)); else -- cgit v0.10.2 From 9595c8f035829d0c5deffbfdc6819d6797b3b402 Mon Sep 17 00:00:00 2001 From: Ben Gardiner Date: Thu, 21 Apr 2011 14:19:02 -0400 Subject: davinci-mcasp: use bitfield definitions for PDIR The current driver creates value for set/clr of PDIR using (x<<26) instead of the #defines that are convieniently made available. Update the driver to use the bitfield definitions of PDIR. There is no functional change introduced by this patch. Signed-off-by: Ben Gardiner Reviewed-by: James Nuss Acked-by: Liam Girdwood Signed-off-by: Mark Brown diff --git a/sound/soc/davinci/davinci-mcasp.c b/sound/soc/davinci/davinci-mcasp.c index 1456a17..2b637e0 100644 --- a/sound/soc/davinci/davinci-mcasp.c +++ b/sound/soc/davinci/davinci-mcasp.c @@ -434,7 +434,8 @@ static int davinci_mcasp_set_dai_fmt(struct snd_soc_dai *cpu_dai, mcasp_set_bits(base + DAVINCI_MCASP_ACLKRCTL_REG, ACLKRE); mcasp_set_bits(base + DAVINCI_MCASP_RXFMCTL_REG, AFSRE); - mcasp_set_bits(base + DAVINCI_MCASP_PDIR_REG, (0x7 << 26)); + mcasp_set_bits(base + DAVINCI_MCASP_PDIR_REG, + ACLKX | AHCLKX | AFSX); break; case SND_SOC_DAIFMT_CBM_CFS: /* codec is clock master and frame slave */ @@ -444,7 +445,8 @@ static int davinci_mcasp_set_dai_fmt(struct snd_soc_dai *cpu_dai, mcasp_set_bits(base + DAVINCI_MCASP_ACLKRCTL_REG, ACLKRE); mcasp_set_bits(base + DAVINCI_MCASP_RXFMCTL_REG, AFSRE); - mcasp_set_bits(base + DAVINCI_MCASP_PDIR_REG, (0x2d << 26)); + mcasp_set_bits(base + DAVINCI_MCASP_PDIR_REG, + ACLKX | AFSX | ACLKR | AFSR); break; case SND_SOC_DAIFMT_CBM_CFM: /* codec is clock and frame master */ @@ -454,7 +456,8 @@ static int davinci_mcasp_set_dai_fmt(struct snd_soc_dai *cpu_dai, mcasp_clr_bits(base + DAVINCI_MCASP_ACLKRCTL_REG, ACLKRE); mcasp_clr_bits(base + DAVINCI_MCASP_RXFMCTL_REG, AFSRE); - mcasp_clr_bits(base + DAVINCI_MCASP_PDIR_REG, (0x3f << 26)); + mcasp_clr_bits(base + DAVINCI_MCASP_PDIR_REG, + ACLKX | AHCLKX | AFSX | ACLKR | AHCLKR | AFSR); break; default: -- cgit v0.10.2 From a90f549e25fa77544aaff18bdf534912f3090d39 Mon Sep 17 00:00:00 2001 From: Ben Gardiner Date: Thu, 21 Apr 2011 14:19:03 -0400 Subject: davinci-mcasp: fix _CBM_CFS hw_params The current davinci_mcasp_set_dai_fmt() sets bits ACLKXE and ACLKRE (CLKXM and CLKRM as they are reffered to in SPRUFM1 [1]) for codec clock-slave/ frame-slave mode (_CBS_CFS) which selects internally generated bit-clock and frame-sync signals; however, it does the same thing again for codec clock-master/frame-slave mode (_CBM_CFS) in the very next case statement which is incorrectly selecting internally generated bit-clocks in this mode. For codec clock-master/frame-slave mode (_CBM_CFS), clear bits ACLKXE and ACLKRE to select externally-generated bit-clocks. [1] http://www.ti.com/litv/pdf/sprufm1 Signed-off-by: Ben Gardiner Reviewed-by: James Nuss Acked-by: Liam Girdwood Signed-off-by: Mark Brown diff --git a/sound/soc/davinci/davinci-mcasp.c b/sound/soc/davinci/davinci-mcasp.c index 2b637e0..09c4ff9 100644 --- a/sound/soc/davinci/davinci-mcasp.c +++ b/sound/soc/davinci/davinci-mcasp.c @@ -439,10 +439,10 @@ static int davinci_mcasp_set_dai_fmt(struct snd_soc_dai *cpu_dai, break; case SND_SOC_DAIFMT_CBM_CFS: /* codec is clock master and frame slave */ - mcasp_set_bits(base + DAVINCI_MCASP_ACLKXCTL_REG, ACLKXE); + mcasp_clr_bits(base + DAVINCI_MCASP_ACLKXCTL_REG, ACLKXE); mcasp_set_bits(base + DAVINCI_MCASP_TXFMCTL_REG, AFSXE); - mcasp_set_bits(base + DAVINCI_MCASP_ACLKRCTL_REG, ACLKRE); + mcasp_clr_bits(base + DAVINCI_MCASP_ACLKRCTL_REG, ACLKRE); mcasp_set_bits(base + DAVINCI_MCASP_RXFMCTL_REG, AFSRE); mcasp_set_bits(base + DAVINCI_MCASP_PDIR_REG, -- cgit v0.10.2 From db92f43745dc07acd05ca64a06075801c042cb57 Mon Sep 17 00:00:00 2001 From: Ben Gardiner Date: Thu, 21 Apr 2011 14:19:04 -0400 Subject: davinci-mcasp: fix _CBM_CFS pin directions The current davinci_mcasp_set_dai_fmt() sets bits ACLKX and ACLKR in the PDIR register for the codec clock-master/frame-slave mode; however, this results in the ACLKX and ACLKR pins being outputs according to SPRUFM1 [1] which conflicts with "codec is clock master." Similarly to the previous patch in this series, "fix _CBM_CFS hw_params" -- For codec clock-master/frame-slave mode (_CMB_CFS), clear bits ACLKX and ACLKR in the PDIR register to set the pins as inputs and hence allow externally sourced bit-clocks. [1] http://www.ti.com/litv/pdf/sprufm1 Signed-off-by: Ben Gardiner Reviewed-by: James Nuss Acked-by: Liam Girdwood Signed-off-by: Mark Brown diff --git a/sound/soc/davinci/davinci-mcasp.c b/sound/soc/davinci/davinci-mcasp.c index 09c4ff9..4ddc6d3 100644 --- a/sound/soc/davinci/davinci-mcasp.c +++ b/sound/soc/davinci/davinci-mcasp.c @@ -445,8 +445,10 @@ static int davinci_mcasp_set_dai_fmt(struct snd_soc_dai *cpu_dai, mcasp_clr_bits(base + DAVINCI_MCASP_ACLKRCTL_REG, ACLKRE); mcasp_set_bits(base + DAVINCI_MCASP_RXFMCTL_REG, AFSRE); + mcasp_clr_bits(base + DAVINCI_MCASP_PDIR_REG, + ACLKX | ACLKR); mcasp_set_bits(base + DAVINCI_MCASP_PDIR_REG, - ACLKX | AFSX | ACLKR | AFSR); + AFSX | AFSR); break; case SND_SOC_DAIFMT_CBM_CFM: /* codec is clock and frame master */ -- cgit v0.10.2 From 1437f5bca3c2d162f058cba37dfbeb20f619040d Mon Sep 17 00:00:00 2001 From: Hillf Danton Date: Sat, 23 Apr 2011 21:29:05 +0800 Subject: sched: Remove noop in alloc_rt_sched_group() The rq varible, though computed for each possible cpu, has nothing to do in the function, so it can be removed. This also eliminates a build warning. Signed-off-by: Hillf Danton Reviewed-by: Yong Zhang Signed-off-by: Peter Zijlstra Link: http://lkml.kernel.org/r/BANLkTin-FfQfqW5ym1iuEmrk8s777Y1LAg@mail.gmail.com Signed-off-by: Ingo Molnar diff --git a/kernel/sched.c b/kernel/sched.c index 9cde2dd..f11a2a5 100644 --- a/kernel/sched.c +++ b/kernel/sched.c @@ -8226,7 +8226,6 @@ int alloc_rt_sched_group(struct task_group *tg, struct task_group *parent) { struct rt_rq *rt_rq; struct sched_rt_entity *rt_se; - struct rq *rq; int i; tg->rt_rq = kzalloc(sizeof(rt_rq) * nr_cpu_ids, GFP_KERNEL); @@ -8240,8 +8239,6 @@ int alloc_rt_sched_group(struct task_group *tg, struct task_group *parent) ktime_to_ns(def_rt_bandwidth.rt_period), 0); for_each_possible_cpu(i) { - rq = cpu_rq(i); - rt_rq = kzalloc_node(sizeof(struct rt_rq), GFP_KERNEL, cpu_to_node(i)); if (!rt_rq) -- cgit v0.10.2 From 18a073a3acd3a47fbb5e23333df7fad28d576345 Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Tue, 26 Apr 2011 13:24:33 +0200 Subject: perf, x86: Fix BTS condition Currently the x86 backend incorrectly assumes that any BRANCH_INSN with sample_period==1 is a BTS request. This is not true when we do frequency driven profiling such as 'perf record -e branches'. Solves this error: $ perf record -e branches ./array Error: sys_perf_event_open() syscall returned with 95 (Operation not supported). Signed-off-by: Peter Zijlstra Reported-by: Ingo Molnar Cc: "Metzger, Markus T" Cc: Peter Zijlstra Cc: Arnaldo Carvalho de Melo Cc: Frederic Weisbecker Link: http://lkml.kernel.org/n/tip-rd2y4ct71hjawzz6fpvsy9hg@git.kernel.org Signed-off-by: Ingo Molnar diff --git a/arch/x86/kernel/cpu/perf_event.c b/arch/x86/kernel/cpu/perf_event.c index 632e5dc..fac0654 100644 --- a/arch/x86/kernel/cpu/perf_event.c +++ b/arch/x86/kernel/cpu/perf_event.c @@ -613,8 +613,8 @@ static int x86_setup_perfctr(struct perf_event *event) /* * Branch tracing: */ - if ((attr->config == PERF_COUNT_HW_BRANCH_INSTRUCTIONS) && - (hwc->sample_period == 1)) { + if (attr->config == PERF_COUNT_HW_BRANCH_INSTRUCTIONS && + !attr->freq && hwc->sample_period == 1) { /* BTS is not supported by this architecture. */ if (!x86_pmu.bts_active) return -EOPNOTSUPP; diff --git a/arch/x86/kernel/cpu/perf_event_intel.c b/arch/x86/kernel/cpu/perf_event_intel.c index 43fa20b..9194b06 100644 --- a/arch/x86/kernel/cpu/perf_event_intel.c +++ b/arch/x86/kernel/cpu/perf_event_intel.c @@ -998,6 +998,9 @@ intel_bts_constraints(struct perf_event *event) struct hw_perf_event *hwc = &event->hw; unsigned int hw_event, bts_event; + if (event->attr.freq) + return NULL; + hw_event = hwc->config & INTEL_ARCH_EVENT_MASK; bts_event = x86_pmu.event_map(PERF_COUNT_HW_BRANCH_INSTRUCTIONS); -- cgit v0.10.2 From aa1f465225384b276e150238472a5452c4f92a84 Mon Sep 17 00:00:00 2001 From: Seth Heasley Date: Wed, 20 Apr 2011 10:56:20 -0700 Subject: watchdog: iTCO_wdt: TCO Watchdog patch for Intel Panther Point PCH This patch adds the TCO Watchdog DeviceIDs for the Intel Panther Point PCH. Signed-off-by: Seth Heasley Signed-off-by: Wim Van Sebroeck diff --git a/drivers/watchdog/iTCO_wdt.c b/drivers/watchdog/iTCO_wdt.c index 35a0d12..5fd020d 100644 --- a/drivers/watchdog/iTCO_wdt.c +++ b/drivers/watchdog/iTCO_wdt.c @@ -35,6 +35,7 @@ * document number 324645-001, 324646-001: Cougar Point (CPT) * document number TBD : Patsburg (PBG) * document number TBD : DH89xxCC + * document number TBD : Panther Point */ /* @@ -153,6 +154,38 @@ enum iTCO_chipsets { TCO_PBG1, /* Patsburg */ TCO_PBG2, /* Patsburg */ TCO_DH89XXCC, /* DH89xxCC */ + TCO_PPT0, /* Panther Point */ + TCO_PPT1, /* Panther Point */ + TCO_PPT2, /* Panther Point */ + TCO_PPT3, /* Panther Point */ + TCO_PPT4, /* Panther Point */ + TCO_PPT5, /* Panther Point */ + TCO_PPT6, /* Panther Point */ + TCO_PPT7, /* Panther Point */ + TCO_PPT8, /* Panther Point */ + TCO_PPT9, /* Panther Point */ + TCO_PPT10, /* Panther Point */ + TCO_PPT11, /* Panther Point */ + TCO_PPT12, /* Panther Point */ + TCO_PPT13, /* Panther Point */ + TCO_PPT14, /* Panther Point */ + TCO_PPT15, /* Panther Point */ + TCO_PPT16, /* Panther Point */ + TCO_PPT17, /* Panther Point */ + TCO_PPT18, /* Panther Point */ + TCO_PPT19, /* Panther Point */ + TCO_PPT20, /* Panther Point */ + TCO_PPT21, /* Panther Point */ + TCO_PPT22, /* Panther Point */ + TCO_PPT23, /* Panther Point */ + TCO_PPT24, /* Panther Point */ + TCO_PPT25, /* Panther Point */ + TCO_PPT26, /* Panther Point */ + TCO_PPT27, /* Panther Point */ + TCO_PPT28, /* Panther Point */ + TCO_PPT29, /* Panther Point */ + TCO_PPT30, /* Panther Point */ + TCO_PPT31, /* Panther Point */ }; static struct { @@ -244,6 +277,38 @@ static struct { {"Patsburg", 2}, {"Patsburg", 2}, {"DH89xxCC", 2}, + {"Panther Point", 2}, + {"Panther Point", 2}, + {"Panther Point", 2}, + {"Panther Point", 2}, + {"Panther Point", 2}, + {"Panther Point", 2}, + {"Panther Point", 2}, + {"Panther Point", 2}, + {"Panther Point", 2}, + {"Panther Point", 2}, + {"Panther Point", 2}, + {"Panther Point", 2}, + {"Panther Point", 2}, + {"Panther Point", 2}, + {"Panther Point", 2}, + {"Panther Point", 2}, + {"Panther Point", 2}, + {"Panther Point", 2}, + {"Panther Point", 2}, + {"Panther Point", 2}, + {"Panther Point", 2}, + {"Panther Point", 2}, + {"Panther Point", 2}, + {"Panther Point", 2}, + {"Panther Point", 2}, + {"Panther Point", 2}, + {"Panther Point", 2}, + {"Panther Point", 2}, + {"Panther Point", 2}, + {"Panther Point", 2}, + {"Panther Point", 2}, + {"Panther Point", 2}, {NULL, 0} }; @@ -363,6 +428,38 @@ static DEFINE_PCI_DEVICE_TABLE(iTCO_wdt_pci_tbl) = { { ITCO_PCI_DEVICE(0x1d40, TCO_PBG1)}, { ITCO_PCI_DEVICE(0x1d41, TCO_PBG2)}, { ITCO_PCI_DEVICE(0x2310, TCO_DH89XXCC)}, + { ITCO_PCI_DEVICE(0x1e40, TCO_PPT0)}, + { ITCO_PCI_DEVICE(0x1e41, TCO_PPT1)}, + { ITCO_PCI_DEVICE(0x1e42, TCO_PPT2)}, + { ITCO_PCI_DEVICE(0x1e43, TCO_PPT3)}, + { ITCO_PCI_DEVICE(0x1e44, TCO_PPT4)}, + { ITCO_PCI_DEVICE(0x1e45, TCO_PPT5)}, + { ITCO_PCI_DEVICE(0x1e46, TCO_PPT6)}, + { ITCO_PCI_DEVICE(0x1e47, TCO_PPT7)}, + { ITCO_PCI_DEVICE(0x1e48, TCO_PPT8)}, + { ITCO_PCI_DEVICE(0x1e49, TCO_PPT9)}, + { ITCO_PCI_DEVICE(0x1e4a, TCO_PPT10)}, + { ITCO_PCI_DEVICE(0x1e4b, TCO_PPT11)}, + { ITCO_PCI_DEVICE(0x1e4c, TCO_PPT12)}, + { ITCO_PCI_DEVICE(0x1e4d, TCO_PPT13)}, + { ITCO_PCI_DEVICE(0x1e4e, TCO_PPT14)}, + { ITCO_PCI_DEVICE(0x1e4f, TCO_PPT15)}, + { ITCO_PCI_DEVICE(0x1e50, TCO_PPT16)}, + { ITCO_PCI_DEVICE(0x1e51, TCO_PPT17)}, + { ITCO_PCI_DEVICE(0x1e52, TCO_PPT18)}, + { ITCO_PCI_DEVICE(0x1e53, TCO_PPT19)}, + { ITCO_PCI_DEVICE(0x1e54, TCO_PPT20)}, + { ITCO_PCI_DEVICE(0x1e55, TCO_PPT21)}, + { ITCO_PCI_DEVICE(0x1e56, TCO_PPT22)}, + { ITCO_PCI_DEVICE(0x1e57, TCO_PPT23)}, + { ITCO_PCI_DEVICE(0x1e58, TCO_PPT24)}, + { ITCO_PCI_DEVICE(0x1e59, TCO_PPT25)}, + { ITCO_PCI_DEVICE(0x1e5a, TCO_PPT26)}, + { ITCO_PCI_DEVICE(0x1e5b, TCO_PPT27)}, + { ITCO_PCI_DEVICE(0x1e5c, TCO_PPT28)}, + { ITCO_PCI_DEVICE(0x1e5d, TCO_PPT29)}, + { ITCO_PCI_DEVICE(0x1e5e, TCO_PPT30)}, + { ITCO_PCI_DEVICE(0x1e5f, TCO_PPT31)}, { 0, }, /* End of list */ }; MODULE_DEVICE_TABLE(pci, iTCO_wdt_pci_tbl); -- cgit v0.10.2 From f030ddfb3752df36bb73285353374fc04feabb80 Mon Sep 17 00:00:00 2001 From: Borislav Petkov Date: Fri, 8 Apr 2011 15:05:21 +0200 Subject: amd64_edac: Remove node interleave warning This warning was wrongfully added for a normal condition - intlvsel actually selects the destination node when node interleaving is enabled and it is not a mismatch. For a detailed example, see section 2.8.10.2 "Node Interleaving" in F10h BKDG. Signed-off-by: Borislav Petkov diff --git a/drivers/edac/amd64_edac.c b/drivers/edac/amd64_edac.c index 4b4071e..601142a 100644 --- a/drivers/edac/amd64_edac.c +++ b/drivers/edac/amd64_edac.c @@ -1401,12 +1401,8 @@ static int f1x_match_to_this_node(struct amd64_pvt *pvt, unsigned range, return -EINVAL; } - if (intlv_en && - (intlv_sel != ((sys_addr >> 12) & intlv_en))) { - amd64_warn("Botched intlv bits, en: 0x%x, sel: 0x%x\n", - intlv_en, intlv_sel); + if (intlv_en && (intlv_sel != ((sys_addr >> 12) & intlv_en))) return -EINVAL; - } sys_addr = f1x_swap_interleaved_region(pvt, sys_addr); -- cgit v0.10.2 From f08e457cecece7fbbdad3add9defac3373a59b5a Mon Sep 17 00:00:00 2001 From: Borislav Petkov Date: Mon, 21 Mar 2011 20:45:06 +0100 Subject: amd64_edac: Factor in CC6 save area F15h and later use a portion of DRAM as a CC6 storage area. BIOS programs D18F1x[17C:140,7C:40] DRAM Base/Limit accordingly by subtracting the storage area from the DRAM limit setting. However, in order for edac to consider that part of DRAM too, we need to include it into the per-node range. Signed-off-by: Borislav Petkov diff --git a/drivers/edac/amd64_edac.c b/drivers/edac/amd64_edac.c index 601142a..e17de90b 100644 --- a/drivers/edac/amd64_edac.c +++ b/drivers/edac/amd64_edac.c @@ -944,12 +944,13 @@ static u64 get_error_address(struct mce *m) static void read_dram_base_limit_regs(struct amd64_pvt *pvt, unsigned range) { + struct cpuinfo_x86 *c = &boot_cpu_data; int off = range << 3; amd64_read_pci_cfg(pvt->F1, DRAM_BASE_LO + off, &pvt->ranges[range].base.lo); amd64_read_pci_cfg(pvt->F1, DRAM_LIMIT_LO + off, &pvt->ranges[range].lim.lo); - if (boot_cpu_data.x86 == 0xf) + if (c->x86 == 0xf) return; if (!dram_rw(pvt, range)) @@ -957,6 +958,31 @@ static void read_dram_base_limit_regs(struct amd64_pvt *pvt, unsigned range) amd64_read_pci_cfg(pvt->F1, DRAM_BASE_HI + off, &pvt->ranges[range].base.hi); amd64_read_pci_cfg(pvt->F1, DRAM_LIMIT_HI + off, &pvt->ranges[range].lim.hi); + + /* Factor in CC6 save area by reading dst node's limit reg */ + if (c->x86 == 0x15) { + struct pci_dev *f1 = NULL; + u8 nid = dram_dst_node(pvt, range); + u32 llim; + + f1 = pci_get_domain_bus_and_slot(0, 0, PCI_DEVFN(0x18 + nid, 1)); + if (WARN_ON(!f1)) + return; + + amd64_read_pci_cfg(f1, DRAM_LOCAL_NODE_LIM, &llim); + + pvt->ranges[range].lim.lo &= GENMASK(0, 15); + + /* {[39:27],111b} */ + pvt->ranges[range].lim.lo |= ((llim & 0x1fff) << 3 | 0x7) << 16; + + pvt->ranges[range].lim.hi &= GENMASK(0, 7); + + /* [47:40] */ + pvt->ranges[range].lim.hi |= llim >> 13; + + pci_dev_put(f1); + } } static void k8_map_sysaddr_to_csrow(struct mem_ctl_info *mci, u64 sys_addr, diff --git a/drivers/edac/amd64_edac.h b/drivers/edac/amd64_edac.h index 11be36a..0110930 100644 --- a/drivers/edac/amd64_edac.h +++ b/drivers/edac/amd64_edac.h @@ -196,6 +196,8 @@ #define DCT_CFG_SEL 0x10C +#define DRAM_LOCAL_NODE_LIM 0x124 + #define DRAM_BASE_HI 0x140 #define DRAM_LIMIT_HI 0x144 -- cgit v0.10.2 From c1ae68309b0c1ea67b72e9e94e26b4e819022fc7 Mon Sep 17 00:00:00 2001 From: Borislav Petkov Date: Wed, 30 Mar 2011 15:42:10 +0200 Subject: amd64_edac: Erratum #637 workaround F15h CPUs may report a non-DRAM address when reporting an error address belonging to a CC6 state save area. Add a workaround to detect this condition and compute the actual DRAM address of the error as documented in the Revision Guide for AMD Family 15h Models 00h-0Fh Processors. Signed-off-by: Borislav Petkov diff --git a/drivers/edac/amd64_edac.c b/drivers/edac/amd64_edac.c index e17de90b..9a8bebc 100644 --- a/drivers/edac/amd64_edac.c +++ b/drivers/edac/amd64_edac.c @@ -931,15 +931,63 @@ static int k8_early_channel_count(struct amd64_pvt *pvt) /* On F10h and later ErrAddr is MC4_ADDR[47:1] */ static u64 get_error_address(struct mce *m) { + struct cpuinfo_x86 *c = &boot_cpu_data; + u64 addr; u8 start_bit = 1; u8 end_bit = 47; - if (boot_cpu_data.x86 == 0xf) { + if (c->x86 == 0xf) { start_bit = 3; end_bit = 39; } - return m->addr & GENMASK(start_bit, end_bit); + addr = m->addr & GENMASK(start_bit, end_bit); + + /* + * Erratum 637 workaround + */ + if (c->x86 == 0x15) { + struct amd64_pvt *pvt; + u64 cc6_base, tmp_addr; + u32 tmp; + u8 mce_nid, intlv_en; + + if ((addr & GENMASK(24, 47)) >> 24 != 0x00fdf7) + return addr; + + mce_nid = amd_get_nb_id(m->extcpu); + pvt = mcis[mce_nid]->pvt_info; + + amd64_read_pci_cfg(pvt->F1, DRAM_LOCAL_NODE_LIM, &tmp); + intlv_en = tmp >> 21 & 0x7; + + /* add [47:27] + 3 trailing bits */ + cc6_base = (tmp & GENMASK(0, 20)) << 3; + + /* reverse and add DramIntlvEn */ + cc6_base |= intlv_en ^ 0x7; + + /* pin at [47:24] */ + cc6_base <<= 24; + + if (!intlv_en) + return cc6_base | (addr & GENMASK(0, 23)); + + amd64_read_pci_cfg(pvt->F1, DRAM_LOCAL_NODE_BASE, &tmp); + + /* faster log2 */ + tmp_addr = (addr & GENMASK(12, 23)) << __fls(intlv_en + 1); + + /* OR DramIntlvSel into bits [14:12] */ + tmp_addr |= (tmp & GENMASK(21, 23)) >> 9; + + /* add remaining [11:0] bits from original MC4_ADDR */ + tmp_addr |= addr & GENMASK(0, 11); + + return cc6_base | tmp_addr; + } + + return addr; } static void read_dram_base_limit_regs(struct amd64_pvt *pvt, unsigned range) diff --git a/drivers/edac/amd64_edac.h b/drivers/edac/amd64_edac.h index 0110930..9a666cb 100644 --- a/drivers/edac/amd64_edac.h +++ b/drivers/edac/amd64_edac.h @@ -196,6 +196,7 @@ #define DCT_CFG_SEL 0x10C +#define DRAM_LOCAL_NODE_BASE 0x120 #define DRAM_LOCAL_NODE_LIM 0x124 #define DRAM_BASE_HI 0x140 -- cgit v0.10.2 From ec75a71634dabe439db91c1ef51d5099f4493808 Mon Sep 17 00:00:00 2001 From: Ingo Molnar Date: Wed, 27 Apr 2011 11:51:41 +0200 Subject: perf events, x86: Work around the Nehalem AAJ80 erratum On Nehalem CPUs the retired branch-misses event can be completely bogus, when there are no branch-misses occuring. When there are a lot of branch misses then the count is pretty accurate. Still, this leaves us with an event that over-counts a lot. Detect this erratum and work it around by using BR_MISP_EXEC.ANY events. These will also count speculated branches but still it's a lot more precise in practice than the architectural event. Acked-by: Peter Zijlstra Cc: Arnaldo Carvalho de Melo Cc: Frederic Weisbecker Link: http://lkml.kernel.org/n/tip-yyfg0bxo9jsqxd6a0ovfny27@git.kernel.org Signed-off-by: Ingo Molnar diff --git a/arch/x86/kernel/cpu/perf_event_intel.c b/arch/x86/kernel/cpu/perf_event_intel.c index 9194b06..9ae4a2a 100644 --- a/arch/x86/kernel/cpu/perf_event_intel.c +++ b/arch/x86/kernel/cpu/perf_event_intel.c @@ -25,7 +25,7 @@ struct intel_percore { /* * Intel PerfMon, used on Core and later. */ -static const u64 intel_perfmon_event_map[] = +static u64 intel_perfmon_event_map[PERF_COUNT_HW_MAX] __read_mostly = { [PERF_COUNT_HW_CPU_CYCLES] = 0x003c, [PERF_COUNT_HW_INSTRUCTIONS] = 0x00c0, @@ -1308,7 +1308,7 @@ static void intel_clovertown_quirks(void) * AJ106 could possibly be worked around by not allowing LBR * usage from PEBS, including the fixup. * AJ68 could possibly be worked around by always programming - * a pebs_event_reset[0] value and coping with the lost events. + * a pebs_event_reset[0] value and coping with the lost events. * * But taken together it might just make sense to not enable PEBS on * these chips. @@ -1412,6 +1412,18 @@ static __init int intel_pmu_init(void) x86_pmu.percore_constraints = intel_nehalem_percore_constraints; x86_pmu.enable_all = intel_pmu_nhm_enable_all; x86_pmu.extra_regs = intel_nehalem_extra_regs; + + if (ebx & 0x40) { + /* + * Erratum AAJ80 detected, we work it around by using + * the BR_MISP_EXEC.ANY event. This will over-count + * branch-misses, but it's still much better than the + * architectural event which is often completely bogus: + */ + intel_perfmon_event_map[PERF_COUNT_HW_BRANCH_MISSES] = 0x7f89; + + pr_cont("erratum AAJ80 worked around, "); + } pr_cont("Nehalem events, "); break; -- cgit v0.10.2 From 94403f8863d0d1d2005291b2ef0719c2534aa303 Mon Sep 17 00:00:00 2001 From: Ingo Molnar Date: Sun, 24 Apr 2011 08:18:31 +0200 Subject: perf events: Add stalled cycles generic event - PERF_COUNT_HW_STALLED_CYCLES The new PERF_COUNT_HW_STALLED_CYCLES event tries to approximate cycles the CPU does nothing useful, because it is stalled on a cache-miss or some other condition. Acked-by: Peter Zijlstra Acked-by: Arnaldo Carvalho de Melo Cc: Frederic Weisbecker Link: http://lkml.kernel.org/n/tip-fue11vymwqsoo5to72jxxjyl@git.kernel.org Signed-off-by: Ingo Molnar diff --git a/arch/x86/kernel/cpu/perf_event_intel.c b/arch/x86/kernel/cpu/perf_event_intel.c index 9ae4a2a..efa2704 100644 --- a/arch/x86/kernel/cpu/perf_event_intel.c +++ b/arch/x86/kernel/cpu/perf_event_intel.c @@ -1413,6 +1413,9 @@ static __init int intel_pmu_init(void) x86_pmu.enable_all = intel_pmu_nhm_enable_all; x86_pmu.extra_regs = intel_nehalem_extra_regs; + /* Install the stalled-cycles event: 0xff: All reasons, 0xa2: Resource stalls */ + intel_perfmon_event_map[PERF_COUNT_HW_STALLED_CYCLES] = 0xffa2; + if (ebx & 0x40) { /* * Erratum AAJ80 detected, we work it around by using diff --git a/include/linux/perf_event.h b/include/linux/perf_event.h index ee9f1e7..ac636dd 100644 --- a/include/linux/perf_event.h +++ b/include/linux/perf_event.h @@ -52,6 +52,7 @@ enum perf_hw_id { PERF_COUNT_HW_BRANCH_INSTRUCTIONS = 4, PERF_COUNT_HW_BRANCH_MISSES = 5, PERF_COUNT_HW_BUS_CYCLES = 6, + PERF_COUNT_HW_STALLED_CYCLES = 7, PERF_COUNT_HW_MAX, /* non-ABI */ }; diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c index 952b4ae..1869e4c 100644 --- a/tools/perf/util/parse-events.c +++ b/tools/perf/util/parse-events.c @@ -38,6 +38,7 @@ static struct event_symbol event_symbols[] = { { CHW(BRANCH_INSTRUCTIONS), "branch-instructions", "branches" }, { CHW(BRANCH_MISSES), "branch-misses", "" }, { CHW(BUS_CYCLES), "bus-cycles", "" }, + { CHW(STALLED_CYCLES), "stalled-cycles", "" }, { CSW(CPU_CLOCK), "cpu-clock", "" }, { CSW(TASK_CLOCK), "task-clock", "" }, diff --git a/tools/perf/util/python.c b/tools/perf/util/python.c index f5e3845..406f613 100644 --- a/tools/perf/util/python.c +++ b/tools/perf/util/python.c @@ -798,6 +798,7 @@ static struct { { "COUNT_HW_BRANCH_INSTRUCTIONS", PERF_COUNT_HW_BRANCH_INSTRUCTIONS }, { "COUNT_HW_BRANCH_MISSES", PERF_COUNT_HW_BRANCH_MISSES }, { "COUNT_HW_BUS_CYCLES", PERF_COUNT_HW_BUS_CYCLES }, + { "COUNT_HW_STALLED_CYCLES", PERF_COUNT_HW_STALLED_CYCLES }, { "COUNT_HW_CACHE_L1D", PERF_COUNT_HW_CACHE_L1D }, { "COUNT_HW_CACHE_L1I", PERF_COUNT_HW_CACHE_L1I }, { "COUNT_HW_CACHE_LL", PERF_COUNT_HW_CACHE_LL }, -- cgit v0.10.2 From 5c543e3c442d6382db127152c7096ca6a55283de Mon Sep 17 00:00:00 2001 From: Ingo Molnar Date: Wed, 27 Apr 2011 12:02:04 +0200 Subject: perf events, x86: Mark constrant tables read mostly Various constraint tables were not marked read-mostly. Acked-by: Peter Zijlstra Acked-by: Arnaldo Carvalho de Melo Cc: Frederic Weisbecker Link: http://lkml.kernel.org/n/tip-wpqwwvmhxucy5e718wnamjiv@git.kernel.org Signed-off-by: Ingo Molnar diff --git a/arch/x86/kernel/cpu/perf_event_intel.c b/arch/x86/kernel/cpu/perf_event_intel.c index efa2704..067a48b 100644 --- a/arch/x86/kernel/cpu/perf_event_intel.c +++ b/arch/x86/kernel/cpu/perf_event_intel.c @@ -36,7 +36,7 @@ static u64 intel_perfmon_event_map[PERF_COUNT_HW_MAX] __read_mostly = [PERF_COUNT_HW_BUS_CYCLES] = 0x013c, }; -static struct event_constraint intel_core_event_constraints[] = +static struct event_constraint intel_core_event_constraints[] __read_mostly = { INTEL_EVENT_CONSTRAINT(0x11, 0x2), /* FP_ASSIST */ INTEL_EVENT_CONSTRAINT(0x12, 0x2), /* MUL */ @@ -47,7 +47,7 @@ static struct event_constraint intel_core_event_constraints[] = EVENT_CONSTRAINT_END }; -static struct event_constraint intel_core2_event_constraints[] = +static struct event_constraint intel_core2_event_constraints[] __read_mostly = { FIXED_EVENT_CONSTRAINT(0x00c0, 0), /* INST_RETIRED.ANY */ FIXED_EVENT_CONSTRAINT(0x003c, 1), /* CPU_CLK_UNHALTED.CORE */ @@ -70,7 +70,7 @@ static struct event_constraint intel_core2_event_constraints[] = EVENT_CONSTRAINT_END }; -static struct event_constraint intel_nehalem_event_constraints[] = +static struct event_constraint intel_nehalem_event_constraints[] __read_mostly = { FIXED_EVENT_CONSTRAINT(0x00c0, 0), /* INST_RETIRED.ANY */ FIXED_EVENT_CONSTRAINT(0x003c, 1), /* CPU_CLK_UNHALTED.CORE */ @@ -86,19 +86,19 @@ static struct event_constraint intel_nehalem_event_constraints[] = EVENT_CONSTRAINT_END }; -static struct extra_reg intel_nehalem_extra_regs[] = +static struct extra_reg intel_nehalem_extra_regs[] __read_mostly = { INTEL_EVENT_EXTRA_REG(0xb7, MSR_OFFCORE_RSP_0, 0xffff), EVENT_EXTRA_END }; -static struct event_constraint intel_nehalem_percore_constraints[] = +static struct event_constraint intel_nehalem_percore_constraints[] __read_mostly = { INTEL_EVENT_CONSTRAINT(0xb7, 0), EVENT_CONSTRAINT_END }; -static struct event_constraint intel_westmere_event_constraints[] = +static struct event_constraint intel_westmere_event_constraints[] __read_mostly = { FIXED_EVENT_CONSTRAINT(0x00c0, 0), /* INST_RETIRED.ANY */ FIXED_EVENT_CONSTRAINT(0x003c, 1), /* CPU_CLK_UNHALTED.CORE */ @@ -110,7 +110,7 @@ static struct event_constraint intel_westmere_event_constraints[] = EVENT_CONSTRAINT_END }; -static struct event_constraint intel_snb_event_constraints[] = +static struct event_constraint intel_snb_event_constraints[] __read_mostly = { FIXED_EVENT_CONSTRAINT(0x00c0, 0), /* INST_RETIRED.ANY */ FIXED_EVENT_CONSTRAINT(0x003c, 1), /* CPU_CLK_UNHALTED.CORE */ @@ -123,21 +123,21 @@ static struct event_constraint intel_snb_event_constraints[] = EVENT_CONSTRAINT_END }; -static struct extra_reg intel_westmere_extra_regs[] = +static struct extra_reg intel_westmere_extra_regs[] __read_mostly = { INTEL_EVENT_EXTRA_REG(0xb7, MSR_OFFCORE_RSP_0, 0xffff), INTEL_EVENT_EXTRA_REG(0xbb, MSR_OFFCORE_RSP_1, 0xffff), EVENT_EXTRA_END }; -static struct event_constraint intel_westmere_percore_constraints[] = +static struct event_constraint intel_westmere_percore_constraints[] __read_mostly = { INTEL_EVENT_CONSTRAINT(0xb7, 0), INTEL_EVENT_CONSTRAINT(0xbb, 0), EVENT_CONSTRAINT_END }; -static struct event_constraint intel_gen_event_constraints[] = +static struct event_constraint intel_gen_event_constraints[] __read_mostly = { FIXED_EVENT_CONSTRAINT(0x00c0, 0), /* INST_RETIRED.ANY */ FIXED_EVENT_CONSTRAINT(0x003c, 1), /* CPU_CLK_UNHALTED.CORE */ -- cgit v0.10.2 From 11ba2b85f506306c8dfc9fe144aa4ddc43242855 Mon Sep 17 00:00:00 2001 From: Ingo Molnar Date: Sun, 24 Apr 2011 15:05:10 +0200 Subject: perf stat: Print stalled cycles percentage Print: 611,527 cycles 400,553 instructions # ( 0.71 instructions per cycle ) 77,809 stalled-cycles # ( 12.71% of all cycles ) 0.000610987 seconds time elapsed Acked-by: Peter Zijlstra Acked-by: Arnaldo Carvalho de Melo Cc: Frederic Weisbecker Signed-off-by: Ingo Molnar Link: http://lkml.kernel.org/n/tip-fd6x8r1cpyb6zhlrc4ix8m45@git.kernel.org diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c index 03f0e45..3a29041 100644 --- a/tools/perf/builtin-stat.c +++ b/tools/perf/builtin-stat.c @@ -442,7 +442,7 @@ static void abs_printout(int cpu, struct perf_evsel *evsel, double avg) if (total) ratio = avg / total; - fprintf(stderr, " # %10.3f IPC ", ratio); + fprintf(stderr, " # ( %4.2f instructions per cycle )", ratio); } else if (perf_evsel__match(evsel, HARDWARE, HW_BRANCH_MISSES) && runtime_branches_stats[cpu].n != 0) { total = avg_stats(&runtime_branches_stats[cpu]); @@ -450,7 +450,7 @@ static void abs_printout(int cpu, struct perf_evsel *evsel, double avg) if (total) ratio = avg * 100 / total; - fprintf(stderr, " # %10.3f %% ", ratio); + fprintf(stderr, " # %10.3f %%", ratio); } else if (runtime_nsecs_stats[cpu].n != 0) { total = avg_stats(&runtime_nsecs_stats[cpu]); @@ -459,6 +459,13 @@ static void abs_printout(int cpu, struct perf_evsel *evsel, double avg) ratio = 1000.0 * avg / total; fprintf(stderr, " # %10.3f M/sec", ratio); + } else if (perf_evsel__match(evsel, HARDWARE, HW_STALLED_CYCLES)) { + total = avg_stats(&runtime_cycles_stats[cpu]); + + if (total) + ratio = avg / total * 100.0; + + fprintf(stderr, " # (%5.2f%% of all cycles )", ratio); } } -- cgit v0.10.2 From d58f4c82fed69fdd4a79fa54fe17fd14d98c27aa Mon Sep 17 00:00:00 2001 From: Ingo Molnar Date: Wed, 27 Apr 2011 03:42:18 +0200 Subject: perf stat: Print cache misses as percentage Before: 113,393,041 cache-references # 83.636 M/sec 7,052,454 cache-misses # 5.202 M/sec After: 112,589,441 cache-references # 87.925 M/sec 6,556,354 cache-misses # 5.823 % misses/hits percentages are more expressive than absolute numbers or rates. (Also prettify the CPUs printout line to not have a trailing whitespace.) Acked-by: Peter Zijlstra Acked-by: Arnaldo Carvalho de Melo Cc: Frederic Weisbecker Link: http://lkml.kernel.org/n/tip-axm28f43x439bl41zkvfzd63@git.kernel.org Signed-off-by: Ingo Molnar diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c index 3a29041..0de3a20 100644 --- a/tools/perf/builtin-stat.c +++ b/tools/perf/builtin-stat.c @@ -157,6 +157,7 @@ static double stddev_stats(struct stats *stats) struct stats runtime_nsecs_stats[MAX_NR_CPUS]; struct stats runtime_cycles_stats[MAX_NR_CPUS]; struct stats runtime_branches_stats[MAX_NR_CPUS]; +struct stats runtime_cacherefs_stats[MAX_NR_CPUS]; struct stats walltime_nsecs_stats; static int create_perf_stat_counter(struct perf_evsel *evsel) @@ -219,10 +220,12 @@ static int read_counter_aggr(struct perf_evsel *counter) */ if (perf_evsel__match(counter, SOFTWARE, SW_TASK_CLOCK)) update_stats(&runtime_nsecs_stats[0], count[0]); - if (perf_evsel__match(counter, HARDWARE, HW_CPU_CYCLES)) + else if (perf_evsel__match(counter, HARDWARE, HW_CPU_CYCLES)) update_stats(&runtime_cycles_stats[0], count[0]); - if (perf_evsel__match(counter, HARDWARE, HW_BRANCH_INSTRUCTIONS)) + else if (perf_evsel__match(counter, HARDWARE, HW_BRANCH_INSTRUCTIONS)) update_stats(&runtime_branches_stats[0], count[0]); + else if (perf_evsel__match(counter, HARDWARE, HW_CACHE_REFERENCES)) + update_stats(&runtime_cacherefs_stats[0], count[0]); return 0; } @@ -404,7 +407,7 @@ static void nsec_printout(int cpu, struct perf_evsel *evsel, double avg) return; if (perf_evsel__match(evsel, SOFTWARE, SW_TASK_CLOCK)) - fprintf(stderr, " # %10.3f CPUs ", + fprintf(stderr, " # %10.3f CPUs", avg / avg_stats(&walltime_nsecs_stats)); } @@ -452,6 +455,15 @@ static void abs_printout(int cpu, struct perf_evsel *evsel, double avg) fprintf(stderr, " # %10.3f %%", ratio); + } else if (perf_evsel__match(evsel, HARDWARE, HW_CACHE_MISSES) && + runtime_cacherefs_stats[cpu].n != 0) { + total = avg_stats(&runtime_cacherefs_stats[cpu]); + + if (total) + ratio = avg * 100 / total; + + fprintf(stderr, " # %10.3f %%", ratio); + } else if (runtime_nsecs_stats[cpu].n != 0) { total = avg_stats(&runtime_nsecs_stats[cpu]); -- cgit v0.10.2 From b908debd4eef91471016138569f7a9e292be682e Mon Sep 17 00:00:00 2001 From: Ingo Molnar Date: Wed, 27 Apr 2011 03:55:40 +0200 Subject: perf tools: Accept case-insensitive symbolic event variants We currently fail on something like '-e CPU-migrations', with: invalid or unsupported event: 'CPU-migrations' While 'CPU-migrations' is how we actually print out the event in the default perf stat output: Performance counter stats for 'true': 0.202204 task-clock-msecs # 0.282 CPUs 0 context-switches # 0.000 M/sec 0 CPU-migrations # 0.000 M/sec So change the matching to be case-insensitive. Acked-by: Peter Zijlstra Acked-by: Arnaldo Carvalho de Melo Cc: Frederic Weisbecker Link: http://lkml.kernel.org/n/tip-omcm3edjjtx83a4kh2e244se@git.kernel.org Signed-off-by: Ingo Molnar diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c index 1869e4c..8e54bdb 100644 --- a/tools/perf/util/parse-events.c +++ b/tools/perf/util/parse-events.c @@ -649,13 +649,15 @@ static int check_events(const char *str, unsigned int i) int n; n = strlen(event_symbols[i].symbol); - if (!strncmp(str, event_symbols[i].symbol, n)) + if (!strncasecmp(str, event_symbols[i].symbol, n)) return n; n = strlen(event_symbols[i].alias); - if (n) - if (!strncmp(str, event_symbols[i].alias, n)) + if (n) { + if (!strncasecmp(str, event_symbols[i].alias, n)) return n; + } + return 0; } -- cgit v0.10.2 From ceb53fbf6dbb1df26d38379a262c6981fe73dd36 Mon Sep 17 00:00:00 2001 From: Ingo Molnar Date: Wed, 27 Apr 2011 04:06:33 +0200 Subject: perf stat: Fail more clearly when an invalid modifier is specified Currently we fail without printing any error message on "perf stat -e task-clock-msecs". The reason is that the task-clock event is matched and the "-msecs" postfix is assumed to be an event modifier - but is not recognized. This patch changes the code to be more informative: $ perf stat -e task-clock-msecs true invalid event modifier: '-msecs' Run 'perf list' for a list of valid events and modifiers And restructures the return value of parse_event_modifier() to allow the printing of all variants of invalid event modifiers. Acked-by: Peter Zijlstra Acked-by: Arnaldo Carvalho de Melo Cc: Frederic Weisbecker Link: http://lkml.kernel.org/n/tip-wlaw3dvz1ly6wple8l52cfca@git.kernel.org Signed-off-by: Ingo Molnar diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c index 8e54bdb..b686269 100644 --- a/tools/perf/util/parse-events.c +++ b/tools/perf/util/parse-events.c @@ -721,15 +721,19 @@ parse_numeric_event(const char **strp, struct perf_event_attr *attr) return EVT_FAILED; } -static enum event_result +static int parse_event_modifier(const char **strp, struct perf_event_attr *attr) { const char *str = *strp; int exclude = 0; int eu = 0, ek = 0, eh = 0, precise = 0; - if (*str++ != ':') + if (!*str) return 0; + + if (*str++ != ':') + return -1; + while (*str) { if (*str == 'u') { if (!exclude) @@ -750,14 +754,16 @@ parse_event_modifier(const char **strp, struct perf_event_attr *attr) ++str; } - if (str >= *strp + 2) { - *strp = str; - attr->exclude_user = eu; - attr->exclude_kernel = ek; - attr->exclude_hv = eh; - attr->precise_ip = precise; - return 1; - } + if (str < *strp + 2) + return -1; + + *strp = str; + + attr->exclude_user = eu; + attr->exclude_kernel = ek; + attr->exclude_hv = eh; + attr->precise_ip = precise; + return 0; } @@ -800,7 +806,12 @@ parse_event_symbols(const struct option *opt, const char **str, return EVT_FAILED; modifier: - parse_event_modifier(str, attr); + if (parse_event_modifier(str, attr) < 0) { + fprintf(stderr, "invalid event modifier: '%s'\n", *str); + fprintf(stderr, "Run 'perf list' for a list of valid events and modifiers\n"); + + return EVT_FAILED; + } return ret; } -- cgit v0.10.2 From 749141d926faf23ef811686a8050e7cf13dc223f Mon Sep 17 00:00:00 2001 From: Ingo Molnar Date: Wed, 27 Apr 2011 04:24:57 +0200 Subject: perf stat: Make all displayed event names parseable as well Right now we display this by default: 0.202204 task-clock-msecs # 0.282 CPUs 0 context-switches # 0.000 M/sec 0 CPU-migrations # 0.000 M/sec 85 page-faults # 0.420 M/sec The task-clock-msecs event cannot actually be passed back as an event name, the event name we recognize is 'task-clock'. So change the output of the cpu-clock and task-clock events to be idempotent. ( Units should be printed out in the right-side column, if needed. ) Acked-by: Peter Zijlstra Acked-by: Arnaldo Carvalho de Melo Cc: Frederic Weisbecker Link: http://lkml.kernel.org/n/tip-lexrnbzy09asscgd4f7oac4i@git.kernel.org Signed-off-by: Ingo Molnar diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c index b686269..b5bfef1 100644 --- a/tools/perf/util/parse-events.c +++ b/tools/perf/util/parse-events.c @@ -70,8 +70,8 @@ static const char *hw_event_names[] = { }; static const char *sw_event_names[] = { - "cpu-clock-msecs", - "task-clock-msecs", + "cpu-clock", + "task-clock", "page-faults", "context-switches", "CPU-migrations", -- cgit v0.10.2 From dcd9936a5a6d89512b5323c1145647f2dbe0236f Mon Sep 17 00:00:00 2001 From: Ingo Molnar Date: Wed, 27 Apr 2011 04:36:37 +0200 Subject: perf stat: Factor our shadow stats Create update_shadow_stats() which is then used in both read_counter_aggr() and read_counter(). This not only simplifies the code but also fixes a bug: HW_CACHE_REFERENCES was not updated in read_counter(). Acked-by: Peter Zijlstra Acked-by: Arnaldo Carvalho de Melo Cc: Frederic Weisbecker Link: http://lkml.kernel.org/n/tip-9uc55z3g88r47exde7zxjm6p@git.kernel.org Signed-off-by: Ingo Molnar diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c index 0de3a20..e5e82f6 100644 --- a/tools/perf/builtin-stat.c +++ b/tools/perf/builtin-stat.c @@ -194,6 +194,23 @@ static inline int nsec_counter(struct perf_evsel *evsel) } /* + * Update various tracking values we maintain to print + * more semantic information such as miss/hit ratios, + * instruction rates, etc: + */ +static void update_shadow_stats(struct perf_evsel *counter, u64 *count) +{ + if (perf_evsel__match(counter, SOFTWARE, SW_TASK_CLOCK)) + update_stats(&runtime_nsecs_stats[0], count[0]); + else if (perf_evsel__match(counter, HARDWARE, HW_CPU_CYCLES)) + update_stats(&runtime_cycles_stats[0], count[0]); + else if (perf_evsel__match(counter, HARDWARE, HW_BRANCH_INSTRUCTIONS)) + update_stats(&runtime_branches_stats[0], count[0]); + else if (perf_evsel__match(counter, HARDWARE, HW_CACHE_REFERENCES)) + update_stats(&runtime_cacherefs_stats[0], count[0]); +} + +/* * Read out the results of a single counter: * aggregate counts across CPUs in system-wide mode */ @@ -218,14 +235,7 @@ static int read_counter_aggr(struct perf_evsel *counter) /* * Save the full runtime - to allow normalization during printout: */ - if (perf_evsel__match(counter, SOFTWARE, SW_TASK_CLOCK)) - update_stats(&runtime_nsecs_stats[0], count[0]); - else if (perf_evsel__match(counter, HARDWARE, HW_CPU_CYCLES)) - update_stats(&runtime_cycles_stats[0], count[0]); - else if (perf_evsel__match(counter, HARDWARE, HW_BRANCH_INSTRUCTIONS)) - update_stats(&runtime_branches_stats[0], count[0]); - else if (perf_evsel__match(counter, HARDWARE, HW_CACHE_REFERENCES)) - update_stats(&runtime_cacherefs_stats[0], count[0]); + update_shadow_stats(counter, count); return 0; } @@ -245,12 +255,7 @@ static int read_counter(struct perf_evsel *counter) count = counter->counts->cpu[cpu].values; - if (perf_evsel__match(counter, SOFTWARE, SW_TASK_CLOCK)) - update_stats(&runtime_nsecs_stats[cpu], count[0]); - if (perf_evsel__match(counter, HARDWARE, HW_CPU_CYCLES)) - update_stats(&runtime_cycles_stats[cpu], count[0]); - if (perf_evsel__match(counter, HARDWARE, HW_BRANCH_INSTRUCTIONS)) - update_stats(&runtime_branches_stats[cpu], count[0]); + update_shadow_stats(counter, count); } return 0; -- cgit v0.10.2 From 481f988a016f7a0327a5537bde4794349fc4625c Mon Sep 17 00:00:00 2001 From: Ingo Molnar Date: Wed, 27 Apr 2011 04:34:16 +0200 Subject: perf stat: Add stalled cycles accounting, prettify the resulting output Add stalled cycles accounting and use it to print the "cycles stalled per instruction" value. Also change the unit of the cycles output from M/sec to GHz - this is more intuitive. Prettify the output to: Performance counter stats for './loop_1b_instructions': 239.775036 task-clock # 0.997 CPUs utilized 761,903,912 cycles # 3.178 GHz 356,620,620 stalled-cycles # 46.81% of all cycles are idle 1,001,578,351 instructions # 1.31 insns per cycle # 0.36 stalled cycles per insn 14,782 cache-references # 0.062 M/sec 5,694 cache-misses # 38.520 % of all cache refs 0.240493656 seconds time elapsed Also adjust the --repeat output to make the percentages align vertically: Performance counter stats for './loop_1b_instructions' (10 runs): 236.096793 task-clock # 0.997 CPUs utilized ( +- 0.011% ) 756,553,086 cycles # 3.204 GHz ( +- 0.002% ) 354,942,692 stalled-cycles # 46.92% of all cycles are idle ( +- 0.008% ) 1,001,389,700 instructions # 1.32 insns per cycle # 0.35 stalled cycles per insn ( +- 0.000% ) 10,166 cache-references # 0.043 M/sec ( +- 0.742% ) 468 cache-misses # 4.608 % of all cache refs ( +- 13.385% ) 0.236874136 seconds time elapsed ( +- 0.01% ) Acked-by: Peter Zijlstra Acked-by: Arnaldo Carvalho de Melo Cc: Frederic Weisbecker Link: http://lkml.kernel.org/n/tip-uapziqny39601apdmmhoz7hk@git.kernel.org Signed-off-by: Ingo Molnar diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c index e5e82f6..e881c20 100644 --- a/tools/perf/builtin-stat.c +++ b/tools/perf/builtin-stat.c @@ -156,6 +156,7 @@ static double stddev_stats(struct stats *stats) struct stats runtime_nsecs_stats[MAX_NR_CPUS]; struct stats runtime_cycles_stats[MAX_NR_CPUS]; +struct stats runtime_stalled_cycles_stats[MAX_NR_CPUS]; struct stats runtime_branches_stats[MAX_NR_CPUS]; struct stats runtime_cacherefs_stats[MAX_NR_CPUS]; struct stats walltime_nsecs_stats; @@ -204,6 +205,8 @@ static void update_shadow_stats(struct perf_evsel *counter, u64 *count) update_stats(&runtime_nsecs_stats[0], count[0]); else if (perf_evsel__match(counter, HARDWARE, HW_CPU_CYCLES)) update_stats(&runtime_cycles_stats[0], count[0]); + else if (perf_evsel__match(counter, HARDWARE, HW_STALLED_CYCLES)) + update_stats(&runtime_stalled_cycles_stats[0], count[0]); else if (perf_evsel__match(counter, HARDWARE, HW_BRANCH_INSTRUCTIONS)) update_stats(&runtime_branches_stats[0], count[0]); else if (perf_evsel__match(counter, HARDWARE, HW_CACHE_REFERENCES)) @@ -412,8 +415,7 @@ static void nsec_printout(int cpu, struct perf_evsel *evsel, double avg) return; if (perf_evsel__match(evsel, SOFTWARE, SW_TASK_CLOCK)) - fprintf(stderr, " # %10.3f CPUs", - avg / avg_stats(&walltime_nsecs_stats)); + fprintf(stderr, " # %8.3f CPUs utilized ", avg / avg_stats(&walltime_nsecs_stats)); } static void abs_printout(int cpu, struct perf_evsel *evsel, double avg) @@ -450,7 +452,15 @@ static void abs_printout(int cpu, struct perf_evsel *evsel, double avg) if (total) ratio = avg / total; - fprintf(stderr, " # ( %4.2f instructions per cycle )", ratio); + fprintf(stderr, " # %4.2f insns per cycle", ratio); + + total = avg_stats(&runtime_stalled_cycles_stats[cpu]); + + if (total && avg) { + ratio = total / avg; + fprintf(stderr, "\n # %4.2f stalled cycles per insn", ratio); + } + } else if (perf_evsel__match(evsel, HARDWARE, HW_BRANCH_MISSES) && runtime_branches_stats[cpu].n != 0) { total = avg_stats(&runtime_branches_stats[cpu]); @@ -458,7 +468,7 @@ static void abs_printout(int cpu, struct perf_evsel *evsel, double avg) if (total) ratio = avg * 100 / total; - fprintf(stderr, " # %10.3f %%", ratio); + fprintf(stderr, " # %8.3f %% of all branches", ratio); } else if (perf_evsel__match(evsel, HARDWARE, HW_CACHE_MISSES) && runtime_cacherefs_stats[cpu].n != 0) { @@ -467,22 +477,29 @@ static void abs_printout(int cpu, struct perf_evsel *evsel, double avg) if (total) ratio = avg * 100 / total; - fprintf(stderr, " # %10.3f %%", ratio); + fprintf(stderr, " # %8.3f %% of all cache refs ", ratio); - } else if (runtime_nsecs_stats[cpu].n != 0) { + } else if (perf_evsel__match(evsel, HARDWARE, HW_STALLED_CYCLES)) { + total = avg_stats(&runtime_cycles_stats[cpu]); + + if (total) + ratio = avg / total * 100.0; + + fprintf(stderr, " # %5.2f%% of all cycles are idle ", ratio); + } else if (perf_evsel__match(evsel, HARDWARE, HW_CPU_CYCLES)) { total = avg_stats(&runtime_nsecs_stats[cpu]); if (total) - ratio = 1000.0 * avg / total; + ratio = 1.0 * avg / total; - fprintf(stderr, " # %10.3f M/sec", ratio); - } else if (perf_evsel__match(evsel, HARDWARE, HW_STALLED_CYCLES)) { - total = avg_stats(&runtime_cycles_stats[cpu]); + fprintf(stderr, " # %8.3f GHz ", ratio); + } else if (runtime_nsecs_stats[cpu].n != 0) { + total = avg_stats(&runtime_nsecs_stats[cpu]); if (total) - ratio = avg / total * 100.0; + ratio = 1000.0 * avg / total; - fprintf(stderr, " # (%5.2f%% of all cycles )", ratio); + fprintf(stderr, " # %8.3f M/sec ", ratio); } } @@ -619,7 +636,7 @@ static void print_stat(int argc, const char **argv) fprintf(stderr, " %18.9f seconds time elapsed", avg_stats(&walltime_nsecs_stats)/1e9); if (run_count > 1) { - fprintf(stderr, " ( +- %7.3f%% )", + fprintf(stderr, " ( +-%5.2f%% )", 100*stddev_stats(&walltime_nsecs_stats) / avg_stats(&walltime_nsecs_stats)); } -- cgit v0.10.2 From 1fc570ad89e55dc32dfa4dda1311948b38f26524 Mon Sep 17 00:00:00 2001 From: Ingo Molnar Date: Wed, 27 Apr 2011 05:20:22 +0200 Subject: perf stat: Add stalled cycles to the default output The new default output looks like this: Performance counter stats for './loop_1b_instructions': 236.010686 task-clock # 0.996 CPUs utilized 0 context-switches # 0.000 M/sec 0 CPU-migrations # 0.000 M/sec 99 page-faults # 0.000 M/sec 756,487,646 cycles # 3.205 GHz 354,938,996 stalled-cycles # 46.92% of all cycles are idle 1,001,403,797 instructions # 1.32 insns per cycle # 0.35 stalled cycles per insn 100,279,773 branches # 424.895 M/sec 12,646 branch-misses # 0.013 % of all branches 0.236902540 seconds time elapsed We dropped cache-refs and cache-misses and added stalled-cycles - this is a more generic "how well utilized is the CPU" metric. If the stalled-cycles ratio is too high then more specific measurements can be taken to figure out the source of the inefficiency. Acked-by: Peter Zijlstra Acked-by: Arnaldo Carvalho de Melo Cc: Frederic Weisbecker Link: http://lkml.kernel.org/n/tip-pbpl2l4mn797s69bclfpwkwn@git.kernel.org Signed-off-by: Ingo Molnar diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c index e881c20..924d18c 100644 --- a/tools/perf/builtin-stat.c +++ b/tools/perf/builtin-stat.c @@ -65,11 +65,10 @@ static struct perf_event_attr default_attrs[] = { { .type = PERF_TYPE_SOFTWARE, .config = PERF_COUNT_SW_PAGE_FAULTS }, { .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_CPU_CYCLES }, + { .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_STALLED_CYCLES }, { .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_INSTRUCTIONS }, { .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_BRANCH_INSTRUCTIONS }, { .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_BRANCH_MISSES }, - { .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_CACHE_REFERENCES }, - { .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_CACHE_MISSES }, }; @@ -468,7 +467,7 @@ static void abs_printout(int cpu, struct perf_evsel *evsel, double avg) if (total) ratio = avg * 100 / total; - fprintf(stderr, " # %8.3f %% of all branches", ratio); + fprintf(stderr, " # %5.2f %% of all branches ", ratio); } else if (perf_evsel__match(evsel, HARDWARE, HW_CACHE_MISSES) && runtime_cacherefs_stats[cpu].n != 0) { diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c index b5bfef1..bbbb735 100644 --- a/tools/perf/util/parse-events.c +++ b/tools/perf/util/parse-events.c @@ -32,13 +32,13 @@ char debugfs_path[MAXPATHLEN]; static struct event_symbol event_symbols[] = { { CHW(CPU_CYCLES), "cpu-cycles", "cycles" }, + { CHW(STALLED_CYCLES), "stalled-cycles", "idle-cycles" }, { CHW(INSTRUCTIONS), "instructions", "" }, { CHW(CACHE_REFERENCES), "cache-references", "" }, { CHW(CACHE_MISSES), "cache-misses", "" }, { CHW(BRANCH_INSTRUCTIONS), "branch-instructions", "branches" }, { CHW(BRANCH_MISSES), "branch-misses", "" }, { CHW(BUS_CYCLES), "bus-cycles", "" }, - { CHW(STALLED_CYCLES), "stalled-cycles", "" }, { CSW(CPU_CLOCK), "cpu-clock", "" }, { CSW(TASK_CLOCK), "task-clock", "" }, @@ -54,9 +54,9 @@ static struct event_symbol event_symbols[] = { #define __PERF_EVENT_FIELD(config, name) \ ((config & PERF_EVENT_##name##_MASK) >> PERF_EVENT_##name##_SHIFT) -#define PERF_EVENT_RAW(config) __PERF_EVENT_FIELD(config, RAW) +#define PERF_EVENT_RAW(config) __PERF_EVENT_FIELD(config, RAW) #define PERF_EVENT_CONFIG(config) __PERF_EVENT_FIELD(config, CONFIG) -#define PERF_EVENT_TYPE(config) __PERF_EVENT_FIELD(config, TYPE) +#define PERF_EVENT_TYPE(config) __PERF_EVENT_FIELD(config, TYPE) #define PERF_EVENT_ID(config) __PERF_EVENT_FIELD(config, EVENT) static const char *hw_event_names[] = { @@ -67,6 +67,7 @@ static const char *hw_event_names[] = { "branches", "branch-misses", "bus-cycles", + "stalled-cycles", }; static const char *sw_event_names[] = { @@ -308,7 +309,7 @@ const char *__event_name(int type, u64 config) switch (type) { case PERF_TYPE_HARDWARE: - if (config < PERF_COUNT_HW_MAX) + if (config < PERF_COUNT_HW_MAX && hw_event_names[config]) return hw_event_names[config]; return "unknown-hardware"; @@ -334,7 +335,7 @@ const char *__event_name(int type, u64 config) } case PERF_TYPE_SOFTWARE: - if (config < PERF_COUNT_SW_MAX) + if (config < PERF_COUNT_SW_MAX && sw_event_names[config]) return sw_event_names[config]; return "unknown-software"; -- cgit v0.10.2 From f99844cb76b7d347711c22cdcb94266b7214141f Mon Sep 17 00:00:00 2001 From: Ingo Molnar Date: Wed, 27 Apr 2011 05:35:39 +0200 Subject: perf stat: Fix -nan% output in perf stat noise printouts Before: 0 CPU-migrations # 0.000 M/sec ( +- -nan% ) After: 0 CPU-migrations # 0.000 M/sec ( +- 0.00% ) Also factor out the noise printing function. Acked-by: Peter Zijlstra Acked-by: Arnaldo Carvalho de Melo Cc: Frederic Weisbecker Link: http://lkml.kernel.org/n/tip-z89h2v1bk1mikcbsf7e6v34q@git.kernel.org Signed-off-by: Ingo Molnar diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c index 924d18c..845ded8 100644 --- a/tools/perf/builtin-stat.c +++ b/tools/perf/builtin-stat.c @@ -382,6 +382,16 @@ static int run_perf_stat(int argc __used, const char **argv) return WEXITSTATUS(status); } +static void print_noise_pct(double total, double avg) +{ + double pct = 0.0; + + if (avg) + pct = 100.0*total/avg; + + fprintf(stderr, " ( +-%6.2f%% )", pct); +} + static void print_noise(struct perf_evsel *evsel, double avg) { struct perf_stat *ps; @@ -390,8 +400,7 @@ static void print_noise(struct perf_evsel *evsel, double avg) return; ps = evsel->priv; - fprintf(stderr, " ( +- %7.3f%% )", - 100 * stddev_stats(&ps->res_stats[0]) / avg); + print_noise_pct(stddev_stats(&ps->res_stats[0]), avg); } static void nsec_printout(int cpu, struct perf_evsel *evsel, double avg) @@ -635,9 +644,8 @@ static void print_stat(int argc, const char **argv) fprintf(stderr, " %18.9f seconds time elapsed", avg_stats(&walltime_nsecs_stats)/1e9); if (run_count > 1) { - fprintf(stderr, " ( +-%5.2f%% )", - 100*stddev_stats(&walltime_nsecs_stats) / - avg_stats(&walltime_nsecs_stats)); + print_noise_pct(stddev_stats(&walltime_nsecs_stats), + avg_stats(&walltime_nsecs_stats)); } fprintf(stderr, "\n\n"); } -- cgit v0.10.2 From a5d243d04a150acbfa79d641154f49e5d920f64f Mon Sep 17 00:00:00 2001 From: Ingo Molnar Date: Wed, 27 Apr 2011 05:39:24 +0200 Subject: perf stat: Print stalled cycles warning colors Print the stalled-cycles percentage with different warning level ASCII colors, as the percentage passes the 25%/50%/75% thresholds. Acked-by: Peter Zijlstra Acked-by: Arnaldo Carvalho de Melo Cc: Frederic Weisbecker Link: http://lkml.kernel.org/n/tip-e25zz44rcms7mu9az4fu5zp0@git.kernel.org Signed-off-by: Ingo Molnar diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c index 845ded8..e7d91f9 100644 --- a/tools/perf/builtin-stat.c +++ b/tools/perf/builtin-stat.c @@ -46,6 +46,7 @@ #include "util/evlist.h" #include "util/evsel.h" #include "util/debug.h" +#include "util/color.h" #include "util/header.h" #include "util/cpumap.h" #include "util/thread.h" @@ -426,6 +427,29 @@ static void nsec_printout(int cpu, struct perf_evsel *evsel, double avg) fprintf(stderr, " # %8.3f CPUs utilized ", avg / avg_stats(&walltime_nsecs_stats)); } +static void print_stalled_cycles(int cpu, struct perf_evsel *evsel __used, double avg) +{ + double total, ratio = 0.0; + const char *color; + + total = avg_stats(&runtime_cycles_stats[cpu]); + + if (total) + ratio = avg / total * 100.0; + + color = PERF_COLOR_NORMAL; + if (ratio > 75.0) + color = PERF_COLOR_RED; + else if (ratio > 50.0) + color = PERF_COLOR_MAGENTA; + else if (ratio > 25.0) + color = PERF_COLOR_YELLOW; + + fprintf(stderr, " # "); + color_fprintf(stderr, color, "%5.2f%%", ratio); + fprintf(stderr, " of all cycles are idle "); +} + static void abs_printout(int cpu, struct perf_evsel *evsel, double avg) { double total, ratio = 0.0; @@ -488,12 +512,7 @@ static void abs_printout(int cpu, struct perf_evsel *evsel, double avg) fprintf(stderr, " # %8.3f %% of all cache refs ", ratio); } else if (perf_evsel__match(evsel, HARDWARE, HW_STALLED_CYCLES)) { - total = avg_stats(&runtime_cycles_stats[cpu]); - - if (total) - ratio = avg / total * 100.0; - - fprintf(stderr, " # %5.2f%% of all cycles are idle ", ratio); + print_stalled_cycles(cpu, evsel, avg); } else if (perf_evsel__match(evsel, HARDWARE, HW_CPU_CYCLES)) { total = avg_stats(&runtime_nsecs_stats[cpu]); @@ -508,6 +527,8 @@ static void abs_printout(int cpu, struct perf_evsel *evsel, double avg) ratio = 1000.0 * avg / total; fprintf(stderr, " # %8.3f M/sec ", ratio); + } else { + fprintf(stderr, " "); } } -- cgit v0.10.2 From c78df6c1d49b5d798f1579141e3a12be7c325d1e Mon Sep 17 00:00:00 2001 From: Ingo Molnar Date: Wed, 27 Apr 2011 12:16:10 +0200 Subject: perf stat: Print branch misses warning colors Print the missed-branches percentage with different warning level ASCII colors, as the percentage passes the 5%/10%/20% thresholds. These thresholds are set to relatively low levels, because on most CPUs even a moderate percentage of branch-misses already shows up as a slowdown. Acked-by: Peter Zijlstra Acked-by: Arnaldo Carvalho de Melo Cc: Frederic Weisbecker Link: http://lkml.kernel.org/n/tip-ybqukg7p86leiup7gl03ecgk@git.kernel.org Signed-off-by: Ingo Molnar diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c index e7d91f9..5d4e1b9 100644 --- a/tools/perf/builtin-stat.c +++ b/tools/perf/builtin-stat.c @@ -450,6 +450,29 @@ static void print_stalled_cycles(int cpu, struct perf_evsel *evsel __used, doubl fprintf(stderr, " of all cycles are idle "); } +static void print_branch_misses(int cpu, struct perf_evsel *evsel __used, double avg) +{ + double total, ratio = 0.0; + const char *color; + + total = avg_stats(&runtime_branches_stats[cpu]); + + if (total) + ratio = avg / total * 100.0; + + color = PERF_COLOR_NORMAL; + if (ratio > 20.0) + color = PERF_COLOR_RED; + else if (ratio > 10.0) + color = PERF_COLOR_MAGENTA; + else if (ratio > 5.0) + color = PERF_COLOR_YELLOW; + + fprintf(stderr, " # "); + color_fprintf(stderr, color, "%5.2f%%", ratio); + fprintf(stderr, " of all branches "); +} + static void abs_printout(int cpu, struct perf_evsel *evsel, double avg) { double total, ratio = 0.0; @@ -495,13 +518,7 @@ static void abs_printout(int cpu, struct perf_evsel *evsel, double avg) } else if (perf_evsel__match(evsel, HARDWARE, HW_BRANCH_MISSES) && runtime_branches_stats[cpu].n != 0) { - total = avg_stats(&runtime_branches_stats[cpu]); - - if (total) - ratio = avg * 100 / total; - - fprintf(stderr, " # %5.2f %% of all branches ", ratio); - + print_branch_misses(cpu, evsel, avg); } else if (perf_evsel__match(evsel, HARDWARE, HW_CACHE_MISSES) && runtime_cacherefs_stats[cpu].n != 0) { total = avg_stats(&runtime_cacherefs_stats[cpu]); -- cgit v0.10.2 From 8bb6c79f24e66538f606076915e918242c02ec7c Mon Sep 17 00:00:00 2001 From: Ingo Molnar Date: Wed, 27 Apr 2011 13:25:24 +0200 Subject: perf stat: Print out miss/hit ratio for L1 data-cache events Print out this kind of l1-dcache-misses percentage: Performance counter stats for './bw_tcp localhost': 29,956,262,201 cycles # 3.002 GHz (scaled from 85.14%) 8,255,209,558 stalled-cycles # 27.56% of all cycles are idle (scaled from 86.56%) 1,206,130,308 l1-dcache-misses # 40.49% of all L1-dcache hits (scaled from 86.30%) 2,978,756,779 l1-dcache-refs # 298.512 M/sec (scaled from 70.02%) 8,861,956,159 instructions # 0.30 insns per cycle # 0.93 stalled cycles per insn (scaled from 84.27%) 1,644,306,068 branches # 164.782 M/sec (scaled from 86.43%) 74,778,443 branch-misses # 4.55% of all branches (scaled from 70.69%) 9978.695711 task-clock # 0.693 CPUs utilized 14.404347983 seconds time elapsed And color the result depending on the severity of cache-trashing. Acked-by: Peter Zijlstra Acked-by Arnaldo Carvalho de Melo Cc: Frederic Weisbecker Link: http://lkml.kernel.org/n/tip-54gmz0zymaid84zcs7joq02p@git.kernel.org Signed-off-by: Ingo Molnar diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c index 5d4e1b9..03bac6a 100644 --- a/tools/perf/builtin-stat.c +++ b/tools/perf/builtin-stat.c @@ -159,6 +159,7 @@ struct stats runtime_cycles_stats[MAX_NR_CPUS]; struct stats runtime_stalled_cycles_stats[MAX_NR_CPUS]; struct stats runtime_branches_stats[MAX_NR_CPUS]; struct stats runtime_cacherefs_stats[MAX_NR_CPUS]; +struct stats runtime_l1_dcache_stats[MAX_NR_CPUS]; struct stats walltime_nsecs_stats; static int create_perf_stat_counter(struct perf_evsel *evsel) @@ -211,6 +212,8 @@ static void update_shadow_stats(struct perf_evsel *counter, u64 *count) update_stats(&runtime_branches_stats[0], count[0]); else if (perf_evsel__match(counter, HARDWARE, HW_CACHE_REFERENCES)) update_stats(&runtime_cacherefs_stats[0], count[0]); + else if (perf_evsel__match(counter, HW_CACHE, HW_CACHE_L1D)) + update_stats(&runtime_l1_dcache_stats[0], count[0]); } /* @@ -473,6 +476,29 @@ static void print_branch_misses(int cpu, struct perf_evsel *evsel __used, double fprintf(stderr, " of all branches "); } +static void print_l1_dcache_misses(int cpu, struct perf_evsel *evsel __used, double avg) +{ + double total, ratio = 0.0; + const char *color; + + total = avg_stats(&runtime_l1_dcache_stats[cpu]); + + if (total) + ratio = avg / total * 100.0; + + color = PERF_COLOR_NORMAL; + if (ratio > 20.0) + color = PERF_COLOR_RED; + else if (ratio > 10.0) + color = PERF_COLOR_MAGENTA; + else if (ratio > 5.0) + color = PERF_COLOR_YELLOW; + + fprintf(stderr, " # "); + color_fprintf(stderr, color, "%5.2f%%", ratio); + fprintf(stderr, " of all L1-dcache hits "); +} + static void abs_printout(int cpu, struct perf_evsel *evsel, double avg) { double total, ratio = 0.0; @@ -519,6 +545,13 @@ static void abs_printout(int cpu, struct perf_evsel *evsel, double avg) } else if (perf_evsel__match(evsel, HARDWARE, HW_BRANCH_MISSES) && runtime_branches_stats[cpu].n != 0) { print_branch_misses(cpu, evsel, avg); + } else if ( + evsel->attr.type == PERF_TYPE_HW_CACHE && + evsel->attr.config == ( PERF_COUNT_HW_CACHE_L1D | + ((PERF_COUNT_HW_CACHE_OP_READ) << 8) | + ((PERF_COUNT_HW_CACHE_RESULT_MISS) << 16)) && + runtime_branches_stats[cpu].n != 0) { + print_l1_dcache_misses(cpu, evsel, avg); } else if (perf_evsel__match(evsel, HARDWARE, HW_CACHE_MISSES) && runtime_cacherefs_stats[cpu].n != 0) { total = avg_stats(&runtime_cacherefs_stats[cpu]); -- cgit v0.10.2 From c6264deff7ea6125492b442edad885e5429679af Mon Sep 17 00:00:00 2001 From: Ingo Molnar Date: Wed, 27 Apr 2011 13:50:47 +0200 Subject: perf stat: Add -d/--detailed flag to run with a lot of events Add the new -d/--detailed flag, which generates a pretty detailed event list: Performance counter stats for './hackbench 10' (10 runs): 1514.287888 task-clock # 10.897 CPUs utilized ( +- 3.05% ) 39,698 context-switches # 0.026 M/sec ( +- 12.19% ) 8,147 CPU-migrations # 0.005 M/sec ( +- 16.55% ) 17,918 page-faults # 0.012 M/sec ( +- 0.37% ) 2,944,504,050 cycles # 1.944 GHz ( +- 3.89% ) (32.60%) 1,043,971,283 stalled-cycles # 35.45% of all cycles are idle ( +- 5.22% ) (44.48%) 1,655,906,768 instructions # 0.56 insns per cycle # 0.63 stalled cycles per insn ( +- 1.95% ) (55.09%) 338,832,373 branches # 223.757 M/sec ( +- 1.96% ) (64.47%) 3,892,416 branch-misses # 1.15% of all branches ( +- 5.49% ) (73.12%) 606,410,482 L1-dcache-loads # 400.459 M/sec ( +- 1.29% ) (71.21%) 31,204,395 L1-dcache-load-misses # 5.15% of all L1-dcache hits ( +- 3.04% ) (60.43%) 3,922,751 LLC-loads # 2.590 M/sec ( +- 6.80% ) (46.87%) 5,037,288 LLC-load-misses # 3.327 M/sec ( +- 3.56% ) (13.00%) 0.138966828 seconds time elapsed ( +- 4.11% ) This can be used "at a glance" for narrower analysis. -d can also be used in addition to other -e events, to further expand an event list. Acked-by: Peter Zijlstra Acked-by: Arnaldo Carvalho de Melo Cc: Frederic Weisbecker Link: http://lkml.kernel.org/n/tip-cxs98quixs3qyvdqx3goojc4@git.kernel.org Signed-off-by: Ingo Molnar diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c index 03bac6a..6959fde 100644 --- a/tools/perf/builtin-stat.c +++ b/tools/perf/builtin-stat.c @@ -73,6 +73,47 @@ static struct perf_event_attr default_attrs[] = { }; +/* + * Detailed stats: + */ +static struct perf_event_attr detailed_attrs[] = { + + { .type = PERF_TYPE_SOFTWARE, .config = PERF_COUNT_SW_TASK_CLOCK }, + { .type = PERF_TYPE_SOFTWARE, .config = PERF_COUNT_SW_CONTEXT_SWITCHES }, + { .type = PERF_TYPE_SOFTWARE, .config = PERF_COUNT_SW_CPU_MIGRATIONS }, + { .type = PERF_TYPE_SOFTWARE, .config = PERF_COUNT_SW_PAGE_FAULTS }, + + { .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_CPU_CYCLES }, + { .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_STALLED_CYCLES }, + { .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_INSTRUCTIONS }, + { .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_BRANCH_INSTRUCTIONS }, + { .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_BRANCH_MISSES }, + + { .type = PERF_TYPE_HW_CACHE, + .config = + PERF_COUNT_HW_CACHE_L1D << 0 | + (PERF_COUNT_HW_CACHE_OP_READ << 8) | + (PERF_COUNT_HW_CACHE_RESULT_ACCESS << 16) }, + + { .type = PERF_TYPE_HW_CACHE, + .config = + PERF_COUNT_HW_CACHE_L1D << 0 | + (PERF_COUNT_HW_CACHE_OP_READ << 8) | + (PERF_COUNT_HW_CACHE_RESULT_MISS << 16) }, + + { .type = PERF_TYPE_HW_CACHE, + .config = + PERF_COUNT_HW_CACHE_LL << 0 | + (PERF_COUNT_HW_CACHE_OP_READ << 8) | + (PERF_COUNT_HW_CACHE_RESULT_ACCESS << 16) }, + + { .type = PERF_TYPE_HW_CACHE, + .config = + PERF_COUNT_HW_CACHE_LL << 0 | + (PERF_COUNT_HW_CACHE_OP_READ << 8) | + (PERF_COUNT_HW_CACHE_RESULT_MISS << 16) }, +}; + struct perf_evlist *evsel_list; static bool system_wide = false; @@ -86,6 +127,7 @@ static pid_t target_pid = -1; static pid_t target_tid = -1; static pid_t child_pid = -1; static bool null_run = false; +static bool detailed_run = false; static bool big_num = true; static int big_num_opt = -1; static const char *cpu_list; @@ -550,7 +592,7 @@ static void abs_printout(int cpu, struct perf_evsel *evsel, double avg) evsel->attr.config == ( PERF_COUNT_HW_CACHE_L1D | ((PERF_COUNT_HW_CACHE_OP_READ) << 8) | ((PERF_COUNT_HW_CACHE_RESULT_MISS) << 16)) && - runtime_branches_stats[cpu].n != 0) { + runtime_l1_dcache_stats[cpu].n != 0) { print_l1_dcache_misses(cpu, evsel, avg); } else if (perf_evsel__match(evsel, HARDWARE, HW_CACHE_MISSES) && runtime_cacherefs_stats[cpu].n != 0) { @@ -625,8 +667,7 @@ static void print_counter_aggr(struct perf_evsel *counter) avg_enabled = avg_stats(&ps->res_stats[1]); avg_running = avg_stats(&ps->res_stats[2]); - fprintf(stderr, " (scaled from %.2f%%)", - 100 * avg_running / avg_enabled); + fprintf(stderr, " (%.2f%%)", 100 * avg_running / avg_enabled); } fprintf(stderr, "\n"); } @@ -668,10 +709,8 @@ static void print_counter(struct perf_evsel *counter) if (!csv_output) { print_noise(counter, 1.0); - if (run != ena) { - fprintf(stderr, " (scaled from %.2f%%)", - 100.0 * run / ena); - } + if (run != ena) + fprintf(stderr, " (%.2f%%)", 100.0 * run / ena); } fputc('\n', stderr); } @@ -778,6 +817,8 @@ static const struct option options[] = { "repeat command and print average + stddev (max: 100)"), OPT_BOOLEAN('n', "null", &null_run, "null run - dont start any counters"), + OPT_BOOLEAN('d', "detailed", &detailed_run, + "detailed run - start a lot of events"), OPT_CALLBACK_NOOPT('B', "big-num", NULL, NULL, "print large numbers with thousands\' separators", stat__set_big_num), @@ -839,7 +880,18 @@ int cmd_stat(int argc, const char **argv, const char *prefix __used) } /* Set attrs and nr_counters if no event is selected and !null_run */ - if (!null_run && !evsel_list->nr_entries) { + if (detailed_run) { + size_t c; + + for (c = 0; c < ARRAY_SIZE(detailed_attrs); ++c) { + pos = perf_evsel__new(&detailed_attrs[c], c); + if (pos == NULL) + goto out; + perf_evlist__add(evsel_list, pos); + } + } + /* Set attrs and nr_counters if no event is selected and !null_run */ + if (!detailed_run && !null_run && !evsel_list->nr_entries) { size_t c; for (c = 0; c < ARRAY_SIZE(default_attrs); ++c) { -- cgit v0.10.2 From 3f602b08dec32c418fc391fc838db357aab84f8a Mon Sep 17 00:00:00 2001 From: Steffen Klassert Date: Mon, 25 Apr 2011 19:39:24 +0000 Subject: xfrm: Fix replay window size calculation on initialization On replay initialization, we compute the size of the replay buffer to see if the replay window fits into the buffer. This computation lacks a mutliplication by 8 because we need the size in bit, not in byte. So we might return an error even though the replay window would fit into the buffer. This patch fixes this issue. Signed-off-by: Steffen Klassert Acked-by: Herbert Xu Signed-off-by: David S. Miller diff --git a/net/xfrm/xfrm_replay.c b/net/xfrm/xfrm_replay.c index f218385..e8a7814 100644 --- a/net/xfrm/xfrm_replay.c +++ b/net/xfrm/xfrm_replay.c @@ -532,7 +532,7 @@ int xfrm_init_replay(struct xfrm_state *x) if (replay_esn) { if (replay_esn->replay_window > - replay_esn->bmp_len * sizeof(__u32)) + replay_esn->bmp_len * sizeof(__u32) * 8) return -EINVAL; if ((x->props.flags & XFRM_STATE_ESN) && x->replay_esn) -- cgit v0.10.2 From c0a56e64aec331f33ead29ba493ee184d9bdc840 Mon Sep 17 00:00:00 2001 From: Steffen Klassert Date: Mon, 25 Apr 2011 19:40:23 +0000 Subject: esp6: Fix scatterlist initialization When we use IPsec extended sequence numbers, we may overwrite the last scatterlist of the associated data by the scatterlist for the skb. This patch fixes this by placing the scatterlist for the skb right behind the last scatterlist of the associated data. esp4 does it already like that. Signed-off-by: Steffen Klassert Acked-by: Herbert Xu Signed-off-by: David S. Miller diff --git a/net/ipv6/esp6.c b/net/ipv6/esp6.c index 5aa8ec8..59dccfb 100644 --- a/net/ipv6/esp6.c +++ b/net/ipv6/esp6.c @@ -371,7 +371,7 @@ static int esp6_input(struct xfrm_state *x, struct sk_buff *skb) iv = esp_tmp_iv(aead, tmp, seqhilen); req = esp_tmp_req(aead, iv); asg = esp_req_sg(aead, req); - sg = asg + 1; + sg = asg + sglists; skb->ip_summed = CHECKSUM_NONE; -- cgit v0.10.2 From 7833aa05b8db63484b43b4b4c389cd4533140afb Mon Sep 17 00:00:00 2001 From: Steffen Klassert Date: Mon, 25 Apr 2011 19:41:21 +0000 Subject: xfrm: Check for the new replay implementation if an esn state is inserted IPsec extended sequence numbers can be used only with the new anti-replay window implementation. So check if the new implementation is used if an esn state is inserted and return an error if it is not. Signed-off-by: Steffen Klassert Acked-by: Herbert Xu Signed-off-by: David S. Miller diff --git a/net/xfrm/xfrm_user.c b/net/xfrm/xfrm_user.c index 5d1d60d..c658cb3 100644 --- a/net/xfrm/xfrm_user.c +++ b/net/xfrm/xfrm_user.c @@ -124,6 +124,9 @@ static inline int verify_replay(struct xfrm_usersa_info *p, { struct nlattr *rt = attrs[XFRMA_REPLAY_ESN_VAL]; + if ((p->flags & XFRM_STATE_ESN) && !rt) + return -EINVAL; + if (!rt) return 0; -- cgit v0.10.2 From 3782c69d6e35e698bcc2aefe803e62d06c5c4997 Mon Sep 17 00:00:00 2001 From: Rajkumar Manoharan Date: Sun, 24 Apr 2011 21:34:39 +0530 Subject: ath9k_hw: Fix Tx IQ Calibration hang issue in AR9003 chips On AR9003 chips, doing three IQ calibrations will possibly cause chip in stuck state. In noisy environment, chip could receive a packet during the middle of three calibrations and it causes the conflict of HW access and the eventual failure. It also causes IQ calibration outliers which results in poor Tx EVM. The IQ Cal procedure is after resetting the chip, run IQ cal 3 times per each cal cycle and find the two closest readings and average of two. The advantage of running Tx IQ cal more than once is that we can compare calibration results for the same gain setting over multiple iterations. Most of the cases the IQ failures were observed after first pass. For the AR9485 and later chips, Tx IQ Calibration is performed along with AGC cal. But for pre-AR9485 chips, Tx IQ cal HW has to be separated from the rest of calibration HW to avoid chip hang. After all calibrations are done in HW, we can start SW post-processing. By doing this way, we minimize the SW difference among all chips. The order of calibration (run IQ cal before other calibration) is also needed to avoid chip hang for chips before AR9485. This issue was originally observed with AR9382. During the issue kernel log was filled with following message ath: timeout (100000 us) on reg 0xa640: 0x00000001 & 0x00000001 != 0x00000000 ath: timeout (100000 us) on reg 0xa2c4: 0x00158dd9 & 0x00000001 != 0x00000000 ath: Unable to reset channel (2412 MHz), reset status -5 ath: Unable to set channel Signed-off-by: Rajkumar Manoharan Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/ar9003_calib.c b/drivers/net/wireless/ath/ath9k/ar9003_calib.c index bceff49..f276cb9 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_calib.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_calib.c @@ -18,13 +18,13 @@ #include "hw-ops.h" #include "ar9003_phy.h" -#define MPASS 3 #define MAX_MEASUREMENT 8 -#define MAX_DIFFERENCE 10 +#define MAX_MAG_DELTA 11 +#define MAX_PHS_DELTA 10 struct coeff { - int mag_coeff[AR9300_MAX_CHAINS][MAX_MEASUREMENT][MPASS]; - int phs_coeff[AR9300_MAX_CHAINS][MAX_MEASUREMENT][MPASS]; + int mag_coeff[AR9300_MAX_CHAINS][MAX_MEASUREMENT]; + int phs_coeff[AR9300_MAX_CHAINS][MAX_MEASUREMENT]; int iqc_coeff[2]; }; @@ -610,36 +610,48 @@ static bool ar9003_hw_calc_iq_corr(struct ath_hw *ah, return true; } -static bool ar9003_hw_compute_closest_pass_and_avg(int *mp_coeff, int *mp_avg) +static void ar9003_hw_detect_outlier(int *mp_coeff, int nmeasurement, + int max_delta) { - int diff[MPASS]; - - diff[0] = abs(mp_coeff[0] - mp_coeff[1]); - diff[1] = abs(mp_coeff[1] - mp_coeff[2]); - diff[2] = abs(mp_coeff[2] - mp_coeff[0]); - - if (diff[0] > MAX_DIFFERENCE && - diff[1] > MAX_DIFFERENCE && - diff[2] > MAX_DIFFERENCE) - return false; + int mp_max = -64, max_idx = 0; + int mp_min = 63, min_idx = 0; + int mp_avg = 0, i, outlier_idx = 0; + + /* find min/max mismatch across all calibrated gains */ + for (i = 0; i < nmeasurement; i++) { + mp_avg += mp_coeff[i]; + if (mp_coeff[i] > mp_max) { + mp_max = mp_coeff[i]; + max_idx = i; + } else if (mp_coeff[i] < mp_min) { + mp_min = mp_coeff[i]; + min_idx = i; + } + } - if (diff[0] <= diff[1] && diff[0] <= diff[2]) - *mp_avg = (mp_coeff[0] + mp_coeff[1]) / 2; - else if (diff[1] <= diff[2]) - *mp_avg = (mp_coeff[1] + mp_coeff[2]) / 2; - else - *mp_avg = (mp_coeff[2] + mp_coeff[0]) / 2; + /* find average (exclude max abs value) */ + for (i = 0; i < nmeasurement; i++) { + if ((abs(mp_coeff[i]) < abs(mp_max)) || + (abs(mp_coeff[i]) < abs(mp_min))) + mp_avg += mp_coeff[i]; + } + mp_avg /= (nmeasurement - 1); - return true; + /* detect outlier */ + if (abs(mp_max - mp_min) > max_delta) { + if (abs(mp_max - mp_avg) > abs(mp_min - mp_avg)) + outlier_idx = max_idx; + else + outlier_idx = min_idx; + } + mp_coeff[outlier_idx] = mp_avg; } static void ar9003_hw_tx_iqcal_load_avg_2_passes(struct ath_hw *ah, u8 num_chains, struct coeff *coeff) { - struct ath_common *common = ath9k_hw_common(ah); int i, im, nmeasurement; - int magnitude, phase; u32 tx_corr_coeff[MAX_MEASUREMENT][AR9300_MAX_CHAINS]; memset(tx_corr_coeff, 0, sizeof(tx_corr_coeff)); @@ -659,37 +671,28 @@ static void ar9003_hw_tx_iqcal_load_avg_2_passes(struct ath_hw *ah, /* Load the average of 2 passes */ for (i = 0; i < num_chains; i++) { - if (AR_SREV_9485(ah)) - nmeasurement = REG_READ_FIELD(ah, - AR_PHY_TX_IQCAL_STATUS_B0_9485, - AR_PHY_CALIBRATED_GAINS_0); - else - nmeasurement = REG_READ_FIELD(ah, - AR_PHY_TX_IQCAL_STATUS_B0, - AR_PHY_CALIBRATED_GAINS_0); + nmeasurement = REG_READ_FIELD(ah, + AR_PHY_TX_IQCAL_STATUS_B0, + AR_PHY_CALIBRATED_GAINS_0); if (nmeasurement > MAX_MEASUREMENT) nmeasurement = MAX_MEASUREMENT; - for (im = 0; im < nmeasurement; im++) { - /* - * Determine which 2 passes are closest and compute avg - * magnitude - */ - if (!ar9003_hw_compute_closest_pass_and_avg(coeff->mag_coeff[i][im], - &magnitude)) - goto disable_txiqcal; + /* detect outlier only if nmeasurement > 1 */ + if (nmeasurement > 1) { + /* Detect magnitude outlier */ + ar9003_hw_detect_outlier(coeff->mag_coeff[i], + nmeasurement, MAX_MAG_DELTA); - /* - * Determine which 2 passes are closest and compute avg - * phase - */ - if (!ar9003_hw_compute_closest_pass_and_avg(coeff->phs_coeff[i][im], - &phase)) - goto disable_txiqcal; + /* Detect phase outlier */ + ar9003_hw_detect_outlier(coeff->phs_coeff[i], + nmeasurement, MAX_PHS_DELTA); + } - coeff->iqc_coeff[0] = (magnitude & 0x7f) | - ((phase & 0x7f) << 7); + for (im = 0; im < nmeasurement; im++) { + + coeff->iqc_coeff[0] = (coeff->mag_coeff[i][im] & 0x7f) | + ((coeff->phs_coeff[i][im] & 0x7f) << 7); if ((im % 2) == 0) REG_RMW_FIELD(ah, tx_corr_coeff[im][i], @@ -709,141 +712,37 @@ static void ar9003_hw_tx_iqcal_load_avg_2_passes(struct ath_hw *ah, return; -disable_txiqcal: - REG_RMW_FIELD(ah, AR_PHY_TX_IQCAL_CONTROL_3, - AR_PHY_TX_IQCAL_CONTROL_3_IQCORR_EN, 0x0); - REG_RMW_FIELD(ah, AR_PHY_RX_IQCAL_CORR_B0, - AR_PHY_RX_IQCAL_CORR_B0_LOOPBACK_IQCORR_EN, 0x0); - - ath_dbg(common, ATH_DBG_CALIBRATE, "TX IQ Cal disabled\n"); } -static void ar9003_hw_tx_iq_cal(struct ath_hw *ah) +static bool ar9003_hw_tx_iq_cal_run(struct ath_hw *ah) { struct ath_common *common = ath9k_hw_common(ah); - static const u32 txiqcal_status[AR9300_MAX_CHAINS] = { - AR_PHY_TX_IQCAL_STATUS_B0, - AR_PHY_TX_IQCAL_STATUS_B1, - AR_PHY_TX_IQCAL_STATUS_B2, - }; - static const u32 chan_info_tab[] = { - AR_PHY_CHAN_INFO_TAB_0, - AR_PHY_CHAN_INFO_TAB_1, - AR_PHY_CHAN_INFO_TAB_2, - }; - struct coeff coeff; - s32 iq_res[6]; - s32 i, j, ip, im, nmeasurement; - u8 nchains = get_streams(common->tx_chainmask); - - for (ip = 0; ip < MPASS; ip++) { - REG_RMW_FIELD(ah, AR_PHY_TX_IQCAL_CONTROL_1, - AR_PHY_TX_IQCAQL_CONTROL_1_IQCORR_I_Q_COFF_DELPT, - DELPT); - REG_RMW_FIELD(ah, AR_PHY_TX_IQCAL_START, - AR_PHY_TX_IQCAL_START_DO_CAL, - AR_PHY_TX_IQCAL_START_DO_CAL); - - if (!ath9k_hw_wait(ah, AR_PHY_TX_IQCAL_START, - AR_PHY_TX_IQCAL_START_DO_CAL, - 0, AH_WAIT_TIMEOUT)) { - ath_dbg(common, ATH_DBG_CALIBRATE, - "Tx IQ Cal not complete.\n"); - goto TX_IQ_CAL_FAILED; - } - - nmeasurement = REG_READ_FIELD(ah, AR_PHY_TX_IQCAL_STATUS_B0, - AR_PHY_CALIBRATED_GAINS_0); - if (nmeasurement > MAX_MEASUREMENT) - nmeasurement = MAX_MEASUREMENT; - - for (i = 0; i < nchains; i++) { - ath_dbg(common, ATH_DBG_CALIBRATE, - "Doing Tx IQ Cal for chain %d.\n", i); - for (im = 0; im < nmeasurement; im++) { - if (REG_READ(ah, txiqcal_status[i]) & - AR_PHY_TX_IQCAL_STATUS_FAILED) { - ath_dbg(common, ATH_DBG_CALIBRATE, - "Tx IQ Cal failed for chain %d.\n", i); - goto TX_IQ_CAL_FAILED; - } - - for (j = 0; j < 3; j++) { - u8 idx = 2 * j, - offset = 4 * (3 * im + j); - - REG_RMW_FIELD(ah, AR_PHY_CHAN_INFO_MEMORY, - AR_PHY_CHAN_INFO_TAB_S2_READ, - 0); - - /* 32 bits */ - iq_res[idx] = REG_READ(ah, - chan_info_tab[i] + - offset); - - REG_RMW_FIELD(ah, AR_PHY_CHAN_INFO_MEMORY, - AR_PHY_CHAN_INFO_TAB_S2_READ, - 1); - - /* 16 bits */ - iq_res[idx+1] = 0xffff & REG_READ(ah, - chan_info_tab[i] + - offset); - - ath_dbg(common, ATH_DBG_CALIBRATE, - "IQ RES[%d]=0x%x IQ_RES[%d]=0x%x\n", - idx, iq_res[idx], idx+1, iq_res[idx+1]); - } - - if (!ar9003_hw_calc_iq_corr(ah, i, iq_res, - coeff.iqc_coeff)) { - ath_dbg(common, ATH_DBG_CALIBRATE, - "Failed in calculation of IQ correction.\n"); - goto TX_IQ_CAL_FAILED; - } - coeff.mag_coeff[i][im][ip] = - coeff.iqc_coeff[0] & 0x7f; - coeff.phs_coeff[i][im][ip] = - (coeff.iqc_coeff[0] >> 7) & 0x7f; - - if (coeff.mag_coeff[i][im][ip] > 63) - coeff.mag_coeff[i][im][ip] -= 128; - if (coeff.phs_coeff[i][im][ip] > 63) - coeff.phs_coeff[i][im][ip] -= 128; - - } - } - } - - ar9003_hw_tx_iqcal_load_avg_2_passes(ah, nchains, &coeff); - - return; - -TX_IQ_CAL_FAILED: - ath_dbg(common, ATH_DBG_CALIBRATE, "Tx IQ Cal failed\n"); -} - -static void ar9003_hw_tx_iq_cal_run(struct ath_hw *ah) -{ u8 tx_gain_forced; - REG_RMW_FIELD(ah, AR_PHY_TX_IQCAL_CONTROL_1_9485, - AR_PHY_TX_IQCAQL_CONTROL_1_IQCORR_I_Q_COFF_DELPT, DELPT); tx_gain_forced = REG_READ_FIELD(ah, AR_PHY_TX_FORCED_GAIN, AR_PHY_TXGAIN_FORCE); if (tx_gain_forced) REG_RMW_FIELD(ah, AR_PHY_TX_FORCED_GAIN, AR_PHY_TXGAIN_FORCE, 0); - REG_RMW_FIELD(ah, AR_PHY_TX_IQCAL_START_9485, - AR_PHY_TX_IQCAL_START_DO_CAL_9485, 1); + REG_RMW_FIELD(ah, AR_PHY_TX_IQCAL_START, + AR_PHY_TX_IQCAL_START_DO_CAL, 1); + + if (!ath9k_hw_wait(ah, AR_PHY_TX_IQCAL_START, + AR_PHY_TX_IQCAL_START_DO_CAL, 0, + AH_WAIT_TIMEOUT)) { + ath_dbg(common, ATH_DBG_CALIBRATE, + "Tx IQ Cal is not completed.\n"); + return false; + } + return true; } static void ar9003_hw_tx_iq_cal_post_proc(struct ath_hw *ah) { struct ath_common *common = ath9k_hw_common(ah); const u32 txiqcal_status[AR9300_MAX_CHAINS] = { - AR_PHY_TX_IQCAL_STATUS_B0_9485, + AR_PHY_TX_IQCAL_STATUS_B0, AR_PHY_TX_IQCAL_STATUS_B1, AR_PHY_TX_IQCAL_STATUS_B2, }; @@ -855,7 +754,7 @@ static void ar9003_hw_tx_iq_cal_post_proc(struct ath_hw *ah) struct coeff coeff; s32 iq_res[6]; u8 num_chains = 0; - int i, ip, im, j; + int i, im, j; int nmeasurement; for (i = 0; i < AR9300_MAX_CHAINS; i++) { @@ -863,71 +762,69 @@ static void ar9003_hw_tx_iq_cal_post_proc(struct ath_hw *ah) num_chains++; } - for (ip = 0; ip < MPASS; ip++) { - for (i = 0; i < num_chains; i++) { - nmeasurement = REG_READ_FIELD(ah, - AR_PHY_TX_IQCAL_STATUS_B0_9485, - AR_PHY_CALIBRATED_GAINS_0); - if (nmeasurement > MAX_MEASUREMENT) - nmeasurement = MAX_MEASUREMENT; + for (i = 0; i < num_chains; i++) { + nmeasurement = REG_READ_FIELD(ah, + AR_PHY_TX_IQCAL_STATUS_B0, + AR_PHY_CALIBRATED_GAINS_0); + if (nmeasurement > MAX_MEASUREMENT) + nmeasurement = MAX_MEASUREMENT; - for (im = 0; im < nmeasurement; im++) { - ath_dbg(common, ATH_DBG_CALIBRATE, - "Doing Tx IQ Cal for chain %d.\n", i); + for (im = 0; im < nmeasurement; im++) { + ath_dbg(common, ATH_DBG_CALIBRATE, + "Doing Tx IQ Cal for chain %d.\n", i); - if (REG_READ(ah, txiqcal_status[i]) & - AR_PHY_TX_IQCAL_STATUS_FAILED) { - ath_dbg(common, ATH_DBG_CALIBRATE, + if (REG_READ(ah, txiqcal_status[i]) & + AR_PHY_TX_IQCAL_STATUS_FAILED) { + ath_dbg(common, ATH_DBG_CALIBRATE, "Tx IQ Cal failed for chain %d.\n", i); - goto tx_iqcal_fail; - } + goto tx_iqcal_fail; + } - for (j = 0; j < 3; j++) { - u32 idx = 2 * j, offset = 4 * (3 * im + j); + for (j = 0; j < 3; j++) { + u32 idx = 2 * j, offset = 4 * (3 * im + j); - REG_RMW_FIELD(ah, + REG_RMW_FIELD(ah, AR_PHY_CHAN_INFO_MEMORY, AR_PHY_CHAN_INFO_TAB_S2_READ, 0); - /* 32 bits */ - iq_res[idx] = REG_READ(ah, - chan_info_tab[i] + - offset); + /* 32 bits */ + iq_res[idx] = REG_READ(ah, + chan_info_tab[i] + + offset); - REG_RMW_FIELD(ah, + REG_RMW_FIELD(ah, AR_PHY_CHAN_INFO_MEMORY, AR_PHY_CHAN_INFO_TAB_S2_READ, 1); - /* 16 bits */ - iq_res[idx + 1] = 0xffff & REG_READ(ah, - chan_info_tab[i] + offset); + /* 16 bits */ + iq_res[idx + 1] = 0xffff & REG_READ(ah, + chan_info_tab[i] + offset); - ath_dbg(common, ATH_DBG_CALIBRATE, - "IQ RES[%d]=0x%x" - "IQ_RES[%d]=0x%x\n", - idx, iq_res[idx], idx + 1, - iq_res[idx + 1]); - } + ath_dbg(common, ATH_DBG_CALIBRATE, + "IQ RES[%d]=0x%x" + "IQ_RES[%d]=0x%x\n", + idx, iq_res[idx], idx + 1, + iq_res[idx + 1]); + } - if (!ar9003_hw_calc_iq_corr(ah, i, iq_res, - coeff.iqc_coeff)) { - ath_dbg(common, ATH_DBG_CALIBRATE, - "Failed in calculation of IQ correction.\n"); - goto tx_iqcal_fail; - } + if (!ar9003_hw_calc_iq_corr(ah, i, iq_res, + coeff.iqc_coeff)) { + ath_dbg(common, ATH_DBG_CALIBRATE, + "Failed in calculation of \ + IQ correction.\n"); + goto tx_iqcal_fail; + } - coeff.mag_coeff[i][im][ip] = - coeff.iqc_coeff[0] & 0x7f; - coeff.phs_coeff[i][im][ip] = - (coeff.iqc_coeff[0] >> 7) & 0x7f; + coeff.mag_coeff[i][im] = coeff.iqc_coeff[0] & 0x7f; + coeff.phs_coeff[i][im] = + (coeff.iqc_coeff[0] >> 7) & 0x7f; - if (coeff.mag_coeff[i][im][ip] > 63) - coeff.mag_coeff[i][im][ip] -= 128; - if (coeff.phs_coeff[i][im][ip] > 63) - coeff.phs_coeff[i][im][ip] -= 128; - } + if (coeff.mag_coeff[i][im] > 63) + coeff.mag_coeff[i][im] -= 128; + if (coeff.phs_coeff[i][im] > 63) + coeff.phs_coeff[i][im] -= 128; } } ar9003_hw_tx_iqcal_load_avg_2_passes(ah, num_chains, &coeff); @@ -944,6 +841,7 @@ static bool ar9003_hw_init_cal(struct ath_hw *ah, struct ath_common *common = ath9k_hw_common(ah); struct ath9k_hw_capabilities *pCap = &ah->caps; int val; + bool txiqcal_done = false; val = REG_READ(ah, AR_ENT_OTP); ath_dbg(common, ATH_DBG_CALIBRATE, "ath9k: AR_ENT_OTP 0x%x\n", val); @@ -956,14 +854,22 @@ static bool ar9003_hw_init_cal(struct ath_hw *ah, pCap->tx_chainmask); /* Do Tx IQ Calibration */ - if (AR_SREV_9485(ah)) - ar9003_hw_tx_iq_cal_run(ah); - else - ar9003_hw_tx_iq_cal(ah); + REG_RMW_FIELD(ah, AR_PHY_TX_IQCAL_CONTROL_1, + AR_PHY_TX_IQCAL_CONTROL_1_IQCORR_I_Q_COFF_DELPT, + DELPT); - REG_WRITE(ah, AR_PHY_ACTIVE, AR_PHY_ACTIVE_DIS); - udelay(5); - REG_WRITE(ah, AR_PHY_ACTIVE, AR_PHY_ACTIVE_EN); + /* + * For AR9485 or later chips, TxIQ cal runs as part of + * AGC calibration + */ + if (AR_SREV_9485_OR_LATER(ah)) + txiqcal_done = true; + else { + txiqcal_done = ar9003_hw_tx_iq_cal_run(ah); + REG_WRITE(ah, AR_PHY_ACTIVE, AR_PHY_ACTIVE_DIS); + udelay(5); + REG_WRITE(ah, AR_PHY_ACTIVE, AR_PHY_ACTIVE_EN); + } /* Calibrate the AGC */ REG_WRITE(ah, AR_PHY_AGC_CONTROL, @@ -978,7 +884,7 @@ static bool ar9003_hw_init_cal(struct ath_hw *ah, return false; } - if (AR_SREV_9485(ah)) + if (txiqcal_done) ar9003_hw_tx_iq_cal_post_proc(ah); /* Revert chainmasks to their original values before NF cal */ diff --git a/drivers/net/wireless/ath/ath9k/ar9003_phy.h b/drivers/net/wireless/ath/ath9k/ar9003_phy.h index d133ee8..2a0d5cb 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_phy.h +++ b/drivers/net/wireless/ath/ath9k/ar9003_phy.h @@ -548,15 +548,12 @@ #define AR_PHY_TXGAIN_TABLE (AR_SM_BASE + 0x300) -#define AR_PHY_TX_IQCAL_START_9485 (AR_SM_BASE + 0x3c4) -#define AR_PHY_TX_IQCAL_START_DO_CAL_9485 0x80000000 -#define AR_PHY_TX_IQCAL_START_DO_CAL_9485_S 31 -#define AR_PHY_TX_IQCAL_CONTROL_1_9485 (AR_SM_BASE + 0x3c8) -#define AR_PHY_TX_IQCAL_STATUS_B0_9485 (AR_SM_BASE + 0x3f0) - -#define AR_PHY_TX_IQCAL_CONTROL_1 (AR_SM_BASE + 0x448) -#define AR_PHY_TX_IQCAL_START (AR_SM_BASE + 0x440) -#define AR_PHY_TX_IQCAL_STATUS_B0 (AR_SM_BASE + 0x48c) +#define AR_PHY_TX_IQCAL_CONTROL_1 (AR_SM_BASE + AR_SREV_9485(ah) ? \ + 0x3c8 : 0x448) +#define AR_PHY_TX_IQCAL_START (AR_SM_BASE + AR_SREV_9485(ah) ? \ + 0x3c4 : 0x440) +#define AR_PHY_TX_IQCAL_STATUS_B0 (AR_SM_BASE + AR_SREV_9485(ah) ? \ + 0x3f0 : 0x48c) #define AR_PHY_TX_IQCAL_CORR_COEFF_B0(_i) (AR_SM_BASE + \ (AR_SREV_9485(ah) ? \ 0x3d0 : 0x450) + ((_i) << 2)) @@ -758,10 +755,10 @@ #define AR_PHY_SPECTRAL_SCAN_SHORT_REPEAT 0x01000000 #define AR_PHY_SPECTRAL_SCAN_SHORT_REPEAT_S 24 #define AR_PHY_CHANNEL_STATUS_RX_CLEAR 0x00000004 -#define AR_PHY_TX_IQCAQL_CONTROL_1_IQCORR_I_Q_COFF_DELPT 0x01fc0000 -#define AR_PHY_TX_IQCAQL_CONTROL_1_IQCORR_I_Q_COFF_DELPT_S 18 -#define AR_PHY_TX_IQCAL_START_DO_CAL 0x00000001 -#define AR_PHY_TX_IQCAL_START_DO_CAL_S 0 +#define AR_PHY_TX_IQCAL_CONTROL_1_IQCORR_I_Q_COFF_DELPT 0x01fc0000 +#define AR_PHY_TX_IQCAL_CONTROL_1_IQCORR_I_Q_COFF_DELPT_S 18 +#define AR_PHY_TX_IQCAL_START_DO_CAL 0x00000001 +#define AR_PHY_TX_IQCAL_START_DO_CAL_S 0 #define AR_PHY_TX_IQCAL_STATUS_FAILED 0x00000001 #define AR_PHY_CALIBRATED_GAINS_0 0x3e diff --git a/drivers/net/wireless/ath/ath9k/reg.h b/drivers/net/wireless/ath/ath9k/reg.h index b42e36c..d5cecdc 100644 --- a/drivers/net/wireless/ath/ath9k/reg.h +++ b/drivers/net/wireless/ath/ath9k/reg.h @@ -870,6 +870,8 @@ #define AR_SREV_9485_11(_ah) \ (AR_SREV_9485(_ah) && \ ((_ah)->hw_version.macRev == AR_SREV_REVISION_9485_11)) +#define AR_SREV_9485_OR_LATER(_ah) \ + (((_ah)->hw_version.macVersion >= AR_SREV_VERSION_9485)) #define AR_SREV_9340(_ah) \ (((_ah)->hw_version.macVersion == AR_SREV_VERSION_9340)) -- cgit v0.10.2 From 92c6f76c6d44a869bf3b252dbb2e358ae7399a96 Mon Sep 17 00:00:00 2001 From: Rajkumar Manoharan Date: Fri, 22 Apr 2011 14:50:39 +0530 Subject: ath9k: set beacon related ps flags on bss_info change Requesting beacon sync up to configure beacon timers properly in hw, has be done after doing beacon config with default values. Setting the flags in beacon config is causing the device to not enter into network sleep on idle state. Signed-off-by: Rajkumar Manoharan Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/beacon.c b/drivers/net/wireless/ath/ath9k/beacon.c index 24f565b..22cd241 100644 --- a/drivers/net/wireless/ath/ath9k/beacon.c +++ b/drivers/net/wireless/ath/ath9k/beacon.c @@ -781,12 +781,6 @@ void ath_set_beacon(struct ath_softc *sc) break; case NL80211_IFTYPE_STATION: ath_beacon_config_sta(sc, cur_conf); - /* - * Request a re-configuration of Beacon related timers - * on the receipt of the first Beacon frame (i.e., - * after time sync with the AP). - */ - sc->ps_flags |= PS_BEACON_SYNC | PS_WAIT_FOR_BEACON; break; default: ath_dbg(common, ATH_DBG_CONFIG, diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index 475009b..c3dbf26 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -1969,6 +1969,12 @@ static void ath9k_bss_iter(void *data, u8 *mac, struct ieee80211_vif *vif) "Bss Info ASSOC %d, bssid: %pM\n", bss_conf->aid, common->curbssid); ath_beacon_config(sc, vif); + /* + * Request a re-configuration of Beacon related timers + * on the receipt of the first Beacon frame (i.e., + * after time sync with the AP). + */ + sc->ps_flags |= PS_BEACON_SYNC | PS_WAIT_FOR_BEACON; /* Reset rssi stats */ sc->last_rssi = ATH_RSSI_DUMMY_MARKER; sc->sc_ah->stats.avgbrssi = ATH_RSSI_DUMMY_MARKER; -- cgit v0.10.2 From 25f63a5a37f9cd925a01840bbb4c3ad9d5034175 Mon Sep 17 00:00:00 2001 From: Adrian Chadd Date: Sat, 23 Apr 2011 12:48:53 +0800 Subject: ath9k: fix AR9160 xpaBiasLvlFreq endianness handling The xpaBiasLvlFreq parameter array is made up of 16 bit words which aren't byte-swapped like the other 16-bit eeprom parameters are. It's only used by the AR9160. Signed-off-by: Adrian Chadd Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/eeprom_def.c b/drivers/net/wireless/ath/ath9k/eeprom_def.c index 995949d..c031854 100644 --- a/drivers/net/wireless/ath/ath9k/eeprom_def.c +++ b/drivers/net/wireless/ath/ath9k/eeprom_def.c @@ -231,6 +231,10 @@ static int ath9k_hw_def_check_eeprom(struct ath_hw *ah) integer = swab32(pModal->antCtrlChain[i]); pModal->antCtrlChain[i] = integer; } + for (i = 0; i < 3; i++) { + word = swab16(pModal->xpaBiasLvlFreq[i]); + pModal->xpaBiasLvlFreq[i] = word; + } for (i = 0; i < AR_EEPROM_MODAL_SPURS; i++) { word = swab16(pModal->spurChans[i].spurChan); -- cgit v0.10.2 From a6ef8143839a8640532ba473906beb1a38b03e29 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= Date: Sat, 23 Apr 2011 19:30:28 +0200 Subject: ssb: mark bus as powered up earlier MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ssb_chipco_set_clockmode may want to touch CC registers to control power of the bus. However touching registers without powered_up set causes warnings. Signed-off-by: RafaÅ‚ MiÅ‚ecki Signed-off-by: John W. Linville diff --git a/drivers/ssb/main.c b/drivers/ssb/main.c index e05ba6e..74aa2cc 100644 --- a/drivers/ssb/main.c +++ b/drivers/ssb/main.c @@ -1309,20 +1309,20 @@ EXPORT_SYMBOL(ssb_bus_may_powerdown); int ssb_bus_powerup(struct ssb_bus *bus, bool dynamic_pctl) { - struct ssb_chipcommon *cc; int err; enum ssb_clkmode mode; err = ssb_pci_xtal(bus, SSB_GPIO_XTAL | SSB_GPIO_PLL, 1); if (err) goto error; - cc = &bus->chipco; - mode = dynamic_pctl ? SSB_CLKMODE_DYNAMIC : SSB_CLKMODE_FAST; - ssb_chipco_set_clockmode(cc, mode); #ifdef CONFIG_SSB_DEBUG bus->powered_up = 1; #endif + + mode = dynamic_pctl ? SSB_CLKMODE_DYNAMIC : SSB_CLKMODE_FAST; + ssb_chipco_set_clockmode(&bus->chipco, mode); + return 0; error: ssb_printk(KERN_ERR PFX "Bus powerup failed\n"); -- cgit v0.10.2 From 04ad1fb2640a4f23e99ccb705c179d64abac03f2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= Date: Sat, 23 Apr 2011 19:30:29 +0200 Subject: ssb: update reject bit for Target State Low MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit My 14e4:4315 is SSB_IDLOW_SSBREV_26: read32 0xfaafcff8 -> 0x600422d5 My 14e4:4328 is SSB_IDLOW_SSBREV_24: read32 0xfaafcff8 -> 0x400422c5 My 14e4:432b is SSB_IDLOW_SSBREV_26 again: read32 0xfaafcff8 -> 0x600422d5 For all of them wl driver is using 0x2 reject bit: write32(0xf98) <- 0x00010002 So it seems SSB 2.3 is the exception using another bit. Signed-off-by: RafaÅ‚ MiÅ‚ecki Signed-off-by: John W. Linville diff --git a/drivers/ssb/main.c b/drivers/ssb/main.c index 74aa2cc..ad3da93 100644 --- a/drivers/ssb/main.c +++ b/drivers/ssb/main.c @@ -1117,23 +1117,22 @@ static u32 ssb_tmslow_reject_bitmask(struct ssb_device *dev) { u32 rev = ssb_read32(dev, SSB_IDLOW) & SSB_IDLOW_SSBREV; - /* The REJECT bit changed position in TMSLOW between - * Backplane revisions. */ + /* The REJECT bit seems to be different for Backplane rev 2.3 */ switch (rev) { case SSB_IDLOW_SSBREV_22: - return SSB_TMSLOW_REJECT_22; + case SSB_IDLOW_SSBREV_24: + case SSB_IDLOW_SSBREV_26: + return SSB_TMSLOW_REJECT; case SSB_IDLOW_SSBREV_23: return SSB_TMSLOW_REJECT_23; - case SSB_IDLOW_SSBREV_24: /* TODO - find the proper REJECT bits */ - case SSB_IDLOW_SSBREV_25: /* same here */ - case SSB_IDLOW_SSBREV_26: /* same here */ + case SSB_IDLOW_SSBREV_25: /* TODO - find the proper REJECT bit */ case SSB_IDLOW_SSBREV_27: /* same here */ - return SSB_TMSLOW_REJECT_23; /* this is a guess */ + return SSB_TMSLOW_REJECT; /* this is a guess */ default: printk(KERN_INFO "ssb: Backplane Revision 0x%.8X\n", rev); WARN_ON(1); } - return (SSB_TMSLOW_REJECT_22 | SSB_TMSLOW_REJECT_23); + return (SSB_TMSLOW_REJECT | SSB_TMSLOW_REJECT_23); } int ssb_device_is_enabled(struct ssb_device *dev) diff --git a/include/linux/ssb/ssb_regs.h b/include/linux/ssb/ssb_regs.h index 402955a..efbf459 100644 --- a/include/linux/ssb/ssb_regs.h +++ b/include/linux/ssb/ssb_regs.h @@ -97,7 +97,7 @@ #define SSB_INTVEC_ENET1 0x00000040 /* Enable interrupts for enet 1 */ #define SSB_TMSLOW 0x0F98 /* SB Target State Low */ #define SSB_TMSLOW_RESET 0x00000001 /* Reset */ -#define SSB_TMSLOW_REJECT_22 0x00000002 /* Reject (Backplane rev 2.2) */ +#define SSB_TMSLOW_REJECT 0x00000002 /* Reject (Standard Backplane) */ #define SSB_TMSLOW_REJECT_23 0x00000004 /* Reject (Backplane rev 2.3) */ #define SSB_TMSLOW_CLOCK 0x00010000 /* Clock Enable */ #define SSB_TMSLOW_FGC 0x00020000 /* Force Gated Clocks On */ -- cgit v0.10.2 From be8d98eab81d1f6445461a1631513f7091805e53 Mon Sep 17 00:00:00 2001 From: Christian Lamparter Date: Sun, 24 Apr 2011 17:22:59 +0200 Subject: p54: implement multicast filter "For best CPU usage and power consumption, having as few frames as possible percolate through the stack is desirable. Hence, the hardware should filter as much as possible." Note: Not all firmwares include the multicast filter feature and the stack does not filter them either. The ARP filter on the other hand was dropped from the patch since it does not work correctly: Quote from: Max Filippov "In the ARP case, when there's no other traffic on p54spi, all ARP requests are dropped. But if there's some egress traffic from p54spi, filter seems to work correctly: only ARP requests that match filter pass through. In the multicast case filter seems to work correctly, but it treats broadcast as subject to that filtering too. By default only 01:00:5e:00:00:01 gets into priv->mc_maclist, so we miss all broadcasts. These two filters seem to interfere: - if we set ARP filter and multicast filter without bc => we miss all ARPs if there's no egress traffic; - if we set ARP filter and multicast filter with bc or don't set mc filter at all => we get all ARPs. This effect does not depend on filter setup order." Signed-off-by: Christian Lamparter Tested-by: Max Filippov Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/p54/fwio.c b/drivers/net/wireless/p54/fwio.c index 2fab7d2..b6a061c 100644 --- a/drivers/net/wireless/p54/fwio.c +++ b/drivers/net/wireless/p54/fwio.c @@ -727,3 +727,34 @@ int p54_fetch_statistics(struct p54_common *priv) p54_tx(priv, skb); return 0; } + +int p54_set_groupfilter(struct p54_common *priv) +{ + struct p54_group_address_table *grp; + struct sk_buff *skb; + bool on = false; + + skb = p54_alloc_skb(priv, P54_HDR_FLAG_CONTROL_OPSET, sizeof(*grp), + P54_CONTROL_TYPE_GROUP_ADDRESS_TABLE, GFP_KERNEL); + if (!skb) + return -ENOMEM; + + grp = (struct p54_group_address_table *)skb_put(skb, sizeof(*grp)); + + on = !(priv->filter_flags & FIF_ALLMULTI) && + (priv->mc_maclist_num > 0 && + priv->mc_maclist_num <= MC_FILTER_ADDRESS_NUM); + + if (on) { + grp->filter_enable = cpu_to_le16(1); + grp->num_address = cpu_to_le16(priv->mc_maclist_num); + memcpy(grp->mac_list, priv->mc_maclist, sizeof(grp->mac_list)); + } else { + grp->filter_enable = cpu_to_le16(0); + grp->num_address = cpu_to_le16(0); + memset(grp->mac_list, 0, sizeof(grp->mac_list)); + } + + p54_tx(priv, skb); + return 0; +} diff --git a/drivers/net/wireless/p54/lmac.h b/drivers/net/wireless/p54/lmac.h index eb581ab..3d8d622 100644 --- a/drivers/net/wireless/p54/lmac.h +++ b/drivers/net/wireless/p54/lmac.h @@ -540,6 +540,7 @@ int p54_update_beacon_tim(struct p54_common *priv, u16 aid, bool set); int p54_setup_mac(struct p54_common *priv); int p54_set_ps(struct p54_common *priv); int p54_fetch_statistics(struct p54_common *priv); +int p54_set_groupfilter(struct p54_common *priv); /* e/v DCF setup */ int p54_set_edcf(struct p54_common *priv); diff --git a/drivers/net/wireless/p54/main.c b/drivers/net/wireless/p54/main.c index 356e6bb..c5c1254 100644 --- a/drivers/net/wireless/p54/main.c +++ b/drivers/net/wireless/p54/main.c @@ -308,6 +308,31 @@ out: return ret; } +static u64 p54_prepare_multicast(struct ieee80211_hw *dev, + struct netdev_hw_addr_list *mc_list) +{ + struct p54_common *priv = dev->priv; + struct netdev_hw_addr *ha; + int i; + + BUILD_BUG_ON(ARRAY_SIZE(priv->mc_maclist) != + ARRAY_SIZE(((struct p54_group_address_table *)NULL)->mac_list)); + /* + * The first entry is reserved for the global broadcast MAC. + * Otherwise the firmware will drop it and ARP will no longer work. + */ + i = 1; + priv->mc_maclist_num = netdev_hw_addr_list_count(mc_list) + i; + netdev_hw_addr_list_for_each(ha, mc_list) { + memcpy(&priv->mc_maclist[i], ha->addr, ETH_ALEN); + i++; + if (i >= ARRAY_SIZE(priv->mc_maclist)) + break; + } + + return 1; /* update */ +} + static void p54_configure_filter(struct ieee80211_hw *dev, unsigned int changed_flags, unsigned int *total_flags, @@ -316,12 +341,16 @@ static void p54_configure_filter(struct ieee80211_hw *dev, struct p54_common *priv = dev->priv; *total_flags &= FIF_PROMISC_IN_BSS | + FIF_ALLMULTI | FIF_OTHER_BSS; priv->filter_flags = *total_flags; if (changed_flags & (FIF_PROMISC_IN_BSS | FIF_OTHER_BSS)) p54_setup_mac(priv); + + if (changed_flags & FIF_ALLMULTI || multicast) + p54_set_groupfilter(priv); } static int p54_conf_tx(struct ieee80211_hw *dev, u16 queue, @@ -591,6 +620,7 @@ static const struct ieee80211_ops p54_ops = { .config = p54_config, .flush = p54_flush, .bss_info_changed = p54_bss_info_changed, + .prepare_multicast = p54_prepare_multicast, .configure_filter = p54_configure_filter, .conf_tx = p54_conf_tx, .get_stats = p54_get_stats, @@ -660,6 +690,7 @@ struct ieee80211_hw *p54_init_common(size_t priv_data_len) init_completion(&priv->beacon_comp); INIT_DELAYED_WORK(&priv->work, p54_work); + memset(&priv->mc_maclist[0], ~0, ETH_ALEN); return dev; } EXPORT_SYMBOL_GPL(p54_init_common); diff --git a/drivers/net/wireless/p54/p54.h b/drivers/net/wireless/p54/p54.h index 50730fc..799d05e 100644 --- a/drivers/net/wireless/p54/p54.h +++ b/drivers/net/wireless/p54/p54.h @@ -211,8 +211,10 @@ struct p54_common { /* BBP/MAC state */ u8 mac_addr[ETH_ALEN]; u8 bssid[ETH_ALEN]; + u8 mc_maclist[4][ETH_ALEN]; u16 wakeup_timer; unsigned int filter_flags; + int mc_maclist_num; int mode; u32 tsf_low32, tsf_high32; u32 basic_rate_mask; -- cgit v0.10.2 From caf1eae206688210f61f3b48627ce4ca3c709784 Mon Sep 17 00:00:00 2001 From: Christian Lamparter Date: Sun, 24 Apr 2011 17:44:19 +0200 Subject: carl9170: improve unicast PS buffering Using the ieee80211_sta_block allows the PS code to handle awake->doze->awake transitions of our clients in a race-free manner. Signed-off-by: Christian Lamparter Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/carl9170/carl9170.h b/drivers/net/wireless/ath/carl9170/carl9170.h index 9cad061..beb725d 100644 --- a/drivers/net/wireless/ath/carl9170/carl9170.h +++ b/drivers/net/wireless/ath/carl9170/carl9170.h @@ -448,6 +448,8 @@ struct carl9170_ba_stats { struct carl9170_sta_info { bool ht_sta; + bool sleeping; + atomic_t pending_frames; unsigned int ampdu_max_len; struct carl9170_sta_tid *agg[CARL9170_NUM_TID]; struct carl9170_ba_stats stats[CARL9170_NUM_TID]; diff --git a/drivers/net/wireless/ath/carl9170/main.c b/drivers/net/wireless/ath/carl9170/main.c index 89fe60a..1638468 100644 --- a/drivers/net/wireless/ath/carl9170/main.c +++ b/drivers/net/wireless/ath/carl9170/main.c @@ -1193,6 +1193,8 @@ static int carl9170_op_sta_add(struct ieee80211_hw *hw, struct carl9170_sta_info *sta_info = (void *) sta->drv_priv; unsigned int i; + atomic_set(&sta_info->pending_frames, 0); + if (sta->ht_cap.ht_supported) { if (sta->ht_cap.ampdu_density > 6) { /* @@ -1467,99 +1469,17 @@ static void carl9170_op_sta_notify(struct ieee80211_hw *hw, enum sta_notify_cmd cmd, struct ieee80211_sta *sta) { - struct ar9170 *ar = hw->priv; struct carl9170_sta_info *sta_info = (void *) sta->drv_priv; - struct sk_buff *skb, *tmp; - struct sk_buff_head free; - int i; switch (cmd) { case STA_NOTIFY_SLEEP: - /* - * Since the peer is no longer listening, we have to return - * as many SKBs as possible back to the mac80211 stack. - * It will deal with the retry procedure, once the peer - * has become available again. - * - * NB: Ideally, the driver should return the all frames in - * the correct, ascending order. However, I think that this - * functionality should be implemented in the stack and not - * here... - */ - - __skb_queue_head_init(&free); - - if (sta->ht_cap.ht_supported) { - rcu_read_lock(); - for (i = 0; i < CARL9170_NUM_TID; i++) { - struct carl9170_sta_tid *tid_info; - - tid_info = rcu_dereference(sta_info->agg[i]); - - if (!tid_info) - continue; - - spin_lock_bh(&ar->tx_ampdu_list_lock); - if (tid_info->state > - CARL9170_TID_STATE_SUSPEND) - tid_info->state = - CARL9170_TID_STATE_SUSPEND; - spin_unlock_bh(&ar->tx_ampdu_list_lock); - - spin_lock_bh(&tid_info->lock); - while ((skb = __skb_dequeue(&tid_info->queue))) - __skb_queue_tail(&free, skb); - spin_unlock_bh(&tid_info->lock); - } - rcu_read_unlock(); - } - - for (i = 0; i < ar->hw->queues; i++) { - spin_lock_bh(&ar->tx_pending[i].lock); - skb_queue_walk_safe(&ar->tx_pending[i], skb, tmp) { - struct _carl9170_tx_superframe *super; - struct ieee80211_hdr *hdr; - struct ieee80211_tx_info *info; - - super = (void *) skb->data; - hdr = (void *) super->frame_data; - - if (compare_ether_addr(hdr->addr1, sta->addr)) - continue; - - __skb_unlink(skb, &ar->tx_pending[i]); - - info = IEEE80211_SKB_CB(skb); - if (info->flags & IEEE80211_TX_CTL_AMPDU) - atomic_dec(&ar->tx_ampdu_upload); - - carl9170_tx_status(ar, skb, false); - } - spin_unlock_bh(&ar->tx_pending[i].lock); - } - - while ((skb = __skb_dequeue(&free))) - carl9170_tx_status(ar, skb, false); - + sta_info->sleeping = true; + if (atomic_read(&sta_info->pending_frames)) + ieee80211_sta_block_awake(hw, sta, true); break; case STA_NOTIFY_AWAKE: - if (!sta->ht_cap.ht_supported) - return; - - rcu_read_lock(); - for (i = 0; i < CARL9170_NUM_TID; i++) { - struct carl9170_sta_tid *tid_info; - - tid_info = rcu_dereference(sta_info->agg[i]); - - if (!tid_info) - continue; - - if ((tid_info->state == CARL9170_TID_STATE_SUSPEND)) - tid_info->state = CARL9170_TID_STATE_IDLE; - } - rcu_read_unlock(); + sta_info->sleeping = false; break; } } diff --git a/drivers/net/wireless/ath/carl9170/tx.c b/drivers/net/wireless/ath/carl9170/tx.c index cb70ed7..bf2eff9 100644 --- a/drivers/net/wireless/ath/carl9170/tx.c +++ b/drivers/net/wireless/ath/carl9170/tx.c @@ -104,6 +104,56 @@ static void carl9170_tx_accounting(struct ar9170 *ar, struct sk_buff *skb) spin_unlock_bh(&ar->tx_stats_lock); } +/* needs rcu_read_lock */ +static struct ieee80211_sta *__carl9170_get_tx_sta(struct ar9170 *ar, + struct sk_buff *skb) +{ + struct _carl9170_tx_superframe *super = (void *) skb->data; + struct ieee80211_hdr *hdr = (void *) super->frame_data; + struct ieee80211_vif *vif; + unsigned int vif_id; + + vif_id = (super->s.misc & CARL9170_TX_SUPER_MISC_VIF_ID) >> + CARL9170_TX_SUPER_MISC_VIF_ID_S; + + if (WARN_ON_ONCE(vif_id >= AR9170_MAX_VIRTUAL_MAC)) + return NULL; + + vif = rcu_dereference(ar->vif_priv[vif_id].vif); + if (unlikely(!vif)) + return NULL; + + /* + * Normally we should use wrappers like ieee80211_get_DA to get + * the correct peer ieee80211_sta. + * + * But there is a problem with indirect traffic (broadcasts, or + * data which is designated for other stations) in station mode. + * The frame will be directed to the AP for distribution and not + * to the actual destination. + */ + + return ieee80211_find_sta(vif, hdr->addr1); +} + +static void carl9170_tx_ps_unblock(struct ar9170 *ar, struct sk_buff *skb) +{ + struct ieee80211_sta *sta; + struct carl9170_sta_info *sta_info; + + rcu_read_lock(); + sta = __carl9170_get_tx_sta(ar, skb); + if (unlikely(!sta)) + goto out_rcu; + + sta_info = (struct carl9170_sta_info *) sta->drv_priv; + if (atomic_dec_return(&sta_info->pending_frames) == 0) + ieee80211_sta_block_awake(ar->hw, sta, false); + +out_rcu: + rcu_read_unlock(); +} + static void carl9170_tx_accounting_free(struct ar9170 *ar, struct sk_buff *skb) { struct ieee80211_tx_info *txinfo; @@ -135,6 +185,7 @@ static void carl9170_tx_accounting_free(struct ar9170 *ar, struct sk_buff *skb) } spin_unlock_bh(&ar->tx_stats_lock); + if (atomic_dec_and_test(&ar->tx_total_queued)) complete(&ar->tx_flush); } @@ -329,13 +380,10 @@ static void carl9170_tx_status_process_ampdu(struct ar9170 *ar, { struct _carl9170_tx_superframe *super = (void *) skb->data; struct ieee80211_hdr *hdr = (void *) super->frame_data; - struct ieee80211_tx_info *tx_info; struct carl9170_tx_info *ar_info; - struct carl9170_sta_info *sta_info; struct ieee80211_sta *sta; + struct carl9170_sta_info *sta_info; struct carl9170_sta_tid *tid_info; - struct ieee80211_vif *vif; - unsigned int vif_id; u8 tid; if (!(txinfo->flags & IEEE80211_TX_CTL_AMPDU) || @@ -343,30 +391,10 @@ static void carl9170_tx_status_process_ampdu(struct ar9170 *ar, (!(super->f.mac_control & cpu_to_le16(AR9170_TX_MAC_AGGR)))) return; - tx_info = IEEE80211_SKB_CB(skb); - ar_info = (void *) tx_info->rate_driver_data; - - vif_id = (super->s.misc & CARL9170_TX_SUPER_MISC_VIF_ID) >> - CARL9170_TX_SUPER_MISC_VIF_ID_S; - - if (WARN_ON_ONCE(vif_id >= AR9170_MAX_VIRTUAL_MAC)) - return; + ar_info = (void *) txinfo->rate_driver_data; rcu_read_lock(); - vif = rcu_dereference(ar->vif_priv[vif_id].vif); - if (unlikely(!vif)) - goto out_rcu; - - /* - * Normally we should use wrappers like ieee80211_get_DA to get - * the correct peer ieee80211_sta. - * - * But there is a problem with indirect traffic (broadcasts, or - * data which is designated for other stations) in station mode. - * The frame will be directed to the AP for distribution and not - * to the actual destination. - */ - sta = ieee80211_find_sta(vif, hdr->addr1); + sta = __carl9170_get_tx_sta(ar, skb); if (unlikely(!sta)) goto out_rcu; @@ -427,6 +455,7 @@ void carl9170_tx_status(struct ar9170 *ar, struct sk_buff *skb, if (txinfo->flags & IEEE80211_TX_CTL_AMPDU) carl9170_tx_status_process_ampdu(ar, skb, txinfo); + carl9170_tx_ps_unblock(ar, skb); carl9170_tx_put_skb(skb); } @@ -540,11 +569,7 @@ static void carl9170_tx_ampdu_timeout(struct ar9170 *ar) struct sk_buff *skb; struct ieee80211_tx_info *txinfo; struct carl9170_tx_info *arinfo; - struct _carl9170_tx_superframe *super; struct ieee80211_sta *sta; - struct ieee80211_vif *vif; - struct ieee80211_hdr *hdr; - unsigned int vif_id; rcu_read_lock(); list_for_each_entry_rcu(iter, &ar->tx_ampdu_list, list) { @@ -562,20 +587,7 @@ static void carl9170_tx_ampdu_timeout(struct ar9170 *ar) msecs_to_jiffies(CARL9170_QUEUE_TIMEOUT))) goto unlock; - super = (void *) skb->data; - hdr = (void *) super->frame_data; - - vif_id = (super->s.misc & CARL9170_TX_SUPER_MISC_VIF_ID) >> - CARL9170_TX_SUPER_MISC_VIF_ID_S; - - if (WARN_ON(vif_id >= AR9170_MAX_VIRTUAL_MAC)) - goto unlock; - - vif = rcu_dereference(ar->vif_priv[vif_id].vif); - if (WARN_ON(!vif)) - goto unlock; - - sta = ieee80211_find_sta(vif, hdr->addr1); + sta = __carl9170_get_tx_sta(ar, skb); if (WARN_ON(!sta)) goto unlock; @@ -1199,15 +1211,6 @@ static struct sk_buff *carl9170_tx_pick_skb(struct ar9170 *ar, arinfo = (void *) info->rate_driver_data; arinfo->timeout = jiffies; - - /* - * increase ref count to "2". - * Ref counting is the easiest way to solve the race between - * the the urb's completion routine: carl9170_tx_callback and - * wlan tx status functions: carl9170_tx_status/janitor. - */ - carl9170_tx_get_skb(skb); - return skb; err_unlock: @@ -1228,6 +1231,36 @@ void carl9170_tx_drop(struct ar9170 *ar, struct sk_buff *skb) __carl9170_tx_process_status(ar, super->s.cookie, q); } +static bool carl9170_tx_ps_drop(struct ar9170 *ar, struct sk_buff *skb) +{ + struct ieee80211_sta *sta; + struct carl9170_sta_info *sta_info; + + rcu_read_lock(); + sta = __carl9170_get_tx_sta(ar, skb); + if (!sta) + goto out_rcu; + + sta_info = (void *) sta->drv_priv; + if (unlikely(sta_info->sleeping)) { + struct ieee80211_tx_info *tx_info; + + rcu_read_unlock(); + + tx_info = IEEE80211_SKB_CB(skb); + if (tx_info->flags & IEEE80211_TX_CTL_AMPDU) + atomic_dec(&ar->tx_ampdu_upload); + + tx_info->flags |= IEEE80211_TX_STAT_TX_FILTERED; + carl9170_tx_status(ar, skb, false); + return true; + } + +out_rcu: + rcu_read_unlock(); + return false; +} + static void carl9170_tx(struct ar9170 *ar) { struct sk_buff *skb; @@ -1247,6 +1280,9 @@ static void carl9170_tx(struct ar9170 *ar) if (unlikely(!skb)) break; + if (unlikely(carl9170_tx_ps_drop(ar, skb))) + continue; + atomic_inc(&ar->tx_total_pending); q = __carl9170_get_queue(ar, i); @@ -1256,6 +1292,16 @@ static void carl9170_tx(struct ar9170 *ar) */ skb_queue_tail(&ar->tx_status[q], skb); + /* + * increase ref count to "2". + * Ref counting is the easiest way to solve the + * race between the urb's completion routine: + * carl9170_tx_callback + * and wlan tx status functions: + * carl9170_tx_status/janitor. + */ + carl9170_tx_get_skb(skb); + carl9170_usb_tx(ar, skb); schedule_garbagecollector = true; } @@ -1368,6 +1414,11 @@ void carl9170_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb) * all ressouces which are associated with the frame. */ + if (sta) { + struct carl9170_sta_info *stai = (void *) sta->drv_priv; + atomic_inc(&stai->pending_frames); + } + if (info->flags & IEEE80211_TX_CTL_AMPDU) { run = carl9170_tx_ampdu_queue(ar, sta, skb); if (run) -- cgit v0.10.2 From 334df731976ee4042c9bf18b2eec9c0a71f45389 Mon Sep 17 00:00:00 2001 From: Christian Lamparter Date: Sun, 24 Apr 2011 20:41:16 +0200 Subject: mac80211: fix too early reorder release timer The release timer has to expire "just" after a frame is up for release. Currently, if the timer callback starts on time, the "!time_after" check above will start a new timer instead of releasing the frames. Signed-off-by: Christian Lamparter Signed-off-by: John W. Linville diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index 1f06b31..b04a437 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -652,7 +652,7 @@ static void ieee80211_sta_reorder_release(struct ieee80211_hw *hw, set_release_timer: mod_timer(&tid_agg_rx->reorder_timer, - tid_agg_rx->reorder_time[j] + + tid_agg_rx->reorder_time[j] + 1 + HT_RX_REORDER_BUF_TIMEOUT); } else { del_timer(&tid_agg_rx->reorder_timer); -- cgit v0.10.2 From 0915cba394268e68b6a8242b15f8c7283453df43 Mon Sep 17 00:00:00 2001 From: Rajkumar Manoharan Date: Mon, 25 Apr 2011 15:56:17 +0530 Subject: mac80211: Fix warnings due to -Wunused-but-set-variable These warnings are exposed by gcc 4.6. net/mac80211/sta_info.c: In function 'sta_info_cleanup_expire_buffered': net/mac80211/sta_info.c:590:32: warning: variable 'sdata' set but not used net/mac80211/ibss.c: In function 'ieee80211_rx_mgmt_auth_ibss': net/mac80211/ibss.c:43:34: warning: variable 'status_code' set but not used net/mac80211/work.c: In function 'ieee80211_send_assoc': net/mac80211/work.c:203:9: warning: variable 'len' set but not used net/mac80211/tx.c: In function '__ieee80211_parse_tx_radiotap': net/mac80211/tx.c:1039:35: warning: variable 'sband' set but not used net/mac80211/mesh.c: In function 'ieee80211_mesh_rx_queued_mgmt': net/mac80211/mesh.c:616:28: warning: variable 'ifmsh' set but not used ... Signed-off-by: Rajkumar Manoharan Signed-off-by: John W. Linville diff --git a/net/mac80211/aes_ccm.c b/net/mac80211/aes_ccm.c index 4bd6ef0..b9b595c 100644 --- a/net/mac80211/aes_ccm.c +++ b/net/mac80211/aes_ccm.c @@ -54,13 +54,12 @@ void ieee80211_aes_ccm_encrypt(struct crypto_cipher *tfm, u8 *scratch, u8 *cdata, u8 *mic) { int i, j, last_len, num_blocks; - u8 *pos, *cpos, *b, *s_0, *e, *b_0, *aad; + u8 *pos, *cpos, *b, *s_0, *e, *b_0; b = scratch; s_0 = scratch + AES_BLOCK_LEN; e = scratch + 2 * AES_BLOCK_LEN; b_0 = scratch + 3 * AES_BLOCK_LEN; - aad = scratch + 4 * AES_BLOCK_LEN; num_blocks = DIV_ROUND_UP(data_len, AES_BLOCK_LEN); last_len = data_len % AES_BLOCK_LEN; @@ -94,13 +93,12 @@ int ieee80211_aes_ccm_decrypt(struct crypto_cipher *tfm, u8 *scratch, u8 *cdata, size_t data_len, u8 *mic, u8 *data) { int i, j, last_len, num_blocks; - u8 *pos, *cpos, *b, *s_0, *a, *b_0, *aad; + u8 *pos, *cpos, *b, *s_0, *a, *b_0; b = scratch; s_0 = scratch + AES_BLOCK_LEN; a = scratch + 2 * AES_BLOCK_LEN; b_0 = scratch + 3 * AES_BLOCK_LEN; - aad = scratch + 4 * AES_BLOCK_LEN; num_blocks = DIV_ROUND_UP(data_len, AES_BLOCK_LEN); last_len = data_len % AES_BLOCK_LEN; diff --git a/net/mac80211/ibss.c b/net/mac80211/ibss.c index 1488396..b81860c 100644 --- a/net/mac80211/ibss.c +++ b/net/mac80211/ibss.c @@ -40,7 +40,7 @@ static void ieee80211_rx_mgmt_auth_ibss(struct ieee80211_sub_if_data *sdata, struct ieee80211_mgmt *mgmt, size_t len) { - u16 auth_alg, auth_transaction, status_code; + u16 auth_alg, auth_transaction; lockdep_assert_held(&sdata->u.ibss.mtx); @@ -49,7 +49,6 @@ static void ieee80211_rx_mgmt_auth_ibss(struct ieee80211_sub_if_data *sdata, auth_alg = le16_to_cpu(mgmt->u.auth.auth_alg); auth_transaction = le16_to_cpu(mgmt->u.auth.auth_transaction); - status_code = le16_to_cpu(mgmt->u.auth.status_code); /* * IEEE 802.11 standard does not require authentication in IBSS @@ -527,8 +526,6 @@ static void ieee80211_sta_merge_ibss(struct ieee80211_sub_if_data *sdata) static void ieee80211_sta_create_ibss(struct ieee80211_sub_if_data *sdata) { struct ieee80211_if_ibss *ifibss = &sdata->u.ibss; - struct ieee80211_local *local = sdata->local; - struct ieee80211_supported_band *sband; u8 bssid[ETH_ALEN]; u16 capability; int i; @@ -551,8 +548,6 @@ static void ieee80211_sta_create_ibss(struct ieee80211_sub_if_data *sdata) printk(KERN_DEBUG "%s: Creating new IBSS network, BSSID %pM\n", sdata->name, bssid); - sband = local->hw.wiphy->bands[ifibss->channel->band]; - capability = WLAN_CAPABILITY_IBSS; if (ifibss->privacy) diff --git a/net/mac80211/mesh.c b/net/mac80211/mesh.c index 1120797..c1299e2 100644 --- a/net/mac80211/mesh.c +++ b/net/mac80211/mesh.c @@ -613,12 +613,9 @@ void ieee80211_mesh_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb) { struct ieee80211_rx_status *rx_status; - struct ieee80211_if_mesh *ifmsh; struct ieee80211_mgmt *mgmt; u16 stype; - ifmsh = &sdata->u.mesh; - rx_status = IEEE80211_SKB_RXCB(skb); mgmt = (struct ieee80211_mgmt *) skb->data; stype = le16_to_cpu(mgmt->frame_control) & IEEE80211_FCTL_STYPE; diff --git a/net/mac80211/mesh_hwmp.c b/net/mac80211/mesh_hwmp.c index 5bf64d7..e57f2e7 100644 --- a/net/mac80211/mesh_hwmp.c +++ b/net/mac80211/mesh_hwmp.c @@ -633,7 +633,6 @@ static void hwmp_perr_frame_process(struct ieee80211_sub_if_data *sdata, struct mesh_path *mpath; u8 ttl; u8 *ta, *target_addr; - u8 target_flags; u32 target_sn; u16 target_rcode; @@ -644,7 +643,6 @@ static void hwmp_perr_frame_process(struct ieee80211_sub_if_data *sdata, return; } ttl--; - target_flags = PERR_IE_TARGET_FLAGS(perr_elem); target_addr = PERR_IE_TARGET_ADDR(perr_elem); target_sn = PERR_IE_TARGET_SN(perr_elem); target_rcode = PERR_IE_TARGET_RCODE(perr_elem); @@ -675,12 +673,10 @@ static void hwmp_rann_frame_process(struct ieee80211_sub_if_data *sdata, { struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; struct mesh_path *mpath; - u8 *ta; u8 ttl, flags, hopcount; u8 *orig_addr; u32 orig_sn, metric; - ta = mgmt->sa; ttl = rann->rann_ttl; if (ttl <= 1) { ifmsh->mshstats.dropped_frames_ttl++; diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c index 7c5c6da..f05244d 100644 --- a/net/mac80211/sta_info.c +++ b/net/mac80211/sta_info.c @@ -587,7 +587,6 @@ static bool sta_info_cleanup_expire_buffered(struct ieee80211_local *local, { unsigned long flags; struct sk_buff *skb; - struct ieee80211_sub_if_data *sdata; if (skb_queue_empty(&sta->ps_tx_buf)) return false; @@ -604,7 +603,6 @@ static bool sta_info_cleanup_expire_buffered(struct ieee80211_local *local, if (!skb) break; - sdata = sta->sdata; local->total_ps_buffered--; #ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG printk(KERN_DEBUG "Buffered frame expired (STA %pM)\n", diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index 17b10be..a2043e4 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -1036,14 +1036,11 @@ static bool __ieee80211_parse_tx_radiotap(struct ieee80211_tx_data *tx, struct ieee80211_radiotap_iterator iterator; struct ieee80211_radiotap_header *rthdr = (struct ieee80211_radiotap_header *) skb->data; - struct ieee80211_supported_band *sband; bool hw_frag; struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); int ret = ieee80211_radiotap_iterator_init(&iterator, rthdr, skb->len, NULL); - sband = tx->local->hw.wiphy->bands[tx->channel->band]; - info->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT; tx->flags &= ~IEEE80211_TX_FRAGMENTED; @@ -1442,11 +1439,8 @@ static bool ieee80211_tx(struct ieee80211_sub_if_data *sdata, struct ieee80211_tx_data tx; ieee80211_tx_result res_prepare; struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); - u16 queue; bool result = true; - queue = skb_get_queue_mapping(skb); - if (unlikely(skb->len < 10)) { dev_kfree_skb(skb); return true; @@ -2485,7 +2479,6 @@ ieee80211_get_buffered_bc(struct ieee80211_hw *hw, { struct ieee80211_local *local = hw_to_local(hw); struct sk_buff *skb = NULL; - struct sta_info *sta; struct ieee80211_tx_data tx; struct ieee80211_sub_if_data *sdata; struct ieee80211_if_ap *bss = NULL; @@ -2527,7 +2520,6 @@ ieee80211_get_buffered_bc(struct ieee80211_hw *hw, info = IEEE80211_SKB_CB(skb); - sta = tx.sta; tx.flags |= IEEE80211_TX_PS_BUFFERED; tx.channel = local->hw.conf.channel; info->band = tx.channel->band; diff --git a/net/mac80211/work.c b/net/mac80211/work.c index e73c8ca..a94b312 100644 --- a/net/mac80211/work.c +++ b/net/mac80211/work.c @@ -198,9 +198,8 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb; struct ieee80211_mgmt *mgmt; u8 *pos, qos_info; - const u8 *ies; size_t offset = 0, noffset; - int i, len, count, rates_len, supp_rates_len; + int i, count, rates_len, supp_rates_len; u16 capab; struct ieee80211_supported_band *sband; u32 rates = 0; @@ -285,7 +284,7 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata, } /* SSID */ - ies = pos = skb_put(skb, 2 + wk->assoc.ssid_len); + pos = skb_put(skb, 2 + wk->assoc.ssid_len); *pos++ = WLAN_EID_SSID; *pos++ = wk->assoc.ssid_len; memcpy(pos, wk->assoc.ssid, wk->assoc.ssid_len); @@ -295,7 +294,6 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata, if (supp_rates_len > 8) supp_rates_len = 8; - len = sband->n_bitrates; pos = skb_put(skb, supp_rates_len + 2); *pos++ = WLAN_EID_SUPP_RATES; *pos++ = supp_rates_len; -- cgit v0.10.2 From e25f51d4f9f8c45382a33b6283418be46425195c Mon Sep 17 00:00:00 2001 From: Chaoming_Li Date: Mon, 25 Apr 2011 12:52:44 -0500 Subject: rtlwifi: Change efuse routines addition of RTL8192SE and RTL8192DE Change efuse routines for addition of RTL8192SE and RTL8192DE code Signed-off-by: Chaoming_Li Signed-off-by: Larry Finger Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/rtlwifi/efuse.c b/drivers/net/wireless/rtlwifi/efuse.c index 5d73c0f..664703c 100644 --- a/drivers/net/wireless/rtlwifi/efuse.c +++ b/drivers/net/wireless/rtlwifi/efuse.c @@ -52,8 +52,6 @@ static const struct efuse_map RTL8712_SDIO_EFUSE_TABLE[] = { {11, 0, 0, 28} }; -static void read_efuse_byte(struct ieee80211_hw *hw, u16 _offset, - u8 *pbuf); static void efuse_shadow_read_1byte(struct ieee80211_hw *hw, u16 offset, u8 *value); static void efuse_shadow_read_2byte(struct ieee80211_hw *hw, u16 offset, @@ -79,7 +77,7 @@ static void efuse_word_enable_data_read(u8 word_en, u8 *sourdata, u8 *targetdata); static u8 efuse_word_enable_data_write(struct ieee80211_hw *hw, u16 efuse_addr, u8 word_en, u8 *data); -static void efuse_power_switch(struct ieee80211_hw *hw, u8 bwrite, +static void efuse_power_switch(struct ieee80211_hw *hw, u8 write, u8 pwrstate); static u16 efuse_get_current_size(struct ieee80211_hw *hw); static u8 efuse_calculate_word_cnts(u8 word_en); @@ -115,8 +113,10 @@ u8 efuse_read_1byte(struct ieee80211_hw *hw, u16 address) u8 bytetemp; u8 temp; u32 k = 0; + const u32 efuse_len = + rtlpriv->cfg->maps[EFUSE_REAL_CONTENT_SIZE]; - if (address < EFUSE_REAL_CONTENT_LEN) { + if (address < efuse_len) { temp = address & 0xFF; rtl_write_byte(rtlpriv, rtlpriv->cfg->maps[EFUSE_CTRL] + 1, temp); @@ -158,11 +158,13 @@ void efuse_write_1byte(struct ieee80211_hw *hw, u16 address, u8 value) u8 bytetemp; u8 temp; u32 k = 0; + const u32 efuse_len = + rtlpriv->cfg->maps[EFUSE_REAL_CONTENT_SIZE]; RT_TRACE(rtlpriv, COMP_EFUSE, DBG_LOUD, ("Addr=%x Data =%x\n", address, value)); - if (address < EFUSE_REAL_CONTENT_LEN) { + if (address < efuse_len) { rtl_write_byte(rtlpriv, rtlpriv->cfg->maps[EFUSE_CTRL], value); temp = address & 0xFF; @@ -198,7 +200,7 @@ void efuse_write_1byte(struct ieee80211_hw *hw, u16 address, u8 value) } -static void read_efuse_byte(struct ieee80211_hw *hw, u16 _offset, u8 *pbuf) +void read_efuse_byte(struct ieee80211_hw *hw, u16 _offset, u8 *pbuf) { struct rtl_priv *rtlpriv = rtl_priv(hw); u32 value32; @@ -233,24 +235,28 @@ void read_efuse(struct ieee80211_hw *hw, u16 _offset, u16 _size_byte, u8 *pbuf) { struct rtl_priv *rtlpriv = rtl_priv(hw); struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw)); - u8 efuse_tbl[EFUSE_MAP_LEN]; + u8 efuse_tbl[rtlpriv->cfg->maps[EFUSE_HWSET_MAX_SIZE]]; u8 rtemp8[1]; u16 efuse_addr = 0; u8 offset, wren; u16 i; u16 j; - u16 efuse_word[EFUSE_MAX_SECTION][EFUSE_MAX_WORD_UNIT]; + const u16 efuse_max_section = + rtlpriv->cfg->maps[EFUSE_MAX_SECTION_MAP]; + const u32 efuse_len = + rtlpriv->cfg->maps[EFUSE_REAL_CONTENT_SIZE]; + u16 efuse_word[efuse_max_section][EFUSE_MAX_WORD_UNIT]; u16 efuse_utilized = 0; u8 efuse_usage; - if ((_offset + _size_byte) > EFUSE_MAP_LEN) { + if ((_offset + _size_byte) > rtlpriv->cfg->maps[EFUSE_HWSET_MAX_SIZE]) { RT_TRACE(rtlpriv, COMP_EFUSE, DBG_LOUD, ("read_efuse(): Invalid offset(%#x) with read " "bytes(%#x)!!\n", _offset, _size_byte)); return; } - for (i = 0; i < EFUSE_MAX_SECTION; i++) + for (i = 0; i < efuse_max_section; i++) for (j = 0; j < EFUSE_MAX_WORD_UNIT; j++) efuse_word[i][j] = 0xFFFF; @@ -262,10 +268,10 @@ void read_efuse(struct ieee80211_hw *hw, u16 _offset, u16 _size_byte, u8 *pbuf) efuse_addr++; } - while ((*rtemp8 != 0xFF) && (efuse_addr < EFUSE_REAL_CONTENT_LEN)) { + while ((*rtemp8 != 0xFF) && (efuse_addr < efuse_len)) { offset = ((*rtemp8 >> 4) & 0x0f); - if (offset < EFUSE_MAX_SECTION) { + if (offset < efuse_max_section) { wren = (*rtemp8 & 0x0f); RTPRINT(rtlpriv, FEEPROM, EFUSE_READ_ALL, ("offset-%d Worden=%x\n", offset, wren)); @@ -281,7 +287,7 @@ void read_efuse(struct ieee80211_hw *hw, u16 _offset, u16 _size_byte, u8 *pbuf) efuse_utilized++; efuse_word[offset][i] = (*rtemp8 & 0xff); - if (efuse_addr >= EFUSE_REAL_CONTENT_LEN) + if (efuse_addr >= efuse_len) break; RTPRINT(rtlpriv, FEEPROM, @@ -294,7 +300,7 @@ void read_efuse(struct ieee80211_hw *hw, u16 _offset, u16 _size_byte, u8 *pbuf) efuse_word[offset][i] |= (((u16)*rtemp8 << 8) & 0xff00); - if (efuse_addr >= EFUSE_REAL_CONTENT_LEN) + if (efuse_addr >= efuse_len) break; } @@ -305,13 +311,13 @@ void read_efuse(struct ieee80211_hw *hw, u16 _offset, u16 _size_byte, u8 *pbuf) RTPRINT(rtlpriv, FEEPROM, EFUSE_READ_ALL, ("Addr=%d\n", efuse_addr)); read_efuse_byte(hw, efuse_addr, rtemp8); - if (*rtemp8 != 0xFF && (efuse_addr < 512)) { + if (*rtemp8 != 0xFF && (efuse_addr < efuse_len)) { efuse_utilized++; efuse_addr++; } } - for (i = 0; i < EFUSE_MAX_SECTION; i++) { + for (i = 0; i < efuse_max_section; i++) { for (j = 0; j < EFUSE_MAX_WORD_UNIT; j++) { efuse_tbl[(i * 8) + (j * 2)] = (efuse_word[i][j] & 0xff); @@ -324,7 +330,7 @@ void read_efuse(struct ieee80211_hw *hw, u16 _offset, u16 _size_byte, u8 *pbuf) pbuf[i] = efuse_tbl[_offset + i]; rtlefuse->efuse_usedbytes = efuse_utilized; - efuse_usage = (u8)((efuse_utilized * 100) / EFUSE_REAL_CONTENT_LEN); + efuse_usage = (u8) ((efuse_utilized * 100) / efuse_len); rtlefuse->efuse_usedpercentage = efuse_usage; rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_EFUSE_BYTES, (u8 *)&efuse_utilized); @@ -478,9 +484,10 @@ void rtl_efuse_shadow_map_update(struct ieee80211_hw *hw) struct rtl_priv *rtlpriv = rtl_priv(hw); struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw)); - if (rtlefuse->autoload_failflag == true) { - memset(&rtlefuse->efuse_map[EFUSE_INIT_MAP][0], 0xFF, 128); - } else + if (rtlefuse->autoload_failflag == true) + memset(&rtlefuse->efuse_map[EFUSE_INIT_MAP][0], 0xFF, + rtlpriv->cfg->maps[EFUSE_HWSET_MAX_SIZE]); + else efuse_read_all_map(hw, &rtlefuse->efuse_map[EFUSE_INIT_MAP][0]); memcpy(&rtlefuse->efuse_map[EFUSE_MODIFY_MAP][0], @@ -632,8 +639,9 @@ static int efuse_one_byte_write(struct ieee80211_hw *hw, u16 addr, u8 data) static void efuse_read_all_map(struct ieee80211_hw *hw, u8 * efuse) { + struct rtl_priv *rtlpriv = rtl_priv(hw); efuse_power_switch(hw, false, true); - read_efuse(hw, 0, 128, efuse); + read_efuse(hw, 0, rtlpriv->cfg->maps[EFUSE_HWSET_MAX_SIZE], efuse); efuse_power_switch(hw, false, false); } @@ -641,7 +649,7 @@ static void efuse_read_data_case1(struct ieee80211_hw *hw, u16 *efuse_addr, u8 efuse_data, u8 offset, u8 *tmpdata, u8 *readstate) { - bool bdataempty = true; + bool dataempty = true; u8 hoffset; u8 tmpidx; u8 hworden; @@ -657,13 +665,13 @@ static void efuse_read_data_case1(struct ieee80211_hw *hw, u16 *efuse_addr, &efuse_data)) { tmpdata[tmpidx] = efuse_data; if (efuse_data != 0xff) - bdataempty = true; + dataempty = true; } } - if (bdataempty == true) + if (dataempty == true) { *readstate = PG_STATE_DATA; - else { + } else { *efuse_addr = *efuse_addr + (word_cnts * 2) + 1; *readstate = PG_STATE_HEADER; } @@ -677,9 +685,7 @@ static void efuse_read_data_case1(struct ieee80211_hw *hw, u16 *efuse_addr, static int efuse_pg_packet_read(struct ieee80211_hw *hw, u8 offset, u8 *data) { u8 readstate = PG_STATE_HEADER; - bool continual = true; - u8 efuse_data, word_cnts = 0; u16 efuse_addr = 0; u8 tmpdata[8]; @@ -795,19 +801,20 @@ static void efuse_write_data_case1(struct ieee80211_hw *hw, u16 *efuse_addr, tmp_word_en &= (~BIT(1)); if ((target_pkt->word_en & BIT(2)) ^ - (match_word_en & BIT(2))) + (match_word_en & BIT(2))) tmp_word_en &= (~BIT(2)); if ((target_pkt->word_en & BIT(3)) ^ - (match_word_en & BIT(3))) + (match_word_en & BIT(3))) tmp_word_en &= (~BIT(3)); if ((tmp_word_en & 0x0F) != 0x0F) { *efuse_addr = efuse_get_current_size(hw); target_pkt->offset = offset; target_pkt->word_en = tmp_word_en; - } else + } else { *continual = false; + } *write_state = PG_STATE_HEADER; *repeat_times += 1; if (*repeat_times > EFUSE_REPEAT_THRESHOLD_) { @@ -842,9 +849,9 @@ static void efuse_write_data_case2(struct ieee80211_hw *hw, u16 *efuse_addr, efuse_one_byte_write(hw, *efuse_addr, pg_header); efuse_one_byte_read(hw, *efuse_addr, &tmp_header); - if (tmp_header == pg_header) + if (tmp_header == pg_header) { *write_state = PG_STATE_DATA; - else if (tmp_header == 0xFF) { + } else if (tmp_header == 0xFF) { *write_state = PG_STATE_HEADER; *repeat_times += 1; if (*repeat_times > EFUSE_REPEAT_THRESHOLD_) { @@ -871,11 +878,13 @@ static void efuse_write_data_case2(struct ieee80211_hw *hw, u16 *efuse_addr, reorg_worden, originaldata); *efuse_addr = efuse_get_current_size(hw); - } else + } else { *efuse_addr = *efuse_addr + (tmp_word_cnts * 2) + 1; - } else + } + } else { *efuse_addr = *efuse_addr + (tmp_word_cnts * 2) + 1; + } *write_state = PG_STATE_HEADER; *repeat_times += 1; @@ -1069,10 +1078,12 @@ static u8 efuse_word_enable_data_write(struct ieee80211_hw *hw, static void efuse_power_switch(struct ieee80211_hw *hw, u8 write, u8 pwrstate) { struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); u8 tempval; u16 tmpV16; - if (pwrstate) { + if (pwrstate && (rtlhal->hw_type != + HARDWARE_TYPE_RTL8192SE)) { tmpV16 = rtl_read_word(rtlpriv, rtlpriv->cfg->maps[SYS_ISO_CTRL]); if (!(tmpV16 & rtlpriv->cfg->maps[EFUSE_PWC_EV12V])) { @@ -1105,13 +1116,22 @@ static void efuse_power_switch(struct ieee80211_hw *hw, u8 write, u8 pwrstate) tempval = rtl_read_byte(rtlpriv, rtlpriv->cfg->maps[EFUSE_TEST] + 3); - tempval &= 0x0F; - tempval |= (VOLTAGE_V25 << 4); + + if (rtlhal->hw_type != HARDWARE_TYPE_RTL8192SE) { + tempval &= 0x0F; + tempval |= (VOLTAGE_V25 << 4); + } + rtl_write_byte(rtlpriv, rtlpriv->cfg->maps[EFUSE_TEST] + 3, (tempval | 0x80)); } + if (rtlhal->hw_type == HARDWARE_TYPE_RTL8192SE) { + rtl_write_byte(rtlpriv, rtlpriv->cfg->maps[EFUSE_CLK], + 0x03); + } + } else { if (write) { tempval = rtl_read_byte(rtlpriv, @@ -1122,6 +1142,11 @@ static void efuse_power_switch(struct ieee80211_hw *hw, u8 write, u8 pwrstate) (tempval & 0x7F)); } + if (rtlhal->hw_type == HARDWARE_TYPE_RTL8192SE) { + rtl_write_byte(rtlpriv, rtlpriv->cfg->maps[EFUSE_CLK], + 0x02); + } + } } diff --git a/drivers/net/wireless/rtlwifi/efuse.h b/drivers/net/wireless/rtlwifi/efuse.h index 47774dd..164daba 100644 --- a/drivers/net/wireless/rtlwifi/efuse.h +++ b/drivers/net/wireless/rtlwifi/efuse.h @@ -30,9 +30,10 @@ #ifndef __RTL_EFUSE_H_ #define __RTL_EFUSE_H_ +#define EFUSE_IC_ID_OFFSET 506 + #define EFUSE_REAL_CONTENT_LEN 512 #define EFUSE_MAP_LEN 128 -#define EFUSE_MAX_SECTION 16 #define EFUSE_MAX_WORD_UNIT 4 #define EFUSE_INIT_MAP 0 @@ -52,6 +53,7 @@ #define _PRE_EXECUTE_READ_CMD_ #define EFUSE_REPEAT_THRESHOLD_ 3 +#define EFUSE_ERROE_HANDLE 1 struct efuse_map { u8 offset; @@ -103,6 +105,7 @@ struct efuse_priv { u8 tx_power_g[14]; }; +extern void read_efuse_byte(struct ieee80211_hw *hw, u16 _offset, u8 *pbuf); extern void efuse_initialize(struct ieee80211_hw *hw); extern u8 efuse_read_1byte(struct ieee80211_hw *hw, u16 address); extern void efuse_write_1byte(struct ieee80211_hw *hw, u16 address, u8 value); -- cgit v0.10.2 From 3dad618b7b929010f05b179bbc4d56e3d5956083 Mon Sep 17 00:00:00 2001 From: Chaoming_Li Date: Mon, 25 Apr 2011 12:52:49 -0500 Subject: rtlwifi: Change wifi.h for rtl8192se and rtl8192de Change wifi.h for addition of RTL8192SE and RTL8192DE code Signed-off-by: Chaoming_Li Signed-off-by: Larry Finger Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/rtlwifi/rtl8192c/dm_common.c b/drivers/net/wireless/rtlwifi/rtl8192c/dm_common.c index c228b9e..5ea3a5e 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192c/dm_common.c +++ b/drivers/net/wireless/rtlwifi/rtl8192c/dm_common.c @@ -640,7 +640,7 @@ static void rtl92c_dm_txpower_tracking_callback_thermalmeter(struct ieee80211_hw u8 txpwr_level[2] = {0, 0}; u8 ofdm_min_index = 6, rf; - rtlpriv->dm.txpower_trackingInit = true; + rtlpriv->dm.txpower_trackinginit = true; RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD, ("rtl92c_dm_txpower_tracking_callback_thermalmeter\n")); @@ -1062,7 +1062,7 @@ static void rtl92c_dm_initialize_txpower_tracking_thermalmeter( struct rtl_priv *rtlpriv = rtl_priv(hw); rtlpriv->dm.txpower_tracking = true; - rtlpriv->dm.txpower_trackingInit = false; + rtlpriv->dm.txpower_trackinginit = false; RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD, ("pMgntInfo->txpower_tracking = %d\n", diff --git a/drivers/net/wireless/rtlwifi/wifi.h b/drivers/net/wireless/rtlwifi/wifi.h index 4ce4853..9124b30 100644 --- a/drivers/net/wireless/rtlwifi/wifi.h +++ b/drivers/net/wireless/rtlwifi/wifi.h @@ -68,6 +68,8 @@ #define QBSS_LOAD_SIZE 5 #define MAX_WMMELE_LENGTH 64 +#define TOTAL_CAM_ENTRY 32 + /*slot time for 11g. */ #define RTL_SLOT_TIME_9 9 #define RTL_SLOT_TIME_20 20 @@ -94,8 +96,10 @@ #define CHANNEL_GROUP_MAX_5G 9 #define CHANNEL_MAX_NUMBER_2G 14 #define AVG_THERMAL_NUM 8 +#define MAX_TID_COUNT 9 /* for early mode */ +#define FCS_LEN 4 #define EM_HDR_LEN 8 enum intf_type { INTF_PCI = 0, @@ -159,6 +163,8 @@ enum hardware_type { (IS_HARDWARE_TYPE_8192DE(rtlhal) || IS_HARDWARE_TYPE_8192DU(rtlhal)) #define IS_HARDWARE_TYPE_8723(rtlhal) \ (IS_HARDWARE_TYPE_8723E(rtlhal) || IS_HARDWARE_TYPE_8723U(rtlhal)) +#define IS_HARDWARE_TYPE_8723U(rtlhal) \ + (rtlhal->hw_type == HARDWARE_TYPE_RTL8723U) enum scan_operation_backup_opt { SCAN_OPT_BACKUP = 0, @@ -843,6 +849,7 @@ struct rtl_phy { bool apk_done; u32 reg_rf3c[2]; /* pathA / pathB */ + /* bfsync */ u8 framesync; u32 framesync_c34; @@ -852,6 +859,10 @@ struct rtl_phy { }; #define MAX_TID_COUNT 9 +#define RTL_AGG_STOP 0 +#define RTL_AGG_PROGRESS 1 +#define RTL_AGG_START 2 +#define RTL_AGG_OPERATIONAL 3 #define RTL_AGG_OFF 0 #define RTL_AGG_ON 1 #define RTL_AGG_EMPTYING_HW_QUEUE_ADDBA 2 @@ -871,6 +882,13 @@ struct rtl_tid_data { struct rtl_ht_agg agg; }; +struct rtl_sta_info { + u8 ratr_index; + u8 wireless_mode; + u8 mimo_ps; + struct rtl_tid_data tids[MAX_TID_COUNT]; +} __packed; + struct rtl_priv; struct rtl_io { struct device *dev; @@ -894,6 +912,7 @@ struct rtl_io { u32(*read32_sync) (struct rtl_priv *rtlpriv, u32 addr); int (*readN_sync) (struct rtl_priv *rtlpriv, u32 addr, u16 len, u8 *pdata); + }; struct rtl_mac { @@ -916,6 +935,8 @@ struct rtl_mac { int n_channels; int n_bitrates; + bool offchan_deley; + /*filters */ u32 rx_conf; u16 rx_mgt_filter; @@ -1032,7 +1053,9 @@ struct rtl_security { enum rt_enc_alg pairwise_enc_algorithm; /*Encryption Algorithm for Brocast/Multicast */ enum rt_enc_alg group_enc_algorithm; - + /*Cam Entry Bitmap */ + u32 hwsec_cam_bitmap; + u8 hwsec_cam_sta_addr[TOTAL_CAM_ENTRY][ETH_ALEN]; /*local Key buffer, indx 0 is for pairwise key 1-4 is for agoup key. */ u8 key_buf[KEY_BUF_SIZE][MAX_KEY_LEN]; @@ -1053,7 +1076,7 @@ struct rtl_dm { bool current_turbo_edca; bool is_any_nonbepkts; /*out dm */ bool is_cur_rdlstate; - bool txpower_trackingInit; + bool txpower_trackinginit; bool disable_framebursting; bool cck_inch14; bool txpower_tracking; @@ -1079,7 +1102,6 @@ struct rtl_dm { bool disable_tx_int; char ofdm_index[2]; char cck_index; - u8 power_index_backup[6]; }; #define EFUSE_MAX_LOGICAL_SIZE 256 @@ -1175,6 +1197,7 @@ struct rtl_ps_ctl { * otherwise Offset[560h] = 0x00. * */ bool support_aspm; + bool support_backdoor; /*for LPS */ @@ -1201,7 +1224,6 @@ struct rtl_ps_ctl { /*just for PCIE ASPM */ u8 const_amdpci_aspm; - bool pwrdown_mode; enum rf_pwrstate inactive_pwrstate; @@ -1282,6 +1304,10 @@ struct rt_link_detect { bool busytraffic; bool higher_busytraffic; bool higher_busyrxtraffic; + + u32 tidtx_in4period[MAX_TID_COUNT][4]; + u32 tidtx_inperiod[MAX_TID_COUNT]; + bool higher_busytxtraffic[MAX_TID_COUNT]; }; struct rtl_tcb_desc { @@ -1344,13 +1370,26 @@ struct rtl_hal_ops { u32 add_msr, u32 rm_msr); void (*get_hw_reg) (struct ieee80211_hw *hw, u8 variable, u8 *val); void (*set_hw_reg) (struct ieee80211_hw *hw, u8 variable, u8 *val); +#if 0 /* temporary */ + void (*update_rate_tbl) (struct ieee80211_hw *hw, + struct ieee80211_sta *sta, u8 rssi_level); +#else void (*update_rate_table) (struct ieee80211_hw *hw); +#endif void (*update_rate_mask) (struct ieee80211_hw *hw, u8 rssi_level); +#if 0 /* temporary */ + void (*fill_tx_desc) (struct ieee80211_hw *hw, + struct ieee80211_hdr *hdr, u8 *pdesc_tx, + struct ieee80211_tx_info *info, + struct sk_buff *skb, u8 hw_queue, + struct rtl_tcb_desc *ptcb_desc); +#else void (*fill_tx_desc) (struct ieee80211_hw *hw, struct ieee80211_hdr *hdr, u8 *pdesc_tx, struct ieee80211_tx_info *info, struct sk_buff *skb, unsigned int queue_index); - void (*fill_fake_txdesc) (struct ieee80211_hw *hw, u8 * pDesc, +#endif + void (*fill_fake_txdesc) (struct ieee80211_hw *hw, u8 *pDesc, u32 buffer_len, bool bIsPsPoll); void (*fill_tx_cmddesc) (struct ieee80211_hw *hw, u8 *pdesc, bool firstseg, bool lastseg, @@ -1370,10 +1409,10 @@ struct rtl_hal_ops { enum led_ctl_mode ledaction); void (*set_desc) (u8 *pdesc, bool istx, u8 desc_name, u8 *val); u32 (*get_desc) (u8 *pdesc, bool istx, u8 desc_name); - void (*tx_polling) (struct ieee80211_hw *hw, unsigned int hw_queue); + void (*tx_polling) (struct ieee80211_hw *hw, u8 hw_queue); void (*enable_hw_sec) (struct ieee80211_hw *hw); void (*set_key) (struct ieee80211_hw *hw, u32 key_index, - u8 *p_macaddr, bool is_group, u8 enc_algo, + u8 *macaddr, bool is_group, u8 enc_algo, bool is_wepkey, bool clear_all); void (*init_sw_leds) (struct ieee80211_hw *hw); void (*deinit_sw_leds) (struct ieee80211_hw *hw); @@ -1384,6 +1423,7 @@ struct rtl_hal_ops { u32 regaddr, u32 bitmask); void (*set_rfreg) (struct ieee80211_hw *hw, enum radio_path rfpath, u32 regaddr, u32 bitmask, u32 data); + void (*linked_set_reg) (struct ieee80211_hw *hw); bool (*phy_rf6052_config) (struct ieee80211_hw *hw); void (*phy_rf6052_set_cck_txpower) (struct ieee80211_hw *hw, u8 *powerlevel); @@ -1404,7 +1444,13 @@ struct rtl_intf_ops { int (*adapter_start) (struct ieee80211_hw *hw); void (*adapter_stop) (struct ieee80211_hw *hw); +#if 0 /* temporary */ + int (*adapter_tx) (struct ieee80211_hw *hw, struct sk_buff *skb, + struct rtl_tcb_desc *ptcb_desc); +#else int (*adapter_tx) (struct ieee80211_hw *hw, struct sk_buff *skb); +#endif + void (*flush)(struct ieee80211_hw *hw, bool drop); int (*reset_trx_ring) (struct ieee80211_hw *hw); bool (*waitq_insert) (struct ieee80211_hw *hw, struct sk_buff *skb); @@ -1418,6 +1464,15 @@ struct rtl_intf_ops { struct rtl_mod_params { /* default: 0 = using hardware encryption */ int sw_crypto; + + /* default: 1 = using no linked power save */ + bool inactiveps; + + /* default: 1 = using linked sw power save */ + bool swctrl_lps; + + /* default: 1 = using linked fw power save */ + bool fwctrl_lps; }; struct rtl_hal_usbint_cfg { @@ -1445,6 +1500,7 @@ struct rtl_hal_usbint_cfg { struct rtl_hal_cfg { u8 bar_id; + bool write_readback; char *name; char *fw_name; struct rtl_hal_ops *ops; @@ -1469,7 +1525,6 @@ struct rtl_locks { spinlock_t rf_lock; spinlock_t lps_lock; spinlock_t waitq_lock; - spinlock_t tx_urb_lock; /*Dual mac*/ spinlock_t cck_and_rw_pagea_lock; @@ -1653,13 +1708,23 @@ struct bt_coexist_info { #define EF4BYTE(_val) \ (le32_to_cpu(_val)) +/* Read data from memory */ +#define READEF1BYTE(_ptr) \ + EF1BYTE(*((u8 *)(_ptr))) /* Read le16 data from memory and convert to host ordering */ #define READEF2BYTE(_ptr) \ EF2BYTE(*((u16 *)(_ptr))) +#define READEF4BYTE(_ptr) \ + EF4BYTE(*((u32 *)(_ptr))) +/* Write data to memory */ +#define WRITEEF1BYTE(_ptr, _val) \ + (*((u8 *)(_ptr))) = EF1BYTE(_val) /* Write le16 data to memory in host ordering */ #define WRITEEF2BYTE(_ptr, _val) \ (*((u16 *)(_ptr))) = EF2BYTE(_val) +#define WRITEEF4BYTE(_ptr, _val) \ + (*((u16 *)(_ptr))) = EF2BYTE(_val) /* Create a bit mask * Examples: @@ -1698,6 +1763,25 @@ struct bt_coexist_info { #define LE_P1BYTE_TO_HOST_1BYTE(__pstart) \ (EF1BYTE(*((u8 *)(__pstart)))) +/*Description: +Translate subfield (continuous bits in little-endian) of 4-byte +value to host byte ordering.*/ +#define LE_BITS_TO_4BYTE(__pstart, __bitoffset, __bitlen) \ + ( \ + (LE_P4BYTE_TO_HOST_4BYTE(__pstart) >> (__bitoffset)) & \ + BIT_LEN_MASK_32(__bitlen) \ + ) +#define LE_BITS_TO_2BYTE(__pstart, __bitoffset, __bitlen) \ + ( \ + (LE_P2BYTE_TO_HOST_2BYTE(__pstart) >> (__bitoffset)) & \ + BIT_LEN_MASK_16(__bitlen) \ + ) +#define LE_BITS_TO_1BYTE(__pstart, __bitoffset, __bitlen) \ + ( \ + (LE_P1BYTE_TO_HOST_1BYTE(__pstart) >> (__bitoffset)) & \ + BIT_LEN_MASK_8(__bitlen) \ + ) + /* Description: * Mask subfield (continuous bits in little-endian) of 4-byte value * and return the result in 4-byte value in host byte ordering. @@ -1721,6 +1805,18 @@ struct bt_coexist_info { /* Description: * Set subfield of little-endian 4-byte value to specified value. */ +#define SET_BITS_TO_LE_4BYTE(__pstart, __bitoffset, __bitlen, __val) \ + *((u32 *)(__pstart)) = EF4BYTE \ + ( \ + LE_BITS_CLEARED_TO_4BYTE(__pstart, __bitoffset, __bitlen) | \ + ((((u32)__val) & BIT_LEN_MASK_32(__bitlen)) << (__bitoffset)) \ + ); +#define SET_BITS_TO_LE_2BYTE(__pstart, __bitoffset, __bitlen, __val) \ + *((u16 *)(__pstart)) = EF2BYTE \ + ( \ + LE_BITS_CLEARED_TO_2BYTE(__pstart, __bitoffset, __bitlen) | \ + ((((u16)__val) & BIT_LEN_MASK_16(__bitlen)) << (__bitoffset)) \ + ); #define SET_BITS_TO_LE_1BYTE(__pstart, __bitoffset, __bitlen, __val) \ *((u8 *)(__pstart)) = EF1BYTE \ ( \ @@ -1728,12 +1824,16 @@ struct bt_coexist_info { ((((u8)__val) & BIT_LEN_MASK_8(__bitlen)) << (__bitoffset)) \ ); +#define N_BYTE_ALIGMENT(__value, __aligment) ((__aligment == 1) ? \ + (__value) : (((__value + __aligment - 1) / __aligment) * __aligment)) + /**************************************** mem access macro define end ****************************************/ #define byte(x, n) ((x >> (8 * n)) & 0xff) +#define packet_get_type(_packet) (EF1BYTE((_packet).octet[0]) & 0xFC) #define RTL_WATCH_DOG_TIME 2000 #define MSECS(t) msecs_to_jiffies(t) #define WLAN_FC_GET_VERS(fc) (le16_to_cpu(fc) & IEEE80211_FCTL_VERS) @@ -1768,6 +1868,15 @@ struct bt_coexist_info { #define container_of_dwork_rtl(x, y, z) \ container_of(container_of(x, struct delayed_work, work), y, z) +#define FILL_OCTET_STRING(_os, _octet, _len) \ + (_os).octet = (u8 *)(_octet); \ + (_os).length = (_len); + +#define CP_MACADDR(des, src) \ + ((des)[0] = (src)[0], (des)[1] = (src)[1],\ + (des)[2] = (src)[2], (des)[3] = (src)[3],\ + (des)[4] = (src)[4], (des)[5] = (src)[5]) + static inline u8 rtl_read_byte(struct rtl_priv *rtlpriv, u32 addr) { return rtlpriv->io.read8_sync(rtlpriv, addr); @@ -1786,17 +1895,26 @@ static inline u32 rtl_read_dword(struct rtl_priv *rtlpriv, u32 addr) static inline void rtl_write_byte(struct rtl_priv *rtlpriv, u32 addr, u8 val8) { rtlpriv->io.write8_async(rtlpriv, addr, val8); + + if (rtlpriv->cfg->write_readback) + rtlpriv->io.read8_sync(rtlpriv, addr); } static inline void rtl_write_word(struct rtl_priv *rtlpriv, u32 addr, u16 val16) { rtlpriv->io.write16_async(rtlpriv, addr, val16); + + if (rtlpriv->cfg->write_readback) + rtlpriv->io.read16_sync(rtlpriv, addr); } static inline void rtl_write_dword(struct rtl_priv *rtlpriv, u32 addr, u32 val32) { rtlpriv->io.write32_async(rtlpriv, addr, val32); + + if (rtlpriv->cfg->write_readback) + rtlpriv->io.read32_sync(rtlpriv, addr); } static inline u32 rtl_get_bbreg(struct ieee80211_hw *hw, @@ -1855,4 +1973,31 @@ static inline u8 get_rf_type(struct rtl_phy *rtlphy) return rtlphy->rf_type; } +static inline struct ieee80211_hdr *rtl_get_hdr(struct sk_buff *skb) +{ + return (struct ieee80211_hdr *)(skb->data); +} + +static inline u16 rtl_get_fc(struct sk_buff *skb) +{ + return le16_to_cpu(rtl_get_hdr(skb)->frame_control); +} + +static inline u16 rtl_get_tid_h(struct ieee80211_hdr *hdr) +{ + return (ieee80211_get_qos_ctl(hdr))[0] & IEEE80211_QOS_CTL_TID_MASK; +} + +static inline u16 rtl_get_tid(struct sk_buff *skb) +{ + return rtl_get_tid_h(rtl_get_hdr(skb)); +} + +static inline struct ieee80211_sta *get_sta(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + u8 *bssid) +{ + return ieee80211_find_sta(vif, bssid); +} + #endif -- cgit v0.10.2 From acd48572c396364bb480175d7de83944eefa2563 Mon Sep 17 00:00:00 2001 From: Chaoming_Li Date: Mon, 25 Apr 2011 12:52:54 -0500 Subject: rtlwifi: Change base routines for addition of rtl8192se and rtl8192de Change base routines for addition of RTL8192SE and RTL8192DE code. Additional files are modified to allow compilation. Signed-off-by: Chaoming_Li Signed-off-by: Larry Finger Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/rtlwifi/base.c b/drivers/net/wireless/rtlwifi/base.c index 9477785..7b3eadf 100644 --- a/drivers/net/wireless/rtlwifi/base.c +++ b/drivers/net/wireless/rtlwifi/base.c @@ -50,8 +50,9 @@ *3) functions called by core.c *4) wq & timer callback functions *5) frame process functions - *6) sysfs functions - *7) ... + *6) IOT functions + *7) sysfs functions + *8) ... */ /********************************************************* @@ -59,7 +60,7 @@ * mac80211 init functions * *********************************************************/ -static struct ieee80211_channel rtl_channeltable[] = { +static struct ieee80211_channel rtl_channeltable_2g[] = { {.center_freq = 2412, .hw_value = 1,}, {.center_freq = 2417, .hw_value = 2,}, {.center_freq = 2422, .hw_value = 3,}, @@ -76,7 +77,34 @@ static struct ieee80211_channel rtl_channeltable[] = { {.center_freq = 2484, .hw_value = 14,}, }; -static struct ieee80211_rate rtl_ratetable[] = { +static struct ieee80211_channel rtl_channeltable_5g[] = { + {.center_freq = 5180, .hw_value = 36,}, + {.center_freq = 5200, .hw_value = 40,}, + {.center_freq = 5220, .hw_value = 44,}, + {.center_freq = 5240, .hw_value = 48,}, + {.center_freq = 5260, .hw_value = 52,}, + {.center_freq = 5280, .hw_value = 56,}, + {.center_freq = 5300, .hw_value = 60,}, + {.center_freq = 5320, .hw_value = 64,}, + {.center_freq = 5500, .hw_value = 100,}, + {.center_freq = 5520, .hw_value = 104,}, + {.center_freq = 5540, .hw_value = 108,}, + {.center_freq = 5560, .hw_value = 112,}, + {.center_freq = 5580, .hw_value = 116,}, + {.center_freq = 5600, .hw_value = 120,}, + {.center_freq = 5620, .hw_value = 124,}, + {.center_freq = 5640, .hw_value = 128,}, + {.center_freq = 5660, .hw_value = 132,}, + {.center_freq = 5680, .hw_value = 136,}, + {.center_freq = 5700, .hw_value = 140,}, + {.center_freq = 5745, .hw_value = 149,}, + {.center_freq = 5765, .hw_value = 153,}, + {.center_freq = 5785, .hw_value = 157,}, + {.center_freq = 5805, .hw_value = 161,}, + {.center_freq = 5825, .hw_value = 165,}, +}; + +static struct ieee80211_rate rtl_ratetable_2g[] = { {.bitrate = 10, .hw_value = 0x00,}, {.bitrate = 20, .hw_value = 0x01,}, {.bitrate = 55, .hw_value = 0x02,}, @@ -91,18 +119,57 @@ static struct ieee80211_rate rtl_ratetable[] = { {.bitrate = 540, .hw_value = 0x0b,}, }; +static struct ieee80211_rate rtl_ratetable_5g[] = { + {.bitrate = 60, .hw_value = 0x04,}, + {.bitrate = 90, .hw_value = 0x05,}, + {.bitrate = 120, .hw_value = 0x06,}, + {.bitrate = 180, .hw_value = 0x07,}, + {.bitrate = 240, .hw_value = 0x08,}, + {.bitrate = 360, .hw_value = 0x09,}, + {.bitrate = 480, .hw_value = 0x0a,}, + {.bitrate = 540, .hw_value = 0x0b,}, +}; + static const struct ieee80211_supported_band rtl_band_2ghz = { .band = IEEE80211_BAND_2GHZ, - .channels = rtl_channeltable, - .n_channels = ARRAY_SIZE(rtl_channeltable), + .channels = rtl_channeltable_2g, + .n_channels = ARRAY_SIZE(rtl_channeltable_2g), - .bitrates = rtl_ratetable, - .n_bitrates = ARRAY_SIZE(rtl_ratetable), + .bitrates = rtl_ratetable_2g, + .n_bitrates = ARRAY_SIZE(rtl_ratetable_2g), .ht_cap = {0}, }; +static struct ieee80211_supported_band rtl_band_5ghz = { + .band = IEEE80211_BAND_5GHZ, + + .channels = rtl_channeltable_5g, + .n_channels = ARRAY_SIZE(rtl_channeltable_5g), + + .bitrates = rtl_ratetable_5g, + .n_bitrates = ARRAY_SIZE(rtl_ratetable_5g), + + .ht_cap = {0}, +}; + +static const u8 tid_to_ac[] = { + 2, /* IEEE80211_AC_BE */ + 3, /* IEEE80211_AC_BK */ + 3, /* IEEE80211_AC_BK */ + 2, /* IEEE80211_AC_BE */ + 1, /* IEEE80211_AC_VI */ + 1, /* IEEE80211_AC_VI */ + 0, /* IEEE80211_AC_VO */ + 0, /* IEEE80211_AC_VO */ +}; + +u8 rtl_tid_to_ac(struct ieee80211_hw *hw, u8 tid) +{ + return tid_to_ac[tid]; +} + static void _rtl_init_hw_ht_capab(struct ieee80211_hw *hw, struct ieee80211_sta_ht_cap *ht_cap) { @@ -115,6 +182,9 @@ static void _rtl_init_hw_ht_capab(struct ieee80211_hw *hw, IEEE80211_HT_CAP_SGI_20 | IEEE80211_HT_CAP_DSSSCCK40 | IEEE80211_HT_CAP_MAX_AMSDU; + if (rtlpriv->rtlhal.disable_amsdu_8k) + ht_cap->cap &= ~IEEE80211_HT_CAP_MAX_AMSDU; + /* *Maximum length of AMPDU that the STA can receive. *Length = 2 ^ (13 + max_ampdu_length_exp) - 1 (octets) @@ -159,37 +229,99 @@ static void _rtl_init_hw_ht_capab(struct ieee80211_hw *hw, static void _rtl_init_mac80211(struct ieee80211_hw *hw) { + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_hal *rtlhal = rtl_hal(rtlpriv); struct rtl_mac *rtlmac = rtl_mac(rtl_priv(hw)); struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw)); struct ieee80211_supported_band *sband; - /* <1> use mac->bands as mem for hw->wiphy->bands */ - sband = &(rtlmac->bands[IEEE80211_BAND_2GHZ]); - /* - * <2> set hw->wiphy->bands[IEEE80211_BAND_2GHZ] - * to default value(1T1R) - */ - memcpy(&(rtlmac->bands[IEEE80211_BAND_2GHZ]), &rtl_band_2ghz, - sizeof(struct ieee80211_supported_band)); + if (rtlhal->macphymode == SINGLEMAC_SINGLEPHY && rtlhal->bandset == + BAND_ON_BOTH) { + /* 1: 2.4 G bands */ + /* <1> use mac->bands as mem for hw->wiphy->bands */ + sband = &(rtlmac->bands[IEEE80211_BAND_2GHZ]); + + /* <2> set hw->wiphy->bands[IEEE80211_BAND_2GHZ] + * to default value(1T1R) */ + memcpy(&(rtlmac->bands[IEEE80211_BAND_2GHZ]), &rtl_band_2ghz, + sizeof(struct ieee80211_supported_band)); - /* <3> init ht cap base on ant_num */ - _rtl_init_hw_ht_capab(hw, &sband->ht_cap); + /* <3> init ht cap base on ant_num */ + _rtl_init_hw_ht_capab(hw, &sband->ht_cap); - /* <4> set mac->sband to wiphy->sband */ - hw->wiphy->bands[IEEE80211_BAND_2GHZ] = sband; + /* <4> set mac->sband to wiphy->sband */ + hw->wiphy->bands[IEEE80211_BAND_2GHZ] = sband; + /* 2: 5 G bands */ + /* <1> use mac->bands as mem for hw->wiphy->bands */ + sband = &(rtlmac->bands[IEEE80211_BAND_5GHZ]); + + /* <2> set hw->wiphy->bands[IEEE80211_BAND_5GHZ] + * to default value(1T1R) */ + memcpy(&(rtlmac->bands[IEEE80211_BAND_5GHZ]), &rtl_band_5ghz, + sizeof(struct ieee80211_supported_band)); + + /* <3> init ht cap base on ant_num */ + _rtl_init_hw_ht_capab(hw, &sband->ht_cap); + + /* <4> set mac->sband to wiphy->sband */ + hw->wiphy->bands[IEEE80211_BAND_5GHZ] = sband; + } else { + if (rtlhal->current_bandtype == BAND_ON_2_4G) { + /* <1> use mac->bands as mem for hw->wiphy->bands */ + sband = &(rtlmac->bands[IEEE80211_BAND_2GHZ]); + + /* <2> set hw->wiphy->bands[IEEE80211_BAND_2GHZ] + * to default value(1T1R) */ + memcpy(&(rtlmac->bands[IEEE80211_BAND_2GHZ]), + &rtl_band_2ghz, + sizeof(struct ieee80211_supported_band)); + + /* <3> init ht cap base on ant_num */ + _rtl_init_hw_ht_capab(hw, &sband->ht_cap); + + /* <4> set mac->sband to wiphy->sband */ + hw->wiphy->bands[IEEE80211_BAND_2GHZ] = sband; + } else if (rtlhal->current_bandtype == BAND_ON_5G) { + /* <1> use mac->bands as mem for hw->wiphy->bands */ + sband = &(rtlmac->bands[IEEE80211_BAND_5GHZ]); + + /* <2> set hw->wiphy->bands[IEEE80211_BAND_5GHZ] + * to default value(1T1R) */ + memcpy(&(rtlmac->bands[IEEE80211_BAND_5GHZ]), + &rtl_band_5ghz, + sizeof(struct ieee80211_supported_band)); + + /* <3> init ht cap base on ant_num */ + _rtl_init_hw_ht_capab(hw, &sband->ht_cap); + + /* <4> set mac->sband to wiphy->sband */ + hw->wiphy->bands[IEEE80211_BAND_5GHZ] = sband; + } else { + RT_TRACE(rtlpriv, COMP_INIT, DBG_EMERG, + ("Err BAND %d\n", + rtlhal->current_bandtype)); + } + } /* <5> set hw caps */ hw->flags = IEEE80211_HW_SIGNAL_DBM | IEEE80211_HW_RX_INCLUDES_FCS | - IEEE80211_HW_BEACON_FILTER | IEEE80211_HW_AMPDU_AGGREGATION | /*PS*/ - /*IEEE80211_HW_SUPPORTS_PS | */ - /*IEEE80211_HW_PS_NULLFUNC_STACK | */ - /*IEEE80211_HW_SUPPORTS_DYNAMIC_PS | */ + IEEE80211_HW_BEACON_FILTER | + IEEE80211_HW_AMPDU_AGGREGATION | IEEE80211_HW_REPORTS_TX_ACK_STATUS | 0; + /* swlps or hwlps has been set in diff chip in init_sw_vars */ + if (rtlpriv->psc.swctrl_lps) + hw->flags |= IEEE80211_HW_SUPPORTS_PS | + IEEE80211_HW_PS_NULLFUNC_STACK | + /* IEEE80211_HW_SUPPORTS_DYNAMIC_PS | */ + 0; + hw->wiphy->interface_modes = - BIT(NL80211_IFTYPE_STATION) | BIT(NL80211_IFTYPE_ADHOC); + BIT(NL80211_IFTYPE_AP) | + BIT(NL80211_IFTYPE_STATION) | + BIT(NL80211_IFTYPE_ADHOC); hw->wiphy->rts_threshold = 2347; @@ -199,9 +331,10 @@ static void _rtl_init_mac80211(struct ieee80211_hw *hw) /* TODO: Correct this value for our hw */ /* TODO: define these hard code value */ hw->channel_change_time = 100; - hw->max_listen_interval = 5; + hw->max_listen_interval = 10; hw->max_rate_tries = 4; /* hw->max_rates = 1; */ + hw->sta_data_size = sizeof(struct rtl_sta_info); /* <6> mac address */ if (is_valid_ether_addr(rtlefuse->dev_addr)) { @@ -230,6 +363,10 @@ static void _rtl_init_deferred_work(struct ieee80211_hw *hw) (void *)rtl_watchdog_wq_callback); INIT_DELAYED_WORK(&rtlpriv->works.ips_nic_off_wq, (void *)rtl_ips_nic_off_wq_callback); + INIT_DELAYED_WORK(&rtlpriv->works.ps_work, + (void *)rtl_swlps_wq_callback); + INIT_DELAYED_WORK(&rtlpriv->works.ps_rfon_wq, + (void *)rtl_swlps_rfon_wq_callback); } @@ -241,6 +378,8 @@ void rtl_deinit_deferred_work(struct ieee80211_hw *hw) cancel_delayed_work(&rtlpriv->works.watchdog_wq); cancel_delayed_work(&rtlpriv->works.ips_nic_off_wq); + cancel_delayed_work(&rtlpriv->works.ps_work); + cancel_delayed_work(&rtlpriv->works.ps_rfon_wq); } void rtl_init_rfkill(struct ieee80211_hw *hw) @@ -310,6 +449,8 @@ int rtl_init_core(struct ieee80211_hw *hw) spin_lock_init(&rtlpriv->locks.rf_ps_lock); spin_lock_init(&rtlpriv->locks.rf_lock); spin_lock_init(&rtlpriv->locks.lps_lock); + spin_lock_init(&rtlpriv->locks.waitq_lock); + spin_lock_init(&rtlpriv->locks.cck_and_rw_pagea_lock); rtlmac->link_state = MAC80211_NOLINK; @@ -329,12 +470,6 @@ void rtl_init_rx_config(struct ieee80211_hw *hw) struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); rtlpriv->cfg->ops->get_hw_reg(hw, HW_VAR_RCR, (u8 *) (&mac->rx_conf)); - rtlpriv->cfg->ops->get_hw_reg(hw, HW_VAR_MGT_FILTER, - (u8 *) (&mac->rx_mgt_filter)); - rtlpriv->cfg->ops->get_hw_reg(hw, HW_VAR_CTRL_FILTER, - (u8 *) (&mac->rx_ctrl_filter)); - rtlpriv->cfg->ops->get_hw_reg(hw, HW_VAR_DATA_FILTER, - (u8 *) (&mac->rx_data_filter)); } /********************************************************* @@ -361,28 +496,40 @@ static void _rtl_qurey_shortpreamble_mode(struct ieee80211_hw *hw, } static void _rtl_query_shortgi(struct ieee80211_hw *hw, + struct ieee80211_sta *sta, struct rtl_tcb_desc *tcb_desc, struct ieee80211_tx_info *info) { struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); u8 rate_flag = info->control.rates[0].flags; - + u8 sgi_40 = 0, sgi_20 = 0, bw_40 = 0; tcb_desc->use_shortgi = false; - if (!mac->ht_enable) + if (sta == NULL) + return; + + sgi_40 = sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_40; + sgi_20 = sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_20; + + if (!(sta->ht_cap.ht_supported)) return; - if (!mac->sgi_40 && !mac->sgi_20) + if (!sgi_40 && !sgi_20) return; - if ((mac->bw_40 == true) && mac->sgi_40) + if (mac->opmode == NL80211_IFTYPE_STATION) + bw_40 = mac->bw_40; + else if (mac->opmode == NL80211_IFTYPE_AP || + mac->opmode == NL80211_IFTYPE_ADHOC) + bw_40 = sta->ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40; + + if ((bw_40 == true) && sgi_40) tcb_desc->use_shortgi = true; - else if ((mac->bw_40 == false) && mac->sgi_20) + else if ((bw_40 == false) && sgi_20) tcb_desc->use_shortgi = true; if (!(rate_flag & IEEE80211_TX_RC_SHORT_GI)) tcb_desc->use_shortgi = false; - } static void _rtl_query_protection_mode(struct ieee80211_hw *hw, @@ -410,19 +557,25 @@ static void _rtl_query_protection_mode(struct ieee80211_hw *hw, tcb_desc->rts_enable = true; tcb_desc->rts_rate = rtlpriv->cfg->maps[RTL_RC_OFDM_RATE24M]; } - } static void _rtl_txrate_selectmode(struct ieee80211_hw *hw, + struct ieee80211_sta *sta, struct rtl_tcb_desc *tcb_desc) { struct rtl_priv *rtlpriv = rtl_priv(hw); struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); + struct rtl_sta_info *sta_entry = NULL; + u8 ratr_index = 7; + if (sta) { + sta_entry = (struct rtl_sta_info *) sta->drv_priv; + ratr_index = sta_entry->ratr_index; + } if (!tcb_desc->disable_ratefallback || !tcb_desc->use_driver_rate) { - if (mac->opmode == NL80211_IFTYPE_STATION) + if (mac->opmode == NL80211_IFTYPE_STATION) { tcb_desc->ratr_index = 0; - else if (mac->opmode == NL80211_IFTYPE_ADHOC) { + } else if (mac->opmode == NL80211_IFTYPE_ADHOC) { if (tcb_desc->multicast || tcb_desc->broadcast) { tcb_desc->hw_rate = rtlpriv->cfg->maps[RTL_RC_CCK_RATE2M]; @@ -430,36 +583,61 @@ static void _rtl_txrate_selectmode(struct ieee80211_hw *hw, } else { /* TODO */ } + tcb_desc->ratr_index = ratr_index; + } else if (mac->opmode == NL80211_IFTYPE_AP) { + tcb_desc->ratr_index = ratr_index; } } if (rtlpriv->dm.useramask) { - /* TODO adhoc and station handled differently in the future */ - tcb_desc->mac_id = 0; - - if ((mac->mode == WIRELESS_MODE_N_24G) || - (mac->mode == WIRELESS_MODE_N_5G)) { - tcb_desc->ratr_index = RATR_INX_WIRELESS_NGB; - } else if (mac->mode & WIRELESS_MODE_G) { - tcb_desc->ratr_index = RATR_INX_WIRELESS_GB; - } else if (mac->mode & WIRELESS_MODE_B) { - tcb_desc->ratr_index = RATR_INX_WIRELESS_B; + /* TODO we will differentiate adhoc and station futrue */ + if (mac->opmode == NL80211_IFTYPE_STATION) { + tcb_desc->mac_id = 0; + + if (mac->mode == WIRELESS_MODE_N_24G) + tcb_desc->ratr_index = RATR_INX_WIRELESS_NGB; + else if (mac->mode == WIRELESS_MODE_N_5G) + tcb_desc->ratr_index = RATR_INX_WIRELESS_NG; + else if (mac->mode & WIRELESS_MODE_G) + tcb_desc->ratr_index = RATR_INX_WIRELESS_GB; + else if (mac->mode & WIRELESS_MODE_B) + tcb_desc->ratr_index = RATR_INX_WIRELESS_B; + else if (mac->mode & WIRELESS_MODE_A) + tcb_desc->ratr_index = RATR_INX_WIRELESS_G; + } else if (mac->opmode == NL80211_IFTYPE_AP || + mac->opmode == NL80211_IFTYPE_ADHOC) { + if (NULL != sta) { + if (sta->aid > 0) + tcb_desc->mac_id = sta->aid + 1; + else + tcb_desc->mac_id = 1; + } else { + tcb_desc->mac_id = 0; + } } } } static void _rtl_query_bandwidth_mode(struct ieee80211_hw *hw, + struct ieee80211_sta *sta, struct rtl_tcb_desc *tcb_desc) { struct rtl_priv *rtlpriv = rtl_priv(hw); struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); tcb_desc->packet_bw = false; - - if (!mac->bw_40 || !mac->ht_enable) + if (!sta) return; - + if (mac->opmode == NL80211_IFTYPE_AP || + mac->opmode == NL80211_IFTYPE_ADHOC) { + if (!(sta->ht_cap.ht_supported) || + !(sta->ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40)) + return; + } else if (mac->opmode == NL80211_IFTYPE_STATION) { + if (!mac->bw_40 || !(sta->ht_cap.ht_supported)) + return; + } if (tcb_desc->multicast || tcb_desc->broadcast) return; @@ -486,22 +664,21 @@ static u8 _rtl_get_highest_n_rate(struct ieee80211_hw *hw) void rtl_get_tcb_desc(struct ieee80211_hw *hw, struct ieee80211_tx_info *info, + struct ieee80211_sta *sta, struct sk_buff *skb, struct rtl_tcb_desc *tcb_desc) { struct rtl_priv *rtlpriv = rtl_priv(hw); struct rtl_mac *rtlmac = rtl_mac(rtl_priv(hw)); - struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)(skb->data); + struct ieee80211_hdr *hdr = rtl_get_hdr(skb); struct ieee80211_rate *txrate; __le16 fc = hdr->frame_control; - memset(tcb_desc, 0, sizeof(struct rtl_tcb_desc)); + txrate = ieee80211_get_tx_rate(hw, info); + tcb_desc->hw_rate = txrate->hw_value; if (ieee80211_is_data(fc)) { - txrate = ieee80211_get_tx_rate(hw, info); - tcb_desc->hw_rate = txrate->hw_value; - /* - *we set data rate RTL_RC_CCK_RATE1M + *we set data rate INX 0 *in rtl_rc.c if skb is special data or *mgt which need low data rate. */ @@ -510,12 +687,11 @@ void rtl_get_tcb_desc(struct ieee80211_hw *hw, *So tcb_desc->hw_rate is just used for *special data and mgt frames */ - if (tcb_desc->hw_rate < rtlpriv->cfg->maps[RTL_RC_CCK_RATE11M]) { + if (info->control.rates[0].idx == 0 && + ieee80211_is_nullfunc(fc)) { tcb_desc->use_driver_rate = true; - tcb_desc->ratr_index = 7; + tcb_desc->ratr_index = RATR_INX_WIRELESS_MC; - tcb_desc->hw_rate = - rtlpriv->cfg->maps[RTL_RC_CCK_RATE1M]; tcb_desc->disable_ratefallback = 1; } else { /* @@ -525,7 +701,7 @@ void rtl_get_tcb_desc(struct ieee80211_hw *hw, *and N rate will all be controled by FW *when tcb_desc->use_driver_rate = false */ - if (rtlmac->ht_enable) { + if (sta && (sta->ht_cap.ht_supported)) { tcb_desc->hw_rate = _rtl_get_highest_n_rate(hw); } else { if (rtlmac->mode == WIRELESS_MODE_B) { @@ -543,43 +719,25 @@ void rtl_get_tcb_desc(struct ieee80211_hw *hw, else if (is_broadcast_ether_addr(ieee80211_get_DA(hdr))) tcb_desc->broadcast = 1; - _rtl_txrate_selectmode(hw, tcb_desc); - _rtl_query_bandwidth_mode(hw, tcb_desc); + _rtl_txrate_selectmode(hw, sta, tcb_desc); + _rtl_query_bandwidth_mode(hw, sta, tcb_desc); _rtl_qurey_shortpreamble_mode(hw, tcb_desc, info); - _rtl_query_shortgi(hw, tcb_desc, info); + _rtl_query_shortgi(hw, sta, tcb_desc, info); _rtl_query_protection_mode(hw, tcb_desc, info); } else { tcb_desc->use_driver_rate = true; - tcb_desc->ratr_index = 7; + tcb_desc->ratr_index = RATR_INX_WIRELESS_MC; tcb_desc->disable_ratefallback = 1; tcb_desc->mac_id = 0; - - tcb_desc->hw_rate = rtlpriv->cfg->maps[RTL_RC_CCK_RATE1M]; + tcb_desc->packet_bw = false; } } EXPORT_SYMBOL(rtl_get_tcb_desc); -bool rtl_tx_mgmt_proc(struct ieee80211_hw *hw, struct sk_buff *skb) -{ - struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); - struct rtl_priv *rtlpriv = rtl_priv(hw); - struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)(skb->data); - __le16 fc = hdr->frame_control; - - if (ieee80211_is_auth(fc)) { - RT_TRACE(rtlpriv, COMP_SEND, DBG_DMESG, ("MAC80211_LINKING\n")); - rtl_ips_nic_on(hw); - - mac->link_state = MAC80211_LINKING; - } - - return true; -} - bool rtl_action_proc(struct ieee80211_hw *hw, struct sk_buff *skb, u8 is_tx) { struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); - struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)(skb->data); + struct ieee80211_hdr *hdr = rtl_get_hdr(skb); struct rtl_priv *rtlpriv = rtl_priv(hw); __le16 fc = hdr->frame_control; u8 *act = (u8 *) (((u8 *) skb->data + MAC80211_3ADDR_LEN)); @@ -624,9 +782,8 @@ bool rtl_action_proc(struct ieee80211_hw *hw, struct sk_buff *skb, u8 is_tx) u8 rtl_is_special_data(struct ieee80211_hw *hw, struct sk_buff *skb, u8 is_tx) { struct rtl_priv *rtlpriv = rtl_priv(hw); - struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)(skb->data); struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); - __le16 fc = hdr->frame_control; + __le16 fc = rtl_get_fc(skb); u16 ether_type; u8 mac_hdr_len = ieee80211_get_hdrlen_from_skb(skb); const struct iphdr *ip; @@ -634,12 +791,11 @@ u8 rtl_is_special_data(struct ieee80211_hw *hw, struct sk_buff *skb, u8 is_tx) if (!ieee80211_is_data(fc)) return false; - if (ieee80211_is_nullfunc(fc)) - return true; ip = (struct iphdr *)((u8 *) skb->data + mac_hdr_len + SNAP_SIZE + PROTOC_TYPE_SIZE); ether_type = *(u16 *) ((u8 *) skb->data + mac_hdr_len + SNAP_SIZE); + ether_type = ntohs(ether_type); if (ETH_P_IP == ether_type) { if (IPPROTO_UDP == ip->protocol) { @@ -696,61 +852,92 @@ u8 rtl_is_special_data(struct ieee80211_hw *hw, struct sk_buff *skb, u8 is_tx) * functions called by core.c * *********************************************************/ -int rtl_tx_agg_start(struct ieee80211_hw *hw, const u8 *ra, u16 tid, u16 *ssn) +int rtl_tx_agg_start(struct ieee80211_hw *hw, + struct ieee80211_sta *sta, u16 tid, u16 *ssn) { struct rtl_priv *rtlpriv = rtl_priv(hw); struct rtl_tid_data *tid_data; struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); + struct rtl_sta_info *sta_entry = NULL; - RT_TRACE(rtlpriv, COMP_SEND, DBG_DMESG, - ("on ra = %pM tid = %d\n", ra, tid)); + if (sta == NULL) + return -EINVAL; if (unlikely(tid >= MAX_TID_COUNT)) return -EINVAL; - if (mac->tids[tid].agg.agg_state != RTL_AGG_OFF) { - RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING, - ("Start AGG when state is not RTL_AGG_OFF !\n")); + sta_entry = (struct rtl_sta_info *)sta->drv_priv; + if (!sta_entry) return -ENXIO; - } - - tid_data = &mac->tids[tid]; - *ssn = SEQ_TO_SN(tid_data->seq_number); + tid_data = &sta_entry->tids[tid]; RT_TRACE(rtlpriv, COMP_SEND, DBG_DMESG, - ("HW queue is empty tid:%d\n", tid)); - tid_data->agg.agg_state = RTL_AGG_ON; + ("on ra = %pM tid = %d seq:%d\n", sta->addr, tid, + tid_data->seq_number)); - ieee80211_start_tx_ba_cb_irqsafe(mac->vif, ra, tid); + *ssn = tid_data->seq_number; + tid_data->agg.agg_state = RTL_AGG_START; + + ieee80211_start_tx_ba_cb_irqsafe(mac->vif, sta->addr, tid); return 0; } -int rtl_tx_agg_stop(struct ieee80211_hw *hw, const u8 * ra, u16 tid) +int rtl_tx_agg_stop(struct ieee80211_hw *hw, + struct ieee80211_sta *sta, u16 tid) { - int ssn = -1; struct rtl_priv *rtlpriv = rtl_priv(hw); struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); struct rtl_tid_data *tid_data; + struct rtl_sta_info *sta_entry = NULL; + + if (sta == NULL) + return -EINVAL; - if (!ra) { + if (!sta->addr) { RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, ("ra = NULL\n")); return -EINVAL; } + RT_TRACE(rtlpriv, COMP_SEND, DBG_DMESG, + ("on ra = %pM tid = %d\n", sta->addr, tid)); + if (unlikely(tid >= MAX_TID_COUNT)) return -EINVAL; - if (mac->tids[tid].agg.agg_state != RTL_AGG_ON) - RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING, - ("Stopping AGG while state not ON or starting\n")); + sta_entry = (struct rtl_sta_info *)sta->drv_priv; + tid_data = &sta_entry->tids[tid]; + sta_entry->tids[tid].agg.agg_state = RTL_AGG_STOP; - tid_data = &mac->tids[tid]; - ssn = (tid_data->seq_number & IEEE80211_SCTL_SEQ) >> 4; + ieee80211_stop_tx_ba_cb_irqsafe(mac->vif, sta->addr, tid); - mac->tids[tid].agg.agg_state = RTL_AGG_OFF; + return 0; +} + +int rtl_tx_agg_oper(struct ieee80211_hw *hw, + struct ieee80211_sta *sta, u16 tid) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_tid_data *tid_data; + struct rtl_sta_info *sta_entry = NULL; - ieee80211_stop_tx_ba_cb_irqsafe(mac->vif, ra, tid); + if (sta == NULL) + return -EINVAL; + + if (!sta->addr) { + RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, ("ra = NULL\n")); + return -EINVAL; + } + + RT_TRACE(rtlpriv, COMP_SEND, DBG_DMESG, + ("on ra = %pM tid = %d\n", sta->addr, tid)); + + if (unlikely(tid >= MAX_TID_COUNT)) + return -EINVAL; + + sta_entry = (struct rtl_sta_info *)sta->drv_priv; + tid_data = &sta_entry->tids[tid]; + sta_entry->tids[tid].agg.agg_state = RTL_AGG_OPERATIONAL; return 0; } @@ -769,18 +956,16 @@ void rtl_watchdog_wq_callback(void *data) struct rtl_priv *rtlpriv = rtl_priv(hw); struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); - bool busytraffic = false; bool higher_busytraffic = false; bool higher_busyrxtraffic = false; - bool higher_busytxtraffic = false; - - u8 idx = 0; + u8 idx, tid; u32 rx_cnt_inp4eriod = 0; u32 tx_cnt_inp4eriod = 0; u32 aver_rx_cnt_inperiod = 0; u32 aver_tx_cnt_inperiod = 0; - + u32 aver_tidtx_inperiod[MAX_TID_COUNT] = {0}; + u32 tidtx_inp4eriod[MAX_TID_COUNT] = {0}; bool enter_ps = false; if (is_hal_stop(rtlhal)) @@ -794,9 +979,6 @@ void rtl_watchdog_wq_callback(void *data) mac->cnt_after_linked = 0; } - /* <2> DM */ - rtlpriv->cfg->ops->dm_watchdog(hw); - /* *<3> to check if traffic busy, if * busytraffic we don't change channel @@ -835,8 +1017,27 @@ void rtl_watchdog_wq_callback(void *data) /* Extremely high Rx data. */ if (aver_rx_cnt_inperiod > 5000) higher_busyrxtraffic = true; + } + + /* check every tid's tx traffic */ + for (tid = 0; tid <= 7; tid++) { + for (idx = 0; idx <= 2; idx++) + rtlpriv->link_info.tidtx_in4period[tid][idx] = + rtlpriv->link_info.tidtx_in4period[tid] + [idx + 1]; + rtlpriv->link_info.tidtx_in4period[tid][3] = + rtlpriv->link_info.tidtx_inperiod[tid]; + + for (idx = 0; idx <= 3; idx++) + tidtx_inp4eriod[tid] += + rtlpriv->link_info.tidtx_in4period[tid][idx]; + aver_tidtx_inperiod[tid] = tidtx_inp4eriod[tid] / 4; + if (aver_tidtx_inperiod[tid] > 5000) + rtlpriv->link_info.higher_busytxtraffic[tid] = + true; else - higher_busytxtraffic = false; + rtlpriv->link_info.higher_busytxtraffic[tid] = + false; } if (((rtlpriv->link_info.num_rx_inperiod + @@ -855,11 +1056,15 @@ void rtl_watchdog_wq_callback(void *data) rtlpriv->link_info.num_rx_inperiod = 0; rtlpriv->link_info.num_tx_inperiod = 0; + for (tid = 0; tid <= 7; tid++) + rtlpriv->link_info.tidtx_inperiod[tid] = 0; rtlpriv->link_info.busytraffic = busytraffic; rtlpriv->link_info.higher_busytraffic = higher_busytraffic; rtlpriv->link_info.higher_busyrxtraffic = higher_busyrxtraffic; + /* <3> DM */ + rtlpriv->cfg->ops->dm_watchdog(hw); } void rtl_watch_dog_timer_callback(unsigned long data) @@ -876,6 +1081,274 @@ void rtl_watch_dog_timer_callback(unsigned long data) /********************************************************* * + * frame process functions + * + *********************************************************/ +u8 *rtl_find_ie(u8 *data, unsigned int len, u8 ie) +{ + struct ieee80211_mgmt *mgmt = (void *)data; + u8 *pos, *end; + + pos = (u8 *)mgmt->u.beacon.variable; + end = data + len; + while (pos < end) { + if (pos + 2 + pos[1] > end) + return NULL; + + if (pos[0] == ie) + return pos; + + pos += 2 + pos[1]; + } + return NULL; +} + +/* when we use 2 rx ants we send IEEE80211_SMPS_OFF */ +/* when we use 1 rx ant we send IEEE80211_SMPS_STATIC */ +struct sk_buff *rtl_make_smps_action(struct ieee80211_hw *hw, + enum ieee80211_smps_mode smps, u8 *da, u8 *bssid) +{ + struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw)); + struct sk_buff *skb; + struct ieee80211_mgmt *action_frame; + + /* 27 = header + category + action + smps mode */ + skb = dev_alloc_skb(27 + hw->extra_tx_headroom); + if (!skb) + return NULL; + + skb_reserve(skb, hw->extra_tx_headroom); + action_frame = (void *)skb_put(skb, 27); + memset(action_frame, 0, 27); + memcpy(action_frame->da, da, ETH_ALEN); + memcpy(action_frame->sa, rtlefuse->dev_addr, ETH_ALEN); + memcpy(action_frame->bssid, bssid, ETH_ALEN); + action_frame->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | + IEEE80211_STYPE_ACTION); + action_frame->u.action.category = WLAN_CATEGORY_HT; + action_frame->u.action.u.ht_smps.action = WLAN_HT_ACTION_SMPS; + switch (smps) { + case IEEE80211_SMPS_AUTOMATIC:/* 0 */ + case IEEE80211_SMPS_NUM_MODES:/* 4 */ + WARN_ON(1); + case IEEE80211_SMPS_OFF:/* 1 */ /*MIMO_PS_NOLIMIT*/ + action_frame->u.action.u.ht_smps.smps_control = + WLAN_HT_SMPS_CONTROL_DISABLED;/* 0 */ + break; + case IEEE80211_SMPS_STATIC:/* 2 */ /*MIMO_PS_STATIC*/ + action_frame->u.action.u.ht_smps.smps_control = + WLAN_HT_SMPS_CONTROL_STATIC;/* 1 */ + break; + case IEEE80211_SMPS_DYNAMIC:/* 3 */ /*MIMO_PS_DYNAMIC*/ + action_frame->u.action.u.ht_smps.smps_control = + WLAN_HT_SMPS_CONTROL_DYNAMIC;/* 3 */ + break; + } + + return skb; +} + +int rtl_send_smps_action(struct ieee80211_hw *hw, + struct ieee80211_sta *sta, u8 *da, u8 *bssid, + enum ieee80211_smps_mode smps) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); + struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); + struct sk_buff *skb = rtl_make_smps_action(hw, smps, da, bssid); + struct rtl_tcb_desc tcb_desc; + memset(&tcb_desc, 0, sizeof(struct rtl_tcb_desc)); + + if (rtlpriv->mac80211.act_scanning) + goto err_free; + + if (!sta) + goto err_free; + + if (unlikely(is_hal_stop(rtlhal) || ppsc->rfpwr_state != ERFON)) + goto err_free; + + if (!test_bit(RTL_STATUS_INTERFACE_START, &rtlpriv->status)) + goto err_free; + + /* this is a type = mgmt * stype = action frame */ + if (skb) { + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); + struct rtl_sta_info *sta_entry = + (struct rtl_sta_info *) sta->drv_priv; + sta_entry->mimo_ps = smps; + rtlpriv->cfg->ops->update_rate_tbl(hw, sta, 0); + + info->control.rates[0].idx = 0; + info->control.sta = sta; + info->band = hw->conf.channel->band; +#if 0 + rtlpriv->intf_ops->adapter_tx(hw, skb, &tcb_desc); +#else + rtlpriv->intf_ops->adapter_tx(hw, skb); +#endif + } + return 1; + +err_free: + return 0; +} + +/********************************************************* + * + * IOT functions + * + *********************************************************/ +static bool rtl_chk_vendor_ouisub(struct ieee80211_hw *hw, + struct octet_string vendor_ie) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + bool matched = false; + static u8 athcap_1[] = { 0x00, 0x03, 0x7F }; + static u8 athcap_2[] = { 0x00, 0x13, 0x74 }; + static u8 broadcap_1[] = { 0x00, 0x10, 0x18 }; + static u8 broadcap_2[] = { 0x00, 0x0a, 0xf7 }; + static u8 broadcap_3[] = { 0x00, 0x05, 0xb5 }; + static u8 racap[] = { 0x00, 0x0c, 0x43 }; + static u8 ciscocap[] = { 0x00, 0x40, 0x96 }; + static u8 marvcap[] = { 0x00, 0x50, 0x43 }; + + if (memcmp(vendor_ie.octet, athcap_1, 3) == 0 || + memcmp(vendor_ie.octet, athcap_2, 3) == 0) { + rtlpriv->mac80211.vendor = PEER_ATH; + matched = true; + } else if (memcmp(vendor_ie.octet, broadcap_1, 3) == 0 || + memcmp(vendor_ie.octet, broadcap_2, 3) == 0 || + memcmp(vendor_ie.octet, broadcap_3, 3) == 0) { + rtlpriv->mac80211.vendor = PEER_BROAD; + matched = true; + } else if (memcmp(vendor_ie.octet, racap, 3) == 0) { + rtlpriv->mac80211.vendor = PEER_RAL; + matched = true; + } else if (memcmp(vendor_ie.octet, ciscocap, 3) == 0) { + rtlpriv->mac80211.vendor = PEER_CISCO; + matched = true; + } else if (memcmp(vendor_ie.octet, marvcap, 3) == 0) { + rtlpriv->mac80211.vendor = PEER_MARV; + matched = true; + } + + return matched; +} + +bool rtl_find_221_ie(struct ieee80211_hw *hw, u8 *data, + unsigned int len) +{ + struct ieee80211_mgmt *mgmt = (void *)data; + struct octet_string vendor_ie; + u8 *pos, *end; + + pos = (u8 *)mgmt->u.beacon.variable; + end = data + len; + while (pos < end) { + if (pos[0] == 221) { + vendor_ie.length = pos[1]; + vendor_ie.octet = &pos[2]; + if (rtl_chk_vendor_ouisub(hw, vendor_ie)) + return true; + } + + if (pos + 2 + pos[1] > end) + return false; + + pos += 2 + pos[1]; + } + return false; +} + +void rtl_recognize_peer(struct ieee80211_hw *hw, u8 *data, unsigned int len) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); + struct ieee80211_hdr *hdr = (void *)data; + u32 vendor = PEER_UNKNOWN; + + static u8 ap3_1[3] = { 0x00, 0x14, 0xbf }; + static u8 ap3_2[3] = { 0x00, 0x1a, 0x70 }; + static u8 ap3_3[3] = { 0x00, 0x1d, 0x7e }; + static u8 ap4_1[3] = { 0x00, 0x90, 0xcc }; + static u8 ap4_2[3] = { 0x00, 0x0e, 0x2e }; + static u8 ap4_3[3] = { 0x00, 0x18, 0x02 }; + static u8 ap4_4[3] = { 0x00, 0x17, 0x3f }; + static u8 ap4_5[3] = { 0x00, 0x1c, 0xdf }; + static u8 ap5_1[3] = { 0x00, 0x1c, 0xf0 }; + static u8 ap5_2[3] = { 0x00, 0x21, 0x91 }; + static u8 ap5_3[3] = { 0x00, 0x24, 0x01 }; + static u8 ap5_4[3] = { 0x00, 0x15, 0xe9 }; + static u8 ap5_5[3] = { 0x00, 0x17, 0x9A }; + static u8 ap5_6[3] = { 0x00, 0x18, 0xE7 }; + static u8 ap6_1[3] = { 0x00, 0x17, 0x94 }; + static u8 ap7_1[3] = { 0x00, 0x14, 0xa4 }; + + if (mac->opmode != NL80211_IFTYPE_STATION) + return; + + if (mac->link_state == MAC80211_NOLINK) { + mac->vendor = PEER_UNKNOWN; + return; + } + + if (mac->cnt_after_linked > 2) + return; + + /* check if this really is a beacon */ + if (!ieee80211_is_beacon(hdr->frame_control)) + return; + + /* min. beacon length + FCS_LEN */ + if (len <= 40 + FCS_LEN) + return; + + /* and only beacons from the associated BSSID, please */ + if (compare_ether_addr(hdr->addr3, rtlpriv->mac80211.bssid)) + return; + + if (rtl_find_221_ie(hw, data, len)) + vendor = mac->vendor; + + if ((memcmp(mac->bssid, ap5_1, 3) == 0) || + (memcmp(mac->bssid, ap5_2, 3) == 0) || + (memcmp(mac->bssid, ap5_3, 3) == 0) || + (memcmp(mac->bssid, ap5_4, 3) == 0) || + (memcmp(mac->bssid, ap5_5, 3) == 0) || + (memcmp(mac->bssid, ap5_6, 3) == 0) || + vendor == PEER_ATH) { + vendor = PEER_ATH; + RT_TRACE(rtlpriv, COMP_MAC80211, DBG_LOUD, ("=>ath find\n")); + } else if ((memcmp(mac->bssid, ap4_4, 3) == 0) || + (memcmp(mac->bssid, ap4_5, 3) == 0) || + (memcmp(mac->bssid, ap4_1, 3) == 0) || + (memcmp(mac->bssid, ap4_2, 3) == 0) || + (memcmp(mac->bssid, ap4_3, 3) == 0) || + vendor == PEER_RAL) { + RT_TRACE(rtlpriv, COMP_MAC80211, DBG_LOUD, ("=>ral findn\n")); + vendor = PEER_RAL; + } else if (memcmp(mac->bssid, ap6_1, 3) == 0 || + vendor == PEER_CISCO) { + vendor = PEER_CISCO; + RT_TRACE(rtlpriv, COMP_MAC80211, DBG_LOUD, ("=>cisco find\n")); + } else if ((memcmp(mac->bssid, ap3_1, 3) == 0) || + (memcmp(mac->bssid, ap3_2, 3) == 0) || + (memcmp(mac->bssid, ap3_3, 3) == 0) || + vendor == PEER_BROAD) { + RT_TRACE(rtlpriv, COMP_MAC80211, DBG_LOUD, ("=>broad find\n")); + vendor = PEER_BROAD; + } else if (memcmp(mac->bssid, ap7_1, 3) == 0 || + vendor == PEER_MARV) { + vendor = PEER_MARV; + RT_TRACE(rtlpriv, COMP_MAC80211, DBG_LOUD, ("=>marv find\n")); + } + + mac->vendor = vendor; +} + +/********************************************************* + * * sysfs functions * *********************************************************/ @@ -941,12 +1414,13 @@ static int __init rtl_core_module_init(void) if (rtl_rate_control_register()) printk(KERN_ERR "rtlwifi: Unable to register rtl_rc," "use default RC !!\n"); + return 0; } static void __exit rtl_core_module_exit(void) { - /*RC*/ + /*RC*/ rtl_rate_control_unregister(); } diff --git a/drivers/net/wireless/rtlwifi/base.h b/drivers/net/wireless/rtlwifi/base.h index 0430453..a91f3ee 100644 --- a/drivers/net/wireless/rtlwifi/base.h +++ b/drivers/net/wireless/rtlwifi/base.h @@ -24,13 +24,26 @@ * Hsinchu 300, Taiwan. * * Larry Finger + * *****************************************************************************/ #ifndef __RTL_BASE_H__ #define __RTL_BASE_H__ +enum ap_peer { + PEER_UNKNOWN = 0, + PEER_RTL = 1, + PEER_RTL_92SE = 2, + PEER_BROAD = 3, + PEER_RAL = 4, + PEER_ATH = 5, + PEER_CISCO = 6, + PEER_MARV = 7, + PEER_AIRGO = 9, + PEER_MAX = 10, +} ; + #define RTL_DUMMY_OFFSET 0 -#define RTL_RX_DESC_SIZE 24 #define RTL_DUMMY_UNIT 8 #define RTL_TX_DUMMY_SIZE (RTL_DUMMY_OFFSET * RTL_DUMMY_UNIT) #define RTL_TX_DESC_SIZE 32 @@ -53,6 +66,14 @@ #define FRAME_OFFSET_SEQUENCE 22 #define FRAME_OFFSET_ADDRESS4 24 +#define SET_80211_HDR_FRAME_CONTROL(_hdr, _val) \ + WRITEEF2BYTE(_hdr, _val) +#define SET_80211_HDR_TYPE_AND_SUBTYPE(_hdr, _val) \ + WRITEEF1BYTE(_hdr, _val) +#define SET_80211_HDR_PWR_MGNT(_hdr, _val) \ + SET_BITS_TO_LE_2BYTE(_hdr, 12, 1, _val) +#define SET_80211_HDR_TO_DS(_hdr, _val) \ + SET_BITS_TO_LE_2BYTE(_hdr, 8, 1, _val) #define SET_80211_PS_POLL_AID(_hdr, _val) \ (*(u16 *)((u8 *)(_hdr) + 2) = le16_to_cpu(_val)) @@ -64,11 +85,27 @@ #define SET_80211_HDR_DURATION(_hdr, _val) \ (*(u16 *)((u8 *)(_hdr) + FRAME_OFFSET_DURATION) = le16_to_cpu(_val)) #define SET_80211_HDR_ADDRESS1(_hdr, _val) \ - memcpy((u8 *)(_hdr)+FRAME_OFFSET_ADDRESS1, (u8*)(_val), ETH_ALEN) + CP_MACADDR((u8 *)(_hdr)+FRAME_OFFSET_ADDRESS1, (u8 *)(_val)) #define SET_80211_HDR_ADDRESS2(_hdr, _val) \ - memcpy((u8 *)(_hdr) + FRAME_OFFSET_ADDRESS2, (u8 *)(_val), ETH_ALEN) + CP_MACADDR((u8 *)(_hdr)+FRAME_OFFSET_ADDRESS2, (u8 *)(_val)) #define SET_80211_HDR_ADDRESS3(_hdr, _val) \ - memcpy((u8 *)(_hdr)+FRAME_OFFSET_ADDRESS3, (u8 *)(_val), ETH_ALEN) + CP_MACADDR((u8 *)(_hdr)+FRAME_OFFSET_ADDRESS3, (u8 *)(_val)) +#define SET_80211_HDR_FRAGMENT_SEQUENCE(_hdr, _val) \ + WRITEEF2BYTE((u8 *)(_hdr)+FRAME_OFFSET_SEQUENCE, _val) + +#define SET_BEACON_PROBE_RSP_TIME_STAMP_LOW(__phdr, __val) \ + WRITEEF4BYTE(((u8 *)(__phdr)) + 24, __val) +#define SET_BEACON_PROBE_RSP_TIME_STAMP_HIGH(__phdr, __val) \ + WRITEEF4BYTE(((u8 *)(__phdr)) + 28, __val) +#define SET_BEACON_PROBE_RSP_BEACON_INTERVAL(__phdr, __val) \ + WRITEEF2BYTE(((u8 *)(__phdr)) + 32, __val) +#define GET_BEACON_PROBE_RSP_CAPABILITY_INFO(__phdr) \ + READEF2BYTE(((u8 *)(__phdr)) + 34) +#define SET_BEACON_PROBE_RSP_CAPABILITY_INFO(__phdr, __val) \ + WRITEEF2BYTE(((u8 *)(__phdr)) + 34, __val) +#define MASK_BEACON_PROBE_RSP_CAPABILITY_INFO(__phdr, __val) \ + SET_BEACON_PROBE_RSP_CAPABILITY_INFO(__phdr, \ + (GET_BEACON_PROBE_RSP_CAPABILITY_INFO(__phdr) & (~(__val)))) int rtl_init_core(struct ieee80211_hw *hw); void rtl_deinit_core(struct ieee80211_hw *hw); @@ -80,18 +117,27 @@ void rtl_watch_dog_timer_callback(unsigned long data); void rtl_deinit_deferred_work(struct ieee80211_hw *hw); bool rtl_action_proc(struct ieee80211_hw *hw, struct sk_buff *skb, u8 is_tx); -bool rtl_tx_mgmt_proc(struct ieee80211_hw *hw, struct sk_buff *skb); u8 rtl_is_special_data(struct ieee80211_hw *hw, struct sk_buff *skb, u8 is_tx); void rtl_watch_dog_timer_callback(unsigned long data); -int rtl_tx_agg_start(struct ieee80211_hw *hw, const u8 *ra, +int rtl_tx_agg_start(struct ieee80211_hw *hw, struct ieee80211_sta *sta, u16 tid, u16 *ssn); -int rtl_tx_agg_stop(struct ieee80211_hw *hw, const u8 *ra, u16 tid); +int rtl_tx_agg_stop(struct ieee80211_hw *hw, struct ieee80211_sta *sta, + u16 tid); +int rtl_tx_agg_oper(struct ieee80211_hw *hw, struct ieee80211_sta *sta, + u16 tid); void rtl_watchdog_wq_callback(void *data); void rtl_get_tcb_desc(struct ieee80211_hw *hw, struct ieee80211_tx_info *info, + struct ieee80211_sta *sta, struct sk_buff *skb, struct rtl_tcb_desc *tcb_desc); +int rtl_send_smps_action(struct ieee80211_hw *hw, + struct ieee80211_sta *sta, u8 *da, u8 *bssid, + enum ieee80211_smps_mode smps); +u8 *rtl_find_ie(u8 *data, unsigned int len, u8 ie); +void rtl_recognize_peer(struct ieee80211_hw *hw, u8 *data, unsigned int len); +u8 rtl_tid_to_ac(struct ieee80211_hw *hw, u8 tid); extern struct attribute_group rtl_attribute_group; #endif diff --git a/drivers/net/wireless/rtlwifi/pci.c b/drivers/net/wireless/rtlwifi/pci.c index 59a150c..e2fa78b 100644 --- a/drivers/net/wireless/rtlwifi/pci.c +++ b/drivers/net/wireless/rtlwifi/pci.c @@ -1242,8 +1242,6 @@ static int rtl_pci_tx(struct ieee80211_hw *hw, struct sk_buff *skb) u8 own; u8 temp_one = 1; - if (ieee80211_is_mgmt(fc)) - rtl_tx_mgmt_proc(hw, skb); rtl_action_proc(hw, skb, true); queue_index = skb_get_queue_mapping(skb); diff --git a/drivers/net/wireless/rtlwifi/ps.c b/drivers/net/wireless/rtlwifi/ps.c index c8395fb..bdb3c5f 100644 --- a/drivers/net/wireless/rtlwifi/ps.c +++ b/drivers/net/wireless/rtlwifi/ps.c @@ -416,6 +416,14 @@ static void rtl_lps_set_psmode(struct ieee80211_hw *hw, u8 rt_psmode) } } +void rtl_swlps_rfon_wq_callback(void *data) +{ +} + +void rtl_swlps_wq_callback(void *data) +{ +} + /*Enter the leisure power save mode.*/ void rtl_lps_enter(struct ieee80211_hw *hw) { diff --git a/drivers/net/wireless/rtlwifi/ps.h b/drivers/net/wireless/rtlwifi/ps.h index ae56da8..36aa24d 100644 --- a/drivers/net/wireless/rtlwifi/ps.h +++ b/drivers/net/wireless/rtlwifi/ps.h @@ -40,4 +40,11 @@ void rtl_ips_nic_on(struct ieee80211_hw *hw); void rtl_ips_nic_off_wq_callback(void *data); void rtl_lps_enter(struct ieee80211_hw *hw); void rtl_lps_leave(struct ieee80211_hw *hw); + +void rtl_swlps_beacon(struct ieee80211_hw *hw, void *data, unsigned int len); +void rtl_swlps_wq_callback(void *data); +void rtl_swlps_rfon_wq_callback(void *data); +void rtl_swlps_rf_awake(struct ieee80211_hw *hw); +void rtl_swlps_rf_sleep(struct ieee80211_hw *hw); + #endif diff --git a/drivers/net/wireless/rtlwifi/rtl8192ce/trx.c b/drivers/net/wireless/rtlwifi/rtl8192ce/trx.c index aa2b581..356b851 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192ce/trx.c +++ b/drivers/net/wireless/rtlwifi/rtl8192ce/trx.c @@ -754,7 +754,7 @@ void rtl92ce_tx_fill_desc(struct ieee80211_hw *hw, seq_number = (le16_to_cpu(hdr->seq_ctrl) & IEEE80211_SCTL_SEQ) >> 4; - rtl_get_tcb_desc(hw, info, skb, &tcb_desc); + rtl_get_tcb_desc(hw, info, sta, skb, &tcb_desc); CLEAR_PCI_TX_DESC_CONTENT(pdesc, sizeof(struct tx_desc_92c)); diff --git a/drivers/net/wireless/rtlwifi/rtl8192cu/trx.c b/drivers/net/wireless/rtlwifi/rtl8192cu/trx.c index 3f0cb81..0df2fec 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192cu/trx.c +++ b/drivers/net/wireless/rtlwifi/rtl8192cu/trx.c @@ -517,7 +517,7 @@ void rtl92cu_tx_fill_desc(struct ieee80211_hw *hw, u8 *txdesc; seq_number = (le16_to_cpu(hdr->seq_ctrl) & IEEE80211_SCTL_SEQ) >> 4; - rtl_get_tcb_desc(hw, info, skb, &tcb_desc); + rtl_get_tcb_desc(hw, info, sta, skb, &tcb_desc); txdesc = (u8 *)skb_push(skb, RTL_TX_HEADER_SIZE); memset(txdesc, 0, RTL_TX_HEADER_SIZE); SET_TX_DESC_PKT_SIZE(txdesc, pktlen); diff --git a/drivers/net/wireless/rtlwifi/usb.c b/drivers/net/wireless/rtlwifi/usb.c index f5d8573..f4ab1b7 100644 --- a/drivers/net/wireless/rtlwifi/usb.c +++ b/drivers/net/wireless/rtlwifi/usb.c @@ -860,8 +860,6 @@ static void _rtl_usb_tx_preprocess(struct ieee80211_hw *hw, struct sk_buff *skb, u8 tid = 0; u16 seq_number = 0; - if (ieee80211_is_mgmt(fc)) - rtl_tx_mgmt_proc(hw, skb); rtl_action_proc(hw, skb, true); if (is_multicast_ether_addr(pda_addr)) rtlpriv->stats.txbytesmulticast += skb->len; diff --git a/drivers/net/wireless/rtlwifi/usb.h b/drivers/net/wireless/rtlwifi/usb.h index abadfe9..d2a63fb 100644 --- a/drivers/net/wireless/rtlwifi/usb.h +++ b/drivers/net/wireless/rtlwifi/usb.h @@ -31,6 +31,8 @@ #include #include +#define RTL_RX_DESC_SIZE 24 + #define RTL_USB_DEVICE(vend, prod, cfg) \ .match_flags = USB_DEVICE_ID_MATCH_DEVICE, \ .idVendor = (vend), \ diff --git a/drivers/net/wireless/rtlwifi/wifi.h b/drivers/net/wireless/rtlwifi/wifi.h index 9124b30..7c52435 100644 --- a/drivers/net/wireless/rtlwifi/wifi.h +++ b/drivers/net/wireless/rtlwifi/wifi.h @@ -1370,10 +1370,11 @@ struct rtl_hal_ops { u32 add_msr, u32 rm_msr); void (*get_hw_reg) (struct ieee80211_hw *hw, u8 variable, u8 *val); void (*set_hw_reg) (struct ieee80211_hw *hw, u8 variable, u8 *val); -#if 0 /* temporary */ +#if 1 /* temporary */ void (*update_rate_tbl) (struct ieee80211_hw *hw, struct ieee80211_sta *sta, u8 rssi_level); -#else +#endif +#if 1 /* temporary */ void (*update_rate_table) (struct ieee80211_hw *hw); #endif void (*update_rate_mask) (struct ieee80211_hw *hw, u8 rssi_level); -- cgit v0.10.2 From 46a6272c20d4f639093ad2ad8db1eba622187bee Mon Sep 17 00:00:00 2001 From: Chaoming_Li Date: Mon, 25 Apr 2011 13:23:05 -0500 Subject: rtlwifi: Change cam routines for addition of rtl8192se and rtl8192de Change cam routines for addition of RTL8192SE and RTL8192DE code Signed-off-by: Chaoming_Li Signed-off-by: Larry Finger Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/rtlwifi/cam.c b/drivers/net/wireless/rtlwifi/cam.c index 52c9c13..7295af0 100644 --- a/drivers/net/wireless/rtlwifi/cam.c +++ b/drivers/net/wireless/rtlwifi/cam.c @@ -23,6 +23,8 @@ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, * Hsinchu 300, Taiwan. * + * Larry Finger + * *****************************************************************************/ #include "wifi.h" @@ -49,7 +51,7 @@ static void rtl_cam_program_entry(struct ieee80211_hw *hw, u32 entry_no, u32 target_content = 0; u8 entry_i; - RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG, + RT_TRACE(rtlpriv, COMP_SEC, DBG_LOUD, ("key_cont_128:\n %x:%x:%x:%x:%x:%x\n", key_cont_128[0], key_cont_128[1], key_cont_128[2], key_cont_128[3], @@ -68,15 +70,13 @@ static void rtl_cam_program_entry(struct ieee80211_hw *hw, u32 entry_no, rtl_write_dword(rtlpriv, rtlpriv->cfg->maps[RWCAM], target_command); - RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG, - ("rtl_cam_program_entry(): " - "WRITE %x: %x\n", + RT_TRACE(rtlpriv, COMP_SEC, DBG_LOUD, + ("WRITE %x: %x\n", rtlpriv->cfg->maps[WCAMI], target_content)); - RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG, + RT_TRACE(rtlpriv, COMP_SEC, DBG_LOUD, ("The Key ID is %d\n", entry_no)); - RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG, - ("rtl_cam_program_entry(): " - "WRITE %x: %x\n", + RT_TRACE(rtlpriv, COMP_SEC, DBG_LOUD, + ("WRITE %x: %x\n", rtlpriv->cfg->maps[RWCAM], target_command)); } else if (entry_i == 1) { @@ -91,12 +91,10 @@ static void rtl_cam_program_entry(struct ieee80211_hw *hw, u32 entry_no, rtl_write_dword(rtlpriv, rtlpriv->cfg->maps[RWCAM], target_command); - RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG, - ("rtl_cam_program_entry(): WRITE A4: %x\n", - target_content)); - RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG, - ("rtl_cam_program_entry(): WRITE A0: %x\n", - target_command)); + RT_TRACE(rtlpriv, COMP_SEC, DBG_LOUD, + ("WRITE A4: %x\n", target_content)); + RT_TRACE(rtlpriv, COMP_SEC, DBG_LOUD, + ("WRITE A0: %x\n", target_command)); } else { @@ -113,16 +111,14 @@ static void rtl_cam_program_entry(struct ieee80211_hw *hw, u32 entry_no, target_command); udelay(100); - RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG, - ("rtl_cam_program_entry(): WRITE A4: %x\n", - target_content)); - RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG, - ("rtl_cam_program_entry(): WRITE A0: %x\n", - target_command)); + RT_TRACE(rtlpriv, COMP_SEC, DBG_LOUD, + ("WRITE A4: %x\n", target_content)); + RT_TRACE(rtlpriv, COMP_SEC, DBG_LOUD, + ("WRITE A0: %x\n", target_command)); } } - RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG, + RT_TRACE(rtlpriv, COMP_SEC, DBG_LOUD, ("after set key, usconfig:%x\n", us_config)); } @@ -289,3 +285,71 @@ void rtl_cam_empty_entry(struct ieee80211_hw *hw, u8 uc_index) } EXPORT_SYMBOL(rtl_cam_empty_entry); + +u8 rtl_cam_get_free_entry(struct ieee80211_hw *hw, u8 *sta_addr) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + u32 bitmap = (rtlpriv->sec.hwsec_cam_bitmap) >> 4; + u8 entry_idx = 0; + u8 i, *addr; + + if (NULL == sta_addr) { + RT_TRACE(rtlpriv, COMP_SEC, DBG_EMERG, + ("sta_addr is NULL.\n")); + return TOTAL_CAM_ENTRY; + } + /* Does STA already exist? */ + for (i = 4; i < TOTAL_CAM_ENTRY; i++) { + addr = rtlpriv->sec.hwsec_cam_sta_addr[i]; + if (memcmp(addr, sta_addr, ETH_ALEN) == 0) + return i; + } + /* Get a free CAM entry. */ + for (entry_idx = 4; entry_idx < TOTAL_CAM_ENTRY; entry_idx++) { + if ((bitmap & BIT(0)) == 0) { + RT_TRACE(rtlpriv, COMP_SEC, DBG_EMERG, + ("-----hwsec_cam_bitmap: 0x%x entry_idx=%d\n", + rtlpriv->sec.hwsec_cam_bitmap, entry_idx)); + rtlpriv->sec.hwsec_cam_bitmap |= BIT(0) << entry_idx; + memcpy(rtlpriv->sec.hwsec_cam_sta_addr[entry_idx], + sta_addr, ETH_ALEN); + return entry_idx; + } + bitmap = bitmap >> 1; + } + return TOTAL_CAM_ENTRY; +} +EXPORT_SYMBOL(rtl_cam_get_free_entry); + +void rtl_cam_del_entry(struct ieee80211_hw *hw, u8 *sta_addr) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + u32 bitmap; + u8 i, *addr; + + if (NULL == sta_addr) { + RT_TRACE(rtlpriv, COMP_SEC, DBG_EMERG, + ("sta_addr is NULL.\n")); + } + + if ((sta_addr[0]|sta_addr[1]|sta_addr[2]|sta_addr[3]|\ + sta_addr[4]|sta_addr[5]) == 0) { + RT_TRACE(rtlpriv, COMP_SEC, DBG_EMERG, + ("sta_addr is 00:00:00:00:00:00.\n")); + return; + } + /* Does STA already exist? */ + for (i = 4; i < TOTAL_CAM_ENTRY; i++) { + addr = rtlpriv->sec.hwsec_cam_sta_addr[i]; + bitmap = (rtlpriv->sec.hwsec_cam_bitmap) >> i; + if (((bitmap & BIT(0)) == BIT(0)) && + (memcmp(addr, sta_addr, ETH_ALEN) == 0)) { + /* Remove from HW Security CAM */ + memset(rtlpriv->sec.hwsec_cam_sta_addr[i], 0, ETH_ALEN); + rtlpriv->sec.hwsec_cam_bitmap &= ~(BIT(0) << i); + printk(KERN_INFO "&&&&&&&&&del entry %d\n", i); + } + } + return; +} +EXPORT_SYMBOL(rtl_cam_del_entry); diff --git a/drivers/net/wireless/rtlwifi/cam.h b/drivers/net/wireless/rtlwifi/cam.h index dd82f05..c62da4e 100644 --- a/drivers/net/wireless/rtlwifi/cam.h +++ b/drivers/net/wireless/rtlwifi/cam.h @@ -23,12 +23,13 @@ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, * Hsinchu 300, Taiwan. * + * Larry Finger + * *****************************************************************************/ #ifndef __RTL_CAM_H_ #define __RTL_CAM_H_ -#define TOTAL_CAM_ENTRY 32 #define CAM_CONTENT_COUNT 8 #define CFG_DEFAULT_KEY BIT(5) @@ -49,5 +50,7 @@ int rtl_cam_delete_one_entry(struct ieee80211_hw *hw, u8 *mac_addr, void rtl_cam_mark_invalid(struct ieee80211_hw *hw, u8 uc_index); void rtl_cam_empty_entry(struct ieee80211_hw *hw, u8 uc_index); void rtl_cam_reset_sec_info(struct ieee80211_hw *hw); +u8 rtl_cam_get_free_entry(struct ieee80211_hw *hw, u8 *sta_addr); +void rtl_cam_del_entry(struct ieee80211_hw *hw, u8 *sta_addr); #endif -- cgit v0.10.2 From 0baa0fd76f3f5a134461d6cf30294f6bb1bb824c Mon Sep 17 00:00:00 2001 From: Chaoming_Li Date: Mon, 25 Apr 2011 13:23:10 -0500 Subject: rtlwifi: Convert core routines for addition of rtl8192se and rtl8192de Convert core routines for addition of RTL8192SE and RTL8192DE code. Additional files are changed to allow compilation. Signed-off-by: Chaoming_Li Signed-off-by: Larry Finger Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/rtlwifi/base.c b/drivers/net/wireless/rtlwifi/base.c index 7b3eadf..2df9946 100644 --- a/drivers/net/wireless/rtlwifi/base.c +++ b/drivers/net/wireless/rtlwifi/base.c @@ -1182,14 +1182,8 @@ int rtl_send_smps_action(struct ieee80211_hw *hw, info->control.rates[0].idx = 0; info->control.sta = sta; info->band = hw->conf.channel->band; -#if 0 rtlpriv->intf_ops->adapter_tx(hw, skb, &tcb_desc); -#else - rtlpriv->intf_ops->adapter_tx(hw, skb); -#endif } - return 1; - err_free: return 0; } diff --git a/drivers/net/wireless/rtlwifi/core.c b/drivers/net/wireless/rtlwifi/core.c index 8fed3c6..fc89cd8 100644 --- a/drivers/net/wireless/rtlwifi/core.c +++ b/drivers/net/wireless/rtlwifi/core.c @@ -24,6 +24,7 @@ * Hsinchu 300, Taiwan. * * Larry Finger + * *****************************************************************************/ #include "wifi.h" @@ -70,6 +71,7 @@ static void rtl_op_stop(struct ieee80211_hw *hw) mac->link_state = MAC80211_NOLINK; memset(mac->bssid, 0, 6); + mac->vendor = PEER_UNKNOWN; /*reset sec info */ rtl_cam_reset_sec_info(hw); @@ -85,6 +87,8 @@ static void rtl_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb) struct rtl_priv *rtlpriv = rtl_priv(hw); struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); + struct rtl_tcb_desc tcb_desc; + memset(&tcb_desc, 0, sizeof(struct rtl_tcb_desc)); if (unlikely(is_hal_stop(rtlhal) || ppsc->rfpwr_state != ERFON)) goto err_free; @@ -92,8 +96,8 @@ static void rtl_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb) if (!test_bit(RTL_STATUS_INTERFACE_START, &rtlpriv->status)) goto err_free; - - rtlpriv->intf_ops->adapter_tx(hw, skb); + if (!rtlpriv->intf_ops->waitq_insert(hw, skb)) + rtlpriv->intf_ops->adapter_tx(hw, skb, &tcb_desc); return; @@ -134,10 +138,26 @@ static int rtl_op_add_interface(struct ieee80211_hw *hw, mac->link_state = MAC80211_LINKED; rtlpriv->cfg->ops->set_bcn_reg(hw); + if (rtlpriv->rtlhal.current_bandtype == BAND_ON_2_4G) + mac->basic_rates = 0xfff; + else + mac->basic_rates = 0xff0; + rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_BASIC_RATE, + (u8 *) (&mac->basic_rates)); + break; case NL80211_IFTYPE_AP: RT_TRACE(rtlpriv, COMP_MAC80211, DBG_LOUD, ("NL80211_IFTYPE_AP\n")); + + mac->link_state = MAC80211_LINKED; + rtlpriv->cfg->ops->set_bcn_reg(hw); + if (rtlpriv->rtlhal.current_bandtype == BAND_ON_2_4G) + mac->basic_rates = 0xfff; + else + mac->basic_rates = 0xff0; + rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_BASIC_RATE, + (u8 *) (&mac->basic_rates)); break; default: RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, @@ -184,13 +204,12 @@ static void rtl_op_remove_interface(struct ieee80211_hw *hw, mac->vif = NULL; mac->link_state = MAC80211_NOLINK; memset(mac->bssid, 0, 6); + mac->vendor = PEER_UNKNOWN; mac->opmode = NL80211_IFTYPE_UNSPECIFIED; rtlpriv->cfg->ops->set_network_type(hw, mac->opmode); - mutex_unlock(&rtlpriv->locks.conf_mutex); } - static int rtl_op_config(struct ieee80211_hw *hw, u32 changed) { struct rtl_priv *rtlpriv = rtl_priv(hw); @@ -222,10 +241,25 @@ static int rtl_op_config(struct ieee80211_hw *hw, u32 changed) /*For LPS */ if (changed & IEEE80211_CONF_CHANGE_PS) { - if (conf->flags & IEEE80211_CONF_PS) - rtl_lps_enter(hw); - else - rtl_lps_leave(hw); + cancel_delayed_work(&rtlpriv->works.ps_work); + cancel_delayed_work(&rtlpriv->works.ps_rfon_wq); + if (conf->flags & IEEE80211_CONF_PS) { + rtlpriv->psc.sw_ps_enabled = true; + /* sleep here is must, or we may recv the beacon and + * cause mac80211 into wrong ps state, this will cause + * power save nullfunc send fail, and further cause + * pkt loss, So sleep must quickly but not immediatly + * because that will cause nullfunc send by mac80211 + * fail, and cause pkt loss, we have tested that 5mA + * is worked very well */ + if (!rtlpriv->psc.multi_buffered) + queue_delayed_work(rtlpriv->works.rtl_wq, + &rtlpriv->works.ps_work, + MSECS(5)); + } else { + rtl_swlps_rf_awake(hw); + rtlpriv->psc.sw_ps_enabled = false; + } } if (changed & IEEE80211_CONF_CHANGE_RETRY_LIMITS) { @@ -257,7 +291,7 @@ static int rtl_op_config(struct ieee80211_hw *hw, u32 changed) case NL80211_CHAN_NO_HT: /* SC */ mac->cur_40_prime_sc = - PRIME_CHNL_OFFSET_DONT_CARE; + PRIME_CHNL_OFFSET_DONT_CARE; rtlphy->current_chan_bw = HT_CHANNEL_WIDTH_20; mac->bw_40 = false; break; @@ -265,7 +299,7 @@ static int rtl_op_config(struct ieee80211_hw *hw, u32 changed) /* SC */ mac->cur_40_prime_sc = PRIME_CHNL_OFFSET_UPPER; rtlphy->current_chan_bw = - HT_CHANNEL_WIDTH_20_40; + HT_CHANNEL_WIDTH_20_40; mac->bw_40 = true; /*wide channel */ @@ -276,7 +310,7 @@ static int rtl_op_config(struct ieee80211_hw *hw, u32 changed) /* SC */ mac->cur_40_prime_sc = PRIME_CHNL_OFFSET_LOWER; rtlphy->current_chan_bw = - HT_CHANNEL_WIDTH_20_40; + HT_CHANNEL_WIDTH_20_40; mac->bw_40 = true; /*wide channel */ @@ -286,16 +320,29 @@ static int rtl_op_config(struct ieee80211_hw *hw, u32 changed) default: mac->bw_40 = false; RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, - ("switch case not processed\n")); + ("switch case not processed\n")); break; } if (wide_chan <= 0) wide_chan = 1; + + /* In scanning, before we go offchannel we may send a ps=1 null + * to AP, and then we may send a ps = 0 null to AP quickly, but + * first null may have caused AP to put lots of packet to hw tx + * buffer. These packets must be tx'd before we go off channel + * so we must delay more time to let AP flush these packets + * before going offchannel, or dis-association or delete BA will + * happen by AP + */ + if (rtlpriv->mac80211.offchan_deley) { + rtlpriv->mac80211.offchan_deley = false; + mdelay(50); + } rtlphy->current_channel = wide_chan; - rtlpriv->cfg->ops->set_channel_access(hw); rtlpriv->cfg->ops->switch_channel(hw); + rtlpriv->cfg->ops->set_channel_access(hw); rtlpriv->cfg->ops->set_bw_mode(hw, hw->conf.channel_type); } @@ -343,27 +390,28 @@ static void rtl_op_configure_filter(struct ieee80211_hw *hw, } } - if (changed_flags & FIF_BCN_PRBRESP_PROMISC) { - /* - *TODO: BIT(5) is probe response BIT(8) is beacon - *TODO: Use define for BIT(5) and BIT(8) - */ - if (*new_flags & FIF_BCN_PRBRESP_PROMISC) - mac->rx_mgt_filter |= (BIT(5) | BIT(8)); - else - mac->rx_mgt_filter &= ~(BIT(5) | BIT(8)); + /* if ssid not set to hw don't check bssid + * here just used for linked scanning, & linked + * and nolink check bssid is set in set network_type */ + if ((changed_flags & FIF_BCN_PRBRESP_PROMISC) && + (mac->link_state >= MAC80211_LINKED)) { + if (mac->opmode != NL80211_IFTYPE_AP) { + if (*new_flags & FIF_BCN_PRBRESP_PROMISC) { + rtlpriv->cfg->ops->set_chk_bssid(hw, false); + } else { + rtlpriv->cfg->ops->set_chk_bssid(hw, true); + } + } } if (changed_flags & FIF_CONTROL) { if (*new_flags & FIF_CONTROL) { mac->rx_conf |= rtlpriv->cfg->maps[MAC_RCR_ACF]; - mac->rx_ctrl_filter |= RTL_SUPPORTED_CTRL_FILTER; RT_TRACE(rtlpriv, COMP_MAC80211, DBG_LOUD, ("Enable receive control frame.\n")); } else { mac->rx_conf &= ~rtlpriv->cfg->maps[MAC_RCR_ACF]; - mac->rx_ctrl_filter &= ~RTL_SUPPORTED_CTRL_FILTER; RT_TRACE(rtlpriv, COMP_MAC80211, DBG_LOUD, ("Disable receive control frame.\n")); } @@ -380,14 +428,54 @@ static void rtl_op_configure_filter(struct ieee80211_hw *hw, ("Disable receive other BSS's frame.\n")); } } - - rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_RCR, (u8 *) (&mac->rx_conf)); - rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_MGT_FILTER, - (u8 *) (&mac->rx_mgt_filter)); - rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_CTRL_FILTER, - (u8 *) (&mac->rx_ctrl_filter)); } +static int rtl_op_sta_add(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct ieee80211_sta *sta) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); + struct rtl_sta_info *sta_entry; + + if (sta) { + sta_entry = (struct rtl_sta_info *) sta->drv_priv; + if (rtlhal->current_bandtype == BAND_ON_2_4G) { + sta_entry->wireless_mode = WIRELESS_MODE_G; + if (sta->supp_rates[0] <= 0xf) + sta_entry->wireless_mode = WIRELESS_MODE_B; + if (sta->ht_cap.ht_supported == true) + sta_entry->wireless_mode = WIRELESS_MODE_N_24G; + } else if (rtlhal->current_bandtype == BAND_ON_5G) { + sta_entry->wireless_mode = WIRELESS_MODE_A; + if (sta->ht_cap.ht_supported == true) + sta_entry->wireless_mode = WIRELESS_MODE_N_24G; + } + + /* I found some times mac80211 give wrong supp_rates for adhoc*/ + if (rtlpriv->mac80211.opmode == NL80211_IFTYPE_ADHOC) + sta_entry->wireless_mode = WIRELESS_MODE_G; + RT_TRACE(rtlpriv, COMP_MAC80211, DBG_DMESG, + ("Add sta addr is "MAC_FMT"\n", MAC_ARG(sta->addr))); + rtlpriv->cfg->ops->update_rate_tbl(hw, sta, 0); + } + return 0; +} +static int rtl_op_sta_remove(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct ieee80211_sta *sta) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_sta_info *sta_entry; + if (sta) { + RT_TRACE(rtlpriv, COMP_MAC80211, DBG_DMESG, + ("Remove sta addr is "MAC_FMT"\n", MAC_ARG(sta->addr))); + sta_entry = (struct rtl_sta_info *) sta->drv_priv; + sta_entry->wireless_mode = 0; + sta_entry->ratr_index = 0; + } + return 0; +} static int _rtl_get_hal_qnum(u16 queue) { int qnum; @@ -444,19 +532,18 @@ static void rtl_op_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_bss_conf *bss_conf, u32 changed) { struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_hal *rtlhal = rtl_hal(rtlpriv); struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); + struct ieee80211_sta *sta = NULL; mutex_lock(&rtlpriv->locks.conf_mutex); - if ((vif->type == NL80211_IFTYPE_ADHOC) || (vif->type == NL80211_IFTYPE_AP) || (vif->type == NL80211_IFTYPE_MESH_POINT)) { - if ((changed & BSS_CHANGED_BEACON) || (changed & BSS_CHANGED_BEACON_ENABLED && bss_conf->enable_beacon)) { - if (mac->beacon_enabled == 0) { RT_TRACE(rtlpriv, COMP_MAC80211, DBG_DMESG, ("BSS_CHANGED_BEACON_ENABLED\n")); @@ -468,8 +555,13 @@ static void rtl_op_bss_info_changed(struct ieee80211_hw *hw, rtlpriv->cfg->maps [RTL_IBSS_INT_MASKS], 0); + + if (rtlpriv->cfg->ops->linked_set_reg) + rtlpriv->cfg->ops->linked_set_reg(hw); } - } else { + } + if ((changed & BSS_CHANGED_BEACON_ENABLED && + !bss_conf->enable_beacon)) { if (mac->beacon_enabled == 1) { RT_TRACE(rtlpriv, COMP_MAC80211, DBG_DMESG, ("ADHOC DISABLE BEACON\n")); @@ -480,7 +572,6 @@ static void rtl_op_bss_info_changed(struct ieee80211_hw *hw, [RTL_IBSS_INT_MASKS]); } } - if (changed & BSS_CHANGED_BEACON_INT) { RT_TRACE(rtlpriv, COMP_BEACON, DBG_TRACE, ("BSS_CHANGED_BEACON_INT\n")); @@ -492,11 +583,25 @@ static void rtl_op_bss_info_changed(struct ieee80211_hw *hw, /*TODO: reference to enum ieee80211_bss_change */ if (changed & BSS_CHANGED_ASSOC) { if (bss_conf->assoc) { + /* we should reset all sec info & cam + * before set cam after linked, we should not + * reset in disassoc, that will cause tkip->wep + * fail because some flag will be wrong */ + /* reset sec info */ + rtl_cam_reset_sec_info(hw); + /* reset cam to fix wep fail issue + * when change from wpa to wep */ + rtl_cam_reset_all_entry(hw); + mac->link_state = MAC80211_LINKED; mac->cnt_after_linked = 0; mac->assoc_id = bss_conf->aid; memcpy(mac->bssid, bss_conf->bssid, 6); + if (rtlpriv->cfg->ops->linked_set_reg) + rtlpriv->cfg->ops->linked_set_reg(hw); + if (mac->opmode == NL80211_IFTYPE_STATION && sta) + rtlpriv->cfg->ops->update_rate_tbl(hw, sta, 0); RT_TRACE(rtlpriv, COMP_MAC80211, DBG_DMESG, ("BSS_CHANGED_ASSOC\n")); } else { @@ -505,9 +610,7 @@ static void rtl_op_bss_info_changed(struct ieee80211_hw *hw, mac->link_state = MAC80211_NOLINK; memset(mac->bssid, 0, 6); - - /* reset sec info */ - rtl_cam_reset_sec_info(hw); + mac->vendor = PEER_UNKNOWN; RT_TRACE(rtlpriv, COMP_MAC80211, DBG_DMESG, ("BSS_CHANGED_UN_ASSOC\n")); @@ -544,14 +647,10 @@ static void rtl_op_bss_info_changed(struct ieee80211_hw *hw, } if (changed & BSS_CHANGED_HT) { - struct ieee80211_sta *sta = NULL; - RT_TRACE(rtlpriv, COMP_MAC80211, DBG_TRACE, ("BSS_CHANGED_HT\n")); - rcu_read_lock(); - sta = ieee80211_find_sta(mac->vif, mac->bssid); - + sta = get_sta(hw, vif, (u8 *)bss_conf->bssid); if (sta) { if (sta->ht_cap.ampdu_density > mac->current_ampdu_density) @@ -573,9 +672,7 @@ static void rtl_op_bss_info_changed(struct ieee80211_hw *hw, } if (changed & BSS_CHANGED_BSSID) { - struct ieee80211_sta *sta = NULL; u32 basic_rates; - u8 i; rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_BSSID, (u8 *) bss_conf->bssid); @@ -583,96 +680,65 @@ static void rtl_op_bss_info_changed(struct ieee80211_hw *hw, RT_TRACE(rtlpriv, COMP_MAC80211, DBG_DMESG, (MAC_FMT "\n", MAC_ARG(bss_conf->bssid))); + mac->vendor = PEER_UNKNOWN; memcpy(mac->bssid, bss_conf->bssid, 6); - if (is_valid_ether_addr(bss_conf->bssid)) { - switch (vif->type) { - case NL80211_IFTYPE_UNSPECIFIED: - break; - case NL80211_IFTYPE_ADHOC: - break; - case NL80211_IFTYPE_STATION: - break; - case NL80211_IFTYPE_AP: - break; - default: - RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, - ("switch case not process\n")); - break; - } - rtlpriv->cfg->ops->set_network_type(hw, vif->type); - } else - rtlpriv->cfg->ops->set_network_type(hw, - NL80211_IFTYPE_UNSPECIFIED); - - memset(mac->mcs, 0, 16); - mac->ht_enable = false; - mac->sgi_40 = false; - mac->sgi_20 = false; - - if (!bss_conf->use_short_slot) - mac->mode = WIRELESS_MODE_B; - else - mac->mode = WIRELESS_MODE_G; + rtlpriv->cfg->ops->set_network_type(hw, vif->type); rcu_read_lock(); - sta = ieee80211_find_sta(mac->vif, mac->bssid); + sta = get_sta(hw, vif, (u8 *)bss_conf->bssid); + if (!sta) { + rcu_read_unlock(); + goto out; + } - if (sta) { - if (sta->ht_cap.ht_supported) { + if (rtlhal->current_bandtype == BAND_ON_5G) { + mac->mode = WIRELESS_MODE_A; + } else { + if (sta->supp_rates[0] <= 0xf) + mac->mode = WIRELESS_MODE_B; + else + mac->mode = WIRELESS_MODE_G; + } + + if (sta->ht_cap.ht_supported) { + if (rtlhal->current_bandtype == BAND_ON_2_4G) mac->mode = WIRELESS_MODE_N_24G; - mac->ht_enable = true; - } + else + mac->mode = WIRELESS_MODE_N_5G; + } - if (mac->ht_enable) { - u16 ht_cap = sta->ht_cap.cap; - memcpy(mac->mcs, (u8 *) (&sta->ht_cap.mcs), 16); - - for (i = 0; i < 16; i++) - RT_TRACE(rtlpriv, COMP_MAC80211, - DBG_LOUD, ("%x ", - mac->mcs[i])); - RT_TRACE(rtlpriv, COMP_MAC80211, DBG_LOUD, - ("\n")); - - if (ht_cap & IEEE80211_HT_CAP_SGI_40) - mac->sgi_40 = true; - - if (ht_cap & IEEE80211_HT_CAP_SGI_20) - mac->sgi_20 = true; - - /* - * for cisco 1252 bw20 it's wrong - * if (ht_cap & - * IEEE80211_HT_CAP_SUP_WIDTH_20_40) { - * mac->bw_40 = true; - * } - */ - } + /* just station need it, because ibss & ap mode will + * set in sta_add, and will be NULL here */ + if (mac->opmode == NL80211_IFTYPE_STATION) { + struct rtl_sta_info *sta_entry; + sta_entry = (struct rtl_sta_info *) sta->drv_priv; + sta_entry->wireless_mode = mac->mode; + } + + if (sta->ht_cap.ht_supported) { + mac->ht_enable = true; + + /* + * for cisco 1252 bw20 it's wrong + * if (ht_cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40) { + * mac->bw_40 = true; + * } + * */ } - rcu_read_unlock(); - /*mac80211 just give us CCK rates any time - *So we add G rate in basic rates when - not in B mode*/ if (changed & BSS_CHANGED_BASIC_RATES) { - if (mac->mode == WIRELESS_MODE_B) - basic_rates = bss_conf->basic_rates | 0x00f; + /* for 5G must << RATE_6M_INDEX=4, + * because 5G have no cck rate*/ + if (rtlhal->current_bandtype == BAND_ON_5G) + basic_rates = sta->supp_rates[1] << 4; else - basic_rates = bss_conf->basic_rates | 0xff0; - - if (!vif) - goto out; + basic_rates = sta->supp_rates[0]; mac->basic_rates = basic_rates; rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_BASIC_RATE, (u8 *) (&basic_rates)); - - if (rtlpriv->dm.useramask) - rtlpriv->cfg->ops->update_rate_mask(hw, 0); - else - rtlpriv->cfg->ops->update_rate_table(hw); - } + rcu_read_unlock(); } /* @@ -758,16 +824,17 @@ static int rtl_op_ampdu_action(struct ieee80211_hw *hw, case IEEE80211_AMPDU_TX_START: RT_TRACE(rtlpriv, COMP_MAC80211, DBG_TRACE, ("IEEE80211_AMPDU_TX_START: TID:%d\n", tid)); - return rtl_tx_agg_start(hw, sta->addr, tid, ssn); + return rtl_tx_agg_start(hw, sta, tid, ssn); break; case IEEE80211_AMPDU_TX_STOP: RT_TRACE(rtlpriv, COMP_MAC80211, DBG_TRACE, ("IEEE80211_AMPDU_TX_STOP: TID:%d\n", tid)); - return rtl_tx_agg_stop(hw, sta->addr, tid); + return rtl_tx_agg_stop(hw, sta, tid); break; case IEEE80211_AMPDU_TX_OPERATIONAL: RT_TRACE(rtlpriv, COMP_MAC80211, DBG_TRACE, ("IEEE80211_AMPDU_TX_OPERATIONAL:TID:%d\n", tid)); + rtl_tx_agg_oper(hw, sta, tid); break; case IEEE80211_AMPDU_RX_START: RT_TRACE(rtlpriv, COMP_MAC80211, DBG_TRACE, @@ -797,8 +864,12 @@ static void rtl_op_sw_scan_start(struct ieee80211_hw *hw) if (mac->link_state == MAC80211_LINKED) { rtl_lps_leave(hw); mac->link_state = MAC80211_LINKED_SCANNING; - } else + } else { rtl_ips_nic_on(hw); + } + + /* Dual mac */ + rtlpriv->rtlhal.load_imrandiqk_setting_for2g = false; rtlpriv->cfg->ops->led_control(hw, LED_CTL_SITE_SURVEY); rtlpriv->cfg->ops->scan_operation_backup(hw, SCAN_OPT_BACKUP); @@ -810,22 +881,19 @@ static void rtl_op_sw_scan_complete(struct ieee80211_hw *hw) struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); RT_TRACE(rtlpriv, COMP_MAC80211, DBG_LOUD, ("\n")); - - rtlpriv->cfg->ops->scan_operation_backup(hw, SCAN_OPT_RESTORE); mac->act_scanning = false; + /* Dual mac */ + rtlpriv->rtlhal.load_imrandiqk_setting_for2g = false; + if (mac->link_state == MAC80211_LINKED_SCANNING) { mac->link_state = MAC80211_LINKED; - - /* fix fwlps issue */ - rtlpriv->cfg->ops->set_network_type(hw, mac->opmode); - - if (rtlpriv->dm.useramask) - rtlpriv->cfg->ops->update_rate_mask(hw, 0); - else - rtlpriv->cfg->ops->update_rate_table(hw); - + if (mac->opmode == NL80211_IFTYPE_STATION) { + /* fix fwlps issue */ + rtlpriv->cfg->ops->set_network_type(hw, mac->opmode); + } } + rtlpriv->cfg->ops->scan_operation_backup(hw, SCAN_OPT_RESTORE); } static int rtl_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, @@ -856,49 +924,73 @@ static int rtl_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, rtl_ips_nic_on(hw); mutex_lock(&rtlpriv->locks.conf_mutex); /* <1> get encryption alg */ + switch (key->cipher) { case WLAN_CIPHER_SUITE_WEP40: key_type = WEP40_ENCRYPTION; RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG, ("alg:WEP40\n")); - rtlpriv->sec.use_defaultkey = true; break; case WLAN_CIPHER_SUITE_WEP104: RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG, ("alg:WEP104\n")); key_type = WEP104_ENCRYPTION; - rtlpriv->sec.use_defaultkey = true; break; case WLAN_CIPHER_SUITE_TKIP: key_type = TKIP_ENCRYPTION; RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG, ("alg:TKIP\n")); - if (mac->opmode == NL80211_IFTYPE_ADHOC) - rtlpriv->sec.use_defaultkey = true; break; case WLAN_CIPHER_SUITE_CCMP: key_type = AESCCMP_ENCRYPTION; RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG, ("alg:CCMP\n")); - if (mac->opmode == NL80211_IFTYPE_ADHOC) - rtlpriv->sec.use_defaultkey = true; break; default: RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, ("alg_err:%x!!!!:\n", key->cipher)); goto out_unlock; } + if (key_type == WEP40_ENCRYPTION || + key_type == WEP104_ENCRYPTION || + mac->opmode == NL80211_IFTYPE_ADHOC) + rtlpriv->sec.use_defaultkey = true; + /* <2> get key_idx */ key_idx = (u8) (key->keyidx); if (key_idx > 3) goto out_unlock; /* <3> if pairwise key enable_hw_sec */ group_key = !(key->flags & IEEE80211_KEY_FLAG_PAIRWISE); - if ((!group_key) || (mac->opmode == NL80211_IFTYPE_ADHOC) || - rtlpriv->sec.pairwise_enc_algorithm == NO_ENCRYPTION) { - if (rtlpriv->sec.pairwise_enc_algorithm == NO_ENCRYPTION && - (key_type == WEP40_ENCRYPTION || - key_type == WEP104_ENCRYPTION)) - wep_only = true; - rtlpriv->sec.pairwise_enc_algorithm = key_type; - rtlpriv->cfg->ops->enable_hw_sec(hw); + + /* wep always be group key, but there are two conditions: + * 1) wep only: is just for wep enc, in this condition + * rtlpriv->sec.pairwise_enc_algorithm == NO_ENCRYPTION + * will be true & enable_hw_sec will be set when wep + * ke setting. + * 2) wep(group) + AES(pairwise): some AP like cisco + * may use it, in this condition enable_hw_sec will not + * be set when wep key setting */ + /* we must reset sec_info after lingked before set key, + * or some flag will be wrong*/ + if (mac->opmode == NL80211_IFTYPE_AP) { + if (!group_key || key_type == WEP40_ENCRYPTION || + key_type == WEP104_ENCRYPTION) { + if (group_key) + wep_only = true; + rtlpriv->cfg->ops->enable_hw_sec(hw); + } + } else { + if ((!group_key) || (mac->opmode == NL80211_IFTYPE_ADHOC) || + rtlpriv->sec.pairwise_enc_algorithm == NO_ENCRYPTION) { + if (rtlpriv->sec.pairwise_enc_algorithm == + NO_ENCRYPTION && + (key_type == WEP40_ENCRYPTION || + key_type == WEP104_ENCRYPTION)) + wep_only = true; + rtlpriv->sec.pairwise_enc_algorithm = key_type; + RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG, + ("set enable_hw_sec, key_type:%x(OPEN:0 WEP40:1" + " TKIP:2 AES:4 WEP104:5)\n", key_type)); + rtlpriv->cfg->ops->enable_hw_sec(hw); + } } /* <4> set key based on cmd */ switch (cmd) { @@ -930,6 +1022,7 @@ static int rtl_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, if (!sta) { RT_ASSERT(false, ("pairwise key withnot" "mac_addr\n")); + err = -EOPNOTSUPP; goto out_unlock; } @@ -957,6 +1050,10 @@ static int rtl_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG, ("disable key delete one entry\n")); /*set local buf about wep key. */ + if (mac->opmode == NL80211_IFTYPE_AP) { + if (sta) + rtl_cam_del_entry(hw, sta->addr); + } memset(rtlpriv->sec.key_buf[key_idx], 0, key->keylen); rtlpriv->sec.key_len[key_idx] = 0; memcpy(mac_addr, zero_addr, ETH_ALEN); @@ -1009,6 +1106,18 @@ static void rtl_op_rfkill_poll(struct ieee80211_hw *hw) mutex_unlock(&rtlpriv->locks.conf_mutex); } +/* this function is called by mac80211 to flush tx buffer + * before switch channle or power save, or tx buffer packet + * maybe send after offchannel or rf sleep, this may cause + * dis-association by AP */ +static void rtl_op_flush(struct ieee80211_hw *hw, bool drop) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + + if (rtlpriv->intf_ops->flush) + rtlpriv->intf_ops->flush(hw, drop); +} + const struct ieee80211_ops rtl_ops = { .start = rtl_op_start, .stop = rtl_op_stop, @@ -1017,6 +1126,8 @@ const struct ieee80211_ops rtl_ops = { .remove_interface = rtl_op_remove_interface, .config = rtl_op_config, .configure_filter = rtl_op_configure_filter, + .sta_add = rtl_op_sta_add, + .sta_remove = rtl_op_sta_remove, .set_key = rtl_op_set_key, .conf_tx = rtl_op_conf_tx, .bss_info_changed = rtl_op_bss_info_changed, @@ -1028,4 +1139,5 @@ const struct ieee80211_ops rtl_ops = { .sw_scan_start = rtl_op_sw_scan_start, .sw_scan_complete = rtl_op_sw_scan_complete, .rfkill_poll = rtl_op_rfkill_poll, + .flush = rtl_op_flush, }; diff --git a/drivers/net/wireless/rtlwifi/core.h b/drivers/net/wireless/rtlwifi/core.h index 0ef31c3c..4b247db 100644 --- a/drivers/net/wireless/rtlwifi/core.h +++ b/drivers/net/wireless/rtlwifi/core.h @@ -24,6 +24,7 @@ * Hsinchu 300, Taiwan. * * Larry Finger + * *****************************************************************************/ #ifndef __RTL_CORE_H__ diff --git a/drivers/net/wireless/rtlwifi/ps.c b/drivers/net/wireless/rtlwifi/ps.c index bdb3c5f..8618490 100644 --- a/drivers/net/wireless/rtlwifi/ps.c +++ b/drivers/net/wireless/rtlwifi/ps.c @@ -424,6 +424,10 @@ void rtl_swlps_wq_callback(void *data) { } +void rtl_swlps_rf_awake(struct ieee80211_hw *hw) +{ +} + /*Enter the leisure power save mode.*/ void rtl_lps_enter(struct ieee80211_hw *hw) { diff --git a/drivers/net/wireless/rtlwifi/rtl8192cu/trx.c b/drivers/net/wireless/rtlwifi/rtl8192cu/trx.c index 0df2fec..cc5de07 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192cu/trx.c +++ b/drivers/net/wireless/rtlwifi/rtl8192cu/trx.c @@ -504,7 +504,7 @@ void rtl92cu_tx_fill_desc(struct ieee80211_hw *hw, struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); bool defaultadapter = true; - struct ieee80211_sta *sta; + struct ieee80211_sta *sta = info->control.sta; struct rtl_tcb_desc tcb_desc; u8 *qc = ieee80211_get_qos_ctl(hdr); u8 tid = qc[0] & IEEE80211_QOS_CTL_TID_MASK; diff --git a/drivers/net/wireless/rtlwifi/usb.c b/drivers/net/wireless/rtlwifi/usb.c index f4ab1b7..14539eb 100644 --- a/drivers/net/wireless/rtlwifi/usb.c +++ b/drivers/net/wireless/rtlwifi/usb.c @@ -885,7 +885,8 @@ static void _rtl_usb_tx_preprocess(struct ieee80211_hw *hw, struct sk_buff *skb, rtlpriv->cfg->ops->led_control(hw, LED_CTL_TX); } -static int rtl_usb_tx(struct ieee80211_hw *hw, struct sk_buff *skb) +static int rtl_usb_tx(struct ieee80211_hw *hw, struct sk_buff *skb, + struct rtl_tcb_desc *dummy) { struct rtl_usb *rtlusb = rtl_usbdev(rtl_usbpriv(hw)); struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); diff --git a/drivers/net/wireless/rtlwifi/wifi.h b/drivers/net/wireless/rtlwifi/wifi.h index 7c52435..4776cd1 100644 --- a/drivers/net/wireless/rtlwifi/wifi.h +++ b/drivers/net/wireless/rtlwifi/wifi.h @@ -1445,12 +1445,8 @@ struct rtl_intf_ops { int (*adapter_start) (struct ieee80211_hw *hw); void (*adapter_stop) (struct ieee80211_hw *hw); -#if 0 /* temporary */ int (*adapter_tx) (struct ieee80211_hw *hw, struct sk_buff *skb, struct rtl_tcb_desc *ptcb_desc); -#else - int (*adapter_tx) (struct ieee80211_hw *hw, struct sk_buff *skb); -#endif void (*flush)(struct ieee80211_hw *hw, bool drop); int (*reset_trx_ring) (struct ieee80211_hw *hw); bool (*waitq_insert) (struct ieee80211_hw *hw, struct sk_buff *skb); -- cgit v0.10.2 From c7cfe38ee0f946415b0b39e3905a91a51d99cf7d Mon Sep 17 00:00:00 2001 From: Chaoming_Li Date: Mon, 25 Apr 2011 13:23:15 -0500 Subject: rtlwifi: Convert pci routines for addition of rtl8192se and rtl8192de Convert pci routines for addition of RTL8192SE and RTL8192DE code These changes allow the upper-level driver to specify the BAR to be used as it is different for rtl8192se than for the others. Signed-off-by: Chaoming_Li Signed-off-by: Larry Finger Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/rtlwifi/pci.c b/drivers/net/wireless/rtlwifi/pci.c index e2fa78b..fa66205 100644 --- a/drivers/net/wireless/rtlwifi/pci.c +++ b/drivers/net/wireless/rtlwifi/pci.c @@ -32,6 +32,7 @@ #include "pci.h" #include "base.h" #include "ps.h" +#include "efuse.h" static const u16 pcibridge_vendors[PCI_BRIDGE_VENDOR_MAX] = { INTEL_VENDOR_ID, @@ -40,6 +41,31 @@ static const u16 pcibridge_vendors[PCI_BRIDGE_VENDOR_MAX] = { SIS_VENDOR_ID }; +static const u8 ac_to_hwq[] = { + VO_QUEUE, + VI_QUEUE, + BE_QUEUE, + BK_QUEUE +}; + +u8 _rtl_mac_to_hwqueue(struct ieee80211_hw *hw, + struct sk_buff *skb) +{ + struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); + u16 fc = rtl_get_fc(skb); + u8 queue_index = skb_get_queue_mapping(skb); + + if (unlikely(ieee80211_is_beacon(fc))) + return BEACON_QUEUE; + if (ieee80211_is_mgmt(fc)) + return MGNT_QUEUE; + if (rtlhal->hw_type == HARDWARE_TYPE_RTL8192SE) + if (ieee80211_is_nullfunc(fc)) + return HIGH_QUEUE; + + return ac_to_hwq[queue_index]; +} + /* Update PCI dependent default settings*/ static void _rtl_pci_update_default_setting(struct ieee80211_hw *hw) { @@ -48,6 +74,7 @@ static void _rtl_pci_update_default_setting(struct ieee80211_hw *hw) struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); u8 pcibridge_vendor = pcipriv->ndis_adapter.pcibridge_vendor; + u8 init_aspm; ppsc->reg_rfps_level = 0; ppsc->support_aspm = 0; @@ -113,25 +140,110 @@ static void _rtl_pci_update_default_setting(struct ieee80211_hw *hw) /*Set HW definition to determine if it supports ASPM. */ switch (rtlpci->const_support_pciaspm) { - case 0: - /*Not support ASPM. */ - ppsc->support_aspm = false; - break; - case 1: - /*Support ASPM. */ - ppsc->support_aspm = true; - ppsc->support_backdoor = true; - break; + case 0:{ + /*Not support ASPM. */ + bool support_aspm = false; + ppsc->support_aspm = support_aspm; + break; + } + case 1:{ + /*Support ASPM. */ + bool support_aspm = true; + bool support_backdoor = true; + ppsc->support_aspm = support_aspm; + + /*if (priv->oem_id == RT_CID_TOSHIBA && + !priv->ndis_adapter.amd_l1_patch) + support_backdoor = false; */ + + ppsc->support_backdoor = support_backdoor; + + break; + } case 2: /*ASPM value set by chipset. */ - if (pcibridge_vendor == PCI_BRIDGE_VENDOR_INTEL) - ppsc->support_aspm = true; + if (pcibridge_vendor == PCI_BRIDGE_VENDOR_INTEL) { + bool support_aspm = true; + ppsc->support_aspm = support_aspm; + } break; default: RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, ("switch case not process\n")); break; } + + /* toshiba aspm issue, toshiba will set aspm selfly + * so we should not set aspm in driver */ + pci_read_config_byte(rtlpci->pdev, 0x80, &init_aspm); + if (rtlpriv->rtlhal.hw_type == HARDWARE_TYPE_RTL8192SE && + init_aspm == 0x43) + ppsc->support_aspm = false; +} + +/*Disable L0s dirtectly. We will disable host L0s by default. */ +void rtl_pci_disable_host_l0s(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_pci_priv *pcipriv = rtl_pcipriv(hw); + struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); + u8 pcibridge_busnum = pcipriv->ndis_adapter.pcibridge_busnum; + u8 pcibridge_devnum = pcipriv->ndis_adapter.pcibridge_devnum; + u8 pcibridge_funcnum = pcipriv->ndis_adapter.pcibridge_funcnum; + u32 pcicfg_addrport = pcipriv->ndis_adapter.pcicfg_addrport; + u8 num4bytes = pcipriv->ndis_adapter.num4bytes; + u8 u_pcibridge_aspmsetting = 0; + + /*Read Link Control Register */ + rtl_pci_raw_write_port_ulong(PCI_CONF_ADDRESS, + pcicfg_addrport + (num4bytes << 2)); + rtl_pci_raw_read_port_uchar(PCI_CONF_DATA, &u_pcibridge_aspmsetting); + + if (u_pcibridge_aspmsetting & BIT(0)) + u_pcibridge_aspmsetting &= ~(BIT(0)); + + rtl_pci_raw_write_port_ulong(PCI_CONF_ADDRESS, + pcicfg_addrport + (num4bytes << 2)); + rtl_pci_raw_write_port_uchar(PCI_CONF_DATA, u_pcibridge_aspmsetting); + + udelay(50); + + RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, + ("PciBridge busnumber[%x], DevNumbe[%x], " + "funcnumber[%x], Write reg[%x] = %lx\n", + pcibridge_busnum, pcibridge_devnum, pcibridge_funcnum, + (pcipriv->ndis_adapter.pcibridge_pciehdr_offset + 0x10), + (pcipriv->ndis_adapter.pcibridge_linkctrlreg | + (rtlpci->const_devicepci_aspm_setting & ~BIT(0))))); +} + +/*Enable rtl8192ce backdoor to control ASPM and clock request.*/ +bool rtl_pci_enable_back_door(struct ieee80211_hw *hw) +{ + struct rtl_pci_priv *pcipriv = rtl_pcipriv(hw); + struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); + u8 pcibridge_vendor = pcipriv->ndis_adapter.pcibridge_vendor; + bool bresult = true; + u8 value; + + pci_read_config_byte(rtlpci->pdev, 0x70f, &value); + + /*0x70f BIT(7) is used to control L0S */ + if (pcibridge_vendor == PCI_BRIDGE_VENDOR_INTEL) { + value |= BIT(7); + } else { + /*Set 0x70f to 0x23 when non-Intel platform. */ + value = 0x23; + } + + pci_write_config_byte(rtlpci->pdev, 0x70f, value); + + pci_read_config_byte(rtlpci->pdev, 0x719, &value); + /*0x719 BIT(3) is for L1 BIT(4) is for clock request */ + value |= (BIT(3) | BIT(4)); + pci_write_config_byte(rtlpci->pdev, 0x719, value); + + return bresult; } static bool _rtl_pci_platform_switch_device_pci_aspm( @@ -139,8 +251,11 @@ static bool _rtl_pci_platform_switch_device_pci_aspm( u8 value) { struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); + struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); + + if (rtlhal->hw_type != HARDWARE_TYPE_RTL8192SE) + value |= 0x40; - value |= 0x40; pci_write_config_byte(rtlpci->pdev, 0x80, value); return false; @@ -150,11 +265,13 @@ static bool _rtl_pci_platform_switch_device_pci_aspm( static bool _rtl_pci_switch_clk_req(struct ieee80211_hw *hw, u8 value) { struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); - u8 buffer; + struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); - buffer = value; pci_write_config_byte(rtlpci->pdev, 0x81, value); + if (rtlhal->hw_type == HARDWARE_TYPE_RTL8192SE) + udelay(100); + return true; } @@ -175,6 +292,9 @@ static void rtl_pci_disable_aspm(struct ieee80211_hw *hw) u16 aspmlevel = 0; u8 tmp_u1b = 0; + if (!ppsc->support_aspm) + return; + if (pcibridge_vendor == PCI_BRIDGE_VENDOR_UNKNOWN) { RT_TRACE(rtlpriv, COMP_POWER, DBG_TRACE, ("PCI(Bridge) UNKNOWN.\n")); @@ -228,6 +348,9 @@ static void rtl_pci_enable_aspm(struct ieee80211_hw *hw) u8 u_pcibridge_aspmsetting; u8 u_device_aspmsetting; + if (!ppsc->support_aspm) + return; + if (pcibridge_vendor == PCI_BRIDGE_VENDOR_UNKNOWN) { RT_TRACE(rtlpriv, COMP_POWER, DBG_TRACE, ("PCI(Bridge) UNKNOWN.\n")); @@ -272,7 +395,7 @@ static void rtl_pci_enable_aspm(struct ieee80211_hw *hw) RT_RF_OFF_LEVL_CLK_REQ) ? 1 : 0); RT_SET_PS_LEVEL(ppsc, RT_RF_OFF_LEVL_CLK_REQ); } - udelay(200); + udelay(100); } static bool rtl_pci_get_amd_l1_patch(struct ieee80211_hw *hw) @@ -303,19 +426,19 @@ static bool rtl_pci_get_amd_l1_patch(struct ieee80211_hw *hw) return status; } -static void rtl_pci_get_linkcontrol_field(struct ieee80211_hw *hw) +void rtl_pci_get_linkcontrol_field(struct ieee80211_hw *hw) { struct rtl_pci_priv *pcipriv = rtl_pcipriv(hw); u8 capabilityoffset = pcipriv->ndis_adapter.pcibridge_pciehdr_offset; u32 pcicfg_addrport = pcipriv->ndis_adapter.pcicfg_addrport; u8 linkctrl_reg; - u8 num4bBytes; + u8 num4bbytes; - num4bBytes = (capabilityoffset + 0x10) / 4; + num4bbytes = (capabilityoffset + 0x10) / 4; /*Read Link Control Register */ rtl_pci_raw_write_port_ulong(PCI_CONF_ADDRESS, - pcicfg_addrport + (num4bBytes << 2)); + pcicfg_addrport + (num4bbytes << 2)); rtl_pci_raw_read_port_uchar(PCI_CONF_DATA, &linkctrl_reg); pcipriv->ndis_adapter.pcibridge_linkctrlreg = linkctrl_reg; @@ -348,7 +471,7 @@ static void rtl_pci_parse_configuration(struct pci_dev *pdev, pci_write_config_byte(pdev, 0x70f, tmp); } -static void _rtl_pci_initialize_adapter_common(struct ieee80211_hw *hw) +static void rtl_pci_init_aspm(struct ieee80211_hw *hw) { struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); @@ -362,52 +485,6 @@ static void _rtl_pci_initialize_adapter_common(struct ieee80211_hw *hw) } -static void rtl_pci_init_aspm(struct ieee80211_hw *hw) -{ - struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); - - /*close ASPM for AMD defaultly */ - rtlpci->const_amdpci_aspm = 0; - - /* - * ASPM PS mode. - * 0 - Disable ASPM, - * 1 - Enable ASPM without Clock Req, - * 2 - Enable ASPM with Clock Req, - * 3 - Alwyas Enable ASPM with Clock Req, - * 4 - Always Enable ASPM without Clock Req. - * set defult to RTL8192CE:3 RTL8192E:2 - * */ - rtlpci->const_pci_aspm = 3; - - /*Setting for PCI-E device */ - rtlpci->const_devicepci_aspm_setting = 0x03; - - /*Setting for PCI-E bridge */ - rtlpci->const_hostpci_aspm_setting = 0x02; - - /* - * In Hw/Sw Radio Off situation. - * 0 - Default, - * 1 - From ASPM setting without low Mac Pwr, - * 2 - From ASPM setting with low Mac Pwr, - * 3 - Bus D3 - * set default to RTL8192CE:0 RTL8192SE:2 - */ - rtlpci->const_hwsw_rfoff_d3 = 0; - - /* - * This setting works for those device with - * backdoor ASPM setting such as EPHY setting. - * 0 - Not support ASPM, - * 1 - Support ASPM, - * 2 - According to chipset. - */ - rtlpci->const_support_pciaspm = 1; - - _rtl_pci_initialize_adapter_common(hw); -} - static void _rtl_pci_io_handler_init(struct device *dev, struct ieee80211_hw *hw) { @@ -429,6 +506,92 @@ static void _rtl_pci_io_handler_release(struct ieee80211_hw *hw) { } +static bool _rtl_update_earlymode_info(struct ieee80211_hw *hw, + struct sk_buff *skb, struct rtl_tcb_desc *tcb_desc, u8 tid) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); + u8 additionlen = FCS_LEN; + struct sk_buff *next_skb; + + /* here open is 4, wep/tkip is 8, aes is 12*/ + if (info->control.hw_key) + additionlen += info->control.hw_key->icv_len; + + /* The most skb num is 6 */ + tcb_desc->empkt_num = 0; + spin_lock_bh(&rtlpriv->locks.waitq_lock); + skb_queue_walk(&rtlpriv->mac80211.skb_waitq[tid], next_skb) { + struct ieee80211_tx_info *next_info; + + next_info = IEEE80211_SKB_CB(next_skb); + if (next_info->flags & IEEE80211_TX_CTL_AMPDU) { + tcb_desc->empkt_len[tcb_desc->empkt_num] = + next_skb->len + additionlen; + tcb_desc->empkt_num++; + } else { + break; + } + + if (skb_queue_is_last(&rtlpriv->mac80211.skb_waitq[tid], + next_skb)) + break; + + if (tcb_desc->empkt_num >= 5) + break; + } + spin_unlock_bh(&rtlpriv->locks.waitq_lock); + + return true; +} + +/* just for early mode now */ +static void _rtl_pci_tx_chk_waitq(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); + struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); + struct sk_buff *skb = NULL; + struct ieee80211_tx_info *info = NULL; + int tid; /* should be int */ + + if (!rtlpriv->rtlhal.earlymode_enable) + return; + + /* we juse use em for BE/BK/VI/VO */ + for (tid = 7; tid >= 0; tid--) { + u8 hw_queue = ac_to_hwq[rtl_tid_to_ac(hw, tid)]; + struct rtl8192_tx_ring *ring = &rtlpci->tx_ring[hw_queue]; + while (!mac->act_scanning && + rtlpriv->psc.rfpwr_state == ERFON) { + struct rtl_tcb_desc tcb_desc; + memset(&tcb_desc, 0, sizeof(struct rtl_tcb_desc)); + + spin_lock_bh(&rtlpriv->locks.waitq_lock); + if (!skb_queue_empty(&mac->skb_waitq[tid]) && + (ring->entries - skb_queue_len(&ring->queue) > 5)) { + skb = skb_dequeue(&mac->skb_waitq[tid]); + } else { + spin_unlock_bh(&rtlpriv->locks.waitq_lock); + break; + } + spin_unlock_bh(&rtlpriv->locks.waitq_lock); + + /* Some macaddr can't do early mode. like + * multicast/broadcast/no_qos data */ + info = IEEE80211_SKB_CB(skb); + if (info->flags & IEEE80211_TX_CTL_AMPDU) + _rtl_update_earlymode_info(hw, skb, + &tcb_desc, tid); + +#if 0 /* temporary */ + rtlpriv->intf_ops->adapter_tx(hw, skb, &tcb_desc); +#endif + } + } +} + + static void _rtl_pci_tx_isr(struct ieee80211_hw *hw, int prio) { struct rtl_priv *rtlpriv = rtl_priv(hw); @@ -440,6 +603,8 @@ static void _rtl_pci_tx_isr(struct ieee80211_hw *hw, int prio) struct rtl_tx_desc *entry = &ring->desc[ring->idx]; struct sk_buff *skb; struct ieee80211_tx_info *info; + __le16 fc; + u8 tid; u8 own = (u8) rtlpriv->cfg->ops->get_desc((u8 *) entry, true, HW_DESC_OWN); @@ -455,11 +620,15 @@ static void _rtl_pci_tx_isr(struct ieee80211_hw *hw, int prio) skb = __skb_dequeue(&ring->queue); pci_unmap_single(rtlpci->pdev, - rtlpriv->cfg->ops-> + le32_to_cpu(rtlpriv->cfg->ops-> get_desc((u8 *) entry, true, - HW_DESC_TXBUFF_ADDR), + HW_DESC_TXBUFF_ADDR)), skb->len, PCI_DMA_TODEVICE); + /* remove early mode header */ + if (rtlpriv->rtlhal.earlymode_enable) + skb_pull(skb, EM_HDR_LEN); + RT_TRACE(rtlpriv, (COMP_INTR | COMP_SEND), DBG_TRACE, ("new ring->idx:%d, " "free: skb_queue_len:%d, free: seq:%x\n", @@ -467,6 +636,30 @@ static void _rtl_pci_tx_isr(struct ieee80211_hw *hw, int prio) skb_queue_len(&ring->queue), *(u16 *) (skb->data + 22))); + if (prio == TXCMD_QUEUE) { + dev_kfree_skb(skb); + goto tx_status_ok; + + } + + /* for sw LPS, just after NULL skb send out, we can + * sure AP kown we are sleeped, our we should not let + * rf to sleep*/ + fc = rtl_get_fc(skb); + if (ieee80211_is_nullfunc(fc)) { + if (ieee80211_has_pm(fc)) { + rtlpriv->mac80211.offchan_deley = true; + rtlpriv->psc.state_inap = 1; + } else { + rtlpriv->psc.state_inap = 0; + } + } + + /* update tid tx pkt num */ + tid = rtl_get_tid(skb); + if (tid <= 7) + rtlpriv->link_info.tidtx_inperiod[tid]++; + info = IEEE80211_SKB_CB(skb); ieee80211_tx_info_clear_status(info); @@ -489,7 +682,7 @@ static void _rtl_pci_tx_isr(struct ieee80211_hw *hw, int prio) skb_get_queue_mapping (skb)); } - +tx_status_ok: skb = NULL; } @@ -561,23 +754,21 @@ static void _rtl_pci_rx_interrupt(struct ieee80211_hw *hw) *skb_trim(skb, skb->len - 4); */ - hdr = (struct ieee80211_hdr *)(skb->data); - fc = hdr->frame_control; + hdr = rtl_get_hdr(skb); + fc = rtl_get_fc(skb); - if (!stats.crc) { + if (!stats.crc || !stats.hwerror) { memcpy(IEEE80211_SKB_RXCB(skb), &rx_status, sizeof(rx_status)); - if (is_broadcast_ether_addr(hdr->addr1)) + if (is_broadcast_ether_addr(hdr->addr1)) { ;/*TODO*/ - else { - if (is_multicast_ether_addr(hdr->addr1)) - ;/*TODO*/ - else { - unicast = true; - rtlpriv->stats.rxbytesunicast += - skb->len; - } + } else if (is_multicast_ether_addr(hdr->addr1)) { + ;/*TODO*/ + } else { + unicast = true; + rtlpriv->stats.rxbytesunicast += + skb->len; } rtl_is_special_data(hw, skb, false); @@ -591,28 +782,38 @@ static void _rtl_pci_rx_interrupt(struct ieee80211_hw *hw) num_rx_inperiod++; } - if (unlikely(!rtl_action_proc(hw, skb, - false))) { + /* for sw lps */ + rtl_swlps_beacon(hw, (void *)skb->data, + skb->len); + rtl_recognize_peer(hw, (void *)skb->data, + skb->len); + if ((rtlpriv->mac80211.opmode == + NL80211_IFTYPE_AP) && + (rtlpriv->rtlhal.current_bandtype == + BAND_ON_2_4G) && + (ieee80211_is_beacon(fc) || + ieee80211_is_probe_resp(fc))) { dev_kfree_skb_any(skb); } else { - struct sk_buff *uskb = NULL; - u8 *pdata; - uskb = dev_alloc_skb(skb->len + 128); - if (!uskb) { - RT_TRACE(rtlpriv, - (COMP_INTR | COMP_RECV), - DBG_EMERG, - ("can't alloc rx skb\n")); - goto done; + if (unlikely(!rtl_action_proc(hw, skb, + false))) { + dev_kfree_skb_any(skb); + } else { + struct sk_buff *uskb = NULL; + u8 *pdata; + uskb = dev_alloc_skb(skb->len + + 128); + memcpy(IEEE80211_SKB_RXCB(uskb), + &rx_status, + sizeof(rx_status)); + pdata = (u8 *)skb_put(uskb, + skb->len); + memcpy(pdata, skb->data, + skb->len); + dev_kfree_skb_any(skb); + + ieee80211_rx_irqsafe(hw, uskb); } - memcpy(IEEE80211_SKB_RXCB(uskb), - &rx_status, - sizeof(rx_status)); - pdata = (u8 *)skb_put(uskb, skb->len); - memcpy(pdata, skb->data, skb->len); - dev_kfree_skb_any(skb); - - ieee80211_rx_irqsafe(hw, uskb); } } else { dev_kfree_skb_any(skb); @@ -627,7 +828,7 @@ static void _rtl_pci_rx_interrupt(struct ieee80211_hw *hw) new_skb = dev_alloc_skb(rtlpci->rxbuffersize); if (unlikely(!new_skb)) { RT_TRACE(rtlpriv, (COMP_INTR | COMP_RECV), - DBG_EMERG, + DBG_DMESG, ("can't alloc skb for rx\n")); goto done; } @@ -645,7 +846,7 @@ static void _rtl_pci_rx_interrupt(struct ieee80211_hw *hw) } done: - bufferaddress = (u32)(*((dma_addr_t *) skb->cb)); + bufferaddress = cpu_to_le32(*((dma_addr_t *)skb->cb)); tmp_one = 1; rtlpriv->cfg->ops->set_desc((u8 *) pdesc, false, HW_DESC_RXBUFF_ADDR, @@ -669,11 +870,81 @@ done: } +void _rtl_pci_tx_interrupt(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); + int prio; + + for (prio = 0; prio < RTL_PCI_MAX_TX_QUEUE_COUNT; prio++) { + struct rtl8192_tx_ring *ring = &rtlpci->tx_ring[prio]; + + while (skb_queue_len(&ring->queue)) { + struct rtl_tx_desc *entry = &ring->desc[ring->idx]; + struct sk_buff *skb; + struct ieee80211_tx_info *info; + u8 own; + + /* + *beacon packet will only use the first + *descriptor defautly, and the own may not + *be cleared by the hardware, and + *beacon will free in prepare beacon + */ + if (prio == BEACON_QUEUE || prio == TXCMD_QUEUE || + prio == HCCA_QUEUE) + break; + + own = (u8) rtlpriv->cfg->ops->get_desc((u8 *) entry, + true, + HW_DESC_OWN); + + if (own) + break; + + skb = __skb_dequeue(&ring->queue); + pci_unmap_single(rtlpci->pdev, + le32_to_cpu(rtlpriv->cfg->ops-> + get_desc((u8 *) entry, + true, + HW_DESC_TXBUFF_ADDR)), + skb->len, PCI_DMA_TODEVICE); + + ring->idx = (ring->idx + 1) % ring->entries; + + info = IEEE80211_SKB_CB(skb); + ieee80211_tx_info_clear_status(info); + + info->flags |= IEEE80211_TX_STAT_ACK; + /*info->status.rates[0].count = 1; */ + + ieee80211_tx_status_irqsafe(hw, skb); + + if ((ring->entries - skb_queue_len(&ring->queue)) + == 2 && prio != BEACON_QUEUE) { + RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, + ("more desc left, wake " + "skb_queue@%d,ring->idx = %d," + "skb_queue_len = 0x%d\n", + prio, ring->idx, + skb_queue_len(&ring->queue))); + + ieee80211_wake_queue(hw, + skb_get_queue_mapping + (skb)); + } + + skb = NULL; + } + } +} + static irqreturn_t _rtl_pci_interrupt(int irq, void *dev_id) { struct ieee80211_hw *hw = dev_id; struct rtl_priv *rtlpriv = rtl_priv(hw); struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); + struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); unsigned long flags; u32 inta = 0; u32 intb = 0; @@ -760,23 +1031,36 @@ static irqreturn_t _rtl_pci_interrupt(int irq, void *dev_id) _rtl_pci_tx_isr(hw, VO_QUEUE); } + if (rtlhal->hw_type == HARDWARE_TYPE_RTL8192SE) { + if (inta & rtlpriv->cfg->maps[RTL_IMR_COMDOK]) { + rtlpriv->link_info.num_tx_inperiod++; + + RT_TRACE(rtlpriv, COMP_INTR, DBG_TRACE, + ("CMD TX OK interrupt!\n")); + _rtl_pci_tx_isr(hw, TXCMD_QUEUE); + } + } + /*<2> Rx related */ if (inta & rtlpriv->cfg->maps[RTL_IMR_ROK]) { RT_TRACE(rtlpriv, COMP_INTR, DBG_TRACE, ("Rx ok interrupt!\n")); - tasklet_schedule(&rtlpriv->works.irq_tasklet); + _rtl_pci_rx_interrupt(hw); } if (unlikely(inta & rtlpriv->cfg->maps[RTL_IMR_RDU])) { RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING, ("rx descriptor unavailable!\n")); - tasklet_schedule(&rtlpriv->works.irq_tasklet); + _rtl_pci_rx_interrupt(hw); } if (unlikely(inta & rtlpriv->cfg->maps[RTL_IMR_RXFOVW])) { RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING, ("rx overflow !\n")); - tasklet_schedule(&rtlpriv->works.irq_tasklet); + _rtl_pci_rx_interrupt(hw); } + if (rtlpriv->rtlhal.earlymode_enable) + tasklet_schedule(&rtlpriv->works.irq_tasklet); + spin_unlock_irqrestore(&rtlpriv->locks.irq_th_lock, flags); return IRQ_HANDLED; @@ -787,7 +1071,7 @@ done: static void _rtl_pci_irq_tasklet(struct ieee80211_hw *hw) { - _rtl_pci_rx_interrupt(hw); + _rtl_pci_tx_chk_waitq(hw); } static void _rtl_pci_prepare_bcn_tasklet(struct ieee80211_hw *hw) @@ -795,14 +1079,15 @@ static void _rtl_pci_prepare_bcn_tasklet(struct ieee80211_hw *hw) struct rtl_priv *rtlpriv = rtl_priv(hw); struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); - struct rtl8192_tx_ring *ring = &rtlpci->tx_ring[BEACON_QUEUE]; + struct rtl8192_tx_ring *ring = NULL; struct ieee80211_hdr *hdr = NULL; struct ieee80211_tx_info *info = NULL; struct sk_buff *pskb = NULL; struct rtl_tx_desc *pdesc = NULL; - unsigned int queue_index; + struct rtl_tcb_desc tcb_desc; u8 temp_one = 1; + memset(&tcb_desc, 0, sizeof(struct rtl_tcb_desc)); ring = &rtlpci->tx_ring[BEACON_QUEUE]; pskb = __skb_dequeue(&ring->queue); if (pskb) @@ -812,14 +1097,13 @@ static void _rtl_pci_prepare_bcn_tasklet(struct ieee80211_hw *hw) pskb = ieee80211_beacon_get(hw, mac->vif); if (pskb == NULL) return; - hdr = (struct ieee80211_hdr *)(pskb->data); + hdr = rtl_get_hdr(pskb); info = IEEE80211_SKB_CB(pskb); - - queue_index = BEACON_QUEUE; - pdesc = &ring->desc[0]; +#if 0 /* temporary */ rtlpriv->cfg->ops->fill_tx_desc(hw, hdr, (u8 *) pdesc, - info, pskb, queue_index); + info, pskb, BEACON_QUEUE, &tcb_desc); +#endif __skb_queue_tail(&ring->queue, pskb); @@ -861,7 +1145,6 @@ static void _rtl_pci_init_struct(struct ieee80211_hw *hw, struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); - struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); rtlpci->up_first_time = true; rtlpci->being_init_adapter = false; @@ -869,31 +1152,20 @@ static void _rtl_pci_init_struct(struct ieee80211_hw *hw, rtlhal->hw = hw; rtlpci->pdev = pdev; - ppsc->inactiveps = false; - ppsc->leisure_ps = true; - ppsc->fwctrl_lps = true; - ppsc->reg_fwctrl_lps = 3; - ppsc->reg_max_lps_awakeintvl = 5; - - if (ppsc->reg_fwctrl_lps == 1) - ppsc->fwctrl_psmode = FW_PS_MIN_MODE; - else if (ppsc->reg_fwctrl_lps == 2) - ppsc->fwctrl_psmode = FW_PS_MAX_MODE; - else if (ppsc->reg_fwctrl_lps == 3) - ppsc->fwctrl_psmode = FW_PS_DTIM_MODE; - /*Tx/Rx related var */ _rtl_pci_init_trx_var(hw); - /*IBSS*/ mac->beacon_interval = 100; + /*IBSS*/ mac->beacon_interval = 100; - /*AMPDU*/ mac->min_space_cfg = 0; + /*AMPDU*/ + mac->min_space_cfg = 0; mac->max_mss_density = 0; /*set sane AMPDU defaults */ mac->current_ampdu_density = 7; mac->current_ampdu_factor = 3; - /*QOS*/ rtlpci->acm_method = eAcmWay2_SW; + /*QOS*/ + rtlpci->acm_method = eAcmWay2_SW; /*task */ tasklet_init(&rtlpriv->works.irq_tasklet, @@ -934,8 +1206,9 @@ static int _rtl_pci_init_tx_ring(struct ieee80211_hw *hw, ("queue:%d, ring_addr:%p\n", prio, ring)); for (i = 0; i < entries; i++) { - nextdescaddress = (u32) dma + ((i + 1) % entries) * - sizeof(*ring); + nextdescaddress = cpu_to_le32((u32) dma + + ((i + 11) % entries) * + sizeof(*ring)); rtlpriv->cfg->ops->set_desc((u8 *)&(ring[i]), true, HW_DESC_TX_NEXTDESC_ADDR, @@ -999,7 +1272,7 @@ static int _rtl_pci_init_rx_ring(struct ieee80211_hw *hw) rtlpci->rxbuffersize, PCI_DMA_FROMDEVICE); - bufferaddress = (u32)(*((dma_addr_t *)skb->cb)); + bufferaddress = cpu_to_le32(*((dma_addr_t *)skb->cb)); rtlpriv->cfg->ops->set_desc((u8 *)entry, false, HW_DESC_RXBUFF_ADDR, (u8 *)&bufferaddress); @@ -1030,9 +1303,9 @@ static void _rtl_pci_free_tx_ring(struct ieee80211_hw *hw, struct sk_buff *skb = __skb_dequeue(&ring->queue); pci_unmap_single(rtlpci->pdev, - rtlpriv->cfg-> + le32_to_cpu(rtlpriv->cfg-> ops->get_desc((u8 *) entry, true, - HW_DESC_TXBUFF_ADDR), + HW_DESC_TXBUFF_ADDR)), skb->len, PCI_DMA_TODEVICE); kfree_skb(skb); ring->idx = (ring->idx + 1) % ring->entries; @@ -1164,11 +1437,11 @@ int rtl_pci_reset_trx_ring(struct ieee80211_hw *hw) __skb_dequeue(&ring->queue); pci_unmap_single(rtlpci->pdev, - rtlpriv->cfg->ops-> + le32_to_cpu(rtlpriv->cfg->ops-> get_desc((u8 *) entry, true, - HW_DESC_TXBUFF_ADDR), + HW_DESC_TXBUFF_ADDR)), skb->len, PCI_DMA_TODEVICE); kfree_skb(skb); ring->idx = (ring->idx + 1) % ring->entries; @@ -1182,70 +1455,73 @@ int rtl_pci_reset_trx_ring(struct ieee80211_hw *hw) return 0; } -static unsigned int _rtl_mac_to_hwqueue(__le16 fc, - unsigned int mac80211_queue_index) +static bool rtl_pci_tx_chk_waitq_insert(struct ieee80211_hw *hw, + struct sk_buff *skb) { - unsigned int hw_queue_index; - - if (unlikely(ieee80211_is_beacon(fc))) { - hw_queue_index = BEACON_QUEUE; - goto out; - } - - if (ieee80211_is_mgmt(fc)) { - hw_queue_index = MGNT_QUEUE; - goto out; - } - - switch (mac80211_queue_index) { - case 0: - hw_queue_index = VO_QUEUE; - break; - case 1: - hw_queue_index = VI_QUEUE; - break; - case 2: - hw_queue_index = BE_QUEUE;; - break; - case 3: - hw_queue_index = BK_QUEUE; - break; - default: - hw_queue_index = BE_QUEUE; - RT_ASSERT(false, ("QSLT_BE queue, skb_queue:%d\n", - mac80211_queue_index)); - break; - } + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); + struct ieee80211_sta *sta = info->control.sta; + struct rtl_sta_info *sta_entry = NULL; + u8 tid = rtl_get_tid(skb); + + if (!sta) + return false; + sta_entry = (struct rtl_sta_info *)sta->drv_priv; + + if (!rtlpriv->rtlhal.earlymode_enable) + return false; + if (sta_entry->tids[tid].agg.agg_state != RTL_AGG_OPERATIONAL) + return false; + if (_rtl_mac_to_hwqueue(hw, skb) > VO_QUEUE) + return false; + if (tid > 7) + return false; + + /* maybe every tid should be checked */ + if (!rtlpriv->link_info.higher_busytxtraffic[tid]) + return false; + + spin_lock_bh(&rtlpriv->locks.waitq_lock); + skb_queue_tail(&rtlpriv->mac80211.skb_waitq[tid], skb); + spin_unlock_bh(&rtlpriv->locks.waitq_lock); -out: - return hw_queue_index; + return true; } -static int rtl_pci_tx(struct ieee80211_hw *hw, struct sk_buff *skb) +int rtl_pci_tx(struct ieee80211_hw *hw, struct sk_buff *skb, + struct rtl_tcb_desc *ptcb_desc) { struct rtl_priv *rtlpriv = rtl_priv(hw); - struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); + struct rtl_sta_info *sta_entry = NULL; struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); + struct ieee80211_sta *sta = info->control.sta; struct rtl8192_tx_ring *ring; struct rtl_tx_desc *pdesc; u8 idx; - unsigned int queue_index, hw_queue; + u8 hw_queue = _rtl_mac_to_hwqueue(hw, skb); unsigned long flags; - struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)(skb->data); - __le16 fc = hdr->frame_control; + struct ieee80211_hdr *hdr = rtl_get_hdr(skb); + __le16 fc = rtl_get_fc(skb); u8 *pda_addr = hdr->addr1; struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); /*ssn */ - u8 *qc = NULL; u8 tid = 0; u16 seq_number = 0; u8 own; u8 temp_one = 1; - rtl_action_proc(hw, skb, true); + if (ieee80211_is_auth(fc)) { + RT_TRACE(rtlpriv, COMP_SEND, DBG_DMESG, ("MAC80211_LINKING\n")); + rtl_ips_nic_on(hw); + } + + if (rtlpriv->psc.sw_ps_enabled) { + if (ieee80211_is_data(fc) && !ieee80211_is_nullfunc(fc) && + !ieee80211_has_pm(fc)) + hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_PM); + } - queue_index = skb_get_queue_mapping(skb); - hw_queue = _rtl_mac_to_hwqueue(fc, queue_index); + rtl_action_proc(hw, skb, true); if (is_multicast_ether_addr(pda_addr)) rtlpriv->stats.txbytesmulticast += skb->len; @@ -1255,7 +1531,6 @@ static int rtl_pci_tx(struct ieee80211_hw *hw, struct sk_buff *skb) rtlpriv->stats.txbytesunicast += skb->len; spin_lock_irqsave(&rtlpriv->locks.irq_th_lock, flags); - ring = &rtlpci->tx_ring[hw_queue]; if (hw_queue != BEACON_QUEUE) idx = (ring->idx + skb_queue_len(&ring->queue)) % @@ -1278,43 +1553,32 @@ static int rtl_pci_tx(struct ieee80211_hw *hw, struct sk_buff *skb) return skb->len; } - /* - *if(ieee80211_is_nullfunc(fc)) { - * spin_unlock_irqrestore(&rtlpriv->locks.irq_th_lock, flags); - * return 1; - *} - */ - if (ieee80211_is_data_qos(fc)) { - qc = ieee80211_get_qos_ctl(hdr); - tid = qc[0] & IEEE80211_QOS_CTL_TID_MASK; - - seq_number = mac->tids[tid].seq_number; - seq_number &= IEEE80211_SCTL_SEQ; - /* - *hdr->seq_ctrl = hdr->seq_ctrl & - *cpu_to_le16(IEEE80211_SCTL_FRAG); - *hdr->seq_ctrl |= cpu_to_le16(seq_number); - */ - - seq_number += 1; + tid = rtl_get_tid(skb); + if (sta) { + sta_entry = (struct rtl_sta_info *)sta->drv_priv; + seq_number = (le16_to_cpu(hdr->seq_ctrl) & + IEEE80211_SCTL_SEQ) >> 4; + seq_number += 1; + + if (!ieee80211_has_morefrags(hdr->frame_control)) + sta_entry->tids[tid].seq_number = seq_number; + } } if (ieee80211_is_data(fc)) rtlpriv->cfg->ops->led_control(hw, LED_CTL_TX); - rtlpriv->cfg->ops->fill_tx_desc(hw, hdr, (u8 *) pdesc, - info, skb, hw_queue); +#if 0 /* temporary */ + rtlpriv->cfg->ops->fill_tx_desc(hw, hdr, (u8 *)pdesc, + info, skb, hw_queue, ptcb_desc); +#endif __skb_queue_tail(&ring->queue, skb); - rtlpriv->cfg->ops->set_desc((u8 *) pdesc, true, + rtlpriv->cfg->ops->set_desc((u8 *)pdesc, true, HW_DESC_OWN, (u8 *)&temp_one); - if (!ieee80211_has_morefrags(hdr->frame_control)) { - if (qc) - mac->tids[tid].seq_number = seq_number; - } if ((ring->entries - skb_queue_len(&ring->queue)) < 2 && hw_queue != BEACON_QUEUE) { @@ -1336,7 +1600,36 @@ static int rtl_pci_tx(struct ieee80211_hw *hw, struct sk_buff *skb) return 0; } -static void rtl_pci_deinit(struct ieee80211_hw *hw) +static void rtl_pci_flush(struct ieee80211_hw *hw, bool drop) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_pci_priv *pcipriv = rtl_pcipriv(hw); + struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); + u16 i = 0; + int queue_id; + struct rtl8192_tx_ring *ring; + + for (queue_id = RTL_PCI_MAX_TX_QUEUE_COUNT - 1; queue_id >= 0;) { + u32 queue_len; + ring = &pcipriv->dev.tx_ring[queue_id]; + queue_len = skb_queue_len(&ring->queue); + if (queue_len == 0 || queue_id == BEACON_QUEUE || + queue_id == TXCMD_QUEUE) { + queue_id--; + continue; + } else { + msleep(20); + i++; + } + + /* we just wait 1s for all queues */ + if (rtlpriv->psc.rfpwr_state == ERFOFF || + is_hal_stop(rtlhal) || i >= 200) + return; + } +} + +void rtl_pci_deinit(struct ieee80211_hw *hw) { struct rtl_priv *rtlpriv = rtl_priv(hw); struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); @@ -1351,7 +1644,7 @@ static void rtl_pci_deinit(struct ieee80211_hw *hw) } -static int rtl_pci_init(struct ieee80211_hw *hw, struct pci_dev *pdev) +int rtl_pci_init(struct ieee80211_hw *hw, struct pci_dev *pdev) { struct rtl_priv *rtlpriv = rtl_priv(hw); int err; @@ -1368,7 +1661,7 @@ static int rtl_pci_init(struct ieee80211_hw *hw, struct pci_dev *pdev) return 1; } -static int rtl_pci_start(struct ieee80211_hw *hw) +int rtl_pci_start(struct ieee80211_hw *hw) { struct rtl_priv *rtlpriv = rtl_priv(hw); struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); @@ -1403,7 +1696,7 @@ static int rtl_pci_start(struct ieee80211_hw *hw) return 0; } -static void rtl_pci_stop(struct ieee80211_hw *hw) +void rtl_pci_stop(struct ieee80211_hw *hw) { struct rtl_priv *rtlpriv = rtl_priv(hw); struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); @@ -1454,11 +1747,13 @@ static bool _rtl_pci_find_adapter(struct pci_dev *pdev, struct pci_dev *bridge_pdev = pdev->bus->self; u16 venderid; u16 deviceid; + u8 revisionid; u16 irqline; u8 tmp; venderid = pdev->vendor; deviceid = pdev->device; + pci_read_config_byte(pdev, 0x8, &revisionid); pci_read_config_word(pdev, 0x3C, &irqline); if (deviceid == RTL_PCI_8192_DID || @@ -1469,7 +1764,7 @@ static bool _rtl_pci_find_adapter(struct pci_dev *pdev, deviceid == RTL_PCI_8173_DID || deviceid == RTL_PCI_8172_DID || deviceid == RTL_PCI_8171_DID) { - switch (pdev->revision) { + switch (revisionid) { case RTL_PCI_REVISION_ID_8192PCIE: RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, ("8192 PCI-E is found - " @@ -1498,6 +1793,12 @@ static bool _rtl_pci_find_adapter(struct pci_dev *pdev, RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, ("8192C PCI-E is found - " "vid/did=%x/%x\n", venderid, deviceid)); + } else if (deviceid == RTL_PCI_8192DE_DID || + deviceid == RTL_PCI_8192DE_DID2) { + rtlhal->hw_type = HARDWARE_TYPE_RTL8192DE; + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, + ("8192D PCI-E is found - " + "vid/did=%x/%x\n", venderid, deviceid)); } else { RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING, ("Err: Unknown device -" @@ -1506,6 +1807,25 @@ static bool _rtl_pci_find_adapter(struct pci_dev *pdev, rtlhal->hw_type = RTL_DEFAULT_HARDWARE_TYPE; } + if (rtlhal->hw_type == HARDWARE_TYPE_RTL8192DE) { + if (revisionid == 0 || revisionid == 1) { + if (revisionid == 0) { + RT_TRACE(rtlpriv, COMP_INIT, + DBG_LOUD, ("Find 92DE MAC0.\n")); + rtlhal->interfaceindex = 0; + } else if (revisionid == 1) { + RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, + ("Find 92DE MAC1.\n")); + rtlhal->interfaceindex = 1; + } + } else { + RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, + ("Unknown device - " + "VendorID/DeviceID=%x/%x, Revision=%x\n", + venderid, deviceid, revisionid)); + rtlhal->interfaceindex = 0; + } + } /*find bus info */ pcipriv->ndis_adapter.busnumber = pdev->bus->number; pcipriv->ndis_adapter.devnumber = PCI_SLOT(pdev->devfn); @@ -1531,12 +1851,12 @@ static bool _rtl_pci_find_adapter(struct pci_dev *pdev, PCI_SLOT(bridge_pdev->devfn); pcipriv->ndis_adapter.pcibridge_funcnum = PCI_FUNC(bridge_pdev->devfn); - pcipriv->ndis_adapter.pcibridge_pciehdr_offset = - pci_pcie_cap(bridge_pdev); pcipriv->ndis_adapter.pcicfg_addrport = (pcipriv->ndis_adapter.pcibridge_busnum << 16) | (pcipriv->ndis_adapter.pcibridge_devnum << 11) | (pcipriv->ndis_adapter.pcibridge_funcnum << 8) | (1 << 31); + pcipriv->ndis_adapter.pcibridge_pciehdr_offset = + pci_pcie_cap(bridge_pdev); pcipriv->ndis_adapter.num4bytes = (pcipriv->ndis_adapter.pcibridge_pciehdr_offset + 0x10) / 4; @@ -1619,6 +1939,11 @@ int __devinit rtl_pci_probe(struct pci_dev *pdev, pcipriv = (void *)rtlpriv->priv; pcipriv->dev.pdev = pdev; + /* init cfg & intf_ops */ + rtlpriv->rtlhal.interface = INTF_PCI; + rtlpriv->cfg = (struct rtl_hal_cfg *)(id->driver_data); + rtlpriv->intf_ops = &rtl_pci_ops; + /* *init dbgp flags before all *other functions, because we will @@ -1636,13 +1961,14 @@ int __devinit rtl_pci_probe(struct pci_dev *pdev, return err; } - pmem_start = pci_resource_start(pdev, 2); - pmem_len = pci_resource_len(pdev, 2); - pmem_flags = pci_resource_flags(pdev, 2); + pmem_start = pci_resource_start(pdev, rtlpriv->cfg->bar_id); + pmem_len = pci_resource_len(pdev, rtlpriv->cfg->bar_id); + pmem_flags = pci_resource_flags(pdev, rtlpriv->cfg->bar_id); /*shared mem start */ rtlpriv->io.pci_mem_start = - (unsigned long)pci_iomap(pdev, 2, pmem_len); + (unsigned long)pci_iomap(pdev, + rtlpriv->cfg->bar_id, pmem_len); if (rtlpriv->io.pci_mem_start == 0) { RT_ASSERT(false, ("Can't map PCI mem\n")); goto fail2; @@ -1661,11 +1987,6 @@ int __devinit rtl_pci_probe(struct pci_dev *pdev, pci_write_config_byte(pdev, 0x04, 0x06); pci_write_config_byte(pdev, 0x04, 0x07); - /* init cfg & intf_ops */ - rtlpriv->rtlhal.interface = INTF_PCI; - rtlpriv->cfg = (struct rtl_hal_cfg *)(id->driver_data); - rtlpriv->intf_ops = &rtl_pci_ops; - /* find adapter */ _rtl_pci_find_adapter(pdev, hw); @@ -1783,8 +2104,6 @@ void rtl_pci_disconnect(struct pci_dev *pdev) rtl_pci_deinit(hw); rtl_deinit_core(hw); - if (rtlpriv->cfg->ops->deinit_sw_leds) - rtlpriv->cfg->ops->deinit_sw_leds(hw); _rtl_pci_io_handler_release(hw); rtlpriv->cfg->ops->deinit_sw_vars(hw); @@ -1799,6 +2118,9 @@ void rtl_pci_disconnect(struct pci_dev *pdev) } pci_disable_device(pdev); + + rtl_pci_disable_aspm(hw); + pci_set_drvdata(pdev, NULL); ieee80211_free_hw(hw); @@ -1822,10 +2144,15 @@ no need to call hw_disable here. ****************************************/ int rtl_pci_suspend(struct pci_dev *pdev, pm_message_t state) { + struct ieee80211_hw *hw = pci_get_drvdata(pdev); + struct rtl_priv *rtlpriv = rtl_priv(hw); + + rtlpriv->cfg->ops->hw_suspend(hw); + rtl_deinit_rfkill(hw); + pci_save_state(pdev); pci_disable_device(pdev); pci_set_power_state(pdev, PCI_D3hot); - return 0; } EXPORT_SYMBOL(rtl_pci_suspend); @@ -1833,6 +2160,8 @@ EXPORT_SYMBOL(rtl_pci_suspend); int rtl_pci_resume(struct pci_dev *pdev) { int ret; + struct ieee80211_hw *hw = pci_get_drvdata(pdev); + struct rtl_priv *rtlpriv = rtl_priv(hw); pci_set_power_state(pdev, PCI_D0); ret = pci_enable_device(pdev); @@ -1843,15 +2172,20 @@ int rtl_pci_resume(struct pci_dev *pdev) pci_restore_state(pdev); + rtlpriv->cfg->ops->hw_resume(hw); + rtl_init_rfkill(hw); return 0; } EXPORT_SYMBOL(rtl_pci_resume); struct rtl_intf_ops rtl_pci_ops = { + .read_efuse_byte = read_efuse_byte, .adapter_start = rtl_pci_start, .adapter_stop = rtl_pci_stop, .adapter_tx = rtl_pci_tx, + .flush = rtl_pci_flush, .reset_trx_ring = rtl_pci_reset_trx_ring, + .waitq_insert = rtl_pci_tx_chk_waitq_insert, .disable_aspm = rtl_pci_disable_aspm, .enable_aspm = rtl_pci_enable_aspm, diff --git a/drivers/net/wireless/rtlwifi/pci.h b/drivers/net/wireless/rtlwifi/pci.h index 12747b9..671b1f5 100644 --- a/drivers/net/wireless/rtlwifi/pci.h +++ b/drivers/net/wireless/rtlwifi/pci.h @@ -102,8 +102,8 @@ #define RTL_PCI_8191CE_DID 0x8177 /*8192ce */ #define RTL_PCI_8188CE_DID 0x8176 /*8192ce */ #define RTL_PCI_8192CU_DID 0x8191 /*8192ce */ -#define RTL_PCI_8192DE_DID 0x092D /*8192ce */ -#define RTL_PCI_8192DU_DID 0x092D /*8192ce */ +#define RTL_PCI_8192DE_DID 0x8193 /*8192de */ +#define RTL_PCI_8192DE_DID2 0x002B /*92DE*/ /*8192 support 16 pages of IO registers*/ #define RTL_MEM_MAPPED_IO_RANGE_8190PCI 0x1000 @@ -129,6 +129,11 @@ enum pci_bridge_vendor { PCI_BRIDGE_VENDOR_MAX, }; +struct rtl_pci_capabilities_header { + u8 capability_id; + u8 next; +}; + struct rtl_rx_desc { u32 dword[8]; } __packed; @@ -161,7 +166,9 @@ struct rtl_pci { bool driver_is_goingto_unload; bool up_first_time; + bool first_init; bool being_init_adapter; + bool init_ready; bool irq_enabled; /*Tx */ @@ -197,6 +204,9 @@ struct rtl_pci { /*QOS & EDCA */ enum acm_method acm_method; + + u16 shortretry_limit; + u16 longretry_limit; }; struct mp_adapter { @@ -227,6 +237,7 @@ struct rtl_pci_priv { struct rtl_pci dev; struct mp_adapter ndis_adapter; struct rtl_led_ctl ledctl; + struct bt_coexist_info bt_coexist; }; #define rtl_pcipriv(hw) (((struct rtl_pci_priv *)(rtl_priv(hw))->priv)) diff --git a/drivers/net/wireless/rtlwifi/ps.c b/drivers/net/wireless/rtlwifi/ps.c index 8618490..cb31aef 100644 --- a/drivers/net/wireless/rtlwifi/ps.c +++ b/drivers/net/wireless/rtlwifi/ps.c @@ -428,6 +428,10 @@ void rtl_swlps_rf_awake(struct ieee80211_hw *hw) { } +void rtl_swlps_beacon(struct ieee80211_hw *hw, void *data, unsigned int len) +{ +} + /*Enter the leisure power save mode.*/ void rtl_lps_enter(struct ieee80211_hw *hw) { -- cgit v0.10.2 From cc7dc0c4ff7c091fb70ff0436f7e3b557e0ac1c3 Mon Sep 17 00:00:00 2001 From: Chaoming_Li Date: Mon, 25 Apr 2011 12:53:14 -0500 Subject: rtlwifi: Convert ps routines for addition of rtl8192se and rtl8192de Convert ps routines for addition of RTL8192SE and RTL8192DE code Signed-off-by: Chaoming_Li Signed-off-by: Larry Finger Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/rtlwifi/ps.c b/drivers/net/wireless/rtlwifi/ps.c index cb31aef..2bb7119 100644 --- a/drivers/net/wireless/rtlwifi/ps.c +++ b/drivers/net/wireless/rtlwifi/ps.c @@ -36,7 +36,6 @@ bool rtl_ps_enable_nic(struct ieee80211_hw *hw) struct rtl_priv *rtlpriv = rtl_priv(hw); struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); - bool init_status = true; /*<1> reset trx ring */ if (rtlhal->interface == INTF_PCI) @@ -49,7 +48,6 @@ bool rtl_ps_enable_nic(struct ieee80211_hw *hw) /*<2> Enable Adapter */ rtlpriv->cfg->ops->hw_init(hw); RT_CLEAR_PS_LEVEL(ppsc, RT_RF_OFF_LEVL_HALT_NIC); - /*init_status = false; */ /*<3> Enable Interrupt */ rtlpriv->cfg->ops->enable_interrupt(hw); @@ -57,7 +55,7 @@ bool rtl_ps_enable_nic(struct ieee80211_hw *hw) /* */ rtl_watch_dog_timer_callback((unsigned long)hw); - return init_status; + return true; } EXPORT_SYMBOL(rtl_ps_enable_nic); @@ -192,12 +190,13 @@ static void _rtl_ps_inactive_ps(struct ieee80211_hw *hw) ppsc->swrf_processing = true; - if (ppsc->inactive_pwrstate == ERFON && rtlhal->interface == INTF_PCI) { + if (ppsc->inactive_pwrstate == ERFOFF && + rtlhal->interface == INTF_PCI) { if ((ppsc->reg_rfps_level & RT_RF_OFF_LEVL_ASPM) && - RT_IN_PS_LEVEL(ppsc, RT_RF_OFF_LEVL_ASPM) && + RT_IN_PS_LEVEL(ppsc, RT_PS_LEVEL_ASPM) && rtlhal->interface == INTF_PCI) { rtlpriv->intf_ops->disable_aspm(hw); - RT_CLEAR_PS_LEVEL(ppsc, RT_RF_OFF_LEVL_ASPM); + RT_CLEAR_PS_LEVEL(ppsc, RT_PS_LEVEL_ASPM); } } @@ -206,9 +205,10 @@ static void _rtl_ps_inactive_ps(struct ieee80211_hw *hw) if (ppsc->inactive_pwrstate == ERFOFF && rtlhal->interface == INTF_PCI) { - if (ppsc->reg_rfps_level & RT_RF_OFF_LEVL_ASPM) { + if (ppsc->reg_rfps_level & RT_RF_OFF_LEVL_ASPM && + !RT_IN_PS_LEVEL(ppsc, RT_PS_LEVEL_ASPM)) { rtlpriv->intf_ops->enable_aspm(hw); - RT_SET_PS_LEVEL(ppsc, RT_RF_OFF_LEVL_ASPM); + RT_SET_PS_LEVEL(ppsc, RT_PS_LEVEL_ASPM); } } @@ -232,6 +232,9 @@ void rtl_ips_nic_off_wq_callback(void *data) return; } + if (mac->link_state > MAC80211_NOLINK) + return; + if (is_hal_stop(rtlhal)) return; @@ -283,10 +286,14 @@ void rtl_ips_nic_off(struct ieee80211_hw *hw) void rtl_ips_nic_on(struct ieee80211_hw *hw) { struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); enum rf_pwrstate rtstate; unsigned long flags; + if (mac->opmode != NL80211_IFTYPE_STATION) + return; + spin_lock_irqsave(&rtlpriv->locks.ips_lock, flags); if (ppsc->inactiveps) { @@ -369,8 +376,7 @@ static void rtl_lps_set_psmode(struct ieee80211_hw *hw, u8 rt_psmode) * mode and set RPWM to turn RF on. */ - if ((ppsc->fwctrl_lps) && (ppsc->leisure_ps) && - ppsc->report_linked) { + if ((ppsc->fwctrl_lps) && ppsc->report_linked) { bool fw_current_inps; if (ppsc->dot11_psmode == EACTIVE) { RT_TRACE(rtlpriv, COMP_RF, DBG_DMESG, @@ -416,22 +422,6 @@ static void rtl_lps_set_psmode(struct ieee80211_hw *hw, u8 rt_psmode) } } -void rtl_swlps_rfon_wq_callback(void *data) -{ -} - -void rtl_swlps_wq_callback(void *data) -{ -} - -void rtl_swlps_rf_awake(struct ieee80211_hw *hw) -{ -} - -void rtl_swlps_beacon(struct ieee80211_hw *hw, void *data, unsigned int len) -{ -} - /*Enter the leisure power save mode.*/ void rtl_lps_enter(struct ieee80211_hw *hw) { @@ -440,7 +430,7 @@ void rtl_lps_enter(struct ieee80211_hw *hw) struct rtl_priv *rtlpriv = rtl_priv(hw); unsigned long flag; - if (!(ppsc->fwctrl_lps && ppsc->leisure_ps)) + if (!ppsc->fwctrl_lps) return; if (rtlpriv->sec.being_setkey) @@ -461,17 +451,16 @@ void rtl_lps_enter(struct ieee80211_hw *hw) spin_lock_irqsave(&rtlpriv->locks.lps_lock, flag); - if (ppsc->leisure_ps) { - /* Idle for a while if we connect to AP a while ago. */ - if (mac->cnt_after_linked >= 2) { - if (ppsc->dot11_psmode == EACTIVE) { - RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD, + /* Idle for a while if we connect to AP a while ago. */ + if (mac->cnt_after_linked >= 2) { + if (ppsc->dot11_psmode == EACTIVE) { + RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD, ("Enter 802.11 power save mode...\n")); - rtl_lps_set_psmode(hw, EAUTOPS); - } + rtl_lps_set_psmode(hw, EAUTOPS); } } + spin_unlock_irqrestore(&rtlpriv->locks.lps_lock, flag); } @@ -485,17 +474,17 @@ void rtl_lps_leave(struct ieee80211_hw *hw) spin_lock_irqsave(&rtlpriv->locks.lps_lock, flag); - if (ppsc->fwctrl_lps && ppsc->leisure_ps) { + if (ppsc->fwctrl_lps) { if (ppsc->dot11_psmode != EACTIVE) { /*FIX ME */ rtlpriv->cfg->ops->enable_interrupt(hw); if (ppsc->reg_rfps_level & RT_RF_LPS_LEVEL_ASPM && - RT_IN_PS_LEVEL(ppsc, RT_RF_LPS_LEVEL_ASPM) && + RT_IN_PS_LEVEL(ppsc, RT_PS_LEVEL_ASPM) && rtlhal->interface == INTF_PCI) { rtlpriv->intf_ops->disable_aspm(hw); - RT_CLEAR_PS_LEVEL(ppsc, RT_RF_LPS_LEVEL_ASPM); + RT_CLEAR_PS_LEVEL(ppsc, RT_PS_LEVEL_ASPM); } RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD, @@ -506,3 +495,214 @@ void rtl_lps_leave(struct ieee80211_hw *hw) } spin_unlock_irqrestore(&rtlpriv->locks.lps_lock, flag); } + +/* For sw LPS*/ +void rtl_swlps_beacon(struct ieee80211_hw *hw, void *data, unsigned int len) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); + struct ieee80211_hdr *hdr = (void *) data; + struct ieee80211_tim_ie *tim_ie; + u8 *tim; + u8 tim_len; + bool u_buffed; + bool m_buffed; + + if (mac->opmode != NL80211_IFTYPE_STATION) + return; + + if (!rtlpriv->psc.swctrl_lps) + return; + + if (rtlpriv->mac80211.link_state != MAC80211_LINKED) + return; + + if (!rtlpriv->psc.sw_ps_enabled) + return; + + if (rtlpriv->psc.fwctrl_lps) + return; + + if (likely(!(hw->conf.flags & IEEE80211_CONF_PS))) + return; + + /* check if this really is a beacon */ + if (!ieee80211_is_beacon(hdr->frame_control)) + return; + + /* min. beacon length + FCS_LEN */ + if (len <= 40 + FCS_LEN) + return; + + /* and only beacons from the associated BSSID, please */ + if (compare_ether_addr(hdr->addr3, rtlpriv->mac80211.bssid)) + return; + + rtlpriv->psc.last_beacon = jiffies; + + tim = rtl_find_ie(data, len - FCS_LEN, WLAN_EID_TIM); + if (!tim) + return; + + if (tim[1] < sizeof(*tim_ie)) + return; + + tim_len = tim[1]; + tim_ie = (struct ieee80211_tim_ie *) &tim[2]; + + if (!WARN_ON_ONCE(!hw->conf.ps_dtim_period)) + rtlpriv->psc.dtim_counter = tim_ie->dtim_count; + + /* Check whenever the PHY can be turned off again. */ + + /* 1. What about buffered unicast traffic for our AID? */ + u_buffed = ieee80211_check_tim(tim_ie, tim_len, + rtlpriv->mac80211.assoc_id); + + /* 2. Maybe the AP wants to send multicast/broadcast data? */ + m_buffed = tim_ie->bitmap_ctrl & 0x01; + rtlpriv->psc.multi_buffered = m_buffed; + + /* unicast will process by mac80211 through + * set ~IEEE80211_CONF_PS, So we just check + * multicast frames here */ + if (!m_buffed) { + /* back to low-power land. and delay is + * prevent null power save frame tx fail */ + queue_delayed_work(rtlpriv->works.rtl_wq, + &rtlpriv->works.ps_work, MSECS(5)); + } else { + RT_TRACE(rtlpriv, COMP_POWER, DBG_DMESG, ("u_bufferd: %x, " + "m_buffered: %x\n", u_buffed, m_buffed)); + } +} + +void rtl_swlps_rf_awake(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); + struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); + unsigned long flag; + + if (!rtlpriv->psc.swctrl_lps) + return; + if (mac->link_state != MAC80211_LINKED) + return; + + if (ppsc->reg_rfps_level & RT_RF_LPS_LEVEL_ASPM && + RT_IN_PS_LEVEL(ppsc, RT_PS_LEVEL_ASPM)) { + rtlpriv->intf_ops->disable_aspm(hw); + RT_CLEAR_PS_LEVEL(ppsc, RT_PS_LEVEL_ASPM); + } + + spin_lock_irqsave(&rtlpriv->locks.lps_lock, flag); + rtl_ps_set_rf_state(hw, ERFON, RF_CHANGE_BY_PS, false); + spin_unlock_irqrestore(&rtlpriv->locks.lps_lock, flag); +} + +void rtl_swlps_rfon_wq_callback(void *data) +{ + struct rtl_works *rtlworks = + container_of_dwork_rtl(data, struct rtl_works, ps_rfon_wq); + struct ieee80211_hw *hw = rtlworks->hw; + + rtl_swlps_rf_awake(hw); +} + +void rtl_swlps_rf_sleep(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); + struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); + unsigned long flag; + u8 sleep_intv; + + if (!rtlpriv->psc.sw_ps_enabled) + return; + + if ((rtlpriv->sec.being_setkey) || + (mac->opmode == NL80211_IFTYPE_ADHOC)) + return; + + /*sleep after linked 10s, to let DHCP and 4-way handshake ok enough!! */ + if ((mac->link_state != MAC80211_LINKED) || (mac->cnt_after_linked < 5)) + return; + + if (rtlpriv->link_info.busytraffic) + return; + + spin_lock_irqsave(&rtlpriv->locks.rf_ps_lock, flag); + if (rtlpriv->psc.rfchange_inprogress) { + spin_unlock_irqrestore(&rtlpriv->locks.rf_ps_lock, flag); + return; + } + spin_unlock_irqrestore(&rtlpriv->locks.rf_ps_lock, flag); + + spin_lock_irqsave(&rtlpriv->locks.lps_lock, flag); + rtl_ps_set_rf_state(hw, ERFSLEEP, RF_CHANGE_BY_PS, false); + spin_unlock_irqrestore(&rtlpriv->locks.lps_lock, flag); + + if (ppsc->reg_rfps_level & RT_RF_OFF_LEVL_ASPM && + !RT_IN_PS_LEVEL(ppsc, RT_PS_LEVEL_ASPM)) { + rtlpriv->intf_ops->enable_aspm(hw); + RT_SET_PS_LEVEL(ppsc, RT_PS_LEVEL_ASPM); + } + + /* here is power save alg, when this beacon is DTIM + * we will set sleep time to dtim_period * n; + * when this beacon is not DTIM, we will set sleep + * time to sleep_intv = rtlpriv->psc.dtim_counter or + * MAX_SW_LPS_SLEEP_INTV(default set to 5) */ + + if (rtlpriv->psc.dtim_counter == 0) { + if (hw->conf.ps_dtim_period == 1) + sleep_intv = hw->conf.ps_dtim_period * 2; + else + sleep_intv = hw->conf.ps_dtim_period; + } else { + sleep_intv = rtlpriv->psc.dtim_counter; + } + + if (sleep_intv > MAX_SW_LPS_SLEEP_INTV) + sleep_intv = MAX_SW_LPS_SLEEP_INTV; + + /* this print should always be dtim_conter = 0 & + * sleep = dtim_period, that meaons, we should + * awake before every dtim */ + RT_TRACE(rtlpriv, COMP_POWER, DBG_DMESG, + ("dtim_counter:%x will sleep :%d" + " beacon_intv\n", rtlpriv->psc.dtim_counter, sleep_intv)); + + /* we tested that 40ms is enough for sw & hw sw delay */ + queue_delayed_work(rtlpriv->works.rtl_wq, &rtlpriv->works.ps_rfon_wq, + MSECS(sleep_intv * mac->vif->bss_conf.beacon_int - 40)); +} + + +void rtl_swlps_wq_callback(void *data) +{ + struct rtl_works *rtlworks = container_of_dwork_rtl(data, + struct rtl_works, + ps_work); + struct ieee80211_hw *hw = rtlworks->hw; + struct rtl_priv *rtlpriv = rtl_priv(hw); + bool ps = false; + + ps = (hw->conf.flags & IEEE80211_CONF_PS); + + /* we can sleep after ps null send ok */ + if (rtlpriv->psc.state_inap) { + rtl_swlps_rf_sleep(hw); + + if (rtlpriv->psc.state && !ps) { + rtlpriv->psc.sleep_ms = jiffies_to_msecs(jiffies - + rtlpriv->psc.last_action); + } + + if (ps) + rtlpriv->psc.last_slept = jiffies; + + rtlpriv->psc.last_action = jiffies; + rtlpriv->psc.state = ps; + } +} diff --git a/drivers/net/wireless/rtlwifi/ps.h b/drivers/net/wireless/rtlwifi/ps.h index 36aa24d..e3bf898 100644 --- a/drivers/net/wireless/rtlwifi/ps.h +++ b/drivers/net/wireless/rtlwifi/ps.h @@ -30,6 +30,8 @@ #ifndef __REALTEK_RTL_PCI_PS_H__ #define __REALTEK_RTL_PCI_PS_H__ +#define MAX_SW_LPS_SLEEP_INTV 5 + bool rtl_ps_set_rf_state(struct ieee80211_hw *hw, enum rf_pwrstate state_toset, u32 changesource, bool protect_or_not); -- cgit v0.10.2 From c6a9de0823e6f1335c93594f7b904f345860dafc Mon Sep 17 00:00:00 2001 From: Chaoming_Li Date: Mon, 25 Apr 2011 12:53:19 -0500 Subject: rtlwifi: Convert rc routines for addition of rtl8192se and rtl8192de Convert rc routines for addition of RTL8192SE and RTL8192DE code Signed-off-by: Chaoming_Li Signed-off-by: Larry Finger Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/rtlwifi/rc.c b/drivers/net/wireless/rtlwifi/rc.c index 9163410..30da68a 100644 --- a/drivers/net/wireless/rtlwifi/rc.c +++ b/drivers/net/wireless/rtlwifi/rc.c @@ -38,17 +38,14 @@ *CCK11M or OFDM_54M based on wireless mode. */ static u8 _rtl_rc_get_highest_rix(struct rtl_priv *rtlpriv, + struct ieee80211_sta *sta, struct sk_buff *skb, bool not_data) { struct rtl_mac *rtlmac = rtl_mac(rtlpriv); - - /* - *mgt use 1M, although we have check it - *before this function use rate_control_send_low, - *we still check it here - */ - if (not_data) - return rtlpriv->cfg->maps[RTL_RC_CCK_RATE1M]; + struct rtl_hal *rtlhal = rtl_hal(rtlpriv); + struct rtl_phy *rtlphy = &(rtlpriv->phy); + struct rtl_sta_info *sta_entry = NULL; + u8 wireless_mode = 0; /* *this rate is no use for true rate, firmware @@ -57,35 +54,78 @@ static u8 _rtl_rc_get_highest_rix(struct rtl_priv *rtlpriv, *2.in rtl_get_tcb_desc when we check rate is * 1M we will not use FW rate but user rate. */ - if (rtl_is_special_data(rtlpriv->mac80211.hw, skb, true)) { - return rtlpriv->cfg->maps[RTL_RC_CCK_RATE1M]; + if (rtlmac->opmode == NL80211_IFTYPE_AP || + rtlmac->opmode == NL80211_IFTYPE_ADHOC) { + if (sta) { + sta_entry = (struct rtl_sta_info *) sta->drv_priv; + wireless_mode = sta_entry->wireless_mode; + } else { + return 0; + } + } else { + wireless_mode = rtlmac->mode; + } + + if (rtl_is_special_data(rtlpriv->mac80211.hw, skb, true) || + not_data) { + return 0; } else { - if (rtlmac->mode == WIRELESS_MODE_B) - return rtlpriv->cfg->maps[RTL_RC_CCK_RATE11M]; - else - return rtlpriv->cfg->maps[RTL_RC_OFDM_RATE54M]; + if (rtlhal->current_bandtype == BAND_ON_2_4G) { + if (wireless_mode == WIRELESS_MODE_B) { + return B_MODE_MAX_RIX; + } else if (wireless_mode == WIRELESS_MODE_G) { + return G_MODE_MAX_RIX; + } else { + if (get_rf_type(rtlphy) != RF_2T2R) + return N_MODE_MCS7_RIX; + else + return N_MODE_MCS15_RIX; + } + } else { + if (wireless_mode == WIRELESS_MODE_A) { + return A_MODE_MAX_RIX; + } else { + if (get_rf_type(rtlphy) != RF_2T2R) + return N_MODE_MCS7_RIX; + else + return N_MODE_MCS15_RIX; + } + } } } static void _rtl_rc_rate_set_series(struct rtl_priv *rtlpriv, + struct ieee80211_sta *sta, struct ieee80211_tx_rate *rate, struct ieee80211_tx_rate_control *txrc, - u8 tries, u8 rix, int rtsctsenable, + u8 tries, char rix, int rtsctsenable, bool not_data) { struct rtl_mac *mac = rtl_mac(rtlpriv); + u8 sgi_20 = 0, sgi_40 = 0; + if (sta) { + sgi_20 = sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_20; + sgi_40 = sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_40; + } rate->count = tries; - rate->idx = (rix > 0x2) ? rix : 0x2; + rate->idx = rix >= 0x00 ? rix : 0x00; if (!not_data) { if (txrc->short_preamble) rate->flags |= IEEE80211_TX_RC_USE_SHORT_PREAMBLE; - if (mac->bw_40) - rate->flags |= IEEE80211_TX_RC_40_MHZ_WIDTH; - if (mac->sgi_20 || mac->sgi_40) + if (mac->opmode == NL80211_IFTYPE_AP || + mac->opmode == NL80211_IFTYPE_ADHOC) { + if (sta && (sta->ht_cap.cap & + IEEE80211_HT_CAP_SUP_WIDTH_20_40)) + rate->flags |= IEEE80211_TX_RC_40_MHZ_WIDTH; + } else { + if (mac->bw_40) + rate->flags |= IEEE80211_TX_RC_40_MHZ_WIDTH; + } + if (sgi_20 || sgi_40) rate->flags |= IEEE80211_TX_RC_SHORT_GI; - if (mac->ht_enable) + if (sta && sta->ht_cap.ht_supported) rate->flags |= IEEE80211_TX_RC_MCS; } } @@ -97,39 +137,39 @@ static void rtl_get_rate(void *ppriv, struct ieee80211_sta *sta, struct sk_buff *skb = txrc->skb; struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); struct ieee80211_tx_rate *rates = tx_info->control.rates; - struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; - __le16 fc = hdr->frame_control; + __le16 fc = rtl_get_fc(skb); u8 try_per_rate, i, rix; bool not_data = !ieee80211_is_data(fc); if (rate_control_send_low(sta, priv_sta, txrc)) return; - rix = _rtl_rc_get_highest_rix(rtlpriv, skb, not_data); - + rix = _rtl_rc_get_highest_rix(rtlpriv, sta, skb, not_data); try_per_rate = 1; - _rtl_rc_rate_set_series(rtlpriv, &rates[0], txrc, + _rtl_rc_rate_set_series(rtlpriv, sta, &rates[0], txrc, try_per_rate, rix, 1, not_data); if (!not_data) { for (i = 1; i < 4; i++) - _rtl_rc_rate_set_series(rtlpriv, &rates[i], + _rtl_rc_rate_set_series(rtlpriv, sta, &rates[i], txrc, i, (rix - i), 1, not_data); } } -static bool _rtl_tx_aggr_check(struct rtl_priv *rtlpriv, u16 tid) +static bool _rtl_tx_aggr_check(struct rtl_priv *rtlpriv, + struct rtl_sta_info *sta_entry, u16 tid) { struct rtl_mac *mac = rtl_mac(rtlpriv); if (mac->act_scanning) return false; - if (mac->cnt_after_linked < 3) + if (mac->opmode == NL80211_IFTYPE_STATION && + mac->cnt_after_linked < 3) return false; - if (mac->tids[tid].agg.agg_state == RTL_AGG_OFF) + if (sta_entry->tids[tid].agg.agg_state == RTL_AGG_STOP) return true; return false; @@ -143,11 +183,9 @@ static void rtl_tx_status(void *ppriv, { struct rtl_priv *rtlpriv = ppriv; struct rtl_mac *mac = rtl_mac(rtlpriv); - struct ieee80211_hdr *hdr; - __le16 fc; - - hdr = (struct ieee80211_hdr *)skb->data; - fc = hdr->frame_control; + struct ieee80211_hdr *hdr = rtl_get_hdr(skb); + __le16 fc = rtl_get_fc(skb); + struct rtl_sta_info *sta_entry; if (!priv_sta || !ieee80211_is_data(fc)) return; @@ -159,17 +197,21 @@ static void rtl_tx_status(void *ppriv, || is_broadcast_ether_addr(ieee80211_get_DA(hdr))) return; - /* Check if aggregation has to be enabled for this tid */ - if (conf_is_ht(&mac->hw->conf) && - !(skb->protocol == cpu_to_be16(ETH_P_PAE))) { - if (ieee80211_is_data_qos(fc)) { - u8 *qc, tid; - - qc = ieee80211_get_qos_ctl(hdr); - tid = qc[0] & 0xf; - - if (_rtl_tx_aggr_check(rtlpriv, tid)) - ieee80211_start_tx_ba_session(sta, tid, 5000); + if (sta) { + /* Check if aggregation has to be enabled for this tid */ + sta_entry = (struct rtl_sta_info *) sta->drv_priv; + if ((sta->ht_cap.ht_supported == true) && + !(skb->protocol == cpu_to_be16(ETH_P_PAE))) { + if (ieee80211_is_data_qos(fc)) { + u8 tid = rtl_get_tid(skb); + if (_rtl_tx_aggr_check(rtlpriv, sta_entry, + tid)) { + sta_entry->tids[tid].agg.agg_state = + RTL_AGG_PROGRESS; + ieee80211_start_tx_ba_session(sta, + tid, 5000); + } + } } } } @@ -178,43 +220,6 @@ static void rtl_rate_init(void *ppriv, struct ieee80211_supported_band *sband, struct ieee80211_sta *sta, void *priv_sta) { - struct rtl_priv *rtlpriv = ppriv; - struct rtl_mac *mac = rtl_mac(rtlpriv); - u8 is_ht = conf_is_ht(&mac->hw->conf); - - if ((mac->opmode == NL80211_IFTYPE_STATION) || - (mac->opmode == NL80211_IFTYPE_MESH_POINT) || - (mac->opmode == NL80211_IFTYPE_ADHOC)) { - - switch (sband->band) { - case IEEE80211_BAND_2GHZ: - rtlpriv->rate_priv->cur_ratetab_idx = - RATR_INX_WIRELESS_G; - if (is_ht) - rtlpriv->rate_priv->cur_ratetab_idx = - RATR_INX_WIRELESS_NGB; - break; - case IEEE80211_BAND_5GHZ: - rtlpriv->rate_priv->cur_ratetab_idx = - RATR_INX_WIRELESS_A; - if (is_ht) - rtlpriv->rate_priv->cur_ratetab_idx = - RATR_INX_WIRELESS_NGB; - break; - default: - RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING, - ("Invalid band\n")); - rtlpriv->rate_priv->cur_ratetab_idx = - RATR_INX_WIRELESS_NGB; - break; - } - - RT_TRACE(rtlpriv, COMP_RATE, DBG_DMESG, - ("Choosing rate table index: %d\n", - rtlpriv->rate_priv->cur_ratetab_idx)); - - } - } static void rtl_rate_update(void *ppriv, @@ -223,49 +228,6 @@ static void rtl_rate_update(void *ppriv, u32 changed, enum nl80211_channel_type oper_chan_type) { - struct rtl_priv *rtlpriv = ppriv; - struct rtl_mac *mac = rtl_mac(rtlpriv); - struct rtl_hal *rtlhal = rtl_hal(rtlpriv); - bool oper_cw40 = false, oper_sgi40; - bool local_cw40 = mac->bw_40; - bool local_sgi40 = mac->sgi_40; - u8 is_ht = conf_is_ht(&mac->hw->conf); - - if (changed & IEEE80211_RC_HT_CHANGED) { - if (mac->opmode != NL80211_IFTYPE_STATION) - return; - - if (rtlhal->hw->conf.channel_type == NL80211_CHAN_HT40MINUS || - rtlhal->hw->conf.channel_type == NL80211_CHAN_HT40PLUS) - oper_cw40 = true; - - oper_sgi40 = mac->sgi_40; - - if ((local_cw40 != oper_cw40) || (local_sgi40 != oper_sgi40)) { - switch (sband->band) { - case IEEE80211_BAND_2GHZ: - rtlpriv->rate_priv->cur_ratetab_idx = - RATR_INX_WIRELESS_G; - if (is_ht) - rtlpriv->rate_priv->cur_ratetab_idx = - RATR_INX_WIRELESS_NGB; - break; - case IEEE80211_BAND_5GHZ: - rtlpriv->rate_priv->cur_ratetab_idx = - RATR_INX_WIRELESS_A; - if (is_ht) - rtlpriv->rate_priv->cur_ratetab_idx = - RATR_INX_WIRELESS_NGB; - break; - default: - RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, - ("Invalid band\n")); - rtlpriv->rate_priv->cur_ratetab_idx = - RATR_INX_WIRELESS_NGB; - break; - } - } - } } static void *rtl_rate_alloc(struct ieee80211_hw *hw, diff --git a/drivers/net/wireless/rtlwifi/rc.h b/drivers/net/wireless/rtlwifi/rc.h index b4667c0..4afa2c2 100644 --- a/drivers/net/wireless/rtlwifi/rc.h +++ b/drivers/net/wireless/rtlwifi/rc.h @@ -30,8 +30,15 @@ #ifndef __RTL_RC_H__ #define __RTL_RC_H__ +#define B_MODE_MAX_RIX 3 +#define G_MODE_MAX_RIX 11 +#define A_MODE_MAX_RIX 7 + +/* in mac80211 mcs0-mcs15 is idx0-idx15*/ +#define N_MODE_MCS7_RIX 7 +#define N_MODE_MCS15_RIX 15 + struct rtl_rate_priv { - u8 cur_ratetab_idx; u8 ht_cap; }; -- cgit v0.10.2 From 81b290451122e93b9731bc333c6be2e49fa5bc0c Mon Sep 17 00:00:00 2001 From: Chaoming_Li Date: Mon, 25 Apr 2011 12:53:24 -0500 Subject: rtlwifi: Convert regulatory domain routines for addition of rtl8192se and rtl8192de Convert regulatory domain routines for addition of RTL8192SE and RTL8192DE code. Signed-off-by: Chaoming_Li Signed-off-by: Larry Finger Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/rtlwifi/regd.c b/drivers/net/wireless/rtlwifi/regd.c index 3336ca9..714858a 100644 --- a/drivers/net/wireless/rtlwifi/regd.c +++ b/drivers/net/wireless/rtlwifi/regd.c @@ -66,31 +66,83 @@ static struct country_code_to_enum_rd allCountries[] = { NL80211_RRF_PASSIVE_SCAN | \ NL80211_RRF_NO_OFDM) +/* 5G chan 36 - chan 64*/ +#define RTL819x_5GHZ_5150_5350 \ + REG_RULE(5150-10, 5350+10, 40, 0, 30, \ + NL80211_RRF_PASSIVE_SCAN | \ + NL80211_RRF_NO_IBSS) + +/* 5G chan 100 - chan 165*/ +#define RTL819x_5GHZ_5470_5850 \ + REG_RULE(5470-10, 5850+10, 40, 0, 30, \ + NL80211_RRF_PASSIVE_SCAN | \ + NL80211_RRF_NO_IBSS) + +/* 5G chan 149 - chan 165*/ +#define RTL819x_5GHZ_5725_5850 \ + REG_RULE(5725-10, 5850+10, 40, 0, 30, \ + NL80211_RRF_PASSIVE_SCAN | \ + NL80211_RRF_NO_IBSS) + +#define RTL819x_5GHZ_ALL \ + (RTL819x_5GHZ_5150_5350, RTL819x_5GHZ_5470_5850) + static const struct ieee80211_regdomain rtl_regdom_11 = { .n_reg_rules = 1, .alpha2 = "99", .reg_rules = { RTL819x_2GHZ_CH01_11, - } + } +}; + +static const struct ieee80211_regdomain rtl_regdom_12_13 = { + .n_reg_rules = 2, + .alpha2 = "99", + .reg_rules = { + RTL819x_2GHZ_CH01_11, + RTL819x_2GHZ_CH12_13, + } }; -static const struct ieee80211_regdomain rtl_regdom_global = { +static const struct ieee80211_regdomain rtl_regdom_no_midband = { .n_reg_rules = 3, .alpha2 = "99", .reg_rules = { RTL819x_2GHZ_CH01_11, - RTL819x_2GHZ_CH12_13, - RTL819x_2GHZ_CH14, - } + RTL819x_5GHZ_5150_5350, + RTL819x_5GHZ_5725_5850, + } }; -static const struct ieee80211_regdomain rtl_regdom_world = { - .n_reg_rules = 2, +static const struct ieee80211_regdomain rtl_regdom_60_64 = { + .n_reg_rules = 3, .alpha2 = "99", .reg_rules = { RTL819x_2GHZ_CH01_11, - RTL819x_2GHZ_CH12_13, - } + RTL819x_2GHZ_CH12_13, + RTL819x_5GHZ_5725_5850, + } +}; + +static const struct ieee80211_regdomain rtl_regdom_14_60_64 = { + .n_reg_rules = 4, + .alpha2 = "99", + .reg_rules = { + RTL819x_2GHZ_CH01_11, + RTL819x_2GHZ_CH12_13, + RTL819x_2GHZ_CH14, + RTL819x_5GHZ_5725_5850, + } +}; + +static const struct ieee80211_regdomain rtl_regdom_14 = { + .n_reg_rules = 3, + .alpha2 = "99", + .reg_rules = { + RTL819x_2GHZ_CH01_11, + RTL819x_2GHZ_CH12_13, + RTL819x_2GHZ_CH14, + } }; static bool _rtl_is_radar_freq(u16 center_freq) @@ -162,6 +214,8 @@ static void _rtl_reg_apply_active_scan_flags(struct wiphy *wiphy, u32 bandwidth = 0; int r; + if (!wiphy->bands[IEEE80211_BAND_2GHZ]) + return; sband = wiphy->bands[IEEE80211_BAND_2GHZ]; /* @@ -292,25 +346,26 @@ static const struct ieee80211_regdomain *_rtl_regdomain_select( { switch (reg->country_code) { case COUNTRY_CODE_FCC: + return &rtl_regdom_no_midband; case COUNTRY_CODE_IC: return &rtl_regdom_11; case COUNTRY_CODE_ETSI: + case COUNTRY_CODE_TELEC_NETGEAR: + return &rtl_regdom_60_64; case COUNTRY_CODE_SPAIN: case COUNTRY_CODE_FRANCE: case COUNTRY_CODE_ISRAEL: - case COUNTRY_CODE_TELEC_NETGEAR: - return &rtl_regdom_world; + case COUNTRY_CODE_WORLD_WIDE_13: + return &rtl_regdom_12_13; case COUNTRY_CODE_MKK: case COUNTRY_CODE_MKK1: case COUNTRY_CODE_TELEC: case COUNTRY_CODE_MIC: - return &rtl_regdom_global; + return &rtl_regdom_14_60_64; case COUNTRY_CODE_GLOBAL_DOMAIN: - return &rtl_regdom_global; - case COUNTRY_CODE_WORLD_WIDE_13: - return &rtl_regdom_world; + return &rtl_regdom_14; default: - return &rtl_regdom_world; + return &rtl_regdom_no_midband; } } @@ -323,9 +378,11 @@ static int _rtl_regd_init_wiphy(struct rtl_regulatory *reg, const struct ieee80211_regdomain *regd; wiphy->reg_notifier = reg_notifier; + wiphy->flags |= WIPHY_FLAG_CUSTOM_REGULATORY; wiphy->flags &= ~WIPHY_FLAG_STRICT_REGULATORY; wiphy->flags &= ~WIPHY_FLAG_DISABLE_BEACON_HINTS; + regd = _rtl_regdomain_select(reg); wiphy_apply_custom_regulatory(wiphy, regd); _rtl_reg_apply_radar_flags(wiphy); @@ -355,8 +412,8 @@ int rtl_regd_init(struct ieee80211_hw *hw, if (wiphy == NULL || &rtlpriv->regd == NULL) return -EINVAL; - /* force the channel plan to world wide 13 */ - rtlpriv->regd.country_code = COUNTRY_CODE_WORLD_WIDE_13; + /* init country_code from efuse channel plan */ + rtlpriv->regd.country_code = rtlpriv->efuse.channel_plan; RT_TRACE(rtlpriv, COMP_REGD, DBG_TRACE, (KERN_DEBUG "rtl: EEPROM regdomain: 0x%0x\n", @@ -373,8 +430,8 @@ int rtl_regd_init(struct ieee80211_hw *hw, country = _rtl_regd_find_country(rtlpriv->regd.country_code); if (country) { - rtlpriv->regd.alpha2[0] = country->isoName[0]; - rtlpriv->regd.alpha2[1] = country->isoName[1]; + rtlpriv->regd.alpha2[0] = country->iso_name[0]; + rtlpriv->regd.alpha2[1] = country->iso_name[1]; } else { rtlpriv->regd.alpha2[0] = '0'; rtlpriv->regd.alpha2[1] = '0'; diff --git a/drivers/net/wireless/rtlwifi/regd.h b/drivers/net/wireless/rtlwifi/regd.h index 4cdbc4a..d231189 100644 --- a/drivers/net/wireless/rtlwifi/regd.h +++ b/drivers/net/wireless/rtlwifi/regd.h @@ -32,7 +32,7 @@ struct country_code_to_enum_rd { u16 countrycode; - const char *isoName; + const char *iso_name; }; enum country_code_type_t { -- cgit v0.10.2 From d93cdee975bc6894b0a7c3f3eb4f2b34303163f8 Mon Sep 17 00:00:00 2001 From: Chaoming_Li Date: Mon, 25 Apr 2011 12:53:29 -0500 Subject: rtlwifi: Convert usb routines for addition of rtl8192se and rtl8192de Convert usb routines for addition of RTL8192SE and RTL8192DE code Signed-off-by: Chaoming_Li Signed-off-by: Larry Finger Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/rtlwifi/pci.c b/drivers/net/wireless/rtlwifi/pci.c index fa66205..e496361 100644 --- a/drivers/net/wireless/rtlwifi/pci.c +++ b/drivers/net/wireless/rtlwifi/pci.c @@ -1569,10 +1569,8 @@ int rtl_pci_tx(struct ieee80211_hw *hw, struct sk_buff *skb, if (ieee80211_is_data(fc)) rtlpriv->cfg->ops->led_control(hw, LED_CTL_TX); -#if 0 /* temporary */ rtlpriv->cfg->ops->fill_tx_desc(hw, hdr, (u8 *)pdesc, info, skb, hw_queue, ptcb_desc); -#endif __skb_queue_tail(&ring->queue, skb); diff --git a/drivers/net/wireless/rtlwifi/usb.c b/drivers/net/wireless/rtlwifi/usb.c index 14539eb..a9367eb 100644 --- a/drivers/net/wireless/rtlwifi/usb.c +++ b/drivers/net/wireless/rtlwifi/usb.c @@ -852,6 +852,7 @@ static void _rtl_usb_tx_preprocess(struct ieee80211_hw *hw, struct sk_buff *skb, struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); struct rtl_tx_desc *pdesc = NULL; + struct rtl_tcb_desc tcb_desc; struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)(skb->data); __le16 fc = hdr->frame_control; u8 *pda_addr = hdr->addr1; @@ -860,6 +861,17 @@ static void _rtl_usb_tx_preprocess(struct ieee80211_hw *hw, struct sk_buff *skb, u8 tid = 0; u16 seq_number = 0; + if (ieee80211_is_auth(fc)) { + RT_TRACE(rtlpriv, COMP_SEND, DBG_DMESG, ("MAC80211_LINKING\n")); + rtl_ips_nic_on(hw); + } + + if (rtlpriv->psc.sw_ps_enabled) { + if (ieee80211_is_data(fc) && !ieee80211_is_nullfunc(fc) && + !ieee80211_has_pm(fc)) + hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_PM); + } + rtl_action_proc(hw, skb, true); if (is_multicast_ether_addr(pda_addr)) rtlpriv->stats.txbytesmulticast += skb->len; @@ -876,7 +888,7 @@ static void _rtl_usb_tx_preprocess(struct ieee80211_hw *hw, struct sk_buff *skb, seq_number <<= 4; } rtlpriv->cfg->ops->fill_tx_desc(hw, hdr, (u8 *)pdesc, info, skb, - hw_queue); + hw_queue, &tcb_desc); if (!ieee80211_has_morefrags(hdr->frame_control)) { if (qc) mac->tids[tid].seq_number = seq_number; diff --git a/drivers/net/wireless/rtlwifi/wifi.h b/drivers/net/wireless/rtlwifi/wifi.h index 4776cd1..683f7f7 100644 --- a/drivers/net/wireless/rtlwifi/wifi.h +++ b/drivers/net/wireless/rtlwifi/wifi.h @@ -1378,18 +1378,11 @@ struct rtl_hal_ops { void (*update_rate_table) (struct ieee80211_hw *hw); #endif void (*update_rate_mask) (struct ieee80211_hw *hw, u8 rssi_level); -#if 0 /* temporary */ void (*fill_tx_desc) (struct ieee80211_hw *hw, struct ieee80211_hdr *hdr, u8 *pdesc_tx, struct ieee80211_tx_info *info, struct sk_buff *skb, u8 hw_queue, struct rtl_tcb_desc *ptcb_desc); -#else - void (*fill_tx_desc) (struct ieee80211_hw *hw, - struct ieee80211_hdr *hdr, u8 *pdesc_tx, - struct ieee80211_tx_info *info, - struct sk_buff *skb, unsigned int queue_index); -#endif void (*fill_fake_txdesc) (struct ieee80211_hw *hw, u8 *pDesc, u32 buffer_len, bool bIsPsPoll); void (*fill_tx_cmddesc) (struct ieee80211_hw *hw, u8 *pdesc, -- cgit v0.10.2 From beb5bc4020436ee50bd50e82c5a64eb087f0e3b3 Mon Sep 17 00:00:00 2001 From: Chaoming_Li Date: Mon, 25 Apr 2011 12:53:35 -0500 Subject: rtlwifi: rtl8192c-common: Convert common dynamic management routines for addition of rtl8192se and rtl8192de Convert common dynamic management routines for addition of RTL8192SE and RTL8192DE code. Signed-off-by: Chaoming_Li Signed-off-by: Larry Finger Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/rtlwifi/rtl8192c/dm_common.c b/drivers/net/wireless/rtlwifi/rtl8192c/dm_common.c index 5ea3a5e..2836d7e 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192c/dm_common.c +++ b/drivers/net/wireless/rtlwifi/rtl8192c/dm_common.c @@ -28,10 +28,26 @@ *****************************************************************************/ #include "dm_common.h" +#include "phy_common.h" +#include "../pci.h" +#include "../base.h" struct dig_t dm_digtable; static struct ps_t dm_pstable; +#define BT_RSSI_STATE_NORMAL_POWER BIT_OFFSET_LEN_MASK_32(0, 1) +#define BT_RSSI_STATE_AMDPU_OFF BIT_OFFSET_LEN_MASK_32(1, 1) +#define BT_RSSI_STATE_SPECIAL_LOW BIT_OFFSET_LEN_MASK_32(2, 1) +#define BT_RSSI_STATE_BG_EDCA_LOW BIT_OFFSET_LEN_MASK_32(3, 1) +#define BT_RSSI_STATE_TXPOWER_LOW BIT_OFFSET_LEN_MASK_32(4, 1) + +#define RTLPRIV (struct rtl_priv *) +#define GET_UNDECORATED_AVERAGE_RSSI(_priv) \ + ((RTLPRIV(_priv))->mac80211.opmode == \ + NL80211_IFTYPE_ADHOC) ? \ + ((RTLPRIV(_priv))->dm.entry_min_undecoratedsmoothed_pwdb) : \ + ((RTLPRIV(_priv))->dm.undecorated_smoothed_pwdb) + static const u32 ofdmswing_table[OFDM_TABLE_SIZE] = { 0x7f8001fe, 0x788001e2, @@ -461,10 +477,7 @@ static void rtl92c_dm_ctrl_initgain_by_twoport(struct ieee80211_hw *hw) if (mac->act_scanning == true) return; - if ((mac->link_state > MAC80211_NOLINK) && - (mac->link_state < MAC80211_LINKED)) - dm_digtable.cursta_connectctate = DIG_STA_BEFORE_CONNECT; - else if (mac->link_state >= MAC80211_LINKED) + if (mac->link_state >= MAC80211_LINKED) dm_digtable.cursta_connectctate = DIG_STA_CONNECT; else dm_digtable.cursta_connectctate = DIG_STA_DISCONNECT; @@ -562,23 +575,42 @@ EXPORT_SYMBOL(rtl92c_dm_init_edca_turbo); static void rtl92c_dm_check_edca_turbo(struct ieee80211_hw *hw) { struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_pci_priv *rtlpcipriv = rtl_pcipriv(hw); struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); + static u64 last_txok_cnt; static u64 last_rxok_cnt; - u64 cur_txok_cnt; - u64 cur_rxok_cnt; + static u32 last_bt_edca_ul; + static u32 last_bt_edca_dl; + u64 cur_txok_cnt = 0; + u64 cur_rxok_cnt = 0; u32 edca_be_ul = 0x5ea42b; u32 edca_be_dl = 0x5ea42b; + bool bt_change_edca = false; - if (mac->opmode == NL80211_IFTYPE_ADHOC) - goto dm_checkedcaturbo_exit; + if ((last_bt_edca_ul != rtlpcipriv->bt_coexist.bt_edca_ul) || + (last_bt_edca_dl != rtlpcipriv->bt_coexist.bt_edca_dl)) { + rtlpriv->dm.current_turbo_edca = false; + last_bt_edca_ul = rtlpcipriv->bt_coexist.bt_edca_ul; + last_bt_edca_dl = rtlpcipriv->bt_coexist.bt_edca_dl; + } + + if (rtlpcipriv->bt_coexist.bt_edca_ul != 0) { + edca_be_ul = rtlpcipriv->bt_coexist.bt_edca_ul; + bt_change_edca = true; + } + + if (rtlpcipriv->bt_coexist.bt_edca_dl != 0) { + edca_be_ul = rtlpcipriv->bt_coexist.bt_edca_dl; + bt_change_edca = true; + } if (mac->link_state != MAC80211_LINKED) { rtlpriv->dm.current_turbo_edca = false; return; } - if (!mac->ht_enable) { /*FIX MERGE */ + if ((!mac->ht_enable) && (!rtlpcipriv->bt_coexist.bt_coexistence)) { if (!(edca_be_ul & 0xffff0000)) edca_be_ul |= 0x005e0000; @@ -586,10 +618,12 @@ static void rtl92c_dm_check_edca_turbo(struct ieee80211_hw *hw) edca_be_dl |= 0x005e0000; } - if ((!rtlpriv->dm.is_any_nonbepkts) && - (!rtlpriv->dm.disable_framebursting)) { + if ((bt_change_edca) || ((!rtlpriv->dm.is_any_nonbepkts) && + (!rtlpriv->dm.disable_framebursting))) { + cur_txok_cnt = rtlpriv->stats.txbytesunicast - last_txok_cnt; cur_rxok_cnt = rtlpriv->stats.rxbytesunicast - last_rxok_cnt; + if (cur_rxok_cnt > 4 * cur_txok_cnt) { if (!rtlpriv->dm.is_cur_rdlstate || !rtlpriv->dm.current_turbo_edca) { @@ -618,7 +652,6 @@ static void rtl92c_dm_check_edca_turbo(struct ieee80211_hw *hw) } } -dm_checkedcaturbo_exit: rtlpriv->dm.is_any_nonbepkts = false; last_txok_cnt = rtlpriv->stats.txbytesunicast; last_rxok_cnt = rtlpriv->stats.rxbytesunicast; @@ -633,7 +666,7 @@ static void rtl92c_dm_txpower_tracking_callback_thermalmeter(struct ieee80211_hw struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw)); u8 thermalvalue, delta, delta_lck, delta_iqk; long ele_a, ele_d, temp_cck, val_x, value32; - long val_y, ele_c; + long val_y, ele_c = 0; u8 ofdm_index[2], cck_index = 0, ofdm_index_old[2], cck_index_old = 0; int i; bool is2t = IS_92C_SERIAL(rtlhal->version); @@ -683,7 +716,6 @@ static void rtl92c_dm_txpower_tracking_callback_thermalmeter(struct ieee80211_hw for (i = 0; i < OFDM_TABLE_LENGTH; i++) { if (ele_d == (ofdmswing_table[i] & MASKOFDM_D)) { - ofdm_index_old[1] = (u8) i; RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD, @@ -1132,6 +1164,7 @@ static void rtl92c_dm_refresh_rate_adaptive_mask(struct ieee80211_hw *hw) struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); struct rate_adaptive *p_ra = &(rtlpriv->ra); u32 low_rssithresh_for_ra, high_rssithresh_for_ra; + struct ieee80211_sta *sta = NULL; if (is_hal_stop(rtlhal)) { RT_TRACE(rtlpriv, COMP_RATE, DBG_LOUD, @@ -1145,8 +1178,8 @@ static void rtl92c_dm_refresh_rate_adaptive_mask(struct ieee80211_hw *hw) return; } - if (mac->link_state == MAC80211_LINKED) { - + if (mac->link_state == MAC80211_LINKED && + mac->opmode == NL80211_IFTYPE_STATION) { switch (p_ra->pre_ratr_state) { case DM_RATR_STA_HIGH: high_rssithresh_for_ra = 50; @@ -1185,10 +1218,13 @@ static void rtl92c_dm_refresh_rate_adaptive_mask(struct ieee80211_hw *hw) ("PreState = %d, CurState = %d\n", p_ra->pre_ratr_state, p_ra->ratr_state)); - rtlpriv->cfg->ops->update_rate_mask(hw, + rcu_read_lock(); + sta = ieee80211_find_sta(mac->vif, mac->bssid); + rtlpriv->cfg->ops->update_rate_tbl(hw, sta, p_ra->ratr_state); p_ra->pre_ratr_state = p_ra->ratr_state; + rcu_read_unlock(); } } } @@ -1202,7 +1238,7 @@ static void rtl92c_dm_init_dynamic_bb_powersaving(struct ieee80211_hw *hw) dm_pstable.rssi_val_min = 0; } -static void rtl92c_dm_1r_cca(struct ieee80211_hw *hw) +void rtl92c_dm_1r_cca(struct ieee80211_hw *hw) { struct rtl_priv *rtlpriv = rtl_priv(hw); struct rtl_phy *rtlphy = &(rtlpriv->phy); @@ -1352,7 +1388,9 @@ static void rtl92c_dm_dynamic_bb_powersaving(struct ieee80211_hw *hw) } if (IS_92C_SERIAL(rtlhal->version)) - rtl92c_dm_1r_cca(hw); + ;/* rtl92c_dm_1r_cca(hw); */ + else + rtl92c_dm_rf_saving(hw, false); } void rtl92c_dm_init(struct ieee80211_hw *hw) @@ -1369,6 +1407,84 @@ void rtl92c_dm_init(struct ieee80211_hw *hw) } EXPORT_SYMBOL(rtl92c_dm_init); +void rtl92c_dm_dynamic_txpower(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_phy *rtlphy = &(rtlpriv->phy); + struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); + long undecorated_smoothed_pwdb; + + if (!rtlpriv->dm.dynamic_txpower_enable) + return; + + if (rtlpriv->dm.dm_flag & HAL_DM_HIPWR_DISABLE) { + rtlpriv->dm.dynamic_txhighpower_lvl = TXHIGHPWRLEVEL_NORMAL; + return; + } + + if ((mac->link_state < MAC80211_LINKED) && + (rtlpriv->dm.entry_min_undecoratedsmoothed_pwdb == 0)) { + RT_TRACE(rtlpriv, COMP_POWER, DBG_TRACE, + ("Not connected to any\n")); + + rtlpriv->dm.dynamic_txhighpower_lvl = TXHIGHPWRLEVEL_NORMAL; + + rtlpriv->dm.last_dtp_lvl = TXHIGHPWRLEVEL_NORMAL; + return; + } + + if (mac->link_state >= MAC80211_LINKED) { + if (mac->opmode == NL80211_IFTYPE_ADHOC) { + undecorated_smoothed_pwdb = + rtlpriv->dm.entry_min_undecoratedsmoothed_pwdb; + RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD, + ("AP Client PWDB = 0x%lx\n", + undecorated_smoothed_pwdb)); + } else { + undecorated_smoothed_pwdb = + rtlpriv->dm.undecorated_smoothed_pwdb; + RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD, + ("STA Default Port PWDB = 0x%lx\n", + undecorated_smoothed_pwdb)); + } + } else { + undecorated_smoothed_pwdb = + rtlpriv->dm.entry_min_undecoratedsmoothed_pwdb; + + RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD, + ("AP Ext Port PWDB = 0x%lx\n", + undecorated_smoothed_pwdb)); + } + + if (undecorated_smoothed_pwdb >= TX_POWER_NEAR_FIELD_THRESH_LVL2) { + rtlpriv->dm.dynamic_txhighpower_lvl = TXHIGHPWRLEVEL_LEVEL1; + RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD, + ("TXHIGHPWRLEVEL_LEVEL1 (TxPwr=0x0)\n")); + } else if ((undecorated_smoothed_pwdb < + (TX_POWER_NEAR_FIELD_THRESH_LVL2 - 3)) && + (undecorated_smoothed_pwdb >= + TX_POWER_NEAR_FIELD_THRESH_LVL1)) { + + rtlpriv->dm.dynamic_txhighpower_lvl = TXHIGHPWRLEVEL_LEVEL1; + RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD, + ("TXHIGHPWRLEVEL_LEVEL1 (TxPwr=0x10)\n")); + } else if (undecorated_smoothed_pwdb < + (TX_POWER_NEAR_FIELD_THRESH_LVL1 - 5)) { + rtlpriv->dm.dynamic_txhighpower_lvl = TXHIGHPWRLEVEL_NORMAL; + RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD, + ("TXHIGHPWRLEVEL_NORMAL\n")); + } + + if ((rtlpriv->dm.dynamic_txhighpower_lvl != rtlpriv->dm.last_dtp_lvl)) { + RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD, + ("PHY_SetTxPowerLevel8192S() Channel = %d\n", + rtlphy->current_channel)); + rtl92c_phy_set_txpower_level(hw, rtlphy->current_channel); + } + + rtlpriv->dm.last_dtp_lvl = rtlpriv->dm.dynamic_txhighpower_lvl; +} + void rtl92c_dm_watchdog(struct ieee80211_hw *hw) { struct rtl_priv *rtlpriv = rtl_priv(hw); @@ -1388,11 +1504,319 @@ void rtl92c_dm_watchdog(struct ieee80211_hw *hw) rtl92c_dm_dig(hw); rtl92c_dm_false_alarm_counter_statistics(hw); rtl92c_dm_dynamic_bb_powersaving(hw); - rtlpriv->cfg->ops->dm_dynamic_txpower(hw); + rtl92c_dm_dynamic_txpower(hw); rtl92c_dm_check_txpower_tracking(hw); rtl92c_dm_refresh_rate_adaptive_mask(hw); + rtl92c_dm_bt_coexist(hw); rtl92c_dm_check_edca_turbo(hw); - } } EXPORT_SYMBOL(rtl92c_dm_watchdog); + +static u8 rtl92c_bt_rssi_state_change(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_pci_priv *rtlpcipriv = rtl_pcipriv(hw); + long undecorated_smoothed_pwdb; + u8 curr_bt_rssi_state = 0x00; + + if (rtlpriv->mac80211.link_state == MAC80211_LINKED) { + undecorated_smoothed_pwdb = + GET_UNDECORATED_AVERAGE_RSSI(rtlpriv); + } else { + if (rtlpriv->dm.entry_min_undecoratedsmoothed_pwdb == 0) + undecorated_smoothed_pwdb = 100; + else + undecorated_smoothed_pwdb = + rtlpriv->dm.entry_min_undecoratedsmoothed_pwdb; + } + + /* Check RSSI to determine HighPower/NormalPower state for + * BT coexistence. */ + if (undecorated_smoothed_pwdb >= 67) + curr_bt_rssi_state &= (~BT_RSSI_STATE_NORMAL_POWER); + else if (undecorated_smoothed_pwdb < 62) + curr_bt_rssi_state |= BT_RSSI_STATE_NORMAL_POWER; + + /* Check RSSI to determine AMPDU setting for BT coexistence. */ + if (undecorated_smoothed_pwdb >= 40) + curr_bt_rssi_state &= (~BT_RSSI_STATE_AMDPU_OFF); + else if (undecorated_smoothed_pwdb <= 32) + curr_bt_rssi_state |= BT_RSSI_STATE_AMDPU_OFF; + + /* Marked RSSI state. It will be used to determine BT coexistence + * setting later. */ + if (undecorated_smoothed_pwdb < 35) + curr_bt_rssi_state |= BT_RSSI_STATE_SPECIAL_LOW; + else + curr_bt_rssi_state &= (~BT_RSSI_STATE_SPECIAL_LOW); + + /* Set Tx Power according to BT status. */ + if (undecorated_smoothed_pwdb >= 30) + curr_bt_rssi_state |= BT_RSSI_STATE_TXPOWER_LOW; + else if (undecorated_smoothed_pwdb < 25) + curr_bt_rssi_state &= (~BT_RSSI_STATE_TXPOWER_LOW); + + /* Check BT state related to BT_Idle in B/G mode. */ + if (undecorated_smoothed_pwdb < 15) + curr_bt_rssi_state |= BT_RSSI_STATE_BG_EDCA_LOW; + else + curr_bt_rssi_state &= (~BT_RSSI_STATE_BG_EDCA_LOW); + + if (curr_bt_rssi_state != rtlpcipriv->bt_coexist.bt_rssi_state) { + rtlpcipriv->bt_coexist.bt_rssi_state = curr_bt_rssi_state; + return true; + } else { + return false; + } +} + +static bool rtl92c_bt_state_change(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_pci_priv *rtlpcipriv = rtl_pcipriv(hw); + + u32 polling, ratio_tx, ratio_pri; + u32 bt_tx, bt_pri; + u8 bt_state; + u8 cur_service_type; + + if (rtlpriv->mac80211.link_state < MAC80211_LINKED) + return false; + + bt_state = rtl_read_byte(rtlpriv, 0x4fd); + bt_tx = rtl_read_dword(rtlpriv, 0x488); + bt_tx = bt_tx & 0x00ffffff; + bt_pri = rtl_read_dword(rtlpriv, 0x48c); + bt_pri = bt_pri & 0x00ffffff; + polling = rtl_read_dword(rtlpriv, 0x490); + + if (bt_tx == 0xffffffff && bt_pri == 0xffffffff && + polling == 0xffffffff && bt_state == 0xff) + return false; + + bt_state &= BIT_OFFSET_LEN_MASK_32(0, 1); + if (bt_state != rtlpcipriv->bt_coexist.bt_cur_state) { + rtlpcipriv->bt_coexist.bt_cur_state = bt_state; + + if (rtlpcipriv->bt_coexist.reg_bt_sco == 3) { + rtlpcipriv->bt_coexist.bt_service = BT_IDLE; + + bt_state = bt_state | + ((rtlpcipriv->bt_coexist.bt_ant_isolation == 1) ? + 0 : BIT_OFFSET_LEN_MASK_32(1, 1)) | + BIT_OFFSET_LEN_MASK_32(2, 1); + rtl_write_byte(rtlpriv, 0x4fd, bt_state); + } + return true; + } + + ratio_tx = bt_tx * 1000 / polling; + ratio_pri = bt_pri * 1000 / polling; + rtlpcipriv->bt_coexist.ratio_tx = ratio_tx; + rtlpcipriv->bt_coexist.ratio_pri = ratio_pri; + + if (bt_state && rtlpcipriv->bt_coexist.reg_bt_sco == 3) { + + if ((ratio_tx < 30) && (ratio_pri < 30)) + cur_service_type = BT_IDLE; + else if ((ratio_pri > 110) && (ratio_pri < 250)) + cur_service_type = BT_SCO; + else if ((ratio_tx >= 200) && (ratio_pri >= 200)) + cur_service_type = BT_BUSY; + else if ((ratio_tx >= 350) && (ratio_tx < 500)) + cur_service_type = BT_OTHERBUSY; + else if (ratio_tx >= 500) + cur_service_type = BT_PAN; + else + cur_service_type = BT_OTHER_ACTION; + + if (cur_service_type != rtlpcipriv->bt_coexist.bt_service) { + rtlpcipriv->bt_coexist.bt_service = cur_service_type; + bt_state = bt_state | + ((rtlpcipriv->bt_coexist.bt_ant_isolation == 1) ? + 0 : BIT_OFFSET_LEN_MASK_32(1, 1)) | + ((rtlpcipriv->bt_coexist.bt_service != BT_IDLE) ? + 0 : BIT_OFFSET_LEN_MASK_32(2, 1)); + + /* Add interrupt migration when bt is not ini + * idle state (no traffic). */ + if (rtlpcipriv->bt_coexist.bt_service != BT_IDLE) { + rtl_write_word(rtlpriv, 0x504, 0x0ccc); + rtl_write_byte(rtlpriv, 0x506, 0x54); + rtl_write_byte(rtlpriv, 0x507, 0x54); + } else { + rtl_write_byte(rtlpriv, 0x506, 0x00); + rtl_write_byte(rtlpriv, 0x507, 0x00); + } + + rtl_write_byte(rtlpriv, 0x4fd, bt_state); + return true; + } + } + + return false; + +} + +static bool rtl92c_bt_wifi_connect_change(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + static bool media_connect; + + if (rtlpriv->mac80211.link_state < MAC80211_LINKED) { + media_connect = false; + } else { + if (!media_connect) { + media_connect = true; + return true; + } + media_connect = true; + } + + return false; +} + +static void rtl92c_bt_set_normal(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_pci_priv *rtlpcipriv = rtl_pcipriv(hw); + + + if (rtlpcipriv->bt_coexist.bt_service == BT_OTHERBUSY) { + rtlpcipriv->bt_coexist.bt_edca_ul = 0x5ea72b; + rtlpcipriv->bt_coexist.bt_edca_dl = 0x5ea72b; + } else if (rtlpcipriv->bt_coexist.bt_service == BT_BUSY) { + rtlpcipriv->bt_coexist.bt_edca_ul = 0x5eb82f; + rtlpcipriv->bt_coexist.bt_edca_dl = 0x5eb82f; + } else if (rtlpcipriv->bt_coexist.bt_service == BT_SCO) { + if (rtlpcipriv->bt_coexist.ratio_tx > 160) { + rtlpcipriv->bt_coexist.bt_edca_ul = 0x5ea72f; + rtlpcipriv->bt_coexist.bt_edca_dl = 0x5ea72f; + } else { + rtlpcipriv->bt_coexist.bt_edca_ul = 0x5ea32b; + rtlpcipriv->bt_coexist.bt_edca_dl = 0x5ea42b; + } + } else { + rtlpcipriv->bt_coexist.bt_edca_ul = 0; + rtlpcipriv->bt_coexist.bt_edca_dl = 0; + } + + if ((rtlpcipriv->bt_coexist.bt_service != BT_IDLE) && + (rtlpriv->mac80211.mode == WIRELESS_MODE_G || + (rtlpriv->mac80211.mode == (WIRELESS_MODE_G | WIRELESS_MODE_B))) && + (rtlpcipriv->bt_coexist.bt_rssi_state & + BT_RSSI_STATE_BG_EDCA_LOW)) { + rtlpcipriv->bt_coexist.bt_edca_ul = 0x5eb82b; + rtlpcipriv->bt_coexist.bt_edca_dl = 0x5eb82b; + } +} + +static void rtl92c_bt_ant_isolation(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_pci_priv *rtlpcipriv = rtl_pcipriv(hw); + + + /* Only enable HW BT coexist when BT in "Busy" state. */ + if (rtlpriv->mac80211.vendor == PEER_CISCO && + rtlpcipriv->bt_coexist.bt_service == BT_OTHER_ACTION) { + rtl_write_byte(rtlpriv, REG_GPIO_MUXCFG, 0xa0); + } else { + if ((rtlpcipriv->bt_coexist.bt_service == BT_BUSY) && + (rtlpcipriv->bt_coexist.bt_rssi_state & + BT_RSSI_STATE_NORMAL_POWER)) { + rtl_write_byte(rtlpriv, REG_GPIO_MUXCFG, 0xa0); + } else if ((rtlpcipriv->bt_coexist.bt_service == + BT_OTHER_ACTION) && (rtlpriv->mac80211.mode < + WIRELESS_MODE_N_24G) && + (rtlpcipriv->bt_coexist.bt_rssi_state & + BT_RSSI_STATE_SPECIAL_LOW)) { + rtl_write_byte(rtlpriv, REG_GPIO_MUXCFG, 0xa0); + } else if (rtlpcipriv->bt_coexist.bt_service == BT_PAN) { + rtl_write_byte(rtlpriv, REG_GPIO_MUXCFG, 0x00); + } else { + rtl_write_byte(rtlpriv, REG_GPIO_MUXCFG, 0x00); + } + } + + if (rtlpcipriv->bt_coexist.bt_service == BT_PAN) + rtl_write_dword(rtlpriv, REG_GPIO_PIN_CTRL, 0x10100); + else + rtl_write_dword(rtlpriv, REG_GPIO_PIN_CTRL, 0x0); + + if (rtlpcipriv->bt_coexist.bt_rssi_state & + BT_RSSI_STATE_NORMAL_POWER) { + rtl92c_bt_set_normal(hw); + } else { + rtlpcipriv->bt_coexist.bt_edca_ul = 0; + rtlpcipriv->bt_coexist.bt_edca_dl = 0; + } + + if (rtlpcipriv->bt_coexist.bt_service != BT_IDLE) { + rtlpriv->cfg->ops->set_rfreg(hw, + RF90_PATH_A, + 0x1e, + 0xf0, 0xf); + } else { + rtlpriv->cfg->ops->set_rfreg(hw, + RF90_PATH_A, 0x1e, 0xf0, + rtlpcipriv->bt_coexist.bt_rfreg_origin_1e); + } + + if (!rtlpriv->dm.dynamic_txpower_enable) { + if (rtlpcipriv->bt_coexist.bt_service != BT_IDLE) { + if (rtlpcipriv->bt_coexist.bt_rssi_state & + BT_RSSI_STATE_TXPOWER_LOW) { + rtlpriv->dm.dynamic_txhighpower_lvl = + TXHIGHPWRLEVEL_BT2; + } else { + rtlpriv->dm.dynamic_txhighpower_lvl = + TXHIGHPWRLEVEL_BT1; + } + } else { + rtlpriv->dm.dynamic_txhighpower_lvl = + TXHIGHPWRLEVEL_NORMAL; + } + rtl92c_phy_set_txpower_level(hw, + rtlpriv->phy.current_channel); + } +} + +static void rtl92c_check_bt_change(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_pci_priv *rtlpcipriv = rtl_pcipriv(hw); + + if (rtlpcipriv->bt_coexist.bt_cur_state) { + if (rtlpcipriv->bt_coexist.bt_ant_isolation) + rtl92c_bt_ant_isolation(hw); + } else { + rtl_write_byte(rtlpriv, REG_GPIO_MUXCFG, 0x00); + rtlpriv->cfg->ops->set_rfreg(hw, RF90_PATH_A, 0x1e, 0xf0, + rtlpcipriv->bt_coexist.bt_rfreg_origin_1e); + + rtlpcipriv->bt_coexist.bt_edca_ul = 0; + rtlpcipriv->bt_coexist.bt_edca_dl = 0; + } +} + +void rtl92c_dm_bt_coexist(struct ieee80211_hw *hw) +{ + struct rtl_pci_priv *rtlpcipriv = rtl_pcipriv(hw); + + bool wifi_connect_change; + bool bt_state_change; + bool rssi_state_change; + + if ((rtlpcipriv->bt_coexist.bt_coexistence) && + (rtlpcipriv->bt_coexist.bt_coexist_type == BT_CSR_BC4)) { + + wifi_connect_change = rtl92c_bt_wifi_connect_change(hw); + bt_state_change = rtl92c_bt_state_change(hw); + rssi_state_change = rtl92c_bt_rssi_state_change(hw); + + if (wifi_connect_change || bt_state_change || rssi_state_change) + rtl92c_check_bt_change(hw); + } +} diff --git a/drivers/net/wireless/rtlwifi/rtl8192c/dm_common.h b/drivers/net/wireless/rtlwifi/rtl8192c/dm_common.h index b9cbb0a..b9736d3 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192c/dm_common.h +++ b/drivers/net/wireless/rtlwifi/rtl8192c/dm_common.h @@ -200,5 +200,7 @@ void rtl92c_dm_rf_saving(struct ieee80211_hw *hw, u8 bforce_in_normal); void rtl92c_phy_ap_calibrate(struct ieee80211_hw *hw, char delta); void rtl92c_phy_lc_calibrate(struct ieee80211_hw *hw); void rtl92c_phy_iq_calibrate(struct ieee80211_hw *hw, bool recovery); +void rtl92c_dm_dynamic_txpower(struct ieee80211_hw *hw); +void rtl92c_dm_bt_coexist(struct ieee80211_hw *hw); #endif -- cgit v0.10.2 From 3ac5e26a1e935469a8bdae1d624bc3b59d1fcdc5 Mon Sep 17 00:00:00 2001 From: Chaoming_Li Date: Mon, 25 Apr 2011 12:53:40 -0500 Subject: rtlwifi: rtl8192c-common: Change common firmware routines for addition of rtl8192se and rtl8192de Change common firmware routines for addition of RTL8192SE and RTL8192DE code. Signed-off-by: Chaoming_Li Signed-off-by: Larry Finger Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/rtlwifi/rtl8192c/fw_common.c b/drivers/net/wireless/rtlwifi/rtl8192c/fw_common.c index bc9d241..50303e1 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192c/fw_common.c +++ b/drivers/net/wireless/rtlwifi/rtl8192c/fw_common.c @@ -223,29 +223,15 @@ int rtl92c_download_fw(struct ieee80211_hw *hw) u8 *pfwdata; u32 fwsize; enum version_8192c version = rtlhal->version; - const struct firmware *firmware; printk(KERN_INFO "rtl8192c: Loading firmware file %s\n", rtlpriv->cfg->fw_name); - if (request_firmware(&firmware, rtlpriv->cfg->fw_name, - rtlpriv->io.dev)) { - printk(KERN_ERR "rtl8192c: Firmware loading failed\n"); + if (!rtlhal->pfirmware) return 1; - } - - if (firmware->size > 0x4000) { - RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, - ("Firmware is too big!\n")); - release_firmware(firmware); - return 1; - } - - memcpy(rtlhal->pfirmware, firmware->data, firmware->size); - fwsize = firmware->size; - release_firmware(firmware); pfwheader = (struct rtl92c_firmware_header *)rtlhal->pfirmware; pfwdata = (u8 *) rtlhal->pfirmware; + fwsize = rtlhal->fwsize; if (IS_FW_HEADER_EXIST(pfwheader)) { RT_TRACE(rtlpriv, COMP_FW, DBG_DMESG, @@ -553,6 +539,39 @@ void rtl92c_set_fw_pwrmode_cmd(struct ieee80211_hw *hw, u8 mode) } EXPORT_SYMBOL(rtl92c_set_fw_pwrmode_cmd); +static bool _rtl92c_cmd_send_packet(struct ieee80211_hw *hw, + struct sk_buff *skb) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); + struct rtl8192_tx_ring *ring; + struct rtl_tx_desc *pdesc; + u8 own; + unsigned long flags; + struct sk_buff *pskb = NULL; + + ring = &rtlpci->tx_ring[BEACON_QUEUE]; + + pskb = __skb_dequeue(&ring->queue); + if (pskb) + kfree_skb(pskb); + + spin_lock_irqsave(&rtlpriv->locks.irq_th_lock, flags); + + pdesc = &ring->desc[0]; + own = (u8) rtlpriv->cfg->ops->get_desc((u8 *) pdesc, true, HW_DESC_OWN); + + rtlpriv->cfg->ops->fill_tx_cmddesc(hw, (u8 *) pdesc, 1, 1, skb); + + __skb_queue_tail(&ring->queue, skb); + + spin_unlock_irqrestore(&rtlpriv->locks.irq_th_lock, flags); + + rtlpriv->cfg->ops->tx_polling(hw, BEACON_QUEUE); + + return true; +} + #define BEACON_PG 0 /*->1*/ #define PSPOLL_PG 2 #define NULL_PG 3 @@ -670,7 +689,7 @@ static u8 reserved_page_packet[TOTAL_RESERVED_PKT_LEN] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, }; -void rtl92c_set_fw_rsvdpagepkt(struct ieee80211_hw *hw, bool b_dl_finished) +void rtl92c_set_fw_rsvdpagepkt(struct ieee80211_hw *hw, bool dl_finished) { struct rtl_priv *rtlpriv = rtl_priv(hw); struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); @@ -679,12 +698,12 @@ void rtl92c_set_fw_rsvdpagepkt(struct ieee80211_hw *hw, bool b_dl_finished) u32 totalpacketlen; bool rtstatus; u8 u1RsvdPageLoc[3] = {0}; - bool b_dlok = false; + bool dlok = false; u8 *beacon; - u8 *p_pspoll; + u8 *pspoll; u8 *nullfunc; - u8 *p_probersp; + u8 *probersp; /*--------------------------------------------------------- (1) beacon ---------------------------------------------------------*/ @@ -695,10 +714,10 @@ void rtl92c_set_fw_rsvdpagepkt(struct ieee80211_hw *hw, bool b_dl_finished) /*------------------------------------------------------- (2) ps-poll --------------------------------------------------------*/ - p_pspoll = &reserved_page_packet[PSPOLL_PG * 128]; - SET_80211_PS_POLL_AID(p_pspoll, (mac->assoc_id | 0xc000)); - SET_80211_PS_POLL_BSSID(p_pspoll, mac->bssid); - SET_80211_PS_POLL_TA(p_pspoll, mac->mac_addr); + pspoll = &reserved_page_packet[PSPOLL_PG * 128]; + SET_80211_PS_POLL_AID(pspoll, (mac->assoc_id | 0xc000)); + SET_80211_PS_POLL_BSSID(pspoll, mac->bssid); + SET_80211_PS_POLL_TA(pspoll, mac->mac_addr); SET_H2CCMD_RSVDPAGE_LOC_PSPOLL(u1RsvdPageLoc, PSPOLL_PG); @@ -715,10 +734,10 @@ void rtl92c_set_fw_rsvdpagepkt(struct ieee80211_hw *hw, bool b_dl_finished) /*--------------------------------------------------------- (4) probe response ----------------------------------------------------------*/ - p_probersp = &reserved_page_packet[PROBERSP_PG * 128]; - SET_80211_HDR_ADDRESS1(p_probersp, mac->bssid); - SET_80211_HDR_ADDRESS2(p_probersp, mac->mac_addr); - SET_80211_HDR_ADDRESS3(p_probersp, mac->bssid); + probersp = &reserved_page_packet[PROBERSP_PG * 128]; + SET_80211_HDR_ADDRESS1(probersp, mac->bssid); + SET_80211_HDR_ADDRESS2(probersp, mac->mac_addr); + SET_80211_HDR_ADDRESS3(probersp, mac->bssid); SET_H2CCMD_RSVDPAGE_LOC_PROBE_RSP(u1RsvdPageLoc, PROBERSP_PG); @@ -736,12 +755,12 @@ void rtl92c_set_fw_rsvdpagepkt(struct ieee80211_hw *hw, bool b_dl_finished) memcpy((u8 *) skb_put(skb, totalpacketlen), &reserved_page_packet, totalpacketlen); - rtstatus = rtlpriv->cfg->ops->cmd_send_packet(hw, skb); + rtstatus = _rtl92c_cmd_send_packet(hw, skb); if (rtstatus) - b_dlok = true; + dlok = true; - if (b_dlok) { + if (dlok) { RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD, ("Set RSVD page location to Fw.\n")); RT_PRINT_DATA(rtlpriv, COMP_CMD, DBG_DMESG, diff --git a/drivers/net/wireless/rtlwifi/rtl8192c/fw_common.h b/drivers/net/wireless/rtlwifi/rtl8192c/fw_common.h index 3db33bd..3d5823c 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192c/fw_common.h +++ b/drivers/net/wireless/rtlwifi/rtl8192c/fw_common.h @@ -27,8 +27,8 @@ * *****************************************************************************/ -#ifndef __RTL92C__FW__H__ -#define __RTL92C__FW__H__ +#ifndef __RTL92C__FW__COMMON__H__ +#define __RTL92C__FW__COMMON__H__ #define FW_8192C_SIZE 0x3000 #define FW_8192C_START_ADDRESS 0x1000 -- cgit v0.10.2 From c07ccff326a2b3d81520e8c7a8e0f5e8cbc77416 Mon Sep 17 00:00:00 2001 From: Chaoming_Li Date: Mon, 25 Apr 2011 12:53:45 -0500 Subject: rtlwifi: rtl8192c-common: Change common PHY routines for addition of rtl8192se and rtl8192de Change common PHY routines for addition of RTL8192SE and RTL8192DE code. Signed-off-by: Chaoming_Li Signed-off-by: Larry Finger Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/rtlwifi/rtl8192c/phy_common.c b/drivers/net/wireless/rtlwifi/rtl8192c/phy_common.c index a702282..3915a1ba5 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192c/phy_common.c +++ b/drivers/net/wireless/rtlwifi/rtl8192c/phy_common.c @@ -78,18 +78,20 @@ void rtl92c_phy_set_bb_reg(struct ieee80211_hw *hw, RT_TRACE(rtlpriv, COMP_RF, DBG_TRACE, ("regaddr(%#x), bitmask(%#x)," " data(%#x)\n", regaddr, bitmask, data)); + } EXPORT_SYMBOL(rtl92c_phy_set_bb_reg); -u32 _rtl92c_phy_fw_rf_serial_read(struct ieee80211_hw *hw, +static u32 _rtl92c_phy_fw_rf_serial_read(struct ieee80211_hw *hw, enum radio_path rfpath, u32 offset) { RT_ASSERT(false, ("deprecated!\n")); return 0; + } EXPORT_SYMBOL(_rtl92c_phy_fw_rf_serial_read); -void _rtl92c_phy_fw_rf_serial_write(struct ieee80211_hw *hw, +static void _rtl92c_phy_fw_rf_serial_write(struct ieee80211_hw *hw, enum radio_path rfpath, u32 offset, u32 data) { @@ -97,7 +99,7 @@ void _rtl92c_phy_fw_rf_serial_write(struct ieee80211_hw *hw, } EXPORT_SYMBOL(_rtl92c_phy_fw_rf_serial_write); -u32 _rtl92c_phy_rf_serial_read(struct ieee80211_hw *hw, +static u32 _rtl92c_phy_rf_serial_read(struct ieee80211_hw *hw, enum radio_path rfpath, u32 offset) { struct rtl_priv *rtlpriv = rtl_priv(hw); @@ -148,7 +150,7 @@ u32 _rtl92c_phy_rf_serial_read(struct ieee80211_hw *hw, } EXPORT_SYMBOL(_rtl92c_phy_rf_serial_read); -void _rtl92c_phy_rf_serial_write(struct ieee80211_hw *hw, +static void _rtl92c_phy_rf_serial_write(struct ieee80211_hw *hw, enum radio_path rfpath, u32 offset, u32 data) { @@ -197,6 +199,7 @@ static void _rtl92c_phy_bb_config_1t(struct ieee80211_hw *hw) rtl_set_bbreg(hw, 0xe80, 0x0c000000, 0x2); rtl_set_bbreg(hw, 0xe88, 0x0c000000, 0x2); } + bool rtl92c_phy_rf_config(struct ieee80211_hw *hw) { struct rtl_priv *rtlpriv = rtl_priv(hw); @@ -205,7 +208,7 @@ bool rtl92c_phy_rf_config(struct ieee80211_hw *hw) } EXPORT_SYMBOL(rtl92c_phy_rf_config); -bool _rtl92c_phy_bb8192c_config_parafile(struct ieee80211_hw *hw) +static bool _rtl92c_phy_bb8192c_config_parafile(struct ieee80211_hw *hw) { struct rtl_priv *rtlpriv = rtl_priv(hw); struct rtl_phy *rtlphy = &(rtlpriv->phy); @@ -241,6 +244,7 @@ bool _rtl92c_phy_bb8192c_config_parafile(struct ieee80211_hw *hw) rtlphy->cck_high_power = (bool) (rtl_get_bbreg(hw, RFPGA0_XA_HSSIPARAMETER2, 0x200)); + return true; } EXPORT_SYMBOL(_rtl92c_phy_bb8192c_config_parafile); @@ -317,61 +321,48 @@ void _rtl92c_store_pwrIndex_diffrate_offset(struct ieee80211_hw *hw, } if (regaddr == RTXAGC_B_RATE54_24) { rtlphy->MCS_TXPWR[rtlphy->pwrgroup_cnt][9] = data; - RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, ("MCSTxPowerLevelOriginalOffset[%d][9] = 0x%x\n", rtlphy->pwrgroup_cnt, rtlphy->MCS_TXPWR[rtlphy->pwrgroup_cnt][9])); } - if (regaddr == RTXAGC_B_CCK1_55_MCS32) { rtlphy->MCS_TXPWR[rtlphy->pwrgroup_cnt][14] = data; - RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, ("MCSTxPowerLevelOriginalOffset[%d][14] = 0x%x\n", rtlphy->pwrgroup_cnt, rtlphy->MCS_TXPWR[rtlphy->pwrgroup_cnt][14])); } - if (regaddr == RTXAGC_B_CCK11_A_CCK2_11 && bitmask == 0x000000ff) { rtlphy->MCS_TXPWR[rtlphy->pwrgroup_cnt][15] = data; - RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, ("MCSTxPowerLevelOriginalOffset[%d][15] = 0x%x\n", rtlphy->pwrgroup_cnt, rtlphy->MCS_TXPWR[rtlphy->pwrgroup_cnt][15])); } - if (regaddr == RTXAGC_B_MCS03_MCS00) { rtlphy->MCS_TXPWR[rtlphy->pwrgroup_cnt][10] = data; - RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, ("MCSTxPowerLevelOriginalOffset[%d][10] = 0x%x\n", rtlphy->pwrgroup_cnt, rtlphy->MCS_TXPWR[rtlphy->pwrgroup_cnt][10])); } - if (regaddr == RTXAGC_B_MCS07_MCS04) { rtlphy->MCS_TXPWR[rtlphy->pwrgroup_cnt][11] = data; - RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, ("MCSTxPowerLevelOriginalOffset[%d][11] = 0x%x\n", rtlphy->pwrgroup_cnt, rtlphy->MCS_TXPWR[rtlphy->pwrgroup_cnt][11])); } - if (regaddr == RTXAGC_B_MCS11_MCS08) { rtlphy->MCS_TXPWR[rtlphy->pwrgroup_cnt][12] = data; - RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, ("MCSTxPowerLevelOriginalOffset[%d][12] = 0x%x\n", rtlphy->pwrgroup_cnt, rtlphy->MCS_TXPWR[rtlphy->pwrgroup_cnt][12])); } - if (regaddr == RTXAGC_B_MCS15_MCS12) { rtlphy->MCS_TXPWR[rtlphy->pwrgroup_cnt][13] = data; - RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, ("MCSTxPowerLevelOriginalOffset[%d][13] = 0x%x\n", rtlphy->pwrgroup_cnt, @@ -583,6 +574,7 @@ static void _rtl92c_ccxpower_index_check(struct ieee80211_hw *hw, rtlphy->cur_cck_txpwridx = cckpowerlevel[0]; rtlphy->cur_ofdm24g_txpwridx = ofdmpowerlevel[0]; + } void rtl92c_phy_set_txpower_level(struct ieee80211_hw *hw, u8 channel) @@ -611,7 +603,6 @@ bool rtl92c_phy_update_txpower_dbm(struct ieee80211_hw *hw, long power_indbm) struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw)); u8 idx; u8 rf_path; - u8 ccktxpwridx = _rtl92c_phy_dbm_to_txpwr_Idx(hw, WIRELESS_MODE_B, power_indbm); @@ -639,11 +630,6 @@ bool rtl92c_phy_update_txpower_dbm(struct ieee80211_hw *hw, long power_indbm) } EXPORT_SYMBOL(rtl92c_phy_update_txpower_dbm); -void rtl92c_phy_set_beacon_hw_reg(struct ieee80211_hw *hw, u16 beaconinterval) -{ -} -EXPORT_SYMBOL(rtl92c_phy_set_beacon_hw_reg); - u8 _rtl92c_phy_dbm_to_txpwr_Idx(struct ieee80211_hw *hw, enum wireless_mode wirelessmode, long power_indbm) @@ -741,9 +727,9 @@ void rtl92c_phy_set_bw_mode(struct ieee80211_hw *hw, if (rtlphy->set_bwmode_inprogress) return; rtlphy->set_bwmode_inprogress = true; - if ((!is_hal_stop(rtlhal)) && !(RT_CANNOT_IO(hw))) - rtlpriv->cfg->ops->phy_set_bw_mode_callback(hw); - else { + if ((!is_hal_stop(rtlhal)) && !(RT_CANNOT_IO(hw))) { + rtlphy->set_bwmode_inprogress = false; + } else { RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING, ("FALSE driver sleep or unload\n")); rtlphy->set_bwmode_inprogress = false; @@ -773,8 +759,9 @@ void rtl92c_phy_sw_chnl_callback(struct ieee80211_hw *hw) mdelay(delay); else continue; - } else + } else { rtlphy->sw_chnl_inprogress = false; + } break; } while (true); RT_TRACE(rtlpriv, COMP_SCAN, DBG_TRACE, ("<==\n")); @@ -811,9 +798,32 @@ u8 rtl92c_phy_sw_chnl(struct ieee80211_hw *hw) } EXPORT_SYMBOL(rtl92c_phy_sw_chnl); -static bool _rtl92c_phy_sw_chnl_step_by_step(struct ieee80211_hw *hw, - u8 channel, u8 *stage, u8 *step, - u32 *delay) +static bool _rtl92c_phy_set_sw_chnl_cmdarray(struct swchnlcmd *cmdtable, + u32 cmdtableidx, u32 cmdtablesz, + enum swchnlcmd_id cmdid, + u32 para1, u32 para2, u32 msdelay) +{ + struct swchnlcmd *pcmd; + + if (cmdtable == NULL) { + RT_ASSERT(false, ("cmdtable cannot be NULL.\n")); + return false; + } + + if (cmdtableidx >= cmdtablesz) + return false; + + pcmd = cmdtable + cmdtableidx; + pcmd->cmdid = cmdid; + pcmd->para1 = para1; + pcmd->para2 = para2; + pcmd->msdelay = msdelay; + return true; +} + +bool _rtl92c_phy_sw_chnl_step_by_step(struct ieee80211_hw *hw, + u8 channel, u8 *stage, u8 *step, + u32 *delay) { struct rtl_priv *rtlpriv = rtl_priv(hw); struct rtl_phy *rtlphy = &(rtlpriv->phy); @@ -917,29 +927,6 @@ static bool _rtl92c_phy_sw_chnl_step_by_step(struct ieee80211_hw *hw, return false; } -static bool _rtl92c_phy_set_sw_chnl_cmdarray(struct swchnlcmd *cmdtable, - u32 cmdtableidx, u32 cmdtablesz, - enum swchnlcmd_id cmdid, - u32 para1, u32 para2, u32 msdelay) -{ - struct swchnlcmd *pcmd; - - if (cmdtable == NULL) { - RT_ASSERT(false, ("cmdtable cannot be NULL.\n")); - return false; - } - - if (cmdtableidx >= cmdtablesz) - return false; - - pcmd = cmdtable + cmdtableidx; - pcmd->cmdid = cmdid; - pcmd->para1 = para1; - pcmd->para2 = para2; - pcmd->msdelay = msdelay; - return true; -} - bool rtl8192_phy_check_is_legal_rfpath(struct ieee80211_hw *hw, u32 rfpath) { return true; @@ -1002,13 +989,13 @@ static u8 _rtl92c_phy_path_b_iqk(struct ieee80211_hw *hw) reg_ebc = rtl_get_bbreg(hw, 0xebc, MASKDWORD); reg_ec4 = rtl_get_bbreg(hw, 0xec4, MASKDWORD); reg_ecc = rtl_get_bbreg(hw, 0xecc, MASKDWORD); + if (!(reg_eac & BIT(31)) && (((reg_eb4 & 0x03FF0000) >> 16) != 0x142) && (((reg_ebc & 0x03FF0000) >> 16) != 0x42)) result |= 0x01; else return result; - if (!(reg_eac & BIT(30)) && (((reg_ec4 & 0x03FF0000) >> 16) != 0x132) && (((reg_ecc & 0x03FF0000) >> 16) != 0x36)) @@ -1023,9 +1010,9 @@ static void _rtl92c_phy_path_a_fill_iqk_matrix(struct ieee80211_hw *hw, u32 oldval_0, x, tx0_a, reg; long y, tx0_c; - if (final_candidate == 0xFF) + if (final_candidate == 0xFF) { return; - else if (iqk_ok) { + } else if (iqk_ok) { oldval_0 = (rtl_get_bbreg(hw, ROFDM0_XATXIQIMBALANCE, MASKDWORD) >> 22) & 0x3FF; x = result[final_candidate][0]; @@ -1063,9 +1050,9 @@ static void _rtl92c_phy_path_b_fill_iqk_matrix(struct ieee80211_hw *hw, u32 oldval_1, x, tx1_a, reg; long y, tx1_c; - if (final_candidate == 0xFF) + if (final_candidate == 0xFF) { return; - else if (iqk_ok) { + } else if (iqk_ok) { oldval_1 = (rtl_get_bbreg(hw, ROFDM0_XBTXIQIMBALANCE, MASKDWORD) >> 22) & 0x3FF; x = result[final_candidate][4]; @@ -1282,6 +1269,7 @@ static void _rtl92c_phy_iq_calibrate(struct ieee80211_hw *hw, RFPGA0_XA_HSSIPARAMETER1, BIT(8)); } + if (!rtlphy->rfpi_enable) _rtl92c_phy_pi_mode_switch(hw, true); if (t == 0) { @@ -1317,9 +1305,10 @@ static void _rtl92c_phy_iq_calibrate(struct ieee80211_hw *hw, 0x3FF0000) >> 16; break; } else if (i == (retrycount - 1) && patha_ok == 0x01) + result[t][0] = (rtl_get_bbreg(hw, 0xe94, MASKDWORD) & 0x3FF0000) >> - 16; + 16; result[t][1] = (rtl_get_bbreg(hw, 0xe9c, MASKDWORD) & 0x3FF0000) >> 16; @@ -1434,7 +1423,7 @@ static void _rtl92c_phy_ap_calibrate(struct ieee80211_hw *hw, 0x04db25a4, 0x0b1b25a4 }; - u32 apk_offset[PATH_NUM] = { 0xb68, 0xb6c }; + const u32 apk_offset[PATH_NUM] = { 0xb68, 0xb6c }; u32 apk_normal_offset[PATH_NUM] = { 0xb28, 0xb98 }; @@ -1463,13 +1452,15 @@ static void _rtl92c_phy_ap_calibrate(struct ieee80211_hw *hw, 0x00050006 }; - const u32 apk_result[PATH_NUM][APK_BB_REG_NUM]; + u32 apk_result[PATH_NUM][APK_BB_REG_NUM]; long bb_offset, delta_v, delta_offset; if (!is2t) pathbound = 1; + return; + for (index = 0; index < PATH_NUM; index++) { apk_offset[index] = apk_normal_offset[index]; apk_value[index] = apk_normal_value[index]; @@ -1730,8 +1721,7 @@ static void _rtl92c_phy_ap_calibrate(struct ieee80211_hw *hw, 0x08)); } - - rtlphy->apk_done = true; + rtlphy->b_apk_done = true; #endif } @@ -1758,6 +1748,7 @@ static void _rtl92c_phy_set_rfpath_switch(struct ieee80211_hw *hw, rtl_set_bbreg(hw, RFPGA0_XA_RFINTERFACEOE, 0x300, 0x1); } + } #undef IQK_ADDA_REG_NUM diff --git a/drivers/net/wireless/rtlwifi/rtl8192c/phy_common.h b/drivers/net/wireless/rtlwifi/rtl8192c/phy_common.h index 53ffb09..b09a458 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192c/phy_common.h +++ b/drivers/net/wireless/rtlwifi/rtl8192c/phy_common.h @@ -27,8 +27,8 @@ * *****************************************************************************/ -#ifndef __RTL92C_PHY_H__ -#define __RTL92C_PHY_H__ +#ifndef __RTL92C_PHY_COMMON_H__ +#define __RTL92C_PHY_COMMON_H__ #define MAX_PRECMD_CNT 16 #define MAX_RFDEPENDCMD_CNT 16 @@ -39,6 +39,7 @@ #define RT_CANNOT_IO(hw) false #define HIGHPOWER_RADIOA_ARRAYLEN 22 +#define IQK_ADDA_REG_NUM 16 #define MAX_TOLERANCE 5 #define IQK_DELAY_TIME 1 @@ -56,6 +57,7 @@ #define IQK_ADDA_REG_NUM 16 #define IQK_MAC_REG_NUM 4 +#define IQK_DELAY_TIME 1 #define RF90_PATH_MAX 2 #define CT_OFFSET_MAC_ADDR 0X16 @@ -77,6 +79,7 @@ #define RTL92C_MAX_PATH_NUM 2 #define LLT_LAST_ENTRY_OF_TX_PKT_BUFFER 255 + enum swchnlcmd_id { CMDID_END, CMDID_SET_TXPOWEROWER_LEVEL, @@ -184,45 +187,41 @@ struct tx_power_struct { u32 mcs_original_offset[4][16]; }; -extern u32 rtl92c_phy_query_bb_reg(struct ieee80211_hw *hw, +u32 rtl92c_phy_query_bb_reg(struct ieee80211_hw *hw, u32 regaddr, u32 bitmask); -extern void rtl92c_phy_set_bb_reg(struct ieee80211_hw *hw, +void rtl92c_phy_set_bb_reg(struct ieee80211_hw *hw, u32 regaddr, u32 bitmask, u32 data); -extern u32 rtl92c_phy_query_rf_reg(struct ieee80211_hw *hw, +u32 rtl92c_phy_query_rf_reg(struct ieee80211_hw *hw, enum radio_path rfpath, u32 regaddr, u32 bitmask); -extern void rtl92c_phy_set_rf_reg(struct ieee80211_hw *hw, - enum radio_path rfpath, u32 regaddr, - u32 bitmask, u32 data); -extern bool rtl92c_phy_mac_config(struct ieee80211_hw *hw); -extern bool rtl92c_phy_bb_config(struct ieee80211_hw *hw); -extern bool rtl92c_phy_rf_config(struct ieee80211_hw *hw); -extern bool rtl92c_phy_config_rf_with_feaderfile(struct ieee80211_hw *hw, +bool rtl92c_phy_mac_config(struct ieee80211_hw *hw); +bool rtl92c_phy_bb_config(struct ieee80211_hw *hw); +bool rtl92c_phy_rf_config(struct ieee80211_hw *hw); +bool rtl92c_phy_config_rf_with_feaderfile(struct ieee80211_hw *hw, enum radio_path rfpath); -extern void rtl92c_phy_get_hw_reg_originalvalue(struct ieee80211_hw *hw); -extern void rtl92c_phy_get_txpower_level(struct ieee80211_hw *hw, +void rtl92c_phy_get_hw_reg_originalvalue(struct ieee80211_hw *hw); +void rtl92c_phy_get_txpower_level(struct ieee80211_hw *hw, long *powerlevel); -extern void rtl92c_phy_set_txpower_level(struct ieee80211_hw *hw, u8 channel); -extern bool rtl92c_phy_update_txpower_dbm(struct ieee80211_hw *hw, +void rtl92c_phy_set_txpower_level(struct ieee80211_hw *hw, u8 channel); +bool rtl92c_phy_update_txpower_dbm(struct ieee80211_hw *hw, long power_indbm); -extern void rtl92c_phy_scan_operation_backup(struct ieee80211_hw *hw, +void rtl92c_phy_scan_operation_backup(struct ieee80211_hw *hw, u8 operation); -extern void rtl92c_phy_set_bw_mode_callback(struct ieee80211_hw *hw); -extern void rtl92c_phy_set_bw_mode(struct ieee80211_hw *hw, +void rtl92c_phy_set_bw_mode(struct ieee80211_hw *hw, enum nl80211_channel_type ch_type); -extern void rtl92c_phy_sw_chnl_callback(struct ieee80211_hw *hw); -extern u8 rtl92c_phy_sw_chnl(struct ieee80211_hw *hw); -extern void rtl92c_phy_iq_calibrate(struct ieee80211_hw *hw, bool b_recovery); -extern void rtl92c_phy_set_beacon_hw_reg(struct ieee80211_hw *hw, +void rtl92c_phy_sw_chnl_callback(struct ieee80211_hw *hw); +u8 rtl92c_phy_sw_chnl(struct ieee80211_hw *hw); +void rtl92c_phy_iq_calibrate(struct ieee80211_hw *hw, bool b_recovery); +void rtl92c_phy_set_beacon_hw_reg(struct ieee80211_hw *hw, u16 beaconinterval); void rtl92c_phy_ap_calibrate(struct ieee80211_hw *hw, char delta); void rtl92c_phy_lc_calibrate(struct ieee80211_hw *hw); void rtl92c_phy_set_rfpath_switch(struct ieee80211_hw *hw, bool bmain); bool rtl92c_phy_config_rf_with_headerfile(struct ieee80211_hw *hw, enum radio_path rfpath); -extern bool rtl8192_phy_check_is_legal_rfpath(struct ieee80211_hw *hw, +bool rtl8192_phy_check_is_legal_rfpath(struct ieee80211_hw *hw, u32 rfpath); -extern bool rtl92c_phy_set_rf_power_state(struct ieee80211_hw *hw, +bool rtl92c_phy_set_rf_power_state(struct ieee80211_hw *hw, enum rf_pwrstate rfpwr_state); void rtl92ce_phy_set_rf_on(struct ieee80211_hw *hw); void rtl92c_phy_set_io(struct ieee80211_hw *hw); @@ -235,12 +234,9 @@ u8 _rtl92c_phy_dbm_to_txpwr_Idx(struct ieee80211_hw *hw, enum wireless_mode wirelessmode, long power_indbm); void _rtl92c_phy_init_bb_rf_register_definition(struct ieee80211_hw *hw); -static bool _rtl92c_phy_set_sw_chnl_cmdarray(struct swchnlcmd *cmdtable, - u32 cmdtableidx, u32 cmdtablesz, - enum swchnlcmd_id cmdid, u32 para1, - u32 para2, u32 msdelay); -static bool _rtl92c_phy_sw_chnl_step_by_step(struct ieee80211_hw *hw, - u8 channel, u8 *stage, u8 *step, - u32 *delay); +void _rtl92c_phy_set_rf_sleep(struct ieee80211_hw *hw); +bool _rtl92c_phy_sw_chnl_step_by_step(struct ieee80211_hw *hw, + u8 channel, u8 *stage, u8 *step, + u32 *delay); #endif -- cgit v0.10.2 From f73b279cdb5fc850b4be355307905f2914b2c0bb Mon Sep 17 00:00:00 2001 From: Chaoming_Li Date: Mon, 25 Apr 2011 12:53:50 -0500 Subject: rtlwifi: rtl8192ce: Change hw routine for addition of rtl8192se and rtl8192de Change rtl8192ce hw routine for addition of RTL8192SE and RTL8192DE. Signed-off-by: Chaoming_Li Signed-off-by: Larry Finger Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/rtlwifi/rtl8192ce/def.h b/drivers/net/wireless/rtlwifi/rtl8192ce/def.h index 2f577c8..35ff7df 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192ce/def.h +++ b/drivers/net/wireless/rtlwifi/rtl8192ce/def.h @@ -121,19 +121,6 @@ #define CHIP_92C 0x01 #define CHIP_88C 0x00 -/* Add vendor information into chip version definition. - * Add UMC B-Cut and RTL8723 chip info definition. - * - * BIT 7 Reserved - * BIT 6 UMC BCut - * BIT 5 Manufacturer(TSMC/UMC) - * BIT 4 TEST/NORMAL - * BIT 3 8723 Version - * BIT 2 8723? - * BIT 1 1T2R? - * BIT 0 88C/92C -*/ - enum version_8192c { VERSION_A_CHIP_92C = 0x01, VERSION_A_CHIP_88C = 0x00, @@ -280,20 +267,6 @@ struct h2c_cmd_8192c { u8 *p_cmdbuffer; }; -static inline u8 _rtl92c_get_chnl_group(u8 chnl) -{ - u8 group = 0; - - if (chnl < 3) - group = 0; - else if (chnl < 9) - group = 1; - else - group = 2; - - return group; -} - /* NOTE: reference to rtl8192c_rates struct */ static inline int _rtl92c_rate_mapping(struct ieee80211_hw *hw, bool isHT, u8 desc_rate, bool first_ampdu) diff --git a/drivers/net/wireless/rtlwifi/rtl8192ce/hw.c b/drivers/net/wireless/rtlwifi/rtl8192ce/hw.c index 05477f4..bb604b8 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192ce/hw.c +++ b/drivers/net/wireless/rtlwifi/rtl8192ce/hw.c @@ -30,12 +30,14 @@ #include "../wifi.h" #include "../efuse.h" #include "../base.h" +#include "../regd.h" #include "../cam.h" #include "../ps.h" #include "../pci.h" #include "reg.h" #include "def.h" #include "phy.h" +#include "../rtl8192c/fw_common.h" #include "dm.h" #include "led.h" #include "hw.h" @@ -137,15 +139,6 @@ void rtl92ce_get_hw_reg(struct ieee80211_hw *hw, u8 variable, u8 *val) break; } - case HW_VAR_MGT_FILTER: - *((u16 *) (val)) = rtl_read_word(rtlpriv, REG_RXFLTMAP0); - break; - case HW_VAR_CTRL_FILTER: - *((u16 *) (val)) = rtl_read_word(rtlpriv, REG_RXFLTMAP1); - break; - case HW_VAR_DATA_FILTER: - *((u16 *) (val)) = rtl_read_word(rtlpriv, REG_RXFLTMAP2); - break; default: RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, ("switch case not process\n")); @@ -156,6 +149,7 @@ void rtl92ce_get_hw_reg(struct ieee80211_hw *hw, u8 variable, u8 *val) void rtl92ce_set_hw_reg(struct ieee80211_hw *hw, u8 variable, u8 *val) { struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_pci_priv *rtlpcipriv = rtl_pcipriv(hw); struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); @@ -178,7 +172,7 @@ void rtl92ce_set_hw_reg(struct ieee80211_hw *hw, u8 variable, u8 *val) rate_cfg |= 0x01; rtl_write_byte(rtlpriv, REG_RRSR, rate_cfg & 0xff); rtl_write_byte(rtlpriv, REG_RRSR + 1, - (rate_cfg >> 8)&0xff); + (rate_cfg >> 8) & 0xff); while (rate_cfg > 0x1) { rate_cfg = (rate_cfg >> 1); rate_index++; @@ -276,13 +270,19 @@ void rtl92ce_set_hw_reg(struct ieee80211_hw *hw, u8 variable, u8 *val) break; } case HW_VAR_AMPDU_FACTOR:{ - u8 regtoset_normal[4] = { 0x41, 0xa8, 0x72, 0xb9 }; + u8 regtoset_normal[4] = {0x41, 0xa8, 0x72, 0xb9}; + u8 regtoset_bt[4] = {0x31, 0x74, 0x42, 0x97}; u8 factor_toset; u8 *p_regtoset = NULL; u8 index = 0; - p_regtoset = regtoset_normal; + if ((rtlpcipriv->bt_coexist.bt_coexistence) && + (rtlpcipriv->bt_coexist.bt_coexist_type == + BT_CSR_BC4)) + p_regtoset = regtoset_bt; + else + p_regtoset = regtoset_normal; factor_toset = *((u8 *) val); if (factor_toset <= 3) { @@ -317,45 +317,7 @@ void rtl92ce_set_hw_reg(struct ieee80211_hw *hw, u8 variable, u8 *val) } case HW_VAR_AC_PARAM:{ u8 e_aci = *((u8 *) val); - u32 u4b_ac_param; - u16 cw_min = le16_to_cpu(mac->ac[e_aci].cw_min); - u16 cw_max = le16_to_cpu(mac->ac[e_aci].cw_max); - u16 tx_op = le16_to_cpu(mac->ac[e_aci].tx_op); - - u4b_ac_param = (u32) mac->ac[e_aci].aifs; - u4b_ac_param |= ((u32)cw_min - & 0xF) << AC_PARAM_ECW_MIN_OFFSET; - u4b_ac_param |= ((u32)cw_max & - 0xF) << AC_PARAM_ECW_MAX_OFFSET; - u4b_ac_param |= (u32)tx_op << AC_PARAM_TXOP_OFFSET; - - RT_TRACE(rtlpriv, COMP_MLME, DBG_LOUD, - ("queue:%x, ac_param:%x\n", e_aci, - u4b_ac_param)); - - switch (e_aci) { - case AC1_BK: - rtl_write_dword(rtlpriv, REG_EDCA_BK_PARAM, - u4b_ac_param); - break; - case AC0_BE: - rtl_write_dword(rtlpriv, REG_EDCA_BE_PARAM, - u4b_ac_param); - break; - case AC2_VI: - rtl_write_dword(rtlpriv, REG_EDCA_VI_PARAM, - u4b_ac_param); - break; - case AC3_VO: - rtl_write_dword(rtlpriv, REG_EDCA_VO_PARAM, - u4b_ac_param); - break; - default: - RT_ASSERT(false, - ("SetHwReg8185(): invalid aci: %d !\n", - e_aci)); - break; - } + rtl92c_dm_init_edca_turbo(hw); if (rtlpci->acm_method != eAcmWay2_SW) rtlpriv->cfg->ops->set_hw_reg(hw, @@ -526,9 +488,6 @@ void rtl92ce_set_hw_reg(struct ieee80211_hw *hw, u8 variable, u8 *val) case HW_VAR_CORRECT_TSF:{ u8 btype_ibss = ((u8 *) (val))[0]; - /*btype_ibss = (mac->opmode == NL80211_IFTYPE_ADHOC) ? - 1 : 0;*/ - if (btype_ibss == true) _rtl92ce_stop_tx_beacon(hw); @@ -537,7 +496,7 @@ void rtl92ce_set_hw_reg(struct ieee80211_hw *hw, u8 variable, u8 *val) rtl_write_dword(rtlpriv, REG_TSFTR, (u32) (mac->tsf & 0xffffffff)); rtl_write_dword(rtlpriv, REG_TSFTR + 4, - (u32) ((mac->tsf >> 32)&0xffffffff)); + (u32) ((mac->tsf >> 32) & 0xffffffff)); _rtl92ce_set_bcn_ctrl_reg(hw, BIT(3), 0); @@ -547,15 +506,6 @@ void rtl92ce_set_hw_reg(struct ieee80211_hw *hw, u8 variable, u8 *val) break; } - case HW_VAR_MGT_FILTER: - rtl_write_word(rtlpriv, REG_RXFLTMAP0, *(u16 *) val); - break; - case HW_VAR_CTRL_FILTER: - rtl_write_word(rtlpriv, REG_RXFLTMAP1, *(u16 *) val); - break; - case HW_VAR_DATA_FILTER: - rtl_write_word(rtlpriv, REG_RXFLTMAP2, *(u16 *) val); - break; default: RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, ("switch case " "not process\n")); @@ -679,12 +629,12 @@ static void _rtl92ce_gen_refresh_led_state(struct ieee80211_hw *hw) rtl92ce_sw_led_on(hw, pLed0); else rtl92ce_sw_led_off(hw, pLed0); - } static bool _rtl92ce_init_mac(struct ieee80211_hw *hw) { struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_pci_priv *rtlpcipriv = rtl_pcipriv(hw); struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); @@ -693,9 +643,22 @@ static bool _rtl92ce_init_mac(struct ieee80211_hw *hw) u16 retry; rtl_write_byte(rtlpriv, REG_RSV_CTRL, 0x00); + if (rtlpcipriv->bt_coexist.bt_coexistence) { + u32 value32; + value32 = rtl_read_dword(rtlpriv, REG_APS_FSMCO); + value32 |= (SOP_ABG | SOP_AMB | XOP_BTCK); + rtl_write_dword(rtlpriv, REG_APS_FSMCO, value32); + } rtl_write_byte(rtlpriv, REG_SPS0_CTRL, 0x2b); rtl_write_byte(rtlpriv, REG_AFE_XTAL_CTRL, 0x0F); + if (rtlpcipriv->bt_coexist.bt_coexistence) { + u32 u4b_tmp = rtl_read_dword(rtlpriv, REG_AFE_XTAL_CTRL); + + u4b_tmp &= (~0x00024800); + rtl_write_dword(rtlpriv, REG_AFE_XTAL_CTRL, u4b_tmp); + } + bytetmp = rtl_read_byte(rtlpriv, REG_APS_FSMCO + 1) | BIT(0); udelay(2); @@ -726,6 +689,11 @@ static bool _rtl92ce_init_mac(struct ieee80211_hw *hw) rtl_write_byte(rtlpriv, REG_SYS_ISO_CTRL + 1, 0x82); udelay(2); + if (rtlpcipriv->bt_coexist.bt_coexistence) { + bytetmp = rtl_read_byte(rtlpriv, REG_AFE_XTAL_CTRL+2) & 0xfd; + rtl_write_byte(rtlpriv, REG_AFE_XTAL_CTRL+2, bytetmp); + } + rtl_write_word(rtlpriv, REG_CR, 0x2ff); if (_rtl92ce_llt_table_init(hw) == false) @@ -793,6 +761,7 @@ static void _rtl92ce_hw_configure(struct ieee80211_hw *hw) { struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_pci_priv *rtlpcipriv = rtl_pcipriv(hw); u8 reg_bw_opmode; u32 reg_ratr, reg_prsr; @@ -824,7 +793,11 @@ static void _rtl92ce_hw_configure(struct ieee80211_hw *hw) rtl_write_dword(rtlpriv, REG_RARFRC, 0x01000000); rtl_write_dword(rtlpriv, REG_RARFRC + 4, 0x07060504); - rtl_write_dword(rtlpriv, REG_AGGLEN_LMT, 0xb972a841); + if ((rtlpcipriv->bt_coexist.bt_coexistence) && + (rtlpcipriv->bt_coexist.bt_coexist_type == BT_CSR_BC4)) + rtl_write_dword(rtlpriv, REG_AGGLEN_LMT, 0x97427431); + else + rtl_write_dword(rtlpriv, REG_AGGLEN_LMT, 0xb972a841); rtl_write_byte(rtlpriv, REG_ATIMWND, 0x2); @@ -840,11 +813,20 @@ static void _rtl92ce_hw_configure(struct ieee80211_hw *hw) rtl_write_byte(rtlpriv, REG_PIFS, 0x1C); rtl_write_byte(rtlpriv, REG_AGGR_BREAK_TIME, 0x16); - rtl_write_word(rtlpriv, REG_NAV_PROT_LEN, 0x0020); - - rtl_write_word(rtlpriv, REG_NAV_PROT_LEN, 0x0020); + if ((rtlpcipriv->bt_coexist.bt_coexistence) && + (rtlpcipriv->bt_coexist.bt_coexist_type == BT_CSR_BC4)) { + rtl_write_word(rtlpriv, REG_NAV_PROT_LEN, 0x0020); + rtl_write_word(rtlpriv, REG_PROT_MODE_CTRL, 0x0402); + } else { + rtl_write_word(rtlpriv, REG_NAV_PROT_LEN, 0x0020); + rtl_write_word(rtlpriv, REG_NAV_PROT_LEN, 0x0020); + } - rtl_write_dword(rtlpriv, REG_FAST_EDCA_CTRL, 0x086666); + if ((rtlpcipriv->bt_coexist.bt_coexistence) && + (rtlpcipriv->bt_coexist.bt_coexist_type == BT_CSR_BC4)) + rtl_write_dword(rtlpriv, REG_FAST_EDCA_CTRL, 0x03086666); + else + rtl_write_dword(rtlpriv, REG_FAST_EDCA_CTRL, 0x086666); rtl_write_byte(rtlpriv, REG_ACKTO, 0x40); @@ -948,8 +930,10 @@ int rtl92ce_hw_init(struct ieee80211_hw *hw) } rtlhal->last_hmeboxnum = 0; - rtl92ce_phy_mac_config(hw); - rtl92ce_phy_bb_config(hw); +#if 0 /* temporary */ + rtl92c_phy_mac_config(hw); + rtl92c_phy_bb_config(hw); +#endif rtlphy->rf_mode = RF_OP_BY_SW_3WIRE; rtl92c_phy_rf_config(hw); rtlphy->rfreg_chnlval[0] = rtl_get_rfreg(hw, (enum radio_path)0, @@ -962,15 +946,20 @@ int rtl92ce_hw_init(struct ieee80211_hw *hw) _rtl92ce_hw_configure(hw); rtl_cam_reset_all_entry(hw); rtl92ce_enable_hw_security_config(hw); + ppsc->rfpwr_state = ERFON; + rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_ETHER_ADDR, mac->mac_addr); _rtl92ce_enable_aspm_back_door(hw); rtlpriv->intf_ops->enable_aspm(hw); + + rtl8192ce_bt_hw_init(hw); + if (ppsc->rfpwr_state == ERFON) { rtl92c_phy_set_rfpath_switch(hw, 1); - if (iqk_initialized) + if (iqk_initialized) { rtl92c_phy_iq_calibrate(hw, true); - else { + } else { rtl92c_phy_iq_calibrate(hw, false); iqk_initialized = true; } @@ -1128,75 +1117,62 @@ static int _rtl92ce_set_media_status(struct ieee80211_hw *hw, return 0; } -static void _rtl92ce_set_check_bssid(struct ieee80211_hw *hw, - enum nl80211_iftype type) +void rtl92ce_set_check_bssid(struct ieee80211_hw *hw, bool check_bssid) { struct rtl_priv *rtlpriv = rtl_priv(hw); u32 reg_rcr = rtl_read_dword(rtlpriv, REG_RCR); - u8 filterout_non_associated_bssid = false; - switch (type) { - case NL80211_IFTYPE_ADHOC: - case NL80211_IFTYPE_STATION: - filterout_non_associated_bssid = true; - break; - case NL80211_IFTYPE_UNSPECIFIED: - case NL80211_IFTYPE_AP: - default: - break; - } + if (rtlpriv->psc.rfpwr_state != ERFON) + return; - if (filterout_non_associated_bssid == true) { + if (check_bssid == true) { reg_rcr |= (RCR_CBSSID_DATA | RCR_CBSSID_BCN); rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_RCR, (u8 *) (®_rcr)); _rtl92ce_set_bcn_ctrl_reg(hw, 0, BIT(4)); - } else if (filterout_non_associated_bssid == false) { + } else if (check_bssid == false) { reg_rcr &= (~(RCR_CBSSID_DATA | RCR_CBSSID_BCN)); _rtl92ce_set_bcn_ctrl_reg(hw, BIT(4), 0); rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_RCR, (u8 *) (®_rcr)); } + } int rtl92ce_set_network_type(struct ieee80211_hw *hw, enum nl80211_iftype type) { + struct rtl_priv *rtlpriv = rtl_priv(hw); + if (_rtl92ce_set_media_status(hw, type)) return -EOPNOTSUPP; - _rtl92ce_set_check_bssid(hw, type); + + if (rtlpriv->mac80211.link_state == MAC80211_LINKED) { + if (type != NL80211_IFTYPE_AP) + rtl92ce_set_check_bssid(hw, true); + } else { + rtl92ce_set_check_bssid(hw, false); + } + return 0; } +/* don't set REG_EDCA_BE_PARAM here because mac80211 will send pkt when scan */ void rtl92ce_set_qos(struct ieee80211_hw *hw, int aci) { struct rtl_priv *rtlpriv = rtl_priv(hw); - struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); - u32 u4b_ac_param; - u16 cw_min = le16_to_cpu(mac->ac[aci].cw_min); - u16 cw_max = le16_to_cpu(mac->ac[aci].cw_max); - u16 tx_op = le16_to_cpu(mac->ac[aci].tx_op); - rtl92c_dm_init_edca_turbo(hw); - u4b_ac_param = (u32) mac->ac[aci].aifs; - u4b_ac_param |= (u32) ((cw_min & 0xF) << AC_PARAM_ECW_MIN_OFFSET); - u4b_ac_param |= (u32) ((cw_max & 0xF) << AC_PARAM_ECW_MAX_OFFSET); - u4b_ac_param |= (u32) (tx_op << AC_PARAM_TXOP_OFFSET); - RT_TRACE(rtlpriv, COMP_QOS, DBG_DMESG, - ("queue:%x, ac_param:%x aifs:%x cwmin:%x cwmax:%x txop:%x\n", - aci, u4b_ac_param, mac->ac[aci].aifs, cw_min, - cw_max, tx_op)); switch (aci) { case AC1_BK: - rtl_write_dword(rtlpriv, REG_EDCA_BK_PARAM, u4b_ac_param); + rtl_write_dword(rtlpriv, REG_EDCA_BK_PARAM, 0xa44f); break; case AC0_BE: - rtl_write_dword(rtlpriv, REG_EDCA_BE_PARAM, u4b_ac_param); + /* rtl_write_dword(rtlpriv, REG_EDCA_BE_PARAM, u4b_ac_param); */ break; case AC2_VI: - rtl_write_dword(rtlpriv, REG_EDCA_VI_PARAM, u4b_ac_param); + rtl_write_dword(rtlpriv, REG_EDCA_VI_PARAM, 0x5e4322); break; case AC3_VO: - rtl_write_dword(rtlpriv, REG_EDCA_VO_PARAM, u4b_ac_param); + rtl_write_dword(rtlpriv, REG_EDCA_VO_PARAM, 0x2f3222); break; default: RT_ASSERT(false, ("invalid aci: %d !\n", aci)); @@ -1227,8 +1203,10 @@ void rtl92ce_disable_interrupt(struct ieee80211_hw *hw) static void _rtl92ce_poweroff_adapter(struct ieee80211_hw *hw) { struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_pci_priv *rtlpcipriv = rtl_pcipriv(hw); struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); u8 u1b_tmp; + u32 u4b_tmp; rtlpriv->intf_ops->enable_aspm(hw); rtl_write_byte(rtlpriv, REG_TXPAUSE, 0xFF); @@ -1243,13 +1221,27 @@ static void _rtl92ce_poweroff_adapter(struct ieee80211_hw *hw) rtl_write_byte(rtlpriv, REG_MCUFWDL, 0x00); rtl_write_dword(rtlpriv, REG_GPIO_PIN_CTRL, 0x00000000); u1b_tmp = rtl_read_byte(rtlpriv, REG_GPIO_PIN_CTRL); - rtl_write_dword(rtlpriv, REG_GPIO_PIN_CTRL, 0x00FF0000 | - (u1b_tmp << 8)); + if ((rtlpcipriv->bt_coexist.bt_coexistence) && + ((rtlpcipriv->bt_coexist.bt_coexist_type == BT_CSR_BC4) || + (rtlpcipriv->bt_coexist.bt_coexist_type == BT_CSR_BC8))) { + rtl_write_dword(rtlpriv, REG_GPIO_PIN_CTRL, 0x00F30000 | + (u1b_tmp << 8)); + } else { + rtl_write_dword(rtlpriv, REG_GPIO_PIN_CTRL, 0x00FF0000 | + (u1b_tmp << 8)); + } rtl_write_word(rtlpriv, REG_GPIO_IO_SEL, 0x0790); rtl_write_word(rtlpriv, REG_LEDCFG0, 0x8080); rtl_write_byte(rtlpriv, REG_AFE_PLL_CTRL, 0x80); rtl_write_byte(rtlpriv, REG_SPS0_CTRL, 0x23); - rtl_write_byte(rtlpriv, REG_AFE_XTAL_CTRL, 0x0e); + if (rtlpcipriv->bt_coexist.bt_coexistence) { + u4b_tmp = rtl_read_dword(rtlpriv, REG_AFE_XTAL_CTRL); + u4b_tmp |= 0x03824800; + rtl_write_dword(rtlpriv, REG_AFE_XTAL_CTRL, u4b_tmp); + } else { + rtl_write_dword(rtlpriv, REG_AFE_XTAL_CTRL, 0x0e); + } + rtl_write_byte(rtlpriv, REG_RSV_CTRL, 0x0e); rtl_write_byte(rtlpriv, REG_APS_FSMCO + 1, 0x10); } @@ -1327,6 +1319,7 @@ void rtl92ce_update_interrupt_mask(struct ieee80211_hw *hw, RT_TRACE(rtlpriv, COMP_INTR, DBG_LOUD, ("add_msr:%x, rm_msr:%x\n", add_msr, rm_msr)); + if (add_msr) rtlpci->irq_mask[0] |= add_msr; if (rm_msr) @@ -1582,7 +1575,7 @@ static void _rtl92ce_read_adapter_info(struct ieee80211_hw *hw) ("RTL819X Not boot from eeprom, check it !!")); } - RT_PRINT_DATA(rtlpriv, COMP_INIT, DBG_LOUD, ("MAP\n"), + RT_PRINT_DATA(rtlpriv, COMP_INIT, DBG_DMESG, ("MAP\n"), hwinfo, HWSET_MAX_SIZE); eeprom_id = *((u16 *)&hwinfo[0]); @@ -1610,6 +1603,10 @@ static void _rtl92ce_read_adapter_info(struct ieee80211_hw *hw) rtlefuse->autoload_failflag, hwinfo); + rtl8192ce_read_bt_coexist_info_from_hwpg(hw, + rtlefuse->autoload_failflag, + hwinfo); + rtlefuse->eeprom_channelplan = *(u8 *)&hwinfo[EEPROM_CHANNELPLAN]; rtlefuse->eeprom_version = *(u16 *)&hwinfo[EEPROM_VERSION]; rtlefuse->txpwr_fromeprom = true; @@ -1618,6 +1615,9 @@ static void _rtl92ce_read_adapter_info(struct ieee80211_hw *hw) RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, ("EEPROM Customer ID: 0x%2x\n", rtlefuse->eeprom_oemid)); + /* set channel paln to world wide 13 */ + rtlefuse->channel_plan = COUNTRY_CODE_WORLD_WIDE_13; + if (rtlhal->oem_id == RT_CID_DEFAULT) { switch (rtlefuse->eeprom_oemid) { case EEPROM_CID_DEFAULT: @@ -1701,30 +1701,36 @@ void rtl92ce_read_eeprom_info(struct ieee80211_hw *hw) } else { RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, ("Autoload ERR!!\n")); } - _rtl92ce_hal_customized_behavior(hw); } -void rtl92ce_update_hal_rate_table(struct ieee80211_hw *hw) +static void rtl92ce_update_hal_rate_table(struct ieee80211_hw *hw, + struct ieee80211_sta *sta) { struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_pci_priv *rtlpcipriv = rtl_pcipriv(hw); struct rtl_phy *rtlphy = &(rtlpriv->phy); struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); - - u32 ratr_value = (u32) mac->basic_rates; - u8 *mcsrate = mac->mcs; + struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); + u32 ratr_value; u8 ratr_index = 0; u8 nmode = mac->ht_enable; - u8 mimo_ps = 1; + u8 mimo_ps = IEEE80211_SMPS_OFF; u16 shortgi_rate; u32 tmp_ratr_value; u8 curtxbw_40mhz = mac->bw_40; - u8 curshortgi_40mhz = mac->sgi_40; - u8 curshortgi_20mhz = mac->sgi_20; + u8 curshortgi_40mhz = (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_40) ? + 1 : 0; + u8 curshortgi_20mhz = (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_20) ? + 1 : 0; enum wireless_mode wirelessmode = mac->mode; - ratr_value |= ((*(u16 *) (mcsrate))) << 12; - + if (rtlhal->current_bandtype == BAND_ON_5G) + ratr_value = sta->supp_rates[1] << 4; + else + ratr_value = sta->supp_rates[0]; + ratr_value |= (sta->ht_cap.mcs.rx_mask[1] << 20 | + sta->ht_cap.mcs.rx_mask[0] << 12); switch (wirelessmode) { case WIRELESS_MODE_B: if (ratr_value & 0x0000000c) @@ -1738,7 +1744,7 @@ void rtl92ce_update_hal_rate_table(struct ieee80211_hw *hw) case WIRELESS_MODE_N_24G: case WIRELESS_MODE_N_5G: nmode = 1; - if (mimo_ps == 0) { + if (mimo_ps == IEEE80211_SMPS_STATIC) { ratr_value &= 0x0007F005; } else { u32 ratr_mask; @@ -1761,10 +1767,19 @@ void rtl92ce_update_hal_rate_table(struct ieee80211_hw *hw) break; } - ratr_value &= 0x0FFFFFFF; + if ((rtlpcipriv->bt_coexist.bt_coexistence) && + (rtlpcipriv->bt_coexist.bt_coexist_type == BT_CSR_BC4) && + (rtlpcipriv->bt_coexist.bt_cur_state) && + (rtlpcipriv->bt_coexist.bt_ant_isolation) && + ((rtlpcipriv->bt_coexist.bt_service == BT_SCO) || + (rtlpcipriv->bt_coexist.bt_service == BT_BUSY))) + ratr_value &= 0x0fffcfc0; + else + ratr_value &= 0x0FFFFFFF; - if (nmode && ((curtxbw_40mhz && curshortgi_40mhz) || (!curtxbw_40mhz && - curshortgi_20mhz))) { + if (nmode && ((curtxbw_40mhz && + curshortgi_40mhz) || (!curtxbw_40mhz && + curshortgi_20mhz))) { ratr_value |= 0x10000000; tmp_ratr_value = (ratr_value >> 12); @@ -1784,24 +1799,42 @@ void rtl92ce_update_hal_rate_table(struct ieee80211_hw *hw) ("%x\n", rtl_read_dword(rtlpriv, REG_ARFR0))); } -void rtl92ce_update_hal_rate_mask(struct ieee80211_hw *hw, u8 rssi_level) +static void rtl92ce_update_hal_rate_mask(struct ieee80211_hw *hw, + struct ieee80211_sta *sta, u8 rssi_level) { struct rtl_priv *rtlpriv = rtl_priv(hw); struct rtl_phy *rtlphy = &(rtlpriv->phy); struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); - u32 ratr_bitmap = (u32) mac->basic_rates; - u8 *p_mcsrate = mac->mcs; + struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); + struct rtl_sta_info *sta_entry = NULL; + u32 ratr_bitmap; u8 ratr_index; - u8 curtxbw_40mhz = mac->bw_40; - u8 curshortgi_40mhz = mac->sgi_40; - u8 curshortgi_20mhz = mac->sgi_20; - enum wireless_mode wirelessmode = mac->mode; + u8 curtxbw_40mhz = (sta->ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40) + ? 1 : 0; + u8 curshortgi_40mhz = (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_40) ? + 1 : 0; + u8 curshortgi_20mhz = (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_20) ? + 1 : 0; + enum wireless_mode wirelessmode = 0; bool shortgi = false; u8 rate_mask[5]; u8 macid = 0; - u8 mimops = 1; - - ratr_bitmap |= (p_mcsrate[1] << 20) | (p_mcsrate[0] << 12); + u8 mimo_ps = IEEE80211_SMPS_OFF; + + sta_entry = (struct rtl_sta_info *) sta->drv_priv; + wirelessmode = sta_entry->wireless_mode; + if (mac->opmode == NL80211_IFTYPE_STATION) + curtxbw_40mhz = mac->bw_40; + else if (mac->opmode == NL80211_IFTYPE_AP || + mac->opmode == NL80211_IFTYPE_ADHOC) + macid = sta->aid + 1; + + if (rtlhal->current_bandtype == BAND_ON_5G) + ratr_bitmap = sta->supp_rates[1] << 4; + else + ratr_bitmap = sta->supp_rates[0]; + ratr_bitmap |= (sta->ht_cap.mcs.rx_mask[1] << 20 | + sta->ht_cap.mcs.rx_mask[0] << 12); switch (wirelessmode) { case WIRELESS_MODE_B: ratr_index = RATR_INX_WIRELESS_B; @@ -1828,7 +1861,7 @@ void rtl92ce_update_hal_rate_mask(struct ieee80211_hw *hw, u8 rssi_level) case WIRELESS_MODE_N_5G: ratr_index = RATR_INX_WIRELESS_NGB; - if (mimops == 0) { + if (mimo_ps == IEEE80211_SMPS_STATIC) { if (rssi_level == 1) ratr_bitmap &= 0x00070000; else if (rssi_level == 2) @@ -1892,8 +1925,8 @@ void rtl92ce_update_hal_rate_mask(struct ieee80211_hw *hw, u8 rssi_level) } RT_TRACE(rtlpriv, COMP_RATR, DBG_DMESG, ("ratr_bitmap :%x\n", ratr_bitmap)); - *(u32 *)&rate_mask = (ratr_bitmap & 0x0fffffff) | - (ratr_index << 28); + *(u32 *)&rate_mask = EF4BYTE((ratr_bitmap & 0x0fffffff) | + (ratr_index << 28)); rate_mask[4] = macid | (shortgi ? 0x20 : 0x00) | 0x80; RT_TRACE(rtlpriv, COMP_RATR, DBG_DMESG, ("Rate_index:%x, " "ratr_val:%x, %x:%x:%x:%x:%x\n", @@ -1902,6 +1935,20 @@ void rtl92ce_update_hal_rate_mask(struct ieee80211_hw *hw, u8 rssi_level) rate_mask[2], rate_mask[3], rate_mask[4])); rtl92c_fill_h2c_cmd(hw, H2C_RA_MASK, 5, rate_mask); + + if (macid != 0) + sta_entry->ratr_index = ratr_index; +} + +void rtl92ce_update_hal_rate_tbl(struct ieee80211_hw *hw, + struct ieee80211_sta *sta, u8 rssi_level) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + + if (rtlpriv->dm.useramask) + rtl92ce_update_hal_rate_mask(hw, sta, rssi_level); + else + rtl92ce_update_hal_rate_table(hw, sta); } void rtl92ce_update_channel_access_setting(struct ieee80211_hw *hw) @@ -1919,7 +1966,7 @@ void rtl92ce_update_channel_access_setting(struct ieee80211_hw *hw) rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_SIFS, (u8 *)&sifs_timer); } -bool rtl92ce_gpio_radio_on_off_checking(struct ieee80211_hw *hw, u8 * valid) +bool rtl92ce_gpio_radio_on_off_checking(struct ieee80211_hw *hw, u8 *valid) { struct rtl_priv *rtlpriv = rtl_priv(hw); struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); @@ -1929,7 +1976,7 @@ bool rtl92ce_gpio_radio_on_off_checking(struct ieee80211_hw *hw, u8 * valid) bool actuallyset = false; unsigned long flag; - if ((rtlpci->up_first_time == 1) || (rtlpci->being_init_adapter)) + if (rtlpci->being_init_adapter) return false; if (ppsc->swrf_processing) @@ -1946,12 +1993,6 @@ bool rtl92ce_gpio_radio_on_off_checking(struct ieee80211_hw *hw, u8 * valid) cur_rfstate = ppsc->rfpwr_state; - if ((ppsc->reg_rfps_level & RT_RF_OFF_LEVL_ASPM) && - RT_IN_PS_LEVEL(ppsc, RT_RF_OFF_LEVL_ASPM)) { - rtlpriv->intf_ops->disable_aspm(hw); - RT_CLEAR_PS_LEVEL(ppsc, RT_RF_OFF_LEVL_ASPM); - } - rtl_write_byte(rtlpriv, REG_MAC_PINMUX_CFG, rtl_read_byte(rtlpriv, REG_MAC_PINMUX_CFG)&~(BIT(3))); @@ -1976,38 +2017,13 @@ bool rtl92ce_gpio_radio_on_off_checking(struct ieee80211_hw *hw, u8 * valid) } if (actuallyset) { - if (e_rfpowerstate_toset == ERFON) { - if ((ppsc->reg_rfps_level & RT_RF_OFF_LEVL_ASPM) && - RT_IN_PS_LEVEL(ppsc, RT_RF_OFF_LEVL_ASPM)) { - rtlpriv->intf_ops->disable_aspm(hw); - RT_CLEAR_PS_LEVEL(ppsc, RT_RF_OFF_LEVL_ASPM); - } - } - spin_lock_irqsave(&rtlpriv->locks.rf_ps_lock, flag); ppsc->rfchange_inprogress = false; spin_unlock_irqrestore(&rtlpriv->locks.rf_ps_lock, flag); - - if (e_rfpowerstate_toset == ERFOFF) { - if (ppsc->reg_rfps_level & RT_RF_OFF_LEVL_ASPM) { - rtlpriv->intf_ops->enable_aspm(hw); - RT_SET_PS_LEVEL(ppsc, RT_RF_OFF_LEVL_ASPM); - } - } - - } else if (e_rfpowerstate_toset == ERFOFF || cur_rfstate == ERFOFF) { + } else { if (ppsc->reg_rfps_level & RT_RF_OFF_LEVL_HALT_NIC) RT_SET_PS_LEVEL(ppsc, RT_RF_OFF_LEVL_HALT_NIC); - if (ppsc->reg_rfps_level & RT_RF_OFF_LEVL_ASPM) { - rtlpriv->intf_ops->enable_aspm(hw); - RT_SET_PS_LEVEL(ppsc, RT_RF_OFF_LEVL_ASPM); - } - - spin_lock_irqsave(&rtlpriv->locks.rf_ps_lock, flag); - ppsc->rfchange_inprogress = false; - spin_unlock_irqrestore(&rtlpriv->locks.rf_ps_lock, flag); - } else { spin_lock_irqsave(&rtlpriv->locks.rf_ps_lock, flag); ppsc->rfchange_inprogress = false; spin_unlock_irqrestore(&rtlpriv->locks.rf_ps_lock, flag); @@ -2086,15 +2102,31 @@ void rtl92ce_set_key(struct ieee80211_hw *hw, u32 key_index, macaddr = cam_const_broad; entry_id = key_index; } else { + if (mac->opmode == NL80211_IFTYPE_AP) { + entry_id = rtl_cam_get_free_entry(hw, + p_macaddr); + if (entry_id >= TOTAL_CAM_ENTRY) { + RT_TRACE(rtlpriv, COMP_SEC, + DBG_EMERG, + ("Can not find free hw" + " security cam entry\n")); + return; + } + } else { + entry_id = CAM_PAIRWISE_KEY_POSITION; + } + key_index = PAIRWISE_KEYIDX; - entry_id = CAM_PAIRWISE_KEY_POSITION; is_pairwise = true; } } if (rtlpriv->sec.key_len[key_index] == 0) { RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG, - ("delete one entry\n")); + ("delete one entry, entry_id is %d\n", + entry_id)); + if (mac->opmode == NL80211_IFTYPE_AP) + rtl_cam_del_entry(hw, p_macaddr); rtl_cam_delete_one_entry(hw, p_macaddr, entry_id); } else { RT_TRACE(rtlpriv, COMP_SEC, DBG_LOUD, @@ -2146,3 +2178,132 @@ void rtl92ce_set_key(struct ieee80211_hw *hw, u32 key_index, } } } + +void rtl8192ce_bt_var_init(struct ieee80211_hw *hw) +{ + struct rtl_pci_priv *rtlpcipriv = rtl_pcipriv(hw); + + rtlpcipriv->bt_coexist.bt_coexistence = + rtlpcipriv->bt_coexist.eeprom_bt_coexist; + rtlpcipriv->bt_coexist.bt_ant_num = + rtlpcipriv->bt_coexist.eeprom_bt_ant_num; + rtlpcipriv->bt_coexist.bt_coexist_type = + rtlpcipriv->bt_coexist.eeprom_bt_type; + + if (rtlpcipriv->bt_coexist.reg_bt_iso == 2) + rtlpcipriv->bt_coexist.bt_ant_isolation = + rtlpcipriv->bt_coexist.eeprom_bt_ant_isolation; + else + rtlpcipriv->bt_coexist.bt_ant_isolation = + rtlpcipriv->bt_coexist.reg_bt_iso; + + rtlpcipriv->bt_coexist.bt_radio_shared_type = + rtlpcipriv->bt_coexist.eeprom_bt_radio_shared; + + if (rtlpcipriv->bt_coexist.bt_coexistence) { + + if (rtlpcipriv->bt_coexist.reg_bt_sco == 1) + rtlpcipriv->bt_coexist.bt_service = BT_OTHER_ACTION; + else if (rtlpcipriv->bt_coexist.reg_bt_sco == 2) + rtlpcipriv->bt_coexist.bt_service = BT_SCO; + else if (rtlpcipriv->bt_coexist.reg_bt_sco == 4) + rtlpcipriv->bt_coexist.bt_service = BT_BUSY; + else if (rtlpcipriv->bt_coexist.reg_bt_sco == 5) + rtlpcipriv->bt_coexist.bt_service = BT_OTHERBUSY; + else + rtlpcipriv->bt_coexist.bt_service = BT_IDLE; + + rtlpcipriv->bt_coexist.bt_edca_ul = 0; + rtlpcipriv->bt_coexist.bt_edca_dl = 0; + rtlpcipriv->bt_coexist.bt_rssi_state = 0xff; + } +} + +void rtl8192ce_read_bt_coexist_info_from_hwpg(struct ieee80211_hw *hw, + bool auto_load_fail, u8 *hwinfo) +{ + struct rtl_pci_priv *rtlpcipriv = rtl_pcipriv(hw); + u8 value; + + if (!auto_load_fail) { + rtlpcipriv->bt_coexist.eeprom_bt_coexist = + ((hwinfo[RF_OPTION1] & 0xe0) >> 5); + value = hwinfo[RF_OPTION4]; + rtlpcipriv->bt_coexist.eeprom_bt_type = ((value & 0xe) >> 1); + rtlpcipriv->bt_coexist.eeprom_bt_ant_num = (value & 0x1); + rtlpcipriv->bt_coexist.eeprom_bt_ant_isolation = + ((value & 0x10) >> 4); + rtlpcipriv->bt_coexist.eeprom_bt_radio_shared = + ((value & 0x20) >> 5); + } else { + rtlpcipriv->bt_coexist.eeprom_bt_coexist = 0; + rtlpcipriv->bt_coexist.eeprom_bt_type = BT_2WIRE; + rtlpcipriv->bt_coexist.eeprom_bt_ant_num = ANT_X2; + rtlpcipriv->bt_coexist.eeprom_bt_ant_isolation = 0; + rtlpcipriv->bt_coexist.eeprom_bt_radio_shared = BT_RADIO_SHARED; + } + + rtl8192ce_bt_var_init(hw); +} + +void rtl8192ce_bt_reg_init(struct ieee80211_hw *hw) +{ + struct rtl_pci_priv *rtlpcipriv = rtl_pcipriv(hw); + + /* 0:Low, 1:High, 2:From Efuse. */ + rtlpcipriv->bt_coexist.reg_bt_iso = 2; + /* 0:Idle, 1:None-SCO, 2:SCO, 3:From Counter. */ + rtlpcipriv->bt_coexist.reg_bt_sco = 3; + /* 0:Disable BT control A-MPDU, 1:Enable BT control A-MPDU. */ + rtlpcipriv->bt_coexist.reg_bt_sco = 0; +} + + +void rtl8192ce_bt_hw_init(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_phy *rtlphy = &(rtlpriv->phy); + struct rtl_pci_priv *rtlpcipriv = rtl_pcipriv(hw); + + u8 u1_tmp; + + if (rtlpcipriv->bt_coexist.bt_coexistence && + ((rtlpcipriv->bt_coexist.bt_coexist_type == BT_CSR_BC4) || + rtlpcipriv->bt_coexist.bt_coexist_type == BT_CSR_BC8)) { + + if (rtlpcipriv->bt_coexist.bt_ant_isolation) + rtl_write_byte(rtlpriv, REG_GPIO_MUXCFG, 0xa0); + + u1_tmp = rtl_read_byte(rtlpriv, 0x4fd) & + BIT_OFFSET_LEN_MASK_32(0, 1); + u1_tmp = u1_tmp | + ((rtlpcipriv->bt_coexist.bt_ant_isolation == 1) ? + 0 : BIT_OFFSET_LEN_MASK_32(1, 1)) | + ((rtlpcipriv->bt_coexist.bt_service == BT_SCO) ? + 0 : BIT_OFFSET_LEN_MASK_32(2, 1)); + rtl_write_byte(rtlpriv, 0x4fd, u1_tmp); + + rtl_write_dword(rtlpriv, REG_BT_COEX_TABLE+4, 0xaaaa9aaa); + rtl_write_dword(rtlpriv, REG_BT_COEX_TABLE+8, 0xffbd0040); + rtl_write_dword(rtlpriv, REG_BT_COEX_TABLE+0xc, 0x40000010); + + /* Config to 1T1R. */ + if (rtlphy->rf_type == RF_1T1R) { + u1_tmp = rtl_read_byte(rtlpriv, ROFDM0_TRXPATHENABLE); + u1_tmp &= ~(BIT_OFFSET_LEN_MASK_32(1, 1)); + rtl_write_byte(rtlpriv, ROFDM0_TRXPATHENABLE, u1_tmp); + + u1_tmp = rtl_read_byte(rtlpriv, ROFDM1_TRXPATHENABLE); + u1_tmp &= ~(BIT_OFFSET_LEN_MASK_32(1, 1)); + rtl_write_byte(rtlpriv, ROFDM1_TRXPATHENABLE, u1_tmp); + } + } +} + +void rtl92ce_suspend(struct ieee80211_hw *hw) +{ +} + +void rtl92ce_resume(struct ieee80211_hw *hw) +{ +} diff --git a/drivers/net/wireless/rtlwifi/rtl8192ce/hw.h b/drivers/net/wireless/rtlwifi/rtl8192ce/hw.h index a3dfdb6..07dbe3e 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192ce/hw.h +++ b/drivers/net/wireless/rtlwifi/rtl8192ce/hw.h @@ -30,7 +30,18 @@ #ifndef __RTL92CE_HW_H__ #define __RTL92CE_HW_H__ -#define H2C_RA_MASK 6 +static inline u8 _rtl92c_get_chnl_group(u8 chnl) +{ + u8 group; + + if (chnl < 3) + group = 0; + else if (chnl < 9) + group = 1; + else + group = 2; + return group; +} void rtl92ce_get_hw_reg(struct ieee80211_hw *hw, u8 variable, u8 *val); void rtl92ce_read_eeprom_info(struct ieee80211_hw *hw); @@ -41,28 +52,27 @@ void rtl92ce_card_disable(struct ieee80211_hw *hw); void rtl92ce_enable_interrupt(struct ieee80211_hw *hw); void rtl92ce_disable_interrupt(struct ieee80211_hw *hw); int rtl92ce_set_network_type(struct ieee80211_hw *hw, enum nl80211_iftype type); +void rtl92ce_set_check_bssid(struct ieee80211_hw *hw, bool check_bssid); void rtl92ce_set_qos(struct ieee80211_hw *hw, int aci); void rtl92ce_set_beacon_related_registers(struct ieee80211_hw *hw); void rtl92ce_set_beacon_interval(struct ieee80211_hw *hw); void rtl92ce_update_interrupt_mask(struct ieee80211_hw *hw, u32 add_msr, u32 rm_msr); void rtl92ce_set_hw_reg(struct ieee80211_hw *hw, u8 variable, u8 *val); -void rtl92ce_update_hal_rate_table(struct ieee80211_hw *hw); -void rtl92ce_update_hal_rate_mask(struct ieee80211_hw *hw, u8 rssi_level); +void rtl92ce_update_hal_rate_tbl(struct ieee80211_hw *hw, + struct ieee80211_sta *sta, u8 rssi_level); void rtl92ce_update_channel_access_setting(struct ieee80211_hw *hw); bool rtl92ce_gpio_radio_on_off_checking(struct ieee80211_hw *hw, u8 *valid); void rtl92ce_enable_hw_security_config(struct ieee80211_hw *hw); void rtl92ce_set_key(struct ieee80211_hw *hw, u32 key_index, u8 *p_macaddr, bool is_group, u8 enc_algo, bool is_wepkey, bool clear_all); -bool _rtl92ce_phy_config_mac_with_headerfile(struct ieee80211_hw *hw); -void rtl92c_set_fw_rsvdpagepkt(struct ieee80211_hw *hw, bool b_dl_finished); -void rtl92c_set_fw_pwrmode_cmd(struct ieee80211_hw *hw, u8 mode); -void rtl92c_set_fw_joinbss_report_cmd(struct ieee80211_hw *hw, u8 mstatus); -int rtl92c_download_fw(struct ieee80211_hw *hw); -void rtl92c_firmware_selfreset(struct ieee80211_hw *hw); -void rtl92c_fill_h2c_cmd(struct ieee80211_hw *hw, - u8 element_id, u32 cmd_len, u8 *p_cmdbuffer); -bool rtl92ce_phy_mac_config(struct ieee80211_hw *hw); + +void rtl8192ce_read_bt_coexist_info_from_hwpg(struct ieee80211_hw *hw, + bool autoload_fail, u8 *hwinfo); +void rtl8192ce_bt_reg_init(struct ieee80211_hw *hw); +void rtl8192ce_bt_hw_init(struct ieee80211_hw *hw); +void rtl92ce_suspend(struct ieee80211_hw *hw); +void rtl92ce_resume(struct ieee80211_hw *hw); #endif diff --git a/drivers/net/wireless/rtlwifi/rtl8192ce/sw.c b/drivers/net/wireless/rtlwifi/rtl8192ce/sw.c index f4e2f3d..0042e0e 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192ce/sw.c +++ b/drivers/net/wireless/rtlwifi/rtl8192ce/sw.c @@ -112,10 +112,12 @@ static struct rtl_hal_ops rtl8192ce_hal_ops = { .update_interrupt_mask = rtl92ce_update_interrupt_mask, .get_hw_reg = rtl92ce_get_hw_reg, .set_hw_reg = rtl92ce_set_hw_reg, +#if 0 /* temporary */ .update_rate_table = rtl92ce_update_hal_rate_table, .update_rate_mask = rtl92ce_update_hal_rate_mask, .fill_tx_desc = rtl92ce_tx_fill_desc, .fill_tx_cmddesc = rtl92ce_tx_fill_cmddesc, +#endif .query_rx_desc = rtl92ce_rx_query_desc, .set_channel_access = rtl92ce_update_channel_access_setting, .radio_onoff_checking = rtl92ce_gpio_radio_on_off_checking, diff --git a/drivers/net/wireless/rtlwifi/rtl8192cu/hw.c b/drivers/net/wireless/rtlwifi/rtl8192cu/hw.c index e43be25..be2d60f 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192cu/hw.c +++ b/drivers/net/wireless/rtlwifi/rtl8192cu/hw.c @@ -42,6 +42,7 @@ #include "trx.h" #include "led.h" #include "table.h" +#include "../rtl8192ce/hw.h" static void _rtl92cu_phy_param_tab_init(struct ieee80211_hw *hw) { diff --git a/drivers/net/wireless/rtlwifi/rtl8192cu/hw.h b/drivers/net/wireless/rtlwifi/rtl8192cu/hw.h index 62af555..17dc5a3 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192cu/hw.h +++ b/drivers/net/wireless/rtlwifi/rtl8192cu/hw.h @@ -104,7 +104,7 @@ void rtl92cu_update_hal_rate_mask(struct ieee80211_hw *hw, u8 rssi_level); void rtl92cu_update_channel_access_setting(struct ieee80211_hw *hw); bool rtl92cu_gpio_radio_on_off_checking(struct ieee80211_hw *hw, u8 * valid); void rtl92cu_set_check_bssid(struct ieee80211_hw *hw, bool check_bssid); -u8 _rtl92c_get_chnl_group(u8 chnl); +static u8 _rtl92c_get_chnl_group(u8 chnl); int rtl92c_download_fw(struct ieee80211_hw *hw); void rtl92c_set_fw_pwrmode_cmd(struct ieee80211_hw *hw, u8 mode); void rtl92c_set_fw_rsvdpagepkt(struct ieee80211_hw *hw, bool dl_finished); -- cgit v0.10.2 From 2b8359f85b81dfe02a631e570582290859191756 Mon Sep 17 00:00:00 2001 From: Chaoming_Li Date: Mon, 25 Apr 2011 12:53:55 -0500 Subject: rtlwifi: rtl8192ce: Change sw and LED routines for addition of rtl8192se and rtl8192de Change rtl8192ce sw and LED routines for addition of RTL8192SE and RTL8192DE. Signed-off-by: Chaoming_Li Signed-off-by: Larry Finger Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/rtlwifi/rtl8192c/dm_common.c b/drivers/net/wireless/rtlwifi/rtl8192c/dm_common.c index 2836d7e..bfc8405 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192c/dm_common.c +++ b/drivers/net/wireless/rtlwifi/rtl8192c/dm_common.c @@ -320,7 +320,7 @@ static void rtl92c_dm_ctrl_initgain_by_rssi(struct ieee80211_hw *hw) static void rtl92c_dm_initial_gain_multi_sta(struct ieee80211_hw *hw) { - static u8 binitialized; /* initialized to false */ + static u8 initialized; /* initialized to false */ struct rtl_priv *rtlpriv = rtl_priv(hw); struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); long rssi_strength = rtlpriv->dm.entry_min_undecoratedsmoothed_pwdb; @@ -331,11 +331,11 @@ static void rtl92c_dm_initial_gain_multi_sta(struct ieee80211_hw *hw) if ((multi_sta == false) || (dm_digtable.cursta_connectctate != DIG_STA_DISCONNECT)) { - binitialized = false; + initialized = false; dm_digtable.dig_ext_port_stage = DIG_EXT_PORT_STAGE_MAX; return; - } else if (binitialized == false) { - binitialized = true; + } else if (initialized == false) { + initialized = true; dm_digtable.dig_ext_port_stage = DIG_EXT_PORT_STAGE_0; dm_digtable.cur_igvalue = 0x20; rtl92c_dm_write_dig(hw); @@ -1513,7 +1513,7 @@ void rtl92c_dm_watchdog(struct ieee80211_hw *hw) } EXPORT_SYMBOL(rtl92c_dm_watchdog); -static u8 rtl92c_bt_rssi_state_change(struct ieee80211_hw *hw) +u8 rtl92c_bt_rssi_state_change(struct ieee80211_hw *hw) { struct rtl_priv *rtlpriv = rtl_priv(hw); struct rtl_pci_priv *rtlpcipriv = rtl_pcipriv(hw); @@ -1570,6 +1570,7 @@ static u8 rtl92c_bt_rssi_state_change(struct ieee80211_hw *hw) return false; } } +EXPORT_SYMBOL(rtl92c_bt_rssi_state_change); static bool rtl92c_bt_state_change(struct ieee80211_hw *hw) { @@ -1820,3 +1821,4 @@ void rtl92c_dm_bt_coexist(struct ieee80211_hw *hw) rtl92c_check_bt_change(hw); } } +EXPORT_SYMBOL(rtl92c_dm_bt_coexist); diff --git a/drivers/net/wireless/rtlwifi/rtl8192ce/dm.c b/drivers/net/wireless/rtlwifi/rtl8192ce/dm.c index 7d76504..2df33e5 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192ce/dm.c +++ b/drivers/net/wireless/rtlwifi/rtl8192ce/dm.c @@ -29,10 +29,12 @@ #include "../wifi.h" #include "../base.h" +#include "../pci.h" #include "reg.h" #include "def.h" #include "phy.h" #include "dm.h" +#include "../rtl8192c/fw_common.h" void rtl92ce_dm_dynamic_txpower(struct ieee80211_hw *hw) { diff --git a/drivers/net/wireless/rtlwifi/rtl8192ce/dm.h b/drivers/net/wireless/rtlwifi/rtl8192ce/dm.h index 36302eb..07dd955 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192ce/dm.h +++ b/drivers/net/wireless/rtlwifi/rtl8192ce/dm.h @@ -192,6 +192,7 @@ void rtl92c_dm_init_edca_turbo(struct ieee80211_hw *hw); void rtl92c_dm_check_txpower_tracking(struct ieee80211_hw *hw); void rtl92c_dm_init_rate_adaptive_mask(struct ieee80211_hw *hw); void rtl92c_dm_rf_saving(struct ieee80211_hw *hw, u8 bforce_in_normal); +void rtl92c_dm_bt_coexist(struct ieee80211_hw *hw); void rtl92ce_dm_dynamic_txpower(struct ieee80211_hw *hw); #endif diff --git a/drivers/net/wireless/rtlwifi/rtl8192ce/led.c b/drivers/net/wireless/rtlwifi/rtl8192ce/led.c index d21b934..9dd1ed7 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192ce/led.c +++ b/drivers/net/wireless/rtlwifi/rtl8192ce/led.c @@ -106,12 +106,11 @@ void rtl92ce_sw_led_off(struct ieee80211_hw *hw, struct rtl_led *pled) void rtl92ce_init_sw_leds(struct ieee80211_hw *hw) { struct rtl_pci_priv *pcipriv = rtl_pcipriv(hw); - _rtl92ce_init_led(hw, &(pcipriv->ledctl.sw_led0), LED_PIN_LED0); _rtl92ce_init_led(hw, &(pcipriv->ledctl.sw_led1), LED_PIN_LED1); } -void _rtl92ce_sw_led_control(struct ieee80211_hw *hw, +static void _rtl92ce_sw_led_control(struct ieee80211_hw *hw, enum led_ctl_mode ledaction) { struct rtl_pci_priv *pcipriv = rtl_pcipriv(hw); @@ -146,7 +145,7 @@ void rtl92ce_led_control(struct ieee80211_hw *hw, ledaction == LED_CTL_POWER_ON)) { return; } - RT_TRACE(rtlpriv, COMP_LED, DBG_LOUD, ("ledaction %d,\n", + RT_TRACE(rtlpriv, COMP_LED, DBG_LOUD, ("ledaction %d.\n", ledaction)); _rtl92ce_sw_led_control(hw, ledaction); } diff --git a/drivers/net/wireless/rtlwifi/rtl8192ce/led.h b/drivers/net/wireless/rtlwifi/rtl8192ce/led.h index 94332b3..7dfccea 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192ce/led.h +++ b/drivers/net/wireless/rtlwifi/rtl8192ce/led.h @@ -34,7 +34,5 @@ void rtl92ce_init_sw_leds(struct ieee80211_hw *hw); void rtl92ce_sw_led_on(struct ieee80211_hw *hw, struct rtl_led *pled); void rtl92ce_sw_led_off(struct ieee80211_hw *hw, struct rtl_led *pled); void rtl92ce_led_control(struct ieee80211_hw *hw, enum led_ctl_mode ledaction); -void _rtl92ce_sw_led_control(struct ieee80211_hw *hw, - enum led_ctl_mode ledaction); #endif diff --git a/drivers/net/wireless/rtlwifi/rtl8192ce/reg.h b/drivers/net/wireless/rtlwifi/rtl8192ce/reg.h index b0868a6..115b3f8 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192ce/reg.h +++ b/drivers/net/wireless/rtlwifi/rtl8192ce/reg.h @@ -72,6 +72,7 @@ #define REG_GPIO_IO_SEL_2 0x0062 /* RTL8723 WIFI/BT/GPS Multi-Function control source. */ #define REG_MULTI_FUNC_CTRL 0x0068 + #define REG_MCUFWDL 0x0080 #define REG_HMEBOX_EXT_0 0x0088 @@ -543,6 +544,8 @@ #define IMR_WLANOFF BIT(0) #define HWSET_MAX_SIZE 128 +#define EFUSE_MAX_SECTION 16 +#define EFUSE_REAL_CONTENT_LEN 512 #define EEPROM_DEFAULT_TSSI 0x0 #define EEPROM_DEFAULT_TXPOWERDIFF 0x0 @@ -656,6 +659,7 @@ #define STOPBE BIT(1) #define STOPBK BIT(0) +#define RCR_APPFCS BIT(31) #define RCR_APP_FCS BIT(31) #define RCR_APP_MIC BIT(30) #define RCR_APP_ICV BIT(29) @@ -688,6 +692,7 @@ #define REG_USB_INFO 0xFE17 #define REG_USB_SPECIAL_OPTION 0xFE55 + #define REG_USB_DMA_AGG_TO 0xFE5B #define REG_USB_AGG_TO 0xFE5C #define REG_USB_AGG_TH 0xFE5D @@ -775,7 +780,6 @@ #define BOOT_FROM_EEPROM BIT(4) #define EEPROM_EN BIT(5) -#define EEPROMSEL BOOT_FROM_EEPROM #define AFE_BGEN BIT(0) #define AFE_MBEN BIT(1) @@ -901,28 +905,7 @@ #define BD_PKG_SEL BIT(25) #define BD_HCI_SEL BIT(26) #define TYPE_ID BIT(27) - -/* REG_GPIO_OUTSTS (For RTL8723 only) */ -#define EFS_HCI_SEL (BIT(0)|BIT(1)) -#define PAD_HCI_SEL (BIT(2)|BIT(3)) -#define HCI_SEL (BIT(4)|BIT(5)) -#define PKG_SEL_HCI BIT(6) -#define FEN_GPS BIT(7) -#define FEN_BT BIT(8) -#define FEN_WL BIT(9) -#define FEN_PCI BIT(10) -#define FEN_USB BIT(11) -#define BTRF_HWPDN_N BIT(12) -#define WLRF_HWPDN_N BIT(13) -#define PDN_BT_N BIT(14) -#define PDN_GPS_N BIT(15) -#define BT_CTL_HWPDN BIT(16) -#define GPS_CTL_HWPDN BIT(17) -#define PPHY_SUSB BIT(20) -#define UPHY_SUSB BIT(21) -#define PCI_SUSEN BIT(22) -#define USB_SUSEN BIT(23) -#define RF_RL_ID (BIT(31) | BIT(30) | BIT(29) | BIT(28)) +#define RF_RL_ID (BIT(31) | BIT(30) | BIT(29) | BIT(28)) #define CHIP_VER_RTL_MASK 0xF000 #define CHIP_VER_RTL_SHIFT 12 @@ -1077,6 +1060,7 @@ #define _RARF_RC8(x) (((x) & 0x1F) << 24) #define AC_PARAM_TXOP_OFFSET 16 +#define AC_PARAM_TXOP_LIMIT_OFFSET 16 #define AC_PARAM_ECW_MAX_OFFSET 12 #define AC_PARAM_ECW_MIN_OFFSET 8 #define AC_PARAM_AIFS_OFFSET 0 @@ -1221,33 +1205,11 @@ #define EPROM_CMD_CONFIG 0x3 #define EPROM_CMD_LOAD 1 -#define HWSET_MAX_SIZE_92S HWSET_MAX_SIZE +#define HWSET_MAX_SIZE_92S HWSET_MAX_SIZE -#define HAL_8192C_HW_GPIO_WPS_BIT BIT(2) - -/* REG_MULTI_FUNC_CTRL(For RTL8723 Only) */ -/* Enable GPIO[9] as WiFi HW PDn source */ #define WL_HWPDN_EN BIT(0) -/* WiFi HW PDn polarity control */ -#define WL_HWPDN_SL BIT(1) -/* WiFi function enable */ -#define WL_FUNC_EN BIT(2) -/* Enable GPIO[9] as WiFi RF HW PDn source */ -#define WL_HWROF_EN BIT(3) -/* Enable GPIO[11] as BT HW PDn source */ -#define BT_HWPDN_EN BIT(16) -/* BT HW PDn polarity control */ -#define BT_HWPDN_SL BIT(17) -/* BT function enable */ -#define BT_FUNC_EN BIT(18) -/* Enable GPIO[11] as BT/GPS RF HW PDn source */ -#define BT_HWROF_EN BIT(19) -/* Enable GPIO[10] as GPS HW PDn source */ -#define GPS_HWPDN_EN BIT(20) -/* GPS HW PDn polarity control */ -#define GPS_HWPDN_SL BIT(21) -/* GPS function enable */ -#define GPS_FUNC_EN BIT(22) + +#define HAL_8192C_HW_GPIO_WPS_BIT BIT(2) #define RPMAC_RESET 0x100 #define RPMAC_TXSTART 0x104 diff --git a/drivers/net/wireless/rtlwifi/rtl8192ce/sw.c b/drivers/net/wireless/rtlwifi/rtl8192ce/sw.c index 0042e0e..5c920c6 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192ce/sw.c +++ b/drivers/net/wireless/rtlwifi/rtl8192ce/sw.c @@ -42,10 +42,58 @@ #include "trx.h" #include "led.h" +void rtl92c_init_aspm_vars(struct ieee80211_hw *hw) +{ + struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); + + /*close ASPM for AMD defaultly */ + rtlpci->const_amdpci_aspm = 0; + + /* + * ASPM PS mode. + * 0 - Disable ASPM, + * 1 - Enable ASPM without Clock Req, + * 2 - Enable ASPM with Clock Req, + * 3 - Alwyas Enable ASPM with Clock Req, + * 4 - Always Enable ASPM without Clock Req. + * set defult to RTL8192CE:3 RTL8192E:2 + * */ + rtlpci->const_pci_aspm = 3; + + /*Setting for PCI-E device */ + rtlpci->const_devicepci_aspm_setting = 0x03; + + /*Setting for PCI-E bridge */ + rtlpci->const_hostpci_aspm_setting = 0x02; + + /* + * In Hw/Sw Radio Off situation. + * 0 - Default, + * 1 - From ASPM setting without low Mac Pwr, + * 2 - From ASPM setting with low Mac Pwr, + * 3 - Bus D3 + * set default to RTL8192CE:0 RTL8192SE:2 + */ + rtlpci->const_hwsw_rfoff_d3 = 0; + + /* + * This setting works for those device with + * backdoor ASPM setting such as EPHY setting. + * 0 - Not support ASPM, + * 1 - Support ASPM, + * 2 - According to chipset. + */ + rtlpci->const_support_pciaspm = 1; +} + int rtl92c_init_sw_vars(struct ieee80211_hw *hw) { + int err; struct rtl_priv *rtlpriv = rtl_priv(hw); struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); + const struct firmware *firmware; + + rtl8192ce_bt_reg_init(hw); rtlpriv->dm.dm_initialgain_enable = 1; rtlpriv->dm.dm_flag = 0; @@ -53,7 +101,12 @@ int rtl92c_init_sw_vars(struct ieee80211_hw *hw) rtlpriv->dm.thermalvalue = 0; rtlpci->transmit_config = CFENDFORM | BIT(12) | BIT(13); - rtlpci->receive_config = (RCR_APP_FCS | + /* compatible 5G band 88ce just 2.4G band & smsp */ + rtlpriv->rtlhal.current_bandtype = BAND_ON_2_4G; + rtlpriv->rtlhal.bandset = BAND_ON_2_4G; + rtlpriv->rtlhal.macphymode = SINGLEMAC_SINGLEPHY; + + rtlpci->receive_config = (RCR_APPFCS | RCR_AMF | RCR_ADF | RCR_APP_MIC | @@ -76,13 +129,49 @@ int rtl92c_init_sw_vars(struct ieee80211_hw *hw) rtlpci->irq_mask[1] = (u32) (IMR_CPWM | IMR_C2HCMD | 0); - rtlpriv->rtlhal.pfirmware = (u8 *) vmalloc(0x4000); + /* for LPS & IPS */ + rtlpriv->psc.inactiveps = rtlpriv->cfg->mod_params->inactiveps; + rtlpriv->psc.swctrl_lps = rtlpriv->cfg->mod_params->swctrl_lps; + rtlpriv->psc.fwctrl_lps = rtlpriv->cfg->mod_params->fwctrl_lps; + rtlpriv->psc.reg_fwctrl_lps = 3; + rtlpriv->psc.reg_max_lps_awakeintvl = 5; + /* for ASPM, you can close aspm through + * set const_support_pciaspm = 0 */ + rtl92c_init_aspm_vars(hw); + + if (rtlpriv->psc.reg_fwctrl_lps == 1) + rtlpriv->psc.fwctrl_psmode = FW_PS_MIN_MODE; + else if (rtlpriv->psc.reg_fwctrl_lps == 2) + rtlpriv->psc.fwctrl_psmode = FW_PS_MAX_MODE; + else if (rtlpriv->psc.reg_fwctrl_lps == 3) + rtlpriv->psc.fwctrl_psmode = FW_PS_DTIM_MODE; + + /* for firmware buf */ + rtlpriv->rtlhal.pfirmware = vzalloc(0x4000); if (!rtlpriv->rtlhal.pfirmware) { RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, ("Can't alloc buffer for fw.\n")); return 1; } + /* request fw */ + err = request_firmware(&firmware, rtlpriv->cfg->fw_name, + rtlpriv->io.dev); + if (err) { + RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, + ("Failed to request firmware!\n")); + return 1; + } + if (firmware->size > 0x4000) { + RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, + ("Firmware is too big!\n")); + release_firmware(firmware); + return 1; + } + memcpy(rtlpriv->rtlhal.pfirmware, firmware->data, firmware->size); + rtlpriv->rtlhal.fwsize = firmware->size; + release_firmware(firmware); + return 0; } @@ -96,28 +185,28 @@ void rtl92c_deinit_sw_vars(struct ieee80211_hw *hw) } } -static struct rtl_hal_ops rtl8192ce_hal_ops = { +struct rtl_hal_ops rtl8192ce_hal_ops = { .init_sw_vars = rtl92c_init_sw_vars, .deinit_sw_vars = rtl92c_deinit_sw_vars, .read_eeprom_info = rtl92ce_read_eeprom_info, .interrupt_recognized = rtl92ce_interrupt_recognized, .hw_init = rtl92ce_hw_init, .hw_disable = rtl92ce_card_disable, + .hw_suspend = rtl92ce_suspend, + .hw_resume = rtl92ce_resume, .enable_interrupt = rtl92ce_enable_interrupt, .disable_interrupt = rtl92ce_disable_interrupt, .set_network_type = rtl92ce_set_network_type, + .set_chk_bssid = rtl92ce_set_check_bssid, .set_qos = rtl92ce_set_qos, .set_bcn_reg = rtl92ce_set_beacon_related_registers, .set_bcn_intv = rtl92ce_set_beacon_interval, .update_interrupt_mask = rtl92ce_update_interrupt_mask, .get_hw_reg = rtl92ce_get_hw_reg, .set_hw_reg = rtl92ce_set_hw_reg, -#if 0 /* temporary */ - .update_rate_table = rtl92ce_update_hal_rate_table, - .update_rate_mask = rtl92ce_update_hal_rate_mask, + .update_rate_tbl = rtl92ce_update_hal_rate_tbl, .fill_tx_desc = rtl92ce_tx_fill_desc, .fill_tx_cmddesc = rtl92ce_tx_fill_cmddesc, -#endif .query_rx_desc = rtl92ce_rx_query_desc, .set_channel_access = rtl92ce_update_channel_access_setting, .radio_onoff_checking = rtl92ce_gpio_radio_on_off_checking, @@ -125,7 +214,8 @@ static struct rtl_hal_ops rtl8192ce_hal_ops = { .switch_channel = rtl92c_phy_sw_chnl, .dm_watchdog = rtl92c_dm_watchdog, .scan_operation_backup = rtl92c_phy_scan_operation_backup, - .set_rf_power_state = rtl92ce_phy_set_rf_power_state, +#if 0 /* temporary */ + .set_rf_power_state = rtl92c_phy_set_rf_power_state, .led_control = rtl92ce_led_control, .set_desc = rtl92ce_set_desc, .get_desc = rtl92ce_get_desc, @@ -135,24 +225,28 @@ static struct rtl_hal_ops rtl8192ce_hal_ops = { .init_sw_leds = rtl92ce_init_sw_leds, .get_bbreg = rtl92c_phy_query_bb_reg, .set_bbreg = rtl92c_phy_set_bb_reg, - .get_rfreg = rtl92ce_phy_query_rf_reg, .set_rfreg = rtl92ce_phy_set_rf_reg, - .cmd_send_packet = _rtl92c_cmd_send_packet, + .get_rfreg = rtl92c_phy_query_rf_reg, .phy_rf6052_config = rtl92ce_phy_rf6052_config, .phy_rf6052_set_cck_txpower = rtl92ce_phy_rf6052_set_cck_txpower, .phy_rf6052_set_ofdm_txpower = rtl92ce_phy_rf6052_set_ofdm_txpower, .config_bb_with_headerfile = _rtl92ce_phy_config_bb_with_headerfile, .config_bb_with_pgheaderfile = _rtl92ce_phy_config_bb_with_pgheaderfile, .phy_lc_calibrate = _rtl92ce_phy_lc_calibrate, - .phy_set_bw_mode_callback = rtl92ce_phy_set_bw_mode_callback, .dm_dynamic_txpower = rtl92ce_dm_dynamic_txpower, +#endif }; -static struct rtl_mod_params rtl92ce_mod_params = { - .sw_crypto = 0, +struct rtl_mod_params rtl92ce_mod_params = { + .sw_crypto = false, + .inactiveps = true, + .swctrl_lps = false, + .fwctrl_lps = true, }; -static struct rtl_hal_cfg rtl92ce_hal_cfg = { +struct rtl_hal_cfg rtl92ce_hal_cfg = { + .bar_id = 2, + .write_readback = true, .name = "rtl92c_pci", .fw_name = "rtlwifi/rtl8192cfw.bin", .ops = &rtl8192ce_hal_ops, @@ -176,6 +270,8 @@ static struct rtl_hal_cfg rtl92ce_hal_cfg = { .maps[EFUSE_LOADER_CLK_EN] = LOADER_CLK_EN, .maps[EFUSE_ANA8M] = EFUSE_ANA8M, .maps[EFUSE_HWSET_MAX_SIZE] = HWSET_MAX_SIZE, + .maps[EFUSE_MAX_SECTION_MAP] = EFUSE_MAX_SECTION, + .maps[EFUSE_REAL_CONTENT_SIZE] = EFUSE_REAL_CONTENT_LEN, .maps[RWCAM] = REG_CAMCMD, .maps[WCAMI] = REG_CAMWRITE, @@ -240,7 +336,7 @@ static struct rtl_hal_cfg rtl92ce_hal_cfg = { .maps[RTL_RC_HT_RATEMCS15] = DESC92C_RATEMCS15, }; -static struct pci_device_id rtl92ce_pci_ids[] __devinitdata = { +DEFINE_PCI_DEVICE_TABLE(rtl92ce_pci_ids) = { {RTL_PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0x8191, rtl92ce_hal_cfg)}, {RTL_PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0x8178, rtl92ce_hal_cfg)}, {RTL_PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0x8177, rtl92ce_hal_cfg)}, @@ -258,7 +354,13 @@ MODULE_DESCRIPTION("Realtek 8192C/8188C 802.11n PCI wireless"); MODULE_FIRMWARE("rtlwifi/rtl8192cfw.bin"); module_param_named(swenc, rtl92ce_mod_params.sw_crypto, bool, 0444); +module_param_named(ips, rtl92ce_mod_params.inactiveps, bool, 0444); +module_param_named(swlps, rtl92ce_mod_params.swctrl_lps, bool, 0444); +module_param_named(fwlps, rtl92ce_mod_params.fwctrl_lps, bool, 0444); MODULE_PARM_DESC(swenc, "using hardware crypto (default 0 [hardware])\n"); +MODULE_PARM_DESC(ips, "using no link power save (default 1 is open)\n"); +MODULE_PARM_DESC(fwlps, "using linked fw control power save " + "(default 1 is open)\n"); static struct pci_driver rtl92ce_driver = { .name = KBUILD_MODNAME, diff --git a/drivers/net/wireless/rtlwifi/rtl8192ce/sw.h b/drivers/net/wireless/rtlwifi/rtl8192ce/sw.h index 36e6576..b7dc326 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192ce/sw.h +++ b/drivers/net/wireless/rtlwifi/rtl8192ce/sw.h @@ -33,19 +33,9 @@ int rtl92c_init_sw_vars(struct ieee80211_hw *hw); void rtl92c_deinit_sw_vars(struct ieee80211_hw *hw); void rtl92c_init_var_map(struct ieee80211_hw *hw); -bool _rtl92c_cmd_send_packet(struct ieee80211_hw *hw, - struct sk_buff *skb); -void rtl92ce_phy_rf6052_set_cck_txpower(struct ieee80211_hw *hw, - u8 *ppowerlevel); -void rtl92ce_phy_rf6052_set_ofdm_txpower(struct ieee80211_hw *hw, - u8 *ppowerlevel, u8 channel); bool _rtl92ce_phy_config_bb_with_headerfile(struct ieee80211_hw *hw, - u8 configtype); + u8 configtype); bool _rtl92ce_phy_config_bb_with_pgheaderfile(struct ieee80211_hw *hw, - u8 configtype); -void _rtl92ce_phy_lc_calibrate(struct ieee80211_hw *hw, bool is2t); -u32 rtl92ce_phy_query_rf_reg(struct ieee80211_hw *hw, - enum radio_path rfpath, u32 regaddr, u32 bitmask); -void rtl92ce_phy_set_bw_mode_callback(struct ieee80211_hw *hw); + u8 configtype); #endif diff --git a/drivers/net/wireless/rtlwifi/rtl8192cu/hw.c b/drivers/net/wireless/rtlwifi/rtl8192cu/hw.c index be2d60f..861f39f 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192cu/hw.c +++ b/drivers/net/wireless/rtlwifi/rtl8192cu/hw.c @@ -606,10 +606,12 @@ void rtl92cu_read_eeprom_info(struct ieee80211_hw *hw) if (!IS_NORMAL_CHIP(rtlhal->version)) return; tmp_u1b = rtl_read_byte(rtlpriv, REG_9346CR); +#if 0 /* temporary */ rtlefuse->epromtype = (tmp_u1b & EEPROMSEL) ? EEPROM_93C46 : EEPROM_BOOT_EFUSE; RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, ("Boot from %s\n", (tmp_u1b & EEPROMSEL) ? "EERROM" : "EFUSE")); +#endif rtlefuse->autoload_failflag = (tmp_u1b & EEPROM_EN) ? false : true; RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, ("Autoload %s\n", (tmp_u1b & EEPROM_EN) ? "OK!!" : "ERR!!")); -- cgit v0.10.2 From e0b5a5078675f58736787982af811244eeb98081 Mon Sep 17 00:00:00 2001 From: Chaoming_Li Date: Mon, 25 Apr 2011 12:54:00 -0500 Subject: rtlwifi: rtl8192ce: Change phy and rc routines for addition of rtl8192se and rtl8192de Change rtl8192ce routines phy and rc for addition of RTL8192SE and RTL8192DE. Signed-off-by: Chaoming_Li Signed-off-by: Larry Finger Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/rtlwifi/rtl8192ce/phy.c b/drivers/net/wireless/rtlwifi/rtl8192ce/phy.c index d0541e8..bbba6f8 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192ce/phy.c +++ b/drivers/net/wireless/rtlwifi/rtl8192ce/phy.c @@ -38,7 +38,9 @@ #include "dm.h" #include "table.h" -u32 rtl92ce_phy_query_rf_reg(struct ieee80211_hw *hw, +static bool _rtl92c_phy_config_mac_with_headerfile(struct ieee80211_hw *hw); + +u32 rtl92c_phy_query_rf_reg(struct ieee80211_hw *hw, enum radio_path rfpath, u32 regaddr, u32 bitmask) { struct rtl_priv *rtlpriv = rtl_priv(hw); @@ -73,9 +75,47 @@ u32 rtl92ce_phy_query_rf_reg(struct ieee80211_hw *hw, return readback_value; } +bool rtl92c_phy_mac_config(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); + bool is92c = IS_92C_SERIAL(rtlhal->version); + bool rtstatus = _rtl92c_phy_config_mac_with_headerfile(hw); + + if (is92c) + rtl_write_byte(rtlpriv, 0x14, 0x71); + return rtstatus; +} + +bool rtl92c_phy_bb_config(struct ieee80211_hw *hw) +{ + bool rtstatus = true; + struct rtl_priv *rtlpriv = rtl_priv(hw); + u16 regval; + u32 regvaldw; + u8 reg_hwparafile = 1; + + _rtl92c_phy_init_bb_rf_register_definition(hw); + regval = rtl_read_word(rtlpriv, REG_SYS_FUNC_EN); + rtl_write_word(rtlpriv, REG_SYS_FUNC_EN, + regval | BIT(13) | BIT(0) | BIT(1)); + rtl_write_byte(rtlpriv, REG_AFE_PLL_CTRL, 0x83); + rtl_write_byte(rtlpriv, REG_AFE_PLL_CTRL + 1, 0xdb); + rtl_write_byte(rtlpriv, REG_RF_CTRL, RF_EN | RF_RSTB | RF_SDMRSTB); + rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN, + FEN_PPLL | FEN_PCIEA | FEN_DIO_PCIE | + FEN_BB_GLB_RSTn | FEN_BBRSTB); + rtl_write_byte(rtlpriv, REG_AFE_XTAL_CTRL + 1, 0x80); + regvaldw = rtl_read_dword(rtlpriv, REG_LEDCFG0); + rtl_write_dword(rtlpriv, REG_LEDCFG0, regvaldw | BIT(23)); + if (reg_hwparafile == 1) + rtstatus = _rtl92c_phy_bb8192c_config_parafile(hw); + return rtstatus; +} + void rtl92ce_phy_set_rf_reg(struct ieee80211_hw *hw, - enum radio_path rfpath, - u32 regaddr, u32 bitmask, u32 data) + enum radio_path rfpath, + u32 regaddr, u32 bitmask, u32 data) { struct rtl_priv *rtlpriv = rtl_priv(hw); struct rtl_phy *rtlphy = &(rtlpriv->phy); @@ -121,45 +161,7 @@ void rtl92ce_phy_set_rf_reg(struct ieee80211_hw *hw, bitmask, data, rfpath)); } -bool rtl92ce_phy_mac_config(struct ieee80211_hw *hw) -{ - struct rtl_priv *rtlpriv = rtl_priv(hw); - struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); - bool is92c = IS_92C_SERIAL(rtlhal->version); - bool rtstatus = _rtl92ce_phy_config_mac_with_headerfile(hw); - - if (is92c) - rtl_write_byte(rtlpriv, 0x14, 0x71); - return rtstatus; -} - -bool rtl92ce_phy_bb_config(struct ieee80211_hw *hw) -{ - bool rtstatus = true; - struct rtl_priv *rtlpriv = rtl_priv(hw); - u16 regval; - u32 regvaldw; - u8 reg_hwparafile = 1; - - _rtl92c_phy_init_bb_rf_register_definition(hw); - regval = rtl_read_word(rtlpriv, REG_SYS_FUNC_EN); - rtl_write_word(rtlpriv, REG_SYS_FUNC_EN, - regval | BIT(13) | BIT(0) | BIT(1)); - rtl_write_byte(rtlpriv, REG_AFE_PLL_CTRL, 0x83); - rtl_write_byte(rtlpriv, REG_AFE_PLL_CTRL + 1, 0xdb); - rtl_write_byte(rtlpriv, REG_RF_CTRL, RF_EN | RF_RSTB | RF_SDMRSTB); - rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN, - FEN_PPLL | FEN_PCIEA | FEN_DIO_PCIE | - FEN_BB_GLB_RSTn | FEN_BBRSTB); - rtl_write_byte(rtlpriv, REG_AFE_XTAL_CTRL + 1, 0x80); - regvaldw = rtl_read_dword(rtlpriv, REG_LEDCFG0); - rtl_write_dword(rtlpriv, REG_LEDCFG0, regvaldw | BIT(23)); - if (reg_hwparafile == 1) - rtstatus = _rtl92c_phy_bb8192c_config_parafile(hw); - return rtstatus; -} - -bool _rtl92ce_phy_config_mac_with_headerfile(struct ieee80211_hw *hw) +static bool _rtl92c_phy_config_mac_with_headerfile(struct ieee80211_hw *hw) { struct rtl_priv *rtlpriv = rtl_priv(hw); u32 i; @@ -177,7 +179,7 @@ bool _rtl92ce_phy_config_mac_with_headerfile(struct ieee80211_hw *hw) } bool _rtl92ce_phy_config_bb_with_headerfile(struct ieee80211_hw *hw, - u8 configtype) + u8 configtype) { int i; u32 *phy_regarray_table; @@ -236,7 +238,7 @@ bool _rtl92ce_phy_config_bb_with_headerfile(struct ieee80211_hw *hw, } bool _rtl92ce_phy_config_bb_with_pgheaderfile(struct ieee80211_hw *hw, - u8 configtype) + u8 configtype) { struct rtl_priv *rtlpriv = rtl_priv(hw); int i; @@ -274,7 +276,7 @@ bool _rtl92ce_phy_config_bb_with_pgheaderfile(struct ieee80211_hw *hw, return true; } -bool rtl92ce_phy_config_rf_with_headerfile(struct ieee80211_hw *hw, +bool rtl92c_phy_config_rf_with_headerfile(struct ieee80211_hw *hw, enum radio_path rfpath) { @@ -364,7 +366,7 @@ bool rtl92ce_phy_config_rf_with_headerfile(struct ieee80211_hw *hw, return true; } -void rtl92ce_phy_set_bw_mode_callback(struct ieee80211_hw *hw) +static void rtl92c_phy_set_bw_mode_callback(struct ieee80211_hw *hw) { struct rtl_priv *rtlpriv = rtl_priv(hw); struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); @@ -378,8 +380,10 @@ void rtl92ce_phy_set_bw_mode_callback(struct ieee80211_hw *hw) rtlphy->current_chan_bw == HT_CHANNEL_WIDTH_20 ? "20MHz" : "40MHz")) - if (is_hal_stop(rtlhal)) + if (is_hal_stop(rtlhal)) { + rtlphy->set_bwmode_inprogress = false; return; + } reg_bw_opmode = rtl_read_byte(rtlpriv, REG_BWOPMODE); reg_prsr_rsc = rtl_read_byte(rtlpriv, REG_RRSR + 2); @@ -389,16 +393,13 @@ void rtl92ce_phy_set_bw_mode_callback(struct ieee80211_hw *hw) reg_bw_opmode |= BW_OPMODE_20MHZ; rtl_write_byte(rtlpriv, REG_BWOPMODE, reg_bw_opmode); break; - case HT_CHANNEL_WIDTH_20_40: reg_bw_opmode &= ~BW_OPMODE_20MHZ; rtl_write_byte(rtlpriv, REG_BWOPMODE, reg_bw_opmode); - reg_prsr_rsc = (reg_prsr_rsc & 0x90) | (mac->cur_40_prime_sc << 5); rtl_write_byte(rtlpriv, REG_RRSR + 2, reg_prsr_rsc); break; - default: RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, ("unknown bandwidth: %#X\n", rtlphy->current_chan_bw)); @@ -414,10 +415,12 @@ void rtl92ce_phy_set_bw_mode_callback(struct ieee80211_hw *hw) case HT_CHANNEL_WIDTH_20_40: rtl_set_bbreg(hw, RFPGA0_RFMOD, BRFMOD, 0x1); rtl_set_bbreg(hw, RFPGA1_RFMOD, BRFMOD, 0x1); + rtl_set_bbreg(hw, RCCK0_SYSTEM, BCCK_SIDEBAND, (mac->cur_40_prime_sc >> 1)); rtl_set_bbreg(hw, ROFDM1_LSTF, 0xC00, mac->cur_40_prime_sc); rtl_set_bbreg(hw, RFPGA0_ANALOGPARAMETER2, BIT(10), 0); + rtl_set_bbreg(hw, 0x818, (BIT(26) | BIT(27)), (mac->cur_40_prime_sc == HAL_PRIME_CHNL_OFFSET_LOWER) ? 2 : 1); @@ -427,11 +430,34 @@ void rtl92ce_phy_set_bw_mode_callback(struct ieee80211_hw *hw) ("unknown bandwidth: %#X\n", rtlphy->current_chan_bw)); break; } - rtl92c_phy_rf6052_set_bandwidth(hw, rtlphy->current_chan_bw); +#if 0 /* temporary */ + rtl92ce_phy_rf6052_set_bandwidth(hw, rtlphy->current_chan_bw); +#endif rtlphy->set_bwmode_inprogress = false; RT_TRACE(rtlpriv, COMP_SCAN, DBG_TRACE, ("<==\n")); } +void rtl92c_phy_set_bw_mode(struct ieee80211_hw *hw, + enum nl80211_channel_type ch_type) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_phy *rtlphy = &(rtlpriv->phy); + struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); + u8 tmp_bw = rtlphy->current_chan_bw; + + if (rtlphy->set_bwmode_inprogress) + return; + rtlphy->set_bwmode_inprogress = true; + if ((!is_hal_stop(rtlhal)) && !(RT_CANNOT_IO(hw))) { + rtl92c_phy_set_bw_mode_callback(hw); + } else { + RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING, + ("FALSE driver sleep or unload\n")); + rtlphy->set_bwmode_inprogress = false; + rtlphy->current_chan_bw = tmp_bw; + } +} + void _rtl92ce_phy_lc_calibrate(struct ieee80211_hw *hw, bool is2t) { u8 tmpreg; @@ -477,6 +503,36 @@ void _rtl92ce_phy_lc_calibrate(struct ieee80211_hw *hw, bool is2t) } } +static void _rtl92ce_phy_set_rf_sleep(struct ieee80211_hw *hw) +{ + u32 u4b_tmp; + u8 delay = 5; + struct rtl_priv *rtlpriv = rtl_priv(hw); + + rtl_write_byte(rtlpriv, REG_TXPAUSE, 0xFF); + rtl_set_rfreg(hw, RF90_PATH_A, 0x00, RFREG_OFFSET_MASK, 0x00); + rtl_write_byte(rtlpriv, REG_APSD_CTRL, 0x40); + u4b_tmp = rtl_get_rfreg(hw, RF90_PATH_A, 0, RFREG_OFFSET_MASK); + while (u4b_tmp != 0 && delay > 0) { + rtl_write_byte(rtlpriv, REG_APSD_CTRL, 0x0); + rtl_set_rfreg(hw, RF90_PATH_A, 0x00, RFREG_OFFSET_MASK, 0x00); + rtl_write_byte(rtlpriv, REG_APSD_CTRL, 0x40); + u4b_tmp = rtl_get_rfreg(hw, RF90_PATH_A, 0, RFREG_OFFSET_MASK); + delay--; + } + if (delay == 0) { + rtl_write_byte(rtlpriv, REG_APSD_CTRL, 0x00); + rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN, 0xE2); + rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN, 0xE3); + rtl_write_byte(rtlpriv, REG_TXPAUSE, 0x00); + RT_TRACE(rtlpriv, COMP_POWER, DBG_TRACE, + ("Switch RF timeout !!!.\n")); + return; + } + rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN, 0xE2); + rtl_write_byte(rtlpriv, REG_SPS0_CTRL, 0x22); +} + static bool _rtl92ce_phy_set_rf_power_state(struct ieee80211_hw *hw, enum rf_pwrstate rfpwr_state) { @@ -523,33 +579,6 @@ static bool _rtl92ce_phy_set_rf_power_state(struct ieee80211_hw *hw, break; } case ERFOFF:{ - for (queue_id = 0, i = 0; - queue_id < RTL_PCI_MAX_TX_QUEUE_COUNT;) { - ring = &pcipriv->dev.tx_ring[queue_id]; - if (skb_queue_len(&ring->queue) == 0 || - queue_id == BEACON_QUEUE) { - queue_id++; - continue; - } else { - RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING, - ("eRf Off/Sleep: %d times " - "TcbBusyQueue[%d] " - "=%d before doze!\n", (i + 1), - queue_id, - skb_queue_len(&ring->queue))); - udelay(10); - i++; - } - if (i >= MAX_DOZE_WAITING_TIMES_9x) { - RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING, - ("\nERFOFF: %d times " - "TcbBusyQueue[%d] = %d !\n", - MAX_DOZE_WAITING_TIMES_9x, - queue_id, - skb_queue_len(&ring->queue))); - break; - } - } if (ppsc->reg_rfps_level & RT_RF_OFF_LEVL_HALT_NIC) { RT_TRACE(rtlpriv, COMP_RF, DBG_DMESG, ("IPS Set eRf nic disable\n")); @@ -581,6 +610,7 @@ static bool _rtl92ce_phy_set_rf_power_state(struct ieee80211_hw *hw, "TcbBusyQueue[%d] =%d before " "doze!\n", (i + 1), queue_id, skb_queue_len(&ring->queue))); + udelay(10); i++; } @@ -599,7 +629,7 @@ static bool _rtl92ce_phy_set_rf_power_state(struct ieee80211_hw *hw, jiffies_to_msecs(jiffies - ppsc->last_awake_jiffies))); ppsc->last_sleep_jiffies = jiffies; - _rtl92c_phy_set_rf_sleep(hw); + _rtl92ce_phy_set_rf_sleep(hw); break; } default: @@ -614,10 +644,11 @@ static bool _rtl92ce_phy_set_rf_power_state(struct ieee80211_hw *hw, return bresult; } -bool rtl92ce_phy_set_rf_power_state(struct ieee80211_hw *hw, +bool rtl92c_phy_set_rf_power_state(struct ieee80211_hw *hw, enum rf_pwrstate rfpwr_state) { struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); + bool bresult = false; if (rfpwr_state == ppsc->rfpwr_state) diff --git a/drivers/net/wireless/rtlwifi/rtl8192ce/phy.h b/drivers/net/wireless/rtlwifi/rtl8192ce/phy.h index a37267e..eb93088 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192ce/phy.h +++ b/drivers/net/wireless/rtlwifi/rtl8192ce/phy.h @@ -39,6 +39,7 @@ #define RT_CANNOT_IO(hw) false #define HIGHPOWER_RADIOA_ARRAYLEN 22 +#define IQK_ADDA_REG_NUM 16 #define MAX_TOLERANCE 5 #define IQK_DELAY_TIME 1 @@ -56,6 +57,8 @@ #define IQK_ADDA_REG_NUM 16 #define IQK_MAC_REG_NUM 4 +#define IQK_DELAY_TIME 1 + #define RF90_PATH_MAX 2 #define CT_OFFSET_MAC_ADDR 0X16 @@ -76,7 +79,7 @@ #define CT_OFFSET_CUSTOMER_ID 0x7F #define RTL92C_MAX_PATH_NUM 2 -#define LLT_LAST_ENTRY_OF_TX_PKT_BUFFER 255 + enum swchnlcmd_id { CMDID_END, CMDID_SET_TXPOWEROWER_LEVEL, @@ -184,43 +187,44 @@ struct tx_power_struct { u32 mcs_original_offset[4][16]; }; -extern u32 rtl92c_phy_query_bb_reg(struct ieee80211_hw *hw, +bool rtl92c_phy_bb_config(struct ieee80211_hw *hw); +u32 rtl92c_phy_query_bb_reg(struct ieee80211_hw *hw, u32 regaddr, u32 bitmask); -extern void rtl92c_phy_set_bb_reg(struct ieee80211_hw *hw, +void rtl92c_phy_set_bb_reg(struct ieee80211_hw *hw, u32 regaddr, u32 bitmask, u32 data); -extern u32 rtl92c_phy_query_rf_reg(struct ieee80211_hw *hw, +u32 rtl92c_phy_query_rf_reg(struct ieee80211_hw *hw, enum radio_path rfpath, u32 regaddr, u32 bitmask); extern void rtl92ce_phy_set_rf_reg(struct ieee80211_hw *hw, - enum radio_path rfpath, u32 regaddr, - u32 bitmask, u32 data); -extern bool rtl92c_phy_mac_config(struct ieee80211_hw *hw); + enum radio_path rfpath, u32 regaddr, + u32 bitmask, u32 data); +bool rtl92c_phy_mac_config(struct ieee80211_hw *hw); bool rtl92ce_phy_bb_config(struct ieee80211_hw *hw); -extern bool rtl92c_phy_rf_config(struct ieee80211_hw *hw); -extern bool rtl92c_phy_config_rf_with_feaderfile(struct ieee80211_hw *hw, +bool rtl92c_phy_rf_config(struct ieee80211_hw *hw); +bool rtl92c_phy_config_rf_with_feaderfile(struct ieee80211_hw *hw, enum radio_path rfpath); -extern void rtl92c_phy_get_hw_reg_originalvalue(struct ieee80211_hw *hw); -extern void rtl92c_phy_get_txpower_level(struct ieee80211_hw *hw, +void rtl92c_phy_get_hw_reg_originalvalue(struct ieee80211_hw *hw); +void rtl92c_phy_get_txpower_level(struct ieee80211_hw *hw, long *powerlevel); -extern void rtl92c_phy_set_txpower_level(struct ieee80211_hw *hw, u8 channel); -extern bool rtl92c_phy_update_txpower_dbm(struct ieee80211_hw *hw, +void rtl92c_phy_set_txpower_level(struct ieee80211_hw *hw, u8 channel); +bool rtl92c_phy_update_txpower_dbm(struct ieee80211_hw *hw, long power_indbm); -extern void rtl92c_phy_scan_operation_backup(struct ieee80211_hw *hw, +void rtl92c_phy_scan_operation_backup(struct ieee80211_hw *hw, u8 operation); -extern void rtl92c_phy_set_bw_mode_callback(struct ieee80211_hw *hw); -extern void rtl92c_phy_set_bw_mode(struct ieee80211_hw *hw, +void rtl92c_phy_set_bw_mode(struct ieee80211_hw *hw, enum nl80211_channel_type ch_type); -extern void rtl92c_phy_sw_chnl_callback(struct ieee80211_hw *hw); -extern u8 rtl92c_phy_sw_chnl(struct ieee80211_hw *hw); -extern void rtl92c_phy_iq_calibrate(struct ieee80211_hw *hw, bool b_recovery); -extern void rtl92c_phy_set_beacon_hw_reg(struct ieee80211_hw *hw, +void rtl92c_phy_sw_chnl_callback(struct ieee80211_hw *hw); +u8 rtl92c_phy_sw_chnl(struct ieee80211_hw *hw); +void rtl92c_phy_iq_calibrate(struct ieee80211_hw *hw, bool b_recovery); +void rtl92c_phy_set_beacon_hw_reg(struct ieee80211_hw *hw, u16 beaconinterval); void rtl92c_phy_ap_calibrate(struct ieee80211_hw *hw, char delta); void rtl92c_phy_lc_calibrate(struct ieee80211_hw *hw); +void _rtl92ce_phy_lc_calibrate(struct ieee80211_hw *hw, bool is2t); void rtl92c_phy_set_rfpath_switch(struct ieee80211_hw *hw, bool bmain); bool rtl92c_phy_config_rf_with_headerfile(struct ieee80211_hw *hw, enum radio_path rfpath); -extern bool rtl8192_phy_check_is_legal_rfpath(struct ieee80211_hw *hw, +bool rtl8192_phy_check_is_legal_rfpath(struct ieee80211_hw *hw, u32 rfpath); bool rtl92c_phy_set_io_cmd(struct ieee80211_hw *hw, enum io_type iotype); bool rtl92ce_phy_set_rf_power_state(struct ieee80211_hw *hw, @@ -237,9 +241,6 @@ u32 _rtl92c_phy_calculate_bit_shift(u32 bitmask); void _rtl92c_phy_rf_serial_write(struct ieee80211_hw *hw, enum radio_path rfpath, u32 offset, u32 data); -void _rtl92c_store_pwrIndex_diffrate_offset(struct ieee80211_hw *hw, - u32 regaddr, u32 bitmask, - u32 data); void _rtl92c_phy_fw_rf_serial_write(struct ieee80211_hw *hw, enum radio_path rfpath, u32 offset, u32 data); @@ -250,5 +251,7 @@ bool _rtl92ce_phy_config_mac_with_headerfile(struct ieee80211_hw *hw); void _rtl92c_phy_init_bb_rf_register_definition(struct ieee80211_hw *hw); bool _rtl92c_phy_bb8192c_config_parafile(struct ieee80211_hw *hw); void _rtl92c_phy_set_rf_sleep(struct ieee80211_hw *hw); +bool rtl92c_phy_set_rf_power_state(struct ieee80211_hw *hw, + enum rf_pwrstate rfpwr_state); #endif diff --git a/drivers/net/wireless/rtlwifi/rtl8192ce/rf.c b/drivers/net/wireless/rtlwifi/rtl8192ce/rf.c index e301b12..90d0f2c 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192ce/rf.c +++ b/drivers/net/wireless/rtlwifi/rtl8192ce/rf.c @@ -34,9 +34,9 @@ #include "rf.h" #include "dm.h" -static bool _rtl92c_phy_rf6052_config_parafile(struct ieee80211_hw *hw); +static bool _rtl92ce_phy_rf6052_config_parafile(struct ieee80211_hw *hw); -void rtl92c_phy_rf6052_set_bandwidth(struct ieee80211_hw *hw, u8 bandwidth) +void rtl92ce_phy_rf6052_set_bandwidth(struct ieee80211_hw *hw, u8 bandwidth) { struct rtl_priv *rtlpriv = rtl_priv(hw); struct rtl_phy *rtlphy = &(rtlpriv->phy); @@ -62,7 +62,7 @@ void rtl92c_phy_rf6052_set_bandwidth(struct ieee80211_hw *hw, u8 bandwidth) } void rtl92ce_phy_rf6052_set_cck_txpower(struct ieee80211_hw *hw, - u8 *ppowerlevel) + u8 *ppowerlevel) { struct rtl_priv *rtlpriv = rtl_priv(hw); struct rtl_phy *rtlphy = &(rtlpriv->phy); @@ -128,8 +128,7 @@ void rtl92ce_phy_rf6052_set_cck_txpower(struct ieee80211_hw *hw, tmpval = tx_agc[RF90_PATH_A] >> 8; - if (mac->mode == WIRELESS_MODE_B) - tmpval = tmpval & 0xff00ffff; + tmpval = tmpval & 0xff00ffff; rtl_set_bbreg(hw, RTXAGC_B_CCK11_A_CCK2_11, 0xffffff00, tmpval); @@ -440,16 +439,17 @@ bool rtl92ce_phy_rf6052_config(struct ieee80211_hw *hw) else rtlphy->num_total_rfpath = 2; - return _rtl92c_phy_rf6052_config_parafile(hw); + return _rtl92ce_phy_rf6052_config_parafile(hw); + } -static bool _rtl92c_phy_rf6052_config_parafile(struct ieee80211_hw *hw) +static bool _rtl92ce_phy_rf6052_config_parafile(struct ieee80211_hw *hw) { struct rtl_priv *rtlpriv = rtl_priv(hw); struct rtl_phy *rtlphy = &(rtlpriv->phy); u32 u4_regvalue = 0; u8 rfpath; - bool rtstatus; + bool rtstatus = true; struct bb_reg_def *pphyreg; for (rfpath = 0; rfpath < rtlphy->num_total_rfpath; rfpath++) { @@ -484,12 +484,12 @@ static bool _rtl92c_phy_rf6052_config_parafile(struct ieee80211_hw *hw) switch (rfpath) { case RF90_PATH_A: - rtstatus = rtl92ce_phy_config_rf_with_headerfile(hw, - (enum radio_path) rfpath); + rtstatus = rtl92c_phy_config_rf_with_headerfile(hw, + (enum radio_path)rfpath); break; case RF90_PATH_B: - rtstatus = rtl92ce_phy_config_rf_with_headerfile(hw, - (enum radio_path) rfpath); + rtstatus = rtl92c_phy_config_rf_with_headerfile(hw, + (enum radio_path)rfpath); break; case RF90_PATH_C: break; diff --git a/drivers/net/wireless/rtlwifi/rtl8192ce/rf.h b/drivers/net/wireless/rtlwifi/rtl8192ce/rf.h index 3aa520c..39ff036 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192ce/rf.h +++ b/drivers/net/wireless/rtlwifi/rtl8192ce/rf.h @@ -34,14 +34,11 @@ #define RF6052_MAX_REG 0x3F #define RF6052_MAX_PATH 2 -extern void rtl92c_phy_rf6052_set_bandwidth(struct ieee80211_hw *hw, - u8 bandwidth); -extern void rtl92c_phy_rf6052_set_cck_txpower(struct ieee80211_hw *hw, - u8 *ppowerlevel); -extern void rtl92c_phy_rf6052_set_ofdm_txpower(struct ieee80211_hw *hw, - u8 *ppowerlevel, u8 channel); -bool rtl92ce_phy_rf6052_config(struct ieee80211_hw *hw); -bool rtl92ce_phy_config_rf_with_headerfile(struct ieee80211_hw *hw, - enum radio_path rfpath); - +extern void rtl92ce_phy_rf6052_set_bandwidth(struct ieee80211_hw *hw, + u8 bandwidth); +extern void rtl92ce_phy_rf6052_set_cck_txpower(struct ieee80211_hw *hw, + u8 *ppowerlevel); +extern void rtl92ce_phy_rf6052_set_ofdm_txpower(struct ieee80211_hw *hw, + u8 *ppowerlevel, u8 channel); +extern bool rtl92ce_phy_rf6052_config(struct ieee80211_hw *hw); #endif -- cgit v0.10.2 From 76c34f910a5c99a402de5068444563d4c151e794 Mon Sep 17 00:00:00 2001 From: Chaoming_Li Date: Mon, 25 Apr 2011 12:54:05 -0500 Subject: rtlwifi: rtl8192ce: Change rtl8192ce routines phy and trx and modify rtl8192cu for addition of rtl8192se and rtl8192de Change rtl8192ce routines phy and trx for addition of RTL8192SE and RTL8192DE. In addition, make necessary modifications to rtl8192cu. This patch also removes the temporary patches needed to enable intermediate steps to build without error. Signed-off-by: Chaoming_Li Signed-off-by: Larry Finger Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/rtlwifi/pci.c b/drivers/net/wireless/rtlwifi/pci.c index e496361..aeb0901 100644 --- a/drivers/net/wireless/rtlwifi/pci.c +++ b/drivers/net/wireless/rtlwifi/pci.c @@ -584,9 +584,7 @@ static void _rtl_pci_tx_chk_waitq(struct ieee80211_hw *hw) _rtl_update_earlymode_info(hw, skb, &tcb_desc, tid); -#if 0 /* temporary */ rtlpriv->intf_ops->adapter_tx(hw, skb, &tcb_desc); -#endif } } } @@ -1100,10 +1098,8 @@ static void _rtl_pci_prepare_bcn_tasklet(struct ieee80211_hw *hw) hdr = rtl_get_hdr(pskb); info = IEEE80211_SKB_CB(pskb); pdesc = &ring->desc[0]; -#if 0 /* temporary */ rtlpriv->cfg->ops->fill_tx_desc(hw, hdr, (u8 *) pdesc, info, pskb, BEACON_QUEUE, &tcb_desc); -#endif __skb_queue_tail(&ring->queue, pskb); diff --git a/drivers/net/wireless/rtlwifi/rtl8192c/phy_common.c b/drivers/net/wireless/rtlwifi/rtl8192c/phy_common.c index 3915a1ba5..991d865 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192c/phy_common.c +++ b/drivers/net/wireless/rtlwifi/rtl8192c/phy_common.c @@ -82,7 +82,7 @@ void rtl92c_phy_set_bb_reg(struct ieee80211_hw *hw, } EXPORT_SYMBOL(rtl92c_phy_set_bb_reg); -static u32 _rtl92c_phy_fw_rf_serial_read(struct ieee80211_hw *hw, +u32 _rtl92c_phy_fw_rf_serial_read(struct ieee80211_hw *hw, enum radio_path rfpath, u32 offset) { RT_ASSERT(false, ("deprecated!\n")); @@ -91,7 +91,7 @@ static u32 _rtl92c_phy_fw_rf_serial_read(struct ieee80211_hw *hw, } EXPORT_SYMBOL(_rtl92c_phy_fw_rf_serial_read); -static void _rtl92c_phy_fw_rf_serial_write(struct ieee80211_hw *hw, +void _rtl92c_phy_fw_rf_serial_write(struct ieee80211_hw *hw, enum radio_path rfpath, u32 offset, u32 data) { @@ -99,7 +99,7 @@ static void _rtl92c_phy_fw_rf_serial_write(struct ieee80211_hw *hw, } EXPORT_SYMBOL(_rtl92c_phy_fw_rf_serial_write); -static u32 _rtl92c_phy_rf_serial_read(struct ieee80211_hw *hw, +u32 _rtl92c_phy_rf_serial_read(struct ieee80211_hw *hw, enum radio_path rfpath, u32 offset) { struct rtl_priv *rtlpriv = rtl_priv(hw); @@ -150,7 +150,7 @@ static u32 _rtl92c_phy_rf_serial_read(struct ieee80211_hw *hw, } EXPORT_SYMBOL(_rtl92c_phy_rf_serial_read); -static void _rtl92c_phy_rf_serial_write(struct ieee80211_hw *hw, +void _rtl92c_phy_rf_serial_write(struct ieee80211_hw *hw, enum radio_path rfpath, u32 offset, u32 data) { @@ -208,7 +208,7 @@ bool rtl92c_phy_rf_config(struct ieee80211_hw *hw) } EXPORT_SYMBOL(rtl92c_phy_rf_config); -static bool _rtl92c_phy_bb8192c_config_parafile(struct ieee80211_hw *hw) +bool _rtl92c_phy_bb8192c_config_parafile(struct ieee80211_hw *hw) { struct rtl_priv *rtlpriv = rtl_priv(hw); struct rtl_phy *rtlphy = &(rtlpriv->phy); @@ -1364,8 +1364,7 @@ static void _rtl92c_phy_iq_calibrate(struct ieee80211_hw *hw, static void _rtl92c_phy_ap_calibrate(struct ieee80211_hw *hw, char delta, bool is2t) { - /* This routine is deliberately dummied out for later fixes */ -#if 0 +#if 0 /* This routine is deliberately dummied out for later fixes */ struct rtl_priv *rtlpriv = rtl_priv(hw); struct rtl_phy *rtlphy = &(rtlpriv->phy); struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw)); diff --git a/drivers/net/wireless/rtlwifi/rtl8192ce/hw.c b/drivers/net/wireless/rtlwifi/rtl8192ce/hw.c index bb604b8..794b4b6 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192ce/hw.c +++ b/drivers/net/wireless/rtlwifi/rtl8192ce/hw.c @@ -930,10 +930,8 @@ int rtl92ce_hw_init(struct ieee80211_hw *hw) } rtlhal->last_hmeboxnum = 0; -#if 0 /* temporary */ rtl92c_phy_mac_config(hw); rtl92c_phy_bb_config(hw); -#endif rtlphy->rf_mode = RF_OP_BY_SW_3WIRE; rtl92c_phy_rf_config(hw); rtlphy->rfreg_chnlval[0] = rtl_get_rfreg(hw, (enum radio_path)0, diff --git a/drivers/net/wireless/rtlwifi/rtl8192ce/phy.c b/drivers/net/wireless/rtlwifi/rtl8192ce/phy.c index bbba6f8..6045401 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192ce/phy.c +++ b/drivers/net/wireless/rtlwifi/rtl8192ce/phy.c @@ -366,7 +366,7 @@ bool rtl92c_phy_config_rf_with_headerfile(struct ieee80211_hw *hw, return true; } -static void rtl92c_phy_set_bw_mode_callback(struct ieee80211_hw *hw) +void rtl92c_phy_set_bw_mode_callback(struct ieee80211_hw *hw) { struct rtl_priv *rtlpriv = rtl_priv(hw); struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); @@ -430,34 +430,11 @@ static void rtl92c_phy_set_bw_mode_callback(struct ieee80211_hw *hw) ("unknown bandwidth: %#X\n", rtlphy->current_chan_bw)); break; } -#if 0 /* temporary */ rtl92ce_phy_rf6052_set_bandwidth(hw, rtlphy->current_chan_bw); -#endif rtlphy->set_bwmode_inprogress = false; RT_TRACE(rtlpriv, COMP_SCAN, DBG_TRACE, ("<==\n")); } -void rtl92c_phy_set_bw_mode(struct ieee80211_hw *hw, - enum nl80211_channel_type ch_type) -{ - struct rtl_priv *rtlpriv = rtl_priv(hw); - struct rtl_phy *rtlphy = &(rtlpriv->phy); - struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); - u8 tmp_bw = rtlphy->current_chan_bw; - - if (rtlphy->set_bwmode_inprogress) - return; - rtlphy->set_bwmode_inprogress = true; - if ((!is_hal_stop(rtlhal)) && !(RT_CANNOT_IO(hw))) { - rtl92c_phy_set_bw_mode_callback(hw); - } else { - RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING, - ("FALSE driver sleep or unload\n")); - rtlphy->set_bwmode_inprogress = false; - rtlphy->current_chan_bw = tmp_bw; - } -} - void _rtl92ce_phy_lc_calibrate(struct ieee80211_hw *hw, bool is2t) { u8 tmpreg; diff --git a/drivers/net/wireless/rtlwifi/rtl8192ce/sw.c b/drivers/net/wireless/rtlwifi/rtl8192ce/sw.c index 5c920c6..702dd11 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192ce/sw.c +++ b/drivers/net/wireless/rtlwifi/rtl8192ce/sw.c @@ -214,7 +214,6 @@ struct rtl_hal_ops rtl8192ce_hal_ops = { .switch_channel = rtl92c_phy_sw_chnl, .dm_watchdog = rtl92c_dm_watchdog, .scan_operation_backup = rtl92c_phy_scan_operation_backup, -#if 0 /* temporary */ .set_rf_power_state = rtl92c_phy_set_rf_power_state, .led_control = rtl92ce_led_control, .set_desc = rtl92ce_set_desc, @@ -234,7 +233,6 @@ struct rtl_hal_ops rtl8192ce_hal_ops = { .config_bb_with_pgheaderfile = _rtl92ce_phy_config_bb_with_pgheaderfile, .phy_lc_calibrate = _rtl92ce_phy_lc_calibrate, .dm_dynamic_txpower = rtl92ce_dm_dynamic_txpower, -#endif }; struct rtl_mod_params rtl92ce_mod_params = { diff --git a/drivers/net/wireless/rtlwifi/rtl8192ce/trx.c b/drivers/net/wireless/rtlwifi/rtl8192ce/trx.c index 356b851..f76d406 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192ce/trx.c +++ b/drivers/net/wireless/rtlwifi/rtl8192ce/trx.c @@ -36,42 +36,16 @@ #include "trx.h" #include "led.h" -static enum rtl_desc_qsel _rtl92ce_map_hwqueue_to_fwqueue(__le16 fc, - unsigned int - skb_queue) +u8 _rtl92ce_map_hwqueue_to_fwqueue(struct sk_buff *skb, u8 hw_queue) { - enum rtl_desc_qsel qsel; + u16 fc = rtl_get_fc(skb); - if (unlikely(ieee80211_is_beacon(fc))) { - qsel = QSLT_BEACON; - return qsel; - } - - if (ieee80211_is_mgmt(fc)) { - qsel = QSLT_MGNT; - return qsel; - } + if (unlikely(ieee80211_is_beacon(fc))) + return QSLT_BEACON; + if (ieee80211_is_mgmt(fc)) + return QSLT_MGNT; - switch (skb_queue) { - case VO_QUEUE: - qsel = QSLT_VO; - break; - case VI_QUEUE: - qsel = QSLT_VI; - break; - case BE_QUEUE: - qsel = QSLT_BE; - break; - case BK_QUEUE: - qsel = QSLT_BK; - break; - default: - qsel = QSLT_BE; - RT_ASSERT(false, ("BE queue, skb_queue:%d," - " set qsel = 0x%X\n", skb_queue, QSLT_BE)); - break; - } - return qsel; + return skb->priority; } static int _rtl92ce_rate_mapping(bool isht, u8 desc_rate, bool first_ampdu) @@ -255,6 +229,7 @@ static void _rtl92ce_query_rxphystatus(struct ieee80211_hw *hw, u8 evm, pwdb_all, rf_rx_num = 0; u8 i, max_spatial_stream; u32 rssi, total_rssi = 0; + bool in_powersavemode = false; bool is_cck_rate; is_cck_rate = RX_HAL_IS_CCK_RATE(pdesc); @@ -270,9 +245,13 @@ static void _rtl92ce_query_rxphystatus(struct ieee80211_hw *hw, u8 report, cck_highpwr; cck_buf = (struct phy_sts_cck_8192s_t *)p_drvinfo; - cck_highpwr = (u8) rtl_get_bbreg(hw, - RFPGA0_XA_HSSIPARAMETER2, - BIT(9)); + if (!in_powersavemode) + cck_highpwr = (u8) rtl_get_bbreg(hw, + RFPGA0_XA_HSSIPARAMETER2, + BIT(9)); + else + cck_highpwr = false; + if (!cck_highpwr) { u8 cck_agc_rpt = cck_buf->cck_agc_rpt; report = cck_buf->cck_agc_rpt & 0xc0; @@ -398,6 +377,7 @@ static void _rtl92ce_process_ui_rssi(struct ieee80211_hw *hw, if (rtlpriv->stats.ui_rssi.total_num++ >= PHY_RSSI_SLID_WIN_MAX) { + rtlpriv->stats.ui_rssi.total_num = PHY_RSSI_SLID_WIN_MAX; last_rssi = @@ -424,10 +404,6 @@ static void _rtl92ce_process_ui_rssi(struct ieee80211_hw *hw, if (!pstats->is_cck && pstats->packet_toself) { for (rfpath = RF90_PATH_A; rfpath < rtlphy->num_total_rfpath; rfpath++) { - - if (!rtl8192_phy_check_is_legal_rfpath(hw, rfpath)) - continue; - if (rtlpriv->stats.rx_rssi_percentage[rfpath] == 0) { rtlpriv->stats.rx_rssi_percentage[rfpath] = pstats->rx_mimo_signalstrength[rfpath]; @@ -723,7 +699,7 @@ bool rtl92ce_rx_query_desc(struct ieee80211_hw *hw, void rtl92ce_tx_fill_desc(struct ieee80211_hw *hw, struct ieee80211_hdr *hdr, u8 *pdesc_tx, struct ieee80211_tx_info *info, struct sk_buff *skb, - unsigned int queue_index) + u8 hw_queue, struct rtl_tcb_desc *tcb_desc) { struct rtl_priv *rtlpriv = rtl_priv(hw); struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); @@ -732,16 +708,9 @@ void rtl92ce_tx_fill_desc(struct ieee80211_hw *hw, bool defaultadapter = true; struct ieee80211_sta *sta; u8 *pdesc = (u8 *) pdesc_tx; - struct rtl_tcb_desc tcb_desc; - u8 *qc = ieee80211_get_qos_ctl(hdr); - u8 tid = qc[0] & IEEE80211_QOS_CTL_TID_MASK; u16 seq_number; __le16 fc = hdr->frame_control; - u8 rate_flag = info->control.rates[0].flags; - - enum rtl_desc_qsel fw_qsel = - _rtl92ce_map_hwqueue_to_fwqueue(fc, queue_index); - + u8 fw_qsel = _rtl92ce_map_hwqueue_to_fwqueue(skb, hw_queue); bool firstseg = ((hdr->seq_ctrl & cpu_to_le16(IEEE80211_SCTL_FRAG)) == 0); @@ -751,56 +720,68 @@ void rtl92ce_tx_fill_desc(struct ieee80211_hw *hw, dma_addr_t mapping = pci_map_single(rtlpci->pdev, skb->data, skb->len, PCI_DMA_TODEVICE); + u8 bw_40 = 0; + + rcu_read_lock(); + sta = get_sta(hw, mac->vif, mac->bssid); + if (mac->opmode == NL80211_IFTYPE_STATION) { + bw_40 = mac->bw_40; + } else if (mac->opmode == NL80211_IFTYPE_AP || + mac->opmode == NL80211_IFTYPE_ADHOC) { + if (sta) + bw_40 = sta->ht_cap.cap & + IEEE80211_HT_CAP_SUP_WIDTH_20_40; + } seq_number = (le16_to_cpu(hdr->seq_ctrl) & IEEE80211_SCTL_SEQ) >> 4; - rtl_get_tcb_desc(hw, info, sta, skb, &tcb_desc); + rtl_get_tcb_desc(hw, info, sta, skb, tcb_desc); CLEAR_PCI_TX_DESC_CONTENT(pdesc, sizeof(struct tx_desc_92c)); + if (ieee80211_is_nullfunc(fc) || ieee80211_is_ctl(fc)) { + firstseg = true; + lastseg = true; + } if (firstseg) { SET_TX_DESC_OFFSET(pdesc, USB_HWDESC_HEADER_LEN); - SET_TX_DESC_TX_RATE(pdesc, tcb_desc.hw_rate); + SET_TX_DESC_TX_RATE(pdesc, tcb_desc->hw_rate); - if (tcb_desc.use_shortgi || tcb_desc.use_shortpreamble) + if (tcb_desc->use_shortgi || tcb_desc->use_shortpreamble) SET_TX_DESC_DATA_SHORTGI(pdesc, 1); - if (mac->tids[tid].agg.agg_state == RTL_AGG_ON && - info->flags & IEEE80211_TX_CTL_AMPDU) { + if (info->flags & IEEE80211_TX_CTL_AMPDU) { SET_TX_DESC_AGG_BREAK(pdesc, 1); SET_TX_DESC_MAX_AGG_NUM(pdesc, 0x14); } SET_TX_DESC_SEQ(pdesc, seq_number); - SET_TX_DESC_RTS_ENABLE(pdesc, ((tcb_desc.rts_enable && - !tcb_desc. + SET_TX_DESC_RTS_ENABLE(pdesc, ((tcb_desc->rts_enable && + !tcb_desc-> cts_enable) ? 1 : 0)); SET_TX_DESC_HW_RTS_ENABLE(pdesc, - ((tcb_desc.rts_enable - || tcb_desc.cts_enable) ? 1 : 0)); - SET_TX_DESC_CTS2SELF(pdesc, ((tcb_desc.cts_enable) ? 1 : 0)); - SET_TX_DESC_RTS_STBC(pdesc, ((tcb_desc.rts_stbc) ? 1 : 0)); + ((tcb_desc->rts_enable + || tcb_desc->cts_enable) ? 1 : 0)); + SET_TX_DESC_CTS2SELF(pdesc, ((tcb_desc->cts_enable) ? 1 : 0)); + SET_TX_DESC_RTS_STBC(pdesc, ((tcb_desc->rts_stbc) ? 1 : 0)); - SET_TX_DESC_RTS_RATE(pdesc, tcb_desc.rts_rate); + SET_TX_DESC_RTS_RATE(pdesc, tcb_desc->rts_rate); SET_TX_DESC_RTS_BW(pdesc, 0); - SET_TX_DESC_RTS_SC(pdesc, tcb_desc.rts_sc); + SET_TX_DESC_RTS_SC(pdesc, tcb_desc->rts_sc); SET_TX_DESC_RTS_SHORT(pdesc, - ((tcb_desc.rts_rate <= DESC92C_RATE54M) ? - (tcb_desc.rts_use_shortpreamble ? 1 : 0) - : (tcb_desc.rts_use_shortgi ? 1 : 0))); + ((tcb_desc->rts_rate <= DESC92C_RATE54M) ? + (tcb_desc->rts_use_shortpreamble ? 1 : 0) + : (tcb_desc->rts_use_shortgi ? 1 : 0))); - if (mac->bw_40) { - if (tcb_desc.packet_bw) { + if (bw_40) { + if (tcb_desc->packet_bw) { SET_TX_DESC_DATA_BW(pdesc, 1); SET_TX_DESC_TX_SUB_CARRIER(pdesc, 3); } else { SET_TX_DESC_DATA_BW(pdesc, 0); - - if (rate_flag & IEEE80211_TX_RC_DUP_DATA) { - SET_TX_DESC_TX_SUB_CARRIER(pdesc, - mac->cur_40_prime_sc); - } + SET_TX_DESC_TX_SUB_CARRIER(pdesc, + mac->cur_40_prime_sc); } } else { SET_TX_DESC_DATA_BW(pdesc, 0); @@ -810,8 +791,6 @@ void rtl92ce_tx_fill_desc(struct ieee80211_hw *hw, SET_TX_DESC_LINIP(pdesc, 0); SET_TX_DESC_PKT_SIZE(pdesc, (u16) skb->len); - rcu_read_lock(); - sta = ieee80211_find_sta(mac->vif, mac->bssid); if (sta) { u8 ampdu_density = sta->ht_cap.ampdu_density; SET_TX_DESC_AMPDU_DENSITY(pdesc, ampdu_density); @@ -844,7 +823,7 @@ void rtl92ce_tx_fill_desc(struct ieee80211_hw *hw, SET_TX_DESC_DATA_RATE_FB_LIMIT(pdesc, 0x1F); SET_TX_DESC_RTS_RATE_FB_LIMIT(pdesc, 0xF); SET_TX_DESC_DISABLE_FB(pdesc, 0); - SET_TX_DESC_USE_RATE(pdesc, tcb_desc.use_driver_rate ? 1 : 0); + SET_TX_DESC_USE_RATE(pdesc, tcb_desc->use_driver_rate ? 1 : 0); if (ieee80211_is_data_qos(fc)) { if (mac->rdg_en) { @@ -864,15 +843,14 @@ void rtl92ce_tx_fill_desc(struct ieee80211_hw *hw, SET_TX_DESC_TX_BUFFER_ADDRESS(pdesc, cpu_to_le32(mapping)); if (rtlpriv->dm.useramask) { - SET_TX_DESC_RATE_ID(pdesc, tcb_desc.ratr_index); - SET_TX_DESC_MACID(pdesc, tcb_desc.mac_id); + SET_TX_DESC_RATE_ID(pdesc, tcb_desc->ratr_index); + SET_TX_DESC_MACID(pdesc, tcb_desc->mac_id); } else { - SET_TX_DESC_RATE_ID(pdesc, 0xC + tcb_desc.ratr_index); - SET_TX_DESC_MACID(pdesc, tcb_desc.ratr_index); + SET_TX_DESC_RATE_ID(pdesc, 0xC + tcb_desc->ratr_index); + SET_TX_DESC_MACID(pdesc, tcb_desc->ratr_index); } - if ((!ieee80211_is_data_qos(fc)) && ppsc->leisure_ps && - ppsc->fwctrl_lps) { + if ((!ieee80211_is_data_qos(fc)) && ppsc->fwctrl_lps) { SET_TX_DESC_HWSEQ_EN(pdesc, 1); SET_TX_DESC_PKT_ID(pdesc, 8); @@ -1021,7 +999,7 @@ u32 rtl92ce_get_desc(u8 *p_desc, bool istx, u8 desc_name) return ret; } -void rtl92ce_tx_polling(struct ieee80211_hw *hw, unsigned int hw_queue) +void rtl92ce_tx_polling(struct ieee80211_hw *hw, u8 hw_queue) { struct rtl_priv *rtlpriv = rtl_priv(hw); if (hw_queue == BEACON_QUEUE) { @@ -1032,35 +1010,3 @@ void rtl92ce_tx_polling(struct ieee80211_hw *hw, unsigned int hw_queue) } } -bool _rtl92c_cmd_send_packet(struct ieee80211_hw *hw, - struct sk_buff *skb) -{ - struct rtl_priv *rtlpriv = rtl_priv(hw); - struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); - struct rtl8192_tx_ring *ring; - struct rtl_tx_desc *pdesc; - u8 own; - unsigned long flags; - struct sk_buff *pskb = NULL; - - ring = &rtlpci->tx_ring[BEACON_QUEUE]; - - spin_lock_irqsave(&rtlpriv->locks.irq_th_lock, flags); - - pskb = __skb_dequeue(&ring->queue); - if (pskb) - kfree_skb(pskb); - - pdesc = &ring->desc[0]; - own = (u8) rtlpriv->cfg->ops->get_desc((u8 *) pdesc, true, HW_DESC_OWN); - - rtlpriv->cfg->ops->fill_tx_cmddesc(hw, (u8 *) pdesc, 1, 1, skb); - - __skb_queue_tail(&ring->queue, skb); - - spin_unlock_irqrestore(&rtlpriv->locks.irq_th_lock, flags); - - rtlpriv->cfg->ops->tx_polling(hw, BEACON_QUEUE); - - return true; -} diff --git a/drivers/net/wireless/rtlwifi/rtl8192ce/trx.h b/drivers/net/wireless/rtlwifi/rtl8192ce/trx.h index b0b0b13..0f11771 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192ce/trx.h +++ b/drivers/net/wireless/rtlwifi/rtl8192ce/trx.h @@ -724,17 +724,16 @@ struct rx_desc_92c { void rtl92ce_tx_fill_desc(struct ieee80211_hw *hw, struct ieee80211_hdr *hdr, u8 *pdesc, struct ieee80211_tx_info *info, - struct sk_buff *skb, unsigned int qsel); + struct sk_buff *skb, u8 hw_queue, + struct rtl_tcb_desc *ptcb_desc); bool rtl92ce_rx_query_desc(struct ieee80211_hw *hw, struct rtl_stats *stats, struct ieee80211_rx_status *rx_status, u8 *pdesc, struct sk_buff *skb); void rtl92ce_set_desc(u8 *pdesc, bool istx, u8 desc_name, u8 *val); u32 rtl92ce_get_desc(u8 *pdesc, bool istx, u8 desc_name); -void rtl92ce_tx_polling(struct ieee80211_hw *hw, unsigned int hw_queue); +void rtl92ce_tx_polling(struct ieee80211_hw *hw, u8 hw_queue); void rtl92ce_tx_fill_cmddesc(struct ieee80211_hw *hw, u8 *pdesc, bool b_firstseg, bool b_lastseg, struct sk_buff *skb); -bool _rtl92c_cmd_send_packet(struct ieee80211_hw *hw, struct sk_buff *skb); - #endif diff --git a/drivers/net/wireless/rtlwifi/rtl8192cu/hw.c b/drivers/net/wireless/rtlwifi/rtl8192cu/hw.c index 861f39f..52e2af5 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192cu/hw.c +++ b/drivers/net/wireless/rtlwifi/rtl8192cu/hw.c @@ -39,10 +39,10 @@ #include "mac.h" #include "dm.h" #include "hw.h" +#include "../rtl8192ce/hw.h" #include "trx.h" #include "led.h" #include "table.h" -#include "../rtl8192ce/hw.h" static void _rtl92cu_phy_param_tab_init(struct ieee80211_hw *hw) { @@ -606,12 +606,10 @@ void rtl92cu_read_eeprom_info(struct ieee80211_hw *hw) if (!IS_NORMAL_CHIP(rtlhal->version)) return; tmp_u1b = rtl_read_byte(rtlpriv, REG_9346CR); -#if 0 /* temporary */ - rtlefuse->epromtype = (tmp_u1b & EEPROMSEL) ? + rtlefuse->epromtype = (tmp_u1b & BOOT_FROM_EEPROM) ? EEPROM_93C46 : EEPROM_BOOT_EFUSE; RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, ("Boot from %s\n", - (tmp_u1b & EEPROMSEL) ? "EERROM" : "EFUSE")); -#endif + (tmp_u1b & BOOT_FROM_EEPROM) ? "EERROM" : "EFUSE")); rtlefuse->autoload_failflag = (tmp_u1b & EEPROM_EN) ? false : true; RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, ("Autoload %s\n", (tmp_u1b & EEPROM_EN) ? "OK!!" : "ERR!!")); @@ -980,7 +978,7 @@ static void _rtl92cu_init_wmac_setting(struct ieee80211_hw *hw) struct rtl_priv *rtlpriv = rtl_priv(hw); struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); - mac->rx_conf = (RCR_APM | RCR_AM | RCR_ADF | RCR_AB | RCR_APP_FCS | + mac->rx_conf = (RCR_APM | RCR_AM | RCR_ADF | RCR_AB | RCR_APPFCS | RCR_APP_ICV | RCR_AMF | RCR_HTC_LOC_CTRL | RCR_APP_MIC | RCR_APP_PHYSTS | RCR_ACRC32); rtl_write_dword(rtlpriv, REG_RCR, mac->rx_conf); @@ -2185,7 +2183,9 @@ void rtl92cu_set_hw_reg(struct ieee80211_hw *hw, u8 variable, u8 *val) } } -void rtl92cu_update_hal_rate_table(struct ieee80211_hw *hw) +void rtl92cu_update_hal_rate_table(struct ieee80211_hw *hw, + struct ieee80211_sta *sta, + u8 rssi_level) { struct rtl_priv *rtlpriv = rtl_priv(hw); struct rtl_phy *rtlphy = &(rtlpriv->phy); diff --git a/drivers/net/wireless/rtlwifi/rtl8192cu/hw.h b/drivers/net/wireless/rtlwifi/rtl8192cu/hw.h index 17dc5a3..32f85cb 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192cu/hw.h +++ b/drivers/net/wireless/rtlwifi/rtl8192cu/hw.h @@ -98,13 +98,14 @@ void rtl92cu_update_interrupt_mask(struct ieee80211_hw *hw, u32 add_msr, u32 rm_msr); void rtl92cu_get_hw_reg(struct ieee80211_hw *hw, u8 variable, u8 *val); void rtl92cu_set_hw_reg(struct ieee80211_hw *hw, u8 variable, u8 *val); -void rtl92cu_update_hal_rate_table(struct ieee80211_hw *hw); +void rtl92cu_update_hal_rate_table(struct ieee80211_hw *hw, + struct ieee80211_sta *sta, + u8 rssi_level); void rtl92cu_update_hal_rate_mask(struct ieee80211_hw *hw, u8 rssi_level); void rtl92cu_update_channel_access_setting(struct ieee80211_hw *hw); bool rtl92cu_gpio_radio_on_off_checking(struct ieee80211_hw *hw, u8 * valid); void rtl92cu_set_check_bssid(struct ieee80211_hw *hw, bool check_bssid); -static u8 _rtl92c_get_chnl_group(u8 chnl); int rtl92c_download_fw(struct ieee80211_hw *hw); void rtl92c_set_fw_pwrmode_cmd(struct ieee80211_hw *hw, u8 mode); void rtl92c_set_fw_rsvdpagepkt(struct ieee80211_hw *hw, bool dl_finished); diff --git a/drivers/net/wireless/rtlwifi/rtl8192cu/sw.c b/drivers/net/wireless/rtlwifi/rtl8192cu/sw.c index 71244a3..bee7c14 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192cu/sw.c +++ b/drivers/net/wireless/rtlwifi/rtl8192cu/sw.c @@ -94,7 +94,7 @@ static struct rtl_hal_ops rtl8192cu_hal_ops = { .update_interrupt_mask = rtl92cu_update_interrupt_mask, .get_hw_reg = rtl92cu_get_hw_reg, .set_hw_reg = rtl92cu_set_hw_reg, - .update_rate_table = rtl92cu_update_hal_rate_table, + .update_rate_tbl = rtl92cu_update_hal_rate_table, .update_rate_mask = rtl92cu_update_hal_rate_mask, .fill_tx_desc = rtl92cu_tx_fill_desc, .fill_fake_txdesc = rtl92cu_fill_fake_txdesc, diff --git a/drivers/net/wireless/rtlwifi/rtl8192cu/trx.c b/drivers/net/wireless/rtlwifi/rtl8192cu/trx.c index cc5de07..79c98f6 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192cu/trx.c +++ b/drivers/net/wireless/rtlwifi/rtl8192cu/trx.c @@ -498,14 +498,14 @@ static void _rtl_tx_desc_checksum(u8 *txdesc) void rtl92cu_tx_fill_desc(struct ieee80211_hw *hw, struct ieee80211_hdr *hdr, u8 *pdesc_tx, struct ieee80211_tx_info *info, struct sk_buff *skb, - unsigned int queue_index) + u8 queue_index, + struct rtl_tcb_desc *tcb_desc) { struct rtl_priv *rtlpriv = rtl_priv(hw); struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); bool defaultadapter = true; - struct ieee80211_sta *sta = info->control.sta; - struct rtl_tcb_desc tcb_desc; + struct ieee80211_sta *sta = info->control.sta = info->control.sta; u8 *qc = ieee80211_get_qos_ctl(hdr); u8 tid = qc[0] & IEEE80211_QOS_CTL_TID_MASK; u16 seq_number; @@ -517,15 +517,15 @@ void rtl92cu_tx_fill_desc(struct ieee80211_hw *hw, u8 *txdesc; seq_number = (le16_to_cpu(hdr->seq_ctrl) & IEEE80211_SCTL_SEQ) >> 4; - rtl_get_tcb_desc(hw, info, sta, skb, &tcb_desc); + rtl_get_tcb_desc(hw, info, sta, skb, tcb_desc); txdesc = (u8 *)skb_push(skb, RTL_TX_HEADER_SIZE); memset(txdesc, 0, RTL_TX_HEADER_SIZE); SET_TX_DESC_PKT_SIZE(txdesc, pktlen); SET_TX_DESC_LINIP(txdesc, 0); SET_TX_DESC_PKT_OFFSET(txdesc, RTL_DUMMY_OFFSET); SET_TX_DESC_OFFSET(txdesc, RTL_TX_HEADER_SIZE); - SET_TX_DESC_TX_RATE(txdesc, tcb_desc.hw_rate); - if (tcb_desc.use_shortgi || tcb_desc.use_shortpreamble) + SET_TX_DESC_TX_RATE(txdesc, tcb_desc->hw_rate); + if (tcb_desc->use_shortgi || tcb_desc->use_shortpreamble) SET_TX_DESC_DATA_SHORTGI(txdesc, 1); if (mac->tids[tid].agg.agg_state == RTL_AGG_ON && info->flags & IEEE80211_TX_CTL_AMPDU) { @@ -535,21 +535,21 @@ void rtl92cu_tx_fill_desc(struct ieee80211_hw *hw, SET_TX_DESC_AGG_BREAK(txdesc, 1); } SET_TX_DESC_SEQ(txdesc, seq_number); - SET_TX_DESC_RTS_ENABLE(txdesc, ((tcb_desc.rts_enable && - !tcb_desc.cts_enable) ? 1 : 0)); - SET_TX_DESC_HW_RTS_ENABLE(txdesc, ((tcb_desc.rts_enable || - tcb_desc.cts_enable) ? 1 : 0)); - SET_TX_DESC_CTS2SELF(txdesc, ((tcb_desc.cts_enable) ? 1 : 0)); - SET_TX_DESC_RTS_STBC(txdesc, ((tcb_desc.rts_stbc) ? 1 : 0)); - SET_TX_DESC_RTS_RATE(txdesc, tcb_desc.rts_rate); + SET_TX_DESC_RTS_ENABLE(txdesc, ((tcb_desc->rts_enable && + !tcb_desc->cts_enable) ? 1 : 0)); + SET_TX_DESC_HW_RTS_ENABLE(txdesc, ((tcb_desc->rts_enable || + tcb_desc->cts_enable) ? 1 : 0)); + SET_TX_DESC_CTS2SELF(txdesc, ((tcb_desc->cts_enable) ? 1 : 0)); + SET_TX_DESC_RTS_STBC(txdesc, ((tcb_desc->rts_stbc) ? 1 : 0)); + SET_TX_DESC_RTS_RATE(txdesc, tcb_desc->rts_rate); SET_TX_DESC_RTS_BW(txdesc, 0); - SET_TX_DESC_RTS_SC(txdesc, tcb_desc.rts_sc); + SET_TX_DESC_RTS_SC(txdesc, tcb_desc->rts_sc); SET_TX_DESC_RTS_SHORT(txdesc, - ((tcb_desc.rts_rate <= DESC92C_RATE54M) ? - (tcb_desc.rts_use_shortpreamble ? 1 : 0) - : (tcb_desc.rts_use_shortgi ? 1 : 0))); + ((tcb_desc->rts_rate <= DESC92C_RATE54M) ? + (tcb_desc->rts_use_shortpreamble ? 1 : 0) + : (tcb_desc->rts_use_shortgi ? 1 : 0))); if (mac->bw_40) { - if (tcb_desc.packet_bw) { + if (tcb_desc->packet_bw) { SET_TX_DESC_DATA_BW(txdesc, 1); SET_TX_DESC_DATA_SC(txdesc, 3); } else { @@ -590,7 +590,7 @@ void rtl92cu_tx_fill_desc(struct ieee80211_hw *hw, SET_TX_DESC_DATA_RATE_FB_LIMIT(txdesc, 0x1F); SET_TX_DESC_RTS_RATE_FB_LIMIT(txdesc, 0xF); SET_TX_DESC_DISABLE_FB(txdesc, 0); - SET_TX_DESC_USE_RATE(txdesc, tcb_desc.use_driver_rate ? 1 : 0); + SET_TX_DESC_USE_RATE(txdesc, tcb_desc->use_driver_rate ? 1 : 0); if (ieee80211_is_data_qos(fc)) { if (mac->rdg_en) { RT_TRACE(rtlpriv, COMP_SEND, DBG_TRACE, @@ -600,11 +600,11 @@ void rtl92cu_tx_fill_desc(struct ieee80211_hw *hw, } } if (rtlpriv->dm.useramask) { - SET_TX_DESC_RATE_ID(txdesc, tcb_desc.ratr_index); - SET_TX_DESC_MACID(txdesc, tcb_desc.mac_id); + SET_TX_DESC_RATE_ID(txdesc, tcb_desc->ratr_index); + SET_TX_DESC_MACID(txdesc, tcb_desc->mac_id); } else { - SET_TX_DESC_RATE_ID(txdesc, 0xC + tcb_desc.ratr_index); - SET_TX_DESC_MACID(txdesc, tcb_desc.ratr_index); + SET_TX_DESC_RATE_ID(txdesc, 0xC + tcb_desc->ratr_index); + SET_TX_DESC_MACID(txdesc, tcb_desc->ratr_index); } if ((!ieee80211_is_data_qos(fc)) && ppsc->leisure_ps && ppsc->fwctrl_lps) { @@ -656,7 +656,7 @@ void rtl92cu_tx_fill_cmddesc(struct ieee80211_hw *hw, struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)(skb->data); __le16 fc = hdr->frame_control; - memset(pdesc, 0, RTL_TX_HEADER_SIZE); + memset((void *)pdesc, 0, RTL_TX_HEADER_SIZE); if (firstseg) SET_TX_DESC_OFFSET(pdesc, RTL_TX_HEADER_SIZE); SET_TX_DESC_TX_RATE(pdesc, DESC92C_RATE1M); diff --git a/drivers/net/wireless/rtlwifi/rtl8192cu/trx.h b/drivers/net/wireless/rtlwifi/rtl8192cu/trx.h index b396d46..53de5f6 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192cu/trx.h +++ b/drivers/net/wireless/rtlwifi/rtl8192cu/trx.h @@ -37,6 +37,8 @@ #define RTL92C_SIZE_MAX_RX_BUFFER 15360 /* 8192 */ #define RX_DRV_INFO_SIZE_UNIT 8 +#define RTL_AGG_ON 1 + enum usb_rx_agg_mode { USB_RX_AGG_DISABLE, USB_RX_AGG_DMA, @@ -419,7 +421,8 @@ struct sk_buff *rtl8192c_tx_aggregate_hdl(struct ieee80211_hw *, void rtl92cu_tx_fill_desc(struct ieee80211_hw *hw, struct ieee80211_hdr *hdr, u8 *pdesc_tx, struct ieee80211_tx_info *info, struct sk_buff *skb, - unsigned int queue_index); + u8 queue_index, + struct rtl_tcb_desc *tcb_desc); void rtl92cu_fill_fake_txdesc(struct ieee80211_hw *hw, u8 * pDesc, u32 buffer_len, bool bIsPsPoll); void rtl92cu_tx_fill_cmddesc(struct ieee80211_hw *hw, diff --git a/drivers/net/wireless/rtlwifi/wifi.h b/drivers/net/wireless/rtlwifi/wifi.h index 683f7f7..690508f 100644 --- a/drivers/net/wireless/rtlwifi/wifi.h +++ b/drivers/net/wireless/rtlwifi/wifi.h @@ -1370,13 +1370,8 @@ struct rtl_hal_ops { u32 add_msr, u32 rm_msr); void (*get_hw_reg) (struct ieee80211_hw *hw, u8 variable, u8 *val); void (*set_hw_reg) (struct ieee80211_hw *hw, u8 variable, u8 *val); -#if 1 /* temporary */ void (*update_rate_tbl) (struct ieee80211_hw *hw, struct ieee80211_sta *sta, u8 rssi_level); -#endif -#if 1 /* temporary */ - void (*update_rate_table) (struct ieee80211_hw *hw); -#endif void (*update_rate_mask) (struct ieee80211_hw *hw, u8 rssi_level); void (*fill_tx_desc) (struct ieee80211_hw *hw, struct ieee80211_hdr *hdr, u8 *pdesc_tx, -- cgit v0.10.2 From d3bb1429a2c1470d1f84646c00e34dc6784ee06e Mon Sep 17 00:00:00 2001 From: Larry Finger Date: Mon, 25 Apr 2011 13:23:20 -0500 Subject: rtlwifi: rtl8192ce: rtl8192cu: Fix most sparse warnings Fix most sparse warnings in rtlwifi, rtl8192ce and rtl8192cu drivers. Signed-off-by: Larry Finger Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/rtlwifi/base.c b/drivers/net/wireless/rtlwifi/base.c index 2df9946..d366657 100644 --- a/drivers/net/wireless/rtlwifi/base.c +++ b/drivers/net/wireless/rtlwifi/base.c @@ -795,7 +795,7 @@ u8 rtl_is_special_data(struct ieee80211_hw *hw, struct sk_buff *skb, u8 is_tx) ip = (struct iphdr *)((u8 *) skb->data + mac_hdr_len + SNAP_SIZE + PROTOC_TYPE_SIZE); ether_type = *(u16 *) ((u8 *) skb->data + mac_hdr_len + SNAP_SIZE); - ether_type = ntohs(ether_type); + /* ether_type = ntohs(ether_type); */ if (ETH_P_IP == ether_type) { if (IPPROTO_UDP == ip->protocol) { @@ -1105,7 +1105,7 @@ u8 *rtl_find_ie(u8 *data, unsigned int len, u8 ie) /* when we use 2 rx ants we send IEEE80211_SMPS_OFF */ /* when we use 1 rx ant we send IEEE80211_SMPS_STATIC */ -struct sk_buff *rtl_make_smps_action(struct ieee80211_hw *hw, +static struct sk_buff *rtl_make_smps_action(struct ieee80211_hw *hw, enum ieee80211_smps_mode smps, u8 *da, u8 *bssid) { struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw)); @@ -1230,7 +1230,7 @@ static bool rtl_chk_vendor_ouisub(struct ieee80211_hw *hw, return matched; } -bool rtl_find_221_ie(struct ieee80211_hw *hw, u8 *data, +static bool rtl_find_221_ie(struct ieee80211_hw *hw, u8 *data, unsigned int len) { struct ieee80211_mgmt *mgmt = (void *)data; diff --git a/drivers/net/wireless/rtlwifi/efuse.c b/drivers/net/wireless/rtlwifi/efuse.c index 664703c..510d42e 100644 --- a/drivers/net/wireless/rtlwifi/efuse.c +++ b/drivers/net/wireless/rtlwifi/efuse.c @@ -235,7 +235,7 @@ void read_efuse(struct ieee80211_hw *hw, u16 _offset, u16 _size_byte, u8 *pbuf) { struct rtl_priv *rtlpriv = rtl_priv(hw); struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw)); - u8 efuse_tbl[rtlpriv->cfg->maps[EFUSE_HWSET_MAX_SIZE]]; + u8 efuse_tbl[HWSET_MAX_SIZE]; u8 rtemp8[1]; u16 efuse_addr = 0; u8 offset, wren; @@ -245,7 +245,7 @@ void read_efuse(struct ieee80211_hw *hw, u16 _offset, u16 _size_byte, u8 *pbuf) rtlpriv->cfg->maps[EFUSE_MAX_SECTION_MAP]; const u32 efuse_len = rtlpriv->cfg->maps[EFUSE_REAL_CONTENT_SIZE]; - u16 efuse_word[efuse_max_section][EFUSE_MAX_WORD_UNIT]; + u16 efuse_word[EFUSE_MAX_SECTION][EFUSE_MAX_WORD_UNIT]; u16 efuse_utilized = 0; u8 efuse_usage; diff --git a/drivers/net/wireless/rtlwifi/pci.c b/drivers/net/wireless/rtlwifi/pci.c index aeb0901..367d9b4 100644 --- a/drivers/net/wireless/rtlwifi/pci.c +++ b/drivers/net/wireless/rtlwifi/pci.c @@ -48,11 +48,11 @@ static const u8 ac_to_hwq[] = { BK_QUEUE }; -u8 _rtl_mac_to_hwqueue(struct ieee80211_hw *hw, +static u8 _rtl_mac_to_hwqueue(struct ieee80211_hw *hw, struct sk_buff *skb) { struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); - u16 fc = rtl_get_fc(skb); + __le16 fc = rtl_get_fc(skb); u8 queue_index = skb_get_queue_mapping(skb); if (unlikely(ieee80211_is_beacon(fc))) @@ -181,71 +181,6 @@ static void _rtl_pci_update_default_setting(struct ieee80211_hw *hw) ppsc->support_aspm = false; } -/*Disable L0s dirtectly. We will disable host L0s by default. */ -void rtl_pci_disable_host_l0s(struct ieee80211_hw *hw) -{ - struct rtl_priv *rtlpriv = rtl_priv(hw); - struct rtl_pci_priv *pcipriv = rtl_pcipriv(hw); - struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); - u8 pcibridge_busnum = pcipriv->ndis_adapter.pcibridge_busnum; - u8 pcibridge_devnum = pcipriv->ndis_adapter.pcibridge_devnum; - u8 pcibridge_funcnum = pcipriv->ndis_adapter.pcibridge_funcnum; - u32 pcicfg_addrport = pcipriv->ndis_adapter.pcicfg_addrport; - u8 num4bytes = pcipriv->ndis_adapter.num4bytes; - u8 u_pcibridge_aspmsetting = 0; - - /*Read Link Control Register */ - rtl_pci_raw_write_port_ulong(PCI_CONF_ADDRESS, - pcicfg_addrport + (num4bytes << 2)); - rtl_pci_raw_read_port_uchar(PCI_CONF_DATA, &u_pcibridge_aspmsetting); - - if (u_pcibridge_aspmsetting & BIT(0)) - u_pcibridge_aspmsetting &= ~(BIT(0)); - - rtl_pci_raw_write_port_ulong(PCI_CONF_ADDRESS, - pcicfg_addrport + (num4bytes << 2)); - rtl_pci_raw_write_port_uchar(PCI_CONF_DATA, u_pcibridge_aspmsetting); - - udelay(50); - - RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, - ("PciBridge busnumber[%x], DevNumbe[%x], " - "funcnumber[%x], Write reg[%x] = %lx\n", - pcibridge_busnum, pcibridge_devnum, pcibridge_funcnum, - (pcipriv->ndis_adapter.pcibridge_pciehdr_offset + 0x10), - (pcipriv->ndis_adapter.pcibridge_linkctrlreg | - (rtlpci->const_devicepci_aspm_setting & ~BIT(0))))); -} - -/*Enable rtl8192ce backdoor to control ASPM and clock request.*/ -bool rtl_pci_enable_back_door(struct ieee80211_hw *hw) -{ - struct rtl_pci_priv *pcipriv = rtl_pcipriv(hw); - struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); - u8 pcibridge_vendor = pcipriv->ndis_adapter.pcibridge_vendor; - bool bresult = true; - u8 value; - - pci_read_config_byte(rtlpci->pdev, 0x70f, &value); - - /*0x70f BIT(7) is used to control L0S */ - if (pcibridge_vendor == PCI_BRIDGE_VENDOR_INTEL) { - value |= BIT(7); - } else { - /*Set 0x70f to 0x23 when non-Intel platform. */ - value = 0x23; - } - - pci_write_config_byte(rtlpci->pdev, 0x70f, value); - - pci_read_config_byte(rtlpci->pdev, 0x719, &value); - /*0x719 BIT(3) is for L1 BIT(4) is for clock request */ - value |= (BIT(3) | BIT(4)); - pci_write_config_byte(rtlpci->pdev, 0x719, value); - - return bresult; -} - static bool _rtl_pci_platform_switch_device_pci_aspm( struct ieee80211_hw *hw, u8 value) @@ -426,7 +361,7 @@ static bool rtl_pci_get_amd_l1_patch(struct ieee80211_hw *hw) return status; } -void rtl_pci_get_linkcontrol_field(struct ieee80211_hw *hw) +static void rtl_pci_get_linkcontrol_field(struct ieee80211_hw *hw) { struct rtl_pci_priv *pcipriv = rtl_pcipriv(hw); u8 capabilityoffset = pcipriv->ndis_adapter.pcibridge_pciehdr_offset; @@ -618,9 +553,9 @@ static void _rtl_pci_tx_isr(struct ieee80211_hw *hw, int prio) skb = __skb_dequeue(&ring->queue); pci_unmap_single(rtlpci->pdev, - le32_to_cpu(rtlpriv->cfg->ops-> + rtlpriv->cfg->ops-> get_desc((u8 *) entry, true, - HW_DESC_TXBUFF_ADDR)), + HW_DESC_TXBUFF_ADDR), skb->len, PCI_DMA_TODEVICE); /* remove early mode header */ @@ -844,7 +779,7 @@ static void _rtl_pci_rx_interrupt(struct ieee80211_hw *hw) } done: - bufferaddress = cpu_to_le32(*((dma_addr_t *)skb->cb)); + bufferaddress = (*((dma_addr_t *)skb->cb)); tmp_one = 1; rtlpriv->cfg->ops->set_desc((u8 *) pdesc, false, HW_DESC_RXBUFF_ADDR, @@ -868,75 +803,6 @@ done: } -void _rtl_pci_tx_interrupt(struct ieee80211_hw *hw) -{ - struct rtl_priv *rtlpriv = rtl_priv(hw); - struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); - int prio; - - for (prio = 0; prio < RTL_PCI_MAX_TX_QUEUE_COUNT; prio++) { - struct rtl8192_tx_ring *ring = &rtlpci->tx_ring[prio]; - - while (skb_queue_len(&ring->queue)) { - struct rtl_tx_desc *entry = &ring->desc[ring->idx]; - struct sk_buff *skb; - struct ieee80211_tx_info *info; - u8 own; - - /* - *beacon packet will only use the first - *descriptor defautly, and the own may not - *be cleared by the hardware, and - *beacon will free in prepare beacon - */ - if (prio == BEACON_QUEUE || prio == TXCMD_QUEUE || - prio == HCCA_QUEUE) - break; - - own = (u8) rtlpriv->cfg->ops->get_desc((u8 *) entry, - true, - HW_DESC_OWN); - - if (own) - break; - - skb = __skb_dequeue(&ring->queue); - pci_unmap_single(rtlpci->pdev, - le32_to_cpu(rtlpriv->cfg->ops-> - get_desc((u8 *) entry, - true, - HW_DESC_TXBUFF_ADDR)), - skb->len, PCI_DMA_TODEVICE); - - ring->idx = (ring->idx + 1) % ring->entries; - - info = IEEE80211_SKB_CB(skb); - ieee80211_tx_info_clear_status(info); - - info->flags |= IEEE80211_TX_STAT_ACK; - /*info->status.rates[0].count = 1; */ - - ieee80211_tx_status_irqsafe(hw, skb); - - if ((ring->entries - skb_queue_len(&ring->queue)) - == 2 && prio != BEACON_QUEUE) { - RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, - ("more desc left, wake " - "skb_queue@%d,ring->idx = %d," - "skb_queue_len = 0x%d\n", - prio, ring->idx, - skb_queue_len(&ring->queue))); - - ieee80211_wake_queue(hw, - skb_get_queue_mapping - (skb)); - } - - skb = NULL; - } - } -} - static irqreturn_t _rtl_pci_interrupt(int irq, void *dev_id) { struct ieee80211_hw *hw = dev_id; @@ -1202,9 +1068,9 @@ static int _rtl_pci_init_tx_ring(struct ieee80211_hw *hw, ("queue:%d, ring_addr:%p\n", prio, ring)); for (i = 0; i < entries; i++) { - nextdescaddress = cpu_to_le32((u32) dma + + nextdescaddress = (u32) dma + ((i + 11) % entries) * - sizeof(*ring)); + sizeof(*ring); rtlpriv->cfg->ops->set_desc((u8 *)&(ring[i]), true, HW_DESC_TX_NEXTDESC_ADDR, @@ -1268,7 +1134,7 @@ static int _rtl_pci_init_rx_ring(struct ieee80211_hw *hw) rtlpci->rxbuffersize, PCI_DMA_FROMDEVICE); - bufferaddress = cpu_to_le32(*((dma_addr_t *)skb->cb)); + bufferaddress = (*((dma_addr_t *)skb->cb)); rtlpriv->cfg->ops->set_desc((u8 *)entry, false, HW_DESC_RXBUFF_ADDR, (u8 *)&bufferaddress); @@ -1299,9 +1165,9 @@ static void _rtl_pci_free_tx_ring(struct ieee80211_hw *hw, struct sk_buff *skb = __skb_dequeue(&ring->queue); pci_unmap_single(rtlpci->pdev, - le32_to_cpu(rtlpriv->cfg-> + rtlpriv->cfg-> ops->get_desc((u8 *) entry, true, - HW_DESC_TXBUFF_ADDR)), + HW_DESC_TXBUFF_ADDR), skb->len, PCI_DMA_TODEVICE); kfree_skb(skb); ring->idx = (ring->idx + 1) % ring->entries; @@ -1433,11 +1299,11 @@ int rtl_pci_reset_trx_ring(struct ieee80211_hw *hw) __skb_dequeue(&ring->queue); pci_unmap_single(rtlpci->pdev, - le32_to_cpu(rtlpriv->cfg->ops-> + rtlpriv->cfg->ops-> get_desc((u8 *) entry, true, - HW_DESC_TXBUFF_ADDR)), + HW_DESC_TXBUFF_ADDR), skb->len, PCI_DMA_TODEVICE); kfree_skb(skb); ring->idx = (ring->idx + 1) % ring->entries; @@ -1484,7 +1350,7 @@ static bool rtl_pci_tx_chk_waitq_insert(struct ieee80211_hw *hw, return true; } -int rtl_pci_tx(struct ieee80211_hw *hw, struct sk_buff *skb, +static int rtl_pci_tx(struct ieee80211_hw *hw, struct sk_buff *skb, struct rtl_tcb_desc *ptcb_desc) { struct rtl_priv *rtlpriv = rtl_priv(hw); @@ -1623,7 +1489,7 @@ static void rtl_pci_flush(struct ieee80211_hw *hw, bool drop) } } -void rtl_pci_deinit(struct ieee80211_hw *hw) +static void rtl_pci_deinit(struct ieee80211_hw *hw) { struct rtl_priv *rtlpriv = rtl_priv(hw); struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); @@ -1638,7 +1504,7 @@ void rtl_pci_deinit(struct ieee80211_hw *hw) } -int rtl_pci_init(struct ieee80211_hw *hw, struct pci_dev *pdev) +static int rtl_pci_init(struct ieee80211_hw *hw, struct pci_dev *pdev) { struct rtl_priv *rtlpriv = rtl_priv(hw); int err; @@ -1655,7 +1521,7 @@ int rtl_pci_init(struct ieee80211_hw *hw, struct pci_dev *pdev) return 1; } -int rtl_pci_start(struct ieee80211_hw *hw) +static int rtl_pci_start(struct ieee80211_hw *hw) { struct rtl_priv *rtlpriv = rtl_priv(hw); struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); @@ -1690,7 +1556,7 @@ int rtl_pci_start(struct ieee80211_hw *hw) return 0; } -void rtl_pci_stop(struct ieee80211_hw *hw) +static void rtl_pci_stop(struct ieee80211_hw *hw) { struct rtl_priv *rtlpriv = rtl_priv(hw); struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); diff --git a/drivers/net/wireless/rtlwifi/rtl8192c/dm_common.c b/drivers/net/wireless/rtlwifi/rtl8192c/dm_common.c index bfc8405..9718382 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192c/dm_common.c +++ b/drivers/net/wireless/rtlwifi/rtl8192c/dm_common.c @@ -1238,51 +1238,6 @@ static void rtl92c_dm_init_dynamic_bb_powersaving(struct ieee80211_hw *hw) dm_pstable.rssi_val_min = 0; } -void rtl92c_dm_1r_cca(struct ieee80211_hw *hw) -{ - struct rtl_priv *rtlpriv = rtl_priv(hw); - struct rtl_phy *rtlphy = &(rtlpriv->phy); - - if (dm_pstable.rssi_val_min != 0) { - if (dm_pstable.pre_ccastate == CCA_2R) { - if (dm_pstable.rssi_val_min >= 35) - dm_pstable.cur_ccasate = CCA_1R; - else - dm_pstable.cur_ccasate = CCA_2R; - } else { - if (dm_pstable.rssi_val_min <= 30) - dm_pstable.cur_ccasate = CCA_2R; - else - dm_pstable.cur_ccasate = CCA_1R; - } - } else { - dm_pstable.cur_ccasate = CCA_MAX; - } - - if (dm_pstable.pre_ccastate != dm_pstable.cur_ccasate) { - if (dm_pstable.cur_ccasate == CCA_1R) { - if (get_rf_type(rtlphy) == RF_2T2R) { - rtl_set_bbreg(hw, ROFDM0_TRXPATHENABLE, - MASKBYTE0, 0x13); - rtl_set_bbreg(hw, 0xe70, MASKBYTE3, 0x20); - } else { - rtl_set_bbreg(hw, ROFDM0_TRXPATHENABLE, - MASKBYTE0, 0x23); - rtl_set_bbreg(hw, 0xe70, 0x7fc00000, 0x10c); - } - } else { - rtl_set_bbreg(hw, ROFDM0_TRXPATHENABLE, MASKBYTE0, - 0x33); - rtl_set_bbreg(hw, 0xe70, MASKBYTE3, 0x63); - } - dm_pstable.pre_ccastate = dm_pstable.cur_ccasate; - } - - RT_TRACE(rtlpriv, DBG_LOUD, DBG_LOUD, ("CCAStage = %s\n", - (dm_pstable.cur_ccasate == - 0) ? "1RCCA" : "2RCCA")); -} - void rtl92c_dm_rf_saving(struct ieee80211_hw *hw, u8 bforce_in_normal) { static u8 initialize; diff --git a/drivers/net/wireless/rtlwifi/rtl8192c/phy_common.c b/drivers/net/wireless/rtlwifi/rtl8192c/phy_common.c index 991d865..c5424ca 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192c/phy_common.c +++ b/drivers/net/wireless/rtlwifi/rtl8192c/phy_common.c @@ -83,7 +83,7 @@ void rtl92c_phy_set_bb_reg(struct ieee80211_hw *hw, EXPORT_SYMBOL(rtl92c_phy_set_bb_reg); u32 _rtl92c_phy_fw_rf_serial_read(struct ieee80211_hw *hw, - enum radio_path rfpath, u32 offset) + enum radio_path rfpath, u32 offset) { RT_ASSERT(false, ("deprecated!\n")); return 0; @@ -92,15 +92,15 @@ u32 _rtl92c_phy_fw_rf_serial_read(struct ieee80211_hw *hw, EXPORT_SYMBOL(_rtl92c_phy_fw_rf_serial_read); void _rtl92c_phy_fw_rf_serial_write(struct ieee80211_hw *hw, - enum radio_path rfpath, u32 offset, - u32 data) + enum radio_path rfpath, u32 offset, + u32 data) { RT_ASSERT(false, ("deprecated!\n")); } EXPORT_SYMBOL(_rtl92c_phy_fw_rf_serial_write); u32 _rtl92c_phy_rf_serial_read(struct ieee80211_hw *hw, - enum radio_path rfpath, u32 offset) + enum radio_path rfpath, u32 offset) { struct rtl_priv *rtlpriv = rtl_priv(hw); struct rtl_phy *rtlphy = &(rtlpriv->phy); @@ -151,8 +151,8 @@ u32 _rtl92c_phy_rf_serial_read(struct ieee80211_hw *hw, EXPORT_SYMBOL(_rtl92c_phy_rf_serial_read); void _rtl92c_phy_rf_serial_write(struct ieee80211_hw *hw, - enum radio_path rfpath, u32 offset, - u32 data) + enum radio_path rfpath, u32 offset, + u32 data) { u32 data_and_addr; u32 newoffset; @@ -250,8 +250,8 @@ bool _rtl92c_phy_bb8192c_config_parafile(struct ieee80211_hw *hw) EXPORT_SYMBOL(_rtl92c_phy_bb8192c_config_parafile); void _rtl92c_store_pwrIndex_diffrate_offset(struct ieee80211_hw *hw, - u32 regaddr, u32 bitmask, - u32 data) + u32 regaddr, u32 bitmask, + u32 data) { struct rtl_priv *rtlpriv = rtl_priv(hw); struct rtl_phy *rtlphy = &(rtlpriv->phy); diff --git a/drivers/net/wireless/rtlwifi/rtl8192c/phy_common.h b/drivers/net/wireless/rtlwifi/rtl8192c/phy_common.h index b09a458..9a264c0 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192c/phy_common.h +++ b/drivers/net/wireless/rtlwifi/rtl8192c/phy_common.h @@ -238,5 +238,21 @@ void _rtl92c_phy_set_rf_sleep(struct ieee80211_hw *hw); bool _rtl92c_phy_sw_chnl_step_by_step(struct ieee80211_hw *hw, u8 channel, u8 *stage, u8 *step, u32 *delay); +u8 rtl92c_bt_rssi_state_change(struct ieee80211_hw *hw); +u32 _rtl92c_phy_fw_rf_serial_read(struct ieee80211_hw *hw, + enum radio_path rfpath, u32 offset); +void _rtl92c_phy_fw_rf_serial_write(struct ieee80211_hw *hw, + enum radio_path rfpath, u32 offset, + u32 data); +u32 _rtl92c_phy_rf_serial_read(struct ieee80211_hw *hw, + enum radio_path rfpath, u32 offset); +void _rtl92c_phy_rf_serial_write(struct ieee80211_hw *hw, + enum radio_path rfpath, u32 offset, + u32 data); +bool _rtl92c_phy_bb8192c_config_parafile(struct ieee80211_hw *hw); +void _rtl92c_store_pwrIndex_diffrate_offset(struct ieee80211_hw *hw, + u32 regaddr, u32 bitmask, + u32 data); +bool rtl92c_phy_set_io_cmd(struct ieee80211_hw *hw, enum io_type iotype); #endif diff --git a/drivers/net/wireless/rtlwifi/rtl8192ce/hw.c b/drivers/net/wireless/rtlwifi/rtl8192ce/hw.c index 794b4b6..4a56138 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192ce/hw.c +++ b/drivers/net/wireless/rtlwifi/rtl8192ce/hw.c @@ -2177,7 +2177,7 @@ void rtl92ce_set_key(struct ieee80211_hw *hw, u32 key_index, } } -void rtl8192ce_bt_var_init(struct ieee80211_hw *hw) +static void rtl8192ce_bt_var_init(struct ieee80211_hw *hw) { struct rtl_pci_priv *rtlpcipriv = rtl_pcipriv(hw); diff --git a/drivers/net/wireless/rtlwifi/rtl8192ce/phy.c b/drivers/net/wireless/rtlwifi/rtl8192ce/phy.c index 6045401..73ae8a4 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192ce/phy.c +++ b/drivers/net/wireless/rtlwifi/rtl8192ce/phy.c @@ -366,75 +366,6 @@ bool rtl92c_phy_config_rf_with_headerfile(struct ieee80211_hw *hw, return true; } -void rtl92c_phy_set_bw_mode_callback(struct ieee80211_hw *hw) -{ - struct rtl_priv *rtlpriv = rtl_priv(hw); - struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); - struct rtl_phy *rtlphy = &(rtlpriv->phy); - struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); - u8 reg_bw_opmode; - u8 reg_prsr_rsc; - - RT_TRACE(rtlpriv, COMP_SCAN, DBG_TRACE, - ("Switch to %s bandwidth\n", - rtlphy->current_chan_bw == HT_CHANNEL_WIDTH_20 ? - "20MHz" : "40MHz")) - - if (is_hal_stop(rtlhal)) { - rtlphy->set_bwmode_inprogress = false; - return; - } - - reg_bw_opmode = rtl_read_byte(rtlpriv, REG_BWOPMODE); - reg_prsr_rsc = rtl_read_byte(rtlpriv, REG_RRSR + 2); - - switch (rtlphy->current_chan_bw) { - case HT_CHANNEL_WIDTH_20: - reg_bw_opmode |= BW_OPMODE_20MHZ; - rtl_write_byte(rtlpriv, REG_BWOPMODE, reg_bw_opmode); - break; - case HT_CHANNEL_WIDTH_20_40: - reg_bw_opmode &= ~BW_OPMODE_20MHZ; - rtl_write_byte(rtlpriv, REG_BWOPMODE, reg_bw_opmode); - reg_prsr_rsc = - (reg_prsr_rsc & 0x90) | (mac->cur_40_prime_sc << 5); - rtl_write_byte(rtlpriv, REG_RRSR + 2, reg_prsr_rsc); - break; - default: - RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, - ("unknown bandwidth: %#X\n", rtlphy->current_chan_bw)); - break; - } - - switch (rtlphy->current_chan_bw) { - case HT_CHANNEL_WIDTH_20: - rtl_set_bbreg(hw, RFPGA0_RFMOD, BRFMOD, 0x0); - rtl_set_bbreg(hw, RFPGA1_RFMOD, BRFMOD, 0x0); - rtl_set_bbreg(hw, RFPGA0_ANALOGPARAMETER2, BIT(10), 1); - break; - case HT_CHANNEL_WIDTH_20_40: - rtl_set_bbreg(hw, RFPGA0_RFMOD, BRFMOD, 0x1); - rtl_set_bbreg(hw, RFPGA1_RFMOD, BRFMOD, 0x1); - - rtl_set_bbreg(hw, RCCK0_SYSTEM, BCCK_SIDEBAND, - (mac->cur_40_prime_sc >> 1)); - rtl_set_bbreg(hw, ROFDM1_LSTF, 0xC00, mac->cur_40_prime_sc); - rtl_set_bbreg(hw, RFPGA0_ANALOGPARAMETER2, BIT(10), 0); - - rtl_set_bbreg(hw, 0x818, (BIT(26) | BIT(27)), - (mac->cur_40_prime_sc == - HAL_PRIME_CHNL_OFFSET_LOWER) ? 2 : 1); - break; - default: - RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, - ("unknown bandwidth: %#X\n", rtlphy->current_chan_bw)); - break; - } - rtl92ce_phy_rf6052_set_bandwidth(hw, rtlphy->current_chan_bw); - rtlphy->set_bwmode_inprogress = false; - RT_TRACE(rtlpriv, COMP_SCAN, DBG_TRACE, ("<==\n")); -} - void _rtl92ce_phy_lc_calibrate(struct ieee80211_hw *hw, bool is2t) { u8 tmpreg; diff --git a/drivers/net/wireless/rtlwifi/rtl8192ce/phy.h b/drivers/net/wireless/rtlwifi/rtl8192ce/phy.h index eb93088..ad58085 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192ce/phy.h +++ b/drivers/net/wireless/rtlwifi/rtl8192ce/phy.h @@ -253,5 +253,9 @@ bool _rtl92c_phy_bb8192c_config_parafile(struct ieee80211_hw *hw); void _rtl92c_phy_set_rf_sleep(struct ieee80211_hw *hw); bool rtl92c_phy_set_rf_power_state(struct ieee80211_hw *hw, enum rf_pwrstate rfpwr_state); +bool _rtl92ce_phy_config_bb_with_headerfile(struct ieee80211_hw *hw, + u8 configtype); +bool _rtl92ce_phy_config_bb_with_pgheaderfile(struct ieee80211_hw *hw, + u8 configtype); #endif diff --git a/drivers/net/wireless/rtlwifi/rtl8192ce/reg.h b/drivers/net/wireless/rtlwifi/rtl8192ce/reg.h index 115b3f8..598cecc 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192ce/reg.h +++ b/drivers/net/wireless/rtlwifi/rtl8192ce/reg.h @@ -543,8 +543,6 @@ #define IMR_OCPINT BIT(1) #define IMR_WLANOFF BIT(0) -#define HWSET_MAX_SIZE 128 -#define EFUSE_MAX_SECTION 16 #define EFUSE_REAL_CONTENT_LEN 512 #define EEPROM_DEFAULT_TSSI 0x0 diff --git a/drivers/net/wireless/rtlwifi/rtl8192ce/sw.c b/drivers/net/wireless/rtlwifi/rtl8192ce/sw.c index 702dd11..390bbb5 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192ce/sw.c +++ b/drivers/net/wireless/rtlwifi/rtl8192ce/sw.c @@ -42,7 +42,7 @@ #include "trx.h" #include "led.h" -void rtl92c_init_aspm_vars(struct ieee80211_hw *hw) +static void rtl92c_init_aspm_vars(struct ieee80211_hw *hw) { struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); @@ -185,7 +185,7 @@ void rtl92c_deinit_sw_vars(struct ieee80211_hw *hw) } } -struct rtl_hal_ops rtl8192ce_hal_ops = { +static struct rtl_hal_ops rtl8192ce_hal_ops = { .init_sw_vars = rtl92c_init_sw_vars, .deinit_sw_vars = rtl92c_deinit_sw_vars, .read_eeprom_info = rtl92ce_read_eeprom_info, @@ -235,14 +235,14 @@ struct rtl_hal_ops rtl8192ce_hal_ops = { .dm_dynamic_txpower = rtl92ce_dm_dynamic_txpower, }; -struct rtl_mod_params rtl92ce_mod_params = { +static struct rtl_mod_params rtl92ce_mod_params = { .sw_crypto = false, .inactiveps = true, .swctrl_lps = false, .fwctrl_lps = true, }; -struct rtl_hal_cfg rtl92ce_hal_cfg = { +static struct rtl_hal_cfg rtl92ce_hal_cfg = { .bar_id = 2, .write_readback = true, .name = "rtl92c_pci", diff --git a/drivers/net/wireless/rtlwifi/rtl8192ce/trx.c b/drivers/net/wireless/rtlwifi/rtl8192ce/trx.c index f76d406..54b2bd5 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192ce/trx.c +++ b/drivers/net/wireless/rtlwifi/rtl8192ce/trx.c @@ -36,9 +36,9 @@ #include "trx.h" #include "led.h" -u8 _rtl92ce_map_hwqueue_to_fwqueue(struct sk_buff *skb, u8 hw_queue) +static u8 _rtl92ce_map_hwqueue_to_fwqueue(struct sk_buff *skb, u8 hw_queue) { - u16 fc = rtl_get_fc(skb); + __le16 fc = rtl_get_fc(skb); if (unlikely(ieee80211_is_beacon(fc))) return QSLT_BEACON; @@ -795,7 +795,6 @@ void rtl92ce_tx_fill_desc(struct ieee80211_hw *hw, u8 ampdu_density = sta->ht_cap.ampdu_density; SET_TX_DESC_AMPDU_DENSITY(pdesc, ampdu_density); } - rcu_read_unlock(); if (info->control.hw_key) { struct ieee80211_key_conf *keyconf = @@ -834,13 +833,14 @@ void rtl92ce_tx_fill_desc(struct ieee80211_hw *hw, } } } + rcu_read_unlock(); SET_TX_DESC_FIRST_SEG(pdesc, (firstseg ? 1 : 0)); SET_TX_DESC_LAST_SEG(pdesc, (lastseg ? 1 : 0)); SET_TX_DESC_TX_BUFFER_SIZE(pdesc, (u16) skb->len); - SET_TX_DESC_TX_BUFFER_ADDRESS(pdesc, cpu_to_le32(mapping)); + SET_TX_DESC_TX_BUFFER_ADDRESS(pdesc, mapping); if (rtlpriv->dm.useramask) { SET_TX_DESC_RATE_ID(pdesc, tcb_desc->ratr_index); @@ -901,7 +901,7 @@ void rtl92ce_tx_fill_cmddesc(struct ieee80211_hw *hw, SET_TX_DESC_TX_BUFFER_SIZE(pdesc, (u16) (skb->len)); - SET_TX_DESC_TX_BUFFER_ADDRESS(pdesc, cpu_to_le32(mapping)); + SET_TX_DESC_TX_BUFFER_ADDRESS(pdesc, mapping); SET_TX_DESC_RATE_ID(pdesc, 7); SET_TX_DESC_MACID(pdesc, 0); diff --git a/drivers/net/wireless/rtlwifi/rtl8192cu/phy.c b/drivers/net/wireless/rtlwifi/rtl8192cu/phy.c index 4e020e6..9a3d023 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192cu/phy.c +++ b/drivers/net/wireless/rtlwifi/rtl8192cu/phy.c @@ -38,7 +38,7 @@ #include "table.h" u32 rtl92cu_phy_query_rf_reg(struct ieee80211_hw *hw, - enum radio_path rfpath, u32 regaddr, u32 bitmask) + enum radio_path rfpath, u32 regaddr, u32 bitmask) { struct rtl_priv *rtlpriv = rtl_priv(hw); u32 original_value, readback_value, bitshift; @@ -64,8 +64,8 @@ u32 rtl92cu_phy_query_rf_reg(struct ieee80211_hw *hw, } void rtl92cu_phy_set_rf_reg(struct ieee80211_hw *hw, - enum radio_path rfpath, - u32 regaddr, u32 bitmask, u32 data) + enum radio_path rfpath, + u32 regaddr, u32 bitmask, u32 data) { struct rtl_priv *rtlpriv = rtl_priv(hw); struct rtl_phy *rtlphy = &(rtlpriv->phy); @@ -163,7 +163,7 @@ bool _rtl92cu_phy_config_mac_with_headerfile(struct ieee80211_hw *hw) } bool _rtl92cu_phy_config_bb_with_headerfile(struct ieee80211_hw *hw, - u8 configtype) + u8 configtype) { int i; u32 *phy_regarray_table; @@ -223,7 +223,7 @@ bool _rtl92cu_phy_config_bb_with_headerfile(struct ieee80211_hw *hw, } bool _rtl92cu_phy_config_bb_with_pgheaderfile(struct ieee80211_hw *hw, - u8 configtype) + u8 configtype) { struct rtl_priv *rtlpriv = rtl_priv(hw); struct rtl_phy *rtlphy = &(rtlpriv->phy); @@ -459,7 +459,7 @@ void _rtl92cu_phy_lc_calibrate(struct ieee80211_hw *hw, bool is2t) } } -bool _rtl92cu_phy_set_rf_power_state(struct ieee80211_hw *hw, +static bool _rtl92cu_phy_set_rf_power_state(struct ieee80211_hw *hw, enum rf_pwrstate rfpwr_state) { struct rtl_priv *rtlpriv = rtl_priv(hw); @@ -595,7 +595,7 @@ bool _rtl92cu_phy_set_rf_power_state(struct ieee80211_hw *hw, } bool rtl92cu_phy_set_rf_power_state(struct ieee80211_hw *hw, - enum rf_pwrstate rfpwr_state) + enum rf_pwrstate rfpwr_state) { struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); bool bresult = false; diff --git a/drivers/net/wireless/rtlwifi/rtl8192cu/phy.h b/drivers/net/wireless/rtlwifi/rtl8192cu/phy.h index 0629955..ff81a61 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192cu/phy.h +++ b/drivers/net/wireless/rtlwifi/rtl8192cu/phy.h @@ -34,3 +34,17 @@ bool rtl8192_phy_check_is_legal_rfpath(struct ieee80211_hw *hw, u32 rfpath); void rtl92c_phy_set_io(struct ieee80211_hw *hw); bool _rtl92cu_phy_config_mac_with_headerfile(struct ieee80211_hw *hw); bool rtl92cu_phy_bb_config(struct ieee80211_hw *hw); +u32 rtl92cu_phy_query_rf_reg(struct ieee80211_hw *hw, + enum radio_path rfpath, u32 regaddr, u32 bitmask); +void rtl92cu_phy_set_rf_reg(struct ieee80211_hw *hw, + enum radio_path rfpath, + u32 regaddr, u32 bitmask, u32 data); +bool rtl92cu_phy_mac_config(struct ieee80211_hw *hw); +bool _rtl92cu_phy_config_bb_with_pgheaderfile(struct ieee80211_hw *hw, + u8 configtype); +void _rtl92cu_phy_lc_calibrate(struct ieee80211_hw *hw, bool is2t); +bool _rtl92cu_phy_config_bb_with_headerfile(struct ieee80211_hw *hw, + u8 configtype); +void rtl92cu_phy_set_bw_mode_callback(struct ieee80211_hw *hw); +bool rtl92cu_phy_set_rf_power_state(struct ieee80211_hw *hw, + enum rf_pwrstate rfpwr_state); diff --git a/drivers/net/wireless/rtlwifi/rtl8192cu/rf.c b/drivers/net/wireless/rtlwifi/rtl8192cu/rf.c index 1c79c22..c7576ec 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192cu/rf.c +++ b/drivers/net/wireless/rtlwifi/rtl8192cu/rf.c @@ -62,7 +62,7 @@ void rtl92cu_phy_rf6052_set_bandwidth(struct ieee80211_hw *hw, u8 bandwidth) } void rtl92cu_phy_rf6052_set_cck_txpower(struct ieee80211_hw *hw, - u8 *ppowerlevel) + u8 *ppowerlevel) { struct rtl_priv *rtlpriv = rtl_priv(hw); struct rtl_phy *rtlphy = &(rtlpriv->phy); @@ -389,7 +389,7 @@ static void _rtl92c_write_ofdm_power_reg(struct ieee80211_hw *hw, } void rtl92cu_phy_rf6052_set_ofdm_txpower(struct ieee80211_hw *hw, - u8 *ppowerlevel, u8 channel) + u8 *ppowerlevel, u8 channel) { u32 writeVal[2], powerBase0[2], powerBase1[2]; u8 index = 0; diff --git a/drivers/net/wireless/rtlwifi/rtl8192cu/rf.h b/drivers/net/wireless/rtlwifi/rtl8192cu/rf.h index 86c2728..500a209 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192cu/rf.h +++ b/drivers/net/wireless/rtlwifi/rtl8192cu/rf.h @@ -43,5 +43,9 @@ extern void rtl92c_phy_rf6052_set_ofdm_txpower(struct ieee80211_hw *hw, bool rtl92cu_phy_rf6052_config(struct ieee80211_hw *hw); bool rtl92cu_phy_config_rf_with_headerfile(struct ieee80211_hw *hw, enum radio_path rfpath); +void rtl92cu_phy_rf6052_set_cck_txpower(struct ieee80211_hw *hw, + u8 *ppowerlevel); +void rtl92cu_phy_rf6052_set_ofdm_txpower(struct ieee80211_hw *hw, + u8 *ppowerlevel, u8 channel); #endif diff --git a/drivers/net/wireless/rtlwifi/wifi.h b/drivers/net/wireless/rtlwifi/wifi.h index 690508f..a406c616 100644 --- a/drivers/net/wireless/rtlwifi/wifi.h +++ b/drivers/net/wireless/rtlwifi/wifi.h @@ -303,6 +303,9 @@ enum hw_variables { HW_VAR_DATA_FILTER, }; +#define HWSET_MAX_SIZE 128 +#define EFUSE_MAX_SECTION 16 + enum _RT_MEDIA_STATUS { RT_MEDIA_DISCONNECT = 0, RT_MEDIA_CONNECT = 1 @@ -1963,9 +1966,9 @@ static inline struct ieee80211_hdr *rtl_get_hdr(struct sk_buff *skb) return (struct ieee80211_hdr *)(skb->data); } -static inline u16 rtl_get_fc(struct sk_buff *skb) +static inline __le16 rtl_get_fc(struct sk_buff *skb) { - return le16_to_cpu(rtl_get_hdr(skb)->frame_control); + return rtl_get_hdr(skb)->frame_control; } static inline u16 rtl_get_tid_h(struct ieee80211_hdr *hdr) -- cgit v0.10.2 From c989bb15e95a93e20fc86783264f6298116e8651 Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Mon, 25 Apr 2011 18:35:48 -0700 Subject: cfg80211: fix regresion on reg user timeout The patch "cfg80211: add a timer for invalid user reg hints" introduced a regression for the case where a secondary identical regulatory hint from a user is sent. What would happen is the second hint would schedule delayed work in to catch a timeout but since we are never processing it given that the hint was already applied we'd always hit the timeout and and restore regulatory settings back to world regulatory domain. This is fixed by simply avoiding sheduling work if the hint was already applied. Tested-by: Felix Fietkau Reported-by: Felix Fietkau Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville diff --git a/net/wireless/reg.c b/net/wireless/reg.c index 2714379..8982053 100644 --- a/net/wireless/reg.c +++ b/net/wireless/reg.c @@ -1455,7 +1455,8 @@ static void reg_process_hint(struct regulatory_request *reg_request) * We only time out user hints, given that they should be the only * source of bogus requests. */ - if (reg_request->initiator == NL80211_REGDOM_SET_BY_USER) + if (r != -EALREADY && + reg_request->initiator == NL80211_REGDOM_SET_BY_USER) schedule_delayed_work(®_timeout, msecs_to_jiffies(3142)); } -- cgit v0.10.2 From 304529b1b6f8612ccbb4582e997051b48b94f4a4 Mon Sep 17 00:00:00 2001 From: John Stultz Date: Fri, 1 Apr 2011 14:32:09 -0700 Subject: time: Add timekeeping_inject_sleeptime MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Some platforms cannot implement read_persistent_clock, as their RTC devices are only accessible when interrupts are enabled. This keeps them from being used by the timekeeping code on resume to measure the time in suspend. The RTC layer tries to work around this, by calling do_settimeofday on resume after irqs are reenabled to set the time properly. However, this only corrects CLOCK_REALTIME, and does not properly adjust the sleep time value. This causes btime in /proc/stat to be incorrect as well as making the new CLOCK_BOTTTIME inaccurate. This patch resolves the issue by introducing a new timekeeping hook to allow the RTC layer to inject the sleep time on resume. The code also checks to make sure that read_persistent_clock is nonfunctional before setting the sleep time, so that should the RTC's HCTOSYS option be configured in on a system that does support read_persistent_clock we will not increase the total_sleep_time twice. CC: Arve HjønnevÃ¥g CC: Thomas Gleixner Acked-by: Arnd Bergmann Signed-off-by: John Stultz diff --git a/drivers/rtc/class.c b/drivers/rtc/class.c index 3901386..4194e59 100644 --- a/drivers/rtc/class.c +++ b/drivers/rtc/class.c @@ -41,26 +41,21 @@ static void rtc_device_release(struct device *dev) * system's wall clock; restore it on resume(). */ -static struct timespec delta; static time_t oldtime; +static struct timespec oldts; static int rtc_suspend(struct device *dev, pm_message_t mesg) { struct rtc_device *rtc = to_rtc_device(dev); struct rtc_time tm; - struct timespec ts = current_kernel_time(); if (strcmp(dev_name(&rtc->dev), CONFIG_RTC_HCTOSYS_DEVICE) != 0) return 0; rtc_read_time(rtc, &tm); + ktime_get_ts(&oldts); rtc_tm_to_time(&tm, &oldtime); - /* RTC precision is 1 second; adjust delta for avg 1/2 sec err */ - set_normalized_timespec(&delta, - ts.tv_sec - oldtime, - ts.tv_nsec - (NSEC_PER_SEC >> 1)); - return 0; } @@ -70,10 +65,12 @@ static int rtc_resume(struct device *dev) struct rtc_time tm; time_t newtime; struct timespec time; + struct timespec newts; if (strcmp(dev_name(&rtc->dev), CONFIG_RTC_HCTOSYS_DEVICE) != 0) return 0; + ktime_get_ts(&newts); rtc_read_time(rtc, &tm); if (rtc_valid_tm(&tm) != 0) { pr_debug("%s: bogus resume time\n", dev_name(&rtc->dev)); @@ -85,15 +82,13 @@ static int rtc_resume(struct device *dev) pr_debug("%s: time travel!\n", dev_name(&rtc->dev)); return 0; } + /* calculate the RTC time delta */ + set_normalized_timespec(&time, newtime - oldtime, 0); - /* restore wall clock using delta against this RTC; - * adjust again for avg 1/2 second RTC sampling error - */ - set_normalized_timespec(&time, - newtime + delta.tv_sec, - (NSEC_PER_SEC >> 1) + delta.tv_nsec); - do_settimeofday(&time); + /* subtract kernel time between rtc_suspend to rtc_resume */ + time = timespec_sub(time, timespec_sub(newts, oldts)); + timekeeping_inject_sleeptime(&time); return 0; } diff --git a/include/linux/time.h b/include/linux/time.h index 454a262..4ea5a75 100644 --- a/include/linux/time.h +++ b/include/linux/time.h @@ -126,6 +126,7 @@ struct timespec __current_kernel_time(void); /* does not take xtime_lock */ struct timespec get_monotonic_coarse(void); void get_xtime_and_monotonic_and_sleep_offset(struct timespec *xtim, struct timespec *wtom, struct timespec *sleep); +void timekeeping_inject_sleeptime(struct timespec *delta); #define CURRENT_TIME (current_kernel_time()) #define CURRENT_TIME_SEC ((struct timespec) { get_seconds(), 0 }) diff --git a/kernel/time/timekeeping.c b/kernel/time/timekeeping.c index 8ad5d57..8e6a05a 100644 --- a/kernel/time/timekeeping.c +++ b/kernel/time/timekeeping.c @@ -596,6 +596,58 @@ void __init timekeeping_init(void) static struct timespec timekeeping_suspend_time; /** + * __timekeeping_inject_sleeptime - Internal function to add sleep interval + * @delta: pointer to a timespec delta value + * + * Takes a timespec offset measuring a suspend interval and properly + * adds the sleep offset to the timekeeping variables. + */ +static void __timekeeping_inject_sleeptime(struct timespec *delta) +{ + xtime = timespec_add(xtime, *delta); + wall_to_monotonic = timespec_sub(wall_to_monotonic, *delta); + total_sleep_time = timespec_add(total_sleep_time, *delta); +} + + +/** + * timekeeping_inject_sleeptime - Adds suspend interval to timeekeeping values + * @delta: pointer to a timespec delta value + * + * This hook is for architectures that cannot support read_persistent_clock + * because their RTC/persistent clock is only accessible when irqs are enabled. + * + * This function should only be called by rtc_resume(), and allows + * a suspend offset to be injected into the timekeeping values. + */ +void timekeeping_inject_sleeptime(struct timespec *delta) +{ + unsigned long flags; + struct timespec ts; + + /* Make sure we don't set the clock twice */ + read_persistent_clock(&ts); + if (!(ts.tv_sec == 0 && ts.tv_nsec == 0)) + return; + + write_seqlock_irqsave(&xtime_lock, flags); + timekeeping_forward_now(); + + __timekeeping_inject_sleeptime(delta); + + timekeeper.ntp_error = 0; + ntp_clear(); + update_vsyscall(&xtime, &wall_to_monotonic, timekeeper.clock, + timekeeper.mult); + + write_sequnlock_irqrestore(&xtime_lock, flags); + + /* signal hrtimers about time change */ + clock_was_set(); +} + + +/** * timekeeping_resume - Resumes the generic timekeeping subsystem. * * This is for the generic clocksource timekeeping. @@ -615,9 +667,7 @@ static void timekeeping_resume(void) if (timespec_compare(&ts, &timekeeping_suspend_time) > 0) { ts = timespec_sub(ts, timekeeping_suspend_time); - xtime = timespec_add(xtime, ts); - wall_to_monotonic = timespec_sub(wall_to_monotonic, ts); - total_sleep_time = timespec_add(total_sleep_time, ts); + __timekeeping_inject_sleeptime(&ts); } /* re-base the last cycle value */ timekeeper.clock->cycle_last = timekeeper.clock->read(timekeeper.clock); -- cgit v0.10.2 From 88d19cf37952a7e1e38b2bf87a00f0e857e63180 Mon Sep 17 00:00:00 2001 From: John Stultz Date: Mon, 3 Jan 2011 18:59:43 -0800 Subject: timers: Add rb_init_node() to allow for stack allocated rb nodes In cases where a timerqueue_node or some structure that utilizes a timerqueue_node is allocated on the stack, gcc would give warnings caused by the timerqueue_init()'s calling RB_CLEAR_NODE, which self-references the nodes uninitialized data. The solution is to create an rb_init_node() function that zeros the rb_node structure out and then calls RB_CLEAR_NODE(), and then call the new init function from timerqueue_init(). CC: Thomas Gleixner Acked-by: Arnd Bergmann Signed-off-by: John Stultz diff --git a/include/linux/rbtree.h b/include/linux/rbtree.h index 7066acb..033b507 100644 --- a/include/linux/rbtree.h +++ b/include/linux/rbtree.h @@ -136,6 +136,14 @@ static inline void rb_set_color(struct rb_node *rb, int color) #define RB_EMPTY_NODE(node) (rb_parent(node) == node) #define RB_CLEAR_NODE(node) (rb_set_parent(node, node)) +static inline void rb_init_node(struct rb_node *rb) +{ + rb->rb_parent_color = 0; + rb->rb_right = NULL; + rb->rb_left = NULL; + RB_CLEAR_NODE(rb); +} + extern void rb_insert_color(struct rb_node *, struct rb_root *); extern void rb_erase(struct rb_node *, struct rb_root *); diff --git a/include/linux/timerqueue.h b/include/linux/timerqueue.h index a520fd7..5088727 100644 --- a/include/linux/timerqueue.h +++ b/include/linux/timerqueue.h @@ -39,7 +39,7 @@ struct timerqueue_node *timerqueue_getnext(struct timerqueue_head *head) static inline void timerqueue_init(struct timerqueue_node *node) { - RB_CLEAR_NODE(&node->node); + rb_init_node(&node->node); } static inline void timerqueue_init_head(struct timerqueue_head *head) -- cgit v0.10.2 From ff3ead96d17f47ee70c294a5cc2cce9b61e82f0f Mon Sep 17 00:00:00 2001 From: John Stultz Date: Tue, 11 Jan 2011 09:42:13 -0800 Subject: timers: Introduce in-kernel alarm-timer interface MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This provides the in kernel interface and infrastructure for alarm-timers. Alarm-timers are a hybrid style timer, similar to hrtimers, but when the system is suspended, the RTC device is set to fire and wake the system for when the soonest alarm-timer expires. The concept for Alarm-timers was inspired by the Android Alarm driver (by Arve HjønnevÃ¥g) found in the Android kernel tree. See: http://android.git.kernel.org/?p=kernel/common.git;a=blob;f=drivers/rtc/alarm.c;h=1250edfbdf3302f5e4ea6194847c6ef4bb7beb1c;hb=android-2.6.36 This in-kernel interface should be fairly compatible with the Android alarm driver in-kernel interface, but has the advantage of utilizing the new RTC timerqueue code instead of doing direct RTC manipulation. CC: Arve HjønnevÃ¥g CC: Thomas Gleixner CC: Alessandro Zummo Acked-by: Arnd Bergmann Signed-off-by: John Stultz diff --git a/include/linux/alarmtimer.h b/include/linux/alarmtimer.h new file mode 100644 index 0000000..6b364b2 --- /dev/null +++ b/include/linux/alarmtimer.h @@ -0,0 +1,30 @@ +#ifndef _LINUX_ALARMTIMER_H +#define _LINUX_ALARMTIMER_H + +#include +#include +#include +#include + +enum alarmtimer_type { + ALARM_REALTIME, + ALARM_BOOTTIME, + + ALARM_NUMTYPE, +}; + +struct alarm { + struct timerqueue_node node; + ktime_t period; + void (*function)(struct alarm *); + enum alarmtimer_type type; + char enabled; + void *data; +}; + +void alarm_init(struct alarm *alarm, enum alarmtimer_type type, + void (*function)(struct alarm *)); +void alarm_start(struct alarm *alarm, ktime_t start, ktime_t period); +void alarm_cancel(struct alarm *alarm); + +#endif diff --git a/kernel/time/Makefile b/kernel/time/Makefile index b042599..e2fd74b 100644 --- a/kernel/time/Makefile +++ b/kernel/time/Makefile @@ -1,5 +1,5 @@ obj-y += timekeeping.o ntp.o clocksource.o jiffies.o timer_list.o timecompare.o -obj-y += timeconv.o posix-clock.o +obj-y += timeconv.o posix-clock.o alarmtimer.o obj-$(CONFIG_GENERIC_CLOCKEVENTS_BUILD) += clockevents.o obj-$(CONFIG_GENERIC_CLOCKEVENTS) += tick-common.o diff --git a/kernel/time/alarmtimer.c b/kernel/time/alarmtimer.c new file mode 100644 index 0000000..48c2ee9 --- /dev/null +++ b/kernel/time/alarmtimer.c @@ -0,0 +1,375 @@ +/* + * Alarmtimer interface + * + * This interface provides a timer which is similarto hrtimers, + * but triggers a RTC alarm if the box is suspend. + * + * This interface is influenced by the Android RTC Alarm timer + * interface. + * + * Copyright (C) 2010 IBM Corperation + * + * Author: John Stultz + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +static struct alarm_base { + spinlock_t lock; + struct timerqueue_head timerqueue; + struct hrtimer timer; + ktime_t (*gettime)(void); + clockid_t base_clockid; + struct work_struct irqwork; +} alarm_bases[ALARM_NUMTYPE]; + +static struct rtc_timer rtctimer; +static struct rtc_device *rtcdev; + +static ktime_t freezer_delta; +static DEFINE_SPINLOCK(freezer_delta_lock); + + +/************************************************************************** + * alarmtimer management code + */ + +/* + * alarmtimer_enqueue - Adds an alarm timer to an alarm_base timerqueue + * @base: pointer to the base where the timer is being run + * @alarm: pointer to alarm being enqueued. + * + * Adds alarm to a alarm_base timerqueue and if necessary sets + * an hrtimer to run. + * + * Must hold base->lock when calling. + */ +static void alarmtimer_enqueue(struct alarm_base *base, struct alarm *alarm) +{ + timerqueue_add(&base->timerqueue, &alarm->node); + if (&alarm->node == timerqueue_getnext(&base->timerqueue)) { + hrtimer_try_to_cancel(&base->timer); + hrtimer_start(&base->timer, alarm->node.expires, + HRTIMER_MODE_ABS); + } +} + +/* + * alarmtimer_remove - Removes an alarm timer from an alarm_base timerqueue + * @base: pointer to the base where the timer is running + * @alarm: pointer to alarm being removed + * + * Removes alarm to a alarm_base timerqueue and if necessary sets + * a new timer to run. + * + * Must hold base->lock when calling. + */ +static void alarmtimer_remove(struct alarm_base *base, struct alarm *alarm) +{ + struct timerqueue_node *next = timerqueue_getnext(&base->timerqueue); + + timerqueue_del(&base->timerqueue, &alarm->node); + if (next == &alarm->node) { + hrtimer_try_to_cancel(&base->timer); + next = timerqueue_getnext(&base->timerqueue); + if (!next) + return; + hrtimer_start(&base->timer, next->expires, HRTIMER_MODE_ABS); + } +} + +/* + * alarmtimer_do_work - Handles alarm being fired. + * @work: pointer to workqueue being run + * + * When a timer fires, this runs through the timerqueue to see + * which alarm timers, and run those that expired. If there are + * more alarm timers queued, we set the hrtimer to fire in the + * future. + */ +void alarmtimer_do_work(struct work_struct *work) +{ + struct alarm_base *base = container_of(work, struct alarm_base, + irqwork); + struct timerqueue_node *next; + unsigned long flags; + ktime_t now; + + spin_lock_irqsave(&base->lock, flags); + now = base->gettime(); + while ((next = timerqueue_getnext(&base->timerqueue))) { + struct alarm *alarm; + ktime_t expired = next->expires; + + if (expired.tv64 >= now.tv64) + break; + + alarm = container_of(next, struct alarm, node); + + timerqueue_del(&base->timerqueue, &alarm->node); + alarm->enabled = 0; + /* Re-add periodic timers */ + if (alarm->period.tv64) { + alarm->node.expires = ktime_add(expired, alarm->period); + timerqueue_add(&base->timerqueue, &alarm->node); + alarm->enabled = 1; + } + spin_unlock_irqrestore(&base->lock, flags); + if (alarm->function) + alarm->function(alarm); + spin_lock_irqsave(&base->lock, flags); + } + + if (next) { + hrtimer_start(&base->timer, next->expires, + HRTIMER_MODE_ABS); + } + spin_unlock_irqrestore(&base->lock, flags); +} + + +/* + * alarmtimer_fired - Handles alarm hrtimer being fired. + * @timer: pointer to hrtimer being run + * + * When a timer fires, this schedules the do_work function to + * be run. + */ +static enum hrtimer_restart alarmtimer_fired(struct hrtimer *timer) +{ + struct alarm_base *base = container_of(timer, struct alarm_base, timer); + schedule_work(&base->irqwork); + return HRTIMER_NORESTART; +} + + +/* + * alarmtimer_suspend - Suspend time callback + * @dev: unused + * @state: unused + * + * When we are going into suspend, we look through the bases + * to see which is the soonest timer to expire. We then + * set an rtc timer to fire that far into the future, which + * will wake us from suspend. + */ +static int alarmtimer_suspend(struct device *dev) +{ + struct rtc_time tm; + ktime_t min, now; + unsigned long flags; + int i; + + spin_lock_irqsave(&freezer_delta_lock, flags); + min = freezer_delta; + freezer_delta = ktime_set(0, 0); + spin_unlock_irqrestore(&freezer_delta_lock, flags); + + /* If we have no rtcdev, just return */ + if (!rtcdev) + return 0; + + /* Find the soonest timer to expire*/ + for (i = 0; i < ALARM_NUMTYPE; i++) { + struct alarm_base *base = &alarm_bases[i]; + struct timerqueue_node *next; + ktime_t delta; + + spin_lock_irqsave(&base->lock, flags); + next = timerqueue_getnext(&base->timerqueue); + spin_unlock_irqrestore(&base->lock, flags); + if (!next) + continue; + delta = ktime_sub(next->expires, base->gettime()); + if (!min.tv64 || (delta.tv64 < min.tv64)) + min = delta; + } + if (min.tv64 == 0) + return 0; + + /* XXX - Should we enforce a minimum sleep time? */ + WARN_ON(min.tv64 < NSEC_PER_SEC); + + /* Setup an rtc timer to fire that far in the future */ + rtc_timer_cancel(rtcdev, &rtctimer); + rtc_read_time(rtcdev, &tm); + now = rtc_tm_to_ktime(tm); + now = ktime_add(now, min); + + rtc_timer_start(rtcdev, &rtctimer, now, ktime_set(0, 0)); + + return 0; +} + + +/************************************************************************** + * alarm kernel interface code + */ + +/* + * alarm_init - Initialize an alarm structure + * @alarm: ptr to alarm to be initialized + * @type: the type of the alarm + * @function: callback that is run when the alarm fires + * + * In-kernel interface to initializes the alarm structure. + */ +void alarm_init(struct alarm *alarm, enum alarmtimer_type type, + void (*function)(struct alarm *)) +{ + timerqueue_init(&alarm->node); + alarm->period = ktime_set(0, 0); + alarm->function = function; + alarm->type = type; + alarm->enabled = 0; +} + +/* + * alarm_start - Sets an alarm to fire + * @alarm: ptr to alarm to set + * @start: time to run the alarm + * @period: period at which the alarm will recur + * + * In-kernel interface set an alarm timer. + */ +void alarm_start(struct alarm *alarm, ktime_t start, ktime_t period) +{ + struct alarm_base *base = &alarm_bases[alarm->type]; + unsigned long flags; + + spin_lock_irqsave(&base->lock, flags); + if (alarm->enabled) + alarmtimer_remove(base, alarm); + alarm->node.expires = start; + alarm->period = period; + alarmtimer_enqueue(base, alarm); + alarm->enabled = 1; + spin_unlock_irqrestore(&base->lock, flags); +} + +/* + * alarm_cancel - Tries to cancel an alarm timer + * @alarm: ptr to alarm to be canceled + * + * In-kernel interface to cancel an alarm timer. + */ +void alarm_cancel(struct alarm *alarm) +{ + struct alarm_base *base = &alarm_bases[alarm->type]; + unsigned long flags; + + spin_lock_irqsave(&base->lock, flags); + if (alarm->enabled) + alarmtimer_remove(base, alarm); + alarm->enabled = 0; + spin_unlock_irqrestore(&base->lock, flags); +} + + + +/************************************************************************** + * alarmtimer initialization code + */ + +/* Suspend hook structures */ +static const struct dev_pm_ops alarmtimer_pm_ops = { + .suspend = alarmtimer_suspend, +}; + +static struct platform_driver alarmtimer_driver = { + .driver = { + .name = "alarmtimer", + .pm = &alarmtimer_pm_ops, + } +}; + +/** + * alarmtimer_init - Initialize alarm timer code + * + * This function initializes the alarm bases and registers + * the posix clock ids. + */ +static int __init alarmtimer_init(void) +{ + int error = 0; + int i; + + /* Initialize alarm bases */ + alarm_bases[ALARM_REALTIME].base_clockid = CLOCK_REALTIME; + alarm_bases[ALARM_REALTIME].gettime = &ktime_get_real; + alarm_bases[ALARM_BOOTTIME].base_clockid = CLOCK_BOOTTIME; + alarm_bases[ALARM_BOOTTIME].gettime = &ktime_get_boottime; + for (i = 0; i < ALARM_NUMTYPE; i++) { + timerqueue_init_head(&alarm_bases[i].timerqueue); + spin_lock_init(&alarm_bases[i].lock); + hrtimer_init(&alarm_bases[i].timer, + alarm_bases[i].base_clockid, + HRTIMER_MODE_ABS); + alarm_bases[i].timer.function = alarmtimer_fired; + INIT_WORK(&alarm_bases[i].irqwork, alarmtimer_do_work); + } + error = platform_driver_register(&alarmtimer_driver); + platform_device_register_simple("alarmtimer", -1, NULL, 0); + + return error; +} +device_initcall(alarmtimer_init); + +/** + * has_wakealarm - check rtc device has wakealarm ability + * @dev: current device + * @name_ptr: name to be returned + * + * This helper function checks to see if the rtc device can wake + * from suspend. + */ +static int __init has_wakealarm(struct device *dev, void *name_ptr) +{ + struct rtc_device *candidate = to_rtc_device(dev); + + if (!candidate->ops->set_alarm) + return 0; + if (!device_may_wakeup(candidate->dev.parent)) + return 0; + + *(const char **)name_ptr = dev_name(dev); + return 1; +} + +/** + * alarmtimer_init_late - Late initializing of alarmtimer code + * + * This function locates a rtc device to use for wakealarms. + * Run as late_initcall to make sure rtc devices have been + * registered. + */ +static int __init alarmtimer_init_late(void) +{ + char *str; + + /* Find an rtc device and init the rtc_timer */ + class_find_device(rtc_class, NULL, &str, has_wakealarm); + if (str) + rtcdev = rtc_class_open(str); + if (!rtcdev) { + printk(KERN_WARNING "No RTC device found, ALARM timers will" + " not wake from suspend"); + } + rtc_timer_init(&rtctimer, NULL, NULL); + + return 0; +} +late_initcall(alarmtimer_init_late); -- cgit v0.10.2 From 9a7adcf5c6dea63d2e47e6f6d2f7a6c9f48b9337 Mon Sep 17 00:00:00 2001 From: John Stultz Date: Tue, 11 Jan 2011 09:54:33 -0800 Subject: timers: Posix interface for alarm-timers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This patch exposes alarm-timers to userland via the posix clock and timers interface, using two new clockids: CLOCK_REALTIME_ALARM and CLOCK_BOOTTIME_ALARM. Both clockids behave identically to CLOCK_REALTIME and CLOCK_BOOTTIME, respectively, but timers set against the _ALARM suffixed clockids will wake the system if it is suspended. Some background can be found here: https://lwn.net/Articles/429925/ The concept for Alarm-timers was inspired by the Android Alarm driver (by Arve HjønnevÃ¥g) found in the Android kernel tree. See: http://android.git.kernel.org/?p=kernel/common.git;a=blob;f=drivers/rtc/alarm.c;h=1250edfbdf3302f5e4ea6194847c6ef4bb7beb1c;hb=android-2.6.36 While the in-kernel interface is pretty similar between alarm-timers and Android alarm driver, the user-space interface for the Android alarm driver is via ioctls to a new char device. As mentioned above, I've instead chosen to export this functionality via the posix interface, as it seemed a little simpler and avoids creating duplicate interfaces to things like CLOCK_REALTIME and CLOCK_MONOTONIC under alternate names (ie:ANDROID_ALARM_RTC and ANDROID_ALARM_SYSTEMTIME). The semantics of the Android alarm driver are different from what this posix interface provides. For instance, threads other then the thread waiting on the Android alarm driver are able to modify the alarm being waited on. Also this interface does not allow the same wakelock semantics that the Android driver provides (ie: kernel takes a wakelock on RTC alarm-interupt, and holds it through process wakeup, and while the process runs, until the process either closes the char device or calls back in to wait on a new alarm). One potential way to implement similar semantics may be via the timerfd infrastructure, but this needs more research. There may also need to be some sort of sysfs system level policy hooks that allow alarm timers to be disabled to keep them from firing at inappropriate times (ie: laptop in a well insulated bag, mid-flight). CC: Arve HjønnevÃ¥g CC: Thomas Gleixner CC: Alessandro Zummo Acked-by: Arnd Bergmann Signed-off-by: John Stultz diff --git a/include/linux/capability.h b/include/linux/capability.h index 16ee8b4..7cb23ea 100644 --- a/include/linux/capability.h +++ b/include/linux/capability.h @@ -355,7 +355,12 @@ struct cpu_vfs_cap_data { #define CAP_SYSLOG 34 -#define CAP_LAST_CAP CAP_SYSLOG +/* Allow triggering something that will wake the system */ + +#define CAP_WAKE_ALARM 35 + + +#define CAP_LAST_CAP CAP_WAKE_ALARM #define cap_valid(x) ((x) >= 0 && (x) <= CAP_LAST_CAP) diff --git a/include/linux/posix-timers.h b/include/linux/posix-timers.h index d51243a..808227d 100644 --- a/include/linux/posix-timers.h +++ b/include/linux/posix-timers.h @@ -5,6 +5,7 @@ #include #include #include +#include union cpu_time_count { cputime_t cpu; @@ -80,6 +81,7 @@ struct k_itimer { unsigned long incr; unsigned long expires; } mmtimer; + struct alarm alarmtimer; } it; }; diff --git a/include/linux/time.h b/include/linux/time.h index 4ea5a75..b306178 100644 --- a/include/linux/time.h +++ b/include/linux/time.h @@ -295,6 +295,8 @@ struct itimerval { #define CLOCK_REALTIME_COARSE 5 #define CLOCK_MONOTONIC_COARSE 6 #define CLOCK_BOOTTIME 7 +#define CLOCK_REALTIME_ALARM 8 +#define CLOCK_BOOTTIME_ALARM 9 /* * The IDs of various hardware clocks: diff --git a/kernel/time/alarmtimer.c b/kernel/time/alarmtimer.c index 48c2ee9..4058ad7 100644 --- a/kernel/time/alarmtimer.c +++ b/kernel/time/alarmtimer.c @@ -215,6 +215,21 @@ static int alarmtimer_suspend(struct device *dev) } +static void alarmtimer_freezerset(ktime_t absexp, enum alarmtimer_type type) +{ + ktime_t delta; + unsigned long flags; + struct alarm_base *base = &alarm_bases[type]; + + delta = ktime_sub(absexp, base->gettime()); + + spin_lock_irqsave(&freezer_delta_lock, flags); + if (!freezer_delta.tv64 || (delta.tv64 < freezer_delta.tv64)) + freezer_delta = delta; + spin_unlock_irqrestore(&freezer_delta_lock, flags); +} + + /************************************************************************** * alarm kernel interface code */ @@ -279,6 +294,309 @@ void alarm_cancel(struct alarm *alarm) } +/************************************************************************** + * alarm posix interface code + */ + +/* + * clock2alarm - helper that converts from clockid to alarmtypes + * @clockid: clockid. + * + * Helper function that converts from clockids to alarmtypes + */ +static enum alarmtimer_type clock2alarm(clockid_t clockid) +{ + if (clockid == CLOCK_REALTIME_ALARM) + return ALARM_REALTIME; + if (clockid == CLOCK_BOOTTIME_ALARM) + return ALARM_BOOTTIME; + return -1; +} + +/* + * alarm_handle_timer - Callback for posix timers + * @alarm: alarm that fired + * + * Posix timer callback for expired alarm timers. + */ +static void alarm_handle_timer(struct alarm *alarm) +{ + struct k_itimer *ptr = container_of(alarm, struct k_itimer, + it.alarmtimer); + if (posix_timer_event(ptr, 0) != 0) + ptr->it_overrun++; +} + +/* + * alarm_clock_getres - posix getres interface + * @which_clock: clockid + * @tp: timespec to fill + * + * Returns the granularity of underlying alarm base clock + */ +static int alarm_clock_getres(const clockid_t which_clock, struct timespec *tp) +{ + clockid_t baseid = alarm_bases[clock2alarm(which_clock)].base_clockid; + + return hrtimer_get_res(baseid, tp); +} + +/** + * alarm_clock_get - posix clock_get interface + * @which_clock: clockid + * @tp: timespec to fill. + * + * Provides the underlying alarm base time. + */ +static int alarm_clock_get(clockid_t which_clock, struct timespec *tp) +{ + struct alarm_base *base = &alarm_bases[clock2alarm(which_clock)]; + + *tp = ktime_to_timespec(base->gettime()); + return 0; +} + +/** + * alarm_timer_create - posix timer_create interface + * @new_timer: k_itimer pointer to manage + * + * Initializes the k_itimer structure. + */ +static int alarm_timer_create(struct k_itimer *new_timer) +{ + enum alarmtimer_type type; + struct alarm_base *base; + + if (!capable(CAP_WAKE_ALARM)) + return -EPERM; + + type = clock2alarm(new_timer->it_clock); + base = &alarm_bases[type]; + alarm_init(&new_timer->it.alarmtimer, type, alarm_handle_timer); + return 0; +} + +/** + * alarm_timer_get - posix timer_get interface + * @new_timer: k_itimer pointer + * @cur_setting: itimerspec data to fill + * + * Copies the itimerspec data out from the k_itimer + */ +static void alarm_timer_get(struct k_itimer *timr, + struct itimerspec *cur_setting) +{ + cur_setting->it_interval = + ktime_to_timespec(timr->it.alarmtimer.period); + cur_setting->it_value = + ktime_to_timespec(timr->it.alarmtimer.node.expires); + return; +} + +/** + * alarm_timer_del - posix timer_del interface + * @timr: k_itimer pointer to be deleted + * + * Cancels any programmed alarms for the given timer. + */ +static int alarm_timer_del(struct k_itimer *timr) +{ + alarm_cancel(&timr->it.alarmtimer); + return 0; +} + +/** + * alarm_timer_set - posix timer_set interface + * @timr: k_itimer pointer to be deleted + * @flags: timer flags + * @new_setting: itimerspec to be used + * @old_setting: itimerspec being replaced + * + * Sets the timer to new_setting, and starts the timer. + */ +static int alarm_timer_set(struct k_itimer *timr, int flags, + struct itimerspec *new_setting, + struct itimerspec *old_setting) +{ + /* Save old values */ + old_setting->it_interval = + ktime_to_timespec(timr->it.alarmtimer.period); + old_setting->it_value = + ktime_to_timespec(timr->it.alarmtimer.node.expires); + + /* If the timer was already set, cancel it */ + alarm_cancel(&timr->it.alarmtimer); + + /* start the timer */ + alarm_start(&timr->it.alarmtimer, + timespec_to_ktime(new_setting->it_value), + timespec_to_ktime(new_setting->it_interval)); + return 0; +} + +/** + * alarmtimer_nsleep_wakeup - Wakeup function for alarm_timer_nsleep + * @alarm: ptr to alarm that fired + * + * Wakes up the task that set the alarmtimer + */ +static void alarmtimer_nsleep_wakeup(struct alarm *alarm) +{ + struct task_struct *task = (struct task_struct *)alarm->data; + + alarm->data = NULL; + if (task) + wake_up_process(task); +} + +/** + * alarmtimer_do_nsleep - Internal alarmtimer nsleep implementation + * @alarm: ptr to alarmtimer + * @absexp: absolute expiration time + * + * Sets the alarm timer and sleeps until it is fired or interrupted. + */ +static int alarmtimer_do_nsleep(struct alarm *alarm, ktime_t absexp) +{ + alarm->data = (void *)current; + do { + set_current_state(TASK_INTERRUPTIBLE); + alarm_start(alarm, absexp, ktime_set(0, 0)); + if (likely(alarm->data)) + schedule(); + + alarm_cancel(alarm); + } while (alarm->data && !signal_pending(current)); + + __set_current_state(TASK_RUNNING); + + return (alarm->data == NULL); +} + + +/** + * update_rmtp - Update remaining timespec value + * @exp: expiration time + * @type: timer type + * @rmtp: user pointer to remaining timepsec value + * + * Helper function that fills in rmtp value with time between + * now and the exp value + */ +static int update_rmtp(ktime_t exp, enum alarmtimer_type type, + struct timespec __user *rmtp) +{ + struct timespec rmt; + ktime_t rem; + + rem = ktime_sub(exp, alarm_bases[type].gettime()); + + if (rem.tv64 <= 0) + return 0; + rmt = ktime_to_timespec(rem); + + if (copy_to_user(rmtp, &rmt, sizeof(*rmtp))) + return -EFAULT; + + return 1; + +} + +/** + * alarm_timer_nsleep_restart - restartblock alarmtimer nsleep + * @restart: ptr to restart block + * + * Handles restarted clock_nanosleep calls + */ +static long __sched alarm_timer_nsleep_restart(struct restart_block *restart) +{ + enum alarmtimer_type type = restart->nanosleep.index; + ktime_t exp; + struct timespec __user *rmtp; + struct alarm alarm; + int ret = 0; + + exp.tv64 = restart->nanosleep.expires; + alarm_init(&alarm, type, alarmtimer_nsleep_wakeup); + + if (alarmtimer_do_nsleep(&alarm, exp)) + goto out; + + if (freezing(current)) + alarmtimer_freezerset(exp, type); + + rmtp = restart->nanosleep.rmtp; + if (rmtp) { + ret = update_rmtp(exp, type, rmtp); + if (ret <= 0) + goto out; + } + + + /* The other values in restart are already filled in */ + ret = -ERESTART_RESTARTBLOCK; +out: + return ret; +} + +/** + * alarm_timer_nsleep - alarmtimer nanosleep + * @which_clock: clockid + * @flags: determins abstime or relative + * @tsreq: requested sleep time (abs or rel) + * @rmtp: remaining sleep time saved + * + * Handles clock_nanosleep calls against _ALARM clockids + */ +static int alarm_timer_nsleep(const clockid_t which_clock, int flags, + struct timespec *tsreq, struct timespec __user *rmtp) +{ + enum alarmtimer_type type = clock2alarm(which_clock); + struct alarm alarm; + ktime_t exp; + int ret = 0; + struct restart_block *restart; + + if (!capable(CAP_WAKE_ALARM)) + return -EPERM; + + alarm_init(&alarm, type, alarmtimer_nsleep_wakeup); + + exp = timespec_to_ktime(*tsreq); + /* Convert (if necessary) to absolute time */ + if (flags != TIMER_ABSTIME) { + ktime_t now = alarm_bases[type].gettime(); + exp = ktime_add(now, exp); + } + + if (alarmtimer_do_nsleep(&alarm, exp)) + goto out; + + if (freezing(current)) + alarmtimer_freezerset(exp, type); + + /* abs timers don't set remaining time or restart */ + if (flags == TIMER_ABSTIME) { + ret = -ERESTARTNOHAND; + goto out; + } + + if (rmtp) { + ret = update_rmtp(exp, type, rmtp); + if (ret <= 0) + goto out; + } + + restart = ¤t_thread_info()->restart_block; + restart->fn = alarm_timer_nsleep_restart; + restart->nanosleep.index = type; + restart->nanosleep.expires = exp.tv64; + restart->nanosleep.rmtp = rmtp; + ret = -ERESTART_RESTARTBLOCK; + +out: + return ret; +} /************************************************************************** * alarmtimer initialization code @@ -306,6 +624,18 @@ static int __init alarmtimer_init(void) { int error = 0; int i; + struct k_clock alarm_clock = { + .clock_getres = alarm_clock_getres, + .clock_get = alarm_clock_get, + .timer_create = alarm_timer_create, + .timer_set = alarm_timer_set, + .timer_del = alarm_timer_del, + .timer_get = alarm_timer_get, + .nsleep = alarm_timer_nsleep, + }; + + posix_timers_register_clock(CLOCK_REALTIME_ALARM, &alarm_clock); + posix_timers_register_clock(CLOCK_BOOTTIME_ALARM, &alarm_clock); /* Initialize alarm bases */ alarm_bases[ALARM_REALTIME].base_clockid = CLOCK_REALTIME; -- cgit v0.10.2 From 76b4eda866c4936af8d696f040abea56bf688e16 Mon Sep 17 00:00:00 2001 From: Benjamin Herrenschmidt Date: Thu, 14 Apr 2011 22:32:01 +0000 Subject: powerpc: Add A2 cpu support Add the cputable entry, regs and setup & restore entries for the PowerPC A2 core. Signed-off-by: Benjamin Herrenschmidt Signed-off-by: Michael Ellerman Signed-off-by: Benjamin Herrenschmidt diff --git a/arch/powerpc/include/asm/cputable.h b/arch/powerpc/include/asm/cputable.h index 2fe37d7..2d71523 100644 --- a/arch/powerpc/include/asm/cputable.h +++ b/arch/powerpc/include/asm/cputable.h @@ -437,9 +437,13 @@ extern const char *powerpc_base_platform; CPU_FTR_PURR | CPU_FTR_REAL_LE | CPU_FTR_NO_SLBIE_B) #define CPU_FTRS_COMPATIBLE (CPU_FTR_USE_TB | CPU_FTR_PPCAS_ARCH_V2) +#define CPU_FTRS_A2 (CPU_FTR_USE_TB | CPU_FTR_SMT | CPU_FTR_DBELL | \ + CPU_FTR_TLBIEL | CPU_FTR_NOEXECUTE | CPU_FTR_NODSISRALIGN | \ + CPU_FTR_16M_PAGE) + #ifdef __powerpc64__ #ifdef CONFIG_PPC_BOOK3E -#define CPU_FTRS_POSSIBLE (CPU_FTRS_E5500) +#define CPU_FTRS_POSSIBLE (CPU_FTRS_E5500 | CPU_FTRS_A2) #else #define CPU_FTRS_POSSIBLE \ (CPU_FTRS_POWER3 | CPU_FTRS_RS64 | CPU_FTRS_POWER4 | \ @@ -488,7 +492,7 @@ enum { #ifdef __powerpc64__ #ifdef CONFIG_PPC_BOOK3E -#define CPU_FTRS_ALWAYS (CPU_FTRS_E5500) +#define CPU_FTRS_ALWAYS (CPU_FTRS_E5500 & CPU_FTRS_A2) #else #define CPU_FTRS_ALWAYS \ (CPU_FTRS_POWER3 & CPU_FTRS_RS64 & CPU_FTRS_POWER4 & \ diff --git a/arch/powerpc/include/asm/reg_a2.h b/arch/powerpc/include/asm/reg_a2.h new file mode 100644 index 0000000..3ba9c6f --- /dev/null +++ b/arch/powerpc/include/asm/reg_a2.h @@ -0,0 +1,156 @@ +/* + * Register definitions specific to the A2 core + * + * Copyright (C) 2008 Ben. Herrenschmidt (benh@kernel.crashing.org), IBM Corp. + * + * 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 __ASM_POWERPC_REG_A2_H__ +#define __ASM_POWERPC_REG_A2_H__ + +#define SPRN_TENSR 0x1b5 +#define SPRN_TENS 0x1b6 /* Thread ENable Set */ +#define SPRN_TENC 0x1b7 /* Thread ENable Clear */ + +#define SPRN_A2_CCR0 0x3f0 /* Core Configuration Register 0 */ +#define SPRN_A2_CCR1 0x3f1 /* Core Configuration Register 1 */ +#define SPRN_A2_CCR2 0x3f2 /* Core Configuration Register 2 */ +#define SPRN_MMUCR0 0x3fc /* MMU Control Register 0 */ +#define SPRN_MMUCR1 0x3fd /* MMU Control Register 1 */ +#define SPRN_MMUCR2 0x3fe /* MMU Control Register 2 */ +#define SPRN_MMUCR3 0x3ff /* MMU Control Register 3 */ + +#define SPRN_IAR 0x372 + +#define SPRN_IUCR0 0x3f3 +#define IUCR0_ICBI_ACK 0x1000 + +#define SPRN_XUCR0 0x3f6 /* Execution Unit Config Register 0 */ + +#define A2_IERAT_SIZE 16 +#define A2_DERAT_SIZE 32 + +/* A2 MMUCR0 bits */ +#define MMUCR0_ECL 0x80000000 /* Extended Class for TLB fills */ +#define MMUCR0_TID_NZ 0x40000000 /* TID is non-zero */ +#define MMUCR0_TS 0x10000000 /* Translation space for TLB fills */ +#define MMUCR0_TGS 0x20000000 /* Guest space for TLB fills */ +#define MMUCR0_TLBSEL 0x0c000000 /* TLB or ERAT target for TLB fills */ +#define MMUCR0_TLBSEL_U 0x00000000 /* TLBSEL = UTLB */ +#define MMUCR0_TLBSEL_I 0x08000000 /* TLBSEL = I-ERAT */ +#define MMUCR0_TLBSEL_D 0x0c000000 /* TLBSEL = D-ERAT */ +#define MMUCR0_LOCKSRSH 0x02000000 /* Use TLB lock on tlbsx. */ +#define MMUCR0_TID_MASK 0x000000ff /* TID field */ + +/* A2 MMUCR1 bits */ +#define MMUCR1_IRRE 0x80000000 /* I-ERAT round robin enable */ +#define MMUCR1_DRRE 0x40000000 /* D-ERAT round robin enable */ +#define MMUCR1_REE 0x20000000 /* Reference Exception Enable*/ +#define MMUCR1_CEE 0x10000000 /* Change exception enable */ +#define MMUCR1_CSINV_ALL 0x00000000 /* Inval ERAT on all CS evts */ +#define MMUCR1_CSINV_NISYNC 0x04000000 /* Inval ERAT on all ex isync*/ +#define MMUCR1_CSINV_NEVER 0x0c000000 /* Don't inval ERAT on CS */ +#define MMUCR1_ICTID 0x00080000 /* IERAT class field as TID */ +#define MMUCR1_ITTID 0x00040000 /* IERAT thdid field as TID */ +#define MMUCR1_DCTID 0x00020000 /* DERAT class field as TID */ +#define MMUCR1_DTTID 0x00010000 /* DERAT thdid field as TID */ +#define MMUCR1_DCCD 0x00008000 /* DERAT class ignore */ +#define MMUCR1_TLBWE_BINV 0x00004000 /* back invalidate on tlbwe */ + +/* A2 MMUCR2 bits */ +#define MMUCR2_PSSEL_SHIFT 4 + +/* A2 MMUCR3 bits */ +#define MMUCR3_THID 0x0000000f /* Thread ID */ + +/* *** ERAT TLB bits definitions */ +#define TLB0_EPN_MASK ASM_CONST(0xfffffffffffff000) +#define TLB0_CLASS_MASK ASM_CONST(0x0000000000000c00) +#define TLB0_CLASS_00 ASM_CONST(0x0000000000000000) +#define TLB0_CLASS_01 ASM_CONST(0x0000000000000400) +#define TLB0_CLASS_10 ASM_CONST(0x0000000000000800) +#define TLB0_CLASS_11 ASM_CONST(0x0000000000000c00) +#define TLB0_V ASM_CONST(0x0000000000000200) +#define TLB0_X ASM_CONST(0x0000000000000100) +#define TLB0_SIZE_MASK ASM_CONST(0x00000000000000f0) +#define TLB0_SIZE_4K ASM_CONST(0x0000000000000010) +#define TLB0_SIZE_64K ASM_CONST(0x0000000000000030) +#define TLB0_SIZE_1M ASM_CONST(0x0000000000000050) +#define TLB0_SIZE_16M ASM_CONST(0x0000000000000070) +#define TLB0_SIZE_1G ASM_CONST(0x00000000000000a0) +#define TLB0_THDID_MASK ASM_CONST(0x000000000000000f) +#define TLB0_THDID_0 ASM_CONST(0x0000000000000001) +#define TLB0_THDID_1 ASM_CONST(0x0000000000000002) +#define TLB0_THDID_2 ASM_CONST(0x0000000000000004) +#define TLB0_THDID_3 ASM_CONST(0x0000000000000008) +#define TLB0_THDID_ALL ASM_CONST(0x000000000000000f) + +#define TLB1_RESVATTR ASM_CONST(0x00f0000000000000) +#define TLB1_U0 ASM_CONST(0x0008000000000000) +#define TLB1_U1 ASM_CONST(0x0004000000000000) +#define TLB1_U2 ASM_CONST(0x0002000000000000) +#define TLB1_U3 ASM_CONST(0x0001000000000000) +#define TLB1_R ASM_CONST(0x0000800000000000) +#define TLB1_C ASM_CONST(0x0000400000000000) +#define TLB1_RPN_MASK ASM_CONST(0x000003fffffff000) +#define TLB1_W ASM_CONST(0x0000000000000800) +#define TLB1_I ASM_CONST(0x0000000000000400) +#define TLB1_M ASM_CONST(0x0000000000000200) +#define TLB1_G ASM_CONST(0x0000000000000100) +#define TLB1_E ASM_CONST(0x0000000000000080) +#define TLB1_VF ASM_CONST(0x0000000000000040) +#define TLB1_UX ASM_CONST(0x0000000000000020) +#define TLB1_SX ASM_CONST(0x0000000000000010) +#define TLB1_UW ASM_CONST(0x0000000000000008) +#define TLB1_SW ASM_CONST(0x0000000000000004) +#define TLB1_UR ASM_CONST(0x0000000000000002) +#define TLB1_SR ASM_CONST(0x0000000000000001) + +/* A2 erativax attributes definitions */ +#define ERATIVAX_RS_IS_ALL 0x000 +#define ERATIVAX_RS_IS_TID 0x040 +#define ERATIVAX_RS_IS_CLASS 0x080 +#define ERATIVAX_RS_IS_FULLMATCH 0x0c0 +#define ERATIVAX_CLASS_00 0x000 +#define ERATIVAX_CLASS_01 0x010 +#define ERATIVAX_CLASS_10 0x020 +#define ERATIVAX_CLASS_11 0x030 +#define ERATIVAX_PSIZE_4K (TLB_PSIZE_4K >> 1) +#define ERATIVAX_PSIZE_64K (TLB_PSIZE_64K >> 1) +#define ERATIVAX_PSIZE_1M (TLB_PSIZE_1M >> 1) +#define ERATIVAX_PSIZE_16M (TLB_PSIZE_16M >> 1) +#define ERATIVAX_PSIZE_1G (TLB_PSIZE_1G >> 1) + +/* A2 eratilx attributes definitions */ +#define ERATILX_T_ALL 0 +#define ERATILX_T_TID 1 +#define ERATILX_T_TGS 2 +#define ERATILX_T_FULLMATCH 3 +#define ERATILX_T_CLASS0 4 +#define ERATILX_T_CLASS1 5 +#define ERATILX_T_CLASS2 6 +#define ERATILX_T_CLASS3 7 + +/* XUCR0 bits */ +#define XUCR0_TRACE_UM_T0 0x40000000 /* Thread 0 */ +#define XUCR0_TRACE_UM_T1 0x20000000 /* Thread 1 */ +#define XUCR0_TRACE_UM_T2 0x10000000 /* Thread 2 */ +#define XUCR0_TRACE_UM_T3 0x08000000 /* Thread 3 */ + +/* A2 CCR0 register */ +#define A2_CCR0_PME_DISABLED 0x00000000 +#define A2_CCR0_PME_SLEEP 0x40000000 +#define A2_CCR0_PME_RVW 0x80000000 +#define A2_CCR0_PME_DISABLED2 0xc0000000 + +/* A2 CCR2 register */ +#define A2_CCR2_ERAT_ONLY_MODE 0x00000001 +#define A2_CCR2_ENABLE_ICSWX 0x00000002 +#define A2_CCR2_ENABLE_PC 0x20000000 +#define A2_CCR2_ENABLE_TRACE 0x40000000 + +#endif /* __ASM_POWERPC_REG_A2_H__ */ diff --git a/arch/powerpc/kernel/Makefile b/arch/powerpc/kernel/Makefile index 0fd6273..058bc8b 100644 --- a/arch/powerpc/kernel/Makefile +++ b/arch/powerpc/kernel/Makefile @@ -41,6 +41,7 @@ obj-$(CONFIG_PPC_BOOK3S_64) += cpu_setup_ppc970.o cpu_setup_pa6t.o obj-$(CONFIG_PPC_BOOK3S_64) += cpu_setup_power7.o obj64-$(CONFIG_RELOCATABLE) += reloc_64.o obj-$(CONFIG_PPC_BOOK3E_64) += exceptions-64e.o idle_book3e.o +obj-$(CONFIG_PPC_A2) += cpu_setup_a2.o obj-$(CONFIG_PPC64) += vdso64/ obj-$(CONFIG_ALTIVEC) += vecemu.o obj-$(CONFIG_PPC_970_NAP) += idle_power4.o diff --git a/arch/powerpc/kernel/cpu_setup_a2.S b/arch/powerpc/kernel/cpu_setup_a2.S new file mode 100644 index 0000000..7f818fe --- /dev/null +++ b/arch/powerpc/kernel/cpu_setup_a2.S @@ -0,0 +1,114 @@ +/* + * A2 specific assembly support code + * + * Copyright 2009 Ben Herrenschmidt, IBM Corp. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ + +#include +#include +#include +#include +#include +#include +#include + +/* + * Disable thdid and class fields in ERATs to bump PID to full 14 bits capacity. + * This also prevents external LPID accesses but that isn't a problem when not a + * guest. Under PV, this setting will be ignored and MMUCR will return the right + * number of PID bits we can use. + */ +#define MMUCR1_EXTEND_PID \ + (MMUCR1_ICTID | MMUCR1_ITTID | MMUCR1_DCTID | \ + MMUCR1_DTTID | MMUCR1_DCCD) + +/* + * Use extended PIDs if enabled. + * Don't clear the ERATs on context sync events and enable I & D LRU. + * Enable ERAT back invalidate when tlbwe overwrites an entry. + */ +#define INITIAL_MMUCR1 \ + (MMUCR1_EXTEND_PID | MMUCR1_CSINV_NEVER | MMUCR1_IRRE | \ + MMUCR1_DRRE | MMUCR1_TLBWE_BINV) + +_GLOBAL(__setup_cpu_a2) + /* Some of these are actually thread local and some are + * core local but doing it always won't hurt + */ + +#ifdef CONFIG_PPC_WSP_COPRO + /* Make sure ACOP starts out as zero */ + li r3,0 + mtspr SPRN_ACOP,r3 + + /* Enable icswx instruction */ + mfspr r3,SPRN_A2_CCR2 + ori r3,r3,A2_CCR2_ENABLE_ICSWX + mtspr SPRN_A2_CCR2,r3 + + /* Unmask all CTs in HACOP */ + li r3,-1 + mtspr SPRN_HACOP,r3 +#endif /* CONFIG_PPC_WSP_COPRO */ + + /* Enable doorbell */ + mfspr r3,SPRN_A2_CCR2 + oris r3,r3,A2_CCR2_ENABLE_PC@h + mtspr SPRN_A2_CCR2,r3 + isync + + /* Setup CCR0 to disable power saving for now as it's busted + * in the current implementations. Setup CCR1 to wake on + * interrupts normally (we write the default value but who + * knows what FW may have clobbered...) + */ + li r3,0 + mtspr SPRN_A2_CCR0, r3 + LOAD_REG_IMMEDIATE(r3,0x0f0f0f0f) + mtspr SPRN_A2_CCR1, r3 + + /* Initialise MMUCR1 */ + lis r3,INITIAL_MMUCR1@h + ori r3,r3,INITIAL_MMUCR1@l + mtspr SPRN_MMUCR1,r3 + + /* Set MMUCR2 to enable 4K, 64K, 1M, 16M and 1G pages */ + LOAD_REG_IMMEDIATE(r3, 0x000a7531) + mtspr SPRN_MMUCR2,r3 + + /* Set MMUCR3 to write all thids bit to the TLB */ + LOAD_REG_IMMEDIATE(r3, 0x0000000f) + mtspr SPRN_MMUCR3,r3 + + /* Don't do ERAT stuff if running guest mode */ + mfmsr r3 + andis. r0,r3,MSR_GS@h + bne 1f + + /* Now set the I-ERAT watermark to 15 */ + lis r4,(MMUCR0_TLBSEL_I|MMUCR0_ECL)@h + mtspr SPRN_MMUCR0, r4 + li r4,A2_IERAT_SIZE-1 + PPC_ERATWE(r4,r4,3) + + /* Now set the D-ERAT watermark to 31 */ + lis r4,(MMUCR0_TLBSEL_D|MMUCR0_ECL)@h + mtspr SPRN_MMUCR0, r4 + li r4,A2_DERAT_SIZE-1 + PPC_ERATWE(r4,r4,3) + + /* And invalidate the beast just in case. That won't get rid of + * a bolted entry though it will be in LRU and so will go away eventually + * but let's not bother for now + */ + PPC_ERATILX(0,0,0) +1: + blr + +_GLOBAL(__restore_cpu_a2) + b __setup_cpu_a2 diff --git a/arch/powerpc/kernel/cputable.c b/arch/powerpc/kernel/cputable.c index b65b490..3d7b65a 100644 --- a/arch/powerpc/kernel/cputable.c +++ b/arch/powerpc/kernel/cputable.c @@ -62,10 +62,12 @@ extern void __setup_cpu_745x(unsigned long offset, struct cpu_spec* spec); extern void __setup_cpu_ppc970(unsigned long offset, struct cpu_spec* spec); extern void __setup_cpu_ppc970MP(unsigned long offset, struct cpu_spec* spec); extern void __setup_cpu_pa6t(unsigned long offset, struct cpu_spec* spec); +extern void __setup_cpu_a2(unsigned long offset, struct cpu_spec* spec); extern void __restore_cpu_pa6t(void); extern void __restore_cpu_ppc970(void); extern void __setup_cpu_power7(unsigned long offset, struct cpu_spec* spec); extern void __restore_cpu_power7(void); +extern void __restore_cpu_a2(void); #endif /* CONFIG_PPC64 */ #if defined(CONFIG_E500) extern void __setup_cpu_e5500(unsigned long offset, struct cpu_spec* spec); @@ -2011,7 +2013,26 @@ static struct cpu_spec __initdata cpu_specs[] = { #endif /* CONFIG_PPC32 */ #endif /* CONFIG_E500 */ -#ifdef CONFIG_PPC_BOOK3E_64 +#ifdef CONFIG_PPC_A2 + { /* Standard A2 (>= DD2) + FPU core */ + .pvr_mask = 0xffff0000, + .pvr_value = 0x00480000, + .cpu_name = "A2 (>= DD2)", + .cpu_features = CPU_FTRS_A2, + .cpu_user_features = COMMON_USER_PPC64, + .mmu_features = MMU_FTR_TYPE_3E | MMU_FTR_USE_TLBILX | + MMU_FTR_USE_TLBIVAX_BCAST | + MMU_FTR_LOCK_BCAST_INVAL | + MMU_FTR_USE_TLBRSRV | + MMU_FTR_USE_PAIRED_MAS, + .icache_bsize = 64, + .dcache_bsize = 64, + .num_pmcs = 0, + .cpu_setup = __setup_cpu_a2, + .cpu_restore = __restore_cpu_a2, + .machine_check = machine_check_generic, + .platform = "ppca2", + }, { /* This is a default entry to get going, to be replaced by * a real one at some stage */ @@ -2032,7 +2053,7 @@ static struct cpu_spec __initdata cpu_specs[] = { .machine_check = machine_check_generic, .platform = "power6", }, -#endif +#endif /* CONFIG_PPC_A2 */ }; static struct cpu_spec the_cpu_spec; diff --git a/arch/powerpc/platforms/Kconfig.cputype b/arch/powerpc/platforms/Kconfig.cputype index 111138c..7c1e1c6 100644 --- a/arch/powerpc/platforms/Kconfig.cputype +++ b/arch/powerpc/platforms/Kconfig.cputype @@ -107,6 +107,10 @@ config POWER4 depends on PPC64 && PPC_BOOK3S def_bool y +config PPC_A2 + bool + depends on PPC_BOOK3E_64 + config TUNE_CELL bool "Optimize for Cell Broadband Engine" depends on PPC64 && PPC_BOOK3S -- cgit v0.10.2 From bd491781097f150687906008d639936a0c00ed90 Mon Sep 17 00:00:00 2001 From: Benjamin Herrenschmidt Date: Thu, 14 Apr 2011 22:32:02 +0000 Subject: powerpc: Add TLB size detection for TYPE_3E MMUs Signed-off-by: Benjamin Herrenschmidt Signed-off-by: Michael Ellerman Signed-off-by: Benjamin Herrenschmidt diff --git a/arch/powerpc/include/asm/mmu-book3e.h b/arch/powerpc/include/asm/mmu-book3e.h index 17194fc..80d68af 100644 --- a/arch/powerpc/include/asm/mmu-book3e.h +++ b/arch/powerpc/include/asm/mmu-book3e.h @@ -137,6 +137,21 @@ #define MMUCSR0_TLB2PS 0x00078000 /* TLB2 Page Size */ #define MMUCSR0_TLB3PS 0x00780000 /* TLB3 Page Size */ +/* MMUCFG bits */ +#define MMUCFG_MAVN_NASK 0x00000003 +#define MMUCFG_MAVN_V1_0 0x00000000 +#define MMUCFG_MAVN_V2_0 0x00000001 +#define MMUCFG_NTLB_MASK 0x0000000c +#define MMUCFG_NTLB_SHIFT 2 +#define MMUCFG_PIDSIZE_MASK 0x000007c0 +#define MMUCFG_PIDSIZE_SHIFT 6 +#define MMUCFG_TWC 0x00008000 +#define MMUCFG_LRAT 0x00010000 +#define MMUCFG_RASIZE_MASK 0x00fe0000 +#define MMUCFG_RASIZE_SHIFT 17 +#define MMUCFG_LPIDSIZE_MASK 0x0f000000 +#define MMUCFG_LPIDSIZE_SHIFT 24 + /* TLBnCFG encoding */ #define TLBnCFG_N_ENTRY 0x00000fff /* number of entries */ #define TLBnCFG_HES 0x00002000 /* HW select supported */ diff --git a/arch/powerpc/mm/mmu_context_nohash.c b/arch/powerpc/mm/mmu_context_nohash.c index 4d8fa91..336807d 100644 --- a/arch/powerpc/mm/mmu_context_nohash.c +++ b/arch/powerpc/mm/mmu_context_nohash.c @@ -409,7 +409,17 @@ void __init mmu_context_init(void) } else if (mmu_has_feature(MMU_FTR_TYPE_47x)) { first_context = 1; last_context = 65535; - } else { + } else +#ifdef CONFIG_PPC_BOOK3E_MMU + if (mmu_has_feature(MMU_FTR_TYPE_3E)) { + u32 mmucfg = mfspr(SPRN_MMUCFG); + u32 pid_bits = (mmucfg & MMUCFG_PIDSIZE_MASK) + >> MMUCFG_PIDSIZE_SHIFT; + first_context = 1; + last_context = (1UL << (pid_bits + 1)) - 1; + } else +#endif + { first_context = 1; last_context = 255; } -- cgit v0.10.2 From ca1769f7a372898f5e3dbb8e4ff53f53f0626ef4 Mon Sep 17 00:00:00 2001 From: Michael Ellerman Date: Thu, 14 Apr 2011 22:32:04 +0000 Subject: powerpc: Index crit/dbg/mcheck stacks using cpu number on 64bit In exc_lvl_ctx_init() we index into the crit/dbg/mcheck stacks using the hard cpu id, but that assumes the hard cpu id is zero based and contiguous. That is not the case on A2. The root of the problem is that the 32bit code has no equivalent of the paca to allow it to do the hard->soft mapping in assembler. Until the 32bit code is updated to handle that, index the stacks using the soft cpu ids on 64bit and hard on 32 bit. Signed-off-by: Michael Ellerman Signed-off-by: Benjamin Herrenschmidt diff --git a/arch/powerpc/kernel/irq.c b/arch/powerpc/kernel/irq.c index f621b7d..ea09512 100644 --- a/arch/powerpc/kernel/irq.c +++ b/arch/powerpc/kernel/irq.c @@ -397,24 +397,28 @@ struct thread_info *mcheckirq_ctx[NR_CPUS] __read_mostly; void exc_lvl_ctx_init(void) { struct thread_info *tp; - int i, hw_cpu; + int i, cpu_nr; for_each_possible_cpu(i) { - hw_cpu = get_hard_smp_processor_id(i); - memset((void *)critirq_ctx[hw_cpu], 0, THREAD_SIZE); - tp = critirq_ctx[hw_cpu]; - tp->cpu = i; +#ifdef CONFIG_PPC64 + cpu_nr = i; +#else + cpu_nr = get_hard_smp_processor_id(i); +#endif + memset((void *)critirq_ctx[cpu_nr], 0, THREAD_SIZE); + tp = critirq_ctx[cpu_nr]; + tp->cpu = cpu_nr; tp->preempt_count = 0; #ifdef CONFIG_BOOKE - memset((void *)dbgirq_ctx[hw_cpu], 0, THREAD_SIZE); - tp = dbgirq_ctx[hw_cpu]; - tp->cpu = i; + memset((void *)dbgirq_ctx[cpu_nr], 0, THREAD_SIZE); + tp = dbgirq_ctx[cpu_nr]; + tp->cpu = cpu_nr; tp->preempt_count = 0; - memset((void *)mcheckirq_ctx[hw_cpu], 0, THREAD_SIZE); - tp = mcheckirq_ctx[hw_cpu]; - tp->cpu = i; + memset((void *)mcheckirq_ctx[cpu_nr], 0, THREAD_SIZE); + tp = mcheckirq_ctx[cpu_nr]; + tp->cpu = cpu_nr; tp->preempt_count = HARDIRQ_OFFSET; #endif } -- cgit v0.10.2 From 1a51dde139d5305b2592c716c50c005d6ab9624b Mon Sep 17 00:00:00 2001 From: Benjamin Herrenschmidt Date: Thu, 14 Apr 2011 22:32:04 +0000 Subject: powerpc/book3e: Use way 3 for linear mapping bolted entry An erratum on A2 can lead to the bolted entry we insert for the linear mapping being evicted, to avoid that write the bolted entry to way 3. Signed-off-by: Benjamin Herrenschmidt Signed-off-by: Michael Ellerman Signed-off-by: Benjamin Herrenschmidt diff --git a/arch/powerpc/kernel/exceptions-64e.S b/arch/powerpc/kernel/exceptions-64e.S index 9651acc..8fe0fc2 100644 --- a/arch/powerpc/kernel/exceptions-64e.S +++ b/arch/powerpc/kernel/exceptions-64e.S @@ -864,8 +864,9 @@ have_hes: * that will have to be made dependent on whether we are running under * a hypervisor I suppose. */ - ori r3,r3,MAS0_HES | MAS0_WQ_ALLWAYS - mtspr SPRN_MAS0,r3 + ori r11,r3,MAS0_WQ_ALLWAYS + oris r11,r11,MAS0_ESEL(3)@h /* Use way 3: workaround A2 erratum 376 */ + mtspr SPRN_MAS0,r11 lis r3,(MAS1_VALID | MAS1_IPROT)@h ori r3,r3,BOOK3E_PAGESZ_1GB << MAS1_TSIZE_SHIFT mtspr SPRN_MAS1,r3 -- cgit v0.10.2 From f0aae3238fc1c28b543cbaaa0e7c5d57685f5f89 Mon Sep 17 00:00:00 2001 From: Jack Miller Date: Thu, 14 Apr 2011 22:32:05 +0000 Subject: powerpc/book3e: Flush IPROT protected TLB entries leftover by firmware When we set up the TLB for ourselves on Book3E, we need to flush out any old mappings established by the firmware or bootloader. At present we attempt this with a tlbilx to flush everything, but this will leave behind any entries with the IPROT bit set. There are several good reason firmware might establish mappings with IPROT, and in fact ePAPR compliant firmwares are required to establish their initial mapped area with IPROT. This patch, therefore adds more complex code to scan through the TLB upon entry and flush away any entries that are not our own. Signed-off-by: Jack Miller Signed-off-by: David Gibson Signed-off-by: Michael Ellerman Signed-off-by: Benjamin Herrenschmidt diff --git a/arch/powerpc/include/asm/mmu-book3e.h b/arch/powerpc/include/asm/mmu-book3e.h index 80d68af..ec61e7b 100644 --- a/arch/powerpc/include/asm/mmu-book3e.h +++ b/arch/powerpc/include/asm/mmu-book3e.h @@ -43,6 +43,7 @@ #define MAS0_TLBSEL(x) (((x) << 28) & 0x30000000) #define MAS0_ESEL(x) (((x) << 16) & 0x0FFF0000) #define MAS0_NV(x) ((x) & 0x00000FFF) +#define MAS0_ESEL_MASK 0x0FFF0000 #define MAS0_HES 0x00004000 #define MAS0_WQ_ALLWAYS 0x00000000 #define MAS0_WQ_COND 0x00001000 diff --git a/arch/powerpc/kernel/exceptions-64e.S b/arch/powerpc/kernel/exceptions-64e.S index 8fe0fc2..23bd83b 100644 --- a/arch/powerpc/kernel/exceptions-64e.S +++ b/arch/powerpc/kernel/exceptions-64e.S @@ -886,8 +886,51 @@ have_hes: bctr 1: /* We are now running at PAGE_OFFSET, clean the TLB of everything - * else (XXX we should scan for bolted crap from the firmware too) + * else (including IPROTed things left by firmware) + * r4 = TLBnCFG + * r3 = current address (more or less) */ + + li r5,0 + mtspr SPRN_MAS6,r5 + tlbsx 0,r3 + + rlwinm r9,r4,0,TLBnCFG_N_ENTRY + rlwinm r10,r4,8,0xff + addi r10,r10,-1 /* Get inner loop mask */ + + li r3,1 + + mfspr r5,SPRN_MAS1 + rlwinm r5,r5,0,(~(MAS1_VALID|MAS1_IPROT)) + + mfspr r6,SPRN_MAS2 + rldicr r6,r6,0,51 /* Extract EPN */ + + mfspr r7,SPRN_MAS0 + rlwinm r7,r7,0,0xffff0fff /* Clear HES and WQ */ + + rlwinm r8,r7,16,0xfff /* Extract ESEL */ + +2: add r4,r3,r8 + and r4,r4,r10 + + rlwimi r7,r4,16,MAS0_ESEL_MASK + + mtspr SPRN_MAS0,r7 + mtspr SPRN_MAS1,r5 + mtspr SPRN_MAS2,r6 + tlbwe + + addi r3,r3,1 + and. r4,r3,r10 + + bne 3f + addis r6,r6,(1<<30)@h +3: + cmpw r3,r9 + blt 2b + PPC_TLBILX(0,0,0) sync isync -- cgit v0.10.2 From 6befe5f69bae9f907e6c85bbfe298e404864092e Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Tue, 26 Apr 2011 12:33:21 -0700 Subject: init/Kconfig: fix EXPERT menu list The EXPERT menu list was recently broken by the insertion of a kconfig symbol (EMBEDDED) at the beginning of the EXPERT list of kconfig items. Broken by: commit 6a108a14fa356ef607be308b68337939e56ea94e Author: David Rientjes Date: Thu Jan 20 14:44:16 2011 -0800 kconfig: rename CONFIG_EMBEDDED to CONFIG_EXPERT Restore the EXPERT menu list -- don't inject a symbol (EMBEDDED) that does not depend on EXPERT into the list. Signed-off-by: Randy Dunlap Cc: David Rientjes Cc: Peter Foley Signed-off-by: Linus Torvalds diff --git a/init/Kconfig b/init/Kconfig index 56240e7..7a71e0a 100644 --- a/init/Kconfig +++ b/init/Kconfig @@ -924,14 +924,6 @@ menuconfig EXPERT environments which can tolerate a "non-standard" kernel. Only use this if you really know what you are doing. -config EMBEDDED - bool "Embedded system" - select EXPERT - help - This option should be enabled if compiling the kernel for - an embedded system so certain expert options are available - for configuration. - config UID16 bool "Enable 16-bit UID system calls" if EXPERT depends on ARM || BLACKFIN || CRIS || FRV || H8300 || X86_32 || M68K || (S390 && !64BIT) || SUPERH || SPARC32 || (SPARC64 && COMPAT) || UML || (X86_64 && IA32_EMULATION) @@ -1104,6 +1096,14 @@ config AIO by some high performance threaded applications. Disabling this option saves about 7k. +config EMBEDDED + bool "Embedded system" + select EXPERT + help + This option should be enabled if compiling the kernel for + an embedded system so certain expert options are available + for configuration. + config HAVE_PERF_EVENTS bool help -- cgit v0.10.2 From 8e10cd74342c7f5ce259cceca36f6eba084f5d58 Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Tue, 26 Apr 2011 20:48:50 -0700 Subject: Linux 2.6.39-rc5 diff --git a/Makefile b/Makefile index b967b96..5a7a2e4 100644 --- a/Makefile +++ b/Makefile @@ -1,7 +1,7 @@ VERSION = 2 PATCHLEVEL = 6 SUBLEVEL = 39 -EXTRAVERSION = -rc4 +EXTRAVERSION = -rc5 NAME = Flesh-Eating Bats with Fangs # *DOCUMENTATION* -- cgit v0.10.2 From efcac6589a277c10060e4be44b9455cf43838dc1 Mon Sep 17 00:00:00 2001 From: Alexey Kardashevskiy Date: Wed, 2 Mar 2011 15:18:48 +0000 Subject: powerpc: Per process DSCR + some fixes (try#4) The DSCR (aka Data Stream Control Register) is supported on some server PowerPC chips and allow some control over the prefetch of data streams. This patch allows the value to be specified per thread by emulating the corresponding mfspr and mtspr instructions. Children of such threads inherit the value. Other threads use a default value that can be specified in sysfs - /sys/devices/system/cpu/dscr_default. If a thread starts with non default value in the sysfs entry, all children threads inherit this non default value even if the sysfs value is changed later. Signed-off-by: Alexey Kardashevskiy Signed-off-by: Benjamin Herrenschmidt diff --git a/arch/powerpc/include/asm/emulated_ops.h b/arch/powerpc/include/asm/emulated_ops.h index f0fb4fc..4592167 100644 --- a/arch/powerpc/include/asm/emulated_ops.h +++ b/arch/powerpc/include/asm/emulated_ops.h @@ -52,6 +52,10 @@ extern struct ppc_emulated { #ifdef CONFIG_VSX struct ppc_emulated_entry vsx; #endif +#ifdef CONFIG_PPC64 + struct ppc_emulated_entry mfdscr; + struct ppc_emulated_entry mtdscr; +#endif } ppc_emulated; extern u32 ppc_warn_emulated; diff --git a/arch/powerpc/include/asm/ppc-opcode.h b/arch/powerpc/include/asm/ppc-opcode.h index 3e25b25..e472659 100644 --- a/arch/powerpc/include/asm/ppc-opcode.h +++ b/arch/powerpc/include/asm/ppc-opcode.h @@ -41,6 +41,10 @@ #define PPC_INST_RFCI 0x4c000066 #define PPC_INST_RFDI 0x4c00004e #define PPC_INST_RFMCI 0x4c00004c +#define PPC_INST_MFSPR_DSCR 0x7c1102a6 +#define PPC_INST_MFSPR_DSCR_MASK 0xfc1fffff +#define PPC_INST_MTSPR_DSCR 0x7c1103a6 +#define PPC_INST_MTSPR_DSCR_MASK 0xfc1fffff #define PPC_INST_STRING 0x7c00042a #define PPC_INST_STRING_MASK 0xfc0007fe diff --git a/arch/powerpc/include/asm/processor.h b/arch/powerpc/include/asm/processor.h index de1967a..d50c2b6 100644 --- a/arch/powerpc/include/asm/processor.h +++ b/arch/powerpc/include/asm/processor.h @@ -238,6 +238,10 @@ struct thread_struct { #ifdef CONFIG_KVM_BOOK3S_32_HANDLER void* kvm_shadow_vcpu; /* KVM internal data */ #endif /* CONFIG_KVM_BOOK3S_32_HANDLER */ +#ifdef CONFIG_PPC64 + unsigned long dscr; + int dscr_inherit; +#endif }; #define ARCH_MIN_TASKALIGN 16 diff --git a/arch/powerpc/kernel/asm-offsets.c b/arch/powerpc/kernel/asm-offsets.c index 23e6a93..6887661 100644 --- a/arch/powerpc/kernel/asm-offsets.c +++ b/arch/powerpc/kernel/asm-offsets.c @@ -74,6 +74,7 @@ int main(void) DEFINE(AUDITCONTEXT, offsetof(struct task_struct, audit_context)); DEFINE(SIGSEGV, SIGSEGV); DEFINE(NMI_MASK, NMI_MASK); + DEFINE(THREAD_DSCR, offsetof(struct thread_struct, dscr)); #else DEFINE(THREAD_INFO, offsetof(struct task_struct, stack)); #endif /* CONFIG_PPC64 */ diff --git a/arch/powerpc/kernel/entry_64.S b/arch/powerpc/kernel/entry_64.S index dbf5bfa..6469370 100644 --- a/arch/powerpc/kernel/entry_64.S +++ b/arch/powerpc/kernel/entry_64.S @@ -421,6 +421,12 @@ BEGIN_FTR_SECTION std r24,THREAD_VRSAVE(r3) END_FTR_SECTION_IFSET(CPU_FTR_ALTIVEC) #endif /* CONFIG_ALTIVEC */ +#ifdef CONFIG_PPC64 +BEGIN_FTR_SECTION + mfspr r25,SPRN_DSCR + std r25,THREAD_DSCR(r3) +END_FTR_SECTION_IFSET(CPU_FTR_DSCR) +#endif and. r0,r0,r22 beq+ 1f andc r22,r22,r0 @@ -522,6 +528,15 @@ BEGIN_FTR_SECTION mtspr SPRN_VRSAVE,r0 /* if G4, restore VRSAVE reg */ END_FTR_SECTION_IFSET(CPU_FTR_ALTIVEC) #endif /* CONFIG_ALTIVEC */ +#ifdef CONFIG_PPC64 +BEGIN_FTR_SECTION + ld r0,THREAD_DSCR(r4) + cmpd r0,r25 + beq 1f + mtspr SPRN_DSCR,r0 +1: +END_FTR_SECTION_IFSET(CPU_FTR_DSCR) +#endif /* r3-r13 are destroyed -- Cort */ REST_8GPRS(14, r1) diff --git a/arch/powerpc/kernel/process.c b/arch/powerpc/kernel/process.c index f74f355..a01c2d9 100644 --- a/arch/powerpc/kernel/process.c +++ b/arch/powerpc/kernel/process.c @@ -702,6 +702,8 @@ void prepare_to_copy(struct task_struct *tsk) /* * Copy a thread.. */ +extern unsigned long dscr_default; /* defined in arch/powerpc/kernel/sysfs.c */ + int copy_thread(unsigned long clone_flags, unsigned long usp, unsigned long unused, struct task_struct *p, struct pt_regs *regs) @@ -769,6 +771,20 @@ int copy_thread(unsigned long clone_flags, unsigned long usp, p->thread.ksp_vsid = sp_vsid; } #endif /* CONFIG_PPC_STD_MMU_64 */ +#ifdef CONFIG_PPC64 + if (cpu_has_feature(CPU_FTR_DSCR)) { + if (current->thread.dscr_inherit) { + p->thread.dscr_inherit = 1; + p->thread.dscr = current->thread.dscr; + } else if (0 != dscr_default) { + p->thread.dscr_inherit = 1; + p->thread.dscr = dscr_default; + } else { + p->thread.dscr_inherit = 0; + p->thread.dscr = 0; + } + } +#endif /* * The PPC64 ABI makes use of a TOC to contain function diff --git a/arch/powerpc/kernel/sysfs.c b/arch/powerpc/kernel/sysfs.c index c0d8c20..f0f2199 100644 --- a/arch/powerpc/kernel/sysfs.c +++ b/arch/powerpc/kernel/sysfs.c @@ -182,6 +182,41 @@ static SYSDEV_ATTR(mmcra, 0600, show_mmcra, store_mmcra); static SYSDEV_ATTR(spurr, 0600, show_spurr, NULL); static SYSDEV_ATTR(dscr, 0600, show_dscr, store_dscr); static SYSDEV_ATTR(purr, 0600, show_purr, store_purr); + +unsigned long dscr_default = 0; +EXPORT_SYMBOL(dscr_default); + +static ssize_t show_dscr_default(struct sysdev_class *class, + struct sysdev_class_attribute *attr, char *buf) +{ + return sprintf(buf, "%lx\n", dscr_default); +} + +static ssize_t __used store_dscr_default(struct sysdev_class *class, + struct sysdev_class_attribute *attr, const char *buf, + size_t count) +{ + unsigned long val; + int ret = 0; + + ret = sscanf(buf, "%lx", &val); + if (ret != 1) + return -EINVAL; + dscr_default = val; + + return count; +} + +static SYSDEV_CLASS_ATTR(dscr_default, 0600, + show_dscr_default, store_dscr_default); + +static void sysfs_create_dscr_default(void) +{ + int err = 0; + if (cpu_has_feature(CPU_FTR_DSCR)) + err = sysfs_create_file(&cpu_sysdev_class.kset.kobj, + &attr_dscr_default.attr); +} #endif /* CONFIG_PPC64 */ #ifdef HAS_PPC_PMC_PA6T @@ -617,6 +652,9 @@ static int __init topology_init(void) if (cpu_online(cpu)) register_cpu_online(cpu); } +#ifdef CONFIG_PPC64 + sysfs_create_dscr_default(); +#endif /* CONFIG_PPC64 */ return 0; } diff --git a/arch/powerpc/kernel/traps.c b/arch/powerpc/kernel/traps.c index 5ddb801..cb71cf2 100644 --- a/arch/powerpc/kernel/traps.c +++ b/arch/powerpc/kernel/traps.c @@ -909,6 +909,26 @@ static int emulate_instruction(struct pt_regs *regs) return emulate_isel(regs, instword); } +#ifdef CONFIG_PPC64 + /* Emulate the mfspr rD, DSCR. */ + if (((instword & PPC_INST_MFSPR_DSCR_MASK) == PPC_INST_MFSPR_DSCR) && + cpu_has_feature(CPU_FTR_DSCR)) { + PPC_WARN_EMULATED(mfdscr, regs); + rd = (instword >> 21) & 0x1f; + regs->gpr[rd] = mfspr(SPRN_DSCR); + return 0; + } + /* Emulate the mtspr DSCR, rD. */ + if (((instword & PPC_INST_MTSPR_DSCR_MASK) == PPC_INST_MTSPR_DSCR) && + cpu_has_feature(CPU_FTR_DSCR)) { + PPC_WARN_EMULATED(mtdscr, regs); + rd = (instword >> 21) & 0x1f; + mtspr(SPRN_DSCR, regs->gpr[rd]); + current->thread.dscr_inherit = 1; + return 0; + } +#endif + return -EINVAL; } @@ -1506,6 +1526,10 @@ struct ppc_emulated ppc_emulated = { #ifdef CONFIG_VSX WARN_EMULATED_SETUP(vsx), #endif +#ifdef CONFIG_PPC64 + WARN_EMULATED_SETUP(mfdscr), + WARN_EMULATED_SETUP(mtdscr), +#endif }; u32 ppc_warn_emulated; -- cgit v0.10.2 From e297d9dd5cfafbeb2e7585bb444941848e030454 Mon Sep 17 00:00:00 2001 From: Nishanth Aravamudan Date: Mon, 14 Mar 2011 10:36:11 +0000 Subject: cxgb4: use pgprot_writecombine() on powerpc Commit fe3cc0d99de6a9bf99b6c279a8afb5833888c1f7 ("powerpc: Add pgprot_writecombine") in benh's tree exposes the pgprot_writecombine() API to drivers on powerpc. cxgb4 has an open-coded version of the same, so use the common API now that it's available. Signed-off-by: Nishanth Aravamudan Cc: Steve Wise Cc: Anton Blanchard Acked-by: Steve Wise Signed-off-by: Benjamin Herrenschmidt diff --git a/drivers/infiniband/hw/cxgb4/t4.h b/drivers/infiniband/hw/cxgb4/t4.h index 24af12f..c0221ee 100644 --- a/drivers/infiniband/hw/cxgb4/t4.h +++ b/drivers/infiniband/hw/cxgb4/t4.h @@ -269,11 +269,8 @@ struct t4_swsqe { static inline pgprot_t t4_pgprot_wc(pgprot_t prot) { -#if defined(__i386__) || defined(__x86_64__) +#if defined(__i386__) || defined(__x86_64__) || defined(CONFIG_PPC64) return pgprot_writecombine(prot); -#elif defined(CONFIG_PPC64) - return __pgprot((pgprot_val(prot) | _PAGE_NO_CACHE) & - ~(pgprot_t)_PAGE_GUARDED); #else return pgprot_noncached(prot); #endif -- cgit v0.10.2 From 21176fed25c3b0cb17c6c42d71b4e3d68b8f9dd4 Mon Sep 17 00:00:00 2001 From: Michael Ellerman Date: Mon, 11 Apr 2011 21:25:01 +0000 Subject: powerpc/pci: Split IO vs MMIO indirect access hooks The goal is to avoid adding overhead to MMIO when only PIO is needed Signed-off-by: Benjamin Herrenschmidt Signed-off-by: Michael Ellerman Signed-off-by: Benjamin Herrenschmidt diff --git a/arch/powerpc/include/asm/io.h b/arch/powerpc/include/asm/io.h index 001f2f1..2f365f5 100644 --- a/arch/powerpc/include/asm/io.h +++ b/arch/powerpc/include/asm/io.h @@ -481,10 +481,16 @@ __do_out_asm(_rec_outl, "stwbrx") _memcpy_fromio(dst,PCI_FIX_ADDR(src),n) #endif /* !CONFIG_EEH */ -#ifdef CONFIG_PPC_INDIRECT_IO -#define DEF_PCI_HOOK(x) x +#ifdef CONFIG_PPC_INDIRECT_PIO +#define DEF_PCI_HOOK_pio(x) x +#else +#define DEF_PCI_HOOK_pio(x) NULL +#endif + +#ifdef CONFIG_PPC_INDIRECT_MMIO +#define DEF_PCI_HOOK_mem(x) x #else -#define DEF_PCI_HOOK(x) NULL +#define DEF_PCI_HOOK_mem(x) NULL #endif /* Structure containing all the hooks */ @@ -504,7 +510,7 @@ extern struct ppc_pci_io { #define DEF_PCI_AC_RET(name, ret, at, al, space, aa) \ static inline ret name at \ { \ - if (DEF_PCI_HOOK(ppc_pci_io.name) != NULL) \ + if (DEF_PCI_HOOK_##space(ppc_pci_io.name) != NULL) \ return ppc_pci_io.name al; \ return __do_##name al; \ } @@ -512,7 +518,7 @@ static inline ret name at \ #define DEF_PCI_AC_NORET(name, at, al, space, aa) \ static inline void name at \ { \ - if (DEF_PCI_HOOK(ppc_pci_io.name) != NULL) \ + if (DEF_PCI_HOOK_##space(ppc_pci_io.name) != NULL) \ ppc_pci_io.name al; \ else \ __do_##name al; \ diff --git a/arch/powerpc/platforms/Kconfig b/arch/powerpc/platforms/Kconfig index 658ffc5..54db9fb 100644 --- a/arch/powerpc/platforms/Kconfig +++ b/arch/powerpc/platforms/Kconfig @@ -154,11 +154,17 @@ config PPC_P7_NAP config PPC_INDIRECT_IO bool select GENERIC_IOMAP - default n + +config PPC_INDIRECT_PIO + bool + select PPC_INDIRECT_IO + +config PPC_INDIRECT_MMIO + bool + select PPC_INDIRECT_IO config GENERIC_IOMAP bool - default n source "drivers/cpufreq/Kconfig" diff --git a/arch/powerpc/platforms/cell/Kconfig b/arch/powerpc/platforms/cell/Kconfig index 81239eb..3c7f1de 100644 --- a/arch/powerpc/platforms/cell/Kconfig +++ b/arch/powerpc/platforms/cell/Kconfig @@ -6,7 +6,8 @@ config PPC_CELL_COMMON bool select PPC_CELL select PPC_DCR_MMIO - select PPC_INDIRECT_IO + select PPC_INDIRECT_PIO + select PPC_INDIRECT_MMIO select PPC_NATIVE select PPC_RTAS select IRQ_EDGE_EOI_HANDLER diff --git a/arch/powerpc/platforms/iseries/Kconfig b/arch/powerpc/platforms/iseries/Kconfig index e5bc9f7..ea1d362 100644 --- a/arch/powerpc/platforms/iseries/Kconfig +++ b/arch/powerpc/platforms/iseries/Kconfig @@ -1,7 +1,8 @@ config PPC_ISERIES bool "IBM Legacy iSeries" depends on PPC64 && PPC_BOOK3S - select PPC_INDIRECT_IO + select PPC_INDIRECT_PIO + select PPC_INDIRECT_MMIO select PPC_PCI_CHOICE if EXPERT menu "iSeries device drivers" -- cgit v0.10.2 From 3cc30d0726d258ac336283bcde66a8ab58283b61 Mon Sep 17 00:00:00 2001 From: Michael Ellerman Date: Mon, 11 Apr 2011 21:25:01 +0000 Subject: powerpc/pci: Move IO workarounds to the common kernel dir Signed-off-by: Benjamin Herrenschmidt Signed-off-by: Michael Ellerman Signed-off-by: Benjamin Herrenschmidt diff --git a/arch/powerpc/include/asm/io-workarounds.h b/arch/powerpc/include/asm/io-workarounds.h new file mode 100644 index 0000000..6efc778 --- /dev/null +++ b/arch/powerpc/include/asm/io-workarounds.h @@ -0,0 +1,49 @@ +/* + * Support PCI IO workaround + * + * (C) Copyright 2007-2008 TOSHIBA CORPORATION + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifndef _IO_WORKAROUNDS_H +#define _IO_WORKAROUNDS_H + +#include +#include + +/* Bus info */ +struct iowa_bus { + struct pci_controller *phb; + struct ppc_pci_io *ops; + void *private; +}; + +void __devinit io_workaround_init(void); +void __devinit iowa_register_bus(struct pci_controller *, struct ppc_pci_io *, + int (*)(struct iowa_bus *, void *), void *); +struct iowa_bus *iowa_mem_find_bus(const PCI_IO_ADDR); +struct iowa_bus *iowa_pio_find_bus(unsigned long); + +extern struct ppc_pci_io spiderpci_ops; +extern int spiderpci_iowa_init(struct iowa_bus *, void *); + +#define SPIDER_PCI_REG_BASE 0xd000 +#define SPIDER_PCI_REG_SIZE 0x1000 +#define SPIDER_PCI_VCI_CNTL_STAT 0x0110 +#define SPIDER_PCI_DUMMY_READ 0x0810 +#define SPIDER_PCI_DUMMY_READ_BASE 0x0814 + +#endif /* _IO_WORKAROUNDS_H */ diff --git a/arch/powerpc/kernel/Makefile b/arch/powerpc/kernel/Makefile index 058bc8b..82e0bed 100644 --- a/arch/powerpc/kernel/Makefile +++ b/arch/powerpc/kernel/Makefile @@ -106,6 +106,8 @@ obj-$(CONFIG_KEXEC) += machine_kexec.o crash.o \ obj-$(CONFIG_AUDIT) += audit.o obj64-$(CONFIG_AUDIT) += compat_audit.o +obj-$(CONFIG_PPC_IO_WORKAROUNDS) += io-workarounds.o + obj-$(CONFIG_DYNAMIC_FTRACE) += ftrace.o obj-$(CONFIG_FUNCTION_GRAPH_TRACER) += ftrace.o obj-$(CONFIG_PERF_EVENTS) += perf_callchain.o diff --git a/arch/powerpc/kernel/io-workarounds.c b/arch/powerpc/kernel/io-workarounds.c new file mode 100644 index 0000000..7e58457 --- /dev/null +++ b/arch/powerpc/kernel/io-workarounds.c @@ -0,0 +1,184 @@ +/* + * Support PCI IO workaround + * + * Copyright (C) 2006 Benjamin Herrenschmidt + * IBM, Corp. + * (C) Copyright 2007-2008 TOSHIBA CORPORATION + * + * 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. + */ +#undef DEBUG + +#include + +#include +#include +#include +#include +#include + +#define IOWA_MAX_BUS 8 + +static struct iowa_bus iowa_busses[IOWA_MAX_BUS]; +static unsigned int iowa_bus_count; + +static struct iowa_bus *iowa_pci_find(unsigned long vaddr, unsigned long paddr) +{ + int i, j; + struct resource *res; + unsigned long vstart, vend; + + for (i = 0; i < iowa_bus_count; i++) { + struct iowa_bus *bus = &iowa_busses[i]; + struct pci_controller *phb = bus->phb; + + if (vaddr) { + vstart = (unsigned long)phb->io_base_virt; + vend = vstart + phb->pci_io_size - 1; + if ((vaddr >= vstart) && (vaddr <= vend)) + return bus; + } + + if (paddr) + for (j = 0; j < 3; j++) { + res = &phb->mem_resources[j]; + if (paddr >= res->start && paddr <= res->end) + return bus; + } + } + + return NULL; +} + +struct iowa_bus *iowa_mem_find_bus(const PCI_IO_ADDR addr) +{ + struct iowa_bus *bus; + int token; + + token = PCI_GET_ADDR_TOKEN(addr); + + if (token && token <= iowa_bus_count) + bus = &iowa_busses[token - 1]; + else { + unsigned long vaddr, paddr; + pte_t *ptep; + + vaddr = (unsigned long)PCI_FIX_ADDR(addr); + if (vaddr < PHB_IO_BASE || vaddr >= PHB_IO_END) + return NULL; + + ptep = find_linux_pte(init_mm.pgd, vaddr); + if (ptep == NULL) + paddr = 0; + else + paddr = pte_pfn(*ptep) << PAGE_SHIFT; + bus = iowa_pci_find(vaddr, paddr); + + if (bus == NULL) + return NULL; + } + + return bus; +} + +struct iowa_bus *iowa_pio_find_bus(unsigned long port) +{ + unsigned long vaddr = (unsigned long)pci_io_base + port; + return iowa_pci_find(vaddr, 0); +} + + +#define DEF_PCI_AC_RET(name, ret, at, al, space, aa) \ +static ret iowa_##name at \ +{ \ + struct iowa_bus *bus; \ + bus = iowa_##space##_find_bus(aa); \ + if (bus && bus->ops && bus->ops->name) \ + return bus->ops->name al; \ + return __do_##name al; \ +} + +#define DEF_PCI_AC_NORET(name, at, al, space, aa) \ +static void iowa_##name at \ +{ \ + struct iowa_bus *bus; \ + bus = iowa_##space##_find_bus(aa); \ + if (bus && bus->ops && bus->ops->name) { \ + bus->ops->name al; \ + return; \ + } \ + __do_##name al; \ +} + +#include + +#undef DEF_PCI_AC_RET +#undef DEF_PCI_AC_NORET + +static const struct ppc_pci_io __devinitconst iowa_pci_io = { + +#define DEF_PCI_AC_RET(name, ret, at, al, space, aa) .name = iowa_##name, +#define DEF_PCI_AC_NORET(name, at, al, space, aa) .name = iowa_##name, + +#include + +#undef DEF_PCI_AC_RET +#undef DEF_PCI_AC_NORET + +}; + +static void __iomem *iowa_ioremap(phys_addr_t addr, unsigned long size, + unsigned long flags, void *caller) +{ + struct iowa_bus *bus; + void __iomem *res = __ioremap_caller(addr, size, flags, caller); + int busno; + + bus = iowa_pci_find(0, (unsigned long)addr); + if (bus != NULL) { + busno = bus - iowa_busses; + PCI_SET_ADDR_TOKEN(res, busno + 1); + } + return res; +} + +/* Regist new bus to support workaround */ +void __devinit iowa_register_bus(struct pci_controller *phb, + struct ppc_pci_io *ops, + int (*initfunc)(struct iowa_bus *, void *), void *data) +{ + struct iowa_bus *bus; + struct device_node *np = phb->dn; + + if (iowa_bus_count >= IOWA_MAX_BUS) { + pr_err("IOWA:Too many pci bridges, " + "workarounds disabled for %s\n", np->full_name); + return; + } + + bus = &iowa_busses[iowa_bus_count]; + bus->phb = phb; + bus->ops = ops; + + if (initfunc) + if ((*initfunc)(bus, data)) + return; + + iowa_bus_count++; + + pr_debug("IOWA:[%d]Add bus, %s.\n", iowa_bus_count-1, np->full_name); +} + +/* enable IO workaround */ +void __devinit io_workaround_init(void) +{ + static int io_workaround_inited; + + if (io_workaround_inited) + return; + ppc_pci_io = iowa_pci_io; + ppc_md.ioremap = iowa_ioremap; + io_workaround_inited = 1; +} diff --git a/arch/powerpc/platforms/Kconfig b/arch/powerpc/platforms/Kconfig index 54db9fb..f2352fc 100644 --- a/arch/powerpc/platforms/Kconfig +++ b/arch/powerpc/platforms/Kconfig @@ -163,6 +163,9 @@ config PPC_INDIRECT_MMIO bool select PPC_INDIRECT_IO +config PPC_IO_WORKAROUNDS + bool + config GENERIC_IOMAP bool diff --git a/arch/powerpc/platforms/cell/Kconfig b/arch/powerpc/platforms/cell/Kconfig index 3c7f1de..67d5009 100644 --- a/arch/powerpc/platforms/cell/Kconfig +++ b/arch/powerpc/platforms/cell/Kconfig @@ -16,6 +16,7 @@ config PPC_CELL_NATIVE bool select PPC_CELL_COMMON select MPIC + select PPC_IO_WORKAROUNDS select IBM_NEW_EMAC_EMAC4 select IBM_NEW_EMAC_RGMII select IBM_NEW_EMAC_ZMII #test only diff --git a/arch/powerpc/platforms/cell/Makefile b/arch/powerpc/platforms/cell/Makefile index 83fafe9..8839ef6 100644 --- a/arch/powerpc/platforms/cell/Makefile +++ b/arch/powerpc/platforms/cell/Makefile @@ -1,7 +1,7 @@ obj-$(CONFIG_PPC_CELL_COMMON) += cbe_regs.o interrupt.o pervasive.o obj-$(CONFIG_PPC_CELL_NATIVE) += iommu.o setup.o spider-pic.o \ - pmu.o io-workarounds.o spider-pci.o + pmu.o spider-pci.o obj-$(CONFIG_CBE_RAS) += ras.o obj-$(CONFIG_CBE_THERM) += cbe_thermal.o @@ -39,9 +39,9 @@ obj-y += celleb_setup.o \ celleb_pci.o celleb_scc_epci.o \ celleb_scc_pciex.o \ celleb_scc_uhc.o \ - io-workarounds.o spider-pci.o \ - beat.o beat_htab.o beat_hvCall.o \ - beat_interrupt.o beat_iommu.o + spider-pci.o beat.o beat_htab.o \ + beat_hvCall.o beat_interrupt.o \ + beat_iommu.o obj-$(CONFIG_SMP) += beat_smp.o obj-$(CONFIG_PPC_UDBG_BEAT) += beat_udbg.o diff --git a/arch/powerpc/platforms/cell/celleb_pci.c b/arch/powerpc/platforms/cell/celleb_pci.c index 404d1fc..c19b783 100644 --- a/arch/powerpc/platforms/cell/celleb_pci.c +++ b/arch/powerpc/platforms/cell/celleb_pci.c @@ -41,7 +41,6 @@ #include #include -#include "io-workarounds.h" #include "celleb_pci.h" #define MAX_PCI_DEVICES 32 diff --git a/arch/powerpc/platforms/cell/celleb_pci.h b/arch/powerpc/platforms/cell/celleb_pci.h index 4cba152..a801fcc 100644 --- a/arch/powerpc/platforms/cell/celleb_pci.h +++ b/arch/powerpc/platforms/cell/celleb_pci.h @@ -26,8 +26,9 @@ #include #include #include +#include -#include "io-workarounds.h" +struct iowa_bus; struct celleb_phb_spec { int (*setup)(struct device_node *, struct pci_controller *); diff --git a/arch/powerpc/platforms/cell/io-workarounds.c b/arch/powerpc/platforms/cell/io-workarounds.c deleted file mode 100644 index 5c1118e..0000000 --- a/arch/powerpc/platforms/cell/io-workarounds.c +++ /dev/null @@ -1,185 +0,0 @@ -/* - * Support PCI IO workaround - * - * Copyright (C) 2006 Benjamin Herrenschmidt - * IBM, Corp. - * (C) Copyright 2007-2008 TOSHIBA CORPORATION - * - * 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. - */ -#undef DEBUG - -#include - -#include -#include -#include -#include - -#include "io-workarounds.h" - -#define IOWA_MAX_BUS 8 - -static struct iowa_bus iowa_busses[IOWA_MAX_BUS]; -static unsigned int iowa_bus_count; - -static struct iowa_bus *iowa_pci_find(unsigned long vaddr, unsigned long paddr) -{ - int i, j; - struct resource *res; - unsigned long vstart, vend; - - for (i = 0; i < iowa_bus_count; i++) { - struct iowa_bus *bus = &iowa_busses[i]; - struct pci_controller *phb = bus->phb; - - if (vaddr) { - vstart = (unsigned long)phb->io_base_virt; - vend = vstart + phb->pci_io_size - 1; - if ((vaddr >= vstart) && (vaddr <= vend)) - return bus; - } - - if (paddr) - for (j = 0; j < 3; j++) { - res = &phb->mem_resources[j]; - if (paddr >= res->start && paddr <= res->end) - return bus; - } - } - - return NULL; -} - -struct iowa_bus *iowa_mem_find_bus(const PCI_IO_ADDR addr) -{ - struct iowa_bus *bus; - int token; - - token = PCI_GET_ADDR_TOKEN(addr); - - if (token && token <= iowa_bus_count) - bus = &iowa_busses[token - 1]; - else { - unsigned long vaddr, paddr; - pte_t *ptep; - - vaddr = (unsigned long)PCI_FIX_ADDR(addr); - if (vaddr < PHB_IO_BASE || vaddr >= PHB_IO_END) - return NULL; - - ptep = find_linux_pte(init_mm.pgd, vaddr); - if (ptep == NULL) - paddr = 0; - else - paddr = pte_pfn(*ptep) << PAGE_SHIFT; - bus = iowa_pci_find(vaddr, paddr); - - if (bus == NULL) - return NULL; - } - - return bus; -} - -struct iowa_bus *iowa_pio_find_bus(unsigned long port) -{ - unsigned long vaddr = (unsigned long)pci_io_base + port; - return iowa_pci_find(vaddr, 0); -} - - -#define DEF_PCI_AC_RET(name, ret, at, al, space, aa) \ -static ret iowa_##name at \ -{ \ - struct iowa_bus *bus; \ - bus = iowa_##space##_find_bus(aa); \ - if (bus && bus->ops && bus->ops->name) \ - return bus->ops->name al; \ - return __do_##name al; \ -} - -#define DEF_PCI_AC_NORET(name, at, al, space, aa) \ -static void iowa_##name at \ -{ \ - struct iowa_bus *bus; \ - bus = iowa_##space##_find_bus(aa); \ - if (bus && bus->ops && bus->ops->name) { \ - bus->ops->name al; \ - return; \ - } \ - __do_##name al; \ -} - -#include - -#undef DEF_PCI_AC_RET -#undef DEF_PCI_AC_NORET - -static const struct ppc_pci_io __devinitconst iowa_pci_io = { - -#define DEF_PCI_AC_RET(name, ret, at, al, space, aa) .name = iowa_##name, -#define DEF_PCI_AC_NORET(name, at, al, space, aa) .name = iowa_##name, - -#include - -#undef DEF_PCI_AC_RET -#undef DEF_PCI_AC_NORET - -}; - -static void __iomem *iowa_ioremap(phys_addr_t addr, unsigned long size, - unsigned long flags, void *caller) -{ - struct iowa_bus *bus; - void __iomem *res = __ioremap_caller(addr, size, flags, caller); - int busno; - - bus = iowa_pci_find(0, (unsigned long)addr); - if (bus != NULL) { - busno = bus - iowa_busses; - PCI_SET_ADDR_TOKEN(res, busno + 1); - } - return res; -} - -/* Regist new bus to support workaround */ -void __devinit iowa_register_bus(struct pci_controller *phb, - struct ppc_pci_io *ops, - int (*initfunc)(struct iowa_bus *, void *), void *data) -{ - struct iowa_bus *bus; - struct device_node *np = phb->dn; - - if (iowa_bus_count >= IOWA_MAX_BUS) { - pr_err("IOWA:Too many pci bridges, " - "workarounds disabled for %s\n", np->full_name); - return; - } - - bus = &iowa_busses[iowa_bus_count]; - bus->phb = phb; - bus->ops = ops; - - if (initfunc) - if ((*initfunc)(bus, data)) - return; - - iowa_bus_count++; - - pr_debug("IOWA:[%d]Add bus, %s.\n", iowa_bus_count-1, np->full_name); -} - -/* enable IO workaround */ -void __devinit io_workaround_init(void) -{ - static int io_workaround_inited; - - if (io_workaround_inited) - return; - ppc_pci_io = iowa_pci_io; - ppc_md.ioremap = iowa_ioremap; - io_workaround_inited = 1; -} diff --git a/arch/powerpc/platforms/cell/io-workarounds.h b/arch/powerpc/platforms/cell/io-workarounds.h deleted file mode 100644 index 6efc778..0000000 --- a/arch/powerpc/platforms/cell/io-workarounds.h +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Support PCI IO workaround - * - * (C) Copyright 2007-2008 TOSHIBA CORPORATION - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ - -#ifndef _IO_WORKAROUNDS_H -#define _IO_WORKAROUNDS_H - -#include -#include - -/* Bus info */ -struct iowa_bus { - struct pci_controller *phb; - struct ppc_pci_io *ops; - void *private; -}; - -void __devinit io_workaround_init(void); -void __devinit iowa_register_bus(struct pci_controller *, struct ppc_pci_io *, - int (*)(struct iowa_bus *, void *), void *); -struct iowa_bus *iowa_mem_find_bus(const PCI_IO_ADDR); -struct iowa_bus *iowa_pio_find_bus(unsigned long); - -extern struct ppc_pci_io spiderpci_ops; -extern int spiderpci_iowa_init(struct iowa_bus *, void *); - -#define SPIDER_PCI_REG_BASE 0xd000 -#define SPIDER_PCI_REG_SIZE 0x1000 -#define SPIDER_PCI_VCI_CNTL_STAT 0x0110 -#define SPIDER_PCI_DUMMY_READ 0x0810 -#define SPIDER_PCI_DUMMY_READ_BASE 0x0814 - -#endif /* _IO_WORKAROUNDS_H */ diff --git a/arch/powerpc/platforms/cell/qpace_setup.c b/arch/powerpc/platforms/cell/qpace_setup.c index d31c594..51e2901 100644 --- a/arch/powerpc/platforms/cell/qpace_setup.c +++ b/arch/powerpc/platforms/cell/qpace_setup.c @@ -42,7 +42,6 @@ #include "interrupt.h" #include "pervasive.h" #include "ras.h" -#include "io-workarounds.h" static void qpace_show_cpuinfo(struct seq_file *m) { diff --git a/arch/powerpc/platforms/cell/setup.c b/arch/powerpc/platforms/cell/setup.c index fd57bfe..af7b13c 100644 --- a/arch/powerpc/platforms/cell/setup.c +++ b/arch/powerpc/platforms/cell/setup.c @@ -51,11 +51,11 @@ #include #include #include +#include #include "interrupt.h" #include "pervasive.h" #include "ras.h" -#include "io-workarounds.h" #ifdef DEBUG #define DBG(fmt...) udbg_printf(fmt) diff --git a/arch/powerpc/platforms/cell/spider-pci.c b/arch/powerpc/platforms/cell/spider-pci.c index ca7731c..f1f7878 100644 --- a/arch/powerpc/platforms/cell/spider-pci.c +++ b/arch/powerpc/platforms/cell/spider-pci.c @@ -27,8 +27,7 @@ #include #include - -#include "io-workarounds.h" +#include #define SPIDER_PCI_DISABLE_PREFETCH -- cgit v0.10.2 From d1109b7529f362c06c47140ae09dbd2b853ffddc Mon Sep 17 00:00:00 2001 From: Michael Ellerman Date: Mon, 11 Apr 2011 21:25:02 +0000 Subject: powerpc/pci: Make IO workarounds init implicit when first bus is registered Signed-off-by: Benjamin Herrenschmidt Signed-off-by: Michael Ellerman Signed-off-by: Benjamin Herrenschmidt diff --git a/arch/powerpc/include/asm/io-workarounds.h b/arch/powerpc/include/asm/io-workarounds.h index 6efc778..fbae492 100644 --- a/arch/powerpc/include/asm/io-workarounds.h +++ b/arch/powerpc/include/asm/io-workarounds.h @@ -31,7 +31,6 @@ struct iowa_bus { void *private; }; -void __devinit io_workaround_init(void); void __devinit iowa_register_bus(struct pci_controller *, struct ppc_pci_io *, int (*)(struct iowa_bus *, void *), void *); struct iowa_bus *iowa_mem_find_bus(const PCI_IO_ADDR); diff --git a/arch/powerpc/kernel/io-workarounds.c b/arch/powerpc/kernel/io-workarounds.c index 7e58457..d36515ea 100644 --- a/arch/powerpc/kernel/io-workarounds.c +++ b/arch/powerpc/kernel/io-workarounds.c @@ -144,7 +144,19 @@ static void __iomem *iowa_ioremap(phys_addr_t addr, unsigned long size, return res; } -/* Regist new bus to support workaround */ +/* Enable IO workaround */ +static void __devinit io_workaround_init(void) +{ + static int io_workaround_inited; + + if (io_workaround_inited) + return; + ppc_pci_io = iowa_pci_io; + ppc_md.ioremap = iowa_ioremap; + io_workaround_inited = 1; +} + +/* Register new bus to support workaround */ void __devinit iowa_register_bus(struct pci_controller *phb, struct ppc_pci_io *ops, int (*initfunc)(struct iowa_bus *, void *), void *data) @@ -152,6 +164,8 @@ void __devinit iowa_register_bus(struct pci_controller *phb, struct iowa_bus *bus; struct device_node *np = phb->dn; + io_workaround_init(); + if (iowa_bus_count >= IOWA_MAX_BUS) { pr_err("IOWA:Too many pci bridges, " "workarounds disabled for %s\n", np->full_name); @@ -171,14 +185,3 @@ void __devinit iowa_register_bus(struct pci_controller *phb, pr_debug("IOWA:[%d]Add bus, %s.\n", iowa_bus_count-1, np->full_name); } -/* enable IO workaround */ -void __devinit io_workaround_init(void) -{ - static int io_workaround_inited; - - if (io_workaround_inited) - return; - ppc_pci_io = iowa_pci_io; - ppc_md.ioremap = iowa_ioremap; - io_workaround_inited = 1; -} diff --git a/arch/powerpc/platforms/cell/celleb_pci.c b/arch/powerpc/platforms/cell/celleb_pci.c index c19b783..2904b0a 100644 --- a/arch/powerpc/platforms/cell/celleb_pci.c +++ b/arch/powerpc/platforms/cell/celleb_pci.c @@ -468,18 +468,6 @@ static struct of_device_id celleb_phb_match[] __initdata = { }, }; -static int __init celleb_io_workaround_init(struct pci_controller *phb, - struct celleb_phb_spec *phb_spec) -{ - if (phb_spec->ops) { - iowa_register_bus(phb, phb_spec->ops, phb_spec->iowa_init, - phb_spec->iowa_data); - io_workaround_init(); - } - - return 0; -} - int __init celleb_setup_phb(struct pci_controller *phb) { struct device_node *dev = phb->dn; @@ -499,7 +487,11 @@ int __init celleb_setup_phb(struct pci_controller *phb) if (rc) return 1; - return celleb_io_workaround_init(phb, phb_spec); + if (phb_spec->ops) + iowa_register_bus(phb, phb_spec->ops, + phb_spec->iowa_init, + phb_spec->iowa_data); + return 0; } int celleb_pci_probe_mode(struct pci_bus *bus) diff --git a/arch/powerpc/platforms/cell/setup.c b/arch/powerpc/platforms/cell/setup.c index af7b13c..c73cf4c 100644 --- a/arch/powerpc/platforms/cell/setup.c +++ b/arch/powerpc/platforms/cell/setup.c @@ -136,8 +136,6 @@ static int __devinit cell_setup_phb(struct pci_controller *phb) iowa_register_bus(phb, &spiderpci_ops, &spiderpci_iowa_init, (void *)SPIDER_PCI_REG_BASE); - io_workaround_init(); - return 0; } -- cgit v0.10.2 From 69b123684b50040b0926eed1e02795dac8cb9587 Mon Sep 17 00:00:00 2001 From: Michael Ellerman Date: Mon, 11 Apr 2011 21:25:02 +0000 Subject: powerpc/pci: Properly initialize IO workaround "private" Even when no initfunc is provided. Signed-off-by: Benjamin Herrenschmidt Signed-off-by: Michael Ellerman Signed-off-by: Benjamin Herrenschmidt diff --git a/arch/powerpc/kernel/io-workarounds.c b/arch/powerpc/kernel/io-workarounds.c index d36515ea..ffafaea 100644 --- a/arch/powerpc/kernel/io-workarounds.c +++ b/arch/powerpc/kernel/io-workarounds.c @@ -175,6 +175,7 @@ void __devinit iowa_register_bus(struct pci_controller *phb, bus = &iowa_busses[iowa_bus_count]; bus->phb = phb; bus->ops = ops; + bus->private = data; if (initfunc) if ((*initfunc)(bus, data)) -- cgit v0.10.2 From e70606eb9beb683ce3991936267deab64ab56d95 Mon Sep 17 00:00:00 2001 From: Michael Ellerman Date: Sun, 10 Apr 2011 20:42:05 +0000 Subject: powerpc/numa: Look for ibm, associativity-reference-points at the root If we don't find ibm,associativity-reference-points as a child of /rtas, look for it at the root of the tree instead. We use this on Book3E where we have no RTAS but still use the sPAPR conventions for NUMA. Signed-off-by: Michael Ellerman Signed-off-by: Benjamin Herrenschmidt diff --git a/arch/powerpc/mm/numa.c b/arch/powerpc/mm/numa.c index 5ec1dad..e49b799 100644 --- a/arch/powerpc/mm/numa.c +++ b/arch/powerpc/mm/numa.c @@ -311,14 +311,13 @@ EXPORT_SYMBOL_GPL(of_node_to_nid); static int __init find_min_common_depth(void) { int depth; - struct device_node *rtas_root; struct device_node *chosen; + struct device_node *root; const char *vec5; - rtas_root = of_find_node_by_path("/rtas"); - - if (!rtas_root) - return -1; + root = of_find_node_by_path("/rtas"); + if (!root) + root = of_find_node_by_path("/"); /* * This property is a set of 32-bit integers, each representing @@ -332,7 +331,7 @@ static int __init find_min_common_depth(void) * NUMA boundary and the following are progressively less significant * boundaries. There can be more than one level of NUMA. */ - distance_ref_points = of_get_property(rtas_root, + distance_ref_points = of_get_property(root, "ibm,associativity-reference-points", &distance_ref_points_depth); @@ -376,11 +375,11 @@ static int __init find_min_common_depth(void) distance_ref_points_depth = MAX_DISTANCE_REF_POINTS; } - of_node_put(rtas_root); + of_node_put(root); return depth; err: - of_node_put(rtas_root); + of_node_put(root); return -1; } -- cgit v0.10.2 From 73706c3283d755d3725c6a48a18e677a15ced8be Mon Sep 17 00:00:00 2001 From: Michael Ellerman Date: Sun, 10 Apr 2011 20:26:15 +0000 Subject: powerpc/irq: Dump chip data pointer in virq_mapping This can be useful for differentiating interrupts on the same host but with different chip data. Signed-off-by: Michael Ellerman Signed-off-by: Benjamin Herrenschmidt diff --git a/arch/powerpc/kernel/irq.c b/arch/powerpc/kernel/irq.c index ea09512..4f5d6e7 100644 --- a/arch/powerpc/kernel/irq.c +++ b/arch/powerpc/kernel/irq.c @@ -1086,10 +1086,11 @@ static int virq_debug_show(struct seq_file *m, void *private) struct irq_desc *desc; const char *p; static const char none[] = "none"; + void *data; int i; - seq_printf(m, "%-5s %-7s %-15s %s\n", "virq", "hwirq", - "chip name", "host name"); + seq_printf(m, "%-5s %-7s %-15s %-18s %s\n", "virq", "hwirq", + "chip name", "chip data", "host name"); for (i = 1; i < nr_irqs; i++) { desc = irq_to_desc(i); @@ -1111,6 +1112,9 @@ static int virq_debug_show(struct seq_file *m, void *private) p = none; seq_printf(m, "%-15s ", p); + data = irq_desc_get_chip_data(desc); + seq_printf(m, "0x%16p ", data); + if (irq_map[i].host && irq_map[i].host->of_node) p = irq_map[i].host->of_node->full_name; else -- cgit v0.10.2 From b618d2f043506e45b1d72b48a4ff7cb5b1a7011c Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Sat, 9 Apr 2011 22:59:07 +0000 Subject: powerpc/ps3: Update debug message for irq_set_chip_data() commit ec775d0e70eb6b7116406b3441cb8501c2849dd2 ("powerpc: Convert to new irq_* function names") changed a call from set_irq_chip_data() to irq_set_chip_data(), but forgot to update the corresponding debug message Signed-off-by: Geert Uytterhoeven Acked-by: Geoff Levand Signed-off-by: Benjamin Herrenschmidt diff --git a/arch/powerpc/platforms/ps3/interrupt.c b/arch/powerpc/platforms/ps3/interrupt.c index f2f6413..523bd0d 100644 --- a/arch/powerpc/platforms/ps3/interrupt.c +++ b/arch/powerpc/platforms/ps3/interrupt.c @@ -197,7 +197,7 @@ static int ps3_virq_setup(enum ps3_cpu_binding cpu, unsigned long outlet, result = irq_set_chip_data(*virq, pd); if (result) { - pr_debug("%s:%d: set_irq_chip_data failed\n", + pr_debug("%s:%d: irq_set_chip_data failed\n", __func__, __LINE__); goto fail_set; } -- cgit v0.10.2 From 0407a31429500e7e56da33a326ca7cf35c2c9d65 Mon Sep 17 00:00:00 2001 From: Wanlong Gao Date: Sat, 9 Apr 2011 08:09:46 +0000 Subject: powerpc: Fix build warning of the defconfigs BT_L2CAP and BT_SCO have changed to bool . Value 'm' has invalid . Signed-off-by: Wanlong Gao Signed-off-by: Benjamin Herrenschmidt diff --git a/arch/powerpc/configs/c2k_defconfig b/arch/powerpc/configs/c2k_defconfig index f9e6a3e..2a84fd7 100644 --- a/arch/powerpc/configs/c2k_defconfig +++ b/arch/powerpc/configs/c2k_defconfig @@ -132,8 +132,8 @@ CONFIG_NET_CLS_RSVP=m CONFIG_NET_CLS_RSVP6=m CONFIG_NET_CLS_IND=y CONFIG_BT=m -CONFIG_BT_L2CAP=m -CONFIG_BT_SCO=m +CONFIG_BT_L2CAP=y +CONFIG_BT_SCO=y CONFIG_BT_RFCOMM=m CONFIG_BT_RFCOMM_TTY=y CONFIG_BT_BNEP=m diff --git a/arch/powerpc/configs/pmac32_defconfig b/arch/powerpc/configs/pmac32_defconfig index ac4fc41..f8b394a 100644 --- a/arch/powerpc/configs/pmac32_defconfig +++ b/arch/powerpc/configs/pmac32_defconfig @@ -112,8 +112,8 @@ CONFIG_IRDA_CACHE_LAST_LSAP=y CONFIG_IRDA_FAST_RR=y CONFIG_IRTTY_SIR=m CONFIG_BT=m -CONFIG_BT_L2CAP=m -CONFIG_BT_SCO=m +CONFIG_BT_L2CAP=y +CONFIG_BT_SCO=y CONFIG_BT_RFCOMM=m CONFIG_BT_RFCOMM_TTY=y CONFIG_BT_BNEP=m diff --git a/arch/powerpc/configs/ppc6xx_defconfig b/arch/powerpc/configs/ppc6xx_defconfig index 0a10fb0..2142089 100644 --- a/arch/powerpc/configs/ppc6xx_defconfig +++ b/arch/powerpc/configs/ppc6xx_defconfig @@ -351,8 +351,8 @@ CONFIG_VLSI_FIR=m CONFIG_VIA_FIR=m CONFIG_MCS_FIR=m CONFIG_BT=m -CONFIG_BT_L2CAP=m -CONFIG_BT_SCO=m +CONFIG_BT_L2CAP=y +CONFIG_BT_SCO=y CONFIG_BT_RFCOMM=m CONFIG_BT_RFCOMM_TTY=y CONFIG_BT_BNEP=m diff --git a/arch/powerpc/configs/ps3_defconfig b/arch/powerpc/configs/ps3_defconfig index caba919..6472322 100644 --- a/arch/powerpc/configs/ps3_defconfig +++ b/arch/powerpc/configs/ps3_defconfig @@ -52,8 +52,8 @@ CONFIG_IP_PNP_DHCP=y # CONFIG_INET_DIAG is not set CONFIG_IPV6=y CONFIG_BT=m -CONFIG_BT_L2CAP=m -CONFIG_BT_SCO=m +CONFIG_BT_L2CAP=y +CONFIG_BT_SCO=y CONFIG_BT_RFCOMM=m CONFIG_BT_RFCOMM_TTY=y CONFIG_BT_BNEP=m -- cgit v0.10.2 From 9d4a2925c290a053bb279e75e7a649069fdcaf6b Mon Sep 17 00:00:00 2001 From: Michael Ellerman Date: Thu, 7 Apr 2011 21:56:02 +0000 Subject: powerpc: Add MSR_64BIT The MSR bit which indicates 64-bit-ness is different between server and booke, so add a #define which gives you the right mask regardless. Signed-off-by: Michael Ellerman Signed-off-by: Benjamin Herrenschmidt diff --git a/arch/powerpc/include/asm/reg.h b/arch/powerpc/include/asm/reg.h index 76d7d5f..1f9ac12 100644 --- a/arch/powerpc/include/asm/reg.h +++ b/arch/powerpc/include/asm/reg.h @@ -99,17 +99,23 @@ #define MSR_LE __MASK(MSR_LE_LG) /* Little Endian */ #if defined(CONFIG_PPC_BOOK3S_64) +#define MSR_64BIT MSR_SF + /* Server variant */ #define MSR_ MSR_ME | MSR_RI | MSR_IR | MSR_DR | MSR_ISF |MSR_HV -#define MSR_KERNEL MSR_ | MSR_SF +#define MSR_KERNEL MSR_ | MSR_64BIT #define MSR_USER32 MSR_ | MSR_PR | MSR_EE -#define MSR_USER64 MSR_USER32 | MSR_SF +#define MSR_USER64 MSR_USER32 | MSR_64BIT #elif defined(CONFIG_PPC_BOOK3S_32) || defined(CONFIG_8xx) /* Default MSR for kernel mode. */ #define MSR_KERNEL (MSR_ME|MSR_RI|MSR_IR|MSR_DR) #define MSR_USER (MSR_KERNEL|MSR_PR|MSR_EE) #endif +#ifndef MSR_64BIT +#define MSR_64BIT 0 +#endif + /* Floating Point Status and Control Register (FPSCR) Fields */ #define FPSCR_FX 0x80000000 /* FPU exception summary */ #define FPSCR_FEX 0x40000000 /* FPU enabled exception summary */ diff --git a/arch/powerpc/include/asm/reg_booke.h b/arch/powerpc/include/asm/reg_booke.h index b316794..817bd1a 100644 --- a/arch/powerpc/include/asm/reg_booke.h +++ b/arch/powerpc/include/asm/reg_booke.h @@ -27,10 +27,12 @@ #define MSR_CM (1<<31) /* Computation Mode (0=32-bit, 1=64-bit) */ #if defined(CONFIG_PPC_BOOK3E_64) +#define MSR_64BIT MSR_CM + #define MSR_ MSR_ME | MSR_CE -#define MSR_KERNEL MSR_ | MSR_CM +#define MSR_KERNEL MSR_ | MSR_64BIT #define MSR_USER32 MSR_ | MSR_PR | MSR_EE | MSR_DE -#define MSR_USER64 MSR_USER32 | MSR_CM | MSR_DE +#define MSR_USER64 MSR_USER32 | MSR_64BIT #elif defined (CONFIG_40x) #define MSR_KERNEL (MSR_ME|MSR_RI|MSR_IR|MSR_DR|MSR_CE) #define MSR_USER (MSR_KERNEL|MSR_PR|MSR_EE) -- cgit v0.10.2 From 9f0b079320ad1cc71ad7ea4e0ed0b64cd72bbd6d Mon Sep 17 00:00:00 2001 From: Michael Ellerman Date: Thu, 7 Apr 2011 21:56:03 +0000 Subject: powerpc: Use MSR_64BIT in places Use the new MSR_64BIT in a few places. Some of these are already ifdef'ed for BOOKE vs BOOKS, but it's still clearer, MSR_SF does not immediately parse as "MSR bit for 64bit". Signed-off-by: Michael Ellerman Signed-off-by: Benjamin Herrenschmidt diff --git a/arch/powerpc/kernel/head_64.S b/arch/powerpc/kernel/head_64.S index 6d17c37..73d6e9a 100644 --- a/arch/powerpc/kernel/head_64.S +++ b/arch/powerpc/kernel/head_64.S @@ -655,7 +655,7 @@ _GLOBAL(enable_64b_mode) oris r11,r11,0x8000 /* CM bit set, we'll set ICM later */ mtmsr r11 #else /* CONFIG_PPC_BOOK3E */ - li r12,(MSR_SF | MSR_ISF)@highest + li r12,(MSR_64BIT | MSR_ISF)@highest sldi r12,r12,48 or r11,r11,r12 mtmsrd r11 diff --git a/arch/powerpc/kernel/signal_64.c b/arch/powerpc/kernel/signal_64.c index 27c4a45..da989ff 100644 --- a/arch/powerpc/kernel/signal_64.c +++ b/arch/powerpc/kernel/signal_64.c @@ -381,7 +381,7 @@ badframe: regs, uc, &uc->uc_mcontext); #endif if (show_unhandled_signals && printk_ratelimit()) - printk(regs->msr & MSR_SF ? fmt64 : fmt32, + printk(regs->msr & MSR_64BIT ? fmt64 : fmt32, current->comm, current->pid, "rt_sigreturn", (long)uc, regs->nip, regs->link); @@ -469,7 +469,7 @@ badframe: regs, frame, newsp); #endif if (show_unhandled_signals && printk_ratelimit()) - printk(regs->msr & MSR_SF ? fmt64 : fmt32, + printk(regs->msr & MSR_64BIT ? fmt64 : fmt32, current->comm, current->pid, "setup_rt_frame", (long)frame, regs->nip, regs->link); diff --git a/arch/powerpc/kernel/traps.c b/arch/powerpc/kernel/traps.c index cb71cf2..4a6a109 100644 --- a/arch/powerpc/kernel/traps.c +++ b/arch/powerpc/kernel/traps.c @@ -199,7 +199,7 @@ void _exception(int signr, struct pt_regs *regs, int code, unsigned long addr) } else if (show_unhandled_signals && unhandled_signal(current, signr) && printk_ratelimit()) { - printk(regs->msr & MSR_SF ? fmt64 : fmt32, + printk(regs->msr & MSR_64BIT ? fmt64 : fmt32, current->comm, current->pid, signr, addr, regs->nip, regs->link, code); } diff --git a/arch/powerpc/xmon/xmon.c b/arch/powerpc/xmon/xmon.c index 33794c1..ef9756ee 100644 --- a/arch/powerpc/xmon/xmon.c +++ b/arch/powerpc/xmon/xmon.c @@ -399,7 +399,7 @@ static int xmon_core(struct pt_regs *regs, int fromipi) cpu_set(cpu, cpus_in_xmon); bp = NULL; - if ((regs->msr & (MSR_IR|MSR_PR|MSR_SF)) == (MSR_IR|MSR_SF)) + if ((regs->msr & (MSR_IR|MSR_PR|MSR_64BIT)) == (MSR_IR|MSR_64BIT)) bp = at_breakpoint(regs->nip); if (bp || unrecoverable_excp(regs)) fromipi = 0; @@ -529,7 +529,7 @@ static int xmon_core(struct pt_regs *regs, int fromipi) } } #else - if ((regs->msr & (MSR_IR|MSR_PR|MSR_SF)) == (MSR_IR|MSR_SF)) { + if ((regs->msr & (MSR_IR|MSR_PR|MSR_64BIT)) == (MSR_IR|MSR_64BIT)) { bp = at_breakpoint(regs->nip); if (bp != NULL) { int stepped = emulate_step(regs, bp->instr[0]); @@ -578,7 +578,7 @@ static int xmon_bpt(struct pt_regs *regs) struct bpt *bp; unsigned long offset; - if ((regs->msr & (MSR_IR|MSR_PR|MSR_SF)) != (MSR_IR|MSR_SF)) + if ((regs->msr & (MSR_IR|MSR_PR|MSR_64BIT)) != (MSR_IR|MSR_64BIT)) return 0; /* Are we at the trap at bp->instr[1] for some bp? */ @@ -609,7 +609,7 @@ static int xmon_sstep(struct pt_regs *regs) static int xmon_dabr_match(struct pt_regs *regs) { - if ((regs->msr & (MSR_IR|MSR_PR|MSR_SF)) != (MSR_IR|MSR_SF)) + if ((regs->msr & (MSR_IR|MSR_PR|MSR_64BIT)) != (MSR_IR|MSR_64BIT)) return 0; if (dabr.enabled == 0) return 0; @@ -619,7 +619,7 @@ static int xmon_dabr_match(struct pt_regs *regs) static int xmon_iabr_match(struct pt_regs *regs) { - if ((regs->msr & (MSR_IR|MSR_PR|MSR_SF)) != (MSR_IR|MSR_SF)) + if ((regs->msr & (MSR_IR|MSR_PR|MSR_64BIT)) != (MSR_IR|MSR_64BIT)) return 0; if (iabr == NULL) return 0; @@ -644,7 +644,7 @@ static int xmon_fault_handler(struct pt_regs *regs) if (in_xmon && catch_memory_errors) handle_fault(regs); /* doesn't return */ - if ((regs->msr & (MSR_IR|MSR_PR|MSR_SF)) == (MSR_IR|MSR_SF)) { + if ((regs->msr & (MSR_IR|MSR_PR|MSR_64BIT)) == (MSR_IR|MSR_64BIT)) { bp = in_breakpoint_table(regs->nip, &offset); if (bp != NULL) { regs->nip = bp->address + offset; @@ -929,7 +929,7 @@ static int do_step(struct pt_regs *regs) int stepped; /* check we are in 64-bit kernel mode, translation enabled */ - if ((regs->msr & (MSR_SF|MSR_PR|MSR_IR)) == (MSR_SF|MSR_IR)) { + if ((regs->msr & (MSR_64BIT|MSR_PR|MSR_IR)) == (MSR_64BIT|MSR_IR)) { if (mread(regs->nip, &instr, 4) == 4) { stepped = emulate_step(regs, instr); if (stepped < 0) { -- cgit v0.10.2 From b91e136cdf88e19e998dbf4631ead266de4b80b5 Mon Sep 17 00:00:00 2001 From: Michael Ellerman Date: Thu, 7 Apr 2011 21:56:04 +0000 Subject: powerpc: Use MSR_64BIT in sstep.c, fix kprobes on BOOK3E We check MSR_SF a lot in sstep.c, to decide if we need to emulate the truncation of values when running in 32-bit mode. Factor out that code into a helper, and convert it and the other uses to use MSR_64BIT. This fixes a bug on BOOK3E where kprobes would end up returning to a 32-bit address, because regs->nip was truncated, because (msr & MSR_SF) was false. Signed-off-by: Michael Ellerman Signed-off-by: Benjamin Herrenschmidt diff --git a/arch/powerpc/lib/sstep.c b/arch/powerpc/lib/sstep.c index ae5189a..0e5e540 100644 --- a/arch/powerpc/lib/sstep.c +++ b/arch/powerpc/lib/sstep.c @@ -45,6 +45,18 @@ extern int do_stxvd2x(int rn, unsigned long ea); #endif /* + * Emulate the truncation of 64 bit values in 32-bit mode. + */ +static unsigned long truncate_if_32bit(unsigned long msr, unsigned long val) +{ +#ifdef __powerpc64__ + if ((msr & MSR_64BIT) == 0) + val &= 0xffffffffUL; +#endif + return val; +} + +/* * Determine whether a conditional branch instruction would branch. */ static int __kprobes branch_taken(unsigned int instr, struct pt_regs *regs) @@ -90,11 +102,8 @@ static unsigned long __kprobes dform_ea(unsigned int instr, struct pt_regs *regs if (instr & 0x04000000) /* update forms */ regs->gpr[ra] = ea; } -#ifdef __powerpc64__ - if (!(regs->msr & MSR_SF)) - ea &= 0xffffffffUL; -#endif - return ea; + + return truncate_if_32bit(regs->msr, ea); } #ifdef __powerpc64__ @@ -113,9 +122,8 @@ static unsigned long __kprobes dsform_ea(unsigned int instr, struct pt_regs *reg if ((instr & 3) == 1) /* update forms */ regs->gpr[ra] = ea; } - if (!(regs->msr & MSR_SF)) - ea &= 0xffffffffUL; - return ea; + + return truncate_if_32bit(regs->msr, ea); } #endif /* __powerpc64 */ @@ -136,11 +144,8 @@ static unsigned long __kprobes xform_ea(unsigned int instr, struct pt_regs *regs if (do_update) /* update forms */ regs->gpr[ra] = ea; } -#ifdef __powerpc64__ - if (!(regs->msr & MSR_SF)) - ea &= 0xffffffffUL; -#endif - return ea; + + return truncate_if_32bit(regs->msr, ea); } /* @@ -466,7 +471,7 @@ static void __kprobes set_cr0(struct pt_regs *regs, int rd) regs->ccr = (regs->ccr & 0x0fffffff) | ((regs->xer >> 3) & 0x10000000); #ifdef __powerpc64__ - if (!(regs->msr & MSR_SF)) + if (!(regs->msr & MSR_64BIT)) val = (int) val; #endif if (val < 0) @@ -487,7 +492,7 @@ static void __kprobes add_with_carry(struct pt_regs *regs, int rd, ++val; regs->gpr[rd] = val; #ifdef __powerpc64__ - if (!(regs->msr & MSR_SF)) { + if (!(regs->msr & MSR_64BIT)) { val = (unsigned int) val; val1 = (unsigned int) val1; } @@ -570,8 +575,7 @@ int __kprobes emulate_step(struct pt_regs *regs, unsigned int instr) if ((instr & 2) == 0) imm += regs->nip; regs->nip += 4; - if ((regs->msr & MSR_SF) == 0) - regs->nip &= 0xffffffffUL; + regs->nip = truncate_if_32bit(regs->msr, regs->nip); if (instr & 1) regs->link = regs->nip; if (branch_taken(instr, regs)) @@ -604,13 +608,9 @@ int __kprobes emulate_step(struct pt_regs *regs, unsigned int instr) imm -= 0x04000000; if ((instr & 2) == 0) imm += regs->nip; - if (instr & 1) { - regs->link = regs->nip + 4; - if ((regs->msr & MSR_SF) == 0) - regs->link &= 0xffffffffUL; - } - if ((regs->msr & MSR_SF) == 0) - imm &= 0xffffffffUL; + if (instr & 1) + regs->link = truncate_if_32bit(regs->msr, regs->nip + 4); + imm = truncate_if_32bit(regs->msr, imm); regs->nip = imm; return 1; case 19: @@ -618,11 +618,8 @@ int __kprobes emulate_step(struct pt_regs *regs, unsigned int instr) case 16: /* bclr */ case 528: /* bcctr */ imm = (instr & 0x400)? regs->ctr: regs->link; - regs->nip += 4; - if ((regs->msr & MSR_SF) == 0) { - regs->nip &= 0xffffffffUL; - imm &= 0xffffffffUL; - } + regs->nip = truncate_if_32bit(regs->msr, regs->nip + 4); + imm = truncate_if_32bit(regs->msr, imm); if (instr & 1) regs->link = regs->nip; if (branch_taken(instr, regs)) @@ -1616,11 +1613,7 @@ int __kprobes emulate_step(struct pt_regs *regs, unsigned int instr) return 0; /* invoke DSI if -EFAULT? */ } instr_done: - regs->nip += 4; -#ifdef __powerpc64__ - if ((regs->msr & MSR_SF) == 0) - regs->nip &= 0xffffffffUL; -#endif + regs->nip = truncate_if_32bit(regs->msr, regs->nip + 4); return 1; logical_done: -- cgit v0.10.2 From a7b8ad405862fb10e496ce839d423dfc94ac821b Mon Sep 17 00:00:00 2001 From: Michael Ellerman Date: Thu, 7 Apr 2011 21:22:23 +0000 Subject: powerpc/book3e: Fix extlb size The calculation of the size for the exception save area of the TLB miss handler is wrong, luckily it's too big not too small. Rework it to make it a bit clearer, and also correct. We want 3 save areas, each EX_TLB_SIZE _bytes_. Signed-off-by: Michael Ellerman Acked-by: Kumar Gala Signed-off-by: Benjamin Herrenschmidt diff --git a/arch/powerpc/include/asm/paca.h b/arch/powerpc/include/asm/paca.h index f6da4f5..65c13c4 100644 --- a/arch/powerpc/include/asm/paca.h +++ b/arch/powerpc/include/asm/paca.h @@ -106,7 +106,8 @@ struct paca_struct { pgd_t *pgd; /* Current PGD */ pgd_t *kernel_pgd; /* Kernel PGD */ u64 exgen[8] __attribute__((aligned(0x80))); - u64 extlb[EX_TLB_SIZE*3] __attribute__((aligned(0x80))); + /* We can have up to 3 levels of reentrancy in the TLB miss handler */ + u64 extlb[3][EX_TLB_SIZE / sizeof(u64)] __attribute__((aligned(0x80))); u64 exmc[8]; /* used for machine checks */ u64 excrit[8]; /* used for crit interrupts */ u64 exdbg[8]; /* used for debug interrupts */ -- cgit v0.10.2 From eca590f402332ab873d13f2d8d00fa0b91cfff36 Mon Sep 17 00:00:00 2001 From: Anton Blanchard Date: Thu, 7 Apr 2011 01:54:07 +0000 Subject: powerpc/rtas: Only sleep in rtas_busy_delay if we have useful work to do RTAS returns extended error codes as a hint of how long the OS might want to wait before retrying a call. If we have nothing else useful to do we may as well call back straight away. This was found when testing the new dynamic dma window feature. Firmware split the zeroing of the TCE table into 32k chunks but returned 9901 (which is a suggested wait of 10ms). All up this took about 10 minutes to complete since msleep is jiffies based and will round 10ms up to 20ms. With the patch below we take 3 seconds to complete the same test. The hint firmware is returning in the RTAS call should definitely be decreased, but even if we slept 1ms each iteration this would take 32s. Signed-off-by: Anton Blanchard Acked-by: Nishanth Aravamudan Signed-off-by: Benjamin Herrenschmidt diff --git a/arch/powerpc/kernel/rtas.c b/arch/powerpc/kernel/rtas.c index 2097f2b..f484466 100644 --- a/arch/powerpc/kernel/rtas.c +++ b/arch/powerpc/kernel/rtas.c @@ -494,7 +494,7 @@ unsigned int rtas_busy_delay(int status) might_sleep(); ms = rtas_busy_delay_time(status); - if (ms) + if (ms && need_resched()) msleep(ms); return ms; -- cgit v0.10.2 From 44ae3ab3358e962039c36ad4ae461ae9fb29596c Mon Sep 17 00:00:00 2001 From: Matt Evans Date: Wed, 6 Apr 2011 19:48:50 +0000 Subject: powerpc: Free up some CPU feature bits by moving out MMU-related features Some of the 64bit PPC CPU features are MMU-related, so this patch moves them to MMU_FTR_ bits. All cpu_has_feature()-style tests are moved to mmu_has_feature(), and seven feature bits are freed as a result. Signed-off-by: Matt Evans Signed-off-by: Benjamin Herrenschmidt diff --git a/arch/powerpc/include/asm/cputable.h b/arch/powerpc/include/asm/cputable.h index 2d71523..3db2476 100644 --- a/arch/powerpc/include/asm/cputable.h +++ b/arch/powerpc/include/asm/cputable.h @@ -178,23 +178,17 @@ extern const char *powerpc_base_platform; #define LONG_ASM_CONST(x) 0 #endif -#define CPU_FTR_SLB LONG_ASM_CONST(0x0000000100000000) -#define CPU_FTR_16M_PAGE LONG_ASM_CONST(0x0000000200000000) -#define CPU_FTR_TLBIEL LONG_ASM_CONST(0x0000000400000000) + #define CPU_FTR_HVMODE_206 LONG_ASM_CONST(0x0000000800000000) #define CPU_FTR_IABR LONG_ASM_CONST(0x0000002000000000) #define CPU_FTR_MMCRA LONG_ASM_CONST(0x0000004000000000) #define CPU_FTR_CTRL LONG_ASM_CONST(0x0000008000000000) #define CPU_FTR_SMT LONG_ASM_CONST(0x0000010000000000) -#define CPU_FTR_LOCKLESS_TLBIE LONG_ASM_CONST(0x0000040000000000) -#define CPU_FTR_CI_LARGE_PAGE LONG_ASM_CONST(0x0000100000000000) #define CPU_FTR_PAUSE_ZERO LONG_ASM_CONST(0x0000200000000000) #define CPU_FTR_PURR LONG_ASM_CONST(0x0000400000000000) #define CPU_FTR_CELL_TB_BUG LONG_ASM_CONST(0x0000800000000000) #define CPU_FTR_SPURR LONG_ASM_CONST(0x0001000000000000) #define CPU_FTR_DSCR LONG_ASM_CONST(0x0002000000000000) -#define CPU_FTR_1T_SEGMENT LONG_ASM_CONST(0x0004000000000000) -#define CPU_FTR_NO_SLBIE_B LONG_ASM_CONST(0x0008000000000000) #define CPU_FTR_VSX LONG_ASM_CONST(0x0010000000000000) #define CPU_FTR_SAO LONG_ASM_CONST(0x0020000000000000) #define CPU_FTR_CP_USE_DCBTZ LONG_ASM_CONST(0x0040000000000000) @@ -206,9 +200,10 @@ extern const char *powerpc_base_platform; #ifndef __ASSEMBLY__ -#define CPU_FTR_PPCAS_ARCH_V2 (CPU_FTR_SLB | \ - CPU_FTR_TLBIEL | CPU_FTR_NOEXECUTE | \ - CPU_FTR_NODSISRALIGN | CPU_FTR_16M_PAGE) +#define CPU_FTR_PPCAS_ARCH_V2 (CPU_FTR_NOEXECUTE | CPU_FTR_NODSISRALIGN) + +#define MMU_FTR_PPCAS_ARCH_V2 (MMU_FTR_SLB | MMU_FTR_TLBIEL | \ + MMU_FTR_16M_PAGE) /* We only set the altivec features if the kernel was compiled with altivec * support @@ -408,38 +403,34 @@ extern const char *powerpc_base_platform; #define CPU_FTRS_POWER5 (CPU_FTR_USE_TB | CPU_FTR_LWSYNC | \ CPU_FTR_PPCAS_ARCH_V2 | CPU_FTR_CTRL | \ CPU_FTR_MMCRA | CPU_FTR_SMT | \ - CPU_FTR_COHERENT_ICACHE | CPU_FTR_LOCKLESS_TLBIE | \ - CPU_FTR_PURR | CPU_FTR_STCX_CHECKS_ADDRESS | \ - CPU_FTR_POPCNTB) + CPU_FTR_COHERENT_ICACHE | CPU_FTR_PURR | \ + CPU_FTR_STCX_CHECKS_ADDRESS | CPU_FTR_POPCNTB) #define CPU_FTRS_POWER6 (CPU_FTR_USE_TB | CPU_FTR_LWSYNC | \ CPU_FTR_PPCAS_ARCH_V2 | CPU_FTR_CTRL | \ CPU_FTR_MMCRA | CPU_FTR_SMT | \ - CPU_FTR_COHERENT_ICACHE | CPU_FTR_LOCKLESS_TLBIE | \ + CPU_FTR_COHERENT_ICACHE | \ CPU_FTR_PURR | CPU_FTR_SPURR | CPU_FTR_REAL_LE | \ CPU_FTR_DSCR | CPU_FTR_UNALIGNED_LD_STD | \ CPU_FTR_STCX_CHECKS_ADDRESS | CPU_FTR_POPCNTB) #define CPU_FTRS_POWER7 (CPU_FTR_USE_TB | CPU_FTR_LWSYNC | \ CPU_FTR_PPCAS_ARCH_V2 | CPU_FTR_CTRL | CPU_FTR_HVMODE_206 |\ CPU_FTR_MMCRA | CPU_FTR_SMT | \ - CPU_FTR_COHERENT_ICACHE | CPU_FTR_LOCKLESS_TLBIE | \ + CPU_FTR_COHERENT_ICACHE | \ CPU_FTR_PURR | CPU_FTR_SPURR | CPU_FTR_REAL_LE | \ CPU_FTR_DSCR | CPU_FTR_SAO | CPU_FTR_ASYM_SMT | \ CPU_FTR_STCX_CHECKS_ADDRESS | CPU_FTR_POPCNTB | CPU_FTR_POPCNTD) #define CPU_FTRS_CELL (CPU_FTR_USE_TB | CPU_FTR_LWSYNC | \ CPU_FTR_PPCAS_ARCH_V2 | CPU_FTR_CTRL | \ CPU_FTR_ALTIVEC_COMP | CPU_FTR_MMCRA | CPU_FTR_SMT | \ - CPU_FTR_PAUSE_ZERO | CPU_FTR_CI_LARGE_PAGE | \ - CPU_FTR_CELL_TB_BUG | CPU_FTR_CP_USE_DCBTZ | \ + CPU_FTR_PAUSE_ZERO | CPU_FTR_CELL_TB_BUG | CPU_FTR_CP_USE_DCBTZ | \ CPU_FTR_UNALIGNED_LD_STD) #define CPU_FTRS_PA6T (CPU_FTR_USE_TB | CPU_FTR_LWSYNC | \ - CPU_FTR_PPCAS_ARCH_V2 | \ - CPU_FTR_ALTIVEC_COMP | CPU_FTR_CI_LARGE_PAGE | \ - CPU_FTR_PURR | CPU_FTR_REAL_LE | CPU_FTR_NO_SLBIE_B) + CPU_FTR_PPCAS_ARCH_V2 | CPU_FTR_ALTIVEC_COMP | \ + CPU_FTR_PURR | CPU_FTR_REAL_LE) #define CPU_FTRS_COMPATIBLE (CPU_FTR_USE_TB | CPU_FTR_PPCAS_ARCH_V2) #define CPU_FTRS_A2 (CPU_FTR_USE_TB | CPU_FTR_SMT | CPU_FTR_DBELL | \ - CPU_FTR_TLBIEL | CPU_FTR_NOEXECUTE | CPU_FTR_NODSISRALIGN | \ - CPU_FTR_16M_PAGE) + CPU_FTR_NOEXECUTE | CPU_FTR_NODSISRALIGN) #ifdef __powerpc64__ #ifdef CONFIG_PPC_BOOK3E @@ -449,7 +440,7 @@ extern const char *powerpc_base_platform; (CPU_FTRS_POWER3 | CPU_FTRS_RS64 | CPU_FTRS_POWER4 | \ CPU_FTRS_PPC970 | CPU_FTRS_POWER5 | CPU_FTRS_POWER6 | \ CPU_FTRS_POWER7 | CPU_FTRS_CELL | CPU_FTRS_PA6T | \ - CPU_FTR_1T_SEGMENT | CPU_FTR_VSX) + CPU_FTR_VSX) #endif #else enum { diff --git a/arch/powerpc/include/asm/mmu.h b/arch/powerpc/include/asm/mmu.h index bb40a06..a39304b 100644 --- a/arch/powerpc/include/asm/mmu.h +++ b/arch/powerpc/include/asm/mmu.h @@ -70,6 +70,54 @@ */ #define MMU_FTR_USE_PAIRED_MAS ASM_CONST(0x01000000) +/* MMU is SLB-based + */ +#define MMU_FTR_SLB ASM_CONST(0x02000000) + +/* Support 16M large pages + */ +#define MMU_FTR_16M_PAGE ASM_CONST(0x04000000) + +/* Supports TLBIEL variant + */ +#define MMU_FTR_TLBIEL ASM_CONST(0x08000000) + +/* Supports tlbies w/o locking + */ +#define MMU_FTR_LOCKLESS_TLBIE ASM_CONST(0x10000000) + +/* Large pages can be marked CI + */ +#define MMU_FTR_CI_LARGE_PAGE ASM_CONST(0x20000000) + +/* 1T segments available + */ +#define MMU_FTR_1T_SEGMENT ASM_CONST(0x40000000) + +/* Doesn't support the B bit (1T segment) in SLBIE + */ +#define MMU_FTR_NO_SLBIE_B ASM_CONST(0x80000000) + +/* MMU feature bit sets for various CPUs */ +#define MMU_FTRS_DEFAULT_HPTE_ARCH_V2 \ + MMU_FTR_HPTE_TABLE | MMU_FTR_PPCAS_ARCH_V2 +#define MMU_FTRS_POWER4 MMU_FTRS_DEFAULT_HPTE_ARCH_V2 +#define MMU_FTRS_PPC970 MMU_FTRS_POWER4 +#define MMU_FTRS_POWER5 MMU_FTRS_POWER4 | MMU_FTR_LOCKLESS_TLBIE +#define MMU_FTRS_POWER6 MMU_FTRS_POWER4 | MMU_FTR_LOCKLESS_TLBIE +#define MMU_FTRS_POWER7 MMU_FTRS_POWER4 | MMU_FTR_LOCKLESS_TLBIE | \ + MMU_FTR_TLBIE_206 +#define MMU_FTRS_CELL MMU_FTRS_DEFAULT_HPTE_ARCH_V2 | \ + MMU_FTR_CI_LARGE_PAGE +#define MMU_FTRS_PA6T MMU_FTRS_DEFAULT_HPTE_ARCH_V2 | \ + MMU_FTR_CI_LARGE_PAGE | MMU_FTR_NO_SLBIE_B +#define MMU_FTRS_A2 MMU_FTR_TYPE_3E | MMU_FTR_USE_TLBILX | \ + MMU_FTR_USE_TLBIVAX_BCAST | \ + MMU_FTR_LOCK_BCAST_INVAL | \ + MMU_FTR_USE_TLBRSRV | \ + MMU_FTR_USE_PAIRED_MAS | \ + MMU_FTR_TLBIEL | \ + MMU_FTR_16M_PAGE #ifndef __ASSEMBLY__ #include diff --git a/arch/powerpc/include/asm/mmu_context.h b/arch/powerpc/include/asm/mmu_context.h index 81fb412..8e13f65 100644 --- a/arch/powerpc/include/asm/mmu_context.h +++ b/arch/powerpc/include/asm/mmu_context.h @@ -67,7 +67,7 @@ static inline void switch_mm(struct mm_struct *prev, struct mm_struct *next, * sub architectures. */ #ifdef CONFIG_PPC_STD_MMU_64 - if (cpu_has_feature(CPU_FTR_SLB)) + if (mmu_has_feature(MMU_FTR_SLB)) switch_slb(tsk, next); else switch_stab(tsk, next); diff --git a/arch/powerpc/kernel/cputable.c b/arch/powerpc/kernel/cputable.c index 3d7b65a..34d2722 100644 --- a/arch/powerpc/kernel/cputable.c +++ b/arch/powerpc/kernel/cputable.c @@ -201,7 +201,7 @@ static struct cpu_spec __initdata cpu_specs[] = { .cpu_name = "POWER4 (gp)", .cpu_features = CPU_FTRS_POWER4, .cpu_user_features = COMMON_USER_POWER4, - .mmu_features = MMU_FTR_HPTE_TABLE, + .mmu_features = MMU_FTRS_POWER4, .icache_bsize = 128, .dcache_bsize = 128, .num_pmcs = 8, @@ -216,7 +216,7 @@ static struct cpu_spec __initdata cpu_specs[] = { .cpu_name = "POWER4+ (gq)", .cpu_features = CPU_FTRS_POWER4, .cpu_user_features = COMMON_USER_POWER4, - .mmu_features = MMU_FTR_HPTE_TABLE, + .mmu_features = MMU_FTRS_POWER4, .icache_bsize = 128, .dcache_bsize = 128, .num_pmcs = 8, @@ -232,7 +232,7 @@ static struct cpu_spec __initdata cpu_specs[] = { .cpu_features = CPU_FTRS_PPC970, .cpu_user_features = COMMON_USER_POWER4 | PPC_FEATURE_HAS_ALTIVEC_COMP, - .mmu_features = MMU_FTR_HPTE_TABLE, + .mmu_features = MMU_FTRS_PPC970, .icache_bsize = 128, .dcache_bsize = 128, .num_pmcs = 8, @@ -250,7 +250,7 @@ static struct cpu_spec __initdata cpu_specs[] = { .cpu_features = CPU_FTRS_PPC970, .cpu_user_features = COMMON_USER_POWER4 | PPC_FEATURE_HAS_ALTIVEC_COMP, - .mmu_features = MMU_FTR_HPTE_TABLE, + .mmu_features = MMU_FTRS_PPC970, .icache_bsize = 128, .dcache_bsize = 128, .num_pmcs = 8, @@ -286,7 +286,7 @@ static struct cpu_spec __initdata cpu_specs[] = { .cpu_features = CPU_FTRS_PPC970, .cpu_user_features = COMMON_USER_POWER4 | PPC_FEATURE_HAS_ALTIVEC_COMP, - .mmu_features = MMU_FTR_HPTE_TABLE, + .mmu_features = MMU_FTRS_PPC970, .icache_bsize = 128, .dcache_bsize = 128, .num_pmcs = 8, @@ -304,7 +304,7 @@ static struct cpu_spec __initdata cpu_specs[] = { .cpu_features = CPU_FTRS_PPC970, .cpu_user_features = COMMON_USER_POWER4 | PPC_FEATURE_HAS_ALTIVEC_COMP, - .mmu_features = MMU_FTR_HPTE_TABLE, + .mmu_features = MMU_FTRS_PPC970, .icache_bsize = 128, .dcache_bsize = 128, .num_pmcs = 8, @@ -320,7 +320,7 @@ static struct cpu_spec __initdata cpu_specs[] = { .cpu_name = "POWER5 (gr)", .cpu_features = CPU_FTRS_POWER5, .cpu_user_features = COMMON_USER_POWER5, - .mmu_features = MMU_FTR_HPTE_TABLE, + .mmu_features = MMU_FTRS_POWER5, .icache_bsize = 128, .dcache_bsize = 128, .num_pmcs = 6, @@ -340,7 +340,7 @@ static struct cpu_spec __initdata cpu_specs[] = { .cpu_name = "POWER5+ (gs)", .cpu_features = CPU_FTRS_POWER5, .cpu_user_features = COMMON_USER_POWER5_PLUS, - .mmu_features = MMU_FTR_HPTE_TABLE, + .mmu_features = MMU_FTRS_POWER5, .icache_bsize = 128, .dcache_bsize = 128, .num_pmcs = 6, @@ -356,7 +356,7 @@ static struct cpu_spec __initdata cpu_specs[] = { .cpu_name = "POWER5+ (gs)", .cpu_features = CPU_FTRS_POWER5, .cpu_user_features = COMMON_USER_POWER5_PLUS, - .mmu_features = MMU_FTR_HPTE_TABLE, + .mmu_features = MMU_FTRS_POWER5, .icache_bsize = 128, .dcache_bsize = 128, .num_pmcs = 6, @@ -373,7 +373,7 @@ static struct cpu_spec __initdata cpu_specs[] = { .cpu_name = "POWER5+", .cpu_features = CPU_FTRS_POWER5, .cpu_user_features = COMMON_USER_POWER5_PLUS, - .mmu_features = MMU_FTR_HPTE_TABLE, + .mmu_features = MMU_FTRS_POWER5, .icache_bsize = 128, .dcache_bsize = 128, .oprofile_cpu_type = "ppc64/ibm-compat-v1", @@ -387,7 +387,7 @@ static struct cpu_spec __initdata cpu_specs[] = { .cpu_features = CPU_FTRS_POWER6, .cpu_user_features = COMMON_USER_POWER6 | PPC_FEATURE_POWER6_EXT, - .mmu_features = MMU_FTR_HPTE_TABLE, + .mmu_features = MMU_FTRS_POWER6, .icache_bsize = 128, .dcache_bsize = 128, .num_pmcs = 6, @@ -406,7 +406,7 @@ static struct cpu_spec __initdata cpu_specs[] = { .cpu_name = "POWER6 (architected)", .cpu_features = CPU_FTRS_POWER6, .cpu_user_features = COMMON_USER_POWER6, - .mmu_features = MMU_FTR_HPTE_TABLE, + .mmu_features = MMU_FTRS_POWER6, .icache_bsize = 128, .dcache_bsize = 128, .oprofile_cpu_type = "ppc64/ibm-compat-v1", @@ -419,8 +419,7 @@ static struct cpu_spec __initdata cpu_specs[] = { .cpu_name = "POWER7 (architected)", .cpu_features = CPU_FTRS_POWER7, .cpu_user_features = COMMON_USER_POWER7, - .mmu_features = MMU_FTR_HPTE_TABLE | - MMU_FTR_TLBIE_206, + .mmu_features = MMU_FTRS_POWER7, .icache_bsize = 128, .dcache_bsize = 128, .oprofile_type = PPC_OPROFILE_POWER4, @@ -435,8 +434,7 @@ static struct cpu_spec __initdata cpu_specs[] = { .cpu_name = "POWER7 (raw)", .cpu_features = CPU_FTRS_POWER7, .cpu_user_features = COMMON_USER_POWER7, - .mmu_features = MMU_FTR_HPTE_TABLE | - MMU_FTR_TLBIE_206, + .mmu_features = MMU_FTRS_POWER7, .icache_bsize = 128, .dcache_bsize = 128, .num_pmcs = 6, @@ -453,8 +451,7 @@ static struct cpu_spec __initdata cpu_specs[] = { .cpu_name = "POWER7+ (raw)", .cpu_features = CPU_FTRS_POWER7, .cpu_user_features = COMMON_USER_POWER7, - .mmu_features = MMU_FTR_HPTE_TABLE | - MMU_FTR_TLBIE_206, + .mmu_features = MMU_FTRS_POWER7, .icache_bsize = 128, .dcache_bsize = 128, .num_pmcs = 6, @@ -473,7 +470,7 @@ static struct cpu_spec __initdata cpu_specs[] = { .cpu_user_features = COMMON_USER_PPC64 | PPC_FEATURE_CELL | PPC_FEATURE_HAS_ALTIVEC_COMP | PPC_FEATURE_SMT, - .mmu_features = MMU_FTR_HPTE_TABLE, + .mmu_features = MMU_FTRS_CELL, .icache_bsize = 128, .dcache_bsize = 128, .num_pmcs = 4, @@ -488,7 +485,7 @@ static struct cpu_spec __initdata cpu_specs[] = { .cpu_name = "PA6T", .cpu_features = CPU_FTRS_PA6T, .cpu_user_features = COMMON_USER_PA6T, - .mmu_features = MMU_FTR_HPTE_TABLE, + .mmu_features = MMU_FTRS_PA6T, .icache_bsize = 64, .dcache_bsize = 64, .num_pmcs = 6, @@ -505,7 +502,7 @@ static struct cpu_spec __initdata cpu_specs[] = { .cpu_name = "POWER4 (compatible)", .cpu_features = CPU_FTRS_COMPATIBLE, .cpu_user_features = COMMON_USER_PPC64, - .mmu_features = MMU_FTR_HPTE_TABLE, + .mmu_features = MMU_FTRS_DEFAULT_HPTE_ARCH_V2, .icache_bsize = 128, .dcache_bsize = 128, .num_pmcs = 6, @@ -2020,11 +2017,7 @@ static struct cpu_spec __initdata cpu_specs[] = { .cpu_name = "A2 (>= DD2)", .cpu_features = CPU_FTRS_A2, .cpu_user_features = COMMON_USER_PPC64, - .mmu_features = MMU_FTR_TYPE_3E | MMU_FTR_USE_TLBILX | - MMU_FTR_USE_TLBIVAX_BCAST | - MMU_FTR_LOCK_BCAST_INVAL | - MMU_FTR_USE_TLBRSRV | - MMU_FTR_USE_PAIRED_MAS, + .mmu_features = MMU_FTRS_A2, .icache_bsize = 64, .dcache_bsize = 64, .num_pmcs = 0, diff --git a/arch/powerpc/kernel/entry_64.S b/arch/powerpc/kernel/entry_64.S index 6469370..d834425 100644 --- a/arch/powerpc/kernel/entry_64.S +++ b/arch/powerpc/kernel/entry_64.S @@ -468,10 +468,10 @@ BEGIN_FTR_SECTION FTR_SECTION_ELSE_NESTED(95) clrrdi r6,r8,40 /* get its 1T ESID */ clrrdi r9,r1,40 /* get current sp 1T ESID */ - ALT_FTR_SECTION_END_NESTED_IFCLR(CPU_FTR_1T_SEGMENT, 95) + ALT_MMU_FTR_SECTION_END_NESTED_IFCLR(MMU_FTR_1T_SEGMENT, 95) FTR_SECTION_ELSE b 2f -ALT_FTR_SECTION_END_IFSET(CPU_FTR_SLB) +ALT_MMU_FTR_SECTION_END_IFSET(MMU_FTR_SLB) clrldi. r0,r6,2 /* is new ESID c00000000? */ cmpd cr1,r6,r9 /* or is new ESID the same as current ESID? */ cror eq,4*cr1+eq,eq @@ -485,7 +485,7 @@ BEGIN_FTR_SECTION li r9,MMU_SEGSIZE_1T /* insert B field */ oris r6,r6,(MMU_SEGSIZE_1T << SLBIE_SSIZE_SHIFT)@h rldimi r7,r9,SLB_VSID_SSIZE_SHIFT,0 -END_FTR_SECTION_IFSET(CPU_FTR_1T_SEGMENT) +END_MMU_FTR_SECTION_IFSET(MMU_FTR_1T_SEGMENT) /* Update the last bolted SLB. No write barriers are needed * here, provided we only update the current CPU's SLB shadow @@ -497,7 +497,7 @@ END_FTR_SECTION_IFSET(CPU_FTR_1T_SEGMENT) std r7,SLBSHADOW_STACKVSID(r9) /* Save VSID */ std r0,SLBSHADOW_STACKESID(r9) /* Save ESID */ - /* No need to check for CPU_FTR_NO_SLBIE_B here, since when + /* No need to check for MMU_FTR_NO_SLBIE_B here, since when * we have 1TB segments, the only CPUs known to have the errata * only support less than 1TB of system memory and we'll never * actually hit this code path. diff --git a/arch/powerpc/kernel/exceptions-64s.S b/arch/powerpc/kernel/exceptions-64s.S index ad06333..226cc8c 100644 --- a/arch/powerpc/kernel/exceptions-64s.S +++ b/arch/powerpc/kernel/exceptions-64s.S @@ -102,7 +102,7 @@ BEGIN_FTR_SECTION EXCEPTION_PROLOG_PSERIES_1(data_access_common, EXC_STD) FTR_SECTION_ELSE EXCEPTION_PROLOG_PSERIES(PACA_EXGEN, data_access_common, EXC_STD) -ALT_FTR_SECTION_END_IFCLR(CPU_FTR_SLB) +ALT_MMU_FTR_SECTION_END_IFCLR(MMU_FTR_SLB) . = 0x380 .globl data_access_slb_pSeries @@ -840,7 +840,7 @@ _STATIC(do_hash_page) BEGIN_FTR_SECTION andis. r0,r4,0x0020 /* Is it a segment table fault? */ bne- do_ste_alloc /* If so handle it */ -END_FTR_SECTION_IFCLR(CPU_FTR_SLB) +END_MMU_FTR_SECTION_IFCLR(MMU_FTR_SLB) clrrdi r11,r1,THREAD_SHIFT lwz r0,TI_PREEMPT(r11) /* If we're in an "NMI" */ diff --git a/arch/powerpc/kernel/process.c b/arch/powerpc/kernel/process.c index a01c2d9..095043d 100644 --- a/arch/powerpc/kernel/process.c +++ b/arch/powerpc/kernel/process.c @@ -757,11 +757,11 @@ int copy_thread(unsigned long clone_flags, unsigned long usp, _ALIGN_UP(sizeof(struct thread_info), 16); #ifdef CONFIG_PPC_STD_MMU_64 - if (cpu_has_feature(CPU_FTR_SLB)) { + if (mmu_has_feature(MMU_FTR_SLB)) { unsigned long sp_vsid; unsigned long llp = mmu_psize_defs[mmu_linear_psize].sllp; - if (cpu_has_feature(CPU_FTR_1T_SEGMENT)) + if (mmu_has_feature(MMU_FTR_1T_SEGMENT)) sp_vsid = get_kernel_vsid(sp, MMU_SEGSIZE_1T) << SLB_VSID_SHIFT_1T; else diff --git a/arch/powerpc/kernel/prom.c b/arch/powerpc/kernel/prom.c index c391dc4..5f5e6ae 100644 --- a/arch/powerpc/kernel/prom.c +++ b/arch/powerpc/kernel/prom.c @@ -123,18 +123,19 @@ static void __init move_device_tree(void) */ static struct ibm_pa_feature { unsigned long cpu_features; /* CPU_FTR_xxx bit */ + unsigned long mmu_features; /* MMU_FTR_xxx bit */ unsigned int cpu_user_ftrs; /* PPC_FEATURE_xxx bit */ unsigned char pabyte; /* byte number in ibm,pa-features */ unsigned char pabit; /* bit number (big-endian) */ unsigned char invert; /* if 1, pa bit set => clear feature */ } ibm_pa_features[] __initdata = { - {0, PPC_FEATURE_HAS_MMU, 0, 0, 0}, - {0, PPC_FEATURE_HAS_FPU, 0, 1, 0}, - {CPU_FTR_SLB, 0, 0, 2, 0}, - {CPU_FTR_CTRL, 0, 0, 3, 0}, - {CPU_FTR_NOEXECUTE, 0, 0, 6, 0}, - {CPU_FTR_NODSISRALIGN, 0, 1, 1, 1}, - {CPU_FTR_CI_LARGE_PAGE, 0, 1, 2, 0}, + {0, 0, PPC_FEATURE_HAS_MMU, 0, 0, 0}, + {0, 0, PPC_FEATURE_HAS_FPU, 0, 1, 0}, + {0, MMU_FTR_SLB, 0, 0, 2, 0}, + {CPU_FTR_CTRL, 0, 0, 0, 3, 0}, + {CPU_FTR_NOEXECUTE, 0, 0, 0, 6, 0}, + {CPU_FTR_NODSISRALIGN, 0, 0, 1, 1, 1}, + {0, MMU_FTR_CI_LARGE_PAGE, 0, 1, 2, 0}, {CPU_FTR_REAL_LE, PPC_FEATURE_TRUE_LE, 5, 0, 0}, }; @@ -166,9 +167,11 @@ static void __init scan_features(unsigned long node, unsigned char *ftrs, if (bit ^ fp->invert) { cur_cpu_spec->cpu_features |= fp->cpu_features; cur_cpu_spec->cpu_user_features |= fp->cpu_user_ftrs; + cur_cpu_spec->mmu_features |= fp->mmu_features; } else { cur_cpu_spec->cpu_features &= ~fp->cpu_features; cur_cpu_spec->cpu_user_features &= ~fp->cpu_user_ftrs; + cur_cpu_spec->mmu_features &= ~fp->mmu_features; } } } diff --git a/arch/powerpc/kernel/setup_64.c b/arch/powerpc/kernel/setup_64.c index 91a5cc5..959c63c 100644 --- a/arch/powerpc/kernel/setup_64.c +++ b/arch/powerpc/kernel/setup_64.c @@ -436,7 +436,7 @@ void __init setup_system(void) static u64 slb0_limit(void) { - if (cpu_has_feature(CPU_FTR_1T_SEGMENT)) { + if (mmu_has_feature(MMU_FTR_1T_SEGMENT)) { return 1UL << SID_SHIFT_1T; } return 1UL << SID_SHIFT; diff --git a/arch/powerpc/mm/hash_low_64.S b/arch/powerpc/mm/hash_low_64.S index 5b7dd4e..a242b5d 100644 --- a/arch/powerpc/mm/hash_low_64.S +++ b/arch/powerpc/mm/hash_low_64.S @@ -118,7 +118,7 @@ _GLOBAL(__hash_page_4K) BEGIN_FTR_SECTION cmpdi r9,0 /* check segment size */ bne 3f -END_FTR_SECTION_IFSET(CPU_FTR_1T_SEGMENT) +END_MMU_FTR_SECTION_IFSET(MMU_FTR_1T_SEGMENT) /* Calc va and put it in r29 */ rldicr r29,r5,28,63-28 rldicl r3,r3,0,36 @@ -401,7 +401,7 @@ _GLOBAL(__hash_page_4K) BEGIN_FTR_SECTION cmpdi r9,0 /* check segment size */ bne 3f -END_FTR_SECTION_IFSET(CPU_FTR_1T_SEGMENT) +END_MMU_FTR_SECTION_IFSET(MMU_FTR_1T_SEGMENT) /* Calc va and put it in r29 */ rldicr r29,r5,28,63-28 /* r29 = (vsid << 28) */ rldicl r3,r3,0,36 /* r3 = (ea & 0x0fffffff) */ @@ -715,7 +715,7 @@ BEGIN_FTR_SECTION andi. r0,r31,_PAGE_NO_CACHE /* If so, bail out and refault as a 4k page */ bne- ht64_bail_ok -END_FTR_SECTION_IFCLR(CPU_FTR_CI_LARGE_PAGE) +END_MMU_FTR_SECTION_IFCLR(MMU_FTR_CI_LARGE_PAGE) /* Prepare new PTE value (turn access RW into DIRTY, then * add BUSY and ACCESSED) */ @@ -736,7 +736,7 @@ END_FTR_SECTION_IFCLR(CPU_FTR_CI_LARGE_PAGE) BEGIN_FTR_SECTION cmpdi r9,0 /* check segment size */ bne 3f -END_FTR_SECTION_IFSET(CPU_FTR_1T_SEGMENT) +END_MMU_FTR_SECTION_IFSET(MMU_FTR_1T_SEGMENT) /* Calc va and put it in r29 */ rldicr r29,r5,28,63-28 rldicl r3,r3,0,36 diff --git a/arch/powerpc/mm/hash_native_64.c b/arch/powerpc/mm/hash_native_64.c index 784a400..c23eef2 100644 --- a/arch/powerpc/mm/hash_native_64.c +++ b/arch/powerpc/mm/hash_native_64.c @@ -98,8 +98,8 @@ static inline void __tlbiel(unsigned long va, int psize, int ssize) static inline void tlbie(unsigned long va, int psize, int ssize, int local) { - unsigned int use_local = local && cpu_has_feature(CPU_FTR_TLBIEL); - int lock_tlbie = !cpu_has_feature(CPU_FTR_LOCKLESS_TLBIE); + unsigned int use_local = local && mmu_has_feature(MMU_FTR_TLBIEL); + int lock_tlbie = !mmu_has_feature(MMU_FTR_LOCKLESS_TLBIE); if (use_local) use_local = mmu_psize_defs[psize].tlbiel; @@ -503,7 +503,7 @@ static void native_flush_hash_range(unsigned long number, int local) } pte_iterate_hashed_end(); } - if (cpu_has_feature(CPU_FTR_TLBIEL) && + if (mmu_has_feature(MMU_FTR_TLBIEL) && mmu_psize_defs[psize].tlbiel && local) { asm volatile("ptesync":::"memory"); for (i = 0; i < number; i++) { @@ -517,7 +517,7 @@ static void native_flush_hash_range(unsigned long number, int local) } asm volatile("ptesync":::"memory"); } else { - int lock_tlbie = !cpu_has_feature(CPU_FTR_LOCKLESS_TLBIE); + int lock_tlbie = !mmu_has_feature(MMU_FTR_LOCKLESS_TLBIE); if (lock_tlbie) raw_spin_lock(&native_tlbie_lock); diff --git a/arch/powerpc/mm/hash_utils_64.c b/arch/powerpc/mm/hash_utils_64.c index d95d8f4..26b2872 100644 --- a/arch/powerpc/mm/hash_utils_64.c +++ b/arch/powerpc/mm/hash_utils_64.c @@ -259,11 +259,11 @@ static int __init htab_dt_scan_seg_sizes(unsigned long node, for (; size >= 4; size -= 4, ++prop) { if (prop[0] == 40) { DBG("1T segment support detected\n"); - cur_cpu_spec->cpu_features |= CPU_FTR_1T_SEGMENT; + cur_cpu_spec->mmu_features |= MMU_FTR_1T_SEGMENT; return 1; } } - cur_cpu_spec->cpu_features &= ~CPU_FTR_NO_SLBIE_B; + cur_cpu_spec->mmu_features &= ~MMU_FTR_NO_SLBIE_B; return 0; } @@ -289,7 +289,7 @@ static int __init htab_dt_scan_page_sizes(unsigned long node, if (prop != NULL) { DBG("Page sizes from device-tree:\n"); size /= 4; - cur_cpu_spec->cpu_features &= ~(CPU_FTR_16M_PAGE); + cur_cpu_spec->mmu_features &= ~(MMU_FTR_16M_PAGE); while(size > 0) { unsigned int shift = prop[0]; unsigned int slbenc = prop[1]; @@ -317,7 +317,7 @@ static int __init htab_dt_scan_page_sizes(unsigned long node, break; case 0x18: idx = MMU_PAGE_16M; - cur_cpu_spec->cpu_features |= CPU_FTR_16M_PAGE; + cur_cpu_spec->mmu_features |= MMU_FTR_16M_PAGE; break; case 0x22: idx = MMU_PAGE_16G; @@ -412,7 +412,7 @@ static void __init htab_init_page_sizes(void) * Not in the device-tree, let's fallback on known size * list for 16M capable GP & GR */ - if (cpu_has_feature(CPU_FTR_16M_PAGE)) + if (mmu_has_feature(MMU_FTR_16M_PAGE)) memcpy(mmu_psize_defs, mmu_psize_defaults_gp, sizeof(mmu_psize_defaults_gp)); found: @@ -442,7 +442,7 @@ static void __init htab_init_page_sizes(void) mmu_vmalloc_psize = MMU_PAGE_64K; if (mmu_linear_psize == MMU_PAGE_4K) mmu_linear_psize = MMU_PAGE_64K; - if (cpu_has_feature(CPU_FTR_CI_LARGE_PAGE)) { + if (mmu_has_feature(MMU_FTR_CI_LARGE_PAGE)) { /* * Don't use 64k pages for ioremap on pSeries, since * that would stop us accessing the HEA ethernet. @@ -608,7 +608,7 @@ static void __init htab_initialize(void) /* Initialize page sizes */ htab_init_page_sizes(); - if (cpu_has_feature(CPU_FTR_1T_SEGMENT)) { + if (mmu_has_feature(MMU_FTR_1T_SEGMENT)) { mmu_kernel_ssize = MMU_SEGSIZE_1T; mmu_highuser_ssize = MMU_SEGSIZE_1T; printk(KERN_INFO "Using 1TB segments\n"); @@ -749,7 +749,7 @@ void __init early_init_mmu(void) /* Initialize stab / SLB management except on iSeries */ - if (cpu_has_feature(CPU_FTR_SLB)) + if (mmu_has_feature(MMU_FTR_SLB)) slb_initialize(); else if (!firmware_has_feature(FW_FEATURE_ISERIES)) stab_initialize(get_paca()->stab_real); @@ -766,7 +766,7 @@ void __cpuinit early_init_mmu_secondary(void) * in real mode on pSeries and we want a virtual address on * iSeries anyway */ - if (cpu_has_feature(CPU_FTR_SLB)) + if (mmu_has_feature(MMU_FTR_SLB)) slb_initialize(); else stab_initialize(get_paca()->stab_addr); diff --git a/arch/powerpc/mm/hugetlbpage.c b/arch/powerpc/mm/hugetlbpage.c index 9bb249c..0b9a5c1 100644 --- a/arch/powerpc/mm/hugetlbpage.c +++ b/arch/powerpc/mm/hugetlbpage.c @@ -529,7 +529,7 @@ static int __init hugetlbpage_init(void) { int psize; - if (!cpu_has_feature(CPU_FTR_16M_PAGE)) + if (!mmu_has_feature(MMU_FTR_16M_PAGE)) return -ENODEV; for (psize = 0; psize < MMU_PAGE_COUNT; ++psize) { diff --git a/arch/powerpc/mm/slb.c b/arch/powerpc/mm/slb.c index 5500712..e22276c 100644 --- a/arch/powerpc/mm/slb.c +++ b/arch/powerpc/mm/slb.c @@ -167,7 +167,7 @@ static inline int esids_match(unsigned long addr1, unsigned long addr2) int esid_1t_count; /* System is not 1T segment size capable. */ - if (!cpu_has_feature(CPU_FTR_1T_SEGMENT)) + if (!mmu_has_feature(MMU_FTR_1T_SEGMENT)) return (GET_ESID(addr1) == GET_ESID(addr2)); esid_1t_count = (((addr1 >> SID_SHIFT_1T) != 0) + @@ -202,7 +202,7 @@ void switch_slb(struct task_struct *tsk, struct mm_struct *mm) */ hard_irq_disable(); offset = get_paca()->slb_cache_ptr; - if (!cpu_has_feature(CPU_FTR_NO_SLBIE_B) && + if (!mmu_has_feature(MMU_FTR_NO_SLBIE_B) && offset <= SLB_CACHE_ENTRIES) { int i; asm volatile("isync" : : : "memory"); diff --git a/arch/powerpc/mm/slb_low.S b/arch/powerpc/mm/slb_low.S index 95ce355..ef653dc 100644 --- a/arch/powerpc/mm/slb_low.S +++ b/arch/powerpc/mm/slb_low.S @@ -58,7 +58,7 @@ _GLOBAL(slb_miss_kernel_load_linear) li r11,0 BEGIN_FTR_SECTION b slb_finish_load -END_FTR_SECTION_IFCLR(CPU_FTR_1T_SEGMENT) +END_MMU_FTR_SECTION_IFCLR(MMU_FTR_1T_SEGMENT) b slb_finish_load_1T 1: @@ -87,7 +87,7 @@ _GLOBAL(slb_miss_kernel_load_vmemmap) 6: BEGIN_FTR_SECTION b slb_finish_load -END_FTR_SECTION_IFCLR(CPU_FTR_1T_SEGMENT) +END_MMU_FTR_SECTION_IFCLR(MMU_FTR_1T_SEGMENT) b slb_finish_load_1T 0: /* user address: proto-VSID = context << 15 | ESID. First check @@ -138,11 +138,11 @@ END_FTR_SECTION_IFCLR(CPU_FTR_1T_SEGMENT) ld r9,PACACONTEXTID(r13) BEGIN_FTR_SECTION cmpldi r10,0x1000 -END_FTR_SECTION_IFSET(CPU_FTR_1T_SEGMENT) +END_MMU_FTR_SECTION_IFSET(MMU_FTR_1T_SEGMENT) rldimi r10,r9,USER_ESID_BITS,0 BEGIN_FTR_SECTION bge slb_finish_load_1T -END_FTR_SECTION_IFSET(CPU_FTR_1T_SEGMENT) +END_MMU_FTR_SECTION_IFSET(MMU_FTR_1T_SEGMENT) b slb_finish_load 8: /* invalid EA */ diff --git a/arch/powerpc/mm/stab.c b/arch/powerpc/mm/stab.c index 446a018..41e3164 100644 --- a/arch/powerpc/mm/stab.c +++ b/arch/powerpc/mm/stab.c @@ -243,7 +243,7 @@ void __init stabs_alloc(void) { int cpu; - if (cpu_has_feature(CPU_FTR_SLB)) + if (mmu_has_feature(MMU_FTR_SLB)) return; for_each_possible_cpu(cpu) { diff --git a/arch/powerpc/platforms/iseries/exception.S b/arch/powerpc/platforms/iseries/exception.S index 32a56c6..a67984c 100644 --- a/arch/powerpc/platforms/iseries/exception.S +++ b/arch/powerpc/platforms/iseries/exception.S @@ -31,6 +31,7 @@ #include #include #include +#include #include "exception.h" @@ -157,7 +158,7 @@ BEGIN_FTR_SECTION FTR_SECTION_ELSE EXCEPTION_PROLOG_1(PACA_EXGEN) EXCEPTION_PROLOG_ISERIES_1 -ALT_FTR_SECTION_END_IFCLR(CPU_FTR_SLB) +ALT_MMU_FTR_SECTION_END_IFCLR(MMU_FTR_SLB) b data_access_common .do_stab_bolted_iSeries: diff --git a/arch/powerpc/platforms/iseries/setup.c b/arch/powerpc/platforms/iseries/setup.c index 2946ae1..81cb8d2 100644 --- a/arch/powerpc/platforms/iseries/setup.c +++ b/arch/powerpc/platforms/iseries/setup.c @@ -249,7 +249,7 @@ static unsigned long iSeries_process_mainstore_vpd(struct MemoryBlock *mb_array, unsigned long i; unsigned long mem_blocks = 0; - if (cpu_has_feature(CPU_FTR_SLB)) + if (mmu_has_feature(MMU_FTR_SLB)) mem_blocks = iSeries_process_Regatta_mainstore_vpd(mb_array, max_entries); else @@ -634,7 +634,7 @@ static int __init iseries_probe(void) hpte_init_iSeries(); /* iSeries does not support 16M pages */ - cur_cpu_spec->cpu_features &= ~CPU_FTR_16M_PAGE; + cur_cpu_spec->mmu_features &= ~MMU_FTR_16M_PAGE; return 1; } diff --git a/arch/powerpc/platforms/pseries/lpar.c b/arch/powerpc/platforms/pseries/lpar.c index ca5d589..6f0ed3a 100644 --- a/arch/powerpc/platforms/pseries/lpar.c +++ b/arch/powerpc/platforms/pseries/lpar.c @@ -573,7 +573,7 @@ static void pSeries_lpar_flush_hash_range(unsigned long number, int local) unsigned long i, pix, rc; unsigned long flags = 0; struct ppc64_tlb_batch *batch = &__get_cpu_var(ppc64_tlb_batch); - int lock_tlbie = !cpu_has_feature(CPU_FTR_LOCKLESS_TLBIE); + int lock_tlbie = !mmu_has_feature(MMU_FTR_LOCKLESS_TLBIE); unsigned long param[9]; unsigned long va; unsigned long hash, index, shift, hidx, slot; diff --git a/arch/powerpc/xmon/xmon.c b/arch/powerpc/xmon/xmon.c index ef9756ee..60593ad 100644 --- a/arch/powerpc/xmon/xmon.c +++ b/arch/powerpc/xmon/xmon.c @@ -2663,7 +2663,7 @@ static void dump_stab(void) void dump_segments(void) { - if (cpu_has_feature(CPU_FTR_SLB)) + if (mmu_has_feature(MMU_FTR_SLB)) dump_slb(); else dump_stab(); -- cgit v0.10.2 From 65f47f1339dfcffcd5837a307172fb41aa39e479 Mon Sep 17 00:00:00 2001 From: "Richard A. Lary" Date: Wed, 6 Apr 2011 12:50:45 +0000 Subject: powerpc/eeh: Add support for ibm,configure-pe RTAS call Added support for ibm,configure-pe RTAS call introduced with PAPR 2.2. Signed-off-by: Richard A. Lary Signed-off-by: Benjamin Herrenschmidt diff --git a/arch/powerpc/platforms/pseries/eeh.c b/arch/powerpc/platforms/pseries/eeh.c index 8964917..22937305 100644 --- a/arch/powerpc/platforms/pseries/eeh.c +++ b/arch/powerpc/platforms/pseries/eeh.c @@ -93,6 +93,7 @@ static int ibm_slot_error_detail; static int ibm_get_config_addr_info; static int ibm_get_config_addr_info2; static int ibm_configure_bridge; +static int ibm_configure_pe; int eeh_subsystem_enabled; EXPORT_SYMBOL(eeh_subsystem_enabled); @@ -261,6 +262,8 @@ void eeh_slot_error_detail(struct pci_dn *pdn, int severity) pci_regs_buf[0] = 0; rtas_pci_enable(pdn, EEH_THAW_MMIO); + rtas_configure_bridge(pdn); + eeh_restore_bars(pdn); loglen = gather_pci_data(pdn, pci_regs_buf, EEH_PCI_REGS_LOG_LEN); rtas_slot_error_detail(pdn, severity, pci_regs_buf, loglen); @@ -895,13 +898,20 @@ rtas_configure_bridge(struct pci_dn *pdn) { int config_addr; int rc; + int token; /* Use PE configuration address, if present */ config_addr = pdn->eeh_config_addr; if (pdn->eeh_pe_config_addr) config_addr = pdn->eeh_pe_config_addr; - rc = rtas_call(ibm_configure_bridge,3,1, NULL, + /* Use new configure-pe function, if supported */ + if (ibm_configure_pe != RTAS_UNKNOWN_SERVICE) + token = ibm_configure_pe; + else + token = ibm_configure_bridge; + + rc = rtas_call(token, 3, 1, NULL, config_addr, BUID_HI(pdn->phb->buid), BUID_LO(pdn->phb->buid)); @@ -1077,6 +1087,7 @@ void __init eeh_init(void) ibm_get_config_addr_info = rtas_token("ibm,get-config-addr-info"); ibm_get_config_addr_info2 = rtas_token("ibm,get-config-addr-info2"); ibm_configure_bridge = rtas_token ("ibm,configure-bridge"); + ibm_configure_pe = rtas_token("ibm,configure-pe"); if (ibm_set_eeh_option == RTAS_UNKNOWN_SERVICE) return; -- cgit v0.10.2 From e9c549998dc24209847007e1f209f3b6c88d21ba Mon Sep 17 00:00:00 2001 From: Lucas De Marchi Date: Tue, 26 Apr 2011 23:28:26 -0700 Subject: Revert wrong fixes for common misspellings These changes were incorrectly fixed by codespell. They were now manually corrected. Signed-off-by: Lucas De Marchi diff --git a/arch/arm/mach-davinci/dm355.c b/arch/arm/mach-davinci/dm355.c index f680122..a3a94e9 100644 --- a/arch/arm/mach-davinci/dm355.c +++ b/arch/arm/mach-davinci/dm355.c @@ -314,7 +314,7 @@ static struct clk timer2_clk = { .name = "timer2", .parent = &pll1_aux_clk, .lpsc = DAVINCI_LPSC_TIMER2, - .usecount = 1, /* REVISIT: why can't' this be disabled? */ + .usecount = 1, /* REVISIT: why can't this be disabled? */ }; static struct clk timer3_clk = { diff --git a/arch/arm/mach-davinci/dm644x.c b/arch/arm/mach-davinci/dm644x.c index 5f8a654..4c82c27 100644 --- a/arch/arm/mach-davinci/dm644x.c +++ b/arch/arm/mach-davinci/dm644x.c @@ -274,7 +274,7 @@ static struct clk timer2_clk = { .name = "timer2", .parent = &pll1_aux_clk, .lpsc = DAVINCI_LPSC_TIMER2, - .usecount = 1, /* REVISIT: why can't' this be disabled? */ + .usecount = 1, /* REVISIT: why can't this be disabled? */ }; static struct clk_lookup dm644x_clks[] = { diff --git a/arch/powerpc/include/asm/uninorth.h b/arch/powerpc/include/asm/uninorth.h index ae9c899..d12b11d 100644 --- a/arch/powerpc/include/asm/uninorth.h +++ b/arch/powerpc/include/asm/uninorth.h @@ -60,7 +60,7 @@ * * Obviously, the GART is not cache coherent and so any change to it * must be flushed to memory (or maybe just make the GART space non - * cachable). AGP memory itself does't seem to be cache coherent neither. + * cachable). AGP memory itself doesn't seem to be cache coherent neither. * * In order to invalidate the GART (which is probably necessary to inval * the bridge internal TLBs), the following sequence has to be written, diff --git a/drivers/infiniband/hw/qib/qib_iba6120.c b/drivers/infiniband/hw/qib/qib_iba6120.c index 7de4b7e..d8ca0a0 100644 --- a/drivers/infiniband/hw/qib/qib_iba6120.c +++ b/drivers/infiniband/hw/qib/qib_iba6120.c @@ -1799,7 +1799,7 @@ static int qib_6120_setup_reset(struct qib_devdata *dd) /* * Keep chip from being accessed until we are ready. Use * writeq() directly, to allow the write even though QIB_PRESENT - * isn't' set. + * isn't set. */ dd->flags &= ~(QIB_INITTED | QIB_PRESENT); dd->int_counter = 0; /* so we check interrupts work again */ diff --git a/drivers/infiniband/hw/qib/qib_iba7220.c b/drivers/infiniband/hw/qib/qib_iba7220.c index 74fe036..c765a2e 100644 --- a/drivers/infiniband/hw/qib/qib_iba7220.c +++ b/drivers/infiniband/hw/qib/qib_iba7220.c @@ -2111,7 +2111,7 @@ static int qib_setup_7220_reset(struct qib_devdata *dd) /* * Keep chip from being accessed until we are ready. Use * writeq() directly, to allow the write even though QIB_PRESENT - * isn't' set. + * isn't set. */ dd->flags &= ~(QIB_INITTED | QIB_PRESENT); dd->int_counter = 0; /* so we check interrupts work again */ diff --git a/drivers/infiniband/hw/qib/qib_iba7322.c b/drivers/infiniband/hw/qib/qib_iba7322.c index 55de3cf..6bab3ea 100644 --- a/drivers/infiniband/hw/qib/qib_iba7322.c +++ b/drivers/infiniband/hw/qib/qib_iba7322.c @@ -3299,7 +3299,7 @@ static int qib_do_7322_reset(struct qib_devdata *dd) /* * Keep chip from being accessed until we are ready. Use * writeq() directly, to allow the write even though QIB_PRESENT - * isn't' set. + * isn't set. */ dd->flags &= ~(QIB_INITTED | QIB_PRESENT | QIB_BADINTR); dd->flags |= QIB_DOING_RESET; diff --git a/drivers/media/radio/radio-sf16fmr2.c b/drivers/media/radio/radio-sf16fmr2.c index dc3f04c..87bad76 100644 --- a/drivers/media/radio/radio-sf16fmr2.c +++ b/drivers/media/radio/radio-sf16fmr2.c @@ -170,7 +170,7 @@ static int fmr2_setfreq(struct fmr2 *dev) return 0; } -/* !!! not tested, in my card this does't work !!! */ +/* !!! not tested, in my card this doesn't work !!! */ static int fmr2_setvolume(struct fmr2 *dev) { int vol[16] = { 0x021, 0x084, 0x090, 0x104, diff --git a/drivers/mtd/nand/diskonchip.c b/drivers/mtd/nand/diskonchip.c index 96c0b34..657b9f4 100644 --- a/drivers/mtd/nand/diskonchip.c +++ b/drivers/mtd/nand/diskonchip.c @@ -400,7 +400,7 @@ static uint16_t __init doc200x_ident_chip(struct mtd_info *mtd, int nr) doc200x_hwcontrol(mtd, 0, NAND_CTRL_ALE | NAND_CTRL_CHANGE); doc200x_hwcontrol(mtd, NAND_CMD_NONE, NAND_NCE | NAND_CTRL_CHANGE); - /* We can't' use dev_ready here, but at least we wait for the + /* We can't use dev_ready here, but at least we wait for the * command to complete */ udelay(50); diff --git a/drivers/pcmcia/pcmcia_resource.c b/drivers/pcmcia/pcmcia_resource.c index fe77e82..e8c19de 100644 --- a/drivers/pcmcia/pcmcia_resource.c +++ b/drivers/pcmcia/pcmcia_resource.c @@ -173,7 +173,7 @@ static int pcmcia_access_config(struct pcmcia_device *p_dev, c = p_dev->function_config; if (!(c->state & CONFIG_LOCKED)) { - dev_dbg(&p_dev->dev, "Configuration isn't't locked\n"); + dev_dbg(&p_dev->dev, "Configuration isn't locked\n"); mutex_unlock(&s->ops_mutex); return -EACCES; } diff --git a/drivers/staging/rt2860/common/cmm_data_pci.c b/drivers/staging/rt2860/common/cmm_data_pci.c index bef0bbd..f01a51c 100644 --- a/drivers/staging/rt2860/common/cmm_data_pci.c +++ b/drivers/staging/rt2860/common/cmm_data_pci.c @@ -444,7 +444,7 @@ int RTMPCheckRxError(struct rt_rtmp_adapter *pAd, return (NDIS_STATUS_FAILURE); } } - /* Drop not U2M frames, can't's drop here because we will drop beacon in this case */ + /* Drop not U2M frames, can't drop here because we will drop beacon in this case */ /* I am kind of doubting the U2M bit operation */ /* if (pRxD->U2M == 0) */ /* return(NDIS_STATUS_FAILURE); */ diff --git a/drivers/staging/rt2860/common/cmm_data_usb.c b/drivers/staging/rt2860/common/cmm_data_usb.c index 5637857..83a62fa 100644 --- a/drivers/staging/rt2860/common/cmm_data_usb.c +++ b/drivers/staging/rt2860/common/cmm_data_usb.c @@ -860,7 +860,7 @@ int RTMPCheckRxError(struct rt_rtmp_adapter *pAd, DBGPRINT_RAW(RT_DEBUG_ERROR, ("received packet too long\n")); return NDIS_STATUS_FAILURE; } - /* Drop not U2M frames, can't's drop here because we will drop beacon in this case */ + /* Drop not U2M frames, can't drop here because we will drop beacon in this case */ /* I am kind of doubting the U2M bit operation */ /* if (pRxD->U2M == 0) */ /* return(NDIS_STATUS_FAILURE); */ diff --git a/drivers/staging/spectra/ffsport.c b/drivers/staging/spectra/ffsport.c index 20dae73..506547b 100644 --- a/drivers/staging/spectra/ffsport.c +++ b/drivers/staging/spectra/ffsport.c @@ -653,7 +653,7 @@ static int SBD_setup_device(struct spectra_nand_dev *dev, int which) } dev->queue->queuedata = dev; - /* As Linux block layer does't support >4KB hardware sector, */ + /* As Linux block layer doesn't support >4KB hardware sector, */ /* Here we force report 512 byte hardware sector size to Kernel */ blk_queue_logical_block_size(dev->queue, 512); diff --git a/drivers/staging/tidspbridge/dynload/cload.c b/drivers/staging/tidspbridge/dynload/cload.c index 5cecd237..fe1ef0a 100644 --- a/drivers/staging/tidspbridge/dynload/cload.c +++ b/drivers/staging/tidspbridge/dynload/cload.c @@ -718,7 +718,7 @@ static void dload_symbols(struct dload_state *dlthis) * as a temporary for .dllview record construction. * Allocate storage for the whole table. Add 1 to the section count * in case a trampoline section is auto-generated as well as the - * size of the trampoline section name so DLLView does't get lost. + * size of the trampoline section name so DLLView doesn't get lost. */ siz = sym_count * sizeof(struct local_symbol); diff --git a/drivers/staging/tty/specialix.c b/drivers/staging/tty/specialix.c index cb24c6d..5c3598e 100644 --- a/drivers/staging/tty/specialix.c +++ b/drivers/staging/tty/specialix.c @@ -978,7 +978,7 @@ static void sx_change_speed(struct specialix_board *bp, spin_lock_irqsave(&bp->lock, flags); sx_out(bp, CD186x_CAR, port_No(port)); - /* The Specialix board does't implement the RTS lines. + /* The Specialix board doesn't implement the RTS lines. They are used to set the IRQ level. Don't touch them. */ if (sx_crtscts(tty)) port->MSVR = MSVR_DTR | (sx_in(bp, CD186x_MSVR) & MSVR_RTS); diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h index 2e61fe1..8f4b81d 100644 --- a/fs/btrfs/ctree.h +++ b/fs/btrfs/ctree.h @@ -718,7 +718,7 @@ struct btrfs_space_info { u64 total_bytes; /* total bytes in the space, this doesn't take mirrors into account */ u64 bytes_used; /* total bytes used, - this does't take mirrors into account */ + this doesn't take mirrors into account */ u64 bytes_pinned; /* total bytes pinned, will be freed when the transaction finishes */ u64 bytes_reserved; /* total bytes the allocator has reserved for diff --git a/fs/ocfs2/ocfs2_fs.h b/fs/ocfs2/ocfs2_fs.h index b68f87a..938387a 100644 --- a/fs/ocfs2/ocfs2_fs.h +++ b/fs/ocfs2/ocfs2_fs.h @@ -1019,7 +1019,7 @@ struct ocfs2_xattr_entry { __le16 xe_name_offset; /* byte offset from the 1st entry in the local xattr storage(inode, xattr block or xattr bucket). */ - __u8 xe_name_len; /* xattr name len, does't include prefix. */ + __u8 xe_name_len; /* xattr name len, doesn't include prefix. */ __u8 xe_type; /* the low 7 bits indicate the name prefix * type and the highest bit indicates whether * the EA is stored in the local storage. */ diff --git a/net/l2tp/l2tp_ip.c b/net/l2tp/l2tp_ip.c index fce9bd3..5c04f3e 100644 --- a/net/l2tp/l2tp_ip.c +++ b/net/l2tp/l2tp_ip.c @@ -667,7 +667,7 @@ MODULE_AUTHOR("James Chapman "); MODULE_DESCRIPTION("L2TP over IP"); MODULE_VERSION("1.0"); -/* Use the value of SOCK_DGRAM (2) directory, because __stringify does't like +/* Use the value of SOCK_DGRAM (2) directory, because __stringify doesn't like * enums */ MODULE_ALIAS_NET_PF_PROTO_TYPE(PF_INET, 2, IPPROTO_L2TP); diff --git a/net/sctp/ulpevent.c b/net/sctp/ulpevent.c index dff27d5..61b1f5a 100644 --- a/net/sctp/ulpevent.c +++ b/net/sctp/ulpevent.c @@ -554,7 +554,7 @@ struct sctp_ulpevent *sctp_ulpevent_make_send_failed( memcpy(&ssf->ssf_info, &chunk->sinfo, sizeof(struct sctp_sndrcvinfo)); /* Per TSVWG discussion with Randy. Allow the application to - * resemble a fragmented message. + * reassemble a fragmented message. */ ssf->ssf_info.sinfo_flags = chunk->chunk_hdr->flags; diff --git a/sound/aoa/codecs/tas.c b/sound/aoa/codecs/tas.c index 58804c7..fd2188c 100644 --- a/sound/aoa/codecs/tas.c +++ b/sound/aoa/codecs/tas.c @@ -170,7 +170,7 @@ static void tas_set_volume(struct tas *tas) /* analysing the volume and mixer tables shows * that they are similar enough when we shift * the mixer table down by 4 bits. The error - * is minuscule, in just one item the error + * is miniscule, in just one item the error * is 1, at a value of 0x07f17b (mixer table * value is 0x07f17a) */ tmp = tas_gaintable[left]; -- cgit v0.10.2 From bf5192edcbc1f0a7f9c054649dbf1a0b3210d9b7 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Fri, 22 Apr 2011 07:51:33 +1000 Subject: drm: select FRAMEBUFFER_CONSOLE_PRIMARY if we have FRAMEBUFFER_CONSOLE Multi-gpu/switcheroo relies on this option to get the console on the correct GPU at bootup, some distros enable it but it seems some get it wrong. cc: stable@kernel.org Signed-off-by: Dave Airlie diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig index c58f691..b493663 100644 --- a/drivers/gpu/drm/Kconfig +++ b/drivers/gpu/drm/Kconfig @@ -24,6 +24,7 @@ config DRM_KMS_HELPER depends on DRM select FB select FRAMEBUFFER_CONSOLE if !EXPERT + select FRAMEBUFFER_CONSOLE_DETECT_PRIMARY if FRAMEBUFFER_CONSOLE help FB and CRTC helpers for KMS drivers. -- cgit v0.10.2 From 834f0c353ae430c1a6ce023c9b77bbd3ff9241a7 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Tue, 26 Apr 2011 13:10:20 -0400 Subject: drm/radeon/kms: add missing safe regs for 6xx/7xx needed for HiS in mesa. Signed-off-by: Alex Deucher Signed-off-by: Dave Airlie diff --git a/drivers/gpu/drm/radeon/reg_srcs/r600 b/drivers/gpu/drm/radeon/reg_srcs/r600 index af0da4a..92f1900 100644 --- a/drivers/gpu/drm/radeon/reg_srcs/r600 +++ b/drivers/gpu/drm/radeon/reg_srcs/r600 @@ -708,6 +708,7 @@ r600 0x9400 0x00028D0C DB_RENDER_CONTROL 0x00028D10 DB_RENDER_OVERRIDE 0x0002880C DB_SHADER_CONTROL +0x00028D28 DB_SRESULTS_COMPARE_STATE0 0x00028D2C DB_SRESULTS_COMPARE_STATE1 0x00028430 DB_STENCILREFMASK 0x00028434 DB_STENCILREFMASK_BF -- cgit v0.10.2 From 6565945b60922211c299968ba66a66617af32c9f Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Tue, 26 Apr 2011 13:27:43 -0400 Subject: drm/radeon/kms: add info query for tile pipes needed by mesa for htile setup. Signed-off-by: Alex Deucher Signed-off-by: Dave Airlie diff --git a/drivers/gpu/drm/radeon/radeon_kms.c b/drivers/gpu/drm/radeon/radeon_kms.c index bf7d4c0..871df03 100644 --- a/drivers/gpu/drm/radeon/radeon_kms.c +++ b/drivers/gpu/drm/radeon/radeon_kms.c @@ -221,6 +221,19 @@ int radeon_info_ioctl(struct drm_device *dev, void *data, struct drm_file *filp) return -EINVAL; } break; + case RADEON_INFO_NUM_TILE_PIPES: + if (rdev->family >= CHIP_CAYMAN) + value = rdev->config.cayman.max_tile_pipes; + else if (rdev->family >= CHIP_CEDAR) + value = rdev->config.evergreen.max_tile_pipes; + else if (rdev->family >= CHIP_RV770) + value = rdev->config.rv770.max_tile_pipes; + else if (rdev->family >= CHIP_R600) + value = rdev->config.r600.max_tile_pipes; + else { + return -EINVAL; + } + break; default: DRM_DEBUG_KMS("Invalid request %d\n", info->request); return -EINVAL; diff --git a/include/drm/radeon_drm.h b/include/drm/radeon_drm.h index 3bce1a4..7aa5ddd 100644 --- a/include/drm/radeon_drm.h +++ b/include/drm/radeon_drm.h @@ -909,6 +909,7 @@ struct drm_radeon_cs { #define RADEON_INFO_WANT_CMASK 0x08 /* get access to CMASK on r300 */ #define RADEON_INFO_CLOCK_CRYSTAL_FREQ 0x09 /* clock crystal frequency */ #define RADEON_INFO_NUM_BACKENDS 0x0a /* DB/backends for r600+ - need for OQ */ +#define RADEON_INFO_NUM_TILE_PIPES 0x0b /* tile pipes for r600+ */ struct drm_radeon_info { uint32_t request; -- cgit v0.10.2 From ed961581a7ca91d6a4852af2e44333e983100505 Mon Sep 17 00:00:00 2001 From: Martin Schwidefsky Date: Wed, 27 Apr 2011 09:34:33 +0200 Subject: [S390] prng: fix pointer arithmetic The git commit c708c57e247775928b9a6bce7b4d8d14883bf39b fixed the access beyond the end of the stack in prng_seed but the pointer arithmetic is still incorrect. The calculation has been off by a factor of 64, now it is only off by a factor of 8. prng_seed is called with a maximum of 16 for nbytes, small enough that the incorrect calculation stays insides the limits of the stack. Place parentheses for correct pointer arithmetic. Signed-off-by: Martin Schwidefsky diff --git a/arch/s390/crypto/prng.c b/arch/s390/crypto/prng.c index 44bca3f..8b16c47 100644 --- a/arch/s390/crypto/prng.c +++ b/arch/s390/crypto/prng.c @@ -76,7 +76,7 @@ static void prng_seed(int nbytes) /* Add the entropy */ while (nbytes >= 8) { - *((__u64 *)parm_block) ^= *((__u64 *)buf+i); + *((__u64 *)parm_block) ^= *((__u64 *)(buf+i)); prng_add_entropy(); i += 8; nbytes -= 8; -- cgit v0.10.2 From e8e7a2b8ccfdae0d4cb6bd25824bbedcd42da316 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Thu, 21 Apr 2011 22:18:32 +0100 Subject: drm/i915: restore only the mode of this driver on lastclose (v2) i915 calls the panic handler function on last close to reset the modes, however this is a really bad idea for multi-gpu machines, esp shareable gpus machines. So add a new entry point for the driver to just restore its own fbcon mode. v2: move code into fb helper, fix panic code to block mode change on powered off GPUs. [airlied: this hits drm core and I wrote it and it was reviewed on intel-gfx so really I signed it off twice ;-).] Signed-off-by: Chris Wilson Signed-off-by: Dave Airlie diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c index 9507204..11d7a72 100644 --- a/drivers/gpu/drm/drm_fb_helper.c +++ b/drivers/gpu/drm/drm_fb_helper.c @@ -342,9 +342,22 @@ int drm_fb_helper_debug_leave(struct fb_info *info) } EXPORT_SYMBOL(drm_fb_helper_debug_leave); +bool drm_fb_helper_restore_fbdev_mode(struct drm_fb_helper *fb_helper) +{ + bool error = false; + int i, ret; + for (i = 0; i < fb_helper->crtc_count; i++) { + struct drm_mode_set *mode_set = &fb_helper->crtc_info[i].mode_set; + ret = drm_crtc_helper_set_config(mode_set); + if (ret) + error = true; + } + return error; +} +EXPORT_SYMBOL(drm_fb_helper_restore_fbdev_mode); + bool drm_fb_helper_force_kernel_mode(void) { - int i = 0; bool ret, error = false; struct drm_fb_helper *helper; @@ -352,12 +365,12 @@ bool drm_fb_helper_force_kernel_mode(void) return false; list_for_each_entry(helper, &kernel_fb_helper_list, kernel_fb_list) { - for (i = 0; i < helper->crtc_count; i++) { - struct drm_mode_set *mode_set = &helper->crtc_info[i].mode_set; - ret = drm_crtc_helper_set_config(mode_set); - if (ret) - error = true; - } + if (helper->dev->switch_power_state == DRM_SWITCH_POWER_OFF) + continue; + + ret = drm_fb_helper_restore_fbdev_mode(helper); + if (ret) + error = true; } return error; } diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c index 7273037..12876f2 100644 --- a/drivers/gpu/drm/i915/i915_dma.c +++ b/drivers/gpu/drm/i915/i915_dma.c @@ -2207,7 +2207,7 @@ void i915_driver_lastclose(struct drm_device * dev) drm_i915_private_t *dev_priv = dev->dev_private; if (!dev_priv || drm_core_check_feature(dev, DRIVER_MODESET)) { - drm_fb_helper_restore(); + intel_fb_restore_mode(dev); vga_switcheroo_process_delayed_switch(); return; } diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index f5b0d83..1d20712 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -338,4 +338,5 @@ extern int intel_overlay_attrs(struct drm_device *dev, void *data, struct drm_file *file_priv); extern void intel_fb_output_poll_changed(struct drm_device *dev); +extern void intel_fb_restore_mode(struct drm_device *dev); #endif /* __INTEL_DRV_H__ */ diff --git a/drivers/gpu/drm/i915/intel_fb.c b/drivers/gpu/drm/i915/intel_fb.c index 5127827..ec49bae 100644 --- a/drivers/gpu/drm/i915/intel_fb.c +++ b/drivers/gpu/drm/i915/intel_fb.c @@ -264,3 +264,13 @@ void intel_fb_output_poll_changed(struct drm_device *dev) drm_i915_private_t *dev_priv = dev->dev_private; drm_fb_helper_hotplug_event(&dev_priv->fbdev->helper); } + +void intel_fb_restore_mode(struct drm_device *dev) +{ + int ret; + drm_i915_private_t *dev_priv = dev->dev_private; + + ret = drm_fb_helper_restore_fbdev_mode(&dev_priv->fbdev->helper); + if (ret) + DRM_DEBUG("failed to restore crtc mode\n"); +} diff --git a/include/drm/drm_fb_helper.h b/include/drm/drm_fb_helper.h index f22e7fe..ade09d7 100644 --- a/include/drm/drm_fb_helper.h +++ b/include/drm/drm_fb_helper.h @@ -118,6 +118,7 @@ int drm_fb_helper_setcolreg(unsigned regno, unsigned transp, struct fb_info *info); +bool drm_fb_helper_restore_fbdev_mode(struct drm_fb_helper *fb_helper); void drm_fb_helper_restore(void); void drm_fb_helper_fill_var(struct fb_info *info, struct drm_fb_helper *fb_helper, uint32_t fb_width, uint32_t fb_height); -- cgit v0.10.2 From dbf80dcbd8ca0c50f343401fedd2d6200cb8097e Mon Sep 17 00:00:00 2001 From: Bruce Allan Date: Sat, 16 Apr 2011 00:34:40 +0000 Subject: e1000e: implement ethtool set_phys_id Based on a patch from Stephen Hemminger . The new ethtool set_phys_id takes over controlling the LED for identifying boards. This fixes the lockout during that period. For this device lots of extra infrastructure can also be removed by using set_phys_id. v2: - return blink frequency for parts that do not support blink in h/w - add blink_led function pointers for devices that do support blink in h/w to cleanup the test for this functionality Signed-off-by: Bruce Allan Cc: Stephen Hemminger Tested-by: Aaron Brown Signed-off-by: Jeff Kirsher diff --git a/drivers/net/e1000e/82571.c b/drivers/net/e1000e/82571.c index ae07d37..8295f21 100644 --- a/drivers/net/e1000e/82571.c +++ b/drivers/net/e1000e/82571.c @@ -300,6 +300,7 @@ static s32 e1000_init_mac_params_82571(struct e1000_adapter *adapter) func->set_lan_id = e1000_set_lan_id_single_port; func->check_mng_mode = e1000e_check_mng_mode_generic; func->led_on = e1000e_led_on_generic; + func->blink_led = e1000e_blink_led_generic; /* FWSM register */ mac->has_fwsm = true; @@ -320,6 +321,7 @@ static s32 e1000_init_mac_params_82571(struct e1000_adapter *adapter) default: func->check_mng_mode = e1000e_check_mng_mode_generic; func->led_on = e1000e_led_on_generic; + func->blink_led = e1000e_blink_led_generic; /* FWSM register */ mac->has_fwsm = true; diff --git a/drivers/net/e1000e/e1000.h b/drivers/net/e1000e/e1000.h index 3be5478..9549879 100644 --- a/drivers/net/e1000e/e1000.h +++ b/drivers/net/e1000e/e1000.h @@ -391,13 +391,10 @@ struct e1000_adapter { bool fc_autoneg; - unsigned long led_status; - unsigned int flags; unsigned int flags2; struct work_struct downshift_task; struct work_struct update_phy_task; - struct work_struct led_blink_task; struct work_struct print_hang_task; bool idle_check; @@ -487,7 +484,6 @@ extern const char e1000e_driver_version[]; extern void e1000e_check_options(struct e1000_adapter *adapter); extern void e1000e_set_ethtool_ops(struct net_device *netdev); -extern void e1000e_led_blink_task(struct work_struct *work); extern int e1000e_up(struct e1000_adapter *adapter); extern void e1000e_down(struct e1000_adapter *adapter); @@ -575,7 +571,7 @@ extern s32 e1000e_valid_led_default(struct e1000_hw *hw, u16 *data); extern void e1000e_config_collision_dist(struct e1000_hw *hw); extern s32 e1000e_config_fc_after_link_up(struct e1000_hw *hw); extern s32 e1000e_force_mac_fc(struct e1000_hw *hw); -extern s32 e1000e_blink_led(struct e1000_hw *hw); +extern s32 e1000e_blink_led_generic(struct e1000_hw *hw); extern void e1000_write_vfta_generic(struct e1000_hw *hw, u32 offset, u32 value); extern s32 e1000_check_alt_mac_addr_generic(struct e1000_hw *hw); extern void e1000e_reset_adaptive(struct e1000_hw *hw); diff --git a/drivers/net/e1000e/es2lan.c b/drivers/net/e1000e/es2lan.c index 0279695..f4bbeb2 100644 --- a/drivers/net/e1000e/es2lan.c +++ b/drivers/net/e1000e/es2lan.c @@ -1434,6 +1434,7 @@ static void e1000_clear_hw_cntrs_80003es2lan(struct e1000_hw *hw) static struct e1000_mac_operations es2_mac_ops = { .read_mac_addr = e1000_read_mac_addr_80003es2lan, .id_led_init = e1000e_id_led_init, + .blink_led = e1000e_blink_led_generic, .check_mng_mode = e1000e_check_mng_mode_generic, /* check_for_link dependent on media type */ .cleanup_led = e1000e_cleanup_led_generic, diff --git a/drivers/net/e1000e/ethtool.c b/drivers/net/e1000e/ethtool.c index a31d280..1d7bf40 100644 --- a/drivers/net/e1000e/ethtool.c +++ b/drivers/net/e1000e/ethtool.c @@ -1851,64 +1851,35 @@ static int e1000_set_wol(struct net_device *netdev, struct ethtool_wolinfo *wol) return 0; } -/* toggle LED 4 times per second = 2 "blinks" per second */ -#define E1000_ID_INTERVAL (HZ/4) - -/* bit defines for adapter->led_status */ -#define E1000_LED_ON 0 - -void e1000e_led_blink_task(struct work_struct *work) -{ - struct e1000_adapter *adapter = container_of(work, - struct e1000_adapter, led_blink_task); - - if (test_and_change_bit(E1000_LED_ON, &adapter->led_status)) - adapter->hw.mac.ops.led_off(&adapter->hw); - else - adapter->hw.mac.ops.led_on(&adapter->hw); -} - -static void e1000_led_blink_callback(unsigned long data) -{ - struct e1000_adapter *adapter = (struct e1000_adapter *) data; - - schedule_work(&adapter->led_blink_task); - mod_timer(&adapter->blink_timer, jiffies + E1000_ID_INTERVAL); -} - -static int e1000_phys_id(struct net_device *netdev, u32 data) +static int e1000_set_phys_id(struct net_device *netdev, + enum ethtool_phys_id_state state) { struct e1000_adapter *adapter = netdev_priv(netdev); struct e1000_hw *hw = &adapter->hw; - if (!data) - data = INT_MAX; + switch (state) { + case ETHTOOL_ID_ACTIVE: + if (!hw->mac.ops.blink_led) + return 2; /* cycle on/off twice per second */ - if ((hw->phy.type == e1000_phy_ife) || - (hw->mac.type == e1000_pchlan) || - (hw->mac.type == e1000_pch2lan) || - (hw->mac.type == e1000_82583) || - (hw->mac.type == e1000_82574)) { - if (!adapter->blink_timer.function) { - init_timer(&adapter->blink_timer); - adapter->blink_timer.function = - e1000_led_blink_callback; - adapter->blink_timer.data = (unsigned long) adapter; - } - mod_timer(&adapter->blink_timer, jiffies); - msleep_interruptible(data * 1000); - del_timer_sync(&adapter->blink_timer); + hw->mac.ops.blink_led(hw); + break; + + case ETHTOOL_ID_INACTIVE: if (hw->phy.type == e1000_phy_ife) e1e_wphy(hw, IFE_PHY_SPECIAL_CONTROL_LED, 0); - } else { - e1000e_blink_led(hw); - msleep_interruptible(data * 1000); - } + hw->mac.ops.led_off(hw); + hw->mac.ops.cleanup_led(hw); + break; - hw->mac.ops.led_off(hw); - clear_bit(E1000_LED_ON, &adapter->led_status); - hw->mac.ops.cleanup_led(hw); + case ETHTOOL_ID_ON: + adapter->hw.mac.ops.led_on(&adapter->hw); + break; + case ETHTOOL_ID_OFF: + adapter->hw.mac.ops.led_off(&adapter->hw); + break; + } return 0; } @@ -2074,7 +2045,7 @@ static const struct ethtool_ops e1000_ethtool_ops = { .set_tso = e1000_set_tso, .self_test = e1000_diag_test, .get_strings = e1000_get_strings, - .phys_id = e1000_phys_id, + .set_phys_id = e1000_set_phys_id, .get_ethtool_stats = e1000_get_ethtool_stats, .get_sset_count = e1000e_get_sset_count, .get_coalesce = e1000_get_coalesce, diff --git a/drivers/net/e1000e/hw.h b/drivers/net/e1000e/hw.h index 307e1ec..6c2fa83 100644 --- a/drivers/net/e1000e/hw.h +++ b/drivers/net/e1000e/hw.h @@ -756,6 +756,7 @@ struct e1000_host_mng_command_info { /* Function pointers and static data for the MAC. */ struct e1000_mac_operations { s32 (*id_led_init)(struct e1000_hw *); + s32 (*blink_led)(struct e1000_hw *); bool (*check_mng_mode)(struct e1000_hw *); s32 (*check_for_link)(struct e1000_hw *); s32 (*cleanup_led)(struct e1000_hw *); diff --git a/drivers/net/e1000e/ich8lan.c b/drivers/net/e1000e/ich8lan.c index 06ff884..3369d1f 100644 --- a/drivers/net/e1000e/ich8lan.c +++ b/drivers/net/e1000e/ich8lan.c @@ -564,6 +564,8 @@ static s32 e1000_init_mac_params_ich8lan(struct e1000_adapter *adapter) mac->ops.check_mng_mode = e1000_check_mng_mode_ich8lan; /* ID LED init */ mac->ops.id_led_init = e1000e_id_led_init; + /* blink LED */ + mac->ops.blink_led = e1000e_blink_led_generic; /* setup LED */ mac->ops.setup_led = e1000e_setup_led_generic; /* cleanup LED */ @@ -767,6 +769,8 @@ static s32 e1000_get_variants_ich8lan(struct e1000_adapter *adapter) (!(er32(CTRL_EXT) & E1000_CTRL_EXT_LSECCK)))) { adapter->flags &= ~FLAG_HAS_JUMBO_FRAMES; adapter->max_hw_frame_size = ETH_FRAME_LEN + ETH_FCS_LEN; + + hw->mac.ops.blink_led = NULL; } if ((adapter->hw.mac.type == e1000_ich8lan) && diff --git a/drivers/net/e1000e/lib.c b/drivers/net/e1000e/lib.c index 30ef8fa..6432dda 100644 --- a/drivers/net/e1000e/lib.c +++ b/drivers/net/e1000e/lib.c @@ -1530,12 +1530,12 @@ s32 e1000e_cleanup_led_generic(struct e1000_hw *hw) } /** - * e1000e_blink_led - Blink LED + * e1000e_blink_led_generic - Blink LED * @hw: pointer to the HW structure * * Blink the LEDs which are set to be on. **/ -s32 e1000e_blink_led(struct e1000_hw *hw) +s32 e1000e_blink_led_generic(struct e1000_hw *hw) { u32 ledctl_blink = 0; u32 i; diff --git a/drivers/net/e1000e/netdev.c b/drivers/net/e1000e/netdev.c index 4deb67d..0939040 100644 --- a/drivers/net/e1000e/netdev.c +++ b/drivers/net/e1000e/netdev.c @@ -6020,7 +6020,6 @@ static int __devinit e1000_probe(struct pci_dev *pdev, INIT_WORK(&adapter->downshift_task, e1000e_downshift_workaround); INIT_WORK(&adapter->update_phy_task, e1000e_update_phy_task); INIT_WORK(&adapter->print_hang_task, e1000_print_hw_hang); - INIT_WORK(&adapter->led_blink_task, e1000e_led_blink_task); /* Initialize link parameters. User can change them with ethtool */ adapter->hw.mac.autoneg = 1; @@ -6153,7 +6152,6 @@ static void __devexit e1000_remove(struct pci_dev *pdev) cancel_work_sync(&adapter->watchdog_task); cancel_work_sync(&adapter->downshift_task); cancel_work_sync(&adapter->update_phy_task); - cancel_work_sync(&adapter->led_blink_task); cancel_work_sync(&adapter->print_hang_task); if (!(netdev->flags & IFF_UP)) -- cgit v0.10.2 From 50c022e7936354d854091ebdc699872d3432e874 Mon Sep 17 00:00:00 2001 From: Emil Tantilov Date: Thu, 31 Mar 2011 09:36:12 +0000 Subject: ixgbe: explicitly disable 100H for x540 100H is not supported on this HW, but the bit is set on the PHY. This can result in link at 100F when advertising only 1000F. Signed-off-by: Emil Tantilov Tested-by: Evan Swanson Signed-off-by: Jeff Kirsher diff --git a/drivers/net/ixgbe/ixgbe_phy.c b/drivers/net/ixgbe/ixgbe_phy.c index fd381ea..edcaaeb 100644 --- a/drivers/net/ixgbe/ixgbe_phy.c +++ b/drivers/net/ixgbe/ixgbe_phy.c @@ -657,7 +657,8 @@ s32 ixgbe_setup_phy_link_tnx(struct ixgbe_hw *hw) MDIO_MMD_AN, &autoneg_reg); - autoneg_reg &= ~ADVERTISE_100FULL; + autoneg_reg &= ~(ADVERTISE_100FULL | + ADVERTISE_100HALF); if (hw->phy.autoneg_advertised & IXGBE_LINK_SPEED_100_FULL) autoneg_reg |= ADVERTISE_100FULL; -- cgit v0.10.2 From 83dfde405322320d538b7087ba741fc9a4780161 Mon Sep 17 00:00:00 2001 From: Emil Tantilov Date: Thu, 31 Mar 2011 09:36:24 +0000 Subject: ixgbe: register defines cleanup Remove duplicates. Fix incorrect defines. Fix/Update comments. Fix whitespace. Add new register defines. Signed-off-by: Emil Tantilov Tested-by: Evan Swanson Signed-off-by: Jeff Kirsher diff --git a/drivers/net/ixgbe/ixgbe_mbx.h b/drivers/net/ixgbe/ixgbe_mbx.h index fe6ea81..f53dc5b 100644 --- a/drivers/net/ixgbe/ixgbe_mbx.h +++ b/drivers/net/ixgbe/ixgbe_mbx.h @@ -36,9 +36,6 @@ #define IXGBE_VFMAILBOX 0x002FC #define IXGBE_VFMBMEM 0x00200 -#define IXGBE_PFMAILBOX(x) (0x04B00 + (4 * x)) -#define IXGBE_PFMBMEM(vfn) (0x13000 + (64 * vfn)) - #define IXGBE_PFMAILBOX_STS 0x00000001 /* Initiate message send to VF */ #define IXGBE_PFMAILBOX_ACK 0x00000002 /* Ack message recv'd from VF */ #define IXGBE_PFMAILBOX_VFU 0x00000004 /* VF owns the mailbox buffer */ diff --git a/drivers/net/ixgbe/ixgbe_type.h b/drivers/net/ixgbe/ixgbe_type.h index f5bec97..fab9737 100644 --- a/drivers/net/ixgbe/ixgbe_type.h +++ b/drivers/net/ixgbe/ixgbe_type.h @@ -164,6 +164,9 @@ (0x0D018 + ((_i - 64) * 0x40))) #define IXGBE_RXDCTL(_i) (((_i) < 64) ? (0x01028 + ((_i) * 0x40)) : \ (0x0D028 + ((_i - 64) * 0x40))) +#define IXGBE_RSCCTL(_i) (((_i) < 64) ? (0x0102C + ((_i) * 0x40)) : \ + (0x0D02C + ((_i - 64) * 0x40))) +#define IXGBE_RSCDBU 0x03028 #define IXGBE_RDDCC 0x02F20 #define IXGBE_RXMEMWRAP 0x03190 #define IXGBE_STARCTRL 0x03024 @@ -228,17 +231,23 @@ #define IXGBE_VLVF(_i) (0x0F100 + ((_i) * 4)) /* 64 of these (0-63) */ #define IXGBE_VLVFB(_i) (0x0F200 + ((_i) * 4)) /* 128 of these (0-127) */ #define IXGBE_VMVIR(_i) (0x08000 + ((_i) * 4)) /* 64 of these (0-63) */ -#define IXGBE_VT_CTL 0x051B0 -#define IXGBE_VFRE(_i) (0x051E0 + ((_i) * 4)) -#define IXGBE_VFTE(_i) (0x08110 + ((_i) * 4)) -#define IXGBE_VMECM(_i) (0x08790 + ((_i) * 4)) -#define IXGBE_QDE 0x2F04 -#define IXGBE_VMOLR(_i) (0x0F000 + ((_i) * 4)) /* 64 total */ -#define IXGBE_UTA(_i) (0x0F400 + ((_i) * 4)) -#define IXGBE_VMRCTL(_i) (0x0F600 + ((_i) * 4)) -#define IXGBE_VMRVLAN(_i) (0x0F610 + ((_i) * 4)) -#define IXGBE_VMRVM(_i) (0x0F630 + ((_i) * 4)) -#define IXGBE_L34T_IMIR(_i) (0x0E800 + ((_i) * 4)) /*128 of these (0-127)*/ +#define IXGBE_VT_CTL 0x051B0 +#define IXGBE_PFMAILBOX(_i) (0x04B00 + (4 * (_i))) /* 64 total */ +#define IXGBE_PFMBMEM(_i) (0x13000 + (64 * (_i))) /* 64 Mailboxes, 16 DW each */ +#define IXGBE_PFMBICR(_i) (0x00710 + (4 * (_i))) /* 4 total */ +#define IXGBE_PFMBIMR(_i) (0x00720 + (4 * (_i))) /* 4 total */ +#define IXGBE_VFRE(_i) (0x051E0 + ((_i) * 4)) +#define IXGBE_VFTE(_i) (0x08110 + ((_i) * 4)) +#define IXGBE_VMECM(_i) (0x08790 + ((_i) * 4)) +#define IXGBE_QDE 0x2F04 +#define IXGBE_VMTXSW(_i) (0x05180 + ((_i) * 4)) /* 2 total */ +#define IXGBE_VMOLR(_i) (0x0F000 + ((_i) * 4)) /* 64 total */ +#define IXGBE_UTA(_i) (0x0F400 + ((_i) * 4)) +#define IXGBE_MRCTL(_i) (0x0F600 + ((_i) * 4)) +#define IXGBE_VMRVLAN(_i) (0x0F610 + ((_i) * 4)) +#define IXGBE_VMRVM(_i) (0x0F630 + ((_i) * 4)) +#define IXGBE_L34T_IMIR(_i) (0x0E800 + ((_i) * 4)) /*128 of these (0-127)*/ +#define IXGBE_RXFECCERR0 0x051B8 #define IXGBE_LLITHRESH 0x0EC90 #define IXGBE_IMIR(_i) (0x05A80 + ((_i) * 4)) /* 8 of these (0-7) */ #define IXGBE_IMIREXT(_i) (0x05AA0 + ((_i) * 4)) /* 8 of these (0-7) */ @@ -365,7 +374,7 @@ #define IXGBE_WUFC_FLX5 0x00200000 /* Flexible Filter 5 Enable */ #define IXGBE_WUFC_FLX_FILTERS 0x000F0000 /* Mask for 4 flex filters */ #define IXGBE_WUFC_EXT_FLX_FILTERS 0x00300000 /* Mask for Ext. flex filters */ -#define IXGBE_WUFC_ALL_FILTERS 0x003F00FF /* Mask for all 6 wakeup filters*/ +#define IXGBE_WUFC_ALL_FILTERS 0x003F00FF /* Mask for all wakeup filters */ #define IXGBE_WUFC_FLX_OFFSET 16 /* Offset to the Flexible Filters bits */ /* Wake Up Status */ @@ -407,7 +416,6 @@ #define IXGBE_SECTXSTAT 0x08804 #define IXGBE_SECTXBUFFAF 0x08808 #define IXGBE_SECTXMINIFG 0x08810 -#define IXGBE_SECTXSTAT 0x08804 #define IXGBE_SECRXCTRL 0x08D00 #define IXGBE_SECRXSTAT 0x08D04 @@ -500,21 +508,6 @@ #define IXGBE_SECTXCTRL_STORE_FORWARD_ENABLE 0x4 -/* HW RSC registers */ -#define IXGBE_RSCCTL(_i) (((_i) < 64) ? (0x0102C + ((_i) * 0x40)) : \ - (0x0D02C + ((_i - 64) * 0x40))) -#define IXGBE_RSCDBU 0x03028 -#define IXGBE_RSCCTL_RSCEN 0x01 -#define IXGBE_RSCCTL_MAXDESC_1 0x00 -#define IXGBE_RSCCTL_MAXDESC_4 0x04 -#define IXGBE_RSCCTL_MAXDESC_8 0x08 -#define IXGBE_RSCCTL_MAXDESC_16 0x0C -#define IXGBE_RXDADV_RSCCNT_SHIFT 17 -#define IXGBE_GPIE_RSC_DELAY_SHIFT 11 -#define IXGBE_RXDADV_RSCCNT_MASK 0x001E0000 -#define IXGBE_RSCDBU_RSCACKDIS 0x00000080 -#define IXGBE_RDRXCTL_RSCFRSTSIZE 0x003E0000 - /* DCB registers */ #define IXGBE_RTRPCS 0x02430 #define IXGBE_RTTDCS 0x04900 @@ -523,6 +516,7 @@ #define IXGBE_RTRUP2TC 0x03020 #define IXGBE_RTTUP2TC 0x0C800 #define IXGBE_RTRPT4C(_i) (0x02140 + ((_i) * 4)) /* 8 of these (0-7) */ +#define IXGBE_TXLLQ(_i) (0x082E0 + ((_i) * 4)) /* 4 of these (0-3) */ #define IXGBE_RTRPT4S(_i) (0x02160 + ((_i) * 4)) /* 8 of these (0-7) */ #define IXGBE_RTTDT2C(_i) (0x04910 + ((_i) * 4)) /* 8 of these (0-7) */ #define IXGBE_RTTDT2S(_i) (0x04930 + ((_i) * 4)) /* 8 of these (0-7) */ @@ -541,7 +535,7 @@ (IXGBE_RTTBCNRC_RF_DEC_MASK << IXGBE_RTTBCNRC_RF_INT_SHIFT) -/* FCoE registers */ +/* FCoE DMA Context Registers */ #define IXGBE_FCPTRL 0x02410 /* FC User Desc. PTR Low */ #define IXGBE_FCPTRH 0x02414 /* FC USer Desc. PTR High */ #define IXGBE_FCBUFF 0x02418 /* FC Buffer Control */ @@ -743,17 +737,10 @@ #define IXGBE_PBACLR_82599 0x11068 #define IXGBE_CIAA_82599 0x11088 #define IXGBE_CIAD_82599 0x1108C -#define IXGBE_PCIE_DIAG_0_82599 0x11090 -#define IXGBE_PCIE_DIAG_1_82599 0x11094 -#define IXGBE_PCIE_DIAG_2_82599 0x11098 -#define IXGBE_PCIE_DIAG_3_82599 0x1109C -#define IXGBE_PCIE_DIAG_4_82599 0x110A0 -#define IXGBE_PCIE_DIAG_5_82599 0x110A4 -#define IXGBE_PCIE_DIAG_6_82599 0x110A8 -#define IXGBE_PCIE_DIAG_7_82599 0x110C0 -#define IXGBE_INTRPT_CSR_82599 0x110B0 -#define IXGBE_INTRPT_MASK_82599 0x110B8 +#define IXGBE_PICAUSE 0x110B0 +#define IXGBE_PIENA 0x110B8 #define IXGBE_CDQ_MBR_82599 0x110B4 +#define IXGBE_PCIESPARE 0x110BC #define IXGBE_MISC_REG_82599 0x110F0 #define IXGBE_ECC_CTRL_0_82599 0x11100 #define IXGBE_ECC_CTRL_1_82599 0x11104 @@ -786,7 +773,19 @@ #define IXGBE_SYSTIML 0x08C0C /* System time register Low - RO */ #define IXGBE_SYSTIMH 0x08C10 /* System time register High - RO */ #define IXGBE_TIMINCA 0x08C14 /* Increment attributes register - RW */ -#define IXGBE_RXUDP 0x08C1C /* Time Sync Rx UDP Port - RW */ +#define IXGBE_TIMADJL 0x08C18 /* Time Adjustment Offset register Low - RW */ +#define IXGBE_TIMADJH 0x08C1C /* Time Adjustment Offset register High - RW */ +#define IXGBE_TSAUXC 0x08C20 /* TimeSync Auxiliary Control register - RW */ +#define IXGBE_TRGTTIML0 0x08C24 /* Target Time Register 0 Low - RW */ +#define IXGBE_TRGTTIMH0 0x08C28 /* Target Time Register 0 High - RW */ +#define IXGBE_TRGTTIML1 0x08C2C /* Target Time Register 1 Low - RW */ +#define IXGBE_TRGTTIMH1 0x08C30 /* Target Time Register 1 High - RW */ +#define IXGBE_FREQOUT0 0x08C34 /* Frequency Out 0 Control register - RW */ +#define IXGBE_FREQOUT1 0x08C38 /* Frequency Out 1 Control register - RW */ +#define IXGBE_AUXSTMPL0 0x08C3C /* Auxiliary Time Stamp 0 register Low - RO */ +#define IXGBE_AUXSTMPH0 0x08C40 /* Auxiliary Time Stamp 0 register High - RO */ +#define IXGBE_AUXSTMPL1 0x08C44 /* Auxiliary Time Stamp 1 register Low - RO */ +#define IXGBE_AUXSTMPH1 0x08C48 /* Auxiliary Time Stamp 1 register High - RO */ /* Diagnostic Registers */ #define IXGBE_RDSTATCTL 0x02C20 @@ -830,8 +829,20 @@ #define IXGBE_TXDATARDPTR(_i) (0x0C720 + ((_i) * 4)) /* 8 of these C720-C72C*/ #define IXGBE_TXDESCRDPTR(_i) (0x0C730 + ((_i) * 4)) /* 8 of these C730-C73C*/ #define IXGBE_PCIEECCCTL 0x1106C +#define IXGBE_RXWRPTR(_i) (0x03100 + ((_i) * 4)) /* 8 of these 3100-310C*/ +#define IXGBE_RXUSED(_i) (0x03120 + ((_i) * 4)) /* 8 of these 3120-312C*/ +#define IXGBE_RXRDPTR(_i) (0x03140 + ((_i) * 4)) /* 8 of these 3140-314C*/ +#define IXGBE_RXRDWRPTR(_i) (0x03160 + ((_i) * 4)) /* 8 of these 3160-310C*/ +#define IXGBE_TXWRPTR(_i) (0x0C100 + ((_i) * 4)) /* 8 of these C100-C10C*/ +#define IXGBE_TXUSED(_i) (0x0C120 + ((_i) * 4)) /* 8 of these C120-C12C*/ +#define IXGBE_TXRDPTR(_i) (0x0C140 + ((_i) * 4)) /* 8 of these C140-C14C*/ +#define IXGBE_TXRDWRPTR(_i) (0x0C160 + ((_i) * 4)) /* 8 of these C160-C10C*/ #define IXGBE_PCIEECCCTL0 0x11100 #define IXGBE_PCIEECCCTL1 0x11104 +#define IXGBE_RXDBUECC 0x03F70 +#define IXGBE_TXDBUECC 0x0CF70 +#define IXGBE_RXDBUEST 0x03F74 +#define IXGBE_TXDBUEST 0x0CF74 #define IXGBE_PBTXECC 0x0C300 #define IXGBE_PBRXECC 0x03300 #define IXGBE_GHECCR 0x110B0 @@ -872,6 +883,7 @@ #define IXGBE_AUTOC3 0x042AC #define IXGBE_ANLP1 0x042B0 #define IXGBE_ANLP2 0x042B4 +#define IXGBE_MACC 0x04330 #define IXGBE_ATLASCTL 0x04800 #define IXGBE_MMNGC 0x042D0 #define IXGBE_ANLPNP1 0x042D4 @@ -884,14 +896,49 @@ #define IXGBE_MPVC 0x04318 #define IXGBE_SGMIIC 0x04314 +/* Statistics Registers */ +#define IXGBE_RXNFGPC 0x041B0 +#define IXGBE_RXNFGBCL 0x041B4 +#define IXGBE_RXNFGBCH 0x041B8 +#define IXGBE_RXDGPC 0x02F50 +#define IXGBE_RXDGBCL 0x02F54 +#define IXGBE_RXDGBCH 0x02F58 +#define IXGBE_RXDDGPC 0x02F5C +#define IXGBE_RXDDGBCL 0x02F60 +#define IXGBE_RXDDGBCH 0x02F64 +#define IXGBE_RXLPBKGPC 0x02F68 +#define IXGBE_RXLPBKGBCL 0x02F6C +#define IXGBE_RXLPBKGBCH 0x02F70 +#define IXGBE_RXDLPBKGPC 0x02F74 +#define IXGBE_RXDLPBKGBCL 0x02F78 +#define IXGBE_RXDLPBKGBCH 0x02F7C +#define IXGBE_TXDGPC 0x087A0 +#define IXGBE_TXDGBCL 0x087A4 +#define IXGBE_TXDGBCH 0x087A8 + +#define IXGBE_RXDSTATCTRL 0x02F40 + +/* Copper Pond 2 link timeout */ #define IXGBE_VALIDATE_LINK_READY_TIMEOUT 50 /* Omer CORECTL */ #define IXGBE_CORECTL 0x014F00 /* BARCTRL */ -#define IXGBE_BARCTRL 0x110F4 -#define IXGBE_BARCTRL_FLSIZE 0x0700 -#define IXGBE_BARCTRL_CSRSIZE 0x2000 +#define IXGBE_BARCTRL 0x110F4 +#define IXGBE_BARCTRL_FLSIZE 0x0700 +#define IXGBE_BARCTRL_FLSIZE_SHIFT 8 +#define IXGBE_BARCTRL_CSRSIZE 0x2000 + +/* RSCCTL Bit Masks */ +#define IXGBE_RSCCTL_RSCEN 0x01 +#define IXGBE_RSCCTL_MAXDESC_1 0x00 +#define IXGBE_RSCCTL_MAXDESC_4 0x04 +#define IXGBE_RSCCTL_MAXDESC_8 0x08 +#define IXGBE_RSCCTL_MAXDESC_16 0x0C + +/* RSCDBU Bit Masks */ +#define IXGBE_RSCDBU_RSCSMALDIS_MASK 0x0000007F +#define IXGBE_RSCDBU_RSCACKDIS 0x00000080 /* RDRXCTL Bit Masks */ #define IXGBE_RDRXCTL_RDMTS_1_2 0x00000000 /* Rx Desc Min Threshold Size */ @@ -899,6 +946,8 @@ #define IXGBE_RDRXCTL_MVMEN 0x00000020 #define IXGBE_RDRXCTL_DMAIDONE 0x00000008 /* DMA init cycle done */ #define IXGBE_RDRXCTL_AGGDIS 0x00010000 /* Aggregation disable */ +#define IXGBE_RDRXCTL_RSCFRSTSIZE 0x003E0000 /* RSC First packet size */ +#define IXGBE_RDRXCTL_RSCLLIDIS 0x00800000 /* Disable RSC compl on LLI */ #define IXGBE_RDRXCTL_RSCACKC 0x02000000 /* must set 1 when RSC enabled */ #define IXGBE_RDRXCTL_FCOE_WRFIX 0x04000000 /* must set 1 when RSC enabled */ @@ -970,8 +1019,8 @@ #define IXGBE_MSCA_OP_CODE_SHIFT 26 /* OP CODE shift */ #define IXGBE_MSCA_ADDR_CYCLE 0x00000000 /* OP CODE 00 (addr cycle) */ #define IXGBE_MSCA_WRITE 0x04000000 /* OP CODE 01 (write) */ -#define IXGBE_MSCA_READ 0x08000000 /* OP CODE 10 (read) */ -#define IXGBE_MSCA_READ_AUTOINC 0x0C000000 /* OP CODE 11 (read, auto inc)*/ +#define IXGBE_MSCA_READ 0x0C000000 /* OP CODE 11 (read) */ +#define IXGBE_MSCA_READ_AUTOINC 0x08000000 /* OP CODE 10 (read, auto inc)*/ #define IXGBE_MSCA_ST_CODE_MASK 0x30000000 /* ST Code mask */ #define IXGBE_MSCA_ST_CODE_SHIFT 28 /* ST Code shift */ #define IXGBE_MSCA_NEW_PROTOCOL 0x00000000 /* ST CODE 00 (new protocol) */ @@ -1058,6 +1107,7 @@ #define IXGBE_GPIE_EIMEN 0x00000040 /* Immediate Interrupt Enable */ #define IXGBE_GPIE_EIAME 0x40000000 #define IXGBE_GPIE_PBA_SUPPORT 0x80000000 +#define IXGBE_GPIE_RSC_DELAY_SHIFT 11 #define IXGBE_GPIE_VTMODE_MASK 0x0000C000 /* VT Mode Mask */ #define IXGBE_GPIE_VTMODE_16 0x00004000 /* 16 VFs 8 queues per VF */ #define IXGBE_GPIE_VTMODE_32 0x00008000 /* 32 VFs 4 queues per VF */ @@ -1292,6 +1342,11 @@ #define IXGBE_FTQF_POOL_SHIFT 8 #define IXGBE_FTQF_5TUPLE_MASK_MASK 0x0000001F #define IXGBE_FTQF_5TUPLE_MASK_SHIFT 25 +#define IXGBE_FTQF_SOURCE_ADDR_MASK 0x1E +#define IXGBE_FTQF_DEST_ADDR_MASK 0x1D +#define IXGBE_FTQF_SOURCE_PORT_MASK 0x1B +#define IXGBE_FTQF_DEST_PORT_MASK 0x17 +#define IXGBE_FTQF_PROTOCOL_COMP_MASK 0x0F #define IXGBE_FTQF_POOL_MASK_EN 0x40000000 #define IXGBE_FTQF_QUEUE_ENABLE 0x80000000 @@ -1334,11 +1389,11 @@ * * Current filters: * EAPOL 802.1x (0x888e): Filter 0 - * BCN (0x8904): Filter 1 + * FCoE (0x8906): Filter 2 * 1588 (0x88f7): Filter 3 + * FIP (0x8914): Filter 4 */ #define IXGBE_ETQF_FILTER_EAPOL 0 -#define IXGBE_ETQF_FILTER_BCN 1 #define IXGBE_ETQF_FILTER_FCOE 2 #define IXGBE_ETQF_FILTER_1588 3 #define IXGBE_ETQF_FILTER_FIP 4 @@ -1449,6 +1504,11 @@ #define IXGBE_AUTOC2_10G_XFI (0x1 << IXGBE_AUTOC2_10G_SERIAL_PMA_PMD_SHIFT) #define IXGBE_AUTOC2_10G_SFI (0x2 << IXGBE_AUTOC2_10G_SERIAL_PMA_PMD_SHIFT) +#define IXGBE_MACC_FLU 0x00000001 +#define IXGBE_MACC_FSV_10G 0x00030000 +#define IXGBE_MACC_FS 0x00040000 +#define IXGBE_MAC_RX2TX_LPBK 0x00000002 + /* LINKS Bit Masks */ #define IXGBE_LINKS_KX_AN_COMP 0x80000000 #define IXGBE_LINKS_UP 0x40000000 @@ -1502,7 +1562,6 @@ #define IXGBE_ANLP1_ASM_PAUSE 0x0800 #define IXGBE_ANLP1_AN_STATE_MASK 0x000f0000 - /* SW Semaphore Register bitmasks */ #define IXGBE_SWSM_SMBI 0x00000001 /* Driver Semaphore bit */ #define IXGBE_SWSM_SWESMBI 0x00000002 /* FW Semaphore bit */ @@ -1515,6 +1574,10 @@ #define IXGBE_GSSR_PHY1_SM 0x0004 #define IXGBE_GSSR_MAC_CSR_SM 0x0008 #define IXGBE_GSSR_FLASH_SM 0x0010 +#define IXGBE_GSSR_SW_MNG_SM 0x0400 + +/* FW Status register bitmask */ +#define IXGBE_FWSTS_FWRI 0x00000200 /* Firmware Reset Indication */ /* EEC Register */ #define IXGBE_EEC_SK 0x00000001 /* EEPROM Clock */ @@ -1535,6 +1598,7 @@ /* EEPROM Addressing bits based on type (0-small, 1-large) */ #define IXGBE_EEC_ADDR_SIZE 0x00000400 #define IXGBE_EEC_SIZE 0x00007800 /* EEPROM Size */ +#define IXGBE_EERD_MAX_ADDR 0x00003FFF /* EERD alows 14 bits for addr. */ #define IXGBE_EEC_SIZE_SHIFT 11 #define IXGBE_EEPROM_WORD_SIZE_SHIFT 6 @@ -1564,8 +1628,10 @@ #define IXGBE_FW_PTR 0x0F #define IXGBE_PBANUM0_PTR 0x15 #define IXGBE_PBANUM1_PTR 0x16 -#define IXGBE_DEVICE_CAPS 0x2C +#define IXGBE_FREE_SPACE_PTR 0X3E #define IXGBE_SAN_MAC_ADDR_PTR 0x28 +#define IXGBE_DEVICE_CAPS 0x2C +#define IXGBE_SERIAL_NUMBER_MAC_ADDR 0x11 #define IXGBE_PCIE_MSIX_82599_CAPS 0x72 #define IXGBE_PCIE_MSIX_82598_CAPS 0x62 @@ -1630,9 +1696,12 @@ #define IXGBE_FW_LESM_STATE_1 0x1 #define IXGBE_FW_LESM_STATE_ENABLED 0x8000 /* LESM Enable bit */ #define IXGBE_FW_PASSTHROUGH_PATCH_CONFIG_PTR 0x4 -#define IXGBE_FW_PATCH_VERSION_4 0x7 - -/* Alternative SAN MAC Address Block */ +#define IXGBE_FW_PATCH_VERSION_4 0x7 +#define IXGBE_FCOE_IBA_CAPS_BLK_PTR 0x33 /* iSCSI/FCOE block */ +#define IXGBE_FCOE_IBA_CAPS_FCOE 0x20 /* FCOE flags */ +#define IXGBE_ISCSI_FCOE_BLK_PTR 0x17 /* iSCSI/FCOE block */ +#define IXGBE_ISCSI_FCOE_FLAGS_OFFSET 0x0 /* FCOE flags */ +#define IXGBE_ISCSI_FCOE_FLAGS_ENABLE 0x1 /* FCOE flags enable bit */ #define IXGBE_ALT_SAN_MAC_ADDR_BLK_PTR 0x27 /* Alt. SAN MAC block */ #define IXGBE_ALT_SAN_MAC_ADDR_CAPS_OFFSET 0x0 /* Alt. SAN MAC capability */ #define IXGBE_ALT_SAN_MAC_ADDR_PORT0_OFFSET 0x1 /* Alt. SAN MAC 0 offset */ @@ -1697,6 +1766,7 @@ /* Transmit Config masks */ #define IXGBE_TXDCTL_ENABLE 0x02000000 /* Enable specific Tx Queue */ #define IXGBE_TXDCTL_SWFLSH 0x04000000 /* Tx Desc. write-back flushing */ +#define IXGBE_TXDCTL_WTHRESH_SHIFT 16 /* shift to WTHRESH bits */ /* Enable short packet padding to 64 bytes */ #define IXGBE_TX_PAD_ENABLE 0x00000400 #define IXGBE_JUMBO_FRAME_ENABLE 0x00000004 /* Allow jumbo frames */ @@ -1710,9 +1780,9 @@ #define IXGBE_RXCTRL_RXEN 0x00000001 /* Enable Receiver */ #define IXGBE_RXCTRL_DMBYPS 0x00000002 /* Descriptor Monitor Bypass */ #define IXGBE_RXDCTL_ENABLE 0x02000000 /* Enable specific Rx Queue */ -#define IXGBE_RXDCTL_VME 0x40000000 /* VLAN mode enable */ #define IXGBE_RXDCTL_RLPMLMASK 0x00003FFF /* Only supported on the X540 */ #define IXGBE_RXDCTL_RLPML_EN 0x00008000 +#define IXGBE_RXDCTL_VME 0x40000000 /* VLAN mode enable */ #define IXGBE_FCTRL_SBP 0x00000002 /* Store Bad Packet */ #define IXGBE_FCTRL_MPE 0x00000100 /* Multicast Promiscuous Ena*/ @@ -1870,6 +1940,8 @@ #define IXGBE_RXDADV_PKTTYPE_MASK 0x0000FFF0 #define IXGBE_RXDADV_PKTTYPE_MASK_EX 0x0001FFF0 #define IXGBE_RXDADV_HDRBUFLEN_MASK 0x00007FE0 +#define IXGBE_RXDADV_RSCCNT_MASK 0x001E0000 +#define IXGBE_RXDADV_RSCCNT_SHIFT 17 #define IXGBE_RXDADV_HDRBUFLEN_SHIFT 5 #define IXGBE_RXDADV_SPLITHEADER_EN 0x00001000 #define IXGBE_RXDADV_SPH 0x8000 @@ -1945,15 +2017,6 @@ #define IXGBE_VFLRE(_i) (((_i & 1) ? 0x001C0 : 0x00600)) #define IXGBE_VFLREC(_i) (0x00700 + (_i * 4)) -/* Little Endian defines */ -#ifndef __le32 -#define __le32 u32 -#endif -#ifndef __le64 -#define __le64 u64 - -#endif - enum ixgbe_fdir_pballoc_type { IXGBE_FDIR_PBALLOC_64K = 0, IXGBE_FDIR_PBALLOC_128K, @@ -2152,8 +2215,6 @@ typedef u32 ixgbe_link_speed; IXGBE_LINK_SPEED_1GB_FULL | \ IXGBE_LINK_SPEED_10GB_FULL) -#define IXGBE_PCIE_DEV_CTRL_2 0xC8 -#define PCIE_COMPL_TO_VALUE 0x05 /* Physical layer type */ typedef u32 ixgbe_physical_layer; -- cgit v0.10.2 From 0665b09f81760c38a882bed65d495a4bd31a5767 Mon Sep 17 00:00:00 2001 From: Emil Tantilov Date: Fri, 1 Apr 2011 08:17:19 +0000 Subject: ixgbe: add support for 64k EEPROM for 82599 82599 supports up to 32k EEPROM addressing via EERD register. If we wish to address larger EEPROM this have to be done via serial interface. This patch adds function ixgbe_read_eeprom_82599 which selects the best method to read the EEPROM. Signed-off-by: Emil Tantilov Tested-by: Evan Swanson Signed-off-by: Jeff Kirsher diff --git a/drivers/net/ixgbe/ixgbe_82599.c b/drivers/net/ixgbe/ixgbe_82599.c index b341ed8..d521baf 100644 --- a/drivers/net/ixgbe/ixgbe_82599.c +++ b/drivers/net/ixgbe/ixgbe_82599.c @@ -2064,6 +2064,35 @@ out: return lesm_enabled; } +/** + * ixgbe_read_eeprom_82599 - Read EEPROM word using + * fastest available method + * + * @hw: pointer to hardware structure + * @offset: offset of word in the EEPROM to read + * @data: word read from the EEPROM + * + * Reads a 16 bit word from the EEPROM + **/ +static s32 ixgbe_read_eeprom_82599(struct ixgbe_hw *hw, + u16 offset, u16 *data) +{ + struct ixgbe_eeprom_info *eeprom = &hw->eeprom; + s32 ret_val = IXGBE_ERR_CONFIG; + + /* + * If EEPROM is detected and can be addressed using 14 bits, + * use EERD otherwise use bit bang + */ + if ((eeprom->type == ixgbe_eeprom_spi) && + (offset <= IXGBE_EERD_MAX_ADDR)) + ret_val = ixgbe_read_eerd_generic(hw, offset, data); + else + ret_val = ixgbe_read_eeprom_bit_bang_generic(hw, offset, data); + + return ret_val; +} + static struct ixgbe_mac_operations mac_ops_82599 = { .init_hw = &ixgbe_init_hw_generic, .reset_hw = &ixgbe_reset_hw_82599, @@ -2110,7 +2139,7 @@ static struct ixgbe_mac_operations mac_ops_82599 = { static struct ixgbe_eeprom_operations eeprom_ops_82599 = { .init_params = &ixgbe_init_eeprom_params_generic, - .read = &ixgbe_read_eerd_generic, + .read = &ixgbe_read_eeprom_82599, .write = &ixgbe_write_eeprom_generic, .calc_checksum = &ixgbe_calc_eeprom_checksum_generic, .validate_checksum = &ixgbe_validate_eeprom_checksum_generic, -- cgit v0.10.2 From 98508c93003d8d24662f32c66dbe4746340c33d4 Mon Sep 17 00:00:00 2001 From: Emil Tantilov Date: Fri, 8 Apr 2011 01:24:05 +0000 Subject: ixgbe: add LED blink code for x540 Implement blink_led_start and blink_led_stop functions for x540 using the MACC register. Signed-off-by: Emil Tantilov Tested-by: Evan Swanson Signed-off-by: Jeff Kirsher diff --git a/drivers/net/ixgbe/ixgbe_x540.c b/drivers/net/ixgbe/ixgbe_x540.c index 932394f..75c6465 100644 --- a/drivers/net/ixgbe/ixgbe_x540.c +++ b/drivers/net/ixgbe/ixgbe_x540.c @@ -744,6 +744,66 @@ static void ixgbe_release_swfw_sync_semaphore(struct ixgbe_hw *hw) IXGBE_WRITE_FLUSH(hw); } +/** + * ixgbe_blink_led_start_X540 - Blink LED based on index. + * @hw: pointer to hardware structure + * @index: led number to blink + * + * Devices that implement the version 2 interface: + * X540 + **/ +static s32 ixgbe_blink_led_start_X540(struct ixgbe_hw *hw, u32 index) +{ + u32 macc_reg; + u32 ledctl_reg; + + /* + * In order for the blink bit in the LED control register + * to work, link and speed must be forced in the MAC. We + * will reverse this when we stop the blinking. + */ + macc_reg = IXGBE_READ_REG(hw, IXGBE_MACC); + macc_reg |= IXGBE_MACC_FLU | IXGBE_MACC_FSV_10G | IXGBE_MACC_FS; + IXGBE_WRITE_REG(hw, IXGBE_MACC, macc_reg); + + /* Set the LED to LINK_UP + BLINK. */ + ledctl_reg = IXGBE_READ_REG(hw, IXGBE_LEDCTL); + ledctl_reg &= ~IXGBE_LED_MODE_MASK(index); + ledctl_reg |= IXGBE_LED_BLINK(index); + IXGBE_WRITE_REG(hw, IXGBE_LEDCTL, ledctl_reg); + IXGBE_WRITE_FLUSH(hw); + + return 0; +} + +/** + * ixgbe_blink_led_stop_X540 - Stop blinking LED based on index. + * @hw: pointer to hardware structure + * @index: led number to stop blinking + * + * Devices that implement the version 2 interface: + * X540 + **/ +static s32 ixgbe_blink_led_stop_X540(struct ixgbe_hw *hw, u32 index) +{ + u32 macc_reg; + u32 ledctl_reg; + + /* Restore the LED to its default value. */ + ledctl_reg = IXGBE_READ_REG(hw, IXGBE_LEDCTL); + ledctl_reg &= ~IXGBE_LED_MODE_MASK(index); + ledctl_reg |= IXGBE_LED_LINK_ACTIVE << IXGBE_LED_MODE_SHIFT(index); + ledctl_reg &= ~IXGBE_LED_BLINK(index); + IXGBE_WRITE_REG(hw, IXGBE_LEDCTL, ledctl_reg); + + /* Unforce link and speed in the MAC. */ + macc_reg = IXGBE_READ_REG(hw, IXGBE_MACC); + macc_reg &= ~(IXGBE_MACC_FLU | IXGBE_MACC_FSV_10G | IXGBE_MACC_FS); + IXGBE_WRITE_REG(hw, IXGBE_MACC, macc_reg); + IXGBE_WRITE_FLUSH(hw); + + return 0; +} static struct ixgbe_mac_operations mac_ops_X540 = { .init_hw = &ixgbe_init_hw_generic, .reset_hw = &ixgbe_reset_hw_X540, @@ -767,8 +827,8 @@ static struct ixgbe_mac_operations mac_ops_X540 = { .get_link_capabilities = &ixgbe_get_copper_link_capabilities_generic, .led_on = &ixgbe_led_on_generic, .led_off = &ixgbe_led_off_generic, - .blink_led_start = &ixgbe_blink_led_start_generic, - .blink_led_stop = &ixgbe_blink_led_stop_generic, + .blink_led_start = &ixgbe_blink_led_start_X540, + .blink_led_stop = &ixgbe_blink_led_stop_X540, .set_rar = &ixgbe_set_rar_generic, .clear_rar = &ixgbe_clear_rar_generic, .set_vmdq = &ixgbe_set_vmdq_generic, -- cgit v0.10.2 From 11b1d38e705fa05282661d2b1710f7a81a7f7045 Mon Sep 17 00:00:00 2001 From: Alexander Duyck Date: Sat, 9 Apr 2011 05:34:06 +0000 Subject: ixgbe: remove ntuple display support This change removes the ntuple display support from ixgbe. The reason for this change is to resolve a number of issues in the way display filtering is handled. I plan to add support for displaying these filters via the network flow classifier interface. Signed-off-by: Alexander Duyck Tested-by: Evan Swanson Signed-off-by: Jeff Kirsher diff --git a/drivers/net/ixgbe/ixgbe_ethtool.c b/drivers/net/ixgbe/ixgbe_ethtool.c index 5005a36..6cf1c71 100644 --- a/drivers/net/ixgbe/ixgbe_ethtool.c +++ b/drivers/net/ixgbe/ixgbe_ethtool.c @@ -1030,9 +1030,6 @@ static int ixgbe_get_sset_count(struct net_device *netdev, int sset) return IXGBE_TEST_LEN; case ETH_SS_STATS: return IXGBE_STATS_LEN; - case ETH_SS_NTUPLE_FILTERS: - return ETHTOOL_MAX_NTUPLE_LIST_ENTRY * - ETHTOOL_MAX_NTUPLE_STRING_PER_ENTRY; default: return -EOPNOTSUPP; } diff --git a/drivers/net/ixgbe/ixgbe_main.c b/drivers/net/ixgbe/ixgbe_main.c index 200ae7e..dbe29e5 100644 --- a/drivers/net/ixgbe/ixgbe_main.c +++ b/drivers/net/ixgbe/ixgbe_main.c @@ -4203,9 +4203,6 @@ void ixgbe_down(struct ixgbe_adapter *adapter) break; } - /* clear n-tuple filters that are cached */ - ethtool_ntuple_flush(netdev); - if (!pci_channel_offline(adapter->pdev)) ixgbe_reset(adapter); -- cgit v0.10.2 From b32c8dcc33a74fb4f1e73ed2263504f5947ca76b Mon Sep 17 00:00:00 2001 From: John Fastabend Date: Tue, 12 Apr 2011 02:44:55 +0000 Subject: ixgbe: fix static functions Define functions as static added C=1 (sparse) to my make line brought these to my attention. Signed-off-by: John Fastabend Signed-off-by: Jeff Kirsher diff --git a/drivers/net/ixgbe/ixgbe_82599.c b/drivers/net/ixgbe/ixgbe_82599.c index d521baf..d1cda36 100644 --- a/drivers/net/ixgbe/ixgbe_82599.c +++ b/drivers/net/ixgbe/ixgbe_82599.c @@ -494,7 +494,7 @@ static void ixgbe_flap_tx_laser_multispeed_fiber(struct ixgbe_hw *hw) * * Set the link speed in the AUTOC register and restarts link. **/ -s32 ixgbe_setup_mac_link_multispeed_fiber(struct ixgbe_hw *hw, +static s32 ixgbe_setup_mac_link_multispeed_fiber(struct ixgbe_hw *hw, ixgbe_link_speed speed, bool autoneg, bool autoneg_wait_to_complete) diff --git a/drivers/net/ixgbe/ixgbe_dcb_82598.c b/drivers/net/ixgbe/ixgbe_dcb_82598.c index 1bc57e5..771d01a 100644 --- a/drivers/net/ixgbe/ixgbe_dcb_82598.c +++ b/drivers/net/ixgbe/ixgbe_dcb_82598.c @@ -289,7 +289,7 @@ s32 ixgbe_dcb_config_pfc_82598(struct ixgbe_hw *hw, u8 pfc_en) * Configure queue statistics registers, all queues belonging to same traffic * class uses a single set of queue statistics counters. */ -s32 ixgbe_dcb_config_tc_stats_82598(struct ixgbe_hw *hw) +static s32 ixgbe_dcb_config_tc_stats_82598(struct ixgbe_hw *hw) { u32 reg = 0; u8 i = 0; diff --git a/drivers/net/ixgbe/ixgbe_main.c b/drivers/net/ixgbe/ixgbe_main.c index dbe29e5..227a9b4 100644 --- a/drivers/net/ixgbe/ixgbe_main.c +++ b/drivers/net/ixgbe/ixgbe_main.c @@ -4566,8 +4566,8 @@ static inline bool ixgbe_cache_ring_rss(struct ixgbe_adapter *adapter) #ifdef CONFIG_IXGBE_DCB /* ixgbe_get_first_reg_idx - Return first register index associated with ring */ -void ixgbe_get_first_reg_idx(struct ixgbe_adapter *adapter, u8 tc, - unsigned int *tx, unsigned int *rx) +static void ixgbe_get_first_reg_idx(struct ixgbe_adapter *adapter, u8 tc, + unsigned int *tx, unsigned int *rx) { struct net_device *dev = adapter->netdev; struct ixgbe_hw *hw = &adapter->hw; diff --git a/drivers/net/ixgbe/ixgbe_sriov.c b/drivers/net/ixgbe/ixgbe_sriov.c index 6e50d83..4765027 100644 --- a/drivers/net/ixgbe/ixgbe_sriov.c +++ b/drivers/net/ixgbe/ixgbe_sriov.c @@ -110,7 +110,7 @@ static int ixgbe_set_vf_vlan(struct ixgbe_adapter *adapter, int add, int vid, return adapter->hw.mac.ops.set_vfta(&adapter->hw, vid, vf, (bool)add); } -void ixgbe_set_vf_lpe(struct ixgbe_adapter *adapter, u32 *msgbuf) +static void ixgbe_set_vf_lpe(struct ixgbe_adapter *adapter, u32 *msgbuf) { struct ixgbe_hw *hw = &adapter->hw; int new_mtu = msgbuf[1]; -- cgit v0.10.2 From 7aba7b077f638deb9569e0b36256cd9ae76e468c Mon Sep 17 00:00:00 2001 From: Yi Zou Date: Sat, 9 Apr 2011 08:34:12 +0000 Subject: ixgbe: do not clear FCoE DDP error status for received ABTS The ddp->err is initialized to be 1 to make sure outstanding DDP context is guaranteed to be invalidated when HW is not auto-invalidating it. However, in case of receiving ABTS response for a DDPed I/O, the ddp->err was cleared, bypassing the invalidating of the DDP context from upper protocol stack when ixgbe_fcoe_ddp_put() is called. This bug is fixed here by updating the error only when FCP_RSP is received. Signed-off-by: Yi Zou Tested-by: Ross Brattain Signed-off-by: Jeff Kirsher diff --git a/drivers/net/ixgbe/ixgbe_fcoe.c b/drivers/net/ixgbe/ixgbe_fcoe.c index dba7d77..0592072 100644 --- a/drivers/net/ixgbe/ixgbe_fcoe.c +++ b/drivers/net/ixgbe/ixgbe_fcoe.c @@ -416,8 +416,7 @@ int ixgbe_fcoe_ddp(struct ixgbe_adapter *adapter, if (!ddp->udl) goto ddp_out; - ddp->err = (fcerr | fceofe); - if (ddp->err) + if (fcerr | fceofe) goto ddp_out; fcstat = (sterr & IXGBE_RXDADV_STAT_FCSTAT); @@ -428,6 +427,7 @@ int ixgbe_fcoe_ddp(struct ixgbe_adapter *adapter, if (fcstat == IXGBE_RXDADV_STAT_FCSTAT_FCPRSP) { pci_unmap_sg(adapter->pdev, ddp->sgl, ddp->sgc, DMA_FROM_DEVICE); + ddp->err = (fcerr | fceofe); ddp->sgl = NULL; ddp->sgc = 0; } -- cgit v0.10.2 From 58be7666a897bb756477da72859f515da35ab805 Mon Sep 17 00:00:00 2001 From: Don Skidmore Date: Tue, 12 Apr 2011 09:42:11 +0000 Subject: ixgbe: enable SCTP checksum offload for X540 X540 supports SCTP checksum offload so enable it. It was overlooked when X540 support was initially added to the driver. Signed-off-by: Don Skidmore Tested-by: Evan Swanson Signed-off-by: Jeff Kirsher diff --git a/drivers/net/ixgbe/ixgbe_main.c b/drivers/net/ixgbe/ixgbe_main.c index 227a9b4..a7da5d9 100644 --- a/drivers/net/ixgbe/ixgbe_main.c +++ b/drivers/net/ixgbe/ixgbe_main.c @@ -7361,8 +7361,14 @@ static int __devinit ixgbe_probe(struct pci_dev *pdev, netdev->features |= NETIF_F_TSO6; netdev->features |= NETIF_F_GRO; - if (adapter->hw.mac.type == ixgbe_mac_82599EB) + switch (adapter->hw.mac.type) { + case ixgbe_mac_82599EB: + case ixgbe_mac_X540: netdev->features |= NETIF_F_SCTP_CSUM; + break; + default: + break; + } netdev->vlan_features |= NETIF_F_TSO; netdev->vlan_features |= NETIF_F_TSO6; -- cgit v0.10.2 From c89c7112d347acc3f4a6fe1459bcb6de02594dc9 Mon Sep 17 00:00:00 2001 From: Don Skidmore Date: Thu, 14 Apr 2011 07:40:11 +0000 Subject: ixgbe: Bump version Bump the driver version number to better match up with the out of tree driver that has similar functionality. Signed-off-by: Don Skidmore Tested-by: Evan Swanson Signed-off-by: Jeff Kirsher diff --git a/drivers/net/ixgbe/ixgbe_main.c b/drivers/net/ixgbe/ixgbe_main.c index a7da5d9..9160811 100644 --- a/drivers/net/ixgbe/ixgbe_main.c +++ b/drivers/net/ixgbe/ixgbe_main.c @@ -52,8 +52,8 @@ char ixgbe_driver_name[] = "ixgbe"; static const char ixgbe_driver_string[] = "Intel(R) 10 Gigabit PCI Express Network Driver"; #define MAJ 3 -#define MIN 2 -#define BUILD 9 +#define MIN 3 +#define BUILD 8 #define KFIX 2 #define DRV_VERSION __stringify(MAJ) "." __stringify(MIN) "." \ __stringify(BUILD) "-k" __stringify(KFIX) -- cgit v0.10.2 From e7fd9253d83703838953160ebb2899c5f6e2eee1 Mon Sep 17 00:00:00 2001 From: Don Skidmore Date: Sat, 16 Apr 2011 05:29:14 +0000 Subject: ixgbe: fix X540 ethtool loopback test. On X540 we need to set the MACC.FLU bit to 1 in order to force the link up before entering MAC loopback. This is only used in the ethtool loopback test, which was failing. This patch corrects it. Signed-off-by: Don Skidmore Tested-by: Evan Swanson Signed-off-by: Jeff Kirsher diff --git a/drivers/net/ixgbe/ixgbe_ethtool.c b/drivers/net/ixgbe/ixgbe_ethtool.c index 6cf1c71..bd7524e 100644 --- a/drivers/net/ixgbe/ixgbe_ethtool.c +++ b/drivers/net/ixgbe/ixgbe_ethtool.c @@ -1595,6 +1595,13 @@ static int ixgbe_setup_loopback_test(struct ixgbe_adapter *adapter) struct ixgbe_hw *hw = &adapter->hw; u32 reg_data; + /* X540 needs to set the MACC.FLU bit to force link up */ + if (adapter->hw.mac.type == ixgbe_mac_X540) { + reg_data = IXGBE_READ_REG(&adapter->hw, IXGBE_MACC); + reg_data |= IXGBE_MACC_FLU; + IXGBE_WRITE_REG(&adapter->hw, IXGBE_MACC, reg_data); + } + /* right now we only support MAC loopback in the driver */ reg_data = IXGBE_READ_REG(&adapter->hw, IXGBE_HLREG0); /* Setup MAC loopback */ -- cgit v0.10.2 From 66e6961c8e53c0c0079d5b67faf9b7fe33525892 Mon Sep 17 00:00:00 2001 From: Emil Tantilov Date: Sat, 16 Apr 2011 06:12:51 +0000 Subject: ixgbe: convert to ethtool set_phys_id Based on the original patch submitted by Stephen Hemminger. This patch makes the following changes: - Change ETHTOOL_ID_INACTIVE return value to 2 (blinks/sec) - Fix restoring of IXGBE_LEDCTL CC: Stephen Hemminger Signed-off-by: Emil Tantilov Tested-by: Evan Swanson Signed-off-by: Jeff Kirsher diff --git a/drivers/net/ixgbe/ixgbe.h b/drivers/net/ixgbe/ixgbe.h index 8d46802..37ff531 100644 --- a/drivers/net/ixgbe/ixgbe.h +++ b/drivers/net/ixgbe/ixgbe.h @@ -461,6 +461,7 @@ struct ixgbe_adapter { u16 eeprom_version; int node; + u32 led_reg; struct work_struct check_overtemp_task; u32 interrupt_event; char lsc_int_name[IFNAMSIZ + 9]; diff --git a/drivers/net/ixgbe/ixgbe_ethtool.c b/drivers/net/ixgbe/ixgbe_ethtool.c index bd7524e..7279345 100644 --- a/drivers/net/ixgbe/ixgbe_ethtool.c +++ b/drivers/net/ixgbe/ixgbe_ethtool.c @@ -2003,25 +2003,30 @@ static int ixgbe_nway_reset(struct net_device *netdev) return 0; } -static int ixgbe_phys_id(struct net_device *netdev, u32 data) +static int ixgbe_set_phys_id(struct net_device *netdev, + enum ethtool_phys_id_state state) { struct ixgbe_adapter *adapter = netdev_priv(netdev); struct ixgbe_hw *hw = &adapter->hw; - u32 led_reg = IXGBE_READ_REG(hw, IXGBE_LEDCTL); - u32 i; - if (!data || data > 300) - data = 300; + switch (state) { + case ETHTOOL_ID_ACTIVE: + adapter->led_reg = IXGBE_READ_REG(hw, IXGBE_LEDCTL); + return 2; - for (i = 0; i < (data * 1000); i += 400) { + case ETHTOOL_ID_ON: hw->mac.ops.led_on(hw, IXGBE_LED_ON); - msleep_interruptible(200); + break; + + case ETHTOOL_ID_OFF: hw->mac.ops.led_off(hw, IXGBE_LED_ON); - msleep_interruptible(200); - } + break; - /* Restore LED settings */ - IXGBE_WRITE_REG(&adapter->hw, IXGBE_LEDCTL, led_reg); + case ETHTOOL_ID_INACTIVE: + /* Restore LED settings */ + IXGBE_WRITE_REG(&adapter->hw, IXGBE_LEDCTL, adapter->led_reg); + break; + } return 0; } @@ -2469,7 +2474,7 @@ static const struct ethtool_ops ixgbe_ethtool_ops = { .set_tso = ixgbe_set_tso, .self_test = ixgbe_diag_test, .get_strings = ixgbe_get_strings, - .phys_id = ixgbe_phys_id, + .set_phys_id = ixgbe_set_phys_id, .get_sset_count = ixgbe_get_sset_count, .get_ethtool_stats = ixgbe_get_ethtool_stats, .get_coalesce = ixgbe_get_coalesce, -- cgit v0.10.2 From 54a96dadaa2bbe81006c66447517b57534d80e7f Mon Sep 17 00:00:00 2001 From: Raymond Yau Date: Mon, 25 Apr 2011 12:05:45 +0800 Subject: ALSA - au88x0 - Add buffer bytes constraints This allow application such as gstreamer and wine which use snd_pcm_hw_params_set_buffer_time_near() won't fail any more since sound chips require special containt power 2 period bytes Signed-off-by: Raymond Yau Signed-off-by: Takashi Iwai diff --git a/sound/pci/au88x0/au88x0_pcm.c b/sound/pci/au88x0/au88x0_pcm.c index 33f0ba5..62e9591 100644 --- a/sound/pci/au88x0/au88x0_pcm.c +++ b/sound/pci/au88x0/au88x0_pcm.c @@ -44,10 +44,10 @@ static struct snd_pcm_hardware snd_vortex_playback_hw_adb = { .channels_min = 1, .channels_max = 2, .buffer_bytes_max = 0x10000, - .period_bytes_min = 0x1, + .period_bytes_min = 0x20, .period_bytes_max = 0x1000, .periods_min = 2, - .periods_max = 32, + .periods_max = 1024, }; #ifndef CHIP_AU8820 @@ -140,6 +140,9 @@ static int snd_vortex_pcm_open(struct snd_pcm_substream *substream) SNDRV_PCM_HW_PARAM_PERIOD_BYTES)) < 0) return err; + snd_pcm_hw_constraint_step(runtime, 0, + SNDRV_PCM_HW_PARAM_BUFFER_BYTES, 64); + if (VORTEX_PCM_TYPE(substream->pcm) != VORTEX_PCM_WT) { #ifndef CHIP_AU8820 if (VORTEX_PCM_TYPE(substream->pcm) == VORTEX_PCM_A3D) { -- cgit v0.10.2 From 4aac0b4815ba592052758f4b468f253d383dc9d6 Mon Sep 17 00:00:00 2001 From: Michael Schmitz Date: Tue, 26 Apr 2011 14:51:53 +1200 Subject: m68k/mm: Set all online nodes in N_NORMAL_MEMORY For m68k, N_NORMAL_MEMORY represents all nodes that have present memory since it does not support HIGHMEM. This patch sets the bit at the time node_present_pages has been set by free_area_init_node. At the time the node is brought online, the node state would have to be done unconditionally since information about present memory has not yet been recorded. If N_NORMAL_MEMORY is not accurate, slub may encounter errors since it uses this nodemask to setup per-cache kmem_cache_node data structures. This pach is an alternative to the one proposed by David Rientjes attempting to set node state immediately when bringing the node online. Signed-off-by: Michael Schmitz Tested-by: Thorsten Glaser Signed-off-by: Geert Uytterhoeven CC: stable@kernel.org diff --git a/arch/m68k/mm/motorola.c b/arch/m68k/mm/motorola.c index 02b7a03..8b3db1c 100644 --- a/arch/m68k/mm/motorola.c +++ b/arch/m68k/mm/motorola.c @@ -300,6 +300,8 @@ void __init paging_init(void) zones_size[ZONE_DMA] = m68k_memory[i].size >> PAGE_SHIFT; free_area_init_node(i, zones_size, m68k_memory[i].addr >> PAGE_SHIFT, NULL); + if (node_present_pages(i)) + node_set_state(i, N_NORMAL_MEMORY); } } -- cgit v0.10.2 From 9ceb1c3d1fe15c2f9b55eaa8978019ef0e0a06ac Mon Sep 17 00:00:00 2001 From: Ingo Molnar Date: Thu, 28 Apr 2011 02:57:53 +0200 Subject: perf stat: Fix printout vertical alignment Before: | | Performance counter stats for '/home/mingo/hackbench 20' (5 runs): | | 71,321,607 instructions:u # 0.42 insns per cycle ( +- 0.00% ) | 168,040,009 cycles:u # 0.000 GHz ( +- 0.81% ) | | 1.468002368 seconds time elapsed ( +- 1.33% ) | After: | | Performance counter stats for '/home/mingo/hackbench 20' (5 runs): | | 71,321,607 instructions:u # 0.42 insns per cycle ( +- 0.00% ) | 168,040,009 cycles:u # 0.000 GHz ( +- 0.81% ) | | 1.468002368 seconds time elapsed ( +- 1.33% ) | The last column (stddev noise) is properly aligned, vertically. Cc: Peter Zijlstra Cc: Arnaldo Carvalho de Melo Cc: Frederic Weisbecker Link: http://lkml.kernel.org/n/tip-7y40wib8n1eqio7hjpn0dsrm@git.kernel.org Signed-off-by: Ingo Molnar diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c index 6959fde..003caa8 100644 --- a/tools/perf/builtin-stat.c +++ b/tools/perf/builtin-stat.c @@ -575,7 +575,7 @@ static void abs_printout(int cpu, struct perf_evsel *evsel, double avg) if (total) ratio = avg / total; - fprintf(stderr, " # %4.2f insns per cycle", ratio); + fprintf(stderr, " # %4.2f insns per cycle ", ratio); total = avg_stats(&runtime_stalled_cycles_stats[cpu]); -- cgit v0.10.2 From 2bce5daca28346f19c190dbdb5542c9fe3e8c6e6 Mon Sep 17 00:00:00 2001 From: Don Zickus Date: Wed, 27 Apr 2011 06:32:33 -0400 Subject: perf, x86, nmi: Move LVT un-masking into irq handlers It was noticed that P4 machines were generating double NMIs for each perf event. These extra NMIs lead to 'Dazed and confused' messages on the screen. I tracked this down to a P4 quirk that said the overflow bit had to be cleared before re-enabling the apic LVT mask. My first attempt was to move the un-masking inside the perf nmi handler from before the chipset NMI handler to after. This broke Nehalem boxes that seem to like the unmasking before the counters themselves are re-enabled. In order to keep this change simple for 2.6.39, I decided to just simply move the apic LVT un-masking to the beginning of all the chipset NMI handlers, with the exception of Pentium4's to fix the double NMI issue. Later on we can move the un-masking to later in the handlers to save a number of 'extra' NMIs on those particular chipsets. I tested this change on a P4 machine, an AMD machine, a Nehalem box, and a core2quad box. 'perf top' worked correctly along with various other small 'perf record' runs. Anything high stress breaks all the machines but that is a different problem. Thanks to various people for testing different versions of this patch. Reported-and-tested-by: Shaun Ruffell Signed-off-by: Don Zickus Cc: Cyrill Gorcunov Link: http://lkml.kernel.org/r/1303900353-10242-1-git-send-email-dzickus@redhat.com Signed-off-by: Ingo Molnar CC: Cyrill Gorcunov diff --git a/arch/x86/kernel/cpu/perf_event.c b/arch/x86/kernel/cpu/perf_event.c index fac0654..e638689 100644 --- a/arch/x86/kernel/cpu/perf_event.c +++ b/arch/x86/kernel/cpu/perf_event.c @@ -1288,6 +1288,16 @@ static int x86_pmu_handle_irq(struct pt_regs *regs) cpuc = &__get_cpu_var(cpu_hw_events); + /* + * Some chipsets need to unmask the LVTPC in a particular spot + * inside the nmi handler. As a result, the unmasking was pushed + * into all the nmi handlers. + * + * This generic handler doesn't seem to have any issues where the + * unmasking occurs so it was left at the top. + */ + apic_write(APIC_LVTPC, APIC_DM_NMI); + for (idx = 0; idx < x86_pmu.num_counters; idx++) { if (!test_bit(idx, cpuc->active_mask)) { /* @@ -1374,8 +1384,6 @@ perf_event_nmi_handler(struct notifier_block *self, return NOTIFY_DONE; } - apic_write(APIC_LVTPC, APIC_DM_NMI); - handled = x86_pmu.handle_irq(args->regs); if (!handled) return NOTIFY_DONE; diff --git a/arch/x86/kernel/cpu/perf_event_intel.c b/arch/x86/kernel/cpu/perf_event_intel.c index 9ae4a2a..e61539b 100644 --- a/arch/x86/kernel/cpu/perf_event_intel.c +++ b/arch/x86/kernel/cpu/perf_event_intel.c @@ -933,6 +933,16 @@ static int intel_pmu_handle_irq(struct pt_regs *regs) cpuc = &__get_cpu_var(cpu_hw_events); + /* + * Some chipsets need to unmask the LVTPC in a particular spot + * inside the nmi handler. As a result, the unmasking was pushed + * into all the nmi handlers. + * + * This handler doesn't seem to have any issues with the unmasking + * so it was left at the top. + */ + apic_write(APIC_LVTPC, APIC_DM_NMI); + intel_pmu_disable_all(); handled = intel_pmu_drain_bts_buffer(); status = intel_pmu_get_status(); diff --git a/arch/x86/kernel/cpu/perf_event_p4.c b/arch/x86/kernel/cpu/perf_event_p4.c index d1f77e2..e93fcd5 100644 --- a/arch/x86/kernel/cpu/perf_event_p4.c +++ b/arch/x86/kernel/cpu/perf_event_p4.c @@ -950,11 +950,20 @@ static int p4_pmu_handle_irq(struct pt_regs *regs) x86_pmu_stop(event, 0); } - if (handled) { - /* p4 quirk: unmask it again */ - apic_write(APIC_LVTPC, apic_read(APIC_LVTPC) & ~APIC_LVT_MASKED); + if (handled) inc_irq_stat(apic_perf_irqs); - } + + /* + * When dealing with the unmasking of the LVTPC on P4 perf hw, it has + * been observed that the OVF bit flag has to be cleared first _before_ + * the LVTPC can be unmasked. + * + * The reason is the NMI line will continue to be asserted while the OVF + * bit is set. This causes a second NMI to generate if the LVTPC is + * unmasked before the OVF bit is cleared, leading to unknown NMI + * messages. + */ + apic_write(APIC_LVTPC, APIC_DM_NMI); return handled; } -- cgit v0.10.2 From 28331a46d88459788c8fca72dbb0415cd7f514c9 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Wed, 27 Apr 2011 13:47:52 -0400 Subject: NFSv4: Ensure we request the ordinary fileid when doing readdirplus When readdir() returns a directory entry for the root of a mounted filesystem, Linux follows the old convention of returning the inode number of the covered directory (despite newer versions of POSIX declaring that this is a bug). To ensure this continues to work, the NFSv4 readdir implementation requests the 'mounted-on-fileid' from the server. However, readdirplus also needs to instantiate an inode for this entry, and for that, we also need to request the real fileid as per this patch. Signed-off-by: Trond Myklebust diff --git a/fs/nfs/nfs4xdr.c b/fs/nfs/nfs4xdr.c index ba952bd..7310d2e 100644 --- a/fs/nfs/nfs4xdr.c +++ b/fs/nfs/nfs4xdr.c @@ -1452,26 +1452,25 @@ static void encode_read(struct xdr_stream *xdr, const struct nfs_readargs *args, static void encode_readdir(struct xdr_stream *xdr, const struct nfs4_readdir_arg *readdir, struct rpc_rqst *req, struct compound_hdr *hdr) { - uint32_t attrs[2] = {0, 0}; + uint32_t attrs[2] = { + FATTR4_WORD0_RDATTR_ERROR, + FATTR4_WORD1_MOUNTED_ON_FILEID, + }; uint32_t dircount = readdir->count >> 1; __be32 *p; if (readdir->plus) { attrs[0] |= FATTR4_WORD0_TYPE|FATTR4_WORD0_CHANGE|FATTR4_WORD0_SIZE| - FATTR4_WORD0_FSID|FATTR4_WORD0_FILEHANDLE; + FATTR4_WORD0_FSID|FATTR4_WORD0_FILEHANDLE|FATTR4_WORD0_FILEID; attrs[1] |= FATTR4_WORD1_MODE|FATTR4_WORD1_NUMLINKS|FATTR4_WORD1_OWNER| FATTR4_WORD1_OWNER_GROUP|FATTR4_WORD1_RAWDEV| FATTR4_WORD1_SPACE_USED|FATTR4_WORD1_TIME_ACCESS| FATTR4_WORD1_TIME_METADATA|FATTR4_WORD1_TIME_MODIFY; dircount >>= 1; } - attrs[0] |= FATTR4_WORD0_RDATTR_ERROR|FATTR4_WORD0_FILEID; - attrs[1] |= FATTR4_WORD1_MOUNTED_ON_FILEID; - /* Switch to mounted_on_fileid if the server supports it */ - if (readdir->bitmask[1] & FATTR4_WORD1_MOUNTED_ON_FILEID) - attrs[0] &= ~FATTR4_WORD0_FILEID; - else - attrs[1] &= ~FATTR4_WORD1_MOUNTED_ON_FILEID; + /* Use mounted_on_fileid only if the server supports it */ + if (!(readdir->bitmask[1] & FATTR4_WORD1_MOUNTED_ON_FILEID)) + attrs[0] |= FATTR4_WORD0_FILEID; p = reserve_space(xdr, 12+NFS4_VERIFIER_SIZE+20); *p++ = cpu_to_be32(OP_READDIR); @@ -3140,7 +3139,7 @@ static int decode_attr_mounted_on_fileid(struct xdr_stream *xdr, uint32_t *bitma goto out_overflow; xdr_decode_hyper(p, fileid); bitmap[1] &= ~FATTR4_WORD1_MOUNTED_ON_FILEID; - ret = NFS_ATTR_FATTR_FILEID; + ret = NFS_ATTR_FATTR_MOUNTED_ON_FILEID; } dprintk("%s: fileid=%Lu\n", __func__, (unsigned long long)*fileid); return ret; @@ -4002,7 +4001,6 @@ static int decode_getfattr_attrs(struct xdr_stream *xdr, uint32_t *bitmap, { int status; umode_t fmode = 0; - uint64_t fileid; uint32_t type; status = decode_attr_type(xdr, bitmap, &type); @@ -4101,13 +4099,10 @@ static int decode_getfattr_attrs(struct xdr_stream *xdr, uint32_t *bitmap, goto xdr_error; fattr->valid |= status; - status = decode_attr_mounted_on_fileid(xdr, bitmap, &fileid); + status = decode_attr_mounted_on_fileid(xdr, bitmap, &fattr->mounted_on_fileid); if (status < 0) goto xdr_error; - if (status != 0 && !(fattr->valid & status)) { - fattr->fileid = fileid; - fattr->valid |= status; - } + fattr->valid |= status; xdr_error: dprintk("%s: xdr returned %d\n", __func__, -status); @@ -6411,7 +6406,9 @@ int nfs4_decode_dirent(struct xdr_stream *xdr, struct nfs_entry *entry, if (decode_getfattr_attrs(xdr, bitmap, entry->fattr, entry->fh, entry->server, 1) < 0) goto out_overflow; - if (entry->fattr->valid & NFS_ATTR_FATTR_FILEID) + if (entry->fattr->valid & NFS_ATTR_FATTR_MOUNTED_ON_FILEID) + entry->ino = entry->fattr->mounted_on_fileid; + else if (entry->fattr->valid & NFS_ATTR_FATTR_FILEID) entry->ino = entry->fattr->fileid; entry->d_type = DT_UNKNOWN; diff --git a/include/linux/nfs_xdr.h b/include/linux/nfs_xdr.h index 78b101e..890dce2 100644 --- a/include/linux/nfs_xdr.h +++ b/include/linux/nfs_xdr.h @@ -50,6 +50,7 @@ struct nfs_fattr { } du; struct nfs_fsid fsid; __u64 fileid; + __u64 mounted_on_fileid; struct timespec atime; struct timespec mtime; struct timespec ctime; @@ -83,6 +84,7 @@ struct nfs_fattr { #define NFS_ATTR_FATTR_PRECHANGE (1U << 18) #define NFS_ATTR_FATTR_V4_REFERRAL (1U << 19) /* NFSv4 referral */ #define NFS_ATTR_FATTR_MOUNTPOINT (1U << 20) /* Treat as mountpoint */ +#define NFS_ATTR_FATTR_MOUNTED_ON_FILEID (1U << 21) #define NFS_ATTR_FATTR (NFS_ATTR_FATTR_TYPE \ | NFS_ATTR_FATTR_MODE \ -- cgit v0.10.2 From 625034113bd45c71fb9e329f52f25fef9e6993a3 Mon Sep 17 00:00:00 2001 From: Weixing Shi Date: Tue, 26 Apr 2011 21:36:32 +0000 Subject: sctp: fix sctp to work with ipv6 source address routing In the below test case, using the source address routing, sctp can not work. Node-A 1)ifconfig eth0 inet6 add 2001:1::1/64 2)ip -6 rule add from 2001:1::1 table 100 pref 100 3)ip -6 route add 2001:2::1 dev eth0 table 100 4)sctp_darn -H 2001:1::1 -P 250 -l & Node-B 1)ifconfig eth0 inet6 add 2001:2::1/64 2)ip -6 rule add from 2001:2::1 table 100 pref 100 3)ip -6 route add 2001:1::1 dev eth0 table 100 4)sctp_darn -H 2001:2::1 -P 250 -h 2001:1::1 -p 250 -s root cause: Node-A and Node-B use the source address routing, and at begining, source address will be NULL,sctp will search the routing table by the destination address, because using the source address routing table, and the result dst_entry will be NULL. solution: walk through the bind address list to get the source address and then lookup the routing table again to get the correct dst_entry. Signed-off-by: Weixing Shi Signed-off-by: Vlad Yasevich Signed-off-by: Wei Yongjun Signed-off-by: David S. Miller diff --git a/net/sctp/ipv6.c b/net/sctp/ipv6.c index 321f175..3a571d6 100644 --- a/net/sctp/ipv6.c +++ b/net/sctp/ipv6.c @@ -80,6 +80,9 @@ #include +static inline int sctp_v6_addr_match_len(union sctp_addr *s1, + union sctp_addr *s2); + /* Event handler for inet6 address addition/deletion events. * The sctp_local_addr_list needs to be protocted by a spin lock since * multiple notifiers (say IPv4 and IPv6) may be running at the same @@ -244,8 +247,14 @@ static struct dst_entry *sctp_v6_get_dst(struct sctp_association *asoc, union sctp_addr *daddr, union sctp_addr *saddr) { - struct dst_entry *dst; + struct dst_entry *dst = NULL; struct flowi6 fl6; + struct sctp_bind_addr *bp; + struct sctp_sockaddr_entry *laddr; + union sctp_addr *baddr = NULL; + __u8 matchlen = 0; + __u8 bmatchlen; + sctp_scope_t scope; memset(&fl6, 0, sizeof(fl6)); ipv6_addr_copy(&fl6.daddr, &daddr->v6.sin6_addr); @@ -261,6 +270,39 @@ static struct dst_entry *sctp_v6_get_dst(struct sctp_association *asoc, } dst = ip6_route_output(&init_net, NULL, &fl6); + if (!asoc || saddr) + goto out; + + if (dst->error) { + dst_release(dst); + dst = NULL; + bp = &asoc->base.bind_addr; + scope = sctp_scope(daddr); + /* Walk through the bind address list and try to get a dst that + * matches a bind address as the source address. + */ + rcu_read_lock(); + list_for_each_entry_rcu(laddr, &bp->address_list, list) { + if (!laddr->valid) + continue; + if ((laddr->state == SCTP_ADDR_SRC) && + (laddr->a.sa.sa_family == AF_INET6) && + (scope <= sctp_scope(&laddr->a))) { + bmatchlen = sctp_v6_addr_match_len(daddr, + &laddr->a); + if (!baddr || (matchlen < bmatchlen)) { + baddr = &laddr->a; + matchlen = bmatchlen; + } + } + } + rcu_read_unlock(); + if (baddr) { + ipv6_addr_copy(&fl6.saddr, &baddr->v6.sin6_addr); + dst = ip6_route_output(&init_net, NULL, &fl6); + } + } +out: if (!dst->error) { struct rt6_info *rt; rt = (struct rt6_info *)dst; -- cgit v0.10.2 From 9914ae3ca770389a3bec3114d0a07532a7f235dd Mon Sep 17 00:00:00 2001 From: Vlad Yasevich Date: Tue, 26 Apr 2011 21:51:31 +0000 Subject: sctp: cache the ipv6 source after route lookup The ipv6 routing lookup does give us a source address, but instead of filling it into the dst, it's stored in the flowi. We can use that instead of going through the entire source address selection again. Also the useless ->dst_saddr member of sctp_pf is removed. And sctp_v6_dst_saddr() is removed, instead by introduce sctp_v6_to_addr(), which can be reused to cleanup some dup code. Signed-off-by: Vlad Yasevich Signed-off-by: Wei Yongjun Signed-off-by: David S. Miller diff --git a/include/net/sctp/structs.h b/include/net/sctp/structs.h index 5c9bada..1d465d6 100644 --- a/include/net/sctp/structs.h +++ b/include/net/sctp/structs.h @@ -566,17 +566,15 @@ struct sctp_af { int __user *optlen); struct dst_entry *(*get_dst) (struct sctp_association *asoc, union sctp_addr *daddr, - union sctp_addr *saddr); + union sctp_addr *saddr, + struct flowi *fl, + struct sock *sk); void (*get_saddr) (struct sctp_sock *sk, - struct sctp_association *asoc, - struct dst_entry *dst, + struct sctp_transport *t, union sctp_addr *daddr, - union sctp_addr *saddr); + struct flowi *fl); void (*copy_addrlist) (struct list_head *, struct net_device *); - void (*dst_saddr) (union sctp_addr *saddr, - struct dst_entry *dst, - __be16 port); int (*cmp_addr) (const union sctp_addr *addr1, const union sctp_addr *addr2); void (*addr_copy) (union sctp_addr *dst, @@ -1061,7 +1059,7 @@ void sctp_transport_set_owner(struct sctp_transport *, struct sctp_association *); void sctp_transport_route(struct sctp_transport *, union sctp_addr *, struct sctp_sock *); -void sctp_transport_pmtu(struct sctp_transport *); +void sctp_transport_pmtu(struct sctp_transport *, struct sock *sk); void sctp_transport_free(struct sctp_transport *); void sctp_transport_reset_timers(struct sctp_transport *); void sctp_transport_hold(struct sctp_transport *); diff --git a/net/sctp/ipv6.c b/net/sctp/ipv6.c index 3a571d6..51c048d 100644 --- a/net/sctp/ipv6.c +++ b/net/sctp/ipv6.c @@ -82,6 +82,10 @@ static inline int sctp_v6_addr_match_len(union sctp_addr *s1, union sctp_addr *s2); +static void sctp_v6_to_addr(union sctp_addr *addr, struct in6_addr *saddr, + __be16 port); +static int sctp_v6_cmp_addr(const union sctp_addr *addr1, + const union sctp_addr *addr2); /* Event handler for inet6 address addition/deletion events. * The sctp_local_addr_list needs to be protocted by a spin lock since @@ -245,73 +249,99 @@ static int sctp_v6_xmit(struct sk_buff *skb, struct sctp_transport *transport) */ static struct dst_entry *sctp_v6_get_dst(struct sctp_association *asoc, union sctp_addr *daddr, - union sctp_addr *saddr) + union sctp_addr *saddr, + struct flowi *fl, + struct sock *sk) { struct dst_entry *dst = NULL; - struct flowi6 fl6; + struct flowi6 *fl6 = &fl->u.ip6; struct sctp_bind_addr *bp; struct sctp_sockaddr_entry *laddr; union sctp_addr *baddr = NULL; + union sctp_addr dst_saddr; __u8 matchlen = 0; __u8 bmatchlen; sctp_scope_t scope; + int err = 0; - memset(&fl6, 0, sizeof(fl6)); - ipv6_addr_copy(&fl6.daddr, &daddr->v6.sin6_addr); + memset(fl6, 0, sizeof(struct flowi6)); + ipv6_addr_copy(&fl6->daddr, &daddr->v6.sin6_addr); if (ipv6_addr_type(&daddr->v6.sin6_addr) & IPV6_ADDR_LINKLOCAL) - fl6.flowi6_oif = daddr->v6.sin6_scope_id; + fl6->flowi6_oif = daddr->v6.sin6_scope_id; - SCTP_DEBUG_PRINTK("%s: DST=%pI6 ", __func__, &fl6.daddr); + SCTP_DEBUG_PRINTK("%s: DST=%pI6 ", __func__, &fl6->daddr); if (saddr) { - ipv6_addr_copy(&fl6.saddr, &saddr->v6.sin6_addr); - SCTP_DEBUG_PRINTK("SRC=%pI6 - ", &fl6.saddr); + ipv6_addr_copy(&fl6->saddr, &saddr->v6.sin6_addr); + SCTP_DEBUG_PRINTK("SRC=%pI6 - ", &fl6->saddr); } - dst = ip6_route_output(&init_net, NULL, &fl6); + err = ip6_dst_lookup(sk, &dst, fl6); if (!asoc || saddr) goto out; - if (dst->error) { - dst_release(dst); - dst = NULL; - bp = &asoc->base.bind_addr; - scope = sctp_scope(daddr); - /* Walk through the bind address list and try to get a dst that - * matches a bind address as the source address. + bp = &asoc->base.bind_addr; + scope = sctp_scope(daddr); + /* ip6_dst_lookup has filled in the fl6->saddr for us. Check + * to see if we can use it. + */ + if (!err) { + /* Walk through the bind address list and look for a bind + * address that matches the source address of the returned dst. */ + sctp_v6_to_addr(&dst_saddr, &fl6->saddr, htons(bp->port)); rcu_read_lock(); list_for_each_entry_rcu(laddr, &bp->address_list, list) { - if (!laddr->valid) + if (!laddr->valid || (laddr->state != SCTP_ADDR_SRC)) continue; - if ((laddr->state == SCTP_ADDR_SRC) && - (laddr->a.sa.sa_family == AF_INET6) && - (scope <= sctp_scope(&laddr->a))) { - bmatchlen = sctp_v6_addr_match_len(daddr, - &laddr->a); - if (!baddr || (matchlen < bmatchlen)) { - baddr = &laddr->a; - matchlen = bmatchlen; - } + + /* Do not compare against v4 addrs */ + if ((laddr->a.sa.sa_family == AF_INET6) && + (sctp_v6_cmp_addr(&dst_saddr, &laddr->a))) { + rcu_read_unlock(); + goto out; } } rcu_read_unlock(); - if (baddr) { - ipv6_addr_copy(&fl6.saddr, &baddr->v6.sin6_addr); - dst = ip6_route_output(&init_net, NULL, &fl6); + /* None of the bound addresses match the source address of the + * dst. So release it. + */ + dst_release(dst); + dst = NULL; + } + + /* Walk through the bind address list and try to get the + * best source address for a given destination. + */ + rcu_read_lock(); + list_for_each_entry_rcu(laddr, &bp->address_list, list) { + if (!laddr->valid && laddr->state != SCTP_ADDR_SRC) + continue; + if ((laddr->a.sa.sa_family == AF_INET6) && + (scope <= sctp_scope(&laddr->a))) { + bmatchlen = sctp_v6_addr_match_len(daddr, &laddr->a); + if (!baddr || (matchlen < bmatchlen)) { + baddr = &laddr->a; + matchlen = bmatchlen; + } } } + rcu_read_unlock(); + if (baddr) { + ipv6_addr_copy(&fl6->saddr, &baddr->v6.sin6_addr); + err = ip6_dst_lookup(sk, &dst, fl6); + } + out: - if (!dst->error) { + if (!err) { struct rt6_info *rt; rt = (struct rt6_info *)dst; SCTP_DEBUG_PRINTK("rt6_dst:%pI6 rt6_src:%pI6\n", - &rt->rt6i_dst.addr, &rt->rt6i_src.addr); + &rt->rt6i_dst.addr, &fl6->saddr); return dst; } SCTP_DEBUG_PRINTK("NO ROUTE\n"); - dst_release(dst); return NULL; } @@ -328,64 +358,21 @@ static inline int sctp_v6_addr_match_len(union sctp_addr *s1, * and asoc's bind address list. */ static void sctp_v6_get_saddr(struct sctp_sock *sk, - struct sctp_association *asoc, - struct dst_entry *dst, + struct sctp_transport *t, union sctp_addr *daddr, - union sctp_addr *saddr) + struct flowi *fl) { - struct sctp_bind_addr *bp; - struct sctp_sockaddr_entry *laddr; - sctp_scope_t scope; - union sctp_addr *baddr = NULL; - __u8 matchlen = 0; - __u8 bmatchlen; + struct flowi6 *fl6 = &fl->u.ip6; + union sctp_addr *saddr = &t->saddr; SCTP_DEBUG_PRINTK("%s: asoc:%p dst:%p daddr:%pI6 ", - __func__, asoc, dst, &daddr->v6.sin6_addr); - - if (!asoc) { - ipv6_dev_get_saddr(sock_net(sctp_opt2sk(sk)), - dst ? ip6_dst_idev(dst)->dev : NULL, - &daddr->v6.sin6_addr, - inet6_sk(&sk->inet.sk)->srcprefs, - &saddr->v6.sin6_addr); - SCTP_DEBUG_PRINTK("saddr from ipv6_get_saddr: %pI6\n", - &saddr->v6.sin6_addr); - return; - } - - scope = sctp_scope(daddr); + __func__, t->asoc, t->dst, &daddr->v6.sin6_addr); - bp = &asoc->base.bind_addr; - - /* Go through the bind address list and find the best source address - * that matches the scope of the destination address. - */ - rcu_read_lock(); - list_for_each_entry_rcu(laddr, &bp->address_list, list) { - if (!laddr->valid) - continue; - if ((laddr->state == SCTP_ADDR_SRC) && - (laddr->a.sa.sa_family == AF_INET6) && - (scope <= sctp_scope(&laddr->a))) { - bmatchlen = sctp_v6_addr_match_len(daddr, &laddr->a); - if (!baddr || (matchlen < bmatchlen)) { - baddr = &laddr->a; - matchlen = bmatchlen; - } - } - } - if (baddr) { - memcpy(saddr, baddr, sizeof(union sctp_addr)); - SCTP_DEBUG_PRINTK("saddr: %pI6\n", &saddr->v6.sin6_addr); - } else { - pr_err("%s: asoc:%p Could not find a valid source " - "address for the dest:%pI6\n", - __func__, asoc, &daddr->v6.sin6_addr); + if (t->dst) { + saddr->v6.sin6_family = AF_INET6; + ipv6_addr_copy(&saddr->v6.sin6_addr, &fl6->saddr); } - - rcu_read_unlock(); } /* Make a copy of all potential local addresses. */ @@ -507,14 +494,13 @@ static int sctp_v6_to_addr_param(const union sctp_addr *addr, return length; } -/* Initialize a sctp_addr from a dst_entry. */ -static void sctp_v6_dst_saddr(union sctp_addr *addr, struct dst_entry *dst, +/* Initialize a sctp_addr from struct in6_addr. */ +static void sctp_v6_to_addr(union sctp_addr *addr, struct in6_addr *saddr, __be16 port) { - struct rt6_info *rt = (struct rt6_info *)dst; addr->sa.sa_family = AF_INET6; addr->v6.sin6_port = port; - ipv6_addr_copy(&addr->v6.sin6_addr, &rt->rt6i_src.addr); + ipv6_addr_copy(&addr->v6.sin6_addr, saddr); } /* Compare addresses exactly. @@ -1001,7 +987,6 @@ static struct sctp_af sctp_af_inet6 = { .to_sk_daddr = sctp_v6_to_sk_daddr, .from_addr_param = sctp_v6_from_addr_param, .to_addr_param = sctp_v6_to_addr_param, - .dst_saddr = sctp_v6_dst_saddr, .cmp_addr = sctp_v6_cmp_addr, .scope = sctp_v6_scope, .addr_valid = sctp_v6_addr_valid, diff --git a/net/sctp/protocol.c b/net/sctp/protocol.c index d5bf91d..3421645 100644 --- a/net/sctp/protocol.c +++ b/net/sctp/protocol.c @@ -465,33 +465,35 @@ static sctp_scope_t sctp_v4_scope(union sctp_addr *addr) */ static struct dst_entry *sctp_v4_get_dst(struct sctp_association *asoc, union sctp_addr *daddr, - union sctp_addr *saddr) + union sctp_addr *saddr, + struct flowi *fl, + struct sock *sk) { struct rtable *rt; - struct flowi4 fl4; + struct flowi4 *fl4 = &fl->u.ip4; struct sctp_bind_addr *bp; struct sctp_sockaddr_entry *laddr; struct dst_entry *dst = NULL; union sctp_addr dst_saddr; - memset(&fl4, 0x0, sizeof(struct flowi4)); - fl4.daddr = daddr->v4.sin_addr.s_addr; - fl4.fl4_dport = daddr->v4.sin_port; - fl4.flowi4_proto = IPPROTO_SCTP; + memset(fl4, 0x0, sizeof(struct flowi4)); + fl4->daddr = daddr->v4.sin_addr.s_addr; + fl4->fl4_dport = daddr->v4.sin_port; + fl4->flowi4_proto = IPPROTO_SCTP; if (asoc) { - fl4.flowi4_tos = RT_CONN_FLAGS(asoc->base.sk); - fl4.flowi4_oif = asoc->base.sk->sk_bound_dev_if; - fl4.fl4_sport = htons(asoc->base.bind_addr.port); + fl4->flowi4_tos = RT_CONN_FLAGS(asoc->base.sk); + fl4->flowi4_oif = asoc->base.sk->sk_bound_dev_if; + fl4->fl4_sport = htons(asoc->base.bind_addr.port); } if (saddr) { - fl4.saddr = saddr->v4.sin_addr.s_addr; - fl4.fl4_sport = saddr->v4.sin_port; + fl4->saddr = saddr->v4.sin_addr.s_addr; + fl4->fl4_sport = saddr->v4.sin_port; } SCTP_DEBUG_PRINTK("%s: DST:%pI4, SRC:%pI4 - ", - __func__, &fl4.daddr, &fl4.saddr); + __func__, &fl4->daddr, &fl4->saddr); - rt = ip_route_output_key(&init_net, &fl4); + rt = ip_route_output_key(&init_net, fl4); if (!IS_ERR(rt)) dst = &rt->dst; @@ -533,9 +535,9 @@ static struct dst_entry *sctp_v4_get_dst(struct sctp_association *asoc, continue; if ((laddr->state == SCTP_ADDR_SRC) && (AF_INET == laddr->a.sa.sa_family)) { - fl4.saddr = laddr->a.v4.sin_addr.s_addr; - fl4.fl4_sport = laddr->a.v4.sin_port; - rt = ip_route_output_key(&init_net, &fl4); + fl4->saddr = laddr->a.v4.sin_addr.s_addr; + fl4->fl4_sport = laddr->a.v4.sin_port; + rt = ip_route_output_key(&init_net, fl4); if (!IS_ERR(rt)) { dst = &rt->dst; goto out_unlock; @@ -559,19 +561,15 @@ out: * to cache it separately and hence this is an empty routine. */ static void sctp_v4_get_saddr(struct sctp_sock *sk, - struct sctp_association *asoc, - struct dst_entry *dst, + struct sctp_transport *t, union sctp_addr *daddr, - union sctp_addr *saddr) + struct flowi *fl) { - struct rtable *rt = (struct rtable *)dst; - - if (!asoc) - return; + union sctp_addr *saddr = &t->saddr; + struct rtable *rt = (struct rtable *)t->dst; if (rt) { saddr->v4.sin_family = AF_INET; - saddr->v4.sin_port = htons(asoc->base.bind_addr.port); saddr->v4.sin_addr.s_addr = rt->rt_src; } } @@ -950,7 +948,6 @@ static struct sctp_af sctp_af_inet = { .to_sk_daddr = sctp_v4_to_sk_daddr, .from_addr_param = sctp_v4_from_addr_param, .to_addr_param = sctp_v4_to_addr_param, - .dst_saddr = sctp_v4_dst_saddr, .cmp_addr = sctp_v4_cmp_addr, .addr_valid = sctp_v4_addr_valid, .inaddr_any = sctp_v4_inaddr_any, diff --git a/net/sctp/socket.c b/net/sctp/socket.c index f694ee1..33d9ee6 100644 --- a/net/sctp/socket.c +++ b/net/sctp/socket.c @@ -2287,7 +2287,7 @@ static int sctp_apply_peer_addr_params(struct sctp_paddrparams *params, trans->param_flags = (trans->param_flags & ~SPP_PMTUD) | pmtud_change; if (update) { - sctp_transport_pmtu(trans); + sctp_transport_pmtu(trans, sctp_opt2sk(sp)); sctp_assoc_sync_pmtu(asoc); } } else if (asoc) { diff --git a/net/sctp/transport.c b/net/sctp/transport.c index d3ae493..2544b9b 100644 --- a/net/sctp/transport.c +++ b/net/sctp/transport.c @@ -211,11 +211,15 @@ void sctp_transport_set_owner(struct sctp_transport *transport, } /* Initialize the pmtu of a transport. */ -void sctp_transport_pmtu(struct sctp_transport *transport) +void sctp_transport_pmtu(struct sctp_transport *transport, struct sock *sk) { struct dst_entry *dst; + struct flowi fl; - dst = transport->af_specific->get_dst(NULL, &transport->ipaddr, NULL); + dst = transport->af_specific->get_dst(transport->asoc, + &transport->ipaddr, + &transport->saddr, + &fl, sk); if (dst) { transport->pathmtu = dst_mtu(dst); @@ -272,15 +276,16 @@ void sctp_transport_route(struct sctp_transport *transport, struct sctp_af *af = transport->af_specific; union sctp_addr *daddr = &transport->ipaddr; struct dst_entry *dst; + struct flowi fl; - dst = af->get_dst(asoc, daddr, saddr); + dst = af->get_dst(asoc, daddr, saddr, &fl, sctp_opt2sk(opt)); + transport->dst = dst; if (saddr) memcpy(&transport->saddr, saddr, sizeof(union sctp_addr)); else - af->get_saddr(opt, asoc, dst, daddr, &transport->saddr); + af->get_saddr(opt, transport, daddr, &fl); - transport->dst = dst; if ((transport->param_flags & SPP_PMTUD_DISABLE) && transport->pathmtu) { return; } -- cgit v0.10.2 From 9c6a02f41d10dc9fbf5dd42058e8846f38dd2d9a Mon Sep 17 00:00:00 2001 From: Vlad Yasevich Date: Tue, 26 Apr 2011 21:52:27 +0000 Subject: sctp: make sctp over IPv6 work with IPsec SCTP never called xfrm_output after it's v6 route lookups so that never really worked with ipsec. Additioanlly, we never passed port nubmers and protocol in the flowi, so any port based policies were never applied as well. Now that we can fixed ipv6 routing lookup code, using ip6_dst_lookup_flow() and pass port numbers. Signed-off-by: Vlad Yasevich Signed-off-by: Wei Yongjun Signed-off-by: David S. Miller diff --git a/net/sctp/ipv6.c b/net/sctp/ipv6.c index 51c048d..593c801 100644 --- a/net/sctp/ipv6.c +++ b/net/sctp/ipv6.c @@ -262,22 +262,27 @@ static struct dst_entry *sctp_v6_get_dst(struct sctp_association *asoc, __u8 matchlen = 0; __u8 bmatchlen; sctp_scope_t scope; - int err = 0; memset(fl6, 0, sizeof(struct flowi6)); ipv6_addr_copy(&fl6->daddr, &daddr->v6.sin6_addr); + fl6->fl6_dport = daddr->v6.sin6_port; + fl6->flowi6_proto = IPPROTO_SCTP; if (ipv6_addr_type(&daddr->v6.sin6_addr) & IPV6_ADDR_LINKLOCAL) fl6->flowi6_oif = daddr->v6.sin6_scope_id; SCTP_DEBUG_PRINTK("%s: DST=%pI6 ", __func__, &fl6->daddr); + if (asoc) + fl6->fl6_sport = htons(asoc->base.bind_addr.port); + if (saddr) { ipv6_addr_copy(&fl6->saddr, &saddr->v6.sin6_addr); + fl6->fl6_sport = saddr->v6.sin6_port; SCTP_DEBUG_PRINTK("SRC=%pI6 - ", &fl6->saddr); } - err = ip6_dst_lookup(sk, &dst, fl6); + dst = ip6_dst_lookup_flow(sk, fl6, NULL, false); if (!asoc || saddr) goto out; @@ -286,7 +291,7 @@ static struct dst_entry *sctp_v6_get_dst(struct sctp_association *asoc, /* ip6_dst_lookup has filled in the fl6->saddr for us. Check * to see if we can use it. */ - if (!err) { + if (!IS_ERR(dst)) { /* Walk through the bind address list and look for a bind * address that matches the source address of the returned dst. */ @@ -330,11 +335,12 @@ static struct dst_entry *sctp_v6_get_dst(struct sctp_association *asoc, rcu_read_unlock(); if (baddr) { ipv6_addr_copy(&fl6->saddr, &baddr->v6.sin6_addr); - err = ip6_dst_lookup(sk, &dst, fl6); + fl6->fl6_sport = baddr->v6.sin6_port; + dst = ip6_dst_lookup_flow(sk, fl6, NULL, false); } out: - if (!err) { + if (!IS_ERR(dst)) { struct rt6_info *rt; rt = (struct rt6_info *)dst; SCTP_DEBUG_PRINTK("rt6_dst:%pI6 rt6_src:%pI6\n", -- cgit v0.10.2 From af1384703f8a4ff3d245925d6596ef1c5c6e469e Mon Sep 17 00:00:00 2001 From: Vlad Yasevich Date: Tue, 26 Apr 2011 21:53:20 +0000 Subject: sctp: remove useless arguments from get_saddr() call There is no point in passing a destination address to a get_saddr() call. Signed-off-by: Vlad Yasevich Signed-off-by: Wei Yongjun Signed-off-by: David S. Miller diff --git a/include/net/sctp/structs.h b/include/net/sctp/structs.h index 1d465d6..bb2f43b 100644 --- a/include/net/sctp/structs.h +++ b/include/net/sctp/structs.h @@ -571,7 +571,6 @@ struct sctp_af { struct sock *sk); void (*get_saddr) (struct sctp_sock *sk, struct sctp_transport *t, - union sctp_addr *daddr, struct flowi *fl); void (*copy_addrlist) (struct list_head *, struct net_device *); diff --git a/net/sctp/ipv6.c b/net/sctp/ipv6.c index 593c801..a1913a4 100644 --- a/net/sctp/ipv6.c +++ b/net/sctp/ipv6.c @@ -365,15 +365,12 @@ static inline int sctp_v6_addr_match_len(union sctp_addr *s1, */ static void sctp_v6_get_saddr(struct sctp_sock *sk, struct sctp_transport *t, - union sctp_addr *daddr, struct flowi *fl) { struct flowi6 *fl6 = &fl->u.ip6; union sctp_addr *saddr = &t->saddr; - SCTP_DEBUG_PRINTK("%s: asoc:%p dst:%p daddr:%pI6 ", - __func__, t->asoc, t->dst, &daddr->v6.sin6_addr); - + SCTP_DEBUG_PRINTK("%s: asoc:%p dst:%p\n", __func__, t->asoc, t->dst); if (t->dst) { saddr->v6.sin6_family = AF_INET6; diff --git a/net/sctp/protocol.c b/net/sctp/protocol.c index 3421645..68b4c43 100644 --- a/net/sctp/protocol.c +++ b/net/sctp/protocol.c @@ -562,7 +562,6 @@ out: */ static void sctp_v4_get_saddr(struct sctp_sock *sk, struct sctp_transport *t, - union sctp_addr *daddr, struct flowi *fl) { union sctp_addr *saddr = &t->saddr; diff --git a/net/sctp/transport.c b/net/sctp/transport.c index 2544b9b..1fbb920 100644 --- a/net/sctp/transport.c +++ b/net/sctp/transport.c @@ -284,7 +284,7 @@ void sctp_transport_route(struct sctp_transport *transport, if (saddr) memcpy(&transport->saddr, saddr, sizeof(union sctp_addr)); else - af->get_saddr(opt, transport, daddr, &fl); + af->get_saddr(opt, transport, &fl); if ((transport->param_flags & SPP_PMTUD_DISABLE) && transport->pathmtu) { return; -- cgit v0.10.2 From da0420bee24a1ba54e55a61e95b1a53205d7e62d Mon Sep 17 00:00:00 2001 From: Vlad Yasevich Date: Tue, 26 Apr 2011 21:54:17 +0000 Subject: sctp: clean up route lookup calls Change the call to take the transport parameter and set the cached 'dst' appropriately inside the get_dst() function calls. This will allow us in the future to clean up source address storage as well. Signed-off-by: Vlad Yasevich Signed-off-by: Wei Yongjun Signed-off-by: David S. Miller diff --git a/include/net/sctp/structs.h b/include/net/sctp/structs.h index bb2f43b..ff3e8cc 100644 --- a/include/net/sctp/structs.h +++ b/include/net/sctp/structs.h @@ -564,8 +564,7 @@ struct sctp_af { int optname, char __user *optval, int __user *optlen); - struct dst_entry *(*get_dst) (struct sctp_association *asoc, - union sctp_addr *daddr, + void (*get_dst) (struct sctp_transport *t, union sctp_addr *saddr, struct flowi *fl, struct sock *sk); diff --git a/net/sctp/ipv6.c b/net/sctp/ipv6.c index a1913a4..500875f 100644 --- a/net/sctp/ipv6.c +++ b/net/sctp/ipv6.c @@ -247,17 +247,16 @@ static int sctp_v6_xmit(struct sk_buff *skb, struct sctp_transport *transport) /* Returns the dst cache entry for the given source and destination ip * addresses. */ -static struct dst_entry *sctp_v6_get_dst(struct sctp_association *asoc, - union sctp_addr *daddr, - union sctp_addr *saddr, - struct flowi *fl, - struct sock *sk) +static void sctp_v6_get_dst(struct sctp_transport *t, union sctp_addr *saddr, + struct flowi *fl, struct sock *sk) { + struct sctp_association *asoc = t->asoc; struct dst_entry *dst = NULL; struct flowi6 *fl6 = &fl->u.ip6; struct sctp_bind_addr *bp; struct sctp_sockaddr_entry *laddr; union sctp_addr *baddr = NULL; + union sctp_addr *daddr = &t->ipaddr; union sctp_addr dst_saddr; __u8 matchlen = 0; __u8 bmatchlen; @@ -270,7 +269,6 @@ static struct dst_entry *sctp_v6_get_dst(struct sctp_association *asoc, if (ipv6_addr_type(&daddr->v6.sin6_addr) & IPV6_ADDR_LINKLOCAL) fl6->flowi6_oif = daddr->v6.sin6_scope_id; - SCTP_DEBUG_PRINTK("%s: DST=%pI6 ", __func__, &fl6->daddr); if (asoc) @@ -343,12 +341,13 @@ out: if (!IS_ERR(dst)) { struct rt6_info *rt; rt = (struct rt6_info *)dst; + t->dst = dst; SCTP_DEBUG_PRINTK("rt6_dst:%pI6 rt6_src:%pI6\n", &rt->rt6i_dst.addr, &fl6->saddr); - return dst; + } else { + t->dst = NULL; + SCTP_DEBUG_PRINTK("NO ROUTE\n"); } - SCTP_DEBUG_PRINTK("NO ROUTE\n"); - return NULL; } /* Returns the number of consecutive initial bits that match in the 2 ipv6 diff --git a/net/sctp/protocol.c b/net/sctp/protocol.c index 68b4c43..9d3f159 100644 --- a/net/sctp/protocol.c +++ b/net/sctp/protocol.c @@ -463,17 +463,16 @@ static sctp_scope_t sctp_v4_scope(union sctp_addr *addr) * addresses. If an association is passed, trys to get a dst entry with a * source address that matches an address in the bind address list. */ -static struct dst_entry *sctp_v4_get_dst(struct sctp_association *asoc, - union sctp_addr *daddr, - union sctp_addr *saddr, - struct flowi *fl, - struct sock *sk) +static void sctp_v4_get_dst(struct sctp_transport *t, union sctp_addr *saddr, + struct flowi *fl, struct sock *sk) { + struct sctp_association *asoc = t->asoc; struct rtable *rt; struct flowi4 *fl4 = &fl->u.ip4; struct sctp_bind_addr *bp; struct sctp_sockaddr_entry *laddr; struct dst_entry *dst = NULL; + union sctp_addr *daddr = &t->ipaddr; union sctp_addr dst_saddr; memset(fl4, 0x0, sizeof(struct flowi4)); @@ -548,13 +547,12 @@ static struct dst_entry *sctp_v4_get_dst(struct sctp_association *asoc, out_unlock: rcu_read_unlock(); out: + t->dst = dst; if (dst) SCTP_DEBUG_PRINTK("rt_dst:%pI4, rt_src:%pI4\n", &rt->rt_dst, &rt->rt_src); else SCTP_DEBUG_PRINTK("NO ROUTE\n"); - - return dst; } /* For v4, the source address is cached in the route entry(dst). So no need diff --git a/net/sctp/transport.c b/net/sctp/transport.c index 1fbb920..d8595dd 100644 --- a/net/sctp/transport.c +++ b/net/sctp/transport.c @@ -213,17 +213,17 @@ void sctp_transport_set_owner(struct sctp_transport *transport, /* Initialize the pmtu of a transport. */ void sctp_transport_pmtu(struct sctp_transport *transport, struct sock *sk) { - struct dst_entry *dst; struct flowi fl; - dst = transport->af_specific->get_dst(transport->asoc, - &transport->ipaddr, - &transport->saddr, + /* If we don't have a fresh route, look one up */ + if (!transport->dst || transport->dst->obsolete > 1) { + dst_release(transport->dst); + transport->af_specific->get_dst(transport, &transport->saddr, &fl, sk); + } - if (dst) { - transport->pathmtu = dst_mtu(dst); - dst_release(dst); + if (transport->dst) { + transport->pathmtu = dst_mtu(transport->dst); } else transport->pathmtu = SCTP_DEFAULT_MAXSEGMENT; } @@ -274,12 +274,9 @@ void sctp_transport_route(struct sctp_transport *transport, { struct sctp_association *asoc = transport->asoc; struct sctp_af *af = transport->af_specific; - union sctp_addr *daddr = &transport->ipaddr; - struct dst_entry *dst; struct flowi fl; - dst = af->get_dst(asoc, daddr, saddr, &fl, sctp_opt2sk(opt)); - transport->dst = dst; + af->get_dst(transport, saddr, &fl, sctp_opt2sk(opt)); if (saddr) memcpy(&transport->saddr, saddr, sizeof(union sctp_addr)); @@ -289,8 +286,8 @@ void sctp_transport_route(struct sctp_transport *transport, if ((transport->param_flags & SPP_PMTUD_DISABLE) && transport->pathmtu) { return; } - if (dst) { - transport->pathmtu = dst_mtu(dst); + if (transport->dst) { + transport->pathmtu = dst_mtu(transport->dst); /* Initialize sk->sk_rcv_saddr, if the transport is the * association's active path for getsockname(). -- cgit v0.10.2 From 613e901e1ee0e1096663b649eee8e5d6697919f3 Mon Sep 17 00:00:00 2001 From: Bryan Schumaker Date: Wed, 27 Apr 2011 15:28:44 -0400 Subject: NFS: Return meaningful status from decode_secinfo() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When compiling, I was getting this warning: fs/nfs/nfs4xdr.c: In function ‘decode_secinfo’: fs/nfs/nfs4xdr.c:4839:6: warning: variable ‘status’ set but not used [-Wunused-but-set-variable] We were unconditionally returning 0 as long as there wasn't an error coming out of xdr_inline_decode(). We probably want to check the error status coming out of decode_op_hdr() and decode_secinfo_gss(), rather than assuming that everything is OK all the time. Signed-off-by: Bryan Schumaker Signed-off-by: Trond Myklebust diff --git a/fs/nfs/nfs4xdr.c b/fs/nfs/nfs4xdr.c index 7310d2e..c3ccd2c 100644 --- a/fs/nfs/nfs4xdr.c +++ b/fs/nfs/nfs4xdr.c @@ -4836,6 +4836,8 @@ static int decode_secinfo(struct xdr_stream *xdr, struct nfs4_secinfo_res *res) int i, num_flavors; status = decode_op_hdr(xdr, OP_SECINFO); + if (status) + goto out; p = xdr_inline_decode(xdr, 4); if (unlikely(!p)) goto out_overflow; @@ -4854,14 +4856,15 @@ static int decode_secinfo(struct xdr_stream *xdr, struct nfs4_secinfo_res *res) sec_flavor->flavor = be32_to_cpup(p); if (sec_flavor->flavor == RPC_AUTH_GSS) { - if (decode_secinfo_gss(xdr, sec_flavor)) - break; + status = decode_secinfo_gss(xdr, sec_flavor); + if (status) + goto out; } res->flavors->num_flavors++; } - return 0; - +out: + return status; out_overflow: print_overflow_msg(__func__, xdr); return -EIO; -- cgit v0.10.2 From 26c4c170731f00008f4317a2888a0a07ac99d90d Mon Sep 17 00:00:00 2001 From: Jeff Layton Date: Wed, 27 Apr 2011 11:49:09 -0400 Subject: nfs: don't lose MS_SYNCHRONOUS on remount of noac mount On a remount, the VFS layer will clear the MS_SYNCHRONOUS bit on the assumption that the flags on the mount syscall will have it set if the remounted fs is supposed to keep it. In the case of "noac" though, MS_SYNCHRONOUS is implied. A remount of such a mount will lose the MS_SYNCHRONOUS flag since "sync" isn't part of the mount options. Reported-by: Max Matveev Signed-off-by: Jeff Layton Cc: stable@kernel.org Signed-off-by: Trond Myklebust diff --git a/fs/nfs/super.c b/fs/nfs/super.c index 75bcc3f..e288f06 100644 --- a/fs/nfs/super.c +++ b/fs/nfs/super.c @@ -1977,6 +1977,15 @@ nfs_remount(struct super_block *sb, int *flags, char *raw_data) if (error < 0) goto out; + /* + * noac is a special case. It implies -o sync, but that's not + * necessarily reflected in the mtab options. do_remount_sb + * will clear MS_SYNCHRONOUS if -o sync wasn't specified in the + * remount options, so we have to explicitly reset it. + */ + if (data->flags & NFS_MOUNT_NOAC) + *flags |= MS_SYNCHRONOUS; + /* compare new mount options with old ones */ error = nfs_compare_remount_data(nfss, data); out: -- cgit v0.10.2 From 15ecd039b7182d725f4294e01f2fb12c3a88db17 Mon Sep 17 00:00:00 2001 From: Francois Romieu Date: Wed, 27 Apr 2011 13:52:22 -0700 Subject: r8169: fix merge conflict fix. - use adequate MAC_VER id (see 01dc7fec4025f6bb72b6b98ec88b375346b6dbbb) - remove duplicate rtl_firmware_info record - remove duplicate functions Signed-off-by: Francois Romieu Cc: Realtek linux nic maintainers Signed-off-by: David S. Miller diff --git a/drivers/net/r8169.c b/drivers/net/r8169.c index 025dedd..6364e0b 100644 --- a/drivers/net/r8169.c +++ b/drivers/net/r8169.c @@ -191,9 +191,8 @@ static const struct rtl_firmware_info { { .mac_version = RTL_GIGA_MAC_VER_26, .fw_name = FIRMWARE_8168D_2 }, { .mac_version = RTL_GIGA_MAC_VER_29, .fw_name = FIRMWARE_8105E_1 }, { .mac_version = RTL_GIGA_MAC_VER_30, .fw_name = FIRMWARE_8105E_1 }, - { .mac_version = RTL_GIGA_MAC_VER_30, .fw_name = FIRMWARE_8105E_1 }, - { .mac_version = RTL_GIGA_MAC_VER_31, .fw_name = FIRMWARE_8168E_1 }, - { .mac_version = RTL_GIGA_MAC_VER_32, .fw_name = FIRMWARE_8168E_2 } + { .mac_version = RTL_GIGA_MAC_VER_32, .fw_name = FIRMWARE_8168E_1 }, + { .mac_version = RTL_GIGA_MAC_VER_33, .fw_name = FIRMWARE_8168E_2 } }; enum cfg_version { @@ -2535,6 +2534,8 @@ static void rtl8168e_hw_phy_config(struct rtl8169_private *tp) { 0x1f, 0x0000 } }; + rtl_apply_firmware(tp); + rtl_writephy_batch(tp, phy_reg_init, ARRAY_SIZE(phy_reg_init)); /* DCO enable for 10M IDLE Power */ @@ -2576,20 +2577,6 @@ static void rtl8168e_hw_phy_config(struct rtl8169_private *tp) rtl_writephy(tp, 0x0d, 0x0000); } -static void rtl8168e_1_hw_phy_config(struct rtl8169_private *tp) -{ - rtl_apply_firmware(tp); - - rtl8168e_hw_phy_config(tp); -} - -static void rtl8168e_2_hw_phy_config(struct rtl8169_private *tp) -{ - rtl_apply_firmware(tp); - - rtl8168e_hw_phy_config(tp); -} - static void rtl8102e_hw_phy_config(struct rtl8169_private *tp) { static const struct phy_reg phy_reg_init[] = { @@ -2705,10 +2692,8 @@ static void rtl_hw_phy_config(struct net_device *dev) rtl8105e_hw_phy_config(tp); break; case RTL_GIGA_MAC_VER_32: - rtl8168e_1_hw_phy_config(tp); - break; case RTL_GIGA_MAC_VER_33: - rtl8168e_2_hw_phy_config(tp); + rtl8168e_hw_phy_config(tp); break; default: -- cgit v0.10.2 From 2d7192d6cbab20e153c47fa1559ffd41ceef0e79 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Tue, 26 Apr 2011 13:28:44 -0700 Subject: ipv4: Sanitize and simplify ip_route_{connect,newports}() These functions are used together as a unit for route resolution during connect(). They address the chicken-and-egg problem that exists when ports need to be allocated during connect() processing, yet such port allocations require addressing information from the routing code. It's currently more heavy handed than it needs to be, and in particular we allocate and initialize a flow object twice. Let the callers provide the on-stack flow object. That way we only need to initialize it once in the ip_route_connect() call. Later, if ip_route_newports() needs to do anything, it re-uses that flow object as-is except for the ports which it updates before the route re-lookup. Also, describe why this set of facilities are needed and how it works in a big comment. Signed-off-by: David S. Miller Reviewed-by: Eric Dumazet diff --git a/include/net/route.h b/include/net/route.h index 3684c3e..79530da 100644 --- a/include/net/route.h +++ b/include/net/route.h @@ -217,17 +217,37 @@ static inline char rt_tos2priority(u8 tos) return ip_tos2prio[IPTOS_TOS(tos)>>1]; } -static inline struct rtable *ip_route_connect(__be32 dst, __be32 src, u32 tos, - int oif, u8 protocol, - __be16 sport, __be16 dport, - struct sock *sk, bool can_sleep) +/* ip_route_connect() and ip_route_newports() work in tandem whilst + * binding a socket for a new outgoing connection. + * + * In order to use IPSEC properly, we must, in the end, have a + * route that was looked up using all available keys including source + * and destination ports. + * + * However, if a source port needs to be allocated (the user specified + * a wildcard source port) we need to obtain addressing information + * in order to perform that allocation. + * + * So ip_route_connect() looks up a route using wildcarded source and + * destination ports in the key, simply so that we can get a pair of + * addresses to use for port allocation. + * + * Later, once the ports are allocated, ip_route_newports() will make + * another route lookup if needed to make sure we catch any IPSEC + * rules keyed on the port information. + * + * The callers allocate the flow key on their stack, and must pass in + * the same flowi4 object to both the ip_route_connect() and the + * ip_route_newports() calls. + */ + +static inline void ip_route_connect_init(struct flowi4 *fl4, __be32 dst, __be32 src, + u32 tos, int oif, u8 protocol, + __be16 sport, __be16 dport, + struct sock *sk, bool can_sleep) { - struct net *net = sock_net(sk); - struct rtable *rt; - struct flowi4 fl4; - __u8 flow_flags; + __u8 flow_flags = 0; - flow_flags = 0; if (inet_sk(sk)->transparent) flow_flags |= FLOWI_FLAG_ANYSRC; if (protocol == IPPROTO_TCP) @@ -235,41 +255,45 @@ static inline struct rtable *ip_route_connect(__be32 dst, __be32 src, u32 tos, if (can_sleep) flow_flags |= FLOWI_FLAG_CAN_SLEEP; - flowi4_init_output(&fl4, oif, sk->sk_mark, tos, RT_SCOPE_UNIVERSE, + flowi4_init_output(fl4, oif, sk->sk_mark, tos, RT_SCOPE_UNIVERSE, protocol, flow_flags, dst, src, dport, sport); +} + +static inline struct rtable *ip_route_connect(struct flowi4 *fl4, + __be32 dst, __be32 src, u32 tos, + int oif, u8 protocol, + __be16 sport, __be16 dport, + struct sock *sk, bool can_sleep) +{ + struct net *net = sock_net(sk); + struct rtable *rt; + + ip_route_connect_init(fl4, dst, src, tos, oif, protocol, + sport, dport, sk, can_sleep); if (!dst || !src) { - rt = __ip_route_output_key(net, &fl4); + rt = __ip_route_output_key(net, fl4); if (IS_ERR(rt)) return rt; - fl4.daddr = rt->rt_dst; - fl4.saddr = rt->rt_src; + fl4->daddr = rt->rt_dst; + fl4->saddr = rt->rt_src; ip_rt_put(rt); } - security_sk_classify_flow(sk, flowi4_to_flowi(&fl4)); - return ip_route_output_flow(net, &fl4, sk); + security_sk_classify_flow(sk, flowi4_to_flowi(fl4)); + return ip_route_output_flow(net, fl4, sk); } -static inline struct rtable *ip_route_newports(struct rtable *rt, - u8 protocol, __be16 orig_sport, - __be16 orig_dport, __be16 sport, - __be16 dport, struct sock *sk) +static inline struct rtable *ip_route_newports(struct flowi4 *fl4, struct rtable *rt, + __be16 orig_sport, __be16 orig_dport, + __be16 sport, __be16 dport, + struct sock *sk) { if (sport != orig_sport || dport != orig_dport) { - struct flowi4 fl4; - __u8 flow_flags; - - flow_flags = 0; - if (inet_sk(sk)->transparent) - flow_flags |= FLOWI_FLAG_ANYSRC; - if (protocol == IPPROTO_TCP) - flow_flags |= FLOWI_FLAG_PRECOW_METRICS; - flowi4_init_output(&fl4, rt->rt_oif, rt->rt_mark, rt->rt_tos, - RT_SCOPE_UNIVERSE, protocol, flow_flags, - rt->rt_dst, rt->rt_src, dport, sport); + fl4->fl4_dport = dport; + fl4->fl4_sport = sport; ip_rt_put(rt); - security_sk_classify_flow(sk, flowi4_to_flowi(&fl4)); - return ip_route_output_flow(sock_net(sk), &fl4, sk); + security_sk_classify_flow(sk, flowi4_to_flowi(fl4)); + return ip_route_output_flow(sock_net(sk), fl4, sk); } return rt; } diff --git a/net/dccp/ipv4.c b/net/dccp/ipv4.c index ae451c6..b92ab65 100644 --- a/net/dccp/ipv4.c +++ b/net/dccp/ipv4.c @@ -40,12 +40,13 @@ int dccp_v4_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len) { + const struct sockaddr_in *usin = (struct sockaddr_in *)uaddr; struct inet_sock *inet = inet_sk(sk); struct dccp_sock *dp = dccp_sk(sk); - const struct sockaddr_in *usin = (struct sockaddr_in *)uaddr; __be16 orig_sport, orig_dport; - struct rtable *rt; __be32 daddr, nexthop; + struct flowi4 fl4; + struct rtable *rt; int err; dp->dccps_role = DCCP_ROLE_CLIENT; @@ -65,7 +66,7 @@ int dccp_v4_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len) orig_sport = inet->inet_sport; orig_dport = usin->sin_port; - rt = ip_route_connect(nexthop, inet->inet_saddr, + rt = ip_route_connect(&fl4, nexthop, inet->inet_saddr, RT_CONN_FLAGS(sk), sk->sk_bound_dev_if, IPPROTO_DCCP, orig_sport, orig_dport, sk, true); @@ -101,8 +102,7 @@ int dccp_v4_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len) if (err != 0) goto failure; - rt = ip_route_newports(rt, IPPROTO_DCCP, - orig_sport, orig_dport, + rt = ip_route_newports(&fl4, rt, orig_sport, orig_dport, inet->inet_sport, inet->inet_dport, sk); if (IS_ERR(rt)) { rt = NULL; diff --git a/net/ipv4/af_inet.c b/net/ipv4/af_inet.c index cae75ef..0413af3 100644 --- a/net/ipv4/af_inet.c +++ b/net/ipv4/af_inet.c @@ -1103,6 +1103,7 @@ static int inet_sk_reselect_saddr(struct sock *sk) struct inet_sock *inet = inet_sk(sk); __be32 old_saddr = inet->inet_saddr; __be32 daddr = inet->inet_daddr; + struct flowi4 fl4; struct rtable *rt; __be32 new_saddr; @@ -1110,7 +1111,7 @@ static int inet_sk_reselect_saddr(struct sock *sk) daddr = inet->opt->faddr; /* Query new route. */ - rt = ip_route_connect(daddr, 0, RT_CONN_FLAGS(sk), + rt = ip_route_connect(&fl4, daddr, 0, RT_CONN_FLAGS(sk), sk->sk_bound_dev_if, sk->sk_protocol, inet->inet_sport, inet->inet_dport, sk, false); if (IS_ERR(rt)) diff --git a/net/ipv4/datagram.c b/net/ipv4/datagram.c index 85bd24c..216ba23 100644 --- a/net/ipv4/datagram.c +++ b/net/ipv4/datagram.c @@ -24,6 +24,7 @@ int ip4_datagram_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len) { struct inet_sock *inet = inet_sk(sk); struct sockaddr_in *usin = (struct sockaddr_in *) uaddr; + struct flowi4 fl4; struct rtable *rt; __be32 saddr; int oif; @@ -46,7 +47,7 @@ int ip4_datagram_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len) if (!saddr) saddr = inet->mc_addr; } - rt = ip_route_connect(usin->sin_addr.s_addr, saddr, + rt = ip_route_connect(&fl4, usin->sin_addr.s_addr, saddr, RT_CONN_FLAGS(sk), oif, sk->sk_protocol, inet->inet_sport, usin->sin_port, sk, true); diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c index edf18bd..310454c 100644 --- a/net/ipv4/tcp_ipv4.c +++ b/net/ipv4/tcp_ipv4.c @@ -146,12 +146,13 @@ EXPORT_SYMBOL_GPL(tcp_twsk_unique); /* This will initiate an outgoing connection. */ int tcp_v4_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len) { + struct sockaddr_in *usin = (struct sockaddr_in *)uaddr; struct inet_sock *inet = inet_sk(sk); struct tcp_sock *tp = tcp_sk(sk); - struct sockaddr_in *usin = (struct sockaddr_in *)uaddr; __be16 orig_sport, orig_dport; - struct rtable *rt; __be32 daddr, nexthop; + struct flowi4 fl4; + struct rtable *rt; int err; if (addr_len < sizeof(struct sockaddr_in)) @@ -169,7 +170,7 @@ int tcp_v4_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len) orig_sport = inet->inet_sport; orig_dport = usin->sin_port; - rt = ip_route_connect(nexthop, inet->inet_saddr, + rt = ip_route_connect(&fl4, nexthop, inet->inet_saddr, RT_CONN_FLAGS(sk), sk->sk_bound_dev_if, IPPROTO_TCP, orig_sport, orig_dport, sk, true); @@ -236,8 +237,7 @@ int tcp_v4_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len) if (err) goto failure; - rt = ip_route_newports(rt, IPPROTO_TCP, - orig_sport, orig_dport, + rt = ip_route_newports(&fl4, rt, orig_sport, orig_dport, inet->inet_sport, inet->inet_dport, sk); if (IS_ERR(rt)) { err = PTR_ERR(rt); diff --git a/net/l2tp/l2tp_ip.c b/net/l2tp/l2tp_ip.c index fce9bd3..cc67367 100644 --- a/net/l2tp/l2tp_ip.c +++ b/net/l2tp/l2tp_ip.c @@ -296,12 +296,12 @@ out_in_use: static int l2tp_ip_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len) { - int rc; - struct inet_sock *inet = inet_sk(sk); struct sockaddr_l2tpip *lsa = (struct sockaddr_l2tpip *) uaddr; + struct inet_sock *inet = inet_sk(sk); + struct flowi4 fl4; struct rtable *rt; __be32 saddr; - int oif; + int oif, rc; rc = -EINVAL; if (addr_len < sizeof(*lsa)) @@ -320,7 +320,7 @@ static int l2tp_ip_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len if (ipv4_is_multicast(lsa->l2tp_addr.s_addr)) goto out; - rt = ip_route_connect(lsa->l2tp_addr.s_addr, saddr, + rt = ip_route_connect(&fl4, lsa->l2tp_addr.s_addr, saddr, RT_CONN_FLAGS(sk), oif, IPPROTO_L2TP, 0, 0, sk, true); -- cgit v0.10.2 From 2e97e980b5653c23d01c911af6a0ab2d3431d7f1 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Tue, 26 Apr 2011 13:57:47 -0700 Subject: ipv4: Remove erroneous check in igmpv3_newpack() and igmp_send_report(). Output route resolution never returns a route with rt_src set to zero (which is INADDR_ANY). Even if the flow key for the output route lookup specifies INADDR_ANY for the source address, the output route resolution chooses a real source address to use in the final route. This test has existed forever in igmp_send_report() and David Stevens simply copied over the erroneous test when implementing support for IGMPv3. Signed-off-by: David S. Miller Reviewed-by: Eric Dumazet diff --git a/net/ipv4/igmp.c b/net/ipv4/igmp.c index 1fd3d9c..8ae0a57 100644 --- a/net/ipv4/igmp.c +++ b/net/ipv4/igmp.c @@ -328,11 +328,6 @@ static struct sk_buff *igmpv3_newpack(struct net_device *dev, int size) kfree_skb(skb); return NULL; } - if (rt->rt_src == 0) { - kfree_skb(skb); - ip_rt_put(rt); - return NULL; - } skb_dst_set(skb, &rt->dst); skb->dev = dev; @@ -670,11 +665,6 @@ static int igmp_send_report(struct in_device *in_dev, struct ip_mc_list *pmc, if (IS_ERR(rt)) return -1; - if (rt->rt_src == 0) { - ip_rt_put(rt); - return -1; - } - skb = alloc_skb(IGMP_SIZE+LL_ALLOCATED_SPACE(dev), GFP_ATOMIC); if (skb == NULL) { ip_rt_put(rt); -- cgit v0.10.2 From b678027cb77b079bc8e5b94172995d173bdb494b Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Tue, 26 Apr 2011 14:58:35 -0700 Subject: ipv4: Kill RTO_CONN. It's not used by anything in the kernel, and defined in net/route.h so never exported to userspace. Therefore we can safely remove it. Signed-off-by: David S. Miller diff --git a/include/net/route.h b/include/net/route.h index 79530da..fdbdb92 100644 --- a/include/net/route.h +++ b/include/net/route.h @@ -37,10 +37,6 @@ #define RTO_ONLINK 0x01 -#define RTO_CONN 0 -/* RTO_CONN is not used (being alias for 0), but preserved not to break - * some modules referring to it. */ - #define RT_CONN_FLAGS(sk) (RT_TOS(inet_sk(sk)->tos) | sock_flag(sk, SOCK_LOCALROUTE)) struct fib_nh; -- cgit v0.10.2 From 860ad7823fdc00cd61dc70e7f35e07fb327cc9a4 Mon Sep 17 00:00:00 2001 From: Sonny Rao Date: Mon, 18 Apr 2011 22:12:59 +0100 Subject: ARM: 6884/1: Fix infinite loop in ARM user perf_event backtrace code The ARM user backtrace code can get into an infinite loop if it runs into an invalid stack frame which points back to itself. This situation has been observed in practice. Fix it by capping the number of entries in the backtrace. This is also what other architectures do in their backtrace code. Signed-off-by: Sonny Rao Acked-by: Jamie Iles Acked-by: Olof Johansson Signed-off-by: Russell King diff --git a/arch/arm/kernel/perf_event.c b/arch/arm/kernel/perf_event.c index 979da39..139e3c8 100644 --- a/arch/arm/kernel/perf_event.c +++ b/arch/arm/kernel/perf_event.c @@ -746,7 +746,8 @@ perf_callchain_user(struct perf_callchain_entry *entry, struct pt_regs *regs) tail = (struct frame_tail __user *)regs->ARM_fp - 1; - while (tail && !((unsigned long)tail & 0x3)) + while ((entry->nr < PERF_MAX_STACK_DEPTH) && + tail && !((unsigned long)tail & 0x3)) tail = user_backtrace(tail, entry); } -- cgit v0.10.2 From a8d2518c2a7235f0b772c1f1bd30218130e631a7 Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Wed, 27 Apr 2011 01:34:27 +0100 Subject: ARM: 6887/1: Mark broadcast_timer_setup() __cpuinit This function is only called by percpu_timer_setup() which is also __cpuinit marked. Thus it's safe to mark this function as __cpuinit as well. Signed-off-by: Stephen Boyd Signed-off-by: Russell King diff --git a/arch/arm/kernel/smp.c b/arch/arm/kernel/smp.c index 8fe05ad..f29b8a2 100644 --- a/arch/arm/kernel/smp.c +++ b/arch/arm/kernel/smp.c @@ -479,7 +479,7 @@ static void broadcast_timer_set_mode(enum clock_event_mode mode, { } -static void broadcast_timer_setup(struct clock_event_device *evt) +static void __cpuinit broadcast_timer_setup(struct clock_event_device *evt) { evt->name = "dummy_timer"; evt->features = CLOCK_EVT_FEAT_ONESHOT | -- cgit v0.10.2 From 0c61227094b3ddaca2f847ee287c4a2e3762b5a2 Mon Sep 17 00:00:00 2001 From: Gleb Natapov Date: Tue, 26 Apr 2011 11:21:32 +0300 Subject: x86, setup: Fix EDD3.0 data verification. Check for nonzero path in edd_has_edd30() has no sense. First, it looks at the wrong memory. Device path starts at offset 30 of the info->params structure which is at offset 8 from the beginning of info structure, but code looks at info + 4 instead. This was correct when code was introduced, but around v2.6.4 three more fields were added to edd_info structure (commit 66b61a5c in history.git). Second, even if it will check correct memory it will always succeed since at offset 30 (params->key) there will be non-zero values otherwise previous check would fail. The patch replaces this bogus check with one that verifies checksum. Signed-off-by: Gleb Natapov Link: http://lkml.kernel.org/r/20110426082132.GG2265@redhat.com Signed-off-by: H. Peter Anvin diff --git a/drivers/firmware/edd.c b/drivers/firmware/edd.c index 96c25d9..f1b7f65 100644 --- a/drivers/firmware/edd.c +++ b/drivers/firmware/edd.c @@ -531,8 +531,8 @@ static int edd_has_edd30(struct edd_device *edev) { struct edd_info *info; - int i, nonzero_path = 0; - char c; + int i; + u8 csum = 0; if (!edev) return 0; @@ -544,16 +544,16 @@ edd_has_edd30(struct edd_device *edev) return 0; } - for (i = 30; i <= 73; i++) { - c = *(((uint8_t *) info) + i + 4); - if (c) { - nonzero_path++; - break; - } - } - if (!nonzero_path) { + + /* We support only T13 spec */ + if (info->params.device_path_info_length != 44) + return 0; + + for (i = 30; i < info->params.device_path_info_length + 30; i++) + csum += *(((u8 *)&info->params) + i); + + if (csum) return 0; - } return 1; } -- cgit v0.10.2 From 5d41ce1dd91bce01d50aff79786dc5d5eedcfab7 Mon Sep 17 00:00:00 2001 From: "Gustavo F. Padovan" Date: Fri, 8 Apr 2011 15:40:02 -0300 Subject: Bluetooth: Refactor L2CAP channel allocation If the allocation happens at l2cap_sock_create() will be able to use the struct l2cap_chan to store channel info that comes from the user via setsockopt. Signed-off-by: Gustavo F. Padovan diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h index 7a215a7..537e3c1 100644 --- a/include/net/bluetooth/l2cap.h +++ b/include/net/bluetooth/l2cap.h @@ -465,7 +465,8 @@ void l2cap_sock_init(struct sock *sk, struct sock *parent); struct sock *l2cap_sock_alloc(struct net *net, struct socket *sock, int proto, gfp_t prio); void l2cap_send_disconn_req(struct l2cap_conn *conn, struct l2cap_chan *chan, int err); +struct l2cap_chan *l2cap_chan_alloc(struct sock *sk); void l2cap_chan_del(struct l2cap_chan *chan, int err); -int l2cap_do_connect(struct sock *sk); +int l2cap_do_connect(struct l2cap_chan *chan); #endif /* __L2CAP_H */ diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index 9e8dc13..4b857ad 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -149,7 +149,7 @@ static u16 l2cap_alloc_cid(struct l2cap_conn *conn) return 0; } -static struct l2cap_chan *l2cap_chan_alloc(struct sock *sk) +struct l2cap_chan *l2cap_chan_alloc(struct sock *sk) { struct l2cap_chan *chan; @@ -648,6 +648,8 @@ static void l2cap_le_conn_ready(struct l2cap_conn *conn) goto clean; } + l2cap_pi(sk)->chan = chan; + write_lock_bh(&conn->chan_lock); hci_conn_hold(conn->hcon); @@ -661,8 +663,6 @@ static void l2cap_le_conn_ready(struct l2cap_conn *conn) __l2cap_chan_add(conn, chan); - l2cap_pi(sk)->chan = chan; - l2cap_sock_set_timer(sk, sk->sk_sndtimeo); sk->sk_state = BT_CONNECTED; @@ -847,12 +847,12 @@ static struct sock *l2cap_get_sock_by_psm(int state, __le16 psm, bdaddr_t *src) return node ? sk : sk1; } -int l2cap_do_connect(struct sock *sk) +int l2cap_do_connect(struct l2cap_chan *chan) { + struct sock *sk = chan->sk; bdaddr_t *src = &bt_sk(sk)->src; bdaddr_t *dst = &bt_sk(sk)->dst; struct l2cap_conn *conn; - struct l2cap_chan *chan; struct hci_conn *hcon; struct hci_dev *hdev; __u8 auth_type; @@ -888,20 +888,11 @@ int l2cap_do_connect(struct sock *sk) goto done; } - chan = l2cap_chan_alloc(sk); - if (!chan) { - hci_conn_put(hcon); - err = -ENOMEM; - goto done; - } - /* Update source addr of the socket */ bacpy(src, conn->src); l2cap_chan_add(conn, chan); - l2cap_pi(sk)->chan = chan; - sk->sk_state = BT_CONNECT; l2cap_sock_set_timer(sk, sk->sk_sndtimeo); @@ -2076,6 +2067,8 @@ static inline int l2cap_connect_req(struct l2cap_conn *conn, struct l2cap_cmd_hd goto response; } + l2cap_pi(sk)->chan = chan; + write_lock_bh(&conn->chan_lock); /* Check if we already have channel with that dcid */ @@ -2098,8 +2091,6 @@ static inline int l2cap_connect_req(struct l2cap_conn *conn, struct l2cap_cmd_hd __l2cap_chan_add(conn, chan); - l2cap_pi(sk)->chan = chan; - dcid = l2cap_pi(sk)->scid; l2cap_sock_set_timer(sk, sk->sk_sndtimeo); diff --git a/net/bluetooth/l2cap_sock.c b/net/bluetooth/l2cap_sock.c index 473e597..e372457 100644 --- a/net/bluetooth/l2cap_sock.c +++ b/net/bluetooth/l2cap_sock.c @@ -229,7 +229,7 @@ static int l2cap_sock_connect(struct socket *sock, struct sockaddr *addr, int al l2cap_pi(sk)->psm = la.l2_psm; l2cap_pi(sk)->dcid = la.l2_cid; - err = l2cap_do_connect(sk); + err = l2cap_do_connect(l2cap_pi(sk)->chan); if (err) goto done; @@ -1054,6 +1054,7 @@ static int l2cap_sock_create(struct net *net, struct socket *sock, int protocol, int kern) { struct sock *sk; + struct l2cap_chan *chan; BT_DBG("sock %p", sock); @@ -1072,6 +1073,14 @@ static int l2cap_sock_create(struct net *net, struct socket *sock, int protocol, if (!sk) return -ENOMEM; + chan = l2cap_chan_alloc(sk); + if (!chan) { + l2cap_sock_kill(sk); + return -ENOMEM; + } + + l2cap_pi(sk)->chan = chan; + l2cap_sock_init(sk, NULL); return 0; } -- cgit v0.10.2 From b44500351845e4f6df0d752a8870da246be8216f Mon Sep 17 00:00:00 2001 From: "Gustavo F. Padovan" Date: Tue, 12 Apr 2011 18:15:09 -0300 Subject: Bluetooth: Move conf_state to struct l2cap_chan First move of elements depending on user data. Signed-off-by: Gustavo F. Padovan diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h index 537e3c1..b3bb3d4 100644 --- a/include/net/bluetooth/l2cap.h +++ b/include/net/bluetooth/l2cap.h @@ -291,6 +291,7 @@ struct l2cap_chan { __u8 num_conf_req; __u8 num_conf_rsp; + __u8 conf_state; __u16 conn_state; __u8 next_tx_seq; @@ -375,8 +376,6 @@ struct l2cap_pinfo { __u8 force_reliable; __u8 flushable; - __u8 conf_state; - __u8 tx_win; __u8 max_tx; __u16 retrans_timeout; diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index 4b857ad..190b049 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -236,8 +236,8 @@ void l2cap_chan_del(struct l2cap_chan *chan, int err) } else sk->sk_state_change(sk); - if (!(l2cap_pi(sk)->conf_state & L2CAP_CONF_OUTPUT_DONE && - l2cap_pi(sk)->conf_state & L2CAP_CONF_INPUT_DONE)) + if (!(chan->conf_state & L2CAP_CONF_OUTPUT_DONE && + chan->conf_state & L2CAP_CONF_INPUT_DONE)) goto free; skb_queue_purge(&chan->tx_q); @@ -411,9 +411,9 @@ static inline void l2cap_send_rr_or_rnr(struct l2cap_chan *chan, u16 control) l2cap_send_sframe(chan, control); } -static inline int __l2cap_no_conn_pending(struct sock *sk) +static inline int __l2cap_no_conn_pending(struct l2cap_chan *chan) { - return !(l2cap_pi(sk)->conf_state & L2CAP_CONF_CONNECT_PEND); + return !(chan->conf_state & L2CAP_CONF_CONNECT_PEND); } static void l2cap_do_start(struct l2cap_chan *chan) @@ -425,13 +425,13 @@ static void l2cap_do_start(struct l2cap_chan *chan) if (!(conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_DONE)) return; - if (l2cap_check_security(sk) && __l2cap_no_conn_pending(sk)) { + if (l2cap_check_security(sk) && __l2cap_no_conn_pending(chan)) { struct l2cap_conn_req req; req.scid = cpu_to_le16(l2cap_pi(sk)->scid); req.psm = l2cap_pi(sk)->psm; chan->ident = l2cap_get_ident(conn); - l2cap_pi(sk)->conf_state |= L2CAP_CONF_CONNECT_PEND; + chan->conf_state |= L2CAP_CONF_CONNECT_PEND; l2cap_send_cmd(conn, chan->ident, L2CAP_CONN_REQ, sizeof(req), &req); @@ -516,14 +516,14 @@ static void l2cap_conn_start(struct l2cap_conn *conn) struct l2cap_conn_req req; if (!l2cap_check_security(sk) || - !__l2cap_no_conn_pending(sk)) { + !__l2cap_no_conn_pending(chan)) { bh_unlock_sock(sk); continue; } if (!l2cap_mode_supported(l2cap_pi(sk)->mode, conn->feat_mask) - && l2cap_pi(sk)->conf_state & + && chan->conf_state & L2CAP_CONF_STATE2_DEVICE) { /* __l2cap_sock_close() calls list_del(chan) * so release the lock */ @@ -538,7 +538,7 @@ static void l2cap_conn_start(struct l2cap_conn *conn) req.psm = l2cap_pi(sk)->psm; chan->ident = l2cap_get_ident(conn); - l2cap_pi(sk)->conf_state |= L2CAP_CONF_CONNECT_PEND; + chan->conf_state |= L2CAP_CONF_CONNECT_PEND; l2cap_send_cmd(conn, chan->ident, L2CAP_CONN_REQ, sizeof(req), &req); @@ -569,13 +569,13 @@ static void l2cap_conn_start(struct l2cap_conn *conn) l2cap_send_cmd(conn, chan->ident, L2CAP_CONN_RSP, sizeof(rsp), &rsp); - if (l2cap_pi(sk)->conf_state & L2CAP_CONF_REQ_SENT || + if (chan->conf_state & L2CAP_CONF_REQ_SENT || rsp.result != L2CAP_CR_SUCCESS) { bh_unlock_sock(sk); continue; } - l2cap_pi(sk)->conf_state |= L2CAP_CONF_REQ_SENT; + chan->conf_state |= L2CAP_CONF_REQ_SENT; l2cap_send_cmd(conn, l2cap_get_ident(conn), L2CAP_CONF_REQ, l2cap_build_conf_req(chan, buf), buf); chan->num_conf_req++; @@ -1382,10 +1382,11 @@ int l2cap_sar_segment_sdu(struct l2cap_chan *chan, struct msghdr *msg, size_t le static void l2cap_chan_ready(struct sock *sk) { struct sock *parent = bt_sk(sk)->parent; + struct l2cap_chan *chan = l2cap_pi(sk)->chan; BT_DBG("sk %p, parent %p", sk, parent); - l2cap_pi(sk)->conf_state = 0; + chan->conf_state = 0; l2cap_sock_clear_timer(sk); if (!parent) { @@ -1619,7 +1620,7 @@ static int l2cap_build_conf_req(struct l2cap_chan *chan, void *data) switch (pi->mode) { case L2CAP_MODE_STREAMING: case L2CAP_MODE_ERTM: - if (pi->conf_state & L2CAP_CONF_STATE2_DEVICE) + if (chan->conf_state & L2CAP_CONF_STATE2_DEVICE) break; /* fall through */ @@ -1666,7 +1667,7 @@ done: break; if (pi->fcs == L2CAP_FCS_NONE || - pi->conf_state & L2CAP_CONF_NO_FCS_RECV) { + chan->conf_state & L2CAP_CONF_NO_FCS_RECV) { pi->fcs = L2CAP_FCS_NONE; l2cap_add_conf_opt(&ptr, L2CAP_CONF_FCS, 1, pi->fcs); } @@ -1689,7 +1690,7 @@ done: break; if (pi->fcs == L2CAP_FCS_NONE || - pi->conf_state & L2CAP_CONF_NO_FCS_RECV) { + chan->conf_state & L2CAP_CONF_NO_FCS_RECV) { pi->fcs = L2CAP_FCS_NONE; l2cap_add_conf_opt(&ptr, L2CAP_CONF_FCS, 1, pi->fcs); } @@ -1742,7 +1743,7 @@ static int l2cap_parse_conf_req(struct l2cap_chan *chan, void *data) case L2CAP_CONF_FCS: if (val == L2CAP_FCS_NONE) - pi->conf_state |= L2CAP_CONF_NO_FCS_RECV; + chan->conf_state |= L2CAP_CONF_NO_FCS_RECV; break; @@ -1762,7 +1763,7 @@ static int l2cap_parse_conf_req(struct l2cap_chan *chan, void *data) switch (pi->mode) { case L2CAP_MODE_STREAMING: case L2CAP_MODE_ERTM: - if (!(pi->conf_state & L2CAP_CONF_STATE2_DEVICE)) { + if (!(chan->conf_state & L2CAP_CONF_STATE2_DEVICE)) { pi->mode = l2cap_select_mode(rfc.mode, pi->conn->feat_mask); break; @@ -1795,14 +1796,14 @@ done: result = L2CAP_CONF_UNACCEPT; else { pi->omtu = mtu; - pi->conf_state |= L2CAP_CONF_MTU_DONE; + chan->conf_state |= L2CAP_CONF_MTU_DONE; } l2cap_add_conf_opt(&ptr, L2CAP_CONF_MTU, 2, pi->omtu); switch (rfc.mode) { case L2CAP_MODE_BASIC: pi->fcs = L2CAP_FCS_NONE; - pi->conf_state |= L2CAP_CONF_MODE_DONE; + chan->conf_state |= L2CAP_CONF_MODE_DONE; break; case L2CAP_MODE_ERTM: @@ -1819,7 +1820,7 @@ done: rfc.monitor_timeout = le16_to_cpu(L2CAP_DEFAULT_MONITOR_TO); - pi->conf_state |= L2CAP_CONF_MODE_DONE; + chan->conf_state |= L2CAP_CONF_MODE_DONE; l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC, sizeof(rfc), (unsigned long) &rfc); @@ -1832,7 +1833,7 @@ done: chan->remote_mps = le16_to_cpu(rfc.max_pdu_size); - pi->conf_state |= L2CAP_CONF_MODE_DONE; + chan->conf_state |= L2CAP_CONF_MODE_DONE; l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC, sizeof(rfc), (unsigned long) &rfc); @@ -1847,7 +1848,7 @@ done: } if (result == L2CAP_CONF_SUCCESS) - pi->conf_state |= L2CAP_CONF_OUTPUT_DONE; + chan->conf_state |= L2CAP_CONF_OUTPUT_DONE; } rsp->scid = cpu_to_le16(pi->dcid); rsp->result = cpu_to_le16(result); @@ -1856,8 +1857,9 @@ done: return ptr - data; } -static int l2cap_parse_conf_rsp(struct sock *sk, void *rsp, int len, void *data, u16 *result) +static int l2cap_parse_conf_rsp(struct l2cap_chan *chan, void *rsp, int len, void *data, u16 *result) { + struct sock *sk = chan->sk; struct l2cap_pinfo *pi = l2cap_pi(sk); struct l2cap_conf_req *req = data; void *ptr = req->data; @@ -1890,7 +1892,7 @@ static int l2cap_parse_conf_rsp(struct sock *sk, void *rsp, int len, void *data, if (olen == sizeof(rfc)) memcpy(&rfc, (void *)val, olen); - if ((pi->conf_state & L2CAP_CONF_STATE2_DEVICE) && + if ((chan->conf_state & L2CAP_CONF_STATE2_DEVICE) && rfc.mode != pi->mode) return -ECONNREFUSED; @@ -1955,10 +1957,10 @@ void __l2cap_connect_rsp_defer(struct sock *sk) l2cap_send_cmd(conn, chan->ident, L2CAP_CONN_RSP, sizeof(rsp), &rsp); - if (l2cap_pi(sk)->conf_state & L2CAP_CONF_REQ_SENT) + if (chan->conf_state & L2CAP_CONF_REQ_SENT) return; - l2cap_pi(sk)->conf_state |= L2CAP_CONF_REQ_SENT; + chan->conf_state |= L2CAP_CONF_REQ_SENT; l2cap_send_cmd(conn, l2cap_get_ident(conn), L2CAP_CONF_REQ, l2cap_build_conf_req(chan, buf), buf); chan->num_conf_req++; @@ -2146,10 +2148,10 @@ sendresp: L2CAP_INFO_REQ, sizeof(info), &info); } - if (chan && !(l2cap_pi(sk)->conf_state & L2CAP_CONF_REQ_SENT) && + if (chan && !(chan->conf_state & L2CAP_CONF_REQ_SENT) && result == L2CAP_CR_SUCCESS) { u8 buf[128]; - l2cap_pi(sk)->conf_state |= L2CAP_CONF_REQ_SENT; + chan->conf_state |= L2CAP_CONF_REQ_SENT; l2cap_send_cmd(conn, l2cap_get_ident(conn), L2CAP_CONF_REQ, l2cap_build_conf_req(chan, buf), buf); chan->num_conf_req++; @@ -2190,12 +2192,12 @@ static inline int l2cap_connect_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hd sk->sk_state = BT_CONFIG; chan->ident = 0; l2cap_pi(sk)->dcid = dcid; - l2cap_pi(sk)->conf_state &= ~L2CAP_CONF_CONNECT_PEND; + chan->conf_state &= ~L2CAP_CONF_CONNECT_PEND; - if (l2cap_pi(sk)->conf_state & L2CAP_CONF_REQ_SENT) + if (chan->conf_state & L2CAP_CONF_REQ_SENT) break; - l2cap_pi(sk)->conf_state |= L2CAP_CONF_REQ_SENT; + chan->conf_state |= L2CAP_CONF_REQ_SENT; l2cap_send_cmd(conn, l2cap_get_ident(conn), L2CAP_CONF_REQ, l2cap_build_conf_req(chan, req), req); @@ -2203,7 +2205,7 @@ static inline int l2cap_connect_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hd break; case L2CAP_CR_PEND: - l2cap_pi(sk)->conf_state |= L2CAP_CONF_CONNECT_PEND; + chan->conf_state |= L2CAP_CONF_CONNECT_PEND; break; default: @@ -2230,7 +2232,7 @@ static inline void set_default_fcs(struct l2cap_pinfo *pi) */ if (pi->mode != L2CAP_MODE_ERTM && pi->mode != L2CAP_MODE_STREAMING) pi->fcs = L2CAP_FCS_NONE; - else if (!(pi->conf_state & L2CAP_CONF_NO_FCS_RECV)) + else if (!(pi->chan->conf_state & L2CAP_CONF_NO_FCS_RECV)) pi->fcs = L2CAP_FCS_CRC16; } @@ -2297,10 +2299,10 @@ static inline int l2cap_config_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr /* Reset config buffer. */ chan->conf_len = 0; - if (!(l2cap_pi(sk)->conf_state & L2CAP_CONF_OUTPUT_DONE)) + if (!(chan->conf_state & L2CAP_CONF_OUTPUT_DONE)) goto unlock; - if (l2cap_pi(sk)->conf_state & L2CAP_CONF_INPUT_DONE) { + if (chan->conf_state & L2CAP_CONF_INPUT_DONE) { set_default_fcs(l2cap_pi(sk)); sk->sk_state = BT_CONNECTED; @@ -2315,9 +2317,9 @@ static inline int l2cap_config_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr goto unlock; } - if (!(l2cap_pi(sk)->conf_state & L2CAP_CONF_REQ_SENT)) { + if (!(chan->conf_state & L2CAP_CONF_REQ_SENT)) { u8 buf[64]; - l2cap_pi(sk)->conf_state |= L2CAP_CONF_REQ_SENT; + chan->conf_state |= L2CAP_CONF_REQ_SENT; l2cap_send_cmd(conn, l2cap_get_ident(conn), L2CAP_CONF_REQ, l2cap_build_conf_req(chan, buf), buf); chan->num_conf_req++; @@ -2365,8 +2367,8 @@ static inline int l2cap_config_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hdr /* throw out any old stored conf requests */ result = L2CAP_CONF_SUCCESS; - len = l2cap_parse_conf_rsp(sk, rsp->data, - len, req, &result); + len = l2cap_parse_conf_rsp(chan, rsp->data, len, + req, &result); if (len < 0) { l2cap_send_disconn_req(conn, chan, ECONNRESET); goto done; @@ -2390,9 +2392,9 @@ static inline int l2cap_config_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hdr if (flags & 0x01) goto done; - l2cap_pi(sk)->conf_state |= L2CAP_CONF_INPUT_DONE; + chan->conf_state |= L2CAP_CONF_INPUT_DONE; - if (l2cap_pi(sk)->conf_state & L2CAP_CONF_OUTPUT_DONE) { + if (chan->conf_state & L2CAP_CONF_OUTPUT_DONE) { set_default_fcs(l2cap_pi(sk)); sk->sk_state = BT_CONNECTED; @@ -3899,7 +3901,7 @@ static int l2cap_security_cfm(struct hci_conn *hcon, u8 status, u8 encrypt) bh_lock_sock(sk); - if (l2cap_pi(sk)->conf_state & L2CAP_CONF_CONNECT_PEND) { + if (chan->conf_state & L2CAP_CONF_CONNECT_PEND) { bh_unlock_sock(sk); continue; } @@ -3918,7 +3920,7 @@ static int l2cap_security_cfm(struct hci_conn *hcon, u8 status, u8 encrypt) req.psm = l2cap_pi(sk)->psm; chan->ident = l2cap_get_ident(conn); - l2cap_pi(sk)->conf_state |= L2CAP_CONF_CONNECT_PEND; + chan->conf_state |= L2CAP_CONF_CONNECT_PEND; l2cap_send_cmd(conn, chan->ident, L2CAP_CONN_REQ, sizeof(req), &req); diff --git a/net/bluetooth/l2cap_sock.c b/net/bluetooth/l2cap_sock.c index e372457..a29782a 100644 --- a/net/bluetooth/l2cap_sock.c +++ b/net/bluetooth/l2cap_sock.c @@ -528,6 +528,7 @@ static int l2cap_sock_getsockopt(struct socket *sock, int level, int optname, ch static int l2cap_sock_setsockopt_old(struct socket *sock, int optname, char __user *optval, unsigned int optlen) { struct sock *sk = sock->sk; + struct l2cap_chan *chan = l2cap_pi(sk)->chan; struct l2cap_options opts; int len, err = 0; u32 opt; @@ -565,7 +566,7 @@ static int l2cap_sock_setsockopt_old(struct socket *sock, int optname, char __us l2cap_pi(sk)->mode = opts.mode; switch (l2cap_pi(sk)->mode) { case L2CAP_MODE_BASIC: - l2cap_pi(sk)->conf_state &= ~L2CAP_CONF_STATE2_DEVICE; + chan->conf_state &= ~L2CAP_CONF_STATE2_DEVICE; break; case L2CAP_MODE_ERTM: case L2CAP_MODE_STREAMING: @@ -979,16 +980,19 @@ static void l2cap_sock_destruct(struct sock *sk) void l2cap_sock_init(struct sock *sk, struct sock *parent) { struct l2cap_pinfo *pi = l2cap_pi(sk); + struct l2cap_chan *chan = pi->chan; BT_DBG("sk %p", sk); if (parent) { + struct l2cap_chan *pchan = l2cap_pi(parent)->chan; + sk->sk_type = parent->sk_type; bt_sk(sk)->defer_setup = bt_sk(parent)->defer_setup; pi->imtu = l2cap_pi(parent)->imtu; pi->omtu = l2cap_pi(parent)->omtu; - pi->conf_state = l2cap_pi(parent)->conf_state; + chan->conf_state = pchan->conf_state; pi->mode = l2cap_pi(parent)->mode; pi->fcs = l2cap_pi(parent)->fcs; pi->max_tx = l2cap_pi(parent)->max_tx; @@ -1002,7 +1006,7 @@ void l2cap_sock_init(struct sock *sk, struct sock *parent) pi->omtu = 0; if (!disable_ertm && sk->sk_type == SOCK_STREAM) { pi->mode = L2CAP_MODE_ERTM; - pi->conf_state |= L2CAP_CONF_STATE2_DEVICE; + chan->conf_state |= L2CAP_CONF_STATE2_DEVICE; } else { pi->mode = L2CAP_MODE_BASIC; } -- cgit v0.10.2 From 77a74c7e0861e6ebac7effe233fd7e83f1ad9ecc Mon Sep 17 00:00:00 2001 From: "Gustavo F. Padovan" Date: Tue, 12 Apr 2011 18:17:14 -0300 Subject: Bluetooth: Rename l2cap_do_connect() to l2cap_chan_connect() l2cap_chan_connect() is a much better name and reflects what this functions is doing (or will do once socket dependence is removed from the core). Signed-off-by: Gustavo F. Padovan diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h index b3bb3d4..f709350 100644 --- a/include/net/bluetooth/l2cap.h +++ b/include/net/bluetooth/l2cap.h @@ -466,6 +466,6 @@ struct sock *l2cap_sock_alloc(struct net *net, struct socket *sock, void l2cap_send_disconn_req(struct l2cap_conn *conn, struct l2cap_chan *chan, int err); struct l2cap_chan *l2cap_chan_alloc(struct sock *sk); void l2cap_chan_del(struct l2cap_chan *chan, int err); -int l2cap_do_connect(struct l2cap_chan *chan); +int l2cap_chan_connect(struct l2cap_chan *chan); #endif /* __L2CAP_H */ diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index 190b049..29742d8 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -847,7 +847,7 @@ static struct sock *l2cap_get_sock_by_psm(int state, __le16 psm, bdaddr_t *src) return node ? sk : sk1; } -int l2cap_do_connect(struct l2cap_chan *chan) +int l2cap_chan_connect(struct l2cap_chan *chan) { struct sock *sk = chan->sk; bdaddr_t *src = &bt_sk(sk)->src; diff --git a/net/bluetooth/l2cap_sock.c b/net/bluetooth/l2cap_sock.c index a29782a..50437c6 100644 --- a/net/bluetooth/l2cap_sock.c +++ b/net/bluetooth/l2cap_sock.c @@ -229,7 +229,7 @@ static int l2cap_sock_connect(struct socket *sock, struct sockaddr *addr, int al l2cap_pi(sk)->psm = la.l2_psm; l2cap_pi(sk)->dcid = la.l2_cid; - err = l2cap_do_connect(l2cap_pi(sk)->chan); + err = l2cap_chan_connect(l2cap_pi(sk)->chan); if (err) goto done; -- cgit v0.10.2 From 4343478f3a4806394136d8141b2e451aa5443f03 Mon Sep 17 00:00:00 2001 From: "Gustavo F. Padovan" Date: Tue, 12 Apr 2011 18:31:57 -0300 Subject: Bluetooth: Move some more elements to struct l2cap_chan In this commit sec_level, force_reliable, role_switch and flushable. Signed-off-by: Gustavo F. Padovan diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h index f709350..684deee 100644 --- a/include/net/bluetooth/l2cap.h +++ b/include/net/bluetooth/l2cap.h @@ -284,6 +284,12 @@ struct srej_list { struct l2cap_chan { struct sock *sk; + + __u8 sec_level; + __u8 role_switch; + __u8 force_reliable; + __u8 flushable; + __u8 ident; __u8 conf_req[64]; @@ -371,10 +377,6 @@ struct l2cap_pinfo { __u8 mode; __u8 fcs; - __u8 sec_level; - __u8 role_switch; - __u8 force_reliable; - __u8 flushable; __u8 tx_win; __u8 max_tx; @@ -452,7 +454,7 @@ struct sk_buff *l2cap_create_connless_pdu(struct sock *sk, struct msghdr *msg, s struct sk_buff *l2cap_create_basic_pdu(struct sock *sk, struct msghdr *msg, size_t len); struct sk_buff *l2cap_create_iframe_pdu(struct sock *sk, struct msghdr *msg, size_t len, u16 control, u16 sdulen); int l2cap_sar_segment_sdu(struct l2cap_chan *chan, struct msghdr *msg, size_t len); -void l2cap_do_send(struct sock *sk, struct sk_buff *skb); +void l2cap_do_send(struct l2cap_chan *chan, struct sk_buff *skb); void l2cap_streaming_send(struct l2cap_chan *chan); int l2cap_ertm_send(struct l2cap_chan *chan); diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index 29742d8..0fc6bbe 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -262,10 +262,12 @@ free: kfree(chan); } -static inline u8 l2cap_get_auth_type(struct sock *sk) +static inline u8 l2cap_get_auth_type(struct l2cap_chan *chan) { + struct sock *sk = chan->sk; + if (sk->sk_type == SOCK_RAW) { - switch (l2cap_pi(sk)->sec_level) { + switch (chan->sec_level) { case BT_SECURITY_HIGH: return HCI_AT_DEDICATED_BONDING_MITM; case BT_SECURITY_MEDIUM: @@ -274,15 +276,15 @@ static inline u8 l2cap_get_auth_type(struct sock *sk) return HCI_AT_NO_BONDING; } } else if (l2cap_pi(sk)->psm == cpu_to_le16(0x0001)) { - if (l2cap_pi(sk)->sec_level == BT_SECURITY_LOW) - l2cap_pi(sk)->sec_level = BT_SECURITY_SDP; + if (chan->sec_level == BT_SECURITY_LOW) + chan->sec_level = BT_SECURITY_SDP; - if (l2cap_pi(sk)->sec_level == BT_SECURITY_HIGH) + if (chan->sec_level == BT_SECURITY_HIGH) return HCI_AT_NO_BONDING_MITM; else return HCI_AT_NO_BONDING; } else { - switch (l2cap_pi(sk)->sec_level) { + switch (chan->sec_level) { case BT_SECURITY_HIGH: return HCI_AT_GENERAL_BONDING_MITM; case BT_SECURITY_MEDIUM: @@ -294,15 +296,14 @@ static inline u8 l2cap_get_auth_type(struct sock *sk) } /* Service level security */ -static inline int l2cap_check_security(struct sock *sk) +static inline int l2cap_check_security(struct l2cap_chan *chan) { - struct l2cap_conn *conn = l2cap_pi(sk)->conn; + struct l2cap_conn *conn = l2cap_pi(chan->sk)->conn; __u8 auth_type; - auth_type = l2cap_get_auth_type(sk); + auth_type = l2cap_get_auth_type(chan); - return hci_conn_security(conn->hcon, l2cap_pi(sk)->sec_level, - auth_type); + return hci_conn_security(conn->hcon, chan->sec_level, auth_type); } u8 l2cap_get_ident(struct l2cap_conn *conn) @@ -425,7 +426,8 @@ static void l2cap_do_start(struct l2cap_chan *chan) if (!(conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_DONE)) return; - if (l2cap_check_security(sk) && __l2cap_no_conn_pending(chan)) { + if (l2cap_check_security(chan) && + __l2cap_no_conn_pending(chan)) { struct l2cap_conn_req req; req.scid = cpu_to_le16(l2cap_pi(sk)->scid); req.psm = l2cap_pi(sk)->psm; @@ -515,7 +517,7 @@ static void l2cap_conn_start(struct l2cap_conn *conn) if (sk->sk_state == BT_CONNECT) { struct l2cap_conn_req req; - if (!l2cap_check_security(sk) || + if (!l2cap_check_security(chan) || !__l2cap_no_conn_pending(chan)) { bh_unlock_sock(sk); continue; @@ -549,7 +551,7 @@ static void l2cap_conn_start(struct l2cap_conn *conn) rsp.scid = cpu_to_le16(l2cap_pi(sk)->dcid); rsp.dcid = cpu_to_le16(l2cap_pi(sk)->scid); - if (l2cap_check_security(sk)) { + if (l2cap_check_security(chan)) { if (bt_sk(sk)->defer_setup) { struct sock *parent = bt_sk(sk)->parent; rsp.result = cpu_to_le16(L2CAP_CR_PEND); @@ -722,7 +724,7 @@ static void l2cap_conn_unreliable(struct l2cap_conn *conn, int err) list_for_each_entry(chan, &conn->chan_l, list) { struct sock *sk = chan->sk; - if (l2cap_pi(sk)->force_reliable) + if (chan->force_reliable) sk->sk_err = err; } @@ -867,14 +869,14 @@ int l2cap_chan_connect(struct l2cap_chan *chan) hci_dev_lock_bh(hdev); - auth_type = l2cap_get_auth_type(sk); + auth_type = l2cap_get_auth_type(chan); if (l2cap_pi(sk)->dcid == L2CAP_CID_LE_DATA) hcon = hci_connect(hdev, LE_LINK, dst, - l2cap_pi(sk)->sec_level, auth_type); + chan->sec_level, auth_type); else hcon = hci_connect(hdev, ACL_LINK, dst, - l2cap_pi(sk)->sec_level, auth_type); + chan->sec_level, auth_type); if (IS_ERR(hcon)) { err = PTR_ERR(hcon); @@ -900,7 +902,7 @@ int l2cap_chan_connect(struct l2cap_chan *chan) if (sk->sk_type != SOCK_SEQPACKET && sk->sk_type != SOCK_STREAM) { l2cap_sock_clear_timer(sk); - if (l2cap_check_security(sk)) + if (l2cap_check_security(chan)) sk->sk_state = BT_CONNECTED; } else l2cap_do_start(chan); @@ -1002,15 +1004,15 @@ static void l2cap_drop_acked_frames(struct l2cap_chan *chan) del_timer(&chan->retrans_timer); } -void l2cap_do_send(struct sock *sk, struct sk_buff *skb) +void l2cap_do_send(struct l2cap_chan *chan, struct sk_buff *skb) { - struct l2cap_pinfo *pi = l2cap_pi(sk); - struct hci_conn *hcon = pi->conn->hcon; + struct sock *sk = chan->sk; + struct hci_conn *hcon = l2cap_pi(sk)->conn->hcon; u16 flags; - BT_DBG("sk %p, skb %p len %d", sk, skb, skb->len); + BT_DBG("chan %p, skb %p len %d", chan, skb, skb->len); - if (!pi->flushable && lmp_no_flush_capable(hcon->hdev)) + if (!chan->flushable && lmp_no_flush_capable(hcon->hdev)) flags = ACL_START_NO_FLUSH; else flags = ACL_START; @@ -1035,7 +1037,7 @@ void l2cap_streaming_send(struct l2cap_chan *chan) put_unaligned_le16(fcs, skb->data + skb->len - 2); } - l2cap_do_send(sk, skb); + l2cap_do_send(chan, skb); chan->next_tx_seq = (chan->next_tx_seq + 1) % 64; } @@ -1087,7 +1089,7 @@ static void l2cap_retransmit_one_frame(struct l2cap_chan *chan, u8 tx_seq) put_unaligned_le16(fcs, tx_skb->data + tx_skb->len - 2); } - l2cap_do_send(sk, tx_skb); + l2cap_do_send(chan, tx_skb); } int l2cap_ertm_send(struct l2cap_chan *chan) @@ -1130,7 +1132,7 @@ int l2cap_ertm_send(struct l2cap_chan *chan) put_unaligned_le16(fcs, skb->data + tx_skb->len - 2); } - l2cap_do_send(sk, tx_skb); + l2cap_do_send(chan, tx_skb); __mod_retrans_timer(); @@ -2100,7 +2102,7 @@ static inline int l2cap_connect_req(struct l2cap_conn *conn, struct l2cap_cmd_hd chan->ident = cmd->ident; if (conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_DONE) { - if (l2cap_check_security(sk)) { + if (l2cap_check_security(chan)) { if (bt_sk(sk)->defer_setup) { sk->sk_state = BT_CONNECT2; result = L2CAP_CR_PEND; @@ -3805,17 +3807,19 @@ static int l2cap_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type) /* Find listening sockets and check their link_mode */ read_lock(&l2cap_sk_list.lock); sk_for_each(sk, node, &l2cap_sk_list.head) { + struct l2cap_chan *chan = l2cap_pi(sk)->chan; + if (sk->sk_state != BT_LISTEN) continue; if (!bacmp(&bt_sk(sk)->src, &hdev->bdaddr)) { lm1 |= HCI_LM_ACCEPT; - if (l2cap_pi(sk)->role_switch) + if (chan->role_switch) lm1 |= HCI_LM_MASTER; exact++; } else if (!bacmp(&bt_sk(sk)->src, BDADDR_ANY)) { lm2 |= HCI_LM_ACCEPT; - if (l2cap_pi(sk)->role_switch) + if (chan->role_switch) lm2 |= HCI_LM_MASTER; } } @@ -3867,19 +3871,21 @@ static int l2cap_disconn_cfm(struct hci_conn *hcon, u8 reason) return 0; } -static inline void l2cap_check_encryption(struct sock *sk, u8 encrypt) +static inline void l2cap_check_encryption(struct l2cap_chan *chan, u8 encrypt) { + struct sock *sk = chan->sk; + if (sk->sk_type != SOCK_SEQPACKET && sk->sk_type != SOCK_STREAM) return; if (encrypt == 0x00) { - if (l2cap_pi(sk)->sec_level == BT_SECURITY_MEDIUM) { + if (chan->sec_level == BT_SECURITY_MEDIUM) { l2cap_sock_clear_timer(sk); l2cap_sock_set_timer(sk, HZ * 5); - } else if (l2cap_pi(sk)->sec_level == BT_SECURITY_HIGH) + } else if (chan->sec_level == BT_SECURITY_HIGH) __l2cap_sock_close(sk, ECONNREFUSED); } else { - if (l2cap_pi(sk)->sec_level == BT_SECURITY_MEDIUM) + if (chan->sec_level == BT_SECURITY_MEDIUM) l2cap_sock_clear_timer(sk); } } @@ -3908,7 +3914,7 @@ static int l2cap_security_cfm(struct hci_conn *hcon, u8 status, u8 encrypt) if (!status && (sk->sk_state == BT_CONNECTED || sk->sk_state == BT_CONFIG)) { - l2cap_check_encryption(sk, encrypt); + l2cap_check_encryption(chan, encrypt); bh_unlock_sock(sk); continue; } @@ -4083,7 +4089,7 @@ static int l2cap_debugfs_show(struct seq_file *f, void *p) batostr(&bt_sk(sk)->dst), sk->sk_state, __le16_to_cpu(pi->psm), pi->scid, pi->dcid, - pi->imtu, pi->omtu, pi->sec_level, + pi->imtu, pi->omtu, pi->chan->sec_level, pi->mode); } diff --git a/net/bluetooth/l2cap_sock.c b/net/bluetooth/l2cap_sock.c index 50437c6..6129556 100644 --- a/net/bluetooth/l2cap_sock.c +++ b/net/bluetooth/l2cap_sock.c @@ -51,7 +51,7 @@ static void l2cap_sock_timeout(unsigned long arg) if (sk->sk_state == BT_CONNECTED || sk->sk_state == BT_CONFIG) reason = ECONNREFUSED; else if (sk->sk_state == BT_CONNECT && - l2cap_pi(sk)->sec_level != BT_SECURITY_SDP) + l2cap_pi(sk)->chan->sec_level != BT_SECURITY_SDP) reason = ECONNREFUSED; else reason = ETIMEDOUT; @@ -91,6 +91,7 @@ found: static int l2cap_sock_bind(struct socket *sock, struct sockaddr *addr, int alen) { struct sock *sk = sock->sk; + struct l2cap_chan *chan = l2cap_pi(sk)->chan; struct sockaddr_l2 la; int len, err = 0; @@ -142,7 +143,7 @@ static int l2cap_sock_bind(struct socket *sock, struct sockaddr *addr, int alen) if (__le16_to_cpu(la.l2_psm) == 0x0001 || __le16_to_cpu(la.l2_psm) == 0x0003) - l2cap_pi(sk)->sec_level = BT_SECURITY_SDP; + chan->sec_level = BT_SECURITY_SDP; } if (la.l2_cid) @@ -382,6 +383,7 @@ static int l2cap_sock_getname(struct socket *sock, struct sockaddr *addr, int *l static int l2cap_sock_getsockopt_old(struct socket *sock, int optname, char __user *optval, int __user *optlen) { struct sock *sk = sock->sk; + struct l2cap_chan *chan = l2cap_pi(sk)->chan; struct l2cap_options opts; struct l2cap_conninfo cinfo; int len, err = 0; @@ -412,7 +414,7 @@ static int l2cap_sock_getsockopt_old(struct socket *sock, int optname, char __us break; case L2CAP_LM: - switch (l2cap_pi(sk)->sec_level) { + switch (chan->sec_level) { case BT_SECURITY_LOW: opt = L2CAP_LM_AUTH; break; @@ -428,10 +430,10 @@ static int l2cap_sock_getsockopt_old(struct socket *sock, int optname, char __us break; } - if (l2cap_pi(sk)->role_switch) + if (chan->role_switch) opt |= L2CAP_LM_MASTER; - if (l2cap_pi(sk)->force_reliable) + if (chan->force_reliable) opt |= L2CAP_LM_RELIABLE; if (put_user(opt, (u32 __user *) optval)) @@ -467,6 +469,7 @@ static int l2cap_sock_getsockopt_old(struct socket *sock, int optname, char __us static int l2cap_sock_getsockopt(struct socket *sock, int level, int optname, char __user *optval, int __user *optlen) { struct sock *sk = sock->sk; + struct l2cap_chan *chan = l2cap_pi(sk)->chan; struct bt_security sec; int len, err = 0; @@ -491,7 +494,7 @@ static int l2cap_sock_getsockopt(struct socket *sock, int level, int optname, ch break; } - sec.level = l2cap_pi(sk)->sec_level; + sec.level = chan->sec_level; len = min_t(unsigned int, len, sizeof(sec)); if (copy_to_user(optval, (char *) &sec, len)) @@ -511,7 +514,7 @@ static int l2cap_sock_getsockopt(struct socket *sock, int level, int optname, ch break; case BT_FLUSHABLE: - if (put_user(l2cap_pi(sk)->flushable, (u32 __user *) optval)) + if (put_user(chan->flushable, (u32 __user *) optval)) err = -EFAULT; break; @@ -592,14 +595,14 @@ static int l2cap_sock_setsockopt_old(struct socket *sock, int optname, char __us } if (opt & L2CAP_LM_AUTH) - l2cap_pi(sk)->sec_level = BT_SECURITY_LOW; + chan->sec_level = BT_SECURITY_LOW; if (opt & L2CAP_LM_ENCRYPT) - l2cap_pi(sk)->sec_level = BT_SECURITY_MEDIUM; + chan->sec_level = BT_SECURITY_MEDIUM; if (opt & L2CAP_LM_SECURE) - l2cap_pi(sk)->sec_level = BT_SECURITY_HIGH; + chan->sec_level = BT_SECURITY_HIGH; - l2cap_pi(sk)->role_switch = (opt & L2CAP_LM_MASTER); - l2cap_pi(sk)->force_reliable = (opt & L2CAP_LM_RELIABLE); + chan->role_switch = (opt & L2CAP_LM_MASTER); + chan->force_reliable = (opt & L2CAP_LM_RELIABLE); break; default: @@ -614,6 +617,7 @@ static int l2cap_sock_setsockopt_old(struct socket *sock, int optname, char __us static int l2cap_sock_setsockopt(struct socket *sock, int level, int optname, char __user *optval, unsigned int optlen) { struct sock *sk = sock->sk; + struct l2cap_chan *chan = l2cap_pi(sk)->chan; struct bt_security sec; int len, err = 0; u32 opt; @@ -650,7 +654,7 @@ static int l2cap_sock_setsockopt(struct socket *sock, int level, int optname, ch break; } - l2cap_pi(sk)->sec_level = sec.level; + chan->sec_level = sec.level; break; case BT_DEFER_SETUP: @@ -688,7 +692,7 @@ static int l2cap_sock_setsockopt(struct socket *sock, int level, int optname, ch } } - l2cap_pi(sk)->flushable = opt; + chan->flushable = opt; break; default: @@ -730,7 +734,7 @@ static int l2cap_sock_sendmsg(struct kiocb *iocb, struct socket *sock, struct ms if (IS_ERR(skb)) { err = PTR_ERR(skb); } else { - l2cap_do_send(sk, skb); + l2cap_do_send(pi->chan, skb); err = len; } goto done; @@ -751,7 +755,7 @@ static int l2cap_sock_sendmsg(struct kiocb *iocb, struct socket *sock, struct ms goto done; } - l2cap_do_send(sk, skb); + l2cap_do_send(pi->chan, skb); err = len; break; @@ -997,10 +1001,10 @@ void l2cap_sock_init(struct sock *sk, struct sock *parent) pi->fcs = l2cap_pi(parent)->fcs; pi->max_tx = l2cap_pi(parent)->max_tx; pi->tx_win = l2cap_pi(parent)->tx_win; - pi->sec_level = l2cap_pi(parent)->sec_level; - pi->role_switch = l2cap_pi(parent)->role_switch; - pi->force_reliable = l2cap_pi(parent)->force_reliable; - pi->flushable = l2cap_pi(parent)->flushable; + chan->sec_level = pchan->sec_level; + chan->role_switch = pchan->role_switch; + chan->force_reliable = pchan->force_reliable; + chan->flushable = pchan->flushable; } else { pi->imtu = L2CAP_DEFAULT_MTU; pi->omtu = 0; @@ -1013,10 +1017,10 @@ void l2cap_sock_init(struct sock *sk, struct sock *parent) pi->max_tx = L2CAP_DEFAULT_MAX_TX; pi->fcs = L2CAP_FCS_CRC16; pi->tx_win = L2CAP_DEFAULT_TX_WINDOW; - pi->sec_level = BT_SECURITY_LOW; - pi->role_switch = 0; - pi->force_reliable = 0; - pi->flushable = BT_FLUSHABLE_OFF; + chan->sec_level = BT_SECURITY_LOW; + chan->role_switch = 0; + chan->force_reliable = 0; + chan->flushable = BT_FLUSHABLE_OFF; } /* Default config options */ -- cgit v0.10.2 From 47d1ec6161da2c7b9dbc56a5200fa26b17d5fdc1 Mon Sep 17 00:00:00 2001 From: "Gustavo F. Padovan" Date: Wed, 13 Apr 2011 15:57:03 -0300 Subject: Bluetooth: Move more vars to struct l2cap_chan In this commit all ERTM and Streaming Mode specific vars. Signed-off-by: Gustavo F. Padovan diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h index 684deee..02db902 100644 --- a/include/net/bluetooth/l2cap.h +++ b/include/net/bluetooth/l2cap.h @@ -297,6 +297,14 @@ struct l2cap_chan { __u8 num_conf_req; __u8 num_conf_rsp; + __u8 fcs; + + __u8 tx_win; + __u8 max_tx; + __u16 retrans_timeout; + __u16 monitor_timeout; + __u16 mps; + __u8 conf_state; __u16 conn_state; @@ -376,14 +384,6 @@ struct l2cap_pinfo { __u16 flush_to; __u8 mode; - __u8 fcs; - - __u8 tx_win; - __u8 max_tx; - __u16 retrans_timeout; - __u16 monitor_timeout; - __u16 mps; - __le16 sport; struct l2cap_conn *conn; @@ -452,7 +452,7 @@ int __l2cap_wait_ack(struct sock *sk); struct sk_buff *l2cap_create_connless_pdu(struct sock *sk, struct msghdr *msg, size_t len); struct sk_buff *l2cap_create_basic_pdu(struct sock *sk, struct msghdr *msg, size_t len); -struct sk_buff *l2cap_create_iframe_pdu(struct sock *sk, struct msghdr *msg, size_t len, u16 control, u16 sdulen); +struct sk_buff *l2cap_create_iframe_pdu(struct l2cap_chan *chan, struct msghdr *msg, size_t len, u16 control, u16 sdulen); int l2cap_sar_segment_sdu(struct l2cap_chan *chan, struct msghdr *msg, size_t len); void l2cap_do_send(struct l2cap_chan *chan, struct sk_buff *skb); void l2cap_streaming_send(struct l2cap_chan *chan); diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index 0fc6bbe..cb3c4ed 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -359,7 +359,7 @@ static inline void l2cap_send_sframe(struct l2cap_chan *chan, u16 control) if (sk->sk_state != BT_CONNECTED) return; - if (pi->fcs == L2CAP_FCS_CRC16) + if (chan->fcs == L2CAP_FCS_CRC16) hlen += 2; BT_DBG("chan %p, control 0x%2.2x", chan, control); @@ -386,7 +386,7 @@ static inline void l2cap_send_sframe(struct l2cap_chan *chan, u16 control) lh->cid = cpu_to_le16(pi->dcid); put_unaligned_le16(control, skb_put(skb, 2)); - if (pi->fcs == L2CAP_FCS_CRC16) { + if (chan->fcs == L2CAP_FCS_CRC16) { u16 fcs = crc16(0, (u8 *)lh, count - 2); put_unaligned_le16(fcs, skb_put(skb, 2)); } @@ -1022,9 +1022,7 @@ void l2cap_do_send(struct l2cap_chan *chan, struct sk_buff *skb) void l2cap_streaming_send(struct l2cap_chan *chan) { - struct sock *sk = chan->sk; struct sk_buff *skb; - struct l2cap_pinfo *pi = l2cap_pi(sk); u16 control, fcs; while ((skb = skb_dequeue(&chan->tx_q))) { @@ -1032,7 +1030,7 @@ void l2cap_streaming_send(struct l2cap_chan *chan) control |= chan->next_tx_seq << L2CAP_CTRL_TXSEQ_SHIFT; put_unaligned_le16(control, skb->data + L2CAP_HDR_SIZE); - if (pi->fcs == L2CAP_FCS_CRC16) { + if (chan->fcs == L2CAP_FCS_CRC16) { fcs = crc16(0, (u8 *)skb->data, skb->len - 2); put_unaligned_le16(fcs, skb->data + skb->len - 2); } @@ -1084,7 +1082,7 @@ static void l2cap_retransmit_one_frame(struct l2cap_chan *chan, u8 tx_seq) put_unaligned_le16(control, tx_skb->data + L2CAP_HDR_SIZE); - if (pi->fcs == L2CAP_FCS_CRC16) { + if (chan->fcs == L2CAP_FCS_CRC16) { fcs = crc16(0, (u8 *)tx_skb->data, tx_skb->len - 2); put_unaligned_le16(fcs, tx_skb->data + tx_skb->len - 2); } @@ -1127,7 +1125,7 @@ int l2cap_ertm_send(struct l2cap_chan *chan) put_unaligned_le16(control, tx_skb->data + L2CAP_HDR_SIZE); - if (pi->fcs == L2CAP_FCS_CRC16) { + if (chan->fcs == L2CAP_FCS_CRC16) { fcs = crc16(0, (u8 *)skb->data, tx_skb->len - 2); put_unaligned_le16(fcs, skb->data + tx_skb->len - 2); } @@ -1290,8 +1288,9 @@ struct sk_buff *l2cap_create_basic_pdu(struct sock *sk, struct msghdr *msg, size return skb; } -struct sk_buff *l2cap_create_iframe_pdu(struct sock *sk, struct msghdr *msg, size_t len, u16 control, u16 sdulen) +struct sk_buff *l2cap_create_iframe_pdu(struct l2cap_chan *chan, struct msghdr *msg, size_t len, u16 control, u16 sdulen) { + struct sock *sk = chan->sk; struct l2cap_conn *conn = l2cap_pi(sk)->conn; struct sk_buff *skb; int err, count, hlen = L2CAP_HDR_SIZE + 2; @@ -1305,7 +1304,7 @@ struct sk_buff *l2cap_create_iframe_pdu(struct sock *sk, struct msghdr *msg, siz if (sdulen) hlen += 2; - if (l2cap_pi(sk)->fcs == L2CAP_FCS_CRC16) + if (chan->fcs == L2CAP_FCS_CRC16) hlen += 2; count = min_t(unsigned int, (conn->mtu - hlen), len); @@ -1328,7 +1327,7 @@ struct sk_buff *l2cap_create_iframe_pdu(struct sock *sk, struct msghdr *msg, siz return ERR_PTR(err); } - if (l2cap_pi(sk)->fcs == L2CAP_FCS_CRC16) + if (chan->fcs == L2CAP_FCS_CRC16) put_unaligned_le16(0, skb_put(skb, 2)); bt_cb(skb)->retries = 0; @@ -1337,7 +1336,6 @@ struct sk_buff *l2cap_create_iframe_pdu(struct sock *sk, struct msghdr *msg, siz int l2cap_sar_segment_sdu(struct l2cap_chan *chan, struct msghdr *msg, size_t len) { - struct sock *sk = chan->sk; struct sk_buff *skb; struct sk_buff_head sar_queue; u16 control; @@ -1345,7 +1343,7 @@ int l2cap_sar_segment_sdu(struct l2cap_chan *chan, struct msghdr *msg, size_t le skb_queue_head_init(&sar_queue); control = L2CAP_SDU_START; - skb = l2cap_create_iframe_pdu(sk, msg, chan->remote_mps, control, len); + skb = l2cap_create_iframe_pdu(chan, msg, chan->remote_mps, control, len); if (IS_ERR(skb)) return PTR_ERR(skb); @@ -1364,7 +1362,7 @@ int l2cap_sar_segment_sdu(struct l2cap_chan *chan, struct msghdr *msg, size_t le buflen = len; } - skb = l2cap_create_iframe_pdu(sk, msg, buflen, control, 0); + skb = l2cap_create_iframe_pdu(chan, msg, buflen, control, 0); if (IS_ERR(skb)) { skb_queue_purge(&sar_queue); return PTR_ERR(skb); @@ -1654,8 +1652,8 @@ done: case L2CAP_MODE_ERTM: rfc.mode = L2CAP_MODE_ERTM; - rfc.txwin_size = pi->tx_win; - rfc.max_transmit = pi->max_tx; + rfc.txwin_size = chan->tx_win; + rfc.max_transmit = chan->max_tx; rfc.retrans_timeout = 0; rfc.monitor_timeout = 0; rfc.max_pdu_size = cpu_to_le16(L2CAP_DEFAULT_MAX_PDU_SIZE); @@ -1668,10 +1666,10 @@ done: if (!(pi->conn->feat_mask & L2CAP_FEAT_FCS)) break; - if (pi->fcs == L2CAP_FCS_NONE || + if (chan->fcs == L2CAP_FCS_NONE || chan->conf_state & L2CAP_CONF_NO_FCS_RECV) { - pi->fcs = L2CAP_FCS_NONE; - l2cap_add_conf_opt(&ptr, L2CAP_CONF_FCS, 1, pi->fcs); + chan->fcs = L2CAP_FCS_NONE; + l2cap_add_conf_opt(&ptr, L2CAP_CONF_FCS, 1, chan->fcs); } break; @@ -1691,10 +1689,10 @@ done: if (!(pi->conn->feat_mask & L2CAP_FEAT_FCS)) break; - if (pi->fcs == L2CAP_FCS_NONE || + if (chan->fcs == L2CAP_FCS_NONE || chan->conf_state & L2CAP_CONF_NO_FCS_RECV) { - pi->fcs = L2CAP_FCS_NONE; - l2cap_add_conf_opt(&ptr, L2CAP_CONF_FCS, 1, pi->fcs); + chan->fcs = L2CAP_FCS_NONE; + l2cap_add_conf_opt(&ptr, L2CAP_CONF_FCS, 1, chan->fcs); } break; } @@ -1804,7 +1802,7 @@ done: switch (rfc.mode) { case L2CAP_MODE_BASIC: - pi->fcs = L2CAP_FCS_NONE; + chan->fcs = L2CAP_FCS_NONE; chan->conf_state |= L2CAP_CONF_MODE_DONE; break; @@ -1898,7 +1896,7 @@ static int l2cap_parse_conf_rsp(struct l2cap_chan *chan, void *rsp, int len, voi rfc.mode != pi->mode) return -ECONNREFUSED; - pi->fcs = 0; + chan->fcs = 0; l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC, sizeof(rfc), (unsigned long) &rfc); @@ -1914,12 +1912,12 @@ static int l2cap_parse_conf_rsp(struct l2cap_chan *chan, void *rsp, int len, voi if (*result == L2CAP_CONF_SUCCESS) { switch (rfc.mode) { case L2CAP_MODE_ERTM: - pi->retrans_timeout = le16_to_cpu(rfc.retrans_timeout); - pi->monitor_timeout = le16_to_cpu(rfc.monitor_timeout); - pi->mps = le16_to_cpu(rfc.max_pdu_size); + chan->retrans_timeout = le16_to_cpu(rfc.retrans_timeout); + chan->monitor_timeout = le16_to_cpu(rfc.monitor_timeout); + chan->mps = le16_to_cpu(rfc.max_pdu_size); break; case L2CAP_MODE_STREAMING: - pi->mps = le16_to_cpu(rfc.max_pdu_size); + chan->mps = le16_to_cpu(rfc.max_pdu_size); } } @@ -1968,14 +1966,14 @@ void __l2cap_connect_rsp_defer(struct sock *sk) chan->num_conf_req++; } -static void l2cap_conf_rfc_get(struct sock *sk, void *rsp, int len) +static void l2cap_conf_rfc_get(struct l2cap_chan *chan, void *rsp, int len) { - struct l2cap_pinfo *pi = l2cap_pi(sk); + struct l2cap_pinfo *pi = l2cap_pi(chan->sk); int type, olen; unsigned long val; struct l2cap_conf_rfc rfc; - BT_DBG("sk %p, rsp %p, len %d", sk, rsp, len); + BT_DBG("chan %p, rsp %p, len %d", chan, rsp, len); if ((pi->mode != L2CAP_MODE_ERTM) && (pi->mode != L2CAP_MODE_STREAMING)) return; @@ -1994,12 +1992,12 @@ static void l2cap_conf_rfc_get(struct sock *sk, void *rsp, int len) done: switch (rfc.mode) { case L2CAP_MODE_ERTM: - pi->retrans_timeout = le16_to_cpu(rfc.retrans_timeout); - pi->monitor_timeout = le16_to_cpu(rfc.monitor_timeout); - pi->mps = le16_to_cpu(rfc.max_pdu_size); + chan->retrans_timeout = le16_to_cpu(rfc.retrans_timeout); + chan->monitor_timeout = le16_to_cpu(rfc.monitor_timeout); + chan->mps = le16_to_cpu(rfc.max_pdu_size); break; case L2CAP_MODE_STREAMING: - pi->mps = le16_to_cpu(rfc.max_pdu_size); + chan->mps = le16_to_cpu(rfc.max_pdu_size); } } @@ -2227,15 +2225,17 @@ static inline int l2cap_connect_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hd return 0; } -static inline void set_default_fcs(struct l2cap_pinfo *pi) +static inline void set_default_fcs(struct l2cap_chan *chan) { + struct l2cap_pinfo *pi = l2cap_pi(chan->sk); + /* FCS is enabled only in ERTM or streaming mode, if one or both * sides request it. */ if (pi->mode != L2CAP_MODE_ERTM && pi->mode != L2CAP_MODE_STREAMING) - pi->fcs = L2CAP_FCS_NONE; + chan->fcs = L2CAP_FCS_NONE; else if (!(pi->chan->conf_state & L2CAP_CONF_NO_FCS_RECV)) - pi->fcs = L2CAP_FCS_CRC16; + chan->fcs = L2CAP_FCS_CRC16; } static inline int l2cap_config_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u16 cmd_len, u8 *data) @@ -2305,7 +2305,7 @@ static inline int l2cap_config_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr goto unlock; if (chan->conf_state & L2CAP_CONF_INPUT_DONE) { - set_default_fcs(l2cap_pi(sk)); + set_default_fcs(chan); sk->sk_state = BT_CONNECTED; @@ -2355,7 +2355,7 @@ static inline int l2cap_config_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hdr switch (result) { case L2CAP_CONF_SUCCESS: - l2cap_conf_rfc_get(sk, rsp->data, len); + l2cap_conf_rfc_get(chan, rsp->data, len); break; case L2CAP_CONF_UNACCEPT: @@ -2397,7 +2397,7 @@ static inline int l2cap_config_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hdr chan->conf_state |= L2CAP_CONF_INPUT_DONE; if (chan->conf_state & L2CAP_CONF_OUTPUT_DONE) { - set_default_fcs(l2cap_pi(sk)); + set_default_fcs(chan); sk->sk_state = BT_CONNECTED; chan->next_tx_seq = 0; @@ -2769,12 +2769,12 @@ static inline void l2cap_sig_channel(struct l2cap_conn *conn, kfree_skb(skb); } -static int l2cap_check_fcs(struct l2cap_pinfo *pi, struct sk_buff *skb) +static int l2cap_check_fcs(struct l2cap_chan *chan, struct sk_buff *skb) { u16 our_fcs, rcv_fcs; int hdr_size = L2CAP_HDR_SIZE + 2; - if (pi->fcs == L2CAP_FCS_CRC16) { + if (chan->fcs == L2CAP_FCS_CRC16) { skb_trim(skb, skb->len - 2); rcv_fcs = get_unaligned_le16(skb->data + skb->len); our_fcs = crc16(0, skb->data - hdr_size, skb->len + hdr_size); @@ -3241,7 +3241,7 @@ static inline int l2cap_data_channel_iframe(struct l2cap_chan *chan, u16 rx_cont u8 req_seq = __get_reqseq(rx_control); u8 sar = rx_control >> L2CAP_CTRL_SAR_SHIFT; int tx_seq_offset, expected_tx_seq_offset; - int num_to_ack = (pi->tx_win/6) + 1; + int num_to_ack = (chan->tx_win/6) + 1; int err = 0; BT_DBG("chan %p len %d tx_seq %d rx_control 0x%4.4x", chan, skb->len, @@ -3266,7 +3266,7 @@ static inline int l2cap_data_channel_iframe(struct l2cap_chan *chan, u16 rx_cont tx_seq_offset += 64; /* invalid tx_seq */ - if (tx_seq_offset >= pi->tx_win) { + if (tx_seq_offset >= chan->tx_win) { l2cap_send_disconn_req(pi->conn, chan, ECONNRESET); goto drop; } @@ -3548,16 +3548,16 @@ static int l2cap_ertm_data_rcv(struct sock *sk, struct sk_buff *skb) * Receiver will miss it and start proper recovery * procedures and ask retransmission. */ - if (l2cap_check_fcs(pi, skb)) + if (l2cap_check_fcs(chan, skb)) goto drop; if (__is_sar_start(control) && __is_iframe(control)) len -= 2; - if (pi->fcs == L2CAP_FCS_CRC16) + if (chan->fcs == L2CAP_FCS_CRC16) len -= 2; - if (len > pi->mps) { + if (len > chan->mps) { l2cap_send_disconn_req(pi->conn, chan, ECONNRESET); goto drop; } @@ -3654,16 +3654,16 @@ static inline int l2cap_data_channel(struct l2cap_conn *conn, u16 cid, struct sk skb_pull(skb, 2); len = skb->len; - if (l2cap_check_fcs(pi, skb)) + if (l2cap_check_fcs(chan, skb)) goto drop; if (__is_sar_start(control)) len -= 2; - if (pi->fcs == L2CAP_FCS_CRC16) + if (chan->fcs == L2CAP_FCS_CRC16) len -= 2; - if (len > pi->mps || len < 0 || __is_sframe(control)) + if (len > chan->mps || len < 0 || __is_sframe(control)) goto drop; tx_seq = __get_txseq(control); diff --git a/net/bluetooth/l2cap_sock.c b/net/bluetooth/l2cap_sock.c index 6129556..4ba15b3 100644 --- a/net/bluetooth/l2cap_sock.c +++ b/net/bluetooth/l2cap_sock.c @@ -403,9 +403,9 @@ static int l2cap_sock_getsockopt_old(struct socket *sock, int optname, char __us opts.omtu = l2cap_pi(sk)->omtu; opts.flush_to = l2cap_pi(sk)->flush_to; opts.mode = l2cap_pi(sk)->mode; - opts.fcs = l2cap_pi(sk)->fcs; - opts.max_tx = l2cap_pi(sk)->max_tx; - opts.txwin_size = (__u16)l2cap_pi(sk)->tx_win; + opts.fcs = chan->fcs; + opts.max_tx = chan->max_tx; + opts.txwin_size = (__u16)chan->tx_win; len = min_t(unsigned int, len, sizeof(opts)); if (copy_to_user(optval, (char *) &opts, len)) @@ -551,9 +551,9 @@ static int l2cap_sock_setsockopt_old(struct socket *sock, int optname, char __us opts.omtu = l2cap_pi(sk)->omtu; opts.flush_to = l2cap_pi(sk)->flush_to; opts.mode = l2cap_pi(sk)->mode; - opts.fcs = l2cap_pi(sk)->fcs; - opts.max_tx = l2cap_pi(sk)->max_tx; - opts.txwin_size = (__u16)l2cap_pi(sk)->tx_win; + opts.fcs = chan->fcs; + opts.max_tx = chan->max_tx; + opts.txwin_size = (__u16)chan->tx_win; len = min_t(unsigned int, sizeof(opts), optlen); if (copy_from_user((char *) &opts, optval, len)) { @@ -583,9 +583,9 @@ static int l2cap_sock_setsockopt_old(struct socket *sock, int optname, char __us l2cap_pi(sk)->imtu = opts.imtu; l2cap_pi(sk)->omtu = opts.omtu; - l2cap_pi(sk)->fcs = opts.fcs; - l2cap_pi(sk)->max_tx = opts.max_tx; - l2cap_pi(sk)->tx_win = (__u8)opts.txwin_size; + chan->fcs = opts.fcs; + chan->max_tx = opts.max_tx; + chan->tx_win = (__u8)opts.txwin_size; break; case L2CAP_LM: @@ -764,7 +764,8 @@ static int l2cap_sock_sendmsg(struct kiocb *iocb, struct socket *sock, struct ms /* Entire SDU fits into one PDU */ if (len <= pi->chan->remote_mps) { control = L2CAP_SDU_UNSEGMENTED; - skb = l2cap_create_iframe_pdu(sk, msg, len, control, 0); + skb = l2cap_create_iframe_pdu(pi->chan, msg, len, + control, 0); if (IS_ERR(skb)) { err = PTR_ERR(skb); goto done; @@ -998,9 +999,9 @@ void l2cap_sock_init(struct sock *sk, struct sock *parent) pi->omtu = l2cap_pi(parent)->omtu; chan->conf_state = pchan->conf_state; pi->mode = l2cap_pi(parent)->mode; - pi->fcs = l2cap_pi(parent)->fcs; - pi->max_tx = l2cap_pi(parent)->max_tx; - pi->tx_win = l2cap_pi(parent)->tx_win; + chan->fcs = pchan->fcs; + chan->max_tx = pchan->max_tx; + chan->tx_win = pchan->tx_win; chan->sec_level = pchan->sec_level; chan->role_switch = pchan->role_switch; chan->force_reliable = pchan->force_reliable; @@ -1014,9 +1015,9 @@ void l2cap_sock_init(struct sock *sk, struct sock *parent) } else { pi->mode = L2CAP_MODE_BASIC; } - pi->max_tx = L2CAP_DEFAULT_MAX_TX; - pi->fcs = L2CAP_FCS_CRC16; - pi->tx_win = L2CAP_DEFAULT_TX_WINDOW; + chan->max_tx = L2CAP_DEFAULT_MAX_TX; + chan->fcs = L2CAP_FCS_CRC16; + chan->tx_win = L2CAP_DEFAULT_TX_WINDOW; chan->sec_level = BT_SECURITY_LOW; chan->role_switch = 0; chan->force_reliable = 0; diff --git a/net/bluetooth/rfcomm/core.c b/net/bluetooth/rfcomm/core.c index c997393..4f728a4 100644 --- a/net/bluetooth/rfcomm/core.c +++ b/net/bluetooth/rfcomm/core.c @@ -711,7 +711,7 @@ static struct rfcomm_session *rfcomm_session_create(bdaddr_t *src, sk = sock->sk; lock_sock(sk); l2cap_pi(sk)->imtu = l2cap_mtu; - l2cap_pi(sk)->sec_level = sec_level; + l2cap_pi(sk)->chan->sec_level = sec_level; if (l2cap_ertm) l2cap_pi(sk)->mode = L2CAP_MODE_ERTM; release_sock(sk); -- cgit v0.10.2 From 9fdcdbb0d84922e7ccda2f717a04ea62629f7e18 Mon Sep 17 00:00:00 2001 From: Chris Ball Date: Tue, 29 Mar 2011 00:46:12 -0400 Subject: mmc: sdhci-pci: Fix error case in sdhci_pci_probe_slot() If pci_ioremap_bar() fails during probe, we "goto release;" and free the host, but then we return 0 -- which tells sdhci_pci_probe() that the probe succeeded. Since we think the probe succeeded, when we unload sdhci we'll go to sdhci_pci_remove_slot() and it will try to dereference slot->host, which is now NULL because we freed it in the error path earlier. The patch simply sets ret appropriately, so that sdhci_pci_probe() will detect the failure immediately and bail out. Signed-off-by: Chris Ball Cc: diff --git a/drivers/mmc/host/sdhci-pci.c b/drivers/mmc/host/sdhci-pci.c index a136be7..f8b5f37 100644 --- a/drivers/mmc/host/sdhci-pci.c +++ b/drivers/mmc/host/sdhci-pci.c @@ -957,6 +957,7 @@ static struct sdhci_pci_slot * __devinit sdhci_pci_probe_slot( host->ioaddr = pci_ioremap_bar(pdev, bar); if (!host->ioaddr) { dev_err(&pdev->dev, "failed to remap registers\n"); + ret = -ENOMEM; goto release; } -- cgit v0.10.2 From 9bc21848b1d6cb8389d927196b16c9950b5e21e9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Miros=C5=82aw?= Date: Sat, 9 Apr 2011 08:16:47 +0200 Subject: mmc: core: mmc_add_card(): fix missing break in switch statement MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes a cosmetic bug that affects printk() for SD-combo cards. Reported-by: Prashanth Bhat Signed-off-by: MichaÅ‚ MirosÅ‚aw Signed-off-by: Chris Ball diff --git a/drivers/mmc/core/bus.c b/drivers/mmc/core/bus.c index 63667a8..d6d62fd 100644 --- a/drivers/mmc/core/bus.c +++ b/drivers/mmc/core/bus.c @@ -284,6 +284,7 @@ int mmc_add_card(struct mmc_card *card) type = "SD-combo"; if (mmc_card_blockaddr(card)) type = "SDHC-combo"; + break; default: type = "?"; break; -- cgit v0.10.2 From f69475142136c8ad9b9c717aea2ff907aed9f863 Mon Sep 17 00:00:00 2001 From: Michael Buesch Date: Mon, 11 Apr 2011 17:00:44 -0400 Subject: mmc: omap: Fix possible NULL pointer deref Either OMAP_MMC_STAT_CARD_ERR or OMAP_MMC_STAT_END_OF_CMD might fire if there is no host->cmd pointer. Check for a valid host->cmd pointer before calling mmc_omap_cmd_done(). Signed-off-by: Michael Buesch Acked-by: Tony Lindgren Signed-off-by: Chris Ball diff --git a/drivers/mmc/host/omap.c b/drivers/mmc/host/omap.c index 2e032f0..a6c3290 100644 --- a/drivers/mmc/host/omap.c +++ b/drivers/mmc/host/omap.c @@ -832,7 +832,7 @@ static irqreturn_t mmc_omap_irq(int irq, void *dev_id) return IRQ_HANDLED; } - if (end_command) + if (end_command && host->cmd) mmc_omap_cmd_done(host, host->cmd); if (host->data != NULL) { if (transfer_error) -- cgit v0.10.2 From 26fc8775b51484d8c0a671198639c6d5ae60533e Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Fri, 15 Apr 2011 20:08:19 +0200 Subject: mmc: fix a race between card-detect rescan and clock-gate work instances Currently there is a race in the MMC core between a card-detect rescan work and the clock-gating work, scheduled from a command completion. Fix it by removing the dedicated clock-gating mutex and using the MMC standard locking mechanism instead. Signed-off-by: Guennadi Liakhovetski Cc: Simon Horman Cc: Magnus Damm Acked-by: Linus Walleij Cc: Signed-off-by: Chris Ball diff --git a/drivers/mmc/core/host.c b/drivers/mmc/core/host.c index 461e6a1..2b200c1 100644 --- a/drivers/mmc/core/host.c +++ b/drivers/mmc/core/host.c @@ -94,7 +94,7 @@ static void mmc_host_clk_gate_delayed(struct mmc_host *host) spin_unlock_irqrestore(&host->clk_lock, flags); return; } - mutex_lock(&host->clk_gate_mutex); + mmc_claim_host(host); spin_lock_irqsave(&host->clk_lock, flags); if (!host->clk_requests) { spin_unlock_irqrestore(&host->clk_lock, flags); @@ -104,7 +104,7 @@ static void mmc_host_clk_gate_delayed(struct mmc_host *host) pr_debug("%s: gated MCI clock\n", mmc_hostname(host)); } spin_unlock_irqrestore(&host->clk_lock, flags); - mutex_unlock(&host->clk_gate_mutex); + mmc_release_host(host); } /* @@ -130,7 +130,7 @@ void mmc_host_clk_ungate(struct mmc_host *host) { unsigned long flags; - mutex_lock(&host->clk_gate_mutex); + mmc_claim_host(host); spin_lock_irqsave(&host->clk_lock, flags); if (host->clk_gated) { spin_unlock_irqrestore(&host->clk_lock, flags); @@ -140,7 +140,7 @@ void mmc_host_clk_ungate(struct mmc_host *host) } host->clk_requests++; spin_unlock_irqrestore(&host->clk_lock, flags); - mutex_unlock(&host->clk_gate_mutex); + mmc_release_host(host); } /** @@ -215,7 +215,6 @@ static inline void mmc_host_clk_init(struct mmc_host *host) host->clk_gated = false; INIT_WORK(&host->clk_gate_work, mmc_host_clk_gate_work); spin_lock_init(&host->clk_lock); - mutex_init(&host->clk_gate_mutex); } /** diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h index bcb793e..eb792cb 100644 --- a/include/linux/mmc/host.h +++ b/include/linux/mmc/host.h @@ -183,7 +183,6 @@ struct mmc_host { struct work_struct clk_gate_work; /* delayed clock gate */ unsigned int clk_old; /* old clock value cache */ spinlock_t clk_lock; /* lock for clk fields */ - struct mutex clk_gate_mutex; /* mutex for clock gating */ #endif /* host specific block data */ -- cgit v0.10.2 From c919c2a073c5d2e076e52a56b44281d922721b61 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Thu, 21 Apr 2011 09:09:59 +0200 Subject: mmc: tmio: fix .set_ios(MMC_POWER_UP) handling The aggressive clock gating for TMIO MMC patch has broken switching interface power on, using MFD or platform callbacks. Restore the ios->power_mode == MMC_POWER_UP && ios->clock == 0 case handling. Signed-off-by: Guennadi Liakhovetski Signed-off-by: Chris Ball diff --git a/drivers/mmc/host/tmio_mmc_pio.c b/drivers/mmc/host/tmio_mmc_pio.c index 62d37de..710339a 100644 --- a/drivers/mmc/host/tmio_mmc_pio.c +++ b/drivers/mmc/host/tmio_mmc_pio.c @@ -728,15 +728,15 @@ static void tmio_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) tmio_mmc_set_clock(host, ios->clock); /* Power sequence - OFF -> UP -> ON */ - if (ios->power_mode == MMC_POWER_OFF || !ios->clock) { + if (ios->power_mode == MMC_POWER_UP) { + /* power up SD bus */ + if (host->set_pwr) + host->set_pwr(host->pdev, 1); + } else if (ios->power_mode == MMC_POWER_OFF || !ios->clock) { /* power down SD bus */ if (ios->power_mode == MMC_POWER_OFF && host->set_pwr) host->set_pwr(host->pdev, 0); tmio_mmc_clk_stop(host); - } else if (ios->power_mode == MMC_POWER_UP) { - /* power up SD bus */ - if (host->set_pwr) - host->set_pwr(host->pdev, 1); } else { /* start bus clock */ tmio_mmc_clk_start(host); -- cgit v0.10.2 From b7b4d3426d2b5ecab21578eb20d8e456a1aace8f Mon Sep 17 00:00:00 2001 From: Ben Dooks Date: Wed, 27 Apr 2011 14:24:19 +0100 Subject: mmc: sdhci: Check mrq->cmd in sdhci_tasklet_finish It seems that under certain circumstances that the sdhci_tasklet_finish() call can be entered with mrq->cmd set to NULL, causing the system to crash with a NULL pointer de-reference. Unable to handle kernel NULL pointer dereference at virtual address 00000000 PC is at sdhci_tasklet_finish+0x34/0xe8 LR is at sdhci_tasklet_finish+0x24/0xe8 Seen on S3C6410 system. Signed-off-by: Ben Dooks Signed-off-by: Mark Brown Cc: Signed-off-by: Chris Ball diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c index 9e15f41..fd8f488 100644 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c @@ -1345,7 +1345,7 @@ static void sdhci_tasklet_finish(unsigned long param) * upon error conditions. */ if (!(host->flags & SDHCI_DEVICE_DEAD) && - (mrq->cmd->error || + ((mrq->cmd && mrq->cmd->error) || (mrq->data && (mrq->data->error || (mrq->data->stop && mrq->data->stop->error))) || (host->quirks & SDHCI_QUIRK_RESET_AFTER_REQUEST))) { -- cgit v0.10.2 From 0c9c99a765321104cc5f9c97f949382a9ba4927e Mon Sep 17 00:00:00 2001 From: Chris Ball Date: Wed, 27 Apr 2011 17:35:31 -0400 Subject: mmc: sdhci: Check mrq != NULL in sdhci_tasklet_finish It seems that under certain circumstances the sdhci_tasklet_finish() call can be entered with mrq set to NULL, causing the system to crash with a NULL pointer de-reference. Seen on S3C6410 system. Based on a patch by Dimitris Papastamos. Reported-by: Dimitris Papastamos Cc: Signed-off-by: Chris Ball diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c index fd8f488..5d20661 100644 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c @@ -1334,6 +1334,13 @@ static void sdhci_tasklet_finish(unsigned long param) host = (struct sdhci_host*)param; + /* + * If this tasklet gets rescheduled while running, it will + * be run again afterwards but without any active request. + */ + if (!host->mrq) + return; + spin_lock_irqsave(&host->lock, flags); del_timer(&host->timer); -- cgit v0.10.2 From 0c1bc5c626e9783034264ccca4b262b3acc628f1 Mon Sep 17 00:00:00 2001 From: "Gustavo F. Padovan" Date: Wed, 13 Apr 2011 17:20:49 -0300 Subject: Bluetooth: Move more channel info to struct l2cap_chan In this commit, omtu, imtu, flush_to, mode and sport. It also remove the pi var from l2cap_sock_sendmsg(). Signed-off-by: Gustavo F. Padovan diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h index 02db902..7522835 100644 --- a/include/net/bluetooth/l2cap.h +++ b/include/net/bluetooth/l2cap.h @@ -285,6 +285,13 @@ struct srej_list { struct l2cap_chan { struct sock *sk; + __u16 imtu; + __u16 omtu; + __u16 flush_to; + __u8 mode; + + __le16 sport; + __u8 sec_level; __u8 role_switch; __u8 force_reliable; @@ -379,13 +386,6 @@ struct l2cap_pinfo { __u16 dcid; __u16 scid; - __u16 imtu; - __u16 omtu; - __u16 flush_to; - __u8 mode; - - __le16 sport; - struct l2cap_conn *conn; struct l2cap_chan *chan; }; diff --git a/net/bluetooth/cmtp/core.c b/net/bluetooth/cmtp/core.c index cce99b0..c5b11af 100644 --- a/net/bluetooth/cmtp/core.c +++ b/net/bluetooth/cmtp/core.c @@ -346,7 +346,8 @@ int cmtp_add_connection(struct cmtp_connadd_req *req, struct socket *sock) bacpy(&session->bdaddr, &bt_sk(sock->sk)->dst); - session->mtu = min_t(uint, l2cap_pi(sock->sk)->omtu, l2cap_pi(sock->sk)->imtu); + session->mtu = min_t(uint, l2cap_pi(sock->sk)->chan->omtu, + l2cap_pi(sock->sk)->chan->imtu); BT_DBG("mtu %d", session->mtu); diff --git a/net/bluetooth/hidp/core.c b/net/bluetooth/hidp/core.c index ae6ebc6..c405a95 100644 --- a/net/bluetooth/hidp/core.c +++ b/net/bluetooth/hidp/core.c @@ -979,8 +979,10 @@ int hidp_add_connection(struct hidp_connadd_req *req, struct socket *ctrl_sock, bacpy(&session->bdaddr, &bt_sk(ctrl_sock->sk)->dst); - session->ctrl_mtu = min_t(uint, l2cap_pi(ctrl_sock->sk)->omtu, l2cap_pi(ctrl_sock->sk)->imtu); - session->intr_mtu = min_t(uint, l2cap_pi(intr_sock->sk)->omtu, l2cap_pi(intr_sock->sk)->imtu); + session->ctrl_mtu = min_t(uint, l2cap_pi(ctrl_sock->sk)->chan->omtu, + l2cap_pi(ctrl_sock->sk)->chan->imtu); + session->intr_mtu = min_t(uint, l2cap_pi(intr_sock->sk)->chan->omtu, + l2cap_pi(intr_sock->sk)->chan->imtu); BT_DBG("ctrl mtu %d intr mtu %d", session->ctrl_mtu, session->intr_mtu); diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index cb3c4ed..7b06375 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -176,24 +176,24 @@ static void __l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan) if (sk->sk_type == SOCK_SEQPACKET || sk->sk_type == SOCK_STREAM) { if (conn->hcon->type == LE_LINK) { /* LE connection */ - l2cap_pi(sk)->omtu = L2CAP_LE_DEFAULT_MTU; + chan->omtu = L2CAP_LE_DEFAULT_MTU; l2cap_pi(sk)->scid = L2CAP_CID_LE_DATA; l2cap_pi(sk)->dcid = L2CAP_CID_LE_DATA; } else { /* Alloc CID for connection-oriented socket */ l2cap_pi(sk)->scid = l2cap_alloc_cid(conn); - l2cap_pi(sk)->omtu = L2CAP_DEFAULT_MTU; + chan->omtu = L2CAP_DEFAULT_MTU; } } else if (sk->sk_type == SOCK_DGRAM) { /* Connectionless socket */ l2cap_pi(sk)->scid = L2CAP_CID_CONN_LESS; l2cap_pi(sk)->dcid = L2CAP_CID_CONN_LESS; - l2cap_pi(sk)->omtu = L2CAP_DEFAULT_MTU; + chan->omtu = L2CAP_DEFAULT_MTU; } else { /* Raw socket can send/recv signalling messages only */ l2cap_pi(sk)->scid = L2CAP_CID_SIGNALING; l2cap_pi(sk)->dcid = L2CAP_CID_SIGNALING; - l2cap_pi(sk)->omtu = L2CAP_DEFAULT_MTU; + chan->omtu = L2CAP_DEFAULT_MTU; } sock_hold(sk); @@ -242,7 +242,7 @@ void l2cap_chan_del(struct l2cap_chan *chan, int err) skb_queue_purge(&chan->tx_q); - if (l2cap_pi(sk)->mode == L2CAP_MODE_ERTM) { + if (chan->mode == L2CAP_MODE_ERTM) { struct srej_list *l, *tmp; del_timer(&chan->retrans_timer); @@ -479,7 +479,7 @@ void l2cap_send_disconn_req(struct l2cap_conn *conn, struct l2cap_chan *chan, in sk = chan->sk; - if (l2cap_pi(sk)->mode == L2CAP_MODE_ERTM) { + if (chan->mode == L2CAP_MODE_ERTM) { del_timer(&chan->retrans_timer); del_timer(&chan->monitor_timer); del_timer(&chan->ack_timer); @@ -523,7 +523,7 @@ static void l2cap_conn_start(struct l2cap_conn *conn) continue; } - if (!l2cap_mode_supported(l2cap_pi(sk)->mode, + if (!l2cap_mode_supported(chan->mode, conn->feat_mask) && chan->conf_state & L2CAP_CONF_STATE2_DEVICE) { @@ -1609,7 +1609,7 @@ static int l2cap_build_conf_req(struct l2cap_chan *chan, void *data) { struct l2cap_pinfo *pi = l2cap_pi(chan->sk); struct l2cap_conf_req *req = data; - struct l2cap_conf_rfc rfc = { .mode = pi->mode }; + struct l2cap_conf_rfc rfc = { .mode = chan->mode }; void *ptr = req->data; BT_DBG("chan %p", chan); @@ -1617,7 +1617,7 @@ static int l2cap_build_conf_req(struct l2cap_chan *chan, void *data) if (chan->num_conf_req || chan->num_conf_rsp) goto done; - switch (pi->mode) { + switch (chan->mode) { case L2CAP_MODE_STREAMING: case L2CAP_MODE_ERTM: if (chan->conf_state & L2CAP_CONF_STATE2_DEVICE) @@ -1625,15 +1625,15 @@ static int l2cap_build_conf_req(struct l2cap_chan *chan, void *data) /* fall through */ default: - pi->mode = l2cap_select_mode(rfc.mode, pi->conn->feat_mask); + chan->mode = l2cap_select_mode(rfc.mode, pi->conn->feat_mask); break; } done: - if (pi->imtu != L2CAP_DEFAULT_MTU) - l2cap_add_conf_opt(&ptr, L2CAP_CONF_MTU, 2, pi->imtu); + if (chan->imtu != L2CAP_DEFAULT_MTU) + l2cap_add_conf_opt(&ptr, L2CAP_CONF_MTU, 2, chan->imtu); - switch (pi->mode) { + switch (chan->mode) { case L2CAP_MODE_BASIC: if (!(pi->conn->feat_mask & L2CAP_FEAT_ERTM) && !(pi->conn->feat_mask & L2CAP_FEAT_STREAMING)) @@ -1730,7 +1730,7 @@ static int l2cap_parse_conf_req(struct l2cap_chan *chan, void *data) break; case L2CAP_CONF_FLUSH_TO: - pi->flush_to = val; + chan->flush_to = val; break; case L2CAP_CONF_QOS: @@ -1760,25 +1760,25 @@ static int l2cap_parse_conf_req(struct l2cap_chan *chan, void *data) if (chan->num_conf_rsp || chan->num_conf_req > 1) goto done; - switch (pi->mode) { + switch (chan->mode) { case L2CAP_MODE_STREAMING: case L2CAP_MODE_ERTM: if (!(chan->conf_state & L2CAP_CONF_STATE2_DEVICE)) { - pi->mode = l2cap_select_mode(rfc.mode, + chan->mode = l2cap_select_mode(rfc.mode, pi->conn->feat_mask); break; } - if (pi->mode != rfc.mode) + if (chan->mode != rfc.mode) return -ECONNREFUSED; break; } done: - if (pi->mode != rfc.mode) { + if (chan->mode != rfc.mode) { result = L2CAP_CONF_UNACCEPT; - rfc.mode = pi->mode; + rfc.mode = chan->mode; if (chan->num_conf_rsp == 1) return -ECONNREFUSED; @@ -1795,10 +1795,10 @@ done: if (mtu < L2CAP_DEFAULT_MIN_MTU) result = L2CAP_CONF_UNACCEPT; else { - pi->omtu = mtu; + chan->omtu = mtu; chan->conf_state |= L2CAP_CONF_MTU_DONE; } - l2cap_add_conf_opt(&ptr, L2CAP_CONF_MTU, 2, pi->omtu); + l2cap_add_conf_opt(&ptr, L2CAP_CONF_MTU, 2, chan->omtu); switch (rfc.mode) { case L2CAP_MODE_BASIC: @@ -1844,7 +1844,7 @@ done: result = L2CAP_CONF_UNACCEPT; memset(&rfc, 0, sizeof(rfc)); - rfc.mode = pi->mode; + rfc.mode = chan->mode; } if (result == L2CAP_CONF_SUCCESS) @@ -1876,16 +1876,16 @@ static int l2cap_parse_conf_rsp(struct l2cap_chan *chan, void *rsp, int len, voi case L2CAP_CONF_MTU: if (val < L2CAP_DEFAULT_MIN_MTU) { *result = L2CAP_CONF_UNACCEPT; - pi->imtu = L2CAP_DEFAULT_MIN_MTU; + chan->imtu = L2CAP_DEFAULT_MIN_MTU; } else - pi->imtu = val; - l2cap_add_conf_opt(&ptr, L2CAP_CONF_MTU, 2, pi->imtu); + chan->imtu = val; + l2cap_add_conf_opt(&ptr, L2CAP_CONF_MTU, 2, chan->imtu); break; case L2CAP_CONF_FLUSH_TO: - pi->flush_to = val; + chan->flush_to = val; l2cap_add_conf_opt(&ptr, L2CAP_CONF_FLUSH_TO, - 2, pi->flush_to); + 2, chan->flush_to); break; case L2CAP_CONF_RFC: @@ -1893,7 +1893,7 @@ static int l2cap_parse_conf_rsp(struct l2cap_chan *chan, void *rsp, int len, voi memcpy(&rfc, (void *)val, olen); if ((chan->conf_state & L2CAP_CONF_STATE2_DEVICE) && - rfc.mode != pi->mode) + rfc.mode != chan->mode) return -ECONNREFUSED; chan->fcs = 0; @@ -1904,10 +1904,10 @@ static int l2cap_parse_conf_rsp(struct l2cap_chan *chan, void *rsp, int len, voi } } - if (pi->mode == L2CAP_MODE_BASIC && pi->mode != rfc.mode) + if (chan->mode == L2CAP_MODE_BASIC && chan->mode != rfc.mode) return -ECONNREFUSED; - pi->mode = rfc.mode; + chan->mode = rfc.mode; if (*result == L2CAP_CONF_SUCCESS) { switch (rfc.mode) { @@ -1968,14 +1968,13 @@ void __l2cap_connect_rsp_defer(struct sock *sk) static void l2cap_conf_rfc_get(struct l2cap_chan *chan, void *rsp, int len) { - struct l2cap_pinfo *pi = l2cap_pi(chan->sk); int type, olen; unsigned long val; struct l2cap_conf_rfc rfc; BT_DBG("chan %p, rsp %p, len %d", chan, rsp, len); - if ((pi->mode != L2CAP_MODE_ERTM) && (pi->mode != L2CAP_MODE_STREAMING)) + if ((chan->mode != L2CAP_MODE_ERTM) && (chan->mode != L2CAP_MODE_STREAMING)) return; while (len >= L2CAP_CONF_OPT_SIZE) { @@ -2232,7 +2231,7 @@ static inline void set_default_fcs(struct l2cap_chan *chan) /* FCS is enabled only in ERTM or streaming mode, if one or both * sides request it. */ - if (pi->mode != L2CAP_MODE_ERTM && pi->mode != L2CAP_MODE_STREAMING) + if (chan->mode != L2CAP_MODE_ERTM && chan->mode != L2CAP_MODE_STREAMING) chan->fcs = L2CAP_FCS_NONE; else if (!(pi->chan->conf_state & L2CAP_CONF_NO_FCS_RECV)) chan->fcs = L2CAP_FCS_CRC16; @@ -2312,7 +2311,7 @@ static inline int l2cap_config_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr chan->next_tx_seq = 0; chan->expected_tx_seq = 0; skb_queue_head_init(&chan->tx_q); - if (l2cap_pi(sk)->mode == L2CAP_MODE_ERTM) + if (chan->mode == L2CAP_MODE_ERTM) l2cap_ertm_init(chan); l2cap_chan_ready(sk); @@ -2403,7 +2402,7 @@ static inline int l2cap_config_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hdr chan->next_tx_seq = 0; chan->expected_tx_seq = 0; skb_queue_head_init(&chan->tx_q); - if (l2cap_pi(sk)->mode == L2CAP_MODE_ERTM) + if (chan->mode == L2CAP_MODE_ERTM) l2cap_ertm_init(chan); l2cap_chan_ready(sk); @@ -2876,7 +2875,7 @@ static int l2cap_ertm_reassembly_sdu(struct l2cap_chan *chan, struct sk_buff *sk chan->sdu_len = get_unaligned_le16(skb->data); - if (chan->sdu_len > pi->imtu) + if (chan->sdu_len > chan->imtu) goto disconnect; chan->sdu = bt_skb_alloc(chan->sdu_len, GFP_ATOMIC); @@ -2919,7 +2918,7 @@ static int l2cap_ertm_reassembly_sdu(struct l2cap_chan *chan, struct sk_buff *sk if (!(chan->conn_state & L2CAP_CONN_SAR_RETRY)) { chan->partial_sdu_len += skb->len; - if (chan->partial_sdu_len > pi->imtu) + if (chan->partial_sdu_len > chan->imtu) goto drop; if (chan->partial_sdu_len != chan->sdu_len) @@ -3087,7 +3086,6 @@ static int l2cap_push_rx_skb(struct l2cap_chan *chan, struct sk_buff *skb, u16 c static int l2cap_streaming_reassembly_sdu(struct l2cap_chan *chan, struct sk_buff *skb, u16 control) { - struct l2cap_pinfo *pi = l2cap_pi(chan->sk); struct sk_buff *_skb; int err = -EINVAL; @@ -3118,7 +3116,7 @@ static int l2cap_streaming_reassembly_sdu(struct l2cap_chan *chan, struct sk_buf chan->sdu_len = get_unaligned_le16(skb->data); skb_pull(skb, 2); - if (chan->sdu_len > pi->imtu) { + if (chan->sdu_len > chan->imtu) { err = -EMSGSIZE; break; } @@ -3159,7 +3157,7 @@ static int l2cap_streaming_reassembly_sdu(struct l2cap_chan *chan, struct sk_buf chan->conn_state &= ~L2CAP_CONN_SAR_SDU; chan->partial_sdu_len += skb->len; - if (chan->partial_sdu_len > pi->imtu) + if (chan->partial_sdu_len > chan->imtu) goto drop; if (chan->partial_sdu_len == chan->sdu_len) { @@ -3625,14 +3623,14 @@ static inline int l2cap_data_channel(struct l2cap_conn *conn, u16 cid, struct sk if (sk->sk_state != BT_CONNECTED) goto drop; - switch (pi->mode) { + switch (chan->mode) { case L2CAP_MODE_BASIC: /* If socket recv buffers overflows we drop data here * which is *bad* because L2CAP has to be reliable. * But we don't have any other choice. L2CAP doesn't * provide flow control mechanism. */ - if (pi->imtu < skb->len) + if (chan->imtu < skb->len) goto drop; if (!sock_queue_rcv_skb(sk, skb)) @@ -3678,7 +3676,7 @@ static inline int l2cap_data_channel(struct l2cap_conn *conn, u16 cid, struct sk goto done; default: - BT_DBG("chan %p: bad mode 0x%2.2x", chan, pi->mode); + BT_DBG("chan %p: bad mode 0x%2.2x", chan, chan->mode); break; } @@ -3707,7 +3705,7 @@ static inline int l2cap_conless_channel(struct l2cap_conn *conn, __le16 psm, str if (sk->sk_state != BT_BOUND && sk->sk_state != BT_CONNECTED) goto drop; - if (l2cap_pi(sk)->imtu < skb->len) + if (l2cap_pi(sk)->chan->imtu < skb->len) goto drop; if (!sock_queue_rcv_skb(sk, skb)) @@ -3737,7 +3735,7 @@ static inline int l2cap_att_channel(struct l2cap_conn *conn, __le16 cid, struct if (sk->sk_state != BT_BOUND && sk->sk_state != BT_CONNECTED) goto drop; - if (l2cap_pi(sk)->imtu < skb->len) + if (l2cap_pi(sk)->chan->imtu < skb->len) goto drop; if (!sock_queue_rcv_skb(sk, skb)) @@ -4020,10 +4018,10 @@ static int l2cap_recv_acldata(struct hci_conn *hcon, struct sk_buff *skb, u16 fl if (chan && chan->sk) { struct sock *sk = chan->sk; - if (l2cap_pi(sk)->imtu < len - L2CAP_HDR_SIZE) { + if (chan->imtu < len - L2CAP_HDR_SIZE) { BT_ERR("Frame exceeding recv MTU (len %d, " "MTU %d)", len, - l2cap_pi(sk)->imtu); + chan->imtu); bh_unlock_sock(sk); l2cap_conn_unreliable(conn, ECOMM); goto drop; @@ -4083,14 +4081,15 @@ static int l2cap_debugfs_show(struct seq_file *f, void *p) sk_for_each(sk, node, &l2cap_sk_list.head) { struct l2cap_pinfo *pi = l2cap_pi(sk); + struct l2cap_chan *chan = pi->chan; seq_printf(f, "%s %s %d %d 0x%4.4x 0x%4.4x %d %d %d %d\n", batostr(&bt_sk(sk)->src), batostr(&bt_sk(sk)->dst), sk->sk_state, __le16_to_cpu(pi->psm), pi->scid, pi->dcid, - pi->imtu, pi->omtu, pi->chan->sec_level, - pi->mode); + chan->imtu, chan->omtu, chan->sec_level, + chan->mode); } read_unlock_bh(&l2cap_sk_list.lock); diff --git a/net/bluetooth/l2cap_sock.c b/net/bluetooth/l2cap_sock.c index 4ba15b3..eef33b17 100644 --- a/net/bluetooth/l2cap_sock.c +++ b/net/bluetooth/l2cap_sock.c @@ -80,9 +80,13 @@ static struct sock *__l2cap_get_sock_by_addr(__le16 psm, bdaddr_t *src) { struct sock *sk; struct hlist_node *node; - sk_for_each(sk, node, &l2cap_sk_list.head) - if (l2cap_pi(sk)->sport == psm && !bacmp(&bt_sk(sk)->src, src)) + sk_for_each(sk, node, &l2cap_sk_list.head) { + struct l2cap_chan *chan = l2cap_pi(sk)->chan; + + if (chan->sport == psm && !bacmp(&bt_sk(sk)->src, src)) goto found; + } + sk = NULL; found: return sk; @@ -138,7 +142,7 @@ static int l2cap_sock_bind(struct socket *sock, struct sockaddr *addr, int alen) /* Save source address */ bacpy(&bt_sk(sk)->src, &la.l2_bdaddr); l2cap_pi(sk)->psm = la.l2_psm; - l2cap_pi(sk)->sport = la.l2_psm; + chan->sport = la.l2_psm; sk->sk_state = BT_BOUND; if (__le16_to_cpu(la.l2_psm) == 0x0001 || @@ -159,6 +163,7 @@ done: static int l2cap_sock_connect(struct socket *sock, struct sockaddr *addr, int alen, int flags) { struct sock *sk = sock->sk; + struct l2cap_chan *chan = l2cap_pi(sk)->chan; struct sockaddr_l2 la; int len, err = 0; @@ -183,7 +188,7 @@ static int l2cap_sock_connect(struct socket *sock, struct sockaddr *addr, int al goto done; } - switch (l2cap_pi(sk)->mode) { + switch (chan->mode) { case L2CAP_MODE_BASIC: break; case L2CAP_MODE_ERTM: @@ -245,6 +250,7 @@ done: static int l2cap_sock_listen(struct socket *sock, int backlog) { struct sock *sk = sock->sk; + struct l2cap_chan *chan = l2cap_pi(sk)->chan; int err = 0; BT_DBG("sk %p backlog %d", sk, backlog); @@ -257,7 +263,7 @@ static int l2cap_sock_listen(struct socket *sock, int backlog) goto done; } - switch (l2cap_pi(sk)->mode) { + switch (chan->mode) { case L2CAP_MODE_BASIC: break; case L2CAP_MODE_ERTM: @@ -281,7 +287,7 @@ static int l2cap_sock_listen(struct socket *sock, int backlog) for (psm = 0x1001; psm < 0x1100; psm += 2) if (!__l2cap_get_sock_by_addr(cpu_to_le16(psm), src)) { l2cap_pi(sk)->psm = cpu_to_le16(psm); - l2cap_pi(sk)->sport = cpu_to_le16(psm); + chan->sport = cpu_to_le16(psm); err = 0; break; } @@ -361,6 +367,7 @@ static int l2cap_sock_getname(struct socket *sock, struct sockaddr *addr, int *l { struct sockaddr_l2 *la = (struct sockaddr_l2 *) addr; struct sock *sk = sock->sk; + struct l2cap_chan *chan = l2cap_pi(sk)->chan; BT_DBG("sock %p, sk %p", sock, sk); @@ -372,7 +379,7 @@ static int l2cap_sock_getname(struct socket *sock, struct sockaddr *addr, int *l bacpy(&la->l2_bdaddr, &bt_sk(sk)->dst); la->l2_cid = cpu_to_le16(l2cap_pi(sk)->dcid); } else { - la->l2_psm = l2cap_pi(sk)->sport; + la->l2_psm = chan->sport; bacpy(&la->l2_bdaddr, &bt_sk(sk)->src); la->l2_cid = cpu_to_le16(l2cap_pi(sk)->scid); } @@ -399,10 +406,10 @@ static int l2cap_sock_getsockopt_old(struct socket *sock, int optname, char __us switch (optname) { case L2CAP_OPTIONS: memset(&opts, 0, sizeof(opts)); - opts.imtu = l2cap_pi(sk)->imtu; - opts.omtu = l2cap_pi(sk)->omtu; - opts.flush_to = l2cap_pi(sk)->flush_to; - opts.mode = l2cap_pi(sk)->mode; + opts.imtu = chan->imtu; + opts.omtu = chan->omtu; + opts.flush_to = chan->flush_to; + opts.mode = chan->mode; opts.fcs = chan->fcs; opts.max_tx = chan->max_tx; opts.txwin_size = (__u16)chan->tx_win; @@ -547,10 +554,10 @@ static int l2cap_sock_setsockopt_old(struct socket *sock, int optname, char __us break; } - opts.imtu = l2cap_pi(sk)->imtu; - opts.omtu = l2cap_pi(sk)->omtu; - opts.flush_to = l2cap_pi(sk)->flush_to; - opts.mode = l2cap_pi(sk)->mode; + opts.imtu = chan->imtu; + opts.omtu = chan->omtu; + opts.flush_to = chan->flush_to; + opts.mode = chan->mode; opts.fcs = chan->fcs; opts.max_tx = chan->max_tx; opts.txwin_size = (__u16)chan->tx_win; @@ -566,8 +573,8 @@ static int l2cap_sock_setsockopt_old(struct socket *sock, int optname, char __us break; } - l2cap_pi(sk)->mode = opts.mode; - switch (l2cap_pi(sk)->mode) { + chan->mode = opts.mode; + switch (chan->mode) { case L2CAP_MODE_BASIC: chan->conf_state &= ~L2CAP_CONF_STATE2_DEVICE; break; @@ -581,8 +588,8 @@ static int l2cap_sock_setsockopt_old(struct socket *sock, int optname, char __us break; } - l2cap_pi(sk)->imtu = opts.imtu; - l2cap_pi(sk)->omtu = opts.omtu; + chan->imtu = opts.imtu; + chan->omtu = opts.omtu; chan->fcs = opts.fcs; chan->max_tx = opts.max_tx; chan->tx_win = (__u8)opts.txwin_size; @@ -707,7 +714,7 @@ static int l2cap_sock_setsockopt(struct socket *sock, int level, int optname, ch static int l2cap_sock_sendmsg(struct kiocb *iocb, struct socket *sock, struct msghdr *msg, size_t len) { struct sock *sk = sock->sk; - struct l2cap_pinfo *pi = l2cap_pi(sk); + struct l2cap_chan *chan = l2cap_pi(sk)->chan; struct sk_buff *skb; u16 control; int err; @@ -734,16 +741,16 @@ static int l2cap_sock_sendmsg(struct kiocb *iocb, struct socket *sock, struct ms if (IS_ERR(skb)) { err = PTR_ERR(skb); } else { - l2cap_do_send(pi->chan, skb); + l2cap_do_send(chan, skb); err = len; } goto done; } - switch (pi->mode) { + switch (chan->mode) { case L2CAP_MODE_BASIC: /* Check outgoing MTU */ - if (len > pi->omtu) { + if (len > chan->omtu) { err = -EMSGSIZE; goto done; } @@ -755,52 +762,52 @@ static int l2cap_sock_sendmsg(struct kiocb *iocb, struct socket *sock, struct ms goto done; } - l2cap_do_send(pi->chan, skb); + l2cap_do_send(chan, skb); err = len; break; case L2CAP_MODE_ERTM: case L2CAP_MODE_STREAMING: /* Entire SDU fits into one PDU */ - if (len <= pi->chan->remote_mps) { + if (len <= chan->remote_mps) { control = L2CAP_SDU_UNSEGMENTED; - skb = l2cap_create_iframe_pdu(pi->chan, msg, len, - control, 0); + skb = l2cap_create_iframe_pdu(chan, msg, len, control, + 0); if (IS_ERR(skb)) { err = PTR_ERR(skb); goto done; } - __skb_queue_tail(&pi->chan->tx_q, skb); + __skb_queue_tail(&chan->tx_q, skb); - if (pi->chan->tx_send_head == NULL) - pi->chan->tx_send_head = skb; + if (chan->tx_send_head == NULL) + chan->tx_send_head = skb; } else { /* Segment SDU into multiples PDUs */ - err = l2cap_sar_segment_sdu(pi->chan, msg, len); + err = l2cap_sar_segment_sdu(chan, msg, len); if (err < 0) goto done; } - if (pi->mode == L2CAP_MODE_STREAMING) { - l2cap_streaming_send(pi->chan); + if (chan->mode == L2CAP_MODE_STREAMING) { + l2cap_streaming_send(chan); err = len; break; } - if ((pi->chan->conn_state & L2CAP_CONN_REMOTE_BUSY) && - (pi->chan->conn_state & L2CAP_CONN_WAIT_F)) { + if ((chan->conn_state & L2CAP_CONN_REMOTE_BUSY) && + (chan->conn_state & L2CAP_CONN_WAIT_F)) { err = len; break; } - err = l2cap_ertm_send(pi->chan); + err = l2cap_ertm_send(chan); if (err >= 0) err = len; break; default: - BT_DBG("bad state %1.1x", pi->mode); + BT_DBG("bad state %1.1x", chan->mode); err = -EBADFD; } @@ -929,6 +936,7 @@ void __l2cap_sock_close(struct sock *sk, int reason) static int l2cap_sock_shutdown(struct socket *sock, int how) { struct sock *sk = sock->sk; + struct l2cap_chan *chan = l2cap_pi(sk)->chan; int err = 0; BT_DBG("sock %p, sk %p", sock, sk); @@ -938,7 +946,7 @@ static int l2cap_sock_shutdown(struct socket *sock, int how) lock_sock(sk); if (!sk->sk_shutdown) { - if (l2cap_pi(sk)->mode == L2CAP_MODE_ERTM) + if (chan->mode == L2CAP_MODE_ERTM) err = __l2cap_wait_ack(sk); sk->sk_shutdown = SHUTDOWN_MASK; @@ -995,10 +1003,10 @@ void l2cap_sock_init(struct sock *sk, struct sock *parent) sk->sk_type = parent->sk_type; bt_sk(sk)->defer_setup = bt_sk(parent)->defer_setup; - pi->imtu = l2cap_pi(parent)->imtu; - pi->omtu = l2cap_pi(parent)->omtu; + chan->imtu = pchan->imtu; + chan->omtu = pchan->omtu; chan->conf_state = pchan->conf_state; - pi->mode = l2cap_pi(parent)->mode; + chan->mode = pchan->mode; chan->fcs = pchan->fcs; chan->max_tx = pchan->max_tx; chan->tx_win = pchan->tx_win; @@ -1007,13 +1015,13 @@ void l2cap_sock_init(struct sock *sk, struct sock *parent) chan->force_reliable = pchan->force_reliable; chan->flushable = pchan->flushable; } else { - pi->imtu = L2CAP_DEFAULT_MTU; - pi->omtu = 0; + chan->imtu = L2CAP_DEFAULT_MTU; + chan->omtu = 0; if (!disable_ertm && sk->sk_type == SOCK_STREAM) { - pi->mode = L2CAP_MODE_ERTM; + chan->mode = L2CAP_MODE_ERTM; chan->conf_state |= L2CAP_CONF_STATE2_DEVICE; } else { - pi->mode = L2CAP_MODE_BASIC; + chan->mode = L2CAP_MODE_BASIC; } chan->max_tx = L2CAP_DEFAULT_MAX_TX; chan->fcs = L2CAP_FCS_CRC16; @@ -1025,7 +1033,7 @@ void l2cap_sock_init(struct sock *sk, struct sock *parent) } /* Default config options */ - pi->flush_to = L2CAP_DEFAULT_FLUSH_TO; + chan->flush_to = L2CAP_DEFAULT_FLUSH_TO; } static struct proto l2cap_proto = { diff --git a/net/bluetooth/rfcomm/core.c b/net/bluetooth/rfcomm/core.c index 4f728a4..fdd8f5a 100644 --- a/net/bluetooth/rfcomm/core.c +++ b/net/bluetooth/rfcomm/core.c @@ -710,10 +710,10 @@ static struct rfcomm_session *rfcomm_session_create(bdaddr_t *src, /* Set L2CAP options */ sk = sock->sk; lock_sock(sk); - l2cap_pi(sk)->imtu = l2cap_mtu; + l2cap_pi(sk)->chan->imtu = l2cap_mtu; l2cap_pi(sk)->chan->sec_level = sec_level; if (l2cap_ertm) - l2cap_pi(sk)->mode = L2CAP_MODE_ERTM; + l2cap_pi(sk)->chan->mode = L2CAP_MODE_ERTM; release_sock(sk); s = rfcomm_session_add(sock, BT_BOUND); @@ -1890,7 +1890,8 @@ static inline void rfcomm_accept_connection(struct rfcomm_session *s) /* We should adjust MTU on incoming sessions. * L2CAP MTU minus UIH header and FCS. */ - s->mtu = min(l2cap_pi(nsock->sk)->omtu, l2cap_pi(nsock->sk)->imtu) - 5; + s->mtu = min(l2cap_pi(nsock->sk)->chan->omtu, + l2cap_pi(nsock->sk)->chan->imtu) - 5; rfcomm_schedule(); } else @@ -1909,7 +1910,7 @@ static inline void rfcomm_check_connection(struct rfcomm_session *s) /* We can adjust MTU on outgoing sessions. * L2CAP MTU minus UIH header and FCS. */ - s->mtu = min(l2cap_pi(sk)->omtu, l2cap_pi(sk)->imtu) - 5; + s->mtu = min(l2cap_pi(sk)->chan->omtu, l2cap_pi(sk)->chan->imtu) - 5; rfcomm_send_sabm(s, 0); break; @@ -1992,7 +1993,7 @@ static int rfcomm_add_listener(bdaddr_t *ba) /* Set L2CAP options */ sk = sock->sk; lock_sock(sk); - l2cap_pi(sk)->imtu = l2cap_mtu; + l2cap_pi(sk)->chan->imtu = l2cap_mtu; release_sock(sk); /* Start listening on the socket */ -- cgit v0.10.2 From fe4128e0aabc3c748786c00da21e6eff9d3aeddb Mon Sep 17 00:00:00 2001 From: "Gustavo F. Padovan" Date: Wed, 13 Apr 2011 19:50:45 -0300 Subject: Bluetooth: Move more vars to struct l2cap_chan In this commit, psm, scid and dcid. Signed-off-by: Gustavo F. Padovan diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h index 7522835..fd199cd 100644 --- a/include/net/bluetooth/l2cap.h +++ b/include/net/bluetooth/l2cap.h @@ -284,6 +284,9 @@ struct srej_list { struct l2cap_chan { struct sock *sk; + __le16 psm; + __u16 dcid; + __u16 scid; __u16 imtu; __u16 omtu; @@ -382,9 +385,6 @@ struct l2cap_conn { struct l2cap_pinfo { struct bt_sock bt; - __le16 psm; - __u16 dcid; - __u16 scid; struct l2cap_conn *conn; struct l2cap_chan *chan; @@ -450,8 +450,8 @@ void l2cap_send_cmd(struct l2cap_conn *conn, u8 ident, u8 code, u16 len, void *d void __l2cap_connect_rsp_defer(struct sock *sk); int __l2cap_wait_ack(struct sock *sk); -struct sk_buff *l2cap_create_connless_pdu(struct sock *sk, struct msghdr *msg, size_t len); -struct sk_buff *l2cap_create_basic_pdu(struct sock *sk, struct msghdr *msg, size_t len); +struct sk_buff *l2cap_create_connless_pdu(struct l2cap_chan *chan, struct msghdr *msg, size_t len); +struct sk_buff *l2cap_create_basic_pdu(struct l2cap_chan *chan, struct msghdr *msg, size_t len); struct sk_buff *l2cap_create_iframe_pdu(struct l2cap_chan *chan, struct msghdr *msg, size_t len, u16 control, u16 sdulen); int l2cap_sar_segment_sdu(struct l2cap_chan *chan, struct msghdr *msg, size_t len); void l2cap_do_send(struct l2cap_chan *chan, struct sk_buff *skb); diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index 7b06375..dd726bd 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -80,8 +80,7 @@ static struct l2cap_chan *__l2cap_get_chan_by_dcid(struct l2cap_conn *conn, u16 struct l2cap_chan *c; list_for_each_entry(c, &conn->chan_l, list) { - struct sock *s = c->sk; - if (l2cap_pi(s)->dcid == cid) + if (c->dcid == cid) return c; } return NULL; @@ -93,8 +92,7 @@ static struct l2cap_chan *__l2cap_get_chan_by_scid(struct l2cap_conn *conn, u16 struct l2cap_chan *c; list_for_each_entry(c, &conn->chan_l, list) { - struct sock *s = c->sk; - if (l2cap_pi(s)->scid == cid) + if (c->scid == cid) return c; } return NULL; @@ -167,7 +165,7 @@ static void __l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan) struct sock *sk = chan->sk; BT_DBG("conn %p, psm 0x%2.2x, dcid 0x%4.4x", conn, - l2cap_pi(sk)->psm, l2cap_pi(sk)->dcid); + chan->psm, chan->dcid); conn->disc_reason = 0x13; @@ -177,22 +175,22 @@ static void __l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan) if (conn->hcon->type == LE_LINK) { /* LE connection */ chan->omtu = L2CAP_LE_DEFAULT_MTU; - l2cap_pi(sk)->scid = L2CAP_CID_LE_DATA; - l2cap_pi(sk)->dcid = L2CAP_CID_LE_DATA; + chan->scid = L2CAP_CID_LE_DATA; + chan->dcid = L2CAP_CID_LE_DATA; } else { /* Alloc CID for connection-oriented socket */ - l2cap_pi(sk)->scid = l2cap_alloc_cid(conn); + chan->scid = l2cap_alloc_cid(conn); chan->omtu = L2CAP_DEFAULT_MTU; } } else if (sk->sk_type == SOCK_DGRAM) { /* Connectionless socket */ - l2cap_pi(sk)->scid = L2CAP_CID_CONN_LESS; - l2cap_pi(sk)->dcid = L2CAP_CID_CONN_LESS; + chan->scid = L2CAP_CID_CONN_LESS; + chan->dcid = L2CAP_CID_CONN_LESS; chan->omtu = L2CAP_DEFAULT_MTU; } else { /* Raw socket can send/recv signalling messages only */ - l2cap_pi(sk)->scid = L2CAP_CID_SIGNALING; - l2cap_pi(sk)->dcid = L2CAP_CID_SIGNALING; + chan->scid = L2CAP_CID_SIGNALING; + chan->dcid = L2CAP_CID_SIGNALING; chan->omtu = L2CAP_DEFAULT_MTU; } @@ -275,7 +273,7 @@ static inline u8 l2cap_get_auth_type(struct l2cap_chan *chan) default: return HCI_AT_NO_BONDING; } - } else if (l2cap_pi(sk)->psm == cpu_to_le16(0x0001)) { + } else if (chan->psm == cpu_to_le16(0x0001)) { if (chan->sec_level == BT_SECURITY_LOW) chan->sec_level = BT_SECURITY_SDP; @@ -383,7 +381,7 @@ static inline void l2cap_send_sframe(struct l2cap_chan *chan, u16 control) lh = (struct l2cap_hdr *) skb_put(skb, L2CAP_HDR_SIZE); lh->len = cpu_to_le16(hlen - L2CAP_HDR_SIZE); - lh->cid = cpu_to_le16(pi->dcid); + lh->cid = cpu_to_le16(chan->dcid); put_unaligned_le16(control, skb_put(skb, 2)); if (chan->fcs == L2CAP_FCS_CRC16) { @@ -429,8 +427,8 @@ static void l2cap_do_start(struct l2cap_chan *chan) if (l2cap_check_security(chan) && __l2cap_no_conn_pending(chan)) { struct l2cap_conn_req req; - req.scid = cpu_to_le16(l2cap_pi(sk)->scid); - req.psm = l2cap_pi(sk)->psm; + req.scid = cpu_to_le16(chan->scid); + req.psm = chan->psm; chan->ident = l2cap_get_ident(conn); chan->conf_state |= L2CAP_CONF_CONNECT_PEND; @@ -485,8 +483,8 @@ void l2cap_send_disconn_req(struct l2cap_conn *conn, struct l2cap_chan *chan, in del_timer(&chan->ack_timer); } - req.dcid = cpu_to_le16(l2cap_pi(sk)->dcid); - req.scid = cpu_to_le16(l2cap_pi(sk)->scid); + req.dcid = cpu_to_le16(chan->dcid); + req.scid = cpu_to_le16(chan->scid); l2cap_send_cmd(conn, l2cap_get_ident(conn), L2CAP_DISCONN_REQ, sizeof(req), &req); @@ -536,8 +534,8 @@ static void l2cap_conn_start(struct l2cap_conn *conn) continue; } - req.scid = cpu_to_le16(l2cap_pi(sk)->scid); - req.psm = l2cap_pi(sk)->psm; + req.scid = cpu_to_le16(chan->scid); + req.psm = chan->psm; chan->ident = l2cap_get_ident(conn); chan->conf_state |= L2CAP_CONF_CONNECT_PEND; @@ -548,8 +546,8 @@ static void l2cap_conn_start(struct l2cap_conn *conn) } else if (sk->sk_state == BT_CONNECT2) { struct l2cap_conn_rsp rsp; char buf[128]; - rsp.scid = cpu_to_le16(l2cap_pi(sk)->dcid); - rsp.dcid = cpu_to_le16(l2cap_pi(sk)->scid); + rsp.scid = cpu_to_le16(chan->dcid); + rsp.dcid = cpu_to_le16(chan->scid); if (l2cap_check_security(chan)) { if (bt_sk(sk)->defer_setup) { @@ -600,10 +598,12 @@ static struct sock *l2cap_get_sock_by_scid(int state, __le16 cid, bdaddr_t *src) read_lock(&l2cap_sk_list.lock); sk_for_each(sk, node, &l2cap_sk_list.head) { + struct l2cap_chan *chan = l2cap_pi(sk)->chan; + if (state && sk->sk_state != state) continue; - if (l2cap_pi(sk)->scid == cid) { + if (chan->scid == cid) { /* Exact match. */ if (!bacmp(&bt_sk(sk)->src, src)) break; @@ -830,10 +830,12 @@ static struct sock *l2cap_get_sock_by_psm(int state, __le16 psm, bdaddr_t *src) read_lock(&l2cap_sk_list.lock); sk_for_each(sk, node, &l2cap_sk_list.head) { + struct l2cap_chan *chan = l2cap_pi(sk)->chan; + if (state && sk->sk_state != state) continue; - if (l2cap_pi(sk)->psm == psm) { + if (chan->psm == psm) { /* Exact match. */ if (!bacmp(&bt_sk(sk)->src, src)) break; @@ -861,7 +863,7 @@ int l2cap_chan_connect(struct l2cap_chan *chan) int err; BT_DBG("%s -> %s psm 0x%2.2x", batostr(src), batostr(dst), - l2cap_pi(sk)->psm); + chan->psm); hdev = hci_get_route(dst, src); if (!hdev) @@ -871,7 +873,7 @@ int l2cap_chan_connect(struct l2cap_chan *chan) auth_type = l2cap_get_auth_type(chan); - if (l2cap_pi(sk)->dcid == L2CAP_CID_LE_DATA) + if (chan->dcid == L2CAP_CID_LE_DATA) hcon = hci_connect(hdev, LE_LINK, dst, chan->sec_level, auth_type); else @@ -1231,8 +1233,9 @@ static inline int l2cap_skbuff_fromiovec(struct sock *sk, struct msghdr *msg, in return sent; } -struct sk_buff *l2cap_create_connless_pdu(struct sock *sk, struct msghdr *msg, size_t len) +struct sk_buff *l2cap_create_connless_pdu(struct l2cap_chan *chan, struct msghdr *msg, size_t len) { + struct sock *sk = chan->sk; struct l2cap_conn *conn = l2cap_pi(sk)->conn; struct sk_buff *skb; int err, count, hlen = L2CAP_HDR_SIZE + 2; @@ -1248,9 +1251,9 @@ struct sk_buff *l2cap_create_connless_pdu(struct sock *sk, struct msghdr *msg, s /* Create L2CAP header */ lh = (struct l2cap_hdr *) skb_put(skb, L2CAP_HDR_SIZE); - lh->cid = cpu_to_le16(l2cap_pi(sk)->dcid); + lh->cid = cpu_to_le16(chan->dcid); lh->len = cpu_to_le16(len + (hlen - L2CAP_HDR_SIZE)); - put_unaligned_le16(l2cap_pi(sk)->psm, skb_put(skb, 2)); + put_unaligned_le16(chan->psm, skb_put(skb, 2)); err = l2cap_skbuff_fromiovec(sk, msg, len, count, skb); if (unlikely(err < 0)) { @@ -1260,8 +1263,9 @@ struct sk_buff *l2cap_create_connless_pdu(struct sock *sk, struct msghdr *msg, s return skb; } -struct sk_buff *l2cap_create_basic_pdu(struct sock *sk, struct msghdr *msg, size_t len) +struct sk_buff *l2cap_create_basic_pdu(struct l2cap_chan *chan, struct msghdr *msg, size_t len) { + struct sock *sk = chan->sk; struct l2cap_conn *conn = l2cap_pi(sk)->conn; struct sk_buff *skb; int err, count, hlen = L2CAP_HDR_SIZE; @@ -1277,7 +1281,7 @@ struct sk_buff *l2cap_create_basic_pdu(struct sock *sk, struct msghdr *msg, size /* Create L2CAP header */ lh = (struct l2cap_hdr *) skb_put(skb, L2CAP_HDR_SIZE); - lh->cid = cpu_to_le16(l2cap_pi(sk)->dcid); + lh->cid = cpu_to_le16(chan->dcid); lh->len = cpu_to_le16(len + (hlen - L2CAP_HDR_SIZE)); err = l2cap_skbuff_fromiovec(sk, msg, len, count, skb); @@ -1315,7 +1319,7 @@ struct sk_buff *l2cap_create_iframe_pdu(struct l2cap_chan *chan, struct msghdr * /* Create L2CAP header */ lh = (struct l2cap_hdr *) skb_put(skb, L2CAP_HDR_SIZE); - lh->cid = cpu_to_le16(l2cap_pi(sk)->dcid); + lh->cid = cpu_to_le16(chan->dcid); lh->len = cpu_to_le16(len + (hlen - L2CAP_HDR_SIZE)); put_unaligned_le16(control, skb_put(skb, 2)); if (sdulen) @@ -1697,7 +1701,7 @@ done: break; } - req->dcid = cpu_to_le16(pi->dcid); + req->dcid = cpu_to_le16(chan->dcid); req->flags = cpu_to_le16(0); return ptr - data; @@ -1850,7 +1854,7 @@ done: if (result == L2CAP_CONF_SUCCESS) chan->conf_state |= L2CAP_CONF_OUTPUT_DONE; } - rsp->scid = cpu_to_le16(pi->dcid); + rsp->scid = cpu_to_le16(chan->dcid); rsp->result = cpu_to_le16(result); rsp->flags = cpu_to_le16(0x0000); @@ -1859,15 +1863,13 @@ done: static int l2cap_parse_conf_rsp(struct l2cap_chan *chan, void *rsp, int len, void *data, u16 *result) { - struct sock *sk = chan->sk; - struct l2cap_pinfo *pi = l2cap_pi(sk); struct l2cap_conf_req *req = data; void *ptr = req->data; int type, olen; unsigned long val; struct l2cap_conf_rfc rfc; - BT_DBG("sk %p, rsp %p, len %d, req %p", sk, rsp, len, data); + BT_DBG("chan %p, rsp %p, len %d, req %p", chan, rsp, len, data); while (len >= L2CAP_CONF_OPT_SIZE) { len -= l2cap_get_conf_opt(&rsp, &type, &olen, &val); @@ -1921,20 +1923,20 @@ static int l2cap_parse_conf_rsp(struct l2cap_chan *chan, void *rsp, int len, voi } } - req->dcid = cpu_to_le16(pi->dcid); + req->dcid = cpu_to_le16(chan->dcid); req->flags = cpu_to_le16(0x0000); return ptr - data; } -static int l2cap_build_conf_rsp(struct sock *sk, void *data, u16 result, u16 flags) +static int l2cap_build_conf_rsp(struct l2cap_chan *chan, void *data, u16 result, u16 flags) { struct l2cap_conf_rsp *rsp = data; void *ptr = rsp->data; - BT_DBG("sk %p", sk); + BT_DBG("chan %p", chan); - rsp->scid = cpu_to_le16(l2cap_pi(sk)->dcid); + rsp->scid = cpu_to_le16(chan->dcid); rsp->result = cpu_to_le16(result); rsp->flags = cpu_to_le16(flags); @@ -1950,8 +1952,8 @@ void __l2cap_connect_rsp_defer(struct sock *sk) sk->sk_state = BT_CONFIG; - rsp.scid = cpu_to_le16(l2cap_pi(sk)->dcid); - rsp.dcid = cpu_to_le16(l2cap_pi(sk)->scid); + rsp.scid = cpu_to_le16(chan->dcid); + rsp.dcid = cpu_to_le16(chan->scid); rsp.result = cpu_to_le16(L2CAP_CR_SUCCESS); rsp.status = cpu_to_le16(L2CAP_CS_NO_INFO); l2cap_send_cmd(conn, chan->ident, @@ -2085,14 +2087,14 @@ static inline int l2cap_connect_req(struct l2cap_conn *conn, struct l2cap_cmd_hd l2cap_sock_init(sk, parent); bacpy(&bt_sk(sk)->src, conn->src); bacpy(&bt_sk(sk)->dst, conn->dst); - l2cap_pi(sk)->psm = psm; - l2cap_pi(sk)->dcid = scid; + chan->psm = psm; + chan->dcid = scid; bt_accept_enqueue(parent, sk); __l2cap_chan_add(conn, chan); - dcid = l2cap_pi(sk)->scid; + dcid = chan->scid; l2cap_sock_set_timer(sk, sk->sk_sndtimeo); @@ -2190,7 +2192,7 @@ static inline int l2cap_connect_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hd case L2CAP_CR_SUCCESS: sk->sk_state = BT_CONFIG; chan->ident = 0; - l2cap_pi(sk)->dcid = dcid; + chan->dcid = dcid; chan->conf_state &= ~L2CAP_CONF_CONNECT_PEND; if (chan->conf_state & L2CAP_CONF_REQ_SENT) @@ -2270,7 +2272,7 @@ static inline int l2cap_config_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr len = cmd_len - sizeof(*req); if (chan->conf_len + len > sizeof(chan->conf_req)) { l2cap_send_cmd(conn, cmd->ident, L2CAP_CONF_RSP, - l2cap_build_conf_rsp(sk, rsp, + l2cap_build_conf_rsp(chan, rsp, L2CAP_CONF_REJECT, flags), rsp); goto unlock; } @@ -2282,7 +2284,7 @@ static inline int l2cap_config_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr if (flags & 0x0001) { /* Incomplete config. Send empty response. */ l2cap_send_cmd(conn, cmd->ident, L2CAP_CONF_RSP, - l2cap_build_conf_rsp(sk, rsp, + l2cap_build_conf_rsp(chan, rsp, L2CAP_CONF_SUCCESS, 0x0001), rsp); goto unlock; } @@ -2432,8 +2434,8 @@ static inline int l2cap_disconnect_req(struct l2cap_conn *conn, struct l2cap_cmd sk = chan->sk; - rsp.dcid = cpu_to_le16(l2cap_pi(sk)->scid); - rsp.scid = cpu_to_le16(l2cap_pi(sk)->dcid); + rsp.dcid = cpu_to_le16(chan->scid); + rsp.scid = cpu_to_le16(chan->dcid); l2cap_send_cmd(conn, cmd->ident, L2CAP_DISCONN_RSP, sizeof(rsp), &rsp); sk->sk_shutdown = SHUTDOWN_MASK; @@ -3920,8 +3922,8 @@ static int l2cap_security_cfm(struct hci_conn *hcon, u8 status, u8 encrypt) if (sk->sk_state == BT_CONNECT) { if (!status) { struct l2cap_conn_req req; - req.scid = cpu_to_le16(l2cap_pi(sk)->scid); - req.psm = l2cap_pi(sk)->psm; + req.scid = cpu_to_le16(chan->scid); + req.psm = chan->psm; chan->ident = l2cap_get_ident(conn); chan->conf_state |= L2CAP_CONF_CONNECT_PEND; @@ -3945,8 +3947,8 @@ static int l2cap_security_cfm(struct hci_conn *hcon, u8 status, u8 encrypt) result = L2CAP_CR_SEC_BLOCK; } - rsp.scid = cpu_to_le16(l2cap_pi(sk)->dcid); - rsp.dcid = cpu_to_le16(l2cap_pi(sk)->scid); + rsp.scid = cpu_to_le16(chan->dcid); + rsp.dcid = cpu_to_le16(chan->scid); rsp.result = cpu_to_le16(result); rsp.status = cpu_to_le16(L2CAP_CS_NO_INFO); l2cap_send_cmd(conn, chan->ident, L2CAP_CONN_RSP, @@ -4086,8 +4088,8 @@ static int l2cap_debugfs_show(struct seq_file *f, void *p) seq_printf(f, "%s %s %d %d 0x%4.4x 0x%4.4x %d %d %d %d\n", batostr(&bt_sk(sk)->src), batostr(&bt_sk(sk)->dst), - sk->sk_state, __le16_to_cpu(pi->psm), - pi->scid, pi->dcid, + sk->sk_state, __le16_to_cpu(chan->psm), + chan->scid, chan->dcid, chan->imtu, chan->omtu, chan->sec_level, chan->mode); } diff --git a/net/bluetooth/l2cap_sock.c b/net/bluetooth/l2cap_sock.c index eef33b17..f5a2773 100644 --- a/net/bluetooth/l2cap_sock.c +++ b/net/bluetooth/l2cap_sock.c @@ -141,7 +141,7 @@ static int l2cap_sock_bind(struct socket *sock, struct sockaddr *addr, int alen) } else { /* Save source address */ bacpy(&bt_sk(sk)->src, &la.l2_bdaddr); - l2cap_pi(sk)->psm = la.l2_psm; + chan->psm = la.l2_psm; chan->sport = la.l2_psm; sk->sk_state = BT_BOUND; @@ -151,7 +151,7 @@ static int l2cap_sock_bind(struct socket *sock, struct sockaddr *addr, int alen) } if (la.l2_cid) - l2cap_pi(sk)->scid = la.l2_cid; + chan->scid = la.l2_cid; write_unlock_bh(&l2cap_sk_list.lock); @@ -232,8 +232,8 @@ static int l2cap_sock_connect(struct socket *sock, struct sockaddr *addr, int al /* Set destination address and psm */ bacpy(&bt_sk(sk)->dst, &la.l2_bdaddr); - l2cap_pi(sk)->psm = la.l2_psm; - l2cap_pi(sk)->dcid = la.l2_cid; + chan->psm = la.l2_psm; + chan->dcid = la.l2_cid; err = l2cap_chan_connect(l2cap_pi(sk)->chan); if (err) @@ -276,7 +276,7 @@ static int l2cap_sock_listen(struct socket *sock, int backlog) goto done; } - if (!l2cap_pi(sk)->psm && !l2cap_pi(sk)->scid) { + if (!chan->psm && !chan->scid) { bdaddr_t *src = &bt_sk(sk)->src; u16 psm; @@ -286,7 +286,7 @@ static int l2cap_sock_listen(struct socket *sock, int backlog) for (psm = 0x1001; psm < 0x1100; psm += 2) if (!__l2cap_get_sock_by_addr(cpu_to_le16(psm), src)) { - l2cap_pi(sk)->psm = cpu_to_le16(psm); + chan->psm = cpu_to_le16(psm); chan->sport = cpu_to_le16(psm); err = 0; break; @@ -375,13 +375,13 @@ static int l2cap_sock_getname(struct socket *sock, struct sockaddr *addr, int *l *len = sizeof(struct sockaddr_l2); if (peer) { - la->l2_psm = l2cap_pi(sk)->psm; + la->l2_psm = chan->psm; bacpy(&la->l2_bdaddr, &bt_sk(sk)->dst); - la->l2_cid = cpu_to_le16(l2cap_pi(sk)->dcid); + la->l2_cid = cpu_to_le16(chan->dcid); } else { la->l2_psm = chan->sport; bacpy(&la->l2_bdaddr, &bt_sk(sk)->src); - la->l2_cid = cpu_to_le16(l2cap_pi(sk)->scid); + la->l2_cid = cpu_to_le16(chan->scid); } return 0; @@ -737,7 +737,7 @@ static int l2cap_sock_sendmsg(struct kiocb *iocb, struct socket *sock, struct ms /* Connectionless channel */ if (sk->sk_type == SOCK_DGRAM) { - skb = l2cap_create_connless_pdu(sk, msg, len); + skb = l2cap_create_connless_pdu(chan, msg, len); if (IS_ERR(skb)) { err = PTR_ERR(skb); } else { @@ -756,7 +756,7 @@ static int l2cap_sock_sendmsg(struct kiocb *iocb, struct socket *sock, struct ms } /* Create a basic PDU */ - skb = l2cap_create_basic_pdu(sk, msg, len); + skb = l2cap_create_basic_pdu(chan, msg, len); if (IS_ERR(skb)) { err = PTR_ERR(skb); goto done; @@ -911,8 +911,8 @@ void __l2cap_sock_close(struct sock *sk, int reason) else result = L2CAP_CR_BAD_PSM; - rsp.scid = cpu_to_le16(l2cap_pi(sk)->dcid); - rsp.dcid = cpu_to_le16(l2cap_pi(sk)->scid); + rsp.scid = cpu_to_le16(chan->dcid); + rsp.dcid = cpu_to_le16(chan->scid); rsp.result = cpu_to_le16(result); rsp.status = cpu_to_le16(L2CAP_CS_NO_INFO); l2cap_send_cmd(conn, chan->ident, L2CAP_CONN_RSP, -- cgit v0.10.2 From 8c1d787be4b62d2d1b6f04953eca4bcf7c839d44 Mon Sep 17 00:00:00 2001 From: "Gustavo F. Padovan" Date: Wed, 13 Apr 2011 20:23:55 -0300 Subject: Bluetooth: Move conn to struct l2cap_chan There is no need to the socket deal directly with the channel, most of the time it cares about the channel only. Signed-off-by: Gustavo F. Padovan diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h index fd199cd..3de90a9 100644 --- a/include/net/bluetooth/l2cap.h +++ b/include/net/bluetooth/l2cap.h @@ -284,6 +284,9 @@ struct srej_list { struct l2cap_chan { struct sock *sk; + + struct l2cap_conn *conn; + __le16 psm; __u16 dcid; __u16 scid; @@ -385,8 +388,6 @@ struct l2cap_conn { struct l2cap_pinfo { struct bt_sock bt; - - struct l2cap_conn *conn; struct l2cap_chan *chan; }; @@ -447,7 +448,7 @@ int l2cap_init_sockets(void); void l2cap_cleanup_sockets(void); void l2cap_send_cmd(struct l2cap_conn *conn, u8 ident, u8 code, u16 len, void *data); -void __l2cap_connect_rsp_defer(struct sock *sk); +void __l2cap_connect_rsp_defer(struct l2cap_chan *chan); int __l2cap_wait_ack(struct sock *sk); struct sk_buff *l2cap_create_connless_pdu(struct l2cap_chan *chan, struct msghdr *msg, size_t len); diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index dd726bd..8562ac1 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -169,7 +169,7 @@ static void __l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan) conn->disc_reason = 0x13; - l2cap_pi(sk)->conn = conn; + chan->conn = conn; if (sk->sk_type == SOCK_SEQPACKET || sk->sk_type == SOCK_STREAM) { if (conn->hcon->type == LE_LINK) { @@ -204,7 +204,7 @@ static void __l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan) void l2cap_chan_del(struct l2cap_chan *chan, int err) { struct sock *sk = chan->sk; - struct l2cap_conn *conn = l2cap_pi(sk)->conn; + struct l2cap_conn *conn = chan->conn; struct sock *parent = bt_sk(sk)->parent; l2cap_sock_clear_timer(sk); @@ -218,7 +218,7 @@ void l2cap_chan_del(struct l2cap_chan *chan, int err) write_unlock_bh(&conn->chan_lock); __sock_put(sk); - l2cap_pi(sk)->conn = NULL; + chan->conn = NULL; hci_conn_put(conn->hcon); } @@ -296,7 +296,7 @@ static inline u8 l2cap_get_auth_type(struct l2cap_chan *chan) /* Service level security */ static inline int l2cap_check_security(struct l2cap_chan *chan) { - struct l2cap_conn *conn = l2cap_pi(chan->sk)->conn; + struct l2cap_conn *conn = chan->conn; __u8 auth_type; auth_type = l2cap_get_auth_type(chan); @@ -349,7 +349,7 @@ static inline void l2cap_send_sframe(struct l2cap_chan *chan, u16 control) struct sk_buff *skb; struct l2cap_hdr *lh; struct l2cap_pinfo *pi = l2cap_pi(chan->sk); - struct l2cap_conn *conn = pi->conn; + struct l2cap_conn *conn = chan->conn; struct sock *sk = (struct sock *)pi; int count, hlen = L2CAP_HDR_SIZE + 2; u8 flags; @@ -394,7 +394,7 @@ static inline void l2cap_send_sframe(struct l2cap_chan *chan, u16 control) else flags = ACL_START; - hci_send_acl(pi->conn->hcon, skb, flags); + hci_send_acl(chan->conn->hcon, skb, flags); } static inline void l2cap_send_rr_or_rnr(struct l2cap_chan *chan, u16 control) @@ -417,8 +417,7 @@ static inline int __l2cap_no_conn_pending(struct l2cap_chan *chan) static void l2cap_do_start(struct l2cap_chan *chan) { - struct sock *sk = chan->sk; - struct l2cap_conn *conn = l2cap_pi(sk)->conn; + struct l2cap_conn *conn = chan->conn; if (conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_SENT) { if (!(conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_DONE)) @@ -920,12 +919,13 @@ done: int __l2cap_wait_ack(struct sock *sk) { + struct l2cap_chan *chan = l2cap_pi(sk)->chan; DECLARE_WAITQUEUE(wait, current); int err = 0; int timeo = HZ/5; add_wait_queue(sk_sleep(sk), &wait); - while ((l2cap_pi(sk)->chan->unacked_frames > 0 && l2cap_pi(sk)->conn)) { + while ((chan->unacked_frames > 0 && chan->conn)) { set_current_state(TASK_INTERRUPTIBLE); if (!timeo) @@ -958,7 +958,7 @@ static void l2cap_monitor_timeout(unsigned long arg) bh_lock_sock(sk); if (chan->retry_count >= chan->remote_max_tx) { - l2cap_send_disconn_req(l2cap_pi(sk)->conn, chan, ECONNABORTED); + l2cap_send_disconn_req(chan->conn, chan, ECONNABORTED); bh_unlock_sock(sk); return; } @@ -1008,8 +1008,7 @@ static void l2cap_drop_acked_frames(struct l2cap_chan *chan) void l2cap_do_send(struct l2cap_chan *chan, struct sk_buff *skb) { - struct sock *sk = chan->sk; - struct hci_conn *hcon = l2cap_pi(sk)->conn->hcon; + struct hci_conn *hcon = chan->conn->hcon; u16 flags; BT_DBG("chan %p, skb %p len %d", chan, skb, skb->len); @@ -1045,8 +1044,6 @@ void l2cap_streaming_send(struct l2cap_chan *chan) static void l2cap_retransmit_one_frame(struct l2cap_chan *chan, u8 tx_seq) { - struct sock *sk = chan->sk; - struct l2cap_pinfo *pi = l2cap_pi(sk); struct sk_buff *skb, *tx_skb; u16 control, fcs; @@ -1065,7 +1062,7 @@ static void l2cap_retransmit_one_frame(struct l2cap_chan *chan, u8 tx_seq) if (chan->remote_max_tx && bt_cb(skb)->retries == chan->remote_max_tx) { - l2cap_send_disconn_req(pi->conn, chan, ECONNABORTED); + l2cap_send_disconn_req(chan->conn, chan, ECONNABORTED); return; } @@ -1096,7 +1093,6 @@ int l2cap_ertm_send(struct l2cap_chan *chan) { struct sk_buff *skb, *tx_skb; struct sock *sk = chan->sk; - struct l2cap_pinfo *pi = l2cap_pi(sk); u16 control, fcs; int nsent = 0; @@ -1107,7 +1103,7 @@ int l2cap_ertm_send(struct l2cap_chan *chan) if (chan->remote_max_tx && bt_cb(skb)->retries == chan->remote_max_tx) { - l2cap_send_disconn_req(pi->conn, chan, ECONNABORTED); + l2cap_send_disconn_req(chan->conn, chan, ECONNABORTED); break; } @@ -1203,7 +1199,7 @@ static void l2cap_send_srejtail(struct l2cap_chan *chan) static inline int l2cap_skbuff_fromiovec(struct sock *sk, struct msghdr *msg, int len, int count, struct sk_buff *skb) { - struct l2cap_conn *conn = l2cap_pi(sk)->conn; + struct l2cap_conn *conn = l2cap_pi(sk)->chan->conn; struct sk_buff **frag; int err, sent = 0; @@ -1236,7 +1232,7 @@ static inline int l2cap_skbuff_fromiovec(struct sock *sk, struct msghdr *msg, in struct sk_buff *l2cap_create_connless_pdu(struct l2cap_chan *chan, struct msghdr *msg, size_t len) { struct sock *sk = chan->sk; - struct l2cap_conn *conn = l2cap_pi(sk)->conn; + struct l2cap_conn *conn = chan->conn; struct sk_buff *skb; int err, count, hlen = L2CAP_HDR_SIZE + 2; struct l2cap_hdr *lh; @@ -1266,7 +1262,7 @@ struct sk_buff *l2cap_create_connless_pdu(struct l2cap_chan *chan, struct msghdr struct sk_buff *l2cap_create_basic_pdu(struct l2cap_chan *chan, struct msghdr *msg, size_t len) { struct sock *sk = chan->sk; - struct l2cap_conn *conn = l2cap_pi(sk)->conn; + struct l2cap_conn *conn = chan->conn; struct sk_buff *skb; int err, count, hlen = L2CAP_HDR_SIZE; struct l2cap_hdr *lh; @@ -1295,7 +1291,7 @@ struct sk_buff *l2cap_create_basic_pdu(struct l2cap_chan *chan, struct msghdr *m struct sk_buff *l2cap_create_iframe_pdu(struct l2cap_chan *chan, struct msghdr *msg, size_t len, u16 control, u16 sdulen) { struct sock *sk = chan->sk; - struct l2cap_conn *conn = l2cap_pi(sk)->conn; + struct l2cap_conn *conn = chan->conn; struct sk_buff *skb; int err, count, hlen = L2CAP_HDR_SIZE + 2; struct l2cap_hdr *lh; @@ -1611,7 +1607,6 @@ static inline __u8 l2cap_select_mode(__u8 mode, __u16 remote_feat_mask) static int l2cap_build_conf_req(struct l2cap_chan *chan, void *data) { - struct l2cap_pinfo *pi = l2cap_pi(chan->sk); struct l2cap_conf_req *req = data; struct l2cap_conf_rfc rfc = { .mode = chan->mode }; void *ptr = req->data; @@ -1629,7 +1624,7 @@ static int l2cap_build_conf_req(struct l2cap_chan *chan, void *data) /* fall through */ default: - chan->mode = l2cap_select_mode(rfc.mode, pi->conn->feat_mask); + chan->mode = l2cap_select_mode(rfc.mode, chan->conn->feat_mask); break; } @@ -1639,8 +1634,8 @@ done: switch (chan->mode) { case L2CAP_MODE_BASIC: - if (!(pi->conn->feat_mask & L2CAP_FEAT_ERTM) && - !(pi->conn->feat_mask & L2CAP_FEAT_STREAMING)) + if (!(chan->conn->feat_mask & L2CAP_FEAT_ERTM) && + !(chan->conn->feat_mask & L2CAP_FEAT_STREAMING)) break; rfc.mode = L2CAP_MODE_BASIC; @@ -1661,13 +1656,13 @@ done: rfc.retrans_timeout = 0; rfc.monitor_timeout = 0; rfc.max_pdu_size = cpu_to_le16(L2CAP_DEFAULT_MAX_PDU_SIZE); - if (L2CAP_DEFAULT_MAX_PDU_SIZE > pi->conn->mtu - 10) - rfc.max_pdu_size = cpu_to_le16(pi->conn->mtu - 10); + if (L2CAP_DEFAULT_MAX_PDU_SIZE > chan->conn->mtu - 10) + rfc.max_pdu_size = cpu_to_le16(chan->conn->mtu - 10); l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC, sizeof(rfc), (unsigned long) &rfc); - if (!(pi->conn->feat_mask & L2CAP_FEAT_FCS)) + if (!(chan->conn->feat_mask & L2CAP_FEAT_FCS)) break; if (chan->fcs == L2CAP_FCS_NONE || @@ -1684,13 +1679,13 @@ done: rfc.retrans_timeout = 0; rfc.monitor_timeout = 0; rfc.max_pdu_size = cpu_to_le16(L2CAP_DEFAULT_MAX_PDU_SIZE); - if (L2CAP_DEFAULT_MAX_PDU_SIZE > pi->conn->mtu - 10) - rfc.max_pdu_size = cpu_to_le16(pi->conn->mtu - 10); + if (L2CAP_DEFAULT_MAX_PDU_SIZE > chan->conn->mtu - 10) + rfc.max_pdu_size = cpu_to_le16(chan->conn->mtu - 10); l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC, sizeof(rfc), (unsigned long) &rfc); - if (!(pi->conn->feat_mask & L2CAP_FEAT_FCS)) + if (!(chan->conn->feat_mask & L2CAP_FEAT_FCS)) break; if (chan->fcs == L2CAP_FCS_NONE || @@ -1709,7 +1704,6 @@ done: static int l2cap_parse_conf_req(struct l2cap_chan *chan, void *data) { - struct l2cap_pinfo *pi = l2cap_pi(chan->sk); struct l2cap_conf_rsp *rsp = data; void *ptr = rsp->data; void *req = chan->conf_req; @@ -1769,7 +1763,7 @@ static int l2cap_parse_conf_req(struct l2cap_chan *chan, void *data) case L2CAP_MODE_ERTM: if (!(chan->conf_state & L2CAP_CONF_STATE2_DEVICE)) { chan->mode = l2cap_select_mode(rfc.mode, - pi->conn->feat_mask); + chan->conn->feat_mask); break; } @@ -1814,8 +1808,8 @@ done: chan->remote_tx_win = rfc.txwin_size; chan->remote_max_tx = rfc.max_transmit; - if (le16_to_cpu(rfc.max_pdu_size) > pi->conn->mtu - 10) - rfc.max_pdu_size = cpu_to_le16(pi->conn->mtu - 10); + if (le16_to_cpu(rfc.max_pdu_size) > chan->conn->mtu - 10) + rfc.max_pdu_size = cpu_to_le16(chan->conn->mtu - 10); chan->remote_mps = le16_to_cpu(rfc.max_pdu_size); @@ -1832,8 +1826,8 @@ done: break; case L2CAP_MODE_STREAMING: - if (le16_to_cpu(rfc.max_pdu_size) > pi->conn->mtu - 10) - rfc.max_pdu_size = cpu_to_le16(pi->conn->mtu - 10); + if (le16_to_cpu(rfc.max_pdu_size) > chan->conn->mtu - 10) + rfc.max_pdu_size = cpu_to_le16(chan->conn->mtu - 10); chan->remote_mps = le16_to_cpu(rfc.max_pdu_size); @@ -1943,15 +1937,12 @@ static int l2cap_build_conf_rsp(struct l2cap_chan *chan, void *data, u16 result, return ptr - data; } -void __l2cap_connect_rsp_defer(struct sock *sk) +void __l2cap_connect_rsp_defer(struct l2cap_chan *chan) { struct l2cap_conn_rsp rsp; - struct l2cap_conn *conn = l2cap_pi(sk)->conn; - struct l2cap_chan *chan = l2cap_pi(sk)->chan; + struct l2cap_conn *conn = chan->conn; u8 buf[128]; - sk->sk_state = BT_CONFIG; - rsp.scid = cpu_to_le16(chan->dcid); rsp.dcid = cpu_to_le16(chan->scid); rsp.result = cpu_to_le16(L2CAP_CR_SUCCESS); @@ -2856,7 +2847,6 @@ static int l2cap_add_to_srej_queue(struct l2cap_chan *chan, struct sk_buff *skb, static int l2cap_ertm_reassembly_sdu(struct l2cap_chan *chan, struct sk_buff *skb, u16 control) { - struct l2cap_pinfo *pi = l2cap_pi(chan->sk); struct sk_buff *_skb; int err; @@ -2957,7 +2947,7 @@ drop: chan->sdu = NULL; disconnect: - l2cap_send_disconn_req(pi->conn, chan, ECONNRESET); + l2cap_send_disconn_req(chan->conn, chan, ECONNRESET); kfree_skb(skb); return 0; } @@ -3018,7 +3008,7 @@ static void l2cap_busy_work(struct work_struct *work) if (n_tries++ > L2CAP_LOCAL_BUSY_TRIES) { err = -EBUSY; - l2cap_send_disconn_req(l2cap_pi(sk)->conn, chan, EBUSY); + l2cap_send_disconn_req(chan->conn, chan, EBUSY); break; } @@ -3236,7 +3226,6 @@ static void l2cap_send_srejframe(struct l2cap_chan *chan, u8 tx_seq) static inline int l2cap_data_channel_iframe(struct l2cap_chan *chan, u16 rx_control, struct sk_buff *skb) { - struct l2cap_pinfo *pi = l2cap_pi(chan->sk); u8 tx_seq = __get_txseq(rx_control); u8 req_seq = __get_reqseq(rx_control); u8 sar = rx_control >> L2CAP_CTRL_SAR_SHIFT; @@ -3267,7 +3256,7 @@ static inline int l2cap_data_channel_iframe(struct l2cap_chan *chan, u16 rx_cont /* invalid tx_seq */ if (tx_seq_offset >= chan->tx_win) { - l2cap_send_disconn_req(pi->conn, chan, ECONNRESET); + l2cap_send_disconn_req(chan->conn, chan, ECONNRESET); goto drop; } @@ -3534,7 +3523,6 @@ static inline int l2cap_data_channel_sframe(struct l2cap_chan *chan, u16 rx_cont static int l2cap_ertm_data_rcv(struct sock *sk, struct sk_buff *skb) { struct l2cap_chan *chan = l2cap_pi(sk)->chan; - struct l2cap_pinfo *pi = l2cap_pi(sk); u16 control; u8 req_seq; int len, next_tx_seq_offset, req_seq_offset; @@ -3558,7 +3546,7 @@ static int l2cap_ertm_data_rcv(struct sock *sk, struct sk_buff *skb) len -= 2; if (len > chan->mps) { - l2cap_send_disconn_req(pi->conn, chan, ECONNRESET); + l2cap_send_disconn_req(chan->conn, chan, ECONNRESET); goto drop; } @@ -3574,13 +3562,13 @@ static int l2cap_ertm_data_rcv(struct sock *sk, struct sk_buff *skb) /* check for invalid req-seq */ if (req_seq_offset > next_tx_seq_offset) { - l2cap_send_disconn_req(pi->conn, chan, ECONNRESET); + l2cap_send_disconn_req(chan->conn, chan, ECONNRESET); goto drop; } if (__is_iframe(control)) { if (len < 0) { - l2cap_send_disconn_req(pi->conn, chan, ECONNRESET); + l2cap_send_disconn_req(chan->conn, chan, ECONNRESET); goto drop; } @@ -3588,7 +3576,7 @@ static int l2cap_ertm_data_rcv(struct sock *sk, struct sk_buff *skb) } else { if (len != 0) { BT_ERR("%d", len); - l2cap_send_disconn_req(pi->conn, chan, ECONNRESET); + l2cap_send_disconn_req(chan->conn, chan, ECONNRESET); goto drop; } diff --git a/net/bluetooth/l2cap_sock.c b/net/bluetooth/l2cap_sock.c index f5a2773..61d93f6 100644 --- a/net/bluetooth/l2cap_sock.c +++ b/net/bluetooth/l2cap_sock.c @@ -455,8 +455,8 @@ static int l2cap_sock_getsockopt_old(struct socket *sock, int optname, char __us break; } - cinfo.hci_handle = l2cap_pi(sk)->conn->hcon->handle; - memcpy(cinfo.dev_class, l2cap_pi(sk)->conn->hcon->dev_class, 3); + cinfo.hci_handle = chan->conn->hcon->handle; + memcpy(cinfo.dev_class, chan->conn->hcon->dev_class, 3); len = min_t(unsigned int, len, sizeof(cinfo)); if (copy_to_user(optval, (char *) &cinfo, len)) @@ -690,7 +690,7 @@ static int l2cap_sock_setsockopt(struct socket *sock, int level, int optname, ch } if (opt == BT_FLUSHABLE_OFF) { - struct l2cap_conn *conn = l2cap_pi(sk)->conn; + struct l2cap_conn *conn = chan->conn; /* proceed futher only when we have l2cap_conn and No Flush support in the LM */ if (!conn || !lmp_no_flush_capable(conn->hcon->hdev)) { @@ -823,7 +823,9 @@ static int l2cap_sock_recvmsg(struct kiocb *iocb, struct socket *sock, struct ms lock_sock(sk); if (sk->sk_state == BT_CONNECT2 && bt_sk(sk)->defer_setup) { - __l2cap_connect_rsp_defer(sk); + sk->sk_state = BT_CONFIG; + + __l2cap_connect_rsp_defer(l2cap_pi(sk)->chan); release_sock(sk); return 0; } @@ -878,8 +880,8 @@ static void l2cap_sock_cleanup_listen(struct sock *parent) void __l2cap_sock_close(struct sock *sk, int reason) { - struct l2cap_conn *conn = l2cap_pi(sk)->conn; struct l2cap_chan *chan = l2cap_pi(sk)->chan; + struct l2cap_conn *conn = chan->conn; BT_DBG("sk %p state %d socket %p", sk, sk->sk_state, sk->sk_socket); diff --git a/net/bluetooth/rfcomm/core.c b/net/bluetooth/rfcomm/core.c index fdd8f5a..121a5c1 100644 --- a/net/bluetooth/rfcomm/core.c +++ b/net/bluetooth/rfcomm/core.c @@ -232,6 +232,8 @@ static int rfcomm_l2sock_create(struct socket **sock) static inline int rfcomm_check_security(struct rfcomm_dlc *d) { struct sock *sk = d->session->sock->sk; + struct l2cap_conn *conn = l2cap_pi(sk)->chan->conn; + __u8 auth_type; switch (d->sec_level) { @@ -246,8 +248,7 @@ static inline int rfcomm_check_security(struct rfcomm_dlc *d) break; } - return hci_conn_security(l2cap_pi(sk)->conn->hcon, d->sec_level, - auth_type); + return hci_conn_security(conn->hcon, d->sec_level, auth_type); } static void rfcomm_session_timeout(unsigned long arg) @@ -1241,6 +1242,7 @@ static int rfcomm_recv_disc(struct rfcomm_session *s, u8 dlci) void rfcomm_dlc_accept(struct rfcomm_dlc *d) { struct sock *sk = d->session->sock->sk; + struct l2cap_conn *conn = l2cap_pi(sk)->chan->conn; BT_DBG("dlc %p", d); @@ -1254,7 +1256,7 @@ void rfcomm_dlc_accept(struct rfcomm_dlc *d) rfcomm_dlc_unlock(d); if (d->role_switch) - hci_conn_switch_role(l2cap_pi(sk)->conn->hcon, 0x00); + hci_conn_switch_role(conn->hcon, 0x00); rfcomm_send_msc(d->session, 1, d->dlci, d->v24_sig); } diff --git a/net/bluetooth/rfcomm/sock.c b/net/bluetooth/rfcomm/sock.c index 66cc1f0..386cfaf 100644 --- a/net/bluetooth/rfcomm/sock.c +++ b/net/bluetooth/rfcomm/sock.c @@ -743,6 +743,7 @@ static int rfcomm_sock_getsockopt_old(struct socket *sock, int optname, char __u struct sock *sk = sock->sk; struct sock *l2cap_sk; struct rfcomm_conninfo cinfo; + struct l2cap_conn *conn = l2cap_pi(sk)->chan->conn; int len, err = 0; u32 opt; @@ -787,8 +788,8 @@ static int rfcomm_sock_getsockopt_old(struct socket *sock, int optname, char __u l2cap_sk = rfcomm_pi(sk)->dlc->session->sock->sk; - cinfo.hci_handle = l2cap_pi(l2cap_sk)->conn->hcon->handle; - memcpy(cinfo.dev_class, l2cap_pi(l2cap_sk)->conn->hcon->dev_class, 3); + cinfo.hci_handle = conn->hcon->handle; + memcpy(cinfo.dev_class, conn->hcon->dev_class, 3); len = min_t(unsigned int, len, sizeof(cinfo)); if (copy_to_user(optval, (char *) &cinfo, len)) -- cgit v0.10.2 From 6ff5abbf4e4aa88feb9c2367d4fbd9ea081bf98c Mon Sep 17 00:00:00 2001 From: "Gustavo F. Padovan" Date: Mon, 25 Apr 2011 15:10:41 -0300 Subject: Bluetooth: Fix memory leak with L2CAP channels A new l2cap_chan_free() is added to free the channels. Signed-off-by: Gustavo F. Padovan diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h index 3de90a9..0a01341 100644 --- a/include/net/bluetooth/l2cap.h +++ b/include/net/bluetooth/l2cap.h @@ -469,6 +469,7 @@ struct sock *l2cap_sock_alloc(struct net *net, struct socket *sock, void l2cap_send_disconn_req(struct l2cap_conn *conn, struct l2cap_chan *chan, int err); struct l2cap_chan *l2cap_chan_alloc(struct sock *sk); void l2cap_chan_del(struct l2cap_chan *chan, int err); +void l2cap_chan_free(struct l2cap_chan *chan); int l2cap_chan_connect(struct l2cap_chan *chan); #endif /* __L2CAP_H */ diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index 8562ac1..338d8c3 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -160,6 +160,11 @@ struct l2cap_chan *l2cap_chan_alloc(struct sock *sk) return chan; } +void l2cap_chan_free(struct l2cap_chan *chan) +{ + kfree(chan); +} + static void __l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan) { struct sock *sk = chan->sk; @@ -236,7 +241,7 @@ void l2cap_chan_del(struct l2cap_chan *chan, int err) if (!(chan->conf_state & L2CAP_CONF_OUTPUT_DONE && chan->conf_state & L2CAP_CONF_INPUT_DONE)) - goto free; + return; skb_queue_purge(&chan->tx_q); @@ -255,9 +260,6 @@ void l2cap_chan_del(struct l2cap_chan *chan, int err) kfree(l); } } - -free: - kfree(chan); } static inline u8 l2cap_get_auth_type(struct l2cap_chan *chan) diff --git a/net/bluetooth/l2cap_sock.c b/net/bluetooth/l2cap_sock.c index 61d93f6..0e23ebd 100644 --- a/net/bluetooth/l2cap_sock.c +++ b/net/bluetooth/l2cap_sock.c @@ -849,6 +849,8 @@ void l2cap_sock_kill(struct sock *sk) BT_DBG("sk %p state %d", sk, sk->sk_state); /* Kill poor orphan */ + + l2cap_chan_free(l2cap_pi(sk)->chan); bt_sock_unlink(&l2cap_sk_list, sk); sock_set_flag(sk, SOCK_DEAD); sock_put(sk); -- cgit v0.10.2 From cf2f90f59bbf2c2a539d171cde6e1dfe72048555 Mon Sep 17 00:00:00 2001 From: "Gustavo F. Padovan" Date: Wed, 27 Apr 2011 18:40:39 -0300 Subject: Bluetooth: Don't export l2cap_sock_ops l2cap_sk_ops can be static, it's not used outside l2cap_sock.c Signed-off-by: Gustavo F. Padovan diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h index 0a01341..c34b1c1 100644 --- a/include/net/bluetooth/l2cap.h +++ b/include/net/bluetooth/l2cap.h @@ -441,7 +441,6 @@ static inline int l2cap_tx_window_full(struct l2cap_chan *ch) #define __is_sar_start(ctrl) (((ctrl) & L2CAP_CTRL_SAR) == L2CAP_SDU_START) extern int disable_ertm; -extern const struct proto_ops l2cap_sock_ops; extern struct bt_sock_list l2cap_sk_list; int l2cap_init_sockets(void); diff --git a/net/bluetooth/l2cap_sock.c b/net/bluetooth/l2cap_sock.c index 0e23ebd..09cc7a0 100644 --- a/net/bluetooth/l2cap_sock.c +++ b/net/bluetooth/l2cap_sock.c @@ -30,6 +30,8 @@ #include #include +static const struct proto_ops l2cap_sock_ops; + /* ---- L2CAP timers ---- */ static void l2cap_sock_timeout(unsigned long arg) { @@ -1106,7 +1108,7 @@ static int l2cap_sock_create(struct net *net, struct socket *sock, int protocol, return 0; } -const struct proto_ops l2cap_sock_ops = { +static const struct proto_ops l2cap_sock_ops = { .family = PF_BLUETOOTH, .owner = THIS_MODULE, .release = l2cap_sock_release, -- cgit v0.10.2 From 14a53664138a8407382745bb470045d1817b7801 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Wed, 27 Apr 2011 10:29:56 -0400 Subject: Bluetooth: Add basic discovery commands to the management interface This patch adds start_discovery and stop_discovery commands to the management interface. Right now their implementation is fairly simplistic and the parameters are fixed to what user space has defaulted to so far. This is the very initial phase for discovery implementation into the kernel. Next steps include name resolution, LE scanning and bdaddr type handling. Signed-off-by: Johan Hedberg Signed-off-by: Anderson Briglia Signed-off-by: Gustavo F. Padovan diff --git a/include/net/bluetooth/mgmt.h b/include/net/bluetooth/mgmt.h index 6b6ff92..be93dd0 100644 --- a/include/net/bluetooth/mgmt.h +++ b/include/net/bluetooth/mgmt.h @@ -195,6 +195,10 @@ struct mgmt_cp_remove_remote_oob_data { bdaddr_t bdaddr; } __packed; +#define MGMT_OP_START_DISCOVERY 0x001B + +#define MGMT_OP_STOP_DISCOVERY 0x001C + #define MGMT_EV_CMD_COMPLETE 0x0001 struct mgmt_ev_cmd_complete { __le16 opcode; diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index c304688..dbc248f 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -1569,6 +1569,75 @@ static int remove_remote_oob_data(struct sock *sk, u16 index, return err; } +static int start_discovery(struct sock *sk, u16 index) +{ + u8 lap[3] = { 0x33, 0x8b, 0x9e }; + struct hci_cp_inquiry cp; + struct pending_cmd *cmd; + struct hci_dev *hdev; + int err; + + BT_DBG("hci%u", index); + + hdev = hci_dev_get(index); + if (!hdev) + return cmd_status(sk, index, MGMT_OP_START_DISCOVERY, ENODEV); + + hci_dev_lock_bh(hdev); + + cmd = mgmt_pending_add(sk, MGMT_OP_START_DISCOVERY, index, NULL, 0); + if (!cmd) { + err = -ENOMEM; + goto failed; + } + + memset(&cp, 0, sizeof(cp)); + memcpy(&cp.lap, lap, 3); + cp.length = 0x08; + cp.num_rsp = 0x00; + + err = hci_send_cmd(hdev, HCI_OP_INQUIRY, sizeof(cp), &cp); + if (err < 0) + mgmt_pending_remove(cmd); + +failed: + hci_dev_unlock_bh(hdev); + hci_dev_put(hdev); + + return err; +} + +static int stop_discovery(struct sock *sk, u16 index) +{ + struct hci_dev *hdev; + struct pending_cmd *cmd; + int err; + + BT_DBG("hci%u", index); + + hdev = hci_dev_get(index); + if (!hdev) + return cmd_status(sk, index, MGMT_OP_STOP_DISCOVERY, ENODEV); + + hci_dev_lock_bh(hdev); + + cmd = mgmt_pending_add(sk, MGMT_OP_STOP_DISCOVERY, index, NULL, 0); + if (!cmd) { + err = -ENOMEM; + goto failed; + } + + err = hci_send_cmd(hdev, HCI_OP_INQUIRY_CANCEL, 0, NULL); + if (err < 0) + mgmt_pending_remove(cmd); + +failed: + hci_dev_unlock_bh(hdev); + hci_dev_put(hdev); + + return err; +} + int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen) { unsigned char *buf; @@ -1677,7 +1746,12 @@ int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen) err = remove_remote_oob_data(sk, index, buf + sizeof(*hdr), len); break; - + case MGMT_OP_START_DISCOVERY: + err = start_discovery(sk, index); + break; + case MGMT_OP_STOP_DISCOVERY: + err = stop_discovery(sk, index); + break; default: BT_DBG("Unknown op %u", opcode); err = cmd_status(sk, index, opcode, 0x01); -- cgit v0.10.2 From 314b2381a79c6bfe3ddc4ba3806ecb6aec27a3db Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Wed, 27 Apr 2011 10:29:57 -0400 Subject: Bluetooth: Add discovering event to the Management interface This patch adds a new event to the Management interface to track when local adapters are discovering remote devices. For now this only tracks BR/EDR discovery procedures. Signed-off-by: Johan Hedberg Signed-off-by: Anderson Briglia Signed-off-by: Gustavo F. Padovan diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index 4093133..69967e5 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -790,6 +790,7 @@ int mgmt_read_local_oob_data_reply_complete(u16 index, u8 *hash, u8 *randomizer, int mgmt_device_found(u16 index, bdaddr_t *bdaddr, u8 *dev_class, s8 rssi, u8 *eir); int mgmt_remote_name(u16 index, bdaddr_t *bdaddr, u8 *name); +int mgmt_discovering(u16 index, u8 discovering); /* HCI info for socket */ #define hci_pi(sk) ((struct hci_pinfo *) sk) diff --git a/include/net/bluetooth/mgmt.h b/include/net/bluetooth/mgmt.h index be93dd0..7434406 100644 --- a/include/net/bluetooth/mgmt.h +++ b/include/net/bluetooth/mgmt.h @@ -285,3 +285,5 @@ struct mgmt_ev_remote_name { bdaddr_t bdaddr; __u8 name[MGMT_MAX_NAME_LENGTH]; } __packed; + +#define MGMT_EV_DISCOVERING 0x0014 diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index cb25628..e64a3de 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -56,7 +56,9 @@ static void hci_cc_inquiry_cancel(struct hci_dev *hdev, struct sk_buff *skb) if (status) return; - clear_bit(HCI_INQUIRY, &hdev->flags); + if (test_bit(HCI_MGMT, &hdev->flags) && + test_and_clear_bit(HCI_INQUIRY, &hdev->flags)) + mgmt_discovering(hdev->id, 0); hci_req_complete(hdev, HCI_OP_INQUIRY_CANCEL, status); @@ -72,7 +74,9 @@ static void hci_cc_exit_periodic_inq(struct hci_dev *hdev, struct sk_buff *skb) if (status) return; - clear_bit(HCI_INQUIRY, &hdev->flags); + if (test_bit(HCI_MGMT, &hdev->flags) && + test_and_clear_bit(HCI_INQUIRY, &hdev->flags)) + mgmt_discovering(hdev->id, 0); hci_conn_check_pending(hdev); } @@ -841,10 +845,14 @@ static inline void hci_cs_inquiry(struct hci_dev *hdev, __u8 status) if (status) { hci_req_complete(hdev, HCI_OP_INQUIRY, status); - hci_conn_check_pending(hdev); - } else - set_bit(HCI_INQUIRY, &hdev->flags); + return; + } + + if (test_bit(HCI_MGMT, &hdev->flags) && + !test_and_set_bit(HCI_INQUIRY, + &hdev->flags)) + mgmt_discovering(hdev->id, 1); } static inline void hci_cs_create_conn(struct hci_dev *hdev, __u8 status) @@ -1208,7 +1216,9 @@ static inline void hci_inquiry_complete_evt(struct hci_dev *hdev, struct sk_buff BT_DBG("%s status %d", hdev->name, status); - clear_bit(HCI_INQUIRY, &hdev->flags); + if (test_bit(HCI_MGMT, &hdev->flags) && + test_and_clear_bit(HCI_INQUIRY, &hdev->flags)) + mgmt_discovering(hdev->id, 0); hci_req_complete(hdev, HCI_OP_INQUIRY, status); @@ -1228,6 +1238,12 @@ static inline void hci_inquiry_result_evt(struct hci_dev *hdev, struct sk_buff * hci_dev_lock(hdev); + if (!test_and_set_bit(HCI_INQUIRY, &hdev->flags)) { + + if (test_bit(HCI_MGMT, &hdev->flags)) + mgmt_discovering(hdev->id, 1); + } + for (; num_rsp; num_rsp--, info++) { bacpy(&data.bdaddr, &info->bdaddr); data.pscan_rep_mode = info->pscan_rep_mode; @@ -2158,6 +2174,12 @@ static inline void hci_inquiry_result_with_rssi_evt(struct hci_dev *hdev, struct hci_dev_lock(hdev); + if (!test_and_set_bit(HCI_INQUIRY, &hdev->flags)) { + + if (test_bit(HCI_MGMT, &hdev->flags)) + mgmt_discovering(hdev->id, 1); + } + if ((skb->len - 1) / num_rsp != sizeof(struct inquiry_info_with_rssi)) { struct inquiry_info_with_rssi_and_pscan_mode *info; info = (void *) (skb->data + 1); @@ -2320,6 +2342,12 @@ static inline void hci_extended_inquiry_result_evt(struct hci_dev *hdev, struct if (!num_rsp) return; + if (!test_and_set_bit(HCI_INQUIRY, &hdev->flags)) { + + if (test_bit(HCI_MGMT, &hdev->flags)) + mgmt_discovering(hdev->id, 1); + } + hci_dev_lock(hdev); for (; num_rsp; num_rsp--, info++) { diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index dbc248f..4542396 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -2149,3 +2149,9 @@ int mgmt_remote_name(u16 index, bdaddr_t *bdaddr, u8 *name) return mgmt_event(MGMT_EV_REMOTE_NAME, index, &ev, sizeof(ev), NULL); } + +int mgmt_discovering(u16 index, u8 discovering) +{ + return mgmt_event(MGMT_EV_DISCOVERING, index, &discovering, + sizeof(discovering), NULL); +} -- cgit v0.10.2 From 0a14842f5a3c0e88a1e59fac5c3025db39721f74 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Wed, 20 Apr 2011 09:27:32 +0000 Subject: net: filter: Just In Time compiler for x86-64 In order to speedup packet filtering, here is an implementation of a JIT compiler for x86_64 It is disabled by default, and must be enabled by the admin. echo 1 >/proc/sys/net/core/bpf_jit_enable It uses module_alloc() and module_free() to get memory in the 2GB text kernel range since we call helpers functions from the generated code. EAX : BPF A accumulator EBX : BPF X accumulator RDI : pointer to skb (first argument given to JIT function) RBP : frame pointer (even if CONFIG_FRAME_POINTER=n) r9d : skb->len - skb->data_len (headlen) r8 : skb->data To get a trace of generated code, use : echo 2 >/proc/sys/net/core/bpf_jit_enable Example of generated code : # tcpdump -p -n -s 0 -i eth1 host 192.168.20.0/24 flen=18 proglen=147 pass=3 image=ffffffffa00b5000 JIT code: ffffffffa00b5000: 55 48 89 e5 48 83 ec 60 48 89 5d f8 44 8b 4f 60 JIT code: ffffffffa00b5010: 44 2b 4f 64 4c 8b 87 b8 00 00 00 be 0c 00 00 00 JIT code: ffffffffa00b5020: e8 24 7b f7 e0 3d 00 08 00 00 75 28 be 1a 00 00 JIT code: ffffffffa00b5030: 00 e8 fe 7a f7 e0 24 00 3d 00 14 a8 c0 74 49 be JIT code: ffffffffa00b5040: 1e 00 00 00 e8 eb 7a f7 e0 24 00 3d 00 14 a8 c0 JIT code: ffffffffa00b5050: 74 36 eb 3b 3d 06 08 00 00 74 07 3d 35 80 00 00 JIT code: ffffffffa00b5060: 75 2d be 1c 00 00 00 e8 c8 7a f7 e0 24 00 3d 00 JIT code: ffffffffa00b5070: 14 a8 c0 74 13 be 26 00 00 00 e8 b5 7a f7 e0 24 JIT code: ffffffffa00b5080: 00 3d 00 14 a8 c0 75 07 b8 ff ff 00 00 eb 02 31 JIT code: ffffffffa00b5090: c0 c9 c3 BPF program is 144 bytes long, so native program is almost same size ;) (000) ldh [12] (001) jeq #0x800 jt 2 jf 8 (002) ld [26] (003) and #0xffffff00 (004) jeq #0xc0a81400 jt 16 jf 5 (005) ld [30] (006) and #0xffffff00 (007) jeq #0xc0a81400 jt 16 jf 17 (008) jeq #0x806 jt 10 jf 9 (009) jeq #0x8035 jt 10 jf 17 (010) ld [28] (011) and #0xffffff00 (012) jeq #0xc0a81400 jt 16 jf 13 (013) ld [38] (014) and #0xffffff00 (015) jeq #0xc0a81400 jt 16 jf 17 (016) ret #65535 (017) ret #0 Signed-off-by: Eric Dumazet Cc: Arnaldo Carvalho de Melo Cc: Ben Hutchings Cc: Hagen Paul Pfeifer Signed-off-by: David S. Miller diff --git a/Documentation/sysctl/net.txt b/Documentation/sysctl/net.txt index cbd05ff..3201a70 100644 --- a/Documentation/sysctl/net.txt +++ b/Documentation/sysctl/net.txt @@ -32,6 +32,17 @@ Table : Subdirectories in /proc/sys/net 1. /proc/sys/net/core - Network core options ------------------------------------------------------- +bpf_jit_enable +-------------- + +This enables Berkeley Packet Filter Just in Time compiler. +Currently supported on x86_64 architecture, bpf_jit provides a framework +to speed packet filtering, the one used by tcpdump/libpcap for example. +Values : + 0 - disable the JIT (default value) + 1 - enable the JIT + 2 - enable the JIT and ask the compiler to emit traces on kernel log. + rmem_default ------------ diff --git a/MAINTAINERS b/MAINTAINERS index b5266ad..17c0917 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -4372,6 +4372,7 @@ S: Maintained F: net/ipv4/ F: net/ipv6/ F: include/net/ip* +F: arch/x86/net/* NETWORKING [LABELED] (NetLabel, CIPSO, Labeled IPsec, SECMARK) M: Paul Moore diff --git a/arch/x86/Kbuild b/arch/x86/Kbuild index 0e10323..0e9dec6 100644 --- a/arch/x86/Kbuild +++ b/arch/x86/Kbuild @@ -15,3 +15,4 @@ obj-y += vdso/ obj-$(CONFIG_IA32_EMULATION) += ia32/ obj-y += platform/ +obj-y += net/ diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig index cc6c53a..855a1bd 100644 --- a/arch/x86/Kconfig +++ b/arch/x86/Kconfig @@ -72,6 +72,7 @@ config X86 select IRQ_FORCED_THREADING select USE_GENERIC_SMP_HELPERS if SMP select ARCH_NO_SYSDEV_OPS + select HAVE_BPF_JIT if X86_64 config INSTRUCTION_DECODER def_bool (KPROBES || PERF_EVENTS) diff --git a/arch/x86/net/Makefile b/arch/x86/net/Makefile new file mode 100644 index 0000000..90568c3 --- /dev/null +++ b/arch/x86/net/Makefile @@ -0,0 +1,4 @@ +# +# Arch-specific network modules +# +obj-$(CONFIG_BPF_JIT) += bpf_jit.o bpf_jit_comp.o diff --git a/arch/x86/net/bpf_jit.S b/arch/x86/net/bpf_jit.S new file mode 100644 index 0000000..6687022 --- /dev/null +++ b/arch/x86/net/bpf_jit.S @@ -0,0 +1,140 @@ +/* bpf_jit.S : BPF JIT helper functions + * + * Copyright (C) 2011 Eric Dumazet (eric.dumazet@gmail.com) + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; version 2 + * of the License. + */ +#include +#include + +/* + * Calling convention : + * rdi : skb pointer + * esi : offset of byte(s) to fetch in skb (can be scratched) + * r8 : copy of skb->data + * r9d : hlen = skb->len - skb->data_len + */ +#define SKBDATA %r8 + +sk_load_word_ind: + .globl sk_load_word_ind + + add %ebx,%esi /* offset += X */ +# test %esi,%esi /* if (offset < 0) goto bpf_error; */ + js bpf_error + +sk_load_word: + .globl sk_load_word + + mov %r9d,%eax # hlen + sub %esi,%eax # hlen - offset + cmp $3,%eax + jle bpf_slow_path_word + mov (SKBDATA,%rsi),%eax + bswap %eax /* ntohl() */ + ret + + +sk_load_half_ind: + .globl sk_load_half_ind + + add %ebx,%esi /* offset += X */ + js bpf_error + +sk_load_half: + .globl sk_load_half + + mov %r9d,%eax + sub %esi,%eax # hlen - offset + cmp $1,%eax + jle bpf_slow_path_half + movzwl (SKBDATA,%rsi),%eax + rol $8,%ax # ntohs() + ret + +sk_load_byte_ind: + .globl sk_load_byte_ind + add %ebx,%esi /* offset += X */ + js bpf_error + +sk_load_byte: + .globl sk_load_byte + + cmp %esi,%r9d /* if (offset >= hlen) goto bpf_slow_path_byte */ + jle bpf_slow_path_byte + movzbl (SKBDATA,%rsi),%eax + ret + +/** + * sk_load_byte_msh - BPF_S_LDX_B_MSH helper + * + * Implements BPF_S_LDX_B_MSH : ldxb 4*([offset]&0xf) + * Must preserve A accumulator (%eax) + * Inputs : %esi is the offset value, already known positive + */ +ENTRY(sk_load_byte_msh) + CFI_STARTPROC + cmp %esi,%r9d /* if (offset >= hlen) goto bpf_slow_path_byte_msh */ + jle bpf_slow_path_byte_msh + movzbl (SKBDATA,%rsi),%ebx + and $15,%bl + shl $2,%bl + ret + CFI_ENDPROC +ENDPROC(sk_load_byte_msh) + +bpf_error: +# force a return 0 from jit handler + xor %eax,%eax + mov -8(%rbp),%rbx + leaveq + ret + +/* rsi contains offset and can be scratched */ +#define bpf_slow_path_common(LEN) \ + push %rdi; /* save skb */ \ + push %r9; \ + push SKBDATA; \ +/* rsi already has offset */ \ + mov $LEN,%ecx; /* len */ \ + lea -12(%rbp),%rdx; \ + call skb_copy_bits; \ + test %eax,%eax; \ + pop SKBDATA; \ + pop %r9; \ + pop %rdi + + +bpf_slow_path_word: + bpf_slow_path_common(4) + js bpf_error + mov -12(%rbp),%eax + bswap %eax + ret + +bpf_slow_path_half: + bpf_slow_path_common(2) + js bpf_error + mov -12(%rbp),%ax + rol $8,%ax + movzwl %ax,%eax + ret + +bpf_slow_path_byte: + bpf_slow_path_common(1) + js bpf_error + movzbl -12(%rbp),%eax + ret + +bpf_slow_path_byte_msh: + xchg %eax,%ebx /* dont lose A , X is about to be scratched */ + bpf_slow_path_common(1) + js bpf_error + movzbl -12(%rbp),%eax + and $15,%al + shl $2,%al + xchg %eax,%ebx + ret diff --git a/arch/x86/net/bpf_jit_comp.c b/arch/x86/net/bpf_jit_comp.c new file mode 100644 index 0000000..bfab3fa --- /dev/null +++ b/arch/x86/net/bpf_jit_comp.c @@ -0,0 +1,654 @@ +/* bpf_jit_comp.c : BPF JIT compiler + * + * Copyright (C) 2011 Eric Dumazet (eric.dumazet@gmail.com) + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; version 2 + * of the License. + */ +#include +#include +#include +#include + +/* + * Conventions : + * EAX : BPF A accumulator + * EBX : BPF X accumulator + * RDI : pointer to skb (first argument given to JIT function) + * RBP : frame pointer (even if CONFIG_FRAME_POINTER=n) + * ECX,EDX,ESI : scratch registers + * r9d : skb->len - skb->data_len (headlen) + * r8 : skb->data + * -8(RBP) : saved RBX value + * -16(RBP)..-80(RBP) : BPF_MEMWORDS values + */ +int bpf_jit_enable __read_mostly; + +/* + * assembly code in arch/x86/net/bpf_jit.S + */ +extern u8 sk_load_word[], sk_load_half[], sk_load_byte[], sk_load_byte_msh[]; +extern u8 sk_load_word_ind[], sk_load_half_ind[], sk_load_byte_ind[]; + +static inline u8 *emit_code(u8 *ptr, u32 bytes, unsigned int len) +{ + if (len == 1) + *ptr = bytes; + else if (len == 2) + *(u16 *)ptr = bytes; + else { + *(u32 *)ptr = bytes; + barrier(); + } + return ptr + len; +} + +#define EMIT(bytes, len) do { prog = emit_code(prog, bytes, len); } while (0) + +#define EMIT1(b1) EMIT(b1, 1) +#define EMIT2(b1, b2) EMIT((b1) + ((b2) << 8), 2) +#define EMIT3(b1, b2, b3) EMIT((b1) + ((b2) << 8) + ((b3) << 16), 3) +#define EMIT4(b1, b2, b3, b4) EMIT((b1) + ((b2) << 8) + ((b3) << 16) + ((b4) << 24), 4) +#define EMIT1_off32(b1, off) do { EMIT1(b1); EMIT(off, 4);} while (0) + +#define CLEAR_A() EMIT2(0x31, 0xc0) /* xor %eax,%eax */ +#define CLEAR_X() EMIT2(0x31, 0xdb) /* xor %ebx,%ebx */ + +static inline bool is_imm8(int value) +{ + return value <= 127 && value >= -128; +} + +static inline bool is_near(int offset) +{ + return offset <= 127 && offset >= -128; +} + +#define EMIT_JMP(offset) \ +do { \ + if (offset) { \ + if (is_near(offset)) \ + EMIT2(0xeb, offset); /* jmp .+off8 */ \ + else \ + EMIT1_off32(0xe9, offset); /* jmp .+off32 */ \ + } \ +} while (0) + +/* list of x86 cond jumps opcodes (. + s8) + * Add 0x10 (and an extra 0x0f) to generate far jumps (. + s32) + */ +#define X86_JB 0x72 +#define X86_JAE 0x73 +#define X86_JE 0x74 +#define X86_JNE 0x75 +#define X86_JBE 0x76 +#define X86_JA 0x77 + +#define EMIT_COND_JMP(op, offset) \ +do { \ + if (is_near(offset)) \ + EMIT2(op, offset); /* jxx .+off8 */ \ + else { \ + EMIT2(0x0f, op + 0x10); \ + EMIT(offset, 4); /* jxx .+off32 */ \ + } \ +} while (0) + +#define COND_SEL(CODE, TOP, FOP) \ + case CODE: \ + t_op = TOP; \ + f_op = FOP; \ + goto cond_branch + + +#define SEEN_DATAREF 1 /* might call external helpers */ +#define SEEN_XREG 2 /* ebx is used */ +#define SEEN_MEM 4 /* use mem[] for temporary storage */ + +static inline void bpf_flush_icache(void *start, void *end) +{ + mm_segment_t old_fs = get_fs(); + + set_fs(KERNEL_DS); + smp_wmb(); + flush_icache_range((unsigned long)start, (unsigned long)end); + set_fs(old_fs); +} + + +void bpf_jit_compile(struct sk_filter *fp) +{ + u8 temp[64]; + u8 *prog; + unsigned int proglen, oldproglen = 0; + int ilen, i; + int t_offset, f_offset; + u8 t_op, f_op, seen = 0, pass; + u8 *image = NULL; + u8 *func; + int pc_ret0 = -1; /* bpf index of first RET #0 instruction (if any) */ + unsigned int cleanup_addr; /* epilogue code offset */ + unsigned int *addrs; + const struct sock_filter *filter = fp->insns; + int flen = fp->len; + + if (!bpf_jit_enable) + return; + + addrs = kmalloc(flen * sizeof(*addrs), GFP_KERNEL); + if (addrs == NULL) + return; + + /* Before first pass, make a rough estimation of addrs[] + * each bpf instruction is translated to less than 64 bytes + */ + for (proglen = 0, i = 0; i < flen; i++) { + proglen += 64; + addrs[i] = proglen; + } + cleanup_addr = proglen; /* epilogue address */ + + for (pass = 0; pass < 10; pass++) { + /* no prologue/epilogue for trivial filters (RET something) */ + proglen = 0; + prog = temp; + + if (seen) { + EMIT4(0x55, 0x48, 0x89, 0xe5); /* push %rbp; mov %rsp,%rbp */ + EMIT4(0x48, 0x83, 0xec, 96); /* subq $96,%rsp */ + /* note : must save %rbx in case bpf_error is hit */ + if (seen & (SEEN_XREG | SEEN_DATAREF)) + EMIT4(0x48, 0x89, 0x5d, 0xf8); /* mov %rbx, -8(%rbp) */ + if (seen & SEEN_XREG) + CLEAR_X(); /* make sure we dont leek kernel memory */ + + /* + * If this filter needs to access skb data, + * loads r9 and r8 with : + * r9 = skb->len - skb->data_len + * r8 = skb->data + */ + if (seen & SEEN_DATAREF) { + if (offsetof(struct sk_buff, len) <= 127) + /* mov off8(%rdi),%r9d */ + EMIT4(0x44, 0x8b, 0x4f, offsetof(struct sk_buff, len)); + else { + /* mov off32(%rdi),%r9d */ + EMIT3(0x44, 0x8b, 0x8f); + EMIT(offsetof(struct sk_buff, len), 4); + } + if (is_imm8(offsetof(struct sk_buff, data_len))) + /* sub off8(%rdi),%r9d */ + EMIT4(0x44, 0x2b, 0x4f, offsetof(struct sk_buff, data_len)); + else { + EMIT3(0x44, 0x2b, 0x8f); + EMIT(offsetof(struct sk_buff, data_len), 4); + } + + if (is_imm8(offsetof(struct sk_buff, data))) + /* mov off8(%rdi),%r8 */ + EMIT4(0x4c, 0x8b, 0x47, offsetof(struct sk_buff, data)); + else { + /* mov off32(%rdi),%r8 */ + EMIT3(0x4c, 0x8b, 0x87); + EMIT(offsetof(struct sk_buff, data), 4); + } + } + } + + switch (filter[0].code) { + case BPF_S_RET_K: + case BPF_S_LD_W_LEN: + case BPF_S_ANC_PROTOCOL: + case BPF_S_ANC_IFINDEX: + case BPF_S_ANC_MARK: + case BPF_S_ANC_RXHASH: + case BPF_S_ANC_CPU: + case BPF_S_ANC_QUEUE: + case BPF_S_LD_W_ABS: + case BPF_S_LD_H_ABS: + case BPF_S_LD_B_ABS: + /* first instruction sets A register (or is RET 'constant') */ + break; + default: + /* make sure we dont leak kernel information to user */ + CLEAR_A(); /* A = 0 */ + } + + for (i = 0; i < flen; i++) { + unsigned int K = filter[i].k; + + switch (filter[i].code) { + case BPF_S_ALU_ADD_X: /* A += X; */ + seen |= SEEN_XREG; + EMIT2(0x01, 0xd8); /* add %ebx,%eax */ + break; + case BPF_S_ALU_ADD_K: /* A += K; */ + if (!K) + break; + if (is_imm8(K)) + EMIT3(0x83, 0xc0, K); /* add imm8,%eax */ + else + EMIT1_off32(0x05, K); /* add imm32,%eax */ + break; + case BPF_S_ALU_SUB_X: /* A -= X; */ + seen |= SEEN_XREG; + EMIT2(0x29, 0xd8); /* sub %ebx,%eax */ + break; + case BPF_S_ALU_SUB_K: /* A -= K */ + if (!K) + break; + if (is_imm8(K)) + EMIT3(0x83, 0xe8, K); /* sub imm8,%eax */ + else + EMIT1_off32(0x2d, K); /* sub imm32,%eax */ + break; + case BPF_S_ALU_MUL_X: /* A *= X; */ + seen |= SEEN_XREG; + EMIT3(0x0f, 0xaf, 0xc3); /* imul %ebx,%eax */ + break; + case BPF_S_ALU_MUL_K: /* A *= K */ + if (is_imm8(K)) + EMIT3(0x6b, 0xc0, K); /* imul imm8,%eax,%eax */ + else { + EMIT2(0x69, 0xc0); /* imul imm32,%eax */ + EMIT(K, 4); + } + break; + case BPF_S_ALU_DIV_X: /* A /= X; */ + seen |= SEEN_XREG; + EMIT2(0x85, 0xdb); /* test %ebx,%ebx */ + if (pc_ret0 != -1) + EMIT_COND_JMP(X86_JE, addrs[pc_ret0] - (addrs[i] - 4)); + else { + EMIT_COND_JMP(X86_JNE, 2 + 5); + CLEAR_A(); + EMIT1_off32(0xe9, cleanup_addr - (addrs[i] - 4)); /* jmp .+off32 */ + } + EMIT4(0x31, 0xd2, 0xf7, 0xf3); /* xor %edx,%edx; div %ebx */ + break; + case BPF_S_ALU_DIV_K: /* A = reciprocal_divide(A, K); */ + EMIT3(0x48, 0x69, 0xc0); /* imul imm32,%rax,%rax */ + EMIT(K, 4); + EMIT4(0x48, 0xc1, 0xe8, 0x20); /* shr $0x20,%rax */ + break; + case BPF_S_ALU_AND_X: + seen |= SEEN_XREG; + EMIT2(0x21, 0xd8); /* and %ebx,%eax */ + break; + case BPF_S_ALU_AND_K: + if (K >= 0xFFFFFF00) { + EMIT2(0x24, K & 0xFF); /* and imm8,%al */ + } else if (K >= 0xFFFF0000) { + EMIT2(0x66, 0x25); /* and imm16,%ax */ + EMIT2(K, 2); + } else { + EMIT1_off32(0x25, K); /* and imm32,%eax */ + } + break; + case BPF_S_ALU_OR_X: + seen |= SEEN_XREG; + EMIT2(0x09, 0xd8); /* or %ebx,%eax */ + break; + case BPF_S_ALU_OR_K: + if (is_imm8(K)) + EMIT3(0x83, 0xc8, K); /* or imm8,%eax */ + else + EMIT1_off32(0x0d, K); /* or imm32,%eax */ + break; + case BPF_S_ALU_LSH_X: /* A <<= X; */ + seen |= SEEN_XREG; + EMIT4(0x89, 0xd9, 0xd3, 0xe0); /* mov %ebx,%ecx; shl %cl,%eax */ + break; + case BPF_S_ALU_LSH_K: + if (K == 0) + break; + else if (K == 1) + EMIT2(0xd1, 0xe0); /* shl %eax */ + else + EMIT3(0xc1, 0xe0, K); + break; + case BPF_S_ALU_RSH_X: /* A >>= X; */ + seen |= SEEN_XREG; + EMIT4(0x89, 0xd9, 0xd3, 0xe8); /* mov %ebx,%ecx; shr %cl,%eax */ + break; + case BPF_S_ALU_RSH_K: /* A >>= K; */ + if (K == 0) + break; + else if (K == 1) + EMIT2(0xd1, 0xe8); /* shr %eax */ + else + EMIT3(0xc1, 0xe8, K); + break; + case BPF_S_ALU_NEG: + EMIT2(0xf7, 0xd8); /* neg %eax */ + break; + case BPF_S_RET_K: + if (!K) { + if (pc_ret0 == -1) + pc_ret0 = i; + CLEAR_A(); + } else { + EMIT1_off32(0xb8, K); /* mov $imm32,%eax */ + } + /* fallinto */ + case BPF_S_RET_A: + if (seen) { + if (i != flen - 1) { + EMIT_JMP(cleanup_addr - addrs[i]); + break; + } + if (seen & SEEN_XREG) + EMIT4(0x48, 0x8b, 0x5d, 0xf8); /* mov -8(%rbp),%rbx */ + EMIT1(0xc9); /* leaveq */ + } + EMIT1(0xc3); /* ret */ + break; + case BPF_S_MISC_TAX: /* X = A */ + seen |= SEEN_XREG; + EMIT2(0x89, 0xc3); /* mov %eax,%ebx */ + break; + case BPF_S_MISC_TXA: /* A = X */ + seen |= SEEN_XREG; + EMIT2(0x89, 0xd8); /* mov %ebx,%eax */ + break; + case BPF_S_LD_IMM: /* A = K */ + if (!K) + CLEAR_A(); + else + EMIT1_off32(0xb8, K); /* mov $imm32,%eax */ + break; + case BPF_S_LDX_IMM: /* X = K */ + seen |= SEEN_XREG; + if (!K) + CLEAR_X(); + else + EMIT1_off32(0xbb, K); /* mov $imm32,%ebx */ + break; + case BPF_S_LD_MEM: /* A = mem[K] : mov off8(%rbp),%eax */ + seen |= SEEN_MEM; + EMIT3(0x8b, 0x45, 0xf0 - K*4); + break; + case BPF_S_LDX_MEM: /* X = mem[K] : mov off8(%rbp),%ebx */ + seen |= SEEN_XREG | SEEN_MEM; + EMIT3(0x8b, 0x5d, 0xf0 - K*4); + break; + case BPF_S_ST: /* mem[K] = A : mov %eax,off8(%rbp) */ + seen |= SEEN_MEM; + EMIT3(0x89, 0x45, 0xf0 - K*4); + break; + case BPF_S_STX: /* mem[K] = X : mov %ebx,off8(%rbp) */ + seen |= SEEN_XREG | SEEN_MEM; + EMIT3(0x89, 0x5d, 0xf0 - K*4); + break; + case BPF_S_LD_W_LEN: /* A = skb->len; */ + BUILD_BUG_ON(FIELD_SIZEOF(struct sk_buff, len) != 4); + if (is_imm8(offsetof(struct sk_buff, len))) + /* mov off8(%rdi),%eax */ + EMIT3(0x8b, 0x47, offsetof(struct sk_buff, len)); + else { + EMIT2(0x8b, 0x87); + EMIT(offsetof(struct sk_buff, len), 4); + } + break; + case BPF_S_LDX_W_LEN: /* X = skb->len; */ + seen |= SEEN_XREG; + if (is_imm8(offsetof(struct sk_buff, len))) + /* mov off8(%rdi),%ebx */ + EMIT3(0x8b, 0x5f, offsetof(struct sk_buff, len)); + else { + EMIT2(0x8b, 0x9f); + EMIT(offsetof(struct sk_buff, len), 4); + } + break; + case BPF_S_ANC_PROTOCOL: /* A = ntohs(skb->protocol); */ + BUILD_BUG_ON(FIELD_SIZEOF(struct sk_buff, protocol) != 2); + if (is_imm8(offsetof(struct sk_buff, protocol))) { + /* movzwl off8(%rdi),%eax */ + EMIT4(0x0f, 0xb7, 0x47, offsetof(struct sk_buff, protocol)); + } else { + EMIT3(0x0f, 0xb7, 0x87); /* movzwl off32(%rdi),%eax */ + EMIT(offsetof(struct sk_buff, protocol), 4); + } + EMIT2(0x86, 0xc4); /* ntohs() : xchg %al,%ah */ + break; + case BPF_S_ANC_IFINDEX: + if (is_imm8(offsetof(struct sk_buff, dev))) { + /* movq off8(%rdi),%rax */ + EMIT4(0x48, 0x8b, 0x47, offsetof(struct sk_buff, dev)); + } else { + EMIT3(0x48, 0x8b, 0x87); /* movq off32(%rdi),%rax */ + EMIT(offsetof(struct sk_buff, dev), 4); + } + EMIT3(0x48, 0x85, 0xc0); /* test %rax,%rax */ + EMIT_COND_JMP(X86_JE, cleanup_addr - (addrs[i] - 6)); + BUILD_BUG_ON(FIELD_SIZEOF(struct net_device, ifindex) != 4); + EMIT2(0x8b, 0x80); /* mov off32(%rax),%eax */ + EMIT(offsetof(struct net_device, ifindex), 4); + break; + case BPF_S_ANC_MARK: + BUILD_BUG_ON(FIELD_SIZEOF(struct sk_buff, mark) != 4); + if (is_imm8(offsetof(struct sk_buff, mark))) { + /* mov off8(%rdi),%eax */ + EMIT3(0x8b, 0x47, offsetof(struct sk_buff, mark)); + } else { + EMIT2(0x8b, 0x87); + EMIT(offsetof(struct sk_buff, mark), 4); + } + break; + case BPF_S_ANC_RXHASH: + BUILD_BUG_ON(FIELD_SIZEOF(struct sk_buff, rxhash) != 4); + if (is_imm8(offsetof(struct sk_buff, rxhash))) { + /* mov off8(%rdi),%eax */ + EMIT3(0x8b, 0x47, offsetof(struct sk_buff, rxhash)); + } else { + EMIT2(0x8b, 0x87); + EMIT(offsetof(struct sk_buff, rxhash), 4); + } + break; + case BPF_S_ANC_QUEUE: + BUILD_BUG_ON(FIELD_SIZEOF(struct sk_buff, queue_mapping) != 2); + if (is_imm8(offsetof(struct sk_buff, queue_mapping))) { + /* movzwl off8(%rdi),%eax */ + EMIT4(0x0f, 0xb7, 0x47, offsetof(struct sk_buff, queue_mapping)); + } else { + EMIT3(0x0f, 0xb7, 0x87); /* movzwl off32(%rdi),%eax */ + EMIT(offsetof(struct sk_buff, queue_mapping), 4); + } + break; + case BPF_S_ANC_CPU: +#ifdef CONFIG_SMP + EMIT4(0x65, 0x8b, 0x04, 0x25); /* mov %gs:off32,%eax */ + EMIT((u32)(unsigned long)&cpu_number, 4); /* A = smp_processor_id(); */ +#else + CLEAR_A(); +#endif + break; + case BPF_S_LD_W_ABS: + func = sk_load_word; +common_load: seen |= SEEN_DATAREF; + if ((int)K < 0) + goto out; + t_offset = func - (image + addrs[i]); + EMIT1_off32(0xbe, K); /* mov imm32,%esi */ + EMIT1_off32(0xe8, t_offset); /* call */ + break; + case BPF_S_LD_H_ABS: + func = sk_load_half; + goto common_load; + case BPF_S_LD_B_ABS: + func = sk_load_byte; + goto common_load; + case BPF_S_LDX_B_MSH: + if ((int)K < 0) { + if (pc_ret0 != -1) { + EMIT_JMP(addrs[pc_ret0] - addrs[i]); + break; + } + CLEAR_A(); + EMIT_JMP(cleanup_addr - addrs[i]); + break; + } + seen |= SEEN_DATAREF | SEEN_XREG; + t_offset = sk_load_byte_msh - (image + addrs[i]); + EMIT1_off32(0xbe, K); /* mov imm32,%esi */ + EMIT1_off32(0xe8, t_offset); /* call sk_load_byte_msh */ + break; + case BPF_S_LD_W_IND: + func = sk_load_word_ind; +common_load_ind: seen |= SEEN_DATAREF | SEEN_XREG; + t_offset = func - (image + addrs[i]); + EMIT1_off32(0xbe, K); /* mov imm32,%esi */ + EMIT1_off32(0xe8, t_offset); /* call sk_load_xxx_ind */ + break; + case BPF_S_LD_H_IND: + func = sk_load_half_ind; + goto common_load_ind; + case BPF_S_LD_B_IND: + func = sk_load_byte_ind; + goto common_load_ind; + case BPF_S_JMP_JA: + t_offset = addrs[i + K] - addrs[i]; + EMIT_JMP(t_offset); + break; + COND_SEL(BPF_S_JMP_JGT_K, X86_JA, X86_JBE); + COND_SEL(BPF_S_JMP_JGE_K, X86_JAE, X86_JB); + COND_SEL(BPF_S_JMP_JEQ_K, X86_JE, X86_JNE); + COND_SEL(BPF_S_JMP_JSET_K,X86_JNE, X86_JE); + COND_SEL(BPF_S_JMP_JGT_X, X86_JA, X86_JBE); + COND_SEL(BPF_S_JMP_JGE_X, X86_JAE, X86_JB); + COND_SEL(BPF_S_JMP_JEQ_X, X86_JE, X86_JNE); + COND_SEL(BPF_S_JMP_JSET_X,X86_JNE, X86_JE); + +cond_branch: f_offset = addrs[i + filter[i].jf] - addrs[i]; + t_offset = addrs[i + filter[i].jt] - addrs[i]; + + /* same targets, can avoid doing the test :) */ + if (filter[i].jt == filter[i].jf) { + EMIT_JMP(t_offset); + break; + } + + switch (filter[i].code) { + case BPF_S_JMP_JGT_X: + case BPF_S_JMP_JGE_X: + case BPF_S_JMP_JEQ_X: + seen |= SEEN_XREG; + EMIT2(0x39, 0xd8); /* cmp %ebx,%eax */ + break; + case BPF_S_JMP_JSET_X: + seen |= SEEN_XREG; + EMIT2(0x85, 0xd8); /* test %ebx,%eax */ + break; + case BPF_S_JMP_JEQ_K: + if (K == 0) { + EMIT2(0x85, 0xc0); /* test %eax,%eax */ + break; + } + case BPF_S_JMP_JGT_K: + case BPF_S_JMP_JGE_K: + if (K <= 127) + EMIT3(0x83, 0xf8, K); /* cmp imm8,%eax */ + else + EMIT1_off32(0x3d, K); /* cmp imm32,%eax */ + break; + case BPF_S_JMP_JSET_K: + if (K <= 0xFF) + EMIT2(0xa8, K); /* test imm8,%al */ + else if (!(K & 0xFFFF00FF)) + EMIT3(0xf6, 0xc4, K >> 8); /* test imm8,%ah */ + else if (K <= 0xFFFF) { + EMIT2(0x66, 0xa9); /* test imm16,%ax */ + EMIT(K, 2); + } else { + EMIT1_off32(0xa9, K); /* test imm32,%eax */ + } + break; + } + if (filter[i].jt != 0) { + if (filter[i].jf) + t_offset += is_near(f_offset) ? 2 : 6; + EMIT_COND_JMP(t_op, t_offset); + if (filter[i].jf) + EMIT_JMP(f_offset); + break; + } + EMIT_COND_JMP(f_op, f_offset); + break; + default: + /* hmm, too complex filter, give up with jit compiler */ + goto out; + } + ilen = prog - temp; + if (image) { + if (unlikely(proglen + ilen > oldproglen)) { + pr_err("bpb_jit_compile fatal error\n"); + kfree(addrs); + module_free(NULL, image); + return; + } + memcpy(image + proglen, temp, ilen); + } + proglen += ilen; + addrs[i] = proglen; + prog = temp; + } + /* last bpf instruction is always a RET : + * use it to give the cleanup instruction(s) addr + */ + cleanup_addr = proglen - 1; /* ret */ + if (seen) + cleanup_addr -= 1; /* leaveq */ + if (seen & SEEN_XREG) + cleanup_addr -= 4; /* mov -8(%rbp),%rbx */ + + if (image) { + WARN_ON(proglen != oldproglen); + break; + } + if (proglen == oldproglen) { + image = module_alloc(max_t(unsigned int, + proglen, + sizeof(struct work_struct))); + if (!image) + goto out; + } + oldproglen = proglen; + } + if (bpf_jit_enable > 1) + pr_err("flen=%d proglen=%u pass=%d image=%p\n", + flen, proglen, pass, image); + + if (image) { + if (bpf_jit_enable > 1) + print_hex_dump(KERN_ERR, "JIT code: ", DUMP_PREFIX_ADDRESS, + 16, 1, image, proglen, false); + + bpf_flush_icache(image, image + proglen); + + fp->bpf_func = (void *)image; + } +out: + kfree(addrs); + return; +} + +static void jit_free_defer(struct work_struct *arg) +{ + module_free(NULL, arg); +} + +/* run from softirq, we must use a work_struct to call + * module_free() from process context + */ +void bpf_jit_free(struct sk_filter *fp) +{ + if (fp->bpf_func != sk_run_filter) { + struct work_struct *work = (struct work_struct *)fp->bpf_func; + + INIT_WORK(work, jit_free_defer); + schedule_work(work); + } +} diff --git a/include/linux/filter.h b/include/linux/filter.h index 45266b7..4609b85 100644 --- a/include/linux/filter.h +++ b/include/linux/filter.h @@ -135,6 +135,8 @@ struct sk_filter { atomic_t refcnt; unsigned int len; /* Number of filter blocks */ + unsigned int (*bpf_func)(const struct sk_buff *skb, + const struct sock_filter *filter); struct rcu_head rcu; struct sock_filter insns[0]; }; @@ -153,6 +155,80 @@ extern unsigned int sk_run_filter(const struct sk_buff *skb, extern int sk_attach_filter(struct sock_fprog *fprog, struct sock *sk); extern int sk_detach_filter(struct sock *sk); extern int sk_chk_filter(struct sock_filter *filter, int flen); + +#ifdef CONFIG_BPF_JIT +extern void bpf_jit_compile(struct sk_filter *fp); +extern void bpf_jit_free(struct sk_filter *fp); +#define SK_RUN_FILTER(FILTER, SKB) (*FILTER->bpf_func)(SKB, FILTER->insns) +#else +static inline void bpf_jit_compile(struct sk_filter *fp) +{ +} +static inline void bpf_jit_free(struct sk_filter *fp) +{ +} +#define SK_RUN_FILTER(FILTER, SKB) sk_run_filter(SKB, FILTER->insns) +#endif + +enum { + BPF_S_RET_K = 1, + BPF_S_RET_A, + BPF_S_ALU_ADD_K, + BPF_S_ALU_ADD_X, + BPF_S_ALU_SUB_K, + BPF_S_ALU_SUB_X, + BPF_S_ALU_MUL_K, + BPF_S_ALU_MUL_X, + BPF_S_ALU_DIV_X, + BPF_S_ALU_AND_K, + BPF_S_ALU_AND_X, + BPF_S_ALU_OR_K, + BPF_S_ALU_OR_X, + BPF_S_ALU_LSH_K, + BPF_S_ALU_LSH_X, + BPF_S_ALU_RSH_K, + BPF_S_ALU_RSH_X, + BPF_S_ALU_NEG, + BPF_S_LD_W_ABS, + BPF_S_LD_H_ABS, + BPF_S_LD_B_ABS, + BPF_S_LD_W_LEN, + BPF_S_LD_W_IND, + BPF_S_LD_H_IND, + BPF_S_LD_B_IND, + BPF_S_LD_IMM, + BPF_S_LDX_W_LEN, + BPF_S_LDX_B_MSH, + BPF_S_LDX_IMM, + BPF_S_MISC_TAX, + BPF_S_MISC_TXA, + BPF_S_ALU_DIV_K, + BPF_S_LD_MEM, + BPF_S_LDX_MEM, + BPF_S_ST, + BPF_S_STX, + BPF_S_JMP_JA, + BPF_S_JMP_JEQ_K, + BPF_S_JMP_JEQ_X, + BPF_S_JMP_JGE_K, + BPF_S_JMP_JGE_X, + BPF_S_JMP_JGT_K, + BPF_S_JMP_JGT_X, + BPF_S_JMP_JSET_K, + BPF_S_JMP_JSET_X, + /* Ancillary data */ + BPF_S_ANC_PROTOCOL, + BPF_S_ANC_PKTTYPE, + BPF_S_ANC_IFINDEX, + BPF_S_ANC_NLATTR, + BPF_S_ANC_NLATTR_NEST, + BPF_S_ANC_MARK, + BPF_S_ANC_QUEUE, + BPF_S_ANC_HATYPE, + BPF_S_ANC_RXHASH, + BPF_S_ANC_CPU, +}; + #endif /* __KERNEL__ */ #endif /* __LINUX_FILTER_H__ */ diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index cb8178a..364bcf2 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -2514,6 +2514,7 @@ extern struct rtnl_link_stats64 *dev_get_stats(struct net_device *dev, extern int netdev_max_backlog; extern int netdev_tstamp_prequeue; extern int weight_p; +extern int bpf_jit_enable; extern int netdev_set_master(struct net_device *dev, struct net_device *master); extern int netdev_set_bond_master(struct net_device *dev, struct net_device *master); diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h index d0ae90a..79aafbb 100644 --- a/include/linux/skbuff.h +++ b/include/linux/skbuff.h @@ -391,8 +391,8 @@ struct sk_buff { __u32 rxhash; + __u16 queue_mapping; kmemcheck_bitfield_begin(flags2); - __u16 queue_mapping:16; #ifdef CONFIG_IPV6_NDISC_NODETYPE __u8 ndisc_nodetype:2; #endif diff --git a/net/Kconfig b/net/Kconfig index 79cabf1..745fb02 100644 --- a/net/Kconfig +++ b/net/Kconfig @@ -232,6 +232,19 @@ config XPS depends on SMP && SYSFS && USE_GENERIC_SMP_HELPERS default y +config HAVE_BPF_JIT + bool + +config BPF_JIT + bool "enable BPF Just In Time compiler" + depends on HAVE_BPF_JIT + ---help--- + Berkeley Packet Filter filtering capabilities are normally handled + by an interpreter. This option allows kernel to generate a native + code when filter is loaded in memory. This should speedup + packet sniffing (libpcap/tcpdump). Note : Admin should enable + this feature changing /proc/sys/net/core/bpf_jit_enable + menu "Network testing" config NET_PKTGEN diff --git a/net/core/filter.c b/net/core/filter.c index afb8afb..0eb8c44 100644 --- a/net/core/filter.c +++ b/net/core/filter.c @@ -39,65 +39,6 @@ #include #include -enum { - BPF_S_RET_K = 1, - BPF_S_RET_A, - BPF_S_ALU_ADD_K, - BPF_S_ALU_ADD_X, - BPF_S_ALU_SUB_K, - BPF_S_ALU_SUB_X, - BPF_S_ALU_MUL_K, - BPF_S_ALU_MUL_X, - BPF_S_ALU_DIV_X, - BPF_S_ALU_AND_K, - BPF_S_ALU_AND_X, - BPF_S_ALU_OR_K, - BPF_S_ALU_OR_X, - BPF_S_ALU_LSH_K, - BPF_S_ALU_LSH_X, - BPF_S_ALU_RSH_K, - BPF_S_ALU_RSH_X, - BPF_S_ALU_NEG, - BPF_S_LD_W_ABS, - BPF_S_LD_H_ABS, - BPF_S_LD_B_ABS, - BPF_S_LD_W_LEN, - BPF_S_LD_W_IND, - BPF_S_LD_H_IND, - BPF_S_LD_B_IND, - BPF_S_LD_IMM, - BPF_S_LDX_W_LEN, - BPF_S_LDX_B_MSH, - BPF_S_LDX_IMM, - BPF_S_MISC_TAX, - BPF_S_MISC_TXA, - BPF_S_ALU_DIV_K, - BPF_S_LD_MEM, - BPF_S_LDX_MEM, - BPF_S_ST, - BPF_S_STX, - BPF_S_JMP_JA, - BPF_S_JMP_JEQ_K, - BPF_S_JMP_JEQ_X, - BPF_S_JMP_JGE_K, - BPF_S_JMP_JGE_X, - BPF_S_JMP_JGT_K, - BPF_S_JMP_JGT_X, - BPF_S_JMP_JSET_K, - BPF_S_JMP_JSET_X, - /* Ancillary data */ - BPF_S_ANC_PROTOCOL, - BPF_S_ANC_PKTTYPE, - BPF_S_ANC_IFINDEX, - BPF_S_ANC_NLATTR, - BPF_S_ANC_NLATTR_NEST, - BPF_S_ANC_MARK, - BPF_S_ANC_QUEUE, - BPF_S_ANC_HATYPE, - BPF_S_ANC_RXHASH, - BPF_S_ANC_CPU, -}; - /* No hurry in this branch */ static void *__load_pointer(const struct sk_buff *skb, int k, unsigned int size) { @@ -145,7 +86,7 @@ int sk_filter(struct sock *sk, struct sk_buff *skb) rcu_read_lock(); filter = rcu_dereference(sk->sk_filter); if (filter) { - unsigned int pkt_len = sk_run_filter(skb, filter->insns); + unsigned int pkt_len = SK_RUN_FILTER(filter, skb); err = pkt_len ? pskb_trim(skb, pkt_len) : -EPERM; } @@ -638,6 +579,7 @@ void sk_filter_release_rcu(struct rcu_head *rcu) { struct sk_filter *fp = container_of(rcu, struct sk_filter, rcu); + bpf_jit_free(fp); kfree(fp); } EXPORT_SYMBOL(sk_filter_release_rcu); @@ -672,6 +614,7 @@ int sk_attach_filter(struct sock_fprog *fprog, struct sock *sk) atomic_set(&fp->refcnt, 1); fp->len = fprog->len; + fp->bpf_func = sk_run_filter; err = sk_chk_filter(fp->insns, fp->len); if (err) { @@ -679,6 +622,8 @@ int sk_attach_filter(struct sock_fprog *fprog, struct sock *sk) return err; } + bpf_jit_compile(fp); + old_fp = rcu_dereference_protected(sk->sk_filter, sock_owned_by_user(sk)); rcu_assign_pointer(sk->sk_filter, fp); diff --git a/net/core/sysctl_net_core.c b/net/core/sysctl_net_core.c index 385b609..a829e3f 100644 --- a/net/core/sysctl_net_core.c +++ b/net/core/sysctl_net_core.c @@ -122,6 +122,15 @@ static struct ctl_table net_core_table[] = { .mode = 0644, .proc_handler = proc_dointvec }, +#ifdef CONFIG_BPF_JIT + { + .procname = "bpf_jit_enable", + .data = &bpf_jit_enable, + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = proc_dointvec + }, +#endif { .procname = "netdev_tstamp_prequeue", .data = &netdev_tstamp_prequeue, diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c index b5362e9..549527b 100644 --- a/net/packet/af_packet.c +++ b/net/packet/af_packet.c @@ -538,7 +538,7 @@ static inline unsigned int run_filter(const struct sk_buff *skb, rcu_read_lock(); filter = rcu_dereference(sk->sk_filter); if (filter != NULL) - res = sk_run_filter(skb, filter->insns); + res = SK_RUN_FILTER(filter, skb); rcu_read_unlock(); return res; -- cgit v0.10.2 From f5346668150c37094b42cc2d07ec5fd1451eb980 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Wed, 27 Apr 2011 23:08:34 -0700 Subject: Input: wm831x-ts - fix races with IRQ management If the WM831x pen down and data IRQs run in parallel it is possible for the data and pen down IRQs to deadlock themselves as one is part way through disabling its operation while the other is part way through enabling. Fix this by always disabling the pen down interrupt while data is active and vice versa. When a changeover is required we disable the IRQ that is to be stopped then schedule work that will enable the new IRQ. We need to handle the data flow in the data IRQ as the readback from the device needs to be ordered correctly with the IRQ for robust operation. This also fixes an issue when using the built in IRQs due to enable_irq() not being valid from interrupt context on an interrupt controller with bus operations like the built in IRQ controller - this issue may also have affected other interrupt controllers. We can't rely on having the data and pen down IRQs available via GPIOs on the CPU on every system. Signed-off-by: Mark Brown Signed-off-by: Dmitry Torokhov diff --git a/drivers/input/touchscreen/wm831x-ts.c b/drivers/input/touchscreen/wm831x-ts.c index 6ae054f..b937301 100644 --- a/drivers/input/touchscreen/wm831x-ts.c +++ b/drivers/input/touchscreen/wm831x-ts.c @@ -68,8 +68,23 @@ struct wm831x_ts { unsigned int pd_irq; bool pressure; bool pen_down; + struct work_struct pd_data_work; }; +static void wm831x_pd_data_work(struct work_struct *work) +{ + struct wm831x_ts *wm831x_ts = + container_of(work, struct wm831x_ts, pd_data_work); + + if (wm831x_ts->pen_down) { + enable_irq(wm831x_ts->data_irq); + dev_dbg(wm831x_ts->wm831x->dev, "IRQ PD->DATA done\n"); + } else { + enable_irq(wm831x_ts->pd_irq); + dev_dbg(wm831x_ts->wm831x->dev, "IRQ DATA->PD done\n"); + } +} + static irqreturn_t wm831x_ts_data_irq(int irq, void *irq_data) { struct wm831x_ts *wm831x_ts = irq_data; @@ -110,6 +125,9 @@ static irqreturn_t wm831x_ts_data_irq(int irq, void *irq_data) } if (!wm831x_ts->pen_down) { + /* Switch from data to pen down */ + dev_dbg(wm831x->dev, "IRQ DATA->PD\n"); + disable_irq_nosync(wm831x_ts->data_irq); /* Don't need data any more */ @@ -128,6 +146,8 @@ static irqreturn_t wm831x_ts_data_irq(int irq, void *irq_data) ABS_PRESSURE, 0); input_report_key(wm831x_ts->input_dev, BTN_TOUCH, 0); + + schedule_work(&wm831x_ts->pd_data_work); } input_sync(wm831x_ts->input_dev); @@ -141,6 +161,11 @@ static irqreturn_t wm831x_ts_pen_down_irq(int irq, void *irq_data) struct wm831x *wm831x = wm831x_ts->wm831x; int ena = 0; + if (wm831x_ts->pen_down) + return IRQ_HANDLED; + + disable_irq_nosync(wm831x_ts->pd_irq); + /* Start collecting data */ if (wm831x_ts->pressure) ena |= WM831X_TCH_Z_ENA; @@ -156,7 +181,10 @@ static irqreturn_t wm831x_ts_pen_down_irq(int irq, void *irq_data) WM831X_TCHPD_EINT, WM831X_TCHPD_EINT); wm831x_ts->pen_down = true; - enable_irq(wm831x_ts->data_irq); + + /* Switch from pen down to data */ + dev_dbg(wm831x->dev, "IRQ PD->DATA\n"); + schedule_work(&wm831x_ts->pd_data_work); return IRQ_HANDLED; } @@ -182,13 +210,28 @@ static void wm831x_ts_input_close(struct input_dev *idev) struct wm831x_ts *wm831x_ts = input_get_drvdata(idev); struct wm831x *wm831x = wm831x_ts->wm831x; + /* Shut the controller down, disabling all other functionality too */ wm831x_set_bits(wm831x, WM831X_TOUCH_CONTROL_1, - WM831X_TCH_ENA | WM831X_TCH_CVT_ENA | - WM831X_TCH_X_ENA | WM831X_TCH_Y_ENA | - WM831X_TCH_Z_ENA, 0); + WM831X_TCH_ENA | WM831X_TCH_X_ENA | + WM831X_TCH_Y_ENA | WM831X_TCH_Z_ENA, 0); - if (wm831x_ts->pen_down) + /* Make sure any pending IRQs are done, the above will prevent + * new ones firing. + */ + synchronize_irq(wm831x_ts->data_irq); + synchronize_irq(wm831x_ts->pd_irq); + + /* Make sure the IRQ completion work is quiesced */ + flush_work_sync(&wm831x_ts->pd_data_work); + + /* If we ended up with the pen down then make sure we revert back + * to pen detection state for the next time we start up. + */ + if (wm831x_ts->pen_down) { disable_irq(wm831x_ts->data_irq); + enable_irq(wm831x_ts->pd_irq); + wm831x_ts->pen_down = false; + } } static __devinit int wm831x_ts_probe(struct platform_device *pdev) @@ -212,6 +255,7 @@ static __devinit int wm831x_ts_probe(struct platform_device *pdev) wm831x_ts->wm831x = wm831x; wm831x_ts->input_dev = input_dev; + INIT_WORK(&wm831x_ts->pd_data_work, wm831x_pd_data_work); /* * If we have a direct IRQ use it, otherwise use the interrupt -- cgit v0.10.2 From acad9853b95df6a3887f52e0ec88e4a77119ee28 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Wed, 27 Apr 2011 23:08:51 -0700 Subject: Input: wm831x-ts - allow IRQ flags to be specified This allows maximum flexibility for configuring the direct GPIO based interrupts. Signed-off-by: Mark Brown Signed-off-by: Dmitry Torokhov diff --git a/drivers/input/touchscreen/wm831x-ts.c b/drivers/input/touchscreen/wm831x-ts.c index b937301..78e8705 100644 --- a/drivers/input/touchscreen/wm831x-ts.c +++ b/drivers/input/touchscreen/wm831x-ts.c @@ -241,7 +241,7 @@ static __devinit int wm831x_ts_probe(struct platform_device *pdev) struct wm831x_pdata *core_pdata = dev_get_platdata(pdev->dev.parent); struct wm831x_touch_pdata *pdata = NULL; struct input_dev *input_dev; - int error; + int error, irqf; if (core_pdata) pdata = core_pdata->touch; @@ -314,9 +314,14 @@ static __devinit int wm831x_ts_probe(struct platform_device *pdev) wm831x_set_bits(wm831x, WM831X_TOUCH_CONTROL_1, WM831X_TCH_RATE_MASK, 6); + if (pdata && pdata->data_irqf) + irqf = pdata->data_irqf; + else + irqf = IRQF_TRIGGER_HIGH; + error = request_threaded_irq(wm831x_ts->data_irq, NULL, wm831x_ts_data_irq, - IRQF_ONESHOT, + irqf | IRQF_ONESHOT, "Touchscreen data", wm831x_ts); if (error) { dev_err(&pdev->dev, "Failed to request data IRQ %d: %d\n", @@ -325,9 +330,14 @@ static __devinit int wm831x_ts_probe(struct platform_device *pdev) } disable_irq(wm831x_ts->data_irq); + if (pdata && pdata->pd_irqf) + irqf = pdata->pd_irqf; + else + irqf = IRQF_TRIGGER_HIGH; + error = request_threaded_irq(wm831x_ts->pd_irq, NULL, wm831x_ts_pen_down_irq, - IRQF_ONESHOT, + irqf | IRQF_ONESHOT, "Touchscreen pen down", wm831x_ts); if (error) { dev_err(&pdev->dev, "Failed to request pen down IRQ %d: %d\n", diff --git a/include/linux/mfd/wm831x/pdata.h b/include/linux/mfd/wm831x/pdata.h index 173086d..6b0eb13 100644 --- a/include/linux/mfd/wm831x/pdata.h +++ b/include/linux/mfd/wm831x/pdata.h @@ -81,7 +81,9 @@ struct wm831x_touch_pdata { int rpu; /** Pen down sensitivity resistor divider */ int pressure; /** Report pressure (boolean) */ unsigned int data_irq; /** Touch data ready IRQ */ + int data_irqf; /** IRQ flags for data ready IRQ */ unsigned int pd_irq; /** Touch pendown detect IRQ */ + int pd_irqf; /** IRQ flags for pen down IRQ */ }; enum wm831x_watchdog_action { -- cgit v0.10.2 From bf283707d5fb174ec09215ae19860ad04ba7b67a Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Wed, 27 Apr 2011 23:09:26 -0700 Subject: Input: wm831x-ts - move BTN_TOUCH reporting to data transfer Don't report BTN_TOUCH until we've got data as some less robust applications can be confused by getting a touch event by itself and it doesn't seem unreasonable for them to expect coordinates along with a touch. Signed-off-by: Mark Brown Signed-off-by: Dmitry Torokhov diff --git a/drivers/input/touchscreen/wm831x-ts.c b/drivers/input/touchscreen/wm831x-ts.c index 78e8705..9175d49 100644 --- a/drivers/input/touchscreen/wm831x-ts.c +++ b/drivers/input/touchscreen/wm831x-ts.c @@ -148,6 +148,8 @@ static irqreturn_t wm831x_ts_data_irq(int irq, void *irq_data) input_report_key(wm831x_ts->input_dev, BTN_TOUCH, 0); schedule_work(&wm831x_ts->pd_data_work); + } else { + input_report_key(wm831x_ts->input_dev, BTN_TOUCH, 1); } input_sync(wm831x_ts->input_dev); @@ -174,9 +176,6 @@ static irqreturn_t wm831x_ts_pen_down_irq(int irq, void *irq_data) WM831X_TCH_X_ENA | WM831X_TCH_Y_ENA | WM831X_TCH_Z_ENA, WM831X_TCH_X_ENA | WM831X_TCH_Y_ENA | ena); - input_report_key(wm831x_ts->input_dev, BTN_TOUCH, 1); - input_sync(wm831x_ts->input_dev); - wm831x_set_bits(wm831x, WM831X_INTERRUPT_STATUS_1, WM831X_TCHPD_EINT, WM831X_TCHPD_EINT); -- cgit v0.10.2 From 8a850cadca0e387c87a0911a61e99fd66aeb57ec Mon Sep 17 00:00:00 2001 From: Ingo Molnar Date: Thu, 28 Apr 2011 11:16:44 +0200 Subject: perf event, x86: Use better stalled cycles metric Use the UOPS_EXECUTED.*,c=1,i=1 event on Intel CPUs - it is a rather good indicator of CPU execution stalls, more sensitive and more inclusive than the 0xa2 resource stalls event (which does not count nearly as many stall types). Cc: Peter Zijlstra Cc: Arnaldo Carvalho de Melo Cc: Frederic Weisbecker Link: http://lkml.kernel.org/n/tip-7y40wib8n1eqio7hjpn2dsrm@git.kernel.org Signed-off-by: Ingo Molnar diff --git a/arch/x86/kernel/cpu/perf_event_intel.c b/arch/x86/kernel/cpu/perf_event_intel.c index 067a48b..1ea9422 100644 --- a/arch/x86/kernel/cpu/perf_event_intel.c +++ b/arch/x86/kernel/cpu/perf_event_intel.c @@ -1413,8 +1413,8 @@ static __init int intel_pmu_init(void) x86_pmu.enable_all = intel_pmu_nhm_enable_all; x86_pmu.extra_regs = intel_nehalem_extra_regs; - /* Install the stalled-cycles event: 0xff: All reasons, 0xa2: Resource stalls */ - intel_perfmon_event_map[PERF_COUNT_HW_STALLED_CYCLES] = 0xffa2; + /* Install the stalled-cycles event: UOPS_EXECUTED.CORE_ACTIVE_CYCLES,c=1,i=1 */ + intel_perfmon_event_map[PERF_COUNT_HW_STALLED_CYCLES] = 0x1803fb1; if (ebx & 0x40) { /* -- cgit v0.10.2 From f9cef0a90c4e7637f1ec98474a1a099aec45eb65 Mon Sep 17 00:00:00 2001 From: Ingo Molnar Date: Thu, 28 Apr 2011 18:17:11 +0200 Subject: perf stat: Add --sync/-S option --sync will tell perf stat to run sync() before starting a command. This allows IO-heavy tests to be used with --repeat, without one iteration impacting the other. Elapsed time will stabilize for example: before: 3.971525714 seconds time elapsed ( +- 8.56% ) after: 3.211098537 seconds time elapsed ( +- 1.52% ) So measurements will be more accurate. Cc: Peter Zijlstra Cc: Arnaldo Carvalho de Melo Cc: Frederic Weisbecker Link: http://lkml.kernel.org/n/tip-7y40wib8n1eqio7hjpn1dsrm@git.kernel.org Signed-off-by: Ingo Molnar diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c index 003caa8..5658a77 100644 --- a/tools/perf/builtin-stat.c +++ b/tools/perf/builtin-stat.c @@ -128,6 +128,7 @@ static pid_t target_tid = -1; static pid_t child_pid = -1; static bool null_run = false; static bool detailed_run = false; +static bool sync_run = false; static bool big_num = true; static int big_num_opt = -1; static const char *cpu_list; @@ -819,6 +820,8 @@ static const struct option options[] = { "null run - dont start any counters"), OPT_BOOLEAN('d', "detailed", &detailed_run, "detailed run - start a lot of events"), + OPT_BOOLEAN('S', "sync", &sync_run, + "call sync() before starting a run"), OPT_CALLBACK_NOOPT('B', "big-num", NULL, NULL, "print large numbers with thousands\' separators", stat__set_big_num), @@ -944,6 +947,10 @@ int cmd_stat(int argc, const char **argv, const char *prefix __used) for (run_idx = 0; run_idx < run_count; run_idx++) { if (run_count != 1 && verbose) fprintf(stderr, "[ perf stat: executing run #%d ... ]\n", run_idx + 1); + + if (sync_run) + sync(); + status = run_perf_stat(argc, argv); } -- cgit v0.10.2 From ede70290046043b2638204cab55e26ea1d0c6cd9 Mon Sep 17 00:00:00 2001 From: Ingo Molnar Date: Thu, 28 Apr 2011 08:48:42 +0200 Subject: perf stat: Fix compatibility behavior Instead of failing on an unknown event, when new perf stat is run on older kernels: $ ./perf stat true Error: open_counter returned with 22 (Invalid argument). /bin/dmesg may provide additional information. Fatal: Not all events could be opened. Just ignore EINVAL and ENOSYS, we'll print the results as not counted: Performance counter stats for 'true': 0.239483 task-clock # 0.493 CPUs utilized 0 context-switches # 0.000 M/sec 0 CPU-migrations # 0.000 M/sec 86 page-faults # 0.359 M/sec 704,766 cycles # 2.943 GHz stalled-cycles 381,961 instructions # 0.54 insns per cycle 69,626 branches # 290.735 M/sec 4,594 branch-misses # 6.60% of all branches 0.000485883 seconds time elapsed Cc: Peter Zijlstra Cc: Arnaldo Carvalho de Melo Cc: Frederic Weisbecker Link: http://lkml.kernel.org/n/tip-7y40wib8n1eqio5hjpn3dsrm@git.kernel.org Signed-off-by: Ingo Molnar diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c index 5658a77..da77077 100644 --- a/tools/perf/builtin-stat.c +++ b/tools/perf/builtin-stat.c @@ -372,7 +372,10 @@ static int run_perf_stat(int argc __used, const char **argv) list_for_each_entry(counter, &evsel_list->entries, node) { if (create_perf_stat_counter(counter) < 0) { - if (errno == -EPERM || errno == -EACCES) { + if (errno == EINVAL || errno == ENOSYS) + continue; + + if (errno == EPERM || errno == EACCES) { error("You may not have permission to collect %sstats.\n" "\t Consider tweaking" " /proc/sys/kernel/perf_event_paranoid or running as root.", -- cgit v0.10.2 From e11feaa1192a079ba8e88a12121e9b12d55d4239 Mon Sep 17 00:00:00 2001 From: Jeff Mahoney Date: Wed, 27 Apr 2011 14:27:24 -0400 Subject: watchdog, hung_task_timeout: Add Kconfig configurable default This patch allows the default value for sysctl_hung_task_timeout_secs to be set at build time. The feature carries virtually no overhead, so it makes sense to keep it enabled. On heavily loaded systems, though, it can end up triggering stack traces when there is no bug other than the system being underprovisioned. We use this patch to keep the hung task facility available but disabled at boot-time. The default of 120 seconds is preserved. As a note, commit e162b39a may have accidentally reverted commit fb822db4, which raised the default from 120 seconds to 480 seconds. Signed-off-by: Jeff Mahoney Acked-by: Mandeep Singh Baines Link: http://lkml.kernel.org/r/4DB8600C.8080000@suse.com Signed-off-by: Ingo Molnar diff --git a/kernel/hung_task.c b/kernel/hung_task.c index 53ead17..ea64012 100644 --- a/kernel/hung_task.c +++ b/kernel/hung_task.c @@ -33,7 +33,7 @@ unsigned long __read_mostly sysctl_hung_task_check_count = PID_MAX_LIMIT; /* * Zero means infinite timeout - no checking done: */ -unsigned long __read_mostly sysctl_hung_task_timeout_secs = 120; +unsigned long __read_mostly sysctl_hung_task_timeout_secs = CONFIG_DEFAULT_HUNG_TASK_TIMEOUT; unsigned long __read_mostly sysctl_hung_task_warnings = 10; diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug index c768bcd..debbb05 100644 --- a/lib/Kconfig.debug +++ b/lib/Kconfig.debug @@ -238,6 +238,21 @@ config DETECT_HUNG_TASK enabled then all held locks will also be reported. This feature has negligible overhead. +config DEFAULT_HUNG_TASK_TIMEOUT + int "Default timeout for hung task detection (in seconds)" + depends on DETECT_HUNG_TASK + default 120 + help + This option controls the default timeout (in seconds) used + to determine when a task has become non-responsive and should + be considered hung. + + It can be adjusted at runtime via the kernel.hung_task_timeout + sysctl or by writing a value to /proc/sys/kernel/hung_task_timeout. + + A timeout of 0 disables the check. The default is two minutes. + Keeping the default should be fine in most cases. + config BOOTPARAM_HUNG_TASK_PANIC bool "Panic (Reboot) On Hung Tasks" depends on DETECT_HUNG_TASK -- cgit v0.10.2 From f945a3d9600633de589ce698233b34ff6ad57e55 Mon Sep 17 00:00:00 2001 From: Zhangfei Gao Date: Wed, 27 Apr 2011 11:44:29 -0700 Subject: rtc: max8925: Call dev_set_drvdata before rtc_device_register We call rtc_read_alarm from rtc_device_register, so it is important that the rtc device is fully initialized prior to registration. rtc-max8925 sets drvdata after register, so the rtc_read_alarm code dereferences a NULL pointer. Call dev_set_drvdata before rtc_device_register. [ jstultz/tglx: Massaged commit message ] Signed-off-by: Zhangfei Gao Cc: Alessandro Zummo Link: http://lkml.kernel.org/r/%3C1303929869-25249-1-git-send-email-john.stultz%40linaro.org%3E Signed-off-by: John Stultz Signed-off-by: Thomas Gleixner diff --git a/drivers/rtc/rtc-max8925.c b/drivers/rtc/rtc-max8925.c index 174036d..20494b5 100644 --- a/drivers/rtc/rtc-max8925.c +++ b/drivers/rtc/rtc-max8925.c @@ -257,6 +257,8 @@ static int __devinit max8925_rtc_probe(struct platform_device *pdev) goto out_irq; } + dev_set_drvdata(&pdev->dev, info); + info->rtc_dev = rtc_device_register("max8925-rtc", &pdev->dev, &max8925_rtc_ops, THIS_MODULE); ret = PTR_ERR(info->rtc_dev); @@ -265,7 +267,6 @@ static int __devinit max8925_rtc_probe(struct platform_device *pdev) goto out_rtc; } - dev_set_drvdata(&pdev->dev, info); platform_set_drvdata(pdev, info); return 0; -- cgit v0.10.2 From 525566cb60e167ca1cd770f3d0738735ec3503bb Mon Sep 17 00:00:00 2001 From: Lydia Wang Date: Thu, 28 Apr 2011 16:03:39 +0800 Subject: ALSA: hda - VIA: Fix notify_aa_path_ctls() invalid issue. In notify_aa_path_ctls(), adds 'rear mic' item and confirms the A-A path control existing before notifying card that the A-A path volume is muted if smart5.1 is enabled. Signed-off-by: Lydia Wang Signed-off-by: Takashi Iwai diff --git a/sound/pci/hda/patch_via.c b/sound/pci/hda/patch_via.c index 1371b57c..0997031 100644 --- a/sound/pci/hda/patch_via.c +++ b/sound/pci/hda/patch_via.c @@ -1292,14 +1292,18 @@ static void notify_aa_path_ctls(struct hda_codec *codec) { int i; struct snd_ctl_elem_id id; - const char *labels[] = {"Mic", "Front Mic", "Line"}; + const char *labels[] = {"Mic", "Front Mic", "Line", "Rear Mic"}; + struct snd_kcontrol *ctl; memset(&id, 0, sizeof(id)); id.iface = SNDRV_CTL_ELEM_IFACE_MIXER; for (i = 0; i < ARRAY_SIZE(labels); i++) { sprintf(id.name, "%s Playback Volume", labels[i]); - snd_ctl_notify(codec->bus->card, SNDRV_CTL_EVENT_MASK_VALUE, - &id); + ctl = snd_hda_find_mixer_ctl(codec, id.name); + if (ctl) + snd_ctl_notify(codec->bus->card, + SNDRV_CTL_EVENT_MASK_VALUE, + &ctl->id); } } -- cgit v0.10.2 From 20443598d9bdfe3563f901e27fd482a3f5d3d231 Mon Sep 17 00:00:00 2001 From: Sebastian Andrzej Siewior Date: Wed, 27 Apr 2011 16:30:52 +0200 Subject: x86: devicetree: Configure IOAPIC pin only once We use io_apic_setup_irq_pin() in order to configure pin's interrupt number polarity and type. This is done on every irq_create_of_mapping() which happens for instance during pci enable calls. Level typed interrupts are masked by default, edge are unmasked. On the first ->xlate() call the level interrupt is configured and masked. The driver calls request_irq() and the line is unmasked. Lets assume the interrupt line is shared with another device and we call pci_enable_device() for this device. The ->xlate() configures the pin again and it is masked. request_irq() does not unmask the line because it _is_ already unmasked according to its internal state. So the interrupt will never be unmasked again. This patch is based on an earlier work by Torben Hohn and solves the problem by configuring the pin only once. Since all devices must agree on the same type and polarity there is no point in configuring the pin more than once. [ tglx: Split out the ce4100 part into a separate patch ] Cc: Torben Hohn Signed-off-by: Sebastian Andrzej Siewior Link: http://lkml.kernel.org/r/%3C20110427143052.GA15211%40linutronix.de%3E Signed-off-by: Thomas Gleixner diff --git a/arch/x86/include/asm/io_apic.h b/arch/x86/include/asm/io_apic.h index c4bd267..a97a240 100644 --- a/arch/x86/include/asm/io_apic.h +++ b/arch/x86/include/asm/io_apic.h @@ -150,7 +150,7 @@ void setup_IO_APIC_irq_extra(u32 gsi); extern void ioapic_and_gsi_init(void); extern void ioapic_insert_resources(void); -int io_apic_setup_irq_pin(unsigned int irq, int node, struct io_apic_irq_attr *attr); +int io_apic_setup_irq_pin_once(unsigned int irq, int node, struct io_apic_irq_attr *attr); extern struct IO_APIC_route_entry **alloc_ioapic_entries(void); extern void free_ioapic_entries(struct IO_APIC_route_entry **ioapic_entries); diff --git a/arch/x86/kernel/apic/io_apic.c b/arch/x86/kernel/apic/io_apic.c index 68df09b..45fd33d 100644 --- a/arch/x86/kernel/apic/io_apic.c +++ b/arch/x86/kernel/apic/io_apic.c @@ -128,8 +128,8 @@ static int __init parse_noapic(char *str) } early_param("noapic", parse_noapic); -static int io_apic_setup_irq_pin_once(unsigned int irq, int node, - struct io_apic_irq_attr *attr); +static int io_apic_setup_irq_pin(unsigned int irq, int node, + struct io_apic_irq_attr *attr); /* Will be called in mpparse/acpi/sfi codes for saving IRQ info */ void mp_save_irq(struct mpc_intsrc *m) @@ -3570,7 +3570,7 @@ int arch_setup_ht_irq(unsigned int irq, struct pci_dev *dev) } #endif /* CONFIG_HT_IRQ */ -int +static int io_apic_setup_irq_pin(unsigned int irq, int node, struct io_apic_irq_attr *attr) { struct irq_cfg *cfg = alloc_irq_and_cfg_at(irq, node); @@ -3585,8 +3585,8 @@ io_apic_setup_irq_pin(unsigned int irq, int node, struct io_apic_irq_attr *attr) return ret; } -static int io_apic_setup_irq_pin_once(unsigned int irq, int node, - struct io_apic_irq_attr *attr) +int io_apic_setup_irq_pin_once(unsigned int irq, int node, + struct io_apic_irq_attr *attr) { unsigned int id = attr->ioapic, pin = attr->ioapic_pin; int ret; diff --git a/arch/x86/kernel/devicetree.c b/arch/x86/kernel/devicetree.c index 706a9fb..e90f084 100644 --- a/arch/x86/kernel/devicetree.c +++ b/arch/x86/kernel/devicetree.c @@ -391,7 +391,7 @@ static int ioapic_xlate(struct irq_domain *id, const u32 *intspec, u32 intsize, set_io_apic_irq_attr(&attr, idx, line, it->trigger, it->polarity); - return io_apic_setup_irq_pin(*out_hwirq, cpu_to_node(0), &attr); + return io_apic_setup_irq_pin_once(*out_hwirq, cpu_to_node(0), &attr); } static void __init ioapic_add_ofnode(struct device_node *np) -- cgit v0.10.2 From 1ff42c32c7614c2e810ed388fd1ba04a5626b74c Mon Sep 17 00:00:00 2001 From: Sebastian Andrzej Siewior Date: Wed, 27 Apr 2011 16:30:52 +0200 Subject: x86: ce4100: Configure IOAPIC pins for USB and SATA to level type The USB and SATA ioapic interrrupt pins are configured as edge type, but need to be level type interrupts to work correctly. [ tglx: Split out from the combo patch ] Cc: Torben Hohn Signed-off-by: Sebastian Andrzej Siewior Link: http://lkml.kernel.org/r/%3C20110427143052.GA15211%40linutronix.de%3E Signed-off-by: Thomas Gleixner diff --git a/arch/x86/platform/ce4100/falconfalls.dts b/arch/x86/platform/ce4100/falconfalls.dts index 2d6d226..e70be38 100644 --- a/arch/x86/platform/ce4100/falconfalls.dts +++ b/arch/x86/platform/ce4100/falconfalls.dts @@ -347,7 +347,7 @@ "pciclass0c03"; reg = <0x16800 0x0 0x0 0x0 0x0>; - interrupts = <22 3>; + interrupts = <22 1>; }; usb@d,1 { @@ -357,7 +357,7 @@ "pciclass0c03"; reg = <0x16900 0x0 0x0 0x0 0x0>; - interrupts = <22 3>; + interrupts = <22 1>; }; sata@e,0 { @@ -367,7 +367,7 @@ "pciclass0106"; reg = <0x17000 0x0 0x0 0x0 0x0>; - interrupts = <23 3>; + interrupts = <23 1>; }; flash@f,0 { -- cgit v0.10.2 From 83a5d2d1b4cc06ce17b44873e004fc0b55552183 Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Sat, 12 Mar 2011 03:27:22 +0000 Subject: ARM: Fix .size directive for xscale_dma_a0_map_area gas used to accept (and ignore?) .size directives which referred to undefined symbols, as this does. In binutils 2.21 these are treated as fatal errors. Signed-off-by: Ben Hutchings Signed-off-by: Eric Miao diff --git a/arch/arm/mm/proc-xscale.S b/arch/arm/mm/proc-xscale.S index ce233bc..42af976 100644 --- a/arch/arm/mm/proc-xscale.S +++ b/arch/arm/mm/proc-xscale.S @@ -395,7 +395,7 @@ ENTRY(xscale_dma_a0_map_area) teq r2, #DMA_TO_DEVICE beq xscale_dma_clean_range b xscale_dma_flush_range -ENDPROC(xscsale_dma_a0_map_area) +ENDPROC(xscale_dma_a0_map_area) /* * dma_unmap_area(start, size, dir) -- cgit v0.10.2 From 0edceb7bcd82802f721f3c94eed9b3e2869d3740 Mon Sep 17 00:00:00 2001 From: Oleg Nesterov Date: Wed, 27 Apr 2011 19:17:37 +0200 Subject: signal: introduce retarget_shared_pending() No functional changes. Move the notify-other-threads code from exit_signals() to the new helper, retarget_shared_pending(). Signed-off-by: Oleg Nesterov Reviewed-by: Matt Fleming Acked-by: Tejun Heo diff --git a/kernel/signal.c b/kernel/signal.c index c15e979..5341e21 100644 --- a/kernel/signal.c +++ b/kernel/signal.c @@ -2198,10 +2198,25 @@ relock: return signr; } +/* + * It could be that complete_signal() picked us to notify about the + * group-wide signal. Another thread should be notified now to take + * the signal since we will not. + */ +static void retarget_shared_pending(struct task_struct *tsk) +{ + struct task_struct *t; + + t = tsk; + while_each_thread(tsk, t) { + if (!signal_pending(t) && !(t->flags & PF_EXITING)) + recalc_sigpending_and_wake(t); + } +} + void exit_signals(struct task_struct *tsk) { int group_stop = 0; - struct task_struct *t; if (thread_group_empty(tsk) || signal_group_exit(tsk->signal)) { tsk->flags |= PF_EXITING; @@ -2217,14 +2232,7 @@ void exit_signals(struct task_struct *tsk) if (!signal_pending(tsk)) goto out; - /* - * It could be that __group_complete_signal() choose us to - * notify about group-wide signal. Another thread should be - * woken now to take the signal since we will not. - */ - for (t = tsk; (t = next_thread(t)) != tsk; ) - if (!signal_pending(t) && !(t->flags & PF_EXITING)) - recalc_sigpending_and_wake(t); + retarget_shared_pending(tsk); if (unlikely(tsk->group_stop & GROUP_STOP_PENDING) && task_participate_group_stop(tsk)) -- cgit v0.10.2 From f646e227b88a164a841d6b6dd969d8a45272dd83 Mon Sep 17 00:00:00 2001 From: Oleg Nesterov Date: Wed, 27 Apr 2011 19:18:39 +0200 Subject: signal: retarget_shared_pending: consider shared/unblocked signals only exit_signals() checks signal_pending() before retarget_shared_pending() but this is suboptimal. We can avoid the while_each_thread() loop in case when there are no shared signals visible to us. Add the "shared_pending.signal & ~blocked" check. We don't use tsk->blocked directly but pass ~blocked as an argument, this is needed for the next patch. Note: we can optimize this more. while_each_thread(t) can check t->blocked into account and stop after every pending signal has the new target, see the next patch. Signed-off-by: Oleg Nesterov Reviewed-by: Matt Fleming Acked-by: Tejun Heo diff --git a/kernel/signal.c b/kernel/signal.c index 5341e21..06214b5 100644 --- a/kernel/signal.c +++ b/kernel/signal.c @@ -2203,10 +2203,15 @@ relock: * group-wide signal. Another thread should be notified now to take * the signal since we will not. */ -static void retarget_shared_pending(struct task_struct *tsk) +static void retarget_shared_pending(struct task_struct *tsk, sigset_t *which) { + sigset_t retarget; struct task_struct *t; + sigandsets(&retarget, &tsk->signal->shared_pending.signal, which); + if (sigisemptyset(&retarget)) + return; + t = tsk; while_each_thread(tsk, t) { if (!signal_pending(t) && !(t->flags & PF_EXITING)) @@ -2217,6 +2222,7 @@ static void retarget_shared_pending(struct task_struct *tsk) void exit_signals(struct task_struct *tsk) { int group_stop = 0; + sigset_t unblocked; if (thread_group_empty(tsk) || signal_group_exit(tsk->signal)) { tsk->flags |= PF_EXITING; @@ -2232,7 +2238,9 @@ void exit_signals(struct task_struct *tsk) if (!signal_pending(tsk)) goto out; - retarget_shared_pending(tsk); + unblocked = tsk->blocked; + signotset(&unblocked); + retarget_shared_pending(tsk, &unblocked); if (unlikely(tsk->group_stop & GROUP_STOP_PENDING) && task_participate_group_stop(tsk)) -- cgit v0.10.2 From fec9993db093acfc3999a364e31f8adae41fcb28 Mon Sep 17 00:00:00 2001 From: Oleg Nesterov Date: Wed, 27 Apr 2011 19:50:21 +0200 Subject: signal: retarget_shared_pending: optimize while_each_thread() loop retarget_shared_pending() blindly does recalc_sigpending_and_wake() for every sub-thread, this is suboptimal. We can check t->blocked and stop looping once every bit in shared_pending has the new target. Note: we do not take task_is_stopped_or_traced(t) into account, we are not trying to speed up the signal delivery or to avoid the unnecessary (but harmless) signal_wake_up(0) in this unlikely case. Signed-off-by: Oleg Nesterov Reviewed-by: Matt Fleming Acked-by: Tejun Heo diff --git a/kernel/signal.c b/kernel/signal.c index 06214b5..707736e 100644 --- a/kernel/signal.c +++ b/kernel/signal.c @@ -2200,8 +2200,8 @@ relock: /* * It could be that complete_signal() picked us to notify about the - * group-wide signal. Another thread should be notified now to take - * the signal since we will not. + * group-wide signal. Other threads should be notified now to take + * the shared signals in @which since we will not. */ static void retarget_shared_pending(struct task_struct *tsk, sigset_t *which) { @@ -2214,8 +2214,19 @@ static void retarget_shared_pending(struct task_struct *tsk, sigset_t *which) t = tsk; while_each_thread(tsk, t) { - if (!signal_pending(t) && !(t->flags & PF_EXITING)) - recalc_sigpending_and_wake(t); + if (t->flags & PF_EXITING) + continue; + + if (!has_pending_signals(&retarget, &t->blocked)) + continue; + /* Remove the signals this thread can handle. */ + sigandsets(&retarget, &retarget, &t->blocked); + + if (!signal_pending(t)) + signal_wake_up(t, 0); + + if (sigisemptyset(&retarget)) + break; } } -- cgit v0.10.2 From 73ef4aeb61b53fce464a7e24ef03a26f98b2f617 Mon Sep 17 00:00:00 2001 From: Oleg Nesterov Date: Wed, 27 Apr 2011 19:54:20 +0200 Subject: signal: sigprocmask: narrow the scope of ->siglock No functional changes, preparation to simplify the review of the next change. 1. We can read current->block lockless, nobody else can ever change this mask. 2. Calculate the resulting sigset_t outside of ->siglock into the temporary variable, then take ->siglock and change ->blocked. Also, kill the stale comment about BKL. Signed-off-by: Oleg Nesterov Reviewed-by: Matt Fleming Acked-by: Tejun Heo diff --git a/kernel/signal.c b/kernel/signal.c index 707736e..e8308e32 100644 --- a/kernel/signal.c +++ b/kernel/signal.c @@ -2300,12 +2300,6 @@ long do_no_restart_syscall(struct restart_block *param) } /* - * We don't need to get the kernel lock - this is all local to this - * particular thread.. (and that's good, because this is _heavily_ - * used by various programs) - */ - -/* * This is also useful for kernel threads that want to temporarily * (or permanently) block certain signals. * @@ -2315,30 +2309,33 @@ long do_no_restart_syscall(struct restart_block *param) */ int sigprocmask(int how, sigset_t *set, sigset_t *oldset) { - int error; + struct task_struct *tsk = current; + sigset_t newset; - spin_lock_irq(¤t->sighand->siglock); + /* Lockless, only current can change ->blocked, never from irq */ if (oldset) - *oldset = current->blocked; + *oldset = tsk->blocked; - error = 0; switch (how) { case SIG_BLOCK: - sigorsets(¤t->blocked, ¤t->blocked, set); + sigorsets(&newset, &tsk->blocked, set); break; case SIG_UNBLOCK: - signandsets(¤t->blocked, ¤t->blocked, set); + signandsets(&newset, &tsk->blocked, set); break; case SIG_SETMASK: - current->blocked = *set; + newset = *set; break; default: - error = -EINVAL; + return -EINVAL; } + + spin_lock_irq(&tsk->sighand->siglock); + tsk->blocked = newset; recalc_sigpending(); - spin_unlock_irq(¤t->sighand->siglock); + spin_unlock_irq(&tsk->sighand->siglock); - return error; + return 0; } /** -- cgit v0.10.2 From e6fa16ab9c1e9b344428e6fea4d29e3cc4b28fb0 Mon Sep 17 00:00:00 2001 From: Oleg Nesterov Date: Wed, 27 Apr 2011 20:59:41 +0200 Subject: signal: sigprocmask() should do retarget_shared_pending() In short, almost every changing of current->blocked is wrong, or at least can lead to the unexpected results. For example. Two threads T1 and T2, T1 sleeps in sigtimedwait/pause/etc. kill(tgid, SIG) can pick T2 for TIF_SIGPENDING. If T2 calls sigprocmask() and blocks SIG before it notices the pending signal, nobody else can handle this pending shared signal. I am not sure this is bug, but at least this looks strange imho. T1 should not sleep forever, there is a signal which should wake it up. This patch moves the code which actually changes ->blocked into the new helper, set_current_blocked() and changes this code to call retarget_shared_pending() as exit_signals() does. We should only care about the signals we just blocked, we use "newset & ~current->blocked" as a mask. We do not check !sigisemptyset(newblocked), retarget_shared_pending() is cheap unless mask & shared_pending. Note: for this particular case we could simply change sigprocmask() to return -EINTR if signal_pending(), but then we should change other callers and, more importantly, if we need this fix then set_current_blocked() will have more callers and some of them can't restart. See the next patch as a random example. Signed-off-by: Oleg Nesterov Reviewed-by: Matt Fleming Acked-by: Tejun Heo diff --git a/include/linux/signal.h b/include/linux/signal.h index fcd2b14..ba009c1 100644 --- a/include/linux/signal.h +++ b/include/linux/signal.h @@ -243,6 +243,7 @@ extern long do_rt_tgsigqueueinfo(pid_t tgid, pid_t pid, int sig, siginfo_t *info); extern long do_sigpending(void __user *, unsigned long); extern int sigprocmask(int, sigset_t *, sigset_t *); +extern void set_current_blocked(const sigset_t *); extern int show_unhandled_signals; struct pt_regs; diff --git a/kernel/signal.c b/kernel/signal.c index e8308e32..8aa3a2e 100644 --- a/kernel/signal.c +++ b/kernel/signal.c @@ -2299,6 +2299,29 @@ long do_no_restart_syscall(struct restart_block *param) return -EINTR; } +/** + * set_current_blocked - change current->blocked mask + * @newset: new mask + * + * It is wrong to change ->blocked directly, this helper should be used + * to ensure the process can't miss a shared signal we are going to block. + */ +void set_current_blocked(const sigset_t *newset) +{ + struct task_struct *tsk = current; + + spin_lock_irq(&tsk->sighand->siglock); + if (signal_pending(tsk) && !thread_group_empty(tsk)) { + sigset_t newblocked; + /* A set of now blocked but previously unblocked signals. */ + signandsets(&newblocked, newset, ¤t->blocked); + retarget_shared_pending(tsk, &newblocked); + } + tsk->blocked = *newset; + recalc_sigpending(); + spin_unlock_irq(&tsk->sighand->siglock); +} + /* * This is also useful for kernel threads that want to temporarily * (or permanently) block certain signals. @@ -2330,11 +2353,7 @@ int sigprocmask(int how, sigset_t *set, sigset_t *oldset) return -EINVAL; } - spin_lock_irq(&tsk->sighand->siglock); - tsk->blocked = newset; - recalc_sigpending(); - spin_unlock_irq(&tsk->sighand->siglock); - + set_current_blocked(&newset); return 0; } -- cgit v0.10.2 From e6a585801b451443480ff66914a522b482457460 Mon Sep 17 00:00:00 2001 From: Oleg Nesterov Date: Wed, 27 Apr 2011 21:04:28 +0200 Subject: x86: signal: handle_signal() should use set_current_blocked() This is ugly, but if sigprocmask() needs retarget_shared_pending() then handle signal should follow this logic. In theory it is newer correct to add the new signals to current->blocked, the signal handler can sleep/etc so we should notify other threads in case we block the pending signal and nobody else has TIF_SIGPENDING. Of course, this change doesn't make signals faster :/ Signed-off-by: Oleg Nesterov Reviewed-by: Matt Fleming Acked-by: Tejun Heo diff --git a/arch/x86/kernel/signal.c b/arch/x86/kernel/signal.c index 4fd173c..5a8f5e6 100644 --- a/arch/x86/kernel/signal.c +++ b/arch/x86/kernel/signal.c @@ -682,6 +682,7 @@ static int handle_signal(unsigned long sig, siginfo_t *info, struct k_sigaction *ka, sigset_t *oldset, struct pt_regs *regs) { + sigset_t blocked; int ret; /* Are we from a system call? */ @@ -741,12 +742,10 @@ handle_signal(unsigned long sig, siginfo_t *info, struct k_sigaction *ka, */ regs->flags &= ~X86_EFLAGS_TF; - spin_lock_irq(¤t->sighand->siglock); - sigorsets(¤t->blocked, ¤t->blocked, &ka->sa.sa_mask); + sigorsets(&blocked, ¤t->blocked, &ka->sa.sa_mask); if (!(ka->sa.sa_flags & SA_NODEFER)) - sigaddset(¤t->blocked, sig); - recalc_sigpending(); - spin_unlock_irq(¤t->sighand->siglock); + sigaddset(&blocked, sig); + set_current_blocked(&blocked); tracehook_signal_handler(sig, info, ka, regs, test_thread_flag(TIF_SINGLESTEP)); -- cgit v0.10.2 From e9bd3f0faa90084f188830d77723bafe422e486b Mon Sep 17 00:00:00 2001 From: Oleg Nesterov Date: Wed, 27 Apr 2011 21:09:39 +0200 Subject: x86: signal: sys_rt_sigreturn() should use set_current_blocked() Normally sys_rt_sigreturn() restores the old current->blocked which was changed by handle_signal(), and unblocking is always fine. But the debugger or application itself can change frame->uc_sigmask and thus we need set_current_blocked()->retarget_shared_pending(). Signed-off-by: Oleg Nesterov Reviewed-by: Matt Fleming Acked-by: Tejun Heo diff --git a/arch/x86/kernel/signal.c b/arch/x86/kernel/signal.c index 5a8f5e6..40a2493 100644 --- a/arch/x86/kernel/signal.c +++ b/arch/x86/kernel/signal.c @@ -601,10 +601,7 @@ long sys_rt_sigreturn(struct pt_regs *regs) goto badframe; sigdelsetmask(&set, ~_BLOCKABLE); - spin_lock_irq(¤t->sighand->siglock); - current->blocked = set; - recalc_sigpending(); - spin_unlock_irq(¤t->sighand->siglock); + set_current_blocked(&set); if (restore_sigcontext(regs, &frame->uc.uc_mcontext, &ax)) goto badframe; -- cgit v0.10.2 From bb7efee2ca63b08795ffb3cda96fc89d2e641b79 Mon Sep 17 00:00:00 2001 From: Oleg Nesterov Date: Wed, 27 Apr 2011 21:18:10 +0200 Subject: signal: cleanup sys_rt_sigprocmask() sys_rt_sigprocmask() looks unnecessarily complicated, simplify it. We can just read current->blocked lockless unconditionally before anything else and then copy-to-user it if needed. At worst we copy 4 words on mips. We could copy-to-user the old mask first and simplify the code even more, but the patch tries to keep the current behaviour: we change current->block even if copy_to_user(oset) fails. Signed-off-by: Oleg Nesterov Reviewed-by: Matt Fleming Acked-by: Tejun Heo diff --git a/kernel/signal.c b/kernel/signal.c index 8aa3a2e..bb92000 100644 --- a/kernel/signal.c +++ b/kernel/signal.c @@ -2364,40 +2364,34 @@ int sigprocmask(int how, sigset_t *set, sigset_t *oldset) * @oset: previous value of signal mask if non-null * @sigsetsize: size of sigset_t type */ -SYSCALL_DEFINE4(rt_sigprocmask, int, how, sigset_t __user *, set, +SYSCALL_DEFINE4(rt_sigprocmask, int, how, sigset_t __user *, nset, sigset_t __user *, oset, size_t, sigsetsize) { - int error = -EINVAL; sigset_t old_set, new_set; + int error; /* XXX: Don't preclude handling different sized sigset_t's. */ if (sigsetsize != sizeof(sigset_t)) - goto out; + return -EINVAL; - if (set) { - error = -EFAULT; - if (copy_from_user(&new_set, set, sizeof(*set))) - goto out; + old_set = current->blocked; + + if (nset) { + if (copy_from_user(&new_set, nset, sizeof(sigset_t))) + return -EFAULT; sigdelsetmask(&new_set, sigmask(SIGKILL)|sigmask(SIGSTOP)); - error = sigprocmask(how, &new_set, &old_set); + error = sigprocmask(how, &new_set, NULL); if (error) - goto out; - if (oset) - goto set_old; - } else if (oset) { - spin_lock_irq(¤t->sighand->siglock); - old_set = current->blocked; - spin_unlock_irq(¤t->sighand->siglock); + return error; + } - set_old: - error = -EFAULT; - if (copy_to_user(oset, &old_set, sizeof(*oset))) - goto out; + if (oset) { + if (copy_to_user(oset, &old_set, sizeof(sigset_t))) + return -EFAULT; } - error = 0; -out: - return error; + + return 0; } long do_sigpending(void __user *set, unsigned long sigsetsize) -- cgit v0.10.2 From fe0faa005d43bc44c357631d51c273806086caa4 Mon Sep 17 00:00:00 2001 From: Oleg Nesterov Date: Wed, 27 Apr 2011 21:24:19 +0200 Subject: signal: sys_rt_sigtimedwait: simplify the timeout logic No functional changes, cleanup compat_sys_rt_sigtimedwait() and sys_rt_sigtimedwait(). Calculate the timeout before we take ->siglock, this simplifies and lessens the code. Use timespec_valid() to check the timespec. Signed-off-by: Oleg Nesterov Acked-by: Tejun Heo Reviewed-by: Matt Fleming diff --git a/kernel/compat.c b/kernel/compat.c index 38b1d2c..06cbb06 100644 --- a/kernel/compat.c +++ b/kernel/compat.c @@ -893,7 +893,7 @@ compat_sys_rt_sigtimedwait (compat_sigset_t __user *uthese, int sig; struct timespec t; siginfo_t info; - long ret, timeout = 0; + long ret, timeout; if (sigsetsize != sizeof(sigset_t)) return -EINVAL; @@ -904,36 +904,30 @@ compat_sys_rt_sigtimedwait (compat_sigset_t __user *uthese, sigdelsetmask(&s,sigmask(SIGKILL)|sigmask(SIGSTOP)); signotset(&s); + timeout = MAX_SCHEDULE_TIMEOUT; if (uts) { if (get_compat_timespec (&t, uts)) return -EFAULT; - if (t.tv_nsec >= 1000000000L || t.tv_nsec < 0 - || t.tv_sec < 0) + if (!timespec_valid(&t)) return -EINVAL; + timeout = timespec_to_jiffies(&t) + (t.tv_sec || t.tv_nsec); } spin_lock_irq(¤t->sighand->siglock); sig = dequeue_signal(current, &s, &info); - if (!sig) { - timeout = MAX_SCHEDULE_TIMEOUT; - if (uts) - timeout = timespec_to_jiffies(&t) - +(t.tv_sec || t.tv_nsec); - if (timeout) { - current->real_blocked = current->blocked; - sigandsets(¤t->blocked, ¤t->blocked, &s); - - recalc_sigpending(); - spin_unlock_irq(¤t->sighand->siglock); - - timeout = schedule_timeout_interruptible(timeout); - - spin_lock_irq(¤t->sighand->siglock); - sig = dequeue_signal(current, &s, &info); - current->blocked = current->real_blocked; - siginitset(¤t->real_blocked, 0); - recalc_sigpending(); - } + if (!sig && timeout) { + current->real_blocked = current->blocked; + sigandsets(¤t->blocked, ¤t->blocked, &s); + recalc_sigpending(); + spin_unlock_irq(¤t->sighand->siglock); + + timeout = schedule_timeout_interruptible(timeout); + + spin_lock_irq(¤t->sighand->siglock); + sig = dequeue_signal(current, &s, &info); + current->blocked = current->real_blocked; + siginitset(¤t->real_blocked, 0); + recalc_sigpending(); } spin_unlock_irq(¤t->sighand->siglock); @@ -943,7 +937,7 @@ compat_sys_rt_sigtimedwait (compat_sigset_t __user *uthese, if (copy_siginfo_to_user32(uinfo, &info)) ret = -EFAULT; } - }else { + } else { ret = timeout?-EINTR:-EAGAIN; } return ret; diff --git a/kernel/signal.c b/kernel/signal.c index bb92000..c734619 100644 --- a/kernel/signal.c +++ b/kernel/signal.c @@ -2519,7 +2519,7 @@ SYSCALL_DEFINE4(rt_sigtimedwait, const sigset_t __user *, uthese, sigset_t these; struct timespec ts; siginfo_t info; - long timeout = 0; + long timeout; /* XXX: Don't preclude handling different sized sigset_t's. */ if (sigsetsize != sizeof(sigset_t)) @@ -2535,41 +2535,35 @@ SYSCALL_DEFINE4(rt_sigtimedwait, const sigset_t __user *, uthese, sigdelsetmask(&these, sigmask(SIGKILL)|sigmask(SIGSTOP)); signotset(&these); + timeout = MAX_SCHEDULE_TIMEOUT; if (uts) { if (copy_from_user(&ts, uts, sizeof(ts))) return -EFAULT; - if (ts.tv_nsec >= 1000000000L || ts.tv_nsec < 0 - || ts.tv_sec < 0) + if (!timespec_valid(&ts)) return -EINVAL; + timeout = timespec_to_jiffies(&ts) + (ts.tv_sec || ts.tv_nsec); } spin_lock_irq(¤t->sighand->siglock); sig = dequeue_signal(current, &these, &info); - if (!sig) { - timeout = MAX_SCHEDULE_TIMEOUT; - if (uts) - timeout = (timespec_to_jiffies(&ts) - + (ts.tv_sec || ts.tv_nsec)); + if (!sig && timeout) { + /* + * None ready -- temporarily unblock those we're + * interested while we are sleeping in so that we'll + * be awakened when they arrive. + */ + current->real_blocked = current->blocked; + sigandsets(¤t->blocked, ¤t->blocked, &these); + recalc_sigpending(); + spin_unlock_irq(¤t->sighand->siglock); - if (timeout) { - /* - * None ready -- temporarily unblock those we're - * interested while we are sleeping in so that we'll - * be awakened when they arrive. - */ - current->real_blocked = current->blocked; - sigandsets(¤t->blocked, ¤t->blocked, &these); - recalc_sigpending(); - spin_unlock_irq(¤t->sighand->siglock); - - timeout = schedule_timeout_interruptible(timeout); - - spin_lock_irq(¤t->sighand->siglock); - sig = dequeue_signal(current, &these, &info); - current->blocked = current->real_blocked; - siginitset(¤t->real_blocked, 0); - recalc_sigpending(); - } + timeout = schedule_timeout_interruptible(timeout); + + spin_lock_irq(¤t->sighand->siglock); + sig = dequeue_signal(current, &these, &info); + current->blocked = current->real_blocked; + siginitset(¤t->real_blocked, 0); + recalc_sigpending(); } spin_unlock_irq(¤t->sighand->siglock); -- cgit v0.10.2 From 943df1485a8ff0e600729e082e568ece04d4de9e Mon Sep 17 00:00:00 2001 From: Oleg Nesterov Date: Wed, 27 Apr 2011 21:44:14 +0200 Subject: signal: introduce do_sigtimedwait() to factor out compat/native code Factor out the common code in sys_rt_sigtimedwait/compat_sys_rt_sigtimedwait to the new helper, do_sigtimedwait(). Add the comment to document the extra tick we add to timespec_to_jiffies(ts), thanks to Linus who explained this to me. Perhaps it would be better to move compat_sys_rt_sigtimedwait() into signal.c under CONFIG_COMPAT, then we can make do_sigtimedwait() static. Signed-off-by: Oleg Nesterov Acked-by: Tejun Heo Reviewed-by: Matt Fleming diff --git a/include/linux/signal.h b/include/linux/signal.h index ba009c1..782546d 100644 --- a/include/linux/signal.h +++ b/include/linux/signal.h @@ -242,6 +242,8 @@ extern int __group_send_sig_info(int, struct siginfo *, struct task_struct *); extern long do_rt_tgsigqueueinfo(pid_t tgid, pid_t pid, int sig, siginfo_t *info); extern long do_sigpending(void __user *, unsigned long); +extern int do_sigtimedwait(const sigset_t *, siginfo_t *, + const struct timespec *); extern int sigprocmask(int, sigset_t *, sigset_t *); extern void set_current_blocked(const sigset_t *); extern int show_unhandled_signals; diff --git a/kernel/compat.c b/kernel/compat.c index 06cbb06..9214dcd 100644 --- a/kernel/compat.c +++ b/kernel/compat.c @@ -890,10 +890,9 @@ compat_sys_rt_sigtimedwait (compat_sigset_t __user *uthese, { compat_sigset_t s32; sigset_t s; - int sig; struct timespec t; siginfo_t info; - long ret, timeout; + long ret; if (sigsetsize != sizeof(sigset_t)) return -EINVAL; @@ -901,45 +900,19 @@ compat_sys_rt_sigtimedwait (compat_sigset_t __user *uthese, if (copy_from_user(&s32, uthese, sizeof(compat_sigset_t))) return -EFAULT; sigset_from_compat(&s, &s32); - sigdelsetmask(&s,sigmask(SIGKILL)|sigmask(SIGSTOP)); - signotset(&s); - timeout = MAX_SCHEDULE_TIMEOUT; if (uts) { - if (get_compat_timespec (&t, uts)) + if (get_compat_timespec(&t, uts)) return -EFAULT; - if (!timespec_valid(&t)) - return -EINVAL; - timeout = timespec_to_jiffies(&t) + (t.tv_sec || t.tv_nsec); } - spin_lock_irq(¤t->sighand->siglock); - sig = dequeue_signal(current, &s, &info); - if (!sig && timeout) { - current->real_blocked = current->blocked; - sigandsets(¤t->blocked, ¤t->blocked, &s); - recalc_sigpending(); - spin_unlock_irq(¤t->sighand->siglock); - - timeout = schedule_timeout_interruptible(timeout); - - spin_lock_irq(¤t->sighand->siglock); - sig = dequeue_signal(current, &s, &info); - current->blocked = current->real_blocked; - siginitset(¤t->real_blocked, 0); - recalc_sigpending(); - } - spin_unlock_irq(¤t->sighand->siglock); + ret = do_sigtimedwait(&s, &info, uts ? &t : NULL); - if (sig) { - ret = sig; - if (uinfo) { - if (copy_siginfo_to_user32(uinfo, &info)) - ret = -EFAULT; - } - } else { - ret = timeout?-EINTR:-EAGAIN; + if (ret > 0 && uinfo) { + if (copy_siginfo_to_user32(uinfo, &info)) + ret = -EFAULT; } + return ret; } diff --git a/kernel/signal.c b/kernel/signal.c index c734619..1ab89f6 100644 --- a/kernel/signal.c +++ b/kernel/signal.c @@ -2504,6 +2504,66 @@ int copy_siginfo_to_user(siginfo_t __user *to, siginfo_t *from) #endif /** + * do_sigtimedwait - wait for queued signals specified in @which + * @which: queued signals to wait for + * @info: if non-null, the signal's siginfo is returned here + * @ts: upper bound on process time suspension + */ +int do_sigtimedwait(const sigset_t *which, siginfo_t *info, + const struct timespec *ts) +{ + struct task_struct *tsk = current; + long timeout = MAX_SCHEDULE_TIMEOUT; + sigset_t mask = *which; + int sig; + + if (ts) { + if (!timespec_valid(ts)) + return -EINVAL; + timeout = timespec_to_jiffies(ts); + /* + * We can be close to the next tick, add another one + * to ensure we will wait at least the time asked for. + */ + if (ts->tv_sec || ts->tv_nsec) + timeout++; + } + + /* + * Invert the set of allowed signals to get those we want to block. + */ + sigdelsetmask(&mask, sigmask(SIGKILL) | sigmask(SIGSTOP)); + signotset(&mask); + + spin_lock_irq(&tsk->sighand->siglock); + sig = dequeue_signal(tsk, &mask, info); + if (!sig && timeout) { + /* + * None ready, temporarily unblock those we're interested + * while we are sleeping in so that we'll be awakened when + * they arrive. + */ + tsk->real_blocked = tsk->blocked; + sigandsets(&tsk->blocked, &tsk->blocked, &mask); + recalc_sigpending(); + spin_unlock_irq(&tsk->sighand->siglock); + + timeout = schedule_timeout_interruptible(timeout); + + spin_lock_irq(&tsk->sighand->siglock); + sig = dequeue_signal(tsk, &mask, info); + tsk->blocked = tsk->real_blocked; + siginitset(&tsk->real_blocked, 0); + recalc_sigpending(); + } + spin_unlock_irq(&tsk->sighand->siglock); + + if (sig) + return sig; + return timeout ? -EINTR : -EAGAIN; +} + +/** * sys_rt_sigtimedwait - synchronously wait for queued signals specified * in @uthese * @uthese: queued signals to wait for @@ -2515,11 +2575,10 @@ SYSCALL_DEFINE4(rt_sigtimedwait, const sigset_t __user *, uthese, siginfo_t __user *, uinfo, const struct timespec __user *, uts, size_t, sigsetsize) { - int ret, sig; sigset_t these; struct timespec ts; siginfo_t info; - long timeout; + int ret; /* XXX: Don't preclude handling different sized sigset_t's. */ if (sigsetsize != sizeof(sigset_t)) @@ -2528,55 +2587,16 @@ SYSCALL_DEFINE4(rt_sigtimedwait, const sigset_t __user *, uthese, if (copy_from_user(&these, uthese, sizeof(these))) return -EFAULT; - /* - * Invert the set of allowed signals to get those we - * want to block. - */ - sigdelsetmask(&these, sigmask(SIGKILL)|sigmask(SIGSTOP)); - signotset(&these); - - timeout = MAX_SCHEDULE_TIMEOUT; if (uts) { if (copy_from_user(&ts, uts, sizeof(ts))) return -EFAULT; - if (!timespec_valid(&ts)) - return -EINVAL; - timeout = timespec_to_jiffies(&ts) + (ts.tv_sec || ts.tv_nsec); } - spin_lock_irq(¤t->sighand->siglock); - sig = dequeue_signal(current, &these, &info); - if (!sig && timeout) { - /* - * None ready -- temporarily unblock those we're - * interested while we are sleeping in so that we'll - * be awakened when they arrive. - */ - current->real_blocked = current->blocked; - sigandsets(¤t->blocked, ¤t->blocked, &these); - recalc_sigpending(); - spin_unlock_irq(¤t->sighand->siglock); - - timeout = schedule_timeout_interruptible(timeout); - - spin_lock_irq(¤t->sighand->siglock); - sig = dequeue_signal(current, &these, &info); - current->blocked = current->real_blocked; - siginitset(¤t->real_blocked, 0); - recalc_sigpending(); - } - spin_unlock_irq(¤t->sighand->siglock); + ret = do_sigtimedwait(&these, &info, uts ? &ts : NULL); - if (sig) { - ret = sig; - if (uinfo) { - if (copy_siginfo_to_user(uinfo, &info)) - ret = -EFAULT; - } - } else { - ret = -EAGAIN; - if (timeout) - ret = -EINTR; + if (ret > 0 && uinfo) { + if (copy_siginfo_to_user(uinfo, &info)) + ret = -EFAULT; } return ret; -- cgit v0.10.2 From b182801ab35f7a0afb3cdf8ba5df464d04206b46 Mon Sep 17 00:00:00 2001 From: Oleg Nesterov Date: Wed, 27 Apr 2011 21:56:14 +0200 Subject: signal: do_sigtimedwait() needs retarget_shared_pending() do_sigtimedwait() changes current->blocked and thus it needs set_current_blocked()->retarget_shared_pending(). We could use set_current_blocked() directly. It is fine to change ->real_blocked from all-zeroes to ->blocked and vice versa lockless, but this is not immediately clear, looks racy, and needs a huge comment to explain why this is correct. To keep the things simple this patch adds the new static helper, __set_task_blocked() which should be called with ->siglock held. This way we can change both ->real_blocked and ->blocked atomically under ->siglock as the current code does. This is more understandable. Signed-off-by: Oleg Nesterov Acked-by: Tejun Heo Reviewed-by: Matt Fleming diff --git a/kernel/signal.c b/kernel/signal.c index 1ab89f6..4d97e11 100644 --- a/kernel/signal.c +++ b/kernel/signal.c @@ -2299,6 +2299,18 @@ long do_no_restart_syscall(struct restart_block *param) return -EINTR; } +static void __set_task_blocked(struct task_struct *tsk, const sigset_t *newset) +{ + if (signal_pending(tsk) && !thread_group_empty(tsk)) { + sigset_t newblocked; + /* A set of now blocked but previously unblocked signals. */ + signandsets(&newblocked, newset, ¤t->blocked); + retarget_shared_pending(tsk, &newblocked); + } + tsk->blocked = *newset; + recalc_sigpending(); +} + /** * set_current_blocked - change current->blocked mask * @newset: new mask @@ -2311,14 +2323,7 @@ void set_current_blocked(const sigset_t *newset) struct task_struct *tsk = current; spin_lock_irq(&tsk->sighand->siglock); - if (signal_pending(tsk) && !thread_group_empty(tsk)) { - sigset_t newblocked; - /* A set of now blocked but previously unblocked signals. */ - signandsets(&newblocked, newset, ¤t->blocked); - retarget_shared_pending(tsk, &newblocked); - } - tsk->blocked = *newset; - recalc_sigpending(); + __set_task_blocked(tsk, newset); spin_unlock_irq(&tsk->sighand->siglock); } @@ -2541,7 +2546,8 @@ int do_sigtimedwait(const sigset_t *which, siginfo_t *info, /* * None ready, temporarily unblock those we're interested * while we are sleeping in so that we'll be awakened when - * they arrive. + * they arrive. Unblocking is always fine, we can avoid + * set_current_blocked(). */ tsk->real_blocked = tsk->blocked; sigandsets(&tsk->blocked, &tsk->blocked, &mask); @@ -2551,10 +2557,9 @@ int do_sigtimedwait(const sigset_t *which, siginfo_t *info, timeout = schedule_timeout_interruptible(timeout); spin_lock_irq(&tsk->sighand->siglock); - sig = dequeue_signal(tsk, &mask, info); - tsk->blocked = tsk->real_blocked; + __set_task_blocked(tsk, &tsk->real_blocked); siginitset(&tsk->real_blocked, 0); - recalc_sigpending(); + sig = dequeue_signal(tsk, &mask, info); } spin_unlock_irq(&tsk->sighand->siglock); -- cgit v0.10.2 From 702a5073fdb71eb29cd4912575289fb5044c1894 Mon Sep 17 00:00:00 2001 From: Oleg Nesterov Date: Wed, 27 Apr 2011 22:01:27 +0200 Subject: signal: rename signandsets() to sigandnsets() As Tejun and Linus pointed out, "nand" is the wrong name for "x & ~y", it should be "andn". Rename signandsets() as suggested. Suggested-by: Tejun Heo Signed-off-by: Oleg Nesterov Acked-by: Tejun Heo diff --git a/include/linux/signal.h b/include/linux/signal.h index 782546d..7e25263 100644 --- a/include/linux/signal.h +++ b/include/linux/signal.h @@ -123,13 +123,13 @@ _SIG_SET_BINOP(sigorsets, _sig_or) #define _sig_and(x,y) ((x) & (y)) _SIG_SET_BINOP(sigandsets, _sig_and) -#define _sig_nand(x,y) ((x) & ~(y)) -_SIG_SET_BINOP(signandsets, _sig_nand) +#define _sig_andn(x,y) ((x) & ~(y)) +_SIG_SET_BINOP(sigandnsets, _sig_andn) #undef _SIG_SET_BINOP #undef _sig_or #undef _sig_and -#undef _sig_nand +#undef _sig_andn #define _SIG_SET_OP(name, op) \ static inline void name(sigset_t *set) \ diff --git a/kernel/signal.c b/kernel/signal.c index 4d97e11..e7ee4e6 100644 --- a/kernel/signal.c +++ b/kernel/signal.c @@ -669,7 +669,7 @@ static int rm_from_queue_full(sigset_t *mask, struct sigpending *s) if (sigisemptyset(&m)) return 0; - signandsets(&s->signal, &s->signal, mask); + sigandnsets(&s->signal, &s->signal, mask); list_for_each_entry_safe(q, n, &s->list, list) { if (sigismember(mask, q->info.si_signo)) { list_del_init(&q->list); @@ -2304,7 +2304,7 @@ static void __set_task_blocked(struct task_struct *tsk, const sigset_t *newset) if (signal_pending(tsk) && !thread_group_empty(tsk)) { sigset_t newblocked; /* A set of now blocked but previously unblocked signals. */ - signandsets(&newblocked, newset, ¤t->blocked); + sigandnsets(&newblocked, newset, ¤t->blocked); retarget_shared_pending(tsk, &newblocked); } tsk->blocked = *newset; @@ -2349,7 +2349,7 @@ int sigprocmask(int how, sigset_t *set, sigset_t *oldset) sigorsets(&newset, &tsk->blocked, set); break; case SIG_UNBLOCK: - signandsets(&newset, &tsk->blocked, set); + sigandnsets(&newset, &tsk->blocked, set); break; case SIG_SETMASK: newset = *set; -- cgit v0.10.2 From b013c399245a88a73aaa031279f0c4d7cea7fe68 Mon Sep 17 00:00:00 2001 From: Oleg Nesterov Date: Thu, 28 Apr 2011 11:36:20 +0200 Subject: signal: cleanup sys_sigprocmask() Cleanup. Remove the unneeded goto's, we can simply read blocked.sig[0] unconditionally and then copy-to-user it if oset != NULL. Signed-off-by: Oleg Nesterov Acked-by: Tejun Heo Reviewed-by: Matt Fleming diff --git a/kernel/signal.c b/kernel/signal.c index e7ee4e6..c0af959 100644 --- a/kernel/signal.c +++ b/kernel/signal.c @@ -2889,29 +2889,28 @@ SYSCALL_DEFINE1(sigpending, old_sigset_t __user *, set) /** * sys_sigprocmask - examine and change blocked signals * @how: whether to add, remove, or set signals - * @set: signals to add or remove (if non-null) + * @nset: signals to add or remove (if non-null) * @oset: previous value of signal mask if non-null * * Some platforms have their own version with special arguments; * others support only sys_rt_sigprocmask. */ -SYSCALL_DEFINE3(sigprocmask, int, how, old_sigset_t __user *, set, +SYSCALL_DEFINE3(sigprocmask, int, how, old_sigset_t __user *, nset, old_sigset_t __user *, oset) { - int error; old_sigset_t old_set, new_set; + int error; - if (set) { - error = -EFAULT; - if (copy_from_user(&new_set, set, sizeof(*set))) - goto out; - new_set &= ~(sigmask(SIGKILL) | sigmask(SIGSTOP)); + old_set = current->blocked.sig[0]; - spin_lock_irq(¤t->sighand->siglock); - old_set = current->blocked.sig[0]; + if (nset) { + if (copy_from_user(&new_set, nset, sizeof(*nset))) + return -EFAULT; + new_set &= ~(sigmask(SIGKILL) | sigmask(SIGSTOP)); error = 0; + spin_lock_irq(¤t->sighand->siglock); switch (how) { default: error = -EINVAL; @@ -2930,19 +2929,15 @@ SYSCALL_DEFINE3(sigprocmask, int, how, old_sigset_t __user *, set, recalc_sigpending(); spin_unlock_irq(¤t->sighand->siglock); if (error) - goto out; - if (oset) - goto set_old; - } else if (oset) { - old_set = current->blocked.sig[0]; - set_old: - error = -EFAULT; + return error; + } + + if (oset) { if (copy_to_user(oset, &old_set, sizeof(*oset))) - goto out; + return -EFAULT; } - error = 0; -out: - return error; + + return 0; } #endif /* __ARCH_WANT_SYS_SIGPROCMASK */ -- cgit v0.10.2 From 1270b01f7530ac73bcf08325bcd85c94e2bbebc1 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Wed, 27 Apr 2011 18:19:17 +0100 Subject: ASoC: Fix CODEC name in Goni This was typoed at some point in the multi-component merge, though the driver was added along with that. Signed-off-by: Mark Brown Acked-by: Jassi Brar Acked-by: Liam Girdwood diff --git a/sound/soc/samsung/goni_wm8994.c b/sound/soc/samsung/goni_wm8994.c index f6b3a3c..3a7861c 100644 --- a/sound/soc/samsung/goni_wm8994.c +++ b/sound/soc/samsung/goni_wm8994.c @@ -238,7 +238,7 @@ static struct snd_soc_dai_link goni_dai[] = { .cpu_dai_name = "samsung-i2s.0", .codec_dai_name = "wm8994-hifi", .platform_name = "samsung-audio", - .codec_name = "wm8994-codec.0-0x1a", + .codec_name = "wm8994-codec.0-001a", .init = goni_wm8994_init, .ops = &goni_hifi_ops, }, { @@ -247,7 +247,7 @@ static struct snd_soc_dai_link goni_dai[] = { .cpu_dai_name = "goni-voice-dai", .codec_dai_name = "wm8994-voice", .platform_name = "samsung-audio", - .codec_name = "wm8994-codec.0-0x1a", + .codec_name = "wm8994-codec.0-001a", .ops = &goni_voice_ops, }, }; -- cgit v0.10.2 From 69b91bc1551a2fc746a01fea9d3291e60be3780d Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Wed, 27 Apr 2011 18:24:35 +0100 Subject: ASoC: Fix CODEC DAI names for Goni Immediately after sending the last fix I realised that the CODEC DAI names also don't correspond to the WM8994 driver. Update the DAI names to match. Signed-off-by: Mark Brown Acked-by: Jassi Brar Acked-by: Liam Girdwood diff --git a/sound/soc/samsung/goni_wm8994.c b/sound/soc/samsung/goni_wm8994.c index 3a7861c..0e80dae 100644 --- a/sound/soc/samsung/goni_wm8994.c +++ b/sound/soc/samsung/goni_wm8994.c @@ -236,7 +236,7 @@ static struct snd_soc_dai_link goni_dai[] = { .name = "WM8994", .stream_name = "WM8994 HiFi", .cpu_dai_name = "samsung-i2s.0", - .codec_dai_name = "wm8994-hifi", + .codec_dai_name = "wm8994-aif1", .platform_name = "samsung-audio", .codec_name = "wm8994-codec.0-001a", .init = goni_wm8994_init, @@ -245,7 +245,7 @@ static struct snd_soc_dai_link goni_dai[] = { .name = "WM8994 Voice", .stream_name = "Voice", .cpu_dai_name = "goni-voice-dai", - .codec_dai_name = "wm8994-voice", + .codec_dai_name = "wm8994-aif2", .platform_name = "samsung-audio", .codec_name = "wm8994-codec.0-001a", .ops = &goni_voice_ops, -- cgit v0.10.2 From 8129e79ed7932bd11d60518d62434a0b687e5771 Mon Sep 17 00:00:00 2001 From: Wolfgang Breyha Date: Thu, 28 Apr 2011 16:18:40 +0200 Subject: ALSA: usb-audio - Terratec Aureon 7.1 USB ID as C-Media cm6206 quirks This patch adds support for the Terratec Aureon 7.1 USB which uses a C-Media cm6206 and needs all the quirks already found in the past. Signed-off-by: Wolfgang Breyha Signed-off-by: Takashi Iwai diff --git a/sound/usb/format.c b/sound/usb/format.c index 5b792d2..f079b5e 100644 --- a/sound/usb/format.c +++ b/sound/usb/format.c @@ -176,9 +176,11 @@ static int parse_audio_format_rates_v1(struct snd_usb_audio *chip, struct audiof if (!rate) continue; /* C-Media CM6501 mislabels its 96 kHz altsetting */ + /* Terratec Aureon 7.1 USB C-Media 6206, too */ if (rate == 48000 && nr_rates == 1 && (chip->usb_id == USB_ID(0x0d8c, 0x0201) || - chip->usb_id == USB_ID(0x0d8c, 0x0102)) && + chip->usb_id == USB_ID(0x0d8c, 0x0102) || + chip->usb_id == USB_ID(0x0ccd, 0x00b1)) && fp->altsetting == 5 && fp->maxpacksize == 392) rate = 96000; /* Creative VF0470 Live Cam reports 16 kHz instead of 8kHz */ diff --git a/sound/usb/quirks.c b/sound/usb/quirks.c index ec07e62..1b94ec3 100644 --- a/sound/usb/quirks.c +++ b/sound/usb/quirks.c @@ -533,6 +533,7 @@ int snd_usb_apply_boot_quirk(struct usb_device *dev, case USB_ID(0x0d8c, 0x0102): /* C-Media CM6206 / CM106-Like Sound Device */ + case USB_ID(0x0ccd, 0x00b1): /* Terratec Aureon 7.1 USB */ return snd_usb_cm6206_boot_quirk(dev); case USB_ID(0x133e, 0x0815): -- cgit v0.10.2 From b6020ba055c7f1ca901dc8751ecc7c9de58164db Mon Sep 17 00:00:00 2001 From: Waldemar Rymarkiewicz Date: Thu, 28 Apr 2011 12:07:53 +0200 Subject: Bluetooth: Add definitions for link key types Introduce the link key types defs and use them instead of magic numbers. Signed-off-by: Waldemar Rymarkiewicz Signed-off-by: Gustavo F. Padovan diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h index 6138e31..e0a3cf1 100644 --- a/include/net/bluetooth/hci.h +++ b/include/net/bluetooth/hci.h @@ -246,6 +246,15 @@ enum { #define HCI_AT_GENERAL_BONDING 0x04 #define HCI_AT_GENERAL_BONDING_MITM 0x05 +/* Link Key types */ +#define HCI_LK_COMBINATION 0x00 +#define HCI_LK_LOCAL_UNIT 0x01 +#define HCI_LK_REMOTE_UNIT 0x02 +#define HCI_LK_DEBUG_COMBINATION 0x03 +#define HCI_LK_UNAUTH_COMBINATION 0x04 +#define HCI_LK_AUTH_COMBINATION 0x05 +#define HCI_LK_CHANGED_COMBINATION 0x06 + /* ----- HCI Commands ---- */ #define HCI_OP_NOP 0x0000 diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 98aa24b..07d0ba3 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -1050,7 +1050,7 @@ int hci_add_link_key(struct hci_dev *hdev, int new_key, bdaddr_t *bdaddr, if (new_key) mgmt_new_key(hdev->id, key, old_key_type); - if (type == 0x06) + if (type == HCI_LK_CHANGED_COMBINATION) key->type = old_key_type; return 0; diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index e64a3de..fbbb63f 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -2053,15 +2053,16 @@ static inline void hci_link_key_request_evt(struct hci_dev *hdev, struct sk_buff BT_DBG("%s found key type %u for %s", hdev->name, key->type, batostr(&ev->bdaddr)); - if (!test_bit(HCI_DEBUG_KEYS, &hdev->flags) && key->type == 0x03) { + if (!test_bit(HCI_DEBUG_KEYS, &hdev->flags) && + key->type == HCI_LK_DEBUG_COMBINATION) { BT_DBG("%s ignoring debug key", hdev->name); goto not_found; } conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &ev->bdaddr); - if (key->type == 0x04 && conn && conn->auth_type != 0xff && - (conn->auth_type & 0x01)) { + if (key->type == HCI_LK_UNAUTH_COMBINATION && conn && + conn->auth_type != 0xff && (conn->auth_type & 0x01)) { BT_DBG("%s ignoring unauthenticated key", hdev->name); goto not_found; } -- cgit v0.10.2 From 9003c4e220c2954a53c5da0d739ed15a46c13429 Mon Sep 17 00:00:00 2001 From: Waldemar Rymarkiewicz Date: Thu, 28 Apr 2011 12:07:54 +0200 Subject: Bluetooth: Don't modify sec_level if auth failed If authentication fails the security level should stay as it was set before the process has started. Setting BT_SECURITY_LOW can hide real security level on a link eg. having BT_SECURITY_MEDIUM on the link, re-authenticate with failure to get BT_SECURITY_HIGH, as a result we get BT_SECURITY_LOW on the link while the real security is still medium. Signed-off-by: Waldemar Rymarkiewicz Signed-off-by: Gustavo F. Padovan diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index fbbb63f..35f9898 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -1459,7 +1459,6 @@ static inline void hci_auth_complete_evt(struct hci_dev *hdev, struct sk_buff *s conn->sec_level = conn->pending_sec_level; } else { mgmt_auth_failed(hdev->id, &conn->dst, ev->status); - conn->sec_level = BT_SECURITY_LOW; } clear_bit(HCI_CONN_AUTH_PEND, &conn->pend); -- cgit v0.10.2 From 13d39315c22b128f4796fc008b04914a7c32bb1a Mon Sep 17 00:00:00 2001 From: Waldemar Rymarkiewicz Date: Thu, 28 Apr 2011 12:07:55 +0200 Subject: Bluetooth: Map sec_level to link key requirements Keep the link key type together with connection and use it to map security level to link key requirements. Authenticate and/or encrypt connection if the link is insufficiently secure. Signed-off-by: Waldemar Rymarkiewicz Signed-off-by: Gustavo F. Padovan diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index 69967e5..2da2eb9 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -226,6 +226,7 @@ struct hci_conn { __u16 pkt_type; __u16 link_policy; __u32 link_mode; + __u8 key_type; __u8 auth_type; __u8 sec_level; __u8 pending_sec_level; diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c index 7a6f56b..74cd755 100644 --- a/net/bluetooth/hci_conn.c +++ b/net/bluetooth/hci_conn.c @@ -287,6 +287,7 @@ struct hci_conn *hci_conn_add(struct hci_dev *hdev, int type, bdaddr_t *dst) conn->auth_type = HCI_AT_GENERAL_BONDING; conn->io_capability = hdev->io_capability; conn->remote_auth = 0xff; + conn->key_type = 0xff; conn->power_save = 1; conn->disc_timeout = HCI_DISCONN_TIMEOUT; @@ -535,32 +536,72 @@ static int hci_conn_auth(struct hci_conn *conn, __u8 sec_level, __u8 auth_type) return 0; } +/* Encrypt the the link */ +static void hci_conn_encrypt(struct hci_conn *conn) +{ + BT_DBG("conn %p", conn); + + if (!test_and_set_bit(HCI_CONN_ENCRYPT_PEND, &conn->pend)) { + struct hci_cp_set_conn_encrypt cp; + cp.handle = cpu_to_le16(conn->handle); + cp.encrypt = 0x01; + hci_send_cmd(conn->hdev, HCI_OP_SET_CONN_ENCRYPT, sizeof(cp), + &cp); + } +} + /* Enable security */ int hci_conn_security(struct hci_conn *conn, __u8 sec_level, __u8 auth_type) { BT_DBG("conn %p", conn); + /* For sdp we don't need the link key. */ if (sec_level == BT_SECURITY_SDP) return 1; + /* For non 2.1 devices and low security level we don't need the link + key. */ if (sec_level == BT_SECURITY_LOW && (!conn->ssp_mode || !conn->hdev->ssp_mode)) return 1; - if (conn->link_mode & HCI_LM_ENCRYPT) - return hci_conn_auth(conn, sec_level, auth_type); - + /* For other security levels we need the link key. */ + if (!(conn->link_mode & HCI_LM_AUTH)) + goto auth; + + /* An authenticated combination key has sufficient security for any + security level. */ + if (conn->key_type == HCI_LK_AUTH_COMBINATION) + goto encrypt; + + /* An unauthenticated combination key has sufficient security for + security level 1 and 2. */ + if (conn->key_type == HCI_LK_UNAUTH_COMBINATION && + (sec_level == BT_SECURITY_MEDIUM || + sec_level == BT_SECURITY_LOW)) + goto encrypt; + + /* A combination key has always sufficient security for the security + levels 1 or 2. High security level requires the combination key + is generated using maximum PIN code length (16). + For pre 2.1 units. */ + if (conn->key_type == HCI_LK_COMBINATION && + (sec_level != BT_SECURITY_HIGH || + conn->pin_length == 16)) + goto encrypt; + +auth: if (test_and_set_bit(HCI_CONN_ENCRYPT_PEND, &conn->pend)) return 0; - if (hci_conn_auth(conn, sec_level, auth_type)) { - struct hci_cp_set_conn_encrypt cp; - cp.handle = cpu_to_le16(conn->handle); - cp.encrypt = 1; - hci_send_cmd(conn->hdev, HCI_OP_SET_CONN_ENCRYPT, - sizeof(cp), &cp); - } + hci_conn_auth(conn, sec_level, auth_type); + return 0; + +encrypt: + if (conn->link_mode & HCI_LM_ENCRYPT) + return 1; + hci_conn_encrypt(conn); return 0; } EXPORT_SYMBOL(hci_conn_security); diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index 35f9898..655af8b 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -2095,6 +2095,10 @@ static inline void hci_link_key_notify_evt(struct hci_dev *hdev, struct sk_buff hci_conn_hold(conn); conn->disc_timeout = HCI_DISCONN_TIMEOUT; pin_len = conn->pin_length; + + if (ev->key_type != HCI_LK_CHANGED_COMBINATION) + conn->key_type = ev->key_type; + hci_conn_put(conn); } -- cgit v0.10.2 From 60b83f571cf17a7a8ca9ddf2090db63e6a594571 Mon Sep 17 00:00:00 2001 From: Waldemar Rymarkiewicz Date: Thu, 28 Apr 2011 12:07:56 +0200 Subject: Bluetooth: Ignore key unauthenticated for high security High security level for pre v2.1 devices requires combination link key authenticated by at least 16 digit PIN code. It's also necessary to update key_type and pin_length when the key exists and is sufficently secured for the connection as there will be no link key notify event in that case. Signed-off-by: Waldemar Rymarkiewicz Signed-off-by: Gustavo F. Padovan diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index 655af8b..40e96cd 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -2059,11 +2059,23 @@ static inline void hci_link_key_request_evt(struct hci_dev *hdev, struct sk_buff } conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &ev->bdaddr); + if (conn) { + if (key->type == HCI_LK_UNAUTH_COMBINATION && + conn->auth_type != 0xff && + (conn->auth_type & 0x01)) { + BT_DBG("%s ignoring unauthenticated key", hdev->name); + goto not_found; + } - if (key->type == HCI_LK_UNAUTH_COMBINATION && conn && - conn->auth_type != 0xff && (conn->auth_type & 0x01)) { - BT_DBG("%s ignoring unauthenticated key", hdev->name); - goto not_found; + if (key->type == HCI_LK_COMBINATION && key->pin_len < 16 && + conn->pending_sec_level == BT_SECURITY_HIGH) { + BT_DBG("%s ignoring key unauthenticated for high \ + security", hdev->name); + goto not_found; + } + + conn->key_type = key->type; + conn->pin_length = key->pin_len; } bacpy(&cp.bdaddr, &ev->bdaddr); -- cgit v0.10.2 From 58797bf77234154a84827186bda316a1205bde05 Mon Sep 17 00:00:00 2001 From: Waldemar Rymarkiewicz Date: Thu, 28 Apr 2011 12:07:58 +0200 Subject: Bluetooth: Respect local MITM req in io_cap reply If host requires MITM protection notify that to controller in io capabilities reply even if the remote device requires no bonding. If it is not respected, host can get an unauthenticated link key while it expects authenticated one. Signed-off-by: Waldemar Rymarkiewicz Signed-off-by: Gustavo F. Padovan diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index 40e96cd..9d50e90 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -2397,7 +2397,7 @@ static inline u8 hci_get_auth_req(struct hci_conn *conn) /* If remote requests no-bonding follow that lead */ if (conn->remote_auth == 0x00 || conn->remote_auth == 0x01) - return 0x00; + return conn->remote_auth | (conn->auth_type & 0x01); return conn->auth_type; } -- cgit v0.10.2 From a770bb5aea84ee2509d4775f9959665f96da3b9d Mon Sep 17 00:00:00 2001 From: Waldemar Rymarkiewicz Date: Thu, 28 Apr 2011 12:07:59 +0200 Subject: Bluetooth: Add secure flag for mgmt_pin_code_req Extend the mgmt_pin_code_request interface to require secure pin code (16 digit) for authentication. This is a kernel part of the secure pin code requirement notification to user space agent. Code styling fix by Johan Hedberg. Signed-off-by: Waldemar Rymarkiewicz Signed-off-by: Johan Hedberg Signed-off-by: Gustavo F. Padovan diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index 2da2eb9..2995e2e 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -777,7 +777,7 @@ int mgmt_connected(u16 index, bdaddr_t *bdaddr); int mgmt_disconnected(u16 index, bdaddr_t *bdaddr); int mgmt_disconnect_failed(u16 index); int mgmt_connect_failed(u16 index, bdaddr_t *bdaddr, u8 status); -int mgmt_pin_code_request(u16 index, bdaddr_t *bdaddr); +int mgmt_pin_code_request(u16 index, bdaddr_t *bdaddr, u8 secure); int mgmt_pin_code_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status); int mgmt_pin_code_neg_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status); int mgmt_user_confirm_request(u16 index, bdaddr_t *bdaddr, __le32 value); diff --git a/include/net/bluetooth/mgmt.h b/include/net/bluetooth/mgmt.h index 7434406..0e7de63 100644 --- a/include/net/bluetooth/mgmt.h +++ b/include/net/bluetooth/mgmt.h @@ -253,6 +253,7 @@ struct mgmt_ev_connect_failed { #define MGMT_EV_PIN_CODE_REQUEST 0x000E struct mgmt_ev_pin_code_request { bdaddr_t bdaddr; + __u8 secure; } __packed; #define MGMT_EV_USER_CONFIRM_REQUEST 0x000F diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index 9d50e90..577d638 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -2022,8 +2022,16 @@ static inline void hci_pin_code_request_evt(struct hci_dev *hdev, struct sk_buff hci_send_cmd(hdev, HCI_OP_PIN_CODE_NEG_REPLY, sizeof(ev->bdaddr), &ev->bdaddr); - if (test_bit(HCI_MGMT, &hdev->flags)) - mgmt_pin_code_request(hdev->id, &ev->bdaddr); + if (test_bit(HCI_MGMT, &hdev->flags)) { + u8 secure; + + if (conn->pending_sec_level == BT_SECURITY_HIGH) + secure = 1; + else + secure = 0; + + mgmt_pin_code_request(hdev->id, &ev->bdaddr, secure); + } hci_dev_unlock(hdev); } diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 4542396..a7b4937 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -1942,11 +1942,12 @@ int mgmt_connect_failed(u16 index, bdaddr_t *bdaddr, u8 status) return mgmt_event(MGMT_EV_CONNECT_FAILED, index, &ev, sizeof(ev), NULL); } -int mgmt_pin_code_request(u16 index, bdaddr_t *bdaddr) +int mgmt_pin_code_request(u16 index, bdaddr_t *bdaddr, u8 secure) { struct mgmt_ev_pin_code_request ev; bacpy(&ev.bdaddr, bdaddr); + ev.secure = secure; return mgmt_event(MGMT_EV_PIN_CODE_REQUEST, index, &ev, sizeof(ev), NULL); -- cgit v0.10.2 From 6d4831c283530a5f2c6bd8172c13efa236eb149d Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Wed, 27 Apr 2011 15:26:41 -0700 Subject: vfs: avoid large kmalloc()s for the fdtable Azurit reports large increases in system time after 2.6.36 when running Apache. It was bisected down to a892e2d7dcdfa6c76e6 ("vfs: use kmalloc() to allocate fdmem if possible"). That patch caused the vfs to use kmalloc() for very large allocations and this is causing excessive work (and presumably excessive reclaim) within the page allocator. Fix it by falling back to vmalloc() earlier - when the allocation attempt would have been considered "costly" by reclaim. Reported-by: azurIt Tested-by: azurIt Acked-by: Changli Gao Cc: Americo Wang Cc: Jiri Slaby Acked-by: Eric Dumazet Cc: Mel Gorman Cc: Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/fs/file.c b/fs/file.c index 0be3447..4c6992d 100644 --- a/fs/file.c +++ b/fs/file.c @@ -9,6 +9,7 @@ #include #include #include +#include #include #include #include @@ -39,14 +40,17 @@ int sysctl_nr_open_max = 1024 * 1024; /* raised later */ */ static DEFINE_PER_CPU(struct fdtable_defer, fdtable_defer_list); -static inline void *alloc_fdmem(unsigned int size) +static void *alloc_fdmem(unsigned int size) { - void *data; - - data = kmalloc(size, GFP_KERNEL|__GFP_NOWARN); - if (data != NULL) - return data; - + /* + * Very large allocations can stress page reclaim, so fall back to + * vmalloc() if the allocation size will be considered "large" by the VM. + */ + if (size <= (PAGE_SIZE << PAGE_ALLOC_COSTLY_ORDER)) { + void *data = kmalloc(size, GFP_KERNEL|__GFP_NOWARN); + if (data != NULL) + return data; + } return vmalloc(size); } -- cgit v0.10.2 From 78f11a255749d09025f54d4e2df4fbcb031530e2 Mon Sep 17 00:00:00 2001 From: Andrea Arcangeli Date: Wed, 27 Apr 2011 15:26:45 -0700 Subject: mm: thp: fix /dev/zero MAP_PRIVATE and vm_flags cleanups The huge_memory.c THP page fault was allowed to run if vm_ops was null (which would succeed for /dev/zero MAP_PRIVATE, as the f_op->mmap wouldn't setup a special vma->vm_ops and it would fallback to regular anonymous memory) but other THP logics weren't fully activated for vmas with vm_file not NULL (/dev/zero has a not NULL vma->vm_file). So this removes the vm_file checks so that /dev/zero also can safely use THP (the other albeit safer approach to fix this bug would have been to prevent the THP initial page fault to run if vm_file was set). After removing the vm_file checks, this also makes huge_memory.c stricter in khugepaged for the DEBUG_VM=y case. It doesn't replace the vm_file check with a is_pfn_mapping check (but it keeps checking for VM_PFNMAP under VM_BUG_ON) because for a is_cow_mapping() mapping VM_PFNMAP should only be allowed to exist before the first page fault, and in turn when vma->anon_vma is null (so preventing khugepaged registration). So I tend to think the previous comment saying if vm_file was set, VM_PFNMAP might have been set and we could still be registered in khugepaged (despite anon_vma was not NULL to be registered in khugepaged) was too paranoid. The is_linear_pfn_mapping check is also I think superfluous (as described by comment) but under DEBUG_VM it is safe to stay. Addresses https://bugzilla.kernel.org/show_bug.cgi?id=33682 Signed-off-by: Andrea Arcangeli Reported-by: Caspar Zhang Acked-by: Mel Gorman Acked-by: Rik van Riel Cc: [2.6.38.x] Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/include/linux/huge_mm.h b/include/linux/huge_mm.h index df29c8f..8847c8c 100644 --- a/include/linux/huge_mm.h +++ b/include/linux/huge_mm.h @@ -117,7 +117,7 @@ static inline void vma_adjust_trans_huge(struct vm_area_struct *vma, unsigned long end, long adjust_next) { - if (!vma->anon_vma || vma->vm_ops || vma->vm_file) + if (!vma->anon_vma || vma->vm_ops) return; __vma_adjust_trans_huge(vma, start, end, adjust_next); } diff --git a/include/linux/mm.h b/include/linux/mm.h index 692dbae..2348db2 100644 --- a/include/linux/mm.h +++ b/include/linux/mm.h @@ -137,7 +137,8 @@ extern unsigned int kobjsize(const void *objp); #define VM_RandomReadHint(v) ((v)->vm_flags & VM_RAND_READ) /* - * special vmas that are non-mergable, non-mlock()able + * Special vmas that are non-mergable, non-mlock()able. + * Note: mm/huge_memory.c VM_NO_THP depends on this definition. */ #define VM_SPECIAL (VM_IO | VM_DONTEXPAND | VM_RESERVED | VM_PFNMAP) diff --git a/mm/huge_memory.c b/mm/huge_memory.c index 470dcda..83326ad 100644 --- a/mm/huge_memory.c +++ b/mm/huge_memory.c @@ -1408,6 +1408,9 @@ out: return ret; } +#define VM_NO_THP (VM_SPECIAL|VM_INSERTPAGE|VM_MIXEDMAP|VM_SAO| \ + VM_HUGETLB|VM_SHARED|VM_MAYSHARE) + int hugepage_madvise(struct vm_area_struct *vma, unsigned long *vm_flags, int advice) { @@ -1416,11 +1419,7 @@ int hugepage_madvise(struct vm_area_struct *vma, /* * Be somewhat over-protective like KSM for now! */ - if (*vm_flags & (VM_HUGEPAGE | - VM_SHARED | VM_MAYSHARE | - VM_PFNMAP | VM_IO | VM_DONTEXPAND | - VM_RESERVED | VM_HUGETLB | VM_INSERTPAGE | - VM_MIXEDMAP | VM_SAO)) + if (*vm_flags & (VM_HUGEPAGE | VM_NO_THP)) return -EINVAL; *vm_flags &= ~VM_NOHUGEPAGE; *vm_flags |= VM_HUGEPAGE; @@ -1436,11 +1435,7 @@ int hugepage_madvise(struct vm_area_struct *vma, /* * Be somewhat over-protective like KSM for now! */ - if (*vm_flags & (VM_NOHUGEPAGE | - VM_SHARED | VM_MAYSHARE | - VM_PFNMAP | VM_IO | VM_DONTEXPAND | - VM_RESERVED | VM_HUGETLB | VM_INSERTPAGE | - VM_MIXEDMAP | VM_SAO)) + if (*vm_flags & (VM_NOHUGEPAGE | VM_NO_THP)) return -EINVAL; *vm_flags &= ~VM_HUGEPAGE; *vm_flags |= VM_NOHUGEPAGE; @@ -1574,10 +1569,14 @@ int khugepaged_enter_vma_merge(struct vm_area_struct *vma) * page fault if needed. */ return 0; - if (vma->vm_file || vma->vm_ops) + if (vma->vm_ops) /* khugepaged not yet working on file or special mappings */ return 0; - VM_BUG_ON(is_linear_pfn_mapping(vma) || is_pfn_mapping(vma)); + /* + * If is_pfn_mapping() is true is_learn_pfn_mapping() must be + * true too, verify it here. + */ + VM_BUG_ON(is_linear_pfn_mapping(vma) || vma->vm_flags & VM_NO_THP); hstart = (vma->vm_start + ~HPAGE_PMD_MASK) & HPAGE_PMD_MASK; hend = vma->vm_end & HPAGE_PMD_MASK; if (hstart < hend) @@ -1828,12 +1827,15 @@ static void collapse_huge_page(struct mm_struct *mm, (vma->vm_flags & VM_NOHUGEPAGE)) goto out; - /* VM_PFNMAP vmas may have vm_ops null but vm_file set */ - if (!vma->anon_vma || vma->vm_ops || vma->vm_file) + if (!vma->anon_vma || vma->vm_ops) goto out; if (is_vma_temporary_stack(vma)) goto out; - VM_BUG_ON(is_linear_pfn_mapping(vma) || is_pfn_mapping(vma)); + /* + * If is_pfn_mapping() is true is_learn_pfn_mapping() must be + * true too, verify it here. + */ + VM_BUG_ON(is_linear_pfn_mapping(vma) || vma->vm_flags & VM_NO_THP); pgd = pgd_offset(mm, address); if (!pgd_present(*pgd)) @@ -2066,13 +2068,16 @@ static unsigned int khugepaged_scan_mm_slot(unsigned int pages, progress++; continue; } - /* VM_PFNMAP vmas may have vm_ops null but vm_file set */ - if (!vma->anon_vma || vma->vm_ops || vma->vm_file) + if (!vma->anon_vma || vma->vm_ops) goto skip; if (is_vma_temporary_stack(vma)) goto skip; - - VM_BUG_ON(is_linear_pfn_mapping(vma) || is_pfn_mapping(vma)); + /* + * If is_pfn_mapping() is true is_learn_pfn_mapping() + * must be true too, verify it here. + */ + VM_BUG_ON(is_linear_pfn_mapping(vma) || + vma->vm_flags & VM_NO_THP); hstart = (vma->vm_start + ~HPAGE_PMD_MASK) & HPAGE_PMD_MASK; hend = vma->vm_end & HPAGE_PMD_MASK; -- cgit v0.10.2 From c446808575150477f23625a60e0867960a110e23 Mon Sep 17 00:00:00 2001 From: Ian Campbell Date: Wed, 27 Apr 2011 15:26:46 -0700 Subject: MAINTAINERS: re-alphabetize Xen entries Signed-off-by: Ian Campbell Acked-by: Konrad Rzeszutek Wilk Cc: Jeremy Fitzhardinge Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/MAINTAINERS b/MAINTAINERS index 1380312..0a8eb1a 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -6921,6 +6921,18 @@ T: git git://git.kernel.org/pub/scm/linux/kernel/git/mjg59/platform-drivers-x86. S: Maintained F: drivers/platform/x86 +XEN HYPERVISOR INTERFACE +M: Jeremy Fitzhardinge +M: Konrad Rzeszutek Wilk +L: xen-devel@lists.xensource.com (moderated for non-subscribers) +L: virtualization@lists.linux-foundation.org +S: Supported +F: arch/x86/xen/ +F: drivers/*/xen-*front.c +F: drivers/xen/ +F: arch/x86/include/asm/xen/ +F: include/xen/ + XEN NETWORK BACKEND DRIVER M: Ian Campbell L: xen-devel@lists.xensource.com (moderated for non-subscribers) @@ -6942,18 +6954,6 @@ S: Supported F: arch/x86/xen/*swiotlb* F: drivers/xen/*swiotlb* -XEN HYPERVISOR INTERFACE -M: Jeremy Fitzhardinge -M: Konrad Rzeszutek Wilk -L: xen-devel@lists.xensource.com (moderated for non-subscribers) -L: virtualization@lists.linux-foundation.org -S: Supported -F: arch/x86/xen/ -F: drivers/*/xen-*front.c -F: drivers/xen/ -F: arch/x86/include/asm/xen/ -F: include/xen/ - XFS FILESYSTEM P: Silicon Graphics Inc M: Alex Elder -- cgit v0.10.2 From 98909cf0d125eb0110afe92d0b419be7fa097f78 Mon Sep 17 00:00:00 2001 From: Kukjin Kim Date: Wed, 27 Apr 2011 15:26:47 -0700 Subject: MAINTAINERS: update Documentation file entry of GPIO subsystem Signed-off-by: Kukjin Kim Cc: Grant Likely Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/MAINTAINERS b/MAINTAINERS index 0a8eb1a..21e7aca 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -2808,7 +2808,7 @@ GPIO SUBSYSTEM M: Grant Likely S: Maintained T: git git://git.secretlab.ca/git/linux-2.6.git -F: Documentation/gpio/gpio.txt +F: Documentation/gpio.txt F: drivers/gpio/ F: include/linux/gpio* -- cgit v0.10.2 From a111c966a65e4b5d9c6fd2d8459978c1407077d5 Mon Sep 17 00:00:00 2001 From: Daisuke Nishimura Date: Wed, 27 Apr 2011 15:26:48 -0700 Subject: memcg: update documentation to describe usage_in_bytes Since 569b846d ("memcg: coalesce uncharge during unmap/truncate"), we do batched (delayed) uncharge at truncation/unmap. And since cdec2e42(memcg: coalesce charging via percpu storage), we have percpu cache for res_counter. These changes improved performance of memory cgroup very much, but made res_counter->usage usually have a bigger value than the actual value of memory usage. So, *.usage_in_bytes, which show res_counter->usage, are not desirable for precise values of memory(and swap) usage anymore. Instead of removing these files completely(because we cannot know res_counter->usage without them), this patch updates the meaning of those files. Signed-off-by: Daisuke Nishimura Acked-by: KAMEZAWA Hiroyuki Acked-by: Michal Hocko Cc: Balbir Singh Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/Documentation/cgroups/memory.txt b/Documentation/cgroups/memory.txt index b6ed61c9..7c16347 100644 --- a/Documentation/cgroups/memory.txt +++ b/Documentation/cgroups/memory.txt @@ -52,8 +52,10 @@ Brief summary of control files. tasks # attach a task(thread) and show list of threads cgroup.procs # show list of processes cgroup.event_control # an interface for event_fd() - memory.usage_in_bytes # show current memory(RSS+Cache) usage. - memory.memsw.usage_in_bytes # show current memory+Swap usage + memory.usage_in_bytes # show current res_counter usage for memory + (See 5.5 for details) + memory.memsw.usage_in_bytes # show current res_counter usage for memory+Swap + (See 5.5 for details) memory.limit_in_bytes # set/show limit of memory usage memory.memsw.limit_in_bytes # set/show limit of memory+Swap usage memory.failcnt # show the number of memory usage hits limits @@ -453,6 +455,15 @@ memory under it will be reclaimed. You can reset failcnt by writing 0 to failcnt file. # echo 0 > .../memory.failcnt +5.5 usage_in_bytes + +For efficiency, as other kernel components, memory cgroup uses some optimization +to avoid unnecessary cacheline false sharing. usage_in_bytes is affected by the +method and doesn't show 'exact' value of memory(and swap) usage, it's an fuzz +value for efficient access. (Of course, when necessary, it's synchronized.) +If you want to know more exact memory usage, you should use RSS+CACHE(+SWAP) +value in memory.stat(see 5.2). + 6. Hierarchy support The memory controller supports a deep hierarchy and hierarchical accounting. -- cgit v0.10.2 From 0dcecae203cd407678e7257efbc9cdd0130967cf Mon Sep 17 00:00:00 2001 From: Kukjin Kim Date: Wed, 27 Apr 2011 15:26:49 -0700 Subject: MAINTAINERS: add EXYNOS ARM architectures Signed-off-by: Kukjin Kim Cc: Ben Dooks Cc: Russell King Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/MAINTAINERS b/MAINTAINERS index 21e7aca..2199ba1 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1032,12 +1032,13 @@ W: http://www.fluff.org/ben/linux/ S: Maintained F: arch/arm/mach-s3c64xx/ -ARM/S5P ARM ARCHITECTURES +ARM/S5P EXYNOS ARM ARCHITECTURES M: Kukjin Kim L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers) L: linux-samsung-soc@vger.kernel.org (moderated for non-subscribers) S: Maintained F: arch/arm/mach-s5p*/ +F: arch/arm/mach-exynos*/ ARM/SAMSUNG MOBILE MACHINE SUPPORT M: Kyungmin Park -- cgit v0.10.2 From f755a042d82b51b54f3bdd0890e5ea56c0fb6807 Mon Sep 17 00:00:00 2001 From: KOSAKI Motohiro Date: Wed, 27 Apr 2011 15:26:50 -0700 Subject: oom: use pte pages in OOM score PTE pages eat up memory just like anything else, but we do not account for them in any way in the OOM scores. They are also _guaranteed_ to get freed up when a process is OOM killed, while RSS is not. Reported-by: Dave Hansen Signed-off-by: KOSAKI Motohiro Cc: Hugh Dickins Cc: KAMEZAWA Hiroyuki Cc: Oleg Nesterov Acked-by: David Rientjes Cc: [2.6.36+] Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/mm/oom_kill.c b/mm/oom_kill.c index 83fb72c1..f52e85c 100644 --- a/mm/oom_kill.c +++ b/mm/oom_kill.c @@ -172,10 +172,13 @@ unsigned int oom_badness(struct task_struct *p, struct mem_cgroup *mem, /* * The baseline for the badness score is the proportion of RAM that each - * task's rss and swap space use. + * task's rss, pagetable and swap space use. */ - points = (get_mm_rss(p->mm) + get_mm_counter(p->mm, MM_SWAPENTS)) * 1000 / - totalpages; + points = get_mm_rss(p->mm) + p->mm->nr_ptes; + points += get_mm_counter(p->mm, MM_SWAPENTS); + + points *= 1000; + points /= totalpages; task_unlock(p); /* -- cgit v0.10.2 From 57d8e02e3cd21bccf2b84b26b42feb79e1f0f83e Mon Sep 17 00:00:00 2001 From: Richard Weinberger Date: Wed, 27 Apr 2011 15:26:51 -0700 Subject: um: mdd support for 64 bit atomic operations This adds support for 64 bit atomic operations on 32 bit UML systems. XFS needs them since 2.6.38. $ make ARCH=um SUBARCH=i386 ... LD .tmp_vmlinux1 fs/built-in.o: In function `xlog_regrant_reserve_log_space': xfs_log.c:(.text+0xd8584): undefined reference to `atomic64_read_386' xfs_log.c:(.text+0xd85ac): undefined reference to `cmpxchg8b_emu' ... Addresses https://bugzilla.kernel.org/show_bug.cgi?id=32812 Reported-by: Martin Walch Tested-by: Martin Walch Cc: Martin Walch Cc: [2.6.38.x 084189a: um: disable CONFIG_CMPXCHG_LOCAL] Signed-off-by: Richard Weinberger Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/arch/um/sys-i386/Makefile b/arch/um/sys-i386/Makefile index 804b28d..b1da91c 100644 --- a/arch/um/sys-i386/Makefile +++ b/arch/um/sys-i386/Makefile @@ -4,7 +4,7 @@ obj-y = bug.o bugs.o checksum.o delay.o fault.o ksyms.o ldt.o ptrace.o \ ptrace_user.o setjmp.o signal.o stub.o stub_segv.o syscalls.o sysrq.o \ - sys_call_table.o tls.o + sys_call_table.o tls.o atomic64_cx8_32.o obj-$(CONFIG_BINFMT_ELF) += elfcore.o diff --git a/arch/um/sys-i386/atomic64_cx8_32.S b/arch/um/sys-i386/atomic64_cx8_32.S new file mode 100644 index 0000000..1e901d3 --- /dev/null +++ b/arch/um/sys-i386/atomic64_cx8_32.S @@ -0,0 +1,225 @@ +/* + * atomic64_t for 586+ + * + * Copied from arch/x86/lib/atomic64_cx8_32.S + * + * Copyright © 2010 Luca Barbieri + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + */ + +#include +#include +#include + +.macro SAVE reg + pushl_cfi %\reg + CFI_REL_OFFSET \reg, 0 +.endm + +.macro RESTORE reg + popl_cfi %\reg + CFI_RESTORE \reg +.endm + +.macro read64 reg + movl %ebx, %eax + movl %ecx, %edx +/* we need LOCK_PREFIX since otherwise cmpxchg8b always does the write */ + LOCK_PREFIX + cmpxchg8b (\reg) +.endm + +ENTRY(atomic64_read_cx8) + CFI_STARTPROC + + read64 %ecx + ret + CFI_ENDPROC +ENDPROC(atomic64_read_cx8) + +ENTRY(atomic64_set_cx8) + CFI_STARTPROC + +1: +/* we don't need LOCK_PREFIX since aligned 64-bit writes + * are atomic on 586 and newer */ + cmpxchg8b (%esi) + jne 1b + + ret + CFI_ENDPROC +ENDPROC(atomic64_set_cx8) + +ENTRY(atomic64_xchg_cx8) + CFI_STARTPROC + + movl %ebx, %eax + movl %ecx, %edx +1: + LOCK_PREFIX + cmpxchg8b (%esi) + jne 1b + + ret + CFI_ENDPROC +ENDPROC(atomic64_xchg_cx8) + +.macro addsub_return func ins insc +ENTRY(atomic64_\func\()_return_cx8) + CFI_STARTPROC + SAVE ebp + SAVE ebx + SAVE esi + SAVE edi + + movl %eax, %esi + movl %edx, %edi + movl %ecx, %ebp + + read64 %ebp +1: + movl %eax, %ebx + movl %edx, %ecx + \ins\()l %esi, %ebx + \insc\()l %edi, %ecx + LOCK_PREFIX + cmpxchg8b (%ebp) + jne 1b + +10: + movl %ebx, %eax + movl %ecx, %edx + RESTORE edi + RESTORE esi + RESTORE ebx + RESTORE ebp + ret + CFI_ENDPROC +ENDPROC(atomic64_\func\()_return_cx8) +.endm + +addsub_return add add adc +addsub_return sub sub sbb + +.macro incdec_return func ins insc +ENTRY(atomic64_\func\()_return_cx8) + CFI_STARTPROC + SAVE ebx + + read64 %esi +1: + movl %eax, %ebx + movl %edx, %ecx + \ins\()l $1, %ebx + \insc\()l $0, %ecx + LOCK_PREFIX + cmpxchg8b (%esi) + jne 1b + +10: + movl %ebx, %eax + movl %ecx, %edx + RESTORE ebx + ret + CFI_ENDPROC +ENDPROC(atomic64_\func\()_return_cx8) +.endm + +incdec_return inc add adc +incdec_return dec sub sbb + +ENTRY(atomic64_dec_if_positive_cx8) + CFI_STARTPROC + SAVE ebx + + read64 %esi +1: + movl %eax, %ebx + movl %edx, %ecx + subl $1, %ebx + sbb $0, %ecx + js 2f + LOCK_PREFIX + cmpxchg8b (%esi) + jne 1b + +2: + movl %ebx, %eax + movl %ecx, %edx + RESTORE ebx + ret + CFI_ENDPROC +ENDPROC(atomic64_dec_if_positive_cx8) + +ENTRY(atomic64_add_unless_cx8) + CFI_STARTPROC + SAVE ebp + SAVE ebx +/* these just push these two parameters on the stack */ + SAVE edi + SAVE esi + + movl %ecx, %ebp + movl %eax, %esi + movl %edx, %edi + + read64 %ebp +1: + cmpl %eax, 0(%esp) + je 4f +2: + movl %eax, %ebx + movl %edx, %ecx + addl %esi, %ebx + adcl %edi, %ecx + LOCK_PREFIX + cmpxchg8b (%ebp) + jne 1b + + movl $1, %eax +3: + addl $8, %esp + CFI_ADJUST_CFA_OFFSET -8 + RESTORE ebx + RESTORE ebp + ret +4: + cmpl %edx, 4(%esp) + jne 2b + xorl %eax, %eax + jmp 3b + CFI_ENDPROC +ENDPROC(atomic64_add_unless_cx8) + +ENTRY(atomic64_inc_not_zero_cx8) + CFI_STARTPROC + SAVE ebx + + read64 %esi +1: + testl %eax, %eax + je 4f +2: + movl %eax, %ebx + movl %edx, %ecx + addl $1, %ebx + adcl $0, %ecx + LOCK_PREFIX + cmpxchg8b (%esi) + jne 1b + + movl $1, %eax +3: + RESTORE ebx + ret +4: + testl %edx, %edx + jne 2b + jmp 3b + CFI_ENDPROC +ENDPROC(atomic64_inc_not_zero_cx8) -- cgit v0.10.2 From 365a0deae2b6743b3263a71871bbd8c9f66ac34c Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Wed, 27 Apr 2011 15:26:53 -0700 Subject: uml: fix hppfs build Make HoneyPot ProcFS depend on CONFIG_PROC_FS so that it will build. Recommended by Christoph Hellwig. Addresses https://bugzilla.kernel.org/show_bug.cgi?id=33692 Reported-by: Simon Danner Signed-off-by: Randy Dunlap Cc: Jeff Dike Cc: Christoph Hellwig Signed-off-by: Richard Weinberger Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/arch/um/Kconfig.um b/arch/um/Kconfig.um index 90a438a..b5e675e 100644 --- a/arch/um/Kconfig.um +++ b/arch/um/Kconfig.um @@ -47,7 +47,7 @@ config HOSTFS config HPPFS tristate "HoneyPot ProcFS (EXPERIMENTAL)" - depends on EXPERIMENTAL + depends on EXPERIMENTAL && PROC_FS help hppfs (HoneyPot ProcFS) is a filesystem which allows UML /proc entries to be overridden, removed, or fabricated from the host. -- cgit v0.10.2 From 534e3adbd22efa327e6ff27cf2d8ebaad8382ecd Mon Sep 17 00:00:00 2001 From: Richard Weinberger Date: Wed, 27 Apr 2011 15:26:54 -0700 Subject: um: adjust current_thread_info() for newer gcc versions In some cases gcc >= 4.5.2 will optimize away current_thread_info(). To prevent gcc from doing so the stack address has to be obtained via inline asm. Signed-off-by: Richard Weinberger Acked-by: Kirill A. Shutemov Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/arch/um/include/asm/thread_info.h b/arch/um/include/asm/thread_info.h index e2cf786bd..5bd1bad 100644 --- a/arch/um/include/asm/thread_info.h +++ b/arch/um/include/asm/thread_info.h @@ -49,7 +49,10 @@ static inline struct thread_info *current_thread_info(void) { struct thread_info *ti; unsigned long mask = THREAD_SIZE - 1; - ti = (struct thread_info *) (((unsigned long) &ti) & ~mask); + void *p; + + asm volatile ("" : "=r" (p) : "0" (&ti)); + ti = (struct thread_info *) (((unsigned long)p) & ~mask); return ti; } -- cgit v0.10.2 From 1409f141ac719b994d2832911b1e9ec928943fc2 Mon Sep 17 00:00:00 2001 From: Hillf Danton Date: Wed, 27 Apr 2011 15:26:55 -0700 Subject: kernel/watchdog.c: disable nmi perf event in the error path of enabling watchdog In corner cases where softlockup watchdog is not setup successfully, the relevant nmi perf event for hardlockup watchdog could be disabled, then the status of the underlying hardware remains unchanged. Also, if the kthread doesn't start then the hrtimer won't run and the hardlockup detector will falsely fire. Signed-off-by: Hillf Danton Signed-off-by: Don Zickus Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/kernel/watchdog.c b/kernel/watchdog.c index 140dce7..14733d4 100644 --- a/kernel/watchdog.c +++ b/kernel/watchdog.c @@ -430,9 +430,12 @@ static int watchdog_enable(int cpu) p = kthread_create(watchdog, (void *)(unsigned long)cpu, "watchdog/%d", cpu); if (IS_ERR(p)) { printk(KERN_ERR "softlockup watchdog for %i failed\n", cpu); - if (!err) + if (!err) { /* if hardlockup hasn't already set this */ err = PTR_ERR(p); + /* and disable the perf event */ + watchdog_nmi_disable(cpu); + } goto out; } kthread_bind(p, cpu); -- cgit v0.10.2 From cc03638df20acbec5d0d0d9e07234aadde9e698d Mon Sep 17 00:00:00 2001 From: Mel Gorman Date: Wed, 27 Apr 2011 15:26:56 -0700 Subject: mm: check if PTE is already allocated during page fault With transparent hugepage support, handle_mm_fault() has to be careful that a normal PMD has been established before handling a PTE fault. To achieve this, it used __pte_alloc() directly instead of pte_alloc_map as pte_alloc_map is unsafe to run against a huge PMD. pte_offset_map() is called once it is known the PMD is safe. pte_alloc_map() is smart enough to check if a PTE is already present before calling __pte_alloc but this check was lost. As a consequence, PTEs may be allocated unnecessarily and the page table lock taken. Thi useless PTE does get cleaned up but it's a performance hit which is visible in page_test from aim9. This patch simply re-adds the check normally done by pte_alloc_map to check if the PTE needs to be allocated before taking the page table lock. The effect is noticable in page_test from aim9. AIM9 2.6.38-vanilla 2.6.38-checkptenone creat-clo 446.10 ( 0.00%) 424.47 (-5.10%) page_test 38.10 ( 0.00%) 42.04 ( 9.37%) brk_test 52.45 ( 0.00%) 51.57 (-1.71%) exec_test 382.00 ( 0.00%) 456.90 (16.39%) fork_test 60.11 ( 0.00%) 67.79 (11.34%) MMTests Statistics: duration Total Elapsed Time (seconds) 611.90 612.22 (While this affects 2.6.38, it is a performance rather than a functional bug and normally outside the rules -stable. While the big performance differences are to a microbench, the difference in fork and exec performance may be significant enough that -stable wants to consider the patch) Reported-by: Raz Ben Yehuda Signed-off-by: Mel Gorman Reviewed-by: Rik van Riel Reviewed-by: Andrea Arcangeli Reviewed-by: Minchan Kim Acked-by: Johannes Weiner Cc: [2.6.38.x] Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/mm/memory.c b/mm/memory.c index ce22a25..607098d4 100644 --- a/mm/memory.c +++ b/mm/memory.c @@ -3396,7 +3396,7 @@ int handle_mm_fault(struct mm_struct *mm, struct vm_area_struct *vma, * run pte_offset_map on the pmd, if an huge pmd could * materialize from under us from a different thread. */ - if (unlikely(__pte_alloc(mm, vma, pmd, address))) + if (unlikely(pmd_none(*pmd)) && __pte_alloc(mm, vma, pmd, address)) return VM_FAULT_OOM; /* if an huge pmd materialized from under us just retry later */ if (unlikely(pmd_trans_huge(*pmd))) -- cgit v0.10.2 From f61583941667c96d61fc6991b9f23307f9bfa87e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= Date: Tue, 19 Apr 2011 22:49:29 +0200 Subject: b43: trivial: update module info about ucode16_mimo firmware 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 diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c index 57eb5b6..7841b95 100644 --- a/drivers/net/wireless/b43/main.c +++ b/drivers/net/wireless/b43/main.c @@ -72,6 +72,7 @@ MODULE_FIRMWARE("b43/ucode11.fw"); MODULE_FIRMWARE("b43/ucode13.fw"); MODULE_FIRMWARE("b43/ucode14.fw"); MODULE_FIRMWARE("b43/ucode15.fw"); +MODULE_FIRMWARE("b43/ucode16_mimo.fw"); MODULE_FIRMWARE("b43/ucode5.fw"); MODULE_FIRMWARE("b43/ucode9.fw"); -- cgit v0.10.2 From 1501b6764f0c363a9f1d72f9d422841f81f1bd8c Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Mon, 25 Apr 2011 11:12:57 -0700 Subject: iwlegacy: led stay solid on when no traffic commit 5ed540aecc2aae92d5c97b9a9306a5bf88ad5574 change the led behavior for iwlwifi driver; the side effect cause led blink all the time. Modify the led blink table to fix this problem Signed-off-by: Wey-Yi Guy Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwlegacy/iwl-led.c b/drivers/net/wireless/iwlegacy/iwl-led.c index 15eb8b7..bda0d61 100644 --- a/drivers/net/wireless/iwlegacy/iwl-led.c +++ b/drivers/net/wireless/iwlegacy/iwl-led.c @@ -48,8 +48,21 @@ module_param(led_mode, int, S_IRUGO); MODULE_PARM_DESC(led_mode, "0=system default, " "1=On(RF On)/Off(RF Off), 2=blinking"); +/* Throughput OFF time(ms) ON time (ms) + * >300 25 25 + * >200 to 300 40 40 + * >100 to 200 55 55 + * >70 to 100 65 65 + * >50 to 70 75 75 + * >20 to 50 85 85 + * >10 to 20 95 95 + * >5 to 10 110 110 + * >1 to 5 130 130 + * >0 to 1 167 167 + * <=0 SOLID ON + */ static const struct ieee80211_tpt_blink iwl_blink[] = { - { .throughput = 0 * 1024 - 1, .blink_time = 334 }, + { .throughput = 0, .blink_time = 334 }, { .throughput = 1 * 1024 - 1, .blink_time = 260 }, { .throughput = 5 * 1024 - 1, .blink_time = 220 }, { .throughput = 10 * 1024 - 1, .blink_time = 190 }, @@ -101,6 +114,11 @@ static int iwl_legacy_led_cmd(struct iwl_priv *priv, if (priv->blink_on == on && priv->blink_off == off) return 0; + if (off == 0) { + /* led is SOLID_ON */ + on = IWL_LED_SOLID; + } + IWL_DEBUG_LED(priv, "Led blink time compensation=%u\n", priv->cfg->base_params->led_compensation); led_cmd.on = iwl_legacy_blink_compensation(priv, on, -- cgit v0.10.2 From f325757ab2812b42da4d690cf8da73c0e678368c Mon Sep 17 00:00:00 2001 From: Stanislaw Gruszka Date: Thu, 28 Apr 2011 11:36:54 +0200 Subject: iwl4965: fix "TX Power requested while scanning" Fix the following: WARNING: at drivers/net/wireless/iwlegacy/iwl-4965.c:1128 \ iwl4965_send_tx_power+0x61/0x102 [iwl4965]() Hardware name: [...] TX Power requested while scanning! Pid: 5723, comm: kworker/u:28 Not tainted 2.6.39-0.rc4.4.fc14.x86_64 #1 Call Trace: [] warn_slowpath_common+0x85/0x9d [] ? iwl4965_show_temperature+0x49/0x49 [iwl4965] [] warn_slowpath_fmt+0x46/0x48 [] iwl4965_send_tx_power+0x61/0x102 [iwl4965] [] ? mutex_lock+0x36/0x50 [] iwl4965_bg_txpower_work+0x57/0x73 [iwl4965] [] process_one_work+0x18d/0x286 [] worker_thread+0xfd/0x181 [] ? manage_workers.clone.16+0x172/0x172 [] kthread+0x82/0x8a [] kernel_thread_helper+0x4/0x10 [] ? kthread_worker_fn+0x14b/0x14b [] ? gs_change+0x13/0x13 Reported-and-tested-by: Paul Bolle Signed-off-by: Stanislaw Gruszka Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwlegacy/iwl4965-base.c b/drivers/net/wireless/iwlegacy/iwl4965-base.c index d484c36..a62fe24 100644 --- a/drivers/net/wireless/iwlegacy/iwl4965-base.c +++ b/drivers/net/wireless/iwlegacy/iwl4965-base.c @@ -2984,15 +2984,15 @@ static void iwl4965_bg_txpower_work(struct work_struct *work) struct iwl_priv *priv = container_of(work, struct iwl_priv, txpower_work); + mutex_lock(&priv->mutex); + /* If a scan happened to start before we got here * then just return; the statistics notification will * kick off another scheduled work to compensate for * any temperature delta we missed here. */ if (test_bit(STATUS_EXIT_PENDING, &priv->status) || test_bit(STATUS_SCANNING, &priv->status)) - return; - - mutex_lock(&priv->mutex); + goto out; /* Regardless of if we are associated, we must reconfigure the * TX power since frames can be sent on non-radar channels while @@ -3002,7 +3002,7 @@ static void iwl4965_bg_txpower_work(struct work_struct *work) /* Update last_temperature to keep is_calib_needed from running * when it isn't needed... */ priv->last_temperature = priv->temperature; - +out: mutex_unlock(&priv->mutex); } -- cgit v0.10.2 From 8178d38b704f0a08a74b030c35e6eca5f5019d3d Mon Sep 17 00:00:00 2001 From: Arik Nemtsov Date: Mon, 18 Apr 2011 14:22:28 +0300 Subject: mac80211: allow low level drivers to report packet loss Add API that allows low level drivers to notify mac80211 about TX packet loss. This is useful when there are FW triggers to notify the low level driver about these events. Signed-off-by: Arik Nemtsov Signed-off-by: John W. Linville diff --git a/include/net/mac80211.h b/include/net/mac80211.h index 162363b..8aad6b3 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -2292,6 +2292,17 @@ void ieee80211_tx_status_irqsafe(struct ieee80211_hw *hw, struct sk_buff *skb); /** + * ieee80211_report_low_ack - report non-responding station + * + * When operating in AP-mode, call this function to report a non-responding + * connected STA. + * + * @sta: the non-responding connected sta + * @num_packets: number of packets sent to @sta without a response + */ +void ieee80211_report_low_ack(struct ieee80211_sta *sta, u32 num_packets); + +/** * ieee80211_beacon_get_tim - beacon generation function * @hw: pointer obtained from ieee80211_alloc_hw(). * @vif: &struct ieee80211_vif pointer from the add_interface callback. diff --git a/net/mac80211/status.c b/net/mac80211/status.c index 3ed3c83..1658efa 100644 --- a/net/mac80211/status.c +++ b/net/mac80211/status.c @@ -446,3 +446,11 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb) dev_kfree_skb(skb); } EXPORT_SYMBOL(ieee80211_tx_status); + +void ieee80211_report_low_ack(struct ieee80211_sta *pubsta, u32 num_packets) +{ + struct sta_info *sta = container_of(pubsta, struct sta_info, sta); + cfg80211_cqm_pktloss_notify(sta->sdata->dev, sta->sta.addr, + num_packets, GFP_ATOMIC); +} +EXPORT_SYMBOL(ieee80211_report_low_ack); -- cgit v0.10.2 From 978f78bf71372a48785ac9407ebc10170f14f56c Mon Sep 17 00:00:00 2001 From: Vivek Natarajan Date: Tue, 26 Apr 2011 10:39:52 +0530 Subject: ath9k_hw: Move bt_stomp to hw from common. Move bt_stomp to ath9k_hw and add its support for latest chipsets. Signed-off-by: Vivek Natarajan Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/btcoex.c b/drivers/net/wireless/ath/ath9k/btcoex.c index d33bf20..71e9e48 100644 --- a/drivers/net/wireless/ath/ath9k/btcoex.c +++ b/drivers/net/wireless/ath/ath9k/btcoex.c @@ -209,3 +209,69 @@ void ath9k_hw_btcoex_disable(struct ath_hw *ah) ah->btcoex_hw.enabled = false; } EXPORT_SYMBOL(ath9k_hw_btcoex_disable); + +static void ar9003_btcoex_bt_stomp(struct ath_hw *ah, + enum ath_stomp_type stomp_type) +{ + ah->bt_coex_bt_weight[0] = AR9300_BT_WGHT; + ah->bt_coex_bt_weight[1] = AR9300_BT_WGHT; + ah->bt_coex_bt_weight[2] = AR9300_BT_WGHT; + ah->bt_coex_bt_weight[3] = AR9300_BT_WGHT; + + + switch (stomp_type) { + case ATH_BTCOEX_STOMP_ALL: + ah->bt_coex_wlan_weight[0] = AR9300_STOMP_ALL_WLAN_WGHT0; + ah->bt_coex_wlan_weight[1] = AR9300_STOMP_ALL_WLAN_WGHT1; + break; + case ATH_BTCOEX_STOMP_LOW: + ah->bt_coex_wlan_weight[0] = AR9300_STOMP_LOW_WLAN_WGHT0; + ah->bt_coex_wlan_weight[1] = AR9300_STOMP_LOW_WLAN_WGHT1; + break; + case ATH_BTCOEX_STOMP_NONE: + ah->bt_coex_wlan_weight[0] = AR9300_STOMP_NONE_WLAN_WGHT0; + ah->bt_coex_wlan_weight[1] = AR9300_STOMP_NONE_WLAN_WGHT1; + break; + + default: + ath_dbg(ath9k_hw_common(ah), ATH_DBG_BTCOEX, + "Invalid Stomptype\n"); + break; + } + + ath9k_hw_btcoex_enable(ah); +} + +/* + * Configures appropriate weight based on stomp type. + */ +void ath9k_hw_btcoex_bt_stomp(struct ath_hw *ah, + enum ath_stomp_type stomp_type) +{ + if (AR_SREV_9300_20_OR_LATER(ah)) { + ar9003_btcoex_bt_stomp(ah, stomp_type); + return; + } + + switch (stomp_type) { + case ATH_BTCOEX_STOMP_ALL: + ath9k_hw_btcoex_set_weight(ah, AR_BT_COEX_WGHT, + AR_STOMP_ALL_WLAN_WGHT); + break; + case ATH_BTCOEX_STOMP_LOW: + ath9k_hw_btcoex_set_weight(ah, AR_BT_COEX_WGHT, + AR_STOMP_LOW_WLAN_WGHT); + break; + case ATH_BTCOEX_STOMP_NONE: + ath9k_hw_btcoex_set_weight(ah, AR_BT_COEX_WGHT, + AR_STOMP_NONE_WLAN_WGHT); + break; + default: + ath_dbg(ath9k_hw_common(ah), ATH_DBG_BTCOEX, + "Invalid Stomptype\n"); + break; + } + + ath9k_hw_btcoex_enable(ah); +} +EXPORT_SYMBOL(ath9k_hw_btcoex_bt_stomp); diff --git a/drivers/net/wireless/ath/ath9k/btcoex.h b/drivers/net/wireless/ath/ath9k/btcoex.h index 588dfd4..aac8fae 100644 --- a/drivers/net/wireless/ath/ath9k/btcoex.h +++ b/drivers/net/wireless/ath/ath9k/btcoex.h @@ -32,6 +32,14 @@ #define ATH_BT_CNT_THRESHOLD 3 #define ATH_BT_CNT_SCAN_THRESHOLD 15 +/* Defines the BT AR_BT_COEX_WGHT used */ +enum ath_stomp_type { + ATH_BTCOEX_NO_STOMP, + ATH_BTCOEX_STOMP_ALL, + ATH_BTCOEX_STOMP_LOW, + ATH_BTCOEX_STOMP_NONE +}; + enum ath_btcoex_scheme { ATH_BTCOEX_CFG_NONE, ATH_BTCOEX_CFG_2WIRE, @@ -57,5 +65,7 @@ void ath9k_hw_btcoex_set_weight(struct ath_hw *ah, u32 wlan_weight); void ath9k_hw_btcoex_enable(struct ath_hw *ah); void ath9k_hw_btcoex_disable(struct ath_hw *ah); +void ath9k_hw_btcoex_bt_stomp(struct ath_hw *ah, + enum ath_stomp_type stomp_type); #endif diff --git a/drivers/net/wireless/ath/ath9k/common.c b/drivers/net/wireless/ath/ath9k/common.c index 16ba8c6..74535e6 100644 --- a/drivers/net/wireless/ath/ath9k/common.c +++ b/drivers/net/wireless/ath/ath9k/common.c @@ -158,37 +158,6 @@ int ath9k_cmn_count_streams(unsigned int chainmask, int max) } EXPORT_SYMBOL(ath9k_cmn_count_streams); -/* - * Configures appropriate weight based on stomp type. - */ -void ath9k_cmn_btcoex_bt_stomp(struct ath_common *common, - enum ath_stomp_type stomp_type) -{ - struct ath_hw *ah = common->ah; - - switch (stomp_type) { - case ATH_BTCOEX_STOMP_ALL: - ath9k_hw_btcoex_set_weight(ah, AR_BT_COEX_WGHT, - AR_STOMP_ALL_WLAN_WGHT); - break; - case ATH_BTCOEX_STOMP_LOW: - ath9k_hw_btcoex_set_weight(ah, AR_BT_COEX_WGHT, - AR_STOMP_LOW_WLAN_WGHT); - break; - case ATH_BTCOEX_STOMP_NONE: - ath9k_hw_btcoex_set_weight(ah, AR_BT_COEX_WGHT, - AR_STOMP_NONE_WLAN_WGHT); - break; - default: - ath_dbg(common, ATH_DBG_BTCOEX, - "Invalid Stomptype\n"); - break; - } - - ath9k_hw_btcoex_enable(ah); -} -EXPORT_SYMBOL(ath9k_cmn_btcoex_bt_stomp); - void ath9k_cmn_update_txpow(struct ath_hw *ah, u16 cur_txpow, u16 new_txpow, u16 *txpower) { diff --git a/drivers/net/wireless/ath/ath9k/common.h b/drivers/net/wireless/ath/ath9k/common.h index b2f7b5f..5124f14 100644 --- a/drivers/net/wireless/ath/ath9k/common.h +++ b/drivers/net/wireless/ath/ath9k/common.h @@ -50,14 +50,6 @@ #define ATH_EP_RND(x, mul) \ ((((x)%(mul)) >= ((mul)/2)) ? ((x) + ((mul) - 1)) / (mul) : (x)/(mul)) -/* Defines the BT AR_BT_COEX_WGHT used */ -enum ath_stomp_type { - ATH_BTCOEX_NO_STOMP, - ATH_BTCOEX_STOMP_ALL, - ATH_BTCOEX_STOMP_LOW, - ATH_BTCOEX_STOMP_NONE -}; - int ath9k_cmn_padpos(__le16 frame_control); int ath9k_cmn_get_hw_crypto_keytype(struct sk_buff *skb); void ath9k_cmn_update_ichannel(struct ath9k_channel *ichan, diff --git a/drivers/net/wireless/ath/ath9k/gpio.c b/drivers/net/wireless/ath/ath9k/gpio.c index 2c59452..3a4ddd1 100644 --- a/drivers/net/wireless/ath/ath9k/gpio.c +++ b/drivers/net/wireless/ath/ath9k/gpio.c @@ -176,7 +176,6 @@ static void ath_btcoex_period_timer(unsigned long data) struct ath_softc *sc = (struct ath_softc *) data; struct ath_hw *ah = sc->sc_ah; struct ath_btcoex *btcoex = &sc->btcoex; - struct ath_common *common = ath9k_hw_common(ah); u32 timer_period; bool is_btscan; @@ -186,7 +185,7 @@ static void ath_btcoex_period_timer(unsigned long data) spin_lock_bh(&btcoex->btcoex_lock); - ath9k_cmn_btcoex_bt_stomp(common, is_btscan ? ATH_BTCOEX_STOMP_ALL : + ath9k_hw_btcoex_bt_stomp(ah, is_btscan ? ATH_BTCOEX_STOMP_ALL : btcoex->bt_stomp_type); spin_unlock_bh(&btcoex->btcoex_lock); @@ -224,9 +223,9 @@ static void ath_btcoex_no_stomp_timer(void *arg) spin_lock_bh(&btcoex->btcoex_lock); if (btcoex->bt_stomp_type == ATH_BTCOEX_STOMP_LOW || is_btscan) - ath9k_cmn_btcoex_bt_stomp(common, ATH_BTCOEX_STOMP_NONE); + ath9k_hw_btcoex_bt_stomp(ah, ATH_BTCOEX_STOMP_NONE); else if (btcoex->bt_stomp_type == ATH_BTCOEX_STOMP_ALL) - ath9k_cmn_btcoex_bt_stomp(common, ATH_BTCOEX_STOMP_LOW); + ath9k_hw_btcoex_bt_stomp(ah, ATH_BTCOEX_STOMP_LOW); spin_unlock_bh(&btcoex->btcoex_lock); } diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_gpio.c b/drivers/net/wireless/ath/ath9k/htc_drv_gpio.c index d051a42..26ede1d 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_gpio.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_gpio.c @@ -77,7 +77,7 @@ static void ath_btcoex_period_work(struct work_struct *work) return; } - ath9k_cmn_btcoex_bt_stomp(common, is_btscan ? ATH_BTCOEX_STOMP_ALL : + ath9k_hw_btcoex_bt_stomp(priv->ah, is_btscan ? ATH_BTCOEX_STOMP_ALL : btcoex->bt_stomp_type); timer_period = is_btscan ? btcoex->btscan_no_stomp : @@ -105,9 +105,9 @@ static void ath_btcoex_duty_cycle_work(struct work_struct *work) "time slice work for bt and wlan\n"); if (btcoex->bt_stomp_type == ATH_BTCOEX_STOMP_LOW || is_btscan) - ath9k_cmn_btcoex_bt_stomp(common, ATH_BTCOEX_STOMP_NONE); + ath9k_hw_btcoex_bt_stomp(ah, ATH_BTCOEX_STOMP_NONE); else if (btcoex->bt_stomp_type == ATH_BTCOEX_STOMP_ALL) - ath9k_cmn_btcoex_bt_stomp(common, ATH_BTCOEX_STOMP_LOW); + ath9k_hw_btcoex_bt_stomp(ah, ATH_BTCOEX_STOMP_LOW); } void ath_htc_init_btcoex_work(struct ath9k_htc_priv *priv) -- cgit v0.10.2 From a6ef530f2b0bc7e871e8c2f2b2a0905eed57fead Mon Sep 17 00:00:00 2001 From: Vivek Natarajan Date: Tue, 26 Apr 2011 10:39:53 +0530 Subject: ath9k_hw: Add support for btcoexistence in AR9300. Signed-off-by: Vivek Natarajan Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/btcoex.c b/drivers/net/wireless/ath/ath9k/btcoex.c index 71e9e48..23f15a7 100644 --- a/drivers/net/wireless/ath/ath9k/btcoex.c +++ b/drivers/net/wireless/ath/ath9k/btcoex.c @@ -51,6 +51,10 @@ void ath9k_hw_init_btcoex_hw(struct ath_hw *ah, int qnum) .bt_hold_rx_clear = true, }; u32 i; + bool rxclear_polarity = ath_bt_config.bt_rxclear_polarity; + + if (AR_SREV_9300_20_OR_LATER(ah)) + rxclear_polarity = !ath_bt_config.bt_rxclear_polarity; btcoex_hw->bt_coex_mode = (btcoex_hw->bt_coex_mode & AR_BT_QCU_THRESH) | @@ -59,7 +63,7 @@ void ath9k_hw_init_btcoex_hw(struct ath_hw *ah, int qnum) SM(ath_bt_config.bt_txframe_extend, AR_BT_TX_FRAME_EXTEND) | SM(ath_bt_config.bt_mode, AR_BT_MODE) | SM(ath_bt_config.bt_quiet_collision, AR_BT_QUIET) | - SM(ath_bt_config.bt_rxclear_polarity, AR_BT_RX_CLEAR_POLARITY) | + SM(rxclear_polarity, AR_BT_RX_CLEAR_POLARITY) | SM(ath_bt_config.bt_priority_time, AR_BT_PRIORITY_TIME) | SM(ath_bt_config.bt_first_slot_time, AR_BT_FIRST_SLOT_TIME) | SM(qnum, AR_BT_QCU_THRESH); @@ -142,6 +146,7 @@ void ath9k_hw_btcoex_set_weight(struct ath_hw *ah, } EXPORT_SYMBOL(ath9k_hw_btcoex_set_weight); + static void ath9k_hw_btcoex_enable_3wire(struct ath_hw *ah) { struct ath_btcoex_hw *btcoex_hw = &ah->btcoex_hw; @@ -152,9 +157,22 @@ static void ath9k_hw_btcoex_enable_3wire(struct ath_hw *ah) * enable coex 3-wire */ REG_WRITE(ah, AR_BT_COEX_MODE, btcoex_hw->bt_coex_mode); - REG_WRITE(ah, AR_BT_COEX_WEIGHT, btcoex_hw->bt_coex_weights); REG_WRITE(ah, AR_BT_COEX_MODE2, btcoex_hw->bt_coex_mode2); + + if (AR_SREV_9300_20_OR_LATER(ah)) { + REG_WRITE(ah, AR_BT_COEX_WL_WEIGHTS0, ah->bt_coex_wlan_weight[0]); + REG_WRITE(ah, AR_BT_COEX_WL_WEIGHTS1, ah->bt_coex_wlan_weight[1]); + REG_WRITE(ah, AR_BT_COEX_BT_WEIGHTS0, ah->bt_coex_bt_weight[0]); + REG_WRITE(ah, AR_BT_COEX_BT_WEIGHTS1, ah->bt_coex_bt_weight[1]); + REG_WRITE(ah, AR_BT_COEX_BT_WEIGHTS2, ah->bt_coex_bt_weight[2]); + REG_WRITE(ah, AR_BT_COEX_BT_WEIGHTS3, ah->bt_coex_bt_weight[3]); + + } else + REG_WRITE(ah, AR_BT_COEX_WEIGHT, btcoex_hw->bt_coex_weights); + + + if (AR_SREV_9271(ah)) { val = REG_READ(ah, 0x50040); val &= 0xFFFFFEFF; @@ -202,8 +220,18 @@ void ath9k_hw_btcoex_disable(struct ath_hw *ah) if (btcoex_hw->scheme == ATH_BTCOEX_CFG_3WIRE) { REG_WRITE(ah, AR_BT_COEX_MODE, AR_BT_QUIET | AR_BT_MODE); - REG_WRITE(ah, AR_BT_COEX_WEIGHT, 0); REG_WRITE(ah, AR_BT_COEX_MODE2, 0); + + if (AR_SREV_9300_20_OR_LATER(ah)) { + REG_WRITE(ah, AR_BT_COEX_WL_WEIGHTS0, 0); + REG_WRITE(ah, AR_BT_COEX_WL_WEIGHTS1, 0); + REG_WRITE(ah, AR_BT_COEX_BT_WEIGHTS0, 0); + REG_WRITE(ah, AR_BT_COEX_BT_WEIGHTS1, 0); + REG_WRITE(ah, AR_BT_COEX_BT_WEIGHTS2, 0); + REG_WRITE(ah, AR_BT_COEX_BT_WEIGHTS3, 0); + } else + REG_WRITE(ah, AR_BT_COEX_WEIGHT, 0); + } ah->btcoex_hw.enabled = false; diff --git a/drivers/net/wireless/ath/ath9k/btcoex.h b/drivers/net/wireless/ath/ath9k/btcoex.h index aac8fae..a9efca8 100644 --- a/drivers/net/wireless/ath/ath9k/btcoex.h +++ b/drivers/net/wireless/ath/ath9k/btcoex.h @@ -19,9 +19,13 @@ #include "hw.h" -#define ATH_WLANACTIVE_GPIO 5 -#define ATH_BTACTIVE_GPIO 6 -#define ATH_BTPRIORITY_GPIO 7 +#define ATH_WLANACTIVE_GPIO_9280 5 +#define ATH_BTACTIVE_GPIO_9280 6 +#define ATH_BTPRIORITY_GPIO_9285 7 + +#define ATH_WLANACTIVE_GPIO_9300 5 +#define ATH_BTACTIVE_GPIO_9300 4 +#define ATH_BTPRIORITY_GPIO_9300 8 #define ATH_BTCOEX_DEF_BT_PERIOD 45 #define ATH_BTCOEX_DEF_DUTY_CYCLE 55 diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index e99e319..58f3d42 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c @@ -1956,15 +1956,23 @@ int ath9k_hw_fill_cap_info(struct ath_hw *ah) else pCap->hw_caps |= ATH9K_HW_CAP_4KB_SPLITTRANS; - if (AR_SREV_9280_20_OR_LATER(ah) && common->btcoex_enabled) { - btcoex_hw->btactive_gpio = ATH_BTACTIVE_GPIO; - btcoex_hw->wlanactive_gpio = ATH_WLANACTIVE_GPIO; - - if (AR_SREV_9285(ah)) { + if (common->btcoex_enabled) { + if (AR_SREV_9300_20_OR_LATER(ah)) { btcoex_hw->scheme = ATH_BTCOEX_CFG_3WIRE; - btcoex_hw->btpriority_gpio = ATH_BTPRIORITY_GPIO; - } else { - btcoex_hw->scheme = ATH_BTCOEX_CFG_2WIRE; + btcoex_hw->btactive_gpio = ATH_BTACTIVE_GPIO_9300; + btcoex_hw->wlanactive_gpio = ATH_WLANACTIVE_GPIO_9300; + btcoex_hw->btpriority_gpio = ATH_BTPRIORITY_GPIO_9300; + } else if (AR_SREV_9280_20_OR_LATER(ah)) { + btcoex_hw->btactive_gpio = ATH_BTACTIVE_GPIO_9280; + btcoex_hw->wlanactive_gpio = ATH_WLANACTIVE_GPIO_9280; + + if (AR_SREV_9285(ah)) { + btcoex_hw->scheme = ATH_BTCOEX_CFG_3WIRE; + btcoex_hw->btpriority_gpio = + ATH_BTPRIORITY_GPIO_9285; + } else { + btcoex_hw->scheme = ATH_BTCOEX_CFG_2WIRE; + } } } else { btcoex_hw->scheme = ATH_BTCOEX_CFG_NONE; diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h index 6a028bd..34ed1bd 100644 --- a/drivers/net/wireless/ath/ath9k/hw.h +++ b/drivers/net/wireless/ath/ath9k/hw.h @@ -56,6 +56,9 @@ #define AT9285_COEX3WIRE_SA_SUBSYSID 0x30aa #define AT9285_COEX3WIRE_DA_SUBSYSID 0x30ab +#define AR9300_NUM_BT_WEIGHTS 4 +#define AR9300_NUM_WLAN_WEIGHTS 4 + #define ATH_AMPDU_LIMIT_MAX (64 * 1024 - 1) #define ATH_DEFAULT_NOISE_FLOOR -95 @@ -772,6 +775,8 @@ struct ath_hw { /* Bluetooth coexistance */ struct ath_btcoex_hw btcoex_hw; + u32 bt_coex_bt_weight[AR9300_NUM_BT_WEIGHTS]; + u32 bt_coex_wlan_weight[AR9300_NUM_WLAN_WEIGHTS]; u32 intr_txqs; u8 txchainmask; diff --git a/drivers/net/wireless/ath/ath9k/reg.h b/drivers/net/wireless/ath/ath9k/reg.h index d5cecdc..456f3ec 100644 --- a/drivers/net/wireless/ath/ath9k/reg.h +++ b/drivers/net/wireless/ath/ath9k/reg.h @@ -1709,6 +1709,22 @@ enum { #define AR_BTCOEX_WL_WGHT 0xffff0000 #define AR_BTCOEX_WL_WGHT_S 16 +#define AR_BT_COEX_WL_WEIGHTS0 0x8174 +#define AR_BT_COEX_WL_WEIGHTS1 0x81c4 + +#define AR_BT_COEX_BT_WEIGHTS0 0x83ac +#define AR_BT_COEX_BT_WEIGHTS1 0x83b0 +#define AR_BT_COEX_BT_WEIGHTS2 0x83b4 +#define AR_BT_COEX_BT_WEIGHTS3 0x83b8 + +#define AR9300_BT_WGHT 0xcccc4444 +#define AR9300_STOMP_ALL_WLAN_WGHT0 0xfffffff0 +#define AR9300_STOMP_ALL_WLAN_WGHT1 0xfffffff0 +#define AR9300_STOMP_LOW_WLAN_WGHT0 0x88888880 +#define AR9300_STOMP_LOW_WLAN_WGHT1 0x88888880 +#define AR9300_STOMP_NONE_WLAN_WGHT0 0x00000000 +#define AR9300_STOMP_NONE_WLAN_WGHT1 0x00000000 + #define AR_BT_COEX_MODE2 0x817c #define AR_BT_BCN_MISS_THRESH 0x000000ff #define AR_BT_BCN_MISS_THRESH_S 0 -- cgit v0.10.2 From f78eb657f067ce87e19da94138d22cde8236c7db Mon Sep 17 00:00:00 2001 From: Vivek Natarajan Date: Tue, 26 Apr 2011 10:39:54 +0530 Subject: ath9k_hw: Enable generic timer interrupt. Generic timer interrupt was not triggered unless autosleep was disabled. Since autosleep is enabled in the newer chipsets, enable generic timer for using with bt coex logic. Signed-off-by: Vivek Natarajan Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/mac.c b/drivers/net/wireless/ath/ath9k/mac.c index c8a4ced..9cf7a7d 100644 --- a/drivers/net/wireless/ath/ath9k/mac.c +++ b/drivers/net/wireless/ath/ath9k/mac.c @@ -885,6 +885,9 @@ void ath9k_hw_set_interrupts(struct ath_hw *ah, enum ath9k_int ints) mask |= AR_IMR_GENTMR; } + if (ints & ATH9K_INT_GENTIMER) + mask |= AR_IMR_GENTMR; + if (ints & (ATH9K_INT_BMISC)) { mask |= AR_IMR_BCNMISC; if (ints & ATH9K_INT_TIM) -- cgit v0.10.2 From a039a993496d79d09ae9709c82b545b9800954c9 Mon Sep 17 00:00:00 2001 From: Vivek Natarajan Date: Tue, 26 Apr 2011 10:39:55 +0530 Subject: ath9k: Use ps wrappers for btcoex logic. Use ps wrappers before accessing hw registers in btcoex. Signed-off-by: Vivek Natarajan Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/gpio.c b/drivers/net/wireless/ath/ath9k/gpio.c index 3a4ddd1..0349b3a 100644 --- a/drivers/net/wireless/ath/ath9k/gpio.c +++ b/drivers/net/wireless/ath/ath9k/gpio.c @@ -179,6 +179,7 @@ static void ath_btcoex_period_timer(unsigned long data) u32 timer_period; bool is_btscan; + ath9k_ps_wakeup(sc); ath_detect_bt_priority(sc); is_btscan = sc->sc_flags & SC_OP_BT_SCAN; @@ -201,6 +202,7 @@ static void ath_btcoex_period_timer(unsigned long data) btcoex->hw_timer_enabled = true; } + ath9k_ps_restore(sc); mod_timer(&btcoex->period_timer, jiffies + msecs_to_jiffies(ATH_BTCOEX_DEF_BT_PERIOD)); } @@ -220,6 +222,7 @@ static void ath_btcoex_no_stomp_timer(void *arg) ath_dbg(common, ATH_DBG_BTCOEX, "no stomp timer running\n"); + ath9k_ps_wakeup(sc); spin_lock_bh(&btcoex->btcoex_lock); if (btcoex->bt_stomp_type == ATH_BTCOEX_STOMP_LOW || is_btscan) @@ -228,6 +231,7 @@ static void ath_btcoex_no_stomp_timer(void *arg) ath9k_hw_btcoex_bt_stomp(ah, ATH_BTCOEX_STOMP_LOW); spin_unlock_bh(&btcoex->btcoex_lock); + ath9k_ps_restore(sc); } int ath_init_btcoex_timer(struct ath_softc *sc) -- cgit v0.10.2 From 47684808fd89d6809c0886e06f8ac324252499d8 Mon Sep 17 00:00:00 2001 From: Arik Nemtsov Date: Tue, 26 Apr 2011 23:21:51 +0300 Subject: wl12xx: support FW TX inactivity triggers In AP mode we register for the MAX_TX_RETRY and INACTIVE_STA events. Both are reported to the upper layers as a TX failure in the offending stations. In STA mode we register only for the MAX_TX_RETRY event. A TX failure is interpreted as a loss of connection. Support for IEEE80211_HW_REPORTS_TX_ACK_STATUS has been removed to avoid the inherent race condition of a mac80211 TX failure counter in addition to the FW counter. This patch depends on "mac80211: allow low level driver to report packet loss" Signed-off-by: Arik Nemtsov Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/wl12xx/acx.c b/drivers/net/wireless/wl12xx/acx.c index b277947..a5c9c0a 100644 --- a/drivers/net/wireless/wl12xx/acx.c +++ b/drivers/net/wireless/wl12xx/acx.c @@ -1524,22 +1524,46 @@ out: return ret; } -int wl1271_acx_max_tx_retry(struct wl1271 *wl) +int wl1271_acx_ap_max_tx_retry(struct wl1271 *wl) { - struct wl1271_acx_max_tx_retry *acx = NULL; + struct wl1271_acx_ap_max_tx_retry *acx = NULL; int ret; - wl1271_debug(DEBUG_ACX, "acx max tx retry"); + wl1271_debug(DEBUG_ACX, "acx ap max tx retry"); acx = kzalloc(sizeof(*acx), GFP_KERNEL); if (!acx) return -ENOMEM; - acx->max_tx_retry = cpu_to_le16(wl->conf.tx.ap_max_tx_retries); + acx->max_tx_retry = cpu_to_le16(wl->conf.tx.max_tx_retries); ret = wl1271_cmd_configure(wl, ACX_MAX_TX_FAILURE, acx, sizeof(*acx)); if (ret < 0) { - wl1271_warning("acx max tx retry failed: %d", ret); + wl1271_warning("acx ap max tx retry failed: %d", ret); + goto out; + } + +out: + kfree(acx); + return ret; +} + +int wl1271_acx_sta_max_tx_retry(struct wl1271 *wl) +{ + struct wl1271_acx_sta_max_tx_retry *acx = NULL; + int ret; + + wl1271_debug(DEBUG_ACX, "acx sta max tx retry"); + + acx = kzalloc(sizeof(*acx), GFP_KERNEL); + if (!acx) + return -ENOMEM; + + acx->max_tx_retry = wl->conf.tx.max_tx_retries; + + ret = wl1271_cmd_configure(wl, ACX_CONS_TX_FAILURE, acx, sizeof(*acx)); + if (ret < 0) { + wl1271_warning("acx sta max tx retry failed: %d", ret); goto out; } diff --git a/drivers/net/wireless/wl12xx/acx.h b/drivers/net/wireless/wl12xx/acx.h index 0a40cae..942908c 100644 --- a/drivers/net/wireless/wl12xx/acx.h +++ b/drivers/net/wireless/wl12xx/acx.h @@ -1145,7 +1145,7 @@ struct wl1271_acx_fw_tsf_information { u8 padding[3]; } __packed; -struct wl1271_acx_max_tx_retry { +struct wl1271_acx_ap_max_tx_retry { struct acx_header header; /* @@ -1156,6 +1156,13 @@ struct wl1271_acx_max_tx_retry { u8 padding_1[2]; } __packed; +struct wl1271_acx_sta_max_tx_retry { + struct acx_header header; + + u8 max_tx_retry; + u8 padding_1[3]; +} __packed; + struct wl1271_acx_config_ps { struct acx_header header; @@ -1307,7 +1314,8 @@ int wl1271_acx_set_ba_session(struct wl1271 *wl, int wl1271_acx_set_ba_receiver_session(struct wl1271 *wl, u8 tid_index, u16 ssn, bool enable); int wl1271_acx_tsf_info(struct wl1271 *wl, u64 *mactime); -int wl1271_acx_max_tx_retry(struct wl1271 *wl); +int wl1271_acx_ap_max_tx_retry(struct wl1271 *wl); +int wl1271_acx_sta_max_tx_retry(struct wl1271 *wl); int wl1271_acx_config_ps(struct wl1271 *wl); int wl1271_acx_set_inconnection_sta(struct wl1271 *wl, u8 *addr); diff --git a/drivers/net/wireless/wl12xx/boot.c b/drivers/net/wireless/wl12xx/boot.c index 2b0cf85..d263ebb 100644 --- a/drivers/net/wireless/wl12xx/boot.c +++ b/drivers/net/wireless/wl12xx/boot.c @@ -478,10 +478,12 @@ static int wl1271_boot_run_firmware(struct wl1271 *wl) DISCONNECT_EVENT_COMPLETE_ID | RSSI_SNR_TRIGGER_0_EVENT_ID | PSPOLL_DELIVERY_FAILURE_EVENT_ID | - SOFT_GEMINI_SENSE_EVENT_ID; + SOFT_GEMINI_SENSE_EVENT_ID | + MAX_TX_RETRY_EVENT_ID; if (wl->bss_type == BSS_TYPE_AP_BSS) - wl->event_mask |= STA_REMOVE_COMPLETE_EVENT_ID; + wl->event_mask |= STA_REMOVE_COMPLETE_EVENT_ID | + INACTIVE_STA_EVENT_ID; else wl->event_mask |= DUMMY_PACKET_EVENT_ID; diff --git a/drivers/net/wireless/wl12xx/cmd.c b/drivers/net/wireless/wl12xx/cmd.c index 2468044..d483316 100644 --- a/drivers/net/wireless/wl12xx/cmd.c +++ b/drivers/net/wireless/wl12xx/cmd.c @@ -1070,7 +1070,7 @@ int wl1271_cmd_start_bss(struct wl1271 *wl) memcpy(cmd->bssid, bss_conf->bssid, ETH_ALEN); - cmd->aging_period = cpu_to_le16(WL1271_AP_DEF_INACTIV_SEC); + cmd->aging_period = cpu_to_le16(wl->conf.tx.ap_aging_period); cmd->bss_index = WL1271_AP_BSS_INDEX; cmd->global_hlid = WL1271_AP_GLOBAL_HLID; cmd->broadcast_hlid = WL1271_AP_BROADCAST_HLID; diff --git a/drivers/net/wireless/wl12xx/conf.h b/drivers/net/wireless/wl12xx/conf.h index 6c9e3a6..d16094f 100644 --- a/drivers/net/wireless/wl12xx/conf.h +++ b/drivers/net/wireless/wl12xx/conf.h @@ -683,10 +683,18 @@ struct conf_tx_settings { struct conf_tx_rate_class ap_bcst_conf; /* - * AP-mode - allow this number of TX retries to a station before an + * Allow this number of TX retries to a connected station/AP before an * event is triggered from FW. + * In AP-mode the hlids of unreachable stations are given in the + * "sta_tx_retry_exceeded" member in the event mailbox. */ - u16 ap_max_tx_retries; + u8 max_tx_retries; + + /* + * AP-mode - after this number of seconds a connected station is + * considered inactive. + */ + u16 ap_aging_period; /* * Configuration for TID parameters. diff --git a/drivers/net/wireless/wl12xx/event.c b/drivers/net/wireless/wl12xx/event.c index ae69330..d7be3ae 100644 --- a/drivers/net/wireless/wl12xx/event.c +++ b/drivers/net/wireless/wl12xx/event.c @@ -174,6 +174,8 @@ static int wl1271_event_process(struct wl1271 *wl, struct event_mailbox *mbox) u32 vector; bool beacon_loss = false; bool is_ap = (wl->bss_type == BSS_TYPE_AP_BSS); + bool disconnect_sta = false; + unsigned long sta_bitmap = 0; wl1271_event_mbox_dump(mbox); @@ -235,9 +237,54 @@ static int wl1271_event_process(struct wl1271 *wl, struct event_mailbox *mbox) wl1271_tx_dummy_packet(wl); } + /* + * "TX retries exceeded" has a different meaning according to mode. + * In AP mode the offending station is disconnected. In STA mode we + * report connection loss. + */ + if (vector & MAX_TX_RETRY_EVENT_ID) { + wl1271_debug(DEBUG_EVENT, "MAX_TX_RETRY_EVENT_ID"); + if (is_ap) { + sta_bitmap |= le16_to_cpu(mbox->sta_tx_retry_exceeded); + disconnect_sta = true; + } else { + beacon_loss = true; + } + } + + if ((vector & INACTIVE_STA_EVENT_ID) && is_ap) { + wl1271_debug(DEBUG_EVENT, "INACTIVE_STA_EVENT_ID"); + sta_bitmap |= le16_to_cpu(mbox->sta_aging_status); + disconnect_sta = true; + } + if (wl->vif && beacon_loss) ieee80211_connection_loss(wl->vif); + if (is_ap && disconnect_sta) { + u32 num_packets = wl->conf.tx.max_tx_retries; + struct ieee80211_sta *sta; + const u8 *addr; + int h; + + for (h = find_first_bit(&sta_bitmap, AP_MAX_LINKS); + h < AP_MAX_LINKS; + h = find_next_bit(&sta_bitmap, AP_MAX_LINKS, h+1)) { + if (!wl1271_is_active_sta(wl, h)) + continue; + + addr = wl->links[h].addr; + + rcu_read_lock(); + sta = ieee80211_find_sta(wl->vif, addr); + if (sta) { + wl1271_debug(DEBUG_EVENT, "remove sta %d", h); + ieee80211_report_low_ack(sta, num_packets); + } + rcu_read_unlock(); + } + } + return 0; } diff --git a/drivers/net/wireless/wl12xx/event.h b/drivers/net/wireless/wl12xx/event.h index b6cf06e..7ae5a08 100644 --- a/drivers/net/wireless/wl12xx/event.h +++ b/drivers/net/wireless/wl12xx/event.h @@ -58,13 +58,16 @@ enum { CHANNEL_SWITCH_COMPLETE_EVENT_ID = BIT(17), BSS_LOSE_EVENT_ID = BIT(18), REGAINED_BSS_EVENT_ID = BIT(19), - ROAMING_TRIGGER_MAX_TX_RETRY_EVENT_ID = BIT(20), + MAX_TX_RETRY_EVENT_ID = BIT(20), /* STA: dummy paket for dynamic mem blocks */ DUMMY_PACKET_EVENT_ID = BIT(21), /* AP: STA remove complete */ STA_REMOVE_COMPLETE_EVENT_ID = BIT(21), SOFT_GEMINI_SENSE_EVENT_ID = BIT(22), + /* STA: SG prediction */ SOFT_GEMINI_PREDICTION_EVENT_ID = BIT(23), + /* AP: Inactive STA */ + INACTIVE_STA_EVENT_ID = BIT(23), SOFT_GEMINI_AVALANCHE_EVENT_ID = BIT(24), PLT_RX_CALIBRATION_COMPLETE_EVENT_ID = BIT(25), DBG_EVENT_ID = BIT(26), @@ -119,7 +122,11 @@ struct event_mailbox { /* AP FW only */ u8 hlid_removed; + + /* a bitmap of hlids for stations that have been inactive too long */ __le16 sta_aging_status; + + /* a bitmap of hlids for stations which didn't respond to TX */ __le16 sta_tx_retry_exceeded; u8 reserved_5[24]; @@ -130,4 +137,7 @@ void wl1271_event_mbox_config(struct wl1271 *wl); int wl1271_event_handle(struct wl1271 *wl, u8 mbox); void wl1271_pspoll_work(struct work_struct *work); +/* Functions from main.c */ +bool wl1271_is_active_sta(struct wl1271 *wl, u8 hlid); + #endif diff --git a/drivers/net/wireless/wl12xx/init.c b/drivers/net/wireless/wl12xx/init.c index cf46607..ab3b1e2 100644 --- a/drivers/net/wireless/wl12xx/init.c +++ b/drivers/net/wireless/wl12xx/init.c @@ -375,6 +375,10 @@ static int wl1271_sta_hw_init(struct wl1271 *wl) if (ret < 0) return ret; + ret = wl1271_acx_sta_max_tx_retry(wl); + if (ret < 0) + return ret; + ret = wl1271_acx_sta_mem_cfg(wl); if (ret < 0) return ret; @@ -441,7 +445,7 @@ static int wl1271_ap_hw_init(struct wl1271 *wl) if (ret < 0) return ret; - ret = wl1271_acx_max_tx_retry(wl); + ret = wl1271_acx_ap_max_tx_retry(wl); if (ret < 0) return ret; diff --git a/drivers/net/wireless/wl12xx/main.c b/drivers/net/wireless/wl12xx/main.c index 866453b..0c69e95 100644 --- a/drivers/net/wireless/wl12xx/main.c +++ b/drivers/net/wireless/wl12xx/main.c @@ -192,7 +192,8 @@ static struct conf_drv_settings default_conf = { .long_retry_limit = 10, .aflags = 0, }, - .ap_max_tx_retries = 100, + .max_tx_retries = 100, + .ap_aging_period = 300, .tid_conf_count = 4, .tid_conf = { [CONF_TX_AC_BE] = { @@ -2953,6 +2954,12 @@ static void wl1271_free_sta(struct wl1271 *wl, u8 hlid) __clear_bit(hlid, (unsigned long *)&wl->ap_fw_ps_map); } +bool wl1271_is_active_sta(struct wl1271 *wl, u8 hlid) +{ + int id = hlid - WL1271_AP_STA_HLID_START; + return test_bit(id, wl->ap_hlid_map); +} + static int wl1271_op_sta_add(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_sta *sta) @@ -3535,7 +3542,6 @@ int wl1271_init_ieee80211(struct wl1271 *wl) IEEE80211_HW_HAS_RATE_CONTROL | IEEE80211_HW_CONNECTION_MONITOR | IEEE80211_HW_SUPPORTS_CQM_RSSI | - IEEE80211_HW_REPORTS_TX_ACK_STATUS | IEEE80211_HW_AP_LINK_PS; wl->hw->wiphy->cipher_suites = cipher_suites; diff --git a/drivers/net/wireless/wl12xx/wl12xx.h b/drivers/net/wireless/wl12xx/wl12xx.h index fb2b79f..7c521af 100644 --- a/drivers/net/wireless/wl12xx/wl12xx.h +++ b/drivers/net/wireless/wl12xx/wl12xx.h @@ -172,7 +172,6 @@ extern u32 wl12xx_debug_level; #define WL1271_PS_STA_MAX_BLOCKS (2 * 9) #define WL1271_AP_BSS_INDEX 0 -#define WL1271_AP_DEF_INACTIV_SEC 300 #define WL1271_AP_DEF_BEACON_EXP 20 #define ACX_TX_DESCRIPTORS 32 -- cgit v0.10.2 From 8973a6e770fc891f92daacbc1c92c7cd396fcf7e Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Tue, 26 Apr 2011 15:25:29 -0700 Subject: libertas: use kernel-doc notation, fix comment style Convert all libertas/ files to use kernel-doc notation instead of whatever it was (doxygen?). Add or fix function parameters in several places. Use expected style for multi-line comments in lots of places. Remove erroneous /** in multiple places. Signed-off-by: Randy Dunlap Acked-by: Dan Williams Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/libertas/cfg.c b/drivers/net/wireless/libertas/cfg.c index 30ef035..f582dfd 100644 --- a/drivers/net/wireless/libertas/cfg.c +++ b/drivers/net/wireless/libertas/cfg.c @@ -122,8 +122,10 @@ static u8 lbs_auth_to_authtype(enum nl80211_auth_type auth_type) } -/* Various firmware commands need the list of supported rates, but with - the hight-bit set for basic rates */ +/* + * Various firmware commands need the list of supported rates, but with + * the hight-bit set for basic rates + */ static int lbs_add_rates(u8 *rates) { size_t i; @@ -425,7 +427,7 @@ static int lbs_add_wpa_tlv(u8 *tlv, const u8 *ie, u8 ie_len) return ie_len + 2; } -/*************************************************************************** +/* * Set Channel */ @@ -452,7 +454,7 @@ static int lbs_cfg_set_channel(struct wiphy *wiphy, -/*************************************************************************** +/* * Scanning */ @@ -538,8 +540,10 @@ static int lbs_ret_scan(struct lbs_private *priv, unsigned long dummy, goto done; } - /* Validity check: the TLV holds TSF values with 8 bytes each, so - * the size in the TLV must match the nr_sets value */ + /* + * Validity check: the TLV holds TSF values with 8 bytes each, so + * the size in the TLV must match the nr_sets value + */ i = get_unaligned_le16(tsfdesc); tsfdesc += 2; if (i / 8 != scanresp->nr_sets) { @@ -581,8 +585,10 @@ static int lbs_ret_scan(struct lbs_private *priv, unsigned long dummy, /* To find out the channel, we must parse the IEs */ ie = pos; - /* 6+1+8+2+2: size of BSSID, RSSI, time stamp, beacon - interval, capabilities */ + /* + * 6+1+8+2+2: size of BSSID, RSSI, time stamp, beacon + * interval, capabilities + */ ielen = left = len - (6 + 1 + 8 + 2 + 2); while (left >= 2) { u8 id, elen; @@ -790,7 +796,7 @@ static int lbs_cfg_scan(struct wiphy *wiphy, -/*************************************************************************** +/* * Events */ @@ -825,7 +831,7 @@ void lbs_send_mic_failureevent(struct lbs_private *priv, u32 event) -/*************************************************************************** +/* * Connect/disconnect */ @@ -950,8 +956,10 @@ static int lbs_enable_rsn(struct lbs_private *priv, int enable) * Set WPA/WPA key material */ -/* like "struct cmd_ds_802_11_key_material", but with cmd_header. Once we - * get rid of WEXT, this should go into host.h */ +/* + * like "struct cmd_ds_802_11_key_material", but with cmd_header. Once we + * get rid of WEXT, this should go into host.h + */ struct cmd_key_material { struct cmd_header hdr; @@ -1536,7 +1544,7 @@ static int lbs_cfg_del_key(struct wiphy *wiphy, struct net_device *netdev, } -/*************************************************************************** +/* * Get station */ @@ -1581,7 +1589,7 @@ static int lbs_cfg_get_station(struct wiphy *wiphy, struct net_device *dev, -/*************************************************************************** +/* * "Site survey", here just current channel and noise level */ @@ -1614,7 +1622,7 @@ static int lbs_get_survey(struct wiphy *wiphy, struct net_device *dev, -/*************************************************************************** +/* * Change interface */ @@ -1656,11 +1664,12 @@ static int lbs_change_intf(struct wiphy *wiphy, struct net_device *dev, -/*************************************************************************** +/* * IBSS (Ad-Hoc) */ -/* The firmware needs the following bits masked out of the beacon-derived +/* + * The firmware needs the following bits masked out of the beacon-derived * capability field when associating/joining to a BSS: * 9 (QoS), 11 (APSD), 12 (unused), 14 (unused), 15 (unused) */ @@ -1999,7 +2008,7 @@ static int lbs_leave_ibss(struct wiphy *wiphy, struct net_device *dev) -/*************************************************************************** +/* * Initialization */ diff --git a/drivers/net/wireless/libertas/cmd.c b/drivers/net/wireless/libertas/cmd.c index 7e8a658..6a96fc9 100644 --- a/drivers/net/wireless/libertas/cmd.c +++ b/drivers/net/wireless/libertas/cmd.c @@ -1,7 +1,7 @@ -/** - * This file contains the handling of command. - * It prepares command and sends it to firmware when it is ready. - */ +/* + * This file contains the handling of command. + * It prepares command and sends it to firmware when it is ready. + */ #include #include @@ -16,14 +16,14 @@ #define CAL_RSSI(snr, nf) ((s32)((s32)(snr) + CAL_NF(nf))) /** - * @brief Simple callback that copies response back into command + * lbs_cmd_copyback - Simple callback that copies response back into command * - * @param priv A pointer to struct lbs_private structure - * @param extra A pointer to the original command structure for which - * 'resp' is a response - * @param resp A pointer to the command response + * @priv: A pointer to &struct lbs_private structure + * @extra: A pointer to the original command structure for which + * 'resp' is a response + * @resp: A pointer to the command response * - * @return 0 on success, error on failure + * returns: 0 on success, error on failure */ int lbs_cmd_copyback(struct lbs_private *priv, unsigned long extra, struct cmd_header *resp) @@ -38,15 +38,15 @@ int lbs_cmd_copyback(struct lbs_private *priv, unsigned long extra, EXPORT_SYMBOL_GPL(lbs_cmd_copyback); /** - * @brief Simple callback that ignores the result. Use this if - * you just want to send a command to the hardware, but don't + * lbs_cmd_async_callback - Simple callback that ignores the result. + * Use this if you just want to send a command to the hardware, but don't * care for the result. * - * @param priv ignored - * @param extra ignored - * @param resp ignored + * @priv: ignored + * @extra: ignored + * @resp: ignored * - * @return 0 for success + * returns: 0 for success */ static int lbs_cmd_async_callback(struct lbs_private *priv, unsigned long extra, struct cmd_header *resp) @@ -56,10 +56,11 @@ static int lbs_cmd_async_callback(struct lbs_private *priv, unsigned long extra, /** - * @brief Checks whether a command is allowed in Power Save mode + * is_command_allowed_in_ps - tests if a command is allowed in Power Save mode + * + * @cmd: the command ID * - * @param command the command ID - * @return 1 if allowed, 0 if not allowed + * returns: 1 if allowed, 0 if not allowed */ static u8 is_command_allowed_in_ps(u16 cmd) { @@ -75,11 +76,12 @@ static u8 is_command_allowed_in_ps(u16 cmd) } /** - * @brief Updates the hardware details like MAC address and regulatory region + * lbs_update_hw_spec - Updates the hardware details like MAC address + * and regulatory region * - * @param priv A pointer to struct lbs_private structure + * @priv: A pointer to &struct lbs_private structure * - * @return 0 on success, error on failure + * returns: 0 on success, error on failure */ int lbs_update_hw_spec(struct lbs_private *priv) { @@ -217,14 +219,14 @@ int lbs_host_sleep_cfg(struct lbs_private *priv, uint32_t criteria, EXPORT_SYMBOL_GPL(lbs_host_sleep_cfg); /** - * @brief Sets the Power Save mode + * lbs_set_ps_mode - Sets the Power Save mode * - * @param priv A pointer to struct lbs_private structure - * @param cmd_action The Power Save operation (PS_MODE_ACTION_ENTER_PS or + * @priv: A pointer to &struct lbs_private structure + * @cmd_action: The Power Save operation (PS_MODE_ACTION_ENTER_PS or * PS_MODE_ACTION_EXIT_PS) - * @param block Whether to block on a response or not + * @block: Whether to block on a response or not * - * @return 0 on success, error on failure + * returns: 0 on success, error on failure */ int lbs_set_ps_mode(struct lbs_private *priv, u16 cmd_action, bool block) { @@ -417,13 +419,13 @@ int lbs_set_host_sleep(struct lbs_private *priv, int host_sleep) } /** - * @brief Set an SNMP MIB value + * lbs_set_snmp_mib - Set an SNMP MIB value * - * @param priv A pointer to struct lbs_private structure - * @param oid The OID to set in the firmware - * @param val Value to set the OID to + * @priv: A pointer to &struct lbs_private structure + * @oid: The OID to set in the firmware + * @val: Value to set the OID to * - * @return 0 on success, error on failure + * returns: 0 on success, error on failure */ int lbs_set_snmp_mib(struct lbs_private *priv, u32 oid, u16 val) { @@ -467,13 +469,13 @@ out: } /** - * @brief Get an SNMP MIB value + * lbs_get_snmp_mib - Get an SNMP MIB value * - * @param priv A pointer to struct lbs_private structure - * @param oid The OID to retrieve from the firmware - * @param out_val Location for the returned value + * @priv: A pointer to &struct lbs_private structure + * @oid: The OID to retrieve from the firmware + * @out_val: Location for the returned value * - * @return 0 on success, error on failure + * returns: 0 on success, error on failure */ int lbs_get_snmp_mib(struct lbs_private *priv, u32 oid, u16 *out_val) { @@ -510,14 +512,14 @@ out: } /** - * @brief Get the min, max, and current TX power + * lbs_get_tx_power - Get the min, max, and current TX power * - * @param priv A pointer to struct lbs_private structure - * @param curlevel Current power level in dBm - * @param minlevel Minimum supported power level in dBm (optional) - * @param maxlevel Maximum supported power level in dBm (optional) + * @priv: A pointer to &struct lbs_private structure + * @curlevel: Current power level in dBm + * @minlevel: Minimum supported power level in dBm (optional) + * @maxlevel: Maximum supported power level in dBm (optional) * - * @return 0 on success, error on failure + * returns: 0 on success, error on failure */ int lbs_get_tx_power(struct lbs_private *priv, s16 *curlevel, s16 *minlevel, s16 *maxlevel) @@ -545,12 +547,12 @@ int lbs_get_tx_power(struct lbs_private *priv, s16 *curlevel, s16 *minlevel, } /** - * @brief Set the TX power + * lbs_set_tx_power - Set the TX power * - * @param priv A pointer to struct lbs_private structure - * @param dbm The desired power level in dBm + * @priv: A pointer to &struct lbs_private structure + * @dbm: The desired power level in dBm * - * @return 0 on success, error on failure + * returns: 0 on success, error on failure */ int lbs_set_tx_power(struct lbs_private *priv, s16 dbm) { @@ -573,12 +575,13 @@ int lbs_set_tx_power(struct lbs_private *priv, s16 dbm) } /** - * @brief Enable or disable monitor mode (only implemented on OLPC usb8388 FW) + * lbs_set_monitor_mode - Enable or disable monitor mode + * (only implemented on OLPC usb8388 FW) * - * @param priv A pointer to struct lbs_private structure - * @param enable 1 to enable monitor mode, 0 to disable + * @priv: A pointer to &struct lbs_private structure + * @enable: 1 to enable monitor mode, 0 to disable * - * @return 0 on success, error on failure + * returns: 0 on success, error on failure */ int lbs_set_monitor_mode(struct lbs_private *priv, int enable) { @@ -604,11 +607,11 @@ int lbs_set_monitor_mode(struct lbs_private *priv, int enable) } /** - * @brief Get the radio channel + * lbs_get_channel - Get the radio channel * - * @param priv A pointer to struct lbs_private structure + * @priv: A pointer to &struct lbs_private structure * - * @return The channel on success, error on failure + * returns: The channel on success, error on failure */ static int lbs_get_channel(struct lbs_private *priv) { @@ -650,12 +653,12 @@ int lbs_update_channel(struct lbs_private *priv) } /** - * @brief Set the radio channel + * lbs_set_channel - Set the radio channel * - * @param priv A pointer to struct lbs_private structure - * @param channel The desired channel, or 0 to clear a locked channel + * @priv: A pointer to &struct lbs_private structure + * @channel: The desired channel, or 0 to clear a locked channel * - * @return 0 on success, error on failure + * returns: 0 on success, error on failure */ int lbs_set_channel(struct lbs_private *priv, u8 channel) { @@ -686,12 +689,13 @@ out: } /** - * @brief Get current RSSI and noise floor + * lbs_get_rssi - Get current RSSI and noise floor * - * @param priv A pointer to struct lbs_private structure - * @param rssi On successful return, signal level in mBm + * @priv: A pointer to &struct lbs_private structure + * @rssi: On successful return, signal level in mBm + * @nf: On successful return, Noise floor * - * @return The channel on success, error on failure + * returns: The channel on success, error on failure */ int lbs_get_rssi(struct lbs_private *priv, s8 *rssi, s8 *nf) { @@ -719,13 +723,14 @@ int lbs_get_rssi(struct lbs_private *priv, s8 *rssi, s8 *nf) } /** - * @brief Send regulatory and 802.11d domain information to the firmware + * lbs_set_11d_domain_info - Send regulatory and 802.11d domain information + * to the firmware * - * @param priv pointer to struct lbs_private - * @param request cfg80211 regulatory request structure - * @param bands the device's supported bands and channels + * @priv: pointer to &struct lbs_private + * @request: cfg80211 regulatory request structure + * @bands: the device's supported bands and channels * - * @return 0 on success, error code on failure + * returns: 0 on success, error code on failure */ int lbs_set_11d_domain_info(struct lbs_private *priv, struct regulatory_request *request, @@ -842,15 +847,15 @@ int lbs_set_11d_domain_info(struct lbs_private *priv, } /** - * @brief Read a MAC, Baseband, or RF register + * lbs_get_reg - Read a MAC, Baseband, or RF register * - * @param priv pointer to struct lbs_private - * @param cmd register command, one of CMD_MAC_REG_ACCESS, - * CMD_BBP_REG_ACCESS, or CMD_RF_REG_ACCESS - * @param offset byte offset of the register to get - * @param value on success, the value of the register at 'offset' + * @priv: pointer to &struct lbs_private + * @reg: register command, one of CMD_MAC_REG_ACCESS, + * CMD_BBP_REG_ACCESS, or CMD_RF_REG_ACCESS + * @offset: byte offset of the register to get + * @value: on success, the value of the register at 'offset' * - * @return 0 on success, error code on failure + * returns: 0 on success, error code on failure */ int lbs_get_reg(struct lbs_private *priv, u16 reg, u16 offset, u32 *value) { @@ -886,15 +891,15 @@ out: } /** - * @brief Write a MAC, Baseband, or RF register + * lbs_set_reg - Write a MAC, Baseband, or RF register * - * @param priv pointer to struct lbs_private - * @param cmd register command, one of CMD_MAC_REG_ACCESS, - * CMD_BBP_REG_ACCESS, or CMD_RF_REG_ACCESS - * @param offset byte offset of the register to set - * @param value the value to write to the register at 'offset' + * @priv: pointer to &struct lbs_private + * @reg: register command, one of CMD_MAC_REG_ACCESS, + * CMD_BBP_REG_ACCESS, or CMD_RF_REG_ACCESS + * @offset: byte offset of the register to set + * @value: the value to write to the register at 'offset' * - * @return 0 on success, error code on failure + * returns: 0 on success, error code on failure */ int lbs_set_reg(struct lbs_private *priv, u16 reg, u16 offset, u32 value) { @@ -1023,7 +1028,7 @@ static void lbs_submit_command(struct lbs_private *priv, lbs_deb_leave(LBS_DEB_HOST); } -/** +/* * This function inserts command node to cmdfreeq * after cleans it. Requires priv->driver_lock held. */ @@ -1125,11 +1130,12 @@ void lbs_set_mac_control(struct lbs_private *priv) } /** - * @brief This function allocates the command buffer and link - * it to command free queue. + * lbs_allocate_cmd_buffer - allocates the command buffer and links + * it to command free queue + * + * @priv: A pointer to &struct lbs_private structure * - * @param priv A pointer to struct lbs_private structure - * @return 0 or -1 + * returns: 0 for success or -1 on error */ int lbs_allocate_cmd_buffer(struct lbs_private *priv) { @@ -1171,10 +1177,11 @@ done: } /** - * @brief This function frees the command buffer. + * lbs_free_cmd_buffer - free the command buffer * - * @param priv A pointer to struct lbs_private structure - * @return 0 or -1 + * @priv: A pointer to &struct lbs_private structure + * + * returns: 0 for success */ int lbs_free_cmd_buffer(struct lbs_private *priv) { @@ -1211,11 +1218,13 @@ done: } /** - * @brief This function gets a free command node if available in - * command free queue. + * lbs_get_free_cmd_node - gets a free command node if available in + * command free queue + * + * @priv: A pointer to &struct lbs_private structure * - * @param priv A pointer to struct lbs_private structure - * @return cmd_ctrl_node A pointer to cmd_ctrl_node structure or NULL + * returns: A pointer to &cmd_ctrl_node structure on success + * or %NULL on error */ static struct cmd_ctrl_node *lbs_get_free_cmd_node(struct lbs_private *priv) { @@ -1245,12 +1254,12 @@ static struct cmd_ctrl_node *lbs_get_free_cmd_node(struct lbs_private *priv) } /** - * @brief This function executes next command in command - * pending queue. It will put firmware back to PS mode - * if applicable. + * lbs_execute_next_command - execute next command in command + * pending queue. Will put firmware back to PS mode if applicable. * - * @param priv A pointer to struct lbs_private structure - * @return 0 or -1 + * @priv: A pointer to &struct lbs_private structure + * + * returns: 0 on success or -1 on error */ int lbs_execute_next_command(struct lbs_private *priv) { @@ -1454,12 +1463,12 @@ out: } /** - * @brief This function checks condition and prepares to - * send sleep confirm command to firmware if ok. + * lbs_ps_confirm_sleep - checks condition and prepares to + * send sleep confirm command to firmware if ok + * + * @priv: A pointer to &struct lbs_private structure * - * @param priv A pointer to struct lbs_private structure - * @param psmode Power Saving mode - * @return n/a + * returns: n/a */ void lbs_ps_confirm_sleep(struct lbs_private *priv) { @@ -1499,16 +1508,16 @@ void lbs_ps_confirm_sleep(struct lbs_private *priv) /** - * @brief Configures the transmission power control functionality. + * lbs_set_tpc_cfg - Configures the transmission power control functionality * - * @param priv A pointer to struct lbs_private structure - * @param enable Transmission power control enable - * @param p0 Power level when link quality is good (dBm). - * @param p1 Power level when link quality is fair (dBm). - * @param p2 Power level when link quality is poor (dBm). - * @param usesnr Use Signal to Noise Ratio in TPC + * @priv: A pointer to &struct lbs_private structure + * @enable: Transmission power control enable + * @p0: Power level when link quality is good (dBm). + * @p1: Power level when link quality is fair (dBm). + * @p2: Power level when link quality is poor (dBm). + * @usesnr: Use Signal to Noise Ratio in TPC * - * @return 0 on success + * returns: 0 on success */ int lbs_set_tpc_cfg(struct lbs_private *priv, int enable, int8_t p0, int8_t p1, int8_t p2, int usesnr) @@ -1531,15 +1540,15 @@ int lbs_set_tpc_cfg(struct lbs_private *priv, int enable, int8_t p0, int8_t p1, } /** - * @brief Configures the power adaptation settings. + * lbs_set_power_adapt_cfg - Configures the power adaptation settings * - * @param priv A pointer to struct lbs_private structure - * @param enable Power adaptation enable - * @param p0 Power level for 1, 2, 5.5 and 11 Mbps (dBm). - * @param p1 Power level for 6, 9, 12, 18, 22, 24 and 36 Mbps (dBm). - * @param p2 Power level for 48 and 54 Mbps (dBm). + * @priv: A pointer to &struct lbs_private structure + * @enable: Power adaptation enable + * @p0: Power level for 1, 2, 5.5 and 11 Mbps (dBm). + * @p1: Power level for 6, 9, 12, 18, 22, 24 and 36 Mbps (dBm). + * @p2: Power level for 48 and 54 Mbps (dBm). * - * @return 0 on Success + * returns: 0 on Success */ int lbs_set_power_adapt_cfg(struct lbs_private *priv, int enable, int8_t p0, diff --git a/drivers/net/wireless/libertas/cmdresp.c b/drivers/net/wireless/libertas/cmdresp.c index 5e95da9..03e5289 100644 --- a/drivers/net/wireless/libertas/cmdresp.c +++ b/drivers/net/wireless/libertas/cmdresp.c @@ -1,7 +1,7 @@ -/** - * This file contains the handling of command - * responses as well as events generated by firmware. - */ +/* + * This file contains the handling of command + * responses as well as events generated by firmware. + */ #include #include #include @@ -12,12 +12,13 @@ #include "cmd.h" /** - * @brief This function handles disconnect event. it - * reports disconnect to upper layer, clean tx/rx packets, - * reset link state etc. + * lbs_mac_event_disconnected - handles disconnect event. It + * reports disconnect to upper layer, clean tx/rx packets, + * reset link state etc. + * + * @priv: A pointer to struct lbs_private structure * - * @param priv A pointer to struct lbs_private structure - * @return n/a + * returns: n/a */ void lbs_mac_event_disconnected(struct lbs_private *priv) { diff --git a/drivers/net/wireless/libertas/debugfs.c b/drivers/net/wireless/libertas/debugfs.c index fbf3b033..851fe7b 100644 --- a/drivers/net/wireless/libertas/debugfs.c +++ b/drivers/net/wireless/libertas/debugfs.c @@ -849,15 +849,14 @@ static struct debug_data items[] = { static int num_of_items = ARRAY_SIZE(items); /** - * @brief proc read function + * lbs_debugfs_read - proc read function * - * @param page pointer to buffer - * @param s read data starting position - * @param off offset - * @param cnt counter - * @param eof end of file flag - * @param data data to output - * @return number of output data + * @file: file to read + * @userbuf: pointer to buffer + * @count: number of bytes to read + * @ppos: read data starting position + * + * returns: amount of data read or negative error code */ static ssize_t lbs_debugfs_read(struct file *file, char __user *userbuf, size_t count, loff_t *ppos) @@ -897,13 +896,14 @@ static ssize_t lbs_debugfs_read(struct file *file, char __user *userbuf, } /** - * @brief proc write function + * lbs_debugfs_write - proc write function + * + * @f: file pointer + * @buf: pointer to data buffer + * @cnt: data number to write + * @ppos: file position * - * @param f file pointer - * @param buf pointer to data buffer - * @param cnt data number to write - * @param data data to write - * @return number of data + * returns: amount of data written */ static ssize_t lbs_debugfs_write(struct file *f, const char __user *buf, size_t cnt, loff_t *ppos) @@ -966,11 +966,11 @@ static const struct file_operations lbs_debug_fops = { }; /** - * @brief create debug proc file + * lbs_debug_init - create debug proc file + * + * @priv: pointer to &struct lbs_private * - * @param priv pointer struct lbs_private - * @param dev pointer net_device - * @return N/A + * returns: N/A */ static void lbs_debug_init(struct lbs_private *priv) { diff --git a/drivers/net/wireless/libertas/decl.h b/drivers/net/wireless/libertas/decl.h index 2ae752d..da0b05b 100644 --- a/drivers/net/wireless/libertas/decl.h +++ b/drivers/net/wireless/libertas/decl.h @@ -1,8 +1,8 @@ -/** - * This file contains declaration referring to - * functions defined in other source files - */ +/* + * This file contains declaration referring to + * functions defined in other source files + */ #ifndef _LBS_DECL_H_ #define _LBS_DECL_H_ diff --git a/drivers/net/wireless/libertas/defs.h b/drivers/net/wireless/libertas/defs.h index d00c728..92b5b1f 100644 --- a/drivers/net/wireless/libertas/defs.h +++ b/drivers/net/wireless/libertas/defs.h @@ -1,7 +1,7 @@ -/** - * This header file contains global constant/enum definitions, - * global variable declaration. - */ +/* + * This header file contains global constant/enum definitions, + * global variable declaration. + */ #ifndef _LBS_DEFS_H_ #define _LBS_DEFS_H_ @@ -123,19 +123,19 @@ static inline void lbs_deb_hex(unsigned int grp, const char *prompt, u8 *buf, in -/** Buffer Constants */ +/* Buffer Constants */ /* The size of SQ memory PPA, DPA are 8 DWORDs, that keep the physical -* addresses of TxPD buffers. Station has only 8 TxPD available, Whereas -* driver has more local TxPDs. Each TxPD on the host memory is associated -* with a Tx control node. The driver maintains 8 RxPD descriptors for -* station firmware to store Rx packet information. -* -* Current version of MAC has a 32x6 multicast address buffer. -* -* 802.11b can have up to 14 channels, the driver keeps the -* BSSID(MAC address) of each APs or Ad hoc stations it has sensed. -*/ + * addresses of TxPD buffers. Station has only 8 TxPD available, Whereas + * driver has more local TxPDs. Each TxPD on the host memory is associated + * with a Tx control node. The driver maintains 8 RxPD descriptors for + * station firmware to store Rx packet information. + * + * Current version of MAC has a 32x6 multicast address buffer. + * + * 802.11b can have up to 14 channels, the driver keeps the + * BSSID(MAC address) of each APs or Ad hoc stations it has sensed. + */ #define MRVDRV_MAX_MULTICAST_LIST_SIZE 32 #define LBS_NUM_CMD_BUFFERS 10 @@ -166,7 +166,7 @@ static inline void lbs_deb_hex(unsigned int grp, const char *prompt, u8 *buf, in #define WOL_RESULT_NOSPC_ERR 1 #define WOL_RESULT_EEXIST_ERR 2 -/** Misc constants */ +/* Misc constants */ /* This section defines 802.11 specific contants */ #define MRVDRV_MAX_BSS_DESCRIPTS 16 @@ -183,7 +183,8 @@ static inline void lbs_deb_hex(unsigned int grp, const char *prompt, u8 *buf, in #define MARVELL_MESH_IE_LENGTH 9 -/* Values used to populate the struct mrvl_mesh_ie. The only time you need this +/* + * Values used to populate the struct mrvl_mesh_ie. The only time you need this * is when enabling the mesh using CMD_MESH_CONFIG. */ #define MARVELL_MESH_IE_TYPE 4 @@ -193,7 +194,7 @@ static inline void lbs_deb_hex(unsigned int grp, const char *prompt, u8 *buf, in #define MARVELL_MESH_METRIC_ID 0 #define MARVELL_MESH_CAPABILITY 0 -/** INT status Bit Definition*/ +/* INT status Bit Definition */ #define MRVDRV_TX_DNLD_RDY 0x0001 #define MRVDRV_RX_UPLD_RDY 0x0002 #define MRVDRV_CMD_DNLD_RDY 0x0004 @@ -208,59 +209,63 @@ static inline void lbs_deb_hex(unsigned int grp, const char *prompt, u8 *buf, in #define TPC_DEFAULT_P1 10 #define TPC_DEFAULT_P2 13 -/** TxPD status */ +/* TxPD status */ -/* Station firmware use TxPD status field to report final Tx transmit -* result, Bit masks are used to present combined situations. -*/ +/* + * Station firmware use TxPD status field to report final Tx transmit + * result, Bit masks are used to present combined situations. + */ #define MRVDRV_TxPD_POWER_MGMT_NULL_PACKET 0x01 #define MRVDRV_TxPD_POWER_MGMT_LAST_PACKET 0x08 -/** Tx mesh flag */ -/* Currently we are using normal WDS flag as mesh flag. +/* Tx mesh flag */ +/* + * Currently we are using normal WDS flag as mesh flag. * TODO: change to proper mesh flag when MAC understands it. */ #define TxPD_CONTROL_WDS_FRAME (1<<17) #define TxPD_MESH_FRAME TxPD_CONTROL_WDS_FRAME -/** Mesh interface ID */ +/* Mesh interface ID */ #define MESH_IFACE_ID 0x0001 -/** Mesh id should be in bits 14-13-12 */ +/* Mesh id should be in bits 14-13-12 */ #define MESH_IFACE_BIT_OFFSET 0x000c -/** Mesh enable bit in FW capability */ +/* Mesh enable bit in FW capability */ #define MESH_CAPINFO_ENABLE_MASK (1<<16) -/** FW definition from Marvell v4 */ +/* FW definition from Marvell v4 */ #define MRVL_FW_V4 (0x04) -/** FW definition from Marvell v5 */ +/* FW definition from Marvell v5 */ #define MRVL_FW_V5 (0x05) -/** FW definition from Marvell v10 */ +/* FW definition from Marvell v10 */ #define MRVL_FW_V10 (0x0a) -/** FW major revision definition */ +/* FW major revision definition */ #define MRVL_FW_MAJOR_REV(x) ((x)>>24) -/** RxPD status */ +/* RxPD status */ #define MRVDRV_RXPD_STATUS_OK 0x0001 -/** RxPD status - Received packet types */ -/** Rx mesh flag */ -/* Currently we are using normal WDS flag as mesh flag. +/* RxPD status - Received packet types */ +/* Rx mesh flag */ +/* + * Currently we are using normal WDS flag as mesh flag. * TODO: change to proper mesh flag when MAC understands it. */ #define RxPD_CONTROL_WDS_FRAME (0x40) #define RxPD_MESH_FRAME RxPD_CONTROL_WDS_FRAME -/** RSSI-related defines */ -/* RSSI constants are used to implement 802.11 RSSI threshold -* indication. if the Rx packet signal got too weak for 5 consecutive -* times, miniport driver (driver) will report this event to wrapper -*/ +/* RSSI-related defines */ +/* + * RSSI constants are used to implement 802.11 RSSI threshold + * indication. if the Rx packet signal got too weak for 5 consecutive + * times, miniport driver (driver) will report this event to wrapper + */ #define MRVDRV_NF_DEFAULT_SCAN_VALUE (-96) -/** RTS/FRAG related defines */ +/* RTS/FRAG related defines */ #define MRVDRV_RTS_MIN_VALUE 0 #define MRVDRV_RTS_MAX_VALUE 2347 #define MRVDRV_FRAG_MIN_VALUE 256 @@ -300,36 +305,36 @@ static inline void lbs_deb_hex(unsigned int grp, const char *prompt, u8 *buf, in #define MAX_LEDS 8 -/** Global Variable Declaration */ +/* Global Variable Declaration */ extern const char lbs_driver_version[]; extern u16 lbs_region_code_to_index[MRVDRV_MAX_REGION_CODE]; -/** ENUM definition*/ -/** SNRNF_TYPE */ +/* ENUM definition */ +/* SNRNF_TYPE */ enum SNRNF_TYPE { TYPE_BEACON = 0, TYPE_RXPD, MAX_TYPE_B }; -/** SNRNF_DATA*/ +/* SNRNF_DATA */ enum SNRNF_DATA { TYPE_NOAVG = 0, TYPE_AVG, MAX_TYPE_AVG }; -/** LBS_802_11_POWER_MODE */ +/* LBS_802_11_POWER_MODE */ enum LBS_802_11_POWER_MODE { LBS802_11POWERMODECAM, LBS802_11POWERMODEMAX_PSP, LBS802_11POWERMODEFAST_PSP, - /*not a real mode, defined as an upper bound */ + /* not a real mode, defined as an upper bound */ LBS802_11POWEMODEMAX }; -/** PS_STATE */ +/* PS_STATE */ enum PS_STATE { PS_STATE_FULL_POWER, PS_STATE_AWAKE, @@ -337,7 +342,7 @@ enum PS_STATE { PS_STATE_SLEEP }; -/** DNLD_STATE */ +/* DNLD_STATE */ enum DNLD_STATE { DNLD_RES_RECEIVED, DNLD_DATA_SENT, @@ -345,19 +350,19 @@ enum DNLD_STATE { DNLD_BOOTCMD_SENT, }; -/** LBS_MEDIA_STATE */ +/* LBS_MEDIA_STATE */ enum LBS_MEDIA_STATE { LBS_CONNECTED, LBS_DISCONNECTED }; -/** LBS_802_11_PRIVACY_FILTER */ +/* LBS_802_11_PRIVACY_FILTER */ enum LBS_802_11_PRIVACY_FILTER { LBS802_11PRIVFILTERACCEPTALL, LBS802_11PRIVFILTER8021XWEP }; -/** mv_ms_type */ +/* mv_ms_type */ enum mv_ms_type { MVMS_DAT = 0, MVMS_CMD = 1, @@ -365,14 +370,14 @@ enum mv_ms_type { MVMS_EVENT }; -/** KEY_TYPE_ID */ +/* KEY_TYPE_ID */ enum KEY_TYPE_ID { KEY_TYPE_ID_WEP = 0, KEY_TYPE_ID_TKIP, KEY_TYPE_ID_AES }; -/** KEY_INFO_WPA (applies to both TKIP and AES/CCMP) */ +/* KEY_INFO_WPA (applies to both TKIP and AES/CCMP) */ enum KEY_INFO_WPA { KEY_INFO_WPA_MCAST = 0x01, KEY_INFO_WPA_UNICAST = 0x02, diff --git a/drivers/net/wireless/libertas/dev.h b/drivers/net/wireless/libertas/dev.h index bc461eb..76d018b 100644 --- a/drivers/net/wireless/libertas/dev.h +++ b/drivers/net/wireless/libertas/dev.h @@ -1,8 +1,8 @@ -/** - * This file contains definitions and data structures specific - * to Marvell 802.11 NIC. It contains the Device Information - * structure struct lbs_private.. - */ +/* + * This file contains definitions and data structures specific + * to Marvell 802.11 NIC. It contains the Device Information + * structure struct lbs_private.. + */ #ifndef _LBS_DEV_H_ #define _LBS_DEV_H_ @@ -12,7 +12,7 @@ #include -/** sleep_params */ +/* sleep_params */ struct sleep_params { uint16_t sp_error; uint16_t sp_offset; @@ -23,7 +23,7 @@ struct sleep_params { }; -/** Private structure for the MV device */ +/* Private structure for the MV device */ struct lbs_private { /* Basic networking */ @@ -125,12 +125,12 @@ struct lbs_private { /* Events sent from hardware to driver */ struct kfifo event_fifo; - /** thread to service interrupts */ + /* thread to service interrupts */ struct task_struct *main_thread; wait_queue_head_t waitq; struct workqueue_struct *work_thread; - /** Encryption stuff */ + /* Encryption stuff */ u8 authtype_auto; u8 wep_tx_key; u8 wep_key[4][WLAN_KEY_LEN_WEP104]; @@ -162,7 +162,7 @@ struct lbs_private { s16 txpower_min; s16 txpower_max; - /** Scanning */ + /* Scanning */ struct delayed_work scan_work; int scan_channel; /* Queue of things waiting for scan completion */ diff --git a/drivers/net/wireless/libertas/ethtool.c b/drivers/net/wireless/libertas/ethtool.c index 50193aa..29dbce4 100644 --- a/drivers/net/wireless/libertas/ethtool.c +++ b/drivers/net/wireless/libertas/ethtool.c @@ -20,7 +20,8 @@ static void lbs_ethtool_get_drvinfo(struct net_device *dev, strcpy(info->version, lbs_driver_version); } -/* All 8388 parts have 16KiB EEPROM size at the time of writing. +/* + * All 8388 parts have 16KiB EEPROM size at the time of writing. * In case that changes this needs fixing. */ #define LBS_EEPROM_LEN 16384 diff --git a/drivers/net/wireless/libertas/host.h b/drivers/net/wireless/libertas/host.h index 6cb6935..2e2dbfa 100644 --- a/drivers/net/wireless/libertas/host.h +++ b/drivers/net/wireless/libertas/host.h @@ -1,7 +1,7 @@ -/** - * This file function prototypes, data structure - * and definitions for all the host/station commands - */ +/* + * This file function prototypes, data structure + * and definitions for all the host/station commands + */ #ifndef _LBS_HOST_H_ #define _LBS_HOST_H_ @@ -13,9 +13,10 @@ #define CMD_OPTION_WAITFORRSP 0x0002 -/** Host command IDs */ +/* Host command IDs */ -/* Return command are almost always the same as the host command, but with +/* + * Return command are almost always the same as the host command, but with * bit 15 set high. There are a few exceptions, though... */ #define CMD_RET(cmd) (0x8000 | cmd) @@ -251,7 +252,7 @@ enum cmd_mesh_config_types { CMD_TYPE_MESH_GET_MESH_IE, /* GET_DEFAULTS is superset of GET_MESHIE */ }; -/** Card Event definition */ +/* Card Event definition */ #define MACREG_INT_CODE_TX_PPA_FREE 0 #define MACREG_INT_CODE_TX_DMA_DONE 1 #define MACREG_INT_CODE_LINK_LOST_W_SCAN 2 @@ -624,12 +625,14 @@ struct cmd_ds_802_11_rf_channel { struct cmd_ds_802_11_rssi { struct cmd_header hdr; - /* request: number of beacons (N) to average the SNR and NF over + /* + * request: number of beacons (N) to average the SNR and NF over * response: SNR of most recent beacon */ __le16 n_or_snr; - /* The following fields are only set in the response. + /* + * The following fields are only set in the response. * In the request these are reserved and should be set to 0. */ __le16 nf; /* most recent beacon noise floor */ @@ -680,14 +683,16 @@ struct cmd_ds_802_11_ps_mode { __le16 action; - /* Interval for keepalive in PS mode: + /* + * Interval for keepalive in PS mode: * 0x0000 = don't change * 0x001E = firmware default * 0xFFFF = disable */ __le16 nullpktinterval; - /* Number of DTIM intervals to wake up for: + /* + * Number of DTIM intervals to wake up for: * 0 = don't change * 1 = firmware default * 5 = max @@ -697,7 +702,8 @@ struct cmd_ds_802_11_ps_mode { __le16 reserved; __le16 locallisteninterval; - /* AdHoc awake period (FW v9+ only): + /* + * AdHoc awake period (FW v9+ only): * 0 = don't change * 1 = always awake (IEEE standard behavior) * 2 - 31 = sleep for (n - 1) periods and awake for 1 period @@ -771,7 +777,8 @@ struct adhoc_bssdesc { __le16 capability; u8 rates[MAX_RATES]; - /* DO NOT ADD ANY FIELDS TO THIS STRUCTURE. It is used below in the + /* + * DO NOT ADD ANY FIELDS TO THIS STRUCTURE. It is used below in the * Adhoc join command and will cause a binary layout mismatch with * the firmware */ diff --git a/drivers/net/wireless/libertas/if_cs.c b/drivers/net/wireless/libertas/if_cs.c index fc81211..4dfd48f 100644 --- a/drivers/net/wireless/libertas/if_cs.c +++ b/drivers/net/wireless/libertas/if_cs.c @@ -312,7 +312,8 @@ static int if_cs_poll_while_fw_download(struct if_cs_card *card, uint addr, u8 r #define CF8385_MANFID 0x02df #define CF8385_CARDID 0x8103 -/* FIXME: just use the 'driver_info' field of 'struct pcmcia_device_id' when +/* + * FIXME: just use the 'driver_info' field of 'struct pcmcia_device_id' when * that gets fixed. Currently there's no way to access it from the probe hook. */ static inline u32 get_model(u16 manf_id, u16 card_id) @@ -621,8 +622,10 @@ static int if_cs_prog_helper(struct if_cs_card *card, const struct firmware *fw) if (remain < count) count = remain; - /* "write the number of bytes to be sent to the I/O Command - * write length register" */ + /* + * "write the number of bytes to be sent to the I/O Command + * write length register" + */ if_cs_write16(card, IF_CS_CMD_LEN, count); /* "write this to I/O Command port register as 16 bit writes */ @@ -631,16 +634,22 @@ static int if_cs_prog_helper(struct if_cs_card *card, const struct firmware *fw) &fw->data[sent], count >> 1); - /* "Assert the download over interrupt command in the Host - * status register" */ + /* + * "Assert the download over interrupt command in the Host + * status register" + */ if_cs_write8(card, IF_CS_HOST_STATUS, IF_CS_BIT_COMMAND); - /* "Assert the download over interrupt command in the Card - * interrupt case register" */ + /* + * "Assert the download over interrupt command in the Card + * interrupt case register" + */ if_cs_write16(card, IF_CS_HOST_INT_CAUSE, IF_CS_BIT_COMMAND); - /* "The host polls the Card Status register ... for 50 ms before - declaring a failure */ + /* + * "The host polls the Card Status register ... for 50 ms before + * declaring a failure" + */ ret = if_cs_poll_while_fw_download(card, IF_CS_CARD_STATUS, IF_CS_BIT_COMMAND); if (ret < 0) { @@ -841,7 +850,7 @@ static int if_cs_probe(struct pcmcia_device *p_dev) /* * Most of the libertas cards can do unaligned register access, but some - * weird ones can not. That's especially true for the CF8305 card. + * weird ones cannot. That's especially true for the CF8305 card. */ card->align_regs = 0; @@ -913,8 +922,10 @@ static int if_cs_probe(struct pcmcia_device *p_dev) goto out3; } - /* Clear any interrupt cause that happend while sending - * firmware/initializing card */ + /* + * Clear any interrupt cause that happened while sending + * firmware/initializing card + */ if_cs_write16(card, IF_CS_CARD_INT_CAUSE, IF_CS_BIT_MASK); if_cs_enable_ints(card); diff --git a/drivers/net/wireless/libertas/if_spi.c b/drivers/net/wireless/libertas/if_spi.c index 078ef43d9..67de5b3 100644 --- a/drivers/net/wireless/libertas/if_spi.c +++ b/drivers/net/wireless/libertas/if_spi.c @@ -143,8 +143,10 @@ static void spu_transaction_finish(struct if_spi_card *card) card->prev_xfer_time = jiffies; } -/* Write out a byte buffer to an SPI register, - * using a series of 16-bit transfers. */ +/* + * Write out a byte buffer to an SPI register, + * using a series of 16-bit transfers. + */ static int spu_write(struct if_spi_card *card, u16 reg, const u8 *buf, int len) { int err = 0; @@ -208,8 +210,10 @@ static int spu_read(struct if_spi_card *card, u16 reg, u8 *buf, int len) struct spi_transfer dummy_trans; struct spi_transfer data_trans; - /* You must take an even number of bytes from the SPU, even if you - * don't care about the last one. */ + /* + * You must take an even number of bytes from the SPU, even if you + * don't care about the last one. + */ BUG_ON(len & 0x1); spu_transaction_init(card); @@ -258,8 +262,10 @@ static inline int spu_read_u16(struct if_spi_card *card, u16 reg, u16 *val) return ret; } -/* Read 32 bits from an SPI register. - * The low 16 bits are read first. */ +/* + * Read 32 bits from an SPI register. + * The low 16 bits are read first. + */ static int spu_read_u32(struct if_spi_card *card, u16 reg, u32 *val) { __le32 buf; @@ -271,13 +277,15 @@ static int spu_read_u32(struct if_spi_card *card, u16 reg, u32 *val) return err; } -/* Keep reading 16 bits from an SPI register until you get the correct result. +/* + * Keep reading 16 bits from an SPI register until you get the correct result. * * If mask = 0, the correct result is any non-zero number. * If mask != 0, the correct result is any number where * number & target_mask == target * - * Returns -ETIMEDOUT if a second passes without the correct result. */ + * Returns -ETIMEDOUT if a second passes without the correct result. + */ static int spu_wait_for_u16(struct if_spi_card *card, u16 reg, u16 target_mask, u16 target) { @@ -305,8 +313,10 @@ static int spu_wait_for_u16(struct if_spi_card *card, u16 reg, } } -/* Read 16 bits from an SPI register until you receive a specific value. - * Returns -ETIMEDOUT if a 4 tries pass without success. */ +/* + * Read 16 bits from an SPI register until you receive a specific value. + * Returns -ETIMEDOUT if a 4 tries pass without success. + */ static int spu_wait_for_u32(struct if_spi_card *card, u32 reg, u32 target) { int err, try; @@ -328,8 +338,10 @@ static int spu_set_interrupt_mode(struct if_spi_card *card, { int err = 0; - /* We can suppress a host interrupt by clearing the appropriate - * bit in the "host interrupt status mask" register */ + /* + * We can suppress a host interrupt by clearing the appropriate + * bit in the "host interrupt status mask" register + */ if (suppress_host_int) { err = spu_write_u16(card, IF_SPI_HOST_INT_STATUS_MASK_REG, 0); if (err) @@ -345,10 +357,12 @@ static int spu_set_interrupt_mode(struct if_spi_card *card, return err; } - /* If auto-interrupts are on, the completion of certain transactions + /* + * If auto-interrupts are on, the completion of certain transactions * will trigger an interrupt automatically. If auto-interrupts * are off, we need to set the "Card Interrupt Cause" register to - * trigger a card interrupt. */ + * trigger a card interrupt. + */ if (auto_int) { err = spu_write_u16(card, IF_SPI_HOST_INT_CTRL_REG, IF_SPI_HICT_TX_DOWNLOAD_OVER_AUTO | @@ -402,8 +416,10 @@ static int spu_init(struct if_spi_card *card, int use_dummy_writes) int err = 0; u32 delay; - /* We have to start up in timed delay mode so that we can safely - * read the Delay Read Register. */ + /* + * We have to start up in timed delay mode so that we can safely + * read the Delay Read Register. + */ card->use_dummy_writes = 0; err = spu_set_bus_mode(card, IF_SPI_BUS_MODE_SPI_CLOCK_PHASE_RISING | @@ -459,8 +475,10 @@ static int if_spi_prog_helper_firmware(struct if_spi_card *card, /* Load helper firmware image */ while (bytes_remaining > 0) { - /* Scratch pad 1 should contain the number of bytes we - * want to download to the firmware */ + /* + * Scratch pad 1 should contain the number of bytes we + * want to download to the firmware + */ err = spu_write_u16(card, IF_SPI_SCRATCH_1_REG, HELPER_FW_LOAD_CHUNK_SZ); if (err) @@ -472,8 +490,10 @@ static int if_spi_prog_helper_firmware(struct if_spi_card *card, if (err) goto out; - /* Feed the data into the command read/write port reg - * in chunks of 64 bytes */ + /* + * Feed the data into the command read/write port reg + * in chunks of 64 bytes + */ memset(temp, 0, sizeof(temp)); memcpy(temp, fw, min(bytes_remaining, HELPER_FW_LOAD_CHUNK_SZ)); @@ -495,9 +515,11 @@ static int if_spi_prog_helper_firmware(struct if_spi_card *card, fw += HELPER_FW_LOAD_CHUNK_SZ; } - /* Once the helper / single stage firmware download is complete, + /* + * Once the helper / single stage firmware download is complete, * write 0 to scratch pad 1 and interrupt the - * bootloader. This completes the helper download. */ + * bootloader. This completes the helper download. + */ err = spu_write_u16(card, IF_SPI_SCRATCH_1_REG, FIRMWARE_DNLD_OK); if (err) goto out; @@ -517,16 +539,20 @@ out: return err; } -/* Returns the length of the next packet the firmware expects us to send - * Sets crc_err if the previous transfer had a CRC error. */ +/* + * Returns the length of the next packet the firmware expects us to send. + * Sets crc_err if the previous transfer had a CRC error. + */ static int if_spi_prog_main_firmware_check_len(struct if_spi_card *card, int *crc_err) { u16 len; int err = 0; - /* wait until the host interrupt status register indicates - * that we are ready to download */ + /* + * wait until the host interrupt status register indicates + * that we are ready to download + */ err = spu_wait_for_u16(card, IF_SPI_HOST_INT_STATUS_REG, IF_SPI_HIST_CMD_DOWNLOAD_RDY, IF_SPI_HIST_CMD_DOWNLOAD_RDY); @@ -587,8 +613,10 @@ static int if_spi_prog_main_firmware(struct if_spi_card *card, goto out; } if (bytes < 0) { - /* If there are no more bytes left, we would normally - * expect to have terminated with len = 0 */ + /* + * If there are no more bytes left, we would normally + * expect to have terminated with len = 0 + */ lbs_pr_err("Firmware load wants more bytes " "than we have to offer.\n"); break; @@ -660,14 +688,18 @@ static int if_spi_c2h_cmd(struct if_spi_card *card) u16 len; u8 i; - /* We need a buffer big enough to handle whatever people send to - * hw_host_to_card */ + /* + * We need a buffer big enough to handle whatever people send to + * hw_host_to_card + */ BUILD_BUG_ON(IF_SPI_CMD_BUF_SIZE < LBS_CMD_BUFFER_SIZE); BUILD_BUG_ON(IF_SPI_CMD_BUF_SIZE < LBS_UPLD_SIZE); - /* It's just annoying if the buffer size isn't a multiple of 4, because - * then we might have len < IF_SPI_CMD_BUF_SIZE but - * ALIGN(len, 4) > IF_SPI_CMD_BUF_SIZE */ + /* + * It's just annoying if the buffer size isn't a multiple of 4, because + * then we might have len < IF_SPI_CMD_BUF_SIZE but + * ALIGN(len, 4) > IF_SPI_CMD_BUF_SIZE + */ BUILD_BUG_ON(IF_SPI_CMD_BUF_SIZE % 4 != 0); lbs_deb_enter(LBS_DEB_SPI); @@ -838,8 +870,10 @@ static void if_spi_host_to_card_worker(struct work_struct *work) lbs_deb_enter(LBS_DEB_SPI); - /* Read the host interrupt status register to see what we - * can do. */ + /* + * Read the host interrupt status register to see what we + * can do. + */ err = spu_read_u16(card, IF_SPI_HOST_INT_STATUS_REG, &hiStatus); if (err) { @@ -858,12 +892,15 @@ static void if_spi_host_to_card_worker(struct work_struct *work) goto err; } - /* workaround: in PS mode, the card does not set the Command - * Download Ready bit, but it sets TX Download Ready. */ + /* + * workaround: in PS mode, the card does not set the Command + * Download Ready bit, but it sets TX Download Ready. + */ if (hiStatus & IF_SPI_HIST_CMD_DOWNLOAD_RDY || (card->priv->psstate != PS_STATE_FULL_POWER && (hiStatus & IF_SPI_HIST_TX_DOWNLOAD_RDY))) { - /* This means two things. First of all, + /* + * This means two things. First of all, * if there was a previous command sent, the card has * successfully received it. * Secondly, it is now ready to download another @@ -871,8 +908,7 @@ static void if_spi_host_to_card_worker(struct work_struct *work) */ lbs_host_to_card_done(card->priv); - /* Do we have any command packets from the host to - * send? */ + /* Do we have any command packets from the host to send? */ packet = NULL; spin_lock_irqsave(&card->buffer_lock, flags); if (!list_empty(&card->cmd_packet_list)) { @@ -886,8 +922,7 @@ static void if_spi_host_to_card_worker(struct work_struct *work) if_spi_h2c(card, packet, MVMS_CMD); } if (hiStatus & IF_SPI_HIST_TX_DOWNLOAD_RDY) { - /* Do we have any data packets from the host to - * send? */ + /* Do we have any data packets from the host to send? */ packet = NULL; spin_lock_irqsave(&card->buffer_lock, flags); if (!list_empty(&card->data_packet_list)) { @@ -914,7 +949,8 @@ err: * Host to Card * * Called from Libertas to transfer some data to the WLAN device - * We can't sleep here. */ + * We can't sleep here. + */ static int if_spi_host_to_card(struct lbs_private *priv, u8 type, u8 *buf, u16 nb) { @@ -1125,8 +1161,10 @@ static int __devinit if_spi_probe(struct spi_device *spi) if (err) goto free_card; - /* Register our card with libertas. - * This will call alloc_etherdev */ + /* + * Register our card with libertas. + * This will call alloc_etherdev. + */ priv = lbs_add_card(card, &spi->dev); if (!priv) { err = -ENOMEM; @@ -1153,9 +1191,11 @@ static int __devinit if_spi_probe(struct spi_device *spi) goto terminate_workqueue; } - /* Start the card. + /* + * Start the card. * This will call register_netdev, and we'll start - * getting interrupts... */ + * getting interrupts... + */ err = lbs_start_card(priv); if (err) goto release_irq; diff --git a/drivers/net/wireless/libertas/if_spi.h b/drivers/net/wireless/libertas/if_spi.h index 8b1417d..9745bd4 100644 --- a/drivers/net/wireless/libertas/if_spi.h +++ b/drivers/net/wireless/libertas/if_spi.h @@ -86,34 +86,34 @@ #define IF_SPI_DEVICEID_CTRL_REG_TO_CARD_REV(dc) (dc & 0x000000ff) /***************** IF_SPI_HOST_INT_CTRL_REG *****************/ -/** Host Interrupt Control bit : Wake up */ +/* Host Interrupt Control bit : Wake up */ #define IF_SPI_HICT_WAKE_UP (1<<0) -/** Host Interrupt Control bit : WLAN ready */ +/* Host Interrupt Control bit : WLAN ready */ #define IF_SPI_HICT_WLAN_READY (1<<1) /*#define IF_SPI_HICT_FIFO_FIRST_HALF_EMPTY (1<<2) */ /*#define IF_SPI_HICT_FIFO_SECOND_HALF_EMPTY (1<<3) */ /*#define IF_SPI_HICT_IRQSRC_WLAN (1<<4) */ -/** Host Interrupt Control bit : Tx auto download */ +/* Host Interrupt Control bit : Tx auto download */ #define IF_SPI_HICT_TX_DOWNLOAD_OVER_AUTO (1<<5) -/** Host Interrupt Control bit : Rx auto upload */ +/* Host Interrupt Control bit : Rx auto upload */ #define IF_SPI_HICT_RX_UPLOAD_OVER_AUTO (1<<6) -/** Host Interrupt Control bit : Command auto download */ +/* Host Interrupt Control bit : Command auto download */ #define IF_SPI_HICT_CMD_DOWNLOAD_OVER_AUTO (1<<7) -/** Host Interrupt Control bit : Command auto upload */ +/* Host Interrupt Control bit : Command auto upload */ #define IF_SPI_HICT_CMD_UPLOAD_OVER_AUTO (1<<8) /***************** IF_SPI_CARD_INT_CAUSE_REG *****************/ -/** Card Interrupt Case bit : Tx download over */ +/* Card Interrupt Case bit : Tx download over */ #define IF_SPI_CIC_TX_DOWNLOAD_OVER (1<<0) -/** Card Interrupt Case bit : Rx upload over */ +/* Card Interrupt Case bit : Rx upload over */ #define IF_SPI_CIC_RX_UPLOAD_OVER (1<<1) -/** Card Interrupt Case bit : Command download over */ +/* Card Interrupt Case bit : Command download over */ #define IF_SPI_CIC_CMD_DOWNLOAD_OVER (1<<2) -/** Card Interrupt Case bit : Host event */ +/* Card Interrupt Case bit : Host event */ #define IF_SPI_CIC_HOST_EVENT (1<<3) -/** Card Interrupt Case bit : Command upload over */ +/* Card Interrupt Case bit : Command upload over */ #define IF_SPI_CIC_CMD_UPLOAD_OVER (1<<4) -/** Card Interrupt Case bit : Power down */ +/* Card Interrupt Case bit : Power down */ #define IF_SPI_CIC_POWER_DOWN (1<<5) /***************** IF_SPI_CARD_INT_STATUS_REG *****************/ @@ -138,51 +138,51 @@ #define IF_SPI_HICU_CMD_RD_FIFO_UNDERFLOW (1<<10) /***************** IF_SPI_HOST_INT_STATUS_REG *****************/ -/** Host Interrupt Status bit : Tx download ready */ +/* Host Interrupt Status bit : Tx download ready */ #define IF_SPI_HIST_TX_DOWNLOAD_RDY (1<<0) -/** Host Interrupt Status bit : Rx upload ready */ +/* Host Interrupt Status bit : Rx upload ready */ #define IF_SPI_HIST_RX_UPLOAD_RDY (1<<1) -/** Host Interrupt Status bit : Command download ready */ +/* Host Interrupt Status bit : Command download ready */ #define IF_SPI_HIST_CMD_DOWNLOAD_RDY (1<<2) -/** Host Interrupt Status bit : Card event */ +/* Host Interrupt Status bit : Card event */ #define IF_SPI_HIST_CARD_EVENT (1<<3) -/** Host Interrupt Status bit : Command upload ready */ +/* Host Interrupt Status bit : Command upload ready */ #define IF_SPI_HIST_CMD_UPLOAD_RDY (1<<4) -/** Host Interrupt Status bit : I/O write FIFO overflow */ +/* Host Interrupt Status bit : I/O write FIFO overflow */ #define IF_SPI_HIST_IO_WR_FIFO_OVERFLOW (1<<5) -/** Host Interrupt Status bit : I/O read FIFO underflow */ +/* Host Interrupt Status bit : I/O read FIFO underflow */ #define IF_SPI_HIST_IO_RD_FIFO_UNDRFLOW (1<<6) -/** Host Interrupt Status bit : Data write FIFO overflow */ +/* Host Interrupt Status bit : Data write FIFO overflow */ #define IF_SPI_HIST_DATA_WR_FIFO_OVERFLOW (1<<7) -/** Host Interrupt Status bit : Data read FIFO underflow */ +/* Host Interrupt Status bit : Data read FIFO underflow */ #define IF_SPI_HIST_DATA_RD_FIFO_UNDERFLOW (1<<8) -/** Host Interrupt Status bit : Command write FIFO overflow */ +/* Host Interrupt Status bit : Command write FIFO overflow */ #define IF_SPI_HIST_CMD_WR_FIFO_OVERFLOW (1<<9) -/** Host Interrupt Status bit : Command read FIFO underflow */ +/* Host Interrupt Status bit : Command read FIFO underflow */ #define IF_SPI_HIST_CMD_RD_FIFO_UNDERFLOW (1<<10) /***************** IF_SPI_HOST_INT_STATUS_MASK_REG *****************/ -/** Host Interrupt Status Mask bit : Tx download ready */ +/* Host Interrupt Status Mask bit : Tx download ready */ #define IF_SPI_HISM_TX_DOWNLOAD_RDY (1<<0) -/** Host Interrupt Status Mask bit : Rx upload ready */ +/* Host Interrupt Status Mask bit : Rx upload ready */ #define IF_SPI_HISM_RX_UPLOAD_RDY (1<<1) -/** Host Interrupt Status Mask bit : Command download ready */ +/* Host Interrupt Status Mask bit : Command download ready */ #define IF_SPI_HISM_CMD_DOWNLOAD_RDY (1<<2) -/** Host Interrupt Status Mask bit : Card event */ +/* Host Interrupt Status Mask bit : Card event */ #define IF_SPI_HISM_CARDEVENT (1<<3) -/** Host Interrupt Status Mask bit : Command upload ready */ +/* Host Interrupt Status Mask bit : Command upload ready */ #define IF_SPI_HISM_CMD_UPLOAD_RDY (1<<4) -/** Host Interrupt Status Mask bit : I/O write FIFO overflow */ +/* Host Interrupt Status Mask bit : I/O write FIFO overflow */ #define IF_SPI_HISM_IO_WR_FIFO_OVERFLOW (1<<5) -/** Host Interrupt Status Mask bit : I/O read FIFO underflow */ +/* Host Interrupt Status Mask bit : I/O read FIFO underflow */ #define IF_SPI_HISM_IO_RD_FIFO_UNDERFLOW (1<<6) -/** Host Interrupt Status Mask bit : Data write FIFO overflow */ +/* Host Interrupt Status Mask bit : Data write FIFO overflow */ #define IF_SPI_HISM_DATA_WR_FIFO_OVERFLOW (1<<7) -/** Host Interrupt Status Mask bit : Data write FIFO underflow */ +/* Host Interrupt Status Mask bit : Data write FIFO underflow */ #define IF_SPI_HISM_DATA_RD_FIFO_UNDERFLOW (1<<8) -/** Host Interrupt Status Mask bit : Command write FIFO overflow */ +/* Host Interrupt Status Mask bit : Command write FIFO overflow */ #define IF_SPI_HISM_CMD_WR_FIFO_OVERFLOW (1<<9) -/** Host Interrupt Status Mask bit : Command write FIFO underflow */ +/* Host Interrupt Status Mask bit : Command write FIFO underflow */ #define IF_SPI_HISM_CMD_RD_FIFO_UNDERFLOW (1<<10) /***************** IF_SPI_SPU_BUS_MODE_REG *****************/ diff --git a/drivers/net/wireless/libertas/if_usb.c b/drivers/net/wireless/libertas/if_usb.c index 6524c70..e1e2128f 100644 --- a/drivers/net/wireless/libertas/if_usb.c +++ b/drivers/net/wireless/libertas/if_usb.c @@ -1,6 +1,6 @@ -/** - * This file contains functions used in USB interface module. - */ +/* + * This file contains functions used in USB interface module. + */ #include #include #include @@ -66,7 +66,7 @@ static int if_usb_reset_device(struct if_usb_card *cardp); /* sysfs hooks */ -/** +/* * Set function to write firmware to device's persistent memory */ static ssize_t if_usb_firmware_set(struct device *dev, @@ -85,7 +85,7 @@ static ssize_t if_usb_firmware_set(struct device *dev, return ret; } -/** +/* * lbs_flash_fw attribute to be exported per ethX interface through sysfs * (/sys/class/net/ethX/lbs_flash_fw). Use this like so to write firmware to * the device's persistent memory: @@ -94,7 +94,14 @@ static ssize_t if_usb_firmware_set(struct device *dev, static DEVICE_ATTR(lbs_flash_fw, 0200, NULL, if_usb_firmware_set); /** - * Set function to write firmware to device's persistent memory + * if_usb_boot2_set - write firmware to device's persistent memory + * + * @dev: target device + * @attr: device attributes + * @buf: firmware buffer to write + * @count: number of bytes to write + * + * returns: number of bytes written or negative error code */ static ssize_t if_usb_boot2_set(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) @@ -112,7 +119,7 @@ static ssize_t if_usb_boot2_set(struct device *dev, return ret; } -/** +/* * lbs_flash_boot2 attribute to be exported per ethX interface through sysfs * (/sys/class/net/ethX/lbs_flash_boot2). Use this like so to write firmware * to the device's persistent memory: @@ -121,9 +128,10 @@ static ssize_t if_usb_boot2_set(struct device *dev, static DEVICE_ATTR(lbs_flash_boot2, 0200, NULL, if_usb_boot2_set); /** - * @brief call back function to handle the status of the URB - * @param urb pointer to urb structure - * @return N/A + * if_usb_write_bulk_callback - callback function to handle the status + * of the URB + * @urb: pointer to &urb structure + * returns: N/A */ static void if_usb_write_bulk_callback(struct urb *urb) { @@ -150,9 +158,9 @@ static void if_usb_write_bulk_callback(struct urb *urb) } /** - * @brief free tx/rx urb, skb and rx buffer - * @param cardp pointer if_usb_card - * @return N/A + * if_usb_free - free tx/rx urb, skb and rx buffer + * @cardp: pointer to &if_usb_card + * returns: N/A */ static void if_usb_free(struct if_usb_card *cardp) { @@ -231,10 +239,10 @@ static void if_usb_reset_olpc_card(struct lbs_private *priv) #endif /** - * @brief sets the configuration values - * @param ifnum interface number - * @param id pointer to usb_device_id - * @return 0 on success, error code on failure + * if_usb_probe - sets the configuration values + * @intf: &usb_interface pointer + * @id: pointer to usb_device_id + * returns: 0 on success, error code on failure */ static int if_usb_probe(struct usb_interface *intf, const struct usb_device_id *id) @@ -366,9 +374,9 @@ error: } /** - * @brief free resource and cleanup - * @param intf USB interface structure - * @return N/A + * if_usb_disconnect - free resource and cleanup + * @intf: USB interface structure + * returns: N/A */ static void if_usb_disconnect(struct usb_interface *intf) { @@ -398,9 +406,9 @@ static void if_usb_disconnect(struct usb_interface *intf) } /** - * @brief This function download FW - * @param priv pointer to struct lbs_private - * @return 0 + * if_usb_send_fw_pkt - download FW + * @cardp: pointer to &struct if_usb_card + * returns: 0 */ static int if_usb_send_fw_pkt(struct if_usb_card *cardp) { @@ -486,11 +494,11 @@ static int if_usb_reset_device(struct if_usb_card *cardp) } /** - * @brief This function transfer the data to the device. - * @param priv pointer to struct lbs_private - * @param payload pointer to payload data - * @param nb data length - * @return 0 or -1 + * usb_tx_block - transfer the data to the device + * @cardp: pointer to &struct if_usb_card + * @payload: pointer to payload data + * @nb: data length + * returns: 0 for success or negative error code */ static int usb_tx_block(struct if_usb_card *cardp, uint8_t *payload, uint16_t nb) { @@ -727,11 +735,11 @@ static inline void process_cmdrequest(int recvlength, uint8_t *recvbuff, } /** - * @brief This function reads of the packet into the upload buff, - * wake up the main thread and initialise the Rx callack. + * if_usb_receive - read the packet into the upload buffer, + * wake up the main thread and initialise the Rx callack * - * @param urb pointer to struct urb - * @return N/A + * @urb: pointer to &struct urb + * returns: N/A */ static void if_usb_receive(struct urb *urb) { @@ -802,12 +810,12 @@ rx_exit: } /** - * @brief This function downloads data to FW - * @param priv pointer to struct lbs_private structure - * @param type type of data - * @param buf pointer to data buffer - * @param len number of bytes - * @return 0 or -1 + * if_usb_host_to_card - downloads data to FW + * @priv: pointer to &struct lbs_private structure + * @type: type of data + * @payload: pointer to data buffer + * @nb: number of bytes + * returns: 0 for success or negative error code */ static int if_usb_host_to_card(struct lbs_private *priv, uint8_t type, uint8_t *payload, uint16_t nb) @@ -831,10 +839,11 @@ static int if_usb_host_to_card(struct lbs_private *priv, uint8_t type, } /** - * @brief This function issues Boot command to the Boot2 code - * @param ivalue 1:Boot from FW by USB-Download - * 2:Boot from FW in EEPROM - * @return 0 + * if_usb_issue_boot_command - issues Boot command to the Boot2 code + * @cardp: pointer to &if_usb_card + * @ivalue: 1:Boot from FW by USB-Download + * 2:Boot from FW in EEPROM + * returns: 0 for success or negative error code */ static int if_usb_issue_boot_command(struct if_usb_card *cardp, int ivalue) { @@ -853,11 +862,11 @@ static int if_usb_issue_boot_command(struct if_usb_card *cardp, int ivalue) /** - * @brief This function checks the validity of Boot2/FW image. + * check_fwfile_format - check the validity of Boot2/FW image * - * @param data pointer to image - * len image length - * @return 0 or -1 + * @data: pointer to image + * @totlen: image length + * returns: 0 (good) or 1 (failure) */ static int check_fwfile_format(const uint8_t *data, uint32_t totlen) { @@ -901,13 +910,13 @@ static int check_fwfile_format(const uint8_t *data, uint32_t totlen) /** -* @brief This function programs the firmware subject to cmd +* if_usb_prog_firmware - programs the firmware subject to cmd * -* @param cardp the if_usb_card descriptor -* fwname firmware or boot2 image file name -* cmd either BOOT_CMD_FW_BY_USB, BOOT_CMD_UPDATE_FW, -* or BOOT_CMD_UPDATE_BOOT2. -* @return 0 or error code +* @cardp: the if_usb_card descriptor +* @fwname: firmware or boot2 image file name +* @cmd: either BOOT_CMD_FW_BY_USB, BOOT_CMD_UPDATE_FW, +* or BOOT_CMD_UPDATE_BOOT2. +* returns: 0 or error code */ static int if_usb_prog_firmware(struct if_usb_card *cardp, const char *fwname, int cmd) diff --git a/drivers/net/wireless/libertas/if_usb.h b/drivers/net/wireless/libertas/if_usb.h index d819e7e..6e42eac 100644 --- a/drivers/net/wireless/libertas/if_usb.h +++ b/drivers/net/wireless/libertas/if_usb.h @@ -6,9 +6,9 @@ struct lbs_private; -/** - * This file contains definition for USB interface. - */ +/* + * This file contains definition for USB interface. + */ #define CMD_TYPE_REQUEST 0xF00DFACE #define CMD_TYPE_DATA 0xBEADC0DE #define CMD_TYPE_INDICATION 0xBEEFFACE @@ -40,7 +40,7 @@ struct bootcmdresp uint8_t pad[2]; }; -/** USB card description structure*/ +/* USB card description structure*/ struct if_usb_card { struct usb_device *udev; uint32_t model; /* MODEL_* */ @@ -77,7 +77,7 @@ struct if_usb_card { __le16 boot2_version; }; -/** fwheader */ +/* fwheader */ struct fwheader { __le32 dnldcmd; __le32 baseaddr; @@ -86,14 +86,14 @@ struct fwheader { }; #define FW_MAX_DATA_BLK_SIZE 600 -/** FWData */ +/* FWData */ struct fwdata { struct fwheader hdr; __le32 seqnum; uint8_t data[0]; }; -/** fwsyncheader */ +/* fwsyncheader */ struct fwsyncheader { __le32 cmd; __le32 seqnum; diff --git a/drivers/net/wireless/libertas/main.c b/drivers/net/wireless/libertas/main.c index ca8149c..ed57cf8 100644 --- a/drivers/net/wireless/libertas/main.c +++ b/drivers/net/wireless/libertas/main.c @@ -1,8 +1,8 @@ -/** - * This file contains the major functions in WLAN - * driver. It includes init, exit, open, close and main - * thread etc.. - */ +/* + * This file contains the major functions in WLAN + * driver. It includes init, exit, open, close and main + * thread etc.. + */ #include #include @@ -35,18 +35,20 @@ EXPORT_SYMBOL_GPL(lbs_debug); module_param_named(libertas_debug, lbs_debug, int, 0644); -/* This global structure is used to send the confirm_sleep command as - * fast as possible down to the firmware. */ +/* + * This global structure is used to send the confirm_sleep command as + * fast as possible down to the firmware. + */ struct cmd_confirm_sleep confirm_sleep; -/** +/* * the table to keep region code */ u16 lbs_region_code_to_index[MRVDRV_MAX_REGION_CODE] = { 0x10, 0x20, 0x30, 0x31, 0x32, 0x40 }; -/** +/* * FW rate table. FW refers to rates by their index in this table, not by the * rate value itself. Values of 0x00 are * reserved positions. @@ -57,10 +59,10 @@ static u8 fw_data_rates[MAX_RATES] = }; /** - * @brief use index to get the data rate + * lbs_fw_index_to_data_rate - use index to get the data rate * - * @param idx The index of data rate - * @return data rate or 0 + * @idx: The index of data rate + * returns: data rate or 0 */ u32 lbs_fw_index_to_data_rate(u8 idx) { @@ -70,10 +72,10 @@ u32 lbs_fw_index_to_data_rate(u8 idx) } /** - * @brief use rate to get the index + * lbs_data_rate_to_fw_index - use rate to get the index * - * @param rate data rate - * @return index or 0 + * @rate: data rate + * returns: index or 0 */ u8 lbs_data_rate_to_fw_index(u32 rate) { @@ -91,10 +93,10 @@ u8 lbs_data_rate_to_fw_index(u32 rate) /** - * @brief This function opens the ethX interface + * lbs_dev_open - open the ethX interface * - * @param dev A pointer to net_device structure - * @return 0 or -EBUSY if monitor mode active + * @dev: A pointer to &net_device structure + * returns: 0 or -EBUSY if monitor mode active */ static int lbs_dev_open(struct net_device *dev) { @@ -120,10 +122,10 @@ static int lbs_dev_open(struct net_device *dev) } /** - * @brief This function closes the ethX interface + * lbs_eth_stop - close the ethX interface * - * @param dev A pointer to net_device structure - * @return 0 + * @dev: A pointer to &net_device structure + * returns: 0 */ static int lbs_eth_stop(struct net_device *dev) { @@ -336,12 +338,12 @@ void lbs_set_multicast_list(struct net_device *dev) } /** - * @brief This function handles the major jobs in the LBS driver. + * lbs_thread - handles the major jobs in the LBS driver. * It handles all events generated by firmware, RX data received * from firmware and TX data sent from kernel. * - * @param data A pointer to lbs_thread structure - * @return 0 + * @data: A pointer to &lbs_thread structure + * returns: 0 */ static int lbs_thread(void *data) { @@ -540,11 +542,11 @@ static int lbs_thread(void *data) } /** - * @brief This function gets the HW spec from the firmware and sets - * some basic parameters. + * lbs_setup_firmware - gets the HW spec from the firmware and sets + * some basic parameters * - * @param priv A pointer to struct lbs_private structure - * @return 0 or -1 + * @priv: A pointer to &struct lbs_private structure + * returns: 0 or -1 */ static int lbs_setup_firmware(struct lbs_private *priv) { @@ -630,8 +632,10 @@ int lbs_resume(struct lbs_private *priv) EXPORT_SYMBOL_GPL(lbs_resume); /** - * This function handles the timeout of command sending. - * It will re-send the same command again. + * lbs_cmd_timeout_handler - handles the timeout of command sending. + * It will re-send the same command again. + * + * @data: &struct lbs_private pointer */ static void lbs_cmd_timeout_handler(unsigned long data) { @@ -655,8 +659,10 @@ out: } /** - * This function put the device back to deep sleep mode when timer expires - * and no activity (command, event, data etc.) is detected. + * auto_deepsleep_timer_fn - put the device back to deep sleep mode when + * timer expires and no activity (command, event, data etc.) is detected. + * @data: &struct lbs_private pointer + * returns: N/A */ static void auto_deepsleep_timer_fn(unsigned long data) { @@ -792,11 +798,12 @@ static const struct net_device_ops lbs_netdev_ops = { }; /** - * @brief This function adds the card. it will probe the + * lbs_add_card - adds the card. It will probe the * card, allocate the lbs_priv and initialize the device. * - * @param card A pointer to card - * @return A pointer to struct lbs_private structure + * @card: A pointer to card + * @dmdev: A pointer to &struct device + * returns: A pointer to &struct lbs_private structure */ struct lbs_private *lbs_add_card(void *card, struct device *dmdev) { @@ -1057,19 +1064,19 @@ void lbs_notify_command_response(struct lbs_private *priv, u8 resp_idx) EXPORT_SYMBOL_GPL(lbs_notify_command_response); /** - * @brief Retrieves two-stage firmware + * lbs_get_firmware - Retrieves two-stage firmware * - * @param dev A pointer to device structure - * @param user_helper User-defined helper firmware file - * @param user_mainfw User-defined main firmware file - * @param card_model Bus-specific card model ID used to filter firmware table - * elements - * @param fw_table Table of firmware file names and device model numbers - * terminated by an entry with a NULL helper name - * @param helper On success, the helper firmware; caller must free - * @param mainfw On success, the main firmware; caller must free + * @dev: A pointer to &device structure + * @user_helper: User-defined helper firmware file + * @user_mainfw: User-defined main firmware file + * @card_model: Bus-specific card model ID used to filter firmware table + * elements + * @fw_table: Table of firmware file names and device model numbers + * terminated by an entry with a NULL helper name + * @helper: On success, the helper firmware; caller must free + * @mainfw: On success, the main firmware; caller must free * - * @return 0 on success, non-zero on failure + * returns: 0 on success, non-zero on failure */ int lbs_get_firmware(struct device *dev, const char *user_helper, const char *user_mainfw, u32 card_model, diff --git a/drivers/net/wireless/libertas/mesh.c b/drivers/net/wireless/libertas/mesh.c index 9d097b9..a0804d1 100644 --- a/drivers/net/wireless/libertas/mesh.c +++ b/drivers/net/wireless/libertas/mesh.c @@ -16,12 +16,15 @@ * Mesh sysfs support */ -/** +/* * Attributes exported through sysfs */ /** - * @brief Get function for sysfs attribute anycast_mask + * lbs_anycast_get - Get function for sysfs attribute anycast_mask + * @dev: the &struct device + * @attr: device attributes + * @buf: buffer where data will be returned */ static ssize_t lbs_anycast_get(struct device *dev, struct device_attribute *attr, char * buf) @@ -40,7 +43,11 @@ static ssize_t lbs_anycast_get(struct device *dev, } /** - * @brief Set function for sysfs attribute anycast_mask + * lbs_anycast_set - Set function for sysfs attribute anycast_mask + * @dev: the &struct device + * @attr: device attributes + * @buf: buffer that contains new attribute value + * @count: size of buffer */ static ssize_t lbs_anycast_set(struct device *dev, struct device_attribute *attr, const char * buf, size_t count) @@ -62,7 +69,10 @@ static ssize_t lbs_anycast_set(struct device *dev, } /** - * @brief Get function for sysfs attribute prb_rsp_limit + * lbs_prb_rsp_limit_get - Get function for sysfs attribute prb_rsp_limit + * @dev: the &struct device + * @attr: device attributes + * @buf: buffer where data will be returned */ static ssize_t lbs_prb_rsp_limit_get(struct device *dev, struct device_attribute *attr, char *buf) @@ -85,7 +95,11 @@ static ssize_t lbs_prb_rsp_limit_get(struct device *dev, } /** - * @brief Set function for sysfs attribute prb_rsp_limit + * lbs_prb_rsp_limit_set - Set function for sysfs attribute prb_rsp_limit + * @dev: the &struct device + * @attr: device attributes + * @buf: buffer that contains new attribute value + * @count: size of buffer */ static ssize_t lbs_prb_rsp_limit_set(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) @@ -114,7 +128,10 @@ static ssize_t lbs_prb_rsp_limit_set(struct device *dev, } /** - * Get function for sysfs attribute mesh + * lbs_mesh_get - Get function for sysfs attribute mesh + * @dev: the &struct device + * @attr: device attributes + * @buf: buffer where data will be returned */ static ssize_t lbs_mesh_get(struct device *dev, struct device_attribute *attr, char * buf) @@ -124,7 +141,11 @@ static ssize_t lbs_mesh_get(struct device *dev, } /** - * Set function for sysfs attribute mesh + * lbs_mesh_set - Set function for sysfs attribute mesh + * @dev: the &struct device + * @attr: device attributes + * @buf: buffer that contains new attribute value + * @count: size of buffer */ static ssize_t lbs_mesh_set(struct device *dev, struct device_attribute *attr, const char * buf, size_t count) @@ -151,19 +172,19 @@ static ssize_t lbs_mesh_set(struct device *dev, return count; } -/** +/* * lbs_mesh attribute to be exported per ethX interface * through sysfs (/sys/class/net/ethX/lbs_mesh) */ static DEVICE_ATTR(lbs_mesh, 0644, lbs_mesh_get, lbs_mesh_set); -/** +/* * anycast_mask attribute to be exported per mshX interface * through sysfs (/sys/class/net/mshX/anycast_mask) */ static DEVICE_ATTR(anycast_mask, 0644, lbs_anycast_get, lbs_anycast_set); -/** +/* * prb_rsp_limit attribute to be exported per mshX interface * through sysfs (/sys/class/net/mshX/prb_rsp_limit) */ @@ -274,10 +295,10 @@ int lbs_deinit_mesh(struct lbs_private *priv) /** - * @brief This function closes the mshX interface + * lbs_mesh_stop - close the mshX interface * - * @param dev A pointer to net_device structure - * @return 0 + * @dev: A pointer to &net_device structure + * returns: 0 */ static int lbs_mesh_stop(struct net_device *dev) { @@ -301,10 +322,10 @@ static int lbs_mesh_stop(struct net_device *dev) } /** - * @brief This function opens the mshX interface + * lbs_mesh_dev_open - open the mshX interface * - * @param dev A pointer to net_device structure - * @return 0 or -EBUSY if monitor mode active + * @dev: A pointer to &net_device structure + * returns: 0 or -EBUSY if monitor mode active */ static int lbs_mesh_dev_open(struct net_device *dev) { @@ -342,10 +363,10 @@ static const struct net_device_ops mesh_netdev_ops = { }; /** - * @brief This function adds mshX interface + * lbs_add_mesh - add mshX interface * - * @param priv A pointer to the struct lbs_private structure - * @return 0 if successful, -X otherwise + * @priv: A pointer to the &struct lbs_private structure + * returns: 0 if successful, -X otherwise */ int lbs_add_mesh(struct lbs_private *priv) { @@ -456,13 +477,13 @@ void lbs_mesh_set_txpd(struct lbs_private *priv, */ /** - * @brief Add or delete Mesh Blinding Table entries + * lbs_mesh_bt_add_del - Add or delete Mesh Blinding Table entries * - * @param priv A pointer to struct lbs_private structure - * @param add TRUE to add the entry, FALSE to delete it - * @param addr1 Destination address to blind or unblind + * @priv: A pointer to &struct lbs_private structure + * @add: TRUE to add the entry, FALSE to delete it + * @addr1: Destination address to blind or unblind * - * @return 0 on success, error on failure + * returns: 0 on success, error on failure */ int lbs_mesh_bt_add_del(struct lbs_private *priv, bool add, u8 *addr1) { @@ -493,11 +514,11 @@ int lbs_mesh_bt_add_del(struct lbs_private *priv, bool add, u8 *addr1) } /** - * @brief Reset/clear the mesh blinding table + * lbs_mesh_bt_reset - Reset/clear the mesh blinding table * - * @param priv A pointer to struct lbs_private structure + * @priv: A pointer to &struct lbs_private structure * - * @return 0 on success, error on failure + * returns: 0 on success, error on failure */ int lbs_mesh_bt_reset(struct lbs_private *priv) { @@ -517,17 +538,18 @@ int lbs_mesh_bt_reset(struct lbs_private *priv) } /** - * @brief Gets the inverted status of the mesh blinding table + * lbs_mesh_bt_get_inverted - Gets the inverted status of the mesh + * blinding table * - * Normally the firmware "blinds" or ignores traffic from mesh nodes in the - * table, but an inverted table allows *only* traffic from nodes listed in - * the table. + * Normally the firmware "blinds" or ignores traffic from mesh nodes in the + * table, but an inverted table allows *only* traffic from nodes listed in + * the table. * - * @param priv A pointer to struct lbs_private structure - * @param invert On success, TRUE if the blinding table is inverted, - * FALSE if it is not inverted + * @priv: A pointer to &struct lbs_private structure + * @inverted: On success, TRUE if the blinding table is inverted, + * FALSE if it is not inverted * - * @return 0 on success, error on failure + * returns: 0 on success, error on failure */ int lbs_mesh_bt_get_inverted(struct lbs_private *priv, bool *inverted) { @@ -551,18 +573,19 @@ int lbs_mesh_bt_get_inverted(struct lbs_private *priv, bool *inverted) } /** - * @brief Sets the inverted status of the mesh blinding table + * lbs_mesh_bt_set_inverted - Sets the inverted status of the mesh + * blinding table * - * Normally the firmware "blinds" or ignores traffic from mesh nodes in the - * table, but an inverted table allows *only* traffic from nodes listed in - * the table. + * Normally the firmware "blinds" or ignores traffic from mesh nodes in the + * table, but an inverted table allows *only* traffic from nodes listed in + * the table. * - * @param priv A pointer to struct lbs_private structure - * @param invert TRUE to invert the blinding table (only traffic from - * listed nodes allowed), FALSE to return it - * to normal state (listed nodes ignored) + * @priv: A pointer to &struct lbs_private structure + * @inverted: TRUE to invert the blinding table (only traffic from + * listed nodes allowed), FALSE to return it + * to normal state (listed nodes ignored) * - * @return 0 on success, error on failure + * returns: 0 on success, error on failure */ int lbs_mesh_bt_set_inverted(struct lbs_private *priv, bool inverted) { @@ -583,13 +606,13 @@ int lbs_mesh_bt_set_inverted(struct lbs_private *priv, bool inverted) } /** - * @brief List an entry in the mesh blinding table + * lbs_mesh_bt_get_entry - List an entry in the mesh blinding table * - * @param priv A pointer to struct lbs_private structure - * @param id The ID of the entry to list - * @param addr1 MAC address associated with the table entry + * @priv: A pointer to &struct lbs_private structure + * @id: The ID of the entry to list + * @addr1: MAC address associated with the table entry * - * @return 0 on success, error on failure + * returns: 0 on success, error on failure */ int lbs_mesh_bt_get_entry(struct lbs_private *priv, u32 id, u8 *addr1) { @@ -614,14 +637,14 @@ int lbs_mesh_bt_get_entry(struct lbs_private *priv, u32 id, u8 *addr1) } /** - * @brief Access the mesh forwarding table + * lbs_cmd_fwt_access - Access the mesh forwarding table * - * @param priv A pointer to struct lbs_private structure - * @param cmd_action The forwarding table action to perform - * @param cmd The pre-filled FWT_ACCESS command + * @priv: A pointer to &struct lbs_private structure + * @cmd_action: The forwarding table action to perform + * @cmd: The pre-filled FWT_ACCESS command * - * @return 0 on success and 'cmd' will be filled with the - * firmware's response + * returns: 0 on success and 'cmd' will be filled with the + * firmware's response */ int lbs_cmd_fwt_access(struct lbs_private *priv, u16 cmd_action, struct cmd_ds_fwt_access *cmd) @@ -774,7 +797,10 @@ static int mesh_get_default_parameters(struct device *dev, } /** - * @brief Get function for sysfs attribute bootflag + * bootflag_get - Get function for sysfs attribute bootflag + * @dev: the &struct device + * @attr: device attributes + * @buf: buffer where data will be returned */ static ssize_t bootflag_get(struct device *dev, struct device_attribute *attr, char *buf) @@ -791,7 +817,11 @@ static ssize_t bootflag_get(struct device *dev, } /** - * @brief Set function for sysfs attribute bootflag + * bootflag_set - Set function for sysfs attribute bootflag + * @dev: the &struct device + * @attr: device attributes + * @buf: buffer that contains new attribute value + * @count: size of buffer */ static ssize_t bootflag_set(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) @@ -817,7 +847,10 @@ static ssize_t bootflag_set(struct device *dev, struct device_attribute *attr, } /** - * @brief Get function for sysfs attribute boottime + * boottime_get - Get function for sysfs attribute boottime + * @dev: the &struct device + * @attr: device attributes + * @buf: buffer where data will be returned */ static ssize_t boottime_get(struct device *dev, struct device_attribute *attr, char *buf) @@ -834,7 +867,11 @@ static ssize_t boottime_get(struct device *dev, } /** - * @brief Set function for sysfs attribute boottime + * boottime_set - Set function for sysfs attribute boottime + * @dev: the &struct device + * @attr: device attributes + * @buf: buffer that contains new attribute value + * @count: size of buffer */ static ssize_t boottime_set(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) @@ -869,7 +906,10 @@ static ssize_t boottime_set(struct device *dev, } /** - * @brief Get function for sysfs attribute channel + * channel_get - Get function for sysfs attribute channel + * @dev: the &struct device + * @attr: device attributes + * @buf: buffer where data will be returned */ static ssize_t channel_get(struct device *dev, struct device_attribute *attr, char *buf) @@ -886,7 +926,11 @@ static ssize_t channel_get(struct device *dev, } /** - * @brief Set function for sysfs attribute channel + * channel_set - Set function for sysfs attribute channel + * @dev: the &struct device + * @attr: device attributes + * @buf: buffer that contains new attribute value + * @count: size of buffer */ static ssize_t channel_set(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) @@ -912,7 +956,10 @@ static ssize_t channel_set(struct device *dev, struct device_attribute *attr, } /** - * @brief Get function for sysfs attribute mesh_id + * mesh_id_get - Get function for sysfs attribute mesh_id + * @dev: the &struct device + * @attr: device attributes + * @buf: buffer where data will be returned */ static ssize_t mesh_id_get(struct device *dev, struct device_attribute *attr, char *buf) @@ -938,7 +985,11 @@ static ssize_t mesh_id_get(struct device *dev, struct device_attribute *attr, } /** - * @brief Set function for sysfs attribute mesh_id + * mesh_id_set - Set function for sysfs attribute mesh_id + * @dev: the &struct device + * @attr: device attributes + * @buf: buffer that contains new attribute value + * @count: size of buffer */ static ssize_t mesh_id_set(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) @@ -980,7 +1031,10 @@ static ssize_t mesh_id_set(struct device *dev, struct device_attribute *attr, } /** - * @brief Get function for sysfs attribute protocol_id + * protocol_id_get - Get function for sysfs attribute protocol_id + * @dev: the &struct device + * @attr: device attributes + * @buf: buffer where data will be returned */ static ssize_t protocol_id_get(struct device *dev, struct device_attribute *attr, char *buf) @@ -997,7 +1051,11 @@ static ssize_t protocol_id_get(struct device *dev, } /** - * @brief Set function for sysfs attribute protocol_id + * protocol_id_set - Set function for sysfs attribute protocol_id + * @dev: the &struct device + * @attr: device attributes + * @buf: buffer that contains new attribute value + * @count: size of buffer */ static ssize_t protocol_id_set(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) @@ -1034,7 +1092,10 @@ static ssize_t protocol_id_set(struct device *dev, } /** - * @brief Get function for sysfs attribute metric_id + * metric_id_get - Get function for sysfs attribute metric_id + * @dev: the &struct device + * @attr: device attributes + * @buf: buffer where data will be returned */ static ssize_t metric_id_get(struct device *dev, struct device_attribute *attr, char *buf) @@ -1051,7 +1112,11 @@ static ssize_t metric_id_get(struct device *dev, } /** - * @brief Set function for sysfs attribute metric_id + * metric_id_set - Set function for sysfs attribute metric_id + * @dev: the &struct device + * @attr: device attributes + * @buf: buffer that contains new attribute value + * @count: size of buffer */ static ssize_t metric_id_set(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) @@ -1088,7 +1153,10 @@ static ssize_t metric_id_set(struct device *dev, struct device_attribute *attr, } /** - * @brief Get function for sysfs attribute capability + * capability_get - Get function for sysfs attribute capability + * @dev: the &struct device + * @attr: device attributes + * @buf: buffer where data will be returned */ static ssize_t capability_get(struct device *dev, struct device_attribute *attr, char *buf) @@ -1105,7 +1173,11 @@ static ssize_t capability_get(struct device *dev, } /** - * @brief Set function for sysfs attribute capability + * capability_set - Set function for sysfs attribute capability + * @dev: the &struct device + * @attr: device attributes + * @buf: buffer that contains new attribute value + * @count: size of buffer */ static ssize_t capability_set(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) diff --git a/drivers/net/wireless/libertas/mesh.h b/drivers/net/wireless/libertas/mesh.h index afb2e8d..ee95c73 100644 --- a/drivers/net/wireless/libertas/mesh.h +++ b/drivers/net/wireless/libertas/mesh.h @@ -1,6 +1,6 @@ -/** - * Contains all definitions needed for the Libertas' MESH implementation. - */ +/* + * Contains all definitions needed for the Libertas' MESH implementation. + */ #ifndef _LBS_MESH_H_ #define _LBS_MESH_H_ diff --git a/drivers/net/wireless/libertas/rx.c b/drivers/net/wireless/libertas/rx.c index a2b1df2..a3f4b55 100644 --- a/drivers/net/wireless/libertas/rx.c +++ b/drivers/net/wireless/libertas/rx.c @@ -1,6 +1,6 @@ -/** - * This file contains the handling of RX in wlan driver. - */ +/* + * This file contains the handling of RX in wlan driver. + */ #include #include #include @@ -40,12 +40,12 @@ static int process_rxed_802_11_packet(struct lbs_private *priv, struct sk_buff *skb); /** - * @brief This function processes received packet and forwards it - * to kernel/upper layer + * lbs_process_rxed_packet - processes received packet and forwards it + * to kernel/upper layer * - * @param priv A pointer to struct lbs_private - * @param skb A pointer to skb which includes the received packet - * @return 0 or -1 + * @priv: A pointer to &struct lbs_private + * @skb: A pointer to skb which includes the received packet + * returns: 0 or -1 */ int lbs_process_rxed_packet(struct lbs_private *priv, struct sk_buff *skb) { @@ -156,11 +156,11 @@ done: EXPORT_SYMBOL_GPL(lbs_process_rxed_packet); /** - * @brief This function converts Tx/Rx rates from the Marvell WLAN format - * (see Table 2 in Section 3.1) to IEEE80211_RADIOTAP_RATE units (500 Kb/s) + * convert_mv_rate_to_radiotap - converts Tx/Rx rates from Marvell WLAN format + * (see Table 2 in Section 3.1) to IEEE80211_RADIOTAP_RATE units (500 Kb/s) * - * @param rate Input rate - * @return Output Rate (0 if invalid) + * @rate: Input rate + * returns: Output Rate (0 if invalid) */ static u8 convert_mv_rate_to_radiotap(u8 rate) { @@ -196,12 +196,12 @@ static u8 convert_mv_rate_to_radiotap(u8 rate) } /** - * @brief This function processes a received 802.11 packet and forwards it - * to kernel/upper layer + * process_rxed_802_11_packet - processes a received 802.11 packet and forwards + * it to kernel/upper layer * - * @param priv A pointer to struct lbs_private - * @param skb A pointer to skb which includes the received packet - * @return 0 or -1 + * @priv: A pointer to &struct lbs_private + * @skb: A pointer to skb which includes the received packet + * returns: 0 or -1 */ static int process_rxed_802_11_packet(struct lbs_private *priv, struct sk_buff *skb) diff --git a/drivers/net/wireless/libertas/tx.c b/drivers/net/wireless/libertas/tx.c index 8000ca6..bbb95f8 100644 --- a/drivers/net/wireless/libertas/tx.c +++ b/drivers/net/wireless/libertas/tx.c @@ -1,6 +1,6 @@ -/** - * This file contains the handling of TX in wlan driver. - */ +/* + * This file contains the handling of TX in wlan driver. + */ #include #include #include @@ -13,11 +13,11 @@ #include "dev.h" /** - * @brief This function converts Tx/Rx rates from IEEE80211_RADIOTAP_RATE - * units (500 Kb/s) into Marvell WLAN format (see Table 8 in Section 3.2.1) + * convert_radiotap_rate_to_mv - converts Tx/Rx rates from IEEE80211_RADIOTAP_RATE + * units (500 Kb/s) into Marvell WLAN format (see Table 8 in Section 3.2.1) * - * @param rate Input rate - * @return Output Rate (0 if invalid) + * @rate: Input rate + * returns: Output Rate (0 if invalid) */ static u32 convert_radiotap_rate_to_mv(u8 rate) { @@ -51,12 +51,12 @@ static u32 convert_radiotap_rate_to_mv(u8 rate) } /** - * @brief This function checks the conditions and sends packet to IF - * layer if everything is ok. + * lbs_hard_start_xmit - checks the conditions and sends packet to IF + * layer if everything is ok * - * @param priv A pointer to struct lbs_private structure - * @param skb A pointer to skb which includes TX packet - * @return 0 or -1 + * @skb: A pointer to skb which includes TX packet + * @dev: A pointer to the &struct net_device + * returns: 0 or -1 */ netdev_tx_t lbs_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) { @@ -168,13 +168,13 @@ netdev_tx_t lbs_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) } /** - * @brief This function sends to the host the last transmitted packet, - * filling the radiotap headers with transmission information. + * lbs_send_tx_feedback - sends to the host the last transmitted packet, + * filling the radiotap headers with transmission information. * - * @param priv A pointer to struct lbs_private structure - * @param status A 32 bit value containing transmission status. + * @priv: A pointer to &struct lbs_private structure + * @try_count: A 32-bit value containing transmission retry status. * - * @returns void + * returns: void */ void lbs_send_tx_feedback(struct lbs_private *priv, u32 try_count) { diff --git a/drivers/net/wireless/libertas/types.h b/drivers/net/wireless/libertas/types.h index 462fbb4..cf1d9b0 100644 --- a/drivers/net/wireless/libertas/types.h +++ b/drivers/net/wireless/libertas/types.h @@ -1,6 +1,6 @@ -/** - * This header file contains definition for global types - */ +/* + * This header file contains definition for global types + */ #ifndef _LBS_TYPES_H_ #define _LBS_TYPES_H_ @@ -54,7 +54,7 @@ union ieee_phy_param_set { struct ieee_ie_ds_param_set ds; } __packed; -/** TLV type ID definition */ +/* TLV type ID definition */ #define PROPRIETARY_TLV_BASE_ID 0x0100 /* Terminating TLV type */ @@ -96,7 +96,7 @@ union ieee_phy_param_set { #define TLV_TYPE_MESH_ID (PROPRIETARY_TLV_BASE_ID + 37) #define TLV_TYPE_OLD_MESH_ID (PROPRIETARY_TLV_BASE_ID + 291) -/** TLV related data structures*/ +/* TLV related data structures */ struct mrvl_ie_header { __le16 type; __le16 len; @@ -177,7 +177,7 @@ struct mrvl_ie_auth_type { __le16 auth; } __packed; -/** Local Power capability */ +/* Local Power capability */ struct mrvl_ie_power_capability { struct mrvl_ie_header header; s8 minpower; @@ -235,9 +235,11 @@ struct mrvl_ie_ledbhv { struct led_bhv ledbhv[1]; } __packed; -/* Meant to be packed as the value member of a struct ieee80211_info_element. +/* + * Meant to be packed as the value member of a struct ieee80211_info_element. * Note that the len member of the ieee80211_info_element varies depending on - * the mesh_id_len */ + * the mesh_id_len + */ struct mrvl_meshie_val { uint8_t oui[3]; uint8_t type; -- cgit v0.10.2 From bdbfd6b582f55384059d9ac5e65b3653092e6adf Mon Sep 17 00:00:00 2001 From: Sujith Manoharan Date: Wed, 27 Apr 2011 16:56:51 +0530 Subject: mac80211: Add new API for rate selection This patch adds a new API for setting a TX rate mask in drivers that have rate control in either the firmware or hardware. This can be used for various purposes, for example, masking out the 11b rates in P2P operation. Signed-off-by: Sujith Manoharan Signed-off-by: John W. Linville diff --git a/include/net/mac80211.h b/include/net/mac80211.h index 8aad6b3..63f75a0 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -1822,6 +1822,10 @@ enum ieee80211_ampdu_mlme_action { * * @tx_frames_pending: Check if there is any pending frame in the hardware * queues before entering power save. + * + * @set_bitrate_mask: Set a mask of rates to be used for rate control selection + * when transmitting a frame. Currently only legacy rates are handled. + * The callback can sleep. */ struct ieee80211_ops { void (*tx)(struct ieee80211_hw *hw, struct sk_buff *skb); @@ -1910,6 +1914,8 @@ struct ieee80211_ops { void (*get_ringparam)(struct ieee80211_hw *hw, u32 *tx, u32 *tx_max, u32 *rx, u32 *rx_max); bool (*tx_frames_pending)(struct ieee80211_hw *hw); + int (*set_bitrate_mask)(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + const struct cfg80211_bitrate_mask *mask); }; /** diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index a9ddaf6..12d52ce 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -1633,16 +1633,13 @@ static int ieee80211_set_bitrate_mask(struct wiphy *wiphy, { struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); - int i; - - /* - * This _could_ be supported by providing a hook for - * drivers for this function, but at this point it - * doesn't seem worth bothering. - */ - if (local->hw.flags & IEEE80211_HW_HAS_RATE_CONTROL) - return -EOPNOTSUPP; + int i, ret; + if (local->hw.flags & IEEE80211_HW_HAS_RATE_CONTROL) { + ret = drv_set_bitrate_mask(local, sdata, mask); + if (ret) + return ret; + } for (i = 0; i < IEEE80211_NUM_BANDS; i++) sdata->rc_rateidx_mask[i] = mask->control[i].legacy; diff --git a/net/mac80211/driver-ops.h b/net/mac80211/driver-ops.h index 00a0685..2ddb56e 100644 --- a/net/mac80211/driver-ops.h +++ b/net/mac80211/driver-ops.h @@ -565,4 +565,22 @@ static inline bool drv_tx_frames_pending(struct ieee80211_local *local) return ret; } + +static inline int drv_set_bitrate_mask(struct ieee80211_local *local, + struct ieee80211_sub_if_data *sdata, + const struct cfg80211_bitrate_mask *mask) +{ + int ret = -EOPNOTSUPP; + + might_sleep(); + + trace_drv_set_bitrate_mask(local, sdata, mask); + if (local->ops->set_bitrate_mask) + ret = local->ops->set_bitrate_mask(&local->hw, + &sdata->vif, mask); + trace_drv_return_int(local, ret); + + return ret; +} + #endif /* __MAC80211_DRIVER_OPS */ diff --git a/net/mac80211/driver-trace.h b/net/mac80211/driver-trace.h index c8c934d..191e834 100644 --- a/net/mac80211/driver-trace.h +++ b/net/mac80211/driver-trace.h @@ -989,6 +989,33 @@ DEFINE_EVENT(local_only_evt, drv_offchannel_tx_cancel_wait, TP_ARGS(local) ); +TRACE_EVENT(drv_set_bitrate_mask, + TP_PROTO(struct ieee80211_local *local, + struct ieee80211_sub_if_data *sdata, + const struct cfg80211_bitrate_mask *mask), + + TP_ARGS(local, sdata, mask), + + TP_STRUCT__entry( + LOCAL_ENTRY + VIF_ENTRY + __field(u32, legacy_2g) + __field(u32, legacy_5g) + ), + + TP_fast_assign( + LOCAL_ASSIGN; + VIF_ASSIGN; + __entry->legacy_2g = mask->control[IEEE80211_BAND_2GHZ].legacy; + __entry->legacy_5g = mask->control[IEEE80211_BAND_5GHZ].legacy; + ), + + TP_printk( + LOCAL_PR_FMT VIF_PR_FMT " 2G Mask:0x%x 5G Mask:0x%x", + LOCAL_PR_ARG, VIF_PR_ARG, __entry->legacy_2g, __entry->legacy_5g + ) +); + /* * Tracing for API calls that drivers call. */ -- cgit v0.10.2 From 484b1829c6a3c5bc38fe0cd626ce2e8a3dfd844c Mon Sep 17 00:00:00 2001 From: Sujith Manoharan Date: Wed, 27 Apr 2011 17:12:56 +0530 Subject: ath9k_htc: Increase credit size for AR7010 devices Bump the firmware version to 1.2 Signed-off-by: Sujith Manoharan Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/hif_usb.h b/drivers/net/wireless/ath/ath9k/hif_usb.h index 9a52ccc..2bdcdbc 100644 --- a/drivers/net/wireless/ath/ath9k/hif_usb.h +++ b/drivers/net/wireless/ath/ath9k/hif_usb.h @@ -18,7 +18,7 @@ #define HTC_USB_H #define MAJOR_VERSION_REQ 1 -#define MINOR_VERSION_REQ 1 +#define MINOR_VERSION_REQ 2 #define IS_AR7010_DEVICE(_v) (((_v) == AR9280_USB) || ((_v) == AR9287_USB)) diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_init.c b/drivers/net/wireless/ath/ath9k/htc_drv_init.c index dbf5f95..d2dd5a6 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_init.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_init.c @@ -243,7 +243,7 @@ static int ath9k_init_htc_services(struct ath9k_htc_priv *priv, u16 devid, */ if (IS_AR7010_DEVICE(drv_info)) - priv->htc->credits = 45; + priv->htc->credits = 48; else priv->htc->credits = 33; -- cgit v0.10.2 From 155dcda6f11a58e4e1443d5fad530b0bf68370b7 Mon Sep 17 00:00:00 2001 From: Sujith Manoharan Date: Wed, 27 Apr 2011 17:13:09 +0530 Subject: ath9k_htc: Remove unused WMI_AGGR_LIMIT_CMD Signed-off-by: Sujith Manoharan Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/wmi.c b/drivers/net/wireless/ath/ath9k/wmi.c index 8f095ad..463b76ab 100644 --- a/drivers/net/wireless/ath/ath9k/wmi.c +++ b/drivers/net/wireless/ath/ath9k/wmi.c @@ -79,8 +79,6 @@ static const char *wmi_cmd_to_name(enum wmi_cmd_id wmi_cmd) return "WMI_TX_STATS_CMDID"; case WMI_RX_STATS_CMDID: return "WMI_RX_STATS_CMDID"; - case WMI_AGGR_LIMIT_CMD: - return "WMI_AGGR_LIMIT_CMD"; } return "Bogus"; diff --git a/drivers/net/wireless/ath/ath9k/wmi.h b/drivers/net/wireless/ath/ath9k/wmi.h index 02ecb9f..5dfc213 100644 --- a/drivers/net/wireless/ath/ath9k/wmi.h +++ b/drivers/net/wireless/ath/ath9k/wmi.h @@ -111,7 +111,6 @@ enum wmi_cmd_id { WMI_INT_STATS_CMDID, WMI_TX_STATS_CMDID, WMI_RX_STATS_CMDID, - WMI_AGGR_LIMIT_CMD = 0x0026, }; enum wmi_event_id { -- cgit v0.10.2 From a55bb94aa37782fe9457751a3e508b1129fbbc7a Mon Sep 17 00:00:00 2001 From: Sujith Manoharan Date: Wed, 27 Apr 2011 17:13:23 +0530 Subject: ath9k_htc: Add a new WMI command to set a rate mask This patch adds WMI_BITRATE_MASK_CMDID which can be used by the set_bitrate_mask() handler. Signed-off-by: Sujith Manoharan Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/htc.h b/drivers/net/wireless/ath/ath9k/htc.h index 55f4bb3..6bb71e3 100644 --- a/drivers/net/wireless/ath/ath9k/htc.h +++ b/drivers/net/wireless/ath/ath9k/htc.h @@ -171,6 +171,13 @@ struct ath9k_htc_target_rate { struct ath9k_htc_rate rates; }; +struct ath9k_htc_target_rate_mask { + u8 vif_index; + u8 band; + __be32 mask; + u16 pad; +} __packed; + struct ath9k_htc_target_int_stats { __be32 rx; __be32 rxorn; diff --git a/drivers/net/wireless/ath/ath9k/wmi.c b/drivers/net/wireless/ath/ath9k/wmi.c index 463b76ab..f9b1eb4 100644 --- a/drivers/net/wireless/ath/ath9k/wmi.c +++ b/drivers/net/wireless/ath/ath9k/wmi.c @@ -79,6 +79,8 @@ static const char *wmi_cmd_to_name(enum wmi_cmd_id wmi_cmd) return "WMI_TX_STATS_CMDID"; case WMI_RX_STATS_CMDID: return "WMI_RX_STATS_CMDID"; + case WMI_BITRATE_MASK_CMDID: + return "WMI_BITRATE_MASK_CMDID"; } return "Bogus"; diff --git a/drivers/net/wireless/ath/ath9k/wmi.h b/drivers/net/wireless/ath/ath9k/wmi.h index 5dfc213..6095eeb 100644 --- a/drivers/net/wireless/ath/ath9k/wmi.h +++ b/drivers/net/wireless/ath/ath9k/wmi.h @@ -111,6 +111,7 @@ enum wmi_cmd_id { WMI_INT_STATS_CMDID, WMI_TX_STATS_CMDID, WMI_RX_STATS_CMDID, + WMI_BITRATE_MASK_CMDID, }; enum wmi_event_id { -- cgit v0.10.2 From e2186b7c25ef9cdb6d631c8dd6a672f41abe22d5 Mon Sep 17 00:00:00 2001 From: Sujith Manoharan Date: Wed, 27 Apr 2011 17:13:40 +0530 Subject: ath9k_htc: Add set_bitrate_mask() callback This callback is used to set the minimum rate for management frames. Signed-off-by: Sujith Manoharan Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_main.c b/drivers/net/wireless/ath/ath9k/htc_drv_main.c index c8577d5..e9746e8 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_main.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_main.c @@ -1659,6 +1659,55 @@ static void ath9k_htc_set_coverage_class(struct ieee80211_hw *hw, mutex_unlock(&priv->mutex); } +/* + * Currently, this is used only for selecting the minimum rate + * for management frames, rate selection for data frames remain + * unaffected. + */ +static int ath9k_htc_set_bitrate_mask(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + const struct cfg80211_bitrate_mask *mask) +{ + struct ath9k_htc_priv *priv = hw->priv; + struct ath_common *common = ath9k_hw_common(priv->ah); + struct ath9k_htc_target_rate_mask tmask; + struct ath9k_htc_vif *avp = (void *)vif->drv_priv; + int ret = 0; + u8 cmd_rsp; + + memset(&tmask, 0, sizeof(struct ath9k_htc_target_rate_mask)); + + tmask.vif_index = avp->index; + tmask.band = IEEE80211_BAND_2GHZ; + tmask.mask = cpu_to_be32(mask->control[IEEE80211_BAND_2GHZ].legacy); + + WMI_CMD_BUF(WMI_BITRATE_MASK_CMDID, &tmask); + if (ret) { + ath_err(common, + "Unable to set 2G rate mask for " + "interface at idx: %d\n", avp->index); + goto out; + } + + tmask.band = IEEE80211_BAND_5GHZ; + tmask.mask = cpu_to_be32(mask->control[IEEE80211_BAND_5GHZ].legacy); + + WMI_CMD_BUF(WMI_BITRATE_MASK_CMDID, &tmask); + if (ret) { + ath_err(common, + "Unable to set 5G rate mask for " + "interface at idx: %d\n", avp->index); + goto out; + } + + ath_dbg(common, ATH_DBG_CONFIG, + "Set bitrate masks: 0x%x, 0x%x\n", + mask->control[IEEE80211_BAND_2GHZ].legacy, + mask->control[IEEE80211_BAND_5GHZ].legacy); +out: + return ret; +} + struct ieee80211_ops ath9k_htc_ops = { .tx = ath9k_htc_tx, .start = ath9k_htc_start, @@ -1681,4 +1730,5 @@ struct ieee80211_ops ath9k_htc_ops = { .set_rts_threshold = ath9k_htc_set_rts_threshold, .rfkill_poll = ath9k_htc_rfkill_poll_state, .set_coverage_class = ath9k_htc_set_coverage_class, + .set_bitrate_mask = ath9k_htc_set_bitrate_mask, }; -- cgit v0.10.2 From aac6af5534fade2b18682a0b9efad1a6c04c34c6 Mon Sep 17 00:00:00 2001 From: Yogesh Ashok Powar Date: Wed, 27 Apr 2011 18:40:29 +0530 Subject: mac80211: Skip tailroom reservation for full HW-crypto devices In xmit path, devices that do full hardware crypto (including TKIP MMIC) need no tailroom. For such devices, tailroom reservation can be skipped if all the keys are programmed into the hardware (i.e software crypto is not used for any of the keys) and none of the keys wants software to generate Michael MIC. Signed-off-by: Yogesh Ashok Powar Signed-off-by: John W. Linville diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 8d6d6e3..9e3b4f0 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -766,6 +766,9 @@ struct ieee80211_local { int tx_headroom; /* required headroom for hardware/radiotap */ + /* count for keys needing tailroom space allocation */ + int crypto_tx_tailroom_needed_cnt; + /* Tasklet and skb queue to process calls from IRQ mode. All frames * added to skb_queue will be processed, but frames in * skb_queue_unreliable may be dropped if the total length of these diff --git a/net/mac80211/key.c b/net/mac80211/key.c index af3c564..ca3c626 100644 --- a/net/mac80211/key.c +++ b/net/mac80211/key.c @@ -101,6 +101,10 @@ static int ieee80211_key_enable_hw_accel(struct ieee80211_key *key) if (!ret) { key->flags |= KEY_FLAG_UPLOADED_TO_HARDWARE; + + if (!(key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_MMIC)) + key->local->crypto_tx_tailroom_needed_cnt--; + return 0; } @@ -156,6 +160,9 @@ static void ieee80211_key_disable_hw_accel(struct ieee80211_key *key) key->conf.keyidx, sta ? sta->addr : bcast_addr, ret); key->flags &= ~KEY_FLAG_UPLOADED_TO_HARDWARE; + + if (!(key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_MMIC)) + key->local->crypto_tx_tailroom_needed_cnt++; } void ieee80211_key_removed(struct ieee80211_key_conf *key_conf) @@ -388,8 +395,10 @@ static void __ieee80211_key_destroy(struct ieee80211_key *key) ieee80211_aes_key_free(key->u.ccmp.tfm); if (key->conf.cipher == WLAN_CIPHER_SUITE_AES_CMAC) ieee80211_aes_cmac_key_free(key->u.aes_cmac.tfm); - if (key->local) + if (key->local) { ieee80211_debugfs_key_remove(key); + key->local->crypto_tx_tailroom_needed_cnt--; + } kfree(key); } @@ -451,6 +460,8 @@ int ieee80211_key_link(struct ieee80211_key *key, ieee80211_debugfs_key_add(key); + key->local->crypto_tx_tailroom_needed_cnt++; + ret = ieee80211_key_enable_hw_accel(key); mutex_unlock(&sdata->local->key_mtx); @@ -492,8 +503,12 @@ void ieee80211_enable_keys(struct ieee80211_sub_if_data *sdata) mutex_lock(&sdata->local->key_mtx); - list_for_each_entry(key, &sdata->key_list, list) + sdata->local->crypto_tx_tailroom_needed_cnt = 0; + + list_for_each_entry(key, &sdata->key_list, list) { + sdata->local->crypto_tx_tailroom_needed_cnt++; ieee80211_key_enable_hw_accel(key); + } mutex_unlock(&sdata->local->key_mtx); } diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index a2043e4..e3e3aa1 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -1476,12 +1476,7 @@ static int ieee80211_skb_resize(struct ieee80211_local *local, { int tail_need = 0; - /* - * This could be optimised, devices that do full hardware - * crypto (including TKIP MMIC) need no tailroom... But we - * have no drivers for such devices currently. - */ - if (may_encrypt) { + if (may_encrypt && local->crypto_tx_tailroom_needed_cnt) { tail_need = IEEE80211_ENCRYPT_TAILROOM; tail_need -= skb_tailroom(skb); tail_need = max_t(int, tail_need, 0); -- cgit v0.10.2 From 6e914101d47c76e09b0568d094ef44257dd3d6e9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= Date: Wed, 27 Apr 2011 17:39:47 +0200 Subject: ssb: pci: separate workarounds 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 diff --git a/drivers/ssb/driver_pcicore.c b/drivers/ssb/driver_pcicore.c index dbda168..adde4f0 100644 --- a/drivers/ssb/driver_pcicore.c +++ b/drivers/ssb/driver_pcicore.c @@ -21,6 +21,8 @@ static u16 ssb_pcie_mdio_read(struct ssb_pcicore *pc, u8 device, u8 address); static void ssb_pcie_mdio_write(struct ssb_pcicore *pc, u8 device, u8 address, u16 data); +static void ssb_commit_settings(struct ssb_bus *bus); + static inline u32 pcicore_read32(struct ssb_pcicore *pc, u16 offset) { @@ -430,6 +432,60 @@ static void ssb_pcicore_serdes_workaround(struct ssb_pcicore *pc) ssb_pcie_mdio_write(pc, serdes_pll_device, 1, tmp & ~0x4000); } +static void ssb_pcicore_pci_setup_workarounds(struct ssb_pcicore *pc) +{ + struct ssb_device *pdev = pc->dev; + struct ssb_bus *bus = pdev->bus; + u32 tmp; + + tmp = pcicore_read32(pc, SSB_PCICORE_SBTOPCI2); + tmp |= SSB_PCICORE_SBTOPCI_PREF; + tmp |= SSB_PCICORE_SBTOPCI_BURST; + pcicore_write32(pc, SSB_PCICORE_SBTOPCI2, tmp); + + if (pdev->id.revision < 5) { + tmp = ssb_read32(pdev, SSB_IMCFGLO); + tmp &= ~SSB_IMCFGLO_SERTO; + tmp |= 2; + tmp &= ~SSB_IMCFGLO_REQTO; + tmp |= 3 << SSB_IMCFGLO_REQTO_SHIFT; + ssb_write32(pdev, SSB_IMCFGLO, tmp); + ssb_commit_settings(bus); + } else if (pdev->id.revision >= 11) { + tmp = pcicore_read32(pc, SSB_PCICORE_SBTOPCI2); + tmp |= SSB_PCICORE_SBTOPCI_MRM; + pcicore_write32(pc, SSB_PCICORE_SBTOPCI2, tmp); + } +} + +static void ssb_pcicore_pcie_setup_workarounds(struct ssb_pcicore *pc) +{ + struct ssb_device *pdev = pc->dev; + u32 tmp; + + if ((pdev->id.revision == 0) || (pdev->id.revision == 1)) { + /* TLP Workaround register. */ + tmp = ssb_pcie_read(pc, 0x4); + tmp |= 0x8; + ssb_pcie_write(pc, 0x4, tmp); + } + if (pdev->id.revision == 0) { + const u8 serdes_rx_device = 0x1F; + + ssb_pcie_mdio_write(pc, serdes_rx_device, + 2 /* Timer */, 0x8128); + ssb_pcie_mdio_write(pc, serdes_rx_device, + 6 /* CDR */, 0x0100); + ssb_pcie_mdio_write(pc, serdes_rx_device, + 7 /* CDR BW */, 0x1466); + } else if (pdev->id.revision == 1) { + /* DLLP Link Control register. */ + tmp = ssb_pcie_read(pc, 0x100); + tmp |= 0x40; + ssb_pcie_write(pc, 0x100, tmp); + } +} + /************************************************** * Generic and Clientmode operation code. **************************************************/ @@ -646,48 +702,10 @@ int ssb_pcicore_dev_irqvecs_enable(struct ssb_pcicore *pc, if (pc->setup_done) goto out; if (pdev->id.coreid == SSB_DEV_PCI) { - tmp = pcicore_read32(pc, SSB_PCICORE_SBTOPCI2); - tmp |= SSB_PCICORE_SBTOPCI_PREF; - tmp |= SSB_PCICORE_SBTOPCI_BURST; - pcicore_write32(pc, SSB_PCICORE_SBTOPCI2, tmp); - - if (pdev->id.revision < 5) { - tmp = ssb_read32(pdev, SSB_IMCFGLO); - tmp &= ~SSB_IMCFGLO_SERTO; - tmp |= 2; - tmp &= ~SSB_IMCFGLO_REQTO; - tmp |= 3 << SSB_IMCFGLO_REQTO_SHIFT; - ssb_write32(pdev, SSB_IMCFGLO, tmp); - ssb_commit_settings(bus); - } else if (pdev->id.revision >= 11) { - tmp = pcicore_read32(pc, SSB_PCICORE_SBTOPCI2); - tmp |= SSB_PCICORE_SBTOPCI_MRM; - pcicore_write32(pc, SSB_PCICORE_SBTOPCI2, tmp); - } + ssb_pcicore_pci_setup_workarounds(pc); } else { WARN_ON(pdev->id.coreid != SSB_DEV_PCIE); - //TODO: Better make defines for all these magic PCIE values. - if ((pdev->id.revision == 0) || (pdev->id.revision == 1)) { - /* TLP Workaround register. */ - tmp = ssb_pcie_read(pc, 0x4); - tmp |= 0x8; - ssb_pcie_write(pc, 0x4, tmp); - } - if (pdev->id.revision == 0) { - const u8 serdes_rx_device = 0x1F; - - ssb_pcie_mdio_write(pc, serdes_rx_device, - 2 /* Timer */, 0x8128); - ssb_pcie_mdio_write(pc, serdes_rx_device, - 6 /* CDR */, 0x0100); - ssb_pcie_mdio_write(pc, serdes_rx_device, - 7 /* CDR BW */, 0x1466); - } else if (pdev->id.revision == 1) { - /* DLLP Link Control register. */ - tmp = ssb_pcie_read(pc, 0x100); - tmp |= 0x40; - ssb_pcie_write(pc, 0x100, tmp); - } + ssb_pcicore_pcie_setup_workarounds(pc); } pc->setup_done = 1; out: -- cgit v0.10.2 From 5890a3ca34aae94dd736557ad8cb898ac2802aa0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= Date: Wed, 27 Apr 2011 17:39:48 +0200 Subject: ssb: pci: update PCIe workarounds 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 diff --git a/drivers/ssb/driver_pcicore.c b/drivers/ssb/driver_pcicore.c index adde4f0..32a9b61 100644 --- a/drivers/ssb/driver_pcicore.c +++ b/drivers/ssb/driver_pcicore.c @@ -460,16 +460,23 @@ static void ssb_pcicore_pci_setup_workarounds(struct ssb_pcicore *pc) static void ssb_pcicore_pcie_setup_workarounds(struct ssb_pcicore *pc) { - struct ssb_device *pdev = pc->dev; u32 tmp; + u8 rev = pc->dev->id.revision; - if ((pdev->id.revision == 0) || (pdev->id.revision == 1)) { + if (rev == 0 || rev == 1) { /* TLP Workaround register. */ tmp = ssb_pcie_read(pc, 0x4); tmp |= 0x8; ssb_pcie_write(pc, 0x4, tmp); } - if (pdev->id.revision == 0) { + if (rev == 1) { + /* DLLP Link Control register. */ + tmp = ssb_pcie_read(pc, 0x100); + tmp |= 0x40; + ssb_pcie_write(pc, 0x100, tmp); + } + + if (rev == 0) { const u8 serdes_rx_device = 0x1F; ssb_pcie_mdio_write(pc, serdes_rx_device, @@ -478,11 +485,20 @@ static void ssb_pcicore_pcie_setup_workarounds(struct ssb_pcicore *pc) 6 /* CDR */, 0x0100); ssb_pcie_mdio_write(pc, serdes_rx_device, 7 /* CDR BW */, 0x1466); - } else if (pdev->id.revision == 1) { - /* DLLP Link Control register. */ - tmp = ssb_pcie_read(pc, 0x100); - tmp |= 0x40; - ssb_pcie_write(pc, 0x100, tmp); + } else if (rev == 3 || rev == 4 || rev == 5) { + /* TODO: DLLP Power Management Threshold */ + ssb_pcicore_serdes_workaround(pc); + /* TODO: ASPM */ + } else if (rev == 7) { + /* TODO: No PLL down */ + } + + if (rev >= 6) { + /* Miscellaneous Configuration Fixup */ + tmp = pcicore_read16(pc, SSB_PCICORE_SPROM(5)); + if (!(tmp & 0x8000)) + pcicore_write16(pc, SSB_PCICORE_SPROM(5), + tmp | 0x8000); } } @@ -513,7 +529,10 @@ void ssb_pcicore_init(struct ssb_pcicore *pc) if (!pc->hostmode) ssb_pcicore_init_clientmode(pc); + /* Additional always once-executed workarounds */ ssb_pcicore_serdes_workaround(pc); + /* TODO: ASPM */ + /* TODO: Clock Request Update */ } static u32 ssb_pcie_read(struct ssb_pcicore *pc, u32 address) -- cgit v0.10.2 From af335a6cbc3dfcba64ad31561c0da563d1c43a2d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= Date: Wed, 27 Apr 2011 18:21:34 +0200 Subject: ssb: pci: early fix for SPROM core index 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 diff --git a/drivers/ssb/driver_pcicore.c b/drivers/ssb/driver_pcicore.c index 32a9b61..8fde122 100644 --- a/drivers/ssb/driver_pcicore.c +++ b/drivers/ssb/driver_pcicore.c @@ -414,6 +414,16 @@ static int pcicore_is_in_hostmode(struct ssb_pcicore *pc) * Workarounds. **************************************************/ +static void ssb_pcicore_fix_sprom_core_index(struct ssb_pcicore *pc) +{ + u16 tmp = pcicore_read16(pc, SSB_PCICORE_SPROM(0)); + if (((tmp & 0xF000) >> 12) != pc->dev->core_index) { + tmp &= ~0xF000; + tmp |= (pc->dev->core_index << 12); + pcicore_write16(pc, SSB_PCICORE_SPROM(0), tmp); + } +} + static u8 ssb_pcicore_polarity_workaround(struct ssb_pcicore *pc) { return (ssb_pcie_read(pc, 0x204) & 0x10) ? 0xC0 : 0x80; @@ -521,6 +531,8 @@ void ssb_pcicore_init(struct ssb_pcicore *pc) if (!ssb_device_is_enabled(dev)) ssb_device_enable(dev, 0); + ssb_pcicore_fix_sprom_core_index(pc); + #ifdef CONFIG_SSB_PCICORE_HOSTMODE pc->hostmode = pcicore_is_in_hostmode(pc); if (pc->hostmode) -- cgit v0.10.2 From 49adc5ceb2b95e517baf625e0c8e06e91073009b Mon Sep 17 00:00:00 2001 From: "John W. Linville" Date: Wed, 27 Apr 2011 15:04:28 -0400 Subject: mwl8k: replace rateinfo bitfields with mask and shift macros AFAICT, this driver is claiming that 24 bits of rate info fit into a 16-bit field in the Tx descriptor. Anyway, the use of bitfields is frowned-upon for a variety of well-documented reasons... Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c index b8f2b12..8a1b262 100644 --- a/drivers/net/wireless/mwl8k.c +++ b/drivers/net/wireless/mwl8k.c @@ -1562,24 +1562,11 @@ static int mwl8k_tid_queue_mapping(u8 tid) /* The firmware will fill in the rate information * for each packet that gets queued in the hardware - * in this structure + * and these macros will interpret that info. */ -struct rateinfo { - __le16 format:1; - __le16 short_gi:1; - __le16 band_width:1; - __le16 rate_id_mcs:6; - __le16 adv_coding:2; - __le16 antenna:2; - __le16 act_sub_chan:2; - __le16 preamble_type:1; - __le16 power_id:4; - __le16 antenna2:1; - __le16 reserved:1; - __le16 tx_bf_frame:1; - __le16 green_field:1; -} __packed; +#define RI_FORMAT(a) (a & 0x0001) +#define RI_RATE_ID_MCS(a) ((a & 0x01f8) >> 3) static int mwl8k_txq_reclaim(struct ieee80211_hw *hw, int index, int limit, int force) @@ -1600,7 +1587,6 @@ mwl8k_txq_reclaim(struct ieee80211_hw *hw, int index, int limit, int force) struct ieee80211_sta *sta; struct mwl8k_sta *sta_info = NULL; u16 rate_info; - struct rateinfo *rate; struct ieee80211_hdr *wh; tx = txq->head; @@ -1643,14 +1629,13 @@ mwl8k_txq_reclaim(struct ieee80211_hw *hw, int index, int limit, int force) sta_info = MWL8K_STA(sta); BUG_ON(sta_info == NULL); rate_info = le16_to_cpu(tx_desc->rate_info); - rate = (struct rateinfo *)&rate_info; /* If rate is < 6.5 Mpbs for an ht station * do not form an ampdu. If the station is a * legacy station (format = 0), do not form an * ampdu */ - if (rate->rate_id_mcs < 1 || - rate->format == 0) { + if (RI_RATE_ID_MCS(rate_info) < 1 || + RI_FORMAT(rate_info) == 0) { sta_info->is_ampdu_allowed = false; } else { sta_info->is_ampdu_allowed = true; -- cgit v0.10.2 From adc89595732b92f78940fc0ccdb52afaec582a48 Mon Sep 17 00:00:00 2001 From: Amitkumar Karwar Date: Wed, 27 Apr 2011 19:13:11 -0700 Subject: mwifiex: check firmware capabilities while initialising 5GHz band parameters There are some SD8787 cards which don't support 5GHz band. Therefore initialise 5GHz band parameters only if hardware supports the band. Signed-off-by: Amitkumar Karwar Signed-off-by: Bing Zhao Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/mwifiex/cfg80211.c b/drivers/net/wireless/mwifiex/cfg80211.c index b99ae26..5855755 100644 --- a/drivers/net/wireless/mwifiex/cfg80211.c +++ b/drivers/net/wireless/mwifiex/cfg80211.c @@ -1235,20 +1235,23 @@ int mwifiex_register_cfg80211(struct net_device *dev, u8 *mac, wdev->wiphy->max_scan_ssids = 10; wdev->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) | BIT(NL80211_IFTYPE_ADHOC); + wdev->wiphy->bands[IEEE80211_BAND_2GHZ] = &mwifiex_band_2ghz; - wdev->wiphy->bands[IEEE80211_BAND_5GHZ] = &mwifiex_band_5ghz; + mwifiex_setup_ht_caps( + &wdev->wiphy->bands[IEEE80211_BAND_2GHZ]->ht_cap, priv); + + if (priv->adapter->config_bands & BAND_A) { + wdev->wiphy->bands[IEEE80211_BAND_5GHZ] = &mwifiex_band_5ghz; + mwifiex_setup_ht_caps( + &wdev->wiphy->bands[IEEE80211_BAND_5GHZ]->ht_cap, priv); + } else { + wdev->wiphy->bands[IEEE80211_BAND_5GHZ] = NULL; + } /* Initialize cipher suits */ wdev->wiphy->cipher_suites = mwifiex_cipher_suites; wdev->wiphy->n_cipher_suites = ARRAY_SIZE(mwifiex_cipher_suites); - /* Initialize parameters for 2GHz band */ - - mwifiex_setup_ht_caps(&wdev->wiphy->bands[IEEE80211_BAND_2GHZ]->ht_cap, - priv); - mwifiex_setup_ht_caps(&wdev->wiphy->bands[IEEE80211_BAND_5GHZ]->ht_cap, - priv); - memcpy(wdev->wiphy->perm_addr, mac, 6); wdev->wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM; -- cgit v0.10.2 From a46b7b5c13b9ecfe2b4e045e06aaec644dcf55d8 Mon Sep 17 00:00:00 2001 From: Amitkumar Karwar Date: Wed, 27 Apr 2011 19:13:12 -0700 Subject: mwifiex: HT capability information handling 1) Initialise HT capabilities in cfg80211 properly. 2) Cfg80211 stack may modify "sband->ht_cap" to disable 40Mhz operation in 2.4GHz band (after recent patch "cfg80211: module_param to disable HT40 in 2.4GHz band") Therefore read "sband->ht_cap" instead of an adapter variable "hw_dot_11n_dev_cap" to get HT capabilities. Signed-off-by: Amitkumar Karwar Signed-off-by: Bing Zhao Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/mwifiex/11n.c b/drivers/net/wireless/mwifiex/11n.c index e22d761..1d294cf 100644 --- a/drivers/net/wireless/mwifiex/11n.c +++ b/drivers/net/wireless/mwifiex/11n.c @@ -29,95 +29,38 @@ * Fills HT capability information field, AMPDU Parameters field, HT extended * capability field, and supported MCS set fields. * - * Only the following HT capability information fields are used, all other - * fields are always turned off. + * HT capability information field, AMPDU Parameters field, supported MCS set + * fields are retrieved from cfg80211 stack * - * Bit 1 : Supported channel width (0: 20MHz, 1: Both 20 and 40 MHz) - * Bit 4 : Greenfield support (0: Not supported, 1: Supported) - * Bit 5 : Short GI for 20 MHz support (0: Not supported, 1: Supported) - * Bit 6 : Short GI for 40 MHz support (0: Not supported, 1: Supported) - * Bit 7 : Tx STBC (0: Not supported, 1: Supported) - * Bit 8-9 : Rx STBC (0: Not supported, X: Support for up to X spatial streams) - * Bit 10 : Delayed BA support (0: Not supported, 1: Supported) - * Bit 11 : Maximum AMSDU length (0: 3839 octets, 1: 7935 octets) - * Bit 14 : 40-Mhz intolerant support (0: Not supported, 1: Supported) - * - * In addition, the following AMPDU Parameters are set - - * - Maximum AMPDU length exponent (set to 3) - * - Minimum AMPDU start spacing (set to 0 - No restrictions) - * - * MCS is set for 1x1, with MSC32 for infra mode or ad-hoc mode with 40 MHz - * support. - * - * RD responder bit to set to clear in the extended capability header. + * RD responder bit to set to clear in the extended capability header. */ void -mwifiex_fill_cap_info(struct mwifiex_private *priv, +mwifiex_fill_cap_info(struct mwifiex_private *priv, u8 radio_type, struct mwifiex_ie_types_htcap *ht_cap) { - struct mwifiex_adapter *adapter = priv->adapter; - u8 *mcs; - int rx_mcs_supp; - uint16_t ht_cap_info = le16_to_cpu(ht_cap->ht_cap.cap_info); uint16_t ht_ext_cap = le16_to_cpu(ht_cap->ht_cap.extended_ht_cap_info); + struct ieee80211_supported_band *sband = + priv->wdev->wiphy->bands[radio_type]; - /* Convert dev_cap to IEEE80211_HT_CAP */ - if (ISSUPP_CHANWIDTH40(adapter->hw_dot_11n_dev_cap)) - ht_cap_info |= IEEE80211_HT_CAP_SUP_WIDTH_20_40; - else - ht_cap_info &= ~IEEE80211_HT_CAP_SUP_WIDTH_20_40; - - if (ISSUPP_SHORTGI20(adapter->hw_dot_11n_dev_cap)) - ht_cap_info |= IEEE80211_HT_CAP_SGI_20; - else - ht_cap_info &= ~IEEE80211_HT_CAP_SGI_20; - - if (ISSUPP_SHORTGI40(adapter->hw_dot_11n_dev_cap)) - ht_cap_info |= IEEE80211_HT_CAP_SGI_40; - else - ht_cap_info &= ~IEEE80211_HT_CAP_SGI_40; - - if (ISSUPP_TXSTBC(adapter->hw_dot_11n_dev_cap)) - ht_cap_info |= IEEE80211_HT_CAP_TX_STBC; - else - ht_cap_info &= ~IEEE80211_HT_CAP_TX_STBC; - - if (ISSUPP_RXSTBC(adapter->hw_dot_11n_dev_cap)) - ht_cap_info |= 1 << IEEE80211_HT_CAP_RX_STBC_SHIFT; - else - ht_cap_info &= ~(3 << IEEE80211_HT_CAP_RX_STBC_SHIFT); - - if (ISSUPP_GREENFIELD(adapter->hw_dot_11n_dev_cap)) - ht_cap_info |= IEEE80211_HT_CAP_GRN_FLD; - else - ht_cap_info &= ~IEEE80211_HT_CAP_GRN_FLD; - - ht_cap_info &= ~IEEE80211_HT_CAP_MAX_AMSDU; - ht_cap_info |= IEEE80211_HT_CAP_SM_PS; + ht_cap->ht_cap.ampdu_params_info = + (sband->ht_cap.ampdu_factor & + IEEE80211_HT_AMPDU_PARM_FACTOR)| + ((sband->ht_cap.ampdu_density << + IEEE80211_HT_AMPDU_PARM_DENSITY_SHIFT) & + IEEE80211_HT_AMPDU_PARM_DENSITY); - ht_cap->ht_cap.ampdu_params_info |= IEEE80211_HT_AMPDU_PARM_FACTOR; - ht_cap->ht_cap.ampdu_params_info &= ~IEEE80211_HT_AMPDU_PARM_DENSITY; - - rx_mcs_supp = GET_RXMCSSUPP(adapter->hw_dev_mcs_support); - - mcs = (u8 *)&ht_cap->ht_cap.mcs; - - /* Set MCS for 1x1 */ - memset(mcs, 0xff, rx_mcs_supp); - - /* Clear all the other values */ - memset(&mcs[rx_mcs_supp], 0, - sizeof(struct ieee80211_mcs_info) - rx_mcs_supp); + memcpy((u8 *) &ht_cap->ht_cap.mcs, &sband->ht_cap.mcs, + sizeof(sband->ht_cap.mcs)); if (priv->bss_mode == NL80211_IFTYPE_STATION || - (ht_cap_info & IEEE80211_HT_CAP_SUP_WIDTH_20_40)) + (sband->ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40)) /* Set MCS32 for infra mode or ad-hoc mode with 40MHz support */ SETHT_MCS32(ht_cap->ht_cap.mcs.rx_mask); /* Clear RD responder bit */ ht_ext_cap &= ~IEEE80211_HT_EXT_CAP_RD_RESPONDER; - ht_cap->ht_cap.cap_info = cpu_to_le16(ht_cap_info); + ht_cap->ht_cap.cap_info = cpu_to_le16(sband->ht_cap.cap); ht_cap->ht_cap.extended_ht_cap_info = cpu_to_le16(ht_ext_cap); } @@ -391,10 +334,15 @@ mwifiex_cmd_append_11n_tlv(struct mwifiex_private *priv, struct mwifiex_ie_types_2040bssco *bss_co_2040; struct mwifiex_ie_types_extcap *ext_cap; int ret_len = 0; + struct ieee80211_supported_band *sband; + u8 radio_type; if (!buffer || !*buffer) return ret_len; + radio_type = mwifiex_band_to_radio_type((u8) bss_desc->bss_band); + sband = priv->wdev->wiphy->bands[radio_type]; + if (bss_desc->bcn_ht_cap) { ht_cap = (struct mwifiex_ie_types_htcap *) *buffer; memset(ht_cap, 0, sizeof(struct mwifiex_ie_types_htcap)); @@ -406,7 +354,7 @@ mwifiex_cmd_append_11n_tlv(struct mwifiex_private *priv, sizeof(struct ieee_types_header), le16_to_cpu(ht_cap->header.len)); - mwifiex_fill_cap_info(priv, ht_cap); + mwifiex_fill_cap_info(priv, radio_type, ht_cap); *buffer += sizeof(struct mwifiex_ie_types_htcap); ret_len += sizeof(struct mwifiex_ie_types_htcap); @@ -428,8 +376,8 @@ mwifiex_cmd_append_11n_tlv(struct mwifiex_private *priv, sizeof(struct ieee_types_header), le16_to_cpu(ht_info->header.len)); - if (!ISSUPP_CHANWIDTH40 - (priv->adapter->hw_dot_11n_dev_cap)) + if (!(sband->ht_cap.cap & + IEEE80211_HT_CAP_SUP_WIDTH_20_40)) ht_info->ht_info.ht_param &= ~(IEEE80211_HT_PARAM_CHAN_WIDTH_ANY | IEEE80211_HT_PARAM_CHA_SEC_OFFSET); @@ -451,7 +399,7 @@ mwifiex_cmd_append_11n_tlv(struct mwifiex_private *priv, chan_list->chan_scan_param[0].radio_type = mwifiex_band_to_radio_type((u8) bss_desc->bss_band); - if (ISSUPP_CHANWIDTH40(priv->adapter->hw_dot_11n_dev_cap) + if ((sband->ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40) && (bss_desc->bcn_ht_info->ht_param & IEEE80211_HT_PARAM_CHAN_WIDTH_ANY)) SET_SECONDARYCHAN(chan_list->chan_scan_param[0]. diff --git a/drivers/net/wireless/mwifiex/11n.h b/drivers/net/wireless/mwifiex/11n.h index 02602ff..a4390a1 100644 --- a/drivers/net/wireless/mwifiex/11n.h +++ b/drivers/net/wireless/mwifiex/11n.h @@ -38,7 +38,7 @@ int mwifiex_cmd_append_11n_tlv(struct mwifiex_private *priv, u8 **buffer); void mwifiex_cfg_tx_buf(struct mwifiex_private *priv, struct mwifiex_bssdescriptor *bss_desc); -void mwifiex_fill_cap_info(struct mwifiex_private *, +void mwifiex_fill_cap_info(struct mwifiex_private *, u8 radio_type, struct mwifiex_ie_types_htcap *); int mwifiex_set_get_11n_htcap_cfg(struct mwifiex_private *priv, u16 action, int *htcap_cfg); diff --git a/drivers/net/wireless/mwifiex/cfg80211.c b/drivers/net/wireless/mwifiex/cfg80211.c index 5855755..98009e2 100644 --- a/drivers/net/wireless/mwifiex/cfg80211.c +++ b/drivers/net/wireless/mwifiex/cfg80211.c @@ -1150,9 +1150,9 @@ mwifiex_cfg80211_scan(struct wiphy *wiphy, struct net_device *dev, * * The following default values are set - * - HT Supported = True - * - Maximum AMPDU length factor = 0x3 - * - Minimum AMPDU spacing = 0x6 - * - HT Capabilities map = IEEE80211_HT_CAP_SUP_WIDTH_20_40 (0x0002) + * - Maximum AMPDU length factor = IEEE80211_HT_MAX_AMPDU_64K + * - Minimum AMPDU spacing = IEEE80211_HT_MPDU_DENSITY_NONE + * - HT Capabilities supported by firmware * - MCS information, Rx mask = 0xff * - MCD information, Tx parameters = IEEE80211_HT_MCS_TX_DEFINED (0x01) */ @@ -1166,13 +1166,41 @@ mwifiex_setup_ht_caps(struct ieee80211_sta_ht_cap *ht_info, struct mwifiex_adapter *adapter = priv->adapter; ht_info->ht_supported = true; - ht_info->ampdu_factor = 0x3; - ht_info->ampdu_density = 0x6; + ht_info->ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K; + ht_info->ampdu_density = IEEE80211_HT_MPDU_DENSITY_NONE; memset(&ht_info->mcs, 0, sizeof(ht_info->mcs)); - ht_info->cap = IEEE80211_HT_CAP_SUP_WIDTH_20_40; - rx_mcs_supp = GET_RXMCSSUPP(priv->adapter->hw_dev_mcs_support); + /* Fill HT capability information */ + if (ISSUPP_CHANWIDTH40(adapter->hw_dot_11n_dev_cap)) + ht_info->cap |= IEEE80211_HT_CAP_SUP_WIDTH_20_40; + else + ht_info->cap &= ~IEEE80211_HT_CAP_SUP_WIDTH_20_40; + + if (ISSUPP_SHORTGI20(adapter->hw_dot_11n_dev_cap)) + ht_info->cap |= IEEE80211_HT_CAP_SGI_20; + else + ht_info->cap &= ~IEEE80211_HT_CAP_SGI_20; + + if (ISSUPP_SHORTGI40(adapter->hw_dot_11n_dev_cap)) + ht_info->cap |= IEEE80211_HT_CAP_SGI_40; + else + ht_info->cap &= ~IEEE80211_HT_CAP_SGI_40; + + if (ISSUPP_RXSTBC(adapter->hw_dot_11n_dev_cap)) + ht_info->cap |= 1 << IEEE80211_HT_CAP_RX_STBC_SHIFT; + else + ht_info->cap &= ~(3 << IEEE80211_HT_CAP_RX_STBC_SHIFT); + + if (ISSUPP_TXSTBC(adapter->hw_dot_11n_dev_cap)) + ht_info->cap |= IEEE80211_HT_CAP_TX_STBC; + else + ht_info->cap &= ~IEEE80211_HT_CAP_TX_STBC; + + ht_info->cap &= ~IEEE80211_HT_CAP_MAX_AMSDU; + ht_info->cap |= IEEE80211_HT_CAP_SM_PS; + + rx_mcs_supp = GET_RXMCSSUPP(adapter->hw_dev_mcs_support); /* Set MCS for 1x1 */ memset(mcs, 0xff, rx_mcs_supp); /* Clear all the other values */ diff --git a/drivers/net/wireless/mwifiex/scan.c b/drivers/net/wireless/mwifiex/scan.c index 68d905d..be708ad 100644 --- a/drivers/net/wireless/mwifiex/scan.c +++ b/drivers/net/wireless/mwifiex/scan.c @@ -1007,7 +1007,9 @@ mwifiex_scan_setup_scan_config(struct mwifiex_private *priv, ht_cap->header.type = cpu_to_le16(WLAN_EID_HT_CAPABILITY); ht_cap->header.len = cpu_to_le16(sizeof(struct ieee80211_ht_cap)); - mwifiex_fill_cap_info(priv, ht_cap); + radio_type = + mwifiex_band_to_radio_type(priv->adapter->config_bands); + mwifiex_fill_cap_info(priv, radio_type, ht_cap); tlv_pos += sizeof(struct mwifiex_ie_types_htcap); } -- cgit v0.10.2 From 030fe7974f48bd86bb706ec05188ebab0cb7af80 Mon Sep 17 00:00:00 2001 From: Amitkumar Karwar Date: Wed, 27 Apr 2011 19:13:13 -0700 Subject: mwifiex: fix bug in mwifiex_save_curr_bcn() Since timestamp in beacon buffer keeps changing all the time, the memcmp check in mwifiex_save_curr_bcn() is redundant. Remove that memcmp check and also avoid freeing and allocation of buffer if required beacon buffer size is same as previous one. Signed-off-by: Amitkumar Karwar Signed-off-by: Bing Zhao Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/mwifiex/scan.c b/drivers/net/wireless/mwifiex/scan.c index be708ad..31a5295 100644 --- a/drivers/net/wireless/mwifiex/scan.c +++ b/drivers/net/wireless/mwifiex/scan.c @@ -2990,32 +2990,28 @@ mwifiex_save_curr_bcn(struct mwifiex_private *priv) struct mwifiex_bssdescriptor *curr_bss = &priv->curr_bss_params.bss_descriptor; - /* save the beacon buffer if it is not saved or updated */ - if ((priv->curr_bcn_buf == NULL) || - (priv->curr_bcn_size != curr_bss->beacon_buf_size) || - (memcmp(priv->curr_bcn_buf, curr_bss->beacon_buf, - curr_bss->beacon_buf_size))) { - - kfree(priv->curr_bcn_buf); - priv->curr_bcn_buf = NULL; + if (!curr_bss->beacon_buf_size) + return; + /* allocate beacon buffer at 1st time; or if it's size has changed */ + if (!priv->curr_bcn_buf || + priv->curr_bcn_size != curr_bss->beacon_buf_size) { priv->curr_bcn_size = curr_bss->beacon_buf_size; - if (!priv->curr_bcn_size) - return; + kfree(priv->curr_bcn_buf); priv->curr_bcn_buf = kzalloc(curr_bss->beacon_buf_size, GFP_KERNEL); if (!priv->curr_bcn_buf) { dev_err(priv->adapter->dev, "failed to alloc curr_bcn_buf\n"); - } else { - memcpy(priv->curr_bcn_buf, curr_bss->beacon_buf, - curr_bss->beacon_buf_size); - dev_dbg(priv->adapter->dev, - "info: current beacon saved %d\n", - priv->curr_bcn_size); + return; } } + + memcpy(priv->curr_bcn_buf, curr_bss->beacon_buf, + curr_bss->beacon_buf_size); + dev_dbg(priv->adapter->dev, "info: current beacon saved %d\n", + priv->curr_bcn_size); } /* -- cgit v0.10.2 From 7a828908a026d801c6192fd32cfb35d6843f1539 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Thu, 28 Apr 2011 11:28:53 -0700 Subject: Bluetooth: Add automated SSP user confirmation responses This patch adds automated negative and positive (auto-accept) responses for Secure Simple Pairing user confirmation requests. The responses are only sent if the HCI_MGMT flag is set in order not to confuse older user space versions (without management interface support). Signed-off-by: Johan Hedberg Signed-off-by: Gustavo F. Padovan diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index 577d638..514e10e 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -2483,14 +2483,47 @@ static inline void hci_user_confirm_request_evt(struct hci_dev *hdev, struct sk_buff *skb) { struct hci_ev_user_confirm_req *ev = (void *) skb->data; + int loc_mitm, rem_mitm; + struct hci_conn *conn; BT_DBG("%s", hdev->name); hci_dev_lock(hdev); - if (test_bit(HCI_MGMT, &hdev->flags)) - mgmt_user_confirm_request(hdev->id, &ev->bdaddr, ev->passkey); + if (!test_bit(HCI_MGMT, &hdev->flags)) + goto unlock; + conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &ev->bdaddr); + if (!conn) + goto unlock; + + loc_mitm = (conn->auth_type & 0x01); + rem_mitm = (conn->remote_auth & 0x01); + + /* If we require MITM but the remote device can't provide that + * (it has NoInputNoOutput) then reject the confirmation + * request. The only exception is when we're dedicated bonding + * initiators (connect_cfm_cb set) since then we always have the MITM + * bit set. */ + if (!conn->connect_cfm_cb && loc_mitm && conn->remote_cap == 0x03) { + BT_DBG("Rejecting request: remote device can't provide MITM"); + hci_send_cmd(hdev, HCI_OP_USER_CONFIRM_NEG_REPLY, + sizeof(ev->bdaddr), &ev->bdaddr); + goto unlock; + } + + /* If no side requires MITM protection; auto-accept */ + if ((!loc_mitm || conn->remote_cap == 0x03) && + (!rem_mitm || conn->io_capability == 0x03)) { + BT_DBG("Auto-accept of user confirmation"); + hci_send_cmd(hdev, HCI_OP_USER_CONFIRM_REPLY, + sizeof(ev->bdaddr), &ev->bdaddr); + goto unlock; + } + + mgmt_user_confirm_request(hdev->id, &ev->bdaddr, ev->passkey); + +unlock: hci_dev_unlock(hdev); } -- cgit v0.10.2 From 9f61656a60c9506e3e4cd41af5efbcf6a30ee3b9 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Thu, 28 Apr 2011 11:28:54 -0700 Subject: Bluetooth: Add variable SSP auto-accept delay support Some test systems require an arbitrary delay to the auto-accept test cases for Secure Simple Pairing in order for the tests to pass. Previously when this was handled in user space it was worked around by code modifications and recompilation, but now that it's on the kernel side it's more convenient if there's a debugfs interface for it. Signed-off-by: Johan Hedberg Signed-off-by: Gustavo F. Padovan diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index 2995e2e..09b9dd6 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -126,6 +126,8 @@ struct hci_dev { __u16 sniff_min_interval; __u16 sniff_max_interval; + unsigned int auto_accept_delay; + unsigned long quirks; atomic_t cmd_cnt; @@ -246,6 +248,7 @@ struct hci_conn { struct timer_list disc_timer; struct timer_list idle_timer; + struct timer_list auto_accept_timer; struct work_struct work_add; struct work_struct work_del; diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c index 74cd755..7f5ad8a 100644 --- a/net/bluetooth/hci_conn.c +++ b/net/bluetooth/hci_conn.c @@ -269,6 +269,19 @@ static void hci_conn_idle(unsigned long arg) hci_conn_enter_sniff_mode(conn); } +static void hci_conn_auto_accept(unsigned long arg) +{ + struct hci_conn *conn = (void *) arg; + struct hci_dev *hdev = conn->hdev; + + hci_dev_lock(hdev); + + hci_send_cmd(hdev, HCI_OP_USER_CONFIRM_REPLY, sizeof(conn->dst), + &conn->dst); + + hci_dev_unlock(hdev); +} + struct hci_conn *hci_conn_add(struct hci_dev *hdev, int type, bdaddr_t *dst) { struct hci_conn *conn; @@ -312,6 +325,8 @@ struct hci_conn *hci_conn_add(struct hci_dev *hdev, int type, bdaddr_t *dst) setup_timer(&conn->disc_timer, hci_conn_timeout, (unsigned long)conn); setup_timer(&conn->idle_timer, hci_conn_idle, (unsigned long)conn); + setup_timer(&conn->auto_accept_timer, hci_conn_auto_accept, + (unsigned long) conn); atomic_set(&conn->refcnt, 0); @@ -342,6 +357,8 @@ int hci_conn_del(struct hci_conn *conn) del_timer(&conn->disc_timer); + del_timer(&conn->auto_accept_timer); + if (conn->type == ACL_LINK) { struct hci_conn *sco = conn->link; if (sco) diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index 514e10e..a479389 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -2515,7 +2515,15 @@ static inline void hci_user_confirm_request_evt(struct hci_dev *hdev, /* If no side requires MITM protection; auto-accept */ if ((!loc_mitm || conn->remote_cap == 0x03) && (!rem_mitm || conn->io_capability == 0x03)) { - BT_DBG("Auto-accept of user confirmation"); + BT_DBG("Auto-accept of user confirmation with %ums delay", + hdev->auto_accept_delay); + + if (hdev->auto_accept_delay > 0) { + int delay = msecs_to_jiffies(hdev->auto_accept_delay); + mod_timer(&conn->auto_accept_timer, jiffies + delay); + goto unlock; + } + hci_send_cmd(hdev, HCI_OP_USER_CONFIRM_REPLY, sizeof(ev->bdaddr), &ev->bdaddr); goto unlock; diff --git a/net/bluetooth/hci_sysfs.c b/net/bluetooth/hci_sysfs.c index 8775933..a6c3aa8 100644 --- a/net/bluetooth/hci_sysfs.c +++ b/net/bluetooth/hci_sysfs.c @@ -511,6 +511,35 @@ static const struct file_operations uuids_fops = { .release = single_release, }; +static int auto_accept_delay_set(void *data, u64 val) +{ + struct hci_dev *hdev = data; + + hci_dev_lock_bh(hdev); + + hdev->auto_accept_delay = val; + + hci_dev_unlock_bh(hdev); + + return 0; +} + +static int auto_accept_delay_get(void *data, u64 *val) +{ + struct hci_dev *hdev = data; + + hci_dev_lock_bh(hdev); + + *val = hdev->auto_accept_delay; + + hci_dev_unlock_bh(hdev); + + return 0; +} + +DEFINE_SIMPLE_ATTRIBUTE(auto_accept_delay_fops, auto_accept_delay_get, + auto_accept_delay_set, "%llu\n"); + int hci_register_sysfs(struct hci_dev *hdev) { struct device *dev = &hdev->dev; @@ -545,6 +574,8 @@ int hci_register_sysfs(struct hci_dev *hdev) debugfs_create_file("uuids", 0444, hdev->debugfs, hdev, &uuids_fops); + debugfs_create_file("auto_accept_delay", 0444, hdev->debugfs, hdev, + &auto_accept_delay_fops); return 0; } -- cgit v0.10.2 From 79c6c70cbe35c270e7b59207ab76b44183a1030a Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Thu, 28 Apr 2011 11:28:55 -0700 Subject: Bluetooth: Fix HCI_CONN_AUTH_PEND flag for all authentication requests The HCI_CONN_AUTH_PEND flag should be set whenever requesting authentication so that multiple pending requests can't occur. Signed-off-by: Johan Hedberg Signed-off-by: Gustavo F. Padovan diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index a479389..ce8e099 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -1021,12 +1021,19 @@ static void hci_cs_remote_name_req(struct hci_dev *hdev, __u8 status) hci_dev_lock(hdev); conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->bdaddr); - if (conn && hci_outgoing_auth_needed(hdev, conn)) { + if (!conn) + goto unlock; + + if (!hci_outgoing_auth_needed(hdev, conn)) + goto unlock; + + if (!test_and_set_bit(HCI_CONN_AUTH_PEND, &conn->pend)) { struct hci_cp_auth_requested cp; cp.handle = __cpu_to_le16(conn->handle); hci_send_cmd(hdev, HCI_OP_AUTH_REQUESTED, sizeof(cp), &cp); } +unlock: hci_dev_unlock(hdev); } @@ -1516,12 +1523,19 @@ static inline void hci_remote_name_evt(struct hci_dev *hdev, struct sk_buff *skb mgmt_remote_name(hdev->id, &ev->bdaddr, ev->name); conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &ev->bdaddr); - if (conn && hci_outgoing_auth_needed(hdev, conn)) { + if (!conn) + goto unlock; + + if (!hci_outgoing_auth_needed(hdev, conn)) + goto unlock; + + if (!test_and_set_bit(HCI_CONN_AUTH_PEND, &conn->pend)) { struct hci_cp_auth_requested cp; cp.handle = __cpu_to_le16(conn->handle); hci_send_cmd(hdev, HCI_OP_AUTH_REQUESTED, sizeof(cp), &cp); } +unlock: hci_dev_unlock(hdev); } -- cgit v0.10.2 From 55bc1a378cc35f21a26e07af2ff2b71820808cd4 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Thu, 28 Apr 2011 11:28:56 -0700 Subject: Bluetooth: Add confirm_hint parameter to user confirmation requests When accepting a pairing request which fulfills the SSP auto-accept criteria we need to push the request all the way to the user for confirmation. This patch adds a new hint to the user_confirm_request management event so user space can know when to show a numeric comparison dialog and when to show a simple yes/no confirmation dialog. Signed-off-by: Johan Hedberg Signed-off-by: Gustavo F. Padovan diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index 09b9dd6..135dfac 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -783,7 +783,8 @@ int mgmt_connect_failed(u16 index, bdaddr_t *bdaddr, u8 status); int mgmt_pin_code_request(u16 index, bdaddr_t *bdaddr, u8 secure); int mgmt_pin_code_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status); int mgmt_pin_code_neg_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status); -int mgmt_user_confirm_request(u16 index, bdaddr_t *bdaddr, __le32 value); +int mgmt_user_confirm_request(u16 index, bdaddr_t *bdaddr, __le32 value, + u8 confirm_hint); int mgmt_user_confirm_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status); int mgmt_user_confirm_neg_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status); diff --git a/include/net/bluetooth/mgmt.h b/include/net/bluetooth/mgmt.h index 0e7de63..c444a2b8 100644 --- a/include/net/bluetooth/mgmt.h +++ b/include/net/bluetooth/mgmt.h @@ -259,6 +259,7 @@ struct mgmt_ev_pin_code_request { #define MGMT_EV_USER_CONFIRM_REQUEST 0x000F struct mgmt_ev_user_confirm_request { bdaddr_t bdaddr; + __u8 confirm_hint; __le32 value; } __packed; diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index ce8e099..29310c7 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -2497,7 +2497,7 @@ static inline void hci_user_confirm_request_evt(struct hci_dev *hdev, struct sk_buff *skb) { struct hci_ev_user_confirm_req *ev = (void *) skb->data; - int loc_mitm, rem_mitm; + int loc_mitm, rem_mitm, confirm_hint = 0; struct hci_conn *conn; BT_DBG("%s", hdev->name); @@ -2529,6 +2529,16 @@ static inline void hci_user_confirm_request_evt(struct hci_dev *hdev, /* If no side requires MITM protection; auto-accept */ if ((!loc_mitm || conn->remote_cap == 0x03) && (!rem_mitm || conn->io_capability == 0x03)) { + + /* If we're not the initiators request authorization to + * proceed from user space (mgmt_user_confirm with + * confirm_hint set to 1). */ + if (!test_bit(HCI_CONN_AUTH_PEND, &conn->pend)) { + BT_DBG("Confirming auto-accept as acceptor"); + confirm_hint = 1; + goto confirm; + } + BT_DBG("Auto-accept of user confirmation with %ums delay", hdev->auto_accept_delay); @@ -2543,7 +2553,9 @@ static inline void hci_user_confirm_request_evt(struct hci_dev *hdev, goto unlock; } - mgmt_user_confirm_request(hdev->id, &ev->bdaddr, ev->passkey); +confirm: + mgmt_user_confirm_request(hdev->id, &ev->bdaddr, ev->passkey, + confirm_hint); unlock: hci_dev_unlock(hdev); diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index a7b4937..a1b0ec4 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -1995,13 +1995,15 @@ int mgmt_pin_code_neg_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status) return err; } -int mgmt_user_confirm_request(u16 index, bdaddr_t *bdaddr, __le32 value) +int mgmt_user_confirm_request(u16 index, bdaddr_t *bdaddr, __le32 value, + u8 confirm_hint) { struct mgmt_ev_user_confirm_request ev; BT_DBG("hci%u", index); bacpy(&ev.bdaddr, bdaddr); + ev.confirm_hint = confirm_hint; put_unaligned_le32(value, &ev.value); return mgmt_event(MGMT_EV_USER_CONFIRM_REQUEST, index, &ev, sizeof(ev), -- cgit v0.10.2 From be77159c3f37e73a18ecc5c1eab3c67e07c6ce22 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Thu, 28 Apr 2011 11:28:57 -0700 Subject: Bluetooth: Fix reason code for pairing rejection "Pairing not allowed" is 0x18 and not 0x16. Signed-off-by: Johan Hedberg Signed-off-by: Gustavo F. Padovan diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index 29310c7..d535ea4 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -2462,7 +2462,7 @@ static inline void hci_io_capa_request_evt(struct hci_dev *hdev, struct sk_buff struct hci_cp_io_capability_neg_reply cp; bacpy(&cp.bdaddr, &ev->bdaddr); - cp.reason = 0x16; /* Pairing not allowed */ + cp.reason = 0x18; /* Pairing not allowed */ hci_send_cmd(hdev, HCI_OP_IO_CAPABILITY_NEG_REPLY, sizeof(cp), &cp); -- cgit v0.10.2 From 582fbe9ef9d6fc089ff20956595f046d4899e74e Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Thu, 28 Apr 2011 11:28:58 -0700 Subject: Bluetooth: Fix logic in hci_pin_code_request_evt The mgmt_ev_pin_code_request event should not be sent to user space if the request gets rejected by the kernel due to the pairable flag not being set. Signed-off-by: Johan Hedberg Signed-off-by: Gustavo F. Padovan diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index d535ea4..ebbaa6c 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -2035,8 +2035,7 @@ static inline void hci_pin_code_request_evt(struct hci_dev *hdev, struct sk_buff if (!test_bit(HCI_PAIRABLE, &hdev->flags)) hci_send_cmd(hdev, HCI_OP_PIN_CODE_NEG_REPLY, sizeof(ev->bdaddr), &ev->bdaddr); - - if (test_bit(HCI_MGMT, &hdev->flags)) { + else if (test_bit(HCI_MGMT, &hdev->flags)) { u8 secure; if (conn->pending_sec_level == BT_SECURITY_HIGH) -- cgit v0.10.2 From d25e28abe58d2bcedf6025a6ccc532c29a19046f Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Thu, 28 Apr 2011 11:28:59 -0700 Subject: Bluetooth: Fix link key persistent storage criteria Link keys should only be stored if very specific criteria of the authentication process are fulfilled. This patch essentially copies the criteria that user space has so far been using to the kernel side so that the management interface works properly. Signed-off-by: Johan Hedberg Signed-off-by: Gustavo F. Padovan diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index 135dfac..3a3f7b4 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -515,8 +515,8 @@ int hci_uuids_clear(struct hci_dev *hdev); int hci_link_keys_clear(struct hci_dev *hdev); struct link_key *hci_find_link_key(struct hci_dev *hdev, bdaddr_t *bdaddr); -int hci_add_link_key(struct hci_dev *hdev, int new_key, bdaddr_t *bdaddr, - u8 *key, u8 type, u8 pin_len); +int hci_add_link_key(struct hci_dev *hdev, struct hci_conn *conn, int new_key, + bdaddr_t *bdaddr, u8 *val, u8 type, u8 pin_len); int hci_remove_link_key(struct hci_dev *hdev, bdaddr_t *bdaddr); int hci_remote_oob_data_clear(struct hci_dev *hdev); diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 07d0ba3..5f55aef 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -1022,8 +1022,44 @@ struct link_key *hci_find_link_key(struct hci_dev *hdev, bdaddr_t *bdaddr) return NULL; } -int hci_add_link_key(struct hci_dev *hdev, int new_key, bdaddr_t *bdaddr, - u8 *val, u8 type, u8 pin_len) +static int hci_persistent_key(struct hci_dev *hdev, struct hci_conn *conn, + u8 key_type, u8 old_key_type) +{ + /* Legacy key */ + if (key_type < 0x03) + return 1; + + /* Debug keys are insecure so don't store them persistently */ + if (key_type == HCI_LK_DEBUG_COMBINATION) + return 0; + + /* Changed combination key and there's no previous one */ + if (key_type == HCI_LK_CHANGED_COMBINATION && old_key_type == 0xff) + return 0; + + /* Security mode 3 case */ + if (!conn) + return 1; + + /* Neither local nor remote side had no-bonding as requirement */ + if (conn->auth_type > 0x01 && conn->remote_auth > 0x01) + return 1; + + /* Local side had dedicated bonding as requirement */ + if (conn->auth_type == 0x02 || conn->auth_type == 0x03) + return 1; + + /* Remote side had dedicated bonding as requirement */ + if (conn->remote_auth == 0x02 || conn->remote_auth == 0x03) + return 1; + + /* If none of the above criteria match, then don't store the key + * persistently */ + return 0; +} + +int hci_add_link_key(struct hci_dev *hdev, struct hci_conn *conn, int new_key, + bdaddr_t *bdaddr, u8 *val, u8 type, u8 pin_len) { struct link_key *key, *old_key; u8 old_key_type; @@ -1042,6 +1078,20 @@ int hci_add_link_key(struct hci_dev *hdev, int new_key, bdaddr_t *bdaddr, BT_DBG("%s key for %s type %u", hdev->name, batostr(bdaddr), type); + /* Some buggy controller combinations generate a changed + * combination key for legacy pairing even when there's no + * previous key */ + if (type == HCI_LK_CHANGED_COMBINATION && + (!conn || conn->remote_auth == 0xff) && + old_key_type == 0xff) + type = HCI_LK_COMBINATION; + + if (new_key && !hci_persistent_key(hdev, conn, type, old_key_type)) { + list_del(&key->list); + kfree(key); + return 0; + } + bacpy(&key->bdaddr, bdaddr); memcpy(key->val, val, 16); key->type = type; diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index ebbaa6c..8a63d3a 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -2136,7 +2136,7 @@ static inline void hci_link_key_notify_evt(struct hci_dev *hdev, struct sk_buff } if (test_bit(HCI_LINK_KEYS, &hdev->flags)) - hci_add_link_key(hdev, 1, &ev->bdaddr, ev->link_key, + hci_add_link_key(hdev, conn, 1, &ev->bdaddr, ev->link_key, ev->key_type, pin_len); hci_dev_unlock(hdev); diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index a1b0ec4..e1384fc 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -945,7 +945,7 @@ static int load_keys(struct sock *sk, u16 index, unsigned char *data, u16 len) for (i = 0; i < key_count; i++) { struct mgmt_key_info *key = &cp->keys[i]; - hci_add_link_key(hdev, 0, &key->bdaddr, key->val, key->type, + hci_add_link_key(hdev, NULL, 0, &key->bdaddr, key->val, key->type, key->pin_len); } -- cgit v0.10.2 From 12adcf3a953c3aa4006d855aa638133bf018ceac Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Thu, 28 Apr 2011 11:29:00 -0700 Subject: Bluetooth: Fix old_key_type logic for non-persistent keys Even if there's no previous key stored the connection might still be secured with a non-persistent key and in that case the key type in the hci_conn struct should be checked. Signed-off-by: Johan Hedberg Signed-off-by: Gustavo F. Padovan diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 5f55aef..2ac6036 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -1069,7 +1069,7 @@ int hci_add_link_key(struct hci_dev *hdev, struct hci_conn *conn, int new_key, old_key_type = old_key->type; key = old_key; } else { - old_key_type = 0xff; + old_key_type = conn ? conn->key_type : 0xff; key = kzalloc(sizeof(*key), GFP_ATOMIC); if (!key) return -ENOMEM; -- cgit v0.10.2 From 655fe6ece7e71b37c17577ae485d11bf701c95f7 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Thu, 28 Apr 2011 11:29:01 -0700 Subject: Bluetooth: Fix connection key type updating for buggy controllers If a controller generates a changed combination key as its first key the connection key type will not be correctly set. In these situations make sure the update the connection key type when such a buggy controller is detected. Signed-off-by: Johan Hedberg Signed-off-by: Gustavo F. Padovan diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 2ac6036..59ca475 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -1083,8 +1083,11 @@ int hci_add_link_key(struct hci_dev *hdev, struct hci_conn *conn, int new_key, * previous key */ if (type == HCI_LK_CHANGED_COMBINATION && (!conn || conn->remote_auth == 0xff) && - old_key_type == 0xff) + old_key_type == 0xff) { type = HCI_LK_COMBINATION; + if (conn) + conn->key_type = type; + } if (new_key && !hci_persistent_key(hdev, conn, type, old_key_type)) { list_del(&key->list); -- cgit v0.10.2 From 4748fed2d1a2a7a816277754498b8aa70850e051 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Thu, 28 Apr 2011 11:29:02 -0700 Subject: Bluetooth: Remove old_key_type from mgmt_ev_new_key User space shouldn't have any need for the old key type so remove it from the corresponding Management interface event. Signed-off-by: Johan Hedberg Signed-off-by: Gustavo F. Padovan diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index 3a3f7b4..88c2cd9 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -775,7 +775,7 @@ int mgmt_index_removed(u16 index); int mgmt_powered(u16 index, u8 powered); int mgmt_discoverable(u16 index, u8 discoverable); int mgmt_connectable(u16 index, u8 connectable); -int mgmt_new_key(u16 index, struct link_key *key, u8 old_key_type); +int mgmt_new_key(u16 index, struct link_key *key); int mgmt_connected(u16 index, bdaddr_t *bdaddr); int mgmt_disconnected(u16 index, bdaddr_t *bdaddr); int mgmt_disconnect_failed(u16 index); diff --git a/include/net/bluetooth/mgmt.h b/include/net/bluetooth/mgmt.h index c444a2b8..353a85d 100644 --- a/include/net/bluetooth/mgmt.h +++ b/include/net/bluetooth/mgmt.h @@ -231,7 +231,6 @@ struct mgmt_ev_controller_error { #define MGMT_EV_NEW_KEY 0x000A struct mgmt_ev_new_key { struct mgmt_key_info key; - __u8 old_key_type; } __packed; #define MGMT_EV_CONNECTED 0x000B diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 59ca475..60260ca 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -1097,14 +1097,15 @@ int hci_add_link_key(struct hci_dev *hdev, struct hci_conn *conn, int new_key, bacpy(&key->bdaddr, bdaddr); memcpy(key->val, val, 16); - key->type = type; key->pin_len = pin_len; - if (new_key) - mgmt_new_key(hdev->id, key, old_key_type); - if (type == HCI_LK_CHANGED_COMBINATION) key->type = old_key_type; + else + key->type = type; + + if (new_key) + mgmt_new_key(hdev->id, key); return 0; } diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index e1384fc..232ea8b 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -1858,7 +1858,7 @@ int mgmt_connectable(u16 index, u8 connectable) return ret; } -int mgmt_new_key(u16 index, struct link_key *key, u8 old_key_type) +int mgmt_new_key(u16 index, struct link_key *key) { struct mgmt_ev_new_key ev; @@ -1868,7 +1868,6 @@ int mgmt_new_key(u16 index, struct link_key *key, u8 old_key_type) ev.key.type = key->type; memcpy(ev.key.val, key->val, 16); ev.key.pin_len = key->pin_len; - ev.old_key_type = old_key_type; return mgmt_event(MGMT_EV_NEW_KEY, index, &ev, sizeof(ev), NULL); } -- cgit v0.10.2 From 4df378a10e31698df1679f3329301d773a654b61 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Thu, 28 Apr 2011 11:29:03 -0700 Subject: Bluetooth: Add store_hint parameter to mgmt_new_key Even for keys that shouldn't be stored some use cases require the knowledge of a new key having been created so that the conclusion of a successful pairing can be made. Therefore, always send the mgmt_new_key event but add a store_hint parameter to it to indicate to user space whether the key should be stored or not. Signed-off-by: Johan Hedberg Signed-off-by: Gustavo F. Padovan diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index 88c2cd9..14cc324 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -775,7 +775,7 @@ int mgmt_index_removed(u16 index); int mgmt_powered(u16 index, u8 powered); int mgmt_discoverable(u16 index, u8 discoverable); int mgmt_connectable(u16 index, u8 connectable); -int mgmt_new_key(u16 index, struct link_key *key); +int mgmt_new_key(u16 index, struct link_key *key, u8 persistent); int mgmt_connected(u16 index, bdaddr_t *bdaddr); int mgmt_disconnected(u16 index, bdaddr_t *bdaddr); int mgmt_disconnect_failed(u16 index); diff --git a/include/net/bluetooth/mgmt.h b/include/net/bluetooth/mgmt.h index 353a85d..4899286 100644 --- a/include/net/bluetooth/mgmt.h +++ b/include/net/bluetooth/mgmt.h @@ -230,6 +230,7 @@ struct mgmt_ev_controller_error { #define MGMT_EV_NEW_KEY 0x000A struct mgmt_ev_new_key { + __u8 store_hint; struct mgmt_key_info key; } __packed; diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 60260ca..b6bda3f 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -1062,7 +1062,7 @@ int hci_add_link_key(struct hci_dev *hdev, struct hci_conn *conn, int new_key, bdaddr_t *bdaddr, u8 *val, u8 type, u8 pin_len) { struct link_key *key, *old_key; - u8 old_key_type; + u8 old_key_type, persistent; old_key = hci_find_link_key(hdev, bdaddr); if (old_key) { @@ -1089,12 +1089,6 @@ int hci_add_link_key(struct hci_dev *hdev, struct hci_conn *conn, int new_key, conn->key_type = type; } - if (new_key && !hci_persistent_key(hdev, conn, type, old_key_type)) { - list_del(&key->list); - kfree(key); - return 0; - } - bacpy(&key->bdaddr, bdaddr); memcpy(key->val, val, 16); key->pin_len = pin_len; @@ -1104,8 +1098,17 @@ int hci_add_link_key(struct hci_dev *hdev, struct hci_conn *conn, int new_key, else key->type = type; - if (new_key) - mgmt_new_key(hdev->id, key); + if (!new_key) + return 0; + + persistent = hci_persistent_key(hdev, conn, type, old_key_type); + + mgmt_new_key(hdev->id, key, persistent); + + if (!persistent) { + list_del(&key->list); + kfree(key); + } return 0; } diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 232ea8b..2481d25 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -1858,12 +1858,13 @@ int mgmt_connectable(u16 index, u8 connectable) return ret; } -int mgmt_new_key(u16 index, struct link_key *key) +int mgmt_new_key(u16 index, struct link_key *key, u8 persistent) { struct mgmt_ev_new_key ev; memset(&ev, 0, sizeof(ev)); + ev.store_hint = persistent; bacpy(&ev.key.bdaddr, &key->bdaddr); ev.key.type = key->type; memcpy(ev.key.val, key->val, 16); -- cgit v0.10.2 From 7cbc9bd99542752ff570abca79d0027669a01fb8 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Thu, 28 Apr 2011 11:29:04 -0700 Subject: Bluetooth: Fix updating conn->auth_type in hci_io_capa_request_evt In some circumstances hci_get_auth_req will return a value different from the current conn->auth_type. In these cases update conn->auth_type so that when a user confirm request comes it doesn't falsely trigger auto-accept. Signed-off-by: Johan Hedberg Signed-off-by: Gustavo F. Padovan diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index 8a63d3a..d5aa97e 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -2447,7 +2447,8 @@ static inline void hci_io_capa_request_evt(struct hci_dev *hdev, struct sk_buff bacpy(&cp.bdaddr, &ev->bdaddr); cp.capability = conn->io_capability; - cp.authentication = hci_get_auth_req(conn); + conn->auth_type = hci_get_auth_req(conn); + cp.authentication = conn->auth_type; if ((conn->out == 0x01 || conn->remote_oob == 0x01) && hci_find_remote_oob_data(hdev, &conn->dst)) -- cgit v0.10.2 From 68972efa657040f891c7eda07c7da8c8dd576788 Mon Sep 17 00:00:00 2001 From: Paul Stewart Date: Thu, 28 Apr 2011 05:43:37 +0000 Subject: usbnet: Resubmit interrupt URB if device is open Resubmit interrupt URB if device is open. Use a flag set in usbnet_open() to determine this state. Also kill and free interrupt URB in usbnet_disconnect(). [Rebased off git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux-2.6.git] Signed-off-by: Paul Stewart Signed-off-by: David S. Miller diff --git a/drivers/net/usb/usbnet.c b/drivers/net/usb/usbnet.c index 069c1cf..009bba3 100644 --- a/drivers/net/usb/usbnet.c +++ b/drivers/net/usb/usbnet.c @@ -736,6 +736,7 @@ int usbnet_open (struct net_device *net) } } + set_bit(EVENT_DEV_OPEN, &dev->flags); netif_start_queue (net); netif_info(dev, ifup, dev->net, "open: enable queueing (rx %d, tx %d) mtu %d %s framing\n", @@ -1259,6 +1260,9 @@ void usbnet_disconnect (struct usb_interface *intf) if (dev->driver_info->unbind) dev->driver_info->unbind (dev, intf); + usb_kill_urb(dev->interrupt); + usb_free_urb(dev->interrupt); + free_netdev(net); usb_put_dev (xdev); } @@ -1498,6 +1502,10 @@ int usbnet_resume (struct usb_interface *intf) int retval; if (!--dev->suspend_count) { + /* resume interrupt URBs */ + if (dev->interrupt && test_bit(EVENT_DEV_OPEN, &dev->flags)) + usb_submit_urb(dev->interrupt, GFP_NOIO); + spin_lock_irq(&dev->txq.lock); while ((res = usb_get_from_anchor(&dev->deferred))) { diff --git a/include/linux/usb/usbnet.h b/include/linux/usb/usbnet.h index 0e18550..605b0aa 100644 --- a/include/linux/usb/usbnet.h +++ b/include/linux/usb/usbnet.h @@ -68,6 +68,7 @@ struct usbnet { # define EVENT_RX_PAUSED 5 # define EVENT_DEV_WAKING 6 # define EVENT_DEV_ASLEEP 7 +# define EVENT_DEV_OPEN 8 }; static inline struct usb_driver *driver_of(struct usb_interface *intf) -- cgit v0.10.2 From cb1e922fa104bb0bb3aa5fc6ca7f7e070f3b55e9 Mon Sep 17 00:00:00 2001 From: Eric Paris Date: Thu, 28 Apr 2011 15:11:21 -0400 Subject: SELinux: pass last path component in may_create New inodes are created in a two stage process. We first will compute the label on a new inode in security_inode_create() and check if the operation is allowed. We will then actually re-compute that same label and apply it in security_inode_init_security(). The change to do new label calculations based in part on the last component of the path name only passed the path component information all the way down the security_inode_init_security hook. Down the security_inode_create hook the path information did not make it past may_create. Thus the two calculations came up differently and the permissions check might not actually be against the label that is created. Pass and use the same information in both places to harmonize the calculations and checks. Reported-by: Dominick Grift Signed-off-by: Eric Paris diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index d52a925..9a93af8 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c @@ -1573,7 +1573,8 @@ static int may_create(struct inode *dir, return rc; if (!newsid || !(sbsec->flags & SE_SBLABELSUPP)) { - rc = security_transition_sid(sid, dsec->sid, tclass, NULL, &newsid); + rc = security_transition_sid(sid, dsec->sid, tclass, + &dentry->d_name, &newsid); if (rc) return rc; } -- cgit v0.10.2 From 5d30b10bd68df007e7ae21e77d1e0ce184b53040 Mon Sep 17 00:00:00 2001 From: Eric Paris Date: Thu, 28 Apr 2011 15:55:52 -0400 Subject: flex_array: flex_array_prealloc takes a number of elements, not an end Change flex_array_prealloc to take the number of elements for which space should be allocated instead of the last (inclusive) element. Users and documentation are updated accordingly. flex_arrays got introduced before they had users. When folks started using it, they ended up needing a different API than was coded up originally. This swaps over to the API that folks apparently need. Based-on-patch-by: Steffen Klassert Signed-off-by: Eric Paris Tested-by: Chris Richards Acked-by: Dave Hansen Cc: stable@kernel.org [2.6.38+] diff --git a/Documentation/flexible-arrays.txt b/Documentation/flexible-arrays.txt index cb8a3a0..df904ae 100644 --- a/Documentation/flexible-arrays.txt +++ b/Documentation/flexible-arrays.txt @@ -66,10 +66,10 @@ trick is to ensure that any needed memory allocations are done before entering atomic context, using: int flex_array_prealloc(struct flex_array *array, unsigned int start, - unsigned int end, gfp_t flags); + unsigned int nr_elements, gfp_t flags); This function will ensure that memory for the elements indexed in the range -defined by start and end has been allocated. Thereafter, a +defined by start and nr_elements has been allocated. Thereafter, a flex_array_put() call on an element in that range is guaranteed not to block. diff --git a/include/linux/flex_array.h b/include/linux/flex_array.h index 70e4efa..ebeb2f3 100644 --- a/include/linux/flex_array.h +++ b/include/linux/flex_array.h @@ -61,7 +61,7 @@ struct flex_array { struct flex_array *flex_array_alloc(int element_size, unsigned int total, gfp_t flags); int flex_array_prealloc(struct flex_array *fa, unsigned int start, - unsigned int end, gfp_t flags); + unsigned int nr_elements, gfp_t flags); void flex_array_free(struct flex_array *fa); void flex_array_free_parts(struct flex_array *fa); int flex_array_put(struct flex_array *fa, unsigned int element_nr, void *src, diff --git a/lib/flex_array.c b/lib/flex_array.c index c0ea40b..0c33b24 100644 --- a/lib/flex_array.c +++ b/lib/flex_array.c @@ -232,10 +232,10 @@ EXPORT_SYMBOL(flex_array_clear); /** * flex_array_prealloc - guarantee that array space exists - * @fa: the flex array for which to preallocate parts - * @start: index of first array element for which space is allocated - * @end: index of last (inclusive) element for which space is allocated - * @flags: page allocation flags + * @fa: the flex array for which to preallocate parts + * @start: index of first array element for which space is allocated + * @nr_elements: number of elements for which space is allocated + * @flags: page allocation flags * * This will guarantee that no future calls to flex_array_put() * will allocate memory. It can be used if you are expecting to @@ -245,13 +245,16 @@ EXPORT_SYMBOL(flex_array_clear); * Locking must be provided by the caller. */ int flex_array_prealloc(struct flex_array *fa, unsigned int start, - unsigned int end, gfp_t flags) + unsigned int nr_elements, gfp_t flags) { int start_part; int end_part; int part_nr; + unsigned int end; struct flex_array_part *part; + end = start + nr_elements - 1; + if (start >= fa->total_nr_elements || end >= fa->total_nr_elements) return -ENOSPC; if (elements_fit_in_base(fa)) diff --git a/security/selinux/ss/policydb.c b/security/selinux/ss/policydb.c index e7b850a..e6e7ce0 100644 --- a/security/selinux/ss/policydb.c +++ b/security/selinux/ss/policydb.c @@ -502,7 +502,7 @@ static int policydb_index(struct policydb *p) goto out; rc = flex_array_prealloc(p->type_val_to_struct_array, 0, - p->p_types.nprim - 1, GFP_KERNEL | __GFP_ZERO); + p->p_types.nprim, GFP_KERNEL | __GFP_ZERO); if (rc) goto out; @@ -519,7 +519,7 @@ static int policydb_index(struct policydb *p) goto out; rc = flex_array_prealloc(p->sym_val_to_name[i], - 0, p->symtab[i].nprim - 1, + 0, p->symtab[i].nprim, GFP_KERNEL | __GFP_ZERO); if (rc) goto out; @@ -2375,7 +2375,7 @@ int policydb_read(struct policydb *p, void *fp) goto bad; /* preallocate so we don't have to worry about the put ever failing */ - rc = flex_array_prealloc(p->type_attr_map_array, 0, p->p_types.nprim - 1, + rc = flex_array_prealloc(p->type_attr_map_array, 0, p->p_types.nprim, GFP_KERNEL | __GFP_ZERO); if (rc) goto bad; -- cgit v0.10.2 From bf69d41d198138e3c601e9a6645f4f1369aff7e0 Mon Sep 17 00:00:00 2001 From: Eric Paris Date: Thu, 28 Apr 2011 15:55:52 -0400 Subject: flex_arrays: allow zero length flex arrays Just like kmalloc will allow one to allocate a 0 length segment of memory flex arrays should do the same thing. It should bomb if you try to use something, but it should at least allow the allocation. This is needed because when SELinux switched to using flex_arrays in 2.6.38 the inability to allocate a 0 length array resulted in SELinux policy load returning -ENOSPC when previously it worked. Based-on-patch-by: Steffen Klassert Signed-off-by: Eric Paris Tested-by: Chris Richards Cc: stable@kernel.org [2.6.38+] diff --git a/lib/flex_array.c b/lib/flex_array.c index 0c33b24..854b57b 100644 --- a/lib/flex_array.c +++ b/lib/flex_array.c @@ -253,9 +253,16 @@ int flex_array_prealloc(struct flex_array *fa, unsigned int start, unsigned int end; struct flex_array_part *part; + if (!start && !nr_elements) + return 0; + if (start >= fa->total_nr_elements) + return -ENOSPC; + if (!nr_elements) + return 0; + end = start + nr_elements - 1; - if (start >= fa->total_nr_elements || end >= fa->total_nr_elements) + if (end >= fa->total_nr_elements) return -ENOSPC; if (elements_fit_in_base(fa)) return 0; @@ -346,6 +353,8 @@ int flex_array_shrink(struct flex_array *fa) int part_nr; int ret = 0; + if (!fa->total_nr_elements) + return 0; if (elements_fit_in_base(fa)) return ret; for (part_nr = 0; part_nr < FLEX_ARRAY_NR_BASE_PTRS; part_nr++) { -- cgit v0.10.2 From f6d8bd051c391c1c0458a30b2a7abcd939329259 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Thu, 21 Apr 2011 09:45:37 +0000 Subject: inet: add RCU protection to inet->opt We lack proper synchronization to manipulate inet->opt ip_options Problem is ip_make_skb() calls ip_setup_cork() and ip_setup_cork() possibly makes a copy of ipc->opt (struct ip_options), without any protection against another thread manipulating inet->opt. Another thread can change inet->opt pointer and free old one under us. Use RCU to protect inet->opt (changed to inet->inet_opt). Instead of handling atomic refcounts, just copy ip_options when necessary, to avoid cache line dirtying. We cant insert an rcu_head in struct ip_options since its included in skb->cb[], so this patch is large because I had to introduce a new ip_options_rcu structure. Signed-off-by: Eric Dumazet Cc: Herbert Xu Signed-off-by: David S. Miller diff --git a/include/net/inet_sock.h b/include/net/inet_sock.h index 7a37369..ed2ba6e 100644 --- a/include/net/inet_sock.h +++ b/include/net/inet_sock.h @@ -57,7 +57,15 @@ struct ip_options { unsigned char __data[0]; }; -#define optlength(opt) (sizeof(struct ip_options) + opt->optlen) +struct ip_options_rcu { + struct rcu_head rcu; + struct ip_options opt; +}; + +struct ip_options_data { + struct ip_options_rcu opt; + char data[40]; +}; struct inet_request_sock { struct request_sock req; @@ -78,7 +86,7 @@ struct inet_request_sock { acked : 1, no_srccheck: 1; kmemcheck_bitfield_end(flags); - struct ip_options *opt; + struct ip_options_rcu *opt; }; static inline struct inet_request_sock *inet_rsk(const struct request_sock *sk) @@ -140,7 +148,7 @@ struct inet_sock { __be16 inet_sport; __u16 inet_id; - struct ip_options *opt; + struct ip_options_rcu __rcu *inet_opt; __u8 tos; __u8 min_ttl; __u8 mc_ttl; diff --git a/include/net/ip.h b/include/net/ip.h index 7c41658..3a59bf9 100644 --- a/include/net/ip.h +++ b/include/net/ip.h @@ -52,7 +52,7 @@ static inline unsigned int ip_hdrlen(const struct sk_buff *skb) struct ipcm_cookie { __be32 addr; int oif; - struct ip_options *opt; + struct ip_options_rcu *opt; __u8 tx_flags; }; @@ -92,7 +92,7 @@ extern int igmp_mc_proc_init(void); extern int ip_build_and_send_pkt(struct sk_buff *skb, struct sock *sk, __be32 saddr, __be32 daddr, - struct ip_options *opt); + struct ip_options_rcu *opt); extern int ip_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt, struct net_device *orig_dev); extern int ip_local_deliver(struct sk_buff *skb); @@ -416,14 +416,15 @@ extern int ip_forward(struct sk_buff *skb); * Functions provided by ip_options.c */ -extern void ip_options_build(struct sk_buff *skb, struct ip_options *opt, __be32 daddr, struct rtable *rt, int is_frag); +extern void ip_options_build(struct sk_buff *skb, struct ip_options *opt, + __be32 daddr, struct rtable *rt, int is_frag); extern int ip_options_echo(struct ip_options *dopt, struct sk_buff *skb); extern void ip_options_fragment(struct sk_buff *skb); extern int ip_options_compile(struct net *net, struct ip_options *opt, struct sk_buff *skb); -extern int ip_options_get(struct net *net, struct ip_options **optp, +extern int ip_options_get(struct net *net, struct ip_options_rcu **optp, unsigned char *data, int optlen); -extern int ip_options_get_from_user(struct net *net, struct ip_options **optp, +extern int ip_options_get_from_user(struct net *net, struct ip_options_rcu **optp, unsigned char __user *data, int optlen); extern void ip_options_undo(struct ip_options * opt); extern void ip_forward_options(struct sk_buff *skb); diff --git a/net/dccp/ipv4.c b/net/dccp/ipv4.c index b92ab65..cbbcc6c 100644 --- a/net/dccp/ipv4.c +++ b/net/dccp/ipv4.c @@ -48,6 +48,7 @@ int dccp_v4_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len) struct flowi4 fl4; struct rtable *rt; int err; + struct ip_options_rcu *inet_opt; dp->dccps_role = DCCP_ROLE_CLIENT; @@ -58,10 +59,13 @@ int dccp_v4_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len) return -EAFNOSUPPORT; nexthop = daddr = usin->sin_addr.s_addr; - if (inet->opt != NULL && inet->opt->srr) { + + inet_opt = rcu_dereference_protected(inet->inet_opt, + sock_owned_by_user(sk)); + if (inet_opt != NULL && inet_opt->opt.srr) { if (daddr == 0) return -EINVAL; - nexthop = inet->opt->faddr; + nexthop = inet_opt->opt.faddr; } orig_sport = inet->inet_sport; @@ -78,7 +82,7 @@ int dccp_v4_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len) return -ENETUNREACH; } - if (inet->opt == NULL || !inet->opt->srr) + if (inet_opt == NULL || !inet_opt->opt.srr) daddr = rt->rt_dst; if (inet->inet_saddr == 0) @@ -89,8 +93,8 @@ int dccp_v4_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len) inet->inet_daddr = daddr; inet_csk(sk)->icsk_ext_hdr_len = 0; - if (inet->opt != NULL) - inet_csk(sk)->icsk_ext_hdr_len = inet->opt->optlen; + if (inet_opt) + inet_csk(sk)->icsk_ext_hdr_len = inet_opt->opt.optlen; /* * Socket identity is still unknown (sport may be zero). * However we set state to DCCP_REQUESTING and not releasing socket @@ -405,7 +409,7 @@ struct sock *dccp_v4_request_recv_sock(struct sock *sk, struct sk_buff *skb, newinet->inet_daddr = ireq->rmt_addr; newinet->inet_rcv_saddr = ireq->loc_addr; newinet->inet_saddr = ireq->loc_addr; - newinet->opt = ireq->opt; + newinet->inet_opt = ireq->opt; ireq->opt = NULL; newinet->mc_index = inet_iif(skb); newinet->mc_ttl = ip_hdr(skb)->ttl; diff --git a/net/dccp/ipv6.c b/net/dccp/ipv6.c index 73add23..8dc4348 100644 --- a/net/dccp/ipv6.c +++ b/net/dccp/ipv6.c @@ -573,7 +573,7 @@ static struct sock *dccp_v6_request_recv_sock(struct sock *sk, First: no IPv4 options. */ - newinet->opt = NULL; + newinet->inet_opt = NULL; /* Clone RX bits */ newnp->rxopt.all = np->rxopt.all; diff --git a/net/ipv4/af_inet.c b/net/ipv4/af_inet.c index 0413af3..963a621 100644 --- a/net/ipv4/af_inet.c +++ b/net/ipv4/af_inet.c @@ -153,7 +153,7 @@ void inet_sock_destruct(struct sock *sk) WARN_ON(sk->sk_wmem_queued); WARN_ON(sk->sk_forward_alloc); - kfree(inet->opt); + kfree(rcu_dereference_protected(inet->inet_opt, 1)); dst_release(rcu_dereference_check(sk->sk_dst_cache, 1)); sk_refcnt_debug_dec(sk); } @@ -1106,9 +1106,12 @@ static int inet_sk_reselect_saddr(struct sock *sk) struct flowi4 fl4; struct rtable *rt; __be32 new_saddr; + struct ip_options_rcu *inet_opt; - if (inet->opt && inet->opt->srr) - daddr = inet->opt->faddr; + inet_opt = rcu_dereference_protected(inet->inet_opt, + sock_owned_by_user(sk)); + if (inet_opt && inet_opt->opt.srr) + daddr = inet_opt->opt.faddr; /* Query new route. */ rt = ip_route_connect(&fl4, daddr, 0, RT_CONN_FLAGS(sk), @@ -1148,6 +1151,7 @@ int inet_sk_rebuild_header(struct sock *sk) struct inet_sock *inet = inet_sk(sk); struct rtable *rt = (struct rtable *)__sk_dst_check(sk, 0); __be32 daddr; + struct ip_options_rcu *inet_opt; int err; /* Route is OK, nothing to do. */ @@ -1155,9 +1159,12 @@ int inet_sk_rebuild_header(struct sock *sk) return 0; /* Reroute. */ + rcu_read_lock(); + inet_opt = rcu_dereference(inet->inet_opt); daddr = inet->inet_daddr; - if (inet->opt && inet->opt->srr) - daddr = inet->opt->faddr; + if (inet_opt && inet_opt->opt.srr) + daddr = inet_opt->opt.faddr; + rcu_read_unlock(); rt = ip_route_output_ports(sock_net(sk), sk, daddr, inet->inet_saddr, inet->inet_dport, inet->inet_sport, sk->sk_protocol, RT_CONN_FLAGS(sk), diff --git a/net/ipv4/cipso_ipv4.c b/net/ipv4/cipso_ipv4.c index a0af7ea..2b3c23c 100644 --- a/net/ipv4/cipso_ipv4.c +++ b/net/ipv4/cipso_ipv4.c @@ -1857,6 +1857,11 @@ static int cipso_v4_genopt(unsigned char *buf, u32 buf_len, return CIPSO_V4_HDR_LEN + ret_val; } +static void opt_kfree_rcu(struct rcu_head *head) +{ + kfree(container_of(head, struct ip_options_rcu, rcu)); +} + /** * cipso_v4_sock_setattr - Add a CIPSO option to a socket * @sk: the socket @@ -1879,7 +1884,7 @@ int cipso_v4_sock_setattr(struct sock *sk, unsigned char *buf = NULL; u32 buf_len; u32 opt_len; - struct ip_options *opt = NULL; + struct ip_options_rcu *old, *opt = NULL; struct inet_sock *sk_inet; struct inet_connection_sock *sk_conn; @@ -1915,22 +1920,25 @@ int cipso_v4_sock_setattr(struct sock *sk, ret_val = -ENOMEM; goto socket_setattr_failure; } - memcpy(opt->__data, buf, buf_len); - opt->optlen = opt_len; - opt->cipso = sizeof(struct iphdr); + memcpy(opt->opt.__data, buf, buf_len); + opt->opt.optlen = opt_len; + opt->opt.cipso = sizeof(struct iphdr); kfree(buf); buf = NULL; sk_inet = inet_sk(sk); + + old = rcu_dereference_protected(sk_inet->inet_opt, sock_owned_by_user(sk)); if (sk_inet->is_icsk) { sk_conn = inet_csk(sk); - if (sk_inet->opt) - sk_conn->icsk_ext_hdr_len -= sk_inet->opt->optlen; - sk_conn->icsk_ext_hdr_len += opt->optlen; + if (old) + sk_conn->icsk_ext_hdr_len -= old->opt.optlen; + sk_conn->icsk_ext_hdr_len += opt->opt.optlen; sk_conn->icsk_sync_mss(sk, sk_conn->icsk_pmtu_cookie); } - opt = xchg(&sk_inet->opt, opt); - kfree(opt); + rcu_assign_pointer(sk_inet->inet_opt, opt); + if (old) + call_rcu(&old->rcu, opt_kfree_rcu); return 0; @@ -1960,7 +1968,7 @@ int cipso_v4_req_setattr(struct request_sock *req, unsigned char *buf = NULL; u32 buf_len; u32 opt_len; - struct ip_options *opt = NULL; + struct ip_options_rcu *opt = NULL; struct inet_request_sock *req_inet; /* We allocate the maximum CIPSO option size here so we are probably @@ -1988,15 +1996,16 @@ int cipso_v4_req_setattr(struct request_sock *req, ret_val = -ENOMEM; goto req_setattr_failure; } - memcpy(opt->__data, buf, buf_len); - opt->optlen = opt_len; - opt->cipso = sizeof(struct iphdr); + memcpy(opt->opt.__data, buf, buf_len); + opt->opt.optlen = opt_len; + opt->opt.cipso = sizeof(struct iphdr); kfree(buf); buf = NULL; req_inet = inet_rsk(req); opt = xchg(&req_inet->opt, opt); - kfree(opt); + if (opt) + call_rcu(&opt->rcu, opt_kfree_rcu); return 0; @@ -2016,34 +2025,34 @@ req_setattr_failure: * values on failure. * */ -static int cipso_v4_delopt(struct ip_options **opt_ptr) +static int cipso_v4_delopt(struct ip_options_rcu **opt_ptr) { int hdr_delta = 0; - struct ip_options *opt = *opt_ptr; + struct ip_options_rcu *opt = *opt_ptr; - if (opt->srr || opt->rr || opt->ts || opt->router_alert) { + if (opt->opt.srr || opt->opt.rr || opt->opt.ts || opt->opt.router_alert) { u8 cipso_len; u8 cipso_off; unsigned char *cipso_ptr; int iter; int optlen_new; - cipso_off = opt->cipso - sizeof(struct iphdr); - cipso_ptr = &opt->__data[cipso_off]; + cipso_off = opt->opt.cipso - sizeof(struct iphdr); + cipso_ptr = &opt->opt.__data[cipso_off]; cipso_len = cipso_ptr[1]; - if (opt->srr > opt->cipso) - opt->srr -= cipso_len; - if (opt->rr > opt->cipso) - opt->rr -= cipso_len; - if (opt->ts > opt->cipso) - opt->ts -= cipso_len; - if (opt->router_alert > opt->cipso) - opt->router_alert -= cipso_len; - opt->cipso = 0; + if (opt->opt.srr > opt->opt.cipso) + opt->opt.srr -= cipso_len; + if (opt->opt.rr > opt->opt.cipso) + opt->opt.rr -= cipso_len; + if (opt->opt.ts > opt->opt.cipso) + opt->opt.ts -= cipso_len; + if (opt->opt.router_alert > opt->opt.cipso) + opt->opt.router_alert -= cipso_len; + opt->opt.cipso = 0; memmove(cipso_ptr, cipso_ptr + cipso_len, - opt->optlen - cipso_off - cipso_len); + opt->opt.optlen - cipso_off - cipso_len); /* determining the new total option length is tricky because of * the padding necessary, the only thing i can think to do at @@ -2052,21 +2061,21 @@ static int cipso_v4_delopt(struct ip_options **opt_ptr) * from there we can determine the new total option length */ iter = 0; optlen_new = 0; - while (iter < opt->optlen) - if (opt->__data[iter] != IPOPT_NOP) { - iter += opt->__data[iter + 1]; + while (iter < opt->opt.optlen) + if (opt->opt.__data[iter] != IPOPT_NOP) { + iter += opt->opt.__data[iter + 1]; optlen_new = iter; } else iter++; - hdr_delta = opt->optlen; - opt->optlen = (optlen_new + 3) & ~3; - hdr_delta -= opt->optlen; + hdr_delta = opt->opt.optlen; + opt->opt.optlen = (optlen_new + 3) & ~3; + hdr_delta -= opt->opt.optlen; } else { /* only the cipso option was present on the socket so we can * remove the entire option struct */ *opt_ptr = NULL; - hdr_delta = opt->optlen; - kfree(opt); + hdr_delta = opt->opt.optlen; + call_rcu(&opt->rcu, opt_kfree_rcu); } return hdr_delta; @@ -2083,15 +2092,15 @@ static int cipso_v4_delopt(struct ip_options **opt_ptr) void cipso_v4_sock_delattr(struct sock *sk) { int hdr_delta; - struct ip_options *opt; + struct ip_options_rcu *opt; struct inet_sock *sk_inet; sk_inet = inet_sk(sk); - opt = sk_inet->opt; - if (opt == NULL || opt->cipso == 0) + opt = rcu_dereference_protected(sk_inet->inet_opt, 1); + if (opt == NULL || opt->opt.cipso == 0) return; - hdr_delta = cipso_v4_delopt(&sk_inet->opt); + hdr_delta = cipso_v4_delopt(&sk_inet->inet_opt); if (sk_inet->is_icsk && hdr_delta > 0) { struct inet_connection_sock *sk_conn = inet_csk(sk); sk_conn->icsk_ext_hdr_len -= hdr_delta; @@ -2109,12 +2118,12 @@ void cipso_v4_sock_delattr(struct sock *sk) */ void cipso_v4_req_delattr(struct request_sock *req) { - struct ip_options *opt; + struct ip_options_rcu *opt; struct inet_request_sock *req_inet; req_inet = inet_rsk(req); opt = req_inet->opt; - if (opt == NULL || opt->cipso == 0) + if (opt == NULL || opt->opt.cipso == 0) return; cipso_v4_delopt(&req_inet->opt); @@ -2184,14 +2193,18 @@ getattr_return: */ int cipso_v4_sock_getattr(struct sock *sk, struct netlbl_lsm_secattr *secattr) { - struct ip_options *opt; + struct ip_options_rcu *opt; + int res = -ENOMSG; - opt = inet_sk(sk)->opt; - if (opt == NULL || opt->cipso == 0) - return -ENOMSG; - - return cipso_v4_getattr(opt->__data + opt->cipso - sizeof(struct iphdr), - secattr); + rcu_read_lock(); + opt = rcu_dereference(inet_sk(sk)->inet_opt); + if (opt && opt->opt.cipso) + res = cipso_v4_getattr(opt->opt.__data + + opt->opt.cipso - + sizeof(struct iphdr), + secattr); + rcu_read_unlock(); + return res; } /** diff --git a/net/ipv4/icmp.c b/net/ipv4/icmp.c index 74e35e5..cfeca3c 100644 --- a/net/ipv4/icmp.c +++ b/net/ipv4/icmp.c @@ -108,8 +108,7 @@ struct icmp_bxm { __be32 times[3]; } data; int head_len; - struct ip_options replyopts; - unsigned char optbuf[40]; + struct ip_options_data replyopts; }; /* An array of errno for error messages from dest unreach. */ @@ -333,7 +332,7 @@ static void icmp_reply(struct icmp_bxm *icmp_param, struct sk_buff *skb) struct inet_sock *inet; __be32 daddr; - if (ip_options_echo(&icmp_param->replyopts, skb)) + if (ip_options_echo(&icmp_param->replyopts.opt.opt, skb)) return; sk = icmp_xmit_lock(net); @@ -347,10 +346,10 @@ static void icmp_reply(struct icmp_bxm *icmp_param, struct sk_buff *skb) daddr = ipc.addr = rt->rt_src; ipc.opt = NULL; ipc.tx_flags = 0; - if (icmp_param->replyopts.optlen) { - ipc.opt = &icmp_param->replyopts; - if (ipc.opt->srr) - daddr = icmp_param->replyopts.faddr; + if (icmp_param->replyopts.opt.opt.optlen) { + ipc.opt = &icmp_param->replyopts.opt; + if (ipc.opt->opt.srr) + daddr = icmp_param->replyopts.opt.opt.faddr; } { struct flowi4 fl4 = { @@ -379,8 +378,8 @@ static struct rtable *icmp_route_lookup(struct net *net, struct sk_buff *skb_in, struct icmp_bxm *param) { struct flowi4 fl4 = { - .daddr = (param->replyopts.srr ? - param->replyopts.faddr : iph->saddr), + .daddr = (param->replyopts.opt.opt.srr ? + param->replyopts.opt.opt.faddr : iph->saddr), .saddr = saddr, .flowi4_tos = RT_TOS(tos), .flowi4_proto = IPPROTO_ICMP, @@ -581,7 +580,7 @@ void icmp_send(struct sk_buff *skb_in, int type, int code, __be32 info) IPTOS_PREC_INTERNETCONTROL) : iph->tos; - if (ip_options_echo(&icmp_param.replyopts, skb_in)) + if (ip_options_echo(&icmp_param.replyopts.opt.opt, skb_in)) goto out_unlock; @@ -597,7 +596,7 @@ void icmp_send(struct sk_buff *skb_in, int type, int code, __be32 info) icmp_param.offset = skb_network_offset(skb_in); inet_sk(sk)->tos = tos; ipc.addr = iph->saddr; - ipc.opt = &icmp_param.replyopts; + ipc.opt = &icmp_param.replyopts.opt; ipc.tx_flags = 0; rt = icmp_route_lookup(net, skb_in, iph, saddr, tos, @@ -613,7 +612,7 @@ void icmp_send(struct sk_buff *skb_in, int type, int code, __be32 info) room = dst_mtu(&rt->dst); if (room > 576) room = 576; - room -= sizeof(struct iphdr) + icmp_param.replyopts.optlen; + room -= sizeof(struct iphdr) + icmp_param.replyopts.opt.opt.optlen; room -= sizeof(struct icmphdr); icmp_param.data_len = skb_in->len - icmp_param.offset; diff --git a/net/ipv4/inet_connection_sock.c b/net/ipv4/inet_connection_sock.c index 8514db5..3282cb2 100644 --- a/net/ipv4/inet_connection_sock.c +++ b/net/ipv4/inet_connection_sock.c @@ -354,20 +354,20 @@ struct dst_entry *inet_csk_route_req(struct sock *sk, { struct rtable *rt; const struct inet_request_sock *ireq = inet_rsk(req); - struct ip_options *opt = inet_rsk(req)->opt; + struct ip_options_rcu *opt = inet_rsk(req)->opt; struct net *net = sock_net(sk); struct flowi4 fl4; flowi4_init_output(&fl4, sk->sk_bound_dev_if, sk->sk_mark, RT_CONN_FLAGS(sk), RT_SCOPE_UNIVERSE, sk->sk_protocol, inet_sk_flowi_flags(sk), - (opt && opt->srr) ? opt->faddr : ireq->rmt_addr, + (opt && opt->opt.srr) ? opt->opt.faddr : ireq->rmt_addr, ireq->loc_addr, ireq->rmt_port, inet_sk(sk)->inet_sport); security_req_classify_flow(req, flowi4_to_flowi(&fl4)); rt = ip_route_output_flow(net, &fl4, sk); if (IS_ERR(rt)) goto no_route; - if (opt && opt->is_strictroute && rt->rt_dst != rt->rt_gateway) + if (opt && opt->opt.is_strictroute && rt->rt_dst != rt->rt_gateway) goto route_err; return &rt->dst; diff --git a/net/ipv4/ip_options.c b/net/ipv4/ip_options.c index 2391b24..01fc409 100644 --- a/net/ipv4/ip_options.c +++ b/net/ipv4/ip_options.c @@ -36,7 +36,7 @@ * saddr is address of outgoing interface. */ -void ip_options_build(struct sk_buff * skb, struct ip_options * opt, +void ip_options_build(struct sk_buff *skb, struct ip_options *opt, __be32 daddr, struct rtable *rt, int is_frag) { unsigned char *iph = skb_network_header(skb); @@ -83,9 +83,9 @@ void ip_options_build(struct sk_buff * skb, struct ip_options * opt, * NOTE: dopt cannot point to skb. */ -int ip_options_echo(struct ip_options * dopt, struct sk_buff * skb) +int ip_options_echo(struct ip_options *dopt, struct sk_buff *skb) { - struct ip_options *sopt; + const struct ip_options *sopt; unsigned char *sptr, *dptr; int soffset, doffset; int optlen; @@ -95,10 +95,8 @@ int ip_options_echo(struct ip_options * dopt, struct sk_buff * skb) sopt = &(IPCB(skb)->opt); - if (sopt->optlen == 0) { - dopt->optlen = 0; + if (sopt->optlen == 0) return 0; - } sptr = skb_network_header(skb); dptr = dopt->__data; @@ -157,7 +155,7 @@ int ip_options_echo(struct ip_options * dopt, struct sk_buff * skb) dopt->optlen += optlen; } if (sopt->srr) { - unsigned char * start = sptr+sopt->srr; + unsigned char *start = sptr+sopt->srr; __be32 faddr; optlen = start[1]; @@ -499,19 +497,19 @@ void ip_options_undo(struct ip_options * opt) } } -static struct ip_options *ip_options_get_alloc(const int optlen) +static struct ip_options_rcu *ip_options_get_alloc(const int optlen) { - return kzalloc(sizeof(struct ip_options) + ((optlen + 3) & ~3), + return kzalloc(sizeof(struct ip_options_rcu) + ((optlen + 3) & ~3), GFP_KERNEL); } -static int ip_options_get_finish(struct net *net, struct ip_options **optp, - struct ip_options *opt, int optlen) +static int ip_options_get_finish(struct net *net, struct ip_options_rcu **optp, + struct ip_options_rcu *opt, int optlen) { while (optlen & 3) - opt->__data[optlen++] = IPOPT_END; - opt->optlen = optlen; - if (optlen && ip_options_compile(net, opt, NULL)) { + opt->opt.__data[optlen++] = IPOPT_END; + opt->opt.optlen = optlen; + if (optlen && ip_options_compile(net, &opt->opt, NULL)) { kfree(opt); return -EINVAL; } @@ -520,29 +518,29 @@ static int ip_options_get_finish(struct net *net, struct ip_options **optp, return 0; } -int ip_options_get_from_user(struct net *net, struct ip_options **optp, +int ip_options_get_from_user(struct net *net, struct ip_options_rcu **optp, unsigned char __user *data, int optlen) { - struct ip_options *opt = ip_options_get_alloc(optlen); + struct ip_options_rcu *opt = ip_options_get_alloc(optlen); if (!opt) return -ENOMEM; - if (optlen && copy_from_user(opt->__data, data, optlen)) { + if (optlen && copy_from_user(opt->opt.__data, data, optlen)) { kfree(opt); return -EFAULT; } return ip_options_get_finish(net, optp, opt, optlen); } -int ip_options_get(struct net *net, struct ip_options **optp, +int ip_options_get(struct net *net, struct ip_options_rcu **optp, unsigned char *data, int optlen) { - struct ip_options *opt = ip_options_get_alloc(optlen); + struct ip_options_rcu *opt = ip_options_get_alloc(optlen); if (!opt) return -ENOMEM; if (optlen) - memcpy(opt->__data, data, optlen); + memcpy(opt->opt.__data, data, optlen); return ip_options_get_finish(net, optp, opt, optlen); } diff --git a/net/ipv4/ip_output.c b/net/ipv4/ip_output.c index bdad3d6..362e66f 100644 --- a/net/ipv4/ip_output.c +++ b/net/ipv4/ip_output.c @@ -140,14 +140,14 @@ static inline int ip_select_ttl(struct inet_sock *inet, struct dst_entry *dst) * */ int ip_build_and_send_pkt(struct sk_buff *skb, struct sock *sk, - __be32 saddr, __be32 daddr, struct ip_options *opt) + __be32 saddr, __be32 daddr, struct ip_options_rcu *opt) { struct inet_sock *inet = inet_sk(sk); struct rtable *rt = skb_rtable(skb); struct iphdr *iph; /* Build the IP header. */ - skb_push(skb, sizeof(struct iphdr) + (opt ? opt->optlen : 0)); + skb_push(skb, sizeof(struct iphdr) + (opt ? opt->opt.optlen : 0)); skb_reset_network_header(skb); iph = ip_hdr(skb); iph->version = 4; @@ -163,9 +163,9 @@ int ip_build_and_send_pkt(struct sk_buff *skb, struct sock *sk, iph->protocol = sk->sk_protocol; ip_select_ident(iph, &rt->dst, sk); - if (opt && opt->optlen) { - iph->ihl += opt->optlen>>2; - ip_options_build(skb, opt, daddr, rt, 0); + if (opt && opt->opt.optlen) { + iph->ihl += opt->opt.optlen>>2; + ip_options_build(skb, &opt->opt, daddr, rt, 0); } skb->priority = sk->sk_priority; @@ -316,7 +316,7 @@ int ip_queue_xmit(struct sk_buff *skb) { struct sock *sk = skb->sk; struct inet_sock *inet = inet_sk(sk); - struct ip_options *opt = inet->opt; + struct ip_options_rcu *inet_opt; struct rtable *rt; struct iphdr *iph; int res; @@ -325,6 +325,7 @@ int ip_queue_xmit(struct sk_buff *skb) * f.e. by something like SCTP. */ rcu_read_lock(); + inet_opt = rcu_dereference(inet->inet_opt); rt = skb_rtable(skb); if (rt != NULL) goto packet_routed; @@ -336,8 +337,8 @@ int ip_queue_xmit(struct sk_buff *skb) /* Use correct destination address if we have options. */ daddr = inet->inet_daddr; - if(opt && opt->srr) - daddr = opt->faddr; + if (inet_opt && inet_opt->opt.srr) + daddr = inet_opt->opt.faddr; /* If this fails, retransmit mechanism of transport layer will * keep trying until route appears or the connection times @@ -357,11 +358,11 @@ int ip_queue_xmit(struct sk_buff *skb) skb_dst_set_noref(skb, &rt->dst); packet_routed: - if (opt && opt->is_strictroute && rt->rt_dst != rt->rt_gateway) + if (inet_opt && inet_opt->opt.is_strictroute && rt->rt_dst != rt->rt_gateway) goto no_route; /* OK, we know where to send it, allocate and build IP header. */ - skb_push(skb, sizeof(struct iphdr) + (opt ? opt->optlen : 0)); + skb_push(skb, sizeof(struct iphdr) + (inet_opt ? inet_opt->opt.optlen : 0)); skb_reset_network_header(skb); iph = ip_hdr(skb); *((__be16 *)iph) = htons((4 << 12) | (5 << 8) | (inet->tos & 0xff)); @@ -375,9 +376,9 @@ packet_routed: iph->daddr = rt->rt_dst; /* Transport layer set skb->h.foo itself. */ - if (opt && opt->optlen) { - iph->ihl += opt->optlen >> 2; - ip_options_build(skb, opt, inet->inet_daddr, rt, 0); + if (inet_opt && inet_opt->opt.optlen) { + iph->ihl += inet_opt->opt.optlen >> 2; + ip_options_build(skb, &inet_opt->opt, inet->inet_daddr, rt, 0); } ip_select_ident_more(iph, &rt->dst, sk, @@ -1033,7 +1034,7 @@ static int ip_setup_cork(struct sock *sk, struct inet_cork *cork, struct ipcm_cookie *ipc, struct rtable **rtp) { struct inet_sock *inet = inet_sk(sk); - struct ip_options *opt; + struct ip_options_rcu *opt; struct rtable *rt; /* @@ -1047,7 +1048,7 @@ static int ip_setup_cork(struct sock *sk, struct inet_cork *cork, if (unlikely(cork->opt == NULL)) return -ENOBUFS; } - memcpy(cork->opt, opt, sizeof(struct ip_options) + opt->optlen); + memcpy(cork->opt, &opt->opt, sizeof(struct ip_options) + opt->opt.optlen); cork->flags |= IPCORK_OPT; cork->addr = ipc->addr; } @@ -1451,26 +1452,23 @@ void ip_send_reply(struct sock *sk, struct sk_buff *skb, struct ip_reply_arg *ar unsigned int len) { struct inet_sock *inet = inet_sk(sk); - struct { - struct ip_options opt; - char data[40]; - } replyopts; + struct ip_options_data replyopts; struct ipcm_cookie ipc; __be32 daddr; struct rtable *rt = skb_rtable(skb); - if (ip_options_echo(&replyopts.opt, skb)) + if (ip_options_echo(&replyopts.opt.opt, skb)) return; daddr = ipc.addr = rt->rt_src; ipc.opt = NULL; ipc.tx_flags = 0; - if (replyopts.opt.optlen) { + if (replyopts.opt.opt.optlen) { ipc.opt = &replyopts.opt; - if (ipc.opt->srr) - daddr = replyopts.opt.faddr; + if (replyopts.opt.opt.srr) + daddr = replyopts.opt.opt.faddr; } { diff --git a/net/ipv4/ip_sockglue.c b/net/ipv4/ip_sockglue.c index 9640900..ab0c9ef 100644 --- a/net/ipv4/ip_sockglue.c +++ b/net/ipv4/ip_sockglue.c @@ -451,6 +451,11 @@ out: } +static void opt_kfree_rcu(struct rcu_head *head) +{ + kfree(container_of(head, struct ip_options_rcu, rcu)); +} + /* * Socket option code for IP. This is the end of the line after any * TCP,UDP etc options on an IP socket. @@ -497,13 +502,16 @@ static int do_ip_setsockopt(struct sock *sk, int level, switch (optname) { case IP_OPTIONS: { - struct ip_options *opt = NULL; + struct ip_options_rcu *old, *opt = NULL; + if (optlen > 40) goto e_inval; err = ip_options_get_from_user(sock_net(sk), &opt, optval, optlen); if (err) break; + old = rcu_dereference_protected(inet->inet_opt, + sock_owned_by_user(sk)); if (inet->is_icsk) { struct inet_connection_sock *icsk = inet_csk(sk); #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) @@ -512,17 +520,18 @@ static int do_ip_setsockopt(struct sock *sk, int level, (TCPF_LISTEN | TCPF_CLOSE)) && inet->inet_daddr != LOOPBACK4_IPV6)) { #endif - if (inet->opt) - icsk->icsk_ext_hdr_len -= inet->opt->optlen; + if (old) + icsk->icsk_ext_hdr_len -= old->opt.optlen; if (opt) - icsk->icsk_ext_hdr_len += opt->optlen; + icsk->icsk_ext_hdr_len += opt->opt.optlen; icsk->icsk_sync_mss(sk, icsk->icsk_pmtu_cookie); #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) } #endif } - opt = xchg(&inet->opt, opt); - kfree(opt); + rcu_assign_pointer(inet->inet_opt, opt); + if (old) + call_rcu(&old->rcu, opt_kfree_rcu); break; } case IP_PKTINFO: @@ -1081,12 +1090,16 @@ static int do_ip_getsockopt(struct sock *sk, int level, int optname, case IP_OPTIONS: { unsigned char optbuf[sizeof(struct ip_options)+40]; - struct ip_options * opt = (struct ip_options *)optbuf; + struct ip_options *opt = (struct ip_options *)optbuf; + struct ip_options_rcu *inet_opt; + + inet_opt = rcu_dereference_protected(inet->inet_opt, + sock_owned_by_user(sk)); opt->optlen = 0; - if (inet->opt) - memcpy(optbuf, inet->opt, - sizeof(struct ip_options)+ - inet->opt->optlen); + if (inet_opt) + memcpy(optbuf, &inet_opt->opt, + sizeof(struct ip_options) + + inet_opt->opt.optlen); release_sock(sk); if (opt->optlen == 0) diff --git a/net/ipv4/raw.c b/net/ipv4/raw.c index abf14db..a8659e0 100644 --- a/net/ipv4/raw.c +++ b/net/ipv4/raw.c @@ -460,6 +460,7 @@ static int raw_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, __be32 saddr; u8 tos; int err; + struct ip_options_data opt_copy; err = -EMSGSIZE; if (len > 0xFFFF) @@ -520,8 +521,18 @@ static int raw_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, saddr = ipc.addr; ipc.addr = daddr; - if (!ipc.opt) - ipc.opt = inet->opt; + if (!ipc.opt) { + struct ip_options_rcu *inet_opt; + + rcu_read_lock(); + inet_opt = rcu_dereference(inet->inet_opt); + if (inet_opt) { + memcpy(&opt_copy, inet_opt, + sizeof(*inet_opt) + inet_opt->opt.optlen); + ipc.opt = &opt_copy.opt; + } + rcu_read_unlock(); + } if (ipc.opt) { err = -EINVAL; @@ -530,10 +541,10 @@ static int raw_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, */ if (inet->hdrincl) goto done; - if (ipc.opt->srr) { + if (ipc.opt->opt.srr) { if (!daddr) goto done; - daddr = ipc.opt->faddr; + daddr = ipc.opt->opt.faddr; } } tos = RT_CONN_FLAGS(sk); diff --git a/net/ipv4/syncookies.c b/net/ipv4/syncookies.c index 71e0296..2646149 100644 --- a/net/ipv4/syncookies.c +++ b/net/ipv4/syncookies.c @@ -321,10 +321,10 @@ struct sock *cookie_v4_check(struct sock *sk, struct sk_buff *skb, * the ACK carries the same options again (see RFC1122 4.2.3.8) */ if (opt && opt->optlen) { - int opt_size = sizeof(struct ip_options) + opt->optlen; + int opt_size = sizeof(struct ip_options_rcu) + opt->optlen; ireq->opt = kmalloc(opt_size, GFP_ATOMIC); - if (ireq->opt != NULL && ip_options_echo(ireq->opt, skb)) { + if (ireq->opt != NULL && ip_options_echo(&ireq->opt->opt, skb)) { kfree(ireq->opt); ireq->opt = NULL; } diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c index 310454c..d60732f 100644 --- a/net/ipv4/tcp_ipv4.c +++ b/net/ipv4/tcp_ipv4.c @@ -154,6 +154,7 @@ int tcp_v4_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len) struct flowi4 fl4; struct rtable *rt; int err; + struct ip_options_rcu *inet_opt; if (addr_len < sizeof(struct sockaddr_in)) return -EINVAL; @@ -162,10 +163,12 @@ int tcp_v4_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len) return -EAFNOSUPPORT; nexthop = daddr = usin->sin_addr.s_addr; - if (inet->opt && inet->opt->srr) { + inet_opt = rcu_dereference_protected(inet->inet_opt, + sock_owned_by_user(sk)); + if (inet_opt && inet_opt->opt.srr) { if (!daddr) return -EINVAL; - nexthop = inet->opt->faddr; + nexthop = inet_opt->opt.faddr; } orig_sport = inet->inet_sport; @@ -186,7 +189,7 @@ int tcp_v4_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len) return -ENETUNREACH; } - if (!inet->opt || !inet->opt->srr) + if (!inet_opt || !inet_opt->opt.srr) daddr = rt->rt_dst; if (!inet->inet_saddr) @@ -222,8 +225,8 @@ int tcp_v4_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len) inet->inet_daddr = daddr; inet_csk(sk)->icsk_ext_hdr_len = 0; - if (inet->opt) - inet_csk(sk)->icsk_ext_hdr_len = inet->opt->optlen; + if (inet_opt) + inet_csk(sk)->icsk_ext_hdr_len = inet_opt->opt.optlen; tp->rx_opt.mss_clamp = TCP_MSS_DEFAULT; @@ -820,17 +823,18 @@ static void syn_flood_warning(const struct sk_buff *skb) /* * Save and compile IPv4 options into the request_sock if needed. */ -static struct ip_options *tcp_v4_save_options(struct sock *sk, - struct sk_buff *skb) +static struct ip_options_rcu *tcp_v4_save_options(struct sock *sk, + struct sk_buff *skb) { - struct ip_options *opt = &(IPCB(skb)->opt); - struct ip_options *dopt = NULL; + const struct ip_options *opt = &(IPCB(skb)->opt); + struct ip_options_rcu *dopt = NULL; if (opt && opt->optlen) { - int opt_size = optlength(opt); + int opt_size = sizeof(*dopt) + opt->optlen; + dopt = kmalloc(opt_size, GFP_ATOMIC); if (dopt) { - if (ip_options_echo(dopt, skb)) { + if (ip_options_echo(&dopt->opt, skb)) { kfree(dopt); dopt = NULL; } @@ -1411,6 +1415,7 @@ struct sock *tcp_v4_syn_recv_sock(struct sock *sk, struct sk_buff *skb, #ifdef CONFIG_TCP_MD5SIG struct tcp_md5sig_key *key; #endif + struct ip_options_rcu *inet_opt; if (sk_acceptq_is_full(sk)) goto exit_overflow; @@ -1431,13 +1436,14 @@ struct sock *tcp_v4_syn_recv_sock(struct sock *sk, struct sk_buff *skb, newinet->inet_daddr = ireq->rmt_addr; newinet->inet_rcv_saddr = ireq->loc_addr; newinet->inet_saddr = ireq->loc_addr; - newinet->opt = ireq->opt; + inet_opt = ireq->opt; + rcu_assign_pointer(newinet->inet_opt, inet_opt); ireq->opt = NULL; newinet->mc_index = inet_iif(skb); newinet->mc_ttl = ip_hdr(skb)->ttl; inet_csk(newsk)->icsk_ext_hdr_len = 0; - if (newinet->opt) - inet_csk(newsk)->icsk_ext_hdr_len = newinet->opt->optlen; + if (inet_opt) + inet_csk(newsk)->icsk_ext_hdr_len = inet_opt->opt.optlen; newinet->inet_id = newtp->write_seq ^ jiffies; tcp_mtup_init(newsk); diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c index bc0dab2..544f435 100644 --- a/net/ipv4/udp.c +++ b/net/ipv4/udp.c @@ -804,6 +804,7 @@ int udp_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, int corkreq = up->corkflag || msg->msg_flags&MSG_MORE; int (*getfrag)(void *, char *, int, int, int, struct sk_buff *); struct sk_buff *skb; + struct ip_options_data opt_copy; if (len > 0xFFFF) return -EMSGSIZE; @@ -877,22 +878,32 @@ int udp_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, free = 1; connected = 0; } - if (!ipc.opt) - ipc.opt = inet->opt; + if (!ipc.opt) { + struct ip_options_rcu *inet_opt; + + rcu_read_lock(); + inet_opt = rcu_dereference(inet->inet_opt); + if (inet_opt) { + memcpy(&opt_copy, inet_opt, + sizeof(*inet_opt) + inet_opt->opt.optlen); + ipc.opt = &opt_copy.opt; + } + rcu_read_unlock(); + } saddr = ipc.addr; ipc.addr = faddr = daddr; - if (ipc.opt && ipc.opt->srr) { + if (ipc.opt && ipc.opt->opt.srr) { if (!daddr) return -EINVAL; - faddr = ipc.opt->faddr; + faddr = ipc.opt->opt.faddr; connected = 0; } tos = RT_TOS(inet->tos); if (sock_flag(sk, SOCK_LOCALROUTE) || (msg->msg_flags & MSG_DONTROUTE) || - (ipc.opt && ipc.opt->is_strictroute)) { + (ipc.opt && ipc.opt->opt.is_strictroute)) { tos |= RTO_ONLINK; connected = 0; } diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c index cb7658a..8683664 100644 --- a/net/ipv6/tcp_ipv6.c +++ b/net/ipv6/tcp_ipv6.c @@ -1469,7 +1469,7 @@ static struct sock * tcp_v6_syn_recv_sock(struct sock *sk, struct sk_buff *skb, First: no IPv4 options. */ - newinet->opt = NULL; + newinet->inet_opt = NULL; newnp->ipv6_fl_list = NULL; /* Clone RX bits */ diff --git a/net/l2tp/l2tp_ip.c b/net/l2tp/l2tp_ip.c index cc67367..962a607 100644 --- a/net/l2tp/l2tp_ip.c +++ b/net/l2tp/l2tp_ip.c @@ -416,7 +416,6 @@ static int l2tp_ip_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *m int rc; struct l2tp_ip_sock *lsa = l2tp_ip_sk(sk); struct inet_sock *inet = inet_sk(sk); - struct ip_options *opt = inet->opt; struct rtable *rt = NULL; int connected = 0; __be32 daddr; @@ -471,9 +470,14 @@ static int l2tp_ip_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *m rt = (struct rtable *) __sk_dst_check(sk, 0); if (rt == NULL) { + struct ip_options_rcu *inet_opt; + + inet_opt = rcu_dereference_protected(inet->inet_opt, + sock_owned_by_user(sk)); + /* Use correct destination address if we have options. */ - if (opt && opt->srr) - daddr = opt->faddr; + if (inet_opt && inet_opt->opt.srr) + daddr = inet_opt->opt.faddr; /* If this fails, retransmit mechanism of transport layer will * keep trying until route appears or the connection times -- cgit v0.10.2 From 96339d6c490a32de35fa798ca7922d13a8538ecd Mon Sep 17 00:00:00 2001 From: Shan Wei Date: Fri, 22 Apr 2011 19:07:41 +0800 Subject: net:use help function of skb_checksum_start_offset to calculate offset Although these are equivalent, but the skb_checksum_start_offset() is more readable. Signed-off-by: Shan Wei Signed-off-by: David S. Miller diff --git a/drivers/net/tile/tilepro.c b/drivers/net/tile/tilepro.c index 0825db6..1e980fd 100644 --- a/drivers/net/tile/tilepro.c +++ b/drivers/net/tile/tilepro.c @@ -1930,7 +1930,7 @@ static int tile_net_tx(struct sk_buff *skb, struct net_device *dev) unsigned int len = skb->len; unsigned char *data = skb->data; - unsigned int csum_start = skb->csum_start - skb_headroom(skb); + unsigned int csum_start = skb_checksum_start_offset(skb); lepp_frag_t frags[LEPP_MAX_FRAGS]; diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c index 98ecfd7..fc0c42a 100644 --- a/net/ipv6/udp.c +++ b/net/ipv6/udp.c @@ -1328,7 +1328,7 @@ static struct sk_buff *udp6_ufo_fragment(struct sk_buff *skb, u32 features) /* Do software UFO. Complete and fill in the UDP checksum as HW cannot * do checksum of UDP packets sent as multiple IP fragments. */ - offset = skb->csum_start - skb_headroom(skb); + offset = skb_checksum_start_offset(skb); csum = skb_checksum(skb, offset, skb->len- offset, 0); offset += skb->csum_offset; *(__sum16 *)(skb->data + offset) = csum_fold(csum); -- cgit v0.10.2 From 1742f183fc218798dab6fcf0ded25b6608fc0a48 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Miros=C5=82aw?= Date: Fri, 22 Apr 2011 06:31:16 +0000 Subject: net: fix netdev_increment_features() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Simplify and fix netdev_increment_features() to conform to what is stated in netdevice.h comments about NETIF_F_ONE_FOR_ALL. Include FCoE segmentation and VLAN-challedged flags in computation. Signed-off-by: MichaÅ‚ MirosÅ‚aw Signed-off-by: David S. Miller diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index 364bcf2..b7d0304 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -1106,7 +1106,12 @@ struct net_device { */ #define NETIF_F_ONE_FOR_ALL (NETIF_F_GSO_SOFTWARE | NETIF_F_GSO_ROBUST | \ NETIF_F_SG | NETIF_F_HIGHDMA | \ - NETIF_F_FRAGLIST) + NETIF_F_FRAGLIST | NETIF_F_VLAN_CHALLENGED) + /* + * If one device doesn't support one of these features, then disable it + * for all in netdev_increment_features. + */ +#define NETIF_F_ALL_FOR_ALL (NETIF_F_NOCACHE_COPY | NETIF_F_FSO) /* changeable features with no special hardware requirements */ #define NETIF_F_SOFT_FEATURES (NETIF_F_GSO | NETIF_F_GRO) diff --git a/net/core/dev.c b/net/core/dev.c index 3bbb4c2..7db99b5 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -6164,33 +6164,20 @@ static int dev_cpu_callback(struct notifier_block *nfb, */ u32 netdev_increment_features(u32 all, u32 one, u32 mask) { - /* If device needs checksumming, downgrade to it. */ - if (all & NETIF_F_NO_CSUM && !(one & NETIF_F_NO_CSUM)) - all ^= NETIF_F_NO_CSUM | (one & NETIF_F_ALL_CSUM); - else if (mask & NETIF_F_ALL_CSUM) { - /* If one device supports v4/v6 checksumming, set for all. */ - if (one & (NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM) && - !(all & NETIF_F_GEN_CSUM)) { - all &= ~NETIF_F_ALL_CSUM; - all |= one & (NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM); - } - - /* If one device supports hw checksumming, set for all. */ - if (one & NETIF_F_GEN_CSUM && !(all & NETIF_F_GEN_CSUM)) { - all &= ~NETIF_F_ALL_CSUM; - all |= NETIF_F_HW_CSUM; - } - } + if (mask & NETIF_F_GEN_CSUM) + mask |= NETIF_F_ALL_CSUM; + mask |= NETIF_F_VLAN_CHALLENGED; - /* If device can't no cache copy, don't do for all */ - if (!(one & NETIF_F_NOCACHE_COPY)) - all &= ~NETIF_F_NOCACHE_COPY; + all |= one & (NETIF_F_ONE_FOR_ALL|NETIF_F_ALL_CSUM) & mask; + all &= one | ~NETIF_F_ALL_FOR_ALL; - one |= NETIF_F_ALL_CSUM; + /* If device needs checksumming, downgrade to it. */ + if (all & (NETIF_F_ALL_CSUM & ~NETIF_F_NO_CSUM)) + all &= ~NETIF_F_NO_CSUM; - one |= all & NETIF_F_ONE_FOR_ALL; - all &= one | NETIF_F_LLTX | NETIF_F_GSO | NETIF_F_UFO; - all |= one & mask & NETIF_F_ONE_FOR_ALL; + /* If one device supports hw checksumming, set for all. */ + if (all & NETIF_F_GEN_CSUM) + all &= ~(NETIF_F_ALL_CSUM & ~NETIF_F_GEN_CSUM); return all; } -- cgit v0.10.2 From c4d27ef957cd9261c0bc8488edaf8390e412cd35 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Miros=C5=82aw?= Date: Fri, 22 Apr 2011 06:31:16 +0000 Subject: bridge: convert br_features_recompute() to ndo_fix_features MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Note: netdev_update_features() needs only rtnl_lock as br->port_list is only changed while holding it. Signed-off-by: MichaÅ‚ MirosÅ‚aw Signed-off-by: David S. Miller diff --git a/net/bridge/br_device.c b/net/bridge/br_device.c index 45cfd54..a6b2f86 100644 --- a/net/bridge/br_device.c +++ b/net/bridge/br_device.c @@ -90,8 +90,7 @@ static int br_dev_open(struct net_device *dev) struct net_bridge *br = netdev_priv(dev); netif_carrier_off(dev); - - br_features_recompute(br); + netdev_update_features(dev); netif_start_queue(dev); br_stp_enable_bridge(br); br_multicast_open(br); @@ -188,48 +187,11 @@ static void br_getinfo(struct net_device *dev, struct ethtool_drvinfo *info) strcpy(info->bus_info, "N/A"); } -static int br_set_sg(struct net_device *dev, u32 data) -{ - struct net_bridge *br = netdev_priv(dev); - - if (data) - br->feature_mask |= NETIF_F_SG; - else - br->feature_mask &= ~NETIF_F_SG; - - br_features_recompute(br); - return 0; -} - -static int br_set_tso(struct net_device *dev, u32 data) +static u32 br_fix_features(struct net_device *dev, u32 features) { struct net_bridge *br = netdev_priv(dev); - if (data) - br->feature_mask |= NETIF_F_TSO; - else - br->feature_mask &= ~NETIF_F_TSO; - - br_features_recompute(br); - return 0; -} - -static int br_set_tx_csum(struct net_device *dev, u32 data) -{ - struct net_bridge *br = netdev_priv(dev); - - if (data) - br->feature_mask |= NETIF_F_NO_CSUM; - else - br->feature_mask &= ~NETIF_F_ALL_CSUM; - - br_features_recompute(br); - return 0; -} - -static int br_set_flags(struct net_device *netdev, u32 data) -{ - return ethtool_op_set_flags(netdev, data, ETH_FLAG_TXVLAN); + return br_features_recompute(br, features); } #ifdef CONFIG_NET_POLL_CONTROLLER @@ -330,16 +292,6 @@ static int br_del_slave(struct net_device *dev, struct net_device *slave_dev) static const struct ethtool_ops br_ethtool_ops = { .get_drvinfo = br_getinfo, .get_link = ethtool_op_get_link, - .get_tx_csum = ethtool_op_get_tx_csum, - .set_tx_csum = br_set_tx_csum, - .get_sg = ethtool_op_get_sg, - .set_sg = br_set_sg, - .get_tso = ethtool_op_get_tso, - .set_tso = br_set_tso, - .get_ufo = ethtool_op_get_ufo, - .set_ufo = ethtool_op_set_ufo, - .get_flags = ethtool_op_get_flags, - .set_flags = br_set_flags, }; static const struct net_device_ops br_netdev_ops = { @@ -359,6 +311,7 @@ static const struct net_device_ops br_netdev_ops = { #endif .ndo_add_slave = br_add_slave, .ndo_del_slave = br_del_slave, + .ndo_fix_features = br_fix_features, }; static void br_dev_free(struct net_device *dev) @@ -389,7 +342,10 @@ void br_dev_setup(struct net_device *dev) dev->features = NETIF_F_SG | NETIF_F_FRAGLIST | NETIF_F_HIGHDMA | NETIF_F_GSO_MASK | NETIF_F_NO_CSUM | NETIF_F_LLTX | - NETIF_F_NETNS_LOCAL | NETIF_F_GSO | NETIF_F_HW_VLAN_TX; + NETIF_F_NETNS_LOCAL | NETIF_F_HW_VLAN_TX; + dev->hw_features = NETIF_F_SG | NETIF_F_FRAGLIST | NETIF_F_HIGHDMA | + NETIF_F_GSO_MASK | NETIF_F_NO_CSUM | + NETIF_F_HW_VLAN_TX; br->dev = dev; spin_lock_init(&br->lock); @@ -401,7 +357,6 @@ void br_dev_setup(struct net_device *dev) memcpy(br->group_addr, br_group_address, ETH_ALEN); - br->feature_mask = dev->features; br->stp_enabled = BR_NO_STP; br->designated_root = br->bridge_id; br->bridge_max_age = br->max_age = 20 * HZ; diff --git a/net/bridge/br_if.c b/net/bridge/br_if.c index 7f5379c..1156460 100644 --- a/net/bridge/br_if.c +++ b/net/bridge/br_if.c @@ -291,15 +291,15 @@ int br_min_mtu(const struct net_bridge *br) /* * Recomputes features using slave's features */ -void br_features_recompute(struct net_bridge *br) +u32 br_features_recompute(struct net_bridge *br, u32 features) { struct net_bridge_port *p; - u32 features, mask; + u32 mask; - features = mask = br->feature_mask; if (list_empty(&br->port_list)) - goto done; + return features; + mask = features; features &= ~NETIF_F_ONE_FOR_ALL; list_for_each_entry(p, &br->port_list, list) { @@ -307,8 +307,7 @@ void br_features_recompute(struct net_bridge *br) p->dev->features, mask); } -done: - br->dev->features = netdev_fix_features(br->dev, features); + return features; } /* called with RTNL */ @@ -373,9 +372,10 @@ int br_add_if(struct net_bridge *br, struct net_device *dev) list_add_rcu(&p->list, &br->port_list); + netdev_update_features(br->dev); + spin_lock_bh(&br->lock); changed_addr = br_stp_recalculate_bridge_id(br); - br_features_recompute(br); if ((dev->flags & IFF_UP) && netif_carrier_ok(dev) && (br->dev->flags & IFF_UP)) @@ -423,9 +423,10 @@ int br_del_if(struct net_bridge *br, struct net_device *dev) spin_lock_bh(&br->lock); br_stp_recalculate_bridge_id(br); - br_features_recompute(br); spin_unlock_bh(&br->lock); + netdev_update_features(br->dev); + return 0; } diff --git a/net/bridge/br_notify.c b/net/bridge/br_notify.c index 606b323..6545ee9 100644 --- a/net/bridge/br_notify.c +++ b/net/bridge/br_notify.c @@ -66,10 +66,7 @@ static int br_device_event(struct notifier_block *unused, unsigned long event, v break; case NETDEV_FEAT_CHANGE: - spin_lock_bh(&br->lock); - if (netif_running(br->dev)) - br_features_recompute(br); - spin_unlock_bh(&br->lock); + netdev_update_features(br->dev); break; case NETDEV_DOWN: diff --git a/net/bridge/br_private.h b/net/bridge/br_private.h index e2a4034..54578f2 100644 --- a/net/bridge/br_private.h +++ b/net/bridge/br_private.h @@ -183,7 +183,6 @@ struct net_bridge struct br_cpu_netstats __percpu *stats; spinlock_t hash_lock; struct hlist_head hash[BR_HASH_SIZE]; - u32 feature_mask; #ifdef CONFIG_BRIDGE_NETFILTER struct rtable fake_rtable; bool nf_call_iptables; @@ -379,7 +378,7 @@ extern int br_add_if(struct net_bridge *br, extern int br_del_if(struct net_bridge *br, struct net_device *dev); extern int br_min_mtu(const struct net_bridge *br); -extern void br_features_recompute(struct net_bridge *br); +extern u32 br_features_recompute(struct net_bridge *br, u32 features); /* br_input.c */ extern int br_handle_frame_finish(struct sk_buff *skb); -- cgit v0.10.2 From fa2bd7ff9247f4218dfc907db14d000cd7edd862 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Miros=C5=82aw?= Date: Fri, 22 Apr 2011 06:31:16 +0000 Subject: net: allow user to change NETIF_F_HIGHDMA MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit NETIF_F_HIGHDMA is like any other TX offloads, so allow user to toggle it. This is needed later for bridge and bonding convertsion to hw_features. Signed-off-by: MichaÅ‚ MirosÅ‚aw Signed-off-by: David S. Miller diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index b7d0304..e03af35 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -1080,7 +1080,7 @@ struct net_device { /* Features valid for ethtool to change */ /* = all defined minus driver/device-class-related */ -#define NETIF_F_NEVER_CHANGE (NETIF_F_HIGHDMA | NETIF_F_VLAN_CHALLENGED | \ +#define NETIF_F_NEVER_CHANGE (NETIF_F_VLAN_CHALLENGED | \ NETIF_F_LLTX | NETIF_F_NETNS_LOCAL) #define NETIF_F_ETHTOOL_BITS (0x7f3fffff & ~NETIF_F_NEVER_CHANGE) @@ -1098,6 +1098,7 @@ struct net_device { #define NETIF_F_ALL_TX_OFFLOADS (NETIF_F_ALL_CSUM | NETIF_F_SG | \ NETIF_F_FRAGLIST | NETIF_F_ALL_TSO | \ + NETIF_F_HIGHDMA | \ NETIF_F_SCTP_CSUM | NETIF_F_FCOE_CRC) /* -- cgit v0.10.2 From b3b270054b80e6195b1d2b2ce082239911261839 Mon Sep 17 00:00:00 2001 From: Peter Korsgaard Date: Tue, 26 Apr 2011 01:45:41 +0000 Subject: dsa/mv88e6131: fix unknown multicast/broadcast forwarding on mv88e6085 The 88e6085 has a few differences from the other devices in the port control registers, causing unknown multicast/broadcast packets to get dropped when using the standard port setup. At the same time update kconfig to clarify that the mv88e6085 is now supported. Signed-off-by: Peter Korsgaard Acked-by: Lennert Buytenhek Signed-off-by: David S. Miller diff --git a/net/dsa/Kconfig b/net/dsa/Kconfig index 87bb5f4..c53ded2 100644 --- a/net/dsa/Kconfig +++ b/net/dsa/Kconfig @@ -41,12 +41,12 @@ config NET_DSA_MV88E6XXX_NEED_PPU default n config NET_DSA_MV88E6131 - bool "Marvell 88E6095/6095F/6131 ethernet switch chip support" + bool "Marvell 88E6085/6095/6095F/6131 ethernet switch chip support" select NET_DSA_MV88E6XXX select NET_DSA_MV88E6XXX_NEED_PPU select NET_DSA_TAG_DSA ---help--- - This enables support for the Marvell 88E6095/6095F/6131 + This enables support for the Marvell 88E6085/6095/6095F/6131 ethernet switch chips. config NET_DSA_MV88E6123_61_65 diff --git a/net/dsa/mv88e6131.c b/net/dsa/mv88e6131.c index 3da4188..45f7411 100644 --- a/net/dsa/mv88e6131.c +++ b/net/dsa/mv88e6131.c @@ -207,8 +207,15 @@ static int mv88e6131_setup_port(struct dsa_switch *ds, int p) * mode, but do not enable forwarding of unknown unicasts. */ val = 0x0433; - if (p == dsa_upstream_port(ds)) + if (p == dsa_upstream_port(ds)) { val |= 0x0104; + /* + * On 6085, unknown multicast forward is controlled + * here rather than in Port Control 2 register. + */ + if (ps->id == ID_6085) + val |= 0x0008; + } if (ds->dsa_port_mask & (1 << p)) val |= 0x0100; REG_WRITE(addr, 0x04, val); @@ -251,10 +258,19 @@ static int mv88e6131_setup_port(struct dsa_switch *ds, int p) * If this is the upstream port for this switch, enable * forwarding of unknown multicast addresses. */ - val = 0x0080 | dsa_upstream_port(ds); - if (p == dsa_upstream_port(ds)) - val |= 0x0040; - REG_WRITE(addr, 0x08, val); + if (ps->id == ID_6085) + /* + * on 6085, bits 3:0 are reserved, bit 6 control ARP + * mirroring, and multicast forward is handled in + * Port Control register. + */ + REG_WRITE(addr, 0x08, 0x0080); + else { + val = 0x0080 | dsa_upstream_port(ds); + if (p == dsa_upstream_port(ds)) + val |= 0x0040; + REG_WRITE(addr, 0x08, val); + } /* * Rate Control: disable ingress rate limiting. -- cgit v0.10.2 From 180bf812ceaf01eb8ac69b86f3be0bd57f697668 Mon Sep 17 00:00:00 2001 From: John Stultz Date: Thu, 28 Apr 2011 12:58:11 -0700 Subject: timers: Improve alarmtimer comments and minor fixes This patch addresses a number of minor comment improvements and other minor issues from Thomas' review of the alarmtimers code. CC: Thomas Gleixner Signed-off-by: John Stultz diff --git a/include/linux/alarmtimer.h b/include/linux/alarmtimer.h index 6b364b2..c5d6095 100644 --- a/include/linux/alarmtimer.h +++ b/include/linux/alarmtimer.h @@ -13,12 +13,22 @@ enum alarmtimer_type { ALARM_NUMTYPE, }; +/** + * struct alarm - Alarm timer structure + * @node: timerqueue node for adding to the event list this value + * also includes the expiration time. + * @period: Period for recuring alarms + * @function: Function pointer to be executed when the timer fires. + * @type: Alarm type (BOOTTIME/REALTIME) + * @enabled: Flag that represents if the alarm is set to fire or not + * @data: Internal data value. + */ struct alarm { struct timerqueue_node node; ktime_t period; void (*function)(struct alarm *); enum alarmtimer_type type; - char enabled; + bool enabled; void *data; }; diff --git a/kernel/time/alarmtimer.c b/kernel/time/alarmtimer.c index 4058ad7..bed9800 100644 --- a/kernel/time/alarmtimer.c +++ b/kernel/time/alarmtimer.c @@ -26,7 +26,15 @@ #include #include - +/** + * struct alarm_base - Alarm timer bases + * @lock: Lock for syncrhonized access to the base + * @timerqueue: Timerqueue head managing the list of events + * @timer: hrtimer used to schedule events while running + * @gettime: Function to read the time correlating to the base + * @base_clockid: clockid for the base + * @irqwork Delayed work structure for expiring timers + */ static struct alarm_base { spinlock_t lock; struct timerqueue_head timerqueue; @@ -36,18 +44,16 @@ static struct alarm_base { struct work_struct irqwork; } alarm_bases[ALARM_NUMTYPE]; +/* rtc timer and device for setting alarm wakeups at suspend */ static struct rtc_timer rtctimer; static struct rtc_device *rtcdev; +/* freezer delta & lock used to handle clock_nanosleep triggered wakeups */ static ktime_t freezer_delta; static DEFINE_SPINLOCK(freezer_delta_lock); -/************************************************************************** - * alarmtimer management code - */ - -/* +/** * alarmtimer_enqueue - Adds an alarm timer to an alarm_base timerqueue * @base: pointer to the base where the timer is being run * @alarm: pointer to alarm being enqueued. @@ -67,7 +73,7 @@ static void alarmtimer_enqueue(struct alarm_base *base, struct alarm *alarm) } } -/* +/** * alarmtimer_remove - Removes an alarm timer from an alarm_base timerqueue * @base: pointer to the base where the timer is running * @alarm: pointer to alarm being removed @@ -91,16 +97,16 @@ static void alarmtimer_remove(struct alarm_base *base, struct alarm *alarm) } } -/* +/** * alarmtimer_do_work - Handles alarm being fired. * @work: pointer to workqueue being run * - * When a timer fires, this runs through the timerqueue to see - * which alarm timers, and run those that expired. If there are - * more alarm timers queued, we set the hrtimer to fire in the - * future. + * When a alarm timer fires, this runs through the timerqueue to + * see which alarms expired, and runs those. If there are more alarm + * timers queued for the future, we set the hrtimer to fire when + * when the next future alarm timer expires. */ -void alarmtimer_do_work(struct work_struct *work) +static void alarmtimer_do_work(struct work_struct *work) { struct alarm_base *base = container_of(work, struct alarm_base, irqwork); @@ -141,7 +147,7 @@ void alarmtimer_do_work(struct work_struct *work) } -/* +/** * alarmtimer_fired - Handles alarm hrtimer being fired. * @timer: pointer to hrtimer being run * @@ -156,7 +162,7 @@ static enum hrtimer_restart alarmtimer_fired(struct hrtimer *timer) } -/* +/** * alarmtimer_suspend - Suspend time callback * @dev: unused * @state: unused @@ -230,17 +236,11 @@ static void alarmtimer_freezerset(ktime_t absexp, enum alarmtimer_type type) } -/************************************************************************** - * alarm kernel interface code - */ - -/* +/** * alarm_init - Initialize an alarm structure * @alarm: ptr to alarm to be initialized * @type: the type of the alarm * @function: callback that is run when the alarm fires - * - * In-kernel interface to initializes the alarm structure. */ void alarm_init(struct alarm *alarm, enum alarmtimer_type type, void (*function)(struct alarm *)) @@ -252,13 +252,11 @@ void alarm_init(struct alarm *alarm, enum alarmtimer_type type, alarm->enabled = 0; } -/* +/** * alarm_start - Sets an alarm to fire * @alarm: ptr to alarm to set * @start: time to run the alarm * @period: period at which the alarm will recur - * - * In-kernel interface set an alarm timer. */ void alarm_start(struct alarm *alarm, ktime_t start, ktime_t period) { @@ -275,11 +273,9 @@ void alarm_start(struct alarm *alarm, ktime_t start, ktime_t period) spin_unlock_irqrestore(&base->lock, flags); } -/* +/** * alarm_cancel - Tries to cancel an alarm timer * @alarm: ptr to alarm to be canceled - * - * In-kernel interface to cancel an alarm timer. */ void alarm_cancel(struct alarm *alarm) { @@ -294,15 +290,9 @@ void alarm_cancel(struct alarm *alarm) } -/************************************************************************** - * alarm posix interface code - */ - -/* +/** * clock2alarm - helper that converts from clockid to alarmtypes * @clockid: clockid. - * - * Helper function that converts from clockids to alarmtypes */ static enum alarmtimer_type clock2alarm(clockid_t clockid) { @@ -313,7 +303,7 @@ static enum alarmtimer_type clock2alarm(clockid_t clockid) return -1; } -/* +/** * alarm_handle_timer - Callback for posix timers * @alarm: alarm that fired * @@ -327,7 +317,7 @@ static void alarm_handle_timer(struct alarm *alarm) ptr->it_overrun++; } -/* +/** * alarm_clock_getres - posix getres interface * @which_clock: clockid * @tp: timespec to fill @@ -598,9 +588,6 @@ out: return ret; } -/************************************************************************** - * alarmtimer initialization code - */ /* Suspend hook structures */ static const struct dev_pm_ops alarmtimer_pm_ops = { -- cgit v0.10.2 From 7068b7a16270f1e85a8893d74b0f3c58d7826883 Mon Sep 17 00:00:00 2001 From: John Stultz Date: Thu, 28 Apr 2011 13:29:18 -0700 Subject: timers: Remove delayed irqwork from alarmtimers implementation Thomas asked about the delayed irq work in the alarmtimers code, and I realized that it was a legacy from when the alarmtimer base lock was a mutex (due to concerns that we'd be interacting with the RTC device, which is protected by mutexes). Since the alarmtimer base is now protected by a spinlock, we can simply execute alarmtimer functions directly from the hrtimer callback. Should any future alarmtimer functions sleep, they can simply manage scheduling any delayed work themselves. CC: Thomas Gleixner Signed-off-by: John Stultz diff --git a/kernel/time/alarmtimer.c b/kernel/time/alarmtimer.c index bed9800..491e37b 100644 --- a/kernel/time/alarmtimer.c +++ b/kernel/time/alarmtimer.c @@ -33,7 +33,6 @@ * @timer: hrtimer used to schedule events while running * @gettime: Function to read the time correlating to the base * @base_clockid: clockid for the base - * @irqwork Delayed work structure for expiring timers */ static struct alarm_base { spinlock_t lock; @@ -41,7 +40,6 @@ static struct alarm_base { struct hrtimer timer; ktime_t (*gettime)(void); clockid_t base_clockid; - struct work_struct irqwork; } alarm_bases[ALARM_NUMTYPE]; /* rtc timer and device for setting alarm wakeups at suspend */ @@ -97,22 +95,23 @@ static void alarmtimer_remove(struct alarm_base *base, struct alarm *alarm) } } + /** - * alarmtimer_do_work - Handles alarm being fired. - * @work: pointer to workqueue being run + * alarmtimer_fired - Handles alarm hrtimer being fired. + * @timer: pointer to hrtimer being run * * When a alarm timer fires, this runs through the timerqueue to * see which alarms expired, and runs those. If there are more alarm * timers queued for the future, we set the hrtimer to fire when * when the next future alarm timer expires. */ -static void alarmtimer_do_work(struct work_struct *work) +static enum hrtimer_restart alarmtimer_fired(struct hrtimer *timer) { - struct alarm_base *base = container_of(work, struct alarm_base, - irqwork); + struct alarm_base *base = container_of(timer, struct alarm_base, timer); struct timerqueue_node *next; unsigned long flags; ktime_t now; + int ret = HRTIMER_NORESTART; spin_lock_irqsave(&base->lock, flags); now = base->gettime(); @@ -140,25 +139,13 @@ static void alarmtimer_do_work(struct work_struct *work) } if (next) { - hrtimer_start(&base->timer, next->expires, - HRTIMER_MODE_ABS); + hrtimer_set_expires(&base->timer, next->expires); + ret = HRTIMER_RESTART; } spin_unlock_irqrestore(&base->lock, flags); -} + return ret; -/** - * alarmtimer_fired - Handles alarm hrtimer being fired. - * @timer: pointer to hrtimer being run - * - * When a timer fires, this schedules the do_work function to - * be run. - */ -static enum hrtimer_restart alarmtimer_fired(struct hrtimer *timer) -{ - struct alarm_base *base = container_of(timer, struct alarm_base, timer); - schedule_work(&base->irqwork); - return HRTIMER_NORESTART; } @@ -636,7 +623,6 @@ static int __init alarmtimer_init(void) alarm_bases[i].base_clockid, HRTIMER_MODE_ABS); alarm_bases[i].timer.function = alarmtimer_fired; - INIT_WORK(&alarm_bases[i].irqwork, alarmtimer_do_work); } error = platform_driver_register(&alarmtimer_driver); platform_device_register_simple("alarmtimer", -1, NULL, 0); -- cgit v0.10.2 From 63c3a66fe6c827a731dcbdee181158b295626f83 Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Tue, 26 Apr 2011 08:12:10 +0000 Subject: tg3: Convert u32 flag,flg2,flg3 uses to bitmap Using a bitmap instead of separate u32 flags allows a consistent, simpler and more extensible mechanism to determine capabilities. Convert bitmasks to enum. Add tg3_flag, tg3_flag_clear and tg3_flag_set. Convert the flag & bitmask tests. Signed-off-by: Joe Perches Acked-by: Matt Carlson Signed-off-by: David S. Miller diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index b20538a..fa57e3d 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -62,6 +62,30 @@ #include "tg3.h" +/* Functions & macros to verify TG3_FLAGS types */ + +static inline int _tg3_flag(enum TG3_FLAGS flag, unsigned long *bits) +{ + return test_bit(flag, bits); +} + +static inline void _tg3_flag_set(enum TG3_FLAGS flag, unsigned long *bits) +{ + set_bit(flag, bits); +} + +static inline void _tg3_flag_clear(enum TG3_FLAGS flag, unsigned long *bits) +{ + clear_bit(flag, bits); +} + +#define tg3_flag(tp, flag) \ + _tg3_flag(TG3_FLAG_##flag, (tp)->tg3_flags) +#define tg3_flag_set(tp, flag) \ + _tg3_flag_set(TG3_FLAG_##flag, (tp)->tg3_flags) +#define tg3_flag_clear(tp, flag) \ + _tg3_flag_clear(TG3_FLAG_##flag, (tp)->tg3_flags) + #define DRV_MODULE_NAME "tg3" #define TG3_MAJ_NUM 3 #define TG3_MIN_NUM 118 @@ -85,23 +109,24 @@ /* length of time before we decide the hardware is borked, * and dev->tx_timeout() should be called to fix the problem */ + #define TG3_TX_TIMEOUT (5 * HZ) /* hardware minimum and maximum for a single frame's data payload */ #define TG3_MIN_MTU 60 #define TG3_MAX_MTU(tp) \ - ((tp->tg3_flags & TG3_FLAG_JUMBO_CAPABLE) ? 9000 : 1500) + (tg3_flag(tp, JUMBO_CAPABLE) ? 9000 : 1500) /* These numbers seem to be hard coded in the NIC firmware somehow. * You can't change the ring sizes, but you can change where you place * them in the NIC onboard memory. */ #define TG3_RX_STD_RING_SIZE(tp) \ - ((tp->tg3_flags3 & TG3_FLG3_LRG_PROD_RING_CAP) ? \ + (tg3_flag(tp, LRG_PROD_RING_CAP) ? \ TG3_RX_STD_MAX_SIZE_5717 : TG3_RX_STD_MAX_SIZE_5700) #define TG3_DEF_RX_RING_PENDING 200 #define TG3_RX_JMB_RING_SIZE(tp) \ - ((tp->tg3_flags3 & TG3_FLG3_LRG_PROD_RING_CAP) ? \ + (tg3_flag(tp, LRG_PROD_RING_CAP) ? \ TG3_RX_JMB_MAX_SIZE_5717 : TG3_RX_JMB_MAX_SIZE_5700) #define TG3_DEF_RX_JUMBO_RING_PENDING 100 #define TG3_RSS_INDIR_TBL_SIZE 128 @@ -468,8 +493,7 @@ static u32 tg3_read_indirect_mbox(struct tg3 *tp, u32 off) */ static void _tw32_flush(struct tg3 *tp, u32 off, u32 val, u32 usec_wait) { - if ((tp->tg3_flags & TG3_FLAG_PCIX_TARGET_HWBUG) || - (tp->tg3_flags2 & TG3_FLG2_ICH_WORKAROUND)) + if (tg3_flag(tp, PCIX_TARGET_HWBUG) || tg3_flag(tp, ICH_WORKAROUND)) /* Non-posted methods */ tp->write32(tp, off, val); else { @@ -489,8 +513,7 @@ static void _tw32_flush(struct tg3 *tp, u32 off, u32 val, u32 usec_wait) static inline void tw32_mailbox_flush(struct tg3 *tp, u32 off, u32 val) { tp->write32_mbox(tp, off, val); - if (!(tp->tg3_flags & TG3_FLAG_MBOX_WRITE_REORDER) && - !(tp->tg3_flags2 & TG3_FLG2_ICH_WORKAROUND)) + if (!tg3_flag(tp, MBOX_WRITE_REORDER) && !tg3_flag(tp, ICH_WORKAROUND)) tp->read32_mbox(tp, off); } @@ -498,9 +521,9 @@ static void tg3_write32_tx_mbox(struct tg3 *tp, u32 off, u32 val) { void __iomem *mbox = tp->regs + off; writel(val, mbox); - if (tp->tg3_flags & TG3_FLAG_TXD_MBOX_HWBUG) + if (tg3_flag(tp, TXD_MBOX_HWBUG)) writel(val, mbox); - if (tp->tg3_flags & TG3_FLAG_MBOX_WRITE_REORDER) + if (tg3_flag(tp, MBOX_WRITE_REORDER)) readl(mbox); } @@ -534,7 +557,7 @@ static void tg3_write_mem(struct tg3 *tp, u32 off, u32 val) return; spin_lock_irqsave(&tp->indirect_lock, flags); - if (tp->tg3_flags & TG3_FLAG_SRAM_USE_CONFIG) { + if (tg3_flag(tp, SRAM_USE_CONFIG)) { pci_write_config_dword(tp->pdev, TG3PCI_MEM_WIN_BASE_ADDR, off); pci_write_config_dword(tp->pdev, TG3PCI_MEM_WIN_DATA, val); @@ -561,7 +584,7 @@ static void tg3_read_mem(struct tg3 *tp, u32 off, u32 *val) } spin_lock_irqsave(&tp->indirect_lock, flags); - if (tp->tg3_flags & TG3_FLAG_SRAM_USE_CONFIG) { + if (tg3_flag(tp, SRAM_USE_CONFIG)) { pci_write_config_dword(tp->pdev, TG3PCI_MEM_WIN_BASE_ADDR, off); pci_read_config_dword(tp->pdev, TG3PCI_MEM_WIN_DATA, val); @@ -598,7 +621,7 @@ static int tg3_ape_lock(struct tg3 *tp, int locknum) int ret = 0; u32 status, req, gnt; - if (!(tp->tg3_flags3 & TG3_FLG3_ENABLE_APE)) + if (!tg3_flag(tp, ENABLE_APE)) return 0; switch (locknum) { @@ -644,7 +667,7 @@ static void tg3_ape_unlock(struct tg3 *tp, int locknum) { u32 gnt; - if (!(tp->tg3_flags3 & TG3_FLG3_ENABLE_APE)) + if (!tg3_flag(tp, ENABLE_APE)) return; switch (locknum) { @@ -688,14 +711,14 @@ static void tg3_enable_ints(struct tg3 *tp) struct tg3_napi *tnapi = &tp->napi[i]; tw32_mailbox_f(tnapi->int_mbox, tnapi->last_tag << 24); - if (tp->tg3_flags2 & TG3_FLG2_1SHOT_MSI) + if (tg3_flag(tp, 1SHOT_MSI)) tw32_mailbox_f(tnapi->int_mbox, tnapi->last_tag << 24); tp->coal_now |= tnapi->coal_now; } /* Force an initial interrupt */ - if (!(tp->tg3_flags & TG3_FLAG_TAGGED_STATUS) && + if (!tg3_flag(tp, TAGGED_STATUS) && (tp->napi[0].hw_status->status & SD_STATUS_UPDATED)) tw32(GRC_LOCAL_CTRL, tp->grc_local_ctrl | GRC_LCLCTRL_SETINT); else @@ -711,9 +734,7 @@ static inline unsigned int tg3_has_work(struct tg3_napi *tnapi) unsigned int work_exists = 0; /* check for phy events */ - if (!(tp->tg3_flags & - (TG3_FLAG_USE_LINKCHG_REG | - TG3_FLAG_POLL_SERDES))) { + if (!(tg3_flag(tp, USE_LINKCHG_REG) || tg3_flag(tp, POLL_SERDES))) { if (sblk->status & SD_STATUS_LINK_CHG) work_exists = 1; } @@ -741,8 +762,7 @@ static void tg3_int_reenable(struct tg3_napi *tnapi) * The last_tag we write above tells the chip which piece of * work we've completed. */ - if (!(tp->tg3_flags & TG3_FLAG_TAGGED_STATUS) && - tg3_has_work(tnapi)) + if (!tg3_flag(tp, TAGGED_STATUS) && tg3_has_work(tnapi)) tw32(HOSTCC_MODE, tp->coalesce_mode | HOSTCC_MODE_ENABLE | tnapi->coal_now); } @@ -752,8 +772,7 @@ static void tg3_switch_clocks(struct tg3 *tp) u32 clock_ctrl; u32 orig_clock_ctrl; - if ((tp->tg3_flags & TG3_FLAG_CPMU_PRESENT) || - (tp->tg3_flags2 & TG3_FLG2_5780_CLASS)) + if (tg3_flag(tp, CPMU_PRESENT) || tg3_flag(tp, 5780_CLASS)) return; clock_ctrl = tr32(TG3PCI_CLOCK_CTRL); @@ -764,7 +783,7 @@ static void tg3_switch_clocks(struct tg3 *tp) 0x1f); tp->pci_clock_ctrl = clock_ctrl; - if (tp->tg3_flags2 & TG3_FLG2_5705_PLUS) { + if (tg3_flag(tp, 5705_PLUS)) { if (orig_clock_ctrl & CLOCK_CTRL_625_CORE) { tw32_wait_f(TG3PCI_CLOCK_CTRL, clock_ctrl | CLOCK_CTRL_625_CORE, 40); @@ -1081,7 +1100,7 @@ static void tg3_mdio_config_5785(struct tg3 *tp) return; } - if (!(tp->tg3_flags3 & TG3_FLG3_RGMII_INBAND_DISABLE)) + if (!tg3_flag(tp, RGMII_INBAND_DISABLE)) val |= MAC_PHYCFG2_EMODE_MASK_MASK | MAC_PHYCFG2_FMODE_MASK_MASK | MAC_PHYCFG2_GMODE_MASK_MASK | @@ -1094,10 +1113,10 @@ static void tg3_mdio_config_5785(struct tg3 *tp) val = tr32(MAC_PHYCFG1); val &= ~(MAC_PHYCFG1_RXCLK_TO_MASK | MAC_PHYCFG1_TXCLK_TO_MASK | MAC_PHYCFG1_RGMII_EXT_RX_DEC | MAC_PHYCFG1_RGMII_SND_STAT_EN); - if (!(tp->tg3_flags3 & TG3_FLG3_RGMII_INBAND_DISABLE)) { - if (tp->tg3_flags3 & TG3_FLG3_RGMII_EXT_IBND_RX_EN) + if (!tg3_flag(tp, RGMII_INBAND_DISABLE)) { + if (tg3_flag(tp, RGMII_EXT_IBND_RX_EN)) val |= MAC_PHYCFG1_RGMII_EXT_RX_DEC; - if (tp->tg3_flags3 & TG3_FLG3_RGMII_EXT_IBND_TX_EN) + if (tg3_flag(tp, RGMII_EXT_IBND_TX_EN)) val |= MAC_PHYCFG1_RGMII_SND_STAT_EN; } val |= MAC_PHYCFG1_RXCLK_TIMEOUT | MAC_PHYCFG1_TXCLK_TIMEOUT | @@ -1112,13 +1131,13 @@ static void tg3_mdio_config_5785(struct tg3 *tp) MAC_RGMII_MODE_TX_ENABLE | MAC_RGMII_MODE_TX_LOWPWR | MAC_RGMII_MODE_TX_RESET); - if (!(tp->tg3_flags3 & TG3_FLG3_RGMII_INBAND_DISABLE)) { - if (tp->tg3_flags3 & TG3_FLG3_RGMII_EXT_IBND_RX_EN) + if (!tg3_flag(tp, RGMII_INBAND_DISABLE)) { + if (tg3_flag(tp, RGMII_EXT_IBND_RX_EN)) val |= MAC_RGMII_MODE_RX_INT_B | MAC_RGMII_MODE_RX_QUALITY | MAC_RGMII_MODE_RX_ACTIVITY | MAC_RGMII_MODE_RX_ENG_DET; - if (tp->tg3_flags3 & TG3_FLG3_RGMII_EXT_IBND_TX_EN) + if (tg3_flag(tp, RGMII_EXT_IBND_TX_EN)) val |= MAC_RGMII_MODE_TX_ENABLE | MAC_RGMII_MODE_TX_LOWPWR | MAC_RGMII_MODE_TX_RESET; @@ -1132,7 +1151,7 @@ static void tg3_mdio_start(struct tg3 *tp) tw32_f(MAC_MI_MODE, tp->mi_mode); udelay(80); - if ((tp->tg3_flags3 & TG3_FLG3_MDIOBUS_INITED) && + if (tg3_flag(tp, MDIOBUS_INITED) && GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5785) tg3_mdio_config_5785(tp); } @@ -1143,7 +1162,7 @@ static int tg3_mdio_init(struct tg3 *tp) u32 reg; struct phy_device *phydev; - if (tp->tg3_flags3 & TG3_FLG3_5717_PLUS) { + if (tg3_flag(tp, 5717_PLUS)) { u32 is_serdes; tp->phy_addr = PCI_FUNC(tp->pdev->devfn) + 1; @@ -1160,8 +1179,7 @@ static int tg3_mdio_init(struct tg3 *tp) tg3_mdio_start(tp); - if (!(tp->tg3_flags3 & TG3_FLG3_USE_PHYLIB) || - (tp->tg3_flags3 & TG3_FLG3_MDIOBUS_INITED)) + if (!tg3_flag(tp, USE_PHYLIB) || tg3_flag(tp, MDIOBUS_INITED)) return 0; tp->mdio_bus = mdiobus_alloc(); @@ -1217,11 +1235,11 @@ static int tg3_mdio_init(struct tg3 *tp) PHY_BRCM_RX_REFCLK_UNUSED | PHY_BRCM_DIS_TXCRXC_NOENRGY | PHY_BRCM_AUTO_PWRDWN_ENABLE; - if (tp->tg3_flags3 & TG3_FLG3_RGMII_INBAND_DISABLE) + if (tg3_flag(tp, RGMII_INBAND_DISABLE)) phydev->dev_flags |= PHY_BRCM_STD_IBND_DISABLE; - if (tp->tg3_flags3 & TG3_FLG3_RGMII_EXT_IBND_RX_EN) + if (tg3_flag(tp, RGMII_EXT_IBND_RX_EN)) phydev->dev_flags |= PHY_BRCM_EXT_IBND_RX_ENABLE; - if (tp->tg3_flags3 & TG3_FLG3_RGMII_EXT_IBND_TX_EN) + if (tg3_flag(tp, RGMII_EXT_IBND_TX_EN)) phydev->dev_flags |= PHY_BRCM_EXT_IBND_TX_ENABLE; /* fallthru */ case PHY_ID_RTL8211C: @@ -1235,7 +1253,7 @@ static int tg3_mdio_init(struct tg3 *tp) break; } - tp->tg3_flags3 |= TG3_FLG3_MDIOBUS_INITED; + tg3_flag_set(tp, MDIOBUS_INITED); if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5785) tg3_mdio_config_5785(tp); @@ -1245,8 +1263,8 @@ static int tg3_mdio_init(struct tg3 *tp) static void tg3_mdio_fini(struct tg3 *tp) { - if (tp->tg3_flags3 & TG3_FLG3_MDIOBUS_INITED) { - tp->tg3_flags3 &= ~TG3_FLG3_MDIOBUS_INITED; + if (tg3_flag(tp, MDIOBUS_INITED)) { + tg3_flag_clear(tp, MDIOBUS_INITED); mdiobus_unregister(tp->mdio_bus); mdiobus_free(tp->mdio_bus); } @@ -1299,8 +1317,7 @@ static void tg3_ump_link_report(struct tg3 *tp) u32 reg; u32 val; - if (!(tp->tg3_flags2 & TG3_FLG2_5780_CLASS) || - !(tp->tg3_flags & TG3_FLAG_ENABLE_ASF)) + if (!tg3_flag(tp, 5780_CLASS) || !tg3_flag(tp, ENABLE_ASF)) return; tg3_wait_for_event_ack(tp); @@ -1430,13 +1447,12 @@ static void tg3_setup_flow_control(struct tg3 *tp, u32 lcladv, u32 rmtadv) u32 old_rx_mode = tp->rx_mode; u32 old_tx_mode = tp->tx_mode; - if (tp->tg3_flags3 & TG3_FLG3_USE_PHYLIB) + if (tg3_flag(tp, USE_PHYLIB)) autoneg = tp->mdio_bus->phy_map[TG3_PHY_MII_ADDR]->autoneg; else autoneg = tp->link_config.autoneg; - if (autoneg == AUTONEG_ENABLE && - (tp->tg3_flags & TG3_FLAG_PAUSE_AUTONEG)) { + if (autoneg == AUTONEG_ENABLE && tg3_flag(tp, PAUSE_AUTONEG)) { if (tp->phy_flags & TG3_PHYFLG_ANY_SERDES) flowctrl = tg3_resolve_flowctrl_1000X(lcladv, rmtadv); else @@ -1657,8 +1673,8 @@ static void tg3_phy_toggle_apd(struct tg3 *tp, bool enable) { u32 reg; - if (!(tp->tg3_flags2 & TG3_FLG2_5705_PLUS) || - ((tp->tg3_flags3 & TG3_FLG3_5717_PLUS) && + if (!tg3_flag(tp, 5705_PLUS) || + (tg3_flag(tp, 5717_PLUS) && (tp->phy_flags & TG3_PHYFLG_MII_SERDES))) return; @@ -1692,7 +1708,7 @@ static void tg3_phy_toggle_automdix(struct tg3 *tp, int enable) { u32 phy; - if (!(tp->tg3_flags2 & TG3_FLG2_5705_PLUS) || + if (!tg3_flag(tp, 5705_PLUS) || (tp->phy_flags & TG3_PHYFLG_ANY_SERDES)) return; @@ -2065,7 +2081,7 @@ static int tg3_phy_reset(struct tg3 *tp) } } - if ((tp->tg3_flags3 & TG3_FLG3_5717_PLUS) && + if (tg3_flag(tp, 5717_PLUS) && (tp->phy_flags & TG3_PHYFLG_MII_SERDES)) return 0; @@ -2115,7 +2131,7 @@ out: if ((tp->phy_id & TG3_PHY_ID_MASK) == TG3_PHY_ID_BCM5401) { /* Cannot do read-modify-write on 5401 */ tg3_phy_auxctl_write(tp, MII_TG3_AUXCTL_SHDWSEL_AUXCTL, 0x4c20); - } else if (tp->tg3_flags & TG3_FLAG_JUMBO_CAPABLE) { + } else if (tg3_flag(tp, JUMBO_CAPABLE)) { /* Set bit 14 with read-modify-write to preserve other bits */ err = tg3_phy_auxctl_read(tp, MII_TG3_AUXCTL_SHDWSEL_AUXCTL, &val); @@ -2127,7 +2143,7 @@ out: /* Set phy register 0x10 bit 0 to high fifo elasticity to support * jumbo frames transmission. */ - if (tp->tg3_flags & TG3_FLAG_JUMBO_CAPABLE) { + if (tg3_flag(tp, JUMBO_CAPABLE)) { if (!tg3_readphy(tp, MII_TG3_EXT_CTRL, &val)) tg3_writephy(tp, MII_TG3_EXT_CTRL, val | MII_TG3_EXT_CTRL_FIFO_ELASTIC); @@ -2148,7 +2164,7 @@ static void tg3_frob_aux_power(struct tg3 *tp) bool need_vaux = false; /* The GPIOs do something completely different on 57765. */ - if ((tp->tg3_flags2 & TG3_FLG2_IS_NIC) == 0 || + if (!tg3_flag(tp, IS_NIC) || GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5719 || GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57765) return; @@ -2166,17 +2182,16 @@ static void tg3_frob_aux_power(struct tg3 *tp) if (dev_peer) { struct tg3 *tp_peer = netdev_priv(dev_peer); - if (tp_peer->tg3_flags & TG3_FLAG_INIT_COMPLETE) + if (tg3_flag(tp_peer, INIT_COMPLETE)) return; - if ((tp_peer->tg3_flags & TG3_FLAG_WOL_ENABLE) || - (tp_peer->tg3_flags & TG3_FLAG_ENABLE_ASF)) + if (tg3_flag(tp_peer, WOL_ENABLE) || + tg3_flag(tp_peer, ENABLE_ASF)) need_vaux = true; } } - if ((tp->tg3_flags & TG3_FLAG_WOL_ENABLE) || - (tp->tg3_flags & TG3_FLAG_ENABLE_ASF)) + if (tg3_flag(tp, WOL_ENABLE) || tg3_flag(tp, ENABLE_ASF)) need_vaux = true; if (need_vaux) { @@ -2359,7 +2374,7 @@ static void tg3_power_down_phy(struct tg3 *tp, bool do_low_power) /* tp->lock is held. */ static int tg3_nvram_lock(struct tg3 *tp) { - if (tp->tg3_flags & TG3_FLAG_NVRAM) { + if (tg3_flag(tp, NVRAM)) { int i; if (tp->nvram_lock_cnt == 0) { @@ -2382,7 +2397,7 @@ static int tg3_nvram_lock(struct tg3 *tp) /* tp->lock is held. */ static void tg3_nvram_unlock(struct tg3 *tp) { - if (tp->tg3_flags & TG3_FLAG_NVRAM) { + if (tg3_flag(tp, NVRAM)) { if (tp->nvram_lock_cnt > 0) tp->nvram_lock_cnt--; if (tp->nvram_lock_cnt == 0) @@ -2393,8 +2408,7 @@ static void tg3_nvram_unlock(struct tg3 *tp) /* tp->lock is held. */ static void tg3_enable_nvram_access(struct tg3 *tp) { - if ((tp->tg3_flags2 & TG3_FLG2_5750_PLUS) && - !(tp->tg3_flags3 & TG3_FLG3_PROTECTED_NVRAM)) { + if (tg3_flag(tp, 5750_PLUS) && !tg3_flag(tp, PROTECTED_NVRAM)) { u32 nvaccess = tr32(NVRAM_ACCESS); tw32(NVRAM_ACCESS, nvaccess | ACCESS_ENABLE); @@ -2404,8 +2418,7 @@ static void tg3_enable_nvram_access(struct tg3 *tp) /* tp->lock is held. */ static void tg3_disable_nvram_access(struct tg3 *tp) { - if ((tp->tg3_flags2 & TG3_FLG2_5750_PLUS) && - !(tp->tg3_flags3 & TG3_FLG3_PROTECTED_NVRAM)) { + if (tg3_flag(tp, 5750_PLUS) && !tg3_flag(tp, PROTECTED_NVRAM)) { u32 nvaccess = tr32(NVRAM_ACCESS); tw32(NVRAM_ACCESS, nvaccess & ~ACCESS_ENABLE); @@ -2475,10 +2488,10 @@ static int tg3_nvram_exec_cmd(struct tg3 *tp, u32 nvram_cmd) static u32 tg3_nvram_phys_addr(struct tg3 *tp, u32 addr) { - if ((tp->tg3_flags & TG3_FLAG_NVRAM) && - (tp->tg3_flags & TG3_FLAG_NVRAM_BUFFERED) && - (tp->tg3_flags2 & TG3_FLG2_FLASH) && - !(tp->tg3_flags3 & TG3_FLG3_NO_NVRAM_ADDR_TRANS) && + if (tg3_flag(tp, NVRAM) && + tg3_flag(tp, NVRAM_BUFFERED) && + tg3_flag(tp, FLASH) && + !tg3_flag(tp, NO_NVRAM_ADDR_TRANS) && (tp->nvram_jedecnum == JEDEC_ATMEL)) addr = ((addr / tp->nvram_pagesize) << @@ -2490,10 +2503,10 @@ static u32 tg3_nvram_phys_addr(struct tg3 *tp, u32 addr) static u32 tg3_nvram_logical_addr(struct tg3 *tp, u32 addr) { - if ((tp->tg3_flags & TG3_FLAG_NVRAM) && - (tp->tg3_flags & TG3_FLAG_NVRAM_BUFFERED) && - (tp->tg3_flags2 & TG3_FLG2_FLASH) && - !(tp->tg3_flags3 & TG3_FLG3_NO_NVRAM_ADDR_TRANS) && + if (tg3_flag(tp, NVRAM) && + tg3_flag(tp, NVRAM_BUFFERED) && + tg3_flag(tp, FLASH) && + !tg3_flag(tp, NO_NVRAM_ADDR_TRANS) && (tp->nvram_jedecnum == JEDEC_ATMEL)) addr = ((addr >> ATMEL_AT45DB0X1B_PAGE_POS) * @@ -2513,7 +2526,7 @@ static int tg3_nvram_read(struct tg3 *tp, u32 offset, u32 *val) { int ret; - if (!(tp->tg3_flags & TG3_FLAG_NVRAM)) + if (!tg3_flag(tp, NVRAM)) return tg3_nvram_read_using_eeprom(tp, offset, val); offset = tg3_nvram_phys_addr(tp, offset); @@ -2605,7 +2618,7 @@ static int tg3_power_up(struct tg3 *tp) pci_set_power_state(tp->pdev, PCI_D0); /* Switch out of Vaux if it is a NIC */ - if (tp->tg3_flags2 & TG3_FLG2_IS_NIC) + if (tg3_flag(tp, IS_NIC)) tw32_wait_f(GRC_LOCAL_CTRL, tp->grc_local_ctrl, 100); return 0; @@ -2619,7 +2632,7 @@ static int tg3_power_down_prepare(struct tg3 *tp) tg3_enable_register_access(tp); /* Restore the CLKREQ setting. */ - if (tp->tg3_flags3 & TG3_FLG3_CLKREQ_BUG) { + if (tg3_flag(tp, CLKREQ_BUG)) { u16 lnkctl; pci_read_config_word(tp->pdev, @@ -2636,9 +2649,9 @@ static int tg3_power_down_prepare(struct tg3 *tp) misc_host_ctrl | MISC_HOST_CTRL_MASK_PCI_INT); device_should_wake = device_may_wakeup(&tp->pdev->dev) && - (tp->tg3_flags & TG3_FLAG_WOL_ENABLE); + tg3_flag(tp, WOL_ENABLE); - if (tp->tg3_flags3 & TG3_FLG3_USE_PHYLIB) { + if (tg3_flag(tp, USE_PHYLIB)) { do_low_power = false; if ((tp->phy_flags & TG3_PHYFLG_IS_CONNECTED) && !(tp->phy_flags & TG3_PHYFLG_IS_LOW_POWER)) { @@ -2659,9 +2672,8 @@ static int tg3_power_down_prepare(struct tg3 *tp) ADVERTISED_Autoneg | ADVERTISED_10baseT_Half; - if ((tp->tg3_flags & TG3_FLAG_ENABLE_ASF) || - device_should_wake) { - if (tp->tg3_flags & TG3_FLAG_WOL_SPEED_100MB) + if (tg3_flag(tp, ENABLE_ASF) || device_should_wake) { + if (tg3_flag(tp, WOL_SPEED_100MB)) advertising |= ADVERTISED_100baseT_Half | ADVERTISED_100baseT_Full | @@ -2706,7 +2718,7 @@ static int tg3_power_down_prepare(struct tg3 *tp) val = tr32(GRC_VCPU_EXT_CTRL); tw32(GRC_VCPU_EXT_CTRL, val | GRC_VCPU_EXT_CTRL_DISABLE_WOL); - } else if (!(tp->tg3_flags & TG3_FLAG_ENABLE_ASF)) { + } else if (!tg3_flag(tp, ENABLE_ASF)) { int i; u32 val; @@ -2717,7 +2729,7 @@ static int tg3_power_down_prepare(struct tg3 *tp) msleep(1); } } - if (tp->tg3_flags & TG3_FLAG_WOL_CAP) + if (tg3_flag(tp, WOL_CAP)) tg3_write_mem(tp, NIC_SRAM_WOL_MBOX, WOL_SIGNATURE | WOL_DRV_STATE_SHUTDOWN | WOL_DRV_WOL | @@ -2745,8 +2757,7 @@ static int tg3_power_down_prepare(struct tg3 *tp) mac_mode |= tp->mac_mode & MAC_MODE_LINK_POLARITY; if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5700) { - u32 speed = (tp->tg3_flags & - TG3_FLAG_WOL_SPEED_100MB) ? + u32 speed = tg3_flag(tp, WOL_SPEED_100MB) ? SPEED_100 : SPEED_10; if (tg3_5700_link_polarity(tp, speed)) mac_mode |= MAC_MODE_LINK_POLARITY; @@ -2757,17 +2768,15 @@ static int tg3_power_down_prepare(struct tg3 *tp) mac_mode = MAC_MODE_PORT_MODE_TBI; } - if (!(tp->tg3_flags2 & TG3_FLG2_5750_PLUS)) + if (!tg3_flag(tp, 5750_PLUS)) tw32(MAC_LED_CTRL, tp->led_ctrl); mac_mode |= MAC_MODE_MAGIC_PKT_ENABLE; - if (((tp->tg3_flags2 & TG3_FLG2_5705_PLUS) && - !(tp->tg3_flags2 & TG3_FLG2_5780_CLASS)) && - ((tp->tg3_flags & TG3_FLAG_ENABLE_ASF) || - (tp->tg3_flags3 & TG3_FLG3_ENABLE_APE))) + if ((tg3_flag(tp, 5705_PLUS) && !tg3_flag(tp, 5780_CLASS)) && + (tg3_flag(tp, ENABLE_ASF) || tg3_flag(tp, ENABLE_APE))) mac_mode |= MAC_MODE_KEEP_FRAME_IN_WOL; - if (tp->tg3_flags3 & TG3_FLG3_ENABLE_APE) + if (tg3_flag(tp, ENABLE_APE)) mac_mode |= MAC_MODE_APE_TX_EN | MAC_MODE_APE_RX_EN | MAC_MODE_TDE_ENABLE; @@ -2779,7 +2788,7 @@ static int tg3_power_down_prepare(struct tg3 *tp) udelay(10); } - if (!(tp->tg3_flags & TG3_FLAG_WOL_SPEED_100MB) && + if (!tg3_flag(tp, WOL_SPEED_100MB) && (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5700 || GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5701)) { u32 base_val; @@ -2790,12 +2799,11 @@ static int tg3_power_down_prepare(struct tg3 *tp) tw32_wait_f(TG3PCI_CLOCK_CTRL, base_val | CLOCK_CTRL_ALTCLK | CLOCK_CTRL_PWRDOWN_PLL133, 40); - } else if ((tp->tg3_flags2 & TG3_FLG2_5780_CLASS) || - (tp->tg3_flags & TG3_FLAG_CPMU_PRESENT) || + } else if (tg3_flag(tp, 5780_CLASS) || + tg3_flag(tp, CPMU_PRESENT) || (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906)) { /* do nothing */ - } else if (!((tp->tg3_flags2 & TG3_FLG2_5750_PLUS) && - (tp->tg3_flags & TG3_FLAG_ENABLE_ASF))) { + } else if (!(tg3_flag(tp, 5750_PLUS) && tg3_flag(tp, ENABLE_ASF))) { u32 newbits1, newbits2; if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5700 || @@ -2804,7 +2812,7 @@ static int tg3_power_down_prepare(struct tg3 *tp) CLOCK_CTRL_TXCLK_DISABLE | CLOCK_CTRL_ALTCLK); newbits2 = newbits1 | CLOCK_CTRL_44MHZ_CORE; - } else if (tp->tg3_flags2 & TG3_FLG2_5705_PLUS) { + } else if (tg3_flag(tp, 5705_PLUS)) { newbits1 = CLOCK_CTRL_625_CORE; newbits2 = newbits1 | CLOCK_CTRL_ALTCLK; } else { @@ -2818,7 +2826,7 @@ static int tg3_power_down_prepare(struct tg3 *tp) tw32_wait_f(TG3PCI_CLOCK_CTRL, tp->pci_clock_ctrl | newbits2, 40); - if (!(tp->tg3_flags2 & TG3_FLG2_5705_PLUS)) { + if (!tg3_flag(tp, 5705_PLUS)) { u32 newbits3; if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5700 || @@ -2835,8 +2843,7 @@ static int tg3_power_down_prepare(struct tg3 *tp) } } - if (!(device_should_wake) && - !(tp->tg3_flags & TG3_FLAG_ENABLE_ASF)) + if (!(device_should_wake) && !tg3_flag(tp, ENABLE_ASF)) tg3_power_down_phy(tp, do_low_power); tg3_frob_aux_power(tp); @@ -2848,7 +2855,7 @@ static int tg3_power_down_prepare(struct tg3 *tp) val &= ~((1 << 16) | (1 << 4) | (1 << 2) | (1 << 1) | 1); tw32(0x7d00, val); - if (!(tp->tg3_flags & TG3_FLAG_ENABLE_ASF)) { + if (!tg3_flag(tp, ENABLE_ASF)) { int err; err = tg3_nvram_lock(tp); @@ -2867,7 +2874,7 @@ static void tg3_power_down(struct tg3 *tp) { tg3_power_down_prepare(tp); - pci_wake_from_d3(tp->pdev, tp->tg3_flags & TG3_FLAG_WOL_ENABLE); + pci_wake_from_d3(tp->pdev, tg3_flag(tp, WOL_ENABLE)); pci_set_power_state(tp->pdev, PCI_D3hot); } @@ -2931,7 +2938,7 @@ static void tg3_phy_copper_begin(struct tg3 *tp) new_adv = (ADVERTISE_10HALF | ADVERTISE_10FULL | ADVERTISE_CSMA | ADVERTISE_PAUSE_CAP); - if (tp->tg3_flags & TG3_FLAG_WOL_SPEED_100MB) + if (tg3_flag(tp, WOL_SPEED_100MB)) new_adv |= (ADVERTISE_100HALF | ADVERTISE_100FULL); tg3_writephy(tp, MII_ADVERTISE, new_adv); @@ -3163,7 +3170,7 @@ static int tg3_adv_1000T_flowctrl_ok(struct tg3 *tp, u32 *lcladv, u32 *rmtadv) if (curadv != reqadv) return 0; - if (tp->tg3_flags & TG3_FLAG_PAUSE_AUTONEG) + if (tg3_flag(tp, PAUSE_AUTONEG)) tg3_readphy(tp, MII_LPA, rmtadv); } else { /* Reprogram the advertisement register, even if it @@ -3226,7 +3233,7 @@ static int tg3_setup_copper_phy(struct tg3 *tp, int force_reset) if ((tp->phy_id & TG3_PHY_ID_MASK) == TG3_PHY_ID_BCM5401) { tg3_readphy(tp, MII_BMSR, &bmsr); if (tg3_readphy(tp, MII_BMSR, &bmsr) || - !(tp->tg3_flags & TG3_FLAG_INIT_COMPLETE)) + !tg3_flag(tp, INIT_COMPLETE)) bmsr = 0; if (!(bmsr & BMSR_LSTATUS)) { @@ -3410,7 +3417,7 @@ relink: tg3_phy_eee_adjust(tp, current_link_up); - if (tp->tg3_flags & TG3_FLAG_USE_LINKCHG_REG) { + if (tg3_flag(tp, USE_LINKCHG_REG)) { /* Polled via timer. */ tw32_f(MAC_EVENT, 0); } else { @@ -3421,8 +3428,7 @@ relink: if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5700 && current_link_up == 1 && tp->link_config.active_speed == SPEED_1000 && - ((tp->tg3_flags & TG3_FLAG_PCIX_MODE) || - (tp->tg3_flags & TG3_FLAG_PCI_HIGH_SPEED))) { + (tg3_flag(tp, PCIX_MODE) || tg3_flag(tp, PCI_HIGH_SPEED))) { udelay(120); tw32_f(MAC_STATUS, (MAC_STATUS_SYNC_CHANGED | @@ -3434,7 +3440,7 @@ relink: } /* Prevent send BD corruption. */ - if (tp->tg3_flags3 & TG3_FLG3_CLKREQ_BUG) { + if (tg3_flag(tp, CLKREQ_BUG)) { u16 oldlnkctl, newlnkctl; pci_read_config_word(tp->pdev, @@ -3829,7 +3835,7 @@ static void tg3_init_bcm8002(struct tg3 *tp) int i; /* Reset when initting first time or we have a link. */ - if ((tp->tg3_flags & TG3_FLAG_INIT_COMPLETE) && + if (tg3_flag(tp, INIT_COMPLETE) && !(mac_status & MAC_STATUS_PCS_SYNCED)) return; @@ -4090,9 +4096,9 @@ static int tg3_setup_fiber_phy(struct tg3 *tp, int force_reset) orig_active_speed = tp->link_config.active_speed; orig_active_duplex = tp->link_config.active_duplex; - if (!(tp->tg3_flags2 & TG3_FLG2_HW_AUTONEG) && + if (!tg3_flag(tp, HW_AUTONEG) && netif_carrier_ok(tp->dev) && - (tp->tg3_flags & TG3_FLAG_INIT_COMPLETE)) { + tg3_flag(tp, INIT_COMPLETE)) { mac_status = tr32(MAC_STATUS); mac_status &= (MAC_STATUS_PCS_SYNCED | MAC_STATUS_SIGNAL_DET | @@ -4123,7 +4129,7 @@ static int tg3_setup_fiber_phy(struct tg3 *tp, int force_reset) current_link_up = 0; mac_status = tr32(MAC_STATUS); - if (tp->tg3_flags2 & TG3_FLG2_HW_AUTONEG) + if (tg3_flag(tp, HW_AUTONEG)) current_link_up = tg3_setup_fiber_hw_autoneg(tp, mac_status); else current_link_up = tg3_setup_fiber_by_hand(tp, mac_status); @@ -4322,7 +4328,7 @@ static int tg3_setup_fiber_mii_phy(struct tg3 *tp, int force_reset) current_duplex = DUPLEX_FULL; else current_duplex = DUPLEX_HALF; - } else if (!(tp->tg3_flags2 & TG3_FLG2_5780_CLASS)) { + } else if (!tg3_flag(tp, 5780_CLASS)) { /* Link is up via parallel detect */ } else { current_link_up = 0; @@ -4460,7 +4466,7 @@ static int tg3_setup_phy(struct tg3 *tp, int force_reset) tw32(MAC_TX_LENGTHS, val | (32 << TX_LENGTHS_SLOT_TIME_SHIFT)); - if (!(tp->tg3_flags2 & TG3_FLG2_5705_PLUS)) { + if (!tg3_flag(tp, 5705_PLUS)) { if (netif_carrier_ok(tp->dev)) { tw32(HOSTCC_STAT_COAL_TICKS, tp->coal.stats_block_coalesce_usecs); @@ -4469,7 +4475,7 @@ static int tg3_setup_phy(struct tg3 *tp, int force_reset) } } - if (tp->tg3_flags & TG3_FLAG_ASPM_WORKAROUND) { + if (tg3_flag(tp, ASPM_WORKAROUND)) { val = tr32(PCIE_PWR_MGMT_THRESH); if (!netif_carrier_ok(tp->dev)) val = (val & ~PCIE_PWR_MGMT_L1_THRESH_MSK) | @@ -4518,7 +4524,7 @@ static void tg3_dump_legacy_regs(struct tg3 *tp, u32 *regs) tg3_rd32_loop(tp, regs, MBFREE_MODE, 0x08); tg3_rd32_loop(tp, regs, HOSTCC_MODE, 0x100); - if (tp->tg3_flags & TG3_FLAG_SUPPORT_MSIX) + if (tg3_flag(tp, SUPPORT_MSIX)) tg3_rd32_loop(tp, regs, HOSTCC_RXCOL_TICKS_VEC1, 0x180); tg3_rd32_loop(tp, regs, MEMARB_MODE, 0x10); @@ -4530,7 +4536,7 @@ static void tg3_dump_legacy_regs(struct tg3 *tp, u32 *regs) tg3_rd32_loop(tp, regs, RX_CPU_PGMCTR, 0x04); tg3_rd32_loop(tp, regs, RX_CPU_HWBKPT, 0x04); - if (!(tp->tg3_flags2 & TG3_FLG2_5705_PLUS)) { + if (!tg3_flag(tp, 5705_PLUS)) { tg3_rd32_loop(tp, regs, TX_CPU_MODE, 0x04); tg3_rd32_loop(tp, regs, TX_CPU_STATE, 0x04); tg3_rd32_loop(tp, regs, TX_CPU_PGMCTR, 0x04); @@ -4542,7 +4548,7 @@ static void tg3_dump_legacy_regs(struct tg3 *tp, u32 *regs) tg3_rd32_loop(tp, regs, DMAC_MODE, 0x04); tg3_rd32_loop(tp, regs, GRC_MODE, 0x4c); - if (tp->tg3_flags & TG3_FLAG_NVRAM) + if (tg3_flag(tp, NVRAM)) tg3_rd32_loop(tp, regs, NVRAM_CMD, 0x24); } @@ -4557,7 +4563,7 @@ static void tg3_dump_state(struct tg3 *tp) return; } - if (tp->tg3_flags2 & TG3_FLG2_PCI_EXPRESS) { + if (tg3_flag(tp, PCI_EXPRESS)) { /* Read up to but not including private PCI registers */ for (i = 0; i < TG3_PCIE_TLDLPL_PORT; i += sizeof(u32)) regs[i / sizeof(u32)] = tr32(i); @@ -4612,7 +4618,7 @@ static void tg3_dump_state(struct tg3 *tp) */ static void tg3_tx_recover(struct tg3 *tp) { - BUG_ON((tp->tg3_flags & TG3_FLAG_MBOX_WRITE_REORDER) || + BUG_ON(tg3_flag(tp, MBOX_WRITE_REORDER) || tp->write32_tx_mbox == tg3_write_indirect_mbox); netdev_warn(tp->dev, @@ -4622,7 +4628,7 @@ static void tg3_tx_recover(struct tg3 *tp) "and include system chipset information.\n"); spin_lock(&tp->lock); - tp->tg3_flags |= TG3_FLAG_TX_RECOVERY_PENDING; + tg3_flag_set(tp, TX_RECOVERY_PENDING); spin_unlock(&tp->lock); } @@ -4646,7 +4652,7 @@ static void tg3_tx(struct tg3_napi *tnapi) struct netdev_queue *txq; int index = tnapi - tp->napi; - if (tp->tg3_flags3 & TG3_FLG3_ENABLE_TSS) + if (tg3_flag(tp, ENABLE_TSS)) index--; txq = netdev_get_tx_queue(tp->dev, index); @@ -5014,7 +5020,7 @@ next_pkt_nopost: tw32_rx_mbox(tnapi->consmbox, sw_idx); /* Refill RX ring(s). */ - if (!(tp->tg3_flags3 & TG3_FLG3_ENABLE_RSS)) { + if (!tg3_flag(tp, ENABLE_RSS)) { if (work_mask & RXD_OPAQUE_RING_STD) { tpr->rx_std_prod_idx = std_prod_idx & tp->rx_std_ring_mask; @@ -5047,16 +5053,14 @@ next_pkt_nopost: static void tg3_poll_link(struct tg3 *tp) { /* handle link change and other phy events */ - if (!(tp->tg3_flags & - (TG3_FLAG_USE_LINKCHG_REG | - TG3_FLAG_POLL_SERDES))) { + if (!(tg3_flag(tp, USE_LINKCHG_REG) || tg3_flag(tp, POLL_SERDES))) { struct tg3_hw_status *sblk = tp->napi[0].hw_status; if (sblk->status & SD_STATUS_LINK_CHG) { sblk->status = SD_STATUS_UPDATED | (sblk->status & ~SD_STATUS_LINK_CHG); spin_lock(&tp->lock); - if (tp->tg3_flags3 & TG3_FLG3_USE_PHYLIB) { + if (tg3_flag(tp, USE_PHYLIB)) { tw32_f(MAC_STATUS, (MAC_STATUS_SYNC_CHANGED | MAC_STATUS_CFG_CHANGED | @@ -5203,7 +5207,7 @@ static int tg3_poll_work(struct tg3_napi *tnapi, int work_done, int budget) /* run TX completion thread */ if (tnapi->hw_status->idx[0].tx_consumer != tnapi->tx_cons) { tg3_tx(tnapi); - if (unlikely(tp->tg3_flags & TG3_FLAG_TX_RECOVERY_PENDING)) + if (unlikely(tg3_flag(tp, TX_RECOVERY_PENDING))) return work_done; } @@ -5214,7 +5218,7 @@ static int tg3_poll_work(struct tg3_napi *tnapi, int work_done, int budget) if (*(tnapi->rx_rcb_prod_idx) != tnapi->rx_rcb_ptr) work_done += tg3_rx(tnapi, budget - work_done); - if ((tp->tg3_flags3 & TG3_FLG3_ENABLE_RSS) && tnapi == &tp->napi[1]) { + if (tg3_flag(tp, ENABLE_RSS) && tnapi == &tp->napi[1]) { struct tg3_rx_prodring_set *dpr = &tp->napi[0].prodring; int i, err = 0; u32 std_prod_idx = dpr->rx_std_prod_idx; @@ -5253,7 +5257,7 @@ static int tg3_poll_msix(struct napi_struct *napi, int budget) while (1) { work_done = tg3_poll_work(tnapi, work_done, budget); - if (unlikely(tp->tg3_flags & TG3_FLAG_TX_RECOVERY_PENDING)) + if (unlikely(tg3_flag(tp, TX_RECOVERY_PENDING))) goto tx_recovery; if (unlikely(work_done >= budget)) @@ -5292,7 +5296,7 @@ static void tg3_process_error(struct tg3 *tp) u32 val; bool real_error = false; - if (tp->tg3_flags & TG3_FLAG_ERROR_PROCESSED) + if (tg3_flag(tp, ERROR_PROCESSED)) return; /* Check Flow Attention register */ @@ -5317,7 +5321,7 @@ static void tg3_process_error(struct tg3 *tp) tg3_dump_state(tp); - tp->tg3_flags |= TG3_FLAG_ERROR_PROCESSED; + tg3_flag_set(tp, ERROR_PROCESSED); schedule_work(&tp->reset_task); } @@ -5336,13 +5340,13 @@ static int tg3_poll(struct napi_struct *napi, int budget) work_done = tg3_poll_work(tnapi, work_done, budget); - if (unlikely(tp->tg3_flags & TG3_FLAG_TX_RECOVERY_PENDING)) + if (unlikely(tg3_flag(tp, TX_RECOVERY_PENDING))) goto tx_recovery; if (unlikely(work_done >= budget)) break; - if (tp->tg3_flags & TG3_FLAG_TAGGED_STATUS) { + if (tg3_flag(tp, TAGGED_STATUS)) { /* tp->last_tag is used in tg3_int_reenable() below * to tell the hw how much work has been processed, * so we must read it before checking for more work. @@ -5509,7 +5513,7 @@ static irqreturn_t tg3_interrupt(int irq, void *dev_id) * interrupt is ours and will flush the status block. */ if (unlikely(!(sblk->status & SD_STATUS_UPDATED))) { - if ((tp->tg3_flags & TG3_FLAG_CHIP_RESETTING) || + if (tg3_flag(tp, CHIP_RESETTING) || (tr32(TG3PCI_PCISTATE) & PCISTATE_INT_NOT_ACTIVE)) { handled = 0; goto out; @@ -5558,7 +5562,7 @@ static irqreturn_t tg3_interrupt_tagged(int irq, void *dev_id) * interrupt is ours and will flush the status block. */ if (unlikely(sblk->status_tag == tnapi->last_irq_tag)) { - if ((tp->tg3_flags & TG3_FLAG_CHIP_RESETTING) || + if (tg3_flag(tp, CHIP_RESETTING) || (tr32(TG3PCI_PCISTATE) & PCISTATE_INT_NOT_ACTIVE)) { handled = 0; goto out; @@ -5671,14 +5675,14 @@ static void tg3_reset_task(struct work_struct *work) tg3_full_lock(tp, 1); - restart_timer = tp->tg3_flags2 & TG3_FLG2_RESTART_TIMER; - tp->tg3_flags2 &= ~TG3_FLG2_RESTART_TIMER; + restart_timer = tg3_flag(tp, RESTART_TIMER); + tg3_flag_clear(tp, RESTART_TIMER); - if (tp->tg3_flags & TG3_FLAG_TX_RECOVERY_PENDING) { + if (tg3_flag(tp, TX_RECOVERY_PENDING)) { tp->write32_tx_mbox = tg3_write32_tx_mbox; tp->write32_rx_mbox = tg3_write_flush_reg32; - tp->tg3_flags |= TG3_FLAG_MBOX_WRITE_REORDER; - tp->tg3_flags &= ~TG3_FLAG_TX_RECOVERY_PENDING; + tg3_flag_set(tp, MBOX_WRITE_REORDER); + tg3_flag_clear(tp, TX_RECOVERY_PENDING); } tg3_halt(tp, RESET_KIND_SHUTDOWN, 0); @@ -5723,7 +5727,7 @@ static inline int tg3_40bit_overflow_test(struct tg3 *tp, dma_addr_t mapping, int len) { #if defined(CONFIG_HIGHMEM) && (BITS_PER_LONG == 64) - if (tp->tg3_flags & TG3_FLAG_40BIT_DMA_BUG) + if (tg3_flag(tp, 40BIT_DMA_BUG)) return ((u64) mapping + len) > DMA_BIT_MASK(40); return 0; #else @@ -5770,8 +5774,8 @@ static int tigon3_dma_hwbug_workaround(struct tg3_napi *tnapi, /* Make sure new skb does not cross any 4G boundaries. * Drop the packet if it does. */ - } else if ((tp->tg3_flags3 & TG3_FLG3_4G_DMA_BNDRY_BUG) && - tg3_4g_overflow_test(new_addr, new_skb->len)) { + } else if (tg3_flag(tp, 4G_DMA_BNDRY_BUG) && + tg3_4g_overflow_test(new_addr, new_skb->len)) { pci_unmap_single(tp->pdev, new_addr, new_skb->len, PCI_DMA_TODEVICE); ret = -1; @@ -5838,7 +5842,7 @@ static void tg3_set_txd(struct tg3_napi *tnapi, int entry, } /* hard_start_xmit for devices that don't have any bugs and - * support TG3_FLG2_HW_TSO_2 and TG3_FLG2_HW_TSO_3 only. + * support TG3_FLAG_HW_TSO_2 and TG3_FLAG_HW_TSO_3 only. */ static netdev_tx_t tg3_start_xmit(struct sk_buff *skb, struct net_device *dev) @@ -5852,7 +5856,7 @@ static netdev_tx_t tg3_start_xmit(struct sk_buff *skb, txq = netdev_get_tx_queue(dev, skb_get_queue_mapping(skb)); tnapi = &tp->napi[skb_get_queue_mapping(skb)]; - if (tp->tg3_flags3 & TG3_FLG3_ENABLE_TSS) + if (tg3_flag(tp, ENABLE_TSS)) tnapi++; /* We are running in BH disabled context with netif_tx_lock @@ -5897,7 +5901,7 @@ static netdev_tx_t tg3_start_xmit(struct sk_buff *skb, hdrlen = ip_tcp_len + tcp_opt_len; } - if (tp->tg3_flags2 & TG3_FLG2_HW_TSO_3) { + if (tg3_flag(tp, HW_TSO_3)) { mss |= (hdrlen & 0xc) << 12; if (hdrlen & 0x10) base_flags |= 0x00000010; @@ -5930,7 +5934,7 @@ static netdev_tx_t tg3_start_xmit(struct sk_buff *skb, tnapi->tx_buffers[entry].skb = skb; dma_unmap_addr_set(&tnapi->tx_buffers[entry], mapping, mapping); - if ((tp->tg3_flags3 & TG3_FLG3_USE_JUMBO_BDFLAG) && + if (tg3_flag(tp, USE_JUMBO_BDFLAG) && !mss && skb->len > VLAN_ETH_FRAME_LEN) base_flags |= TXD_FLAG_JMB_PKT; @@ -6053,7 +6057,7 @@ tg3_tso_bug_end: } /* hard_start_xmit for devices that have the 4G bug and/or 40-bit bug and - * support TG3_FLG2_HW_TSO_1 or firmware TSO only. + * support TG3_FLAG_HW_TSO_1 or firmware TSO only. */ static netdev_tx_t tg3_start_xmit_dma_bug(struct sk_buff *skb, struct net_device *dev) @@ -6068,7 +6072,7 @@ static netdev_tx_t tg3_start_xmit_dma_bug(struct sk_buff *skb, txq = netdev_get_tx_queue(dev, skb_get_queue_mapping(skb)); tnapi = &tp->napi[skb_get_queue_mapping(skb)]; - if (tp->tg3_flags3 & TG3_FLG3_ENABLE_TSS) + if (tg3_flag(tp, ENABLE_TSS)) tnapi++; /* We are running in BH disabled context with netif_tx_lock @@ -6119,13 +6123,15 @@ static netdev_tx_t tg3_start_xmit_dma_bug(struct sk_buff *skb, } if (unlikely((ETH_HLEN + hdr_len) > 80) && - (tp->tg3_flags2 & TG3_FLG2_TSO_BUG)) + tg3_flag(tp, TSO_BUG)) return tg3_tso_bug(tp, skb); base_flags |= (TXD_FLAG_CPU_PRE_DMA | TXD_FLAG_CPU_POST_DMA); - if (tp->tg3_flags2 & TG3_FLG2_HW_TSO) { + if (tg3_flag(tp, HW_TSO_1) || + tg3_flag(tp, HW_TSO_2) || + tg3_flag(tp, HW_TSO_3)) { tcp_hdr(skb)->check = 0; base_flags &= ~TXD_FLAG_TCPUDP_CSUM; } else @@ -6134,14 +6140,14 @@ static netdev_tx_t tg3_start_xmit_dma_bug(struct sk_buff *skb, IPPROTO_TCP, 0); - if (tp->tg3_flags2 & TG3_FLG2_HW_TSO_3) { + if (tg3_flag(tp, HW_TSO_3)) { mss |= (hdr_len & 0xc) << 12; if (hdr_len & 0x10) base_flags |= 0x00000010; base_flags |= (hdr_len & 0x3e0) << 5; - } else if (tp->tg3_flags2 & TG3_FLG2_HW_TSO_2) + } else if (tg3_flag(tp, HW_TSO_2)) mss |= hdr_len << 9; - else if ((tp->tg3_flags2 & TG3_FLG2_HW_TSO_1) || + else if (tg3_flag(tp, HW_TSO_1) || GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5705) { if (tcp_opt_len || iph->ihl > 5) { int tsflags; @@ -6163,7 +6169,7 @@ static netdev_tx_t tg3_start_xmit_dma_bug(struct sk_buff *skb, base_flags |= (TXD_FLAG_VLAN | (vlan_tx_tag_get(skb) << 16)); - if ((tp->tg3_flags3 & TG3_FLG3_USE_JUMBO_BDFLAG) && + if (tg3_flag(tp, USE_JUMBO_BDFLAG) && !mss && skb->len > VLAN_ETH_FRAME_LEN) base_flags |= TXD_FLAG_JMB_PKT; @@ -6180,18 +6186,18 @@ static netdev_tx_t tg3_start_xmit_dma_bug(struct sk_buff *skb, would_hit_hwbug = 0; - if ((tp->tg3_flags3 & TG3_FLG3_SHORT_DMA_BUG) && len <= 8) + if (tg3_flag(tp, SHORT_DMA_BUG) && len <= 8) would_hit_hwbug = 1; - if ((tp->tg3_flags3 & TG3_FLG3_4G_DMA_BNDRY_BUG) && + if (tg3_flag(tp, 4G_DMA_BNDRY_BUG) && tg3_4g_overflow_test(mapping, len)) would_hit_hwbug = 1; - if ((tp->tg3_flags3 & TG3_FLG3_40BIT_DMA_LIMIT_BUG) && + if (tg3_flag(tp, 40BIT_DMA_LIMIT_BUG) && tg3_40bit_overflow_test(tp, mapping, len)) would_hit_hwbug = 1; - if (tp->tg3_flags3 & TG3_FLG3_5701_DMA_BUG) + if (tg3_flag(tp, 5701_DMA_BUG)) would_hit_hwbug = 1; tg3_set_txd(tnapi, entry, mapping, len, base_flags, @@ -6217,19 +6223,21 @@ static netdev_tx_t tg3_start_xmit_dma_bug(struct sk_buff *skb, if (pci_dma_mapping_error(tp->pdev, mapping)) goto dma_error; - if ((tp->tg3_flags3 & TG3_FLG3_SHORT_DMA_BUG) && + if (tg3_flag(tp, SHORT_DMA_BUG) && len <= 8) would_hit_hwbug = 1; - if ((tp->tg3_flags3 & TG3_FLG3_4G_DMA_BNDRY_BUG) && + if (tg3_flag(tp, 4G_DMA_BNDRY_BUG) && tg3_4g_overflow_test(mapping, len)) would_hit_hwbug = 1; - if ((tp->tg3_flags3 & TG3_FLG3_40BIT_DMA_LIMIT_BUG) && + if (tg3_flag(tp, 40BIT_DMA_LIMIT_BUG) && tg3_40bit_overflow_test(tp, mapping, len)) would_hit_hwbug = 1; - if (tp->tg3_flags2 & TG3_FLG2_HW_TSO) + if (tg3_flag(tp, HW_TSO_1) || + tg3_flag(tp, HW_TSO_2) || + tg3_flag(tp, HW_TSO_3)) tg3_set_txd(tnapi, entry, mapping, len, base_flags, (i == last)|(mss << 1)); else @@ -6305,7 +6313,7 @@ static u32 tg3_fix_features(struct net_device *dev, u32 features) { struct tg3 *tp = netdev_priv(dev); - if (dev->mtu > ETH_DATA_LEN && (tp->tg3_flags2 & TG3_FLG2_5780_CLASS)) + if (dev->mtu > ETH_DATA_LEN && tg3_flag(tp, 5780_CLASS)) features &= ~NETIF_F_ALL_TSO; return features; @@ -6317,18 +6325,18 @@ static inline void tg3_set_mtu(struct net_device *dev, struct tg3 *tp, dev->mtu = new_mtu; if (new_mtu > ETH_DATA_LEN) { - if (tp->tg3_flags2 & TG3_FLG2_5780_CLASS) { + if (tg3_flag(tp, 5780_CLASS)) { netdev_update_features(dev); - tp->tg3_flags2 &= ~TG3_FLG2_TSO_CAPABLE; + tg3_flag_clear(tp, TSO_CAPABLE); } else { - tp->tg3_flags |= TG3_FLAG_JUMBO_RING_ENABLE; + tg3_flag_set(tp, JUMBO_RING_ENABLE); } } else { - if (tp->tg3_flags2 & TG3_FLG2_5780_CLASS) { - tp->tg3_flags2 |= TG3_FLG2_TSO_CAPABLE; + if (tg3_flag(tp, 5780_CLASS)) { + tg3_flag_set(tp, TSO_CAPABLE); netdev_update_features(dev); } - tp->tg3_flags &= ~TG3_FLAG_JUMBO_RING_ENABLE; + tg3_flag_clear(tp, JUMBO_RING_ENABLE); } } @@ -6382,7 +6390,7 @@ static void tg3_rx_prodring_free(struct tg3 *tp, tg3_rx_skb_free(tp, &tpr->rx_std_buffers[i], tp->rx_pkt_map_sz); - if (tp->tg3_flags & TG3_FLAG_JUMBO_CAPABLE) { + if (tg3_flag(tp, JUMBO_CAPABLE)) { for (i = tpr->rx_jmb_cons_idx; i != tpr->rx_jmb_prod_idx; i = (i + 1) & tp->rx_jmb_ring_mask) { @@ -6398,8 +6406,7 @@ static void tg3_rx_prodring_free(struct tg3 *tp, tg3_rx_skb_free(tp, &tpr->rx_std_buffers[i], tp->rx_pkt_map_sz); - if ((tp->tg3_flags & TG3_FLAG_JUMBO_CAPABLE) && - !(tp->tg3_flags2 & TG3_FLG2_5780_CLASS)) { + if (tg3_flag(tp, JUMBO_CAPABLE) && !tg3_flag(tp, 5780_CLASS)) { for (i = 0; i <= tp->rx_jmb_ring_mask; i++) tg3_rx_skb_free(tp, &tpr->rx_jmb_buffers[i], TG3_RX_JMB_MAP_SZ); @@ -6436,7 +6443,7 @@ static int tg3_rx_prodring_alloc(struct tg3 *tp, memset(tpr->rx_std, 0, TG3_RX_STD_RING_BYTES(tp)); rx_pkt_dma_sz = TG3_RX_STD_DMA_SZ; - if ((tp->tg3_flags2 & TG3_FLG2_5780_CLASS) && + if (tg3_flag(tp, 5780_CLASS) && tp->dev->mtu > ETH_DATA_LEN) rx_pkt_dma_sz = TG3_RX_JMB_DMA_SZ; tp->rx_pkt_map_sz = TG3_RX_DMA_TO_MAP_SZ(rx_pkt_dma_sz); @@ -6469,13 +6476,12 @@ static int tg3_rx_prodring_alloc(struct tg3 *tp, } } - if (!(tp->tg3_flags & TG3_FLAG_JUMBO_CAPABLE) || - (tp->tg3_flags2 & TG3_FLG2_5780_CLASS)) + if (!tg3_flag(tp, JUMBO_CAPABLE) || tg3_flag(tp, 5780_CLASS)) goto done; memset(tpr->rx_jmb, 0, TG3_RX_JMB_RING_BYTES(tp)); - if (!(tp->tg3_flags & TG3_FLAG_JUMBO_RING_ENABLE)) + if (!tg3_flag(tp, JUMBO_RING_ENABLE)) goto done; for (i = 0; i <= tp->rx_jmb_ring_mask; i++) { @@ -6544,8 +6550,7 @@ static int tg3_rx_prodring_init(struct tg3 *tp, if (!tpr->rx_std) goto err_out; - if ((tp->tg3_flags & TG3_FLAG_JUMBO_CAPABLE) && - !(tp->tg3_flags2 & TG3_FLG2_5780_CLASS)) { + if (tg3_flag(tp, JUMBO_CAPABLE) && !tg3_flag(tp, 5780_CLASS)) { tpr->rx_jmb_buffers = kzalloc(TG3_RX_JMB_BUFF_RING_SIZE(tp), GFP_KERNEL); if (!tpr->rx_jmb_buffers) @@ -6743,8 +6748,8 @@ static int tg3_alloc_consistent(struct tg3 *tp) /* If multivector TSS is enabled, vector 0 does not handle * tx interrupts. Don't allocate any resources for it. */ - if ((!i && !(tp->tg3_flags3 & TG3_FLG3_ENABLE_TSS)) || - (i && (tp->tg3_flags3 & TG3_FLG3_ENABLE_TSS))) { + if ((!i && !tg3_flag(tp, ENABLE_TSS)) || + (i && tg3_flag(tp, ENABLE_TSS))) { tnapi->tx_buffers = kzalloc(sizeof(struct ring_info) * TG3_TX_RING_SIZE, GFP_KERNEL); @@ -6784,7 +6789,7 @@ static int tg3_alloc_consistent(struct tg3 *tp) * If multivector RSS is enabled, vector 0 does not handle * rx or tx interrupts. Don't allocate any resources for it. */ - if (!i && (tp->tg3_flags3 & TG3_FLG3_ENABLE_RSS)) + if (!i && tg3_flag(tp, ENABLE_RSS)) continue; tnapi->rx_rcb = dma_alloc_coherent(&tp->pdev->dev, @@ -6814,7 +6819,7 @@ static int tg3_stop_block(struct tg3 *tp, unsigned long ofs, u32 enable_bit, int unsigned int i; u32 val; - if (tp->tg3_flags2 & TG3_FLG2_5705_PLUS) { + if (tg3_flag(tp, 5705_PLUS)) { switch (ofs) { case RCVLSC_MODE: case DMAC_MODE: @@ -6924,7 +6929,7 @@ static void tg3_ape_send_event(struct tg3 *tp, u32 event) u32 apedata; /* NCSI does not support APE events */ - if (tp->tg3_flags3 & TG3_FLG3_APE_HAS_NCSI) + if (tg3_flag(tp, APE_HAS_NCSI)) return; apedata = tg3_ape_read32(tp, TG3_APE_SEG_SIG); @@ -6963,7 +6968,7 @@ static void tg3_ape_driver_state_change(struct tg3 *tp, int kind) u32 event; u32 apedata; - if (!(tp->tg3_flags3 & TG3_FLG3_ENABLE_APE)) + if (!tg3_flag(tp, ENABLE_APE)) return; switch (kind) { @@ -6992,7 +6997,7 @@ static void tg3_ape_driver_state_change(struct tg3 *tp, int kind) tg3_ape_write32(tp, TG3_APE_HOST_SEG_SIG, 0x0); if (device_may_wakeup(&tp->pdev->dev) && - (tp->tg3_flags & TG3_FLAG_WOL_ENABLE)) { + tg3_flag(tp, WOL_ENABLE)) { tg3_ape_write32(tp, TG3_APE_HOST_WOL_SPEED, TG3_APE_HOST_WOL_SPEED_AUTO); apedata = TG3_APE_HOST_DRVR_STATE_WOL; @@ -7021,7 +7026,7 @@ static void tg3_write_sig_pre_reset(struct tg3 *tp, int kind) tg3_write_mem(tp, NIC_SRAM_FIRMWARE_MBOX, NIC_SRAM_FIRMWARE_MBOX_MAGIC1); - if (tp->tg3_flags2 & TG3_FLG2_ASF_NEW_HANDSHAKE) { + if (tg3_flag(tp, ASF_NEW_HANDSHAKE)) { switch (kind) { case RESET_KIND_INIT: tg3_write_mem(tp, NIC_SRAM_FW_DRV_STATE_MBOX, @@ -7051,7 +7056,7 @@ static void tg3_write_sig_pre_reset(struct tg3 *tp, int kind) /* tp->lock is held. */ static void tg3_write_sig_post_reset(struct tg3 *tp, int kind) { - if (tp->tg3_flags2 & TG3_FLG2_ASF_NEW_HANDSHAKE) { + if (tg3_flag(tp, ASF_NEW_HANDSHAKE)) { switch (kind) { case RESET_KIND_INIT: tg3_write_mem(tp, NIC_SRAM_FW_DRV_STATE_MBOX, @@ -7075,7 +7080,7 @@ static void tg3_write_sig_post_reset(struct tg3 *tp, int kind) /* tp->lock is held. */ static void tg3_write_sig_legacy(struct tg3 *tp, int kind) { - if (tp->tg3_flags & TG3_FLAG_ENABLE_ASF) { + if (tg3_flag(tp, ENABLE_ASF)) { switch (kind) { case RESET_KIND_INIT: tg3_write_mem(tp, NIC_SRAM_FW_DRV_STATE_MBOX, @@ -7126,9 +7131,8 @@ static int tg3_poll_fw(struct tg3 *tp) * of the above loop as an error, but do report the lack of * running firmware once. */ - if (i >= 100000 && - !(tp->tg3_flags2 & TG3_FLG2_NO_FWARE_REPORTED)) { - tp->tg3_flags2 |= TG3_FLG2_NO_FWARE_REPORTED; + if (i >= 100000 && !tg3_flag(tp, NO_FWARE_REPORTED)) { + tg3_flag_set(tp, NO_FWARE_REPORTED); netdev_info(tp->dev, "No firmware running\n"); } @@ -7161,10 +7165,10 @@ static void tg3_restore_pci_state(struct tg3 *tp) /* Set MAX PCI retry to zero. */ val = (PCISTATE_ROM_ENABLE | PCISTATE_ROM_RETRY_ENABLE); if (tp->pci_chip_rev_id == CHIPREV_ID_5704_A0 && - (tp->tg3_flags & TG3_FLAG_PCIX_MODE)) + tg3_flag(tp, PCIX_MODE)) val |= PCISTATE_RETRY_SAME_DMA; /* Allow reads and writes to the APE register and memory space. */ - if (tp->tg3_flags3 & TG3_FLG3_ENABLE_APE) + if (tg3_flag(tp, ENABLE_APE)) val |= PCISTATE_ALLOW_APE_CTLSPC_WR | PCISTATE_ALLOW_APE_SHMEM_WR | PCISTATE_ALLOW_APE_PSPACE_WR; @@ -7173,7 +7177,7 @@ static void tg3_restore_pci_state(struct tg3 *tp) pci_write_config_word(tp->pdev, PCI_COMMAND, tp->pci_cmd); if (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5785) { - if (tp->tg3_flags2 & TG3_FLG2_PCI_EXPRESS) + if (tg3_flag(tp, PCI_EXPRESS)) pcie_set_readrq(tp->pdev, tp->pcie_readrq); else { pci_write_config_byte(tp->pdev, PCI_CACHE_LINE_SIZE, @@ -7184,7 +7188,7 @@ static void tg3_restore_pci_state(struct tg3 *tp) } /* Make sure PCI-X relaxed ordering bit is clear. */ - if (tp->tg3_flags & TG3_FLAG_PCIX_MODE) { + if (tg3_flag(tp, PCIX_MODE)) { u16 pcix_cmd; pci_read_config_word(tp->pdev, tp->pcix_cap + PCI_X_CMD, @@ -7194,12 +7198,12 @@ static void tg3_restore_pci_state(struct tg3 *tp) pcix_cmd); } - if (tp->tg3_flags2 & TG3_FLG2_5780_CLASS) { + if (tg3_flag(tp, 5780_CLASS)) { /* Chip reset on 5780 will reset MSI enable bit, * so need to restore it. */ - if (tp->tg3_flags2 & TG3_FLG2_USING_MSI) { + if (tg3_flag(tp, USING_MSI)) { u16 ctrl; pci_read_config_word(tp->pdev, @@ -7239,7 +7243,7 @@ static int tg3_chip_reset(struct tg3 *tp) tg3_save_pci_state(tp); if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5752 || - (tp->tg3_flags3 & TG3_FLG3_5755_PLUS)) + tg3_flag(tp, 5755_PLUS)) tw32(GRC_FASTBOOT_PC, 0); /* @@ -7258,7 +7262,7 @@ static int tg3_chip_reset(struct tg3 *tp) * at this time, but the irq handler may still be called due to irq * sharing or irqpoll. */ - tp->tg3_flags |= TG3_FLAG_CHIP_RESETTING; + tg3_flag_set(tp, CHIP_RESETTING); for (i = 0; i < tp->irq_cnt; i++) { struct tg3_napi *tnapi = &tp->napi[i]; if (tnapi->hw_status) { @@ -7281,10 +7285,10 @@ static int tg3_chip_reset(struct tg3 *tp) /* do the reset */ val = GRC_MISC_CFG_CORECLK_RESET; - if (tp->tg3_flags2 & TG3_FLG2_PCI_EXPRESS) { + if (tg3_flag(tp, PCI_EXPRESS)) { /* Force PCIe 1.0a mode */ if (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5785 && - !(tp->tg3_flags3 & TG3_FLG3_57765_PLUS) && + !tg3_flag(tp, 57765_PLUS) && tr32(TG3_PCIE_PHY_TSTCTL) == (TG3_PCIE_PHY_TSTCTL_PCIE10 | TG3_PCIE_PHY_TSTCTL_PSCRAM)) tw32(TG3_PCIE_PHY_TSTCTL, TG3_PCIE_PHY_TSTCTL_PSCRAM); @@ -7302,8 +7306,7 @@ static int tg3_chip_reset(struct tg3 *tp) } /* Manage gphy power for all CPMU absent PCIe devices. */ - if ((tp->tg3_flags2 & TG3_FLG2_5705_PLUS) && - !(tp->tg3_flags & TG3_FLAG_CPMU_PRESENT)) + if (tg3_flag(tp, 5705_PLUS) && !tg3_flag(tp, CPMU_PRESENT)) val |= GRC_MISC_CFG_KEEP_GPHY_POWER; tw32(GRC_MISC_CFG, val); @@ -7336,7 +7339,7 @@ static int tg3_chip_reset(struct tg3 *tp) udelay(120); - if ((tp->tg3_flags2 & TG3_FLG2_PCI_EXPRESS) && tp->pcie_cap) { + if (tg3_flag(tp, PCI_EXPRESS) && tp->pcie_cap) { u16 val16; if (tp->pci_chip_rev_id == CHIPREV_ID_5750_A0) { @@ -7362,7 +7365,7 @@ static int tg3_chip_reset(struct tg3 *tp) * Older PCIe devices only support the 128 byte * MPS setting. Enforce the restriction. */ - if (!(tp->tg3_flags & TG3_FLAG_CPMU_PRESENT)) + if (!tg3_flag(tp, CPMU_PRESENT)) val16 &= ~PCI_EXP_DEVCTL_PAYLOAD; pci_write_config_word(tp->pdev, tp->pcie_cap + PCI_EXP_DEVCTL, @@ -7381,11 +7384,11 @@ static int tg3_chip_reset(struct tg3 *tp) tg3_restore_pci_state(tp); - tp->tg3_flags &= ~(TG3_FLAG_CHIP_RESETTING | - TG3_FLAG_ERROR_PROCESSED); + tg3_flag_clear(tp, CHIP_RESETTING); + tg3_flag_clear(tp, ERROR_PROCESSED); val = 0; - if (tp->tg3_flags2 & TG3_FLG2_5780_CLASS) + if (tg3_flag(tp, 5780_CLASS)) val = tr32(MEMARB_MODE); tw32(MEMARB_MODE, val | MEMARB_MODE_ENABLE); @@ -7410,7 +7413,7 @@ static int tg3_chip_reset(struct tg3 *tp) tw32(TG3PCI_CLOCK_CTRL, tp->pci_clock_ctrl); } - if (tp->tg3_flags3 & TG3_FLG3_ENABLE_APE) + if (tg3_flag(tp, ENABLE_APE)) tp->mac_mode = MAC_MODE_APE_TX_EN | MAC_MODE_APE_RX_EN | MAC_MODE_TDE_ENABLE; @@ -7435,10 +7438,10 @@ static int tg3_chip_reset(struct tg3 *tp) tg3_mdio_start(tp); - if ((tp->tg3_flags2 & TG3_FLG2_PCI_EXPRESS) && + if (tg3_flag(tp, PCI_EXPRESS) && tp->pci_chip_rev_id != CHIPREV_ID_5750_A0 && GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5785 && - !(tp->tg3_flags3 & TG3_FLG3_57765_PLUS)) { + !tg3_flag(tp, 57765_PLUS)) { val = tr32(0x7c00); tw32(0x7c00, val | (1 << 25)); @@ -7450,18 +7453,18 @@ static int tg3_chip_reset(struct tg3 *tp) } /* Reprobe ASF enable state. */ - tp->tg3_flags &= ~TG3_FLAG_ENABLE_ASF; - tp->tg3_flags2 &= ~TG3_FLG2_ASF_NEW_HANDSHAKE; + tg3_flag_clear(tp, ENABLE_ASF); + tg3_flag_clear(tp, ASF_NEW_HANDSHAKE); tg3_read_mem(tp, NIC_SRAM_DATA_SIG, &val); if (val == NIC_SRAM_DATA_SIG_MAGIC) { u32 nic_cfg; tg3_read_mem(tp, NIC_SRAM_DATA_CFG, &nic_cfg); if (nic_cfg & NIC_SRAM_DATA_CFG_ASF_ENABLE) { - tp->tg3_flags |= TG3_FLAG_ENABLE_ASF; + tg3_flag_set(tp, ENABLE_ASF); tp->last_event_jiffies = jiffies; - if (tp->tg3_flags2 & TG3_FLG2_5750_PLUS) - tp->tg3_flags2 |= TG3_FLG2_ASF_NEW_HANDSHAKE; + if (tg3_flag(tp, 5750_PLUS)) + tg3_flag_set(tp, ASF_NEW_HANDSHAKE); } } @@ -7471,8 +7474,7 @@ static int tg3_chip_reset(struct tg3 *tp) /* tp->lock is held. */ static void tg3_stop_fw(struct tg3 *tp) { - if ((tp->tg3_flags & TG3_FLAG_ENABLE_ASF) && - !(tp->tg3_flags3 & TG3_FLG3_ENABLE_APE)) { + if (tg3_flag(tp, ENABLE_ASF) && !tg3_flag(tp, ENABLE_APE)) { /* Wait for RX cpu to ACK the previous event. */ tg3_wait_for_event_ack(tp); @@ -7518,8 +7520,7 @@ static int tg3_halt_cpu(struct tg3 *tp, u32 offset) { int i; - BUG_ON(offset == TX_CPU_BASE && - (tp->tg3_flags2 & TG3_FLG2_5705_PLUS)); + BUG_ON(offset == TX_CPU_BASE && tg3_flag(tp, 5705_PLUS)); if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906) { u32 val = tr32(GRC_VCPU_EXT_CTRL); @@ -7554,7 +7555,7 @@ static int tg3_halt_cpu(struct tg3 *tp, u32 offset) } /* Clear firmware's nvram arbitration. */ - if (tp->tg3_flags & TG3_FLAG_NVRAM) + if (tg3_flag(tp, NVRAM)) tw32(NVRAM_SWARB, SWARB_REQ_CLR0); return 0; } @@ -7572,15 +7573,14 @@ static int tg3_load_firmware_cpu(struct tg3 *tp, u32 cpu_base, u32 cpu_scratch_b int err, lock_err, i; void (*write_op)(struct tg3 *, u32, u32); - if (cpu_base == TX_CPU_BASE && - (tp->tg3_flags2 & TG3_FLG2_5705_PLUS)) { + if (cpu_base == TX_CPU_BASE && tg3_flag(tp, 5705_PLUS)) { netdev_err(tp->dev, "%s: Trying to load TX cpu firmware which is 5705\n", __func__); return -EINVAL; } - if (tp->tg3_flags2 & TG3_FLG2_5705_PLUS) + if (tg3_flag(tp, 5705_PLUS)) write_op = tg3_write_mem; else write_op = tg3_write_indirect_reg32; @@ -7674,7 +7674,9 @@ static int tg3_load_tso_firmware(struct tg3 *tp) unsigned long cpu_base, cpu_scratch_base, cpu_scratch_size; int err, i; - if (tp->tg3_flags2 & TG3_FLG2_HW_TSO) + if (tg3_flag(tp, HW_TSO_1) || + tg3_flag(tp, HW_TSO_2) || + tg3_flag(tp, HW_TSO_3)) return 0; fw_data = (void *)tp->fw->data; @@ -7743,7 +7745,7 @@ static int tg3_set_mac_addr(struct net_device *dev, void *p) if (!netif_running(dev)) return 0; - if (tp->tg3_flags & TG3_FLAG_ENABLE_ASF) { + if (tg3_flag(tp, ENABLE_ASF)) { u32 addr0_high, addr0_low, addr1_high, addr1_low; addr0_high = tr32(MAC_ADDR_0_HIGH); @@ -7778,7 +7780,7 @@ static void tg3_set_bdinfo(struct tg3 *tp, u32 bdinfo_addr, (bdinfo_addr + TG3_BDINFO_MAXLEN_FLAGS), maxlen_flags); - if (!(tp->tg3_flags2 & TG3_FLG2_5705_PLUS)) + if (!tg3_flag(tp, 5705_PLUS)) tg3_write_mem(tp, (bdinfo_addr + TG3_BDINFO_NIC_ADDR), nic_addr); @@ -7789,7 +7791,7 @@ static void __tg3_set_coalesce(struct tg3 *tp, struct ethtool_coalesce *ec) { int i; - if (!(tp->tg3_flags3 & TG3_FLG3_ENABLE_TSS)) { + if (!tg3_flag(tp, ENABLE_TSS)) { tw32(HOSTCC_TXCOL_TICKS, ec->tx_coalesce_usecs); tw32(HOSTCC_TXMAX_FRAMES, ec->tx_max_coalesced_frames); tw32(HOSTCC_TXCOAL_MAXF_INT, ec->tx_max_coalesced_frames_irq); @@ -7799,7 +7801,7 @@ static void __tg3_set_coalesce(struct tg3 *tp, struct ethtool_coalesce *ec) tw32(HOSTCC_TXCOAL_MAXF_INT, 0); } - if (!(tp->tg3_flags3 & TG3_FLG3_ENABLE_RSS)) { + if (!tg3_flag(tp, ENABLE_RSS)) { tw32(HOSTCC_RXCOL_TICKS, ec->rx_coalesce_usecs); tw32(HOSTCC_RXMAX_FRAMES, ec->rx_max_coalesced_frames); tw32(HOSTCC_RXCOAL_MAXF_INT, ec->rx_max_coalesced_frames_irq); @@ -7809,7 +7811,7 @@ static void __tg3_set_coalesce(struct tg3 *tp, struct ethtool_coalesce *ec) tw32(HOSTCC_RXCOAL_MAXF_INT, 0); } - if (!(tp->tg3_flags2 & TG3_FLG2_5705_PLUS)) { + if (!tg3_flag(tp, 5705_PLUS)) { u32 val = ec->stats_block_coalesce_usecs; tw32(HOSTCC_RXCOAL_TICK_INT, ec->rx_coalesce_usecs_irq); @@ -7831,7 +7833,7 @@ static void __tg3_set_coalesce(struct tg3 *tp, struct ethtool_coalesce *ec) reg = HOSTCC_RXCOAL_MAXF_INT_VEC1 + i * 0x18; tw32(reg, ec->rx_max_coalesced_frames_irq); - if (tp->tg3_flags3 & TG3_FLG3_ENABLE_TSS) { + if (tg3_flag(tp, ENABLE_TSS)) { reg = HOSTCC_TXCOL_TICKS_VEC1 + i * 0x18; tw32(reg, ec->tx_coalesce_usecs); reg = HOSTCC_TXMAX_FRAMES_VEC1 + i * 0x18; @@ -7846,7 +7848,7 @@ static void __tg3_set_coalesce(struct tg3 *tp, struct ethtool_coalesce *ec) tw32(HOSTCC_RXMAX_FRAMES_VEC1 + i * 0x18, 0); tw32(HOSTCC_RXCOAL_MAXF_INT_VEC1 + i * 0x18, 0); - if (tp->tg3_flags3 & TG3_FLG3_ENABLE_TSS) { + if (tg3_flag(tp, ENABLE_TSS)) { tw32(HOSTCC_TXCOL_TICKS_VEC1 + i * 0x18, 0); tw32(HOSTCC_TXMAX_FRAMES_VEC1 + i * 0x18, 0); tw32(HOSTCC_TXCOAL_MAXF_INT_VEC1 + i * 0x18, 0); @@ -7862,9 +7864,9 @@ static void tg3_rings_reset(struct tg3 *tp) struct tg3_napi *tnapi = &tp->napi[0]; /* Disable all transmit rings but the first. */ - if (!(tp->tg3_flags2 & TG3_FLG2_5705_PLUS)) + if (!tg3_flag(tp, 5705_PLUS)) limit = NIC_SRAM_SEND_RCB + TG3_BDINFO_SIZE * 16; - else if (tp->tg3_flags3 & TG3_FLG3_5717_PLUS) + else if (tg3_flag(tp, 5717_PLUS)) limit = NIC_SRAM_SEND_RCB + TG3_BDINFO_SIZE * 4; else if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57765) limit = NIC_SRAM_SEND_RCB + TG3_BDINFO_SIZE * 2; @@ -7878,9 +7880,9 @@ static void tg3_rings_reset(struct tg3 *tp) /* Disable all receive return rings but the first. */ - if (tp->tg3_flags3 & TG3_FLG3_5717_PLUS) + if (tg3_flag(tp, 5717_PLUS)) limit = NIC_SRAM_RCV_RET_RCB + TG3_BDINFO_SIZE * 17; - else if (!(tp->tg3_flags2 & TG3_FLG2_5705_PLUS)) + else if (!tg3_flag(tp, 5705_PLUS)) limit = NIC_SRAM_RCV_RET_RCB + TG3_BDINFO_SIZE * 16; else if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5755 || GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57765) @@ -7897,16 +7899,16 @@ static void tg3_rings_reset(struct tg3 *tp) tw32_mailbox_f(tp->napi[0].int_mbox, 1); /* Zero mailbox registers. */ - if (tp->tg3_flags & TG3_FLAG_SUPPORT_MSIX) { + if (tg3_flag(tp, SUPPORT_MSIX)) { for (i = 1; i < tp->irq_max; i++) { tp->napi[i].tx_prod = 0; tp->napi[i].tx_cons = 0; - if (tp->tg3_flags3 & TG3_FLG3_ENABLE_TSS) + if (tg3_flag(tp, ENABLE_TSS)) tw32_mailbox(tp->napi[i].prodmbox, 0); tw32_rx_mbox(tp->napi[i].consmbox, 0); tw32_mailbox_f(tp->napi[i].int_mbox, 1); } - if (!(tp->tg3_flags3 & TG3_FLG3_ENABLE_TSS)) + if (!tg3_flag(tp, ENABLE_TSS)) tw32_mailbox(tp->napi[0].prodmbox, 0); } else { tp->napi[0].tx_prod = 0; @@ -7916,7 +7918,7 @@ static void tg3_rings_reset(struct tg3 *tp) } /* Make sure the NIC-based send BD rings are disabled. */ - if (!(tp->tg3_flags2 & TG3_FLG2_5705_PLUS)) { + if (!tg3_flag(tp, 5705_PLUS)) { u32 mbox = MAILBOX_SNDNIC_PROD_IDX_0 + TG3_64BIT_REG_LOW; for (i = 0; i < 16; i++) tw32_tx_mbox(mbox + i * 8, 0); @@ -7980,8 +7982,8 @@ static void tg3_setup_rxbd_thresholds(struct tg3 *tp) { u32 val, bdcache_maxcnt, host_rep_thresh, nic_rep_thresh; - if (!(tp->tg3_flags2 & TG3_FLG2_5750_PLUS) || - (tp->tg3_flags2 & TG3_FLG2_5780_CLASS) || + if (!tg3_flag(tp, 5750_PLUS) || + tg3_flag(tp, 5780_CLASS) || GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5750 || GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5752) bdcache_maxcnt = TG3_SRAM_RX_STD_BDCACHE_SIZE_5700; @@ -7997,14 +7999,13 @@ static void tg3_setup_rxbd_thresholds(struct tg3 *tp) val = min(nic_rep_thresh, host_rep_thresh); tw32(RCVBDI_STD_THRESH, val); - if (tp->tg3_flags3 & TG3_FLG3_57765_PLUS) + if (tg3_flag(tp, 57765_PLUS)) tw32(STD_REPLENISH_LWM, bdcache_maxcnt); - if (!(tp->tg3_flags & TG3_FLAG_JUMBO_CAPABLE) || - (tp->tg3_flags2 & TG3_FLG2_5780_CLASS)) + if (!tg3_flag(tp, JUMBO_CAPABLE) || tg3_flag(tp, 5780_CLASS)) return; - if (!(tp->tg3_flags2 & TG3_FLG2_5705_PLUS)) + if (!tg3_flag(tp, 5705_PLUS)) bdcache_maxcnt = TG3_SRAM_RX_JMB_BDCACHE_SIZE_5700; else bdcache_maxcnt = TG3_SRAM_RX_JMB_BDCACHE_SIZE_5717; @@ -8014,7 +8015,7 @@ static void tg3_setup_rxbd_thresholds(struct tg3 *tp) val = min(bdcache_maxcnt / 2, host_rep_thresh); tw32(RCVBDI_JUMBO_THRESH, val); - if (tp->tg3_flags3 & TG3_FLG3_57765_PLUS) + if (tg3_flag(tp, 57765_PLUS)) tw32(JMB_REPLENISH_LWM, bdcache_maxcnt); } @@ -8031,7 +8032,7 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy) tg3_write_sig_pre_reset(tp, RESET_KIND_INIT); - if (tp->tg3_flags & TG3_FLAG_INIT_COMPLETE) + if (tg3_flag(tp, INIT_COMPLETE)) tg3_abort_hw(tp, 1); /* Enable MAC control of LPI */ @@ -8051,7 +8052,7 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy) if (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5717) val |= TG3_CPMU_EEEMD_SND_IDX_DET_EN; - if (tp->tg3_flags3 & TG3_FLG3_ENABLE_APE) + if (tg3_flag(tp, ENABLE_APE)) val |= TG3_CPMU_EEEMD_APE_TX_DET_EN; tw32_f(TG3_CPMU_EEE_MODE, val); @@ -8110,7 +8111,7 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy) tw32(TG3_PCIE_LNKCTL, val | TG3_PCIE_LNKCTL_L1_PLL_PD_DIS); } - if (tp->tg3_flags3 & TG3_FLG3_L1PLLPD_EN) { + if (tg3_flag(tp, L1PLLPD_EN)) { u32 grc_mode = tr32(GRC_MODE); /* Access the lower 1K of PL PCIE block registers. */ @@ -8151,20 +8152,20 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy) * other revision. But do not set this on PCI Express * chips and don't even touch the clocks if the CPMU is present. */ - if (!(tp->tg3_flags & TG3_FLAG_CPMU_PRESENT)) { - if (!(tp->tg3_flags2 & TG3_FLG2_PCI_EXPRESS)) + if (!tg3_flag(tp, CPMU_PRESENT)) { + if (!tg3_flag(tp, PCI_EXPRESS)) tp->pci_clock_ctrl |= CLOCK_CTRL_DELAY_PCI_GRANT; tw32_f(TG3PCI_CLOCK_CTRL, tp->pci_clock_ctrl); } if (tp->pci_chip_rev_id == CHIPREV_ID_5704_A0 && - (tp->tg3_flags & TG3_FLAG_PCIX_MODE)) { + tg3_flag(tp, PCIX_MODE)) { val = tr32(TG3PCI_PCISTATE); val |= PCISTATE_RETRY_SAME_DMA; tw32(TG3PCI_PCISTATE, val); } - if (tp->tg3_flags3 & TG3_FLG3_ENABLE_APE) { + if (tg3_flag(tp, ENABLE_APE)) { /* Allow reads and writes to the * APE register and memory space. */ @@ -8191,7 +8192,7 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy) if (err) return err; - if (tp->tg3_flags3 & TG3_FLG3_57765_PLUS) { + if (tg3_flag(tp, 57765_PLUS)) { val = tr32(TG3PCI_DMA_RW_CTRL) & ~DMA_RWCTRL_DIS_CACHE_ALIGNMENT; if (tp->pci_chip_rev_id == CHIPREV_ID_57765_A0) @@ -8233,7 +8234,7 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy) tw32(GRC_MISC_CFG, val); /* Initialize MBUF/DESC pool. */ - if (tp->tg3_flags2 & TG3_FLG2_5750_PLUS) { + if (tg3_flag(tp, 5750_PLUS)) { /* Do nothing. */ } else if (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5705) { tw32(BUFMGR_MB_POOL_ADDR, NIC_SRAM_MBUF_POOL_BASE); @@ -8243,7 +8244,7 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy) tw32(BUFMGR_MB_POOL_SIZE, NIC_SRAM_MBUF_POOL_SIZE96); tw32(BUFMGR_DMA_DESC_POOL_ADDR, NIC_SRAM_DMA_DESC_POOL_BASE); tw32(BUFMGR_DMA_DESC_POOL_SIZE, NIC_SRAM_DMA_DESC_POOL_SIZE); - } else if (tp->tg3_flags2 & TG3_FLG2_TSO_CAPABLE) { + } else if (tg3_flag(tp, TSO_CAPABLE)) { int fw_len; fw_len = tp->fw_len; @@ -8318,12 +8319,12 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy) ((u64) tpr->rx_std_mapping >> 32)); tw32(RCVDBDI_STD_BD + TG3_BDINFO_HOST_ADDR + TG3_64BIT_REG_LOW, ((u64) tpr->rx_std_mapping & 0xffffffff)); - if (!(tp->tg3_flags3 & TG3_FLG3_5717_PLUS)) + if (!tg3_flag(tp, 5717_PLUS)) tw32(RCVDBDI_STD_BD + TG3_BDINFO_NIC_ADDR, NIC_SRAM_RX_BUFFER_DESC); /* Disable the mini ring */ - if (!(tp->tg3_flags2 & TG3_FLG2_5705_PLUS)) + if (!tg3_flag(tp, 5705_PLUS)) tw32(RCVDBDI_MINI_BD + TG3_BDINFO_MAXLEN_FLAGS, BDINFO_FLAGS_DISABLED); @@ -8331,10 +8332,9 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy) * blocks on those devices that have them. */ if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5719 || - ((tp->tg3_flags & TG3_FLAG_JUMBO_CAPABLE) && - !(tp->tg3_flags2 & TG3_FLG2_5780_CLASS))) { + (tg3_flag(tp, JUMBO_CAPABLE) && !tg3_flag(tp, 5780_CLASS))) { - if (tp->tg3_flags & TG3_FLAG_JUMBO_RING_ENABLE) { + if (tg3_flag(tp, JUMBO_RING_ENABLE)) { tw32(RCVDBDI_JUMBO_BD + TG3_BDINFO_HOST_ADDR + TG3_64BIT_REG_HIGH, ((u64) tpr->rx_jmb_mapping >> 32)); tw32(RCVDBDI_JUMBO_BD + TG3_BDINFO_HOST_ADDR + TG3_64BIT_REG_LOW, @@ -8343,7 +8343,7 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy) BDINFO_FLAGS_MAXLEN_SHIFT; tw32(RCVDBDI_JUMBO_BD + TG3_BDINFO_MAXLEN_FLAGS, val | BDINFO_FLAGS_USE_EXT_RECV); - if (!(tp->tg3_flags3 & TG3_FLG3_USE_JUMBO_BDFLAG) || + if (!tg3_flag(tp, USE_JUMBO_BDFLAG) || GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57765) tw32(RCVDBDI_JUMBO_BD + TG3_BDINFO_NIC_ADDR, NIC_SRAM_RX_JUMBO_BUFFER_DESC); @@ -8352,7 +8352,7 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy) BDINFO_FLAGS_DISABLED); } - if (tp->tg3_flags3 & TG3_FLG3_57765_PLUS) { + if (tg3_flag(tp, 57765_PLUS)) { if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57765) val = TG3_RX_STD_MAX_SIZE_5700; else @@ -8369,8 +8369,8 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy) tpr->rx_std_prod_idx = tp->rx_pending; tw32_rx_mbox(TG3_RX_STD_PROD_IDX_REG, tpr->rx_std_prod_idx); - tpr->rx_jmb_prod_idx = (tp->tg3_flags & TG3_FLAG_JUMBO_RING_ENABLE) ? - tp->rx_jumbo_pending : 0; + tpr->rx_jmb_prod_idx = + tg3_flag(tp, JUMBO_RING_ENABLE) ? tp->rx_jumbo_pending : 0; tw32_rx_mbox(TG3_RX_JMB_PROD_IDX_REG, tpr->rx_jmb_prod_idx); tg3_rings_reset(tp); @@ -8421,22 +8421,24 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy) if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5705 && tp->pci_chip_rev_id != CHIPREV_ID_5705_A0) { - if (tp->tg3_flags2 & TG3_FLG2_TSO_CAPABLE && + if (tg3_flag(tp, TSO_CAPABLE) && GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5705) { rdmac_mode |= RDMAC_MODE_FIFO_SIZE_128; } else if (!(tr32(TG3PCI_PCISTATE) & PCISTATE_BUS_SPEED_HIGH) && - !(tp->tg3_flags2 & TG3_FLG2_IS_5788)) { + !tg3_flag(tp, IS_5788)) { rdmac_mode |= RDMAC_MODE_FIFO_LONG_BURST; } } - if (tp->tg3_flags2 & TG3_FLG2_PCI_EXPRESS) + if (tg3_flag(tp, PCI_EXPRESS)) rdmac_mode |= RDMAC_MODE_FIFO_LONG_BURST; - if (tp->tg3_flags2 & TG3_FLG2_HW_TSO) + if (tg3_flag(tp, HW_TSO_1) || + tg3_flag(tp, HW_TSO_2) || + tg3_flag(tp, HW_TSO_3)) rdmac_mode |= RDMAC_MODE_IPV4_LSO_EN; - if ((tp->tg3_flags2 & TG3_FLG2_HW_TSO_3) || + if (tg3_flag(tp, HW_TSO_3) || GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5785 || GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57780) rdmac_mode |= RDMAC_MODE_IPV6_LSO_EN; @@ -8448,7 +8450,7 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy) GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784 || GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5785 || GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57780 || - (tp->tg3_flags3 & TG3_FLG3_57765_PLUS)) { + tg3_flag(tp, 57765_PLUS)) { val = tr32(TG3_RDMA_RSRVCTRL_REG); if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5719 || GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5720) { @@ -8472,12 +8474,12 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy) } /* Receive/send statistics. */ - if (tp->tg3_flags2 & TG3_FLG2_5750_PLUS) { + if (tg3_flag(tp, 5750_PLUS)) { val = tr32(RCVLPC_STATS_ENABLE); val &= ~RCVLPC_STATSENAB_DACK_FIX; tw32(RCVLPC_STATS_ENABLE, val); } else if ((rdmac_mode & RDMAC_MODE_FIFO_SIZE_128) && - (tp->tg3_flags2 & TG3_FLG2_TSO_CAPABLE)) { + tg3_flag(tp, TSO_CAPABLE)) { val = tr32(RCVLPC_STATS_ENABLE); val &= ~RCVLPC_STATSENAB_LNGBRST_RFIX; tw32(RCVLPC_STATS_ENABLE, val); @@ -8500,7 +8502,7 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy) __tg3_set_coalesce(tp, &tp->coal); - if (!(tp->tg3_flags2 & TG3_FLG2_5705_PLUS)) { + if (!tg3_flag(tp, 5705_PLUS)) { /* Status/statistics block address. See tg3_timer, * the tg3_periodic_fetch_stats call there, and * tg3_get_stats to see how this works for 5705/5750 chips. @@ -8526,7 +8528,7 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy) tw32(RCVCC_MODE, RCVCC_MODE_ENABLE | RCVCC_MODE_ATTN_ENABLE); tw32(RCVLPC_MODE, RCVLPC_MODE_ENABLE); - if (!(tp->tg3_flags2 & TG3_FLG2_5705_PLUS)) + if (!tg3_flag(tp, 5705_PLUS)) tw32(RCVLSC_MODE, RCVLSC_MODE_ENABLE | RCVLSC_MODE_ATTN_ENABLE); if (tp->phy_flags & TG3_PHYFLG_MII_SERDES) { @@ -8536,13 +8538,13 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy) udelay(10); } - if (tp->tg3_flags3 & TG3_FLG3_ENABLE_APE) + if (tg3_flag(tp, ENABLE_APE)) tp->mac_mode = MAC_MODE_APE_TX_EN | MAC_MODE_APE_RX_EN; else tp->mac_mode = 0; tp->mac_mode |= MAC_MODE_TXSTAT_ENABLE | MAC_MODE_RXSTAT_ENABLE | MAC_MODE_TDE_ENABLE | MAC_MODE_RDE_ENABLE | MAC_MODE_FHDE_ENABLE; - if (!(tp->tg3_flags2 & TG3_FLG2_5705_PLUS) && + if (!tg3_flag(tp, 5705_PLUS) && !(tp->phy_flags & TG3_PHYFLG_PHY_SERDES) && GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5700) tp->mac_mode |= MAC_MODE_LINK_POLARITY; @@ -8550,12 +8552,12 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy) udelay(40); /* tp->grc_local_ctrl is partially set up during tg3_get_invariants(). - * If TG3_FLG2_IS_NIC is zero, we should read the + * If TG3_FLAG_IS_NIC is zero, we should read the * register to preserve the GPIO settings for LOMs. The GPIOs, * whether used as inputs or outputs, are set by boot code after * reset. */ - if (!(tp->tg3_flags2 & TG3_FLG2_IS_NIC)) { + if (!tg3_flag(tp, IS_NIC)) { u32 gpio_mask; gpio_mask = GRC_LCLCTRL_GPIO_OE0 | GRC_LCLCTRL_GPIO_OE1 | @@ -8573,21 +8575,20 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy) tp->grc_local_ctrl |= tr32(GRC_LOCAL_CTRL) & gpio_mask; /* GPIO1 must be driven high for eeprom write protect */ - if (tp->tg3_flags & TG3_FLAG_EEPROM_WRITE_PROT) + if (tg3_flag(tp, EEPROM_WRITE_PROT)) tp->grc_local_ctrl |= (GRC_LCLCTRL_GPIO_OE1 | GRC_LCLCTRL_GPIO_OUTPUT1); } tw32_f(GRC_LOCAL_CTRL, tp->grc_local_ctrl); udelay(100); - if ((tp->tg3_flags2 & TG3_FLG2_USING_MSIX) && - tp->irq_cnt > 1) { + if (tg3_flag(tp, USING_MSIX) && tp->irq_cnt > 1) { val = tr32(MSGINT_MODE); val |= MSGINT_MODE_MULTIVEC_EN | MSGINT_MODE_ENABLE; tw32(MSGINT_MODE, val); } - if (!(tp->tg3_flags2 & TG3_FLG2_5705_PLUS)) { + if (!tg3_flag(tp, 5705_PLUS)) { tw32_f(DMAC_MODE, DMAC_MODE_ENABLE); udelay(40); } @@ -8600,18 +8601,18 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy) if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5705 && tp->pci_chip_rev_id != CHIPREV_ID_5705_A0) { - if ((tp->tg3_flags2 & TG3_FLG2_TSO_CAPABLE) && + if (tg3_flag(tp, TSO_CAPABLE) && (tp->pci_chip_rev_id == CHIPREV_ID_5705_A1 || tp->pci_chip_rev_id == CHIPREV_ID_5705_A2)) { /* nothing */ } else if (!(tr32(TG3PCI_PCISTATE) & PCISTATE_BUS_SPEED_HIGH) && - !(tp->tg3_flags2 & TG3_FLG2_IS_5788)) { + !tg3_flag(tp, IS_5788)) { val |= WDMAC_MODE_RX_ACCEL; } } /* Enable host coalescing bug fix */ - if (tp->tg3_flags3 & TG3_FLG3_5755_PLUS) + if (tg3_flag(tp, 5755_PLUS)) val |= WDMAC_MODE_STATUS_TAG_FIX; if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5785) @@ -8620,7 +8621,7 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy) tw32_f(WDMAC_MODE, val); udelay(40); - if (tp->tg3_flags & TG3_FLAG_PCIX_MODE) { + if (tg3_flag(tp, PCIX_MODE)) { u16 pcix_cmd; pci_read_config_word(tp->pdev, tp->pcix_cap + PCI_X_CMD, @@ -8640,7 +8641,7 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy) udelay(40); tw32(RCVDCC_MODE, RCVDCC_MODE_ENABLE | RCVDCC_MODE_ATTN_ENABLE); - if (!(tp->tg3_flags2 & TG3_FLG2_5705_PLUS)) + if (!tg3_flag(tp, 5705_PLUS)) tw32(MBFREE_MODE, MBFREE_MODE_ENABLE); if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761) @@ -8652,14 +8653,16 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy) tw32(SNDBDC_MODE, SNDBDC_MODE_ENABLE | SNDBDC_MODE_ATTN_ENABLE); tw32(RCVBDI_MODE, RCVBDI_MODE_ENABLE | RCVBDI_MODE_RCB_ATTN_ENAB); val = RCVDBDI_MODE_ENABLE | RCVDBDI_MODE_INV_RING_SZ; - if (tp->tg3_flags3 & TG3_FLG3_LRG_PROD_RING_CAP) + if (tg3_flag(tp, LRG_PROD_RING_CAP)) val |= RCVDBDI_MODE_LRG_RING_SZ; tw32(RCVDBDI_MODE, val); tw32(SNDDATAI_MODE, SNDDATAI_MODE_ENABLE); - if (tp->tg3_flags2 & TG3_FLG2_HW_TSO) + if (tg3_flag(tp, HW_TSO_1) || + tg3_flag(tp, HW_TSO_2) || + tg3_flag(tp, HW_TSO_3)) tw32(SNDDATAI_MODE, SNDDATAI_MODE_ENABLE | 0x8); val = SNDBDI_MODE_ENABLE | SNDBDI_MODE_ATTN_ENABLE; - if (tp->tg3_flags3 & TG3_FLG3_ENABLE_TSS) + if (tg3_flag(tp, ENABLE_TSS)) val |= SNDBDI_MODE_MULTI_TXQ_EN; tw32(SNDBDI_MODE, val); tw32(SNDBDS_MODE, SNDBDS_MODE_ENABLE | SNDBDS_MODE_ATTN_ENABLE); @@ -8670,7 +8673,7 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy) return err; } - if (tp->tg3_flags2 & TG3_FLG2_TSO_CAPABLE) { + if (tg3_flag(tp, TSO_CAPABLE)) { err = tg3_load_tso_firmware(tp); if (err) return err; @@ -8678,7 +8681,7 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy) tp->tx_mode = TX_MODE_ENABLE; - if ((tp->tg3_flags3 & TG3_FLG3_5755_PLUS) || + if (tg3_flag(tp, 5755_PLUS) || GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906) tp->tx_mode |= TX_MODE_MBUF_LOCKUP_FIX; @@ -8691,7 +8694,7 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy) tw32_f(MAC_TX_MODE, tp->tx_mode); udelay(100); - if (tp->tg3_flags3 & TG3_FLG3_ENABLE_RSS) { + if (tg3_flag(tp, ENABLE_RSS)) { u32 reg = MAC_RSS_INDIR_TBL_0; u8 *ent = (u8 *)&val; @@ -8720,10 +8723,10 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy) } tp->rx_mode = RX_MODE_ENABLE; - if (tp->tg3_flags3 & TG3_FLG3_5755_PLUS) + if (tg3_flag(tp, 5755_PLUS)) tp->rx_mode |= RX_MODE_IPV6_CSUM_ENABLE; - if (tp->tg3_flags3 & TG3_FLG3_ENABLE_RSS) + if (tg3_flag(tp, ENABLE_RSS)) tp->rx_mode |= RX_MODE_RSS_ENABLE | RX_MODE_RSS_ITBL_HASH_BITS_7 | RX_MODE_RSS_IPV6_HASH_EN | @@ -8770,7 +8773,7 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy) if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5704 && (tp->phy_flags & TG3_PHYFLG_PHY_SERDES)) { /* Use hardware link auto-negotiation */ - tp->tg3_flags2 |= TG3_FLG2_HW_AUTONEG; + tg3_flag_set(tp, HW_AUTONEG); } if ((tp->phy_flags & TG3_PHYFLG_MII_SERDES) && @@ -8784,7 +8787,7 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy) tw32(GRC_LOCAL_CTRL, tp->grc_local_ctrl); } - if (!(tp->tg3_flags3 & TG3_FLG3_USE_PHYLIB)) { + if (!tg3_flag(tp, USE_PHYLIB)) { if (tp->phy_flags & TG3_PHYFLG_IS_LOW_POWER) { tp->phy_flags &= ~TG3_PHYFLG_IS_LOW_POWER; tp->link_config.speed = tp->link_config.orig_speed; @@ -8817,12 +8820,11 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy) tw32(MAC_RCV_RULE_1, 0x86000004 & RCV_RULE_DISABLE_MASK); tw32(MAC_RCV_VALUE_1, 0xffffffff & RCV_RULE_DISABLE_MASK); - if ((tp->tg3_flags2 & TG3_FLG2_5705_PLUS) && - !(tp->tg3_flags2 & TG3_FLG2_5780_CLASS)) + if (tg3_flag(tp, 5705_PLUS) && !tg3_flag(tp, 5780_CLASS)) limit = 8; else limit = 16; - if (tp->tg3_flags & TG3_FLAG_ENABLE_ASF) + if (tg3_flag(tp, ENABLE_ASF)) limit -= 4; switch (limit) { case 16: @@ -8860,7 +8862,7 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy) break; } - if (tp->tg3_flags3 & TG3_FLG3_ENABLE_APE) + if (tg3_flag(tp, ENABLE_APE)) /* Write our heartbeat update interval to APE. */ tg3_ape_write32(tp, TG3_APE_HOST_HEARTBEAT_INT_MS, APE_HOST_HEARTBEAT_INT_DISABLE); @@ -8951,7 +8953,7 @@ static void tg3_timer(unsigned long __opaque) spin_lock(&tp->lock); - if (!(tp->tg3_flags & TG3_FLAG_TAGGED_STATUS)) { + if (!tg3_flag(tp, TAGGED_STATUS)) { /* All of this garbage is because when using non-tagged * IRQ status the mailbox/status_block protocol the chip * uses with the cpu is race prone. @@ -8965,7 +8967,7 @@ static void tg3_timer(unsigned long __opaque) } if (!(tr32(WDMAC_MODE) & WDMAC_MODE_ENABLE)) { - tp->tg3_flags2 |= TG3_FLG2_RESTART_TIMER; + tg3_flag_set(tp, RESTART_TIMER); spin_unlock(&tp->lock); schedule_work(&tp->reset_task); return; @@ -8974,7 +8976,7 @@ static void tg3_timer(unsigned long __opaque) /* This part only runs once per second. */ if (!--tp->timer_counter) { - if (tp->tg3_flags2 & TG3_FLG2_5705_PLUS) + if (tg3_flag(tp, 5705_PLUS)) tg3_periodic_fetch_stats(tp); if (tp->setlpicnt && !--tp->setlpicnt) { @@ -8983,7 +8985,7 @@ static void tg3_timer(unsigned long __opaque) val | TG3_CPMU_EEEMD_LPI_ENABLE); } - if (tp->tg3_flags & TG3_FLAG_USE_LINKCHG_REG) { + if (tg3_flag(tp, USE_LINKCHG_REG)) { u32 mac_stat; int phy_event; @@ -8998,7 +9000,7 @@ static void tg3_timer(unsigned long __opaque) if (phy_event) tg3_setup_phy(tp, 0); - } else if (tp->tg3_flags & TG3_FLAG_POLL_SERDES) { + } else if (tg3_flag(tp, POLL_SERDES)) { u32 mac_stat = tr32(MAC_STATUS); int need_setup = 0; @@ -9023,7 +9025,7 @@ static void tg3_timer(unsigned long __opaque) tg3_setup_phy(tp, 0); } } else if ((tp->phy_flags & TG3_PHYFLG_MII_SERDES) && - (tp->tg3_flags2 & TG3_FLG2_5780_CLASS)) { + tg3_flag(tp, 5780_CLASS)) { tg3_serdes_parallel_detect(tp); } @@ -9048,8 +9050,7 @@ static void tg3_timer(unsigned long __opaque) * resets. */ if (!--tp->asf_counter) { - if ((tp->tg3_flags & TG3_FLAG_ENABLE_ASF) && - !(tp->tg3_flags3 & TG3_FLG3_ENABLE_APE)) { + if (tg3_flag(tp, ENABLE_ASF) && !tg3_flag(tp, ENABLE_APE)) { tg3_wait_for_event_ack(tp); tg3_write_mem(tp, NIC_SRAM_FW_CMD_MBOX, @@ -9085,14 +9086,14 @@ static int tg3_request_irq(struct tg3 *tp, int irq_num) name[IFNAMSIZ-1] = 0; } - if (tp->tg3_flags2 & TG3_FLG2_USING_MSI_OR_MSIX) { + if (tg3_flag(tp, USING_MSI) || tg3_flag(tp, USING_MSIX)) { fn = tg3_msi; - if (tp->tg3_flags2 & TG3_FLG2_1SHOT_MSI) + if (tg3_flag(tp, 1SHOT_MSI)) fn = tg3_msi_1shot; flags = 0; } else { fn = tg3_interrupt; - if (tp->tg3_flags & TG3_FLAG_TAGGED_STATUS) + if (tg3_flag(tp, TAGGED_STATUS)) fn = tg3_interrupt_tagged; flags = IRQF_SHARED; } @@ -9118,8 +9119,7 @@ static int tg3_test_interrupt(struct tg3 *tp) * Turn off MSI one shot mode. Otherwise this test has no * observable way to know whether the interrupt was delivered. */ - if ((tp->tg3_flags3 & TG3_FLG3_57765_PLUS) && - (tp->tg3_flags2 & TG3_FLG2_USING_MSI)) { + if (tg3_flag(tp, 57765_PLUS) && tg3_flag(tp, USING_MSI)) { val = tr32(MSGINT_MODE) | MSGINT_MODE_ONE_SHOT_DISABLE; tw32(MSGINT_MODE, val); } @@ -9161,8 +9161,7 @@ static int tg3_test_interrupt(struct tg3 *tp) if (intr_ok) { /* Reenable MSI one shot mode. */ - if ((tp->tg3_flags3 & TG3_FLG3_57765_PLUS) && - (tp->tg3_flags2 & TG3_FLG2_USING_MSI)) { + if (tg3_flag(tp, 57765_PLUS) && tg3_flag(tp, USING_MSI)) { val = tr32(MSGINT_MODE) & ~MSGINT_MODE_ONE_SHOT_DISABLE; tw32(MSGINT_MODE, val); } @@ -9180,7 +9179,7 @@ static int tg3_test_msi(struct tg3 *tp) int err; u16 pci_cmd; - if (!(tp->tg3_flags2 & TG3_FLG2_USING_MSI)) + if (!tg3_flag(tp, USING_MSI)) return 0; /* Turn off SERR reporting in case MSI terminates with Master @@ -9210,7 +9209,7 @@ static int tg3_test_msi(struct tg3 *tp) pci_disable_msi(tp->pdev); - tp->tg3_flags2 &= ~TG3_FLG2_USING_MSI; + tg3_flag_clear(tp, USING_MSI); tp->napi[0].irq_vec = tp->pdev->irq; err = tg3_request_irq(tp, 0); @@ -9307,11 +9306,11 @@ static bool tg3_enable_msix(struct tg3 *tp) } if (tp->irq_cnt > 1) { - tp->tg3_flags3 |= TG3_FLG3_ENABLE_RSS; + tg3_flag_set(tp, ENABLE_RSS); if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5719 || GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5720) { - tp->tg3_flags3 |= TG3_FLG3_ENABLE_TSS; + tg3_flag_set(tp, ENABLE_TSS); netif_set_real_num_tx_queues(tp->dev, tp->irq_cnt - 1); } } @@ -9321,8 +9320,8 @@ static bool tg3_enable_msix(struct tg3 *tp) static void tg3_ints_init(struct tg3 *tp) { - if ((tp->tg3_flags & TG3_FLAG_SUPPORT_MSI_OR_MSIX) && - !(tp->tg3_flags & TG3_FLAG_TAGGED_STATUS)) { + if ((tg3_flag(tp, SUPPORT_MSI) || tg3_flag(tp, SUPPORT_MSIX)) && + !tg3_flag(tp, TAGGED_STATUS)) { /* All MSI supporting chips should support tagged * status. Assert that this is the case. */ @@ -9331,21 +9330,19 @@ static void tg3_ints_init(struct tg3 *tp) goto defcfg; } - if ((tp->tg3_flags & TG3_FLAG_SUPPORT_MSIX) && tg3_enable_msix(tp)) - tp->tg3_flags2 |= TG3_FLG2_USING_MSIX; - else if ((tp->tg3_flags & TG3_FLAG_SUPPORT_MSI) && - pci_enable_msi(tp->pdev) == 0) - tp->tg3_flags2 |= TG3_FLG2_USING_MSI; + if (tg3_flag(tp, SUPPORT_MSIX) && tg3_enable_msix(tp)) + tg3_flag_set(tp, USING_MSIX); + else if (tg3_flag(tp, SUPPORT_MSI) && pci_enable_msi(tp->pdev) == 0) + tg3_flag_set(tp, USING_MSI); - if (tp->tg3_flags2 & TG3_FLG2_USING_MSI_OR_MSIX) { + if (tg3_flag(tp, USING_MSI) || tg3_flag(tp, USING_MSIX)) { u32 msi_mode = tr32(MSGINT_MODE); - if ((tp->tg3_flags2 & TG3_FLG2_USING_MSIX) && - tp->irq_cnt > 1) + if (tg3_flag(tp, USING_MSIX) && tp->irq_cnt > 1) msi_mode |= MSGINT_MODE_MULTIVEC_EN; tw32(MSGINT_MODE, msi_mode | MSGINT_MODE_ENABLE); } defcfg: - if (!(tp->tg3_flags2 & TG3_FLG2_USING_MSIX)) { + if (!tg3_flag(tp, USING_MSIX)) { tp->irq_cnt = 1; tp->napi[0].irq_vec = tp->pdev->irq; netif_set_real_num_tx_queues(tp->dev, 1); @@ -9355,12 +9352,14 @@ defcfg: static void tg3_ints_fini(struct tg3 *tp) { - if (tp->tg3_flags2 & TG3_FLG2_USING_MSIX) + if (tg3_flag(tp, USING_MSIX)) pci_disable_msix(tp->pdev); - else if (tp->tg3_flags2 & TG3_FLG2_USING_MSI) + else if (tg3_flag(tp, USING_MSI)) pci_disable_msi(tp->pdev); - tp->tg3_flags2 &= ~TG3_FLG2_USING_MSI_OR_MSIX; - tp->tg3_flags3 &= ~(TG3_FLG3_ENABLE_RSS | TG3_FLG3_ENABLE_TSS); + tg3_flag_clear(tp, USING_MSI); + tg3_flag_clear(tp, USING_MSIX); + tg3_flag_clear(tp, ENABLE_RSS); + tg3_flag_clear(tp, ENABLE_TSS); } static int tg3_open(struct net_device *dev) @@ -9375,10 +9374,10 @@ static int tg3_open(struct net_device *dev) return err; } else if (err) { netdev_warn(tp->dev, "TSO capability disabled\n"); - tp->tg3_flags2 &= ~TG3_FLG2_TSO_CAPABLE; - } else if (!(tp->tg3_flags2 & TG3_FLG2_TSO_CAPABLE)) { + tg3_flag_clear(tp, TSO_CAPABLE); + } else if (!tg3_flag(tp, TSO_CAPABLE)) { netdev_notice(tp->dev, "TSO capability restored\n"); - tp->tg3_flags2 |= TG3_FLG2_TSO_CAPABLE; + tg3_flag_set(tp, TSO_CAPABLE); } } @@ -9391,7 +9390,7 @@ static int tg3_open(struct net_device *dev) tg3_full_lock(tp, 0); tg3_disable_ints(tp); - tp->tg3_flags &= ~TG3_FLAG_INIT_COMPLETE; + tg3_flag_clear(tp, INIT_COMPLETE); tg3_full_unlock(tp); @@ -9432,7 +9431,7 @@ static int tg3_open(struct net_device *dev) tg3_halt(tp, RESET_KIND_SHUTDOWN, 1); tg3_free_rings(tp); } else { - if (tp->tg3_flags & TG3_FLAG_TAGGED_STATUS) + if (tg3_flag(tp, TAGGED_STATUS)) tp->timer_offset = HZ; else tp->timer_offset = HZ / 10; @@ -9454,7 +9453,7 @@ static int tg3_open(struct net_device *dev) if (err) goto err_out3; - if (tp->tg3_flags2 & TG3_FLG2_USING_MSI) { + if (tg3_flag(tp, USING_MSI)) { err = tg3_test_msi(tp); if (err) { @@ -9466,8 +9465,7 @@ static int tg3_open(struct net_device *dev) goto err_out2; } - if (!(tp->tg3_flags3 & TG3_FLG3_57765_PLUS) && - (tp->tg3_flags2 & TG3_FLG2_USING_MSI)) { + if (!tg3_flag(tp, 57765_PLUS) && tg3_flag(tp, USING_MSI)) { u32 val = tr32(PCIE_TRANSACTION_CFG); tw32(PCIE_TRANSACTION_CFG, @@ -9480,7 +9478,7 @@ static int tg3_open(struct net_device *dev) tg3_full_lock(tp, 0); add_timer(&tp->timer); - tp->tg3_flags |= TG3_FLAG_INIT_COMPLETE; + tg3_flag_set(tp, INIT_COMPLETE); tg3_enable_ints(tp); tg3_full_unlock(tp); @@ -9529,7 +9527,7 @@ static int tg3_close(struct net_device *dev) tg3_halt(tp, RESET_KIND_SHUTDOWN, 1); tg3_free_rings(tp); - tp->tg3_flags &= ~TG3_FLAG_INIT_COMPLETE; + tg3_flag_clear(tp, INIT_COMPLETE); tg3_full_unlock(tp); @@ -9786,7 +9784,7 @@ static void __tg3_set_rx_mode(struct net_device *dev) /* When ASF is in use, we always keep the RX_MODE_KEEP_VLAN_TAG * flag clear. */ - if (!(tp->tg3_flags & TG3_FLAG_ENABLE_ASF)) + if (!tg3_flag(tp, ENABLE_ASF)) rx_mode |= RX_MODE_KEEP_VLAN_TAG; #endif @@ -9879,7 +9877,7 @@ static int tg3_get_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom, u32 i, offset, len, b_offset, b_count; __be32 val; - if (tp->tg3_flags3 & TG3_FLG3_NO_NVRAM) + if (tg3_flag(tp, NO_NVRAM)) return -EINVAL; if (tp->phy_flags & TG3_PHYFLG_IS_LOW_POWER) @@ -9947,7 +9945,7 @@ static int tg3_set_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom, if (tp->phy_flags & TG3_PHYFLG_IS_LOW_POWER) return -EAGAIN; - if ((tp->tg3_flags3 & TG3_FLG3_NO_NVRAM) || + if (tg3_flag(tp, NO_NVRAM) || eeprom->magic != TG3_EEPROM_MAGIC) return -EINVAL; @@ -9999,7 +9997,7 @@ static int tg3_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) { struct tg3 *tp = netdev_priv(dev); - if (tp->tg3_flags3 & TG3_FLG3_USE_PHYLIB) { + if (tg3_flag(tp, USE_PHYLIB)) { struct phy_device *phydev; if (!(tp->phy_flags & TG3_PHYFLG_IS_CONNECTED)) return -EAGAIN; @@ -10045,7 +10043,7 @@ static int tg3_set_settings(struct net_device *dev, struct ethtool_cmd *cmd) { struct tg3 *tp = netdev_priv(dev); - if (tp->tg3_flags3 & TG3_FLG3_USE_PHYLIB) { + if (tg3_flag(tp, USE_PHYLIB)) { struct phy_device *phydev; if (!(tp->phy_flags & TG3_PHYFLG_IS_CONNECTED)) return -EAGAIN; @@ -10145,14 +10143,12 @@ static void tg3_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol) { struct tg3 *tp = netdev_priv(dev); - if ((tp->tg3_flags & TG3_FLAG_WOL_CAP) && - device_can_wakeup(&tp->pdev->dev)) + if (tg3_flag(tp, WOL_CAP) && device_can_wakeup(&tp->pdev->dev)) wol->supported = WAKE_MAGIC; else wol->supported = 0; wol->wolopts = 0; - if ((tp->tg3_flags & TG3_FLAG_WOL_ENABLE) && - device_can_wakeup(&tp->pdev->dev)) + if (tg3_flag(tp, WOL_ENABLE) && device_can_wakeup(&tp->pdev->dev)) wol->wolopts = WAKE_MAGIC; memset(&wol->sopass, 0, sizeof(wol->sopass)); } @@ -10165,16 +10161,16 @@ static int tg3_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol) if (wol->wolopts & ~WAKE_MAGIC) return -EINVAL; if ((wol->wolopts & WAKE_MAGIC) && - !((tp->tg3_flags & TG3_FLAG_WOL_CAP) && device_can_wakeup(dp))) + !(tg3_flag(tp, WOL_CAP) && device_can_wakeup(dp))) return -EINVAL; device_set_wakeup_enable(dp, wol->wolopts & WAKE_MAGIC); spin_lock_bh(&tp->lock); if (device_may_wakeup(dp)) - tp->tg3_flags |= TG3_FLAG_WOL_ENABLE; + tg3_flag_set(tp, WOL_ENABLE); else - tp->tg3_flags &= ~TG3_FLAG_WOL_ENABLE; + tg3_flag_clear(tp, WOL_ENABLE); spin_unlock_bh(&tp->lock); return 0; @@ -10203,7 +10199,7 @@ static int tg3_nway_reset(struct net_device *dev) if (tp->phy_flags & TG3_PHYFLG_PHY_SERDES) return -EINVAL; - if (tp->tg3_flags3 & TG3_FLG3_USE_PHYLIB) { + if (tg3_flag(tp, USE_PHYLIB)) { if (!(tp->phy_flags & TG3_PHYFLG_IS_CONNECTED)) return -EAGAIN; r = phy_start_aneg(tp->mdio_bus->phy_map[TG3_PHY_MII_ADDR]); @@ -10232,7 +10228,7 @@ static void tg3_get_ringparam(struct net_device *dev, struct ethtool_ringparam * ering->rx_max_pending = tp->rx_std_ring_mask; ering->rx_mini_max_pending = 0; - if (tp->tg3_flags & TG3_FLAG_JUMBO_RING_ENABLE) + if (tg3_flag(tp, JUMBO_RING_ENABLE)) ering->rx_jumbo_max_pending = tp->rx_jmb_ring_mask; else ering->rx_jumbo_max_pending = 0; @@ -10241,7 +10237,7 @@ static void tg3_get_ringparam(struct net_device *dev, struct ethtool_ringparam * ering->rx_pending = tp->rx_pending; ering->rx_mini_pending = 0; - if (tp->tg3_flags & TG3_FLAG_JUMBO_RING_ENABLE) + if (tg3_flag(tp, JUMBO_RING_ENABLE)) ering->rx_jumbo_pending = tp->rx_jumbo_pending; else ering->rx_jumbo_pending = 0; @@ -10258,7 +10254,7 @@ static int tg3_set_ringparam(struct net_device *dev, struct ethtool_ringparam *e (ering->rx_jumbo_pending > tp->rx_jmb_ring_mask) || (ering->tx_pending > TG3_TX_RING_SIZE - 1) || (ering->tx_pending <= MAX_SKB_FRAGS) || - ((tp->tg3_flags2 & TG3_FLG2_TSO_BUG) && + (tg3_flag(tp, TSO_BUG) && (ering->tx_pending <= (MAX_SKB_FRAGS * 3)))) return -EINVAL; @@ -10272,7 +10268,7 @@ static int tg3_set_ringparam(struct net_device *dev, struct ethtool_ringparam *e tp->rx_pending = ering->rx_pending; - if ((tp->tg3_flags2 & TG3_FLG2_MAX_RXPEND_64) && + if (tg3_flag(tp, MAX_RXPEND_64) && tp->rx_pending > 63) tp->rx_pending = 63; tp->rx_jumbo_pending = ering->rx_jumbo_pending; @@ -10299,7 +10295,7 @@ static void tg3_get_pauseparam(struct net_device *dev, struct ethtool_pauseparam { struct tg3 *tp = netdev_priv(dev); - epause->autoneg = (tp->tg3_flags & TG3_FLAG_PAUSE_AUTONEG) != 0; + epause->autoneg = !!tg3_flag(tp, PAUSE_AUTONEG); if (tp->link_config.active_flowctrl & FLOW_CTRL_RX) epause->rx_pause = 1; @@ -10317,7 +10313,7 @@ static int tg3_set_pauseparam(struct net_device *dev, struct ethtool_pauseparam struct tg3 *tp = netdev_priv(dev); int err = 0; - if (tp->tg3_flags3 & TG3_FLG3_USE_PHYLIB) { + if (tg3_flag(tp, USE_PHYLIB)) { u32 newadv; struct phy_device *phydev; @@ -10345,9 +10341,9 @@ static int tg3_set_pauseparam(struct net_device *dev, struct ethtool_pauseparam newadv = 0; if (epause->autoneg) - tp->tg3_flags |= TG3_FLAG_PAUSE_AUTONEG; + tg3_flag_set(tp, PAUSE_AUTONEG); else - tp->tg3_flags &= ~TG3_FLAG_PAUSE_AUTONEG; + tg3_flag_clear(tp, PAUSE_AUTONEG); if (tp->phy_flags & TG3_PHYFLG_IS_CONNECTED) { u32 oldadv = phydev->advertising & @@ -10389,9 +10385,9 @@ static int tg3_set_pauseparam(struct net_device *dev, struct ethtool_pauseparam tg3_full_lock(tp, irq_sync); if (epause->autoneg) - tp->tg3_flags |= TG3_FLAG_PAUSE_AUTONEG; + tg3_flag_set(tp, PAUSE_AUTONEG); else - tp->tg3_flags &= ~TG3_FLAG_PAUSE_AUTONEG; + tg3_flag_clear(tp, PAUSE_AUTONEG); if (epause->rx_pause) tp->link_config.flowctrl |= FLOW_CTRL_RX; else @@ -10490,8 +10486,7 @@ static __be32 * tg3_vpd_readblock(struct tg3 *tp) u32 offset = 0, len = 0; u32 magic, val; - if ((tp->tg3_flags3 & TG3_FLG3_NO_NVRAM) || - tg3_nvram_read(tp, 0, &magic)) + if (tg3_flag(tp, NO_NVRAM) || tg3_nvram_read(tp, 0, &magic)) return NULL; if (magic == TG3_EEPROM_MAGIC) { @@ -10571,7 +10566,7 @@ static int tg3_test_nvram(struct tg3 *tp) __be32 *buf; int i, j, k, err = 0, size; - if (tp->tg3_flags3 & TG3_FLG3_NO_NVRAM) + if (tg3_flag(tp, NO_NVRAM)) return 0; if (tg3_nvram_read(tp, 0, &magic) != 0) @@ -10913,9 +10908,9 @@ static int tg3_test_registers(struct tg3 *tp) }; is_5705 = is_5750 = 0; - if (tp->tg3_flags2 & TG3_FLG2_5705_PLUS) { + if (tg3_flag(tp, 5705_PLUS)) { is_5705 = 1; - if (tp->tg3_flags2 & TG3_FLG2_5750_PLUS) + if (tg3_flag(tp, 5750_PLUS)) is_5750 = 1; } @@ -10926,7 +10921,7 @@ static int tg3_test_registers(struct tg3 *tp) if (!is_5705 && (reg_tbl[i].flags & TG3_FL_5705)) continue; - if ((tp->tg3_flags2 & TG3_FLG2_IS_5788) && + if (tg3_flag(tp, IS_5788) && (reg_tbl[i].flags & TG3_FL_NOT_5788)) continue; @@ -11049,15 +11044,15 @@ static int tg3_test_memory(struct tg3 *tp) int err = 0; int i; - if (tp->tg3_flags3 & TG3_FLG3_5717_PLUS) + if (tg3_flag(tp, 5717_PLUS)) mem_tbl = mem_tbl_5717; else if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57765) mem_tbl = mem_tbl_57765; - else if (tp->tg3_flags3 & TG3_FLG3_5755_PLUS) + else if (tg3_flag(tp, 5755_PLUS)) mem_tbl = mem_tbl_5755; else if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906) mem_tbl = mem_tbl_5906; - else if (tp->tg3_flags2 & TG3_FLG2_5705_PLUS) + else if (tg3_flag(tp, 5705_PLUS)) mem_tbl = mem_tbl_5705; else mem_tbl = mem_tbl_570x; @@ -11113,9 +11108,9 @@ static int tg3_run_loopback(struct tg3 *tp, u32 pktsz, int loopback_mode) tnapi = &tp->napi[0]; rnapi = &tp->napi[0]; if (tp->irq_cnt > 1) { - if (tp->tg3_flags3 & TG3_FLG3_ENABLE_RSS) + if (tg3_flag(tp, ENABLE_RSS)) rnapi = &tp->napi[1]; - if (tp->tg3_flags3 & TG3_FLG3_ENABLE_TSS) + if (tg3_flag(tp, ENABLE_TSS)) tnapi = &tp->napi[1]; } coal_now = tnapi->coal_now | rnapi->coal_now; @@ -11127,13 +11122,13 @@ static int tg3_run_loopback(struct tg3 *tp, u32 pktsz, int loopback_mode) * all newer ASIC revisions. */ if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5780 || - (tp->tg3_flags & TG3_FLAG_CPMU_PRESENT)) + tg3_flag(tp, CPMU_PRESENT)) return 0; mac_mode = tp->mac_mode & ~(MAC_MODE_PORT_MODE_MASK | MAC_MODE_HALF_DUPLEX); mac_mode |= MAC_MODE_PORT_INT_LPBACK; - if (!(tp->tg3_flags2 & TG3_FLG2_5705_PLUS)) + if (!tg3_flag(tp, 5705_PLUS)) mac_mode |= MAC_MODE_LINK_POLARITY; if (tp->phy_flags & TG3_PHYFLG_10_100_ONLY) mac_mode |= MAC_MODE_PORT_MODE_MII; @@ -11222,7 +11217,9 @@ static int tg3_run_loopback(struct tg3 *tp, u32 pktsz, int loopback_mode) base_flags = (TXD_FLAG_CPU_PRE_DMA | TXD_FLAG_CPU_POST_DMA); - if (tp->tg3_flags2 & TG3_FLG2_HW_TSO) { + if (tg3_flag(tp, HW_TSO_1) || + tg3_flag(tp, HW_TSO_2) || + tg3_flag(tp, HW_TSO_3)) { struct tcphdr *th; val = ETH_HLEN + TG3_TSO_IP_HDR_LEN; th = (struct tcphdr *)&tx_data[val]; @@ -11230,14 +11227,14 @@ static int tg3_run_loopback(struct tg3 *tp, u32 pktsz, int loopback_mode) } else base_flags |= TXD_FLAG_TCPUDP_CSUM; - if (tp->tg3_flags2 & TG3_FLG2_HW_TSO_3) { + if (tg3_flag(tp, HW_TSO_3)) { mss |= (hdr_len & 0xc) << 12; if (hdr_len & 0x10) base_flags |= 0x00000010; base_flags |= (hdr_len & 0x3e0) << 5; - } else if (tp->tg3_flags2 & TG3_FLG2_HW_TSO_2) + } else if (tg3_flag(tp, HW_TSO_2)) mss |= hdr_len << 9; - else if ((tp->tg3_flags2 & TG3_FLG2_HW_TSO_1) || + else if (tg3_flag(tp, HW_TSO_1) || GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5705) { mss |= (TG3_TSO_TCP_OPT_LEN << 9); } else { @@ -11381,7 +11378,7 @@ static int tg3_test_loopback(struct tg3 *tp) goto done; } - if (tp->tg3_flags3 & TG3_FLG3_ENABLE_RSS) { + if (tg3_flag(tp, ENABLE_RSS)) { int i; /* Reroute all rx packets to the 1st queue */ @@ -11394,7 +11391,7 @@ static int tg3_test_loopback(struct tg3 *tp) if (tp->phy_flags & TG3_PHYFLG_ENABLE_APD) tg3_phy_toggle_apd(tp, false); - if (tp->tg3_flags & TG3_FLAG_CPMU_PRESENT) { + if (tg3_flag(tp, CPMU_PRESENT)) { int i; u32 status; @@ -11423,11 +11420,11 @@ static int tg3_test_loopback(struct tg3 *tp) if (tg3_run_loopback(tp, ETH_FRAME_LEN, TG3_MAC_LOOPBACK)) err |= TG3_STD_LOOPBACK_FAILED << TG3_MAC_LOOPBACK_SHIFT; - if ((tp->tg3_flags & TG3_FLAG_JUMBO_RING_ENABLE) && + if (tg3_flag(tp, JUMBO_RING_ENABLE) && tg3_run_loopback(tp, 9000 + ETH_HLEN, TG3_MAC_LOOPBACK)) err |= TG3_JMB_LOOPBACK_FAILED << TG3_MAC_LOOPBACK_SHIFT; - if (tp->tg3_flags & TG3_FLAG_CPMU_PRESENT) { + if (tg3_flag(tp, CPMU_PRESENT)) { tw32(TG3_CPMU_CTRL, cpmuctrl); /* Release the mutex */ @@ -11435,15 +11432,15 @@ static int tg3_test_loopback(struct tg3 *tp) } if (!(tp->phy_flags & TG3_PHYFLG_PHY_SERDES) && - !(tp->tg3_flags3 & TG3_FLG3_USE_PHYLIB)) { + !tg3_flag(tp, USE_PHYLIB)) { if (tg3_run_loopback(tp, ETH_FRAME_LEN, TG3_PHY_LOOPBACK)) err |= TG3_STD_LOOPBACK_FAILED << TG3_PHY_LOOPBACK_SHIFT; - if ((tp->tg3_flags2 & TG3_FLG2_TSO_CAPABLE) && + if (tg3_flag(tp, TSO_CAPABLE) && tg3_run_loopback(tp, ETH_FRAME_LEN, TG3_TSO_LOOPBACK)) err |= TG3_TSO_LOOPBACK_FAILED << TG3_PHY_LOOPBACK_SHIFT; - if ((tp->tg3_flags & TG3_FLAG_JUMBO_RING_ENABLE) && + if (tg3_flag(tp, JUMBO_RING_ENABLE) && tg3_run_loopback(tp, 9000 + ETH_HLEN, TG3_PHY_LOOPBACK)) err |= TG3_JMB_LOOPBACK_FAILED << TG3_PHY_LOOPBACK_SHIFT; @@ -11491,7 +11488,7 @@ static void tg3_self_test(struct net_device *dev, struct ethtool_test *etest, tg3_halt(tp, RESET_KIND_SUSPEND, 1); err = tg3_nvram_lock(tp); tg3_halt_cpu(tp, RX_CPU_BASE); - if (!(tp->tg3_flags2 & TG3_FLG2_5705_PLUS)) + if (!tg3_flag(tp, 5705_PLUS)) tg3_halt_cpu(tp, TX_CPU_BASE); if (!err) tg3_nvram_unlock(tp); @@ -11521,7 +11518,7 @@ static void tg3_self_test(struct net_device *dev, struct ethtool_test *etest, tg3_halt(tp, RESET_KIND_SHUTDOWN, 1); if (netif_running(dev)) { - tp->tg3_flags |= TG3_FLAG_INIT_COMPLETE; + tg3_flag_set(tp, INIT_COMPLETE); err2 = tg3_restart_hw(tp, 1); if (!err2) tg3_netif_start(tp); @@ -11543,7 +11540,7 @@ static int tg3_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) struct tg3 *tp = netdev_priv(dev); int err; - if (tp->tg3_flags3 & TG3_FLG3_USE_PHYLIB) { + if (tg3_flag(tp, USE_PHYLIB)) { struct phy_device *phydev; if (!(tp->phy_flags & TG3_PHYFLG_IS_CONNECTED)) return -EAGAIN; @@ -11608,7 +11605,7 @@ static int tg3_set_coalesce(struct net_device *dev, struct ethtool_coalesce *ec) u32 max_rxcoal_tick_int = 0, max_txcoal_tick_int = 0; u32 max_stat_coal_ticks = 0, min_stat_coal_ticks = 0; - if (!(tp->tg3_flags2 & TG3_FLG2_5705_PLUS)) { + if (!tg3_flag(tp, 5705_PLUS)) { max_rxcoal_tick_int = MAX_RXCOAL_TICK_INT; max_txcoal_tick_int = MAX_TXCOAL_TICK_INT; max_stat_coal_ticks = MAX_STAT_COAL_TICKS; @@ -11722,8 +11719,7 @@ static void __devinit tg3_get_nvram_size(struct tg3 *tp) { u32 val; - if ((tp->tg3_flags3 & TG3_FLG3_NO_NVRAM) || - tg3_nvram_read(tp, 0, &val) != 0) + if (tg3_flag(tp, NO_NVRAM) || tg3_nvram_read(tp, 0, &val) != 0) return; /* Selfboot format */ @@ -11758,19 +11754,19 @@ static void __devinit tg3_get_nvram_info(struct tg3 *tp) nvcfg1 = tr32(NVRAM_CFG1); if (nvcfg1 & NVRAM_CFG1_FLASHIF_ENAB) { - tp->tg3_flags2 |= TG3_FLG2_FLASH; + tg3_flag_set(tp, FLASH); } else { nvcfg1 &= ~NVRAM_CFG1_COMPAT_BYPASS; tw32(NVRAM_CFG1, nvcfg1); } if ((GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5750) || - (tp->tg3_flags2 & TG3_FLG2_5780_CLASS)) { + tg3_flag(tp, 5780_CLASS)) { switch (nvcfg1 & NVRAM_CFG1_VENDOR_MASK) { case FLASH_VENDOR_ATMEL_FLASH_BUFFERED: tp->nvram_jedecnum = JEDEC_ATMEL; tp->nvram_pagesize = ATMEL_AT45DB0X1B_PAGE_SIZE; - tp->tg3_flags |= TG3_FLAG_NVRAM_BUFFERED; + tg3_flag_set(tp, NVRAM_BUFFERED); break; case FLASH_VENDOR_ATMEL_FLASH_UNBUFFERED: tp->nvram_jedecnum = JEDEC_ATMEL; @@ -11779,12 +11775,12 @@ static void __devinit tg3_get_nvram_info(struct tg3 *tp) case FLASH_VENDOR_ATMEL_EEPROM: tp->nvram_jedecnum = JEDEC_ATMEL; tp->nvram_pagesize = ATMEL_AT24C512_CHIP_SIZE; - tp->tg3_flags |= TG3_FLAG_NVRAM_BUFFERED; + tg3_flag_set(tp, NVRAM_BUFFERED); break; case FLASH_VENDOR_ST: tp->nvram_jedecnum = JEDEC_ST; tp->nvram_pagesize = ST_M45PEX0_PAGE_SIZE; - tp->tg3_flags |= TG3_FLAG_NVRAM_BUFFERED; + tg3_flag_set(tp, NVRAM_BUFFERED); break; case FLASH_VENDOR_SAIFUN: tp->nvram_jedecnum = JEDEC_SAIFUN; @@ -11799,7 +11795,7 @@ static void __devinit tg3_get_nvram_info(struct tg3 *tp) } else { tp->nvram_jedecnum = JEDEC_ATMEL; tp->nvram_pagesize = ATMEL_AT45DB0X1B_PAGE_SIZE; - tp->tg3_flags |= TG3_FLAG_NVRAM_BUFFERED; + tg3_flag_set(tp, NVRAM_BUFFERED); } } @@ -11838,29 +11834,29 @@ static void __devinit tg3_get_5752_nvram_info(struct tg3 *tp) /* NVRAM protection for TPM */ if (nvcfg1 & (1 << 27)) - tp->tg3_flags3 |= TG3_FLG3_PROTECTED_NVRAM; + tg3_flag_set(tp, PROTECTED_NVRAM); switch (nvcfg1 & NVRAM_CFG1_5752VENDOR_MASK) { case FLASH_5752VENDOR_ATMEL_EEPROM_64KHZ: case FLASH_5752VENDOR_ATMEL_EEPROM_376KHZ: tp->nvram_jedecnum = JEDEC_ATMEL; - tp->tg3_flags |= TG3_FLAG_NVRAM_BUFFERED; + tg3_flag_set(tp, NVRAM_BUFFERED); break; case FLASH_5752VENDOR_ATMEL_FLASH_BUFFERED: tp->nvram_jedecnum = JEDEC_ATMEL; - tp->tg3_flags |= TG3_FLAG_NVRAM_BUFFERED; - tp->tg3_flags2 |= TG3_FLG2_FLASH; + tg3_flag_set(tp, NVRAM_BUFFERED); + tg3_flag_set(tp, FLASH); break; case FLASH_5752VENDOR_ST_M45PE10: case FLASH_5752VENDOR_ST_M45PE20: case FLASH_5752VENDOR_ST_M45PE40: tp->nvram_jedecnum = JEDEC_ST; - tp->tg3_flags |= TG3_FLAG_NVRAM_BUFFERED; - tp->tg3_flags2 |= TG3_FLG2_FLASH; + tg3_flag_set(tp, NVRAM_BUFFERED); + tg3_flag_set(tp, FLASH); break; } - if (tp->tg3_flags2 & TG3_FLG2_FLASH) { + if (tg3_flag(tp, FLASH)) { tg3_nvram_get_pagesize(tp, nvcfg1); } else { /* For eeprom, set pagesize to maximum eeprom size */ @@ -11879,7 +11875,7 @@ static void __devinit tg3_get_5755_nvram_info(struct tg3 *tp) /* NVRAM protection for TPM */ if (nvcfg1 & (1 << 27)) { - tp->tg3_flags3 |= TG3_FLG3_PROTECTED_NVRAM; + tg3_flag_set(tp, PROTECTED_NVRAM); protect = 1; } @@ -11890,8 +11886,8 @@ static void __devinit tg3_get_5755_nvram_info(struct tg3 *tp) case FLASH_5755VENDOR_ATMEL_FLASH_3: case FLASH_5755VENDOR_ATMEL_FLASH_5: tp->nvram_jedecnum = JEDEC_ATMEL; - tp->tg3_flags |= TG3_FLAG_NVRAM_BUFFERED; - tp->tg3_flags2 |= TG3_FLG2_FLASH; + tg3_flag_set(tp, NVRAM_BUFFERED); + tg3_flag_set(tp, FLASH); tp->nvram_pagesize = 264; if (nvcfg1 == FLASH_5755VENDOR_ATMEL_FLASH_1 || nvcfg1 == FLASH_5755VENDOR_ATMEL_FLASH_5) @@ -11908,8 +11904,8 @@ static void __devinit tg3_get_5755_nvram_info(struct tg3 *tp) case FLASH_5752VENDOR_ST_M45PE20: case FLASH_5752VENDOR_ST_M45PE40: tp->nvram_jedecnum = JEDEC_ST; - tp->tg3_flags |= TG3_FLAG_NVRAM_BUFFERED; - tp->tg3_flags2 |= TG3_FLG2_FLASH; + tg3_flag_set(tp, NVRAM_BUFFERED); + tg3_flag_set(tp, FLASH); tp->nvram_pagesize = 256; if (nvcfg1 == FLASH_5752VENDOR_ST_M45PE10) tp->nvram_size = (protect ? @@ -11939,7 +11935,7 @@ static void __devinit tg3_get_5787_nvram_info(struct tg3 *tp) case FLASH_5787VENDOR_MICRO_EEPROM_64KHZ: case FLASH_5787VENDOR_MICRO_EEPROM_376KHZ: tp->nvram_jedecnum = JEDEC_ATMEL; - tp->tg3_flags |= TG3_FLAG_NVRAM_BUFFERED; + tg3_flag_set(tp, NVRAM_BUFFERED); tp->nvram_pagesize = ATMEL_AT24C512_CHIP_SIZE; nvcfg1 &= ~NVRAM_CFG1_COMPAT_BYPASS; @@ -11950,16 +11946,16 @@ static void __devinit tg3_get_5787_nvram_info(struct tg3 *tp) case FLASH_5755VENDOR_ATMEL_FLASH_2: case FLASH_5755VENDOR_ATMEL_FLASH_3: tp->nvram_jedecnum = JEDEC_ATMEL; - tp->tg3_flags |= TG3_FLAG_NVRAM_BUFFERED; - tp->tg3_flags2 |= TG3_FLG2_FLASH; + tg3_flag_set(tp, NVRAM_BUFFERED); + tg3_flag_set(tp, FLASH); tp->nvram_pagesize = 264; break; case FLASH_5752VENDOR_ST_M45PE10: case FLASH_5752VENDOR_ST_M45PE20: case FLASH_5752VENDOR_ST_M45PE40: tp->nvram_jedecnum = JEDEC_ST; - tp->tg3_flags |= TG3_FLAG_NVRAM_BUFFERED; - tp->tg3_flags2 |= TG3_FLG2_FLASH; + tg3_flag_set(tp, NVRAM_BUFFERED); + tg3_flag_set(tp, FLASH); tp->nvram_pagesize = 256; break; } @@ -11973,7 +11969,7 @@ static void __devinit tg3_get_5761_nvram_info(struct tg3 *tp) /* NVRAM protection for TPM */ if (nvcfg1 & (1 << 27)) { - tp->tg3_flags3 |= TG3_FLG3_PROTECTED_NVRAM; + tg3_flag_set(tp, PROTECTED_NVRAM); protect = 1; } @@ -11988,9 +11984,9 @@ static void __devinit tg3_get_5761_nvram_info(struct tg3 *tp) case FLASH_5761VENDOR_ATMEL_MDB081D: case FLASH_5761VENDOR_ATMEL_MDB161D: tp->nvram_jedecnum = JEDEC_ATMEL; - tp->tg3_flags |= TG3_FLAG_NVRAM_BUFFERED; - tp->tg3_flags2 |= TG3_FLG2_FLASH; - tp->tg3_flags3 |= TG3_FLG3_NO_NVRAM_ADDR_TRANS; + tg3_flag_set(tp, NVRAM_BUFFERED); + tg3_flag_set(tp, FLASH); + tg3_flag_set(tp, NO_NVRAM_ADDR_TRANS); tp->nvram_pagesize = 256; break; case FLASH_5761VENDOR_ST_A_M45PE20: @@ -12002,8 +11998,8 @@ static void __devinit tg3_get_5761_nvram_info(struct tg3 *tp) case FLASH_5761VENDOR_ST_M_M45PE80: case FLASH_5761VENDOR_ST_M_M45PE16: tp->nvram_jedecnum = JEDEC_ST; - tp->tg3_flags |= TG3_FLAG_NVRAM_BUFFERED; - tp->tg3_flags2 |= TG3_FLG2_FLASH; + tg3_flag_set(tp, NVRAM_BUFFERED); + tg3_flag_set(tp, FLASH); tp->nvram_pagesize = 256; break; } @@ -12043,7 +12039,7 @@ static void __devinit tg3_get_5761_nvram_info(struct tg3 *tp) static void __devinit tg3_get_5906_nvram_info(struct tg3 *tp) { tp->nvram_jedecnum = JEDEC_ATMEL; - tp->tg3_flags |= TG3_FLAG_NVRAM_BUFFERED; + tg3_flag_set(tp, NVRAM_BUFFERED); tp->nvram_pagesize = ATMEL_AT24C512_CHIP_SIZE; } @@ -12057,7 +12053,7 @@ static void __devinit tg3_get_57780_nvram_info(struct tg3 *tp) case FLASH_5787VENDOR_ATMEL_EEPROM_376KHZ: case FLASH_5787VENDOR_MICRO_EEPROM_376KHZ: tp->nvram_jedecnum = JEDEC_ATMEL; - tp->tg3_flags |= TG3_FLAG_NVRAM_BUFFERED; + tg3_flag_set(tp, NVRAM_BUFFERED); tp->nvram_pagesize = ATMEL_AT24C512_CHIP_SIZE; nvcfg1 &= ~NVRAM_CFG1_COMPAT_BYPASS; @@ -12071,8 +12067,8 @@ static void __devinit tg3_get_57780_nvram_info(struct tg3 *tp) case FLASH_57780VENDOR_ATMEL_AT45DB041D: case FLASH_57780VENDOR_ATMEL_AT45DB041B: tp->nvram_jedecnum = JEDEC_ATMEL; - tp->tg3_flags |= TG3_FLAG_NVRAM_BUFFERED; - tp->tg3_flags2 |= TG3_FLG2_FLASH; + tg3_flag_set(tp, NVRAM_BUFFERED); + tg3_flag_set(tp, FLASH); switch (nvcfg1 & NVRAM_CFG1_5752VENDOR_MASK) { case FLASH_5752VENDOR_ATMEL_FLASH_BUFFERED: @@ -12094,8 +12090,8 @@ static void __devinit tg3_get_57780_nvram_info(struct tg3 *tp) case FLASH_5752VENDOR_ST_M45PE20: case FLASH_5752VENDOR_ST_M45PE40: tp->nvram_jedecnum = JEDEC_ST; - tp->tg3_flags |= TG3_FLAG_NVRAM_BUFFERED; - tp->tg3_flags2 |= TG3_FLG2_FLASH; + tg3_flag_set(tp, NVRAM_BUFFERED); + tg3_flag_set(tp, FLASH); switch (nvcfg1 & NVRAM_CFG1_5752VENDOR_MASK) { case FLASH_5752VENDOR_ST_M45PE10: @@ -12110,13 +12106,13 @@ static void __devinit tg3_get_57780_nvram_info(struct tg3 *tp) } break; default: - tp->tg3_flags3 |= TG3_FLG3_NO_NVRAM; + tg3_flag_set(tp, NO_NVRAM); return; } tg3_nvram_get_pagesize(tp, nvcfg1); if (tp->nvram_pagesize != 264 && tp->nvram_pagesize != 528) - tp->tg3_flags3 |= TG3_FLG3_NO_NVRAM_ADDR_TRANS; + tg3_flag_set(tp, NO_NVRAM_ADDR_TRANS); } @@ -12130,7 +12126,7 @@ static void __devinit tg3_get_5717_nvram_info(struct tg3 *tp) case FLASH_5717VENDOR_ATMEL_EEPROM: case FLASH_5717VENDOR_MICRO_EEPROM: tp->nvram_jedecnum = JEDEC_ATMEL; - tp->tg3_flags |= TG3_FLAG_NVRAM_BUFFERED; + tg3_flag_set(tp, NVRAM_BUFFERED); tp->nvram_pagesize = ATMEL_AT24C512_CHIP_SIZE; nvcfg1 &= ~NVRAM_CFG1_COMPAT_BYPASS; @@ -12144,8 +12140,8 @@ static void __devinit tg3_get_5717_nvram_info(struct tg3 *tp) case FLASH_5717VENDOR_ATMEL_ADB021D: case FLASH_5717VENDOR_ATMEL_45USPT: tp->nvram_jedecnum = JEDEC_ATMEL; - tp->tg3_flags |= TG3_FLAG_NVRAM_BUFFERED; - tp->tg3_flags2 |= TG3_FLG2_FLASH; + tg3_flag_set(tp, NVRAM_BUFFERED); + tg3_flag_set(tp, FLASH); switch (nvcfg1 & NVRAM_CFG1_5752VENDOR_MASK) { case FLASH_5717VENDOR_ATMEL_MDB021D: @@ -12171,8 +12167,8 @@ static void __devinit tg3_get_5717_nvram_info(struct tg3 *tp) case FLASH_5717VENDOR_ST_25USPT: case FLASH_5717VENDOR_ST_45USPT: tp->nvram_jedecnum = JEDEC_ST; - tp->tg3_flags |= TG3_FLAG_NVRAM_BUFFERED; - tp->tg3_flags2 |= TG3_FLG2_FLASH; + tg3_flag_set(tp, NVRAM_BUFFERED); + tg3_flag_set(tp, FLASH); switch (nvcfg1 & NVRAM_CFG1_5752VENDOR_MASK) { case FLASH_5717VENDOR_ST_M_M25PE20: @@ -12189,13 +12185,13 @@ static void __devinit tg3_get_5717_nvram_info(struct tg3 *tp) } break; default: - tp->tg3_flags3 |= TG3_FLG3_NO_NVRAM; + tg3_flag_set(tp, NO_NVRAM); return; } tg3_nvram_get_pagesize(tp, nvcfg1); if (tp->nvram_pagesize != 264 && tp->nvram_pagesize != 528) - tp->tg3_flags3 |= TG3_FLG3_NO_NVRAM_ADDR_TRANS; + tg3_flag_set(tp, NO_NVRAM_ADDR_TRANS); } static void __devinit tg3_get_5720_nvram_info(struct tg3 *tp) @@ -12209,7 +12205,7 @@ static void __devinit tg3_get_5720_nvram_info(struct tg3 *tp) case FLASH_5720_EEPROM_HD: case FLASH_5720_EEPROM_LD: tp->nvram_jedecnum = JEDEC_ATMEL; - tp->tg3_flags |= TG3_FLAG_NVRAM_BUFFERED; + tg3_flag_set(tp, NVRAM_BUFFERED); nvcfg1 &= ~NVRAM_CFG1_COMPAT_BYPASS; tw32(NVRAM_CFG1, nvcfg1); @@ -12231,8 +12227,8 @@ static void __devinit tg3_get_5720_nvram_info(struct tg3 *tp) case FLASH_5720VENDOR_A_ATMEL_DB081D: case FLASH_5720VENDOR_ATMEL_45USPT: tp->nvram_jedecnum = JEDEC_ATMEL; - tp->tg3_flags |= TG3_FLAG_NVRAM_BUFFERED; - tp->tg3_flags2 |= TG3_FLG2_FLASH; + tg3_flag_set(tp, NVRAM_BUFFERED); + tg3_flag_set(tp, FLASH); switch (nvmpinstrp) { case FLASH_5720VENDOR_M_ATMEL_DB021D: @@ -12273,8 +12269,8 @@ static void __devinit tg3_get_5720_nvram_info(struct tg3 *tp) case FLASH_5720VENDOR_ST_25USPT: case FLASH_5720VENDOR_ST_45USPT: tp->nvram_jedecnum = JEDEC_ST; - tp->tg3_flags |= TG3_FLAG_NVRAM_BUFFERED; - tp->tg3_flags2 |= TG3_FLG2_FLASH; + tg3_flag_set(tp, NVRAM_BUFFERED); + tg3_flag_set(tp, FLASH); switch (nvmpinstrp) { case FLASH_5720VENDOR_M_ST_M25PE20: @@ -12301,13 +12297,13 @@ static void __devinit tg3_get_5720_nvram_info(struct tg3 *tp) } break; default: - tp->tg3_flags3 |= TG3_FLG3_NO_NVRAM; + tg3_flag_set(tp, NO_NVRAM); return; } tg3_nvram_get_pagesize(tp, nvcfg1); if (tp->nvram_pagesize != 264 && tp->nvram_pagesize != 528) - tp->tg3_flags3 |= TG3_FLG3_NO_NVRAM_ADDR_TRANS; + tg3_flag_set(tp, NO_NVRAM_ADDR_TRANS); } /* Chips other than 5700/5701 use the NVRAM for fetching info. */ @@ -12327,7 +12323,7 @@ static void __devinit tg3_nvram_init(struct tg3 *tp) if (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5700 && GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5701) { - tp->tg3_flags |= TG3_FLAG_NVRAM; + tg3_flag_set(tp, NVRAM); if (tg3_nvram_lock(tp)) { netdev_warn(tp->dev, @@ -12369,7 +12365,8 @@ static void __devinit tg3_nvram_init(struct tg3 *tp) tg3_nvram_unlock(tp); } else { - tp->tg3_flags &= ~(TG3_FLAG_NVRAM | TG3_FLAG_NVRAM_BUFFERED); + tg3_flag_clear(tp, NVRAM); + tg3_flag_clear(tp, NVRAM_BUFFERED); tg3_get_eeprom_size(tp); } @@ -12552,7 +12549,7 @@ static int tg3_nvram_write_block_buffered(struct tg3 *tp, u32 offset, u32 len, nvram_cmd |= NVRAM_CMD_LAST; if (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5752 && - !(tp->tg3_flags3 & TG3_FLG3_5755_PLUS) && + !tg3_flag(tp, 5755_PLUS) && (tp->nvram_jedecnum == JEDEC_ST) && (nvram_cmd & NVRAM_CMD_FIRST)) { @@ -12562,7 +12559,7 @@ static int tg3_nvram_write_block_buffered(struct tg3 *tp, u32 offset, u32 len, break; } - if (!(tp->tg3_flags2 & TG3_FLG2_FLASH)) { + if (!tg3_flag(tp, FLASH)) { /* We always do complete word writes to eeprom. */ nvram_cmd |= (NVRAM_CMD_FIRST | NVRAM_CMD_LAST); } @@ -12578,13 +12575,13 @@ static int tg3_nvram_write_block(struct tg3 *tp, u32 offset, u32 len, u8 *buf) { int ret; - if (tp->tg3_flags & TG3_FLAG_EEPROM_WRITE_PROT) { + if (tg3_flag(tp, EEPROM_WRITE_PROT)) { tw32_f(GRC_LOCAL_CTRL, tp->grc_local_ctrl & ~GRC_LCLCTRL_GPIO_OUTPUT1); udelay(40); } - if (!(tp->tg3_flags & TG3_FLAG_NVRAM)) { + if (!tg3_flag(tp, NVRAM)) { ret = tg3_nvram_write_block_using_eeprom(tp, offset, len, buf); } else { u32 grc_mode; @@ -12594,16 +12591,13 @@ static int tg3_nvram_write_block(struct tg3 *tp, u32 offset, u32 len, u8 *buf) return ret; tg3_enable_nvram_access(tp); - if ((tp->tg3_flags2 & TG3_FLG2_5750_PLUS) && - !(tp->tg3_flags3 & TG3_FLG3_PROTECTED_NVRAM)) + if (tg3_flag(tp, 5750_PLUS) && !tg3_flag(tp, PROTECTED_NVRAM)) tw32(NVRAM_WRITE1, 0x406); grc_mode = tr32(GRC_MODE); tw32(GRC_MODE, grc_mode | GRC_MODE_NVRAM_WR_ENABLE); - if ((tp->tg3_flags & TG3_FLAG_NVRAM_BUFFERED) || - !(tp->tg3_flags2 & TG3_FLG2_FLASH)) { - + if (tg3_flag(tp, NVRAM_BUFFERED) || !tg3_flag(tp, FLASH)) { ret = tg3_nvram_write_block_buffered(tp, offset, len, buf); } else { @@ -12618,7 +12612,7 @@ static int tg3_nvram_write_block(struct tg3 *tp, u32 offset, u32 len, u8 *buf) tg3_nvram_unlock(tp); } - if (tp->tg3_flags & TG3_FLAG_EEPROM_WRITE_PROT) { + if (tg3_flag(tp, EEPROM_WRITE_PROT)) { tw32_f(GRC_LOCAL_CTRL, tp->grc_local_ctrl); udelay(40); } @@ -12740,19 +12734,20 @@ static void __devinit tg3_get_eeprom_hw_cfg(struct tg3 *tp) tp->led_ctrl = LED_CTRL_MODE_PHY_1; /* Assume an onboard device and WOL capable by default. */ - tp->tg3_flags |= TG3_FLAG_EEPROM_WRITE_PROT | TG3_FLAG_WOL_CAP; + tg3_flag_set(tp, EEPROM_WRITE_PROT); + tg3_flag_set(tp, WOL_CAP); if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906) { if (!(tr32(PCIE_TRANSACTION_CFG) & PCIE_TRANS_CFG_LOM)) { - tp->tg3_flags &= ~TG3_FLAG_EEPROM_WRITE_PROT; - tp->tg3_flags2 |= TG3_FLG2_IS_NIC; + tg3_flag_clear(tp, EEPROM_WRITE_PROT); + tg3_flag_set(tp, IS_NIC); } val = tr32(VCPU_CFGSHDW); if (val & VCPU_CFGSHDW_ASPM_DBNC) - tp->tg3_flags |= TG3_FLAG_ASPM_WORKAROUND; + tg3_flag_set(tp, ASPM_WORKAROUND); if ((val & VCPU_CFGSHDW_WOL_ENABLE) && (val & VCPU_CFGSHDW_WOL_MAGPKT)) - tp->tg3_flags |= TG3_FLAG_WOL_ENABLE; + tg3_flag_set(tp, WOL_ENABLE); goto done; } @@ -12793,13 +12788,13 @@ static void __devinit tg3_get_eeprom_hw_cfg(struct tg3 *tp) tp->phy_id = eeprom_phy_id; if (eeprom_phy_serdes) { - if (!(tp->tg3_flags2 & TG3_FLG2_5705_PLUS)) + if (!tg3_flag(tp, 5705_PLUS)) tp->phy_flags |= TG3_PHYFLG_PHY_SERDES; else tp->phy_flags |= TG3_PHYFLG_MII_SERDES; } - if (tp->tg3_flags2 & TG3_FLG2_5750_PLUS) + if (tg3_flag(tp, 5750_PLUS)) led_cfg = cfg2 & (NIC_SRAM_DATA_CFG_LED_MODE_MASK | SHASTA_EXT_LED_MODE_MASK); else @@ -12859,34 +12854,34 @@ static void __devinit tg3_get_eeprom_hw_cfg(struct tg3 *tp) tp->led_ctrl = LED_CTRL_MODE_PHY_1; if (nic_cfg & NIC_SRAM_DATA_CFG_EEPROM_WP) { - tp->tg3_flags |= TG3_FLAG_EEPROM_WRITE_PROT; + tg3_flag_set(tp, EEPROM_WRITE_PROT); if ((tp->pdev->subsystem_vendor == PCI_VENDOR_ID_ARIMA) && (tp->pdev->subsystem_device == 0x205a || tp->pdev->subsystem_device == 0x2063)) - tp->tg3_flags &= ~TG3_FLAG_EEPROM_WRITE_PROT; + tg3_flag_clear(tp, EEPROM_WRITE_PROT); } else { - tp->tg3_flags &= ~TG3_FLAG_EEPROM_WRITE_PROT; - tp->tg3_flags2 |= TG3_FLG2_IS_NIC; + tg3_flag_clear(tp, EEPROM_WRITE_PROT); + tg3_flag_set(tp, IS_NIC); } if (nic_cfg & NIC_SRAM_DATA_CFG_ASF_ENABLE) { - tp->tg3_flags |= TG3_FLAG_ENABLE_ASF; - if (tp->tg3_flags2 & TG3_FLG2_5750_PLUS) - tp->tg3_flags2 |= TG3_FLG2_ASF_NEW_HANDSHAKE; + tg3_flag_set(tp, ENABLE_ASF); + if (tg3_flag(tp, 5750_PLUS)) + tg3_flag_set(tp, ASF_NEW_HANDSHAKE); } if ((nic_cfg & NIC_SRAM_DATA_CFG_APE_ENABLE) && - (tp->tg3_flags2 & TG3_FLG2_5750_PLUS)) - tp->tg3_flags3 |= TG3_FLG3_ENABLE_APE; + tg3_flag(tp, 5750_PLUS)) + tg3_flag_set(tp, ENABLE_APE); if (tp->phy_flags & TG3_PHYFLG_ANY_SERDES && !(nic_cfg & NIC_SRAM_DATA_CFG_FIBER_WOL)) - tp->tg3_flags &= ~TG3_FLAG_WOL_CAP; + tg3_flag_clear(tp, WOL_CAP); - if ((tp->tg3_flags & TG3_FLAG_WOL_CAP) && + if (tg3_flag(tp, WOL_CAP) && (nic_cfg & NIC_SRAM_DATA_CFG_WOL_ENABLE)) - tp->tg3_flags |= TG3_FLAG_WOL_ENABLE; + tg3_flag_set(tp, WOL_ENABLE); if (cfg2 & (1 << 17)) tp->phy_flags |= TG3_PHYFLG_CAPACITIVE_COUPLING; @@ -12896,33 +12891,33 @@ static void __devinit tg3_get_eeprom_hw_cfg(struct tg3 *tp) if (cfg2 & (1 << 18)) tp->phy_flags |= TG3_PHYFLG_SERDES_PREEMPHASIS; - if (((tp->tg3_flags3 & TG3_FLG3_57765_PLUS) || - ((GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784 && - GET_CHIP_REV(tp->pci_chip_rev_id) != CHIPREV_5784_AX))) && + if ((tg3_flag(tp, 57765_PLUS) || + (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784 && + GET_CHIP_REV(tp->pci_chip_rev_id) != CHIPREV_5784_AX)) && (cfg2 & NIC_SRAM_DATA_CFG_2_APD_EN)) tp->phy_flags |= TG3_PHYFLG_ENABLE_APD; - if ((tp->tg3_flags2 & TG3_FLG2_PCI_EXPRESS) && + if (tg3_flag(tp, PCI_EXPRESS) && GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5785 && - !(tp->tg3_flags3 & TG3_FLG3_57765_PLUS)) { + !tg3_flag(tp, 57765_PLUS)) { u32 cfg3; tg3_read_mem(tp, NIC_SRAM_DATA_CFG_3, &cfg3); if (cfg3 & NIC_SRAM_ASPM_DEBOUNCE) - tp->tg3_flags |= TG3_FLAG_ASPM_WORKAROUND; + tg3_flag_set(tp, ASPM_WORKAROUND); } if (cfg4 & NIC_SRAM_RGMII_INBAND_DISABLE) - tp->tg3_flags3 |= TG3_FLG3_RGMII_INBAND_DISABLE; + tg3_flag_set(tp, RGMII_INBAND_DISABLE); if (cfg4 & NIC_SRAM_RGMII_EXT_IBND_RX_EN) - tp->tg3_flags3 |= TG3_FLG3_RGMII_EXT_IBND_RX_EN; + tg3_flag_set(tp, RGMII_EXT_IBND_RX_EN); if (cfg4 & NIC_SRAM_RGMII_EXT_IBND_TX_EN) - tp->tg3_flags3 |= TG3_FLG3_RGMII_EXT_IBND_TX_EN; + tg3_flag_set(tp, RGMII_EXT_IBND_TX_EN); } done: - if (tp->tg3_flags & TG3_FLAG_WOL_CAP) + if (tg3_flag(tp, WOL_CAP)) device_set_wakeup_enable(&tp->pdev->dev, - tp->tg3_flags & TG3_FLAG_WOL_ENABLE); + tg3_flag(tp, WOL_ENABLE)); else device_set_wakeup_capable(&tp->pdev->dev, false); } @@ -13012,18 +13007,17 @@ static int __devinit tg3_phy_probe(struct tg3 *tp) int err; /* flow control autonegotiation is default behavior */ - tp->tg3_flags |= TG3_FLAG_PAUSE_AUTONEG; + tg3_flag_set(tp, PAUSE_AUTONEG); tp->link_config.flowctrl = FLOW_CTRL_TX | FLOW_CTRL_RX; - if (tp->tg3_flags3 & TG3_FLG3_USE_PHYLIB) + if (tg3_flag(tp, USE_PHYLIB)) return tg3_phy_init(tp); /* Reading the PHY ID register can conflict with ASF * firmware access to the PHY hardware. */ err = 0; - if ((tp->tg3_flags & TG3_FLAG_ENABLE_ASF) || - (tp->tg3_flags3 & TG3_FLG3_ENABLE_APE)) { + if (tg3_flag(tp, ENABLE_ASF) || tg3_flag(tp, ENABLE_APE)) { hw_phy_id = hw_phy_id_masked = TG3_PHY_ID_INVALID; } else { /* Now read the physical PHY_ID from the chip and verify @@ -13079,8 +13073,8 @@ static int __devinit tg3_phy_probe(struct tg3 *tp) tg3_phy_init_link_config(tp); if (!(tp->phy_flags & TG3_PHYFLG_ANY_SERDES) && - !(tp->tg3_flags3 & TG3_FLG3_ENABLE_APE) && - !(tp->tg3_flags & TG3_FLAG_ENABLE_ASF)) { + !tg3_flag(tp, ENABLE_APE) && + !tg3_flag(tp, ENABLE_ASF)) { u32 bmsr, adv_reg, tg3_ctrl, mask; tg3_readphy(tp, MII_BMSR, &bmsr); @@ -13399,7 +13393,7 @@ static void __devinit tg3_read_mgmtfw_ver(struct tg3 *tp) if (offset == TG3_NVM_DIR_END) return; - if (!(tp->tg3_flags2 & TG3_FLG2_5705_PLUS)) + if (!tg3_flag(tp, 5705_PLUS)) start = 0x08000000; else if (tg3_nvram_read(tp, offset - 4, &start)) return; @@ -13439,8 +13433,7 @@ static void __devinit tg3_read_dash_ver(struct tg3 *tp) u32 apedata; char *fwtype; - if (!(tp->tg3_flags3 & TG3_FLG3_ENABLE_APE) || - !(tp->tg3_flags & TG3_FLAG_ENABLE_ASF)) + if (!tg3_flag(tp, ENABLE_APE) || !tg3_flag(tp, ENABLE_ASF)) return; apedata = tg3_ape_read32(tp, TG3_APE_SEG_SIG); @@ -13454,7 +13447,7 @@ static void __devinit tg3_read_dash_ver(struct tg3 *tp) apedata = tg3_ape_read32(tp, TG3_APE_FW_VERSION); if (tg3_ape_read32(tp, TG3_APE_FW_FEATURES) & TG3_APE_FW_FEATURE_NCSI) { - tp->tg3_flags3 |= TG3_FLG3_APE_HAS_NCSI; + tg3_flag_set(tp, APE_HAS_NCSI); fwtype = "NCSI"; } else { fwtype = "DASH"; @@ -13478,7 +13471,7 @@ static void __devinit tg3_read_fw_ver(struct tg3 *tp) if (tp->fw_ver[0] != 0) vpd_vers = true; - if (tp->tg3_flags3 & TG3_FLG3_NO_NVRAM) { + if (tg3_flag(tp, NO_NVRAM)) { strcat(tp->fw_ver, "sb"); return; } @@ -13495,8 +13488,7 @@ static void __devinit tg3_read_fw_ver(struct tg3 *tp) else return; - if (!(tp->tg3_flags & TG3_FLAG_ENABLE_ASF) || - (tp->tg3_flags3 & TG3_FLG3_ENABLE_APE) || vpd_vers) + if (!tg3_flag(tp, ENABLE_ASF) || tg3_flag(tp, ENABLE_APE) || vpd_vers) goto done; tg3_read_mgmtfw_ver(tp); @@ -13509,10 +13501,9 @@ static struct pci_dev * __devinit tg3_find_peer(struct tg3 *); static inline u32 tg3_rx_ret_ring_size(struct tg3 *tp) { - if (tp->tg3_flags3 & TG3_FLG3_LRG_PROD_RING_CAP) + if (tg3_flag(tp, LRG_PROD_RING_CAP)) return TG3_RX_RET_MAX_SIZE_5717; - else if ((tp->tg3_flags & TG3_FLAG_JUMBO_CAPABLE) && - !(tp->tg3_flags2 & TG3_FLG2_5780_CLASS)) + else if (tg3_flag(tp, JUMBO_CAPABLE) && !tg3_flag(tp, 5780_CLASS)) return TG3_RX_RET_MAX_SIZE_5700; else return TG3_RX_RET_MAX_SIZE_5705; @@ -13638,8 +13629,7 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) if (bridge->subordinate && (bridge->subordinate->number == tp->pdev->bus->number)) { - - tp->tg3_flags2 |= TG3_FLG2_ICH_WORKAROUND; + tg3_flag_set(tp, ICH_WORKAROUND); pci_dev_put(bridge); break; } @@ -13671,7 +13661,7 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) tp->pdev->bus->number) && (bridge->subordinate->subordinate >= tp->pdev->bus->number)) { - tp->tg3_flags3 |= TG3_FLG3_5701_DMA_BUG; + tg3_flag_set(tp, 5701_DMA_BUG); pci_dev_put(bridge); break; } @@ -13686,8 +13676,8 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) */ if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5780 || GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5714) { - tp->tg3_flags2 |= TG3_FLG2_5780_CLASS; - tp->tg3_flags |= TG3_FLAG_40BIT_DMA_BUG; + tg3_flag_set(tp, 5780_CLASS); + tg3_flag_set(tp, 40BIT_DMA_BUG); tp->msi_cap = pci_find_capability(tp->pdev, PCI_CAP_ID_MSI); } else { struct pci_dev *bridge = NULL; @@ -13701,7 +13691,7 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) tp->pdev->bus->number) && (bridge->subordinate->subordinate >= tp->pdev->bus->number)) { - tp->tg3_flags |= TG3_FLAG_40BIT_DMA_BUG; + tg3_flag_set(tp, 40BIT_DMA_BUG); pci_dev_put(bridge); break; } @@ -13723,11 +13713,11 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5717 || GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5719 || GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5720) - tp->tg3_flags3 |= TG3_FLG3_5717_PLUS; + tg3_flag_set(tp, 5717_PLUS); if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57765 || - (tp->tg3_flags3 & TG3_FLG3_5717_PLUS)) - tp->tg3_flags3 |= TG3_FLG3_57765_PLUS; + tg3_flag(tp, 5717_PLUS)) + tg3_flag_set(tp, 57765_PLUS); /* Intentionally exclude ASIC_REV_5906 */ if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5755 || @@ -13736,19 +13726,19 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761 || GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5785 || GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57780 || - (tp->tg3_flags3 & TG3_FLG3_57765_PLUS)) - tp->tg3_flags3 |= TG3_FLG3_5755_PLUS; + tg3_flag(tp, 57765_PLUS)) + tg3_flag_set(tp, 5755_PLUS); if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5750 || GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5752 || GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906 || - (tp->tg3_flags3 & TG3_FLG3_5755_PLUS) || - (tp->tg3_flags2 & TG3_FLG2_5780_CLASS)) - tp->tg3_flags2 |= TG3_FLG2_5750_PLUS; + tg3_flag(tp, 5755_PLUS) || + tg3_flag(tp, 5780_CLASS)) + tg3_flag_set(tp, 5750_PLUS); if ((GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5705) || - (tp->tg3_flags2 & TG3_FLG2_5750_PLUS)) - tp->tg3_flags2 |= TG3_FLG2_5705_PLUS; + tg3_flag(tp, 5750_PLUS)) + tg3_flag_set(tp, 5705_PLUS); /* 5700 B0 chips do not support checksumming correctly due * to hardware bugs. @@ -13756,7 +13746,7 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) if (tp->pci_chip_rev_id != CHIPREV_ID_5700_B0) { u32 features = NETIF_F_SG | NETIF_F_IP_CSUM | NETIF_F_RXCSUM; - if (tp->tg3_flags3 & TG3_FLG3_5755_PLUS) + if (tg3_flag(tp, 5755_PLUS)) features |= NETIF_F_IPV6_CSUM; tp->dev->features |= features; tp->dev->hw_features |= features; @@ -13766,20 +13756,21 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) /* Determine TSO capabilities */ if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5719) ; /* Do nothing. HW bug. */ - else if (tp->tg3_flags3 & TG3_FLG3_57765_PLUS) - tp->tg3_flags2 |= TG3_FLG2_HW_TSO_3; - else if ((tp->tg3_flags3 & TG3_FLG3_5755_PLUS) || + else if (tg3_flag(tp, 57765_PLUS)) + tg3_flag_set(tp, HW_TSO_3); + else if (tg3_flag(tp, 5755_PLUS) || GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906) - tp->tg3_flags2 |= TG3_FLG2_HW_TSO_2; - else if (tp->tg3_flags2 & TG3_FLG2_5750_PLUS) { - tp->tg3_flags2 |= TG3_FLG2_HW_TSO_1 | TG3_FLG2_TSO_BUG; + tg3_flag_set(tp, HW_TSO_2); + else if (tg3_flag(tp, 5750_PLUS)) { + tg3_flag_set(tp, HW_TSO_1); + tg3_flag_set(tp, TSO_BUG); if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5750 && tp->pci_chip_rev_id >= CHIPREV_ID_5750_C2) - tp->tg3_flags2 &= ~TG3_FLG2_TSO_BUG; + tg3_flag_clear(tp, TSO_BUG); } else if (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5700 && GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5701 && tp->pci_chip_rev_id != CHIPREV_ID_5705_A0) { - tp->tg3_flags2 |= TG3_FLG2_TSO_BUG; + tg3_flag_set(tp, TSO_BUG); if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5705) tp->fw_needed = FIRMWARE_TG3TSO5; else @@ -13788,22 +13779,22 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) tp->irq_max = 1; - if (tp->tg3_flags2 & TG3_FLG2_5750_PLUS) { - tp->tg3_flags |= TG3_FLAG_SUPPORT_MSI; + if (tg3_flag(tp, 5750_PLUS)) { + tg3_flag_set(tp, SUPPORT_MSI); if (GET_CHIP_REV(tp->pci_chip_rev_id) == CHIPREV_5750_AX || GET_CHIP_REV(tp->pci_chip_rev_id) == CHIPREV_5750_BX || (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5714 && tp->pci_chip_rev_id <= CHIPREV_ID_5714_A2 && tp->pdev_peer == tp->pdev)) - tp->tg3_flags &= ~TG3_FLAG_SUPPORT_MSI; + tg3_flag_clear(tp, SUPPORT_MSI); - if ((tp->tg3_flags3 & TG3_FLG3_5755_PLUS) || + if (tg3_flag(tp, 5755_PLUS) || GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906) { - tp->tg3_flags2 |= TG3_FLG2_1SHOT_MSI; + tg3_flag_set(tp, 1SHOT_MSI); } - if (tp->tg3_flags3 & TG3_FLG3_57765_PLUS) { - tp->tg3_flags |= TG3_FLAG_SUPPORT_MSIX; + if (tg3_flag(tp, 57765_PLUS)) { + tg3_flag_set(tp, SUPPORT_MSIX); tp->irq_max = TG3_IRQ_MAX_VECS; } } @@ -13811,23 +13802,23 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5717 || GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5719 || GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906) - tp->tg3_flags3 |= TG3_FLG3_SHORT_DMA_BUG; - else if (!(tp->tg3_flags3 & TG3_FLG3_5755_PLUS)) { - tp->tg3_flags3 |= TG3_FLG3_4G_DMA_BNDRY_BUG; - tp->tg3_flags3 |= TG3_FLG3_40BIT_DMA_LIMIT_BUG; + tg3_flag_set(tp, SHORT_DMA_BUG); + else if (!tg3_flag(tp, 5755_PLUS)) { + tg3_flag_set(tp, 4G_DMA_BNDRY_BUG); + tg3_flag_set(tp, 40BIT_DMA_LIMIT_BUG); } - if (tp->tg3_flags3 & TG3_FLG3_5717_PLUS) - tp->tg3_flags3 |= TG3_FLG3_LRG_PROD_RING_CAP; + if (tg3_flag(tp, 5717_PLUS)) + tg3_flag_set(tp, LRG_PROD_RING_CAP); - if ((tp->tg3_flags3 & TG3_FLG3_57765_PLUS) && + if (tg3_flag(tp, 57765_PLUS) && GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5719) - tp->tg3_flags3 |= TG3_FLG3_USE_JUMBO_BDFLAG; + tg3_flag_set(tp, USE_JUMBO_BDFLAG); - if (!(tp->tg3_flags2 & TG3_FLG2_5705_PLUS) || - (tp->tg3_flags2 & TG3_FLG2_5780_CLASS) || - (tp->tg3_flags3 & TG3_FLG3_USE_JUMBO_BDFLAG)) - tp->tg3_flags |= TG3_FLAG_JUMBO_CAPABLE; + if (!tg3_flag(tp, 5705_PLUS) || + tg3_flag(tp, 5780_CLASS) || + tg3_flag(tp, USE_JUMBO_BDFLAG)) + tg3_flag_set(tp, JUMBO_CAPABLE); pci_read_config_dword(tp->pdev, TG3PCI_PCISTATE, &pci_state_reg); @@ -13836,7 +13827,7 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) if (tp->pcie_cap != 0) { u16 lnkctl; - tp->tg3_flags2 |= TG3_FLG2_PCI_EXPRESS; + tg3_flag_set(tp, PCI_EXPRESS); tp->pcie_readrq = 4096; if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5719 || @@ -13850,19 +13841,19 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) &lnkctl); if (lnkctl & PCI_EXP_LNKCTL_CLKREQ_EN) { if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906) - tp->tg3_flags2 &= ~TG3_FLG2_HW_TSO_2; + tg3_flag_clear(tp, HW_TSO_2); if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784 || GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761 || tp->pci_chip_rev_id == CHIPREV_ID_57780_A0 || tp->pci_chip_rev_id == CHIPREV_ID_57780_A1) - tp->tg3_flags3 |= TG3_FLG3_CLKREQ_BUG; + tg3_flag_set(tp, CLKREQ_BUG); } else if (tp->pci_chip_rev_id == CHIPREV_ID_5717_A0) { - tp->tg3_flags3 |= TG3_FLG3_L1PLLPD_EN; + tg3_flag_set(tp, L1PLLPD_EN); } } else if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5785) { - tp->tg3_flags2 |= TG3_FLG2_PCI_EXPRESS; - } else if (!(tp->tg3_flags2 & TG3_FLG2_5705_PLUS) || - (tp->tg3_flags2 & TG3_FLG2_5780_CLASS)) { + tg3_flag_set(tp, PCI_EXPRESS); + } else if (!tg3_flag(tp, 5705_PLUS) || + tg3_flag(tp, 5780_CLASS)) { tp->pcix_cap = pci_find_capability(tp->pdev, PCI_CAP_ID_PCIX); if (!tp->pcix_cap) { dev_err(&tp->pdev->dev, @@ -13871,7 +13862,7 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) } if (!(pci_state_reg & PCISTATE_CONV_PCI_MODE)) - tp->tg3_flags |= TG3_FLAG_PCIX_MODE; + tg3_flag_set(tp, PCIX_MODE); } /* If we have an AMD 762 or VIA K8T800 chipset, write @@ -13881,8 +13872,8 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) * posted to the chip in order. */ if (pci_dev_present(tg3_write_reorder_chipsets) && - !(tp->tg3_flags2 & TG3_FLG2_PCI_EXPRESS)) - tp->tg3_flags |= TG3_FLAG_MBOX_WRITE_REORDER; + !tg3_flag(tp, PCI_EXPRESS)) + tg3_flag_set(tp, MBOX_WRITE_REORDER); pci_read_config_byte(tp->pdev, PCI_CACHE_LINE_SIZE, &tp->pci_cacheline_sz); @@ -13899,17 +13890,17 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) /* 5700 BX chips need to have their TX producer index * mailboxes written twice to workaround a bug. */ - tp->tg3_flags |= TG3_FLAG_TXD_MBOX_HWBUG; + tg3_flag_set(tp, TXD_MBOX_HWBUG); /* If we are in PCI-X mode, enable register write workaround. * * The workaround is to use indirect register accesses * for all chip writes not to mailbox registers. */ - if (tp->tg3_flags & TG3_FLAG_PCIX_MODE) { + if (tg3_flag(tp, PCIX_MODE)) { u32 pm_reg; - tp->tg3_flags |= TG3_FLAG_PCIX_TARGET_HWBUG; + tg3_flag_set(tp, PCIX_TARGET_HWBUG); /* The chip can have it's power management PCI config * space registers clobbered due to this bug. @@ -13932,9 +13923,9 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) } if ((pci_state_reg & PCISTATE_BUS_SPEED_HIGH) != 0) - tp->tg3_flags |= TG3_FLAG_PCI_HIGH_SPEED; + tg3_flag_set(tp, PCI_HIGH_SPEED); if ((pci_state_reg & PCISTATE_BUS_32BIT) != 0) - tp->tg3_flags |= TG3_FLAG_PCI_32BIT; + tg3_flag_set(tp, PCI_32BIT); /* Chip-specific fixup from Broadcom driver */ if ((tp->pci_chip_rev_id == CHIPREV_ID_5704_A0) && @@ -13952,10 +13943,10 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) tp->write32_rx_mbox = tg3_write32; /* Various workaround register access methods */ - if (tp->tg3_flags & TG3_FLAG_PCIX_TARGET_HWBUG) + if (tg3_flag(tp, PCIX_TARGET_HWBUG)) tp->write32 = tg3_write_indirect_reg32; else if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5701 || - ((tp->tg3_flags2 & TG3_FLG2_PCI_EXPRESS) && + (tg3_flag(tp, PCI_EXPRESS) && tp->pci_chip_rev_id == CHIPREV_ID_5750_A0)) { /* * Back to back register writes can cause problems on these @@ -13967,14 +13958,13 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) tp->write32 = tg3_write_flush_reg32; } - if ((tp->tg3_flags & TG3_FLAG_TXD_MBOX_HWBUG) || - (tp->tg3_flags & TG3_FLAG_MBOX_WRITE_REORDER)) { + if (tg3_flag(tp, TXD_MBOX_HWBUG) || tg3_flag(tp, MBOX_WRITE_REORDER)) { tp->write32_tx_mbox = tg3_write32_tx_mbox; - if (tp->tg3_flags & TG3_FLAG_MBOX_WRITE_REORDER) + if (tg3_flag(tp, MBOX_WRITE_REORDER)) tp->write32_rx_mbox = tg3_write_flush_reg32; } - if (tp->tg3_flags2 & TG3_FLG2_ICH_WORKAROUND) { + if (tg3_flag(tp, ICH_WORKAROUND)) { tp->read32 = tg3_read_indirect_reg32; tp->write32 = tg3_write_indirect_reg32; tp->read32_mbox = tg3_read_indirect_mbox; @@ -13997,13 +13987,13 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) } if (tp->write32 == tg3_write_indirect_reg32 || - ((tp->tg3_flags & TG3_FLAG_PCIX_MODE) && + (tg3_flag(tp, PCIX_MODE) && (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5700 || GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5701))) - tp->tg3_flags |= TG3_FLAG_SRAM_USE_CONFIG; + tg3_flag_set(tp, SRAM_USE_CONFIG); /* Get eeprom hw config before calling tg3_set_power_state(). - * In particular, the TG3_FLG2_IS_NIC flag must be + * In particular, the TG3_FLAG_IS_NIC flag must be * determined before calling tg3_set_power_state() so that * we know whether or not to switch out of Vaux power. * When the flag is set, it means that GPIO1 is used for eeprom @@ -14012,7 +14002,7 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) */ tg3_get_eeprom_hw_cfg(tp); - if (tp->tg3_flags3 & TG3_FLG3_ENABLE_APE) { + if (tg3_flag(tp, ENABLE_APE)) { /* Allow reads and writes to the * APE register and memory space. */ @@ -14027,8 +14017,8 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761 || GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5785 || GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57780 || - (tp->tg3_flags3 & TG3_FLG3_57765_PLUS)) - tp->tg3_flags |= TG3_FLAG_CPMU_PRESENT; + tg3_flag(tp, 57765_PLUS)) + tg3_flag_set(tp, CPMU_PRESENT); /* Set up tp->grc_local_ctrl before calling tg3_power_up(). * GPIO1 driven high will bring 5700's external PHY out of reset. @@ -14036,7 +14026,7 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) */ tp->grc_local_ctrl = GRC_LCLCTRL_INT_ON_ATTN | GRC_LCLCTRL_AUTO_SEEPROM; if ((GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5700) || - (tp->tg3_flags & TG3_FLAG_EEPROM_WRITE_PROT)) + tg3_flag(tp, EEPROM_WRITE_PROT)) tp->grc_local_ctrl |= (GRC_LCLCTRL_GPIO_OE1 | GRC_LCLCTRL_GPIO_OUTPUT1); /* Unused GPIO3 must be driven as output on 5752 because there @@ -14054,7 +14044,7 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) tp->pdev->device == TG3PCI_DEVICE_TIGON3_5761S) { /* Turn off the debug UART. */ tp->grc_local_ctrl |= GRC_LCLCTRL_GPIO_UART_SEL; - if (tp->tg3_flags2 & TG3_FLG2_IS_NIC) + if (tg3_flag(tp, IS_NIC)) /* Keep VMain power. */ tp->grc_local_ctrl |= GRC_LCLCTRL_GPIO_OE0 | GRC_LCLCTRL_GPIO_OUTPUT0; @@ -14070,18 +14060,17 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) /* Derive initial jumbo mode from MTU assigned in * ether_setup() via the alloc_etherdev() call */ - if (tp->dev->mtu > ETH_DATA_LEN && - !(tp->tg3_flags2 & TG3_FLG2_5780_CLASS)) - tp->tg3_flags |= TG3_FLAG_JUMBO_RING_ENABLE; + if (tp->dev->mtu > ETH_DATA_LEN && !tg3_flag(tp, 5780_CLASS)) + tg3_flag_set(tp, JUMBO_RING_ENABLE); /* Determine WakeOnLan speed to use. */ if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5700 || tp->pci_chip_rev_id == CHIPREV_ID_5701_A0 || tp->pci_chip_rev_id == CHIPREV_ID_5701_B0 || tp->pci_chip_rev_id == CHIPREV_ID_5701_B2) { - tp->tg3_flags &= ~(TG3_FLAG_WOL_SPEED_100MB); + tg3_flag_clear(tp, WOL_SPEED_100MB); } else { - tp->tg3_flags |= TG3_FLAG_WOL_SPEED_100MB; + tg3_flag_set(tp, WOL_SPEED_100MB); } if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906) @@ -14102,11 +14091,11 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) if (tp->pci_chip_rev_id == CHIPREV_ID_5704_A0) tp->phy_flags |= TG3_PHYFLG_5704_A0_BUG; - if ((tp->tg3_flags2 & TG3_FLG2_5705_PLUS) && + if (tg3_flag(tp, 5705_PLUS) && !(tp->phy_flags & TG3_PHYFLG_IS_FET) && GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5785 && GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_57780 && - !(tp->tg3_flags3 & TG3_FLG3_57765_PLUS)) { + !tg3_flag(tp, 57765_PLUS)) { if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5755 || GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5787 || GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784 || @@ -14127,7 +14116,7 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) tp->phy_otp = TG3_OTP_DEFAULT; } - if (tp->tg3_flags & TG3_FLAG_CPMU_PRESENT) + if (tg3_flag(tp, CPMU_PRESENT)) tp->mi_mode = MAC_MI_MODE_500KHZ_CONST; else tp->mi_mode = MAC_MI_MODE_BASE; @@ -14147,7 +14136,7 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5785 || GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57780) - tp->tg3_flags3 |= TG3_FLG3_USE_PHYLIB; + tg3_flag_set(tp, USE_PHYLIB); err = tg3_mdio_init(tp); if (err) @@ -14174,7 +14163,7 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) pci_read_config_dword(tp->pdev, TG3PCI_PCISTATE, &pci_state_reg); if ((pci_state_reg & PCISTATE_CONV_PCI_MODE) == 0 && - (tp->tg3_flags & TG3_FLAG_PCIX_TARGET_HWBUG) == 0) { + !tg3_flag(tp, PCIX_TARGET_HWBUG)) { u32 chiprevid = GET_CHIP_REV_ID(tp->misc_host_ctrl); if (chiprevid == CHIPREV_ID_5701_A0 || @@ -14193,7 +14182,7 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) writel(0x00000000, sram_base + 4); writel(0xffffffff, sram_base + 4); if (readl(sram_base) != 0x00000000) - tp->tg3_flags |= TG3_FLAG_PCIX_TARGET_HWBUG; + tg3_flag_set(tp, PCIX_TARGET_HWBUG); } } @@ -14206,12 +14195,12 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5705 && (grc_misc_cfg == GRC_MISC_CFG_BOARD_ID_5788 || grc_misc_cfg == GRC_MISC_CFG_BOARD_ID_5788M)) - tp->tg3_flags2 |= TG3_FLG2_IS_5788; + tg3_flag_set(tp, IS_5788); - if (!(tp->tg3_flags2 & TG3_FLG2_IS_5788) && + if (!tg3_flag(tp, IS_5788) && (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5700)) - tp->tg3_flags |= TG3_FLAG_TAGGED_STATUS; - if (tp->tg3_flags & TG3_FLAG_TAGGED_STATUS) { + tg3_flag_set(tp, TAGGED_STATUS); + if (tg3_flag(tp, TAGGED_STATUS)) { tp->coalesce_mode |= (HOSTCC_MODE_CLRTICK_RXBD | HOSTCC_MODE_CLRTICK_TXBD); @@ -14221,7 +14210,7 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) } /* Preserve the APE MAC_MODE bits */ - if (tp->tg3_flags3 & TG3_FLG3_ENABLE_APE) + if (tg3_flag(tp, ENABLE_APE)) tp->mac_mode = MAC_MODE_APE_TX_EN | MAC_MODE_APE_RX_EN; else tp->mac_mode = TG3_DEF_MAC_MODE; @@ -14268,9 +14257,9 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) * status register in those cases. */ if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5700) - tp->tg3_flags |= TG3_FLAG_USE_LINKCHG_REG; + tg3_flag_set(tp, USE_LINKCHG_REG); else - tp->tg3_flags &= ~TG3_FLAG_USE_LINKCHG_REG; + tg3_flag_clear(tp, USE_LINKCHG_REG); /* The led_ctrl is set during tg3_phy_probe, here we might * have to force the link status polling mechanism based @@ -14280,19 +14269,19 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5701 && !(tp->phy_flags & TG3_PHYFLG_PHY_SERDES)) { tp->phy_flags |= TG3_PHYFLG_USE_MI_INTERRUPT; - tp->tg3_flags |= TG3_FLAG_USE_LINKCHG_REG; + tg3_flag_set(tp, USE_LINKCHG_REG); } /* For all SERDES we poll the MAC status register. */ if (tp->phy_flags & TG3_PHYFLG_PHY_SERDES) - tp->tg3_flags |= TG3_FLAG_POLL_SERDES; + tg3_flag_set(tp, POLL_SERDES); else - tp->tg3_flags &= ~TG3_FLAG_POLL_SERDES; + tg3_flag_clear(tp, POLL_SERDES); tp->rx_offset = NET_IP_ALIGN; tp->rx_copy_thresh = TG3_RX_COPY_THRESHOLD; if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5701 && - (tp->tg3_flags & TG3_FLAG_PCIX_MODE) != 0) { + tg3_flag(tp, PCIX_MODE)) { tp->rx_offset = 0; #ifndef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS tp->rx_copy_thresh = ~(u16)0; @@ -14313,7 +14302,7 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5755) tp->rx_std_max_post = 8; - if (tp->tg3_flags & TG3_FLAG_ASPM_WORKAROUND) + if (tg3_flag(tp, ASPM_WORKAROUND)) tp->pwrmgmt_thresh = tr32(PCIE_PWR_MGMT_THRESH) & PCIE_PWR_MGMT_L1_THRESH_MSK; @@ -14361,14 +14350,14 @@ static int __devinit tg3_get_device_address(struct tg3 *tp) mac_offset = 0x7c; if ((GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5704) || - (tp->tg3_flags2 & TG3_FLG2_5780_CLASS)) { + tg3_flag(tp, 5780_CLASS)) { if (tr32(TG3PCI_DUAL_MAC_CTRL) & DUAL_MAC_CTRL_ID) mac_offset = 0xcc; if (tg3_nvram_lock(tp)) tw32_f(NVRAM_CMD, NVRAM_CMD_RESET); else tg3_nvram_unlock(tp); - } else if (tp->tg3_flags3 & TG3_FLG3_5717_PLUS) { + } else if (tg3_flag(tp, 5717_PLUS)) { if (PCI_FUNC(tp->pdev->devfn) & 1) mac_offset = 0xcc; if (PCI_FUNC(tp->pdev->devfn) > 1) @@ -14393,7 +14382,7 @@ static int __devinit tg3_get_device_address(struct tg3 *tp) } if (!addr_ok) { /* Next, try NVRAM. */ - if (!(tp->tg3_flags3 & TG3_FLG3_NO_NVRAM) && + if (!tg3_flag(tp, NO_NVRAM) && !tg3_nvram_read_be32(tp, mac_offset + 0, &hi) && !tg3_nvram_read_be32(tp, mac_offset + 4, &lo)) { memcpy(&dev->dev_addr[0], ((char *)&hi) + 2, 2); @@ -14444,7 +14433,7 @@ static u32 __devinit tg3_calc_dma_bndry(struct tg3 *tp, u32 val) */ if (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5700 && GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5701 && - !(tp->tg3_flags2 & TG3_FLG2_PCI_EXPRESS)) + !tg3_flag(tp, PCI_EXPRESS)) goto out; #if defined(CONFIG_PPC64) || defined(CONFIG_IA64) || defined(CONFIG_PARISC) @@ -14457,7 +14446,7 @@ static u32 __devinit tg3_calc_dma_bndry(struct tg3 *tp, u32 val) #endif #endif - if (tp->tg3_flags3 & TG3_FLG3_57765_PLUS) { + if (tg3_flag(tp, 57765_PLUS)) { val = goal ? 0 : DMA_RWCTRL_DIS_CACHE_ALIGNMENT; goto out; } @@ -14476,8 +14465,7 @@ static u32 __devinit tg3_calc_dma_bndry(struct tg3 *tp, u32 val) * other than 5700 and 5701 which do not implement the * boundary bits. */ - if ((tp->tg3_flags & TG3_FLAG_PCIX_MODE) && - !(tp->tg3_flags2 & TG3_FLG2_PCI_EXPRESS)) { + if (tg3_flag(tp, PCIX_MODE) && !tg3_flag(tp, PCI_EXPRESS)) { switch (cacheline_size) { case 16: case 32: @@ -14502,7 +14490,7 @@ static u32 __devinit tg3_calc_dma_bndry(struct tg3 *tp, u32 val) DMA_RWCTRL_WRITE_BNDRY_384_PCIX); break; } - } else if (tp->tg3_flags2 & TG3_FLG2_PCI_EXPRESS) { + } else if (tg3_flag(tp, PCI_EXPRESS)) { switch (cacheline_size) { case 16: case 32: @@ -14674,13 +14662,13 @@ static int __devinit tg3_test_dma(struct tg3 *tp) tp->dma_rwctrl = tg3_calc_dma_bndry(tp, tp->dma_rwctrl); - if (tp->tg3_flags3 & TG3_FLG3_57765_PLUS) + if (tg3_flag(tp, 57765_PLUS)) goto out; - if (tp->tg3_flags2 & TG3_FLG2_PCI_EXPRESS) { + if (tg3_flag(tp, PCI_EXPRESS)) { /* DMA read watermark not used on PCIE */ tp->dma_rwctrl |= 0x00180000; - } else if (!(tp->tg3_flags & TG3_FLAG_PCIX_MODE)) { + } else if (!tg3_flag(tp, PCIX_MODE)) { if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5705 || GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5750) tp->dma_rwctrl |= 0x003f0000; @@ -14696,7 +14684,7 @@ static int __devinit tg3_test_dma(struct tg3 *tp) * do the less restrictive ONE_DMA workaround for * better performance. */ - if ((tp->tg3_flags & TG3_FLAG_40BIT_DMA_BUG) && + if (tg3_flag(tp, 40BIT_DMA_BUG) && GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5704) tp->dma_rwctrl |= 0x8000; else if (ccval == 0x6 || ccval == 0x7) @@ -14848,7 +14836,7 @@ out_nofree: static void __devinit tg3_init_bufmgr_config(struct tg3 *tp) { - if (tp->tg3_flags3 & TG3_FLG3_57765_PLUS) { + if (tg3_flag(tp, 57765_PLUS)) { tp->bufmgr_config.mbuf_read_dma_low_water = DEFAULT_MB_RDMA_LOW_WATER_5705; tp->bufmgr_config.mbuf_mac_rx_low_water = @@ -14862,7 +14850,7 @@ static void __devinit tg3_init_bufmgr_config(struct tg3 *tp) DEFAULT_MB_MACRX_LOW_WATER_JUMBO_57765; tp->bufmgr_config.mbuf_high_water_jumbo = DEFAULT_MB_HIGH_WATER_JUMBO_57765; - } else if (tp->tg3_flags2 & TG3_FLG2_5705_PLUS) { + } else if (tg3_flag(tp, 5705_PLUS)) { tp->bufmgr_config.mbuf_read_dma_low_water = DEFAULT_MB_RDMA_LOW_WATER_5705; tp->bufmgr_config.mbuf_mac_rx_low_water = @@ -14935,10 +14923,10 @@ static char * __devinit tg3_phy_string(struct tg3 *tp) static char * __devinit tg3_bus_string(struct tg3 *tp, char *str) { - if (tp->tg3_flags2 & TG3_FLG2_PCI_EXPRESS) { + if (tg3_flag(tp, PCI_EXPRESS)) { strcpy(str, "PCI Express"); return str; - } else if (tp->tg3_flags & TG3_FLAG_PCIX_MODE) { + } else if (tg3_flag(tp, PCIX_MODE)) { u32 clock_ctrl = tr32(TG3PCI_CLOCK_CTRL) & 0x1f; strcpy(str, "PCIX:"); @@ -14957,12 +14945,12 @@ static char * __devinit tg3_bus_string(struct tg3 *tp, char *str) strcat(str, "100MHz"); } else { strcpy(str, "PCI:"); - if (tp->tg3_flags & TG3_FLAG_PCI_HIGH_SPEED) + if (tg3_flag(tp, PCI_HIGH_SPEED)) strcat(str, "66MHz"); else strcat(str, "33MHz"); } - if (tp->tg3_flags & TG3_FLAG_PCI_32BIT) + if (tg3_flag(tp, PCI_32BIT)) strcat(str, ":32-bit"); else strcat(str, ":64-bit"); @@ -15021,7 +15009,7 @@ static void __devinit tg3_init_coal(struct tg3 *tp) ec->tx_coalesce_usecs_irq = DEFAULT_TXCOAL_TICK_INT_CLRTCKS; } - if (tp->tg3_flags2 & TG3_FLG2_5705_PLUS) { + if (tg3_flag(tp, 5705_PLUS)) { ec->rx_coalesce_usecs_irq = 0; ec->tx_coalesce_usecs_irq = 0; ec->stats_block_coalesce_usecs = 0; @@ -15166,8 +15154,7 @@ static int __devinit tg3_init_one(struct pci_dev *pdev, goto err_out_iounmap; } - if ((tp->tg3_flags3 & TG3_FLG3_5755_PLUS) && - !(tp->tg3_flags3 & TG3_FLG3_5717_PLUS)) + if (tg3_flag(tp, 5755_PLUS) && !tg3_flag(tp, 5717_PLUS)) dev->netdev_ops = &tg3_netdev_ops; else dev->netdev_ops = &tg3_netdev_ops_dma_bug; @@ -15179,9 +15166,9 @@ static int __devinit tg3_init_one(struct pci_dev *pdev, * On 64-bit systems without IOMMU, use 64-bit dma_mask and * do DMA address check in tg3_start_xmit(). */ - if (tp->tg3_flags2 & TG3_FLG2_IS_5788) + if (tg3_flag(tp, IS_5788)) persist_dma_mask = dma_mask = DMA_BIT_MASK(32); - else if (tp->tg3_flags & TG3_FLAG_40BIT_DMA_BUG) { + else if (tg3_flag(tp, 40BIT_DMA_BUG)) { persist_dma_mask = dma_mask = DMA_BIT_MASK(40); #ifdef CONFIG_HIGHMEM dma_mask = DMA_BIT_MASK(64); @@ -15215,11 +15202,14 @@ static int __devinit tg3_init_one(struct pci_dev *pdev, tg3_init_bufmgr_config(tp); /* Selectively allow TSO based on operating conditions */ - if ((tp->tg3_flags2 & TG3_FLG2_HW_TSO) || - (tp->fw_needed && !(tp->tg3_flags & TG3_FLAG_ENABLE_ASF))) - tp->tg3_flags2 |= TG3_FLG2_TSO_CAPABLE; + if ((tg3_flag(tp, HW_TSO_1) || + tg3_flag(tp, HW_TSO_2) || + tg3_flag(tp, HW_TSO_3)) || + (tp->fw_needed && !tg3_flag(tp, ENABLE_ASF))) + tg3_flag_set(tp, TSO_CAPABLE); else { - tp->tg3_flags2 &= ~(TG3_FLG2_TSO_CAPABLE | TG3_FLG2_TSO_BUG); + tg3_flag_clear(tp, TSO_CAPABLE); + tg3_flag_clear(tp, TSO_BUG); tp->fw_needed = NULL; } @@ -15230,18 +15220,19 @@ static int __devinit tg3_init_one(struct pci_dev *pdev, * Firmware TSO on older chips gives lower performance, so it * is off by default, but can be enabled using ethtool. */ - if ((tp->tg3_flags2 & TG3_FLG2_HW_TSO) && + if ((tg3_flag(tp, HW_TSO_1) || + tg3_flag(tp, HW_TSO_2) || + tg3_flag(tp, HW_TSO_3)) && (dev->features & NETIF_F_IP_CSUM)) hw_features |= NETIF_F_TSO; - if ((tp->tg3_flags2 & TG3_FLG2_HW_TSO_2) || - (tp->tg3_flags2 & TG3_FLG2_HW_TSO_3)) { + if (tg3_flag(tp, HW_TSO_2) || tg3_flag(tp, HW_TSO_3)) { if (dev->features & NETIF_F_IPV6_CSUM) hw_features |= NETIF_F_TSO6; - if ((tp->tg3_flags2 & TG3_FLG2_HW_TSO_3) || + if (tg3_flag(tp, HW_TSO_3) || GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761 || (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784 && GET_CHIP_REV(tp->pci_chip_rev_id) != CHIPREV_5784_AX) || - GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5785 || + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5785 || GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57780) hw_features |= NETIF_F_TSO_ECN; } @@ -15251,9 +15242,9 @@ static int __devinit tg3_init_one(struct pci_dev *pdev, dev->vlan_features |= hw_features; if (tp->pci_chip_rev_id == CHIPREV_ID_5705_A1 && - !(tp->tg3_flags2 & TG3_FLG2_TSO_CAPABLE) && + !tg3_flag(tp, TSO_CAPABLE) && !(tr32(TG3PCI_PCISTATE) & PCISTATE_BUS_SPEED_HIGH)) { - tp->tg3_flags2 |= TG3_FLG2_MAX_RXPEND_64; + tg3_flag_set(tp, MAX_RXPEND_64); tp->rx_pending = 63; } @@ -15264,7 +15255,7 @@ static int __devinit tg3_init_one(struct pci_dev *pdev, goto err_out_iounmap; } - if (tp->tg3_flags3 & TG3_FLG3_ENABLE_APE) { + if (tg3_flag(tp, ENABLE_APE)) { tp->aperegs = pci_ioremap_bar(pdev, BAR_2); if (!tp->aperegs) { dev_err(&pdev->dev, @@ -15275,7 +15266,7 @@ static int __devinit tg3_init_one(struct pci_dev *pdev, tg3_ape_lock_init(tp); - if (tp->tg3_flags & TG3_FLAG_ENABLE_ASF) + if (tg3_flag(tp, ENABLE_ASF)) tg3_read_dash_ver(tp); } @@ -15319,7 +15310,7 @@ static int __devinit tg3_init_one(struct pci_dev *pdev, else tnapi->coal_now = HOSTCC_MODE_NOW; - if (!(tp->tg3_flags & TG3_FLAG_SUPPORT_MSIX)) + if (!tg3_flag(tp, SUPPORT_MSIX)) break; /* @@ -15381,10 +15372,10 @@ static int __devinit tg3_init_one(struct pci_dev *pdev, netdev_info(dev, "RXcsums[%d] LinkChgREG[%d] MIirq[%d] ASF[%d] TSOcap[%d]\n", (dev->features & NETIF_F_RXCSUM) != 0, - (tp->tg3_flags & TG3_FLAG_USE_LINKCHG_REG) != 0, + tg3_flag(tp, USE_LINKCHG_REG) != 0, (tp->phy_flags & TG3_PHYFLG_USE_MI_INTERRUPT) != 0, - (tp->tg3_flags & TG3_FLAG_ENABLE_ASF) != 0, - (tp->tg3_flags2 & TG3_FLG2_TSO_CAPABLE) != 0); + tg3_flag(tp, ENABLE_ASF) != 0, + tg3_flag(tp, TSO_CAPABLE) != 0); netdev_info(dev, "dma_rwctrl[%08x] dma_mask[%d-bit]\n", tp->dma_rwctrl, pdev->dma_mask == DMA_BIT_MASK(32) ? 32 : @@ -15430,7 +15421,7 @@ static void __devexit tg3_remove_one(struct pci_dev *pdev) cancel_work_sync(&tp->reset_task); - if (tp->tg3_flags3 & TG3_FLG3_USE_PHYLIB) { + if (!tg3_flag(tp, USE_PHYLIB)) { tg3_phy_fini(tp); tg3_mdio_fini(tp); } @@ -15476,7 +15467,7 @@ static int tg3_suspend(struct device *device) tg3_full_lock(tp, 0); tg3_halt(tp, RESET_KIND_SHUTDOWN, 1); - tp->tg3_flags &= ~TG3_FLAG_INIT_COMPLETE; + tg3_flag_clear(tp, INIT_COMPLETE); tg3_full_unlock(tp); err = tg3_power_down_prepare(tp); @@ -15485,7 +15476,7 @@ static int tg3_suspend(struct device *device) tg3_full_lock(tp, 0); - tp->tg3_flags |= TG3_FLAG_INIT_COMPLETE; + tg3_flag_set(tp, INIT_COMPLETE); err2 = tg3_restart_hw(tp, 1); if (err2) goto out; @@ -15520,7 +15511,7 @@ static int tg3_resume(struct device *device) tg3_full_lock(tp, 0); - tp->tg3_flags |= TG3_FLAG_INIT_COMPLETE; + tg3_flag_set(tp, INIT_COMPLETE); err = tg3_restart_hw(tp, 1); if (err) goto out; @@ -15575,12 +15566,12 @@ static pci_ers_result_t tg3_io_error_detected(struct pci_dev *pdev, tg3_netif_stop(tp); del_timer_sync(&tp->timer); - tp->tg3_flags2 &= ~TG3_FLG2_RESTART_TIMER; + tg3_flag_clear(tp, RESTART_TIMER); /* Want to make sure that the reset task doesn't run */ cancel_work_sync(&tp->reset_task); - tp->tg3_flags &= ~TG3_FLAG_TX_RECOVERY_PENDING; - tp->tg3_flags2 &= ~TG3_FLG2_RESTART_TIMER; + tg3_flag_clear(tp, TX_RECOVERY_PENDING); + tg3_flag_clear(tp, RESTART_TIMER); netif_device_detach(netdev); @@ -15665,7 +15656,7 @@ static void tg3_io_resume(struct pci_dev *pdev) goto done; tg3_full_lock(tp, 0); - tp->tg3_flags |= TG3_FLAG_INIT_COMPLETE; + tg3_flag_set(tp, INIT_COMPLETE); err = tg3_restart_hw(tp, 1); tg3_full_unlock(tp); if (err) { diff --git a/drivers/net/tg3.h b/drivers/net/tg3.h index 6f37d2a..ce010cd3 100644 --- a/drivers/net/tg3.h +++ b/drivers/net/tg3.h @@ -2816,6 +2816,86 @@ struct tg3_napi { unsigned int irq_vec; }; +enum TG3_FLAGS { + TG3_FLAG_TAGGED_STATUS = 0, + TG3_FLAG_TXD_MBOX_HWBUG, + TG3_FLAG_USE_LINKCHG_REG, + TG3_FLAG_ERROR_PROCESSED, + TG3_FLAG_ENABLE_ASF, + TG3_FLAG_ASPM_WORKAROUND, + TG3_FLAG_POLL_SERDES, + TG3_FLAG_MBOX_WRITE_REORDER, + TG3_FLAG_PCIX_TARGET_HWBUG, + TG3_FLAG_WOL_SPEED_100MB, + TG3_FLAG_WOL_ENABLE, + TG3_FLAG_EEPROM_WRITE_PROT, + TG3_FLAG_NVRAM, + TG3_FLAG_NVRAM_BUFFERED, + TG3_FLAG_SUPPORT_MSI, + TG3_FLAG_SUPPORT_MSIX, + TG3_FLAG_PCIX_MODE, + TG3_FLAG_PCI_HIGH_SPEED, + TG3_FLAG_PCI_32BIT, + TG3_FLAG_SRAM_USE_CONFIG, + TG3_FLAG_TX_RECOVERY_PENDING, + TG3_FLAG_WOL_CAP, + TG3_FLAG_JUMBO_RING_ENABLE, + TG3_FLAG_PAUSE_AUTONEG, + TG3_FLAG_CPMU_PRESENT, + TG3_FLAG_40BIT_DMA_BUG, + TG3_FLAG_BROKEN_CHECKSUMS, + TG3_FLAG_JUMBO_CAPABLE, + TG3_FLAG_CHIP_RESETTING, + TG3_FLAG_INIT_COMPLETE, + TG3_FLAG_RESTART_TIMER, + TG3_FLAG_TSO_BUG, + TG3_FLAG_IS_5788, + TG3_FLAG_MAX_RXPEND_64, + TG3_FLAG_TSO_CAPABLE, + TG3_FLAG_PCI_EXPRESS, + TG3_FLAG_ASF_NEW_HANDSHAKE, + TG3_FLAG_HW_AUTONEG, + TG3_FLAG_IS_NIC, + TG3_FLAG_FLASH, + TG3_FLAG_HW_TSO_1, + TG3_FLAG_5705_PLUS, + TG3_FLAG_5750_PLUS, + TG3_FLAG_HW_TSO_3, + TG3_FLAG_USING_MSI, + TG3_FLAG_USING_MSIX, + TG3_FLAG_ICH_WORKAROUND, + TG3_FLAG_5780_CLASS, + TG3_FLAG_HW_TSO_2, + TG3_FLAG_1SHOT_MSI, + TG3_FLAG_NO_FWARE_REPORTED, + TG3_FLAG_NO_NVRAM_ADDR_TRANS, + TG3_FLAG_ENABLE_APE, + TG3_FLAG_PROTECTED_NVRAM, + TG3_FLAG_5701_DMA_BUG, + TG3_FLAG_USE_PHYLIB, + TG3_FLAG_MDIOBUS_INITED, + TG3_FLAG_LRG_PROD_RING_CAP, + TG3_FLAG_RGMII_INBAND_DISABLE, + TG3_FLAG_RGMII_EXT_IBND_RX_EN, + TG3_FLAG_RGMII_EXT_IBND_TX_EN, + TG3_FLAG_CLKREQ_BUG, + TG3_FLAG_5755_PLUS, + TG3_FLAG_NO_NVRAM, + TG3_FLAG_ENABLE_RSS, + TG3_FLAG_ENABLE_TSS, + TG3_FLAG_4G_DMA_BNDRY_BUG, + TG3_FLAG_40BIT_DMA_LIMIT_BUG, + TG3_FLAG_SHORT_DMA_BUG, + TG3_FLAG_USE_JUMBO_BDFLAG, + TG3_FLAG_L1PLLPD_EN, + TG3_FLAG_57765_PLUS, + TG3_FLAG_APE_HAS_NCSI, + TG3_FLAG_5717_PLUS, + + /* Add new flags before this comment and TG3_FLAG_NUMBER_OF_FLAGS */ + TG3_FLAG_NUMBER_OF_FLAGS, /* Last entry in enum TG3_FLAGS */ +}; + struct tg3 { /* begin "general, frequently-used members" cacheline section */ @@ -2839,7 +2919,7 @@ struct tg3 { /* SMP locking strategy: * * lock: Held during reset, PHY access, timer, and when - * updating tg3_flags and tg3_flags2. + * updating tg3_flags. * * netif_tx_lock: Held during tg3_start_xmit. tg3_tx holds * netif_tx_lock when it needs to call @@ -2896,95 +2976,13 @@ struct tg3 { struct tg3_ethtool_stats estats; struct tg3_ethtool_stats estats_prev; + DECLARE_BITMAP(tg3_flags, TG3_FLAG_NUMBER_OF_FLAGS); + union { unsigned long phy_crc_errors; unsigned long last_event_jiffies; }; - u32 tg3_flags; -#define TG3_FLAG_TAGGED_STATUS 0x00000001 -#define TG3_FLAG_TXD_MBOX_HWBUG 0x00000002 -#define TG3_FLAG_USE_LINKCHG_REG 0x00000008 -#define TG3_FLAG_ERROR_PROCESSED 0x00000010 -#define TG3_FLAG_ENABLE_ASF 0x00000020 -#define TG3_FLAG_ASPM_WORKAROUND 0x00000040 -#define TG3_FLAG_POLL_SERDES 0x00000080 -#define TG3_FLAG_MBOX_WRITE_REORDER 0x00000100 -#define TG3_FLAG_PCIX_TARGET_HWBUG 0x00000200 -#define TG3_FLAG_WOL_SPEED_100MB 0x00000400 -#define TG3_FLAG_WOL_ENABLE 0x00000800 -#define TG3_FLAG_EEPROM_WRITE_PROT 0x00001000 -#define TG3_FLAG_NVRAM 0x00002000 -#define TG3_FLAG_NVRAM_BUFFERED 0x00004000 -#define TG3_FLAG_SUPPORT_MSI 0x00008000 -#define TG3_FLAG_SUPPORT_MSIX 0x00010000 -#define TG3_FLAG_SUPPORT_MSI_OR_MSIX (TG3_FLAG_SUPPORT_MSI | \ - TG3_FLAG_SUPPORT_MSIX) -#define TG3_FLAG_PCIX_MODE 0x00020000 -#define TG3_FLAG_PCI_HIGH_SPEED 0x00040000 -#define TG3_FLAG_PCI_32BIT 0x00080000 -#define TG3_FLAG_SRAM_USE_CONFIG 0x00100000 -#define TG3_FLAG_TX_RECOVERY_PENDING 0x00200000 -#define TG3_FLAG_WOL_CAP 0x00400000 -#define TG3_FLAG_JUMBO_RING_ENABLE 0x00800000 -#define TG3_FLAG_PAUSE_AUTONEG 0x02000000 -#define TG3_FLAG_CPMU_PRESENT 0x04000000 -#define TG3_FLAG_40BIT_DMA_BUG 0x08000000 -#define TG3_FLAG_JUMBO_CAPABLE 0x20000000 -#define TG3_FLAG_CHIP_RESETTING 0x40000000 -#define TG3_FLAG_INIT_COMPLETE 0x80000000 - u32 tg3_flags2; -#define TG3_FLG2_RESTART_TIMER 0x00000001 -#define TG3_FLG2_TSO_BUG 0x00000002 -#define TG3_FLG2_IS_5788 0x00000008 -#define TG3_FLG2_MAX_RXPEND_64 0x00000010 -#define TG3_FLG2_TSO_CAPABLE 0x00000020 -#define TG3_FLG2_PCI_EXPRESS 0x00000200 -#define TG3_FLG2_ASF_NEW_HANDSHAKE 0x00000400 -#define TG3_FLG2_HW_AUTONEG 0x00000800 -#define TG3_FLG2_IS_NIC 0x00001000 -#define TG3_FLG2_FLASH 0x00008000 -#define TG3_FLG2_HW_TSO_1 0x00010000 -#define TG3_FLG2_5705_PLUS 0x00040000 -#define TG3_FLG2_5750_PLUS 0x00080000 -#define TG3_FLG2_HW_TSO_3 0x00100000 -#define TG3_FLG2_USING_MSI 0x00200000 -#define TG3_FLG2_USING_MSIX 0x00400000 -#define TG3_FLG2_USING_MSI_OR_MSIX (TG3_FLG2_USING_MSI | \ - TG3_FLG2_USING_MSIX) -#define TG3_FLG2_ICH_WORKAROUND 0x02000000 -#define TG3_FLG2_5780_CLASS 0x04000000 -#define TG3_FLG2_HW_TSO_2 0x08000000 -#define TG3_FLG2_HW_TSO (TG3_FLG2_HW_TSO_1 | \ - TG3_FLG2_HW_TSO_2 | \ - TG3_FLG2_HW_TSO_3) -#define TG3_FLG2_1SHOT_MSI 0x10000000 -#define TG3_FLG2_NO_FWARE_REPORTED 0x40000000 - u32 tg3_flags3; -#define TG3_FLG3_NO_NVRAM_ADDR_TRANS 0x00000001 -#define TG3_FLG3_ENABLE_APE 0x00000002 -#define TG3_FLG3_PROTECTED_NVRAM 0x00000004 -#define TG3_FLG3_5701_DMA_BUG 0x00000008 -#define TG3_FLG3_USE_PHYLIB 0x00000010 -#define TG3_FLG3_MDIOBUS_INITED 0x00000020 -#define TG3_FLG3_LRG_PROD_RING_CAP 0x00000080 -#define TG3_FLG3_RGMII_INBAND_DISABLE 0x00000100 -#define TG3_FLG3_RGMII_EXT_IBND_RX_EN 0x00000200 -#define TG3_FLG3_RGMII_EXT_IBND_TX_EN 0x00000400 -#define TG3_FLG3_CLKREQ_BUG 0x00000800 -#define TG3_FLG3_5755_PLUS 0x00002000 -#define TG3_FLG3_NO_NVRAM 0x00004000 -#define TG3_FLG3_ENABLE_RSS 0x00020000 -#define TG3_FLG3_ENABLE_TSS 0x00040000 -#define TG3_FLG3_4G_DMA_BNDRY_BUG 0x00080000 -#define TG3_FLG3_40BIT_DMA_LIMIT_BUG 0x00100000 -#define TG3_FLG3_SHORT_DMA_BUG 0x00200000 -#define TG3_FLG3_USE_JUMBO_BDFLAG 0x00400000 -#define TG3_FLG3_L1PLLPD_EN 0x00800000 -#define TG3_FLG3_57765_PLUS 0x01000000 -#define TG3_FLG3_APE_HAS_NCSI 0x02000000 -#define TG3_FLG3_5717_PLUS 0x04000000 - struct timer_list timer; u16 timer_counter; u16 timer_multiplier; -- cgit v0.10.2 From 89b4208e2861bc7dc325840b44bae302a4e30add Mon Sep 17 00:00:00 2001 From: Sucheta Chakraborty Date: Wed, 27 Apr 2011 14:43:44 +0000 Subject: qlcnic: fix memory leak in qlcnic_blink_led. o Memory allocated in ETHTOOL_ACTIVE mode, is not getting freed. So, in ETHTOOL_ID_INACTIVE mode, return after freeing allocated memory. o Using set bit instead of blink_down field, as it is also required in internal Loopback test and etc. Signed-off-by: Sucheta Chakraborty Signed-off-by: Amit Kumar Salecha Signed-off-by: David S. Miller diff --git a/drivers/net/qlcnic/qlcnic.h b/drivers/net/qlcnic/qlcnic.h index fa5b15c..f7acb80 100644 --- a/drivers/net/qlcnic/qlcnic.h +++ b/drivers/net/qlcnic/qlcnic.h @@ -884,6 +884,7 @@ struct qlcnic_ipaddr { #define __QLCNIC_RESETTING 2 #define __QLCNIC_START_FW 4 #define __QLCNIC_AER 5 +#define __QLCNIC_DIAG_RES_ALLOC 6 #define QLCNIC_INTERRUPT_TEST 1 #define QLCNIC_LOOPBACK_TEST 2 @@ -913,7 +914,6 @@ struct qlcnic_adapter { struct net_device *netdev; struct pci_dev *pdev; - bool blink_was_down; unsigned long state; u32 flags; diff --git a/drivers/net/qlcnic/qlcnic_ethtool.c b/drivers/net/qlcnic/qlcnic_ethtool.c index 615a5ab..de65847 100644 --- a/drivers/net/qlcnic/qlcnic_ethtool.c +++ b/drivers/net/qlcnic/qlcnic_ethtool.c @@ -772,7 +772,6 @@ static int qlcnic_set_led(struct net_device *dev, switch (state) { case ETHTOOL_ID_ACTIVE: - adapter->blink_was_down = false; if (!test_bit(__QLCNIC_DEV_UP, &adapter->state)) { if (test_and_set_bit(__QLCNIC_RESETTING, &adapter->state)) return -EIO; @@ -781,7 +780,7 @@ static int qlcnic_set_led(struct net_device *dev, clear_bit(__QLCNIC_RESETTING, &adapter->state); return -EIO; } - adapter->blink_was_down = true; + set_bit(__QLCNIC_DIAG_RES_ALLOC, &adapter->state); } if (adapter->nic_ops->config_led(adapter, 1, 0xf) == 0) @@ -792,18 +791,17 @@ static int qlcnic_set_led(struct net_device *dev, break; case ETHTOOL_ID_INACTIVE: - if (adapter->nic_ops->config_led(adapter, 0, 0xf) == 0) - return 0; + if (adapter->nic_ops->config_led(adapter, 0, 0xf)) + dev_err(&adapter->pdev->dev, + "Failed to reset LED blink state.\n"); - dev_err(&adapter->pdev->dev, - "Failed to reset LED blink state.\n"); break; default: return -EINVAL; } - if (adapter->blink_was_down) { + if (test_and_clear_bit(__QLCNIC_DIAG_RES_ALLOC, &adapter->state)) { qlcnic_diag_free_res(dev, max_sds_rings); clear_bit(__QLCNIC_RESETTING, &adapter->state); } -- cgit v0.10.2 From b801a4e7092bb869fb5a7d8ee11a9435c5c7b2b1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Miros=C5=82aw?= Date: Thu, 28 Apr 2011 11:59:15 +1000 Subject: net: ibmveth: force reconfiguring checksum settings on startup MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Commit b9367bf3ee6d ("net: ibmveth: convert to hw_features") accidentally removed call to ibmveth_set_csum_offload() in ibmveth_probe(). Put the call back where it was, but with additional error checking provided by ibmveth_set_features(). Signed-off-by: MichaÅ‚ MirosÅ‚aw Reported-by: Stephen Rothwell [sfr: dev -> netdev] Signed-off-by: Stephen Rothwell Signed-off-by: David S. Miller diff --git a/drivers/net/ibmveth.c b/drivers/net/ibmveth.c index 4855f1f..be3fe71 100644 --- a/drivers/net/ibmveth.c +++ b/drivers/net/ibmveth.c @@ -1397,6 +1397,8 @@ static int __devinit ibmveth_probe(struct vio_dev *dev, netdev_dbg(netdev, "registering netdev...\n"); + ibmveth_set_features(netdev, netdev->features); + rc = register_netdev(netdev); if (rc) { -- cgit v0.10.2 From 778865a550e7958c1211242cc481f48d46de0f04 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Thu, 28 Apr 2011 13:54:06 -0700 Subject: l2tp: Fix inet_opt conversion. We don't actually hold the socket lock at this point, so the rcu_dereference_protected() isn't' correct. Thanks to Eric Dumazet for pointing this out. Thankfully, we're only interested in fetching the faddr value if srr is enabled, so we can simply make this an RCU sequence and use plain rcu_dereference(). Reported-by: Eric Dumazet Signed-off-by: David S. Miller diff --git a/net/l2tp/l2tp_ip.c b/net/l2tp/l2tp_ip.c index 962a607..e13c166 100644 --- a/net/l2tp/l2tp_ip.c +++ b/net/l2tp/l2tp_ip.c @@ -472,13 +472,15 @@ static int l2tp_ip_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *m if (rt == NULL) { struct ip_options_rcu *inet_opt; - inet_opt = rcu_dereference_protected(inet->inet_opt, - sock_owned_by_user(sk)); + rcu_read_lock(); + inet_opt = rcu_dereference(inet->inet_opt); /* Use correct destination address if we have options. */ if (inet_opt && inet_opt->opt.srr) daddr = inet_opt->opt.faddr; + rcu_read_unlock(); + /* If this fails, retransmit mechanism of transport layer will * keep trying until route appears or the connection times * itself out. -- cgit v0.10.2 From 4d27e9dcff00a6425d779b065ec8892e4f391661 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Fri, 29 Apr 2011 00:35:50 +0200 Subject: PM: Make power domain callbacks take precedence over subsystem ones Change the PM core's behavior related to power domains in such a way that, if a power domain is defined for a given device, its callbacks will be executed instead of and not in addition to the device subsystem's PM callbacks. The idea behind the initial implementation of power domains handling by the PM core was that power domain callbacks would be executed in addition to subsystem callbacks, so that it would be possible to extend the subsystem callbacks by using power domains. It turns out, however, that this wouldn't be really convenient in some important situations. For example, there are systems in which power can only be removed from entire power domains. On those systems it is not desirable to execute device drivers' PM callbacks until it is known that power is going to be removed from the devices in question, which means that they should be executed by power domain callbacks rather then by subsystem (e.g. bus type) PM callbacks, because subsystems generally have no information about what devices belong to which power domain. Thus, for instance, if the bus type in question is the platform bus type, its PM callbacks generally should not be called in addition to power domain callbacks, because they run device drivers' callbacks unconditionally if defined. While in principle the default subsystem PM callbacks, or a subset of them, may be replaced with different functions, it doesn't seem correct to do so, because that would change the subsystem's behavior with respect to all devices in the system, regardless of whether or not they belong to any power domains. Thus, the only remaining option is to make power domain callbacks take precedence over subsystem callbacks. Signed-off-by: Rafael J. Wysocki Acked-by: Grant Likely Acked-by: Kevin Hilman diff --git a/drivers/base/power/main.c b/drivers/base/power/main.c index abe3ab7..3b35456 100644 --- a/drivers/base/power/main.c +++ b/drivers/base/power/main.c @@ -426,10 +426,8 @@ static int device_resume_noirq(struct device *dev, pm_message_t state) if (dev->pwr_domain) { pm_dev_dbg(dev, state, "EARLY power domain "); - pm_noirq_op(dev, &dev->pwr_domain->ops, state); - } - - if (dev->type && dev->type->pm) { + error = pm_noirq_op(dev, &dev->pwr_domain->ops, state); + } else if (dev->type && dev->type->pm) { pm_dev_dbg(dev, state, "EARLY type "); error = pm_noirq_op(dev, dev->type->pm, state); } else if (dev->class && dev->class->pm) { @@ -517,7 +515,8 @@ static int device_resume(struct device *dev, pm_message_t state, bool async) if (dev->pwr_domain) { pm_dev_dbg(dev, state, "power domain "); - pm_op(dev, &dev->pwr_domain->ops, state); + error = pm_op(dev, &dev->pwr_domain->ops, state); + goto End; } if (dev->type && dev->type->pm) { @@ -629,12 +628,11 @@ static void device_complete(struct device *dev, pm_message_t state) { device_lock(dev); - if (dev->pwr_domain && dev->pwr_domain->ops.complete) { + if (dev->pwr_domain) { pm_dev_dbg(dev, state, "completing power domain "); - dev->pwr_domain->ops.complete(dev); - } - - if (dev->type && dev->type->pm) { + if (dev->pwr_domain->ops.complete) + dev->pwr_domain->ops.complete(dev); + } else if (dev->type && dev->type->pm) { pm_dev_dbg(dev, state, "completing type "); if (dev->type->pm->complete) dev->type->pm->complete(dev); @@ -732,7 +730,12 @@ static int device_suspend_noirq(struct device *dev, pm_message_t state) { int error; - if (dev->type && dev->type->pm) { + if (dev->pwr_domain) { + pm_dev_dbg(dev, state, "LATE power domain "); + error = pm_noirq_op(dev, &dev->pwr_domain->ops, state); + if (error) + return error; + } else if (dev->type && dev->type->pm) { pm_dev_dbg(dev, state, "LATE type "); error = pm_noirq_op(dev, dev->type->pm, state); if (error) @@ -749,11 +752,6 @@ static int device_suspend_noirq(struct device *dev, pm_message_t state) return error; } - if (dev->pwr_domain) { - pm_dev_dbg(dev, state, "LATE power domain "); - pm_noirq_op(dev, &dev->pwr_domain->ops, state); - } - return 0; } @@ -841,21 +839,27 @@ static int __device_suspend(struct device *dev, pm_message_t state, bool async) goto End; } + if (dev->pwr_domain) { + pm_dev_dbg(dev, state, "power domain "); + error = pm_op(dev, &dev->pwr_domain->ops, state); + goto End; + } + if (dev->type && dev->type->pm) { pm_dev_dbg(dev, state, "type "); error = pm_op(dev, dev->type->pm, state); - goto Domain; + goto End; } if (dev->class) { if (dev->class->pm) { pm_dev_dbg(dev, state, "class "); error = pm_op(dev, dev->class->pm, state); - goto Domain; + goto End; } else if (dev->class->suspend) { pm_dev_dbg(dev, state, "legacy class "); error = legacy_suspend(dev, state, dev->class->suspend); - goto Domain; + goto End; } } @@ -869,12 +873,6 @@ static int __device_suspend(struct device *dev, pm_message_t state, bool async) } } - Domain: - if (!error && dev->pwr_domain) { - pm_dev_dbg(dev, state, "power domain "); - pm_op(dev, &dev->pwr_domain->ops, state); - } - End: device_unlock(dev); complete_all(&dev->power.completion); @@ -965,7 +963,14 @@ static int device_prepare(struct device *dev, pm_message_t state) device_lock(dev); - if (dev->type && dev->type->pm) { + if (dev->pwr_domain) { + pm_dev_dbg(dev, state, "preparing power domain "); + if (dev->pwr_domain->ops.prepare) + error = dev->pwr_domain->ops.prepare(dev); + suspend_report_result(dev->pwr_domain->ops.prepare, error); + if (error) + goto End; + } else if (dev->type && dev->type->pm) { pm_dev_dbg(dev, state, "preparing type "); if (dev->type->pm->prepare) error = dev->type->pm->prepare(dev); @@ -984,13 +989,6 @@ static int device_prepare(struct device *dev, pm_message_t state) if (dev->bus->pm->prepare) error = dev->bus->pm->prepare(dev); suspend_report_result(dev->bus->pm->prepare, error); - if (error) - goto End; - } - - if (dev->pwr_domain && dev->pwr_domain->ops.prepare) { - pm_dev_dbg(dev, state, "preparing power domain "); - dev->pwr_domain->ops.prepare(dev); } End: diff --git a/drivers/base/power/runtime.c b/drivers/base/power/runtime.c index 3172c60..0d4587b 100644 --- a/drivers/base/power/runtime.c +++ b/drivers/base/power/runtime.c @@ -168,7 +168,6 @@ static int rpm_check_suspend_allowed(struct device *dev) static int rpm_idle(struct device *dev, int rpmflags) { int (*callback)(struct device *); - int (*domain_callback)(struct device *); int retval; retval = rpm_check_suspend_allowed(dev); @@ -214,7 +213,9 @@ static int rpm_idle(struct device *dev, int rpmflags) dev->power.idle_notification = true; - if (dev->type && dev->type->pm) + if (dev->pwr_domain) + callback = dev->pwr_domain->ops.runtime_idle; + else if (dev->type && dev->type->pm) callback = dev->type->pm->runtime_idle; else if (dev->class && dev->class->pm) callback = dev->class->pm->runtime_idle; @@ -223,19 +224,10 @@ static int rpm_idle(struct device *dev, int rpmflags) else callback = NULL; - if (dev->pwr_domain) - domain_callback = dev->pwr_domain->ops.runtime_idle; - else - domain_callback = NULL; - - if (callback || domain_callback) { + if (callback) { spin_unlock_irq(&dev->power.lock); - if (domain_callback) - retval = domain_callback(dev); - - if (!retval && callback) - callback(dev); + callback(dev); spin_lock_irq(&dev->power.lock); } @@ -382,7 +374,9 @@ static int rpm_suspend(struct device *dev, int rpmflags) __update_runtime_status(dev, RPM_SUSPENDING); - if (dev->type && dev->type->pm) + if (dev->pwr_domain) + callback = dev->pwr_domain->ops.runtime_suspend; + else if (dev->type && dev->type->pm) callback = dev->type->pm->runtime_suspend; else if (dev->class && dev->class->pm) callback = dev->class->pm->runtime_suspend; @@ -400,8 +394,6 @@ static int rpm_suspend(struct device *dev, int rpmflags) else pm_runtime_cancel_pending(dev); } else { - if (dev->pwr_domain) - rpm_callback(dev->pwr_domain->ops.runtime_suspend, dev); no_callback: __update_runtime_status(dev, RPM_SUSPENDED); pm_runtime_deactivate_timer(dev); @@ -582,9 +574,8 @@ static int rpm_resume(struct device *dev, int rpmflags) __update_runtime_status(dev, RPM_RESUMING); if (dev->pwr_domain) - rpm_callback(dev->pwr_domain->ops.runtime_resume, dev); - - if (dev->type && dev->type->pm) + callback = dev->pwr_domain->ops.runtime_resume; + else if (dev->type && dev->type->pm) callback = dev->type->pm->runtime_resume; else if (dev->class && dev->class->pm) callback = dev->class->pm->runtime_resume; -- cgit v0.10.2 From 69c9dd1ecf446ad8a830e4afc539a2a1adc85b78 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Fri, 29 Apr 2011 00:36:05 +0200 Subject: PM: Export platform bus type's default PM callbacks Export the default PM callbacks defined for the platform bus type so that they can be used by power domains for suspending and resuming platform devices in the future. Signed-off-by: Rafael J. Wysocki diff --git a/drivers/base/platform.c b/drivers/base/platform.c index 9e0e4fc..313556f 100644 --- a/drivers/base/platform.c +++ b/drivers/base/platform.c @@ -667,7 +667,7 @@ static int platform_legacy_resume(struct device *dev) return ret; } -static int platform_pm_prepare(struct device *dev) +int platform_pm_prepare(struct device *dev) { struct device_driver *drv = dev->driver; int ret = 0; @@ -678,7 +678,7 @@ static int platform_pm_prepare(struct device *dev) return ret; } -static void platform_pm_complete(struct device *dev) +void platform_pm_complete(struct device *dev) { struct device_driver *drv = dev->driver; @@ -686,16 +686,11 @@ static void platform_pm_complete(struct device *dev) drv->pm->complete(dev); } -#else /* !CONFIG_PM_SLEEP */ - -#define platform_pm_prepare NULL -#define platform_pm_complete NULL - -#endif /* !CONFIG_PM_SLEEP */ +#endif /* CONFIG_PM_SLEEP */ #ifdef CONFIG_SUSPEND -int __weak platform_pm_suspend(struct device *dev) +int platform_pm_suspend(struct device *dev) { struct device_driver *drv = dev->driver; int ret = 0; @@ -713,7 +708,7 @@ int __weak platform_pm_suspend(struct device *dev) return ret; } -int __weak platform_pm_suspend_noirq(struct device *dev) +int platform_pm_suspend_noirq(struct device *dev) { struct device_driver *drv = dev->driver; int ret = 0; @@ -729,7 +724,7 @@ int __weak platform_pm_suspend_noirq(struct device *dev) return ret; } -int __weak platform_pm_resume(struct device *dev) +int platform_pm_resume(struct device *dev) { struct device_driver *drv = dev->driver; int ret = 0; @@ -747,7 +742,7 @@ int __weak platform_pm_resume(struct device *dev) return ret; } -int __weak platform_pm_resume_noirq(struct device *dev) +int platform_pm_resume_noirq(struct device *dev) { struct device_driver *drv = dev->driver; int ret = 0; @@ -763,18 +758,11 @@ int __weak platform_pm_resume_noirq(struct device *dev) return ret; } -#else /* !CONFIG_SUSPEND */ - -#define platform_pm_suspend NULL -#define platform_pm_resume NULL -#define platform_pm_suspend_noirq NULL -#define platform_pm_resume_noirq NULL - -#endif /* !CONFIG_SUSPEND */ +#endif /* CONFIG_SUSPEND */ #ifdef CONFIG_HIBERNATE_CALLBACKS -static int platform_pm_freeze(struct device *dev) +int platform_pm_freeze(struct device *dev) { struct device_driver *drv = dev->driver; int ret = 0; @@ -792,7 +780,7 @@ static int platform_pm_freeze(struct device *dev) return ret; } -static int platform_pm_freeze_noirq(struct device *dev) +int platform_pm_freeze_noirq(struct device *dev) { struct device_driver *drv = dev->driver; int ret = 0; @@ -808,7 +796,7 @@ static int platform_pm_freeze_noirq(struct device *dev) return ret; } -static int platform_pm_thaw(struct device *dev) +int platform_pm_thaw(struct device *dev) { struct device_driver *drv = dev->driver; int ret = 0; @@ -826,7 +814,7 @@ static int platform_pm_thaw(struct device *dev) return ret; } -static int platform_pm_thaw_noirq(struct device *dev) +int platform_pm_thaw_noirq(struct device *dev) { struct device_driver *drv = dev->driver; int ret = 0; @@ -842,7 +830,7 @@ static int platform_pm_thaw_noirq(struct device *dev) return ret; } -static int platform_pm_poweroff(struct device *dev) +int platform_pm_poweroff(struct device *dev) { struct device_driver *drv = dev->driver; int ret = 0; @@ -860,7 +848,7 @@ static int platform_pm_poweroff(struct device *dev) return ret; } -static int platform_pm_poweroff_noirq(struct device *dev) +int platform_pm_poweroff_noirq(struct device *dev) { struct device_driver *drv = dev->driver; int ret = 0; @@ -876,7 +864,7 @@ static int platform_pm_poweroff_noirq(struct device *dev) return ret; } -static int platform_pm_restore(struct device *dev) +int platform_pm_restore(struct device *dev) { struct device_driver *drv = dev->driver; int ret = 0; @@ -894,7 +882,7 @@ static int platform_pm_restore(struct device *dev) return ret; } -static int platform_pm_restore_noirq(struct device *dev) +int platform_pm_restore_noirq(struct device *dev) { struct device_driver *drv = dev->driver; int ret = 0; @@ -910,18 +898,7 @@ static int platform_pm_restore_noirq(struct device *dev) return ret; } -#else /* !CONFIG_HIBERNATE_CALLBACKS */ - -#define platform_pm_freeze NULL -#define platform_pm_thaw NULL -#define platform_pm_poweroff NULL -#define platform_pm_restore NULL -#define platform_pm_freeze_noirq NULL -#define platform_pm_thaw_noirq NULL -#define platform_pm_poweroff_noirq NULL -#define platform_pm_restore_noirq NULL - -#endif /* !CONFIG_HIBERNATE_CALLBACKS */ +#endif /* CONFIG_HIBERNATE_CALLBACKS */ #ifdef CONFIG_PM_RUNTIME @@ -949,23 +926,10 @@ int __weak platform_pm_runtime_idle(struct device *dev) #endif /* !CONFIG_PM_RUNTIME */ static const struct dev_pm_ops platform_dev_pm_ops = { - .prepare = platform_pm_prepare, - .complete = platform_pm_complete, - .suspend = platform_pm_suspend, - .resume = platform_pm_resume, - .freeze = platform_pm_freeze, - .thaw = platform_pm_thaw, - .poweroff = platform_pm_poweroff, - .restore = platform_pm_restore, - .suspend_noirq = platform_pm_suspend_noirq, - .resume_noirq = platform_pm_resume_noirq, - .freeze_noirq = platform_pm_freeze_noirq, - .thaw_noirq = platform_pm_thaw_noirq, - .poweroff_noirq = platform_pm_poweroff_noirq, - .restore_noirq = platform_pm_restore_noirq, .runtime_suspend = platform_pm_runtime_suspend, .runtime_resume = platform_pm_runtime_resume, .runtime_idle = platform_pm_runtime_idle, + USE_PLATFORM_PM_SLEEP_OPS }; struct bus_type platform_bus_type = { diff --git a/include/linux/platform_device.h b/include/linux/platform_device.h index 744942c..e0093e0 100644 --- a/include/linux/platform_device.h +++ b/include/linux/platform_device.h @@ -205,4 +205,64 @@ static inline char *early_platform_driver_setup_func(void) \ } #endif /* MODULE */ +#ifdef CONFIG_PM_SLEEP +extern int platform_pm_prepare(struct device *dev); +extern void platform_pm_complete(struct device *dev); +#else +#define platform_pm_prepare NULL +#define platform_pm_complete NULL +#endif + +#ifdef CONFIG_SUSPEND +extern int platform_pm_suspend(struct device *dev); +extern int platform_pm_suspend_noirq(struct device *dev); +extern int platform_pm_resume(struct device *dev); +extern int platform_pm_resume_noirq(struct device *dev); +#else +#define platform_pm_suspend NULL +#define platform_pm_resume NULL +#define platform_pm_suspend_noirq NULL +#define platform_pm_resume_noirq NULL +#endif + +#ifdef CONFIG_HIBERNATE_CALLBACKS +extern int platform_pm_freeze(struct device *dev); +extern int platform_pm_freeze_noirq(struct device *dev); +extern int platform_pm_thaw(struct device *dev); +extern int platform_pm_thaw_noirq(struct device *dev); +extern int platform_pm_poweroff(struct device *dev); +extern int platform_pm_poweroff_noirq(struct device *dev); +extern int platform_pm_restore(struct device *dev); +extern int platform_pm_restore_noirq(struct device *dev); +#else +#define platform_pm_freeze NULL +#define platform_pm_thaw NULL +#define platform_pm_poweroff NULL +#define platform_pm_restore NULL +#define platform_pm_freeze_noirq NULL +#define platform_pm_thaw_noirq NULL +#define platform_pm_poweroff_noirq NULL +#define platform_pm_restore_noirq NULL +#endif + +#ifdef CONFIG_PM_SLEEP +#define USE_PLATFORM_PM_SLEEP_OPS \ + .prepare = platform_pm_prepare, \ + .complete = platform_pm_complete, \ + .suspend = platform_pm_suspend, \ + .resume = platform_pm_resume, \ + .freeze = platform_pm_freeze, \ + .thaw = platform_pm_thaw, \ + .poweroff = platform_pm_poweroff, \ + .restore = platform_pm_restore, \ + .suspend_noirq = platform_pm_suspend_noirq, \ + .resume_noirq = platform_pm_resume_noirq, \ + .freeze_noirq = platform_pm_freeze_noirq, \ + .thaw_noirq = platform_pm_thaw_noirq, \ + .poweroff_noirq = platform_pm_poweroff_noirq, \ + .restore_noirq = platform_pm_restore_noirq, +#else +#define USE_PLATFORM_PM_SLEEP_OPS +#endif + #endif /* _PLATFORM_DEVICE_H_ */ -- cgit v0.10.2 From 38ade3a1fa0421c12627c7b48c33e89414fc9b76 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Fri, 29 Apr 2011 00:36:21 +0200 Subject: shmobile: Use power domains for platform runtime PM shmobile platforms replace the runtime PM callbacks of the platform bus type with their own routines, but this means that the callbacks are replaced system-wide. This may not be the right approach if the platform devices on the system are not of the same type (e.g. some of them belong to an SoC and the others are located in separate chips), because in those cases they may require different handling. Thus it is better to use power domains to override the platform bus type's PM handling, as it generally is possible to use different power domains for devices with different PM requirements. Define a default power domain for shmobile in both the SH and ARM falvors and use it to override the platform bus type's PM callbacks. Since the suspend and hibernate callbacks of the new "default" power domains need to be the same and the platform bus type's suspend and hibernate callbacks for the time being, export those callbacks so that can be used outside of the platform bus type code. Signed-off-by: Rafael J. Wysocki diff --git a/arch/arm/mach-shmobile/pm_runtime.c b/arch/arm/mach-shmobile/pm_runtime.c index 94912d3..12bb504 100644 --- a/arch/arm/mach-shmobile/pm_runtime.c +++ b/arch/arm/mach-shmobile/pm_runtime.c @@ -66,11 +66,11 @@ static void platform_pm_runtime_bug(struct device *dev, dev_err(dev, "runtime pm suspend before resume\n"); } -int platform_pm_runtime_suspend(struct device *dev) +static int default_platform_runtime_suspend(struct device *dev) { struct pm_runtime_data *prd = __to_prd(dev); - dev_dbg(dev, "platform_pm_runtime_suspend()\n"); + dev_dbg(dev, "%s()\n", __func__); platform_pm_runtime_bug(dev, prd); @@ -82,11 +82,11 @@ int platform_pm_runtime_suspend(struct device *dev) return 0; } -int platform_pm_runtime_resume(struct device *dev) +static int default_platform_runtime_resume(struct device *dev) { struct pm_runtime_data *prd = __to_prd(dev); - dev_dbg(dev, "platform_pm_runtime_resume()\n"); + dev_dbg(dev, "%s()\n", __func__); platform_pm_runtime_init(dev, prd); @@ -98,12 +98,21 @@ int platform_pm_runtime_resume(struct device *dev) return 0; } -int platform_pm_runtime_idle(struct device *dev) +static int default_platform_runtime_idle(struct device *dev) { /* suspend synchronously to disable clocks immediately */ return pm_runtime_suspend(dev); } +static struct dev_power_domain default_power_domain = { + .ops = { + .runtime_suspend = default_platform_runtime_suspend, + .runtime_resume = default_platform_runtime_resume, + .runtime_idle = default_platform_runtime_idle, + USE_PLATFORM_PM_SLEEP_OPS + }, +}; + static int platform_bus_notify(struct notifier_block *nb, unsigned long action, void *data) { @@ -114,10 +123,12 @@ static int platform_bus_notify(struct notifier_block *nb, if (action == BUS_NOTIFY_BIND_DRIVER) { prd = devres_alloc(__devres_release, sizeof(*prd), GFP_KERNEL); - if (prd) + if (prd) { devres_add(dev, prd); - else + dev->pwr_domain = &default_power_domain; + } else { dev_err(dev, "unable to alloc memory for runtime pm\n"); + } } return 0; diff --git a/arch/sh/kernel/cpu/shmobile/pm_runtime.c b/arch/sh/kernel/cpu/shmobile/pm_runtime.c index 6dcb816..22db127 100644 --- a/arch/sh/kernel/cpu/shmobile/pm_runtime.c +++ b/arch/sh/kernel/cpu/shmobile/pm_runtime.c @@ -139,7 +139,7 @@ void platform_pm_runtime_suspend_idle(void) queue_work(pm_wq, &hwblk_work); } -int platform_pm_runtime_suspend(struct device *dev) +static int default_platform_runtime_suspend(struct device *dev) { struct platform_device *pdev = to_platform_device(dev); struct pdev_archdata *ad = &pdev->archdata; @@ -147,7 +147,7 @@ int platform_pm_runtime_suspend(struct device *dev) int hwblk = ad->hwblk_id; int ret = 0; - dev_dbg(dev, "platform_pm_runtime_suspend() [%d]\n", hwblk); + dev_dbg(dev, "%s() [%d]\n", __func__, hwblk); /* ignore off-chip platform devices */ if (!hwblk) @@ -183,20 +183,20 @@ int platform_pm_runtime_suspend(struct device *dev) mutex_unlock(&ad->mutex); out: - dev_dbg(dev, "platform_pm_runtime_suspend() [%d] returns %d\n", - hwblk, ret); + dev_dbg(dev, "%s() [%d] returns %d\n", + __func__, hwblk, ret); return ret; } -int platform_pm_runtime_resume(struct device *dev) +static int default_platform_runtime_resume(struct device *dev) { struct platform_device *pdev = to_platform_device(dev); struct pdev_archdata *ad = &pdev->archdata; int hwblk = ad->hwblk_id; int ret = 0; - dev_dbg(dev, "platform_pm_runtime_resume() [%d]\n", hwblk); + dev_dbg(dev, "%s() [%d]\n", __func__, hwblk); /* ignore off-chip platform devices */ if (!hwblk) @@ -228,19 +228,19 @@ int platform_pm_runtime_resume(struct device *dev) */ mutex_unlock(&ad->mutex); out: - dev_dbg(dev, "platform_pm_runtime_resume() [%d] returns %d\n", - hwblk, ret); + dev_dbg(dev, "%s() [%d] returns %d\n", + __func__, hwblk, ret); return ret; } -int platform_pm_runtime_idle(struct device *dev) +static int default_platform_runtime_idle(struct device *dev) { struct platform_device *pdev = to_platform_device(dev); int hwblk = pdev->archdata.hwblk_id; int ret = 0; - dev_dbg(dev, "platform_pm_runtime_idle() [%d]\n", hwblk); + dev_dbg(dev, "%s() [%d]\n", __func__, hwblk); /* ignore off-chip platform devices */ if (!hwblk) @@ -252,10 +252,19 @@ int platform_pm_runtime_idle(struct device *dev) /* suspend synchronously to disable clocks immediately */ ret = pm_runtime_suspend(dev); out: - dev_dbg(dev, "platform_pm_runtime_idle() [%d] done!\n", hwblk); + dev_dbg(dev, "%s() [%d] done!\n", __func__, hwblk); return ret; } +static struct dev_power_domain default_power_domain = { + .ops = { + .runtime_suspend = default_platform_runtime_suspend, + .runtime_resume = default_platform_runtime_resume, + .runtime_idle = default_platform_runtime_idle, + USE_PLATFORM_PM_SLEEP_OPS + }, +}; + static int platform_bus_notify(struct notifier_block *nb, unsigned long action, void *data) { @@ -276,6 +285,7 @@ static int platform_bus_notify(struct notifier_block *nb, hwblk_disable(hwblk_info, hwblk); /* make sure driver re-inits itself once */ __set_bit(PDEV_ARCHDATA_FLAG_INIT, &pdev->archdata.flags); + dev->pwr_domain = &default_power_domain; break; /* TODO: add BUS_NOTIFY_BIND_DRIVER and increase idle count */ case BUS_NOTIFY_BOUND_DRIVER: @@ -289,6 +299,7 @@ static int platform_bus_notify(struct notifier_block *nb, __set_bit(PDEV_ARCHDATA_FLAG_INIT, &pdev->archdata.flags); break; case BUS_NOTIFY_DEL_DEVICE: + dev->pwr_domain = NULL; break; } return 0; -- cgit v0.10.2 From 8b313a38ecffc0ff0b4c5115f0a461f73b7dfdb6 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Fri, 29 Apr 2011 00:36:32 +0200 Subject: PM / Platform: Use generic runtime PM callbacks directly Once shmobile platforms have been converted to using power domains for overriding the platform bus type's PM callbacks, it isn't necessary to use the __weakly defined wrappers around the generinc runtime PM callbacks in the platform bus type any more. Signed-off-by: Rafael J. Wysocki diff --git a/drivers/base/platform.c b/drivers/base/platform.c index 313556f..079c18a 100644 --- a/drivers/base/platform.c +++ b/drivers/base/platform.c @@ -900,35 +900,10 @@ int platform_pm_restore_noirq(struct device *dev) #endif /* CONFIG_HIBERNATE_CALLBACKS */ -#ifdef CONFIG_PM_RUNTIME - -int __weak platform_pm_runtime_suspend(struct device *dev) -{ - return pm_generic_runtime_suspend(dev); -}; - -int __weak platform_pm_runtime_resume(struct device *dev) -{ - return pm_generic_runtime_resume(dev); -}; - -int __weak platform_pm_runtime_idle(struct device *dev) -{ - return pm_generic_runtime_idle(dev); -}; - -#else /* !CONFIG_PM_RUNTIME */ - -#define platform_pm_runtime_suspend NULL -#define platform_pm_runtime_resume NULL -#define platform_pm_runtime_idle NULL - -#endif /* !CONFIG_PM_RUNTIME */ - static const struct dev_pm_ops platform_dev_pm_ops = { - .runtime_suspend = platform_pm_runtime_suspend, - .runtime_resume = platform_pm_runtime_resume, - .runtime_idle = platform_pm_runtime_idle, + .runtime_suspend = pm_generic_runtime_suspend, + .runtime_resume = pm_generic_runtime_resume, + .runtime_idle = pm_generic_runtime_idle, USE_PLATFORM_PM_SLEEP_OPS }; -- cgit v0.10.2 From 638080c37ae08fd0c44cec13d7948ca5385ae851 Mon Sep 17 00:00:00 2001 From: Kevin Hilman Date: Fri, 29 Apr 2011 00:36:42 +0200 Subject: OMAP2+ / PM: move runtime PM implementation to use device power domains In commit 7538e3db6e015e890825fbd9f8659952896ddd5b (PM: add support for device power domains) a better way for handling platform-specific power hooks was introduced. Rather than using the platform_bus dev_pm_ops overrides (platform_bus_set_pm_ops()), this patch moves the OMAP runtime PM implementation over to using device power domains. Since OMAP is the only user of platform_bus_set_pm_ops(), that interface can be removed (and will be in a forthcoming patch.) [rjw: Rebased on top of a previous change modifying the handling of power domains by the PM core so that power domain callbacks take precendence over subsystem-level PM callbacks.] Signed-off-by: Kevin Hilman Acked-by: Grant Likely Signed-off-by: Rafael J. Wysocki diff --git a/arch/arm/mach-omap2/Makefile b/arch/arm/mach-omap2/Makefile index a45cd64..b353584 100644 --- a/arch/arm/mach-omap2/Makefile +++ b/arch/arm/mach-omap2/Makefile @@ -59,10 +59,10 @@ endif # Power Management ifeq ($(CONFIG_PM),y) obj-$(CONFIG_ARCH_OMAP2) += pm24xx.o -obj-$(CONFIG_ARCH_OMAP2) += sleep24xx.o pm_bus.o +obj-$(CONFIG_ARCH_OMAP2) += sleep24xx.o obj-$(CONFIG_ARCH_OMAP3) += pm34xx.o sleep34xx.o \ - cpuidle34xx.o pm_bus.o -obj-$(CONFIG_ARCH_OMAP4) += pm44xx.o pm_bus.o + cpuidle34xx.o +obj-$(CONFIG_ARCH_OMAP4) += pm44xx.o obj-$(CONFIG_PM_DEBUG) += pm-debug.o obj-$(CONFIG_OMAP_SMARTREFLEX) += sr_device.o smartreflex.o obj-$(CONFIG_OMAP_SMARTREFLEX_CLASS3) += smartreflex-class3.o diff --git a/arch/arm/mach-omap2/pm_bus.c b/arch/arm/mach-omap2/pm_bus.c deleted file mode 100644 index 5acd2ab..0000000 --- a/arch/arm/mach-omap2/pm_bus.c +++ /dev/null @@ -1,85 +0,0 @@ -/* - * Runtime PM support code for OMAP - * - * Author: Kevin Hilman, Deep Root Systems, LLC - * - * Copyright (C) 2010 Texas Instruments, Inc. - * - * This file is licensed under the terms of the GNU General Public - * License version 2. This program is licensed "as is" without any - * warranty of any kind, whether express or implied. - */ -#include -#include -#include -#include -#include -#include - -#include -#include - -#ifdef CONFIG_PM_RUNTIME -static int omap_pm_runtime_suspend(struct device *dev) -{ - struct platform_device *pdev = to_platform_device(dev); - int r, ret = 0; - - dev_dbg(dev, "%s\n", __func__); - - ret = pm_generic_runtime_suspend(dev); - - if (!ret && dev->parent == &omap_device_parent) { - r = omap_device_idle(pdev); - WARN_ON(r); - } - - return ret; -}; - -static int omap_pm_runtime_resume(struct device *dev) -{ - struct platform_device *pdev = to_platform_device(dev); - int r; - - dev_dbg(dev, "%s\n", __func__); - - if (dev->parent == &omap_device_parent) { - r = omap_device_enable(pdev); - WARN_ON(r); - } - - return pm_generic_runtime_resume(dev); -}; -#else -#define omap_pm_runtime_suspend NULL -#define omap_pm_runtime_resume NULL -#endif /* CONFIG_PM_RUNTIME */ - -static int __init omap_pm_runtime_init(void) -{ - const struct dev_pm_ops *pm; - struct dev_pm_ops *omap_pm; - - pm = platform_bus_get_pm_ops(); - if (!pm) { - pr_err("%s: unable to get dev_pm_ops from platform_bus\n", - __func__); - return -ENODEV; - } - - omap_pm = kmemdup(pm, sizeof(struct dev_pm_ops), GFP_KERNEL); - if (!omap_pm) { - pr_err("%s: unable to alloc memory for new dev_pm_ops\n", - __func__); - return -ENOMEM; - } - - omap_pm->runtime_suspend = omap_pm_runtime_suspend; - omap_pm->runtime_resume = omap_pm_runtime_resume; - - platform_bus_set_pm_ops(omap_pm); - - return 0; -} -core_initcall(omap_pm_runtime_init); diff --git a/arch/arm/plat-omap/omap_device.c b/arch/arm/plat-omap/omap_device.c index 9bbda9a..a37b8eb 100644 --- a/arch/arm/plat-omap/omap_device.c +++ b/arch/arm/plat-omap/omap_device.c @@ -536,6 +536,28 @@ int omap_early_device_register(struct omap_device *od) return 0; } +static int _od_runtime_suspend(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + + return omap_device_idle(pdev); +} + +static int _od_runtime_resume(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + + return omap_device_enable(pdev); +} + +static struct dev_power_domain omap_device_power_domain = { + .ops = { + .runtime_suspend = _od_runtime_suspend, + .runtime_resume = _od_runtime_resume, + USE_PLATFORM_PM_SLEEP_OPS + } +}; + /** * omap_device_register - register an omap_device with one omap_hwmod * @od: struct omap_device * to register @@ -549,6 +571,7 @@ int omap_device_register(struct omap_device *od) pr_debug("omap_device: %s: registering\n", od->pdev.name); od->pdev.dev.parent = &omap_device_parent; + od->pdev.dev.pwr_domain = &omap_device_power_domain; return platform_device_register(&od->pdev); } -- cgit v0.10.2 From 1d2b71f61b6a10216274e27b717becf9ae101fc7 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Fri, 29 Apr 2011 00:36:53 +0200 Subject: PM / Runtime: Add subsystem data field to struct dev_pm_info Some subsystems need to attach PM-related data to struct device and they need to use devres for this purpose. For their convenience and to make code more straightforward, add a new field called subsys_data to struct dev_pm_info and let subsystems use it for attaching PM-related information to devices. Convert the ARM shmobile platform to using the new field. Signed-off-by: Rafael J. Wysocki diff --git a/arch/arm/mach-shmobile/pm_runtime.c b/arch/arm/mach-shmobile/pm_runtime.c index 12bb504..30bbe9a 100644 --- a/arch/arm/mach-shmobile/pm_runtime.c +++ b/arch/arm/mach-shmobile/pm_runtime.c @@ -18,6 +18,7 @@ #include #include #include +#include #ifdef CONFIG_PM_RUNTIME #define BIT_ONCE 0 @@ -29,22 +30,9 @@ struct pm_runtime_data { struct clk *clk; }; -static void __devres_release(struct device *dev, void *res) -{ - struct pm_runtime_data *prd = res; - - dev_dbg(dev, "__devres_release()\n"); - - if (test_bit(BIT_CLK_ENABLED, &prd->flags)) - clk_disable(prd->clk); - - if (test_bit(BIT_ACTIVE, &prd->flags)) - clk_put(prd->clk); -} - static struct pm_runtime_data *__to_prd(struct device *dev) { - return devres_find(dev, __devres_release, NULL, NULL); + return dev ? dev->power.subsys_data : NULL; } static void platform_pm_runtime_init(struct device *dev, @@ -121,14 +109,26 @@ static int platform_bus_notify(struct notifier_block *nb, dev_dbg(dev, "platform_bus_notify() %ld !\n", action); - if (action == BUS_NOTIFY_BIND_DRIVER) { - prd = devres_alloc(__devres_release, sizeof(*prd), GFP_KERNEL); + switch (action) { + case BUS_NOTIFY_BIND_DRIVER: + prd = kzalloc(sizeof(*prd), GFP_KERNEL); if (prd) { - devres_add(dev, prd); + dev->power.subsys_data = prd; dev->pwr_domain = &default_power_domain; } else { dev_err(dev, "unable to alloc memory for runtime pm\n"); } + break; + case BUS_NOTIFY_UNBOUND_DRIVER: + prd = __to_prd(dev); + if (prd) { + if (test_bit(BIT_CLK_ENABLED, &prd->flags)) + clk_disable(prd->clk); + + if (test_bit(BIT_ACTIVE, &prd->flags)) + clk_put(prd->clk); + } + break; } return 0; diff --git a/include/linux/pm.h b/include/linux/pm.h index 512e091..f4167d0 100644 --- a/include/linux/pm.h +++ b/include/linux/pm.h @@ -460,6 +460,7 @@ struct dev_pm_info { unsigned long active_jiffies; unsigned long suspended_jiffies; unsigned long accounting_timestamp; + void *subsys_data; /* Owned by the subsystem. */ #endif }; -- cgit v0.10.2 From cf3cc1aa9b6d0bf1750143af65829f4368d77492 Mon Sep 17 00:00:00 2001 From: Viktor Rosendahl Date: Mon, 28 Mar 2011 18:56:05 +0300 Subject: kprobes/arm: Fix ldrd/strd emulation Currently emulate_ldrd and emulate_strd don't even have the adjustment of the PC value, so in case of Rn == PC, it will not update the PC incorrectly but instead load/store from the wrong address. Let's add both the adjustment of the PC value and the check for PC == PC. Signed-off-by: Viktor Rosendahl Signed-off-by: Nicolas Pitre diff --git a/arch/arm/kernel/kprobes-decode.c b/arch/arm/kernel/kprobes-decode.c index 2389131..3b0cf90 100644 --- a/arch/arm/kernel/kprobes-decode.c +++ b/arch/arm/kernel/kprobes-decode.c @@ -540,9 +540,12 @@ static void __kprobes emulate_ldrd(struct kprobe *p, struct pt_regs *regs) { insn_2arg_fn_t *i_fn = (insn_2arg_fn_t *)&p->ainsn.insn[0]; kprobe_opcode_t insn = p->opcode; + long ppc = (long)p->addr + 8; int rd = (insn >> 12) & 0xf; int rn = (insn >> 16) & 0xf; int rm = insn & 0xf; /* rm may be invalid, don't care. */ + long rmv = (rm == 15) ? ppc : regs->uregs[rm]; + long rnv = (rn == 15) ? ppc : regs->uregs[rn]; /* Not following the C calling convention here, so need asm(). */ __asm__ __volatile__ ( @@ -554,29 +557,36 @@ static void __kprobes emulate_ldrd(struct kprobe *p, struct pt_regs *regs) "str r0, %[rn] \n\t" /* in case of writeback */ "str r2, %[rd0] \n\t" "str r3, %[rd1] \n\t" - : [rn] "+m" (regs->uregs[rn]), + : [rn] "+m" (rnv), [rd0] "=m" (regs->uregs[rd]), [rd1] "=m" (regs->uregs[rd+1]) - : [rm] "m" (regs->uregs[rm]), + : [rm] "m" (rmv), [cpsr] "r" (regs->ARM_cpsr), [i_fn] "r" (i_fn) : "r0", "r1", "r2", "r3", "lr", "cc" ); + if (rn != 15) + regs->uregs[rn] = rnv; /* Save Rn in case of writeback. */ } static void __kprobes emulate_strd(struct kprobe *p, struct pt_regs *regs) { insn_4arg_fn_t *i_fn = (insn_4arg_fn_t *)&p->ainsn.insn[0]; kprobe_opcode_t insn = p->opcode; + long ppc = (long)p->addr + 8; int rd = (insn >> 12) & 0xf; int rn = (insn >> 16) & 0xf; int rm = insn & 0xf; - long rnv = regs->uregs[rn]; - long rmv = regs->uregs[rm]; /* rm/rmv may be invalid, don't care. */ + long rnv = (rn == 15) ? ppc : regs->uregs[rn]; + /* rm/rmv may be invalid, don't care. */ + long rmv = (rm == 15) ? ppc : regs->uregs[rm]; + long rnv_wb; - regs->uregs[rn] = insnslot_4arg_rflags(rnv, rmv, regs->uregs[rd], + rnv_wb = insnslot_4arg_rflags(rnv, rmv, regs->uregs[rd], regs->uregs[rd+1], regs->ARM_cpsr, i_fn); + if (rn != 15) + regs->uregs[rn] = rnv_wb; /* Save Rn in case of writeback. */ } static void __kprobes emulate_ldr(struct kprobe *p, struct pt_regs *regs) -- cgit v0.10.2 From 073090cb701148396b1130be81f8ac84a41f196d Mon Sep 17 00:00:00 2001 From: Jon Medhurst Date: Wed, 6 Apr 2011 11:17:09 +0100 Subject: ARM: kprobes: Fix probing of conditionally executed instructions When a kprobe is placed onto conditionally executed ARM instructions, many of the emulation routines used to single step them produce corrupt register results. Rather than fix all of these cases we modify the framework which calls them to test the relevant condition flags and, if the test fails, skip calling the emulation code. Signed-off-by: Jon Medhurst Signed-off-by: Nicolas Pitre diff --git a/arch/arm/include/asm/kprobes.h b/arch/arm/include/asm/kprobes.h index bb8a19b..e46bdd0 100644 --- a/arch/arm/include/asm/kprobes.h +++ b/arch/arm/include/asm/kprobes.h @@ -39,10 +39,13 @@ typedef u32 kprobe_opcode_t; struct kprobe; typedef void (kprobe_insn_handler_t)(struct kprobe *, struct pt_regs *); +typedef unsigned long (kprobe_check_cc)(unsigned long); + /* Architecture specific copy of original instruction. */ struct arch_specific_insn { kprobe_opcode_t *insn; kprobe_insn_handler_t *insn_handler; + kprobe_check_cc *insn_check_cc; }; struct prev_kprobe { diff --git a/arch/arm/kernel/kprobes-decode.c b/arch/arm/kernel/kprobes-decode.c index 3b0cf90..2e84169 100644 --- a/arch/arm/kernel/kprobes-decode.c +++ b/arch/arm/kernel/kprobes-decode.c @@ -1396,6 +1396,96 @@ space_cccc_111x(kprobe_opcode_t insn, struct arch_specific_insn *asi) return INSN_GOOD; } +static unsigned long __kprobes __check_eq(unsigned long cpsr) +{ + return cpsr & PSR_Z_BIT; +} + +static unsigned long __kprobes __check_ne(unsigned long cpsr) +{ + return (~cpsr) & PSR_Z_BIT; +} + +static unsigned long __kprobes __check_cs(unsigned long cpsr) +{ + return cpsr & PSR_C_BIT; +} + +static unsigned long __kprobes __check_cc(unsigned long cpsr) +{ + return (~cpsr) & PSR_C_BIT; +} + +static unsigned long __kprobes __check_mi(unsigned long cpsr) +{ + return cpsr & PSR_N_BIT; +} + +static unsigned long __kprobes __check_pl(unsigned long cpsr) +{ + return (~cpsr) & PSR_N_BIT; +} + +static unsigned long __kprobes __check_vs(unsigned long cpsr) +{ + return cpsr & PSR_V_BIT; +} + +static unsigned long __kprobes __check_vc(unsigned long cpsr) +{ + return (~cpsr) & PSR_V_BIT; +} + +static unsigned long __kprobes __check_hi(unsigned long cpsr) +{ + cpsr &= ~(cpsr >> 1); /* PSR_C_BIT &= ~PSR_Z_BIT */ + return cpsr & PSR_C_BIT; +} + +static unsigned long __kprobes __check_ls(unsigned long cpsr) +{ + cpsr &= ~(cpsr >> 1); /* PSR_C_BIT &= ~PSR_Z_BIT */ + return (~cpsr) & PSR_C_BIT; +} + +static unsigned long __kprobes __check_ge(unsigned long cpsr) +{ + cpsr ^= (cpsr << 3); /* PSR_N_BIT ^= PSR_V_BIT */ + return (~cpsr) & PSR_N_BIT; +} + +static unsigned long __kprobes __check_lt(unsigned long cpsr) +{ + cpsr ^= (cpsr << 3); /* PSR_N_BIT ^= PSR_V_BIT */ + return cpsr & PSR_N_BIT; +} + +static unsigned long __kprobes __check_gt(unsigned long cpsr) +{ + unsigned long temp = cpsr ^ (cpsr << 3); /* PSR_N_BIT ^= PSR_V_BIT */ + temp |= (cpsr << 1); /* PSR_N_BIT |= PSR_Z_BIT */ + return (~temp) & PSR_N_BIT; +} + +static unsigned long __kprobes __check_le(unsigned long cpsr) +{ + unsigned long temp = cpsr ^ (cpsr << 3); /* PSR_N_BIT ^= PSR_V_BIT */ + temp |= (cpsr << 1); /* PSR_N_BIT |= PSR_Z_BIT */ + return temp & PSR_N_BIT; +} + +static unsigned long __kprobes __check_al(unsigned long cpsr) +{ + return true; +} + +static kprobe_check_cc * const condition_checks[16] = { + &__check_eq, &__check_ne, &__check_cs, &__check_cc, + &__check_mi, &__check_pl, &__check_vs, &__check_vc, + &__check_hi, &__check_ls, &__check_ge, &__check_lt, + &__check_gt, &__check_le, &__check_al, &__check_al +}; + /* Return: * INSN_REJECTED If instruction is one not allowed to kprobe, * INSN_GOOD If instruction is supported and uses instruction slot, @@ -1411,6 +1501,7 @@ space_cccc_111x(kprobe_opcode_t insn, struct arch_specific_insn *asi) enum kprobe_insn __kprobes arm_kprobe_decode_insn(kprobe_opcode_t insn, struct arch_specific_insn *asi) { + asi->insn_check_cc = condition_checks[insn>>28]; asi->insn[1] = KPROBE_RETURN_INSTRUCTION; if ((insn & 0xf0000000) == 0xf0000000) { diff --git a/arch/arm/kernel/kprobes.c b/arch/arm/kernel/kprobes.c index 2ba7deb..1656c87 100644 --- a/arch/arm/kernel/kprobes.c +++ b/arch/arm/kernel/kprobes.c @@ -134,7 +134,8 @@ static void __kprobes singlestep(struct kprobe *p, struct pt_regs *regs, struct kprobe_ctlblk *kcb) { regs->ARM_pc += 4; - p->ainsn.insn_handler(p, regs); + if (p->ainsn.insn_check_cc(regs->ARM_cpsr)) + p->ainsn.insn_handler(p, regs); } /* -- cgit v0.10.2 From a539f5d46c868cb1f37b92e62e040b400571aed4 Mon Sep 17 00:00:00 2001 From: Jon Medhurst Date: Wed, 6 Apr 2011 11:17:10 +0100 Subject: ARM: kprobes: Remove redundant condition checks from simulation routines Now we have the framework code handling conditionally executed instructions we can remove redundant checks in individual simulation routines. Signed-off-by: Jon Medhurst Signed-off-by: Nicolas Pitre diff --git a/arch/arm/kernel/kprobes-decode.c b/arch/arm/kernel/kprobes-decode.c index 2e84169..f52fac0c5 100644 --- a/arch/arm/kernel/kprobes-decode.c +++ b/arch/arm/kernel/kprobes-decode.c @@ -71,10 +71,6 @@ #define PSR_fs (PSR_f|PSR_s) #define KPROBE_RETURN_INSTRUCTION 0xe1a0f00e /* mov pc, lr */ -#define SET_R0_TRUE_INSTRUCTION 0xe3a00001 /* mov r0, #1 */ - -#define truecc_insn(insn) (((insn) & 0xf0000000) | \ - (SET_R0_TRUE_INSTRUCTION & 0x0fffffff)) typedef long (insn_0arg_fn_t)(void); typedef long (insn_1arg_fn_t)(long); @@ -419,14 +415,10 @@ insnslot_llret_4arg_rwflags(long r0, long r1, long r2, long r3, long *cpsr, static void __kprobes simulate_bbl(struct kprobe *p, struct pt_regs *regs) { - insn_1arg_fn_t *i_fn = (insn_1arg_fn_t *)&p->ainsn.insn[0]; kprobe_opcode_t insn = p->opcode; long iaddr = (long)p->addr; int disp = branch_displacement(insn); - if (!insnslot_1arg_rflags(0, regs->ARM_cpsr, i_fn)) - return; - if (insn & (1 << 24)) regs->ARM_lr = iaddr + 4; @@ -446,14 +438,10 @@ static void __kprobes simulate_blx1(struct kprobe *p, struct pt_regs *regs) static void __kprobes simulate_blx2bx(struct kprobe *p, struct pt_regs *regs) { - insn_1arg_fn_t *i_fn = (insn_1arg_fn_t *)&p->ainsn.insn[0]; kprobe_opcode_t insn = p->opcode; int rm = insn & 0xf; long rmv = regs->uregs[rm]; - if (!insnslot_1arg_rflags(0, regs->ARM_cpsr, i_fn)) - return; - if (insn & (1 << 5)) regs->ARM_lr = (long)p->addr + 4; @@ -465,7 +453,6 @@ static void __kprobes simulate_blx2bx(struct kprobe *p, struct pt_regs *regs) static void __kprobes simulate_ldm1stm1(struct kprobe *p, struct pt_regs *regs) { - insn_1arg_fn_t *i_fn = (insn_1arg_fn_t *)&p->ainsn.insn[0]; kprobe_opcode_t insn = p->opcode; int rn = (insn >> 16) & 0xf; int lbit = insn & (1 << 20); @@ -476,9 +463,6 @@ static void __kprobes simulate_ldm1stm1(struct kprobe *p, struct pt_regs *regs) int reg_bit_vector; int reg_count; - if (!insnslot_1arg_rflags(0, regs->ARM_cpsr, i_fn)) - return; - reg_count = 0; reg_bit_vector = insn & 0xffff; while (reg_bit_vector) { @@ -510,11 +494,6 @@ static void __kprobes simulate_ldm1stm1(struct kprobe *p, struct pt_regs *regs) static void __kprobes simulate_stm1_pc(struct kprobe *p, struct pt_regs *regs) { - insn_1arg_fn_t *i_fn = (insn_1arg_fn_t *)&p->ainsn.insn[0]; - - if (!insnslot_1arg_rflags(0, regs->ARM_cpsr, i_fn)) - return; - regs->ARM_pc = (long)p->addr + str_pc_offset; simulate_ldm1stm1(p, regs); regs->ARM_pc = (long)p->addr + 4; @@ -1056,9 +1035,8 @@ space_cccc_000x(kprobe_opcode_t insn, struct arch_specific_insn *asi) /* BLX(2) : cccc 0001 0010 xxxx xxxx xxxx 0011 xxxx */ /* BX : cccc 0001 0010 xxxx xxxx xxxx 0001 xxxx */ if ((insn & 0x0ff000d0) == 0x01200010) { - asi->insn[0] = truecc_insn(insn); asi->insn_handler = simulate_blx2bx; - return INSN_GOOD; + return INSN_GOOD_NO_SLOT; } /* CLZ : cccc 0001 0110 xxxx xxxx xxxx 0001 xxxx */ @@ -1333,10 +1311,9 @@ space_cccc_100x(kprobe_opcode_t insn, struct arch_specific_insn *asi) /* LDM(1) : cccc 100x x0x1 xxxx xxxx xxxx xxxx xxxx */ /* STM(1) : cccc 100x x0x0 xxxx xxxx xxxx xxxx xxxx */ - asi->insn[0] = truecc_insn(insn); asi->insn_handler = ((insn & 0x108000) == 0x008000) ? /* STM & R15 */ simulate_stm1_pc : simulate_ldm1stm1; - return INSN_GOOD; + return INSN_GOOD_NO_SLOT; } static enum kprobe_insn __kprobes @@ -1344,9 +1321,8 @@ space_cccc_101x(kprobe_opcode_t insn, struct arch_specific_insn *asi) { /* B : cccc 1010 xxxx xxxx xxxx xxxx xxxx xxxx */ /* BL : cccc 1011 xxxx xxxx xxxx xxxx xxxx xxxx */ - asi->insn[0] = truecc_insn(insn); asi->insn_handler = simulate_bbl; - return INSN_GOOD; + return INSN_GOOD_NO_SLOT; } static enum kprobe_insn __kprobes -- cgit v0.10.2 From ad111ce46674a473370d302325db8f418ac4fe92 Mon Sep 17 00:00:00 2001 From: Jon Medhurst Date: Wed, 6 Apr 2011 11:17:11 +0100 Subject: ARM: kprobes: Fix emulation of CMP, CMN, TST and TEQ instructions. Probing these instructions was corrupting R0 because the emulation code didn't account for the fact that they don't write a result to a register. Signed-off-by: Jon Medhurst Signed-off-by: Nicolas Pitre diff --git a/arch/arm/kernel/kprobes-decode.c b/arch/arm/kernel/kprobes-decode.c index f52fac0c5..ee29d33 100644 --- a/arch/arm/kernel/kprobes-decode.c +++ b/arch/arm/kernel/kprobes-decode.c @@ -808,6 +808,17 @@ emulate_alu_imm_rwflags(struct kprobe *p, struct pt_regs *regs) } static void __kprobes +emulate_alu_tests_imm(struct kprobe *p, struct pt_regs *regs) +{ + insn_1arg_fn_t *i_fn = (insn_1arg_fn_t *)&p->ainsn.insn[0]; + kprobe_opcode_t insn = p->opcode; + int rn = (insn >> 16) & 0xf; + long rnv = (rn == 15) ? (long)p->addr + 8 : regs->uregs[rn]; + + insnslot_1arg_rwflags(rnv, ®s->ARM_cpsr, i_fn); +} + +static void __kprobes emulate_alu_rflags(struct kprobe *p, struct pt_regs *regs) { insn_3arg_fn_t *i_fn = (insn_3arg_fn_t *)&p->ainsn.insn[0]; @@ -843,6 +854,22 @@ emulate_alu_rwflags(struct kprobe *p, struct pt_regs *regs) insnslot_3arg_rwflags(rnv, rmv, rsv, ®s->ARM_cpsr, i_fn); } +static void __kprobes +emulate_alu_tests(struct kprobe *p, struct pt_regs *regs) +{ + insn_3arg_fn_t *i_fn = (insn_3arg_fn_t *)&p->ainsn.insn[0]; + kprobe_opcode_t insn = p->opcode; + long ppc = (long)p->addr + 8; + int rn = (insn >> 16) & 0xf; + int rs = (insn >> 8) & 0xf; /* rs/rsv may be invalid, don't care. */ + int rm = insn & 0xf; + long rnv = (rn == 15) ? ppc : regs->uregs[rn]; + long rmv = (rm == 15) ? ppc : regs->uregs[rm]; + long rsv = regs->uregs[rs]; + + insnslot_3arg_rwflags(rnv, rmv, rsv, ®s->ARM_cpsr, i_fn); +} + static enum kprobe_insn __kprobes prep_emulate_ldr_str(kprobe_opcode_t insn, struct arch_specific_insn *asi) { @@ -1142,8 +1169,20 @@ space_cccc_000x(kprobe_opcode_t insn, struct arch_specific_insn *asi) insn |= 0x00000200; /* Rs = r2 */ } asi->insn[0] = insn; - asi->insn_handler = (insn & (1 << 20)) ? /* S-bit */ + + if ((insn & 0x0f900000) == 0x01100000) { + /* + * TST : cccc 0001 0001 xxxx xxxx xxxx xxxx xxxx + * TEQ : cccc 0001 0011 xxxx xxxx xxxx xxxx xxxx + * CMP : cccc 0001 0101 xxxx xxxx xxxx xxxx xxxx + * CMN : cccc 0001 0111 xxxx xxxx xxxx xxxx xxxx + */ + asi->insn_handler = emulate_alu_tests; + } else { + /* ALU ops which write to Rd */ + asi->insn_handler = (insn & (1 << 20)) ? /* S-bit */ emulate_alu_rwflags : emulate_alu_rflags; + } return INSN_GOOD; } @@ -1170,8 +1209,20 @@ space_cccc_001x(kprobe_opcode_t insn, struct arch_specific_insn *asi) */ insn &= 0xffff0fff; /* Rd = r0 */ asi->insn[0] = insn; - asi->insn_handler = (insn & (1 << 20)) ? /* S-bit */ + + if ((insn & 0x0f900000) == 0x03100000) { + /* + * TST : cccc 0011 0001 xxxx xxxx xxxx xxxx xxxx + * TEQ : cccc 0011 0011 xxxx xxxx xxxx xxxx xxxx + * CMP : cccc 0011 0101 xxxx xxxx xxxx xxxx xxxx + * CMN : cccc 0011 0111 xxxx xxxx xxxx xxxx xxxx + */ + asi->insn_handler = emulate_alu_tests_imm; + } else { + /* ALU ops which write to Rd */ + asi->insn_handler = (insn & (1 << 20)) ? /* S-bit */ emulate_alu_imm_rwflags : emulate_alu_imm_rflags; + } return INSN_GOOD; } -- cgit v0.10.2 From 896a74e19d0131413a96502429994bc8e6bbbe5a Mon Sep 17 00:00:00 2001 From: Jon Medhurst Date: Wed, 6 Apr 2011 11:17:12 +0100 Subject: ARM: kprobes: Fix emulation of Data-processing (immediate) instructions Emulation of instructions like "ADD rd, rn, #" would result in a corrupted value for rd. Signed-off-by: Jon Medhurst Signed-off-by: Nicolas Pitre diff --git a/arch/arm/kernel/kprobes-decode.c b/arch/arm/kernel/kprobes-decode.c index ee29d33..baf053e 100644 --- a/arch/arm/kernel/kprobes-decode.c +++ b/arch/arm/kernel/kprobes-decode.c @@ -1207,7 +1207,7 @@ space_cccc_001x(kprobe_opcode_t insn, struct arch_specific_insn *asi) * *S (bit 20) updates condition codes * ADC/SBC/RSC reads the C flag */ - insn &= 0xffff0fff; /* Rd = r0 */ + insn &= 0xfff00fff; /* Rn = r0 and Rd = r0 */ asi->insn[0] = insn; if ((insn & 0x0f900000) == 0x03100000) { -- cgit v0.10.2 From 51468ea91efad9c7e6dbae43cd8bdc423ec61709 Mon Sep 17 00:00:00 2001 From: Jon Medhurst Date: Thu, 7 Apr 2011 13:25:15 +0100 Subject: ARM: kprobes: Reject probing MRS instructions which read SPSR We need to reject probing of instructions which read SPSR because we can't handle this as the value in SPSR is lost when the exception handler for the probe breakpoint first runs. This patch also fixes the bitmask for MRS instructions decoding to include checking bits 5-7. Signed-off-by: Jon Medhurst Signed-off-by: Nicolas Pitre diff --git a/arch/arm/kernel/kprobes-decode.c b/arch/arm/kernel/kprobes-decode.c index baf053e..e5bc576 100644 --- a/arch/arm/kernel/kprobes-decode.c +++ b/arch/arm/kernel/kprobes-decode.c @@ -1026,14 +1026,16 @@ space_cccc_000x(kprobe_opcode_t insn, struct arch_specific_insn *asi) /* cccc 0001 0xx0 xxxx xxxx xxxx xxxx xxx0 xxxx */ if ((insn & 0x0f900010) == 0x01000000) { - /* BXJ : cccc 0001 0010 xxxx xxxx xxxx 0010 xxxx */ - /* MSR : cccc 0001 0x10 xxxx xxxx xxxx 0000 xxxx */ + /* BXJ : cccc 0001 0010 xxxx xxxx xxxx 0010 xxxx */ + /* MSR : cccc 0001 0x10 xxxx xxxx xxxx 0000 xxxx */ + /* MRS spsr : cccc 0001 0100 xxxx xxxx xxxx 0000 xxxx */ if ((insn & 0x0ff000f0) == 0x01200020 || - (insn & 0x0fb000f0) == 0x01200000) + (insn & 0x0fb000f0) == 0x01200000 || + (insn & 0x0ff000f0) == 0x01400000) return INSN_REJECTED; - /* MRS : cccc 0001 0x00 xxxx xxxx xxxx 0000 xxxx */ - if ((insn & 0x0fb00010) == 0x01000000) + /* MRS cpsr : cccc 0001 0000 xxxx xxxx xxxx 0000 xxxx */ + if ((insn & 0x0ff000f0) == 0x01000000) return prep_emulate_rd12(insn, asi); /* SMLALxy : cccc 0001 0100 xxxx xxxx xxxx 1xx0 xxxx */ -- cgit v0.10.2 From c412aba2a1243192a4d53736805a96bdda915608 Mon Sep 17 00:00:00 2001 From: Jon Medhurst Date: Thu, 7 Apr 2011 13:25:16 +0100 Subject: ARM: kprobes: Fix emulation of MRS instruction The MRS instruction should set mode and interrupt bits in the read value so it is simpler to use a new simulation routine (simulate_mrs) rather than some modified emulation. prep_emulate_rd12 is now unused and removed. Signed-off-by: Jon Medhurst Signed-off-by: Nicolas Pitre diff --git a/arch/arm/kernel/kprobes-decode.c b/arch/arm/kernel/kprobes-decode.c index e5bc576..4ab83f4 100644 --- a/arch/arm/kernel/kprobes-decode.c +++ b/arch/arm/kernel/kprobes-decode.c @@ -451,6 +451,14 @@ static void __kprobes simulate_blx2bx(struct kprobe *p, struct pt_regs *regs) regs->ARM_cpsr |= PSR_T_BIT; } +static void __kprobes simulate_mrs(struct kprobe *p, struct pt_regs *regs) +{ + kprobe_opcode_t insn = p->opcode; + int rd = (insn >> 12) & 0xf; + unsigned long mask = 0xf8ff03df; /* Mask out execution state */ + regs->uregs[rd] = regs->ARM_cpsr & mask; +} + static void __kprobes simulate_ldm1stm1(struct kprobe *p, struct pt_regs *regs) { kprobe_opcode_t insn = p->opcode; @@ -896,15 +904,6 @@ prep_emulate_rd12rm0(kprobe_opcode_t insn, struct arch_specific_insn *asi) } static enum kprobe_insn __kprobes -prep_emulate_rd12(kprobe_opcode_t insn, struct arch_specific_insn *asi) -{ - insn &= 0xffff0fff; /* Rd = r0 */ - asi->insn[0] = insn; - asi->insn_handler = emulate_rd12; - return INSN_GOOD; -} - -static enum kprobe_insn __kprobes prep_emulate_rd12rn16rm0_wflags(kprobe_opcode_t insn, struct arch_specific_insn *asi) { @@ -1035,8 +1034,10 @@ space_cccc_000x(kprobe_opcode_t insn, struct arch_specific_insn *asi) return INSN_REJECTED; /* MRS cpsr : cccc 0001 0000 xxxx xxxx xxxx 0000 xxxx */ - if ((insn & 0x0ff000f0) == 0x01000000) - return prep_emulate_rd12(insn, asi); + if ((insn & 0x0ff000f0) == 0x01000000) { + asi->insn_handler = simulate_mrs; + return INSN_GOOD_NO_SLOT; + } /* SMLALxy : cccc 0001 0100 xxxx xxxx xxxx 1xx0 xxxx */ if ((insn & 0x0ff00090) == 0x01400080) -- cgit v0.10.2 From 983ebd9365096c3386f6ed0978333e15f66024f5 Mon Sep 17 00:00:00 2001 From: Jon Medhurst Date: Thu, 7 Apr 2011 13:25:17 +0100 Subject: ARM: kprobes: Reject probing of instructions which write to PC unpredictably. Signed-off-by: Jon Medhurst Signed-off-by: Nicolas Pitre diff --git a/arch/arm/kernel/kprobes-decode.c b/arch/arm/kernel/kprobes-decode.c index 4ab83f4..6d09db9 100644 --- a/arch/arm/kernel/kprobes-decode.c +++ b/arch/arm/kernel/kprobes-decode.c @@ -68,6 +68,8 @@ #define branch_displacement(insn) sign_extend(((insn) & 0xffffff) << 2, 25) +#define is_r15(insn, bitpos) (((insn) & (0xf << bitpos)) == (0xf << bitpos)) + #define PSR_fs (PSR_f|PSR_s) #define KPROBE_RETURN_INSTRUCTION 0xe1a0f00e /* mov pc, lr */ @@ -897,6 +899,9 @@ prep_emulate_ldr_str(kprobe_opcode_t insn, struct arch_specific_insn *asi) static enum kprobe_insn __kprobes prep_emulate_rd12rm0(kprobe_opcode_t insn, struct arch_specific_insn *asi) { + if (is_r15(insn, 12)) + return INSN_REJECTED; /* Rd is PC */ + insn &= 0xffff0ff0; /* Rd = r0, Rm = r0 */ asi->insn[0] = insn; asi->insn_handler = emulate_rd12rm0; @@ -907,6 +912,9 @@ static enum kprobe_insn __kprobes prep_emulate_rd12rn16rm0_wflags(kprobe_opcode_t insn, struct arch_specific_insn *asi) { + if (is_r15(insn, 12)) + return INSN_REJECTED; /* Rd is PC */ + insn &= 0xfff00ff0; /* Rd = r0, Rn = r0 */ insn |= 0x00000001; /* Rm = r1 */ asi->insn[0] = insn; @@ -918,6 +926,9 @@ static enum kprobe_insn __kprobes prep_emulate_rd16rs8rm0_wflags(kprobe_opcode_t insn, struct arch_specific_insn *asi) { + if (is_r15(insn, 16)) + return INSN_REJECTED; /* Rd is PC */ + insn &= 0xfff0f0f0; /* Rd = r0, Rs = r0 */ insn |= 0x00000001; /* Rm = r1 */ asi->insn[0] = insn; @@ -929,6 +940,9 @@ static enum kprobe_insn __kprobes prep_emulate_rd16rn12rs8rm0_wflags(kprobe_opcode_t insn, struct arch_specific_insn *asi) { + if (is_r15(insn, 16)) + return INSN_REJECTED; /* Rd is PC */ + insn &= 0xfff000f0; /* Rd = r0, Rn = r0 */ insn |= 0x00000102; /* Rs = r1, Rm = r2 */ asi->insn[0] = insn; @@ -940,6 +954,9 @@ static enum kprobe_insn __kprobes prep_emulate_rdhi16rdlo12rs8rm0_wflags(kprobe_opcode_t insn, struct arch_specific_insn *asi) { + if (is_r15(insn, 16) || is_r15(insn, 12)) + return INSN_REJECTED; /* RdHi or RdLo is PC */ + insn &= 0xfff000f0; /* RdHi = r0, RdLo = r1 */ insn |= 0x00001203; /* Rs = r2, Rm = r3 */ asi->insn[0] = insn; @@ -1035,6 +1052,8 @@ space_cccc_000x(kprobe_opcode_t insn, struct arch_specific_insn *asi) /* MRS cpsr : cccc 0001 0000 xxxx xxxx xxxx 0000 xxxx */ if ((insn & 0x0ff000f0) == 0x01000000) { + if (is_r15(insn, 12)) + return INSN_REJECTED; /* Rd is PC */ asi->insn_handler = simulate_mrs; return INSN_GOOD_NO_SLOT; } @@ -1065,6 +1084,8 @@ space_cccc_000x(kprobe_opcode_t insn, struct arch_specific_insn *asi) /* BLX(2) : cccc 0001 0010 xxxx xxxx xxxx 0011 xxxx */ /* BX : cccc 0001 0010 xxxx xxxx xxxx 0001 xxxx */ if ((insn & 0x0ff000d0) == 0x01200010) { + if ((insn & 0x0ff000ff) == 0x0120003f) + return INSN_REJECTED; /* BLX pc */ asi->insn_handler = simulate_blx2bx; return INSN_GOOD_NO_SLOT; } @@ -1234,6 +1255,8 @@ space_cccc_0110__1(kprobe_opcode_t insn, struct arch_specific_insn *asi) { /* SEL : cccc 0110 1000 xxxx xxxx xxxx 1011 xxxx GE: !!! */ if ((insn & 0x0ff000f0) == 0x068000b0) { + if (is_r15(insn, 12)) + return INSN_REJECTED; /* Rd is PC */ insn &= 0xfff00ff0; /* Rd = r0, Rn = r0 */ insn |= 0x00000001; /* Rm = r1 */ asi->insn[0] = insn; @@ -1247,6 +1270,8 @@ space_cccc_0110__1(kprobe_opcode_t insn, struct arch_specific_insn *asi) /* USAT16 : cccc 0110 1110 xxxx xxxx xxxx 0011 xxxx :Q */ if ((insn & 0x0fa00030) == 0x06a00010 || (insn & 0x0fb000f0) == 0x06a00030) { + if (is_r15(insn, 12)) + return INSN_REJECTED; /* Rd is PC */ insn &= 0xffff0ff0; /* Rd = r0, Rm = r0 */ asi->insn[0] = insn; asi->insn_handler = emulate_sat; @@ -1384,6 +1409,9 @@ space_cccc_1100_010x(kprobe_opcode_t insn, struct arch_specific_insn *asi) { /* MCRR : cccc 1100 0100 xxxx xxxx xxxx xxxx xxxx : (Rd!=Rn) */ /* MRRC : cccc 1100 0101 xxxx xxxx xxxx xxxx xxxx : (Rd!=Rn) */ + if (is_r15(insn, 16) || is_r15(insn, 12)) + return INSN_REJECTED; /* Rn or Rd is PC */ + insn &= 0xfff00fff; insn |= 0x00001000; /* Rn = r0, Rd = r1 */ asi->insn[0] = insn; -- cgit v0.10.2 From 75539aea4cb96823171cabac7391f1a26fbf9c1b Mon Sep 17 00:00:00 2001 From: Jon Medhurst Date: Thu, 7 Apr 2011 13:25:18 +0100 Subject: ARM: kprobes: Fix error in comment Signed-off-by: Jon Medhurst Signed-off-by: Nicolas Pitre diff --git a/arch/arm/kernel/kprobes-decode.c b/arch/arm/kernel/kprobes-decode.c index 6d09db9..54c1759 100644 --- a/arch/arm/kernel/kprobes-decode.c +++ b/arch/arm/kernel/kprobes-decode.c @@ -1069,7 +1069,7 @@ space_cccc_000x(kprobe_opcode_t insn, struct arch_specific_insn *asi) return prep_emulate_rd16rs8rm0_wflags(insn, asi); /* SMLAxy : cccc 0001 0000 xxxx xxxx xxxx 1xx0 xxxx : Q */ - /* SMLAWy : cccc 0001 0010 xxxx xxxx xxxx 0x00 xxxx : Q */ + /* SMLAWy : cccc 0001 0010 xxxx xxxx xxxx 1x00 xxxx : Q */ return prep_emulate_rd16rn12rs8rm0_wflags(insn, asi); } -- cgit v0.10.2 From ba48d40713ae5afe758dd5525a0f8740cce71d22 Mon Sep 17 00:00:00 2001 From: Jon Medhurst Date: Thu, 7 Apr 2011 13:25:19 +0100 Subject: ARM: kprobes: Reject probing of undefined multiply instructions The instructions space for 'Multiply and multiply-accumulate' instructions contains some undefined patterns. We need to reject probing of these because they may in future become defined and the kprobes code may then emulate them faultily. This has already happened with the new MLS instruction which this patch also adds correct decoding for as well as tightening up other decoding tests. (Before this patch the wrong emulation routine was being called for MLS though it still produced correct results.) Signed-off-by: Jon Medhurst Signed-off-by: Nicolas Pitre diff --git a/arch/arm/kernel/kprobes-decode.c b/arch/arm/kernel/kprobes-decode.c index 54c1759..8f3f03e 100644 --- a/arch/arm/kernel/kprobes-decode.c +++ b/arch/arm/kernel/kprobes-decode.c @@ -1102,13 +1102,16 @@ space_cccc_000x(kprobe_opcode_t insn, struct arch_specific_insn *asi) } /* cccc 0000 xxxx xxxx xxxx xxxx xxxx 1001 xxxx */ - else if ((insn & 0x0f000090) == 0x00000090) { + else if ((insn & 0x0f0000f0) == 0x00000090) { /* MUL : cccc 0000 0000 xxxx xxxx xxxx 1001 xxxx : */ /* MULS : cccc 0000 0001 xxxx xxxx xxxx 1001 xxxx :cc */ /* MLA : cccc 0000 0010 xxxx xxxx xxxx 1001 xxxx : */ /* MLAS : cccc 0000 0011 xxxx xxxx xxxx 1001 xxxx :cc */ /* UMAAL : cccc 0000 0100 xxxx xxxx xxxx 1001 xxxx : */ + /* undef : cccc 0000 0101 xxxx xxxx xxxx 1001 xxxx : */ + /* MLS : cccc 0000 0110 xxxx xxxx xxxx 1001 xxxx : */ + /* undef : cccc 0000 0111 xxxx xxxx xxxx 1001 xxxx : */ /* UMULL : cccc 0000 1000 xxxx xxxx xxxx 1001 xxxx : */ /* UMULLS : cccc 0000 1001 xxxx xxxx xxxx 1001 xxxx :cc */ /* UMLAL : cccc 0000 1010 xxxx xxxx xxxx 1001 xxxx : */ @@ -1117,9 +1120,11 @@ space_cccc_000x(kprobe_opcode_t insn, struct arch_specific_insn *asi) /* SMULLS : cccc 0000 1101 xxxx xxxx xxxx 1001 xxxx :cc */ /* SMLAL : cccc 0000 1110 xxxx xxxx xxxx 1001 xxxx : */ /* SMLALS : cccc 0000 1111 xxxx xxxx xxxx 1001 xxxx :cc */ - if ((insn & 0x0fe000f0) == 0x00000090) { + if ((insn & 0x00d00000) == 0x00500000) { + return INSN_REJECTED; + } else if ((insn & 0x00e00000) == 0x00000000) { return prep_emulate_rd16rs8rm0_wflags(insn, asi); - } else if ((insn & 0x0fe000f0) == 0x00200090) { + } else if ((insn & 0x00a00000) == 0x00200000) { return prep_emulate_rd16rn12rs8rm0_wflags(insn, asi); } else { return prep_emulate_rdhi16rdlo12rs8rm0_wflags(insn, asi); -- cgit v0.10.2 From ec58d7f2373cec47f30b773d40a89f18bf6fc489 Mon Sep 17 00:00:00 2001 From: Jon Medhurst Date: Fri, 8 Apr 2011 15:32:53 +0100 Subject: ARM: kprobes: Reject probing of STREX and LDREX instructions The emulation code for STREX and LDREX instructions is faulty, however, rather than attempting to fix this we reject probes of these instructions. We do this because they can never succeed in gaining exclusive access as the exception framework clears the exclusivity monitor when a probes breakpoint is hit. (This is a general problem when probing all instructions executing between a LDREX and its corresponding STREX and can lead to infinite retry loops.) Signed-off-by: Jon Medhurst Signed-off-by: Nicolas Pitre diff --git a/arch/arm/kernel/kprobes-decode.c b/arch/arm/kernel/kprobes-decode.c index 8f3f03e..c24e21e 100644 --- a/arch/arm/kernel/kprobes-decode.c +++ b/arch/arm/kernel/kprobes-decode.c @@ -1136,17 +1136,34 @@ space_cccc_000x(kprobe_opcode_t insn, struct arch_specific_insn *asi) /* SWP : cccc 0001 0000 xxxx xxxx xxxx 1001 xxxx */ /* SWPB : cccc 0001 0100 xxxx xxxx xxxx 1001 xxxx */ - /* LDRD : cccc 000x xxx0 xxxx xxxx xxxx 1101 xxxx */ - /* STRD : cccc 000x xxx0 xxxx xxxx xxxx 1111 xxxx */ + /* ??? : cccc 0001 0x01 xxxx xxxx xxxx 1001 xxxx */ + /* ??? : cccc 0001 0x10 xxxx xxxx xxxx 1001 xxxx */ + /* ??? : cccc 0001 0x11 xxxx xxxx xxxx 1001 xxxx */ /* STREX : cccc 0001 1000 xxxx xxxx xxxx 1001 xxxx */ /* LDREX : cccc 0001 1001 xxxx xxxx xxxx 1001 xxxx */ + /* STREXD: cccc 0001 1010 xxxx xxxx xxxx 1001 xxxx */ + /* LDREXD: cccc 0001 1011 xxxx xxxx xxxx 1001 xxxx */ + /* STREXB: cccc 0001 1100 xxxx xxxx xxxx 1001 xxxx */ + /* LDREXB: cccc 0001 1101 xxxx xxxx xxxx 1001 xxxx */ + /* STREXH: cccc 0001 1110 xxxx xxxx xxxx 1001 xxxx */ + /* LDREXH: cccc 0001 1111 xxxx xxxx xxxx 1001 xxxx */ + + /* LDRD : cccc 000x xxx0 xxxx xxxx xxxx 1101 xxxx */ + /* STRD : cccc 000x xxx0 xxxx xxxx xxxx 1111 xxxx */ /* LDRH : cccc 000x xxx1 xxxx xxxx xxxx 1011 xxxx */ /* STRH : cccc 000x xxx0 xxxx xxxx xxxx 1011 xxxx */ /* LDRSB : cccc 000x xxx1 xxxx xxxx xxxx 1101 xxxx */ /* LDRSH : cccc 000x xxx1 xxxx xxxx xxxx 1111 xxxx */ - if ((insn & 0x0fb000f0) == 0x01000090) { - /* SWP/SWPB */ - return prep_emulate_rd12rn16rm0_wflags(insn, asi); + if ((insn & 0x0f0000f0) == 0x01000090) { + if ((insn & 0x0fb000f0) == 0x01000090) { + /* SWP/SWPB */ + return prep_emulate_rd12rn16rm0_wflags(insn, + asi); + } else { + /* STREX/LDREX variants and unallocaed space */ + return INSN_REJECTED; + } + } else if ((insn & 0x0e1000d0) == 0x00000d0) { /* STRD/LDRD */ insn &= 0xfff00fff; -- cgit v0.10.2 From 6823fc85fcfba11675f2027aadf2d5291c6f351b Mon Sep 17 00:00:00 2001 From: Jon Medhurst Date: Fri, 8 Apr 2011 15:32:54 +0100 Subject: ARM: kprobes: Fix emulation of LDRH, STRH, LDRSB and LDRSH instructions The decoding of these instructions got the register indexed and immediate indexed forms the wrong way around, causing incorrect emulation. Signed-off-by: Jon Medhurst Signed-off-by: Nicolas Pitre diff --git a/arch/arm/kernel/kprobes-decode.c b/arch/arm/kernel/kprobes-decode.c index c24e21e..348ff47 100644 --- a/arch/arm/kernel/kprobes-decode.c +++ b/arch/arm/kernel/kprobes-decode.c @@ -883,11 +883,12 @@ emulate_alu_tests(struct kprobe *p, struct pt_regs *regs) static enum kprobe_insn __kprobes prep_emulate_ldr_str(kprobe_opcode_t insn, struct arch_specific_insn *asi) { - int ibit = (insn & (1 << 26)) ? 25 : 22; + int not_imm = (insn & (1 << 26)) ? (insn & (1 << 25)) + : (~insn & (1 << 22)); insn &= 0xfff00fff; insn |= 0x00001000; /* Rn = r0, Rd = r1 */ - if (insn & (1 << ibit)) { + if (not_imm) { insn &= ~0xf; insn |= 2; /* Rm = r2 */ } -- cgit v0.10.2 From 54823accfcfc715e9e757a621afb40dabc01d033 Mon Sep 17 00:00:00 2001 From: Jon Medhurst Date: Fri, 8 Apr 2011 15:32:55 +0100 Subject: ARM: kprobes: Reject probing of LDR/STR instructions which update PC unpredictably Using PC as an base register with writeback is UNPREDICTABLE, as is non word-sized loads or stores of PC. (We only really care about preventing loads to PC but it keeps the code simpler if we also exclude stores.) Signed-off-by: Jon Medhurst Signed-off-by: Nicolas Pitre diff --git a/arch/arm/kernel/kprobes-decode.c b/arch/arm/kernel/kprobes-decode.c index 348ff47..a4dba1f 100644 --- a/arch/arm/kernel/kprobes-decode.c +++ b/arch/arm/kernel/kprobes-decode.c @@ -70,6 +70,12 @@ #define is_r15(insn, bitpos) (((insn) & (0xf << bitpos)) == (0xf << bitpos)) +/* + * Test if load/store instructions writeback the address register. + * if P (bit 24) == 0 or W (bit 21) == 1 + */ +#define is_writeback(insn) ((insn ^ 0x01000000) & 0x01200000) + #define PSR_fs (PSR_f|PSR_s) #define KPROBE_RETURN_INSTRUCTION 0xe1a0f00e /* mov pc, lr */ @@ -886,6 +892,9 @@ prep_emulate_ldr_str(kprobe_opcode_t insn, struct arch_specific_insn *asi) int not_imm = (insn & (1 << 26)) ? (insn & (1 << 25)) : (~insn & (1 << 22)); + if (is_writeback(insn) && is_r15(insn, 16)) + return INSN_REJECTED; /* Writeback to PC */ + insn &= 0xfff00fff; insn |= 0x00001000; /* Rn = r0, Rd = r1 */ if (not_imm) { @@ -1167,6 +1176,11 @@ space_cccc_000x(kprobe_opcode_t insn, struct arch_specific_insn *asi) } else if ((insn & 0x0e1000d0) == 0x00000d0) { /* STRD/LDRD */ + if ((insn & 0x0000e000) == 0x0000e000) + return INSN_REJECTED; /* Rd is LR or PC */ + if (is_writeback(insn) && is_r15(insn, 16)) + return INSN_REJECTED; /* Writeback to PC */ + insn &= 0xfff00fff; insn |= 0x00002000; /* Rn = r0, Rd = r2 */ if (insn & (1 << 22)) { @@ -1180,6 +1194,9 @@ space_cccc_000x(kprobe_opcode_t insn, struct arch_specific_insn *asi) return INSN_GOOD; } + /* LDRH/STRH/LDRSB/LDRSH */ + if (is_r15(insn, 12)) + return INSN_REJECTED; /* Rd is PC */ return prep_emulate_ldr_str(insn, asi); } -- cgit v0.10.2 From 5c6b76fc7d8220e8f00e7a49fb56ca852d7fb661 Mon Sep 17 00:00:00 2001 From: Jon Medhurst Date: Fri, 8 Apr 2011 15:32:56 +0100 Subject: ARM: kprobes: Fix emulation of LDRD and STRD instructions The decoding of these instructions got the register indexed and immediate indexed forms the wrong way around, causing incorrect emulation. Instructions like "LDRD Rx, [Rx]" were corrupting Rx because the base register writeback was being performed unconditionally, overwriting the value just loaded from memory. The fix is to only writeback the base register when that form of the instruction is used. Note, now that we reject probing writeback with PC the emulation code doesn't need the check rn!=15. Signed-off-by: Jon Medhurst Signed-off-by: Nicolas Pitre diff --git a/arch/arm/kernel/kprobes-decode.c b/arch/arm/kernel/kprobes-decode.c index a4dba1f..826abc1 100644 --- a/arch/arm/kernel/kprobes-decode.c +++ b/arch/arm/kernel/kprobes-decode.c @@ -560,8 +560,8 @@ static void __kprobes emulate_ldrd(struct kprobe *p, struct pt_regs *regs) [i_fn] "r" (i_fn) : "r0", "r1", "r2", "r3", "lr", "cc" ); - if (rn != 15) - regs->uregs[rn] = rnv; /* Save Rn in case of writeback. */ + if (is_writeback(insn)) + regs->uregs[rn] = rnv; } static void __kprobes emulate_strd(struct kprobe *p, struct pt_regs *regs) @@ -580,8 +580,8 @@ static void __kprobes emulate_strd(struct kprobe *p, struct pt_regs *regs) rnv_wb = insnslot_4arg_rflags(rnv, rmv, regs->uregs[rd], regs->uregs[rd+1], regs->ARM_cpsr, i_fn); - if (rn != 15) - regs->uregs[rn] = rnv_wb; /* Save Rn in case of writeback. */ + if (is_writeback(insn)) + regs->uregs[rn] = rnv_wb; } static void __kprobes emulate_ldr(struct kprobe *p, struct pt_regs *regs) @@ -1183,8 +1183,8 @@ space_cccc_000x(kprobe_opcode_t insn, struct arch_specific_insn *asi) insn &= 0xfff00fff; insn |= 0x00002000; /* Rn = r0, Rd = r2 */ - if (insn & (1 << 22)) { - /* I bit */ + if (!(insn & (1 << 22))) { + /* Register index */ insn &= ~0xf; insn |= 1; /* Rm = r1 */ } -- cgit v0.10.2 From 81ff5720b9561b48e3dc640ca15799ba3919f5a6 Mon Sep 17 00:00:00 2001 From: Jon Medhurst Date: Tue, 12 Apr 2011 07:45:21 +0100 Subject: ARM: kprobes: Reject probing of LDRB instructions which load PC These instructions are specified as UNPREDICTABLE. Signed-off-by: Jon Medhurst Signed-off-by: Nicolas Pitre diff --git a/arch/arm/kernel/kprobes-decode.c b/arch/arm/kernel/kprobes-decode.c index 826abc1..a37745f 100644 --- a/arch/arm/kernel/kprobes-decode.c +++ b/arch/arm/kernel/kprobes-decode.c @@ -1416,6 +1416,10 @@ space_cccc_01xx(kprobe_opcode_t insn, struct arch_specific_insn *asi) /* STRB : cccc 01xx x1x0 xxxx xxxx xxxx xxxx xxxx */ /* STRBT : cccc 01x0 x110 xxxx xxxx xxxx xxxx xxxx */ /* STRT : cccc 01x0 x010 xxxx xxxx xxxx xxxx xxxx */ + + if ((insn & 0x00500000) == 0x00500000 && is_r15(insn, 12)) + return INSN_REJECTED; /* LDRB into PC */ + return prep_emulate_ldr_str(insn, asi); } -- cgit v0.10.2 From 0e384ed164bdc2ad832270e81dbd14a17c143e78 Mon Sep 17 00:00:00 2001 From: Jon Medhurst Date: Tue, 12 Apr 2011 07:45:22 +0100 Subject: ARM: kprobes: Add emulation of RBIT instruction The v6T2 RBIT instruction was accidentally being emulated correctly, this patch adds correct decoding for the instruction. Signed-off-by: Jon Medhurst Signed-off-by: Nicolas Pitre diff --git a/arch/arm/kernel/kprobes-decode.c b/arch/arm/kernel/kprobes-decode.c index a37745f..b6bbc0b 100644 --- a/arch/arm/kernel/kprobes-decode.c +++ b/arch/arm/kernel/kprobes-decode.c @@ -1320,9 +1320,10 @@ space_cccc_0110__1(kprobe_opcode_t insn, struct arch_specific_insn *asi) /* REV : cccc 0110 1011 xxxx xxxx xxxx 0011 xxxx */ /* REV16 : cccc 0110 1011 xxxx xxxx xxxx 1011 xxxx */ + /* RBIT : cccc 0110 1111 xxxx xxxx xxxx 0011 xxxx */ /* REVSH : cccc 0110 1111 xxxx xxxx xxxx 1011 xxxx */ if ((insn & 0x0ff00070) == 0x06b00030 || - (insn & 0x0ff000f0) == 0x06f000b0) + (insn & 0x0ff00070) == 0x06f00030) return prep_emulate_rd12rm0(insn, asi); /* SADD16 : cccc 0110 0001 xxxx xxxx xxxx 0001 xxxx :GE */ -- cgit v0.10.2 From 780b5c1162286cc75ef2dcc0f14215d9f9f06230 Mon Sep 17 00:00:00 2001 From: Jon Medhurst Date: Tue, 12 Apr 2011 07:45:23 +0100 Subject: ARM: kprobes: Reject probing of undefined media instructions The instructions space for media instructions contains some undefined patterns. We need to reject probing of these because they may in future become defined and the kprobes code may then emulate them faultily. Signed-off-by: Jon Medhurst Signed-off-by: Nicolas Pitre diff --git a/arch/arm/kernel/kprobes-decode.c b/arch/arm/kernel/kprobes-decode.c index b6bbc0b..f0ca7f4 100644 --- a/arch/arm/kernel/kprobes-decode.c +++ b/arch/arm/kernel/kprobes-decode.c @@ -1326,52 +1326,86 @@ space_cccc_0110__1(kprobe_opcode_t insn, struct arch_specific_insn *asi) (insn & 0x0ff00070) == 0x06f00030) return prep_emulate_rd12rm0(insn, asi); + /* ??? : cccc 0110 0000 xxxx xxxx xxxx xxx1 xxxx : */ /* SADD16 : cccc 0110 0001 xxxx xxxx xxxx 0001 xxxx :GE */ /* SADDSUBX : cccc 0110 0001 xxxx xxxx xxxx 0011 xxxx :GE */ /* SSUBADDX : cccc 0110 0001 xxxx xxxx xxxx 0101 xxxx :GE */ /* SSUB16 : cccc 0110 0001 xxxx xxxx xxxx 0111 xxxx :GE */ /* SADD8 : cccc 0110 0001 xxxx xxxx xxxx 1001 xxxx :GE */ + /* ??? : cccc 0110 0001 xxxx xxxx xxxx 1011 xxxx : */ + /* ??? : cccc 0110 0001 xxxx xxxx xxxx 1101 xxxx : */ /* SSUB8 : cccc 0110 0001 xxxx xxxx xxxx 1111 xxxx :GE */ /* QADD16 : cccc 0110 0010 xxxx xxxx xxxx 0001 xxxx : */ /* QADDSUBX : cccc 0110 0010 xxxx xxxx xxxx 0011 xxxx : */ /* QSUBADDX : cccc 0110 0010 xxxx xxxx xxxx 0101 xxxx : */ /* QSUB16 : cccc 0110 0010 xxxx xxxx xxxx 0111 xxxx : */ /* QADD8 : cccc 0110 0010 xxxx xxxx xxxx 1001 xxxx : */ + /* ??? : cccc 0110 0010 xxxx xxxx xxxx 1011 xxxx : */ + /* ??? : cccc 0110 0010 xxxx xxxx xxxx 1101 xxxx : */ /* QSUB8 : cccc 0110 0010 xxxx xxxx xxxx 1111 xxxx : */ /* SHADD16 : cccc 0110 0011 xxxx xxxx xxxx 0001 xxxx : */ /* SHADDSUBX : cccc 0110 0011 xxxx xxxx xxxx 0011 xxxx : */ /* SHSUBADDX : cccc 0110 0011 xxxx xxxx xxxx 0101 xxxx : */ /* SHSUB16 : cccc 0110 0011 xxxx xxxx xxxx 0111 xxxx : */ /* SHADD8 : cccc 0110 0011 xxxx xxxx xxxx 1001 xxxx : */ + /* ??? : cccc 0110 0011 xxxx xxxx xxxx 1011 xxxx : */ + /* ??? : cccc 0110 0011 xxxx xxxx xxxx 1101 xxxx : */ /* SHSUB8 : cccc 0110 0011 xxxx xxxx xxxx 1111 xxxx : */ + /* ??? : cccc 0110 0100 xxxx xxxx xxxx xxx1 xxxx : */ /* UADD16 : cccc 0110 0101 xxxx xxxx xxxx 0001 xxxx :GE */ /* UADDSUBX : cccc 0110 0101 xxxx xxxx xxxx 0011 xxxx :GE */ /* USUBADDX : cccc 0110 0101 xxxx xxxx xxxx 0101 xxxx :GE */ /* USUB16 : cccc 0110 0101 xxxx xxxx xxxx 0111 xxxx :GE */ /* UADD8 : cccc 0110 0101 xxxx xxxx xxxx 1001 xxxx :GE */ + /* ??? : cccc 0110 0101 xxxx xxxx xxxx 1011 xxxx : */ + /* ??? : cccc 0110 0101 xxxx xxxx xxxx 1101 xxxx : */ /* USUB8 : cccc 0110 0101 xxxx xxxx xxxx 1111 xxxx :GE */ /* UQADD16 : cccc 0110 0110 xxxx xxxx xxxx 0001 xxxx : */ /* UQADDSUBX : cccc 0110 0110 xxxx xxxx xxxx 0011 xxxx : */ /* UQSUBADDX : cccc 0110 0110 xxxx xxxx xxxx 0101 xxxx : */ /* UQSUB16 : cccc 0110 0110 xxxx xxxx xxxx 0111 xxxx : */ /* UQADD8 : cccc 0110 0110 xxxx xxxx xxxx 1001 xxxx : */ + /* ??? : cccc 0110 0110 xxxx xxxx xxxx 1011 xxxx : */ + /* ??? : cccc 0110 0110 xxxx xxxx xxxx 1101 xxxx : */ /* UQSUB8 : cccc 0110 0110 xxxx xxxx xxxx 1111 xxxx : */ /* UHADD16 : cccc 0110 0111 xxxx xxxx xxxx 0001 xxxx : */ /* UHADDSUBX : cccc 0110 0111 xxxx xxxx xxxx 0011 xxxx : */ /* UHSUBADDX : cccc 0110 0111 xxxx xxxx xxxx 0101 xxxx : */ /* UHSUB16 : cccc 0110 0111 xxxx xxxx xxxx 0111 xxxx : */ /* UHADD8 : cccc 0110 0111 xxxx xxxx xxxx 1001 xxxx : */ + /* ??? : cccc 0110 0111 xxxx xxxx xxxx 1011 xxxx : */ + /* ??? : cccc 0110 0111 xxxx xxxx xxxx 1101 xxxx : */ /* UHSUB8 : cccc 0110 0111 xxxx xxxx xxxx 1111 xxxx : */ + if ((insn & 0x0f800010) == 0x06000010) { + if ((insn & 0x00300000) == 0x00000000 || + (insn & 0x000000e0) == 0x000000a0 || + (insn & 0x000000e0) == 0x000000c0) + return INSN_REJECTED; /* Unallocated space */ + return prep_emulate_rd12rn16rm0_wflags(insn, asi); + } + /* PKHBT : cccc 0110 1000 xxxx xxxx xxxx x001 xxxx : */ /* PKHTB : cccc 0110 1000 xxxx xxxx xxxx x101 xxxx : */ + if ((insn & 0x0ff00030) == 0x06800010) + return prep_emulate_rd12rn16rm0_wflags(insn, asi); + /* SXTAB16 : cccc 0110 1000 xxxx xxxx xxxx 0111 xxxx : */ /* SXTB : cccc 0110 1010 xxxx xxxx xxxx 0111 xxxx : */ + /* ??? : cccc 0110 1001 xxxx xxxx xxxx 0111 xxxx : */ /* SXTAB : cccc 0110 1010 xxxx xxxx xxxx 0111 xxxx : */ /* SXTAH : cccc 0110 1011 xxxx xxxx xxxx 0111 xxxx : */ /* UXTAB16 : cccc 0110 1100 xxxx xxxx xxxx 0111 xxxx : */ + /* ??? : cccc 0110 1101 xxxx xxxx xxxx 0111 xxxx : */ /* UXTAB : cccc 0110 1110 xxxx xxxx xxxx 0111 xxxx : */ /* UXTAH : cccc 0110 1111 xxxx xxxx xxxx 0111 xxxx : */ - return prep_emulate_rd12rn16rm0_wflags(insn, asi); + if ((insn & 0x0f8000f0) == 0x06800070) { + if ((insn & 0x00300000) == 0x00100000) + return INSN_REJECTED; /* Unallocated space */ + return prep_emulate_rd12rn16rm0_wflags(insn, asi); + } + + /* Other instruction encodings aren't yet defined */ + return INSN_REJECTED; } static enum kprobe_insn __kprobes -- cgit v0.10.2 From 8dd7cfbed83c74b1fb991fae264944e041e22e62 Mon Sep 17 00:00:00 2001 From: Jon Medhurst Date: Tue, 12 Apr 2011 07:45:24 +0100 Subject: ARM: kprobes: Fix emulation of SXTB16, SXTB, SXTH, UXTB16, UXTB and UXTH instructions These sign extension instructions are encoded as extend-and-add instructions where the register to add is specified as r15. The decoding routines weren't checking for this and were using the incorrect emulation code, giving incorrect results. Signed-off-by: Jon Medhurst Signed-off-by: Nicolas Pitre diff --git a/arch/arm/kernel/kprobes-decode.c b/arch/arm/kernel/kprobes-decode.c index f0ca7f4..1e413a9 100644 --- a/arch/arm/kernel/kprobes-decode.c +++ b/arch/arm/kernel/kprobes-decode.c @@ -1390,18 +1390,28 @@ space_cccc_0110__1(kprobe_opcode_t insn, struct arch_specific_insn *asi) return prep_emulate_rd12rn16rm0_wflags(insn, asi); /* SXTAB16 : cccc 0110 1000 xxxx xxxx xxxx 0111 xxxx : */ - /* SXTB : cccc 0110 1010 xxxx xxxx xxxx 0111 xxxx : */ + /* SXTB16 : cccc 0110 1000 1111 xxxx xxxx 0111 xxxx : */ /* ??? : cccc 0110 1001 xxxx xxxx xxxx 0111 xxxx : */ /* SXTAB : cccc 0110 1010 xxxx xxxx xxxx 0111 xxxx : */ + /* SXTB : cccc 0110 1010 1111 xxxx xxxx 0111 xxxx : */ /* SXTAH : cccc 0110 1011 xxxx xxxx xxxx 0111 xxxx : */ + /* SXTH : cccc 0110 1011 1111 xxxx xxxx 0111 xxxx : */ /* UXTAB16 : cccc 0110 1100 xxxx xxxx xxxx 0111 xxxx : */ + /* UXTB16 : cccc 0110 1100 1111 xxxx xxxx 0111 xxxx : */ /* ??? : cccc 0110 1101 xxxx xxxx xxxx 0111 xxxx : */ /* UXTAB : cccc 0110 1110 xxxx xxxx xxxx 0111 xxxx : */ + /* UXTB : cccc 0110 1110 1111 xxxx xxxx 0111 xxxx : */ /* UXTAH : cccc 0110 1111 xxxx xxxx xxxx 0111 xxxx : */ + /* UXTH : cccc 0110 1111 1111 xxxx xxxx 0111 xxxx : */ if ((insn & 0x0f8000f0) == 0x06800070) { if ((insn & 0x00300000) == 0x00100000) return INSN_REJECTED; /* Unallocated space */ - return prep_emulate_rd12rn16rm0_wflags(insn, asi); + + if ((insn & 0x000f0000) == 0x000f0000) { + return prep_emulate_rd12rm0(insn, asi); + } else { + return prep_emulate_rd12rn16rm0_wflags(insn, asi); + } } /* Other instruction encodings aren't yet defined */ -- cgit v0.10.2 From 038c3839c917e3eea1150a1dc55607b9bde2d5ac Mon Sep 17 00:00:00 2001 From: Jon Medhurst Date: Tue, 12 Apr 2011 07:45:25 +0100 Subject: ARM: kprobes: Fix emulation of SMUAD, SMUSD and SMMUL instructions The signed multiply instructions were being decoded incorrectly. Signed-off-by: Jon Medhurst Signed-off-by: Nicolas Pitre diff --git a/arch/arm/kernel/kprobes-decode.c b/arch/arm/kernel/kprobes-decode.c index 1e413a9..068e5c8 100644 --- a/arch/arm/kernel/kprobes-decode.c +++ b/arch/arm/kernel/kprobes-decode.c @@ -1436,18 +1436,26 @@ space_cccc_0111__1(kprobe_opcode_t insn, struct arch_specific_insn *asi) return prep_emulate_rdhi16rdlo12rs8rm0_wflags(insn, asi); /* SMLAD : cccc 0111 0000 xxxx xxxx xxxx 00x1 xxxx :Q */ + /* SMUAD : cccc 0111 0000 xxxx 1111 xxxx 00x1 xxxx :Q */ /* SMLSD : cccc 0111 0000 xxxx xxxx xxxx 01x1 xxxx :Q */ + /* SMUSD : cccc 0111 0000 xxxx 1111 xxxx 01x1 xxxx : */ /* SMMLA : cccc 0111 0101 xxxx xxxx xxxx 00x1 xxxx : */ - /* SMMLS : cccc 0111 0101 xxxx xxxx xxxx 11x1 xxxx : */ + /* SMMUL : cccc 0111 0101 xxxx 1111 xxxx 00x1 xxxx : */ if ((insn & 0x0ff00090) == 0x07000010 || - (insn & 0x0ff000d0) == 0x07500010 || - (insn & 0x0ff000d0) == 0x075000d0) + (insn & 0x0ff000d0) == 0x07500010) { + + if ((insn & 0x0000f000) == 0x0000f000) { + return prep_emulate_rd16rs8rm0_wflags(insn, asi); + } else { + return prep_emulate_rd16rn12rs8rm0_wflags(insn, asi); + } + } + + /* SMMLS : cccc 0111 0101 xxxx xxxx xxxx 11x1 xxxx : */ + if ((insn & 0x0ff000d0) == 0x075000d0) return prep_emulate_rd16rn12rs8rm0_wflags(insn, asi); - /* SMUSD : cccc 0111 0000 xxxx xxxx xxxx 01x1 xxxx : */ - /* SMUAD : cccc 0111 0000 xxxx 1111 xxxx 00x1 xxxx :Q */ - /* SMMUL : cccc 0111 0101 xxxx 1111 xxxx 00x1 xxxx : */ - return prep_emulate_rd16rs8rm0_wflags(insn, asi); + return INSN_REJECTED; } static enum kprobe_insn __kprobes -- cgit v0.10.2 From c6e4ae32911c2a0ad02d47ee59ccba352a74c38e Mon Sep 17 00:00:00 2001 From: Jon Medhurst Date: Tue, 12 Apr 2011 07:45:26 +0100 Subject: ARM: kprobes: Fix emulation of USAD8 instructions The USAD8 instruction wasn't being explicitly decoded leading to the incorrect emulation routine being called. It can be correctly decoded in the same way as the signed multiply instructions so we move the decoding there. Signed-off-by: Jon Medhurst Signed-off-by: Nicolas Pitre diff --git a/arch/arm/kernel/kprobes-decode.c b/arch/arm/kernel/kprobes-decode.c index 068e5c8..8391dac 100644 --- a/arch/arm/kernel/kprobes-decode.c +++ b/arch/arm/kernel/kprobes-decode.c @@ -1425,11 +1425,6 @@ space_cccc_0111__1(kprobe_opcode_t insn, struct arch_specific_insn *asi) if ((insn & 0x0ff000f0) == 0x03f000f0) return INSN_REJECTED; - /* USADA8 : cccc 0111 1000 xxxx xxxx xxxx 0001 xxxx */ - /* USAD8 : cccc 0111 1000 xxxx 1111 xxxx 0001 xxxx */ - if ((insn & 0x0ff000f0) == 0x07800010) - return prep_emulate_rd16rn12rs8rm0_wflags(insn, asi); - /* SMLALD : cccc 0111 0100 xxxx xxxx xxxx 00x1 xxxx */ /* SMLSLD : cccc 0111 0100 xxxx xxxx xxxx 01x1 xxxx */ if ((insn & 0x0ff00090) == 0x07400010) @@ -1441,8 +1436,11 @@ space_cccc_0111__1(kprobe_opcode_t insn, struct arch_specific_insn *asi) /* SMUSD : cccc 0111 0000 xxxx 1111 xxxx 01x1 xxxx : */ /* SMMLA : cccc 0111 0101 xxxx xxxx xxxx 00x1 xxxx : */ /* SMMUL : cccc 0111 0101 xxxx 1111 xxxx 00x1 xxxx : */ + /* USADA8 : cccc 0111 1000 xxxx xxxx xxxx 0001 xxxx : */ + /* USAD8 : cccc 0111 1000 xxxx 1111 xxxx 0001 xxxx : */ if ((insn & 0x0ff00090) == 0x07000010 || - (insn & 0x0ff000d0) == 0x07500010) { + (insn & 0x0ff000d0) == 0x07500010 || + (insn & 0x0ff000f0) == 0x07800010) { if ((insn & 0x0000f000) == 0x0000f000) { return prep_emulate_rd16rs8rm0_wflags(insn, asi); -- cgit v0.10.2 From fa1a03b429b3fd5f28e7fdd20ce99ca572bfd236 Mon Sep 17 00:00:00 2001 From: Jon Medhurst Date: Mon, 18 Apr 2011 08:53:54 +0100 Subject: ARM: kprobes: Reject probing of all coprocessor instructions The kernel doesn't currently support VFP or Neon code, and probing of code with CP15 operations is fraught with bad consequences. Therefore we don't need the ability to probe coprocessor instructions and the code to support this can be removed. The removed code also had at least two bugs: - MRC into R15 should set CPSR not trash PC - LDC and STC which use PC as base register needed the address offset by 8 Signed-off-by: Jon Medhurst Signed-off-by: Nicolas Pitre diff --git a/arch/arm/kernel/kprobes-decode.c b/arch/arm/kernel/kprobes-decode.c index 8391dac..ff39707 100644 --- a/arch/arm/kernel/kprobes-decode.c +++ b/arch/arm/kernel/kprobes-decode.c @@ -520,17 +520,6 @@ static void __kprobes simulate_mov_ipsp(struct kprobe *p, struct pt_regs *regs) regs->uregs[12] = regs->uregs[13]; } -static void __kprobes emulate_ldcstc(struct kprobe *p, struct pt_regs *regs) -{ - insn_1arg_fn_t *i_fn = (insn_1arg_fn_t *)&p->ainsn.insn[0]; - kprobe_opcode_t insn = p->opcode; - int rn = (insn >> 16) & 0xf; - long rnv = regs->uregs[rn]; - - /* Save Rn in case of writeback. */ - regs->uregs[rn] = insnslot_1arg_rflags(rnv, regs->ARM_cpsr, i_fn); -} - static void __kprobes emulate_ldrd(struct kprobe *p, struct pt_regs *regs) { insn_2arg_fn_t *i_fn = (insn_2arg_fn_t *)&p->ainsn.insn[0]; @@ -635,31 +624,6 @@ static void __kprobes emulate_str(struct kprobe *p, struct pt_regs *regs) regs->uregs[rn] = rnv_wb; /* Save Rn in case of writeback. */ } -static void __kprobes emulate_mrrc(struct kprobe *p, struct pt_regs *regs) -{ - insn_llret_0arg_fn_t *i_fn = (insn_llret_0arg_fn_t *)&p->ainsn.insn[0]; - kprobe_opcode_t insn = p->opcode; - union reg_pair fnr; - int rd = (insn >> 12) & 0xf; - int rn = (insn >> 16) & 0xf; - - fnr.dr = insnslot_llret_0arg_rflags(regs->ARM_cpsr, i_fn); - regs->uregs[rn] = fnr.r0; - regs->uregs[rd] = fnr.r1; -} - -static void __kprobes emulate_mcrr(struct kprobe *p, struct pt_regs *regs) -{ - insn_2arg_fn_t *i_fn = (insn_2arg_fn_t *)&p->ainsn.insn[0]; - kprobe_opcode_t insn = p->opcode; - int rd = (insn >> 12) & 0xf; - int rn = (insn >> 16) & 0xf; - long rnv = regs->uregs[rn]; - long rdv = regs->uregs[rd]; - - insnslot_2arg_rflags(rnv, rdv, regs->ARM_cpsr, i_fn); -} - static void __kprobes emulate_sat(struct kprobe *p, struct pt_regs *regs) { insn_1arg_fn_t *i_fn = (insn_1arg_fn_t *)&p->ainsn.insn[0]; @@ -693,24 +657,6 @@ static void __kprobes emulate_none(struct kprobe *p, struct pt_regs *regs) insnslot_0arg_rflags(regs->ARM_cpsr, i_fn); } -static void __kprobes emulate_rd12(struct kprobe *p, struct pt_regs *regs) -{ - insn_0arg_fn_t *i_fn = (insn_0arg_fn_t *)&p->ainsn.insn[0]; - kprobe_opcode_t insn = p->opcode; - int rd = (insn >> 12) & 0xf; - - regs->uregs[rd] = insnslot_0arg_rflags(regs->ARM_cpsr, i_fn); -} - -static void __kprobes emulate_ird12(struct kprobe *p, struct pt_regs *regs) -{ - insn_1arg_fn_t *i_fn = (insn_1arg_fn_t *)&p->ainsn.insn[0]; - kprobe_opcode_t insn = p->opcode; - int ird = (insn >> 12) & 0xf; - - insnslot_1arg_rflags(regs->uregs[ird], regs->ARM_cpsr, i_fn); -} - static void __kprobes emulate_rn16(struct kprobe *p, struct pt_regs *regs) { insn_1arg_fn_t *i_fn = (insn_1arg_fn_t *)&p->ainsn.insn[0]; @@ -1010,40 +956,22 @@ space_1111(kprobe_opcode_t insn, struct arch_specific_insn *asi) } /* SETEND : 1111 0001 0000 0001 xxxx xxxx 0000 xxxx */ - /* CDP2 : 1111 1110 xxxx xxxx xxxx xxxx xxx0 xxxx */ - if ((insn & 0xffff00f0) == 0xf1010000 || - (insn & 0xff000010) == 0xfe000000) { + if ((insn & 0xffff00f0) == 0xf1010000) { asi->insn[0] = insn; asi->insn_handler = emulate_none; return INSN_GOOD; } + /* Coprocessor instructions... */ /* MCRR2 : 1111 1100 0100 xxxx xxxx xxxx xxxx xxxx : (Rd != Rn) */ /* MRRC2 : 1111 1100 0101 xxxx xxxx xxxx xxxx xxxx : (Rd != Rn) */ - if ((insn & 0xffe00000) == 0xfc400000) { - insn &= 0xfff00fff; /* Rn = r0 */ - insn |= 0x00001000; /* Rd = r1 */ - asi->insn[0] = insn; - asi->insn_handler = - (insn & (1 << 20)) ? emulate_mrrc : emulate_mcrr; - return INSN_GOOD; - } + /* LDC2 : 1111 110x xxx1 xxxx xxxx xxxx xxxx xxxx */ + /* STC2 : 1111 110x xxx0 xxxx xxxx xxxx xxxx xxxx */ + /* CDP2 : 1111 1110 xxxx xxxx xxxx xxxx xxx0 xxxx */ + /* MCR2 : 1111 1110 xxx0 xxxx xxxx xxxx xxx1 xxxx */ + /* MRC2 : 1111 1110 xxx1 xxxx xxxx xxxx xxx1 xxxx */ - /* LDC2 : 1111 110x xxx1 xxxx xxxx xxxx xxxx xxxx */ - /* STC2 : 1111 110x xxx0 xxxx xxxx xxxx xxxx xxxx */ - if ((insn & 0xfe000000) == 0xfc000000) { - insn &= 0xfff0ffff; /* Rn = r0 */ - asi->insn[0] = insn; - asi->insn_handler = emulate_ldcstc; - return INSN_GOOD; - } - - /* MCR2 : 1111 1110 xxx0 xxxx xxxx xxxx xxx1 xxxx */ - /* MRC2 : 1111 1110 xxx1 xxxx xxxx xxxx xxx1 xxxx */ - insn &= 0xffff0fff; /* Rd = r0 */ - asi->insn[0] = insn; - asi->insn_handler = (insn & (1 << 20)) ? emulate_rd12 : emulate_ird12; - return INSN_GOOD; + return INSN_REJECTED; } static enum kprobe_insn __kprobes @@ -1504,14 +1432,7 @@ space_cccc_1100_010x(kprobe_opcode_t insn, struct arch_specific_insn *asi) { /* MCRR : cccc 1100 0100 xxxx xxxx xxxx xxxx xxxx : (Rd!=Rn) */ /* MRRC : cccc 1100 0101 xxxx xxxx xxxx xxxx xxxx : (Rd!=Rn) */ - if (is_r15(insn, 16) || is_r15(insn, 12)) - return INSN_REJECTED; /* Rn or Rd is PC */ - - insn &= 0xfff00fff; - insn |= 0x00001000; /* Rn = r0, Rd = r1 */ - asi->insn[0] = insn; - asi->insn_handler = (insn & (1 << 20)) ? emulate_mrrc : emulate_mcrr; - return INSN_GOOD; + return INSN_REJECTED; } static enum kprobe_insn __kprobes @@ -1519,10 +1440,7 @@ space_cccc_110x(kprobe_opcode_t insn, struct arch_specific_insn *asi) { /* LDC : cccc 110x xxx1 xxxx xxxx xxxx xxxx xxxx */ /* STC : cccc 110x xxx0 xxxx xxxx xxxx xxxx xxxx */ - insn &= 0xfff0ffff; /* Rn = r0 */ - asi->insn[0] = insn; - asi->insn_handler = emulate_ldcstc; - return INSN_GOOD; + return INSN_REJECTED; } static enum kprobe_insn __kprobes @@ -1535,18 +1453,9 @@ space_cccc_111x(kprobe_opcode_t insn, struct arch_specific_insn *asi) return INSN_REJECTED; /* CDP : cccc 1110 xxxx xxxx xxxx xxxx xxx0 xxxx */ - if ((insn & 0x0f000010) == 0x0e000000) { - asi->insn[0] = insn; - asi->insn_handler = emulate_none; - return INSN_GOOD; - } - /* MCR : cccc 1110 xxx0 xxxx xxxx xxxx xxx1 xxxx */ /* MRC : cccc 1110 xxx1 xxxx xxxx xxxx xxx1 xxxx */ - insn &= 0xffff0fff; /* Rd = r0 */ - asi->insn[0] = insn; - asi->insn_handler = (insn & (1 << 20)) ? emulate_rd12 : emulate_ird12; - return INSN_GOOD; + return INSN_REJECTED; } static unsigned long __kprobes __check_eq(unsigned long cpsr) -- cgit v0.10.2 From ac211c6994fb5f1f282745054c00d29e53639cb1 Mon Sep 17 00:00:00 2001 From: Jon Medhurst Date: Mon, 18 Apr 2011 08:53:55 +0100 Subject: ARM: kprobes: Consolidate stub decoding functions Following the change to remove support for coprocessor instructions we are left with three stub functions which can be consolidated. Signed-off-by: Jon Medhurst Signed-off-by: Nicolas Pitre diff --git a/arch/arm/kernel/kprobes-decode.c b/arch/arm/kernel/kprobes-decode.c index ff39707..fb81897 100644 --- a/arch/arm/kernel/kprobes-decode.c +++ b/arch/arm/kernel/kprobes-decode.c @@ -1428,33 +1428,19 @@ space_cccc_101x(kprobe_opcode_t insn, struct arch_specific_insn *asi) } static enum kprobe_insn __kprobes -space_cccc_1100_010x(kprobe_opcode_t insn, struct arch_specific_insn *asi) +space_cccc_11xx(kprobe_opcode_t insn, struct arch_specific_insn *asi) { + /* Coprocessor instructions... */ /* MCRR : cccc 1100 0100 xxxx xxxx xxxx xxxx xxxx : (Rd!=Rn) */ /* MRRC : cccc 1100 0101 xxxx xxxx xxxx xxxx xxxx : (Rd!=Rn) */ - return INSN_REJECTED; -} + /* LDC : cccc 110x xxx1 xxxx xxxx xxxx xxxx xxxx */ + /* STC : cccc 110x xxx0 xxxx xxxx xxxx xxxx xxxx */ + /* CDP : cccc 1110 xxxx xxxx xxxx xxxx xxx0 xxxx */ + /* MCR : cccc 1110 xxx0 xxxx xxxx xxxx xxx1 xxxx */ + /* MRC : cccc 1110 xxx1 xxxx xxxx xxxx xxx1 xxxx */ -static enum kprobe_insn __kprobes -space_cccc_110x(kprobe_opcode_t insn, struct arch_specific_insn *asi) -{ - /* LDC : cccc 110x xxx1 xxxx xxxx xxxx xxxx xxxx */ - /* STC : cccc 110x xxx0 xxxx xxxx xxxx xxxx xxxx */ - return INSN_REJECTED; -} + /* SVC : cccc 1111 xxxx xxxx xxxx xxxx xxxx xxxx */ -static enum kprobe_insn __kprobes -space_cccc_111x(kprobe_opcode_t insn, struct arch_specific_insn *asi) -{ - /* BKPT : 1110 0001 0010 xxxx xxxx xxxx 0111 xxxx */ - /* SWI : cccc 1111 xxxx xxxx xxxx xxxx xxxx xxxx */ - if ((insn & 0xfff000f0) == 0xe1200070 || - (insn & 0x0f000000) == 0x0f000000) - return INSN_REJECTED; - - /* CDP : cccc 1110 xxxx xxxx xxxx xxxx xxx0 xxxx */ - /* MCR : cccc 1110 xxx0 xxxx xxxx xxxx xxx1 xxxx */ - /* MRC : cccc 1110 xxx1 xxxx xxxx xxxx xxx1 xxxx */ return INSN_REJECTED; } @@ -1598,17 +1584,9 @@ arm_kprobe_decode_insn(kprobe_opcode_t insn, struct arch_specific_insn *asi) return space_cccc_101x(insn, asi); - } else if ((insn & 0x0fe00000) == 0x0c400000) { - - return space_cccc_1100_010x(insn, asi); - - } else if ((insn & 0x0e000000) == 0x0c000000) { - - return space_cccc_110x(insn, asi); - } - return space_cccc_111x(insn, asi); + return space_cccc_11xx(insn, asi); } void __init arm_kprobe_decode_init(void) -- cgit v0.10.2 From f0aeb8bff0fe9de50e1e4093ef86ff8f17a9b1b0 Mon Sep 17 00:00:00 2001 From: Jon Medhurst Date: Mon, 18 Apr 2011 08:53:56 +0100 Subject: ARM: kprobes: Reject probing of SETEND instructions The emulation of SETEND was broken as it changed the endianess for the running kprobes handling code. Rather than adding a new simulation routine to fix this we'll just reject probing of SETEND as these should be very rare in the kernel. Note, the function emulate_none is now unused but it is left in the source code as future patches will use it. Signed-off-by: Jon Medhurst Signed-off-by: Nicolas Pitre diff --git a/arch/arm/kernel/kprobes-decode.c b/arch/arm/kernel/kprobes-decode.c index fb81897..b81fbfb 100644 --- a/arch/arm/kernel/kprobes-decode.c +++ b/arch/arm/kernel/kprobes-decode.c @@ -956,11 +956,6 @@ space_1111(kprobe_opcode_t insn, struct arch_specific_insn *asi) } /* SETEND : 1111 0001 0000 0001 xxxx xxxx 0000 xxxx */ - if ((insn & 0xffff00f0) == 0xf1010000) { - asi->insn[0] = insn; - asi->insn_handler = emulate_none; - return INSN_GOOD; - } /* Coprocessor instructions... */ /* MCRR2 : 1111 1100 0100 xxxx xxxx xxxx xxxx xxxx : (Rd != Rn) */ -- cgit v0.10.2 From 41713d1396312a027ec02abc4767041627c178ef Mon Sep 17 00:00:00 2001 From: Jon Medhurst Date: Mon, 18 Apr 2011 08:53:57 +0100 Subject: ARM: kprobes: Fix emulation of PLD instructions The PLD instructions wasn't being decoded correctly and the emulation code wasn't adjusting PC correctly. As the PLD instruction is only a performance hint we emulate it as a simple nop, and we can broaden the instruction decoding to take into account newer PLI and PLDW instructions. Signed-off-by: Jon Medhurst Signed-off-by: Nicolas Pitre diff --git a/arch/arm/kernel/kprobes-decode.c b/arch/arm/kernel/kprobes-decode.c index b81fbfb..bddf8d0 100644 --- a/arch/arm/kernel/kprobes-decode.c +++ b/arch/arm/kernel/kprobes-decode.c @@ -657,14 +657,8 @@ static void __kprobes emulate_none(struct kprobe *p, struct pt_regs *regs) insnslot_0arg_rflags(regs->ARM_cpsr, i_fn); } -static void __kprobes emulate_rn16(struct kprobe *p, struct pt_regs *regs) +static void __kprobes emulate_nop(struct kprobe *p, struct pt_regs *regs) { - insn_1arg_fn_t *i_fn = (insn_1arg_fn_t *)&p->ainsn.insn[0]; - kprobe_opcode_t insn = p->opcode; - int rn = (insn >> 16) & 0xf; - long rnv = regs->uregs[rn]; - - insnslot_1arg_rflags(rnv, regs->ARM_cpsr, i_fn); } static void __kprobes emulate_rd12rm0(struct kprobe *p, struct pt_regs *regs) @@ -941,12 +935,13 @@ space_1111(kprobe_opcode_t insn, struct arch_specific_insn *asi) (insn & 0xfe5f0f00) == 0xf84d0500) return INSN_REJECTED; - /* PLD : 1111 01x1 x101 xxxx xxxx xxxx xxxx xxxx : */ - if ((insn & 0xfd700000) == 0xf4500000) { - insn &= 0xfff0ffff; /* Rn = r0 */ - asi->insn[0] = insn; - asi->insn_handler = emulate_rn16; - return INSN_GOOD; + /* memory hint : 1111 0100 x001 xxxx xxxx xxxx xxxx xxxx : */ + /* PLDI : 1111 0100 x101 xxxx xxxx xxxx xxxx xxxx : */ + /* PLDW : 1111 0101 x001 xxxx xxxx xxxx xxxx xxxx : */ + /* PLD : 1111 0101 x101 xxxx xxxx xxxx xxxx xxxx : */ + if ((insn & 0xfe300000) == 0xf4100000) { + asi->insn_handler = emulate_nop; + return INSN_GOOD_NO_SLOT; } /* BLX(1) : 1111 101x xxxx xxxx xxxx xxxx xxxx xxxx : */ -- cgit v0.10.2 From 72c2bab2be734d63dee4342e67b1754c54fded70 Mon Sep 17 00:00:00 2001 From: Jon Medhurst Date: Mon, 18 Apr 2011 08:53:58 +0100 Subject: ARM: kprobes: Remove redundant code in space_1111 The tests to explicitly reject probing CPS, RFE and SRS instructions are redundant as the default case is now to reject undecoded patterns. Signed-off-by: Jon Medhurst Signed-off-by: Nicolas Pitre diff --git a/arch/arm/kernel/kprobes-decode.c b/arch/arm/kernel/kprobes-decode.c index bddf8d0..dc315c1 100644 --- a/arch/arm/kernel/kprobes-decode.c +++ b/arch/arm/kernel/kprobes-decode.c @@ -927,14 +927,6 @@ prep_emulate_rdhi16rdlo12rs8rm0_wflags(kprobe_opcode_t insn, static enum kprobe_insn __kprobes space_1111(kprobe_opcode_t insn, struct arch_specific_insn *asi) { - /* CPS mmod == 1 : 1111 0001 0000 xx10 xxxx xxxx xx0x xxxx */ - /* RFE : 1111 100x x0x1 xxxx xxxx 1010 xxxx xxxx */ - /* SRS : 1111 100x x1x0 1101 xxxx 0101 xxxx xxxx */ - if ((insn & 0xfff30020) == 0xf1020000 || - (insn & 0xfe500f00) == 0xf8100a00 || - (insn & 0xfe5f0f00) == 0xf84d0500) - return INSN_REJECTED; - /* memory hint : 1111 0100 x001 xxxx xxxx xxxx xxxx xxxx : */ /* PLDI : 1111 0100 x101 xxxx xxxx xxxx xxxx xxxx : */ /* PLDW : 1111 0101 x001 xxxx xxxx xxxx xxxx xxxx : */ @@ -950,7 +942,11 @@ space_1111(kprobe_opcode_t insn, struct arch_specific_insn *asi) return INSN_GOOD_NO_SLOT; } - /* SETEND : 1111 0001 0000 0001 xxxx xxxx 0000 xxxx */ + /* CPS : 1111 0001 0000 xxx0 xxxx xxxx xx0x xxxx */ + /* SETEND: 1111 0001 0000 0001 xxxx xxxx 0000 xxxx */ + + /* SRS : 1111 100x x1x0 xxxx xxxx xxxx xxxx xxxx */ + /* RFE : 1111 100x x0x1 xxxx xxxx xxxx xxxx xxxx */ /* Coprocessor instructions... */ /* MCRR2 : 1111 1100 0100 xxxx xxxx xxxx xxxx xxxx : (Rd != Rn) */ -- cgit v0.10.2 From f704a6e25bd07e1381af81f19fb1d123975807b1 Mon Sep 17 00:00:00 2001 From: Jon Medhurst Date: Tue, 19 Apr 2011 10:52:16 +0100 Subject: ARM: kprobes: Reject probing of undefined data processing instructions The instruction decoding in space_cccc_000x needs to reject probing of instructions with undefined patterns as they may in future become defined and then emulated faultily - as has already happened with the SMC instruction. This fix is achieved by testing for the instruction patterns we want to probe and making the the default fall-through paths reject probes. This also allows us to remove some explicit tests for instructions that we wish to reject, as that is now the default action. Signed-off-by: Jon Medhurst Signed-off-by: Nicolas Pitre diff --git a/arch/arm/kernel/kprobes-decode.c b/arch/arm/kernel/kprobes-decode.c index dc315c1..4715537 100644 --- a/arch/arm/kernel/kprobes-decode.c +++ b/arch/arm/kernel/kprobes-decode.c @@ -966,14 +966,6 @@ space_cccc_000x(kprobe_opcode_t insn, struct arch_specific_insn *asi) /* cccc 0001 0xx0 xxxx xxxx xxxx xxxx xxx0 xxxx */ if ((insn & 0x0f900010) == 0x01000000) { - /* BXJ : cccc 0001 0010 xxxx xxxx xxxx 0010 xxxx */ - /* MSR : cccc 0001 0x10 xxxx xxxx xxxx 0000 xxxx */ - /* MRS spsr : cccc 0001 0100 xxxx xxxx xxxx 0000 xxxx */ - if ((insn & 0x0ff000f0) == 0x01200020 || - (insn & 0x0fb000f0) == 0x01200000 || - (insn & 0x0ff000f0) == 0x01400000) - return INSN_REJECTED; - /* MRS cpsr : cccc 0001 0000 xxxx xxxx xxxx 0000 xxxx */ if ((insn & 0x0ff000f0) == 0x01000000) { if (is_r15(insn, 12)) @@ -994,17 +986,21 @@ space_cccc_000x(kprobe_opcode_t insn, struct arch_specific_insn *asi) /* SMLAxy : cccc 0001 0000 xxxx xxxx xxxx 1xx0 xxxx : Q */ /* SMLAWy : cccc 0001 0010 xxxx xxxx xxxx 1x00 xxxx : Q */ - return prep_emulate_rd16rn12rs8rm0_wflags(insn, asi); + if ((insn & 0x0ff00090) == 0x01000080 || + (insn & 0x0ff000b0) == 0x01200080) + return prep_emulate_rd16rn12rs8rm0_wflags(insn, asi); + + /* BXJ : cccc 0001 0010 xxxx xxxx xxxx 0010 xxxx */ + /* MSR : cccc 0001 0x10 xxxx xxxx xxxx 0000 xxxx */ + /* MRS spsr : cccc 0001 0100 xxxx xxxx xxxx 0000 xxxx */ + /* Other instruction encodings aren't yet defined */ + return INSN_REJECTED; } /* cccc 0001 0xx0 xxxx xxxx xxxx xxxx 0xx1 xxxx */ else if ((insn & 0x0f900090) == 0x01000010) { - /* BKPT : 1110 0001 0010 xxxx xxxx xxxx 0111 xxxx */ - if ((insn & 0xfff000f0) == 0xe1200070) - return INSN_REJECTED; - /* BLX(2) : cccc 0001 0010 xxxx xxxx xxxx 0011 xxxx */ /* BX : cccc 0001 0010 xxxx xxxx xxxx 0001 xxxx */ if ((insn & 0x0ff000d0) == 0x01200010) { @@ -1022,7 +1018,14 @@ space_cccc_000x(kprobe_opcode_t insn, struct arch_specific_insn *asi) /* QSUB : cccc 0001 0010 xxxx xxxx xxxx 0101 xxxx :Q */ /* QDADD : cccc 0001 0100 xxxx xxxx xxxx 0101 xxxx :Q */ /* QDSUB : cccc 0001 0110 xxxx xxxx xxxx 0101 xxxx :Q */ - return prep_emulate_rd12rn16rm0_wflags(insn, asi); + if ((insn & 0x0f9000f0) == 0x01000050) + return prep_emulate_rd12rn16rm0_wflags(insn, asi); + + /* BKPT : 1110 0001 0010 xxxx xxxx xxxx 0111 xxxx */ + /* SMC : cccc 0001 0110 xxxx xxxx xxxx 0111 xxxx */ + + /* Other instruction encodings aren't yet defined */ + return INSN_REJECTED; } /* cccc 0000 xxxx xxxx xxxx xxxx xxxx 1001 xxxx */ -- cgit v0.10.2 From c9836777d5f22e64eefc759d682511560b6d6d78 Mon Sep 17 00:00:00 2001 From: Jon Medhurst Date: Tue, 19 Apr 2011 10:52:17 +0100 Subject: ARM: kprobes: Add emulation of MOVW and MOVT instructions The MOVW and MOVT instructions account for approximately 7% of all instructions in a ARMv7 kernel as GCC uses them instead of a literal pool. Signed-off-by: Jon Medhurst Signed-off-by: Nicolas Pitre diff --git a/arch/arm/kernel/kprobes-decode.c b/arch/arm/kernel/kprobes-decode.c index 4715537..a063f15 100644 --- a/arch/arm/kernel/kprobes-decode.c +++ b/arch/arm/kernel/kprobes-decode.c @@ -661,6 +661,17 @@ static void __kprobes emulate_nop(struct kprobe *p, struct pt_regs *regs) { } +static void __kprobes +emulate_rd12_modify(struct kprobe *p, struct pt_regs *regs) +{ + insn_1arg_fn_t *i_fn = (insn_1arg_fn_t *)&p->ainsn.insn[0]; + kprobe_opcode_t insn = p->opcode; + int rd = (insn >> 12) & 0xf; + long rdv = regs->uregs[rd]; + + regs->uregs[rd] = insnslot_1arg_rflags(rdv, regs->ARM_cpsr, i_fn); +} + static void __kprobes emulate_rd12rm0(struct kprobe *p, struct pt_regs *regs) { insn_1arg_fn_t *i_fn = (insn_1arg_fn_t *)&p->ainsn.insn[0]; @@ -847,6 +858,18 @@ prep_emulate_ldr_str(kprobe_opcode_t insn, struct arch_specific_insn *asi) } static enum kprobe_insn __kprobes +prep_emulate_rd12_modify(kprobe_opcode_t insn, struct arch_specific_insn *asi) +{ + if (is_r15(insn, 12)) + return INSN_REJECTED; /* Rd is PC */ + + insn &= 0xffff0fff; /* Rd = r0 */ + asi->insn[0] = insn; + asi->insn_handler = emulate_rd12_modify; + return INSN_GOOD; +} + +static enum kprobe_insn __kprobes prep_emulate_rd12rm0(kprobe_opcode_t insn, struct arch_specific_insn *asi) { if (is_r15(insn, 12)) @@ -1170,14 +1193,17 @@ space_cccc_000x(kprobe_opcode_t insn, struct arch_specific_insn *asi) static enum kprobe_insn __kprobes space_cccc_001x(kprobe_opcode_t insn, struct arch_specific_insn *asi) { + /* MOVW : cccc 0011 0000 xxxx xxxx xxxx xxxx xxxx */ + /* MOVT : cccc 0011 0100 xxxx xxxx xxxx xxxx xxxx */ + if ((insn & 0x0fb00000) == 0x03000000) + return prep_emulate_rd12_modify(insn, asi); + /* * MSR : cccc 0011 0x10 xxxx xxxx xxxx xxxx xxxx - * Undef : cccc 0011 0100 xxxx xxxx xxxx xxxx xxxx * ALU op with S bit and Rd == 15 : * cccc 001x xxx1 xxxx 1111 xxxx xxxx xxxx */ if ((insn & 0x0fb00000) == 0x03200000 || /* MSR */ - (insn & 0x0ff00000) == 0x03400000 || /* Undef */ (insn & 0x0e10f000) == 0x0210f000) /* ALU s-bit, R15 */ return INSN_REJECTED; -- cgit v0.10.2 From 20e8155e24ba5c04558780d0a8da13c39f98c002 Mon Sep 17 00:00:00 2001 From: Jon Medhurst Date: Tue, 19 Apr 2011 10:52:18 +0100 Subject: ARM: kprobes: Add emulation of SBFX, UBFX, BFI and BFC instructions These bit field manipulation instructions occur several thousand times in an ARMv7 kernel. Signed-off-by: Jon Medhurst Signed-off-by: Nicolas Pitre diff --git a/arch/arm/kernel/kprobes-decode.c b/arch/arm/kernel/kprobes-decode.c index a063f15..6bed8b0 100644 --- a/arch/arm/kernel/kprobes-decode.c +++ b/arch/arm/kernel/kprobes-decode.c @@ -672,6 +672,19 @@ emulate_rd12_modify(struct kprobe *p, struct pt_regs *regs) regs->uregs[rd] = insnslot_1arg_rflags(rdv, regs->ARM_cpsr, i_fn); } +static void __kprobes +emulate_rd12rn0_modify(struct kprobe *p, struct pt_regs *regs) +{ + insn_2arg_fn_t *i_fn = (insn_2arg_fn_t *)&p->ainsn.insn[0]; + kprobe_opcode_t insn = p->opcode; + int rd = (insn >> 12) & 0xf; + int rn = insn & 0xf; + long rdv = regs->uregs[rd]; + long rnv = regs->uregs[rn]; + + regs->uregs[rd] = insnslot_2arg_rflags(rdv, rnv, regs->ARM_cpsr, i_fn); +} + static void __kprobes emulate_rd12rm0(struct kprobe *p, struct pt_regs *regs) { insn_1arg_fn_t *i_fn = (insn_1arg_fn_t *)&p->ainsn.insn[0]; @@ -870,6 +883,20 @@ prep_emulate_rd12_modify(kprobe_opcode_t insn, struct arch_specific_insn *asi) } static enum kprobe_insn __kprobes +prep_emulate_rd12rn0_modify(kprobe_opcode_t insn, + struct arch_specific_insn *asi) +{ + if (is_r15(insn, 12)) + return INSN_REJECTED; /* Rd is PC */ + + insn &= 0xffff0ff0; /* Rd = r0 */ + insn |= 0x00000001; /* Rn = r1 */ + asi->insn[0] = insn; + asi->insn_handler = emulate_rd12rn0_modify; + return INSN_GOOD; +} + +static enum kprobe_insn __kprobes prep_emulate_rd12rm0(kprobe_opcode_t insn, struct arch_specific_insn *asi) { if (is_r15(insn, 12)) @@ -1396,6 +1423,21 @@ space_cccc_0111__1(kprobe_opcode_t insn, struct arch_specific_insn *asi) if ((insn & 0x0ff000d0) == 0x075000d0) return prep_emulate_rd16rn12rs8rm0_wflags(insn, asi); + /* SBFX : cccc 0111 101x xxxx xxxx xxxx x101 xxxx : */ + /* UBFX : cccc 0111 111x xxxx xxxx xxxx x101 xxxx : */ + if ((insn & 0x0fa00070) == 0x07a00050) + return prep_emulate_rd12rm0(insn, asi); + + /* BFI : cccc 0111 110x xxxx xxxx xxxx x001 xxxx : */ + /* BFC : cccc 0111 110x xxxx xxxx xxxx x001 1111 : */ + if ((insn & 0x0fe00070) == 0x07c00010) { + + if ((insn & 0x0000000f) == 0x0000000f) + return prep_emulate_rd12_modify(insn, asi); + else + return prep_emulate_rd12rn0_modify(insn, asi); + } + return INSN_REJECTED; } -- cgit v0.10.2 From 94254930786216106100e9a28c9a244df58be61f Mon Sep 17 00:00:00 2001 From: Jon Medhurst Date: Tue, 19 Apr 2011 10:52:19 +0100 Subject: ARM: kprobes: Add emulation of hint instructions like NOP and WFI Being able to probe NOP instructions is useful for hard-coding probeable locations and is used by the kprobes test code. Signed-off-by: Jon Medhurst Signed-off-by: Nicolas Pitre diff --git a/arch/arm/kernel/kprobes-decode.c b/arch/arm/kernel/kprobes-decode.c index 6bed8b0..03b85ad 100644 --- a/arch/arm/kernel/kprobes-decode.c +++ b/arch/arm/kernel/kprobes-decode.c @@ -1225,6 +1225,30 @@ space_cccc_001x(kprobe_opcode_t insn, struct arch_specific_insn *asi) if ((insn & 0x0fb00000) == 0x03000000) return prep_emulate_rd12_modify(insn, asi); + /* hints : cccc 0011 0010 0000 xxxx xxxx xxxx xxxx */ + if ((insn & 0x0fff0000) == 0x03200000) { + unsigned op2 = insn & 0x000000ff; + if (op2 == 0x01 || op2 == 0x04) { + /* YIELD : cccc 0011 0010 0000 xxxx xxxx 0000 0001 */ + /* SEV : cccc 0011 0010 0000 xxxx xxxx 0000 0100 */ + asi->insn[0] = insn; + asi->insn_handler = emulate_none; + return INSN_GOOD; + } else if (op2 <= 0x03) { + /* NOP : cccc 0011 0010 0000 xxxx xxxx 0000 0000 */ + /* WFE : cccc 0011 0010 0000 xxxx xxxx 0000 0010 */ + /* WFI : cccc 0011 0010 0000 xxxx xxxx 0000 0011 */ + /* + * We make WFE and WFI true NOPs to avoid stalls due + * to missing events whilst processing the probe. + */ + asi->insn_handler = emulate_nop; + return INSN_GOOD_NO_SLOT; + } + /* For DBG and unallocated hints it's safest to reject them */ + return INSN_REJECTED; + } + /* * MSR : cccc 0011 0x10 xxxx xxxx xxxx xxxx xxxx * ALU op with S bit and Rd == 15 : -- cgit v0.10.2 From cdc253611582f08036ccb6e10efe95b8e760a7e2 Mon Sep 17 00:00:00 2001 From: Jon Medhurst Date: Tue, 19 Apr 2011 10:52:20 +0100 Subject: ARM: kprobes: Tidy-up kprobes-decode.c - Remove coding standard violations reported by checkpatch.pl - Delete comment about handling of conditional branches which is no longer true. - Delete comment at end of file which lists all ARM instructions. This duplicates data available in the ARM ARM and seems like an unnecessary maintenance burden to keep this up to date and accurate. Signed-off-by: Jon Medhurst Signed-off-by: Nicolas Pitre diff --git a/arch/arm/kernel/kprobes-decode.c b/arch/arm/kernel/kprobes-decode.c index 03b85ad..15eeff6 100644 --- a/arch/arm/kernel/kprobes-decode.c +++ b/arch/arm/kernel/kprobes-decode.c @@ -34,9 +34,6 @@ * * *) If the PC is written to by the instruction, the * instruction must be fully simulated in software. - * If it is a conditional instruction, the handler - * will use insn[0] to copy its condition code to - * set r0 to 1 and insn[1] to "mov pc, lr" to return. * * *) Otherwise, a modified form of the instruction is * directly executed. Its handler calls the @@ -1026,7 +1023,8 @@ space_cccc_000x(kprobe_opcode_t insn, struct arch_specific_insn *asi) /* SMLALxy : cccc 0001 0100 xxxx xxxx xxxx 1xx0 xxxx */ if ((insn & 0x0ff00090) == 0x01400080) - return prep_emulate_rdhi16rdlo12rs8rm0_wflags(insn, asi); + return prep_emulate_rdhi16rdlo12rs8rm0_wflags(insn, + asi); /* SMULWy : cccc 0001 0010 xxxx xxxx xxxx 1x10 xxxx */ /* SMULxy : cccc 0001 0110 xxxx xxxx xxxx 1xx0 xxxx */ @@ -1097,15 +1095,15 @@ space_cccc_000x(kprobe_opcode_t insn, struct arch_specific_insn *asi) /* SMULLS : cccc 0000 1101 xxxx xxxx xxxx 1001 xxxx :cc */ /* SMLAL : cccc 0000 1110 xxxx xxxx xxxx 1001 xxxx : */ /* SMLALS : cccc 0000 1111 xxxx xxxx xxxx 1001 xxxx :cc */ - if ((insn & 0x00d00000) == 0x00500000) { + if ((insn & 0x00d00000) == 0x00500000) return INSN_REJECTED; - } else if ((insn & 0x00e00000) == 0x00000000) { - return prep_emulate_rd16rs8rm0_wflags(insn, asi); - } else if ((insn & 0x00a00000) == 0x00200000) { - return prep_emulate_rd16rn12rs8rm0_wflags(insn, asi); - } else { - return prep_emulate_rdhi16rdlo12rs8rm0_wflags(insn, asi); - } + else if ((insn & 0x00e00000) == 0x00000000) + return prep_emulate_rd16rs8rm0_wflags(insn, asi); + else if ((insn & 0x00a00000) == 0x00200000) + return prep_emulate_rd16rn12rs8rm0_wflags(insn, asi); + else + return prep_emulate_rdhi16rdlo12rs8rm0_wflags(insn, + asi); } /* cccc 000x xxxx xxxx xxxx xxxx xxxx 1xx1 xxxx */ @@ -1171,7 +1169,7 @@ space_cccc_000x(kprobe_opcode_t insn, struct arch_specific_insn *asi) /* * ALU op with S bit and Rd == 15 : - * cccc 000x xxx1 xxxx 1111 xxxx xxxx xxxx + * cccc 000x xxx1 xxxx 1111 xxxx xxxx xxxx */ if ((insn & 0x0e10f000) == 0x0010f000) return INSN_REJECTED; @@ -1401,11 +1399,10 @@ space_cccc_0110__1(kprobe_opcode_t insn, struct arch_specific_insn *asi) if ((insn & 0x00300000) == 0x00100000) return INSN_REJECTED; /* Unallocated space */ - if ((insn & 0x000f0000) == 0x000f0000) { + if ((insn & 0x000f0000) == 0x000f0000) return prep_emulate_rd12rm0(insn, asi); - } else { + else return prep_emulate_rd12rn16rm0_wflags(insn, asi); - } } /* Other instruction encodings aren't yet defined */ @@ -1436,11 +1433,10 @@ space_cccc_0111__1(kprobe_opcode_t insn, struct arch_specific_insn *asi) (insn & 0x0ff000d0) == 0x07500010 || (insn & 0x0ff000f0) == 0x07800010) { - if ((insn & 0x0000f000) == 0x0000f000) { + if ((insn & 0x0000f000) == 0x0000f000) return prep_emulate_rd16rs8rm0_wflags(insn, asi); - } else { + else return prep_emulate_rd16rn12rs8rm0_wflags(insn, asi); - } } /* SMMLS : cccc 0111 0101 xxxx xxxx xxxx 11x1 xxxx : */ @@ -1633,40 +1629,38 @@ arm_kprobe_decode_insn(kprobe_opcode_t insn, struct arch_specific_insn *asi) asi->insn_check_cc = condition_checks[insn>>28]; asi->insn[1] = KPROBE_RETURN_INSTRUCTION; - if ((insn & 0xf0000000) == 0xf0000000) { + if ((insn & 0xf0000000) == 0xf0000000) return space_1111(insn, asi); - } else if ((insn & 0x0e000000) == 0x00000000) { + else if ((insn & 0x0e000000) == 0x00000000) return space_cccc_000x(insn, asi); - } else if ((insn & 0x0e000000) == 0x02000000) { + else if ((insn & 0x0e000000) == 0x02000000) return space_cccc_001x(insn, asi); - } else if ((insn & 0x0f000010) == 0x06000010) { + else if ((insn & 0x0f000010) == 0x06000010) return space_cccc_0110__1(insn, asi); - } else if ((insn & 0x0f000010) == 0x07000010) { + else if ((insn & 0x0f000010) == 0x07000010) return space_cccc_0111__1(insn, asi); - } else if ((insn & 0x0c000000) == 0x04000000) { + else if ((insn & 0x0c000000) == 0x04000000) return space_cccc_01xx(insn, asi); - } else if ((insn & 0x0e000000) == 0x08000000) { + else if ((insn & 0x0e000000) == 0x08000000) return space_cccc_100x(insn, asi); - } else if ((insn & 0x0e000000) == 0x0a000000) { + else if ((insn & 0x0e000000) == 0x0a000000) return space_cccc_101x(insn, asi); - } - return space_cccc_11xx(insn, asi); } @@ -1674,82 +1668,3 @@ void __init arm_kprobe_decode_init(void) { find_str_pc_offset(); } - - -/* - * All ARM instructions listed below. - * - * Instructions and their general purpose registers are given. - * If a particular register may not use R15, it is prefixed with a "!". - * If marked with a "*" means the value returned by reading R15 - * is implementation defined. - * - * ADC/ADD/AND/BIC/CMN/CMP/EOR/MOV/MVN/ORR/RSB/RSC/SBC/SUB/TEQ - * TST: Rd, Rn, Rm, !Rs - * BX: Rm - * BLX(2): !Rm - * BX: Rm (R15 legal, but discouraged) - * BXJ: !Rm, - * CLZ: !Rd, !Rm - * CPY: Rd, Rm - * LDC/2,STC/2 immediate offset & unindex: Rn - * LDC/2,STC/2 immediate pre/post-indexed: !Rn - * LDM(1/3): !Rn, register_list - * LDM(2): !Rn, !register_list - * LDR,STR,PLD immediate offset: Rd, Rn - * LDR,STR,PLD register offset: Rd, Rn, !Rm - * LDR,STR,PLD scaled register offset: Rd, !Rn, !Rm - * LDR,STR immediate pre/post-indexed: Rd, !Rn - * LDR,STR register pre/post-indexed: Rd, !Rn, !Rm - * LDR,STR scaled register pre/post-indexed: Rd, !Rn, !Rm - * LDRB,STRB immediate offset: !Rd, Rn - * LDRB,STRB register offset: !Rd, Rn, !Rm - * LDRB,STRB scaled register offset: !Rd, !Rn, !Rm - * LDRB,STRB immediate pre/post-indexed: !Rd, !Rn - * LDRB,STRB register pre/post-indexed: !Rd, !Rn, !Rm - * LDRB,STRB scaled register pre/post-indexed: !Rd, !Rn, !Rm - * LDRT,LDRBT,STRBT immediate pre/post-indexed: !Rd, !Rn - * LDRT,LDRBT,STRBT register pre/post-indexed: !Rd, !Rn, !Rm - * LDRT,LDRBT,STRBT scaled register pre/post-indexed: !Rd, !Rn, !Rm - * LDRH/SH/SB/D,STRH/SH/SB/D immediate offset: !Rd, Rn - * LDRH/SH/SB/D,STRH/SH/SB/D register offset: !Rd, Rn, !Rm - * LDRH/SH/SB/D,STRH/SH/SB/D immediate pre/post-indexed: !Rd, !Rn - * LDRH/SH/SB/D,STRH/SH/SB/D register pre/post-indexed: !Rd, !Rn, !Rm - * LDREX: !Rd, !Rn - * MCR/2: !Rd - * MCRR/2,MRRC/2: !Rd, !Rn - * MLA: !Rd, !Rn, !Rm, !Rs - * MOV: Rd - * MRC/2: !Rd (if Rd==15, only changes cond codes, not the register) - * MRS,MSR: !Rd - * MUL: !Rd, !Rm, !Rs - * PKH{BT,TB}: !Rd, !Rn, !Rm - * QDADD,[U]QADD/16/8/SUBX: !Rd, !Rm, !Rn - * QDSUB,[U]QSUB/16/8/ADDX: !Rd, !Rm, !Rn - * REV/16/SH: !Rd, !Rm - * RFE: !Rn - * {S,U}[H]ADD{16,8,SUBX},{S,U}[H]SUB{16,8,ADDX}: !Rd, !Rn, !Rm - * SEL: !Rd, !Rn, !Rm - * SMLA,SMLA{D,W},SMLSD,SMML{A,S}: !Rd, !Rn, !Rm, !Rs - * SMLAL,SMLA{D,LD},SMLSLD,SMMULL,SMULW: !RdHi, !RdLo, !Rm, !Rs - * SMMUL,SMUAD,SMUL,SMUSD: !Rd, !Rm, !Rs - * SSAT/16: !Rd, !Rm - * STM(1/2): !Rn, register_list* (R15 in reg list not recommended) - * STRT immediate pre/post-indexed: Rd*, !Rn - * STRT register pre/post-indexed: Rd*, !Rn, !Rm - * STRT scaled register pre/post-indexed: Rd*, !Rn, !Rm - * STREX: !Rd, !Rn, !Rm - * SWP/B: !Rd, !Rn, !Rm - * {S,U}XTA{B,B16,H}: !Rd, !Rn, !Rm - * {S,U}XT{B,B16,H}: !Rd, !Rm - * UM{AA,LA,UL}L: !RdHi, !RdLo, !Rm, !Rs - * USA{D8,A8,T,T16}: !Rd, !Rm, !Rs - * - * May transfer control by writing R15 (possible mode changes or alternate - * mode accesses marked by "*"): - * ALU op (* with s-bit), B, BL, BKPT, BLX(1/2), BX, BXJ, CPS*, CPY, - * LDM(1), LDM(2/3)*, LDR, MOV, RFE*, SWI* - * - * Instructions that do not take general registers, nor transfer control: - * CDP/2, SETEND, SRS* - */ -- cgit v0.10.2 From bfacf2225a955bea9c41c707fc72ba16009674a0 Mon Sep 17 00:00:00 2001 From: Jeff Layton Date: Wed, 27 Apr 2011 13:25:51 -0400 Subject: cifs: change bleft in decode_unicode_ssetup back to signed type The buffer length checks in this function depend on this value being a signed data type, but 690c522fa converted it to an unsigned type. Also, eliminate a problem with the null termination check in the same function. cifs_strndup_from_ucs handles that situation correctly already, and the existing check could potentially lead to a buffer overrun since it increments bleft without checking to see whether it falls off the end of the buffer. Cc: stable@kernel.org Reported-and-Acked-by: David Howells Signed-off-by: Jeff Layton Signed-off-by: Steve French diff --git a/fs/cifs/sess.c b/fs/cifs/sess.c index f6728eb..2e2c911 100644 --- a/fs/cifs/sess.c +++ b/fs/cifs/sess.c @@ -276,7 +276,7 @@ static void ascii_ssetup_strings(char **pbcc_area, struct cifsSesInfo *ses, } static void -decode_unicode_ssetup(char **pbcc_area, __u16 bleft, struct cifsSesInfo *ses, +decode_unicode_ssetup(char **pbcc_area, int bleft, struct cifsSesInfo *ses, const struct nls_table *nls_cp) { int len; @@ -284,19 +284,6 @@ decode_unicode_ssetup(char **pbcc_area, __u16 bleft, struct cifsSesInfo *ses, cFYI(1, "bleft %d", bleft); - /* - * Windows servers do not always double null terminate their final - * Unicode string. Check to see if there are an uneven number of bytes - * left. If so, then add an extra NULL pad byte to the end of the - * response. - * - * See section 2.7.2 in "Implementing CIFS" for details - */ - if (bleft % 2) { - data[bleft] = 0; - ++bleft; - } - kfree(ses->serverOS); ses->serverOS = cifs_strndup_from_ucs(data, bleft, true, nls_cp); cFYI(1, "serverOS=%s", ses->serverOS); -- cgit v0.10.2 From fcda7f4578bbf9717444ca6da8a421d21489d078 Mon Sep 17 00:00:00 2001 From: Jeff Layton Date: Wed, 27 Apr 2011 13:25:51 -0400 Subject: cifs: check for bytes_remaining going to zero in CIFS_SessSetup It's possible that when we go to decode the string area in the SESSION_SETUP response, that bytes_remaining will be 0. Decrementing it at that point will mean that it can go "negative" and wrap. Check for a bytes_remaining value of 0, and don't try to decode the string area if that's the case. Cc: stable@kernel.org Reported-and-Acked-by: David Howells Signed-off-by: Jeff Layton Signed-off-by: Steve French diff --git a/fs/cifs/sess.c b/fs/cifs/sess.c index 2e2c911..645114a 100644 --- a/fs/cifs/sess.c +++ b/fs/cifs/sess.c @@ -916,7 +916,9 @@ ssetup_ntlmssp_authenticate: } /* BB check if Unicode and decode strings */ - if (smb_buf->Flags2 & SMBFLG2_UNICODE) { + if (bytes_remaining == 0) { + /* no string area to decode, do nothing */ + } else if (smb_buf->Flags2 & SMBFLG2_UNICODE) { /* unicode string area must be word-aligned */ if (((unsigned long) bcc_ptr - (unsigned long) smb_buf) % 2) { ++bcc_ptr; -- cgit v0.10.2 From 2a2047bc94d0efc316401170c3d078d9edc20dc4 Mon Sep 17 00:00:00 2001 From: Jeff Layton Date: Wed, 27 Apr 2011 13:29:49 -0400 Subject: cifs: sanitize length checking in coalesce_t2 (try #3) There are a couple of places in this code where these values can wrap or go negative, and that could potentially end up overflowing the buffer. Ensure that that doesn't happen. Do all of the length calculation and checks first, and only perform the memcpy after they pass. Also, increase some stack variables to 32 bits to ensure that they don't wrap without being detected. Finally, change the error codes to be a bit more descriptive of any problems detected. -EINVAL isn't very accurate. Cc: stable@kernel.org Reported-and-Acked-by: David Howells Signed-off-by: Jeff Layton Signed-off-by: Steve French diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index 4bc862a..8b75a8ec 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c @@ -274,7 +274,8 @@ static int coalesce_t2(struct smb_hdr *psecond, struct smb_hdr *pTargetSMB) char *data_area_of_target; char *data_area_of_buf2; int remaining; - __u16 byte_count, total_data_size, total_in_buf, total_in_buf2; + unsigned int byte_count, total_in_buf; + __u16 total_data_size, total_in_buf2; total_data_size = get_unaligned_le16(&pSMBt->t2_rsp.TotalDataCount); @@ -287,7 +288,7 @@ static int coalesce_t2(struct smb_hdr *psecond, struct smb_hdr *pTargetSMB) remaining = total_data_size - total_in_buf; if (remaining < 0) - return -EINVAL; + return -EPROTO; if (remaining == 0) /* nothing to do, ignore */ return 0; @@ -308,20 +309,29 @@ static int coalesce_t2(struct smb_hdr *psecond, struct smb_hdr *pTargetSMB) data_area_of_target += total_in_buf; /* copy second buffer into end of first buffer */ - memcpy(data_area_of_target, data_area_of_buf2, total_in_buf2); total_in_buf += total_in_buf2; + /* is the result too big for the field? */ + if (total_in_buf > USHRT_MAX) + return -EPROTO; put_unaligned_le16(total_in_buf, &pSMBt->t2_rsp.DataCount); + + /* fix up the BCC */ byte_count = get_bcc_le(pTargetSMB); byte_count += total_in_buf2; + /* is the result too big for the field? */ + if (byte_count > USHRT_MAX) + return -EPROTO; put_bcc_le(byte_count, pTargetSMB); byte_count = pTargetSMB->smb_buf_length; byte_count += total_in_buf2; - - /* BB also add check that we are not beyond maximum buffer size */ - + /* don't allow buffer to overflow */ + if (byte_count > CIFSMaxBufSize) + return -ENOBUFS; pTargetSMB->smb_buf_length = byte_count; + memcpy(data_area_of_target, data_area_of_buf2, total_in_buf2); + if (remaining == total_in_buf2) { cFYI(1, "found the last secondary response"); return 0; /* we are done */ -- cgit v0.10.2 From 5c1e6aa300a7a669dc469d2dcb20172c6bd8fed9 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Thu, 28 Apr 2011 14:13:38 -0700 Subject: net: Make dst_alloc() take more explicit initializations. Now the dst->dev, dev->obsolete, and dst->flags values can be specified as well. Signed-off-by: David S. Miller diff --git a/include/net/dst.h b/include/net/dst.h index d7bb740..2588a9a 100644 --- a/include/net/dst.h +++ b/include/net/dst.h @@ -350,7 +350,8 @@ static inline struct dst_entry *skb_dst_pop(struct sk_buff *skb) } extern int dst_discard(struct sk_buff *skb); -extern void *dst_alloc(struct dst_ops * ops, int initial_ref); +extern void *dst_alloc(struct dst_ops * ops, struct net_device *dev, + int initial_ref, int initial_obsolete, int flags); extern void __dst_free(struct dst_entry * dst); extern struct dst_entry *dst_destroy(struct dst_entry * dst); diff --git a/net/core/dst.c b/net/core/dst.c index 91104d3..9505778 100644 --- a/net/core/dst.c +++ b/net/core/dst.c @@ -166,7 +166,8 @@ EXPORT_SYMBOL(dst_discard); const u32 dst_default_metrics[RTAX_MAX]; -void *dst_alloc(struct dst_ops *ops, int initial_ref) +void *dst_alloc(struct dst_ops *ops, struct net_device *dev, + int initial_ref, int initial_obsolete, int flags) { struct dst_entry *dst; @@ -177,12 +178,19 @@ void *dst_alloc(struct dst_ops *ops, int initial_ref) dst = kmem_cache_zalloc(ops->kmem_cachep, GFP_ATOMIC); if (!dst) return NULL; - atomic_set(&dst->__refcnt, initial_ref); dst->ops = ops; - dst->lastuse = jiffies; - dst->path = dst; - dst->input = dst->output = dst_discard; + dst->dev = dev; + if (dev) + dev_hold(dev); dst_init_metrics(dst, dst_default_metrics, true); + dst->path = dst; + dst->input = dst_discard; + dst->output = dst_discard; + + dst->obsolete = initial_obsolete; + atomic_set(&dst->__refcnt, initial_ref); + dst->lastuse = jiffies; + dst->flags = flags; #if RT_CACHE_DEBUG >= 2 atomic_inc(&dst_total); #endif diff --git a/net/decnet/dn_route.c b/net/decnet/dn_route.c index 9f09d4f..f489b08 100644 --- a/net/decnet/dn_route.c +++ b/net/decnet/dn_route.c @@ -1125,13 +1125,10 @@ make_route: if (dev_out->flags & IFF_LOOPBACK) flags |= RTCF_LOCAL; - rt = dst_alloc(&dn_dst_ops, 0); + rt = dst_alloc(&dn_dst_ops, dev_out, 1, 0, DST_HOST); if (rt == NULL) goto e_nobufs; - atomic_set(&rt->dst.__refcnt, 1); - rt->dst.flags = DST_HOST; - rt->fld.saddr = oldflp->saddr; rt->fld.daddr = oldflp->daddr; rt->fld.flowidn_oif = oldflp->flowidn_oif; @@ -1146,8 +1143,6 @@ make_route: rt->rt_dst_map = fld.daddr; rt->rt_src_map = fld.saddr; - rt->dst.dev = dev_out; - dev_hold(dev_out); rt->dst.neighbour = neigh; neigh = NULL; @@ -1399,7 +1394,7 @@ static int dn_route_input_slow(struct sk_buff *skb) } make_route: - rt = dst_alloc(&dn_dst_ops, 0); + rt = dst_alloc(&dn_dst_ops, out_dev, 0, 0, DST_HOST); if (rt == NULL) goto e_nobufs; @@ -1419,9 +1414,7 @@ make_route: rt->fld.flowidn_iif = in_dev->ifindex; rt->fld.flowidn_mark = fld.flowidn_mark; - rt->dst.flags = DST_HOST; rt->dst.neighbour = neigh; - rt->dst.dev = out_dev; rt->dst.lastuse = jiffies; rt->dst.output = dn_rt_bug; switch(res.type) { @@ -1440,8 +1433,6 @@ make_route: rt->dst.input = dst_discard; } rt->rt_flags = flags; - if (rt->dst.dev) - dev_hold(rt->dst.dev); err = dn_rt_set_next_hop(rt, &res); if (err) diff --git a/net/ipv4/route.c b/net/ipv4/route.c index d63f780..b471d89 100644 --- a/net/ipv4/route.c +++ b/net/ipv4/route.c @@ -1833,17 +1833,13 @@ static void rt_set_nexthop(struct rtable *rt, const struct flowi4 *oldflp4, rt->rt_type = type; } -static struct rtable *rt_dst_alloc(bool nopolicy, bool noxfrm) +static struct rtable *rt_dst_alloc(struct net_device *dev, + bool nopolicy, bool noxfrm) { - struct rtable *rt = dst_alloc(&ipv4_dst_ops, 1); - if (rt) { - rt->dst.obsolete = -1; - - rt->dst.flags = DST_HOST | - (nopolicy ? DST_NOPOLICY : 0) | - (noxfrm ? DST_NOXFRM : 0); - } - return rt; + return dst_alloc(&ipv4_dst_ops, dev, 1, -1, + DST_HOST | + (nopolicy ? DST_NOPOLICY : 0) | + (noxfrm ? DST_NOXFRM : 0)); } /* called in rcu_read_lock() section */ @@ -1876,7 +1872,8 @@ static int ip_route_input_mc(struct sk_buff *skb, __be32 daddr, __be32 saddr, if (err < 0) goto e_err; } - rth = rt_dst_alloc(IN_DEV_CONF_GET(in_dev, NOPOLICY), false); + rth = rt_dst_alloc(init_net.loopback_dev, + IN_DEV_CONF_GET(in_dev, NOPOLICY), false); if (!rth) goto e_nobufs; @@ -1893,8 +1890,6 @@ static int ip_route_input_mc(struct sk_buff *skb, __be32 daddr, __be32 saddr, #endif rth->rt_route_iif = dev->ifindex; rth->rt_iif = dev->ifindex; - rth->dst.dev = init_net.loopback_dev; - dev_hold(rth->dst.dev); rth->rt_oif = 0; rth->rt_gateway = daddr; rth->rt_spec_dst= spec_dst; @@ -2013,7 +2008,8 @@ static int __mkroute_input(struct sk_buff *skb, } } - rth = rt_dst_alloc(IN_DEV_CONF_GET(in_dev, NOPOLICY), + rth = rt_dst_alloc(out_dev->dev, + IN_DEV_CONF_GET(in_dev, NOPOLICY), IN_DEV_CONF_GET(out_dev, NOXFRM)); if (!rth) { err = -ENOBUFS; @@ -2029,8 +2025,6 @@ static int __mkroute_input(struct sk_buff *skb, rth->rt_gateway = daddr; rth->rt_route_iif = in_dev->dev->ifindex; rth->rt_iif = in_dev->dev->ifindex; - rth->dst.dev = (out_dev)->dev; - dev_hold(rth->dst.dev); rth->rt_oif = 0; rth->rt_spec_dst= spec_dst; @@ -2188,7 +2182,8 @@ brd_input: RT_CACHE_STAT_INC(in_brd); local_input: - rth = rt_dst_alloc(IN_DEV_CONF_GET(in_dev, NOPOLICY), false); + rth = rt_dst_alloc(net->loopback_dev, + IN_DEV_CONF_GET(in_dev, NOPOLICY), false); if (!rth) goto e_nobufs; @@ -2206,8 +2201,6 @@ local_input: #endif rth->rt_route_iif = dev->ifindex; rth->rt_iif = dev->ifindex; - rth->dst.dev = net->loopback_dev; - dev_hold(rth->dst.dev); rth->rt_gateway = daddr; rth->rt_spec_dst= spec_dst; rth->dst.input= ip_local_deliver; @@ -2392,7 +2385,8 @@ static struct rtable *__mkroute_output(const struct fib_result *res, fi = NULL; } - rth = rt_dst_alloc(IN_DEV_CONF_GET(in_dev, NOPOLICY), + rth = rt_dst_alloc(dev_out, + IN_DEV_CONF_GET(in_dev, NOPOLICY), IN_DEV_CONF_GET(in_dev, NOXFRM)); if (!rth) return ERR_PTR(-ENOBUFS); @@ -2406,10 +2400,6 @@ static struct rtable *__mkroute_output(const struct fib_result *res, rth->rt_src = fl4->saddr; rth->rt_route_iif = 0; rth->rt_iif = oldflp4->flowi4_oif ? : dev_out->ifindex; - /* get references to the devices that are to be hold by the routing - cache entry */ - rth->dst.dev = dev_out; - dev_hold(dev_out); rth->rt_gateway = fl4->daddr; rth->rt_spec_dst= fl4->saddr; @@ -2711,7 +2701,7 @@ static struct dst_ops ipv4_dst_blackhole_ops = { struct dst_entry *ipv4_blackhole_route(struct net *net, struct dst_entry *dst_orig) { - struct rtable *rt = dst_alloc(&ipv4_dst_blackhole_ops, 1); + struct rtable *rt = dst_alloc(&ipv4_dst_blackhole_ops, NULL, 1, 0, 0); struct rtable *ort = (struct rtable *) dst_orig; if (rt) { diff --git a/net/ipv6/route.c b/net/ipv6/route.c index 19a77d0..e8b2bb9 100644 --- a/net/ipv6/route.c +++ b/net/ipv6/route.c @@ -227,9 +227,10 @@ static struct rt6_info ip6_blk_hole_entry_template = { #endif /* allocate dst with ip6_dst_ops */ -static inline struct rt6_info *ip6_dst_alloc(struct dst_ops *ops) +static inline struct rt6_info *ip6_dst_alloc(struct dst_ops *ops, + struct net_device *dev) { - return (struct rt6_info *)dst_alloc(ops, 0); + return (struct rt6_info *)dst_alloc(ops, dev, 0, 0, 0); } static void ip6_dst_destroy(struct dst_entry *dst) @@ -881,10 +882,10 @@ EXPORT_SYMBOL(ip6_route_output); struct dst_entry *ip6_blackhole_route(struct net *net, struct dst_entry *dst_orig) { - struct rt6_info *rt = dst_alloc(&ip6_dst_blackhole_ops, 1); - struct rt6_info *ort = (struct rt6_info *) dst_orig; + struct rt6_info *rt, *ort = (struct rt6_info *) dst_orig; struct dst_entry *new = NULL; + rt = dst_alloc(&ip6_dst_blackhole_ops, ort->dst.dev, 1, 0, 0); if (rt) { new = &rt->dst; @@ -893,9 +894,6 @@ struct dst_entry *ip6_blackhole_route(struct net *net, struct dst_entry *dst_ori new->output = dst_discard; dst_copy_metrics(new, &ort->dst); - new->dev = ort->dst.dev; - if (new->dev) - dev_hold(new->dev); rt->rt6i_idev = ort->rt6i_idev; if (rt->rt6i_idev) in6_dev_hold(rt->rt6i_idev); @@ -1038,13 +1036,12 @@ struct dst_entry *icmp6_dst_alloc(struct net_device *dev, if (unlikely(idev == NULL)) return NULL; - rt = ip6_dst_alloc(&net->ipv6.ip6_dst_ops); + rt = ip6_dst_alloc(&net->ipv6.ip6_dst_ops, dev); if (unlikely(rt == NULL)) { in6_dev_put(idev); goto out; } - dev_hold(dev); if (neigh) neigh_hold(neigh); else { @@ -1053,7 +1050,6 @@ struct dst_entry *icmp6_dst_alloc(struct net_device *dev, neigh = NULL; } - rt->rt6i_dev = dev; rt->rt6i_idev = idev; rt->rt6i_nexthop = neigh; atomic_set(&rt->dst.__refcnt, 1); @@ -1212,7 +1208,7 @@ int ip6_route_add(struct fib6_config *cfg) goto out; } - rt = ip6_dst_alloc(&net->ipv6.ip6_dst_ops); + rt = ip6_dst_alloc(&net->ipv6.ip6_dst_ops, NULL); if (rt == NULL) { err = -ENOMEM; @@ -1731,7 +1727,8 @@ void rt6_pmtu_discovery(const struct in6_addr *daddr, const struct in6_addr *sad static struct rt6_info * ip6_rt_copy(struct rt6_info *ort) { struct net *net = dev_net(ort->rt6i_dev); - struct rt6_info *rt = ip6_dst_alloc(&net->ipv6.ip6_dst_ops); + struct rt6_info *rt = ip6_dst_alloc(&net->ipv6.ip6_dst_ops, + ort->dst.dev); if (rt) { rt->dst.input = ort->dst.input; @@ -1739,9 +1736,6 @@ static struct rt6_info * ip6_rt_copy(struct rt6_info *ort) dst_copy_metrics(&rt->dst, &ort->dst); rt->dst.error = ort->dst.error; - rt->dst.dev = ort->dst.dev; - if (rt->dst.dev) - dev_hold(rt->dst.dev); rt->rt6i_idev = ort->rt6i_idev; if (rt->rt6i_idev) in6_dev_hold(rt->rt6i_idev); @@ -2011,7 +2005,8 @@ struct rt6_info *addrconf_dst_alloc(struct inet6_dev *idev, int anycast) { struct net *net = dev_net(idev->dev); - struct rt6_info *rt = ip6_dst_alloc(&net->ipv6.ip6_dst_ops); + struct rt6_info *rt = ip6_dst_alloc(&net->ipv6.ip6_dst_ops, + net->loopback_dev); struct neighbour *neigh; if (rt == NULL) { @@ -2021,13 +2016,11 @@ struct rt6_info *addrconf_dst_alloc(struct inet6_dev *idev, return ERR_PTR(-ENOMEM); } - dev_hold(net->loopback_dev); in6_dev_hold(idev); rt->dst.flags = DST_HOST; rt->dst.input = ip6_input; rt->dst.output = ip6_output; - rt->rt6i_dev = net->loopback_dev; rt->rt6i_idev = idev; rt->dst.obsolete = -1; diff --git a/net/xfrm/xfrm_policy.c b/net/xfrm/xfrm_policy.c index 15792d8..70552c4 100644 --- a/net/xfrm/xfrm_policy.c +++ b/net/xfrm/xfrm_policy.c @@ -1348,7 +1348,7 @@ static inline struct xfrm_dst *xfrm_alloc_dst(struct net *net, int family) default: BUG(); } - xdst = dst_alloc(dst_ops, 0); + xdst = dst_alloc(dst_ops, NULL, 0, 0, 0); xfrm_policy_put_afinfo(afinfo); if (likely(xdst)) -- cgit v0.10.2 From cf91166223772ef4a2ed98b9874958bf6a2470df Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Thu, 28 Apr 2011 14:31:47 -0700 Subject: net: Use non-zero allocations in dst_alloc(). Make dst_alloc() and it's users explicitly initialize the entire entry. The zero'ing done by kmem_cache_zalloc() was almost entirely redundant. Signed-off-by: David S. Miller diff --git a/net/core/dst.c b/net/core/dst.c index 9505778..30f0093 100644 --- a/net/core/dst.c +++ b/net/core/dst.c @@ -175,22 +175,36 @@ void *dst_alloc(struct dst_ops *ops, struct net_device *dev, if (ops->gc(ops)) return NULL; } - dst = kmem_cache_zalloc(ops->kmem_cachep, GFP_ATOMIC); + dst = kmem_cache_alloc(ops->kmem_cachep, GFP_ATOMIC); if (!dst) return NULL; - dst->ops = ops; + dst->child = NULL; dst->dev = dev; if (dev) dev_hold(dev); + dst->ops = ops; dst_init_metrics(dst, dst_default_metrics, true); + dst->expires = 0UL; dst->path = dst; + dst->neighbour = NULL; + dst->hh = NULL; +#ifdef CONFIG_XFRM + dst->xfrm = NULL; +#endif dst->input = dst_discard; dst->output = dst_discard; - + dst->error = 0; dst->obsolete = initial_obsolete; + dst->header_len = 0; + dst->trailer_len = 0; +#ifdef CONFIG_IP_ROUTE_CLASSID + dst->tclassid = 0; +#endif atomic_set(&dst->__refcnt, initial_ref); + dst->__use = 0; dst->lastuse = jiffies; dst->flags = flags; + dst->next = NULL; #if RT_CACHE_DEBUG >= 2 atomic_inc(&dst_total); #endif diff --git a/net/decnet/dn_route.c b/net/decnet/dn_route.c index f489b08..74544bc 100644 --- a/net/decnet/dn_route.c +++ b/net/decnet/dn_route.c @@ -1129,6 +1129,7 @@ make_route: if (rt == NULL) goto e_nobufs; + memset(&rt->fld, 0, sizeof(rt->fld)); rt->fld.saddr = oldflp->saddr; rt->fld.daddr = oldflp->daddr; rt->fld.flowidn_oif = oldflp->flowidn_oif; @@ -1398,6 +1399,7 @@ make_route: if (rt == NULL) goto e_nobufs; + memset(&rt->fld, 0, sizeof(rt->fld)); rt->rt_saddr = fld.saddr; rt->rt_daddr = fld.daddr; rt->rt_gateway = fld.daddr; diff --git a/net/ipv4/route.c b/net/ipv4/route.c index b471d89..fb9211a 100644 --- a/net/ipv4/route.c +++ b/net/ipv4/route.c @@ -1830,7 +1830,6 @@ static void rt_set_nexthop(struct rtable *rt, const struct flowi4 *oldflp4, #endif set_class_tag(rt, itag); #endif - rt->rt_type = type; } static struct rtable *rt_dst_alloc(struct net_device *dev, @@ -1877,25 +1876,28 @@ static int ip_route_input_mc(struct sk_buff *skb, __be32 daddr, __be32 saddr, if (!rth) goto e_nobufs; +#ifdef CONFIG_IP_ROUTE_CLASSID + rth->dst.tclassid = itag; +#endif rth->dst.output = ip_rt_bug; rth->rt_key_dst = daddr; - rth->rt_dst = daddr; - rth->rt_tos = tos; - rth->rt_mark = skb->mark; rth->rt_key_src = saddr; + rth->rt_genid = rt_genid(dev_net(dev)); + rth->rt_flags = RTCF_MULTICAST; + rth->rt_type = RTN_MULTICAST; + rth->rt_tos = tos; + rth->rt_dst = daddr; rth->rt_src = saddr; -#ifdef CONFIG_IP_ROUTE_CLASSID - rth->dst.tclassid = itag; -#endif rth->rt_route_iif = dev->ifindex; rth->rt_iif = dev->ifindex; rth->rt_oif = 0; + rth->rt_mark = skb->mark; rth->rt_gateway = daddr; rth->rt_spec_dst= spec_dst; - rth->rt_genid = rt_genid(dev_net(dev)); - rth->rt_flags = RTCF_MULTICAST; - rth->rt_type = RTN_MULTICAST; + rth->rt_peer_genid = 0; + rth->peer = NULL; + rth->fi = NULL; if (our) { rth->dst.input= ip_local_deliver; rth->rt_flags |= RTCF_LOCAL; @@ -2017,25 +2019,28 @@ static int __mkroute_input(struct sk_buff *skb, } rth->rt_key_dst = daddr; - rth->rt_dst = daddr; - rth->rt_tos = tos; - rth->rt_mark = skb->mark; rth->rt_key_src = saddr; + rth->rt_genid = rt_genid(dev_net(rth->dst.dev)); + rth->rt_flags = flags; + rth->rt_type = res->type; + rth->rt_tos = tos; + rth->rt_dst = daddr; rth->rt_src = saddr; - rth->rt_gateway = daddr; rth->rt_route_iif = in_dev->dev->ifindex; rth->rt_iif = in_dev->dev->ifindex; rth->rt_oif = 0; + rth->rt_mark = skb->mark; + rth->rt_gateway = daddr; rth->rt_spec_dst= spec_dst; + rth->rt_peer_genid = 0; + rth->peer = NULL; + rth->fi = NULL; rth->dst.input = ip_forward; rth->dst.output = ip_output; - rth->rt_genid = rt_genid(dev_net(rth->dst.dev)); rt_set_nexthop(rth, NULL, res, res->fi, res->type, itag); - rth->rt_flags = flags; - *result = rth; err = 0; cleanup: @@ -2187,30 +2192,37 @@ local_input: if (!rth) goto e_nobufs; + rth->dst.input= ip_local_deliver; rth->dst.output= ip_rt_bug; - rth->rt_genid = rt_genid(net); +#ifdef CONFIG_IP_ROUTE_CLASSID + rth->dst.tclassid = itag; +#endif rth->rt_key_dst = daddr; - rth->rt_dst = daddr; - rth->rt_tos = tos; - rth->rt_mark = skb->mark; rth->rt_key_src = saddr; + rth->rt_genid = rt_genid(net); + rth->rt_flags = flags|RTCF_LOCAL; + rth->rt_type = res.type; + rth->rt_tos = tos; + rth->rt_dst = daddr; rth->rt_src = saddr; #ifdef CONFIG_IP_ROUTE_CLASSID rth->dst.tclassid = itag; #endif rth->rt_route_iif = dev->ifindex; rth->rt_iif = dev->ifindex; + rth->rt_oif = 0; + rth->rt_mark = skb->mark; rth->rt_gateway = daddr; rth->rt_spec_dst= spec_dst; - rth->dst.input= ip_local_deliver; - rth->rt_flags = flags|RTCF_LOCAL; + rth->rt_peer_genid = 0; + rth->peer = NULL; + rth->fi = NULL; if (res.type == RTN_UNREACHABLE) { rth->dst.input= ip_error; rth->dst.error= -err; rth->rt_flags &= ~RTCF_LOCAL; } - rth->rt_type = res.type; hash = rt_hash(daddr, saddr, fl4.flowi4_iif, rt_genid(net)); rth = rt_intern_hash(hash, rth, skb, fl4.flowi4_iif); err = 0; @@ -2391,20 +2403,25 @@ static struct rtable *__mkroute_output(const struct fib_result *res, if (!rth) return ERR_PTR(-ENOBUFS); + rth->dst.output = ip_output; + rth->rt_key_dst = oldflp4->daddr; - rth->rt_tos = tos; rth->rt_key_src = oldflp4->saddr; - rth->rt_oif = oldflp4->flowi4_oif; - rth->rt_mark = oldflp4->flowi4_mark; + rth->rt_genid = rt_genid(dev_net(dev_out)); + rth->rt_flags = flags; + rth->rt_type = type; + rth->rt_tos = tos; rth->rt_dst = fl4->daddr; rth->rt_src = fl4->saddr; rth->rt_route_iif = 0; rth->rt_iif = oldflp4->flowi4_oif ? : dev_out->ifindex; + rth->rt_oif = oldflp4->flowi4_oif; + rth->rt_mark = oldflp4->flowi4_mark; rth->rt_gateway = fl4->daddr; rth->rt_spec_dst= fl4->saddr; - - rth->dst.output=ip_output; - rth->rt_genid = rt_genid(dev_net(dev_out)); + rth->rt_peer_genid = 0; + rth->peer = NULL; + rth->fi = NULL; RT_CACHE_STAT_INC(out_slow_tot); @@ -2432,7 +2449,6 @@ static struct rtable *__mkroute_output(const struct fib_result *res, rt_set_nexthop(rth, oldflp4, res, fi, type, 0); - rth->rt_flags = flags; return rth; } diff --git a/net/ipv6/route.c b/net/ipv6/route.c index e8b2bb9..f1be5c5 100644 --- a/net/ipv6/route.c +++ b/net/ipv6/route.c @@ -230,7 +230,11 @@ static struct rt6_info ip6_blk_hole_entry_template = { static inline struct rt6_info *ip6_dst_alloc(struct dst_ops *ops, struct net_device *dev) { - return (struct rt6_info *)dst_alloc(ops, dev, 0, 0, 0); + struct rt6_info *rt = dst_alloc(ops, dev, 0, 0, 0); + + memset(&rt->rt6i_table, 0, sizeof(*rt) - sizeof(struct dst_entry)); + + return rt; } static void ip6_dst_destroy(struct dst_entry *dst) @@ -887,6 +891,8 @@ struct dst_entry *ip6_blackhole_route(struct net *net, struct dst_entry *dst_ori rt = dst_alloc(&ip6_dst_blackhole_ops, ort->dst.dev, 1, 0, 0); if (rt) { + memset(&rt->rt6i_table, 0, sizeof(*rt) - sizeof(struct dst_entry)); + new = &rt->dst; new->__use = 1; diff --git a/net/xfrm/xfrm_policy.c b/net/xfrm/xfrm_policy.c index 70552c4..00bcb88 100644 --- a/net/xfrm/xfrm_policy.c +++ b/net/xfrm/xfrm_policy.c @@ -1349,6 +1349,7 @@ static inline struct xfrm_dst *xfrm_alloc_dst(struct net *net, int family) BUG(); } xdst = dst_alloc(dst_ops, NULL, 0, 0, 0); + memset(&xdst->u.rt6.rt6i_table, 0, sizeof(*xdst) - sizeof(struct dst_entry)); xfrm_policy_put_afinfo(afinfo); if (likely(xdst)) -- cgit v0.10.2 From 813b3b5db831ddbd92b5ce0fdeb74e3368f1323c Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Thu, 28 Apr 2011 14:48:42 -0700 Subject: ipv4: Use caller's on-stack flowi as-is in output route lookups. Signed-off-by: David S. Miller diff --git a/include/net/route.h b/include/net/route.h index fdbdb92..81b6cf2 100644 --- a/include/net/route.h +++ b/include/net/route.h @@ -115,7 +115,7 @@ extern void ip_rt_redirect(__be32 old_gw, __be32 dst, __be32 new_gw, __be32 src, struct net_device *dev); extern void rt_cache_flush(struct net *net, int how); extern void rt_cache_flush_batch(struct net *net); -extern struct rtable *__ip_route_output_key(struct net *, const struct flowi4 *flp); +extern struct rtable *__ip_route_output_key(struct net *, struct flowi4 *flp); extern struct rtable *ip_route_output_flow(struct net *, struct flowi4 *flp, struct sock *sk); extern struct dst_entry *ipv4_blackhole_route(struct net *net, struct dst_entry *dst_orig); diff --git a/net/ipv4/route.c b/net/ipv4/route.c index fb9211a..93f71be 100644 --- a/net/ipv4/route.c +++ b/net/ipv4/route.c @@ -1767,7 +1767,7 @@ static unsigned int ipv4_default_mtu(const struct dst_entry *dst) return mtu; } -static void rt_init_metrics(struct rtable *rt, const struct flowi4 *oldflp4, +static void rt_init_metrics(struct rtable *rt, const struct flowi4 *fl4, struct fib_info *fi) { struct inet_peer *peer; @@ -1776,7 +1776,7 @@ static void rt_init_metrics(struct rtable *rt, const struct flowi4 *oldflp4, /* If a peer entry exists for this destination, we must hook * it up in order to get at cached metrics. */ - if (oldflp4 && (oldflp4->flowi4_flags & FLOWI_FLAG_PRECOW_METRICS)) + if (fl4 && (fl4->flowi4_flags & FLOWI_FLAG_PRECOW_METRICS)) create = 1; rt->peer = peer = inet_getpeer_v4(rt->rt_dst, create); @@ -1803,7 +1803,7 @@ static void rt_init_metrics(struct rtable *rt, const struct flowi4 *oldflp4, } } -static void rt_set_nexthop(struct rtable *rt, const struct flowi4 *oldflp4, +static void rt_set_nexthop(struct rtable *rt, const struct flowi4 *fl4, const struct fib_result *res, struct fib_info *fi, u16 type, u32 itag) { @@ -1813,7 +1813,7 @@ static void rt_set_nexthop(struct rtable *rt, const struct flowi4 *oldflp4, if (FIB_RES_GW(*res) && FIB_RES_NH(*res).nh_scope == RT_SCOPE_LINK) rt->rt_gateway = FIB_RES_GW(*res); - rt_init_metrics(rt, oldflp4, fi); + rt_init_metrics(rt, fl4, fi); #ifdef CONFIG_IP_ROUTE_CLASSID dst->tclassid = FIB_RES_NH(*res).nh_tclassid; #endif @@ -2354,12 +2354,12 @@ EXPORT_SYMBOL(ip_route_input_common); /* called with rcu_read_lock() */ static struct rtable *__mkroute_output(const struct fib_result *res, const struct flowi4 *fl4, - const struct flowi4 *oldflp4, - struct net_device *dev_out, + __be32 orig_daddr, __be32 orig_saddr, + int orig_oif, struct net_device *dev_out, unsigned int flags) { struct fib_info *fi = res->fi; - u32 tos = RT_FL_TOS(oldflp4); + u32 tos = RT_FL_TOS(fl4); struct in_device *in_dev; u16 type = res->type; struct rtable *rth; @@ -2386,8 +2386,8 @@ static struct rtable *__mkroute_output(const struct fib_result *res, fi = NULL; } else if (type == RTN_MULTICAST) { flags |= RTCF_MULTICAST | RTCF_LOCAL; - if (!ip_check_mc_rcu(in_dev, oldflp4->daddr, oldflp4->saddr, - oldflp4->flowi4_proto)) + if (!ip_check_mc_rcu(in_dev, fl4->daddr, fl4->saddr, + fl4->flowi4_proto)) flags &= ~RTCF_LOCAL; /* If multicast route do not exist use * default one, but do not gateway in this case. @@ -2405,8 +2405,8 @@ static struct rtable *__mkroute_output(const struct fib_result *res, rth->dst.output = ip_output; - rth->rt_key_dst = oldflp4->daddr; - rth->rt_key_src = oldflp4->saddr; + rth->rt_key_dst = orig_daddr; + rth->rt_key_src = orig_saddr; rth->rt_genid = rt_genid(dev_net(dev_out)); rth->rt_flags = flags; rth->rt_type = type; @@ -2414,9 +2414,9 @@ static struct rtable *__mkroute_output(const struct fib_result *res, rth->rt_dst = fl4->daddr; rth->rt_src = fl4->saddr; rth->rt_route_iif = 0; - rth->rt_iif = oldflp4->flowi4_oif ? : dev_out->ifindex; - rth->rt_oif = oldflp4->flowi4_oif; - rth->rt_mark = oldflp4->flowi4_mark; + rth->rt_iif = orig_oif ? : dev_out->ifindex; + rth->rt_oif = orig_oif; + rth->rt_mark = fl4->flowi4_mark; rth->rt_gateway = fl4->daddr; rth->rt_spec_dst= fl4->saddr; rth->rt_peer_genid = 0; @@ -2439,7 +2439,7 @@ static struct rtable *__mkroute_output(const struct fib_result *res, #ifdef CONFIG_IP_MROUTE if (type == RTN_MULTICAST) { if (IN_DEV_MFORWARD(in_dev) && - !ipv4_is_local_multicast(oldflp4->daddr)) { + !ipv4_is_local_multicast(fl4->daddr)) { rth->dst.input = ip_mr_input; rth->dst.output = ip_mc_output; } @@ -2447,7 +2447,7 @@ static struct rtable *__mkroute_output(const struct fib_result *res, #endif } - rt_set_nexthop(rth, oldflp4, res, fi, type, 0); + rt_set_nexthop(rth, fl4, res, fi, type, 0); return rth; } @@ -2457,36 +2457,37 @@ static struct rtable *__mkroute_output(const struct fib_result *res, * called with rcu_read_lock(); */ -static struct rtable *ip_route_output_slow(struct net *net, - const struct flowi4 *oldflp4) +static struct rtable *ip_route_output_slow(struct net *net, struct flowi4 *fl4) { - u32 tos = RT_FL_TOS(oldflp4); - struct flowi4 fl4; - struct fib_result res; - unsigned int flags = 0; struct net_device *dev_out = NULL; + u32 tos = RT_FL_TOS(fl4); + unsigned int flags = 0; + struct fib_result res; struct rtable *rth; + __be32 orig_daddr; + __be32 orig_saddr; + int orig_oif; res.fi = NULL; #ifdef CONFIG_IP_MULTIPLE_TABLES res.r = NULL; #endif - fl4.flowi4_oif = oldflp4->flowi4_oif; - fl4.flowi4_iif = net->loopback_dev->ifindex; - fl4.flowi4_mark = oldflp4->flowi4_mark; - fl4.daddr = oldflp4->daddr; - fl4.saddr = oldflp4->saddr; - fl4.flowi4_tos = tos & IPTOS_RT_MASK; - fl4.flowi4_scope = ((tos & RTO_ONLINK) ? - RT_SCOPE_LINK : RT_SCOPE_UNIVERSE); + orig_daddr = fl4->daddr; + orig_saddr = fl4->saddr; + orig_oif = fl4->flowi4_oif; + + fl4->flowi4_iif = net->loopback_dev->ifindex; + fl4->flowi4_tos = tos & IPTOS_RT_MASK; + fl4->flowi4_scope = ((tos & RTO_ONLINK) ? + RT_SCOPE_LINK : RT_SCOPE_UNIVERSE); rcu_read_lock(); - if (oldflp4->saddr) { + if (fl4->saddr) { rth = ERR_PTR(-EINVAL); - if (ipv4_is_multicast(oldflp4->saddr) || - ipv4_is_lbcast(oldflp4->saddr) || - ipv4_is_zeronet(oldflp4->saddr)) + if (ipv4_is_multicast(fl4->saddr) || + ipv4_is_lbcast(fl4->saddr) || + ipv4_is_zeronet(fl4->saddr)) goto out; /* I removed check for oif == dev_out->oif here. @@ -2497,11 +2498,11 @@ static struct rtable *ip_route_output_slow(struct net *net, of another iface. --ANK */ - if (oldflp4->flowi4_oif == 0 && - (ipv4_is_multicast(oldflp4->daddr) || - ipv4_is_lbcast(oldflp4->daddr))) { + if (fl4->flowi4_oif == 0 && + (ipv4_is_multicast(fl4->daddr) || + ipv4_is_lbcast(fl4->daddr))) { /* It is equivalent to inet_addr_type(saddr) == RTN_LOCAL */ - dev_out = __ip_dev_find(net, oldflp4->saddr, false); + dev_out = __ip_dev_find(net, fl4->saddr, false); if (dev_out == NULL) goto out; @@ -2520,20 +2521,20 @@ static struct rtable *ip_route_output_slow(struct net *net, Luckily, this hack is good workaround. */ - fl4.flowi4_oif = dev_out->ifindex; + fl4->flowi4_oif = dev_out->ifindex; goto make_route; } - if (!(oldflp4->flowi4_flags & FLOWI_FLAG_ANYSRC)) { + if (!(fl4->flowi4_flags & FLOWI_FLAG_ANYSRC)) { /* It is equivalent to inet_addr_type(saddr) == RTN_LOCAL */ - if (!__ip_dev_find(net, oldflp4->saddr, false)) + if (!__ip_dev_find(net, fl4->saddr, false)) goto out; } } - if (oldflp4->flowi4_oif) { - dev_out = dev_get_by_index_rcu(net, oldflp4->flowi4_oif); + if (fl4->flowi4_oif) { + dev_out = dev_get_by_index_rcu(net, fl4->flowi4_oif); rth = ERR_PTR(-ENODEV); if (dev_out == NULL) goto out; @@ -2543,37 +2544,37 @@ static struct rtable *ip_route_output_slow(struct net *net, rth = ERR_PTR(-ENETUNREACH); goto out; } - if (ipv4_is_local_multicast(oldflp4->daddr) || - ipv4_is_lbcast(oldflp4->daddr)) { - if (!fl4.saddr) - fl4.saddr = inet_select_addr(dev_out, 0, - RT_SCOPE_LINK); + if (ipv4_is_local_multicast(fl4->daddr) || + ipv4_is_lbcast(fl4->daddr)) { + if (!fl4->saddr) + fl4->saddr = inet_select_addr(dev_out, 0, + RT_SCOPE_LINK); goto make_route; } - if (!fl4.saddr) { - if (ipv4_is_multicast(oldflp4->daddr)) - fl4.saddr = inet_select_addr(dev_out, 0, - fl4.flowi4_scope); - else if (!oldflp4->daddr) - fl4.saddr = inet_select_addr(dev_out, 0, - RT_SCOPE_HOST); + if (fl4->saddr) { + if (ipv4_is_multicast(fl4->daddr)) + fl4->saddr = inet_select_addr(dev_out, 0, + fl4->flowi4_scope); + else if (!fl4->daddr) + fl4->saddr = inet_select_addr(dev_out, 0, + RT_SCOPE_HOST); } } - if (!fl4.daddr) { - fl4.daddr = fl4.saddr; - if (!fl4.daddr) - fl4.daddr = fl4.saddr = htonl(INADDR_LOOPBACK); + if (!fl4->daddr) { + fl4->daddr = fl4->saddr; + if (!fl4->daddr) + fl4->daddr = fl4->saddr = htonl(INADDR_LOOPBACK); dev_out = net->loopback_dev; - fl4.flowi4_oif = net->loopback_dev->ifindex; + fl4->flowi4_oif = net->loopback_dev->ifindex; res.type = RTN_LOCAL; flags |= RTCF_LOCAL; goto make_route; } - if (fib_lookup(net, &fl4, &res)) { + if (fib_lookup(net, fl4, &res)) { res.fi = NULL; - if (oldflp4->flowi4_oif) { + if (fl4->flowi4_oif) { /* Apparently, routing tables are wrong. Assume, that the destination is on link. @@ -2592,9 +2593,9 @@ static struct rtable *ip_route_output_slow(struct net *net, likely IPv6, but we do not. */ - if (fl4.saddr == 0) - fl4.saddr = inet_select_addr(dev_out, 0, - RT_SCOPE_LINK); + if (fl4->saddr == 0) + fl4->saddr = inet_select_addr(dev_out, 0, + RT_SCOPE_LINK); res.type = RTN_UNICAST; goto make_route; } @@ -2603,44 +2604,45 @@ static struct rtable *ip_route_output_slow(struct net *net, } if (res.type == RTN_LOCAL) { - if (!fl4.saddr) { + if (!fl4->saddr) { if (res.fi->fib_prefsrc) - fl4.saddr = res.fi->fib_prefsrc; + fl4->saddr = res.fi->fib_prefsrc; else - fl4.saddr = fl4.daddr; + fl4->saddr = fl4->daddr; } dev_out = net->loopback_dev; - fl4.flowi4_oif = dev_out->ifindex; + fl4->flowi4_oif = dev_out->ifindex; res.fi = NULL; flags |= RTCF_LOCAL; goto make_route; } #ifdef CONFIG_IP_ROUTE_MULTIPATH - if (res.fi->fib_nhs > 1 && fl4.flowi4_oif == 0) + if (res.fi->fib_nhs > 1 && fl4->flowi4_oif == 0) fib_select_multipath(&res); else #endif if (!res.prefixlen && res.table->tb_num_default > 1 && - res.type == RTN_UNICAST && !fl4.flowi4_oif) + res.type == RTN_UNICAST && !fl4->flowi4_oif) fib_select_default(&res); - if (!fl4.saddr) - fl4.saddr = FIB_RES_PREFSRC(net, res); + if (!fl4->saddr) + fl4->saddr = FIB_RES_PREFSRC(net, res); dev_out = FIB_RES_DEV(res); - fl4.flowi4_oif = dev_out->ifindex; + fl4->flowi4_oif = dev_out->ifindex; make_route: - rth = __mkroute_output(&res, &fl4, oldflp4, dev_out, flags); + rth = __mkroute_output(&res, fl4, orig_daddr, orig_saddr, orig_oif, + dev_out, flags); if (!IS_ERR(rth)) { unsigned int hash; - hash = rt_hash(oldflp4->daddr, oldflp4->saddr, oldflp4->flowi4_oif, + hash = rt_hash(orig_daddr, orig_saddr, orig_oif, rt_genid(dev_net(dev_out))); - rth = rt_intern_hash(hash, rth, NULL, oldflp4->flowi4_oif); + rth = rt_intern_hash(hash, rth, NULL, orig_oif); } out: @@ -2648,7 +2650,7 @@ out: return rth; } -struct rtable *__ip_route_output_key(struct net *net, const struct flowi4 *flp4) +struct rtable *__ip_route_output_key(struct net *net, struct flowi4 *flp4) { struct rtable *rth; unsigned int hash; -- cgit v0.10.2 From c7a7b814c9dca9ee01b38e63b4a46de87156d3b6 Mon Sep 17 00:00:00 2001 From: Tim Gardner Date: Thu, 28 Apr 2011 11:00:30 -0600 Subject: ioremap: Delay sanity check until after a successful mapping While tracking down the reason for an ioremap() failure I was distracted by the WARN_ONCE() in __ioremap_caller(). Performing a WARN_ONCE() sanity check before the mapping is successful seems pointless if the caller sends bad values. A case in point is when the BIOS provides erroneous screen_info values causing vesafb_probe() to request an outrageuous size. The WARN_ONCE is then wasted on bogosity. Move the warning to a point where the mapping has been successfully allocated. Addresses: http://bugs.launchpad.net/bugs/772042 Reviewed-by: Suresh Siddha Signed-off-by: Tim Gardner Link: http://lkml.kernel.org/r/4DB99D2E.9080106@canonical.com Signed-off-by: Ingo Molnar diff --git a/arch/x86/mm/ioremap.c b/arch/x86/mm/ioremap.c index 0369843..be1ef57 100644 --- a/arch/x86/mm/ioremap.c +++ b/arch/x86/mm/ioremap.c @@ -91,13 +91,6 @@ static void __iomem *__ioremap_caller(resource_size_t phys_addr, return (__force void __iomem *)phys_to_virt(phys_addr); /* - * Check if the request spans more than any BAR in the iomem resource - * tree. - */ - WARN_ONCE(iomem_map_sanity_check(phys_addr, size), - KERN_INFO "Info: mapping multiple BARs. Your kernel is fine."); - - /* * Don't allow anybody to remap normal RAM that we're using.. */ last_pfn = last_addr >> PAGE_SHIFT; @@ -170,6 +163,13 @@ static void __iomem *__ioremap_caller(resource_size_t phys_addr, ret_addr = (void __iomem *) (vaddr + offset); mmiotrace_ioremap(unaligned_phys_addr, unaligned_size, ret_addr); + /* + * Check if the request spans more than any BAR in the iomem resource + * tree. + */ + WARN_ONCE(iomem_map_sanity_check(unaligned_phys_addr, unaligned_size), + KERN_INFO "Info: mapping multiple BARs. Your kernel is fine."); + return ret_addr; err_free_area: free_vm_area(area); -- cgit v0.10.2 From 6706b6ebab85dfca4e2886e35ec9c3c4ee13e27e Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Thu, 28 Apr 2011 23:13:17 -0700 Subject: ipv4: Remove now superfluous code in ip_route_connect(). Now that output route lookups update the flow with source address et al. selections, the fl4->{saddr,daddr} assignments here are no longer necessary. Signed-off-by: David S. Miller diff --git a/include/net/route.h b/include/net/route.h index 81b6cf2..16eb59c 100644 --- a/include/net/route.h +++ b/include/net/route.h @@ -271,8 +271,6 @@ static inline struct rtable *ip_route_connect(struct flowi4 *fl4, rt = __ip_route_output_key(net, fl4); if (IS_ERR(rt)) return rt; - fl4->daddr = rt->rt_dst; - fl4->saddr = rt->rt_src; ip_rt_put(rt); } security_sk_classify_flow(sk, flowi4_to_flowi(fl4)); -- cgit v0.10.2 From b883187785004cacea053569f1655fada0dfc299 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Thu, 28 Apr 2011 23:16:53 -0700 Subject: ipv4: Fetch route saddr from flow key in inet_sk_reselect_saddr(). Now that output route lookups update the flow with source address selection, we can fetch it from fl4->saddr instead of rt->rt_src Signed-off-by: David S. Miller diff --git a/net/ipv4/af_inet.c b/net/ipv4/af_inet.c index 963a621..4e73499 100644 --- a/net/ipv4/af_inet.c +++ b/net/ipv4/af_inet.c @@ -1122,7 +1122,7 @@ static int inet_sk_reselect_saddr(struct sock *sk) sk_setup_caps(sk, &rt->dst); - new_saddr = rt->rt_src; + new_saddr = fl4.saddr; if (new_saddr == old_saddr) return 0; -- cgit v0.10.2 From a406b611b5f26a18773e4237d79f6df3eaed1d32 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Thu, 28 Apr 2011 23:17:16 -0700 Subject: ipv4: Fetch route saddr from flow key in ip4_datagram_connect(). Now that output route lookups update the flow with source address selection, we can fetch it from fl4->saddr instead of rt->rt_src Signed-off-by: David S. Miller diff --git a/net/ipv4/datagram.c b/net/ipv4/datagram.c index 216ba23..b7f583c 100644 --- a/net/ipv4/datagram.c +++ b/net/ipv4/datagram.c @@ -63,9 +63,9 @@ int ip4_datagram_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len) return -EACCES; } if (!inet->inet_saddr) - inet->inet_saddr = rt->rt_src; /* Update source address */ + inet->inet_saddr = fl4.saddr; /* Update source address */ if (!inet->inet_rcv_saddr) { - inet->inet_rcv_saddr = rt->rt_src; + inet->inet_rcv_saddr = fl4.saddr; if (sk->sk_prot->rehash) sk->sk_prot->rehash(sk); } -- cgit v0.10.2 From 4071cfff84c5b084762fe288781cd7faab14cb4b Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Thu, 28 Apr 2011 23:17:31 -0700 Subject: ipv4: Fetch route saddr from flow key in tcp_v4_connect(). Now that output route lookups update the flow with source address selection, we can fetch it from fl4->saddr instead of rt->rt_src Signed-off-by: David S. Miller diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c index d60732f..3be00af 100644 --- a/net/ipv4/tcp_ipv4.c +++ b/net/ipv4/tcp_ipv4.c @@ -193,7 +193,7 @@ int tcp_v4_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len) daddr = rt->rt_dst; if (!inet->inet_saddr) - inet->inet_saddr = rt->rt_src; + inet->inet_saddr = fl4.saddr; inet->inet_rcv_saddr = inet->inet_saddr; if (tp->rx_opt.ts_recent_stamp && inet->inet_daddr != daddr) { -- cgit v0.10.2 From 44901666a1a736b3f43eac7894b07183f127e9a9 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Thu, 28 Apr 2011 23:17:58 -0700 Subject: ipv4: Fetch route saddr from flow key in l2tp_ip_connect(). Now that output route lookups update the flow with source address selection, we can fetch it from fl4->saddr instead of rt->rt_src Signed-off-by: David S. Miller diff --git a/net/l2tp/l2tp_ip.c b/net/l2tp/l2tp_ip.c index e13c166..c100fa9 100644 --- a/net/l2tp/l2tp_ip.c +++ b/net/l2tp/l2tp_ip.c @@ -340,9 +340,9 @@ static int l2tp_ip_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len l2tp_ip_sk(sk)->peer_conn_id = lsa->l2tp_conn_id; if (!inet->inet_saddr) - inet->inet_saddr = rt->rt_src; + inet->inet_saddr = fl4.saddr; if (!inet->inet_rcv_saddr) - inet->inet_rcv_saddr = rt->rt_src; + inet->inet_rcv_saddr = fl4.saddr; inet->inet_daddr = rt->rt_dst; sk->sk_state = TCP_ESTABLISHED; inet->inet_id = jiffies; -- cgit v0.10.2 From a7e985e18fbfda71313a399688a6233802e7fbd0 Mon Sep 17 00:00:00 2001 From: Daniel Cordero Date: Fri, 29 Apr 2011 08:18:06 +0200 Subject: ALSA: hda: add beep quirk for Realtek 0x1043:831a PC Beep was not being reported as enabled on my EeePC 901: SKU: enable_pcbeep=0x0 Signed-off-by: Daniel Cordero Signed-off-by: Takashi Iwai diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index d3bd2c1..0735222 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -5645,6 +5645,7 @@ static void fillup_priv_adc_nids(struct hda_codec *codec, hda_nid_t *nids, static struct snd_pci_quirk beep_white_list[] = { SND_PCI_QUIRK(0x1043, 0x829f, "ASUS", 1), SND_PCI_QUIRK(0x1043, 0x83ce, "EeePC", 1), + SND_PCI_QUIRK(0x1043, 0x831a, "EeePC", 1), SND_PCI_QUIRK(0x8086, 0xd613, "Intel", 1), {} }; -- cgit v0.10.2 From 91ab0b60a12833b4715b838474f23496af8de30c Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Thu, 28 Apr 2011 23:49:30 -0700 Subject: ipv4: Get route daddr from flow key in dccp_v4_connect(). Now that output route lookups update the flow with destination address selection, we can fetch it from fl4->daddr instead of rt->rt_dst Signed-off-by: David S. Miller diff --git a/net/dccp/ipv4.c b/net/dccp/ipv4.c index cbbcc6c..f4254bb 100644 --- a/net/dccp/ipv4.c +++ b/net/dccp/ipv4.c @@ -83,7 +83,7 @@ int dccp_v4_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len) } if (inet_opt == NULL || !inet_opt->opt.srr) - daddr = rt->rt_dst; + daddr = fl4.daddr; if (inet->inet_saddr == 0) inet->inet_saddr = rt->rt_src; -- cgit v0.10.2 From 87321c839fb4a65b5d78c16d79d1674cf223a452 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Thu, 28 Apr 2011 23:49:45 -0700 Subject: ipv4: Get route daddr from flow key in ip4_datagram_connect(). Now that output route lookups update the flow with destination address selection, we can fetch it from fl4->daddr instead of rt->rt_dst Signed-off-by: David S. Miller diff --git a/net/ipv4/datagram.c b/net/ipv4/datagram.c index b7f583c..d5a2e69 100644 --- a/net/ipv4/datagram.c +++ b/net/ipv4/datagram.c @@ -69,7 +69,7 @@ int ip4_datagram_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len) if (sk->sk_prot->rehash) sk->sk_prot->rehash(sk); } - inet->inet_daddr = rt->rt_dst; + inet->inet_daddr = fl4.daddr; inet->inet_dport = usin->sin_port; sk->sk_state = TCP_ESTABLISHED; inet->inet_id = jiffies; -- cgit v0.10.2 From 072d8c94142a3a95151774975f6c1fd1dc1f1e1b Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Thu, 28 Apr 2011 23:50:09 -0700 Subject: ipv4: Get route daddr from flow key in inet_csk_route_req(). Now that output route lookups update the flow with destination address selection, we can fetch it from fl4->daddr instead of rt->rt_dst Signed-off-by: David S. Miller diff --git a/net/ipv4/inet_connection_sock.c b/net/ipv4/inet_connection_sock.c index 3282cb2..54944da 100644 --- a/net/ipv4/inet_connection_sock.c +++ b/net/ipv4/inet_connection_sock.c @@ -367,7 +367,7 @@ struct dst_entry *inet_csk_route_req(struct sock *sk, rt = ip_route_output_flow(net, &fl4, sk); if (IS_ERR(rt)) goto no_route; - if (opt && opt->opt.is_strictroute && rt->rt_dst != rt->rt_gateway) + if (opt && opt->opt.is_strictroute && fl4.daddr != rt->rt_gateway) goto route_err; return &rt->dst; -- cgit v0.10.2 From d4fb3d74d7a17833de2ba8cbd4f029b30feb4825 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Thu, 28 Apr 2011 23:50:32 -0700 Subject: ipv4: Get route daddr from flow key in tcp_v4_connect(). Now that output route lookups update the flow with destination address selection, we can fetch it from fl4->daddr instead of rt->rt_dst Signed-off-by: David S. Miller diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c index 3be00af..f3d16d8 100644 --- a/net/ipv4/tcp_ipv4.c +++ b/net/ipv4/tcp_ipv4.c @@ -190,7 +190,7 @@ int tcp_v4_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len) } if (!inet_opt || !inet_opt->opt.srr) - daddr = rt->rt_dst; + daddr = fl4.daddr; if (!inet->inet_saddr) inet->inet_saddr = fl4.saddr; @@ -204,7 +204,7 @@ int tcp_v4_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len) } if (tcp_death_row.sysctl_tw_recycle && - !tp->rx_opt.ts_recent_stamp && rt->rt_dst == daddr) { + !tp->rx_opt.ts_recent_stamp && fl4.daddr == daddr) { struct inet_peer *peer = rt_get_peer(rt); /* * VJ's idea. We save last timestamp seen from -- cgit v0.10.2 From ad227425c9ca907b5498e2558320b7e585d86ec9 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Thu, 28 Apr 2011 23:50:49 -0700 Subject: ipv4: Get route daddr from flow key in l2tp_ip_connect(). Now that output route lookups update the flow with destination address selection, we can fetch it from fl4->daddr instead of rt->rt_dst Signed-off-by: David S. Miller diff --git a/net/l2tp/l2tp_ip.c b/net/l2tp/l2tp_ip.c index c100fa9..a4d2dfa 100644 --- a/net/l2tp/l2tp_ip.c +++ b/net/l2tp/l2tp_ip.c @@ -343,7 +343,7 @@ static int l2tp_ip_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len inet->inet_saddr = fl4.saddr; if (!inet->inet_rcv_saddr) inet->inet_rcv_saddr = fl4.saddr; - inet->inet_daddr = rt->rt_dst; + inet->inet_daddr = fl4.daddr; sk->sk_state = TCP_ESTABLISHED; inet->inet_id = jiffies; -- cgit v0.10.2 From bf2253a6f00e8fea5b026e471e9f0d0a1b3621f2 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Fri, 29 Apr 2011 10:15:14 +0200 Subject: cdrom: always check_disk_change() on open cdrom_open() called check_disk_change() after the rest of open path succeeded which leads to the following bizarre behavior. * After media change, if the device opened without O_NONBLOCK, open_for_data() naturally fails with -ENOMEDIA and check_disk_change() is never called. The media is known to be gone and the open failure makes it obvious to the userland but device invalidation never happens. * But if the device is opened with O_NONBLOCK, all the checks are bypassed and cdrom_open() doesn't notice that the media is not there and check_disk_change() is called and invalidation happens. There's nothing to be gained by avoiding calling check_disk_change() on open failure. Common cases end up calling check_disk_change() anyway. All we get is inconsistent behavior. Fix it by moving check_disk_change() invocation to the top of cdrom_open() so that it always gets called regardless of how the rest of open proceeds. Stable: 2.6.38 Signed-off-by: Tejun Heo Reported-by: Amit Shah Tested-by: Amit Shah Cc: stable@kernel.org Signed-off-by: Jens Axboe diff --git a/drivers/cdrom/cdrom.c b/drivers/cdrom/cdrom.c index 514dd8e..75fb965 100644 --- a/drivers/cdrom/cdrom.c +++ b/drivers/cdrom/cdrom.c @@ -986,6 +986,9 @@ int cdrom_open(struct cdrom_device_info *cdi, struct block_device *bdev, fmode_t cdinfo(CD_OPEN, "entering cdrom_open\n"); + /* open is event synchronization point, check events first */ + check_disk_change(bdev); + /* if this was a O_NONBLOCK open and we should honor the flags, * do a quick open without drive/disc integrity checks. */ cdi->use_count++; @@ -1012,9 +1015,6 @@ int cdrom_open(struct cdrom_device_info *cdi, struct block_device *bdev, fmode_t cdinfo(CD_OPEN, "Use count for \"/dev/%s\" now %d\n", cdi->name, cdi->use_count); - /* Do this on open. Don't wait for mount, because they might - not be mounting, but opening with O_NONBLOCK */ - check_disk_change(bdev); return 0; err_release: if (CDROM_CAN(CDC_LOCK) && cdi->options & CDO_LOCK) { -- cgit v0.10.2 From 02e352287a40bd456eb78df705bf888bc3161d3f Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Fri, 29 Apr 2011 10:15:20 +0200 Subject: block: rescan partitions on invalidated devices on -ENOMEDIA too __blkdev_get() doesn't rescan partitions if disk->fops->open() fails, which leads to ghost partition devices lingering after medimum removal is known to both the kernel and userland. The behavior also creates a subtle inconsistency where O_NONBLOCK open, which doesn't fail even if there's no medium, clears the ghots partitions, which is exploited to work around the problem from userland. Fix it by updating __blkdev_get() to issue partition rescan after -ENOMEDIA too. This was reported in the following bz. https://bugzilla.kernel.org/show_bug.cgi?id=13029 Stable: 2.6.38 Signed-off-by: Tejun Heo Reported-by: David Zeuthen Reported-by: Martin Pitt Reported-by: Kay Sievers Tested-by: Kay Sievers Cc: Alan Cox Cc: stable@kernel.org Signed-off-by: Jens Axboe diff --git a/fs/block_dev.c b/fs/block_dev.c index 5147bdd..257b00e 100644 --- a/fs/block_dev.c +++ b/fs/block_dev.c @@ -1102,6 +1102,7 @@ static int __blkdev_get(struct block_device *bdev, fmode_t mode, int for_part) if (!bdev->bd_part) goto out_clear; + ret = 0; if (disk->fops->open) { ret = disk->fops->open(bdev, mode); if (ret == -ERESTARTSYS) { @@ -1118,9 +1119,18 @@ static int __blkdev_get(struct block_device *bdev, fmode_t mode, int for_part) put_disk(disk); goto restart; } - if (ret) - goto out_clear; } + /* + * If the device is invalidated, rescan partition + * if open succeeded or failed with -ENOMEDIUM. + * The latter is necessary to prevent ghost + * partitions on a removed medium. + */ + if (bdev->bd_invalidated && (!ret || ret == -ENOMEDIUM)) + rescan_partitions(disk, bdev); + if (ret) + goto out_clear; + if (!bdev->bd_openers) { bd_set_size(bdev,(loff_t)get_capacity(disk)<<9); bdi = blk_get_backing_dev_info(bdev); @@ -1128,8 +1138,6 @@ static int __blkdev_get(struct block_device *bdev, fmode_t mode, int for_part) bdi = &default_backing_dev_info; bdev_inode_switch_bdi(bdev->bd_inode, bdi); } - if (bdev->bd_invalidated) - rescan_partitions(disk, bdev); } else { struct block_device *whole; whole = bdget_disk(disk, 0); @@ -1153,13 +1161,14 @@ static int __blkdev_get(struct block_device *bdev, fmode_t mode, int for_part) } } else { if (bdev->bd_contains == bdev) { - if (bdev->bd_disk->fops->open) { + ret = 0; + if (bdev->bd_disk->fops->open) ret = bdev->bd_disk->fops->open(bdev, mode); - if (ret) - goto out_unlock_bdev; - } - if (bdev->bd_invalidated) + /* the same as first opener case, read comment there */ + if (bdev->bd_invalidated && (!ret || ret == -ENOMEDIUM)) rescan_partitions(bdev->bd_disk, bdev); + if (ret) + goto out_unlock_bdev; } /* only one opener holds refs to the module and disk */ module_put(disk->fops->owner); -- cgit v0.10.2 From a9851832857dc1e4efefca1713f5cff3e168a25c Mon Sep 17 00:00:00 2001 From: Heiko Carstens Date: Fri, 29 Apr 2011 10:42:19 +0200 Subject: [S390] irqstats: fix counting of pfault, dasd diag and virtio irqs pfault, dasd diag and virtio all use the same external interrupt number. The respective interrupt handlers decide by the subcode if they are meant to handle the interrupt. Counting is currently done before looking at the subcode which means each handler counts an interrupt even if it is not handling it. Fix this by moving the kstat code after the code which looks at the subcode. Signed-off-by: Heiko Carstens Signed-off-by: Martin Schwidefsky diff --git a/arch/s390/mm/fault.c b/arch/s390/mm/fault.c index 4cf85fe..ab98813 100644 --- a/arch/s390/mm/fault.c +++ b/arch/s390/mm/fault.c @@ -543,7 +543,6 @@ static void pfault_interrupt(unsigned int ext_int_code, struct task_struct *tsk; __u16 subcode; - kstat_cpu(smp_processor_id()).irqs[EXTINT_PFL]++; /* * Get the external interruption subcode & pfault * initial/completion signal bit. VM stores this @@ -553,6 +552,7 @@ static void pfault_interrupt(unsigned int ext_int_code, subcode = ext_int_code >> 16; if ((subcode & 0xff00) != __SUBCODE_MASK) return; + kstat_cpu(smp_processor_id()).irqs[EXTINT_PFL]++; /* * Get the token (= address of the task structure of the affected task). diff --git a/drivers/s390/block/dasd_diag.c b/drivers/s390/block/dasd_diag.c index 29143ed..85dddb1 100644 --- a/drivers/s390/block/dasd_diag.c +++ b/drivers/s390/block/dasd_diag.c @@ -239,7 +239,6 @@ static void dasd_ext_handler(unsigned int ext_int_code, addr_t ip; int rc; - kstat_cpu(smp_processor_id()).irqs[EXTINT_DSD]++; switch (ext_int_code >> 24) { case DASD_DIAG_CODE_31BIT: ip = (addr_t) param32; @@ -250,6 +249,7 @@ static void dasd_ext_handler(unsigned int ext_int_code, default: return; } + kstat_cpu(smp_processor_id()).irqs[EXTINT_DSD]++; if (!ip) { /* no intparm: unsolicited interrupt */ DBF_EVENT(DBF_NOTICE, "%s", "caught unsolicited " "interrupt"); diff --git a/drivers/s390/kvm/kvm_virtio.c b/drivers/s390/kvm/kvm_virtio.c index 414427d..607998f 100644 --- a/drivers/s390/kvm/kvm_virtio.c +++ b/drivers/s390/kvm/kvm_virtio.c @@ -381,10 +381,10 @@ static void kvm_extint_handler(unsigned int ext_int_code, u16 subcode; u32 param; - kstat_cpu(smp_processor_id()).irqs[EXTINT_VRT]++; subcode = ext_int_code >> 16; if ((subcode & 0xff00) != VIRTIO_SUBCODE_64) return; + kstat_cpu(smp_processor_id()).irqs[EXTINT_VRT]++; /* The LSB might be overloaded, we have to mask it */ vq = (struct virtqueue *)(param64 & ~1UL); -- cgit v0.10.2 From ce31332d3c77532d6ea97ddcb475a2b02dd358b4 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Fri, 29 Apr 2011 00:02:00 +0200 Subject: hrtimer: Initialize CLOCK_ID to HRTIMER_BASE table statically MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Sedat and Bruno reported RCU stalls which turned out to be caused by the following; sched_init() calls init_rt_bandwidth() which calls hrtimer_init() _BEFORE_ hrtimers_init() is called. While not entirely correct this worked because hrtimer_init() only accessed statically initialized data (hrtimer_bases.clock_base[CLOCK_MONOTONIC]) Commit e06383db9 (hrtimers: extend hrtimer base code to handle more then 2 clockids) added an indirection to the hrtimer_bases.clock_base lookup to avoid gap handling in the hot path. The table which is used for the translataion from CLOCK_ID to HRTIMER_BASE index is initialized at runtime in hrtimers_init(). So the early call of the scheduler code translates CLOCK_MONOTONIC to HRTIMER_BASE_REALTIME. Thus the rt_bandwith timer ends up on CLOCK_REALTIME. If the timer is armed and the wall clock time is set (e.g. ntpdate in the early boot process - which also gives the problem deterministic behaviour i.e. magic recovery after N hours), then the timer ends up with an expiry time far into the future. That breaks the RT throttler mechanism as rt runtime is accumulated and never cleared, so the rt throttler detects a false cpu hog condition and blocks all RT tasks until the timer finally expires. That in turn stalls the RCU thread of TINYRCU which leads to an huge amount of RCU callbacks piling up. Make the translation table statically initialized, so we are back to the status of <= 2.6.39. Reported-and-tested-by: Sedat Dilek Reported-by: Bruno Prémont Cc: John stultz Cc: Mike Galbraith Cc: Paul E. McKenney Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/%3Calpine.LFD.2.02.1104282353140.3005%40ionos%3E Reviewed-by: Ingo Molnar Signed-off-by: Thomas Gleixner diff --git a/kernel/hrtimer.c b/kernel/hrtimer.c index 9017478..87fdb3f 100644 --- a/kernel/hrtimer.c +++ b/kernel/hrtimer.c @@ -81,7 +81,11 @@ DEFINE_PER_CPU(struct hrtimer_cpu_base, hrtimer_bases) = } }; -static int hrtimer_clock_to_base_table[MAX_CLOCKS]; +static int hrtimer_clock_to_base_table[MAX_CLOCKS] = { + [CLOCK_REALTIME] = HRTIMER_BASE_REALTIME, + [CLOCK_MONOTONIC] = HRTIMER_BASE_MONOTONIC, + [CLOCK_BOOTTIME] = HRTIMER_BASE_BOOTTIME, +}; static inline int hrtimer_clockid_to_base(clockid_t clock_id) { @@ -1722,10 +1726,6 @@ static struct notifier_block __cpuinitdata hrtimers_nb = { void __init hrtimers_init(void) { - hrtimer_clock_to_base_table[CLOCK_REALTIME] = HRTIMER_BASE_REALTIME; - hrtimer_clock_to_base_table[CLOCK_MONOTONIC] = HRTIMER_BASE_MONOTONIC; - hrtimer_clock_to_base_table[CLOCK_BOOTTIME] = HRTIMER_BASE_BOOTTIME; - hrtimer_cpu_notify(&hrtimers_nb, (unsigned long)CPU_UP_PREPARE, (void *)(long)smp_processor_id()); register_cpu_notifier(&hrtimers_nb); -- cgit v0.10.2 From 94024cd1aefa0f8bcc9dfe46c05bd7ce3f471a1c Mon Sep 17 00:00:00 2001 From: David Henningsson Date: Fri, 29 Apr 2011 14:10:55 +0200 Subject: ALSA: HDA: Fix automute for Gateway NV79 The PCI SSID is 1025:031c and the codec SSID is 1025:031d, so the driver mistakes this for a SKU value, but looking at the numbers, this is obviously wrong. Cc: stable@kernel.org (2.6.38+) BugLink: http://bugs.launchpad.net/bugs/761861 Signed-off-by: David Henningsson Signed-off-by: Takashi Iwai diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 0735222..5c26c71 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -19480,6 +19480,7 @@ enum { ALC272_FIXUP_MARIO, ALC662_FIXUP_CZC_P10T, ALC662_FIXUP_GIGABYTE, + ALC662_FIXUP_SKU_IGNORE, }; static const struct alc_fixup alc662_fixups[] = { @@ -19515,10 +19516,15 @@ static const struct alc_fixup alc662_fixups[] = { { } } }, + [ALC662_FIXUP_SKU_IGNORE] = { + .type = ALC_FIXUP_SKU, + .v.sku = ALC_FIXUP_SKU_IGNORE, + }, }; static struct snd_pci_quirk alc662_fixup_tbl[] = { SND_PCI_QUIRK(0x1025, 0x0308, "Acer Aspire 8942G", ALC662_FIXUP_ASPIRE), + SND_PCI_QUIRK(0x1025, 0x031c, "Gateway NV79", ALC662_FIXUP_SKU_IGNORE), SND_PCI_QUIRK(0x1025, 0x038b, "Acer Aspire 8943G", ALC662_FIXUP_ASPIRE), SND_PCI_QUIRK(0x144d, 0xc051, "Samsung R720", ALC662_FIXUP_IDEAPAD), SND_PCI_QUIRK(0x1458, 0xa002, "Gigabyte", ALC662_FIXUP_GIGABYTE), -- cgit v0.10.2 From 8f62242246351b5a4bc0c1f00c0c7003edea128a Mon Sep 17 00:00:00 2001 From: Ingo Molnar Date: Fri, 29 Apr 2011 13:19:47 +0200 Subject: perf events: Add generic front-end and back-end stalled cycle event definitions Add two generic hardware events: front-end and back-end stalled cycles. These events measure conditions when the CPU is executing code but its capabilities are not fully utilized. Understanding such situations and analyzing them is an important sub-task of code optimization workflows. Both events limit performance: most front end stalls tend to be caused by branch misprediction or instruction fetch cachemisses, backend stalls can be caused by various resource shortages or inefficient instruction scheduling. Front-end stalls are the more important ones: code cannot run fast if the instruction stream is not being kept up. An over-utilized back-end can cause front-end stalls and thus has to be kept an eye on as well. The exact composition is very program logic and instruction mix dependent. We use the terms 'stall', 'front-end' and 'back-end' loosely and try to use the best available events from specific CPUs that approximate these concepts. Cc: Peter Zijlstra Cc: Arnaldo Carvalho de Melo Cc: Frederic Weisbecker Link: http://lkml.kernel.org/n/tip-7y40wib8n000io7hjpn1dsrm@git.kernel.org Signed-off-by: Ingo Molnar diff --git a/arch/x86/kernel/cpu/perf_event_intel.c b/arch/x86/kernel/cpu/perf_event_intel.c index 1ea9422..393085b 100644 --- a/arch/x86/kernel/cpu/perf_event_intel.c +++ b/arch/x86/kernel/cpu/perf_event_intel.c @@ -1414,7 +1414,7 @@ static __init int intel_pmu_init(void) x86_pmu.extra_regs = intel_nehalem_extra_regs; /* Install the stalled-cycles event: UOPS_EXECUTED.CORE_ACTIVE_CYCLES,c=1,i=1 */ - intel_perfmon_event_map[PERF_COUNT_HW_STALLED_CYCLES] = 0x1803fb1; + intel_perfmon_event_map[PERF_COUNT_HW_STALLED_CYCLES_BACKEND] = 0x1803fb1; if (ebx & 0x40) { /* diff --git a/include/linux/perf_event.h b/include/linux/perf_event.h index ac636dd..4e2d7ae 100644 --- a/include/linux/perf_event.h +++ b/include/linux/perf_event.h @@ -52,7 +52,8 @@ enum perf_hw_id { PERF_COUNT_HW_BRANCH_INSTRUCTIONS = 4, PERF_COUNT_HW_BRANCH_MISSES = 5, PERF_COUNT_HW_BUS_CYCLES = 6, - PERF_COUNT_HW_STALLED_CYCLES = 7, + PERF_COUNT_HW_STALLED_CYCLES_FRONTEND = 7, + PERF_COUNT_HW_STALLED_CYCLES_BACKEND = 8, PERF_COUNT_HW_MAX, /* non-ABI */ }; -- cgit v0.10.2 From 91fc4cc00099986bc1ba50e1f421c3548cffae42 Mon Sep 17 00:00:00 2001 From: Ingo Molnar Date: Fri, 29 Apr 2011 14:17:19 +0200 Subject: perf, x86: Add new stalled cycles events for Intel and AMD CPUs Extend the Intel and AMD event definitions with generic front-end and back-end stall events. ( These are only approximations - suggestions are welcome for better events. ) Cc: Peter Zijlstra Cc: Arnaldo Carvalho de Melo Cc: Frederic Weisbecker Link: http://lkml.kernel.org/n/tip-7y40wib8n001io7hjpn1dsrm@git.kernel.org Signed-off-by: Ingo Molnar diff --git a/arch/x86/kernel/cpu/perf_event_amd.c b/arch/x86/kernel/cpu/perf_event_amd.c index cf4e369..fe29c1d 100644 --- a/arch/x86/kernel/cpu/perf_event_amd.c +++ b/arch/x86/kernel/cpu/perf_event_amd.c @@ -96,12 +96,14 @@ static __initconst const u64 amd_hw_cache_event_ids */ static const u64 amd_perfmon_event_map[] = { - [PERF_COUNT_HW_CPU_CYCLES] = 0x0076, - [PERF_COUNT_HW_INSTRUCTIONS] = 0x00c0, - [PERF_COUNT_HW_CACHE_REFERENCES] = 0x0080, - [PERF_COUNT_HW_CACHE_MISSES] = 0x0081, - [PERF_COUNT_HW_BRANCH_INSTRUCTIONS] = 0x00c2, - [PERF_COUNT_HW_BRANCH_MISSES] = 0x00c3, + [PERF_COUNT_HW_CPU_CYCLES] = 0x0076, + [PERF_COUNT_HW_INSTRUCTIONS] = 0x00c0, + [PERF_COUNT_HW_CACHE_REFERENCES] = 0x0080, + [PERF_COUNT_HW_CACHE_MISSES] = 0x0081, + [PERF_COUNT_HW_BRANCH_INSTRUCTIONS] = 0x00c2, + [PERF_COUNT_HW_BRANCH_MISSES] = 0x00c3, + [PERF_COUNT_HW_STALLED_CYCLES_FRONTEND] = 0x00d0, /* "Decoder empty" event */ + [PERF_COUNT_HW_STALLED_CYCLES_BACKEND] = 0x00d1, /* "Dispatch stalls" event */ }; static u64 amd_pmu_event_map(int hw_event) diff --git a/arch/x86/kernel/cpu/perf_event_intel.c b/arch/x86/kernel/cpu/perf_event_intel.c index 393085b..7983b9a 100644 --- a/arch/x86/kernel/cpu/perf_event_intel.c +++ b/arch/x86/kernel/cpu/perf_event_intel.c @@ -1413,7 +1413,9 @@ static __init int intel_pmu_init(void) x86_pmu.enable_all = intel_pmu_nhm_enable_all; x86_pmu.extra_regs = intel_nehalem_extra_regs; - /* Install the stalled-cycles event: UOPS_EXECUTED.CORE_ACTIVE_CYCLES,c=1,i=1 */ + /* UOPS_ISSUED.STALLED_CYCLES */ + intel_perfmon_event_map[PERF_COUNT_HW_STALLED_CYCLES_FRONTEND] = 0x180010e; + /* UOPS_EXECUTED.CORE_ACTIVE_CYCLES,c=1,i=1 */ intel_perfmon_event_map[PERF_COUNT_HW_STALLED_CYCLES_BACKEND] = 0x1803fb1; if (ebx & 0x40) { -- cgit v0.10.2 From e296e1276ca389156d7f06eed668dac30141c37d Mon Sep 17 00:00:00 2001 From: Jarod Wilson Date: Mon, 25 Apr 2011 14:48:18 -0300 Subject: [media] mceusb: add Dell transceiver ID Add device ID for a Dell-branded, Philips device ID transceiver reported by an OpenELEC user on their forums. http://openelec.tv/forum/27-hardware-support/5622-adding-support-for-an-ir-receiver--dell-branded--#5622 Signed-off-by: Jarod Wilson Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/rc/mceusb.c b/drivers/media/rc/mceusb.c index 044fb7a..0c273ec 100644 --- a/drivers/media/rc/mceusb.c +++ b/drivers/media/rc/mceusb.c @@ -220,6 +220,8 @@ static struct usb_device_id mceusb_dev_table[] = { { USB_DEVICE(VENDOR_PHILIPS, 0x206c) }, /* Philips/Spinel plus IR transceiver for ASUS */ { USB_DEVICE(VENDOR_PHILIPS, 0x2088) }, + /* Philips IR transceiver (Dell branded) */ + { USB_DEVICE(VENDOR_PHILIPS, 0x2093) }, /* Realtek MCE IR Receiver and card reader */ { USB_DEVICE(VENDOR_REALTEK, 0x0161), .driver_info = MULTIFUNCTION }, -- cgit v0.10.2 From d7516c7cf37a5fcb84b8f229947e3f52c62e19ae Mon Sep 17 00:00:00 2001 From: Jarod Wilson Date: Mon, 25 Apr 2011 14:50:50 -0300 Subject: [media] ite-cir: modular build on ppc requires delay.h include Signed-off-by: Jarod Wilson Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/rc/ite-cir.c b/drivers/media/rc/ite-cir.c index ac0e42b..9485dac 100644 --- a/drivers/media/rc/ite-cir.c +++ b/drivers/media/rc/ite-cir.c @@ -36,6 +36,7 @@ #include #include #include +#include #include #include #include -- cgit v0.10.2 From b30039333ae2a1cdd19ebd856a69e96918a46637 Mon Sep 17 00:00:00 2001 From: Jarod Wilson Date: Tue, 26 Apr 2011 12:25:02 -0300 Subject: [media] rc: show RC_TYPE_OTHER in sysfs Signed-off-by: Jarod Wilson Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/rc/rc-main.c b/drivers/media/rc/rc-main.c index 5ac1baf..9f0a2d9 100644 --- a/drivers/media/rc/rc-main.c +++ b/drivers/media/rc/rc-main.c @@ -733,6 +733,7 @@ static struct { { RC_TYPE_SONY, "sony" }, { RC_TYPE_RC5_SZ, "rc-5-sz" }, { RC_TYPE_LIRC, "lirc" }, + { RC_TYPE_OTHER, "other" }, }; #define PROTO_NONE "none" -- cgit v0.10.2 From 23ef710e1a6c4d6b9ef1c2fa19410f7f1479401e Mon Sep 17 00:00:00 2001 From: Jarod Wilson Date: Wed, 27 Apr 2011 19:01:44 -0300 Subject: [media] imon: add conditional locking in change_protocol The imon_ir_change_protocol function gets called two different ways, one way is from rc_register_device, for initial protocol selection/setup, and the other is via a userspace-initiated protocol change request, either by direct sysfs prodding or by something like ir-keytable. In the rc_register_device case, the imon context lock is already held, but when initiated from userspace, it is not, so we must acquire it, prior to calling send_packet, which requires that the lock is held. Without this change, there's an easily reproduceable deadlock when another function calls send_packet (such as either of the display write fops) after a userspace-initiated change_protocol. With a lock-debugging-enabled kernel, I was getting this: [ 15.014153] ===================================== [ 15.015048] [ BUG: bad unlock balance detected! ] [ 15.015048] ------------------------------------- [ 15.015048] ir-keytable/773 is trying to release lock (&ictx->lock) at: [ 15.015048] [] mutex_unlock+0xe/0x10 [ 15.015048] but there are no more locks to release! [ 15.015048] [ 15.015048] other info that might help us debug this: [ 15.015048] 2 locks held by ir-keytable/773: [ 15.015048] #0: (&buffer->mutex){+.+.+.}, at: [] sysfs_write_file+0x3c/0x144 [ 15.015048] #1: (s_active#87){.+.+.+}, at: [] sysfs_write_file+0xe7/0x144 [ 15.015048] [ 15.015048] stack backtrace: [ 15.015048] Pid: 773, comm: ir-keytable Not tainted 2.6.38.4-20.fc15.x86_64.debug #1 [ 15.015048] Call Trace: [ 15.015048] [] ? print_unlock_inbalance_bug+0xca/0xd5 [ 15.015048] [] ? lock_release_non_nested+0xc1/0x263 [ 15.015048] [] ? mutex_unlock+0xe/0x10 [ 15.015048] [] ? mutex_unlock+0xe/0x10 [ 15.015048] [] ? lock_release+0x17d/0x1a4 [ 15.015048] [] ? __mutex_unlock_slowpath+0xc5/0x125 [ 15.015048] [] ? mutex_unlock+0xe/0x10 [ 15.015048] [] ? send_packet+0x1c9/0x264 [imon] [ 15.015048] [] ? lock_release_non_nested+0xdb/0x263 [ 15.015048] [] ? imon_ir_change_protocol+0x126/0x15e [imon] [ 15.015048] [] ? store_protocols+0x1c3/0x286 [rc_core] [ 15.015048] [] ? dev_attr_store+0x20/0x22 [ 15.015048] [] ? sysfs_write_file+0x108/0x144 ... The original report that led to the investigation was the following: [ 1679.457305] INFO: task LCDd:8460 blocked for more than 120 seconds. [ 1679.457307] "echo 0 > /proc/sys/kernel/hung_task_timeout_secs" disables this message. [ 1679.457309] LCDd D ffff88010fcd89c8 0 8460 1 0x00000000 [ 1679.457312] ffff8800d5a03b48 0000000000000082 0000000000000000 ffff8800d5a03fd8 [ 1679.457314] 00000000012dcd30 fffffffffffffffd ffff8800d5a03fd8 ffff88010fcd86f0 [ 1679.457316] ffff8800d5a03fd8 ffff8800d5a03fd8 ffff88010fcd89d0 ffff8800d5a03fd8 [ 1679.457319] Call Trace: [ 1679.457324] [] ? zone_statistics+0x75/0x90 [ 1679.457327] [] ? get_page_from_freelist+0x3c7/0x820 [ 1679.457330] [] __mutex_lock_slowpath+0x139/0x320 [ 1679.457335] [] mutex_lock+0x11/0x30 [ 1679.457338] [] display_open+0x66/0x130 [imon] [ 1679.457345] [] usb_open+0x180/0x310 [usbcore] [ 1679.457349] [] chrdev_open+0x1bb/0x2d0 [ 1679.457350] [] __dentry_open+0x10d/0x370 [ 1679.457352] [] ? chrdev_open+0x0/0x2d0 ... Bump the driver version here so its easier to tell if people have this locking fix or not, and also make locking during probe easier to follow. CC: stable@kernel.org Reported-by: Benjamin Hodgetts Signed-off-by: Jarod Wilson Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/rc/imon.c b/drivers/media/rc/imon.c index f714e1a..3ca8659 100644 --- a/drivers/media/rc/imon.c +++ b/drivers/media/rc/imon.c @@ -46,7 +46,7 @@ #define MOD_AUTHOR "Jarod Wilson " #define MOD_DESC "Driver for SoundGraph iMON MultiMedia IR/Display" #define MOD_NAME "imon" -#define MOD_VERSION "0.9.2" +#define MOD_VERSION "0.9.3" #define DISPLAY_MINOR_BASE 144 #define DEVICE_NAME "lcd%d" @@ -460,8 +460,9 @@ static int display_close(struct inode *inode, struct file *file) } /** - * Sends a packet to the device -- this function must be called - * with ictx->lock held. + * Sends a packet to the device -- this function must be called with + * ictx->lock held, or its unlock/lock sequence while waiting for tx + * to complete can/will lead to a deadlock. */ static int send_packet(struct imon_context *ictx) { @@ -991,12 +992,21 @@ static void imon_touch_display_timeout(unsigned long data) * the iMON remotes, and those used by the Windows MCE remotes (which is * really just RC-6), but only one or the other at a time, as the signals * are decoded onboard the receiver. + * + * This function gets called two different ways, one way is from + * rc_register_device, for initial protocol selection/setup, and the other is + * via a userspace-initiated protocol change request, either by direct sysfs + * prodding or by something like ir-keytable. In the rc_register_device case, + * the imon context lock is already held, but when initiated from userspace, + * it is not, so we must acquire it prior to calling send_packet, which + * requires that the lock is held. */ static int imon_ir_change_protocol(struct rc_dev *rc, u64 rc_type) { int retval; struct imon_context *ictx = rc->priv; struct device *dev = ictx->dev; + bool unlock = false; unsigned char ir_proto_packet[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x86 }; @@ -1029,6 +1039,11 @@ static int imon_ir_change_protocol(struct rc_dev *rc, u64 rc_type) memcpy(ictx->usb_tx_buf, &ir_proto_packet, sizeof(ir_proto_packet)); + if (!mutex_is_locked(&ictx->lock)) { + unlock = true; + mutex_lock(&ictx->lock); + } + retval = send_packet(ictx); if (retval) goto out; @@ -1037,6 +1052,9 @@ static int imon_ir_change_protocol(struct rc_dev *rc, u64 rc_type) ictx->pad_mouse = false; out: + if (unlock) + mutex_unlock(&ictx->lock); + return retval; } @@ -2134,6 +2152,7 @@ static struct imon_context *imon_init_intf0(struct usb_interface *intf) goto rdev_setup_failed; } + mutex_unlock(&ictx->lock); return ictx; rdev_setup_failed: @@ -2205,6 +2224,7 @@ static struct imon_context *imon_init_intf1(struct usb_interface *intf, goto urb_submit_failed; } + mutex_unlock(&ictx->lock); return ictx; urb_submit_failed: @@ -2299,6 +2319,8 @@ static int __devinit imon_probe(struct usb_interface *interface, usb_set_intfdata(interface, ictx); if (ifnum == 0) { + mutex_lock(&ictx->lock); + if (product == 0xffdc && ictx->rf_device) { sysfs_err = sysfs_create_group(&interface->dev.kobj, &imon_rf_attr_group); @@ -2309,13 +2331,14 @@ static int __devinit imon_probe(struct usb_interface *interface, if (ictx->display_supported) imon_init_display(ictx, interface); + + mutex_unlock(&ictx->lock); } dev_info(dev, "iMON device (%04x:%04x, intf%d) on " "usb<%d:%d> initialized\n", vendor, product, ifnum, usbdev->bus->busnum, usbdev->devnum); - mutex_unlock(&ictx->lock); mutex_unlock(&driver_lock); return 0; -- cgit v0.10.2 From 129c04cb8ce2e4bf3f17223f58ef16aa8a2cb3b8 Mon Sep 17 00:00:00 2001 From: Ingo Molnar Date: Fri, 29 Apr 2011 14:41:28 +0200 Subject: perf tools: Add front-end and back-end stalled cycles support Update perf tooling to deal with front-end and back-end stalled cycles events. Add both the default 'perf stat' output. Cc: Peter Zijlstra Cc: Arnaldo Carvalho de Melo Cc: Frederic Weisbecker Link: http://lkml.kernel.org/n/tip-7y40wib8n002io7hjpn1dsrm@git.kernel.org Signed-off-by: Ingo Molnar diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c index da77077..6a4a8a3 100644 --- a/tools/perf/builtin-stat.c +++ b/tools/perf/builtin-stat.c @@ -66,7 +66,8 @@ static struct perf_event_attr default_attrs[] = { { .type = PERF_TYPE_SOFTWARE, .config = PERF_COUNT_SW_PAGE_FAULTS }, { .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_CPU_CYCLES }, - { .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_STALLED_CYCLES }, + { .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_STALLED_CYCLES_FRONTEND }, + { .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_STALLED_CYCLES_BACKEND }, { .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_INSTRUCTIONS }, { .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_BRANCH_INSTRUCTIONS }, { .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_BRANCH_MISSES }, @@ -84,7 +85,8 @@ static struct perf_event_attr detailed_attrs[] = { { .type = PERF_TYPE_SOFTWARE, .config = PERF_COUNT_SW_PAGE_FAULTS }, { .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_CPU_CYCLES }, - { .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_STALLED_CYCLES }, + { .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_STALLED_CYCLES_FRONTEND }, + { .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_STALLED_CYCLES_BACKEND }, { .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_INSTRUCTIONS }, { .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_BRANCH_INSTRUCTIONS }, { .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_BRANCH_MISSES }, @@ -249,7 +251,7 @@ static void update_shadow_stats(struct perf_evsel *counter, u64 *count) update_stats(&runtime_nsecs_stats[0], count[0]); else if (perf_evsel__match(counter, HARDWARE, HW_CPU_CYCLES)) update_stats(&runtime_cycles_stats[0], count[0]); - else if (perf_evsel__match(counter, HARDWARE, HW_STALLED_CYCLES)) + else if (perf_evsel__match(counter, HARDWARE, HW_STALLED_CYCLES_BACKEND)) update_stats(&runtime_stalled_cycles_stats[0], count[0]); else if (perf_evsel__match(counter, HARDWARE, HW_BRANCH_INSTRUCTIONS)) update_stats(&runtime_branches_stats[0], count[0]); @@ -607,7 +609,7 @@ static void abs_printout(int cpu, struct perf_evsel *evsel, double avg) fprintf(stderr, " # %8.3f %% of all cache refs ", ratio); - } else if (perf_evsel__match(evsel, HARDWARE, HW_STALLED_CYCLES)) { + } else if (perf_evsel__match(evsel, HARDWARE, HW_STALLED_CYCLES_BACKEND)) { print_stalled_cycles(cpu, evsel, avg); } else if (perf_evsel__match(evsel, HARDWARE, HW_CPU_CYCLES)) { total = avg_stats(&runtime_nsecs_stats[cpu]); diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c index bbbb735..04d2f0a 100644 --- a/tools/perf/util/parse-events.c +++ b/tools/perf/util/parse-events.c @@ -31,24 +31,25 @@ char debugfs_path[MAXPATHLEN]; #define CSW(x) .type = PERF_TYPE_SOFTWARE, .config = PERF_COUNT_SW_##x static struct event_symbol event_symbols[] = { - { CHW(CPU_CYCLES), "cpu-cycles", "cycles" }, - { CHW(STALLED_CYCLES), "stalled-cycles", "idle-cycles" }, - { CHW(INSTRUCTIONS), "instructions", "" }, - { CHW(CACHE_REFERENCES), "cache-references", "" }, - { CHW(CACHE_MISSES), "cache-misses", "" }, - { CHW(BRANCH_INSTRUCTIONS), "branch-instructions", "branches" }, - { CHW(BRANCH_MISSES), "branch-misses", "" }, - { CHW(BUS_CYCLES), "bus-cycles", "" }, - - { CSW(CPU_CLOCK), "cpu-clock", "" }, - { CSW(TASK_CLOCK), "task-clock", "" }, - { CSW(PAGE_FAULTS), "page-faults", "faults" }, - { CSW(PAGE_FAULTS_MIN), "minor-faults", "" }, - { CSW(PAGE_FAULTS_MAJ), "major-faults", "" }, - { CSW(CONTEXT_SWITCHES), "context-switches", "cs" }, - { CSW(CPU_MIGRATIONS), "cpu-migrations", "migrations" }, - { CSW(ALIGNMENT_FAULTS), "alignment-faults", "" }, - { CSW(EMULATION_FAULTS), "emulation-faults", "" }, + { CHW(CPU_CYCLES), "cpu-cycles", "cycles" }, + { CHW(STALLED_CYCLES_FRONTEND), "stalled-cycles-frontend", "idle-cycles-frontend" }, + { CHW(STALLED_CYCLES_BACKEND), "stalled-cycles-backend", "idle-cycles-backend" }, + { CHW(INSTRUCTIONS), "instructions", "" }, + { CHW(CACHE_REFERENCES), "cache-references", "" }, + { CHW(CACHE_MISSES), "cache-misses", "" }, + { CHW(BRANCH_INSTRUCTIONS), "branch-instructions", "branches" }, + { CHW(BRANCH_MISSES), "branch-misses", "" }, + { CHW(BUS_CYCLES), "bus-cycles", "" }, + + { CSW(CPU_CLOCK), "cpu-clock", "" }, + { CSW(TASK_CLOCK), "task-clock", "" }, + { CSW(PAGE_FAULTS), "page-faults", "faults" }, + { CSW(PAGE_FAULTS_MIN), "minor-faults", "" }, + { CSW(PAGE_FAULTS_MAJ), "major-faults", "" }, + { CSW(CONTEXT_SWITCHES), "context-switches", "cs" }, + { CSW(CPU_MIGRATIONS), "cpu-migrations", "migrations" }, + { CSW(ALIGNMENT_FAULTS), "alignment-faults", "" }, + { CSW(EMULATION_FAULTS), "emulation-faults", "" }, }; #define __PERF_EVENT_FIELD(config, name) \ diff --git a/tools/perf/util/python.c b/tools/perf/util/python.c index 406f613..8b0eff8 100644 --- a/tools/perf/util/python.c +++ b/tools/perf/util/python.c @@ -798,7 +798,6 @@ static struct { { "COUNT_HW_BRANCH_INSTRUCTIONS", PERF_COUNT_HW_BRANCH_INSTRUCTIONS }, { "COUNT_HW_BRANCH_MISSES", PERF_COUNT_HW_BRANCH_MISSES }, { "COUNT_HW_BUS_CYCLES", PERF_COUNT_HW_BUS_CYCLES }, - { "COUNT_HW_STALLED_CYCLES", PERF_COUNT_HW_STALLED_CYCLES }, { "COUNT_HW_CACHE_L1D", PERF_COUNT_HW_CACHE_L1D }, { "COUNT_HW_CACHE_L1I", PERF_COUNT_HW_CACHE_L1I }, { "COUNT_HW_CACHE_LL", PERF_COUNT_HW_CACHE_LL }, @@ -811,6 +810,9 @@ static struct { { "COUNT_HW_CACHE_RESULT_ACCESS", PERF_COUNT_HW_CACHE_RESULT_ACCESS }, { "COUNT_HW_CACHE_RESULT_MISS", PERF_COUNT_HW_CACHE_RESULT_MISS }, + { "COUNT_HW_STALLED_CYCLES_FRONTEND", PERF_COUNT_HW_STALLED_CYCLES_FRONTEND }, + { "COUNT_HW_STALLED_CYCLES_BACKEND", PERF_COUNT_HW_STALLED_CYCLES_BACKEND }, + { "COUNT_SW_CPU_CLOCK", PERF_COUNT_SW_CPU_CLOCK }, { "COUNT_SW_TASK_CLOCK", PERF_COUNT_SW_TASK_CLOCK }, { "COUNT_SW_PAGE_FAULTS", PERF_COUNT_SW_PAGE_FAULTS }, -- cgit v0.10.2 From d3d1e86da07b4565815e3dbcd082f53017d215f8 Mon Sep 17 00:00:00 2001 From: Ingo Molnar Date: Fri, 29 Apr 2011 13:49:08 +0200 Subject: perf stat: Analyze front-end and back-end stall counts Sample output: Performance counter stats for './loop_1b': 873.691065 task-clock # 1.000 CPUs utilized 1 context-switches # 0.000 M/sec 1 CPU-migrations # 0.000 M/sec 96 page-faults # 0.000 M/sec 2,012,637,222 cycles # 2.304 GHz (66.58%) 1,001,397,911 stalled-cycles-frontend # 49.76% frontend cycles idle (66.58%) 7,523,398 stalled-cycles-backend # 0.37% backend cycles idle (66.76%) 2,004,551,046 instructions # 1.00 insns per cycle # 0.50 stalled cycles per insn (66.80%) 1,001,304,992 branches # 1146.063 M/sec (66.76%) 39,453 branch-misses # 0.00% of all branches (66.64%) 0.874046121 seconds time elapsed Cc: Peter Zijlstra Cc: Arnaldo Carvalho de Melo Cc: Frederic Weisbecker Link: http://lkml.kernel.org/n/tip-7y40wib8n003io7hjpn1dsrm@git.kernel.org Signed-off-by: Ingo Molnar diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c index 6a4a8a3..e454499 100644 --- a/tools/perf/builtin-stat.c +++ b/tools/perf/builtin-stat.c @@ -201,7 +201,8 @@ static double stddev_stats(struct stats *stats) struct stats runtime_nsecs_stats[MAX_NR_CPUS]; struct stats runtime_cycles_stats[MAX_NR_CPUS]; -struct stats runtime_stalled_cycles_stats[MAX_NR_CPUS]; +struct stats runtime_stalled_cycles_front_stats[MAX_NR_CPUS]; +struct stats runtime_stalled_cycles_back_stats[MAX_NR_CPUS]; struct stats runtime_branches_stats[MAX_NR_CPUS]; struct stats runtime_cacherefs_stats[MAX_NR_CPUS]; struct stats runtime_l1_dcache_stats[MAX_NR_CPUS]; @@ -251,8 +252,10 @@ static void update_shadow_stats(struct perf_evsel *counter, u64 *count) update_stats(&runtime_nsecs_stats[0], count[0]); else if (perf_evsel__match(counter, HARDWARE, HW_CPU_CYCLES)) update_stats(&runtime_cycles_stats[0], count[0]); + else if (perf_evsel__match(counter, HARDWARE, HW_STALLED_CYCLES_FRONTEND)) + update_stats(&runtime_stalled_cycles_front_stats[0], count[0]); else if (perf_evsel__match(counter, HARDWARE, HW_STALLED_CYCLES_BACKEND)) - update_stats(&runtime_stalled_cycles_stats[0], count[0]); + update_stats(&runtime_stalled_cycles_back_stats[0], count[0]); else if (perf_evsel__match(counter, HARDWARE, HW_BRANCH_INSTRUCTIONS)) update_stats(&runtime_branches_stats[0], count[0]); else if (perf_evsel__match(counter, HARDWARE, HW_CACHE_REFERENCES)) @@ -478,7 +481,30 @@ static void nsec_printout(int cpu, struct perf_evsel *evsel, double avg) fprintf(stderr, " # %8.3f CPUs utilized ", avg / avg_stats(&walltime_nsecs_stats)); } -static void print_stalled_cycles(int cpu, struct perf_evsel *evsel __used, double avg) +static void print_stalled_cycles_frontend(int cpu, struct perf_evsel *evsel __used, double avg) +{ + double total, ratio = 0.0; + const char *color; + + total = avg_stats(&runtime_cycles_stats[cpu]); + + if (total) + ratio = avg / total * 100.0; + + color = PERF_COLOR_NORMAL; + if (ratio > 75.0) + color = PERF_COLOR_RED; + else if (ratio > 50.0) + color = PERF_COLOR_MAGENTA; + else if (ratio > 20.0) + color = PERF_COLOR_YELLOW; + + fprintf(stderr, " # "); + color_fprintf(stderr, color, "%5.2f%%", ratio); + fprintf(stderr, " frontend cycles idle "); +} + +static void print_stalled_cycles_backend(int cpu, struct perf_evsel *evsel __used, double avg) { double total, ratio = 0.0; const char *color; @@ -498,7 +524,7 @@ static void print_stalled_cycles(int cpu, struct perf_evsel *evsel __used, doubl fprintf(stderr, " # "); color_fprintf(stderr, color, "%5.2f%%", ratio); - fprintf(stderr, " of all cycles are idle "); + fprintf(stderr, " backend cycles idle "); } static void print_branch_misses(int cpu, struct perf_evsel *evsel __used, double avg) @@ -583,7 +609,8 @@ static void abs_printout(int cpu, struct perf_evsel *evsel, double avg) fprintf(stderr, " # %4.2f insns per cycle ", ratio); - total = avg_stats(&runtime_stalled_cycles_stats[cpu]); + total = avg_stats(&runtime_stalled_cycles_front_stats[cpu]); + total = max(total, avg_stats(&runtime_stalled_cycles_back_stats[cpu])); if (total && avg) { ratio = total / avg; @@ -609,8 +636,10 @@ static void abs_printout(int cpu, struct perf_evsel *evsel, double avg) fprintf(stderr, " # %8.3f %% of all cache refs ", ratio); + } else if (perf_evsel__match(evsel, HARDWARE, HW_STALLED_CYCLES_FRONTEND)) { + print_stalled_cycles_frontend(cpu, evsel, avg); } else if (perf_evsel__match(evsel, HARDWARE, HW_STALLED_CYCLES_BACKEND)) { - print_stalled_cycles(cpu, evsel, avg); + print_stalled_cycles_backend(cpu, evsel, avg); } else if (perf_evsel__match(evsel, HARDWARE, HW_CPU_CYCLES)) { total = avg_stats(&runtime_nsecs_stats[cpu]); diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c index 04d2f0a..8a407f3 100644 --- a/tools/perf/util/parse-events.c +++ b/tools/perf/util/parse-events.c @@ -60,7 +60,7 @@ static struct event_symbol event_symbols[] = { #define PERF_EVENT_TYPE(config) __PERF_EVENT_FIELD(config, TYPE) #define PERF_EVENT_ID(config) __PERF_EVENT_FIELD(config, EVENT) -static const char *hw_event_names[] = { +static const char *hw_event_names[PERF_COUNT_HW_MAX] = { "cycles", "instructions", "cache-references", @@ -68,10 +68,11 @@ static const char *hw_event_names[] = { "branches", "branch-misses", "bus-cycles", - "stalled-cycles", + "stalled-cycles-frontend", + "stalled-cycles-backend", }; -static const char *sw_event_names[] = { +static const char *sw_event_names[PERF_COUNT_SW_MAX] = { "cpu-clock", "task-clock", "page-faults", -- cgit v0.10.2 From 2b427e14b77dbf3e05f1bd0785f1d07ea5fe924e Mon Sep 17 00:00:00 2001 From: Ingo Molnar Date: Fri, 29 Apr 2011 14:16:18 +0200 Subject: perf stat: Adjust stall cycles warning percentages Adjust to color thresholds to better match the percentages seen in real workloads. Both are now a bit more sensitive. Cc: Peter Zijlstra Cc: Arnaldo Carvalho de Melo Cc: Frederic Weisbecker Link: http://lkml.kernel.org/n/tip-7y40wib8n004io7hjpn1dsrm@git.kernel.org Signed-off-by: Ingo Molnar diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c index e454499..2492a0e 100644 --- a/tools/perf/builtin-stat.c +++ b/tools/perf/builtin-stat.c @@ -492,11 +492,11 @@ static void print_stalled_cycles_frontend(int cpu, struct perf_evsel *evsel __us ratio = avg / total * 100.0; color = PERF_COLOR_NORMAL; - if (ratio > 75.0) + if (ratio > 50.0) color = PERF_COLOR_RED; - else if (ratio > 50.0) + else if (ratio > 30.0) color = PERF_COLOR_MAGENTA; - else if (ratio > 20.0) + else if (ratio > 10.0) color = PERF_COLOR_YELLOW; fprintf(stderr, " # "); @@ -519,7 +519,7 @@ static void print_stalled_cycles_backend(int cpu, struct perf_evsel *evsel __use color = PERF_COLOR_RED; else if (ratio > 50.0) color = PERF_COLOR_MAGENTA; - else if (ratio > 25.0) + else if (ratio > 20.0) color = PERF_COLOR_YELLOW; fprintf(stderr, " # "); -- cgit v0.10.2 From fce3c786d3a49eff397583b4b62fa38df90db937 Mon Sep 17 00:00:00 2001 From: Ingo Molnar Date: Sat, 30 Apr 2011 09:03:15 +0200 Subject: perf stat: Leave more room for percentages Triple digit percentages do not fit otherwise. Cc: Peter Zijlstra Cc: Arnaldo Carvalho de Melo Cc: Frederic Weisbecker Link: http://lkml.kernel.org/n/tip-7y40wib8n005io7hjpn1dsrm@git.kernel.org Signed-off-by: Ingo Molnar diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c index 2492a0e..9e596ab 100644 --- a/tools/perf/builtin-stat.c +++ b/tools/perf/builtin-stat.c @@ -499,8 +499,8 @@ static void print_stalled_cycles_frontend(int cpu, struct perf_evsel *evsel __us else if (ratio > 10.0) color = PERF_COLOR_YELLOW; - fprintf(stderr, " # "); - color_fprintf(stderr, color, "%5.2f%%", ratio); + fprintf(stderr, " # "); + color_fprintf(stderr, color, "%6.2f%%", ratio); fprintf(stderr, " frontend cycles idle "); } @@ -522,9 +522,9 @@ static void print_stalled_cycles_backend(int cpu, struct perf_evsel *evsel __use else if (ratio > 20.0) color = PERF_COLOR_YELLOW; - fprintf(stderr, " # "); - color_fprintf(stderr, color, "%5.2f%%", ratio); - fprintf(stderr, " backend cycles idle "); + fprintf(stderr, " # "); + color_fprintf(stderr, color, "%6.2f%%", ratio); + fprintf(stderr, " backend cycles idle "); } static void print_branch_misses(int cpu, struct perf_evsel *evsel __used, double avg) @@ -545,8 +545,8 @@ static void print_branch_misses(int cpu, struct perf_evsel *evsel __used, double else if (ratio > 5.0) color = PERF_COLOR_YELLOW; - fprintf(stderr, " # "); - color_fprintf(stderr, color, "%5.2f%%", ratio); + fprintf(stderr, " # "); + color_fprintf(stderr, color, "%6.2f%%", ratio); fprintf(stderr, " of all branches "); } @@ -568,8 +568,8 @@ static void print_l1_dcache_misses(int cpu, struct perf_evsel *evsel __used, dou else if (ratio > 5.0) color = PERF_COLOR_YELLOW; - fprintf(stderr, " # "); - color_fprintf(stderr, color, "%5.2f%%", ratio); + fprintf(stderr, " # "); + color_fprintf(stderr, color, "%6.2f%%", ratio); fprintf(stderr, " of all L1-dcache hits "); } @@ -607,14 +607,14 @@ static void abs_printout(int cpu, struct perf_evsel *evsel, double avg) if (total) ratio = avg / total; - fprintf(stderr, " # %4.2f insns per cycle ", ratio); + fprintf(stderr, " # %5.2f insns per cycle ", ratio); total = avg_stats(&runtime_stalled_cycles_front_stats[cpu]); total = max(total, avg_stats(&runtime_stalled_cycles_back_stats[cpu])); if (total && avg) { ratio = total / avg; - fprintf(stderr, "\n # %4.2f stalled cycles per insn", ratio); + fprintf(stderr, "\n # %5.2f stalled cycles per insn", ratio); } } else if (perf_evsel__match(evsel, HARDWARE, HW_BRANCH_MISSES) && -- cgit v0.10.2 From 370faf1dd0461ad811852c8abbbcd3d73b1e4fc4 Mon Sep 17 00:00:00 2001 From: Ingo Molnar Date: Fri, 29 Apr 2011 16:11:03 +0200 Subject: perf stat: Fail softly on unsupported events David Ahern reported this perf stat failure: > # /tmp/build-perf/perf stat -- sleep 1 > Error: stalled-cycles-frontend event is not supported. > Fatal: Not all events could be opened. > > This is a Dell R410 with an E5620 processor. Fail in a softer fashion on unknown/unsupported events. Reported-by: David Ahern Cc: Peter Zijlstra Cc: Arnaldo Carvalho de Melo Cc: Frederic Weisbecker Link: http://lkml.kernel.org/n/tip-7y40wib8n006io7hjpn1dsrm@git.kernel.org Signed-off-by: Ingo Molnar diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c index 9e596ab..c8b535b 100644 --- a/tools/perf/builtin-stat.c +++ b/tools/perf/builtin-stat.c @@ -377,7 +377,7 @@ static int run_perf_stat(int argc __used, const char **argv) list_for_each_entry(counter, &evsel_list->entries, node) { if (create_perf_stat_counter(counter) < 0) { - if (errno == EINVAL || errno == ENOSYS) + if (errno == EINVAL || errno == ENOSYS || errno == ENOENT) continue; if (errno == EPERM || errno == EACCES) { @@ -385,8 +385,6 @@ static int run_perf_stat(int argc __used, const char **argv) "\t Consider tweaking" " /proc/sys/kernel/perf_event_paranoid or running as root.", system_wide ? "system-wide " : ""); - } else if (errno == ENOENT) { - error("%s event is not supported. ", event_name(counter)); } else { error("open_counter returned with %d (%s). " "/bin/dmesg may provide additional information.\n", -- cgit v0.10.2 From 301120396b766ae4480e52ece220516a1707822b Mon Sep 17 00:00:00 2001 From: Ingo Molnar Date: Sat, 30 Apr 2011 09:14:54 +0200 Subject: perf events, x86: Add Westmere stalled-cycles-frontend/backend events Extend the Intel Westmere PMU driver with definitions for generic front-end and back-end stall events. ( These are only approximations. ) Reported-by: David Ahern Cc: Peter Zijlstra Cc: Arnaldo Carvalho de Melo Cc: Frederic Weisbecker Link: http://lkml.kernel.org/n/tip-7y40wib8n008io7hjpn1dsrm@git.kernel.org Signed-off-by: Ingo Molnar diff --git a/arch/x86/kernel/cpu/perf_event_intel.c b/arch/x86/kernel/cpu/perf_event_intel.c index 7983b9a..be8363a 100644 --- a/arch/x86/kernel/cpu/perf_event_intel.c +++ b/arch/x86/kernel/cpu/perf_event_intel.c @@ -1458,6 +1458,12 @@ static __init int intel_pmu_init(void) x86_pmu.enable_all = intel_pmu_nhm_enable_all; x86_pmu.pebs_constraints = intel_westmere_pebs_event_constraints; x86_pmu.extra_regs = intel_westmere_extra_regs; + + /* UOPS_ISSUED.STALLED_CYCLES */ + intel_perfmon_event_map[PERF_COUNT_HW_STALLED_CYCLES_FRONTEND] = 0x180010e; + /* UOPS_EXECUTED.CORE_ACTIVE_CYCLES,c=1,i=1 */ + intel_perfmon_event_map[PERF_COUNT_HW_STALLED_CYCLES_BACKEND] = 0x1803fb1; + pr_cont("Westmere events, "); break; -- cgit v0.10.2 From 5a4e5e6a701bea7d3cbeed19fa9ea45802e8fabb Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Fri, 29 Apr 2011 16:33:35 +0200 Subject: hwmon: (lm90) Add support for ADT7461A and NCT1008 This patch adds support for ADT7461A and NCT1008 to the lm90 driver. Both chips have identical functionality and report the same manufacturing ID and device ID values. Signed-off-by: Guenter Roeck Signed-off-by: Jean Delvare diff --git a/Documentation/hwmon/lm90 b/Documentation/hwmon/lm90 index fa475c0..aa820ac 100644 --- a/Documentation/hwmon/lm90 +++ b/Documentation/hwmon/lm90 @@ -32,6 +32,16 @@ Supported chips: Addresses scanned: I2C 0x4c and 0x4d Datasheet: Publicly available at the ON Semiconductor website http://www.onsemi.com/PowerSolutions/product.do?id=ADT7461 + * Analog Devices ADT7461A + Prefix: 'adt7461a' + Addresses scanned: I2C 0x4c and 0x4d + Datasheet: Publicly available at the ON Semiconductor website + http://www.onsemi.com/PowerSolutions/product.do?id=ADT7461A + * ON Semiconductor NCT1008 + Prefix: 'nct1008' + Addresses scanned: I2C 0x4c and 0x4d + Datasheet: Publicly available at the ON Semiconductor website + http://www.onsemi.com/PowerSolutions/product.do?id=NCT1008 * Maxim MAX6646 Prefix: 'max6646' Addresses scanned: I2C 0x4d @@ -149,7 +159,7 @@ ADM1032: * ALERT is triggered by open remote sensor. * SMBus PEC support for Write Byte and Receive Byte transactions. -ADT7461: +ADT7461, ADT7461A, NCT1008: * Extended temperature range (breaks compatibility) * Lower resolution for remote temperature @@ -205,11 +215,12 @@ SMBus Alert Support This driver has basic support for SMBus alert. When an alert is received, the status register is read and the faulty temperature channel is logged. -The Analog Devices chips (ADM1032 and ADT7461) do not implement the SMBus -alert protocol properly so additional care is needed: the ALERT output is -disabled when an alert is received, and is re-enabled only when the alarm -is gone. Otherwise the chip would block alerts from other chips in the bus -as long as the alarm is active. +The Analog Devices chips (ADM1032, ADT7461 and ADT7461A) and ON +Semiconductor chips (NCT1008) do not implement the SMBus alert protocol +properly so additional care is needed: the ALERT output is disabled when +an alert is received, and is re-enabled only when the alarm is gone. +Otherwise the chip would block alerts from other chips in the bus as long +as the alarm is active. PEC Support ----------- diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig index 060ef63..92d0251 100644 --- a/drivers/hwmon/Kconfig +++ b/drivers/hwmon/Kconfig @@ -618,10 +618,10 @@ config SENSORS_LM90 depends on I2C help If you say yes here you get support for National Semiconductor LM90, - LM86, LM89 and LM99, Analog Devices ADM1032 and ADT7461, Maxim - MAX6646, MAX6647, MAX6648, MAX6649, MAX6657, MAX6658, MAX6659, - MAX6680, MAX6681, MAX6692, MAX6695, MAX6696, and Winbond/Nuvoton - W83L771W/G/AWG/ASG sensor chips. + LM86, LM89 and LM99, Analog Devices ADM1032, ADT7461, and ADT7461A, + Maxim MAX6646, MAX6647, MAX6648, MAX6649, MAX6657, MAX6658, MAX6659, + MAX6680, MAX6681, MAX6692, MAX6695, MAX6696, ON Semiconductor NCT1008, + and Winbond/Nuvoton W83L771W/G/AWG/ASG sensor chips. This driver can also be built as a module. If so, the module will be called lm90. diff --git a/drivers/hwmon/lm90.c b/drivers/hwmon/lm90.c index c43b4e9..2f94f95 100644 --- a/drivers/hwmon/lm90.c +++ b/drivers/hwmon/lm90.c @@ -49,10 +49,10 @@ * chips, but support three temperature sensors instead of two. MAX6695 * and MAX6696 only differ in the pinout so they can be treated identically. * - * This driver also supports the ADT7461 chip from Analog Devices. - * It's supported in both compatibility and extended mode. It is mostly - * compatible with LM90 except for a data format difference for the - * temperature value registers. + * This driver also supports ADT7461 and ADT7461A from Analog Devices as well as + * NCT1008 from ON Semiconductor. The chips are supported in both compatibility + * and extended mode. They are mostly compatible with LM90 except for a data + * format difference for the temperature value registers. * * Since the LM90 was the first chipset supported by this driver, most * comments will refer to this chipset, but are actually general and @@ -88,9 +88,10 @@ * Addresses to scan * Address is fully defined internally and cannot be changed except for * MAX6659, MAX6680 and MAX6681. - * LM86, LM89, LM90, LM99, ADM1032, ADM1032-1, ADT7461, MAX6649, MAX6657, - * MAX6658 and W83L771 have address 0x4c. - * ADM1032-2, ADT7461-2, LM89-1, LM99-1 and MAX6646 have address 0x4d. + * LM86, LM89, LM90, LM99, ADM1032, ADM1032-1, ADT7461, ADT7461A, MAX6649, + * MAX6657, MAX6658, NCT1008 and W83L771 have address 0x4c. + * ADM1032-2, ADT7461-2, ADT7461A-2, LM89-1, LM99-1, MAX6646, and NCT1008D + * have address 0x4d. * MAX6647 has address 0x4e. * MAX6659 can have address 0x4c, 0x4d or 0x4e. * MAX6680 and MAX6681 can have address 0x18, 0x19, 0x1a, 0x29, 0x2a, 0x2b, @@ -174,6 +175,7 @@ enum chips { lm90, adm1032, lm99, lm86, max6657, max6659, adt7461, max6680, static const struct i2c_device_id lm90_id[] = { { "adm1032", adm1032 }, { "adt7461", adt7461 }, + { "adt7461a", adt7461 }, { "lm90", lm90 }, { "lm86", lm86 }, { "lm89", lm86 }, @@ -188,6 +190,7 @@ static const struct i2c_device_id lm90_id[] = { { "max6681", max6680 }, { "max6695", max6696 }, { "max6696", max6696 }, + { "nct1008", adt7461 }, { "w83l771", w83l771 }, { } }; @@ -1153,6 +1156,11 @@ static int lm90_detect(struct i2c_client *new_client, && (reg_config1 & 0x1B) == 0x00 && reg_convrate <= 0x0A) { name = "adt7461"; + } else + if (chip_id == 0x57 /* ADT7461A, NCT1008 */ + && (reg_config1 & 0x1B) == 0x00 + && reg_convrate <= 0x0A) { + name = "adt7461a"; } } else if (man_id == 0x4D) { /* Maxim */ -- cgit v0.10.2 From 177e75925bead0c1f8bb8b2e69bcddabb1e07c11 Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Fri, 29 Apr 2011 16:33:35 +0200 Subject: hwmon: (lm90) Fix update interval information in driver documentation The lm90 driver's attribute update interval is configurable. Reflect this information in the driver documentation. Signed-off-by: Guenter Roeck Signed-off-by: Jean Delvare diff --git a/Documentation/hwmon/lm90 b/Documentation/hwmon/lm90 index aa820ac..f3efd18 100644 --- a/Documentation/hwmon/lm90 +++ b/Documentation/hwmon/lm90 @@ -205,9 +205,9 @@ are exported, one for each channel, but these values are of course linked. Only the local hysteresis can be set from user-space, and the same delta applies to the remote hysteresis. -The lm90 driver will not update its values more frequently than every -other second; reading them more often will do no harm, but will return -'old' values. +The lm90 driver will not update its values more frequently than configured with +the update_interval attribute; reading them more often will do no harm, but will +return 'old' values. SMBus Alert Support ------------------- -- cgit v0.10.2 From d7ce0335b5ddbe4cc1c519750074b5176a4124ab Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Fri, 29 Apr 2011 16:33:36 +0200 Subject: hwmon: (adm1021) Clarify documentation regarding Xeon processors Recent Xeon processor thermal sensors are supported by the coretemp driver and not the adm1021 driver. Only one old generation of Xeon processors (the first Netburst ones) are supported by the adm1021 driver. Reported-by: Darren Hart Signed-off-by: Jean Delvare Acked-by: Guenter Roeck diff --git a/Documentation/hwmon/adm1021 b/Documentation/hwmon/adm1021 index 03d02bf..02ad96c 100644 --- a/Documentation/hwmon/adm1021 +++ b/Documentation/hwmon/adm1021 @@ -14,10 +14,6 @@ Supported chips: Prefix: 'gl523sm' Addresses scanned: I2C 0x18 - 0x1a, 0x29 - 0x2b, 0x4c - 0x4e Datasheet: - * Intel Xeon Processor - Prefix: - any other - may require 'force_adm1021' parameter - Addresses scanned: none - Datasheet: Publicly available at Intel website * Maxim MAX1617 Prefix: 'max1617' Addresses scanned: I2C 0x18 - 0x1a, 0x29 - 0x2b, 0x4c - 0x4e @@ -91,21 +87,27 @@ will do no harm, but will return 'old' values. It is possible to make ADM1021-clones do faster measurements, but there is really no good reason for that. -Xeon support ------------- -Some Xeon processors have real max1617, adm1021, or compatible chips -within them, with two temperature sensors. +Netburst-based Xeon support +--------------------------- -Other Xeons have chips with only one sensor. +Some Xeon processors based on the Netburst (early Pentium 4, from 2001 to +2003) microarchitecture had real MAX1617, ADM1021, or compatible chips +within them, with two temperature sensors. Other Xeon processors of this +era (with 400 MHz FSB) had chips with only one temperature sensor. -If you have a Xeon, and the adm1021 module loads, and both temperatures -appear valid, then things are good. +If you have such an old Xeon, and you get two valid temperatures when +loading the adm1021 module, then things are good. -If the adm1021 module doesn't load, you should try this: - modprobe adm1021 force_adm1021=BUS,ADDRESS - ADDRESS can only be 0x18, 0x1a, 0x29, 0x2b, 0x4c, or 0x4e. +If nothing happens when loading the adm1021 module, and you are certain +that your specific Xeon processor model includes compatible sensors, you +will have to explicitly instantiate the sensor chips from user-space. See +method 4 in Documentation/i2c/instantiating-devices. Possible slave +addresses are 0x18, 0x1a, 0x29, 0x2b, 0x4c, or 0x4e. It is likely that +only temp2 will be correct and temp1 will have to be ignored. -If you have dual Xeons you may have appear to have two separate -adm1021-compatible chips, or two single-temperature sensors, at distinct -addresses. +Previous generations of the Xeon processor (based on Pentium II/III) +didn't have these sensors. Next generations of Xeon processors (533 MHz +FSB and faster) lost them, until the Core-based generation which +introduced integrated digital thermal sensors. These are supported by +the coretemp driver. diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig index 92d0251..50e40db 100644 --- a/drivers/hwmon/Kconfig +++ b/drivers/hwmon/Kconfig @@ -110,8 +110,7 @@ config SENSORS_ADM1021 help If you say yes here you get support for Analog Devices ADM1021 and ADM1023 sensor chips and clones: Maxim MAX1617 and MAX1617A, - Genesys Logic GL523SM, National Semiconductor LM84, TI THMC10, - and the XEON processor built-in sensor. + Genesys Logic GL523SM, National Semiconductor LM84 and TI THMC10. This driver can also be built as a module. If so, the module will be called adm1021. -- cgit v0.10.2 From 5f441e2256506a5878d276399e0a22a13942fe4b Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Fri, 29 Apr 2011 16:33:36 +0200 Subject: hwmon: (lm85) Add missing list terminators Fixes kernel bug #34072: https://bugzilla.kernel.org/show_bug.cgi?id=34072 Signed-off-by: Jean Delvare Acked-by: Guenter Roeck diff --git a/drivers/hwmon/lm85.c b/drivers/hwmon/lm85.c index 250d099..b5a6bc4 100644 --- a/drivers/hwmon/lm85.c +++ b/drivers/hwmon/lm85.c @@ -1094,6 +1094,7 @@ static struct attribute *lm85_attributes_minctl[] = { &sensor_dev_attr_pwm1_auto_pwm_minctl.dev_attr.attr, &sensor_dev_attr_pwm2_auto_pwm_minctl.dev_attr.attr, &sensor_dev_attr_pwm3_auto_pwm_minctl.dev_attr.attr, + NULL }; static const struct attribute_group lm85_group_minctl = { @@ -1104,6 +1105,7 @@ static struct attribute *lm85_attributes_temp_off[] = { &sensor_dev_attr_temp1_auto_temp_off.dev_attr.attr, &sensor_dev_attr_temp2_auto_temp_off.dev_attr.attr, &sensor_dev_attr_temp3_auto_temp_off.dev_attr.attr, + NULL }; static const struct attribute_group lm85_group_temp_off = { -- cgit v0.10.2 From bc4d45f1901042a295b10949f51d24cce223e65d Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Fri, 29 Apr 2011 16:33:36 +0200 Subject: hwmon: (lm85) Fix error paths in probe function We must remove all files we created, even in error cases. Fixes second part of kernel bug #34072: https://bugzilla.kernel.org/show_bug.cgi?id=34072 Signed-off-by: Jean Delvare Acked-by: Guenter Roeck diff --git a/drivers/hwmon/lm85.c b/drivers/hwmon/lm85.c index b5a6bc4..da72dc1 100644 --- a/drivers/hwmon/lm85.c +++ b/drivers/hwmon/lm85.c @@ -1331,11 +1331,11 @@ static int lm85_probe(struct i2c_client *client, if (data->type != emc6d103s) { err = sysfs_create_group(&client->dev.kobj, &lm85_group_minctl); if (err) - goto err_kfree; + goto err_remove_files; err = sysfs_create_group(&client->dev.kobj, &lm85_group_temp_off); if (err) - goto err_kfree; + goto err_remove_files; } /* The ADT7463/68 have an optional VRM 10 mode where pin 21 is used -- cgit v0.10.2 From 88fda5619e6cd7988dc1d9a52f2da9ee8fd0e64d Mon Sep 17 00:00:00 2001 From: Hussam Al-Tayeb Date: Mon, 21 Feb 2011 15:20:26 -0300 Subject: [media] rc_core: avoid kernel oops when rmmod saa7134 The following is a patch to avoid a kernel oops when running rmmod saa7134 on kernel 2.6.27.1. The change is as suggested by mchehab on irc.freenode.org Signed-off-by: Hussam Al-Tayeb Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/rc/rc-main.c b/drivers/media/rc/rc-main.c index 9f0a2d9..33afd98 100644 --- a/drivers/media/rc/rc-main.c +++ b/drivers/media/rc/rc-main.c @@ -707,7 +707,8 @@ static void ir_close(struct input_dev *idev) { struct rc_dev *rdev = input_get_drvdata(idev); - rdev->close(rdev); + if (rdev) + rdev->close(rdev); } /* class for /sys/class/rc */ -- cgit v0.10.2 From 2b5cb549f8a31b44575fe25ccd043ddb7e901cf8 Mon Sep 17 00:00:00 2001 From: Malcolm Priestley Date: Tue, 22 Feb 2011 03:14:34 -0300 Subject: [media] Missing frontend config for LME DM04/QQBOX Forgot to add the DVB_STV0299/DVB_PLL to config Signed-off-by: Malcolm Priestley Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/dvb/dvb-usb/Kconfig b/drivers/media/dvb/dvb-usb/Kconfig index ccbd39a..c545039 100644 --- a/drivers/media/dvb/dvb-usb/Kconfig +++ b/drivers/media/dvb/dvb-usb/Kconfig @@ -356,6 +356,8 @@ config DVB_USB_LME2510 select DVB_TDA826X if !DVB_FE_CUSTOMISE select DVB_STV0288 if !DVB_FE_CUSTOMISE select DVB_IX2505V if !DVB_FE_CUSTOMISE + select DVB_STV0299 if !DVB_FE_CUSTOMISE + select DVB_PLL if !DVB_FE_CUSTOMISE help Say Y here to support the LME DM04/QQBOX DVB-S USB2.0 . -- cgit v0.10.2 From 0f22072ab50cac7983f9660d33974b45184da4f9 Mon Sep 17 00:00:00 2001 From: Dan Rosenberg Date: Fri, 29 Apr 2011 15:48:07 +0100 Subject: ARM: 6891/1: prevent heap corruption in OABI semtimedop When CONFIG_OABI_COMPAT is set, the wrapper for semtimedop does not bound the nsops argument. A sufficiently large value will cause an integer overflow in allocation size, followed by copying too much data into the allocated buffer. Fix this by restricting nsops to SEMOPM. Untested. Cc: stable@kernel.org Signed-off-by: Dan Rosenberg Signed-off-by: Russell King diff --git a/arch/arm/kernel/sys_oabi-compat.c b/arch/arm/kernel/sys_oabi-compat.c index 4ad8da1..af0aaeb 100644 --- a/arch/arm/kernel/sys_oabi-compat.c +++ b/arch/arm/kernel/sys_oabi-compat.c @@ -311,7 +311,7 @@ asmlinkage long sys_oabi_semtimedop(int semid, long err; int i; - if (nsops < 1) + if (nsops < 1 || nsops > SEMOPM) return -EINVAL; sops = kmalloc(sizeof(*sops) * nsops, GFP_KERNEL); if (!sops) -- cgit v0.10.2 From 80845a33165278f3236812009e9c568ba8c29938 Mon Sep 17 00:00:00 2001 From: Herton Ronaldo Krzesinski Date: Fri, 1 Apr 2011 14:12:02 -0300 Subject: [media] v4l: make sure drivers supply a zeroed struct v4l2_subdev Some v4l drivers currently don't initialize their struct v4l2_subdev with zeros, and this is a problem since some of the v4l2 code expects this. One example is the addition of internal_ops in commit 45f6f84, after that we are at risk of random oopses with these drivers when code in v4l2_device_register_subdev tries to dereference sd->internal_ops->*, as can be shown by the report at http://bugs.launchpad.net/bugs/745213 and analysis of its crash at https://lkml.org/lkml/2011/4/1/168 Use kzalloc within problematic drivers to ensure we have a zeroed struct v4l2_subdev. BugLink: http://bugs.launchpad.net/bugs/745213 Cc: Signed-off-by: Herton Ronaldo Krzesinski Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/radio/saa7706h.c b/drivers/media/radio/saa7706h.c index 585680f..b1193df 100644 --- a/drivers/media/radio/saa7706h.c +++ b/drivers/media/radio/saa7706h.c @@ -376,7 +376,7 @@ static int __devinit saa7706h_probe(struct i2c_client *client, v4l_info(client, "chip found @ 0x%02x (%s)\n", client->addr << 1, client->adapter->name); - state = kmalloc(sizeof(struct saa7706h_state), GFP_KERNEL); + state = kzalloc(sizeof(struct saa7706h_state), GFP_KERNEL); if (state == NULL) return -ENOMEM; sd = &state->sd; diff --git a/drivers/media/radio/tef6862.c b/drivers/media/radio/tef6862.c index 7c0d777..0991e19 100644 --- a/drivers/media/radio/tef6862.c +++ b/drivers/media/radio/tef6862.c @@ -176,7 +176,7 @@ static int __devinit tef6862_probe(struct i2c_client *client, v4l_info(client, "chip found @ 0x%02x (%s)\n", client->addr << 1, client->adapter->name); - state = kmalloc(sizeof(struct tef6862_state), GFP_KERNEL); + state = kzalloc(sizeof(struct tef6862_state), GFP_KERNEL); if (state == NULL) return -ENOMEM; state->freq = TEF6862_LO_FREQ; diff --git a/drivers/media/video/m52790.c b/drivers/media/video/m52790.c index 5e1c9a8..303ffa7 100644 --- a/drivers/media/video/m52790.c +++ b/drivers/media/video/m52790.c @@ -174,7 +174,7 @@ static int m52790_probe(struct i2c_client *client, v4l_info(client, "chip found @ 0x%x (%s)\n", client->addr << 1, client->adapter->name); - state = kmalloc(sizeof(struct m52790_state), GFP_KERNEL); + state = kzalloc(sizeof(struct m52790_state), GFP_KERNEL); if (state == NULL) return -ENOMEM; diff --git a/drivers/media/video/tda9840.c b/drivers/media/video/tda9840.c index 5d4cf3b..22fa820 100644 --- a/drivers/media/video/tda9840.c +++ b/drivers/media/video/tda9840.c @@ -171,7 +171,7 @@ static int tda9840_probe(struct i2c_client *client, v4l_info(client, "chip found @ 0x%x (%s)\n", client->addr << 1, client->adapter->name); - sd = kmalloc(sizeof(struct v4l2_subdev), GFP_KERNEL); + sd = kzalloc(sizeof(struct v4l2_subdev), GFP_KERNEL); if (sd == NULL) return -ENOMEM; v4l2_i2c_subdev_init(sd, client, &tda9840_ops); diff --git a/drivers/media/video/tea6415c.c b/drivers/media/video/tea6415c.c index 19621ed5..827425c 100644 --- a/drivers/media/video/tea6415c.c +++ b/drivers/media/video/tea6415c.c @@ -152,7 +152,7 @@ static int tea6415c_probe(struct i2c_client *client, v4l_info(client, "chip found @ 0x%x (%s)\n", client->addr << 1, client->adapter->name); - sd = kmalloc(sizeof(struct v4l2_subdev), GFP_KERNEL); + sd = kzalloc(sizeof(struct v4l2_subdev), GFP_KERNEL); if (sd == NULL) return -ENOMEM; v4l2_i2c_subdev_init(sd, client, &tea6415c_ops); diff --git a/drivers/media/video/tea6420.c b/drivers/media/video/tea6420.c index 5ea8404..f350b6c 100644 --- a/drivers/media/video/tea6420.c +++ b/drivers/media/video/tea6420.c @@ -125,7 +125,7 @@ static int tea6420_probe(struct i2c_client *client, v4l_info(client, "chip found @ 0x%x (%s)\n", client->addr << 1, client->adapter->name); - sd = kmalloc(sizeof(struct v4l2_subdev), GFP_KERNEL); + sd = kzalloc(sizeof(struct v4l2_subdev), GFP_KERNEL); if (sd == NULL) return -ENOMEM; v4l2_i2c_subdev_init(sd, client, &tea6420_ops); diff --git a/drivers/media/video/upd64031a.c b/drivers/media/video/upd64031a.c index f8138c7..1aab96a 100644 --- a/drivers/media/video/upd64031a.c +++ b/drivers/media/video/upd64031a.c @@ -230,7 +230,7 @@ static int upd64031a_probe(struct i2c_client *client, v4l_info(client, "chip found @ 0x%x (%s)\n", client->addr << 1, client->adapter->name); - state = kmalloc(sizeof(struct upd64031a_state), GFP_KERNEL); + state = kzalloc(sizeof(struct upd64031a_state), GFP_KERNEL); if (state == NULL) return -ENOMEM; sd = &state->sd; diff --git a/drivers/media/video/upd64083.c b/drivers/media/video/upd64083.c index 28e0e6b..9bbe617 100644 --- a/drivers/media/video/upd64083.c +++ b/drivers/media/video/upd64083.c @@ -202,7 +202,7 @@ static int upd64083_probe(struct i2c_client *client, v4l_info(client, "chip found @ 0x%x (%s)\n", client->addr << 1, client->adapter->name); - state = kmalloc(sizeof(struct upd64083_state), GFP_KERNEL); + state = kzalloc(sizeof(struct upd64083_state), GFP_KERNEL); if (state == NULL) return -ENOMEM; sd = &state->sd; -- cgit v0.10.2 From b730011061e2805a46b7291e708b6caaf2be6869 Mon Sep 17 00:00:00 2001 From: Oliver Endriss Date: Tue, 29 Mar 2011 17:35:24 -0300 Subject: [media] ngene: Fix CI data transfer regression Fix CI data transfer regression introduced by previous cleanup. Signed-off-by: Oliver Endriss Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/dvb/ngene/ngene-core.c b/drivers/media/dvb/ngene/ngene-core.c index 175a0f6..9630705 100644 --- a/drivers/media/dvb/ngene/ngene-core.c +++ b/drivers/media/dvb/ngene/ngene-core.c @@ -1520,6 +1520,7 @@ static int init_channel(struct ngene_channel *chan) if (dev->ci.en && (io & NGENE_IO_TSOUT)) { dvb_ca_en50221_init(adapter, dev->ci.en, 0, 1); set_transfer(chan, 1); + chan->dev->channel[2].DataFormatFlags = DF_SWAP32; set_transfer(&chan->dev->channel[2], 1); dvb_register_device(adapter, &chan->ci_dev, &ngene_dvbdev_ci, (void *) chan, -- cgit v0.10.2 From 5035b20fa5cd146b66f5f89619c20a4177fb736d Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Fri, 29 Apr 2011 18:08:37 +0200 Subject: workqueue: fix deadlock in worker_maybe_bind_and_lock() If a rescuer and stop_machine() bringing down a CPU race with each other, they may deadlock on non-preemptive kernel. The CPU won't accept a new task, so the rescuer can't migrate to the target CPU, while stop_machine() can't proceed because the rescuer is holding one of the CPU retrying migration. GCWQ_DISASSOCIATED is never cleared and worker_maybe_bind_and_lock() retries indefinitely. This problem can be reproduced semi reliably while the system is entering suspend. http://thread.gmane.org/gmane.linux.kernel/1122051 A lot of kudos to Thilo-Alexander for reporting this tricky issue and painstaking testing. stable: This affects all kernels with cmwq, so all kernels since and including v2.6.36 need this fix. Signed-off-by: Tejun Heo Reported-by: Thilo-Alexander Ginkel Tested-by: Thilo-Alexander Ginkel Cc: stable@kernel.org diff --git a/kernel/workqueue.c b/kernel/workqueue.c index 04ef830..e3378e8 100644 --- a/kernel/workqueue.c +++ b/kernel/workqueue.c @@ -1291,8 +1291,14 @@ __acquires(&gcwq->lock) return true; spin_unlock_irq(&gcwq->lock); - /* CPU has come up inbetween, retry migration */ + /* + * We've raced with CPU hot[un]plug. Give it a breather + * and retry migration. cond_resched() is required here; + * otherwise, we might deadlock against cpu_stop trying to + * bring down the CPU on non-preemptive kernel. + */ cpu_relax(); + cond_resched(); } } -- cgit v0.10.2 From b6202f97897a13ef531b822ab326dfc7eb90bdaf Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Fri, 29 Apr 2011 10:20:53 -0700 Subject: bpf: depends on MODULES module_alloc() and module_free() are available only if CONFIG_MODULES=y Reported-by: Randy Dunlap Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller diff --git a/net/Kconfig b/net/Kconfig index 745fb02..878151c 100644 --- a/net/Kconfig +++ b/net/Kconfig @@ -238,6 +238,7 @@ config HAVE_BPF_JIT config BPF_JIT bool "enable BPF Just In Time compiler" depends on HAVE_BPF_JIT + depends on MODULES ---help--- Berkeley Packet Filter filtering capabilities are normally handled by an interpreter. This option allows kernel to generate a native -- cgit v0.10.2 From 7d36a991e8d36b8ae87e2aa1158d3735e656253b Mon Sep 17 00:00:00 2001 From: amit salecha Date: Fri, 22 Apr 2011 16:22:20 +0000 Subject: pktgen: create num frags requested Pktgen doesn't generate number of frags requested. Divide packet size by number of frags and fill that in every frags. Example: With packet size 1470, it generate only 11 frags. Initial frags get lenght 706, 353, 177....so on. Last frag get divided by 2. Now with this fix, each frags will get 78 bytes. Signed-off-by: Amit Kumar Salecha Signed-off-by: David S. Miller diff --git a/net/core/pktgen.c b/net/core/pktgen.c index 2fa6fee..ff79d94 100644 --- a/net/core/pktgen.c +++ b/net/core/pktgen.c @@ -2622,6 +2622,7 @@ static void pktgen_finalize_skb(struct pktgen_dev *pkt_dev, struct sk_buff *skb, } else { int frags = pkt_dev->nfrags; int i, len; + int frag_len; if (frags > MAX_SKB_FRAGS) @@ -2633,6 +2634,8 @@ static void pktgen_finalize_skb(struct pktgen_dev *pkt_dev, struct sk_buff *skb, } i = 0; + frag_len = (datalen/frags) < PAGE_SIZE ? + (datalen/frags) : PAGE_SIZE; while (datalen > 0) { if (unlikely(!pkt_dev->page)) { int node = numa_node_id(); @@ -2646,38 +2649,18 @@ static void pktgen_finalize_skb(struct pktgen_dev *pkt_dev, struct sk_buff *skb, skb_shinfo(skb)->frags[i].page = pkt_dev->page; get_page(pkt_dev->page); skb_shinfo(skb)->frags[i].page_offset = 0; - skb_shinfo(skb)->frags[i].size = - (datalen < PAGE_SIZE ? datalen : PAGE_SIZE); + /*last fragment, fill rest of data*/ + if (i == (frags - 1)) + skb_shinfo(skb)->frags[i].size = + (datalen < PAGE_SIZE ? datalen : PAGE_SIZE); + else + skb_shinfo(skb)->frags[i].size = frag_len; datalen -= skb_shinfo(skb)->frags[i].size; skb->len += skb_shinfo(skb)->frags[i].size; skb->data_len += skb_shinfo(skb)->frags[i].size; i++; skb_shinfo(skb)->nr_frags = i; } - - while (i < frags) { - int rem; - - if (i == 0) - break; - - rem = skb_shinfo(skb)->frags[i - 1].size / 2; - if (rem == 0) - break; - - skb_shinfo(skb)->frags[i - 1].size -= rem; - - skb_shinfo(skb)->frags[i] = - skb_shinfo(skb)->frags[i - 1]; - get_page(skb_shinfo(skb)->frags[i].page); - skb_shinfo(skb)->frags[i].page = - skb_shinfo(skb)->frags[i - 1].page; - skb_shinfo(skb)->frags[i].page_offset += - skb_shinfo(skb)->frags[i - 1].size; - skb_shinfo(skb)->frags[i].size = rem; - i++; - skb_shinfo(skb)->nr_frags = i; - } } /* Stamp the time, and sequence number, -- cgit v0.10.2 From bfd36103ec26599557c2bd3225a1f1c9267f8fcb Mon Sep 17 00:00:00 2001 From: Stanislaw Gruszka Date: Fri, 29 Apr 2011 17:51:06 +0200 Subject: iwlagn: fix "Received BA when not expected" Need to use broadcast sta_id for management frames, otherwise we broke BA session in the firmware and get messages like that: "Received BA when not expected" or (on older kernels): "BA scd_flow 0 does not match txq_id 10" This fix regression introduced in 2.6.35 during station management code rewrite by: commit 2a87c26bbe9587baeb9e56d3ce0b4971bd777643 Author: Johannes Berg Date: Fri Apr 30 11:30:45 2010 -0700 iwlwifi: use iwl_find_station less Patch partially resolve: https://bugzilla.kernel.org/show_bug.cgi?id=16691 However, there are still 11n performance problems on 4965 and 5xxx devices that need to be investigated. Cc: stable@kernel.org # 2.6.35+ Signed-off-by: Stanislaw Gruszka Acked-by: Johannes Berg Acked-by: Wey-Yi Guy Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-tx.c b/drivers/net/wireless/iwlwifi/iwl-agn-tx.c index 2dd7d54..0712b672 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-tx.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-tx.c @@ -568,12 +568,17 @@ int iwlagn_tx_skb(struct iwl_priv *priv, struct sk_buff *skb) hdr_len = ieee80211_hdrlen(fc); - /* Find index into station table for destination station */ - sta_id = iwl_sta_id_or_broadcast(priv, ctx, info->control.sta); - if (sta_id == IWL_INVALID_STATION) { - IWL_DEBUG_DROP(priv, "Dropping - INVALID STATION: %pM\n", - hdr->addr1); - goto drop_unlock; + /* For management frames use broadcast id to do not break aggregation */ + if (!ieee80211_is_data(fc)) + sta_id = ctx->bcast_sta_id; + else { + /* Find index into station table for destination station */ + sta_id = iwl_sta_id_or_broadcast(priv, ctx, info->control.sta); + if (sta_id == IWL_INVALID_STATION) { + IWL_DEBUG_DROP(priv, "Dropping - INVALID STATION: %pM\n", + hdr->addr1); + goto drop_unlock; + } } IWL_DEBUG_TX(priv, "station Id %d\n", sta_id); -- cgit v0.10.2 From 16b345d89686ca0482a9ca741a1167def1abdd7f Mon Sep 17 00:00:00 2001 From: Stanislaw Gruszka Date: Fri, 29 Apr 2011 17:51:56 +0200 Subject: iwl4965: fix "Received BA when not expected" Need to use broadcast sta_id for management frames, otherwise we broke BA session in the firmware and get messages like that: "Received BA when not expected" or (on older kernels): "BA scd_flow 0 does not match txq_id 10" This fix regression introduced in 2.6.35 during station management code rewrite by: commit 2a87c26bbe9587baeb9e56d3ce0b4971bd777643 Author: Johannes Berg Date: Fri Apr 30 11:30:45 2010 -0700 iwlwifi: use iwl_find_station less Signed-off-by: Stanislaw Gruszka Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwlegacy/iwl-4965-tx.c b/drivers/net/wireless/iwlegacy/iwl-4965-tx.c index fbec88d..79ac081 100644 --- a/drivers/net/wireless/iwlegacy/iwl-4965-tx.c +++ b/drivers/net/wireless/iwlegacy/iwl-4965-tx.c @@ -316,12 +316,18 @@ int iwl4965_tx_skb(struct iwl_priv *priv, struct sk_buff *skb) hdr_len = ieee80211_hdrlen(fc); - /* Find index into station table for destination station */ - sta_id = iwl_legacy_sta_id_or_broadcast(priv, ctx, info->control.sta); - if (sta_id == IWL_INVALID_STATION) { - IWL_DEBUG_DROP(priv, "Dropping - INVALID STATION: %pM\n", - hdr->addr1); - goto drop_unlock; + /* For management frames use broadcast id to do not break aggregation */ + if (!ieee80211_is_data(fc)) + sta_id = ctx->bcast_sta_id; + else { + /* Find index into station table for destination station */ + sta_id = iwl_legacy_sta_id_or_broadcast(priv, ctx, info->control.sta); + + if (sta_id == IWL_INVALID_STATION) { + IWL_DEBUG_DROP(priv, "Dropping - INVALID STATION: %pM\n", + hdr->addr1); + goto drop_unlock; + } } IWL_DEBUG_TX(priv, "station Id %d\n", sta_id); -- cgit v0.10.2 From e245292e0a98bfbf2b54c5c0f079033f4d06dd32 Mon Sep 17 00:00:00 2001 From: "John W. Linville" Date: Fri, 29 Apr 2011 14:35:14 -0400 Subject: ath5k: fix uninitialized var warning for txf2txs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit CC [M] drivers/net/wireless/ath/ath5k/reset.o drivers/net/wireless/ath/ath5k/reset.c: In function ‘ath5k_hw_init_core_clock’: drivers/net/wireless/ath/ath5k/reset.c:100:51: warning: ‘txf2txs’ may be used uninitialized in this function Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath5k/reset.c b/drivers/net/wireless/ath/ath5k/reset.c index 8420689..3510de2 100644 --- a/drivers/net/wireless/ath/ath5k/reset.c +++ b/drivers/net/wireless/ath/ath5k/reset.c @@ -159,6 +159,11 @@ static void ath5k_hw_init_core_clock(struct ath5k_hw *ah) rxlat = AR5K_REG_MS(usec_reg, AR5K_USEC_RX_LATENCY_5211); /* + * Set default Tx frame to Tx data start delay + */ + txf2txs = AR5K_INIT_TXF2TXD_START_DEFAULT; + + /* * 5210 initvals don't include usec settings * so we need to use magic values here for * tx/rx latencies -- cgit v0.10.2 From 2eeb6fd063d812a528118536857d078bca5a1e05 Mon Sep 17 00:00:00 2001 From: "John W. Linville" Date: Fri, 29 Apr 2011 14:54:27 -0400 Subject: b43: avoid uninitialized variable warnings in phy_n MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit CC [M] drivers/net/wireless/b43/phy_n.o drivers/net/wireless/b43/phy_n.c: In function ‘b43_nphy_set_channel’: drivers/net/wireless/b43/phy_n.c:3848:47: warning: ‘tabent_r2’ may be used uninitialized in this function drivers/net/wireless/b43/phy_n.c:3849:47: warning: ‘tabent_r3’ may be used uninitialized in this function drivers/net/wireless/b43/phy_n.c: In function ‘b43_nphy_poll_rssi.clone.14’: drivers/net/wireless/b43/phy_n.c:2270:6: warning: ‘save_regs_phy$7’ may be used uninitialized in this function drivers/net/wireless/b43/phy_n.c:2270:6: warning: ‘save_regs_phy$8’ may be used uninitialized in this function FWIW, the usage of these variables is goverened by checks that match their initializations. So, I think these are actually false warnings. Still, I would rather avoid the warning SPAM... Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/b43/phy_n.c b/drivers/net/wireless/b43/phy_n.c index 8a00f9a..6755063 100644 --- a/drivers/net/wireless/b43/phy_n.c +++ b/drivers/net/wireless/b43/phy_n.c @@ -2281,6 +2281,7 @@ static int b43_nphy_poll_rssi(struct b43_wldev *dev, u8 type, s32 *buf, save_regs_phy[5] = b43_phy_read(dev, B43_NPHY_AFECTL_OVER); save_regs_phy[6] = b43_phy_read(dev, B43_NPHY_TXF_40CO_B1S0); save_regs_phy[7] = b43_phy_read(dev, B43_NPHY_TXF_40CO_B32S1); + save_regs_phy[8] = 0; } else { save_regs_phy[0] = b43_phy_read(dev, B43_NPHY_AFECTL_C1); save_regs_phy[1] = b43_phy_read(dev, B43_NPHY_AFECTL_C2); @@ -2289,6 +2290,8 @@ static int b43_nphy_poll_rssi(struct b43_wldev *dev, u8 type, s32 *buf, save_regs_phy[4] = b43_phy_read(dev, B43_NPHY_RFCTL_OVER); save_regs_phy[5] = b43_phy_read(dev, B43_NPHY_RFCTL_RSSIO1); save_regs_phy[6] = b43_phy_read(dev, B43_NPHY_RFCTL_RSSIO2); + save_regs_phy[7] = 0; + save_regs_phy[8] = 0; } b43_nphy_rssi_select(dev, 5, type); @@ -3845,8 +3848,8 @@ static int b43_nphy_set_channel(struct b43_wldev *dev, { struct b43_phy *phy = &dev->phy; - const struct b43_nphy_channeltab_entry_rev2 *tabent_r2; - const struct b43_nphy_channeltab_entry_rev3 *tabent_r3; + const struct b43_nphy_channeltab_entry_rev2 *tabent_r2 = NULL; + const struct b43_nphy_channeltab_entry_rev3 *tabent_r3 = NULL; u8 tmp; -- cgit v0.10.2 From f9c2fdbab1f1854f2bfcc75c326d0f4537ec2a7e Mon Sep 17 00:00:00 2001 From: "John W. Linville" Date: Fri, 29 Apr 2011 15:04:58 -0400 Subject: mwifiex: fix copy-n-paste 'thinko' for tsf_val MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit CC [M] drivers/net/wireless/mwifiex/join.o drivers/net/wireless/mwifiex/join.c: In function ‘mwifiex_cmd_802_11_associate’: drivers/net/wireless/mwifiex/join.c:119:8: warning: ‘tsf_val’ may be used uninitialized in this function drivers/net/wireless/mwifiex/join.c:103:12: note: ‘tsf_val’ was declared here Looks like a copy-n-paste error, identical lines are a few lines below the ones removed, with an actual memcpy to tsf_val in between... Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/mwifiex/join.c b/drivers/net/wireless/mwifiex/join.c index 23d2d0b..042eb77 100644 --- a/drivers/net/wireless/mwifiex/join.c +++ b/drivers/net/wireless/mwifiex/join.c @@ -116,9 +116,6 @@ mwifiex_cmd_append_tsf_tlv(struct mwifiex_private *priv, u8 **buffer, memcpy(*buffer, &tsf_tlv, sizeof(tsf_tlv.header)); *buffer += sizeof(tsf_tlv.header); - memcpy(*buffer, &tsf_val, sizeof(tsf_val)); - *buffer += sizeof(tsf_val); - memcpy(&tsf_val, bss_desc->time_stamp, sizeof(tsf_val)); dev_dbg(priv->adapter->dev, "info: %s: TSF offset calc: %016llx - " -- cgit v0.10.2 From ce6cac88a4f1e52a51a31c31562f4da347543147 Mon Sep 17 00:00:00 2001 From: "John W. Linville" Date: Fri, 29 Apr 2011 15:09:39 -0400 Subject: p54: avoid uninitialized variable warning for freq MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit CC [M] drivers/net/wireless/p54/eeprom.o drivers/net/wireless/p54/eeprom.c: In function ‘p54_parse_rssical’: drivers/net/wireless/p54/eeprom.c:494:8: warning: ‘freq’ may be used uninitialized in this function Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/p54/eeprom.c b/drivers/net/wireless/p54/eeprom.c index 13d750d..54cc0bb 100644 --- a/drivers/net/wireless/p54/eeprom.c +++ b/drivers/net/wireless/p54/eeprom.c @@ -491,7 +491,7 @@ static int p54_parse_rssical(struct ieee80211_hw *dev, struct pda_rssi_cal_entry *cal = (void *) &data[offset]; for (i = 0; i < entries; i++) { - u16 freq; + u16 freq = 0; switch (i) { case IEEE80211_BAND_2GHZ: freq = 2437; -- cgit v0.10.2 From 8333a46ad3877485e4d67ef499c6dda36bfd1f9a Mon Sep 17 00:00:00 2001 From: Neil Horman Date: Tue, 26 Apr 2011 10:30:11 +0000 Subject: bnx2: cancel timer on device removal This oops was recently reported to me: invalid opcode: 0000 [#1] SMP last sysfs file: /sys/devices/pci0000:00/0000:00:01.0/0000:01:0d.0/0000:02:05.0/device CPU 1 Modules linked in: bnx2(+) sunrpc ipv6 dm_mirror dm_region_hash dm_log sg microcode serio_raw amd64_edac_mod edac_core edac_mce_amd k8temp i2c_piix4 shpchp ext4 mbcache jbd2 sd_mod crc_t10dif mptsas mptscsih mptbase scsi_transport_sas radeon ttm drm_kms_helper drm hwmon i2c_algo_bit i2c_core dm_mod [last unloaded: bnx2] Modules linked in: bnx2(+) sunrpc ipv6 dm_mirror dm_region_hash dm_log sg microcode serio_raw amd64_edac_mod edac_core edac_mce_amd k8temp i2c_piix4 shpchp ext4 mbcache jbd2 sd_mod crc_t10dif mptsas mptscsih mptbase scsi_transport_sas radeon ttm drm_kms_helper drm hwmon i2c_algo_bit i2c_core dm_mod [last unloaded: bnx2] Pid: 23900, comm: pidof Not tainted 2.6.32-130.el6.x86_64 #1 BladeCenter LS21 -[797251Z]- RIP: 0010:[] [] 0xffffffffa058b270 RSP: 0018:ffff880002083e48 EFLAGS: 00010246 RAX: ffff880002083e90 RBX: ffff88007ccd4000 RCX: 0000000000000000 RDX: 0000000000000100 RSI: dead000000200200 RDI: ffff8800007b8700 RBP: ffff880002083ed0 R08: ffff88000208db40 R09: 0000022d191d27c8 R10: 0000000000000000 R11: 0000000000000000 R12: ffff8800007b9bc8 R13: ffff880002083e90 R14: ffff8800007b8700 R15: ffffffffa058b270 FS: 00007fbb3bcf7700(0000) GS:ffff880002080000(0000) knlGS:0000000000000000 CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 CR2: 0000000001664a98 CR3: 0000000060395000 CR4: 00000000000006e0 DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000 DR3: 0000000000000000 DR6: 00000000ffff0ff0 DR7: 0000000000000400 Process pidof (pid: 23900, threadinfo ffff8800007e8000, task ffff8800091c0040) Stack: ffffffff81079f77 ffffffff8109e010 ffff88007ccd5c20 ffff88007ccd5820 <0> ffff88007ccd5420 ffff8800007e9fd8 ffff8800007e9fd8 0000010000000000 <0> ffff88007ccd5020 ffff880002083e90 ffff880002083e90 ffffffff8102a00d Call Trace: [] ? run_timer_softirq+0x197/0x340 [] ? tick_sched_timer+0x0/0xc0 [] ? lapic_next_event+0x1d/0x30 [] __do_softirq+0xb7/0x1e0 [] ? hrtimer_interrupt+0x140/0x250 [] ? filldir+0x0/0xe0 [] call_softirq+0x1c/0x30 [] do_softirq+0x65/0xa0 [] irq_exit+0x85/0x90 [] smp_apic_timer_interrupt+0x70/0x9b [] apic_timer_interrupt+0x13/0x20 [] ? selinux_file_permission+0x45/0x150 [] ? _atomic_dec_and_lock+0x55/0x80 [] security_file_permission+0x16/0x20 [] vfs_readdir+0x71/0xe0 [] sys_getdents+0x89/0xf0 [] system_call_fastpath+0x16/0x1b It occured during some stress testing, in which the reporter was repeatedly removing and modprobing the bnx2 module while doing various other random operations on the bnx2 registered net device. Noting that this error occured on a serdes based device, we noted that there were a few ethtool operations (most notably self_test and set_phys_id) that have execution paths that lead into bnx2_setup_serdes_phy. This function is notable because it executes a mod_timer call, which starts the bp->timer running. Currently bnx2 is setup to assume that this timer only nees to be stopped when bnx2_close or bnx2_suspend is called. Since the above ethtool operations are not gated on the net device having been opened however, that assumption is incorrect, and can lead to the timer still running after the module has been removed, leading to the oops above (as well as other simmilar oopses). Fix the problem by ensuring that the timer is stopped when pci_device_unregister is called. Signed-off-by: Neil Horman Reported-by: Hushan Jia CC: Michael Chan CC: "David S. Miller" Acked-by: Michael Chan Signed-off-by: David S. Miller diff --git a/drivers/net/bnx2.c b/drivers/net/bnx2.c index 8e6d618..d8383a9 100644 --- a/drivers/net/bnx2.c +++ b/drivers/net/bnx2.c @@ -8413,6 +8413,8 @@ bnx2_remove_one(struct pci_dev *pdev) unregister_netdev(dev); + del_timer_sync(&bp->timer); + if (bp->mips_firmware) release_firmware(bp->mips_firmware); if (bp->rv2p_firmware) -- cgit v0.10.2 From 80d887c3b4566f4d14cd7cd5374eba30131d020f Mon Sep 17 00:00:00 2001 From: Sujith Manoharan Date: Thu, 28 Apr 2011 14:28:33 +0530 Subject: ath9k_htc: Dump base eeprom header for UB91/94/95 Debugfs file location: /ieee80211/phy#/ath9k_htc/base_eeprom Signed-off-by: Sujith Manoharan Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_debug.c b/drivers/net/wireless/ath/ath9k/htc_drv_debug.c index 894e5ef..cff2d21 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_debug.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_debug.c @@ -492,6 +492,158 @@ static const struct file_operations fops_debug = { .llseek = default_llseek, }; +static ssize_t read_file_base_eeprom(struct file *file, char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct ath9k_htc_priv *priv = file->private_data; + struct ath_common *common = ath9k_hw_common(priv->ah); + struct base_eep_header *pBase = NULL; + unsigned int len = 0, size = 1500; + ssize_t retval = 0; + char *buf; + + /* + * This can be done since all the 3 EEPROM families have the + * same base header upto a certain point, and we are interested in + * the data only upto that point. + */ + + if (AR_SREV_9271(priv->ah)) + pBase = (struct base_eep_header *) + &priv->ah->eeprom.map4k.baseEepHeader; + else if (priv->ah->hw_version.usbdev == AR9280_USB) + pBase = (struct base_eep_header *) + &priv->ah->eeprom.def.baseEepHeader; + else if (priv->ah->hw_version.usbdev == AR9287_USB) + pBase = (struct base_eep_header *) + &priv->ah->eeprom.map9287.baseEepHeader; + + if (pBase == NULL) { + ath_err(common, "Unknown EEPROM type\n"); + return 0; + } + + buf = kzalloc(size, GFP_KERNEL); + if (buf == NULL) + return -ENOMEM; + + len += snprintf(buf + len, size - len, + "%20s : %10d\n", "Major Version", + pBase->version >> 12); + len += snprintf(buf + len, size - len, + "%20s : %10d\n", "Minor Version", + pBase->version & 0xFFF); + len += snprintf(buf + len, size - len, + "%20s : %10d\n", "Checksum", + pBase->checksum); + len += snprintf(buf + len, size - len, + "%20s : %10d\n", "Length", + pBase->length); + len += snprintf(buf + len, size - len, + "%20s : %10d\n", "RegDomain1", + pBase->regDmn[0]); + len += snprintf(buf + len, size - len, + "%20s : %10d\n", "RegDomain2", + pBase->regDmn[1]); + len += snprintf(buf + len, size - len, + "%20s : %10d\n", + "TX Mask", pBase->txMask); + len += snprintf(buf + len, size - len, + "%20s : %10d\n", + "RX Mask", pBase->rxMask); + len += snprintf(buf + len, size - len, + "%20s : %10d\n", + "Allow 5GHz", + !!(pBase->opCapFlags & AR5416_OPFLAGS_11A)); + len += snprintf(buf + len, size - len, + "%20s : %10d\n", + "Allow 2GHz", + !!(pBase->opCapFlags & AR5416_OPFLAGS_11G)); + len += snprintf(buf + len, size - len, + "%20s : %10d\n", + "Disable 2GHz HT20", + !!(pBase->opCapFlags & AR5416_OPFLAGS_N_2G_HT20)); + len += snprintf(buf + len, size - len, + "%20s : %10d\n", + "Disable 2GHz HT40", + !!(pBase->opCapFlags & AR5416_OPFLAGS_N_2G_HT40)); + len += snprintf(buf + len, size - len, + "%20s : %10d\n", + "Disable 5Ghz HT20", + !!(pBase->opCapFlags & AR5416_OPFLAGS_N_5G_HT20)); + len += snprintf(buf + len, size - len, + "%20s : %10d\n", + "Disable 5Ghz HT40", + !!(pBase->opCapFlags & AR5416_OPFLAGS_N_5G_HT40)); + len += snprintf(buf + len, size - len, + "%20s : %10d\n", + "Big Endian", + !!(pBase->eepMisc & 0x01)); + len += snprintf(buf + len, size - len, + "%20s : %10d\n", + "Cal Bin Major Ver", + (pBase->binBuildNumber >> 24) & 0xFF); + len += snprintf(buf + len, size - len, + "%20s : %10d\n", + "Cal Bin Minor Ver", + (pBase->binBuildNumber >> 16) & 0xFF); + len += snprintf(buf + len, size - len, + "%20s : %10d\n", + "Cal Bin Build", + (pBase->binBuildNumber >> 8) & 0xFF); + + /* + * UB91 specific data. + */ + if (AR_SREV_9271(priv->ah)) { + struct base_eep_header_4k *pBase4k = + &priv->ah->eeprom.map4k.baseEepHeader; + + len += snprintf(buf + len, size - len, + "%20s : %10d\n", + "TX Gain type", + pBase4k->txGainType); + } + + /* + * UB95 specific data. + */ + if (priv->ah->hw_version.usbdev == AR9287_USB) { + struct base_eep_ar9287_header *pBase9287 = + &priv->ah->eeprom.map9287.baseEepHeader; + + len += snprintf(buf + len, size - len, + "%20s : %10ddB\n", + "Power Table Offset", + pBase9287->pwrTableOffset); + + len += snprintf(buf + len, size - len, + "%20s : %10d\n", + "OpenLoop Power Ctrl", + pBase9287->openLoopPwrCntl); + } + + len += snprintf(buf + len, size - len, + "%20s : %02X:%02X:%02X:%02X:%02X:%02X\n", + "MacAddress", + pBase->macAddr[0], pBase->macAddr[1], pBase->macAddr[2], + pBase->macAddr[3], pBase->macAddr[4], pBase->macAddr[5]); + if (len > size) + len = size; + + retval = simple_read_from_buffer(user_buf, count, ppos, buf, len); + kfree(buf); + + return retval; +} + +static const struct file_operations fops_base_eeprom = { + .read = read_file_base_eeprom, + .open = ath9k_debugfs_open, + .owner = THIS_MODULE, + .llseek = default_llseek, +}; + int ath9k_htc_init_debug(struct ath_hw *ah) { struct ath_common *common = ath9k_hw_common(ah); @@ -503,21 +655,23 @@ int ath9k_htc_init_debug(struct ath_hw *ah) return -ENOMEM; debugfs_create_file("tgt_int_stats", S_IRUSR, priv->debug.debugfs_phy, - priv, &fops_tgt_int_stats); + priv, &fops_tgt_int_stats); debugfs_create_file("tgt_tx_stats", S_IRUSR, priv->debug.debugfs_phy, - priv, &fops_tgt_tx_stats); + priv, &fops_tgt_tx_stats); debugfs_create_file("tgt_rx_stats", S_IRUSR, priv->debug.debugfs_phy, - priv, &fops_tgt_rx_stats); + priv, &fops_tgt_rx_stats); debugfs_create_file("xmit", S_IRUSR, priv->debug.debugfs_phy, - priv, &fops_xmit); + priv, &fops_xmit); debugfs_create_file("recv", S_IRUSR, priv->debug.debugfs_phy, - priv, &fops_recv); + priv, &fops_recv); debugfs_create_file("slot", S_IRUSR, priv->debug.debugfs_phy, - priv, &fops_slot); + priv, &fops_slot); debugfs_create_file("queue", S_IRUSR, priv->debug.debugfs_phy, - priv, &fops_queue); + priv, &fops_queue); debugfs_create_file("debug", S_IRUSR | S_IWUSR, priv->debug.debugfs_phy, - priv, &fops_debug); + priv, &fops_debug); + debugfs_create_file("base_eeprom", S_IRUSR, priv->debug.debugfs_phy, + priv, &fops_base_eeprom); return 0; } -- cgit v0.10.2 From 44368796b87d321e6ea84295a23b2e8eb415d300 Mon Sep 17 00:00:00 2001 From: Sujith Manoharan Date: Thu, 28 Apr 2011 14:28:51 +0530 Subject: ath9k_htc: Dump modal eeprom header for UB91/94/95 Debugfs file location: /ieee80211/phy#/ath9k_htc/modal_eeprom Signed-off-by: Sujith Manoharan Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_debug.c b/drivers/net/wireless/ath/ath9k/htc_drv_debug.c index cff2d21..aa48b3ab 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_debug.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_debug.c @@ -644,6 +644,287 @@ static const struct file_operations fops_base_eeprom = { .llseek = default_llseek, }; +static ssize_t read_4k_modal_eeprom(struct file *file, + char __user *user_buf, + size_t count, loff_t *ppos) +{ +#define PR_EEP(_s, _val) \ + do { \ + len += snprintf(buf + len, size - len, "%20s : %10d\n", \ + _s, (_val)); \ + } while (0) + + struct ath9k_htc_priv *priv = file->private_data; + struct modal_eep_4k_header *pModal = &priv->ah->eeprom.map4k.modalHeader; + unsigned int len = 0, size = 2048; + ssize_t retval = 0; + char *buf; + + buf = kzalloc(size, GFP_KERNEL); + if (buf == NULL) + return -ENOMEM; + + PR_EEP("Chain0 Ant. Control", pModal->antCtrlChain[0]); + PR_EEP("Ant. Common Control", pModal->antCtrlCommon); + PR_EEP("Chain0 Ant. Gain", pModal->antennaGainCh[0]); + PR_EEP("Switch Settle", pModal->switchSettling); + PR_EEP("Chain0 TxRxAtten", pModal->txRxAttenCh[0]); + PR_EEP("Chain0 RxTxMargin", pModal->rxTxMarginCh[0]); + PR_EEP("ADC Desired size", pModal->adcDesiredSize); + PR_EEP("PGA Desired size", pModal->pgaDesiredSize); + PR_EEP("Chain0 xlna Gain", pModal->xlnaGainCh[0]); + PR_EEP("txEndToXpaOff", pModal->txEndToXpaOff); + PR_EEP("txEndToRxOn", pModal->txEndToRxOn); + PR_EEP("txFrameToXpaOn", pModal->txFrameToXpaOn); + PR_EEP("CCA Threshold)", pModal->thresh62); + PR_EEP("Chain0 NF Threshold", pModal->noiseFloorThreshCh[0]); + PR_EEP("xpdGain", pModal->xpdGain); + PR_EEP("External PD", pModal->xpd); + PR_EEP("Chain0 I Coefficient", pModal->iqCalICh[0]); + PR_EEP("Chain0 Q Coefficient", pModal->iqCalQCh[0]); + PR_EEP("pdGainOverlap", pModal->pdGainOverlap); + PR_EEP("O/D Bias Version", pModal->version); + PR_EEP("CCK OutputBias", pModal->ob_0); + PR_EEP("BPSK OutputBias", pModal->ob_1); + PR_EEP("QPSK OutputBias", pModal->ob_2); + PR_EEP("16QAM OutputBias", pModal->ob_3); + PR_EEP("64QAM OutputBias", pModal->ob_4); + PR_EEP("CCK Driver1_Bias", pModal->db1_0); + PR_EEP("BPSK Driver1_Bias", pModal->db1_1); + PR_EEP("QPSK Driver1_Bias", pModal->db1_2); + PR_EEP("16QAM Driver1_Bias", pModal->db1_3); + PR_EEP("64QAM Driver1_Bias", pModal->db1_4); + PR_EEP("CCK Driver2_Bias", pModal->db2_0); + PR_EEP("BPSK Driver2_Bias", pModal->db2_1); + PR_EEP("QPSK Driver2_Bias", pModal->db2_2); + PR_EEP("16QAM Driver2_Bias", pModal->db2_3); + PR_EEP("64QAM Driver2_Bias", pModal->db2_4); + PR_EEP("xPA Bias Level", pModal->xpaBiasLvl); + PR_EEP("txFrameToDataStart", pModal->txFrameToDataStart); + PR_EEP("txFrameToPaOn", pModal->txFrameToPaOn); + PR_EEP("HT40 Power Inc.", pModal->ht40PowerIncForPdadc); + PR_EEP("Chain0 bswAtten", pModal->bswAtten[0]); + PR_EEP("Chain0 bswMargin", pModal->bswMargin[0]); + PR_EEP("HT40 Switch Settle", pModal->swSettleHt40); + PR_EEP("Chain0 xatten2Db", pModal->xatten2Db[0]); + PR_EEP("Chain0 xatten2Margin", pModal->xatten2Margin[0]); + PR_EEP("Ant. Diversity ctl1", pModal->antdiv_ctl1); + PR_EEP("Ant. Diversity ctl2", pModal->antdiv_ctl2); + PR_EEP("TX Diversity", pModal->tx_diversity); + + if (len > size) + len = size; + + retval = simple_read_from_buffer(user_buf, count, ppos, buf, len); + kfree(buf); + + return retval; + +#undef PR_EEP +} + +static ssize_t read_def_modal_eeprom(struct file *file, + char __user *user_buf, + size_t count, loff_t *ppos) +{ +#define PR_EEP(_s, _val) \ + do { \ + if (pBase->opCapFlags & AR5416_OPFLAGS_11G) { \ + pModal = &priv->ah->eeprom.def.modalHeader[1]; \ + len += snprintf(buf + len, size - len, "%20s : %8d%7s", \ + _s, (_val), "|"); \ + } \ + if (pBase->opCapFlags & AR5416_OPFLAGS_11A) { \ + pModal = &priv->ah->eeprom.def.modalHeader[0]; \ + len += snprintf(buf + len, size - len, "%9d\n", \ + (_val)); \ + } \ + } while (0) + + struct ath9k_htc_priv *priv = file->private_data; + struct base_eep_header *pBase = &priv->ah->eeprom.def.baseEepHeader; + struct modal_eep_header *pModal = NULL; + unsigned int len = 0, size = 3500; + ssize_t retval = 0; + char *buf; + + buf = kzalloc(size, GFP_KERNEL); + if (buf == NULL) + return -ENOMEM; + + len += snprintf(buf + len, size - len, + "%31s %15s\n", "2G", "5G"); + len += snprintf(buf + len, size - len, + "%32s %16s\n", "====", "====\n"); + + PR_EEP("Chain0 Ant. Control", pModal->antCtrlChain[0]); + PR_EEP("Chain1 Ant. Control", pModal->antCtrlChain[1]); + PR_EEP("Chain2 Ant. Control", pModal->antCtrlChain[2]); + PR_EEP("Ant. Common Control", pModal->antCtrlCommon); + PR_EEP("Chain0 Ant. Gain", pModal->antennaGainCh[0]); + PR_EEP("Chain1 Ant. Gain", pModal->antennaGainCh[1]); + PR_EEP("Chain2 Ant. Gain", pModal->antennaGainCh[2]); + PR_EEP("Switch Settle", pModal->switchSettling); + PR_EEP("Chain0 TxRxAtten", pModal->txRxAttenCh[0]); + PR_EEP("Chain1 TxRxAtten", pModal->txRxAttenCh[1]); + PR_EEP("Chain2 TxRxAtten", pModal->txRxAttenCh[2]); + PR_EEP("Chain0 RxTxMargin", pModal->rxTxMarginCh[0]); + PR_EEP("Chain1 RxTxMargin", pModal->rxTxMarginCh[1]); + PR_EEP("Chain2 RxTxMargin", pModal->rxTxMarginCh[2]); + PR_EEP("ADC Desired size", pModal->adcDesiredSize); + PR_EEP("PGA Desired size", pModal->pgaDesiredSize); + PR_EEP("Chain0 xlna Gain", pModal->xlnaGainCh[0]); + PR_EEP("Chain1 xlna Gain", pModal->xlnaGainCh[1]); + PR_EEP("Chain2 xlna Gain", pModal->xlnaGainCh[2]); + PR_EEP("txEndToXpaOff", pModal->txEndToXpaOff); + PR_EEP("txEndToRxOn", pModal->txEndToRxOn); + PR_EEP("txFrameToXpaOn", pModal->txFrameToXpaOn); + PR_EEP("CCA Threshold)", pModal->thresh62); + PR_EEP("Chain0 NF Threshold", pModal->noiseFloorThreshCh[0]); + PR_EEP("Chain1 NF Threshold", pModal->noiseFloorThreshCh[1]); + PR_EEP("Chain2 NF Threshold", pModal->noiseFloorThreshCh[2]); + PR_EEP("xpdGain", pModal->xpdGain); + PR_EEP("External PD", pModal->xpd); + PR_EEP("Chain0 I Coefficient", pModal->iqCalICh[0]); + PR_EEP("Chain1 I Coefficient", pModal->iqCalICh[1]); + PR_EEP("Chain2 I Coefficient", pModal->iqCalICh[2]); + PR_EEP("Chain0 Q Coefficient", pModal->iqCalQCh[0]); + PR_EEP("Chain1 Q Coefficient", pModal->iqCalQCh[1]); + PR_EEP("Chain2 Q Coefficient", pModal->iqCalQCh[2]); + PR_EEP("pdGainOverlap", pModal->pdGainOverlap); + PR_EEP("Chain0 OutputBias", pModal->ob); + PR_EEP("Chain0 DriverBias", pModal->db); + PR_EEP("xPA Bias Level", pModal->xpaBiasLvl); + PR_EEP("2chain pwr decrease", pModal->pwrDecreaseFor2Chain); + PR_EEP("3chain pwr decrease", pModal->pwrDecreaseFor3Chain); + PR_EEP("txFrameToDataStart", pModal->txFrameToDataStart); + PR_EEP("txFrameToPaOn", pModal->txFrameToPaOn); + PR_EEP("HT40 Power Inc.", pModal->ht40PowerIncForPdadc); + PR_EEP("Chain0 bswAtten", pModal->bswAtten[0]); + PR_EEP("Chain1 bswAtten", pModal->bswAtten[1]); + PR_EEP("Chain2 bswAtten", pModal->bswAtten[2]); + PR_EEP("Chain0 bswMargin", pModal->bswMargin[0]); + PR_EEP("Chain1 bswMargin", pModal->bswMargin[1]); + PR_EEP("Chain2 bswMargin", pModal->bswMargin[2]); + PR_EEP("HT40 Switch Settle", pModal->swSettleHt40); + PR_EEP("Chain0 xatten2Db", pModal->xatten2Db[0]); + PR_EEP("Chain1 xatten2Db", pModal->xatten2Db[1]); + PR_EEP("Chain2 xatten2Db", pModal->xatten2Db[2]); + PR_EEP("Chain0 xatten2Margin", pModal->xatten2Margin[0]); + PR_EEP("Chain1 xatten2Margin", pModal->xatten2Margin[1]); + PR_EEP("Chain2 xatten2Margin", pModal->xatten2Margin[2]); + PR_EEP("Chain1 OutputBias", pModal->ob_ch1); + PR_EEP("Chain1 DriverBias", pModal->db_ch1); + PR_EEP("LNA Control", pModal->lna_ctl); + PR_EEP("XPA Bias Freq0", pModal->xpaBiasLvlFreq[0]); + PR_EEP("XPA Bias Freq1", pModal->xpaBiasLvlFreq[1]); + PR_EEP("XPA Bias Freq2", pModal->xpaBiasLvlFreq[2]); + + if (len > size) + len = size; + + retval = simple_read_from_buffer(user_buf, count, ppos, buf, len); + kfree(buf); + + return retval; + +#undef PR_EEP +} + +static ssize_t read_9287_modal_eeprom(struct file *file, + char __user *user_buf, + size_t count, loff_t *ppos) +{ +#define PR_EEP(_s, _val) \ + do { \ + len += snprintf(buf + len, size - len, "%20s : %10d\n", \ + _s, (_val)); \ + } while (0) + + struct ath9k_htc_priv *priv = file->private_data; + struct modal_eep_ar9287_header *pModal = &priv->ah->eeprom.map9287.modalHeader; + unsigned int len = 0, size = 3000; + ssize_t retval = 0; + char *buf; + + buf = kzalloc(size, GFP_KERNEL); + if (buf == NULL) + return -ENOMEM; + + PR_EEP("Chain0 Ant. Control", pModal->antCtrlChain[0]); + PR_EEP("Chain1 Ant. Control", pModal->antCtrlChain[1]); + PR_EEP("Ant. Common Control", pModal->antCtrlCommon); + PR_EEP("Chain0 Ant. Gain", pModal->antennaGainCh[0]); + PR_EEP("Chain1 Ant. Gain", pModal->antennaGainCh[1]); + PR_EEP("Switch Settle", pModal->switchSettling); + PR_EEP("Chain0 TxRxAtten", pModal->txRxAttenCh[0]); + PR_EEP("Chain1 TxRxAtten", pModal->txRxAttenCh[1]); + PR_EEP("Chain0 RxTxMargin", pModal->rxTxMarginCh[0]); + PR_EEP("Chain1 RxTxMargin", pModal->rxTxMarginCh[1]); + PR_EEP("ADC Desired size", pModal->adcDesiredSize); + PR_EEP("txEndToXpaOff", pModal->txEndToXpaOff); + PR_EEP("txEndToRxOn", pModal->txEndToRxOn); + PR_EEP("txFrameToXpaOn", pModal->txFrameToXpaOn); + PR_EEP("CCA Threshold)", pModal->thresh62); + PR_EEP("Chain0 NF Threshold", pModal->noiseFloorThreshCh[0]); + PR_EEP("Chain1 NF Threshold", pModal->noiseFloorThreshCh[1]); + PR_EEP("xpdGain", pModal->xpdGain); + PR_EEP("External PD", pModal->xpd); + PR_EEP("Chain0 I Coefficient", pModal->iqCalICh[0]); + PR_EEP("Chain1 I Coefficient", pModal->iqCalICh[1]); + PR_EEP("Chain0 Q Coefficient", pModal->iqCalQCh[0]); + PR_EEP("Chain1 Q Coefficient", pModal->iqCalQCh[1]); + PR_EEP("pdGainOverlap", pModal->pdGainOverlap); + PR_EEP("xPA Bias Level", pModal->xpaBiasLvl); + PR_EEP("txFrameToDataStart", pModal->txFrameToDataStart); + PR_EEP("txFrameToPaOn", pModal->txFrameToPaOn); + PR_EEP("HT40 Power Inc.", pModal->ht40PowerIncForPdadc); + PR_EEP("Chain0 bswAtten", pModal->bswAtten[0]); + PR_EEP("Chain1 bswAtten", pModal->bswAtten[1]); + PR_EEP("Chain0 bswMargin", pModal->bswMargin[0]); + PR_EEP("Chain1 bswMargin", pModal->bswMargin[1]); + PR_EEP("HT40 Switch Settle", pModal->swSettleHt40); + PR_EEP("AR92x7 Version", pModal->version); + PR_EEP("DriverBias1", pModal->db1); + PR_EEP("DriverBias2", pModal->db1); + PR_EEP("CCK OutputBias", pModal->ob_cck); + PR_EEP("PSK OutputBias", pModal->ob_psk); + PR_EEP("QAM OutputBias", pModal->ob_qam); + PR_EEP("PAL_OFF OutputBias", pModal->ob_pal_off); + + if (len > size) + len = size; + + retval = simple_read_from_buffer(user_buf, count, ppos, buf, len); + kfree(buf); + + return retval; + +#undef PR_EEP +} + +static ssize_t read_file_modal_eeprom(struct file *file, char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct ath9k_htc_priv *priv = file->private_data; + + if (AR_SREV_9271(priv->ah)) + return read_4k_modal_eeprom(file, user_buf, count, ppos); + else if (priv->ah->hw_version.usbdev == AR9280_USB) + return read_def_modal_eeprom(file, user_buf, count, ppos); + else if (priv->ah->hw_version.usbdev == AR9287_USB) + return read_9287_modal_eeprom(file, user_buf, count, ppos); + + return 0; +} + +static const struct file_operations fops_modal_eeprom = { + .read = read_file_modal_eeprom, + .open = ath9k_debugfs_open, + .owner = THIS_MODULE, + .llseek = default_llseek, +}; + int ath9k_htc_init_debug(struct ath_hw *ah) { struct ath_common *common = ath9k_hw_common(ah); @@ -672,6 +953,8 @@ int ath9k_htc_init_debug(struct ath_hw *ah) priv, &fops_debug); debugfs_create_file("base_eeprom", S_IRUSR, priv->debug.debugfs_phy, priv, &fops_base_eeprom); + debugfs_create_file("modal_eeprom", S_IRUSR, priv->debug.debugfs_phy, + priv, &fops_modal_eeprom); return 0; } -- cgit v0.10.2 From 75d80cadf4ceb238e55487ff6d3f9a0706e1028d Mon Sep 17 00:00:00 2001 From: Stanislaw Gruszka Date: Thu, 28 Apr 2011 11:12:10 +0200 Subject: iwlagn: fix tx power initialization Since commit f844a709a7d8f8be61a571afc31dfaca9e779621 Author: Stanislaw Gruszka Date: Fri Jan 28 16:47:44 2011 +0100 iwlwifi: do not set tx power when channel is changing we set device tx power during initialization to priv->tx_power_next, which itself is initialized to minimum power. That changed default behaviour of driver. Previously we initialized device to transmit at maximum available power by default. Patch change again to previous behaviour and cleanup tx power initialization. Fortunately this is not critical fix, as mac80211 layer setup tx power lately to 14dB, hence device does not operate at minimal transmit power all the time. Signed-off-by: Stanislaw Gruszka Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index a4f1009..a4ec524 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -3444,12 +3444,6 @@ static int iwl_init_drv(struct iwl_priv *priv) priv->dynamic_frag_thresh = BT_FRAG_THRESHOLD_DEF; } - /* Set the tx_power_user_lmt to the lowest power level - * this value will get overwritten by channel max power avg - * from eeprom */ - priv->tx_power_user_lmt = IWLAGN_TX_POWER_TARGET_POWER_MIN; - priv->tx_power_next = IWLAGN_TX_POWER_TARGET_POWER_MIN; - ret = iwl_init_channel_map(priv); if (ret) { IWL_ERR(priv, "initializing regulatory failed: %d\n", ret); diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index 46d6965..af72fd5 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -135,6 +135,7 @@ int iwlcore_init_geos(struct iwl_priv *priv) struct ieee80211_channel *geo_ch; struct ieee80211_rate *rates; int i = 0; + s8 max_tx_power = IWLAGN_TX_POWER_TARGET_POWER_MIN; if (priv->bands[IEEE80211_BAND_2GHZ].n_bitrates || priv->bands[IEEE80211_BAND_5GHZ].n_bitrates) { @@ -208,8 +209,8 @@ int iwlcore_init_geos(struct iwl_priv *priv) geo_ch->flags |= ch->ht40_extension_channel; - if (ch->max_power_avg > priv->tx_power_device_lmt) - priv->tx_power_device_lmt = ch->max_power_avg; + if (ch->max_power_avg > max_tx_power) + max_tx_power = ch->max_power_avg; } else { geo_ch->flags |= IEEE80211_CHAN_DISABLED; } @@ -222,6 +223,10 @@ int iwlcore_init_geos(struct iwl_priv *priv) geo_ch->flags); } + priv->tx_power_device_lmt = max_tx_power; + priv->tx_power_user_lmt = max_tx_power; + priv->tx_power_next = max_tx_power; + if ((priv->bands[IEEE80211_BAND_5GHZ].n_channels == 0) && priv->cfg->sku & IWL_SKU_A) { IWL_INFO(priv, "Incorrectly detected BG card as ABG. " diff --git a/drivers/net/wireless/iwlwifi/iwl-eeprom.c b/drivers/net/wireless/iwlwifi/iwl-eeprom.c index 4027336..1e1a2d8 100644 --- a/drivers/net/wireless/iwlwifi/iwl-eeprom.c +++ b/drivers/net/wireless/iwlwifi/iwl-eeprom.c @@ -711,13 +711,6 @@ int iwl_init_channel_map(struct iwl_priv *priv) flags & EEPROM_CHANNEL_RADAR)) ? "" : "not "); - /* Set the tx_power_user_lmt to the highest power - * supported by any channel */ - if (eeprom_ch_info[ch].max_power_avg > - priv->tx_power_user_lmt) - priv->tx_power_user_lmt = - eeprom_ch_info[ch].max_power_avg; - ch_info++; } } -- cgit v0.10.2 From ab42b4041707f075533845ecb320c7a1c5621f1b Mon Sep 17 00:00:00 2001 From: Stanislaw Gruszka Date: Thu, 28 Apr 2011 11:51:24 +0200 Subject: iwlegacy: remove duplicate initialization in iwl4956_down() Signed-off-by: Stanislaw Gruszka Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwlegacy/iwl4965-base.c b/drivers/net/wireless/iwlegacy/iwl4965-base.c index f887054..0387383 100644 --- a/drivers/net/wireless/iwlegacy/iwl4965-base.c +++ b/drivers/net/wireless/iwlegacy/iwl4965-base.c @@ -2139,7 +2139,7 @@ static void iwl4965_cancel_deferred_work(struct iwl_priv *priv); static void __iwl4965_down(struct iwl_priv *priv) { unsigned long flags; - int exit_pending = test_bit(STATUS_EXIT_PENDING, &priv->status); + int exit_pending; IWL_DEBUG_INFO(priv, DRV_NAME " is going down\n"); -- cgit v0.10.2 From a078a1fde11b350161e7db2c44353dfae7749212 Mon Sep 17 00:00:00 2001 From: Stanislaw Gruszka Date: Thu, 28 Apr 2011 11:51:25 +0200 Subject: iwlegacy: enable only rfkill interrupt when device is down Add two below iwlwifi commits to iwlegacy: commit 554d1d027b19265c4aa3f718b3126d2b86e09a08 Author: Stanislaw Gruszka Date: Thu Dec 23 12:38:21 2010 +0100 iwlagn: enable only rfkill interrupt when device is down commit 3dd823e6b86407aed1a025041d8f1df77e43a9c8 Author: Don Fry Date: Sun Feb 6 09:29:45 2011 -0800 iwlagn: Re-enable RF_KILL interrupt when down Signed-off-by: Stanislaw Gruszka Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwlegacy/iwl-helpers.h b/drivers/net/wireless/iwlegacy/iwl-helpers.h index 02132e7..a6effda 100644 --- a/drivers/net/wireless/iwlegacy/iwl-helpers.h +++ b/drivers/net/wireless/iwlegacy/iwl-helpers.h @@ -149,6 +149,12 @@ static inline void iwl_legacy_disable_interrupts(struct iwl_priv *priv) IWL_DEBUG_ISR(priv, "Disabled interrupts\n"); } +static inline void iwl_legacy_enable_rfkill_int(struct iwl_priv *priv) +{ + IWL_DEBUG_ISR(priv, "Enabling rfkill interrupt\n"); + iwl_write32(priv, CSR_INT_MASK, CSR_INT_BIT_RF_KILL); +} + static inline void iwl_legacy_enable_interrupts(struct iwl_priv *priv) { IWL_DEBUG_ISR(priv, "Enabling interrupts\n"); diff --git a/drivers/net/wireless/iwlegacy/iwl4965-base.c b/drivers/net/wireless/iwlegacy/iwl4965-base.c index 0387383..58a2e63 100644 --- a/drivers/net/wireless/iwlegacy/iwl4965-base.c +++ b/drivers/net/wireless/iwlegacy/iwl4965-base.c @@ -1072,6 +1072,9 @@ static void iwl4965_irq_tasklet(struct iwl_priv *priv) /* only Re-enable if diabled by irq */ if (test_bit(STATUS_INT_ENABLED, &priv->status)) iwl_legacy_enable_interrupts(priv); + /* Re-enable RF_KILL if it occurred */ + else if (handled & CSR_INT_BIT_RF_KILL) + iwl_legacy_enable_rfkill_int(priv); #ifdef CONFIG_IWLWIFI_LEGACY_DEBUG if (iwl_legacy_get_debug_level(priv) & (IWL_DL_ISR)) { @@ -2624,9 +2627,10 @@ void iwl4965_mac_stop(struct ieee80211_hw *hw) flush_workqueue(priv->workqueue); - /* enable interrupts again in order to receive rfkill changes */ + /* User space software may expect getting rfkill changes + * even if interface is down */ iwl_write32(priv, CSR_INT, 0xFFFFFFFF); - iwl_legacy_enable_interrupts(priv); + iwl_legacy_enable_rfkill_int(priv); IWL_DEBUG_MAC80211(priv, "leave\n"); } @@ -3406,14 +3410,14 @@ iwl4965_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) * 8. Enable interrupts and read RFKILL state *********************************************/ - /* enable interrupts if needed: hw bug w/a */ + /* enable rfkill interrupt: hw bug w/a */ pci_read_config_word(priv->pci_dev, PCI_COMMAND, &pci_cmd); if (pci_cmd & PCI_COMMAND_INTX_DISABLE) { pci_cmd &= ~PCI_COMMAND_INTX_DISABLE; pci_write_config_word(priv->pci_dev, PCI_COMMAND, pci_cmd); } - iwl_legacy_enable_interrupts(priv); + iwl_legacy_enable_rfkill_int(priv); /* If platform's RF_KILL switch is NOT set to KILL */ if (iwl_read32(priv, CSR_GP_CNTRL) & -- cgit v0.10.2 From 3e41de85f8e3419257df62dd6fe6bdd95a1fdcab Mon Sep 17 00:00:00 2001 From: Stanislaw Gruszka Date: Thu, 28 Apr 2011 11:51:26 +0200 Subject: iwlegacy: simplify init geos Don't need to use conditional as ch->band is already assigned to IEEE80211_BAND_5GHZ or IEEE80211_BAND_2GHZ Signed-off-by: Stanislaw Gruszka Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwlegacy/iwl-core.c b/drivers/net/wireless/iwlegacy/iwl-core.c index 2b08efb..82201ac 100644 --- a/drivers/net/wireless/iwlegacy/iwl-core.c +++ b/drivers/net/wireless/iwlegacy/iwl-core.c @@ -211,10 +211,7 @@ int iwl_legacy_init_geos(struct iwl_priv *priv) if (!iwl_legacy_is_channel_valid(ch)) continue; - if (iwl_legacy_is_channel_a_band(ch)) - sband = &priv->bands[IEEE80211_BAND_5GHZ]; - else - sband = &priv->bands[IEEE80211_BAND_2GHZ]; + sband = &priv->bands[ch->band]; geo_ch = &sband->channels[sband->n_channels++]; -- cgit v0.10.2 From 8eb0ac70a7a53cf851027d022616c01591ee4c33 Mon Sep 17 00:00:00 2001 From: Stanislaw Gruszka Date: Thu, 28 Apr 2011 11:51:27 +0200 Subject: iwlegacy: remove unneeded disable_hw_scan check We never set STATUS_SCANNING in softwre scanning mode, disable_hw_scan check is unneeded. Correct debug message while at it. Signed-off-by: Stanislaw Gruszka Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwlegacy/iwl-core.c b/drivers/net/wireless/iwlegacy/iwl-core.c index 82201ac..9676b3d 100644 --- a/drivers/net/wireless/iwlegacy/iwl-core.c +++ b/drivers/net/wireless/iwlegacy/iwl-core.c @@ -2114,10 +2114,9 @@ int iwl_legacy_mac_config(struct ieee80211_hw *hw, u32 changed) IWL_DEBUG_MAC80211(priv, "enter to channel %d changed 0x%X\n", channel->hw_value, changed); - if (unlikely(!priv->cfg->mod_params->disable_hw_scan && - test_bit(STATUS_SCANNING, &priv->status))) { + if (unlikely(test_bit(STATUS_SCANNING, &priv->status))) { scan_active = 1; - IWL_DEBUG_MAC80211(priv, "leave - scanning\n"); + IWL_DEBUG_MAC80211(priv, "scan active\n"); } if (changed & (IEEE80211_CONF_CHANGE_SMPS | -- cgit v0.10.2 From 5855c7d81530aaf82293aaa252c4f9ff69ef33f9 Mon Sep 17 00:00:00 2001 From: Stanislaw Gruszka Date: Thu, 28 Apr 2011 11:51:28 +0200 Subject: iwlegacy: remove unneeded __packed struct iwl_queue is not part of firmware interface, so __packed is not needed. Remove it since is may affect performance. Signed-off-by: Stanislaw Gruszka Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwlegacy/iwl-dev.h b/drivers/net/wireless/iwlegacy/iwl-dev.h index 9ee849d..36c01aa 100644 --- a/drivers/net/wireless/iwlegacy/iwl-dev.h +++ b/drivers/net/wireless/iwlegacy/iwl-dev.h @@ -134,7 +134,7 @@ struct iwl_queue { * space more than this */ int high_mark; /* high watermark, stop queue if free * space less than this */ -} __packed; +}; /* One for each TFD */ struct iwl_tx_info { -- cgit v0.10.2 From 7a55237ac9f133c1d48fbe54d22dc2bd715e7b51 Mon Sep 17 00:00:00 2001 From: Stanislaw Gruszka Date: Thu, 28 Apr 2011 11:51:29 +0200 Subject: iwlegacy: remove scan_tx_antennas Signed-off-by: Stanislaw Gruszka Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwlegacy/iwl-4965-lib.c b/drivers/net/wireless/iwlegacy/iwl-4965-lib.c index 5a8a3cc..7e5e85a 100644 --- a/drivers/net/wireless/iwlegacy/iwl-4965-lib.c +++ b/drivers/net/wireless/iwlegacy/iwl-4965-lib.c @@ -955,9 +955,6 @@ int iwl4965_request_scan(struct iwl_priv *priv, struct ieee80211_vif *vif) if (priv->cfg->scan_rx_antennas[band]) rx_ant = priv->cfg->scan_rx_antennas[band]; - if (priv->cfg->scan_tx_antennas[band]) - scan_tx_antennas = priv->cfg->scan_tx_antennas[band]; - priv->scan_tx_ant[band] = iwl4965_toggle_tx_ant(priv, priv->scan_tx_ant[band], scan_tx_antennas); diff --git a/drivers/net/wireless/iwlegacy/iwl-core.h b/drivers/net/wireless/iwlegacy/iwl-core.h index f03b463..bc66c60 100644 --- a/drivers/net/wireless/iwlegacy/iwl-core.h +++ b/drivers/net/wireless/iwlegacy/iwl-core.h @@ -287,7 +287,6 @@ struct iwl_cfg { struct iwl_base_params *base_params; /* params likely to change within a device family */ u8 scan_rx_antennas[IEEE80211_NUM_BANDS]; - u8 scan_tx_antennas[IEEE80211_NUM_BANDS]; enum iwl_led_mode led_mode; }; -- cgit v0.10.2 From 93fd74e3d5471c4c91a239599a88fa7e52686e71 Mon Sep 17 00:00:00 2001 From: Stanislaw Gruszka Date: Thu, 28 Apr 2011 11:51:30 +0200 Subject: iwlegacy: comment typo fix diable -> disable Signed-off-by: Stanislaw Gruszka Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwlegacy/iwl-core.c b/drivers/net/wireless/iwlegacy/iwl-core.c index 9676b3d..553c91b 100644 --- a/drivers/net/wireless/iwlegacy/iwl-core.c +++ b/drivers/net/wireless/iwlegacy/iwl-core.c @@ -2642,7 +2642,7 @@ unplugged: none: /* re-enable interrupts here since we don't have anything to service. */ - /* only Re-enable if diabled by irq */ + /* only Re-enable if disabled by irq */ if (test_bit(STATUS_INT_ENABLED, &priv->status)) iwl_legacy_enable_interrupts(priv); spin_unlock_irqrestore(&priv->lock, flags); diff --git a/drivers/net/wireless/iwlegacy/iwl4965-base.c b/drivers/net/wireless/iwlegacy/iwl4965-base.c index 58a2e63..2da6070 100644 --- a/drivers/net/wireless/iwlegacy/iwl4965-base.c +++ b/drivers/net/wireless/iwlegacy/iwl4965-base.c @@ -1069,7 +1069,7 @@ static void iwl4965_irq_tasklet(struct iwl_priv *priv) } /* Re-enable all interrupts */ - /* only Re-enable if diabled by irq */ + /* only Re-enable if disabled by irq */ if (test_bit(STATUS_INT_ENABLED, &priv->status)) iwl_legacy_enable_interrupts(priv); /* Re-enable RF_KILL if it occurred */ -- cgit v0.10.2 From 81e63263aa3c5bfa64aa3206f4be3e59afc1c183 Mon Sep 17 00:00:00 2001 From: Stanislaw Gruszka Date: Thu, 28 Apr 2011 11:51:31 +0200 Subject: iwlegacy: fix enqueue hcmd race conditions We mark command as huge by using meta->flags from other (non huge) command, but flags can be possibly overridden, when non huge command is enqueued, what can lead to: WARNING: at lib/dma-debug.c:696 dma_debug_device_change+0x1a3/0x1f0() DMA-API: device driver has pending DMA allocations while released from device [count=1] To fix introduce additional CMD_MAPPED to mark command as mapped and serialize iwl_enqueue_hcmd() with iwl_tx_cmd_complete() using hcmd_lock. Serialization will also fix possible race conditions, because q->read_ptr, q->write_ptr are modified/used in parallel. Do not change callback, I did (and fixed) that mistake in iwlagn. Signed-off-by: Stanislaw Gruszka Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwlegacy/iwl-dev.h b/drivers/net/wireless/iwlegacy/iwl-dev.h index 36c01aa..df19d5c 100644 --- a/drivers/net/wireless/iwlegacy/iwl-dev.h +++ b/drivers/net/wireless/iwlegacy/iwl-dev.h @@ -290,6 +290,7 @@ enum { CMD_SIZE_HUGE = (1 << 0), CMD_ASYNC = (1 << 1), CMD_WANT_SKB = (1 << 2), + CMD_MAPPED = (1 << 3), }; #define DEF_CMD_PAYLOAD_SIZE 320 diff --git a/drivers/net/wireless/iwlegacy/iwl-tx.c b/drivers/net/wireless/iwlegacy/iwl-tx.c index a227773..4fff995 100644 --- a/drivers/net/wireless/iwlegacy/iwl-tx.c +++ b/drivers/net/wireless/iwlegacy/iwl-tx.c @@ -146,33 +146,32 @@ void iwl_legacy_cmd_queue_unmap(struct iwl_priv *priv) { struct iwl_tx_queue *txq = &priv->txq[priv->cmd_queue]; struct iwl_queue *q = &txq->q; - bool huge = false; int i; if (q->n_bd == 0) return; while (q->read_ptr != q->write_ptr) { - /* we have no way to tell if it is a huge cmd ATM */ i = iwl_legacy_get_cmd_index(q, q->read_ptr, 0); - if (txq->meta[i].flags & CMD_SIZE_HUGE) - huge = true; - else + if (txq->meta[i].flags & CMD_MAPPED) { pci_unmap_single(priv->pci_dev, dma_unmap_addr(&txq->meta[i], mapping), dma_unmap_len(&txq->meta[i], len), PCI_DMA_BIDIRECTIONAL); + txq->meta[i].flags = 0; + } q->read_ptr = iwl_legacy_queue_inc_wrap(q->read_ptr, q->n_bd); } - if (huge) { - i = q->n_window; + i = q->n_window; + if (txq->meta[i].flags & CMD_MAPPED) { pci_unmap_single(priv->pci_dev, dma_unmap_addr(&txq->meta[i], mapping), dma_unmap_len(&txq->meta[i], len), PCI_DMA_BIDIRECTIONAL); + txq->meta[i].flags = 0; } } EXPORT_SYMBOL(iwl_legacy_cmd_queue_unmap); @@ -467,29 +466,27 @@ int iwl_legacy_enqueue_hcmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd) return -EIO; } + spin_lock_irqsave(&priv->hcmd_lock, flags); + if (iwl_legacy_queue_space(q) < ((cmd->flags & CMD_ASYNC) ? 2 : 1)) { - IWL_ERR(priv, "No space in command queue\n"); - IWL_ERR(priv, "Restarting adapter due to queue full\n"); + spin_unlock_irqrestore(&priv->hcmd_lock, flags); + + IWL_ERR(priv, "Restarting adapter due to command queue full\n"); queue_work(priv->workqueue, &priv->restart); return -ENOSPC; } - spin_lock_irqsave(&priv->hcmd_lock, flags); - - /* If this is a huge cmd, mark the huge flag also on the meta.flags - * of the _original_ cmd. This is used for DMA mapping clean up. - */ - if (cmd->flags & CMD_SIZE_HUGE) { - idx = iwl_legacy_get_cmd_index(q, q->write_ptr, 0); - txq->meta[idx].flags = CMD_SIZE_HUGE; - } - idx = iwl_legacy_get_cmd_index(q, q->write_ptr, cmd->flags & CMD_SIZE_HUGE); out_cmd = txq->cmd[idx]; out_meta = &txq->meta[idx]; + if (WARN_ON(out_meta->flags & CMD_MAPPED)) { + spin_unlock_irqrestore(&priv->hcmd_lock, flags); + return -ENOSPC; + } + memset(out_meta, 0, sizeof(*out_meta)); /* re-initialize to NULL */ - out_meta->flags = cmd->flags; + out_meta->flags = cmd->flags | CMD_MAPPED; if (cmd->flags & CMD_WANT_SKB) out_meta->source = cmd; if (cmd->flags & CMD_ASYNC) @@ -610,6 +607,7 @@ iwl_legacy_tx_cmd_complete(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb) struct iwl_device_cmd *cmd; struct iwl_cmd_meta *meta; struct iwl_tx_queue *txq = &priv->txq[priv->cmd_queue]; + unsigned long flags; /* If a Tx command is being handled and it isn't in the actual * command queue then there a command routing bug has been introduced @@ -623,14 +621,6 @@ iwl_legacy_tx_cmd_complete(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb) return; } - /* If this is a huge cmd, clear the huge flag on the meta.flags - * of the _original_ cmd. So that iwl_legacy_cmd_queue_free won't unmap - * the DMA buffer for the scan (huge) command. - */ - if (huge) { - cmd_index = iwl_legacy_get_cmd_index(&txq->q, index, 0); - txq->meta[cmd_index].flags = 0; - } cmd_index = iwl_legacy_get_cmd_index(&txq->q, index, huge); cmd = txq->cmd[cmd_index]; meta = &txq->meta[cmd_index]; @@ -647,6 +637,8 @@ iwl_legacy_tx_cmd_complete(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb) } else if (meta->callback) meta->callback(priv, cmd, pkt); + spin_lock_irqsave(&priv->hcmd_lock, flags); + iwl_legacy_hcmd_queue_reclaim(priv, txq_id, index, cmd_index); if (!(meta->flags & CMD_ASYNC)) { @@ -655,6 +647,10 @@ iwl_legacy_tx_cmd_complete(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb) iwl_legacy_get_cmd_string(cmd->hdr.cmd)); wake_up_interruptible(&priv->wait_command_queue); } + + /* Mark as unmapped */ meta->flags = 0; + + spin_unlock_irqrestore(&priv->hcmd_lock, flags); } EXPORT_SYMBOL(iwl_legacy_tx_cmd_complete); -- cgit v0.10.2 From 28a6e577c65cc317fed5265efc43ce9282928bd4 Mon Sep 17 00:00:00 2001 From: Stanislaw Gruszka Date: Thu, 28 Apr 2011 11:51:32 +0200 Subject: iwlegacy: more priv->mutex serialization Check status bits with mutex taken, because when we wait for mutex unlock, status can change. Patch should also make remaining sync commands be send with priv->mutex taken. That will prevent execute these commands when we are currently reset firmware, what could possibly cause troubles. Signed-off-by: Stanislaw Gruszka Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwlegacy/iwl-core.c b/drivers/net/wireless/iwlegacy/iwl-core.c index 553c91b..0073f92 100644 --- a/drivers/net/wireless/iwlegacy/iwl-core.c +++ b/drivers/net/wireless/iwlegacy/iwl-core.c @@ -2429,11 +2429,13 @@ void iwl_legacy_mac_bss_info_changed(struct ieee80211_hw *hw, IWL_DEBUG_MAC80211(priv, "changes = 0x%X\n", changes); - if (!iwl_legacy_is_alive(priv)) - return; - mutex_lock(&priv->mutex); + if (!iwl_legacy_is_alive(priv)) { + mutex_unlock(&priv->mutex); + return; + } + if (changes & BSS_CHANGED_QOS) { unsigned long flags; diff --git a/drivers/net/wireless/iwlegacy/iwl3945-base.c b/drivers/net/wireless/iwlegacy/iwl3945-base.c index cc7ebce..5bdcc36 100644 --- a/drivers/net/wireless/iwlegacy/iwl3945-base.c +++ b/drivers/net/wireless/iwlegacy/iwl3945-base.c @@ -2748,11 +2748,12 @@ static void iwl3945_bg_init_alive_start(struct work_struct *data) struct iwl_priv *priv = container_of(data, struct iwl_priv, init_alive_start.work); + mutex_lock(&priv->mutex); if (test_bit(STATUS_EXIT_PENDING, &priv->status)) - return; + goto out; - mutex_lock(&priv->mutex); iwl3945_init_alive_start(priv); +out: mutex_unlock(&priv->mutex); } @@ -2761,11 +2762,12 @@ static void iwl3945_bg_alive_start(struct work_struct *data) struct iwl_priv *priv = container_of(data, struct iwl_priv, alive_start.work); + mutex_lock(&priv->mutex); if (test_bit(STATUS_EXIT_PENDING, &priv->status)) - return; + goto out; - mutex_lock(&priv->mutex); iwl3945_alive_start(priv); +out: mutex_unlock(&priv->mutex); } @@ -2995,10 +2997,12 @@ static void iwl3945_bg_restart(struct work_struct *data) } else { iwl3945_down(priv); - if (test_bit(STATUS_EXIT_PENDING, &priv->status)) + mutex_lock(&priv->mutex); + if (test_bit(STATUS_EXIT_PENDING, &priv->status)) { + mutex_unlock(&priv->mutex); return; + } - mutex_lock(&priv->mutex); __iwl3945_up(priv); mutex_unlock(&priv->mutex); } @@ -3009,11 +3013,12 @@ static void iwl3945_bg_rx_replenish(struct work_struct *data) struct iwl_priv *priv = container_of(data, struct iwl_priv, rx_replenish); + mutex_lock(&priv->mutex); if (test_bit(STATUS_EXIT_PENDING, &priv->status)) - return; + goto out; - mutex_lock(&priv->mutex); iwl3945_rx_replenish(priv); +out: mutex_unlock(&priv->mutex); } diff --git a/drivers/net/wireless/iwlegacy/iwl4965-base.c b/drivers/net/wireless/iwlegacy/iwl4965-base.c index 2da6070..55851ac 100644 --- a/drivers/net/wireless/iwlegacy/iwl4965-base.c +++ b/drivers/net/wireless/iwlegacy/iwl4965-base.c @@ -2404,11 +2404,12 @@ static void iwl4965_bg_init_alive_start(struct work_struct *data) struct iwl_priv *priv = container_of(data, struct iwl_priv, init_alive_start.work); + mutex_lock(&priv->mutex); if (test_bit(STATUS_EXIT_PENDING, &priv->status)) - return; + goto out; - mutex_lock(&priv->mutex); priv->cfg->ops->lib->init_alive_start(priv); +out: mutex_unlock(&priv->mutex); } @@ -2417,11 +2418,12 @@ static void iwl4965_bg_alive_start(struct work_struct *data) struct iwl_priv *priv = container_of(data, struct iwl_priv, alive_start.work); + mutex_lock(&priv->mutex); if (test_bit(STATUS_EXIT_PENDING, &priv->status)) - return; + goto out; - mutex_lock(&priv->mutex); iwl4965_alive_start(priv); +out: mutex_unlock(&priv->mutex); } @@ -2471,10 +2473,12 @@ static void iwl4965_bg_restart(struct work_struct *data) } else { iwl4965_down(priv); - if (test_bit(STATUS_EXIT_PENDING, &priv->status)) + mutex_lock(&priv->mutex); + if (test_bit(STATUS_EXIT_PENDING, &priv->status)) { + mutex_unlock(&priv->mutex); return; + } - mutex_lock(&priv->mutex); __iwl4965_up(priv); mutex_unlock(&priv->mutex); } @@ -2851,21 +2855,22 @@ void iwl4965_mac_channel_switch(struct ieee80211_hw *hw, IWL_DEBUG_MAC80211(priv, "enter\n"); + mutex_lock(&priv->mutex); + if (iwl_legacy_is_rfkill(priv)) - goto out_exit; + goto out; if (test_bit(STATUS_EXIT_PENDING, &priv->status) || test_bit(STATUS_SCANNING, &priv->status)) - goto out_exit; + goto out; if (!iwl_legacy_is_associated_ctx(ctx)) - goto out_exit; + goto out; /* channel switch in progress */ if (priv->switch_rxon.switch_in_progress == true) - goto out_exit; + goto out; - mutex_lock(&priv->mutex); if (priv->cfg->ops->lib->set_channel_switch) { ch = channel->hw_value; @@ -2921,7 +2926,6 @@ void iwl4965_mac_channel_switch(struct ieee80211_hw *hw, } out: mutex_unlock(&priv->mutex); -out_exit: if (!priv->switch_rxon.switch_in_progress) ieee80211_chswitch_done(ctx->vif, false); IWL_DEBUG_MAC80211(priv, "leave\n"); -- cgit v0.10.2 From 22450902e4a13479acf6f4e93475af7ca1829d92 Mon Sep 17 00:00:00 2001 From: Stanislaw Gruszka Date: Thu, 28 Apr 2011 11:51:33 +0200 Subject: iwlegacy: remove sync_cmd_mutex We now use priv->mutex to serialize sync command, remove old priv->sync_cmd_mutex and add assertion that priv->mutex must be locked. Signed-off-by: Stanislaw Gruszka Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwlegacy/iwl-dev.h b/drivers/net/wireless/iwlegacy/iwl-dev.h index df19d5c..2d87dba 100644 --- a/drivers/net/wireless/iwlegacy/iwl-dev.h +++ b/drivers/net/wireless/iwlegacy/iwl-dev.h @@ -1077,7 +1077,6 @@ struct iwl_priv { spinlock_t hcmd_lock; /* protect hcmd */ spinlock_t reg_lock; /* protect hw register access */ struct mutex mutex; - struct mutex sync_cmd_mutex; /* enable serialization of sync commands */ /* basic pci-network driver stuff */ struct pci_dev *pci_dev; diff --git a/drivers/net/wireless/iwlegacy/iwl-hcmd.c b/drivers/net/wireless/iwlegacy/iwl-hcmd.c index 9d721cb..62b4b09 100644 --- a/drivers/net/wireless/iwlegacy/iwl-hcmd.c +++ b/drivers/net/wireless/iwlegacy/iwl-hcmd.c @@ -145,6 +145,8 @@ int iwl_legacy_send_cmd_sync(struct iwl_priv *priv, struct iwl_host_cmd *cmd) int cmd_idx; int ret; + lockdep_assert_held(&priv->mutex); + BUG_ON(cmd->flags & CMD_ASYNC); /* A synchronous command can not have a callback set. */ @@ -152,7 +154,6 @@ int iwl_legacy_send_cmd_sync(struct iwl_priv *priv, struct iwl_host_cmd *cmd) IWL_DEBUG_INFO(priv, "Attempting to send sync command %s\n", iwl_legacy_get_cmd_string(cmd->id)); - mutex_lock(&priv->sync_cmd_mutex); set_bit(STATUS_HCMD_ACTIVE, &priv->status); IWL_DEBUG_INFO(priv, "Setting HCMD_ACTIVE for command %s\n", @@ -224,7 +225,6 @@ fail: cmd->reply_page = 0; } out: - mutex_unlock(&priv->sync_cmd_mutex); return ret; } EXPORT_SYMBOL(iwl_legacy_send_cmd_sync); diff --git a/drivers/net/wireless/iwlegacy/iwl3945-base.c b/drivers/net/wireless/iwlegacy/iwl3945-base.c index 5bdcc36..0ee6be6 100644 --- a/drivers/net/wireless/iwlegacy/iwl3945-base.c +++ b/drivers/net/wireless/iwlegacy/iwl3945-base.c @@ -3815,7 +3815,6 @@ static int iwl3945_init_drv(struct iwl_priv *priv) INIT_LIST_HEAD(&priv->free_frames); mutex_init(&priv->mutex); - mutex_init(&priv->sync_cmd_mutex); priv->ieee_channels = NULL; priv->ieee_rates = NULL; diff --git a/drivers/net/wireless/iwlegacy/iwl4965-base.c b/drivers/net/wireless/iwlegacy/iwl4965-base.c index 55851ac..f781b7e 100644 --- a/drivers/net/wireless/iwlegacy/iwl4965-base.c +++ b/drivers/net/wireless/iwlegacy/iwl4965-base.c @@ -3124,7 +3124,6 @@ static int iwl4965_init_drv(struct iwl_priv *priv) INIT_LIST_HEAD(&priv->free_frames); mutex_init(&priv->mutex); - mutex_init(&priv->sync_cmd_mutex); priv->ieee_channels = NULL; priv->ieee_rates = NULL; -- cgit v0.10.2 From d244f21e79162b829c9af09845421d9b4fac4253 Mon Sep 17 00:00:00 2001 From: Sujith Manoharan Date: Thu, 28 Apr 2011 16:14:05 +0530 Subject: ath9k_htc: Revamp LED management Remove all the convoluted hacks in the driver and simplify things by making use of mac80211's LED triggers. Signed-off-by: Sujith Manoharan Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/htc.h b/drivers/net/wireless/ath/ath9k/htc.h index 6bb71e3..dfc7a98 100644 --- a/drivers/net/wireless/ath/ath9k/htc.h +++ b/drivers/net/wireless/ath/ath9k/htc.h @@ -385,25 +385,6 @@ static inline void ath9k_htc_err_stat_rx(struct ath9k_htc_priv *priv, #define ATH_LED_PIN_9287 10 #define ATH_LED_PIN_9271 15 #define ATH_LED_PIN_7010 12 -#define ATH_LED_ON_DURATION_IDLE 350 /* in msecs */ -#define ATH_LED_OFF_DURATION_IDLE 250 /* in msecs */ - -enum ath_led_type { - ATH_LED_RADIO, - ATH_LED_ASSOC, - ATH_LED_TX, - ATH_LED_RX -}; - -struct ath_led { - struct ath9k_htc_priv *priv; - struct led_classdev led_cdev; - enum ath_led_type led_type; - struct delayed_work brightness_work; - char name[32]; - bool registered; - int brightness; -}; #define BSTUCK_THRESHOLD 10 @@ -437,14 +418,11 @@ void ath_htc_cancel_btcoex_work(struct ath9k_htc_priv *priv); #define OP_INVALID BIT(0) #define OP_SCANNING BIT(1) -#define OP_LED_ASSOCIATED BIT(2) -#define OP_LED_ON BIT(3) -#define OP_ENABLE_BEACON BIT(4) -#define OP_LED_DEINIT BIT(5) -#define OP_BT_PRIORITY_DETECTED BIT(6) -#define OP_BT_SCAN BIT(7) -#define OP_ANI_RUNNING BIT(8) -#define OP_TSF_RESET BIT(9) +#define OP_ENABLE_BEACON BIT(2) +#define OP_BT_PRIORITY_DETECTED BIT(3) +#define OP_BT_SCAN BIT(4) +#define OP_ANI_RUNNING BIT(5) +#define OP_TSF_RESET BIT(6) struct ath9k_htc_priv { struct device *dev; @@ -504,15 +482,13 @@ struct ath9k_htc_priv { bool ps_enabled; bool ps_idle; - struct ath_led radio_led; - struct ath_led assoc_led; - struct ath_led tx_led; - struct ath_led rx_led; - struct delayed_work ath9k_led_blink_work; - int led_on_duration; - int led_off_duration; - int led_on_cnt; - int led_off_cnt; +#ifdef CONFIG_MAC80211_LEDS + enum led_brightness brightness; + bool led_registered; + char led_name[32]; + struct led_classdev led_cdev; + struct work_struct led_work; +#endif int beaconq; int cabq; @@ -597,9 +573,24 @@ void ath9k_start_rfkill_poll(struct ath9k_htc_priv *priv); void ath9k_htc_rfkill_poll_state(struct ieee80211_hw *hw); void ath9k_htc_radio_enable(struct ieee80211_hw *hw); void ath9k_htc_radio_disable(struct ieee80211_hw *hw); -void ath9k_led_stop_brightness(struct ath9k_htc_priv *priv); + +#ifdef CONFIG_MAC80211_LEDS void ath9k_init_leds(struct ath9k_htc_priv *priv); void ath9k_deinit_leds(struct ath9k_htc_priv *priv); +void ath9k_led_work(struct work_struct *work); +#else +static inline void ath9k_init_leds(struct ath9k_htc_priv *priv) +{ +} + +static inline void ath9k_deinit_leds(struct ath9k_htc_priv *priv) +{ +} + +static inline void ath9k_led_work(struct work_struct *work) +{ +} +#endif int ath9k_htc_probe_device(struct htc_target *htc_handle, struct device *dev, u16 devid, char *product, u32 drv_info); diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_gpio.c b/drivers/net/wireless/ath/ath9k/htc_drv_gpio.c index 26ede1d..af57fe5 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_gpio.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_gpio.c @@ -154,140 +154,41 @@ void ath_htc_cancel_btcoex_work(struct ath9k_htc_priv *priv) /* LED */ /*******/ -static void ath9k_led_blink_work(struct work_struct *work) +#ifdef CONFIG_MAC80211_LEDS +void ath9k_led_work(struct work_struct *work) { - struct ath9k_htc_priv *priv = container_of(work, struct ath9k_htc_priv, - ath9k_led_blink_work.work); - - if (!(priv->op_flags & OP_LED_ASSOCIATED)) - return; + struct ath9k_htc_priv *priv = container_of(work, + struct ath9k_htc_priv, + led_work); - if ((priv->led_on_duration == ATH_LED_ON_DURATION_IDLE) || - (priv->led_off_duration == ATH_LED_OFF_DURATION_IDLE)) - ath9k_hw_set_gpio(priv->ah, priv->ah->led_pin, 0); - else - ath9k_hw_set_gpio(priv->ah, priv->ah->led_pin, - (priv->op_flags & OP_LED_ON) ? 1 : 0); - - ieee80211_queue_delayed_work(priv->hw, - &priv->ath9k_led_blink_work, - (priv->op_flags & OP_LED_ON) ? - msecs_to_jiffies(priv->led_off_duration) : - msecs_to_jiffies(priv->led_on_duration)); - - priv->led_on_duration = priv->led_on_cnt ? - max((ATH_LED_ON_DURATION_IDLE - priv->led_on_cnt), 25) : - ATH_LED_ON_DURATION_IDLE; - priv->led_off_duration = priv->led_off_cnt ? - max((ATH_LED_OFF_DURATION_IDLE - priv->led_off_cnt), 10) : - ATH_LED_OFF_DURATION_IDLE; - priv->led_on_cnt = priv->led_off_cnt = 0; - - if (priv->op_flags & OP_LED_ON) - priv->op_flags &= ~OP_LED_ON; - else - priv->op_flags |= OP_LED_ON; -} - -static void ath9k_led_brightness_work(struct work_struct *work) -{ - struct ath_led *led = container_of(work, struct ath_led, - brightness_work.work); - struct ath9k_htc_priv *priv = led->priv; - - switch (led->brightness) { - case LED_OFF: - if (led->led_type == ATH_LED_ASSOC || - led->led_type == ATH_LED_RADIO) { - ath9k_hw_set_gpio(priv->ah, priv->ah->led_pin, - (led->led_type == ATH_LED_RADIO)); - priv->op_flags &= ~OP_LED_ASSOCIATED; - if (led->led_type == ATH_LED_RADIO) - priv->op_flags &= ~OP_LED_ON; - } else { - priv->led_off_cnt++; - } - break; - case LED_FULL: - if (led->led_type == ATH_LED_ASSOC) { - priv->op_flags |= OP_LED_ASSOCIATED; - ieee80211_queue_delayed_work(priv->hw, - &priv->ath9k_led_blink_work, 0); - } else if (led->led_type == ATH_LED_RADIO) { - ath9k_hw_set_gpio(priv->ah, priv->ah->led_pin, 0); - priv->op_flags |= OP_LED_ON; - } else { - priv->led_on_cnt++; - } - break; - default: - break; - } + ath9k_hw_set_gpio(priv->ah, priv->ah->led_pin, + (priv->brightness == LED_OFF)); } static void ath9k_led_brightness(struct led_classdev *led_cdev, enum led_brightness brightness) { - struct ath_led *led = container_of(led_cdev, struct ath_led, led_cdev); - struct ath9k_htc_priv *priv = led->priv; - - led->brightness = brightness; - if (!(priv->op_flags & OP_LED_DEINIT)) - ieee80211_queue_delayed_work(priv->hw, - &led->brightness_work, 0); -} + struct ath9k_htc_priv *priv = container_of(led_cdev, + struct ath9k_htc_priv, + led_cdev); -void ath9k_led_stop_brightness(struct ath9k_htc_priv *priv) -{ - cancel_delayed_work_sync(&priv->radio_led.brightness_work); - cancel_delayed_work_sync(&priv->assoc_led.brightness_work); - cancel_delayed_work_sync(&priv->tx_led.brightness_work); - cancel_delayed_work_sync(&priv->rx_led.brightness_work); -} - -static int ath9k_register_led(struct ath9k_htc_priv *priv, struct ath_led *led, - char *trigger) -{ - int ret; - - led->priv = priv; - led->led_cdev.name = led->name; - led->led_cdev.default_trigger = trigger; - led->led_cdev.brightness_set = ath9k_led_brightness; - - ret = led_classdev_register(wiphy_dev(priv->hw->wiphy), &led->led_cdev); - if (ret) - ath_err(ath9k_hw_common(priv->ah), - "Failed to register led:%s", led->name); - else - led->registered = 1; - - INIT_DELAYED_WORK(&led->brightness_work, ath9k_led_brightness_work); - - return ret; -} - -static void ath9k_unregister_led(struct ath_led *led) -{ - if (led->registered) { - led_classdev_unregister(&led->led_cdev); - led->registered = 0; - } + /* Not locked, but it's just a tiny green light..*/ + priv->brightness = brightness; + ieee80211_queue_work(priv->hw, &priv->led_work); } void ath9k_deinit_leds(struct ath9k_htc_priv *priv) { - priv->op_flags |= OP_LED_DEINIT; - ath9k_unregister_led(&priv->assoc_led); - priv->op_flags &= ~OP_LED_ASSOCIATED; - ath9k_unregister_led(&priv->tx_led); - ath9k_unregister_led(&priv->rx_led); - ath9k_unregister_led(&priv->radio_led); + if (!priv->led_registered) + return; + + ath9k_led_brightness(&priv->led_cdev, LED_OFF); + led_classdev_unregister(&priv->led_cdev); + cancel_work_sync(&priv->led_work); } void ath9k_init_leds(struct ath9k_htc_priv *priv) { - char *trigger; int ret; if (AR_SREV_9287(priv->ah)) @@ -305,48 +206,21 @@ void ath9k_init_leds(struct ath9k_htc_priv *priv) /* LED off, active low */ ath9k_hw_set_gpio(priv->ah, priv->ah->led_pin, 1); - INIT_DELAYED_WORK(&priv->ath9k_led_blink_work, ath9k_led_blink_work); - - trigger = ieee80211_get_radio_led_name(priv->hw); - snprintf(priv->radio_led.name, sizeof(priv->radio_led.name), - "ath9k-%s::radio", wiphy_name(priv->hw->wiphy)); - ret = ath9k_register_led(priv, &priv->radio_led, trigger); - priv->radio_led.led_type = ATH_LED_RADIO; - if (ret) - goto fail; - - trigger = ieee80211_get_assoc_led_name(priv->hw); - snprintf(priv->assoc_led.name, sizeof(priv->assoc_led.name), - "ath9k-%s::assoc", wiphy_name(priv->hw->wiphy)); - ret = ath9k_register_led(priv, &priv->assoc_led, trigger); - priv->assoc_led.led_type = ATH_LED_ASSOC; - if (ret) - goto fail; - - trigger = ieee80211_get_tx_led_name(priv->hw); - snprintf(priv->tx_led.name, sizeof(priv->tx_led.name), - "ath9k-%s::tx", wiphy_name(priv->hw->wiphy)); - ret = ath9k_register_led(priv, &priv->tx_led, trigger); - priv->tx_led.led_type = ATH_LED_TX; - if (ret) - goto fail; - - trigger = ieee80211_get_rx_led_name(priv->hw); - snprintf(priv->rx_led.name, sizeof(priv->rx_led.name), - "ath9k-%s::rx", wiphy_name(priv->hw->wiphy)); - ret = ath9k_register_led(priv, &priv->rx_led, trigger); - priv->rx_led.led_type = ATH_LED_RX; - if (ret) - goto fail; - - priv->op_flags &= ~OP_LED_DEINIT; + snprintf(priv->led_name, sizeof(priv->led_name), + "ath9k_htc-%s", wiphy_name(priv->hw->wiphy)); + priv->led_cdev.name = priv->led_name; + priv->led_cdev.brightness_set = ath9k_led_brightness; - return; + ret = led_classdev_register(wiphy_dev(priv->hw->wiphy), &priv->led_cdev); + if (ret < 0) + return; -fail: - cancel_delayed_work_sync(&priv->ath9k_led_blink_work); - ath9k_deinit_leds(priv); + INIT_WORK(&priv->led_work, ath9k_led_work); + priv->led_registered = true; + + return; } +#endif /*******************/ /* Rfkill */ diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_init.c b/drivers/net/wireless/ath/ath9k/htc_drv_init.c index d2dd5a6..bfdc8a8 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_init.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_init.c @@ -117,6 +117,21 @@ static struct ieee80211_rate ath9k_legacy_rates[] = { RATE(540, 0x0c, 0), }; +#ifdef CONFIG_MAC80211_LEDS +static const struct ieee80211_tpt_blink ath9k_htc_tpt_blink[] = { + { .throughput = 0 * 1024, .blink_time = 334 }, + { .throughput = 1 * 1024, .blink_time = 260 }, + { .throughput = 5 * 1024, .blink_time = 220 }, + { .throughput = 10 * 1024, .blink_time = 190 }, + { .throughput = 20 * 1024, .blink_time = 170 }, + { .throughput = 50 * 1024, .blink_time = 150 }, + { .throughput = 70 * 1024, .blink_time = 130 }, + { .throughput = 100 * 1024, .blink_time = 110 }, + { .throughput = 200 * 1024, .blink_time = 80 }, + { .throughput = 300 * 1024, .blink_time = 50 }, +}; +#endif + static int ath9k_htc_wait_for_target(struct ath9k_htc_priv *priv) { int time_left; @@ -863,6 +878,13 @@ static int ath9k_init_device(struct ath9k_htc_priv *priv, if (error != 0) goto err_rx; +#ifdef CONFIG_MAC80211_LEDS + /* must be initialized before ieee80211_register_hw */ + priv->led_cdev.default_trigger = ieee80211_create_tpt_led_trigger(priv->hw, + IEEE80211_TPT_LEDTRIG_FL_RADIO, ath9k_htc_tpt_blink, + ARRAY_SIZE(ath9k_htc_tpt_blink)); +#endif + /* Register with mac80211 */ error = ieee80211_register_hw(hw); if (error) diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_main.c b/drivers/net/wireless/ath/ath9k/htc_drv_main.c index e9746e8..5aa104fe 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_main.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_main.c @@ -1003,9 +1003,11 @@ static void ath9k_htc_stop(struct ieee80211_hw *hw) /* Cancel all the running timers/work .. */ cancel_work_sync(&priv->fatal_work); cancel_work_sync(&priv->ps_work); - cancel_delayed_work_sync(&priv->ath9k_led_blink_work); + +#ifdef CONFIG_MAC80211_LEDS + cancel_work_sync(&priv->led_work); +#endif ath9k_htc_stop_ani(priv); - ath9k_led_stop_brightness(priv); mutex_lock(&priv->mutex); -- cgit v0.10.2 From ff776cecec92fe7cac4a9ce1919576ad6e737e08 Mon Sep 17 00:00:00 2001 From: Yogesh Ashok Powar Date: Thu, 28 Apr 2011 17:34:48 +0530 Subject: mwl8k: Reducing extra_tx_headroom for tx optimization in AP mode The tx_headroom required for mwl8k driver is 32 bytes and it can use the space for 802.11 header received from mac80211. mwl8k considers the smallest 802.11 frame (CTS2self of 10 bytes) that can be received from mac80211 to compute the extra_tx_headroom as 22 (32 - 10) bytes. When the wireless interface is part of bridge, this extra_tx_headroom requirement results in a memcpy in mac80211 (in function pskb_expand_head) for all the data frames needing L2 forwarding/bridging, when NET_SKB_PAD is defined as 32. This patch reduces the extra_tx_headroom by 8 bytes so that memcpy of data frames in mac80211 is avoided in this case. The resize will be required in driver for frames with 802.11 header size of less than 18 bytes. Signed-off-by: Yogesh Ashok Powar Signed-off-by: Pradeep Nemavat Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c index 8a1b262..9f5ecef 100644 --- a/drivers/net/wireless/mwl8k.c +++ b/drivers/net/wireless/mwl8k.c @@ -781,8 +781,10 @@ static inline void mwl8k_remove_dma_header(struct sk_buff *skb, __le16 qos) skb_pull(skb, sizeof(*tr) - hdrlen); } +#define REDUCED_TX_HEADROOM 8 + static void -mwl8k_add_dma_header(struct sk_buff *skb, int tail_pad) +mwl8k_add_dma_header(struct mwl8k_priv *priv, struct sk_buff *skb, int tail_pad) { struct ieee80211_hdr *wh; int hdrlen; @@ -798,6 +800,22 @@ mwl8k_add_dma_header(struct sk_buff *skb, int tail_pad) wh = (struct ieee80211_hdr *)skb->data; hdrlen = ieee80211_hdrlen(wh->frame_control); + + /* + * Check if skb_resize is required because of + * tx_headroom adjustment. + */ + if (priv->ap_fw && (hdrlen < (sizeof(struct ieee80211_cts) + + REDUCED_TX_HEADROOM))) { + if (pskb_expand_head(skb, REDUCED_TX_HEADROOM, 0, GFP_ATOMIC)) { + + wiphy_err(priv->hw->wiphy, + "Failed to reallocate TX buffer\n"); + return; + } + skb->truesize += REDUCED_TX_HEADROOM; + } + reqd_hdrlen = sizeof(*tr); if (hdrlen != reqd_hdrlen) @@ -820,7 +838,8 @@ mwl8k_add_dma_header(struct sk_buff *skb, int tail_pad) tr->fwlen = cpu_to_le16(skb->len - sizeof(*tr) + tail_pad); } -static void mwl8k_encapsulate_tx_frame(struct sk_buff *skb) +static void mwl8k_encapsulate_tx_frame(struct mwl8k_priv *priv, + struct sk_buff *skb) { struct ieee80211_hdr *wh; struct ieee80211_tx_info *tx_info; @@ -861,7 +880,7 @@ static void mwl8k_encapsulate_tx_frame(struct sk_buff *skb) break; } } - mwl8k_add_dma_header(skb, data_pad); + mwl8k_add_dma_header(priv, skb, data_pad); } /* @@ -1816,9 +1835,9 @@ mwl8k_txq_xmit(struct ieee80211_hw *hw, int index, struct sk_buff *skb) mgmtframe = true; if (priv->ap_fw) - mwl8k_encapsulate_tx_frame(skb); + mwl8k_encapsulate_tx_frame(priv, skb); else - mwl8k_add_dma_header(skb, 0); + mwl8k_add_dma_header(priv, skb, 0); wh = &((struct mwl8k_dma_data *)skb->data)->wh; @@ -5474,6 +5493,8 @@ static int mwl8k_firmware_load_success(struct mwl8k_priv *priv) hw->extra_tx_headroom = sizeof(struct mwl8k_dma_data) - sizeof(struct ieee80211_cts); + hw->extra_tx_headroom -= priv->ap_fw ? REDUCED_TX_HEADROOM : 0; + hw->channel_change_time = 10; hw->queues = MWL8K_TX_WMM_QUEUES; -- cgit v0.10.2 From b3c914aa84f4e4bbb3efc8f41c359d96e5e932d2 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Wed, 27 Apr 2011 09:54:28 +0000 Subject: usbnet: add support for some Huawei modems with cdc-ether ports Some newer Huawei devices (T-Mobile Rocket, others) have cdc-ether compatible ports, so recognize and expose them. Signed-off-by: Dan Williams Acked-by: Oliver Neukum Signed-off-by: David S. Miller diff --git a/drivers/net/usb/cdc_ether.c b/drivers/net/usb/cdc_ether.c index 341f705..a301479 100644 --- a/drivers/net/usb/cdc_ether.c +++ b/drivers/net/usb/cdc_ether.c @@ -460,7 +460,7 @@ static const struct driver_info cdc_info = { .manage_power = cdc_manage_power, }; -static const struct driver_info mbm_info = { +static const struct driver_info wwan_info = { .description = "Mobile Broadband Network Device", .flags = FLAG_WWAN, .bind = usbnet_cdc_bind, @@ -471,6 +471,7 @@ static const struct driver_info mbm_info = { /*-------------------------------------------------------------------------*/ +#define HUAWEI_VENDOR_ID 0x12D1 static const struct usb_device_id products [] = { /* @@ -587,8 +588,17 @@ static const struct usb_device_id products [] = { }, { USB_INTERFACE_INFO(USB_CLASS_COMM, USB_CDC_SUBCLASS_MDLM, USB_CDC_PROTO_NONE), - .driver_info = (unsigned long)&mbm_info, + .driver_info = (unsigned long)&wwan_info, +}, { + /* Various Huawei modems with a network port like the UMG1831 */ + .match_flags = USB_DEVICE_ID_MATCH_VENDOR + | USB_DEVICE_ID_MATCH_INT_INFO, + .idVendor = HUAWEI_VENDOR_ID, + .bInterfaceClass = USB_CLASS_COMM, + .bInterfaceSubClass = USB_CDC_SUBCLASS_ETHERNET, + .bInterfaceProtocol = 255, + .driver_info = (unsigned long)&wwan_info, }, { }, // END }; -- cgit v0.10.2 From 686f13bb17784fbf8595a59ff4e4bd707d5ae66f Mon Sep 17 00:00:00 2001 From: Oliver Neukum Date: Fri, 29 Apr 2011 14:15:53 +0200 Subject: usbnet: Transfer of maintainership Somebody has to do it, however unfortunate be the cause. Signed-off-by: Oliver Neukum Signed-off-by: David S. Miller diff --git a/MAINTAINERS b/MAINTAINERS index c85368d..eb4f996 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -6551,7 +6551,7 @@ S: Maintained F: drivers/usb/host/uhci* USB "USBNET" DRIVER FRAMEWORK -M: David Brownell +M: Oliver Neukum L: netdev@vger.kernel.org W: http://www.linux-usb.org/usbnet S: Maintained -- cgit v0.10.2 From eee9700c5dd8fbac517c8c1e85c60b688bc311a9 Mon Sep 17 00:00:00 2001 From: Adam Jaremko Date: Thu, 28 Apr 2011 07:41:18 +0000 Subject: net: ftmac100: fix scheduling while atomic during PHY link status change Signed-off-by: Adam Jaremko Acked-by: Po-Yu Chuang Signed-off-by: David S. Miller diff --git a/drivers/net/ftmac100.c b/drivers/net/ftmac100.c index a316619..9bd7746 100644 --- a/drivers/net/ftmac100.c +++ b/drivers/net/ftmac100.c @@ -139,11 +139,11 @@ static int ftmac100_reset(struct ftmac100 *priv) * that hardware reset completed (what the f*ck). * We still need to wait for a while. */ - usleep_range(500, 1000); + udelay(500); return 0; } - usleep_range(1000, 10000); + udelay(1000); } netdev_err(netdev, "software reset failed\n"); @@ -772,7 +772,7 @@ static int ftmac100_mdio_read(struct net_device *netdev, int phy_id, int reg) if ((phycr & FTMAC100_PHYCR_MIIRD) == 0) return phycr & FTMAC100_PHYCR_MIIRDATA; - usleep_range(100, 1000); + udelay(100); } netdev_err(netdev, "mdio read timed out\n"); @@ -801,7 +801,7 @@ static void ftmac100_mdio_write(struct net_device *netdev, int phy_id, int reg, if ((phycr & FTMAC100_PHYCR_MIIWR) == 0) return; - usleep_range(100, 1000); + udelay(100); } netdev_err(netdev, "mdio write timed out\n"); -- cgit v0.10.2 From ad246c992bea6d33c6421ba1f03e2b405792adf9 Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Tue, 26 Apr 2011 15:25:52 +0000 Subject: ipv4, ipv6, bonding: Restore control over number of peer notifications For backward compatibility, we should retain the module parameters and sysfs attributes to control the number of peer notifications (gratuitous ARPs and unsolicited NAs) sent after bonding failover. Also, it is possible for failover to take place even though the new active slave does not have link up, and in that case the peer notification should be deferred until it does. Change ipv4 and ipv6 so they do not automatically send peer notifications on bonding failover. Change the bonding driver to send separate NETDEV_NOTIFY_PEERS notifications when the link is up, as many times as requested. Since it does not directly control which protocols send notifications, make num_grat_arp and num_unsol_na aliases for a single parameter. Bump the bonding version number and update its documentation. Signed-off-by: Ben Hutchings Signed-off-by: Jay Vosburgh Acked-by: Brian Haley Signed-off-by: David S. Miller diff --git a/Documentation/networking/bonding.txt b/Documentation/networking/bonding.txt index e27202bb..1f45bd8 100644 --- a/Documentation/networking/bonding.txt +++ b/Documentation/networking/bonding.txt @@ -1,7 +1,7 @@ Linux Ethernet Bonding Driver HOWTO - Latest update: 23 September 2009 + Latest update: 27 April 2011 Initial release : Thomas Davis Corrections, HA extensions : 2000/10/03-15 : @@ -585,25 +585,23 @@ mode chosen. num_grat_arp - - Specifies the number of gratuitous ARPs to be issued after a - failover event. One gratuitous ARP is issued immediately after - the failover, subsequent ARPs are sent at a rate of one per link - monitor interval (arp_interval or miimon, whichever is active). - - The valid range is 0 - 255; the default value is 1. This option - affects only the active-backup mode. This option was added for - bonding version 3.3.0. - num_unsol_na - Specifies the number of unsolicited IPv6 Neighbor Advertisements - to be issued after a failover event. One unsolicited NA is issued - immediately after the failover. - - The valid range is 0 - 255; the default value is 1. This option - affects only the active-backup mode. This option was added for - bonding version 3.4.0. + Specify the number of peer notifications (gratuitous ARPs and + unsolicited IPv6 Neighbor Advertisements) to be issued after a + failover event. As soon as the link is up on the new slave + (possibly immediately) a peer notification is sent on the + bonding device and each VLAN sub-device. This is repeated at + each link monitor interval (arp_interval or miimon, whichever + is active) if the number is greater than 1. + + The valid range is 0 - 255; the default value is 1. These options + affect only the active-backup mode. These options were added for + bonding versions 3.3.0 and 3.4.0 respectively. + + From Linux 2.6.40 and bonding version 3.7.1, these notifications + are generated by the ipv4 and ipv6 code and the numbers of + repetitions cannot be set independently. primary diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index 66d9dc6..22bd03b 100644 --- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c @@ -89,6 +89,7 @@ static int max_bonds = BOND_DEFAULT_MAX_BONDS; static int tx_queues = BOND_DEFAULT_TX_QUEUES; +static int num_peer_notif = 1; static int miimon = BOND_LINK_MON_INTERV; static int updelay; static int downdelay; @@ -111,6 +112,10 @@ module_param(max_bonds, int, 0); MODULE_PARM_DESC(max_bonds, "Max number of bonded devices"); module_param(tx_queues, int, 0); MODULE_PARM_DESC(tx_queues, "Max number of transmit queues (default = 16)"); +module_param_named(num_grat_arp, num_peer_notif, int, 0644); +MODULE_PARM_DESC(num_grat_arp, "Number of peer notifications to send on failover event (alias of num_unsol_na)"); +module_param_named(num_unsol_na, num_peer_notif, int, 0644); +MODULE_PARM_DESC(num_unsol_na, "Number of peer notifications to send on failover event (alias of num_grat_arp)"); module_param(miimon, int, 0); MODULE_PARM_DESC(miimon, "Link check interval in milliseconds"); module_param(updelay, int, 0); @@ -1082,6 +1087,21 @@ static struct slave *bond_find_best_slave(struct bonding *bond) return bestslave; } +static bool bond_should_notify_peers(struct bonding *bond) +{ + struct slave *slave = bond->curr_active_slave; + + pr_debug("bond_should_notify_peers: bond %s slave %s\n", + bond->dev->name, slave ? slave->dev->name : "NULL"); + + if (!slave || !bond->send_peer_notif || + test_bit(__LINK_STATE_LINKWATCH_PENDING, &slave->dev->state)) + return false; + + bond->send_peer_notif--; + return true; +} + /** * change_active_interface - change the active slave into the specified one * @bond: our bonding struct @@ -1149,16 +1169,28 @@ void bond_change_active_slave(struct bonding *bond, struct slave *new_active) bond_set_slave_inactive_flags(old_active); if (new_active) { + bool should_notify_peers = false; + bond_set_slave_active_flags(new_active); if (bond->params.fail_over_mac) bond_do_fail_over_mac(bond, new_active, old_active); + if (netif_running(bond->dev)) { + bond->send_peer_notif = + bond->params.num_peer_notif; + should_notify_peers = + bond_should_notify_peers(bond); + } + write_unlock_bh(&bond->curr_slave_lock); read_unlock(&bond->lock); netdev_bonding_change(bond->dev, NETDEV_BONDING_FAILOVER); + if (should_notify_peers) + netdev_bonding_change(bond->dev, + NETDEV_NOTIFY_PEERS); read_lock(&bond->lock); write_lock_bh(&bond->curr_slave_lock); @@ -2556,6 +2588,7 @@ void bond_mii_monitor(struct work_struct *work) { struct bonding *bond = container_of(work, struct bonding, mii_work.work); + bool should_notify_peers = false; read_lock(&bond->lock); if (bond->kill_timers) @@ -2564,6 +2597,8 @@ void bond_mii_monitor(struct work_struct *work) if (bond->slave_cnt == 0) goto re_arm; + should_notify_peers = bond_should_notify_peers(bond); + if (bond_miimon_inspect(bond)) { read_unlock(&bond->lock); rtnl_lock(); @@ -2582,6 +2617,12 @@ re_arm: msecs_to_jiffies(bond->params.miimon)); out: read_unlock(&bond->lock); + + if (should_notify_peers) { + rtnl_lock(); + netdev_bonding_change(bond->dev, NETDEV_NOTIFY_PEERS); + rtnl_unlock(); + } } static __be32 bond_glean_dev_ip(struct net_device *dev) @@ -3154,6 +3195,7 @@ void bond_activebackup_arp_mon(struct work_struct *work) { struct bonding *bond = container_of(work, struct bonding, arp_work.work); + bool should_notify_peers = false; int delta_in_ticks; read_lock(&bond->lock); @@ -3166,6 +3208,8 @@ void bond_activebackup_arp_mon(struct work_struct *work) if (bond->slave_cnt == 0) goto re_arm; + should_notify_peers = bond_should_notify_peers(bond); + if (bond_ab_arp_inspect(bond, delta_in_ticks)) { read_unlock(&bond->lock); rtnl_lock(); @@ -3185,6 +3229,12 @@ re_arm: queue_delayed_work(bond->wq, &bond->arp_work, delta_in_ticks); out: read_unlock(&bond->lock); + + if (should_notify_peers) { + rtnl_lock(); + netdev_bonding_change(bond->dev, NETDEV_NOTIFY_PEERS); + rtnl_unlock(); + } } /*-------------------------- netdev event handling --------------------------*/ @@ -3494,6 +3544,8 @@ static int bond_close(struct net_device *bond_dev) write_lock_bh(&bond->lock); + bond->send_peer_notif = 0; + /* signal timers not to re-arm */ bond->kill_timers = 1; @@ -4571,6 +4623,12 @@ static int bond_check_params(struct bond_params *params) use_carrier = 1; } + if (num_peer_notif < 0 || num_peer_notif > 255) { + pr_warning("Warning: num_grat_arp/num_unsol_na (%d) not in range 0-255 so it was reset to 1\n", + num_peer_notif); + num_peer_notif = 1; + } + /* reset values for 802.3ad */ if (bond_mode == BOND_MODE_8023AD) { if (!miimon) { @@ -4760,6 +4818,7 @@ static int bond_check_params(struct bond_params *params) params->mode = bond_mode; params->xmit_policy = xmit_hashtype; params->miimon = miimon; + params->num_peer_notif = num_peer_notif; params->arp_interval = arp_interval; params->arp_validate = arp_validate_value; params->updelay = updelay; diff --git a/drivers/net/bonding/bond_sysfs.c b/drivers/net/bonding/bond_sysfs.c index 935406a..4059bfc 100644 --- a/drivers/net/bonding/bond_sysfs.c +++ b/drivers/net/bonding/bond_sysfs.c @@ -869,6 +869,30 @@ static DEVICE_ATTR(ad_select, S_IRUGO | S_IWUSR, bonding_show_ad_select, bonding_store_ad_select); /* + * Show and set the number of peer notifications to send after a failover event. + */ +static ssize_t bonding_show_num_peer_notif(struct device *d, + struct device_attribute *attr, + char *buf) +{ + struct bonding *bond = to_bond(d); + return sprintf(buf, "%d\n", bond->params.num_peer_notif); +} + +static ssize_t bonding_store_num_peer_notif(struct device *d, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct bonding *bond = to_bond(d); + int err = kstrtou8(buf, 10, &bond->params.num_peer_notif); + return err ? err : count; +} +static DEVICE_ATTR(num_grat_arp, S_IRUGO | S_IWUSR, + bonding_show_num_peer_notif, bonding_store_num_peer_notif); +static DEVICE_ATTR(num_unsol_na, S_IRUGO | S_IWUSR, + bonding_show_num_peer_notif, bonding_store_num_peer_notif); + +/* * Show and set the MII monitor interval. There are two tricky bits * here. First, if MII monitoring is activated, then we must disable * ARP monitoring. Second, if the timer isn't running, we must @@ -1566,6 +1590,8 @@ static struct attribute *per_bond_attrs[] = { &dev_attr_lacp_rate.attr, &dev_attr_ad_select.attr, &dev_attr_xmit_hash_policy.attr, + &dev_attr_num_grat_arp.attr, + &dev_attr_num_unsol_na.attr, &dev_attr_miimon.attr, &dev_attr_primary.attr, &dev_attr_primary_reselect.attr, diff --git a/drivers/net/bonding/bonding.h b/drivers/net/bonding/bonding.h index 85fb822..d08362e 100644 --- a/drivers/net/bonding/bonding.h +++ b/drivers/net/bonding/bonding.h @@ -24,8 +24,8 @@ #include "bond_3ad.h" #include "bond_alb.h" -#define DRV_VERSION "3.7.0" -#define DRV_RELDATE "June 2, 2010" +#define DRV_VERSION "3.7.1" +#define DRV_RELDATE "April 27, 2011" #define DRV_NAME "bonding" #define DRV_DESCRIPTION "Ethernet Channel Bonding Driver" @@ -149,6 +149,7 @@ struct bond_params { int mode; int xmit_policy; int miimon; + u8 num_peer_notif; int arp_interval; int arp_validate; int use_carrier; @@ -231,6 +232,7 @@ struct bonding { rwlock_t lock; rwlock_t curr_slave_lock; s8 kill_timers; + u8 send_peer_notif; s8 setup_by_slave; s8 igmp_retrans; #ifdef CONFIG_PROC_FS diff --git a/net/ipv4/devinet.c b/net/ipv4/devinet.c index acf553f..5345b0b 100644 --- a/net/ipv4/devinet.c +++ b/net/ipv4/devinet.c @@ -1203,7 +1203,6 @@ static int inetdev_event(struct notifier_block *this, unsigned long event, break; /* fall through */ case NETDEV_NOTIFY_PEERS: - case NETDEV_BONDING_FAILOVER: /* Send gratuitous ARP to notify of link change */ inetdev_send_gratuitous_arp(dev, in_dev); break; diff --git a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c index 69aacd1..7596f07 100644 --- a/net/ipv6/ndisc.c +++ b/net/ipv6/ndisc.c @@ -1747,7 +1747,6 @@ static int ndisc_netdev_event(struct notifier_block *this, unsigned long event, fib6_run_gc(~0UL, net); break; case NETDEV_NOTIFY_PEERS: - case NETDEV_BONDING_FAILOVER: ndisc_send_unsol_na(dev); break; default: -- cgit v0.10.2 From f94bc1e70281c5a587049015af8f3e024d45ad66 Mon Sep 17 00:00:00 2001 From: Sucheta Chakraborty Date: Thu, 28 Apr 2011 11:48:18 +0000 Subject: qlcnic: support rcv ring configuration through ethtool o Support ethtool command ETHTOOL_GCHANNELS and ETHTOOL_SCHANNELS. o Number of rcv rings configuration depend upon number of msix vector. Signed-off-by: Sucheta Chakraborty Signed-off-by: Amit Kumar Salecha Signed-off-by: David S. Miller diff --git a/drivers/net/qlcnic/qlcnic.h b/drivers/net/qlcnic/qlcnic.h index f7acb80..1934ed9 100644 --- a/drivers/net/qlcnic/qlcnic.h +++ b/drivers/net/qlcnic/qlcnic.h @@ -118,7 +118,6 @@ #define PHAN_PEG_RCV_INITIALIZED 0xff01 #define NUM_RCV_DESC_RINGS 3 -#define NUM_STS_DESC_RINGS 4 #define RCV_RING_NORMAL 0 #define RCV_RING_JUMBO 1 @@ -871,7 +870,8 @@ struct qlcnic_ipaddr { #define QLCNIC_IS_MSI_FAMILY(adapter) \ ((adapter)->flags & (QLCNIC_MSI_ENABLED | QLCNIC_MSIX_ENABLED)) -#define MSIX_ENTRIES_PER_ADAPTER NUM_STS_DESC_RINGS +#define QLCNIC_DEF_NUM_STS_DESC_RINGS 4 +#define QLCNIC_MIN_NUM_RSS_RINGS 2 #define QLCNIC_MSIX_TBL_SPACE 8192 #define QLCNIC_PCI_REG_MSIX_TBL 0x44 #define QLCNIC_MSIX_TBL_PGSIZE 4096 @@ -987,7 +987,7 @@ struct qlcnic_adapter { void __iomem *crb_int_state_reg; void __iomem *isr_int_vec; - struct msix_entry msix_entries[MSIX_ENTRIES_PER_ADAPTER]; + struct msix_entry *msix_entries; struct delayed_work fw_work; @@ -1262,6 +1262,8 @@ u32 qlcnic_issue_cmd(struct qlcnic_adapter *adapter, void qlcnic_diag_free_res(struct net_device *netdev, int max_sds_rings); int qlcnic_diag_alloc_res(struct net_device *netdev, int test); netdev_tx_t qlcnic_xmit_frame(struct sk_buff *skb, struct net_device *netdev); +int qlcnic_validate_max_rss(struct net_device *netdev, u8 max_hw, u8 val); +int qlcnic_set_max_rss(struct qlcnic_adapter *adapter, u8 data); /* Management functions */ int qlcnic_get_mac_address(struct qlcnic_adapter *, u8*); diff --git a/drivers/net/qlcnic/qlcnic_ethtool.c b/drivers/net/qlcnic/qlcnic_ethtool.c index de65847..8db1d19 100644 --- a/drivers/net/qlcnic/qlcnic_ethtool.c +++ b/drivers/net/qlcnic/qlcnic_ethtool.c @@ -474,6 +474,39 @@ qlcnic_set_ringparam(struct net_device *dev, return qlcnic_reset_context(adapter); } +static void qlcnic_get_channels(struct net_device *dev, + struct ethtool_channels *channel) +{ + struct qlcnic_adapter *adapter = netdev_priv(dev); + + channel->max_rx = rounddown_pow_of_two(min_t(int, + adapter->max_rx_ques, num_online_cpus())); + channel->max_tx = adapter->max_tx_ques; + + channel->rx_count = adapter->max_sds_rings; + channel->tx_count = adapter->max_tx_ques; +} + +static int qlcnic_set_channels(struct net_device *dev, + struct ethtool_channels *channel) +{ + struct qlcnic_adapter *adapter = netdev_priv(dev); + int err; + + if (channel->other_count || channel->combined_count || + channel->tx_count != channel->max_tx) + return -EINVAL; + + err = qlcnic_validate_max_rss(dev, channel->max_rx, channel->rx_count); + if (err) + return err; + + err = qlcnic_set_max_rss(adapter, channel->rx_count); + netdev_info(dev, "allocated 0x%x sds rings\n", + adapter->max_sds_rings); + return err; +} + static void qlcnic_get_pauseparam(struct net_device *netdev, struct ethtool_pauseparam *pause) @@ -949,6 +982,8 @@ const struct ethtool_ops qlcnic_ethtool_ops = { .get_eeprom = qlcnic_get_eeprom, .get_ringparam = qlcnic_get_ringparam, .set_ringparam = qlcnic_set_ringparam, + .get_channels = qlcnic_get_channels, + .set_channels = qlcnic_set_channels, .get_pauseparam = qlcnic_get_pauseparam, .set_pauseparam = qlcnic_set_pauseparam, .get_wol = qlcnic_get_wol, diff --git a/drivers/net/qlcnic/qlcnic_main.c b/drivers/net/qlcnic/qlcnic_main.c index 6e61951..d6cc4d4 100644 --- a/drivers/net/qlcnic/qlcnic_main.c +++ b/drivers/net/qlcnic/qlcnic_main.c @@ -18,6 +18,7 @@ #include #include #include +#include MODULE_DESCRIPTION("QLogic 1/10 GbE Converged/Intelligent Ethernet Driver"); MODULE_LICENSE("GPL"); @@ -350,39 +351,17 @@ static struct qlcnic_nic_template qlcnic_vf_ops = { .start_firmware = qlcnicvf_start_firmware }; -static void -qlcnic_setup_intr(struct qlcnic_adapter *adapter) +static int qlcnic_enable_msix(struct qlcnic_adapter *adapter, u32 num_msix) { - const struct qlcnic_legacy_intr_set *legacy_intrp; struct pci_dev *pdev = adapter->pdev; - int err, num_msix; - - if (adapter->msix_supported) { - num_msix = (num_online_cpus() >= MSIX_ENTRIES_PER_ADAPTER) ? - MSIX_ENTRIES_PER_ADAPTER : 2; - } else - num_msix = 1; + int err = -1; adapter->max_sds_rings = 1; - adapter->flags &= ~(QLCNIC_MSI_ENABLED | QLCNIC_MSIX_ENABLED); - - legacy_intrp = &legacy_intr[adapter->ahw->pci_func]; - - adapter->int_vec_bit = legacy_intrp->int_vec_bit; - adapter->tgt_status_reg = qlcnic_get_ioaddr(adapter, - legacy_intrp->tgt_status_reg); - adapter->tgt_mask_reg = qlcnic_get_ioaddr(adapter, - legacy_intrp->tgt_mask_reg); - adapter->isr_int_vec = qlcnic_get_ioaddr(adapter, ISR_INT_VECTOR); - - adapter->crb_int_state_reg = qlcnic_get_ioaddr(adapter, - ISR_INT_STATE_REG); - qlcnic_set_msix_bit(pdev, 0); if (adapter->msix_supported) { - + enable_msix: qlcnic_init_msix_entries(adapter, num_msix); err = pci_enable_msix(pdev, adapter->msix_entries, num_msix); if (err == 0) { @@ -392,14 +371,22 @@ qlcnic_setup_intr(struct qlcnic_adapter *adapter) adapter->max_sds_rings = num_msix; dev_info(&pdev->dev, "using msi-x interrupts\n"); - return; + return err; } + if (err > 0) { + num_msix = rounddown_pow_of_two(err); + if (num_msix) + goto enable_msix; + } + } + return err; +} - if (err > 0) - pci_disable_msix(pdev); - /* fall through for msi */ - } +static void qlcnic_enable_msi_legacy(struct qlcnic_adapter *adapter) +{ + const struct qlcnic_legacy_intr_set *legacy_intrp; + struct pci_dev *pdev = adapter->pdev; if (use_msi && !pci_enable_msi(pdev)) { adapter->flags |= QLCNIC_MSI_ENABLED; @@ -410,11 +397,41 @@ qlcnic_setup_intr(struct qlcnic_adapter *adapter) return; } + legacy_intrp = &legacy_intr[adapter->ahw->pci_func]; + + adapter->int_vec_bit = legacy_intrp->int_vec_bit; + adapter->tgt_status_reg = qlcnic_get_ioaddr(adapter, + legacy_intrp->tgt_status_reg); + adapter->tgt_mask_reg = qlcnic_get_ioaddr(adapter, + legacy_intrp->tgt_mask_reg); + adapter->isr_int_vec = qlcnic_get_ioaddr(adapter, ISR_INT_VECTOR); + + adapter->crb_int_state_reg = qlcnic_get_ioaddr(adapter, + ISR_INT_STATE_REG); dev_info(&pdev->dev, "using legacy interrupts\n"); adapter->msix_entries[0].vector = pdev->irq; } static void +qlcnic_setup_intr(struct qlcnic_adapter *adapter) +{ + int num_msix; + + if (adapter->msix_supported) { + num_msix = (num_online_cpus() >= + QLCNIC_DEF_NUM_STS_DESC_RINGS) ? + QLCNIC_DEF_NUM_STS_DESC_RINGS : + QLCNIC_MIN_NUM_RSS_RINGS; + } else + num_msix = 1; + + if (!qlcnic_enable_msix(adapter, num_msix)) + return; + + qlcnic_enable_msi_legacy(adapter); +} + +static void qlcnic_teardown_intr(struct qlcnic_adapter *adapter) { if (adapter->flags & QLCNIC_MSIX_ENABLED) @@ -1493,6 +1510,19 @@ static int qlcnic_set_dma_mask(struct pci_dev *pdev, u8 *pci_using_dac) return 0; } +static int +qlcnic_alloc_msix_entries(struct qlcnic_adapter *adapter, u16 count) +{ + adapter->msix_entries = kcalloc(count, sizeof(struct msix_entry), + GFP_KERNEL); + + if (adapter->msix_entries) + return 0; + + dev_err(&adapter->pdev->dev, "failed allocating msix_entries\n"); + return -ENOMEM; +} + static int __devinit qlcnic_probe(struct pci_dev *pdev, const struct pci_device_id *ent) { @@ -1587,6 +1617,10 @@ qlcnic_probe(struct pci_dev *pdev, const struct pci_device_id *ent) qlcnic_clear_stats(adapter); + err = qlcnic_alloc_msix_entries(adapter, adapter->max_rx_ques); + if (err) + goto err_out_decr_ref; + qlcnic_setup_intr(adapter); err = qlcnic_setup_netdev(adapter, netdev, pci_using_dac); @@ -1615,6 +1649,7 @@ qlcnic_probe(struct pci_dev *pdev, const struct pci_device_id *ent) err_out_disable_msi: qlcnic_teardown_intr(adapter); + kfree(adapter->msix_entries); err_out_decr_ref: qlcnic_clr_all_drv_state(adapter, 0); @@ -1666,6 +1701,7 @@ static void __devexit qlcnic_remove(struct pci_dev *pdev) qlcnic_free_lb_filters_mem(adapter); qlcnic_teardown_intr(adapter); + kfree(adapter->msix_entries); qlcnic_remove_diag_entries(adapter); @@ -3299,6 +3335,56 @@ static struct device_attribute dev_attr_diag_mode = { .store = qlcnic_store_diag_mode, }; +int qlcnic_validate_max_rss(struct net_device *netdev, u8 max_hw, u8 val) +{ + if (!use_msi_x && !use_msi) { + netdev_info(netdev, "no msix or msi support, hence no rss\n"); + return -EINVAL; + } + + if ((val > max_hw) || (val < 2) || !is_power_of_2(val)) { + netdev_info(netdev, "rss_ring valid range [2 - %x] in " + " powers of 2\n", max_hw); + return -EINVAL; + } + return 0; + +} + +int qlcnic_set_max_rss(struct qlcnic_adapter *adapter, u8 data) +{ + struct net_device *netdev = adapter->netdev; + int err = 0; + + if (test_and_set_bit(__QLCNIC_RESETTING, &adapter->state)) + return -EBUSY; + + netif_device_detach(netdev); + if (netif_running(netdev)) + __qlcnic_down(adapter, netdev); + qlcnic_detach(adapter); + qlcnic_teardown_intr(adapter); + + if (qlcnic_enable_msix(adapter, data)) { + netdev_info(netdev, "failed setting max_rss; rss disabled\n"); + qlcnic_enable_msi_legacy(adapter); + } + + if (netif_running(netdev)) { + err = qlcnic_attach(adapter); + if (err) + goto done; + err = __qlcnic_up(adapter, netdev); + if (err) + goto done; + qlcnic_restore_indev_addr(netdev, NETDEV_UP); + } + done: + netif_device_attach(netdev); + clear_bit(__QLCNIC_RESETTING, &adapter->state); + return err; +} + static int qlcnic_sysfs_validate_crb(struct qlcnic_adapter *adapter, loff_t offset, size_t size) -- cgit v0.10.2 From 7e610caaa5b32d3be9216f040f178e4a23b678b2 Mon Sep 17 00:00:00 2001 From: Sony Chacko Date: Thu, 28 Apr 2011 11:48:19 +0000 Subject: qlcnic: Support for GBE port settings Enable setting speed and auto negotiation parameters for GbE ports. Hardware do not support half duplex setting currently. o Update driver version to 5.0.17. Signed-off-by: Sony Chacko Signed-off-by: Amit Kumar Salecha Signed-off-by: David S. Miller diff --git a/drivers/net/qlcnic/qlcnic.h b/drivers/net/qlcnic/qlcnic.h index 1934ed9..f729363 100644 --- a/drivers/net/qlcnic/qlcnic.h +++ b/drivers/net/qlcnic/qlcnic.h @@ -36,8 +36,8 @@ #define _QLCNIC_LINUX_MAJOR 5 #define _QLCNIC_LINUX_MINOR 0 -#define _QLCNIC_LINUX_SUBVERSION 16 -#define QLCNIC_LINUX_VERSIONID "5.0.16" +#define _QLCNIC_LINUX_SUBVERSION 17 +#define QLCNIC_LINUX_VERSIONID "5.0.17" #define QLCNIC_DRV_IDC_VER 0x01 #define QLCNIC_DRIVER_VERSION ((_QLCNIC_LINUX_MAJOR << 16) |\ (_QLCNIC_LINUX_MINOR << 8) | (_QLCNIC_LINUX_SUBVERSION)) @@ -573,8 +573,10 @@ struct qlcnic_recv_context { #define QLCNIC_CDRP_CMD_CONFIGURE_ESWITCH 0x00000028 #define QLCNIC_CDRP_CMD_GET_ESWITCH_PORT_CONFIG 0x00000029 #define QLCNIC_CDRP_CMD_GET_ESWITCH_STATS 0x0000002a +#define QLCNIC_CDRP_CMD_CONFIG_PORT 0x0000002E #define QLCNIC_RCODE_SUCCESS 0 +#define QLCNIC_RCODE_NOT_SUPPORTED 9 #define QLCNIC_RCODE_TIMEOUT 17 #define QLCNIC_DESTROY_CTX_RESET 0 @@ -1155,8 +1157,7 @@ struct qlcnic_esw_statistics { struct __qlcnic_esw_statistics tx; }; -int qlcnic_fw_cmd_query_phy(struct qlcnic_adapter *adapter, u32 reg, u32 *val); -int qlcnic_fw_cmd_set_phy(struct qlcnic_adapter *adapter, u32 reg, u32 val); +int qlcnic_fw_cmd_set_port(struct qlcnic_adapter *adapter, u32 config); u32 qlcnic_hw_read_wx_2M(struct qlcnic_adapter *adapter, ulong off); int qlcnic_hw_write_wx_2M(struct qlcnic_adapter *, ulong off, u32 data); diff --git a/drivers/net/qlcnic/qlcnic_ctx.c b/drivers/net/qlcnic/qlcnic_ctx.c index 050fa5a..3a99886 100644 --- a/drivers/net/qlcnic/qlcnic_ctx.c +++ b/drivers/net/qlcnic/qlcnic_ctx.c @@ -359,33 +359,15 @@ qlcnic_fw_cmd_destroy_tx_ctx(struct qlcnic_adapter *adapter) } int -qlcnic_fw_cmd_query_phy(struct qlcnic_adapter *adapter, u32 reg, u32 *val) -{ - - if (qlcnic_issue_cmd(adapter, - adapter->ahw->pci_func, - adapter->fw_hal_version, - reg, - 0, - 0, - QLCNIC_CDRP_CMD_READ_PHY)) { - - return -EIO; - } - - return QLCRD32(adapter, QLCNIC_ARG1_CRB_OFFSET); -} - -int -qlcnic_fw_cmd_set_phy(struct qlcnic_adapter *adapter, u32 reg, u32 val) +qlcnic_fw_cmd_set_port(struct qlcnic_adapter *adapter, u32 config) { return qlcnic_issue_cmd(adapter, adapter->ahw->pci_func, adapter->fw_hal_version, - reg, - val, + config, + 0, 0, - QLCNIC_CDRP_CMD_WRITE_PHY); + QLCNIC_CDRP_CMD_CONFIG_PORT); } int qlcnic_alloc_hw_resources(struct qlcnic_adapter *adapter) diff --git a/drivers/net/qlcnic/qlcnic_ethtool.c b/drivers/net/qlcnic/qlcnic_ethtool.c index 8db1d19..27726eb 100644 --- a/drivers/net/qlcnic/qlcnic_ethtool.c +++ b/drivers/net/qlcnic/qlcnic_ethtool.c @@ -284,50 +284,44 @@ skip: static int qlcnic_set_settings(struct net_device *dev, struct ethtool_cmd *ecmd) { + u32 config = 0; + u32 ret = 0; struct qlcnic_adapter *adapter = netdev_priv(dev); - __u32 status; + + if (adapter->ahw->port_type != QLCNIC_GBE) + return -EOPNOTSUPP; /* read which mode */ - if (adapter->ahw->port_type == QLCNIC_GBE) { - /* autonegotiation */ - if (qlcnic_fw_cmd_set_phy(adapter, - QLCNIC_NIU_GB_MII_MGMT_ADDR_AUTONEG, - ecmd->autoneg) != 0) - return -EIO; - else - adapter->link_autoneg = ecmd->autoneg; + if (ecmd->duplex) + config |= 0x1; - if (qlcnic_fw_cmd_query_phy(adapter, - QLCNIC_NIU_GB_MII_MGMT_ADDR_PHY_STATUS, - &status) != 0) - return -EIO; + if (ecmd->autoneg) + config |= 0x2; - switch (ecmd->speed) { - case SPEED_10: - qlcnic_set_phy_speed(status, 0); - break; - case SPEED_100: - qlcnic_set_phy_speed(status, 1); - break; - case SPEED_1000: - qlcnic_set_phy_speed(status, 2); - break; - } + switch (ethtool_cmd_speed(ecmd)) { + case SPEED_10: + config |= (0 << 8); + break; + case SPEED_100: + config |= (1 << 8); + break; + case SPEED_1000: + config |= (10 << 8); + break; + default: + return -EIO; + } - if (ecmd->duplex == DUPLEX_HALF) - qlcnic_clear_phy_duplex(status); - if (ecmd->duplex == DUPLEX_FULL) - qlcnic_set_phy_duplex(status); - if (qlcnic_fw_cmd_set_phy(adapter, - QLCNIC_NIU_GB_MII_MGMT_ADDR_PHY_STATUS, - *((int *)&status)) != 0) - return -EIO; - else { - adapter->link_speed = ecmd->speed; - adapter->link_duplex = ecmd->duplex; - } - } else + ret = qlcnic_fw_cmd_set_port(adapter, config); + + if (ret == QLCNIC_RCODE_NOT_SUPPORTED) return -EOPNOTSUPP; + else if (ret) + return -EIO; + + adapter->link_speed = ethtool_cmd_speed(ecmd); + adapter->link_duplex = ecmd->duplex; + adapter->link_autoneg = ecmd->autoneg; if (!netif_running(dev)) return 0; -- cgit v0.10.2 From 947b4ad1d198b7303ecc961f4939a331be0c48f0 Mon Sep 17 00:00:00 2001 From: Ingo Molnar Date: Fri, 29 Apr 2011 22:52:42 +0200 Subject: perf list: Fix max event string size Recent stalled-cycles event names were larger than the 40 chars printout used by perf list. Extend that, make it robust for future extensions and also adjust alignments in face of wider event names. Cc: Peter Zijlstra Cc: Arnaldo Carvalho de Melo Cc: Frederic Weisbecker Link: http://lkml.kernel.org/n/tip-7y40wib8n009io7hjpn1dsrm@git.kernel.org Signed-off-by: Ingo Molnar diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c index 8a407f3..ffa493a 100644 --- a/tools/perf/util/parse-events.c +++ b/tools/perf/util/parse-events.c @@ -929,7 +929,7 @@ void print_tracepoint_events(const char *subsys_glob, const char *event_glob) snprintf(evt_path, MAXPATHLEN, "%s:%s", sys_dirent.d_name, evt_dirent.d_name); - printf(" %-42s [%s]\n", evt_path, + printf(" %-50s [%s]\n", evt_path, event_type_descriptors[PERF_TYPE_TRACEPOINT]); } closedir(evt_dir); @@ -994,7 +994,7 @@ void print_events_type(u8 type) else snprintf(name, sizeof(name), "%s", syms->symbol); - printf(" %-42s [%s]\n", name, + printf(" %-50s [%s]\n", name, event_type_descriptors[type]); } } @@ -1012,11 +1012,10 @@ int print_hwcache_events(const char *event_glob) for (i = 0; i < PERF_COUNT_HW_CACHE_RESULT_MAX; i++) { char *name = event_cache_name(type, op, i); - if (event_glob != NULL && - !strglobmatch(name, event_glob)) + if (event_glob != NULL && !strglobmatch(name, event_glob)) continue; - printf(" %-42s [%s]\n", name, + printf(" %-50s [%s]\n", name, event_type_descriptors[PERF_TYPE_HW_CACHE]); ++printed; } @@ -1026,14 +1025,16 @@ int print_hwcache_events(const char *event_glob) return printed; } +#define MAX_NAME_LEN 100 + /* * Print the help text for the event symbols: */ void print_events(const char *event_glob) { - struct event_symbol *syms = event_symbols; unsigned int i, type, prev_type = -1, printed = 0, ntypes_printed = 0; - char name[40]; + struct event_symbol *syms = event_symbols; + char name[MAX_NAME_LEN]; printf("\n"); printf("List of pre-defined events (to be used in -e):\n"); @@ -1053,10 +1054,10 @@ void print_events(const char *event_glob) continue; if (strlen(syms->alias)) - sprintf(name, "%s OR %s", syms->symbol, syms->alias); + snprintf(name, MAX_NAME_LEN, "%s OR %s", syms->symbol, syms->alias); else - strcpy(name, syms->symbol); - printf(" %-42s [%s]\n", name, + strncpy(name, syms->symbol, MAX_NAME_LEN); + printf(" %-50s [%s]\n", name, event_type_descriptors[type]); prev_type = type; @@ -1073,12 +1074,12 @@ void print_events(const char *event_glob) return; printf("\n"); - printf(" %-42s [%s]\n", + printf(" %-50s [%s]\n", "rNNN (see 'perf list --help' on how to encode it)", event_type_descriptors[PERF_TYPE_RAW]); printf("\n"); - printf(" %-42s [%s]\n", + printf(" %-50s [%s]\n", "mem:[:access]", event_type_descriptors[PERF_TYPE_BREAKPOINT]); printf("\n"); -- cgit v0.10.2 From 2b5a4ace664cfe05c17bee60c4da66263a05fccf Mon Sep 17 00:00:00 2001 From: artpol Date: Wed, 27 Apr 2011 17:49:14 +0000 Subject: mii: add support of pause frames in mii_get_an Add support of pause frames advertise in mii_get_an. This provides all drivers that use mii_ethtool_gset to represent their own and Link partner flow control abilities in ethtool. Signed-off-by: Artem Polyakov Signed-off-by: David S. Miller diff --git a/drivers/net/mii.c b/drivers/net/mii.c index 0a6c6a2..d4fc00b 100644 --- a/drivers/net/mii.c +++ b/drivers/net/mii.c @@ -49,6 +49,10 @@ static u32 mii_get_an(struct mii_if_info *mii, u16 addr) result |= ADVERTISED_100baseT_Half; if (advert & ADVERTISE_100FULL) result |= ADVERTISED_100baseT_Full; + if (advert & ADVERTISE_PAUSE_CAP) + result |= ADVERTISED_Pause; + if (advert & ADVERTISE_PAUSE_ASYM) + result |= ADVERTISED_Asym_Pause; return result; } -- cgit v0.10.2 From 36504605432996590f889e33d47e2d9c581f7569 Mon Sep 17 00:00:00 2001 From: David Decotigny Date: Wed, 27 Apr 2011 18:32:37 +0000 Subject: ethtool: cosmetics: enforce const-ness in ethtool_cmd_speed The 'ep' argument of ethtool_cmd_speed is not altered: advertise it in protoype. +Indentation fix. Also add comments to advise using the ethtool_cmd_speed API to get/set the link speed. Signed-off-by: David Decotigny Signed-off-by: David S. Miller diff --git a/include/linux/ethtool.h b/include/linux/ethtool.h index 9de3127..7e6e0a8 100644 --- a/include/linux/ethtool.h +++ b/include/linux/ethtool.h @@ -24,7 +24,10 @@ struct ethtool_cmd { __u32 cmd; __u32 supported; /* Features this interface supports */ __u32 advertising; /* Features this interface advertises */ - __u16 speed; /* The forced speed, 10Mb, 100Mb, gigabit */ + __u16 speed; /* The forced speed (lower bits) in + * Mbps. Please use + * ethtool_cmd_speed()/_set() to + * access it */ __u8 duplex; /* Duplex, half or full */ __u8 port; /* Which connector port */ __u8 phy_address; @@ -33,7 +36,10 @@ struct ethtool_cmd { __u8 mdio_support; __u32 maxtxpkt; /* Tx pkts before generating tx int */ __u32 maxrxpkt; /* Rx pkts before generating rx int */ - __u16 speed_hi; + __u16 speed_hi; /* The forced speed (upper + * bits) in Mbps. Please use + * ethtool_cmd_speed()/_set() to + * access it */ __u8 eth_tp_mdix; __u8 reserved2; __u32 lp_advertising; /* Features the link partner advertises */ @@ -41,14 +47,14 @@ struct ethtool_cmd { }; static inline void ethtool_cmd_speed_set(struct ethtool_cmd *ep, - __u32 speed) + __u32 speed) { ep->speed = (__u16)speed; ep->speed_hi = (__u16)(speed >> 16); } -static inline __u32 ethtool_cmd_speed(struct ethtool_cmd *ep) +static inline __u32 ethtool_cmd_speed(const struct ethtool_cmd *ep) { return (ep->speed_hi << 16) | ep->speed; } -- cgit v0.10.2 From 8ae6daca85c8bbd6a32c382db5e2a2a989f8bed2 Mon Sep 17 00:00:00 2001 From: David Decotigny Date: Wed, 27 Apr 2011 18:32:38 +0000 Subject: ethtool: Call ethtool's get/set_settings callbacks with cleaned data This makes sure that when a driver calls the ethtool's get/set_settings() callback of another driver, the data passed to it is clean. This guarantees that speed_hi will be zeroed correctly if the called callback doesn't explicitely set it: we are sure we don't get a corrupted speed from the underlying driver. We also take care of setting the cmd field appropriately (ETHTOOL_GSET/SSET). This applies to dev_ethtool_get_settings(), which now makes sure it sets up that ethtool command parameter correctly before passing it to drivers. This also means that whoever calls dev_ethtool_get_settings() does not have to clean the ethtool command parameter. This function also becomes an exported symbol instead of an inline. All drivers visible to make allyesconfig under x86_64 have been updated. Signed-off-by: David Decotigny Signed-off-by: David S. Miller diff --git a/arch/mips/txx9/generic/setup_tx4939.c b/arch/mips/txx9/generic/setup_tx4939.c index 3dc19f4..e9f95dc 100644 --- a/arch/mips/txx9/generic/setup_tx4939.c +++ b/arch/mips/txx9/generic/setup_tx4939.c @@ -318,19 +318,15 @@ void __init tx4939_sio_init(unsigned int sclk, unsigned int cts_mask) } #if defined(CONFIG_TC35815) || defined(CONFIG_TC35815_MODULE) -static int tx4939_get_eth_speed(struct net_device *dev) +static u32 tx4939_get_eth_speed(struct net_device *dev) { - struct ethtool_cmd cmd = { ETHTOOL_GSET }; - int speed = 100; /* default 100Mbps */ - int err; - if (!dev->ethtool_ops || !dev->ethtool_ops->get_settings) - return speed; - err = dev->ethtool_ops->get_settings(dev, &cmd); - if (err < 0) - return speed; - speed = cmd.speed == SPEED_100 ? 100 : 10; - return speed; + struct ethtool_cmd cmd; + if (dev_ethtool_get_settings(dev, &cmd)) + return 100; /* default 100Mbps */ + + return ethtool_cmd_speed(&cmd); } + static int tx4939_netdev_event(struct notifier_block *this, unsigned long event, void *ptr) @@ -343,8 +339,7 @@ static int tx4939_netdev_event(struct notifier_block *this, else if (dev->irq == TXX9_IRQ_BASE + TX4939_IR_ETH(1)) bit = TX4939_PCFG_SPEED1; if (bit) { - int speed = tx4939_get_eth_speed(dev); - if (speed == 100) + if (tx4939_get_eth_speed(dev) == 100) txx9_set64(&tx4939_ccfgptr->pcfg, bit); else txx9_clear64(&tx4939_ccfgptr->pcfg, bit); diff --git a/drivers/net/e100.c b/drivers/net/e100.c index b0aa9e6..66ba596 100644 --- a/drivers/net/e100.c +++ b/drivers/net/e100.c @@ -1668,7 +1668,7 @@ static void e100_adjust_adaptive_ifs(struct nic *nic, int speed, int duplex) static void e100_watchdog(unsigned long data) { struct nic *nic = (struct nic *)data; - struct ethtool_cmd cmd; + struct ethtool_cmd cmd = { .cmd = ETHTOOL_GSET }; netif_printk(nic, timer, KERN_DEBUG, nic->netdev, "right now = %ld\n", jiffies); diff --git a/drivers/net/mdio.c b/drivers/net/mdio.c index e85bf04..f2d10ab 100644 --- a/drivers/net/mdio.c +++ b/drivers/net/mdio.c @@ -176,6 +176,9 @@ static u32 mdio45_get_an(const struct mdio_if_info *mdio, u16 addr) * @npage_adv: Modes currently advertised on next pages * @npage_lpa: Modes advertised by link partner on next pages * + * The @ecmd parameter is expected to have been cleared before calling + * mdio45_ethtool_gset_npage(). + * * Since the CSRs for auto-negotiation using next pages are not fully * standardised, this function does not attempt to decode them. The * caller must pass them in. diff --git a/drivers/net/mii.c b/drivers/net/mii.c index 0a6c6a2..05acca7 100644 --- a/drivers/net/mii.c +++ b/drivers/net/mii.c @@ -58,6 +58,9 @@ static u32 mii_get_an(struct mii_if_info *mii, u16 addr) * @mii: MII interface * @ecmd: requested ethtool_cmd * + * The @ecmd parameter is expected to have been cleared before calling + * mii_ethtool_gset(). + * * Returns 0 for success, negative on error. */ int mii_ethtool_gset(struct mii_if_info *mii, struct ethtool_cmd *ecmd) diff --git a/drivers/net/pch_gbe/pch_gbe_main.c b/drivers/net/pch_gbe/pch_gbe_main.c index 4cc9872..f3e4b0a 100644 --- a/drivers/net/pch_gbe/pch_gbe_main.c +++ b/drivers/net/pch_gbe/pch_gbe_main.c @@ -888,12 +888,12 @@ static void pch_gbe_watchdog(unsigned long data) struct pch_gbe_adapter *adapter = (struct pch_gbe_adapter *)data; struct net_device *netdev = adapter->netdev; struct pch_gbe_hw *hw = &adapter->hw; - struct ethtool_cmd cmd; pr_debug("right now = %ld\n", jiffies); pch_gbe_update_stats(adapter); if ((mii_link_ok(&adapter->mii)) && (!netif_carrier_ok(netdev))) { + struct ethtool_cmd cmd = { .cmd = ETHTOOL_GSET }; netdev->tx_queue_len = adapter->tx_queue_len; /* mii library handles link maintenance tasks */ if (mii_ethtool_gset(&adapter->mii, &cmd)) { @@ -903,7 +903,7 @@ static void pch_gbe_watchdog(unsigned long data) PCH_GBE_WATCHDOG_PERIOD)); return; } - hw->mac.link_speed = cmd.speed; + hw->mac.link_speed = ethtool_cmd_speed(&cmd); hw->mac.link_duplex = cmd.duplex; /* Set the RGMII control. */ pch_gbe_set_rgmii_ctrl(adapter, hw->mac.link_speed, @@ -913,7 +913,7 @@ static void pch_gbe_watchdog(unsigned long data) hw->mac.link_duplex); netdev_dbg(netdev, "Link is Up %d Mbps %s-Duplex\n", - cmd.speed, + hw->mac.link_speed, cmd.duplex == DUPLEX_FULL ? "Full" : "Half"); netif_carrier_on(netdev); netif_wake_queue(netdev); diff --git a/drivers/net/pch_gbe/pch_gbe_phy.c b/drivers/net/pch_gbe/pch_gbe_phy.c index 923a687..9a8207f 100644 --- a/drivers/net/pch_gbe/pch_gbe_phy.c +++ b/drivers/net/pch_gbe/pch_gbe_phy.c @@ -247,7 +247,7 @@ inline void pch_gbe_phy_set_rgmii(struct pch_gbe_hw *hw) void pch_gbe_phy_init_setting(struct pch_gbe_hw *hw) { struct pch_gbe_adapter *adapter; - struct ethtool_cmd cmd; + struct ethtool_cmd cmd = { .cmd = ETHTOOL_GSET }; int ret; u16 mii_reg; diff --git a/drivers/net/pcnet32.c b/drivers/net/pcnet32.c index 0a1efba..b48aba9 100644 --- a/drivers/net/pcnet32.c +++ b/drivers/net/pcnet32.c @@ -2099,7 +2099,7 @@ static int pcnet32_open(struct net_device *dev) int first_phy = -1; u16 bmcr; u32 bcr9; - struct ethtool_cmd ecmd; + struct ethtool_cmd ecmd = { .cmd = ETHTOOL_GSET }; /* * There is really no good other way to handle multiple PHYs @@ -2115,9 +2115,9 @@ static int pcnet32_open(struct net_device *dev) ecmd.port = PORT_MII; ecmd.transceiver = XCVR_INTERNAL; ecmd.autoneg = AUTONEG_DISABLE; - ecmd.speed = - lp-> - options & PCNET32_PORT_100 ? SPEED_100 : SPEED_10; + ethtool_cmd_speed_set(&ecmd, + (lp->options & PCNET32_PORT_100) ? + SPEED_100 : SPEED_10); bcr9 = lp->a.read_bcr(ioaddr, 9); if (lp->options & PCNET32_PORT_FD) { @@ -2763,11 +2763,11 @@ static void pcnet32_check_media(struct net_device *dev, int verbose) netif_carrier_on(dev); if (lp->mii) { if (netif_msg_link(lp)) { - struct ethtool_cmd ecmd; + struct ethtool_cmd ecmd = { + .cmd = ETHTOOL_GSET }; mii_ethtool_gset(&lp->mii_if, &ecmd); - netdev_info(dev, "link up, %sMbps, %s-duplex\n", - (ecmd.speed == SPEED_100) - ? "100" : "10", + netdev_info(dev, "link up, %uMbps, %s-duplex\n", + ethtool_cmd_speed(&ecmd), (ecmd.duplex == DUPLEX_FULL) ? "full" : "half"); } diff --git a/drivers/net/sfc/mdio_10g.c b/drivers/net/sfc/mdio_10g.c index 19e68c2..7115914 100644 --- a/drivers/net/sfc/mdio_10g.c +++ b/drivers/net/sfc/mdio_10g.c @@ -232,12 +232,12 @@ void efx_mdio_set_mmds_lpower(struct efx_nic *efx, */ int efx_mdio_set_settings(struct efx_nic *efx, struct ethtool_cmd *ecmd) { - struct ethtool_cmd prev; + struct ethtool_cmd prev = { .cmd = ETHTOOL_GSET }; efx->phy_op->get_settings(efx, &prev); if (ecmd->advertising == prev.advertising && - ecmd->speed == prev.speed && + ethtool_cmd_speed(ecmd) == ethtool_cmd_speed(&prev) && ecmd->duplex == prev.duplex && ecmd->port == prev.port && ecmd->autoneg == prev.autoneg) diff --git a/drivers/net/stmmac/stmmac_ethtool.c b/drivers/net/stmmac/stmmac_ethtool.c index 0e61ac8..6f5aaeb 100644 --- a/drivers/net/stmmac/stmmac_ethtool.c +++ b/drivers/net/stmmac/stmmac_ethtool.c @@ -237,13 +237,12 @@ stmmac_set_pauseparam(struct net_device *netdev, if (phy->autoneg) { if (netif_running(netdev)) { - struct ethtool_cmd cmd; + struct ethtool_cmd cmd = { .cmd = ETHTOOL_SSET }; /* auto-negotiation automatically restarted */ - cmd.cmd = ETHTOOL_NWAY_RST; cmd.supported = phy->supported; cmd.advertising = phy->advertising; cmd.autoneg = phy->autoneg; - cmd.speed = phy->speed; + ethtool_cmd_speed_set(&cmd, phy->speed); cmd.duplex = phy->duplex; cmd.phy_address = phy->addr; ret = phy_ethtool_sset(phy, &cmd); diff --git a/drivers/net/usb/asix.c b/drivers/net/usb/asix.c index 6140b56..6998aa6 100644 --- a/drivers/net/usb/asix.c +++ b/drivers/net/usb/asix.c @@ -847,7 +847,7 @@ static void ax88172_set_multicast(struct net_device *net) static int ax88172_link_reset(struct usbnet *dev) { u8 mode; - struct ethtool_cmd ecmd; + struct ethtool_cmd ecmd = { .cmd = ETHTOOL_GSET }; mii_check_media(&dev->mii, 1, 1); mii_ethtool_gset(&dev->mii, &ecmd); @@ -856,8 +856,8 @@ static int ax88172_link_reset(struct usbnet *dev) if (ecmd.duplex != DUPLEX_FULL) mode |= ~AX88172_MEDIUM_FD; - netdev_dbg(dev->net, "ax88172_link_reset() speed: %d duplex: %d setting mode to 0x%04x\n", - ecmd.speed, ecmd.duplex, mode); + netdev_dbg(dev->net, "ax88172_link_reset() speed: %u duplex: %d setting mode to 0x%04x\n", + ethtool_cmd_speed(&ecmd), ecmd.duplex, mode); asix_write_medium_mode(dev, mode); @@ -947,20 +947,20 @@ static const struct ethtool_ops ax88772_ethtool_ops = { static int ax88772_link_reset(struct usbnet *dev) { u16 mode; - struct ethtool_cmd ecmd; + struct ethtool_cmd ecmd = { .cmd = ETHTOOL_GSET }; mii_check_media(&dev->mii, 1, 1); mii_ethtool_gset(&dev->mii, &ecmd); mode = AX88772_MEDIUM_DEFAULT; - if (ecmd.speed != SPEED_100) + if (ethtool_cmd_speed(&ecmd) != SPEED_100) mode &= ~AX_MEDIUM_PS; if (ecmd.duplex != DUPLEX_FULL) mode &= ~AX_MEDIUM_FD; - netdev_dbg(dev->net, "ax88772_link_reset() speed: %d duplex: %d setting mode to 0x%04x\n", - ecmd.speed, ecmd.duplex, mode); + netdev_dbg(dev->net, "ax88772_link_reset() speed: %u duplex: %d setting mode to 0x%04x\n", + ethtool_cmd_speed(&ecmd), ecmd.duplex, mode); asix_write_medium_mode(dev, mode); @@ -1173,18 +1173,20 @@ static int marvell_led_status(struct usbnet *dev, u16 speed) static int ax88178_link_reset(struct usbnet *dev) { u16 mode; - struct ethtool_cmd ecmd; + struct ethtool_cmd ecmd = { .cmd = ETHTOOL_GSET }; struct asix_data *data = (struct asix_data *)&dev->data; + u32 speed; netdev_dbg(dev->net, "ax88178_link_reset()\n"); mii_check_media(&dev->mii, 1, 1); mii_ethtool_gset(&dev->mii, &ecmd); mode = AX88178_MEDIUM_DEFAULT; + speed = ethtool_cmd_speed(&ecmd); - if (ecmd.speed == SPEED_1000) + if (speed == SPEED_1000) mode |= AX_MEDIUM_GM; - else if (ecmd.speed == SPEED_100) + else if (speed == SPEED_100) mode |= AX_MEDIUM_PS; else mode &= ~(AX_MEDIUM_PS | AX_MEDIUM_GM); @@ -1196,13 +1198,13 @@ static int ax88178_link_reset(struct usbnet *dev) else mode &= ~AX_MEDIUM_FD; - netdev_dbg(dev->net, "ax88178_link_reset() speed: %d duplex: %d setting mode to 0x%04x\n", - ecmd.speed, ecmd.duplex, mode); + netdev_dbg(dev->net, "ax88178_link_reset() speed: %u duplex: %d setting mode to 0x%04x\n", + speed, ecmd.duplex, mode); asix_write_medium_mode(dev, mode); if (data->phymode == PHY_MODE_MARVELL && data->ledmode) - marvell_led_status(dev, ecmd.speed); + marvell_led_status(dev, speed); return 0; } diff --git a/drivers/net/usb/dm9601.c b/drivers/net/usb/dm9601.c index 5002f5b..1d93133 100644 --- a/drivers/net/usb/dm9601.c +++ b/drivers/net/usb/dm9601.c @@ -599,13 +599,13 @@ static void dm9601_status(struct usbnet *dev, struct urb *urb) static int dm9601_link_reset(struct usbnet *dev) { - struct ethtool_cmd ecmd; + struct ethtool_cmd ecmd = { .cmd = ETHTOOL_GSET }; mii_check_media(&dev->mii, 1, 1); mii_ethtool_gset(&dev->mii, &ecmd); - netdev_dbg(dev->net, "link_reset() speed: %d duplex: %d\n", - ecmd.speed, ecmd.duplex); + netdev_dbg(dev->net, "link_reset() speed: %u duplex: %d\n", + ethtool_cmd_speed(&ecmd), ecmd.duplex); return 0; } diff --git a/drivers/net/usb/smsc75xx.c b/drivers/net/usb/smsc75xx.c index 860a20c..15b3d68 100644 --- a/drivers/net/usb/smsc75xx.c +++ b/drivers/net/usb/smsc75xx.c @@ -503,7 +503,7 @@ static int smsc75xx_update_flowcontrol(struct usbnet *dev, u8 duplex, static int smsc75xx_link_reset(struct usbnet *dev) { struct mii_if_info *mii = &dev->mii; - struct ethtool_cmd ecmd; + struct ethtool_cmd ecmd = { .cmd = ETHTOOL_GSET }; u16 lcladv, rmtadv; int ret; @@ -519,8 +519,9 @@ static int smsc75xx_link_reset(struct usbnet *dev) lcladv = smsc75xx_mdio_read(dev->net, mii->phy_id, MII_ADVERTISE); rmtadv = smsc75xx_mdio_read(dev->net, mii->phy_id, MII_LPA); - netif_dbg(dev, link, dev->net, "speed: %d duplex: %d lcladv: %04x" - " rmtadv: %04x", ecmd.speed, ecmd.duplex, lcladv, rmtadv); + netif_dbg(dev, link, dev->net, "speed: %u duplex: %d lcladv: %04x" + " rmtadv: %04x", ethtool_cmd_speed(&ecmd), + ecmd.duplex, lcladv, rmtadv); return smsc75xx_update_flowcontrol(dev, ecmd.duplex, lcladv, rmtadv); } diff --git a/drivers/net/usb/smsc95xx.c b/drivers/net/usb/smsc95xx.c index 24f4b37..b374a99 100644 --- a/drivers/net/usb/smsc95xx.c +++ b/drivers/net/usb/smsc95xx.c @@ -457,7 +457,7 @@ static int smsc95xx_link_reset(struct usbnet *dev) { struct smsc95xx_priv *pdata = (struct smsc95xx_priv *)(dev->data[0]); struct mii_if_info *mii = &dev->mii; - struct ethtool_cmd ecmd; + struct ethtool_cmd ecmd = { .cmd = ETHTOOL_GSET }; unsigned long flags; u16 lcladv, rmtadv; u32 intdata; @@ -472,8 +472,9 @@ static int smsc95xx_link_reset(struct usbnet *dev) lcladv = smsc95xx_mdio_read(dev->net, mii->phy_id, MII_ADVERTISE); rmtadv = smsc95xx_mdio_read(dev->net, mii->phy_id, MII_LPA); - netif_dbg(dev, link, dev->net, "speed: %d duplex: %d lcladv: %04x rmtadv: %04x\n", - ecmd.speed, ecmd.duplex, lcladv, rmtadv); + netif_dbg(dev, link, dev->net, + "speed: %u duplex: %d lcladv: %04x rmtadv: %04x\n", + ethtool_cmd_speed(&ecmd), ecmd.duplex, lcladv, rmtadv); spin_lock_irqsave(&pdata->mac_cr_lock, flags); if (ecmd.duplex != DUPLEX_FULL) { diff --git a/drivers/scsi/bnx2fc/bnx2fc_fcoe.c b/drivers/scsi/bnx2fc/bnx2fc_fcoe.c index e2e6475..cd05019 100644 --- a/drivers/scsi/bnx2fc/bnx2fc_fcoe.c +++ b/drivers/scsi/bnx2fc/bnx2fc_fcoe.c @@ -664,7 +664,7 @@ static void bnx2fc_link_speed_update(struct fc_lport *lport) struct fcoe_port *port = lport_priv(lport); struct bnx2fc_hba *hba = port->priv; struct net_device *netdev = hba->netdev; - struct ethtool_cmd ecmd = { ETHTOOL_GSET }; + struct ethtool_cmd ecmd; if (!dev_ethtool_get_settings(netdev, &ecmd)) { lport->link_supported_speeds &= @@ -675,12 +675,15 @@ static void bnx2fc_link_speed_update(struct fc_lport *lport) if (ecmd.supported & SUPPORTED_10000baseT_Full) lport->link_supported_speeds |= FC_PORTSPEED_10GBIT; - if (ecmd.speed == SPEED_1000) + switch (ethtool_cmd_speed(&ecmd)) { + case SPEED_1000: lport->link_speed = FC_PORTSPEED_1GBIT; - if (ecmd.speed == SPEED_10000) + break; + case SPEED_10000: lport->link_speed = FC_PORTSPEED_10GBIT; + break; + } } - return; } static int bnx2fc_link_ok(struct fc_lport *lport) { diff --git a/drivers/scsi/fcoe/fcoe.c b/drivers/scsi/fcoe/fcoe.c index bde6ee5..04f346b 100644 --- a/drivers/scsi/fcoe/fcoe.c +++ b/drivers/scsi/fcoe/fcoe.c @@ -2026,7 +2026,7 @@ out_nodev: int fcoe_link_speed_update(struct fc_lport *lport) { struct net_device *netdev = fcoe_netdev(lport); - struct ethtool_cmd ecmd = { ETHTOOL_GSET }; + struct ethtool_cmd ecmd; if (!dev_ethtool_get_settings(netdev, &ecmd)) { lport->link_supported_speeds &= @@ -2037,11 +2037,14 @@ int fcoe_link_speed_update(struct fc_lport *lport) if (ecmd.supported & SUPPORTED_10000baseT_Full) lport->link_supported_speeds |= FC_PORTSPEED_10GBIT; - if (ecmd.speed == SPEED_1000) + switch (ethtool_cmd_speed(&ecmd)) { + case SPEED_1000: lport->link_speed = FC_PORTSPEED_1GBIT; - if (ecmd.speed == SPEED_10000) + break; + case SPEED_10000: lport->link_speed = FC_PORTSPEED_10GBIT; - + break; + } return 0; } return -1; diff --git a/include/linux/ethtool.h b/include/linux/ethtool.h index 7e6e0a8..4194a20 100644 --- a/include/linux/ethtool.h +++ b/include/linux/ethtool.h @@ -744,7 +744,9 @@ bool ethtool_invalid_flags(struct net_device *dev, u32 data, u32 supported); /** * struct ethtool_ops - optional netdev operations * @get_settings: Get various device settings including Ethernet link - * settings. Returns a negative error code or zero. + * settings. The @cmd parameter is expected to have been cleared + * before get_settings is called. Returns a negative error code or + * zero. * @set_settings: Set various device settings including Ethernet link * settings. Returns a negative error code or zero. * @get_drvinfo: Report driver/device information. Should only set the diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index e03af35..d5de66a 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -2597,13 +2597,8 @@ static inline int netif_is_bond_slave(struct net_device *dev) extern struct pernet_operations __net_initdata loopback_net_ops; -static inline int dev_ethtool_get_settings(struct net_device *dev, - struct ethtool_cmd *cmd) -{ - if (!dev->ethtool_ops || !dev->ethtool_ops->get_settings) - return -EOPNOTSUPP; - return dev->ethtool_ops->get_settings(dev, cmd); -} +int dev_ethtool_get_settings(struct net_device *dev, + struct ethtool_cmd *cmd); static inline u32 dev_ethtool_get_rx_csum(struct net_device *dev) { diff --git a/include/rdma/ib_addr.h b/include/rdma/ib_addr.h index b5fc9f3..ae8c68f 100644 --- a/include/rdma/ib_addr.h +++ b/include/rdma/ib_addr.h @@ -217,18 +217,19 @@ static inline enum ib_mtu iboe_get_mtu(int mtu) static inline int iboe_get_rate(struct net_device *dev) { struct ethtool_cmd cmd; + u32 speed; - if (!dev->ethtool_ops || !dev->ethtool_ops->get_settings || - dev->ethtool_ops->get_settings(dev, &cmd)) + if (dev_ethtool_get_settings(dev, &cmd)) return IB_RATE_PORT_CURRENT; - if (cmd.speed >= 40000) + speed = ethtool_cmd_speed(&cmd); + if (speed >= 40000) return IB_RATE_40_GBPS; - else if (cmd.speed >= 30000) + else if (speed >= 30000) return IB_RATE_30_GBPS; - else if (cmd.speed >= 20000) + else if (speed >= 20000) return IB_RATE_20_GBPS; - else if (cmd.speed >= 10000) + else if (speed >= 10000) return IB_RATE_10_GBPS; else return IB_RATE_PORT_CURRENT; diff --git a/net/core/dev.c b/net/core/dev.c index 7db99b5..e95dc30 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -4496,6 +4496,30 @@ void dev_set_rx_mode(struct net_device *dev) } /** + * dev_ethtool_get_settings - call device's ethtool_ops::get_settings() + * @dev: device + * @cmd: memory area for ethtool_ops::get_settings() result + * + * The cmd arg is initialized properly (cleared and + * ethtool_cmd::cmd field set to ETHTOOL_GSET). + * + * Return device's ethtool_ops::get_settings() result value or + * -EOPNOTSUPP when device doesn't expose + * ethtool_ops::get_settings() operation. + */ +int dev_ethtool_get_settings(struct net_device *dev, + struct ethtool_cmd *cmd) +{ + if (!dev->ethtool_ops || !dev->ethtool_ops->get_settings) + return -EOPNOTSUPP; + + memset(cmd, 0, sizeof(struct ethtool_cmd)); + cmd->cmd = ETHTOOL_GSET; + return dev->ethtool_ops->get_settings(dev, cmd); +} +EXPORT_SYMBOL(dev_ethtool_get_settings); + +/** * dev_get_flags - get flags reported to userspace * @dev: device * diff --git a/net/core/net-sysfs.c b/net/core/net-sysfs.c index 5ceb257..381813e 100644 --- a/net/core/net-sysfs.c +++ b/net/core/net-sysfs.c @@ -28,6 +28,7 @@ static const char fmt_hex[] = "%#x\n"; static const char fmt_long_hex[] = "%#lx\n"; static const char fmt_dec[] = "%d\n"; +static const char fmt_udec[] = "%u\n"; static const char fmt_ulong[] = "%lu\n"; static const char fmt_u64[] = "%llu\n"; @@ -145,13 +146,10 @@ static ssize_t show_speed(struct device *dev, if (!rtnl_trylock()) return restart_syscall(); - if (netif_running(netdev) && - netdev->ethtool_ops && - netdev->ethtool_ops->get_settings) { - struct ethtool_cmd cmd = { ETHTOOL_GSET }; - - if (!netdev->ethtool_ops->get_settings(netdev, &cmd)) - ret = sprintf(buf, fmt_dec, ethtool_cmd_speed(&cmd)); + if (netif_running(netdev)) { + struct ethtool_cmd cmd; + if (!dev_ethtool_get_settings(netdev, &cmd)) + ret = sprintf(buf, fmt_udec, ethtool_cmd_speed(&cmd)); } rtnl_unlock(); return ret; @@ -166,13 +164,11 @@ static ssize_t show_duplex(struct device *dev, if (!rtnl_trylock()) return restart_syscall(); - if (netif_running(netdev) && - netdev->ethtool_ops && - netdev->ethtool_ops->get_settings) { - struct ethtool_cmd cmd = { ETHTOOL_GSET }; - - if (!netdev->ethtool_ops->get_settings(netdev, &cmd)) - ret = sprintf(buf, "%s\n", cmd.duplex ? "full" : "half"); + if (netif_running(netdev)) { + struct ethtool_cmd cmd; + if (!dev_ethtool_get_settings(netdev, &cmd)) + ret = sprintf(buf, "%s\n", + cmd.duplex ? "full" : "half"); } rtnl_unlock(); return ret; -- cgit v0.10.2 From 25db0338813a8915457636b1f6abe6a28fa73f8d Mon Sep 17 00:00:00 2001 From: David Decotigny Date: Wed, 27 Apr 2011 18:32:39 +0000 Subject: ethtool: Use full 32 bit speed range in ethtool's set_settings This makes sure the ethtool's set_settings() callback of network drivers don't ignore the 16 most significant bits when ethtool calls their set_settings(). All drivers compiled with make allyesconfig on x86_64 have been updated. Signed-off-by: David Decotigny Signed-off-by: David S. Miller diff --git a/drivers/net/acenic.c b/drivers/net/acenic.c index ee648fe..0b4d8d1 100644 --- a/drivers/net/acenic.c +++ b/drivers/net/acenic.c @@ -2718,7 +2718,7 @@ static int ace_set_settings(struct net_device *dev, struct ethtool_cmd *ecmd) link |= LNK_TX_FLOW_CTL_Y; if (ecmd->autoneg == AUTONEG_ENABLE) link |= LNK_NEGOTIATE; - if (ecmd->speed != speed) { + if (ethtool_cmd_speed(ecmd) != speed) { link &= ~(LNK_1000MB | LNK_100MB | LNK_10MB); switch (speed) { case SPEED_1000: diff --git a/drivers/net/atl1c/atl1c_ethtool.c b/drivers/net/atl1c/atl1c_ethtool.c index 3af5a33..b1eceee 100644 --- a/drivers/net/atl1c/atl1c_ethtool.c +++ b/drivers/net/atl1c/atl1c_ethtool.c @@ -77,7 +77,8 @@ static int atl1c_set_settings(struct net_device *netdev, if (ecmd->autoneg == AUTONEG_ENABLE) { autoneg_advertised = ADVERTISED_Autoneg; } else { - if (ecmd->speed == SPEED_1000) { + u32 speed = ethtool_cmd_speed(ecmd); + if (speed == SPEED_1000) { if (ecmd->duplex != DUPLEX_FULL) { if (netif_msg_link(adapter)) dev_warn(&adapter->pdev->dev, @@ -86,7 +87,7 @@ static int atl1c_set_settings(struct net_device *netdev, return -EINVAL; } autoneg_advertised = ADVERTISED_1000baseT_Full; - } else if (ecmd->speed == SPEED_100) { + } else if (speed == SPEED_100) { if (ecmd->duplex == DUPLEX_FULL) autoneg_advertised = ADVERTISED_100baseT_Full; else diff --git a/drivers/net/atlx/atl1.c b/drivers/net/atlx/atl1.c index dffa691..37a092f 100644 --- a/drivers/net/atlx/atl1.c +++ b/drivers/net/atlx/atl1.c @@ -3268,7 +3268,8 @@ static int atl1_set_settings(struct net_device *netdev, if (ecmd->autoneg == AUTONEG_ENABLE) hw->media_type = MEDIA_TYPE_AUTO_SENSOR; else { - if (ecmd->speed == SPEED_1000) { + u32 speed = ethtool_cmd_speed(ecmd); + if (speed == SPEED_1000) { if (ecmd->duplex != DUPLEX_FULL) { if (netif_msg_link(adapter)) dev_warn(&adapter->pdev->dev, @@ -3277,7 +3278,7 @@ static int atl1_set_settings(struct net_device *netdev, goto exit_sset; } hw->media_type = MEDIA_TYPE_1000M_FULL; - } else if (ecmd->speed == SPEED_100) { + } else if (speed == SPEED_100) { if (ecmd->duplex == DUPLEX_FULL) hw->media_type = MEDIA_TYPE_100M_FULL; else diff --git a/drivers/net/b44.c b/drivers/net/b44.c index 2e2b762..909cc4b 100644 --- a/drivers/net/b44.c +++ b/drivers/net/b44.c @@ -1831,6 +1831,7 @@ static int b44_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) static int b44_set_settings(struct net_device *dev, struct ethtool_cmd *cmd) { struct b44 *bp = netdev_priv(dev); + u32 speed = ethtool_cmd_speed(cmd); /* We do not support gigabit. */ if (cmd->autoneg == AUTONEG_ENABLE) { @@ -1838,8 +1839,8 @@ static int b44_set_settings(struct net_device *dev, struct ethtool_cmd *cmd) (ADVERTISED_1000baseT_Half | ADVERTISED_1000baseT_Full)) return -EINVAL; - } else if ((cmd->speed != SPEED_100 && - cmd->speed != SPEED_10) || + } else if ((speed != SPEED_100 && + speed != SPEED_10) || (cmd->duplex != DUPLEX_HALF && cmd->duplex != DUPLEX_FULL)) { return -EINVAL; @@ -1873,7 +1874,7 @@ static int b44_set_settings(struct net_device *dev, struct ethtool_cmd *cmd) } else { bp->flags |= B44_FLAG_FORCE_LINK; bp->flags &= ~(B44_FLAG_100_BASE_T | B44_FLAG_FULL_DUPLEX); - if (cmd->speed == SPEED_100) + if (speed == SPEED_100) bp->flags |= B44_FLAG_100_BASE_T; if (cmd->duplex == DUPLEX_FULL) bp->flags |= B44_FLAG_FULL_DUPLEX; diff --git a/drivers/net/bna/bnad_ethtool.c b/drivers/net/bna/bnad_ethtool.c index c51e078e..ae1e118 100644 --- a/drivers/net/bna/bnad_ethtool.c +++ b/drivers/net/bna/bnad_ethtool.c @@ -256,7 +256,8 @@ bnad_set_settings(struct net_device *netdev, struct ethtool_cmd *cmd) /* 10G full duplex setting supported only */ if (cmd->autoneg == AUTONEG_ENABLE) return -EOPNOTSUPP; else { - if ((cmd->speed == SPEED_10000) && (cmd->duplex == DUPLEX_FULL)) + if ((ethtool_cmd_speed(cmd) == SPEED_10000) + && (cmd->duplex == DUPLEX_FULL)) return 0; } diff --git a/drivers/net/bnx2.c b/drivers/net/bnx2.c index bf729ee..e43efd8 100644 --- a/drivers/net/bnx2.c +++ b/drivers/net/bnx2.c @@ -6758,21 +6758,21 @@ bnx2_set_settings(struct net_device *dev, struct ethtool_cmd *cmd) advertising |= ADVERTISED_Autoneg; } else { + u32 speed = ethtool_cmd_speed(cmd); if (cmd->port == PORT_FIBRE) { - if ((cmd->speed != SPEED_1000 && - cmd->speed != SPEED_2500) || + if ((speed != SPEED_1000 && + speed != SPEED_2500) || (cmd->duplex != DUPLEX_FULL)) goto err_out_unlock; - if (cmd->speed == SPEED_2500 && + if (speed == SPEED_2500 && !(bp->phy_flags & BNX2_PHY_FLAG_2_5G_CAPABLE)) goto err_out_unlock; - } - else if (cmd->speed == SPEED_1000 || cmd->speed == SPEED_2500) + } else if (speed == SPEED_1000 || speed == SPEED_2500) goto err_out_unlock; autoneg &= ~AUTONEG_SPEED; - req_line_speed = cmd->speed; + req_line_speed = speed; req_duplex = cmd->duplex; advertising = 0; } diff --git a/drivers/net/cassini.c b/drivers/net/cassini.c index 143a28c..a6c3f8c 100644 --- a/drivers/net/cassini.c +++ b/drivers/net/cassini.c @@ -709,10 +709,11 @@ static void cas_begin_auto_negotiation(struct cas *cp, struct ethtool_cmd *ep) if (ep->autoneg == AUTONEG_ENABLE) cp->link_cntl = BMCR_ANENABLE; else { + u32 speed = ethtool_cmd_speed(ep); cp->link_cntl = 0; - if (ep->speed == SPEED_100) + if (speed == SPEED_100) cp->link_cntl |= BMCR_SPEED100; - else if (ep->speed == SPEED_1000) + else if (speed == SPEED_1000) cp->link_cntl |= CAS_BMCR_SPEED1000; if (ep->duplex == DUPLEX_FULL) cp->link_cntl |= BMCR_FULLDPLX; @@ -4653,6 +4654,7 @@ static int cas_set_settings(struct net_device *dev, struct ethtool_cmd *cmd) { struct cas *cp = netdev_priv(dev); unsigned long flags; + u32 speed = ethtool_cmd_speed(cmd); /* Verify the settings we care about. */ if (cmd->autoneg != AUTONEG_ENABLE && @@ -4660,9 +4662,9 @@ static int cas_set_settings(struct net_device *dev, struct ethtool_cmd *cmd) return -EINVAL; if (cmd->autoneg == AUTONEG_DISABLE && - ((cmd->speed != SPEED_1000 && - cmd->speed != SPEED_100 && - cmd->speed != SPEED_10) || + ((speed != SPEED_1000 && + speed != SPEED_100 && + speed != SPEED_10) || (cmd->duplex != DUPLEX_HALF && cmd->duplex != DUPLEX_FULL))) return -EINVAL; diff --git a/drivers/net/chelsio/cxgb2.c b/drivers/net/chelsio/cxgb2.c index 5f82c9c..8e14d65 100644 --- a/drivers/net/chelsio/cxgb2.c +++ b/drivers/net/chelsio/cxgb2.c @@ -638,11 +638,12 @@ static int set_settings(struct net_device *dev, struct ethtool_cmd *cmd) return -EOPNOTSUPP; /* can't change speed/duplex */ if (cmd->autoneg == AUTONEG_DISABLE) { - int cap = speed_duplex_to_caps(cmd->speed, cmd->duplex); + u32 speed = ethtool_cmd_speed(cmd); + int cap = speed_duplex_to_caps(speed, cmd->duplex); - if (!(lc->supported & cap) || cmd->speed == SPEED_1000) + if (!(lc->supported & cap) || (speed == SPEED_1000)) return -EINVAL; - lc->requested_speed = cmd->speed; + lc->requested_speed = speed; lc->requested_duplex = cmd->duplex; lc->advertising = 0; } else { diff --git a/drivers/net/cxgb3/cxgb3_main.c b/drivers/net/cxgb3/cxgb3_main.c index 0404918..0526715 100644 --- a/drivers/net/cxgb3/cxgb3_main.c +++ b/drivers/net/cxgb3/cxgb3_main.c @@ -1821,7 +1821,8 @@ static int set_settings(struct net_device *dev, struct ethtool_cmd *cmd) * being requested. */ if (cmd->autoneg == AUTONEG_DISABLE) { - int cap = speed_duplex_to_caps(cmd->speed, cmd->duplex); + u32 speed = ethtool_cmd_speed(cmd); + int cap = speed_duplex_to_caps(speed, cmd->duplex); if (lc->supported & cap) return 0; } @@ -1829,11 +1830,12 @@ static int set_settings(struct net_device *dev, struct ethtool_cmd *cmd) } if (cmd->autoneg == AUTONEG_DISABLE) { - int cap = speed_duplex_to_caps(cmd->speed, cmd->duplex); + u32 speed = ethtool_cmd_speed(cmd); + int cap = speed_duplex_to_caps(speed, cmd->duplex); - if (!(lc->supported & cap) || cmd->speed == SPEED_1000) + if (!(lc->supported & cap) || (speed == SPEED_1000)) return -EINVAL; - lc->requested_speed = cmd->speed; + lc->requested_speed = speed; lc->requested_duplex = cmd->duplex; lc->advertising = 0; } else { diff --git a/drivers/net/cxgb4/cxgb4_main.c b/drivers/net/cxgb4/cxgb4_main.c index bdc868c..c02b4d3 100644 --- a/drivers/net/cxgb4/cxgb4_main.c +++ b/drivers/net/cxgb4/cxgb4_main.c @@ -1460,6 +1460,7 @@ static int set_settings(struct net_device *dev, struct ethtool_cmd *cmd) unsigned int cap; struct port_info *p = netdev_priv(dev); struct link_config *lc = &p->link_cfg; + u32 speed = ethtool_cmd_speed(cmd); if (cmd->duplex != DUPLEX_FULL) /* only full-duplex supported */ return -EINVAL; @@ -1470,16 +1471,16 @@ static int set_settings(struct net_device *dev, struct ethtool_cmd *cmd) * being requested. */ if (cmd->autoneg == AUTONEG_DISABLE && - (lc->supported & speed_to_caps(cmd->speed))) - return 0; + (lc->supported & speed_to_caps(speed))) + return 0; return -EINVAL; } if (cmd->autoneg == AUTONEG_DISABLE) { - cap = speed_to_caps(cmd->speed); + cap = speed_to_caps(speed); - if (!(lc->supported & cap) || cmd->speed == SPEED_1000 || - cmd->speed == SPEED_10000) + if (!(lc->supported & cap) || (speed == SPEED_1000) || + (speed == SPEED_10000)) return -EINVAL; lc->requested_speed = cap; lc->advertising = 0; diff --git a/drivers/net/dl2k.c b/drivers/net/dl2k.c index c05db60..ab63989 100644 --- a/drivers/net/dl2k.c +++ b/drivers/net/dl2k.c @@ -1219,31 +1219,20 @@ static int rio_set_settings(struct net_device *dev, struct ethtool_cmd *cmd) } else { np->an_enable = 0; if (np->speed == 1000) { - cmd->speed = SPEED_100; + ethtool_cmd_speed_set(cmd, SPEED_100); cmd->duplex = DUPLEX_FULL; printk("Warning!! Can't disable Auto negotiation in 1000Mbps, change to Manual 100Mbps, Full duplex.\n"); } - switch(cmd->speed + cmd->duplex) { - - case SPEED_10 + DUPLEX_HALF: - np->speed = 10; - np->full_duplex = 0; - break; - - case SPEED_10 + DUPLEX_FULL: + switch (ethtool_cmd_speed(cmd)) { + case SPEED_10: np->speed = 10; - np->full_duplex = 1; + np->full_duplex = (cmd->duplex == DUPLEX_FULL); break; - case SPEED_100 + DUPLEX_HALF: + case SPEED_100: np->speed = 100; - np->full_duplex = 0; - break; - case SPEED_100 + DUPLEX_FULL: - np->speed = 100; - np->full_duplex = 1; + np->full_duplex = (cmd->duplex == DUPLEX_FULL); break; - case SPEED_1000 + DUPLEX_HALF:/* not supported */ - case SPEED_1000 + DUPLEX_FULL:/* not supported */ + case SPEED_1000: /* not supported */ default: return -EINVAL; } diff --git a/drivers/net/e100.c b/drivers/net/e100.c index 66ba596..c810cda 100644 --- a/drivers/net/e100.c +++ b/drivers/net/e100.c @@ -1669,6 +1669,7 @@ static void e100_watchdog(unsigned long data) { struct nic *nic = (struct nic *)data; struct ethtool_cmd cmd = { .cmd = ETHTOOL_GSET }; + u32 speed; netif_printk(nic, timer, KERN_DEBUG, nic->netdev, "right now = %ld\n", jiffies); @@ -1676,10 +1677,11 @@ static void e100_watchdog(unsigned long data) /* mii library handles link maintenance tasks */ mii_ethtool_gset(&nic->mii, &cmd); + speed = ethtool_cmd_speed(&cmd); if (mii_link_ok(&nic->mii) && !netif_carrier_ok(nic->netdev)) { netdev_info(nic->netdev, "NIC Link is Up %u Mbps %s Duplex\n", - cmd.speed == SPEED_100 ? 100 : 10, + speed == SPEED_100 ? 100 : 10, cmd.duplex == DUPLEX_FULL ? "Full" : "Half"); } else if (!mii_link_ok(&nic->mii) && netif_carrier_ok(nic->netdev)) { netdev_info(nic->netdev, "NIC Link is Down\n"); @@ -1698,13 +1700,13 @@ static void e100_watchdog(unsigned long data) spin_unlock_irq(&nic->cmd_lock); e100_update_stats(nic); - e100_adjust_adaptive_ifs(nic, cmd.speed, cmd.duplex); + e100_adjust_adaptive_ifs(nic, speed, cmd.duplex); if (nic->mac <= mac_82557_D100_C) /* Issue a multicast command to workaround a 557 lock up */ e100_set_multicast_list(nic->netdev); - if (nic->flags & ich && cmd.speed==SPEED_10 && cmd.duplex==DUPLEX_HALF) + if (nic->flags & ich && speed == SPEED_10 && cmd.duplex == DUPLEX_HALF) /* Need SW workaround for ICH[x] 10Mbps/half duplex Tx hang. */ nic->flags |= ich_10h_workaround; else diff --git a/drivers/net/e1000/e1000_ethtool.c b/drivers/net/e1000/e1000_ethtool.c index dd70738..a53629d 100644 --- a/drivers/net/e1000/e1000_ethtool.c +++ b/drivers/net/e1000/e1000_ethtool.c @@ -197,11 +197,13 @@ static int e1000_set_settings(struct net_device *netdev, ADVERTISED_TP | ADVERTISED_Autoneg; ecmd->advertising = hw->autoneg_advertised; - } else - if (e1000_set_spd_dplx(adapter, ecmd->speed + ecmd->duplex)) { + } else { + u32 speed = ethtool_cmd_speed(ecmd); + if (e1000_set_spd_dplx(adapter, speed + ecmd->duplex)) { clear_bit(__E1000_RESETTING, &adapter->flags); return -EINVAL; } + } /* reset the link */ diff --git a/drivers/net/e1000e/ethtool.c b/drivers/net/e1000e/ethtool.c index 1d7bf40..bc02c6b 100644 --- a/drivers/net/e1000e/ethtool.c +++ b/drivers/net/e1000e/ethtool.c @@ -269,7 +269,8 @@ static int e1000_set_settings(struct net_device *netdev, if (adapter->fc_autoneg) hw->fc.requested_mode = e1000_fc_default; } else { - if (e1000_set_spd_dplx(adapter, ecmd->speed + ecmd->duplex)) { + u32 speed = ethtool_cmd_speed(ecmd); + if (e1000_set_spd_dplx(adapter, speed + ecmd->duplex)) { clear_bit(__E1000_RESETTING, &adapter->state); return -EINVAL; } diff --git a/drivers/net/enc28j60.c b/drivers/net/enc28j60.c index 907b05a..81a7937 100644 --- a/drivers/net/enc28j60.c +++ b/drivers/net/enc28j60.c @@ -1499,7 +1499,8 @@ enc28j60_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) static int enc28j60_set_settings(struct net_device *dev, struct ethtool_cmd *cmd) { - return enc28j60_setlink(dev, cmd->autoneg, cmd->speed, cmd->duplex); + return enc28j60_setlink(dev, cmd->autoneg, + ethtool_cmd_speed(cmd), cmd->duplex); } static u32 enc28j60_get_msglevel(struct net_device *dev) diff --git a/drivers/net/forcedeth.c b/drivers/net/forcedeth.c index 0e1c76a..d24b3f3 100644 --- a/drivers/net/forcedeth.c +++ b/drivers/net/forcedeth.c @@ -4029,6 +4029,7 @@ static int nv_get_settings(struct net_device *dev, struct ethtool_cmd *ecmd) static int nv_set_settings(struct net_device *dev, struct ethtool_cmd *ecmd) { struct fe_priv *np = netdev_priv(dev); + u32 speed = ethtool_cmd_speed(ecmd); if (ecmd->port != PORT_MII) return -EINVAL; @@ -4054,7 +4055,7 @@ static int nv_set_settings(struct net_device *dev, struct ethtool_cmd *ecmd) /* Note: autonegotiation disable, speed 1000 intentionally * forbidden - no one should need that. */ - if (ecmd->speed != SPEED_10 && ecmd->speed != SPEED_100) + if (speed != SPEED_10 && speed != SPEED_100) return -EINVAL; if (ecmd->duplex != DUPLEX_HALF && ecmd->duplex != DUPLEX_FULL) return -EINVAL; @@ -4138,13 +4139,13 @@ static int nv_set_settings(struct net_device *dev, struct ethtool_cmd *ecmd) adv = mii_rw(dev, np->phyaddr, MII_ADVERTISE, MII_READ); adv &= ~(ADVERTISE_ALL | ADVERTISE_100BASE4 | ADVERTISE_PAUSE_CAP | ADVERTISE_PAUSE_ASYM); - if (ecmd->speed == SPEED_10 && ecmd->duplex == DUPLEX_HALF) + if (speed == SPEED_10 && ecmd->duplex == DUPLEX_HALF) adv |= ADVERTISE_10HALF; - if (ecmd->speed == SPEED_10 && ecmd->duplex == DUPLEX_FULL) + if (speed == SPEED_10 && ecmd->duplex == DUPLEX_FULL) adv |= ADVERTISE_10FULL; - if (ecmd->speed == SPEED_100 && ecmd->duplex == DUPLEX_HALF) + if (speed == SPEED_100 && ecmd->duplex == DUPLEX_HALF) adv |= ADVERTISE_100HALF; - if (ecmd->speed == SPEED_100 && ecmd->duplex == DUPLEX_FULL) + if (speed == SPEED_100 && ecmd->duplex == DUPLEX_FULL) adv |= ADVERTISE_100FULL; np->pause_flags &= ~(NV_PAUSEFRAME_AUTONEG|NV_PAUSEFRAME_RX_ENABLE|NV_PAUSEFRAME_TX_ENABLE); if (np->pause_flags & NV_PAUSEFRAME_RX_REQ) {/* for rx we set both advertisements but disable tx pause */ diff --git a/drivers/net/igb/igb_ethtool.c b/drivers/net/igb/igb_ethtool.c index d976733..2cc221b 100644 --- a/drivers/net/igb/igb_ethtool.c +++ b/drivers/net/igb/igb_ethtool.c @@ -223,7 +223,8 @@ static int igb_set_settings(struct net_device *netdev, struct ethtool_cmd *ecmd) if (adapter->fc_autoneg) hw->fc.requested_mode = e1000_fc_default; } else { - if (igb_set_spd_dplx(adapter, ecmd->speed + ecmd->duplex)) { + u32 speed = ethtool_cmd_speed(ecmd); + if (igb_set_spd_dplx(adapter, speed + ecmd->duplex)) { clear_bit(__IGB_RESETTING, &adapter->state); return -EINVAL; } diff --git a/drivers/net/ixgb/ixgb_ethtool.c b/drivers/net/ixgb/ixgb_ethtool.c index cc53aa1..edb3d7e 100644 --- a/drivers/net/ixgb/ixgb_ethtool.c +++ b/drivers/net/ixgb/ixgb_ethtool.c @@ -129,9 +129,10 @@ static int ixgb_set_settings(struct net_device *netdev, struct ethtool_cmd *ecmd) { struct ixgb_adapter *adapter = netdev_priv(netdev); + u32 speed = ethtool_cmd_speed(ecmd); if (ecmd->autoneg == AUTONEG_ENABLE || - ecmd->speed + ecmd->duplex != SPEED_10000 + DUPLEX_FULL) + (speed + ecmd->duplex != SPEED_10000 + DUPLEX_FULL)) return -EINVAL; if (netif_running(adapter->netdev)) { diff --git a/drivers/net/ixgbe/ixgbe_ethtool.c b/drivers/net/ixgbe/ixgbe_ethtool.c index 7279345..c52243d 100644 --- a/drivers/net/ixgbe/ixgbe_ethtool.c +++ b/drivers/net/ixgbe/ixgbe_ethtool.c @@ -346,9 +346,10 @@ static int ixgbe_set_settings(struct net_device *netdev, } } else { /* in this case we currently only support 10Gb/FULL */ + u32 speed = ethtool_cmd_speed(ecmd); if ((ecmd->autoneg == AUTONEG_ENABLE) || (ecmd->advertising != ADVERTISED_10000baseT_Full) || - (ecmd->speed + ecmd->duplex != SPEED_10000 + DUPLEX_FULL)) + (speed + ecmd->duplex != SPEED_10000 + DUPLEX_FULL)) return -EINVAL; } diff --git a/drivers/net/jme.c b/drivers/net/jme.c index be4773f..b5b174a 100644 --- a/drivers/net/jme.c +++ b/drivers/net/jme.c @@ -2555,7 +2555,8 @@ jme_set_settings(struct net_device *netdev, struct jme_adapter *jme = netdev_priv(netdev); int rc, fdc = 0; - if (ecmd->speed == SPEED_1000 && ecmd->autoneg != AUTONEG_ENABLE) + if (ethtool_cmd_speed(ecmd) == SPEED_1000 + && ecmd->autoneg != AUTONEG_ENABLE) return -EINVAL; /* diff --git a/drivers/net/ksz884x.c b/drivers/net/ksz884x.c index 2c37a38..41ea592 100644 --- a/drivers/net/ksz884x.c +++ b/drivers/net/ksz884x.c @@ -5998,6 +5998,7 @@ static int netdev_set_settings(struct net_device *dev, struct ethtool_cmd *cmd) struct dev_priv *priv = netdev_priv(dev); struct dev_info *hw_priv = priv->adapter; struct ksz_port *port = &priv->port; + u32 speed = ethtool_cmd_speed(cmd); int rc; /* @@ -6006,11 +6007,11 @@ static int netdev_set_settings(struct net_device *dev, struct ethtool_cmd *cmd) */ if (cmd->autoneg && priv->advertising == cmd->advertising) { cmd->advertising |= ADVERTISED_ALL; - if (10 == cmd->speed) + if (10 == speed) cmd->advertising &= ~(ADVERTISED_100baseT_Full | ADVERTISED_100baseT_Half); - else if (100 == cmd->speed) + else if (100 == speed) cmd->advertising &= ~(ADVERTISED_10baseT_Full | ADVERTISED_10baseT_Half); @@ -6032,8 +6033,8 @@ static int netdev_set_settings(struct net_device *dev, struct ethtool_cmd *cmd) port->force_link = 0; } else { port->duplex = cmd->duplex + 1; - if (cmd->speed != 1000) - port->speed = cmd->speed; + if (1000 != speed) + port->speed = speed; if (cmd->autoneg) port->force_link = 0; else diff --git a/drivers/net/mii.c b/drivers/net/mii.c index 05acca7..e8198ed 100644 --- a/drivers/net/mii.c +++ b/drivers/net/mii.c @@ -157,10 +157,11 @@ int mii_ethtool_gset(struct mii_if_info *mii, struct ethtool_cmd *ecmd) int mii_ethtool_sset(struct mii_if_info *mii, struct ethtool_cmd *ecmd) { struct net_device *dev = mii->dev; + u32 speed = ethtool_cmd_speed(ecmd); - if (ecmd->speed != SPEED_10 && - ecmd->speed != SPEED_100 && - ecmd->speed != SPEED_1000) + if (speed != SPEED_10 && + speed != SPEED_100 && + speed != SPEED_1000) return -EINVAL; if (ecmd->duplex != DUPLEX_HALF && ecmd->duplex != DUPLEX_FULL) return -EINVAL; @@ -172,7 +173,7 @@ int mii_ethtool_sset(struct mii_if_info *mii, struct ethtool_cmd *ecmd) return -EINVAL; if (ecmd->autoneg != AUTONEG_DISABLE && ecmd->autoneg != AUTONEG_ENABLE) return -EINVAL; - if ((ecmd->speed == SPEED_1000) && (!mii->supports_gmii)) + if ((speed == SPEED_1000) && (!mii->supports_gmii)) return -EINVAL; /* ignore supported, maxtxpkt, maxrxpkt */ @@ -230,9 +231,9 @@ int mii_ethtool_sset(struct mii_if_info *mii, struct ethtool_cmd *ecmd) bmcr = mii->mdio_read(dev, mii->phy_id, MII_BMCR); tmp = bmcr & ~(BMCR_ANENABLE | BMCR_SPEED100 | BMCR_SPEED1000 | BMCR_FULLDPLX); - if (ecmd->speed == SPEED_1000) + if (speed == SPEED_1000) tmp |= BMCR_SPEED1000; - else if (ecmd->speed == SPEED_100) + else if (speed == SPEED_100) tmp |= BMCR_SPEED100; if (ecmd->duplex == DUPLEX_FULL) { tmp |= BMCR_FULLDPLX; diff --git a/drivers/net/mlx4/en_ethtool.c b/drivers/net/mlx4/en_ethtool.c index da1b64d..be4a9e0 100644 --- a/drivers/net/mlx4/en_ethtool.c +++ b/drivers/net/mlx4/en_ethtool.c @@ -292,7 +292,8 @@ static int mlx4_en_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) static int mlx4_en_set_settings(struct net_device *dev, struct ethtool_cmd *cmd) { if ((cmd->autoneg == AUTONEG_ENABLE) || - (cmd->speed != SPEED_10000) || (cmd->duplex != DUPLEX_FULL)) + (ethtool_cmd_speed(cmd) != SPEED_10000) || + (cmd->duplex != DUPLEX_FULL)) return -EINVAL; /* Nothing to change */ diff --git a/drivers/net/natsemi.c b/drivers/net/natsemi.c index 1074231..7633c67 100644 --- a/drivers/net/natsemi.c +++ b/drivers/net/natsemi.c @@ -2908,7 +2908,8 @@ static int netdev_set_ecmd(struct net_device *dev, struct ethtool_cmd *ecmd) return -EINVAL; } } else if (ecmd->autoneg == AUTONEG_DISABLE) { - if (ecmd->speed != SPEED_10 && ecmd->speed != SPEED_100) + u32 speed = ethtool_cmd_speed(ecmd); + if (speed != SPEED_10 && speed != SPEED_100) return -EINVAL; if (ecmd->duplex != DUPLEX_HALF && ecmd->duplex != DUPLEX_FULL) return -EINVAL; @@ -2956,7 +2957,7 @@ static int netdev_set_ecmd(struct net_device *dev, struct ethtool_cmd *ecmd) if (ecmd->advertising & ADVERTISED_100baseT_Full) np->advertising |= ADVERTISE_100FULL; } else { - np->speed = ecmd->speed; + np->speed = ethtool_cmd_speed(ecmd); np->duplex = ecmd->duplex; /* user overriding the initial full duplex parm? */ if (np->duplex == DUPLEX_HALF) diff --git a/drivers/net/netxen/netxen_nic_ethtool.c b/drivers/net/netxen/netxen_nic_ethtool.c index 29f90ba..e8d16f6 100644 --- a/drivers/net/netxen/netxen_nic_ethtool.c +++ b/drivers/net/netxen/netxen_nic_ethtool.c @@ -251,6 +251,7 @@ static int netxen_nic_set_settings(struct net_device *dev, struct ethtool_cmd *ecmd) { struct netxen_adapter *adapter = netdev_priv(dev); + u32 speed = ethtool_cmd_speed(ecmd); int ret; if (adapter->ahw.port_type != NETXEN_NIC_GBE) @@ -259,14 +260,14 @@ netxen_nic_set_settings(struct net_device *dev, struct ethtool_cmd *ecmd) if (!(adapter->capabilities & NX_FW_CAPABILITY_GBE_LINK_CFG)) return -EOPNOTSUPP; - ret = nx_fw_cmd_set_gbe_port(adapter, ecmd->speed, ecmd->duplex, + ret = nx_fw_cmd_set_gbe_port(adapter, speed, ecmd->duplex, ecmd->autoneg); if (ret == NX_RCODE_NOT_SUPPORTED) return -EOPNOTSUPP; else if (ret) return -EIO; - adapter->link_speed = ecmd->speed; + adapter->link_speed = speed; adapter->link_duplex = ecmd->duplex; adapter->link_autoneg = ecmd->autoneg; diff --git a/drivers/net/niu.c b/drivers/net/niu.c index a707217..524e800 100644 --- a/drivers/net/niu.c +++ b/drivers/net/niu.c @@ -6859,7 +6859,7 @@ static int niu_set_settings(struct net_device *dev, struct ethtool_cmd *cmd) struct niu_link_config *lp = &np->link_config; lp->advertising = cmd->advertising; - lp->speed = cmd->speed; + lp->speed = ethtool_cmd_speed(cmd); lp->duplex = cmd->duplex; lp->autoneg = cmd->autoneg; return niu_init_link(np); diff --git a/drivers/net/pch_gbe/pch_gbe_ethtool.c b/drivers/net/pch_gbe/pch_gbe_ethtool.c index c35d105..ea2d8e4 100644 --- a/drivers/net/pch_gbe/pch_gbe_ethtool.c +++ b/drivers/net/pch_gbe/pch_gbe_ethtool.c @@ -92,7 +92,7 @@ static int pch_gbe_get_settings(struct net_device *netdev, ecmd->advertising &= ~(ADVERTISED_TP | ADVERTISED_1000baseT_Half); if (!netif_carrier_ok(adapter->netdev)) - ecmd->speed = -1; + ethtool_cmd_speed_set(ecmd, -1); return ret; } @@ -109,12 +109,15 @@ static int pch_gbe_set_settings(struct net_device *netdev, { struct pch_gbe_adapter *adapter = netdev_priv(netdev); struct pch_gbe_hw *hw = &adapter->hw; + u32 speed = ethtool_cmd_speed(ecmd); int ret; pch_gbe_hal_write_phy_reg(hw, MII_BMCR, BMCR_RESET); - if (ecmd->speed == USHRT_MAX) { - ecmd->speed = SPEED_1000; + /* when set_settings() is called with a ethtool_cmd previously + * filled by get_settings() on a down link, speed is -1: */ + if (speed == UINT_MAX) { + speed = SPEED_1000; ecmd->duplex = DUPLEX_FULL; } ret = mii_ethtool_sset(&adapter->mii, ecmd); @@ -122,7 +125,7 @@ static int pch_gbe_set_settings(struct net_device *netdev, pr_err("Error: mii_ethtool_sset\n"); return ret; } - hw->mac.link_speed = ecmd->speed; + hw->mac.link_speed = speed; hw->mac.link_duplex = ecmd->duplex; hw->phy.autoneg_advertised = ecmd->advertising; hw->mac.autoneg = ecmd->autoneg; diff --git a/drivers/net/pcmcia/smc91c92_cs.c b/drivers/net/pcmcia/smc91c92_cs.c index 1085917..bc71cb2 100644 --- a/drivers/net/pcmcia/smc91c92_cs.c +++ b/drivers/net/pcmcia/smc91c92_cs.c @@ -1875,8 +1875,8 @@ static int smc_netdev_set_ecmd(struct net_device *dev, struct ethtool_cmd *ecmd) u16 tmp; unsigned int ioaddr = dev->base_addr; - if (ecmd->speed != SPEED_10) - return -EINVAL; + if (ethtool_cmd_speed(ecmd) != SPEED_10) + return -EINVAL; if (ecmd->duplex != DUPLEX_HALF && ecmd->duplex != DUPLEX_FULL) return -EINVAL; if (ecmd->port != PORT_TP && ecmd->port != PORT_AUI) diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c index f767033..e3f3501 100644 --- a/drivers/net/phy/phy.c +++ b/drivers/net/phy/phy.c @@ -238,6 +238,8 @@ static void phy_sanitize_settings(struct phy_device *phydev) */ int phy_ethtool_sset(struct phy_device *phydev, struct ethtool_cmd *cmd) { + u32 speed = ethtool_cmd_speed(cmd); + if (cmd->phy_address != phydev->addr) return -EINVAL; @@ -253,16 +255,16 @@ int phy_ethtool_sset(struct phy_device *phydev, struct ethtool_cmd *cmd) return -EINVAL; if (cmd->autoneg == AUTONEG_DISABLE && - ((cmd->speed != SPEED_1000 && - cmd->speed != SPEED_100 && - cmd->speed != SPEED_10) || + ((speed != SPEED_1000 && + speed != SPEED_100 && + speed != SPEED_10) || (cmd->duplex != DUPLEX_HALF && cmd->duplex != DUPLEX_FULL))) return -EINVAL; phydev->autoneg = cmd->autoneg; - phydev->speed = cmd->speed; + phydev->speed = speed; phydev->advertising = cmd->advertising; diff --git a/drivers/net/r8169.c b/drivers/net/r8169.c index 6364e0b..b52ee17 100644 --- a/drivers/net/r8169.c +++ b/drivers/net/r8169.c @@ -1349,7 +1349,8 @@ static int rtl8169_set_settings(struct net_device *dev, struct ethtool_cmd *cmd) spin_lock_irqsave(&tp->lock, flags); ret = rtl8169_set_speed(dev, - cmd->autoneg, cmd->speed, cmd->duplex, cmd->advertising); + cmd->autoneg, ethtool_cmd_speed(cmd), + cmd->duplex, cmd->advertising); spin_unlock_irqrestore(&tp->lock, flags); return ret; diff --git a/drivers/net/s2io.c b/drivers/net/s2io.c index 58b78f4..5443985 100644 --- a/drivers/net/s2io.c +++ b/drivers/net/s2io.c @@ -5380,7 +5380,7 @@ static int s2io_ethtool_sset(struct net_device *dev, { struct s2io_nic *sp = netdev_priv(dev); if ((info->autoneg == AUTONEG_ENABLE) || - (info->speed != SPEED_10000) || + (ethtool_cmd_speed(info) != SPEED_10000) || (info->duplex != DUPLEX_FULL)) return -EINVAL; else { diff --git a/drivers/net/sc92031.c b/drivers/net/sc92031.c index 76290a8..f3ffc1d 100644 --- a/drivers/net/sc92031.c +++ b/drivers/net/sc92031.c @@ -1188,10 +1188,11 @@ static int sc92031_ethtool_set_settings(struct net_device *dev, { struct sc92031_priv *priv = netdev_priv(dev); void __iomem *port_base = priv->port_base; + u32 speed = ethtool_cmd_speed(cmd); u32 phy_ctrl; u32 old_phy_ctrl; - if (!(cmd->speed == SPEED_10 || cmd->speed == SPEED_100)) + if (!(speed == SPEED_10 || speed == SPEED_100)) return -EINVAL; if (!(cmd->duplex == DUPLEX_HALF || cmd->duplex == DUPLEX_FULL)) return -EINVAL; @@ -1229,7 +1230,7 @@ static int sc92031_ethtool_set_settings(struct net_device *dev, // FIXME: Whole branch guessed phy_ctrl = 0; - if (cmd->speed == SPEED_10) + if (speed == SPEED_10) phy_ctrl |= PhyCtrlSpd10; else /* cmd->speed == SPEED_100 */ phy_ctrl |= PhyCtrlSpd100; diff --git a/drivers/net/sfc/ethtool.c b/drivers/net/sfc/ethtool.c index 5d8468f..10b160a 100644 --- a/drivers/net/sfc/ethtool.c +++ b/drivers/net/sfc/ethtool.c @@ -234,7 +234,8 @@ static int efx_ethtool_set_settings(struct net_device *net_dev, int rc; /* GMAC does not support 1000Mbps HD */ - if (ecmd->speed == SPEED_1000 && ecmd->duplex != DUPLEX_FULL) { + if ((ethtool_cmd_speed(ecmd) == SPEED_1000) && + (ecmd->duplex != DUPLEX_FULL)) { netif_dbg(efx, drv, efx->net_dev, "rejecting unsupported 1000Mbps HD setting\n"); return -EINVAL; diff --git a/drivers/net/sfc/mcdi_phy.c b/drivers/net/sfc/mcdi_phy.c index 1fcda2d..6c5fccb 100644 --- a/drivers/net/sfc/mcdi_phy.c +++ b/drivers/net/sfc/mcdi_phy.c @@ -545,7 +545,7 @@ static int efx_mcdi_phy_set_settings(struct efx_nic *efx, struct ethtool_cmd *ec caps = (ethtool_to_mcdi_cap(ecmd->advertising) | 1 << MC_CMD_PHY_CAP_AN_LBN); } else if (ecmd->duplex) { - switch (ecmd->speed) { + switch (ethtool_cmd_speed(ecmd)) { case 10: caps = 1 << MC_CMD_PHY_CAP_10FDX_LBN; break; case 100: caps = 1 << MC_CMD_PHY_CAP_100FDX_LBN; break; case 1000: caps = 1 << MC_CMD_PHY_CAP_1000FDX_LBN; break; @@ -553,7 +553,7 @@ static int efx_mcdi_phy_set_settings(struct efx_nic *efx, struct ethtool_cmd *ec default: return -EINVAL; } } else { - switch (ecmd->speed) { + switch (ethtool_cmd_speed(ecmd)) { case 10: caps = 1 << MC_CMD_PHY_CAP_10HDX_LBN; break; case 100: caps = 1 << MC_CMD_PHY_CAP_100HDX_LBN; break; case 1000: caps = 1 << MC_CMD_PHY_CAP_1000HDX_LBN; break; diff --git a/drivers/net/skge.c b/drivers/net/skge.c index 176d784..a05e864 100644 --- a/drivers/net/skge.c +++ b/drivers/net/skge.c @@ -321,8 +321,9 @@ static int skge_set_settings(struct net_device *dev, struct ethtool_cmd *ecmd) skge->speed = -1; } else { u32 setting; + u32 speed = ethtool_cmd_speed(ecmd); - switch (ecmd->speed) { + switch (speed) { case SPEED_1000: if (ecmd->duplex == DUPLEX_FULL) setting = SUPPORTED_1000baseT_Full; @@ -355,7 +356,7 @@ static int skge_set_settings(struct net_device *dev, struct ethtool_cmd *ecmd) if ((setting & supported) == 0) return -EINVAL; - skge->speed = ecmd->speed; + skge->speed = speed; skge->duplex = ecmd->duplex; } diff --git a/drivers/net/sky2.c b/drivers/net/sky2.c index c8d0451..5c7e2d6 100644 --- a/drivers/net/sky2.c +++ b/drivers/net/sky2.c @@ -3452,8 +3452,9 @@ static int sky2_set_settings(struct net_device *dev, struct ethtool_cmd *ecmd) sky2->speed = -1; } else { u32 setting; + u32 speed = ethtool_cmd_speed(ecmd); - switch (ecmd->speed) { + switch (speed) { case SPEED_1000: if (ecmd->duplex == DUPLEX_FULL) setting = SUPPORTED_1000baseT_Full; @@ -3486,7 +3487,7 @@ static int sky2_set_settings(struct net_device *dev, struct ethtool_cmd *ecmd) if ((setting & supported) == 0) return -EINVAL; - sky2->speed = ecmd->speed; + sky2->speed = speed; sky2->duplex = ecmd->duplex; sky2->flags &= ~SKY2_FLAG_AUTO_SPEED; } diff --git a/drivers/net/sungem.c b/drivers/net/sungem.c index 81b6eb8..40a755d 100644 --- a/drivers/net/sungem.c +++ b/drivers/net/sungem.c @@ -1294,7 +1294,7 @@ static void gem_begin_auto_negotiation(struct gem *gp, struct ethtool_cmd *ep) autoneg = 1; } else { autoneg = 0; - speed = ep->speed; + speed = ethtool_cmd_speed(ep); duplex = ep->duplex; } @@ -2686,6 +2686,7 @@ static int gem_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) static int gem_set_settings(struct net_device *dev, struct ethtool_cmd *cmd) { struct gem *gp = netdev_priv(dev); + u32 speed = ethtool_cmd_speed(cmd); /* Verify the settings we care about. */ if (cmd->autoneg != AUTONEG_ENABLE && @@ -2697,9 +2698,9 @@ static int gem_set_settings(struct net_device *dev, struct ethtool_cmd *cmd) return -EINVAL; if (cmd->autoneg == AUTONEG_DISABLE && - ((cmd->speed != SPEED_1000 && - cmd->speed != SPEED_100 && - cmd->speed != SPEED_10) || + ((speed != SPEED_1000 && + speed != SPEED_100 && + speed != SPEED_10) || (cmd->duplex != DUPLEX_HALF && cmd->duplex != DUPLEX_FULL))) return -EINVAL; diff --git a/drivers/net/sunhme.c b/drivers/net/sunhme.c index 80e907d..8f3f028 100644 --- a/drivers/net/sunhme.c +++ b/drivers/net/sunhme.c @@ -1383,7 +1383,7 @@ force_link: if (ep == NULL || ep->autoneg == AUTONEG_ENABLE) { hp->sw_bmcr = BMCR_SPEED100; } else { - if (ep->speed == SPEED_100) + if (ethtool_cmd_speed(ep) == SPEED_100) hp->sw_bmcr = BMCR_SPEED100; else hp->sw_bmcr = 0; @@ -2452,8 +2452,8 @@ static int hme_set_settings(struct net_device *dev, struct ethtool_cmd *cmd) cmd->autoneg != AUTONEG_DISABLE) return -EINVAL; if (cmd->autoneg == AUTONEG_DISABLE && - ((cmd->speed != SPEED_100 && - cmd->speed != SPEED_10) || + ((ethtool_cmd_speed(cmd) != SPEED_100 && + ethtool_cmd_speed(cmd) != SPEED_10) || (cmd->duplex != DUPLEX_HALF && cmd->duplex != DUPLEX_FULL))) return -EINVAL; diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index fa57e3d..004f266 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -10042,6 +10042,7 @@ static int tg3_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) static int tg3_set_settings(struct net_device *dev, struct ethtool_cmd *cmd) { struct tg3 *tp = netdev_priv(dev); + u32 speed = ethtool_cmd_speed(cmd); if (tg3_flag(tp, USE_PHYLIB)) { struct phy_device *phydev; @@ -10091,14 +10092,14 @@ static int tg3_set_settings(struct net_device *dev, struct ethtool_cmd *cmd) cmd->advertising &= mask; } else { if (tp->phy_flags & TG3_PHYFLG_ANY_SERDES) { - if (cmd->speed != SPEED_1000) + if (speed != SPEED_1000) return -EINVAL; if (cmd->duplex != DUPLEX_FULL) return -EINVAL; } else { - if (cmd->speed != SPEED_100 && - cmd->speed != SPEED_10) + if (speed != SPEED_100 && + speed != SPEED_10) return -EINVAL; } } @@ -10113,7 +10114,7 @@ static int tg3_set_settings(struct net_device *dev, struct ethtool_cmd *cmd) tp->link_config.duplex = DUPLEX_INVALID; } else { tp->link_config.advertising = 0; - tp->link_config.speed = cmd->speed; + tp->link_config.speed = speed; tp->link_config.duplex = cmd->duplex; } diff --git a/drivers/net/tulip/de2104x.c b/drivers/net/tulip/de2104x.c index b13c6b0..f8d26bf 100644 --- a/drivers/net/tulip/de2104x.c +++ b/drivers/net/tulip/de2104x.c @@ -1549,10 +1549,11 @@ static int __de_set_settings(struct de_private *de, struct ethtool_cmd *ecmd) { u32 new_media; unsigned int media_lock; + u32 speed = ethtool_cmd_speed(ecmd); - if (ecmd->speed != SPEED_10 && ecmd->speed != 5 && ecmd->speed != 2) + if (speed != SPEED_10 && speed != 5 && speed != 2) return -EINVAL; - if (de->de21040 && ecmd->speed == 2) + if (de->de21040 && speed == 2) return -EINVAL; if (ecmd->duplex != DUPLEX_HALF && ecmd->duplex != DUPLEX_FULL) return -EINVAL; diff --git a/drivers/net/typhoon.c b/drivers/net/typhoon.c index 119c394..9f11c11 100644 --- a/drivers/net/typhoon.c +++ b/drivers/net/typhoon.c @@ -1068,25 +1068,26 @@ static int typhoon_set_settings(struct net_device *dev, struct ethtool_cmd *cmd) { struct typhoon *tp = netdev_priv(dev); + u32 speed = ethtool_cmd_speed(cmd); struct cmd_desc xp_cmd; __le16 xcvr; int err; err = -EINVAL; - if(cmd->autoneg == AUTONEG_ENABLE) { + if (cmd->autoneg == AUTONEG_ENABLE) { xcvr = TYPHOON_XCVR_AUTONEG; } else { - if(cmd->duplex == DUPLEX_HALF) { - if(cmd->speed == SPEED_10) + if (cmd->duplex == DUPLEX_HALF) { + if (speed == SPEED_10) xcvr = TYPHOON_XCVR_10HALF; - else if(cmd->speed == SPEED_100) + else if (speed == SPEED_100) xcvr = TYPHOON_XCVR_100HALF; else goto out; - } else if(cmd->duplex == DUPLEX_FULL) { - if(cmd->speed == SPEED_10) + } else if (cmd->duplex == DUPLEX_FULL) { + if (speed == SPEED_10) xcvr = TYPHOON_XCVR_10FULL; - else if(cmd->speed == SPEED_100) + else if (speed == SPEED_100) xcvr = TYPHOON_XCVR_100FULL; else goto out; @@ -1105,7 +1106,7 @@ typhoon_set_settings(struct net_device *dev, struct ethtool_cmd *cmd) tp->speed = 0xff; /* invalid */ tp->duplex = 0xff; /* invalid */ } else { - tp->speed = cmd->speed; + tp->speed = speed; tp->duplex = cmd->duplex; } diff --git a/drivers/net/via-velocity.c b/drivers/net/via-velocity.c index baf04b0..9a8f116 100644 --- a/drivers/net/via-velocity.c +++ b/drivers/net/via-velocity.c @@ -3247,9 +3247,11 @@ static int velocity_get_settings(struct net_device *dev, struct ethtool_cmd *cmd return 0; } -static int velocity_set_settings(struct net_device *dev, struct ethtool_cmd *cmd) +static int velocity_set_settings(struct net_device *dev, + struct ethtool_cmd *cmd) { struct velocity_info *vptr = netdev_priv(dev); + u32 speed = ethtool_cmd_speed(cmd); u32 curr_status; u32 new_status = 0; int ret = 0; @@ -3258,9 +3260,9 @@ static int velocity_set_settings(struct net_device *dev, struct ethtool_cmd *cmd curr_status &= (~VELOCITY_LINK_FAIL); new_status |= ((cmd->autoneg) ? VELOCITY_AUTONEG_ENABLE : 0); - new_status |= ((cmd->speed == SPEED_1000) ? VELOCITY_SPEED_1000 : 0); - new_status |= ((cmd->speed == SPEED_100) ? VELOCITY_SPEED_100 : 0); - new_status |= ((cmd->speed == SPEED_10) ? VELOCITY_SPEED_10 : 0); + new_status |= ((speed == SPEED_1000) ? VELOCITY_SPEED_1000 : 0); + new_status |= ((speed == SPEED_100) ? VELOCITY_SPEED_100 : 0); + new_status |= ((speed == SPEED_10) ? VELOCITY_SPEED_10 : 0); new_status |= ((cmd->duplex == DUPLEX_FULL) ? VELOCITY_DUPLEX_FULL : 0); if ((new_status & VELOCITY_AUTONEG_ENABLE) && diff --git a/drivers/net/vxge/vxge-ethtool.c b/drivers/net/vxge/vxge-ethtool.c index 5aef6c8..a70874e 100644 --- a/drivers/net/vxge/vxge-ethtool.c +++ b/drivers/net/vxge/vxge-ethtool.c @@ -33,7 +33,8 @@ static int vxge_ethtool_sset(struct net_device *dev, struct ethtool_cmd *info) { /* We currently only support 10Gb/FULL */ if ((info->autoneg == AUTONEG_ENABLE) || - (info->speed != SPEED_10000) || (info->duplex != DUPLEX_FULL)) + (ethtool_cmd_speed(info) != SPEED_10000) || + (info->duplex != DUPLEX_FULL)) return -EINVAL; return 0; diff --git a/net/bridge/br_if.c b/net/bridge/br_if.c index 1156460..5dbdfdf 100644 --- a/net/bridge/br_if.c +++ b/net/bridge/br_if.c @@ -36,8 +36,8 @@ static int port_cost(struct net_device *dev) if (dev->ethtool_ops && dev->ethtool_ops->get_settings) { struct ethtool_cmd ecmd = { .cmd = ETHTOOL_GSET, }; - if (!dev->ethtool_ops->get_settings(dev, &ecmd)) { - switch(ecmd.speed) { + if (!dev_ethtool_get_settings(dev, &ecmd)) { + switch (ethtool_cmd_speed(&ecmd)) { case SPEED_10000: return 2; case SPEED_1000: -- cgit v0.10.2 From 707394972093e2056e1e8cc39be19cf9bcb3e7b3 Mon Sep 17 00:00:00 2001 From: David Decotigny Date: Wed, 27 Apr 2011 18:32:40 +0000 Subject: ethtool: cosmetic: Use ethtool ethtool_cmd_speed API This updates the network drivers so that they don't access the ethtool_cmd::speed field directly, but use ethtool_cmd_speed() instead. For most of the drivers, these changes are purely cosmetic and don't fix any problem, such as for those 1GbE/10GbE drivers that indirectly call their own ethtool get_settings()/mii_ethtool_gset(). The changes are meant to enforce code consistency and provide robustness with future larger throughputs, at the expense of a few CPU cycles for each ethtool operation. All drivers compiled with make allyesconfig ion x86_64 have been updated. Tested: make allyesconfig on x86_64 + e1000e/bnx2x work Signed-off-by: David Decotigny Signed-off-by: David S. Miller diff --git a/drivers/infiniband/hw/nes/nes_nic.c b/drivers/infiniband/hw/nes/nes_nic.c index d2e67c4..d3a1c41 100644 --- a/drivers/infiniband/hw/nes/nes_nic.c +++ b/drivers/infiniband/hw/nes/nes_nic.c @@ -1493,7 +1493,7 @@ static int nes_netdev_get_settings(struct net_device *netdev, struct ethtool_cmd et_cmd->maxrxpkt = 511; if (nesadapter->OneG_Mode) { - et_cmd->speed = SPEED_1000; + ethtool_cmd_speed_set(et_cmd, SPEED_1000); if (phy_type == NES_PHY_TYPE_PUMA_1G) { et_cmd->supported = SUPPORTED_1000baseT_Full; et_cmd->advertising = ADVERTISED_1000baseT_Full; @@ -1532,7 +1532,7 @@ static int nes_netdev_get_settings(struct net_device *netdev, struct ethtool_cmd et_cmd->advertising = ADVERTISED_10000baseT_Full; et_cmd->phy_address = mac_index; } - et_cmd->speed = SPEED_10000; + ethtool_cmd_speed_set(et_cmd, SPEED_10000); et_cmd->autoneg = AUTONEG_DISABLE; return 0; } diff --git a/drivers/net/3c509.c b/drivers/net/3c509.c index cb39ded..5f25889 100644 --- a/drivers/net/3c509.c +++ b/drivers/net/3c509.c @@ -1207,7 +1207,7 @@ el3_netdev_get_ecmd(struct net_device *dev, struct ethtool_cmd *ecmd) ecmd->duplex = DUPLEX_FULL; } - ecmd->speed = SPEED_10; + ethtool_cmd_speed_set(ecmd, SPEED_10); EL3WINDOW(1); return 0; } diff --git a/drivers/net/acenic.c b/drivers/net/acenic.c index 0b4d8d1..a579899 100644 --- a/drivers/net/acenic.c +++ b/drivers/net/acenic.c @@ -2658,15 +2658,15 @@ static int ace_get_settings(struct net_device *dev, struct ethtool_cmd *ecmd) link = readl(®s->GigLnkState); if (link & LNK_1000MB) - ecmd->speed = SPEED_1000; + ethtool_cmd_speed_set(ecmd, SPEED_1000); else { link = readl(®s->FastLnkState); if (link & LNK_100MB) - ecmd->speed = SPEED_100; + ethtool_cmd_speed_set(ecmd, SPEED_100); else if (link & LNK_10MB) - ecmd->speed = SPEED_10; + ethtool_cmd_speed_set(ecmd, SPEED_10); else - ecmd->speed = 0; + ethtool_cmd_speed_set(ecmd, 0); } if (link & LNK_FULL_DUPLEX) ecmd->duplex = DUPLEX_FULL; diff --git a/drivers/net/arm/etherh.c b/drivers/net/arm/etherh.c index 4af235d..e252cd5 100644 --- a/drivers/net/arm/etherh.c +++ b/drivers/net/arm/etherh.c @@ -591,10 +591,11 @@ static void etherh_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *i static int etherh_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) { cmd->supported = etherh_priv(dev)->supported; - cmd->speed = SPEED_10; + ethtool_cmd_speed_set(cmd, SPEED_10); cmd->duplex = DUPLEX_HALF; cmd->port = dev->if_port == IF_PORT_10BASET ? PORT_TP : PORT_BNC; - cmd->autoneg = dev->flags & IFF_AUTOMEDIA ? AUTONEG_ENABLE : AUTONEG_DISABLE; + cmd->autoneg = (dev->flags & IFF_AUTOMEDIA ? + AUTONEG_ENABLE : AUTONEG_DISABLE); return 0; } diff --git a/drivers/net/arm/ks8695net.c b/drivers/net/arm/ks8695net.c index aa07657..a7b0caa 100644 --- a/drivers/net/arm/ks8695net.c +++ b/drivers/net/arm/ks8695net.c @@ -891,15 +891,16 @@ ks8695_wan_get_settings(struct net_device *ndev, struct ethtool_cmd *cmd) cmd->advertising |= ADVERTISED_Pause; cmd->autoneg = AUTONEG_ENABLE; - cmd->speed = (ctrl & WMC_WSS) ? SPEED_100 : SPEED_10; + ethtool_cmd_speed_set(cmd, + (ctrl & WMC_WSS) ? SPEED_100 : SPEED_10); cmd->duplex = (ctrl & WMC_WDS) ? DUPLEX_FULL : DUPLEX_HALF; } else { /* auto-negotiation is disabled */ cmd->autoneg = AUTONEG_DISABLE; - cmd->speed = (ctrl & WMC_WANF100) ? - SPEED_100 : SPEED_10; + ethtool_cmd_speed_set(cmd, ((ctrl & WMC_WANF100) ? + SPEED_100 : SPEED_10)); cmd->duplex = (ctrl & WMC_WANFF) ? DUPLEX_FULL : DUPLEX_HALF; } diff --git a/drivers/net/atl1c/atl1c_ethtool.c b/drivers/net/atl1c/atl1c_ethtool.c index b1eceee..7be884d 100644 --- a/drivers/net/atl1c/atl1c_ethtool.c +++ b/drivers/net/atl1c/atl1c_ethtool.c @@ -50,13 +50,13 @@ static int atl1c_get_settings(struct net_device *netdev, ecmd->transceiver = XCVR_INTERNAL; if (adapter->link_speed != SPEED_0) { - ecmd->speed = adapter->link_speed; + ethtool_cmd_speed_set(ecmd, adapter->link_speed); if (adapter->link_duplex == FULL_DUPLEX) ecmd->duplex = DUPLEX_FULL; else ecmd->duplex = DUPLEX_HALF; } else { - ecmd->speed = -1; + ethtool_cmd_speed_set(ecmd, -1); ecmd->duplex = -1; } diff --git a/drivers/net/atl1e/atl1e_ethtool.c b/drivers/net/atl1e/atl1e_ethtool.c index 4778374..6269438 100644 --- a/drivers/net/atl1e/atl1e_ethtool.c +++ b/drivers/net/atl1e/atl1e_ethtool.c @@ -51,13 +51,13 @@ static int atl1e_get_settings(struct net_device *netdev, ecmd->transceiver = XCVR_INTERNAL; if (adapter->link_speed != SPEED_0) { - ecmd->speed = adapter->link_speed; + ethtool_cmd_speed_set(ecmd, adapter->link_speed); if (adapter->link_duplex == FULL_DUPLEX) ecmd->duplex = DUPLEX_FULL; else ecmd->duplex = DUPLEX_HALF; } else { - ecmd->speed = -1; + ethtool_cmd_speed_set(ecmd, -1); ecmd->duplex = -1; } diff --git a/drivers/net/atlx/atl1.c b/drivers/net/atlx/atl1.c index 37a092f..c5298d1 100644 --- a/drivers/net/atlx/atl1.c +++ b/drivers/net/atlx/atl1.c @@ -3231,13 +3231,13 @@ static int atl1_get_settings(struct net_device *netdev, if (netif_carrier_ok(adapter->netdev)) { u16 link_speed, link_duplex; atl1_get_speed_and_duplex(hw, &link_speed, &link_duplex); - ecmd->speed = link_speed; + ethtool_cmd_speed_set(ecmd, link_speed); if (link_duplex == FULL_DUPLEX) ecmd->duplex = DUPLEX_FULL; else ecmd->duplex = DUPLEX_HALF; } else { - ecmd->speed = -1; + ethtool_cmd_speed_set(ecmd, -1); ecmd->duplex = -1; } if (hw->media_type == MEDIA_TYPE_AUTO_SENSOR || diff --git a/drivers/net/atlx/atl2.c b/drivers/net/atlx/atl2.c index b75aa29..16249e9 100644 --- a/drivers/net/atlx/atl2.c +++ b/drivers/net/atlx/atl2.c @@ -1769,13 +1769,13 @@ static int atl2_get_settings(struct net_device *netdev, ecmd->transceiver = XCVR_INTERNAL; if (adapter->link_speed != SPEED_0) { - ecmd->speed = adapter->link_speed; + ethtool_cmd_speed_set(ecmd, adapter->link_speed); if (adapter->link_duplex == FULL_DUPLEX) ecmd->duplex = DUPLEX_FULL; else ecmd->duplex = DUPLEX_HALF; } else { - ecmd->speed = -1; + ethtool_cmd_speed_set(ecmd, -1); ecmd->duplex = -1; } diff --git a/drivers/net/b44.c b/drivers/net/b44.c index 909cc4b..a69331e 100644 --- a/drivers/net/b44.c +++ b/drivers/net/b44.c @@ -1807,8 +1807,8 @@ static int b44_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) if (bp->flags & B44_FLAG_ADV_100FULL) cmd->advertising |= ADVERTISED_100baseT_Full; cmd->advertising |= ADVERTISED_Pause | ADVERTISED_Asym_Pause; - cmd->speed = (bp->flags & B44_FLAG_100_BASE_T) ? - SPEED_100 : SPEED_10; + ethtool_cmd_speed_set(cmd, ((bp->flags & B44_FLAG_100_BASE_T) ? + SPEED_100 : SPEED_10)); cmd->duplex = (bp->flags & B44_FLAG_FULL_DUPLEX) ? DUPLEX_FULL : DUPLEX_HALF; cmd->port = 0; @@ -1820,7 +1820,7 @@ static int b44_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) if (cmd->autoneg == AUTONEG_ENABLE) cmd->advertising |= ADVERTISED_Autoneg; if (!netif_running(dev)){ - cmd->speed = 0; + ethtool_cmd_speed_set(cmd, 0); cmd->duplex = 0xff; } cmd->maxtxpkt = 0; diff --git a/drivers/net/bcm63xx_enet.c b/drivers/net/bcm63xx_enet.c index e68ffe6..f1573d4 100644 --- a/drivers/net/bcm63xx_enet.c +++ b/drivers/net/bcm63xx_enet.c @@ -1346,7 +1346,8 @@ static int bcm_enet_get_settings(struct net_device *dev, return phy_ethtool_gset(priv->phydev, cmd); } else { cmd->autoneg = 0; - cmd->speed = (priv->force_speed_100) ? SPEED_100 : SPEED_10; + ethtool_cmd_speed_set(cmd, ((priv->force_speed_100) + ? SPEED_100 : SPEED_10)); cmd->duplex = (priv->force_duplex_full) ? DUPLEX_FULL : DUPLEX_HALF; cmd->supported = ADVERTISED_10baseT_Half | diff --git a/drivers/net/benet/be_ethtool.c b/drivers/net/benet/be_ethtool.c index 6565f3e..8e770e8 100644 --- a/drivers/net/benet/be_ethtool.c +++ b/drivers/net/benet/be_ethtool.c @@ -381,23 +381,23 @@ static int be_get_settings(struct net_device *netdev, struct ethtool_cmd *ecmd) be_link_status_update(adapter, link_up); /* link_speed is in units of 10 Mbps */ if (link_speed) { - ecmd->speed = link_speed*10; + ethtool_cmd_speed_set(ecmd, link_speed*10); } else { switch (mac_speed) { case PHY_LINK_SPEED_10MBPS: - ecmd->speed = SPEED_10; + ethtool_cmd_speed_set(ecmd, SPEED_10); break; case PHY_LINK_SPEED_100MBPS: - ecmd->speed = SPEED_100; + ethtool_cmd_speed_set(ecmd, SPEED_100); break; case PHY_LINK_SPEED_1GBPS: - ecmd->speed = SPEED_1000; + ethtool_cmd_speed_set(ecmd, SPEED_1000); break; case PHY_LINK_SPEED_10GBPS: - ecmd->speed = SPEED_10000; + ethtool_cmd_speed_set(ecmd, SPEED_10000); break; case PHY_LINK_SPEED_ZERO: - ecmd->speed = 0; + ethtool_cmd_speed_set(ecmd, 0); break; } } @@ -440,14 +440,14 @@ static int be_get_settings(struct net_device *netdev, struct ethtool_cmd *ecmd) } /* Save for future use */ - adapter->link_speed = ecmd->speed; + adapter->link_speed = ethtool_cmd_speed(ecmd); adapter->port_type = ecmd->port; adapter->transceiver = ecmd->transceiver; adapter->autoneg = ecmd->autoneg; dma_free_coherent(&adapter->pdev->dev, phy_cmd.size, phy_cmd.va, phy_cmd.dma); } else { - ecmd->speed = adapter->link_speed; + ethtool_cmd_speed_set(ecmd, adapter->link_speed); ecmd->port = adapter->port_type; ecmd->transceiver = adapter->transceiver; ecmd->autoneg = adapter->autoneg; diff --git a/drivers/net/bna/bnad_ethtool.c b/drivers/net/bna/bnad_ethtool.c index ae1e118..3330cd78 100644 --- a/drivers/net/bna/bnad_ethtool.c +++ b/drivers/net/bna/bnad_ethtool.c @@ -237,10 +237,10 @@ bnad_get_settings(struct net_device *netdev, struct ethtool_cmd *cmd) cmd->phy_address = 0; if (netif_carrier_ok(netdev)) { - cmd->speed = SPEED_10000; + ethtool_cmd_speed_set(cmd, SPEED_10000); cmd->duplex = DUPLEX_FULL; } else { - cmd->speed = -1; + ethtool_cmd_speed_set(cmd, -1); cmd->duplex = -1; } cmd->transceiver = XCVR_EXTERNAL; diff --git a/drivers/net/bnx2.c b/drivers/net/bnx2.c index e43efd8..1bebdfb 100644 --- a/drivers/net/bnx2.c +++ b/drivers/net/bnx2.c @@ -6696,17 +6696,16 @@ bnx2_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) if (bp->autoneg & AUTONEG_SPEED) { cmd->autoneg = AUTONEG_ENABLE; - } - else { + } else { cmd->autoneg = AUTONEG_DISABLE; } if (netif_carrier_ok(dev)) { - cmd->speed = bp->line_speed; + ethtool_cmd_speed_set(cmd, bp->line_speed); cmd->duplex = bp->duplex; } else { - cmd->speed = -1; + ethtool_cmd_speed_set(cmd, -1); cmd->duplex = -1; } spin_unlock_bh(&bp->phy_lock); diff --git a/drivers/net/cassini.c b/drivers/net/cassini.c index a6c3f8c..22ce03e 100644 --- a/drivers/net/cassini.c +++ b/drivers/net/cassini.c @@ -4606,18 +4606,17 @@ static int cas_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) if (bmcr & BMCR_ANENABLE) { cmd->advertising |= ADVERTISED_Autoneg; cmd->autoneg = AUTONEG_ENABLE; - cmd->speed = ((speed == 10) ? - SPEED_10 : - ((speed == 1000) ? - SPEED_1000 : SPEED_100)); + ethtool_cmd_speed_set(cmd, ((speed == 10) ? + SPEED_10 : + ((speed == 1000) ? + SPEED_1000 : SPEED_100))); cmd->duplex = full_duplex ? DUPLEX_FULL : DUPLEX_HALF; } else { cmd->autoneg = AUTONEG_DISABLE; - cmd->speed = - (bmcr & CAS_BMCR_SPEED1000) ? - SPEED_1000 : - ((bmcr & BMCR_SPEED100) ? SPEED_100: - SPEED_10); + ethtool_cmd_speed_set(cmd, ((bmcr & CAS_BMCR_SPEED1000) ? + SPEED_1000 : + ((bmcr & BMCR_SPEED100) ? + SPEED_100 : SPEED_10))); cmd->duplex = (bmcr & BMCR_FULLDPLX) ? DUPLEX_FULL : DUPLEX_HALF; @@ -4634,14 +4633,14 @@ static int cas_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) * settings that we configured. */ if (cp->link_cntl & BMCR_ANENABLE) { - cmd->speed = 0; + ethtool_cmd_speed_set(cmd, 0); cmd->duplex = 0xff; } else { - cmd->speed = SPEED_10; + ethtool_cmd_speed_set(cmd, SPEED_10); if (cp->link_cntl & BMCR_SPEED100) { - cmd->speed = SPEED_100; + ethtool_cmd_speed_set(cmd, SPEED_100); } else if (cp->link_cntl & CAS_BMCR_SPEED1000) { - cmd->speed = SPEED_1000; + ethtool_cmd_speed_set(cmd, SPEED_1000); } cmd->duplex = (cp->link_cntl & BMCR_FULLDPLX)? DUPLEX_FULL : DUPLEX_HALF; diff --git a/drivers/net/chelsio/cxgb2.c b/drivers/net/chelsio/cxgb2.c index 8e14d65..b422d83 100644 --- a/drivers/net/chelsio/cxgb2.c +++ b/drivers/net/chelsio/cxgb2.c @@ -577,10 +577,10 @@ static int get_settings(struct net_device *dev, struct ethtool_cmd *cmd) cmd->advertising = p->link_config.advertising; if (netif_carrier_ok(dev)) { - cmd->speed = p->link_config.speed; + ethtool_cmd_speed_set(cmd, p->link_config.speed); cmd->duplex = p->link_config.duplex; } else { - cmd->speed = -1; + ethtool_cmd_speed_set(cmd, -1); cmd->duplex = -1; } diff --git a/drivers/net/cxgb3/cxgb3_main.c b/drivers/net/cxgb3/cxgb3_main.c index 0526715..9081ce0 100644 --- a/drivers/net/cxgb3/cxgb3_main.c +++ b/drivers/net/cxgb3/cxgb3_main.c @@ -1759,10 +1759,10 @@ static int get_settings(struct net_device *dev, struct ethtool_cmd *cmd) cmd->advertising = p->link_config.advertising; if (netif_carrier_ok(dev)) { - cmd->speed = p->link_config.speed; + ethtool_cmd_speed_set(cmd, p->link_config.speed); cmd->duplex = p->link_config.duplex; } else { - cmd->speed = -1; + ethtool_cmd_speed_set(cmd, -1); cmd->duplex = -1; } diff --git a/drivers/net/cxgb4/cxgb4_main.c b/drivers/net/cxgb4/cxgb4_main.c index c02b4d3..7e3cfbe 100644 --- a/drivers/net/cxgb4/cxgb4_main.c +++ b/drivers/net/cxgb4/cxgb4_main.c @@ -1436,7 +1436,8 @@ static int get_settings(struct net_device *dev, struct ethtool_cmd *cmd) cmd->supported = from_fw_linkcaps(p->port_type, p->link_cfg.supported); cmd->advertising = from_fw_linkcaps(p->port_type, p->link_cfg.advertising); - cmd->speed = netif_carrier_ok(dev) ? p->link_cfg.speed : 0; + ethtool_cmd_speed_set(cmd, + netif_carrier_ok(dev) ? p->link_cfg.speed : 0); cmd->duplex = DUPLEX_FULL; cmd->autoneg = p->link_cfg.autoneg; cmd->maxtxpkt = 0; diff --git a/drivers/net/cxgb4vf/cxgb4vf_main.c b/drivers/net/cxgb4vf/cxgb4vf_main.c index 8cf9890..e71c08e 100644 --- a/drivers/net/cxgb4vf/cxgb4vf_main.c +++ b/drivers/net/cxgb4vf/cxgb4vf_main.c @@ -1167,7 +1167,8 @@ static int cxgb4vf_get_settings(struct net_device *dev, cmd->supported = pi->link_cfg.supported; cmd->advertising = pi->link_cfg.advertising; - cmd->speed = netif_carrier_ok(dev) ? pi->link_cfg.speed : -1; + ethtool_cmd_speed_set(cmd, + netif_carrier_ok(dev) ? pi->link_cfg.speed : -1); cmd->duplex = DUPLEX_FULL; cmd->port = (cmd->supported & SUPPORTED_TP) ? PORT_TP : PORT_FIBRE; diff --git a/drivers/net/dl2k.c b/drivers/net/dl2k.c index ab63989..c445457 100644 --- a/drivers/net/dl2k.c +++ b/drivers/net/dl2k.c @@ -1189,10 +1189,10 @@ static int rio_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) cmd->transceiver = XCVR_INTERNAL; } if ( np->link_status ) { - cmd->speed = np->speed; + ethtool_cmd_speed_set(cmd, np->speed); cmd->duplex = np->full_duplex ? DUPLEX_FULL : DUPLEX_HALF; } else { - cmd->speed = -1; + ethtool_cmd_speed_set(cmd, -1); cmd->duplex = -1; } if ( np->an_enable) diff --git a/drivers/net/e1000/e1000_ethtool.c b/drivers/net/e1000/e1000_ethtool.c index a53629d..127fef4 100644 --- a/drivers/net/e1000/e1000_ethtool.c +++ b/drivers/net/e1000/e1000_ethtool.c @@ -158,7 +158,7 @@ static int e1000_get_settings(struct net_device *netdev, e1000_get_speed_and_duplex(hw, &adapter->link_speed, &adapter->link_duplex); - ecmd->speed = adapter->link_speed; + ethtool_cmd_speed_set(ecmd, adapter->link_speed); /* unfortunately FULL_DUPLEX != DUPLEX_FULL * and HALF_DUPLEX != DUPLEX_HALF */ @@ -168,7 +168,7 @@ static int e1000_get_settings(struct net_device *netdev, else ecmd->duplex = DUPLEX_HALF; } else { - ecmd->speed = -1; + ethtool_cmd_speed_set(ecmd, -1); ecmd->duplex = -1; } diff --git a/drivers/net/e1000e/ethtool.c b/drivers/net/e1000e/ethtool.c index bc02c6b..12f1ee2 100644 --- a/drivers/net/e1000e/ethtool.c +++ b/drivers/net/e1000e/ethtool.c @@ -122,6 +122,7 @@ static int e1000_get_settings(struct net_device *netdev, { struct e1000_adapter *adapter = netdev_priv(netdev); struct e1000_hw *hw = &adapter->hw; + u32 speed; if (hw->phy.media_type == e1000_media_type_copper) { @@ -159,23 +160,23 @@ static int e1000_get_settings(struct net_device *netdev, ecmd->transceiver = XCVR_EXTERNAL; } - ecmd->speed = -1; + speed = -1; ecmd->duplex = -1; if (netif_running(netdev)) { if (netif_carrier_ok(netdev)) { - ecmd->speed = adapter->link_speed; + speed = adapter->link_speed; ecmd->duplex = adapter->link_duplex - 1; } } else { u32 status = er32(STATUS); if (status & E1000_STATUS_LU) { if (status & E1000_STATUS_SPEED_1000) - ecmd->speed = 1000; + speed = SPEED_1000; else if (status & E1000_STATUS_SPEED_100) - ecmd->speed = 100; + speed = SPEED_100; else - ecmd->speed = 10; + speed = SPEED_10; if (status & E1000_STATUS_FD) ecmd->duplex = DUPLEX_FULL; @@ -184,6 +185,7 @@ static int e1000_get_settings(struct net_device *netdev, } } + ethtool_cmd_speed_set(ecmd, speed); ecmd->autoneg = ((hw->phy.media_type == e1000_media_type_fiber) || hw->mac.autoneg) ? AUTONEG_ENABLE : AUTONEG_DISABLE; diff --git a/drivers/net/eepro.c b/drivers/net/eepro.c index eb35951..dfeb006 100644 --- a/drivers/net/eepro.c +++ b/drivers/net/eepro.c @@ -1703,7 +1703,7 @@ static int eepro_ethtool_get_settings(struct net_device *dev, cmd->advertising |= ADVERTISED_AUI; } - cmd->speed = SPEED_10; + ethtool_cmd_speed_set(cmd, SPEED_10); if (dev->if_port == TPE && lp->word[1] & ee_Duplex) { cmd->duplex = DUPLEX_FULL; diff --git a/drivers/net/ehea/ehea_ethtool.c b/drivers/net/ehea/ehea_ethtool.c index 5f13491..1df5f40 100644 --- a/drivers/net/ehea/ehea_ethtool.c +++ b/drivers/net/ehea/ehea_ethtool.c @@ -34,6 +34,7 @@ static int ehea_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) { struct ehea_port *port = netdev_priv(dev); + u32 speed; int ret; ret = ehea_sense_port_attr(port); @@ -43,17 +44,29 @@ static int ehea_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) if (netif_carrier_ok(dev)) { switch (port->port_speed) { - case EHEA_SPEED_10M: cmd->speed = SPEED_10; break; - case EHEA_SPEED_100M: cmd->speed = SPEED_100; break; - case EHEA_SPEED_1G: cmd->speed = SPEED_1000; break; - case EHEA_SPEED_10G: cmd->speed = SPEED_10000; break; + case EHEA_SPEED_10M: + speed = SPEED_10; + break; + case EHEA_SPEED_100M: + speed = SPEED_100; + break; + case EHEA_SPEED_1G: + speed = SPEED_1000; + break; + case EHEA_SPEED_10G: + speed = SPEED_10000; + break; + default: + speed = -1; + break; /* BUG */ } cmd->duplex = port->full_duplex == 1 ? DUPLEX_FULL : DUPLEX_HALF; } else { - cmd->speed = -1; + speed = ~0; cmd->duplex = -1; } + ethtool_cmd_speed_set(cmd, speed); cmd->supported = (SUPPORTED_10000baseT_Full | SUPPORTED_1000baseT_Full | SUPPORTED_100baseT_Full | SUPPORTED_100baseT_Half diff --git a/drivers/net/enc28j60.c b/drivers/net/enc28j60.c index 81a7937..2837ce2 100644 --- a/drivers/net/enc28j60.c +++ b/drivers/net/enc28j60.c @@ -1488,7 +1488,7 @@ enc28j60_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) cmd->supported = SUPPORTED_10baseT_Half | SUPPORTED_10baseT_Full | SUPPORTED_TP; - cmd->speed = SPEED_10; + ethtool_cmd_speed_set(cmd, SPEED_10); cmd->duplex = priv->full_duplex ? DUPLEX_FULL : DUPLEX_HALF; cmd->port = PORT_TP; cmd->autoneg = AUTONEG_DISABLE; diff --git a/drivers/net/enic/enic_main.c b/drivers/net/enic/enic_main.c index b224551..3d99b0f 100644 --- a/drivers/net/enic/enic_main.c +++ b/drivers/net/enic/enic_main.c @@ -180,10 +180,10 @@ static int enic_get_settings(struct net_device *netdev, ecmd->transceiver = XCVR_EXTERNAL; if (netif_carrier_ok(netdev)) { - ecmd->speed = vnic_dev_port_speed(enic->vdev); + ethtool_cmd_speed_set(ecmd, vnic_dev_port_speed(enic->vdev)); ecmd->duplex = DUPLEX_FULL; } else { - ecmd->speed = -1; + ethtool_cmd_speed_set(ecmd, -1); ecmd->duplex = -1; } diff --git a/drivers/net/ewrk3.c b/drivers/net/ewrk3.c index 17b6027..b5f6173 100644 --- a/drivers/net/ewrk3.c +++ b/drivers/net/ewrk3.c @@ -1545,7 +1545,7 @@ static int ewrk3_get_settings(struct net_device *dev, struct ethtool_cmd *ecmd) } ecmd->supported |= SUPPORTED_10baseT_Half; - ecmd->speed = SPEED_10; + ethtool_cmd_speed_set(ecmd, SPEED_10); ecmd->duplex = DUPLEX_HALF; return 0; } diff --git a/drivers/net/forcedeth.c b/drivers/net/forcedeth.c index d24b3f3..d09e8b0 100644 --- a/drivers/net/forcedeth.c +++ b/drivers/net/forcedeth.c @@ -3955,6 +3955,7 @@ static int nv_set_wol(struct net_device *dev, struct ethtool_wolinfo *wolinfo) static int nv_get_settings(struct net_device *dev, struct ethtool_cmd *ecmd) { struct fe_priv *np = netdev_priv(dev); + u32 speed; int adv; spin_lock_irq(&np->lock); @@ -3974,23 +3975,26 @@ static int nv_get_settings(struct net_device *dev, struct ethtool_cmd *ecmd) if (netif_carrier_ok(dev)) { switch (np->linkspeed & (NVREG_LINKSPEED_MASK)) { case NVREG_LINKSPEED_10: - ecmd->speed = SPEED_10; + speed = SPEED_10; break; case NVREG_LINKSPEED_100: - ecmd->speed = SPEED_100; + speed = SPEED_100; break; case NVREG_LINKSPEED_1000: - ecmd->speed = SPEED_1000; + speed = SPEED_1000; + break; + default: + speed = -1; break; } ecmd->duplex = DUPLEX_HALF; if (np->duplex) ecmd->duplex = DUPLEX_FULL; } else { - ecmd->speed = -1; + speed = -1; ecmd->duplex = -1; } - + ethtool_cmd_speed_set(ecmd, speed); ecmd->autoneg = np->autoneg; ecmd->advertising = ADVERTISED_MII; diff --git a/drivers/net/ibmveth.c b/drivers/net/ibmveth.c index be3fe71..b388d78 100644 --- a/drivers/net/ibmveth.c +++ b/drivers/net/ibmveth.c @@ -710,7 +710,7 @@ static int netdev_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) SUPPORTED_FIBRE); cmd->advertising = (ADVERTISED_1000baseT_Full | ADVERTISED_Autoneg | ADVERTISED_FIBRE); - cmd->speed = SPEED_1000; + ethtool_cmd_speed_set(cmd, SPEED_1000); cmd->duplex = DUPLEX_FULL; cmd->port = PORT_FIBRE; cmd->phy_address = 0; diff --git a/drivers/net/igb/igb_ethtool.c b/drivers/net/igb/igb_ethtool.c index 2cc221b..023aa9b 100644 --- a/drivers/net/igb/igb_ethtool.c +++ b/drivers/net/igb/igb_ethtool.c @@ -178,11 +178,11 @@ static int igb_get_settings(struct net_device *netdev, struct ethtool_cmd *ecmd) if ((status & E1000_STATUS_SPEED_1000) || hw->phy.media_type != e1000_media_type_copper) - ecmd->speed = SPEED_1000; + ethtool_cmd_speed_set(ecmd, SPEED_1000); else if (status & E1000_STATUS_SPEED_100) - ecmd->speed = SPEED_100; + ethtool_cmd_speed_set(ecmd, SPEED_100); else - ecmd->speed = SPEED_10; + ethtool_cmd_speed_set(ecmd, SPEED_10); if ((status & E1000_STATUS_FD) || hw->phy.media_type != e1000_media_type_copper) @@ -190,7 +190,7 @@ static int igb_get_settings(struct net_device *netdev, struct ethtool_cmd *ecmd) else ecmd->duplex = DUPLEX_HALF; } else { - ecmd->speed = -1; + ethtool_cmd_speed_set(ecmd, -1); ecmd->duplex = -1; } diff --git a/drivers/net/igbvf/ethtool.c b/drivers/net/igbvf/ethtool.c index 1d943aa..112ae15b 100644 --- a/drivers/net/igbvf/ethtool.c +++ b/drivers/net/igbvf/ethtool.c @@ -90,18 +90,18 @@ static int igbvf_get_settings(struct net_device *netdev, status = er32(STATUS); if (status & E1000_STATUS_LU) { if (status & E1000_STATUS_SPEED_1000) - ecmd->speed = 1000; + ethtool_cmd_speed_set(ecmd, SPEED_1000); else if (status & E1000_STATUS_SPEED_100) - ecmd->speed = 100; + ethtool_cmd_speed_set(ecmd, SPEED_100); else - ecmd->speed = 10; + ethtool_cmd_speed_set(ecmd, SPEED_10); if (status & E1000_STATUS_FD) ecmd->duplex = DUPLEX_FULL; else ecmd->duplex = DUPLEX_HALF; } else { - ecmd->speed = -1; + ethtool_cmd_speed_set(ecmd, -1); ecmd->duplex = -1; } diff --git a/drivers/net/ixgb/ixgb_ethtool.c b/drivers/net/ixgb/ixgb_ethtool.c index edb3d7e..5f224c3 100644 --- a/drivers/net/ixgb/ixgb_ethtool.c +++ b/drivers/net/ixgb/ixgb_ethtool.c @@ -104,10 +104,10 @@ ixgb_get_settings(struct net_device *netdev, struct ethtool_cmd *ecmd) ecmd->transceiver = XCVR_EXTERNAL; if (netif_carrier_ok(adapter->netdev)) { - ecmd->speed = SPEED_10000; + ethtool_cmd_speed_set(ecmd, SPEED_10000); ecmd->duplex = DUPLEX_FULL; } else { - ecmd->speed = -1; + ethtool_cmd_speed_set(ecmd, -1); ecmd->duplex = -1; } diff --git a/drivers/net/ixgbe/ixgbe_ethtool.c b/drivers/net/ixgbe/ixgbe_ethtool.c index c52243d..bcba057 100644 --- a/drivers/net/ixgbe/ixgbe_ethtool.c +++ b/drivers/net/ixgbe/ixgbe_ethtool.c @@ -288,20 +288,20 @@ static int ixgbe_get_settings(struct net_device *netdev, if (link_up) { switch (link_speed) { case IXGBE_LINK_SPEED_10GB_FULL: - ecmd->speed = SPEED_10000; + ethtool_cmd_speed_set(ecmd, SPEED_10000); break; case IXGBE_LINK_SPEED_1GB_FULL: - ecmd->speed = SPEED_1000; + ethtool_cmd_speed_set(ecmd, SPEED_1000); break; case IXGBE_LINK_SPEED_100_FULL: - ecmd->speed = SPEED_100; + ethtool_cmd_speed_set(ecmd, SPEED_100); break; default: break; } ecmd->duplex = DUPLEX_FULL; } else { - ecmd->speed = -1; + ethtool_cmd_speed_set(ecmd, -1); ecmd->duplex = -1; } diff --git a/drivers/net/ixgbevf/ethtool.c b/drivers/net/ixgbevf/ethtool.c index 0563ab2..deee375 100644 --- a/drivers/net/ixgbevf/ethtool.c +++ b/drivers/net/ixgbevf/ethtool.c @@ -104,11 +104,13 @@ static int ixgbevf_get_settings(struct net_device *netdev, hw->mac.ops.check_link(hw, &link_speed, &link_up, false); if (link_up) { - ecmd->speed = (link_speed == IXGBE_LINK_SPEED_10GB_FULL) ? - SPEED_10000 : SPEED_1000; + ethtool_cmd_speed_set( + ecmd, + (link_speed == IXGBE_LINK_SPEED_10GB_FULL) ? + SPEED_10000 : SPEED_1000); ecmd->duplex = DUPLEX_FULL; } else { - ecmd->speed = -1; + ethtool_cmd_speed_set(ecmd, -1); ecmd->duplex = -1; } diff --git a/drivers/net/mdio.c b/drivers/net/mdio.c index f2d10ab..16fbb11 100644 --- a/drivers/net/mdio.c +++ b/drivers/net/mdio.c @@ -188,6 +188,7 @@ void mdio45_ethtool_gset_npage(const struct mdio_if_info *mdio, u32 npage_adv, u32 npage_lpa) { int reg; + u32 speed; ecmd->transceiver = XCVR_INTERNAL; ecmd->phy_address = mdio->prtad; @@ -290,33 +291,36 @@ void mdio45_ethtool_gset_npage(const struct mdio_if_info *mdio, if (modes & (ADVERTISED_10000baseT_Full | ADVERTISED_10000baseKX4_Full | ADVERTISED_10000baseKR_Full)) { - ecmd->speed = SPEED_10000; + speed = SPEED_10000; ecmd->duplex = DUPLEX_FULL; } else if (modes & (ADVERTISED_1000baseT_Full | ADVERTISED_1000baseT_Half | ADVERTISED_1000baseKX_Full)) { - ecmd->speed = SPEED_1000; + speed = SPEED_1000; ecmd->duplex = !(modes & ADVERTISED_1000baseT_Half); } else if (modes & (ADVERTISED_100baseT_Full | ADVERTISED_100baseT_Half)) { - ecmd->speed = SPEED_100; + speed = SPEED_100; ecmd->duplex = !!(modes & ADVERTISED_100baseT_Full); } else { - ecmd->speed = SPEED_10; + speed = SPEED_10; ecmd->duplex = !!(modes & ADVERTISED_10baseT_Full); } } else { /* Report forced settings */ reg = mdio->mdio_read(mdio->dev, mdio->prtad, MDIO_MMD_PMAPMD, MDIO_CTRL1); - ecmd->speed = (((reg & MDIO_PMA_CTRL1_SPEED1000) ? 100 : 1) * - ((reg & MDIO_PMA_CTRL1_SPEED100) ? 100 : 10)); + speed = (((reg & MDIO_PMA_CTRL1_SPEED1000) ? 100 : 1) + * ((reg & MDIO_PMA_CTRL1_SPEED100) ? 100 : 10)); ecmd->duplex = (reg & MDIO_CTRL1_FULLDPLX || - ecmd->speed == SPEED_10000); + speed == SPEED_10000); } + ethtool_cmd_speed_set(ecmd, speed); + /* 10GBASE-T MDI/MDI-X */ - if (ecmd->port == PORT_TP && ecmd->speed == SPEED_10000) { + if (ecmd->port == PORT_TP + && (ethtool_cmd_speed(ecmd) == SPEED_10000)) { switch (mdio->mdio_read(mdio->dev, mdio->prtad, MDIO_MMD_PMAPMD, MDIO_PMA_10GBT_SWAPPOL)) { case MDIO_PMA_10GBT_SWAPPOL_ABNX | MDIO_PMA_10GBT_SWAPPOL_CDNX: diff --git a/drivers/net/mii.c b/drivers/net/mii.c index e8198ed..4fbc816 100644 --- a/drivers/net/mii.c +++ b/drivers/net/mii.c @@ -121,22 +121,25 @@ int mii_ethtool_gset(struct mii_if_info *mii, struct ethtool_cmd *ecmd) if (nego & (ADVERTISED_1000baseT_Full | ADVERTISED_1000baseT_Half)) { - ecmd->speed = SPEED_1000; + ethtool_cmd_speed_set(ecmd, SPEED_1000); ecmd->duplex = !!(nego & ADVERTISED_1000baseT_Full); } else if (nego & (ADVERTISED_100baseT_Full | ADVERTISED_100baseT_Half)) { - ecmd->speed = SPEED_100; + ethtool_cmd_speed_set(ecmd, SPEED_100); ecmd->duplex = !!(nego & ADVERTISED_100baseT_Full); } else { - ecmd->speed = SPEED_10; + ethtool_cmd_speed_set(ecmd, SPEED_10); ecmd->duplex = !!(nego & ADVERTISED_10baseT_Full); } } else { ecmd->autoneg = AUTONEG_DISABLE; - ecmd->speed = ((bmcr & BMCR_SPEED1000 && - (bmcr & BMCR_SPEED100) == 0) ? SPEED_1000 : - (bmcr & BMCR_SPEED100) ? SPEED_100 : SPEED_10); + ethtool_cmd_speed_set(ecmd, + ((bmcr & BMCR_SPEED1000 && + (bmcr & BMCR_SPEED100) == 0) ? + SPEED_1000 : + ((bmcr & BMCR_SPEED100) ? + SPEED_100 : SPEED_10))); ecmd->duplex = (bmcr & BMCR_FULLDPLX) ? DUPLEX_FULL : DUPLEX_HALF; } diff --git a/drivers/net/mlx4/en_ethtool.c b/drivers/net/mlx4/en_ethtool.c index be4a9e0..2e858e4 100644 --- a/drivers/net/mlx4/en_ethtool.c +++ b/drivers/net/mlx4/en_ethtool.c @@ -265,10 +265,10 @@ static int mlx4_en_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) trans_type = priv->port_state.transciver; if (netif_carrier_ok(dev)) { - cmd->speed = priv->port_state.link_speed; + ethtool_cmd_speed_set(cmd, priv->port_state.link_speed); cmd->duplex = DUPLEX_FULL; } else { - cmd->speed = -1; + ethtool_cmd_speed_set(cmd, -1); cmd->duplex = -1; } diff --git a/drivers/net/mv643xx_eth.c b/drivers/net/mv643xx_eth.c index 57c2ac0..a5d9b1c 100644 --- a/drivers/net/mv643xx_eth.c +++ b/drivers/net/mv643xx_eth.c @@ -1444,13 +1444,13 @@ mv643xx_eth_get_settings_phyless(struct mv643xx_eth_private *mp, cmd->advertising = ADVERTISED_MII; switch (port_status & PORT_SPEED_MASK) { case PORT_SPEED_10: - cmd->speed = SPEED_10; + ethtool_cmd_speed_set(cmd, SPEED_10); break; case PORT_SPEED_100: - cmd->speed = SPEED_100; + ethtool_cmd_speed_set(cmd, SPEED_100); break; case PORT_SPEED_1000: - cmd->speed = SPEED_1000; + ethtool_cmd_speed_set(cmd, SPEED_1000); break; default: cmd->speed = -1; diff --git a/drivers/net/myri10ge/myri10ge.c b/drivers/net/myri10ge/myri10ge.c index e7f80164..b1358f7 100644 --- a/drivers/net/myri10ge/myri10ge.c +++ b/drivers/net/myri10ge/myri10ge.c @@ -1644,7 +1644,7 @@ myri10ge_get_settings(struct net_device *netdev, struct ethtool_cmd *cmd) int i; cmd->autoneg = AUTONEG_DISABLE; - cmd->speed = SPEED_10000; + ethtool_cmd_speed_set(cmd, SPEED_10000); cmd->duplex = DUPLEX_FULL; /* diff --git a/drivers/net/natsemi.c b/drivers/net/natsemi.c index 7633c67..b78be08 100644 --- a/drivers/net/natsemi.c +++ b/drivers/net/natsemi.c @@ -2820,7 +2820,7 @@ static int netdev_get_ecmd(struct net_device *dev, struct ethtool_cmd *ecmd) u32 tmp; ecmd->port = dev->if_port; - ecmd->speed = np->speed; + ethtool_cmd_speed_set(ecmd, np->speed); ecmd->duplex = np->duplex; ecmd->autoneg = np->autoneg; ecmd->advertising = 0; @@ -2878,9 +2878,9 @@ static int netdev_get_ecmd(struct net_device *dev, struct ethtool_cmd *ecmd) tmp = mii_nway_result( np->advertising & mdio_read(dev, MII_LPA)); if (tmp == LPA_100FULL || tmp == LPA_100HALF) - ecmd->speed = SPEED_100; + ethtool_cmd_speed_set(ecmd, SPEED_100); else - ecmd->speed = SPEED_10; + ethtool_cmd_speed_set(ecmd, SPEED_10); if (tmp == LPA_100FULL || tmp == LPA_10FULL) ecmd->duplex = DUPLEX_FULL; else diff --git a/drivers/net/netxen/netxen_nic_ethtool.c b/drivers/net/netxen/netxen_nic_ethtool.c index e8d16f6..b34fb74 100644 --- a/drivers/net/netxen/netxen_nic_ethtool.c +++ b/drivers/net/netxen/netxen_nic_ethtool.c @@ -117,7 +117,7 @@ netxen_nic_get_settings(struct net_device *dev, struct ethtool_cmd *ecmd) ecmd->port = PORT_TP; - ecmd->speed = adapter->link_speed; + ethtool_cmd_speed_set(ecmd, adapter->link_speed); ecmd->duplex = adapter->link_duplex; ecmd->autoneg = adapter->link_autoneg; @@ -134,7 +134,7 @@ netxen_nic_get_settings(struct net_device *dev, struct ethtool_cmd *ecmd) } if (netif_running(dev) && adapter->has_link_events) { - ecmd->speed = adapter->link_speed; + ethtool_cmd_speed_set(ecmd, adapter->link_speed); ecmd->autoneg = adapter->link_autoneg; ecmd->duplex = adapter->link_duplex; goto skip; @@ -146,10 +146,10 @@ netxen_nic_get_settings(struct net_device *dev, struct ethtool_cmd *ecmd) u16 pcifn = adapter->ahw.pci_func; val = NXRD32(adapter, P3_LINK_SPEED_REG(pcifn)); - ecmd->speed = P3_LINK_SPEED_MHZ * - P3_LINK_SPEED_VAL(pcifn, val); + ethtool_cmd_speed_set(ecmd, P3_LINK_SPEED_MHZ * + P3_LINK_SPEED_VAL(pcifn, val)); } else - ecmd->speed = SPEED_10000; + ethtool_cmd_speed_set(ecmd, SPEED_10000); ecmd->duplex = DUPLEX_FULL; ecmd->autoneg = AUTONEG_DISABLE; diff --git a/drivers/net/niu.c b/drivers/net/niu.c index 524e800..cc25bff0 100644 --- a/drivers/net/niu.c +++ b/drivers/net/niu.c @@ -6844,7 +6844,7 @@ static int niu_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) cmd->supported = lp->supported; cmd->advertising = lp->active_advertising; cmd->autoneg = lp->active_autoneg; - cmd->speed = lp->active_speed; + ethtool_cmd_speed_set(cmd, lp->active_speed); cmd->duplex = lp->active_duplex; cmd->port = (np->flags & NIU_FLAGS_FIBER) ? PORT_FIBRE : PORT_TP; cmd->transceiver = (np->flags & NIU_FLAGS_XCVR_SERDES) ? diff --git a/drivers/net/ns83820.c b/drivers/net/ns83820.c index 6667e06..3e4040f 100644 --- a/drivers/net/ns83820.c +++ b/drivers/net/ns83820.c @@ -1251,7 +1251,7 @@ static int ns83820_get_settings(struct net_device *ndev, /* * Here's the list of available ethtool commands from other drivers: * cmd->advertising = - * cmd->speed = + * ethtool_cmd_speed_set(cmd, ...) * cmd->duplex = * cmd->port = 0; * cmd->phy_address = @@ -1289,13 +1289,13 @@ static int ns83820_get_settings(struct net_device *ndev, cmd->duplex = fullduplex ? DUPLEX_FULL : DUPLEX_HALF; switch (cfg / CFG_SPDSTS0 & 3) { case 2: - cmd->speed = SPEED_1000; + ethtool_cmd_speed_set(cmd, SPEED_1000); break; case 1: - cmd->speed = SPEED_100; + ethtool_cmd_speed_set(cmd, SPEED_100); break; default: - cmd->speed = SPEED_10; + ethtool_cmd_speed_set(cmd, SPEED_10); break; } cmd->autoneg = (tbicr & TBICR_MR_AN_ENABLE) diff --git a/drivers/net/pch_gbe/pch_gbe_phy.c b/drivers/net/pch_gbe/pch_gbe_phy.c index 9a8207f..28bb960 100644 --- a/drivers/net/pch_gbe/pch_gbe_phy.c +++ b/drivers/net/pch_gbe/pch_gbe_phy.c @@ -256,7 +256,7 @@ void pch_gbe_phy_init_setting(struct pch_gbe_hw *hw) if (ret) pr_err("Error: mii_ethtool_gset\n"); - cmd.speed = hw->mac.link_speed; + ethtool_cmd_speed_set(&cmd, hw->mac.link_speed); cmd.duplex = hw->mac.link_duplex; cmd.advertising = hw->phy.autoneg_advertised; cmd.autoneg = hw->mac.autoneg; diff --git a/drivers/net/pcmcia/smc91c92_cs.c b/drivers/net/pcmcia/smc91c92_cs.c index bc71cb2..288e4f1 100644 --- a/drivers/net/pcmcia/smc91c92_cs.c +++ b/drivers/net/pcmcia/smc91c92_cs.c @@ -1860,7 +1860,7 @@ static int smc_netdev_get_ecmd(struct net_device *dev, struct ethtool_cmd *ecmd) tmp = inw(ioaddr + CONFIG); ecmd->port = (tmp & CFG_AUI_SELECT) ? PORT_AUI : PORT_TP; ecmd->transceiver = XCVR_INTERNAL; - ecmd->speed = SPEED_10; + ethtool_cmd_speed_set(ecmd, SPEED_10); ecmd->phy_address = ioaddr + MGMT; SMC_SELECT_BANK(0); diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c index e3f3501..a475957 100644 --- a/drivers/net/phy/phy.c +++ b/drivers/net/phy/phy.c @@ -288,7 +288,7 @@ int phy_ethtool_gset(struct phy_device *phydev, struct ethtool_cmd *cmd) cmd->advertising = phydev->advertising; - cmd->speed = phydev->speed; + ethtool_cmd_speed_set(cmd, phydev->speed); cmd->duplex = phydev->duplex; cmd->port = PORT_MII; cmd->phy_address = phydev->addr; diff --git a/drivers/net/ps3_gelic_net.c b/drivers/net/ps3_gelic_net.c index 4383ed2..b1f251d 100644 --- a/drivers/net/ps3_gelic_net.c +++ b/drivers/net/ps3_gelic_net.c @@ -1243,17 +1243,17 @@ static int gelic_ether_get_settings(struct net_device *netdev, switch (card->ether_port_status & GELIC_LV1_ETHER_SPEED_MASK) { case GELIC_LV1_ETHER_SPEED_10: - cmd->speed = SPEED_10; + ethtool_cmd_speed_set(cmd, SPEED_10); break; case GELIC_LV1_ETHER_SPEED_100: - cmd->speed = SPEED_100; + ethtool_cmd_speed_set(cmd, SPEED_100); break; case GELIC_LV1_ETHER_SPEED_1000: - cmd->speed = SPEED_1000; + ethtool_cmd_speed_set(cmd, SPEED_1000); break; default: pr_info("%s: speed unknown\n", __func__); - cmd->speed = SPEED_10; + ethtool_cmd_speed_set(cmd, SPEED_10); break; } diff --git a/drivers/net/qla3xxx.c b/drivers/net/qla3xxx.c index f3f737b..d495a68 100644 --- a/drivers/net/qla3xxx.c +++ b/drivers/net/qla3xxx.c @@ -1725,7 +1725,7 @@ static int ql_get_settings(struct net_device *ndev, struct ethtool_cmd *ecmd) } ecmd->advertising = ql_supported_modes(qdev); ecmd->autoneg = ql_get_auto_cfg_status(qdev); - ecmd->speed = ql_get_speed(qdev); + ethtool_cmd_speed_set(ecmd, ql_get_speed(qdev)); ecmd->duplex = ql_get_full_dup(qdev); return 0; } diff --git a/drivers/net/qlcnic/qlcnic_ethtool.c b/drivers/net/qlcnic/qlcnic_ethtool.c index 27726eb..c541461 100644 --- a/drivers/net/qlcnic/qlcnic_ethtool.c +++ b/drivers/net/qlcnic/qlcnic_ethtool.c @@ -166,7 +166,7 @@ qlcnic_get_settings(struct net_device *dev, struct ethtool_cmd *ecmd) ADVERTISED_1000baseT_Half | ADVERTISED_1000baseT_Full); - ecmd->speed = adapter->link_speed; + ethtool_cmd_speed_set(ecmd, adapter->link_speed); ecmd->duplex = adapter->link_duplex; ecmd->autoneg = adapter->link_autoneg; @@ -183,15 +183,15 @@ qlcnic_get_settings(struct net_device *dev, struct ethtool_cmd *ecmd) } if (netif_running(dev) && adapter->has_link_events) { - ecmd->speed = adapter->link_speed; + ethtool_cmd_speed_set(ecmd, adapter->link_speed); ecmd->autoneg = adapter->link_autoneg; ecmd->duplex = adapter->link_duplex; goto skip; } val = QLCRD32(adapter, P3P_LINK_SPEED_REG(pcifn)); - ecmd->speed = P3P_LINK_SPEED_MHZ * - P3P_LINK_SPEED_VAL(pcifn, val); + ethtool_cmd_speed_set(ecmd, P3P_LINK_SPEED_MHZ * + P3P_LINK_SPEED_VAL(pcifn, val)); ecmd->duplex = DUPLEX_FULL; ecmd->autoneg = AUTONEG_DISABLE; } else diff --git a/drivers/net/qlge/qlge_ethtool.c b/drivers/net/qlge/qlge_ethtool.c index 78dc40c..19b00fa 100644 --- a/drivers/net/qlge/qlge_ethtool.c +++ b/drivers/net/qlge/qlge_ethtool.c @@ -356,7 +356,7 @@ static int ql_get_settings(struct net_device *ndev, ecmd->port = PORT_FIBRE; } - ecmd->speed = SPEED_10000; + ethtool_cmd_speed_set(ecmd, SPEED_10000); ecmd->duplex = DUPLEX_FULL; return 0; diff --git a/drivers/net/r8169.c b/drivers/net/r8169.c index b52ee17..a8976a7 100644 --- a/drivers/net/r8169.c +++ b/drivers/net/r8169.c @@ -1422,7 +1422,7 @@ static int rtl8169_gset_tbi(struct net_device *dev, struct ethtool_cmd *cmd) cmd->advertising = (status & TBINwEnable) ? ADVERTISED_Autoneg : 0; cmd->autoneg = !!(status & TBINwEnable); - cmd->speed = SPEED_1000; + ethtool_cmd_speed_set(cmd, SPEED_1000); cmd->duplex = DUPLEX_FULL; /* Always set */ return 0; diff --git a/drivers/net/s2io.c b/drivers/net/s2io.c index 5443985..89cfee7 100644 --- a/drivers/net/s2io.c +++ b/drivers/net/s2io.c @@ -5414,10 +5414,10 @@ static int s2io_ethtool_gset(struct net_device *dev, struct ethtool_cmd *info) info->transceiver = XCVR_EXTERNAL; if (netif_carrier_ok(sp->dev)) { - info->speed = 10000; + ethtool_cmd_speed_set(info, SPEED_10000); info->duplex = DUPLEX_FULL; } else { - info->speed = -1; + ethtool_cmd_speed_set(info, -1); info->duplex = -1; } diff --git a/drivers/net/sc92031.c b/drivers/net/sc92031.c index f3ffc1d..fa74314 100644 --- a/drivers/net/sc92031.c +++ b/drivers/net/sc92031.c @@ -1173,7 +1173,8 @@ static int sc92031_ethtool_get_settings(struct net_device *dev, if (phy_ctrl & PhyCtrlAne) cmd->advertising |= ADVERTISED_Autoneg; - cmd->speed = (output_status & 0x2) ? SPEED_100 : SPEED_10; + ethtool_cmd_speed_set(cmd, + (output_status & 0x2) ? SPEED_100 : SPEED_10); cmd->duplex = (output_status & 0x4) ? DUPLEX_FULL : DUPLEX_HALF; cmd->port = PORT_MII; cmd->phy_address = phy_address; diff --git a/drivers/net/sfc/ethtool.c b/drivers/net/sfc/ethtool.c index 10b160a..8c5e005 100644 --- a/drivers/net/sfc/ethtool.c +++ b/drivers/net/sfc/ethtool.c @@ -219,7 +219,7 @@ static int efx_ethtool_get_settings(struct net_device *net_dev, ecmd->supported |= SUPPORTED_Pause | SUPPORTED_Asym_Pause; if (LOOPBACK_INTERNAL(efx)) { - ecmd->speed = link_state->speed; + ethtool_cmd_speed_set(ecmd, link_state->speed); ecmd->duplex = link_state->fd ? DUPLEX_FULL : DUPLEX_HALF; } diff --git a/drivers/net/sfc/mcdi_phy.c b/drivers/net/sfc/mcdi_phy.c index 6c5fccb..6c63ab0 100644 --- a/drivers/net/sfc/mcdi_phy.c +++ b/drivers/net/sfc/mcdi_phy.c @@ -513,7 +513,7 @@ static void efx_mcdi_phy_get_settings(struct efx_nic *efx, struct ethtool_cmd *e ecmd->supported = mcdi_to_ethtool_cap(phy_cfg->media, phy_cfg->supported_cap); ecmd->advertising = efx->link_advertising; - ecmd->speed = efx->link_state.speed; + ethtool_cmd_speed_set(ecmd, efx->link_state.speed); ecmd->duplex = efx->link_state.fd; ecmd->port = mcdi_to_ethtool_media(phy_cfg->media); ecmd->phy_address = phy_cfg->port; diff --git a/drivers/net/sfc/tenxpress.c b/drivers/net/sfc/tenxpress.c index 204ecda..7b0fd89 100644 --- a/drivers/net/sfc/tenxpress.c +++ b/drivers/net/sfc/tenxpress.c @@ -460,7 +460,7 @@ tenxpress_get_settings(struct efx_nic *efx, struct ethtool_cmd *ecmd) /* In loopback, the PHY automatically brings up the correct interface, * but doesn't advertise the correct speed. So override it */ if (LOOPBACK_EXTERNAL(efx)) - ecmd->speed = SPEED_10000; + ethtool_cmd_speed_set(ecmd, SPEED_10000); } static int tenxpress_set_settings(struct efx_nic *efx, struct ethtool_cmd *ecmd) diff --git a/drivers/net/skge.c b/drivers/net/skge.c index a05e864..52a48cb 100644 --- a/drivers/net/skge.c +++ b/drivers/net/skge.c @@ -303,7 +303,7 @@ static int skge_get_settings(struct net_device *dev, ecmd->advertising = skge->advertising; ecmd->autoneg = skge->autoneg; - ecmd->speed = skge->speed; + ethtool_cmd_speed_set(ecmd, skge->speed); ecmd->duplex = skge->duplex; return 0; } diff --git a/drivers/net/sky2.c b/drivers/net/sky2.c index 5c7e2d6..3ee41da 100644 --- a/drivers/net/sky2.c +++ b/drivers/net/sky2.c @@ -3413,10 +3413,10 @@ static int sky2_get_settings(struct net_device *dev, struct ethtool_cmd *ecmd) ecmd->phy_address = PHY_ADDR_MARV; if (sky2_is_copper(hw)) { ecmd->port = PORT_TP; - ecmd->speed = sky2->speed; + ethtool_cmd_speed_set(ecmd, sky2->speed); ecmd->supported |= SUPPORTED_Autoneg | SUPPORTED_TP; } else { - ecmd->speed = SPEED_1000; + ethtool_cmd_speed_set(ecmd, SPEED_1000); ecmd->port = PORT_FIBRE; ecmd->supported |= SUPPORTED_Autoneg | SUPPORTED_FIBRE; } diff --git a/drivers/net/smc911x.c b/drivers/net/smc911x.c index 66831f3..053863a 100644 --- a/drivers/net/smc911x.c +++ b/drivers/net/smc911x.c @@ -1488,9 +1488,9 @@ smc911x_ethtool_getsettings(struct net_device *dev, struct ethtool_cmd *cmd) SUPPORTED_TP | SUPPORTED_AUI; if (lp->ctl_rspeed == 10) - cmd->speed = SPEED_10; + ethtool_cmd_speed_set(cmd, SPEED_10); else if (lp->ctl_rspeed == 100) - cmd->speed = SPEED_100; + ethtool_cmd_speed_set(cmd, SPEED_100); cmd->autoneg = AUTONEG_DISABLE; if (lp->mii.phy_id==1) diff --git a/drivers/net/smc91x.c b/drivers/net/smc91x.c index 43654a3..dc4805f 100644 --- a/drivers/net/smc91x.c +++ b/drivers/net/smc91x.c @@ -1565,9 +1565,9 @@ smc_ethtool_getsettings(struct net_device *dev, struct ethtool_cmd *cmd) SUPPORTED_TP | SUPPORTED_AUI; if (lp->ctl_rspeed == 10) - cmd->speed = SPEED_10; + ethtool_cmd_speed_set(cmd, SPEED_10); else if (lp->ctl_rspeed == 100) - cmd->speed = SPEED_100; + ethtool_cmd_speed_set(cmd, SPEED_100); cmd->autoneg = AUTONEG_DISABLE; cmd->transceiver = XCVR_INTERNAL; diff --git a/drivers/net/spider_net_ethtool.c b/drivers/net/spider_net_ethtool.c index d723fca..9c288cd 100644 --- a/drivers/net/spider_net_ethtool.c +++ b/drivers/net/spider_net_ethtool.c @@ -58,7 +58,7 @@ spider_net_ethtool_get_settings(struct net_device *netdev, cmd->advertising = (ADVERTISED_1000baseT_Full | ADVERTISED_FIBRE); cmd->port = PORT_FIBRE; - cmd->speed = card->phy.speed; + ethtool_cmd_speed_set(cmd, card->phy.speed); cmd->duplex = DUPLEX_FULL; return 0; diff --git a/drivers/net/sungem.c b/drivers/net/sungem.c index 40a755d..ab59300 100644 --- a/drivers/net/sungem.c +++ b/drivers/net/sungem.c @@ -2642,7 +2642,7 @@ static int gem_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) /* Return current PHY settings */ spin_lock_irq(&gp->lock); cmd->autoneg = gp->want_autoneg; - cmd->speed = gp->phy_mii.speed; + ethtool_cmd_speed_set(cmd, gp->phy_mii.speed); cmd->duplex = gp->phy_mii.duplex; cmd->advertising = gp->phy_mii.advertising; @@ -2659,7 +2659,7 @@ static int gem_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) SUPPORTED_100baseT_Half | SUPPORTED_100baseT_Full | SUPPORTED_Autoneg); cmd->advertising = cmd->supported; - cmd->speed = 0; + ethtool_cmd_speed_set(cmd, 0); cmd->duplex = cmd->port = cmd->phy_address = cmd->transceiver = cmd->autoneg = 0; @@ -2673,7 +2673,7 @@ static int gem_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) cmd->advertising = cmd->supported; cmd->transceiver = XCVR_INTERNAL; if (gp->lstate == link_up) - cmd->speed = SPEED_1000; + ethtool_cmd_speed_set(cmd, SPEED_1000); cmd->duplex = DUPLEX_FULL; cmd->autoneg = 1; } diff --git a/drivers/net/sunhme.c b/drivers/net/sunhme.c index 8f3f028..d381a0f 100644 --- a/drivers/net/sunhme.c +++ b/drivers/net/sunhme.c @@ -2401,6 +2401,7 @@ static void happy_meal_set_multicast(struct net_device *dev) static int hme_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) { struct happy_meal *hp = netdev_priv(dev); + u32 speed; cmd->supported = (SUPPORTED_10baseT_Half | SUPPORTED_10baseT_Full | @@ -2420,10 +2421,9 @@ static int hme_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) if (hp->sw_bmcr & BMCR_ANENABLE) { cmd->autoneg = AUTONEG_ENABLE; - cmd->speed = - (hp->sw_lpa & (LPA_100HALF | LPA_100FULL)) ? - SPEED_100 : SPEED_10; - if (cmd->speed == SPEED_100) + speed = ((hp->sw_lpa & (LPA_100HALF | LPA_100FULL)) ? + SPEED_100 : SPEED_10); + if (speed == SPEED_100) cmd->duplex = (hp->sw_lpa & (LPA_100FULL)) ? DUPLEX_FULL : DUPLEX_HALF; @@ -2433,13 +2433,12 @@ static int hme_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) DUPLEX_FULL : DUPLEX_HALF; } else { cmd->autoneg = AUTONEG_DISABLE; - cmd->speed = - (hp->sw_bmcr & BMCR_SPEED100) ? - SPEED_100 : SPEED_10; + speed = (hp->sw_bmcr & BMCR_SPEED100) ? SPEED_100 : SPEED_10; cmd->duplex = (hp->sw_bmcr & BMCR_FULLDPLX) ? DUPLEX_FULL : DUPLEX_HALF; } + ethtool_cmd_speed_set(cmd, speed); return 0; } diff --git a/drivers/net/tehuti.c b/drivers/net/tehuti.c index 8be71de..80fbee0 100644 --- a/drivers/net/tehuti.c +++ b/drivers/net/tehuti.c @@ -2151,7 +2151,7 @@ static int bdx_get_settings(struct net_device *netdev, struct ethtool_cmd *ecmd) ecmd->supported = (SUPPORTED_10000baseT_Full | SUPPORTED_FIBRE); ecmd->advertising = (ADVERTISED_10000baseT_Full | ADVERTISED_FIBRE); - ecmd->speed = SPEED_10000; + ethtool_cmd_speed_set(ecmd, SPEED_10000); ecmd->duplex = DUPLEX_FULL; ecmd->port = PORT_FIBRE; ecmd->transceiver = XCVR_EXTERNAL; /* what does it mean? */ diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index 004f266..7c7c9a8 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -10025,10 +10025,10 @@ static int tg3_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) cmd->advertising = tp->link_config.advertising; if (netif_running(dev)) { - cmd->speed = tp->link_config.active_speed; + ethtool_cmd_speed_set(cmd, tp->link_config.active_speed); cmd->duplex = tp->link_config.active_duplex; } else { - cmd->speed = SPEED_INVALID; + ethtool_cmd_speed_set(cmd, SPEED_INVALID); cmd->duplex = DUPLEX_INVALID; } cmd->phy_address = tp->phy_addr; diff --git a/drivers/net/tulip/de2104x.c b/drivers/net/tulip/de2104x.c index f8d26bf..ab78e1d 100644 --- a/drivers/net/tulip/de2104x.c +++ b/drivers/net/tulip/de2104x.c @@ -1518,15 +1518,15 @@ static int __de_get_settings(struct de_private *de, struct ethtool_cmd *ecmd) switch (de->media_type) { case DE_MEDIA_AUI: ecmd->port = PORT_AUI; - ecmd->speed = 5; + ethtool_cmd_speed_set(ecmd, 5); break; case DE_MEDIA_BNC: ecmd->port = PORT_BNC; - ecmd->speed = 2; + ethtool_cmd_speed_set(ecmd, 2); break; default: ecmd->port = PORT_TP; - ecmd->speed = SPEED_10; + ethtool_cmd_speed_set(ecmd, SPEED_10); break; } diff --git a/drivers/net/tulip/uli526x.c b/drivers/net/tulip/uli526x.c index 74217db..a4375c4 100644 --- a/drivers/net/tulip/uli526x.c +++ b/drivers/net/tulip/uli526x.c @@ -945,12 +945,12 @@ ULi_ethtool_gset(struct uli526x_board_info *db, struct ethtool_cmd *ecmd) ecmd->transceiver = XCVR_EXTERNAL; - ecmd->speed = 10; + ethtool_cmd_speed_set(ecmd, SPEED_10); ecmd->duplex = DUPLEX_HALF; if(db->op_mode==ULI526X_100MHF || db->op_mode==ULI526X_100MFD) { - ecmd->speed = 100; + ethtool_cmd_speed_set(ecmd, SPEED_100); } if(db->op_mode==ULI526X_10MFD || db->op_mode==ULI526X_100MFD) { @@ -958,7 +958,7 @@ ULi_ethtool_gset(struct uli526x_board_info *db, struct ethtool_cmd *ecmd) } if(db->link_failed) { - ecmd->speed = -1; + ethtool_cmd_speed_set(ecmd, -1); ecmd->duplex = -1; } diff --git a/drivers/net/tun.c b/drivers/net/tun.c index ade3cf9..0636f70 100644 --- a/drivers/net/tun.c +++ b/drivers/net/tun.c @@ -1553,7 +1553,7 @@ static int tun_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) { cmd->supported = 0; cmd->advertising = 0; - cmd->speed = SPEED_10; + ethtool_cmd_speed_set(cmd, SPEED_10); cmd->duplex = DUPLEX_FULL; cmd->port = PORT_TP; cmd->phy_address = 0; diff --git a/drivers/net/typhoon.c b/drivers/net/typhoon.c index 9f11c11..3de4283 100644 --- a/drivers/net/typhoon.c +++ b/drivers/net/typhoon.c @@ -1050,7 +1050,7 @@ typhoon_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) /* need to get stats to make these link speed/duplex valid */ typhoon_do_get_stats(tp); - cmd->speed = tp->speed; + ethtool_cmd_speed_set(cmd, tp->speed); cmd->duplex = tp->duplex; cmd->phy_address = 0; cmd->transceiver = XCVR_INTERNAL; diff --git a/drivers/net/usb/catc.c b/drivers/net/usb/catc.c index 97687d3..d7221c4 100644 --- a/drivers/net/usb/catc.c +++ b/drivers/net/usb/catc.c @@ -686,7 +686,7 @@ static int catc_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) cmd->supported = SUPPORTED_10baseT_Half | SUPPORTED_TP; cmd->advertising = ADVERTISED_10baseT_Half | ADVERTISED_TP; - cmd->speed = SPEED_10; + ethtool_cmd_speed_set(cmd, SPEED_10); cmd->duplex = DUPLEX_HALF; cmd->port = PORT_TP; cmd->phy_address = 0; diff --git a/drivers/net/usb/rtl8150.c b/drivers/net/usb/rtl8150.c index e85c89c..041fb7d 100644 --- a/drivers/net/usb/rtl8150.c +++ b/drivers/net/usb/rtl8150.c @@ -843,10 +843,11 @@ static int rtl8150_get_settings(struct net_device *netdev, struct ethtool_cmd *e get_registers(dev, BMCR, 2, &bmcr); get_registers(dev, ANLP, 2, &lpa); if (bmcr & BMCR_ANENABLE) { + u32 speed = ((lpa & (LPA_100HALF | LPA_100FULL)) ? + SPEED_100 : SPEED_10); + ethtool_cmd_speed_set(ecmd, speed); ecmd->autoneg = AUTONEG_ENABLE; - ecmd->speed = (lpa & (LPA_100HALF | LPA_100FULL)) ? - SPEED_100 : SPEED_10; - if (ecmd->speed == SPEED_100) + if (speed == SPEED_100) ecmd->duplex = (lpa & LPA_100FULL) ? DUPLEX_FULL : DUPLEX_HALF; else @@ -854,8 +855,8 @@ static int rtl8150_get_settings(struct net_device *netdev, struct ethtool_cmd *e DUPLEX_FULL : DUPLEX_HALF; } else { ecmd->autoneg = AUTONEG_DISABLE; - ecmd->speed = (bmcr & BMCR_SPEED100) ? - SPEED_100 : SPEED_10; + ethtool_cmd_speed_set(ecmd, ((bmcr & BMCR_SPEED100) ? + SPEED_100 : SPEED_10)); ecmd->duplex = (bmcr & BMCR_FULLDPLX) ? DUPLEX_FULL : DUPLEX_HALF; } diff --git a/drivers/net/veth.c b/drivers/net/veth.c index 6542288..cbe953a 100644 --- a/drivers/net/veth.c +++ b/drivers/net/veth.c @@ -52,7 +52,7 @@ static int veth_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) { cmd->supported = 0; cmd->advertising = 0; - cmd->speed = SPEED_10000; + ethtool_cmd_speed_set(cmd, SPEED_10000); cmd->duplex = DUPLEX_FULL; cmd->port = PORT_TP; cmd->phy_address = 0; diff --git a/drivers/net/via-velocity.c b/drivers/net/via-velocity.c index 9a8f116..06daa9d 100644 --- a/drivers/net/via-velocity.c +++ b/drivers/net/via-velocity.c @@ -3182,7 +3182,8 @@ static void velocity_ethtool_down(struct net_device *dev) pci_set_power_state(vptr->pdev, PCI_D3hot); } -static int velocity_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) +static int velocity_get_settings(struct net_device *dev, + struct ethtool_cmd *cmd) { struct velocity_info *vptr = netdev_priv(dev); struct mac_regs __iomem *regs = vptr->mac_regs; @@ -3228,12 +3229,14 @@ static int velocity_get_settings(struct net_device *dev, struct ethtool_cmd *cmd break; } } + if (status & VELOCITY_SPEED_1000) - cmd->speed = SPEED_1000; + ethtool_cmd_speed_set(cmd, SPEED_1000); else if (status & VELOCITY_SPEED_100) - cmd->speed = SPEED_100; + ethtool_cmd_speed_set(cmd, SPEED_100); else - cmd->speed = SPEED_10; + ethtool_cmd_speed_set(cmd, SPEED_10); + cmd->autoneg = (status & VELOCITY_AUTONEG_ENABLE) ? AUTONEG_ENABLE : AUTONEG_DISABLE; cmd->port = PORT_TP; cmd->transceiver = XCVR_INTERNAL; diff --git a/drivers/net/vmxnet3/vmxnet3_ethtool.c b/drivers/net/vmxnet3/vmxnet3_ethtool.c index 70c1ab9..64303eb 100644 --- a/drivers/net/vmxnet3/vmxnet3_ethtool.c +++ b/drivers/net/vmxnet3/vmxnet3_ethtool.c @@ -424,10 +424,10 @@ vmxnet3_get_settings(struct net_device *netdev, struct ethtool_cmd *ecmd) ecmd->transceiver = XCVR_INTERNAL; if (adapter->link_speed) { - ecmd->speed = adapter->link_speed; + ethtool_cmd_speed_set(ecmd, adapter->link_speed); ecmd->duplex = DUPLEX_FULL; } else { - ecmd->speed = -1; + ethtool_cmd_speed_set(ecmd, -1); ecmd->duplex = -1; } return 0; diff --git a/drivers/net/vxge/vxge-ethtool.c b/drivers/net/vxge/vxge-ethtool.c index a70874e..92dd72d 100644 --- a/drivers/net/vxge/vxge-ethtool.c +++ b/drivers/net/vxge/vxge-ethtool.c @@ -59,10 +59,10 @@ static int vxge_ethtool_gset(struct net_device *dev, struct ethtool_cmd *info) info->transceiver = XCVR_EXTERNAL; if (netif_carrier_ok(dev)) { - info->speed = SPEED_10000; + ethtool_cmd_speed_set(info, SPEED_10000); info->duplex = DUPLEX_FULL; } else { - info->speed = -1; + ethtool_cmd_speed_set(info, -1); info->duplex = -1; } diff --git a/net/batman-adv/soft-interface.c b/net/batman-adv/soft-interface.c index f4d80ad..eeabbb8 100644 --- a/net/batman-adv/soft-interface.c +++ b/net/batman-adv/soft-interface.c @@ -697,7 +697,7 @@ static int bat_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) { cmd->supported = 0; cmd->advertising = 0; - cmd->speed = SPEED_10; + ethtool_cmd_speed_set(cmd, SPEED_10); cmd->duplex = DUPLEX_FULL; cmd->port = PORT_TP; cmd->phy_address = 0; -- cgit v0.10.2 From 1258c076edcf4a253657320cfc2bd24fd5981d79 Mon Sep 17 00:00:00 2001 From: David Decotigny Date: Wed, 27 Apr 2011 18:32:41 +0000 Subject: acenic: Fix using the specified speed when configuring NIC This tells the NIC to take the speed specified by ethtool into account when configuring the NIC, instead of keeping the previous speed. Signed-off-by: David Decotigny Signed-off-by: David S. Miller diff --git a/drivers/net/acenic.c b/drivers/net/acenic.c index a579899..82260ca 100644 --- a/drivers/net/acenic.c +++ b/drivers/net/acenic.c @@ -2720,7 +2720,7 @@ static int ace_set_settings(struct net_device *dev, struct ethtool_cmd *ecmd) link |= LNK_NEGOTIATE; if (ethtool_cmd_speed(ecmd) != speed) { link &= ~(LNK_1000MB | LNK_100MB | LNK_10MB); - switch (speed) { + switch (ethtool_cmd_speed(ecmd)) { case SPEED_1000: link |= LNK_1000MB; break; -- cgit v0.10.2 From fbef7139a8b89a7f49ba1410593ed894b4c8b017 Mon Sep 17 00:00:00 2001 From: David Decotigny Date: Wed, 27 Apr 2011 18:32:42 +0000 Subject: tulip/de2104x: don't report different speeds depending on port type Initial driver reported different speeds depending on the port being used. This advertises the speed to be 10Mbps in any case, which is what it actually is on the wire. Signed-off-by: David Decotigny Signed-off-by: David S. Miller diff --git a/drivers/net/tulip/de2104x.c b/drivers/net/tulip/de2104x.c index ab78e1d..46d5a1b 100644 --- a/drivers/net/tulip/de2104x.c +++ b/drivers/net/tulip/de2104x.c @@ -1518,18 +1518,17 @@ static int __de_get_settings(struct de_private *de, struct ethtool_cmd *ecmd) switch (de->media_type) { case DE_MEDIA_AUI: ecmd->port = PORT_AUI; - ethtool_cmd_speed_set(ecmd, 5); break; case DE_MEDIA_BNC: ecmd->port = PORT_BNC; - ethtool_cmd_speed_set(ecmd, 2); break; default: ecmd->port = PORT_TP; - ethtool_cmd_speed_set(ecmd, SPEED_10); break; } + ethtool_cmd_speed_set(ecmd, 10); + if (dr32(MacMode) & FullDuplex) ecmd->duplex = DUPLEX_FULL; else @@ -1549,11 +1548,8 @@ static int __de_set_settings(struct de_private *de, struct ethtool_cmd *ecmd) { u32 new_media; unsigned int media_lock; - u32 speed = ethtool_cmd_speed(ecmd); - if (speed != SPEED_10 && speed != 5 && speed != 2) - return -EINVAL; - if (de->de21040 && speed == 2) + if (ethtool_cmd_speed(ecmd) != 10) return -EINVAL; if (ecmd->duplex != DUPLEX_HALF && ecmd->duplex != DUPLEX_FULL) return -EINVAL; -- cgit v0.10.2 From 14ad2513ed5b709e566a853f4b515d91c5d83311 Mon Sep 17 00:00:00 2001 From: David Decotigny Date: Wed, 27 Apr 2011 18:32:43 +0000 Subject: net/igb/e1000/e1000e: more robust ethtool duplex/speed configuration This makes sure that one cannot request a 99Mbps full-duplex and get a 100Mbps half-duplex configuration in return due to the way the speed/duplex parameters are handled internally. Tested: e1000 works Signed-off-by: David Decotigny Signed-off-by: David S. Miller diff --git a/drivers/net/e1000/e1000.h b/drivers/net/e1000/e1000.h index a881dd0..b1b23dd 100644 --- a/drivers/net/e1000/e1000.h +++ b/drivers/net/e1000/e1000.h @@ -349,7 +349,7 @@ extern int e1000_up(struct e1000_adapter *adapter); extern void e1000_down(struct e1000_adapter *adapter); extern void e1000_reinit_locked(struct e1000_adapter *adapter); extern void e1000_reset(struct e1000_adapter *adapter); -extern int e1000_set_spd_dplx(struct e1000_adapter *adapter, u16 spddplx); +extern int e1000_set_spd_dplx(struct e1000_adapter *adapter, u32 spd, u8 dplx); extern int e1000_setup_all_rx_resources(struct e1000_adapter *adapter); extern int e1000_setup_all_tx_resources(struct e1000_adapter *adapter); extern void e1000_free_all_rx_resources(struct e1000_adapter *adapter); diff --git a/drivers/net/e1000/e1000_ethtool.c b/drivers/net/e1000/e1000_ethtool.c index 127fef4..4fa727c 100644 --- a/drivers/net/e1000/e1000_ethtool.c +++ b/drivers/net/e1000/e1000_ethtool.c @@ -199,7 +199,7 @@ static int e1000_set_settings(struct net_device *netdev, ecmd->advertising = hw->autoneg_advertised; } else { u32 speed = ethtool_cmd_speed(ecmd); - if (e1000_set_spd_dplx(adapter, speed + ecmd->duplex)) { + if (e1000_set_spd_dplx(adapter, speed, ecmd->duplex)) { clear_bit(__E1000_RESETTING, &adapter->flags); return -EINVAL; } diff --git a/drivers/net/e1000/e1000_main.c b/drivers/net/e1000/e1000_main.c index 477e066..c18cb8e 100644 --- a/drivers/net/e1000/e1000_main.c +++ b/drivers/net/e1000/e1000_main.c @@ -96,7 +96,6 @@ int e1000_up(struct e1000_adapter *adapter); void e1000_down(struct e1000_adapter *adapter); void e1000_reinit_locked(struct e1000_adapter *adapter); void e1000_reset(struct e1000_adapter *adapter); -int e1000_set_spd_dplx(struct e1000_adapter *adapter, u16 spddplx); int e1000_setup_all_tx_resources(struct e1000_adapter *adapter); int e1000_setup_all_rx_resources(struct e1000_adapter *adapter); void e1000_free_all_tx_resources(struct e1000_adapter *adapter); @@ -4385,7 +4384,6 @@ static int e1000_mii_ioctl(struct net_device *netdev, struct ifreq *ifr, struct mii_ioctl_data *data = if_mii(ifr); int retval; u16 mii_reg; - u16 spddplx; unsigned long flags; if (hw->media_type != e1000_media_type_copper) @@ -4424,17 +4422,18 @@ static int e1000_mii_ioctl(struct net_device *netdev, struct ifreq *ifr, hw->autoneg = 1; hw->autoneg_advertised = 0x2F; } else { + u32 speed; if (mii_reg & 0x40) - spddplx = SPEED_1000; + speed = SPEED_1000; else if (mii_reg & 0x2000) - spddplx = SPEED_100; + speed = SPEED_100; else - spddplx = SPEED_10; - spddplx += (mii_reg & 0x100) - ? DUPLEX_FULL : - DUPLEX_HALF; - retval = e1000_set_spd_dplx(adapter, - spddplx); + speed = SPEED_10; + retval = e1000_set_spd_dplx( + adapter, speed, + ((mii_reg & 0x100) + ? DUPLEX_FULL : + DUPLEX_HALF)); if (retval) return retval; } @@ -4596,20 +4595,24 @@ static void e1000_restore_vlan(struct e1000_adapter *adapter) } } -int e1000_set_spd_dplx(struct e1000_adapter *adapter, u16 spddplx) +int e1000_set_spd_dplx(struct e1000_adapter *adapter, u32 spd, u8 dplx) { struct e1000_hw *hw = &adapter->hw; hw->autoneg = 0; + /* Make sure dplx is at most 1 bit and lsb of speed is not set + * for the switch() below to work */ + if ((spd & 1) || (dplx & ~1)) + goto err_inval; + /* Fiber NICs only allow 1000 gbps Full duplex */ if ((hw->media_type == e1000_media_type_fiber) && - spddplx != (SPEED_1000 + DUPLEX_FULL)) { - e_err(probe, "Unsupported Speed/Duplex configuration\n"); - return -EINVAL; - } + spd != SPEED_1000 && + dplx != DUPLEX_FULL) + goto err_inval; - switch (spddplx) { + switch (spd + dplx) { case SPEED_10 + DUPLEX_HALF: hw->forced_speed_duplex = e1000_10_half; break; @@ -4628,10 +4631,13 @@ int e1000_set_spd_dplx(struct e1000_adapter *adapter, u16 spddplx) break; case SPEED_1000 + DUPLEX_HALF: /* not supported */ default: - e_err(probe, "Unsupported Speed/Duplex configuration\n"); - return -EINVAL; + goto err_inval; } return 0; + +err_inval: + e_err(probe, "Unsupported Speed/Duplex configuration\n"); + return -EINVAL; } static int __e1000_shutdown(struct pci_dev *pdev, bool *enable_wake) diff --git a/drivers/net/e1000e/ethtool.c b/drivers/net/e1000e/ethtool.c index 12f1ee2..859d0d3 100644 --- a/drivers/net/e1000e/ethtool.c +++ b/drivers/net/e1000e/ethtool.c @@ -200,20 +200,25 @@ static int e1000_get_settings(struct net_device *netdev, return 0; } -static int e1000_set_spd_dplx(struct e1000_adapter *adapter, u16 spddplx) +static int e1000_set_spd_dplx(struct e1000_adapter *adapter, u32 spd, u8 dplx) { struct e1000_mac_info *mac = &adapter->hw.mac; mac->autoneg = 0; + /* Make sure dplx is at most 1 bit and lsb of speed is not set + * for the switch() below to work */ + if ((spd & 1) || (dplx & ~1)) + goto err_inval; + /* Fiber NICs only allow 1000 gbps Full duplex */ if ((adapter->hw.phy.media_type == e1000_media_type_fiber) && - spddplx != (SPEED_1000 + DUPLEX_FULL)) { - e_err("Unsupported Speed/Duplex configuration\n"); - return -EINVAL; + spd != SPEED_1000 && + dplx != DUPLEX_FULL) { + goto err_inval; } - switch (spddplx) { + switch (spd + dplx) { case SPEED_10 + DUPLEX_HALF: mac->forced_speed_duplex = ADVERTISE_10_HALF; break; @@ -232,10 +237,13 @@ static int e1000_set_spd_dplx(struct e1000_adapter *adapter, u16 spddplx) break; case SPEED_1000 + DUPLEX_HALF: /* not supported */ default: - e_err("Unsupported Speed/Duplex configuration\n"); - return -EINVAL; + goto err_inval; } return 0; + +err_inval: + e_err("Unsupported Speed/Duplex configuration\n"); + return -EINVAL; } static int e1000_set_settings(struct net_device *netdev, @@ -272,7 +280,7 @@ static int e1000_set_settings(struct net_device *netdev, hw->fc.requested_mode = e1000_fc_default; } else { u32 speed = ethtool_cmd_speed(ecmd); - if (e1000_set_spd_dplx(adapter, speed + ecmd->duplex)) { + if (e1000_set_spd_dplx(adapter, speed, ecmd->duplex)) { clear_bit(__E1000_RESETTING, &adapter->state); return -EINVAL; } diff --git a/drivers/net/igb/igb.h b/drivers/net/igb/igb.h index 1c687e2..f4fa4b1 100644 --- a/drivers/net/igb/igb.h +++ b/drivers/net/igb/igb.h @@ -360,7 +360,7 @@ extern int igb_up(struct igb_adapter *); extern void igb_down(struct igb_adapter *); extern void igb_reinit_locked(struct igb_adapter *); extern void igb_reset(struct igb_adapter *); -extern int igb_set_spd_dplx(struct igb_adapter *, u16); +extern int igb_set_spd_dplx(struct igb_adapter *, u32, u8); extern int igb_setup_tx_resources(struct igb_ring *); extern int igb_setup_rx_resources(struct igb_ring *); extern void igb_free_tx_resources(struct igb_ring *); diff --git a/drivers/net/igb/igb_ethtool.c b/drivers/net/igb/igb_ethtool.c index 023aa9b..6e29634 100644 --- a/drivers/net/igb/igb_ethtool.c +++ b/drivers/net/igb/igb_ethtool.c @@ -224,7 +224,7 @@ static int igb_set_settings(struct net_device *netdev, struct ethtool_cmd *ecmd) hw->fc.requested_mode = e1000_fc_default; } else { u32 speed = ethtool_cmd_speed(ecmd); - if (igb_set_spd_dplx(adapter, speed + ecmd->duplex)) { + if (igb_set_spd_dplx(adapter, speed, ecmd->duplex)) { clear_bit(__IGB_RESETTING, &adapter->state); return -EINVAL; } diff --git a/drivers/net/igb/igb_main.c b/drivers/net/igb/igb_main.c index cdfd572..ce7838e 100644 --- a/drivers/net/igb/igb_main.c +++ b/drivers/net/igb/igb_main.c @@ -6349,21 +6349,25 @@ static void igb_restore_vlan(struct igb_adapter *adapter) } } -int igb_set_spd_dplx(struct igb_adapter *adapter, u16 spddplx) +int igb_set_spd_dplx(struct igb_adapter *adapter, u32 spd, u8 dplx) { struct pci_dev *pdev = adapter->pdev; struct e1000_mac_info *mac = &adapter->hw.mac; mac->autoneg = 0; + /* Make sure dplx is at most 1 bit and lsb of speed is not set + * for the switch() below to work */ + if ((spd & 1) || (dplx & ~1)) + goto err_inval; + /* Fiber NIC's only allow 1000 Gbps Full duplex */ if ((adapter->hw.phy.media_type == e1000_media_type_internal_serdes) && - spddplx != (SPEED_1000 + DUPLEX_FULL)) { - dev_err(&pdev->dev, "Unsupported Speed/Duplex configuration\n"); - return -EINVAL; - } + spd != SPEED_1000 && + dplx != DUPLEX_FULL) + goto err_inval; - switch (spddplx) { + switch (spd + dplx) { case SPEED_10 + DUPLEX_HALF: mac->forced_speed_duplex = ADVERTISE_10_HALF; break; @@ -6382,10 +6386,13 @@ int igb_set_spd_dplx(struct igb_adapter *adapter, u16 spddplx) break; case SPEED_1000 + DUPLEX_HALF: /* not supported */ default: - dev_err(&pdev->dev, "Unsupported Speed/Duplex configuration\n"); - return -EINVAL; + goto err_inval; } return 0; + +err_inval: + dev_err(&pdev->dev, "Unsupported Speed/Duplex configuration\n"); + return -EINVAL; } static int __igb_shutdown(struct pci_dev *pdev, bool *enable_wake) -- cgit v0.10.2 From 773d67903ad608d3f64cc5b00e2f881473413c13 Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Tue, 26 Apr 2011 09:18:51 -0700 Subject: misc: fix ti-st build issues st_drv uses skb*() interfaces, so it should depend on NET. It also uses GPIO interfaces, so it should depend on GPIOLIB. st_kim.c uses syss_*() calls, so it should #include . Fixes these observed build errors: ERROR: "skb_queue_purge" [drivers/misc/ti-st/st_drv.ko] undefined! ERROR: "skb_pull" [drivers/misc/ti-st/st_drv.ko] undefined! ERROR: "skb_queue_tail" [drivers/misc/ti-st/st_drv.ko] undefined! ERROR: "__alloc_skb" [drivers/misc/ti-st/st_drv.ko] undefined! ERROR: "kfree_skb" [drivers/misc/ti-st/st_drv.ko] undefined! ERROR: "skb_dequeue" [drivers/misc/ti-st/st_drv.ko] undefined! ERROR: "skb_put" [drivers/misc/ti-st/st_drv.ko] undefined! Signed-off-by: Randy Dunlap Cc: Pavan Savoy Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/misc/ti-st/Kconfig b/drivers/misc/ti-st/Kconfig index 7c3e106..abb5de1 100644 --- a/drivers/misc/ti-st/Kconfig +++ b/drivers/misc/ti-st/Kconfig @@ -5,6 +5,7 @@ menu "Texas Instruments shared transport line discipline" config TI_ST tristate "Shared transport core driver" + depends on NET && GPIOLIB select FW_LOADER help This enables the shared transport core driver for TI diff --git a/drivers/misc/ti-st/st_kim.c b/drivers/misc/ti-st/st_kim.c index b4488c8..5da93ee 100644 --- a/drivers/misc/ti-st/st_kim.c +++ b/drivers/misc/ti-st/st_kim.c @@ -30,6 +30,7 @@ #include #include #include +#include #include #include -- cgit v0.10.2 From 57d5f9f808b7650a92f31e9cd3acd3f415a22530 Mon Sep 17 00:00:00 2001 From: Mike Waychison Date: Mon, 14 Mar 2011 23:58:45 -0700 Subject: x86: get_bios_ebda_length() Add a wrapper routine that tells us the length of the EBDA if it is present. This guy also ensures that the returned length doesn't let the EBDA run past the 640KiB mark. Signed-off-by: Mike Waychison Signed-off-by: Greg Kroah-Hartman diff --git a/arch/x86/include/asm/bios_ebda.h b/arch/x86/include/asm/bios_ebda.h index 3c75210..5174cf0 100644 --- a/arch/x86/include/asm/bios_ebda.h +++ b/arch/x86/include/asm/bios_ebda.h @@ -14,6 +14,27 @@ static inline unsigned int get_bios_ebda(void) return address; /* 0 means none */ } +/* + * Return the sanitized length of the EBDA in bytes, if it exists. + */ +static inline unsigned int get_bios_ebda_length(void) +{ + unsigned int address; + unsigned int length; + + address = get_bios_ebda(); + if (!address) + return 0; + + /* EBDA length is byte 0 of the EBDA (stored in KiB) */ + length = *(unsigned char *)phys_to_virt(address); + length <<= 10; + + /* Trim the length if it extends beyond 640KiB */ + length = min_t(unsigned int, (640 * 1024) - address, length); + return length; +} + void reserve_ebda_region(void); #ifdef CONFIG_X86_CHECK_BIOS_CORRUPTION -- cgit v0.10.2 From f548ccd47d608e88d432745091e13f927ced83f7 Mon Sep 17 00:00:00 2001 From: Mike Waychison Date: Mon, 14 Mar 2011 23:58:50 -0700 Subject: x86: Better comments for get_bios_ebda() Make the comments a bit clearer for get_bios_ebda so that it actually tells us what it is returning. Signed-off-by: Mike Waychison Signed-off-by: Greg Kroah-Hartman diff --git a/arch/x86/include/asm/bios_ebda.h b/arch/x86/include/asm/bios_ebda.h index 5174cf0..aa6a317 100644 --- a/arch/x86/include/asm/bios_ebda.h +++ b/arch/x86/include/asm/bios_ebda.h @@ -4,11 +4,14 @@ #include /* - * there is a real-mode segmented pointer pointing to the - * 4K EBDA area at 0x40E. + * Returns physical address of EBDA. Returns 0 if there is no EBDA. */ static inline unsigned int get_bios_ebda(void) { + /* + * There is a real-mode segmented pointer pointing to the + * 4K EBDA area at 0x40E. + */ unsigned int address = *(unsigned short *)phys_to_virt(0x40E); address <<= 4; return address; /* 0 means none */ -- cgit v0.10.2 From c63ca0c01d73563d4e2ab174bb3dd1e5efb907e6 Mon Sep 17 00:00:00 2001 From: David Ahern Date: Fri, 29 Apr 2011 16:04:15 -0600 Subject: perf stat: Tell user about unsupported events in the list Similar to perf-record, tell user about unsupported events that will not be counted if invoked in verbose mode. e.g., $ perf stat -e dTLB-prefetch-misses -v -- sleep 1 dTLB-prefetch-misses event is not supported by the kernel. dTLB-prefetch-misses: 0 0 0 Performance counter stats for 'sleep 1': dTLB-prefetch-misses 1.001884783 seconds time elapsed Signed-off-by: David Ahern Cc: Peter Zijlstra Cc: Arnaldo Carvalho de Melo Cc: Frederic Weisbecker Link: http://lkml.kernel.org/r/1304114655-10600-1-git-send-email-dsahern@gmail.com Signed-off-by: Ingo Molnar diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c index c8b535b..602c3c9 100644 --- a/tools/perf/builtin-stat.c +++ b/tools/perf/builtin-stat.c @@ -377,8 +377,12 @@ static int run_perf_stat(int argc __used, const char **argv) list_for_each_entry(counter, &evsel_list->entries, node) { if (create_perf_stat_counter(counter) < 0) { - if (errno == EINVAL || errno == ENOSYS || errno == ENOENT) + if (errno == EINVAL || errno == ENOSYS || errno == ENOENT) { + if (verbose) + ui__warning("%s event is not supported by the kernel.\n", + event_name(counter)); continue; + } if (errno == EPERM || errno == EACCES) { error("You may not have permission to collect %sstats.\n" -- cgit v0.10.2 From 85eb8c8d0b0900c073b0e6f89979ac9c439ade1a Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Sat, 30 Apr 2011 00:25:44 +0200 Subject: PM / Runtime: Generic clock manipulation rountines for runtime PM (v6) Many different platforms and subsystems may want to disable device clocks during suspend and enable them during resume which is going to be done in a very similar way in all those cases. For this reason, provide generic routines for the manipulation of device clocks during suspend and resume. Convert the ARM shmobile platform to using the new routines. Signed-off-by: Rafael J. Wysocki diff --git a/arch/arm/mach-shmobile/pm_runtime.c b/arch/arm/mach-shmobile/pm_runtime.c index 30bbe9a..2d1b67a 100644 --- a/arch/arm/mach-shmobile/pm_runtime.c +++ b/arch/arm/mach-shmobile/pm_runtime.c @@ -21,70 +21,6 @@ #include #ifdef CONFIG_PM_RUNTIME -#define BIT_ONCE 0 -#define BIT_ACTIVE 1 -#define BIT_CLK_ENABLED 2 - -struct pm_runtime_data { - unsigned long flags; - struct clk *clk; -}; - -static struct pm_runtime_data *__to_prd(struct device *dev) -{ - return dev ? dev->power.subsys_data : NULL; -} - -static void platform_pm_runtime_init(struct device *dev, - struct pm_runtime_data *prd) -{ - if (prd && !test_and_set_bit(BIT_ONCE, &prd->flags)) { - prd->clk = clk_get(dev, NULL); - if (!IS_ERR(prd->clk)) { - set_bit(BIT_ACTIVE, &prd->flags); - dev_info(dev, "clocks managed by runtime pm\n"); - } - } -} - -static void platform_pm_runtime_bug(struct device *dev, - struct pm_runtime_data *prd) -{ - if (prd && !test_and_set_bit(BIT_ONCE, &prd->flags)) - dev_err(dev, "runtime pm suspend before resume\n"); -} - -static int default_platform_runtime_suspend(struct device *dev) -{ - struct pm_runtime_data *prd = __to_prd(dev); - - dev_dbg(dev, "%s()\n", __func__); - - platform_pm_runtime_bug(dev, prd); - - if (prd && test_bit(BIT_ACTIVE, &prd->flags)) { - clk_disable(prd->clk); - clear_bit(BIT_CLK_ENABLED, &prd->flags); - } - - return 0; -} - -static int default_platform_runtime_resume(struct device *dev) -{ - struct pm_runtime_data *prd = __to_prd(dev); - - dev_dbg(dev, "%s()\n", __func__); - - platform_pm_runtime_init(dev, prd); - - if (prd && test_bit(BIT_ACTIVE, &prd->flags)) { - clk_enable(prd->clk); - set_bit(BIT_CLK_ENABLED, &prd->flags); - } - - return 0; -} static int default_platform_runtime_idle(struct device *dev) { @@ -94,87 +30,29 @@ static int default_platform_runtime_idle(struct device *dev) static struct dev_power_domain default_power_domain = { .ops = { - .runtime_suspend = default_platform_runtime_suspend, - .runtime_resume = default_platform_runtime_resume, + .runtime_suspend = pm_runtime_clk_suspend, + .runtime_resume = pm_runtime_clk_resume, .runtime_idle = default_platform_runtime_idle, USE_PLATFORM_PM_SLEEP_OPS }, }; -static int platform_bus_notify(struct notifier_block *nb, - unsigned long action, void *data) -{ - struct device *dev = data; - struct pm_runtime_data *prd; - - dev_dbg(dev, "platform_bus_notify() %ld !\n", action); - - switch (action) { - case BUS_NOTIFY_BIND_DRIVER: - prd = kzalloc(sizeof(*prd), GFP_KERNEL); - if (prd) { - dev->power.subsys_data = prd; - dev->pwr_domain = &default_power_domain; - } else { - dev_err(dev, "unable to alloc memory for runtime pm\n"); - } - break; - case BUS_NOTIFY_UNBOUND_DRIVER: - prd = __to_prd(dev); - if (prd) { - if (test_bit(BIT_CLK_ENABLED, &prd->flags)) - clk_disable(prd->clk); +#define DEFAULT_PWR_DOMAIN_PTR (&default_power_domain) - if (test_bit(BIT_ACTIVE, &prd->flags)) - clk_put(prd->clk); - } - break; - } +#else - return 0; -} - -#else /* CONFIG_PM_RUNTIME */ - -static int platform_bus_notify(struct notifier_block *nb, - unsigned long action, void *data) -{ - struct device *dev = data; - struct clk *clk; - - dev_dbg(dev, "platform_bus_notify() %ld !\n", action); - - switch (action) { - case BUS_NOTIFY_BIND_DRIVER: - clk = clk_get(dev, NULL); - if (!IS_ERR(clk)) { - clk_enable(clk); - clk_put(clk); - dev_info(dev, "runtime pm disabled, clock forced on\n"); - } - break; - case BUS_NOTIFY_UNBOUND_DRIVER: - clk = clk_get(dev, NULL); - if (!IS_ERR(clk)) { - clk_disable(clk); - clk_put(clk); - dev_info(dev, "runtime pm disabled, clock forced off\n"); - } - break; - } - - return 0; -} +#define DEFAULT_PWR_DOMAIN_PTR NULL #endif /* CONFIG_PM_RUNTIME */ -static struct notifier_block platform_bus_notifier = { - .notifier_call = platform_bus_notify +static struct pm_clk_notifier_block platform_bus_notifier = { + .pwr_domain = DEFAULT_PWR_DOMAIN_PTR, + .con_ids = { NULL, }, }; static int __init sh_pm_runtime_init(void) { - bus_register_notifier(&platform_bus_type, &platform_bus_notifier); + pm_runtime_clk_add_notifier(&platform_bus_type, &platform_bus_notifier); return 0; } core_initcall(sh_pm_runtime_init); diff --git a/drivers/base/power/Makefile b/drivers/base/power/Makefile index 118c1b9..06a7073 100644 --- a/drivers/base/power/Makefile +++ b/drivers/base/power/Makefile @@ -3,6 +3,7 @@ obj-$(CONFIG_PM_SLEEP) += main.o wakeup.o obj-$(CONFIG_PM_RUNTIME) += runtime.o obj-$(CONFIG_PM_TRACE_RTC) += trace.o obj-$(CONFIG_PM_OPP) += opp.o +obj-$(CONFIG_HAVE_CLK) += clock_ops.o ccflags-$(CONFIG_DEBUG_DRIVER) := -DDEBUG ccflags-$(CONFIG_PM_VERBOSE) += -DDEBUG diff --git a/drivers/base/power/clock_ops.c b/drivers/base/power/clock_ops.c new file mode 100644 index 0000000..d74abf3 --- /dev/null +++ b/drivers/base/power/clock_ops.c @@ -0,0 +1,430 @@ +/* + * drivers/base/power/clock_ops.c - Generic clock manipulation PM callbacks + * + * Copyright (c) 2011 Rafael J. Wysocki , Renesas Electronics Corp. + * + * This file is released under the GPLv2. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef CONFIG_PM_RUNTIME + +struct pm_runtime_clk_data { + struct list_head clock_list; + struct mutex lock; +}; + +enum pce_status { + PCE_STATUS_NONE = 0, + PCE_STATUS_ACQUIRED, + PCE_STATUS_ENABLED, + PCE_STATUS_ERROR, +}; + +struct pm_clock_entry { + struct list_head node; + char *con_id; + struct clk *clk; + enum pce_status status; +}; + +static struct pm_runtime_clk_data *__to_prd(struct device *dev) +{ + return dev ? dev->power.subsys_data : NULL; +} + +/** + * pm_runtime_clk_add - Start using a device clock for runtime PM. + * @dev: Device whose clock is going to be used for runtime PM. + * @con_id: Connection ID of the clock. + * + * Add the clock represented by @con_id to the list of clocks used for + * the runtime PM of @dev. + */ +int pm_runtime_clk_add(struct device *dev, const char *con_id) +{ + struct pm_runtime_clk_data *prd = __to_prd(dev); + struct pm_clock_entry *ce; + + if (!prd) + return -EINVAL; + + ce = kzalloc(sizeof(*ce), GFP_KERNEL); + if (!ce) { + dev_err(dev, "Not enough memory for clock entry.\n"); + return -ENOMEM; + } + + if (con_id) { + ce->con_id = kstrdup(con_id, GFP_KERNEL); + if (!ce->con_id) { + dev_err(dev, + "Not enough memory for clock connection ID.\n"); + kfree(ce); + return -ENOMEM; + } + } + + mutex_lock(&prd->lock); + list_add_tail(&ce->node, &prd->clock_list); + mutex_unlock(&prd->lock); + return 0; +} + +/** + * __pm_runtime_clk_remove - Destroy runtime PM clock entry. + * @ce: Runtime PM clock entry to destroy. + * + * This routine must be called under the mutex protecting the runtime PM list + * of clocks corresponding the the @ce's device. + */ +static void __pm_runtime_clk_remove(struct pm_clock_entry *ce) +{ + if (!ce) + return; + + list_del(&ce->node); + + if (ce->status < PCE_STATUS_ERROR) { + if (ce->status == PCE_STATUS_ENABLED) + clk_disable(ce->clk); + + if (ce->status >= PCE_STATUS_ACQUIRED) + clk_put(ce->clk); + } + + if (ce->con_id) + kfree(ce->con_id); + + kfree(ce); +} + +/** + * pm_runtime_clk_remove - Stop using a device clock for runtime PM. + * @dev: Device whose clock should not be used for runtime PM any more. + * @con_id: Connection ID of the clock. + * + * Remove the clock represented by @con_id from the list of clocks used for + * the runtime PM of @dev. + */ +void pm_runtime_clk_remove(struct device *dev, const char *con_id) +{ + struct pm_runtime_clk_data *prd = __to_prd(dev); + struct pm_clock_entry *ce; + + if (!prd) + return; + + mutex_lock(&prd->lock); + + list_for_each_entry(ce, &prd->clock_list, node) { + if (!con_id && !ce->con_id) { + __pm_runtime_clk_remove(ce); + break; + } else if (!con_id || !ce->con_id) { + continue; + } else if (!strcmp(con_id, ce->con_id)) { + __pm_runtime_clk_remove(ce); + break; + } + } + + mutex_unlock(&prd->lock); +} + +/** + * pm_runtime_clk_init - Initialize a device's list of runtime PM clocks. + * @dev: Device to initialize the list of runtime PM clocks for. + * + * Allocate a struct pm_runtime_clk_data object, initialize its lock member and + * make the @dev's power.subsys_data field point to it. + */ +int pm_runtime_clk_init(struct device *dev) +{ + struct pm_runtime_clk_data *prd; + + prd = kzalloc(sizeof(*prd), GFP_KERNEL); + if (!prd) { + dev_err(dev, "Not enough memory fo runtime PM data.\n"); + return -ENOMEM; + } + + INIT_LIST_HEAD(&prd->clock_list); + mutex_init(&prd->lock); + dev->power.subsys_data = prd; + return 0; +} + +/** + * pm_runtime_clk_destroy - Destroy a device's list of runtime PM clocks. + * @dev: Device to destroy the list of runtime PM clocks for. + * + * Clear the @dev's power.subsys_data field, remove the list of clock entries + * from the struct pm_runtime_clk_data object pointed to by it before and free + * that object. + */ +void pm_runtime_clk_destroy(struct device *dev) +{ + struct pm_runtime_clk_data *prd = __to_prd(dev); + struct pm_clock_entry *ce, *c; + + if (!prd) + return; + + dev->power.subsys_data = NULL; + + mutex_lock(&prd->lock); + + list_for_each_entry_safe_reverse(ce, c, &prd->clock_list, node) + __pm_runtime_clk_remove(ce); + + mutex_unlock(&prd->lock); + + kfree(prd); +} + +/** + * pm_runtime_clk_acquire - Acquire a device clock. + * @dev: Device whose clock is to be acquired. + * @con_id: Connection ID of the clock. + */ +static void pm_runtime_clk_acquire(struct device *dev, + struct pm_clock_entry *ce) +{ + ce->clk = clk_get(dev, ce->con_id); + if (IS_ERR(ce->clk)) { + ce->status = PCE_STATUS_ERROR; + } else { + ce->status = PCE_STATUS_ACQUIRED; + dev_dbg(dev, "Clock %s managed by runtime PM.\n", ce->con_id); + } +} + +/** + * pm_runtime_clk_suspend - Disable clocks in a device's runtime PM clock list. + * @dev: Device to disable the clocks for. + */ +int pm_runtime_clk_suspend(struct device *dev) +{ + struct pm_runtime_clk_data *prd = __to_prd(dev); + struct pm_clock_entry *ce; + + dev_dbg(dev, "%s()\n", __func__); + + if (!prd) + return 0; + + mutex_lock(&prd->lock); + + list_for_each_entry_reverse(ce, &prd->clock_list, node) { + if (ce->status == PCE_STATUS_NONE) + pm_runtime_clk_acquire(dev, ce); + + if (ce->status < PCE_STATUS_ERROR) { + clk_disable(ce->clk); + ce->status = PCE_STATUS_ACQUIRED; + } + } + + mutex_unlock(&prd->lock); + + return 0; +} + +/** + * pm_runtime_clk_resume - Enable clocks in a device's runtime PM clock list. + * @dev: Device to enable the clocks for. + */ +int pm_runtime_clk_resume(struct device *dev) +{ + struct pm_runtime_clk_data *prd = __to_prd(dev); + struct pm_clock_entry *ce; + + dev_dbg(dev, "%s()\n", __func__); + + if (!prd) + return 0; + + mutex_lock(&prd->lock); + + list_for_each_entry(ce, &prd->clock_list, node) { + if (ce->status == PCE_STATUS_NONE) + pm_runtime_clk_acquire(dev, ce); + + if (ce->status < PCE_STATUS_ERROR) { + clk_enable(ce->clk); + ce->status = PCE_STATUS_ENABLED; + } + } + + mutex_unlock(&prd->lock); + + return 0; +} + +/** + * pm_runtime_clk_notify - Notify routine for device addition and removal. + * @nb: Notifier block object this function is a member of. + * @action: Operation being carried out by the caller. + * @data: Device the routine is being run for. + * + * For this function to work, @nb must be a member of an object of type + * struct pm_clk_notifier_block containing all of the requisite data. + * Specifically, the pwr_domain member of that object is copied to the device's + * pwr_domain field and its con_ids member is used to populate the device's list + * of runtime PM clocks, depending on @action. + * + * If the device's pwr_domain field is already populated with a value different + * from the one stored in the struct pm_clk_notifier_block object, the function + * does nothing. + */ +static int pm_runtime_clk_notify(struct notifier_block *nb, + unsigned long action, void *data) +{ + struct pm_clk_notifier_block *clknb; + struct device *dev = data; + char *con_id; + int error; + + dev_dbg(dev, "%s() %ld\n", __func__, action); + + clknb = container_of(nb, struct pm_clk_notifier_block, nb); + + switch (action) { + case BUS_NOTIFY_ADD_DEVICE: + if (dev->pwr_domain) + break; + + error = pm_runtime_clk_init(dev); + if (error) + break; + + dev->pwr_domain = clknb->pwr_domain; + if (clknb->con_ids[0]) { + for (con_id = clknb->con_ids[0]; *con_id; con_id++) + pm_runtime_clk_add(dev, con_id); + } else { + pm_runtime_clk_add(dev, NULL); + } + + break; + case BUS_NOTIFY_DEL_DEVICE: + if (dev->pwr_domain != clknb->pwr_domain) + break; + + dev->pwr_domain = NULL; + pm_runtime_clk_destroy(dev); + break; + } + + return 0; +} + +#else /* !CONFIG_PM_RUNTIME */ + +/** + * enable_clock - Enable a device clock. + * @dev: Device whose clock is to be enabled. + * @con_id: Connection ID of the clock. + */ +static void enable_clock(struct device *dev, const char *con_id) +{ + struct clk *clk; + + clk = clk_get(dev, con_id); + if (!IS_ERR(clk)) { + clk_enable(clk); + clk_put(clk); + dev_info(dev, "Runtime PM disabled, clock forced on.\n"); + } +} + +/** + * disable_clock - Disable a device clock. + * @dev: Device whose clock is to be disabled. + * @con_id: Connection ID of the clock. + */ +static void disable_clock(struct device *dev, const char *con_id) +{ + struct clk *clk; + + clk = clk_get(dev, con_id); + if (!IS_ERR(clk)) { + clk_disable(clk); + clk_put(clk); + dev_info(dev, "Runtime PM disabled, clock forced off.\n"); + } +} + +/** + * pm_runtime_clk_notify - Notify routine for device addition and removal. + * @nb: Notifier block object this function is a member of. + * @action: Operation being carried out by the caller. + * @data: Device the routine is being run for. + * + * For this function to work, @nb must be a member of an object of type + * struct pm_clk_notifier_block containing all of the requisite data. + * Specifically, the con_ids member of that object is used to enable or disable + * the device's clocks, depending on @action. + */ +static int pm_runtime_clk_notify(struct notifier_block *nb, + unsigned long action, void *data) +{ + struct pm_clk_notifier_block *clknb; + struct device *dev = data; + + dev_dbg(dev, "%s() %ld\n", __func__, action); + + clknb = container_of(nb, struct pm_clk_notifier_block, nb); + + switch (action) { + case BUS_NOTIFY_ADD_DEVICE: + if (clknb->con_ids[0]) { + for (con_id = clknb->con_ids[0]; *con_id; con_id++) + enable_clock(dev, con_id); + } else { + enable_clock(dev, NULL); + } + break; + case BUS_NOTIFY_DEL_DEVICE: + if (clknb->con_ids[0]) { + for (con_id = clknb->con_ids[0]; *con_id; con_id++) + disable_clock(dev, con_id); + } else { + disable_clock(dev, NULL); + } + break; + } + + return 0; +} + +#endif /* !CONFIG_PM_RUNTIME */ + +/** + * pm_runtime_clk_add_notifier - Add bus type notifier for runtime PM clocks. + * @bus: Bus type to add the notifier to. + * @clknb: Notifier to be added to the given bus type. + * + * The nb member of @clknb is not expected to be initialized and its + * notifier_call member will be replaced with pm_runtime_clk_notify(). However, + * the remaining members of @clknb should be populated prior to calling this + * routine. + */ +void pm_runtime_clk_add_notifier(struct bus_type *bus, + struct pm_clk_notifier_block *clknb) +{ + if (!bus || !clknb) + return; + + clknb->nb.notifier_call = pm_runtime_clk_notify; + bus_register_notifier(bus, &clknb->nb); +} diff --git a/include/linux/pm_runtime.h b/include/linux/pm_runtime.h index 8de9aa6..878cf84 100644 --- a/include/linux/pm_runtime.h +++ b/include/linux/pm_runtime.h @@ -245,4 +245,46 @@ static inline void pm_runtime_dont_use_autosuspend(struct device *dev) __pm_runtime_use_autosuspend(dev, false); } +struct pm_clk_notifier_block { + struct notifier_block nb; + struct dev_power_domain *pwr_domain; + char *con_ids[]; +}; + +#ifdef CONFIG_PM_RUNTIME_CLK +extern int pm_runtime_clk_init(struct device *dev); +extern void pm_runtime_clk_destroy(struct device *dev); +extern int pm_runtime_clk_add(struct device *dev, const char *con_id); +extern void pm_runtime_clk_remove(struct device *dev, const char *con_id); +extern int pm_runtime_clk_suspend(struct device *dev); +extern int pm_runtime_clk_resume(struct device *dev); +#else +static inline int pm_runtime_clk_init(struct device *dev) +{ + return -EINVAL; +} +static inline void pm_runtime_clk_destroy(struct device *dev) +{ +} +static inline int pm_runtime_clk_add(struct device *dev, const char *con_id) +{ + return -EINVAL; +} +static inline void pm_runtime_clk_remove(struct device *dev, const char *con_id) +{ +} +#define pm_runtime_clock_suspend NULL +#define pm_runtime_clock_resume NULL +#endif + +#ifdef CONFIG_HAVE_CLK +extern void pm_runtime_clk_add_notifier(struct bus_type *bus, + struct pm_clk_notifier_block *clknb); +#else +static inline void pm_runtime_clk_add_notifier(struct bus_type *bus, + struct pm_clk_notifier_block *clknb) +{ +} +#endif + #endif diff --git a/kernel/power/Kconfig b/kernel/power/Kconfig index 6de9a8f..d74ad4a 100644 --- a/kernel/power/Kconfig +++ b/kernel/power/Kconfig @@ -229,3 +229,7 @@ config PM_OPP representing individual voltage domains and provides SOC implementations a ready to use framework to manage OPPs. For more information, read + +config PM_RUNTIME_CLK + def_bool y + depends on PM_RUNTIME && HAVE_CLK -- cgit v0.10.2 From 74c5b31c6618f01079212332b2e5f6c42f2d6307 Mon Sep 17 00:00:00 2001 From: Mike Waychison Date: Fri, 29 Apr 2011 17:39:19 -0700 Subject: driver: Google EFI SMI The "gsmi" driver bridges userland with firmware specific routines for accessing hardware. Currently, this driver only supports NVRAM and eventlog information. Deprecated functions have been removed from the driver, though their op-codes are left in place so that they are not re-used. This driver works by trampolining into the firmware via the smi_command outlined in the FADT table. Three protocols are used due to various limitations over time, but all are included herein. This driver should only ever load on Google boards, identified by either a "Google, Inc." board vendor string in DMI, or "GOOGLE" in the OEM strings of the FADT ACPI table. This logic happens in gsmi_system_valid(). Signed-off-by: Duncan Laurie Signed-off-by: Aaron Durbin Signed-off-by: Mike Waychison Signed-off-by: Greg Kroah-Hartman diff --git a/Documentation/ABI/testing/sysfs-firmware-gsmi b/Documentation/ABI/testing/sysfs-firmware-gsmi new file mode 100644 index 0000000..0faa0aa --- /dev/null +++ b/Documentation/ABI/testing/sysfs-firmware-gsmi @@ -0,0 +1,58 @@ +What: /sys/firmware/gsmi +Date: March 2011 +Contact: Mike Waychison +Description: + Some servers used internally at Google have firmware + that provides callback functionality via explicit SMI + triggers. Some of the callbacks are similar to those + provided by the EFI runtime services page, but due to + historical reasons this different entry-point has been + used. + + The gsmi driver implements the kernel's abstraction for + these firmware callbacks. Currently, this functionality + is limited to handling the system event log and getting + access to EFI-style variables stored in nvram. + + Layout: + + /sys/firmware/gsmi/vars: + + This directory has the same layout (and + underlying implementation as /sys/firmware/efi/vars. + See Documentation/ABI/*/sysfs-firmware-efi-vars + for more information on how to interact with + this structure. + + /sys/firmware/gsmi/append_to_eventlog - write-only: + + This file takes a binary blob and passes it onto + the firmware to be timestamped and appended to + the system eventlog. The binary format is + interpreted by the firmware and may change from + platform to platform. The only kernel-enforced + requirement is that the blob be prefixed with a + 32bit host-endian type used as part of the + firmware call. + + /sys/firmware/gsmi/clear_config - write-only: + + Writing any value to this file will cause the + entire firmware configuration to be reset to + "factory defaults". Callers should assume that + a reboot is required for the configuration to be + cleared. + + /sys/firmware/gsmi/clear_eventlog - write-only: + + This file is used to clear out a portion/the + whole of the system event log. Values written + should be values between 1 and 100 inclusive (in + ASCII) representing the fraction of the log to + clear. Not all platforms support fractional + clearing though, and this writes to this file + will error out if the firmware doesn't like your + submitted fraction. + + Callers should assume that a reboot is needed + for this operation to complete. diff --git a/drivers/firmware/Kconfig b/drivers/firmware/Kconfig index b3a25a5..efba163 100644 --- a/drivers/firmware/Kconfig +++ b/drivers/firmware/Kconfig @@ -157,4 +157,6 @@ config SIGMA If unsure, say N here. Drivers that need these helpers will select this option automatically. +source "drivers/firmware/google/Kconfig" + endmenu diff --git a/drivers/firmware/Makefile b/drivers/firmware/Makefile index 00bb0b8..d7d6009 100644 --- a/drivers/firmware/Makefile +++ b/drivers/firmware/Makefile @@ -13,3 +13,5 @@ obj-$(CONFIG_ISCSI_IBFT_FIND) += iscsi_ibft_find.o obj-$(CONFIG_ISCSI_IBFT) += iscsi_ibft.o obj-$(CONFIG_FIRMWARE_MEMMAP) += memmap.o obj-$(CONFIG_SIGMA) += sigma.o + +obj-y += google/ diff --git a/drivers/firmware/google/Kconfig b/drivers/firmware/google/Kconfig new file mode 100644 index 0000000..4a03835 --- /dev/null +++ b/drivers/firmware/google/Kconfig @@ -0,0 +1,9 @@ +config GOOGLE_SMI + tristate "SMI interface for Google platforms" + depends on ACPI && DMI + select EFI_VARS + help + Say Y here if you want to enable SMI callbacks for Google + platforms. This provides an interface for writing to and + clearing the EFI event log and reading and writing NVRAM + variables. diff --git a/drivers/firmware/google/Makefile b/drivers/firmware/google/Makefile new file mode 100644 index 0000000..fb127d7 --- /dev/null +++ b/drivers/firmware/google/Makefile @@ -0,0 +1,2 @@ + +obj-$(CONFIG_GOOGLE_SMI) += gsmi.o diff --git a/drivers/firmware/google/gsmi.c b/drivers/firmware/google/gsmi.c new file mode 100644 index 0000000..fa7f0b3 --- /dev/null +++ b/drivers/firmware/google/gsmi.c @@ -0,0 +1,940 @@ +/* + * Copyright 2010 Google Inc. All Rights Reserved. + * Author: dlaurie@google.com (Duncan Laurie) + * + * Re-worked to expose sysfs APIs by mikew@google.com (Mike Waychison) + * + * EFI SMI interface for Google platforms + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define GSMI_SHUTDOWN_CLEAN 0 /* Clean Shutdown */ +/* TODO(mikew@google.com): Tie in HARDLOCKUP_DETECTOR with NMIWDT */ +#define GSMI_SHUTDOWN_NMIWDT 1 /* NMI Watchdog */ +#define GSMI_SHUTDOWN_PANIC 2 /* Panic */ +#define GSMI_SHUTDOWN_OOPS 3 /* Oops */ +#define GSMI_SHUTDOWN_DIE 4 /* Die -- No longer meaningful */ +#define GSMI_SHUTDOWN_MCE 5 /* Machine Check */ +#define GSMI_SHUTDOWN_SOFTWDT 6 /* Software Watchdog */ +#define GSMI_SHUTDOWN_MBE 7 /* Uncorrected ECC */ +#define GSMI_SHUTDOWN_TRIPLE 8 /* Triple Fault */ + +#define DRIVER_VERSION "1.0" +#define GSMI_GUID_SIZE 16 +#define GSMI_BUF_SIZE 1024 +#define GSMI_BUF_ALIGN sizeof(u64) +#define GSMI_CALLBACK 0xef + +/* SMI return codes */ +#define GSMI_SUCCESS 0x00 +#define GSMI_UNSUPPORTED2 0x03 +#define GSMI_LOG_FULL 0x0b +#define GSMI_VAR_NOT_FOUND 0x0e +#define GSMI_HANDSHAKE_SPIN 0x7d +#define GSMI_HANDSHAKE_CF 0x7e +#define GSMI_HANDSHAKE_NONE 0x7f +#define GSMI_INVALID_PARAMETER 0x82 +#define GSMI_UNSUPPORTED 0x83 +#define GSMI_BUFFER_TOO_SMALL 0x85 +#define GSMI_NOT_READY 0x86 +#define GSMI_DEVICE_ERROR 0x87 +#define GSMI_NOT_FOUND 0x8e + +#define QUIRKY_BOARD_HASH 0x78a30a50 + +/* Internally used commands passed to the firmware */ +#define GSMI_CMD_GET_NVRAM_VAR 0x01 +#define GSMI_CMD_GET_NEXT_VAR 0x02 +#define GSMI_CMD_SET_NVRAM_VAR 0x03 +#define GSMI_CMD_SET_EVENT_LOG 0x08 +#define GSMI_CMD_CLEAR_EVENT_LOG 0x09 +#define GSMI_CMD_CLEAR_CONFIG 0x20 +#define GSMI_CMD_HANDSHAKE_TYPE 0xC1 + +/* Magic entry type for kernel events */ +#define GSMI_LOG_ENTRY_TYPE_KERNEL 0xDEAD + +/* SMI buffers must be in 32bit physical address space */ +struct gsmi_buf { + u8 *start; /* start of buffer */ + size_t length; /* length of buffer */ + dma_addr_t handle; /* dma allocation handle */ + u32 address; /* physical address of buffer */ +}; + +struct gsmi_device { + struct platform_device *pdev; /* platform device */ + struct gsmi_buf *name_buf; /* variable name buffer */ + struct gsmi_buf *data_buf; /* generic data buffer */ + struct gsmi_buf *param_buf; /* parameter buffer */ + spinlock_t lock; /* serialize access to SMIs */ + u16 smi_cmd; /* SMI command port */ + int handshake_type; /* firmware handler interlock type */ + struct dma_pool *dma_pool; /* DMA buffer pool */ +} gsmi_dev; + +/* Packed structures for communicating with the firmware */ +struct gsmi_nvram_var_param { + efi_guid_t guid; + u32 name_ptr; + u32 attributes; + u32 data_len; + u32 data_ptr; +} __packed; + +struct gsmi_get_next_var_param { + u8 guid[GSMI_GUID_SIZE]; + u32 name_ptr; + u32 name_len; +} __packed; + +struct gsmi_set_eventlog_param { + u32 data_ptr; + u32 data_len; + u32 type; +} __packed; + +/* Event log formats */ +struct gsmi_log_entry_type_1 { + u16 type; + u32 instance; +} __packed; + + +/* + * Some platforms don't have explicit SMI handshake + * and need to wait for SMI to complete. + */ +#define GSMI_DEFAULT_SPINCOUNT 0x10000 +static unsigned int spincount = GSMI_DEFAULT_SPINCOUNT; +module_param(spincount, uint, 0600); +MODULE_PARM_DESC(spincount, + "The number of loop iterations to use when using the spin handshake."); + +static struct gsmi_buf *gsmi_buf_alloc(void) +{ + struct gsmi_buf *smibuf; + + smibuf = kzalloc(sizeof(*smibuf), GFP_KERNEL); + if (!smibuf) { + printk(KERN_ERR "gsmi: out of memory\n"); + return NULL; + } + + /* allocate buffer in 32bit address space */ + smibuf->start = dma_pool_alloc(gsmi_dev.dma_pool, GFP_KERNEL, + &smibuf->handle); + if (!smibuf->start) { + printk(KERN_ERR "gsmi: failed to allocate name buffer\n"); + kfree(smibuf); + return NULL; + } + + /* fill in the buffer handle */ + smibuf->length = GSMI_BUF_SIZE; + smibuf->address = (u32)virt_to_phys(smibuf->start); + + return smibuf; +} + +static void gsmi_buf_free(struct gsmi_buf *smibuf) +{ + if (smibuf) { + if (smibuf->start) + dma_pool_free(gsmi_dev.dma_pool, smibuf->start, + smibuf->handle); + kfree(smibuf); + } +} + +/* + * Make a call to gsmi func(sub). GSMI error codes are translated to + * in-kernel errnos (0 on success, -ERRNO on error). + */ +static int gsmi_exec(u8 func, u8 sub) +{ + u16 cmd = (sub << 8) | func; + u16 result = 0; + int rc = 0; + + /* + * AH : Subfunction number + * AL : Function number + * EBX : Parameter block address + * DX : SMI command port + * + * Three protocols here. See also the comment in gsmi_init(). + */ + if (gsmi_dev.handshake_type == GSMI_HANDSHAKE_CF) { + /* + * If handshake_type == HANDSHAKE_CF then set CF on the + * way in and wait for the handler to clear it; this avoids + * corrupting register state on those chipsets which have + * a delay between writing the SMI trigger register and + * entering SMM. + */ + asm volatile ( + "stc\n" + "outb %%al, %%dx\n" + "1: jc 1b\n" + : "=a" (result) + : "0" (cmd), + "d" (gsmi_dev.smi_cmd), + "b" (gsmi_dev.param_buf->address) + : "memory", "cc" + ); + } else if (gsmi_dev.handshake_type == GSMI_HANDSHAKE_SPIN) { + /* + * If handshake_type == HANDSHAKE_SPIN we spin a + * hundred-ish usecs to ensure the SMI has triggered. + */ + asm volatile ( + "outb %%al, %%dx\n" + "1: loop 1b\n" + : "=a" (result) + : "0" (cmd), + "d" (gsmi_dev.smi_cmd), + "b" (gsmi_dev.param_buf->address), + "c" (spincount) + : "memory", "cc" + ); + } else { + /* + * If handshake_type == HANDSHAKE_NONE we do nothing; + * either we don't need to or it's legacy firmware that + * doesn't understand the CF protocol. + */ + asm volatile ( + "outb %%al, %%dx\n\t" + : "=a" (result) + : "0" (cmd), + "d" (gsmi_dev.smi_cmd), + "b" (gsmi_dev.param_buf->address) + : "memory", "cc" + ); + } + + /* check return code from SMI handler */ + switch (result) { + case GSMI_SUCCESS: + break; + case GSMI_VAR_NOT_FOUND: + /* not really an error, but let the caller know */ + rc = 1; + break; + case GSMI_INVALID_PARAMETER: + printk(KERN_ERR "gsmi: exec 0x%04x: Invalid parameter\n", cmd); + rc = -EINVAL; + break; + case GSMI_BUFFER_TOO_SMALL: + printk(KERN_ERR "gsmi: exec 0x%04x: Buffer too small\n", cmd); + rc = -ENOMEM; + break; + case GSMI_UNSUPPORTED: + case GSMI_UNSUPPORTED2: + if (sub != GSMI_CMD_HANDSHAKE_TYPE) + printk(KERN_ERR "gsmi: exec 0x%04x: Not supported\n", + cmd); + rc = -ENOSYS; + break; + case GSMI_NOT_READY: + printk(KERN_ERR "gsmi: exec 0x%04x: Not ready\n", cmd); + rc = -EBUSY; + break; + case GSMI_DEVICE_ERROR: + printk(KERN_ERR "gsmi: exec 0x%04x: Device error\n", cmd); + rc = -EFAULT; + break; + case GSMI_NOT_FOUND: + printk(KERN_ERR "gsmi: exec 0x%04x: Data not found\n", cmd); + rc = -ENOENT; + break; + case GSMI_LOG_FULL: + printk(KERN_ERR "gsmi: exec 0x%04x: Log full\n", cmd); + rc = -ENOSPC; + break; + case GSMI_HANDSHAKE_CF: + case GSMI_HANDSHAKE_SPIN: + case GSMI_HANDSHAKE_NONE: + rc = result; + break; + default: + printk(KERN_ERR "gsmi: exec 0x%04x: Unknown error 0x%04x\n", + cmd, result); + rc = -ENXIO; + } + + return rc; +} + +/* Return the number of unicode characters in data */ +static size_t +utf16_strlen(efi_char16_t *data, unsigned long maxlength) +{ + unsigned long length = 0; + + while (*data++ != 0 && length < maxlength) + length++; + return length; +} + +static efi_status_t gsmi_get_variable(efi_char16_t *name, + efi_guid_t *vendor, u32 *attr, + unsigned long *data_size, + void *data) +{ + struct gsmi_nvram_var_param param = { + .name_ptr = gsmi_dev.name_buf->address, + .data_ptr = gsmi_dev.data_buf->address, + .data_len = (u32)*data_size, + }; + efi_status_t ret = EFI_SUCCESS; + unsigned long flags; + size_t name_len = utf16_strlen(name, GSMI_BUF_SIZE / 2); + int rc; + + if (name_len >= GSMI_BUF_SIZE / 2) + return EFI_BAD_BUFFER_SIZE; + + spin_lock_irqsave(&gsmi_dev.lock, flags); + + /* Vendor guid */ + memcpy(¶m.guid, vendor, sizeof(param.guid)); + + /* variable name, already in UTF-16 */ + memset(gsmi_dev.name_buf->start, 0, gsmi_dev.name_buf->length); + memcpy(gsmi_dev.name_buf->start, name, name_len * 2); + + /* data pointer */ + memset(gsmi_dev.data_buf->start, 0, gsmi_dev.data_buf->length); + + /* parameter buffer */ + memset(gsmi_dev.param_buf->start, 0, gsmi_dev.param_buf->length); + memcpy(gsmi_dev.param_buf->start, ¶m, sizeof(param)); + + rc = gsmi_exec(GSMI_CALLBACK, GSMI_CMD_GET_NVRAM_VAR); + if (rc < 0) { + printk(KERN_ERR "gsmi: Get Variable failed\n"); + ret = EFI_LOAD_ERROR; + } else if (rc == 1) { + /* variable was not found */ + ret = EFI_NOT_FOUND; + } else { + /* Get the arguments back */ + memcpy(¶m, gsmi_dev.param_buf->start, sizeof(param)); + + /* The size reported is the min of all of our buffers */ + *data_size = min(*data_size, gsmi_dev.data_buf->length); + *data_size = min_t(unsigned long, *data_size, param.data_len); + + /* Copy data back to return buffer. */ + memcpy(data, gsmi_dev.data_buf->start, *data_size); + + /* All variables are have the following attributes */ + *attr = EFI_VARIABLE_NON_VOLATILE | + EFI_VARIABLE_BOOTSERVICE_ACCESS | + EFI_VARIABLE_RUNTIME_ACCESS; + } + + spin_unlock_irqrestore(&gsmi_dev.lock, flags); + + return ret; +} + +static efi_status_t gsmi_get_next_variable(unsigned long *name_size, + efi_char16_t *name, + efi_guid_t *vendor) +{ + struct gsmi_get_next_var_param param = { + .name_ptr = gsmi_dev.name_buf->address, + .name_len = gsmi_dev.name_buf->length, + }; + efi_status_t ret = EFI_SUCCESS; + int rc; + unsigned long flags; + + /* For the moment, only support buffers that exactly match in size */ + if (*name_size != GSMI_BUF_SIZE) + return EFI_BAD_BUFFER_SIZE; + + /* Let's make sure the thing is at least null-terminated */ + if (utf16_strlen(name, GSMI_BUF_SIZE / 2) == GSMI_BUF_SIZE / 2) + return EFI_INVALID_PARAMETER; + + spin_lock_irqsave(&gsmi_dev.lock, flags); + + /* guid */ + memcpy(¶m.guid, vendor, sizeof(param.guid)); + + /* variable name, already in UTF-16 */ + memcpy(gsmi_dev.name_buf->start, name, *name_size); + + /* parameter buffer */ + memset(gsmi_dev.param_buf->start, 0, gsmi_dev.param_buf->length); + memcpy(gsmi_dev.param_buf->start, ¶m, sizeof(param)); + + rc = gsmi_exec(GSMI_CALLBACK, GSMI_CMD_GET_NEXT_VAR); + if (rc < 0) { + printk(KERN_ERR "gsmi: Get Next Variable Name failed\n"); + ret = EFI_LOAD_ERROR; + } else if (rc == 1) { + /* variable not found -- end of list */ + ret = EFI_NOT_FOUND; + } else { + /* copy variable data back to return buffer */ + memcpy(¶m, gsmi_dev.param_buf->start, sizeof(param)); + + /* Copy the name back */ + memcpy(name, gsmi_dev.name_buf->start, GSMI_BUF_SIZE); + *name_size = utf16_strlen(name, GSMI_BUF_SIZE / 2) * 2; + + /* copy guid to return buffer */ + memcpy(vendor, ¶m.guid, sizeof(param.guid)); + ret = EFI_SUCCESS; + } + + spin_unlock_irqrestore(&gsmi_dev.lock, flags); + + return ret; +} + +static efi_status_t gsmi_set_variable(efi_char16_t *name, + efi_guid_t *vendor, + unsigned long attr, + unsigned long data_size, + void *data) +{ + struct gsmi_nvram_var_param param = { + .name_ptr = gsmi_dev.name_buf->address, + .data_ptr = gsmi_dev.data_buf->address, + .data_len = (u32)data_size, + .attributes = EFI_VARIABLE_NON_VOLATILE | + EFI_VARIABLE_BOOTSERVICE_ACCESS | + EFI_VARIABLE_RUNTIME_ACCESS, + }; + size_t name_len = utf16_strlen(name, GSMI_BUF_SIZE / 2); + efi_status_t ret = EFI_SUCCESS; + int rc; + unsigned long flags; + + if (name_len >= GSMI_BUF_SIZE / 2) + return EFI_BAD_BUFFER_SIZE; + + spin_lock_irqsave(&gsmi_dev.lock, flags); + + /* guid */ + memcpy(¶m.guid, vendor, sizeof(param.guid)); + + /* variable name, already in UTF-16 */ + memset(gsmi_dev.name_buf->start, 0, gsmi_dev.name_buf->length); + memcpy(gsmi_dev.name_buf->start, name, name_len * 2); + + /* data pointer */ + memset(gsmi_dev.data_buf->start, 0, gsmi_dev.data_buf->length); + memcpy(gsmi_dev.data_buf->start, data, data_size); + + /* parameter buffer */ + memset(gsmi_dev.param_buf->start, 0, gsmi_dev.param_buf->length); + memcpy(gsmi_dev.param_buf->start, ¶m, sizeof(param)); + + rc = gsmi_exec(GSMI_CALLBACK, GSMI_CMD_SET_NVRAM_VAR); + if (rc < 0) { + printk(KERN_ERR "gsmi: Set Variable failed\n"); + ret = EFI_INVALID_PARAMETER; + } + + spin_unlock_irqrestore(&gsmi_dev.lock, flags); + + return ret; +} + +static const struct efivar_operations efivar_ops = { + .get_variable = gsmi_get_variable, + .set_variable = gsmi_set_variable, + .get_next_variable = gsmi_get_next_variable, +}; + +static ssize_t eventlog_write(struct file *filp, struct kobject *kobj, + struct bin_attribute *bin_attr, + char *buf, loff_t pos, size_t count) +{ + struct gsmi_set_eventlog_param param = { + .data_ptr = gsmi_dev.data_buf->address, + }; + int rc = 0; + unsigned long flags; + + /* Pull the type out */ + if (count < sizeof(u32)) + return -EINVAL; + param.type = *(u32 *)buf; + count -= sizeof(u32); + buf += sizeof(u32); + + /* The remaining buffer is the data payload */ + if (count > gsmi_dev.data_buf->length) + return -EINVAL; + param.data_len = count - sizeof(u32); + + spin_lock_irqsave(&gsmi_dev.lock, flags); + + /* data pointer */ + memset(gsmi_dev.data_buf->start, 0, gsmi_dev.data_buf->length); + memcpy(gsmi_dev.data_buf->start, buf, param.data_len); + + /* parameter buffer */ + memset(gsmi_dev.param_buf->start, 0, gsmi_dev.param_buf->length); + memcpy(gsmi_dev.param_buf->start, ¶m, sizeof(param)); + + rc = gsmi_exec(GSMI_CALLBACK, GSMI_CMD_SET_EVENT_LOG); + if (rc < 0) + printk(KERN_ERR "gsmi: Set Event Log failed\n"); + + spin_unlock_irqrestore(&gsmi_dev.lock, flags); + + return rc; + +} + +static struct bin_attribute eventlog_bin_attr = { + .attr = {.name = "append_to_eventlog", .mode = 0200}, + .write = eventlog_write, +}; + +static ssize_t gsmi_clear_eventlog_store(struct kobject *kobj, + struct kobj_attribute *attr, + const char *buf, size_t count) +{ + int rc; + unsigned long flags; + unsigned long val; + struct { + u32 percentage; + u32 data_type; + } param; + + rc = strict_strtoul(buf, 0, &val); + if (rc) + return rc; + + /* + * Value entered is a percentage, 0 through 100, anything else + * is invalid. + */ + if (val > 100) + return -EINVAL; + + /* data_type here selects the smbios event log. */ + param.percentage = val; + param.data_type = 0; + + spin_lock_irqsave(&gsmi_dev.lock, flags); + + /* parameter buffer */ + memset(gsmi_dev.param_buf->start, 0, gsmi_dev.param_buf->length); + memcpy(gsmi_dev.param_buf->start, ¶m, sizeof(param)); + + rc = gsmi_exec(GSMI_CALLBACK, GSMI_CMD_CLEAR_EVENT_LOG); + + spin_unlock_irqrestore(&gsmi_dev.lock, flags); + + if (rc) + return rc; + return count; +} + +static struct kobj_attribute gsmi_clear_eventlog_attr = { + .attr = {.name = "clear_eventlog", .mode = 0200}, + .store = gsmi_clear_eventlog_store, +}; + +static ssize_t gsmi_clear_config_store(struct kobject *kobj, + struct kobj_attribute *attr, + const char *buf, size_t count) +{ + int rc; + unsigned long flags; + + spin_lock_irqsave(&gsmi_dev.lock, flags); + + /* clear parameter buffer */ + memset(gsmi_dev.param_buf->start, 0, gsmi_dev.param_buf->length); + + rc = gsmi_exec(GSMI_CALLBACK, GSMI_CMD_CLEAR_CONFIG); + + spin_unlock_irqrestore(&gsmi_dev.lock, flags); + + if (rc) + return rc; + return count; +} + +static struct kobj_attribute gsmi_clear_config_attr = { + .attr = {.name = "clear_config", .mode = 0200}, + .store = gsmi_clear_config_store, +}; + +static const struct attribute *gsmi_attrs[] = { + &gsmi_clear_config_attr.attr, + &gsmi_clear_eventlog_attr.attr, + NULL, +}; + +static int gsmi_shutdown_reason(int reason) +{ + struct gsmi_log_entry_type_1 entry = { + .type = GSMI_LOG_ENTRY_TYPE_KERNEL, + .instance = reason, + }; + struct gsmi_set_eventlog_param param = { + .data_len = sizeof(entry), + .type = 1, + }; + static int saved_reason; + int rc = 0; + unsigned long flags; + + /* avoid duplicate entries in the log */ + if (saved_reason & (1 << reason)) + return 0; + + spin_lock_irqsave(&gsmi_dev.lock, flags); + + saved_reason |= (1 << reason); + + /* data pointer */ + memset(gsmi_dev.data_buf->start, 0, gsmi_dev.data_buf->length); + memcpy(gsmi_dev.data_buf->start, &entry, sizeof(entry)); + + /* parameter buffer */ + param.data_ptr = gsmi_dev.data_buf->address; + memset(gsmi_dev.param_buf->start, 0, gsmi_dev.param_buf->length); + memcpy(gsmi_dev.param_buf->start, ¶m, sizeof(param)); + + rc = gsmi_exec(GSMI_CALLBACK, GSMI_CMD_SET_EVENT_LOG); + + spin_unlock_irqrestore(&gsmi_dev.lock, flags); + + if (rc < 0) + printk(KERN_ERR "gsmi: Log Shutdown Reason failed\n"); + else + printk(KERN_EMERG "gsmi: Log Shutdown Reason 0x%02x\n", + reason); + + return rc; +} + +static int gsmi_reboot_callback(struct notifier_block *nb, + unsigned long reason, void *arg) +{ + gsmi_shutdown_reason(GSMI_SHUTDOWN_CLEAN); + return NOTIFY_DONE; +} + +static struct notifier_block gsmi_reboot_notifier = { + .notifier_call = gsmi_reboot_callback +}; + +static int gsmi_die_callback(struct notifier_block *nb, + unsigned long reason, void *arg) +{ + if (reason == DIE_OOPS) + gsmi_shutdown_reason(GSMI_SHUTDOWN_OOPS); + return NOTIFY_DONE; +} + +static struct notifier_block gsmi_die_notifier = { + .notifier_call = gsmi_die_callback +}; + +static int gsmi_panic_callback(struct notifier_block *nb, + unsigned long reason, void *arg) +{ + gsmi_shutdown_reason(GSMI_SHUTDOWN_PANIC); + return NOTIFY_DONE; +} + +static struct notifier_block gsmi_panic_notifier = { + .notifier_call = gsmi_panic_callback, +}; + +/* + * This hash function was blatantly copied from include/linux/hash.h. + * It is used by this driver to obfuscate a board name that requires a + * quirk within this driver. + * + * Please do not remove this copy of the function as any changes to the + * global utility hash_64() function would break this driver's ability + * to identify a board and provide the appropriate quirk -- mikew@google.com + */ +static u64 __init local_hash_64(u64 val, unsigned bits) +{ + u64 hash = val; + + /* Sigh, gcc can't optimise this alone like it does for 32 bits. */ + u64 n = hash; + n <<= 18; + hash -= n; + n <<= 33; + hash -= n; + n <<= 3; + hash += n; + n <<= 3; + hash -= n; + n <<= 4; + hash += n; + n <<= 2; + hash += n; + + /* High bits are more random, so use them. */ + return hash >> (64 - bits); +} + +static u32 __init hash_oem_table_id(char s[8]) +{ + u64 input; + memcpy(&input, s, 8); + return local_hash_64(input, 32); +} + +static struct dmi_system_id gsmi_dmi_table[] __initdata = { + { + .ident = "Google Board", + .matches = { + DMI_MATCH(DMI_BOARD_VENDOR, "Google, Inc."), + }, + }, + {} +}; +MODULE_DEVICE_TABLE(dmi, gsmi_dmi_table); + +static __init int gsmi_system_valid(void) +{ + u32 hash; + + if (!dmi_check_system(gsmi_dmi_table)) + return -ENODEV; + + /* + * Only newer firmware supports the gsmi interface. All older + * firmware that didn't support this interface used to plug the + * table name in the first four bytes of the oem_table_id field. + * Newer firmware doesn't do that though, so use that as the + * discriminant factor. We have to do this in order to + * whitewash our board names out of the public driver. + */ + if (!strncmp(acpi_gbl_FADT.header.oem_table_id, "FACP", 4)) { + printk(KERN_INFO "gsmi: Board is too old\n"); + return -ENODEV; + } + + /* Disable on board with 1.0 BIOS due to Google bug 2602657 */ + hash = hash_oem_table_id(acpi_gbl_FADT.header.oem_table_id); + if (hash == QUIRKY_BOARD_HASH) { + const char *bios_ver = dmi_get_system_info(DMI_BIOS_VERSION); + if (strncmp(bios_ver, "1.0", 3) == 0) { + pr_info("gsmi: disabled on this board's BIOS %s\n", + bios_ver); + return -ENODEV; + } + } + + /* check for valid SMI command port in ACPI FADT */ + if (acpi_gbl_FADT.smi_command == 0) { + pr_info("gsmi: missing smi_command\n"); + return -ENODEV; + } + + /* Found */ + return 0; +} + +static struct kobject *gsmi_kobj; +static struct efivars efivars; + +static __init int gsmi_init(void) +{ + unsigned long flags; + int ret; + + ret = gsmi_system_valid(); + if (ret) + return ret; + + gsmi_dev.smi_cmd = acpi_gbl_FADT.smi_command; + + /* register device */ + gsmi_dev.pdev = platform_device_register_simple("gsmi", -1, NULL, 0); + if (IS_ERR(gsmi_dev.pdev)) { + printk(KERN_ERR "gsmi: unable to register platform device\n"); + return PTR_ERR(gsmi_dev.pdev); + } + + /* SMI access needs to be serialized */ + spin_lock_init(&gsmi_dev.lock); + + /* SMI callbacks require 32bit addresses */ + gsmi_dev.pdev->dev.coherent_dma_mask = DMA_BIT_MASK(32); + gsmi_dev.pdev->dev.dma_mask = + &gsmi_dev.pdev->dev.coherent_dma_mask; + ret = -ENOMEM; + gsmi_dev.dma_pool = dma_pool_create("gsmi", &gsmi_dev.pdev->dev, + GSMI_BUF_SIZE, GSMI_BUF_ALIGN, 0); + if (!gsmi_dev.dma_pool) + goto out_err; + + /* + * pre-allocate buffers because sometimes we are called when + * this is not feasible: oops, panic, die, mce, etc + */ + gsmi_dev.name_buf = gsmi_buf_alloc(); + if (!gsmi_dev.name_buf) { + printk(KERN_ERR "gsmi: failed to allocate name buffer\n"); + goto out_err; + } + + gsmi_dev.data_buf = gsmi_buf_alloc(); + if (!gsmi_dev.data_buf) { + printk(KERN_ERR "gsmi: failed to allocate data buffer\n"); + goto out_err; + } + + gsmi_dev.param_buf = gsmi_buf_alloc(); + if (!gsmi_dev.param_buf) { + printk(KERN_ERR "gsmi: failed to allocate param buffer\n"); + goto out_err; + } + + /* + * Determine type of handshake used to serialize the SMI + * entry. See also gsmi_exec(). + * + * There's a "behavior" present on some chipsets where writing the + * SMI trigger register in the southbridge doesn't result in an + * immediate SMI. Rather, the processor can execute "a few" more + * instructions before the SMI takes effect. To ensure synchronous + * behavior, implement a handshake between the kernel driver and the + * firmware handler to spin until released. This ioctl determines + * the type of handshake. + * + * NONE: The firmware handler does not implement any + * handshake. Either it doesn't need to, or it's legacy firmware + * that doesn't know it needs to and never will. + * + * CF: The firmware handler will clear the CF in the saved + * state before returning. The driver may set the CF and test for + * it to clear before proceeding. + * + * SPIN: The firmware handler does not implement any handshake + * but the driver should spin for a hundred or so microseconds + * to ensure the SMI has triggered. + * + * Finally, the handler will return -ENOSYS if + * GSMI_CMD_HANDSHAKE_TYPE is unimplemented, which implies + * HANDSHAKE_NONE. + */ + spin_lock_irqsave(&gsmi_dev.lock, flags); + gsmi_dev.handshake_type = GSMI_HANDSHAKE_SPIN; + gsmi_dev.handshake_type = + gsmi_exec(GSMI_CALLBACK, GSMI_CMD_HANDSHAKE_TYPE); + if (gsmi_dev.handshake_type == -ENOSYS) + gsmi_dev.handshake_type = GSMI_HANDSHAKE_NONE; + spin_unlock_irqrestore(&gsmi_dev.lock, flags); + + /* Remove and clean up gsmi if the handshake could not complete. */ + if (gsmi_dev.handshake_type == -ENXIO) { + printk(KERN_INFO "gsmi version " DRIVER_VERSION + " failed to load\n"); + ret = -ENODEV; + goto out_err; + } + + printk(KERN_INFO "gsmi version " DRIVER_VERSION " loaded\n"); + + /* Register in the firmware directory */ + ret = -ENOMEM; + gsmi_kobj = kobject_create_and_add("gsmi", firmware_kobj); + if (!gsmi_kobj) { + printk(KERN_INFO "gsmi: Failed to create firmware kobj\n"); + goto out_err; + } + + /* Setup eventlog access */ + ret = sysfs_create_bin_file(gsmi_kobj, &eventlog_bin_attr); + if (ret) { + printk(KERN_INFO "gsmi: Failed to setup eventlog"); + goto out_err; + } + + /* Other attributes */ + ret = sysfs_create_files(gsmi_kobj, gsmi_attrs); + if (ret) { + printk(KERN_INFO "gsmi: Failed to add attrs"); + goto out_err; + } + + if (register_efivars(&efivars, &efivar_ops, gsmi_kobj)) { + printk(KERN_INFO "gsmi: Failed to register efivars\n"); + goto out_err; + } + + register_reboot_notifier(&gsmi_reboot_notifier); + register_die_notifier(&gsmi_die_notifier); + atomic_notifier_chain_register(&panic_notifier_list, + &gsmi_panic_notifier); + + return 0; + + out_err: + kobject_put(gsmi_kobj); + gsmi_buf_free(gsmi_dev.param_buf); + gsmi_buf_free(gsmi_dev.data_buf); + gsmi_buf_free(gsmi_dev.name_buf); + if (gsmi_dev.dma_pool) + dma_pool_destroy(gsmi_dev.dma_pool); + platform_device_unregister(gsmi_dev.pdev); + pr_info("gsmi: failed to load: %d\n", ret); + return ret; +} + +static void __exit gsmi_exit(void) +{ + unregister_reboot_notifier(&gsmi_reboot_notifier); + unregister_die_notifier(&gsmi_die_notifier); + atomic_notifier_chain_unregister(&panic_notifier_list, + &gsmi_panic_notifier); + unregister_efivars(&efivars); + + kobject_put(gsmi_kobj); + gsmi_buf_free(gsmi_dev.param_buf); + gsmi_buf_free(gsmi_dev.data_buf); + gsmi_buf_free(gsmi_dev.name_buf); + dma_pool_destroy(gsmi_dev.dma_pool); + platform_device_unregister(gsmi_dev.pdev); +} + +module_init(gsmi_init); +module_exit(gsmi_exit); + +MODULE_AUTHOR("Google, Inc."); +MODULE_LICENSE("GPL"); -- cgit v0.10.2 From e561bc45920aade3f8a5aad9058a00e750af1345 Mon Sep 17 00:00:00 2001 From: Mike Waychison Date: Fri, 29 Apr 2011 17:39:25 -0700 Subject: driver: Google Memory Console This patch introduces the 'memconsole' driver. Our firmware gives us access to an in-memory log of the firmware's output. This gives us visibility in a data-center of headless machines as to what the firmware is doing. The memory console is found by the driver by finding a header block in the EBDA. The buffer is then copied out, and is exported to userland in the file /sys/firmware/log. Signed-off-by: San Mehat Signed-off-by: Mike Waychison Signed-off-by: Greg Kroah-Hartman diff --git a/Documentation/ABI/testing/sysfs-firmware-log b/Documentation/ABI/testing/sysfs-firmware-log new file mode 100644 index 0000000..9b58e7c --- /dev/null +++ b/Documentation/ABI/testing/sysfs-firmware-log @@ -0,0 +1,7 @@ +What: /sys/firmware/log +Date: February 2011 +Contact: Mike Waychison +Description: + The /sys/firmware/log is a binary file that represents a + read-only copy of the firmware's log if one is + available. diff --git a/drivers/firmware/google/Kconfig b/drivers/firmware/google/Kconfig index 4a03835..640dc6b 100644 --- a/drivers/firmware/google/Kconfig +++ b/drivers/firmware/google/Kconfig @@ -7,3 +7,11 @@ config GOOGLE_SMI platforms. This provides an interface for writing to and clearing the EFI event log and reading and writing NVRAM variables. + +config GOOGLE_MEMCONSOLE + tristate "Firmware Memory Console" + depends on DMI + help + This option enables the kernel to search for a firmware log in + the EBDA on Google servers. If found, this log is exported to + userland in the file /sys/firmware/log. diff --git a/drivers/firmware/google/Makefile b/drivers/firmware/google/Makefile index fb127d7..54a294e 100644 --- a/drivers/firmware/google/Makefile +++ b/drivers/firmware/google/Makefile @@ -1,2 +1,3 @@ obj-$(CONFIG_GOOGLE_SMI) += gsmi.o +obj-$(CONFIG_GOOGLE_MEMCONSOLE) += memconsole.o diff --git a/drivers/firmware/google/memconsole.c b/drivers/firmware/google/memconsole.c new file mode 100644 index 0000000..2a90ba6 --- /dev/null +++ b/drivers/firmware/google/memconsole.c @@ -0,0 +1,166 @@ +/* + * memconsole.c + * + * Infrastructure for importing the BIOS memory based console + * into the kernel log ringbuffer. + * + * Copyright 2010 Google Inc. All rights reserved. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define BIOS_MEMCONSOLE_V1_MAGIC 0xDEADBABE +#define BIOS_MEMCONSOLE_V2_MAGIC (('M')|('C'<<8)|('O'<<16)|('N'<<24)) + +struct biosmemcon_ebda { + u32 signature; + union { + struct { + u8 enabled; + u32 buffer_addr; + u16 start; + u16 end; + u16 num_chars; + u8 wrapped; + } __packed v1; + struct { + u32 buffer_addr; + /* Misdocumented as number of pages! */ + u16 num_bytes; + u16 start; + u16 end; + } __packed v2; + }; +} __packed; + +static char *memconsole_baseaddr; +static size_t memconsole_length; + +static ssize_t memconsole_read(struct file *filp, struct kobject *kobp, + struct bin_attribute *bin_attr, char *buf, + loff_t pos, size_t count) +{ + return memory_read_from_buffer(buf, count, &pos, memconsole_baseaddr, + memconsole_length); +} + +static struct bin_attribute memconsole_bin_attr = { + .attr = {.name = "log", .mode = 0444}, + .read = memconsole_read, +}; + + +static void found_v1_header(struct biosmemcon_ebda *hdr) +{ + printk(KERN_INFO "BIOS console v1 EBDA structure found at %p\n", hdr); + printk(KERN_INFO "BIOS console buffer at 0x%.8x, " + "start = %d, end = %d, num = %d\n", + hdr->v1.buffer_addr, hdr->v1.start, + hdr->v1.end, hdr->v1.num_chars); + + memconsole_length = hdr->v1.num_chars; + memconsole_baseaddr = phys_to_virt(hdr->v1.buffer_addr); +} + +static void found_v2_header(struct biosmemcon_ebda *hdr) +{ + printk(KERN_INFO "BIOS console v2 EBDA structure found at %p\n", hdr); + printk(KERN_INFO "BIOS console buffer at 0x%.8x, " + "start = %d, end = %d, num_bytes = %d\n", + hdr->v2.buffer_addr, hdr->v2.start, + hdr->v2.end, hdr->v2.num_bytes); + + memconsole_length = hdr->v2.end - hdr->v2.start; + memconsole_baseaddr = phys_to_virt(hdr->v2.buffer_addr + + hdr->v2.start); +} + +/* + * Search through the EBDA for the BIOS Memory Console, and + * set the global variables to point to it. Return true if found. + */ +static bool found_memconsole(void) +{ + unsigned int address; + size_t length, cur; + + address = get_bios_ebda(); + if (!address) { + printk(KERN_INFO "BIOS EBDA non-existent.\n"); + return false; + } + + /* EBDA length is byte 0 of EBDA (in KB) */ + length = *(u8 *)phys_to_virt(address); + length <<= 10; /* convert to bytes */ + + /* + * Search through EBDA for BIOS memory console structure + * note: signature is not necessarily dword-aligned + */ + for (cur = 0; cur < length; cur++) { + struct biosmemcon_ebda *hdr = phys_to_virt(address + cur); + + /* memconsole v1 */ + if (hdr->signature == BIOS_MEMCONSOLE_V1_MAGIC) { + found_v1_header(hdr); + return true; + } + + /* memconsole v2 */ + if (hdr->signature == BIOS_MEMCONSOLE_V2_MAGIC) { + found_v2_header(hdr); + return true; + } + } + + printk(KERN_INFO "BIOS console EBDA structure not found!\n"); + return false; +} + +static struct dmi_system_id memconsole_dmi_table[] __initdata = { + { + .ident = "Google Board", + .matches = { + DMI_MATCH(DMI_BOARD_VENDOR, "Google, Inc."), + }, + }, + {} +}; +MODULE_DEVICE_TABLE(dmi, memconsole_dmi_table); + +static int __init memconsole_init(void) +{ + int ret; + + if (!dmi_check_system(memconsole_dmi_table)) + return -ENODEV; + + if (!found_memconsole()) + return -ENODEV; + + memconsole_bin_attr.size = memconsole_length; + + ret = sysfs_create_bin_file(firmware_kobj, &memconsole_bin_attr); + + return ret; +} + +static void __exit memconsole_exit(void) +{ + sysfs_remove_bin_file(firmware_kobj, &memconsole_bin_attr); +} + +module_init(memconsole_init); +module_exit(memconsole_exit); + +MODULE_AUTHOR("Google, Inc."); +MODULE_LICENSE("GPL"); -- cgit v0.10.2 From a1d9a09ae8003380a7f2297ee4367947cbdf874f Mon Sep 17 00:00:00 2001 From: Mike Waychison Date: Fri, 29 Apr 2011 17:39:31 -0700 Subject: Introduce CONFIG_GOOGLE_FIRMWARE In order to keep Google's firmware drivers organized amongst themselves, all Google firmware drivers are gated on CONFIG_GOOGLE_FIRMWARE=y, which defaults to 'n' in the kernel build. Signed-off-by: Mike Waychison Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/firmware/Makefile b/drivers/firmware/Makefile index d7d6009..47338c9 100644 --- a/drivers/firmware/Makefile +++ b/drivers/firmware/Makefile @@ -14,4 +14,4 @@ obj-$(CONFIG_ISCSI_IBFT) += iscsi_ibft.o obj-$(CONFIG_FIRMWARE_MEMMAP) += memmap.o obj-$(CONFIG_SIGMA) += sigma.o -obj-y += google/ +obj-$(CONFIG_GOOGLE_FIRMWARE) += google/ diff --git a/drivers/firmware/google/Kconfig b/drivers/firmware/google/Kconfig index 640dc6b..87096b6 100644 --- a/drivers/firmware/google/Kconfig +++ b/drivers/firmware/google/Kconfig @@ -1,3 +1,15 @@ +config GOOGLE_FIRMWARE + bool "Google Firmware Drivers" + depends on X86 + default n + help + These firmware drivers are used by Google's servers. They are + only useful if you are working directly on one of their + proprietary servers. If in doubt, say "N". + +menu "Google Firmware Drivers" + depends on GOOGLE_FIRMWARE + config GOOGLE_SMI tristate "SMI interface for Google platforms" depends on ACPI && DMI @@ -15,3 +27,5 @@ config GOOGLE_MEMCONSOLE This option enables the kernel to search for a firmware log in the EBDA on Google servers. If found, this log is exported to userland in the file /sys/firmware/log. + +endmenu -- cgit v0.10.2 From 058e297d34a404caaa5ed277de15698d8dc43000 Mon Sep 17 00:00:00 2001 From: Steven Rostedt Date: Fri, 29 Apr 2011 22:35:33 -0400 Subject: ftrace: Only update the function code on write to filter files If function tracing is enabled, a read of the filter files will cause the call to stop_machine to update the function trace sites. It should only call stop_machine on write. Cc: stable@kernel.org Signed-off-by: Steven Rostedt diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c index ee24fa1..666880d 100644 --- a/kernel/trace/ftrace.c +++ b/kernel/trace/ftrace.c @@ -2413,14 +2413,16 @@ ftrace_regex_release(struct inode *inode, struct file *file, int enable) ftrace_match_records(parser->buffer, parser->idx, enable); } - mutex_lock(&ftrace_lock); - if (ftrace_start_up && ftrace_enabled) - ftrace_run_update_code(FTRACE_ENABLE_CALLS); - mutex_unlock(&ftrace_lock); - trace_parser_put(parser); kfree(iter); + if (file->f_mode & FMODE_WRITE) { + mutex_lock(&ftrace_lock); + if (ftrace_start_up && ftrace_enabled) + ftrace_run_update_code(FTRACE_ENABLE_CALLS); + mutex_unlock(&ftrace_lock); + } + mutex_unlock(&ftrace_regex_lock); return 0; } -- cgit v0.10.2 From 0778d9ad33898faab7bf6316108b471790376e35 Mon Sep 17 00:00:00 2001 From: Steven Rostedt Date: Fri, 29 Apr 2011 10:36:31 -0400 Subject: ftrace: Make FTRACE_WARN_ON() work in if condition Let FTRACE_WARN_ON() be used as a stand alone statement or inside a conditional: if (FTRACE_WARN_ON(x)) Signed-off-by: Steven Rostedt diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c index ee24fa1..4ff65599 100644 --- a/kernel/trace/ftrace.c +++ b/kernel/trace/ftrace.c @@ -39,16 +39,20 @@ #include "trace_stat.h" #define FTRACE_WARN_ON(cond) \ - do { \ - if (WARN_ON(cond)) \ + ({ \ + int ___r = cond; \ + if (WARN_ON(___r)) \ ftrace_kill(); \ - } while (0) + ___r; \ + }) #define FTRACE_WARN_ON_ONCE(cond) \ - do { \ - if (WARN_ON_ONCE(cond)) \ + ({ \ + int ___r = cond; \ + if (WARN_ON_ONCE(___r)) \ ftrace_kill(); \ - } while (0) + ___r; \ + }) /* hash bits for specific function selection */ #define FTRACE_HASH_BITS 7 -- cgit v0.10.2 From 8ab2b7efd3e2ccf2c2dda3206b8171ecdbd0af40 Mon Sep 17 00:00:00 2001 From: Steven Rostedt Date: Thu, 21 Apr 2011 22:41:35 -0400 Subject: ftrace: Remove unnecessary disabling of irqs The disabling of interrupts around ftrace_update_code() was used to protect against the evil ftrace daemon from years past. But that daemon has long been killed. It is safe to keep interrupts enabled while updating the initial mcount into nops. The ftrace_mutex is also held which keeps other users at bay. Signed-off-by: Steven Rostedt diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c index 4ff65599..f199fb2 100644 --- a/kernel/trace/ftrace.c +++ b/kernel/trace/ftrace.c @@ -2707,7 +2707,6 @@ static int ftrace_process_locs(struct module *mod, { unsigned long *p; unsigned long addr; - unsigned long flags; mutex_lock(&ftrace_lock); p = start; @@ -2724,10 +2723,7 @@ static int ftrace_process_locs(struct module *mod, ftrace_record_ip(addr); } - /* disable interrupts to prevent kstop machine */ - local_irq_save(flags); ftrace_update_code(mod); - local_irq_restore(flags); mutex_unlock(&ftrace_lock); return 0; -- cgit v0.10.2 From 3499e461147636bf55c41128d83b679ac6ab2d86 Mon Sep 17 00:00:00 2001 From: Steven Rostedt Date: Thu, 21 Apr 2011 22:59:12 -0400 Subject: ftrace: Remove failures file The failures file in the debugfs tracing directory would list the functions that failed to convert when the old dead ftrace daemon tried to update code but failed. Since this code is now dead along with the daemon the failures file is useless. Remove it. Signed-off-by: Steven Rostedt diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c index f199fb2..97b30f8 100644 --- a/kernel/trace/ftrace.c +++ b/kernel/trace/ftrace.c @@ -1355,9 +1355,8 @@ static int __init ftrace_dyn_table_alloc(unsigned long num_to_init) enum { FTRACE_ITER_FILTER = (1 << 0), FTRACE_ITER_NOTRACE = (1 << 1), - FTRACE_ITER_FAILURES = (1 << 2), - FTRACE_ITER_PRINTALL = (1 << 3), - FTRACE_ITER_HASH = (1 << 4), + FTRACE_ITER_PRINTALL = (1 << 2), + FTRACE_ITER_HASH = (1 << 3), }; #define FTRACE_BUFF_MAX (KSYM_SYMBOL_LEN+4) /* room for wildcards */ @@ -1487,12 +1486,6 @@ t_next(struct seq_file *m, void *v, loff_t *pos) rec = &iter->pg->records[iter->idx++]; if ((rec->flags & FTRACE_FL_FREE) || - (!(iter->flags & FTRACE_ITER_FAILURES) && - (rec->flags & FTRACE_FL_FAILED)) || - - ((iter->flags & FTRACE_ITER_FAILURES) && - !(rec->flags & FTRACE_FL_FAILED)) || - ((iter->flags & FTRACE_ITER_FILTER) && !(rec->flags & FTRACE_FL_FILTER)) || @@ -1633,24 +1626,6 @@ ftrace_avail_open(struct inode *inode, struct file *file) return ret; } -static int -ftrace_failures_open(struct inode *inode, struct file *file) -{ - int ret; - struct seq_file *m; - struct ftrace_iterator *iter; - - ret = ftrace_avail_open(inode, file); - if (!ret) { - m = file->private_data; - iter = m->private; - iter->flags = FTRACE_ITER_FAILURES; - } - - return ret; -} - - static void ftrace_filter_reset(int enable) { struct ftrace_page *pg; @@ -2448,13 +2423,6 @@ static const struct file_operations ftrace_avail_fops = { .release = seq_release_private, }; -static const struct file_operations ftrace_failures_fops = { - .open = ftrace_failures_open, - .read = seq_read, - .llseek = seq_lseek, - .release = seq_release_private, -}; - static const struct file_operations ftrace_filter_fops = { .open = ftrace_filter_open, .read = seq_read, @@ -2683,9 +2651,6 @@ static __init int ftrace_init_dyn_debugfs(struct dentry *d_tracer) trace_create_file("available_filter_functions", 0444, d_tracer, NULL, &ftrace_avail_fops); - trace_create_file("failures", 0444, - d_tracer, NULL, &ftrace_failures_fops); - trace_create_file("set_ftrace_filter", 0644, d_tracer, NULL, &ftrace_filter_fops); -- cgit v0.10.2 From 45a4a2372b364107cabea79f255b333236626416 Mon Sep 17 00:00:00 2001 From: Steven Rostedt Date: Thu, 21 Apr 2011 23:16:46 -0400 Subject: ftrace: Remove FTRACE_FL_FAILED flag Since we disable all function tracer processing if we detect that a modification of a instruction had failed, we do not need to track that the record has failed. No more ftrace processing is allowed, and the FTRACE_FL_FAILED flag is pointless. Removing this flag simplifies some of the code, but some ftrace_disabled checks needed to be added or move around a little. Signed-off-by: Steven Rostedt diff --git a/include/linux/ftrace.h b/include/linux/ftrace.h index ca29e03..2a195ff 100644 --- a/include/linux/ftrace.h +++ b/include/linux/ftrace.h @@ -147,11 +147,10 @@ extern int ftrace_text_reserved(void *start, void *end); enum { FTRACE_FL_FREE = (1 << 0), - FTRACE_FL_FAILED = (1 << 1), - FTRACE_FL_FILTER = (1 << 2), - FTRACE_FL_ENABLED = (1 << 3), - FTRACE_FL_NOTRACE = (1 << 4), - FTRACE_FL_CONVERTED = (1 << 5), + FTRACE_FL_FILTER = (1 << 1), + FTRACE_FL_ENABLED = (1 << 2), + FTRACE_FL_NOTRACE = (1 << 3), + FTRACE_FL_CONVERTED = (1 << 4), }; struct dyn_ftrace { diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c index 97b30f8..eb19fae 100644 --- a/kernel/trace/ftrace.c +++ b/kernel/trace/ftrace.c @@ -1083,19 +1083,20 @@ static void ftrace_replace_code(int enable) struct ftrace_page *pg; int failed; + if (unlikely(ftrace_disabled)) + return; + do_for_each_ftrace_rec(pg, rec) { /* * Skip over free records, records that have * failed and not converted. */ if (rec->flags & FTRACE_FL_FREE || - rec->flags & FTRACE_FL_FAILED || !(rec->flags & FTRACE_FL_CONVERTED)) continue; failed = __ftrace_replace_code(rec, enable); if (failed) { - rec->flags |= FTRACE_FL_FAILED; ftrace_bug(failed, rec->ip); /* Stop processing */ return; @@ -1111,10 +1112,12 @@ ftrace_code_disable(struct module *mod, struct dyn_ftrace *rec) ip = rec->ip; + if (unlikely(ftrace_disabled)) + return 0; + ret = ftrace_make_nop(mod, rec, MCOUNT_ADDR); if (ret) { ftrace_bug(ret, ip); - rec->flags |= FTRACE_FL_FAILED; return 0; } return 1; @@ -1466,6 +1469,9 @@ t_next(struct seq_file *m, void *v, loff_t *pos) struct ftrace_iterator *iter = m->private; struct dyn_ftrace *rec = NULL; + if (unlikely(ftrace_disabled)) + return NULL; + if (iter->flags & FTRACE_ITER_HASH) return t_hash_next(m, pos); @@ -1518,6 +1524,10 @@ static void *t_start(struct seq_file *m, loff_t *pos) loff_t l; mutex_lock(&ftrace_lock); + + if (unlikely(ftrace_disabled)) + return NULL; + /* * If an lseek was done, then reset and start from beginning. */ @@ -1636,8 +1646,6 @@ static void ftrace_filter_reset(int enable) if (enable) ftrace_filtered = 0; do_for_each_ftrace_rec(pg, rec) { - if (rec->flags & FTRACE_FL_FAILED) - continue; rec->flags &= ~type; } while_for_each_ftrace_rec(); mutex_unlock(&ftrace_lock); @@ -1767,9 +1775,6 @@ static int ftrace_match_records(char *buff, int len, int enable) mutex_lock(&ftrace_lock); do_for_each_ftrace_rec(pg, rec) { - if (rec->flags & FTRACE_FL_FAILED) - continue; - if (ftrace_match_record(rec, search, search_len, type)) { if (not) rec->flags &= ~flag; @@ -1837,10 +1842,11 @@ static int ftrace_match_module_records(char *buff, char *mod, int enable) } mutex_lock(&ftrace_lock); - do_for_each_ftrace_rec(pg, rec) { - if (rec->flags & FTRACE_FL_FAILED) - continue; + if (unlikely(ftrace_disabled)) + goto out_unlock; + + do_for_each_ftrace_rec(pg, rec) { if (ftrace_match_module_record(rec, mod, search, search_len, type)) { @@ -1854,6 +1860,7 @@ static int ftrace_match_module_records(char *buff, char *mod, int enable) ftrace_filtered = 1; } while_for_each_ftrace_rec(); + out_unlock: mutex_unlock(&ftrace_lock); return found; @@ -2008,10 +2015,11 @@ register_ftrace_function_probe(char *glob, struct ftrace_probe_ops *ops, return -EINVAL; mutex_lock(&ftrace_lock); - do_for_each_ftrace_rec(pg, rec) { - if (rec->flags & FTRACE_FL_FAILED) - continue; + if (unlikely(ftrace_disabled)) + goto out_unlock; + + do_for_each_ftrace_rec(pg, rec) { if (!ftrace_match_record(rec, search, len, type)) continue; @@ -2218,6 +2226,10 @@ ftrace_regex_write(struct file *file, const char __user *ubuf, mutex_lock(&ftrace_regex_lock); + ret = -ENODEV; + if (unlikely(ftrace_disabled)) + goto out_unlock; + if (file->f_mode & FMODE_READ) { struct seq_file *m = file->private_data; iter = m->private; @@ -2545,9 +2557,6 @@ ftrace_set_func(unsigned long *array, int *idx, char *buffer) bool exists; int i; - if (ftrace_disabled) - return -ENODEV; - /* decode regex */ type = filter_parse_regex(buffer, strlen(buffer), &search, ¬); if (!not && *idx >= FTRACE_GRAPH_MAX_FUNCS) @@ -2556,9 +2565,15 @@ ftrace_set_func(unsigned long *array, int *idx, char *buffer) search_len = strlen(search); mutex_lock(&ftrace_lock); + + if (unlikely(ftrace_disabled)) { + mutex_unlock(&ftrace_lock); + return -ENODEV; + } + do_for_each_ftrace_rec(pg, rec) { - if (rec->flags & (FTRACE_FL_FAILED | FTRACE_FL_FREE)) + if (rec->flags & FTRACE_FL_FREE) continue; if (ftrace_match_record(rec, search, search_len, type)) { @@ -2700,10 +2715,11 @@ void ftrace_release_mod(struct module *mod) struct dyn_ftrace *rec; struct ftrace_page *pg; + mutex_lock(&ftrace_lock); + if (ftrace_disabled) - return; + goto out_unlock; - mutex_lock(&ftrace_lock); do_for_each_ftrace_rec(pg, rec) { if (within_module_core(rec->ip, mod)) { /* @@ -2714,6 +2730,7 @@ void ftrace_release_mod(struct module *mod) ftrace_free_rec(rec); } } while_for_each_ftrace_rec(); + out_unlock: mutex_unlock(&ftrace_lock); } @@ -3108,16 +3125,17 @@ void ftrace_kill(void) */ int register_ftrace_function(struct ftrace_ops *ops) { - int ret; - - if (unlikely(ftrace_disabled)) - return -1; + int ret = -1; mutex_lock(&ftrace_lock); + if (unlikely(ftrace_disabled)) + goto out_unlock; + ret = __register_ftrace_function(ops); ftrace_startup(0); + out_unlock: mutex_unlock(&ftrace_lock); return ret; } @@ -3145,14 +3163,14 @@ ftrace_enable_sysctl(struct ctl_table *table, int write, void __user *buffer, size_t *lenp, loff_t *ppos) { - int ret; - - if (unlikely(ftrace_disabled)) - return -ENODEV; + int ret = -ENODEV; mutex_lock(&ftrace_lock); - ret = proc_dointvec(table, write, buffer, lenp, ppos); + if (unlikely(ftrace_disabled)) + goto out; + + ret = proc_dointvec(table, write, buffer, lenp, ppos); if (ret || !write || (last_ftrace_enabled == !!ftrace_enabled)) goto out; -- cgit v0.10.2 From d2c8c3eafbf715306ec891e7ca52d3d999acbe31 Mon Sep 17 00:00:00 2001 From: Steven Rostedt Date: Mon, 25 Apr 2011 14:32:42 -0400 Subject: ftrace: Remove FTRACE_FL_CONVERTED flag Since we disable all function tracer processing if we detect that a modification of a instruction had failed, we do not need to track that the record has failed. No more ftrace processing is allowed, and the FTRACE_FL_CONVERTED flag is pointless. The FTRACE_FL_CONVERTED flag was used to denote records that were successfully converted from mcount calls into nops. But if a single record fails, all of ftrace is disabled. Signed-off-by: Steven Rostedt diff --git a/include/linux/ftrace.h b/include/linux/ftrace.h index 2a195ff..3204744 100644 --- a/include/linux/ftrace.h +++ b/include/linux/ftrace.h @@ -150,7 +150,6 @@ enum { FTRACE_FL_FILTER = (1 << 1), FTRACE_FL_ENABLED = (1 << 2), FTRACE_FL_NOTRACE = (1 << 3), - FTRACE_FL_CONVERTED = (1 << 4), }; struct dyn_ftrace { diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c index eb19fae..9abaaf4 100644 --- a/kernel/trace/ftrace.c +++ b/kernel/trace/ftrace.c @@ -1087,12 +1087,8 @@ static void ftrace_replace_code(int enable) return; do_for_each_ftrace_rec(pg, rec) { - /* - * Skip over free records, records that have - * failed and not converted. - */ - if (rec->flags & FTRACE_FL_FREE || - !(rec->flags & FTRACE_FL_CONVERTED)) + /* Skip over free records */ + if (rec->flags & FTRACE_FL_FREE) continue; failed = __ftrace_replace_code(rec, enable); @@ -1280,10 +1276,10 @@ static int ftrace_update_code(struct module *mod) */ if (!ftrace_code_disable(mod, p)) { ftrace_free_rec(p); - continue; + /* Game over */ + break; } - p->flags |= FTRACE_FL_CONVERTED; ftrace_update_cnt++; /* -- cgit v0.10.2 From 996e87be7f537fb34638875dd37083166c733425 Mon Sep 17 00:00:00 2001 From: Steven Rostedt Date: Tue, 26 Apr 2011 16:11:03 -0400 Subject: ftrace: Move record update for normal and modules into a separate function The updating of a function record is moved to a single function. This will allow us to add specific changes in one location for both modules and kernel functions. Later patches will determine if the function record itself needs to be updated (which enables the mcount caller), or just the ftrace_ops needs the update. Signed-off-by: Steven Rostedt diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c index 9abaaf4..5b758ea 100644 --- a/kernel/trace/ftrace.c +++ b/kernel/trace/ftrace.c @@ -1743,6 +1743,15 @@ static int ftrace_match(char *str, char *regex, int len, int type) return matched; } +static void +update_record(struct dyn_ftrace *rec, unsigned long flag, int not) +{ + if (not) + rec->flags &= ~flag; + else + rec->flags |= flag; +} + static int ftrace_match_record(struct dyn_ftrace *rec, char *regex, int len, int type) { @@ -1772,10 +1781,7 @@ static int ftrace_match_records(char *buff, int len, int enable) do_for_each_ftrace_rec(pg, rec) { if (ftrace_match_record(rec, search, search_len, type)) { - if (not) - rec->flags &= ~flag; - else - rec->flags |= flag; + update_record(rec, flag, not); found = 1; } /* @@ -1846,10 +1852,7 @@ static int ftrace_match_module_records(char *buff, char *mod, int enable) if (ftrace_match_module_record(rec, mod, search, search_len, type)) { - if (not) - rec->flags &= ~flag; - else - rec->flags |= flag; + update_record(rec, flag, not); found = 1; } if (enable && (rec->flags & FTRACE_FL_FILTER)) -- cgit v0.10.2 From 491d0dcfb9707e1f83eff93ca503eb7573162ef2 Mon Sep 17 00:00:00 2001 From: Steven Rostedt Date: Wed, 27 Apr 2011 21:43:36 -0400 Subject: ftrace: Consolidate updating of ftrace_trace_function There are three locations that perform almost identical functions in order to update the ftrace_trace_function (the ftrace function variable that gets called by mcount). Consolidate these into a single function called update_ftrace_function(). Signed-off-by: Steven Rostedt diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c index 5b758ea..33bcc71 100644 --- a/kernel/trace/ftrace.c +++ b/kernel/trace/ftrace.c @@ -151,6 +151,34 @@ static void ftrace_test_stop_func(unsigned long ip, unsigned long parent_ip) } #endif +static void update_ftrace_function(void) +{ + ftrace_func_t func; + + /* + * If there's only one function registered, then call that + * function directly. Otherwise, we need to iterate over the + * registered callers. + */ + if (ftrace_list == &ftrace_list_end || + ftrace_list->next == &ftrace_list_end) + func = ftrace_list->func; + else + func = ftrace_list_func; + + /* If we filter on pids, update to use the pid function */ + if (!list_empty(&ftrace_pids)) { + set_ftrace_pid_function(func); + func = ftrace_pid_func; + } +#ifdef CONFIG_HAVE_FUNCTION_TRACE_MCOUNT_TEST + ftrace_trace_function = func; +#else + __ftrace_trace_function = func; + ftrace_trace_function = ftrace_test_stop_func; +#endif +} + static int __register_ftrace_function(struct ftrace_ops *ops) { ops->next = ftrace_list; @@ -162,30 +190,8 @@ static int __register_ftrace_function(struct ftrace_ops *ops) */ rcu_assign_pointer(ftrace_list, ops); - if (ftrace_enabled) { - ftrace_func_t func; - - if (ops->next == &ftrace_list_end) - func = ops->func; - else - func = ftrace_list_func; - - if (!list_empty(&ftrace_pids)) { - set_ftrace_pid_function(func); - func = ftrace_pid_func; - } - - /* - * For one func, simply call it directly. - * For more than one func, call the chain. - */ -#ifdef CONFIG_HAVE_FUNCTION_TRACE_MCOUNT_TEST - ftrace_trace_function = func; -#else - __ftrace_trace_function = func; - ftrace_trace_function = ftrace_test_stop_func; -#endif - } + if (ftrace_enabled) + update_ftrace_function(); return 0; } @@ -213,52 +219,19 @@ static int __unregister_ftrace_function(struct ftrace_ops *ops) *p = (*p)->next; - if (ftrace_enabled) { - /* If we only have one func left, then call that directly */ - if (ftrace_list->next == &ftrace_list_end) { - ftrace_func_t func = ftrace_list->func; - - if (!list_empty(&ftrace_pids)) { - set_ftrace_pid_function(func); - func = ftrace_pid_func; - } -#ifdef CONFIG_HAVE_FUNCTION_TRACE_MCOUNT_TEST - ftrace_trace_function = func; -#else - __ftrace_trace_function = func; -#endif - } - } + if (ftrace_enabled) + update_ftrace_function(); return 0; } static void ftrace_update_pid_func(void) { - ftrace_func_t func; - + /* Only do something if we are tracing something */ if (ftrace_trace_function == ftrace_stub) return; -#ifdef CONFIG_HAVE_FUNCTION_TRACE_MCOUNT_TEST - func = ftrace_trace_function; -#else - func = __ftrace_trace_function; -#endif - - if (!list_empty(&ftrace_pids)) { - set_ftrace_pid_function(func); - func = ftrace_pid_func; - } else { - if (func == ftrace_pid_func) - func = ftrace_pid_function; - } - -#ifdef CONFIG_HAVE_FUNCTION_TRACE_MCOUNT_TEST - ftrace_trace_function = func; -#else - __ftrace_trace_function = func; -#endif + update_ftrace_function(); } #ifdef CONFIG_FUNCTION_PROFILER -- cgit v0.10.2 From b9df92d2a94eef8811061aecb1396290df440e2e Mon Sep 17 00:00:00 2001 From: Steven Rostedt Date: Thu, 28 Apr 2011 20:32:08 -0400 Subject: ftrace: Consolidate the function match routines for normal and mods The code used for matching functions is almost identical between normal selecting of functions and using the :mod: feature of set_ftrace_notrace. Consolidate the two users into one function. Signed-off-by: Steven Rostedt diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c index 33bcc71..4f19dbb 100644 --- a/kernel/trace/ftrace.c +++ b/kernel/trace/ftrace.c @@ -1726,34 +1726,52 @@ update_record(struct dyn_ftrace *rec, unsigned long flag, int not) } static int -ftrace_match_record(struct dyn_ftrace *rec, char *regex, int len, int type) +ftrace_match_record(struct dyn_ftrace *rec, char *mod, + char *regex, int len, int type) { char str[KSYM_SYMBOL_LEN]; + char *modname; + + kallsyms_lookup(rec->ip, NULL, NULL, &modname, str); + + if (mod) { + /* module lookup requires matching the module */ + if (!modname || strcmp(modname, mod)) + return 0; + + /* blank search means to match all funcs in the mod */ + if (!len) + return 1; + } - kallsyms_lookup(rec->ip, NULL, NULL, NULL, str); return ftrace_match(str, regex, len, type); } -static int ftrace_match_records(char *buff, int len, int enable) +static int match_records(char *buff, int len, char *mod, int enable, int not) { - unsigned int search_len; + unsigned search_len = 0; struct ftrace_page *pg; struct dyn_ftrace *rec; + int type = MATCH_FULL; + char *search = buff; unsigned long flag; - char *search; - int type; - int not; int found = 0; - flag = enable ? FTRACE_FL_FILTER : FTRACE_FL_NOTRACE; - type = filter_parse_regex(buff, len, &search, ¬); + if (len) { + type = filter_parse_regex(buff, len, &search, ¬); + search_len = strlen(search); + } - search_len = strlen(search); + flag = enable ? FTRACE_FL_FILTER : FTRACE_FL_NOTRACE; mutex_lock(&ftrace_lock); + + if (unlikely(ftrace_disabled)) + goto out_unlock; + do_for_each_ftrace_rec(pg, rec) { - if (ftrace_match_record(rec, search, search_len, type)) { + if (ftrace_match_record(rec, mod, search, search_len, type)) { update_record(rec, flag, not); found = 1; } @@ -1763,43 +1781,23 @@ static int ftrace_match_records(char *buff, int len, int enable) */ if (enable && (rec->flags & FTRACE_FL_FILTER)) ftrace_filtered = 1; + } while_for_each_ftrace_rec(); + out_unlock: mutex_unlock(&ftrace_lock); return found; } static int -ftrace_match_module_record(struct dyn_ftrace *rec, char *mod, - char *regex, int len, int type) +ftrace_match_records(char *buff, int len, int enable) { - char str[KSYM_SYMBOL_LEN]; - char *modname; - - kallsyms_lookup(rec->ip, NULL, NULL, &modname, str); - - if (!modname || strcmp(modname, mod)) - return 0; - - /* blank search means to match all funcs in the mod */ - if (len) - return ftrace_match(str, regex, len, type); - else - return 1; + return match_records(buff, len, NULL, enable, 0); } static int ftrace_match_module_records(char *buff, char *mod, int enable) { - unsigned search_len = 0; - struct ftrace_page *pg; - struct dyn_ftrace *rec; - int type = MATCH_FULL; - char *search = buff; - unsigned long flag; int not = 0; - int found = 0; - - flag = enable ? FTRACE_FL_FILTER : FTRACE_FL_NOTRACE; /* blank or '*' mean the same */ if (strcmp(buff, "*") == 0) @@ -1811,31 +1809,7 @@ static int ftrace_match_module_records(char *buff, char *mod, int enable) not = 1; } - if (strlen(buff)) { - type = filter_parse_regex(buff, strlen(buff), &search, ¬); - search_len = strlen(search); - } - - mutex_lock(&ftrace_lock); - - if (unlikely(ftrace_disabled)) - goto out_unlock; - - do_for_each_ftrace_rec(pg, rec) { - - if (ftrace_match_module_record(rec, mod, - search, search_len, type)) { - update_record(rec, flag, not); - found = 1; - } - if (enable && (rec->flags & FTRACE_FL_FILTER)) - ftrace_filtered = 1; - - } while_for_each_ftrace_rec(); - out_unlock: - mutex_unlock(&ftrace_lock); - - return found; + return match_records(buff, strlen(buff), mod, enable, not); } /* @@ -1993,7 +1967,7 @@ register_ftrace_function_probe(char *glob, struct ftrace_probe_ops *ops, do_for_each_ftrace_rec(pg, rec) { - if (!ftrace_match_record(rec, search, len, type)) + if (!ftrace_match_record(rec, NULL, search, len, type)) continue; entry = kmalloc(sizeof(*entry), GFP_KERNEL); @@ -2548,7 +2522,7 @@ ftrace_set_func(unsigned long *array, int *idx, char *buffer) if (rec->flags & FTRACE_FL_FREE) continue; - if (ftrace_match_record(rec, search, search_len, type)) { + if (ftrace_match_record(rec, NULL, search, search_len, type)) { /* if it is in the array */ exists = false; for (i = 0; i < *idx; i++) { -- cgit v0.10.2 From e8bf8df9c296b782c32236c6a5893aec301320c7 Mon Sep 17 00:00:00 2001 From: Russell King Date: Sat, 30 Apr 2011 10:14:08 +0100 Subject: CLKDEV: Fix clkdev return value for NULL clk case clkdev may incorrectly cause a clkdev entry with a NULL clk to return -ENOENT. This is not the intention of this code; -ENOENT should only be returned if the clock entry can not be found in the table. Fix this. Reported-by: Stephen Boyd Signed-off-by: Russell King diff --git a/drivers/clk/clkdev.c b/drivers/clk/clkdev.c index 0fc0a79..6db161f 100644 --- a/drivers/clk/clkdev.c +++ b/drivers/clk/clkdev.c @@ -32,10 +32,9 @@ static DEFINE_MUTEX(clocks_mutex); * Then we take the most specific entry - with the following * order of precedence: dev+con > dev only > con only. */ -static struct clk *clk_find(const char *dev_id, const char *con_id) +static struct clk_lookup *clk_find(const char *dev_id, const char *con_id) { - struct clk_lookup *p; - struct clk *clk = NULL; + struct clk_lookup *p, *cl = NULL; int match, best = 0; list_for_each_entry(p, &clocks, node) { @@ -52,27 +51,27 @@ static struct clk *clk_find(const char *dev_id, const char *con_id) } if (match > best) { - clk = p->clk; + cl = p; if (match != 3) best = match; else break; } } - return clk; + return cl; } struct clk *clk_get_sys(const char *dev_id, const char *con_id) { - struct clk *clk; + struct clk_lookup *cl; mutex_lock(&clocks_mutex); - clk = clk_find(dev_id, con_id); - if (clk && !__clk_get(clk)) - clk = NULL; + cl = clk_find(dev_id, con_id); + if (cl && !__clk_get(cl->clk)) + cl = NULL; mutex_unlock(&clocks_mutex); - return clk ? clk : ERR_PTR(-ENOENT); + return cl ? cl->clk : ERR_PTR(-ENOENT); } EXPORT_SYMBOL(clk_get_sys); -- cgit v0.10.2 From 9d39e5bad76a8830a8fa0c03cadc1e36ce2ec2ef Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 19 Apr 2011 07:38:23 -0700 Subject: iwlagn: avoid hangs when restarting device If a device error happens while the uCode is being loaded or initialised, we will attempt to restart the device (which will likely fail again, but that's not the issue here). During this new restart, we turn off the device, but as the uCode failed to initialise it already is turned off. As a consequence, grabbing NIC access will fail and cause excessive messages and hangs. To fix this issue, introduce a new status bit and only attempt to reprogram the device when it isn't already disabled. Signed-off-by: Johannes Berg Signed-off-by: Wey-Yi Guy diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-lib.c b/drivers/net/wireless/iwlwifi/iwl-agn-lib.c index e202a40..75e1035 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-lib.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-lib.c @@ -2363,12 +2363,21 @@ void iwlagn_stop_device(struct iwl_priv *priv) /* device going down, Stop using ICT table */ iwl_disable_ict(priv); - iwlagn_txq_ctx_stop(priv); - iwlagn_rxq_stop(priv); - - /* Power-down device's busmaster DMA clocks */ - iwl_write_prph(priv, APMG_CLK_DIS_REG, APMG_CLK_VAL_DMA_CLK_RQT); - udelay(5); + /* + * If a HW restart happens during firmware loading, + * then the firmware loading might call this function + * and later it might be called again due to the + * restart. So don't process again if the device is + * already dead. + */ + if (test_bit(STATUS_DEVICE_ENABLED, &priv->status)) { + iwlagn_txq_ctx_stop(priv); + iwlagn_rxq_stop(priv); + + /* Power-down device's busmaster DMA clocks */ + iwl_write_prph(priv, APMG_CLK_DIS_REG, APMG_CLK_VAL_DMA_CLK_RQT); + udelay(5); + } /* Make sure (redundant) we've released our request to stay awake */ iwl_clear_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ); diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index af72fd5..66da1de 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -995,6 +995,8 @@ void iwl_apm_stop(struct iwl_priv *priv) { IWL_DEBUG_INFO(priv, "Stop card, put in low power state\n"); + clear_bit(STATUS_DEVICE_ENABLED, &priv->status); + /* Stop device's DMA activity */ iwl_apm_stop_master(priv); @@ -1109,6 +1111,8 @@ int iwl_apm_init(struct iwl_priv *priv) iwl_set_bits_prph(priv, APMG_PCIDEV_STT_REG, APMG_PCIDEV_STT_VAL_L1_ACT_DIS); + set_bit(STATUS_DEVICE_ENABLED, &priv->status); + out: return ret; } diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h index 32a990f..6226e3d 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.h +++ b/drivers/net/wireless/iwlwifi/iwl-core.h @@ -592,6 +592,7 @@ void iwlcore_free_geos(struct iwl_priv *priv); #define STATUS_SCAN_HW 15 #define STATUS_POWER_PMI 16 #define STATUS_FW_ERROR 17 +#define STATUS_DEVICE_ENABLED 18 static inline int iwl_is_ready(struct iwl_priv *priv) -- cgit v0.10.2 From 4119904f3ebf30c25afb42195740f9ee5dc7749c Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 19 Apr 2011 07:42:03 -0700 Subject: iwlagn: introduce silent grabbing of NIC access There are a few cases like the WoWLAN support I'm writing that require attempting to access the NIC when it is known that it might not be accessible, e.g. after the system woke up and the platform might have reset the device. To avoid messages in this case, introduce the new function iwl_grab_nic_access_silent(), it will only return an error status. Signed-off-by: Johannes Berg Signed-off-by: Wey-Yi Guy diff --git a/drivers/net/wireless/iwlwifi/iwl-io.c b/drivers/net/wireless/iwlwifi/iwl-io.c index 993b3df..aa4a906 100644 --- a/drivers/net/wireless/iwlwifi/iwl-io.c +++ b/drivers/net/wireless/iwlwifi/iwl-io.c @@ -73,10 +73,9 @@ int iwl_poll_bit(struct iwl_priv *priv, u32 addr, return -ETIMEDOUT; } -int iwl_grab_nic_access(struct iwl_priv *priv) +int iwl_grab_nic_access_silent(struct iwl_priv *priv) { int ret; - u32 val; lockdep_assert_held(&priv->reg_lock); @@ -107,9 +106,6 @@ int iwl_grab_nic_access(struct iwl_priv *priv) (CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY | CSR_GP_CNTRL_REG_FLAG_GOING_TO_SLEEP), 15000); if (ret < 0) { - val = iwl_read32(priv, CSR_GP_CNTRL); - IWL_ERR(priv, - "MAC is in deep sleep!. CSR_GP_CNTRL = 0x%08X\n", val); iwl_write32(priv, CSR_RESET, CSR_RESET_REG_FLAG_FORCE_NMI); return -EIO; } @@ -117,6 +113,18 @@ int iwl_grab_nic_access(struct iwl_priv *priv) return 0; } +int iwl_grab_nic_access(struct iwl_priv *priv) +{ + int ret = iwl_grab_nic_access_silent(priv); + if (ret) { + u32 val = iwl_read32(priv, CSR_GP_CNTRL); + IWL_ERR(priv, + "MAC is in deep sleep!. CSR_GP_CNTRL = 0x%08X\n", val); + } + + return ret; +} + void iwl_release_nic_access(struct iwl_priv *priv) { lockdep_assert_held(&priv->reg_lock); diff --git a/drivers/net/wireless/iwlwifi/iwl-io.h b/drivers/net/wireless/iwlwifi/iwl-io.h index 262e026..869edc5 100644 --- a/drivers/net/wireless/iwlwifi/iwl-io.h +++ b/drivers/net/wireless/iwlwifi/iwl-io.h @@ -62,6 +62,7 @@ int iwl_poll_bit(struct iwl_priv *priv, u32 addr, int iwl_poll_direct_bit(struct iwl_priv *priv, u32 addr, u32 mask, int timeout); +int iwl_grab_nic_access_silent(struct iwl_priv *priv); int iwl_grab_nic_access(struct iwl_priv *priv); void iwl_release_nic_access(struct iwl_priv *priv); -- cgit v0.10.2 From e43e85c40d83f0a7a6ff5631d1009d142b72dbca Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 19 Apr 2011 07:45:16 -0700 Subject: iwlagn: refactor restart The WoWLAN resume code will have to essentially do a restart, but without going through the work struct. To support that, refactor the restart by splitting out the preparation code into a new function. Signed-off-by: Johannes Berg Signed-off-by: Wey-Yi Guy diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index a4ec524..c27147c 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -2493,6 +2493,42 @@ static void iwl_bg_run_time_calib_work(struct work_struct *work) mutex_unlock(&priv->mutex); } +static void iwlagn_prepare_restart(struct iwl_priv *priv) +{ + struct iwl_rxon_context *ctx; + bool bt_full_concurrent; + u8 bt_ci_compliance; + u8 bt_load; + u8 bt_status; + + lockdep_assert_held(&priv->mutex); + + for_each_context(priv, ctx) + ctx->vif = NULL; + priv->is_open = 0; + + /* + * __iwl_down() will clear the BT status variables, + * which is correct, but when we restart we really + * want to keep them so restore them afterwards. + * + * The restart process will later pick them up and + * re-configure the hw when we reconfigure the BT + * command. + */ + bt_full_concurrent = priv->bt_full_concurrent; + bt_ci_compliance = priv->bt_ci_compliance; + bt_load = priv->bt_traffic_load; + bt_status = priv->bt_status; + + __iwl_down(priv); + + priv->bt_full_concurrent = bt_full_concurrent; + priv->bt_ci_compliance = bt_ci_compliance; + priv->bt_traffic_load = bt_load; + priv->bt_status = bt_status; +} + static void iwl_bg_restart(struct work_struct *data) { struct iwl_priv *priv = container_of(data, struct iwl_priv, restart); @@ -2501,38 +2537,8 @@ static void iwl_bg_restart(struct work_struct *data) return; if (test_and_clear_bit(STATUS_FW_ERROR, &priv->status)) { - struct iwl_rxon_context *ctx; - bool bt_full_concurrent; - u8 bt_ci_compliance; - u8 bt_load; - u8 bt_status; - mutex_lock(&priv->mutex); - for_each_context(priv, ctx) - ctx->vif = NULL; - priv->is_open = 0; - - /* - * __iwl_down() will clear the BT status variables, - * which is correct, but when we restart we really - * want to keep them so restore them afterwards. - * - * The restart process will later pick them up and - * re-configure the hw when we reconfigure the BT - * command. - */ - bt_full_concurrent = priv->bt_full_concurrent; - bt_ci_compliance = priv->bt_ci_compliance; - bt_load = priv->bt_traffic_load; - bt_status = priv->bt_status; - - __iwl_down(priv); - - priv->bt_full_concurrent = bt_full_concurrent; - priv->bt_ci_compliance = bt_ci_compliance; - priv->bt_traffic_load = bt_load; - priv->bt_status = bt_status; - + iwlagn_prepare_restart(priv); mutex_unlock(&priv->mutex); iwl_cancel_deferred_work(priv); ieee80211_restart_hw(priv->hw); -- cgit v0.10.2 From c3f6e9cff950c312d409e5767365aeb2475b2ab7 Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Tue, 19 Apr 2011 16:52:57 -0700 Subject: iwlagn: make rxon_assoc static function Move rxon_assoc to static function from ops Signed-off-by: Wey-Yi Guy diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-hcmd.c b/drivers/net/wireless/iwlwifi/iwl-agn-hcmd.c index 861cc93..49dd03f 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-hcmd.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-hcmd.c @@ -37,54 +37,6 @@ #include "iwl-io.h" #include "iwl-agn.h" -int iwlagn_send_rxon_assoc(struct iwl_priv *priv, - struct iwl_rxon_context *ctx) -{ - int ret = 0; - struct iwl5000_rxon_assoc_cmd rxon_assoc; - const struct iwl_rxon_cmd *rxon1 = &ctx->staging; - const struct iwl_rxon_cmd *rxon2 = &ctx->active; - - if ((rxon1->flags == rxon2->flags) && - (rxon1->filter_flags == rxon2->filter_flags) && - (rxon1->cck_basic_rates == rxon2->cck_basic_rates) && - (rxon1->ofdm_ht_single_stream_basic_rates == - rxon2->ofdm_ht_single_stream_basic_rates) && - (rxon1->ofdm_ht_dual_stream_basic_rates == - rxon2->ofdm_ht_dual_stream_basic_rates) && - (rxon1->ofdm_ht_triple_stream_basic_rates == - rxon2->ofdm_ht_triple_stream_basic_rates) && - (rxon1->acquisition_data == rxon2->acquisition_data) && - (rxon1->rx_chain == rxon2->rx_chain) && - (rxon1->ofdm_basic_rates == rxon2->ofdm_basic_rates)) { - IWL_DEBUG_INFO(priv, "Using current RXON_ASSOC. Not resending.\n"); - return 0; - } - - rxon_assoc.flags = ctx->staging.flags; - rxon_assoc.filter_flags = ctx->staging.filter_flags; - rxon_assoc.ofdm_basic_rates = ctx->staging.ofdm_basic_rates; - rxon_assoc.cck_basic_rates = ctx->staging.cck_basic_rates; - rxon_assoc.reserved1 = 0; - rxon_assoc.reserved2 = 0; - rxon_assoc.reserved3 = 0; - rxon_assoc.ofdm_ht_single_stream_basic_rates = - ctx->staging.ofdm_ht_single_stream_basic_rates; - rxon_assoc.ofdm_ht_dual_stream_basic_rates = - ctx->staging.ofdm_ht_dual_stream_basic_rates; - rxon_assoc.rx_chain_select_flags = ctx->staging.rx_chain; - rxon_assoc.ofdm_ht_triple_stream_basic_rates = - ctx->staging.ofdm_ht_triple_stream_basic_rates; - rxon_assoc.acquisition_data = ctx->staging.acquisition_data; - - ret = iwl_send_cmd_pdu_async(priv, ctx->rxon_assoc_cmd, - sizeof(rxon_assoc), &rxon_assoc, NULL); - if (ret) - return ret; - - return ret; -} - int iwlagn_send_tx_ant_config(struct iwl_priv *priv, u8 valid_tx_ant) { struct iwl_tx_ant_config_cmd tx_ant_cmd = { @@ -364,7 +316,6 @@ static int iwlagn_set_pan_params(struct iwl_priv *priv) } struct iwl_hcmd_ops iwlagn_hcmd = { - .rxon_assoc = iwlagn_send_rxon_assoc, .commit_rxon = iwlagn_commit_rxon, .set_rxon_chain = iwlagn_set_rxon_chain, .set_tx_ant = iwlagn_send_tx_ant_config, @@ -373,7 +324,6 @@ struct iwl_hcmd_ops iwlagn_hcmd = { }; struct iwl_hcmd_ops iwlagn_bt_hcmd = { - .rxon_assoc = iwlagn_send_rxon_assoc, .commit_rxon = iwlagn_commit_rxon, .set_rxon_chain = iwlagn_set_rxon_chain, .set_tx_ant = iwlagn_send_tx_ant_config, diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-rxon.c b/drivers/net/wireless/iwlwifi/iwl-agn-rxon.c index 202ef64..aba5bc9 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-rxon.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-rxon.c @@ -121,6 +121,54 @@ static int iwlagn_update_beacon(struct iwl_priv *priv, return iwlagn_send_beacon_cmd(priv); } +static int iwlagn_send_rxon_assoc(struct iwl_priv *priv, + struct iwl_rxon_context *ctx) +{ + int ret = 0; + struct iwl5000_rxon_assoc_cmd rxon_assoc; + const struct iwl_rxon_cmd *rxon1 = &ctx->staging; + const struct iwl_rxon_cmd *rxon2 = &ctx->active; + + if ((rxon1->flags == rxon2->flags) && + (rxon1->filter_flags == rxon2->filter_flags) && + (rxon1->cck_basic_rates == rxon2->cck_basic_rates) && + (rxon1->ofdm_ht_single_stream_basic_rates == + rxon2->ofdm_ht_single_stream_basic_rates) && + (rxon1->ofdm_ht_dual_stream_basic_rates == + rxon2->ofdm_ht_dual_stream_basic_rates) && + (rxon1->ofdm_ht_triple_stream_basic_rates == + rxon2->ofdm_ht_triple_stream_basic_rates) && + (rxon1->acquisition_data == rxon2->acquisition_data) && + (rxon1->rx_chain == rxon2->rx_chain) && + (rxon1->ofdm_basic_rates == rxon2->ofdm_basic_rates)) { + IWL_DEBUG_INFO(priv, "Using current RXON_ASSOC. Not resending.\n"); + return 0; + } + + rxon_assoc.flags = ctx->staging.flags; + rxon_assoc.filter_flags = ctx->staging.filter_flags; + rxon_assoc.ofdm_basic_rates = ctx->staging.ofdm_basic_rates; + rxon_assoc.cck_basic_rates = ctx->staging.cck_basic_rates; + rxon_assoc.reserved1 = 0; + rxon_assoc.reserved2 = 0; + rxon_assoc.reserved3 = 0; + rxon_assoc.ofdm_ht_single_stream_basic_rates = + ctx->staging.ofdm_ht_single_stream_basic_rates; + rxon_assoc.ofdm_ht_dual_stream_basic_rates = + ctx->staging.ofdm_ht_dual_stream_basic_rates; + rxon_assoc.rx_chain_select_flags = ctx->staging.rx_chain; + rxon_assoc.ofdm_ht_triple_stream_basic_rates = + ctx->staging.ofdm_ht_triple_stream_basic_rates; + rxon_assoc.acquisition_data = ctx->staging.acquisition_data; + + ret = iwl_send_cmd_pdu_async(priv, ctx->rxon_assoc_cmd, + sizeof(rxon_assoc), &rxon_assoc, NULL); + if (ret) + return ret; + + return ret; +} + /** * iwlagn_commit_rxon - commit staging_rxon to hardware * @@ -200,7 +248,7 @@ int iwlagn_commit_rxon(struct iwl_priv *priv, struct iwl_rxon_context *ctx) * and other flags for the current radio configuration. */ if (!iwl_full_rxon_required(priv, ctx)) { - ret = iwl_send_rxon_assoc(priv, ctx); + ret = iwlagn_send_rxon_assoc(priv, ctx); if (ret) { IWL_ERR(priv, "Error setting RXON_ASSOC (%d)\n", ret); return ret; diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.h b/drivers/net/wireless/iwlwifi/iwl-agn.h index c475ac4..7d8e16e 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.h +++ b/drivers/net/wireless/iwlwifi/iwl-agn.h @@ -256,8 +256,6 @@ int iwlagn_manage_ibss_station(struct iwl_priv *priv, struct ieee80211_vif *vif, bool add); /* hcmd */ -int iwlagn_send_rxon_assoc(struct iwl_priv *priv, - struct iwl_rxon_context *ctx); int iwlagn_send_tx_ant_config(struct iwl_priv *priv, u8 valid_tx_ant); int iwlagn_send_beacon_cmd(struct iwl_priv *priv); diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h index 6226e3d..4cdb85d 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.h +++ b/drivers/net/wireless/iwlwifi/iwl-core.h @@ -90,7 +90,6 @@ struct iwl_cmd; #define IWL_CMD(x) case x: return #x struct iwl_hcmd_ops { - int (*rxon_assoc)(struct iwl_priv *priv, struct iwl_rxon_context *ctx); int (*commit_rxon)(struct iwl_priv *priv, struct iwl_rxon_context *ctx); void (*set_rxon_chain)(struct iwl_priv *priv, struct iwl_rxon_context *ctx); @@ -645,11 +644,6 @@ void iwl_apm_stop(struct iwl_priv *priv); int iwl_apm_init(struct iwl_priv *priv); int iwl_send_rxon_timing(struct iwl_priv *priv, struct iwl_rxon_context *ctx); -static inline int iwl_send_rxon_assoc(struct iwl_priv *priv, - struct iwl_rxon_context *ctx) -{ - return priv->cfg->ops->hcmd->rxon_assoc(priv, ctx); -} static inline int iwlcore_commit_rxon(struct iwl_priv *priv, struct iwl_rxon_context *ctx) { -- cgit v0.10.2 From 89e746b244064406c3bfe442bb64c3230f42fa98 Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Tue, 19 Apr 2011 16:52:58 -0700 Subject: iwlagn: remove 5000 from rxon_assoc structure The data structure is shared by all _agn devices, remove the reference to 5000 Signed-off-by: Wey-Yi Guy diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-rxon.c b/drivers/net/wireless/iwlwifi/iwl-agn-rxon.c index aba5bc9..7f52ab8 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-rxon.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-rxon.c @@ -125,7 +125,7 @@ static int iwlagn_send_rxon_assoc(struct iwl_priv *priv, struct iwl_rxon_context *ctx) { int ret = 0; - struct iwl5000_rxon_assoc_cmd rxon_assoc; + struct iwl_rxon_assoc_cmd rxon_assoc; const struct iwl_rxon_cmd *rxon1 = &ctx->staging; const struct iwl_rxon_cmd *rxon2 = &ctx->active; diff --git a/drivers/net/wireless/iwlwifi/iwl-commands.h b/drivers/net/wireless/iwlwifi/iwl-commands.h index e125896..5fdad65 100644 --- a/drivers/net/wireless/iwlwifi/iwl-commands.h +++ b/drivers/net/wireless/iwlwifi/iwl-commands.h @@ -661,7 +661,7 @@ struct iwl_rxon_cmd { /* * REPLY_RXON_ASSOC = 0x11 (command, has simple generic response) */ -struct iwl5000_rxon_assoc_cmd { +struct iwl_rxon_assoc_cmd { __le32 flags; __le32 filter_flags; u8 ofdm_basic_rates; -- cgit v0.10.2 From c1821c95c13240c2c8d3da8845c2021e575e29c6 Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Tue, 19 Apr 2011 16:52:59 -0700 Subject: iwlagn: connect and disconnect sequence for RXON No functional changes, separate the connect and disconnect sequences in RXON commit function, easier to read and understand. Signed-off-by: Wey-Yi Guy diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-rxon.c b/drivers/net/wireless/iwlwifi/iwl-agn-rxon.c index 7f52ab8..178b2b5 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-rxon.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-rxon.c @@ -169,6 +169,103 @@ static int iwlagn_send_rxon_assoc(struct iwl_priv *priv, return ret; } +static int iwlagn_rxon_disconn(struct iwl_priv *priv, + struct iwl_rxon_context *ctx) +{ + int ret; + struct iwl_rxon_cmd *active = (void *)&ctx->active; + + if (ctx->ctxid == IWL_RXON_CTX_BSS) + ret = iwlagn_disable_bss(priv, ctx, &ctx->staging); + else + ret = iwlagn_disable_pan(priv, ctx, &ctx->staging); + if (ret) + return ret; + + /* + * Un-assoc RXON clears the station table and WEP + * keys, so we have to restore those afterwards. + */ + iwl_clear_ucode_stations(priv, ctx); + iwl_restore_stations(priv, ctx); + ret = iwl_restore_default_wep_keys(priv, ctx); + if (ret) { + IWL_ERR(priv, "Failed to restore WEP keys (%d)\n", ret); + return ret; + } + + memcpy(active, &ctx->staging, sizeof(*active)); + return 0; +} + +static int iwlagn_rxon_connect(struct iwl_priv *priv, + struct iwl_rxon_context *ctx) +{ + int ret; + struct iwl_rxon_cmd *active = (void *)&ctx->active; + + /* RXON timing must be before associated RXON */ + ret = iwl_send_rxon_timing(priv, ctx); + if (ret) { + IWL_ERR(priv, "Failed to send timing (%d)!\n", ret); + return ret; + } + /* QoS info may be cleared by previous un-assoc RXON */ + iwlagn_update_qos(priv, ctx); + + /* + * We'll run into this code path when beaconing is + * enabled, but then we also need to send the beacon + * to the device. + */ + if (ctx->vif && (ctx->vif->type == NL80211_IFTYPE_AP)) { + ret = iwlagn_update_beacon(priv, ctx->vif); + if (ret) { + IWL_ERR(priv, + "Error sending required beacon (%d)!\n", + ret); + return ret; + } + } + + priv->start_calib = 0; + /* + * Apply the new configuration. + * + * Associated RXON doesn't clear the station table in uCode, + * so we don't need to restore stations etc. after this. + */ + ret = iwl_send_cmd_pdu(priv, ctx->rxon_cmd, + sizeof(struct iwl_rxon_cmd), &ctx->staging); + if (ret) { + IWL_ERR(priv, "Error setting new RXON (%d)\n", ret); + return ret; + } + memcpy(active, &ctx->staging, sizeof(*active)); + + iwl_reprogram_ap_sta(priv, ctx); + + /* IBSS beacon needs to be sent after setting assoc */ + if (ctx->vif && (ctx->vif->type == NL80211_IFTYPE_ADHOC)) + if (iwlagn_update_beacon(priv, ctx->vif)) + IWL_ERR(priv, "Error sending IBSS beacon\n"); + iwl_init_sensitivity(priv); + + /* + * If we issue a new RXON command which required a tune then + * we must send a new TXPOWER command or we won't be able to + * Tx any frames. + * + * It's expected we set power here if channel is changing. + */ + ret = iwl_set_tx_power(priv, priv->tx_power_next, true); + if (ret) { + IWL_ERR(priv, "Error sending TX power (%d)\n", ret); + return ret; + } + return 0; +} + /** * iwlagn_commit_rxon - commit staging_rxon to hardware * @@ -176,6 +273,16 @@ static int iwlagn_send_rxon_assoc(struct iwl_priv *priv, * the active_rxon structure is updated with the new data. This * function correctly transitions out of the RXON_ASSOC_MSK state if * a HW tune is required based on the RXON structure changes. + * + * The connect/disconnect flow should be as the following: + * + * 1. make sure send RXON command with association bit unset if not connect + * this should include the channel and the band for the candidate + * to be connected to + * 2. Add Station before RXON association with the AP + * 3. RXON_timing has to send before RXON for connection + * 4. full RXON command - associated bit set + * 5. use RXON_ASSOC command to update any flags changes */ int iwlagn_commit_rxon(struct iwl_priv *priv, struct iwl_rxon_context *ctx) { @@ -225,6 +332,7 @@ int iwlagn_commit_rxon(struct iwl_priv *priv, struct iwl_rxon_context *ctx) else ctx->staging.flags &= ~RXON_FLG_SHORT_SLOT_MSK; + iwl_print_rx_config_cmd(priv, ctx); ret = iwl_check_rxon_cmd(priv, ctx); if (ret) { IWL_ERR(priv, "Invalid RXON configuration. Not committing.\n"); @@ -255,7 +363,6 @@ int iwlagn_commit_rxon(struct iwl_priv *priv, struct iwl_rxon_context *ctx) } memcpy(active, &ctx->staging, sizeof(*active)); - iwl_print_rx_config_cmd(priv, ctx); return 0; } @@ -283,92 +390,13 @@ int iwlagn_commit_rxon(struct iwl_priv *priv, struct iwl_rxon_context *ctx) * set up filters in the device. */ if ((old_assoc && new_assoc) || !new_assoc) { - if (ctx->ctxid == IWL_RXON_CTX_BSS) - ret = iwlagn_disable_bss(priv, ctx, &ctx->staging); - else - ret = iwlagn_disable_pan(priv, ctx, &ctx->staging); + ret = iwlagn_rxon_disconn(priv, ctx); if (ret) return ret; - - memcpy(active, &ctx->staging, sizeof(*active)); - - /* - * Un-assoc RXON clears the station table and WEP - * keys, so we have to restore those afterwards. - */ - iwl_clear_ucode_stations(priv, ctx); - iwl_restore_stations(priv, ctx); - ret = iwl_restore_default_wep_keys(priv, ctx); - if (ret) { - IWL_ERR(priv, "Failed to restore WEP keys (%d)\n", ret); - return ret; - } } - /* RXON timing must be before associated RXON */ - ret = iwl_send_rxon_timing(priv, ctx); - if (ret) { - IWL_ERR(priv, "Failed to send timing (%d)!\n", ret); - return ret; - } - - if (new_assoc) { - /* QoS info may be cleared by previous un-assoc RXON */ - iwlagn_update_qos(priv, ctx); - - /* - * We'll run into this code path when beaconing is - * enabled, but then we also need to send the beacon - * to the device. - */ - if (ctx->vif && (ctx->vif->type == NL80211_IFTYPE_AP)) { - ret = iwlagn_update_beacon(priv, ctx->vif); - if (ret) { - IWL_ERR(priv, - "Error sending required beacon (%d)!\n", - ret); - return ret; - } - } - - priv->start_calib = 0; - /* - * Apply the new configuration. - * - * Associated RXON doesn't clear the station table in uCode, - * so we don't need to restore stations etc. after this. - */ - ret = iwl_send_cmd_pdu(priv, ctx->rxon_cmd, - sizeof(struct iwl_rxon_cmd), &ctx->staging); - if (ret) { - IWL_ERR(priv, "Error setting new RXON (%d)\n", ret); - return ret; - } - memcpy(active, &ctx->staging, sizeof(*active)); - - iwl_reprogram_ap_sta(priv, ctx); - - /* IBSS beacon needs to be sent after setting assoc */ - if (ctx->vif && (ctx->vif->type == NL80211_IFTYPE_ADHOC)) - if (iwlagn_update_beacon(priv, ctx->vif)) - IWL_ERR(priv, "Error sending IBSS beacon\n"); - } - - iwl_print_rx_config_cmd(priv, ctx); - - iwl_init_sensitivity(priv); - - /* - * If we issue a new RXON command which required a tune then we must - * send a new TXPOWER command or we won't be able to Tx any frames. - * - * It's expected we set power here if channel is changing. - */ - ret = iwl_set_tx_power(priv, priv->tx_power_next, true); - if (ret) { - IWL_ERR(priv, "Error sending TX power (%d)\n", ret); - return ret; - } + if (new_assoc) + return iwlagn_rxon_connect(priv, ctx); return 0; } -- cgit v0.10.2 From d2690c0db7146b12e4fc2d572053c823e512758a Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 20 Apr 2011 09:10:39 -0700 Subject: iwlagn: use proper good CRC threshold behaviour New microcode versions use the good CRC threshold field differently, as a flag, and in that case we should set it to 1/0 instead of 1/65535 for an active/passive scan. The new behaviour is advertised by the uCode with a feature flag. Signed-off-by: Johannes Berg Signed-off-by: Wey-Yi Guy diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-lib.c b/drivers/net/wireless/iwlwifi/iwl-agn-lib.c index 75e1035..7fe9e0f 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-lib.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-lib.c @@ -1294,9 +1294,17 @@ int iwlagn_request_scan(struct iwl_priv *priv, struct ieee80211_vif *vif) * mean we never reach it, but at the same time work around * the aforementioned issue. Thus use IWL_GOOD_CRC_TH_NEVER * here instead of IWL_GOOD_CRC_TH_DISABLED. + * + * This was fixed in later versions along with some other + * scan changes, and the threshold behaves as a flag in those + * versions. */ - scan->good_CRC_th = is_active ? IWL_GOOD_CRC_TH_DEFAULT : - IWL_GOOD_CRC_TH_NEVER; + if (priv->new_scan_threshold_behaviour) + scan->good_CRC_th = is_active ? IWL_GOOD_CRC_TH_DEFAULT : + IWL_GOOD_CRC_TH_DISABLED; + else + scan->good_CRC_th = is_active ? IWL_GOOD_CRC_TH_DEFAULT : + IWL_GOOD_CRC_TH_NEVER; band = priv->scan_band; diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index c27147c..395d1ad 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -1716,6 +1716,9 @@ static void iwl_ucode_callback(const struct firmware *ucode_raw, void *context) priv->cfg->base_params->max_event_log_size; priv->_agn.inst_errlog_ptr = pieces.inst_errlog_ptr; + priv->new_scan_threshold_behaviour = + !!(ucode_capa.flags & IWL_UCODE_TLV_FLAGS_NEWSCAN); + if (ucode_capa.flags & IWL_UCODE_TLV_FLAGS_PAN) { priv->valid_contexts |= BIT(IWL_RXON_CTX_PAN); priv->sta_key_max_num = STA_KEY_MAX_NUM_PAN; diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index 197fa74..f098eff 100644 --- a/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h @@ -547,12 +547,13 @@ enum iwl_ucode_tlv_type { * enum iwl_ucode_tlv_flag - ucode API flags * @IWL_UCODE_TLV_FLAGS_PAN: This is PAN capable microcode; this previously * was a separate TLV but moved here to save space. - * @IWL_UCODE_TLV_FLAGS_RESERVED_1: reserved + * @IWL_UCODE_TLV_FLAGS_NEWSCAN: new uCode scan behaviour on hidden SSID, + * treats good CRC threshold as a boolean * @IWL_UCODE_TLV_FLAGS_MFP: This uCode image supports MFP (802.11w). */ enum iwl_ucode_tlv_flag { IWL_UCODE_TLV_FLAGS_PAN = BIT(0), - IWL_UCODE_TLV_FLAGS_RESERVED_1 = BIT(1), + IWL_UCODE_TLV_FLAGS_NEWSCAN = BIT(1), IWL_UCODE_TLV_FLAGS_MFP = BIT(2), }; @@ -1263,6 +1264,8 @@ struct iwl_priv { /* max number of station keys */ u8 sta_key_max_num; + bool new_scan_threshold_behaviour; + /* EEPROM MAC addresses */ struct mac_address addresses[2]; -- cgit v0.10.2 From b4ed221daba1b129c3efff8a7352d9791d034330 Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Sat, 30 Apr 2011 08:55:16 -0700 Subject: iwlagn: new 105 series device Correction for new 105 series devices Signed-off-by: Wey-Yi Guy diff --git a/drivers/net/wireless/iwlwifi/iwl-2000.c b/drivers/net/wireless/iwlwifi/iwl-2000.c index e76e02c..f90d6af 100644 --- a/drivers/net/wireless/iwlwifi/iwl-2000.c +++ b/drivers/net/wireless/iwlwifi/iwl-2000.c @@ -51,12 +51,12 @@ /* Highest firmware API version supported */ #define IWL2030_UCODE_API_MAX 5 #define IWL2000_UCODE_API_MAX 5 -#define IWL200_UCODE_API_MAX 5 +#define IWL105_UCODE_API_MAX 5 /* Lowest firmware API version supported */ #define IWL2030_UCODE_API_MIN 5 #define IWL2000_UCODE_API_MIN 5 -#define IWL200_UCODE_API_MIN 5 +#define IWL105_UCODE_API_MIN 5 #define IWL2030_FW_PRE "iwlwifi-2030-" #define IWL2030_MODULE_FIRMWARE(api) IWL2030_FW_PRE #api ".ucode" @@ -64,8 +64,8 @@ #define IWL2000_FW_PRE "iwlwifi-2000-" #define IWL2000_MODULE_FIRMWARE(api) IWL2000_FW_PRE #api ".ucode" -#define IWL200_FW_PRE "iwlwifi-200-" -#define IWL200_MODULE_FIRMWARE(api) IWL200_FW_PRE #api ".ucode" +#define IWL105_FW_PRE "iwlwifi-105-" +#define IWL105_MODULE_FIRMWARE(api) IWL105_FW_PRE #api ".ucode" static void iwl2000_set_ct_threshold(struct iwl_priv *priv) { @@ -312,13 +312,13 @@ static const struct iwl_ops iwl2030_ops = { .utils = &iwlagn_hcmd_utils, }; -static const struct iwl_ops iwl200_ops = { +static const struct iwl_ops iwl105_ops = { .lib = &iwl2000_lib, .hcmd = &iwlagn_hcmd, .utils = &iwlagn_hcmd_utils, }; -static const struct iwl_ops iwl230_ops = { +static const struct iwl_ops iwl135_ops = { .lib = &iwl2000_lib, .hcmd = &iwlagn_bt_hcmd, .utils = &iwlagn_hcmd_utils, @@ -429,13 +429,13 @@ struct iwl_cfg iwl2030_2bg_cfg = { IWL_DEVICE_2030, }; -#define IWL_DEVICE_200 \ - .fw_name_pre = IWL200_FW_PRE, \ - .ucode_api_max = IWL200_UCODE_API_MAX, \ - .ucode_api_min = IWL200_UCODE_API_MIN, \ +#define IWL_DEVICE_105 \ + .fw_name_pre = IWL105_FW_PRE, \ + .ucode_api_max = IWL105_UCODE_API_MAX, \ + .ucode_api_min = IWL105_UCODE_API_MIN, \ .eeprom_ver = EEPROM_2000_EEPROM_VERSION, \ .eeprom_calib_ver = EEPROM_2000_TX_POWER_VERSION, \ - .ops = &iwl200_ops, \ + .ops = &iwl105_ops, \ .mod_params = &iwlagn_mod_params, \ .base_params = &iwl2000_base_params, \ .need_dc_calib = true, \ @@ -444,24 +444,24 @@ struct iwl_cfg iwl2030_2bg_cfg = { .adv_pm = true, \ .rx_with_siso_diversity = true \ -struct iwl_cfg iwl200_bg_cfg = { - .name = "200 Series 1x1 BG", - IWL_DEVICE_200, +struct iwl_cfg iwl105_bg_cfg = { + .name = "105 Series 1x1 BG", + IWL_DEVICE_105, }; -struct iwl_cfg iwl200_bgn_cfg = { - .name = "200 Series 1x1 BGN", - IWL_DEVICE_200, +struct iwl_cfg iwl105_bgn_cfg = { + .name = "105 Series 1x1 BGN", + IWL_DEVICE_105, .ht_params = &iwl2000_ht_params, }; -#define IWL_DEVICE_230 \ - .fw_name_pre = IWL200_FW_PRE, \ - .ucode_api_max = IWL200_UCODE_API_MAX, \ - .ucode_api_min = IWL200_UCODE_API_MIN, \ +#define IWL_DEVICE_135 \ + .fw_name_pre = IWL105_FW_PRE, \ + .ucode_api_max = IWL105_UCODE_API_MAX, \ + .ucode_api_min = IWL105_UCODE_API_MIN, \ .eeprom_ver = EEPROM_2000_EEPROM_VERSION, \ .eeprom_calib_ver = EEPROM_2000_TX_POWER_VERSION, \ - .ops = &iwl230_ops, \ + .ops = &iwl135_ops, \ .mod_params = &iwlagn_mod_params, \ .base_params = &iwl2030_base_params, \ .bt_params = &iwl2030_bt_params, \ @@ -471,17 +471,17 @@ struct iwl_cfg iwl200_bgn_cfg = { .adv_pm = true, \ .rx_with_siso_diversity = true \ -struct iwl_cfg iwl230_bg_cfg = { - .name = "200 Series 1x1 BG/BT", - IWL_DEVICE_230, +struct iwl_cfg iwl135_bg_cfg = { + .name = "105 Series 1x1 BG/BT", + IWL_DEVICE_135, }; -struct iwl_cfg iwl230_bgn_cfg = { - .name = "200 Series 1x1 BGN/BT", - IWL_DEVICE_230, +struct iwl_cfg iwl135_bgn_cfg = { + .name = "105 Series 1x1 BGN/BT", + IWL_DEVICE_135, .ht_params = &iwl2000_ht_params, }; MODULE_FIRMWARE(IWL2000_MODULE_FIRMWARE(IWL2000_UCODE_API_MAX)); MODULE_FIRMWARE(IWL2030_MODULE_FIRMWARE(IWL2030_UCODE_API_MAX)); -MODULE_FIRMWARE(IWL200_MODULE_FIRMWARE(IWL200_UCODE_API_MAX)); +MODULE_FIRMWARE(IWL105_MODULE_FIRMWARE(IWL105_UCODE_API_MAX)); diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index 395d1ad..8232245 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -4129,21 +4129,21 @@ static DEFINE_PCI_DEVICE_TABLE(iwl_hw_card_ids) = { {IWL_PCI_DEVICE(0x088F, 0x4266, iwl6035_2bg_cfg)}, {IWL_PCI_DEVICE(0x088E, 0x4466, iwl6035_2bg_cfg)}, -/* 200 Series */ - {IWL_PCI_DEVICE(0x0894, 0x0022, iwl200_bgn_cfg)}, - {IWL_PCI_DEVICE(0x0895, 0x0222, iwl200_bgn_cfg)}, - {IWL_PCI_DEVICE(0x0894, 0x0422, iwl200_bgn_cfg)}, - {IWL_PCI_DEVICE(0x0894, 0x0026, iwl200_bg_cfg)}, - {IWL_PCI_DEVICE(0x0895, 0x0226, iwl200_bg_cfg)}, - {IWL_PCI_DEVICE(0x0894, 0x0426, iwl200_bg_cfg)}, - -/* 230 Series */ - {IWL_PCI_DEVICE(0x0892, 0x0062, iwl230_bgn_cfg)}, - {IWL_PCI_DEVICE(0x0893, 0x0262, iwl230_bgn_cfg)}, - {IWL_PCI_DEVICE(0x0892, 0x0462, iwl230_bgn_cfg)}, - {IWL_PCI_DEVICE(0x0892, 0x0066, iwl230_bg_cfg)}, - {IWL_PCI_DEVICE(0x0893, 0x0266, iwl230_bg_cfg)}, - {IWL_PCI_DEVICE(0x0892, 0x0466, iwl230_bg_cfg)}, +/* 105 Series */ + {IWL_PCI_DEVICE(0x0894, 0x0022, iwl105_bgn_cfg)}, + {IWL_PCI_DEVICE(0x0895, 0x0222, iwl105_bgn_cfg)}, + {IWL_PCI_DEVICE(0x0894, 0x0422, iwl105_bgn_cfg)}, + {IWL_PCI_DEVICE(0x0894, 0x0026, iwl105_bg_cfg)}, + {IWL_PCI_DEVICE(0x0895, 0x0226, iwl105_bg_cfg)}, + {IWL_PCI_DEVICE(0x0894, 0x0426, iwl105_bg_cfg)}, + +/* 135 Series */ + {IWL_PCI_DEVICE(0x0892, 0x0062, iwl135_bgn_cfg)}, + {IWL_PCI_DEVICE(0x0893, 0x0262, iwl135_bgn_cfg)}, + {IWL_PCI_DEVICE(0x0892, 0x0462, iwl135_bgn_cfg)}, + {IWL_PCI_DEVICE(0x0892, 0x0066, iwl135_bg_cfg)}, + {IWL_PCI_DEVICE(0x0893, 0x0266, iwl135_bg_cfg)}, + {IWL_PCI_DEVICE(0x0892, 0x0466, iwl135_bg_cfg)}, {0} }; diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.h b/drivers/net/wireless/iwlwifi/iwl-agn.h index 7d8e16e..9d644d4 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.h +++ b/drivers/net/wireless/iwlwifi/iwl-agn.h @@ -102,10 +102,10 @@ extern struct iwl_cfg iwl2030_2bg_cfg; extern struct iwl_cfg iwl6035_2agn_cfg; extern struct iwl_cfg iwl6035_2abg_cfg; extern struct iwl_cfg iwl6035_2bg_cfg; -extern struct iwl_cfg iwl200_bg_cfg; -extern struct iwl_cfg iwl200_bgn_cfg; -extern struct iwl_cfg iwl230_bg_cfg; -extern struct iwl_cfg iwl230_bgn_cfg; +extern struct iwl_cfg iwl105_bg_cfg; +extern struct iwl_cfg iwl105_bgn_cfg; +extern struct iwl_cfg iwl135_bg_cfg; +extern struct iwl_cfg iwl135_bgn_cfg; extern struct iwl_mod_params iwlagn_mod_params; extern struct iwl_hcmd_ops iwlagn_hcmd; -- cgit v0.10.2 From 9d143e9a0d68025efe902d86eb6207cbec36dcdb Mon Sep 17 00:00:00 2001 From: Don Fry Date: Wed, 20 Apr 2011 15:23:57 -0700 Subject: iwlagn: mod param cleanup All agn devices use the same module parameter structure. Delete the indirection and access the structure diretly. Signed-off-by: Don Fry Signed-off-by: Wey-Yi Guy diff --git a/drivers/net/wireless/iwlwifi/iwl-1000.c b/drivers/net/wireless/iwlwifi/iwl-1000.c index baf8011..d2b1be6 100644 --- a/drivers/net/wireless/iwlwifi/iwl-1000.c +++ b/drivers/net/wireless/iwlwifi/iwl-1000.c @@ -121,10 +121,10 @@ static struct iwl_sensitivity_ranges iwl1000_sensitivity = { static int iwl1000_hw_set_hw_params(struct iwl_priv *priv) { - if (priv->cfg->mod_params->num_of_queues >= IWL_MIN_NUM_QUEUES && - priv->cfg->mod_params->num_of_queues <= IWLAGN_NUM_QUEUES) + if (iwlagn_mod_params.num_of_queues >= IWL_MIN_NUM_QUEUES && + iwlagn_mod_params.num_of_queues <= IWLAGN_NUM_QUEUES) priv->cfg->base_params->num_of_queues = - priv->cfg->mod_params->num_of_queues; + iwlagn_mod_params.num_of_queues; priv->hw_params.max_txq_num = priv->cfg->base_params->num_of_queues; priv->hw_params.dma_chnl_num = FH50_TCSR_CHNL_NUM; @@ -249,7 +249,6 @@ static struct iwl_ht_params iwl1000_ht_params = { .eeprom_ver = EEPROM_1000_EEPROM_VERSION, \ .eeprom_calib_ver = EEPROM_1000_TX_POWER_VERSION, \ .ops = &iwl1000_ops, \ - .mod_params = &iwlagn_mod_params, \ .base_params = &iwl1000_base_params, \ .led_mode = IWL_LED_BLINK @@ -271,7 +270,6 @@ struct iwl_cfg iwl1000_bg_cfg = { .eeprom_ver = EEPROM_1000_EEPROM_VERSION, \ .eeprom_calib_ver = EEPROM_1000_TX_POWER_VERSION, \ .ops = &iwl1000_ops, \ - .mod_params = &iwlagn_mod_params, \ .base_params = &iwl1000_base_params, \ .led_mode = IWL_LED_RF_STATE, \ .rx_with_siso_diversity = true diff --git a/drivers/net/wireless/iwlwifi/iwl-2000.c b/drivers/net/wireless/iwlwifi/iwl-2000.c index f90d6af..476150f 100644 --- a/drivers/net/wireless/iwlwifi/iwl-2000.c +++ b/drivers/net/wireless/iwlwifi/iwl-2000.c @@ -128,10 +128,10 @@ static struct iwl_sensitivity_ranges iwl2000_sensitivity = { static int iwl2000_hw_set_hw_params(struct iwl_priv *priv) { - if (priv->cfg->mod_params->num_of_queues >= IWL_MIN_NUM_QUEUES && - priv->cfg->mod_params->num_of_queues <= IWLAGN_NUM_QUEUES) + if (iwlagn_mod_params.num_of_queues >= IWL_MIN_NUM_QUEUES && + iwlagn_mod_params.num_of_queues <= IWLAGN_NUM_QUEUES) priv->cfg->base_params->num_of_queues = - priv->cfg->mod_params->num_of_queues; + iwlagn_mod_params.num_of_queues; priv->hw_params.max_txq_num = priv->cfg->base_params->num_of_queues; priv->hw_params.dma_chnl_num = FH50_TCSR_CHNL_NUM; @@ -383,7 +383,6 @@ static struct iwl_bt_params iwl2030_bt_params = { .eeprom_ver = EEPROM_2000_EEPROM_VERSION, \ .eeprom_calib_ver = EEPROM_2000_TX_POWER_VERSION, \ .ops = &iwl2000_ops, \ - .mod_params = &iwlagn_mod_params, \ .base_params = &iwl2000_base_params, \ .need_dc_calib = true, \ .need_temp_offset_calib = true, \ @@ -409,7 +408,6 @@ struct iwl_cfg iwl2000_2bg_cfg = { .eeprom_ver = EEPROM_2000_EEPROM_VERSION, \ .eeprom_calib_ver = EEPROM_2000_TX_POWER_VERSION, \ .ops = &iwl2030_ops, \ - .mod_params = &iwlagn_mod_params, \ .base_params = &iwl2030_base_params, \ .bt_params = &iwl2030_bt_params, \ .need_dc_calib = true, \ @@ -436,7 +434,6 @@ struct iwl_cfg iwl2030_2bg_cfg = { .eeprom_ver = EEPROM_2000_EEPROM_VERSION, \ .eeprom_calib_ver = EEPROM_2000_TX_POWER_VERSION, \ .ops = &iwl105_ops, \ - .mod_params = &iwlagn_mod_params, \ .base_params = &iwl2000_base_params, \ .need_dc_calib = true, \ .need_temp_offset_calib = true, \ @@ -462,7 +459,6 @@ struct iwl_cfg iwl105_bgn_cfg = { .eeprom_ver = EEPROM_2000_EEPROM_VERSION, \ .eeprom_calib_ver = EEPROM_2000_TX_POWER_VERSION, \ .ops = &iwl135_ops, \ - .mod_params = &iwlagn_mod_params, \ .base_params = &iwl2030_base_params, \ .bt_params = &iwl2030_bt_params, \ .need_dc_calib = true, \ diff --git a/drivers/net/wireless/iwlwifi/iwl-5000.c b/drivers/net/wireless/iwlwifi/iwl-5000.c index 655afc1..969c91a 100644 --- a/drivers/net/wireless/iwlwifi/iwl-5000.c +++ b/drivers/net/wireless/iwlwifi/iwl-5000.c @@ -165,10 +165,10 @@ static void iwl5000_set_ct_threshold(struct iwl_priv *priv) static int iwl5000_hw_set_hw_params(struct iwl_priv *priv) { - if (priv->cfg->mod_params->num_of_queues >= IWL_MIN_NUM_QUEUES && - priv->cfg->mod_params->num_of_queues <= IWLAGN_NUM_QUEUES) + if (iwlagn_mod_params.num_of_queues >= IWL_MIN_NUM_QUEUES && + iwlagn_mod_params.num_of_queues <= IWLAGN_NUM_QUEUES) priv->cfg->base_params->num_of_queues = - priv->cfg->mod_params->num_of_queues; + iwlagn_mod_params.num_of_queues; priv->hw_params.max_txq_num = priv->cfg->base_params->num_of_queues; priv->hw_params.dma_chnl_num = FH50_TCSR_CHNL_NUM; @@ -210,10 +210,10 @@ static int iwl5000_hw_set_hw_params(struct iwl_priv *priv) static int iwl5150_hw_set_hw_params(struct iwl_priv *priv) { - if (priv->cfg->mod_params->num_of_queues >= IWL_MIN_NUM_QUEUES && - priv->cfg->mod_params->num_of_queues <= IWLAGN_NUM_QUEUES) + if (iwlagn_mod_params.num_of_queues >= IWL_MIN_NUM_QUEUES && + iwlagn_mod_params.num_of_queues <= IWLAGN_NUM_QUEUES) priv->cfg->base_params->num_of_queues = - priv->cfg->mod_params->num_of_queues; + iwlagn_mod_params.num_of_queues; priv->hw_params.max_txq_num = priv->cfg->base_params->num_of_queues; priv->hw_params.dma_chnl_num = FH50_TCSR_CHNL_NUM; @@ -468,7 +468,6 @@ static struct iwl_ht_params iwl5000_ht_params = { .eeprom_ver = EEPROM_5000_EEPROM_VERSION, \ .eeprom_calib_ver = EEPROM_5000_TX_POWER_VERSION, \ .ops = &iwl5000_ops, \ - .mod_params = &iwlagn_mod_params, \ .base_params = &iwl5000_base_params, \ .led_mode = IWL_LED_BLINK @@ -512,7 +511,6 @@ struct iwl_cfg iwl5350_agn_cfg = { .eeprom_ver = EEPROM_5050_EEPROM_VERSION, .eeprom_calib_ver = EEPROM_5050_TX_POWER_VERSION, .ops = &iwl5000_ops, - .mod_params = &iwlagn_mod_params, .base_params = &iwl5000_base_params, .ht_params = &iwl5000_ht_params, .led_mode = IWL_LED_BLINK, @@ -526,7 +524,6 @@ struct iwl_cfg iwl5350_agn_cfg = { .eeprom_ver = EEPROM_5050_EEPROM_VERSION, \ .eeprom_calib_ver = EEPROM_5050_TX_POWER_VERSION, \ .ops = &iwl5150_ops, \ - .mod_params = &iwlagn_mod_params, \ .base_params = &iwl5000_base_params, \ .need_dc_calib = true, \ .led_mode = IWL_LED_BLINK, \ diff --git a/drivers/net/wireless/iwlwifi/iwl-6000.c b/drivers/net/wireless/iwlwifi/iwl-6000.c index 905eb57..91edb57 100644 --- a/drivers/net/wireless/iwlwifi/iwl-6000.c +++ b/drivers/net/wireless/iwlwifi/iwl-6000.c @@ -154,10 +154,10 @@ static struct iwl_sensitivity_ranges iwl6000_sensitivity = { static int iwl6000_hw_set_hw_params(struct iwl_priv *priv) { - if (priv->cfg->mod_params->num_of_queues >= IWL_MIN_NUM_QUEUES && - priv->cfg->mod_params->num_of_queues <= IWLAGN_NUM_QUEUES) + if (iwlagn_mod_params.num_of_queues >= IWL_MIN_NUM_QUEUES && + iwlagn_mod_params.num_of_queues <= IWLAGN_NUM_QUEUES) priv->cfg->base_params->num_of_queues = - priv->cfg->mod_params->num_of_queues; + iwlagn_mod_params.num_of_queues; priv->hw_params.max_txq_num = priv->cfg->base_params->num_of_queues; priv->hw_params.dma_chnl_num = FH50_TCSR_CHNL_NUM; @@ -482,7 +482,6 @@ static struct iwl_bt_params iwl6000_bt_params = { .eeprom_ver = EEPROM_6005_EEPROM_VERSION, \ .eeprom_calib_ver = EEPROM_6005_TX_POWER_VERSION, \ .ops = &iwl6000_ops, \ - .mod_params = &iwlagn_mod_params, \ .base_params = &iwl6000_g2_base_params, \ .need_dc_calib = true, \ .need_temp_offset_calib = true, \ @@ -511,7 +510,6 @@ struct iwl_cfg iwl6005_2bg_cfg = { .eeprom_ver = EEPROM_6030_EEPROM_VERSION, \ .eeprom_calib_ver = EEPROM_6030_TX_POWER_VERSION, \ .ops = &iwl6030_ops, \ - .mod_params = &iwlagn_mod_params, \ .base_params = &iwl6000_g2_base_params, \ .bt_params = &iwl6000_bt_params, \ .need_dc_calib = true, \ @@ -593,7 +591,6 @@ struct iwl_cfg iwl130_bg_cfg = { .eeprom_ver = EEPROM_6000_EEPROM_VERSION, \ .eeprom_calib_ver = EEPROM_6000_TX_POWER_VERSION, \ .ops = &iwl6000_ops, \ - .mod_params = &iwlagn_mod_params, \ .base_params = &iwl6000_base_params, \ .pa_type = IWL_PA_INTERNAL, \ .led_mode = IWL_LED_BLINK @@ -623,7 +620,6 @@ struct iwl_cfg iwl6000i_2bg_cfg = { .ops = &iwl6050_ops, \ .eeprom_ver = EEPROM_6050_EEPROM_VERSION, \ .eeprom_calib_ver = EEPROM_6050_TX_POWER_VERSION, \ - .mod_params = &iwlagn_mod_params, \ .base_params = &iwl6050_base_params, \ .need_dc_calib = true, \ .led_mode = IWL_LED_BLINK, \ @@ -648,7 +644,6 @@ struct iwl_cfg iwl6150_bgn_cfg = { .eeprom_ver = EEPROM_6150_EEPROM_VERSION, .eeprom_calib_ver = EEPROM_6150_TX_POWER_VERSION, .ops = &iwl6150_ops, - .mod_params = &iwlagn_mod_params, .base_params = &iwl6050_base_params, .ht_params = &iwl6000_ht_params, .need_dc_calib = true, @@ -664,7 +659,6 @@ struct iwl_cfg iwl6000_3agn_cfg = { .eeprom_ver = EEPROM_6000_EEPROM_VERSION, .eeprom_calib_ver = EEPROM_6000_TX_POWER_VERSION, .ops = &iwl6000_ops, - .mod_params = &iwlagn_mod_params, .base_params = &iwl6000_base_params, .ht_params = &iwl6000_ht_params, .need_dc_calib = true, diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-lib.c b/drivers/net/wireless/iwlwifi/iwl-agn-lib.c index 7fe9e0f..8e79653 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-lib.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-lib.c @@ -665,7 +665,7 @@ int iwlagn_rx_init(struct iwl_priv *priv, struct iwl_rx_queue *rxq) rb_timeout = RX_RB_TIMEOUT; - if (priv->cfg->mod_params->amsdu_size_8K) + if (iwlagn_mod_params.amsdu_size_8K) rb_size = FH_RCSR_RX_CONFIG_REG_VAL_RB_SIZE_8K; else rb_size = FH_RCSR_RX_CONFIG_REG_VAL_RB_SIZE_4K; diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-rxon.c b/drivers/net/wireless/iwlwifi/iwl-agn-rxon.c index 178b2b5..0238743 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-rxon.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-rxon.c @@ -372,7 +372,7 @@ int iwlagn_commit_rxon(struct iwl_priv *priv, struct iwl_rxon_context *ctx) return ret; } - iwl_set_rxon_hwcrypto(priv, ctx, !priv->cfg->mod_params->sw_crypto); + iwl_set_rxon_hwcrypto(priv, ctx, !iwlagn_mod_params.sw_crypto); IWL_DEBUG_INFO(priv, "Going to commit RXON\n" diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index 8232245..003d524 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -2834,7 +2834,7 @@ static int iwlagn_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, IWL_DEBUG_MAC80211(priv, "enter\n"); - if (priv->cfg->mod_params->sw_crypto) { + if (iwlagn_mod_params.sw_crypto) { IWL_DEBUG_MAC80211(priv, "leave - hwcrypto disabled\n"); return -EOPNOTSUPP; } @@ -3522,14 +3522,14 @@ static int iwl_set_hw_params(struct iwl_priv *priv) { priv->hw_params.max_rxq_size = RX_QUEUE_SIZE; priv->hw_params.max_rxq_log = RX_QUEUE_SIZE_LOG; - if (priv->cfg->mod_params->amsdu_size_8K) + if (iwlagn_mod_params.amsdu_size_8K) priv->hw_params.rx_page_order = get_order(IWL_RX_BUF_SIZE_8K); else priv->hw_params.rx_page_order = get_order(IWL_RX_BUF_SIZE_4K); priv->hw_params.max_beacon_itrvl = IWL_MAX_UCODE_BEACON_INTERVAL; - if (priv->cfg->mod_params->disable_11n) + if (iwlagn_mod_params.disable_11n) priv->cfg->sku &= ~IWL_SKU_N; /* Device-specific setup */ diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index 66da1de..1b2a7d9 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -41,6 +41,7 @@ #include "iwl-power.h" #include "iwl-sta.h" #include "iwl-helpers.h" +#include "iwl-agn.h" /* @@ -94,7 +95,7 @@ static void iwlcore_init_ht_hw_capab(const struct iwl_priv *priv, max_bit_rate = MAX_BIT_RATE_40_MHZ; } - if (priv->cfg->mod_params->amsdu_size_8K) + if (iwlagn_mod_params.amsdu_size_8K) ht_info->cap |= IEEE80211_HT_CAP_MAX_AMSDU; ht_info->ampdu_factor = CFG_HT_RX_AMPDU_FACTOR_DEF; @@ -926,7 +927,7 @@ void iwlagn_fw_error(struct iwl_priv *priv, bool ondemand) } if (!test_bit(STATUS_EXIT_PENDING, &priv->status)) { - if (priv->cfg->mod_params->restart_fw) { + if (iwlagn_mod_params.restart_fw) { IWL_DEBUG(priv, IWL_DL_FW_ERRORS, "Restarting adapter due to uCode error.\n"); queue_work(priv->workqueue, &priv->restart); @@ -1747,7 +1748,7 @@ int iwl_force_reset(struct iwl_priv *priv, int mode, bool external) * detect failure), then fw_restart module parameter * need to be check before performing firmware reload */ - if (!external && !priv->cfg->mod_params->restart_fw) { + if (!external && !iwlagn_mod_params.restart_fw) { IWL_DEBUG_INFO(priv, "Cancel firmware reload based on " "module parameter setting\n"); break; diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h index 4cdb85d..ca6bd07 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.h +++ b/drivers/net/wireless/iwlwifi/iwl-core.h @@ -325,8 +325,6 @@ struct iwl_cfg { u16 eeprom_ver; u16 eeprom_calib_ver; const struct iwl_ops *ops; - /* module based parameters which can be set from modprobe cmd */ - const struct iwl_mod_params *mod_params; /* params not likely to change within a device family */ struct iwl_base_params *base_params; /* params likely to change within a device family */ diff --git a/drivers/net/wireless/iwlwifi/iwl-rx.c b/drivers/net/wireless/iwlwifi/iwl-rx.c index aca9a1d..0053e9e 100644 --- a/drivers/net/wireless/iwlwifi/iwl-rx.c +++ b/drivers/net/wireless/iwlwifi/iwl-rx.c @@ -433,7 +433,6 @@ static void iwl_recover_from_statistics(struct iwl_priv *priv, struct statistics_tx *tx, unsigned long stamp) { - const struct iwl_mod_params *mod_params = priv->cfg->mod_params; unsigned int msecs; if (test_bit(STATUS_EXIT_PENDING, &priv->status)) @@ -449,13 +448,13 @@ static void iwl_recover_from_statistics(struct iwl_priv *priv, if (msecs < 99) return; - if (mod_params->ack_check && !iwl_good_ack_health(priv, tx)) { + if (iwlagn_mod_params.ack_check && !iwl_good_ack_health(priv, tx)) { IWL_ERR(priv, "low ack count detected, restart firmware\n"); if (!iwl_force_reset(priv, IWL_FW_RESET, false)) return; } - if (mod_params->plcp_check && + if (iwlagn_mod_params.plcp_check && !iwl_good_plcp_health(priv, cur_ofdm, cur_ofdm_ht, msecs)) iwl_force_reset(priv, IWL_RF_RESET, false); } @@ -846,7 +845,7 @@ static void iwl_pass_packet_to_mac80211(struct iwl_priv *priv, } /* In case of HW accelerated crypto and bad decryption, drop */ - if (!priv->cfg->mod_params->sw_crypto && + if (!iwlagn_mod_params.sw_crypto && iwl_set_decrypted_flag(priv, hdr, ampdu_status, stats)) return; -- cgit v0.10.2 From 16b80b714f8ef86d47680e4afa0eeb8cc61daef4 Mon Sep 17 00:00:00 2001 From: Don Fry Date: Wed, 20 Apr 2011 15:25:14 -0700 Subject: iwlagn: semaphore and calib cleanup All agn devices use the same eeprom semaphore and calib version routines. Delete the indirection and move the semaphore routines to where they are used and make static. Signed-off-by: Don Fry Signed-off-by: Wey-Yi Guy diff --git a/drivers/net/wireless/iwlwifi/iwl-1000.c b/drivers/net/wireless/iwlwifi/iwl-1000.c index d2b1be6..4767edf 100644 --- a/drivers/net/wireless/iwlwifi/iwl-1000.c +++ b/drivers/net/wireless/iwlwifi/iwl-1000.c @@ -197,9 +197,6 @@ static struct iwl_lib_ops iwl1000_lib = { EEPROM_REG_BAND_24_HT40_CHANNELS, EEPROM_REGULATORY_BAND_NO_HT40, }, - .acquire_semaphore = iwlcore_eeprom_acquire_semaphore, - .release_semaphore = iwlcore_eeprom_release_semaphore, - .calib_version = iwlagn_eeprom_calib_version, .query_addr = iwlagn_eeprom_query_addr, }, .temp_ops = { diff --git a/drivers/net/wireless/iwlwifi/iwl-2000.c b/drivers/net/wireless/iwlwifi/iwl-2000.c index 476150f..80137ed 100644 --- a/drivers/net/wireless/iwlwifi/iwl-2000.c +++ b/drivers/net/wireless/iwlwifi/iwl-2000.c @@ -280,9 +280,6 @@ static struct iwl_lib_ops iwl2000_lib = { EEPROM_6000_REG_BAND_24_HT40_CHANNELS, EEPROM_REGULATORY_BAND_NO_HT40, }, - .acquire_semaphore = iwlcore_eeprom_acquire_semaphore, - .release_semaphore = iwlcore_eeprom_release_semaphore, - .calib_version = iwlagn_eeprom_calib_version, .query_addr = iwlagn_eeprom_query_addr, .update_enhanced_txpower = iwlcore_eeprom_enhanced_txpower, }, diff --git a/drivers/net/wireless/iwlwifi/iwl-5000.c b/drivers/net/wireless/iwlwifi/iwl-5000.c index 969c91a..cc25351 100644 --- a/drivers/net/wireless/iwlwifi/iwl-5000.c +++ b/drivers/net/wireless/iwlwifi/iwl-5000.c @@ -366,9 +366,6 @@ static struct iwl_lib_ops iwl5000_lib = { EEPROM_REG_BAND_24_HT40_CHANNELS, EEPROM_REG_BAND_52_HT40_CHANNELS }, - .acquire_semaphore = iwlcore_eeprom_acquire_semaphore, - .release_semaphore = iwlcore_eeprom_release_semaphore, - .calib_version = iwlagn_eeprom_calib_version, .query_addr = iwlagn_eeprom_query_addr, }, .temp_ops = { @@ -413,9 +410,6 @@ static struct iwl_lib_ops iwl5150_lib = { EEPROM_REG_BAND_24_HT40_CHANNELS, EEPROM_REG_BAND_52_HT40_CHANNELS }, - .acquire_semaphore = iwlcore_eeprom_acquire_semaphore, - .release_semaphore = iwlcore_eeprom_release_semaphore, - .calib_version = iwlagn_eeprom_calib_version, .query_addr = iwlagn_eeprom_query_addr, }, .temp_ops = { diff --git a/drivers/net/wireless/iwlwifi/iwl-6000.c b/drivers/net/wireless/iwlwifi/iwl-6000.c index 91edb57..f9ef227 100644 --- a/drivers/net/wireless/iwlwifi/iwl-6000.c +++ b/drivers/net/wireless/iwlwifi/iwl-6000.c @@ -80,7 +80,7 @@ static void iwl6000_set_ct_threshold(struct iwl_priv *priv) static void iwl6050_additional_nic_config(struct iwl_priv *priv) { /* Indicate calibration version to uCode. */ - if (priv->cfg->ops->lib->eeprom_ops.calib_version(priv) >= 6) + if (iwlagn_eeprom_calib_version(priv) >= 6) iwl_set_bit(priv, CSR_GP_DRIVER_REG, CSR_GP_DRIVER_REG_BIT_CALIB_VERSION6); } @@ -88,7 +88,7 @@ static void iwl6050_additional_nic_config(struct iwl_priv *priv) static void iwl6150_additional_nic_config(struct iwl_priv *priv) { /* Indicate calibration version to uCode. */ - if (priv->cfg->ops->lib->eeprom_ops.calib_version(priv) >= 6) + if (iwlagn_eeprom_calib_version(priv) >= 6) iwl_set_bit(priv, CSR_GP_DRIVER_REG, CSR_GP_DRIVER_REG_BIT_CALIB_VERSION6); iwl_set_bit(priv, CSR_GP_DRIVER_REG, @@ -305,9 +305,6 @@ static struct iwl_lib_ops iwl6000_lib = { EEPROM_6000_REG_BAND_24_HT40_CHANNELS, EEPROM_REG_BAND_52_HT40_CHANNELS }, - .acquire_semaphore = iwlcore_eeprom_acquire_semaphore, - .release_semaphore = iwlcore_eeprom_release_semaphore, - .calib_version = iwlagn_eeprom_calib_version, .query_addr = iwlagn_eeprom_query_addr, .update_enhanced_txpower = iwlcore_eeprom_enhanced_txpower, }, @@ -354,9 +351,6 @@ static struct iwl_lib_ops iwl6030_lib = { EEPROM_6000_REG_BAND_24_HT40_CHANNELS, EEPROM_REG_BAND_52_HT40_CHANNELS }, - .acquire_semaphore = iwlcore_eeprom_acquire_semaphore, - .release_semaphore = iwlcore_eeprom_release_semaphore, - .calib_version = iwlagn_eeprom_calib_version, .query_addr = iwlagn_eeprom_query_addr, .update_enhanced_txpower = iwlcore_eeprom_enhanced_txpower, }, diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-eeprom.c b/drivers/net/wireless/iwlwifi/iwl-agn-eeprom.c index 3bcaa10..2ef9448 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-eeprom.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-eeprom.c @@ -81,52 +81,13 @@ * ******************************************************************************/ -/* - * The device's EEPROM semaphore prevents conflicts between driver and uCode - * when accessing the EEPROM; each access is a series of pulses to/from the - * EEPROM chip, not a single event, so even reads could conflict if they - * weren't arbitrated by the semaphore. - */ -int iwlcore_eeprom_acquire_semaphore(struct iwl_priv *priv) -{ - u16 count; - int ret; - - for (count = 0; count < EEPROM_SEM_RETRY_LIMIT; count++) { - /* Request semaphore */ - iwl_set_bit(priv, CSR_HW_IF_CONFIG_REG, - CSR_HW_IF_CONFIG_REG_BIT_EEPROM_OWN_SEM); - - /* See if we got it */ - ret = iwl_poll_bit(priv, CSR_HW_IF_CONFIG_REG, - CSR_HW_IF_CONFIG_REG_BIT_EEPROM_OWN_SEM, - CSR_HW_IF_CONFIG_REG_BIT_EEPROM_OWN_SEM, - EEPROM_SEM_TIMEOUT); - if (ret >= 0) { - IWL_DEBUG_EEPROM(priv, - "Acquired semaphore after %d tries.\n", - count+1); - return ret; - } - } - - return ret; -} - -void iwlcore_eeprom_release_semaphore(struct iwl_priv *priv) -{ - iwl_clear_bit(priv, CSR_HW_IF_CONFIG_REG, - CSR_HW_IF_CONFIG_REG_BIT_EEPROM_OWN_SEM); - -} - int iwl_eeprom_check_version(struct iwl_priv *priv) { u16 eeprom_ver; u16 calib_ver; eeprom_ver = iwl_eeprom_query16(priv, EEPROM_VERSION); - calib_ver = priv->cfg->ops->lib->eeprom_ops.calib_version(priv); + calib_ver = iwlagn_eeprom_calib_version(priv); if (eeprom_ver < priv->cfg->eeprom_ver || calib_ver < priv->cfg->eeprom_calib_ver) diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.h b/drivers/net/wireless/iwlwifi/iwl-agn.h index 9d644d4..b477336 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.h +++ b/drivers/net/wireless/iwlwifi/iwl-agn.h @@ -327,8 +327,6 @@ static inline __le32 iwl_hw_set_rate_n_flags(u8 rate, u32 flags) /* eeprom */ void iwlcore_eeprom_enhanced_txpower(struct iwl_priv *priv); void iwl_eeprom_get_mac(const struct iwl_priv *priv, u8 *mac); -int iwlcore_eeprom_acquire_semaphore(struct iwl_priv *priv); -void iwlcore_eeprom_release_semaphore(struct iwl_priv *priv); /* notification wait support */ void __acquires(wait_entry) diff --git a/drivers/net/wireless/iwlwifi/iwl-eeprom.c b/drivers/net/wireless/iwlwifi/iwl-eeprom.c index 1e1a2d8..c839796 100644 --- a/drivers/net/wireless/iwlwifi/iwl-eeprom.c +++ b/drivers/net/wireless/iwlwifi/iwl-eeprom.c @@ -142,6 +142,45 @@ static const u8 iwl_eeprom_band_7[] = { /* 5.2 ht40 channel */ * ******************************************************************************/ +/* + * The device's EEPROM semaphore prevents conflicts between driver and uCode + * when accessing the EEPROM; each access is a series of pulses to/from the + * EEPROM chip, not a single event, so even reads could conflict if they + * weren't arbitrated by the semaphore. + */ +static int iwl_eeprom_acquire_semaphore(struct iwl_priv *priv) +{ + u16 count; + int ret; + + for (count = 0; count < EEPROM_SEM_RETRY_LIMIT; count++) { + /* Request semaphore */ + iwl_set_bit(priv, CSR_HW_IF_CONFIG_REG, + CSR_HW_IF_CONFIG_REG_BIT_EEPROM_OWN_SEM); + + /* See if we got it */ + ret = iwl_poll_bit(priv, CSR_HW_IF_CONFIG_REG, + CSR_HW_IF_CONFIG_REG_BIT_EEPROM_OWN_SEM, + CSR_HW_IF_CONFIG_REG_BIT_EEPROM_OWN_SEM, + EEPROM_SEM_TIMEOUT); + if (ret >= 0) { + IWL_DEBUG_EEPROM(priv, + "Acquired semaphore after %d tries.\n", + count+1); + return ret; + } + } + + return ret; +} + +static void iwl_eeprom_release_semaphore(struct iwl_priv *priv) +{ + iwl_clear_bit(priv, CSR_HW_IF_CONFIG_REG, + CSR_HW_IF_CONFIG_REG_BIT_EEPROM_OWN_SEM); + +} + static int iwl_eeprom_verify_signature(struct iwl_priv *priv) { u32 gp = iwl_read32(priv, CSR_EEPROM_GP) & CSR_EEPROM_GP_VALID_MSK; @@ -421,7 +460,7 @@ int iwl_eeprom_init(struct iwl_priv *priv, u32 hw_rev) } /* Make sure driver (instead of uCode) is allowed to read EEPROM */ - ret = priv->cfg->ops->lib->eeprom_ops.acquire_semaphore(priv); + ret = iwl_eeprom_acquire_semaphore(priv); if (ret < 0) { IWL_ERR(priv, "Failed to acquire EEPROM semaphore.\n"); ret = -ENOENT; @@ -488,7 +527,7 @@ int iwl_eeprom_init(struct iwl_priv *priv, u32 hw_rev) ret = 0; done: - priv->cfg->ops->lib->eeprom_ops.release_semaphore(priv); + iwl_eeprom_release_semaphore(priv); err: if (ret) diff --git a/drivers/net/wireless/iwlwifi/iwl-eeprom.h b/drivers/net/wireless/iwlwifi/iwl-eeprom.h index 9ce0525..c960c6f 100644 --- a/drivers/net/wireless/iwlwifi/iwl-eeprom.h +++ b/drivers/net/wireless/iwlwifi/iwl-eeprom.h @@ -294,9 +294,6 @@ extern const u8 iwl_eeprom_band_1[14]; struct iwl_eeprom_ops { const u32 regulatory_bands[7]; - int (*acquire_semaphore) (struct iwl_priv *priv); - void (*release_semaphore) (struct iwl_priv *priv); - u16 (*calib_version) (struct iwl_priv *priv); const u8* (*query_addr) (const struct iwl_priv *priv, size_t offset); void (*update_enhanced_txpower) (struct iwl_priv *priv); }; -- cgit v0.10.2 From bbf18ff1be8a3c6567bc052e690189b55e16b8eb Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 21 Apr 2011 07:09:43 -0700 Subject: iwlagn: remove spectrum measurement header This header file isn't used, and if we ever need these definitions they shouldn't be added to a driver but rather to the common 802.11 include file that has all frame definitions. Thus, just remove it. Signed-off-by: Johannes Berg Signed-off-by: Wey-Yi Guy diff --git a/drivers/net/wireless/iwlwifi/iwl-spectrum.h b/drivers/net/wireless/iwlwifi/iwl-spectrum.h deleted file mode 100644 index cb80bb4..0000000 --- a/drivers/net/wireless/iwlwifi/iwl-spectrum.h +++ /dev/null @@ -1,92 +0,0 @@ -/****************************************************************************** - * - * Copyright(c) 2003 - 2011 Intel Corporation. All rights reserved. - * - * Portions of this file are derived from the ieee80211 subsystem header files. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of version 2 of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA - * - * The full GNU General Public License is included in this distribution in the - * file called LICENSE. - * - * Contact Information: - * Intel Linux Wireless - * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 - * - *****************************************************************************/ - -#ifndef __iwl_spectrum_h__ -#define __iwl_spectrum_h__ -enum { /* ieee80211_basic_report.map */ - IEEE80211_BASIC_MAP_BSS = (1 << 0), - IEEE80211_BASIC_MAP_OFDM = (1 << 1), - IEEE80211_BASIC_MAP_UNIDENTIFIED = (1 << 2), - IEEE80211_BASIC_MAP_RADAR = (1 << 3), - IEEE80211_BASIC_MAP_UNMEASURED = (1 << 4), - /* Bits 5-7 are reserved */ - -}; -struct ieee80211_basic_report { - u8 channel; - __le64 start_time; - __le16 duration; - u8 map; -} __packed; - -enum { /* ieee80211_measurement_request.mode */ - /* Bit 0 is reserved */ - IEEE80211_MEASUREMENT_ENABLE = (1 << 1), - IEEE80211_MEASUREMENT_REQUEST = (1 << 2), - IEEE80211_MEASUREMENT_REPORT = (1 << 3), - /* Bits 4-7 are reserved */ -}; - -enum { - IEEE80211_REPORT_BASIC = 0, /* required */ - IEEE80211_REPORT_CCA = 1, /* optional */ - IEEE80211_REPORT_RPI = 2, /* optional */ - /* 3-255 reserved */ -}; - -struct ieee80211_measurement_params { - u8 channel; - __le64 start_time; - __le16 duration; -} __packed; - -struct ieee80211_info_element { - u8 id; - u8 len; - u8 data[0]; -} __packed; - -struct ieee80211_measurement_request { - struct ieee80211_info_element ie; - u8 token; - u8 mode; - u8 type; - struct ieee80211_measurement_params params[0]; -} __packed; - -struct ieee80211_measurement_report { - struct ieee80211_info_element ie; - u8 token; - u8 mode; - u8 type; - union { - struct ieee80211_basic_report basic[0]; - } u; -} __packed; - -#endif -- cgit v0.10.2 From c914ac26caf462567078f9615ffcedf1962087f2 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 21 Apr 2011 10:57:23 -0700 Subject: iwlagn: improve RXON checking The current RXON checking doesn't verify that the channel is valid (or at least non-zero), so add that. Also, add a WARN() so we get a stacktrace, and capture a bitmask of errors in order to capture all necessary information in the warning itself (in case the previous messages are snipped off.) Signed-off-by: Johannes Berg Signed-off-by: Wey-Yi Guy diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index 1b2a7d9..98cfbb6 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -416,72 +416,72 @@ void iwl_set_rxon_hwcrypto(struct iwl_priv *priv, struct iwl_rxon_context *ctx, int iwl_check_rxon_cmd(struct iwl_priv *priv, struct iwl_rxon_context *ctx) { struct iwl_rxon_cmd *rxon = &ctx->staging; - bool error = false; + u32 errors = 0; if (rxon->flags & RXON_FLG_BAND_24G_MSK) { if (rxon->flags & RXON_FLG_TGJ_NARROW_BAND_MSK) { IWL_WARN(priv, "check 2.4G: wrong narrow\n"); - error = true; + errors |= BIT(0); } if (rxon->flags & RXON_FLG_RADAR_DETECT_MSK) { IWL_WARN(priv, "check 2.4G: wrong radar\n"); - error = true; + errors |= BIT(1); } } else { if (!(rxon->flags & RXON_FLG_SHORT_SLOT_MSK)) { IWL_WARN(priv, "check 5.2G: not short slot!\n"); - error = true; + errors |= BIT(2); } if (rxon->flags & RXON_FLG_CCK_MSK) { IWL_WARN(priv, "check 5.2G: CCK!\n"); - error = true; + errors |= BIT(3); } } if ((rxon->node_addr[0] | rxon->bssid_addr[0]) & 0x1) { IWL_WARN(priv, "mac/bssid mcast!\n"); - error = true; + errors |= BIT(4); } /* make sure basic rates 6Mbps and 1Mbps are supported */ if ((rxon->ofdm_basic_rates & IWL_RATE_6M_MASK) == 0 && (rxon->cck_basic_rates & IWL_RATE_1M_MASK) == 0) { IWL_WARN(priv, "neither 1 nor 6 are basic\n"); - error = true; + errors |= BIT(5); } if (le16_to_cpu(rxon->assoc_id) > 2007) { IWL_WARN(priv, "aid > 2007\n"); - error = true; + errors |= BIT(6); } if ((rxon->flags & (RXON_FLG_CCK_MSK | RXON_FLG_SHORT_SLOT_MSK)) == (RXON_FLG_CCK_MSK | RXON_FLG_SHORT_SLOT_MSK)) { IWL_WARN(priv, "CCK and short slot\n"); - error = true; + errors |= BIT(7); } if ((rxon->flags & (RXON_FLG_CCK_MSK | RXON_FLG_AUTO_DETECT_MSK)) == (RXON_FLG_CCK_MSK | RXON_FLG_AUTO_DETECT_MSK)) { IWL_WARN(priv, "CCK and auto detect"); - error = true; + errors |= BIT(8); } if ((rxon->flags & (RXON_FLG_AUTO_DETECT_MSK | RXON_FLG_TGG_PROTECT_MSK)) == RXON_FLG_TGG_PROTECT_MSK) { IWL_WARN(priv, "TGg but no auto-detect\n"); - error = true; + errors |= BIT(9); } - if (error) - IWL_WARN(priv, "Tuning to channel %d\n", - le16_to_cpu(rxon->channel)); - - if (error) { - IWL_ERR(priv, "Invalid RXON\n"); - return -EINVAL; + if (rxon->channel == 0) { + IWL_WARN(priv, "zero channel is invalid\n"); + errors |= BIT(10); } - return 0; + + WARN(errors, "Invalid RXON (%#x), channel %d", + errors, le16_to_cpu(rxon->channel)); + + return errors ? -EINVAL : 0; } /** -- cgit v0.10.2 From ebf8dc8060e4b10e8e13abbf98544f5c6cc8b25e Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 27 Apr 2011 05:19:34 -0700 Subject: iwlagn: prefer BSS context If an interface type changes from a type that is only supported on the PAN context (e.g. P2P GO) to a type that is supported on the BSS context, and the BSS context is not in use, then we need to use the BSS context instead of changing the device type within the context. To achieve this, refuse the type change, which causes a down/up cycle that will allocate the BSS context for the interface. Signed-off-by: Johannes Berg Signed-off-by: Wey-Yi Guy diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index 98cfbb6..4653dea 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -1765,6 +1765,7 @@ int iwl_mac_change_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif, { struct iwl_priv *priv = hw->priv; struct iwl_rxon_context *ctx = iwl_rxon_ctx_from_vif(vif); + struct iwl_rxon_context *bss_ctx = &priv->contexts[IWL_RXON_CTX_BSS]; struct iwl_rxon_context *tmp; u32 interface_modes; int err; @@ -1789,6 +1790,19 @@ int iwl_mac_change_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif, goto out; } + /* + * Refuse a change that should be done by moving from the PAN + * context to the BSS context instead, if the BSS context is + * available and can support the new interface type. + */ + if (ctx->ctxid == IWL_RXON_CTX_PAN && !bss_ctx->vif && + (bss_ctx->interface_modes & BIT(newtype) || + bss_ctx->exclusive_interface_modes & BIT(newtype))) { + BUILD_BUG_ON(NUM_IWL_RXON_CTX != 2); + err = -EBUSY; + goto out; + } + if (ctx->exclusive_interface_modes & BIT(newtype)) { for_each_context(priv, tmp) { if (ctx == tmp) -- cgit v0.10.2 From d6d023a1948d13652d719238f8039c09acceda8c Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Sat, 30 Apr 2011 09:10:53 -0700 Subject: iwlagn: remove un-necessary debugfs callback After driver split, no need for debugfs callback, remove those Signed-off-by: Wey-Yi Guy diff --git a/drivers/net/wireless/iwlwifi/Makefile b/drivers/net/wireless/iwlwifi/Makefile index bb6a737..89a41d3 100644 --- a/drivers/net/wireless/iwlwifi/Makefile +++ b/drivers/net/wireless/iwlwifi/Makefile @@ -14,7 +14,6 @@ iwlagn-objs += iwl-6000.o iwlagn-objs += iwl-1000.o iwlagn-objs += iwl-2000.o -iwlagn-$(CONFIG_IWLWIFI_DEBUGFS) += iwl-agn-debugfs.o iwlagn-$(CONFIG_IWLWIFI_DEBUGFS) += iwl-debugfs.o iwlagn-$(CONFIG_IWLWIFI_DEVICE_TRACING) += iwl-devtrace.o diff --git a/drivers/net/wireless/iwlwifi/iwl-1000.c b/drivers/net/wireless/iwlwifi/iwl-1000.c index 4767edf..3da8cf2 100644 --- a/drivers/net/wireless/iwlwifi/iwl-1000.c +++ b/drivers/net/wireless/iwlwifi/iwl-1000.c @@ -45,7 +45,6 @@ #include "iwl-agn.h" #include "iwl-helpers.h" #include "iwl-agn-hw.h" -#include "iwl-agn-debugfs.h" /* Highest firmware API version supported */ #define IWL1000_UCODE_API_MAX 5 @@ -202,13 +201,6 @@ static struct iwl_lib_ops iwl1000_lib = { .temp_ops = { .temperature = iwlagn_temperature, }, - .debugfs_ops = { - .rx_stats_read = iwl_ucode_rx_stats_read, - .tx_stats_read = iwl_ucode_tx_stats_read, - .general_stats_read = iwl_ucode_general_stats_read, - .bt_stats_read = iwl_ucode_bt_stats_read, - .reply_tx_error = iwl_reply_tx_error_read, - }, .txfifo_flush = iwlagn_txfifo_flush, .dev_txfifo_flush = iwlagn_dev_txfifo_flush, }; diff --git a/drivers/net/wireless/iwlwifi/iwl-2000.c b/drivers/net/wireless/iwlwifi/iwl-2000.c index 80137ed..bca462c 100644 --- a/drivers/net/wireless/iwlwifi/iwl-2000.c +++ b/drivers/net/wireless/iwlwifi/iwl-2000.c @@ -46,7 +46,6 @@ #include "iwl-helpers.h" #include "iwl-agn-hw.h" #include "iwl-6000-hw.h" -#include "iwl-agn-debugfs.h" /* Highest firmware API version supported */ #define IWL2030_UCODE_API_MAX 5 @@ -286,13 +285,6 @@ static struct iwl_lib_ops iwl2000_lib = { .temp_ops = { .temperature = iwlagn_temperature, }, - .debugfs_ops = { - .rx_stats_read = iwl_ucode_rx_stats_read, - .tx_stats_read = iwl_ucode_tx_stats_read, - .general_stats_read = iwl_ucode_general_stats_read, - .bt_stats_read = iwl_ucode_bt_stats_read, - .reply_tx_error = iwl_reply_tx_error_read, - }, .txfifo_flush = iwlagn_txfifo_flush, .dev_txfifo_flush = iwlagn_dev_txfifo_flush, }; diff --git a/drivers/net/wireless/iwlwifi/iwl-5000.c b/drivers/net/wireless/iwlwifi/iwl-5000.c index cc25351..561f2cd 100644 --- a/drivers/net/wireless/iwlwifi/iwl-5000.c +++ b/drivers/net/wireless/iwlwifi/iwl-5000.c @@ -47,7 +47,6 @@ #include "iwl-agn.h" #include "iwl-agn-hw.h" #include "iwl-5000-hw.h" -#include "iwl-agn-debugfs.h" /* Highest firmware API version supported */ #define IWL5000_UCODE_API_MAX 5 @@ -371,13 +370,6 @@ static struct iwl_lib_ops iwl5000_lib = { .temp_ops = { .temperature = iwlagn_temperature, }, - .debugfs_ops = { - .rx_stats_read = iwl_ucode_rx_stats_read, - .tx_stats_read = iwl_ucode_tx_stats_read, - .general_stats_read = iwl_ucode_general_stats_read, - .bt_stats_read = iwl_ucode_bt_stats_read, - .reply_tx_error = iwl_reply_tx_error_read, - }, .txfifo_flush = iwlagn_txfifo_flush, .dev_txfifo_flush = iwlagn_dev_txfifo_flush, }; @@ -415,13 +407,6 @@ static struct iwl_lib_ops iwl5150_lib = { .temp_ops = { .temperature = iwl5150_temperature, }, - .debugfs_ops = { - .rx_stats_read = iwl_ucode_rx_stats_read, - .tx_stats_read = iwl_ucode_tx_stats_read, - .general_stats_read = iwl_ucode_general_stats_read, - .bt_stats_read = iwl_ucode_bt_stats_read, - .reply_tx_error = iwl_reply_tx_error_read, - }, .txfifo_flush = iwlagn_txfifo_flush, .dev_txfifo_flush = iwlagn_dev_txfifo_flush, }; diff --git a/drivers/net/wireless/iwlwifi/iwl-6000.c b/drivers/net/wireless/iwlwifi/iwl-6000.c index f9ef227..6045457 100644 --- a/drivers/net/wireless/iwlwifi/iwl-6000.c +++ b/drivers/net/wireless/iwlwifi/iwl-6000.c @@ -46,7 +46,6 @@ #include "iwl-helpers.h" #include "iwl-agn-hw.h" #include "iwl-6000-hw.h" -#include "iwl-agn-debugfs.h" /* Highest firmware API version supported */ #define IWL6000_UCODE_API_MAX 4 @@ -311,13 +310,6 @@ static struct iwl_lib_ops iwl6000_lib = { .temp_ops = { .temperature = iwlagn_temperature, }, - .debugfs_ops = { - .rx_stats_read = iwl_ucode_rx_stats_read, - .tx_stats_read = iwl_ucode_tx_stats_read, - .general_stats_read = iwl_ucode_general_stats_read, - .bt_stats_read = iwl_ucode_bt_stats_read, - .reply_tx_error = iwl_reply_tx_error_read, - }, .txfifo_flush = iwlagn_txfifo_flush, .dev_txfifo_flush = iwlagn_dev_txfifo_flush, }; @@ -357,13 +349,6 @@ static struct iwl_lib_ops iwl6030_lib = { .temp_ops = { .temperature = iwlagn_temperature, }, - .debugfs_ops = { - .rx_stats_read = iwl_ucode_rx_stats_read, - .tx_stats_read = iwl_ucode_tx_stats_read, - .general_stats_read = iwl_ucode_general_stats_read, - .bt_stats_read = iwl_ucode_bt_stats_read, - .reply_tx_error = iwl_reply_tx_error_read, - }, .txfifo_flush = iwlagn_txfifo_flush, .dev_txfifo_flush = iwlagn_dev_txfifo_flush, }; diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-debugfs.c b/drivers/net/wireless/iwlwifi/iwl-agn-debugfs.c deleted file mode 100644 index 71a5f31..0000000 --- a/drivers/net/wireless/iwlwifi/iwl-agn-debugfs.c +++ /dev/null @@ -1,1025 +0,0 @@ -/****************************************************************************** - * - * GPL LICENSE SUMMARY - * - * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of version 2 of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, - * USA - * - * The full GNU General Public License is included in this distribution - * in the file called LICENSE.GPL. - * - * Contact Information: - * Intel Linux Wireless - * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 - *****************************************************************************/ -#include "iwl-agn.h" -#include "iwl-agn-debugfs.h" - -static const char *fmt_value = " %-30s %10u\n"; -static const char *fmt_hex = " %-30s 0x%02X\n"; -static const char *fmt_table = " %-30s %10u %10u %10u %10u\n"; -static const char *fmt_header = - "%-32s current cumulative delta max\n"; - -static int iwl_statistics_flag(struct iwl_priv *priv, char *buf, int bufsz) -{ - int p = 0; - u32 flag; - - flag = le32_to_cpu(priv->statistics.flag); - - p += scnprintf(buf + p, bufsz - p, "Statistics Flag(0x%X):\n", flag); - if (flag & UCODE_STATISTICS_CLEAR_MSK) - p += scnprintf(buf + p, bufsz - p, - "\tStatistics have been cleared\n"); - p += scnprintf(buf + p, bufsz - p, "\tOperational Frequency: %s\n", - (flag & UCODE_STATISTICS_FREQUENCY_MSK) - ? "2.4 GHz" : "5.2 GHz"); - p += scnprintf(buf + p, bufsz - p, "\tTGj Narrow Band: %s\n", - (flag & UCODE_STATISTICS_NARROW_BAND_MSK) - ? "enabled" : "disabled"); - - return p; -} - -ssize_t iwl_ucode_rx_stats_read(struct file *file, char __user *user_buf, - size_t count, loff_t *ppos) - { - struct iwl_priv *priv = file->private_data; - int pos = 0; - char *buf; - int bufsz = sizeof(struct statistics_rx_phy) * 40 + - sizeof(struct statistics_rx_non_phy) * 40 + - sizeof(struct statistics_rx_ht_phy) * 40 + 400; - ssize_t ret; - struct statistics_rx_phy *ofdm, *accum_ofdm, *delta_ofdm, *max_ofdm; - struct statistics_rx_phy *cck, *accum_cck, *delta_cck, *max_cck; - struct statistics_rx_non_phy *general, *accum_general; - struct statistics_rx_non_phy *delta_general, *max_general; - struct statistics_rx_ht_phy *ht, *accum_ht, *delta_ht, *max_ht; - - if (!iwl_is_alive(priv)) - return -EAGAIN; - - buf = kzalloc(bufsz, GFP_KERNEL); - if (!buf) { - IWL_ERR(priv, "Can not allocate Buffer\n"); - return -ENOMEM; - } - - /* - * the statistic information display here is based on - * the last statistics notification from uCode - * might not reflect the current uCode activity - */ - ofdm = &priv->statistics.rx_ofdm; - cck = &priv->statistics.rx_cck; - general = &priv->statistics.rx_non_phy; - ht = &priv->statistics.rx_ofdm_ht; - accum_ofdm = &priv->accum_stats.rx_ofdm; - accum_cck = &priv->accum_stats.rx_cck; - accum_general = &priv->accum_stats.rx_non_phy; - accum_ht = &priv->accum_stats.rx_ofdm_ht; - delta_ofdm = &priv->delta_stats.rx_ofdm; - delta_cck = &priv->delta_stats.rx_cck; - delta_general = &priv->delta_stats.rx_non_phy; - delta_ht = &priv->delta_stats.rx_ofdm_ht; - max_ofdm = &priv->max_delta_stats.rx_ofdm; - max_cck = &priv->max_delta_stats.rx_cck; - max_general = &priv->max_delta_stats.rx_non_phy; - max_ht = &priv->max_delta_stats.rx_ofdm_ht; - - pos += iwl_statistics_flag(priv, buf, bufsz); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_header, "Statistics_Rx - OFDM:"); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "ina_cnt:", - le32_to_cpu(ofdm->ina_cnt), - accum_ofdm->ina_cnt, - delta_ofdm->ina_cnt, max_ofdm->ina_cnt); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "fina_cnt:", - le32_to_cpu(ofdm->fina_cnt), accum_ofdm->fina_cnt, - delta_ofdm->fina_cnt, max_ofdm->fina_cnt); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "plcp_err:", - le32_to_cpu(ofdm->plcp_err), accum_ofdm->plcp_err, - delta_ofdm->plcp_err, max_ofdm->plcp_err); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "crc32_err:", - le32_to_cpu(ofdm->crc32_err), accum_ofdm->crc32_err, - delta_ofdm->crc32_err, max_ofdm->crc32_err); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "overrun_err:", - le32_to_cpu(ofdm->overrun_err), - accum_ofdm->overrun_err, delta_ofdm->overrun_err, - max_ofdm->overrun_err); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "early_overrun_err:", - le32_to_cpu(ofdm->early_overrun_err), - accum_ofdm->early_overrun_err, - delta_ofdm->early_overrun_err, - max_ofdm->early_overrun_err); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "crc32_good:", - le32_to_cpu(ofdm->crc32_good), - accum_ofdm->crc32_good, delta_ofdm->crc32_good, - max_ofdm->crc32_good); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "false_alarm_cnt:", - le32_to_cpu(ofdm->false_alarm_cnt), - accum_ofdm->false_alarm_cnt, - delta_ofdm->false_alarm_cnt, - max_ofdm->false_alarm_cnt); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "fina_sync_err_cnt:", - le32_to_cpu(ofdm->fina_sync_err_cnt), - accum_ofdm->fina_sync_err_cnt, - delta_ofdm->fina_sync_err_cnt, - max_ofdm->fina_sync_err_cnt); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "sfd_timeout:", - le32_to_cpu(ofdm->sfd_timeout), - accum_ofdm->sfd_timeout, delta_ofdm->sfd_timeout, - max_ofdm->sfd_timeout); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "fina_timeout:", - le32_to_cpu(ofdm->fina_timeout), - accum_ofdm->fina_timeout, delta_ofdm->fina_timeout, - max_ofdm->fina_timeout); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "unresponded_rts:", - le32_to_cpu(ofdm->unresponded_rts), - accum_ofdm->unresponded_rts, - delta_ofdm->unresponded_rts, - max_ofdm->unresponded_rts); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "rxe_frame_lmt_ovrun:", - le32_to_cpu(ofdm->rxe_frame_limit_overrun), - accum_ofdm->rxe_frame_limit_overrun, - delta_ofdm->rxe_frame_limit_overrun, - max_ofdm->rxe_frame_limit_overrun); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "sent_ack_cnt:", - le32_to_cpu(ofdm->sent_ack_cnt), - accum_ofdm->sent_ack_cnt, delta_ofdm->sent_ack_cnt, - max_ofdm->sent_ack_cnt); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "sent_cts_cnt:", - le32_to_cpu(ofdm->sent_cts_cnt), - accum_ofdm->sent_cts_cnt, delta_ofdm->sent_cts_cnt, - max_ofdm->sent_cts_cnt); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "sent_ba_rsp_cnt:", - le32_to_cpu(ofdm->sent_ba_rsp_cnt), - accum_ofdm->sent_ba_rsp_cnt, - delta_ofdm->sent_ba_rsp_cnt, - max_ofdm->sent_ba_rsp_cnt); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "dsp_self_kill:", - le32_to_cpu(ofdm->dsp_self_kill), - accum_ofdm->dsp_self_kill, - delta_ofdm->dsp_self_kill, - max_ofdm->dsp_self_kill); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "mh_format_err:", - le32_to_cpu(ofdm->mh_format_err), - accum_ofdm->mh_format_err, - delta_ofdm->mh_format_err, - max_ofdm->mh_format_err); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "re_acq_main_rssi_sum:", - le32_to_cpu(ofdm->re_acq_main_rssi_sum), - accum_ofdm->re_acq_main_rssi_sum, - delta_ofdm->re_acq_main_rssi_sum, - max_ofdm->re_acq_main_rssi_sum); - - pos += scnprintf(buf + pos, bufsz - pos, - fmt_header, "Statistics_Rx - CCK:"); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "ina_cnt:", - le32_to_cpu(cck->ina_cnt), accum_cck->ina_cnt, - delta_cck->ina_cnt, max_cck->ina_cnt); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "fina_cnt:", - le32_to_cpu(cck->fina_cnt), accum_cck->fina_cnt, - delta_cck->fina_cnt, max_cck->fina_cnt); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "plcp_err:", - le32_to_cpu(cck->plcp_err), accum_cck->plcp_err, - delta_cck->plcp_err, max_cck->plcp_err); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "crc32_err:", - le32_to_cpu(cck->crc32_err), accum_cck->crc32_err, - delta_cck->crc32_err, max_cck->crc32_err); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "overrun_err:", - le32_to_cpu(cck->overrun_err), - accum_cck->overrun_err, delta_cck->overrun_err, - max_cck->overrun_err); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "early_overrun_err:", - le32_to_cpu(cck->early_overrun_err), - accum_cck->early_overrun_err, - delta_cck->early_overrun_err, - max_cck->early_overrun_err); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "crc32_good:", - le32_to_cpu(cck->crc32_good), accum_cck->crc32_good, - delta_cck->crc32_good, max_cck->crc32_good); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "false_alarm_cnt:", - le32_to_cpu(cck->false_alarm_cnt), - accum_cck->false_alarm_cnt, - delta_cck->false_alarm_cnt, max_cck->false_alarm_cnt); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "fina_sync_err_cnt:", - le32_to_cpu(cck->fina_sync_err_cnt), - accum_cck->fina_sync_err_cnt, - delta_cck->fina_sync_err_cnt, - max_cck->fina_sync_err_cnt); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "sfd_timeout:", - le32_to_cpu(cck->sfd_timeout), - accum_cck->sfd_timeout, delta_cck->sfd_timeout, - max_cck->sfd_timeout); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "fina_timeout:", - le32_to_cpu(cck->fina_timeout), - accum_cck->fina_timeout, delta_cck->fina_timeout, - max_cck->fina_timeout); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "unresponded_rts:", - le32_to_cpu(cck->unresponded_rts), - accum_cck->unresponded_rts, delta_cck->unresponded_rts, - max_cck->unresponded_rts); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "rxe_frame_lmt_ovrun:", - le32_to_cpu(cck->rxe_frame_limit_overrun), - accum_cck->rxe_frame_limit_overrun, - delta_cck->rxe_frame_limit_overrun, - max_cck->rxe_frame_limit_overrun); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "sent_ack_cnt:", - le32_to_cpu(cck->sent_ack_cnt), - accum_cck->sent_ack_cnt, delta_cck->sent_ack_cnt, - max_cck->sent_ack_cnt); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "sent_cts_cnt:", - le32_to_cpu(cck->sent_cts_cnt), - accum_cck->sent_cts_cnt, delta_cck->sent_cts_cnt, - max_cck->sent_cts_cnt); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "sent_ba_rsp_cnt:", - le32_to_cpu(cck->sent_ba_rsp_cnt), - accum_cck->sent_ba_rsp_cnt, - delta_cck->sent_ba_rsp_cnt, - max_cck->sent_ba_rsp_cnt); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "dsp_self_kill:", - le32_to_cpu(cck->dsp_self_kill), - accum_cck->dsp_self_kill, delta_cck->dsp_self_kill, - max_cck->dsp_self_kill); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "mh_format_err:", - le32_to_cpu(cck->mh_format_err), - accum_cck->mh_format_err, delta_cck->mh_format_err, - max_cck->mh_format_err); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "re_acq_main_rssi_sum:", - le32_to_cpu(cck->re_acq_main_rssi_sum), - accum_cck->re_acq_main_rssi_sum, - delta_cck->re_acq_main_rssi_sum, - max_cck->re_acq_main_rssi_sum); - - pos += scnprintf(buf + pos, bufsz - pos, - fmt_header, "Statistics_Rx - GENERAL:"); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "bogus_cts:", - le32_to_cpu(general->bogus_cts), - accum_general->bogus_cts, delta_general->bogus_cts, - max_general->bogus_cts); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "bogus_ack:", - le32_to_cpu(general->bogus_ack), - accum_general->bogus_ack, delta_general->bogus_ack, - max_general->bogus_ack); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "non_bssid_frames:", - le32_to_cpu(general->non_bssid_frames), - accum_general->non_bssid_frames, - delta_general->non_bssid_frames, - max_general->non_bssid_frames); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "filtered_frames:", - le32_to_cpu(general->filtered_frames), - accum_general->filtered_frames, - delta_general->filtered_frames, - max_general->filtered_frames); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "non_channel_beacons:", - le32_to_cpu(general->non_channel_beacons), - accum_general->non_channel_beacons, - delta_general->non_channel_beacons, - max_general->non_channel_beacons); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "channel_beacons:", - le32_to_cpu(general->channel_beacons), - accum_general->channel_beacons, - delta_general->channel_beacons, - max_general->channel_beacons); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "num_missed_bcon:", - le32_to_cpu(general->num_missed_bcon), - accum_general->num_missed_bcon, - delta_general->num_missed_bcon, - max_general->num_missed_bcon); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "adc_rx_saturation_time:", - le32_to_cpu(general->adc_rx_saturation_time), - accum_general->adc_rx_saturation_time, - delta_general->adc_rx_saturation_time, - max_general->adc_rx_saturation_time); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "ina_detect_search_tm:", - le32_to_cpu(general->ina_detection_search_time), - accum_general->ina_detection_search_time, - delta_general->ina_detection_search_time, - max_general->ina_detection_search_time); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "beacon_silence_rssi_a:", - le32_to_cpu(general->beacon_silence_rssi_a), - accum_general->beacon_silence_rssi_a, - delta_general->beacon_silence_rssi_a, - max_general->beacon_silence_rssi_a); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "beacon_silence_rssi_b:", - le32_to_cpu(general->beacon_silence_rssi_b), - accum_general->beacon_silence_rssi_b, - delta_general->beacon_silence_rssi_b, - max_general->beacon_silence_rssi_b); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "beacon_silence_rssi_c:", - le32_to_cpu(general->beacon_silence_rssi_c), - accum_general->beacon_silence_rssi_c, - delta_general->beacon_silence_rssi_c, - max_general->beacon_silence_rssi_c); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "interference_data_flag:", - le32_to_cpu(general->interference_data_flag), - accum_general->interference_data_flag, - delta_general->interference_data_flag, - max_general->interference_data_flag); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "channel_load:", - le32_to_cpu(general->channel_load), - accum_general->channel_load, - delta_general->channel_load, - max_general->channel_load); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "dsp_false_alarms:", - le32_to_cpu(general->dsp_false_alarms), - accum_general->dsp_false_alarms, - delta_general->dsp_false_alarms, - max_general->dsp_false_alarms); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "beacon_rssi_a:", - le32_to_cpu(general->beacon_rssi_a), - accum_general->beacon_rssi_a, - delta_general->beacon_rssi_a, - max_general->beacon_rssi_a); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "beacon_rssi_b:", - le32_to_cpu(general->beacon_rssi_b), - accum_general->beacon_rssi_b, - delta_general->beacon_rssi_b, - max_general->beacon_rssi_b); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "beacon_rssi_c:", - le32_to_cpu(general->beacon_rssi_c), - accum_general->beacon_rssi_c, - delta_general->beacon_rssi_c, - max_general->beacon_rssi_c); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "beacon_energy_a:", - le32_to_cpu(general->beacon_energy_a), - accum_general->beacon_energy_a, - delta_general->beacon_energy_a, - max_general->beacon_energy_a); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "beacon_energy_b:", - le32_to_cpu(general->beacon_energy_b), - accum_general->beacon_energy_b, - delta_general->beacon_energy_b, - max_general->beacon_energy_b); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "beacon_energy_c:", - le32_to_cpu(general->beacon_energy_c), - accum_general->beacon_energy_c, - delta_general->beacon_energy_c, - max_general->beacon_energy_c); - - pos += scnprintf(buf + pos, bufsz - pos, - fmt_header, "Statistics_Rx - OFDM_HT:"); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "plcp_err:", - le32_to_cpu(ht->plcp_err), accum_ht->plcp_err, - delta_ht->plcp_err, max_ht->plcp_err); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "overrun_err:", - le32_to_cpu(ht->overrun_err), accum_ht->overrun_err, - delta_ht->overrun_err, max_ht->overrun_err); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "early_overrun_err:", - le32_to_cpu(ht->early_overrun_err), - accum_ht->early_overrun_err, - delta_ht->early_overrun_err, - max_ht->early_overrun_err); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "crc32_good:", - le32_to_cpu(ht->crc32_good), accum_ht->crc32_good, - delta_ht->crc32_good, max_ht->crc32_good); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "crc32_err:", - le32_to_cpu(ht->crc32_err), accum_ht->crc32_err, - delta_ht->crc32_err, max_ht->crc32_err); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "mh_format_err:", - le32_to_cpu(ht->mh_format_err), - accum_ht->mh_format_err, - delta_ht->mh_format_err, max_ht->mh_format_err); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "agg_crc32_good:", - le32_to_cpu(ht->agg_crc32_good), - accum_ht->agg_crc32_good, - delta_ht->agg_crc32_good, max_ht->agg_crc32_good); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "agg_mpdu_cnt:", - le32_to_cpu(ht->agg_mpdu_cnt), - accum_ht->agg_mpdu_cnt, - delta_ht->agg_mpdu_cnt, max_ht->agg_mpdu_cnt); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "agg_cnt:", - le32_to_cpu(ht->agg_cnt), accum_ht->agg_cnt, - delta_ht->agg_cnt, max_ht->agg_cnt); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "unsupport_mcs:", - le32_to_cpu(ht->unsupport_mcs), - accum_ht->unsupport_mcs, - delta_ht->unsupport_mcs, max_ht->unsupport_mcs); - - ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos); - kfree(buf); - return ret; -} - -ssize_t iwl_ucode_tx_stats_read(struct file *file, - char __user *user_buf, - size_t count, loff_t *ppos) -{ - struct iwl_priv *priv = file->private_data; - int pos = 0; - char *buf; - int bufsz = (sizeof(struct statistics_tx) * 48) + 250; - ssize_t ret; - struct statistics_tx *tx, *accum_tx, *delta_tx, *max_tx; - - if (!iwl_is_alive(priv)) - return -EAGAIN; - - buf = kzalloc(bufsz, GFP_KERNEL); - if (!buf) { - IWL_ERR(priv, "Can not allocate Buffer\n"); - return -ENOMEM; - } - - /* the statistic information display here is based on - * the last statistics notification from uCode - * might not reflect the current uCode activity - */ - tx = &priv->statistics.tx; - accum_tx = &priv->accum_stats.tx; - delta_tx = &priv->delta_stats.tx; - max_tx = &priv->max_delta_stats.tx; - - pos += iwl_statistics_flag(priv, buf, bufsz); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_header, "Statistics_Tx:"); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "preamble:", - le32_to_cpu(tx->preamble_cnt), - accum_tx->preamble_cnt, - delta_tx->preamble_cnt, max_tx->preamble_cnt); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "rx_detected_cnt:", - le32_to_cpu(tx->rx_detected_cnt), - accum_tx->rx_detected_cnt, - delta_tx->rx_detected_cnt, max_tx->rx_detected_cnt); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "bt_prio_defer_cnt:", - le32_to_cpu(tx->bt_prio_defer_cnt), - accum_tx->bt_prio_defer_cnt, - delta_tx->bt_prio_defer_cnt, - max_tx->bt_prio_defer_cnt); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "bt_prio_kill_cnt:", - le32_to_cpu(tx->bt_prio_kill_cnt), - accum_tx->bt_prio_kill_cnt, - delta_tx->bt_prio_kill_cnt, - max_tx->bt_prio_kill_cnt); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "few_bytes_cnt:", - le32_to_cpu(tx->few_bytes_cnt), - accum_tx->few_bytes_cnt, - delta_tx->few_bytes_cnt, max_tx->few_bytes_cnt); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "cts_timeout:", - le32_to_cpu(tx->cts_timeout), accum_tx->cts_timeout, - delta_tx->cts_timeout, max_tx->cts_timeout); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "ack_timeout:", - le32_to_cpu(tx->ack_timeout), - accum_tx->ack_timeout, - delta_tx->ack_timeout, max_tx->ack_timeout); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "expected_ack_cnt:", - le32_to_cpu(tx->expected_ack_cnt), - accum_tx->expected_ack_cnt, - delta_tx->expected_ack_cnt, - max_tx->expected_ack_cnt); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "actual_ack_cnt:", - le32_to_cpu(tx->actual_ack_cnt), - accum_tx->actual_ack_cnt, - delta_tx->actual_ack_cnt, - max_tx->actual_ack_cnt); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "dump_msdu_cnt:", - le32_to_cpu(tx->dump_msdu_cnt), - accum_tx->dump_msdu_cnt, - delta_tx->dump_msdu_cnt, - max_tx->dump_msdu_cnt); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "abort_nxt_frame_mismatch:", - le32_to_cpu(tx->burst_abort_next_frame_mismatch_cnt), - accum_tx->burst_abort_next_frame_mismatch_cnt, - delta_tx->burst_abort_next_frame_mismatch_cnt, - max_tx->burst_abort_next_frame_mismatch_cnt); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "abort_missing_nxt_frame:", - le32_to_cpu(tx->burst_abort_missing_next_frame_cnt), - accum_tx->burst_abort_missing_next_frame_cnt, - delta_tx->burst_abort_missing_next_frame_cnt, - max_tx->burst_abort_missing_next_frame_cnt); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "cts_timeout_collision:", - le32_to_cpu(tx->cts_timeout_collision), - accum_tx->cts_timeout_collision, - delta_tx->cts_timeout_collision, - max_tx->cts_timeout_collision); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "ack_ba_timeout_collision:", - le32_to_cpu(tx->ack_or_ba_timeout_collision), - accum_tx->ack_or_ba_timeout_collision, - delta_tx->ack_or_ba_timeout_collision, - max_tx->ack_or_ba_timeout_collision); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "agg ba_timeout:", - le32_to_cpu(tx->agg.ba_timeout), - accum_tx->agg.ba_timeout, - delta_tx->agg.ba_timeout, - max_tx->agg.ba_timeout); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "agg ba_resched_frames:", - le32_to_cpu(tx->agg.ba_reschedule_frames), - accum_tx->agg.ba_reschedule_frames, - delta_tx->agg.ba_reschedule_frames, - max_tx->agg.ba_reschedule_frames); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "agg scd_query_agg_frame:", - le32_to_cpu(tx->agg.scd_query_agg_frame_cnt), - accum_tx->agg.scd_query_agg_frame_cnt, - delta_tx->agg.scd_query_agg_frame_cnt, - max_tx->agg.scd_query_agg_frame_cnt); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "agg scd_query_no_agg:", - le32_to_cpu(tx->agg.scd_query_no_agg), - accum_tx->agg.scd_query_no_agg, - delta_tx->agg.scd_query_no_agg, - max_tx->agg.scd_query_no_agg); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "agg scd_query_agg:", - le32_to_cpu(tx->agg.scd_query_agg), - accum_tx->agg.scd_query_agg, - delta_tx->agg.scd_query_agg, - max_tx->agg.scd_query_agg); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "agg scd_query_mismatch:", - le32_to_cpu(tx->agg.scd_query_mismatch), - accum_tx->agg.scd_query_mismatch, - delta_tx->agg.scd_query_mismatch, - max_tx->agg.scd_query_mismatch); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "agg frame_not_ready:", - le32_to_cpu(tx->agg.frame_not_ready), - accum_tx->agg.frame_not_ready, - delta_tx->agg.frame_not_ready, - max_tx->agg.frame_not_ready); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "agg underrun:", - le32_to_cpu(tx->agg.underrun), - accum_tx->agg.underrun, - delta_tx->agg.underrun, max_tx->agg.underrun); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "agg bt_prio_kill:", - le32_to_cpu(tx->agg.bt_prio_kill), - accum_tx->agg.bt_prio_kill, - delta_tx->agg.bt_prio_kill, - max_tx->agg.bt_prio_kill); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "agg rx_ba_rsp_cnt:", - le32_to_cpu(tx->agg.rx_ba_rsp_cnt), - accum_tx->agg.rx_ba_rsp_cnt, - delta_tx->agg.rx_ba_rsp_cnt, - max_tx->agg.rx_ba_rsp_cnt); - - if (tx->tx_power.ant_a || tx->tx_power.ant_b || tx->tx_power.ant_c) { - pos += scnprintf(buf + pos, bufsz - pos, - "tx power: (1/2 dB step)\n"); - if ((priv->cfg->valid_tx_ant & ANT_A) && tx->tx_power.ant_a) - pos += scnprintf(buf + pos, bufsz - pos, - fmt_hex, "antenna A:", - tx->tx_power.ant_a); - if ((priv->cfg->valid_tx_ant & ANT_B) && tx->tx_power.ant_b) - pos += scnprintf(buf + pos, bufsz - pos, - fmt_hex, "antenna B:", - tx->tx_power.ant_b); - if ((priv->cfg->valid_tx_ant & ANT_C) && tx->tx_power.ant_c) - pos += scnprintf(buf + pos, bufsz - pos, - fmt_hex, "antenna C:", - tx->tx_power.ant_c); - } - ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos); - kfree(buf); - return ret; -} - -ssize_t iwl_ucode_general_stats_read(struct file *file, char __user *user_buf, - size_t count, loff_t *ppos) -{ - struct iwl_priv *priv = file->private_data; - int pos = 0; - char *buf; - int bufsz = sizeof(struct statistics_general) * 10 + 300; - ssize_t ret; - struct statistics_general_common *general, *accum_general; - struct statistics_general_common *delta_general, *max_general; - struct statistics_dbg *dbg, *accum_dbg, *delta_dbg, *max_dbg; - struct statistics_div *div, *accum_div, *delta_div, *max_div; - - if (!iwl_is_alive(priv)) - return -EAGAIN; - - buf = kzalloc(bufsz, GFP_KERNEL); - if (!buf) { - IWL_ERR(priv, "Can not allocate Buffer\n"); - return -ENOMEM; - } - - /* the statistic information display here is based on - * the last statistics notification from uCode - * might not reflect the current uCode activity - */ - general = &priv->statistics.common; - dbg = &priv->statistics.common.dbg; - div = &priv->statistics.common.div; - accum_general = &priv->accum_stats.common; - accum_dbg = &priv->accum_stats.common.dbg; - accum_div = &priv->accum_stats.common.div; - delta_general = &priv->delta_stats.common; - max_general = &priv->max_delta_stats.common; - delta_dbg = &priv->delta_stats.common.dbg; - max_dbg = &priv->max_delta_stats.common.dbg; - delta_div = &priv->delta_stats.common.div; - max_div = &priv->max_delta_stats.common.div; - - pos += iwl_statistics_flag(priv, buf, bufsz); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_header, "Statistics_General:"); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_value, "temperature:", - le32_to_cpu(general->temperature)); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_value, "temperature_m:", - le32_to_cpu(general->temperature_m)); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_value, "ttl_timestamp:", - le32_to_cpu(general->ttl_timestamp)); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "burst_check:", - le32_to_cpu(dbg->burst_check), - accum_dbg->burst_check, - delta_dbg->burst_check, max_dbg->burst_check); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "burst_count:", - le32_to_cpu(dbg->burst_count), - accum_dbg->burst_count, - delta_dbg->burst_count, max_dbg->burst_count); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "wait_for_silence_timeout_count:", - le32_to_cpu(dbg->wait_for_silence_timeout_cnt), - accum_dbg->wait_for_silence_timeout_cnt, - delta_dbg->wait_for_silence_timeout_cnt, - max_dbg->wait_for_silence_timeout_cnt); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "sleep_time:", - le32_to_cpu(general->sleep_time), - accum_general->sleep_time, - delta_general->sleep_time, max_general->sleep_time); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "slots_out:", - le32_to_cpu(general->slots_out), - accum_general->slots_out, - delta_general->slots_out, max_general->slots_out); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "slots_idle:", - le32_to_cpu(general->slots_idle), - accum_general->slots_idle, - delta_general->slots_idle, max_general->slots_idle); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "tx_on_a:", - le32_to_cpu(div->tx_on_a), accum_div->tx_on_a, - delta_div->tx_on_a, max_div->tx_on_a); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "tx_on_b:", - le32_to_cpu(div->tx_on_b), accum_div->tx_on_b, - delta_div->tx_on_b, max_div->tx_on_b); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "exec_time:", - le32_to_cpu(div->exec_time), accum_div->exec_time, - delta_div->exec_time, max_div->exec_time); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "probe_time:", - le32_to_cpu(div->probe_time), accum_div->probe_time, - delta_div->probe_time, max_div->probe_time); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "rx_enable_counter:", - le32_to_cpu(general->rx_enable_counter), - accum_general->rx_enable_counter, - delta_general->rx_enable_counter, - max_general->rx_enable_counter); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "num_of_sos_states:", - le32_to_cpu(general->num_of_sos_states), - accum_general->num_of_sos_states, - delta_general->num_of_sos_states, - max_general->num_of_sos_states); - ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos); - kfree(buf); - return ret; -} - -ssize_t iwl_ucode_bt_stats_read(struct file *file, - char __user *user_buf, - size_t count, loff_t *ppos) -{ - struct iwl_priv *priv = (struct iwl_priv *)file->private_data; - int pos = 0; - char *buf; - int bufsz = (sizeof(struct statistics_bt_activity) * 24) + 200; - ssize_t ret; - struct statistics_bt_activity *bt, *accum_bt; - - if (!iwl_is_alive(priv)) - return -EAGAIN; - - if (!priv->bt_enable_flag) - return -EINVAL; - - /* make request to uCode to retrieve statistics information */ - mutex_lock(&priv->mutex); - ret = iwl_send_statistics_request(priv, CMD_SYNC, false); - mutex_unlock(&priv->mutex); - - if (ret) { - IWL_ERR(priv, - "Error sending statistics request: %zd\n", ret); - return -EAGAIN; - } - buf = kzalloc(bufsz, GFP_KERNEL); - if (!buf) { - IWL_ERR(priv, "Can not allocate Buffer\n"); - return -ENOMEM; - } - - /* - * the statistic information display here is based on - * the last statistics notification from uCode - * might not reflect the current uCode activity - */ - bt = &priv->statistics.bt_activity; - accum_bt = &priv->accum_stats.bt_activity; - - pos += iwl_statistics_flag(priv, buf, bufsz); - pos += scnprintf(buf + pos, bufsz - pos, "Statistics_BT:\n"); - pos += scnprintf(buf + pos, bufsz - pos, - "\t\t\tcurrent\t\t\taccumulative\n"); - pos += scnprintf(buf + pos, bufsz - pos, - "hi_priority_tx_req_cnt:\t\t%u\t\t\t%u\n", - le32_to_cpu(bt->hi_priority_tx_req_cnt), - accum_bt->hi_priority_tx_req_cnt); - pos += scnprintf(buf + pos, bufsz - pos, - "hi_priority_tx_denied_cnt:\t%u\t\t\t%u\n", - le32_to_cpu(bt->hi_priority_tx_denied_cnt), - accum_bt->hi_priority_tx_denied_cnt); - pos += scnprintf(buf + pos, bufsz - pos, - "lo_priority_tx_req_cnt:\t\t%u\t\t\t%u\n", - le32_to_cpu(bt->lo_priority_tx_req_cnt), - accum_bt->lo_priority_tx_req_cnt); - pos += scnprintf(buf + pos, bufsz - pos, - "lo_priority_tx_denied_cnt:\t%u\t\t\t%u\n", - le32_to_cpu(bt->lo_priority_tx_denied_cnt), - accum_bt->lo_priority_tx_denied_cnt); - pos += scnprintf(buf + pos, bufsz - pos, - "hi_priority_rx_req_cnt:\t\t%u\t\t\t%u\n", - le32_to_cpu(bt->hi_priority_rx_req_cnt), - accum_bt->hi_priority_rx_req_cnt); - pos += scnprintf(buf + pos, bufsz - pos, - "hi_priority_rx_denied_cnt:\t%u\t\t\t%u\n", - le32_to_cpu(bt->hi_priority_rx_denied_cnt), - accum_bt->hi_priority_rx_denied_cnt); - pos += scnprintf(buf + pos, bufsz - pos, - "lo_priority_rx_req_cnt:\t\t%u\t\t\t%u\n", - le32_to_cpu(bt->lo_priority_rx_req_cnt), - accum_bt->lo_priority_rx_req_cnt); - pos += scnprintf(buf + pos, bufsz - pos, - "lo_priority_rx_denied_cnt:\t%u\t\t\t%u\n", - le32_to_cpu(bt->lo_priority_rx_denied_cnt), - accum_bt->lo_priority_rx_denied_cnt); - - pos += scnprintf(buf + pos, bufsz - pos, - "(rx)num_bt_kills:\t\t%u\t\t\t%u\n", - le32_to_cpu(priv->statistics.num_bt_kills), - priv->statistics.accum_num_bt_kills); - - ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos); - kfree(buf); - return ret; -} - -ssize_t iwl_reply_tx_error_read(struct file *file, - char __user *user_buf, - size_t count, loff_t *ppos) -{ - struct iwl_priv *priv = (struct iwl_priv *)file->private_data; - int pos = 0; - char *buf; - int bufsz = (sizeof(struct reply_tx_error_statistics) * 24) + - (sizeof(struct reply_agg_tx_error_statistics) * 24) + 200; - ssize_t ret; - - if (!iwl_is_alive(priv)) - return -EAGAIN; - - buf = kzalloc(bufsz, GFP_KERNEL); - if (!buf) { - IWL_ERR(priv, "Can not allocate Buffer\n"); - return -ENOMEM; - } - - pos += scnprintf(buf + pos, bufsz - pos, "Statistics_TX_Error:\n"); - pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t\t%u\n", - iwl_get_tx_fail_reason(TX_STATUS_POSTPONE_DELAY), - priv->_agn.reply_tx_stats.pp_delay); - pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n", - iwl_get_tx_fail_reason(TX_STATUS_POSTPONE_FEW_BYTES), - priv->_agn.reply_tx_stats.pp_few_bytes); - pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n", - iwl_get_tx_fail_reason(TX_STATUS_POSTPONE_BT_PRIO), - priv->_agn.reply_tx_stats.pp_bt_prio); - pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n", - iwl_get_tx_fail_reason(TX_STATUS_POSTPONE_QUIET_PERIOD), - priv->_agn.reply_tx_stats.pp_quiet_period); - pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n", - iwl_get_tx_fail_reason(TX_STATUS_POSTPONE_CALC_TTAK), - priv->_agn.reply_tx_stats.pp_calc_ttak); - pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t%u\n", - iwl_get_tx_fail_reason( - TX_STATUS_FAIL_INTERNAL_CROSSED_RETRY), - priv->_agn.reply_tx_stats.int_crossed_retry); - pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n", - iwl_get_tx_fail_reason(TX_STATUS_FAIL_SHORT_LIMIT), - priv->_agn.reply_tx_stats.short_limit); - pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n", - iwl_get_tx_fail_reason(TX_STATUS_FAIL_LONG_LIMIT), - priv->_agn.reply_tx_stats.long_limit); - pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n", - iwl_get_tx_fail_reason(TX_STATUS_FAIL_FIFO_UNDERRUN), - priv->_agn.reply_tx_stats.fifo_underrun); - pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n", - iwl_get_tx_fail_reason(TX_STATUS_FAIL_DRAIN_FLOW), - priv->_agn.reply_tx_stats.drain_flow); - pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n", - iwl_get_tx_fail_reason(TX_STATUS_FAIL_RFKILL_FLUSH), - priv->_agn.reply_tx_stats.rfkill_flush); - pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n", - iwl_get_tx_fail_reason(TX_STATUS_FAIL_LIFE_EXPIRE), - priv->_agn.reply_tx_stats.life_expire); - pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n", - iwl_get_tx_fail_reason(TX_STATUS_FAIL_DEST_PS), - priv->_agn.reply_tx_stats.dest_ps); - pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n", - iwl_get_tx_fail_reason(TX_STATUS_FAIL_HOST_ABORTED), - priv->_agn.reply_tx_stats.host_abort); - pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n", - iwl_get_tx_fail_reason(TX_STATUS_FAIL_BT_RETRY), - priv->_agn.reply_tx_stats.pp_delay); - pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n", - iwl_get_tx_fail_reason(TX_STATUS_FAIL_STA_INVALID), - priv->_agn.reply_tx_stats.sta_invalid); - pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n", - iwl_get_tx_fail_reason(TX_STATUS_FAIL_FRAG_DROPPED), - priv->_agn.reply_tx_stats.frag_drop); - pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n", - iwl_get_tx_fail_reason(TX_STATUS_FAIL_TID_DISABLE), - priv->_agn.reply_tx_stats.tid_disable); - pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n", - iwl_get_tx_fail_reason(TX_STATUS_FAIL_FIFO_FLUSHED), - priv->_agn.reply_tx_stats.fifo_flush); - pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t%u\n", - iwl_get_tx_fail_reason( - TX_STATUS_FAIL_INSUFFICIENT_CF_POLL), - priv->_agn.reply_tx_stats.insuff_cf_poll); - pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n", - iwl_get_tx_fail_reason(TX_STATUS_FAIL_PASSIVE_NO_RX), - priv->_agn.reply_tx_stats.fail_hw_drop); - pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t%u\n", - iwl_get_tx_fail_reason( - TX_STATUS_FAIL_NO_BEACON_ON_RADAR), - priv->_agn.reply_tx_stats.sta_color_mismatch); - pos += scnprintf(buf + pos, bufsz - pos, "UNKNOWN:\t\t\t%u\n", - priv->_agn.reply_tx_stats.unknown); - - pos += scnprintf(buf + pos, bufsz - pos, - "\nStatistics_Agg_TX_Error:\n"); - - pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n", - iwl_get_agg_tx_fail_reason(AGG_TX_STATE_UNDERRUN_MSK), - priv->_agn.reply_agg_tx_stats.underrun); - pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n", - iwl_get_agg_tx_fail_reason(AGG_TX_STATE_BT_PRIO_MSK), - priv->_agn.reply_agg_tx_stats.bt_prio); - pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n", - iwl_get_agg_tx_fail_reason(AGG_TX_STATE_FEW_BYTES_MSK), - priv->_agn.reply_agg_tx_stats.few_bytes); - pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n", - iwl_get_agg_tx_fail_reason(AGG_TX_STATE_ABORT_MSK), - priv->_agn.reply_agg_tx_stats.abort); - pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t%u\n", - iwl_get_agg_tx_fail_reason( - AGG_TX_STATE_LAST_SENT_TTL_MSK), - priv->_agn.reply_agg_tx_stats.last_sent_ttl); - pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t%u\n", - iwl_get_agg_tx_fail_reason( - AGG_TX_STATE_LAST_SENT_TRY_CNT_MSK), - priv->_agn.reply_agg_tx_stats.last_sent_try); - pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t%u\n", - iwl_get_agg_tx_fail_reason( - AGG_TX_STATE_LAST_SENT_BT_KILL_MSK), - priv->_agn.reply_agg_tx_stats.last_sent_bt_kill); - pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n", - iwl_get_agg_tx_fail_reason(AGG_TX_STATE_SCD_QUERY_MSK), - priv->_agn.reply_agg_tx_stats.scd_query); - pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t%u\n", - iwl_get_agg_tx_fail_reason( - AGG_TX_STATE_TEST_BAD_CRC32_MSK), - priv->_agn.reply_agg_tx_stats.bad_crc32); - pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n", - iwl_get_agg_tx_fail_reason(AGG_TX_STATE_RESPONSE_MSK), - priv->_agn.reply_agg_tx_stats.response); - pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n", - iwl_get_agg_tx_fail_reason(AGG_TX_STATE_DUMP_TX_MSK), - priv->_agn.reply_agg_tx_stats.dump_tx); - pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n", - iwl_get_agg_tx_fail_reason(AGG_TX_STATE_DELAY_TX_MSK), - priv->_agn.reply_agg_tx_stats.delay_tx); - pos += scnprintf(buf + pos, bufsz - pos, "UNKNOWN:\t\t\t%u\n", - priv->_agn.reply_agg_tx_stats.unknown); - - ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos); - kfree(buf); - return ret; -} diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-debugfs.h b/drivers/net/wireless/iwlwifi/iwl-agn-debugfs.h deleted file mode 100644 index 9a3f329..0000000 --- a/drivers/net/wireless/iwlwifi/iwl-agn-debugfs.h +++ /dev/null @@ -1,70 +0,0 @@ -/****************************************************************************** - * - * GPL LICENSE SUMMARY - * - * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of version 2 of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, - * USA - * - * The full GNU General Public License is included in this distribution - * in the file called LICENSE.GPL. - * - * Contact Information: - * Intel Linux Wireless - * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 - *****************************************************************************/ - -#include "iwl-dev.h" -#include "iwl-core.h" -#include "iwl-debug.h" - -#ifdef CONFIG_IWLWIFI_DEBUGFS -ssize_t iwl_ucode_rx_stats_read(struct file *file, char __user *user_buf, - size_t count, loff_t *ppos); -ssize_t iwl_ucode_tx_stats_read(struct file *file, char __user *user_buf, - size_t count, loff_t *ppos); -ssize_t iwl_ucode_general_stats_read(struct file *file, char __user *user_buf, - size_t count, loff_t *ppos); -ssize_t iwl_ucode_bt_stats_read(struct file *file, char __user *user_buf, - size_t count, loff_t *ppos); -ssize_t iwl_reply_tx_error_read(struct file *file, char __user *user_buf, - size_t count, loff_t *ppos); -#else -static ssize_t iwl_ucode_rx_stats_read(struct file *file, char __user *user_buf, - size_t count, loff_t *ppos) -{ - return 0; -} -static ssize_t iwl_ucode_tx_stats_read(struct file *file, char __user *user_buf, - size_t count, loff_t *ppos) -{ - return 0; -} -static ssize_t iwl_ucode_general_stats_read(struct file *file, char __user *user_buf, - size_t count, loff_t *ppos) -{ - return 0; -} -static ssize_t iwl_ucode_bt_stats_read(struct file *file, char __user *user_buf, - size_t count, loff_t *ppos) -{ - return 0; -} -static ssize_t iwl_reply_tx_error_read(struct file *file, char __user *user_buf, - size_t count, loff_t *ppos) -{ - return 0; -} -#endif diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h index ca6bd07..dec98207 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.h +++ b/drivers/net/wireless/iwlwifi/iwl-core.h @@ -121,19 +121,6 @@ struct iwl_apm_ops { void (*config)(struct iwl_priv *priv); }; -struct iwl_debugfs_ops { - ssize_t (*rx_stats_read)(struct file *file, char __user *user_buf, - size_t count, loff_t *ppos); - ssize_t (*tx_stats_read)(struct file *file, char __user *user_buf, - size_t count, loff_t *ppos); - ssize_t (*general_stats_read)(struct file *file, char __user *user_buf, - size_t count, loff_t *ppos); - ssize_t (*bt_stats_read)(struct file *file, char __user *user_buf, - size_t count, loff_t *ppos); - ssize_t (*reply_tx_error)(struct file *file, char __user *user_buf, - size_t count, loff_t *ppos); -}; - struct iwl_temp_ops { void (*temperature)(struct iwl_priv *priv); }; @@ -182,7 +169,6 @@ struct iwl_lib_ops { int (*txfifo_flush)(struct iwl_priv *priv, u16 flush_control); void (*dev_txfifo_flush)(struct iwl_priv *priv, u16 flush_control); - struct iwl_debugfs_ops debugfs_ops; }; /* NIC specific ops */ diff --git a/drivers/net/wireless/iwlwifi/iwl-debugfs.c b/drivers/net/wireless/iwlwifi/iwl-debugfs.c index 7bd4f5a..0e6a04b 100644 --- a/drivers/net/wireless/iwlwifi/iwl-debugfs.c +++ b/drivers/net/wireless/iwlwifi/iwl-debugfs.c @@ -39,6 +39,7 @@ #include "iwl-debug.h" #include "iwl-core.h" #include "iwl-io.h" +#include "iwl-agn.h" /* create and remove of files */ #define DEBUGFS_ADD_FILE(name, parent, mode) do { \ @@ -1037,13 +1038,463 @@ static ssize_t iwl_dbgfs_rx_queue_read(struct file *file, return simple_read_from_buffer(user_buf, count, ppos, buf, pos); } +static const char *fmt_value = " %-30s %10u\n"; +static const char *fmt_hex = " %-30s 0x%02X\n"; +static const char *fmt_table = " %-30s %10u %10u %10u %10u\n"; +static const char *fmt_header = + "%-32s current cumulative delta max\n"; + +static int iwl_statistics_flag(struct iwl_priv *priv, char *buf, int bufsz) +{ + int p = 0; + u32 flag; + + flag = le32_to_cpu(priv->statistics.flag); + + p += scnprintf(buf + p, bufsz - p, "Statistics Flag(0x%X):\n", flag); + if (flag & UCODE_STATISTICS_CLEAR_MSK) + p += scnprintf(buf + p, bufsz - p, + "\tStatistics have been cleared\n"); + p += scnprintf(buf + p, bufsz - p, "\tOperational Frequency: %s\n", + (flag & UCODE_STATISTICS_FREQUENCY_MSK) + ? "2.4 GHz" : "5.2 GHz"); + p += scnprintf(buf + p, bufsz - p, "\tTGj Narrow Band: %s\n", + (flag & UCODE_STATISTICS_NARROW_BAND_MSK) + ? "enabled" : "disabled"); + + return p; +} + static ssize_t iwl_dbgfs_ucode_rx_stats_read(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) { struct iwl_priv *priv = file->private_data; - return priv->cfg->ops->lib->debugfs_ops.rx_stats_read(file, - user_buf, count, ppos); + int pos = 0; + char *buf; + int bufsz = sizeof(struct statistics_rx_phy) * 40 + + sizeof(struct statistics_rx_non_phy) * 40 + + sizeof(struct statistics_rx_ht_phy) * 40 + 400; + ssize_t ret; + struct statistics_rx_phy *ofdm, *accum_ofdm, *delta_ofdm, *max_ofdm; + struct statistics_rx_phy *cck, *accum_cck, *delta_cck, *max_cck; + struct statistics_rx_non_phy *general, *accum_general; + struct statistics_rx_non_phy *delta_general, *max_general; + struct statistics_rx_ht_phy *ht, *accum_ht, *delta_ht, *max_ht; + + if (!iwl_is_alive(priv)) + return -EAGAIN; + + buf = kzalloc(bufsz, GFP_KERNEL); + if (!buf) { + IWL_ERR(priv, "Can not allocate Buffer\n"); + return -ENOMEM; + } + + /* + * the statistic information display here is based on + * the last statistics notification from uCode + * might not reflect the current uCode activity + */ + ofdm = &priv->statistics.rx_ofdm; + cck = &priv->statistics.rx_cck; + general = &priv->statistics.rx_non_phy; + ht = &priv->statistics.rx_ofdm_ht; + accum_ofdm = &priv->accum_stats.rx_ofdm; + accum_cck = &priv->accum_stats.rx_cck; + accum_general = &priv->accum_stats.rx_non_phy; + accum_ht = &priv->accum_stats.rx_ofdm_ht; + delta_ofdm = &priv->delta_stats.rx_ofdm; + delta_cck = &priv->delta_stats.rx_cck; + delta_general = &priv->delta_stats.rx_non_phy; + delta_ht = &priv->delta_stats.rx_ofdm_ht; + max_ofdm = &priv->max_delta_stats.rx_ofdm; + max_cck = &priv->max_delta_stats.rx_cck; + max_general = &priv->max_delta_stats.rx_non_phy; + max_ht = &priv->max_delta_stats.rx_ofdm_ht; + + pos += iwl_statistics_flag(priv, buf, bufsz); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_header, "Statistics_Rx - OFDM:"); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "ina_cnt:", + le32_to_cpu(ofdm->ina_cnt), + accum_ofdm->ina_cnt, + delta_ofdm->ina_cnt, max_ofdm->ina_cnt); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "fina_cnt:", + le32_to_cpu(ofdm->fina_cnt), accum_ofdm->fina_cnt, + delta_ofdm->fina_cnt, max_ofdm->fina_cnt); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "plcp_err:", + le32_to_cpu(ofdm->plcp_err), accum_ofdm->plcp_err, + delta_ofdm->plcp_err, max_ofdm->plcp_err); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "crc32_err:", + le32_to_cpu(ofdm->crc32_err), accum_ofdm->crc32_err, + delta_ofdm->crc32_err, max_ofdm->crc32_err); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "overrun_err:", + le32_to_cpu(ofdm->overrun_err), + accum_ofdm->overrun_err, delta_ofdm->overrun_err, + max_ofdm->overrun_err); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "early_overrun_err:", + le32_to_cpu(ofdm->early_overrun_err), + accum_ofdm->early_overrun_err, + delta_ofdm->early_overrun_err, + max_ofdm->early_overrun_err); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "crc32_good:", + le32_to_cpu(ofdm->crc32_good), + accum_ofdm->crc32_good, delta_ofdm->crc32_good, + max_ofdm->crc32_good); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "false_alarm_cnt:", + le32_to_cpu(ofdm->false_alarm_cnt), + accum_ofdm->false_alarm_cnt, + delta_ofdm->false_alarm_cnt, + max_ofdm->false_alarm_cnt); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "fina_sync_err_cnt:", + le32_to_cpu(ofdm->fina_sync_err_cnt), + accum_ofdm->fina_sync_err_cnt, + delta_ofdm->fina_sync_err_cnt, + max_ofdm->fina_sync_err_cnt); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "sfd_timeout:", + le32_to_cpu(ofdm->sfd_timeout), + accum_ofdm->sfd_timeout, delta_ofdm->sfd_timeout, + max_ofdm->sfd_timeout); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "fina_timeout:", + le32_to_cpu(ofdm->fina_timeout), + accum_ofdm->fina_timeout, delta_ofdm->fina_timeout, + max_ofdm->fina_timeout); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "unresponded_rts:", + le32_to_cpu(ofdm->unresponded_rts), + accum_ofdm->unresponded_rts, + delta_ofdm->unresponded_rts, + max_ofdm->unresponded_rts); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "rxe_frame_lmt_ovrun:", + le32_to_cpu(ofdm->rxe_frame_limit_overrun), + accum_ofdm->rxe_frame_limit_overrun, + delta_ofdm->rxe_frame_limit_overrun, + max_ofdm->rxe_frame_limit_overrun); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "sent_ack_cnt:", + le32_to_cpu(ofdm->sent_ack_cnt), + accum_ofdm->sent_ack_cnt, delta_ofdm->sent_ack_cnt, + max_ofdm->sent_ack_cnt); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "sent_cts_cnt:", + le32_to_cpu(ofdm->sent_cts_cnt), + accum_ofdm->sent_cts_cnt, delta_ofdm->sent_cts_cnt, + max_ofdm->sent_cts_cnt); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "sent_ba_rsp_cnt:", + le32_to_cpu(ofdm->sent_ba_rsp_cnt), + accum_ofdm->sent_ba_rsp_cnt, + delta_ofdm->sent_ba_rsp_cnt, + max_ofdm->sent_ba_rsp_cnt); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "dsp_self_kill:", + le32_to_cpu(ofdm->dsp_self_kill), + accum_ofdm->dsp_self_kill, + delta_ofdm->dsp_self_kill, + max_ofdm->dsp_self_kill); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "mh_format_err:", + le32_to_cpu(ofdm->mh_format_err), + accum_ofdm->mh_format_err, + delta_ofdm->mh_format_err, + max_ofdm->mh_format_err); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "re_acq_main_rssi_sum:", + le32_to_cpu(ofdm->re_acq_main_rssi_sum), + accum_ofdm->re_acq_main_rssi_sum, + delta_ofdm->re_acq_main_rssi_sum, + max_ofdm->re_acq_main_rssi_sum); + + pos += scnprintf(buf + pos, bufsz - pos, + fmt_header, "Statistics_Rx - CCK:"); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "ina_cnt:", + le32_to_cpu(cck->ina_cnt), accum_cck->ina_cnt, + delta_cck->ina_cnt, max_cck->ina_cnt); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "fina_cnt:", + le32_to_cpu(cck->fina_cnt), accum_cck->fina_cnt, + delta_cck->fina_cnt, max_cck->fina_cnt); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "plcp_err:", + le32_to_cpu(cck->plcp_err), accum_cck->plcp_err, + delta_cck->plcp_err, max_cck->plcp_err); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "crc32_err:", + le32_to_cpu(cck->crc32_err), accum_cck->crc32_err, + delta_cck->crc32_err, max_cck->crc32_err); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "overrun_err:", + le32_to_cpu(cck->overrun_err), + accum_cck->overrun_err, delta_cck->overrun_err, + max_cck->overrun_err); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "early_overrun_err:", + le32_to_cpu(cck->early_overrun_err), + accum_cck->early_overrun_err, + delta_cck->early_overrun_err, + max_cck->early_overrun_err); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "crc32_good:", + le32_to_cpu(cck->crc32_good), accum_cck->crc32_good, + delta_cck->crc32_good, max_cck->crc32_good); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "false_alarm_cnt:", + le32_to_cpu(cck->false_alarm_cnt), + accum_cck->false_alarm_cnt, + delta_cck->false_alarm_cnt, max_cck->false_alarm_cnt); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "fina_sync_err_cnt:", + le32_to_cpu(cck->fina_sync_err_cnt), + accum_cck->fina_sync_err_cnt, + delta_cck->fina_sync_err_cnt, + max_cck->fina_sync_err_cnt); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "sfd_timeout:", + le32_to_cpu(cck->sfd_timeout), + accum_cck->sfd_timeout, delta_cck->sfd_timeout, + max_cck->sfd_timeout); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "fina_timeout:", + le32_to_cpu(cck->fina_timeout), + accum_cck->fina_timeout, delta_cck->fina_timeout, + max_cck->fina_timeout); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "unresponded_rts:", + le32_to_cpu(cck->unresponded_rts), + accum_cck->unresponded_rts, delta_cck->unresponded_rts, + max_cck->unresponded_rts); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "rxe_frame_lmt_ovrun:", + le32_to_cpu(cck->rxe_frame_limit_overrun), + accum_cck->rxe_frame_limit_overrun, + delta_cck->rxe_frame_limit_overrun, + max_cck->rxe_frame_limit_overrun); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "sent_ack_cnt:", + le32_to_cpu(cck->sent_ack_cnt), + accum_cck->sent_ack_cnt, delta_cck->sent_ack_cnt, + max_cck->sent_ack_cnt); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "sent_cts_cnt:", + le32_to_cpu(cck->sent_cts_cnt), + accum_cck->sent_cts_cnt, delta_cck->sent_cts_cnt, + max_cck->sent_cts_cnt); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "sent_ba_rsp_cnt:", + le32_to_cpu(cck->sent_ba_rsp_cnt), + accum_cck->sent_ba_rsp_cnt, + delta_cck->sent_ba_rsp_cnt, + max_cck->sent_ba_rsp_cnt); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "dsp_self_kill:", + le32_to_cpu(cck->dsp_self_kill), + accum_cck->dsp_self_kill, delta_cck->dsp_self_kill, + max_cck->dsp_self_kill); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "mh_format_err:", + le32_to_cpu(cck->mh_format_err), + accum_cck->mh_format_err, delta_cck->mh_format_err, + max_cck->mh_format_err); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "re_acq_main_rssi_sum:", + le32_to_cpu(cck->re_acq_main_rssi_sum), + accum_cck->re_acq_main_rssi_sum, + delta_cck->re_acq_main_rssi_sum, + max_cck->re_acq_main_rssi_sum); + + pos += scnprintf(buf + pos, bufsz - pos, + fmt_header, "Statistics_Rx - GENERAL:"); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "bogus_cts:", + le32_to_cpu(general->bogus_cts), + accum_general->bogus_cts, delta_general->bogus_cts, + max_general->bogus_cts); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "bogus_ack:", + le32_to_cpu(general->bogus_ack), + accum_general->bogus_ack, delta_general->bogus_ack, + max_general->bogus_ack); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "non_bssid_frames:", + le32_to_cpu(general->non_bssid_frames), + accum_general->non_bssid_frames, + delta_general->non_bssid_frames, + max_general->non_bssid_frames); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "filtered_frames:", + le32_to_cpu(general->filtered_frames), + accum_general->filtered_frames, + delta_general->filtered_frames, + max_general->filtered_frames); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "non_channel_beacons:", + le32_to_cpu(general->non_channel_beacons), + accum_general->non_channel_beacons, + delta_general->non_channel_beacons, + max_general->non_channel_beacons); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "channel_beacons:", + le32_to_cpu(general->channel_beacons), + accum_general->channel_beacons, + delta_general->channel_beacons, + max_general->channel_beacons); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "num_missed_bcon:", + le32_to_cpu(general->num_missed_bcon), + accum_general->num_missed_bcon, + delta_general->num_missed_bcon, + max_general->num_missed_bcon); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "adc_rx_saturation_time:", + le32_to_cpu(general->adc_rx_saturation_time), + accum_general->adc_rx_saturation_time, + delta_general->adc_rx_saturation_time, + max_general->adc_rx_saturation_time); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "ina_detect_search_tm:", + le32_to_cpu(general->ina_detection_search_time), + accum_general->ina_detection_search_time, + delta_general->ina_detection_search_time, + max_general->ina_detection_search_time); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "beacon_silence_rssi_a:", + le32_to_cpu(general->beacon_silence_rssi_a), + accum_general->beacon_silence_rssi_a, + delta_general->beacon_silence_rssi_a, + max_general->beacon_silence_rssi_a); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "beacon_silence_rssi_b:", + le32_to_cpu(general->beacon_silence_rssi_b), + accum_general->beacon_silence_rssi_b, + delta_general->beacon_silence_rssi_b, + max_general->beacon_silence_rssi_b); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "beacon_silence_rssi_c:", + le32_to_cpu(general->beacon_silence_rssi_c), + accum_general->beacon_silence_rssi_c, + delta_general->beacon_silence_rssi_c, + max_general->beacon_silence_rssi_c); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "interference_data_flag:", + le32_to_cpu(general->interference_data_flag), + accum_general->interference_data_flag, + delta_general->interference_data_flag, + max_general->interference_data_flag); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "channel_load:", + le32_to_cpu(general->channel_load), + accum_general->channel_load, + delta_general->channel_load, + max_general->channel_load); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "dsp_false_alarms:", + le32_to_cpu(general->dsp_false_alarms), + accum_general->dsp_false_alarms, + delta_general->dsp_false_alarms, + max_general->dsp_false_alarms); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "beacon_rssi_a:", + le32_to_cpu(general->beacon_rssi_a), + accum_general->beacon_rssi_a, + delta_general->beacon_rssi_a, + max_general->beacon_rssi_a); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "beacon_rssi_b:", + le32_to_cpu(general->beacon_rssi_b), + accum_general->beacon_rssi_b, + delta_general->beacon_rssi_b, + max_general->beacon_rssi_b); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "beacon_rssi_c:", + le32_to_cpu(general->beacon_rssi_c), + accum_general->beacon_rssi_c, + delta_general->beacon_rssi_c, + max_general->beacon_rssi_c); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "beacon_energy_a:", + le32_to_cpu(general->beacon_energy_a), + accum_general->beacon_energy_a, + delta_general->beacon_energy_a, + max_general->beacon_energy_a); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "beacon_energy_b:", + le32_to_cpu(general->beacon_energy_b), + accum_general->beacon_energy_b, + delta_general->beacon_energy_b, + max_general->beacon_energy_b); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "beacon_energy_c:", + le32_to_cpu(general->beacon_energy_c), + accum_general->beacon_energy_c, + delta_general->beacon_energy_c, + max_general->beacon_energy_c); + + pos += scnprintf(buf + pos, bufsz - pos, + fmt_header, "Statistics_Rx - OFDM_HT:"); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "plcp_err:", + le32_to_cpu(ht->plcp_err), accum_ht->plcp_err, + delta_ht->plcp_err, max_ht->plcp_err); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "overrun_err:", + le32_to_cpu(ht->overrun_err), accum_ht->overrun_err, + delta_ht->overrun_err, max_ht->overrun_err); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "early_overrun_err:", + le32_to_cpu(ht->early_overrun_err), + accum_ht->early_overrun_err, + delta_ht->early_overrun_err, + max_ht->early_overrun_err); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "crc32_good:", + le32_to_cpu(ht->crc32_good), accum_ht->crc32_good, + delta_ht->crc32_good, max_ht->crc32_good); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "crc32_err:", + le32_to_cpu(ht->crc32_err), accum_ht->crc32_err, + delta_ht->crc32_err, max_ht->crc32_err); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "mh_format_err:", + le32_to_cpu(ht->mh_format_err), + accum_ht->mh_format_err, + delta_ht->mh_format_err, max_ht->mh_format_err); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "agg_crc32_good:", + le32_to_cpu(ht->agg_crc32_good), + accum_ht->agg_crc32_good, + delta_ht->agg_crc32_good, max_ht->agg_crc32_good); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "agg_mpdu_cnt:", + le32_to_cpu(ht->agg_mpdu_cnt), + accum_ht->agg_mpdu_cnt, + delta_ht->agg_mpdu_cnt, max_ht->agg_mpdu_cnt); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "agg_cnt:", + le32_to_cpu(ht->agg_cnt), accum_ht->agg_cnt, + delta_ht->agg_cnt, max_ht->agg_cnt); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "unsupport_mcs:", + le32_to_cpu(ht->unsupport_mcs), + accum_ht->unsupport_mcs, + delta_ht->unsupport_mcs, max_ht->unsupport_mcs); + + ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos); + kfree(buf); + return ret; } static ssize_t iwl_dbgfs_ucode_tx_stats_read(struct file *file, @@ -1051,8 +1502,190 @@ static ssize_t iwl_dbgfs_ucode_tx_stats_read(struct file *file, size_t count, loff_t *ppos) { struct iwl_priv *priv = file->private_data; - return priv->cfg->ops->lib->debugfs_ops.tx_stats_read(file, - user_buf, count, ppos); + int pos = 0; + char *buf; + int bufsz = (sizeof(struct statistics_tx) * 48) + 250; + ssize_t ret; + struct statistics_tx *tx, *accum_tx, *delta_tx, *max_tx; + + if (!iwl_is_alive(priv)) + return -EAGAIN; + + buf = kzalloc(bufsz, GFP_KERNEL); + if (!buf) { + IWL_ERR(priv, "Can not allocate Buffer\n"); + return -ENOMEM; + } + + /* the statistic information display here is based on + * the last statistics notification from uCode + * might not reflect the current uCode activity + */ + tx = &priv->statistics.tx; + accum_tx = &priv->accum_stats.tx; + delta_tx = &priv->delta_stats.tx; + max_tx = &priv->max_delta_stats.tx; + + pos += iwl_statistics_flag(priv, buf, bufsz); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_header, "Statistics_Tx:"); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "preamble:", + le32_to_cpu(tx->preamble_cnt), + accum_tx->preamble_cnt, + delta_tx->preamble_cnt, max_tx->preamble_cnt); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "rx_detected_cnt:", + le32_to_cpu(tx->rx_detected_cnt), + accum_tx->rx_detected_cnt, + delta_tx->rx_detected_cnt, max_tx->rx_detected_cnt); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "bt_prio_defer_cnt:", + le32_to_cpu(tx->bt_prio_defer_cnt), + accum_tx->bt_prio_defer_cnt, + delta_tx->bt_prio_defer_cnt, + max_tx->bt_prio_defer_cnt); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "bt_prio_kill_cnt:", + le32_to_cpu(tx->bt_prio_kill_cnt), + accum_tx->bt_prio_kill_cnt, + delta_tx->bt_prio_kill_cnt, + max_tx->bt_prio_kill_cnt); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "few_bytes_cnt:", + le32_to_cpu(tx->few_bytes_cnt), + accum_tx->few_bytes_cnt, + delta_tx->few_bytes_cnt, max_tx->few_bytes_cnt); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "cts_timeout:", + le32_to_cpu(tx->cts_timeout), accum_tx->cts_timeout, + delta_tx->cts_timeout, max_tx->cts_timeout); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "ack_timeout:", + le32_to_cpu(tx->ack_timeout), + accum_tx->ack_timeout, + delta_tx->ack_timeout, max_tx->ack_timeout); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "expected_ack_cnt:", + le32_to_cpu(tx->expected_ack_cnt), + accum_tx->expected_ack_cnt, + delta_tx->expected_ack_cnt, + max_tx->expected_ack_cnt); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "actual_ack_cnt:", + le32_to_cpu(tx->actual_ack_cnt), + accum_tx->actual_ack_cnt, + delta_tx->actual_ack_cnt, + max_tx->actual_ack_cnt); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "dump_msdu_cnt:", + le32_to_cpu(tx->dump_msdu_cnt), + accum_tx->dump_msdu_cnt, + delta_tx->dump_msdu_cnt, + max_tx->dump_msdu_cnt); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "abort_nxt_frame_mismatch:", + le32_to_cpu(tx->burst_abort_next_frame_mismatch_cnt), + accum_tx->burst_abort_next_frame_mismatch_cnt, + delta_tx->burst_abort_next_frame_mismatch_cnt, + max_tx->burst_abort_next_frame_mismatch_cnt); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "abort_missing_nxt_frame:", + le32_to_cpu(tx->burst_abort_missing_next_frame_cnt), + accum_tx->burst_abort_missing_next_frame_cnt, + delta_tx->burst_abort_missing_next_frame_cnt, + max_tx->burst_abort_missing_next_frame_cnt); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "cts_timeout_collision:", + le32_to_cpu(tx->cts_timeout_collision), + accum_tx->cts_timeout_collision, + delta_tx->cts_timeout_collision, + max_tx->cts_timeout_collision); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "ack_ba_timeout_collision:", + le32_to_cpu(tx->ack_or_ba_timeout_collision), + accum_tx->ack_or_ba_timeout_collision, + delta_tx->ack_or_ba_timeout_collision, + max_tx->ack_or_ba_timeout_collision); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "agg ba_timeout:", + le32_to_cpu(tx->agg.ba_timeout), + accum_tx->agg.ba_timeout, + delta_tx->agg.ba_timeout, + max_tx->agg.ba_timeout); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "agg ba_resched_frames:", + le32_to_cpu(tx->agg.ba_reschedule_frames), + accum_tx->agg.ba_reschedule_frames, + delta_tx->agg.ba_reschedule_frames, + max_tx->agg.ba_reschedule_frames); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "agg scd_query_agg_frame:", + le32_to_cpu(tx->agg.scd_query_agg_frame_cnt), + accum_tx->agg.scd_query_agg_frame_cnt, + delta_tx->agg.scd_query_agg_frame_cnt, + max_tx->agg.scd_query_agg_frame_cnt); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "agg scd_query_no_agg:", + le32_to_cpu(tx->agg.scd_query_no_agg), + accum_tx->agg.scd_query_no_agg, + delta_tx->agg.scd_query_no_agg, + max_tx->agg.scd_query_no_agg); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "agg scd_query_agg:", + le32_to_cpu(tx->agg.scd_query_agg), + accum_tx->agg.scd_query_agg, + delta_tx->agg.scd_query_agg, + max_tx->agg.scd_query_agg); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "agg scd_query_mismatch:", + le32_to_cpu(tx->agg.scd_query_mismatch), + accum_tx->agg.scd_query_mismatch, + delta_tx->agg.scd_query_mismatch, + max_tx->agg.scd_query_mismatch); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "agg frame_not_ready:", + le32_to_cpu(tx->agg.frame_not_ready), + accum_tx->agg.frame_not_ready, + delta_tx->agg.frame_not_ready, + max_tx->agg.frame_not_ready); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "agg underrun:", + le32_to_cpu(tx->agg.underrun), + accum_tx->agg.underrun, + delta_tx->agg.underrun, max_tx->agg.underrun); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "agg bt_prio_kill:", + le32_to_cpu(tx->agg.bt_prio_kill), + accum_tx->agg.bt_prio_kill, + delta_tx->agg.bt_prio_kill, + max_tx->agg.bt_prio_kill); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "agg rx_ba_rsp_cnt:", + le32_to_cpu(tx->agg.rx_ba_rsp_cnt), + accum_tx->agg.rx_ba_rsp_cnt, + delta_tx->agg.rx_ba_rsp_cnt, + max_tx->agg.rx_ba_rsp_cnt); + + if (tx->tx_power.ant_a || tx->tx_power.ant_b || tx->tx_power.ant_c) { + pos += scnprintf(buf + pos, bufsz - pos, + "tx power: (1/2 dB step)\n"); + if ((priv->cfg->valid_tx_ant & ANT_A) && tx->tx_power.ant_a) + pos += scnprintf(buf + pos, bufsz - pos, + fmt_hex, "antenna A:", + tx->tx_power.ant_a); + if ((priv->cfg->valid_tx_ant & ANT_B) && tx->tx_power.ant_b) + pos += scnprintf(buf + pos, bufsz - pos, + fmt_hex, "antenna B:", + tx->tx_power.ant_b); + if ((priv->cfg->valid_tx_ant & ANT_C) && tx->tx_power.ant_c) + pos += scnprintf(buf + pos, bufsz - pos, + fmt_hex, "antenna C:", + tx->tx_power.ant_c); + } + ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos); + kfree(buf); + return ret; } static ssize_t iwl_dbgfs_ucode_general_stats_read(struct file *file, @@ -1060,8 +1693,347 @@ static ssize_t iwl_dbgfs_ucode_general_stats_read(struct file *file, size_t count, loff_t *ppos) { struct iwl_priv *priv = file->private_data; - return priv->cfg->ops->lib->debugfs_ops.general_stats_read(file, - user_buf, count, ppos); + int pos = 0; + char *buf; + int bufsz = sizeof(struct statistics_general) * 10 + 300; + ssize_t ret; + struct statistics_general_common *general, *accum_general; + struct statistics_general_common *delta_general, *max_general; + struct statistics_dbg *dbg, *accum_dbg, *delta_dbg, *max_dbg; + struct statistics_div *div, *accum_div, *delta_div, *max_div; + + if (!iwl_is_alive(priv)) + return -EAGAIN; + + buf = kzalloc(bufsz, GFP_KERNEL); + if (!buf) { + IWL_ERR(priv, "Can not allocate Buffer\n"); + return -ENOMEM; + } + + /* the statistic information display here is based on + * the last statistics notification from uCode + * might not reflect the current uCode activity + */ + general = &priv->statistics.common; + dbg = &priv->statistics.common.dbg; + div = &priv->statistics.common.div; + accum_general = &priv->accum_stats.common; + accum_dbg = &priv->accum_stats.common.dbg; + accum_div = &priv->accum_stats.common.div; + delta_general = &priv->delta_stats.common; + max_general = &priv->max_delta_stats.common; + delta_dbg = &priv->delta_stats.common.dbg; + max_dbg = &priv->max_delta_stats.common.dbg; + delta_div = &priv->delta_stats.common.div; + max_div = &priv->max_delta_stats.common.div; + + pos += iwl_statistics_flag(priv, buf, bufsz); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_header, "Statistics_General:"); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_value, "temperature:", + le32_to_cpu(general->temperature)); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_value, "temperature_m:", + le32_to_cpu(general->temperature_m)); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_value, "ttl_timestamp:", + le32_to_cpu(general->ttl_timestamp)); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "burst_check:", + le32_to_cpu(dbg->burst_check), + accum_dbg->burst_check, + delta_dbg->burst_check, max_dbg->burst_check); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "burst_count:", + le32_to_cpu(dbg->burst_count), + accum_dbg->burst_count, + delta_dbg->burst_count, max_dbg->burst_count); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "wait_for_silence_timeout_count:", + le32_to_cpu(dbg->wait_for_silence_timeout_cnt), + accum_dbg->wait_for_silence_timeout_cnt, + delta_dbg->wait_for_silence_timeout_cnt, + max_dbg->wait_for_silence_timeout_cnt); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "sleep_time:", + le32_to_cpu(general->sleep_time), + accum_general->sleep_time, + delta_general->sleep_time, max_general->sleep_time); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "slots_out:", + le32_to_cpu(general->slots_out), + accum_general->slots_out, + delta_general->slots_out, max_general->slots_out); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "slots_idle:", + le32_to_cpu(general->slots_idle), + accum_general->slots_idle, + delta_general->slots_idle, max_general->slots_idle); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "tx_on_a:", + le32_to_cpu(div->tx_on_a), accum_div->tx_on_a, + delta_div->tx_on_a, max_div->tx_on_a); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "tx_on_b:", + le32_to_cpu(div->tx_on_b), accum_div->tx_on_b, + delta_div->tx_on_b, max_div->tx_on_b); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "exec_time:", + le32_to_cpu(div->exec_time), accum_div->exec_time, + delta_div->exec_time, max_div->exec_time); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "probe_time:", + le32_to_cpu(div->probe_time), accum_div->probe_time, + delta_div->probe_time, max_div->probe_time); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "rx_enable_counter:", + le32_to_cpu(general->rx_enable_counter), + accum_general->rx_enable_counter, + delta_general->rx_enable_counter, + max_general->rx_enable_counter); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "num_of_sos_states:", + le32_to_cpu(general->num_of_sos_states), + accum_general->num_of_sos_states, + delta_general->num_of_sos_states, + max_general->num_of_sos_states); + ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos); + kfree(buf); + return ret; +} + +static ssize_t iwl_dbgfs_ucode_bt_stats_read(struct file *file, + char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct iwl_priv *priv = (struct iwl_priv *)file->private_data; + int pos = 0; + char *buf; + int bufsz = (sizeof(struct statistics_bt_activity) * 24) + 200; + ssize_t ret; + struct statistics_bt_activity *bt, *accum_bt; + + if (!iwl_is_alive(priv)) + return -EAGAIN; + + if (!priv->bt_enable_flag) + return -EINVAL; + + /* make request to uCode to retrieve statistics information */ + mutex_lock(&priv->mutex); + ret = iwl_send_statistics_request(priv, CMD_SYNC, false); + mutex_unlock(&priv->mutex); + + if (ret) { + IWL_ERR(priv, + "Error sending statistics request: %zd\n", ret); + return -EAGAIN; + } + buf = kzalloc(bufsz, GFP_KERNEL); + if (!buf) { + IWL_ERR(priv, "Can not allocate Buffer\n"); + return -ENOMEM; + } + + /* + * the statistic information display here is based on + * the last statistics notification from uCode + * might not reflect the current uCode activity + */ + bt = &priv->statistics.bt_activity; + accum_bt = &priv->accum_stats.bt_activity; + + pos += iwl_statistics_flag(priv, buf, bufsz); + pos += scnprintf(buf + pos, bufsz - pos, "Statistics_BT:\n"); + pos += scnprintf(buf + pos, bufsz - pos, + "\t\t\tcurrent\t\t\taccumulative\n"); + pos += scnprintf(buf + pos, bufsz - pos, + "hi_priority_tx_req_cnt:\t\t%u\t\t\t%u\n", + le32_to_cpu(bt->hi_priority_tx_req_cnt), + accum_bt->hi_priority_tx_req_cnt); + pos += scnprintf(buf + pos, bufsz - pos, + "hi_priority_tx_denied_cnt:\t%u\t\t\t%u\n", + le32_to_cpu(bt->hi_priority_tx_denied_cnt), + accum_bt->hi_priority_tx_denied_cnt); + pos += scnprintf(buf + pos, bufsz - pos, + "lo_priority_tx_req_cnt:\t\t%u\t\t\t%u\n", + le32_to_cpu(bt->lo_priority_tx_req_cnt), + accum_bt->lo_priority_tx_req_cnt); + pos += scnprintf(buf + pos, bufsz - pos, + "lo_priority_tx_denied_cnt:\t%u\t\t\t%u\n", + le32_to_cpu(bt->lo_priority_tx_denied_cnt), + accum_bt->lo_priority_tx_denied_cnt); + pos += scnprintf(buf + pos, bufsz - pos, + "hi_priority_rx_req_cnt:\t\t%u\t\t\t%u\n", + le32_to_cpu(bt->hi_priority_rx_req_cnt), + accum_bt->hi_priority_rx_req_cnt); + pos += scnprintf(buf + pos, bufsz - pos, + "hi_priority_rx_denied_cnt:\t%u\t\t\t%u\n", + le32_to_cpu(bt->hi_priority_rx_denied_cnt), + accum_bt->hi_priority_rx_denied_cnt); + pos += scnprintf(buf + pos, bufsz - pos, + "lo_priority_rx_req_cnt:\t\t%u\t\t\t%u\n", + le32_to_cpu(bt->lo_priority_rx_req_cnt), + accum_bt->lo_priority_rx_req_cnt); + pos += scnprintf(buf + pos, bufsz - pos, + "lo_priority_rx_denied_cnt:\t%u\t\t\t%u\n", + le32_to_cpu(bt->lo_priority_rx_denied_cnt), + accum_bt->lo_priority_rx_denied_cnt); + + pos += scnprintf(buf + pos, bufsz - pos, + "(rx)num_bt_kills:\t\t%u\t\t\t%u\n", + le32_to_cpu(priv->statistics.num_bt_kills), + priv->statistics.accum_num_bt_kills); + + ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos); + kfree(buf); + return ret; +} + +static ssize_t iwl_dbgfs_reply_tx_error_read(struct file *file, + char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct iwl_priv *priv = (struct iwl_priv *)file->private_data; + int pos = 0; + char *buf; + int bufsz = (sizeof(struct reply_tx_error_statistics) * 24) + + (sizeof(struct reply_agg_tx_error_statistics) * 24) + 200; + ssize_t ret; + + if (!iwl_is_alive(priv)) + return -EAGAIN; + + buf = kzalloc(bufsz, GFP_KERNEL); + if (!buf) { + IWL_ERR(priv, "Can not allocate Buffer\n"); + return -ENOMEM; + } + + pos += scnprintf(buf + pos, bufsz - pos, "Statistics_TX_Error:\n"); + pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t\t%u\n", + iwl_get_tx_fail_reason(TX_STATUS_POSTPONE_DELAY), + priv->_agn.reply_tx_stats.pp_delay); + pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n", + iwl_get_tx_fail_reason(TX_STATUS_POSTPONE_FEW_BYTES), + priv->_agn.reply_tx_stats.pp_few_bytes); + pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n", + iwl_get_tx_fail_reason(TX_STATUS_POSTPONE_BT_PRIO), + priv->_agn.reply_tx_stats.pp_bt_prio); + pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n", + iwl_get_tx_fail_reason(TX_STATUS_POSTPONE_QUIET_PERIOD), + priv->_agn.reply_tx_stats.pp_quiet_period); + pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n", + iwl_get_tx_fail_reason(TX_STATUS_POSTPONE_CALC_TTAK), + priv->_agn.reply_tx_stats.pp_calc_ttak); + pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t%u\n", + iwl_get_tx_fail_reason( + TX_STATUS_FAIL_INTERNAL_CROSSED_RETRY), + priv->_agn.reply_tx_stats.int_crossed_retry); + pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n", + iwl_get_tx_fail_reason(TX_STATUS_FAIL_SHORT_LIMIT), + priv->_agn.reply_tx_stats.short_limit); + pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n", + iwl_get_tx_fail_reason(TX_STATUS_FAIL_LONG_LIMIT), + priv->_agn.reply_tx_stats.long_limit); + pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n", + iwl_get_tx_fail_reason(TX_STATUS_FAIL_FIFO_UNDERRUN), + priv->_agn.reply_tx_stats.fifo_underrun); + pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n", + iwl_get_tx_fail_reason(TX_STATUS_FAIL_DRAIN_FLOW), + priv->_agn.reply_tx_stats.drain_flow); + pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n", + iwl_get_tx_fail_reason(TX_STATUS_FAIL_RFKILL_FLUSH), + priv->_agn.reply_tx_stats.rfkill_flush); + pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n", + iwl_get_tx_fail_reason(TX_STATUS_FAIL_LIFE_EXPIRE), + priv->_agn.reply_tx_stats.life_expire); + pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n", + iwl_get_tx_fail_reason(TX_STATUS_FAIL_DEST_PS), + priv->_agn.reply_tx_stats.dest_ps); + pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n", + iwl_get_tx_fail_reason(TX_STATUS_FAIL_HOST_ABORTED), + priv->_agn.reply_tx_stats.host_abort); + pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n", + iwl_get_tx_fail_reason(TX_STATUS_FAIL_BT_RETRY), + priv->_agn.reply_tx_stats.pp_delay); + pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n", + iwl_get_tx_fail_reason(TX_STATUS_FAIL_STA_INVALID), + priv->_agn.reply_tx_stats.sta_invalid); + pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n", + iwl_get_tx_fail_reason(TX_STATUS_FAIL_FRAG_DROPPED), + priv->_agn.reply_tx_stats.frag_drop); + pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n", + iwl_get_tx_fail_reason(TX_STATUS_FAIL_TID_DISABLE), + priv->_agn.reply_tx_stats.tid_disable); + pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n", + iwl_get_tx_fail_reason(TX_STATUS_FAIL_FIFO_FLUSHED), + priv->_agn.reply_tx_stats.fifo_flush); + pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t%u\n", + iwl_get_tx_fail_reason( + TX_STATUS_FAIL_INSUFFICIENT_CF_POLL), + priv->_agn.reply_tx_stats.insuff_cf_poll); + pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n", + iwl_get_tx_fail_reason(TX_STATUS_FAIL_PASSIVE_NO_RX), + priv->_agn.reply_tx_stats.fail_hw_drop); + pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t%u\n", + iwl_get_tx_fail_reason( + TX_STATUS_FAIL_NO_BEACON_ON_RADAR), + priv->_agn.reply_tx_stats.sta_color_mismatch); + pos += scnprintf(buf + pos, bufsz - pos, "UNKNOWN:\t\t\t%u\n", + priv->_agn.reply_tx_stats.unknown); + + pos += scnprintf(buf + pos, bufsz - pos, + "\nStatistics_Agg_TX_Error:\n"); + + pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n", + iwl_get_agg_tx_fail_reason(AGG_TX_STATE_UNDERRUN_MSK), + priv->_agn.reply_agg_tx_stats.underrun); + pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n", + iwl_get_agg_tx_fail_reason(AGG_TX_STATE_BT_PRIO_MSK), + priv->_agn.reply_agg_tx_stats.bt_prio); + pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n", + iwl_get_agg_tx_fail_reason(AGG_TX_STATE_FEW_BYTES_MSK), + priv->_agn.reply_agg_tx_stats.few_bytes); + pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n", + iwl_get_agg_tx_fail_reason(AGG_TX_STATE_ABORT_MSK), + priv->_agn.reply_agg_tx_stats.abort); + pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t%u\n", + iwl_get_agg_tx_fail_reason( + AGG_TX_STATE_LAST_SENT_TTL_MSK), + priv->_agn.reply_agg_tx_stats.last_sent_ttl); + pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t%u\n", + iwl_get_agg_tx_fail_reason( + AGG_TX_STATE_LAST_SENT_TRY_CNT_MSK), + priv->_agn.reply_agg_tx_stats.last_sent_try); + pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t%u\n", + iwl_get_agg_tx_fail_reason( + AGG_TX_STATE_LAST_SENT_BT_KILL_MSK), + priv->_agn.reply_agg_tx_stats.last_sent_bt_kill); + pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n", + iwl_get_agg_tx_fail_reason(AGG_TX_STATE_SCD_QUERY_MSK), + priv->_agn.reply_agg_tx_stats.scd_query); + pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t%u\n", + iwl_get_agg_tx_fail_reason( + AGG_TX_STATE_TEST_BAD_CRC32_MSK), + priv->_agn.reply_agg_tx_stats.bad_crc32); + pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n", + iwl_get_agg_tx_fail_reason(AGG_TX_STATE_RESPONSE_MSK), + priv->_agn.reply_agg_tx_stats.response); + pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n", + iwl_get_agg_tx_fail_reason(AGG_TX_STATE_DUMP_TX_MSK), + priv->_agn.reply_agg_tx_stats.dump_tx); + pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n", + iwl_get_agg_tx_fail_reason(AGG_TX_STATE_DELAY_TX_MSK), + priv->_agn.reply_agg_tx_stats.delay_tx); + pos += scnprintf(buf + pos, bufsz - pos, "UNKNOWN:\t\t\t%u\n", + priv->_agn.reply_agg_tx_stats.unknown); + + ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos); + kfree(buf); + return ret; } static ssize_t iwl_dbgfs_sensitivity_read(struct file *file, @@ -1526,16 +2498,6 @@ static ssize_t iwl_dbgfs_txfifo_flush_write(struct file *file, return count; } -static ssize_t iwl_dbgfs_ucode_bt_stats_read(struct file *file, - char __user *user_buf, - size_t count, loff_t *ppos) -{ - struct iwl_priv *priv = (struct iwl_priv *)file->private_data; - - return priv->cfg->ops->lib->debugfs_ops.bt_stats_read(file, - user_buf, count, ppos); -} - static ssize_t iwl_dbgfs_wd_timeout_write(struct file *file, const char __user *user_buf, size_t count, loff_t *ppos) { @@ -1650,18 +2612,6 @@ static ssize_t iwl_dbgfs_protection_mode_write(struct file *file, return count; } -static ssize_t iwl_dbgfs_reply_tx_error_read(struct file *file, - char __user *user_buf, - size_t count, loff_t *ppos) -{ - struct iwl_priv *priv = file->private_data; - - if (priv->cfg->ops->lib->debugfs_ops.reply_tx_error) - return priv->cfg->ops->lib->debugfs_ops.reply_tx_error( - file, user_buf, count, ppos); - else - return -ENODATA; -} DEBUGFS_READ_FILE_OPS(rx_statistics); DEBUGFS_READ_FILE_OPS(tx_statistics); DEBUGFS_READ_WRITE_FILE_OPS(traffic_log); -- cgit v0.10.2 From 1940ce7317826c230055e826727acb891fb8bece Mon Sep 17 00:00:00 2001 From: Andrew Vasquez Date: Wed, 30 Mar 2011 11:46:16 -0700 Subject: [SCSI] qla2xxx: Display PortID information during FCP command-status handling. To provide a clearer translation of the command-status origin in relation to the midlayer's standard SCSI nexus. Signed-off-by: Andrew Vasquez Signed-off-by: Madhuranath Iyengar Signed-off-by: James Bottomley diff --git a/drivers/scsi/qla2xxx/qla_isr.c b/drivers/scsi/qla2xxx/qla_isr.c index 712518d..4db80d8 100644 --- a/drivers/scsi/qla2xxx/qla_isr.c +++ b/drivers/scsi/qla2xxx/qla_isr.c @@ -1794,12 +1794,13 @@ out: if (logit) DEBUG2(qla_printk(KERN_INFO, ha, "scsi(%ld:%d:%d) FCP command status: 0x%x-0x%x (0x%x) " - "oxid=0x%x cdb=%02x%02x%02x len=0x%x " + "portid=%02x%02x%02x oxid=0x%x cdb=%02x%02x%02x len=0x%x " "rsp_info=0x%x resid=0x%x fw_resid=0x%x\n", vha->host_no, cp->device->id, cp->device->lun, comp_status, scsi_status, - cp->result, ox_id, cp->cmnd[0], - cp->cmnd[1], cp->cmnd[2], scsi_bufflen(cp), rsp_info_len, - resid_len, fw_resid_len)); + cp->result, fcport->d_id.b.domain, fcport->d_id.b.area, + fcport->d_id.b.al_pa, ox_id, cp->cmnd[0], cp->cmnd[1], + cp->cmnd[2], scsi_bufflen(cp), rsp_info_len, resid_len, + fw_resid_len)); if (rsp->status_srb == NULL) qla2x00_sp_compl(ha, sp); -- cgit v0.10.2 From 80d79440ad98a660bd6d81e5c06e85581ff6ac46 Mon Sep 17 00:00:00 2001 From: Andrew Vasquez Date: Wed, 30 Mar 2011 11:46:17 -0700 Subject: [SCSI] qla2xxx: Correct calling contexts of qla2x00_mark_device_lost() in async paths. The respective done() functions are called from process context, so there's no reason to 'defer' the request. Signed-off-by: Andrew Vasquez Signed-off-by: Madhuranath Iyengar Signed-off-by: James Bottomley diff --git a/drivers/scsi/qla2xxx/qla_init.c b/drivers/scsi/qla2xxx/qla_init.c index 8575808..394d03d 100644 --- a/drivers/scsi/qla2xxx/qla_init.c +++ b/drivers/scsi/qla2xxx/qla_init.c @@ -397,7 +397,7 @@ qla2x00_async_login_done(struct scsi_qla_host *vha, fc_port_t *fcport, if (data[1] & QLA_LOGIO_LOGIN_RETRIED) set_bit(RELOGIN_NEEDED, &vha->dpc_flags); else - qla2x00_mark_device_lost(vha, fcport, 1, 1); + qla2x00_mark_device_lost(vha, fcport, 1, 0); break; case MBS_PORT_ID_USED: fcport->loop_id = data[1]; @@ -409,7 +409,7 @@ qla2x00_async_login_done(struct scsi_qla_host *vha, fc_port_t *fcport, rval = qla2x00_find_new_loop_id(vha, fcport); if (rval != QLA_SUCCESS) { fcport->flags &= ~FCF_ASYNC_SENT; - qla2x00_mark_device_lost(vha, fcport, 1, 1); + qla2x00_mark_device_lost(vha, fcport, 1, 0); break; } qla2x00_post_async_login_work(vha, fcport, NULL); @@ -441,7 +441,7 @@ qla2x00_async_adisc_done(struct scsi_qla_host *vha, fc_port_t *fcport, if (data[1] & QLA_LOGIO_LOGIN_RETRIED) set_bit(RELOGIN_NEEDED, &vha->dpc_flags); else - qla2x00_mark_device_lost(vha, fcport, 1, 1); + qla2x00_mark_device_lost(vha, fcport, 1, 0); return; } -- cgit v0.10.2 From f28a0a96130e7557d0cdcba0bcd394735eadfad8 Mon Sep 17 00:00:00 2001 From: Andrew Vasquez Date: Wed, 30 Mar 2011 11:46:18 -0700 Subject: [SCSI] qla2xxx: Check for a match before attempting to set FCP-priority information. Modifying qla24xx_get_fcp_prio() to return a 'found' status allows the driver to short circuit the 'set FCP-priority' call and reduce the amount of noise generated in the messages file: scsi(5): Unable to activate fcp priority, ret=0x102 scsi(5): Unable to activate fcp priority, ret=0x102 Also make qla24xx_get_fcp_prio() static. Signed-off-by: Andrew Vasquez Signed-off-by: Madhuranath Iyengar Signed-off-by: James Bottomley diff --git a/drivers/scsi/qla2xxx/qla_init.c b/drivers/scsi/qla2xxx/qla_init.c index 394d03d..f98cfac 100644 --- a/drivers/scsi/qla2xxx/qla_init.c +++ b/drivers/scsi/qla2xxx/qla_init.c @@ -5508,26 +5508,26 @@ qla81xx_update_fw_options(scsi_qla_host_t *vha) * * Return: * non-zero (if found) - * 0 (if not found) + * -1 (if not found) * * Context: * Kernel context */ -uint8_t +static int qla24xx_get_fcp_prio(scsi_qla_host_t *vha, fc_port_t *fcport) { int i, entries; uint8_t pid_match, wwn_match; - uint8_t priority; + int priority; uint32_t pid1, pid2; uint64_t wwn1, wwn2; struct qla_fcp_prio_entry *pri_entry; struct qla_hw_data *ha = vha->hw; if (!ha->fcp_prio_cfg || !ha->flags.fcp_prio_enabled) - return 0; + return -1; - priority = 0; + priority = -1; entries = ha->fcp_prio_cfg->num_entries; pri_entry = &ha->fcp_prio_cfg->entry[0]; @@ -5610,7 +5610,7 @@ int qla24xx_update_fcport_fcp_prio(scsi_qla_host_t *vha, fc_port_t *fcport) { int ret; - uint8_t priority; + int priority; uint16_t mb[5]; if (fcport->port_type != FCT_TARGET || @@ -5618,6 +5618,9 @@ qla24xx_update_fcport_fcp_prio(scsi_qla_host_t *vha, fc_port_t *fcport) return QLA_FUNCTION_FAILED; priority = qla24xx_get_fcp_prio(vha, fcport); + if (priority < 0) + return QLA_FUNCTION_FAILED; + ret = qla24xx_set_fcp_prio(vha, fcport->loop_id, priority, mb); if (ret == QLA_SUCCESS) fcport->fcp_prio = priority; -- cgit v0.10.2 From 3e8bb8410fafb36739beeb27e1c2fe76261a80dc Mon Sep 17 00:00:00 2001 From: Andrew Vasquez Date: Wed, 30 Mar 2011 11:46:19 -0700 Subject: [SCSI] qla2xxx: Remove extraneous setting of FCF_ASYNC_SENT during login-done completion. The bit is already set upon entry. Signed-off-by: Andrew Vasquez Signed-off-by: Madhuranath Iyengar Signed-off-by: James Bottomley diff --git a/drivers/scsi/qla2xxx/qla_init.c b/drivers/scsi/qla2xxx/qla_init.c index f98cfac..0f75fab 100644 --- a/drivers/scsi/qla2xxx/qla_init.c +++ b/drivers/scsi/qla2xxx/qla_init.c @@ -386,7 +386,6 @@ qla2x00_async_login_done(struct scsi_qla_host *vha, fc_port_t *fcport, switch (data[0]) { case MBS_COMMAND_COMPLETE: if (fcport->flags & FCF_FCP2_DEVICE) { - fcport->flags |= FCF_ASYNC_SENT; qla2x00_post_async_adisc_work(vha, fcport, data); break; } -- cgit v0.10.2 From a74ec14ffb17bb8033e7b41470019d30c8300707 Mon Sep 17 00:00:00 2001 From: Mike Hernandez Date: Wed, 30 Mar 2011 11:46:20 -0700 Subject: [SCSI] qla2xxx: Include request queue ID in the upper 16-bits of the I/O handle for Abort I/O IOCBs. The upper 16-bits of the handle for all I/O in multi-queue supported drivers carries the ID of the request queue it was submitted on. When using Abort I/O IOCB, the driver needs to also populate the upper 16-bits in the handle_to_abort field so the fw can correlate with the actual I/O. Signed-off-by: Mike Hernandez Signed-off-by: Madhuranath Iyengar Signed-off-by: James Bottomley diff --git a/drivers/scsi/qla2xxx/qla_mbx.c b/drivers/scsi/qla2xxx/qla_mbx.c index 3489339..1ef46ab 100644 --- a/drivers/scsi/qla2xxx/qla_mbx.c +++ b/drivers/scsi/qla2xxx/qla_mbx.c @@ -2362,7 +2362,7 @@ qla24xx_abort_command(srb_t *sp) abt->entry_count = 1; abt->handle = MAKE_HANDLE(req->id, abt->handle); abt->nport_handle = cpu_to_le16(fcport->loop_id); - abt->handle_to_abort = handle; + abt->handle_to_abort = MAKE_HANDLE(req->id, handle); abt->port_id[0] = fcport->d_id.b.al_pa; abt->port_id[1] = fcport->d_id.b.area; abt->port_id[2] = fcport->d_id.b.domain; -- cgit v0.10.2 From c8d6691b95eccce0033e925ba88b04eef4deac05 Mon Sep 17 00:00:00 2001 From: Andrew Vasquez Date: Wed, 30 Mar 2011 11:46:21 -0700 Subject: [SCSI] qla2xxx: Free firmware PCB on logout request. Signed-off-by: Andrew Vasquez Signed-off-by: Madhuranath Iyengar Signed-off-by: James Bottomley diff --git a/drivers/scsi/qla2xxx/qla_mbx.c b/drivers/scsi/qla2xxx/qla_mbx.c index 1ef46ab..260d1b3 100644 --- a/drivers/scsi/qla2xxx/qla_mbx.c +++ b/drivers/scsi/qla2xxx/qla_mbx.c @@ -1883,7 +1883,8 @@ qla24xx_fabric_logout(scsi_qla_host_t *vha, uint16_t loop_id, uint8_t domain, lg->handle = MAKE_HANDLE(req->id, lg->handle); lg->nport_handle = cpu_to_le16(loop_id); lg->control_flags = - __constant_cpu_to_le16(LCF_COMMAND_LOGO|LCF_IMPL_LOGO); + __constant_cpu_to_le16(LCF_COMMAND_LOGO|LCF_IMPL_LOGO| + LCF_FREE_NPORT); lg->port_id[0] = al_pa; lg->port_id[1] = area; lg->port_id[2] = domain; -- cgit v0.10.2 From 2fb0ee8a7f23e5f4df31f73da06731990ebb0044 Mon Sep 17 00:00:00 2001 From: Madhuranath Iyengar Date: Wed, 30 Mar 2011 11:46:22 -0700 Subject: [SCSI] qla2xxx: Update License file. Signed-off-by: Madhuranath Iyengar Signed-off-by: James Bottomley diff --git a/Documentation/scsi/LICENSE.qla2xxx b/Documentation/scsi/LICENSE.qla2xxx index 9e15b4f..19e7cd4 100644 --- a/Documentation/scsi/LICENSE.qla2xxx +++ b/Documentation/scsi/LICENSE.qla2xxx @@ -1,11 +1,11 @@ -Copyright (c) 2003-2005 QLogic Corporation -QLogic Linux Fibre Channel HBA Driver +Copyright (c) 2003-2011 QLogic Corporation +QLogic Linux/ESX Fibre Channel HBA Driver -This program includes a device driver for Linux 2.6 that may be +This program includes a device driver for Linux 2.6/ESX that may be distributed with QLogic hardware specific firmware binary file. You may modify and redistribute the device driver code under the -GNU General Public License as published by the Free Software -Foundation (version 2 or a later version). +GNU General Public License (a copy of which is attached hereto as +Exhibit A) published by the Free Software Foundation (version 2). You may redistribute the hardware specific firmware binary file under the following terms: @@ -43,3 +43,285 @@ OTHERWISE IN ANY INTELLECTUAL PROPERTY RIGHTS (PATENT, COPYRIGHT, TRADE SECRET, MASK WORK, OR OTHER PROPRIETARY RIGHT) EMBODIED IN ANY OTHER QLOGIC HARDWARE OR SOFTWARE EITHER SOLELY OR IN COMBINATION WITH THIS PROGRAM. + + +EXHIBIT A + + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Lesser General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. -- cgit v0.10.2 From 07e264b76d1db5794614ca3d726fdf1c0399dac0 Mon Sep 17 00:00:00 2001 From: Andrew Vasquez Date: Wed, 30 Mar 2011 11:46:23 -0700 Subject: [SCSI] qla2xxx: Update copyright banner. Signed-off-by: Andrew Vasquez Signed-off-by: Madhuranath Iyengar Signed-off-by: James Bottomley diff --git a/drivers/scsi/qla2xxx/qla_attr.c b/drivers/scsi/qla2xxx/qla_attr.c index d3e58d7..cee3eed 100644 --- a/drivers/scsi/qla2xxx/qla_attr.c +++ b/drivers/scsi/qla2xxx/qla_attr.c @@ -1,6 +1,6 @@ /* * QLogic Fibre Channel HBA Driver - * Copyright (c) 2003-2010 QLogic Corporation + * Copyright (c) 2003-2011 QLogic Corporation * * See LICENSE.qla2xxx for copyright and licensing details. */ diff --git a/drivers/scsi/qla2xxx/qla_bsg.c b/drivers/scsi/qla2xxx/qla_bsg.c index 903b058..8c10e2c 100644 --- a/drivers/scsi/qla2xxx/qla_bsg.c +++ b/drivers/scsi/qla2xxx/qla_bsg.c @@ -1,6 +1,6 @@ /* * QLogic Fibre Channel HBA Driver - * Copyright (c) 2003-2010 QLogic Corporation + * Copyright (c) 2003-2011 QLogic Corporation * * See LICENSE.qla2xxx for copyright and licensing details. */ diff --git a/drivers/scsi/qla2xxx/qla_bsg.h b/drivers/scsi/qla2xxx/qla_bsg.h index 074a999..0f0f54e 100644 --- a/drivers/scsi/qla2xxx/qla_bsg.h +++ b/drivers/scsi/qla2xxx/qla_bsg.h @@ -1,6 +1,6 @@ /* * QLogic Fibre Channel HBA Driver - * Copyright (c) 2003-2010 QLogic Corporation + * Copyright (c) 2003-2011 QLogic Corporation * * See LICENSE.qla2xxx for copyright and licensing details. */ diff --git a/drivers/scsi/qla2xxx/qla_dbg.c b/drivers/scsi/qla2xxx/qla_dbg.c index 0961411..c53719a 100644 --- a/drivers/scsi/qla2xxx/qla_dbg.c +++ b/drivers/scsi/qla2xxx/qla_dbg.c @@ -1,6 +1,6 @@ /* * QLogic Fibre Channel HBA Driver - * Copyright (c) 2003-2010 QLogic Corporation + * Copyright (c) 2003-2011 QLogic Corporation * * See LICENSE.qla2xxx for copyright and licensing details. */ diff --git a/drivers/scsi/qla2xxx/qla_dbg.h b/drivers/scsi/qla2xxx/qla_dbg.h index b74e6b5..9304145 100644 --- a/drivers/scsi/qla2xxx/qla_dbg.h +++ b/drivers/scsi/qla2xxx/qla_dbg.h @@ -1,6 +1,6 @@ /* * QLogic Fibre Channel HBA Driver - * Copyright (c) 2003-2010 QLogic Corporation + * Copyright (c) 2003-2011 QLogic Corporation * * See LICENSE.qla2xxx for copyright and licensing details. */ diff --git a/drivers/scsi/qla2xxx/qla_def.h b/drivers/scsi/qla2xxx/qla_def.h index ee20353..c2fc965 100644 --- a/drivers/scsi/qla2xxx/qla_def.h +++ b/drivers/scsi/qla2xxx/qla_def.h @@ -1,6 +1,6 @@ /* * QLogic Fibre Channel HBA Driver - * Copyright (c) 2003-2010 QLogic Corporation + * Copyright (c) 2003-2011 QLogic Corporation * * See LICENSE.qla2xxx for copyright and licensing details. */ diff --git a/drivers/scsi/qla2xxx/qla_dfs.c b/drivers/scsi/qla2xxx/qla_dfs.c index 6271353..a5a4e12 100644 --- a/drivers/scsi/qla2xxx/qla_dfs.c +++ b/drivers/scsi/qla2xxx/qla_dfs.c @@ -1,6 +1,6 @@ /* * QLogic Fibre Channel HBA Driver - * Copyright (c) 2003-2010 QLogic Corporation + * Copyright (c) 2003-2011 QLogic Corporation * * See LICENSE.qla2xxx for copyright and licensing details. */ diff --git a/drivers/scsi/qla2xxx/qla_fw.h b/drivers/scsi/qla2xxx/qla_fw.h index f5ba09c..73888ae 100644 --- a/drivers/scsi/qla2xxx/qla_fw.h +++ b/drivers/scsi/qla2xxx/qla_fw.h @@ -1,6 +1,6 @@ /* * QLogic Fibre Channel HBA Driver - * Copyright (c) 2003-2010 QLogic Corporation + * Copyright (c) 2003-2011 QLogic Corporation * * See LICENSE.qla2xxx for copyright and licensing details. */ diff --git a/drivers/scsi/qla2xxx/qla_gbl.h b/drivers/scsi/qla2xxx/qla_gbl.h index d48326e..d009c6f 100644 --- a/drivers/scsi/qla2xxx/qla_gbl.h +++ b/drivers/scsi/qla2xxx/qla_gbl.h @@ -1,6 +1,6 @@ /* * QLogic Fibre Channel HBA Driver - * Copyright (c) 2003-2010 QLogic Corporation + * Copyright (c) 2003-2011 QLogic Corporation * * See LICENSE.qla2xxx for copyright and licensing details. */ diff --git a/drivers/scsi/qla2xxx/qla_gs.c b/drivers/scsi/qla2xxx/qla_gs.c index 74a91b6..8cd9066 100644 --- a/drivers/scsi/qla2xxx/qla_gs.c +++ b/drivers/scsi/qla2xxx/qla_gs.c @@ -1,6 +1,6 @@ /* * QLogic Fibre Channel HBA Driver - * Copyright (c) 2003-2010 QLogic Corporation + * Copyright (c) 2003-2011 QLogic Corporation * * See LICENSE.qla2xxx for copyright and licensing details. */ diff --git a/drivers/scsi/qla2xxx/qla_init.c b/drivers/scsi/qla2xxx/qla_init.c index 0f75fab..2c9f47a 100644 --- a/drivers/scsi/qla2xxx/qla_init.c +++ b/drivers/scsi/qla2xxx/qla_init.c @@ -1,6 +1,6 @@ /* * QLogic Fibre Channel HBA Driver - * Copyright (c) 2003-2010 QLogic Corporation + * Copyright (c) 2003-2011 QLogic Corporation * * See LICENSE.qla2xxx for copyright and licensing details. */ diff --git a/drivers/scsi/qla2xxx/qla_inline.h b/drivers/scsi/qla2xxx/qla_inline.h index 48f97a9..4d17e70 100644 --- a/drivers/scsi/qla2xxx/qla_inline.h +++ b/drivers/scsi/qla2xxx/qla_inline.h @@ -1,6 +1,6 @@ /* * QLogic Fibre Channel HBA Driver - * Copyright (c) 2003-2010 QLogic Corporation + * Copyright (c) 2003-2011 QLogic Corporation * * See LICENSE.qla2xxx for copyright and licensing details. */ diff --git a/drivers/scsi/qla2xxx/qla_iocb.c b/drivers/scsi/qla2xxx/qla_iocb.c index d78d589..7bac3cd 100644 --- a/drivers/scsi/qla2xxx/qla_iocb.c +++ b/drivers/scsi/qla2xxx/qla_iocb.c @@ -1,6 +1,6 @@ /* * QLogic Fibre Channel HBA Driver - * Copyright (c) 2003-2010 QLogic Corporation + * Copyright (c) 2003-2011 QLogic Corporation * * See LICENSE.qla2xxx for copyright and licensing details. */ diff --git a/drivers/scsi/qla2xxx/qla_isr.c b/drivers/scsi/qla2xxx/qla_isr.c index 4db80d8..b614c8d 100644 --- a/drivers/scsi/qla2xxx/qla_isr.c +++ b/drivers/scsi/qla2xxx/qla_isr.c @@ -1,6 +1,6 @@ /* * QLogic Fibre Channel HBA Driver - * Copyright (c) 2003-2010 QLogic Corporation + * Copyright (c) 2003-2011 QLogic Corporation * * See LICENSE.qla2xxx for copyright and licensing details. */ diff --git a/drivers/scsi/qla2xxx/qla_mbx.c b/drivers/scsi/qla2xxx/qla_mbx.c index 260d1b3..32b6890 100644 --- a/drivers/scsi/qla2xxx/qla_mbx.c +++ b/drivers/scsi/qla2xxx/qla_mbx.c @@ -1,6 +1,6 @@ /* * QLogic Fibre Channel HBA Driver - * Copyright (c) 2003-2010 QLogic Corporation + * Copyright (c) 2003-2011 QLogic Corporation * * See LICENSE.qla2xxx for copyright and licensing details. */ diff --git a/drivers/scsi/qla2xxx/qla_mid.c b/drivers/scsi/qla2xxx/qla_mid.c index 2b69392..3082e2f 100644 --- a/drivers/scsi/qla2xxx/qla_mid.c +++ b/drivers/scsi/qla2xxx/qla_mid.c @@ -1,6 +1,6 @@ /* * QLogic Fibre Channel HBA Driver - * Copyright (c) 2003-2010 QLogic Corporation + * Copyright (c) 2003-2011 QLogic Corporation * * See LICENSE.qla2xxx for copyright and licensing details. */ diff --git a/drivers/scsi/qla2xxx/qla_nx.c b/drivers/scsi/qla2xxx/qla_nx.c index 455fe13..f81a870 100644 --- a/drivers/scsi/qla2xxx/qla_nx.c +++ b/drivers/scsi/qla2xxx/qla_nx.c @@ -1,6 +1,6 @@ /* * QLogic Fibre Channel HBA Driver - * Copyright (c) 2003-2010 QLogic Corporation + * Copyright (c) 2003-2011 QLogic Corporation * * See LICENSE.qla2xxx for copyright and licensing details. */ diff --git a/drivers/scsi/qla2xxx/qla_nx.h b/drivers/scsi/qla2xxx/qla_nx.h index ed5883f..8a21832 100644 --- a/drivers/scsi/qla2xxx/qla_nx.h +++ b/drivers/scsi/qla2xxx/qla_nx.h @@ -1,6 +1,6 @@ /* * QLogic Fibre Channel HBA Driver - * Copyright (c) 2003-2010 QLogic Corporation + * Copyright (c) 2003-2011 QLogic Corporation * * See LICENSE.qla2xxx for copyright and licensing details. */ diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c index aa77475..f040a2a 100644 --- a/drivers/scsi/qla2xxx/qla_os.c +++ b/drivers/scsi/qla2xxx/qla_os.c @@ -1,6 +1,6 @@ /* * QLogic Fibre Channel HBA Driver - * Copyright (c) 2003-2010 QLogic Corporation + * Copyright (c) 2003-2011 QLogic Corporation * * See LICENSE.qla2xxx for copyright and licensing details. */ diff --git a/drivers/scsi/qla2xxx/qla_settings.h b/drivers/scsi/qla2xxx/qla_settings.h index f0b2b99..d70f030 100644 --- a/drivers/scsi/qla2xxx/qla_settings.h +++ b/drivers/scsi/qla2xxx/qla_settings.h @@ -1,6 +1,6 @@ /* * QLogic Fibre Channel HBA Driver - * Copyright (c) 2003-2010 QLogic Corporation + * Copyright (c) 2003-2011 QLogic Corporation * * See LICENSE.qla2xxx for copyright and licensing details. */ diff --git a/drivers/scsi/qla2xxx/qla_sup.c b/drivers/scsi/qla2xxx/qla_sup.c index 2207062..6936476 100644 --- a/drivers/scsi/qla2xxx/qla_sup.c +++ b/drivers/scsi/qla2xxx/qla_sup.c @@ -1,6 +1,6 @@ /* * QLogic Fibre Channel HBA Driver - * Copyright (c) 2003-2010 QLogic Corporation + * Copyright (c) 2003-2011 QLogic Corporation * * See LICENSE.qla2xxx for copyright and licensing details. */ diff --git a/drivers/scsi/qla2xxx/qla_version.h b/drivers/scsi/qla2xxx/qla_version.h index 3a260c3..86f589c 100644 --- a/drivers/scsi/qla2xxx/qla_version.h +++ b/drivers/scsi/qla2xxx/qla_version.h @@ -1,6 +1,6 @@ /* * QLogic Fibre Channel HBA Driver - * Copyright (c) 2003-2010 QLogic Corporation + * Copyright (c) 2003-2011 QLogic Corporation * * See LICENSE.qla2xxx for copyright and licensing details. */ -- cgit v0.10.2 From 02be22155689d4e3a8bd04243547262b2915f4e3 Mon Sep 17 00:00:00 2001 From: Giridhar Malavali Date: Wed, 30 Mar 2011 11:46:24 -0700 Subject: [SCSI] qla2xxx: Updated the reset sequence for ISP82xx. Signed-off-by: Giridhar Malavali Signed-off-by: Madhuranath Iyengar Signed-off-by: James Bottomley diff --git a/drivers/scsi/qla2xxx/qla_nx.c b/drivers/scsi/qla2xxx/qla_nx.c index f81a870..794c164 100644 --- a/drivers/scsi/qla2xxx/qla_nx.c +++ b/drivers/scsi/qla2xxx/qla_nx.c @@ -1081,12 +1081,26 @@ qla82xx_pinit_from_rom(scsi_qla_host_t *vha) /* Halt all the indiviual PEGs and other blocks of the ISP */ qla82xx_rom_lock(ha); - /* mask all niu interrupts */ + /* disable all I2Q */ + qla82xx_wr_32(ha, QLA82XX_CRB_I2Q + 0x10, 0x0); + qla82xx_wr_32(ha, QLA82XX_CRB_I2Q + 0x14, 0x0); + qla82xx_wr_32(ha, QLA82XX_CRB_I2Q + 0x18, 0x0); + qla82xx_wr_32(ha, QLA82XX_CRB_I2Q + 0x1c, 0x0); + qla82xx_wr_32(ha, QLA82XX_CRB_I2Q + 0x20, 0x0); + qla82xx_wr_32(ha, QLA82XX_CRB_I2Q + 0x24, 0x0); + + /* disable all niu interrupts */ qla82xx_wr_32(ha, QLA82XX_CRB_NIU + 0x40, 0xff); /* disable xge rx/tx */ qla82xx_wr_32(ha, QLA82XX_CRB_NIU + 0x70000, 0x00); /* disable xg1 rx/tx */ qla82xx_wr_32(ha, QLA82XX_CRB_NIU + 0x80000, 0x00); + /* disable sideband mac */ + qla82xx_wr_32(ha, QLA82XX_CRB_NIU + 0x90000, 0x00); + /* disable ap0 mac */ + qla82xx_wr_32(ha, QLA82XX_CRB_NIU + 0xa0000, 0x00); + /* disable ap1 mac */ + qla82xx_wr_32(ha, QLA82XX_CRB_NIU + 0xb0000, 0x00); /* halt sre */ val = qla82xx_rd_32(ha, QLA82XX_CRB_SRE + 0x1000); @@ -1101,6 +1115,7 @@ qla82xx_pinit_from_rom(scsi_qla_host_t *vha) qla82xx_wr_32(ha, QLA82XX_CRB_TIMER + 0x10, 0x0); qla82xx_wr_32(ha, QLA82XX_CRB_TIMER + 0x18, 0x0); qla82xx_wr_32(ha, QLA82XX_CRB_TIMER + 0x100, 0x0); + qla82xx_wr_32(ha, QLA82XX_CRB_TIMER + 0x200, 0x0); /* halt pegs */ qla82xx_wr_32(ha, QLA82XX_CRB_PEG_NET_0 + 0x3c, 1); @@ -1108,9 +1123,9 @@ qla82xx_pinit_from_rom(scsi_qla_host_t *vha) qla82xx_wr_32(ha, QLA82XX_CRB_PEG_NET_2 + 0x3c, 1); qla82xx_wr_32(ha, QLA82XX_CRB_PEG_NET_3 + 0x3c, 1); qla82xx_wr_32(ha, QLA82XX_CRB_PEG_NET_4 + 0x3c, 1); + msleep(20); /* big hammer */ - msleep(1000); if (test_bit(ABORT_ISP_ACTIVE, &vha->dpc_flags)) /* don't reset CAM block on reset */ qla82xx_wr_32(ha, QLA82XX_ROMUSB_GLB_SW_RESET, 0xfeffffff); -- cgit v0.10.2 From aee3dbcdd1f8f7dea4500824ae1ac9cfbbe71700 Mon Sep 17 00:00:00 2001 From: Giridhar Malavali Date: Wed, 30 Mar 2011 11:46:25 -0700 Subject: [SCSI] qla2xxx: Remove extra call to qla82xx_check_fw_alive(). The stanadlone call to qla82xx_check_fw_alive() in qla82xx_watchdog() is a typo, so remove it. Signed-off-by: Giridhar Malavali Signed-off-by: Madhuranath Iyengar Signed-off-by: James Bottomley diff --git a/drivers/scsi/qla2xxx/qla_nx.c b/drivers/scsi/qla2xxx/qla_nx.c index 794c164..9618d6d 100644 --- a/drivers/scsi/qla2xxx/qla_nx.c +++ b/drivers/scsi/qla2xxx/qla_nx.c @@ -3647,7 +3647,6 @@ void qla82xx_watchdog(scsi_qla_host_t *vha) set_bit(ISP_QUIESCE_NEEDED, &vha->dpc_flags); qla2xxx_wake_dpc(vha); } else { - qla82xx_check_fw_alive(vha); if (qla82xx_check_fw_alive(vha)) { halt_status = qla82xx_rd_32(ha, QLA82XX_PEG_HALT_STATUS1); -- cgit v0.10.2 From 8f7daead3c7861f9d0caa55269773136ab443b41 Mon Sep 17 00:00:00 2001 From: Giridhar Malavali Date: Wed, 30 Mar 2011 11:46:26 -0700 Subject: [SCSI] qla2xxx: Perform FCoE context reset before trying adapter reset for ISP82xx. For certain failures, try to recover first by doing FCoE context reset before attempting big hammer approach(adpater reset). Signed-off-by: Giridhar Malavali Signed-off-by: Madhuranath Iyengar Signed-off-by: James Bottomley diff --git a/drivers/scsi/qla2xxx/qla_isr.c b/drivers/scsi/qla2xxx/qla_isr.c index b614c8d..9c0f0e3 100644 --- a/drivers/scsi/qla2xxx/qla_isr.c +++ b/drivers/scsi/qla2xxx/qla_isr.c @@ -843,7 +843,10 @@ qla2x00_process_completed_request(struct scsi_qla_host *vha, qla_printk(KERN_WARNING, ha, "Invalid SCSI completion handle %d.\n", index); - set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags); + if (IS_QLA82XX(ha)) + set_bit(FCOE_CTX_RESET_NEEDED, &vha->dpc_flags); + else + set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags); return; } @@ -861,7 +864,10 @@ qla2x00_process_completed_request(struct scsi_qla_host *vha, qla_printk(KERN_WARNING, ha, "Invalid ISP SCSI completion handle\n"); - set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags); + if (IS_QLA82XX(ha)) + set_bit(FCOE_CTX_RESET_NEEDED, &vha->dpc_flags); + else + set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags); } } @@ -878,7 +884,10 @@ qla2x00_get_sp_from_handle(scsi_qla_host_t *vha, const char *func, if (index >= MAX_OUTSTANDING_COMMANDS) { qla_printk(KERN_WARNING, ha, "%s: Invalid completion handle (%x).\n", func, index); - set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags); + if (IS_QLA82XX(ha)) + set_bit(FCOE_CTX_RESET_NEEDED, &vha->dpc_flags); + else + set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags); goto done; } sp = req->outstanding_cmds[index]; @@ -1564,7 +1573,10 @@ qla2x00_status_entry(scsi_qla_host_t *vha, struct rsp_que *rsp, void *pkt) "scsi(%ld): Invalid status handle (0x%x).\n", vha->host_no, sts->handle); - set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags); + if (IS_QLA82XX(ha)) + set_bit(FCOE_CTX_RESET_NEEDED, &vha->dpc_flags); + else + set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags); qla2xxx_wake_dpc(vha); return; } @@ -1909,13 +1921,17 @@ qla2x00_error_entry(scsi_qla_host_t *vha, struct rsp_que *rsp, sts_entry_t *pkt) qla2x00_sp_compl(ha, sp); } else if (pkt->entry_type == COMMAND_A64_TYPE || pkt->entry_type == - COMMAND_TYPE || pkt->entry_type == COMMAND_TYPE_7) { + COMMAND_TYPE || pkt->entry_type == COMMAND_TYPE_7 + || pkt->entry_type == COMMAND_TYPE_6) { DEBUG2(printk("scsi(%ld): Error entry - invalid handle\n", - vha->host_no)); + vha->host_no)); qla_printk(KERN_WARNING, ha, - "Error entry - invalid handle\n"); + "Error entry - invalid handle\n"); - set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags); + if (IS_QLA82XX(ha)) + set_bit(FCOE_CTX_RESET_NEEDED, &vha->dpc_flags); + else + set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags); qla2xxx_wake_dpc(vha); } } diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c index f040a2a..2f039e0 100644 --- a/drivers/scsi/qla2xxx/qla_os.c +++ b/drivers/scsi/qla2xxx/qla_os.c @@ -3612,7 +3612,8 @@ qla2x00_timer(scsi_qla_host_t *vha) /* Loop down handler. */ if (atomic_read(&vha->loop_down_timer) > 0 && - !(test_bit(ABORT_ISP_ACTIVE, &vha->dpc_flags)) + !(test_bit(ABORT_ISP_ACTIVE, &vha->dpc_flags)) && + !(test_bit(FCOE_CTX_RESET_NEEDED, &vha->dpc_flags)) && vha->flags.online) { if (atomic_read(&vha->loop_down_timer) == @@ -3648,7 +3649,11 @@ qla2x00_timer(scsi_qla_host_t *vha) if (!(sfcp->flags & FCF_FCP2_DEVICE)) continue; - set_bit(ISP_ABORT_NEEDED, + if (IS_QLA82XX(ha)) + set_bit(FCOE_CTX_RESET_NEEDED, + &vha->dpc_flags); + else + set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags); break; } @@ -3667,7 +3672,12 @@ qla2x00_timer(scsi_qla_host_t *vha) qla_printk(KERN_WARNING, ha, "Loop down - aborting ISP.\n"); - set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags); + if (IS_QLA82XX(ha)) + set_bit(FCOE_CTX_RESET_NEEDED, + &vha->dpc_flags); + else + set_bit(ISP_ABORT_NEEDED, + &vha->dpc_flags); } } DEBUG3(printk("scsi(%ld): Loop Down - seconds remaining %d\n", -- cgit v0.10.2 From 03bcfb57c098016e318e2672028f93ec072a2333 Mon Sep 17 00:00:00 2001 From: Joe Carnuccio Date: Wed, 30 Mar 2011 11:46:27 -0700 Subject: [SCSI] qla2xxx: Add test for valid loop id to qla2x00_relogin(). If fabric device has invalid loop id (FC_NO_LOOP_ID) then call qla2x00_find_new_loop_id() to attempt to obtain valid loop id. Signed-off-by: Joe Carnuccio Signed-off-by: Madhuranath Iyengar Signed-off-by: James Bottomley diff --git a/drivers/scsi/qla2xxx/qla_gbl.h b/drivers/scsi/qla2xxx/qla_gbl.h index d009c6f..cd646ca 100644 --- a/drivers/scsi/qla2xxx/qla_gbl.h +++ b/drivers/scsi/qla2xxx/qla_gbl.h @@ -39,6 +39,8 @@ extern int qla81xx_load_risc(scsi_qla_host_t *, uint32_t *); extern int qla2x00_perform_loop_resync(scsi_qla_host_t *); extern int qla2x00_loop_resync(scsi_qla_host_t *); +extern int qla2x00_find_new_loop_id(scsi_qla_host_t *, fc_port_t *); + extern int qla2x00_fabric_login(scsi_qla_host_t *, fc_port_t *, uint16_t *); extern int qla2x00_local_device_login(scsi_qla_host_t *, fc_port_t *); diff --git a/drivers/scsi/qla2xxx/qla_init.c b/drivers/scsi/qla2xxx/qla_init.c index 2c9f47a..234c1c2 100644 --- a/drivers/scsi/qla2xxx/qla_init.c +++ b/drivers/scsi/qla2xxx/qla_init.c @@ -35,8 +35,6 @@ static int qla2x00_fabric_dev_login(scsi_qla_host_t *, fc_port_t *, static int qla2x00_restart_isp(scsi_qla_host_t *); -static int qla2x00_find_new_loop_id(scsi_qla_host_t *, fc_port_t *); - static struct qla_chip_state_84xx *qla84xx_get_chip(struct scsi_qla_host *); static int qla84xx_init_chip(scsi_qla_host_t *); static int qla25xx_init_queues(struct qla_hw_data *); @@ -3390,7 +3388,7 @@ qla2x00_find_all_fabric_devs(scsi_qla_host_t *vha, * Context: * Kernel context. */ -static int +int qla2x00_find_new_loop_id(scsi_qla_host_t *vha, fc_port_t *dev) { int rval; diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c index 2f039e0..d1b29dc 100644 --- a/drivers/scsi/qla2xxx/qla_os.c +++ b/drivers/scsi/qla2xxx/qla_os.c @@ -3214,6 +3214,17 @@ void qla2x00_relogin(struct scsi_qla_host *vha) fcport->d_id.b.area, fcport->d_id.b.al_pa); + if (fcport->loop_id == FC_NO_LOOP_ID) { + fcport->loop_id = next_loopid = + ha->min_external_loopid; + status = qla2x00_find_new_loop_id( + vha, fcport); + if (status != QLA_SUCCESS) { + /* Ran out of IDs to use */ + break; + } + } + if (IS_ALOGIO_CAPABLE(ha)) { fcport->flags |= FCF_ASYNC_SENT; data[0] = 0; -- cgit v0.10.2 From 0e8edb0303a97717a9518428329adad3d6fe3b4d Mon Sep 17 00:00:00 2001 From: Giridhar Malavali Date: Wed, 30 Mar 2011 11:46:28 -0700 Subject: [SCSI] qla2xxx: Display hardware/firmware registers to get more information about the error for ISP82xx. Signed-off-by: Giridhar Malavali Signed-off-by: Madhuranath Iyengar Signed-off-by: James Bottomley diff --git a/drivers/scsi/qla2xxx/qla_nx.c b/drivers/scsi/qla2xxx/qla_nx.c index 9618d6d..81472e43 100644 --- a/drivers/scsi/qla2xxx/qla_nx.c +++ b/drivers/scsi/qla2xxx/qla_nx.c @@ -3650,6 +3650,24 @@ void qla82xx_watchdog(scsi_qla_host_t *vha) if (qla82xx_check_fw_alive(vha)) { halt_status = qla82xx_rd_32(ha, QLA82XX_PEG_HALT_STATUS1); + qla_printk(KERN_INFO, ha, + "scsi(%ld): %s, Dumping hw/fw registers:\n " + " PEG_HALT_STATUS1: 0x%x, PEG_HALT_STATUS2: 0x%x,\n " + " PEG_NET_0_PC: 0x%x, PEG_NET_1_PC: 0x%x,\n " + " PEG_NET_2_PC: 0x%x, PEG_NET_3_PC: 0x%x,\n " + " PEG_NET_4_PC: 0x%x\n", + vha->host_no, __func__, halt_status, + qla82xx_rd_32(ha, QLA82XX_PEG_HALT_STATUS2), + qla82xx_rd_32(ha, + QLA82XX_CRB_PEG_NET_0 + 0x3c), + qla82xx_rd_32(ha, + QLA82XX_CRB_PEG_NET_1 + 0x3c), + qla82xx_rd_32(ha, + QLA82XX_CRB_PEG_NET_2 + 0x3c), + qla82xx_rd_32(ha, + QLA82XX_CRB_PEG_NET_3 + 0x3c), + qla82xx_rd_32(ha, + QLA82XX_CRB_PEG_NET_4 + 0x3c)); if (halt_status & HALT_STATUS_UNRECOVERABLE) { set_bit(ISP_UNRECOVERABLE, &vha->dpc_flags); -- cgit v0.10.2 From ed0de87ce6be92bd84858ad496ffaf60344495a3 Mon Sep 17 00:00:00 2001 From: Giridhar Malavali Date: Wed, 30 Mar 2011 11:46:29 -0700 Subject: [SCSI] qla2xxx: Add the ql2xdontresethba module_param. Also, change the ISP82xx code to only reset if this module_param is set and reset is intended via the QLA82XX_DEV_NEED_RESET case. Signed-off-by: Giridhar Malavali Signed-off-by: Madhuranath Iyengar Signed-off-by: James Bottomley diff --git a/drivers/scsi/qla2xxx/qla_gbl.h b/drivers/scsi/qla2xxx/qla_gbl.h index cd646ca..fbb4b8f 100644 --- a/drivers/scsi/qla2xxx/qla_gbl.h +++ b/drivers/scsi/qla2xxx/qla_gbl.h @@ -102,6 +102,7 @@ extern int ql2xgffidenable; extern int ql2xenabledif; extern int ql2xenablehba_err_chk; extern int ql2xtargetreset; +extern int ql2xdontresethba; extern int qla2x00_loop_reset(scsi_qla_host_t *); extern void qla2x00_abort_all_cmds(scsi_qla_host_t *, int); diff --git a/drivers/scsi/qla2xxx/qla_nx.c b/drivers/scsi/qla2xxx/qla_nx.c index 81472e43..a62856e 100644 --- a/drivers/scsi/qla2xxx/qla_nx.c +++ b/drivers/scsi/qla2xxx/qla_nx.c @@ -3585,6 +3585,7 @@ qla82xx_device_state_handler(scsi_qla_host_t *vha) qla82xx_idc_lock(ha); break; case QLA82XX_DEV_NEED_RESET: + if (!ql2xdontresethba) qla82xx_need_reset_handler(vha); dev_init_timeout = jiffies + (ha->nx_dev_init_timeout * HZ); diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c index d1b29dc..8791642 100644 --- a/drivers/scsi/qla2xxx/qla_os.c +++ b/drivers/scsi/qla2xxx/qla_os.c @@ -164,6 +164,14 @@ module_param(ql2xasynctmfenable, int, S_IRUGO); MODULE_PARM_DESC(ql2xasynctmfenable, "Enables issue of TM IOCBs asynchronously via IOCB mechanism" "Default is 0 - Issue TM IOCBs via mailbox mechanism."); + +int ql2xdontresethba; +module_param(ql2xdontresethba, int, S_IRUGO); +MODULE_PARM_DESC(ql2xdontresethba, + "Option to specify reset behaviour\n" + " 0 (Default) -- Reset on failure.\n" + " 1 -- Do not reset on failure.\n"); + /* * SCSI host template entry points */ -- cgit v0.10.2 From 92dbf273921eb53a9d5b760a8f3b32eefd776b1b Mon Sep 17 00:00:00 2001 From: Giridhar Malavali Date: Wed, 30 Mar 2011 11:46:30 -0700 Subject: [SCSI] qla2xxx: Limit the logs in case device state does not change for ISP82xx. Signed-off-by: Giridhar Malavali Signed-off-by: Madhuranath Iyengar Signed-off-by: James Bottomley diff --git a/drivers/scsi/qla2xxx/qla_nx.c b/drivers/scsi/qla2xxx/qla_nx.c index a62856e..acd1ad3 100644 --- a/drivers/scsi/qla2xxx/qla_nx.c +++ b/drivers/scsi/qla2xxx/qla_nx.c @@ -3543,15 +3543,18 @@ int qla82xx_device_state_handler(scsi_qla_host_t *vha) { uint32_t dev_state; + uint32_t old_dev_state; int rval = QLA_SUCCESS; unsigned long dev_init_timeout; struct qla_hw_data *ha = vha->hw; + int loopcount = 0; qla82xx_idc_lock(ha); if (!vha->flags.init_done) qla82xx_set_drv_active(vha); dev_state = qla82xx_rd_32(ha, QLA82XX_CRB_DEV_STATE); + old_dev_state = dev_state; qla_printk(KERN_INFO, ha, "1:Device state is 0x%x = %s\n", dev_state, dev_state < MAX_STATES ? qdev_state[dev_state] : "Unknown"); @@ -3568,10 +3571,16 @@ qla82xx_device_state_handler(scsi_qla_host_t *vha) break; } dev_state = qla82xx_rd_32(ha, QLA82XX_CRB_DEV_STATE); - qla_printk(KERN_INFO, ha, - "2:Device state is 0x%x = %s\n", dev_state, - dev_state < MAX_STATES ? - qdev_state[dev_state] : "Unknown"); + if (old_dev_state != dev_state) { + loopcount = 0; + old_dev_state = dev_state; + } + if (loopcount < 5) { + qla_printk(KERN_INFO, ha, + "2:Device state is 0x%x = %s\n", dev_state, + dev_state < MAX_STATES ? + qdev_state[dev_state] : "Unknown"); + } switch (dev_state) { case QLA82XX_DEV_READY: @@ -3620,6 +3629,7 @@ qla82xx_device_state_handler(scsi_qla_host_t *vha) msleep(1000); qla82xx_idc_lock(ha); } + loopcount++; } exit: qla82xx_idc_unlock(ha); -- cgit v0.10.2 From a4f92a32a0fb827f7bd40c69f021cf57d3dc4249 Mon Sep 17 00:00:00 2001 From: Andrew Vasquez Date: Wed, 30 Mar 2011 11:46:31 -0700 Subject: [SCSI] qla2xxx: Verify login-state has transitioned to PRLI-completed. Before driver's own internal state is marked as PLOGI/PRLI complete. This additional check closes a window seen with dual-personality initiator/target devices where a driver's PLOGI/PRLI request occurs within the window after the target's PLOGI request has completed, but prior to the target's PRLI arriving and processed by the firmware. Without this additional check, the firmware will return port-information stating that the port neither supports target nor initiator functions, causing the driver to register the rport prematurely to the FC-transport without the proper 'roles' being set. Signed-off-by: Andrew Vasquez Signed-off-by: Giridhar Malavali Signed-off-by: Madhuranath Iyengar Signed-off-by: James Bottomley diff --git a/drivers/scsi/qla2xxx/qla_init.c b/drivers/scsi/qla2xxx/qla_init.c index 234c1c2..d31ac9b 100644 --- a/drivers/scsi/qla2xxx/qla_init.c +++ b/drivers/scsi/qla2xxx/qla_init.c @@ -383,6 +383,17 @@ qla2x00_async_login_done(struct scsi_qla_host *vha, fc_port_t *fcport, switch (data[0]) { case MBS_COMMAND_COMPLETE: + /* + * Driver must validate login state - If PRLI not complete, + * force a relogin attempt via implicit LOGO, PLOGI, and PRLI + * requests. + */ + rval = qla2x00_get_port_database(vha, fcport, 0); + if (rval != QLA_SUCCESS) { + qla2x00_post_async_logout_work(vha, fcport, NULL); + qla2x00_post_async_login_work(vha, fcport, NULL); + break; + } if (fcport->flags & FCF_FCP2_DEVICE) { qla2x00_post_async_adisc_work(vha, fcport, data); break; diff --git a/drivers/scsi/qla2xxx/qla_mbx.c b/drivers/scsi/qla2xxx/qla_mbx.c index 32b6890..975aeaa 100644 --- a/drivers/scsi/qla2xxx/qla_mbx.c +++ b/drivers/scsi/qla2xxx/qla_mbx.c @@ -1261,11 +1261,12 @@ qla2x00_get_port_database(scsi_qla_host_t *vha, fc_port_t *fcport, uint8_t opt) /* Check for logged in state. */ if (pd24->current_login_state != PDS_PRLI_COMPLETE && pd24->last_login_state != PDS_PRLI_COMPLETE) { - DEBUG2(printk("%s(%ld): Unable to verify " - "login-state (%x/%x) for loop_id %x\n", - __func__, vha->host_no, - pd24->current_login_state, - pd24->last_login_state, fcport->loop_id)); + DEBUG2(qla_printk(KERN_WARNING, ha, + "scsi(%ld): Unable to verify login-state (%x/%x) " + " - portid=%02x%02x%02x.\n", vha->host_no, + pd24->current_login_state, pd24->last_login_state, + fcport->d_id.b.domain, fcport->d_id.b.area, + fcport->d_id.b.al_pa)); rval = QLA_FUNCTION_FAILED; goto gpd_error_out; } @@ -1289,6 +1290,12 @@ qla2x00_get_port_database(scsi_qla_host_t *vha, fc_port_t *fcport, uint8_t opt) /* Check for logged in state. */ if (pd->master_state != PD_STATE_PORT_LOGGED_IN && pd->slave_state != PD_STATE_PORT_LOGGED_IN) { + DEBUG2(qla_printk(KERN_WARNING, ha, + "scsi(%ld): Unable to verify login-state (%x/%x) " + " - portid=%02x%02x%02x.\n", vha->host_no, + pd->master_state, pd->slave_state, + fcport->d_id.b.domain, fcport->d_id.b.area, + fcport->d_id.b.al_pa)); rval = QLA_FUNCTION_FAILED; goto gpd_error_out; } -- cgit v0.10.2 From ec426e106c410b000ac590b6e776d5a6cd9bccd9 Mon Sep 17 00:00:00 2001 From: Chad Dupuis Date: Wed, 30 Mar 2011 11:46:32 -0700 Subject: [SCSI] qla2xxx: Log fcport state transitions when debug messages are enabled. Add the inline function qla2x00_set_port_state() so that when a fcport state transition happens we can log the state transition if debug messages are enabled. Signed-off-by: Chad Dupuis Signed-off-by: Madhuranath Iyengar Signed-off-by: James Bottomley diff --git a/drivers/scsi/qla2xxx/qla_attr.c b/drivers/scsi/qla2xxx/qla_attr.c index cee3eed..75faf48 100644 --- a/drivers/scsi/qla2xxx/qla_attr.c +++ b/drivers/scsi/qla2xxx/qla_attr.c @@ -1568,7 +1568,7 @@ qla2x00_dev_loss_tmo_callbk(struct fc_rport *rport) /* Now that the rport has been deleted, set the fcport state to FCS_DEVICE_DEAD */ - atomic_set(&fcport->state, FCS_DEVICE_DEAD); + qla2x00_set_fcport_state(fcport, FCS_DEVICE_DEAD); /* * Transport has effectively 'deleted' the rport, clear diff --git a/drivers/scsi/qla2xxx/qla_def.h b/drivers/scsi/qla2xxx/qla_def.h index c2fc965..cc5a792 100644 --- a/drivers/scsi/qla2xxx/qla_def.h +++ b/drivers/scsi/qla2xxx/qla_def.h @@ -1717,6 +1717,14 @@ typedef struct fc_port { #define FCS_DEVICE_LOST 3 #define FCS_ONLINE 4 +static const char * const port_state_str[] = { + "Unknown", + "UNCONFIGURED", + "DEAD", + "LOST", + "ONLINE" +}; + /* * FC port flags. */ diff --git a/drivers/scsi/qla2xxx/qla_init.c b/drivers/scsi/qla2xxx/qla_init.c index d31ac9b..24d2d19 100644 --- a/drivers/scsi/qla2xxx/qla_init.c +++ b/drivers/scsi/qla2xxx/qla_init.c @@ -2544,7 +2544,7 @@ qla2x00_alloc_fcport(scsi_qla_host_t *vha, gfp_t flags) fcport->vp_idx = vha->vp_idx; fcport->port_type = FCT_UNKNOWN; fcport->loop_id = FC_NO_LOOP_ID; - atomic_set(&fcport->state, FCS_UNCONFIGURED); + qla2x00_set_fcport_state(fcport, FCS_UNCONFIGURED); fcport->supported_classes = FC_COS_UNSPECIFIED; return fcport; @@ -2730,7 +2730,7 @@ qla2x00_configure_local_loop(scsi_qla_host_t *vha) "loop_id=0x%04x\n", vha->host_no, fcport->loop_id)); - atomic_set(&fcport->state, FCS_DEVICE_LOST); + qla2x00_set_fcport_state(fcport, FCS_DEVICE_LOST); } } @@ -2942,7 +2942,7 @@ qla2x00_update_fcport(scsi_qla_host_t *vha, fc_port_t *fcport) qla2x00_iidma_fcport(vha, fcport); qla24xx_update_fcport_fcp_prio(vha, fcport); qla2x00_reg_remote_port(vha, fcport); - atomic_set(&fcport->state, FCS_ONLINE); + qla2x00_set_fcport_state(fcport, FCS_ONLINE); } /* diff --git a/drivers/scsi/qla2xxx/qla_inline.h b/drivers/scsi/qla2xxx/qla_inline.h index 4d17e70..4c8167e 100644 --- a/drivers/scsi/qla2xxx/qla_inline.h +++ b/drivers/scsi/qla2xxx/qla_inline.h @@ -83,3 +83,22 @@ qla2x00_clean_dsd_pool(struct qla_hw_data *ha, srb_t *sp) } INIT_LIST_HEAD(&((struct crc_context *)sp->ctx)->dsd_list); } + +static inline void +qla2x00_set_fcport_state(fc_port_t *fcport, int state) +{ + int old_state; + + old_state = atomic_read(&fcport->state); + atomic_set(&fcport->state, state); + + /* Don't print state transitions during initial allocation of fcport */ + if (old_state && old_state != state) { + DEBUG(qla_printk(KERN_WARNING, fcport->vha->hw, + "scsi(%ld): FCPort state transitioned from %s to %s - " + "portid=%02x%02x%02x.\n", fcport->vha->host_no, + port_state_str[old_state], port_state_str[state], + fcport->d_id.b.domain, fcport->d_id.b.area, + fcport->d_id.b.al_pa)); + } +} diff --git a/drivers/scsi/qla2xxx/qla_mid.c b/drivers/scsi/qla2xxx/qla_mid.c index 3082e2f..e34d7dd 100644 --- a/drivers/scsi/qla2xxx/qla_mid.c +++ b/drivers/scsi/qla2xxx/qla_mid.c @@ -136,7 +136,7 @@ qla2x00_mark_vp_devices_dead(scsi_qla_host_t *vha) vha->host_no, fcport->loop_id, fcport->vp_idx)); qla2x00_mark_device_lost(vha, fcport, 0, 0); - atomic_set(&fcport->state, FCS_UNCONFIGURED); + qla2x00_set_fcport_state(fcport, FCS_UNCONFIGURED); } } diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c index 8791642..0ca6664 100644 --- a/drivers/scsi/qla2xxx/qla_os.c +++ b/drivers/scsi/qla2xxx/qla_os.c @@ -2552,7 +2552,7 @@ void qla2x00_mark_device_lost(scsi_qla_host_t *vha, fc_port_t *fcport, { if (atomic_read(&fcport->state) == FCS_ONLINE && vha->vp_idx == fcport->vp_idx) { - atomic_set(&fcport->state, FCS_DEVICE_LOST); + qla2x00_set_fcport_state(fcport, FCS_DEVICE_LOST); qla2x00_schedule_rport_del(vha, fcport, defer); } /* @@ -2560,7 +2560,7 @@ void qla2x00_mark_device_lost(scsi_qla_host_t *vha, fc_port_t *fcport, * port but do the retries. */ if (atomic_read(&fcport->state) != FCS_DEVICE_DEAD) - atomic_set(&fcport->state, FCS_DEVICE_LOST); + qla2x00_set_fcport_state(fcport, FCS_DEVICE_LOST); if (!do_login) return; @@ -2615,7 +2615,7 @@ qla2x00_mark_all_devices_lost(scsi_qla_host_t *vha, int defer) if (atomic_read(&fcport->state) == FCS_DEVICE_DEAD) continue; if (atomic_read(&fcport->state) == FCS_ONLINE) { - atomic_set(&fcport->state, FCS_DEVICE_LOST); + qla2x00_set_fcport_state(fcport, FCS_DEVICE_LOST); if (defer) qla2x00_schedule_rport_del(vha, fcport, defer); else if (vha->vp_idx == fcport->vp_idx) -- cgit v0.10.2 From c9c2a14047447251838334045e7af99b3b15f725 Mon Sep 17 00:00:00 2001 From: Madhuranath Iyengar Date: Wed, 30 Mar 2011 11:46:33 -0700 Subject: [SCSI] qla2xxx: Update version number to 8.03.07.03-k. A minor change in the versioning. We'll be attaching the "-k" in the end. Signed-off-by: Madhuranath Iyengar Signed-off-by: James Bottomley diff --git a/drivers/scsi/qla2xxx/qla_version.h b/drivers/scsi/qla2xxx/qla_version.h index 86f589c..062c97b 100644 --- a/drivers/scsi/qla2xxx/qla_version.h +++ b/drivers/scsi/qla2xxx/qla_version.h @@ -7,9 +7,9 @@ /* * Driver version */ -#define QLA2XXX_VERSION "8.03.07.00" +#define QLA2XXX_VERSION "8.03.07.03-k" #define QLA_DRIVER_MAJOR_VER 8 #define QLA_DRIVER_MINOR_VER 3 #define QLA_DRIVER_PATCH_VER 7 -#define QLA_DRIVER_BETA_VER 0 +#define QLA_DRIVER_BETA_VER 3 -- cgit v0.10.2 From ab6c10b136d5f8eb856a0f17247edc7c19805e1b Mon Sep 17 00:00:00 2001 From: Wayne Boyer Date: Thu, 31 Mar 2011 09:56:10 -0700 Subject: [SCSI] ipr: fix synchronous request flags for better performance In testing it was noticed that Extended Delay after Reset flag was being set for gscsi and volume set devices. This had a negative effect on performance for volume sets. The fix is to only set the flag for gscsi devices. Signed-off-by: Wayne Boyer Acked-by: Brian King Signed-off-by: James Bottomley diff --git a/drivers/scsi/ipr.c b/drivers/scsi/ipr.c index 0621238..37790c0 100644 --- a/drivers/scsi/ipr.c +++ b/drivers/scsi/ipr.c @@ -5773,7 +5773,8 @@ static int ipr_queuecommand_lck(struct scsi_cmnd *scsi_cmd, } ioarcb->cmd_pkt.flags_hi |= IPR_FLAGS_HI_NO_LINK_DESC; - ioarcb->cmd_pkt.flags_lo |= IPR_FLAGS_LO_DELAY_AFTER_RST; + if (ipr_is_gscsi(res)) + ioarcb->cmd_pkt.flags_lo |= IPR_FLAGS_LO_DELAY_AFTER_RST; ioarcb->cmd_pkt.flags_lo |= IPR_FLAGS_LO_ALIGNED_BFR; ioarcb->cmd_pkt.flags_lo |= ipr_get_task_attributes(scsi_cmd); } diff --git a/drivers/scsi/ipr.h b/drivers/scsi/ipr.h index 13f425f..11b2dac 100644 --- a/drivers/scsi/ipr.h +++ b/drivers/scsi/ipr.h @@ -474,7 +474,7 @@ struct ipr_cmd_pkt { u8 flags_lo; #define IPR_FLAGS_LO_ALIGNED_BFR 0x20 -#define IPR_FLAGS_LO_DELAY_AFTER_RST 0x10 +#define IPR_FLAGS_LO_DELAY_AFTER_RST 0x10 #define IPR_FLAGS_LO_UNTAGGED_TASK 0x00 #define IPR_FLAGS_LO_SIMPLE_TASK 0x02 #define IPR_FLAGS_LO_ORDERED_TASK 0x04 -- cgit v0.10.2 From 5c2dce26fd670607b5ff04f18efa38739805f6d6 Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Fri, 1 Apr 2011 16:23:46 +0200 Subject: [SCSI] bnx2fc: introduce missing kfree Error handling code following a kmalloc should free the allocated data. The semantic match that finds the problem is as follows: (http://www.emn.fr/x-info/coccinelle/) // @r exists@ local idexpression x; statement S; expression E; identifier f,f1,l; position p1,p2; expression *ptr != NULL; @@ x@p1 = \(kmalloc\|kzalloc\|kcalloc\)(...); ... if (x == NULL) S <... when != x when != if (...) { <+...x...+> } ( x->f1 = E | (x->f1 == NULL || ...) | f(...,x->f1,...) ) ...> ( return \(0\|<+...x...+>\|ptr\); | return@p2 ...; ) @script:python@ p1 << r.p1; p2 << r.p2; @@ print "* file: %s kmalloc %s return %s" % (p1[0].file,p1[0].line,p2[0].line) // Signed-off-by: Julia Lawall Acked-by: Bhanu Prakash Gollapudi Signed-off-by: James Bottomley diff --git a/drivers/scsi/bnx2fc/bnx2fc_hwi.c b/drivers/scsi/bnx2fc/bnx2fc_hwi.c index 1b680e2..f756d5f 100644 --- a/drivers/scsi/bnx2fc/bnx2fc_hwi.c +++ b/drivers/scsi/bnx2fc/bnx2fc_hwi.c @@ -522,6 +522,7 @@ void bnx2fc_process_l2_frame_compl(struct bnx2fc_rport *tgt, fp = fc_frame_alloc(lport, payload_len); if (!fp) { printk(KERN_ERR PFX "fc_frame_alloc failure\n"); + kfree(unsol_els); return; } @@ -547,6 +548,7 @@ void bnx2fc_process_l2_frame_compl(struct bnx2fc_rport *tgt, */ printk(KERN_ERR PFX "dropping ELS 0x%x\n", op); kfree_skb(skb); + kfree(unsol_els); return; } } @@ -563,6 +565,7 @@ void bnx2fc_process_l2_frame_compl(struct bnx2fc_rport *tgt, } else { BNX2FC_HBA_DBG(lport, "fh_r_ctl = 0x%x\n", fh->fh_r_ctl); kfree_skb(skb); + kfree(unsol_els); } } -- cgit v0.10.2 From b3960afe0477781c84faa2e92dfb00016d6d4e30 Mon Sep 17 00:00:00 2001 From: Robert Love Date: Fri, 1 Apr 2011 16:05:53 -0700 Subject: [SCSI] libfcoe: Remove mutex_trylock/restart_syscall checks This code was incorrectly ported from fcoe.c when the fcoe transport infrastructure was put into place. It was originally needed in fcoe.c when dealing with the rtnl mutex. In that code it was only needed to avoid a lockdep false positive. In libfcoe we don't deal with the rtnl mutex, we don't get the lockdep false positive and therefore we don't need these checks. Signed-off-by: Robert Love Tested-by: Ross Brattain Signed-off-by: James Bottomley diff --git a/drivers/scsi/fcoe/fcoe_transport.c b/drivers/scsi/fcoe/fcoe_transport.c index 2586841..7b61d00 100644 --- a/drivers/scsi/fcoe/fcoe_transport.c +++ b/drivers/scsi/fcoe/fcoe_transport.c @@ -530,9 +530,6 @@ static int fcoe_transport_create(const char *buffer, struct kernel_param *kp) struct fcoe_transport *ft = NULL; enum fip_state fip_mode = (enum fip_state)(long)kp->arg; - if (!mutex_trylock(&ft_mutex)) - return restart_syscall(); - #ifdef CONFIG_LIBFCOE_MODULE /* * Make sure the module has been initialized, and is not about to be @@ -543,6 +540,8 @@ static int fcoe_transport_create(const char *buffer, struct kernel_param *kp) goto out_nodev; #endif + mutex_lock(&ft_mutex); + netdev = fcoe_if_to_netdev(buffer); if (!netdev) { LIBFCOE_TRANSPORT_DBG("Invalid device %s.\n", buffer); @@ -586,10 +585,7 @@ out_putdev: dev_put(netdev); out_nodev: mutex_unlock(&ft_mutex); - if (rc == -ERESTARTSYS) - return restart_syscall(); - else - return rc; + return rc; } /** @@ -608,9 +604,6 @@ static int fcoe_transport_destroy(const char *buffer, struct kernel_param *kp) struct net_device *netdev = NULL; struct fcoe_transport *ft = NULL; - if (!mutex_trylock(&ft_mutex)) - return restart_syscall(); - #ifdef CONFIG_LIBFCOE_MODULE /* * Make sure the module has been initialized, and is not about to be @@ -621,6 +614,8 @@ static int fcoe_transport_destroy(const char *buffer, struct kernel_param *kp) goto out_nodev; #endif + mutex_lock(&ft_mutex); + netdev = fcoe_if_to_netdev(buffer); if (!netdev) { LIBFCOE_TRANSPORT_DBG("invalid device %s.\n", buffer); @@ -645,11 +640,7 @@ out_putdev: dev_put(netdev); out_nodev: mutex_unlock(&ft_mutex); - - if (rc == -ERESTARTSYS) - return restart_syscall(); - else - return rc; + return rc; } /** @@ -667,9 +658,6 @@ static int fcoe_transport_disable(const char *buffer, struct kernel_param *kp) struct net_device *netdev = NULL; struct fcoe_transport *ft = NULL; - if (!mutex_trylock(&ft_mutex)) - return restart_syscall(); - #ifdef CONFIG_LIBFCOE_MODULE /* * Make sure the module has been initialized, and is not about to be @@ -680,6 +668,8 @@ static int fcoe_transport_disable(const char *buffer, struct kernel_param *kp) goto out_nodev; #endif + mutex_lock(&ft_mutex); + netdev = fcoe_if_to_netdev(buffer); if (!netdev) goto out_nodev; @@ -716,9 +706,6 @@ static int fcoe_transport_enable(const char *buffer, struct kernel_param *kp) struct net_device *netdev = NULL; struct fcoe_transport *ft = NULL; - if (!mutex_trylock(&ft_mutex)) - return restart_syscall(); - #ifdef CONFIG_LIBFCOE_MODULE /* * Make sure the module has been initialized, and is not about to be @@ -729,6 +716,8 @@ static int fcoe_transport_enable(const char *buffer, struct kernel_param *kp) goto out_nodev; #endif + mutex_lock(&ft_mutex); + netdev = fcoe_if_to_netdev(buffer); if (!netdev) goto out_nodev; @@ -743,10 +732,7 @@ out_putdev: dev_put(netdev); out_nodev: mutex_unlock(&ft_mutex); - if (rc == -ERESTARTSYS) - return restart_syscall(); - else - return rc; + return rc; } /** -- cgit v0.10.2 From ee5df628c1d7f3ff4db3174f7c00873c94f616d9 Mon Sep 17 00:00:00 2001 From: Robert Love Date: Fri, 1 Apr 2011 16:05:59 -0700 Subject: [SCSI] fcoe: Remove mutex_trylock/restart_syscall checks These checks were initially added to avoid a lockdep false positive when dealing with the s_active, rtnl and fcoe_config_mutex mutexes. Recently the create, destroy, enable and disable sysfs entries were moved from fcoe.ko to libfcoe.ko. With this change the mutex usage was shuffled around and the lockdep false positive stopped happening. We can now remove these checks. Signed-off-by: Robert Love Tested-by: Ross Brattain Signed-off-by: James Bottomley diff --git a/drivers/scsi/fcoe/fcoe.c b/drivers/scsi/fcoe/fcoe.c index bde6ee5..9e7206e 100644 --- a/drivers/scsi/fcoe/fcoe.c +++ b/drivers/scsi/fcoe/fcoe.c @@ -1795,11 +1795,7 @@ static int fcoe_disable(struct net_device *netdev) } #endif - if (!rtnl_trylock()) { - mutex_unlock(&fcoe_config_mutex); - return -ERESTARTSYS; - } - + rtnl_lock(); fcoe = fcoe_hostlist_lookup_port(netdev); rtnl_unlock(); @@ -1839,11 +1835,7 @@ static int fcoe_enable(struct net_device *netdev) goto out_nodev; } #endif - if (!rtnl_trylock()) { - mutex_unlock(&fcoe_config_mutex); - return -ERESTARTSYS; - } - + rtnl_lock(); fcoe = fcoe_hostlist_lookup_port(netdev); rtnl_unlock(); @@ -1882,11 +1874,7 @@ static int fcoe_destroy(struct net_device *netdev) goto out_nodev; } #endif - if (!rtnl_trylock()) { - mutex_unlock(&fcoe_config_mutex); - return -ERESTARTSYS; - } - + rtnl_lock(); fcoe = fcoe_hostlist_lookup_port(netdev); if (!fcoe) { rtnl_unlock(); @@ -1948,11 +1936,7 @@ static int fcoe_create(struct net_device *netdev, enum fip_state fip_mode) struct fc_lport *lport; mutex_lock(&fcoe_config_mutex); - - if (!rtnl_trylock()) { - mutex_unlock(&fcoe_config_mutex); - return -ERESTARTSYS; - } + rtnl_lock(); #ifdef CONFIG_FCOE_MODULE /* -- cgit v0.10.2 From 38b34aca30ef1296bbc552505d80c69f274f0872 Mon Sep 17 00:00:00 2001 From: Yi Zou Date: Fri, 1 Apr 2011 16:06:04 -0700 Subject: [SCSI] fcoe: remove unnecessary module state check The check of module state being MODULE_STATE_LIVE is no longer needed for the individual fcoe transport driver, e.g., fcoe.ko, as sysfs entries now go to libfcoe now, if it reaches fcoe.ko, it has to be already registered. The module state check for libfcoe will guard the possible race condition of sysfs being writable before module_init function is called and after module_exit. Signed-off-by: Yi Zou Tested-by: Ross Brattain Signed-off-by: Robert Love Signed-off-by: James Bottomley diff --git a/drivers/scsi/fcoe/fcoe.c b/drivers/scsi/fcoe/fcoe.c index 9e7206e..34408d9 100644 --- a/drivers/scsi/fcoe/fcoe.c +++ b/drivers/scsi/fcoe/fcoe.c @@ -1783,17 +1783,6 @@ static int fcoe_disable(struct net_device *netdev) int rc = 0; mutex_lock(&fcoe_config_mutex); -#ifdef CONFIG_FCOE_MODULE - /* - * Make sure the module has been initialized, and is not about to be - * removed. Module paramter sysfs files are writable before the - * module_init function is called and after module_exit. - */ - if (THIS_MODULE->state != MODULE_STATE_LIVE) { - rc = -ENODEV; - goto out_nodev; - } -#endif rtnl_lock(); fcoe = fcoe_hostlist_lookup_port(netdev); @@ -1805,7 +1794,6 @@ static int fcoe_disable(struct net_device *netdev) } else rc = -ENODEV; -out_nodev: mutex_unlock(&fcoe_config_mutex); return rc; } @@ -1824,17 +1812,6 @@ static int fcoe_enable(struct net_device *netdev) int rc = 0; mutex_lock(&fcoe_config_mutex); -#ifdef CONFIG_FCOE_MODULE - /* - * Make sure the module has been initialized, and is not about to be - * removed. Module paramter sysfs files are writable before the - * module_init function is called and after module_exit. - */ - if (THIS_MODULE->state != MODULE_STATE_LIVE) { - rc = -ENODEV; - goto out_nodev; - } -#endif rtnl_lock(); fcoe = fcoe_hostlist_lookup_port(netdev); rtnl_unlock(); @@ -1844,7 +1821,6 @@ static int fcoe_enable(struct net_device *netdev) else if (!fcoe_link_ok(fcoe->ctlr.lp)) fcoe_ctlr_link_up(&fcoe->ctlr); -out_nodev: mutex_unlock(&fcoe_config_mutex); return rc; } @@ -1863,17 +1839,6 @@ static int fcoe_destroy(struct net_device *netdev) int rc = 0; mutex_lock(&fcoe_config_mutex); -#ifdef CONFIG_FCOE_MODULE - /* - * Make sure the module has been initialized, and is not about to be - * removed. Module paramter sysfs files are writable before the - * module_init function is called and after module_exit. - */ - if (THIS_MODULE->state != MODULE_STATE_LIVE) { - rc = -ENODEV; - goto out_nodev; - } -#endif rtnl_lock(); fcoe = fcoe_hostlist_lookup_port(netdev); if (!fcoe) { @@ -1938,18 +1903,6 @@ static int fcoe_create(struct net_device *netdev, enum fip_state fip_mode) mutex_lock(&fcoe_config_mutex); rtnl_lock(); -#ifdef CONFIG_FCOE_MODULE - /* - * Make sure the module has been initialized, and is not about to be - * removed. Module paramter sysfs files are writable before the - * module_init function is called and after module_exit. - */ - if (THIS_MODULE->state != MODULE_STATE_LIVE) { - rc = -ENODEV; - goto out_nodev; - } -#endif - /* look for existing lport */ if (fcoe_hostlist_lookup(netdev)) { rc = -EEXIST; -- cgit v0.10.2 From 63ce2499947683dcc026373e24a4cb5a9d086e7d Mon Sep 17 00:00:00 2001 From: "Kirill A. Shutemov" Date: Fri, 1 Apr 2011 16:06:09 -0700 Subject: [SCSI] esp, scsi_tgt_lib, fcoe: use list_move() instead of list_del()/list_add() combination Signed-off-by: Kirill A. Shutemov Signed-off-by: Robert Love Signed-off-by: James Bottomley diff --git a/drivers/scsi/esp_scsi.c b/drivers/scsi/esp_scsi.c index 5755852..9a1af1d 100644 --- a/drivers/scsi/esp_scsi.c +++ b/drivers/scsi/esp_scsi.c @@ -708,8 +708,7 @@ static void esp_maybe_execute_command(struct esp *esp) tp = &esp->target[tgt]; lp = dev->hostdata; - list_del(&ent->list); - list_add(&ent->list, &esp->active_cmds); + list_move(&ent->list, &esp->active_cmds); esp->active_cmd = ent; @@ -1244,8 +1243,7 @@ static int esp_finish_select(struct esp *esp) /* Now that the state is unwound properly, put back onto * the issue queue. This command is no longer active. */ - list_del(&ent->list); - list_add(&ent->list, &esp->queued_cmds); + list_move(&ent->list, &esp->queued_cmds); esp->active_cmd = NULL; /* Return value ignored by caller, it directly invokes diff --git a/drivers/scsi/fcoe/fcoe_ctlr.c b/drivers/scsi/fcoe/fcoe_ctlr.c index 9d38be2..229e4af 100644 --- a/drivers/scsi/fcoe/fcoe_ctlr.c +++ b/drivers/scsi/fcoe/fcoe_ctlr.c @@ -978,10 +978,8 @@ static void fcoe_ctlr_recv_adv(struct fcoe_ctlr *fip, struct sk_buff *skb) * the FCF that answers multicast solicitations, not the others that * are sending periodic multicast advertisements. */ - if (mtu_valid) { - list_del(&fcf->list); - list_add(&fcf->list, &fip->fcfs); - } + if (mtu_valid) + list_move(&fcf->list, &fip->fcfs); /* * If this is the first validated FCF, note the time and diff --git a/drivers/scsi/scsi_tgt_lib.c b/drivers/scsi/scsi_tgt_lib.c index 8bca8c2..84a1fdf 100644 --- a/drivers/scsi/scsi_tgt_lib.c +++ b/drivers/scsi/scsi_tgt_lib.c @@ -275,10 +275,8 @@ void scsi_tgt_free_queue(struct Scsi_Host *shost) for (i = 0; i < ARRAY_SIZE(qdata->cmd_hash); i++) { list_for_each_entry_safe(tcmd, n, &qdata->cmd_hash[i], - hash_list) { - list_del(&tcmd->hash_list); - list_add(&tcmd->hash_list, &cmds); - } + hash_list) + list_move(&tcmd->hash_list, &cmds); } spin_unlock_irqrestore(&qdata->cmd_hash_lock, flags); -- cgit v0.10.2 From 9c8cce8e416b3286720379b5efa1c7fa81b2ec36 Mon Sep 17 00:00:00 2001 From: Robert Love Date: Fri, 1 Apr 2011 16:06:14 -0700 Subject: [SCSI] libfc: Move host_lock usage into ramp_up/down routines The host_lock is still used to protect the can_queue value in the Scsi_Host, but it doesn't need to be held and released by each caller. This patch moves the lock usage into the fc_fcp_can_queue_ramp_up and fc_fcp_can_queue_ramp_down routines. Signed-off-by: Robert Love Tested-by: Ross Brattain Signed-off-by: James Bottomley diff --git a/drivers/scsi/libfc/fc_fcp.c b/drivers/scsi/libfc/fc_fcp.c index 5b799a3..3591b87 100644 --- a/drivers/scsi/libfc/fc_fcp.c +++ b/drivers/scsi/libfc/fc_fcp.c @@ -335,22 +335,23 @@ static void fc_fcp_ddp_done(struct fc_fcp_pkt *fsp) /** * fc_fcp_can_queue_ramp_up() - increases can_queue * @lport: lport to ramp up can_queue - * - * Locking notes: Called with Scsi_Host lock held */ static void fc_fcp_can_queue_ramp_up(struct fc_lport *lport) { struct fc_fcp_internal *si = fc_get_scsi_internal(lport); + unsigned long flags; int can_queue; + spin_lock_irqsave(lport->host->host_lock, flags); + if (si->last_can_queue_ramp_up_time && (time_before(jiffies, si->last_can_queue_ramp_up_time + FC_CAN_QUEUE_PERIOD))) - return; + goto unlock; if (time_before(jiffies, si->last_can_queue_ramp_down_time + FC_CAN_QUEUE_PERIOD)) - return; + goto unlock; si->last_can_queue_ramp_up_time = jiffies; @@ -362,6 +363,9 @@ static void fc_fcp_can_queue_ramp_up(struct fc_lport *lport) lport->host->can_queue = can_queue; shost_printk(KERN_ERR, lport->host, "libfc: increased " "can_queue to %d.\n", can_queue); + +unlock: + spin_unlock_irqrestore(lport->host->host_lock, flags); } /** @@ -373,18 +377,19 @@ static void fc_fcp_can_queue_ramp_up(struct fc_lport *lport) * commands complete or timeout, then try again with a reduced * can_queue. Eventually we will hit the point where we run * on all reserved structs. - * - * Locking notes: Called with Scsi_Host lock held */ static void fc_fcp_can_queue_ramp_down(struct fc_lport *lport) { struct fc_fcp_internal *si = fc_get_scsi_internal(lport); + unsigned long flags; int can_queue; + spin_lock_irqsave(lport->host->host_lock, flags); + if (si->last_can_queue_ramp_down_time && (time_before(jiffies, si->last_can_queue_ramp_down_time + FC_CAN_QUEUE_PERIOD))) - return; + goto unlock; si->last_can_queue_ramp_down_time = jiffies; @@ -395,6 +400,9 @@ static void fc_fcp_can_queue_ramp_down(struct fc_lport *lport) lport->host->can_queue = can_queue; shost_printk(KERN_ERR, lport->host, "libfc: Could not allocate frame.\n" "Reducing can_queue to %d.\n", can_queue); + +unlock: + spin_unlock_irqrestore(lport->host->host_lock, flags); } /* @@ -409,16 +417,13 @@ static inline struct fc_frame *fc_fcp_frame_alloc(struct fc_lport *lport, size_t len) { struct fc_frame *fp; - unsigned long flags; fp = fc_frame_alloc(lport, len); if (likely(fp)) return fp; /* error case */ - spin_lock_irqsave(lport->host->host_lock, flags); fc_fcp_can_queue_ramp_down(lport); - spin_unlock_irqrestore(lport->host->host_lock, flags); return NULL; } -- cgit v0.10.2 From 69922fcd534cfc82e2d44374fa219e7c3b27c492 Mon Sep 17 00:00:00 2001 From: Yi Zou Date: Fri, 1 Apr 2011 16:06:19 -0700 Subject: [SCSI] libfcoe: clean up netdev mapping properly when the transport goes away When rmmoving the underlying fcoe transport driver module by force when it's attached and in use, the correspoding netdev mapping should be cleaned up properly as well, otherwise the lookup for a given netdev for the transport would still return non NULL pointer, causing "unable to handle paging request" bug. Signed-off-by: Yi Zou Tested-by: Ross Brattain Signed-off-by: Robert Love Signed-off-by: James Bottomley diff --git a/drivers/scsi/fcoe/fcoe_transport.c b/drivers/scsi/fcoe/fcoe_transport.c index 7b61d00..ec0f395 100644 --- a/drivers/scsi/fcoe/fcoe_transport.c +++ b/drivers/scsi/fcoe/fcoe_transport.c @@ -343,6 +343,7 @@ EXPORT_SYMBOL(fcoe_transport_attach); int fcoe_transport_detach(struct fcoe_transport *ft) { int rc = 0; + struct fcoe_netdev_mapping *nm = NULL, *tmp; mutex_lock(&ft_mutex); if (!ft->attached) { @@ -352,6 +353,19 @@ int fcoe_transport_detach(struct fcoe_transport *ft) goto out_attach; } + /* remove netdev mapping for this transport as it is going away */ + mutex_lock(&fn_mutex); + list_for_each_entry_safe(nm, tmp, &fcoe_netdevs, list) { + if (nm->ft == ft) { + LIBFCOE_TRANSPORT_DBG("transport %s going away, " + "remove its netdev mapping for %s\n", + ft->name, nm->netdev->name); + list_del(&nm->list); + kfree(nm); + } + } + mutex_unlock(&fn_mutex); + list_del(&ft->list); ft->attached = false; LIBFCOE_TRANSPORT_DBG("detaching transport %s\n", ft->name); -- cgit v0.10.2 From a01a5a5789287113cd6bb25c79cf2a826874c918 Mon Sep 17 00:00:00 2001 From: Yi Zou Date: Fri, 1 Apr 2011 16:06:25 -0700 Subject: [SCSI] libfcoe: fix possible buffer overflow in fcoe_transport_show possible buffer overflow in fcoe_transport_show when reaching the end of buffer and crossing PAGE_SIZE boundary. Signed-off-by: Yi Zou Signed-off-by: Tomas Henzl Tested-by: Ross Brattain Signed-off-by: Robert Love Signed-off-by: James Bottomley diff --git a/drivers/scsi/fcoe/fcoe_transport.c b/drivers/scsi/fcoe/fcoe_transport.c index ec0f395..538f299 100644 --- a/drivers/scsi/fcoe/fcoe_transport.c +++ b/drivers/scsi/fcoe/fcoe_transport.c @@ -385,9 +385,9 @@ static int fcoe_transport_show(char *buffer, const struct kernel_param *kp) i = j = sprintf(buffer, "Attached FCoE transports:"); mutex_lock(&ft_mutex); list_for_each_entry(ft, &fcoe_transports, list) { - i += snprintf(&buffer[i], IFNAMSIZ, "%s ", ft->name); - if (i >= PAGE_SIZE) + if (i >= PAGE_SIZE - IFNAMSIZ) break; + i += snprintf(&buffer[i], IFNAMSIZ, "%s ", ft->name); } mutex_unlock(&ft_mutex); if (i == j) -- cgit v0.10.2 From 4ef7fb150f3002c5e494b2a327fa532bf8fd0927 Mon Sep 17 00:00:00 2001 From: Yi Zou Date: Fri, 1 Apr 2011 16:06:30 -0700 Subject: [SCSI] libfcoe: fix wrong comment in fcoe_transport_detach fix typo of '_attach' -> '_detach' in the comment. Reported-by: Frank Zhang Signed-off-by: Yi Zou Tested-by: Ross Brattain Signed-off-by: Robert Love Signed-off-by: James Bottomley diff --git a/drivers/scsi/fcoe/fcoe_transport.c b/drivers/scsi/fcoe/fcoe_transport.c index 538f299..f81f77c 100644 --- a/drivers/scsi/fcoe/fcoe_transport.c +++ b/drivers/scsi/fcoe/fcoe_transport.c @@ -335,7 +335,7 @@ out_attach: EXPORT_SYMBOL(fcoe_transport_attach); /** - * fcoe_transport_attach - Detaches an FCoE transport + * fcoe_transport_detach - Detaches an FCoE transport * @ft: The fcoe transport to be attached * * Returns : 0 for success -- cgit v0.10.2 From 66a5b3acba563b53cfbca96c7fff2207c94a87e2 Mon Sep 17 00:00:00 2001 From: Vasu Dev Date: Fri, 1 Apr 2011 16:06:35 -0700 Subject: [SCSI] libfc: remove duplicate ema_list init As ema_list is already initialized by libfc_host_alloc. Signed-off-by: Vasu Dev Signed-off-by: Robert Love Signed-off-by: James Bottomley diff --git a/drivers/scsi/libfc/fc_lport.c b/drivers/scsi/libfc/fc_lport.c index 906bbca..389ab80 100644 --- a/drivers/scsi/libfc/fc_lport.c +++ b/drivers/scsi/libfc/fc_lport.c @@ -1590,7 +1590,6 @@ void fc_lport_enter_flogi(struct fc_lport *lport) */ int fc_lport_config(struct fc_lport *lport) { - INIT_LIST_HEAD(&lport->ema_list); INIT_DELAYED_WORK(&lport->retry_work, fc_lport_timeout); mutex_init(&lport->lp_mutex); -- cgit v0.10.2 From f2817ec2e0faece03959888050730ed35e5f2bd2 Mon Sep 17 00:00:00 2001 From: Vasu Dev Date: Fri, 1 Apr 2011 16:06:40 -0700 Subject: [SCSI] libfc: rec tov value and REC_TOV_CONST units usages is incorrect Added REC_TOV_CONST intent was to have rec tov as e_d_tov + 1s but currently it is e_d_tov + 1ms since e_d_tov is stored in ms unit. Also returned rec tov by get_fsp_rec_tov is in ms and this ms tov is used as-is with fc_fcp_timer_set expecting jiffies tov. Fixed this by having get_fsp_rec_tov return rec tov in jiffies as e_d_tov + 1s and then use jiffies tov w/ fc_fcp_timer_set. Also some cleanup, no need to cache get_fsp_rec_tov return value in local rec_tov at various places. Signed-off-by: Vasu Dev Tested-by: Ross Brattain Signed-off-by: Robert Love Signed-off-by: James Bottomley diff --git a/drivers/scsi/libfc/fc_fcp.c b/drivers/scsi/libfc/fc_fcp.c index 3591b87..2a3a472 100644 --- a/drivers/scsi/libfc/fc_fcp.c +++ b/drivers/scsi/libfc/fc_fcp.c @@ -57,9 +57,6 @@ static struct kmem_cache *scsi_pkt_cachep; #define FC_SRB_READ (1 << 1) #define FC_SRB_WRITE (1 << 0) -/* constant added to e_d_tov timeout to get rec_tov value */ -#define REC_TOV_CONST 1 - /* * The SCp.ptr should be tested and set under the scsi_pkt_queue lock */ @@ -248,7 +245,7 @@ static inline void fc_fcp_unlock_pkt(struct fc_fcp_pkt *fsp) /** * fc_fcp_timer_set() - Start a timer for a fcp_pkt * @fsp: The FCP packet to start a timer for - * @delay: The timeout period for the timer + * @delay: The timeout period in jiffies */ static void fc_fcp_timer_set(struct fc_fcp_pkt *fsp, unsigned long delay) { @@ -1098,16 +1095,14 @@ static int fc_fcp_pkt_send(struct fc_lport *lport, struct fc_fcp_pkt *fsp) /** * get_fsp_rec_tov() - Helper function to get REC_TOV * @fsp: the FCP packet + * + * Returns rec tov in jiffies as rpriv->e_d_tov + 1 second */ static inline unsigned int get_fsp_rec_tov(struct fc_fcp_pkt *fsp) { - struct fc_rport *rport; - struct fc_rport_libfc_priv *rpriv; + struct fc_rport_libfc_priv *rpriv = fsp->rport->dd_data; - rport = fsp->rport; - rpriv = rport->dd_data; - - return rpriv->e_d_tov + REC_TOV_CONST; + return msecs_to_jiffies(rpriv->e_d_tov) + HZ; } /** @@ -1127,7 +1122,6 @@ static int fc_fcp_cmd_send(struct fc_lport *lport, struct fc_fcp_pkt *fsp, struct fc_rport_libfc_priv *rpriv; const size_t len = sizeof(fsp->cdb_cmd); int rc = 0; - unsigned int rec_tov; if (fc_fcp_lock_pkt(fsp)) return 0; @@ -1158,12 +1152,9 @@ static int fc_fcp_cmd_send(struct fc_lport *lport, struct fc_fcp_pkt *fsp, fsp->seq_ptr = seq; fc_fcp_pkt_hold(fsp); /* hold for fc_fcp_pkt_destroy */ - rec_tov = get_fsp_rec_tov(fsp); - setup_timer(&fsp->timer, fc_fcp_timeout, (unsigned long)fsp); - if (rpriv->flags & FC_RP_FLAGS_REC_SUPPORTED) - fc_fcp_timer_set(fsp, rec_tov); + fc_fcp_timer_set(fsp, get_fsp_rec_tov(fsp)); unlock: fc_fcp_unlock_pkt(fsp); @@ -1240,16 +1231,14 @@ static void fc_lun_reset_send(unsigned long data) { struct fc_fcp_pkt *fsp = (struct fc_fcp_pkt *)data; struct fc_lport *lport = fsp->lp; - unsigned int rec_tov; if (lport->tt.fcp_cmd_send(lport, fsp, fc_tm_done)) { if (fsp->recov_retry++ >= FC_MAX_RECOV_RETRY) return; if (fc_fcp_lock_pkt(fsp)) return; - rec_tov = get_fsp_rec_tov(fsp); setup_timer(&fsp->timer, fc_lun_reset_send, (unsigned long)fsp); - fc_fcp_timer_set(fsp, rec_tov); + fc_fcp_timer_set(fsp, get_fsp_rec_tov(fsp)); fc_fcp_unlock_pkt(fsp); } } @@ -1541,12 +1530,11 @@ static void fc_fcp_rec_resp(struct fc_seq *seq, struct fc_frame *fp, void *arg) } fc_fcp_srr(fsp, r_ctl, offset); } else if (e_stat & ESB_ST_SEQ_INIT) { - unsigned int rec_tov = get_fsp_rec_tov(fsp); /* * The remote port has the initiative, so just * keep waiting for it to complete. */ - fc_fcp_timer_set(fsp, rec_tov); + fc_fcp_timer_set(fsp, get_fsp_rec_tov(fsp)); } else { /* @@ -1710,7 +1698,6 @@ static void fc_fcp_srr_resp(struct fc_seq *seq, struct fc_frame *fp, void *arg) { struct fc_fcp_pkt *fsp = arg; struct fc_frame_header *fh; - unsigned int rec_tov; if (IS_ERR(fp)) { fc_fcp_srr_error(fsp, fp); @@ -1737,8 +1724,7 @@ static void fc_fcp_srr_resp(struct fc_seq *seq, struct fc_frame *fp, void *arg) switch (fc_frame_payload_op(fp)) { case ELS_LS_ACC: fsp->recov_retry = 0; - rec_tov = get_fsp_rec_tov(fsp); - fc_fcp_timer_set(fsp, rec_tov); + fc_fcp_timer_set(fsp, get_fsp_rec_tov(fsp)); break; case ELS_LS_RJT: default: -- cgit v0.10.2 From f04ca1b65480df9ecbaaa797e62b063387429410 Mon Sep 17 00:00:00 2001 From: Vasu Dev Date: Fri, 1 Apr 2011 16:06:45 -0700 Subject: [SCSI] fcoe: have fcoe log off and lport destroy before ndo_fcoe_disable Currently fcoe interface cleanup is done after ndo_fcoe_disable and that prevents logoff going out to the peer, so this patch moves all netdev cleanup and its releasing inside fcoe_interface_cleanup to have log off before ndo_fcoe_disable disables the fcoe. This patch also fixes asymmetric rtnl locking around fcoe_if_destroy, as currently this function requires rtnl held by its caller and then have this func drops the lock, instead now don't have any processing under rtnl inside fcoe_if_destroy, this required moving few func to get build working again. Signed-off-by: Vasu Dev Signed-off-by: Robert Love Signed-off-by: James Bottomley diff --git a/drivers/scsi/fcoe/fcoe.c b/drivers/scsi/fcoe/fcoe.c index 34408d9..5d3700d 100644 --- a/drivers/scsi/fcoe/fcoe.c +++ b/drivers/scsi/fcoe/fcoe.c @@ -381,6 +381,42 @@ out: } /** + * fcoe_interface_release() - fcoe_port kref release function + * @kref: Embedded reference count in an fcoe_interface struct + */ +static void fcoe_interface_release(struct kref *kref) +{ + struct fcoe_interface *fcoe; + struct net_device *netdev; + + fcoe = container_of(kref, struct fcoe_interface, kref); + netdev = fcoe->netdev; + /* tear-down the FCoE controller */ + fcoe_ctlr_destroy(&fcoe->ctlr); + kfree(fcoe); + dev_put(netdev); + module_put(THIS_MODULE); +} + +/** + * fcoe_interface_get() - Get a reference to a FCoE interface + * @fcoe: The FCoE interface to be held + */ +static inline void fcoe_interface_get(struct fcoe_interface *fcoe) +{ + kref_get(&fcoe->kref); +} + +/** + * fcoe_interface_put() - Put a reference to a FCoE interface + * @fcoe: The FCoE interface to be released + */ +static inline void fcoe_interface_put(struct fcoe_interface *fcoe) +{ + kref_put(&fcoe->kref, fcoe_interface_release); +} + +/** * fcoe_interface_cleanup() - Clean up a FCoE interface * @fcoe: The FCoE interface to be cleaned up * @@ -392,6 +428,21 @@ void fcoe_interface_cleanup(struct fcoe_interface *fcoe) struct fcoe_ctlr *fip = &fcoe->ctlr; u8 flogi_maddr[ETH_ALEN]; const struct net_device_ops *ops; + struct fcoe_port *port = lport_priv(fcoe->ctlr.lp); + + FCOE_NETDEV_DBG(netdev, "Destroying interface\n"); + + /* Logout of the fabric */ + fc_fabric_logoff(fcoe->ctlr.lp); + + /* Cleanup the fc_lport */ + fc_lport_destroy(fcoe->ctlr.lp); + + /* Stop the transmit retry timer */ + del_timer_sync(&port->timer); + + /* Free existing transmit skbs */ + fcoe_clean_pending_queue(fcoe->ctlr.lp); /* * Don't listen for Ethernet packets anymore. @@ -414,6 +465,9 @@ void fcoe_interface_cleanup(struct fcoe_interface *fcoe) } else dev_mc_del(netdev, FIP_ALL_ENODE_MACS); + if (!is_zero_ether_addr(port->data_src_addr)) + dev_uc_del(netdev, port->data_src_addr); + /* Tell the LLD we are done w/ FCoE */ ops = netdev->netdev_ops; if (ops->ndo_fcoe_disable) { @@ -421,42 +475,7 @@ void fcoe_interface_cleanup(struct fcoe_interface *fcoe) FCOE_NETDEV_DBG(netdev, "Failed to disable FCoE" " specific feature for LLD.\n"); } -} - -/** - * fcoe_interface_release() - fcoe_port kref release function - * @kref: Embedded reference count in an fcoe_interface struct - */ -static void fcoe_interface_release(struct kref *kref) -{ - struct fcoe_interface *fcoe; - struct net_device *netdev; - - fcoe = container_of(kref, struct fcoe_interface, kref); - netdev = fcoe->netdev; - /* tear-down the FCoE controller */ - fcoe_ctlr_destroy(&fcoe->ctlr); - kfree(fcoe); - dev_put(netdev); - module_put(THIS_MODULE); -} - -/** - * fcoe_interface_get() - Get a reference to a FCoE interface - * @fcoe: The FCoE interface to be held - */ -static inline void fcoe_interface_get(struct fcoe_interface *fcoe) -{ - kref_get(&fcoe->kref); -} - -/** - * fcoe_interface_put() - Put a reference to a FCoE interface - * @fcoe: The FCoE interface to be released - */ -static inline void fcoe_interface_put(struct fcoe_interface *fcoe) -{ - kref_put(&fcoe->kref, fcoe_interface_release); + fcoe_interface_put(fcoe); } /** @@ -821,39 +840,9 @@ skip_oem: * fcoe_if_destroy() - Tear down a SW FCoE instance * @lport: The local port to be destroyed * - * Locking: must be called with the RTNL mutex held and RTNL mutex - * needed to be dropped by this function since not dropping RTNL - * would cause circular locking warning on synchronous fip worker - * cancelling thru fcoe_interface_put invoked by this function. - * */ static void fcoe_if_destroy(struct fc_lport *lport) { - struct fcoe_port *port = lport_priv(lport); - struct fcoe_interface *fcoe = port->priv; - struct net_device *netdev = fcoe->netdev; - - FCOE_NETDEV_DBG(netdev, "Destroying interface\n"); - - /* Logout of the fabric */ - fc_fabric_logoff(lport); - - /* Cleanup the fc_lport */ - fc_lport_destroy(lport); - - /* Stop the transmit retry timer */ - del_timer_sync(&port->timer); - - /* Free existing transmit skbs */ - fcoe_clean_pending_queue(lport); - - if (!is_zero_ether_addr(port->data_src_addr)) - dev_uc_del(netdev, port->data_src_addr); - rtnl_unlock(); - - /* receives may not be stopped until after this */ - fcoe_interface_put(fcoe); - /* Free queued packets for the per-CPU receive threads */ fcoe_percpu_clean(lport); @@ -1836,6 +1825,7 @@ static int fcoe_enable(struct net_device *netdev) static int fcoe_destroy(struct net_device *netdev) { struct fcoe_interface *fcoe; + struct fc_lport *lport; int rc = 0; mutex_lock(&fcoe_config_mutex); @@ -1846,10 +1836,11 @@ static int fcoe_destroy(struct net_device *netdev) rc = -ENODEV; goto out_nodev; } - fcoe_interface_cleanup(fcoe); + lport = fcoe->ctlr.lp; list_del(&fcoe->list); - /* RTNL mutex is dropped by fcoe_if_destroy */ - fcoe_if_destroy(fcoe->ctlr.lp); + fcoe_interface_cleanup(fcoe); + rtnl_unlock(); + fcoe_if_destroy(lport); out_nodev: mutex_unlock(&fcoe_config_mutex); return rc; @@ -1865,8 +1856,6 @@ static void fcoe_destroy_work(struct work_struct *work) port = container_of(work, struct fcoe_port, destroy_work); mutex_lock(&fcoe_config_mutex); - rtnl_lock(); - /* RTNL mutex is dropped by fcoe_if_destroy */ fcoe_if_destroy(port->lport); mutex_unlock(&fcoe_config_mutex); } -- cgit v0.10.2 From 5cd049a59913f359e7d30c11d2dc6187822e77b1 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Mon, 4 Apr 2011 09:42:14 -0400 Subject: [SCSI] remove cmd->serial_number litter Stop using cmd->serial_number in printks. Signed-off-by: Christoph Hellwig Signed-off-by: James Bottomley diff --git a/drivers/message/i2o/i2o_scsi.c b/drivers/message/i2o/i2o_scsi.c index f003957..74fbe56 100644 --- a/drivers/message/i2o/i2o_scsi.c +++ b/drivers/message/i2o/i2o_scsi.c @@ -361,7 +361,7 @@ static int i2o_scsi_reply(struct i2o_controller *c, u32 m, */ error = le32_to_cpu(msg->body[0]); - osm_debug("Completed %ld\n", cmd->serial_number); + osm_debug("Completed %0x%p\n", cmd); cmd->result = error & 0xff; /* @@ -678,7 +678,7 @@ static int i2o_scsi_queuecommand_lck(struct scsi_cmnd *SCpnt, /* Queue the message */ i2o_msg_post(c, msg); - osm_debug("Issued %ld\n", SCpnt->serial_number); + osm_debug("Issued %0x%p\n", SCpnt); return 0; diff --git a/drivers/scsi/dc395x.c b/drivers/scsi/dc395x.c index b10b384..f5b718d 100644 --- a/drivers/scsi/dc395x.c +++ b/drivers/scsi/dc395x.c @@ -778,8 +778,8 @@ static void srb_free_insert(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb) static void srb_waiting_insert(struct DeviceCtlBlk *dcb, struct ScsiReqBlk *srb) { - dprintkdbg(DBG_0, "srb_waiting_insert: (pid#%li) <%02i-%i> srb=%p\n", - srb->cmd->serial_number, dcb->target_id, dcb->target_lun, srb); + dprintkdbg(DBG_0, "srb_waiting_insert: (0x%p) <%02i-%i> srb=%p\n", + srb->cmd, dcb->target_id, dcb->target_lun, srb); list_add(&srb->list, &dcb->srb_waiting_list); } @@ -787,16 +787,16 @@ static void srb_waiting_insert(struct DeviceCtlBlk *dcb, static void srb_waiting_append(struct DeviceCtlBlk *dcb, struct ScsiReqBlk *srb) { - dprintkdbg(DBG_0, "srb_waiting_append: (pid#%li) <%02i-%i> srb=%p\n", - srb->cmd->serial_number, dcb->target_id, dcb->target_lun, srb); + dprintkdbg(DBG_0, "srb_waiting_append: (0x%p) <%02i-%i> srb=%p\n", + srb->cmd, dcb->target_id, dcb->target_lun, srb); list_add_tail(&srb->list, &dcb->srb_waiting_list); } static void srb_going_append(struct DeviceCtlBlk *dcb, struct ScsiReqBlk *srb) { - dprintkdbg(DBG_0, "srb_going_append: (pid#%li) <%02i-%i> srb=%p\n", - srb->cmd->serial_number, dcb->target_id, dcb->target_lun, srb); + dprintkdbg(DBG_0, "srb_going_append: (0x%p) <%02i-%i> srb=%p\n", + srb->cmd, dcb->target_id, dcb->target_lun, srb); list_add_tail(&srb->list, &dcb->srb_going_list); } @@ -805,8 +805,8 @@ static void srb_going_remove(struct DeviceCtlBlk *dcb, struct ScsiReqBlk *srb) { struct ScsiReqBlk *i; struct ScsiReqBlk *tmp; - dprintkdbg(DBG_0, "srb_going_remove: (pid#%li) <%02i-%i> srb=%p\n", - srb->cmd->serial_number, dcb->target_id, dcb->target_lun, srb); + dprintkdbg(DBG_0, "srb_going_remove: (0x%p) <%02i-%i> srb=%p\n", + srb->cmd, dcb->target_id, dcb->target_lun, srb); list_for_each_entry_safe(i, tmp, &dcb->srb_going_list, list) if (i == srb) { @@ -821,8 +821,8 @@ static void srb_waiting_remove(struct DeviceCtlBlk *dcb, { struct ScsiReqBlk *i; struct ScsiReqBlk *tmp; - dprintkdbg(DBG_0, "srb_waiting_remove: (pid#%li) <%02i-%i> srb=%p\n", - srb->cmd->serial_number, dcb->target_id, dcb->target_lun, srb); + dprintkdbg(DBG_0, "srb_waiting_remove: (0x%p) <%02i-%i> srb=%p\n", + srb->cmd, dcb->target_id, dcb->target_lun, srb); list_for_each_entry_safe(i, tmp, &dcb->srb_waiting_list, list) if (i == srb) { @@ -836,8 +836,8 @@ static void srb_going_to_waiting_move(struct DeviceCtlBlk *dcb, struct ScsiReqBlk *srb) { dprintkdbg(DBG_0, - "srb_going_to_waiting_move: (pid#%li) <%02i-%i> srb=%p\n", - srb->cmd->serial_number, dcb->target_id, dcb->target_lun, srb); + "srb_going_to_waiting_move: (0x%p) <%02i-%i> srb=%p\n", + srb->cmd, dcb->target_id, dcb->target_lun, srb); list_move(&srb->list, &dcb->srb_waiting_list); } @@ -846,8 +846,8 @@ static void srb_waiting_to_going_move(struct DeviceCtlBlk *dcb, struct ScsiReqBlk *srb) { dprintkdbg(DBG_0, - "srb_waiting_to_going_move: (pid#%li) <%02i-%i> srb=%p\n", - srb->cmd->serial_number, dcb->target_id, dcb->target_lun, srb); + "srb_waiting_to_going_move: (0x%p) <%02i-%i> srb=%p\n", + srb->cmd, dcb->target_id, dcb->target_lun, srb); list_move(&srb->list, &dcb->srb_going_list); } @@ -982,8 +982,8 @@ static void build_srb(struct scsi_cmnd *cmd, struct DeviceCtlBlk *dcb, { int nseg; enum dma_data_direction dir = cmd->sc_data_direction; - dprintkdbg(DBG_0, "build_srb: (pid#%li) <%02i-%i>\n", - cmd->serial_number, dcb->target_id, dcb->target_lun); + dprintkdbg(DBG_0, "build_srb: (0x%p) <%02i-%i>\n", + cmd, dcb->target_id, dcb->target_lun); srb->dcb = dcb; srb->cmd = cmd; @@ -1086,8 +1086,8 @@ static int dc395x_queue_command_lck(struct scsi_cmnd *cmd, void (*done)(struct s struct ScsiReqBlk *srb; struct AdapterCtlBlk *acb = (struct AdapterCtlBlk *)cmd->device->host->hostdata; - dprintkdbg(DBG_0, "queue_command: (pid#%li) <%02i-%i> cmnd=0x%02x\n", - cmd->serial_number, cmd->device->id, cmd->device->lun, cmd->cmnd[0]); + dprintkdbg(DBG_0, "queue_command: (0x%p) <%02i-%i> cmnd=0x%02x\n", + cmd, cmd->device->id, cmd->device->lun, cmd->cmnd[0]); /* Assume BAD_TARGET; will be cleared later */ cmd->result = DID_BAD_TARGET << 16; @@ -1140,7 +1140,7 @@ static int dc395x_queue_command_lck(struct scsi_cmnd *cmd, void (*done)(struct s /* process immediately */ send_srb(acb, srb); } - dprintkdbg(DBG_1, "queue_command: (pid#%li) done\n", cmd->serial_number); + dprintkdbg(DBG_1, "queue_command: (0x%p) done\n", cmd); return 0; complete: @@ -1203,9 +1203,9 @@ static void dump_register_info(struct AdapterCtlBlk *acb, dprintkl(KERN_INFO, "dump: srb=%p cmd=%p OOOPS!\n", srb, srb->cmd); else - dprintkl(KERN_INFO, "dump: srb=%p cmd=%p (pid#%li) " + dprintkl(KERN_INFO, "dump: srb=%p cmd=%p " "cmnd=0x%02x <%02i-%i>\n", - srb, srb->cmd, srb->cmd->serial_number, + srb, srb->cmd, srb->cmd->cmnd[0], srb->cmd->device->id, srb->cmd->device->lun); printk(" sglist=%p cnt=%i idx=%i len=%zu\n", @@ -1301,8 +1301,8 @@ static int __dc395x_eh_bus_reset(struct scsi_cmnd *cmd) struct AdapterCtlBlk *acb = (struct AdapterCtlBlk *)cmd->device->host->hostdata; dprintkl(KERN_INFO, - "eh_bus_reset: (pid#%li) target=<%02i-%i> cmd=%p\n", - cmd->serial_number, cmd->device->id, cmd->device->lun, cmd); + "eh_bus_reset: (0%p) target=<%02i-%i> cmd=%p\n", + cmd, cmd->device->id, cmd->device->lun, cmd); if (timer_pending(&acb->waiting_timer)) del_timer(&acb->waiting_timer); @@ -1368,8 +1368,8 @@ static int dc395x_eh_abort(struct scsi_cmnd *cmd) (struct AdapterCtlBlk *)cmd->device->host->hostdata; struct DeviceCtlBlk *dcb; struct ScsiReqBlk *srb; - dprintkl(KERN_INFO, "eh_abort: (pid#%li) target=<%02i-%i> cmd=%p\n", - cmd->serial_number, cmd->device->id, cmd->device->lun, cmd); + dprintkl(KERN_INFO, "eh_abort: (0x%p) target=<%02i-%i> cmd=%p\n", + cmd, cmd->device->id, cmd->device->lun, cmd); dcb = find_dcb(acb, cmd->device->id, cmd->device->lun); if (!dcb) { @@ -1495,8 +1495,8 @@ static u8 start_scsi(struct AdapterCtlBlk* acb, struct DeviceCtlBlk* dcb, u16 s_stat2, return_code; u8 s_stat, scsicommand, i, identify_message; u8 *ptr; - dprintkdbg(DBG_0, "start_scsi: (pid#%li) <%02i-%i> srb=%p\n", - srb->cmd->serial_number, dcb->target_id, dcb->target_lun, srb); + dprintkdbg(DBG_0, "start_scsi: (0x%p) <%02i-%i> srb=%p\n", + dcb->target_id, dcb->target_lun, srb); srb->tag_number = TAG_NONE; /* acb->tag_max_num: had error read in eeprom */ @@ -1505,8 +1505,8 @@ static u8 start_scsi(struct AdapterCtlBlk* acb, struct DeviceCtlBlk* dcb, s_stat2 = DC395x_read16(acb, TRM_S1040_SCSI_STATUS); #if 1 if (s_stat & 0x20 /* s_stat2 & 0x02000 */ ) { - dprintkdbg(DBG_KG, "start_scsi: (pid#%li) BUSY %02x %04x\n", - srb->cmd->serial_number, s_stat, s_stat2); + dprintkdbg(DBG_KG, "start_scsi: (0x%p) BUSY %02x %04x\n", + s_stat, s_stat2); /* * Try anyway? * @@ -1522,16 +1522,15 @@ static u8 start_scsi(struct AdapterCtlBlk* acb, struct DeviceCtlBlk* dcb, } #endif if (acb->active_dcb) { - dprintkl(KERN_DEBUG, "start_scsi: (pid#%li) Attempt to start a" - "command while another command (pid#%li) is active.", - srb->cmd->serial_number, + dprintkl(KERN_DEBUG, "start_scsi: (0x%p) Attempt to start a" + "command while another command (0x%p) is active.", + srb->cmd, acb->active_dcb->active_srb ? - acb->active_dcb->active_srb->cmd->serial_number : 0); + acb->active_dcb->active_srb->cmd : 0); return 1; } if (DC395x_read16(acb, TRM_S1040_SCSI_STATUS) & SCSIINTERRUPT) { - dprintkdbg(DBG_KG, "start_scsi: (pid#%li) Failed (busy)\n", - srb->cmd->serial_number); + dprintkdbg(DBG_KG, "start_scsi: (0x%p) Failed (busy)\n", srb->cmd); return 1; } /* Allow starting of SCSI commands half a second before we allow the mid-level @@ -1603,9 +1602,9 @@ static u8 start_scsi(struct AdapterCtlBlk* acb, struct DeviceCtlBlk* dcb, tag_number++; } if (tag_number >= dcb->max_command) { - dprintkl(KERN_WARNING, "start_scsi: (pid#%li) " + dprintkl(KERN_WARNING, "start_scsi: (0x%p) " "Out of tags target=<%02i-%i>)\n", - srb->cmd->serial_number, srb->cmd->device->id, + srb->cmd, srb->cmd->device->id, srb->cmd->device->lun); srb->state = SRB_READY; DC395x_write16(acb, TRM_S1040_SCSI_CONTROL, @@ -1623,8 +1622,8 @@ static u8 start_scsi(struct AdapterCtlBlk* acb, struct DeviceCtlBlk* dcb, #endif /*polling:*/ /* Send CDB ..command block ......... */ - dprintkdbg(DBG_KG, "start_scsi: (pid#%li) <%02i-%i> cmnd=0x%02x tag=%i\n", - srb->cmd->serial_number, srb->cmd->device->id, srb->cmd->device->lun, + dprintkdbg(DBG_KG, "start_scsi: (0x%p) <%02i-%i> cmnd=0x%02x tag=%i\n", + srb->cmd, srb->cmd->device->id, srb->cmd->device->lun, srb->cmd->cmnd[0], srb->tag_number); if (srb->flag & AUTO_REQSENSE) { DC395x_write8(acb, TRM_S1040_SCSI_FIFO, REQUEST_SENSE); @@ -1647,8 +1646,8 @@ static u8 start_scsi(struct AdapterCtlBlk* acb, struct DeviceCtlBlk* dcb, * we caught an interrupt (must be reset or reselection ... ) * : Let's process it first! */ - dprintkdbg(DBG_0, "start_scsi: (pid#%li) <%02i-%i> Failed - busy\n", - srb->cmd->serial_number, dcb->target_id, dcb->target_lun); + dprintkdbg(DBG_0, "start_scsi: (0x%p) <%02i-%i> Failed - busy\n", + srb->cmd, dcb->target_id, dcb->target_lun); srb->state = SRB_READY; free_tag(dcb, srb); srb->msg_count = 0; @@ -1843,7 +1842,7 @@ static irqreturn_t dc395x_interrupt(int irq, void *dev_id) static void msgout_phase0(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb, u16 *pscsi_status) { - dprintkdbg(DBG_0, "msgout_phase0: (pid#%li)\n", srb->cmd->serial_number); + dprintkdbg(DBG_0, "msgout_phase0: (0x%p)\n", srb->cmd); if (srb->state & (SRB_UNEXPECT_RESEL + SRB_ABORT_SENT)) *pscsi_status = PH_BUS_FREE; /*.. initial phase */ @@ -1857,18 +1856,18 @@ static void msgout_phase1(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb, { u16 i; u8 *ptr; - dprintkdbg(DBG_0, "msgout_phase1: (pid#%li)\n", srb->cmd->serial_number); + dprintkdbg(DBG_0, "msgout_phase1: (0x%p)\n", srb->cmd); clear_fifo(acb, "msgout_phase1"); if (!(srb->state & SRB_MSGOUT)) { srb->state |= SRB_MSGOUT; dprintkl(KERN_DEBUG, - "msgout_phase1: (pid#%li) Phase unexpected\n", - srb->cmd->serial_number); /* So what ? */ + "msgout_phase1: (0x%p) Phase unexpected\n", + srb->cmd); /* So what ? */ } if (!srb->msg_count) { - dprintkdbg(DBG_0, "msgout_phase1: (pid#%li) NOP msg\n", - srb->cmd->serial_number); + dprintkdbg(DBG_0, "msgout_phase1: (0x%p) NOP msg\n", + srb->cmd); DC395x_write8(acb, TRM_S1040_SCSI_FIFO, MSG_NOP); DC395x_write16(acb, TRM_S1040_SCSI_CONTROL, DO_DATALATCH); /* it's important for atn stop */ DC395x_write8(acb, TRM_S1040_SCSI_COMMAND, SCMD_FIFO_OUT); @@ -1888,7 +1887,7 @@ static void msgout_phase1(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb, static void command_phase0(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb, u16 *pscsi_status) { - dprintkdbg(DBG_0, "command_phase0: (pid#%li)\n", srb->cmd->serial_number); + dprintkdbg(DBG_0, "command_phase0: (0x%p)\n", srb->cmd); DC395x_write16(acb, TRM_S1040_SCSI_CONTROL, DO_DATALATCH); } @@ -1899,7 +1898,7 @@ static void command_phase1(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb, struct DeviceCtlBlk *dcb; u8 *ptr; u16 i; - dprintkdbg(DBG_0, "command_phase1: (pid#%li)\n", srb->cmd->serial_number); + dprintkdbg(DBG_0, "command_phase1: (0x%p)\n", srb->cmd); clear_fifo(acb, "command_phase1"); DC395x_write16(acb, TRM_S1040_SCSI_CONTROL, DO_CLRATN); @@ -2041,8 +2040,8 @@ static void data_out_phase0(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb, struct DeviceCtlBlk *dcb = srb->dcb; u16 scsi_status = *pscsi_status; u32 d_left_counter = 0; - dprintkdbg(DBG_0, "data_out_phase0: (pid#%li) <%02i-%i>\n", - srb->cmd->serial_number, srb->cmd->device->id, srb->cmd->device->lun); + dprintkdbg(DBG_0, "data_out_phase0: (0x%p) <%02i-%i>\n", + srb->cmd, srb->cmd->device->id, srb->cmd->device->lun); /* * KG: We need to drain the buffers before we draw any conclusions! @@ -2171,8 +2170,8 @@ static void data_out_phase0(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb, static void data_out_phase1(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb, u16 *pscsi_status) { - dprintkdbg(DBG_0, "data_out_phase1: (pid#%li) <%02i-%i>\n", - srb->cmd->serial_number, srb->cmd->device->id, srb->cmd->device->lun); + dprintkdbg(DBG_0, "data_out_phase1: (0x%p) <%02i-%i>\n", + srb->cmd, srb->cmd->device->id, srb->cmd->device->lun); clear_fifo(acb, "data_out_phase1"); /* do prepare before transfer when data out phase */ data_io_transfer(acb, srb, XFERDATAOUT); @@ -2183,8 +2182,8 @@ static void data_in_phase0(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb, { u16 scsi_status = *pscsi_status; - dprintkdbg(DBG_0, "data_in_phase0: (pid#%li) <%02i-%i>\n", - srb->cmd->serial_number, srb->cmd->device->id, srb->cmd->device->lun); + dprintkdbg(DBG_0, "data_in_phase0: (0x%p) <%02i-%i>\n", + srb->cmd, srb->cmd->device->id, srb->cmd->device->lun); /* * KG: DataIn is much more tricky than DataOut. When the device is finished @@ -2204,8 +2203,8 @@ static void data_in_phase0(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb, unsigned int sc, fc; if (scsi_status & PARITYERROR) { - dprintkl(KERN_INFO, "data_in_phase0: (pid#%li) " - "Parity Error\n", srb->cmd->serial_number); + dprintkl(KERN_INFO, "data_in_phase0: (0x%p) " + "Parity Error\n", srb->cmd); srb->status |= PARITY_ERROR; } /* @@ -2394,8 +2393,8 @@ static void data_in_phase0(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb, static void data_in_phase1(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb, u16 *pscsi_status) { - dprintkdbg(DBG_0, "data_in_phase1: (pid#%li) <%02i-%i>\n", - srb->cmd->serial_number, srb->cmd->device->id, srb->cmd->device->lun); + dprintkdbg(DBG_0, "data_in_phase1: (0x%p) <%02i-%i>\n", + srb->cmd, srb->cmd->device->id, srb->cmd->device->lun); data_io_transfer(acb, srb, XFERDATAIN); } @@ -2406,8 +2405,8 @@ static void data_io_transfer(struct AdapterCtlBlk *acb, struct DeviceCtlBlk *dcb = srb->dcb; u8 bval; dprintkdbg(DBG_0, - "data_io_transfer: (pid#%li) <%02i-%i> %c len=%i, sg=(%i/%i)\n", - srb->cmd->serial_number, srb->cmd->device->id, srb->cmd->device->lun, + "data_io_transfer: (0x%p) <%02i-%i> %c len=%i, sg=(%i/%i)\n", + srb->cmd, srb->cmd->device->id, srb->cmd->device->lun, ((io_dir & DMACMD_DIR) ? 'r' : 'w'), srb->total_xfer_length, srb->sg_index, srb->sg_count); if (srb == acb->tmp_srb) @@ -2579,8 +2578,8 @@ static void data_io_transfer(struct AdapterCtlBlk *acb, static void status_phase0(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb, u16 *pscsi_status) { - dprintkdbg(DBG_0, "status_phase0: (pid#%li) <%02i-%i>\n", - srb->cmd->serial_number, srb->cmd->device->id, srb->cmd->device->lun); + dprintkdbg(DBG_0, "status_phase0: (0x%p) <%02i-%i>\n", + srb->cmd, srb->cmd->device->id, srb->cmd->device->lun); srb->target_status = DC395x_read8(acb, TRM_S1040_SCSI_FIFO); srb->end_message = DC395x_read8(acb, TRM_S1040_SCSI_FIFO); /* get message */ srb->state = SRB_COMPLETED; @@ -2593,8 +2592,8 @@ static void status_phase0(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb, static void status_phase1(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb, u16 *pscsi_status) { - dprintkdbg(DBG_0, "status_phase1: (pid#%li) <%02i-%i>\n", - srb->cmd->serial_number, srb->cmd->device->id, srb->cmd->device->lun); + dprintkdbg(DBG_0, "status_phase1: (0x%p) <%02i-%i>\n", + srb->cmd, srb->cmd->device->id, srb->cmd->device->lun); srb->state = SRB_STATUS; DC395x_write16(acb, TRM_S1040_SCSI_CONTROL, DO_DATALATCH); /* it's important for atn stop */ DC395x_write8(acb, TRM_S1040_SCSI_COMMAND, SCMD_COMP); @@ -2635,8 +2634,8 @@ static struct ScsiReqBlk *msgin_qtag(struct AdapterCtlBlk *acb, { struct ScsiReqBlk *srb = NULL; struct ScsiReqBlk *i; - dprintkdbg(DBG_0, "msgin_qtag: (pid#%li) tag=%i srb=%p\n", - srb->cmd->serial_number, tag, srb); + dprintkdbg(DBG_0, "msgin_qtag: (0x%p) tag=%i srb=%p\n", + srb->cmd, tag, srb); if (!(dcb->tag_mask & (1 << tag))) dprintkl(KERN_DEBUG, @@ -2654,8 +2653,8 @@ static struct ScsiReqBlk *msgin_qtag(struct AdapterCtlBlk *acb, if (!srb) goto mingx0; - dprintkdbg(DBG_0, "msgin_qtag: (pid#%li) <%02i-%i>\n", - srb->cmd->serial_number, srb->dcb->target_id, srb->dcb->target_lun); + dprintkdbg(DBG_0, "msgin_qtag: (0x%p) <%02i-%i>\n", + srb->cmd, srb->dcb->target_id, srb->dcb->target_lun); if (dcb->flag & ABORT_DEV_) { /*srb->state = SRB_ABORT_SENT; */ enable_msgout_abort(acb, srb); @@ -2865,7 +2864,7 @@ static void msgin_phase0(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb, u16 *pscsi_status) { struct DeviceCtlBlk *dcb = acb->active_dcb; - dprintkdbg(DBG_0, "msgin_phase0: (pid#%li)\n", srb->cmd->serial_number); + dprintkdbg(DBG_0, "msgin_phase0: (0x%p)\n", srb->cmd); srb->msgin_buf[acb->msg_len++] = DC395x_read8(acb, TRM_S1040_SCSI_FIFO); if (msgin_completed(srb->msgin_buf, acb->msg_len)) { @@ -2931,9 +2930,9 @@ static void msgin_phase0(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb, * SAVE POINTER may be ignored as we have the struct * ScsiReqBlk* associated with the scsi command. */ - dprintkdbg(DBG_0, "msgin_phase0: (pid#%li) " + dprintkdbg(DBG_0, "msgin_phase0: (0x%p) " "SAVE POINTER rem=%i Ignore\n", - srb->cmd->serial_number, srb->total_xfer_length); + srb->cmd, srb->total_xfer_length); break; case RESTORE_POINTERS: @@ -2941,9 +2940,9 @@ static void msgin_phase0(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb, break; case ABORT: - dprintkdbg(DBG_0, "msgin_phase0: (pid#%li) " + dprintkdbg(DBG_0, "msgin_phase0: (0x%p) " "<%02i-%i> ABORT msg\n", - srb->cmd->serial_number, dcb->target_id, + srb->cmd, dcb->target_id, dcb->target_lun); dcb->flag |= ABORT_DEV_; enable_msgout_abort(acb, srb); @@ -2975,7 +2974,7 @@ static void msgin_phase0(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb, static void msgin_phase1(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb, u16 *pscsi_status) { - dprintkdbg(DBG_0, "msgin_phase1: (pid#%li)\n", srb->cmd->serial_number); + dprintkdbg(DBG_0, "msgin_phase1: (0x%p)\n", srb->cmd); clear_fifo(acb, "msgin_phase1"); DC395x_write32(acb, TRM_S1040_SCSI_COUNTER, 1); if (!(srb->state & SRB_MSGIN)) { @@ -3041,7 +3040,7 @@ static void disconnect(struct AdapterCtlBlk *acb) } srb = dcb->active_srb; acb->active_dcb = NULL; - dprintkdbg(DBG_0, "disconnect: (pid#%li)\n", srb->cmd->serial_number); + dprintkdbg(DBG_0, "disconnect: (0x%p)\n", srb->cmd); srb->scsi_phase = PH_BUS_FREE; /* initial phase */ clear_fifo(acb, "disconnect"); @@ -3071,14 +3070,14 @@ static void disconnect(struct AdapterCtlBlk *acb) && srb->state != SRB_MSGOUT) { srb->state = SRB_READY; dprintkl(KERN_DEBUG, - "disconnect: (pid#%li) Unexpected\n", - srb->cmd->serial_number); + "disconnect: (0x%p) Unexpected\n", + srb->cmd); srb->target_status = SCSI_STAT_SEL_TIMEOUT; goto disc1; } else { /* Normal selection timeout */ - dprintkdbg(DBG_KG, "disconnect: (pid#%li) " - "<%02i-%i> SelTO\n", srb->cmd->serial_number, + dprintkdbg(DBG_KG, "disconnect: (0x%p) " + "<%02i-%i> SelTO\n", srb->cmd, dcb->target_id, dcb->target_lun); if (srb->retry_count++ > DC395x_MAX_RETRIES || acb->scan_devices) { @@ -3089,8 +3088,8 @@ static void disconnect(struct AdapterCtlBlk *acb) free_tag(dcb, srb); srb_going_to_waiting_move(dcb, srb); dprintkdbg(DBG_KG, - "disconnect: (pid#%li) Retry\n", - srb->cmd->serial_number); + "disconnect: (0x%p) Retry\n", + srb->cmd); waiting_set_timer(acb, HZ / 20); } } else if (srb->state & SRB_DISCONNECT) { @@ -3142,9 +3141,9 @@ static void reselect(struct AdapterCtlBlk *acb) } /* Why the if ? */ if (!acb->scan_devices) { - dprintkdbg(DBG_KG, "reselect: (pid#%li) <%02i-%i> " + dprintkdbg(DBG_KG, "reselect: (0x%p) <%02i-%i> " "Arb lost but Resel win rsel=%i stat=0x%04x\n", - srb->cmd->serial_number, dcb->target_id, + srb->cmd, dcb->target_id, dcb->target_lun, rsel_tar_lun_id, DC395x_read16(acb, TRM_S1040_SCSI_STATUS)); arblostflag = 1; @@ -3318,7 +3317,7 @@ static void srb_done(struct AdapterCtlBlk *acb, struct DeviceCtlBlk *dcb, enum dma_data_direction dir = cmd->sc_data_direction; int ckc_only = 1; - dprintkdbg(DBG_1, "srb_done: (pid#%li) <%02i-%i>\n", srb->cmd->serial_number, + dprintkdbg(DBG_1, "srb_done: (0x%p) <%02i-%i>\n", srb->cmd, srb->cmd->device->id, srb->cmd->device->lun); dprintkdbg(DBG_SG, "srb_done: srb=%p sg=%i(%i/%i) buf=%p\n", srb, scsi_sg_count(cmd), srb->sg_index, srb->sg_count, @@ -3497,9 +3496,9 @@ static void srb_done(struct AdapterCtlBlk *acb, struct DeviceCtlBlk *dcb, cmd->SCp.buffers_residual = 0; if (debug_enabled(DBG_KG)) { if (srb->total_xfer_length) - dprintkdbg(DBG_KG, "srb_done: (pid#%li) <%02i-%i> " + dprintkdbg(DBG_KG, "srb_done: (0x%p) <%02i-%i> " "cmnd=0x%02x Missed %i bytes\n", - cmd->serial_number, cmd->device->id, cmd->device->lun, + cmd, cmd->device->id, cmd->device->lun, cmd->cmnd[0], srb->total_xfer_length); } @@ -3508,8 +3507,8 @@ static void srb_done(struct AdapterCtlBlk *acb, struct DeviceCtlBlk *dcb, if (srb == acb->tmp_srb) dprintkl(KERN_ERR, "srb_done: ERROR! Completed cmd with tmp_srb\n"); else { - dprintkdbg(DBG_0, "srb_done: (pid#%li) done result=0x%08x\n", - cmd->serial_number, cmd->result); + dprintkdbg(DBG_0, "srb_done: (0x%p) done result=0x%08x\n", + cmd, cmd->result); srb_free_insert(acb, srb); } pci_unmap_srb(acb, srb); @@ -3538,7 +3537,7 @@ static void doing_srb_done(struct AdapterCtlBlk *acb, u8 did_flag, p = srb->cmd; dir = p->sc_data_direction; result = MK_RES(0, did_flag, 0, 0); - printk("G:%li(%02i-%i) ", p->serial_number, + printk("G:%p(%02i-%i) ", p, p->device->id, p->device->lun); srb_going_remove(dcb, srb); free_tag(dcb, srb); @@ -3568,7 +3567,7 @@ static void doing_srb_done(struct AdapterCtlBlk *acb, u8 did_flag, p = srb->cmd; result = MK_RES(0, did_flag, 0, 0); - printk("W:%li<%02i-%i>", p->serial_number, p->device->id, + printk("W:%p<%02i-%i>", p, p->device->id, p->device->lun); srb_waiting_remove(dcb, srb); srb_free_insert(acb, srb); @@ -3677,8 +3676,8 @@ static void request_sense(struct AdapterCtlBlk *acb, struct DeviceCtlBlk *dcb, struct ScsiReqBlk *srb) { struct scsi_cmnd *cmd = srb->cmd; - dprintkdbg(DBG_1, "request_sense: (pid#%li) <%02i-%i>\n", - cmd->serial_number, cmd->device->id, cmd->device->lun); + dprintkdbg(DBG_1, "request_sense: (0x%p) <%02i-%i>\n", + cmd, cmd->device->id, cmd->device->lun); srb->flag |= AUTO_REQSENSE; srb->adapter_status = 0; @@ -3708,8 +3707,8 @@ static void request_sense(struct AdapterCtlBlk *acb, struct DeviceCtlBlk *dcb, if (start_scsi(acb, dcb, srb)) { /* Should only happen, if sb. else grabs the bus */ dprintkl(KERN_DEBUG, - "request_sense: (pid#%li) failed <%02i-%i>\n", - srb->cmd->serial_number, dcb->target_id, dcb->target_lun); + "request_sense: (0x%p) failed <%02i-%i>\n", + srb->cmd, dcb->target_id, dcb->target_lun); srb_going_to_waiting_move(dcb, srb); waiting_set_timer(acb, HZ / 100); } @@ -4717,13 +4716,13 @@ static int dc395x_proc_info(struct Scsi_Host *host, char *buffer, dcb->target_id, dcb->target_lun, list_size(&dcb->srb_waiting_list)); list_for_each_entry(srb, &dcb->srb_waiting_list, list) - SPRINTF(" %li", srb->cmd->serial_number); + SPRINTF(" %p", srb->cmd); if (!list_empty(&dcb->srb_going_list)) SPRINTF("\nDCB (%02i-%i): Going : %i:", dcb->target_id, dcb->target_lun, list_size(&dcb->srb_going_list)); list_for_each_entry(srb, &dcb->srb_going_list, list) - SPRINTF(" %li", srb->cmd->serial_number); + SPRINTF(" %p", srb->cmd); if (!list_empty(&dcb->srb_waiting_list) || !list_empty(&dcb->srb_going_list)) SPRINTF("\n"); } diff --git a/drivers/scsi/dpt_i2o.c b/drivers/scsi/dpt_i2o.c index cffcb10..b4f6c9a 100644 --- a/drivers/scsi/dpt_i2o.c +++ b/drivers/scsi/dpt_i2o.c @@ -780,7 +780,7 @@ static int adpt_abort(struct scsi_cmnd * cmd) return FAILED; } pHba = (adpt_hba*) cmd->device->host->hostdata[0]; - printk(KERN_INFO"%s: Trying to Abort cmd=%ld\n",pHba->name, cmd->serial_number); + printk(KERN_INFO"%s: Trying to Abort\n",pHba->name); if ((dptdevice = (void*) (cmd->device->hostdata)) == NULL) { printk(KERN_ERR "%s: Unable to abort: No device in cmnd\n",pHba->name); return FAILED; @@ -802,10 +802,10 @@ static int adpt_abort(struct scsi_cmnd * cmd) printk(KERN_INFO"%s: Abort cmd not supported\n",pHba->name); return FAILED; } - printk(KERN_INFO"%s: Abort cmd=%ld failed.\n",pHba->name, cmd->serial_number); + printk(KERN_INFO"%s: Abort failed.\n",pHba->name); return FAILED; } - printk(KERN_INFO"%s: Abort cmd=%ld complete.\n",pHba->name, cmd->serial_number); + printk(KERN_INFO"%s: Abort complete.\n",pHba->name); return SUCCESS; } diff --git a/drivers/scsi/eata.c b/drivers/scsi/eata.c index 0eb4fe6..94de889 100644 --- a/drivers/scsi/eata.c +++ b/drivers/scsi/eata.c @@ -1766,8 +1766,8 @@ static int eata2x_queuecommand_lck(struct scsi_cmnd *SCpnt, struct mscp *cpp; if (SCpnt->host_scribble) - panic("%s: qcomm, pid %ld, SCpnt %p already active.\n", - ha->board_name, SCpnt->serial_number, SCpnt); + panic("%s: qcomm, SCpnt %p already active.\n", + ha->board_name, SCpnt); /* i is the mailbox number, look for the first free mailbox starting from last_cp_used */ @@ -1801,7 +1801,7 @@ static int eata2x_queuecommand_lck(struct scsi_cmnd *SCpnt, if (do_trace) scmd_printk(KERN_INFO, SCpnt, - "qcomm, mbox %d, pid %ld.\n", i, SCpnt->serial_number); + "qcomm, mbox %d.\n", i); cpp->reqsen = 1; cpp->dispri = 1; @@ -1833,8 +1833,7 @@ static int eata2x_queuecommand_lck(struct scsi_cmnd *SCpnt, if (do_dma(shost->io_port, cpp->cp_dma_addr, SEND_CP_DMA)) { unmap_dma(i, ha); SCpnt->host_scribble = NULL; - scmd_printk(KERN_INFO, SCpnt, - "qcomm, pid %ld, adapter busy.\n", SCpnt->serial_number); + scmd_printk(KERN_INFO, SCpnt, "qcomm, adapter busy.\n"); return 1; } @@ -1851,14 +1850,12 @@ static int eata2x_eh_abort(struct scsi_cmnd *SCarg) unsigned int i; if (SCarg->host_scribble == NULL) { - scmd_printk(KERN_INFO, SCarg, - "abort, pid %ld inactive.\n", SCarg->serial_number); + scmd_printk(KERN_INFO, SCarg, "abort, cmd inactive.\n"); return SUCCESS; } i = *(unsigned int *)SCarg->host_scribble; - scmd_printk(KERN_WARNING, SCarg, - "abort, mbox %d, pid %ld.\n", i, SCarg->serial_number); + scmd_printk(KERN_WARNING, SCarg, "abort, mbox %d.\n", i); if (i >= shost->can_queue) panic("%s: abort, invalid SCarg->host_scribble.\n", ha->board_name); @@ -1902,8 +1899,8 @@ static int eata2x_eh_abort(struct scsi_cmnd *SCarg) SCarg->result = DID_ABORT << 16; SCarg->host_scribble = NULL; ha->cp_stat[i] = FREE; - printk("%s, abort, mbox %d ready, DID_ABORT, pid %ld done.\n", - ha->board_name, i, SCarg->serial_number); + printk("%s, abort, mbox %d ready, DID_ABORT, done.\n", + ha->board_name, i); SCarg->scsi_done(SCarg); return SUCCESS; } @@ -1919,13 +1916,12 @@ static int eata2x_eh_host_reset(struct scsi_cmnd *SCarg) struct Scsi_Host *shost = SCarg->device->host; struct hostdata *ha = (struct hostdata *)shost->hostdata; - scmd_printk(KERN_INFO, SCarg, - "reset, enter, pid %ld.\n", SCarg->serial_number); + scmd_printk(KERN_INFO, SCarg, "reset, enter.\n"); spin_lock_irq(shost->host_lock); if (SCarg->host_scribble == NULL) - printk("%s: reset, pid %ld inactive.\n", ha->board_name, SCarg->serial_number); + printk("%s: reset, inactive.\n", ha->board_name); if (ha->in_reset) { printk("%s: reset, exit, already in reset.\n", ha->board_name); @@ -1964,14 +1960,14 @@ static int eata2x_eh_host_reset(struct scsi_cmnd *SCarg) if (ha->cp_stat[i] == READY || ha->cp_stat[i] == ABORTING) { ha->cp_stat[i] = ABORTING; - printk("%s: reset, mbox %d aborting, pid %ld.\n", - ha->board_name, i, SCpnt->serial_number); + printk("%s: reset, mbox %d aborting.\n", + ha->board_name, i); } else { ha->cp_stat[i] = IN_RESET; - printk("%s: reset, mbox %d in reset, pid %ld.\n", - ha->board_name, i, SCpnt->serial_number); + printk("%s: reset, mbox %d in reset.\n", + ha->board_name, i); } if (SCpnt->host_scribble == NULL) @@ -2025,8 +2021,8 @@ static int eata2x_eh_host_reset(struct scsi_cmnd *SCarg) ha->cp_stat[i] = LOCKED; printk - ("%s, reset, mbox %d locked, DID_RESET, pid %ld done.\n", - ha->board_name, i, SCpnt->serial_number); + ("%s, reset, mbox %d locked, DID_RESET, done.\n", + ha->board_name, i); } else if (ha->cp_stat[i] == ABORTING) { @@ -2039,8 +2035,8 @@ static int eata2x_eh_host_reset(struct scsi_cmnd *SCarg) ha->cp_stat[i] = FREE; printk - ("%s, reset, mbox %d aborting, DID_RESET, pid %ld done.\n", - ha->board_name, i, SCpnt->serial_number); + ("%s, reset, mbox %d aborting, DID_RESET, done.\n", + ha->board_name, i); } else @@ -2054,7 +2050,7 @@ static int eata2x_eh_host_reset(struct scsi_cmnd *SCarg) do_trace = 0; if (arg_done) - printk("%s: reset, exit, pid %ld done.\n", ha->board_name, SCarg->serial_number); + printk("%s: reset, exit, done.\n", ha->board_name); else printk("%s: reset, exit.\n", ha->board_name); @@ -2238,10 +2234,10 @@ static int reorder(struct hostdata *ha, unsigned long cursec, cpp = &ha->cp[k]; SCpnt = cpp->SCpnt; scmd_printk(KERN_INFO, SCpnt, - "%s pid %ld mb %d fc %d nr %d sec %ld ns %u" + "%s mb %d fc %d nr %d sec %ld ns %u" " cur %ld s:%c r:%c rev:%c in:%c ov:%c xd %d.\n", (ihdlr ? "ihdlr" : "qcomm"), - SCpnt->serial_number, k, flushcount, + k, flushcount, n_ready, blk_rq_pos(SCpnt->request), blk_rq_sectors(SCpnt->request), cursec, YESNO(s), YESNO(r), YESNO(rev), YESNO(input_only), @@ -2285,10 +2281,10 @@ static void flush_dev(struct scsi_device *dev, unsigned long cursec, if (do_dma(dev->host->io_port, cpp->cp_dma_addr, SEND_CP_DMA)) { scmd_printk(KERN_INFO, SCpnt, - "%s, pid %ld, mbox %d, adapter" + "%s, mbox %d, adapter" " busy, will abort.\n", (ihdlr ? "ihdlr" : "qcomm"), - SCpnt->serial_number, k); + k); ha->cp_stat[k] = ABORTING; continue; } @@ -2398,12 +2394,12 @@ static irqreturn_t ihdlr(struct Scsi_Host *shost) panic("%s: ihdlr, mbox %d, SCpnt == NULL.\n", ha->board_name, i); if (SCpnt->host_scribble == NULL) - panic("%s: ihdlr, mbox %d, pid %ld, SCpnt %p garbled.\n", ha->board_name, - i, SCpnt->serial_number, SCpnt); + panic("%s: ihdlr, mbox %d, SCpnt %p garbled.\n", ha->board_name, + i, SCpnt); if (*(unsigned int *)SCpnt->host_scribble != i) - panic("%s: ihdlr, mbox %d, pid %ld, index mismatch %d.\n", - ha->board_name, i, SCpnt->serial_number, + panic("%s: ihdlr, mbox %d, index mismatch %d.\n", + ha->board_name, i, *(unsigned int *)SCpnt->host_scribble); sync_dma(i, ha); @@ -2449,11 +2445,11 @@ static irqreturn_t ihdlr(struct Scsi_Host *shost) if (spp->target_status && SCpnt->device->type == TYPE_DISK && (!(tstatus == CHECK_CONDITION && ha->iocount <= 1000 && (SCpnt->sense_buffer[2] & 0xf) == NOT_READY))) - printk("%s: ihdlr, target %d.%d:%d, pid %ld, " + printk("%s: ihdlr, target %d.%d:%d, " "target_status 0x%x, sense key 0x%x.\n", ha->board_name, SCpnt->device->channel, SCpnt->device->id, - SCpnt->device->lun, SCpnt->serial_number, + SCpnt->device->lun, spp->target_status, SCpnt->sense_buffer[2]); ha->target_to[SCpnt->device->id][SCpnt->device->channel] = 0; @@ -2522,9 +2518,9 @@ static irqreturn_t ihdlr(struct Scsi_Host *shost) do_trace || msg_byte(spp->target_status)) #endif scmd_printk(KERN_INFO, SCpnt, "ihdlr, mbox %2d, err 0x%x:%x," - " pid %ld, reg 0x%x, count %d.\n", + " reg 0x%x, count %d.\n", i, spp->adapter_status, spp->target_status, - SCpnt->serial_number, reg, ha->iocount); + reg, ha->iocount); unmap_dma(i, ha); diff --git a/drivers/scsi/eata_pio.c b/drivers/scsi/eata_pio.c index 4a9641e..d5f8362 100644 --- a/drivers/scsi/eata_pio.c +++ b/drivers/scsi/eata_pio.c @@ -372,8 +372,7 @@ static int eata_pio_queue_lck(struct scsi_cmnd *cmd, cp->status = USED; /* claim free slot */ DBG(DBG_QUEUE, scmd_printk(KERN_DEBUG, cmd, - "eata_pio_queue pid %ld, y %d\n", - cmd->serial_number, y)); + "eata_pio_queue 0x%p, y %d\n", cmd, y)); cmd->scsi_done = (void *) done; @@ -417,8 +416,8 @@ static int eata_pio_queue_lck(struct scsi_cmnd *cmd, if (eata_pio_send_command(base, EATA_CMD_PIO_SEND_CP)) { cmd->result = DID_BUS_BUSY << 16; scmd_printk(KERN_NOTICE, cmd, - "eata_pio_queue pid %ld, HBA busy, " - "returning DID_BUS_BUSY, done.\n", cmd->serial_number); + "eata_pio_queue pid 0x%p, HBA busy, " + "returning DID_BUS_BUSY, done.\n", cmd); done(cmd); cp->status = FREE; return 0; @@ -432,8 +431,8 @@ static int eata_pio_queue_lck(struct scsi_cmnd *cmd, outw(0, base + HA_RDATA); DBG(DBG_QUEUE, scmd_printk(KERN_DEBUG, cmd, - "Queued base %#.4lx pid: %ld " - "slot %d irq %d\n", sh->base, cmd->serial_number, y, sh->irq)); + "Queued base %#.4lx cmd: 0x%p " + "slot %d irq %d\n", sh->base, cmd, y, sh->irq)); return 0; } @@ -445,8 +444,7 @@ static int eata_pio_abort(struct scsi_cmnd *cmd) unsigned int loop = 100; DBG(DBG_ABNORM, scmd_printk(KERN_WARNING, cmd, - "eata_pio_abort called pid: %ld\n", - cmd->serial_number)); + "eata_pio_abort called pid: 0x%p\n", cmd)); while (inb(cmd->device->host->base + HA_RAUXSTAT) & HA_ABUSY) if (--loop == 0) { @@ -481,8 +479,7 @@ static int eata_pio_host_reset(struct scsi_cmnd *cmd) struct Scsi_Host *host = cmd->device->host; DBG(DBG_ABNORM, scmd_printk(KERN_WARNING, cmd, - "eata_pio_reset called pid:%ld\n", - cmd->serial_number)); + "eata_pio_reset called\n")); spin_lock_irq(host->host_lock); @@ -501,7 +498,7 @@ static int eata_pio_host_reset(struct scsi_cmnd *cmd) sp = HD(cmd)->ccb[x].cmd; HD(cmd)->ccb[x].status = RESET; - printk(KERN_WARNING "eata_pio_reset: slot %d in reset, pid %ld.\n", x, sp->serial_number); + printk(KERN_WARNING "eata_pio_reset: slot %d in reset.\n", x); if (sp == NULL) panic("eata_pio_reset: slot %d, sp==NULL.\n", x); diff --git a/drivers/scsi/in2000.c b/drivers/scsi/in2000.c index 6568aab..92109b1 100644 --- a/drivers/scsi/in2000.c +++ b/drivers/scsi/in2000.c @@ -343,7 +343,7 @@ static int in2000_queuecommand_lck(Scsi_Cmnd * cmd, void (*done) (Scsi_Cmnd *)) instance = cmd->device->host; hostdata = (struct IN2000_hostdata *) instance->hostdata; - DB(DB_QUEUE_COMMAND, scmd_printk(KERN_DEBUG, cmd, "Q-%02x-%ld(", cmd->cmnd[0], cmd->serial_number)) + DB(DB_QUEUE_COMMAND, scmd_printk(KERN_DEBUG, cmd, "Q-%02x(", cmd->cmnd[0])) /* Set up a few fields in the Scsi_Cmnd structure for our own use: * - host_scribble is the pointer to the next cmd in the input queue @@ -427,7 +427,7 @@ static int in2000_queuecommand_lck(Scsi_Cmnd * cmd, void (*done) (Scsi_Cmnd *)) in2000_execute(cmd->device->host); - DB(DB_QUEUE_COMMAND, printk(")Q-%ld ", cmd->serial_number)) + DB(DB_QUEUE_COMMAND, printk(")Q ")) return 0; } @@ -705,7 +705,7 @@ static void in2000_execute(struct Scsi_Host *instance) * to search the input_Q again... */ - DB(DB_EXECUTE, printk("%s%ld)EX-2 ", (cmd->SCp.phase) ? "d:" : "", cmd->serial_number)) + DB(DB_EXECUTE, printk("%s)EX-2 ", (cmd->SCp.phase) ? "d:" : "")) } @@ -1149,7 +1149,7 @@ static irqreturn_t in2000_intr(int irqnum, void *dev_id) case CSR_XFER_DONE | PHS_COMMAND: case CSR_UNEXP | PHS_COMMAND: case CSR_SRV_REQ | PHS_COMMAND: - DB(DB_INTR, printk("CMND-%02x,%ld", cmd->cmnd[0], cmd->serial_number)) + DB(DB_INTR, printk("CMND-%02x", cmd->cmnd[0])) transfer_pio(cmd->cmnd, cmd->cmd_len, DATA_OUT_DIR, hostdata); hostdata->state = S_CONNECTED; break; @@ -1191,7 +1191,7 @@ static irqreturn_t in2000_intr(int irqnum, void *dev_id) switch (msg) { case COMMAND_COMPLETE: - DB(DB_INTR, printk("CCMP-%ld", cmd->serial_number)) + DB(DB_INTR, printk("CCMP")) write_3393_cmd(hostdata, WD_CMD_NEGATE_ACK); hostdata->state = S_PRE_CMP_DISC; break; @@ -1329,7 +1329,7 @@ static irqreturn_t in2000_intr(int irqnum, void *dev_id) write_3393(hostdata, WD_SOURCE_ID, SRCID_ER); if (phs == 0x60) { - DB(DB_INTR, printk("SX-DONE-%ld", cmd->serial_number)) + DB(DB_INTR, printk("SX-DONE")) cmd->SCp.Message = COMMAND_COMPLETE; lun = read_3393(hostdata, WD_TARGET_LUN); DB(DB_INTR, printk(":%d.%d", cmd->SCp.Status, lun)) @@ -1350,7 +1350,7 @@ static irqreturn_t in2000_intr(int irqnum, void *dev_id) in2000_execute(instance); } else { - printk("%02x:%02x:%02x-%ld: Unknown SEL_XFER_DONE phase!!---", asr, sr, phs, cmd->serial_number); + printk("%02x:%02x:%02x: Unknown SEL_XFER_DONE phase!!---", asr, sr, phs); } break; @@ -1417,7 +1417,7 @@ static irqreturn_t in2000_intr(int irqnum, void *dev_id) spin_unlock_irqrestore(instance->host_lock, flags); return IRQ_HANDLED; } - DB(DB_INTR, printk("UNEXP_DISC-%ld", cmd->serial_number)) + DB(DB_INTR, printk("UNEXP_DISC")) hostdata->connected = NULL; hostdata->busy[cmd->device->id] &= ~(1 << cmd->device->lun); hostdata->state = S_UNCONNECTED; @@ -1442,7 +1442,7 @@ static irqreturn_t in2000_intr(int irqnum, void *dev_id) */ write_3393(hostdata, WD_SOURCE_ID, SRCID_ER); - DB(DB_INTR, printk("DISC-%ld", cmd->serial_number)) + DB(DB_INTR, printk("DISC")) if (cmd == NULL) { printk(" - Already disconnected! "); hostdata->state = S_UNCONNECTED; @@ -1575,7 +1575,6 @@ static irqreturn_t in2000_intr(int irqnum, void *dev_id) } else hostdata->state = S_CONNECTED; - DB(DB_INTR, printk("-%ld", cmd->serial_number)) break; default: @@ -1704,7 +1703,7 @@ static int __in2000_abort(Scsi_Cmnd * cmd) prev->host_scribble = cmd->host_scribble; cmd->host_scribble = NULL; cmd->result = DID_ABORT << 16; - printk(KERN_WARNING "scsi%d: Abort - removing command %ld from input_Q. ", instance->host_no, cmd->serial_number); + printk(KERN_WARNING "scsi%d: Abort - removing command from input_Q. ", instance->host_no); cmd->scsi_done(cmd); return SUCCESS; } @@ -1725,7 +1724,7 @@ static int __in2000_abort(Scsi_Cmnd * cmd) if (hostdata->connected == cmd) { - printk(KERN_WARNING "scsi%d: Aborting connected command %ld - ", instance->host_no, cmd->serial_number); + printk(KERN_WARNING "scsi%d: Aborting connected command - ", instance->host_no); printk("sending wd33c93 ABORT command - "); write_3393(hostdata, WD_CONTROL, CTRL_IDI | CTRL_EDI | CTRL_POLLED); @@ -2270,7 +2269,7 @@ static int in2000_proc_info(struct Scsi_Host *instance, char *buf, char **start, strcat(bp, "\nconnected: "); if (hd->connected) { cmd = (Scsi_Cmnd *) hd->connected; - sprintf(tbuf, " %ld-%d:%d(%02x)", cmd->serial_number, cmd->device->id, cmd->device->lun, cmd->cmnd[0]); + sprintf(tbuf, " %d:%d(%02x)", cmd->device->id, cmd->device->lun, cmd->cmnd[0]); strcat(bp, tbuf); } } @@ -2278,7 +2277,7 @@ static int in2000_proc_info(struct Scsi_Host *instance, char *buf, char **start, strcat(bp, "\ninput_Q: "); cmd = (Scsi_Cmnd *) hd->input_Q; while (cmd) { - sprintf(tbuf, " %ld-%d:%d(%02x)", cmd->serial_number, cmd->device->id, cmd->device->lun, cmd->cmnd[0]); + sprintf(tbuf, " %d:%d(%02x)", cmd->device->id, cmd->device->lun, cmd->cmnd[0]); strcat(bp, tbuf); cmd = (Scsi_Cmnd *) cmd->host_scribble; } @@ -2287,7 +2286,7 @@ static int in2000_proc_info(struct Scsi_Host *instance, char *buf, char **start, strcat(bp, "\ndisconnected_Q:"); cmd = (Scsi_Cmnd *) hd->disconnected_Q; while (cmd) { - sprintf(tbuf, " %ld-%d:%d(%02x)", cmd->serial_number, cmd->device->id, cmd->device->lun, cmd->cmnd[0]); + sprintf(tbuf, " %d:%d(%02x)", cmd->device->id, cmd->device->lun, cmd->cmnd[0]); strcat(bp, tbuf); cmd = (Scsi_Cmnd *) cmd->host_scribble; } diff --git a/drivers/scsi/lpfc/lpfc_scsi.c b/drivers/scsi/lpfc/lpfc_scsi.c index fe7cc84..84e4481 100644 --- a/drivers/scsi/lpfc/lpfc_scsi.c +++ b/drivers/scsi/lpfc/lpfc_scsi.c @@ -3238,9 +3238,8 @@ lpfc_abort_handler(struct scsi_cmnd *cmnd) if (!lpfc_cmd) { lpfc_printf_vlog(vport, KERN_WARNING, LOG_FCP, "2873 SCSI Layer I/O Abort Request IO CMPL Status " - "x%x ID %d " - "LUN %d snum %#lx\n", ret, cmnd->device->id, - cmnd->device->lun, cmnd->serial_number); + "x%x ID %d LUN %d\n", + ret, cmnd->device->id, cmnd->device->lun); return SUCCESS; } @@ -3318,16 +3317,15 @@ lpfc_abort_handler(struct scsi_cmnd *cmnd) lpfc_printf_vlog(vport, KERN_ERR, LOG_FCP, "0748 abort handler timed out waiting " "for abort to complete: ret %#x, ID %d, " - "LUN %d, snum %#lx\n", - ret, cmnd->device->id, cmnd->device->lun, - cmnd->serial_number); + "LUN %d\n", + ret, cmnd->device->id, cmnd->device->lun); } out: lpfc_printf_vlog(vport, KERN_WARNING, LOG_FCP, "0749 SCSI Layer I/O Abort Request Status x%x ID %d " - "LUN %d snum %#lx\n", ret, cmnd->device->id, - cmnd->device->lun, cmnd->serial_number); + "LUN %d\n", ret, cmnd->device->id, + cmnd->device->lun); return ret; } diff --git a/drivers/scsi/megaraid.c b/drivers/scsi/megaraid.c index f2684dd..5c17764 100644 --- a/drivers/scsi/megaraid.c +++ b/drivers/scsi/megaraid.c @@ -1469,8 +1469,8 @@ mega_cmd_done(adapter_t *adapter, u8 completed[], int nstatus, int status) if( scb->state & SCB_ABORT ) { printk(KERN_WARNING - "megaraid: aborted cmd %lx[%x] complete.\n", - scb->cmd->serial_number, scb->idx); + "megaraid: aborted cmd [%x] complete.\n", + scb->idx); scb->cmd->result = (DID_ABORT << 16); @@ -1488,8 +1488,8 @@ mega_cmd_done(adapter_t *adapter, u8 completed[], int nstatus, int status) if( scb->state & SCB_RESET ) { printk(KERN_WARNING - "megaraid: reset cmd %lx[%x] complete.\n", - scb->cmd->serial_number, scb->idx); + "megaraid: reset cmd [%x] complete.\n", + scb->idx); scb->cmd->result = (DID_RESET << 16); @@ -1958,8 +1958,8 @@ megaraid_abort_and_reset(adapter_t *adapter, Scsi_Cmnd *cmd, int aor) struct list_head *pos, *next; scb_t *scb; - printk(KERN_WARNING "megaraid: %s-%lx cmd=%x \n", - (aor == SCB_ABORT)? "ABORTING":"RESET", cmd->serial_number, + printk(KERN_WARNING "megaraid: %s cmd=%x \n", + (aor == SCB_ABORT)? "ABORTING":"RESET", cmd->cmnd[0], cmd->device->channel, cmd->device->id, cmd->device->lun); @@ -1983,9 +1983,9 @@ megaraid_abort_and_reset(adapter_t *adapter, Scsi_Cmnd *cmd, int aor) if( scb->state & SCB_ISSUED ) { printk(KERN_WARNING - "megaraid: %s-%lx[%x], fw owner.\n", + "megaraid: %s[%x], fw owner.\n", (aor==SCB_ABORT) ? "ABORTING":"RESET", - cmd->serial_number, scb->idx); + scb->idx); return FALSE; } @@ -1996,9 +1996,9 @@ megaraid_abort_and_reset(adapter_t *adapter, Scsi_Cmnd *cmd, int aor) * list */ printk(KERN_WARNING - "megaraid: %s-%lx[%x], driver owner.\n", + "megaraid: %s-[%x], driver owner.\n", (aor==SCB_ABORT) ? "ABORTING":"RESET", - cmd->serial_number, scb->idx); + scb->idx); mega_free_scb(adapter, scb); diff --git a/drivers/scsi/megaraid/megaraid_mbox.c b/drivers/scsi/megaraid/megaraid_mbox.c index 1dba328..2e6619e 100644 --- a/drivers/scsi/megaraid/megaraid_mbox.c +++ b/drivers/scsi/megaraid/megaraid_mbox.c @@ -2315,8 +2315,8 @@ megaraid_mbox_dpc(unsigned long devp) // Was an abort issued for this command earlier if (scb->state & SCB_ABORT) { con_log(CL_ANN, (KERN_NOTICE - "megaraid: aborted cmd %lx[%x] completed\n", - scp->serial_number, scb->sno)); + "megaraid: aborted cmd [%x] completed\n", + scb->sno)); } /* @@ -2472,8 +2472,8 @@ megaraid_abort_handler(struct scsi_cmnd *scp) raid_dev = ADAP2RAIDDEV(adapter); con_log(CL_ANN, (KERN_WARNING - "megaraid: aborting-%ld cmd=%x \n", - scp->serial_number, scp->cmnd[0], SCP2CHANNEL(scp), + "megaraid: aborting cmd=%x \n", + scp->cmnd[0], SCP2CHANNEL(scp), SCP2TARGET(scp), SCP2LUN(scp))); // If FW has stopped responding, simply return failure @@ -2496,9 +2496,8 @@ megaraid_abort_handler(struct scsi_cmnd *scp) list_del_init(&scb->list); // from completed list con_log(CL_ANN, (KERN_WARNING - "megaraid: %ld:%d[%d:%d], abort from completed list\n", - scp->serial_number, scb->sno, - scb->dev_channel, scb->dev_target)); + "megaraid: %d[%d:%d], abort from completed list\n", + scb->sno, scb->dev_channel, scb->dev_target)); scp->result = (DID_ABORT << 16); scp->scsi_done(scp); @@ -2527,9 +2526,8 @@ megaraid_abort_handler(struct scsi_cmnd *scp) ASSERT(!(scb->state & SCB_ISSUED)); con_log(CL_ANN, (KERN_WARNING - "megaraid abort: %ld[%d:%d], driver owner\n", - scp->serial_number, scb->dev_channel, - scb->dev_target)); + "megaraid abort: [%d:%d], driver owner\n", + scb->dev_channel, scb->dev_target)); scp->result = (DID_ABORT << 16); scp->scsi_done(scp); @@ -2560,25 +2558,21 @@ megaraid_abort_handler(struct scsi_cmnd *scp) if (!(scb->state & SCB_ISSUED)) { con_log(CL_ANN, (KERN_WARNING - "megaraid abort: %ld%d[%d:%d], invalid state\n", - scp->serial_number, scb->sno, scb->dev_channel, - scb->dev_target)); + "megaraid abort: %d[%d:%d], invalid state\n", + scb->sno, scb->dev_channel, scb->dev_target)); BUG(); } else { con_log(CL_ANN, (KERN_WARNING - "megaraid abort: %ld:%d[%d:%d], fw owner\n", - scp->serial_number, scb->sno, scb->dev_channel, - scb->dev_target)); + "megaraid abort: %d[%d:%d], fw owner\n", + scb->sno, scb->dev_channel, scb->dev_target)); } } } spin_unlock_irq(&adapter->lock); if (!found) { - con_log(CL_ANN, (KERN_WARNING - "megaraid abort: scsi cmd:%ld, do now own\n", - scp->serial_number)); + con_log(CL_ANN, (KERN_WARNING "megaraid abort: do now own\n")); // FIXME: Should there be a callback for this command? return SUCCESS; @@ -2649,9 +2643,8 @@ megaraid_reset_handler(struct scsi_cmnd *scp) } else { if (scb->scp == scp) { // Found command con_log(CL_ANN, (KERN_WARNING - "megaraid: %ld:%d[%d:%d], reset from pending list\n", - scp->serial_number, scb->sno, - scb->dev_channel, scb->dev_target)); + "megaraid: %d[%d:%d], reset from pending list\n", + scb->sno, scb->dev_channel, scb->dev_target)); } else { con_log(CL_ANN, (KERN_WARNING "megaraid: IO packet with %d[%d:%d] being reset\n", diff --git a/drivers/scsi/megaraid/megaraid_sas_base.c b/drivers/scsi/megaraid/megaraid_sas_base.c index 66d4cea..89c623e 100644 --- a/drivers/scsi/megaraid/megaraid_sas_base.c +++ b/drivers/scsi/megaraid/megaraid_sas_base.c @@ -1751,10 +1751,9 @@ static int megasas_wait_for_outstanding(struct megasas_instance *instance) list_del_init(&reset_cmd->list); if (reset_cmd->scmd) { reset_cmd->scmd->result = DID_RESET << 16; - printk(KERN_NOTICE "%d:%p reset [%02x], %#lx\n", + printk(KERN_NOTICE "%d:%p reset [%02x]\n", reset_index, reset_cmd, - reset_cmd->scmd->cmnd[0], - reset_cmd->scmd->serial_number); + reset_cmd->scmd->cmnd[0]); reset_cmd->scmd->scsi_done(reset_cmd->scmd); megasas_return_cmd(instance, reset_cmd); @@ -1879,8 +1878,8 @@ static int megasas_generic_reset(struct scsi_cmnd *scmd) instance = (struct megasas_instance *)scmd->device->host->hostdata; - scmd_printk(KERN_NOTICE, scmd, "megasas: RESET -%ld cmd=%x retries=%x\n", - scmd->serial_number, scmd->cmnd[0], scmd->retries); + scmd_printk(KERN_NOTICE, scmd, "megasas: RESET cmd=%x retries=%x\n", + scmd->cmnd[0], scmd->retries); if (instance->adprecovery == MEGASAS_HW_CRITICAL_ERROR) { printk(KERN_ERR "megasas: cannot recover from previous reset " @@ -2349,9 +2348,9 @@ megasas_issue_pending_cmds_again(struct megasas_instance *instance) cmd->frame_phys_addr , 0, instance->reg_set); } else if (cmd->scmd) { - printk(KERN_NOTICE "megasas: %p scsi cmd [%02x],%#lx" + printk(KERN_NOTICE "megasas: %p scsi cmd [%02x]" "detected on the internal queue, issue again.\n", - cmd, cmd->scmd->cmnd[0], cmd->scmd->serial_number); + cmd, cmd->scmd->cmnd[0]); atomic_inc(&instance->fw_outstanding); instance->instancet->fire_cmd(instance, diff --git a/drivers/scsi/mesh.c b/drivers/scsi/mesh.c index 197aa1b..4944747 100644 --- a/drivers/scsi/mesh.c +++ b/drivers/scsi/mesh.c @@ -415,8 +415,7 @@ static void mesh_start_cmd(struct mesh_state *ms, struct scsi_cmnd *cmd) #if 1 if (DEBUG_TARGET(cmd)) { int i; - printk(KERN_DEBUG "mesh_start: %p ser=%lu tgt=%d cmd=", - cmd, cmd->serial_number, id); + printk(KERN_DEBUG "mesh_start: %p tgt=%d cmd=", cmd, id); for (i = 0; i < cmd->cmd_len; ++i) printk(" %x", cmd->cmnd[i]); printk(" use_sg=%d buffer=%p bufflen=%u\n", diff --git a/drivers/scsi/ncr53c8xx.c b/drivers/scsi/ncr53c8xx.c index 835d8d6..4b3b475 100644 --- a/drivers/scsi/ncr53c8xx.c +++ b/drivers/scsi/ncr53c8xx.c @@ -8147,7 +8147,7 @@ static int ncr53c8xx_abort(struct scsi_cmnd *cmd) unsigned long flags; struct scsi_cmnd *done_list; - printk("ncr53c8xx_abort: command pid %lu\n", cmd->serial_number); + printk("ncr53c8xx_abort\n"); NCR_LOCK_NCB(np, flags); diff --git a/drivers/scsi/qla1280.c b/drivers/scsi/qla1280.c index 8ba5744..d838205 100644 --- a/drivers/scsi/qla1280.c +++ b/drivers/scsi/qla1280.c @@ -4066,7 +4066,7 @@ __qla1280_print_scsi_cmd(struct scsi_cmnd *cmd) } */ printk(" tag=%d, transfersize=0x%x \n", cmd->tag, cmd->transfersize); - printk(" Pid=%li, SP=0x%p\n", cmd->serial_number, CMD_SP(cmd)); + printk(" SP=0x%p\n", CMD_SP(cmd)); printk(" underflow size = 0x%x, direction=0x%x\n", cmd->underflow, cmd->sc_data_direction); } diff --git a/drivers/scsi/qla4xxx/ql4_os.c b/drivers/scsi/qla4xxx/ql4_os.c index 230ba09..c22f2a7 100644 --- a/drivers/scsi/qla4xxx/ql4_os.c +++ b/drivers/scsi/qla4xxx/ql4_os.c @@ -2068,15 +2068,14 @@ static int qla4xxx_eh_abort(struct scsi_cmnd *cmd) struct scsi_qla_host *ha = to_qla_host(cmd->device->host); unsigned int id = cmd->device->id; unsigned int lun = cmd->device->lun; - unsigned long serial = cmd->serial_number; unsigned long flags; struct srb *srb = NULL; int ret = SUCCESS; int wait = 0; ql4_printk(KERN_INFO, ha, - "scsi%ld:%d:%d: Abort command issued cmd=%p, pid=%ld\n", - ha->host_no, id, lun, cmd, serial); + "scsi%ld:%d:%d: Abort command issued cmd=%p\n", + ha->host_no, id, lun, cmd); spin_lock_irqsave(&ha->hardware_lock, flags); srb = (struct srb *) CMD_SP(cmd); diff --git a/drivers/scsi/tmscsim.c b/drivers/scsi/tmscsim.c index a124a28f..a1baccc 100644 --- a/drivers/scsi/tmscsim.c +++ b/drivers/scsi/tmscsim.c @@ -565,12 +565,12 @@ dc390_StartSCSI( struct dc390_acb* pACB, struct dc390_dcb* pDCB, struct dc390_sr pDCB->TagMask |= 1 << tag[1]; pSRB->TagNumber = tag[1]; DC390_write8(ScsiFifo, tag[1]); - DEBUG1(printk(KERN_INFO "DC390: Select w/DisCn for Cmd %li (SRB %p), block tag %02x\n", scmd->serial_number, pSRB, tag[1])); + DEBUG1(printk(KERN_INFO "DC390: Select w/DisCn for SRB %p, block tag %02x\n", pSRB, tag[1])); cmd = SEL_W_ATN3; } else { /* No TagQ */ //no_tag: - DEBUG1(printk(KERN_INFO "DC390: Select w%s/DisCn for Cmd %li (SRB %p), No TagQ\n", disc_allowed ? "" : "o", scmd->serial_number, pSRB)); + DEBUG1(printk(KERN_INFO "DC390: Select w%s/DisCn for SRB %p, No TagQ\n", disc_allowed ? "" : "o", pSRB)); } pSRB->SRBState = SRB_START_; @@ -620,8 +620,8 @@ dc390_StartSCSI( struct dc390_acb* pACB, struct dc390_dcb* pDCB, struct dc390_sr if (DC390_read8 (Scsi_Status) & INTERRUPT) { dc390_freetag (pDCB, pSRB); - DEBUG0(printk ("DC390: Interrupt during Start SCSI (pid %li, target %02i-%02i)\n", - scmd->serial_number, scmd->device->id, scmd->device->lun)); + DEBUG0(printk ("DC390: Interrupt during Start SCSI (target %02i-%02i)\n", + scmd->device->id, scmd->device->lun)); pSRB->SRBState = SRB_READY; //DC390_write8 (ScsiCmd, CLEAR_FIFO_CMD); pACB->SelLost++; @@ -1705,8 +1705,7 @@ dc390_SRBdone( struct dc390_acb* pACB, struct dc390_dcb* pDCB, struct dc390_srb* status = pSRB->TargetStatus; - DEBUG0(printk (" SRBdone (%02x,%08x), SRB %p, pid %li\n", status, pcmd->result,\ - pSRB, pcmd->serial_number)); + DEBUG0(printk (" SRBdone (%02x,%08x), SRB %p\n", status, pcmd->result, pSRB)); if(pSRB->SRBFlag & AUTO_REQSENSE) { /* Last command was a Request Sense */ pSRB->SRBFlag &= ~AUTO_REQSENSE; @@ -1727,7 +1726,7 @@ dc390_SRBdone( struct dc390_acb* pACB, struct dc390_dcb* pDCB, struct dc390_srb* } else { SET_RES_DRV(pcmd->result, DRIVER_SENSE); //pSRB->ScsiCmdLen = (u8) (pSRB->Segment1[0] >> 8); - DEBUG0 (printk ("DC390: RETRY pid %li (%02x), target %02i-%02i\n", pcmd->serial_number, pcmd->cmnd[0], pcmd->device->id, pcmd->device->lun)); + DEBUG0 (printk ("DC390: RETRY (%02x), target %02i-%02i\n", pcmd->cmnd[0], pcmd->device->id, pcmd->device->lun)); pSRB->TotalXferredLen = 0; SET_RES_DID(pcmd->result, DID_SOFT_ERROR); } @@ -1747,7 +1746,7 @@ dc390_SRBdone( struct dc390_acb* pACB, struct dc390_dcb* pDCB, struct dc390_srb* else if (status == SAM_STAT_TASK_SET_FULL) { scsi_track_queue_full(pcmd->device, pDCB->GoingSRBCnt - 1); - DEBUG0 (printk ("DC390: RETRY pid %li (%02x), target %02i-%02i\n", pcmd->serial_number, pcmd->cmnd[0], pcmd->device->id, pcmd->device->lun)); + DEBUG0 (printk ("DC390: RETRY (%02x), target %02i-%02i\n", pcmd->cmnd[0], pcmd->device->id, pcmd->device->lun)); pSRB->TotalXferredLen = 0; SET_RES_DID(pcmd->result, DID_SOFT_ERROR); } @@ -1801,7 +1800,7 @@ cmd_done: /* Add to free list */ dc390_Free_insert (pACB, pSRB); - DEBUG0(printk (KERN_DEBUG "DC390: SRBdone: done pid %li\n", pcmd->serial_number)); + DEBUG0(printk (KERN_DEBUG "DC390: SRBdone: done\n")); pcmd->scsi_done (pcmd); return; @@ -1997,8 +1996,7 @@ static int DC390_abort(struct scsi_cmnd *cmd) struct dc390_acb *pACB = (struct dc390_acb*) cmd->device->host->hostdata; struct dc390_dcb *pDCB = (struct dc390_dcb*) cmd->device->hostdata; - scmd_printk(KERN_WARNING, cmd, - "DC390: Abort command (pid %li)\n", cmd->serial_number); + scmd_printk(KERN_WARNING, cmd, "DC390: Abort command\n"); /* abort() is too stupid for already sent commands at the moment. * If it's called we are in trouble anyway, so let's dump some info @@ -2006,7 +2004,7 @@ static int DC390_abort(struct scsi_cmnd *cmd) dc390_dumpinfo(pACB, pDCB, NULL); pDCB->DCBFlag |= ABORT_DEV_; - printk(KERN_INFO "DC390: Aborted pid %li\n", cmd->serial_number); + printk(KERN_INFO "DC390: Aborted.\n"); return FAILED; } diff --git a/drivers/scsi/u14-34f.c b/drivers/scsi/u14-34f.c index edfc5da..90e104d 100644 --- a/drivers/scsi/u14-34f.c +++ b/drivers/scsi/u14-34f.c @@ -1256,8 +1256,8 @@ static int u14_34f_queuecommand_lck(struct scsi_cmnd *SCpnt, void (*done)(struct j = ((struct hostdata *) SCpnt->device->host->hostdata)->board_number; if (SCpnt->host_scribble) - panic("%s: qcomm, pid %ld, SCpnt %p already active.\n", - BN(j), SCpnt->serial_number, SCpnt); + panic("%s: qcomm, SCpnt %p already active.\n", + BN(j), SCpnt); /* i is the mailbox number, look for the first free mailbox starting from last_cp_used */ @@ -1286,9 +1286,9 @@ static int u14_34f_queuecommand_lck(struct scsi_cmnd *SCpnt, void (*done)(struct cpp->cpp_index = i; SCpnt->host_scribble = (unsigned char *) &cpp->cpp_index; - if (do_trace) printk("%s: qcomm, mbox %d, target %d.%d:%d, pid %ld.\n", + if (do_trace) printk("%s: qcomm, mbox %d, target %d.%d:%d.\n", BN(j), i, SCpnt->device->channel, SCpnt->device->id, - SCpnt->device->lun, SCpnt->serial_number); + SCpnt->device->lun); cpp->opcode = OP_SCSI; cpp->channel = SCpnt->device->channel; @@ -1315,7 +1315,7 @@ static int u14_34f_queuecommand_lck(struct scsi_cmnd *SCpnt, void (*done)(struct unmap_dma(i, j); SCpnt->host_scribble = NULL; scmd_printk(KERN_INFO, SCpnt, - "qcomm, pid %ld, adapter busy.\n", SCpnt->serial_number); + "qcomm, adapter busy.\n"); return 1; } @@ -1337,14 +1337,12 @@ static int u14_34f_eh_abort(struct scsi_cmnd *SCarg) { j = ((struct hostdata *) SCarg->device->host->hostdata)->board_number; if (SCarg->host_scribble == NULL) { - scmd_printk(KERN_INFO, SCarg, "abort, pid %ld inactive.\n", - SCarg->serial_number); + scmd_printk(KERN_INFO, SCarg, "abort, command inactive.\n"); return SUCCESS; } i = *(unsigned int *)SCarg->host_scribble; - scmd_printk(KERN_INFO, SCarg, "abort, mbox %d, pid %ld.\n", - i, SCarg->serial_number); + scmd_printk(KERN_INFO, SCarg, "abort, mbox %d.\n", i); if (i >= sh[j]->can_queue) panic("%s: abort, invalid SCarg->host_scribble.\n", BN(j)); @@ -1387,8 +1385,7 @@ static int u14_34f_eh_abort(struct scsi_cmnd *SCarg) { SCarg->result = DID_ABORT << 16; SCarg->host_scribble = NULL; HD(j)->cp_stat[i] = FREE; - printk("%s, abort, mbox %d ready, DID_ABORT, pid %ld done.\n", - BN(j), i, SCarg->serial_number); + printk("%s, abort, mbox %d ready, DID_ABORT, done.\n", BN(j), i); SCarg->scsi_done(SCarg); return SUCCESS; } @@ -1403,12 +1400,12 @@ static int u14_34f_eh_host_reset(struct scsi_cmnd *SCarg) { struct scsi_cmnd *SCpnt; j = ((struct hostdata *) SCarg->device->host->hostdata)->board_number; - scmd_printk(KERN_INFO, SCarg, "reset, enter, pid %ld.\n", SCarg->serial_number); + scmd_printk(KERN_INFO, SCarg, "reset, enter.\n"); spin_lock_irq(sh[j]->host_lock); if (SCarg->host_scribble == NULL) - printk("%s: reset, pid %ld inactive.\n", BN(j), SCarg->serial_number); + printk("%s: reset, inactive.\n", BN(j)); if (HD(j)->in_reset) { printk("%s: reset, exit, already in reset.\n", BN(j)); @@ -1445,14 +1442,12 @@ static int u14_34f_eh_host_reset(struct scsi_cmnd *SCarg) { if (HD(j)->cp_stat[i] == READY || HD(j)->cp_stat[i] == ABORTING) { HD(j)->cp_stat[i] = ABORTING; - printk("%s: reset, mbox %d aborting, pid %ld.\n", - BN(j), i, SCpnt->serial_number); + printk("%s: reset, mbox %d aborting.\n", BN(j), i); } else { HD(j)->cp_stat[i] = IN_RESET; - printk("%s: reset, mbox %d in reset, pid %ld.\n", - BN(j), i, SCpnt->serial_number); + printk("%s: reset, mbox %d in reset.\n", BN(j), i); } if (SCpnt->host_scribble == NULL) @@ -1500,8 +1495,7 @@ static int u14_34f_eh_host_reset(struct scsi_cmnd *SCarg) { /* This mailbox is still waiting for its interrupt */ HD(j)->cp_stat[i] = LOCKED; - printk("%s, reset, mbox %d locked, DID_RESET, pid %ld done.\n", - BN(j), i, SCpnt->serial_number); + printk("%s, reset, mbox %d locked, DID_RESET, done.\n", BN(j), i); } else if (HD(j)->cp_stat[i] == ABORTING) { @@ -1513,8 +1507,7 @@ static int u14_34f_eh_host_reset(struct scsi_cmnd *SCarg) { /* This mailbox was never queued to the adapter */ HD(j)->cp_stat[i] = FREE; - printk("%s, reset, mbox %d aborting, DID_RESET, pid %ld done.\n", - BN(j), i, SCpnt->serial_number); + printk("%s, reset, mbox %d aborting, DID_RESET, done.\n", BN(j), i); } else @@ -1528,7 +1521,7 @@ static int u14_34f_eh_host_reset(struct scsi_cmnd *SCarg) { HD(j)->in_reset = FALSE; do_trace = FALSE; - if (arg_done) printk("%s: reset, exit, pid %ld done.\n", BN(j), SCarg->serial_number); + if (arg_done) printk("%s: reset, exit, done.\n", BN(j)); else printk("%s: reset, exit.\n", BN(j)); spin_unlock_irq(sh[j]->host_lock); @@ -1671,10 +1664,10 @@ static int reorder(unsigned int j, unsigned long cursec, if (link_statistics && (overlap || !(flushcount % link_statistics))) for (n = 0; n < n_ready; n++) { k = il[n]; cpp = &HD(j)->cp[k]; SCpnt = cpp->SCpnt; - printk("%s %d.%d:%d pid %ld mb %d fc %d nr %d sec %ld ns %u"\ + printk("%s %d.%d:%d mb %d fc %d nr %d sec %ld ns %u"\ " cur %ld s:%c r:%c rev:%c in:%c ov:%c xd %d.\n", (ihdlr ? "ihdlr" : "qcomm"), SCpnt->channel, SCpnt->target, - SCpnt->lun, SCpnt->serial_number, k, flushcount, n_ready, + SCpnt->lun, k, flushcount, n_ready, blk_rq_pos(SCpnt->request), blk_rq_sectors(SCpnt->request), cursec, YESNO(s), YESNO(r), YESNO(rev), YESNO(input_only), YESNO(overlap), cpp->xdir); @@ -1709,9 +1702,9 @@ static void flush_dev(struct scsi_device *dev, unsigned long cursec, unsigned in if (wait_on_busy(sh[j]->io_port, MAXLOOP)) { scmd_printk(KERN_INFO, SCpnt, - "%s, pid %ld, mbox %d, adapter" + "%s, mbox %d, adapter" " busy, will abort.\n", (ihdlr ? "ihdlr" : "qcomm"), - SCpnt->serial_number, k); + k); HD(j)->cp_stat[k] = ABORTING; continue; } @@ -1793,12 +1786,12 @@ static irqreturn_t ihdlr(unsigned int j) if (SCpnt == NULL) panic("%s: ihdlr, mbox %d, SCpnt == NULL.\n", BN(j), i); if (SCpnt->host_scribble == NULL) - panic("%s: ihdlr, mbox %d, pid %ld, SCpnt %p garbled.\n", BN(j), i, - SCpnt->serial_number, SCpnt); + panic("%s: ihdlr, mbox %d, SCpnt %p garbled.\n", BN(j), i, + SCpnt); if (*(unsigned int *)SCpnt->host_scribble != i) - panic("%s: ihdlr, mbox %d, pid %ld, index mismatch %d.\n", - BN(j), i, SCpnt->serial_number, *(unsigned int *)SCpnt->host_scribble); + panic("%s: ihdlr, mbox %d, index mismatch %d.\n", + BN(j), i, *(unsigned int *)SCpnt->host_scribble); sync_dma(i, j); @@ -1841,8 +1834,8 @@ static irqreturn_t ihdlr(unsigned int j) (!(tstatus == CHECK_CONDITION && HD(j)->iocount <= 1000 && (SCpnt->sense_buffer[2] & 0xf) == NOT_READY))) scmd_printk(KERN_INFO, SCpnt, - "ihdlr, pid %ld, target_status 0x%x, sense key 0x%x.\n", - SCpnt->serial_number, spp->target_status, + "ihdlr, target_status 0x%x, sense key 0x%x.\n", + spp->target_status, SCpnt->sense_buffer[2]); HD(j)->target_to[scmd_id(SCpnt)][scmd_channel(SCpnt)] = 0; @@ -1913,8 +1906,8 @@ static irqreturn_t ihdlr(unsigned int j) do_trace || msg_byte(spp->target_status)) #endif scmd_printk(KERN_INFO, SCpnt, "ihdlr, mbox %2d, err 0x%x:%x,"\ - " pid %ld, reg 0x%x, count %d.\n", - i, spp->adapter_status, spp->target_status, SCpnt->serial_number, + " reg 0x%x, count %d.\n", + i, spp->adapter_status, spp->target_status, reg, HD(j)->iocount); unmap_dma(i, j); diff --git a/drivers/scsi/wd33c93.c b/drivers/scsi/wd33c93.c index 4468ae3..97ae716 100644 --- a/drivers/scsi/wd33c93.c +++ b/drivers/scsi/wd33c93.c @@ -381,7 +381,7 @@ wd33c93_queuecommand_lck(struct scsi_cmnd *cmd, hostdata = (struct WD33C93_hostdata *) cmd->device->host->hostdata; DB(DB_QUEUE_COMMAND, - printk("Q-%d-%02x-%ld( ", cmd->device->id, cmd->cmnd[0], cmd->serial_number)) + printk("Q-%d-%02x( ", cmd->device->id, cmd->cmnd[0])) /* Set up a few fields in the scsi_cmnd structure for our own use: * - host_scribble is the pointer to the next cmd in the input queue @@ -462,7 +462,7 @@ wd33c93_queuecommand_lck(struct scsi_cmnd *cmd, wd33c93_execute(cmd->device->host); - DB(DB_QUEUE_COMMAND, printk(")Q-%ld ", cmd->serial_number)) + DB(DB_QUEUE_COMMAND, printk(")Q ")) spin_unlock_irq(&hostdata->lock); return 0; @@ -687,7 +687,7 @@ wd33c93_execute(struct Scsi_Host *instance) */ DB(DB_EXECUTE, - printk("%s%ld)EX-2 ", (cmd->SCp.phase) ? "d:" : "", cmd->serial_number)) + printk("%s)EX-2 ", (cmd->SCp.phase) ? "d:" : "")) } static void @@ -963,7 +963,7 @@ wd33c93_intr(struct Scsi_Host *instance) case CSR_XFER_DONE | PHS_COMMAND: case CSR_UNEXP | PHS_COMMAND: case CSR_SRV_REQ | PHS_COMMAND: - DB(DB_INTR, printk("CMND-%02x,%ld", cmd->cmnd[0], cmd->serial_number)) + DB(DB_INTR, printk("CMND-%02x", cmd->cmnd[0])) transfer_pio(regs, cmd->cmnd, cmd->cmd_len, DATA_OUT_DIR, hostdata); hostdata->state = S_CONNECTED; @@ -1007,7 +1007,7 @@ wd33c93_intr(struct Scsi_Host *instance) switch (msg) { case COMMAND_COMPLETE: - DB(DB_INTR, printk("CCMP-%ld", cmd->serial_number)) + DB(DB_INTR, printk("CCMP")) write_wd33c93_cmd(regs, WD_CMD_NEGATE_ACK); hostdata->state = S_PRE_CMP_DISC; break; @@ -1174,7 +1174,7 @@ wd33c93_intr(struct Scsi_Host *instance) write_wd33c93(regs, WD_SOURCE_ID, SRCID_ER); if (phs == 0x60) { - DB(DB_INTR, printk("SX-DONE-%ld", cmd->serial_number)) + DB(DB_INTR, printk("SX-DONE")) cmd->SCp.Message = COMMAND_COMPLETE; lun = read_wd33c93(regs, WD_TARGET_LUN); DB(DB_INTR, printk(":%d.%d", cmd->SCp.Status, lun)) @@ -1200,8 +1200,8 @@ wd33c93_intr(struct Scsi_Host *instance) wd33c93_execute(instance); } else { printk - ("%02x:%02x:%02x-%ld: Unknown SEL_XFER_DONE phase!!---", - asr, sr, phs, cmd->serial_number); + ("%02x:%02x:%02x: Unknown SEL_XFER_DONE phase!!---", + asr, sr, phs); spin_unlock_irqrestore(&hostdata->lock, flags); } break; @@ -1266,7 +1266,7 @@ wd33c93_intr(struct Scsi_Host *instance) spin_unlock_irqrestore(&hostdata->lock, flags); return; } - DB(DB_INTR, printk("UNEXP_DISC-%ld", cmd->serial_number)) + DB(DB_INTR, printk("UNEXP_DISC")) hostdata->connected = NULL; hostdata->busy[cmd->device->id] &= ~(1 << cmd->device->lun); hostdata->state = S_UNCONNECTED; @@ -1292,7 +1292,7 @@ wd33c93_intr(struct Scsi_Host *instance) */ write_wd33c93(regs, WD_SOURCE_ID, SRCID_ER); - DB(DB_INTR, printk("DISC-%ld", cmd->serial_number)) + DB(DB_INTR, printk("DISC")) if (cmd == NULL) { printk(" - Already disconnected! "); hostdata->state = S_UNCONNECTED; @@ -1491,7 +1491,6 @@ wd33c93_intr(struct Scsi_Host *instance) } else hostdata->state = S_CONNECTED; - DB(DB_INTR, printk("-%ld", cmd->serial_number)) spin_unlock_irqrestore(&hostdata->lock, flags); break; @@ -1637,8 +1636,8 @@ wd33c93_abort(struct scsi_cmnd * cmd) cmd->host_scribble = NULL; cmd->result = DID_ABORT << 16; printk - ("scsi%d: Abort - removing command %ld from input_Q. ", - instance->host_no, cmd->serial_number); + ("scsi%d: Abort - removing command from input_Q. ", + instance->host_no); enable_irq(cmd->device->host->irq); cmd->scsi_done(cmd); return SUCCESS; @@ -1662,8 +1661,8 @@ wd33c93_abort(struct scsi_cmnd * cmd) uchar sr, asr; unsigned long timeout; - printk("scsi%d: Aborting connected command %ld - ", - instance->host_no, cmd->serial_number); + printk("scsi%d: Aborting connected command - ", + instance->host_no); printk("stopping DMA - "); if (hostdata->dma == D_DMA_RUNNING) { @@ -1729,8 +1728,8 @@ wd33c93_abort(struct scsi_cmnd * cmd) while (tmp) { if (tmp == cmd) { printk - ("scsi%d: Abort - command %ld found on disconnected_Q - ", - instance->host_no, cmd->serial_number); + ("scsi%d: Abort - command found on disconnected_Q - ", + instance->host_no); printk("Abort SNOOZE. "); enable_irq(cmd->device->host->irq); return FAILED; @@ -2180,8 +2179,8 @@ wd33c93_proc_info(struct Scsi_Host *instance, char *buf, char **start, off_t off strcat(bp, "\nconnected: "); if (hd->connected) { cmd = (struct scsi_cmnd *) hd->connected; - sprintf(tbuf, " %ld-%d:%d(%02x)", - cmd->serial_number, cmd->device->id, cmd->device->lun, cmd->cmnd[0]); + sprintf(tbuf, " %d:%d(%02x)", + cmd->device->id, cmd->device->lun, cmd->cmnd[0]); strcat(bp, tbuf); } } @@ -2189,8 +2188,8 @@ wd33c93_proc_info(struct Scsi_Host *instance, char *buf, char **start, off_t off strcat(bp, "\ninput_Q: "); cmd = (struct scsi_cmnd *) hd->input_Q; while (cmd) { - sprintf(tbuf, " %ld-%d:%d(%02x)", - cmd->serial_number, cmd->device->id, cmd->device->lun, cmd->cmnd[0]); + sprintf(tbuf, " %d:%d(%02x)", + cmd->device->id, cmd->device->lun, cmd->cmnd[0]); strcat(bp, tbuf); cmd = (struct scsi_cmnd *) cmd->host_scribble; } @@ -2199,8 +2198,8 @@ wd33c93_proc_info(struct Scsi_Host *instance, char *buf, char **start, off_t off strcat(bp, "\ndisconnected_Q:"); cmd = (struct scsi_cmnd *) hd->disconnected_Q; while (cmd) { - sprintf(tbuf, " %ld-%d:%d(%02x)", - cmd->serial_number, cmd->device->id, cmd->device->lun, cmd->cmnd[0]); + sprintf(tbuf, " %d:%d(%02x)", + cmd->device->id, cmd->device->lun, cmd->cmnd[0]); strcat(bp, tbuf); cmd = (struct scsi_cmnd *) cmd->host_scribble; } -- cgit v0.10.2 From 05d1091fd9fe3672bde444506fe426d864c52013 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Mon, 4 Apr 2011 09:42:22 -0400 Subject: [SCSI] usb-storage: do not increment cmd->serial_number The isd200 sub-driver increments the command serial number despite not using it at all in it's routine for sending internal scsi commands. Remove the increment to prepare for removing the serial_number field. Signed-off-by: Christoph Hellwig Signed-off-by: James Bottomley diff --git a/drivers/usb/storage/isd200.c b/drivers/usb/storage/isd200.c index 09e52ba..ffc4193 100644 --- a/drivers/usb/storage/isd200.c +++ b/drivers/usb/storage/isd200.c @@ -499,7 +499,6 @@ static int isd200_action( struct us_data *us, int action, memset(&ata, 0, sizeof(ata)); srb->cmnd = info->cmnd; srb->device = &srb_dev; - ++srb->serial_number; ata.generic.SignatureByte0 = info->ConfigData.ATAMajorCommand; ata.generic.SignatureByte1 = info->ConfigData.ATAMinorCommand; -- cgit v0.10.2 From a7c44d4ad147d54f041ba3885cc28549da72f55a Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Mon, 4 Apr 2011 09:42:30 -0400 Subject: [SCSI] mpt2sas: do not check serial_number in the abort handler The SCSI midlayer stops all command processing when in error handling, which means there is no chance for command reuse when the abort handler is called. Signed-off-by: Christoph Hellwig Acked-by: "Moore, Eric" Signed-off-by: James Bottomley diff --git a/drivers/scsi/mpt2sas/mpt2sas_scsih.c b/drivers/scsi/mpt2sas/mpt2sas_scsih.c index d2064a0..33723ed 100644 --- a/drivers/scsi/mpt2sas/mpt2sas_scsih.c +++ b/drivers/scsi/mpt2sas/mpt2sas_scsih.c @@ -2133,8 +2133,7 @@ mpt2sas_scsih_issue_tm(struct MPT2SAS_ADAPTER *ioc, u16 handle, uint channel, switch (type) { case MPI2_SCSITASKMGMT_TASKTYPE_ABORT_TASK: scmd_lookup = _scsih_scsi_lookup_get(ioc, smid_task); - if (scmd_lookup && (scmd_lookup->serial_number == - scmd->serial_number)) + if (scmd_lookup) rc = FAILED; else rc = SUCCESS; -- cgit v0.10.2 From aeaeb5cec5a5477b392e627883fdb46d8a5dcc1f Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Mon, 4 Apr 2011 09:42:41 -0400 Subject: [SCSI] fusion: do not check serial_number in the abort handler The SCSI midlayer stops all command processing when in error handling, which means there is no chance for command reuse when the abort handler is called. Signed-off-by: Christoph Hellwig Signed-off-by: James Bottomley diff --git a/drivers/message/fusion/mptscsih.c b/drivers/message/fusion/mptscsih.c index 0d9b82a..b871ab3 100644 --- a/drivers/message/fusion/mptscsih.c +++ b/drivers/message/fusion/mptscsih.c @@ -1773,7 +1773,6 @@ mptscsih_abort(struct scsi_cmnd * SCpnt) int scpnt_idx; int retval; VirtDevice *vdevice; - ulong sn = SCpnt->serial_number; MPT_ADAPTER *ioc; /* If we can't locate our host adapter structure, return FAILED status. @@ -1859,8 +1858,7 @@ mptscsih_abort(struct scsi_cmnd * SCpnt) vdevice->vtarget->id, vdevice->lun, ctx2abort, mptscsih_get_tm_timeout(ioc)); - if (SCPNT_TO_LOOKUP_IDX(ioc, SCpnt) == scpnt_idx && - SCpnt->serial_number == sn) { + if (SCPNT_TO_LOOKUP_IDX(ioc, SCpnt) == scpnt_idx) { dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "task abort: command still in active list! (sc=%p)\n", ioc->name, SCpnt)); @@ -1873,9 +1871,9 @@ mptscsih_abort(struct scsi_cmnd * SCpnt) } out: - printk(MYIOC_s_INFO_FMT "task abort: %s (rv=%04x) (sc=%p) (sn=%ld)\n", + printk(MYIOC_s_INFO_FMT "task abort: %s (rv=%04x) (sc=%p)\n", ioc->name, ((retval == SUCCESS) ? "SUCCESS" : "FAILED"), retval, - SCpnt, SCpnt->serial_number); + SCpnt); return retval; } -- cgit v0.10.2 From 0bdccdb0a090ad8dc5f851cad5e843244c410ee8 Mon Sep 17 00:00:00 2001 From: "Kashyap, Desai" Date: Thu, 7 Apr 2011 12:32:49 +0530 Subject: [SCSI] mpt2sas : WarpDrive New product SSS6200 support added This patch has Support for the new solid state device product SSS6200 from LSI and relavent features w.r.t SSS6200. The major feature added in this driver is supporting Direct-I/O to the SSS6200 storage.There are some additional changes done to avoid exposing the RAID member disks to the OS and hiding/exposing drives based on the OEM Specific Flag in Manufacturing Page10 (this is required to handle specific changes in the SSS6200 firmware). Each and every changes are listed below. 1. Hiding IR related messages. For SSS6200, the driver is modified not to print IR related events. Even if the debugging is enabled the IR related messages will not be displayed. In some places if there is a need to display a message related to IR the string "IR" is replaced with string "DD" and the string "volume" is replaced with "direct drive". But the function names are not changed hence there are some places where the reference to volume can be seen if debug level is set. 2. Removed RAID transport support In Linux the user can retrieve RAID volume information from the sysfs directory. This support is removed for SSS6200. 3. Direct I/O support. The driver tries to enable direct I/O when a volume is reported to the driver by the firmware through IRCC events and the driver does this just before reporting to the OS, hence all the OS issued I/O can go through direct path if they can, The first validation is to see whether the manufacturing page10 flag is set to expose all drives always. If that is set, the driver will not enable direct I/O and displays the message "DDIO" is disabled globally as drives are exposed. The driver checks whether there is more than one volume in the controller, if so the direct I/O will be disabled globally for all volumes in the controller and the message displayed will be "DDIO is disabled globally as number of drives > 1. If retrieving number of PD is failed the driver will not enable direct I/O and displays the message Failure in computing number of drives DDIO disabled. If memory allocation for RAIDVolumePage0 is failed, the driver will not enable direct I/O and displays the message Memory allocation failure for RVPG0 DDIO disabled. If retrieving RAIDVolumePage0 is failed the driver will not enable direct I/O and displays the message Failure in retrieving RVPG0 DDIO disabled If the number of PD in a volume is greater than 8, then the direct I/O will be disabled. If any of individual drives handle retrieval is failed then the DD-IO will be disabled. If the volume is not RAID0 or if the block size is not 512 then the DD-IO will be disabled. If the volume size is greater than 2TB then the DD-IO will be disabled. If the driver is not able to find a valid stripe exponent using the configured stripe size then the DD-IO will be disabled When the DD-IO is enabled the driver will check every I/O request issued to the storage and checks whether the request is either READ6/WRITE6/READ10/WRITE10, if it is and if the complete I/O transfer is within a stripe size then the I/O is redirected to the drive directly instead of the volume. On completion of every I/O, if the completion is failure means if the reply is address reply with a reply frame associated with it, then the type of I/O will be checked, if the I/O is direct then the I/O will be retried to the volume once. Signed-off-by: Kashyap Desai Reviewed-by: Eric Moore Reviewed-by: Sathya Prakash Signed-off-by: James Bottomley diff --git a/drivers/scsi/mpt2sas/mpt2sas_base.c b/drivers/scsi/mpt2sas/mpt2sas_base.c index 3346357..efa0255 100644 --- a/drivers/scsi/mpt2sas/mpt2sas_base.c +++ b/drivers/scsi/mpt2sas/mpt2sas_base.c @@ -522,7 +522,8 @@ _base_display_event_data(struct MPT2SAS_ADAPTER *ioc, desc = "Device Status Change"; break; case MPI2_EVENT_IR_OPERATION_STATUS: - desc = "IR Operation Status"; + if (!ioc->hide_ir_msg) + desc = "IR Operation Status"; break; case MPI2_EVENT_SAS_DISCOVERY: { @@ -553,16 +554,20 @@ _base_display_event_data(struct MPT2SAS_ADAPTER *ioc, desc = "SAS Enclosure Device Status Change"; break; case MPI2_EVENT_IR_VOLUME: - desc = "IR Volume"; + if (!ioc->hide_ir_msg) + desc = "IR Volume"; break; case MPI2_EVENT_IR_PHYSICAL_DISK: - desc = "IR Physical Disk"; + if (!ioc->hide_ir_msg) + desc = "IR Physical Disk"; break; case MPI2_EVENT_IR_CONFIGURATION_CHANGE_LIST: - desc = "IR Configuration Change List"; + if (!ioc->hide_ir_msg) + desc = "IR Configuration Change List"; break; case MPI2_EVENT_LOG_ENTRY_ADDED: - desc = "Log Entry Added"; + if (!ioc->hide_ir_msg) + desc = "Log Entry Added"; break; } @@ -616,7 +621,10 @@ _base_sas_log_info(struct MPT2SAS_ADAPTER *ioc , u32 log_info) originator_str = "PL"; break; case 2: - originator_str = "IR"; + if (!ioc->hide_ir_msg) + originator_str = "IR"; + else + originator_str = "WarpDrive"; break; } @@ -1508,6 +1516,7 @@ mpt2sas_base_free_smid(struct MPT2SAS_ADAPTER *ioc, u16 smid) } ioc->scsi_lookup[i].cb_idx = 0xFF; ioc->scsi_lookup[i].scmd = NULL; + ioc->scsi_lookup[i].direct_io = 0; list_add_tail(&ioc->scsi_lookup[i].tracker_list, &ioc->free_list); spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags); @@ -1844,10 +1853,12 @@ _base_display_ioc_capabilities(struct MPT2SAS_ADAPTER *ioc) printk("), "); printk("Capabilities=("); - if (ioc->facts.IOCCapabilities & - MPI2_IOCFACTS_CAPABILITY_INTEGRATED_RAID) { - printk("Raid"); - i++; + if (!ioc->hide_ir_msg) { + if (ioc->facts.IOCCapabilities & + MPI2_IOCFACTS_CAPABILITY_INTEGRATED_RAID) { + printk("Raid"); + i++; + } } if (ioc->facts.IOCCapabilities & MPI2_IOCFACTS_CAPABILITY_TLR) { @@ -3680,6 +3691,7 @@ _base_make_ioc_operational(struct MPT2SAS_ADAPTER *ioc, int sleep_flag) u32 reply_address; u16 smid; struct _tr_list *delayed_tr, *delayed_tr_next; + u8 hide_flag; dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "%s\n", ioc->name, __func__)); @@ -3706,6 +3718,7 @@ _base_make_ioc_operational(struct MPT2SAS_ADAPTER *ioc, int sleep_flag) ioc->scsi_lookup[i].cb_idx = 0xFF; ioc->scsi_lookup[i].smid = smid; ioc->scsi_lookup[i].scmd = NULL; + ioc->scsi_lookup[i].direct_io = 0; list_add_tail(&ioc->scsi_lookup[i].tracker_list, &ioc->free_list); } @@ -3766,6 +3779,15 @@ _base_make_ioc_operational(struct MPT2SAS_ADAPTER *ioc, int sleep_flag) if (sleep_flag == CAN_SLEEP) _base_static_config_pages(ioc); + if (ioc->wait_for_port_enable_to_complete && ioc->is_warpdrive) { + if (ioc->manu_pg10.OEMIdentifier == 0x80) { + hide_flag = (u8) (ioc->manu_pg10.OEMSpecificFlags0 & + MFG_PAGE10_HIDE_SSDS_MASK); + if (hide_flag != MFG_PAGE10_HIDE_SSDS_MASK) + ioc->mfg_pg10_hide_flag = hide_flag; + } + } + if (ioc->wait_for_port_enable_to_complete) { if (diag_buffer_enable != 0) mpt2sas_enable_diag_buffer(ioc, diag_buffer_enable); diff --git a/drivers/scsi/mpt2sas/mpt2sas_base.h b/drivers/scsi/mpt2sas/mpt2sas_base.h index 5003282..2a3c05f 100644 --- a/drivers/scsi/mpt2sas/mpt2sas_base.h +++ b/drivers/scsi/mpt2sas/mpt2sas_base.h @@ -69,11 +69,11 @@ #define MPT2SAS_DRIVER_NAME "mpt2sas" #define MPT2SAS_AUTHOR "LSI Corporation " #define MPT2SAS_DESCRIPTION "LSI MPT Fusion SAS 2.0 Device Driver" -#define MPT2SAS_DRIVER_VERSION "08.100.00.00" +#define MPT2SAS_DRIVER_VERSION "08.100.00.01" #define MPT2SAS_MAJOR_VERSION 08 #define MPT2SAS_MINOR_VERSION 100 #define MPT2SAS_BUILD_VERSION 00 -#define MPT2SAS_RELEASE_VERSION 00 +#define MPT2SAS_RELEASE_VERSION 01 /* * Set MPT2SAS_SG_DEPTH value based on user input. @@ -189,6 +189,16 @@ #define MPT2SAS_HP_DAUGHTER_2_4_INTERNAL_SSDID 0x0046 /* + * WarpDrive Specific Log codes + */ + +#define MPT2_WARPDRIVE_LOGENTRY (0x8002) +#define MPT2_WARPDRIVE_LC_SSDT (0x41) +#define MPT2_WARPDRIVE_LC_SSDLW (0x43) +#define MPT2_WARPDRIVE_LC_SSDLF (0x44) +#define MPT2_WARPDRIVE_LC_BRMF (0x4D) + +/* * per target private data */ #define MPT_TARGET_FLAGS_RAID_COMPONENT 0x01 @@ -199,6 +209,7 @@ * struct MPT2SAS_TARGET - starget private hostdata * @starget: starget object * @sas_address: target sas address + * @raid_device: raid_device pointer to access volume data * @handle: device handle * @num_luns: number luns * @flags: MPT_TARGET_FLAGS_XXX flags @@ -208,6 +219,7 @@ struct MPT2SAS_TARGET { struct scsi_target *starget; u64 sas_address; + struct _raid_device *raid_device; u16 handle; int num_luns; u32 flags; @@ -215,6 +227,7 @@ struct MPT2SAS_TARGET { u8 tm_busy; }; + /* * per device private data */ @@ -262,6 +275,12 @@ typedef struct _MPI2_CONFIG_PAGE_MAN_10 { MPI2_POINTER PTR_MPI2_CONFIG_PAGE_MAN_10, Mpi2ManufacturingPage10_t, MPI2_POINTER pMpi2ManufacturingPage10_t; +#define MFG_PAGE10_HIDE_SSDS_MASK (0x00000003) +#define MFG_PAGE10_HIDE_ALL_DISKS (0x00) +#define MFG_PAGE10_EXPOSE_ALL_DISKS (0x01) +#define MFG_PAGE10_HIDE_IF_VOL_PRESENT (0x02) + + struct MPT2SAS_DEVICE { struct MPT2SAS_TARGET *sas_target; unsigned int lun; @@ -341,6 +360,7 @@ struct _sas_device { * @sdev: scsi device struct (volumes are single lun) * @wwid: unique identifier for the volume * @handle: device handle + * @block_size: Block size of the volume * @id: target id * @channel: target channel * @volume_type: the raid level @@ -348,20 +368,33 @@ struct _sas_device { * @num_pds: number of hidden raid components * @responding: used in _scsih_raid_device_mark_responding * @percent_complete: resync percent complete + * @direct_io_enabled: Whether direct io to PDs are allowed or not + * @stripe_exponent: X where 2powX is the stripe sz in blocks + * @max_lba: Maximum number of LBA in the volume + * @stripe_sz: Stripe Size of the volume + * @device_info: Device info of the volume member disk + * @pd_handle: Array of handles of the physical drives for direct I/O in le16 */ +#define MPT_MAX_WARPDRIVE_PDS 8 struct _raid_device { struct list_head list; struct scsi_target *starget; struct scsi_device *sdev; u64 wwid; u16 handle; + u16 block_sz; int id; int channel; u8 volume_type; - u32 device_info; u8 num_pds; u8 responding; u8 percent_complete; + u8 direct_io_enabled; + u8 stripe_exponent; + u64 max_lba; + u32 stripe_sz; + u32 device_info; + u16 pd_handle[MPT_MAX_WARPDRIVE_PDS]; }; /** @@ -470,6 +503,7 @@ struct chain_tracker { * @smid: system message id * @scmd: scsi request pointer * @cb_idx: callback index + * @direct_io: To indicate whether I/O is direct (WARPDRIVE) * @chain_list: list of chains associated to this IO * @tracker_list: list of free request (ioc->free_list) */ @@ -477,14 +511,14 @@ struct scsiio_tracker { u16 smid; struct scsi_cmnd *scmd; u8 cb_idx; + u8 direct_io; struct list_head chain_list; struct list_head tracker_list; }; /** - * struct request_tracker - misc mf request tracker + * struct request_tracker - firmware request tracker * @smid: system message id - * @scmd: scsi request pointer * @cb_idx: callback index * @tracker_list: list of free request (ioc->free_list) */ @@ -832,6 +866,11 @@ struct MPT2SAS_ADAPTER { u32 diagnostic_flags[MPI2_DIAG_BUF_TYPE_COUNT]; u32 ring_buffer_offset; u32 ring_buffer_sz; + u8 is_warpdrive; + u8 hide_ir_msg; + u8 mfg_pg10_hide_flag; + u8 hide_drives; + }; typedef u8 (*MPT_CALLBACK)(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 msix_index, diff --git a/drivers/scsi/mpt2sas/mpt2sas_ctl.c b/drivers/scsi/mpt2sas/mpt2sas_ctl.c index 1c6d2b4..2661e4f 100644 --- a/drivers/scsi/mpt2sas/mpt2sas_ctl.c +++ b/drivers/scsi/mpt2sas/mpt2sas_ctl.c @@ -1034,7 +1034,10 @@ _ctl_getiocinfo(void __user *arg) __func__)); memset(&karg, 0 , sizeof(karg)); - karg.adapter_type = MPT2_IOCTL_INTERFACE_SAS2; + if (ioc->is_warpdrive) + karg.adapter_type = MPT2_IOCTL_INTERFACE_SAS2_SSS6200; + else + karg.adapter_type = MPT2_IOCTL_INTERFACE_SAS2; if (ioc->pfacts) karg.port_number = ioc->pfacts[0].PortNumber; pci_read_config_byte(ioc->pdev, PCI_CLASS_REVISION, &revision); diff --git a/drivers/scsi/mpt2sas/mpt2sas_ctl.h b/drivers/scsi/mpt2sas/mpt2sas_ctl.h index 69916e4..11ff1d5 100644 --- a/drivers/scsi/mpt2sas/mpt2sas_ctl.h +++ b/drivers/scsi/mpt2sas/mpt2sas_ctl.h @@ -133,6 +133,7 @@ struct mpt2_ioctl_pci_info { #define MPT2_IOCTL_INTERFACE_FC_IP (0x02) #define MPT2_IOCTL_INTERFACE_SAS (0x03) #define MPT2_IOCTL_INTERFACE_SAS2 (0x04) +#define MPT2_IOCTL_INTERFACE_SAS2_SSS6200 (0x05) #define MPT2_IOCTL_VERSION_LENGTH (32) /** diff --git a/drivers/scsi/mpt2sas/mpt2sas_scsih.c b/drivers/scsi/mpt2sas/mpt2sas_scsih.c index 33723ed..f12e023 100644 --- a/drivers/scsi/mpt2sas/mpt2sas_scsih.c +++ b/drivers/scsi/mpt2sas/mpt2sas_scsih.c @@ -233,6 +233,9 @@ static struct pci_device_id scsih_pci_table[] = { PCI_ANY_ID, PCI_ANY_ID }, { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2308_3, PCI_ANY_ID, PCI_ANY_ID }, + /* SSS6200 */ + { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SSS6200, + PCI_ANY_ID, PCI_ANY_ID }, {0} /* Terminating entry */ }; MODULE_DEVICE_TABLE(pci, scsih_pci_table); @@ -1256,6 +1259,7 @@ _scsih_target_alloc(struct scsi_target *starget) sas_target_priv_data->handle = raid_device->handle; sas_target_priv_data->sas_address = raid_device->wwid; sas_target_priv_data->flags |= MPT_TARGET_FLAGS_VOLUME; + sas_target_priv_data->raid_device = raid_device; raid_device->starget = starget; } spin_unlock_irqrestore(&ioc->raid_device_lock, flags); @@ -1455,7 +1459,10 @@ static int _scsih_is_raid(struct device *dev) { struct scsi_device *sdev = to_scsi_device(dev); + struct MPT2SAS_ADAPTER *ioc = shost_priv(sdev->host); + if (ioc->is_warpdrive) + return 0; return (sdev->channel == RAID_CHANNEL) ? 1 : 0; } @@ -1480,7 +1487,7 @@ _scsih_get_resync(struct device *dev) sdev->channel); spin_unlock_irqrestore(&ioc->raid_device_lock, flags); - if (!raid_device) + if (!raid_device || ioc->is_warpdrive) goto out; if (mpt2sas_config_get_raid_volume_pg0(ioc, &mpi_reply, &vol_pg0, @@ -1640,6 +1647,212 @@ _scsih_get_volume_capabilities(struct MPT2SAS_ADAPTER *ioc, kfree(vol_pg0); } +/** + * _scsih_disable_ddio - Disable direct I/O for all the volumes + * @ioc: per adapter object + */ +static void +_scsih_disable_ddio(struct MPT2SAS_ADAPTER *ioc) +{ + Mpi2RaidVolPage1_t vol_pg1; + Mpi2ConfigReply_t mpi_reply; + struct _raid_device *raid_device; + u16 handle; + u16 ioc_status; + + handle = 0xFFFF; + while (!(mpt2sas_config_get_raid_volume_pg1(ioc, &mpi_reply, + &vol_pg1, MPI2_RAID_VOLUME_PGAD_FORM_GET_NEXT_HANDLE, handle))) { + ioc_status = le16_to_cpu(mpi_reply.IOCStatus) & + MPI2_IOCSTATUS_MASK; + if (ioc_status == MPI2_IOCSTATUS_CONFIG_INVALID_PAGE) + break; + handle = le16_to_cpu(vol_pg1.DevHandle); + raid_device = _scsih_raid_device_find_by_handle(ioc, handle); + if (raid_device) + raid_device->direct_io_enabled = 0; + } + return; +} + + +/** + * _scsih_get_num_volumes - Get number of volumes in the ioc + * @ioc: per adapter object + */ +static u8 +_scsih_get_num_volumes(struct MPT2SAS_ADAPTER *ioc) +{ + Mpi2RaidVolPage1_t vol_pg1; + Mpi2ConfigReply_t mpi_reply; + u16 handle; + u8 vol_cnt = 0; + u16 ioc_status; + + handle = 0xFFFF; + while (!(mpt2sas_config_get_raid_volume_pg1(ioc, &mpi_reply, + &vol_pg1, MPI2_RAID_VOLUME_PGAD_FORM_GET_NEXT_HANDLE, handle))) { + ioc_status = le16_to_cpu(mpi_reply.IOCStatus) & + MPI2_IOCSTATUS_MASK; + if (ioc_status == MPI2_IOCSTATUS_CONFIG_INVALID_PAGE) + break; + vol_cnt++; + handle = le16_to_cpu(vol_pg1.DevHandle); + } + return vol_cnt; +} + + +/** + * _scsih_init_warpdrive_properties - Set properties for warpdrive direct I/O. + * @ioc: per adapter object + * @raid_device: the raid_device object + */ +static void +_scsih_init_warpdrive_properties(struct MPT2SAS_ADAPTER *ioc, + struct _raid_device *raid_device) +{ + Mpi2RaidVolPage0_t *vol_pg0; + Mpi2RaidPhysDiskPage0_t pd_pg0; + Mpi2ConfigReply_t mpi_reply; + u16 sz; + u8 num_pds, count; + u64 mb = 1024 * 1024; + u64 tb_2 = 2 * mb * mb; + u64 capacity; + u32 stripe_sz; + u8 i, stripe_exp; + + if (!ioc->is_warpdrive) + return; + + if (ioc->mfg_pg10_hide_flag == MFG_PAGE10_EXPOSE_ALL_DISKS) { + printk(MPT2SAS_INFO_FMT "WarpDrive : Direct IO is disabled " + "globally as drives are exposed\n", ioc->name); + return; + } + if (_scsih_get_num_volumes(ioc) > 1) { + _scsih_disable_ddio(ioc); + printk(MPT2SAS_INFO_FMT "WarpDrive : Direct IO is disabled " + "globally as number of drives > 1\n", ioc->name); + return; + } + if ((mpt2sas_config_get_number_pds(ioc, raid_device->handle, + &num_pds)) || !num_pds) { + printk(MPT2SAS_INFO_FMT "WarpDrive : Direct IO is disabled " + "Failure in computing number of drives\n", ioc->name); + return; + } + + sz = offsetof(Mpi2RaidVolPage0_t, PhysDisk) + (num_pds * + sizeof(Mpi2RaidVol0PhysDisk_t)); + vol_pg0 = kzalloc(sz, GFP_KERNEL); + if (!vol_pg0) { + printk(MPT2SAS_INFO_FMT "WarpDrive : Direct IO is disabled " + "Memory allocation failure for RVPG0\n", ioc->name); + return; + } + + if ((mpt2sas_config_get_raid_volume_pg0(ioc, &mpi_reply, vol_pg0, + MPI2_RAID_VOLUME_PGAD_FORM_HANDLE, raid_device->handle, sz))) { + printk(MPT2SAS_INFO_FMT "WarpDrive : Direct IO is disabled " + "Failure in retrieving RVPG0\n", ioc->name); + kfree(vol_pg0); + return; + } + + /* + * WARPDRIVE:If number of physical disks in a volume exceeds the max pds + * assumed for WARPDRIVE, disable direct I/O + */ + if (num_pds > MPT_MAX_WARPDRIVE_PDS) { + printk(MPT2SAS_WARN_FMT "WarpDrive : Direct IO is disabled " + "for the drive with handle(0x%04x): num_mem=%d, " + "max_mem_allowed=%d\n", ioc->name, raid_device->handle, + num_pds, MPT_MAX_WARPDRIVE_PDS); + kfree(vol_pg0); + return; + } + for (count = 0; count < num_pds; count++) { + if (mpt2sas_config_get_phys_disk_pg0(ioc, &mpi_reply, + &pd_pg0, MPI2_PHYSDISK_PGAD_FORM_PHYSDISKNUM, + vol_pg0->PhysDisk[count].PhysDiskNum) || + pd_pg0.DevHandle == MPT2SAS_INVALID_DEVICE_HANDLE) { + printk(MPT2SAS_INFO_FMT "WarpDrive : Direct IO is " + "disabled for the drive with handle(0x%04x) member" + "handle retrieval failed for member number=%d\n", + ioc->name, raid_device->handle, + vol_pg0->PhysDisk[count].PhysDiskNum); + goto out_error; + } + raid_device->pd_handle[count] = le16_to_cpu(pd_pg0.DevHandle); + } + + /* + * Assumption for WD: Direct I/O is not supported if the volume is + * not RAID0, if the stripe size is not 64KB, if the block size is + * not 512 and if the volume size is >2TB + */ + if (raid_device->volume_type != MPI2_RAID_VOL_TYPE_RAID0 || + le16_to_cpu(vol_pg0->BlockSize) != 512) { + printk(MPT2SAS_INFO_FMT "WarpDrive : Direct IO is disabled " + "for the drive with handle(0x%04x): type=%d, " + "s_sz=%uK, blk_size=%u\n", ioc->name, + raid_device->handle, raid_device->volume_type, + le32_to_cpu(vol_pg0->StripeSize)/2, + le16_to_cpu(vol_pg0->BlockSize)); + goto out_error; + } + + capacity = (u64) le16_to_cpu(vol_pg0->BlockSize) * + (le64_to_cpu(vol_pg0->MaxLBA) + 1); + + if (capacity > tb_2) { + printk(MPT2SAS_INFO_FMT "WarpDrive : Direct IO is disabled " + "for the drive with handle(0x%04x) since drive sz > 2TB\n", + ioc->name, raid_device->handle); + goto out_error; + } + + stripe_sz = le32_to_cpu(vol_pg0->StripeSize); + stripe_exp = 0; + for (i = 0; i < 32; i++) { + if (stripe_sz & 1) + break; + stripe_exp++; + stripe_sz >>= 1; + } + if (i == 32) { + printk(MPT2SAS_INFO_FMT "WarpDrive : Direct IO is disabled " + "for the drive with handle(0x%04x) invalid stripe sz %uK\n", + ioc->name, raid_device->handle, + le32_to_cpu(vol_pg0->StripeSize)/2); + goto out_error; + } + raid_device->stripe_exponent = stripe_exp; + raid_device->direct_io_enabled = 1; + + printk(MPT2SAS_INFO_FMT "WarpDrive : Direct IO is Enabled for the drive" + " with handle(0x%04x)\n", ioc->name, raid_device->handle); + /* + * WARPDRIVE: Though the following fields are not used for direct IO, + * stored for future purpose: + */ + raid_device->max_lba = le64_to_cpu(vol_pg0->MaxLBA); + raid_device->stripe_sz = le32_to_cpu(vol_pg0->StripeSize); + raid_device->block_sz = le16_to_cpu(vol_pg0->BlockSize); + + + kfree(vol_pg0); + return; + +out_error: + raid_device->direct_io_enabled = 0; + for (count = 0; count < num_pds; count++) + raid_device->pd_handle[count] = 0; + kfree(vol_pg0); + return; +} /** * _scsih_enable_tlr - setting TLR flags @@ -1710,6 +1923,11 @@ _scsih_slave_configure(struct scsi_device *sdev) _scsih_get_volume_capabilities(ioc, raid_device); + /* + * WARPDRIVE: Initialize the required data for Direct IO + */ + _scsih_init_warpdrive_properties(ioc, raid_device); + /* RAID Queue Depth Support * IS volume = underlying qdepth of drive type, either * MPT2SAS_SAS_QUEUE_DEPTH or MPT2SAS_SATA_QUEUE_DEPTH @@ -1757,14 +1975,16 @@ _scsih_slave_configure(struct scsi_device *sdev) break; } - sdev_printk(KERN_INFO, sdev, "%s: " - "handle(0x%04x), wwid(0x%016llx), pd_count(%d), type(%s)\n", - r_level, raid_device->handle, - (unsigned long long)raid_device->wwid, - raid_device->num_pds, ds); + if (!ioc->hide_ir_msg) + sdev_printk(KERN_INFO, sdev, "%s: handle(0x%04x), " + "wwid(0x%016llx), pd_count(%d), type(%s)\n", + r_level, raid_device->handle, + (unsigned long long)raid_device->wwid, + raid_device->num_pds, ds); _scsih_change_queue_depth(sdev, qdepth, SCSI_QDEPTH_DEFAULT); /* raid transport support */ - _scsih_set_level(sdev, raid_device); + if (!ioc->is_warpdrive) + _scsih_set_level(sdev, raid_device); return 0; } @@ -2181,16 +2401,20 @@ _scsih_tm_display_info(struct MPT2SAS_ADAPTER *ioc, struct scsi_cmnd *scmd) struct MPT2SAS_TARGET *priv_target = starget->hostdata; struct _sas_device *sas_device = NULL; unsigned long flags; + char *device_str = NULL; if (!priv_target) return; + if (ioc->hide_ir_msg) + device_str = "WarpDrive"; + else + device_str = "volume"; scsi_print_command(scmd); if (priv_target->flags & MPT_TARGET_FLAGS_VOLUME) { - starget_printk(KERN_INFO, starget, "volume handle(0x%04x), " - "volume wwid(0x%016llx)\n", - priv_target->handle, - (unsigned long long)priv_target->sas_address); + starget_printk(KERN_INFO, starget, "%s handle(0x%04x), " + "%s wwid(0x%016llx)\n", device_str, priv_target->handle, + device_str, (unsigned long long)priv_target->sas_address); } else { spin_lock_irqsave(&ioc->sas_device_lock, flags); sas_device = mpt2sas_scsih_sas_device_find_by_sas_address(ioc, @@ -3129,6 +3353,9 @@ _scsih_check_ir_config_unhide_events(struct MPT2SAS_ADAPTER *ioc, a = 0; b = 0; + if (ioc->is_warpdrive) + return; + /* Volume Resets for Deleted or Removed */ element = (Mpi2EventIrConfigElement_t *)&event_data->ConfigElement[0]; for (i = 0; i < event_data->NumElements; i++, element++) { @@ -3346,6 +3573,105 @@ _scsih_eedp_error_handling(struct scsi_cmnd *scmd, u16 ioc_status) } /** + * _scsih_scsi_direct_io_get - returns direct io flag + * @ioc: per adapter object + * @smid: system request message index + * + * Returns the smid stored scmd pointer. + */ +static inline u8 +_scsih_scsi_direct_io_get(struct MPT2SAS_ADAPTER *ioc, u16 smid) +{ + return ioc->scsi_lookup[smid - 1].direct_io; +} + +/** + * _scsih_scsi_direct_io_set - sets direct io flag + * @ioc: per adapter object + * @smid: system request message index + * @direct_io: Zero or non-zero value to set in the direct_io flag + * + * Returns Nothing. + */ +static inline void +_scsih_scsi_direct_io_set(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 direct_io) +{ + ioc->scsi_lookup[smid - 1].direct_io = direct_io; +} + + +/** + * _scsih_setup_direct_io - setup MPI request for WARPDRIVE Direct I/O + * @ioc: per adapter object + * @scmd: pointer to scsi command object + * @raid_device: pointer to raid device data structure + * @mpi_request: pointer to the SCSI_IO reqest message frame + * @smid: system request message index + * + * Returns nothing + */ +static void +_scsih_setup_direct_io(struct MPT2SAS_ADAPTER *ioc, struct scsi_cmnd *scmd, + struct _raid_device *raid_device, Mpi2SCSIIORequest_t *mpi_request, + u16 smid) +{ + u32 v_lba, p_lba, stripe_off, stripe_unit, column, io_size; + u32 stripe_sz, stripe_exp; + u8 num_pds, *cdb_ptr, *tmp_ptr, *lba_ptr1, *lba_ptr2; + u8 cdb0 = scmd->cmnd[0]; + + /* + * Try Direct I/O to RAID memeber disks + */ + if (cdb0 == READ_16 || cdb0 == READ_10 || + cdb0 == WRITE_16 || cdb0 == WRITE_10) { + cdb_ptr = mpi_request->CDB.CDB32; + + if ((cdb0 < READ_16) || !(cdb_ptr[2] | cdb_ptr[3] | cdb_ptr[4] + | cdb_ptr[5])) { + io_size = scsi_bufflen(scmd) >> 9; + /* get virtual lba */ + lba_ptr1 = lba_ptr2 = (cdb0 < READ_16) ? &cdb_ptr[2] : + &cdb_ptr[6]; + tmp_ptr = (u8 *)&v_lba + 3; + *tmp_ptr-- = *lba_ptr1++; + *tmp_ptr-- = *lba_ptr1++; + *tmp_ptr-- = *lba_ptr1++; + *tmp_ptr = *lba_ptr1; + + if (((u64)v_lba + (u64)io_size - 1) <= + (u32)raid_device->max_lba) { + stripe_sz = raid_device->stripe_sz; + stripe_exp = raid_device->stripe_exponent; + stripe_off = v_lba & (stripe_sz - 1); + + /* Check whether IO falls within a stripe */ + if ((stripe_off + io_size) <= stripe_sz) { + num_pds = raid_device->num_pds; + p_lba = v_lba >> stripe_exp; + stripe_unit = p_lba / num_pds; + column = p_lba % num_pds; + p_lba = (stripe_unit << stripe_exp) + + stripe_off; + mpi_request->DevHandle = + cpu_to_le16(raid_device-> + pd_handle[column]); + tmp_ptr = (u8 *)&p_lba + 3; + *lba_ptr2++ = *tmp_ptr--; + *lba_ptr2++ = *tmp_ptr--; + *lba_ptr2++ = *tmp_ptr--; + *lba_ptr2 = *tmp_ptr; + /* + * WD: To indicate this I/O is directI/O + */ + _scsih_scsi_direct_io_set(ioc, smid, 1); + } + } + } + } +} + +/** * _scsih_qcmd - main scsi request entry point * @scmd: pointer to scsi command object * @done: function pointer to be invoked on completion @@ -3362,6 +3688,7 @@ _scsih_qcmd_lck(struct scsi_cmnd *scmd, void (*done)(struct scsi_cmnd *)) struct MPT2SAS_ADAPTER *ioc = shost_priv(scmd->device->host); struct MPT2SAS_DEVICE *sas_device_priv_data; struct MPT2SAS_TARGET *sas_target_priv_data; + struct _raid_device *raid_device; Mpi2SCSIIORequest_t *mpi_request; u32 mpi_control; u16 smid; @@ -3423,8 +3750,10 @@ _scsih_qcmd_lck(struct scsi_cmnd *scmd, void (*done)(struct scsi_cmnd *)) } else mpi_control |= MPI2_SCSIIO_CONTROL_SIMPLEQ; - /* Make sure Device is not raid volume */ - if (!_scsih_is_raid(&scmd->device->sdev_gendev) && + /* Make sure Device is not raid volume. + * We do not expose raid functionality to upper layer for warpdrive. + */ + if (!ioc->is_warpdrive && !_scsih_is_raid(&scmd->device->sdev_gendev) && sas_is_tlr_enabled(scmd->device) && scmd->cmd_len != 32) mpi_control |= MPI2_SCSIIO_CONTROL_TLR_ON; @@ -3472,9 +3801,14 @@ _scsih_qcmd_lck(struct scsi_cmnd *scmd, void (*done)(struct scsi_cmnd *)) } } + raid_device = sas_target_priv_data->raid_device; + if (raid_device && raid_device->direct_io_enabled) + _scsih_setup_direct_io(ioc, scmd, raid_device, mpi_request, + smid); + if (likely(mpi_request->Function == MPI2_FUNCTION_SCSI_IO_REQUEST)) mpt2sas_base_put_smid_scsi_io(ioc, smid, - sas_device_priv_data->sas_target->handle); + le16_to_cpu(mpi_request->DevHandle)); else mpt2sas_base_put_smid_default(ioc, smid); return 0; @@ -3539,10 +3873,16 @@ _scsih_scsi_ioc_info(struct MPT2SAS_ADAPTER *ioc, struct scsi_cmnd *scmd, unsigned long flags; struct scsi_target *starget = scmd->device->sdev_target; struct MPT2SAS_TARGET *priv_target = starget->hostdata; + char *device_str = NULL; if (!priv_target) return; + if (ioc->hide_ir_msg) + device_str = "WarpDrive"; + else + device_str = "volume"; + if (log_info == 0x31170000) return; @@ -3659,8 +3999,8 @@ _scsih_scsi_ioc_info(struct MPT2SAS_ADAPTER *ioc, struct scsi_cmnd *scmd, scsi_print_command(scmd); if (priv_target->flags & MPT_TARGET_FLAGS_VOLUME) { - printk(MPT2SAS_WARN_FMT "\tvolume wwid(0x%016llx)\n", ioc->name, - (unsigned long long)priv_target->sas_address); + printk(MPT2SAS_WARN_FMT "\t%s wwid(0x%016llx)\n", ioc->name, + device_str, (unsigned long long)priv_target->sas_address); } else { spin_lock_irqsave(&ioc->sas_device_lock, flags); sas_device = mpt2sas_scsih_sas_device_find_by_sas_address(ioc, @@ -3839,6 +4179,20 @@ _scsih_io_done(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 msix_index, u32 reply) scmd->result = DID_NO_CONNECT << 16; goto out; } + /* + * WARPDRIVE: If direct_io is set then it is directIO, + * the failed direct I/O should be redirected to volume + */ + if (_scsih_scsi_direct_io_get(ioc, smid)) { + _scsih_scsi_direct_io_set(ioc, smid, 0); + memcpy(mpi_request->CDB.CDB32, scmd->cmnd, scmd->cmd_len); + mpi_request->DevHandle = + cpu_to_le16(sas_device_priv_data->sas_target->handle); + mpt2sas_base_put_smid_scsi_io(ioc, smid, + sas_device_priv_data->sas_target->handle); + return 0; + } + /* turning off TLR */ scsi_state = mpi_reply->SCSIState; @@ -3847,7 +4201,10 @@ _scsih_io_done(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 msix_index, u32 reply) le32_to_cpu(mpi_reply->ResponseInfo) & 0xFF; if (!sas_device_priv_data->tlr_snoop_check) { sas_device_priv_data->tlr_snoop_check++; - if (!_scsih_is_raid(&scmd->device->sdev_gendev) && + /* Make sure Device is not raid volume. + * We do not expose raid functionality to upper layer for warpdrive. + */ + if (!ioc->is_warpdrive && !_scsih_is_raid(&scmd->device->sdev_gendev) && sas_is_tlr_enabled(scmd->device) && response_code == MPI2_SCSITASKMGMT_RSP_INVALID_FRAME) { sas_disable_tlr(scmd->device); @@ -4680,8 +5037,10 @@ _scsih_remove_device(struct MPT2SAS_ADAPTER *ioc, _scsih_ublock_io_device(ioc, sas_device_backup.handle); - mpt2sas_transport_port_remove(ioc, sas_device_backup.sas_address, - sas_device_backup.sas_address_parent); + if (!ioc->hide_drives) + mpt2sas_transport_port_remove(ioc, + sas_device_backup.sas_address, + sas_device_backup.sas_address_parent); printk(MPT2SAS_INFO_FMT "removing handle(0x%04x), sas_addr" "(0x%016llx)\n", ioc->name, sas_device_backup.handle, @@ -5412,6 +5771,7 @@ _scsih_sas_pd_hide(struct MPT2SAS_ADAPTER *ioc, &sas_device->volume_wwid); set_bit(handle, ioc->pd_handles); _scsih_reprobe_target(sas_device->starget, 1); + } /** @@ -5590,7 +5950,8 @@ _scsih_sas_ir_config_change_event(struct MPT2SAS_ADAPTER *ioc, Mpi2EventDataIrConfigChangeList_t *event_data = fw_event->event_data; #ifdef CONFIG_SCSI_MPT2SAS_LOGGING - if (ioc->logging_level & MPT_DEBUG_EVENT_WORK_TASK) + if ((ioc->logging_level & MPT_DEBUG_EVENT_WORK_TASK) + && !ioc->hide_ir_msg) _scsih_sas_ir_config_change_event_debug(ioc, event_data); #endif @@ -5613,16 +5974,20 @@ _scsih_sas_ir_config_change_event(struct MPT2SAS_ADAPTER *ioc, le16_to_cpu(element->VolDevHandle)); break; case MPI2_EVENT_IR_CHANGE_RC_PD_CREATED: - _scsih_sas_pd_hide(ioc, element); + if (!ioc->is_warpdrive) + _scsih_sas_pd_hide(ioc, element); break; case MPI2_EVENT_IR_CHANGE_RC_PD_DELETED: - _scsih_sas_pd_expose(ioc, element); + if (!ioc->is_warpdrive) + _scsih_sas_pd_expose(ioc, element); break; case MPI2_EVENT_IR_CHANGE_RC_HIDE: - _scsih_sas_pd_add(ioc, element); + if (!ioc->is_warpdrive) + _scsih_sas_pd_add(ioc, element); break; case MPI2_EVENT_IR_CHANGE_RC_UNHIDE: - _scsih_sas_pd_delete(ioc, element); + if (!ioc->is_warpdrive) + _scsih_sas_pd_delete(ioc, element); break; } } @@ -5653,9 +6018,10 @@ _scsih_sas_ir_volume_event(struct MPT2SAS_ADAPTER *ioc, handle = le16_to_cpu(event_data->VolDevHandle); state = le32_to_cpu(event_data->NewValue); - dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: handle(0x%04x), " - "old(0x%08x), new(0x%08x)\n", ioc->name, __func__, handle, - le32_to_cpu(event_data->PreviousValue), state)); + if (!ioc->hide_ir_msg) + dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: handle(0x%04x), " + "old(0x%08x), new(0x%08x)\n", ioc->name, __func__, handle, + le32_to_cpu(event_data->PreviousValue), state)); switch (state) { case MPI2_RAID_VOL_STATE_MISSING: @@ -5735,9 +6101,10 @@ _scsih_sas_ir_physical_disk_event(struct MPT2SAS_ADAPTER *ioc, handle = le16_to_cpu(event_data->PhysDiskDevHandle); state = le32_to_cpu(event_data->NewValue); - dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: handle(0x%04x), " - "old(0x%08x), new(0x%08x)\n", ioc->name, __func__, handle, - le32_to_cpu(event_data->PreviousValue), state)); + if (!ioc->hide_ir_msg) + dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: handle(0x%04x), " + "old(0x%08x), new(0x%08x)\n", ioc->name, __func__, handle, + le32_to_cpu(event_data->PreviousValue), state)); switch (state) { case MPI2_RAID_PD_STATE_ONLINE: @@ -5746,7 +6113,8 @@ _scsih_sas_ir_physical_disk_event(struct MPT2SAS_ADAPTER *ioc, case MPI2_RAID_PD_STATE_OPTIMAL: case MPI2_RAID_PD_STATE_HOT_SPARE: - set_bit(handle, ioc->pd_handles); + if (!ioc->is_warpdrive) + set_bit(handle, ioc->pd_handles); spin_lock_irqsave(&ioc->sas_device_lock, flags); sas_device = _scsih_sas_device_find_by_handle(ioc, handle); @@ -5850,7 +6218,8 @@ _scsih_sas_ir_operation_status_event(struct MPT2SAS_ADAPTER *ioc, u16 handle; #ifdef CONFIG_SCSI_MPT2SAS_LOGGING - if (ioc->logging_level & MPT_DEBUG_EVENT_WORK_TASK) + if ((ioc->logging_level & MPT_DEBUG_EVENT_WORK_TASK) + && !ioc->hide_ir_msg) _scsih_sas_ir_operation_status_event_debug(ioc, event_data); #endif @@ -5909,7 +6278,7 @@ static void _scsih_mark_responding_sas_device(struct MPT2SAS_ADAPTER *ioc, u64 sas_address, u16 slot, u16 handle) { - struct MPT2SAS_TARGET *sas_target_priv_data; + struct MPT2SAS_TARGET *sas_target_priv_data = NULL; struct scsi_target *starget; struct _sas_device *sas_device; unsigned long flags; @@ -5917,7 +6286,7 @@ _scsih_mark_responding_sas_device(struct MPT2SAS_ADAPTER *ioc, u64 sas_address, spin_lock_irqsave(&ioc->sas_device_lock, flags); list_for_each_entry(sas_device, &ioc->sas_device_list, list) { if (sas_device->sas_address == sas_address && - sas_device->slot == slot && sas_device->starget) { + sas_device->slot == slot) { sas_device->responding = 1; starget = sas_device->starget; if (starget && starget->hostdata) { @@ -5926,13 +6295,15 @@ _scsih_mark_responding_sas_device(struct MPT2SAS_ADAPTER *ioc, u64 sas_address, sas_target_priv_data->deleted = 0; } else sas_target_priv_data = NULL; - starget_printk(KERN_INFO, sas_device->starget, - "handle(0x%04x), sas_addr(0x%016llx), enclosure " - "logical id(0x%016llx), slot(%d)\n", handle, - (unsigned long long)sas_device->sas_address, - (unsigned long long) - sas_device->enclosure_logical_id, - sas_device->slot); + if (starget) + starget_printk(KERN_INFO, starget, + "handle(0x%04x), sas_addr(0x%016llx), " + "enclosure logical id(0x%016llx), " + "slot(%d)\n", handle, + (unsigned long long)sas_device->sas_address, + (unsigned long long) + sas_device->enclosure_logical_id, + sas_device->slot); if (sas_device->handle == handle) goto out; printk(KERN_INFO "\thandle changed from(0x%04x)!!!\n", @@ -6024,6 +6395,12 @@ _scsih_mark_responding_raid_device(struct MPT2SAS_ADAPTER *ioc, u64 wwid, starget_printk(KERN_INFO, raid_device->starget, "handle(0x%04x), wwid(0x%016llx)\n", handle, (unsigned long long)raid_device->wwid); + /* + * WARPDRIVE: The handles of the PDs might have changed + * across the host reset so re-initialize the + * required data for Direct IO + */ + _scsih_init_warpdrive_properties(ioc, raid_device); if (raid_device->handle == handle) goto out; printk(KERN_INFO "\thandle changed from(0x%04x)!!!\n", @@ -6085,18 +6462,20 @@ _scsih_search_responding_raid_devices(struct MPT2SAS_ADAPTER *ioc) } /* refresh the pd_handles */ - phys_disk_num = 0xFF; - memset(ioc->pd_handles, 0, ioc->pd_handles_sz); - while (!(mpt2sas_config_get_phys_disk_pg0(ioc, &mpi_reply, - &pd_pg0, MPI2_PHYSDISK_PGAD_FORM_GET_NEXT_PHYSDISKNUM, - phys_disk_num))) { - ioc_status = le16_to_cpu(mpi_reply.IOCStatus) & - MPI2_IOCSTATUS_MASK; - if (ioc_status == MPI2_IOCSTATUS_CONFIG_INVALID_PAGE) - break; - phys_disk_num = pd_pg0.PhysDiskNum; - handle = le16_to_cpu(pd_pg0.DevHandle); - set_bit(handle, ioc->pd_handles); + if (!ioc->is_warpdrive) { + phys_disk_num = 0xFF; + memset(ioc->pd_handles, 0, ioc->pd_handles_sz); + while (!(mpt2sas_config_get_phys_disk_pg0(ioc, &mpi_reply, + &pd_pg0, MPI2_PHYSDISK_PGAD_FORM_GET_NEXT_PHYSDISKNUM, + phys_disk_num))) { + ioc_status = le16_to_cpu(mpi_reply.IOCStatus) & + MPI2_IOCSTATUS_MASK; + if (ioc_status == MPI2_IOCSTATUS_CONFIG_INVALID_PAGE) + break; + phys_disk_num = pd_pg0.PhysDiskNum; + handle = le16_to_cpu(pd_pg0.DevHandle); + set_bit(handle, ioc->pd_handles); + } } } @@ -6242,6 +6621,50 @@ _scsih_remove_unresponding_sas_devices(struct MPT2SAS_ADAPTER *ioc) } /** + * _scsih_hide_unhide_sas_devices - add/remove device to/from OS + * @ioc: per adapter object + * + * Return nothing. + */ +static void +_scsih_hide_unhide_sas_devices(struct MPT2SAS_ADAPTER *ioc) +{ + struct _sas_device *sas_device, *sas_device_next; + + if (!ioc->is_warpdrive || ioc->mfg_pg10_hide_flag != + MFG_PAGE10_HIDE_IF_VOL_PRESENT) + return; + + if (ioc->hide_drives) { + if (_scsih_get_num_volumes(ioc)) + return; + ioc->hide_drives = 0; + list_for_each_entry_safe(sas_device, sas_device_next, + &ioc->sas_device_list, list) { + if (!mpt2sas_transport_port_add(ioc, sas_device->handle, + sas_device->sas_address_parent)) { + _scsih_sas_device_remove(ioc, sas_device); + } else if (!sas_device->starget) { + mpt2sas_transport_port_remove(ioc, + sas_device->sas_address, + sas_device->sas_address_parent); + _scsih_sas_device_remove(ioc, sas_device); + } + } + } else { + if (!_scsih_get_num_volumes(ioc)) + return; + ioc->hide_drives = 1; + list_for_each_entry_safe(sas_device, sas_device_next, + &ioc->sas_device_list, list) { + mpt2sas_transport_port_remove(ioc, + sas_device->sas_address, + sas_device->sas_address_parent); + } + } +} + +/** * mpt2sas_scsih_reset_handler - reset callback handler (for scsih) * @ioc: per adapter object * @reset_phase: phase @@ -6325,6 +6748,7 @@ _firmware_event_work(struct work_struct *work) spin_unlock_irqrestore(&ioc->ioc_reset_in_progress_lock, flags); _scsih_remove_unresponding_sas_devices(ioc); + _scsih_hide_unhide_sas_devices(ioc); return; } @@ -6424,6 +6848,53 @@ mpt2sas_scsih_event_callback(struct MPT2SAS_ADAPTER *ioc, u8 msix_index, (Mpi2EventDataIrVolume_t *) mpi_reply->EventData); break; + case MPI2_EVENT_LOG_ENTRY_ADDED: + { + Mpi2EventDataLogEntryAdded_t *log_entry; + u32 *log_code; + + if (!ioc->is_warpdrive) + break; + + log_entry = (Mpi2EventDataLogEntryAdded_t *) + mpi_reply->EventData; + log_code = (u32 *)log_entry->LogData; + + if (le16_to_cpu(log_entry->LogEntryQualifier) + != MPT2_WARPDRIVE_LOGENTRY) + break; + + switch (le32_to_cpu(*log_code)) { + case MPT2_WARPDRIVE_LC_SSDT: + printk(MPT2SAS_WARN_FMT "WarpDrive Warning: " + "IO Throttling has occurred in the WarpDrive " + "subsystem. Check WarpDrive documentation for " + "additional details.\n", ioc->name); + break; + case MPT2_WARPDRIVE_LC_SSDLW: + printk(MPT2SAS_WARN_FMT "WarpDrive Warning: " + "Program/Erase Cycles for the WarpDrive subsystem " + "in degraded range. Check WarpDrive documentation " + "for additional details.\n", ioc->name); + break; + case MPT2_WARPDRIVE_LC_SSDLF: + printk(MPT2SAS_ERR_FMT "WarpDrive Fatal Error: " + "There are no Program/Erase Cycles for the " + "WarpDrive subsystem. The storage device will be " + "in read-only mode. Check WarpDrive documentation " + "for additional details.\n", ioc->name); + break; + case MPT2_WARPDRIVE_LC_BRMF: + printk(MPT2SAS_ERR_FMT "WarpDrive Fatal Error: " + "The Backup Rail Monitor has failed on the " + "WarpDrive subsystem. Check WarpDrive " + "documentation for additional details.\n", + ioc->name); + break; + } + + break; + } case MPI2_EVENT_SAS_DEVICE_STATUS_CHANGE: case MPI2_EVENT_IR_OPERATION_STATUS: case MPI2_EVENT_SAS_DISCOVERY: @@ -6582,7 +7053,8 @@ _scsih_ir_shutdown(struct MPT2SAS_ADAPTER *ioc) mpi_request->Function = MPI2_FUNCTION_RAID_ACTION; mpi_request->Action = MPI2_RAID_ACTION_SYSTEM_SHUTDOWN_INITIATED; - printk(MPT2SAS_INFO_FMT "IR shutdown (sending)\n", ioc->name); + if (!ioc->hide_ir_msg) + printk(MPT2SAS_INFO_FMT "IR shutdown (sending)\n", ioc->name); init_completion(&ioc->scsih_cmds.done); mpt2sas_base_put_smid_default(ioc, smid); wait_for_completion_timeout(&ioc->scsih_cmds.done, 10*HZ); @@ -6596,10 +7068,11 @@ _scsih_ir_shutdown(struct MPT2SAS_ADAPTER *ioc) if (ioc->scsih_cmds.status & MPT2_CMD_REPLY_VALID) { mpi_reply = ioc->scsih_cmds.reply; - printk(MPT2SAS_INFO_FMT "IR shutdown (complete): " - "ioc_status(0x%04x), loginfo(0x%08x)\n", - ioc->name, le16_to_cpu(mpi_reply->IOCStatus), - le32_to_cpu(mpi_reply->IOCLogInfo)); + if (!ioc->hide_ir_msg) + printk(MPT2SAS_INFO_FMT "IR shutdown (complete): " + "ioc_status(0x%04x), loginfo(0x%08x)\n", + ioc->name, le16_to_cpu(mpi_reply->IOCStatus), + le32_to_cpu(mpi_reply->IOCLogInfo)); } out: @@ -6758,6 +7231,9 @@ _scsih_probe_boot_devices(struct MPT2SAS_ADAPTER *ioc) spin_lock_irqsave(&ioc->sas_device_lock, flags); list_move_tail(&sas_device->list, &ioc->sas_device_list); spin_unlock_irqrestore(&ioc->sas_device_lock, flags); + + if (ioc->hide_drives) + return; if (!mpt2sas_transport_port_add(ioc, sas_device->handle, sas_device->sas_address_parent)) { _scsih_sas_device_remove(ioc, sas_device); @@ -6811,6 +7287,9 @@ _scsih_probe_sas(struct MPT2SAS_ADAPTER *ioc) list_move_tail(&sas_device->list, &ioc->sas_device_list); spin_unlock_irqrestore(&ioc->sas_device_lock, flags); + if (ioc->hide_drives) + continue; + if (!mpt2sas_transport_port_add(ioc, sas_device->handle, sas_device->sas_address_parent)) { _scsih_sas_device_remove(ioc, sas_device); @@ -6881,6 +7360,11 @@ _scsih_probe(struct pci_dev *pdev, const struct pci_device_id *id) ioc->id = mpt_ids++; sprintf(ioc->name, "%s%d", MPT2SAS_DRIVER_NAME, ioc->id); ioc->pdev = pdev; + if (id->device == MPI2_MFGPAGE_DEVID_SSS6200) { + ioc->is_warpdrive = 1; + ioc->hide_ir_msg = 1; + } else + ioc->mfg_pg10_hide_flag = MFG_PAGE10_EXPOSE_ALL_DISKS; ioc->scsi_io_cb_idx = scsi_io_cb_idx; ioc->tm_cb_idx = tm_cb_idx; ioc->ctl_cb_idx = ctl_cb_idx; @@ -6946,6 +7430,20 @@ _scsih_probe(struct pci_dev *pdev, const struct pci_device_id *id) } ioc->wait_for_port_enable_to_complete = 0; + if (ioc->is_warpdrive) { + if (ioc->mfg_pg10_hide_flag == MFG_PAGE10_EXPOSE_ALL_DISKS) + ioc->hide_drives = 0; + else if (ioc->mfg_pg10_hide_flag == MFG_PAGE10_HIDE_ALL_DISKS) + ioc->hide_drives = 1; + else { + if (_scsih_get_num_volumes(ioc)) + ioc->hide_drives = 1; + else + ioc->hide_drives = 0; + } + } else + ioc->hide_drives = 0; + _scsih_probe_devices(ioc); return 0; -- cgit v0.10.2 From 630ad8317feed51c55fa5c1c701e67430923aad8 Mon Sep 17 00:00:00 2001 From: Wayne Boyer Date: Thu, 7 Apr 2011 12:12:30 -0700 Subject: [SCSI] ipr: remove unneeded volatile declarations This patch removes three volatile declarations based on some feedback and code analysis. Signed-off-by: Wayne Boyer Acked-by: Brian King Signed-off-by: James Bottomley diff --git a/drivers/scsi/ipr.c b/drivers/scsi/ipr.c index 37790c0..a485e52 100644 --- a/drivers/scsi/ipr.c +++ b/drivers/scsi/ipr.c @@ -4953,7 +4953,7 @@ static int ipr_eh_abort(struct scsi_cmnd * scsi_cmd) * IRQ_NONE / IRQ_HANDLED **/ static irqreturn_t ipr_handle_other_interrupt(struct ipr_ioa_cfg *ioa_cfg, - volatile u32 int_reg) + u32 int_reg) { irqreturn_t rc = IRQ_HANDLED; @@ -5016,7 +5016,7 @@ static irqreturn_t ipr_isr(int irq, void *devp) { struct ipr_ioa_cfg *ioa_cfg = (struct ipr_ioa_cfg *)devp; unsigned long lock_flags = 0; - volatile u32 int_reg, int_mask_reg; + u32 int_reg, int_mask_reg; u32 ioasc; u16 cmd_index; int num_hrrq = 0; @@ -7517,7 +7517,7 @@ static int ipr_reset_get_unit_check_job(struct ipr_cmnd *ipr_cmd) static int ipr_reset_restore_cfg_space(struct ipr_cmnd *ipr_cmd) { struct ipr_ioa_cfg *ioa_cfg = ipr_cmd->ioa_cfg; - volatile u32 int_reg; + u32 int_reg; ENTER; ioa_cfg->pdev->state_saved = true; -- cgit v0.10.2 From eebe9b96dda9018cc68a2855ca506ec26a1e449e Mon Sep 17 00:00:00 2001 From: "Moger, Babu" Date: Fri, 8 Apr 2011 11:37:40 -0600 Subject: [SCSI] scsi_dh_rdac : Add definitions for different RDAC operating modes This patch adds definitions to support for different operating modes for LSI rdac storage. Currently, rdac support 3 operation modes. 1. RDAC mode(legacy) 2. AVT mode 3. IOSHIP mode These definitions are used while activating the path(rdac_activate). Signed-off-by: Babu Moger Reviewed-by: Yanling Qi Reviewed-by: Sudhir Dachepalli Reviewed-by: Somasundaram Krishnasamy Reviewed-by: Bob Stankey Reviewed-by: Vijay Chauhan Signed-off-by: James Bottomley diff --git a/drivers/scsi/device_handler/scsi_dh_rdac.c b/drivers/scsi/device_handler/scsi_dh_rdac.c index 293c183..afb2fb1 100644 --- a/drivers/scsi/device_handler/scsi_dh_rdac.c +++ b/drivers/scsi/device_handler/scsi_dh_rdac.c @@ -182,6 +182,12 @@ struct rdac_dh_data { struct rdac_controller *ctlr; #define UNINITIALIZED_LUN (1 << 8) unsigned lun; + +#define RDAC_MODE 0 +#define RDAC_MODE_AVT 1 +#define RDAC_MODE_IOSHIP 2 + unsigned char mode; + #define RDAC_STATE_ACTIVE 0 #define RDAC_STATE_PASSIVE 1 unsigned char state; @@ -190,6 +196,11 @@ struct rdac_dh_data { #define RDAC_LUN_OWNED 1 #define RDAC_LUN_AVT 2 char lun_state; + +#define RDAC_PREFERRED 0 +#define RDAC_NON_PREFERRED 1 + char preferred; + unsigned char sense[SCSI_SENSE_BUFFERSIZE]; union { struct c2_inquiry c2; @@ -199,11 +210,15 @@ struct rdac_dh_data { } inq; }; +static const char *mode[] = { + "RDAC", + "AVT", + "IOSHIP", +}; static const char *lun_state[] = { "unowned", "owned", - "owned (AVT mode)", }; struct rdac_queue_data { @@ -836,8 +851,9 @@ static int rdac_bus_attach(struct scsi_device *sdev) spin_unlock_irqrestore(sdev->request_queue->queue_lock, flags); sdev_printk(KERN_NOTICE, sdev, - "%s: LUN %d (%s)\n", - RDAC_NAME, h->lun, lun_state[(int)h->lun_state]); + "%s: LUN %d (%s) (%s)\n", + RDAC_NAME, h->lun, mode[(int)h->mode], + lun_state[(int)h->lun_state]); return 0; -- cgit v0.10.2 From 1c3afc423460035a6c2d0e4f01217e953bad3fd7 Mon Sep 17 00:00:00 2001 From: "Moger, Babu" Date: Fri, 8 Apr 2011 11:38:33 -0600 Subject: [SCSI] scsi_dh_rdac : Detect the different RDAC operating modes This patch detects different operating RDAC modes during the discovery. It also collects the information about the preferred path. Signed-off-by: Babu Moger Reviewed-by: Yanling Qi Reviewed-by: Sudhir Dachepalli Reviewed-by: Somasundaram Krishnasamy Reviewed-by: Bob Stankey Reviewed-by: Vijay Chauhan Signed-off-by: James Bottomley diff --git a/drivers/scsi/device_handler/scsi_dh_rdac.c b/drivers/scsi/device_handler/scsi_dh_rdac.c index afb2fb1..4efe638 100644 --- a/drivers/scsi/device_handler/scsi_dh_rdac.c +++ b/drivers/scsi/device_handler/scsi_dh_rdac.c @@ -194,7 +194,6 @@ struct rdac_dh_data { #define RDAC_LUN_UNOWNED 0 #define RDAC_LUN_OWNED 1 -#define RDAC_LUN_AVT 2 char lun_state; #define RDAC_PREFERRED 0 @@ -473,25 +472,33 @@ static int check_ownership(struct scsi_device *sdev, struct rdac_dh_data *h) int err; struct c9_inquiry *inqp; - h->lun_state = RDAC_LUN_UNOWNED; h->state = RDAC_STATE_ACTIVE; err = submit_inquiry(sdev, 0xC9, sizeof(struct c9_inquiry), h); if (err == SCSI_DH_OK) { inqp = &h->inq.c9; - if ((inqp->avte_cvp >> 7) == 0x1) { - /* LUN in AVT mode */ - sdev_printk(KERN_NOTICE, sdev, - "%s: AVT mode detected\n", - RDAC_NAME); - h->lun_state = RDAC_LUN_AVT; - } else if ((inqp->avte_cvp & 0x1) != 0) { - /* LUN was owned by the controller */ + /* detect the operating mode */ + if ((inqp->avte_cvp >> 5) & 0x1) + h->mode = RDAC_MODE_IOSHIP; /* LUN in IOSHIP mode */ + else if (inqp->avte_cvp >> 7) + h->mode = RDAC_MODE_AVT; /* LUN in AVT mode */ + else + h->mode = RDAC_MODE; /* LUN in RDAC mode */ + + /* Update ownership */ + if (inqp->avte_cvp & 0x1) h->lun_state = RDAC_LUN_OWNED; + else { + h->lun_state = RDAC_LUN_UNOWNED; + if (h->mode == RDAC_MODE) + h->state = RDAC_STATE_PASSIVE; } - } - if (h->lun_state == RDAC_LUN_UNOWNED) - h->state = RDAC_STATE_PASSIVE; + /* Update path prio*/ + if (inqp->path_prio & 0x1) + h->preferred = RDAC_PREFERRED; + else + h->preferred = RDAC_NON_PREFERRED; + } return err; } -- cgit v0.10.2 From 3425fbfe2293244abba72c80b215d09ead32d1ad Mon Sep 17 00:00:00 2001 From: "Moger, Babu" Date: Fri, 8 Apr 2011 11:39:30 -0600 Subject: [SCSI] scsi_dh_rdac : decide whether to send mode select based on operating mode Based on the operating modes, handler decides whether to send mode select or not. Purpose here is to reduce io-shipping as much as possible whenever there is an option. Signed-off-by: Babu Moger Reviewed-by: Yanling Qi Reviewed-by: Sudhir Dachepalli Reviewed-by: Somasundaram Krishnasamy Reviewed-by: Bob Stankey Reviewed-by: Vijay Chauhan Signed-off-by: James Bottomley diff --git a/drivers/scsi/device_handler/scsi_dh_rdac.c b/drivers/scsi/device_handler/scsi_dh_rdac.c index 4efe638..e7fc70d 100644 --- a/drivers/scsi/device_handler/scsi_dh_rdac.c +++ b/drivers/scsi/device_handler/scsi_dh_rdac.c @@ -670,12 +670,27 @@ static int rdac_activate(struct scsi_device *sdev, { struct rdac_dh_data *h = get_rdac_data(sdev); int err = SCSI_DH_OK; + int act = 0; err = check_ownership(sdev, h); if (err != SCSI_DH_OK) goto done; - if (h->lun_state == RDAC_LUN_UNOWNED) { + switch (h->mode) { + case RDAC_MODE: + if (h->lun_state == RDAC_LUN_UNOWNED) + act = 1; + break; + case RDAC_MODE_IOSHIP: + if ((h->lun_state == RDAC_LUN_UNOWNED) && + (h->preferred == RDAC_PREFERRED)) + act = 1; + break; + default: + break; + } + + if (act) { err = queue_mode_select(sdev, fn, data); if (err == SCSI_DH_OK) return 0; -- cgit v0.10.2 From 7dacb64f49848f1f28018fd3e58af8d6ba234960 Mon Sep 17 00:00:00 2001 From: Wayne Boyer Date: Tue, 12 Apr 2011 10:29:02 -0700 Subject: [SCSI] ipr: improve interrupt service routine performance During performance testing on P7 machines it was observed that the interrupt service routine was doing unnecessary MMIO operations. This patch rearranges the logic of the routine and moves some of the code out of the main routine. The result is that there are now fewer MMIO operations in the performance path of the code. As a result of the above change, an existing condition was exposed where the driver could get an "unexpected" hrrq interrupt. The original code would flag the interrupt as unexpected and then reset the adapter. After further analysis it was confirmed that this condition can occasionally occur and that the interrupt can safely be ignored. Additional code in this patch detects this condition, clears the interrupt and allows the driver to continue without resetting the adapter. Signed-off-by: Wayne Boyer Acked-by: Brian King Signed-off-by: James Bottomley diff --git a/drivers/scsi/ipr.c b/drivers/scsi/ipr.c index a485e52..fa2513c 100644 --- a/drivers/scsi/ipr.c +++ b/drivers/scsi/ipr.c @@ -4956,6 +4956,32 @@ static irqreturn_t ipr_handle_other_interrupt(struct ipr_ioa_cfg *ioa_cfg, u32 int_reg) { irqreturn_t rc = IRQ_HANDLED; + u32 int_mask_reg; + + int_mask_reg = readl(ioa_cfg->regs.sense_interrupt_mask_reg32); + int_reg &= ~int_mask_reg; + + /* If an interrupt on the adapter did not occur, ignore it. + * Or in the case of SIS 64, check for a stage change interrupt. + */ + if ((int_reg & IPR_PCII_OPER_INTERRUPTS) == 0) { + if (ioa_cfg->sis64) { + int_mask_reg = readl(ioa_cfg->regs.sense_interrupt_mask_reg); + int_reg = readl(ioa_cfg->regs.sense_interrupt_reg) & ~int_mask_reg; + if (int_reg & IPR_PCII_IPL_STAGE_CHANGE) { + + /* clear stage change */ + writel(IPR_PCII_IPL_STAGE_CHANGE, ioa_cfg->regs.clr_interrupt_reg); + int_reg = readl(ioa_cfg->regs.sense_interrupt_reg) & ~int_mask_reg; + list_del(&ioa_cfg->reset_cmd->queue); + del_timer(&ioa_cfg->reset_cmd->timer); + ipr_reset_ioa_job(ioa_cfg->reset_cmd); + return IRQ_HANDLED; + } + } + + return IRQ_NONE; + } if (int_reg & IPR_PCII_IOA_TRANS_TO_OPER) { /* Mask the interrupt */ @@ -4968,6 +4994,13 @@ static irqreturn_t ipr_handle_other_interrupt(struct ipr_ioa_cfg *ioa_cfg, list_del(&ioa_cfg->reset_cmd->queue); del_timer(&ioa_cfg->reset_cmd->timer); ipr_reset_ioa_job(ioa_cfg->reset_cmd); + } else if ((int_reg & IPR_PCII_HRRQ_UPDATED) == int_reg) { + if (ipr_debug && printk_ratelimit()) + dev_err(&ioa_cfg->pdev->dev, + "Spurious interrupt detected. 0x%08X\n", int_reg); + writel(IPR_PCII_HRRQ_UPDATED, ioa_cfg->regs.clr_interrupt_reg32); + int_reg = readl(ioa_cfg->regs.sense_interrupt_reg32); + return IRQ_NONE; } else { if (int_reg & IPR_PCII_IOA_UNIT_CHECKED) ioa_cfg->ioa_unit_checked = 1; @@ -5016,10 +5049,11 @@ static irqreturn_t ipr_isr(int irq, void *devp) { struct ipr_ioa_cfg *ioa_cfg = (struct ipr_ioa_cfg *)devp; unsigned long lock_flags = 0; - u32 int_reg, int_mask_reg; + u32 int_reg = 0; u32 ioasc; u16 cmd_index; int num_hrrq = 0; + int irq_none = 0; struct ipr_cmnd *ipr_cmd; irqreturn_t rc = IRQ_NONE; @@ -5031,33 +5065,6 @@ static irqreturn_t ipr_isr(int irq, void *devp) return IRQ_NONE; } - int_mask_reg = readl(ioa_cfg->regs.sense_interrupt_mask_reg32); - int_reg = readl(ioa_cfg->regs.sense_interrupt_reg32) & ~int_mask_reg; - - /* If an interrupt on the adapter did not occur, ignore it. - * Or in the case of SIS 64, check for a stage change interrupt. - */ - if (unlikely((int_reg & IPR_PCII_OPER_INTERRUPTS) == 0)) { - if (ioa_cfg->sis64) { - int_mask_reg = readl(ioa_cfg->regs.sense_interrupt_mask_reg); - int_reg = readl(ioa_cfg->regs.sense_interrupt_reg) & ~int_mask_reg; - if (int_reg & IPR_PCII_IPL_STAGE_CHANGE) { - - /* clear stage change */ - writel(IPR_PCII_IPL_STAGE_CHANGE, ioa_cfg->regs.clr_interrupt_reg); - int_reg = readl(ioa_cfg->regs.sense_interrupt_reg) & ~int_mask_reg; - list_del(&ioa_cfg->reset_cmd->queue); - del_timer(&ioa_cfg->reset_cmd->timer); - ipr_reset_ioa_job(ioa_cfg->reset_cmd); - spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags); - return IRQ_HANDLED; - } - } - - spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags); - return IRQ_NONE; - } - while (1) { ipr_cmd = NULL; @@ -5097,7 +5104,7 @@ static irqreturn_t ipr_isr(int irq, void *devp) /* Clear the PCI interrupt */ do { writel(IPR_PCII_HRRQ_UPDATED, ioa_cfg->regs.clr_interrupt_reg32); - int_reg = readl(ioa_cfg->regs.sense_interrupt_reg32) & ~int_mask_reg; + int_reg = readl(ioa_cfg->regs.sense_interrupt_reg32); } while (int_reg & IPR_PCII_HRRQ_UPDATED && num_hrrq++ < IPR_MAX_HRRQ_RETRIES); @@ -5107,6 +5114,9 @@ static irqreturn_t ipr_isr(int irq, void *devp) return IRQ_HANDLED; } + } else if (rc == IRQ_NONE && irq_none == 0) { + int_reg = readl(ioa_cfg->regs.sense_interrupt_reg32); + irq_none++; } else break; } -- cgit v0.10.2 From 61338a0b3493fddfca2980ece4423839748fcbab Mon Sep 17 00:00:00 2001 From: Jing Huang Date: Wed, 13 Apr 2011 11:44:03 -0700 Subject: [SCSI] bfa: firmware download fix This patch includes fixes for two issues releated to firmware download implementation: 1) Merged memory leak fix provided by Jesper Juhl . Basically we need to call release_firmware() after request_firmware(). 2) fixed issues with the firmware download interface as pointed out by Rolf Eike Beer in linux-scsi. Rearranged the code and fixed related function protypes. Signed-off-by: Jing Huang Signed-off-by: James Bottomley diff --git a/drivers/scsi/bfa/bfad.c b/drivers/scsi/bfa/bfad.c index 0fd510a..d9360bf 100644 --- a/drivers/scsi/bfa/bfad.c +++ b/drivers/scsi/bfa/bfad.c @@ -57,9 +57,19 @@ int pcie_max_read_reqsz; int bfa_debugfs_enable = 1; int msix_disable_cb = 0, msix_disable_ct = 0; +/* Firmware releated */ u32 bfi_image_ct_fc_size, bfi_image_ct_cna_size, bfi_image_cb_fc_size; u32 *bfi_image_ct_fc, *bfi_image_ct_cna, *bfi_image_cb_fc; +#define BFAD_FW_FILE_CT_FC "ctfw_fc.bin" +#define BFAD_FW_FILE_CT_CNA "ctfw_cna.bin" +#define BFAD_FW_FILE_CB_FC "cbfw_fc.bin" + +static u32 *bfad_load_fwimg(struct pci_dev *pdev); +static void bfad_free_fwimg(void); +static void bfad_read_firmware(struct pci_dev *pdev, u32 **bfi_image, + u32 *bfi_image_size, char *fw_name); + static const char *msix_name_ct[] = { "cpe0", "cpe1", "cpe2", "cpe3", "rme0", "rme1", "rme2", "rme3", @@ -1550,7 +1560,7 @@ bfad_exit(void) } /* Firmware handling */ -u32 * +static void bfad_read_firmware(struct pci_dev *pdev, u32 **bfi_image, u32 *bfi_image_size, char *fw_name) { @@ -1558,27 +1568,25 @@ bfad_read_firmware(struct pci_dev *pdev, u32 **bfi_image, if (request_firmware(&fw, fw_name, &pdev->dev)) { printk(KERN_ALERT "Can't locate firmware %s\n", fw_name); - goto error; + *bfi_image = NULL; + goto out; } *bfi_image = vmalloc(fw->size); if (NULL == *bfi_image) { printk(KERN_ALERT "Fail to allocate buffer for fw image " "size=%x!\n", (u32) fw->size); - goto error; + goto out; } memcpy(*bfi_image, fw->data, fw->size); *bfi_image_size = fw->size/sizeof(u32); - - return *bfi_image; - -error: - return NULL; +out: + release_firmware(fw); } -u32 * -bfad_get_firmware_buf(struct pci_dev *pdev) +static u32 * +bfad_load_fwimg(struct pci_dev *pdev) { if (pdev->device == BFA_PCI_DEVICE_ID_CT_FC) { if (bfi_image_ct_fc_size == 0) @@ -1598,6 +1606,17 @@ bfad_get_firmware_buf(struct pci_dev *pdev) } } +static void +bfad_free_fwimg(void) +{ + if (bfi_image_ct_fc_size && bfi_image_ct_fc) + vfree(bfi_image_ct_fc); + if (bfi_image_ct_cna_size && bfi_image_ct_cna) + vfree(bfi_image_ct_cna); + if (bfi_image_cb_fc_size && bfi_image_cb_fc) + vfree(bfi_image_cb_fc); +} + module_init(bfad_init); module_exit(bfad_exit); MODULE_LICENSE("GPL"); diff --git a/drivers/scsi/bfa/bfad_im.h b/drivers/scsi/bfa/bfad_im.h index bfee63b..c296c89 100644 --- a/drivers/scsi/bfa/bfad_im.h +++ b/drivers/scsi/bfa/bfad_im.h @@ -141,29 +141,4 @@ extern struct device_attribute *bfad_im_vport_attrs[]; irqreturn_t bfad_intx(int irq, void *dev_id); -/* Firmware releated */ -#define BFAD_FW_FILE_CT_FC "ctfw_fc.bin" -#define BFAD_FW_FILE_CT_CNA "ctfw_cna.bin" -#define BFAD_FW_FILE_CB_FC "cbfw_fc.bin" - -u32 *bfad_get_firmware_buf(struct pci_dev *pdev); -u32 *bfad_read_firmware(struct pci_dev *pdev, u32 **bfi_image, - u32 *bfi_image_size, char *fw_name); - -static inline u32 * -bfad_load_fwimg(struct pci_dev *pdev) -{ - return bfad_get_firmware_buf(pdev); -} - -static inline void -bfad_free_fwimg(void) -{ - if (bfi_image_ct_fc_size && bfi_image_ct_fc) - vfree(bfi_image_ct_fc); - if (bfi_image_ct_cna_size && bfi_image_ct_cna) - vfree(bfi_image_ct_cna); - if (bfi_image_cb_fc_size && bfi_image_cb_fc) - vfree(bfi_image_cb_fc); -} #endif -- cgit v0.10.2 From 7c38c05b3ef1a8a9f7e0416072a8ea2730841c91 Mon Sep 17 00:00:00 2001 From: Krishna Gudipati Date: Thu, 14 Apr 2011 16:50:35 -0700 Subject: [SCSI] bfa: Move debugfs initialization before bfa init. Move the initialization of debugfs before bfa init, to enable us to collect driver/firmware traces if init fails. Also add a printk to display message on bfa_init failure. Signed-off-by: Krishna Gudipati Signed-off-by: James Bottomley diff --git a/drivers/scsi/bfa/bfad.c b/drivers/scsi/bfa/bfad.c index d9360bf..59b5e9b 100644 --- a/drivers/scsi/bfa/bfad.c +++ b/drivers/scsi/bfa/bfad.c @@ -232,6 +232,9 @@ bfad_sm_created(struct bfad_s *bfad, enum bfad_sm_event event) if ((bfad->bfad_flags & BFAD_HAL_INIT_DONE)) { bfa_sm_send_event(bfad, BFAD_E_INIT_SUCCESS); } else { + printk(KERN_WARNING + "bfa %s: bfa init failed\n", + bfad->pci_name); bfad->bfad_flags |= BFAD_HAL_INIT_FAIL; bfa_sm_send_event(bfad, BFAD_E_INIT_FAILED); } @@ -1001,10 +1004,6 @@ bfad_cfg_pport(struct bfad_s *bfad, enum bfa_lport_role role) bfad->pport.roles |= BFA_LPORT_ROLE_FCP_IM; } - /* Setup the debugfs node for this scsi_host */ - if (bfa_debugfs_enable) - bfad_debugfs_init(&bfad->pport); - bfad->bfad_flags |= BFAD_CFG_PPORT_DONE; out: @@ -1014,10 +1013,6 @@ out: void bfad_uncfg_pport(struct bfad_s *bfad) { - /* Remove the debugfs node for this scsi_host */ - kfree(bfad->regdata); - bfad_debugfs_exit(&bfad->pport); - if ((supported_fc4s & BFA_LPORT_ROLE_FCP_IM) && (bfad->pport.roles & BFA_LPORT_ROLE_FCP_IM)) { bfad_im_scsi_host_free(bfad, bfad->pport.im_port); @@ -1399,6 +1394,10 @@ bfad_pci_probe(struct pci_dev *pdev, const struct pci_device_id *pid) bfad->pport.bfad = bfad; INIT_LIST_HEAD(&bfad->pbc_vport_list); + /* Setup the debugfs node for this bfad */ + if (bfa_debugfs_enable) + bfad_debugfs_init(&bfad->pport); + retval = bfad_drv_init(bfad); if (retval != BFA_STATUS_OK) goto out_drv_init_failure; @@ -1414,6 +1413,9 @@ out_bfad_sm_failure: bfa_detach(&bfad->bfa); bfad_hal_mem_release(bfad); out_drv_init_failure: + /* Remove the debugfs node for this bfad */ + kfree(bfad->regdata); + bfad_debugfs_exit(&bfad->pport); mutex_lock(&bfad_mutex); bfad_inst--; list_del(&bfad->list_entry); @@ -1455,6 +1457,10 @@ bfad_pci_remove(struct pci_dev *pdev) spin_unlock_irqrestore(&bfad->bfad_lock, flags); bfad_hal_mem_release(bfad); + /* Remove the debugfs node for this bfad */ + kfree(bfad->regdata); + bfad_debugfs_exit(&bfad->pport); + /* Cleaning the BFAD instance */ mutex_lock(&bfad_mutex); bfad_inst--; diff --git a/drivers/scsi/bfa/bfad_debugfs.c b/drivers/scsi/bfa/bfad_debugfs.c index c66e32e..48be0c5 100644 --- a/drivers/scsi/bfa/bfad_debugfs.c +++ b/drivers/scsi/bfa/bfad_debugfs.c @@ -28,10 +28,10 @@ * mount -t debugfs none /sys/kernel/debug * * BFA Hierarchy: - * - bfa/host# - * where the host number corresponds to the one under /sys/class/scsi_host/host# + * - bfa/pci_dev: + * where the pci_name corresponds to the one under /sys/bus/pci/drivers/bfa * - * Debugging service available per host: + * Debugging service available per pci_dev: * fwtrc: To collect current firmware trace. * drvtrc: To collect current driver trace * fwsave: To collect last saved fw trace as a result of firmware crash. @@ -489,11 +489,9 @@ static atomic_t bfa_debugfs_port_count; inline void bfad_debugfs_init(struct bfad_port_s *port) { - struct bfad_im_port_s *im_port = port->im_port; - struct bfad_s *bfad = im_port->bfad; - struct Scsi_Host *shost = im_port->shost; + struct bfad_s *bfad = port->bfad; const struct bfad_debugfs_entry *file; - char name[16]; + char name[64]; int i; if (!bfa_debugfs_enable) @@ -510,17 +508,15 @@ bfad_debugfs_init(struct bfad_port_s *port) } } - /* - * Setup the host# directory for the port, - * corresponds to the scsi_host num of this port. - */ - snprintf(name, sizeof(name), "host%d", shost->host_no); + /* Setup the pci_dev debugfs directory for the port */ + snprintf(name, sizeof(name), "pci_dev:%s", bfad->pci_name); if (!port->port_debugfs_root) { port->port_debugfs_root = debugfs_create_dir(name, bfa_debugfs_root); if (!port->port_debugfs_root) { printk(KERN_WARNING - "BFA host root dir creation failed\n"); + "bfa %s: debugfs root creation failed\n", + bfad->pci_name); goto err; } @@ -536,8 +532,8 @@ bfad_debugfs_init(struct bfad_port_s *port) file->fops); if (!bfad->bfad_dentry_files[i]) { printk(KERN_WARNING - "BFA host%d: create %s entry failed\n", - shost->host_no, file->name); + "bfa %s: debugfs %s creation failed\n", + bfad->pci_name, file->name); goto err; } } @@ -550,8 +546,7 @@ err: inline void bfad_debugfs_exit(struct bfad_port_s *port) { - struct bfad_im_port_s *im_port = port->im_port; - struct bfad_s *bfad = im_port->bfad; + struct bfad_s *bfad = port->bfad; int i; for (i = 0; i < ARRAY_SIZE(bfad_debugfs_files); i++) { @@ -562,9 +557,7 @@ bfad_debugfs_exit(struct bfad_port_s *port) } /* - * Remove the host# directory for the port, - * corresponds to the scsi_host num of this port. - */ + * Remove the pci_dev debugfs directory for the port */ if (port->port_debugfs_root) { debugfs_remove(port->port_debugfs_root); port->port_debugfs_root = NULL; -- cgit v0.10.2 From 86a80846a68eeb8575119db61f6b262f49522e6f Mon Sep 17 00:00:00 2001 From: James Smart Date: Sat, 16 Apr 2011 11:03:04 -0400 Subject: [SCSI] lpfc 8.3.23: Debugfs enhancements Debugfs enhancements - Added iDiag support for new adapters. - Added queue entry access methods. - Fix host/port index in decimal - Added Doorbell register access methods. Signed-off-by: Alex Iannicelli Signed-off-by: James Smart Signed-off-by: James Bottomley diff --git a/drivers/scsi/lpfc/lpfc.h b/drivers/scsi/lpfc/lpfc.h index 60e98a62..02d53d8 100644 --- a/drivers/scsi/lpfc/lpfc.h +++ b/drivers/scsi/lpfc/lpfc.h @@ -805,6 +805,8 @@ struct lpfc_hba { struct dentry *idiag_root; struct dentry *idiag_pci_cfg; struct dentry *idiag_que_info; + struct dentry *idiag_que_acc; + struct dentry *idiag_drb_acc; #endif /* Used for deferred freeing of ELS data buffers */ diff --git a/drivers/scsi/lpfc/lpfc_debugfs.c b/drivers/scsi/lpfc/lpfc_debugfs.c index 3d96774..c93fca0 100644 --- a/drivers/scsi/lpfc/lpfc_debugfs.c +++ b/drivers/scsi/lpfc/lpfc_debugfs.c @@ -1119,172 +1119,14 @@ lpfc_debugfs_dumpDataDif_release(struct inode *inode, struct file *file) } /* + * --------------------------------- * iDiag debugfs file access methods - */ - -/* - * iDiag PCI config space register access methods: - * - * The PCI config space register accessees of read, write, read-modify-write - * for set bits, and read-modify-write for clear bits to SLI4 PCI functions - * are provided. In the proper SLI4 PCI function's debugfs iDiag directory, - * - * /sys/kernel/debug/lpfc/fn<#>/iDiag - * - * the access is through the debugfs entry pciCfg: - * - * 1. For PCI config space register read access, there are two read methods: - * A) read a single PCI config space register in the size of a byte - * (8 bits), a word (16 bits), or a dword (32 bits); or B) browse through - * the 4K extended PCI config space. - * - * A) Read a single PCI config space register consists of two steps: - * - * Step-1: Set up PCI config space register read command, the command - * syntax is, - * - * echo 1 > pciCfg - * - * where, 1 is the iDiag command for PCI config space read, is the - * offset from the beginning of the device's PCI config space to read from, - * and is the size of PCI config space register data to read back, - * it will be 1 for reading a byte (8 bits), 2 for reading a word (16 bits - * or 2 bytes), or 4 for reading a dword (32 bits or 4 bytes). - * - * Setp-2: Perform the debugfs read operation to execute the idiag command - * set up in Step-1, - * - * cat pciCfg - * - * Examples: - * To read PCI device's vendor-id and device-id from PCI config space, - * - * echo 1 0 4 > pciCfg - * cat pciCfg - * - * To read PCI device's currnt command from config space, - * - * echo 1 4 2 > pciCfg - * cat pciCfg - * - * B) Browse through the entire 4K extended PCI config space also consists - * of two steps: - * - * Step-1: Set up PCI config space register browsing command, the command - * syntax is, - * - * echo 1 0 4096 > pciCfg - * - * where, 1 is the iDiag command for PCI config space read, 0 must be used - * as the offset for PCI config space register browse, and 4096 must be - * used as the count for PCI config space register browse. - * - * Step-2: Repeately issue the debugfs read operation to browse through - * the entire PCI config space registers: - * - * cat pciCfg - * cat pciCfg - * cat pciCfg - * ... - * - * When browsing to the end of the 4K PCI config space, the browse method - * shall wrap around to start reading from beginning again, and again... - * - * 2. For PCI config space register write access, it supports a single PCI - * config space register write in the size of a byte (8 bits), a word - * (16 bits), or a dword (32 bits). The command syntax is, - * - * echo 2 > pciCfg - * - * where, 2 is the iDiag command for PCI config space write, is - * the offset from the beginning of the device's PCI config space to write - * into, is the size of data to write into the PCI config space, - * it will be 1 for writing a byte (8 bits), 2 for writing a word (16 bits - * or 2 bytes), or 4 for writing a dword (32 bits or 4 bytes), and - * is the data to be written into the PCI config space register at the - * offset. - * - * Examples: - * To disable PCI device's interrupt assertion, - * - * 1) Read in device's PCI config space register command field : - * - * echo 1 4 2 > pciCfg - * cat pciCfg - * - * 2) Set bit 10 (Interrupt Disable bit) in the : - * - * = | (1 < 10) - * - * 3) Write the modified command back: - * - * echo 2 4 2 > pciCfg - * - * 3. For PCI config space register set bits access, it supports a single PCI - * config space register set bits in the size of a byte (8 bits), a word - * (16 bits), or a dword (32 bits). The command syntax is, - * - * echo 3 > pciCfg - * - * where, 3 is the iDiag command for PCI config space set bits, is - * the offset from the beginning of the device's PCI config space to set - * bits into, is the size of the bitmask to set into the PCI config - * space, it will be 1 for setting a byte (8 bits), 2 for setting a word - * (16 bits or 2 bytes), or 4 for setting a dword (32 bits or 4 bytes), and - * is the bitmask, indicating the bits to be set into the PCI - * config space register at the offset. The logic performed to the content - * of the PCI config space register, regval, is, - * - * regval |= - * - * 4. For PCI config space register clear bits access, it supports a single - * PCI config space register clear bits in the size of a byte (8 bits), - * a word (16 bits), or a dword (32 bits). The command syntax is, - * - * echo 4 > pciCfg - * - * where, 4 is the iDiag command for PCI config space clear bits, - * is the offset from the beginning of the device's PCI config space to - * clear bits from, is the size of the bitmask to set into the PCI - * config space, it will be 1 for setting a byte (8 bits), 2 for setting - * a word(16 bits or 2 bytes), or 4 for setting a dword (32 bits or 4 - * bytes), and is the bitmask, indicating the bits to be cleared - * from the PCI config space register at the offset. the logic performed - * to the content of the PCI config space register, regval, is, - * - * regval &= ~ - * - * Note, for all single register read, write, set bits, or clear bits access, - * the offset () must be aligned with the size of the data: - * - * For data size of byte (8 bits), the offset must be aligned to the byte - * boundary; for data size of word (16 bits), the offset must be aligned - * to the word boundary; while for data size of dword (32 bits), the offset - * must be aligned to the dword boundary. Otherwise, the interface will - * return the error: + * --------------------------------- * - * "-bash: echo: write error: Invalid argument". + * All access methods are through the proper SLI4 PCI function's debugfs + * iDiag directory: * - * For example: - * - * echo 1 2 4 > pciCfg - * -bash: echo: write error: Invalid argument - * - * Note also, all of the numbers in the command fields for all read, write, - * set bits, and clear bits PCI config space register command fields can be - * either decimal or hex. - * - * For example, - * echo 1 0 4096 > pciCfg - * - * will be the same as - * echo 1 0 0x1000 > pciCfg - * - * And, - * echo 2 155 1 10 > pciCfg - * - * will be - * echo 2 0x9b 1 0xa > pciCfg + * /sys/kernel/debug/lpfc/fn<#>/iDiag */ /** @@ -1331,10 +1173,10 @@ static int lpfc_idiag_cmd_get(const char __user *buf, size_t nbytes, for (i = 0; i < LPFC_IDIAG_CMD_DATA_SIZE; i++) { step_str = strsep(&pbuf, "\t "); if (!step_str) - return 0; + return i; idiag_cmd->data[i] = simple_strtol(step_str, NULL, 0); } - return 0; + return i; } /** @@ -1403,7 +1245,7 @@ lpfc_idiag_release(struct inode *inode, struct file *file) * Description: * This routine frees the buffer that was allocated when the debugfs file * was opened. It also reset the fields in the idiag command struct in the - * case the command is not continuous browsing of the data structure. + * case of command for write operation. * * Returns: * This function returns zero. @@ -1413,18 +1255,20 @@ lpfc_idiag_cmd_release(struct inode *inode, struct file *file) { struct lpfc_debug *debug = file->private_data; - /* Read PCI config register, if not read all, clear command fields */ - if ((debug->op == LPFC_IDIAG_OP_RD) && - (idiag.cmd.opcode == LPFC_IDIAG_CMD_PCICFG_RD)) - if ((idiag.cmd.data[1] == sizeof(uint8_t)) || - (idiag.cmd.data[1] == sizeof(uint16_t)) || - (idiag.cmd.data[1] == sizeof(uint32_t))) + if (debug->op == LPFC_IDIAG_OP_WR) { + switch (idiag.cmd.opcode) { + case LPFC_IDIAG_CMD_PCICFG_WR: + case LPFC_IDIAG_CMD_PCICFG_ST: + case LPFC_IDIAG_CMD_PCICFG_CL: + case LPFC_IDIAG_CMD_QUEACC_WR: + case LPFC_IDIAG_CMD_QUEACC_ST: + case LPFC_IDIAG_CMD_QUEACC_CL: memset(&idiag, 0, sizeof(idiag)); - - /* Write PCI config register, clear command fields */ - if ((debug->op == LPFC_IDIAG_OP_WR) && - (idiag.cmd.opcode == LPFC_IDIAG_CMD_PCICFG_WR)) - memset(&idiag, 0, sizeof(idiag)); + break; + default: + break; + } + } /* Free the buffers to the file operation */ kfree(debug->buffer); @@ -1504,7 +1348,7 @@ lpfc_idiag_pcicfg_read(struct file *file, char __user *buf, size_t nbytes, len += snprintf(pbuffer+len, LPFC_PCI_CFG_SIZE-len, "%03x: %08x\n", where, u32val); break; - case LPFC_PCI_CFG_SIZE: /* browse all */ + case LPFC_PCI_CFG_BROWSE: /* browse all */ goto pcicfg_browse; break; default: @@ -1586,16 +1430,21 @@ lpfc_idiag_pcicfg_write(struct file *file, const char __user *buf, debug->op = LPFC_IDIAG_OP_WR; rc = lpfc_idiag_cmd_get(buf, nbytes, &idiag.cmd); - if (rc) + if (rc < 0) return rc; if (idiag.cmd.opcode == LPFC_IDIAG_CMD_PCICFG_RD) { + /* Sanity check on PCI config read command line arguments */ + if (rc != LPFC_PCI_CFG_RD_CMD_ARG) + goto error_out; /* Read command from PCI config space, set up command fields */ where = idiag.cmd.data[0]; count = idiag.cmd.data[1]; - if (count == LPFC_PCI_CFG_SIZE) { - if (where != 0) + if (count == LPFC_PCI_CFG_BROWSE) { + if (where % sizeof(uint32_t)) goto error_out; + /* Starting offset to browse */ + idiag.offset.last_rd = where; } else if ((count != sizeof(uint8_t)) && (count != sizeof(uint16_t)) && (count != sizeof(uint32_t))) @@ -1621,6 +1470,9 @@ lpfc_idiag_pcicfg_write(struct file *file, const char __user *buf, } else if (idiag.cmd.opcode == LPFC_IDIAG_CMD_PCICFG_WR || idiag.cmd.opcode == LPFC_IDIAG_CMD_PCICFG_ST || idiag.cmd.opcode == LPFC_IDIAG_CMD_PCICFG_CL) { + /* Sanity check on PCI config write command line arguments */ + if (rc != LPFC_PCI_CFG_WR_CMD_ARG) + goto error_out; /* Write command to PCI config space, read-modify-write */ where = idiag.cmd.data[0]; count = idiag.cmd.data[1]; @@ -1753,10 +1605,12 @@ lpfc_idiag_queinfo_read(struct file *file, char __user *buf, size_t nbytes, len += snprintf(pbuffer+len, LPFC_QUE_INFO_GET_BUF_SIZE-len, "Slow-path EQ information:\n"); len += snprintf(pbuffer+len, LPFC_QUE_INFO_GET_BUF_SIZE-len, - "\tID [%02d], EQE-COUNT [%04d], " - "HOST-INDEX [%04x], PORT-INDEX [%04x]\n\n", + "\tEQID[%02d], " + "QE-COUNT[%04d], QE-SIZE[%04d], " + "HOST-INDEX[%04d], PORT-INDEX[%04d]\n\n", phba->sli4_hba.sp_eq->queue_id, phba->sli4_hba.sp_eq->entry_count, + phba->sli4_hba.sp_eq->entry_size, phba->sli4_hba.sp_eq->host_index, phba->sli4_hba.sp_eq->hba_index); @@ -1765,10 +1619,12 @@ lpfc_idiag_queinfo_read(struct file *file, char __user *buf, size_t nbytes, "Fast-path EQ information:\n"); for (fcp_qidx = 0; fcp_qidx < phba->cfg_fcp_eq_count; fcp_qidx++) { len += snprintf(pbuffer+len, LPFC_QUE_INFO_GET_BUF_SIZE-len, - "\tID [%02d], EQE-COUNT [%04d], " - "HOST-INDEX [%04x], PORT-INDEX [%04x]\n", + "\tEQID[%02d], " + "QE-COUNT[%04d], QE-SIZE[%04d], " + "HOST-INDEX[%04d], PORT-INDEX[%04d]\n", phba->sli4_hba.fp_eq[fcp_qidx]->queue_id, phba->sli4_hba.fp_eq[fcp_qidx]->entry_count, + phba->sli4_hba.fp_eq[fcp_qidx]->entry_size, phba->sli4_hba.fp_eq[fcp_qidx]->host_index, phba->sli4_hba.fp_eq[fcp_qidx]->hba_index); } @@ -1776,89 +1632,101 @@ lpfc_idiag_queinfo_read(struct file *file, char __user *buf, size_t nbytes, /* Get mailbox complete queue information */ len += snprintf(pbuffer+len, LPFC_QUE_INFO_GET_BUF_SIZE-len, - "Mailbox CQ information:\n"); + "Slow-path MBX CQ information:\n"); len += snprintf(pbuffer+len, LPFC_QUE_INFO_GET_BUF_SIZE-len, - "\t\tAssociated EQ-ID [%02d]:\n", + "Associated EQID[%02d]:\n", phba->sli4_hba.mbx_cq->assoc_qid); len += snprintf(pbuffer+len, LPFC_QUE_INFO_GET_BUF_SIZE-len, - "\tID [%02d], CQE-COUNT [%04d], " - "HOST-INDEX [%04x], PORT-INDEX [%04x]\n\n", + "\tCQID[%02d], " + "QE-COUNT[%04d], QE-SIZE[%04d], " + "HOST-INDEX[%04d], PORT-INDEX[%04d]\n\n", phba->sli4_hba.mbx_cq->queue_id, phba->sli4_hba.mbx_cq->entry_count, + phba->sli4_hba.mbx_cq->entry_size, phba->sli4_hba.mbx_cq->host_index, phba->sli4_hba.mbx_cq->hba_index); /* Get slow-path complete queue information */ len += snprintf(pbuffer+len, LPFC_QUE_INFO_GET_BUF_SIZE-len, - "Slow-path CQ information:\n"); + "Slow-path ELS CQ information:\n"); len += snprintf(pbuffer+len, LPFC_QUE_INFO_GET_BUF_SIZE-len, - "\t\tAssociated EQ-ID [%02d]:\n", + "Associated EQID[%02d]:\n", phba->sli4_hba.els_cq->assoc_qid); len += snprintf(pbuffer+len, LPFC_QUE_INFO_GET_BUF_SIZE-len, - "\tID [%02d], CQE-COUNT [%04d], " - "HOST-INDEX [%04x], PORT-INDEX [%04x]\n\n", + "\tCQID [%02d], " + "QE-COUNT[%04d], QE-SIZE[%04d], " + "HOST-INDEX[%04d], PORT-INDEX[%04d]\n\n", phba->sli4_hba.els_cq->queue_id, phba->sli4_hba.els_cq->entry_count, + phba->sli4_hba.els_cq->entry_size, phba->sli4_hba.els_cq->host_index, phba->sli4_hba.els_cq->hba_index); /* Get fast-path complete queue information */ len += snprintf(pbuffer+len, LPFC_QUE_INFO_GET_BUF_SIZE-len, - "Fast-path CQ information:\n"); + "Fast-path FCP CQ information:\n"); for (fcp_qidx = 0; fcp_qidx < phba->cfg_fcp_eq_count; fcp_qidx++) { len += snprintf(pbuffer+len, LPFC_QUE_INFO_GET_BUF_SIZE-len, - "\t\tAssociated EQ-ID [%02d]:\n", + "Associated EQID[%02d]:\n", phba->sli4_hba.fcp_cq[fcp_qidx]->assoc_qid); len += snprintf(pbuffer+len, LPFC_QUE_INFO_GET_BUF_SIZE-len, - "\tID [%02d], EQE-COUNT [%04d], " - "HOST-INDEX [%04x], PORT-INDEX [%04x]\n", - phba->sli4_hba.fcp_cq[fcp_qidx]->queue_id, - phba->sli4_hba.fcp_cq[fcp_qidx]->entry_count, - phba->sli4_hba.fcp_cq[fcp_qidx]->host_index, - phba->sli4_hba.fcp_cq[fcp_qidx]->hba_index); + "\tCQID[%02d], " + "QE-COUNT[%04d], QE-SIZE[%04d], " + "HOST-INDEX[%04d], PORT-INDEX[%04d]\n", + phba->sli4_hba.fcp_cq[fcp_qidx]->queue_id, + phba->sli4_hba.fcp_cq[fcp_qidx]->entry_count, + phba->sli4_hba.fcp_cq[fcp_qidx]->entry_size, + phba->sli4_hba.fcp_cq[fcp_qidx]->host_index, + phba->sli4_hba.fcp_cq[fcp_qidx]->hba_index); } len += snprintf(pbuffer+len, LPFC_QUE_INFO_GET_BUF_SIZE-len, "\n"); /* Get mailbox queue information */ len += snprintf(pbuffer+len, LPFC_QUE_INFO_GET_BUF_SIZE-len, - "Mailbox MQ information:\n"); + "Slow-path MBX MQ information:\n"); len += snprintf(pbuffer+len, LPFC_QUE_INFO_GET_BUF_SIZE-len, - "\t\tAssociated CQ-ID [%02d]:\n", + "Associated CQID[%02d]:\n", phba->sli4_hba.mbx_wq->assoc_qid); len += snprintf(pbuffer+len, LPFC_QUE_INFO_GET_BUF_SIZE-len, - "\tID [%02d], MQE-COUNT [%04d], " - "HOST-INDEX [%04x], PORT-INDEX [%04x]\n\n", + "\tWQID[%02d], " + "QE-COUNT[%04d], QE-SIZE[%04d], " + "HOST-INDEX[%04d], PORT-INDEX[%04d]\n\n", phba->sli4_hba.mbx_wq->queue_id, phba->sli4_hba.mbx_wq->entry_count, + phba->sli4_hba.mbx_wq->entry_size, phba->sli4_hba.mbx_wq->host_index, phba->sli4_hba.mbx_wq->hba_index); /* Get slow-path work queue information */ len += snprintf(pbuffer+len, LPFC_QUE_INFO_GET_BUF_SIZE-len, - "Slow-path WQ information:\n"); + "Slow-path ELS WQ information:\n"); len += snprintf(pbuffer+len, LPFC_QUE_INFO_GET_BUF_SIZE-len, - "\t\tAssociated CQ-ID [%02d]:\n", + "Associated CQID[%02d]:\n", phba->sli4_hba.els_wq->assoc_qid); len += snprintf(pbuffer+len, LPFC_QUE_INFO_GET_BUF_SIZE-len, - "\tID [%02d], WQE-COUNT [%04d], " - "HOST-INDEX [%04x], PORT-INDEX [%04x]\n\n", + "\tWQID[%02d], " + "QE-COUNT[%04d], QE-SIZE[%04d], " + "HOST-INDEX[%04d], PORT-INDEX[%04d]\n\n", phba->sli4_hba.els_wq->queue_id, phba->sli4_hba.els_wq->entry_count, + phba->sli4_hba.els_wq->entry_size, phba->sli4_hba.els_wq->host_index, phba->sli4_hba.els_wq->hba_index); /* Get fast-path work queue information */ len += snprintf(pbuffer+len, LPFC_QUE_INFO_GET_BUF_SIZE-len, - "Fast-path WQ information:\n"); + "Fast-path FCP WQ information:\n"); for (fcp_qidx = 0; fcp_qidx < phba->cfg_fcp_wq_count; fcp_qidx++) { len += snprintf(pbuffer+len, LPFC_QUE_INFO_GET_BUF_SIZE-len, - "\t\tAssociated CQ-ID [%02d]:\n", + "Associated CQID[%02d]:\n", phba->sli4_hba.fcp_wq[fcp_qidx]->assoc_qid); len += snprintf(pbuffer+len, LPFC_QUE_INFO_GET_BUF_SIZE-len, - "\tID [%02d], WQE-COUNT [%04d], " - "HOST-INDEX [%04x], PORT-INDEX [%04x]\n", + "\tWQID[%02d], " + "QE-COUNT[%04d], WQE-SIZE[%04d], " + "HOST-INDEX[%04d], PORT-INDEX[%04d]\n", phba->sli4_hba.fcp_wq[fcp_qidx]->queue_id, phba->sli4_hba.fcp_wq[fcp_qidx]->entry_count, + phba->sli4_hba.fcp_wq[fcp_qidx]->entry_size, phba->sli4_hba.fcp_wq[fcp_qidx]->host_index, phba->sli4_hba.fcp_wq[fcp_qidx]->hba_index); } @@ -1868,26 +1736,597 @@ lpfc_idiag_queinfo_read(struct file *file, char __user *buf, size_t nbytes, len += snprintf(pbuffer+len, LPFC_QUE_INFO_GET_BUF_SIZE-len, "Slow-path RQ information:\n"); len += snprintf(pbuffer+len, LPFC_QUE_INFO_GET_BUF_SIZE-len, - "\t\tAssociated CQ-ID [%02d]:\n", + "Associated CQID[%02d]:\n", phba->sli4_hba.hdr_rq->assoc_qid); len += snprintf(pbuffer+len, LPFC_QUE_INFO_GET_BUF_SIZE-len, - "\tID [%02d], RHQE-COUNT [%04d], " - "HOST-INDEX [%04x], PORT-INDEX [%04x]\n", + "\tHQID[%02d], " + "QE-COUNT[%04d], QE-SIZE[%04d], " + "HOST-INDEX[%04d], PORT-INDEX[%04d]\n", phba->sli4_hba.hdr_rq->queue_id, phba->sli4_hba.hdr_rq->entry_count, + phba->sli4_hba.hdr_rq->entry_size, phba->sli4_hba.hdr_rq->host_index, phba->sli4_hba.hdr_rq->hba_index); len += snprintf(pbuffer+len, LPFC_QUE_INFO_GET_BUF_SIZE-len, - "\tID [%02d], RDQE-COUNT [%04d], " - "HOST-INDEX [%04x], PORT-INDEX [%04x]\n", + "\tDQID[%02d], " + "QE-COUNT[%04d], QE-SIZE[%04d], " + "HOST-INDEX[%04d], PORT-INDEX[%04d]\n", phba->sli4_hba.dat_rq->queue_id, phba->sli4_hba.dat_rq->entry_count, + phba->sli4_hba.dat_rq->entry_size, phba->sli4_hba.dat_rq->host_index, phba->sli4_hba.dat_rq->hba_index); return simple_read_from_buffer(buf, nbytes, ppos, pbuffer, len); } +/** + * lpfc_idiag_que_param_check - queue access command parameter sanity check + * @q: The pointer to queue structure. + * @index: The index into a queue entry. + * @count: The number of queue entries to access. + * + * Description: + * The routine performs sanity check on device queue access method commands. + * + * Returns: + * This function returns -EINVAL when fails the sanity check, otherwise, it + * returns 0. + **/ +static int +lpfc_idiag_que_param_check(struct lpfc_queue *q, int index, int count) +{ + /* Only support single entry read or browsing */ + if ((count != 1) && (count != LPFC_QUE_ACC_BROWSE)) + return -EINVAL; + if (index > q->entry_count - 1) + return -EINVAL; + return 0; +} + +/** + * lpfc_idiag_queacc_read_qe - read a single entry from the given queue index + * @pbuffer: The pointer to buffer to copy the read data into. + * @pque: The pointer to the queue to be read. + * @index: The index into the queue entry. + * + * Description: + * This routine reads out a single entry from the given queue's index location + * and copies it into the buffer provided. + * + * Returns: + * This function returns 0 when it fails, otherwise, it returns the length of + * the data read into the buffer provided. + **/ +static int +lpfc_idiag_queacc_read_qe(char *pbuffer, int len, struct lpfc_queue *pque, + uint32_t index) +{ + int offset, esize; + uint32_t *pentry; + + if (!pbuffer || !pque) + return 0; + + esize = pque->entry_size; + len += snprintf(pbuffer+len, LPFC_QUE_ACC_BUF_SIZE-len, + "QE-INDEX[%04d]:\n", index); + + offset = 0; + pentry = pque->qe[index].address; + while (esize > 0) { + len += snprintf(pbuffer+len, LPFC_QUE_ACC_BUF_SIZE-len, + "%08x ", *pentry); + pentry++; + offset += sizeof(uint32_t); + esize -= sizeof(uint32_t); + if (esize > 0 && !(offset % (4 * sizeof(uint32_t)))) + len += snprintf(pbuffer+len, + LPFC_QUE_ACC_BUF_SIZE-len, "\n"); + } + len += snprintf(pbuffer+len, LPFC_QUE_ACC_BUF_SIZE-len, "\n"); + + return len; +} + +/** + * lpfc_idiag_queacc_read - idiag debugfs read port queue + * @file: The file pointer to read from. + * @buf: The buffer to copy the data to. + * @nbytes: The number of bytes to read. + * @ppos: The position in the file to start reading from. + * + * Description: + * This routine reads data from the @phba device queue memory according to the + * idiag command, and copies to user @buf. Depending on the queue dump read + * command setup, it does either a single queue entry read or browing through + * all entries of the queue. + * + * Returns: + * This function returns the amount of data that was read (this could be less + * than @nbytes if the end of the file was reached) or a negative error value. + **/ +static ssize_t +lpfc_idiag_queacc_read(struct file *file, char __user *buf, size_t nbytes, + loff_t *ppos) +{ + struct lpfc_debug *debug = file->private_data; + uint32_t last_index, index, count; + struct lpfc_queue *pque = NULL; + char *pbuffer; + int len = 0; + + /* This is a user read operation */ + debug->op = LPFC_IDIAG_OP_RD; + + if (!debug->buffer) + debug->buffer = kmalloc(LPFC_QUE_ACC_BUF_SIZE, GFP_KERNEL); + if (!debug->buffer) + return 0; + pbuffer = debug->buffer; + + if (*ppos) + return 0; + + if (idiag.cmd.opcode == LPFC_IDIAG_CMD_QUEACC_RD) { + index = idiag.cmd.data[2]; + count = idiag.cmd.data[3]; + pque = (struct lpfc_queue *)idiag.ptr_private; + } else + return 0; + + /* Browse the queue starting from index */ + if (count == LPFC_QUE_ACC_BROWSE) + goto que_browse; + + /* Read a single entry from the queue */ + len = lpfc_idiag_queacc_read_qe(pbuffer, len, pque, index); + + return simple_read_from_buffer(buf, nbytes, ppos, pbuffer, len); + +que_browse: + + /* Browse all entries from the queue */ + last_index = idiag.offset.last_rd; + index = last_index; + + while (len < LPFC_QUE_ACC_SIZE - pque->entry_size) { + len = lpfc_idiag_queacc_read_qe(pbuffer, len, pque, index); + index++; + if (index > pque->entry_count - 1) + break; + } + + /* Set up the offset for next portion of pci cfg read */ + if (index > pque->entry_count - 1) + index = 0; + idiag.offset.last_rd = index; + + return simple_read_from_buffer(buf, nbytes, ppos, pbuffer, len); +} + +/** + * lpfc_idiag_queacc_write - Syntax check and set up idiag queacc commands + * @file: The file pointer to read from. + * @buf: The buffer to copy the user data from. + * @nbytes: The number of bytes to get. + * @ppos: The position in the file to start reading from. + * + * This routine get the debugfs idiag command struct from user space and then + * perform the syntax check for port queue read (dump) or write (set) command + * accordingly. In the case of port queue read command, it sets up the command + * in the idiag command struct for the following debugfs read operation. In + * the case of port queue write operation, it executes the write operation + * into the port queue entry accordingly. + * + * It returns the @nbytges passing in from debugfs user space when successful. + * In case of error conditions, it returns proper error code back to the user + * space. + **/ +static ssize_t +lpfc_idiag_queacc_write(struct file *file, const char __user *buf, + size_t nbytes, loff_t *ppos) +{ + struct lpfc_debug *debug = file->private_data; + struct lpfc_hba *phba = (struct lpfc_hba *)debug->i_private; + uint32_t qidx, quetp, queid, index, count, offset, value; + uint32_t *pentry; + struct lpfc_queue *pque; + int rc; + + /* This is a user write operation */ + debug->op = LPFC_IDIAG_OP_WR; + + rc = lpfc_idiag_cmd_get(buf, nbytes, &idiag.cmd); + if (rc < 0) + return rc; + + /* Get and sanity check on command feilds */ + quetp = idiag.cmd.data[0]; + queid = idiag.cmd.data[1]; + index = idiag.cmd.data[2]; + count = idiag.cmd.data[3]; + offset = idiag.cmd.data[4]; + value = idiag.cmd.data[5]; + + /* Sanity check on command line arguments */ + if (idiag.cmd.opcode == LPFC_IDIAG_CMD_QUEACC_WR || + idiag.cmd.opcode == LPFC_IDIAG_CMD_QUEACC_ST || + idiag.cmd.opcode == LPFC_IDIAG_CMD_QUEACC_CL) { + if (rc != LPFC_QUE_ACC_WR_CMD_ARG) + goto error_out; + if (count != 1) + goto error_out; + } else if (idiag.cmd.opcode == LPFC_IDIAG_CMD_QUEACC_RD) { + if (rc != LPFC_QUE_ACC_RD_CMD_ARG) + goto error_out; + } else + goto error_out; + + switch (quetp) { + case LPFC_IDIAG_EQ: + /* Slow-path event queue */ + if (phba->sli4_hba.sp_eq->queue_id == queid) { + /* Sanity check */ + rc = lpfc_idiag_que_param_check( + phba->sli4_hba.sp_eq, index, count); + if (rc) + goto error_out; + idiag.ptr_private = phba->sli4_hba.sp_eq; + goto pass_check; + } + /* Fast-path event queue */ + for (qidx = 0; qidx < phba->cfg_fcp_eq_count; qidx++) { + if (phba->sli4_hba.fp_eq[qidx]->queue_id == queid) { + /* Sanity check */ + rc = lpfc_idiag_que_param_check( + phba->sli4_hba.fp_eq[qidx], + index, count); + if (rc) + goto error_out; + idiag.ptr_private = phba->sli4_hba.fp_eq[qidx]; + goto pass_check; + } + } + goto error_out; + break; + case LPFC_IDIAG_CQ: + /* MBX complete queue */ + if (phba->sli4_hba.mbx_cq->queue_id == queid) { + /* Sanity check */ + rc = lpfc_idiag_que_param_check( + phba->sli4_hba.mbx_cq, index, count); + if (rc) + goto error_out; + idiag.ptr_private = phba->sli4_hba.mbx_cq; + goto pass_check; + } + /* ELS complete queue */ + if (phba->sli4_hba.els_cq->queue_id == queid) { + /* Sanity check */ + rc = lpfc_idiag_que_param_check( + phba->sli4_hba.els_cq, index, count); + if (rc) + goto error_out; + idiag.ptr_private = phba->sli4_hba.els_cq; + goto pass_check; + } + /* FCP complete queue */ + for (qidx = 0; qidx < phba->cfg_fcp_eq_count; qidx++) { + if (phba->sli4_hba.fcp_cq[qidx]->queue_id == queid) { + /* Sanity check */ + rc = lpfc_idiag_que_param_check( + phba->sli4_hba.fcp_cq[qidx], + index, count); + if (rc) + goto error_out; + idiag.ptr_private = + phba->sli4_hba.fcp_cq[qidx]; + goto pass_check; + } + } + goto error_out; + break; + case LPFC_IDIAG_MQ: + /* MBX work queue */ + if (phba->sli4_hba.mbx_wq->queue_id == queid) { + /* Sanity check */ + rc = lpfc_idiag_que_param_check( + phba->sli4_hba.mbx_wq, index, count); + if (rc) + goto error_out; + idiag.ptr_private = phba->sli4_hba.mbx_wq; + goto pass_check; + } + break; + case LPFC_IDIAG_WQ: + /* ELS work queue */ + if (phba->sli4_hba.els_wq->queue_id == queid) { + /* Sanity check */ + rc = lpfc_idiag_que_param_check( + phba->sli4_hba.els_wq, index, count); + if (rc) + goto error_out; + idiag.ptr_private = phba->sli4_hba.els_wq; + goto pass_check; + } + /* FCP work queue */ + for (qidx = 0; qidx < phba->cfg_fcp_wq_count; qidx++) { + if (phba->sli4_hba.fcp_wq[qidx]->queue_id == queid) { + /* Sanity check */ + rc = lpfc_idiag_que_param_check( + phba->sli4_hba.fcp_wq[qidx], + index, count); + if (rc) + goto error_out; + idiag.ptr_private = + phba->sli4_hba.fcp_wq[qidx]; + goto pass_check; + } + } + goto error_out; + break; + case LPFC_IDIAG_RQ: + /* HDR queue */ + if (phba->sli4_hba.hdr_rq->queue_id == queid) { + /* Sanity check */ + rc = lpfc_idiag_que_param_check( + phba->sli4_hba.hdr_rq, index, count); + if (rc) + goto error_out; + idiag.ptr_private = phba->sli4_hba.hdr_rq; + goto pass_check; + } + /* DAT queue */ + if (phba->sli4_hba.dat_rq->queue_id == queid) { + /* Sanity check */ + rc = lpfc_idiag_que_param_check( + phba->sli4_hba.dat_rq, index, count); + if (rc) + goto error_out; + idiag.ptr_private = phba->sli4_hba.dat_rq; + goto pass_check; + } + goto error_out; + break; + default: + goto error_out; + break; + } + +pass_check: + + if (idiag.cmd.opcode == LPFC_IDIAG_CMD_QUEACC_RD) { + if (count == LPFC_QUE_ACC_BROWSE) + idiag.offset.last_rd = index; + } + + if (idiag.cmd.opcode == LPFC_IDIAG_CMD_QUEACC_WR || + idiag.cmd.opcode == LPFC_IDIAG_CMD_QUEACC_ST || + idiag.cmd.opcode == LPFC_IDIAG_CMD_QUEACC_CL) { + /* Additional sanity checks on write operation */ + pque = (struct lpfc_queue *)idiag.ptr_private; + if (offset > pque->entry_size/sizeof(uint32_t) - 1) + goto error_out; + pentry = pque->qe[index].address; + pentry += offset; + if (idiag.cmd.opcode == LPFC_IDIAG_CMD_QUEACC_WR) + *pentry = value; + if (idiag.cmd.opcode == LPFC_IDIAG_CMD_QUEACC_ST) + *pentry |= value; + if (idiag.cmd.opcode == LPFC_IDIAG_CMD_QUEACC_CL) + *pentry &= ~value; + } + return nbytes; + +error_out: + /* Clean out command structure on command error out */ + memset(&idiag, 0, sizeof(idiag)); + return -EINVAL; +} + +/** + * lpfc_idiag_drbacc_read_reg - idiag debugfs read a doorbell register + * @phba: The pointer to hba structure. + * @pbuffer: The pointer to the buffer to copy the data to. + * @len: The lenght of bytes to copied. + * @drbregid: The id to doorbell registers. + * + * Description: + * This routine reads a doorbell register and copies its content to the + * user buffer pointed to by @pbuffer. + * + * Returns: + * This function returns the amount of data that was copied into @pbuffer. + **/ +static int +lpfc_idiag_drbacc_read_reg(struct lpfc_hba *phba, char *pbuffer, + int len, uint32_t drbregid) +{ + + if (!pbuffer) + return 0; + + switch (drbregid) { + case LPFC_DRB_EQCQ: + len += snprintf(pbuffer+len, LPFC_DRB_ACC_BUF_SIZE-len, + "EQCQ-DRB-REG: 0x%08x\n", + readl(phba->sli4_hba.EQCQDBregaddr)); + break; + case LPFC_DRB_MQ: + len += snprintf(pbuffer+len, LPFC_DRB_ACC_BUF_SIZE-len, + "MQ-DRB-REG: 0x%08x\n", + readl(phba->sli4_hba.MQDBregaddr)); + break; + case LPFC_DRB_WQ: + len += snprintf(pbuffer+len, LPFC_DRB_ACC_BUF_SIZE-len, + "WQ-DRB-REG: 0x%08x\n", + readl(phba->sli4_hba.WQDBregaddr)); + break; + case LPFC_DRB_RQ: + len += snprintf(pbuffer+len, LPFC_DRB_ACC_BUF_SIZE-len, + "RQ-DRB-REG: 0x%08x\n", + readl(phba->sli4_hba.RQDBregaddr)); + break; + default: + break; + } + + return len; +} + +/** + * lpfc_idiag_drbacc_read - idiag debugfs read port doorbell + * @file: The file pointer to read from. + * @buf: The buffer to copy the data to. + * @nbytes: The number of bytes to read. + * @ppos: The position in the file to start reading from. + * + * Description: + * This routine reads data from the @phba device doorbell register according + * to the idiag command, and copies to user @buf. Depending on the doorbell + * register read command setup, it does either a single doorbell register + * read or dump all doorbell registers. + * + * Returns: + * This function returns the amount of data that was read (this could be less + * than @nbytes if the end of the file was reached) or a negative error value. + **/ +static ssize_t +lpfc_idiag_drbacc_read(struct file *file, char __user *buf, size_t nbytes, + loff_t *ppos) +{ + struct lpfc_debug *debug = file->private_data; + struct lpfc_hba *phba = (struct lpfc_hba *)debug->i_private; + uint32_t drb_reg_id, i; + char *pbuffer; + int len = 0; + + /* This is a user read operation */ + debug->op = LPFC_IDIAG_OP_RD; + + if (!debug->buffer) + debug->buffer = kmalloc(LPFC_DRB_ACC_BUF_SIZE, GFP_KERNEL); + if (!debug->buffer) + return 0; + pbuffer = debug->buffer; + + if (*ppos) + return 0; + + if (idiag.cmd.opcode == LPFC_IDIAG_CMD_DRBACC_RD) + drb_reg_id = idiag.cmd.data[0]; + else + return 0; + + if (drb_reg_id == LPFC_DRB_ACC_ALL) + for (i = 1; i <= LPFC_DRB_MAX; i++) + len = lpfc_idiag_drbacc_read_reg(phba, + pbuffer, len, i); + else + len = lpfc_idiag_drbacc_read_reg(phba, + pbuffer, len, drb_reg_id); + + return simple_read_from_buffer(buf, nbytes, ppos, pbuffer, len); +} + +/** + * lpfc_idiag_drbacc_write - Syntax check and set up idiag drbacc commands + * @file: The file pointer to read from. + * @buf: The buffer to copy the user data from. + * @nbytes: The number of bytes to get. + * @ppos: The position in the file to start reading from. + * + * This routine get the debugfs idiag command struct from user space and then + * perform the syntax check for port doorbell register read (dump) or write + * (set) command accordingly. In the case of port queue read command, it sets + * up the command in the idiag command struct for the following debugfs read + * operation. In the case of port doorbell register write operation, it + * executes the write operation into the port doorbell register accordingly. + * + * It returns the @nbytges passing in from debugfs user space when successful. + * In case of error conditions, it returns proper error code back to the user + * space. + **/ +static ssize_t +lpfc_idiag_drbacc_write(struct file *file, const char __user *buf, + size_t nbytes, loff_t *ppos) +{ + struct lpfc_debug *debug = file->private_data; + struct lpfc_hba *phba = (struct lpfc_hba *)debug->i_private; + uint32_t drb_reg_id, value, reg_val; + void __iomem *drb_reg; + int rc; + + /* This is a user write operation */ + debug->op = LPFC_IDIAG_OP_WR; + + rc = lpfc_idiag_cmd_get(buf, nbytes, &idiag.cmd); + if (rc < 0) + return rc; + + /* Sanity check on command line arguments */ + drb_reg_id = idiag.cmd.data[0]; + value = idiag.cmd.data[1]; + + if (idiag.cmd.opcode == LPFC_IDIAG_CMD_DRBACC_WR || + idiag.cmd.opcode == LPFC_IDIAG_CMD_DRBACC_ST || + idiag.cmd.opcode == LPFC_IDIAG_CMD_DRBACC_CL) { + if (rc != LPFC_DRB_ACC_WR_CMD_ARG) + goto error_out; + if (drb_reg_id > LPFC_DRB_MAX) + goto error_out; + } else if (idiag.cmd.opcode == LPFC_IDIAG_CMD_DRBACC_RD) { + if (rc != LPFC_DRB_ACC_RD_CMD_ARG) + goto error_out; + if ((drb_reg_id > LPFC_DRB_MAX) && + (drb_reg_id != LPFC_DRB_ACC_ALL)) + goto error_out; + } else + goto error_out; + + /* Perform the write access operation */ + if (idiag.cmd.opcode == LPFC_IDIAG_CMD_DRBACC_WR || + idiag.cmd.opcode == LPFC_IDIAG_CMD_DRBACC_ST || + idiag.cmd.opcode == LPFC_IDIAG_CMD_DRBACC_CL) { + switch (drb_reg_id) { + case LPFC_DRB_EQCQ: + drb_reg = phba->sli4_hba.EQCQDBregaddr; + break; + case LPFC_DRB_MQ: + drb_reg = phba->sli4_hba.MQDBregaddr; + break; + case LPFC_DRB_WQ: + drb_reg = phba->sli4_hba.WQDBregaddr; + break; + case LPFC_DRB_RQ: + drb_reg = phba->sli4_hba.RQDBregaddr; + break; + default: + goto error_out; + } + + if (idiag.cmd.opcode == LPFC_IDIAG_CMD_DRBACC_WR) + reg_val = value; + if (idiag.cmd.opcode == LPFC_IDIAG_CMD_DRBACC_ST) { + reg_val = readl(drb_reg); + reg_val |= value; + } + if (idiag.cmd.opcode == LPFC_IDIAG_CMD_DRBACC_CL) { + reg_val = readl(drb_reg); + reg_val &= ~value; + } + writel(reg_val, drb_reg); + readl(drb_reg); /* flush */ + } + return nbytes; + +error_out: + /* Clean out command structure on command error out */ + memset(&idiag, 0, sizeof(idiag)); + return -EINVAL; +} + #undef lpfc_debugfs_op_disc_trc static const struct file_operations lpfc_debugfs_op_disc_trc = { .owner = THIS_MODULE, @@ -1986,6 +2425,26 @@ static const struct file_operations lpfc_idiag_op_queInfo = { .release = lpfc_idiag_release, }; +#undef lpfc_idiag_op_queacc +static const struct file_operations lpfc_idiag_op_queAcc = { + .owner = THIS_MODULE, + .open = lpfc_idiag_open, + .llseek = lpfc_debugfs_lseek, + .read = lpfc_idiag_queacc_read, + .write = lpfc_idiag_queacc_write, + .release = lpfc_idiag_cmd_release, +}; + +#undef lpfc_idiag_op_drbacc +static const struct file_operations lpfc_idiag_op_drbAcc = { + .owner = THIS_MODULE, + .open = lpfc_idiag_open, + .llseek = lpfc_debugfs_lseek, + .read = lpfc_idiag_drbacc_read, + .write = lpfc_idiag_drbacc_write, + .release = lpfc_idiag_cmd_release, +}; + #endif /** @@ -2261,6 +2720,32 @@ lpfc_debugfs_initialize(struct lpfc_vport *vport) } } + /* iDiag access PCI function queue */ + snprintf(name, sizeof(name), "queAcc"); + if (!phba->idiag_que_acc) { + phba->idiag_que_acc = + debugfs_create_file(name, S_IFREG|S_IRUGO|S_IWUSR, + phba->idiag_root, phba, &lpfc_idiag_op_queAcc); + if (!phba->idiag_que_acc) { + lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT, + "2926 Can't create idiag debugfs\n"); + goto debug_failed; + } + } + + /* iDiag access PCI function doorbell registers */ + snprintf(name, sizeof(name), "drbAcc"); + if (!phba->idiag_drb_acc) { + phba->idiag_drb_acc = + debugfs_create_file(name, S_IFREG|S_IRUGO|S_IWUSR, + phba->idiag_root, phba, &lpfc_idiag_op_drbAcc); + if (!phba->idiag_drb_acc) { + lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT, + "2927 Can't create idiag debugfs\n"); + goto debug_failed; + } + } + debug_failed: return; #endif @@ -2339,6 +2824,16 @@ lpfc_debugfs_terminate(struct lpfc_vport *vport) * iDiag release */ if (phba->sli_rev == LPFC_SLI_REV4) { + if (phba->idiag_drb_acc) { + /* iDiag drbAcc */ + debugfs_remove(phba->idiag_drb_acc); + phba->idiag_drb_acc = NULL; + } + if (phba->idiag_que_acc) { + /* iDiag queAcc */ + debugfs_remove(phba->idiag_que_acc); + phba->idiag_que_acc = NULL; + } if (phba->idiag_que_info) { /* iDiag queInfo */ debugfs_remove(phba->idiag_que_info); diff --git a/drivers/scsi/lpfc/lpfc_debugfs.h b/drivers/scsi/lpfc/lpfc_debugfs.h index 91b9a94..6525a5e 100644 --- a/drivers/scsi/lpfc/lpfc_debugfs.h +++ b/drivers/scsi/lpfc/lpfc_debugfs.h @@ -39,13 +39,42 @@ /* hbqinfo output buffer size */ #define LPFC_HBQINFO_SIZE 8192 -/* rdPciConf output buffer size */ +/* pciConf */ +#define LPFC_PCI_CFG_BROWSE 0xffff +#define LPFC_PCI_CFG_RD_CMD_ARG 2 +#define LPFC_PCI_CFG_WR_CMD_ARG 3 #define LPFC_PCI_CFG_SIZE 4096 #define LPFC_PCI_CFG_RD_BUF_SIZE (LPFC_PCI_CFG_SIZE/2) #define LPFC_PCI_CFG_RD_SIZE (LPFC_PCI_CFG_SIZE/4) -/* queue info output buffer size */ -#define LPFC_QUE_INFO_GET_BUF_SIZE 2048 +/* queue info */ +#define LPFC_QUE_INFO_GET_BUF_SIZE 4096 + +/* queue acc */ +#define LPFC_QUE_ACC_BROWSE 0xffff +#define LPFC_QUE_ACC_RD_CMD_ARG 4 +#define LPFC_QUE_ACC_WR_CMD_ARG 6 +#define LPFC_QUE_ACC_BUF_SIZE 4096 +#define LPFC_QUE_ACC_SIZE (LPFC_QUE_ACC_BUF_SIZE/2) + +#define LPFC_IDIAG_EQ 1 +#define LPFC_IDIAG_CQ 2 +#define LPFC_IDIAG_MQ 3 +#define LPFC_IDIAG_WQ 4 +#define LPFC_IDIAG_RQ 5 + +/* doorbell acc */ +#define LPFC_DRB_ACC_ALL 0xffff +#define LPFC_DRB_ACC_RD_CMD_ARG 1 +#define LPFC_DRB_ACC_WR_CMD_ARG 2 +#define LPFC_DRB_ACC_BUF_SIZE 256 + +#define LPFC_DRB_EQCQ 1 +#define LPFC_DRB_MQ 2 +#define LPFC_DRB_WQ 3 +#define LPFC_DRB_RQ 4 + +#define LPFC_DRB_MAX 4 #define SIZE_U8 sizeof(uint8_t) #define SIZE_U16 sizeof(uint16_t) @@ -73,13 +102,23 @@ struct lpfc_idiag_offset { uint32_t last_rd; }; -#define LPFC_IDIAG_CMD_DATA_SIZE 4 +#define LPFC_IDIAG_CMD_DATA_SIZE 8 struct lpfc_idiag_cmd { uint32_t opcode; #define LPFC_IDIAG_CMD_PCICFG_RD 0x00000001 #define LPFC_IDIAG_CMD_PCICFG_WR 0x00000002 #define LPFC_IDIAG_CMD_PCICFG_ST 0x00000003 #define LPFC_IDIAG_CMD_PCICFG_CL 0x00000004 + +#define LPFC_IDIAG_CMD_QUEACC_RD 0x00000011 +#define LPFC_IDIAG_CMD_QUEACC_WR 0x00000012 +#define LPFC_IDIAG_CMD_QUEACC_ST 0x00000013 +#define LPFC_IDIAG_CMD_QUEACC_CL 0x00000014 + +#define LPFC_IDIAG_CMD_DRBACC_RD 0x00000021 +#define LPFC_IDIAG_CMD_DRBACC_WR 0x00000022 +#define LPFC_IDIAG_CMD_DRBACC_ST 0x00000023 +#define LPFC_IDIAG_CMD_DRBACC_CL 0x00000024 uint32_t data[LPFC_IDIAG_CMD_DATA_SIZE]; }; @@ -87,6 +126,7 @@ struct lpfc_idiag { uint32_t active; struct lpfc_idiag_cmd cmd; struct lpfc_idiag_offset offset; + void *ptr_private; }; #endif -- cgit v0.10.2 From 9589b062f53e314ea3abfaca8de7a260b4ef69c2 Mon Sep 17 00:00:00 2001 From: James Smart Date: Sat, 16 Apr 2011 11:03:17 -0400 Subject: [SCSI] lpfc 8.3.23: Miscellaneous fixes Miscellaneous fixes - Do not limit RPI Count to a minimum of 64 - Fix FCFI incorrect on received unsolicited frames. - Save the FCFI returned in the REG_FCFI mailbox command if it was successful. - Fixed Vports not sending FDISC after lips. - Align based on the SLI4_PAGE_SIZE. - Fixed double byte swap on received RRQ. - Fixed mask size for the wq_id mask from 0x7F to 0x7FFF. - Clear FC_FABRIC flag when NPIV LOGO completes (and add a log message). - Modified driver to skip round robin only when ulpStatus==LOCAL_REJECT and word4=SEQUENCE_TIMEOUT to prevent FLOGI to disconnected FCF. - Don't add rport if driver unloading Signed-off-by: Alex Iannicelli Signed-off-by: James Smart Signed-off-by: James Bottomley diff --git a/drivers/scsi/lpfc/lpfc_els.c b/drivers/scsi/lpfc/lpfc_els.c index d34b69f..04a5aeb 100644 --- a/drivers/scsi/lpfc/lpfc_els.c +++ b/drivers/scsi/lpfc/lpfc_els.c @@ -670,6 +670,7 @@ lpfc_cmpl_els_flogi_fabric(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, * Driver needs to re-reg VPI in order for f/w * to update the MAC address. */ + lpfc_nlp_set_state(vport, ndlp, NLP_STE_UNMAPPED_NODE); lpfc_register_new_vport(phba, vport, ndlp); return 0; } @@ -869,8 +870,8 @@ lpfc_cmpl_els_flogi(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, */ if ((phba->hba_flag & HBA_FIP_SUPPORT) && (phba->fcf.fcf_flag & FCF_DISCOVERY) && - (irsp->ulpStatus != IOSTAT_LOCAL_REJECT) && - (irsp->un.ulpWord[4] != IOERR_SLI_ABORTED)) { + !((irsp->ulpStatus == IOSTAT_LOCAL_REJECT) && + (irsp->un.ulpWord[4] == IOERR_SLI_ABORTED))) { lpfc_printf_log(phba, KERN_WARNING, LOG_FIP | LOG_ELS, "2611 FLOGI failed on FCF (x%x), " "status:x%x/x%x, tmo:x%x, perform " @@ -4107,13 +4108,13 @@ lpfc_els_clear_rrq(struct lpfc_vport *vport, pcmd += sizeof(uint32_t); rrq = (struct RRQ *)pcmd; rrq->rrq_exchg = be32_to_cpu(rrq->rrq_exchg); - rxid = be16_to_cpu(bf_get(rrq_rxid, rrq)); + rxid = bf_get(rrq_rxid, rrq); lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS, "2883 Clear RRQ for SID:x%x OXID:x%x RXID:x%x" " x%x x%x\n", be32_to_cpu(bf_get(rrq_did, rrq)), - be16_to_cpu(bf_get(rrq_oxid, rrq)), + bf_get(rrq_oxid, rrq), rxid, iocb->iotag, iocb->iocb.ulpContext); @@ -4121,7 +4122,7 @@ lpfc_els_clear_rrq(struct lpfc_vport *vport, "Clear RRQ: did:x%x flg:x%x exchg:x%.08x", ndlp->nlp_DID, ndlp->nlp_flag, rrq->rrq_exchg); if (vport->fc_myDID == be32_to_cpu(bf_get(rrq_did, rrq))) - xri = be16_to_cpu(bf_get(rrq_oxid, rrq)); + xri = bf_get(rrq_oxid, rrq); else xri = rxid; prrq = lpfc_get_active_rrq(vport, xri, ndlp->nlp_DID); @@ -7290,8 +7291,9 @@ lpfc_cmpl_els_npiv_logo(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, struct lpfc_vport *vport = cmdiocb->vport; IOCB_t *irsp; struct lpfc_nodelist *ndlp; - ndlp = (struct lpfc_nodelist *)cmdiocb->context1; + struct Scsi_Host *shost = lpfc_shost_from_vport(vport); + ndlp = (struct lpfc_nodelist *)cmdiocb->context1; irsp = &rspiocb->iocb; lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_CMD, "LOGO npiv cmpl: status:x%x/x%x did:x%x", @@ -7302,6 +7304,19 @@ lpfc_cmpl_els_npiv_logo(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, /* Trigger the release of the ndlp after logo */ lpfc_nlp_put(ndlp); + + /* NPIV LOGO completes to NPort */ + lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS, + "2928 NPIV LOGO completes to NPort x%x " + "Data: x%x x%x x%x x%x\n", + ndlp->nlp_DID, irsp->ulpStatus, irsp->un.ulpWord[4], + irsp->ulpTimeout, vport->num_disc_nodes); + + if (irsp->ulpStatus == IOSTAT_SUCCESS) { + spin_lock_irq(shost->host_lock); + vport->fc_flag &= ~FC_FABRIC; + spin_unlock_irq(shost->host_lock); + } } /** diff --git a/drivers/scsi/lpfc/lpfc_hbadisc.c b/drivers/scsi/lpfc/lpfc_hbadisc.c index 3014983..7a35df5 100644 --- a/drivers/scsi/lpfc/lpfc_hbadisc.c +++ b/drivers/scsi/lpfc/lpfc_hbadisc.c @@ -1,7 +1,7 @@ /******************************************************************* * This file is part of the Emulex Linux Device Driver for * * Fibre Channel Host Bus Adapters. * - * Copyright (C) 2004-2009 Emulex. All rights reserved. * + * Copyright (C) 2004-2011 Emulex. All rights reserved. * * EMULEX and SLI are trademarks of Emulex. * * www.emulex.com * * Portions Copyright (C) 2004-2005 Christoph Hellwig * @@ -3569,6 +3569,10 @@ lpfc_register_remote_port(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) "rport add: did:x%x flg:x%x type x%x", ndlp->nlp_DID, ndlp->nlp_flag, ndlp->nlp_type); + /* Don't add the remote port if unloading. */ + if (vport->load_flag & FC_UNLOADING) + return; + ndlp->rport = rport = fc_remote_port_add(shost, 0, &rport_ids); if (!rport || !get_device(&rport->dev)) { dev_printk(KERN_WARNING, &phba->pcidev->dev, diff --git a/drivers/scsi/lpfc/lpfc_hw4.h b/drivers/scsi/lpfc/lpfc_hw4.h index 8433ac0..a8e2c69 100644 --- a/drivers/scsi/lpfc/lpfc_hw4.h +++ b/drivers/scsi/lpfc/lpfc_hw4.h @@ -2108,6 +2108,8 @@ struct lpfc_mbx_pc_sli4_params { #define sgl_pp_align_WORD word12 uint32_t rsvd_13_63[51]; }; +#define SLI4_PAGE_ALIGN(addr) (((addr)+((SLI4_PAGE_SIZE)-1)) \ + &(~((SLI4_PAGE_SIZE)-1))) struct lpfc_sli4_parameters { uint32_t word0; @@ -2524,7 +2526,7 @@ struct wqe_common { #define wqe_wqes_WORD word10 /* Note that this field overlaps above fields */ #define wqe_wqid_SHIFT 1 -#define wqe_wqid_MASK 0x0000007f +#define wqe_wqid_MASK 0x00007fff #define wqe_wqid_WORD word10 #define wqe_pri_SHIFT 16 #define wqe_pri_MASK 0x00000007 diff --git a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c index 505f884..7b6a089 100644 --- a/drivers/scsi/lpfc/lpfc_init.c +++ b/drivers/scsi/lpfc/lpfc_init.c @@ -4906,6 +4906,7 @@ lpfc_sli4_create_rpi_hdr(struct lpfc_hba *phba) uint16_t rpi_limit, curr_rpi_range; struct lpfc_dmabuf *dmabuf; struct lpfc_rpi_hdr *rpi_hdr; + uint32_t rpi_count; rpi_limit = phba->sli4_hba.max_cfg_param.rpi_base + phba->sli4_hba.max_cfg_param.max_rpi - 1; @@ -4920,7 +4921,9 @@ lpfc_sli4_create_rpi_hdr(struct lpfc_hba *phba) * and to allow the full max_rpi range per port. */ if ((curr_rpi_range + (LPFC_RPI_HDR_COUNT - 1)) > rpi_limit) - return NULL; + rpi_count = rpi_limit - curr_rpi_range; + else + rpi_count = LPFC_RPI_HDR_COUNT; /* * First allocate the protocol header region for the port. The @@ -4961,7 +4964,7 @@ lpfc_sli4_create_rpi_hdr(struct lpfc_hba *phba) * The next_rpi stores the next module-64 rpi value to post * in any subsequent rpi memory region postings. */ - phba->sli4_hba.next_rpi += LPFC_RPI_HDR_COUNT; + phba->sli4_hba.next_rpi += rpi_count; spin_unlock_irq(&phba->hbalock); return rpi_hdr; diff --git a/drivers/scsi/lpfc/lpfc_mbox.c b/drivers/scsi/lpfc/lpfc_mbox.c index fbab973..e6ce903 100644 --- a/drivers/scsi/lpfc/lpfc_mbox.c +++ b/drivers/scsi/lpfc/lpfc_mbox.c @@ -1736,7 +1736,7 @@ lpfc_sli4_config(struct lpfc_hba *phba, struct lpfcMboxq *mbox, } /* Setup for the none-embedded mbox command */ - pcount = (PAGE_ALIGN(length))/SLI4_PAGE_SIZE; + pcount = (SLI4_PAGE_ALIGN(length))/SLI4_PAGE_SIZE; pcount = (pcount > LPFC_SLI4_MBX_SGE_MAX_PAGES) ? LPFC_SLI4_MBX_SGE_MAX_PAGES : pcount; /* Allocate record for keeping SGE virtual addresses */ diff --git a/drivers/scsi/lpfc/lpfc_sli.c b/drivers/scsi/lpfc/lpfc_sli.c index dacabbe..580b00b 100644 --- a/drivers/scsi/lpfc/lpfc_sli.c +++ b/drivers/scsi/lpfc/lpfc_sli.c @@ -5018,10 +5018,11 @@ lpfc_sli4_hba_setup(struct lpfc_hba *phba) lpfc_reg_fcfi(phba, mboxq); mboxq->vport = phba->pport; rc = lpfc_sli_issue_mbox(phba, mboxq, MBX_POLL); - if (rc == MBX_SUCCESS) - rc = 0; - else + if (rc != MBX_SUCCESS) goto out_unset_queue; + rc = 0; + phba->fcf.fcfi = bf_get(lpfc_reg_fcfi_fcfi, + &mboxq->u.mqe.un.reg_fcfi); } /* * The port is ready, set the host's link state to LINK_DOWN -- cgit v0.10.2 From c30aa39c233ca1df8397eb9e9c8b40a397ce72bb Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Sun, 1 May 2011 11:34:55 -0400 Subject: hwmon: (twl4030-madc-hwmon) Return proper error if hwmon_device_register fails The driver did not return an error if the call to hwmon_device_register failed. Fix by returning the error reported from hwmon_device_register. Signed-off-by: Axel Lin Signed-off-by: Guenter Roeck diff --git a/drivers/hwmon/twl4030-madc-hwmon.c b/drivers/hwmon/twl4030-madc-hwmon.c index de58191..5724074 100644 --- a/drivers/hwmon/twl4030-madc-hwmon.c +++ b/drivers/hwmon/twl4030-madc-hwmon.c @@ -98,7 +98,6 @@ static const struct attribute_group twl4030_madc_group = { static int __devinit twl4030_madc_hwmon_probe(struct platform_device *pdev) { int ret; - int status; struct device *hwmon; ret = sysfs_create_group(&pdev->dev.kobj, &twl4030_madc_group); @@ -107,7 +106,7 @@ static int __devinit twl4030_madc_hwmon_probe(struct platform_device *pdev) hwmon = hwmon_device_register(&pdev->dev); if (IS_ERR(hwmon)) { dev_err(&pdev->dev, "hwmon_device_register failed.\n"); - status = PTR_ERR(hwmon); + ret = PTR_ERR(hwmon); goto err_reg; } -- cgit v0.10.2 From c31098cef5e091e22a02ff255f911e0ad71cc393 Mon Sep 17 00:00:00 2001 From: James Smart Date: Sat, 16 Apr 2011 11:03:33 -0400 Subject: [SCSI] lpfc 8.3.23: Fixes related to new hardware Fixes related to new hardware - Restrict driver to look at BAR2 or BAR4 only for if_type 0. - Allow SLI4 with FCOE_MODE not set for new SLI4 FC adapters. - Add Temporary RPI field to the ELS request WQE. - Do not override CT field in issue_els_flogi for SLI4 IF type 2 - For RQ_CREATE_V2 mbx cmd: fill in the rqe_size and page_size for RQ_CREATE. Signed-off-by: Alex Iannicelli Signed-off-by: James Smart Signed-off-by: James Bottomley diff --git a/drivers/scsi/lpfc/lpfc_els.c b/drivers/scsi/lpfc/lpfc_els.c index 04a5aeb..e2c4524 100644 --- a/drivers/scsi/lpfc/lpfc_els.c +++ b/drivers/scsi/lpfc/lpfc_els.c @@ -1086,14 +1086,15 @@ lpfc_issue_els_flogi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, if (sp->cmn.fcphHigh < FC_PH3) sp->cmn.fcphHigh = FC_PH3; - if ((phba->sli_rev == LPFC_SLI_REV4) && - (bf_get(lpfc_sli_intf_if_type, &phba->sli4_hba.sli_intf) == - LPFC_SLI_INTF_IF_TYPE_0)) { - elsiocb->iocb.ulpCt_h = ((SLI4_CT_FCFI >> 1) & 1); - elsiocb->iocb.ulpCt_l = (SLI4_CT_FCFI & 1); - /* FLOGI needs to be 3 for WQE FCFI */ - /* Set the fcfi to the fcfi we registered with */ - elsiocb->iocb.ulpContext = phba->fcf.fcfi; + if (phba->sli_rev == LPFC_SLI_REV4) { + if (bf_get(lpfc_sli_intf_if_type, &phba->sli4_hba.sli_intf) == + LPFC_SLI_INTF_IF_TYPE_0) { + elsiocb->iocb.ulpCt_h = ((SLI4_CT_FCFI >> 1) & 1); + elsiocb->iocb.ulpCt_l = (SLI4_CT_FCFI & 1); + /* FLOGI needs to be 3 for WQE FCFI */ + /* Set the fcfi to the fcfi we registered with */ + elsiocb->iocb.ulpContext = phba->fcf.fcfi; + } } else if (phba->sli3_options & LPFC_SLI3_NPIV_ENABLED) { sp->cmn.request_multiple_Nport = 1; /* For FLOGI, Let FLOGI rsp set the NPortID for VPI 0 */ diff --git a/drivers/scsi/lpfc/lpfc_hw4.h b/drivers/scsi/lpfc/lpfc_hw4.h index a8e2c69..4dff668 100644 --- a/drivers/scsi/lpfc/lpfc_hw4.h +++ b/drivers/scsi/lpfc/lpfc_hw4.h @@ -1059,6 +1059,11 @@ struct rq_context { #define lpfc_rq_context_rqe_size_SHIFT 8 /* Version 1 Only */ #define lpfc_rq_context_rqe_size_MASK 0x0000000F #define lpfc_rq_context_rqe_size_WORD word0 +#define LPFC_RQE_SIZE_8 2 +#define LPFC_RQE_SIZE_16 3 +#define LPFC_RQE_SIZE_32 4 +#define LPFC_RQE_SIZE_64 5 +#define LPFC_RQE_SIZE_128 6 #define lpfc_rq_context_page_size_SHIFT 0 /* Version 1 Only */ #define lpfc_rq_context_page_size_MASK 0x000000FF #define lpfc_rq_context_page_size_WORD word0 @@ -2493,6 +2498,9 @@ struct wqe_common { #define wqe_reqtag_SHIFT 0 #define wqe_reqtag_MASK 0x0000FFFF #define wqe_reqtag_WORD word9 +#define wqe_temp_rpi_SHIFT 16 +#define wqe_temp_rpi_MASK 0x0000FFFF +#define wqe_temp_rpi_WORD word9 #define wqe_rcvoxid_SHIFT 16 #define wqe_rcvoxid_MASK 0x0000FFFF #define wqe_rcvoxid_WORD word9 @@ -2623,7 +2631,11 @@ struct xmit_els_rsp64_wqe { uint32_t rsvd4; struct wqe_did wqe_dest; struct wqe_common wqe_com; /* words 6-11 */ - uint32_t rsvd_12_15[4]; + uint32_t word12; +#define wqe_rsp_temp_rpi_SHIFT 0 +#define wqe_rsp_temp_rpi_MASK 0x0000FFFF +#define wqe_rsp_temp_rpi_WORD word12 + uint32_t rsvd_13_15[3]; }; struct xmit_bls_rsp64_wqe { diff --git a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c index 7b6a089..7dda036 100644 --- a/drivers/scsi/lpfc/lpfc_init.c +++ b/drivers/scsi/lpfc/lpfc_init.c @@ -3209,9 +3209,9 @@ lpfc_sli4_async_link_evt(struct lpfc_hba *phba, phba->sli4_hba.link_state.logical_speed = bf_get(lpfc_acqe_logical_link_speed, acqe_link); lpfc_printf_log(phba, KERN_INFO, LOG_SLI, - "2900 Async FCoE Link event - Speed:%dGBit duplex:x%x " - "LA Type:x%x Port Type:%d Port Number:%d Logical " - "speed:%dMbps Fault:%d\n", + "2900 Async FC/FCoE Link event - Speed:%dGBit " + "duplex:x%x LA Type:x%x Port Type:%d Port Number:%d " + "Logical speed:%dMbps Fault:%d\n", phba->sli4_hba.link_state.speed, phba->sli4_hba.link_state.topology, phba->sli4_hba.link_state.status, @@ -7007,7 +7007,8 @@ lpfc_sli4_pci_mem_setup(struct lpfc_hba *phba) lpfc_sli4_bar0_register_memmap(phba, if_type); } - if (pci_resource_start(pdev, 2)) { + if ((if_type == LPFC_SLI_INTF_IF_TYPE_0) && + (pci_resource_start(pdev, 2))) { /* * Map SLI4 if type 0 HBA Control Register base to a kernel * virtual address and setup the registers. @@ -7024,7 +7025,8 @@ lpfc_sli4_pci_mem_setup(struct lpfc_hba *phba) lpfc_sli4_bar1_register_memmap(phba); } - if (pci_resource_start(pdev, 4)) { + if ((if_type == LPFC_SLI_INTF_IF_TYPE_0) && + (pci_resource_start(pdev, 4))) { /* * Map SLI4 if type 0 HBA Doorbell Register base to a kernel * virtual address and setup the registers. diff --git a/drivers/scsi/lpfc/lpfc_sli.c b/drivers/scsi/lpfc/lpfc_sli.c index 580b00b..837d272 100644 --- a/drivers/scsi/lpfc/lpfc_sli.c +++ b/drivers/scsi/lpfc/lpfc_sli.c @@ -4769,8 +4769,7 @@ lpfc_sli4_hba_setup(struct lpfc_hba *phba) else phba->hba_flag &= ~HBA_FIP_SUPPORT; - if (phba->sli_rev != LPFC_SLI_REV4 || - !(phba->hba_flag & HBA_FCOE_MODE)) { + if (phba->sli_rev != LPFC_SLI_REV4) { lpfc_printf_log(phba, KERN_ERR, LOG_MBOX | LOG_SLI, "0376 READ_REV Error. SLI Level %d " "FCoE enabled %d\n", @@ -6403,6 +6402,7 @@ lpfc_sli4_iocb2wqe(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq, uint32_t els_id = LPFC_ELS_ID_DEFAULT; int numBdes, i; struct ulp_bde64 bde; + struct lpfc_nodelist *ndlp; fip = phba->hba_flag & HBA_FIP_SUPPORT; /* The fcp commands will set command type */ @@ -6448,6 +6448,7 @@ lpfc_sli4_iocb2wqe(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq, switch (iocbq->iocb.ulpCommand) { case CMD_ELS_REQUEST64_CR: + ndlp = (struct lpfc_nodelist *)iocbq->context1; if (!iocbq->iocb.ulpLe) { lpfc_printf_log(phba, KERN_ERR, LOG_SLI, "2007 Only Limited Edition cmd Format" @@ -6473,6 +6474,7 @@ lpfc_sli4_iocb2wqe(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq, els_id = ((iocbq->iocb_flag & LPFC_FIP_ELS_ID_MASK) >> LPFC_FIP_ELS_ID_SHIFT); } + bf_set(wqe_temp_rpi, &wqe->els_req.wqe_com, ndlp->nlp_rpi); bf_set(wqe_els_id, &wqe->els_req.wqe_com, els_id); bf_set(wqe_dbde, &wqe->els_req.wqe_com, 1); bf_set(wqe_iod, &wqe->els_req.wqe_com, LPFC_WQE_IOD_READ); @@ -6605,6 +6607,7 @@ lpfc_sli4_iocb2wqe(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq, command_type = OTHER_COMMAND; break; case CMD_XMIT_ELS_RSP64_CX: + ndlp = (struct lpfc_nodelist *)iocbq->context1; /* words0-2 BDE memcpy */ /* word3 iocb=iotag32 wqe=response_payload_len */ wqe->xmit_els_rsp.response_payload_len = xmit_len; @@ -6627,6 +6630,7 @@ lpfc_sli4_iocb2wqe(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq, bf_set(wqe_lenloc, &wqe->xmit_els_rsp.wqe_com, LPFC_WQE_LENLOC_WORD3); bf_set(wqe_ebde_cnt, &wqe->xmit_els_rsp.wqe_com, 0); + bf_set(wqe_rsp_temp_rpi, &wqe->xmit_els_rsp, ndlp->nlp_rpi); command_type = OTHER_COMMAND; break; case CMD_CLOSE_XRI_CN: @@ -10523,8 +10527,8 @@ lpfc_cq_create(struct lpfc_hba *phba, struct lpfc_queue *cq, bf_set(lpfc_mbox_hdr_version, &shdr->request, phba->sli4_hba.pc_sli4_params.cqv); if (phba->sli4_hba.pc_sli4_params.cqv == LPFC_Q_CREATE_VERSION_2) { - bf_set(lpfc_mbx_cq_create_page_size, &cq_create->u.request, - (PAGE_SIZE/SLI4_PAGE_SIZE)); + /* FW only supports 1. Should be PAGE_SIZE/SLI4_PAGE_SIZE */ + bf_set(lpfc_mbx_cq_create_page_size, &cq_create->u.request, 1); bf_set(lpfc_cq_eq_id_2, &cq_create->u.request.context, eq->queue_id); } else { @@ -10968,6 +10972,12 @@ lpfc_rq_create(struct lpfc_hba *phba, struct lpfc_queue *hrq, &rq_create->u.request.context, hrq->entry_count); rq_create->u.request.context.buffer_size = LPFC_HDR_BUF_SIZE; + bf_set(lpfc_rq_context_rqe_size, + &rq_create->u.request.context, + LPFC_RQE_SIZE_8); + bf_set(lpfc_rq_context_page_size, + &rq_create->u.request.context, + (PAGE_SIZE/SLI4_PAGE_SIZE)); } else { switch (hrq->entry_count) { default: @@ -11043,9 +11053,12 @@ lpfc_rq_create(struct lpfc_hba *phba, struct lpfc_queue *hrq, phba->sli4_hba.pc_sli4_params.rqv); if (phba->sli4_hba.pc_sli4_params.rqv == LPFC_Q_CREATE_VERSION_1) { bf_set(lpfc_rq_context_rqe_count_1, - &rq_create->u.request.context, - hrq->entry_count); + &rq_create->u.request.context, hrq->entry_count); rq_create->u.request.context.buffer_size = LPFC_DATA_BUF_SIZE; + bf_set(lpfc_rq_context_rqe_size, &rq_create->u.request.context, + LPFC_RQE_SIZE_8); + bf_set(lpfc_rq_context_page_size, &rq_create->u.request.context, + (PAGE_SIZE/SLI4_PAGE_SIZE)); } else { switch (drq->entry_count) { default: -- cgit v0.10.2 From b6e3b9c606f271824bdeb6a40a080452eb086598 Mon Sep 17 00:00:00 2001 From: James Smart Date: Sat, 16 Apr 2011 11:03:43 -0400 Subject: [SCSI] lpfc 8.3.23: BSG additions and fixes - Fixed the mixed declarations and codes which violate ISO C90 (declarations in subsections that assign at declaration) - Add BSG data transfer size protection in mailbox command pass-through path - Invoke BSG job_done while holding spinlock to fix deadlock - Added support for checking SLI_CONFIG subcommands - Fixed bug in BSG mailbox size check to non-embedded external buffer Signed-off-by: Alex Iannicelli Signed-off-by: James Smart Signed-off-by: James Bottomley diff --git a/drivers/scsi/lpfc/lpfc_bsg.c b/drivers/scsi/lpfc/lpfc_bsg.c index 77b2871..37e2a12 100644 --- a/drivers/scsi/lpfc/lpfc_bsg.c +++ b/drivers/scsi/lpfc/lpfc_bsg.c @@ -2426,6 +2426,7 @@ lpfc_bsg_wake_mbox_wait(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmboxq) { struct bsg_job_data *dd_data; struct fc_bsg_job *job; + struct lpfc_mbx_nembed_cmd *nembed_sge; uint32_t size; unsigned long flags; uint8_t *to; @@ -2469,9 +2470,8 @@ lpfc_bsg_wake_mbox_wait(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmboxq) memcpy(to, from, size); } else if ((phba->sli_rev == LPFC_SLI_REV4) && (pmboxq->u.mb.mbxCommand == MBX_SLI4_CONFIG)) { - struct lpfc_mbx_nembed_cmd *nembed_sge = - (struct lpfc_mbx_nembed_cmd *) - &pmboxq->u.mb.un.varWords[0]; + nembed_sge = (struct lpfc_mbx_nembed_cmd *) + &pmboxq->u.mb.un.varWords[0]; from = (uint8_t *)dd_data->context_un.mbox.dmp->dma. virt; @@ -2496,16 +2496,18 @@ lpfc_bsg_wake_mbox_wait(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmboxq) job->reply_payload.sg_cnt, from, size); job->reply->result = 0; - + /* need to hold the lock until we set job->dd_data to NULL + * to hold off the timeout handler returning to the mid-layer + * while we are still processing the job. + */ job->dd_data = NULL; + dd_data->context_un.mbox.set_job = NULL; + spin_unlock_irqrestore(&phba->ct_ev_lock, flags); job->job_done(job); + } else { + dd_data->context_un.mbox.set_job = NULL; + spin_unlock_irqrestore(&phba->ct_ev_lock, flags); } - dd_data->context_un.mbox.set_job = NULL; - /* need to hold the lock until we call job done to hold off - * the timeout handler returning to the midlayer while - * we are stillprocessing the job - */ - spin_unlock_irqrestore(&phba->ct_ev_lock, flags); kfree(dd_data->context_un.mbox.mb); mempool_free(dd_data->context_un.mbox.pmboxq, phba->mbox_mem_pool); @@ -2644,6 +2646,11 @@ lpfc_bsg_issue_mbox(struct lpfc_hba *phba, struct fc_bsg_job *job, struct ulp_bde64 *rxbpl = NULL; struct dfc_mbox_req *mbox_req = (struct dfc_mbox_req *) job->request->rqst_data.h_vendor.vendor_cmd; + struct READ_EVENT_LOG_VAR *rdEventLog; + uint32_t transmit_length, receive_length, mode; + struct lpfc_mbx_nembed_cmd *nembed_sge; + struct mbox_header *header; + struct ulp_bde64 *bde; uint8_t *ext = NULL; int rc = 0; uint8_t *from; @@ -2651,9 +2658,16 @@ lpfc_bsg_issue_mbox(struct lpfc_hba *phba, struct fc_bsg_job *job, /* in case no data is transferred */ job->reply->reply_payload_rcv_len = 0; + /* sanity check to protect driver */ + if (job->reply_payload.payload_len > BSG_MBOX_SIZE || + job->request_payload.payload_len > BSG_MBOX_SIZE) { + rc = -ERANGE; + goto job_done; + } + /* check if requested extended data lengths are valid */ - if ((mbox_req->inExtWLen > MAILBOX_EXT_SIZE) || - (mbox_req->outExtWLen > MAILBOX_EXT_SIZE)) { + if ((mbox_req->inExtWLen > BSG_MBOX_SIZE/sizeof(uint32_t)) || + (mbox_req->outExtWLen > BSG_MBOX_SIZE/sizeof(uint32_t))) { rc = -ERANGE; goto job_done; } @@ -2744,8 +2758,8 @@ lpfc_bsg_issue_mbox(struct lpfc_hba *phba, struct fc_bsg_job *job, * use ours */ if (pmb->mbxCommand == MBX_RUN_BIU_DIAG64) { - uint32_t transmit_length = pmb->un.varWords[1]; - uint32_t receive_length = pmb->un.varWords[4]; + transmit_length = pmb->un.varWords[1]; + receive_length = pmb->un.varWords[4]; /* transmit length cannot be greater than receive length or * mailbox extension size */ @@ -2795,10 +2809,9 @@ lpfc_bsg_issue_mbox(struct lpfc_hba *phba, struct fc_bsg_job *job, from += sizeof(MAILBOX_t); memcpy((uint8_t *)dmp->dma.virt, from, transmit_length); } else if (pmb->mbxCommand == MBX_READ_EVENT_LOG) { - struct READ_EVENT_LOG_VAR *rdEventLog = - &pmb->un.varRdEventLog ; - uint32_t receive_length = rdEventLog->rcv_bde64.tus.f.bdeSize; - uint32_t mode = bf_get(lpfc_event_log, rdEventLog); + rdEventLog = &pmb->un.varRdEventLog; + receive_length = rdEventLog->rcv_bde64.tus.f.bdeSize; + mode = bf_get(lpfc_event_log, rdEventLog); /* receive length cannot be greater than mailbox * extension size @@ -2843,7 +2856,7 @@ lpfc_bsg_issue_mbox(struct lpfc_hba *phba, struct fc_bsg_job *job, /* rebuild the command for sli4 using our own buffers * like we do for biu diags */ - uint32_t receive_length = pmb->un.varWords[2]; + receive_length = pmb->un.varWords[2]; /* receive length cannot be greater than mailbox * extension size */ @@ -2879,8 +2892,7 @@ lpfc_bsg_issue_mbox(struct lpfc_hba *phba, struct fc_bsg_job *job, pmb->un.varWords[4] = putPaddrHigh(dmp->dma.phys); } else if ((pmb->mbxCommand == MBX_UPDATE_CFG) && pmb->un.varUpdateCfg.co) { - struct ulp_bde64 *bde = - (struct ulp_bde64 *)&pmb->un.varWords[4]; + bde = (struct ulp_bde64 *)&pmb->un.varWords[4]; /* bde size cannot be greater than mailbox ext size */ if (bde->tus.f.bdeSize > MAILBOX_EXT_SIZE) { @@ -2921,10 +2933,6 @@ lpfc_bsg_issue_mbox(struct lpfc_hba *phba, struct fc_bsg_job *job, memcpy((uint8_t *)dmp->dma.virt, from, bde->tus.f.bdeSize); } else if (pmb->mbxCommand == MBX_SLI4_CONFIG) { - struct lpfc_mbx_nembed_cmd *nembed_sge; - struct mbox_header *header; - uint32_t receive_length; - /* rebuild the command for sli4 using our own buffers * like we do for biu diags */ @@ -3386,6 +3394,7 @@ no_dd_data: job->dd_data = NULL; return rc; } + /** * lpfc_bsg_hst_vendor - process a vendor-specific fc_bsg_job * @job: fc_bsg_job to handle diff --git a/drivers/scsi/lpfc/lpfc_bsg.h b/drivers/scsi/lpfc/lpfc_bsg.h index a2c33e7..b542aca 100644 --- a/drivers/scsi/lpfc/lpfc_bsg.h +++ b/drivers/scsi/lpfc/lpfc_bsg.h @@ -109,3 +109,133 @@ struct menlo_response { uint32_t xri; /* return the xri of the iocb exchange */ }; +/* + * macros and data structures for handling sli-config mailbox command + * pass-through support, this header file is shared between user and + * kernel spaces, note the set of macros are duplicates from lpfc_hw4.h, + * with macro names prefixed with bsg_, as the macros defined in + * lpfc_hw4.h are not accessible from user space. + */ + +/* Macros to deal with bit fields. Each bit field must have 3 #defines + * associated with it (_SHIFT, _MASK, and _WORD). + * EG. For a bit field that is in the 7th bit of the "field4" field of a + * structure and is 2 bits in size the following #defines must exist: + * struct temp { + * uint32_t field1; + * uint32_t field2; + * uint32_t field3; + * uint32_t field4; + * #define example_bit_field_SHIFT 7 + * #define example_bit_field_MASK 0x03 + * #define example_bit_field_WORD field4 + * uint32_t field5; + * }; + * Then the macros below may be used to get or set the value of that field. + * EG. To get the value of the bit field from the above example: + * struct temp t1; + * value = bsg_bf_get(example_bit_field, &t1); + * And then to set that bit field: + * bsg_bf_set(example_bit_field, &t1, 2); + * Or clear that bit field: + * bsg_bf_set(example_bit_field, &t1, 0); + */ +#define bsg_bf_get_le32(name, ptr) \ + ((le32_to_cpu((ptr)->name##_WORD) >> name##_SHIFT) & name##_MASK) +#define bsg_bf_get(name, ptr) \ + (((ptr)->name##_WORD >> name##_SHIFT) & name##_MASK) +#define bsg_bf_set_le32(name, ptr, value) \ + ((ptr)->name##_WORD = cpu_to_le32(((((value) & \ + name##_MASK) << name##_SHIFT) | (le32_to_cpu((ptr)->name##_WORD) & \ + ~(name##_MASK << name##_SHIFT))))) +#define bsg_bf_set(name, ptr, value) \ + ((ptr)->name##_WORD = ((((value) & name##_MASK) << name##_SHIFT) | \ + ((ptr)->name##_WORD & ~(name##_MASK << name##_SHIFT)))) + +/* + * The sli_config structure specified here is based on the following + * restriction: + * + * -- SLI_CONFIG EMB=0, carrying MSEs, will carry subcommands without + * carrying HBD. + * -- SLI_CONFIG EMB=1, not carrying MSE, will carry subcommands with or + * without carrying HBDs. + */ + +struct lpfc_sli_config_mse { + uint32_t pa_lo; + uint32_t pa_hi; + uint32_t buf_len; +#define lpfc_mbox_sli_config_mse_len_SHIFT 0 +#define lpfc_mbox_sli_config_mse_len_MASK 0xffffff +#define lpfc_mbox_sli_config_mse_len_WORD buf_len +}; + +struct lpfc_sli_config_subcmd_hbd { + uint32_t buf_len; +#define lpfc_mbox_sli_config_ecmn_hbd_len_SHIFT 0 +#define lpfc_mbox_sli_config_ecmn_hbd_len_MASK 0xffffff +#define lpfc_mbox_sli_config_ecmn_hbd_len_WORD buf_len + uint32_t pa_lo; + uint32_t pa_hi; +}; + +struct lpfc_sli_config_hdr { + uint32_t word1; +#define lpfc_mbox_hdr_emb_SHIFT 0 +#define lpfc_mbox_hdr_emb_MASK 0x00000001 +#define lpfc_mbox_hdr_emb_WORD word1 +#define lpfc_mbox_hdr_mse_cnt_SHIFT 3 +#define lpfc_mbox_hdr_mse_cnt_MASK 0x0000001f +#define lpfc_mbox_hdr_mse_cnt_WORD word1 + uint32_t payload_length; + uint32_t tag_lo; + uint32_t tag_hi; + uint32_t reserved5; +}; + +struct lpfc_sli_config_generic { + struct lpfc_sli_config_hdr sli_config_hdr; +#define LPFC_MBX_SLI_CONFIG_MAX_MSE 19 + struct lpfc_sli_config_mse mse[LPFC_MBX_SLI_CONFIG_MAX_MSE]; +}; + +struct lpfc_sli_config_subcmnd { + struct lpfc_sli_config_hdr sli_config_hdr; + uint32_t word6; +#define lpfc_subcmnd_opcode_SHIFT 0 +#define lpfc_subcmnd_opcode_MASK 0xff +#define lpfc_subcmnd_opcode_WORD word6 +#define lpfc_subcmnd_subsys_SHIFT 8 +#define lpfc_subcmnd_subsys_MASK 0xff +#define lpfc_subcmnd_subsys_WORD word6 + uint32_t timeout; + uint32_t request_length; + uint32_t word9; +#define lpfc_subcmnd_version_SHIFT 0 +#define lpfc_subcmnd_version_MASK 0xff +#define lpfc_subcmnd_version_WORD word9 + uint32_t word10; +#define lpfc_subcmnd_ask_rd_len_SHIFT 0 +#define lpfc_subcmnd_ask_rd_len_MASK 0xffffff +#define lpfc_subcmnd_ask_rd_len_WORD word10 + uint32_t rd_offset; + uint32_t obj_name[26]; + uint32_t hbd_count; +#define LPFC_MBX_SLI_CONFIG_MAX_HBD 10 + struct lpfc_sli_config_subcmd_hbd hbd[LPFC_MBX_SLI_CONFIG_MAX_HBD]; +}; + +struct lpfc_sli_config_mbox { + uint32_t word0; +#define lpfc_mqe_status_SHIFT 16 +#define lpfc_mqe_status_MASK 0x0000FFFF +#define lpfc_mqe_status_WORD word0 +#define lpfc_mqe_command_SHIFT 8 +#define lpfc_mqe_command_MASK 0x000000FF +#define lpfc_mqe_command_WORD word0 + union { + struct lpfc_sli_config_generic sli_config_generic; + struct lpfc_sli_config_subcmnd sli_config_subcmnd; + } un; +}; -- cgit v0.10.2 From b413f498e12faaf5912de89e7ac7e882956e0b0a Mon Sep 17 00:00:00 2001 From: James Smart Date: Sat, 16 Apr 2011 11:03:52 -0400 Subject: [SCSI] lpfc 8.3.23: Update driver version to 8.3.23 Update driver version to 8.3.22 Signed-off-by: Alex Iannicelli Signed-off-by: James Smart Signed-off-by: James Bottomley diff --git a/drivers/scsi/lpfc/lpfc_version.h b/drivers/scsi/lpfc/lpfc_version.h index 2404d1d..c03921b 100644 --- a/drivers/scsi/lpfc/lpfc_version.h +++ b/drivers/scsi/lpfc/lpfc_version.h @@ -18,7 +18,7 @@ * included with this package. * *******************************************************************/ -#define LPFC_DRIVER_VERSION "8.3.22" +#define LPFC_DRIVER_VERSION "8.3.23" #define LPFC_DRIVER_NAME "lpfc" #define LPFC_SP_DRIVER_HANDLER_NAME "lpfc:sp" #define LPFC_FP_DRIVER_HANDLER_NAME "lpfc:fp" -- cgit v0.10.2 From a6e5e2be44616c8400f9ec2f635b10f8e579217c Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Sun, 1 May 2011 18:18:49 +0200 Subject: i2c-i801: Move device ID definitions to driver Move the SMBus device ID definitions of recent devices from pci_ids.h to the i2c-i801.c driver file. They don't have to be shared, as they are clearly identified and only used in this driver. In the future, such IDs will go to i2c-i801 directly. This will make adding support for new devices much faster and easier, as it will avoid cross- subsystem patch sets and merge conflicts. Signed-off-by: Jean Delvare Cc: Seth Heasley Acked-by: Jesse Barnes diff --git a/drivers/i2c/busses/i2c-i801.c b/drivers/i2c/busses/i2c-i801.c index 72c0415f..455e909 100644 --- a/drivers/i2c/busses/i2c-i801.c +++ b/drivers/i2c/busses/i2c-i801.c @@ -134,10 +134,15 @@ SMBHSTSTS_BUS_ERR | SMBHSTSTS_DEV_ERR | \ SMBHSTSTS_INTR) +/* Older devices have their ID defined in */ +#define PCI_DEVICE_ID_INTEL_COUGARPOINT_SMBUS 0x1c22 +#define PCI_DEVICE_ID_INTEL_PATSBURG_SMBUS 0x1d22 /* Patsburg also has three 'Integrated Device Function' SMBus controllers */ #define PCI_DEVICE_ID_INTEL_PATSBURG_SMBUS_IDF0 0x1d70 #define PCI_DEVICE_ID_INTEL_PATSBURG_SMBUS_IDF1 0x1d71 #define PCI_DEVICE_ID_INTEL_PATSBURG_SMBUS_IDF2 0x1d72 +#define PCI_DEVICE_ID_INTEL_DH89XXCC_SMBUS 0x2330 +#define PCI_DEVICE_ID_INTEL_5_3400_SERIES_SMBUS 0x3b30 struct i801_priv { struct i2c_adapter adapter; diff --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h index 4e2c915..8abe8d7 100644 --- a/include/linux/pci_ids.h +++ b/include/linux/pci_ids.h @@ -2477,15 +2477,12 @@ #define PCI_DEVICE_ID_INTEL_82840_HB 0x1a21 #define PCI_DEVICE_ID_INTEL_82845_HB 0x1a30 #define PCI_DEVICE_ID_INTEL_IOAT 0x1a38 -#define PCI_DEVICE_ID_INTEL_COUGARPOINT_SMBUS 0x1c22 #define PCI_DEVICE_ID_INTEL_COUGARPOINT_LPC_MIN 0x1c41 #define PCI_DEVICE_ID_INTEL_COUGARPOINT_LPC_MAX 0x1c5f -#define PCI_DEVICE_ID_INTEL_PATSBURG_SMBUS 0x1d22 #define PCI_DEVICE_ID_INTEL_PATSBURG_LPC_0 0x1d40 #define PCI_DEVICE_ID_INTEL_PATSBURG_LPC_1 0x1d41 #define PCI_DEVICE_ID_INTEL_DH89XXCC_LPC_MIN 0x2310 #define PCI_DEVICE_ID_INTEL_DH89XXCC_LPC_MAX 0x231f -#define PCI_DEVICE_ID_INTEL_DH89XXCC_SMBUS 0x2330 #define PCI_DEVICE_ID_INTEL_82801AA_0 0x2410 #define PCI_DEVICE_ID_INTEL_82801AA_1 0x2411 #define PCI_DEVICE_ID_INTEL_82801AA_3 0x2413 @@ -2696,7 +2693,6 @@ #define PCI_DEVICE_ID_INTEL_ICH10_5 0x3a60 #define PCI_DEVICE_ID_INTEL_5_3400_SERIES_LPC_MIN 0x3b00 #define PCI_DEVICE_ID_INTEL_5_3400_SERIES_LPC_MAX 0x3b1f -#define PCI_DEVICE_ID_INTEL_5_3400_SERIES_SMBUS 0x3b30 #define PCI_DEVICE_ID_INTEL_IOAT_SNB 0x402f #define PCI_DEVICE_ID_INTEL_5100_16 0x65f0 #define PCI_DEVICE_ID_INTEL_5100_21 0x65f5 -- cgit v0.10.2 From 56acc7a39ac4ac7638cdc32cd3d0832ebbc834e4 Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Sun, 1 May 2011 18:18:49 +0200 Subject: i2c-parport: Fix adapter list handling Use a standard list with proper locking to handle the list of adapters. Thankfully it only matters on systems with more than one parallel port, which are very rare. Thanks to Lukasz Kapiec for reporting the problem to me. Signed-off-by: Jean Delvare Cc: stable@kernel.org diff --git a/drivers/i2c/busses/i2c-parport.c b/drivers/i2c/busses/i2c-parport.c index 0eb1515..2dbba16 100644 --- a/drivers/i2c/busses/i2c-parport.c +++ b/drivers/i2c/busses/i2c-parport.c @@ -1,7 +1,7 @@ /* ------------------------------------------------------------------------ * * i2c-parport.c I2C bus over parallel port * * ------------------------------------------------------------------------ * - Copyright (C) 2003-2010 Jean Delvare + Copyright (C) 2003-2011 Jean Delvare Based on older i2c-philips-par.c driver Copyright (C) 1995-2000 Simon G. Vogl @@ -33,6 +33,8 @@ #include #include #include +#include +#include #include "i2c-parport.h" /* ----- Device list ------------------------------------------------------ */ @@ -43,10 +45,11 @@ struct i2c_par { struct i2c_algo_bit_data algo_data; struct i2c_smbus_alert_setup alert_data; struct i2c_client *ara; - struct i2c_par *next; + struct list_head node; }; -static struct i2c_par *adapter_list; +static LIST_HEAD(adapter_list); +static DEFINE_MUTEX(adapter_list_lock); /* ----- Low-level parallel port access ----------------------------------- */ @@ -228,8 +231,9 @@ static void i2c_parport_attach (struct parport *port) } /* Add the new adapter to the list */ - adapter->next = adapter_list; - adapter_list = adapter; + mutex_lock(&adapter_list_lock); + list_add_tail(&adapter->node, &adapter_list); + mutex_unlock(&adapter_list_lock); return; ERROR1: @@ -241,11 +245,11 @@ ERROR0: static void i2c_parport_detach (struct parport *port) { - struct i2c_par *adapter, *prev; + struct i2c_par *adapter, *_n; /* Walk the list */ - for (prev = NULL, adapter = adapter_list; adapter; - prev = adapter, adapter = adapter->next) { + mutex_lock(&adapter_list_lock); + list_for_each_entry_safe(adapter, _n, &adapter_list, node) { if (adapter->pdev->port == port) { if (adapter->ara) { parport_disable_irq(port); @@ -259,14 +263,11 @@ static void i2c_parport_detach (struct parport *port) parport_release(adapter->pdev); parport_unregister_device(adapter->pdev); - if (prev) - prev->next = adapter->next; - else - adapter_list = adapter->next; + list_del(&adapter->node); kfree(adapter); - return; } } + mutex_unlock(&adapter_list_lock); } static struct parport_driver i2c_parport_driver = { -- cgit v0.10.2 From 112f661d6dac9af1235d2d05299fc2c9cb876ae7 Mon Sep 17 00:00:00 2001 From: Nithin Nayak Sujir Date: Mon, 25 Apr 2011 12:30:06 -0700 Subject: [SCSI] scsi_transport_fc: Fix deadlock during fc_remove_host Creating and destroying fcoe interface in a tight loop leads to a system deadlock with the following call traces: Call Trace: [] schedule_timeout+0x1fd/0x2c0 [] ? wait_for_common+0x4f/0x190 [] ? wait_for_common+0x4f/0x190 [] wait_for_common+0xe7/0x190 [] ? default_wake_function+0x0/0x20 [] ? trace_hardirqs_on+0xd/0x10 [] wait_for_completion+0x1d/0x20 [] flush_workqueue+0x290/0x5f0 [] ? flush_workqueue+0x0/0x5f0 [] destroy_workqueue+0x38/0x340 [] fc_remove_host+0x1b9/0x1f0 [scsi_transport_fc] [] bnx2fc_if_destroy+0xc5/0x1f0 [bnx2fc] [] bnx2fc_destroy+0x7a/0x100 [bnx2fc] [] fcoe_transport_destroy+0x9b/0x1b0 [libfcoe] [] param_attr_store+0x52/0x80 [] module_attr_store+0x26/0x30 [] sysfs_write_file+0xe6/0x170 [] vfs_write+0xd0/0x1a0 [] sys_write+0x54/0xa0 [] system_call_fastpath+0x16/0x1b Call Trace: [] async_synchronize_cookie_domain+0x75/0x120 [] ? autoremove_wake_function+0x0/0x40 [] async_synchronize_cookie+0x15/0x20 [] async_synchronize_full+0x1c/0x40 [] sd_remove+0x36/0xc0 [sd_mod] [] __device_release_driver+0x75/0xe0 [] device_release_driver+0x2f/0x50 [] bus_remove_device+0xbe/0x120 [] device_del+0x12f/0x1e0 [] __scsi_remove_device+0xbd/0xc0 [] scsi_remove_device+0x35/0x50 [] __scsi_remove_target+0xe7/0x110 [] ? __remove_child+0x0/0x30 [] __remove_child+0x23/0x30 [] device_for_each_child+0x4c/0x80 [] scsi_remove_target+0x33/0x60 [] fc_starget_delete+0x26/0x30 [scsi_transport_fc] [] fc_rport_final_delete+0xaa/0x200 [scsi_transport_fc] [] process_one_work+0x1aa/0x540 [] ? process_one_work+0x13b/0x540 [] ? fc_rport_final_delete+0x0/0x200 [scsi_transport_fc] [] worker_thread+0x179/0x410 [] ? worker_thread+0x0/0x410 [] kthread+0xb6/0xc0 [] ? finish_task_switch+0x4b/0xe0 [] kernel_thread_helper+0x4/0x10 [] ? restore_args+0x0/0x30 [] ? kthread+0x0/0xc0 [] ? kernel_thread_helper+0x0/0x10 fc_remove_host() waits for flushing the workqueue, but it is stuck at flushing the first work. The first work doesnt complete, because it is waiting for async layer to complete the IOs. The async layer cannot complete the IO as the terminate_rport_io for the second work was not called, which will be called only when the first work completes. Hence the deadlock. To resolve this deadlock, the workqueue allocation has been modified from create_singlethread_workqueue() to alloc_workqueue(). In addition, fc_terminate_rport_io() should be called before the scsi_flush_work() to avoid the similar deadlock as above. scsi fc alloc queue. move terminate rport io before flush Signed-off-by: Nithin Nayak Sujir Signed-off-by: Bhanu Prakash Gollapudi Signed-off-by: James Bottomley diff --git a/drivers/scsi/scsi_transport_fc.c b/drivers/scsi/scsi_transport_fc.c index fdf3fa6..358dff6 100644 --- a/drivers/scsi/scsi_transport_fc.c +++ b/drivers/scsi/scsi_transport_fc.c @@ -422,8 +422,7 @@ static int fc_host_setup(struct transport_container *tc, struct device *dev, snprintf(fc_host->work_q_name, sizeof(fc_host->work_q_name), "fc_wq_%d", shost->host_no); - fc_host->work_q = create_singlethread_workqueue( - fc_host->work_q_name); + fc_host->work_q = alloc_workqueue(fc_host->work_q_name, 0, 0); if (!fc_host->work_q) return -ENOMEM; @@ -431,8 +430,8 @@ static int fc_host_setup(struct transport_container *tc, struct device *dev, snprintf(fc_host->devloss_work_q_name, sizeof(fc_host->devloss_work_q_name), "fc_dl_%d", shost->host_no); - fc_host->devloss_work_q = create_singlethread_workqueue( - fc_host->devloss_work_q_name); + fc_host->devloss_work_q = + alloc_workqueue(fc_host->devloss_work_q_name, 0, 0); if (!fc_host->devloss_work_q) { destroy_workqueue(fc_host->work_q); fc_host->work_q = NULL; @@ -2489,6 +2488,8 @@ fc_rport_final_delete(struct work_struct *work) unsigned long flags; int do_callback = 0; + fc_terminate_rport_io(rport); + /* * if a scan is pending, flush the SCSI Host work_q so that * that we can reclaim the rport scan work element. @@ -2496,8 +2497,6 @@ fc_rport_final_delete(struct work_struct *work) if (rport->flags & FC_RPORT_SCAN_PENDING) scsi_flush_work(shost); - fc_terminate_rport_io(rport); - /* * Cancel any outstanding timers. These should really exist * only when rmmod'ing the LLDD and we're asking for -- cgit v0.10.2 From 0117ddb0c8df8e107bc8e9713c6638270638fff9 Mon Sep 17 00:00:00 2001 From: Nithin Nayak Sujir Date: Mon, 25 Apr 2011 12:30:07 -0700 Subject: [SCSI] bnx2fc: Release the reference to hba only after the interface is destroyed Prematurely decrementing the reference may lead to cmd_mgr becoming NULL with the cmds are still active. Signed-off-by: Nithin Nayak Sujir Signed-off-by: Bhanu Prakash Gollapudi Signed-off-by: James Bottomley diff --git a/drivers/scsi/bnx2fc/bnx2fc_fcoe.c b/drivers/scsi/bnx2fc/bnx2fc_fcoe.c index e2e6475..b936aee 100644 --- a/drivers/scsi/bnx2fc/bnx2fc_fcoe.c +++ b/drivers/scsi/bnx2fc/bnx2fc_fcoe.c @@ -1352,8 +1352,6 @@ static void bnx2fc_if_destroy(struct fc_lport *lport) /* Free existing transmit skbs */ fcoe_clean_pending_queue(lport); - bnx2fc_interface_put(hba); - /* Free queued packets for the receive thread */ bnx2fc_clean_rx_queue(lport); @@ -1372,6 +1370,8 @@ static void bnx2fc_if_destroy(struct fc_lport *lport) /* Release Scsi_Host */ scsi_host_put(lport->host); + + bnx2fc_interface_put(hba); } /** -- cgit v0.10.2 From 35dd71ae82afaef3980638c528b21f018c46211a Mon Sep 17 00:00:00 2001 From: Nithin Nayak Sujir Date: Mon, 25 Apr 2011 12:30:08 -0700 Subject: [SCSI] bnx2fc: call scsi_done if session goes to not ready from ready If the session is not ready yet, we ask the SCSI-ml to retry. However, if the session is just uploaded, we should not retry, but instead call scsi_done to fail the IO. Signed-off-by: Nithin Nayak Sujir Signed-off-by: Bhanu Prakash Gollapudi Signed-off-by: James Bottomley diff --git a/drivers/scsi/bnx2fc/bnx2fc_io.c b/drivers/scsi/bnx2fc/bnx2fc_io.c index 1decefb..b5b5c34 100644 --- a/drivers/scsi/bnx2fc/bnx2fc_io.c +++ b/drivers/scsi/bnx2fc/bnx2fc_io.c @@ -1663,6 +1663,12 @@ int bnx2fc_queuecommand(struct Scsi_Host *host, tgt = (struct bnx2fc_rport *)&rp[1]; if (!test_bit(BNX2FC_FLAG_SESSION_READY, &tgt->flags)) { + if (test_bit(BNX2FC_FLAG_UPLD_REQ_COMPL, &tgt->flags)) { + sc_cmd->result = DID_NO_CONNECT << 16; + sc_cmd->scsi_done(sc_cmd); + return 0; + + } /* * Session is not offloaded yet. Let SCSI-ml retry * the command. -- cgit v0.10.2 From 068bdce41297b69e75f72a029d42e70c282273f6 Mon Sep 17 00:00:00 2001 From: Nithin Nayak Sujir Date: Mon, 25 Apr 2011 12:30:09 -0700 Subject: [SCSI] bnx2fc: Do not use HBA_DBG macro when lport is not available Use MISC_DBG instead. Signed-off-by: Nithin Nayak Sujir Signed-off-by: Bhanu Prakash Gollapudi Signed-off-by: James Bottomley diff --git a/drivers/scsi/bnx2fc/bnx2fc_fcoe.c b/drivers/scsi/bnx2fc/bnx2fc_fcoe.c index b936aee..139955a 100644 --- a/drivers/scsi/bnx2fc/bnx2fc_fcoe.c +++ b/drivers/scsi/bnx2fc/bnx2fc_fcoe.c @@ -1130,7 +1130,7 @@ static void bnx2fc_interface_release(struct kref *kref) struct net_device *phys_dev; hba = container_of(kref, struct bnx2fc_hba, kref); - BNX2FC_HBA_DBG(hba->ctlr.lp, "Interface is being released\n"); + BNX2FC_MISC_DBG("Interface is being released\n"); netdev = hba->netdev; phys_dev = hba->phys_dev; -- cgit v0.10.2 From befc9b4dda55a146f3e7e1d00abcb4a18fd75887 Mon Sep 17 00:00:00 2001 From: Nithin Nayak Sujir Date: Mon, 25 Apr 2011 12:30:10 -0700 Subject: [SCSI] bnx2fc: increase cleanup wait time FW may take more time cleaning up IOs issued to multiple targets. Signed-off-by: Nithin Nayak Sujir Signed-off-by: Bhanu Prakash Gollapudi Signed-off-by: James Bottomley diff --git a/drivers/scsi/bnx2fc/bnx2fc.h b/drivers/scsi/bnx2fc/bnx2fc.h index b6d350a..0a404bf 100644 --- a/drivers/scsi/bnx2fc/bnx2fc.h +++ b/drivers/scsi/bnx2fc/bnx2fc.h @@ -130,7 +130,7 @@ #define BNX2FC_TM_TIMEOUT 60 /* secs */ #define BNX2FC_IO_TIMEOUT 20000UL /* msecs */ -#define BNX2FC_WAIT_CNT 120 +#define BNX2FC_WAIT_CNT 1200 #define BNX2FC_FW_TIMEOUT (3 * HZ) #define PORT_MAX 2 -- cgit v0.10.2 From 56cee8d57744ec5782e3a8722c1bc45951d2c037 Mon Sep 17 00:00:00 2001 From: "Kashyap, Desai" Date: Tue, 26 Apr 2011 12:09:15 +0530 Subject: [SCSI] mptfusion: Remove debug print from mptscsih_qcmd() Remove debug print from mptscsih_qcmd function call. This debug print cause flood of prints and difficult to debug other issues. Signed-off-by: Kashyap Desai Signed-off-by: James Bottomley diff --git a/drivers/message/fusion/mptscsih.c b/drivers/message/fusion/mptscsih.c index b871ab3..a1d4ee6 100644 --- a/drivers/message/fusion/mptscsih.c +++ b/drivers/message/fusion/mptscsih.c @@ -1415,11 +1415,8 @@ mptscsih_qcmd(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *)) dmfprintk(ioc, printk(MYIOC_s_DEBUG_FMT "qcmd: SCpnt=%p, done()=%p\n", ioc->name, SCpnt, done)); - if (ioc->taskmgmt_quiesce_io) { - dtmprintk(ioc, printk(MYIOC_s_WARN_FMT "qcmd: SCpnt=%p timeout + 60HZ\n", - ioc->name, SCpnt)); + if (ioc->taskmgmt_quiesce_io) return SCSI_MLQUEUE_HOST_BUSY; - } /* * Put together a MPT SCSI request... -- cgit v0.10.2 From e20a2d205c05cef6b5783df339a7d54adeb50962 Mon Sep 17 00:00:00 2001 From: Boris Ostrovsky Date: Fri, 29 Apr 2011 17:47:43 -0400 Subject: x86, AMD: Fix APIC timer erratum 400 affecting K8 Rev.A-E processors Older AMD K8 processors (Revisions A-E) are affected by erratum 400 (APIC timer interrupts don't occur in C states greater than C1). This, for example, means that X86_FEATURE_ARAT flag should not be set for these parts. This addresses regression introduced by commit b87cf80af3ba4b4c008b4face3c68d604e1715c6 ("x86, AMD: Set ARAT feature on AMD processors") where the system may become unresponsive until external interrupt (such as keyboard input) occurs. This results, for example, in time not being reported correctly, lack of progress on the system and other lockups. Reported-by: Joerg-Volker Peetz Tested-by: Joerg-Volker Peetz Acked-by: Borislav Petkov Signed-off-by: Boris Ostrovsky Cc: stable@kernel.org Link: http://lkml.kernel.org/r/1304113663-6586-1-git-send-email-ostr@amd64.org Signed-off-by: Ingo Molnar diff --git a/arch/x86/kernel/cpu/amd.c b/arch/x86/kernel/cpu/amd.c index 3532d3b..bb9eb29 100644 --- a/arch/x86/kernel/cpu/amd.c +++ b/arch/x86/kernel/cpu/amd.c @@ -698,7 +698,7 @@ cpu_dev_register(amd_cpu_dev); */ const int amd_erratum_400[] = - AMD_OSVW_ERRATUM(1, AMD_MODEL_RANGE(0xf, 0x41, 0x2, 0xff, 0xf), + AMD_OSVW_ERRATUM(1, AMD_MODEL_RANGE(0x0f, 0x4, 0x2, 0xff, 0xf), AMD_MODEL_RANGE(0x10, 0x2, 0x1, 0xff, 0xf)); EXPORT_SYMBOL_GPL(amd_erratum_400); -- cgit v0.10.2 From 19fff154e7ee35d1297eb27d7d41e6f8742101ec Mon Sep 17 00:00:00 2001 From: "Kashyap, Desai" Date: Tue, 26 Apr 2011 12:09:46 +0530 Subject: [SCSI] mptfusion: Adding inline data padding support for TAPE drive. Adding support for inline data padding for TAPE drive when running U320. [jejb: whitespace fixes] Signed-off-by: Kashyap Desai Signed-off-by: James Bottomley diff --git a/drivers/message/fusion/mptspi.c b/drivers/message/fusion/mptspi.c index 6d9568d..8f61ba6 100644 --- a/drivers/message/fusion/mptspi.c +++ b/drivers/message/fusion/mptspi.c @@ -867,6 +867,10 @@ static int mptspi_write_spi_device_pg1(struct scsi_target *starget, struct _x_config_parms cfg; struct _CONFIG_PAGE_HEADER hdr; int err = -EBUSY; + u32 nego_parms; + u32 period; + struct scsi_device *sdev; + int i; /* don't allow updating nego parameters on RAID devices */ if (starget->channel == 0 && @@ -904,6 +908,24 @@ static int mptspi_write_spi_device_pg1(struct scsi_target *starget, pg1->Header.PageNumber = hdr.PageNumber; pg1->Header.PageType = hdr.PageType; + nego_parms = le32_to_cpu(pg1->RequestedParameters); + period = (nego_parms & MPI_SCSIDEVPAGE1_RP_MIN_SYNC_PERIOD_MASK) >> + MPI_SCSIDEVPAGE1_RP_SHIFT_MIN_SYNC_PERIOD; + if (period == 8) { + /* Turn on inline data padding for TAPE when running U320 */ + for (i = 0 ; i < 16; i++) { + sdev = scsi_device_lookup_by_target(starget, i); + if (sdev && sdev->type == TYPE_TAPE) { + sdev_printk(KERN_DEBUG, sdev, MYIOC_s_FMT + "IDP:ON\n", ioc->name); + nego_parms |= MPI_SCSIDEVPAGE1_RP_IDP; + pg1->RequestedParameters = + cpu_to_le32(nego_parms); + break; + } + } + } + mptspi_print_write_nego(hd, starget, le32_to_cpu(pg1->RequestedParameters)); if (mpt_config(ioc, &cfg)) { -- cgit v0.10.2 From cbc78ae73bcab6b3277977a6a30e74d1be3cedfa Mon Sep 17 00:00:00 2001 From: "Kashyap, Desai" Date: Tue, 26 Apr 2011 12:10:08 +0530 Subject: [SCSI] mptfusion: Bump version 3.4.19 Signed-off-by: Kashyap Desai Signed-off-by: James Bottomley diff --git a/drivers/message/fusion/mptbase.h b/drivers/message/fusion/mptbase.h index 1735c84..fe90233 100644 --- a/drivers/message/fusion/mptbase.h +++ b/drivers/message/fusion/mptbase.h @@ -76,8 +76,8 @@ #define COPYRIGHT "Copyright (c) 1999-2008 " MODULEAUTHOR #endif -#define MPT_LINUX_VERSION_COMMON "3.04.18" -#define MPT_LINUX_PACKAGE_NAME "@(#)mptlinux-3.04.18" +#define MPT_LINUX_VERSION_COMMON "3.04.19" +#define MPT_LINUX_PACKAGE_NAME "@(#)mptlinux-3.04.19" #define WHAT_MAGIC_STRING "@" "(" "#" ")" #define show_mptmod_ver(s,ver) \ -- cgit v0.10.2 From c0d289b3e59577532c45ee9110ef81bd7b341272 Mon Sep 17 00:00:00 2001 From: Martin George Date: Tue, 26 Apr 2011 18:27:05 +0530 Subject: [SCSI] scsi_dh_alua: Attach to UNAVAILABLE/OFFLINE AAS devices The SCSI ALUA handler currently fails to attach to devices reporting an UNAVAILABLE/OFFLINE AAS. But given that an UNAVAILABLE/OFFLINE AAS can transition to other states like ACTIVE/OPTIMIZED, ACTIVE/NON-OPTIMIZED, etc. as per SPC4, this ALUA handler behavior should be rectified so as to attach to devices which also report an UNAVAILABLE/OFFLINE AAS. Signed-off-by: Martin George Reviewed-by: Mike Christie Signed-off-by: James Bottomley diff --git a/drivers/scsi/device_handler/scsi_dh_alua.c b/drivers/scsi/device_handler/scsi_dh_alua.c index 42fe529..6fec9fe 100644 --- a/drivers/scsi/device_handler/scsi_dh_alua.c +++ b/drivers/scsi/device_handler/scsi_dh_alua.c @@ -782,7 +782,7 @@ static int alua_bus_attach(struct scsi_device *sdev) h->sdev = sdev; err = alua_initialize(sdev, h); - if (err != SCSI_DH_OK) + if ((err != SCSI_DH_OK) && (err != SCSI_DH_DEV_OFFLINED)) goto failed; if (!try_module_get(THIS_MODULE)) -- cgit v0.10.2 From 8214028344b4a38aabf73d95347e1e35538c75f6 Mon Sep 17 00:00:00 2001 From: Xiangliang Yu Date: Tue, 26 Apr 2011 06:34:01 -0700 Subject: [SCSI] mvsas: add support for Marvell 88SE9445/88SE9485 This is support for Marvell 88SE9445/88SE9485 SAS/SATA HBA, which is based on Marvell 88SE9480. Signed-off-by: Xiangliang Yu Signed-off-by: James Bottomley diff --git a/drivers/scsi/mvsas/mv_defs.h b/drivers/scsi/mvsas/mv_defs.h index 1849da1..880613f 100644 --- a/drivers/scsi/mvsas/mv_defs.h +++ b/drivers/scsi/mvsas/mv_defs.h @@ -34,6 +34,8 @@ enum chip_flavors { chip_6485, chip_9480, chip_9180, + chip_9445, + chip_9485, chip_1300, chip_1320 }; diff --git a/drivers/scsi/mvsas/mv_init.c b/drivers/scsi/mvsas/mv_init.c index 938d045..0123c6b 100644 --- a/drivers/scsi/mvsas/mv_init.c +++ b/drivers/scsi/mvsas/mv_init.c @@ -32,6 +32,8 @@ static const struct mvs_chip_info mvs_chips[] = { [chip_6485] = { 1, 8, 0x800, 33, 32, 10, &mvs_64xx_dispatch, }, [chip_9180] = { 2, 4, 0x800, 17, 64, 9, &mvs_94xx_dispatch, }, [chip_9480] = { 2, 4, 0x800, 17, 64, 9, &mvs_94xx_dispatch, }, + [chip_9445] = { 1, 4, 0x800, 17, 64, 11, &mvs_94xx_dispatch, }, + [chip_9485] = { 2, 4, 0x800, 17, 64, 11, &mvs_94xx_dispatch, }, [chip_1300] = { 1, 4, 0x400, 17, 16, 9, &mvs_64xx_dispatch, }, [chip_1320] = { 2, 4, 0x800, 17, 64, 9, &mvs_94xx_dispatch, }, }; @@ -670,6 +672,24 @@ static struct pci_device_id __devinitdata mvs_pci_table[] = { { PCI_VDEVICE(TTI, 0x2740), chip_9480 }, { PCI_VDEVICE(TTI, 0x2744), chip_9480 }, { PCI_VDEVICE(TTI, 0x2760), chip_9480 }, + { + .vendor = 0x1b4b, + .device = 0x9445, + .subvendor = PCI_ANY_ID, + .subdevice = 0x9480, + .class = 0, + .class_mask = 0, + .driver_data = chip_9445, + }, + { + .vendor = 0x1b4b, + .device = 0x9485, + .subvendor = PCI_ANY_ID, + .subdevice = 0x9480, + .class = 0, + .class_mask = 0, + .driver_data = chip_9485, + }, { } /* terminate list */ }; -- cgit v0.10.2 From 0b15fb1fdfd403726542cb6111bc916b7a9f7fad Mon Sep 17 00:00:00 2001 From: Xiangliang Yu Date: Tue, 26 Apr 2011 06:36:51 -0700 Subject: [SCSI] mvsas: add support for Task collector mode and fixed relative bugs 1. Add support for Task collector mode. 2. Fixed relative collector mode bug: - I/O failed when disks is on two ports - system hang when hotplug disk - system hang when unplug disk during run IO 3. Unlock ap->lock within .lldd_execute_task for direct mode to improve performance Signed-off-by: Xiangliang Yu Signed-off-by: James Bottomley diff --git a/drivers/scsi/mvsas/Kconfig b/drivers/scsi/mvsas/Kconfig index 6de7af2..c82b012 100644 --- a/drivers/scsi/mvsas/Kconfig +++ b/drivers/scsi/mvsas/Kconfig @@ -3,6 +3,7 @@ # # Copyright 2007 Red Hat, Inc. # Copyright 2008 Marvell. +# Copyright 2009-20011 Marvell. # # This file is licensed under GPLv2. # diff --git a/drivers/scsi/mvsas/Makefile b/drivers/scsi/mvsas/Makefile index ffbf759..87b231a 100644 --- a/drivers/scsi/mvsas/Makefile +++ b/drivers/scsi/mvsas/Makefile @@ -3,6 +3,7 @@ # # Copyright 2007 Red Hat, Inc. # Copyright 2008 Marvell. +# Copyright 2009-2011 Marvell. # # This file is licensed under GPLv2. # diff --git a/drivers/scsi/mvsas/mv_64xx.c b/drivers/scsi/mvsas/mv_64xx.c index afc7f6f..13c9604 100644 --- a/drivers/scsi/mvsas/mv_64xx.c +++ b/drivers/scsi/mvsas/mv_64xx.c @@ -3,6 +3,7 @@ * * Copyright 2007 Red Hat, Inc. * Copyright 2008 Marvell. + * Copyright 2009-2011 Marvell. * * This file is licensed under GPLv2. * diff --git a/drivers/scsi/mvsas/mv_64xx.h b/drivers/scsi/mvsas/mv_64xx.h index 42e947d..545889b 100644 --- a/drivers/scsi/mvsas/mv_64xx.h +++ b/drivers/scsi/mvsas/mv_64xx.h @@ -3,6 +3,7 @@ * * Copyright 2007 Red Hat, Inc. * Copyright 2008 Marvell. + * Copyright 2009-2011 Marvell. * * This file is licensed under GPLv2. * diff --git a/drivers/scsi/mvsas/mv_94xx.c b/drivers/scsi/mvsas/mv_94xx.c index eed4c5c..78162c3 100644 --- a/drivers/scsi/mvsas/mv_94xx.c +++ b/drivers/scsi/mvsas/mv_94xx.c @@ -3,6 +3,7 @@ * * Copyright 2007 Red Hat, Inc. * Copyright 2008 Marvell. + * Copyright 2009-2011 Marvell. * * This file is licensed under GPLv2. * diff --git a/drivers/scsi/mvsas/mv_94xx.h b/drivers/scsi/mvsas/mv_94xx.h index 23ed9b1..8835bef 100644 --- a/drivers/scsi/mvsas/mv_94xx.h +++ b/drivers/scsi/mvsas/mv_94xx.h @@ -3,6 +3,7 @@ * * Copyright 2007 Red Hat, Inc. * Copyright 2008 Marvell. + * Copyright 2009-2011 Marvell. * * This file is licensed under GPLv2. * diff --git a/drivers/scsi/mvsas/mv_chips.h b/drivers/scsi/mvsas/mv_chips.h index a67e1c4..1753a6f 100644 --- a/drivers/scsi/mvsas/mv_chips.h +++ b/drivers/scsi/mvsas/mv_chips.h @@ -3,6 +3,7 @@ * * Copyright 2007 Red Hat, Inc. * Copyright 2008 Marvell. + * Copyright 2009-2011 Marvell. * * This file is licensed under GPLv2. * diff --git a/drivers/scsi/mvsas/mv_defs.h b/drivers/scsi/mvsas/mv_defs.h index 880613f..bc00c94 100644 --- a/drivers/scsi/mvsas/mv_defs.h +++ b/drivers/scsi/mvsas/mv_defs.h @@ -3,6 +3,7 @@ * * Copyright 2007 Red Hat, Inc. * Copyright 2008 Marvell. + * Copyright 2009-2011 Marvell. * * This file is licensed under GPLv2. * diff --git a/drivers/scsi/mvsas/mv_init.c b/drivers/scsi/mvsas/mv_init.c index 0123c6b..90b6366 100644 --- a/drivers/scsi/mvsas/mv_init.c +++ b/drivers/scsi/mvsas/mv_init.c @@ -3,6 +3,7 @@ * * Copyright 2007 Red Hat, Inc. * Copyright 2008 Marvell. + * Copyright 2009-2011 Marvell. * * This file is licensed under GPLv2. * @@ -25,7 +26,16 @@ #include "mv_sas.h" +static int lldd_max_execute_num = 1; +module_param_named(collector, lldd_max_execute_num, int, S_IRUGO); +MODULE_PARM_DESC(collector, "\n" + "\tIf greater than one, tells the SAS Layer to run in Task Collector\n" + "\tMode. If 1 or 0, tells the SAS Layer to run in Direct Mode.\n" + "\tThe mvsas SAS LLDD supports both modes.\n" + "\tDefault: 1 (Direct Mode).\n"); + static struct scsi_transport_template *mvs_stt; +struct kmem_cache *mvs_task_list_cache; static const struct mvs_chip_info mvs_chips[] = { [chip_6320] = { 1, 2, 0x400, 17, 16, 9, &mvs_64xx_dispatch, }, [chip_6440] = { 1, 4, 0x400, 17, 16, 9, &mvs_64xx_dispatch, }, @@ -109,7 +119,6 @@ static void __devinit mvs_phy_init(struct mvs_info *mvi, int phy_id) static void mvs_free(struct mvs_info *mvi) { - int i; struct mvs_wq *mwq; int slot_nr; @@ -121,12 +130,8 @@ static void mvs_free(struct mvs_info *mvi) else slot_nr = MVS_SLOTS; - for (i = 0; i < mvi->tags_num; i++) { - struct mvs_slot_info *slot = &mvi->slot_info[i]; - if (slot->buf) - dma_free_coherent(mvi->dev, MVS_SLOT_BUF_SZ, - slot->buf, slot->buf_dma); - } + if (mvi->dma_pool) + pci_pool_destroy(mvi->dma_pool); if (mvi->tx) dma_free_coherent(mvi->dev, @@ -215,6 +220,7 @@ static irqreturn_t mvs_interrupt(int irq, void *opaque) static int __devinit mvs_alloc(struct mvs_info *mvi, struct Scsi_Host *shost) { int i = 0, slot_nr; + char pool_name[32]; if (mvi->flags & MVF_FLAG_SOC) slot_nr = MVS_SOC_SLOTS; @@ -274,18 +280,14 @@ static int __devinit mvs_alloc(struct mvs_info *mvi, struct Scsi_Host *shost) if (!mvi->bulk_buffer) goto err_out; #endif - for (i = 0; i < slot_nr; i++) { - struct mvs_slot_info *slot = &mvi->slot_info[i]; - - slot->buf = dma_alloc_coherent(mvi->dev, MVS_SLOT_BUF_SZ, - &slot->buf_dma, GFP_KERNEL); - if (!slot->buf) { - printk(KERN_DEBUG"failed to allocate slot->buf.\n"); + sprintf(pool_name, "%s%d", "mvs_dma_pool", mvi->id); + mvi->dma_pool = pci_pool_create(pool_name, mvi->pdev, MVS_SLOT_BUF_SZ, 16, 0); + if (!mvi->dma_pool) { + printk(KERN_DEBUG "failed to create dma pool %s.\n", pool_name); goto err_out; - } - memset(slot->buf, 0, MVS_SLOT_BUF_SZ); - ++mvi->tags_num; } + mvi->tags_num = slot_nr; + /* Initialize tags */ mvs_tag_init(mvi); return 0; @@ -486,7 +488,7 @@ static void __devinit mvs_post_sas_ha_init(struct Scsi_Host *shost, sha->num_phys = nr_core * chip_info->n_phy; - sha->lldd_max_execute_num = 1; + sha->lldd_max_execute_num = lldd_max_execute_num; if (mvi->flags & MVF_FLAG_SOC) can_queue = MVS_SOC_CAN_QUEUE; @@ -710,6 +712,14 @@ static int __init mvs_init(void) if (!mvs_stt) return -ENOMEM; + mvs_task_list_cache = kmem_cache_create("mvs_task_list", sizeof(struct mvs_task_list), + 0, SLAB_HWCACHE_ALIGN, NULL); + if (!mvs_task_list_cache) { + rc = -ENOMEM; + mv_printk("%s: mvs_task_list_cache alloc failed! \n", __func__); + goto err_out; + } + rc = pci_register_driver(&mvs_pci_driver); if (rc) @@ -726,6 +736,7 @@ static void __exit mvs_exit(void) { pci_unregister_driver(&mvs_pci_driver); sas_release_transport(mvs_stt); + kmem_cache_destroy(mvs_task_list_cache); } module_init(mvs_init); diff --git a/drivers/scsi/mvsas/mv_sas.c b/drivers/scsi/mvsas/mv_sas.c index adedaa9..0ef2742 100644 --- a/drivers/scsi/mvsas/mv_sas.c +++ b/drivers/scsi/mvsas/mv_sas.c @@ -3,6 +3,7 @@ * * Copyright 2007 Red Hat, Inc. * Copyright 2008 Marvell. + * Copyright 2009-2011 Marvell. * * This file is licensed under GPLv2. * @@ -862,178 +863,286 @@ static int mvs_task_prep_ssp(struct mvs_info *mvi, } #define DEV_IS_GONE(mvi_dev) ((!mvi_dev || (mvi_dev->dev_type == NO_DEVICE))) -static int mvs_task_exec(struct sas_task *task, const int num, gfp_t gfp_flags, - struct completion *completion,int is_tmf, - struct mvs_tmf_task *tmf) +static int mvs_task_prep(struct sas_task *task, struct mvs_info *mvi, int is_tmf, + struct mvs_tmf_task *tmf, int *pass) { struct domain_device *dev = task->dev; - struct mvs_device *mvi_dev = (struct mvs_device *)dev->lldd_dev; - struct mvs_info *mvi = mvi_dev->mvi_info; + struct mvs_device *mvi_dev = dev->lldd_dev; struct mvs_task_exec_info tei; - struct sas_task *t = task; struct mvs_slot_info *slot; - u32 tag = 0xdeadbeef, rc, n_elem = 0; - u32 n = num, pass = 0; - unsigned long flags = 0, flags_libsas = 0; + u32 tag = 0xdeadbeef, n_elem = 0; + int rc = 0; if (!dev->port) { - struct task_status_struct *tsm = &t->task_status; + struct task_status_struct *tsm = &task->task_status; tsm->resp = SAS_TASK_UNDELIVERED; tsm->stat = SAS_PHY_DOWN; + /* + * libsas will use dev->port, should + * not call task_done for sata + */ if (dev->dev_type != SATA_DEV) - t->task_done(t); - return 0; + task->task_done(task); + return rc; } - spin_lock_irqsave(&mvi->lock, flags); - do { - dev = t->dev; - mvi_dev = dev->lldd_dev; - if (DEV_IS_GONE(mvi_dev)) { - if (mvi_dev) - mv_dprintk("device %d not ready.\n", - mvi_dev->device_id); - else - mv_dprintk("device %016llx not ready.\n", - SAS_ADDR(dev->sas_addr)); + if (DEV_IS_GONE(mvi_dev)) { + if (mvi_dev) + mv_dprintk("device %d not ready.\n", + mvi_dev->device_id); + else + mv_dprintk("device %016llx not ready.\n", + SAS_ADDR(dev->sas_addr)); rc = SAS_PHY_DOWN; - goto out_done; - } + return rc; + } + tei.port = dev->port->lldd_port; + if (tei.port && !tei.port->port_attached && !tmf) { + if (sas_protocol_ata(task->task_proto)) { + struct task_status_struct *ts = &task->task_status; + mv_dprintk("SATA/STP port %d does not attach" + "device.\n", dev->port->id); + ts->resp = SAS_TASK_COMPLETE; + ts->stat = SAS_PHY_DOWN; - if (dev->port->id >= mvi->chip->n_phy) - tei.port = &mvi->port[dev->port->id - mvi->chip->n_phy]; - else - tei.port = &mvi->port[dev->port->id]; - - if (tei.port && !tei.port->port_attached) { - if (sas_protocol_ata(t->task_proto)) { - struct task_status_struct *ts = &t->task_status; - - mv_dprintk("port %d does not" - "attached device.\n", dev->port->id); - ts->stat = SAS_PROTO_RESPONSE; - ts->stat = SAS_PHY_DOWN; - spin_unlock_irqrestore(dev->sata_dev.ap->lock, - flags_libsas); - spin_unlock_irqrestore(&mvi->lock, flags); - t->task_done(t); - spin_lock_irqsave(&mvi->lock, flags); - spin_lock_irqsave(dev->sata_dev.ap->lock, - flags_libsas); - if (n > 1) - t = list_entry(t->list.next, - struct sas_task, list); - continue; - } else { - struct task_status_struct *ts = &t->task_status; - ts->resp = SAS_TASK_UNDELIVERED; - ts->stat = SAS_PHY_DOWN; - t->task_done(t); - if (n > 1) - t = list_entry(t->list.next, - struct sas_task, list); - continue; - } - } + task->task_done(task); - if (!sas_protocol_ata(t->task_proto)) { - if (t->num_scatter) { - n_elem = dma_map_sg(mvi->dev, - t->scatter, - t->num_scatter, - t->data_dir); - if (!n_elem) { - rc = -ENOMEM; - goto err_out; - } - } } else { - n_elem = t->num_scatter; + struct task_status_struct *ts = &task->task_status; + mv_dprintk("SAS port %d does not attach" + "device.\n", dev->port->id); + ts->resp = SAS_TASK_UNDELIVERED; + ts->stat = SAS_PHY_DOWN; + task->task_done(task); } + return rc; + } - rc = mvs_tag_alloc(mvi, &tag); - if (rc) - goto err_out; + if (!sas_protocol_ata(task->task_proto)) { + if (task->num_scatter) { + n_elem = dma_map_sg(mvi->dev, + task->scatter, + task->num_scatter, + task->data_dir); + if (!n_elem) { + rc = -ENOMEM; + goto prep_out; + } + } + } else { + n_elem = task->num_scatter; + } - slot = &mvi->slot_info[tag]; + rc = mvs_tag_alloc(mvi, &tag); + if (rc) + goto err_out; + slot = &mvi->slot_info[tag]; - t->lldd_task = NULL; - slot->n_elem = n_elem; - slot->slot_tag = tag; - memset(slot->buf, 0, MVS_SLOT_BUF_SZ); + task->lldd_task = NULL; + slot->n_elem = n_elem; + slot->slot_tag = tag; + + slot->buf = pci_pool_alloc(mvi->dma_pool, GFP_ATOMIC, &slot->buf_dma); + if (!slot->buf) + goto err_out_tag; + memset(slot->buf, 0, MVS_SLOT_BUF_SZ); + + tei.task = task; + tei.hdr = &mvi->slot[tag]; + tei.tag = tag; + tei.n_elem = n_elem; + switch (task->task_proto) { + case SAS_PROTOCOL_SMP: + rc = mvs_task_prep_smp(mvi, &tei); + break; + case SAS_PROTOCOL_SSP: + rc = mvs_task_prep_ssp(mvi, &tei, is_tmf, tmf); + break; + case SAS_PROTOCOL_SATA: + case SAS_PROTOCOL_STP: + case SAS_PROTOCOL_SATA | SAS_PROTOCOL_STP: + rc = mvs_task_prep_ata(mvi, &tei); + break; + default: + dev_printk(KERN_ERR, mvi->dev, + "unknown sas_task proto: 0x%x\n", + task->task_proto); + rc = -EINVAL; + break; + } - tei.task = t; - tei.hdr = &mvi->slot[tag]; - tei.tag = tag; - tei.n_elem = n_elem; - switch (t->task_proto) { - case SAS_PROTOCOL_SMP: - rc = mvs_task_prep_smp(mvi, &tei); - break; - case SAS_PROTOCOL_SSP: - rc = mvs_task_prep_ssp(mvi, &tei, is_tmf, tmf); - break; - case SAS_PROTOCOL_SATA: - case SAS_PROTOCOL_STP: - case SAS_PROTOCOL_SATA | SAS_PROTOCOL_STP: - rc = mvs_task_prep_ata(mvi, &tei); - break; - default: - dev_printk(KERN_ERR, mvi->dev, - "unknown sas_task proto: 0x%x\n", - t->task_proto); - rc = -EINVAL; - break; - } + if (rc) { + mv_dprintk("rc is %x\n", rc); + goto err_out_slot_buf; + } + slot->task = task; + slot->port = tei.port; + task->lldd_task = slot; + list_add_tail(&slot->entry, &tei.port->list); + spin_lock(&task->task_state_lock); + task->task_state_flags |= SAS_TASK_AT_INITIATOR; + spin_unlock(&task->task_state_lock); - if (rc) { - mv_dprintk("rc is %x\n", rc); - goto err_out_tag; - } - slot->task = t; - slot->port = tei.port; - t->lldd_task = slot; - list_add_tail(&slot->entry, &tei.port->list); - /* TODO: select normal or high priority */ - spin_lock(&t->task_state_lock); - t->task_state_flags |= SAS_TASK_AT_INITIATOR; - spin_unlock(&t->task_state_lock); - - mvs_hba_memory_dump(mvi, tag, t->task_proto); - mvi_dev->running_req++; - ++pass; - mvi->tx_prod = (mvi->tx_prod + 1) & (MVS_CHIP_SLOT_SZ - 1); - if (n > 1) - t = list_entry(t->list.next, struct sas_task, list); - if (likely(pass)) - MVS_CHIP_DISP->start_delivery(mvi, (mvi->tx_prod - 1) & - (MVS_CHIP_SLOT_SZ - 1)); + mvs_hba_memory_dump(mvi, tag, task->task_proto); + mvi_dev->running_req++; + ++(*pass); + mvi->tx_prod = (mvi->tx_prod + 1) & (MVS_CHIP_SLOT_SZ - 1); - } while (--n); - rc = 0; - goto out_done; + return rc; +err_out_slot_buf: + pci_pool_free(mvi->dma_pool, slot->buf, slot->buf_dma); err_out_tag: mvs_tag_free(mvi, tag); err_out: - dev_printk(KERN_ERR, mvi->dev, "mvsas exec failed[%d]!\n", rc); - if (!sas_protocol_ata(t->task_proto)) + dev_printk(KERN_ERR, mvi->dev, "mvsas prep failed[%d]!\n", rc); + if (!sas_protocol_ata(task->task_proto)) if (n_elem) - dma_unmap_sg(mvi->dev, t->scatter, n_elem, - t->data_dir); -out_done: + dma_unmap_sg(mvi->dev, task->scatter, n_elem, + task->data_dir); +prep_out: + return rc; +} + +static struct mvs_task_list *mvs_task_alloc_list(int *num, gfp_t gfp_flags) +{ + struct mvs_task_list *first = NULL; + + for (; *num > 0; --*num) { + struct mvs_task_list *mvs_list = kmem_cache_zalloc(mvs_task_list_cache, gfp_flags); + + if (!mvs_list) + break; + + INIT_LIST_HEAD(&mvs_list->list); + if (!first) + first = mvs_list; + else + list_add_tail(&mvs_list->list, &first->list); + + } + + return first; +} + +static inline void mvs_task_free_list(struct mvs_task_list *mvs_list) +{ + LIST_HEAD(list); + struct list_head *pos, *a; + struct mvs_task_list *mlist = NULL; + + __list_add(&list, mvs_list->list.prev, &mvs_list->list); + + list_for_each_safe(pos, a, &list) { + list_del_init(pos); + mlist = list_entry(pos, struct mvs_task_list, list); + kmem_cache_free(mvs_task_list_cache, mlist); + } +} + +static int mvs_task_exec(struct sas_task *task, const int num, gfp_t gfp_flags, + struct completion *completion, int is_tmf, + struct mvs_tmf_task *tmf) +{ + struct domain_device *dev = task->dev; + struct mvs_info *mvi = NULL; + u32 rc = 0; + u32 pass = 0; + unsigned long flags = 0; + + mvi = ((struct mvs_device *)task->dev->lldd_dev)->mvi_info; + + if ((dev->dev_type == SATA_DEV) && (dev->sata_dev.ap != NULL)) + spin_unlock_irq(dev->sata_dev.ap->lock); + + spin_lock_irqsave(&mvi->lock, flags); + rc = mvs_task_prep(task, mvi, is_tmf, tmf, &pass); + if (rc) + dev_printk(KERN_ERR, mvi->dev, "mvsas exec failed[%d]!\n", rc); + + if (likely(pass)) + MVS_CHIP_DISP->start_delivery(mvi, (mvi->tx_prod - 1) & + (MVS_CHIP_SLOT_SZ - 1)); spin_unlock_irqrestore(&mvi->lock, flags); + + if ((dev->dev_type == SATA_DEV) && (dev->sata_dev.ap != NULL)) + spin_lock_irq(dev->sata_dev.ap->lock); + + return rc; +} + +static int mvs_collector_task_exec(struct sas_task *task, const int num, gfp_t gfp_flags, + struct completion *completion, int is_tmf, + struct mvs_tmf_task *tmf) +{ + struct domain_device *dev = task->dev; + struct mvs_prv_info *mpi = dev->port->ha->lldd_ha; + struct mvs_info *mvi = NULL; + struct sas_task *t = task; + struct mvs_task_list *mvs_list = NULL, *a; + LIST_HEAD(q); + int pass[2] = {0}; + u32 rc = 0; + u32 n = num; + unsigned long flags = 0; + + mvs_list = mvs_task_alloc_list(&n, gfp_flags); + if (n) { + printk(KERN_ERR "%s: mvs alloc list failed.\n", __func__); + rc = -ENOMEM; + goto free_list; + } + + __list_add(&q, mvs_list->list.prev, &mvs_list->list); + + list_for_each_entry(a, &q, list) { + a->task = t; + t = list_entry(t->list.next, struct sas_task, list); + } + + list_for_each_entry(a, &q , list) { + + t = a->task; + mvi = ((struct mvs_device *)t->dev->lldd_dev)->mvi_info; + + spin_lock_irqsave(&mvi->lock, flags); + rc = mvs_task_prep(t, mvi, is_tmf, tmf, &pass[mvi->id]); + if (rc) + dev_printk(KERN_ERR, mvi->dev, "mvsas exec failed[%d]!\n", rc); + spin_unlock_irqrestore(&mvi->lock, flags); + } + + if (likely(pass[0])) + MVS_CHIP_DISP->start_delivery(mpi->mvi[0], + (mpi->mvi[0]->tx_prod - 1) & (MVS_CHIP_SLOT_SZ - 1)); + + if (likely(pass[1])) + MVS_CHIP_DISP->start_delivery(mpi->mvi[1], + (mpi->mvi[1]->tx_prod - 1) & (MVS_CHIP_SLOT_SZ - 1)); + + list_del_init(&q); + +free_list: + if (mvs_list) + mvs_task_free_list(mvs_list); + return rc; } int mvs_queue_command(struct sas_task *task, const int num, gfp_t gfp_flags) { - return mvs_task_exec(task, num, gfp_flags, NULL, 0, NULL); + struct mvs_device *mvi_dev = task->dev->lldd_dev; + struct sas_ha_struct *sas = mvi_dev->mvi_info->sas; + + if (sas->lldd_max_execute_num < 2) + return mvs_task_exec(task, num, gfp_flags, NULL, 0, NULL); + else + return mvs_collector_task_exec(task, num, gfp_flags, NULL, 0, NULL); } static void mvs_slot_free(struct mvs_info *mvi, u32 rx_desc) @@ -1067,6 +1176,11 @@ static void mvs_slot_task_free(struct mvs_info *mvi, struct sas_task *task, /* do nothing */ break; } + + if (slot->buf) { + pci_pool_free(mvi->dma_pool, slot->buf, slot->buf_dma); + slot->buf = NULL; + } list_del_init(&slot->entry); task->lldd_task = NULL; slot->task = NULL; @@ -1255,6 +1369,7 @@ static void mvs_port_notify_formed(struct asd_sas_phy *sas_phy, int lock) spin_lock_irqsave(&mvi->lock, flags); port->port_attached = 1; phy->port = port; + sas_port->lldd_port = port; if (phy->phy_type & PORT_TYPE_SAS) { port->wide_port_phymap = sas_port->phy_mask; mv_printk("set wide port phy map %x\n", sas_port->phy_mask); diff --git a/drivers/scsi/mvsas/mv_sas.h b/drivers/scsi/mvsas/mv_sas.h index 77ddc7c..1367d8b 100644 --- a/drivers/scsi/mvsas/mv_sas.h +++ b/drivers/scsi/mvsas/mv_sas.h @@ -3,6 +3,7 @@ * * Copyright 2007 Red Hat, Inc. * Copyright 2008 Marvell. + * Copyright 2009-2011 Marvell. * * This file is licensed under GPLv2. * @@ -67,6 +68,7 @@ extern struct mvs_tgt_initiator mvs_tgt; extern struct mvs_info *tgt_mvi; extern const struct mvs_dispatch mvs_64xx_dispatch; extern const struct mvs_dispatch mvs_94xx_dispatch; +extern struct kmem_cache *mvs_task_list_cache; #define DEV_IS_EXPANDER(type) \ ((type == EDGE_DEV) || (type == FANOUT_DEV)) @@ -341,6 +343,7 @@ struct mvs_info { dma_addr_t bulk_buffer_dma; #define TRASH_BUCKET_SIZE 0x20000 #endif + void *dma_pool; struct mvs_slot_info slot_info[0]; }; @@ -367,6 +370,11 @@ struct mvs_task_exec_info { int n_elem; }; +struct mvs_task_list { + struct sas_task *task; + struct list_head list; +}; + /******************** function prototype *********************/ void mvs_get_sas_addr(void *buf, u32 buflen); -- cgit v0.10.2 From 4d4dd7065572225bf6d97e5eb9915d94f9d53548 Mon Sep 17 00:00:00 2001 From: Kleber Sacilotto de Souza Date: Tue, 26 Apr 2011 19:23:29 -0300 Subject: [SCSI] ipr: increase the dump size for 64 bit adapters Currently the size of the dump generated by the driver is limited in 4MB, which is insufficient to gather much useful data from the new 64 bit adapters. This patch makes the needed changes to increase the dump limit for the 64 bit adapters to 32MB, or even to a bigger value in the future, but keeping the current limitations for the legacy 32 bit adapters. Signed-off-by: Kleber Sacilotto de Souza Acked-by: Brian King Signed-off-by: James Bottomley diff --git a/drivers/scsi/ipr.c b/drivers/scsi/ipr.c index fa2513c..3667f89 100644 --- a/drivers/scsi/ipr.c +++ b/drivers/scsi/ipr.c @@ -60,6 +60,7 @@ #include #include #include +#include #include #include #include @@ -2717,13 +2718,18 @@ static int ipr_sdt_copy(struct ipr_ioa_cfg *ioa_cfg, unsigned long pci_address, u32 length) { int bytes_copied = 0; - int cur_len, rc, rem_len, rem_page_len; + int cur_len, rc, rem_len, rem_page_len, max_dump_size; __be32 *page; unsigned long lock_flags = 0; struct ipr_ioa_dump *ioa_dump = &ioa_cfg->dump->ioa_dump; + if (ioa_cfg->sis64) + max_dump_size = IPR_FMT3_MAX_IOA_DUMP_SIZE; + else + max_dump_size = IPR_FMT2_MAX_IOA_DUMP_SIZE; + while (bytes_copied < length && - (ioa_dump->hdr.len + bytes_copied) < IPR_MAX_IOA_DUMP_SIZE) { + (ioa_dump->hdr.len + bytes_copied) < max_dump_size) { if (ioa_dump->page_offset >= PAGE_SIZE || ioa_dump->page_offset == 0) { page = (__be32 *)__get_free_page(GFP_ATOMIC); @@ -2885,8 +2891,8 @@ static void ipr_get_ioa_dump(struct ipr_ioa_cfg *ioa_cfg, struct ipr_dump *dump) unsigned long lock_flags = 0; struct ipr_driver_dump *driver_dump = &dump->driver_dump; struct ipr_ioa_dump *ioa_dump = &dump->ioa_dump; - u32 num_entries, start_off, end_off; - u32 bytes_to_copy, bytes_copied, rc; + u32 num_entries, max_num_entries, start_off, end_off; + u32 max_dump_size, bytes_to_copy, bytes_copied, rc; struct ipr_sdt *sdt; int valid = 1; int i; @@ -2947,8 +2953,18 @@ static void ipr_get_ioa_dump(struct ipr_ioa_cfg *ioa_cfg, struct ipr_dump *dump) on entries in this table */ sdt = &ioa_dump->sdt; + if (ioa_cfg->sis64) { + max_num_entries = IPR_FMT3_NUM_SDT_ENTRIES; + max_dump_size = IPR_FMT3_MAX_IOA_DUMP_SIZE; + } else { + max_num_entries = IPR_FMT2_NUM_SDT_ENTRIES; + max_dump_size = IPR_FMT2_MAX_IOA_DUMP_SIZE; + } + + bytes_to_copy = offsetof(struct ipr_sdt, entry) + + (max_num_entries * sizeof(struct ipr_sdt_entry)); rc = ipr_get_ldump_data_section(ioa_cfg, start_addr, (__be32 *)sdt, - sizeof(struct ipr_sdt) / sizeof(__be32)); + bytes_to_copy / sizeof(__be32)); /* Smart Dump table is ready to use and the first entry is valid */ if (rc || ((be32_to_cpu(sdt->hdr.state) != IPR_FMT3_SDT_READY_TO_USE) && @@ -2964,13 +2980,20 @@ static void ipr_get_ioa_dump(struct ipr_ioa_cfg *ioa_cfg, struct ipr_dump *dump) num_entries = be32_to_cpu(sdt->hdr.num_entries_used); - if (num_entries > IPR_NUM_SDT_ENTRIES) - num_entries = IPR_NUM_SDT_ENTRIES; + if (num_entries > max_num_entries) + num_entries = max_num_entries; + + /* Update dump length to the actual data to be copied */ + dump->driver_dump.hdr.len += sizeof(struct ipr_sdt_header); + if (ioa_cfg->sis64) + dump->driver_dump.hdr.len += num_entries * sizeof(struct ipr_sdt_entry); + else + dump->driver_dump.hdr.len += max_num_entries * sizeof(struct ipr_sdt_entry); spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags); for (i = 0; i < num_entries; i++) { - if (ioa_dump->hdr.len > IPR_MAX_IOA_DUMP_SIZE) { + if (ioa_dump->hdr.len > max_dump_size) { driver_dump->hdr.status = IPR_DUMP_STATUS_QUAL_SUCCESS; break; } @@ -2989,7 +3012,7 @@ static void ipr_get_ioa_dump(struct ipr_ioa_cfg *ioa_cfg, struct ipr_dump *dump) valid = 0; } if (valid) { - if (bytes_to_copy > IPR_MAX_IOA_DUMP_SIZE) { + if (bytes_to_copy > max_dump_size) { sdt->entry[i].flags &= ~IPR_SDT_VALID_ENTRY; continue; } @@ -3044,6 +3067,7 @@ static void ipr_release_dump(struct kref *kref) for (i = 0; i < dump->ioa_dump.next_page_index; i++) free_page((unsigned long) dump->ioa_dump.ioa_data[i]); + vfree(dump->ioa_dump.ioa_data); kfree(dump); LEAVE; } @@ -3835,7 +3859,7 @@ static ssize_t ipr_read_dump(struct file *filp, struct kobject *kobj, struct ipr_dump *dump; unsigned long lock_flags = 0; char *src; - int len; + int len, sdt_end; size_t rc = count; if (!capable(CAP_SYS_ADMIN)) @@ -3875,9 +3899,17 @@ static ssize_t ipr_read_dump(struct file *filp, struct kobject *kobj, off -= sizeof(dump->driver_dump); - if (count && off < offsetof(struct ipr_ioa_dump, ioa_data)) { - if (off + count > offsetof(struct ipr_ioa_dump, ioa_data)) - len = offsetof(struct ipr_ioa_dump, ioa_data) - off; + if (ioa_cfg->sis64) + sdt_end = offsetof(struct ipr_ioa_dump, sdt.entry) + + (be32_to_cpu(dump->ioa_dump.sdt.hdr.num_entries_used) * + sizeof(struct ipr_sdt_entry)); + else + sdt_end = offsetof(struct ipr_ioa_dump, sdt.entry) + + (IPR_FMT2_NUM_SDT_ENTRIES * sizeof(struct ipr_sdt_entry)); + + if (count && off < sdt_end) { + if (off + count > sdt_end) + len = sdt_end - off; else len = count; src = (u8 *)&dump->ioa_dump + off; @@ -3887,7 +3919,7 @@ static ssize_t ipr_read_dump(struct file *filp, struct kobject *kobj, count -= len; } - off -= offsetof(struct ipr_ioa_dump, ioa_data); + off -= sdt_end; while (count) { if ((off & PAGE_MASK) != ((off + count) & PAGE_MASK)) @@ -3916,6 +3948,7 @@ static ssize_t ipr_read_dump(struct file *filp, struct kobject *kobj, static int ipr_alloc_dump(struct ipr_ioa_cfg *ioa_cfg) { struct ipr_dump *dump; + __be32 **ioa_data; unsigned long lock_flags = 0; dump = kzalloc(sizeof(struct ipr_dump), GFP_KERNEL); @@ -3925,6 +3958,19 @@ static int ipr_alloc_dump(struct ipr_ioa_cfg *ioa_cfg) return -ENOMEM; } + if (ioa_cfg->sis64) + ioa_data = vmalloc(IPR_FMT3_MAX_NUM_DUMP_PAGES * sizeof(__be32 *)); + else + ioa_data = vmalloc(IPR_FMT2_MAX_NUM_DUMP_PAGES * sizeof(__be32 *)); + + if (!ioa_data) { + ipr_err("Dump memory allocation failed\n"); + kfree(dump); + return -ENOMEM; + } + + dump->ioa_dump.ioa_data = ioa_data; + kref_init(&dump->kref); dump->ioa_cfg = ioa_cfg; @@ -3932,6 +3978,7 @@ static int ipr_alloc_dump(struct ipr_ioa_cfg *ioa_cfg) if (INACTIVE != ioa_cfg->sdt_state) { spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags); + vfree(dump->ioa_dump.ioa_data); kfree(dump); return 0; } @@ -7566,7 +7613,10 @@ static int ipr_reset_restore_cfg_space(struct ipr_cmnd *ipr_cmd) ipr_cmd->job_step = ipr_reset_enable_ioa; if (GET_DUMP == ioa_cfg->sdt_state) { - ipr_reset_start_timer(ipr_cmd, IPR_DUMP_TIMEOUT); + if (ioa_cfg->sis64) + ipr_reset_start_timer(ipr_cmd, IPR_SIS64_DUMP_TIMEOUT); + else + ipr_reset_start_timer(ipr_cmd, IPR_SIS32_DUMP_TIMEOUT); ipr_cmd->job_step = ipr_reset_wait_for_dump; schedule_work(&ioa_cfg->work_q); return IPR_RC_JOB_RETURN; diff --git a/drivers/scsi/ipr.h b/drivers/scsi/ipr.h index 11b2dac..4e9701e 100644 --- a/drivers/scsi/ipr.h +++ b/drivers/scsi/ipr.h @@ -217,7 +217,8 @@ #define IPR_CHECK_FOR_RESET_TIMEOUT (HZ / 10) #define IPR_WAIT_FOR_BIST_TIMEOUT (2 * HZ) #define IPR_PCI_RESET_TIMEOUT (HZ / 2) -#define IPR_DUMP_TIMEOUT (15 * HZ) +#define IPR_SIS32_DUMP_TIMEOUT (15 * HZ) +#define IPR_SIS64_DUMP_TIMEOUT (40 * HZ) #define IPR_DUMP_DELAY_SECONDS 4 #define IPR_DUMP_DELAY_TIMEOUT (IPR_DUMP_DELAY_SECONDS * HZ) @@ -285,9 +286,12 @@ IPR_PCII_NO_HOST_RRQ | IPR_PCII_IOARRIN_LOST | IPR_PCII_MMIO_ERROR) /* * Dump literals */ -#define IPR_MAX_IOA_DUMP_SIZE (4 * 1024 * 1024) -#define IPR_NUM_SDT_ENTRIES 511 -#define IPR_MAX_NUM_DUMP_PAGES ((IPR_MAX_IOA_DUMP_SIZE / PAGE_SIZE) + 1) +#define IPR_FMT2_MAX_IOA_DUMP_SIZE (4 * 1024 * 1024) +#define IPR_FMT3_MAX_IOA_DUMP_SIZE (32 * 1024 * 1024) +#define IPR_FMT2_NUM_SDT_ENTRIES 511 +#define IPR_FMT3_NUM_SDT_ENTRIES 0xFFF +#define IPR_FMT2_MAX_NUM_DUMP_PAGES ((IPR_FMT2_MAX_IOA_DUMP_SIZE / PAGE_SIZE) + 1) +#define IPR_FMT3_MAX_NUM_DUMP_PAGES ((IPR_FMT3_MAX_IOA_DUMP_SIZE / PAGE_SIZE) + 1) /* * Misc literals @@ -1164,7 +1168,7 @@ struct ipr_sdt_header { struct ipr_sdt { struct ipr_sdt_header hdr; - struct ipr_sdt_entry entry[IPR_NUM_SDT_ENTRIES]; + struct ipr_sdt_entry entry[IPR_FMT3_NUM_SDT_ENTRIES]; }__attribute__((packed, aligned (4))); struct ipr_uc_sdt { @@ -1608,7 +1612,7 @@ struct ipr_driver_dump { struct ipr_ioa_dump { struct ipr_dump_entry_header hdr; struct ipr_sdt sdt; - __be32 *ioa_data[IPR_MAX_NUM_DUMP_PAGES]; + __be32 **ioa_data; u32 reserved; u32 next_page_index; u32 page_offset; -- cgit v0.10.2 From 201aed678482f247aa96bd8fcd9e960fefd82d59 Mon Sep 17 00:00:00 2001 From: Brian King Date: Wed, 27 Apr 2011 10:27:08 -0500 Subject: [SCSI] ibmvscsi: Improve CRQ reset reliability This patch fixes an issue seen where an event occurs which causes the ibmvscsi driver to reset its CRQ. Upon re-registering its CRQ, it receives H_CLOSED, indicating the Virtual I/O Server is not yet ready to receive commands. This resulted in the ibmvscsi driver essentially offlining the adapter and not recovering. The fix is to re-enable our interrupt so that when the Virtual I/O server is ready and sends a CRQ init, we will be able to receive it and resume initialization of the VSCSI adapter. Signed-off-by: Brian King Signed-off-by: James Bottomley diff --git a/drivers/scsi/ibmvscsi/ibmvscsi.c b/drivers/scsi/ibmvscsi/ibmvscsi.c index 0419584..3d391dc 100644 --- a/drivers/scsi/ibmvscsi/ibmvscsi.c +++ b/drivers/scsi/ibmvscsi/ibmvscsi.c @@ -1849,8 +1849,7 @@ static void ibmvscsi_do_work(struct ibmvscsi_host_data *hostdata) rc = ibmvscsi_ops->reset_crq_queue(&hostdata->queue, hostdata); if (!rc) rc = ibmvscsi_ops->send_crq(hostdata, 0xC001000000000000LL, 0); - if (!rc) - rc = vio_enable_interrupts(to_vio_dev(hostdata->dev)); + vio_enable_interrupts(to_vio_dev(hostdata->dev)); } else if (hostdata->reenable_crq) { smp_rmb(); action = "enable"; -- cgit v0.10.2 From 9c324b8ba8e3ee8772a0c716d557e1582699d481 Mon Sep 17 00:00:00 2001 From: Kleber Sacilotto de Souza Date: Wed, 27 Apr 2011 14:43:40 -0300 Subject: [SCSI] ipr: Driver version 2.5.2 Bump the driver version. Signed-off-by: Kleber Sacilotto de Souza Signed-off-by: James Bottomley diff --git a/drivers/scsi/ipr.h b/drivers/scsi/ipr.h index 4e9701e..f93f863 100644 --- a/drivers/scsi/ipr.h +++ b/drivers/scsi/ipr.h @@ -38,8 +38,8 @@ /* * Literals */ -#define IPR_DRIVER_VERSION "2.5.1" -#define IPR_DRIVER_DATE "(August 10, 2010)" +#define IPR_DRIVER_VERSION "2.5.2" +#define IPR_DRIVER_DATE "(April 27, 2011)" /* * IPR_MAX_CMD_PER_LUN: This defines the maximum number of outstanding -- cgit v0.10.2 From 2be19102b71c1a45d37fec50303791daa1a06869 Mon Sep 17 00:00:00 2001 From: Yinghai Lu Date: Sun, 1 May 2011 19:12:04 +0200 Subject: x86, NUMA: Fix empty memblk detection in numa_cleanup_meminfo() numa_cleanup_meminfo() trims each memblk between low (0) and high (max_pfn) limits and discards empty ones. However, the emptiness detection incorrectly used equality test. If the start of a memblk is higher than max_pfn, it is empty but fails the equality test and doesn't get discarded. The condition triggers when max_pfn is lower than start of a NUMA node and results in memory misconfiguration - leading to WARN_ON()s and other funnies. The bug was discovered in devel branch where 32bit too uses this code path for NUMA init. If a node is above the addressing limit, max_pfn ends up lower than the node triggering this problem. The failure hasn't been observed on x86-64 but is still possible with broken hardware e820/NUMA info. As the fix is very low risk, it would be better to apply it even for 64bit. Fix it by using >= instead of ==. Signed-off-by: Yinghai Lu [ Extracted the actual fix from the original patch and rewrote patch description. ] Signed-off-by: Tejun Heo Link: http://lkml.kernel.org/r/20110501171204.GO29280@htj.dyndns.org Signed-off-by: Ingo Molnar diff --git a/arch/x86/mm/numa_64.c b/arch/x86/mm/numa_64.c index e8c00cc..85b52fc 100644 --- a/arch/x86/mm/numa_64.c +++ b/arch/x86/mm/numa_64.c @@ -306,7 +306,7 @@ int __init numa_cleanup_meminfo(struct numa_meminfo *mi) bi->end = min(bi->end, high); /* and there's no empty block */ - if (bi->start == bi->end) { + if (bi->start >= bi->end) { numa_remove_memblk_from(i--, mi); continue; } -- cgit v0.10.2 From 9de4966a4d218f29c68e96e8e7b4d2840dedec79 Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Sun, 1 May 2011 14:09:21 +0200 Subject: x86: Fix spelling error in the memcpy() source code comment Signed-off-by: Bart Van Assche Cc: "H. Peter Anvin" Link: http://lkml.kernel.org/r/201105011409.21629.bvanassche@acm.org Signed-off-by: Ingo Molnar diff --git a/arch/x86/lib/memcpy_64.S b/arch/x86/lib/memcpy_64.S index 75ef61e..2a560bb 100644 --- a/arch/x86/lib/memcpy_64.S +++ b/arch/x86/lib/memcpy_64.S @@ -49,7 +49,7 @@ ENTRY(memcpy) jb .Lhandle_tail /* - * We check whether memory false dependece could occur, + * We check whether memory false dependence could occur, * then jump to corresponding copy mode. */ cmp %dil, %sil -- cgit v0.10.2 From e37c4913c555bd149eba3af953fb5d3a1686dfbd Mon Sep 17 00:00:00 2001 From: Jeff Mahoney Date: Wed, 27 Apr 2011 16:22:20 -0400 Subject: [SCSI] iterate over devices individually for /proc/scsi/scsi On systems with very large numbers (> 1600 or so) of SCSI devices, cat /proc/scsi/scsi ends up failing with -ENOMEM. This is due to the show routine simply iterating over all of the devices with bus_for_each_dev(), and trying to dump all of them into the buffer at the same time. On my test system (using scsi_debug with 4064 devices), the output ends up being ~ 632k, far more than kmalloc will typically allow. This patch defines its own seq_file opreations to iterate over the scsi devices.The result is that each show() operation only dumps ~ 180 bytes into the buffer at a time so we don't run out of memory. If the "Attached devices" header isn't required, we can dump the sfile->private bit completely. Signed-off-by: Jeff Mahoney Signed-off-by: James Bottomley diff --git a/drivers/scsi/scsi_proc.c b/drivers/scsi/scsi_proc.c index c99da92..f46855c 100644 --- a/drivers/scsi/scsi_proc.c +++ b/drivers/scsi/scsi_proc.c @@ -386,13 +386,59 @@ static ssize_t proc_scsi_write(struct file *file, const char __user *buf, * @s: output goes here * @p: not used */ -static int proc_scsi_show(struct seq_file *s, void *p) +static int always_match(struct device *dev, void *data) { - seq_printf(s, "Attached devices:\n"); - bus_for_each_dev(&scsi_bus_type, NULL, s, proc_print_scsidevice); - return 0; + return 1; +} + +static inline struct device *next_scsi_device(struct device *start) +{ + struct device *next = bus_find_device(&scsi_bus_type, start, NULL, + always_match); + put_device(start); + return next; } +static void *scsi_seq_start(struct seq_file *sfile, loff_t *pos) +{ + struct device *dev = NULL; + loff_t n = *pos; + + while ((dev = next_scsi_device(dev))) { + if (!n--) + break; + sfile->private++; + } + return dev; +} + +static void *scsi_seq_next(struct seq_file *sfile, void *v, loff_t *pos) +{ + (*pos)++; + sfile->private++; + return next_scsi_device(v); +} + +static void scsi_seq_stop(struct seq_file *sfile, void *v) +{ + put_device(v); +} + +static int scsi_seq_show(struct seq_file *sfile, void *dev) +{ + if (!sfile->private) + seq_puts(sfile, "Attached devices:\n"); + + return proc_print_scsidevice(dev, sfile); +} + +static const struct seq_operations scsi_seq_ops = { + .start = scsi_seq_start, + .next = scsi_seq_next, + .stop = scsi_seq_stop, + .show = scsi_seq_show +}; + /** * proc_scsi_open - glue function * @inode: not used @@ -406,7 +452,7 @@ static int proc_scsi_open(struct inode *inode, struct file *file) * We don't really need this for the write case but it doesn't * harm either. */ - return single_open(file, proc_scsi_show, NULL); + return seq_open(file, &scsi_seq_ops); } static const struct file_operations proc_scsi_operations = { @@ -415,7 +461,7 @@ static const struct file_operations proc_scsi_operations = { .read = seq_read, .write = proc_scsi_write, .llseek = seq_lseek, - .release = single_release, + .release = seq_release, }; /** -- cgit v0.10.2 From b5a6f69c5ca024bea43496d517c3b7ccfdb084a6 Mon Sep 17 00:00:00 2001 From: Antonio Quartulli Date: Sat, 16 Apr 2011 11:30:57 +0200 Subject: batman-adv: orig_hash_find() manages rcu_lock/unlock internally orig_hash_find() manages rcu_lock/unlock internally and doesn't need to be surrounded by rcu_read_lock() / rcu_read_unlock() anymore Signed-off-by: Antonio Quartulli Acked-by: Marek Lindner Signed-off-by: Sven Eckelmann diff --git a/net/batman-adv/routing.c b/net/batman-adv/routing.c index f6c6422..2d77bd3 100644 --- a/net/batman-adv/routing.c +++ b/net/batman-adv/routing.c @@ -1310,13 +1310,10 @@ int route_unicast_packet(struct sk_buff *skb, struct hard_iface *recv_if) } /* get routing information */ - rcu_read_lock(); orig_node = orig_hash_find(bat_priv, unicast_packet->dest); if (!orig_node) - goto unlock; - - rcu_read_unlock(); + goto out; /* find_router() increases neigh_nodes refcount if found. */ neigh_node = find_router(bat_priv, orig_node, recv_if); @@ -1362,10 +1359,7 @@ int route_unicast_packet(struct sk_buff *skb, struct hard_iface *recv_if) /* route it */ send_skb_packet(skb, neigh_node->if_incoming, neigh_node->addr); ret = NET_RX_SUCCESS; - goto out; -unlock: - rcu_read_unlock(); out: if (neigh_node) neigh_node_free_ref(neigh_node); @@ -1464,13 +1458,10 @@ int recv_bcast_packet(struct sk_buff *skb, struct hard_iface *recv_if) if (bcast_packet->ttl < 2) goto out; - rcu_read_lock(); orig_node = orig_hash_find(bat_priv, bcast_packet->orig); if (!orig_node) - goto rcu_unlock; - - rcu_read_unlock(); + goto out; spin_lock_bh(&orig_node->bcast_seqno_lock); @@ -1501,9 +1492,6 @@ int recv_bcast_packet(struct sk_buff *skb, struct hard_iface *recv_if) ret = NET_RX_SUCCESS; goto out; -rcu_unlock: - rcu_read_unlock(); - goto out; spin_unlock: spin_unlock_bh(&orig_node->bcast_seqno_lock); out: -- cgit v0.10.2 From 5f657ec0d2103571a31707711926b443a27b0c66 Mon Sep 17 00:00:00 2001 From: Antonio Quartulli Date: Wed, 20 Apr 2011 09:52:56 +0200 Subject: batman-adv: Move definition of atomic_dec_not_zero() into main.h atomic_dec_not_zero() is very useful and it is currently defined multiple times. So it is possible to move it in main.h Signed-off-by: Antonio Quartulli Signed-off-by: Sven Eckelmann diff --git a/net/batman-adv/aggregation.c b/net/batman-adv/aggregation.c index af45d6b..c11788c 100644 --- a/net/batman-adv/aggregation.c +++ b/net/batman-adv/aggregation.c @@ -95,7 +95,6 @@ static bool can_aggregate_with(struct batman_packet *new_batman_packet, return false; } -#define atomic_dec_not_zero(v) atomic_add_unless((v), -1, 0) /* create a new aggregated packet and add this packet to it */ static void new_aggregated_packet(unsigned char *packet_buff, int packet_len, unsigned long send_time, bool direct_link, diff --git a/net/batman-adv/main.h b/net/batman-adv/main.h index dc24869..ace7285 100644 --- a/net/batman-adv/main.h +++ b/net/batman-adv/main.h @@ -175,4 +175,6 @@ static inline int compare_eth(void *data1, void *data2) return (memcmp(data1, data2, ETH_ALEN) == 0 ? 1 : 0); } +#define atomic_dec_not_zero(v) atomic_add_unless((v), -1, 0) + #endif /* _NET_BATMAN_ADV_MAIN_H_ */ diff --git a/net/batman-adv/send.c b/net/batman-adv/send.c index e78670c..7650e2b 100644 --- a/net/batman-adv/send.c +++ b/net/batman-adv/send.c @@ -393,7 +393,6 @@ static void _add_bcast_packet_to_list(struct bat_priv *bat_priv, send_time); } -#define atomic_dec_not_zero(v) atomic_add_unless((v), -1, 0) /* add a broadcast packet to the queue and setup timers. broadcast packets * are sent multiple times to increase probability for beeing received. * -- cgit v0.10.2 From 71e4aa9c465fd66c110667ab5d620fb6a4ef2157 Mon Sep 17 00:00:00 2001 From: Antonio Quartulli Date: Mon, 25 Apr 2011 22:44:32 +0200 Subject: batman-adv: fix gw_node_update() and gw_election() This is a regression from c4aac1ab9b973798163b34939b522f01e4d28ac9 - gw_node_update() doesn't add a new gw_node in case of empty curr_gw. This means that at the beginning no gw_node is added, leading to an empty gateway list. - gw_election() is terminating in case of curr_gw == NULL. It has to terminate in case of curr_gw != NULL Signed-off-by: Antonio Quartulli Signed-off-by: Sven Eckelmann diff --git a/net/batman-adv/gateway_client.c b/net/batman-adv/gateway_client.c index 2acd7a66..af128ef 100644 --- a/net/batman-adv/gateway_client.c +++ b/net/batman-adv/gateway_client.c @@ -127,7 +127,7 @@ void gw_election(struct bat_priv *bat_priv) return; curr_gw = gw_get_selected_gw_node(bat_priv); - if (!curr_gw) + if (curr_gw) goto out; rcu_read_lock(); @@ -310,9 +310,13 @@ void gw_node_update(struct bat_priv *bat_priv, struct hlist_node *node; struct gw_node *gw_node, *curr_gw; + /** + * Note: We don't need a NULL check here, since curr_gw never gets + * dereferenced. If curr_gw is NULL we also should not exit as we may + * have this gateway in our list (duplication check!) even though we + * have no currently selected gateway. + */ curr_gw = gw_get_selected_gw_node(bat_priv); - if (!curr_gw) - goto out; rcu_read_lock(); hlist_for_each_entry_rcu(gw_node, node, &bat_priv->gw_list, list) { @@ -350,7 +354,7 @@ deselect: gw_deselect(bat_priv); unlock: rcu_read_unlock(); -out: + if (curr_gw) gw_node_free_ref(curr_gw); } -- cgit v0.10.2 From 32ae9b221e788413ce68feaae2ca39e406211a0a Mon Sep 17 00:00:00 2001 From: Marek Lindner Date: Wed, 20 Apr 2011 15:40:58 +0200 Subject: batman-adv: Make bat_priv->primary_if an rcu protected pointer The rcu protected macros rcu_dereference() and rcu_assign_pointer() for the bat_priv->primary_if need to be used, as well as spin/rcu locking. Otherwise we might end up using a primary_if pointer pointing to already freed memory. Signed-off-by: Marek Lindner Signed-off-by: Sven Eckelmann diff --git a/net/batman-adv/gateway_client.c b/net/batman-adv/gateway_client.c index af128ef..65f3953 100644 --- a/net/batman-adv/gateway_client.c +++ b/net/batman-adv/gateway_client.c @@ -439,30 +439,32 @@ int gw_client_seq_print_text(struct seq_file *seq, void *offset) { struct net_device *net_dev = (struct net_device *)seq->private; struct bat_priv *bat_priv = netdev_priv(net_dev); + struct hard_iface *primary_if; struct gw_node *gw_node; struct hlist_node *node; - int gw_count = 0; + int gw_count = 0, ret = 0; - if (!bat_priv->primary_if) { - - return seq_printf(seq, "BATMAN mesh %s disabled - please " - "specify interfaces to enable it\n", - net_dev->name); + primary_if = primary_if_get_selected(bat_priv); + if (!primary_if) { + ret = seq_printf(seq, "BATMAN mesh %s disabled - please " + "specify interfaces to enable it\n", + net_dev->name); + goto out; } - if (bat_priv->primary_if->if_status != IF_ACTIVE) { - - return seq_printf(seq, "BATMAN mesh %s disabled - " - "primary interface not active\n", - net_dev->name); + if (primary_if->if_status != IF_ACTIVE) { + ret = seq_printf(seq, "BATMAN mesh %s disabled - " + "primary interface not active\n", + net_dev->name); + goto out; } seq_printf(seq, " %-12s (%s/%i) %17s [%10s]: gw_class ... " "[B.A.T.M.A.N. adv %s%s, MainIF/MAC: %s/%pM (%s)]\n", "Gateway", "#", TQ_MAX_VALUE, "Nexthop", "outgoingIF", SOURCE_VERSION, REVISION_VERSION_STR, - bat_priv->primary_if->net_dev->name, - bat_priv->primary_if->net_dev->dev_addr, net_dev->name); + primary_if->net_dev->name, + primary_if->net_dev->dev_addr, net_dev->name); rcu_read_lock(); hlist_for_each_entry_rcu(gw_node, node, &bat_priv->gw_list, list) { @@ -480,7 +482,10 @@ int gw_client_seq_print_text(struct seq_file *seq, void *offset) if (gw_count == 0) seq_printf(seq, "No gateways in range ...\n"); - return 0; +out: + if (primary_if) + hardif_free_ref(primary_if); + return ret; } int gw_is_target(struct bat_priv *bat_priv, struct sk_buff *skb) diff --git a/net/batman-adv/hard-interface.c b/net/batman-adv/hard-interface.c index b3058e4..3e888f1 100644 --- a/net/batman-adv/hard-interface.c +++ b/net/batman-adv/hard-interface.c @@ -110,47 +110,60 @@ out: return hard_iface; } -static void update_primary_addr(struct bat_priv *bat_priv) +static void primary_if_update_addr(struct bat_priv *bat_priv) { struct vis_packet *vis_packet; + struct hard_iface *primary_if; + + primary_if = primary_if_get_selected(bat_priv); + if (!primary_if) + goto out; vis_packet = (struct vis_packet *) bat_priv->my_vis_info->skb_packet->data; - memcpy(vis_packet->vis_orig, - bat_priv->primary_if->net_dev->dev_addr, ETH_ALEN); + memcpy(vis_packet->vis_orig, primary_if->net_dev->dev_addr, ETH_ALEN); memcpy(vis_packet->sender_orig, - bat_priv->primary_if->net_dev->dev_addr, ETH_ALEN); + primary_if->net_dev->dev_addr, ETH_ALEN); + +out: + if (primary_if) + hardif_free_ref(primary_if); } -static void set_primary_if(struct bat_priv *bat_priv, - struct hard_iface *hard_iface) +static void primary_if_select(struct bat_priv *bat_priv, + struct hard_iface *new_hard_iface) { + struct hard_iface *curr_hard_iface; struct batman_packet *batman_packet; - struct hard_iface *old_if; - if (hard_iface && !atomic_inc_not_zero(&hard_iface->refcount)) - hard_iface = NULL; + spin_lock_bh(&hardif_list_lock); - old_if = bat_priv->primary_if; - bat_priv->primary_if = hard_iface; + if (new_hard_iface && !atomic_inc_not_zero(&new_hard_iface->refcount)) + new_hard_iface = NULL; - if (old_if) - hardif_free_ref(old_if); + curr_hard_iface = bat_priv->primary_if; + rcu_assign_pointer(bat_priv->primary_if, new_hard_iface); - if (!bat_priv->primary_if) - return; + if (curr_hard_iface) + hardif_free_ref(curr_hard_iface); - batman_packet = (struct batman_packet *)(hard_iface->packet_buff); + if (!new_hard_iface) + goto out; + + batman_packet = (struct batman_packet *)(new_hard_iface->packet_buff); batman_packet->flags = PRIMARIES_FIRST_HOP; batman_packet->ttl = TTL; - update_primary_addr(bat_priv); + primary_if_update_addr(bat_priv); /*** * hacky trick to make sure that we send the HNA information via * our new primary interface */ atomic_set(&bat_priv->hna_local_changed, 1); + +out: + spin_unlock_bh(&hardif_list_lock); } static bool hardif_is_iface_up(struct hard_iface *hard_iface) @@ -236,9 +249,10 @@ void update_min_mtu(struct net_device *soft_iface) static void hardif_activate_interface(struct hard_iface *hard_iface) { struct bat_priv *bat_priv; + struct hard_iface *primary_if = NULL; if (hard_iface->if_status != IF_INACTIVE) - return; + goto out; bat_priv = netdev_priv(hard_iface->soft_iface); @@ -249,14 +263,18 @@ static void hardif_activate_interface(struct hard_iface *hard_iface) * the first active interface becomes our primary interface or * the next active interface after the old primay interface was removed */ - if (!bat_priv->primary_if) - set_primary_if(bat_priv, hard_iface); + primary_if = primary_if_get_selected(bat_priv); + if (!primary_if) + primary_if_select(bat_priv, hard_iface); bat_info(hard_iface->soft_iface, "Interface activated: %s\n", hard_iface->net_dev->name); update_min_mtu(hard_iface->soft_iface); - return; + +out: + if (primary_if) + hardif_free_ref(primary_if); } static void hardif_deactivate_interface(struct hard_iface *hard_iface) @@ -386,12 +404,13 @@ err: void hardif_disable_interface(struct hard_iface *hard_iface) { struct bat_priv *bat_priv = netdev_priv(hard_iface->soft_iface); + struct hard_iface *primary_if = NULL; if (hard_iface->if_status == IF_ACTIVE) hardif_deactivate_interface(hard_iface); if (hard_iface->if_status != IF_INACTIVE) - return; + goto out; bat_info(hard_iface->soft_iface, "Removing interface: %s\n", hard_iface->net_dev->name); @@ -400,11 +419,12 @@ void hardif_disable_interface(struct hard_iface *hard_iface) bat_priv->num_ifaces--; orig_hash_del_if(hard_iface, bat_priv->num_ifaces); - if (hard_iface == bat_priv->primary_if) { + primary_if = primary_if_get_selected(bat_priv); + if (hard_iface == primary_if) { struct hard_iface *new_if; new_if = hardif_get_active(hard_iface->soft_iface); - set_primary_if(bat_priv, new_if); + primary_if_select(bat_priv, new_if); if (new_if) hardif_free_ref(new_if); @@ -425,6 +445,10 @@ void hardif_disable_interface(struct hard_iface *hard_iface) hard_iface->soft_iface = NULL; hardif_free_ref(hard_iface); + +out: + if (primary_if) + hardif_free_ref(primary_if); } static struct hard_iface *hardif_add_interface(struct net_device *net_dev) @@ -514,6 +538,7 @@ static int hard_if_event(struct notifier_block *this, { struct net_device *net_dev = (struct net_device *)ptr; struct hard_iface *hard_iface = hardif_get_by_netdev(net_dev); + struct hard_iface *primary_if = NULL; struct bat_priv *bat_priv; if (!hard_iface && event == NETDEV_REGISTER) @@ -549,8 +574,12 @@ static int hard_if_event(struct notifier_block *this, update_mac_addresses(hard_iface); bat_priv = netdev_priv(hard_iface->soft_iface); - if (hard_iface == bat_priv->primary_if) - update_primary_addr(bat_priv); + primary_if = primary_if_get_selected(bat_priv); + if (!primary_if) + goto hardif_put; + + if (hard_iface == primary_if) + primary_if_update_addr(bat_priv); break; default: break; @@ -559,6 +588,8 @@ static int hard_if_event(struct notifier_block *this, hardif_put: hardif_free_ref(hard_iface); out: + if (primary_if) + hardif_free_ref(primary_if); return NOTIFY_DONE; } diff --git a/net/batman-adv/hard-interface.h b/net/batman-adv/hard-interface.h index a9ddf36..6426599 100644 --- a/net/batman-adv/hard-interface.h +++ b/net/batman-adv/hard-interface.h @@ -45,4 +45,22 @@ static inline void hardif_free_ref(struct hard_iface *hard_iface) call_rcu(&hard_iface->rcu, hardif_free_rcu); } +static inline struct hard_iface *primary_if_get_selected( + struct bat_priv *bat_priv) +{ + struct hard_iface *hard_iface; + + rcu_read_lock(); + hard_iface = rcu_dereference(bat_priv->primary_if); + if (!hard_iface) + goto out; + + if (!atomic_inc_not_zero(&hard_iface->refcount)) + hard_iface = NULL; + +out: + rcu_read_unlock(); + return hard_iface; +} + #endif /* _NET_BATMAN_ADV_HARD_INTERFACE_H_ */ diff --git a/net/batman-adv/icmp_socket.c b/net/batman-adv/icmp_socket.c index 49079c2..fa22ba2 100644 --- a/net/batman-adv/icmp_socket.c +++ b/net/batman-adv/icmp_socket.c @@ -153,6 +153,7 @@ static ssize_t bat_socket_write(struct file *file, const char __user *buff, { struct socket_client *socket_client = file->private_data; struct bat_priv *bat_priv = socket_client->bat_priv; + struct hard_iface *primary_if = NULL; struct sk_buff *skb; struct icmp_packet_rr *icmp_packet; @@ -167,15 +168,21 @@ static ssize_t bat_socket_write(struct file *file, const char __user *buff, return -EINVAL; } - if (!bat_priv->primary_if) - return -EFAULT; + primary_if = primary_if_get_selected(bat_priv); + + if (!primary_if) { + len = -EFAULT; + goto out; + } if (len >= sizeof(struct icmp_packet_rr)) packet_len = sizeof(struct icmp_packet_rr); skb = dev_alloc_skb(packet_len + sizeof(struct ethhdr)); - if (!skb) - return -ENOMEM; + if (!skb) { + len = -ENOMEM; + goto out; + } skb_reserve(skb, sizeof(struct ethhdr)); icmp_packet = (struct icmp_packet_rr *)skb_put(skb, packet_len); @@ -233,7 +240,7 @@ static ssize_t bat_socket_write(struct file *file, const char __user *buff, goto dst_unreach; memcpy(icmp_packet->orig, - bat_priv->primary_if->net_dev->dev_addr, ETH_ALEN); + primary_if->net_dev->dev_addr, ETH_ALEN); if (packet_len == sizeof(struct icmp_packet_rr)) memcpy(icmp_packet->rr, @@ -248,6 +255,8 @@ dst_unreach: free_skb: kfree_skb(skb); out: + if (primary_if) + hardif_free_ref(primary_if); if (neigh_node) neigh_node_free_ref(neigh_node); if (orig_node) diff --git a/net/batman-adv/originator.c b/net/batman-adv/originator.c index 5b8fe32..ef4a9be 100644 --- a/net/batman-adv/originator.c +++ b/net/batman-adv/originator.c @@ -405,29 +405,34 @@ int orig_seq_print_text(struct seq_file *seq, void *offset) struct hashtable_t *hash = bat_priv->orig_hash; struct hlist_node *node, *node_tmp; struct hlist_head *head; + struct hard_iface *primary_if; struct orig_node *orig_node; struct neigh_node *neigh_node, *neigh_node_tmp; int batman_count = 0; int last_seen_secs; int last_seen_msecs; - int i; + int i, ret = 0; + + primary_if = primary_if_get_selected(bat_priv); - if ((!bat_priv->primary_if) || - (bat_priv->primary_if->if_status != IF_ACTIVE)) { - if (!bat_priv->primary_if) - return seq_printf(seq, "BATMAN mesh %s disabled - " - "please specify interfaces to enable it\n", - net_dev->name); + if (!primary_if) { + ret = seq_printf(seq, "BATMAN mesh %s disabled - " + "please specify interfaces to enable it\n", + net_dev->name); + goto out; + } - return seq_printf(seq, "BATMAN mesh %s " - "disabled - primary interface not active\n", - net_dev->name); + if (primary_if->if_status != IF_ACTIVE) { + ret = seq_printf(seq, "BATMAN mesh %s " + "disabled - primary interface not active\n", + net_dev->name); + goto out; } seq_printf(seq, "[B.A.T.M.A.N. adv %s%s, MainIF/MAC: %s/%pM (%s)]\n", SOURCE_VERSION, REVISION_VERSION_STR, - bat_priv->primary_if->net_dev->name, - bat_priv->primary_if->net_dev->dev_addr, net_dev->name); + primary_if->net_dev->name, + primary_if->net_dev->dev_addr, net_dev->name); seq_printf(seq, " %-15s %s (%s/%i) %17s [%10s]: %20s ...\n", "Originator", "last-seen", "#", TQ_MAX_VALUE, "Nexthop", "outgoingIF", "Potential nexthops"); @@ -474,7 +479,10 @@ next: if (batman_count == 0) seq_printf(seq, "No batman nodes in range ...\n"); - return 0; +out: + if (primary_if) + hardif_free_ref(primary_if); + return ret; } static int orig_node_add_if(struct orig_node *orig_node, int max_if_num) diff --git a/net/batman-adv/routing.c b/net/batman-adv/routing.c index 2d77bd3..49f5715 100644 --- a/net/batman-adv/routing.c +++ b/net/batman-adv/routing.c @@ -904,6 +904,7 @@ int recv_bat_packet(struct sk_buff *skb, struct hard_iface *hard_iface) static int recv_my_icmp_packet(struct bat_priv *bat_priv, struct sk_buff *skb, size_t icmp_len) { + struct hard_iface *primary_if = NULL; struct orig_node *orig_node = NULL; struct neigh_node *router = NULL; struct icmp_packet_rr *icmp_packet; @@ -917,7 +918,8 @@ static int recv_my_icmp_packet(struct bat_priv *bat_priv, goto out; } - if (!bat_priv->primary_if) + primary_if = primary_if_get_selected(bat_priv); + if (!primary_if) goto out; /* answer echo request (ping) */ @@ -937,8 +939,7 @@ static int recv_my_icmp_packet(struct bat_priv *bat_priv, icmp_packet = (struct icmp_packet_rr *)skb->data; memcpy(icmp_packet->dst, icmp_packet->orig, ETH_ALEN); - memcpy(icmp_packet->orig, - bat_priv->primary_if->net_dev->dev_addr, ETH_ALEN); + memcpy(icmp_packet->orig, primary_if->net_dev->dev_addr, ETH_ALEN); icmp_packet->msg_type = ECHO_REPLY; icmp_packet->ttl = TTL; @@ -946,6 +947,8 @@ static int recv_my_icmp_packet(struct bat_priv *bat_priv, ret = NET_RX_SUCCESS; out: + if (primary_if) + hardif_free_ref(primary_if); if (router) neigh_node_free_ref(router); if (orig_node) @@ -956,6 +959,7 @@ out: static int recv_icmp_ttl_exceeded(struct bat_priv *bat_priv, struct sk_buff *skb) { + struct hard_iface *primary_if = NULL; struct orig_node *orig_node = NULL; struct neigh_node *router = NULL; struct icmp_packet *icmp_packet; @@ -971,7 +975,8 @@ static int recv_icmp_ttl_exceeded(struct bat_priv *bat_priv, goto out; } - if (!bat_priv->primary_if) + primary_if = primary_if_get_selected(bat_priv); + if (!primary_if) goto out; /* get routing information */ @@ -990,8 +995,7 @@ static int recv_icmp_ttl_exceeded(struct bat_priv *bat_priv, icmp_packet = (struct icmp_packet *)skb->data; memcpy(icmp_packet->dst, icmp_packet->orig, ETH_ALEN); - memcpy(icmp_packet->orig, - bat_priv->primary_if->net_dev->dev_addr, ETH_ALEN); + memcpy(icmp_packet->orig, primary_if->net_dev->dev_addr, ETH_ALEN); icmp_packet->msg_type = TTL_EXCEEDED; icmp_packet->ttl = TTL; @@ -999,6 +1003,8 @@ static int recv_icmp_ttl_exceeded(struct bat_priv *bat_priv, ret = NET_RX_SUCCESS; out: + if (primary_if) + hardif_free_ref(primary_if); if (router) neigh_node_free_ref(router); if (orig_node) diff --git a/net/batman-adv/send.c b/net/batman-adv/send.c index 7650e2b..02b541a6 100644 --- a/net/batman-adv/send.c +++ b/net/batman-adv/send.c @@ -244,6 +244,7 @@ static void rebuild_batman_packet(struct bat_priv *bat_priv, void schedule_own_packet(struct hard_iface *hard_iface) { struct bat_priv *bat_priv = netdev_priv(hard_iface->soft_iface); + struct hard_iface *primary_if; unsigned long send_time; struct batman_packet *batman_packet; int vis_server; @@ -253,6 +254,7 @@ void schedule_own_packet(struct hard_iface *hard_iface) return; vis_server = atomic_read(&bat_priv->vis_mode); + primary_if = primary_if_get_selected(bat_priv); /** * the interface gets activated here to avoid race conditions between @@ -266,7 +268,7 @@ void schedule_own_packet(struct hard_iface *hard_iface) /* if local hna has changed and interface is a primary interface */ if ((atomic_read(&bat_priv->hna_local_changed)) && - (hard_iface == bat_priv->primary_if)) + (hard_iface == primary_if)) rebuild_batman_packet(bat_priv, hard_iface); /** @@ -284,7 +286,7 @@ void schedule_own_packet(struct hard_iface *hard_iface) else batman_packet->flags &= ~VIS_SERVER; - if ((hard_iface == bat_priv->primary_if) && + if ((hard_iface == primary_if) && (atomic_read(&bat_priv->gw_mode) == GW_MODE_SERVER)) batman_packet->gw_flags = (uint8_t)atomic_read(&bat_priv->gw_bandwidth); @@ -299,6 +301,9 @@ void schedule_own_packet(struct hard_iface *hard_iface) hard_iface->packet_buff, hard_iface->packet_len, hard_iface, 1, send_time); + + if (primary_if) + hardif_free_ref(primary_if); } void schedule_forward_packet(struct orig_node *orig_node, @@ -403,6 +408,7 @@ static void _add_bcast_packet_to_list(struct bat_priv *bat_priv, * skb is freed. */ int add_bcast_packet_to_list(struct bat_priv *bat_priv, struct sk_buff *skb) { + struct hard_iface *primary_if = NULL; struct forw_packet *forw_packet; struct bcast_packet *bcast_packet; @@ -411,7 +417,8 @@ int add_bcast_packet_to_list(struct bat_priv *bat_priv, struct sk_buff *skb) goto out; } - if (!bat_priv->primary_if) + primary_if = primary_if_get_selected(bat_priv); + if (!primary_if) goto out; forw_packet = kmalloc(sizeof(struct forw_packet), GFP_ATOMIC); @@ -430,7 +437,7 @@ int add_bcast_packet_to_list(struct bat_priv *bat_priv, struct sk_buff *skb) skb_reset_mac_header(skb); forw_packet->skb = skb; - forw_packet->if_incoming = bat_priv->primary_if; + forw_packet->if_incoming = primary_if; /* how often did we send the bcast packet ? */ forw_packet->num_packets = 0; @@ -443,6 +450,8 @@ packet_free: out_and_inc: atomic_inc(&bat_priv->bcast_queue_left); out: + if (primary_if) + hardif_free_ref(primary_if); return NETDEV_TX_BUSY; } diff --git a/net/batman-adv/soft-interface.c b/net/batman-adv/soft-interface.c index 58ce440..ea5e58c 100644 --- a/net/batman-adv/soft-interface.c +++ b/net/batman-adv/soft-interface.c @@ -215,13 +215,24 @@ int softif_neigh_seq_print_text(struct seq_file *seq, void *offset) struct net_device *net_dev = (struct net_device *)seq->private; struct bat_priv *bat_priv = netdev_priv(net_dev); struct softif_neigh *softif_neigh; + struct hard_iface *primary_if; struct hlist_node *node; struct softif_neigh *curr_softif_neigh; + int ret = 0; - if (!bat_priv->primary_if) { - return seq_printf(seq, "BATMAN mesh %s disabled - " - "please specify interfaces to enable it\n", - net_dev->name); + primary_if = primary_if_get_selected(bat_priv); + if (!primary_if) { + ret = seq_printf(seq, "BATMAN mesh %s disabled - " + "please specify interfaces to enable it\n", + net_dev->name); + goto out; + } + + if (primary_if->if_status != IF_ACTIVE) { + ret = seq_printf(seq, "BATMAN mesh %s " + "disabled - primary interface not active\n", + net_dev->name); + goto out; } seq_printf(seq, "Softif neighbor list (%s)\n", net_dev->name); @@ -238,7 +249,10 @@ int softif_neigh_seq_print_text(struct seq_file *seq, void *offset) if (curr_softif_neigh) softif_neigh_free_ref(curr_softif_neigh); - return 0; +out: + if (primary_if) + hardif_free_ref(primary_if); + return ret; } static void softif_batman_recv(struct sk_buff *skb, struct net_device *dev, @@ -247,7 +261,8 @@ static void softif_batman_recv(struct sk_buff *skb, struct net_device *dev, struct bat_priv *bat_priv = netdev_priv(dev); struct ethhdr *ethhdr = (struct ethhdr *)skb->data; struct batman_packet *batman_packet; - struct softif_neigh *softif_neigh; + struct softif_neigh *softif_neigh = NULL; + struct hard_iface *primary_if = NULL; struct softif_neigh *curr_softif_neigh = NULL; if (ntohs(ethhdr->h_proto) == ETH_P_8021Q) @@ -257,28 +272,34 @@ static void softif_batman_recv(struct sk_buff *skb, struct net_device *dev, batman_packet = (struct batman_packet *)(skb->data + ETH_HLEN); if (batman_packet->version != COMPAT_VERSION) - goto err; + goto out; if (batman_packet->packet_type != BAT_PACKET) - goto err; + goto out; if (!(batman_packet->flags & PRIMARIES_FIRST_HOP)) - goto err; + goto out; if (is_my_mac(batman_packet->orig)) - goto err; + goto out; softif_neigh = softif_neigh_get(bat_priv, batman_packet->orig, vid); - if (!softif_neigh) - goto err; + goto out; curr_softif_neigh = softif_neigh_get_selected(bat_priv); + if (!curr_softif_neigh) + goto out; + if (curr_softif_neigh == softif_neigh) goto out; + primary_if = primary_if_get_selected(bat_priv); + if (!primary_if) + goto out; + /* we got a neighbor but its mac is 'bigger' than ours */ - if (memcmp(bat_priv->primary_if->net_dev->dev_addr, + if (memcmp(primary_if->net_dev->dev_addr, softif_neigh->addr, ETH_ALEN) < 0) goto out; @@ -300,7 +321,7 @@ static void softif_batman_recv(struct sk_buff *skb, struct net_device *dev, /* close own batX device and use softif_neigh as exit node */ if ((!curr_softif_neigh) && (memcmp(softif_neigh->addr, - bat_priv->primary_if->net_dev->dev_addr, ETH_ALEN) < 0)) { + primary_if->net_dev->dev_addr, ETH_ALEN) < 0)) { bat_dbg(DBG_ROUTES, bat_priv, "Setting mesh exit point to %pM (vid: %d).\n", softif_neigh->addr, softif_neigh->vid); @@ -310,12 +331,13 @@ static void softif_batman_recv(struct sk_buff *skb, struct net_device *dev, } out: - softif_neigh_free_ref(softif_neigh); -err: kfree_skb(skb); + if (softif_neigh) + softif_neigh_free_ref(softif_neigh); if (curr_softif_neigh) softif_neigh_free_ref(curr_softif_neigh); - + if (primary_if) + hardif_free_ref(primary_if); return; } @@ -371,6 +393,7 @@ int interface_tx(struct sk_buff *skb, struct net_device *soft_iface) { struct ethhdr *ethhdr = (struct ethhdr *)skb->data; struct bat_priv *bat_priv = netdev_priv(soft_iface); + struct hard_iface *primary_if = NULL; struct bcast_packet *bcast_packet; struct vlan_ethhdr *vhdr; struct softif_neigh *curr_softif_neigh = NULL; @@ -420,7 +443,8 @@ int interface_tx(struct sk_buff *skb, struct net_device *soft_iface) /* ethernet packet should be broadcasted */ if (do_bcast) { - if (!bat_priv->primary_if) + primary_if = primary_if_get_selected(bat_priv); + if (!primary_if) goto dropped; if (my_skb_head_push(skb, sizeof(struct bcast_packet)) < 0) @@ -436,7 +460,7 @@ int interface_tx(struct sk_buff *skb, struct net_device *soft_iface) /* hw address of first interface is the orig mac because only * this mac is known throughout the mesh */ memcpy(bcast_packet->orig, - bat_priv->primary_if->net_dev->dev_addr, ETH_ALEN); + primary_if->net_dev->dev_addr, ETH_ALEN); /* set broadcast sequence number */ bcast_packet->seqno = @@ -466,6 +490,8 @@ dropped_freed: end: if (curr_softif_neigh) softif_neigh_free_ref(curr_softif_neigh); + if (primary_if) + hardif_free_ref(primary_if); return NETDEV_TX_OK; } diff --git a/net/batman-adv/translation-table.c b/net/batman-adv/translation-table.c index 8d15b48..f931830 100644 --- a/net/batman-adv/translation-table.c +++ b/net/batman-adv/translation-table.c @@ -22,6 +22,7 @@ #include "main.h" #include "translation-table.h" #include "soft-interface.h" +#include "hard-interface.h" #include "hash.h" #include "originator.h" @@ -237,16 +238,26 @@ int hna_local_seq_print_text(struct seq_file *seq, void *offset) struct bat_priv *bat_priv = netdev_priv(net_dev); struct hashtable_t *hash = bat_priv->hna_local_hash; struct hna_local_entry *hna_local_entry; + struct hard_iface *primary_if; struct hlist_node *node; struct hlist_head *head; size_t buf_size, pos; char *buff; - int i; + int i, ret = 0; - if (!bat_priv->primary_if) { - return seq_printf(seq, "BATMAN mesh %s disabled - " - "please specify interfaces to enable it\n", - net_dev->name); + primary_if = primary_if_get_selected(bat_priv); + if (!primary_if) { + ret = seq_printf(seq, "BATMAN mesh %s disabled - " + "please specify interfaces to enable it\n", + net_dev->name); + goto out; + } + + if (primary_if->if_status != IF_ACTIVE) { + ret = seq_printf(seq, "BATMAN mesh %s disabled - " + "primary interface not active\n", + net_dev->name); + goto out; } seq_printf(seq, "Locally retrieved addresses (from %s) " @@ -269,7 +280,8 @@ int hna_local_seq_print_text(struct seq_file *seq, void *offset) buff = kmalloc(buf_size, GFP_ATOMIC); if (!buff) { spin_unlock_bh(&bat_priv->hna_lhash_lock); - return -ENOMEM; + ret = -ENOMEM; + goto out; } buff[0] = '\0'; @@ -291,7 +303,10 @@ int hna_local_seq_print_text(struct seq_file *seq, void *offset) seq_printf(seq, "%s", buff); kfree(buff); - return 0; +out: + if (primary_if) + hardif_free_ref(primary_if); + return ret; } static void _hna_local_del(struct hlist_node *node, void *arg) @@ -468,16 +483,26 @@ int hna_global_seq_print_text(struct seq_file *seq, void *offset) struct bat_priv *bat_priv = netdev_priv(net_dev); struct hashtable_t *hash = bat_priv->hna_global_hash; struct hna_global_entry *hna_global_entry; + struct hard_iface *primary_if; struct hlist_node *node; struct hlist_head *head; size_t buf_size, pos; char *buff; - int i; + int i, ret = 0; - if (!bat_priv->primary_if) { - return seq_printf(seq, "BATMAN mesh %s disabled - " - "please specify interfaces to enable it\n", - net_dev->name); + primary_if = primary_if_get_selected(bat_priv); + if (!primary_if) { + ret = seq_printf(seq, "BATMAN mesh %s disabled - please " + "specify interfaces to enable it\n", + net_dev->name); + goto out; + } + + if (primary_if->if_status != IF_ACTIVE) { + ret = seq_printf(seq, "BATMAN mesh %s disabled - " + "primary interface not active\n", + net_dev->name); + goto out; } seq_printf(seq, "Globally announced HNAs received via the mesh %s\n", @@ -499,7 +524,8 @@ int hna_global_seq_print_text(struct seq_file *seq, void *offset) buff = kmalloc(buf_size, GFP_ATOMIC); if (!buff) { spin_unlock_bh(&bat_priv->hna_ghash_lock); - return -ENOMEM; + ret = -ENOMEM; + goto out; } buff[0] = '\0'; pos = 0; @@ -522,7 +548,10 @@ int hna_global_seq_print_text(struct seq_file *seq, void *offset) seq_printf(seq, "%s", buff); kfree(buff); - return 0; +out: + if (primary_if) + hardif_free_ref(primary_if); + return ret; } static void _hna_global_del_orig(struct bat_priv *bat_priv, diff --git a/net/batman-adv/types.h b/net/batman-adv/types.h index 75123b1..947bafc 100644 --- a/net/batman-adv/types.h +++ b/net/batman-adv/types.h @@ -149,7 +149,6 @@ struct bat_priv { struct hlist_head softif_neigh_list; struct softif_neigh __rcu *softif_neigh; struct debug_log *debug_log; - struct hard_iface *primary_if; struct kobject *mesh_obj; struct dentry *debug_dir; struct hlist_head forw_bat_list; @@ -174,6 +173,7 @@ struct bat_priv { struct delayed_work orig_work; struct delayed_work vis_work; struct gw_node __rcu *curr_gw; /* rcu protected pointer */ + struct hard_iface __rcu *primary_if; /* rcu protected pointer */ struct vis_info *my_vis_info; }; diff --git a/net/batman-adv/unicast.c b/net/batman-adv/unicast.c index d46acc8..b46cbf1 100644 --- a/net/batman-adv/unicast.c +++ b/net/batman-adv/unicast.c @@ -221,15 +221,17 @@ int frag_send_skb(struct sk_buff *skb, struct bat_priv *bat_priv, struct hard_iface *hard_iface, uint8_t dstaddr[]) { struct unicast_packet tmp_uc, *unicast_packet; + struct hard_iface *primary_if; struct sk_buff *frag_skb; struct unicast_frag_packet *frag1, *frag2; int uc_hdr_len = sizeof(struct unicast_packet); int ucf_hdr_len = sizeof(struct unicast_frag_packet); int data_len = skb->len - uc_hdr_len; - int large_tail = 0; + int large_tail = 0, ret = NET_RX_DROP; uint16_t seqno; - if (!bat_priv->primary_if) + primary_if = primary_if_get_selected(bat_priv); + if (!primary_if) goto dropped; frag_skb = dev_alloc_skb(data_len - (data_len / 2) + ucf_hdr_len); @@ -254,7 +256,7 @@ int frag_send_skb(struct sk_buff *skb, struct bat_priv *bat_priv, frag1->version = COMPAT_VERSION; frag1->packet_type = BAT_UNICAST_FRAG; - memcpy(frag1->orig, bat_priv->primary_if->net_dev->dev_addr, ETH_ALEN); + memcpy(frag1->orig, primary_if->net_dev->dev_addr, ETH_ALEN); memcpy(frag2, frag1, sizeof(struct unicast_frag_packet)); if (data_len & 1) @@ -269,13 +271,17 @@ int frag_send_skb(struct sk_buff *skb, struct bat_priv *bat_priv, send_skb_packet(skb, hard_iface, dstaddr); send_skb_packet(frag_skb, hard_iface, dstaddr); - return NET_RX_SUCCESS; + ret = NET_RX_SUCCESS; + goto out; drop_frag: kfree_skb(frag_skb); dropped: kfree_skb(skb); - return NET_RX_DROP; +out: + if (primary_if) + hardif_free_ref(primary_if); + return ret; } int unicast_send_skb(struct sk_buff *skb, struct bat_priv *bat_priv) diff --git a/net/batman-adv/vis.c b/net/batman-adv/vis.c index d4cc4f5..c8f571d 100644 --- a/net/batman-adv/vis.c +++ b/net/batman-adv/vis.c @@ -204,6 +204,7 @@ static ssize_t vis_data_read_entry(char *buff, struct vis_info_entry *entry, int vis_seq_print_text(struct seq_file *seq, void *offset) { + struct hard_iface *primary_if; struct hlist_node *node; struct hlist_head *head; struct vis_info *info; @@ -215,15 +216,18 @@ int vis_seq_print_text(struct seq_file *seq, void *offset) HLIST_HEAD(vis_if_list); struct if_list_entry *entry; struct hlist_node *pos, *n; - int i, j; + int i, j, ret = 0; int vis_server = atomic_read(&bat_priv->vis_mode); size_t buff_pos, buf_size; char *buff; int compare; - if ((!bat_priv->primary_if) || - (vis_server == VIS_TYPE_CLIENT_UPDATE)) - return 0; + primary_if = primary_if_get_selected(bat_priv); + if (!primary_if) + goto out; + + if (vis_server == VIS_TYPE_CLIENT_UPDATE) + goto out; buf_size = 1; /* Estimate length */ @@ -270,7 +274,8 @@ int vis_seq_print_text(struct seq_file *seq, void *offset) buff = kmalloc(buf_size, GFP_ATOMIC); if (!buff) { spin_unlock_bh(&bat_priv->vis_hash_lock); - return -ENOMEM; + ret = -ENOMEM; + goto out; } buff[0] = '\0'; buff_pos = 0; @@ -328,7 +333,10 @@ int vis_seq_print_text(struct seq_file *seq, void *offset) seq_printf(seq, "%s", buff); kfree(buff); - return 0; +out: + if (primary_if) + hardif_free_ref(primary_if); + return ret; } /* add the info packet to the send list, if it was not @@ -815,16 +823,20 @@ out: /* only send one vis packet. called from send_vis_packets() */ static void send_vis_packet(struct bat_priv *bat_priv, struct vis_info *info) { + struct hard_iface *primary_if; struct vis_packet *packet; + primary_if = primary_if_get_selected(bat_priv); + if (!primary_if) + goto out; + packet = (struct vis_packet *)info->skb_packet->data; if (packet->ttl < 2) { pr_debug("Error - can't send vis packet: ttl exceeded\n"); - return; + goto out; } - memcpy(packet->sender_orig, bat_priv->primary_if->net_dev->dev_addr, - ETH_ALEN); + memcpy(packet->sender_orig, primary_if->net_dev->dev_addr, ETH_ALEN); packet->ttl--; if (is_broadcast_ether_addr(packet->target_orig)) @@ -832,6 +844,10 @@ static void send_vis_packet(struct bat_priv *bat_priv, struct vis_info *info) else unicast_vis_packet(bat_priv, info); packet->ttl++; /* restore TTL */ + +out: + if (primary_if) + hardif_free_ref(primary_if); } /* called from timer; send (and maybe generate) vis packet. */ @@ -858,8 +874,7 @@ static void send_vis_packets(struct work_struct *work) kref_get(&info->refcount); spin_unlock_bh(&bat_priv->vis_hash_lock); - if (bat_priv->primary_if) - send_vis_packet(bat_priv, info); + send_vis_packet(bat_priv, info); spin_lock_bh(&bat_priv->vis_hash_lock); send_list_del(info); -- cgit v0.10.2 From 134a4e27a2c4372f23b94fd3be041133cb69b52a Mon Sep 17 00:00:00 2001 From: Vasu Dev Date: Thu, 28 Apr 2011 15:55:44 -0700 Subject: [SCSI] bnx2fc: setup em for npiv port Use fc_exch_mgr_list_clone to setup em for npiv port. Also remove redundant vport and lport initializations. Signed-off-by: Vasu Dev Acked-by: Bhanu Prakash Gollapudi Signed-off-by: James Bottomley diff --git a/drivers/scsi/bnx2fc/bnx2fc_fcoe.c b/drivers/scsi/bnx2fc/bnx2fc_fcoe.c index 139955a..6623656 100644 --- a/drivers/scsi/bnx2fc/bnx2fc_fcoe.c +++ b/drivers/scsi/bnx2fc/bnx2fc_fcoe.c @@ -1254,20 +1254,17 @@ setup_err: static struct fc_lport *bnx2fc_if_create(struct bnx2fc_hba *hba, struct device *parent, int npiv) { - struct fc_lport *lport = NULL; + struct fc_lport *lport, *n_port; struct fcoe_port *port; struct Scsi_Host *shost; struct fc_vport *vport = dev_to_vport(parent); int rc = 0; /* Allocate Scsi_Host structure */ - if (!npiv) { - lport = libfc_host_alloc(&bnx2fc_shost_template, - sizeof(struct fcoe_port)); - } else { - lport = libfc_vport_create(vport, - sizeof(struct fcoe_port)); - } + if (!npiv) + lport = libfc_host_alloc(&bnx2fc_shost_template, sizeof(*port)); + else + lport = libfc_vport_create(vport, sizeof(*port)); if (!lport) { printk(KERN_ERR PFX "could not allocate scsi host structure\n"); @@ -1285,7 +1282,6 @@ static struct fc_lport *bnx2fc_if_create(struct bnx2fc_hba *hba, goto lp_config_err; if (npiv) { - vport = dev_to_vport(parent); printk(KERN_ERR PFX "Setting vport names, 0x%llX 0x%llX\n", vport->node_name, vport->port_name); fc_set_wwnn(lport, vport->node_name); @@ -1314,12 +1310,17 @@ static struct fc_lport *bnx2fc_if_create(struct bnx2fc_hba *hba, fc_host_port_type(lport->host) = FC_PORTTYPE_UNKNOWN; /* Allocate exchange manager */ - if (!npiv) { + if (!npiv) rc = bnx2fc_em_config(lport); - if (rc) { - printk(KERN_ERR PFX "Error on bnx2fc_em_config\n"); - goto shost_err; - } + else { + shost = vport_to_shost(vport); + n_port = shost_priv(shost); + rc = fc_exch_mgr_list_clone(n_port, lport); + } + + if (rc) { + printk(KERN_ERR PFX "Error on bnx2fc_em_config\n"); + goto shost_err; } bnx2fc_interface_get(hba); -- cgit v0.10.2 From 8b7eb86f61a10132aad7f90e89a15dc89e495d9e Mon Sep 17 00:00:00 2001 From: Tomas Henzl Date: Fri, 29 Apr 2011 16:28:24 +0200 Subject: [SCSI] arcmsr: simplify some double loops in sleeping functions I removed outer loops in ...wait_msgint_ready the sleeptime and retrycount are in fact never changed so I changed them into defines. In arcmsr_flush_hba_cache is a loop removed, which printed the same printk 100 times, one line in log is enough I think. The arcmsr_sleep_for_bus_reset has lost a functionality with the latest patches, The only thing the function does is a long sleep, so it's replaced with a ssleep. [jejb: checkpatch fixes] Signed-off-by: Tomas henzl Acked-by: Nick Cheng Signed-off-by: James Bottomley diff --git a/drivers/scsi/arcmsr/arcmsr_hba.c b/drivers/scsi/arcmsr/arcmsr_hba.c index da7b988..a47327f 100644 --- a/drivers/scsi/arcmsr/arcmsr_hba.c +++ b/drivers/scsi/arcmsr/arcmsr_hba.c @@ -75,8 +75,10 @@ MODULE_AUTHOR("Nick Cheng "); MODULE_DESCRIPTION("ARECA (ARC11xx/12xx/16xx/1880) SATA/SAS RAID Host Bus Adapter"); MODULE_LICENSE("Dual BSD/GPL"); MODULE_VERSION(ARCMSR_DRIVER_VERSION); -static int sleeptime = 10; -static int retrycount = 12; + +#define ARCMSR_SLEEPTIME 10 +#define ARCMSR_RETRYCOUNT 12 + wait_queue_head_t wait_q; static int arcmsr_iop_message_xfer(struct AdapterControlBlock *acb, struct scsi_cmnd *cmd); @@ -171,24 +173,6 @@ static struct pci_driver arcmsr_pci_driver = { **************************************************************************** **************************************************************************** */ -int arcmsr_sleep_for_bus_reset(struct scsi_cmnd *cmd) -{ - struct Scsi_Host *shost = NULL; - int i, isleep; - shost = cmd->device->host; - isleep = sleeptime / 10; - if (isleep > 0) { - for (i = 0; i < isleep; i++) { - msleep(10000); - } - } - - isleep = sleeptime % 10; - if (isleep > 0) { - msleep(isleep*1000); - } - return 0; -} static void arcmsr_free_hbb_mu(struct AdapterControlBlock *acb) { @@ -323,66 +307,64 @@ static void arcmsr_define_adapter_type(struct AdapterControlBlock *acb) default: acb->adapter_type = ACB_ADAPTER_TYPE_A; } -} +} static uint8_t arcmsr_hba_wait_msgint_ready(struct AdapterControlBlock *acb) { struct MessageUnit_A __iomem *reg = acb->pmuA; - uint32_t Index; - uint8_t Retries = 0x00; - do { - for (Index = 0; Index < 100; Index++) { - if (readl(®->outbound_intstatus) & - ARCMSR_MU_OUTBOUND_MESSAGE0_INT) { - writel(ARCMSR_MU_OUTBOUND_MESSAGE0_INT, - ®->outbound_intstatus); - return true; - } - msleep(10); - }/*max 1 seconds*/ + int i; + + for (i = 0; i < 2000; i++) { + if (readl(®->outbound_intstatus) & + ARCMSR_MU_OUTBOUND_MESSAGE0_INT) { + writel(ARCMSR_MU_OUTBOUND_MESSAGE0_INT, + ®->outbound_intstatus); + return true; + } + msleep(10); + } /* max 20 seconds */ - } while (Retries++ < 20);/*max 20 sec*/ return false; } static uint8_t arcmsr_hbb_wait_msgint_ready(struct AdapterControlBlock *acb) { struct MessageUnit_B *reg = acb->pmuB; - uint32_t Index; - uint8_t Retries = 0x00; - do { - for (Index = 0; Index < 100; Index++) { - if (readl(reg->iop2drv_doorbell) - & ARCMSR_IOP2DRV_MESSAGE_CMD_DONE) { - writel(ARCMSR_MESSAGE_INT_CLEAR_PATTERN - , reg->iop2drv_doorbell); - writel(ARCMSR_DRV2IOP_END_OF_INTERRUPT, reg->drv2iop_doorbell); - return true; - } - msleep(10); - }/*max 1 seconds*/ + int i; + + for (i = 0; i < 2000; i++) { + if (readl(reg->iop2drv_doorbell) + & ARCMSR_IOP2DRV_MESSAGE_CMD_DONE) { + writel(ARCMSR_MESSAGE_INT_CLEAR_PATTERN, + reg->iop2drv_doorbell); + writel(ARCMSR_DRV2IOP_END_OF_INTERRUPT, + reg->drv2iop_doorbell); + return true; + } + msleep(10); + } /* max 20 seconds */ - } while (Retries++ < 20);/*max 20 sec*/ return false; } static uint8_t arcmsr_hbc_wait_msgint_ready(struct AdapterControlBlock *pACB) { struct MessageUnit_C *phbcmu = (struct MessageUnit_C *)pACB->pmuC; - unsigned char Retries = 0x00; - uint32_t Index; - do { - for (Index = 0; Index < 100; Index++) { - if (readl(&phbcmu->outbound_doorbell) & ARCMSR_HBCMU_IOP2DRV_MESSAGE_CMD_DONE) { - writel(ARCMSR_HBCMU_IOP2DRV_MESSAGE_CMD_DONE_DOORBELL_CLEAR, &phbcmu->outbound_doorbell_clear);/*clear interrupt*/ - return true; - } - /* one us delay */ - msleep(10); - } /*max 1 seconds*/ - } while (Retries++ < 20); /*max 20 sec*/ + int i; + + for (i = 0; i < 2000; i++) { + if (readl(&phbcmu->outbound_doorbell) + & ARCMSR_HBCMU_IOP2DRV_MESSAGE_CMD_DONE) { + writel(ARCMSR_HBCMU_IOP2DRV_MESSAGE_CMD_DONE_DOORBELL_CLEAR, + &phbcmu->outbound_doorbell_clear); /*clear interrupt*/ + return true; + } + msleep(10); + } /* max 20 seconds */ + return false; } + static void arcmsr_flush_hba_cache(struct AdapterControlBlock *acb) { struct MessageUnit_A __iomem *reg = acb->pmuA; @@ -2602,12 +2584,8 @@ static int arcmsr_iop_confirm(struct AdapterControlBlock *acb) if (cdb_phyaddr_hi32 != 0) { struct MessageUnit_C *reg = (struct MessageUnit_C *)acb->pmuC; - if (cdb_phyaddr_hi32 != 0) { - unsigned char Retries = 0x00; - do { - printk(KERN_NOTICE "arcmsr%d: cdb_phyaddr_hi32=0x%x \n", acb->adapter_index, cdb_phyaddr_hi32); - } while (Retries++ < 100); - } + printk(KERN_NOTICE "arcmsr%d: cdb_phyaddr_hi32=0x%x\n", + acb->adapter_index, cdb_phyaddr_hi32); writel(ARCMSR_SIGNATURE_SET_CONFIG, ®->msgcode_rwbuffer[0]); writel(cdb_phyaddr_hi32, ®->msgcode_rwbuffer[1]); writel(ARCMSR_INBOUND_MESG0_SET_CONFIG, ®->inbound_msgaddr0); @@ -2955,12 +2933,12 @@ static int arcmsr_bus_reset(struct scsi_cmnd *cmd) arcmsr_hardware_reset(acb); acb->acb_flags &= ~ACB_F_IOP_INITED; sleep_again: - arcmsr_sleep_for_bus_reset(cmd); + ssleep(ARCMSR_SLEEPTIME); if ((readl(®->outbound_msgaddr1) & ARCMSR_OUTBOUND_MESG1_FIRMWARE_OK) == 0) { - printk(KERN_ERR "arcmsr%d: waiting for hw bus reset return, retry=%d \n", acb->host->host_no, retry_count); - if (retry_count > retrycount) { + printk(KERN_ERR "arcmsr%d: waiting for hw bus reset return, retry=%d\n", acb->host->host_no, retry_count); + if (retry_count > ARCMSR_RETRYCOUNT) { acb->fw_flag = FW_DEADLOCK; - printk(KERN_ERR "arcmsr%d: waiting for hw bus reset return, RETRY TERMINATED!! \n", acb->host->host_no); + printk(KERN_ERR "arcmsr%d: waiting for hw bus reset return, RETRY TERMINATED!!\n", acb->host->host_no); return FAILED; } retry_count++; @@ -3025,12 +3003,12 @@ sleep_again: arcmsr_hardware_reset(acb); acb->acb_flags &= ~ACB_F_IOP_INITED; sleep: - arcmsr_sleep_for_bus_reset(cmd); + ssleep(ARCMSR_SLEEPTIME); if ((readl(®->host_diagnostic) & 0x04) != 0) { - printk(KERN_ERR "arcmsr%d: waiting for hw bus reset return, retry=%d \n", acb->host->host_no, retry_count); - if (retry_count > retrycount) { + printk(KERN_ERR "arcmsr%d: waiting for hw bus reset return, retry=%d\n", acb->host->host_no, retry_count); + if (retry_count > ARCMSR_RETRYCOUNT) { acb->fw_flag = FW_DEADLOCK; - printk(KERN_ERR "arcmsr%d: waiting for hw bus reset return, RETRY TERMINATED!! \n", acb->host->host_no); + printk(KERN_ERR "arcmsr%d: waiting for hw bus reset return, RETRY TERMINATED!!\n", acb->host->host_no); return FAILED; } retry_count++; -- cgit v0.10.2 From 87f76152dfb1bf3de18dc01cf97c70a5c9d2583e Mon Sep 17 00:00:00 2001 From: Tomas Henzl Date: Fri, 29 Apr 2011 16:28:30 +0200 Subject: [SCSI] arcmsr: simplify assumptions in dma_alloc_coherent() The code currently computes an offset into a dma_alloc_coherent() area on the assumption that the alignment is imprecise. In fact, the API guarantees PAGE_SIZE alignment, so the offset calculation is always zero: remove it. [jejb: make description actually descriptive] Signed-off-by: Tomas henzl Acked-by: Nick Cheng Signed-off-by: James Bottomley diff --git a/drivers/scsi/arcmsr/arcmsr_hba.c b/drivers/scsi/arcmsr/arcmsr_hba.c index a47327f..f980600 100644 --- a/drivers/scsi/arcmsr/arcmsr_hba.c +++ b/drivers/scsi/arcmsr/arcmsr_hba.c @@ -441,10 +441,11 @@ static int arcmsr_alloc_ccb_pool(struct AdapterControlBlock *acb) struct CommandControlBlock *ccb_tmp; int i = 0, j = 0; dma_addr_t cdb_phyaddr; - unsigned long roundup_ccbsize = 0, offset; + unsigned long roundup_ccbsize; unsigned long max_xfer_len; unsigned long max_sg_entrys; uint32_t firm_config_version; + for (i = 0; i < ARCMSR_MAX_TARGETID; i++) for (j = 0; j < ARCMSR_MAX_TARGETLUN; j++) acb->devstate[i][j] = ARECA_RAID_GONE; @@ -454,23 +455,20 @@ static int arcmsr_alloc_ccb_pool(struct AdapterControlBlock *acb) firm_config_version = acb->firm_cfg_version; if((firm_config_version & 0xFF) >= 3){ max_xfer_len = (ARCMSR_CDB_SG_PAGE_LENGTH << ((firm_config_version >> 8) & 0xFF)) * 1024;/* max 4M byte */ - max_sg_entrys = (max_xfer_len/4096); + max_sg_entrys = (max_xfer_len/4096); } acb->host->max_sectors = max_xfer_len/512; acb->host->sg_tablesize = max_sg_entrys; roundup_ccbsize = roundup(sizeof(struct CommandControlBlock) + (max_sg_entrys - 1) * sizeof(struct SG64ENTRY), 32); - acb->uncache_size = roundup_ccbsize * ARCMSR_MAX_FREECCB_NUM + 32; + acb->uncache_size = roundup_ccbsize * ARCMSR_MAX_FREECCB_NUM; dma_coherent = dma_alloc_coherent(&pdev->dev, acb->uncache_size, &dma_coherent_handle, GFP_KERNEL); if(!dma_coherent){ - printk(KERN_NOTICE "arcmsr%d: dma_alloc_coherent got error \n", acb->host->host_no); + printk(KERN_NOTICE "arcmsr%d: dma_alloc_coherent got error\n", acb->host->host_no); return -ENOMEM; } acb->dma_coherent = dma_coherent; acb->dma_coherent_handle = dma_coherent_handle; memset(dma_coherent, 0, acb->uncache_size); - offset = roundup((unsigned long)dma_coherent, 32) - (unsigned long)dma_coherent; - dma_coherent_handle = dma_coherent_handle + offset; - dma_coherent = (struct CommandControlBlock *)dma_coherent + offset; ccb_tmp = dma_coherent; acb->vir2phy_offset = (unsigned long)dma_coherent - (unsigned long)dma_coherent_handle; for(i = 0; i < ARCMSR_MAX_FREECCB_NUM; i++){ -- cgit v0.10.2 From 665d6d94b73f1d706d6c006264cce7537ac708f4 Mon Sep 17 00:00:00 2001 From: Jayamohan Kallickal Date: Fri, 29 Apr 2011 14:30:06 -0500 Subject: [SCSI] be2iscsi: fix boot hang due to interrupts not getting rearmed This patch fixes a bug where the interrupts were not rearmed if the Interrupt Mask was enabled. This patch checks for Interrupt mask enabled and still rearms interrupt generation even if the Interrupt mask was enabled Signed-off-by: Jayamohan Kallickal Signed-off-by: Mike Christie Signed-off-by: James Bottomley diff --git a/drivers/scsi/be2iscsi/be_main.c b/drivers/scsi/be2iscsi/be_main.c index d834136..cea9b27 100644 --- a/drivers/scsi/be2iscsi/be_main.c +++ b/drivers/scsi/be2iscsi/be_main.c @@ -3465,23 +3465,23 @@ static void hwi_enable_intr(struct beiscsi_hba *phba) addr = (u8 __iomem *) ((u8 __iomem *) ctrl->pcicfg + PCICFG_MEMBAR_CTRL_INT_CTRL_OFFSET); reg = ioread32(addr); - SE_DEBUG(DBG_LVL_8, "reg =x%08x\n", reg); enabled = reg & MEMBAR_CTRL_INT_CTRL_HOSTINTR_MASK; if (!enabled) { reg |= MEMBAR_CTRL_INT_CTRL_HOSTINTR_MASK; SE_DEBUG(DBG_LVL_8, "reg =x%08x addr=%p\n", reg, addr); iowrite32(reg, addr); - if (!phba->msix_enabled) { - eq = &phwi_context->be_eq[0].q; + } + + if (!phba->msix_enabled) { + eq = &phwi_context->be_eq[0].q; + SE_DEBUG(DBG_LVL_8, "eq->id=%d\n", eq->id); + hwi_ring_eq_db(phba, eq->id, 0, 0, 1, 1); + } else { + for (i = 0; i <= phba->num_cpus; i++) { + eq = &phwi_context->be_eq[i].q; SE_DEBUG(DBG_LVL_8, "eq->id=%d\n", eq->id); hwi_ring_eq_db(phba, eq->id, 0, 0, 1, 1); - } else { - for (i = 0; i <= phba->num_cpus; i++) { - eq = &phwi_context->be_eq[i].q; - SE_DEBUG(DBG_LVL_8, "eq->id=%d\n", eq->id); - hwi_ring_eq_db(phba, eq->id, 0, 0, 1, 1); - } } } } -- cgit v0.10.2 From 069adc7b0617348dd4c5cace1b35a90d6ddf1013 Mon Sep 17 00:00:00 2001 From: Jayamohan Kallickal Date: Fri, 29 Apr 2011 14:30:07 -0500 Subject: [SCSI] be2iscsi: fix chip cleanup This patch fixes a bug where proper queue id's were not passed to chip for cleanup. Signed-off-by: Jayamohan Kallickal Signed-off-by: Mike Christie Signed-off-by: James Bottomley diff --git a/drivers/scsi/be2iscsi/be_mgmt.c b/drivers/scsi/be2iscsi/be_mgmt.c index 65a402b..44762cf 100644 --- a/drivers/scsi/be2iscsi/be_mgmt.c +++ b/drivers/scsi/be2iscsi/be_mgmt.c @@ -202,8 +202,8 @@ int mgmt_epfw_cleanup(struct beiscsi_hba *phba, unsigned short chute) OPCODE_COMMON_ISCSI_CLEANUP, sizeof(*req)); req->chute = chute; - req->hdr_ring_id = 0; - req->data_ring_id = 0; + req->hdr_ring_id = cpu_to_le16(HWI_GET_DEF_HDRQ_ID(phba)); + req->data_ring_id = cpu_to_le16(HWI_GET_DEF_BUFQ_ID(phba)); status = be_mcc_notify_wait(phba); if (status) -- cgit v0.10.2 From 8a025bbc8ff897c36c6e2b91c2e852ea5e569394 Mon Sep 17 00:00:00 2001 From: Jayamohan Kallickal Date: Fri, 29 Apr 2011 14:30:08 -0500 Subject: [SCSI] be2iscsi: update version Bump version. Signed-off-by: Jayamohan Kallickal Signed-off-by: Mike Christie Signed-off-by: James Bottomley diff --git a/drivers/scsi/be2iscsi/be_main.h b/drivers/scsi/be2iscsi/be_main.h index 1f7c495..081c171 100644 --- a/drivers/scsi/be2iscsi/be_main.h +++ b/drivers/scsi/be2iscsi/be_main.h @@ -34,7 +34,7 @@ #include "be.h" #define DRV_NAME "be2iscsi" -#define BUILD_STR "2.0.549.0" +#define BUILD_STR "2.103.298.0" #define BE_NAME "ServerEngines BladeEngine2" \ "Linux iSCSI Driver version" BUILD_STR #define DRV_DESC BE_NAME " " "Driver" -- cgit v0.10.2 From a05d2ad1c1f391c7f514a1d1e09b5417968a7d07 Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Sun, 24 Apr 2011 01:54:57 +0000 Subject: af_unix: Only allow recv on connected seqpacket sockets. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This fixes the following oops discovered by Dan Aloni: > Anyway, the following is the output of the Oops that I got on the > Ubuntu kernel on which I first detected the problem > (2.6.37-12-generic). The Oops that followed will be more useful, I > guess. >[ 5594.669852] BUG: unable to handle kernel NULL pointer dereference > at           (null) > [ 5594.681606] IP: [] unix_dgram_recvmsg+0x1fb/0x420 > [ 5594.687576] PGD 2a05d067 PUD 2b951067 PMD 0 > [ 5594.693720] Oops: 0002 [#1] SMP > [ 5594.699888] last sysfs file: The bug was that unix domain sockets use a pseduo packet for connecting and accept uses that psudo packet to get the socket. In the buggy seqpacket case we were allowing unconnected sockets to call recvmsg and try to receive the pseudo packet. That is always wrong and as of commit 7361c36c5 the pseudo packet had become enough different from a normal packet that the kernel started oopsing. Do for seqpacket_recv what was done for seqpacket_send in 2.5 and only allow it on connected seqpacket sockets. Cc: stable@kernel.org Tested-by: Dan Aloni Signed-off-by: Eric W. Biederman Signed-off-by: David S. Miller diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c index 3a43a83..b1d75be 100644 --- a/net/unix/af_unix.c +++ b/net/unix/af_unix.c @@ -524,6 +524,8 @@ static int unix_dgram_connect(struct socket *, struct sockaddr *, int, int); static int unix_seqpacket_sendmsg(struct kiocb *, struct socket *, struct msghdr *, size_t); +static int unix_seqpacket_recvmsg(struct kiocb *, struct socket *, + struct msghdr *, size_t, int); static const struct proto_ops unix_stream_ops = { .family = PF_UNIX, @@ -583,7 +585,7 @@ static const struct proto_ops unix_seqpacket_ops = { .setsockopt = sock_no_setsockopt, .getsockopt = sock_no_getsockopt, .sendmsg = unix_seqpacket_sendmsg, - .recvmsg = unix_dgram_recvmsg, + .recvmsg = unix_seqpacket_recvmsg, .mmap = sock_no_mmap, .sendpage = sock_no_sendpage, }; @@ -1699,6 +1701,18 @@ static int unix_seqpacket_sendmsg(struct kiocb *kiocb, struct socket *sock, return unix_dgram_sendmsg(kiocb, sock, msg, len); } +static int unix_seqpacket_recvmsg(struct kiocb *iocb, struct socket *sock, + struct msghdr *msg, size_t size, + int flags) +{ + struct sock *sk = sock->sk; + + if (sk->sk_state != TCP_ESTABLISHED) + return -ENOTCONN; + + return unix_dgram_recvmsg(iocb, sock, msg, size, flags); +} + static void unix_copy_addr(struct msghdr *msg, struct sock *sk) { struct unix_sock *u = unix_sk(sk); -- cgit v0.10.2 From 7cfd260910b881250cde76ba92ebe3cbf8493a8f Mon Sep 17 00:00:00 2001 From: Alexey Dobriyan Date: Sun, 1 May 2011 02:04:11 +0000 Subject: ipv4: don't spam dmesg with "Using LC-trie" messages fib_trie_table() is called during netns creation and Chromium uses clone(CLONE_NEWNET) to sandbox renderer process. Don't print anything. Signed-off-by: Alexey Dobriyan Signed-off-by: David S. Miller diff --git a/net/ipv4/fib_trie.c b/net/ipv4/fib_trie.c index e9013d6..5fe9b8b 100644 --- a/net/ipv4/fib_trie.c +++ b/net/ipv4/fib_trie.c @@ -1978,9 +1978,6 @@ struct fib_table *fib_trie_table(u32 id) t = (struct trie *) tb->tb_data; memset(t, 0, sizeof(*t)); - if (id == RT_TABLE_LOCAL) - pr_info("IPv4 FIB: Using LC-trie version %s\n", VERSION); - return tb; } -- cgit v0.10.2 From 564f59509e26355965949c677f9d6eb064a3aa0b Mon Sep 17 00:00:00 2001 From: Shahar Levi Date: Mon, 4 Apr 2011 10:20:39 +0300 Subject: wl12xx: Set End-of-transaction Flag at Wl127x AP Mode End-of-transaction flag should be set when working with wl127x chip on AP mode. Thanks Ido Yariv for the guidance with that. Signed-off-by: Shahar Levi Signed-off-by: Luciano Coelho diff --git a/drivers/net/wireless/wl12xx/main.c b/drivers/net/wireless/wl12xx/main.c index 0c69e95..11497a9 100644 --- a/drivers/net/wireless/wl12xx/main.c +++ b/drivers/net/wireless/wl12xx/main.c @@ -1011,6 +1011,10 @@ static int wl1271_chip_wakeup(struct wl1271 *wl) wl1271_debug(DEBUG_BOOT, "chip id 0x%x (1271 PG20)", wl->chip.id); + /* end-of-transaction flag should be set in wl127x AP mode */ + if (wl->bss_type == BSS_TYPE_AP_BSS) + wl->quirks |= WL12XX_QUIRK_END_OF_TRANSACTION; + ret = wl1271_setup(wl); if (ret < 0) goto out; -- cgit v0.10.2 From c75bbcdb200e2815c855e42a4685d170858af306 Mon Sep 17 00:00:00 2001 From: Eliad Peller Date: Mon, 4 Apr 2011 10:38:47 +0300 Subject: wl12xx: sleep instead of wakeup after tx work commit d05c806 ("wl12xx: rearrange some ELP wake_up/sleep calls") introduced a bug in which wl1271_ps_elp_wakeup() was called instead of wl1271_ps_elp_sleep() after completing the tx work. Reported-by: Arik Nemtsov Signed-off-by: Eliad Peller Signed-off-by: Luciano Coelho diff --git a/drivers/net/wireless/wl12xx/tx.c b/drivers/net/wireless/wl12xx/tx.c index 7a3339f..c836659 100644 --- a/drivers/net/wireless/wl12xx/tx.c +++ b/drivers/net/wireless/wl12xx/tx.c @@ -630,7 +630,7 @@ void wl1271_tx_work(struct work_struct *work) wl1271_tx_work_locked(wl); - wl1271_ps_elp_wakeup(wl); + wl1271_ps_elp_sleep(wl); out: mutex_unlock(&wl->mutex); } -- cgit v0.10.2 From a665d6e260f0233aac73f74d15bb6a029cc5ec47 Mon Sep 17 00:00:00 2001 From: Eliad Peller Date: Sun, 3 Apr 2011 02:01:59 +0300 Subject: wl12xx: avoid premature elp entrance The elp_work is being enqueued on wl1271_ps_elp_sleep, but doesn't get cancelled on wl1271_ps_elp_wakeup. This might cause immediate entrance to elp when the wl->mutex is being released, rather than using the delayed enqueueing optimization. Cancel elp_work on wakeup request, and add a new WL1271_FLAG_ELP_REQUESTED flag to further synchronize the elp actions. [Fixed a couple of typos in some comments -- Luca] Signed-off-by: Eliad Peller Signed-off-by: Luciano Coelho diff --git a/drivers/net/wireless/wl12xx/ps.c b/drivers/net/wireless/wl12xx/ps.c index b8deada..b59b6771 100644 --- a/drivers/net/wireless/wl12xx/ps.c +++ b/drivers/net/wireless/wl12xx/ps.c @@ -43,6 +43,10 @@ void wl1271_elp_work(struct work_struct *work) if (unlikely(wl->state == WL1271_STATE_OFF)) goto out; + /* our work might have been already cancelled */ + if (unlikely(!test_bit(WL1271_FLAG_ELP_REQUESTED, &wl->flags))) + goto out; + if (test_bit(WL1271_FLAG_IN_ELP, &wl->flags) || (!test_bit(WL1271_FLAG_PSM, &wl->flags) && !test_bit(WL1271_FLAG_IDLE, &wl->flags))) @@ -61,12 +65,16 @@ out: /* Routines to toggle sleep mode while in ELP */ void wl1271_ps_elp_sleep(struct wl1271 *wl) { - if (test_bit(WL1271_FLAG_PSM, &wl->flags) || - test_bit(WL1271_FLAG_IDLE, &wl->flags)) { - cancel_delayed_work(&wl->elp_work); - ieee80211_queue_delayed_work(wl->hw, &wl->elp_work, - msecs_to_jiffies(ELP_ENTRY_DELAY)); - } + /* we shouldn't get consecutive sleep requests */ + if (WARN_ON(test_and_set_bit(WL1271_FLAG_ELP_REQUESTED, &wl->flags))) + return; + + if (!test_bit(WL1271_FLAG_PSM, &wl->flags) && + !test_bit(WL1271_FLAG_IDLE, &wl->flags)) + return; + + ieee80211_queue_delayed_work(wl->hw, &wl->elp_work, + msecs_to_jiffies(ELP_ENTRY_DELAY)); } int wl1271_ps_elp_wakeup(struct wl1271 *wl) @@ -77,6 +85,16 @@ int wl1271_ps_elp_wakeup(struct wl1271 *wl) u32 start_time = jiffies; bool pending = false; + /* + * we might try to wake up even if we didn't go to sleep + * before (e.g. on boot) + */ + if (!test_and_clear_bit(WL1271_FLAG_ELP_REQUESTED, &wl->flags)) + return 0; + + /* don't cancel_sync as it might contend for a mutex and deadlock */ + cancel_delayed_work(&wl->elp_work); + if (!test_bit(WL1271_FLAG_IN_ELP, &wl->flags)) return 0; diff --git a/drivers/net/wireless/wl12xx/wl12xx.h b/drivers/net/wireless/wl12xx/wl12xx.h index 7c521af..f3de962 100644 --- a/drivers/net/wireless/wl12xx/wl12xx.h +++ b/drivers/net/wireless/wl12xx/wl12xx.h @@ -345,6 +345,7 @@ enum wl12xx_flags { WL1271_FLAG_TX_QUEUE_STOPPED, WL1271_FLAG_TX_PENDING, WL1271_FLAG_IN_ELP, + WL1271_FLAG_ELP_REQUESTED, WL1271_FLAG_PSM, WL1271_FLAG_PSM_REQUESTED, WL1271_FLAG_IRQ_RUNNING, -- cgit v0.10.2 From b03acadea4f46884aa3c3e4d3a6ce03d283525e6 Mon Sep 17 00:00:00 2001 From: Shahar Levi Date: Sun, 3 Apr 2011 13:54:54 +0300 Subject: wl12xx: Set correct REF CLK and TCXO CLK values to the FW Fix mismatch between the REF CLK and TCXO CLK information that is set in the platform data and the NVS, so we override what comes from the NVS and replace it with what comes from the platform data. [Small fix in a comment -- Luca] Signed-off-by: Shahar Levi Signed-off-by: Luciano Coelho diff --git a/drivers/net/wireless/wl12xx/cmd.c b/drivers/net/wireless/wl12xx/cmd.c index d483316..a9ffdd8 100644 --- a/drivers/net/wireless/wl12xx/cmd.c +++ b/drivers/net/wireless/wl12xx/cmd.c @@ -129,6 +129,9 @@ int wl1271_cmd_general_parms(struct wl1271 *wl) if (gp->tx_bip_fem_auto_detect) answer = true; + /* Override the REF CLK from the NVS with the one from platform data */ + gen_parms->general_params.ref_clock = wl->ref_clock; + ret = wl1271_cmd_test(wl, gen_parms, sizeof(*gen_parms), answer); if (ret < 0) { wl1271_warning("CMD_INI_FILE_GENERAL_PARAM failed"); @@ -168,6 +171,10 @@ int wl128x_cmd_general_parms(struct wl1271 *wl) if (gp->tx_bip_fem_auto_detect) answer = true; + /* Replace REF and TCXO CLKs with the ones from platform data */ + gen_parms->general_params.ref_clock = wl->ref_clock; + gen_parms->general_params.tcxo_ref_clock = wl->tcxo_clock; + ret = wl1271_cmd_test(wl, gen_parms, sizeof(*gen_parms), answer); if (ret < 0) { wl1271_warning("CMD_INI_FILE_GENERAL_PARAM failed"); -- cgit v0.10.2 From a20a5b7e48e24c1bf9c10ba27cb1862f8f777d00 Mon Sep 17 00:00:00 2001 From: Eliad Peller Date: Tue, 5 Apr 2011 18:21:31 +0300 Subject: wl12xx: print actual rx packet size (without padding) When debugging, reduce the padding size from each rx packet, to get the actual packet size (so comparing it against a cap file will be easier) Signed-off-by: Eliad Peller Signed-off-by: Luciano Coelho diff --git a/drivers/net/wireless/wl12xx/rx.c b/drivers/net/wireless/wl12xx/rx.c index 2a58149..faf5a1d 100644 --- a/drivers/net/wireless/wl12xx/rx.c +++ b/drivers/net/wireless/wl12xx/rx.c @@ -121,7 +121,8 @@ static int wl1271_rx_handle_data(struct wl1271 *wl, u8 *data, u32 length) wl1271_rx_status(wl, desc, IEEE80211_SKB_RXCB(skb), beacon); - wl1271_debug(DEBUG_RX, "rx skb 0x%p: %d B %s", skb, skb->len, + wl1271_debug(DEBUG_RX, "rx skb 0x%p: %d B %s", skb, + skb->len - desc->pad_len, beacon ? "beacon" : ""); skb_trim(skb, skb->len - desc->pad_len); -- cgit v0.10.2 From 30df14d0d35dd166d50b8ea80d5f0b7ef1edb6da Mon Sep 17 00:00:00 2001 From: Eliad Peller Date: Tue, 5 Apr 2011 19:13:28 +0300 Subject: wl12xx: avoid redundant join on interface reconfiguration ieee80211_reconfig() sets most of the "changed" flags regardless of the actual change (e.g. BSS_CHANGED_ASSOC will be set even if the interface is still not associated). in this case the driver will issue some unneeded commands. Since the driver relies solely on the BSS_CHANGED_ASSOC flag, without checking if there was an actual change, it will end up issuing unjoin() and dummy_join() commands, although it was never associated and should just remain idle. Avoid it by checking the actual state change, in addition to the "changed" flag. (there seem to be more redundant configuration commands being issued, but they shouldn't harm) Signed-off-by: Eliad Peller Signed-off-by: Luciano Coelho diff --git a/drivers/net/wireless/wl12xx/main.c b/drivers/net/wireless/wl12xx/main.c index 11497a9..1dd735c 100644 --- a/drivers/net/wireless/wl12xx/main.c +++ b/drivers/net/wireless/wl12xx/main.c @@ -2698,8 +2698,10 @@ static void wl1271_bss_info_changed_sta(struct wl1271 *wl, } } else { /* use defaults when not associated */ + bool was_assoc = + !!test_and_clear_bit(WL1271_FLAG_STA_ASSOCIATED, + &wl->flags); clear_bit(WL1271_FLAG_STA_STATE_SENT, &wl->flags); - clear_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags); wl->aid = 0; /* free probe-request template */ @@ -2725,8 +2727,10 @@ static void wl1271_bss_info_changed_sta(struct wl1271 *wl, goto out; /* restore the bssid filter and go to dummy bssid */ - wl1271_unjoin(wl); - wl1271_dummy_join(wl); + if (was_assoc) { + wl1271_unjoin(wl); + wl1271_dummy_join(wl); + } } } -- cgit v0.10.2 From cb5ae0530e0e2af86d128ce758645b6b4a9132e1 Mon Sep 17 00:00:00 2001 From: Eliad Peller Date: Thu, 7 Apr 2011 15:52:05 +0300 Subject: wl12xx: configure rates when working in ibss mode When working in ibss mode, we don't configure rate policy per station (as we use the same link for multiple stations), so currently the 1mb/s rate is being used. Instead, configure the firmware to use the whole 11b rates by default. Signed-off-by: Eliad Peller Signed-off-by: Luciano Coelho diff --git a/drivers/net/wireless/wl12xx/conf.h b/drivers/net/wireless/wl12xx/conf.h index d16094f..5551d9d 100644 --- a/drivers/net/wireless/wl12xx/conf.h +++ b/drivers/net/wireless/wl12xx/conf.h @@ -516,6 +516,13 @@ struct conf_rx_settings { #define CONF_TX_AP_DEFAULT_MGMT_RATES (CONF_HW_BIT_RATE_1MBPS | \ CONF_HW_BIT_RATE_2MBPS | CONF_HW_BIT_RATE_5_5MBPS) +/* + * Default rates for working as IBSS. use 11b rates + */ +#define CONF_TX_IBSS_DEFAULT_RATES (CONF_HW_BIT_RATE_1MBPS | \ + CONF_HW_BIT_RATE_2MBPS | CONF_HW_BIT_RATE_5_5MBPS | \ + CONF_HW_BIT_RATE_11MBPS); + struct conf_tx_rate_class { /* diff --git a/drivers/net/wireless/wl12xx/main.c b/drivers/net/wireless/wl12xx/main.c index 1dd735c..53a8e23 100644 --- a/drivers/net/wireless/wl12xx/main.c +++ b/drivers/net/wireless/wl12xx/main.c @@ -2509,6 +2509,24 @@ static void wl1271_bss_info_changed_ap(struct wl1271 *wl, } } + if (changed & BSS_CHANGED_IBSS) { + wl1271_debug(DEBUG_ADHOC, "ibss_joined: %d", + bss_conf->ibss_joined); + + if (bss_conf->ibss_joined) { + u32 rates = bss_conf->basic_rates; + wl->basic_rate_set = wl1271_tx_enabled_rates_get(wl, + rates); + wl->basic_rate = wl1271_tx_min_rate_get(wl); + + /* by default, use 11b rates */ + wl->rate_set = CONF_TX_IBSS_DEFAULT_RATES; + ret = wl1271_acx_sta_rate_policies(wl); + if (ret < 0) + goto out; + } + } + ret = wl1271_bss_erp_info_changed(wl, bss_conf, changed); if (ret < 0) goto out; -- cgit v0.10.2 From ff86843dfbb368766d0aecd0147821d9a2b60edb Mon Sep 17 00:00:00 2001 From: Shahar Levi Date: Mon, 11 Apr 2011 15:41:46 +0300 Subject: wl12xx: FM WLAN coexistence Add support to FM WLAN coexistence (STA only). Some WiFi harmonics may interfere with FM operation, to avoid this problem special coexistence techniques are activated around some FM frequencies. Signed-off-by: Shahar Levi Signed-off-by: Luciano Coelho diff --git a/drivers/net/wireless/wl12xx/acx.c b/drivers/net/wireless/wl12xx/acx.c index a5c9c0a..8a39d1e 100644 --- a/drivers/net/wireless/wl12xx/acx.c +++ b/drivers/net/wireless/wl12xx/acx.c @@ -1626,3 +1626,43 @@ out: kfree(acx); return ret; } + +int wl1271_acx_fm_coex(struct wl1271 *wl) +{ + struct wl1271_acx_fm_coex *acx; + int ret; + + wl1271_debug(DEBUG_ACX, "acx fm coex setting"); + + acx = kzalloc(sizeof(*acx), GFP_KERNEL); + if (!acx) { + ret = -ENOMEM; + goto out; + } + + acx->enable = wl->conf.fm_coex.enable; + acx->swallow_period = wl->conf.fm_coex.swallow_period; + acx->n_divider_fref_set_1 = wl->conf.fm_coex.n_divider_fref_set_1; + acx->n_divider_fref_set_2 = wl->conf.fm_coex.n_divider_fref_set_2; + acx->m_divider_fref_set_1 = + cpu_to_le16(wl->conf.fm_coex.m_divider_fref_set_1); + acx->m_divider_fref_set_2 = + cpu_to_le16(wl->conf.fm_coex.m_divider_fref_set_2); + acx->coex_pll_stabilization_time = + cpu_to_le32(wl->conf.fm_coex.coex_pll_stabilization_time); + acx->ldo_stabilization_time = + cpu_to_le16(wl->conf.fm_coex.ldo_stabilization_time); + acx->fm_disturbed_band_margin = + wl->conf.fm_coex.fm_disturbed_band_margin; + acx->swallow_clk_diff = wl->conf.fm_coex.swallow_clk_diff; + + ret = wl1271_cmd_configure(wl, ACX_FM_COEX_CFG, acx, sizeof(*acx)); + if (ret < 0) { + wl1271_warning("acx fm coex setting failed: %d", ret); + goto out; + } + +out: + kfree(acx); + return ret; +} diff --git a/drivers/net/wireless/wl12xx/acx.h b/drivers/net/wireless/wl12xx/acx.h index 942908c..2dde034 100644 --- a/drivers/net/wireless/wl12xx/acx.h +++ b/drivers/net/wireless/wl12xx/acx.h @@ -1179,6 +1179,65 @@ struct wl1271_acx_inconnection_sta { u8 padding1[2]; } __packed; +/* + * ACX_FM_COEX_CFG + * set the FM co-existence parameters. + */ +struct wl1271_acx_fm_coex { + struct acx_header header; + /* enable(1) / disable(0) the FM Coex feature */ + u8 enable; + /* + * Swallow period used in COEX PLL swallowing mechanism. + * 0xFF = use FW default + */ + u8 swallow_period; + /* + * The N divider used in COEX PLL swallowing mechanism for Fref of + * 38.4/19.2 Mhz. 0xFF = use FW default + */ + u8 n_divider_fref_set_1; + /* + * The N divider used in COEX PLL swallowing mechanism for Fref of + * 26/52 Mhz. 0xFF = use FW default + */ + u8 n_divider_fref_set_2; + /* + * The M divider used in COEX PLL swallowing mechanism for Fref of + * 38.4/19.2 Mhz. 0xFFFF = use FW default + */ + __le16 m_divider_fref_set_1; + /* + * The M divider used in COEX PLL swallowing mechanism for Fref of + * 26/52 Mhz. 0xFFFF = use FW default + */ + __le16 m_divider_fref_set_2; + /* + * The time duration in uSec required for COEX PLL to stabilize. + * 0xFFFFFFFF = use FW default + */ + __le32 coex_pll_stabilization_time; + /* + * The time duration in uSec required for LDO to stabilize. + * 0xFFFFFFFF = use FW default + */ + __le16 ldo_stabilization_time; + /* + * The disturbed frequency band margin around the disturbed frequency + * center (single sided). + * For example, if 2 is configured, the following channels will be + * considered disturbed channel: + * 80 +- 0.1 MHz, 91 +- 0.1 MHz, 98 +- 0.1 MHz, 102 +- 0.1 MH + * 0xFF = use FW default + */ + u8 fm_disturbed_band_margin; + /* + * The swallow clock difference of the swallowing mechanism. + * 0xFF = use FW default + */ + u8 swallow_clk_diff; +} __packed; + enum { ACX_WAKE_UP_CONDITIONS = 0x0002, ACX_MEM_CFG = 0x0003, @@ -1208,6 +1267,7 @@ enum { ACX_BCN_DTIM_OPTIONS = 0x0031, ACX_SG_ENABLE = 0x0032, ACX_SG_CFG = 0x0033, + ACX_FM_COEX_CFG = 0x0034, ACX_BEACON_FILTER_TABLE = 0x0038, ACX_ARP_IP_FILTER = 0x0039, ACX_ROAMING_STATISTICS_TBL = 0x003B, @@ -1318,5 +1378,6 @@ int wl1271_acx_ap_max_tx_retry(struct wl1271 *wl); int wl1271_acx_sta_max_tx_retry(struct wl1271 *wl); int wl1271_acx_config_ps(struct wl1271 *wl); int wl1271_acx_set_inconnection_sta(struct wl1271 *wl, u8 *addr); +int wl1271_acx_fm_coex(struct wl1271 *wl); #endif /* __WL1271_ACX_H__ */ diff --git a/drivers/net/wireless/wl12xx/conf.h b/drivers/net/wireless/wl12xx/conf.h index 5551d9d..a4e0acf 100644 --- a/drivers/net/wireless/wl12xx/conf.h +++ b/drivers/net/wireless/wl12xx/conf.h @@ -1199,6 +1199,19 @@ struct conf_memory_settings { u8 tx_min; }; +struct conf_fm_coex { + u8 enable; + u8 swallow_period; + u8 n_divider_fref_set_1; + u8 n_divider_fref_set_2; + u16 m_divider_fref_set_1; + u16 m_divider_fref_set_2; + u32 coex_pll_stabilization_time; + u16 ldo_stabilization_time; + u8 fm_disturbed_band_margin; + u8 swallow_clk_diff; +}; + struct conf_drv_settings { struct conf_sg_settings sg; struct conf_rx_settings rx; @@ -1212,6 +1225,7 @@ struct conf_drv_settings { struct conf_ht_setting ht; struct conf_memory_settings mem_wl127x; struct conf_memory_settings mem_wl128x; + struct conf_fm_coex fm_coex; u8 hci_io_ds; }; diff --git a/drivers/net/wireless/wl12xx/init.c b/drivers/net/wireless/wl12xx/init.c index ab3b1e2..46fd721 100644 --- a/drivers/net/wireless/wl12xx/init.c +++ b/drivers/net/wireless/wl12xx/init.c @@ -356,6 +356,11 @@ static int wl1271_sta_hw_init(struct wl1271 *wl) if (ret < 0) return ret; + /* FM WLAN coexistence */ + ret = wl1271_acx_fm_coex(wl); + if (ret < 0) + return ret; + /* Beacons and broadcast settings */ ret = wl1271_init_beacon_broadcast(wl); if (ret < 0) diff --git a/drivers/net/wireless/wl12xx/main.c b/drivers/net/wireless/wl12xx/main.c index 53a8e23..8a7a8c5 100644 --- a/drivers/net/wireless/wl12xx/main.c +++ b/drivers/net/wireless/wl12xx/main.c @@ -320,6 +320,18 @@ static struct conf_drv_settings default_conf = { .min_req_rx_blocks = 22, .tx_min = 27, }, + .fm_coex = { + .enable = true, + .swallow_period = 5, + .n_divider_fref_set_1 = 0xff, /* default */ + .n_divider_fref_set_2 = 12, + .m_divider_fref_set_1 = 148, + .m_divider_fref_set_2 = 0xffff, /* default */ + .coex_pll_stabilization_time = 0xffffffff, /* default */ + .ldo_stabilization_time = 0xffff, /* default */ + .fm_disturbed_band_margin = 0xff, /* default */ + .swallow_clk_diff = 0xff, /* default */ + }, .hci_io_ds = HCI_IO_DS_6MA, }; @@ -508,6 +520,11 @@ static int wl1271_plt_init(struct wl1271 *wl) if (ret < 0) goto out_free_memmap; + /* FM WLAN coexistence */ + ret = wl1271_acx_fm_coex(wl); + if (ret < 0) + goto out_free_memmap; + /* Energy detection */ ret = wl1271_init_energy_detection(wl); if (ret < 0) -- cgit v0.10.2 From 2370841bf1a735661db3d3ae63385be3475b7452 Mon Sep 17 00:00:00 2001 From: Shahar Levi Date: Wed, 13 Apr 2011 14:52:50 +0300 Subject: wl12xx: Update Power Save Exit Retries Packets Reducing the retries of sending PS exit packets to the peer AP. That fix is to avoid sending unrealizable number of PS exit packets in case of ap lost. Signed-off-by: Shahar Levi Signed-off-by: Luciano Coelho diff --git a/drivers/net/wireless/wl12xx/main.c b/drivers/net/wireless/wl12xx/main.c index 8a7a8c5..c0cfcc7 100644 --- a/drivers/net/wireless/wl12xx/main.c +++ b/drivers/net/wireless/wl12xx/main.c @@ -258,7 +258,7 @@ static struct conf_drv_settings default_conf = { .bet_enable = CONF_BET_MODE_ENABLE, .bet_max_consecutive = 50, .psm_entry_retries = 5, - .psm_exit_retries = 255, + .psm_exit_retries = 16, .psm_entry_nullfunc_retries = 3, .psm_entry_hangover_period = 1, .keep_alive_interval = 55000, -- cgit v0.10.2 From 1fe9e2464c667903d7eec0314db26c462ca9d276 Mon Sep 17 00:00:00 2001 From: Eliad Peller Date: Sun, 17 Apr 2011 11:20:47 +0300 Subject: wl12xx: add debugfs entries for dtim_interval and beacon_interval When configuring ACX_WAKE_UP_CONDITIONS (before entering psm), we tell the firmware to wake up once in N DTIMs/beacons. Allow control of this value via debugfs (for debugging purposes). Signed-off-by: Eliad Peller Signed-off-by: Luciano Coelho diff --git a/drivers/net/wireless/wl12xx/debugfs.c b/drivers/net/wireless/wl12xx/debugfs.c index 70ab198..88c6efe 100644 --- a/drivers/net/wireless/wl12xx/debugfs.c +++ b/drivers/net/wireless/wl12xx/debugfs.c @@ -291,6 +291,136 @@ static const struct file_operations gpio_power_ops = { .llseek = default_llseek, }; +static ssize_t dtim_interval_read(struct file *file, char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct wl1271 *wl = file->private_data; + u8 value; + + if (wl->conf.conn.wake_up_event == CONF_WAKE_UP_EVENT_DTIM || + wl->conf.conn.wake_up_event == CONF_WAKE_UP_EVENT_N_DTIM) + value = wl->conf.conn.listen_interval; + else + value = 0; + + return wl1271_format_buffer(user_buf, count, ppos, "%d\n", value); +} + +static ssize_t dtim_interval_write(struct file *file, + const char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct wl1271 *wl = file->private_data; + char buf[10]; + size_t len; + unsigned long value; + int ret; + + len = min(count, sizeof(buf) - 1); + if (copy_from_user(buf, user_buf, len)) + return -EFAULT; + buf[len] = '\0'; + + ret = strict_strtoul(buf, 0, &value); + if (ret < 0) { + wl1271_warning("illegal value for dtim_interval"); + return -EINVAL; + } + + if (value < 1 || value > 10) { + wl1271_warning("dtim value is not in valid range"); + return -ERANGE; + } + + mutex_lock(&wl->mutex); + + wl->conf.conn.listen_interval = value; + /* for some reason there are different event types for 1 and >1 */ + if (value == 1) + wl->conf.conn.wake_up_event = CONF_WAKE_UP_EVENT_DTIM; + else + wl->conf.conn.wake_up_event = CONF_WAKE_UP_EVENT_N_DTIM; + + /* + * we don't reconfigure ACX_WAKE_UP_CONDITIONS now, so it will only + * take effect on the next time we enter psm. + */ + mutex_unlock(&wl->mutex); + return count; +} + +static const struct file_operations dtim_interval_ops = { + .read = dtim_interval_read, + .write = dtim_interval_write, + .open = wl1271_open_file_generic, + .llseek = default_llseek, +}; + +static ssize_t beacon_interval_read(struct file *file, char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct wl1271 *wl = file->private_data; + u8 value; + + if (wl->conf.conn.wake_up_event == CONF_WAKE_UP_EVENT_BEACON || + wl->conf.conn.wake_up_event == CONF_WAKE_UP_EVENT_N_BEACONS) + value = wl->conf.conn.listen_interval; + else + value = 0; + + return wl1271_format_buffer(user_buf, count, ppos, "%d\n", value); +} + +static ssize_t beacon_interval_write(struct file *file, + const char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct wl1271 *wl = file->private_data; + char buf[10]; + size_t len; + unsigned long value; + int ret; + + len = min(count, sizeof(buf) - 1); + if (copy_from_user(buf, user_buf, len)) + return -EFAULT; + buf[len] = '\0'; + + ret = strict_strtoul(buf, 0, &value); + if (ret < 0) { + wl1271_warning("illegal value for beacon_interval"); + return -EINVAL; + } + + if (value < 1 || value > 255) { + wl1271_warning("beacon interval value is not in valid range"); + return -ERANGE; + } + + mutex_lock(&wl->mutex); + + wl->conf.conn.listen_interval = value; + /* for some reason there are different event types for 1 and >1 */ + if (value == 1) + wl->conf.conn.wake_up_event = CONF_WAKE_UP_EVENT_BEACON; + else + wl->conf.conn.wake_up_event = CONF_WAKE_UP_EVENT_N_BEACONS; + + /* + * we don't reconfigure ACX_WAKE_UP_CONDITIONS now, so it will only + * take effect on the next time we enter psm. + */ + mutex_unlock(&wl->mutex); + return count; +} + +static const struct file_operations beacon_interval_ops = { + .read = beacon_interval_read, + .write = beacon_interval_write, + .open = wl1271_open_file_generic, + .llseek = default_llseek, +}; + static int wl1271_debugfs_add_files(struct wl1271 *wl, struct dentry *rootdir) { @@ -399,6 +529,8 @@ static int wl1271_debugfs_add_files(struct wl1271 *wl, DEBUGFS_ADD(excessive_retries, rootdir); DEBUGFS_ADD(gpio_power, rootdir); + DEBUGFS_ADD(dtim_interval, rootdir); + DEBUGFS_ADD(beacon_interval, rootdir); return 0; -- cgit v0.10.2 From ae825e4ba81203e1b3d3159f24327cdc2629dbd8 Mon Sep 17 00:00:00 2001 From: Ido Yariv Date: Mon, 18 Apr 2011 16:40:14 +0300 Subject: wl12xx: Modify memory configuration for 128x/AP The 128x/AP firmware does not yet support dynamic memory. Temporarily, the memory configuration for the 127x was used both for 127x/AP as well as 128x/AP. Since the two chips don't have the same number of memory blocks, TP was significantly degraded. This hasn't been fine tuned yet, but using the base 128x numbers (without dynamic memory) seems to yield much better results (around 30% more). Additional fine tuning will be required in the future. Signed-off-by: Ido Yariv Signed-off-by: Luciano Coelho diff --git a/drivers/net/wireless/wl12xx/acx.c b/drivers/net/wireless/wl12xx/acx.c index 8a39d1e..b1b5139 100644 --- a/drivers/net/wireless/wl12xx/acx.c +++ b/drivers/net/wireless/wl12xx/acx.c @@ -954,6 +954,7 @@ out: int wl1271_acx_ap_mem_cfg(struct wl1271 *wl) { struct wl1271_acx_ap_config_memory *mem_conf; + struct conf_memory_settings *mem; int ret; wl1271_debug(DEBUG_ACX, "wl1271 mem cfg"); @@ -964,14 +965,21 @@ int wl1271_acx_ap_mem_cfg(struct wl1271 *wl) goto out; } + if (wl->chip.id == CHIP_ID_1283_PG20) + /* + * FIXME: The 128x AP FW does not yet support dynamic memory. + * Use the base memory configuration for 128x for now. This + * should be fine tuned in the future. + */ + mem = &wl->conf.mem_wl128x; + else + mem = &wl->conf.mem_wl127x; + /* memory config */ - /* FIXME: for now we always use mem_wl127x for AP, because it - * doesn't support dynamic memory and we don't have the - * optimal values for wl128x without dynamic memory yet */ - mem_conf->num_stations = wl->conf.mem_wl127x.num_stations; - mem_conf->rx_mem_block_num = wl->conf.mem_wl127x.rx_block_num; - mem_conf->tx_min_mem_block_num = wl->conf.mem_wl127x.tx_min_block_num; - mem_conf->num_ssid_profiles = wl->conf.mem_wl127x.ssid_profiles; + mem_conf->num_stations = mem->num_stations; + mem_conf->rx_mem_block_num = mem->rx_block_num; + mem_conf->tx_min_mem_block_num = mem->tx_min_block_num; + mem_conf->num_ssid_profiles = mem->ssid_profiles; mem_conf->total_tx_descriptors = cpu_to_le32(ACX_TX_DESCRIPTORS); ret = wl1271_cmd_configure(wl, ACX_MEM_CFG, mem_conf, -- cgit v0.10.2 From ef2e3004855e90d2919105e4a91d7df6ab9845a9 Mon Sep 17 00:00:00 2001 From: Ido Yariv Date: Mon, 18 Apr 2011 16:44:11 +0300 Subject: wl12xx: Restart TX when TX descriptors are available The driver stops sending TX packets when either there aren't enough memory blocks, or it runs out of TX descriptors. The driver continues to send packets to the FW only when more memory blocks are available. The FW might free TX descriptors without freeing the corresponding memory blocks, especially when dynamic memory is enabled. In cases where memory blocks are not freed at all, the driver will keep waiting for more memory blocks indefinitely. Fix this by clearing the WL1271_FLAG_FW_TX_BUSY flag when there are available TX descriptors. Signed-off-by: Ido Yariv Signed-off-by: Luciano Coelho diff --git a/drivers/net/wireless/wl12xx/tx.c b/drivers/net/wireless/wl12xx/tx.c index c836659..cc837bb 100644 --- a/drivers/net/wireless/wl12xx/tx.c +++ b/drivers/net/wireless/wl12xx/tx.c @@ -65,6 +65,9 @@ static int wl1271_alloc_tx_id(struct wl1271 *wl, struct sk_buff *skb) static void wl1271_free_tx_id(struct wl1271 *wl, int id) { if (__test_and_clear_bit(id, wl->tx_frames_map)) { + if (unlikely(wl->tx_frames_cnt == ACX_TX_DESCRIPTORS)) + clear_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags); + wl->tx_frames[id] = NULL; wl->tx_frames_cnt--; } -- cgit v0.10.2 From 4cf557fcf01e352fb418e110dd013e4128493c5f Mon Sep 17 00:00:00 2001 From: Ido Yariv Date: Mon, 18 Apr 2011 16:45:10 +0300 Subject: wl12xx: Enable dynamic memory for 127x The FW can dynamically manage its internal TX & RX memory pools, moving blocks from one pool to another when necessary. This can significantly improve performance. Currently this feature is enabled only for 128x. Enable dynamic memory for 127x as well. Other parameters in the memory configuration structure may need to be fine tuned, as the optimal values for these may change once dynamic memory is enabled. Signed-off-by: Ido Yariv Signed-off-by: Luciano Coelho diff --git a/drivers/net/wireless/wl12xx/main.c b/drivers/net/wireless/wl12xx/main.c index c0cfcc7..6dd7236 100644 --- a/drivers/net/wireless/wl12xx/main.c +++ b/drivers/net/wireless/wl12xx/main.c @@ -305,7 +305,7 @@ static struct conf_drv_settings default_conf = { .ssid_profiles = 1, .rx_block_num = 70, .tx_min_block_num = 40, - .dynamic_memory = 0, + .dynamic_memory = 1, .min_req_tx_blocks = 100, .min_req_rx_blocks = 22, .tx_min = 27, -- cgit v0.10.2 From 33437893025aa3c0195b933ac99ef7de924019f4 Mon Sep 17 00:00:00 2001 From: Arik Nemtsov Date: Tue, 26 Apr 2011 23:35:39 +0300 Subject: wl12xx: implement the tx_frames_pending mac80211 callback Frames are considered pending when they reside in the driver TX queue or already queued in the FW. This notion of "pending" is appropriate for power save considerations in STA mode, but not necessarily in other modes (for instance P2P-GO). [Fixed a sparse warning about missing "static" in a function declaration -- Luca] Signed-off-by: Arik Nemtsov Signed-off-by: Luciano Coelho diff --git a/drivers/net/wireless/wl12xx/main.c b/drivers/net/wireless/wl12xx/main.c index 6dd7236..e177764 100644 --- a/drivers/net/wireless/wl12xx/main.c +++ b/drivers/net/wireless/wl12xx/main.c @@ -3147,6 +3147,28 @@ out: return ret; } +static bool wl1271_tx_frames_pending(struct ieee80211_hw *hw) +{ + struct wl1271 *wl = hw->priv; + bool ret = false; + + mutex_lock(&wl->mutex); + + if (unlikely(wl->state == WL1271_STATE_OFF)) + goto out; + + /* packets are considered pending if in the TX queue or the FW */ + ret = (wl->tx_queue_count > 0) || (wl->tx_frames_cnt > 0); + + /* the above is appropriate for STA mode for PS purposes */ + WARN_ON(wl->bss_type != BSS_TYPE_STA_BSS); + +out: + mutex_unlock(&wl->mutex); + + return ret; +} + /* can't be const, mac80211 writes to this */ static struct ieee80211_rate wl1271_rates[] = { { .bitrate = 10, @@ -3398,6 +3420,7 @@ static const struct ieee80211_ops wl1271_ops = { .sta_add = wl1271_op_sta_add, .sta_remove = wl1271_op_sta_remove, .ampdu_action = wl1271_op_ampdu_action, + .tx_frames_pending = wl1271_tx_frames_pending, CFG80211_TESTMODE_CMD(wl1271_tm_cmd) }; -- cgit v0.10.2 From 34c8e3d2bb901b2920d2a8930c0de82e7fefac76 Mon Sep 17 00:00:00 2001 From: Arik Nemtsov Date: Tue, 26 Apr 2011 23:35:40 +0300 Subject: wl12xx: discard corrupted packets in RX When packets arrive with a RX descriptor indicating corruption, discard them. In general white-list the RX descriptor status to prevent rouge data from being sent up. Signed-off-by: Arik Nemtsov Signed-off-by: Luciano Coelho diff --git a/drivers/net/wireless/wl12xx/rx.c b/drivers/net/wireless/wl12xx/rx.c index faf5a1d..7009103 100644 --- a/drivers/net/wireless/wl12xx/rx.c +++ b/drivers/net/wireless/wl12xx/rx.c @@ -76,12 +76,15 @@ static void wl1271_rx_status(struct wl1271 *wl, status->band); if (desc->flags & WL1271_RX_DESC_ENCRYPT_MASK) { - status->flag |= RX_FLAG_IV_STRIPPED | RX_FLAG_MMIC_STRIPPED; + u8 desc_err_code = desc->status & WL1271_RX_DESC_STATUS_MASK; - if (likely(!(desc->status & WL1271_RX_DESC_DECRYPT_FAIL))) - status->flag |= RX_FLAG_DECRYPTED; - if (unlikely(desc->status & WL1271_RX_DESC_MIC_FAIL)) + status->flag |= RX_FLAG_IV_STRIPPED | RX_FLAG_MMIC_STRIPPED | + RX_FLAG_DECRYPTED; + + if (unlikely(desc_err_code == WL1271_RX_DESC_MIC_FAIL)) { status->flag |= RX_FLAG_MMIC_ERROR; + wl1271_warning("Michael MIC error"); + } } } @@ -100,6 +103,25 @@ static int wl1271_rx_handle_data(struct wl1271 *wl, u8 *data, u32 length) if (unlikely(wl->state == WL1271_STATE_PLT)) return -EINVAL; + /* the data read starts with the descriptor */ + desc = (struct wl1271_rx_descriptor *) data; + + switch (desc->status & WL1271_RX_DESC_STATUS_MASK) { + /* discard corrupted packets */ + case WL1271_RX_DESC_DRIVER_RX_Q_FAIL: + case WL1271_RX_DESC_DECRYPT_FAIL: + wl1271_warning("corrupted packet in RX with status: 0x%x", + desc->status & WL1271_RX_DESC_STATUS_MASK); + return -EINVAL; + case WL1271_RX_DESC_SUCCESS: + case WL1271_RX_DESC_MIC_FAIL: + break; + default: + wl1271_error("invalid RX descriptor status: 0x%x", + desc->status & WL1271_RX_DESC_STATUS_MASK); + return -EINVAL; + } + skb = __dev_alloc_skb(length, GFP_KERNEL); if (!skb) { wl1271_error("Couldn't allocate RX frame"); @@ -109,9 +131,6 @@ static int wl1271_rx_handle_data(struct wl1271 *wl, u8 *data, u32 length) buf = skb_put(skb, length); memcpy(buf, data, length); - /* the data read starts with the descriptor */ - desc = (struct wl1271_rx_descriptor *) buf; - /* now we pull the descriptor out of the buffer */ skb_pull(skb, sizeof(*desc)); -- cgit v0.10.2 From 86c438f40cf3e0f6ce2da80f2d759e61d3e85ad7 Mon Sep 17 00:00:00 2001 From: Hauke Mehrtens Date: Tue, 26 Apr 2011 23:27:44 +0200 Subject: wl12xx: do not set queue_mapping directly It is preferred to use the setter that to set queue_mapping directly. This also helps backporting in compat-wireless. Signed-off-by: Hauke Mehrtens Signed-off-by: Luciano Coelho diff --git a/drivers/net/wireless/wl12xx/main.c b/drivers/net/wireless/wl12xx/main.c index e177764..a877010 100644 --- a/drivers/net/wireless/wl12xx/main.c +++ b/drivers/net/wireless/wl12xx/main.c @@ -1294,7 +1294,7 @@ static struct sk_buff *wl12xx_alloc_dummy_packet(struct wl1271 *wl) skb->priority = WL1271_TID_MGMT; /* Initialize all fields that might be used */ - skb->queue_mapping = 0; + skb_set_queue_mapping(skb, 0); memset(IEEE80211_SKB_CB(skb), 0, sizeof(struct ieee80211_tx_info)); return skb; -- cgit v0.10.2 From f7c7c7e69cbc3c5b660a32cc2cb31720b2b420c8 Mon Sep 17 00:00:00 2001 From: Luciano Coelho Date: Fri, 29 Apr 2011 22:25:28 +0300 Subject: wl12xx: strict_stroul introduced converted to kstrtoul One new patch applied added a couple of new strict_strtoul calls. Converted those to kstroul(). Signed-off-by: Luciano Coelho diff --git a/drivers/net/wireless/wl12xx/debugfs.c b/drivers/net/wireless/wl12xx/debugfs.c index 88c6efe..b17cff6 100644 --- a/drivers/net/wireless/wl12xx/debugfs.c +++ b/drivers/net/wireless/wl12xx/debugfs.c @@ -321,7 +321,7 @@ static ssize_t dtim_interval_write(struct file *file, return -EFAULT; buf[len] = '\0'; - ret = strict_strtoul(buf, 0, &value); + ret = kstrtoul(buf, 0, &value); if (ret < 0) { wl1271_warning("illegal value for dtim_interval"); return -EINVAL; @@ -386,7 +386,7 @@ static ssize_t beacon_interval_write(struct file *file, return -EFAULT; buf[len] = '\0'; - ret = strict_strtoul(buf, 0, &value); + ret = kstrtoul(buf, 0, &value); if (ret < 0) { wl1271_warning("illegal value for beacon_interval"); return -EINVAL; -- cgit v0.10.2 From 801f870bc0524bad7ebef9cea52d20e4d4992e4a Mon Sep 17 00:00:00 2001 From: Arik Nemtsov Date: Mon, 18 Apr 2011 14:15:20 +0300 Subject: wl12xx: add BT-coexistance for AP Initialize AP specific BT coexitance parameters to default values and enable them in AP mode. Signed-off-by: Arik Nemtsov Signed-off-by: Luciano Coelho diff --git a/drivers/net/wireless/wl12xx/acx.c b/drivers/net/wireless/wl12xx/acx.c index b1b5139..2b5fb3d 100644 --- a/drivers/net/wireless/wl12xx/acx.c +++ b/drivers/net/wireless/wl12xx/acx.c @@ -540,13 +540,13 @@ out: return ret; } -int wl1271_acx_sg_cfg(struct wl1271 *wl) +int wl1271_acx_sta_sg_cfg(struct wl1271 *wl) { - struct acx_bt_wlan_coex_param *param; + struct acx_sta_bt_wlan_coex_param *param; struct conf_sg_settings *c = &wl->conf.sg; int i, ret; - wl1271_debug(DEBUG_ACX, "acx sg cfg"); + wl1271_debug(DEBUG_ACX, "acx sg sta cfg"); param = kzalloc(sizeof(*param), GFP_KERNEL); if (!param) { @@ -555,8 +555,38 @@ int wl1271_acx_sg_cfg(struct wl1271 *wl) } /* BT-WLAN coext parameters */ - for (i = 0; i < CONF_SG_PARAMS_MAX; i++) - param->params[i] = cpu_to_le32(c->params[i]); + for (i = 0; i < CONF_SG_STA_PARAMS_MAX; i++) + param->params[i] = cpu_to_le32(c->sta_params[i]); + param->param_idx = CONF_SG_PARAMS_ALL; + + ret = wl1271_cmd_configure(wl, ACX_SG_CFG, param, sizeof(*param)); + if (ret < 0) { + wl1271_warning("failed to set sg config: %d", ret); + goto out; + } + +out: + kfree(param); + return ret; +} + +int wl1271_acx_ap_sg_cfg(struct wl1271 *wl) +{ + struct acx_ap_bt_wlan_coex_param *param; + struct conf_sg_settings *c = &wl->conf.sg; + int i, ret; + + wl1271_debug(DEBUG_ACX, "acx sg ap cfg"); + + param = kzalloc(sizeof(*param), GFP_KERNEL); + if (!param) { + ret = -ENOMEM; + goto out; + } + + /* BT-WLAN coext parameters */ + for (i = 0; i < CONF_SG_AP_PARAMS_MAX; i++) + param->params[i] = cpu_to_le32(c->ap_params[i]); param->param_idx = CONF_SG_PARAMS_ALL; ret = wl1271_cmd_configure(wl, ACX_SG_CFG, param, sizeof(*param)); diff --git a/drivers/net/wireless/wl12xx/acx.h b/drivers/net/wireless/wl12xx/acx.h index 2dde034..cd7548d 100644 --- a/drivers/net/wireless/wl12xx/acx.h +++ b/drivers/net/wireless/wl12xx/acx.h @@ -370,14 +370,23 @@ struct acx_bt_wlan_coex { u8 pad[3]; } __packed; -struct acx_bt_wlan_coex_param { +struct acx_sta_bt_wlan_coex_param { struct acx_header header; - __le32 params[CONF_SG_PARAMS_MAX]; + __le32 params[CONF_SG_STA_PARAMS_MAX]; u8 param_idx; u8 padding[3]; } __packed; +struct acx_ap_bt_wlan_coex_param { + struct acx_header header; + + __le32 params[CONF_SG_AP_PARAMS_MAX]; + u8 param_idx; + u8 padding[3]; +} __packed; + + struct acx_dco_itrim_params { struct acx_header header; @@ -1330,7 +1339,8 @@ int wl1271_acx_beacon_filter_opt(struct wl1271 *wl, bool enable_filter); int wl1271_acx_beacon_filter_table(struct wl1271 *wl); int wl1271_acx_conn_monit_params(struct wl1271 *wl, bool enable); int wl1271_acx_sg_enable(struct wl1271 *wl, bool enable); -int wl1271_acx_sg_cfg(struct wl1271 *wl); +int wl1271_acx_sta_sg_cfg(struct wl1271 *wl); +int wl1271_acx_ap_sg_cfg(struct wl1271 *wl); int wl1271_acx_cca_threshold(struct wl1271 *wl); int wl1271_acx_bcn_dtim_options(struct wl1271 *wl); int wl1271_acx_aid(struct wl1271 *wl, u16 aid); diff --git a/drivers/net/wireless/wl12xx/conf.h b/drivers/net/wireless/wl12xx/conf.h index a4e0acf..2ffbe3e 100644 --- a/drivers/net/wireless/wl12xx/conf.h +++ b/drivers/net/wireless/wl12xx/conf.h @@ -396,12 +396,43 @@ enum { CONF_SG_TEMP_PARAM_3, CONF_SG_TEMP_PARAM_4, CONF_SG_TEMP_PARAM_5, - CONF_SG_PARAMS_MAX, + + /* + * AP beacon miss + * + * Range: 0 - 255 + */ + CONF_SG_AP_BEACON_MISS_TX, + + /* + * AP RX window length + * + * Range: 0 - 50 + */ + CONF_SG_RX_WINDOW_LENGTH, + + /* + * AP connection protection time + * + * Range: 0 - 5000 + */ + CONF_SG_AP_CONNECTION_PROTECTION_TIME, + + CONF_SG_TEMP_PARAM_6, + CONF_SG_TEMP_PARAM_7, + CONF_SG_TEMP_PARAM_8, + CONF_SG_TEMP_PARAM_9, + CONF_SG_TEMP_PARAM_10, + + CONF_SG_STA_PARAMS_MAX = CONF_SG_TEMP_PARAM_5 + 1, + CONF_SG_AP_PARAMS_MAX = CONF_SG_TEMP_PARAM_10 + 1, + CONF_SG_PARAMS_ALL = 0xff }; struct conf_sg_settings { - u32 params[CONF_SG_PARAMS_MAX]; + u32 sta_params[CONF_SG_STA_PARAMS_MAX]; + u32 ap_params[CONF_SG_AP_PARAMS_MAX]; u8 state; }; diff --git a/drivers/net/wireless/wl12xx/init.c b/drivers/net/wireless/wl12xx/init.c index 46fd721..1be6569 100644 --- a/drivers/net/wireless/wl12xx/init.c +++ b/drivers/net/wireless/wl12xx/init.c @@ -285,7 +285,10 @@ int wl1271_init_pta(struct wl1271 *wl) { int ret; - ret = wl1271_acx_sg_cfg(wl); + if (wl->bss_type == BSS_TYPE_AP_BSS) + ret = wl1271_acx_ap_sg_cfg(wl); + else + ret = wl1271_acx_sta_sg_cfg(wl); if (ret < 0) return ret; @@ -351,11 +354,6 @@ static int wl1271_sta_hw_init(struct wl1271 *wl) if (ret < 0) return ret; - /* Bluetooth WLAN coexistence */ - ret = wl1271_init_pta(wl); - if (ret < 0) - return ret; - /* FM WLAN coexistence */ ret = wl1271_acx_fm_coex(wl); if (ret < 0) @@ -572,6 +570,11 @@ int wl1271_hw_init(struct wl1271 *wl) if (ret < 0) return ret; + /* Bluetooth WLAN coexistence */ + ret = wl1271_init_pta(wl); + if (ret < 0) + return ret; + /* Default memory configuration */ ret = wl1271_acx_init_mem_config(wl); if (ret < 0) diff --git a/drivers/net/wireless/wl12xx/main.c b/drivers/net/wireless/wl12xx/main.c index a877010..5f8bb35 100644 --- a/drivers/net/wireless/wl12xx/main.c +++ b/drivers/net/wireless/wl12xx/main.c @@ -51,7 +51,7 @@ static struct conf_drv_settings default_conf = { .sg = { - .params = { + .sta_params = { [CONF_SG_BT_PER_THRESHOLD] = 7500, [CONF_SG_HV3_MAX_OVERRIDE] = 0, [CONF_SG_BT_NFS_SAMPLE_INTERVAL] = 400, @@ -101,6 +101,61 @@ static struct conf_drv_settings default_conf = { [CONF_SG_DHCP_TIME] = 5000, [CONF_SG_ACTIVE_SCAN_DURATION_FACTOR_A2DP] = 100, }, + .ap_params = { + [CONF_SG_BT_PER_THRESHOLD] = 7500, + [CONF_SG_HV3_MAX_OVERRIDE] = 0, + [CONF_SG_BT_NFS_SAMPLE_INTERVAL] = 400, + [CONF_SG_BT_LOAD_RATIO] = 50, + [CONF_SG_AUTO_PS_MODE] = 1, + [CONF_SG_AUTO_SCAN_PROBE_REQ] = 170, + [CONF_SG_ACTIVE_SCAN_DURATION_FACTOR_HV3] = 50, + [CONF_SG_ANTENNA_CONFIGURATION] = 0, + [CONF_SG_BEACON_MISS_PERCENT] = 60, + [CONF_SG_RATE_ADAPT_THRESH] = 64, + [CONF_SG_RATE_ADAPT_SNR] = 1, + [CONF_SG_WLAN_PS_BT_ACL_MASTER_MIN_BR] = 10, + [CONF_SG_WLAN_PS_BT_ACL_MASTER_MAX_BR] = 25, + [CONF_SG_WLAN_PS_MAX_BT_ACL_MASTER_BR] = 25, + [CONF_SG_WLAN_PS_BT_ACL_SLAVE_MIN_BR] = 20, + [CONF_SG_WLAN_PS_BT_ACL_SLAVE_MAX_BR] = 25, + [CONF_SG_WLAN_PS_MAX_BT_ACL_SLAVE_BR] = 25, + [CONF_SG_WLAN_PS_BT_ACL_MASTER_MIN_EDR] = 7, + [CONF_SG_WLAN_PS_BT_ACL_MASTER_MAX_EDR] = 25, + [CONF_SG_WLAN_PS_MAX_BT_ACL_MASTER_EDR] = 25, + [CONF_SG_WLAN_PS_BT_ACL_SLAVE_MIN_EDR] = 8, + [CONF_SG_WLAN_PS_BT_ACL_SLAVE_MAX_EDR] = 25, + [CONF_SG_WLAN_PS_MAX_BT_ACL_SLAVE_EDR] = 25, + [CONF_SG_RXT] = 1200, + [CONF_SG_TXT] = 1000, + [CONF_SG_ADAPTIVE_RXT_TXT] = 1, + [CONF_SG_PS_POLL_TIMEOUT] = 10, + [CONF_SG_UPSD_TIMEOUT] = 10, + [CONF_SG_WLAN_ACTIVE_BT_ACL_MASTER_MIN_EDR] = 7, + [CONF_SG_WLAN_ACTIVE_BT_ACL_MASTER_MAX_EDR] = 15, + [CONF_SG_WLAN_ACTIVE_MAX_BT_ACL_MASTER_EDR] = 15, + [CONF_SG_WLAN_ACTIVE_BT_ACL_SLAVE_MIN_EDR] = 8, + [CONF_SG_WLAN_ACTIVE_BT_ACL_SLAVE_MAX_EDR] = 20, + [CONF_SG_WLAN_ACTIVE_MAX_BT_ACL_SLAVE_EDR] = 15, + [CONF_SG_WLAN_ACTIVE_BT_ACL_MIN_BR] = 20, + [CONF_SG_WLAN_ACTIVE_BT_ACL_MAX_BR] = 50, + [CONF_SG_WLAN_ACTIVE_MAX_BT_ACL_BR] = 10, + [CONF_SG_PASSIVE_SCAN_DURATION_FACTOR_HV3] = 200, + [CONF_SG_PASSIVE_SCAN_DURATION_FACTOR_A2DP] = 800, + [CONF_SG_PASSIVE_SCAN_A2DP_BT_TIME] = 75, + [CONF_SG_PASSIVE_SCAN_A2DP_WLAN_TIME] = 15, + [CONF_SG_HV3_MAX_SERVED] = 6, + [CONF_SG_DHCP_TIME] = 5000, + [CONF_SG_ACTIVE_SCAN_DURATION_FACTOR_A2DP] = 100, + [CONF_SG_TEMP_PARAM_1] = 0, + [CONF_SG_TEMP_PARAM_2] = 0, + [CONF_SG_TEMP_PARAM_3] = 0, + [CONF_SG_TEMP_PARAM_4] = 0, + [CONF_SG_TEMP_PARAM_5] = 0, + [CONF_SG_AP_BEACON_MISS_TX] = 3, + [CONF_SG_RX_WINDOW_LENGTH] = 6, + [CONF_SG_AP_CONNECTION_PROTECTION_TIME] = 50, + [CONF_SG_TEMP_PARAM_6] = 1, + }, .state = CONF_SG_PROTECTIVE, }, .rx = { -- cgit v0.10.2 From 5f704d180e448d05859e1cb6572822ba27dbcdc7 Mon Sep 17 00:00:00 2001 From: Arik Nemtsov Date: Mon, 18 Apr 2011 14:15:21 +0300 Subject: wl12xx: use wiphy values for setting rts, frag thresholds on init Use the wiphy RTS and fragmentation thresholds for initializing the FW when possible. This mitigates a bug where previously set values are forgotten after interface down/up. Add checks before settings these values to ensure they are valid. Use default values when invalid thresholds are configured. Update the default RTS threshold to the maximum value given by the specification. Signed-off-by: Arik Nemtsov Signed-off-by: Luciano Coelho diff --git a/drivers/net/wireless/wl12xx/acx.c b/drivers/net/wireless/wl12xx/acx.c index 2b5fb3d..729f72a 100644 --- a/drivers/net/wireless/wl12xx/acx.c +++ b/drivers/net/wireless/wl12xx/acx.c @@ -325,12 +325,19 @@ out: return ret; } -int wl1271_acx_rts_threshold(struct wl1271 *wl, u16 rts_threshold) +int wl1271_acx_rts_threshold(struct wl1271 *wl, u32 rts_threshold) { struct acx_rts_threshold *rts; int ret; - wl1271_debug(DEBUG_ACX, "acx rts threshold"); + /* + * If the RTS threshold is not configured or out of range, use the + * default value. + */ + if (rts_threshold > IEEE80211_MAX_RTS_THRESHOLD) + rts_threshold = wl->conf.rx.rts_threshold; + + wl1271_debug(DEBUG_ACX, "acx rts threshold: %d", rts_threshold); rts = kzalloc(sizeof(*rts), GFP_KERNEL); if (!rts) { @@ -338,7 +345,7 @@ int wl1271_acx_rts_threshold(struct wl1271 *wl, u16 rts_threshold) goto out; } - rts->threshold = cpu_to_le16(rts_threshold); + rts->threshold = cpu_to_le16((u16)rts_threshold); ret = wl1271_cmd_configure(wl, DOT11_RTS_THRESHOLD, rts, sizeof(*rts)); if (ret < 0) { @@ -928,12 +935,19 @@ out: return ret; } -int wl1271_acx_frag_threshold(struct wl1271 *wl, u16 frag_threshold) +int wl1271_acx_frag_threshold(struct wl1271 *wl, u32 frag_threshold) { struct acx_frag_threshold *acx; int ret = 0; - wl1271_debug(DEBUG_ACX, "acx frag threshold"); + /* + * If the fragmentation is not configured or out of range, use the + * default value. + */ + if (frag_threshold > IEEE80211_MAX_FRAG_THRESHOLD) + frag_threshold = wl->conf.tx.frag_threshold; + + wl1271_debug(DEBUG_ACX, "acx frag threshold: %d", frag_threshold); acx = kzalloc(sizeof(*acx), GFP_KERNEL); @@ -942,7 +956,7 @@ int wl1271_acx_frag_threshold(struct wl1271 *wl, u16 frag_threshold) goto out; } - acx->frag_threshold = cpu_to_le16(frag_threshold); + acx->frag_threshold = cpu_to_le16((u16)frag_threshold); ret = wl1271_cmd_configure(wl, ACX_FRAG_CFG, acx, sizeof(*acx)); if (ret < 0) { wl1271_warning("Setting of frag threshold failed: %d", ret); diff --git a/drivers/net/wireless/wl12xx/acx.h b/drivers/net/wireless/wl12xx/acx.h index cd7548d..828367d6 100644 --- a/drivers/net/wireless/wl12xx/acx.h +++ b/drivers/net/wireless/wl12xx/acx.h @@ -1333,7 +1333,7 @@ int wl1271_acx_slot(struct wl1271 *wl, enum acx_slot_type slot_time); int wl1271_acx_group_address_tbl(struct wl1271 *wl, bool enable, void *mc_list, u32 mc_list_len); int wl1271_acx_service_period_timeout(struct wl1271 *wl); -int wl1271_acx_rts_threshold(struct wl1271 *wl, u16 rts_threshold); +int wl1271_acx_rts_threshold(struct wl1271 *wl, u32 rts_threshold); int wl1271_acx_dco_itrim_params(struct wl1271 *wl); int wl1271_acx_beacon_filter_opt(struct wl1271 *wl, bool enable_filter); int wl1271_acx_beacon_filter_table(struct wl1271 *wl); @@ -1357,7 +1357,7 @@ int wl1271_acx_ac_cfg(struct wl1271 *wl, u8 ac, u8 cw_min, u16 cw_max, int wl1271_acx_tid_cfg(struct wl1271 *wl, u8 queue_id, u8 channel_type, u8 tsid, u8 ps_scheme, u8 ack_policy, u32 apsd_conf0, u32 apsd_conf1); -int wl1271_acx_frag_threshold(struct wl1271 *wl, u16 frag_threshold); +int wl1271_acx_frag_threshold(struct wl1271 *wl, u32 frag_threshold); int wl1271_acx_tx_config_options(struct wl1271 *wl); int wl1271_acx_ap_mem_cfg(struct wl1271 *wl); int wl1271_acx_sta_mem_cfg(struct wl1271 *wl); diff --git a/drivers/net/wireless/wl12xx/init.c b/drivers/net/wireless/wl12xx/init.c index 1be6569..060ca31 100644 --- a/drivers/net/wireless/wl12xx/init.c +++ b/drivers/net/wireless/wl12xx/init.c @@ -258,7 +258,7 @@ int wl1271_init_phy_config(struct wl1271 *wl) if (ret < 0) return ret; - ret = wl1271_acx_rts_threshold(wl, wl->conf.rx.rts_threshold); + ret = wl1271_acx_rts_threshold(wl, wl->hw->wiphy->rts_threshold); if (ret < 0) return ret; @@ -614,7 +614,7 @@ int wl1271_hw_init(struct wl1271 *wl) goto out_free_memmap; /* Default fragmentation threshold */ - ret = wl1271_acx_frag_threshold(wl, wl->conf.tx.frag_threshold); + ret = wl1271_acx_frag_threshold(wl, wl->hw->wiphy->frag_threshold); if (ret < 0) goto out_free_memmap; diff --git a/drivers/net/wireless/wl12xx/main.c b/drivers/net/wireless/wl12xx/main.c index 5f8bb35..81a0c8e 100644 --- a/drivers/net/wireless/wl12xx/main.c +++ b/drivers/net/wireless/wl12xx/main.c @@ -163,7 +163,7 @@ static struct conf_drv_settings default_conf = { .packet_detection_threshold = 0, .ps_poll_timeout = 15, .upsd_timeout = 15, - .rts_threshold = 2347, + .rts_threshold = IEEE80211_MAX_RTS_THRESHOLD, .rx_cca_threshold = 0, .irq_blk_threshold = 0xFFFF, .irq_pkt_threshold = 0, @@ -2360,7 +2360,7 @@ static int wl1271_op_set_frag_threshold(struct ieee80211_hw *hw, u32 value) if (ret < 0) goto out; - ret = wl1271_acx_frag_threshold(wl, (u16)value); + ret = wl1271_acx_frag_threshold(wl, value); if (ret < 0) wl1271_warning("wl1271_op_set_frag_threshold failed: %d", ret); @@ -2388,7 +2388,7 @@ static int wl1271_op_set_rts_threshold(struct ieee80211_hw *hw, u32 value) if (ret < 0) goto out; - ret = wl1271_acx_rts_threshold(wl, (u16) value); + ret = wl1271_acx_rts_threshold(wl, value); if (ret < 0) wl1271_warning("wl1271_op_set_rts_threshold failed: %d", ret); -- cgit v0.10.2 From 521a4a23261354885c01bf75b42150629004ed83 Mon Sep 17 00:00:00 2001 From: Arik Nemtsov Date: Mon, 18 Apr 2011 14:15:22 +0300 Subject: wl12xx: AP-mode - disable beacon filtering on start up New AP-mode FWs filter external beacons by default. Disable this filtering on start up so we can properly configure ERP protection. Signed-off-by: Arik Nemtsov Signed-off-by: Luciano Coelho diff --git a/drivers/net/wireless/wl12xx/acx.c b/drivers/net/wireless/wl12xx/acx.c index 729f72a..6860d7e 100644 --- a/drivers/net/wireless/wl12xx/acx.c +++ b/drivers/net/wireless/wl12xx/acx.c @@ -1679,6 +1679,31 @@ out: return ret; } +int wl1271_acx_set_ap_beacon_filter(struct wl1271 *wl, bool enable) +{ + struct acx_ap_beacon_filter *acx = NULL; + int ret; + + wl1271_debug(DEBUG_ACX, "acx set ap beacon filter: %d", enable); + + acx = kzalloc(sizeof(*acx), GFP_KERNEL); + if (!acx) + return -ENOMEM; + + acx->enable = enable ? 1 : 0; + + ret = wl1271_cmd_configure(wl, ACX_AP_BEACON_FILTER_OPT, + acx, sizeof(*acx)); + if (ret < 0) { + wl1271_warning("acx set ap beacon filter failed: %d", ret); + goto out; + } + +out: + kfree(acx); + return ret; +} + int wl1271_acx_fm_coex(struct wl1271 *wl) { struct wl1271_acx_fm_coex *acx; diff --git a/drivers/net/wireless/wl12xx/acx.h b/drivers/net/wireless/wl12xx/acx.h index 828367d6..75338f9 100644 --- a/drivers/net/wireless/wl12xx/acx.h +++ b/drivers/net/wireless/wl12xx/acx.h @@ -303,7 +303,6 @@ struct acx_beacon_filter_option { struct acx_header header; u8 enable; - /* * The number of beacons without the unicast TIM * bit set that the firmware buffers before @@ -1188,6 +1187,13 @@ struct wl1271_acx_inconnection_sta { u8 padding1[2]; } __packed; +struct acx_ap_beacon_filter { + struct acx_header header; + + u8 enable; + u8 pad[3]; +} __packed; + /* * ACX_FM_COEX_CFG * set the FM co-existence parameters. @@ -1265,6 +1271,7 @@ enum { ACX_TID_CFG = 0x001A, ACX_PS_RX_STREAMING = 0x001B, ACX_BEACON_FILTER_OPT = 0x001F, + ACX_AP_BEACON_FILTER_OPT = 0x0020, ACX_NOISE_HIST = 0x0021, ACX_HDK_VERSION = 0x0022, /* ??? */ ACX_PD_THRESHOLD = 0x0023, @@ -1388,6 +1395,7 @@ int wl1271_acx_ap_max_tx_retry(struct wl1271 *wl); int wl1271_acx_sta_max_tx_retry(struct wl1271 *wl); int wl1271_acx_config_ps(struct wl1271 *wl); int wl1271_acx_set_inconnection_sta(struct wl1271 *wl, u8 *addr); +int wl1271_acx_set_ap_beacon_filter(struct wl1271 *wl, bool enable); int wl1271_acx_fm_coex(struct wl1271 *wl); #endif /* __WL1271_ACX_H__ */ diff --git a/drivers/net/wireless/wl12xx/init.c b/drivers/net/wireless/wl12xx/init.c index 060ca31..e0de041 100644 --- a/drivers/net/wireless/wl12xx/init.c +++ b/drivers/net/wireless/wl12xx/init.c @@ -475,6 +475,14 @@ static int wl1271_ap_hw_init_post_mem(struct wl1271 *wl) if (ret < 0) return ret; + /* + * when operating as AP we want to receive external beacons for + * configuring ERP protection. + */ + ret = wl1271_acx_set_ap_beacon_filter(wl, false); + if (ret < 0) + return ret; + return 0; } -- cgit v0.10.2 From f482b76202f4ac0f62a77b0e55ac1a1cfe480e2b Mon Sep 17 00:00:00 2001 From: Arik Nemtsov Date: Mon, 18 Apr 2011 14:15:23 +0300 Subject: wl12xx: schedule recovery on command timeout We use a long timeout (2 seconds) when sending commands to the FW. When a command times out, it means the FW is stuck, and we should commence recovery. This should make recovery times shorter as we'll recover on the first timeout indication. Signed-off-by: Arik Nemtsov Signed-off-by: Luciano Coelho diff --git a/drivers/net/wireless/wl12xx/cmd.c b/drivers/net/wireless/wl12xx/cmd.c index a9ffdd8..d8596ae 100644 --- a/drivers/net/wireless/wl12xx/cmd.c +++ b/drivers/net/wireless/wl12xx/cmd.c @@ -76,7 +76,7 @@ int wl1271_cmd_send(struct wl1271 *wl, u16 id, void *buf, size_t len, if (time_after(jiffies, timeout)) { wl1271_error("command complete timeout"); ret = -ETIMEDOUT; - goto out; + goto fail; } poll_count++; @@ -96,14 +96,17 @@ int wl1271_cmd_send(struct wl1271 *wl, u16 id, void *buf, size_t len, status = le16_to_cpu(cmd->status); if (status != CMD_STATUS_SUCCESS) { wl1271_error("command execute failure %d", status); - ieee80211_queue_work(wl->hw, &wl->recovery_work); ret = -EIO; + goto fail; } wl1271_write32(wl, ACX_REG_INTERRUPT_ACK, WL1271_ACX_INTR_CMD_COMPLETE); + return 0; -out: +fail: + WARN_ON(1); + ieee80211_queue_work(wl->hw, &wl->recovery_work); return ret; } -- cgit v0.10.2 From 52dcaf577f3b6d878a337a44a99a122017c85ff6 Mon Sep 17 00:00:00 2001 From: Arik Nemtsov Date: Mon, 18 Apr 2011 14:15:24 +0300 Subject: wl12xx: print firmware program counter during recovery When performing recovery, print the firmware version and program counter (by reading the SCR_PAD4 register). The value of the firmware program counter during assert can be useful for debugging. Signed-off-by: Arik Nemtsov Signed-off-by: Luciano Coelho diff --git a/drivers/net/wireless/wl12xx/main.c b/drivers/net/wireless/wl12xx/main.c index 81a0c8e..7b88dd2 100644 --- a/drivers/net/wireless/wl12xx/main.c +++ b/drivers/net/wireless/wl12xx/main.c @@ -1004,7 +1004,8 @@ static void wl1271_recovery_work(struct work_struct *work) if (wl->state != WL1271_STATE_ON) goto out; - wl1271_info("Hardware recovery in progress."); + wl1271_info("Hardware recovery in progress. FW ver: %s pc: 0x%x", + wl->chip.fw_ver_str, wl1271_read32(wl, SCR_PAD4)); if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags)) ieee80211_connection_loss(wl->vif); -- cgit v0.10.2 From 70f474241b3d5fb633635a2ce39ea9da4afeea6c Mon Sep 17 00:00:00 2001 From: Arik Nemtsov Date: Mon, 18 Apr 2011 14:15:25 +0300 Subject: wl12xx: AP-mode - overhaul rate policy configuration Use the minimal rate configured in the basic rates set as the AP broadcast and multicast rate. The minimal rate is used to ensure weak links can still communicate. When the basic rates contains at least one OFDM rate, configure all unicast TX rates to OFDM only. Unify rate configuration on initialization and on change notification into a single function. Signed-off-by: Arik Nemtsov Signed-off-by: Luciano Coelho diff --git a/drivers/net/wireless/wl12xx/acx.c b/drivers/net/wireless/wl12xx/acx.c index 6860d7e..ec0156b 100644 --- a/drivers/net/wireless/wl12xx/acx.c +++ b/drivers/net/wireless/wl12xx/acx.c @@ -841,7 +841,8 @@ int wl1271_acx_ap_rate_policy(struct wl1271 *wl, struct conf_tx_rate_class *c, struct acx_ap_rate_policy *acx; int ret = 0; - wl1271_debug(DEBUG_ACX, "acx ap rate policy"); + wl1271_debug(DEBUG_ACX, "acx ap rate policy %d rates 0x%x", + idx, c->enabled_rates); acx = kzalloc(sizeof(*acx), GFP_KERNEL); if (!acx) { diff --git a/drivers/net/wireless/wl12xx/conf.h b/drivers/net/wireless/wl12xx/conf.h index 2ffbe3e..c0045f0 100644 --- a/drivers/net/wireless/wl12xx/conf.h +++ b/drivers/net/wireless/wl12xx/conf.h @@ -540,6 +540,12 @@ struct conf_rx_settings { CONF_HW_BIT_RATE_36MBPS | CONF_HW_BIT_RATE_48MBPS | \ CONF_HW_BIT_RATE_54MBPS) +#define CONF_TX_OFDM_RATES (CONF_HW_BIT_RATE_6MBPS | \ + CONF_HW_BIT_RATE_12MBPS | CONF_HW_BIT_RATE_24MBPS | \ + CONF_HW_BIT_RATE_36MBPS | CONF_HW_BIT_RATE_48MBPS | \ + CONF_HW_BIT_RATE_54MBPS) + + /* * Default rates for management traffic when operating in AP mode. This * should be configured according to the basic rate set of the AP @@ -705,22 +711,6 @@ struct conf_tx_settings { struct conf_tx_ac_category ac_conf[CONF_TX_MAX_AC_COUNT]; /* - * Configuration for rate classes in AP-mode. These rate classes - * are for the AC TX queues - */ - struct conf_tx_rate_class ap_rc_conf[CONF_TX_MAX_AC_COUNT]; - - /* - * Management TX rate class for AP-mode. - */ - struct conf_tx_rate_class ap_mgmt_conf; - - /* - * Broadcast TX rate class for AP-mode. - */ - struct conf_tx_rate_class ap_bcst_conf; - - /* * Allow this number of TX retries to a connected station/AP before an * event is triggered from FW. * In AP-mode the hlids of unreachable stations are given in the diff --git a/drivers/net/wireless/wl12xx/init.c b/drivers/net/wireless/wl12xx/init.c index e0de041..5d0ecd2 100644 --- a/drivers/net/wireless/wl12xx/init.c +++ b/drivers/net/wireless/wl12xx/init.c @@ -417,7 +417,7 @@ static int wl1271_sta_hw_init_post_mem(struct wl1271 *wl) static int wl1271_ap_hw_init(struct wl1271 *wl) { - int ret, i; + int ret; ret = wl1271_ap_init_templates_config(wl); if (ret < 0) @@ -428,23 +428,7 @@ static int wl1271_ap_hw_init(struct wl1271 *wl) if (ret < 0) return ret; - /* Configure initial TX rate classes */ - for (i = 0; i < wl->conf.tx.ac_conf_count; i++) { - ret = wl1271_acx_ap_rate_policy(wl, - &wl->conf.tx.ap_rc_conf[i], i); - if (ret < 0) - return ret; - } - - ret = wl1271_acx_ap_rate_policy(wl, - &wl->conf.tx.ap_mgmt_conf, - ACX_TX_AP_MODE_MGMT_RATE); - if (ret < 0) - return ret; - - ret = wl1271_acx_ap_rate_policy(wl, - &wl->conf.tx.ap_bcst_conf, - ACX_TX_AP_MODE_BCST_RATE); + ret = wl1271_init_ap_rates(wl); if (ret < 0) return ret; @@ -486,6 +470,57 @@ static int wl1271_ap_hw_init_post_mem(struct wl1271 *wl) return 0; } +int wl1271_init_ap_rates(struct wl1271 *wl) +{ + int i, ret; + struct conf_tx_rate_class rc; + u32 supported_rates; + + wl1271_debug(DEBUG_AP, "AP basic rate set: 0x%x", wl->basic_rate_set); + + if (wl->basic_rate_set == 0) + return -EINVAL; + + rc.enabled_rates = wl->basic_rate_set; + rc.long_retry_limit = 10; + rc.short_retry_limit = 10; + rc.aflags = 0; + ret = wl1271_acx_ap_rate_policy(wl, &rc, ACX_TX_AP_MODE_MGMT_RATE); + if (ret < 0) + return ret; + + /* use the min basic rate for AP broadcast/multicast */ + rc.enabled_rates = wl1271_tx_min_rate_get(wl); + rc.short_retry_limit = 10; + rc.long_retry_limit = 10; + rc.aflags = 0; + ret = wl1271_acx_ap_rate_policy(wl, &rc, ACX_TX_AP_MODE_BCST_RATE); + if (ret < 0) + return ret; + + /* + * If the basic rates contain OFDM rates, use OFDM only + * rates for unicast TX as well. Else use all supported rates. + */ + if ((wl->basic_rate_set & CONF_TX_OFDM_RATES)) + supported_rates = CONF_TX_OFDM_RATES; + else + supported_rates = CONF_TX_AP_ENABLED_RATES; + + /* configure unicast TX rate classes */ + for (i = 0; i < wl->conf.tx.ac_conf_count; i++) { + rc.enabled_rates = supported_rates; + rc.short_retry_limit = 10; + rc.long_retry_limit = 10; + rc.aflags = 0; + ret = wl1271_acx_ap_rate_policy(wl, &rc, i); + if (ret < 0) + return ret; + } + + return 0; +} + static void wl1271_check_ba_support(struct wl1271 *wl) { /* validate FW cose ver x.x.x.50-60.x */ diff --git a/drivers/net/wireless/wl12xx/init.h b/drivers/net/wireless/wl12xx/init.h index 4975270..0dd2414 100644 --- a/drivers/net/wireless/wl12xx/init.h +++ b/drivers/net/wireless/wl12xx/init.h @@ -33,5 +33,6 @@ int wl1271_init_pta(struct wl1271 *wl); int wl1271_init_energy_detection(struct wl1271 *wl); int wl1271_chip_specific_init(struct wl1271 *wl); int wl1271_hw_init(struct wl1271 *wl); +int wl1271_init_ap_rates(struct wl1271 *wl); #endif diff --git a/drivers/net/wireless/wl12xx/main.c b/drivers/net/wireless/wl12xx/main.c index 7b88dd2..e9d4cf48 100644 --- a/drivers/net/wireless/wl12xx/main.c +++ b/drivers/net/wireless/wl12xx/main.c @@ -209,44 +209,6 @@ static struct conf_drv_settings default_conf = { .tx_op_limit = 1504, }, }, - .ap_rc_conf = { - [0] = { - .enabled_rates = CONF_TX_AP_ENABLED_RATES, - .short_retry_limit = 10, - .long_retry_limit = 10, - .aflags = 0, - }, - [1] = { - .enabled_rates = CONF_TX_AP_ENABLED_RATES, - .short_retry_limit = 10, - .long_retry_limit = 10, - .aflags = 0, - }, - [2] = { - .enabled_rates = CONF_TX_AP_ENABLED_RATES, - .short_retry_limit = 10, - .long_retry_limit = 10, - .aflags = 0, - }, - [3] = { - .enabled_rates = CONF_TX_AP_ENABLED_RATES, - .short_retry_limit = 10, - .long_retry_limit = 10, - .aflags = 0, - }, - }, - .ap_mgmt_conf = { - .enabled_rates = CONF_TX_AP_DEFAULT_MGMT_RATES, - .short_retry_limit = 10, - .long_retry_limit = 10, - .aflags = 0, - }, - .ap_bcst_conf = { - .enabled_rates = CONF_HW_BIT_RATE_1MBPS, - .short_retry_limit = 10, - .long_retry_limit = 10, - .aflags = 0, - }, .max_tx_retries = 100, .ap_aging_period = 300, .tid_conf_count = 4, @@ -2532,22 +2494,13 @@ static void wl1271_bss_info_changed_ap(struct wl1271 *wl, if ((changed & BSS_CHANGED_BASIC_RATES)) { u32 rates = bss_conf->basic_rates; - struct conf_tx_rate_class mgmt_rc; wl->basic_rate_set = wl1271_tx_enabled_rates_get(wl, rates); wl->basic_rate = wl1271_tx_min_rate_get(wl); - wl1271_debug(DEBUG_AP, "basic rates: 0x%x", - wl->basic_rate_set); - - /* update the AP management rate policy with the new rates */ - mgmt_rc.enabled_rates = wl->basic_rate_set; - mgmt_rc.long_retry_limit = 10; - mgmt_rc.short_retry_limit = 10; - mgmt_rc.aflags = 0; - ret = wl1271_acx_ap_rate_policy(wl, &mgmt_rc, - ACX_TX_AP_MODE_MGMT_RATE); + + ret = wl1271_init_ap_rates(wl); if (ret < 0) { - wl1271_error("AP mgmt policy change failed %d", ret); + wl1271_error("AP rate policy change failed %d", ret); goto out; } } -- cgit v0.10.2 From c45a85b5a3c0ca841a7ffc700bdece8ee01486be Mon Sep 17 00:00:00 2001 From: Arik Nemtsov Date: Mon, 18 Apr 2011 14:15:26 +0300 Subject: wl12xx: AP-mode - reconfigure templates after basic rates change When there's a change in the basic rates of the AP, reconfigure relevant templates with the new rates. Signed-off-by: Arik Nemtsov Signed-off-by: Luciano Coelho diff --git a/drivers/net/wireless/wl12xx/init.c b/drivers/net/wireless/wl12xx/init.c index 5d0ecd2..b1242a6 100644 --- a/drivers/net/wireless/wl12xx/init.c +++ b/drivers/net/wireless/wl12xx/init.c @@ -443,7 +443,7 @@ static int wl1271_ap_hw_init(struct wl1271 *wl) return 0; } -static int wl1271_ap_hw_init_post_mem(struct wl1271 *wl) +int wl1271_ap_init_templates(struct wl1271 *wl) { int ret; @@ -470,6 +470,11 @@ static int wl1271_ap_hw_init_post_mem(struct wl1271 *wl) return 0; } +static int wl1271_ap_hw_init_post_mem(struct wl1271 *wl) +{ + return wl1271_ap_init_templates(wl); +} + int wl1271_init_ap_rates(struct wl1271 *wl) { int i, ret; diff --git a/drivers/net/wireless/wl12xx/init.h b/drivers/net/wireless/wl12xx/init.h index 0dd2414..3a3c230 100644 --- a/drivers/net/wireless/wl12xx/init.h +++ b/drivers/net/wireless/wl12xx/init.h @@ -34,5 +34,6 @@ int wl1271_init_energy_detection(struct wl1271 *wl); int wl1271_chip_specific_init(struct wl1271 *wl); int wl1271_hw_init(struct wl1271 *wl); int wl1271_init_ap_rates(struct wl1271 *wl); +int wl1271_ap_init_templates(struct wl1271 *wl); #endif diff --git a/drivers/net/wireless/wl12xx/main.c b/drivers/net/wireless/wl12xx/main.c index e9d4cf48..433bc03 100644 --- a/drivers/net/wireless/wl12xx/main.c +++ b/drivers/net/wireless/wl12xx/main.c @@ -2503,6 +2503,10 @@ static void wl1271_bss_info_changed_ap(struct wl1271 *wl, wl1271_error("AP rate policy change failed %d", ret); goto out; } + + ret = wl1271_ap_init_templates(wl); + if (ret < 0) + goto out; } ret = wl1271_bss_beacon_info_changed(wl, vif, bss_conf, changed); -- cgit v0.10.2 From 2dc5a5c2c656b9029a0e635bb3a1cbcfbcb4ca5c Mon Sep 17 00:00:00 2001 From: Arik Nemtsov Date: Mon, 18 Apr 2011 14:15:27 +0300 Subject: wl12xx: add debugfs entry for starting recovery This entry is useful for debugging the driver state machine during recovery. Signed-off-by: Arik Nemtsov Signed-off-by: Luciano Coelho diff --git a/drivers/net/wireless/wl12xx/debugfs.c b/drivers/net/wireless/wl12xx/debugfs.c index b17cff6..a2b55e5 100644 --- a/drivers/net/wireless/wl12xx/debugfs.c +++ b/drivers/net/wireless/wl12xx/debugfs.c @@ -291,6 +291,25 @@ static const struct file_operations gpio_power_ops = { .llseek = default_llseek, }; +static ssize_t start_recovery_write(struct file *file, + const char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct wl1271 *wl = file->private_data; + + mutex_lock(&wl->mutex); + ieee80211_queue_work(wl->hw, &wl->recovery_work); + mutex_unlock(&wl->mutex); + + return count; +} + +static const struct file_operations start_recovery_ops = { + .write = start_recovery_write, + .open = wl1271_open_file_generic, + .llseek = default_llseek, +}; + static ssize_t dtim_interval_read(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) { @@ -529,6 +548,7 @@ static int wl1271_debugfs_add_files(struct wl1271 *wl, DEBUGFS_ADD(excessive_retries, rootdir); DEBUGFS_ADD(gpio_power, rootdir); + DEBUGFS_ADD(start_recovery, rootdir); DEBUGFS_ADD(dtim_interval, rootdir); DEBUGFS_ADD(beacon_interval, rootdir); -- cgit v0.10.2 From 7dece1c8e1044287287d44ac183a946333b55fc3 Mon Sep 17 00:00:00 2001 From: Arik Nemtsov Date: Mon, 18 Apr 2011 14:15:28 +0300 Subject: wl12xx: fix race condition during recovery in AP mode When operating as AP, the TX queues are not stopped when we start recovery. mac80211 is notified only after the fact. When there is pending TX, it will be queued even after the FW is down. This leads to situations where the TX queues are stopped (because of the TX-watermark mechanism), and are never woken up when we return from recovery. Fix this by explicitly stopping the TX queues when before initiating recovery. Signed-off-by: Arik Nemtsov Signed-off-by: Luciano Coelho diff --git a/drivers/net/wireless/wl12xx/main.c b/drivers/net/wireless/wl12xx/main.c index 433bc03..6dd42c9 100644 --- a/drivers/net/wireless/wl12xx/main.c +++ b/drivers/net/wireless/wl12xx/main.c @@ -352,7 +352,8 @@ static struct conf_drv_settings default_conf = { .hci_io_ds = HCI_IO_DS_6MA, }; -static void __wl1271_op_remove_interface(struct wl1271 *wl); +static void __wl1271_op_remove_interface(struct wl1271 *wl, + bool reset_tx_queues); static void wl1271_free_ap_keys(struct wl1271 *wl); @@ -972,10 +973,19 @@ static void wl1271_recovery_work(struct work_struct *work) if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags)) ieee80211_connection_loss(wl->vif); + /* Prevent spurious TX during FW restart */ + ieee80211_stop_queues(wl->hw); + /* reboot the chipset */ - __wl1271_op_remove_interface(wl); + __wl1271_op_remove_interface(wl, false); ieee80211_restart_hw(wl->hw); + /* + * Its safe to enable TX now - the queues are stopped after a request + * to restart the HW. + */ + ieee80211_wake_queues(wl->hw); + out: mutex_unlock(&wl->mutex); } @@ -1479,7 +1489,8 @@ out: return ret; } -static void __wl1271_op_remove_interface(struct wl1271 *wl) +static void __wl1271_op_remove_interface(struct wl1271 *wl, + bool reset_tx_queues) { int i; @@ -1525,7 +1536,7 @@ static void __wl1271_op_remove_interface(struct wl1271 *wl) mutex_lock(&wl->mutex); /* let's notify MAC80211 about the remaining pending TX frames */ - wl1271_tx_reset(wl); + wl1271_tx_reset(wl, reset_tx_queues); wl1271_power_off(wl); memset(wl->bssid, 0, ETH_ALEN); @@ -1586,7 +1597,7 @@ static void wl1271_op_remove_interface(struct ieee80211_hw *hw, */ if (wl->vif) { WARN_ON(wl->vif != vif); - __wl1271_op_remove_interface(wl); + __wl1271_op_remove_interface(wl, true); } mutex_unlock(&wl->mutex); diff --git a/drivers/net/wireless/wl12xx/tx.c b/drivers/net/wireless/wl12xx/tx.c index cc837bb..ca3ab1c 100644 --- a/drivers/net/wireless/wl12xx/tx.c +++ b/drivers/net/wireless/wl12xx/tx.c @@ -769,8 +769,8 @@ void wl1271_tx_reset_link_queues(struct wl1271 *wl, u8 hlid) wl1271_handle_tx_low_watermark(wl); } -/* caller must hold wl->mutex */ -void wl1271_tx_reset(struct wl1271 *wl) +/* caller must hold wl->mutex and TX must be stopped */ +void wl1271_tx_reset(struct wl1271 *wl, bool reset_tx_queues) { int i; struct sk_buff *skb; @@ -806,8 +806,10 @@ void wl1271_tx_reset(struct wl1271 *wl) /* * Make sure the driver is at a consistent state, in case this * function is called from a context other than interface removal. + * This call will always wake the TX queues. */ - wl1271_handle_tx_low_watermark(wl); + if (reset_tx_queues) + wl1271_handle_tx_low_watermark(wl); for (i = 0; i < ACX_TX_DESCRIPTORS; i++) { if (wl->tx_frames[i] == NULL) diff --git a/drivers/net/wireless/wl12xx/tx.h b/drivers/net/wireless/wl12xx/tx.h index fc7835c..832f925 100644 --- a/drivers/net/wireless/wl12xx/tx.h +++ b/drivers/net/wireless/wl12xx/tx.h @@ -185,7 +185,7 @@ static inline int wl1271_tx_get_queue(int queue) void wl1271_tx_work(struct work_struct *work); void wl1271_tx_work_locked(struct wl1271 *wl); void wl1271_tx_complete(struct wl1271 *wl); -void wl1271_tx_reset(struct wl1271 *wl); +void wl1271_tx_reset(struct wl1271 *wl, bool reset_tx_queues); void wl1271_tx_flush(struct wl1271 *wl); u8 wl1271_rate_to_idx(int rate, enum ieee80211_band band); u32 wl1271_tx_enabled_rates_get(struct wl1271 *wl, u32 rate_set); -- cgit v0.10.2 From 2d66bee7fbd38d28e9ed12f45b8e9db8e6aa0c49 Mon Sep 17 00:00:00 2001 From: Arik Nemtsov Date: Mon, 18 Apr 2011 14:15:29 +0300 Subject: wl12xx: export driver state to debugfs By reading the "driver_state" debugfs value we get all the important state information from the wl12xx driver. This helps testing and debugging, particularly in situations where the driver seems "stuck". Signed-off-by: Arik Nemtsov Signed-off-by: Luciano Coelho diff --git a/drivers/net/wireless/wl12xx/debugfs.c b/drivers/net/wireless/wl12xx/debugfs.c index a2b55e5..b2f692b 100644 --- a/drivers/net/wireless/wl12xx/debugfs.c +++ b/drivers/net/wireless/wl12xx/debugfs.c @@ -310,6 +310,92 @@ static const struct file_operations start_recovery_ops = { .llseek = default_llseek, }; +static ssize_t driver_state_read(struct file *file, char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct wl1271 *wl = file->private_data; + int res = 0; + char buf[1024]; + + mutex_lock(&wl->mutex); + +#define DRIVER_STATE_PRINT(x, fmt) \ + (res += scnprintf(buf + res, sizeof(buf) - res,\ + #x " = " fmt "\n", wl->x)) + +#define DRIVER_STATE_PRINT_LONG(x) DRIVER_STATE_PRINT(x, "%ld") +#define DRIVER_STATE_PRINT_INT(x) DRIVER_STATE_PRINT(x, "%d") +#define DRIVER_STATE_PRINT_STR(x) DRIVER_STATE_PRINT(x, "%s") +#define DRIVER_STATE_PRINT_LHEX(x) DRIVER_STATE_PRINT(x, "0x%lx") +#define DRIVER_STATE_PRINT_HEX(x) DRIVER_STATE_PRINT(x, "0x%x") + + DRIVER_STATE_PRINT_INT(tx_blocks_available); + DRIVER_STATE_PRINT_INT(tx_allocated_blocks); + DRIVER_STATE_PRINT_INT(tx_frames_cnt); + DRIVER_STATE_PRINT_LHEX(tx_frames_map[0]); + DRIVER_STATE_PRINT_INT(tx_queue_count); + DRIVER_STATE_PRINT_INT(tx_packets_count); + DRIVER_STATE_PRINT_INT(tx_results_count); + DRIVER_STATE_PRINT_LHEX(flags); + DRIVER_STATE_PRINT_INT(tx_blocks_freed[0]); + DRIVER_STATE_PRINT_INT(tx_blocks_freed[1]); + DRIVER_STATE_PRINT_INT(tx_blocks_freed[2]); + DRIVER_STATE_PRINT_INT(tx_blocks_freed[3]); + DRIVER_STATE_PRINT_INT(tx_security_last_seq); + DRIVER_STATE_PRINT_INT(rx_counter); + DRIVER_STATE_PRINT_INT(session_counter); + DRIVER_STATE_PRINT_INT(state); + DRIVER_STATE_PRINT_INT(bss_type); + DRIVER_STATE_PRINT_INT(channel); + DRIVER_STATE_PRINT_HEX(rate_set); + DRIVER_STATE_PRINT_HEX(basic_rate_set); + DRIVER_STATE_PRINT_HEX(basic_rate); + DRIVER_STATE_PRINT_INT(band); + DRIVER_STATE_PRINT_INT(beacon_int); + DRIVER_STATE_PRINT_INT(psm_entry_retry); + DRIVER_STATE_PRINT_INT(ps_poll_failures); + DRIVER_STATE_PRINT_HEX(filters); + DRIVER_STATE_PRINT_HEX(rx_config); + DRIVER_STATE_PRINT_HEX(rx_filter); + DRIVER_STATE_PRINT_INT(power_level); + DRIVER_STATE_PRINT_INT(rssi_thold); + DRIVER_STATE_PRINT_INT(last_rssi_event); + DRIVER_STATE_PRINT_INT(sg_enabled); + DRIVER_STATE_PRINT_INT(enable_11a); + DRIVER_STATE_PRINT_INT(noise); + DRIVER_STATE_PRINT_LHEX(ap_hlid_map[0]); + DRIVER_STATE_PRINT_INT(last_tx_hlid); + DRIVER_STATE_PRINT_INT(ba_support); + DRIVER_STATE_PRINT_HEX(ba_rx_bitmap); + DRIVER_STATE_PRINT_HEX(ap_fw_ps_map); + DRIVER_STATE_PRINT_LHEX(ap_ps_map); + DRIVER_STATE_PRINT_HEX(quirks); + DRIVER_STATE_PRINT_HEX(irq); + DRIVER_STATE_PRINT_HEX(ref_clock); + DRIVER_STATE_PRINT_HEX(tcxo_clock); + DRIVER_STATE_PRINT_HEX(hw_pg_ver); + DRIVER_STATE_PRINT_HEX(platform_quirks); + DRIVER_STATE_PRINT_HEX(chip.id); + DRIVER_STATE_PRINT_STR(chip.fw_ver_str); + +#undef DRIVER_STATE_PRINT_INT +#undef DRIVER_STATE_PRINT_LONG +#undef DRIVER_STATE_PRINT_HEX +#undef DRIVER_STATE_PRINT_LHEX +#undef DRIVER_STATE_PRINT_STR +#undef DRIVER_STATE_PRINT + + mutex_unlock(&wl->mutex); + + return simple_read_from_buffer(user_buf, count, ppos, buf, res); +} + +static const struct file_operations driver_state_ops = { + .read = driver_state_read, + .open = wl1271_open_file_generic, + .llseek = default_llseek, +}; + static ssize_t dtim_interval_read(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) { @@ -549,6 +635,7 @@ static int wl1271_debugfs_add_files(struct wl1271 *wl, DEBUGFS_ADD(gpio_power, rootdir); DEBUGFS_ADD(start_recovery, rootdir); + DEBUGFS_ADD(driver_state, rootdir); DEBUGFS_ADD(dtim_interval, rootdir); DEBUGFS_ADD(beacon_interval, rootdir); -- cgit v0.10.2 From ebb47241ea0eac6a5a23404821a2d62f64c68496 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 2 May 2011 10:37:29 +0200 Subject: Revert "ALSA: hda - Fix pin-config of Gigabyte mobo" This reverts commit c6b358748e19ce7e230b0926ac42696bc485a562. It turned out that there are different pin configurations for this PCI SSID, including multi-channel modes. And more proper fix for allowing line-out mutes will come up in 2.6.40 tree, so we won't need this fixup any more there. Reported-by: Andrew Clayton Reported-by: Emmanuel Benisty Cc: Signed-off-by: Takashi Iwai diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 5c26c71..3091e0c 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -9864,6 +9864,7 @@ static struct snd_pci_quirk alc882_cfg_tbl[] = { SND_PCI_QUIRK(0x1071, 0x8258, "Evesham Voyaeger", ALC883_LAPTOP_EAPD), SND_PCI_QUIRK(0x10f1, 0x2350, "TYAN-S2350", ALC888_6ST_DELL), SND_PCI_QUIRK(0x108e, 0x534d, NULL, ALC883_3ST_6ch), + SND_PCI_QUIRK(0x1458, 0xa002, "Gigabyte P35 DS3R", ALC882_6ST_DIG), SND_PCI_QUIRK(0x1462, 0x0349, "MSI", ALC883_TARGA_2ch_DIG), SND_PCI_QUIRK(0x1462, 0x040d, "MSI", ALC883_TARGA_2ch_DIG), @@ -10700,7 +10701,6 @@ enum { PINFIX_LENOVO_Y530, PINFIX_PB_M5210, PINFIX_ACER_ASPIRE_7736, - PINFIX_GIGABYTE_880GM, }; static const struct alc_fixup alc882_fixups[] = { @@ -10732,13 +10732,6 @@ static const struct alc_fixup alc882_fixups[] = { .type = ALC_FIXUP_SKU, .v.sku = ALC_FIXUP_SKU_IGNORE, }, - [PINFIX_GIGABYTE_880GM] = { - .type = ALC_FIXUP_PINS, - .v.pins = (const struct alc_pincfg[]) { - { 0x14, 0x1114410 }, /* set as speaker */ - { } - } - }, }; static struct snd_pci_quirk alc882_fixup_tbl[] = { @@ -10746,7 +10739,6 @@ static struct snd_pci_quirk alc882_fixup_tbl[] = { SND_PCI_QUIRK(0x17aa, 0x3a0d, "Lenovo Y530", PINFIX_LENOVO_Y530), SND_PCI_QUIRK(0x147b, 0x107a, "Abit AW9D-MAX", PINFIX_ABIT_AW9D_MAX), SND_PCI_QUIRK(0x1025, 0x0296, "Acer Aspire 7736z", PINFIX_ACER_ASPIRE_7736), - SND_PCI_QUIRK(0x1458, 0xa002, "Gigabyte", PINFIX_GIGABYTE_880GM), {} }; @@ -18806,6 +18798,8 @@ static struct snd_pci_quirk alc662_cfg_tbl[] = { ALC662_3ST_6ch_DIG), SND_PCI_QUIRK(0x1179, 0xff6e, "Toshiba NB20x", ALC662_AUTO), SND_PCI_QUIRK(0x144d, 0xca00, "Samsung NC10", ALC272_SAMSUNG_NC10), + SND_PCI_QUIRK(0x1458, 0xa002, "Gigabyte 945GCM-S2L", + ALC662_3ST_6ch_DIG), SND_PCI_QUIRK(0x152d, 0x2304, "Quanta WH1", ALC663_ASUS_H13), SND_PCI_QUIRK(0x1565, 0x820f, "Biostar TA780G M2+", ALC662_3ST_6ch_DIG), SND_PCI_QUIRK(0x1631, 0xc10c, "PB RS65", ALC663_ASUS_M51VA), @@ -19479,7 +19473,6 @@ enum { ALC662_FIXUP_IDEAPAD, ALC272_FIXUP_MARIO, ALC662_FIXUP_CZC_P10T, - ALC662_FIXUP_GIGABYTE, ALC662_FIXUP_SKU_IGNORE, }; @@ -19509,13 +19502,6 @@ static const struct alc_fixup alc662_fixups[] = { {} } }, - [ALC662_FIXUP_GIGABYTE] = { - .type = ALC_FIXUP_PINS, - .v.pins = (const struct alc_pincfg[]) { - { 0x14, 0x1114410 }, /* set as speaker */ - { } - } - }, [ALC662_FIXUP_SKU_IGNORE] = { .type = ALC_FIXUP_SKU, .v.sku = ALC_FIXUP_SKU_IGNORE, @@ -19527,7 +19513,6 @@ static struct snd_pci_quirk alc662_fixup_tbl[] = { SND_PCI_QUIRK(0x1025, 0x031c, "Gateway NV79", ALC662_FIXUP_SKU_IGNORE), SND_PCI_QUIRK(0x1025, 0x038b, "Acer Aspire 8943G", ALC662_FIXUP_ASPIRE), SND_PCI_QUIRK(0x144d, 0xc051, "Samsung R720", ALC662_FIXUP_IDEAPAD), - SND_PCI_QUIRK(0x1458, 0xa002, "Gigabyte", ALC662_FIXUP_GIGABYTE), SND_PCI_QUIRK(0x17aa, 0x38af, "Lenovo Ideapad Y550P", ALC662_FIXUP_IDEAPAD), SND_PCI_QUIRK(0x17aa, 0x3a0d, "Lenovo Ideapad Y550", ALC662_FIXUP_IDEAPAD), SND_PCI_QUIRK(0x1b35, 0x2206, "CZC P10T", ALC662_FIXUP_CZC_P10T), -- cgit v0.10.2 From 383cf4e8d47f902600263191f8f167379c376985 Mon Sep 17 00:00:00 2001 From: Jarkko Nikula Date: Wed, 27 Apr 2011 17:02:37 +0300 Subject: usb: musb: omap2430: Fix retention idle on musb peripheral only boards Recent runtime pm and hwmod conversions for 2.6.39 broke the musb peripheral mode OMAP retention idle on boards where the board mode in struct musb_hdrc_platform_data is set to MUSB_PERIPHERAL. These conversions changed the way how the OTG_SYSCONFIG register is configured and used in runtime. Before 2.6.39 smart standby/idle modes were activated statically in OTG_SYSCONFIG. Those modes allow that the musb is able to idle when peripheral device is not connected to host. In 2.6.39 the OTG_SYSCONFIG is updated runtime depending on VBUS status. No standby/idle modes are used when device is connected and force standby/idle when disconnected. Unfortunately VBUS disconnect event that handles the disconnect case lets the peripheral musb to idle only when board mode is MUSB_OTG. Fix this by checking the peripheral mode also. Signed-off-by: Jarkko Nikula Signed-off-by: Felipe Balbi diff --git a/drivers/usb/musb/omap2430.c b/drivers/usb/musb/omap2430.c index 57a27fa..e9e60b6 100644 --- a/drivers/usb/musb/omap2430.c +++ b/drivers/usb/musb/omap2430.c @@ -270,7 +270,7 @@ static int musb_otg_notifications(struct notifier_block *nb, DBG(4, "VBUS Disconnect\n"); #ifdef CONFIG_USB_GADGET_MUSB_HDRC - if (is_otg_enabled(musb)) + if (is_otg_enabled(musb) || is_peripheral_enabled(musb)) if (musb->gadget_driver) #endif { -- cgit v0.10.2 From cdefce169594742ace29a2016dfa381755428ab5 Mon Sep 17 00:00:00 2001 From: Jarkko Nikula Date: Fri, 29 Apr 2011 16:17:35 +0300 Subject: usb: musb: gadget: Fix out-of-sync runtime pm calls If cable is not connected to peripheral only board when initializing the gadget driver, then runtime pm calls are out-of-sync and the musb cannot idle with omap2430.c. This was noted on Nokia N900 where musb prevented the CPU to be able to enter deeper retention idle state. This was working in 2.6.38 before runtime pm conversions but there musb smart standby/idle modes were configured statically where they are now updated runtime depending on use and cable status. Reason for out-of-sync is that runtime pm is activated in function musb_gadget.c: usb_gadget_probe_driver but suspended only in OTG mode if cable is not connected when initializing. In peripheral only mode this leads to out-of-sync runtime pm since runtime pm remain active and is activated another time in omap2430.c: musb_otg_notifications for VBUS Connect event and thus cannot suspend for VBUS Disconnect event since the use count remains active. Fix this by moving cable status check and pm_runtime_put call in usb_gadget_probe_driver out of is_otg_enabled block. Signed-off-by: Jarkko Nikula Signed-off-by: Felipe Balbi diff --git a/drivers/usb/musb/musb_gadget.c b/drivers/usb/musb/musb_gadget.c index 6dfbf9f..f47c201 100644 --- a/drivers/usb/musb/musb_gadget.c +++ b/drivers/usb/musb/musb_gadget.c @@ -1887,11 +1887,9 @@ int usb_gadget_probe_driver(struct usb_gadget_driver *driver, otg_set_vbus(musb->xceiv, 1); hcd->self.uses_pio_for_control = 1; - - if (musb->xceiv->last_event == USB_EVENT_NONE) - pm_runtime_put(musb->controller); - } + if (musb->xceiv->last_event == USB_EVENT_NONE) + pm_runtime_put(musb->controller); return 0; -- cgit v0.10.2 From d11536e4e0e99c26d33c849b44cd279cdd67b032 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Thu, 21 Apr 2011 19:52:41 +0530 Subject: mfd: Fix usbhs_enable error handling In the case of missing platform_data we do not hold a spin_lock, thus we should not call spin_unlock_irqrestore in the error path. Also simplify the error handling by separating the successful path from error path. I think this change improves readability. Signed-off-by: Axel Lin Tested-by: Steve Calfee Signed-off-by: Felipe Balbi diff --git a/drivers/mfd/omap-usb-host.c b/drivers/mfd/omap-usb-host.c index 53450f4..b3bb3ac 100644 --- a/drivers/mfd/omap-usb-host.c +++ b/drivers/mfd/omap-usb-host.c @@ -700,8 +700,7 @@ static int usbhs_enable(struct device *dev) dev_dbg(dev, "starting TI HSUSB Controller\n"); if (!pdata) { dev_dbg(dev, "missing platform_data\n"); - ret = -ENODEV; - goto end_enable; + return -ENODEV; } spin_lock_irqsave(&omap->lock, flags); @@ -915,7 +914,8 @@ static int usbhs_enable(struct device *dev) end_count: omap->count++; - goto end_enable; + spin_unlock_irqrestore(&omap->lock, flags); + return 0; err_tll: if (pdata->ehci_data->phy_reset) { @@ -931,8 +931,6 @@ err_tll: clk_disable(omap->usbhost_fs_fck); clk_disable(omap->usbhost_hs_fck); clk_disable(omap->usbhost_ick); - -end_enable: spin_unlock_irqrestore(&omap->lock, flags); return ret; } -- cgit v0.10.2 From 25eaea30cd7b009ba2ca693708330d2f395cbc4d Mon Sep 17 00:00:00 2001 From: Luciano Coelho Date: Mon, 2 May 2011 12:37:33 +0300 Subject: Revert "wl12xx: support FW TX inactivity triggers" This reverts commit 47684808fd89d6809c0886e06f8ac324252499d8. Conflicts: drivers/net/wireless/wl12xx/conf.h drivers/net/wireless/wl12xx/main.c diff --git a/drivers/net/wireless/wl12xx/acx.c b/drivers/net/wireless/wl12xx/acx.c index ec0156b..c6ee530 100644 --- a/drivers/net/wireless/wl12xx/acx.c +++ b/drivers/net/wireless/wl12xx/acx.c @@ -1577,46 +1577,22 @@ out: return ret; } -int wl1271_acx_ap_max_tx_retry(struct wl1271 *wl) +int wl1271_acx_max_tx_retry(struct wl1271 *wl) { - struct wl1271_acx_ap_max_tx_retry *acx = NULL; + struct wl1271_acx_max_tx_retry *acx = NULL; int ret; - wl1271_debug(DEBUG_ACX, "acx ap max tx retry"); + wl1271_debug(DEBUG_ACX, "acx max tx retry"); acx = kzalloc(sizeof(*acx), GFP_KERNEL); if (!acx) return -ENOMEM; - acx->max_tx_retry = cpu_to_le16(wl->conf.tx.max_tx_retries); + acx->max_tx_retry = cpu_to_le16(wl->conf.tx.ap_max_tx_retries); ret = wl1271_cmd_configure(wl, ACX_MAX_TX_FAILURE, acx, sizeof(*acx)); if (ret < 0) { - wl1271_warning("acx ap max tx retry failed: %d", ret); - goto out; - } - -out: - kfree(acx); - return ret; -} - -int wl1271_acx_sta_max_tx_retry(struct wl1271 *wl) -{ - struct wl1271_acx_sta_max_tx_retry *acx = NULL; - int ret; - - wl1271_debug(DEBUG_ACX, "acx sta max tx retry"); - - acx = kzalloc(sizeof(*acx), GFP_KERNEL); - if (!acx) - return -ENOMEM; - - acx->max_tx_retry = wl->conf.tx.max_tx_retries; - - ret = wl1271_cmd_configure(wl, ACX_CONS_TX_FAILURE, acx, sizeof(*acx)); - if (ret < 0) { - wl1271_warning("acx sta max tx retry failed: %d", ret); + wl1271_warning("acx max tx retry failed: %d", ret); goto out; } diff --git a/drivers/net/wireless/wl12xx/acx.h b/drivers/net/wireless/wl12xx/acx.h index 75338f9..9a895e3 100644 --- a/drivers/net/wireless/wl12xx/acx.h +++ b/drivers/net/wireless/wl12xx/acx.h @@ -1153,7 +1153,7 @@ struct wl1271_acx_fw_tsf_information { u8 padding[3]; } __packed; -struct wl1271_acx_ap_max_tx_retry { +struct wl1271_acx_max_tx_retry { struct acx_header header; /* @@ -1164,13 +1164,6 @@ struct wl1271_acx_ap_max_tx_retry { u8 padding_1[2]; } __packed; -struct wl1271_acx_sta_max_tx_retry { - struct acx_header header; - - u8 max_tx_retry; - u8 padding_1[3]; -} __packed; - struct wl1271_acx_config_ps { struct acx_header header; @@ -1391,8 +1384,7 @@ int wl1271_acx_set_ba_session(struct wl1271 *wl, int wl1271_acx_set_ba_receiver_session(struct wl1271 *wl, u8 tid_index, u16 ssn, bool enable); int wl1271_acx_tsf_info(struct wl1271 *wl, u64 *mactime); -int wl1271_acx_ap_max_tx_retry(struct wl1271 *wl); -int wl1271_acx_sta_max_tx_retry(struct wl1271 *wl); +int wl1271_acx_max_tx_retry(struct wl1271 *wl); int wl1271_acx_config_ps(struct wl1271 *wl); int wl1271_acx_set_inconnection_sta(struct wl1271 *wl, u8 *addr); int wl1271_acx_set_ap_beacon_filter(struct wl1271 *wl, bool enable); diff --git a/drivers/net/wireless/wl12xx/boot.c b/drivers/net/wireless/wl12xx/boot.c index d263ebb..2b0cf85 100644 --- a/drivers/net/wireless/wl12xx/boot.c +++ b/drivers/net/wireless/wl12xx/boot.c @@ -478,12 +478,10 @@ static int wl1271_boot_run_firmware(struct wl1271 *wl) DISCONNECT_EVENT_COMPLETE_ID | RSSI_SNR_TRIGGER_0_EVENT_ID | PSPOLL_DELIVERY_FAILURE_EVENT_ID | - SOFT_GEMINI_SENSE_EVENT_ID | - MAX_TX_RETRY_EVENT_ID; + SOFT_GEMINI_SENSE_EVENT_ID; if (wl->bss_type == BSS_TYPE_AP_BSS) - wl->event_mask |= STA_REMOVE_COMPLETE_EVENT_ID | - INACTIVE_STA_EVENT_ID; + wl->event_mask |= STA_REMOVE_COMPLETE_EVENT_ID; else wl->event_mask |= DUMMY_PACKET_EVENT_ID; diff --git a/drivers/net/wireless/wl12xx/cmd.c b/drivers/net/wireless/wl12xx/cmd.c index d8596ae..2116a37 100644 --- a/drivers/net/wireless/wl12xx/cmd.c +++ b/drivers/net/wireless/wl12xx/cmd.c @@ -1080,7 +1080,7 @@ int wl1271_cmd_start_bss(struct wl1271 *wl) memcpy(cmd->bssid, bss_conf->bssid, ETH_ALEN); - cmd->aging_period = cpu_to_le16(wl->conf.tx.ap_aging_period); + cmd->aging_period = cpu_to_le16(WL1271_AP_DEF_INACTIV_SEC); cmd->bss_index = WL1271_AP_BSS_INDEX; cmd->global_hlid = WL1271_AP_GLOBAL_HLID; cmd->broadcast_hlid = WL1271_AP_BROADCAST_HLID; diff --git a/drivers/net/wireless/wl12xx/conf.h b/drivers/net/wireless/wl12xx/conf.h index c0045f0..1f94736 100644 --- a/drivers/net/wireless/wl12xx/conf.h +++ b/drivers/net/wireless/wl12xx/conf.h @@ -711,18 +711,10 @@ struct conf_tx_settings { struct conf_tx_ac_category ac_conf[CONF_TX_MAX_AC_COUNT]; /* - * Allow this number of TX retries to a connected station/AP before an + * AP-mode - allow this number of TX retries to a station before an * event is triggered from FW. - * In AP-mode the hlids of unreachable stations are given in the - * "sta_tx_retry_exceeded" member in the event mailbox. */ - u8 max_tx_retries; - - /* - * AP-mode - after this number of seconds a connected station is - * considered inactive. - */ - u16 ap_aging_period; + u16 ap_max_tx_retries; /* * Configuration for TID parameters. diff --git a/drivers/net/wireless/wl12xx/event.c b/drivers/net/wireless/wl12xx/event.c index d7be3ae..ae69330 100644 --- a/drivers/net/wireless/wl12xx/event.c +++ b/drivers/net/wireless/wl12xx/event.c @@ -174,8 +174,6 @@ static int wl1271_event_process(struct wl1271 *wl, struct event_mailbox *mbox) u32 vector; bool beacon_loss = false; bool is_ap = (wl->bss_type == BSS_TYPE_AP_BSS); - bool disconnect_sta = false; - unsigned long sta_bitmap = 0; wl1271_event_mbox_dump(mbox); @@ -237,54 +235,9 @@ static int wl1271_event_process(struct wl1271 *wl, struct event_mailbox *mbox) wl1271_tx_dummy_packet(wl); } - /* - * "TX retries exceeded" has a different meaning according to mode. - * In AP mode the offending station is disconnected. In STA mode we - * report connection loss. - */ - if (vector & MAX_TX_RETRY_EVENT_ID) { - wl1271_debug(DEBUG_EVENT, "MAX_TX_RETRY_EVENT_ID"); - if (is_ap) { - sta_bitmap |= le16_to_cpu(mbox->sta_tx_retry_exceeded); - disconnect_sta = true; - } else { - beacon_loss = true; - } - } - - if ((vector & INACTIVE_STA_EVENT_ID) && is_ap) { - wl1271_debug(DEBUG_EVENT, "INACTIVE_STA_EVENT_ID"); - sta_bitmap |= le16_to_cpu(mbox->sta_aging_status); - disconnect_sta = true; - } - if (wl->vif && beacon_loss) ieee80211_connection_loss(wl->vif); - if (is_ap && disconnect_sta) { - u32 num_packets = wl->conf.tx.max_tx_retries; - struct ieee80211_sta *sta; - const u8 *addr; - int h; - - for (h = find_first_bit(&sta_bitmap, AP_MAX_LINKS); - h < AP_MAX_LINKS; - h = find_next_bit(&sta_bitmap, AP_MAX_LINKS, h+1)) { - if (!wl1271_is_active_sta(wl, h)) - continue; - - addr = wl->links[h].addr; - - rcu_read_lock(); - sta = ieee80211_find_sta(wl->vif, addr); - if (sta) { - wl1271_debug(DEBUG_EVENT, "remove sta %d", h); - ieee80211_report_low_ack(sta, num_packets); - } - rcu_read_unlock(); - } - } - return 0; } diff --git a/drivers/net/wireless/wl12xx/event.h b/drivers/net/wireless/wl12xx/event.h index 7ae5a08..b6cf06e 100644 --- a/drivers/net/wireless/wl12xx/event.h +++ b/drivers/net/wireless/wl12xx/event.h @@ -58,16 +58,13 @@ enum { CHANNEL_SWITCH_COMPLETE_EVENT_ID = BIT(17), BSS_LOSE_EVENT_ID = BIT(18), REGAINED_BSS_EVENT_ID = BIT(19), - MAX_TX_RETRY_EVENT_ID = BIT(20), + ROAMING_TRIGGER_MAX_TX_RETRY_EVENT_ID = BIT(20), /* STA: dummy paket for dynamic mem blocks */ DUMMY_PACKET_EVENT_ID = BIT(21), /* AP: STA remove complete */ STA_REMOVE_COMPLETE_EVENT_ID = BIT(21), SOFT_GEMINI_SENSE_EVENT_ID = BIT(22), - /* STA: SG prediction */ SOFT_GEMINI_PREDICTION_EVENT_ID = BIT(23), - /* AP: Inactive STA */ - INACTIVE_STA_EVENT_ID = BIT(23), SOFT_GEMINI_AVALANCHE_EVENT_ID = BIT(24), PLT_RX_CALIBRATION_COMPLETE_EVENT_ID = BIT(25), DBG_EVENT_ID = BIT(26), @@ -122,11 +119,7 @@ struct event_mailbox { /* AP FW only */ u8 hlid_removed; - - /* a bitmap of hlids for stations that have been inactive too long */ __le16 sta_aging_status; - - /* a bitmap of hlids for stations which didn't respond to TX */ __le16 sta_tx_retry_exceeded; u8 reserved_5[24]; @@ -137,7 +130,4 @@ void wl1271_event_mbox_config(struct wl1271 *wl); int wl1271_event_handle(struct wl1271 *wl, u8 mbox); void wl1271_pspoll_work(struct work_struct *work); -/* Functions from main.c */ -bool wl1271_is_active_sta(struct wl1271 *wl, u8 hlid); - #endif diff --git a/drivers/net/wireless/wl12xx/init.c b/drivers/net/wireless/wl12xx/init.c index b1242a6..a8f4f15 100644 --- a/drivers/net/wireless/wl12xx/init.c +++ b/drivers/net/wireless/wl12xx/init.c @@ -378,10 +378,6 @@ static int wl1271_sta_hw_init(struct wl1271 *wl) if (ret < 0) return ret; - ret = wl1271_acx_sta_max_tx_retry(wl); - if (ret < 0) - return ret; - ret = wl1271_acx_sta_mem_cfg(wl); if (ret < 0) return ret; @@ -432,7 +428,7 @@ static int wl1271_ap_hw_init(struct wl1271 *wl) if (ret < 0) return ret; - ret = wl1271_acx_ap_max_tx_retry(wl); + ret = wl1271_acx_max_tx_retry(wl); if (ret < 0) return ret; diff --git a/drivers/net/wireless/wl12xx/main.c b/drivers/net/wireless/wl12xx/main.c index 6dd42c9..6dab6f0 100644 --- a/drivers/net/wireless/wl12xx/main.c +++ b/drivers/net/wireless/wl12xx/main.c @@ -209,8 +209,7 @@ static struct conf_drv_settings default_conf = { .tx_op_limit = 1504, }, }, - .max_tx_retries = 100, - .ap_aging_period = 300, + .ap_max_tx_retries = 100, .tid_conf_count = 4, .tid_conf = { [CONF_TX_AC_BE] = { @@ -3021,12 +3020,6 @@ static void wl1271_free_sta(struct wl1271 *wl, u8 hlid) __clear_bit(hlid, (unsigned long *)&wl->ap_fw_ps_map); } -bool wl1271_is_active_sta(struct wl1271 *wl, u8 hlid) -{ - int id = hlid - WL1271_AP_STA_HLID_START; - return test_bit(id, wl->ap_hlid_map); -} - static int wl1271_op_sta_add(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_sta *sta) @@ -3632,6 +3625,7 @@ int wl1271_init_ieee80211(struct wl1271 *wl) IEEE80211_HW_HAS_RATE_CONTROL | IEEE80211_HW_CONNECTION_MONITOR | IEEE80211_HW_SUPPORTS_CQM_RSSI | + IEEE80211_HW_REPORTS_TX_ACK_STATUS | IEEE80211_HW_AP_LINK_PS; wl->hw->wiphy->cipher_suites = cipher_suites; diff --git a/drivers/net/wireless/wl12xx/wl12xx.h b/drivers/net/wireless/wl12xx/wl12xx.h index f3de962..b760143 100644 --- a/drivers/net/wireless/wl12xx/wl12xx.h +++ b/drivers/net/wireless/wl12xx/wl12xx.h @@ -172,6 +172,7 @@ extern u32 wl12xx_debug_level; #define WL1271_PS_STA_MAX_BLOCKS (2 * 9) #define WL1271_AP_BSS_INDEX 0 +#define WL1271_AP_DEF_INACTIV_SEC 300 #define WL1271_AP_DEF_BEACON_EXP 20 #define ACX_TX_DESCRIPTORS 32 -- cgit v0.10.2 From 24af2b1cc418d6791b1d9e56bf6070cccb752db3 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 2 May 2011 13:55:36 +0200 Subject: ALSA: hda - Fix Realtek's chained fixup checks The check of chained fixup list entry was done against the wrong element. A stupid mistake during refactoring. Cc: Signed-off-by: Takashi Iwai diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 3091e0c..c82979a 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -1704,11 +1704,11 @@ static void alc_apply_fixup(struct hda_codec *codec, int action) codec->chip_name, fix->type); break; } - if (!fix[id].chained) + if (!fix->chained) break; if (++depth > 10) break; - id = fix[id].chain_id; + id = fix->chain_id; } } -- cgit v0.10.2 From 9688678a6670c7f0ae3872450a8047c0ad401efb Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Mon, 2 May 2011 14:18:51 +0200 Subject: x86-64, NUMA: Simplify hotadd memory handling The only special handling NUMA needs to do for hotadd memory is determining the node for the hotadd memory given the address of it and there's nothing specific to specific config method used. srat_64.c does somewhat elaborate error checking on ACPI_SRAT_MEM_HOT_PLUGGABLE regions, remembers them and implements memory_add_physaddr_to_nid() which determines the node for given hotadd address. This is almost completely redundant. All the information is already available to the generic NUMA code which already performs all the sanity checking and merging. All that's necessary is not using __initdata from numa_meminfo and providing a function which uses it to map address to node. Drop the specific implementation from srat_64.c and add generic memory_add_physaddr_to_nid() in numa_64.c, which is enabled if CONFIG_MEMORY_HOTPLUG is set. Other than dropping the code, srat_64.c doesn't need any change as it already calls numa_add_memblk() for hot pluggable regions which is enough. While at it, change CONFIG_MEMORY_HOTPLUG_SPARSE in srat_64.c to CONFIG_MEMORY_HOTPLUG, for NUMA on x86-64, the two are always the same. Signed-off-by: Tejun Heo Cc: Ingo Molnar Cc: Yinghai Lu Cc: David Rientjes Cc: Thomas Gleixner Cc: "H. Peter Anvin" diff --git a/arch/x86/mm/init_64.c b/arch/x86/mm/init_64.c index 7942335..0404bb3 100644 --- a/arch/x86/mm/init_64.c +++ b/arch/x86/mm/init_64.c @@ -679,14 +679,6 @@ int arch_add_memory(int nid, u64 start, u64 size) } EXPORT_SYMBOL_GPL(arch_add_memory); -#if !defined(CONFIG_ACPI_NUMA) && defined(CONFIG_NUMA) -int memory_add_physaddr_to_nid(u64 start) -{ - return 0; -} -EXPORT_SYMBOL_GPL(memory_add_physaddr_to_nid); -#endif - #endif /* CONFIG_MEMORY_HOTPLUG */ static struct kcore_list kcore_vsyscall; diff --git a/arch/x86/mm/numa_64.c b/arch/x86/mm/numa_64.c index a96767c..4057b5d 100644 --- a/arch/x86/mm/numa_64.c +++ b/arch/x86/mm/numa_64.c @@ -28,7 +28,12 @@ EXPORT_SYMBOL(node_data); nodemask_t numa_nodes_parsed __initdata; -static struct numa_meminfo numa_meminfo __initdata; +static struct numa_meminfo numa_meminfo +#ifndef CONFIG_MEMORY_HOTPLUG +__initdata +#endif +; + static int numa_distance_cnt; static u8 *numa_distance; @@ -540,3 +545,18 @@ int __cpuinit numa_cpu_node(int cpu) return __apicid_to_node[apicid]; return NUMA_NO_NODE; } + +#ifdef CONFIG_MEMORY_HOTPLUG +int memory_add_physaddr_to_nid(u64 start) +{ + struct numa_meminfo *mi = &numa_meminfo; + int nid = mi->blk[0].nid; + int i; + + for (i = 0; i < mi->nr_blks; i++) + if (mi->blk[i].start <= start && mi->blk[i].end > start) + nid = mi->blk[i].nid; + return nid; +} +EXPORT_SYMBOL_GPL(memory_add_physaddr_to_nid); +#endif diff --git a/arch/x86/mm/srat_64.c b/arch/x86/mm/srat_64.c index 8e9d339..9994d2c 100644 --- a/arch/x86/mm/srat_64.c +++ b/arch/x86/mm/srat_64.c @@ -26,8 +26,6 @@ int acpi_numa __initdata; -static struct bootnode nodes_add[MAX_NUMNODES]; - static __init int setup_node(int pxm) { return acpi_map_pxm_to_node(pxm); @@ -37,7 +35,6 @@ static __init void bad_srat(void) { printk(KERN_ERR "SRAT: SRAT not used.\n"); acpi_numa = -1; - memset(nodes_add, 0, sizeof(nodes_add)); } static __init inline int srat_disabled(void) @@ -131,67 +128,11 @@ acpi_numa_processor_affinity_init(struct acpi_srat_cpu_affinity *pa) pxm, apic_id, node); } -#ifdef CONFIG_MEMORY_HOTPLUG_SPARSE +#ifdef CONFIG_MEMORY_HOTPLUG static inline int save_add_info(void) {return 1;} #else static inline int save_add_info(void) {return 0;} #endif -/* - * Update nodes_add[] - * This code supports one contiguous hot add area per node - */ -static void __init -update_nodes_add(int node, unsigned long start, unsigned long end) -{ - unsigned long s_pfn = start >> PAGE_SHIFT; - unsigned long e_pfn = end >> PAGE_SHIFT; - int changed = 0; - struct bootnode *nd = &nodes_add[node]; - - /* I had some trouble with strange memory hotadd regions breaking - the boot. Be very strict here and reject anything unexpected. - If you want working memory hotadd write correct SRATs. - - The node size check is a basic sanity check to guard against - mistakes */ - if ((signed long)(end - start) < NODE_MIN_SIZE) { - printk(KERN_ERR "SRAT: Hotplug area too small\n"); - return; - } - - /* This check might be a bit too strict, but I'm keeping it for now. */ - if (absent_pages_in_range(s_pfn, e_pfn) != e_pfn - s_pfn) { - printk(KERN_ERR - "SRAT: Hotplug area %lu -> %lu has existing memory\n", - s_pfn, e_pfn); - return; - } - - /* Looks good */ - - if (nd->start == nd->end) { - nd->start = start; - nd->end = end; - changed = 1; - } else { - if (nd->start == end) { - nd->start = start; - changed = 1; - } - if (nd->end == start) { - nd->end = end; - changed = 1; - } - if (!changed) - printk(KERN_ERR "SRAT: Hotplug zone not continuous. Partly ignored\n"); - } - - if (changed) { - node_set(node, numa_nodes_parsed); - printk(KERN_INFO "SRAT: hot plug zone found %Lx - %Lx\n", - nd->start, nd->end); - } -} /* Callback for parsing of the Proximity Domain <-> Memory Area mappings */ void __init @@ -228,9 +169,6 @@ acpi_numa_memory_affinity_init(struct acpi_srat_mem_affinity *ma) printk(KERN_INFO "SRAT: Node %u PXM %u %lx-%lx\n", node, pxm, start, end); - - if (ma->flags & ACPI_SRAT_MEM_HOT_PLUGGABLE) - update_nodes_add(node, start, end); } void __init acpi_numa_arch_fixup(void) {} @@ -244,17 +182,3 @@ int __init x86_acpi_numa_init(void) return ret; return srat_disabled() ? -EINVAL : 0; } - -#if defined(CONFIG_MEMORY_HOTPLUG_SPARSE) || defined(CONFIG_ACPI_HOTPLUG_MEMORY) -int memory_add_physaddr_to_nid(u64 start) -{ - int i, ret = 0; - - for_each_node(i) - if (nodes_add[i].start <= start && nodes_add[i].end > start) - ret = i; - - return ret; -} -EXPORT_SYMBOL_GPL(memory_add_physaddr_to_nid); -#endif -- cgit v0.10.2 From ebe685f24eeb85fbdb0f33792f1dabdbf35eff38 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Mon, 2 May 2011 14:18:51 +0200 Subject: x86-64, NUMA: trivial cleanups for setup_node_bootmem() Make the following trivial changes in preparation for further updates. * nodeid -> nid, nid -> tnid * use nd_ prefix for nodedata related variables * remove start/end_pfn and use start/end directly Signed-off-by: Tejun Heo Cc: Ingo Molnar Cc: Yinghai Lu Cc: David Rientjes Cc: Thomas Gleixner Cc: "H. Peter Anvin" diff --git a/arch/x86/mm/numa_64.c b/arch/x86/mm/numa_64.c index 4057b5d..8043d5e 100644 --- a/arch/x86/mm/numa_64.c +++ b/arch/x86/mm/numa_64.c @@ -128,14 +128,11 @@ int __init numa_add_memblk(int nid, u64 start, u64 end) /* Initialize bootmem allocator for a node */ void __init -setup_node_bootmem(int nodeid, unsigned long start, unsigned long end) +setup_node_bootmem(int nid, unsigned long start, unsigned long end) { - unsigned long start_pfn, last_pfn, nodedata_phys; - const int pgdat_size = roundup(sizeof(pg_data_t), PAGE_SIZE); - int nid; - - if (!end) - return; + const size_t nd_size = roundup(sizeof(pg_data_t), PAGE_SIZE); + unsigned long nd_pa; + int tnid; /* * Don't confuse VM with a node that doesn't have the @@ -146,30 +143,27 @@ setup_node_bootmem(int nodeid, unsigned long start, unsigned long end) start = roundup(start, ZONE_ALIGN); - printk(KERN_INFO "Initmem setup node %d %016lx-%016lx\n", nodeid, - start, end); - - start_pfn = start >> PAGE_SHIFT; - last_pfn = end >> PAGE_SHIFT; + printk(KERN_INFO "Initmem setup node %d %016lx-%016lx\n", + nid, start, end); - node_data[nodeid] = early_node_mem(nodeid, start, end, pgdat_size, - SMP_CACHE_BYTES); - if (node_data[nodeid] == NULL) + node_data[nid] = early_node_mem(nid, start, end, nd_size, + SMP_CACHE_BYTES); + if (node_data[nid] == NULL) return; - nodedata_phys = __pa(node_data[nodeid]); - memblock_x86_reserve_range(nodedata_phys, nodedata_phys + pgdat_size, "NODE_DATA"); - printk(KERN_INFO " NODE_DATA [%016lx - %016lx]\n", nodedata_phys, - nodedata_phys + pgdat_size - 1); - nid = early_pfn_to_nid(nodedata_phys >> PAGE_SHIFT); - if (nid != nodeid) - printk(KERN_INFO " NODE_DATA(%d) on node %d\n", nodeid, nid); - - memset(NODE_DATA(nodeid), 0, sizeof(pg_data_t)); - NODE_DATA(nodeid)->node_id = nodeid; - NODE_DATA(nodeid)->node_start_pfn = start_pfn; - NODE_DATA(nodeid)->node_spanned_pages = last_pfn - start_pfn; - - node_set_online(nodeid); + nd_pa = __pa(node_data[nid]); + memblock_x86_reserve_range(nd_pa, nd_pa + nd_size, "NODE_DATA"); + printk(KERN_INFO " NODE_DATA [%016lx - %016lx]\n", + nd_pa, nd_pa + nd_size - 1); + tnid = early_pfn_to_nid(nd_pa >> PAGE_SHIFT); + if (tnid != nid) + printk(KERN_INFO " NODE_DATA(%d) on node %d\n", nid, tnid); + + memset(NODE_DATA(nid), 0, sizeof(pg_data_t)); + NODE_DATA(nid)->node_id = nid; + NODE_DATA(nid)->node_start_pfn = start >> PAGE_SHIFT; + NODE_DATA(nid)->node_spanned_pages = (end - start) >> PAGE_SHIFT; + + node_set_online(nid); } /** -- cgit v0.10.2 From acd26d611e60c1a7c2a14269ab99760f779121f4 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Mon, 2 May 2011 14:18:51 +0200 Subject: x86-64, NUMA: simplify nodedata allocation With top-down memblock allocation, the allocation range limits in ealry_node_mem() can be simplified - try node-local first, then any node but in any case don't allocate below DMA limit. Remove early_node_mem() and implement simplified allocation directly in setup_node_bootmem(). Signed-off-by: Tejun Heo Cc: Ingo Molnar Cc: Yinghai Lu Cc: David Rientjes Cc: Thomas Gleixner Cc: "H. Peter Anvin" diff --git a/arch/x86/mm/numa_64.c b/arch/x86/mm/numa_64.c index 8043d5e..b4fd25e 100644 --- a/arch/x86/mm/numa_64.c +++ b/arch/x86/mm/numa_64.c @@ -37,38 +37,6 @@ __initdata static int numa_distance_cnt; static u8 *numa_distance; -static void * __init early_node_mem(int nodeid, unsigned long start, - unsigned long end, unsigned long size, - unsigned long align) -{ - unsigned long mem; - - /* - * put it on high as possible - * something will go with NODE_DATA - */ - if (start < (MAX_DMA_PFN< (MAX_DMA32_PFN<> PAGE_SHIFT); if (tnid != nid) printk(KERN_INFO " NODE_DATA(%d) on node %d\n", nid, tnid); + node_data[nid] = __va(nd_pa); memset(NODE_DATA(nid), 0, sizeof(pg_data_t)); NODE_DATA(nid)->node_id = nid; NODE_DATA(nid)->node_start_pfn = start >> PAGE_SHIFT; -- cgit v0.10.2 From c4b90c11992e61123071977c0e5556e59a70852c Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Mon, 2 May 2011 14:18:52 +0200 Subject: x86-32, NUMA: Automatically set apicid -> node in setup_local_APIC() Some x86-32 NUMA implementations (NUMAQ) don't initialize apicid -> node mapping using set_apicid_to_node() during NUMA init but implement custom apic->x86_32_numa_cpu_node() instead. This patch automatically initializes the default apic -> node mapping table from apic->x86_32_numa_cpu_node() from setup_local_APIC() such that the mapping table is in sync with the actual mapping. As the table isn't used by custom implementations, this doesn't make any difference at this point. This is in preparation of unifying numa_cpu_node() between x86-32 and 64. Signed-off-by: Tejun Heo Cc: Ingo Molnar Cc: Yinghai Lu Cc: David Rientjes Cc: Thomas Gleixner Cc: "H. Peter Anvin" diff --git a/arch/x86/kernel/apic/apic.c b/arch/x86/kernel/apic/apic.c index 2bc503b..a6cd02a 100644 --- a/arch/x86/kernel/apic/apic.c +++ b/arch/x86/kernel/apic/apic.c @@ -1237,6 +1237,16 @@ void __cpuinit setup_local_APIC(void) /* always use the value from LDR */ early_per_cpu(x86_cpu_to_logical_apicid, cpu) = logical_smp_processor_id(); + + /* + * Some NUMA implementations (NUMAQ) don't initialize apicid to + * node mapping during NUMA init. Now that logical apicid is + * guaranteed to be known, give it another chance. This is already + * a bit too late - percpu allocation has already happened without + * proper NUMA affinity. + */ + set_apicid_to_node(early_per_cpu(x86_cpu_to_apicid, cpu), + apic->x86_32_numa_cpu_node(cpu)); #endif /* -- cgit v0.10.2 From 6bd262731bf7559bab8c749786e8652e2df1fb4e Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Mon, 2 May 2011 14:18:52 +0200 Subject: x86, NUMA: Unify 32/64bit numa_cpu_node() implementation Currently, the only meaningful user of apic->x86_32_numa_cpu_node() is NUMAQ which returns valid mapping only after CPU is initialized during SMP bringup; thus, the previous patch to set apicid -> node in setup_local_APIC() makes __apicid_to_node[] always contain the correct mapping whether custom apic->x86_32_numa_cpu_node() is used or not. So, there is no reason to keep separate 32bit implementation. We can always consult __apicid_to_node[]. Move 64bit implementation from numa_64.c to numa.c and remove 32bit implementation from numa_32.c. Signed-off-by: Tejun Heo Cc: Ingo Molnar Cc: Yinghai Lu Cc: David Rientjes Cc: Thomas Gleixner Cc: "H. Peter Anvin" diff --git a/arch/x86/include/asm/numa.h b/arch/x86/include/asm/numa.h index a50fc9f..5982d41 100644 --- a/arch/x86/include/asm/numa.h +++ b/arch/x86/include/asm/numa.h @@ -1,6 +1,8 @@ #ifndef _ASM_X86_NUMA_H #define _ASM_X86_NUMA_H +#include + #include #include @@ -22,10 +24,18 @@ static inline void set_apicid_to_node(int apicid, s16 node) { __apicid_to_node[apicid] = node; } + +extern int __cpuinit numa_cpu_node(int cpu); + #else /* CONFIG_NUMA */ static inline void set_apicid_to_node(int apicid, s16 node) { } + +static inline int numa_cpu_node(int cpu) +{ + return NUMA_NO_NODE; +} #endif /* CONFIG_NUMA */ #ifdef CONFIG_X86_32 diff --git a/arch/x86/include/asm/numa_32.h b/arch/x86/include/asm/numa_32.h index c6beed1..242522f 100644 --- a/arch/x86/include/asm/numa_32.h +++ b/arch/x86/include/asm/numa_32.h @@ -5,12 +5,6 @@ extern int numa_off; extern int pxm_to_nid(int pxm); -#ifdef CONFIG_NUMA -extern int __cpuinit numa_cpu_node(int cpu); -#else /* CONFIG_NUMA */ -static inline int numa_cpu_node(int cpu) { return NUMA_NO_NODE; } -#endif /* CONFIG_NUMA */ - #ifdef CONFIG_HIGHMEM extern void set_highmem_pages_init(void); #else diff --git a/arch/x86/include/asm/numa_64.h b/arch/x86/include/asm/numa_64.h index 344eb17..12461eb 100644 --- a/arch/x86/include/asm/numa_64.h +++ b/arch/x86/include/asm/numa_64.h @@ -26,7 +26,6 @@ extern void setup_node_bootmem(int nodeid, unsigned long start, extern nodemask_t numa_nodes_parsed __initdata; -extern int __cpuinit numa_cpu_node(int cpu); extern int __init numa_add_memblk(int nodeid, u64 start, u64 end); extern void __init numa_set_distance(int from, int to, int distance); @@ -35,8 +34,6 @@ extern void __init numa_set_distance(int from, int to, int distance); #define FAKE_NODE_MIN_HASH_MASK (~(FAKE_NODE_MIN_SIZE - 1UL)) void numa_emu_cmdline(char *); #endif /* CONFIG_NUMA_EMU */ -#else -static inline int numa_cpu_node(int cpu) { return NUMA_NO_NODE; } #endif #endif /* _ASM_X86_NUMA_64_H */ diff --git a/arch/x86/mm/numa.c b/arch/x86/mm/numa.c index 745258d..e9005c4 100644 --- a/arch/x86/mm/numa.c +++ b/arch/x86/mm/numa.c @@ -32,6 +32,15 @@ s16 __apicid_to_node[MAX_LOCAL_APIC] __cpuinitdata = { [0 ... MAX_LOCAL_APIC-1] = NUMA_NO_NODE }; +int __cpuinit numa_cpu_node(int cpu) +{ + int apicid = early_per_cpu(x86_cpu_to_apicid, cpu); + + if (apicid != BAD_APICID) + return __apicid_to_node[apicid]; + return NUMA_NO_NODE; +} + cpumask_var_t node_to_cpumask_map[MAX_NUMNODES]; EXPORT_SYMBOL(node_to_cpumask_map); diff --git a/arch/x86/mm/numa_32.c b/arch/x86/mm/numa_32.c index c757c0a..e0d9716 100644 --- a/arch/x86/mm/numa_32.c +++ b/arch/x86/mm/numa_32.c @@ -107,11 +107,6 @@ extern unsigned long highend_pfn, highstart_pfn; static void *node_remap_start_vaddr[MAX_NUMNODES]; void set_pmd_pfn(unsigned long vaddr, unsigned long pfn, pgprot_t flags); -int __cpuinit numa_cpu_node(int cpu) -{ - return apic->x86_32_numa_cpu_node(cpu); -} - /* * FLAT - support for basic PC memory model with discontig enabled, essentially * a single node with all available processors in it with a flat diff --git a/arch/x86/mm/numa_64.c b/arch/x86/mm/numa_64.c index b4fd25e..7f83ade 100644 --- a/arch/x86/mm/numa_64.c +++ b/arch/x86/mm/numa_64.c @@ -512,15 +512,6 @@ unsigned long __init numa_free_all_bootmem(void) return pages; } -int __cpuinit numa_cpu_node(int cpu) -{ - int apicid = early_per_cpu(x86_cpu_to_apicid, cpu); - - if (apicid != BAD_APICID) - return __apicid_to_node[apicid]; - return NUMA_NO_NODE; -} - #ifdef CONFIG_MEMORY_HOTPLUG int memory_add_physaddr_to_nid(u64 start) { -- cgit v0.10.2 From 84914ed0ec6787d38e84b510f92ad4ca3a572fd8 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Mon, 2 May 2011 14:18:52 +0200 Subject: x86-32, NUMA: Make apic->x86_32_numa_cpu_node() optional NUMAQ is the only meaningful user of this callback and setup_local_APIC() the only callsite. Stop torturing everyone else by making the callback optional and removing all the boilerplate implementations and assignments. Signed-off-by: Tejun Heo Cc: Ingo Molnar Cc: Yinghai Lu Cc: David Rientjes Cc: Thomas Gleixner Cc: "H. Peter Anvin" diff --git a/arch/x86/include/asm/apic.h b/arch/x86/include/asm/apic.h index 2b7d573..a0c46f0 100644 --- a/arch/x86/include/asm/apic.h +++ b/arch/x86/include/asm/apic.h @@ -363,7 +363,12 @@ struct apic { */ int (*x86_32_early_logical_apicid)(int cpu); - /* determine CPU -> NUMA node mapping */ + /* + * Optional method called from setup_local_APIC() after logical + * apicid is guaranteed to be known to initialize apicid -> node + * mapping if NUMA initialization hasn't done so already. Don't + * add new users. + */ int (*x86_32_numa_cpu_node)(int cpu); #endif }; @@ -537,8 +542,6 @@ static inline int default_phys_pkg_id(int cpuid_apic, int index_msb) return cpuid_apic >> index_msb; } -extern int default_x86_32_numa_cpu_node(int cpu); - #endif static inline unsigned int diff --git a/arch/x86/kernel/apic/apic.c b/arch/x86/kernel/apic/apic.c index a6cd02a..0c67b4f 100644 --- a/arch/x86/kernel/apic/apic.c +++ b/arch/x86/kernel/apic/apic.c @@ -1245,8 +1245,9 @@ void __cpuinit setup_local_APIC(void) * a bit too late - percpu allocation has already happened without * proper NUMA affinity. */ - set_apicid_to_node(early_per_cpu(x86_cpu_to_apicid, cpu), - apic->x86_32_numa_cpu_node(cpu)); + if (apic->x86_32_numa_cpu_node) + set_apicid_to_node(early_per_cpu(x86_cpu_to_apicid, cpu), + apic->x86_32_numa_cpu_node(cpu)); #endif /* @@ -2013,21 +2014,6 @@ void default_init_apic_ldr(void) apic_write(APIC_LDR, val); } -#ifdef CONFIG_X86_32 -int default_x86_32_numa_cpu_node(int cpu) -{ -#ifdef CONFIG_NUMA - int apicid = early_per_cpu(x86_cpu_to_apicid, cpu); - - if (apicid != BAD_APICID) - return __apicid_to_node[apicid]; - return NUMA_NO_NODE; -#else - return 0; -#endif -} -#endif - /* * Power management */ diff --git a/arch/x86/kernel/apic/apic_noop.c b/arch/x86/kernel/apic/apic_noop.c index f1baa2d..775b82b 100644 --- a/arch/x86/kernel/apic/apic_noop.c +++ b/arch/x86/kernel/apic/apic_noop.c @@ -119,14 +119,6 @@ static void noop_apic_write(u32 reg, u32 v) WARN_ON_ONCE(cpu_has_apic && !disable_apic); } -#ifdef CONFIG_X86_32 -static int noop_x86_32_numa_cpu_node(int cpu) -{ - /* we're always on node 0 */ - return 0; -} -#endif - struct apic apic_noop = { .name = "noop", .probe = noop_probe, @@ -195,6 +187,5 @@ struct apic apic_noop = { #ifdef CONFIG_X86_32 .x86_32_early_logical_apicid = noop_x86_32_early_logical_apicid, - .x86_32_numa_cpu_node = noop_x86_32_numa_cpu_node, #endif }; diff --git a/arch/x86/kernel/apic/bigsmp_32.c b/arch/x86/kernel/apic/bigsmp_32.c index 541a2e4..d84ac5a5 100644 --- a/arch/x86/kernel/apic/bigsmp_32.c +++ b/arch/x86/kernel/apic/bigsmp_32.c @@ -253,5 +253,4 @@ struct apic apic_bigsmp = { .safe_wait_icr_idle = native_safe_apic_wait_icr_idle, .x86_32_early_logical_apicid = bigsmp_early_logical_apicid, - .x86_32_numa_cpu_node = default_x86_32_numa_cpu_node, }; diff --git a/arch/x86/kernel/apic/es7000_32.c b/arch/x86/kernel/apic/es7000_32.c index 3e9de48..70533de 100644 --- a/arch/x86/kernel/apic/es7000_32.c +++ b/arch/x86/kernel/apic/es7000_32.c @@ -510,11 +510,6 @@ static void es7000_setup_apic_routing(void) nr_ioapics, cpumask_bits(es7000_target_cpus())[0]); } -static int es7000_numa_cpu_node(int cpu) -{ - return 0; -} - static int es7000_cpu_present_to_apicid(int mps_cpu) { if (!mps_cpu) @@ -688,7 +683,6 @@ struct apic __refdata apic_es7000_cluster = { .safe_wait_icr_idle = native_safe_apic_wait_icr_idle, .x86_32_early_logical_apicid = es7000_early_logical_apicid, - .x86_32_numa_cpu_node = es7000_numa_cpu_node, }; struct apic __refdata apic_es7000 = { @@ -752,5 +746,4 @@ struct apic __refdata apic_es7000 = { .safe_wait_icr_idle = native_safe_apic_wait_icr_idle, .x86_32_early_logical_apicid = es7000_early_logical_apicid, - .x86_32_numa_cpu_node = es7000_numa_cpu_node, }; diff --git a/arch/x86/kernel/apic/probe_32.c b/arch/x86/kernel/apic/probe_32.c index fc84c7b..6541e47 100644 --- a/arch/x86/kernel/apic/probe_32.c +++ b/arch/x86/kernel/apic/probe_32.c @@ -172,7 +172,6 @@ struct apic apic_default = { .safe_wait_icr_idle = native_safe_apic_wait_icr_idle, .x86_32_early_logical_apicid = default_x86_32_early_logical_apicid, - .x86_32_numa_cpu_node = default_x86_32_numa_cpu_node, }; extern struct apic apic_numaq; diff --git a/arch/x86/kernel/apic/summit_32.c b/arch/x86/kernel/apic/summit_32.c index e4b8059..35bcd7d 100644 --- a/arch/x86/kernel/apic/summit_32.c +++ b/arch/x86/kernel/apic/summit_32.c @@ -551,5 +551,4 @@ struct apic apic_summit = { .safe_wait_icr_idle = native_safe_apic_wait_icr_idle, .x86_32_early_logical_apicid = summit_early_logical_apicid, - .x86_32_numa_cpu_node = default_x86_32_numa_cpu_node, }; -- cgit v0.10.2 From 797390d8554b1e07aabea37d0140933b0412dba0 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Mon, 2 May 2011 14:18:52 +0200 Subject: x86-32, NUMA: use sparse_memory_present_with_active_regions() Instead of calling memory_present() for each region from NUMA init, call sparse_memory_present_with_active_regions() from paging_init() similarly to x86-64. For flat and numaq, this results in exactly the same memory_present() calls. For srat, if there are multiple memory chunks for a node, after this change, memory_present() will be called separately for each chunk instead of being called once to encompass the whole range, which doesn't cause any harm and actually is the better behavior. Signed-off-by: Tejun Heo Cc: Ingo Molnar Cc: Yinghai Lu Cc: David Rientjes Cc: Thomas Gleixner Cc: "H. Peter Anvin" diff --git a/arch/x86/kernel/apic/numaq_32.c b/arch/x86/kernel/apic/numaq_32.c index 0aced70..41b8b29 100644 --- a/arch/x86/kernel/apic/numaq_32.c +++ b/arch/x86/kernel/apic/numaq_32.c @@ -91,8 +91,6 @@ static inline void numaq_register_node(int node, struct sys_cfg_data *scd) memblock_x86_register_active_regions(node, node_start_pfn[node], node_end_pfn[node]); - - memory_present(node, node_start_pfn[node], node_end_pfn[node]); } /* diff --git a/arch/x86/mm/init_32.c b/arch/x86/mm/init_32.c index 80088f9..2cde0a34 100644 --- a/arch/x86/mm/init_32.c +++ b/arch/x86/mm/init_32.c @@ -716,6 +716,7 @@ void __init paging_init(void) * NOTE: at this point the bootmem allocator is fully available. */ olpc_dt_build_devicetree(); + sparse_memory_present_with_active_regions(MAX_NUMNODES); sparse_init(); zone_sizes_init(); } diff --git a/arch/x86/mm/numa_32.c b/arch/x86/mm/numa_32.c index e0d9716..f847fa1 100644 --- a/arch/x86/mm/numa_32.c +++ b/arch/x86/mm/numa_32.c @@ -119,7 +119,6 @@ int __init get_memcfg_numa_flat(void) node_start_pfn[0] = 0; node_end_pfn[0] = max_pfn; memblock_x86_register_active_regions(0, 0, max_pfn); - memory_present(0, 0, max_pfn); /* Indicate there is one node available. */ nodes_clear(node_online_map); diff --git a/arch/x86/mm/srat_32.c b/arch/x86/mm/srat_32.c index ae20046..6b9bfd7 100644 --- a/arch/x86/mm/srat_32.c +++ b/arch/x86/mm/srat_32.c @@ -209,7 +209,7 @@ static __init int node_read_chunk(int nid, struct node_memory_chunk_s *memory_ch int __init get_memcfg_from_srat(void) { - int i, j, nid; + int i, j; if (srat_disabled()) goto out_fail; @@ -273,12 +273,6 @@ int __init get_memcfg_from_srat(void) /* for out of order entries in SRAT */ sort_node_map(); - for_each_online_node(nid) { - unsigned long start = node_start_pfn[nid]; - unsigned long end = min(node_end_pfn[nid], max_pfn); - - memory_present(nid, start, end); - } return 1; out_fail: printk(KERN_DEBUG "failed to get NUMA memory information from SRAT" -- cgit v0.10.2 From 1201e10a092adc9c88a6ce5f27740cc5cd0d26e5 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Mon, 2 May 2011 14:18:52 +0200 Subject: x86, NUMA: trivial cleanups * Kill no longer used struct bootnode. * Kill dangling declaration of pxm_to_nid() in numa_32.h. * Make setup_node_bootmem() static. Signed-off-by: Tejun Heo Cc: Ingo Molnar Cc: Yinghai Lu Cc: David Rientjes Cc: Thomas Gleixner Cc: "H. Peter Anvin" diff --git a/arch/x86/include/asm/acpi.h b/arch/x86/include/asm/acpi.h index 12e0e7d..416d865 100644 --- a/arch/x86/include/asm/acpi.h +++ b/arch/x86/include/asm/acpi.h @@ -183,8 +183,6 @@ static inline void disable_acpi(void) { } #define ARCH_HAS_POWER_INIT 1 -struct bootnode; - #ifdef CONFIG_ACPI_NUMA extern int acpi_numa; extern int x86_acpi_numa_init(void); diff --git a/arch/x86/include/asm/amd_nb.h b/arch/x86/include/asm/amd_nb.h index 3316822..67f87f2 100644 --- a/arch/x86/include/asm/amd_nb.h +++ b/arch/x86/include/asm/amd_nb.h @@ -11,7 +11,6 @@ struct amd_nb_bus_dev_range { extern const struct pci_device_id amd_nb_misc_ids[]; extern const struct amd_nb_bus_dev_range amd_nb_bus_dev_ranges[]; -struct bootnode; extern bool early_is_amd_nb(u32 value); extern int amd_cache_northbridges(void); diff --git a/arch/x86/include/asm/numa_32.h b/arch/x86/include/asm/numa_32.h index 242522f..7e54b64 100644 --- a/arch/x86/include/asm/numa_32.h +++ b/arch/x86/include/asm/numa_32.h @@ -3,8 +3,6 @@ extern int numa_off; -extern int pxm_to_nid(int pxm); - #ifdef CONFIG_HIGHMEM extern void set_highmem_pages_init(void); #else diff --git a/arch/x86/include/asm/numa_64.h b/arch/x86/include/asm/numa_64.h index 12461eb..794da6d 100644 --- a/arch/x86/include/asm/numa_64.h +++ b/arch/x86/include/asm/numa_64.h @@ -3,18 +3,11 @@ #include -struct bootnode { - u64 start; - u64 end; -}; - #define ZONE_ALIGN (1UL << (MAX_ORDER+PAGE_SHIFT)) extern int numa_off; extern unsigned long numa_free_all_bootmem(void); -extern void setup_node_bootmem(int nodeid, unsigned long start, - unsigned long end); #ifdef CONFIG_NUMA /* diff --git a/arch/x86/mm/numa_64.c b/arch/x86/mm/numa_64.c index 7f83ade..287ae79 100644 --- a/arch/x86/mm/numa_64.c +++ b/arch/x86/mm/numa_64.c @@ -95,7 +95,7 @@ int __init numa_add_memblk(int nid, u64 start, u64 end) } /* Initialize bootmem allocator for a node */ -void __init +static void __init setup_node_bootmem(int nid, unsigned long start, unsigned long end) { const u64 nd_low = (u64)MAX_DMA_PFN << PAGE_SHIFT; -- cgit v0.10.2 From 7b2600f8ee0536bb738f3387cf2c30e8e334e149 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Mon, 2 May 2011 14:18:52 +0200 Subject: x86, NUMA: rename srat_64.c to srat.c Rename srat_64.c to srat.c. This is to prepare for unification of NUMA init paths between 32 and 64bit. Signed-off-by: Tejun Heo Cc: Ingo Molnar Cc: Yinghai Lu Cc: David Rientjes Cc: Thomas Gleixner Cc: "H. Peter Anvin" diff --git a/arch/x86/mm/Makefile b/arch/x86/mm/Makefile index 3e608ed..37e7043 100644 --- a/arch/x86/mm/Makefile +++ b/arch/x86/mm/Makefile @@ -24,7 +24,10 @@ obj-$(CONFIG_MMIOTRACE_TEST) += testmmiotrace.o obj-$(CONFIG_NUMA) += numa.o numa_$(BITS).o obj-$(CONFIG_AMD_NUMA) += amdtopology_64.o -obj-$(CONFIG_ACPI_NUMA) += srat_$(BITS).o +ifeq ($(CONFIG_ACPI_NUMA),y) +obj-$(CONFIG_X86_64) += srat.o +obj-$(CONFIG_X86_32) += srat_32.o +endif obj-$(CONFIG_NUMA_EMU) += numa_emulation.o obj-$(CONFIG_HAVE_MEMBLOCK) += memblock.o diff --git a/arch/x86/mm/srat.c b/arch/x86/mm/srat.c new file mode 100644 index 0000000..9994d2c --- /dev/null +++ b/arch/x86/mm/srat.c @@ -0,0 +1,184 @@ +/* + * ACPI 3.0 based NUMA setup + * Copyright 2004 Andi Kleen, SuSE Labs. + * + * Reads the ACPI SRAT table to figure out what memory belongs to which CPUs. + * + * Called from acpi_numa_init while reading the SRAT and SLIT tables. + * Assumes all memory regions belonging to a single proximity domain + * are in one chunk. Holes between them will be included in the node. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +int acpi_numa __initdata; + +static __init int setup_node(int pxm) +{ + return acpi_map_pxm_to_node(pxm); +} + +static __init void bad_srat(void) +{ + printk(KERN_ERR "SRAT: SRAT not used.\n"); + acpi_numa = -1; +} + +static __init inline int srat_disabled(void) +{ + return acpi_numa < 0; +} + +/* Callback for SLIT parsing */ +void __init acpi_numa_slit_init(struct acpi_table_slit *slit) +{ + int i, j; + + for (i = 0; i < slit->locality_count; i++) + for (j = 0; j < slit->locality_count; j++) + numa_set_distance(pxm_to_node(i), pxm_to_node(j), + slit->entry[slit->locality_count * i + j]); +} + +/* Callback for Proximity Domain -> x2APIC mapping */ +void __init +acpi_numa_x2apic_affinity_init(struct acpi_srat_x2apic_cpu_affinity *pa) +{ + int pxm, node; + int apic_id; + + if (srat_disabled()) + return; + if (pa->header.length < sizeof(struct acpi_srat_x2apic_cpu_affinity)) { + bad_srat(); + return; + } + if ((pa->flags & ACPI_SRAT_CPU_ENABLED) == 0) + return; + pxm = pa->proximity_domain; + node = setup_node(pxm); + if (node < 0) { + printk(KERN_ERR "SRAT: Too many proximity domains %x\n", pxm); + bad_srat(); + return; + } + + apic_id = pa->apic_id; + if (apic_id >= MAX_LOCAL_APIC) { + printk(KERN_INFO "SRAT: PXM %u -> APIC 0x%04x -> Node %u skipped apicid that is too big\n", pxm, apic_id, node); + return; + } + set_apicid_to_node(apic_id, node); + node_set(node, numa_nodes_parsed); + acpi_numa = 1; + printk(KERN_INFO "SRAT: PXM %u -> APIC 0x%04x -> Node %u\n", + pxm, apic_id, node); +} + +/* Callback for Proximity Domain -> LAPIC mapping */ +void __init +acpi_numa_processor_affinity_init(struct acpi_srat_cpu_affinity *pa) +{ + int pxm, node; + int apic_id; + + if (srat_disabled()) + return; + if (pa->header.length != sizeof(struct acpi_srat_cpu_affinity)) { + bad_srat(); + return; + } + if ((pa->flags & ACPI_SRAT_CPU_ENABLED) == 0) + return; + pxm = pa->proximity_domain_lo; + node = setup_node(pxm); + if (node < 0) { + printk(KERN_ERR "SRAT: Too many proximity domains %x\n", pxm); + bad_srat(); + return; + } + + if (get_uv_system_type() >= UV_X2APIC) + apic_id = (pa->apic_id << 8) | pa->local_sapic_eid; + else + apic_id = pa->apic_id; + + if (apic_id >= MAX_LOCAL_APIC) { + printk(KERN_INFO "SRAT: PXM %u -> APIC 0x%02x -> Node %u skipped apicid that is too big\n", pxm, apic_id, node); + return; + } + + set_apicid_to_node(apic_id, node); + node_set(node, numa_nodes_parsed); + acpi_numa = 1; + printk(KERN_INFO "SRAT: PXM %u -> APIC 0x%02x -> Node %u\n", + pxm, apic_id, node); +} + +#ifdef CONFIG_MEMORY_HOTPLUG +static inline int save_add_info(void) {return 1;} +#else +static inline int save_add_info(void) {return 0;} +#endif + +/* Callback for parsing of the Proximity Domain <-> Memory Area mappings */ +void __init +acpi_numa_memory_affinity_init(struct acpi_srat_mem_affinity *ma) +{ + unsigned long start, end; + int node, pxm; + + if (srat_disabled()) + return; + if (ma->header.length != sizeof(struct acpi_srat_mem_affinity)) { + bad_srat(); + return; + } + if ((ma->flags & ACPI_SRAT_MEM_ENABLED) == 0) + return; + + if ((ma->flags & ACPI_SRAT_MEM_HOT_PLUGGABLE) && !save_add_info()) + return; + start = ma->base_address; + end = start + ma->length; + pxm = ma->proximity_domain; + node = setup_node(pxm); + if (node < 0) { + printk(KERN_ERR "SRAT: Too many proximity domains.\n"); + bad_srat(); + return; + } + + if (numa_add_memblk(node, start, end) < 0) { + bad_srat(); + return; + } + + printk(KERN_INFO "SRAT: Node %u PXM %u %lx-%lx\n", node, pxm, + start, end); +} + +void __init acpi_numa_arch_fixup(void) {} + +int __init x86_acpi_numa_init(void) +{ + int ret; + + ret = acpi_numa_init(); + if (ret < 0) + return ret; + return srat_disabled() ? -EINVAL : 0; +} diff --git a/arch/x86/mm/srat_64.c b/arch/x86/mm/srat_64.c deleted file mode 100644 index 9994d2c..0000000 --- a/arch/x86/mm/srat_64.c +++ /dev/null @@ -1,184 +0,0 @@ -/* - * ACPI 3.0 based NUMA setup - * Copyright 2004 Andi Kleen, SuSE Labs. - * - * Reads the ACPI SRAT table to figure out what memory belongs to which CPUs. - * - * Called from acpi_numa_init while reading the SRAT and SLIT tables. - * Assumes all memory regions belonging to a single proximity domain - * are in one chunk. Holes between them will be included in the node. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -int acpi_numa __initdata; - -static __init int setup_node(int pxm) -{ - return acpi_map_pxm_to_node(pxm); -} - -static __init void bad_srat(void) -{ - printk(KERN_ERR "SRAT: SRAT not used.\n"); - acpi_numa = -1; -} - -static __init inline int srat_disabled(void) -{ - return acpi_numa < 0; -} - -/* Callback for SLIT parsing */ -void __init acpi_numa_slit_init(struct acpi_table_slit *slit) -{ - int i, j; - - for (i = 0; i < slit->locality_count; i++) - for (j = 0; j < slit->locality_count; j++) - numa_set_distance(pxm_to_node(i), pxm_to_node(j), - slit->entry[slit->locality_count * i + j]); -} - -/* Callback for Proximity Domain -> x2APIC mapping */ -void __init -acpi_numa_x2apic_affinity_init(struct acpi_srat_x2apic_cpu_affinity *pa) -{ - int pxm, node; - int apic_id; - - if (srat_disabled()) - return; - if (pa->header.length < sizeof(struct acpi_srat_x2apic_cpu_affinity)) { - bad_srat(); - return; - } - if ((pa->flags & ACPI_SRAT_CPU_ENABLED) == 0) - return; - pxm = pa->proximity_domain; - node = setup_node(pxm); - if (node < 0) { - printk(KERN_ERR "SRAT: Too many proximity domains %x\n", pxm); - bad_srat(); - return; - } - - apic_id = pa->apic_id; - if (apic_id >= MAX_LOCAL_APIC) { - printk(KERN_INFO "SRAT: PXM %u -> APIC 0x%04x -> Node %u skipped apicid that is too big\n", pxm, apic_id, node); - return; - } - set_apicid_to_node(apic_id, node); - node_set(node, numa_nodes_parsed); - acpi_numa = 1; - printk(KERN_INFO "SRAT: PXM %u -> APIC 0x%04x -> Node %u\n", - pxm, apic_id, node); -} - -/* Callback for Proximity Domain -> LAPIC mapping */ -void __init -acpi_numa_processor_affinity_init(struct acpi_srat_cpu_affinity *pa) -{ - int pxm, node; - int apic_id; - - if (srat_disabled()) - return; - if (pa->header.length != sizeof(struct acpi_srat_cpu_affinity)) { - bad_srat(); - return; - } - if ((pa->flags & ACPI_SRAT_CPU_ENABLED) == 0) - return; - pxm = pa->proximity_domain_lo; - node = setup_node(pxm); - if (node < 0) { - printk(KERN_ERR "SRAT: Too many proximity domains %x\n", pxm); - bad_srat(); - return; - } - - if (get_uv_system_type() >= UV_X2APIC) - apic_id = (pa->apic_id << 8) | pa->local_sapic_eid; - else - apic_id = pa->apic_id; - - if (apic_id >= MAX_LOCAL_APIC) { - printk(KERN_INFO "SRAT: PXM %u -> APIC 0x%02x -> Node %u skipped apicid that is too big\n", pxm, apic_id, node); - return; - } - - set_apicid_to_node(apic_id, node); - node_set(node, numa_nodes_parsed); - acpi_numa = 1; - printk(KERN_INFO "SRAT: PXM %u -> APIC 0x%02x -> Node %u\n", - pxm, apic_id, node); -} - -#ifdef CONFIG_MEMORY_HOTPLUG -static inline int save_add_info(void) {return 1;} -#else -static inline int save_add_info(void) {return 0;} -#endif - -/* Callback for parsing of the Proximity Domain <-> Memory Area mappings */ -void __init -acpi_numa_memory_affinity_init(struct acpi_srat_mem_affinity *ma) -{ - unsigned long start, end; - int node, pxm; - - if (srat_disabled()) - return; - if (ma->header.length != sizeof(struct acpi_srat_mem_affinity)) { - bad_srat(); - return; - } - if ((ma->flags & ACPI_SRAT_MEM_ENABLED) == 0) - return; - - if ((ma->flags & ACPI_SRAT_MEM_HOT_PLUGGABLE) && !save_add_info()) - return; - start = ma->base_address; - end = start + ma->length; - pxm = ma->proximity_domain; - node = setup_node(pxm); - if (node < 0) { - printk(KERN_ERR "SRAT: Too many proximity domains.\n"); - bad_srat(); - return; - } - - if (numa_add_memblk(node, start, end) < 0) { - bad_srat(); - return; - } - - printk(KERN_INFO "SRAT: Node %u PXM %u %lx-%lx\n", node, pxm, - start, end); -} - -void __init acpi_numa_arch_fixup(void) {} - -int __init x86_acpi_numa_init(void) -{ - int ret; - - ret = acpi_numa_init(); - if (ret < 0) - return ret; - return srat_disabled() ? -EINVAL : 0; -} -- cgit v0.10.2 From eca9ad313293c41021bfcf23e985a14f6991a121 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Mon, 2 May 2011 14:18:52 +0200 Subject: x86, NUMA: make srat.c 32bit safe Make srat.c 32bit safe by removing the assumption that unsigned long is 64bit. Signed-off-by: Tejun Heo Cc: Ingo Molnar Cc: Yinghai Lu Cc: David Rientjes Cc: Thomas Gleixner Cc: "H. Peter Anvin" diff --git a/arch/x86/mm/srat.c b/arch/x86/mm/srat.c index 9994d2c..81dbfde 100644 --- a/arch/x86/mm/srat.c +++ b/arch/x86/mm/srat.c @@ -138,7 +138,7 @@ static inline int save_add_info(void) {return 0;} void __init acpi_numa_memory_affinity_init(struct acpi_srat_mem_affinity *ma) { - unsigned long start, end; + u64 start, end; int node, pxm; if (srat_disabled()) @@ -167,7 +167,7 @@ acpi_numa_memory_affinity_init(struct acpi_srat_mem_affinity *ma) return; } - printk(KERN_INFO "SRAT: Node %u PXM %u %lx-%lx\n", node, pxm, + printk(KERN_INFO "SRAT: Node %u PXM %u %Lx-%Lx\n", node, pxm, start, end); } -- cgit v0.10.2 From daf4f480ae24270bac06db4293908d36b4834e21 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Mon, 2 May 2011 14:18:53 +0200 Subject: x86-32, NUMA: Move get_memcfg_numa() into numa_32.c There's no reason get_memcfg_numa() to be implemented inline in mmzone_32.h. Move it to numa_32.c and also make get_memcfg_numa_flag() static. Signed-off-by: Tejun Heo Cc: Ingo Molnar Cc: Yinghai Lu Cc: David Rientjes Cc: Thomas Gleixner Cc: "H. Peter Anvin" diff --git a/arch/x86/include/asm/mmzone_32.h b/arch/x86/include/asm/mmzone_32.h index 91df7c5..73e5745 100644 --- a/arch/x86/include/asm/mmzone_32.h +++ b/arch/x86/include/asm/mmzone_32.h @@ -16,28 +16,10 @@ extern struct pglist_data *node_data[]; /* summit or generic arch */ #include -extern int get_memcfg_numa_flat(void); -/* - * This allows any one NUMA architecture to be compiled - * for, and still fall back to the flat function if it - * fails. - */ -static inline void get_memcfg_numa(void) -{ - - if (get_memcfg_numaq()) - return; - if (get_memcfg_from_srat()) - return; - get_memcfg_numa_flat(); -} - extern void resume_map_numa_kva(pgd_t *pgd); #else /* !CONFIG_NUMA */ -#define get_memcfg_numa get_memcfg_numa_flat - static inline void resume_map_numa_kva(pgd_t *pgd) {} #endif /* CONFIG_NUMA */ diff --git a/arch/x86/mm/numa_32.c b/arch/x86/mm/numa_32.c index f847fa1..abf1247 100644 --- a/arch/x86/mm/numa_32.c +++ b/arch/x86/mm/numa_32.c @@ -112,7 +112,7 @@ void set_pmd_pfn(unsigned long vaddr, unsigned long pfn, pgprot_t flags); * a single node with all available processors in it with a flat * memory map. */ -int __init get_memcfg_numa_flat(void) +static int __init get_memcfg_numa_flat(void) { printk(KERN_DEBUG "NUMA - single node, flat memory mode\n"); @@ -332,6 +332,15 @@ static __init void init_alloc_remap(int nid) nid, node_pa, node_pa + size, remap_va, remap_va + size); } +static void get_memcfg_numa(void) +{ + if (get_memcfg_numaq()) + return; + if (get_memcfg_from_srat()) + return; + get_memcfg_numa_flat(); +} + void __init initmem_init(void) { int nid; -- cgit v0.10.2 From e6df595b37c7c033ef7400b4fdd382a2dc4f4131 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Mon, 2 May 2011 14:18:53 +0200 Subject: x86, NUMA: Move numa_nodes_parsed to numa.[hc] Move numa_nodes_parsed from numa_64.[hc] to numa.[hc] to prepare for NUMA init path unification. Signed-off-by: Tejun Heo Cc: Ingo Molnar Cc: Yinghai Lu Cc: David Rientjes Cc: Thomas Gleixner Cc: "H. Peter Anvin" diff --git a/arch/x86/include/asm/numa.h b/arch/x86/include/asm/numa.h index 5982d41..c24306c 100644 --- a/arch/x86/include/asm/numa.h +++ b/arch/x86/include/asm/numa.h @@ -19,6 +19,7 @@ * numa_cpu_node(). */ extern s16 __apicid_to_node[MAX_LOCAL_APIC]; +extern nodemask_t numa_nodes_parsed __initdata; static inline void set_apicid_to_node(int apicid, s16 node) { diff --git a/arch/x86/include/asm/numa_64.h b/arch/x86/include/asm/numa_64.h index 794da6d..e84113f 100644 --- a/arch/x86/include/asm/numa_64.h +++ b/arch/x86/include/asm/numa_64.h @@ -1,8 +1,6 @@ #ifndef _ASM_X86_NUMA_64_H #define _ASM_X86_NUMA_64_H -#include - #define ZONE_ALIGN (1UL << (MAX_ORDER+PAGE_SHIFT)) extern int numa_off; @@ -17,8 +15,6 @@ extern unsigned long numa_free_all_bootmem(void); */ #define NODE_MIN_SIZE (4*1024*1024) -extern nodemask_t numa_nodes_parsed __initdata; - extern int __init numa_add_memblk(int nodeid, u64 start, u64 end); extern void __init numa_set_distance(int from, int to, int distance); diff --git a/arch/x86/mm/numa.c b/arch/x86/mm/numa.c index e9005c4..cce1741 100644 --- a/arch/x86/mm/numa.c +++ b/arch/x86/mm/numa.c @@ -6,6 +6,7 @@ #include int __initdata numa_off; +nodemask_t numa_nodes_parsed __initdata; static __init int numa_setup(char *opt) { diff --git a/arch/x86/mm/numa_64.c b/arch/x86/mm/numa_64.c index 287ae79..70bd822 100644 --- a/arch/x86/mm/numa_64.c +++ b/arch/x86/mm/numa_64.c @@ -26,8 +26,6 @@ struct pglist_data *node_data[MAX_NUMNODES] __read_mostly; EXPORT_SYMBOL(node_data); -nodemask_t numa_nodes_parsed __initdata; - static struct numa_meminfo numa_meminfo #ifndef CONFIG_MEMORY_HOTPLUG __initdata -- cgit v0.10.2 From b0d310801a4c1f95b44357e4ebc22a9903e3bf3d Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Mon, 2 May 2011 14:18:53 +0200 Subject: x86-32, NUMA: implement temporary NUMA init shims To help transition to common NUMA init, implement temporary 32bit shims for numa_add_memblk() and numa_set_distance(). numa_add_memblk() registers the memblk and adjusts node_start/end_pfn[]. numa_set_distance() is noop. These shims will allow using 64bit NUMA init functions on 32bit and gradual transition to common NUMA init path. For detailed description, please read description of commits which make use of the shim functions. Signed-off-by: Tejun Heo Cc: Ingo Molnar Cc: Yinghai Lu Cc: David Rientjes Cc: Thomas Gleixner Cc: "H. Peter Anvin" diff --git a/arch/x86/include/asm/numa.h b/arch/x86/include/asm/numa.h index c24306c..db449c7 100644 --- a/arch/x86/include/asm/numa.h +++ b/arch/x86/include/asm/numa.h @@ -21,6 +21,9 @@ extern s16 __apicid_to_node[MAX_LOCAL_APIC]; extern nodemask_t numa_nodes_parsed __initdata; +extern int __init numa_add_memblk(int nodeid, u64 start, u64 end); +extern void __init numa_set_distance(int from, int to, int distance); + static inline void set_apicid_to_node(int apicid, s16 node) { __apicid_to_node[apicid] = node; diff --git a/arch/x86/include/asm/numa_64.h b/arch/x86/include/asm/numa_64.h index e84113f..506dd05 100644 --- a/arch/x86/include/asm/numa_64.h +++ b/arch/x86/include/asm/numa_64.h @@ -15,9 +15,6 @@ extern unsigned long numa_free_all_bootmem(void); */ #define NODE_MIN_SIZE (4*1024*1024) -extern int __init numa_add_memblk(int nodeid, u64 start, u64 end); -extern void __init numa_set_distance(int from, int to, int distance); - #ifdef CONFIG_NUMA_EMU #define FAKE_NODE_MIN_SIZE ((u64)32 << 20) #define FAKE_NODE_MIN_HASH_MASK (~(FAKE_NODE_MIN_SIZE - 1UL)) diff --git a/arch/x86/mm/numa_32.c b/arch/x86/mm/numa_32.c index abf1247..d0369a5 100644 --- a/arch/x86/mm/numa_32.c +++ b/arch/x86/mm/numa_32.c @@ -414,3 +414,37 @@ int memory_add_physaddr_to_nid(u64 addr) EXPORT_SYMBOL_GPL(memory_add_physaddr_to_nid); #endif +/* temporary shim, will go away soon */ +int __init numa_add_memblk(int nid, u64 start, u64 end) +{ + unsigned long start_pfn = start >> PAGE_SHIFT; + unsigned long end_pfn = end >> PAGE_SHIFT; + + printk(KERN_DEBUG "nid %d start_pfn %08lx end_pfn %08lx\n", + nid, start_pfn, end_pfn); + + if (start >= (u64)max_pfn << PAGE_SHIFT) { + printk(KERN_INFO "Ignoring SRAT pfns: %08lx - %08lx\n", + start_pfn, end_pfn); + return 0; + } + + node_set_online(nid); + memblock_x86_register_active_regions(nid, start_pfn, + min(end_pfn, max_pfn)); + + if (!node_has_online_mem(nid)) { + node_start_pfn[nid] = start_pfn; + node_end_pfn[nid] = end_pfn; + } else { + node_start_pfn[nid] = min(node_start_pfn[nid], start_pfn); + node_end_pfn[nid] = max(node_end_pfn[nid], end_pfn); + } + return 0; +} + +/* temporary shim, will go away soon */ +void __init numa_set_distance(int from, int to, int distance) +{ + /* nada */ +} -- cgit v0.10.2 From 5acd91ab837c9d066af7345aea6462dc55695db7 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Mon, 2 May 2011 14:18:53 +0200 Subject: x86-32, NUMA: Replace srat_32.c with srat.c SRAT support implementation in srat_32.c and srat.c are generally similar; however, there are some differences. First of all, 64bit implementation supports more types of SRAT entries. 64bit supports x2apic, affinity, memory and SLIT. 32bit only supports processor and memory. Most other differences stem from different initialization protocols employed by 64bit and 32bit NUMA init paths. On 64bit, * Mappings among PXM, node and apicid are directly done in each SRAT entry callback. * Memory affinity information is passed to numa_add_memblk() which takes care of all interfacing with NUMA init. * Doesn't directly initialize NUMA configurations. All the information is recorded in numa_nodes_parsed and memblks. On 32bit, * Checks numa_off. * Things go through one more level of indirection via private tables but eventually end up initializing the same mappings. * node_start/end_pfn[] are initialized and memblock_x86_register_active_regions() is called for each memory chunk. * node_set_online() is called for each online node. * sort_node_map() is called. There are also other minor differences in sanity checking and messages but taking 64bit version should be good enough. This patch drops the 32bit specific implementation and makes the 64bit implementation common for both 32 and 64bit. The init protocol differences are dealt with in two places - the numa_add_memblk() shim added in the previous patch and new temporary numa_32.c:get_memcfg_from_srat() which wraps invocation of x86_acpi_numa_init(). The shim numa_add_memblk() handles the folowings. * node_start/end_pfn[] initialization. * node_set_online() for memory nodes. * Invocation of memblock_x86_register_active_regions(). The shim get_memcfg_from_srat() handles the followings. * numa_off check. * node_set_online() for CPU nodes. * sort_node_map() invocation. * Clearing of numa_nodes_parsed and active_ranges on failure. The shims are temporary and will be removed as the generic NUMA init path in 32bit is replaced with 64bit one. Signed-off-by: Tejun Heo Cc: Ingo Molnar Cc: Yinghai Lu Cc: David Rientjes Cc: Thomas Gleixner Cc: "H. Peter Anvin" diff --git a/arch/x86/include/asm/mmzone_32.h b/arch/x86/include/asm/mmzone_32.h index 73e5745..5e83a41 100644 --- a/arch/x86/include/asm/mmzone_32.h +++ b/arch/x86/include/asm/mmzone_32.h @@ -13,8 +13,6 @@ extern struct pglist_data *node_data[]; #define NODE_DATA(nid) (node_data[nid]) #include -/* summit or generic arch */ -#include extern void resume_map_numa_kva(pgd_t *pgd); diff --git a/arch/x86/include/asm/srat.h b/arch/x86/include/asm/srat.h deleted file mode 100644 index b508d63..0000000 --- a/arch/x86/include/asm/srat.h +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Some of the code in this file has been gleaned from the 64 bit - * discontigmem support code base. - * - * Copyright (C) 2002, IBM Corp. - * - * All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or - * NON INFRINGEMENT. See the GNU General Public License for more - * details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - * - * Send feedback to Pat Gaughen - */ - -#ifndef _ASM_X86_SRAT_H -#define _ASM_X86_SRAT_H - -#ifdef CONFIG_ACPI_NUMA -extern int get_memcfg_from_srat(void); -#else -static inline int get_memcfg_from_srat(void) -{ - return 0; -} -#endif - -#endif /* _ASM_X86_SRAT_H */ diff --git a/arch/x86/mm/Makefile b/arch/x86/mm/Makefile index 37e7043..62997be 100644 --- a/arch/x86/mm/Makefile +++ b/arch/x86/mm/Makefile @@ -24,10 +24,7 @@ obj-$(CONFIG_MMIOTRACE_TEST) += testmmiotrace.o obj-$(CONFIG_NUMA) += numa.o numa_$(BITS).o obj-$(CONFIG_AMD_NUMA) += amdtopology_64.o -ifeq ($(CONFIG_ACPI_NUMA),y) -obj-$(CONFIG_X86_64) += srat.o -obj-$(CONFIG_X86_32) += srat_32.o -endif +obj-$(CONFIG_ACPI_NUMA) += srat.o obj-$(CONFIG_NUMA_EMU) += numa_emulation.o obj-$(CONFIG_HAVE_MEMBLOCK) += memblock.o diff --git a/arch/x86/mm/numa_32.c b/arch/x86/mm/numa_32.c index d0369a5..8641239 100644 --- a/arch/x86/mm/numa_32.c +++ b/arch/x86/mm/numa_32.c @@ -332,6 +332,29 @@ static __init void init_alloc_remap(int nid) nid, node_pa, node_pa + size, remap_va, remap_va + size); } +static int get_memcfg_from_srat(void) +{ +#ifdef CONFIG_ACPI_NUMA + int nid; + + if (numa_off) + return 0; + + if (x86_acpi_numa_init() < 0) { + nodes_clear(numa_nodes_parsed); + remove_all_active_ranges(); + return 0; + } + + for_each_node_mask(nid, numa_nodes_parsed) + node_set_online(nid); + sort_node_map(); + return 1; +#else + return 0; +#endif +} + static void get_memcfg_numa(void) { if (get_memcfg_numaq()) diff --git a/arch/x86/mm/srat_32.c b/arch/x86/mm/srat_32.c deleted file mode 100644 index 6b9bfd7..0000000 --- a/arch/x86/mm/srat_32.c +++ /dev/null @@ -1,281 +0,0 @@ -/* - * Some of the code in this file has been gleaned from the 64 bit - * discontigmem support code base. - * - * Copyright (C) 2002, IBM Corp. - * - * All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or - * NON INFRINGEMENT. See the GNU General Public License for more - * details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - * - * Send feedback to Pat Gaughen - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* - * proximity macros and definitions - */ -#define NODE_ARRAY_INDEX(x) ((x) / 8) /* 8 bits/char */ -#define NODE_ARRAY_OFFSET(x) ((x) % 8) /* 8 bits/char */ -#define BMAP_SET(bmap, bit) ((bmap)[NODE_ARRAY_INDEX(bit)] |= 1 << NODE_ARRAY_OFFSET(bit)) -#define BMAP_TEST(bmap, bit) ((bmap)[NODE_ARRAY_INDEX(bit)] & (1 << NODE_ARRAY_OFFSET(bit))) -/* bitmap length; _PXM is at most 255 */ -#define PXM_BITMAP_LEN (MAX_PXM_DOMAINS / 8) -static u8 __initdata pxm_bitmap[PXM_BITMAP_LEN]; /* bitmap of proximity domains */ - -#define MAX_CHUNKS_PER_NODE 3 -#define MAXCHUNKS (MAX_CHUNKS_PER_NODE * MAX_NUMNODES) -struct node_memory_chunk_s { - unsigned long start_pfn; - unsigned long end_pfn; - u8 pxm; // proximity domain of node - u8 nid; // which cnode contains this chunk? - u8 bank; // which mem bank on this node -}; -static struct node_memory_chunk_s __initdata node_memory_chunk[MAXCHUNKS]; - -static int __initdata num_memory_chunks; /* total number of memory chunks */ -static u8 __initdata apicid_to_pxm[MAX_LOCAL_APIC]; - -int acpi_numa __initdata; - -static __init void bad_srat(void) -{ - printk(KERN_ERR "SRAT: SRAT not used.\n"); - acpi_numa = -1; - num_memory_chunks = 0; -} - -static __init inline int srat_disabled(void) -{ - return numa_off || acpi_numa < 0; -} - -/* Identify CPU proximity domains */ -void __init -acpi_numa_processor_affinity_init(struct acpi_srat_cpu_affinity *cpu_affinity) -{ - if (srat_disabled()) - return; - if (cpu_affinity->header.length != - sizeof(struct acpi_srat_cpu_affinity)) { - bad_srat(); - return; - } - - if ((cpu_affinity->flags & ACPI_SRAT_CPU_ENABLED) == 0) - return; /* empty entry */ - - /* mark this node as "seen" in node bitmap */ - BMAP_SET(pxm_bitmap, cpu_affinity->proximity_domain_lo); - - /* don't need to check apic_id here, because it is always 8 bits */ - apicid_to_pxm[cpu_affinity->apic_id] = cpu_affinity->proximity_domain_lo; - - printk(KERN_DEBUG "CPU %02x in proximity domain %02x\n", - cpu_affinity->apic_id, cpu_affinity->proximity_domain_lo); -} - -/* - * Identify memory proximity domains and hot-remove capabilities. - * Fill node memory chunk list structure. - */ -void __init -acpi_numa_memory_affinity_init(struct acpi_srat_mem_affinity *memory_affinity) -{ - unsigned long long paddr, size; - unsigned long start_pfn, end_pfn; - u8 pxm; - struct node_memory_chunk_s *p, *q, *pend; - - if (srat_disabled()) - return; - if (memory_affinity->header.length != - sizeof(struct acpi_srat_mem_affinity)) { - bad_srat(); - return; - } - - if ((memory_affinity->flags & ACPI_SRAT_MEM_ENABLED) == 0) - return; /* empty entry */ - - pxm = memory_affinity->proximity_domain & 0xff; - - /* mark this node as "seen" in node bitmap */ - BMAP_SET(pxm_bitmap, pxm); - - /* calculate info for memory chunk structure */ - paddr = memory_affinity->base_address; - size = memory_affinity->length; - - start_pfn = paddr >> PAGE_SHIFT; - end_pfn = (paddr + size) >> PAGE_SHIFT; - - - if (num_memory_chunks >= MAXCHUNKS) { - printk(KERN_WARNING "Too many mem chunks in SRAT." - " Ignoring %lld MBytes at %llx\n", - size/(1024*1024), paddr); - return; - } - - /* Insertion sort based on base address */ - pend = &node_memory_chunk[num_memory_chunks]; - for (p = &node_memory_chunk[0]; p < pend; p++) { - if (start_pfn < p->start_pfn) - break; - } - if (p < pend) { - for (q = pend; q >= p; q--) - *(q + 1) = *q; - } - p->start_pfn = start_pfn; - p->end_pfn = end_pfn; - p->pxm = pxm; - - num_memory_chunks++; - - printk(KERN_DEBUG "Memory range %08lx to %08lx" - " in proximity domain %02x %s\n", - start_pfn, end_pfn, - pxm, - ((memory_affinity->flags & ACPI_SRAT_MEM_HOT_PLUGGABLE) ? - "enabled and removable" : "enabled" ) ); -} - -/* Callback for SLIT parsing */ -void __init acpi_numa_slit_init(struct acpi_table_slit *slit) -{ -} - -void acpi_numa_arch_fixup(void) -{ -} -/* - * The SRAT table always lists ascending addresses, so can always - * assume that the first "start" address that you see is the real - * start of the node, and that the current "end" address is after - * the previous one. - */ -static __init int node_read_chunk(int nid, struct node_memory_chunk_s *memory_chunk) -{ - /* - * Only add present memory as told by the e820. - * There is no guarantee from the SRAT that the memory it - * enumerates is present at boot time because it represents - * *possible* memory hotplug areas the same as normal RAM. - */ - if (memory_chunk->start_pfn >= max_pfn) { - printk(KERN_INFO "Ignoring SRAT pfns: %08lx - %08lx\n", - memory_chunk->start_pfn, memory_chunk->end_pfn); - return -1; - } - if (memory_chunk->nid != nid) - return -1; - - if (!node_has_online_mem(nid)) - node_start_pfn[nid] = memory_chunk->start_pfn; - - if (node_start_pfn[nid] > memory_chunk->start_pfn) - node_start_pfn[nid] = memory_chunk->start_pfn; - - if (node_end_pfn[nid] < memory_chunk->end_pfn) - node_end_pfn[nid] = memory_chunk->end_pfn; - - return 0; -} - -int __init get_memcfg_from_srat(void) -{ - int i, j; - - if (srat_disabled()) - goto out_fail; - - if (acpi_numa_init() < 0) - goto out_fail; - - if (num_memory_chunks == 0) { - printk(KERN_DEBUG - "could not find any ACPI SRAT memory areas.\n"); - goto out_fail; - } - - /* Calculate total number of nodes in system from PXM bitmap and create - * a set of sequential node IDs starting at zero. (ACPI doesn't seem - * to specify the range of _PXM values.) - */ - /* - * MCD - we no longer HAVE to number nodes sequentially. PXM domain - * numbers could go as high as 256, and MAX_NUMNODES for i386 is typically - * 32, so we will continue numbering them in this manner until MAX_NUMNODES - * approaches MAX_PXM_DOMAINS for i386. - */ - nodes_clear(node_online_map); - for (i = 0; i < MAX_PXM_DOMAINS; i++) { - if (BMAP_TEST(pxm_bitmap, i)) { - int nid = acpi_map_pxm_to_node(i); - node_set_online(nid); - } - } - BUG_ON(num_online_nodes() == 0); - - /* set cnode id in memory chunk structure */ - for (i = 0; i < num_memory_chunks; i++) - node_memory_chunk[i].nid = pxm_to_node(node_memory_chunk[i].pxm); - - printk(KERN_DEBUG "pxm bitmap: "); - for (i = 0; i < sizeof(pxm_bitmap); i++) { - printk(KERN_CONT "%02x ", pxm_bitmap[i]); - } - printk(KERN_CONT "\n"); - printk(KERN_DEBUG "Number of logical nodes in system = %d\n", - num_online_nodes()); - printk(KERN_DEBUG "Number of memory chunks in system = %d\n", - num_memory_chunks); - - for (i = 0; i < MAX_LOCAL_APIC; i++) - set_apicid_to_node(i, pxm_to_node(apicid_to_pxm[i])); - - for (j = 0; j < num_memory_chunks; j++){ - struct node_memory_chunk_s * chunk = &node_memory_chunk[j]; - printk(KERN_DEBUG - "chunk %d nid %d start_pfn %08lx end_pfn %08lx\n", - j, chunk->nid, chunk->start_pfn, chunk->end_pfn); - if (node_read_chunk(chunk->nid, chunk)) - continue; - - memblock_x86_register_active_regions(chunk->nid, chunk->start_pfn, - min(chunk->end_pfn, max_pfn)); - } - /* for out of order entries in SRAT */ - sort_node_map(); - - return 1; -out_fail: - printk(KERN_DEBUG "failed to get NUMA memory information from SRAT" - " table\n"); - return 0; -} -- cgit v0.10.2 From 299a180aec6a8ee3069cf0fe90d722ac20c1f837 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Mon, 2 May 2011 14:18:53 +0200 Subject: x86-32, NUMA: Update numaq to use new NUMA init protocol Update numaq such that it calls numa_add_memblk() and sets numa_nodes_parsed instead of directly diddling with NUMA states. The original get_memcfg_numaq() is renamed to numaq_numa_init() and new get_memcfg_numaq() is created in numa_32.c. The shim numa_add_memblk() implementation handles node_start/end_pfn[] and node_set_online() for nodes with memory. The new get_memcfg_numaq() exactly the same with get_memcfg_from_srat() other than calling the numaq init function. Things get_memcfgs_numaq() do are not strictly necessary for numaq but added for consistency and to help unifying NUMA init handling. Signed-off-by: Tejun Heo Cc: Ingo Molnar Cc: Yinghai Lu Cc: David Rientjes Cc: Thomas Gleixner Cc: "H. Peter Anvin" diff --git a/arch/x86/include/asm/numaq.h b/arch/x86/include/asm/numaq.h index 37c5165..c3b3c32 100644 --- a/arch/x86/include/asm/numaq.h +++ b/arch/x86/include/asm/numaq.h @@ -29,7 +29,7 @@ #ifdef CONFIG_X86_NUMAQ extern int found_numaq; -extern int get_memcfg_numaq(void); +extern int numaq_numa_init(void); extern int pci_numaq_init(void); extern void *xquad_portio; @@ -166,11 +166,6 @@ struct sys_cfg_data { void numaq_tsc_disable(void); -#else -static inline int get_memcfg_numaq(void) -{ - return 0; -} #endif /* CONFIG_X86_NUMAQ */ #endif /* _ASM_X86_NUMAQ_H */ diff --git a/arch/x86/kernel/apic/numaq_32.c b/arch/x86/kernel/apic/numaq_32.c index 41b8b29..30f1331 100644 --- a/arch/x86/kernel/apic/numaq_32.c +++ b/arch/x86/kernel/apic/numaq_32.c @@ -48,8 +48,6 @@ #include #include -#define MB_TO_PAGES(addr) ((addr) << (20 - PAGE_SHIFT)) - int found_numaq; /* @@ -79,25 +77,20 @@ int quad_local_to_mp_bus_id[NR_CPUS/4][4]; static inline void numaq_register_node(int node, struct sys_cfg_data *scd) { struct eachquadmem *eq = scd->eq + node; + u64 start = (u64)(eq->hi_shrd_mem_start - eq->priv_mem_size) << 20; + u64 end = (u64)(eq->hi_shrd_mem_start + eq->hi_shrd_mem_size) << 20; + int ret; - node_set_online(node); - - /* Convert to pages */ - node_start_pfn[node] = - MB_TO_PAGES(eq->hi_shrd_mem_start - eq->priv_mem_size); - - node_end_pfn[node] = - MB_TO_PAGES(eq->hi_shrd_mem_start + eq->hi_shrd_mem_size); - - memblock_x86_register_active_regions(node, node_start_pfn[node], - node_end_pfn[node]); + node_set(node, numa_nodes_parsed); + ret = numa_add_memblk(node, start, end); + BUG_ON(ret < 0); } /* * Function: smp_dump_qct() * * Description: gets memory layout from the quad config table. This - * function also updates node_online_map with the nodes (quads) present. + * function also updates numa_nodes_parsed with the nodes (quads) present. */ static void __init smp_dump_qct(void) { @@ -106,7 +99,6 @@ static void __init smp_dump_qct(void) scd = (void *)__va(SYS_CFG_DATA_PRIV_ADDR); - nodes_clear(node_online_map); for_each_node(node) { if (scd->quads_present31_0 & (1 << node)) numaq_register_node(node, scd); @@ -276,14 +268,14 @@ static __init void early_check_numaq(void) } } -int __init get_memcfg_numaq(void) +int __init numaq_numa_init(void) { early_check_numaq(); if (!found_numaq) - return 0; + return -ENOENT; smp_dump_qct(); - return 1; + return 0; } #define NUMAQ_APIC_DFR_VALUE (APIC_DFR_CLUSTER) diff --git a/arch/x86/mm/numa_32.c b/arch/x86/mm/numa_32.c index 8641239..14135e5 100644 --- a/arch/x86/mm/numa_32.c +++ b/arch/x86/mm/numa_32.c @@ -332,6 +332,29 @@ static __init void init_alloc_remap(int nid) nid, node_pa, node_pa + size, remap_va, remap_va + size); } +static int get_memcfg_numaq(void) +{ +#ifdef CONFIG_X86_NUMAQ + int nid; + + if (numa_off) + return 0; + + if (numaq_numa_init() < 0) { + nodes_clear(numa_nodes_parsed); + remove_all_active_ranges(); + return 0; + } + + for_each_node_mask(nid, numa_nodes_parsed) + node_set_online(nid); + sort_node_map(); + return 1; +#else + return 0; +#endif +} + static int get_memcfg_from_srat(void) { #ifdef CONFIG_ACPI_NUMA -- cgit v0.10.2 From a4106eae650a4d5d30fcdd36d998edfa5ccb0ec4 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Mon, 2 May 2011 14:18:53 +0200 Subject: x86, NUMA: Move NUMA init logic from numa_64.c to numa.c Move the generic 64bit NUMA init machinery from numa_64.c to numa.c. * node_data[], numa_mem_info and numa_distance * numa_add_memblk[_to](), numa_remove_memblk[_from]() * numa_set_distance() and friends * numa_init() and all the numa_meminfo handling helpers called from it * dummy_numa_init() * memory_add_physaddr_to_nid() A new function x86_numa_init() is added and the content of numa_64.c::initmem_init() is moved into it. initmem_init() now simply calls x86_numa_init(). Constants and numa_off declaration are moved from numa_{32|64}.h to numa.h. This is code reorganization and doesn't involve any functional change. Signed-off-by: Tejun Heo Cc: Ingo Molnar Cc: Yinghai Lu Cc: David Rientjes Cc: Thomas Gleixner Cc: "H. Peter Anvin" diff --git a/arch/x86/include/asm/numa.h b/arch/x86/include/asm/numa.h index db449c7..7454086 100644 --- a/arch/x86/include/asm/numa.h +++ b/arch/x86/include/asm/numa.h @@ -9,6 +9,16 @@ #ifdef CONFIG_NUMA #define NR_NODE_MEMBLKS (MAX_NUMNODES*2) +#define ZONE_ALIGN (1UL << (MAX_ORDER+PAGE_SHIFT)) + +/* + * Too small node sizes may confuse the VM badly. Usually they + * result from BIOS bugs. So dont recognize nodes as standalone + * NUMA entities that have less than this amount of RAM listed: + */ +#define NODE_MIN_SIZE (4*1024*1024) + +extern int numa_off; /* * __apicid_to_node[] stores the raw mapping between physical apicid and @@ -68,4 +78,10 @@ static inline void numa_remove_cpu(int cpu) { } void debug_cpumask_set_cpu(int cpu, int node, bool enable); #endif +#ifdef CONFIG_NUMA_EMU +#define FAKE_NODE_MIN_SIZE ((u64)32 << 20) +#define FAKE_NODE_MIN_HASH_MASK (~(FAKE_NODE_MIN_SIZE - 1UL)) +void numa_emu_cmdline(char *); +#endif /* CONFIG_NUMA_EMU */ + #endif /* _ASM_X86_NUMA_H */ diff --git a/arch/x86/include/asm/numa_32.h b/arch/x86/include/asm/numa_32.h index 7e54b64..e7d6b82 100644 --- a/arch/x86/include/asm/numa_32.h +++ b/arch/x86/include/asm/numa_32.h @@ -1,8 +1,6 @@ #ifndef _ASM_X86_NUMA_32_H #define _ASM_X86_NUMA_32_H -extern int numa_off; - #ifdef CONFIG_HIGHMEM extern void set_highmem_pages_init(void); #else diff --git a/arch/x86/include/asm/numa_64.h b/arch/x86/include/asm/numa_64.h index 506dd05..0c05f7a 100644 --- a/arch/x86/include/asm/numa_64.h +++ b/arch/x86/include/asm/numa_64.h @@ -1,25 +1,6 @@ #ifndef _ASM_X86_NUMA_64_H #define _ASM_X86_NUMA_64_H -#define ZONE_ALIGN (1UL << (MAX_ORDER+PAGE_SHIFT)) - -extern int numa_off; - extern unsigned long numa_free_all_bootmem(void); -#ifdef CONFIG_NUMA -/* - * Too small node sizes may confuse the VM badly. Usually they - * result from BIOS bugs. So dont recognize nodes as standalone - * NUMA entities that have less than this amount of RAM listed: - */ -#define NODE_MIN_SIZE (4*1024*1024) - -#ifdef CONFIG_NUMA_EMU -#define FAKE_NODE_MIN_SIZE ((u64)32 << 20) -#define FAKE_NODE_MIN_HASH_MASK (~(FAKE_NODE_MIN_SIZE - 1UL)) -void numa_emu_cmdline(char *); -#endif /* CONFIG_NUMA_EMU */ -#endif - #endif /* _ASM_X86_NUMA_64_H */ diff --git a/arch/x86/mm/numa.c b/arch/x86/mm/numa.c index cce1741..ed1daba 100644 --- a/arch/x86/mm/numa.c +++ b/arch/x86/mm/numa.c @@ -1,13 +1,42 @@ /* Common code for 32 and 64-bit NUMA */ -#include -#include +#include +#include +#include +#include #include -#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include #include +#include + +#include "numa_internal.h" int __initdata numa_off; nodemask_t numa_nodes_parsed __initdata; +#ifdef CONFIG_X86_64 +struct pglist_data *node_data[MAX_NUMNODES] __read_mostly; +EXPORT_SYMBOL(node_data); + +static struct numa_meminfo numa_meminfo +#ifndef CONFIG_MEMORY_HOTPLUG +__initdata +#endif +; + +static int numa_distance_cnt; +static u8 *numa_distance; +#endif + static __init int numa_setup(char *opt) { if (!opt) @@ -105,6 +134,392 @@ void __init setup_node_to_cpumask_map(void) pr_debug("Node to cpumask map for %d nodes\n", nr_node_ids); } +#ifdef CONFIG_X86_64 +static int __init numa_add_memblk_to(int nid, u64 start, u64 end, + struct numa_meminfo *mi) +{ + /* ignore zero length blks */ + if (start == end) + return 0; + + /* whine about and ignore invalid blks */ + if (start > end || nid < 0 || nid >= MAX_NUMNODES) { + pr_warning("NUMA: Warning: invalid memblk node %d (%Lx-%Lx)\n", + nid, start, end); + return 0; + } + + if (mi->nr_blks >= NR_NODE_MEMBLKS) { + pr_err("NUMA: too many memblk ranges\n"); + return -EINVAL; + } + + mi->blk[mi->nr_blks].start = start; + mi->blk[mi->nr_blks].end = end; + mi->blk[mi->nr_blks].nid = nid; + mi->nr_blks++; + return 0; +} + +/** + * numa_remove_memblk_from - Remove one numa_memblk from a numa_meminfo + * @idx: Index of memblk to remove + * @mi: numa_meminfo to remove memblk from + * + * Remove @idx'th numa_memblk from @mi by shifting @mi->blk[] and + * decrementing @mi->nr_blks. + */ +void __init numa_remove_memblk_from(int idx, struct numa_meminfo *mi) +{ + mi->nr_blks--; + memmove(&mi->blk[idx], &mi->blk[idx + 1], + (mi->nr_blks - idx) * sizeof(mi->blk[0])); +} + +/** + * numa_add_memblk - Add one numa_memblk to numa_meminfo + * @nid: NUMA node ID of the new memblk + * @start: Start address of the new memblk + * @end: End address of the new memblk + * + * Add a new memblk to the default numa_meminfo. + * + * RETURNS: + * 0 on success, -errno on failure. + */ +int __init numa_add_memblk(int nid, u64 start, u64 end) +{ + return numa_add_memblk_to(nid, start, end, &numa_meminfo); +} + +/* Initialize bootmem allocator for a node */ +static void __init +setup_node_bootmem(int nid, unsigned long start, unsigned long end) +{ + const u64 nd_low = (u64)MAX_DMA_PFN << PAGE_SHIFT; + const u64 nd_high = (u64)max_pfn_mapped << PAGE_SHIFT; + const size_t nd_size = roundup(sizeof(pg_data_t), PAGE_SIZE); + unsigned long nd_pa; + int tnid; + + /* + * Don't confuse VM with a node that doesn't have the + * minimum amount of memory: + */ + if (end && (end - start) < NODE_MIN_SIZE) + return; + + start = roundup(start, ZONE_ALIGN); + + printk(KERN_INFO "Initmem setup node %d %016lx-%016lx\n", + nid, start, end); + + /* + * Try to allocate node data on local node and then fall back to + * all nodes. Never allocate in DMA zone. + */ + nd_pa = memblock_x86_find_in_range_node(nid, nd_low, nd_high, + nd_size, SMP_CACHE_BYTES); + if (nd_pa == MEMBLOCK_ERROR) + nd_pa = memblock_find_in_range(nd_low, nd_high, + nd_size, SMP_CACHE_BYTES); + if (nd_pa == MEMBLOCK_ERROR) { + pr_err("Cannot find %lu bytes in node %d\n", nd_size, nid); + return; + } + memblock_x86_reserve_range(nd_pa, nd_pa + nd_size, "NODE_DATA"); + + /* report and initialize */ + printk(KERN_INFO " NODE_DATA [%016lx - %016lx]\n", + nd_pa, nd_pa + nd_size - 1); + tnid = early_pfn_to_nid(nd_pa >> PAGE_SHIFT); + if (tnid != nid) + printk(KERN_INFO " NODE_DATA(%d) on node %d\n", nid, tnid); + + node_data[nid] = __va(nd_pa); + memset(NODE_DATA(nid), 0, sizeof(pg_data_t)); + NODE_DATA(nid)->node_id = nid; + NODE_DATA(nid)->node_start_pfn = start >> PAGE_SHIFT; + NODE_DATA(nid)->node_spanned_pages = (end - start) >> PAGE_SHIFT; + + node_set_online(nid); +} + +/** + * numa_cleanup_meminfo - Cleanup a numa_meminfo + * @mi: numa_meminfo to clean up + * + * Sanitize @mi by merging and removing unncessary memblks. Also check for + * conflicts and clear unused memblks. + * + * RETURNS: + * 0 on success, -errno on failure. + */ +int __init numa_cleanup_meminfo(struct numa_meminfo *mi) +{ + const u64 low = 0; + const u64 high = (u64)max_pfn << PAGE_SHIFT; + int i, j, k; + + for (i = 0; i < mi->nr_blks; i++) { + struct numa_memblk *bi = &mi->blk[i]; + + /* make sure all blocks are inside the limits */ + bi->start = max(bi->start, low); + bi->end = min(bi->end, high); + + /* and there's no empty block */ + if (bi->start >= bi->end) { + numa_remove_memblk_from(i--, mi); + continue; + } + + for (j = i + 1; j < mi->nr_blks; j++) { + struct numa_memblk *bj = &mi->blk[j]; + unsigned long start, end; + + /* + * See whether there are overlapping blocks. Whine + * about but allow overlaps of the same nid. They + * will be merged below. + */ + if (bi->end > bj->start && bi->start < bj->end) { + if (bi->nid != bj->nid) { + pr_err("NUMA: node %d (%Lx-%Lx) overlaps with node %d (%Lx-%Lx)\n", + bi->nid, bi->start, bi->end, + bj->nid, bj->start, bj->end); + return -EINVAL; + } + pr_warning("NUMA: Warning: node %d (%Lx-%Lx) overlaps with itself (%Lx-%Lx)\n", + bi->nid, bi->start, bi->end, + bj->start, bj->end); + } + + /* + * Join together blocks on the same node, holes + * between which don't overlap with memory on other + * nodes. + */ + if (bi->nid != bj->nid) + continue; + start = max(min(bi->start, bj->start), low); + end = min(max(bi->end, bj->end), high); + for (k = 0; k < mi->nr_blks; k++) { + struct numa_memblk *bk = &mi->blk[k]; + + if (bi->nid == bk->nid) + continue; + if (start < bk->end && end > bk->start) + break; + } + if (k < mi->nr_blks) + continue; + printk(KERN_INFO "NUMA: Node %d [%Lx,%Lx) + [%Lx,%Lx) -> [%lx,%lx)\n", + bi->nid, bi->start, bi->end, bj->start, bj->end, + start, end); + bi->start = start; + bi->end = end; + numa_remove_memblk_from(j--, mi); + } + } + + for (i = mi->nr_blks; i < ARRAY_SIZE(mi->blk); i++) { + mi->blk[i].start = mi->blk[i].end = 0; + mi->blk[i].nid = NUMA_NO_NODE; + } + + return 0; +} + +/* + * Set nodes, which have memory in @mi, in *@nodemask. + */ +static void __init numa_nodemask_from_meminfo(nodemask_t *nodemask, + const struct numa_meminfo *mi) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(mi->blk); i++) + if (mi->blk[i].start != mi->blk[i].end && + mi->blk[i].nid != NUMA_NO_NODE) + node_set(mi->blk[i].nid, *nodemask); +} + +/** + * numa_reset_distance - Reset NUMA distance table + * + * The current table is freed. The next numa_set_distance() call will + * create a new one. + */ +void __init numa_reset_distance(void) +{ + size_t size = numa_distance_cnt * numa_distance_cnt * sizeof(numa_distance[0]); + + /* numa_distance could be 1LU marking allocation failure, test cnt */ + if (numa_distance_cnt) + memblock_x86_free_range(__pa(numa_distance), + __pa(numa_distance) + size); + numa_distance_cnt = 0; + numa_distance = NULL; /* enable table creation */ +} + +static int __init numa_alloc_distance(void) +{ + nodemask_t nodes_parsed; + size_t size; + int i, j, cnt = 0; + u64 phys; + + /* size the new table and allocate it */ + nodes_parsed = numa_nodes_parsed; + numa_nodemask_from_meminfo(&nodes_parsed, &numa_meminfo); + + for_each_node_mask(i, nodes_parsed) + cnt = i; + cnt++; + size = cnt * cnt * sizeof(numa_distance[0]); + + phys = memblock_find_in_range(0, (u64)max_pfn_mapped << PAGE_SHIFT, + size, PAGE_SIZE); + if (phys == MEMBLOCK_ERROR) { + pr_warning("NUMA: Warning: can't allocate distance table!\n"); + /* don't retry until explicitly reset */ + numa_distance = (void *)1LU; + return -ENOMEM; + } + memblock_x86_reserve_range(phys, phys + size, "NUMA DIST"); + + numa_distance = __va(phys); + numa_distance_cnt = cnt; + + /* fill with the default distances */ + for (i = 0; i < cnt; i++) + for (j = 0; j < cnt; j++) + numa_distance[i * cnt + j] = i == j ? + LOCAL_DISTANCE : REMOTE_DISTANCE; + printk(KERN_DEBUG "NUMA: Initialized distance table, cnt=%d\n", cnt); + + return 0; +} + +/** + * numa_set_distance - Set NUMA distance from one NUMA to another + * @from: the 'from' node to set distance + * @to: the 'to' node to set distance + * @distance: NUMA distance + * + * Set the distance from node @from to @to to @distance. If distance table + * doesn't exist, one which is large enough to accommodate all the currently + * known nodes will be created. + * + * If such table cannot be allocated, a warning is printed and further + * calls are ignored until the distance table is reset with + * numa_reset_distance(). + * + * If @from or @to is higher than the highest known node at the time of + * table creation or @distance doesn't make sense, the call is ignored. + * This is to allow simplification of specific NUMA config implementations. + */ +void __init numa_set_distance(int from, int to, int distance) +{ + if (!numa_distance && numa_alloc_distance() < 0) + return; + + if (from >= numa_distance_cnt || to >= numa_distance_cnt) { + printk_once(KERN_DEBUG "NUMA: Debug: distance out of bound, from=%d to=%d distance=%d\n", + from, to, distance); + return; + } + + if ((u8)distance != distance || + (from == to && distance != LOCAL_DISTANCE)) { + pr_warn_once("NUMA: Warning: invalid distance parameter, from=%d to=%d distance=%d\n", + from, to, distance); + return; + } + + numa_distance[from * numa_distance_cnt + to] = distance; +} + +int __node_distance(int from, int to) +{ + if (from >= numa_distance_cnt || to >= numa_distance_cnt) + return from == to ? LOCAL_DISTANCE : REMOTE_DISTANCE; + return numa_distance[from * numa_distance_cnt + to]; +} +EXPORT_SYMBOL(__node_distance); + +/* + * Sanity check to catch more bad NUMA configurations (they are amazingly + * common). Make sure the nodes cover all memory. + */ +static bool __init numa_meminfo_cover_memory(const struct numa_meminfo *mi) +{ + unsigned long numaram, e820ram; + int i; + + numaram = 0; + for (i = 0; i < mi->nr_blks; i++) { + unsigned long s = mi->blk[i].start >> PAGE_SHIFT; + unsigned long e = mi->blk[i].end >> PAGE_SHIFT; + numaram += e - s; + numaram -= __absent_pages_in_range(mi->blk[i].nid, s, e); + if ((long)numaram < 0) + numaram = 0; + } + + e820ram = max_pfn - (memblock_x86_hole_size(0, + max_pfn << PAGE_SHIFT) >> PAGE_SHIFT); + /* We seem to lose 3 pages somewhere. Allow 1M of slack. */ + if ((long)(e820ram - numaram) >= (1 << (20 - PAGE_SHIFT))) { + printk(KERN_ERR "NUMA: nodes only cover %luMB of your %luMB e820 RAM. Not used.\n", + (numaram << PAGE_SHIFT) >> 20, + (e820ram << PAGE_SHIFT) >> 20); + return false; + } + return true; +} + +static int __init numa_register_memblks(struct numa_meminfo *mi) +{ + int i, nid; + + /* Account for nodes with cpus and no memory */ + node_possible_map = numa_nodes_parsed; + numa_nodemask_from_meminfo(&node_possible_map, mi); + if (WARN_ON(nodes_empty(node_possible_map))) + return -EINVAL; + + for (i = 0; i < mi->nr_blks; i++) + memblock_x86_register_active_regions(mi->blk[i].nid, + mi->blk[i].start >> PAGE_SHIFT, + mi->blk[i].end >> PAGE_SHIFT); + + /* for out of order entries */ + sort_node_map(); + if (!numa_meminfo_cover_memory(mi)) + return -EINVAL; + + /* Finally register nodes. */ + for_each_node_mask(nid, node_possible_map) { + u64 start = (u64)max_pfn << PAGE_SHIFT; + u64 end = 0; + + for (i = 0; i < mi->nr_blks; i++) { + if (nid != mi->blk[i].nid) + continue; + start = min(mi->blk[i].start, start); + end = max(mi->blk[i].end, end); + } + + if (start < end) + setup_node_bootmem(nid, start, end); + } + + return 0; +} +#endif + /* * There are unfortunately some poorly designed mainboards around that * only connect memory to a single CPU. This breaks the 1:1 cpu->node @@ -127,6 +542,93 @@ void __init numa_init_array(void) } } +#ifdef CONFIG_X86_64 +static int __init numa_init(int (*init_func)(void)) +{ + int i; + int ret; + + for (i = 0; i < MAX_LOCAL_APIC; i++) + set_apicid_to_node(i, NUMA_NO_NODE); + + nodes_clear(numa_nodes_parsed); + nodes_clear(node_possible_map); + nodes_clear(node_online_map); + memset(&numa_meminfo, 0, sizeof(numa_meminfo)); + remove_all_active_ranges(); + numa_reset_distance(); + + ret = init_func(); + if (ret < 0) + return ret; + ret = numa_cleanup_meminfo(&numa_meminfo); + if (ret < 0) + return ret; + + numa_emulation(&numa_meminfo, numa_distance_cnt); + + ret = numa_register_memblks(&numa_meminfo); + if (ret < 0) + return ret; + + for (i = 0; i < nr_cpu_ids; i++) { + int nid = early_cpu_to_node(i); + + if (nid == NUMA_NO_NODE) + continue; + if (!node_online(nid)) + numa_clear_node(i); + } + numa_init_array(); + return 0; +} + +/** + * dummy_numa_init - Fallback dummy NUMA init + * + * Used if there's no underlying NUMA architecture, NUMA initialization + * fails, or NUMA is disabled on the command line. + * + * Must online at least one node and add memory blocks that cover all + * allowed memory. This function must not fail. + */ +static int __init dummy_numa_init(void) +{ + printk(KERN_INFO "%s\n", + numa_off ? "NUMA turned off" : "No NUMA configuration found"); + printk(KERN_INFO "Faking a node at %016lx-%016lx\n", + 0LU, max_pfn << PAGE_SHIFT); + + node_set(0, numa_nodes_parsed); + numa_add_memblk(0, 0, (u64)max_pfn << PAGE_SHIFT); + + return 0; +} + +/** + * x86_numa_init - Initialize NUMA + * + * Try each configured NUMA initialization method until one succeeds. The + * last fallback is dummy single node config encomapssing whole memory and + * never fails. + */ +void __init x86_numa_init(void) +{ + if (!numa_off) { +#ifdef CONFIG_ACPI_NUMA + if (!numa_init(x86_acpi_numa_init)) + return; +#endif +#ifdef CONFIG_AMD_NUMA + if (!numa_init(amd_numa_init)) + return; +#endif + } + + numa_init(dummy_numa_init); +} +#endif + static __init int find_near_online_node(int node) { int n, val; @@ -292,3 +794,18 @@ const struct cpumask *cpumask_of_node(int node) EXPORT_SYMBOL(cpumask_of_node); #endif /* !CONFIG_DEBUG_PER_CPU_MAPS */ + +#if defined(CONFIG_X86_64) && defined(CONFIG_MEMORY_HOTPLUG) +int memory_add_physaddr_to_nid(u64 start) +{ + struct numa_meminfo *mi = &numa_meminfo; + int nid = mi->blk[0].nid; + int i; + + for (i = 0; i < mi->nr_blks; i++) + if (mi->blk[i].start <= start && mi->blk[i].end > start) + nid = mi->blk[i].nid; + return nid; +} +EXPORT_SYMBOL_GPL(memory_add_physaddr_to_nid); +#endif diff --git a/arch/x86/mm/numa_64.c b/arch/x86/mm/numa_64.c index 70bd822..dd27f40 100644 --- a/arch/x86/mm/numa_64.c +++ b/arch/x86/mm/numa_64.c @@ -2,499 +2,13 @@ * Generic VM initialization for x86-64 NUMA setups. * Copyright 2002,2003 Andi Kleen, SuSE Labs. */ -#include -#include -#include -#include #include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include #include "numa_internal.h" -struct pglist_data *node_data[MAX_NUMNODES] __read_mostly; -EXPORT_SYMBOL(node_data); - -static struct numa_meminfo numa_meminfo -#ifndef CONFIG_MEMORY_HOTPLUG -__initdata -#endif -; - -static int numa_distance_cnt; -static u8 *numa_distance; - -static int __init numa_add_memblk_to(int nid, u64 start, u64 end, - struct numa_meminfo *mi) -{ - /* ignore zero length blks */ - if (start == end) - return 0; - - /* whine about and ignore invalid blks */ - if (start > end || nid < 0 || nid >= MAX_NUMNODES) { - pr_warning("NUMA: Warning: invalid memblk node %d (%Lx-%Lx)\n", - nid, start, end); - return 0; - } - - if (mi->nr_blks >= NR_NODE_MEMBLKS) { - pr_err("NUMA: too many memblk ranges\n"); - return -EINVAL; - } - - mi->blk[mi->nr_blks].start = start; - mi->blk[mi->nr_blks].end = end; - mi->blk[mi->nr_blks].nid = nid; - mi->nr_blks++; - return 0; -} - -/** - * numa_remove_memblk_from - Remove one numa_memblk from a numa_meminfo - * @idx: Index of memblk to remove - * @mi: numa_meminfo to remove memblk from - * - * Remove @idx'th numa_memblk from @mi by shifting @mi->blk[] and - * decrementing @mi->nr_blks. - */ -void __init numa_remove_memblk_from(int idx, struct numa_meminfo *mi) -{ - mi->nr_blks--; - memmove(&mi->blk[idx], &mi->blk[idx + 1], - (mi->nr_blks - idx) * sizeof(mi->blk[0])); -} - -/** - * numa_add_memblk - Add one numa_memblk to numa_meminfo - * @nid: NUMA node ID of the new memblk - * @start: Start address of the new memblk - * @end: End address of the new memblk - * - * Add a new memblk to the default numa_meminfo. - * - * RETURNS: - * 0 on success, -errno on failure. - */ -int __init numa_add_memblk(int nid, u64 start, u64 end) -{ - return numa_add_memblk_to(nid, start, end, &numa_meminfo); -} - -/* Initialize bootmem allocator for a node */ -static void __init -setup_node_bootmem(int nid, unsigned long start, unsigned long end) -{ - const u64 nd_low = (u64)MAX_DMA_PFN << PAGE_SHIFT; - const u64 nd_high = (u64)max_pfn_mapped << PAGE_SHIFT; - const size_t nd_size = roundup(sizeof(pg_data_t), PAGE_SIZE); - unsigned long nd_pa; - int tnid; - - /* - * Don't confuse VM with a node that doesn't have the - * minimum amount of memory: - */ - if (end && (end - start) < NODE_MIN_SIZE) - return; - - start = roundup(start, ZONE_ALIGN); - - printk(KERN_INFO "Initmem setup node %d %016lx-%016lx\n", - nid, start, end); - - /* - * Try to allocate node data on local node and then fall back to - * all nodes. Never allocate in DMA zone. - */ - nd_pa = memblock_x86_find_in_range_node(nid, nd_low, nd_high, - nd_size, SMP_CACHE_BYTES); - if (nd_pa == MEMBLOCK_ERROR) - nd_pa = memblock_find_in_range(nd_low, nd_high, - nd_size, SMP_CACHE_BYTES); - if (nd_pa == MEMBLOCK_ERROR) { - pr_err("Cannot find %lu bytes in node %d\n", nd_size, nid); - return; - } - memblock_x86_reserve_range(nd_pa, nd_pa + nd_size, "NODE_DATA"); - - /* report and initialize */ - printk(KERN_INFO " NODE_DATA [%016lx - %016lx]\n", - nd_pa, nd_pa + nd_size - 1); - tnid = early_pfn_to_nid(nd_pa >> PAGE_SHIFT); - if (tnid != nid) - printk(KERN_INFO " NODE_DATA(%d) on node %d\n", nid, tnid); - - node_data[nid] = __va(nd_pa); - memset(NODE_DATA(nid), 0, sizeof(pg_data_t)); - NODE_DATA(nid)->node_id = nid; - NODE_DATA(nid)->node_start_pfn = start >> PAGE_SHIFT; - NODE_DATA(nid)->node_spanned_pages = (end - start) >> PAGE_SHIFT; - - node_set_online(nid); -} - -/** - * numa_cleanup_meminfo - Cleanup a numa_meminfo - * @mi: numa_meminfo to clean up - * - * Sanitize @mi by merging and removing unncessary memblks. Also check for - * conflicts and clear unused memblks. - * - * RETURNS: - * 0 on success, -errno on failure. - */ -int __init numa_cleanup_meminfo(struct numa_meminfo *mi) -{ - const u64 low = 0; - const u64 high = (u64)max_pfn << PAGE_SHIFT; - int i, j, k; - - for (i = 0; i < mi->nr_blks; i++) { - struct numa_memblk *bi = &mi->blk[i]; - - /* make sure all blocks are inside the limits */ - bi->start = max(bi->start, low); - bi->end = min(bi->end, high); - - /* and there's no empty block */ - if (bi->start >= bi->end) { - numa_remove_memblk_from(i--, mi); - continue; - } - - for (j = i + 1; j < mi->nr_blks; j++) { - struct numa_memblk *bj = &mi->blk[j]; - unsigned long start, end; - - /* - * See whether there are overlapping blocks. Whine - * about but allow overlaps of the same nid. They - * will be merged below. - */ - if (bi->end > bj->start && bi->start < bj->end) { - if (bi->nid != bj->nid) { - pr_err("NUMA: node %d (%Lx-%Lx) overlaps with node %d (%Lx-%Lx)\n", - bi->nid, bi->start, bi->end, - bj->nid, bj->start, bj->end); - return -EINVAL; - } - pr_warning("NUMA: Warning: node %d (%Lx-%Lx) overlaps with itself (%Lx-%Lx)\n", - bi->nid, bi->start, bi->end, - bj->start, bj->end); - } - - /* - * Join together blocks on the same node, holes - * between which don't overlap with memory on other - * nodes. - */ - if (bi->nid != bj->nid) - continue; - start = max(min(bi->start, bj->start), low); - end = min(max(bi->end, bj->end), high); - for (k = 0; k < mi->nr_blks; k++) { - struct numa_memblk *bk = &mi->blk[k]; - - if (bi->nid == bk->nid) - continue; - if (start < bk->end && end > bk->start) - break; - } - if (k < mi->nr_blks) - continue; - printk(KERN_INFO "NUMA: Node %d [%Lx,%Lx) + [%Lx,%Lx) -> [%lx,%lx)\n", - bi->nid, bi->start, bi->end, bj->start, bj->end, - start, end); - bi->start = start; - bi->end = end; - numa_remove_memblk_from(j--, mi); - } - } - - for (i = mi->nr_blks; i < ARRAY_SIZE(mi->blk); i++) { - mi->blk[i].start = mi->blk[i].end = 0; - mi->blk[i].nid = NUMA_NO_NODE; - } - - return 0; -} - -/* - * Set nodes, which have memory in @mi, in *@nodemask. - */ -static void __init numa_nodemask_from_meminfo(nodemask_t *nodemask, - const struct numa_meminfo *mi) -{ - int i; - - for (i = 0; i < ARRAY_SIZE(mi->blk); i++) - if (mi->blk[i].start != mi->blk[i].end && - mi->blk[i].nid != NUMA_NO_NODE) - node_set(mi->blk[i].nid, *nodemask); -} - -/** - * numa_reset_distance - Reset NUMA distance table - * - * The current table is freed. The next numa_set_distance() call will - * create a new one. - */ -void __init numa_reset_distance(void) -{ - size_t size = numa_distance_cnt * numa_distance_cnt * sizeof(numa_distance[0]); - - /* numa_distance could be 1LU marking allocation failure, test cnt */ - if (numa_distance_cnt) - memblock_x86_free_range(__pa(numa_distance), - __pa(numa_distance) + size); - numa_distance_cnt = 0; - numa_distance = NULL; /* enable table creation */ -} - -static int __init numa_alloc_distance(void) -{ - nodemask_t nodes_parsed; - size_t size; - int i, j, cnt = 0; - u64 phys; - - /* size the new table and allocate it */ - nodes_parsed = numa_nodes_parsed; - numa_nodemask_from_meminfo(&nodes_parsed, &numa_meminfo); - - for_each_node_mask(i, nodes_parsed) - cnt = i; - cnt++; - size = cnt * cnt * sizeof(numa_distance[0]); - - phys = memblock_find_in_range(0, (u64)max_pfn_mapped << PAGE_SHIFT, - size, PAGE_SIZE); - if (phys == MEMBLOCK_ERROR) { - pr_warning("NUMA: Warning: can't allocate distance table!\n"); - /* don't retry until explicitly reset */ - numa_distance = (void *)1LU; - return -ENOMEM; - } - memblock_x86_reserve_range(phys, phys + size, "NUMA DIST"); - - numa_distance = __va(phys); - numa_distance_cnt = cnt; - - /* fill with the default distances */ - for (i = 0; i < cnt; i++) - for (j = 0; j < cnt; j++) - numa_distance[i * cnt + j] = i == j ? - LOCAL_DISTANCE : REMOTE_DISTANCE; - printk(KERN_DEBUG "NUMA: Initialized distance table, cnt=%d\n", cnt); - - return 0; -} - -/** - * numa_set_distance - Set NUMA distance from one NUMA to another - * @from: the 'from' node to set distance - * @to: the 'to' node to set distance - * @distance: NUMA distance - * - * Set the distance from node @from to @to to @distance. If distance table - * doesn't exist, one which is large enough to accommodate all the currently - * known nodes will be created. - * - * If such table cannot be allocated, a warning is printed and further - * calls are ignored until the distance table is reset with - * numa_reset_distance(). - * - * If @from or @to is higher than the highest known node at the time of - * table creation or @distance doesn't make sense, the call is ignored. - * This is to allow simplification of specific NUMA config implementations. - */ -void __init numa_set_distance(int from, int to, int distance) -{ - if (!numa_distance && numa_alloc_distance() < 0) - return; - - if (from >= numa_distance_cnt || to >= numa_distance_cnt) { - printk_once(KERN_DEBUG "NUMA: Debug: distance out of bound, from=%d to=%d distance=%d\n", - from, to, distance); - return; - } - - if ((u8)distance != distance || - (from == to && distance != LOCAL_DISTANCE)) { - pr_warn_once("NUMA: Warning: invalid distance parameter, from=%d to=%d distance=%d\n", - from, to, distance); - return; - } - - numa_distance[from * numa_distance_cnt + to] = distance; -} - -int __node_distance(int from, int to) -{ - if (from >= numa_distance_cnt || to >= numa_distance_cnt) - return from == to ? LOCAL_DISTANCE : REMOTE_DISTANCE; - return numa_distance[from * numa_distance_cnt + to]; -} -EXPORT_SYMBOL(__node_distance); - -/* - * Sanity check to catch more bad NUMA configurations (they are amazingly - * common). Make sure the nodes cover all memory. - */ -static bool __init numa_meminfo_cover_memory(const struct numa_meminfo *mi) -{ - unsigned long numaram, e820ram; - int i; - - numaram = 0; - for (i = 0; i < mi->nr_blks; i++) { - unsigned long s = mi->blk[i].start >> PAGE_SHIFT; - unsigned long e = mi->blk[i].end >> PAGE_SHIFT; - numaram += e - s; - numaram -= __absent_pages_in_range(mi->blk[i].nid, s, e); - if ((long)numaram < 0) - numaram = 0; - } - - e820ram = max_pfn - (memblock_x86_hole_size(0, - max_pfn << PAGE_SHIFT) >> PAGE_SHIFT); - /* We seem to lose 3 pages somewhere. Allow 1M of slack. */ - if ((long)(e820ram - numaram) >= (1 << (20 - PAGE_SHIFT))) { - printk(KERN_ERR "NUMA: nodes only cover %luMB of your %luMB e820 RAM. Not used.\n", - (numaram << PAGE_SHIFT) >> 20, - (e820ram << PAGE_SHIFT) >> 20); - return false; - } - return true; -} - -static int __init numa_register_memblks(struct numa_meminfo *mi) -{ - int i, nid; - - /* Account for nodes with cpus and no memory */ - node_possible_map = numa_nodes_parsed; - numa_nodemask_from_meminfo(&node_possible_map, mi); - if (WARN_ON(nodes_empty(node_possible_map))) - return -EINVAL; - - for (i = 0; i < mi->nr_blks; i++) - memblock_x86_register_active_regions(mi->blk[i].nid, - mi->blk[i].start >> PAGE_SHIFT, - mi->blk[i].end >> PAGE_SHIFT); - - /* for out of order entries */ - sort_node_map(); - if (!numa_meminfo_cover_memory(mi)) - return -EINVAL; - - /* Finally register nodes. */ - for_each_node_mask(nid, node_possible_map) { - u64 start = (u64)max_pfn << PAGE_SHIFT; - u64 end = 0; - - for (i = 0; i < mi->nr_blks; i++) { - if (nid != mi->blk[i].nid) - continue; - start = min(mi->blk[i].start, start); - end = max(mi->blk[i].end, end); - } - - if (start < end) - setup_node_bootmem(nid, start, end); - } - - return 0; -} - -/** - * dummy_numma_init - Fallback dummy NUMA init - * - * Used if there's no underlying NUMA architecture, NUMA initialization - * fails, or NUMA is disabled on the command line. - * - * Must online at least one node and add memory blocks that cover all - * allowed memory. This function must not fail. - */ -static int __init dummy_numa_init(void) -{ - printk(KERN_INFO "%s\n", - numa_off ? "NUMA turned off" : "No NUMA configuration found"); - printk(KERN_INFO "Faking a node at %016lx-%016lx\n", - 0LU, max_pfn << PAGE_SHIFT); - - node_set(0, numa_nodes_parsed); - numa_add_memblk(0, 0, (u64)max_pfn << PAGE_SHIFT); - - return 0; -} - -static int __init numa_init(int (*init_func)(void)) -{ - int i; - int ret; - - for (i = 0; i < MAX_LOCAL_APIC; i++) - set_apicid_to_node(i, NUMA_NO_NODE); - - nodes_clear(numa_nodes_parsed); - nodes_clear(node_possible_map); - nodes_clear(node_online_map); - memset(&numa_meminfo, 0, sizeof(numa_meminfo)); - remove_all_active_ranges(); - numa_reset_distance(); - - ret = init_func(); - if (ret < 0) - return ret; - ret = numa_cleanup_meminfo(&numa_meminfo); - if (ret < 0) - return ret; - - numa_emulation(&numa_meminfo, numa_distance_cnt); - - ret = numa_register_memblks(&numa_meminfo); - if (ret < 0) - return ret; - - for (i = 0; i < nr_cpu_ids; i++) { - int nid = early_cpu_to_node(i); - - if (nid == NUMA_NO_NODE) - continue; - if (!node_online(nid)) - numa_clear_node(i); - } - numa_init_array(); - return 0; -} - void __init initmem_init(void) { - if (!numa_off) { -#ifdef CONFIG_ACPI_NUMA - if (!numa_init(x86_acpi_numa_init)) - return; -#endif -#ifdef CONFIG_AMD_NUMA - if (!numa_init(amd_numa_init)) - return; -#endif - } - - numa_init(dummy_numa_init); + x86_numa_init(); } unsigned long __init numa_free_all_bootmem(void) @@ -509,18 +23,3 @@ unsigned long __init numa_free_all_bootmem(void) return pages; } - -#ifdef CONFIG_MEMORY_HOTPLUG -int memory_add_physaddr_to_nid(u64 start) -{ - struct numa_meminfo *mi = &numa_meminfo; - int nid = mi->blk[0].nid; - int i; - - for (i = 0; i < mi->nr_blks; i++) - if (mi->blk[i].start <= start && mi->blk[i].end > start) - nid = mi->blk[i].nid; - return nid; -} -EXPORT_SYMBOL_GPL(memory_add_physaddr_to_nid); -#endif diff --git a/arch/x86/mm/numa_internal.h b/arch/x86/mm/numa_internal.h index ef2d973..ad86ec9 100644 --- a/arch/x86/mm/numa_internal.h +++ b/arch/x86/mm/numa_internal.h @@ -19,6 +19,8 @@ void __init numa_remove_memblk_from(int idx, struct numa_meminfo *mi); int __init numa_cleanup_meminfo(struct numa_meminfo *mi); void __init numa_reset_distance(void); +void __init x86_numa_init(void); + #ifdef CONFIG_NUMA_EMU void __init numa_emulation(struct numa_meminfo *numa_meminfo, int numa_dist_cnt); -- cgit v0.10.2 From 744baba0c4072b04664952a89292e4708eaf949a Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Mon, 2 May 2011 14:18:53 +0200 Subject: x86, NUMA: Enable build of generic NUMA init code on 32bit Generic NUMA init code was moved to numa.c from numa_64.c but is still guaraded by CONFIG_X86_64. This patch removes the compile guard and enables compiling on 32bit. * numa_add_memblk() and numa_set_distance() clash with the shim implementation in numa_32.c and are left out. * memory_add_physaddr_to_nid() clashes with 32bit implementation and is left out. * MAX_DMA_PFN definition in dma.h moved out of !CONFIG_X86_32. * node_data definition in numa_32.c removed in favor of the one in numa.c. There are places where ulong is assumed to be 64bit. The next patch will fix them up. Note that although the code is compiled it isn't used yet and this patch doesn't cause any functional change. Signed-off-by: Tejun Heo Cc: Ingo Molnar Cc: Yinghai Lu Cc: David Rientjes Cc: Thomas Gleixner Cc: "H. Peter Anvin" diff --git a/arch/x86/include/asm/dma.h b/arch/x86/include/asm/dma.h index 057099e..d1a314b 100644 --- a/arch/x86/include/asm/dma.h +++ b/arch/x86/include/asm/dma.h @@ -69,6 +69,9 @@ #define MAX_DMA_CHANNELS 8 +/* 16MB ISA DMA zone */ +#define MAX_DMA_PFN ((16 * 1024 * 1024) >> PAGE_SHIFT) + #ifdef CONFIG_X86_32 /* The maximum address that we can perform a DMA transfer to on this platform */ @@ -76,9 +79,6 @@ #else -/* 16MB ISA DMA zone */ -#define MAX_DMA_PFN ((16 * 1024 * 1024) >> PAGE_SHIFT) - /* 4GB broken PCI/AGP hardware bus master zone */ #define MAX_DMA32_PFN ((4UL * 1024 * 1024 * 1024) >> PAGE_SHIFT) diff --git a/arch/x86/mm/numa.c b/arch/x86/mm/numa.c index ed1daba..c400f3b 100644 --- a/arch/x86/mm/numa.c +++ b/arch/x86/mm/numa.c @@ -23,7 +23,6 @@ int __initdata numa_off; nodemask_t numa_nodes_parsed __initdata; -#ifdef CONFIG_X86_64 struct pglist_data *node_data[MAX_NUMNODES] __read_mostly; EXPORT_SYMBOL(node_data); @@ -35,7 +34,6 @@ __initdata static int numa_distance_cnt; static u8 *numa_distance; -#endif static __init int numa_setup(char *opt) { @@ -134,7 +132,6 @@ void __init setup_node_to_cpumask_map(void) pr_debug("Node to cpumask map for %d nodes\n", nr_node_ids); } -#ifdef CONFIG_X86_64 static int __init numa_add_memblk_to(int nid, u64 start, u64 end, struct numa_meminfo *mi) { @@ -176,6 +173,7 @@ void __init numa_remove_memblk_from(int idx, struct numa_meminfo *mi) (mi->nr_blks - idx) * sizeof(mi->blk[0])); } +#ifdef CONFIG_X86_64 /** * numa_add_memblk - Add one numa_memblk to numa_meminfo * @nid: NUMA node ID of the new memblk @@ -191,6 +189,7 @@ int __init numa_add_memblk(int nid, u64 start, u64 end) { return numa_add_memblk_to(nid, start, end, &numa_meminfo); } +#endif /* Initialize bootmem allocator for a node */ static void __init @@ -402,6 +401,7 @@ static int __init numa_alloc_distance(void) return 0; } +#ifdef CONFIG_X86_64 /** * numa_set_distance - Set NUMA distance from one NUMA to another * @from: the 'from' node to set distance @@ -440,6 +440,7 @@ void __init numa_set_distance(int from, int to, int distance) numa_distance[from * numa_distance_cnt + to] = distance; } +#endif int __node_distance(int from, int to) { @@ -518,7 +519,6 @@ static int __init numa_register_memblks(struct numa_meminfo *mi) return 0; } -#endif /* * There are unfortunately some poorly designed mainboards around that @@ -542,7 +542,6 @@ void __init numa_init_array(void) } } -#ifdef CONFIG_X86_64 static int __init numa_init(int (*init_func)(void)) { int i; @@ -627,7 +626,6 @@ void __init x86_numa_init(void) numa_init(dummy_numa_init); } -#endif static __init int find_near_online_node(int node) { diff --git a/arch/x86/mm/numa_32.c b/arch/x86/mm/numa_32.c index 14135e5..975a76f 100644 --- a/arch/x86/mm/numa_32.c +++ b/arch/x86/mm/numa_32.c @@ -41,9 +41,6 @@ #include #include -struct pglist_data *node_data[MAX_NUMNODES] __read_mostly; -EXPORT_SYMBOL(node_data); - /* * numa interface - we expect the numa architecture specific code to have * populated the following initialisation. -- cgit v0.10.2 From 38f3e1ca24cc3ec416855e02676f91c898a8a262 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Mon, 2 May 2011 14:18:53 +0200 Subject: x86, NUMA: Remove long 64bit assumption from numa.c Code moved from numa_64.c has assumption that long is 64bit in several places. This patch removes the assumption by using {s|u}64_t explicity, using PFN_PHYS() for page number -> addr conversions and adjusting printf formats. Signed-off-by: Tejun Heo Cc: Ingo Molnar Cc: Yinghai Lu Cc: David Rientjes Cc: Thomas Gleixner Cc: "H. Peter Anvin" diff --git a/arch/x86/mm/numa.c b/arch/x86/mm/numa.c index c400f3b..b45caa3 100644 --- a/arch/x86/mm/numa.c +++ b/arch/x86/mm/numa.c @@ -192,13 +192,12 @@ int __init numa_add_memblk(int nid, u64 start, u64 end) #endif /* Initialize bootmem allocator for a node */ -static void __init -setup_node_bootmem(int nid, unsigned long start, unsigned long end) +static void __init setup_node_bootmem(int nid, u64 start, u64 end) { - const u64 nd_low = (u64)MAX_DMA_PFN << PAGE_SHIFT; - const u64 nd_high = (u64)max_pfn_mapped << PAGE_SHIFT; + const u64 nd_low = PFN_PHYS(MAX_DMA_PFN); + const u64 nd_high = PFN_PHYS(max_pfn_mapped); const size_t nd_size = roundup(sizeof(pg_data_t), PAGE_SIZE); - unsigned long nd_pa; + u64 nd_pa; int tnid; /* @@ -210,7 +209,7 @@ setup_node_bootmem(int nid, unsigned long start, unsigned long end) start = roundup(start, ZONE_ALIGN); - printk(KERN_INFO "Initmem setup node %d %016lx-%016lx\n", + printk(KERN_INFO "Initmem setup node %d %016Lx-%016Lx\n", nid, start, end); /* @@ -223,13 +222,13 @@ setup_node_bootmem(int nid, unsigned long start, unsigned long end) nd_pa = memblock_find_in_range(nd_low, nd_high, nd_size, SMP_CACHE_BYTES); if (nd_pa == MEMBLOCK_ERROR) { - pr_err("Cannot find %lu bytes in node %d\n", nd_size, nid); + pr_err("Cannot find %zu bytes in node %d\n", nd_size, nid); return; } memblock_x86_reserve_range(nd_pa, nd_pa + nd_size, "NODE_DATA"); /* report and initialize */ - printk(KERN_INFO " NODE_DATA [%016lx - %016lx]\n", + printk(KERN_INFO " NODE_DATA [%016Lx - %016Lx]\n", nd_pa, nd_pa + nd_size - 1); tnid = early_pfn_to_nid(nd_pa >> PAGE_SHIFT); if (tnid != nid) @@ -257,7 +256,7 @@ setup_node_bootmem(int nid, unsigned long start, unsigned long end) int __init numa_cleanup_meminfo(struct numa_meminfo *mi) { const u64 low = 0; - const u64 high = (u64)max_pfn << PAGE_SHIFT; + const u64 high = PFN_PHYS(max_pfn); int i, j, k; for (i = 0; i < mi->nr_blks; i++) { @@ -275,7 +274,7 @@ int __init numa_cleanup_meminfo(struct numa_meminfo *mi) for (j = i + 1; j < mi->nr_blks; j++) { struct numa_memblk *bj = &mi->blk[j]; - unsigned long start, end; + u64 start, end; /* * See whether there are overlapping blocks. Whine @@ -313,7 +312,7 @@ int __init numa_cleanup_meminfo(struct numa_meminfo *mi) } if (k < mi->nr_blks) continue; - printk(KERN_INFO "NUMA: Node %d [%Lx,%Lx) + [%Lx,%Lx) -> [%lx,%lx)\n", + printk(KERN_INFO "NUMA: Node %d [%Lx,%Lx) + [%Lx,%Lx) -> [%Lx,%Lx)\n", bi->nid, bi->start, bi->end, bj->start, bj->end, start, end); bi->start = start; @@ -378,7 +377,7 @@ static int __init numa_alloc_distance(void) cnt++; size = cnt * cnt * sizeof(numa_distance[0]); - phys = memblock_find_in_range(0, (u64)max_pfn_mapped << PAGE_SHIFT, + phys = memblock_find_in_range(0, PFN_PHYS(max_pfn_mapped), size, PAGE_SIZE); if (phys == MEMBLOCK_ERROR) { pr_warning("NUMA: Warning: can't allocate distance table!\n"); @@ -456,24 +455,24 @@ EXPORT_SYMBOL(__node_distance); */ static bool __init numa_meminfo_cover_memory(const struct numa_meminfo *mi) { - unsigned long numaram, e820ram; + u64 numaram, e820ram; int i; numaram = 0; for (i = 0; i < mi->nr_blks; i++) { - unsigned long s = mi->blk[i].start >> PAGE_SHIFT; - unsigned long e = mi->blk[i].end >> PAGE_SHIFT; + u64 s = mi->blk[i].start >> PAGE_SHIFT; + u64 e = mi->blk[i].end >> PAGE_SHIFT; numaram += e - s; numaram -= __absent_pages_in_range(mi->blk[i].nid, s, e); - if ((long)numaram < 0) + if ((s64)numaram < 0) numaram = 0; } e820ram = max_pfn - (memblock_x86_hole_size(0, - max_pfn << PAGE_SHIFT) >> PAGE_SHIFT); + PFN_PHYS(max_pfn)) >> PAGE_SHIFT); /* We seem to lose 3 pages somewhere. Allow 1M of slack. */ - if ((long)(e820ram - numaram) >= (1 << (20 - PAGE_SHIFT))) { - printk(KERN_ERR "NUMA: nodes only cover %luMB of your %luMB e820 RAM. Not used.\n", + if ((s64)(e820ram - numaram) >= (1 << (20 - PAGE_SHIFT))) { + printk(KERN_ERR "NUMA: nodes only cover %LuMB of your %LuMB e820 RAM. Not used.\n", (numaram << PAGE_SHIFT) >> 20, (e820ram << PAGE_SHIFT) >> 20); return false; @@ -503,7 +502,7 @@ static int __init numa_register_memblks(struct numa_meminfo *mi) /* Finally register nodes. */ for_each_node_mask(nid, node_possible_map) { - u64 start = (u64)max_pfn << PAGE_SHIFT; + u64 start = PFN_PHYS(max_pfn); u64 end = 0; for (i = 0; i < mi->nr_blks; i++) { @@ -595,11 +594,11 @@ static int __init dummy_numa_init(void) { printk(KERN_INFO "%s\n", numa_off ? "NUMA turned off" : "No NUMA configuration found"); - printk(KERN_INFO "Faking a node at %016lx-%016lx\n", - 0LU, max_pfn << PAGE_SHIFT); + printk(KERN_INFO "Faking a node at %016Lx-%016Lx\n", + 0LLU, PFN_PHYS(max_pfn)); node_set(0, numa_nodes_parsed); - numa_add_memblk(0, 0, (u64)max_pfn << PAGE_SHIFT); + numa_add_memblk(0, 0, PFN_PHYS(max_pfn)); return 0; } -- cgit v0.10.2 From 99cca492ea8ced305bfd687521ed69fb9e0147aa Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Mon, 2 May 2011 14:18:54 +0200 Subject: x86-32, NUMA: Add @start and @end to init_alloc_remap() Instead of dereferencing node_start/end_pfn[] directly, make init_alloc_remap() take @start and @end and let the caller be responsible for making sure the range is sane. This is to prepare for use from unified NUMA init code. Signed-off-by: Tejun Heo Cc: Ingo Molnar Cc: Yinghai Lu Cc: David Rientjes Cc: Thomas Gleixner Cc: "H. Peter Anvin" diff --git a/arch/x86/mm/numa_32.c b/arch/x86/mm/numa_32.c index 975a76f..9008632 100644 --- a/arch/x86/mm/numa_32.c +++ b/arch/x86/mm/numa_32.c @@ -265,8 +265,10 @@ void resume_map_numa_kva(pgd_t *pgd_base) * opportunistically and the callers will fall back to other memory * allocation mechanisms on failure. */ -static __init void init_alloc_remap(int nid) +static __init void init_alloc_remap(int nid, u64 start, u64 end) { + unsigned long start_pfn = start >> PAGE_SHIFT; + unsigned long end_pfn = end >> PAGE_SHIFT; unsigned long size, pfn; u64 node_pa, remap_pa; void *remap_va; @@ -276,24 +278,15 @@ static __init void init_alloc_remap(int nid) * memory could be added but not currently present. */ printk(KERN_DEBUG "node %d pfn: [%lx - %lx]\n", - nid, node_start_pfn[nid], node_end_pfn[nid]); - if (node_start_pfn[nid] > max_pfn) - return; - if (!node_end_pfn[nid]) - return; - if (node_end_pfn[nid] > max_pfn) - node_end_pfn[nid] = max_pfn; + nid, start_pfn, end_pfn); /* calculate the necessary space aligned to large page size */ - size = node_memmap_size_bytes(nid, node_start_pfn[nid], - min(node_end_pfn[nid], max_pfn)); + size = node_memmap_size_bytes(nid, start_pfn, end_pfn); size += ALIGN(sizeof(pg_data_t), PAGE_SIZE); size = ALIGN(size, LARGE_PAGE_BYTES); /* allocate node memory and the lowmem remap area */ - node_pa = memblock_find_in_range(node_start_pfn[nid] << PAGE_SHIFT, - (u64)node_end_pfn[nid] << PAGE_SHIFT, - size, LARGE_PAGE_BYTES); + node_pa = memblock_find_in_range(start, end, size, LARGE_PAGE_BYTES); if (node_pa == MEMBLOCK_ERROR) { pr_warning("remap_alloc: failed to allocate %lu bytes for node %d\n", size, nid); @@ -391,8 +384,14 @@ void __init initmem_init(void) get_memcfg_numa(); numa_init_array(); - for_each_online_node(nid) - init_alloc_remap(nid); + for_each_online_node(nid) { + u64 start = (u64)node_start_pfn[nid] << PAGE_SHIFT; + u64 end = min((u64)node_end_pfn[nid] << PAGE_SHIFT, + (u64)max_pfn << PAGE_SHIFT); + + if (start < end) + init_alloc_remap(nid, start, end); + } #ifdef CONFIG_HIGHMEM highstart_pfn = highend_pfn = max_pfn; -- cgit v0.10.2 From 7888e96b264fad27f97f58c0f3a4d20326eaf181 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Mon, 2 May 2011 14:18:54 +0200 Subject: x86, NUMA: Initialize and use remap allocator from setup_node_bootmem() setup_node_bootmem() is taken from 64bit and doesn't use remap allocator. It's about to be shared with 32bit so add support for it. If NODE_DATA is remapped, it's noted in the debug message and node locality check is skipped as the __pa() of the remapped address doesn't reflect the actual physical address. On 64bit, remap allocator becomes noop and doesn't affect the behavior. Signed-off-by: Tejun Heo Cc: Ingo Molnar Cc: Yinghai Lu Cc: David Rientjes Cc: Thomas Gleixner Cc: "H. Peter Anvin" diff --git a/arch/x86/mm/numa.c b/arch/x86/mm/numa.c index b45caa3..a72317a 100644 --- a/arch/x86/mm/numa.c +++ b/arch/x86/mm/numa.c @@ -197,7 +197,9 @@ static void __init setup_node_bootmem(int nid, u64 start, u64 end) const u64 nd_low = PFN_PHYS(MAX_DMA_PFN); const u64 nd_high = PFN_PHYS(max_pfn_mapped); const size_t nd_size = roundup(sizeof(pg_data_t), PAGE_SIZE); + bool remapped = false; u64 nd_pa; + void *nd; int tnid; /* @@ -207,34 +209,45 @@ static void __init setup_node_bootmem(int nid, u64 start, u64 end) if (end && (end - start) < NODE_MIN_SIZE) return; + /* initialize remap allocator before aligning to ZONE_ALIGN */ + init_alloc_remap(nid, start, end); + start = roundup(start, ZONE_ALIGN); printk(KERN_INFO "Initmem setup node %d %016Lx-%016Lx\n", nid, start, end); /* - * Try to allocate node data on local node and then fall back to - * all nodes. Never allocate in DMA zone. + * Allocate node data. Try remap allocator first, node-local + * memory and then any node. Never allocate in DMA zone. */ - nd_pa = memblock_x86_find_in_range_node(nid, nd_low, nd_high, + nd = alloc_remap(nid, nd_size); + if (nd) { + nd_pa = __pa(nd); + remapped = true; + } else { + nd_pa = memblock_x86_find_in_range_node(nid, nd_low, nd_high, nd_size, SMP_CACHE_BYTES); - if (nd_pa == MEMBLOCK_ERROR) - nd_pa = memblock_find_in_range(nd_low, nd_high, - nd_size, SMP_CACHE_BYTES); - if (nd_pa == MEMBLOCK_ERROR) { - pr_err("Cannot find %zu bytes in node %d\n", nd_size, nid); - return; + if (nd_pa == MEMBLOCK_ERROR) + nd_pa = memblock_find_in_range(nd_low, nd_high, + nd_size, SMP_CACHE_BYTES); + if (nd_pa == MEMBLOCK_ERROR) { + pr_err("Cannot find %zu bytes in node %d\n", + nd_size, nid); + return; + } + memblock_x86_reserve_range(nd_pa, nd_pa + nd_size, "NODE_DATA"); + nd = __va(nd_pa); } - memblock_x86_reserve_range(nd_pa, nd_pa + nd_size, "NODE_DATA"); /* report and initialize */ - printk(KERN_INFO " NODE_DATA [%016Lx - %016Lx]\n", - nd_pa, nd_pa + nd_size - 1); + printk(KERN_INFO " NODE_DATA [%016Lx - %016Lx]%s\n", + nd_pa, nd_pa + nd_size - 1, remapped ? " (remapped)" : ""); tnid = early_pfn_to_nid(nd_pa >> PAGE_SHIFT); - if (tnid != nid) + if (!remapped && tnid != nid) printk(KERN_INFO " NODE_DATA(%d) on node %d\n", nid, tnid); - node_data[nid] = __va(nd_pa); + node_data[nid] = nd; memset(NODE_DATA(nid), 0, sizeof(pg_data_t)); NODE_DATA(nid)->node_id = nid; NODE_DATA(nid)->node_start_pfn = start >> PAGE_SHIFT; diff --git a/arch/x86/mm/numa_32.c b/arch/x86/mm/numa_32.c index 9008632..fbd558f 100644 --- a/arch/x86/mm/numa_32.c +++ b/arch/x86/mm/numa_32.c @@ -265,7 +265,7 @@ void resume_map_numa_kva(pgd_t *pgd_base) * opportunistically and the callers will fall back to other memory * allocation mechanisms on failure. */ -static __init void init_alloc_remap(int nid, u64 start, u64 end) +void __init init_alloc_remap(int nid, u64 start, u64 end) { unsigned long start_pfn = start >> PAGE_SHIFT; unsigned long end_pfn = end >> PAGE_SHIFT; diff --git a/arch/x86/mm/numa_internal.h b/arch/x86/mm/numa_internal.h index ad86ec9..7178c3a 100644 --- a/arch/x86/mm/numa_internal.h +++ b/arch/x86/mm/numa_internal.h @@ -21,6 +21,12 @@ void __init numa_reset_distance(void); void __init x86_numa_init(void); +#ifdef CONFIG_X86_64 +static inline void init_alloc_remap(int nid, u64 start, u64 end) { } +#else +void __init init_alloc_remap(int nid, u64 start, u64 end); +#endif + #ifdef CONFIG_NUMA_EMU void __init numa_emulation(struct numa_meminfo *numa_meminfo, int numa_dist_cnt); -- cgit v0.10.2 From 6e3d4bec6b1e0829ed8b23be750762255f225019 Mon Sep 17 00:00:00 2001 From: Keshava Munegowda Date: Thu, 21 Apr 2011 19:52:43 +0530 Subject: omap:usb: add regulator support for EHCI in case of ehci phy mode; regulator of phy should be enabled before initializing the usbhs core driver. Signed-off-by: Keshava Munegowda Tested-by: Steve Calfee Signed-off-by: Felipe Balbi diff --git a/drivers/mfd/omap-usb-host.c b/drivers/mfd/omap-usb-host.c index b3bb3ac..2e16511 100644 --- a/drivers/mfd/omap-usb-host.c +++ b/drivers/mfd/omap-usb-host.c @@ -25,7 +25,6 @@ #include #include #include -#include #include #define USBHS_DRIVER_NAME "usbhs-omap" diff --git a/drivers/usb/host/ehci-omap.c b/drivers/usb/host/ehci-omap.c index 7e41a95..627f3a6 100644 --- a/drivers/usb/host/ehci-omap.c +++ b/drivers/usb/host/ehci-omap.c @@ -40,6 +40,7 @@ #include #include #include +#include /* EHCI Register Set */ #define EHCI_INSNREG04 (0xA0) @@ -118,6 +119,8 @@ static int ehci_hcd_omap_probe(struct platform_device *pdev) struct ehci_hcd *omap_ehci; int ret = -ENODEV; int irq; + int i; + char supply[7]; if (usb_disabled()) return -ENODEV; @@ -158,6 +161,23 @@ static int ehci_hcd_omap_probe(struct platform_device *pdev) hcd->rsrc_len = resource_size(res); hcd->regs = regs; + /* get ehci regulator and enable */ + for (i = 0 ; i < OMAP3_HS_USB_PORTS ; i++) { + if (pdata->port_mode[i] != OMAP_EHCI_PORT_MODE_PHY) { + pdata->regulator[i] = NULL; + continue; + } + snprintf(supply, sizeof(supply), "hsusb%d", i); + pdata->regulator[i] = regulator_get(dev, supply); + if (IS_ERR(pdata->regulator[i])) { + pdata->regulator[i] = NULL; + dev_dbg(dev, + "failed to get ehci port%d regulator\n", i); + } else { + regulator_enable(pdata->regulator[i]); + } + } + ret = omap_usbhs_enable(dev); if (ret) { dev_err(dev, "failed to start usbhs with err %d\n", ret); -- cgit v0.10.2 From bd6709a91a593d8fe35d08da542e9f93bb74a304 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Mon, 2 May 2011 17:24:48 +0200 Subject: x86, NUMA: Make 32bit use common NUMA init path With both _numa_init() methods converted and the rest of init code adjusted, numa_32.c now can switch from the 32bit only init code to the common one in numa.c. * Shim get_memcfg_*()'s are dropped and initmem_init() calls x86_numa_init(), which is updated to handle NUMAQ. * All boilerplate operations including node range limiting, pgdat alloc/init are handled by numa_init(). 32bit only implementation is removed. * 32bit numa_add_memblk(), numa_set_distance() and memory_add_physaddr_to_nid() removed and common versions in numa_32.c enabled for 32bit. This change causes the following behavior changes. * NODE_DATA()->node_start_pfn/node_spanned_pages properly initialized for 32bit too. * Much more sanity checks and configuration cleanups. * Proper handling of node distances. * The same NUMA init messages as 64bit. Signed-off-by: Tejun Heo Cc: Ingo Molnar Cc: Yinghai Lu Cc: David Rientjes Cc: Thomas Gleixner Cc: "H. Peter Anvin" diff --git a/arch/x86/include/asm/topology.h b/arch/x86/include/asm/topology.h index 8dba769..c006924 100644 --- a/arch/x86/include/asm/topology.h +++ b/arch/x86/include/asm/topology.h @@ -93,18 +93,11 @@ extern void setup_node_to_cpumask_map(void); #define pcibus_to_node(bus) __pcibus_to_node(bus) #ifdef CONFIG_X86_32 -extern unsigned long node_start_pfn[]; -extern unsigned long node_end_pfn[]; -#define node_has_online_mem(nid) (node_start_pfn[nid] != node_end_pfn[nid]) - # define SD_CACHE_NICE_TRIES 1 # define SD_IDLE_IDX 1 - #else - # define SD_CACHE_NICE_TRIES 2 # define SD_IDLE_IDX 2 - #endif /* sched_domains SD_NODE_INIT for NUMA machines */ diff --git a/arch/x86/mm/numa.c b/arch/x86/mm/numa.c index a72317a..56ed714 100644 --- a/arch/x86/mm/numa.c +++ b/arch/x86/mm/numa.c @@ -173,7 +173,6 @@ void __init numa_remove_memblk_from(int idx, struct numa_meminfo *mi) (mi->nr_blks - idx) * sizeof(mi->blk[0])); } -#ifdef CONFIG_X86_64 /** * numa_add_memblk - Add one numa_memblk to numa_meminfo * @nid: NUMA node ID of the new memblk @@ -189,7 +188,6 @@ int __init numa_add_memblk(int nid, u64 start, u64 end) { return numa_add_memblk_to(nid, start, end, &numa_meminfo); } -#endif /* Initialize bootmem allocator for a node */ static void __init setup_node_bootmem(int nid, u64 start, u64 end) @@ -413,7 +411,6 @@ static int __init numa_alloc_distance(void) return 0; } -#ifdef CONFIG_X86_64 /** * numa_set_distance - Set NUMA distance from one NUMA to another * @from: the 'from' node to set distance @@ -452,7 +449,6 @@ void __init numa_set_distance(int from, int to, int distance) numa_distance[from * numa_distance_cnt + to] = distance; } -#endif int __node_distance(int from, int to) { @@ -626,6 +622,10 @@ static int __init dummy_numa_init(void) void __init x86_numa_init(void) { if (!numa_off) { +#ifdef CONFIG_X86_NUMAQ + if (!numa_init(numaq_numa_init)) + return; +#endif #ifdef CONFIG_ACPI_NUMA if (!numa_init(x86_acpi_numa_init)) return; @@ -805,7 +805,7 @@ EXPORT_SYMBOL(cpumask_of_node); #endif /* !CONFIG_DEBUG_PER_CPU_MAPS */ -#if defined(CONFIG_X86_64) && defined(CONFIG_MEMORY_HOTPLUG) +#ifdef CONFIG_MEMORY_HOTPLUG int memory_add_physaddr_to_nid(u64 start) { struct numa_meminfo *mi = &numa_meminfo; diff --git a/arch/x86/mm/numa_32.c b/arch/x86/mm/numa_32.c index fbd558f..849a975 100644 --- a/arch/x86/mm/numa_32.c +++ b/arch/x86/mm/numa_32.c @@ -22,36 +22,11 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -#include #include #include -#include -#include -#include -#include #include -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -/* - * numa interface - we expect the numa architecture specific code to have - * populated the following initialisation. - * - * 1) node_online_map - the map of all nodes configured (online) in the system - * 2) node_start_pfn - the starting page frame number for a node - * 3) node_end_pfn - the ending page fram number for a node - */ -unsigned long node_start_pfn[MAX_NUMNODES] __read_mostly; -unsigned long node_end_pfn[MAX_NUMNODES] __read_mostly; +#include "numa_internal.h" #ifdef CONFIG_DISCONTIGMEM /* @@ -96,7 +71,6 @@ unsigned long node_memmap_size_bytes(int nid, unsigned long start_pfn, } #endif -extern unsigned long find_max_low_pfn(void); extern unsigned long highend_pfn, highstart_pfn; #define LARGE_PAGE_BYTES (PTRS_PER_PTE * PAGE_SIZE) @@ -105,68 +79,6 @@ static void *node_remap_start_vaddr[MAX_NUMNODES]; void set_pmd_pfn(unsigned long vaddr, unsigned long pfn, pgprot_t flags); /* - * FLAT - support for basic PC memory model with discontig enabled, essentially - * a single node with all available processors in it with a flat - * memory map. - */ -static int __init get_memcfg_numa_flat(void) -{ - printk(KERN_DEBUG "NUMA - single node, flat memory mode\n"); - - node_start_pfn[0] = 0; - node_end_pfn[0] = max_pfn; - memblock_x86_register_active_regions(0, 0, max_pfn); - - /* Indicate there is one node available. */ - nodes_clear(node_online_map); - node_set_online(0); - return 1; -} - -/* - * Find the highest page frame number we have available for the node - */ -static void __init propagate_e820_map_node(int nid) -{ - if (node_end_pfn[nid] > max_pfn) - node_end_pfn[nid] = max_pfn; - /* - * if a user has given mem=XXXX, then we need to make sure - * that the node _starts_ before that, too, not just ends - */ - if (node_start_pfn[nid] > max_pfn) - node_start_pfn[nid] = max_pfn; - BUG_ON(node_start_pfn[nid] > node_end_pfn[nid]); -} - -/* - * Allocate memory for the pg_data_t for this node via a crude pre-bootmem - * method. For node zero take this from the bottom of memory, for - * subsequent nodes place them at node_remap_start_vaddr which contains - * node local data in physically node local memory. See setup_memory() - * for details. - */ -static void __init allocate_pgdat(int nid) -{ - char buf[16]; - - NODE_DATA(nid) = alloc_remap(nid, ALIGN(sizeof(pg_data_t), PAGE_SIZE)); - if (!NODE_DATA(nid)) { - unsigned long pgdat_phys; - pgdat_phys = memblock_find_in_range(min_low_pfn<>PAGE_SHIFT)); - memset(buf, 0, sizeof(buf)); - sprintf(buf, "NODE_DATA %d", nid); - memblock_x86_reserve_range(pgdat_phys, pgdat_phys + sizeof(pg_data_t), buf); - } - printk(KERN_DEBUG "allocate_pgdat: node %d NODE_DATA %08lx\n", - nid, (unsigned long)NODE_DATA(nid)); -} - -/* * Remap memory allocator */ static unsigned long node_remap_start_pfn[MAX_NUMNODES]; @@ -322,76 +234,9 @@ void __init init_alloc_remap(int nid, u64 start, u64 end) nid, node_pa, node_pa + size, remap_va, remap_va + size); } -static int get_memcfg_numaq(void) -{ -#ifdef CONFIG_X86_NUMAQ - int nid; - - if (numa_off) - return 0; - - if (numaq_numa_init() < 0) { - nodes_clear(numa_nodes_parsed); - remove_all_active_ranges(); - return 0; - } - - for_each_node_mask(nid, numa_nodes_parsed) - node_set_online(nid); - sort_node_map(); - return 1; -#else - return 0; -#endif -} - -static int get_memcfg_from_srat(void) -{ -#ifdef CONFIG_ACPI_NUMA - int nid; - - if (numa_off) - return 0; - - if (x86_acpi_numa_init() < 0) { - nodes_clear(numa_nodes_parsed); - remove_all_active_ranges(); - return 0; - } - - for_each_node_mask(nid, numa_nodes_parsed) - node_set_online(nid); - sort_node_map(); - return 1; -#else - return 0; -#endif -} - -static void get_memcfg_numa(void) -{ - if (get_memcfg_numaq()) - return; - if (get_memcfg_from_srat()) - return; - get_memcfg_numa_flat(); -} - void __init initmem_init(void) { - int nid; - - get_memcfg_numa(); - numa_init_array(); - - for_each_online_node(nid) { - u64 start = (u64)node_start_pfn[nid] << PAGE_SHIFT; - u64 end = min((u64)node_end_pfn[nid] << PAGE_SHIFT, - (u64)max_pfn << PAGE_SHIFT); - - if (start < end) - init_alloc_remap(nid, start, end); - } + x86_numa_init(); #ifdef CONFIG_HIGHMEM highstart_pfn = highend_pfn = max_pfn; @@ -412,81 +257,9 @@ void __init initmem_init(void) printk(KERN_DEBUG "Low memory ends at vaddr %08lx\n", (ulong) pfn_to_kaddr(max_low_pfn)); - for_each_online_node(nid) - allocate_pgdat(nid); printk(KERN_DEBUG "High memory starts at vaddr %08lx\n", (ulong) pfn_to_kaddr(highstart_pfn)); - for_each_online_node(nid) - propagate_e820_map_node(nid); - - for_each_online_node(nid) { - memset(NODE_DATA(nid), 0, sizeof(struct pglist_data)); - NODE_DATA(nid)->node_id = nid; - } setup_bootmem_allocator(); } - -#ifdef CONFIG_MEMORY_HOTPLUG -static int paddr_to_nid(u64 addr) -{ - int nid; - unsigned long pfn = PFN_DOWN(addr); - - for_each_node(nid) - if (node_start_pfn[nid] <= pfn && - pfn < node_end_pfn[nid]) - return nid; - - return -1; -} - -/* - * This function is used to ask node id BEFORE memmap and mem_section's - * initialization (pfn_to_nid() can't be used yet). - * If _PXM is not defined on ACPI's DSDT, node id must be found by this. - */ -int memory_add_physaddr_to_nid(u64 addr) -{ - int nid = paddr_to_nid(addr); - return (nid >= 0) ? nid : 0; -} - -EXPORT_SYMBOL_GPL(memory_add_physaddr_to_nid); -#endif - -/* temporary shim, will go away soon */ -int __init numa_add_memblk(int nid, u64 start, u64 end) -{ - unsigned long start_pfn = start >> PAGE_SHIFT; - unsigned long end_pfn = end >> PAGE_SHIFT; - - printk(KERN_DEBUG "nid %d start_pfn %08lx end_pfn %08lx\n", - nid, start_pfn, end_pfn); - - if (start >= (u64)max_pfn << PAGE_SHIFT) { - printk(KERN_INFO "Ignoring SRAT pfns: %08lx - %08lx\n", - start_pfn, end_pfn); - return 0; - } - - node_set_online(nid); - memblock_x86_register_active_regions(nid, start_pfn, - min(end_pfn, max_pfn)); - - if (!node_has_online_mem(nid)) { - node_start_pfn[nid] = start_pfn; - node_end_pfn[nid] = end_pfn; - } else { - node_start_pfn[nid] = min(node_start_pfn[nid], start_pfn); - node_end_pfn[nid] = max(node_end_pfn[nid], end_pfn); - } - return 0; -} - -/* temporary shim, will go away soon */ -void __init numa_set_distance(int from, int to, int distance) -{ - /* nada */ -} -- cgit v0.10.2 From 752d4f372f90a2f6eb562aaffb639957890cbcab Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Mon, 2 May 2011 17:24:48 +0200 Subject: x86, NUMA: Make numa_init_array() static numa_init_array() no longer has users outside of numa.c. Make it static. Signed-off-by: Tejun Heo Cc: Ingo Molnar Cc: Yinghai Lu Cc: David Rientjes Cc: Thomas Gleixner Cc: "H. Peter Anvin" diff --git a/arch/x86/include/asm/numa.h b/arch/x86/include/asm/numa.h index 7454086..bfacd2c 100644 --- a/arch/x86/include/asm/numa.h +++ b/arch/x86/include/asm/numa.h @@ -61,14 +61,12 @@ static inline int numa_cpu_node(int cpu) #ifdef CONFIG_NUMA extern void __cpuinit numa_set_node(int cpu, int node); extern void __cpuinit numa_clear_node(int cpu); -extern void __init numa_init_array(void); extern void __init init_cpu_to_node(void); extern void __cpuinit numa_add_cpu(int cpu); extern void __cpuinit numa_remove_cpu(int cpu); #else /* CONFIG_NUMA */ static inline void numa_set_node(int cpu, int node) { } static inline void numa_clear_node(int cpu) { } -static inline void numa_init_array(void) { } static inline void init_cpu_to_node(void) { } static inline void numa_add_cpu(int cpu) { } static inline void numa_remove_cpu(int cpu) { } diff --git a/arch/x86/mm/numa.c b/arch/x86/mm/numa.c index 56ed714..ecb5685 100644 --- a/arch/x86/mm/numa.c +++ b/arch/x86/mm/numa.c @@ -535,7 +535,7 @@ static int __init numa_register_memblks(struct numa_meminfo *mi) * as the number of CPUs is not known yet. We round robin the existing * nodes. */ -void __init numa_init_array(void) +static void __init numa_init_array(void) { int rr, i; -- cgit v0.10.2 From c6f58878204b0414e00b43f9bcebf754284f95b4 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Mon, 2 May 2011 17:24:48 +0200 Subject: x86, NUMA: Rename amdtopology_64.c to amdtopology.c amdtopology is going to be used by 32bit too drop _64 suffix. This is pure rename. Signed-off-by: Tejun Heo Cc: Ingo Molnar Cc: Yinghai Lu Cc: David Rientjes Cc: Thomas Gleixner Cc: "H. Peter Anvin" diff --git a/arch/x86/mm/Makefile b/arch/x86/mm/Makefile index 62997be..3d11327 100644 --- a/arch/x86/mm/Makefile +++ b/arch/x86/mm/Makefile @@ -23,7 +23,7 @@ mmiotrace-y := kmmio.o pf_in.o mmio-mod.o obj-$(CONFIG_MMIOTRACE_TEST) += testmmiotrace.o obj-$(CONFIG_NUMA) += numa.o numa_$(BITS).o -obj-$(CONFIG_AMD_NUMA) += amdtopology_64.o +obj-$(CONFIG_AMD_NUMA) += amdtopology.o obj-$(CONFIG_ACPI_NUMA) += srat.o obj-$(CONFIG_NUMA_EMU) += numa_emulation.o diff --git a/arch/x86/mm/amdtopology.c b/arch/x86/mm/amdtopology.c new file mode 100644 index 0000000..0919c26 --- /dev/null +++ b/arch/x86/mm/amdtopology.c @@ -0,0 +1,196 @@ +/* + * AMD NUMA support. + * Discover the memory map and associated nodes. + * + * This version reads it directly from the AMD northbridge. + * + * Copyright 2002,2003 Andi Kleen, SuSE Labs. + */ +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static unsigned char __initdata nodeids[8]; + +static __init int find_northbridge(void) +{ + int num; + + for (num = 0; num < 32; num++) { + u32 header; + + header = read_pci_config(0, num, 0, 0x00); + if (header != (PCI_VENDOR_ID_AMD | (0x1100<<16)) && + header != (PCI_VENDOR_ID_AMD | (0x1200<<16)) && + header != (PCI_VENDOR_ID_AMD | (0x1300<<16))) + continue; + + header = read_pci_config(0, num, 1, 0x00); + if (header != (PCI_VENDOR_ID_AMD | (0x1101<<16)) && + header != (PCI_VENDOR_ID_AMD | (0x1201<<16)) && + header != (PCI_VENDOR_ID_AMD | (0x1301<<16))) + continue; + return num; + } + + return -ENOENT; +} + +static __init void early_get_boot_cpu_id(void) +{ + /* + * need to get the APIC ID of the BSP so can use that to + * create apicid_to_node in amd_scan_nodes() + */ +#ifdef CONFIG_X86_MPPARSE + /* + * get boot-time SMP configuration: + */ + if (smp_found_config) + early_get_smp_config(); +#endif +} + +int __init amd_numa_init(void) +{ + unsigned long start = PFN_PHYS(0); + unsigned long end = PFN_PHYS(max_pfn); + unsigned numnodes; + unsigned long prevbase; + int i, j, nb; + u32 nodeid, reg; + unsigned int bits, cores, apicid_base; + + if (!early_pci_allowed()) + return -EINVAL; + + nb = find_northbridge(); + if (nb < 0) + return nb; + + pr_info("Scanning NUMA topology in Northbridge %d\n", nb); + + reg = read_pci_config(0, nb, 0, 0x60); + numnodes = ((reg >> 4) & 0xF) + 1; + if (numnodes <= 1) + return -ENOENT; + + pr_info("Number of physical nodes %d\n", numnodes); + + prevbase = 0; + for (i = 0; i < 8; i++) { + unsigned long base, limit; + + base = read_pci_config(0, nb, 1, 0x40 + i*8); + limit = read_pci_config(0, nb, 1, 0x44 + i*8); + + nodeids[i] = nodeid = limit & 7; + if ((base & 3) == 0) { + if (i < numnodes) + pr_info("Skipping disabled node %d\n", i); + continue; + } + if (nodeid >= numnodes) { + pr_info("Ignoring excess node %d (%lx:%lx)\n", nodeid, + base, limit); + continue; + } + + if (!limit) { + pr_info("Skipping node entry %d (base %lx)\n", + i, base); + continue; + } + if ((base >> 8) & 3 || (limit >> 8) & 3) { + pr_err("Node %d using interleaving mode %lx/%lx\n", + nodeid, (base >> 8) & 3, (limit >> 8) & 3); + return -EINVAL; + } + if (node_isset(nodeid, numa_nodes_parsed)) { + pr_info("Node %d already present, skipping\n", + nodeid); + continue; + } + + limit >>= 16; + limit <<= 24; + limit |= (1<<24)-1; + limit++; + + if (limit > end) + limit = end; + if (limit <= base) + continue; + + base >>= 16; + base <<= 24; + + if (base < start) + base = start; + if (limit > end) + limit = end; + if (limit == base) { + pr_err("Empty node %d\n", nodeid); + continue; + } + if (limit < base) { + pr_err("Node %d bogus settings %lx-%lx.\n", + nodeid, base, limit); + continue; + } + + /* Could sort here, but pun for now. Should not happen anyroads. */ + if (prevbase > base) { + pr_err("Node map not sorted %lx,%lx\n", + prevbase, base); + return -EINVAL; + } + + pr_info("Node %d MemBase %016lx Limit %016lx\n", + nodeid, base, limit); + + prevbase = base; + numa_add_memblk(nodeid, base, limit); + node_set(nodeid, numa_nodes_parsed); + } + + if (!nodes_weight(numa_nodes_parsed)) + return -ENOENT; + + /* + * We seem to have valid NUMA configuration. Map apicids to nodes + * using the coreid bits from early_identify_cpu. + */ + bits = boot_cpu_data.x86_coreid_bits; + cores = 1 << bits; + apicid_base = 0; + + /* get the APIC ID of the BSP early for systems with apicid lifting */ + early_get_boot_cpu_id(); + if (boot_cpu_physical_apicid > 0) { + pr_info("BSP APIC ID: %02x\n", boot_cpu_physical_apicid); + apicid_base = boot_cpu_physical_apicid; + } + + for_each_node_mask(i, numa_nodes_parsed) + for (j = apicid_base; j < cores + apicid_base; j++) + set_apicid_to_node((i << bits) + j, i); + + return 0; +} diff --git a/arch/x86/mm/amdtopology_64.c b/arch/x86/mm/amdtopology_64.c deleted file mode 100644 index 0919c26..0000000 --- a/arch/x86/mm/amdtopology_64.c +++ /dev/null @@ -1,196 +0,0 @@ -/* - * AMD NUMA support. - * Discover the memory map and associated nodes. - * - * This version reads it directly from the AMD northbridge. - * - * Copyright 2002,2003 Andi Kleen, SuSE Labs. - */ -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -static unsigned char __initdata nodeids[8]; - -static __init int find_northbridge(void) -{ - int num; - - for (num = 0; num < 32; num++) { - u32 header; - - header = read_pci_config(0, num, 0, 0x00); - if (header != (PCI_VENDOR_ID_AMD | (0x1100<<16)) && - header != (PCI_VENDOR_ID_AMD | (0x1200<<16)) && - header != (PCI_VENDOR_ID_AMD | (0x1300<<16))) - continue; - - header = read_pci_config(0, num, 1, 0x00); - if (header != (PCI_VENDOR_ID_AMD | (0x1101<<16)) && - header != (PCI_VENDOR_ID_AMD | (0x1201<<16)) && - header != (PCI_VENDOR_ID_AMD | (0x1301<<16))) - continue; - return num; - } - - return -ENOENT; -} - -static __init void early_get_boot_cpu_id(void) -{ - /* - * need to get the APIC ID of the BSP so can use that to - * create apicid_to_node in amd_scan_nodes() - */ -#ifdef CONFIG_X86_MPPARSE - /* - * get boot-time SMP configuration: - */ - if (smp_found_config) - early_get_smp_config(); -#endif -} - -int __init amd_numa_init(void) -{ - unsigned long start = PFN_PHYS(0); - unsigned long end = PFN_PHYS(max_pfn); - unsigned numnodes; - unsigned long prevbase; - int i, j, nb; - u32 nodeid, reg; - unsigned int bits, cores, apicid_base; - - if (!early_pci_allowed()) - return -EINVAL; - - nb = find_northbridge(); - if (nb < 0) - return nb; - - pr_info("Scanning NUMA topology in Northbridge %d\n", nb); - - reg = read_pci_config(0, nb, 0, 0x60); - numnodes = ((reg >> 4) & 0xF) + 1; - if (numnodes <= 1) - return -ENOENT; - - pr_info("Number of physical nodes %d\n", numnodes); - - prevbase = 0; - for (i = 0; i < 8; i++) { - unsigned long base, limit; - - base = read_pci_config(0, nb, 1, 0x40 + i*8); - limit = read_pci_config(0, nb, 1, 0x44 + i*8); - - nodeids[i] = nodeid = limit & 7; - if ((base & 3) == 0) { - if (i < numnodes) - pr_info("Skipping disabled node %d\n", i); - continue; - } - if (nodeid >= numnodes) { - pr_info("Ignoring excess node %d (%lx:%lx)\n", nodeid, - base, limit); - continue; - } - - if (!limit) { - pr_info("Skipping node entry %d (base %lx)\n", - i, base); - continue; - } - if ((base >> 8) & 3 || (limit >> 8) & 3) { - pr_err("Node %d using interleaving mode %lx/%lx\n", - nodeid, (base >> 8) & 3, (limit >> 8) & 3); - return -EINVAL; - } - if (node_isset(nodeid, numa_nodes_parsed)) { - pr_info("Node %d already present, skipping\n", - nodeid); - continue; - } - - limit >>= 16; - limit <<= 24; - limit |= (1<<24)-1; - limit++; - - if (limit > end) - limit = end; - if (limit <= base) - continue; - - base >>= 16; - base <<= 24; - - if (base < start) - base = start; - if (limit > end) - limit = end; - if (limit == base) { - pr_err("Empty node %d\n", nodeid); - continue; - } - if (limit < base) { - pr_err("Node %d bogus settings %lx-%lx.\n", - nodeid, base, limit); - continue; - } - - /* Could sort here, but pun for now. Should not happen anyroads. */ - if (prevbase > base) { - pr_err("Node map not sorted %lx,%lx\n", - prevbase, base); - return -EINVAL; - } - - pr_info("Node %d MemBase %016lx Limit %016lx\n", - nodeid, base, limit); - - prevbase = base; - numa_add_memblk(nodeid, base, limit); - node_set(nodeid, numa_nodes_parsed); - } - - if (!nodes_weight(numa_nodes_parsed)) - return -ENOENT; - - /* - * We seem to have valid NUMA configuration. Map apicids to nodes - * using the coreid bits from early_identify_cpu. - */ - bits = boot_cpu_data.x86_coreid_bits; - cores = 1 << bits; - apicid_base = 0; - - /* get the APIC ID of the BSP early for systems with apicid lifting */ - early_get_boot_cpu_id(); - if (boot_cpu_physical_apicid > 0) { - pr_info("BSP APIC ID: %02x\n", boot_cpu_physical_apicid); - apicid_base = boot_cpu_physical_apicid; - } - - for_each_node_mask(i, numa_nodes_parsed) - for (j = apicid_base; j < cores + apicid_base; j++) - set_apicid_to_node((i << bits) + j, i); - - return 0; -} -- cgit v0.10.2 From 2706a0bf7b02693ed88752df877f10c2206292ff Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Mon, 2 May 2011 17:24:48 +0200 Subject: x86, NUMA: Enable CONFIG_AMD_NUMA on 32bit too Now that NUMA init path is unified, amdtopology can be enabled on 32bit. Make amdtopology.c safe on 32bit by explicitly using u64 and drop X86_64 dependency from Kconfig. Inclusion of bootmem.h is added for max_pfn declaration. Signed-off-by: Tejun Heo Cc: Ingo Molnar Cc: Yinghai Lu Cc: David Rientjes Cc: Thomas Gleixner Cc: "H. Peter Anvin" diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig index 8db4fbf..50cb68d 100644 --- a/arch/x86/Kconfig +++ b/arch/x86/Kconfig @@ -1174,7 +1174,7 @@ comment "NUMA (Summit) requires SMP, 64GB highmem support, ACPI" config AMD_NUMA def_bool y prompt "Old style AMD Opteron NUMA detection" - depends on X86_64 && NUMA && PCI + depends on NUMA && PCI ---help--- Enable AMD NUMA node topology detection. You should say Y here if you have a multi processor AMD system. This uses an old method to diff --git a/arch/x86/mm/amdtopology.c b/arch/x86/mm/amdtopology.c index 0919c26..5247d01 100644 --- a/arch/x86/mm/amdtopology.c +++ b/arch/x86/mm/amdtopology.c @@ -12,6 +12,7 @@ #include #include #include +#include #include #include @@ -69,10 +70,10 @@ static __init void early_get_boot_cpu_id(void) int __init amd_numa_init(void) { - unsigned long start = PFN_PHYS(0); - unsigned long end = PFN_PHYS(max_pfn); + u64 start = PFN_PHYS(0); + u64 end = PFN_PHYS(max_pfn); unsigned numnodes; - unsigned long prevbase; + u64 prevbase; int i, j, nb; u32 nodeid, reg; unsigned int bits, cores, apicid_base; @@ -95,7 +96,7 @@ int __init amd_numa_init(void) prevbase = 0; for (i = 0; i < 8; i++) { - unsigned long base, limit; + u64 base, limit; base = read_pci_config(0, nb, 1, 0x40 + i*8); limit = read_pci_config(0, nb, 1, 0x44 + i*8); @@ -107,18 +108,18 @@ int __init amd_numa_init(void) continue; } if (nodeid >= numnodes) { - pr_info("Ignoring excess node %d (%lx:%lx)\n", nodeid, + pr_info("Ignoring excess node %d (%Lx:%Lx)\n", nodeid, base, limit); continue; } if (!limit) { - pr_info("Skipping node entry %d (base %lx)\n", + pr_info("Skipping node entry %d (base %Lx)\n", i, base); continue; } if ((base >> 8) & 3 || (limit >> 8) & 3) { - pr_err("Node %d using interleaving mode %lx/%lx\n", + pr_err("Node %d using interleaving mode %Lx/%Lx\n", nodeid, (base >> 8) & 3, (limit >> 8) & 3); return -EINVAL; } @@ -150,19 +151,19 @@ int __init amd_numa_init(void) continue; } if (limit < base) { - pr_err("Node %d bogus settings %lx-%lx.\n", + pr_err("Node %d bogus settings %Lx-%Lx.\n", nodeid, base, limit); continue; } /* Could sort here, but pun for now. Should not happen anyroads. */ if (prevbase > base) { - pr_err("Node map not sorted %lx,%lx\n", + pr_err("Node map not sorted %Lx,%Lx\n", prevbase, base); return -EINVAL; } - pr_info("Node %d MemBase %016lx Limit %016lx\n", + pr_info("Node %d MemBase %016Lx Limit %016Lx\n", nodeid, base, limit); prevbase = base; -- cgit v0.10.2 From 1b7e03ef7570568d2fb9e6640d7006a0edd728f6 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Mon, 2 May 2011 17:24:48 +0200 Subject: x86, NUMA: Enable emulation on 32bit too Now that NUMA init path is unified, NUMA emulation can be enabled on 32bit. Make numa_emluation.c safe on 32bit by doing the followings. * Define MAX_DMA32_PFN on 32bit too. * Include bootmem.h for max_pfn declaration. * Use u64 explicitly and always use PFN_PHYS() when converting page number to address. * Avoid __udivdi3() generation on 32bit by doing number of pages calculation instead in split_nodes_interleave(). And drop X86_64 dependency from Kconfig. Signed-off-by: Tejun Heo Cc: Ingo Molnar Cc: Yinghai Lu Cc: David Rientjes Cc: Thomas Gleixner Cc: "H. Peter Anvin" diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig index 50cb68d..648fca4 100644 --- a/arch/x86/Kconfig +++ b/arch/x86/Kconfig @@ -1201,7 +1201,7 @@ config NODES_SPAN_OTHER_NODES config NUMA_EMU bool "NUMA emulation" - depends on X86_64 && NUMA + depends on NUMA ---help--- Enable NUMA emulation. A flat machine will be split into virtual nodes when booted with "numa=fake=N", where N is the diff --git a/arch/x86/include/asm/dma.h b/arch/x86/include/asm/dma.h index d1a314b..0bdb0c5 100644 --- a/arch/x86/include/asm/dma.h +++ b/arch/x86/include/asm/dma.h @@ -72,19 +72,15 @@ /* 16MB ISA DMA zone */ #define MAX_DMA_PFN ((16 * 1024 * 1024) >> PAGE_SHIFT) -#ifdef CONFIG_X86_32 +/* 4GB broken PCI/AGP hardware bus master zone */ +#define MAX_DMA32_PFN ((4UL * 1024 * 1024 * 1024) >> PAGE_SHIFT) +#ifdef CONFIG_X86_32 /* The maximum address that we can perform a DMA transfer to on this platform */ #define MAX_DMA_ADDRESS (PAGE_OFFSET + 0x1000000) - #else - -/* 4GB broken PCI/AGP hardware bus master zone */ -#define MAX_DMA32_PFN ((4UL * 1024 * 1024 * 1024) >> PAGE_SHIFT) - /* Compat define for old dma zone */ #define MAX_DMA_ADDRESS ((unsigned long)__va(MAX_DMA_PFN << PAGE_SHIFT)) - #endif /* 8237 DMA controllers */ diff --git a/arch/x86/mm/numa_emulation.c b/arch/x86/mm/numa_emulation.c index de84cc1..d0ed086 100644 --- a/arch/x86/mm/numa_emulation.c +++ b/arch/x86/mm/numa_emulation.c @@ -5,6 +5,7 @@ #include #include #include +#include #include #include "numa_internal.h" @@ -84,7 +85,13 @@ static int __init split_nodes_interleave(struct numa_meminfo *ei, nr_nodes = MAX_NUMNODES; } - size = (max_addr - addr - memblock_x86_hole_size(addr, max_addr)) / nr_nodes; + /* + * Calculate target node size. x86_32 freaks on __udivdi3() so do + * the division in ulong number of pages and convert back. + */ + size = max_addr - addr - memblock_x86_hole_size(addr, max_addr); + size = PFN_PHYS((unsigned long)(size >> PAGE_SHIFT) / nr_nodes); + /* * Calculate the number of big nodes that can be allocated as a result * of consolidating the remainder. @@ -226,7 +233,7 @@ static int __init split_nodes_size_interleave(struct numa_meminfo *ei, */ while (nodes_weight(physnode_mask)) { for_each_node_mask(i, physnode_mask) { - u64 dma32_end = MAX_DMA32_PFN << PAGE_SHIFT; + u64 dma32_end = PFN_PHYS(MAX_DMA32_PFN); u64 start, limit, end; int phys_blk; @@ -298,7 +305,7 @@ void __init numa_emulation(struct numa_meminfo *numa_meminfo, int numa_dist_cnt) { static struct numa_meminfo ei __initdata; static struct numa_meminfo pi __initdata; - const u64 max_addr = max_pfn << PAGE_SHIFT; + const u64 max_addr = PFN_PHYS(max_pfn); u8 *phys_dist = NULL; size_t phys_size = numa_dist_cnt * numa_dist_cnt * sizeof(phys_dist[0]); int max_emu_nid, dfl_phys_nid; @@ -342,8 +349,7 @@ void __init numa_emulation(struct numa_meminfo *numa_meminfo, int numa_dist_cnt) if (numa_dist_cnt) { u64 phys; - phys = memblock_find_in_range(0, - (u64)max_pfn_mapped << PAGE_SHIFT, + phys = memblock_find_in_range(0, PFN_PHYS(max_pfn_mapped), phys_size, PAGE_SIZE); if (phys == MEMBLOCK_ERROR) { pr_warning("NUMA: Warning: can't allocate copy of distance table, disabling emulation\n"); -- cgit v0.10.2 From a56bca80db8903bb557b9ac38da68dc5b98ea672 Mon Sep 17 00:00:00 2001 From: Yinghai Lu Date: Mon, 2 May 2011 17:24:49 +0200 Subject: x86, NUMA: Rename setup_node_bootmem() to setup_node_data() After using memblock to replace bootmem, that function only sets up node_data now. Change the name to reflect what it actually does. tj: Minor adjustment to the patch description. Signed-off-by: Yinghai Lu Signed-off-by: Tejun Heo diff --git a/arch/x86/mm/numa.c b/arch/x86/mm/numa.c index ecb5685..9a0ed31 100644 --- a/arch/x86/mm/numa.c +++ b/arch/x86/mm/numa.c @@ -189,8 +189,8 @@ int __init numa_add_memblk(int nid, u64 start, u64 end) return numa_add_memblk_to(nid, start, end, &numa_meminfo); } -/* Initialize bootmem allocator for a node */ -static void __init setup_node_bootmem(int nid, u64 start, u64 end) +/* Initialize NODE_DATA for a node on the local memory */ +static void __init setup_node_data(int nid, u64 start, u64 end) { const u64 nd_low = PFN_PHYS(MAX_DMA_PFN); const u64 nd_high = PFN_PHYS(max_pfn_mapped); @@ -522,7 +522,7 @@ static int __init numa_register_memblks(struct numa_meminfo *mi) } if (start < end) - setup_node_bootmem(nid, start, end); + setup_node_data(nid, start, end); } return 0; -- cgit v0.10.2 From e5a10c1bd12a5d71bbb6406c1b0dbbc9d8958397 Mon Sep 17 00:00:00 2001 From: Yinghai Lu Date: Mon, 2 May 2011 17:24:49 +0200 Subject: x86, NUMA: Trim numa meminfo with max_pfn in a separate loop During testing 32bit numa unifying code from tj, found one system with more than 64g fails to use numa. It turns out we do not trim numa meminfo correctly against max_pfn in case start address of a node is higher than 64GiB. Bug fix made it to tip tree. This patch moves the checking and trimming to a separate loop. So we don't need to compare low/high in following merge loops. It makes the code more readable. Also it makes the node merge printouts less strange. On a 512GiB numa system with 32bit, before: > NUMA: Node 0 [0,a0000) + [100000,80000000) -> [0,80000000) > NUMA: Node 0 [0,80000000) + [100000000,1080000000) -> [0,1000000000) after: > NUMA: Node 0 [0,a0000) + [100000,80000000) -> [0,80000000) > NUMA: Node 0 [0,80000000) + [100000000,1000000000) -> [0,1000000000) Signed-off-by: Yinghai Lu [Updated patch description and comment slightly.] Signed-off-by: Tejun Heo diff --git a/arch/x86/mm/numa.c b/arch/x86/mm/numa.c index 9a0ed31..f5510d8 100644 --- a/arch/x86/mm/numa.c +++ b/arch/x86/mm/numa.c @@ -270,6 +270,7 @@ int __init numa_cleanup_meminfo(struct numa_meminfo *mi) const u64 high = PFN_PHYS(max_pfn); int i, j, k; + /* first, trim all entries */ for (i = 0; i < mi->nr_blks; i++) { struct numa_memblk *bi = &mi->blk[i]; @@ -278,10 +279,13 @@ int __init numa_cleanup_meminfo(struct numa_meminfo *mi) bi->end = min(bi->end, high); /* and there's no empty block */ - if (bi->start >= bi->end) { + if (bi->start >= bi->end) numa_remove_memblk_from(i--, mi); - continue; - } + } + + /* merge neighboring / overlapping entries */ + for (i = 0; i < mi->nr_blks; i++) { + struct numa_memblk *bi = &mi->blk[i]; for (j = i + 1; j < mi->nr_blks; j++) { struct numa_memblk *bj = &mi->blk[j]; @@ -311,8 +315,8 @@ int __init numa_cleanup_meminfo(struct numa_meminfo *mi) */ if (bi->nid != bj->nid) continue; - start = max(min(bi->start, bj->start), low); - end = min(max(bi->end, bj->end), high); + start = min(bi->start, bj->start); + end = max(bi->end, bj->end); for (k = 0; k < mi->nr_blks; k++) { struct numa_memblk *bk = &mi->blk[k]; @@ -332,6 +336,7 @@ int __init numa_cleanup_meminfo(struct numa_meminfo *mi) } } + /* clear unused ones */ for (i = mi->nr_blks; i < ARRAY_SIZE(mi->blk); i++) { mi->blk[i].start = mi->blk[i].end = 0; mi->blk[i].nid = NUMA_NO_NODE; -- cgit v0.10.2 From 646032e3b05b32d3f20cb108a030593d9d792eb5 Mon Sep 17 00:00:00 2001 From: Lasse Collin Date: Sun, 1 May 2011 19:38:42 +0300 Subject: XZ decompressor: Fix decoding of empty LZMA2 streams The old code considered valid empty LZMA2 streams to be corrupt. Note that a typical empty .xz file has no LZMA2 data at all, and thus most .xz files having no uncompressed data are handled correctly even without this fix. Signed-off-by: Lasse Collin Signed-off-by: Linus Torvalds diff --git a/lib/xz/xz_dec_lzma2.c b/lib/xz/xz_dec_lzma2.c index ea5fa4f..a6cdc96 100644 --- a/lib/xz/xz_dec_lzma2.c +++ b/lib/xz/xz_dec_lzma2.c @@ -969,6 +969,9 @@ XZ_EXTERN enum xz_ret xz_dec_lzma2_run(struct xz_dec_lzma2 *s, */ tmp = b->in[b->in_pos++]; + if (tmp == 0x00) + return XZ_STREAM_END; + if (tmp >= 0xE0 || tmp == 0x01) { s->lzma2.need_props = true; s->lzma2.need_dict_reset = false; @@ -1001,9 +1004,6 @@ XZ_EXTERN enum xz_ret xz_dec_lzma2_run(struct xz_dec_lzma2 *s, lzma_reset(s); } } else { - if (tmp == 0x00) - return XZ_STREAM_END; - if (tmp > 0x02) return XZ_DATA_ERROR; -- cgit v0.10.2 From c42321c76b0ef472e3bae4bfcb0f46ab19e038ef Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Mon, 2 May 2011 18:16:22 +0200 Subject: genirq: Make generic irq chip depend on CONFIG_GENERIC_IRQ_CHIP Only compile it in when there are users. Signed-off-by: Thomas Gleixner Cc: linux-arm-kernel@lists.infradead.org diff --git a/kernel/irq/Kconfig b/kernel/irq/Kconfig index c574f9a..d1d051b3 100644 --- a/kernel/irq/Kconfig +++ b/kernel/irq/Kconfig @@ -48,6 +48,10 @@ config IRQ_PREFLOW_FASTEOI config IRQ_EDGE_EOI_HANDLER bool +# Generic configurable interrupt chip implementation +config GENERIC_IRQ_CHIP + bool + # Support forced irq threading config IRQ_FORCED_THREADING bool diff --git a/kernel/irq/Makefile b/kernel/irq/Makefile index e7a13bd..7329005 100644 --- a/kernel/irq/Makefile +++ b/kernel/irq/Makefile @@ -1,6 +1,6 @@ obj-y := irqdesc.o handle.o manage.o spurious.o resend.o chip.o dummychip.o devres.o -obj-y += generic-chip.o +obj-$(CONFIG_GENERIC_IRQ_CHIP) += generic-chip.o obj-$(CONFIG_GENERIC_IRQ_PROBE) += autoprobe.o obj-$(CONFIG_PROC_FS) += proc.o obj-$(CONFIG_GENERIC_PENDING_IRQ) += migration.o -- cgit v0.10.2 From b50b9f408502a2ea90459ae36ba8cdc9cc005cfe Mon Sep 17 00:00:00 2001 From: Artem Bityutskiy Date: Mon, 25 Apr 2011 18:17:09 +0300 Subject: UBIFS: do not free write-buffers when in R/O mode Currently UBIFS has a small optimization - it frees write-buffers when it is re-mounted from R/W mode to R/O mode. Of course, when it is mounted R/O, it does not allocate write-buffers as well. This optimization is nice but it leads to subtle problems and complications in recovery, which I can reproduce using the integck test. The symptoms are that after a power cut the file-system cannot be mounted if we first mount it R/O, and then re-mount R/W - 'ubifs_rcvry_gc_commit()' prints: UBIFS error (pid 34456): could not find an empty LEB Analysis of the problem. When mounting R/W, the reply process sets journal heads to buds [1], but when mounting R/O - it does not do this, because the write-buffers are not allocated. So 'ubifs_rcvry_gc_commit()' works completely differently for the same file-system but for the following 2 cases: 1. mounting R/W after a power cut and recover 2. mounting R/O after a power cut, re-mounting R/W and run deferred recovery In the former case, we have journal heads seeked to the a bud, in the latter case, they are non-seeked (wbuf->lnum == -1). So in the latter case we do not try to recover the GC LEB by garbage-collecting to the GC head, but we just try to find an empty LEB, and there may be no empty LEBs, so we just fail. On the other hand, in the former case (mount R/W), we are able to make a GC LEB (@c->gc_lnum) by garbage-collecting. Thus, let's remove this small nice optimization and always allocate write-buffers. This should not make too big difference - we have only 3 of them, each of max. write unit size, which is usually 2KiB. So this is about 6KiB of RAM for the typical case, and only when mounted R/O. [1]: Note, currently the replay process is setting (seeking) the journal heads to _some_ buds, not necessarily to the buds which had been the journal heads before the power cut happened. This will be fixed separately. Signed-off-by: Artem Bityutskiy Cc: stable@kernel.org diff --git a/fs/ubifs/log.c b/fs/ubifs/log.c index 4d0cb12..40fa780 100644 --- a/fs/ubifs/log.c +++ b/fs/ubifs/log.c @@ -175,26 +175,6 @@ void ubifs_add_bud(struct ubifs_info *c, struct ubifs_bud *bud) } /** - * ubifs_create_buds_lists - create journal head buds lists for remount rw. - * @c: UBIFS file-system description object - */ -void ubifs_create_buds_lists(struct ubifs_info *c) -{ - struct rb_node *p; - - spin_lock(&c->buds_lock); - p = rb_first(&c->buds); - while (p) { - struct ubifs_bud *bud = rb_entry(p, struct ubifs_bud, rb); - struct ubifs_jhead *jhead = &c->jheads[bud->jhead]; - - list_add_tail(&bud->list, &jhead->buds_list); - p = rb_next(p); - } - spin_unlock(&c->buds_lock); -} - -/** * ubifs_add_bud_to_log - add a new bud to the log. * @c: UBIFS file-system description object * @jhead: journal head the bud belongs to diff --git a/fs/ubifs/super.c b/fs/ubifs/super.c index be6c7b0..04ad07f 100644 --- a/fs/ubifs/super.c +++ b/fs/ubifs/super.c @@ -1257,12 +1257,12 @@ static int mount_ubifs(struct ubifs_info *c) goto out_free; } + err = alloc_wbufs(c); + if (err) + goto out_cbuf; + sprintf(c->bgt_name, BGT_NAME_PATTERN, c->vi.ubi_num, c->vi.vol_id); if (!c->ro_mount) { - err = alloc_wbufs(c); - if (err) - goto out_cbuf; - /* Create background thread */ c->bgt = kthread_create(ubifs_bg_thread, c, "%s", c->bgt_name); if (IS_ERR(c->bgt)) { @@ -1631,12 +1631,6 @@ static int ubifs_remount_rw(struct ubifs_info *c) if (err) goto out; - err = alloc_wbufs(c); - if (err) - goto out; - - ubifs_create_buds_lists(c); - /* Create background thread */ c->bgt = kthread_create(ubifs_bg_thread, c, "%s", c->bgt_name); if (IS_ERR(c->bgt)) { @@ -1744,7 +1738,6 @@ static void ubifs_remount_ro(struct ubifs_info *c) if (err) ubifs_ro_mode(c, err); - free_wbufs(c); vfree(c->orph_buf); c->orph_buf = NULL; kfree(c->write_reserve_buf); -- cgit v0.10.2 From 52c6e6f990669deac3f370f1603815adb55a1dbd Mon Sep 17 00:00:00 2001 From: Artem Bityutskiy Date: Mon, 25 Apr 2011 18:46:31 +0300 Subject: UBIFS: seek journal heads to the latest bud in replay This is the second fix of the following symptom: UBIFS error (pid 34456): could not find an empty LEB which sometimes happens after power cuts when we mount the file-system - UBIFS refuses it with the above error message which comes from the 'ubifs_rcvry_gc_commit()' function. I can reproduce this using the integck test with the UBIFS power cut emulation enabled. Analysis of the problem. Currently UBIFS replay seeks the journal heads to the last _replayed_ bud. But the buds are replayed out-of-order, so the replay basically seeks journal heads to the "random" bud belonging to this head, and not to the _last_ one. The result of this is that the GC head may be seeked to a full LEB with no free space, or very little free space. And 'ubifs_rcvry_gc_commit()' tries to find a fully or mostly dirty LEB to match the current GC head (because we need to garbage-collect that dirty LEB at one go, because we do not have @c->gc_lnum). So 'ubifs_find_dirty_leb()' fails and we fall back to finding an empty LEB and also fail. As a result - recovery fails and mounting fails. This patch teaches the replay to initialize the GC heads exactly to the latest buds, i.e. the buds which have the largest sequence number in corresponding log reference nodes. Signed-off-by: Artem Bityutskiy Cc: stable@kernel.org diff --git a/fs/ubifs/replay.c b/fs/ubifs/replay.c index eed0fcf..d3d6d36 100644 --- a/fs/ubifs/replay.c +++ b/fs/ubifs/replay.c @@ -59,6 +59,7 @@ enum { * @new_size: truncation new size * @free: amount of free space in a bud * @dirty: amount of dirty space in a bud from padding and deletion nodes + * @jhead: journal head number of the bud * * UBIFS journal replay must compare node sequence numbers, which means it must * build a tree of node information to insert into the TNC. @@ -80,6 +81,7 @@ struct replay_entry { struct { int free; int dirty; + int jhead; }; }; }; @@ -159,6 +161,11 @@ static int set_bud_lprops(struct ubifs_info *c, struct replay_entry *r) err = PTR_ERR(lp); goto out; } + + /* Make sure the journal head points to the latest bud */ + err = ubifs_wbuf_seek_nolock(&c->jheads[r->jhead].wbuf, r->lnum, + c->leb_size - r->free, UBI_SHORTTERM); + out: ubifs_release_lprops(c); return err; @@ -627,10 +634,6 @@ static int replay_bud(struct ubifs_info *c, int lnum, int offs, int jhead, ubifs_assert(sleb->endpt - offs >= used); ubifs_assert(sleb->endpt % c->min_io_size == 0); - if (sleb->endpt + c->min_io_size <= c->leb_size && !c->ro_mount) - err = ubifs_wbuf_seek_nolock(&c->jheads[jhead].wbuf, lnum, - sleb->endpt, UBI_SHORTTERM); - *dirty = sleb->endpt - offs - used; *free = c->leb_size - sleb->endpt; @@ -653,12 +656,14 @@ out_dump: * @sqnum: sequence number * @free: amount of free space in bud * @dirty: amount of dirty space from padding and deletion nodes + * @jhead: journal head number for the bud * * This function inserts a reference node to the replay tree and returns zero * in case of success or a negative error code in case of failure. */ static int insert_ref_node(struct ubifs_info *c, int lnum, int offs, - unsigned long long sqnum, int free, int dirty) + unsigned long long sqnum, int free, int dirty, + int jhead) { struct rb_node **p = &c->replay_tree.rb_node, *parent = NULL; struct replay_entry *r; @@ -688,6 +693,7 @@ static int insert_ref_node(struct ubifs_info *c, int lnum, int offs, r->flags = REPLAY_REF; r->free = free; r->dirty = dirty; + r->jhead = jhead; rb_link_node(&r->rb, parent, p); rb_insert_color(&r->rb, &c->replay_tree); @@ -712,7 +718,7 @@ static int replay_buds(struct ubifs_info *c) if (err) return err; err = insert_ref_node(c, b->bud->lnum, b->bud->start, b->sqnum, - free, dirty); + free, dirty, b->bud->jhead); if (err) return err; } -- cgit v0.10.2 From 0ca699552c441e2c4201a6f60eac98b8865c1743 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= Date: Wed, 27 Apr 2011 17:40:11 +0200 Subject: ssb: cc: prepare clockmode support for cores rev 10+ 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 diff --git a/drivers/ssb/driver_chipcommon.c b/drivers/ssb/driver_chipcommon.c index b4b3733..06d15b6 100644 --- a/drivers/ssb/driver_chipcommon.c +++ b/drivers/ssb/driver_chipcommon.c @@ -46,40 +46,66 @@ void ssb_chipco_set_clockmode(struct ssb_chipcommon *cc, if (!ccdev) return; bus = ccdev->bus; + + /* We support SLOW only on 6..9 */ + if (ccdev->id.revision >= 10 && mode == SSB_CLKMODE_SLOW) + mode = SSB_CLKMODE_DYNAMIC; + + if (cc->capabilities & SSB_CHIPCO_CAP_PMU) + return; /* PMU controls clockmode, separated function needed */ + SSB_WARN_ON(ccdev->id.revision >= 20); + /* chipcommon cores prior to rev6 don't support dynamic clock control */ if (ccdev->id.revision < 6) return; - /* chipcommon cores rev10 are a whole new ball game */ + + /* ChipCommon cores rev10+ need testing */ if (ccdev->id.revision >= 10) return; + if (!(cc->capabilities & SSB_CHIPCO_CAP_PCTL)) return; switch (mode) { - case SSB_CLKMODE_SLOW: + case SSB_CLKMODE_SLOW: /* For revs 6..9 only */ tmp = chipco_read32(cc, SSB_CHIPCO_SLOWCLKCTL); tmp |= SSB_CHIPCO_SLOWCLKCTL_FSLOW; chipco_write32(cc, SSB_CHIPCO_SLOWCLKCTL, tmp); break; case SSB_CLKMODE_FAST: - ssb_pci_xtal(bus, SSB_GPIO_XTAL, 1); /* Force crystal on */ - tmp = chipco_read32(cc, SSB_CHIPCO_SLOWCLKCTL); - tmp &= ~SSB_CHIPCO_SLOWCLKCTL_FSLOW; - tmp |= SSB_CHIPCO_SLOWCLKCTL_IPLL; - chipco_write32(cc, SSB_CHIPCO_SLOWCLKCTL, tmp); + if (ccdev->id.revision < 10) { + ssb_pci_xtal(bus, SSB_GPIO_XTAL, 1); /* Force crystal on */ + tmp = chipco_read32(cc, SSB_CHIPCO_SLOWCLKCTL); + tmp &= ~SSB_CHIPCO_SLOWCLKCTL_FSLOW; + tmp |= SSB_CHIPCO_SLOWCLKCTL_IPLL; + chipco_write32(cc, SSB_CHIPCO_SLOWCLKCTL, tmp); + } else { + chipco_write32(cc, SSB_CHIPCO_SYSCLKCTL, + (chipco_read32(cc, SSB_CHIPCO_SYSCLKCTL) | + SSB_CHIPCO_SYSCLKCTL_FORCEHT)); + /* udelay(150); TODO: not available in early init */ + } break; case SSB_CLKMODE_DYNAMIC: - tmp = chipco_read32(cc, SSB_CHIPCO_SLOWCLKCTL); - tmp &= ~SSB_CHIPCO_SLOWCLKCTL_FSLOW; - tmp &= ~SSB_CHIPCO_SLOWCLKCTL_IPLL; - tmp &= ~SSB_CHIPCO_SLOWCLKCTL_ENXTAL; - if ((tmp & SSB_CHIPCO_SLOWCLKCTL_SRC) != SSB_CHIPCO_SLOWCLKCTL_SRC_XTAL) - tmp |= SSB_CHIPCO_SLOWCLKCTL_ENXTAL; - chipco_write32(cc, SSB_CHIPCO_SLOWCLKCTL, tmp); - - /* for dynamic control, we have to release our xtal_pu "force on" */ - if (tmp & SSB_CHIPCO_SLOWCLKCTL_ENXTAL) - ssb_pci_xtal(bus, SSB_GPIO_XTAL, 0); + if (ccdev->id.revision < 10) { + tmp = chipco_read32(cc, SSB_CHIPCO_SLOWCLKCTL); + tmp &= ~SSB_CHIPCO_SLOWCLKCTL_FSLOW; + tmp &= ~SSB_CHIPCO_SLOWCLKCTL_IPLL; + tmp &= ~SSB_CHIPCO_SLOWCLKCTL_ENXTAL; + if ((tmp & SSB_CHIPCO_SLOWCLKCTL_SRC) != + SSB_CHIPCO_SLOWCLKCTL_SRC_XTAL) + tmp |= SSB_CHIPCO_SLOWCLKCTL_ENXTAL; + chipco_write32(cc, SSB_CHIPCO_SLOWCLKCTL, tmp); + + /* For dynamic control, we have to release our xtal_pu + * "force on" */ + if (tmp & SSB_CHIPCO_SLOWCLKCTL_ENXTAL) + ssb_pci_xtal(bus, SSB_GPIO_XTAL, 0); + } else { + chipco_write32(cc, SSB_CHIPCO_SYSCLKCTL, + (chipco_read32(cc, SSB_CHIPCO_SYSCLKCTL) & + ~SSB_CHIPCO_SYSCLKCTL_FORCEHT)); + } break; default: SSB_WARN_ON(1); -- cgit v0.10.2 From 816c04fe7ef01dd9649f5ccfe796474db8708be5 Mon Sep 17 00:00:00 2001 From: Christian Lamparter Date: Sat, 30 Apr 2011 15:24:30 +0200 Subject: mac80211: consolidate MIC failure report handling Currently, mac80211 handles MIC failures differently depending on whenever they are detected by the stack's own software crypto or when are handed down from the driver. This patch tries to unify both by moving the special branch out of mac80211 rx hotpath and into into the software crypto part. This has the advantage that we can run a few more sanity checks on the data and verify if the key type was TKIP. This is very handy because several devices generate false postive MIC failure reports. Like carl9170, ath9k and wl12xx: "mac80211: report MIC failure for truncated packets in AP mode" Cc: Luciano Coelho Cc: Arik Nemtsov Signed-off-by: Christian Lamparter Signed-off-by: John W. Linville diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index b04a437..81241e1 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -2368,47 +2368,6 @@ ieee80211_rx_h_mgmt(struct ieee80211_rx_data *rx) return RX_QUEUED; } -static void ieee80211_rx_michael_mic_report(struct ieee80211_hdr *hdr, - struct ieee80211_rx_data *rx) -{ - int keyidx; - unsigned int hdrlen; - - hdrlen = ieee80211_hdrlen(hdr->frame_control); - if (rx->skb->len >= hdrlen + 4) - keyidx = rx->skb->data[hdrlen + 3] >> 6; - else - keyidx = -1; - - if (!rx->sta) { - /* - * Some hardware seem to generate incorrect Michael MIC - * reports; ignore them to avoid triggering countermeasures. - */ - return; - } - - if (!ieee80211_has_protected(hdr->frame_control)) - return; - - if (rx->sdata->vif.type == NL80211_IFTYPE_AP && keyidx) { - /* - * APs with pairwise keys should never receive Michael MIC - * errors for non-zero keyidx because these are reserved for - * group keys and only the AP is sending real multicast - * frames in the BSS. - */ - return; - } - - if (!ieee80211_is_data(hdr->frame_control) && - !ieee80211_is_auth(hdr->frame_control)) - return; - - mac80211_ev_michael_mic_failure(rx->sdata, keyidx, hdr, NULL, - GFP_ATOMIC); -} - /* TODO: use IEEE80211_RX_FRAGMENTED */ static void ieee80211_rx_cooked_monitor(struct ieee80211_rx_data *rx, struct ieee80211_rate *rate) @@ -2752,12 +2711,6 @@ static bool ieee80211_prepare_and_rx_handle(struct ieee80211_rx_data *rx, if (!prepares) return false; - if (status->flag & RX_FLAG_MMIC_ERROR) { - if (status->rx_flags & IEEE80211_RX_RA_MATCH) - ieee80211_rx_michael_mic_report(hdr, rx); - return false; - } - if (!consume) { skb = skb_copy(skb, GFP_ATOMIC); if (!skb) { diff --git a/net/mac80211/wpa.c b/net/mac80211/wpa.c index f1765de..9dc3b5f 100644 --- a/net/mac80211/wpa.c +++ b/net/mac80211/wpa.c @@ -87,42 +87,76 @@ ieee80211_rx_h_michael_mic_verify(struct ieee80211_rx_data *rx) struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb); struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; - /* No way to verify the MIC if the hardware stripped it */ - if (status->flag & RX_FLAG_MMIC_STRIPPED) + /* + * it makes no sense to check for MIC errors on anything other + * than data frames. + */ + if (!ieee80211_is_data_present(hdr->frame_control)) + return RX_CONTINUE; + + /* + * No way to verify the MIC if the hardware stripped it or + * the IV with the key index. In this case we have solely rely + * on the driver to set RX_FLAG_MMIC_ERROR in the event of a + * MIC failure report. + */ + if (status->flag & (RX_FLAG_MMIC_STRIPPED | RX_FLAG_IV_STRIPPED)) { + if (status->flag & RX_FLAG_MMIC_ERROR) + goto mic_fail; + + if (!(status->flag & RX_FLAG_IV_STRIPPED)) + goto update_iv; + return RX_CONTINUE; + } + /* + * Some hardware seems to generate Michael MIC failure reports; even + * though, the frame was not encrypted with TKIP and therefore has no + * MIC. Ignore the flag them to avoid triggering countermeasures. + */ if (!rx->key || rx->key->conf.cipher != WLAN_CIPHER_SUITE_TKIP || - !ieee80211_has_protected(hdr->frame_control) || - !ieee80211_is_data_present(hdr->frame_control)) + !(status->flag & RX_FLAG_DECRYPTED)) return RX_CONTINUE; + if (rx->sdata->vif.type == NL80211_IFTYPE_AP && rx->key->conf.keyidx) { + /* + * APs with pairwise keys should never receive Michael MIC + * errors for non-zero keyidx because these are reserved for + * group keys and only the AP is sending real multicast + * frames in the BSS. ( + */ + return RX_DROP_UNUSABLE; + } + + if (status->flag & RX_FLAG_MMIC_ERROR) + goto mic_fail; + hdrlen = ieee80211_hdrlen(hdr->frame_control); if (skb->len < hdrlen + MICHAEL_MIC_LEN) return RX_DROP_UNUSABLE; data = skb->data + hdrlen; data_len = skb->len - hdrlen - MICHAEL_MIC_LEN; - key = &rx->key->conf.key[NL80211_TKIP_DATA_OFFSET_RX_MIC_KEY]; michael_mic(key, hdr, data, data_len, mic); - if (memcmp(mic, data + data_len, MICHAEL_MIC_LEN) != 0) { - if (!(status->rx_flags & IEEE80211_RX_RA_MATCH)) - return RX_DROP_UNUSABLE; - - mac80211_ev_michael_mic_failure(rx->sdata, rx->key->conf.keyidx, - (void *) skb->data, NULL, - GFP_ATOMIC); - return RX_DROP_UNUSABLE; - } + if (memcmp(mic, data + data_len, MICHAEL_MIC_LEN) != 0) + goto mic_fail; /* remove Michael MIC from payload */ skb_trim(skb, skb->len - MICHAEL_MIC_LEN); +update_iv: /* update IV in key information to be able to detect replays */ rx->key->u.tkip.rx[rx->queue].iv32 = rx->tkip_iv32; rx->key->u.tkip.rx[rx->queue].iv16 = rx->tkip_iv16; return RX_CONTINUE; + +mic_fail: + mac80211_ev_michael_mic_failure(rx->sdata, rx->key->conf.keyidx, + (void *) skb->data, NULL, GFP_ATOMIC); + return RX_DROP_UNUSABLE; } -- cgit v0.10.2 From 16763478892c271293d02872475a67a648ae12fc Mon Sep 17 00:00:00 2001 From: Ivo van Doorn Date: Sat, 30 Apr 2011 17:13:46 +0200 Subject: rt2x00: Reduce tx status reading timeout When no TX status was available, the default timeout of 20ms is a bit high. The frame is highly likely already send out, so the TX status should be available within only a few milliseconds. Signed-off-by: Ivo van Doorn Acked-by: Gertjan van Wingerde Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/rt2x00/rt2800usb.c b/drivers/net/wireless/rt2x00/rt2800usb.c index 0d4e8fa..e4f82d2 100644 --- a/drivers/net/wireless/rt2x00/rt2800usb.c +++ b/drivers/net/wireless/rt2x00/rt2800usb.c @@ -134,7 +134,7 @@ static void rt2800usb_tx_sta_fifo_read_completed(struct rt2x00_dev *rt2x00dev, } else if (!kfifo_is_empty(&rt2x00dev->txstatus_fifo)) { queue_work(rt2x00dev->workqueue, &rt2x00dev->txdone_work); } else if (rt2800usb_txstatus_pending(rt2x00dev)) { - mod_timer(&rt2x00dev->txstatus_timer, jiffies + msecs_to_jiffies(20)); + mod_timer(&rt2x00dev->txstatus_timer, jiffies + msecs_to_jiffies(2)); } } @@ -493,7 +493,7 @@ static void rt2800usb_work_txdone(struct work_struct *work) * also delayed -> use a timer to retrieve it. */ if (rt2800usb_txstatus_pending(rt2x00dev)) - mod_timer(&rt2x00dev->txstatus_timer, jiffies + msecs_to_jiffies(20)); + mod_timer(&rt2x00dev->txstatus_timer, jiffies + msecs_to_jiffies(2)); } /* -- cgit v0.10.2 From a073fdef46d50440ee573452a436023dcf4f9edf Mon Sep 17 00:00:00 2001 From: Ivo van Doorn Date: Sat, 30 Apr 2011 17:14:23 +0200 Subject: rt2x00: Optimize TX_STA_FIFO register reading Add recycling functionality to rt2x00usb_register_read_async. When the callback function returns true, resubmit the urb to read the register again. This optimizes the rt2800usb driver when multiple TX status reports are pending in the register, because now we don't need to allocate the rt2x00_async_read_data and urb structure each time. Signed-off-by: Ivo van Doorn Acked-by: Gertjan van Wingerde Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/rt2x00/rt2800usb.c b/drivers/net/wireless/rt2x00/rt2800usb.c index e4f82d2..b5d5f22 100644 --- a/drivers/net/wireless/rt2x00/rt2800usb.c +++ b/drivers/net/wireless/rt2x00/rt2800usb.c @@ -114,12 +114,12 @@ static bool rt2800usb_txstatus_pending(struct rt2x00_dev *rt2x00dev) return false; } -static void rt2800usb_tx_sta_fifo_read_completed(struct rt2x00_dev *rt2x00dev, +static bool rt2800usb_tx_sta_fifo_read_completed(struct rt2x00_dev *rt2x00dev, int urb_status, u32 tx_status) { if (urb_status) { WARNING(rt2x00dev, "rt2x00usb_register_read_async failed: %d\n", urb_status); - return; + return false; } /* try to read all TX_STA_FIFO entries before scheduling txdone_work */ @@ -129,13 +129,14 @@ static void rt2800usb_tx_sta_fifo_read_completed(struct rt2x00_dev *rt2x00dev, "drop tx status report.\n"); queue_work(rt2x00dev->workqueue, &rt2x00dev->txdone_work); } else - rt2x00usb_register_read_async(rt2x00dev, TX_STA_FIFO, - rt2800usb_tx_sta_fifo_read_completed); + return true; } else if (!kfifo_is_empty(&rt2x00dev->txstatus_fifo)) { queue_work(rt2x00dev->workqueue, &rt2x00dev->txdone_work); } else if (rt2800usb_txstatus_pending(rt2x00dev)) { mod_timer(&rt2x00dev->txstatus_timer, jiffies + msecs_to_jiffies(2)); } + + return false; } static void rt2800usb_tx_dma_done(struct queue_entry *entry) diff --git a/drivers/net/wireless/rt2x00/rt2x00usb.c b/drivers/net/wireless/rt2x00/rt2x00usb.c index 570184e..e027ebd 100644 --- a/drivers/net/wireless/rt2x00/rt2x00usb.c +++ b/drivers/net/wireless/rt2x00/rt2x00usb.c @@ -170,19 +170,22 @@ struct rt2x00_async_read_data { __le32 reg; struct usb_ctrlrequest cr; struct rt2x00_dev *rt2x00dev; - void (*callback)(struct rt2x00_dev *,int,u32); + bool (*callback)(struct rt2x00_dev *, int, u32); }; static void rt2x00usb_register_read_async_cb(struct urb *urb) { struct rt2x00_async_read_data *rd = urb->context; - rd->callback(rd->rt2x00dev, urb->status, le32_to_cpu(rd->reg)); - kfree(urb->context); + if (rd->callback(rd->rt2x00dev, urb->status, le32_to_cpu(rd->reg))) { + if (usb_submit_urb(urb, GFP_ATOMIC) < 0) + kfree(rd); + } else + kfree(rd); } void rt2x00usb_register_read_async(struct rt2x00_dev *rt2x00dev, const unsigned int offset, - void (*callback)(struct rt2x00_dev*,int,u32)) + bool (*callback)(struct rt2x00_dev*, int, u32)) { struct usb_device *usb_dev = to_usb_device_intf(rt2x00dev->dev); struct urb *urb; diff --git a/drivers/net/wireless/rt2x00/rt2x00usb.h b/drivers/net/wireless/rt2x00/rt2x00usb.h index 52b09d2..a69f187 100644 --- a/drivers/net/wireless/rt2x00/rt2x00usb.h +++ b/drivers/net/wireless/rt2x00/rt2x00usb.h @@ -349,10 +349,12 @@ int rt2x00usb_regbusy_read(struct rt2x00_dev *rt2x00dev, * be called from atomic context. The callback will be called * when the URB completes. Otherwise the function is similar * to rt2x00usb_register_read(). + * When the callback function returns false, the memory will be cleaned up, + * when it returns true, the urb will be fired again. */ void rt2x00usb_register_read_async(struct rt2x00_dev *rt2x00dev, const unsigned int offset, - void (*callback)(struct rt2x00_dev*,int,u32)); + bool (*callback)(struct rt2x00_dev*, int, u32)); /* * Radio handlers -- cgit v0.10.2 From d4c838ef5e5c2c7e205adf9e011d2e8bd6eae738 Mon Sep 17 00:00:00 2001 From: Ivo van Doorn Date: Sat, 30 Apr 2011 17:14:49 +0200 Subject: rt2x00: Fix optimize register access for rt2800pci The patch rt2x00: Optimize register access in rt2800pci from Helmut Schaa missed one register call, namely the rt2800_register_multiwrite which should be changed to rt2x00pci_register_multiwrite. Signed-off-by: Ivo van Doorn Acked-by: Helmut Schaa Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/rt2x00/rt2800pci.c b/drivers/net/wireless/rt2x00/rt2800pci.c index 08d3947..cc4a54f 100644 --- a/drivers/net/wireless/rt2x00/rt2800pci.c +++ b/drivers/net/wireless/rt2x00/rt2800pci.c @@ -302,8 +302,8 @@ static int rt2800pci_write_firmware(struct rt2x00_dev *rt2x00dev, /* * Write firmware to device. */ - rt2800_register_multiwrite(rt2x00dev, FIRMWARE_IMAGE_BASE, - data, len); + rt2x00pci_register_multiwrite(rt2x00dev, FIRMWARE_IMAGE_BASE, + data, len); rt2x00pci_register_write(rt2x00dev, PBF_SYS_CTRL, 0x00000); rt2x00pci_register_write(rt2x00dev, PBF_SYS_CTRL, 0x00001); -- cgit v0.10.2 From 9328fdac499b969ec57a195845f168e7c5168ccd Mon Sep 17 00:00:00 2001 From: Gertjan van Wingerde Date: Sat, 30 Apr 2011 17:15:13 +0200 Subject: rt2x00: Streamline rt2800 eeprom initialisations. In rt2800lib.c the rt2800_init_eeprom function the same eeprom words were read multiple times, due to inefficient ordering of the eeprom checks. Reorder the checks so that each EEPROM word only has to be read once. Signed-off-by: Gertjan van Wingerde Signed-off-by: Ivo van Doorn Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/rt2x00/rt2800lib.c b/drivers/net/wireless/rt2x00/rt2800lib.c index d79c8fd..71c16c6 100644 --- a/drivers/net/wireless/rt2x00/rt2800lib.c +++ b/drivers/net/wireless/rt2x00/rt2800lib.c @@ -3727,16 +3727,8 @@ int rt2800_init_eeprom(struct rt2x00_dev *rt2x00dev) } /* - * Read frequency offset and RF programming sequence. + * Determine external LNA informations. */ - rt2x00_eeprom_read(rt2x00dev, EEPROM_FREQ, &eeprom); - rt2x00dev->freq_offset = rt2x00_get_field16(eeprom, EEPROM_FREQ_OFFSET); - - /* - * Read external LNA informations. - */ - rt2x00_eeprom_read(rt2x00dev, EEPROM_NIC_CONF1, &eeprom); - if (rt2x00_get_field16(eeprom, EEPROM_NIC_CONF1_EXTERNAL_LNA_5G)) __set_bit(CAPABILITY_EXTERNAL_LNA_A, &rt2x00dev->cap_flags); if (rt2x00_get_field16(eeprom, EEPROM_NIC_CONF1_EXTERNAL_LNA_2G)) @@ -3749,6 +3741,12 @@ int rt2800_init_eeprom(struct rt2x00_dev *rt2x00dev) __set_bit(CAPABILITY_HW_BUTTON, &rt2x00dev->cap_flags); /* + * Read frequency offset and RF programming sequence. + */ + rt2x00_eeprom_read(rt2x00dev, EEPROM_FREQ, &eeprom); + rt2x00dev->freq_offset = rt2x00_get_field16(eeprom, EEPROM_FREQ_OFFSET); + + /* * Store led settings, for correct led behaviour. */ #ifdef CONFIG_RT2X00_LIB_LEDS @@ -3756,7 +3754,7 @@ int rt2800_init_eeprom(struct rt2x00_dev *rt2x00dev) rt2800_init_led(rt2x00dev, &rt2x00dev->led_assoc, LED_TYPE_ASSOC); rt2800_init_led(rt2x00dev, &rt2x00dev->led_qual, LED_TYPE_QUALITY); - rt2x00_eeprom_read(rt2x00dev, EEPROM_FREQ, &rt2x00dev->led_mcu_reg); + rt2x00dev->led_mcu_reg = eeprom; #endif /* CONFIG_RT2X00_LIB_LEDS */ /* -- cgit v0.10.2 From fdbc7b0a262e24a3ee00f1f9acb5a97309a173d5 Mon Sep 17 00:00:00 2001 From: Gertjan van Wingerde Date: Sat, 30 Apr 2011 17:15:37 +0200 Subject: rt2x00: Introduce capability flag for Bluetooth co-existence. Use flag instead of re-reading the eeprom every time. Signed-off-by: Gertjan van Wingerde Signed-off-by: Ivo van Doorn Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/rt2x00/rt2800lib.c b/drivers/net/wireless/rt2x00/rt2800lib.c index 71c16c6..6ed646a 100644 --- a/drivers/net/wireless/rt2x00/rt2800lib.c +++ b/drivers/net/wireless/rt2x00/rt2800lib.c @@ -1640,7 +1640,6 @@ static void rt2800_config_channel_rf53xx(struct rt2x00_dev *rt2x00dev, struct channel_info *info) { u8 rfcsr; - u16 eeprom; rt2800_rfcsr_write(rt2x00dev, 8, rf->rf1); rt2800_rfcsr_write(rt2x00dev, 9, rf->rf3); @@ -1670,11 +1669,10 @@ static void rt2800_config_channel_rf53xx(struct rt2x00_dev *rt2x00dev, rt2x00_set_field8(&rfcsr, RFCSR17_CODE, rt2x00dev->freq_offset); rt2800_rfcsr_write(rt2x00dev, 17, rfcsr); - rt2x00_eeprom_read(rt2x00dev, EEPROM_NIC_CONF1, &eeprom); if (rf->channel <= 14) { int idx = rf->channel-1; - if (rt2x00_get_field16(eeprom, EEPROM_NIC_CONF1_BT_COEXIST)) { + if (test_bit(CAPABILITY_BT_COEXIST, &rt2x00dev->cap_flags)) { if (rt2x00_rt_rev_gte(rt2x00dev, RT5390, REV_RT5390F)) { /* r55/r59 value array of channel 1~14 */ static const char r55_bt_rev[] = {0x83, 0x83, @@ -2917,8 +2915,7 @@ static int rt2800_init_bbp(struct rt2x00_dev *rt2x00dev) ant = (div_mode == 3) ? 1 : 0; /* check if this is a Bluetooth combo card */ - rt2x00_eeprom_read(rt2x00dev, EEPROM_NIC_CONF1, &eeprom); - if (rt2x00_get_field16(eeprom, EEPROM_NIC_CONF1_BT_COEXIST)) { + if (test_bit(CAPABILITY_BT_COEXIST, &rt2x00dev->cap_flags)) { u32 reg; rt2800_register_read(rt2x00dev, GPIO_CTRL_CFG, ®); @@ -3741,6 +3738,12 @@ int rt2800_init_eeprom(struct rt2x00_dev *rt2x00dev) __set_bit(CAPABILITY_HW_BUTTON, &rt2x00dev->cap_flags); /* + * Detect if this device has Bluetooth co-existence. + */ + if (rt2x00_get_field16(eeprom, EEPROM_NIC_CONF1_BT_COEXIST)) + __set_bit(CAPABILITY_BT_COEXIST, &rt2x00dev->cap_flags); + + /* * Read frequency offset and RF programming sequence. */ rt2x00_eeprom_read(rt2x00dev, EEPROM_FREQ, &eeprom); diff --git a/drivers/net/wireless/rt2x00/rt2x00.h b/drivers/net/wireless/rt2x00/rt2x00.h index acf561f..86e1410 100644 --- a/drivers/net/wireless/rt2x00/rt2x00.h +++ b/drivers/net/wireless/rt2x00/rt2x00.h @@ -697,6 +697,7 @@ enum rt2x00_capability_flags { CAPABILITY_EXTERNAL_LNA_A, CAPABILITY_EXTERNAL_LNA_BG, CAPABILITY_DOUBLE_ANTENNA, + CAPABILITY_BT_COEXIST, }; /* -- cgit v0.10.2 From 1c0bcf89d85cc97a0d9ce4cd909351a81fa4fdde Mon Sep 17 00:00:00 2001 From: Ivo van Doorn Date: Sat, 30 Apr 2011 17:18:18 +0200 Subject: rt2x00: Add autowake support for USB hardware The USB drivers don't support automatically waking up when in powersaving mode, add a work object which will wakeup the device in time to receive the next beacon. Based on that beacon, we either go back into powersaving mode, or we remain awake to receive the buffered frames for our station. Some part of the code, especially rt2x00lib_find_ie and rt2x00lib_rxdone_check_ps are inspired on the code from carl9170. Signed-off-by: Ivo van Doorn Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/rt2x00/rt2500usb.c b/drivers/net/wireless/rt2x00/rt2500usb.c index b21f8123..15237c2 100644 --- a/drivers/net/wireless/rt2x00/rt2500usb.c +++ b/drivers/net/wireless/rt2x00/rt2500usb.c @@ -1797,6 +1797,7 @@ static int rt2500usb_probe_hw(struct rt2x00_dev *rt2x00dev) __set_bit(REQUIRE_COPY_IV, &rt2x00dev->cap_flags); } __set_bit(REQUIRE_SW_SEQNO, &rt2x00dev->cap_flags); + __set_bit(REQUIRE_PS_AUTOWAKE, &rt2x00dev->cap_flags); /* * Set the rssi offset. diff --git a/drivers/net/wireless/rt2x00/rt2800usb.c b/drivers/net/wireless/rt2x00/rt2800usb.c index b5d5f22..0eb44cf 100644 --- a/drivers/net/wireless/rt2x00/rt2800usb.c +++ b/drivers/net/wireless/rt2x00/rt2800usb.c @@ -634,6 +634,7 @@ static int rt2800usb_probe_hw(struct rt2x00_dev *rt2x00dev) __set_bit(CAPABILITY_LINK_TUNING, &rt2x00dev->cap_flags); __set_bit(REQUIRE_HT_TX_DESC, &rt2x00dev->cap_flags); __set_bit(REQUIRE_TXSTATUS_FIFO, &rt2x00dev->cap_flags); + __set_bit(REQUIRE_PS_AUTOWAKE, &rt2x00dev->cap_flags); setup_timer(&rt2x00dev->txstatus_timer, rt2800usb_tx_sta_fifo_timeout, diff --git a/drivers/net/wireless/rt2x00/rt2x00.h b/drivers/net/wireless/rt2x00/rt2x00.h index 86e1410..73d3332 100644 --- a/drivers/net/wireless/rt2x00/rt2x00.h +++ b/drivers/net/wireless/rt2x00/rt2x00.h @@ -662,6 +662,7 @@ enum rt2x00_state_flags { * Driver configuration */ CONFIG_CHANNEL_HT40, + CONFIG_POWERSAVING, }; /* @@ -681,6 +682,7 @@ enum rt2x00_capability_flags { REQUIRE_TASKLET_CONTEXT, REQUIRE_SW_SEQNO, REQUIRE_HT_TX_DESC, + REQUIRE_PS_AUTOWAKE, /* * Capabilities @@ -875,10 +877,20 @@ struct rt2x00_dev { u8 calibration[2]; /* + * Association id. + */ + u16 aid; + + /* * Beacon interval. */ u16 beacon_int; + /** + * Timestamp of last received beacon + */ + unsigned long last_beacon; + /* * Low level statistics which will have * to be kept up to date while device is running. @@ -907,6 +919,11 @@ struct rt2x00_dev { struct work_struct txdone_work; /* + * Powersaving work + */ + struct delayed_work autowakeup_work; + + /* * Data queue arrays for RX, TX, Beacon and ATIM. */ unsigned int data_queues; diff --git a/drivers/net/wireless/rt2x00/rt2x00config.c b/drivers/net/wireless/rt2x00/rt2x00config.c index 2a313b6..edebbf0 100644 --- a/drivers/net/wireless/rt2x00/rt2x00config.c +++ b/drivers/net/wireless/rt2x00/rt2x00config.c @@ -100,6 +100,10 @@ void rt2x00lib_config_erp(struct rt2x00_dev *rt2x00dev, erp.basic_rates = bss_conf->basic_rates; erp.beacon_int = bss_conf->beacon_int; + /* Update the AID, this is needed for dynamic PS support */ + rt2x00dev->aid = bss_conf->assoc ? bss_conf->aid : 0; + rt2x00dev->last_beacon = bss_conf->timestamp; + /* Update global beacon interval time, this is needed for PS support */ rt2x00dev->beacon_int = bss_conf->beacon_int; @@ -204,6 +208,9 @@ void rt2x00lib_config(struct rt2x00_dev *rt2x00dev, { struct rt2x00lib_conf libconf; u16 hw_value; + u16 autowake_timeout; + u16 beacon_int; + u16 beacon_diff; memset(&libconf, 0, sizeof(libconf)); @@ -227,6 +234,10 @@ void rt2x00lib_config(struct rt2x00_dev *rt2x00dev, sizeof(libconf.channel)); } + if (test_bit(REQUIRE_PS_AUTOWAKE, &rt2x00dev->cap_flags) && + (ieee80211_flags & IEEE80211_CONF_CHANGE_PS)) + cancel_delayed_work_sync(&rt2x00dev->autowakeup_work); + /* * Start configuration. */ @@ -239,6 +250,26 @@ void rt2x00lib_config(struct rt2x00_dev *rt2x00dev, if (ieee80211_flags & IEEE80211_CONF_CHANGE_CHANNEL) rt2x00link_reset_tuner(rt2x00dev, false); + if (test_bit(REQUIRE_PS_AUTOWAKE, &rt2x00dev->cap_flags) && + (ieee80211_flags & IEEE80211_CONF_CHANGE_PS) && + (conf->flags & IEEE80211_CONF_PS)) { + beacon_diff = (long)jiffies - (long)rt2x00dev->last_beacon; + beacon_int = msecs_to_jiffies(rt2x00dev->beacon_int); + + if (beacon_diff > beacon_int) + beacon_diff = 0; + + autowake_timeout = (conf->max_sleep_period * beacon_int) - beacon_diff; + queue_delayed_work(rt2x00dev->workqueue, + &rt2x00dev->autowakeup_work, + autowake_timeout - 15); + } + + if (conf->flags & IEEE80211_CONF_PS) + set_bit(CONFIG_POWERSAVING, &rt2x00dev->flags); + else + clear_bit(CONFIG_POWERSAVING, &rt2x00dev->flags); + rt2x00dev->curr_band = conf->channel->band; rt2x00dev->curr_freq = conf->channel->center_freq; rt2x00dev->tx_power = conf->power_level; diff --git a/drivers/net/wireless/rt2x00/rt2x00dev.c b/drivers/net/wireless/rt2x00/rt2x00dev.c index 7776d9f..2eb5196 100644 --- a/drivers/net/wireless/rt2x00/rt2x00dev.c +++ b/drivers/net/wireless/rt2x00/rt2x00dev.c @@ -141,6 +141,16 @@ static void rt2x00lib_intf_scheduled(struct work_struct *work) rt2x00dev); } +static void rt2x00lib_autowakeup(struct work_struct *work) +{ + struct rt2x00_dev *rt2x00dev = + container_of(work, struct rt2x00_dev, autowakeup_work.work); + + if (rt2x00dev->ops->lib->set_device_state(rt2x00dev, STATE_AWAKE)) + ERROR(rt2x00dev, "Device failed to wakeup.\n"); + clear_bit(CONFIG_POWERSAVING, &rt2x00dev->flags); +} + /* * Interrupt context handlers. */ @@ -416,6 +426,77 @@ void rt2x00lib_txdone_noinfo(struct queue_entry *entry, u32 status) } EXPORT_SYMBOL_GPL(rt2x00lib_txdone_noinfo); +static u8 *rt2x00lib_find_ie(u8 *data, unsigned int len, u8 ie) +{ + struct ieee80211_mgmt *mgmt = (void *)data; + u8 *pos, *end; + + pos = (u8 *)mgmt->u.beacon.variable; + end = data + len; + while (pos < end) { + if (pos + 2 + pos[1] > end) + return NULL; + + if (pos[0] == ie) + return pos; + + pos += 2 + pos[1]; + } + + return NULL; +} + +static void rt2x00lib_rxdone_check_ps(struct rt2x00_dev *rt2x00dev, + struct sk_buff *skb, + struct rxdone_entry_desc *rxdesc) +{ + struct ieee80211_hdr *hdr = (void *) skb->data; + struct ieee80211_tim_ie *tim_ie; + u8 *tim; + u8 tim_len; + bool cam; + + /* If this is not a beacon, or if mac80211 has no powersaving + * configured, or if the device is already in powersaving mode + * we can exit now. */ + if (likely(!ieee80211_is_beacon(hdr->frame_control) || + !(rt2x00dev->hw->conf.flags & IEEE80211_CONF_PS))) + return; + + /* min. beacon length + FCS_LEN */ + if (skb->len <= 40 + FCS_LEN) + return; + + /* and only beacons from the associated BSSID, please */ + if (!(rxdesc->dev_flags & RXDONE_MY_BSS) || + !rt2x00dev->aid) + return; + + rt2x00dev->last_beacon = jiffies; + + tim = rt2x00lib_find_ie(skb->data, skb->len - FCS_LEN, WLAN_EID_TIM); + if (!tim) + return; + + if (tim[1] < sizeof(*tim_ie)) + return; + + tim_len = tim[1]; + tim_ie = (struct ieee80211_tim_ie *) &tim[2]; + + /* Check whenever the PHY can be turned off again. */ + + /* 1. What about buffered unicast traffic for our AID? */ + cam = ieee80211_check_tim(tim_ie, tim_len, rt2x00dev->aid); + + /* 2. Maybe the AP wants to send multicast/broadcast data? */ + cam |= (tim_ie->bitmap_ctrl & 0x01); + + if (!cam && !test_bit(CONFIG_POWERSAVING, &rt2x00dev->flags)) + rt2x00lib_config(rt2x00dev, &rt2x00dev->hw->conf, + IEEE80211_CONF_CHANGE_PS); +} + static int rt2x00lib_rxdone_read_signal(struct rt2x00_dev *rt2x00dev, struct rxdone_entry_desc *rxdesc) { @@ -531,6 +612,12 @@ void rt2x00lib_rxdone(struct queue_entry *entry) rxdesc.flags |= RX_FLAG_HT; /* + * Check if this is a beacon, and more frames have been + * buffered while we were in powersaving mode. + */ + rt2x00lib_rxdone_check_ps(rt2x00dev, entry->skb, &rxdesc); + + /* * Update extra components */ rt2x00link_update_stats(rt2x00dev, entry->skb, &rxdesc); @@ -1017,6 +1104,7 @@ int rt2x00lib_probe_dev(struct rt2x00_dev *rt2x00dev) } INIT_WORK(&rt2x00dev->intf_work, rt2x00lib_intf_scheduled); + INIT_DELAYED_WORK(&rt2x00dev->autowakeup_work, rt2x00lib_autowakeup); /* * Let the driver probe the device to detect the capabilities. diff --git a/drivers/net/wireless/rt2x00/rt73usb.c b/drivers/net/wireless/rt2x00/rt73usb.c index a6ce7d6..ad20953 100644 --- a/drivers/net/wireless/rt2x00/rt73usb.c +++ b/drivers/net/wireless/rt2x00/rt73usb.c @@ -2209,6 +2209,7 @@ static int rt73usb_probe_hw(struct rt2x00_dev *rt2x00dev) if (!modparam_nohwcrypt) __set_bit(CAPABILITY_HW_CRYPTO, &rt2x00dev->cap_flags); __set_bit(CAPABILITY_LINK_TUNING, &rt2x00dev->cap_flags); + __set_bit(REQUIRE_PS_AUTOWAKE, &rt2x00dev->cap_flags); /* * Set the rssi offset. -- cgit v0.10.2 From 982d96bbb7f084644ee10214812ab167e52c2c5d Mon Sep 17 00:00:00 2001 From: Larry Finger Date: Sun, 1 May 2011 22:30:54 -0500 Subject: rtlwifi: Fix typo in pci.c Signed-off-by: Larry Finger Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/rtlwifi/pci.c b/drivers/net/wireless/rtlwifi/pci.c index 367d9b4..3550c9f 100644 --- a/drivers/net/wireless/rtlwifi/pci.c +++ b/drivers/net/wireless/rtlwifi/pci.c @@ -1069,7 +1069,7 @@ static int _rtl_pci_init_tx_ring(struct ieee80211_hw *hw, for (i = 0; i < entries; i++) { nextdescaddress = (u32) dma + - ((i + 11) % entries) * + ((i + 1) % entries) * sizeof(*ring); rtlpriv->cfg->ops->set_desc((u8 *)&(ring[i]), -- cgit v0.10.2 From 1a5b306f5d7398c7ffb0f69fe9a2d0023f28deb9 Mon Sep 17 00:00:00 2001 From: Bing Zhao Date: Mon, 2 May 2011 11:00:45 -0700 Subject: mwifiex: fix missing tsf_val TLV In mwifiex_cmd_append_tsf_tlv(), two tsf_val TLVs should be filled in the buffer and then sent to firmware. The missing first TLV for tsf_val is added back in this patch. Signed-off-by: Bing Zhao Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/mwifiex/join.c b/drivers/net/wireless/mwifiex/join.c index 042eb77..85fca5e 100644 --- a/drivers/net/wireless/mwifiex/join.c +++ b/drivers/net/wireless/mwifiex/join.c @@ -100,7 +100,7 @@ mwifiex_cmd_append_tsf_tlv(struct mwifiex_private *priv, u8 **buffer, struct mwifiex_bssdescriptor *bss_desc) { struct mwifiex_ie_types_tsf_timestamp tsf_tlv; - long long tsf_val; + __le64 tsf_val; /* Null Checks */ if (buffer == NULL) @@ -116,6 +116,11 @@ mwifiex_cmd_append_tsf_tlv(struct mwifiex_private *priv, u8 **buffer, memcpy(*buffer, &tsf_tlv, sizeof(tsf_tlv.header)); *buffer += sizeof(tsf_tlv.header); + /* TSF at the time when beacon/probe_response was received */ + tsf_val = cpu_to_le64(bss_desc->network_tsf); + memcpy(*buffer, &tsf_val, sizeof(tsf_val)); + *buffer += sizeof(tsf_val); + memcpy(&tsf_val, bss_desc->time_stamp, sizeof(tsf_val)); dev_dbg(priv->adapter->dev, "info: %s: TSF offset calc: %016llx - " diff --git a/drivers/net/wireless/mwifiex/main.h b/drivers/net/wireless/mwifiex/main.h index 1b50303..5043fcd 100644 --- a/drivers/net/wireless/mwifiex/main.h +++ b/drivers/net/wireless/mwifiex/main.h @@ -280,7 +280,7 @@ struct mwifiex_bssdescriptor { * BAND_A(0X04): 'a' band */ u16 bss_band; - long long network_tsf; + u64 network_tsf; u8 time_stamp[8]; union ieee_types_phy_param_set phy_param_set; union ieee_types_ss_param_set ss_param_set; -- cgit v0.10.2 From 94b2c363dcf732a4edab4ed66041cb36e7f28fbf Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Sat, 30 Apr 2011 22:56:20 +0200 Subject: genirq: Fix typo CONFIG_GENIRC_IRQ_SHOW_LEVEL commit ab7798ffcf98b11a9525cf65bacdae3fd58d357f ("genirq: Expand generic show_interrupts()") added the Kconfig option GENERIC_IRQ_SHOW_LEVEL to accomodate PowerPC, but this doesn't actually enable the functionality due to a typo in the #ifdef check. Signed-off-by: Geert Uytterhoeven Cc: Linux/PPC Development Link: http://lkml.kernel.org/r/%3Calpine.DEB.2.00.1104302251370.19068%40ayla.of.borg%3E Signed-off-by: Thomas Gleixner diff --git a/kernel/irq/proc.c b/kernel/irq/proc.c index dd201bd..834899f 100644 --- a/kernel/irq/proc.c +++ b/kernel/irq/proc.c @@ -419,7 +419,7 @@ int show_interrupts(struct seq_file *p, void *v) } else { seq_printf(p, " %8s", "None"); } -#ifdef CONFIG_GENIRC_IRQ_SHOW_LEVEL +#ifdef CONFIG_GENERIC_IRQ_SHOW_LEVEL seq_printf(p, " %-8s", irqd_is_level_type(&desc->irq_data) ? "Level" : "Edge"); #endif if (desc->name) -- cgit v0.10.2 From 472647dcd7e351dbeda750e5ab3e8f7b06d1199a Mon Sep 17 00:00:00 2001 From: John Stultz Date: Fri, 29 Apr 2011 15:03:10 -0700 Subject: timers: Fix alarmtimer build issues when CONFIG_RTC_CLASS=n Ingo pointed out that the alarmtimers won't build if CONFIG_RTC_CLASS=n. This patch adds proper ifdefs to the alarmtimer code to disable the rtc usage if it is not built in. Reported-by: Ingo Molnar Signed-off-by: John Stultz Signed-off-by: Thomas Gleixner diff --git a/kernel/time/alarmtimer.c b/kernel/time/alarmtimer.c index 491e37b..9265014 100644 --- a/kernel/time/alarmtimer.c +++ b/kernel/time/alarmtimer.c @@ -42,9 +42,11 @@ static struct alarm_base { clockid_t base_clockid; } alarm_bases[ALARM_NUMTYPE]; +#ifdef CONFIG_RTC_CLASS /* rtc timer and device for setting alarm wakeups at suspend */ static struct rtc_timer rtctimer; static struct rtc_device *rtcdev; +#endif /* freezer delta & lock used to handle clock_nanosleep triggered wakeups */ static ktime_t freezer_delta; @@ -148,7 +150,7 @@ static enum hrtimer_restart alarmtimer_fired(struct hrtimer *timer) } - +#ifdef CONFIG_RTC_CLASS /** * alarmtimer_suspend - Suspend time callback * @dev: unused @@ -206,7 +208,12 @@ static int alarmtimer_suspend(struct device *dev) return 0; } - +#else +static int alarmtimer_suspend(struct device *dev) +{ + return 0; +} +#endif static void alarmtimer_freezerset(ktime_t absexp, enum alarmtimer_type type) { @@ -631,6 +638,7 @@ static int __init alarmtimer_init(void) } device_initcall(alarmtimer_init); +#ifdef CONFIG_RTC_CLASS /** * has_wakealarm - check rtc device has wakealarm ability * @dev: current device @@ -675,4 +683,12 @@ static int __init alarmtimer_init_late(void) return 0; } +#else +static int __init alarmtimer_init_late(void) +{ + printk(KERN_WARNING "Kernel not built with RTC support, ALARM timers" + " will not wake from suspend"); + return 0; +} +#endif late_initcall(alarmtimer_init_late); -- cgit v0.10.2 From b4d246b12410b53506c311e5e0b6abb71ead65c6 Mon Sep 17 00:00:00 2001 From: John Stultz Date: Fri, 29 Apr 2011 15:03:11 -0700 Subject: RTC: Disable CONFIG_RTC_CLASS from being built as a module The RTC subsystem has a number of accessors that are available via include/linux/rtc.h. However many of these interfaces are not available for use if CONFIG_RTC_CLASS=m. So in order to support wider use of the RTC in the kernel, I'm removing the tristate config option for a bool, so that code can easily be conditionalized if the RTC class is present or not. Signed-off-by: John Stultz Cc: Ingo Molnar Signed-off-by: Thomas Gleixner diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig index e187887..4289172 100644 --- a/drivers/rtc/Kconfig +++ b/drivers/rtc/Kconfig @@ -3,10 +3,10 @@ # config RTC_LIB - tristate + bool menuconfig RTC_CLASS - tristate "Real Time Clock" + bool "Real Time Clock" default n depends on !S390 select RTC_LIB @@ -15,9 +15,6 @@ menuconfig RTC_CLASS be allowed to plug one or more RTCs to your system. You will probably want to enable one or more of the interfaces below. - This driver can also be built as a module. If so, the module - will be called rtc-core. - if RTC_CLASS config RTC_HCTOSYS -- cgit v0.10.2 From 942c3c5c329274fa6de5998cb911cf3d0a42d0b1 Mon Sep 17 00:00:00 2001 From: Mike Frysinger Date: Mon, 2 May 2011 15:24:27 -0400 Subject: hrtimer: Make lookup table const Signed-off-by: Mike Frysinger Link: http://lkml.kernel.org/r/%3C1304364267-14489-1-git-send-email-vapier%40gentoo.org%3E Signed-off-by: Thomas Gleixner diff --git a/kernel/hrtimer.c b/kernel/hrtimer.c index 87fdb3f..dbbbf7d 100644 --- a/kernel/hrtimer.c +++ b/kernel/hrtimer.c @@ -81,7 +81,7 @@ DEFINE_PER_CPU(struct hrtimer_cpu_base, hrtimer_bases) = } }; -static int hrtimer_clock_to_base_table[MAX_CLOCKS] = { +static const int hrtimer_clock_to_base_table[MAX_CLOCKS] = { [CLOCK_REALTIME] = HRTIMER_BASE_REALTIME, [CLOCK_MONOTONIC] = HRTIMER_BASE_MONOTONIC, [CLOCK_BOOTTIME] = HRTIMER_BASE_BOOTTIME, -- cgit v0.10.2 From a38647837a411f7df79623128421eef2118b5884 Mon Sep 17 00:00:00 2001 From: Konrad Rzeszutek Wilk Date: Fri, 29 Apr 2011 11:34:00 -0400 Subject: xen/mmu: Add workaround "x86-64, mm: Put early page table high" As a consequence of the commit: commit 4b239f458c229de044d6905c2b0f9fe16ed9e01e Author: Yinghai Lu Date: Fri Dec 17 16:58:28 2010 -0800 x86-64, mm: Put early page table high it causes the Linux kernel to crash under Xen: mapping kernel into physical memory Xen: setup ISA identity maps about to get started... (XEN) mm.c:2466:d0 Bad type (saw 7400000000000001 != exp 1000000000000000) for mfn b1d89 (pfn bacf7) (XEN) mm.c:3027:d0 Error while pinning mfn b1d89 (XEN) traps.c:481:d0 Unhandled invalid opcode fault/trap [#6] on VCPU 0 [ec=0000] (XEN) domain_crash_sync called from entry.S (XEN) Domain 0 (vcpu#0) crashed on cpu#0: ... The reason is that at some point init_memory_mapping is going to reach the pagetable pages area and map those pages too (mapping them as normal memory that falls in the range of addresses passed to init_memory_mapping as argument). Some of those pages are already pagetable pages (they are in the range pgt_buf_start-pgt_buf_end) therefore they are going to be mapped RO and everything is fine. Some of these pages are not pagetable pages yet (they fall in the range pgt_buf_end-pgt_buf_top; for example the page at pgt_buf_end) so they are going to be mapped RW. When these pages become pagetable pages and are hooked into the pagetable, xen will find that the guest has already a RW mapping of them somewhere and fail the operation. The reason Xen requires pagetables to be RO is that the hypervisor needs to verify that the pagetables are valid before using them. The validation operations are called "pinning" (more details in arch/x86/xen/mmu.c). In order to fix the issue we mark all the pages in the entire range pgt_buf_start-pgt_buf_top as RO, however when the pagetable allocation is completed only the range pgt_buf_start-pgt_buf_end is reserved by init_memory_mapping. Hence the kernel is going to crash as soon as one of the pages in the range pgt_buf_end-pgt_buf_top is reused (b/c those ranges are RO). For this reason, this function is introduced which is called _after_ the init_memory_mapping has completed (in a perfect world we would call this function from init_memory_mapping, but lets ignore that). Because we are called _after_ init_memory_mapping the pgt_buf_[start, end,top] have all changed to new values (b/c another init_memory_mapping is called). Hence, the first time we enter this function, we save away the pgt_buf_start value and update the pgt_buf_[end,top]. When we detect that the "old" pgt_buf_start through pgt_buf_end PFNs have been reserved (so memblock_x86_reserve_range has been called), we immediately set out to RW the "old" pgt_buf_end through pgt_buf_top. And then we update those "old" pgt_buf_[end|top] with the new ones so that we can redo this on the next pagetable. Acked-by: "H. Peter Anvin" Reviewed-by: Jeremy Fitzhardinge [v1: Updated with Jeremy's comments] [v2: Added the crash output] Signed-off-by: Konrad Rzeszutek Wilk diff --git a/arch/x86/xen/mmu.c b/arch/x86/xen/mmu.c index aef7af9..1bca25f 100644 --- a/arch/x86/xen/mmu.c +++ b/arch/x86/xen/mmu.c @@ -1463,6 +1463,119 @@ static int xen_pgd_alloc(struct mm_struct *mm) return ret; } +#ifdef CONFIG_X86_64 +static __initdata u64 __last_pgt_set_rw = 0; +static __initdata u64 __pgt_buf_start = 0; +static __initdata u64 __pgt_buf_end = 0; +static __initdata u64 __pgt_buf_top = 0; +/* + * As a consequence of the commit: + * + * commit 4b239f458c229de044d6905c2b0f9fe16ed9e01e + * Author: Yinghai Lu + * Date: Fri Dec 17 16:58:28 2010 -0800 + * + * x86-64, mm: Put early page table high + * + * at some point init_memory_mapping is going to reach the pagetable pages + * area and map those pages too (mapping them as normal memory that falls + * in the range of addresses passed to init_memory_mapping as argument). + * Some of those pages are already pagetable pages (they are in the range + * pgt_buf_start-pgt_buf_end) therefore they are going to be mapped RO and + * everything is fine. + * Some of these pages are not pagetable pages yet (they fall in the range + * pgt_buf_end-pgt_buf_top; for example the page at pgt_buf_end) so they + * are going to be mapped RW. When these pages become pagetable pages and + * are hooked into the pagetable, xen will find that the guest has already + * a RW mapping of them somewhere and fail the operation. + * The reason Xen requires pagetables to be RO is that the hypervisor needs + * to verify that the pagetables are valid before using them. The validation + * operations are called "pinning". + * + * In order to fix the issue we mark all the pages in the entire range + * pgt_buf_start-pgt_buf_top as RO, however when the pagetable allocation + * is completed only the range pgt_buf_start-pgt_buf_end is reserved by + * init_memory_mapping. Hence the kernel is going to crash as soon as one + * of the pages in the range pgt_buf_end-pgt_buf_top is reused (b/c those + * ranges are RO). + * + * For this reason, 'mark_rw_past_pgt' is introduced which is called _after_ + * the init_memory_mapping has completed (in a perfect world we would + * call this function from init_memory_mapping, but lets ignore that). + * + * Because we are called _after_ init_memory_mapping the pgt_buf_[start, + * end,top] have all changed to new values (b/c init_memory_mapping + * is called and setting up another new page-table). Hence, the first time + * we enter this function, we save away the pgt_buf_start value and update + * the pgt_buf_[end,top]. + * + * When we detect that the "old" pgt_buf_start through pgt_buf_end + * PFNs have been reserved (so memblock_x86_reserve_range has been called), + * we immediately set out to RW the "old" pgt_buf_end through pgt_buf_top. + * + * And then we update those "old" pgt_buf_[end|top] with the new ones + * so that we can redo this on the next pagetable. + */ +static __init void mark_rw_past_pgt(void) { + + if (pgt_buf_end > pgt_buf_start) { + u64 addr, size; + + /* Save it away. */ + if (!__pgt_buf_start) { + __pgt_buf_start = pgt_buf_start; + __pgt_buf_end = pgt_buf_end; + __pgt_buf_top = pgt_buf_top; + return; + } + /* If we get the range that starts at __pgt_buf_end that means + * the range is reserved, and that in 'init_memory_mapping' + * the 'memblock_x86_reserve_range' has been called with the + * outdated __pgt_buf_start, __pgt_buf_end (the "new" + * pgt_buf_[start|end|top] refer now to a new pagetable. + * Note: we are called _after_ the pgt_buf_[..] have been + * updated.*/ + + addr = memblock_x86_find_in_range_size(PFN_PHYS(__pgt_buf_start), + &size, PAGE_SIZE); + + /* Still not reserved, meaning 'memblock_x86_reserve_range' + * hasn't been called yet. Update the _end and _top.*/ + if (addr == PFN_PHYS(__pgt_buf_start)) { + __pgt_buf_end = pgt_buf_end; + __pgt_buf_top = pgt_buf_top; + return; + } + + /* OK, the area is reserved, meaning it is time for us to + * set RW for the old end->top PFNs. */ + + /* ..unless we had already done this. */ + if (__pgt_buf_end == __last_pgt_set_rw) + return; + + addr = PFN_PHYS(__pgt_buf_end); + + /* set as RW the rest */ + printk(KERN_DEBUG "xen: setting RW the range %llx - %llx\n", + PFN_PHYS(__pgt_buf_end), PFN_PHYS(__pgt_buf_top)); + + while (addr < PFN_PHYS(__pgt_buf_top)) { + make_lowmem_page_readwrite(__va(addr)); + addr += PAGE_SIZE; + } + /* And update everything so that we are ready for the next + * pagetable (the one created for regions past 4GB) */ + __last_pgt_set_rw = __pgt_buf_end; + __pgt_buf_start = pgt_buf_start; + __pgt_buf_end = pgt_buf_end; + __pgt_buf_top = pgt_buf_top; + } + return; +} +#else +static __init void mark_rw_past_pgt(void) { } +#endif static void xen_pgd_free(struct mm_struct *mm, pgd_t *pgd) { #ifdef CONFIG_X86_64 @@ -1489,6 +1602,14 @@ static __init pte_t mask_rw_pte(pte_t *ptep, pte_t pte) unsigned long pfn = pte_pfn(pte); /* + * A bit of optimization. We do not need to call the workaround + * when xen_set_pte_init is called with a PTE with 0 as PFN. + * That is b/c the pagetable at that point are just being populated + * with empty values and we can save some cycles by not calling + * the 'memblock' code.*/ + if (pfn) + mark_rw_past_pgt(); + /* * If the new pfn is within the range of the newly allocated * kernel pagetable, and it isn't being mapped into an * early_ioremap fixmap slot as a freshly allocated page, make sure @@ -1997,6 +2118,8 @@ __init void xen_ident_map_ISA(void) static __init void xen_post_allocator_init(void) { + mark_rw_past_pgt(); + #ifdef CONFIG_XEN_DEBUG pv_mmu_ops.make_pte = PV_CALLEE_SAVE(xen_make_pte_debug); #endif -- cgit v0.10.2 From b9269dc7bfdf8c985971c09f2dcb2aa04ad7986d Mon Sep 17 00:00:00 2001 From: Stefano Stabellini Date: Tue, 12 Apr 2011 12:19:49 +0100 Subject: xen: mask_rw_pte mark RO all pagetable pages up to pgt_buf_top mask_rw_pte is currently checking if a pfn is a pagetable page if it falls in the range pgt_buf_start - pgt_buf_end but that is incorrect because pgt_buf_end is a moving target: pgt_buf_top is the real boundary. Acked-by: "H. Peter Anvin" Signed-off-by: Stefano Stabellini Signed-off-by: Konrad Rzeszutek Wilk diff --git a/arch/x86/xen/mmu.c b/arch/x86/xen/mmu.c index 1bca25f..55c965b 100644 --- a/arch/x86/xen/mmu.c +++ b/arch/x86/xen/mmu.c @@ -1616,7 +1616,7 @@ static __init pte_t mask_rw_pte(pte_t *ptep, pte_t pte) * it is RO. */ if (((!is_early_ioremap_ptep(ptep) && - pfn >= pgt_buf_start && pfn < pgt_buf_end)) || + pfn >= pgt_buf_start && pfn < pgt_buf_top)) || (is_early_ioremap_ptep(ptep) && pfn != (pgt_buf_end - 1))) pte = pte_wrprotect(pte); -- cgit v0.10.2 From 2e053a27d9d5ad5e0831e002cbf8043836fb2060 Mon Sep 17 00:00:00 2001 From: "B.J. Buchalter" Date: Mon, 2 May 2011 13:33:42 -0400 Subject: firewire: Fix for broken configrom updates in quick succession Current implementation of ohci_set_config_rom() uses a deferred bus reset via fw_schedule_bus_reset(). If clients add multiple unit descriptors to the config_rom in quick succession, the deferred bus reset may not have fired before succeeding update requests have come in. This can lead to an incorrect partial update of the config_rom for both addition and removal of config_rom descriptors, as the ohci_set_config_rom() routine will return -EBUSY if a previous pending update has not been completed yet; the requested update just gets dropped on the floor. This patch recognizes that the "in-flight" update can be modified until it has been processed by the bus-reset, and the locking in the bus_reset_tasklet ensures that the update is done atomically with respect to modifications made by ohci_set_config_rom(). The -EBUSY error case is simply removed. [Stefan R: The bug always existed at least theoretically. But it became easy to trigger since 2.6.36 commit 02d37bed188c "firewire: core: integrate software-forced bus resets with bus management" which introduced long mandatory delays between janitorial bus resets.] Signed-off-by: Benjamin Buchalter Signed-off-by: Stefan Richter (trivial style changes) Cc: # 2.6.36.y and newer diff --git a/drivers/firewire/ohci.c b/drivers/firewire/ohci.c index f903d7b6..23d1468 100644 --- a/drivers/firewire/ohci.c +++ b/drivers/firewire/ohci.c @@ -2199,7 +2199,6 @@ static int ohci_set_config_rom(struct fw_card *card, { struct fw_ohci *ohci; unsigned long flags; - int ret = -EBUSY; __be32 *next_config_rom; dma_addr_t uninitialized_var(next_config_rom_bus); @@ -2240,22 +2239,37 @@ static int ohci_set_config_rom(struct fw_card *card, spin_lock_irqsave(&ohci->lock, flags); + /* + * If there is not an already pending config_rom update, + * push our new allocation into the ohci->next_config_rom + * and then mark the local variable as null so that we + * won't deallocate the new buffer. + * + * OTOH, if there is a pending config_rom update, just + * use that buffer with the new config_rom data, and + * let this routine free the unused DMA allocation. + */ + if (ohci->next_config_rom == NULL) { ohci->next_config_rom = next_config_rom; ohci->next_config_rom_bus = next_config_rom_bus; + next_config_rom = NULL; + } - copy_config_rom(ohci->next_config_rom, config_rom, length); + copy_config_rom(ohci->next_config_rom, config_rom, length); - ohci->next_header = config_rom[0]; - ohci->next_config_rom[0] = 0; + ohci->next_header = config_rom[0]; + ohci->next_config_rom[0] = 0; - reg_write(ohci, OHCI1394_ConfigROMmap, - ohci->next_config_rom_bus); - ret = 0; - } + reg_write(ohci, OHCI1394_ConfigROMmap, ohci->next_config_rom_bus); spin_unlock_irqrestore(&ohci->lock, flags); + /* If we didn't use the DMA allocation, delete it. */ + if (next_config_rom != NULL) + dma_free_coherent(ohci->card.device, CONFIG_ROM_SIZE, + next_config_rom, next_config_rom_bus); + /* * Now initiate a bus reset to have the changes take * effect. We clean up the old config rom memory and DMA @@ -2263,13 +2277,10 @@ static int ohci_set_config_rom(struct fw_card *card, * controller could need to access it before the bus reset * takes effect. */ - if (ret == 0) - fw_schedule_bus_reset(&ohci->card, true, true); - else - dma_free_coherent(ohci->card.device, CONFIG_ROM_SIZE, - next_config_rom, next_config_rom_bus); - return ret; + fw_schedule_bus_reset(&ohci->card, true, true); + + return 0; } static void ohci_send_request(struct fw_card *card, struct fw_packet *packet) -- cgit v0.10.2 From 5615787257742aab42ecf17c11e3244d9536a48d Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Mon, 2 May 2011 14:37:45 -0700 Subject: ipv4: Make sure flowi4->{saddr,daddr} are always set. Slow path output route resolution always makes sure that ->{saddr,daddr} are set, and also if we trigger into IPSEC resolution we initialize them as well, because xfrm_lookup() expects them to be fully resolved. But if we hit the fast path and flowi4->flowi4_proto is zero, we won't do this initialization. Therefore, move the IPSEC path initialization to the route cache lookup fast path to make sure these are always set. Signed-off-by: David S. Miller diff --git a/net/ipv4/route.c b/net/ipv4/route.c index 93f71be..64f360d 100644 --- a/net/ipv4/route.c +++ b/net/ipv4/route.c @@ -2675,6 +2675,10 @@ struct rtable *__ip_route_output_key(struct net *net, struct flowi4 *flp4) dst_use(&rth->dst, jiffies); RT_CACHE_STAT_INC(out_hit); rcu_read_unlock_bh(); + if (!flp4->saddr) + flp4->saddr = rth->rt_src; + if (!flp4->daddr) + flp4->daddr = rth->rt_dst; return rth; } RT_CACHE_STAT_INC(out_hlist_search); @@ -2772,15 +2776,10 @@ struct rtable *ip_route_output_flow(struct net *net, struct flowi4 *flp4, if (IS_ERR(rt)) return rt; - if (flp4->flowi4_proto) { - if (!flp4->saddr) - flp4->saddr = rt->rt_src; - if (!flp4->daddr) - flp4->daddr = rt->rt_dst; + if (flp4->flowi4_proto) rt = (struct rtable *) xfrm_lookup(net, &rt->dst, flowi4_to_flowi(flp4), sk, 0); - } return rt; } -- cgit v0.10.2 From 983960b159a75621855283030d92a80bea92e071 Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Mon, 2 May 2011 09:59:29 +0000 Subject: amd8111e: trivial typo spelling: Negotitate -> Negotiate Signed-off-by: Joe Perches Signed-off-by: David S. Miller diff --git a/drivers/net/amd8111e.c b/drivers/net/amd8111e.c index 88495c4..241b185 100644 --- a/drivers/net/amd8111e.c +++ b/drivers/net/amd8111e.c @@ -106,7 +106,7 @@ MODULE_DESCRIPTION ("AMD8111 based 10/100 Ethernet Controller. Driver Version "M MODULE_LICENSE("GPL"); MODULE_DEVICE_TABLE(pci, amd8111e_pci_tbl); module_param_array(speed_duplex, int, NULL, 0); -MODULE_PARM_DESC(speed_duplex, "Set device speed and duplex modes, 0: Auto Negotitate, 1: 10Mbps Half Duplex, 2: 10Mbps Full Duplex, 3: 100Mbps Half Duplex, 4: 100Mbps Full Duplex"); +MODULE_PARM_DESC(speed_duplex, "Set device speed and duplex modes, 0: Auto Negotiate, 1: 10Mbps Half Duplex, 2: 10Mbps Full Duplex, 3: 100Mbps Half Duplex, 4: 100Mbps Full Duplex"); module_param_array(coalesce, bool, NULL, 0); MODULE_PARM_DESC(coalesce, "Enable or Disable interrupt coalescing, 1: Enable, 0: Disable"); module_param_array(dynamic_ipg, bool, NULL, 0); -- cgit v0.10.2 From 7806a49ab625ebeb1709e5e87299b64932b807a7 Mon Sep 17 00:00:00 2001 From: "H. Peter Anvin" Date: Mon, 2 May 2011 14:33:24 -0700 Subject: x86, reboot: Fix relocations in reboot_32.S The use of base for %ebx in this file is arbitrary, *except* that we also use it to compute the real-mode segment. Therefore, make it so that r_base really is the true address to which %ebx points. This resolves kernel bugzilla 33302. Reported-and-tested-by: Alexey Zaytsev Signed-off-by: H. Peter Anvin Link: http://lkml.kernel.org/n/tip-08os5wi3yq1no0y4i5m4z7he@git.kernel.org diff --git a/arch/x86/kernel/reboot_32.S b/arch/x86/kernel/reboot_32.S index 29092b3..1d5c46d 100644 --- a/arch/x86/kernel/reboot_32.S +++ b/arch/x86/kernel/reboot_32.S @@ -21,26 +21,26 @@ r_base = . /* Get our own relocated address */ call 1f 1: popl %ebx - subl $1b, %ebx + subl $(1b - r_base), %ebx /* Compute the equivalent real-mode segment */ movl %ebx, %ecx shrl $4, %ecx /* Patch post-real-mode segment jump */ - movw dispatch_table(%ebx,%eax,2),%ax - movw %ax, 101f(%ebx) - movw %cx, 102f(%ebx) + movw (dispatch_table - r_base)(%ebx,%eax,2),%ax + movw %ax, (101f - r_base)(%ebx) + movw %cx, (102f - r_base)(%ebx) /* Set up the IDT for real mode. */ - lidtl machine_real_restart_idt(%ebx) + lidtl (machine_real_restart_idt - r_base)(%ebx) /* * Set up a GDT from which we can load segment descriptors for real * mode. The GDT is not used in real mode; it is just needed here to * prepare the descriptors. */ - lgdtl machine_real_restart_gdt(%ebx) + lgdtl (machine_real_restart_gdt - r_base)(%ebx) /* * Load the data segment registers with 16-bit compatible values -- cgit v0.10.2 From e67f88dd12f610da98ca838822f2c9b4e7c6100e Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Wed, 27 Apr 2011 22:56:07 +0000 Subject: net: dont hold rtnl mutex during netlink dump callbacks Four years ago, Patrick made a change to hold rtnl mutex during netlink dump callbacks. I believe it was a wrong move. This slows down concurrent dumps, making good old /proc/net/ files faster than rtnetlink in some situations. This occurred to me because one "ip link show dev ..." was _very_ slow on a workload adding/removing network devices in background. All dump callbacks are able to use RCU locking now, so this patch does roughly a revert of commits : 1c2d670f366 : [RTNETLINK]: Hold rtnl_mutex during netlink dump callbacks 6313c1e0992 : [RTNETLINK]: Remove unnecessary locking in dump callbacks This let writers fight for rtnl mutex and readers going full speed. It also takes care of phonet : phonet_route_get() is now called from rcu read section. I renamed it to phonet_route_get_rcu() Signed-off-by: Eric Dumazet Cc: Patrick McHardy Cc: Remi Denis-Courmont Acked-by: Stephen Hemminger Signed-off-by: David S. Miller diff --git a/include/net/phonet/pn_dev.h b/include/net/phonet/pn_dev.h index 13649eb..8639de5 100644 --- a/include/net/phonet/pn_dev.h +++ b/include/net/phonet/pn_dev.h @@ -51,7 +51,7 @@ void phonet_address_notify(int event, struct net_device *dev, u8 addr); int phonet_route_add(struct net_device *dev, u8 daddr); int phonet_route_del(struct net_device *dev, u8 daddr); void rtm_phonet_notify(int event, struct net_device *dev, u8 dst); -struct net_device *phonet_route_get(struct net *net, u8 daddr); +struct net_device *phonet_route_get_rcu(struct net *net, u8 daddr); struct net_device *phonet_route_output(struct net *net, u8 daddr); #define PN_NO_ADDR 0xff diff --git a/net/bridge/br_netlink.c b/net/bridge/br_netlink.c index 134a2ff..ffb0dc4 100644 --- a/net/bridge/br_netlink.c +++ b/net/bridge/br_netlink.c @@ -120,8 +120,9 @@ static int br_dump_ifinfo(struct sk_buff *skb, struct netlink_callback *cb) int idx; idx = 0; - for_each_netdev(net, dev) { - struct net_bridge_port *port = br_port_get_rtnl(dev); + rcu_read_lock(); + for_each_netdev_rcu(net, dev) { + struct net_bridge_port *port = br_port_get_rcu(dev); /* not a bridge port */ if (!port || idx < cb->args[0]) @@ -135,7 +136,7 @@ static int br_dump_ifinfo(struct sk_buff *skb, struct netlink_callback *cb) skip: ++idx; } - + rcu_read_unlock(); cb->args[0] = idx; return skb->len; diff --git a/net/core/fib_rules.c b/net/core/fib_rules.c index 8248ebb..3911586 100644 --- a/net/core/fib_rules.c +++ b/net/core/fib_rules.c @@ -590,7 +590,8 @@ static int dump_rules(struct sk_buff *skb, struct netlink_callback *cb, int idx = 0; struct fib_rule *rule; - list_for_each_entry(rule, &ops->rules_list, list) { + rcu_read_lock(); + list_for_each_entry_rcu(rule, &ops->rules_list, list) { if (idx < cb->args[1]) goto skip; diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c index d7c4bb4..29633125 100644 --- a/net/core/rtnetlink.c +++ b/net/core/rtnetlink.c @@ -1007,10 +1007,11 @@ static int rtnl_dump_ifinfo(struct sk_buff *skb, struct netlink_callback *cb) s_h = cb->args[0]; s_idx = cb->args[1]; + rcu_read_lock(); for (h = s_h; h < NETDEV_HASHENTRIES; h++, s_idx = 0) { idx = 0; head = &net->dev_index_head[h]; - hlist_for_each_entry(dev, node, head, index_hlist) { + hlist_for_each_entry_rcu(dev, node, head, index_hlist) { if (idx < s_idx) goto cont; if (rtnl_fill_ifinfo(skb, dev, RTM_NEWLINK, @@ -1023,6 +1024,7 @@ cont: } } out: + rcu_read_unlock(); cb->args[1] = idx; cb->args[0] = h; @@ -1879,7 +1881,6 @@ static int rtnetlink_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh) int min_len; int family; int type; - int err; type = nlh->nlmsg_type; if (type > RTM_MAX) @@ -1906,11 +1907,8 @@ static int rtnetlink_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh) if (dumpit == NULL) return -EOPNOTSUPP; - __rtnl_unlock(); rtnl = net->rtnl; - err = netlink_dump_start(rtnl, skb, nlh, dumpit, NULL); - rtnl_lock(); - return err; + return netlink_dump_start(rtnl, skb, nlh, dumpit, NULL); } memset(rta_buf, 0, (rtattr_max * sizeof(struct rtattr *))); @@ -1980,7 +1978,7 @@ static int __net_init rtnetlink_net_init(struct net *net) { struct sock *sk; sk = netlink_kernel_create(net, NETLINK_ROUTE, RTNLGRP_MAX, - rtnetlink_rcv, &rtnl_mutex, THIS_MODULE); + rtnetlink_rcv, NULL, THIS_MODULE); if (!sk) return -ENOMEM; net->rtnl = sk; diff --git a/net/decnet/dn_dev.c b/net/decnet/dn_dev.c index 0dcaa90..404fa15 100644 --- a/net/decnet/dn_dev.c +++ b/net/decnet/dn_dev.c @@ -752,7 +752,8 @@ static int dn_nl_dump_ifaddr(struct sk_buff *skb, struct netlink_callback *cb) skip_naddr = cb->args[1]; idx = 0; - for_each_netdev(&init_net, dev) { + rcu_read_lock(); + for_each_netdev_rcu(&init_net, dev) { if (idx < skip_ndevs) goto cont; else if (idx > skip_ndevs) { @@ -761,11 +762,11 @@ static int dn_nl_dump_ifaddr(struct sk_buff *skb, struct netlink_callback *cb) skip_naddr = 0; } - if ((dn_db = rtnl_dereference(dev->dn_ptr)) == NULL) + if ((dn_db = rcu_dereference(dev->dn_ptr)) == NULL) goto cont; - for (ifa = rtnl_dereference(dn_db->ifa_list), dn_idx = 0; ifa; - ifa = rtnl_dereference(ifa->ifa_next), dn_idx++) { + for (ifa = rcu_dereference(dn_db->ifa_list), dn_idx = 0; ifa; + ifa = rcu_dereference(ifa->ifa_next), dn_idx++) { if (dn_idx < skip_naddr) continue; @@ -778,6 +779,7 @@ cont: idx++; } done: + rcu_read_unlock(); cb->args[0] = idx; cb->args[1] = dn_idx; diff --git a/net/ipv6/ip6_fib.c b/net/ipv6/ip6_fib.c index dd88df0..4076a0b 100644 --- a/net/ipv6/ip6_fib.c +++ b/net/ipv6/ip6_fib.c @@ -394,10 +394,11 @@ static int inet6_dump_fib(struct sk_buff *skb, struct netlink_callback *cb) arg.net = net; w->args = &arg; + rcu_read_lock(); for (h = s_h; h < FIB6_TABLE_HASHSZ; h++, s_e = 0) { e = 0; head = &net->ipv6.fib_table_hash[h]; - hlist_for_each_entry(tb, node, head, tb6_hlist) { + hlist_for_each_entry_rcu(tb, node, head, tb6_hlist) { if (e < s_e) goto next; res = fib6_dump_table(tb, skb, cb); @@ -408,6 +409,7 @@ next: } } out: + rcu_read_unlock(); cb->args[1] = e; cb->args[0] = h; diff --git a/net/phonet/pn_dev.c b/net/phonet/pn_dev.c index 947038d..47b3452 100644 --- a/net/phonet/pn_dev.c +++ b/net/phonet/pn_dev.c @@ -426,18 +426,14 @@ int phonet_route_del(struct net_device *dev, u8 daddr) return 0; } -struct net_device *phonet_route_get(struct net *net, u8 daddr) +struct net_device *phonet_route_get_rcu(struct net *net, u8 daddr) { struct phonet_net *pnn = phonet_pernet(net); struct phonet_routes *routes = &pnn->routes; struct net_device *dev; - ASSERT_RTNL(); /* no need to hold the device */ - daddr >>= 2; - rcu_read_lock(); dev = rcu_dereference(routes->table[daddr]); - rcu_read_unlock(); return dev; } diff --git a/net/phonet/pn_netlink.c b/net/phonet/pn_netlink.c index 58b3b1f..438accb 100644 --- a/net/phonet/pn_netlink.c +++ b/net/phonet/pn_netlink.c @@ -264,10 +264,11 @@ static int route_dumpit(struct sk_buff *skb, struct netlink_callback *cb) struct net *net = sock_net(skb->sk); u8 addr, addr_idx = 0, addr_start_idx = cb->args[0]; + rcu_read_lock(); for (addr = 0; addr < 64; addr++) { struct net_device *dev; - dev = phonet_route_get(net, addr << 2); + dev = phonet_route_get_rcu(net, addr << 2); if (!dev) continue; @@ -279,6 +280,7 @@ static int route_dumpit(struct sk_buff *skb, struct netlink_callback *cb) } out: + rcu_read_unlock(); cb->args[0] = addr_idx; cb->args[1] = 0; -- cgit v0.10.2 From 41c31f318a5209922d051e293c61e4724daad11c Mon Sep 17 00:00:00 2001 From: Lifeng Sun Date: Wed, 27 Apr 2011 22:04:51 +0000 Subject: networking: inappropriate ioctl operation should return ENOTTY ioctl() calls against a socket with an inappropriate ioctl operation are incorrectly returning EINVAL rather than ENOTTY: [ENOTTY] Inappropriate I/O control operation. BugLink: https://bugzilla.kernel.org/show_bug.cgi?id=33992 Signed-off-by: Lifeng Sun Signed-off-by: David S. Miller diff --git a/net/core/dev.c b/net/core/dev.c index c2ac599..856b6ee 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -4773,7 +4773,7 @@ static int dev_ifsioc_locked(struct net *net, struct ifreq *ifr, unsigned int cm * is never reached */ WARN_ON(1); - err = -EINVAL; + err = -ENOTTY; break; } @@ -5041,7 +5041,7 @@ int dev_ioctl(struct net *net, unsigned int cmd, void __user *arg) /* Set the per device memory buffer space. * Not applicable in our case */ case SIOCSIFLINK: - return -EINVAL; + return -ENOTTY; /* * Unknown or private ioctl. @@ -5062,7 +5062,7 @@ int dev_ioctl(struct net *net, unsigned int cmd, void __user *arg) /* Take care of Wireless Extensions */ if (cmd >= SIOCIWFIRST && cmd <= SIOCIWLAST) return wext_handle_ioctl(net, &ifr, cmd, arg); - return -EINVAL; + return -ENOTTY; } } -- cgit v0.10.2 From 6fdbab9d93e04bfe71f2b3fde485d092e2ffe3ec Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Thu, 28 Apr 2011 11:02:15 +0000 Subject: tg3: Fix failure to enable WoL by default when possible tg3 is supposed to enable WoL by default on adapters which support that, but it fails to do so unless the adapter's /sys/devices/.../power/wakeup file contains 'enabled' during the initialization of the adapter. Fix that by making tg3 use device_set_wakeup_enable() to enable wakeup automatically whenever WoL should be enabled by default. Signed-off-by: Rafael J. Wysocki Signed-off-by: David S. Miller diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index b8c5f35..7a5daef 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -12327,8 +12327,10 @@ static void __devinit tg3_get_eeprom_hw_cfg(struct tg3 *tp) if (val & VCPU_CFGSHDW_ASPM_DBNC) tp->tg3_flags |= TG3_FLAG_ASPM_WORKAROUND; if ((val & VCPU_CFGSHDW_WOL_ENABLE) && - (val & VCPU_CFGSHDW_WOL_MAGPKT)) + (val & VCPU_CFGSHDW_WOL_MAGPKT)) { tp->tg3_flags |= TG3_FLAG_WOL_ENABLE; + device_set_wakeup_enable(&tp->pdev->dev, true); + } goto done; } @@ -12461,8 +12463,10 @@ static void __devinit tg3_get_eeprom_hw_cfg(struct tg3 *tp) tp->tg3_flags &= ~TG3_FLAG_WOL_CAP; if ((tp->tg3_flags & TG3_FLAG_WOL_CAP) && - (nic_cfg & NIC_SRAM_DATA_CFG_WOL_ENABLE)) + (nic_cfg & NIC_SRAM_DATA_CFG_WOL_ENABLE)) { tp->tg3_flags |= TG3_FLAG_WOL_ENABLE; + device_set_wakeup_enable(&tp->pdev->dev, true); + } if (cfg2 & (1 << 17)) tp->phy_flags |= TG3_PHYFLG_CAPACITIVE_COUPLING; -- cgit v0.10.2 From d946092000698fd204d82a9d239103c656fb63bf Mon Sep 17 00:00:00 2001 From: Rabin Vincent Date: Sat, 30 Apr 2011 08:29:27 +0000 Subject: smsc95xx: fix reset check The reset loop check should check the MII_BMCR register value for BMCR_RESET rather than for MII_BMCR (the register address, which also happens to be zero). Signed-off-by: Rabin Vincent Signed-off-by: David S. Miller diff --git a/drivers/net/usb/smsc95xx.c b/drivers/net/usb/smsc95xx.c index 47a6c87..48d4efd 100644 --- a/drivers/net/usb/smsc95xx.c +++ b/drivers/net/usb/smsc95xx.c @@ -730,7 +730,7 @@ static int smsc95xx_phy_initialize(struct usbnet *dev) msleep(10); bmcr = smsc95xx_mdio_read(dev->net, dev->mii.phy_id, MII_BMCR); timeout++; - } while ((bmcr & MII_BMCR) && (timeout < 100)); + } while ((bmcr & BMCR_RESET) && (timeout < 100)); if (timeout >= 100) { netdev_warn(dev->net, "timeout on PHY Reset"); -- cgit v0.10.2 From 6c8c44462ac8ac3f95929328f0c56e9e8b6dd524 Mon Sep 17 00:00:00 2001 From: Jiri Pirko Date: Sat, 30 Apr 2011 01:28:17 +0000 Subject: Revert: veth: remove unneeded ifname code from veth_newlink() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 84c49d8c3e4abefb0a41a77b25aa37ebe8d6b743 ("veth: remove unneeded ifname code from veth_newlink()") caused regression on veth creation. This patch reverts the original one. Reported-by: MichaÅ‚ MirosÅ‚aw Signed-off-by: Jiri Pirko Signed-off-by: David S. Miller diff --git a/drivers/net/veth.c b/drivers/net/veth.c index 2de9b90..3b99f64 100644 --- a/drivers/net/veth.c +++ b/drivers/net/veth.c @@ -403,6 +403,17 @@ static int veth_newlink(struct net *src_net, struct net_device *dev, if (tb[IFLA_ADDRESS] == NULL) random_ether_addr(dev->dev_addr); + if (tb[IFLA_IFNAME]) + nla_strlcpy(dev->name, tb[IFLA_IFNAME], IFNAMSIZ); + else + snprintf(dev->name, IFNAMSIZ, DRV_NAME "%%d"); + + if (strchr(dev->name, '%')) { + err = dev_alloc_name(dev, dev->name); + if (err < 0) + goto err_alloc_name; + } + err = register_netdevice(dev); if (err < 0) goto err_register_dev; @@ -422,6 +433,7 @@ static int veth_newlink(struct net *src_net, struct net_device *dev, err_register_dev: /* nothing to do */ +err_alloc_name: err_configure_peer: unregister_netdevice(peer); return err; -- cgit v0.10.2 From ff538818f4a82c4cf02d2d6bd6ac5c7360b9d41d Mon Sep 17 00:00:00 2001 From: Lucian Adrian Grijincu Date: Sun, 1 May 2011 01:44:01 +0000 Subject: sysctl: net: call unregister_net_sysctl_table where needed ctl_table_headers registered with register_net_sysctl_table should have been unregistered with the equivalent unregister_net_sysctl_table Signed-off-by: Lucian Adrian Grijincu Signed-off-by: David S. Miller diff --git a/net/ipv4/devinet.c b/net/ipv4/devinet.c index 5345b0b..cd9ca08 100644 --- a/net/ipv4/devinet.c +++ b/net/ipv4/devinet.c @@ -1680,7 +1680,7 @@ static void __devinet_sysctl_unregister(struct ipv4_devconf *cnf) return; cnf->sysctl = NULL; - unregister_sysctl_table(t->sysctl_header); + unregister_net_sysctl_table(t->sysctl_header); kfree(t->dev_name); kfree(t); } diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c index 1493534..a7bda07 100644 --- a/net/ipv6/addrconf.c +++ b/net/ipv6/addrconf.c @@ -4537,7 +4537,7 @@ static void __addrconf_sysctl_unregister(struct ipv6_devconf *p) t = p->sysctl; p->sysctl = NULL; - unregister_sysctl_table(t->sysctl_header); + unregister_net_sysctl_table(t->sysctl_header); kfree(t->dev_name); kfree(t); } -- cgit v0.10.2 From 9620fd959fb169358f2ba349c9fd1bcd96944c28 Mon Sep 17 00:00:00 2001 From: Kim Phillips Date: Mon, 11 Apr 2011 19:15:16 -0500 Subject: crypto: caam - handle interrupt lines shared across rings - add IRQF_SHARED to request_irq flags to support parts such as the p1023 that has one IRQ line per couple of rings. - resetting a job ring triggers an interrupt, so move request_irq prior to jr_reset to avoid 'got IRQ but nobody cared' messages. - disable IRQs in h/w to avoid contention between reset and interrupt status - delete invalid comment - if there were incomplete jobs, module would be in use, preventing an unload. Signed-off-by: Kim Phillips Signed-off-by: Herbert Xu diff --git a/drivers/crypto/caam/jr.c b/drivers/crypto/caam/jr.c index 68cb9af..340fa32 100644 --- a/drivers/crypto/caam/jr.c +++ b/drivers/crypto/caam/jr.c @@ -292,10 +292,10 @@ static int caam_reset_hw_jr(struct device *dev) unsigned int timeout = 100000; /* - * FIXME: disabling IRQs here inhibits proper job completion - * and error propagation + * mask interrupts since we are going to poll + * for reset completion status */ - disable_irq(jrp->irq); + setbits32(&jrp->rregs->rconfig_lo, JRCFG_IMSK); /* initiate flush (required prior to reset) */ wr_reg32(&jrp->rregs->jrcommand, JRCR_RESET); @@ -320,7 +320,8 @@ static int caam_reset_hw_jr(struct device *dev) return -EIO; } - enable_irq(jrp->irq); + /* unmask interrupts */ + clrbits32(&jrp->rregs->rconfig_lo, JRCFG_IMSK); return 0; } @@ -336,6 +337,21 @@ static int caam_jr_init(struct device *dev) jrp = dev_get_drvdata(dev); + /* Connect job ring interrupt handler. */ + for_each_possible_cpu(i) + tasklet_init(&jrp->irqtask[i], caam_jr_dequeue, + (unsigned long)dev); + + error = request_irq(jrp->irq, caam_jr_interrupt, IRQF_SHARED, + "caam-jobr", dev); + if (error) { + dev_err(dev, "can't connect JobR %d interrupt (%d)\n", + jrp->ridx, jrp->irq); + irq_dispose_mapping(jrp->irq); + jrp->irq = 0; + return -EINVAL; + } + error = caam_reset_hw_jr(dev); if (error) return error; @@ -404,28 +420,6 @@ static int caam_jr_init(struct device *dev) (JOBR_INTC_COUNT_THLD << JRCFG_ICDCT_SHIFT) | (JOBR_INTC_TIME_THLD << JRCFG_ICTT_SHIFT)); - /* Connect job ring interrupt handler. */ - for_each_possible_cpu(i) - tasklet_init(&jrp->irqtask[i], caam_jr_dequeue, - (unsigned long)dev); - - error = request_irq(jrp->irq, caam_jr_interrupt, 0, - "caam-jobr", dev); - if (error) { - dev_err(dev, "can't connect JobR %d interrupt (%d)\n", - jrp->ridx, jrp->irq); - irq_dispose_mapping(jrp->irq); - jrp->irq = 0; - dma_unmap_single(dev, inpbusaddr, sizeof(u32 *) * JOBR_DEPTH, - DMA_BIDIRECTIONAL); - dma_unmap_single(dev, outbusaddr, sizeof(u32 *) * JOBR_DEPTH, - DMA_BIDIRECTIONAL); - kfree(jrp->inpring); - kfree(jrp->outring); - kfree(jrp->entinfo); - return -EINVAL; - } - jrp->assign = JOBR_UNASSIGNED; return 0; } -- cgit v0.10.2 From f3af98681f16063d110075eba79a8621ae9a376a Mon Sep 17 00:00:00 2001 From: Kim Phillips Date: Mon, 11 Apr 2011 19:15:21 -0500 Subject: crypto: caam - fix queue interface detection The presence of a h/w Queue Interface would fail due to this cut-n-paste snafu. Signed-off-by: Kim Phillips Signed-off-by: Herbert Xu diff --git a/drivers/crypto/caam/regs.h b/drivers/crypto/caam/regs.h index d063a26..aee394e 100644 --- a/drivers/crypto/caam/regs.h +++ b/drivers/crypto/caam/regs.h @@ -131,7 +131,7 @@ struct caam_perfmon { /* CAAM Hardware Instantiation Parameters fa0-fbf */ u64 cha_rev; /* CRNR - CHA Revision Number */ #define CTPR_QI_SHIFT 57 -#define CTPR_QI_MASK (0x1ull << CHA_NUM_DECONUM_SHIFT) +#define CTPR_QI_MASK (0x1ull << CTPR_QI_SHIFT) u64 comp_parms; /* CTPR - Compile Parameters Register */ u64 rsvd1[2]; -- cgit v0.10.2 From d37d36e31cb8b4bd7c4e052e29674bf897ea466c Mon Sep 17 00:00:00 2001 From: Kim Phillips Date: Mon, 11 Apr 2011 19:15:24 -0500 Subject: crypto: caam - remove WAIT-FOR-COMPLETIONs from givencrypt descriptor remains from descriptor debugging - not required for normal operation. Signed-off-by: Kim Phillips Signed-off-by: Herbert Xu diff --git a/drivers/crypto/caam/caamalg.c b/drivers/crypto/caam/caamalg.c index 20e1215..8eb84d3 100644 --- a/drivers/crypto/caam/caamalg.c +++ b/drivers/crypto/caam/caamalg.c @@ -828,15 +828,13 @@ static int aead_authenc_givencrypt(struct aead_givcrypt_request *req) append_cmd(desc, CMD_LOAD | DISABLE_AUTO_INFO_FIFO); /* MOVE DECO Alignment -> C1 Context 16 bytes */ - append_move(desc, MOVE_WAITCOMP | MOVE_SRC_INFIFO | - MOVE_DEST_CLASS1CTX | ivsize); + append_move(desc, MOVE_SRC_INFIFO | MOVE_DEST_CLASS1CTX | ivsize); /* re-enable info fifo entries */ append_cmd(desc, CMD_LOAD | ENABLE_AUTO_INFO_FIFO); /* MOVE C1 Context -> OFIFO 16 bytes */ - append_move(desc, MOVE_WAITCOMP | MOVE_SRC_CLASS1CTX | - MOVE_DEST_OUTFIFO | ivsize); + append_move(desc, MOVE_SRC_CLASS1CTX | MOVE_DEST_OUTFIFO | ivsize); append_fifo_store(desc, iv_dma, ivsize, FIFOST_TYPE_MESSAGE_DATA); -- cgit v0.10.2 From ec8e8dfe5f862a01bf1b5cdac441c083ce0a2a22 Mon Sep 17 00:00:00 2001 From: Kim Phillips Date: Mon, 11 Apr 2011 19:15:28 -0500 Subject: crypto: caam - remove duplicate dev_err keep the hex error value reporting version (a) to be consistent with decrypt_done(), and (b) to keep our hardware guys happy. Signed-off-by: Kim Phillips Signed-off-by: Herbert Xu diff --git a/drivers/crypto/caam/caamalg.c b/drivers/crypto/caam/caamalg.c index 8eb84d3..245cfe4 100644 --- a/drivers/crypto/caam/caamalg.c +++ b/drivers/crypto/caam/caamalg.c @@ -418,7 +418,6 @@ static void ipsec_esp_encrypt_done(struct device *jrdev, u32 *desc, u32 err, if (err) { char tmp[256]; - dev_err(jrdev, "%s\n", caam_jr_strstatus(tmp, err)); dev_err(jrdev, "%08x: %s\n", err, caam_jr_strstatus(tmp, err)); } -- cgit v0.10.2 From d93da492d9a8840a0bdda88e74df8d0f593f1977 Mon Sep 17 00:00:00 2001 From: Arvid Brodin Date: Tue, 26 Apr 2011 21:46:47 +0200 Subject: usb/isp1760: Report correct urb status after unlink This fixes a bug in my previous (2.6.38) patch series which caused urb->status value to be wrong after unlink (broke usbtest 11, 12). Signed-off-by: Arvid Brodin Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/usb/host/isp1760-hcd.c b/drivers/usb/host/isp1760-hcd.c index 795345a..7b2e69a 100644 --- a/drivers/usb/host/isp1760-hcd.c +++ b/drivers/usb/host/isp1760-hcd.c @@ -1633,6 +1633,7 @@ static int isp1760_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status) ints[i].qh = NULL; ints[i].qtd = NULL; + urb->status = status; isp1760_urb_done(hcd, urb); if (qtd) pe(hcd, qh, qtd); -- cgit v0.10.2 From cee6a262550f53a13acfefbc1e3e5ff35c96182c Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Mon, 2 May 2011 14:21:44 -0400 Subject: USB: fix regression in usbip by setting has_tt flag This patch (as1460) fixes a regression in the usbip driver caused by the new check for Transaction Translators in USB-2 hubs. The root hub registered by vhci_hcd needs to have the has_tt flag set, because it can connect to low- and full-speed devices as well as high-speed devices. Signed-off-by: Alan Stern Reported-and-tested-by: Nikola Ciprich CC: Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/staging/usbip/vhci_hcd.c b/drivers/staging/usbip/vhci_hcd.c index 0f02a4b..5d0caa8 100644 --- a/drivers/staging/usbip/vhci_hcd.c +++ b/drivers/staging/usbip/vhci_hcd.c @@ -1139,7 +1139,7 @@ static int vhci_hcd_probe(struct platform_device *pdev) usbip_uerr("create hcd failed\n"); return -ENOMEM; } - + hcd->has_tt = 1; /* this is private data for vhci_hcd */ the_controller = hcd_to_vhci(hcd); -- cgit v0.10.2 From 146f9f65bd13f56665205aed7205d531c810cb35 Mon Sep 17 00:00:00 2001 From: Jeff Layton Date: Fri, 29 Apr 2011 06:52:43 -0400 Subject: cifs: refactor mid finding loop in cifs_demultiplex_thread ...to reduce the extreme indentation. This should introduce no behavioral changes. Cc: stable@kernel.org Acked-by: David Howells Signed-off-by: Jeff Layton Signed-off-by: Steve French diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index 8b75a8ec..bfbf323 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c @@ -617,59 +617,59 @@ incomplete_rcv: list_for_each_safe(tmp, tmp2, &server->pending_mid_q) { mid_entry = list_entry(tmp, struct mid_q_entry, qhead); - if ((mid_entry->mid == smb_buffer->Mid) && - (mid_entry->midState == MID_REQUEST_SUBMITTED) && - (mid_entry->command == smb_buffer->Command)) { - if (length == 0 && - check2ndT2(smb_buffer, server->maxBuf) > 0) { - /* We have a multipart transact2 resp */ - isMultiRsp = true; - if (mid_entry->resp_buf) { - /* merge response - fix up 1st*/ - if (coalesce_t2(smb_buffer, + if (mid_entry->mid != smb_buffer->Mid || + mid_entry->midState != MID_REQUEST_SUBMITTED || + mid_entry->command != smb_buffer->Command) { + mid_entry = NULL; + continue; + } + + if (length == 0 && + check2ndT2(smb_buffer, server->maxBuf) > 0) { + /* We have a multipart transact2 resp */ + isMultiRsp = true; + if (mid_entry->resp_buf) { + /* merge response - fix up 1st*/ + if (coalesce_t2(smb_buffer, mid_entry->resp_buf)) { - mid_entry->multiRsp = - true; - break; - } else { - /* all parts received */ - mid_entry->multiEnd = - true; - goto multi_t2_fnd; - } + mid_entry->multiRsp = true; + break; } else { - if (!isLargeBuf) { - cERROR(1, "1st trans2 resp needs bigbuf"); - /* BB maybe we can fix this up, switch - to already allocated large buffer? */ - } else { - /* Have first buffer */ - mid_entry->resp_buf = - smb_buffer; - mid_entry->largeBuf = - true; - bigbuf = NULL; - } + /* all parts received */ + mid_entry->multiEnd = true; + goto multi_t2_fnd; + } + } else { + if (!isLargeBuf) { + /* + * FIXME: switch to already + * allocated largebuf? + */ + cERROR(1, "1st trans2 resp " + "needs bigbuf"); + } else { + /* Have first buffer */ + mid_entry->resp_buf = + smb_buffer; + mid_entry->largeBuf = true; + bigbuf = NULL; } - break; } - mid_entry->resp_buf = smb_buffer; - mid_entry->largeBuf = isLargeBuf; + break; + } + mid_entry->resp_buf = smb_buffer; + mid_entry->largeBuf = isLargeBuf; multi_t2_fnd: - if (length == 0) - mid_entry->midState = - MID_RESPONSE_RECEIVED; - else - mid_entry->midState = - MID_RESPONSE_MALFORMED; + if (length == 0) + mid_entry->midState = MID_RESPONSE_RECEIVED; + else + mid_entry->midState = MID_RESPONSE_MALFORMED; #ifdef CONFIG_CIFS_STATS2 - mid_entry->when_received = jiffies; + mid_entry->when_received = jiffies; #endif - list_del_init(&mid_entry->qhead); - mid_entry->callback(mid_entry); - break; - } - mid_entry = NULL; + list_del_init(&mid_entry->qhead); + mid_entry->callback(mid_entry); + break; } spin_unlock(&GlobalMid_Lock); -- cgit v0.10.2 From 16541ba11c4f04ffe94b073e301f00b749fb84a1 Mon Sep 17 00:00:00 2001 From: Jeff Layton Date: Fri, 29 Apr 2011 06:52:44 -0400 Subject: cifs: handle errors from coalesce_t2 cifs_demultiplex_thread calls coalesce_t2 to try and merge follow-on t2 responses into the original mid buffer. coalesce_t2 however can return errors, but the caller doesn't handle that situation properly. Fix the thread to treat such a case as it would a malformed packet. Mark the mid as being malformed and issue the callback. Cc: stable@kernel.org Acked-by: David Howells Signed-off-by: Jeff Layton Signed-off-by: Steve French diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index bfbf323..05f1dcf 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c @@ -630,12 +630,16 @@ incomplete_rcv: isMultiRsp = true; if (mid_entry->resp_buf) { /* merge response - fix up 1st*/ - if (coalesce_t2(smb_buffer, - mid_entry->resp_buf)) { + length = coalesce_t2(smb_buffer, + mid_entry->resp_buf); + if (length > 0) { + length = 0; mid_entry->multiRsp = true; break; } else { - /* all parts received */ + /* all parts received or + * packet is malformed + */ mid_entry->multiEnd = true; goto multi_t2_fnd; } -- cgit v0.10.2 From 6905d9e4dda6112f007e9090bca80507da158e63 Mon Sep 17 00:00:00 2001 From: Benjamin Marzinski Date: Tue, 26 Apr 2011 01:13:24 -0500 Subject: GFS2: make sure fallocate bytes is a multiple of blksize The GFS2 fallocate code chooses a target size to for allocating chunks of space. Whenever it can't find any resource groups with enough space free, it halves its target. Since this target is in bytes, eventually it will no longer be a multiple of blksize. As long as there is more space available in the resource group than the target, this isn't a problem, since gfs2 will use the actual space available, which is always a multiple of blksize. However, when gfs couldn't fallocate a bigger chunk than the target, it was using the non-blksize aligned number. This caused a BUG in later code that required blksize aligned offsets. GFS2 now ensures that bytes is always a multiple of blksize Signed-off-by: Benjamin Marzinski Signed-off-by: Steven Whitehouse diff --git a/fs/gfs2/file.c b/fs/gfs2/file.c index 23eab47..a9f5cbe 100644 --- a/fs/gfs2/file.c +++ b/fs/gfs2/file.c @@ -816,6 +816,7 @@ static long gfs2_fallocate(struct file *file, int mode, loff_t offset, loff_t bytes, max_bytes; struct gfs2_alloc *al; int error; + loff_t bsize_mask = ~((loff_t)sdp->sd_sb.sb_bsize - 1); loff_t next = (offset + len - 1) >> sdp->sd_sb.sb_bsize_shift; next = (next + 1) << sdp->sd_sb.sb_bsize_shift; @@ -823,13 +824,15 @@ static long gfs2_fallocate(struct file *file, int mode, loff_t offset, if (mode & ~FALLOC_FL_KEEP_SIZE) return -EOPNOTSUPP; - offset = (offset >> sdp->sd_sb.sb_bsize_shift) << - sdp->sd_sb.sb_bsize_shift; + offset &= bsize_mask; len = next - offset; bytes = sdp->sd_max_rg_data * sdp->sd_sb.sb_bsize / 2; if (!bytes) bytes = UINT_MAX; + bytes &= bsize_mask; + if (bytes == 0) + bytes = sdp->sd_sb.sb_bsize; gfs2_holder_init(ip->i_gl, LM_ST_EXCLUSIVE, 0, &ip->i_gh); error = gfs2_glock_nq(&ip->i_gh); @@ -860,6 +863,9 @@ retry: if (error) { if (error == -ENOSPC && bytes > sdp->sd_sb.sb_bsize) { bytes >>= 1; + bytes &= bsize_mask; + if (bytes == 0) + bytes = sdp->sd_sb.sb_bsize; goto retry; } goto out_qunlock; -- cgit v0.10.2 From 4f1de018215fb56940ce5793e11becd1e8cd6e44 Mon Sep 17 00:00:00 2001 From: Steven Whitehouse Date: Tue, 26 Apr 2011 10:23:56 +0100 Subject: GFS2: Fix ail list traversal In the recent patches to update the AIL list code, I managed to forget that the ail list lock got dropped, even though I added a comment specifically to remind myself :( Reported-by: Barry Marson Signed-off-by: Steven Whitehouse diff --git a/fs/gfs2/log.c b/fs/gfs2/log.c index ad1f188..cec26c0 100644 --- a/fs/gfs2/log.c +++ b/fs/gfs2/log.c @@ -89,9 +89,9 @@ void gfs2_remove_from_ail(struct gfs2_bufdata *bd) * */ -static void gfs2_ail1_start_one(struct gfs2_sbd *sdp, - struct writeback_control *wbc, - struct gfs2_ail *ai) +static int gfs2_ail1_start_one(struct gfs2_sbd *sdp, + struct writeback_control *wbc, + struct gfs2_ail *ai) __releases(&sdp->sd_ail_lock) __acquires(&sdp->sd_ail_lock) { @@ -100,7 +100,6 @@ __acquires(&sdp->sd_ail_lock) struct gfs2_bufdata *bd, *s; struct buffer_head *bh; -restart: list_for_each_entry_safe_reverse(bd, s, &ai->ai_ail1_list, bd_ail_st_list) { bh = bd->bd_bh; @@ -120,13 +119,17 @@ restart: gl = bd->bd_gl; list_move(&bd->bd_ail_st_list, &ai->ai_ail1_list); mapping = bh->b_page->mapping; + if (!mapping) + continue; spin_unlock(&sdp->sd_ail_lock); generic_writepages(mapping, wbc); spin_lock(&sdp->sd_ail_lock); if (wbc->nr_to_write <= 0) break; - goto restart; + return 1; } + + return 0; } @@ -146,10 +149,12 @@ void gfs2_ail1_flush(struct gfs2_sbd *sdp, struct writeback_control *wbc) trace_gfs2_ail_flush(sdp, wbc, 1); spin_lock(&sdp->sd_ail_lock); +restart: list_for_each_entry_reverse(ai, head, ai_list) { if (wbc->nr_to_write <= 0) break; - gfs2_ail1_start_one(sdp, wbc, ai); /* This may drop ail lock */ + if (gfs2_ail1_start_one(sdp, wbc, ai)) + goto restart; } spin_unlock(&sdp->sd_ail_lock); trace_gfs2_ail_flush(sdp, wbc, 0); -- cgit v0.10.2 From 8f065d36508f283ee6cbeb05829f032d0b782a16 Mon Sep 17 00:00:00 2001 From: Steven Whitehouse Date: Tue, 3 May 2011 11:49:19 +0100 Subject: GFS2: Improve bug trap code in ->releasepage() If the buffer is dirty or pinned, then as well as printing a warning, we should also refuse to release the page in question. Currently this can occur if there is a race between mmap()ed writers and O_DIRECT on the same file. With the addition of ->launder_page() in the future, we should be able to close this gap. Signed-off-by: Steven Whitehouse diff --git a/fs/gfs2/aops.c b/fs/gfs2/aops.c index 0f5c4f9..802ac5e 100644 --- a/fs/gfs2/aops.c +++ b/fs/gfs2/aops.c @@ -1076,8 +1076,8 @@ int gfs2_releasepage(struct page *page, gfp_t gfp_mask) bd = bh->b_private; if (bd && bd->bd_ail) goto cannot_release; - gfs2_assert_warn(sdp, !buffer_pinned(bh)); - gfs2_assert_warn(sdp, !buffer_dirty(bh)); + if (buffer_pinned(bh) || buffer_dirty(bh)) + goto not_possible; bh = bh->b_this_page; } while(bh != head); gfs2_log_unlock(sdp); @@ -1107,6 +1107,10 @@ int gfs2_releasepage(struct page *page, gfp_t gfp_mask) } while (bh != head); return try_to_free_buffers(page); + +not_possible: /* Should never happen */ + WARN_ON(buffer_dirty(bh)); + WARN_ON(buffer_pinned(bh)); cannot_release: gfs2_log_unlock(sdp); return 0; -- cgit v0.10.2 From fae85b7c8bcc7de9c0a2698587e20c15beb7d5a6 Mon Sep 17 00:00:00 2001 From: Borislav Petkov Date: Tue, 26 Oct 2010 20:24:03 +0200 Subject: perf: Start the restructuring mv kernel/perf_event.c -> kernel/events/core.c. From there, all further sensible splitting can happen. The idea is that due to perf_event.c becoming pretty sizable and with the advent of the marriage with ftrace, splitting functionality into its logical parts should help speeding up the unification and to manage the complexity of the subsystem. Signed-off-by: Borislav Petkov diff --git a/kernel/Makefile b/kernel/Makefile index 85cbfb3..7981530 100644 --- a/kernel/Makefile +++ b/kernel/Makefile @@ -21,7 +21,6 @@ CFLAGS_REMOVE_mutex-debug.o = -pg CFLAGS_REMOVE_rtmutex-debug.o = -pg CFLAGS_REMOVE_cgroup-debug.o = -pg CFLAGS_REMOVE_sched_clock.o = -pg -CFLAGS_REMOVE_perf_event.o = -pg CFLAGS_REMOVE_irq_work.o = -pg endif @@ -103,7 +102,9 @@ obj-$(CONFIG_RING_BUFFER) += trace/ obj-$(CONFIG_TRACEPOINTS) += trace/ obj-$(CONFIG_SMP) += sched_cpupri.o obj-$(CONFIG_IRQ_WORK) += irq_work.o -obj-$(CONFIG_PERF_EVENTS) += perf_event.o + +obj-$(CONFIG_PERF_EVENTS) += events/ + obj-$(CONFIG_HAVE_HW_BREAKPOINT) += hw_breakpoint.o obj-$(CONFIG_USER_RETURN_NOTIFIER) += user-return-notifier.o obj-$(CONFIG_PADATA) += padata.o diff --git a/kernel/events/Makefile b/kernel/events/Makefile new file mode 100644 index 0000000..26c00e4 --- /dev/null +++ b/kernel/events/Makefile @@ -0,0 +1,5 @@ +ifdef CONFIG_FUNCTION_TRACER +CFLAGS_REMOVE_core.o = -pg +endif + +obj-y += core.o diff --git a/kernel/events/core.c b/kernel/events/core.c new file mode 100644 index 0000000..440bc48 --- /dev/null +++ b/kernel/events/core.c @@ -0,0 +1,7455 @@ +/* + * Performance events core code: + * + * Copyright (C) 2008 Thomas Gleixner + * Copyright (C) 2008-2009 Red Hat, Inc., Ingo Molnar + * Copyright (C) 2008-2009 Red Hat, Inc., Peter Zijlstra + * Copyright © 2009 Paul Mackerras, IBM Corp. + * + * For licensing details see kernel-base/COPYING + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +struct remote_function_call { + struct task_struct *p; + int (*func)(void *info); + void *info; + int ret; +}; + +static void remote_function(void *data) +{ + struct remote_function_call *tfc = data; + struct task_struct *p = tfc->p; + + if (p) { + tfc->ret = -EAGAIN; + if (task_cpu(p) != smp_processor_id() || !task_curr(p)) + return; + } + + tfc->ret = tfc->func(tfc->info); +} + +/** + * task_function_call - call a function on the cpu on which a task runs + * @p: the task to evaluate + * @func: the function to be called + * @info: the function call argument + * + * Calls the function @func when the task is currently running. This might + * be on the current CPU, which just calls the function directly + * + * returns: @func return value, or + * -ESRCH - when the process isn't running + * -EAGAIN - when the process moved away + */ +static int +task_function_call(struct task_struct *p, int (*func) (void *info), void *info) +{ + struct remote_function_call data = { + .p = p, + .func = func, + .info = info, + .ret = -ESRCH, /* No such (running) process */ + }; + + if (task_curr(p)) + smp_call_function_single(task_cpu(p), remote_function, &data, 1); + + return data.ret; +} + +/** + * cpu_function_call - call a function on the cpu + * @func: the function to be called + * @info: the function call argument + * + * Calls the function @func on the remote cpu. + * + * returns: @func return value or -ENXIO when the cpu is offline + */ +static int cpu_function_call(int cpu, int (*func) (void *info), void *info) +{ + struct remote_function_call data = { + .p = NULL, + .func = func, + .info = info, + .ret = -ENXIO, /* No such CPU */ + }; + + smp_call_function_single(cpu, remote_function, &data, 1); + + return data.ret; +} + +#define PERF_FLAG_ALL (PERF_FLAG_FD_NO_GROUP |\ + PERF_FLAG_FD_OUTPUT |\ + PERF_FLAG_PID_CGROUP) + +enum event_type_t { + EVENT_FLEXIBLE = 0x1, + EVENT_PINNED = 0x2, + EVENT_ALL = EVENT_FLEXIBLE | EVENT_PINNED, +}; + +/* + * perf_sched_events : >0 events exist + * perf_cgroup_events: >0 per-cpu cgroup events exist on this cpu + */ +struct jump_label_key perf_sched_events __read_mostly; +static DEFINE_PER_CPU(atomic_t, perf_cgroup_events); + +static atomic_t nr_mmap_events __read_mostly; +static atomic_t nr_comm_events __read_mostly; +static atomic_t nr_task_events __read_mostly; + +static LIST_HEAD(pmus); +static DEFINE_MUTEX(pmus_lock); +static struct srcu_struct pmus_srcu; + +/* + * perf event paranoia level: + * -1 - not paranoid at all + * 0 - disallow raw tracepoint access for unpriv + * 1 - disallow cpu events for unpriv + * 2 - disallow kernel profiling for unpriv + */ +int sysctl_perf_event_paranoid __read_mostly = 1; + +/* Minimum for 512 kiB + 1 user control page */ +int sysctl_perf_event_mlock __read_mostly = 512 + (PAGE_SIZE / 1024); /* 'free' kiB per user */ + +/* + * max perf event sample rate + */ +#define DEFAULT_MAX_SAMPLE_RATE 100000 +int sysctl_perf_event_sample_rate __read_mostly = DEFAULT_MAX_SAMPLE_RATE; +static int max_samples_per_tick __read_mostly = + DIV_ROUND_UP(DEFAULT_MAX_SAMPLE_RATE, HZ); + +int perf_proc_update_handler(struct ctl_table *table, int write, + void __user *buffer, size_t *lenp, + loff_t *ppos) +{ + int ret = proc_dointvec(table, write, buffer, lenp, ppos); + + if (ret || !write) + return ret; + + max_samples_per_tick = DIV_ROUND_UP(sysctl_perf_event_sample_rate, HZ); + + return 0; +} + +static atomic64_t perf_event_id; + +static void cpu_ctx_sched_out(struct perf_cpu_context *cpuctx, + enum event_type_t event_type); + +static void cpu_ctx_sched_in(struct perf_cpu_context *cpuctx, + enum event_type_t event_type, + struct task_struct *task); + +static void update_context_time(struct perf_event_context *ctx); +static u64 perf_event_time(struct perf_event *event); + +void __weak perf_event_print_debug(void) { } + +extern __weak const char *perf_pmu_name(void) +{ + return "pmu"; +} + +static inline u64 perf_clock(void) +{ + return local_clock(); +} + +static inline struct perf_cpu_context * +__get_cpu_context(struct perf_event_context *ctx) +{ + return this_cpu_ptr(ctx->pmu->pmu_cpu_context); +} + +#ifdef CONFIG_CGROUP_PERF + +/* + * Must ensure cgroup is pinned (css_get) before calling + * this function. In other words, we cannot call this function + * if there is no cgroup event for the current CPU context. + */ +static inline struct perf_cgroup * +perf_cgroup_from_task(struct task_struct *task) +{ + return container_of(task_subsys_state(task, perf_subsys_id), + struct perf_cgroup, css); +} + +static inline bool +perf_cgroup_match(struct perf_event *event) +{ + struct perf_event_context *ctx = event->ctx; + struct perf_cpu_context *cpuctx = __get_cpu_context(ctx); + + return !event->cgrp || event->cgrp == cpuctx->cgrp; +} + +static inline void perf_get_cgroup(struct perf_event *event) +{ + css_get(&event->cgrp->css); +} + +static inline void perf_put_cgroup(struct perf_event *event) +{ + css_put(&event->cgrp->css); +} + +static inline void perf_detach_cgroup(struct perf_event *event) +{ + perf_put_cgroup(event); + event->cgrp = NULL; +} + +static inline int is_cgroup_event(struct perf_event *event) +{ + return event->cgrp != NULL; +} + +static inline u64 perf_cgroup_event_time(struct perf_event *event) +{ + struct perf_cgroup_info *t; + + t = per_cpu_ptr(event->cgrp->info, event->cpu); + return t->time; +} + +static inline void __update_cgrp_time(struct perf_cgroup *cgrp) +{ + struct perf_cgroup_info *info; + u64 now; + + now = perf_clock(); + + info = this_cpu_ptr(cgrp->info); + + info->time += now - info->timestamp; + info->timestamp = now; +} + +static inline void update_cgrp_time_from_cpuctx(struct perf_cpu_context *cpuctx) +{ + struct perf_cgroup *cgrp_out = cpuctx->cgrp; + if (cgrp_out) + __update_cgrp_time(cgrp_out); +} + +static inline void update_cgrp_time_from_event(struct perf_event *event) +{ + struct perf_cgroup *cgrp; + + /* + * ensure we access cgroup data only when needed and + * when we know the cgroup is pinned (css_get) + */ + if (!is_cgroup_event(event)) + return; + + cgrp = perf_cgroup_from_task(current); + /* + * Do not update time when cgroup is not active + */ + if (cgrp == event->cgrp) + __update_cgrp_time(event->cgrp); +} + +static inline void +perf_cgroup_set_timestamp(struct task_struct *task, + struct perf_event_context *ctx) +{ + struct perf_cgroup *cgrp; + struct perf_cgroup_info *info; + + /* + * ctx->lock held by caller + * ensure we do not access cgroup data + * unless we have the cgroup pinned (css_get) + */ + if (!task || !ctx->nr_cgroups) + return; + + cgrp = perf_cgroup_from_task(task); + info = this_cpu_ptr(cgrp->info); + info->timestamp = ctx->timestamp; +} + +#define PERF_CGROUP_SWOUT 0x1 /* cgroup switch out every event */ +#define PERF_CGROUP_SWIN 0x2 /* cgroup switch in events based on task */ + +/* + * reschedule events based on the cgroup constraint of task. + * + * mode SWOUT : schedule out everything + * mode SWIN : schedule in based on cgroup for next + */ +void perf_cgroup_switch(struct task_struct *task, int mode) +{ + struct perf_cpu_context *cpuctx; + struct pmu *pmu; + unsigned long flags; + + /* + * disable interrupts to avoid geting nr_cgroup + * changes via __perf_event_disable(). Also + * avoids preemption. + */ + local_irq_save(flags); + + /* + * we reschedule only in the presence of cgroup + * constrained events. + */ + rcu_read_lock(); + + list_for_each_entry_rcu(pmu, &pmus, entry) { + + cpuctx = this_cpu_ptr(pmu->pmu_cpu_context); + + perf_pmu_disable(cpuctx->ctx.pmu); + + /* + * perf_cgroup_events says at least one + * context on this CPU has cgroup events. + * + * ctx->nr_cgroups reports the number of cgroup + * events for a context. + */ + if (cpuctx->ctx.nr_cgroups > 0) { + + if (mode & PERF_CGROUP_SWOUT) { + cpu_ctx_sched_out(cpuctx, EVENT_ALL); + /* + * must not be done before ctxswout due + * to event_filter_match() in event_sched_out() + */ + cpuctx->cgrp = NULL; + } + + if (mode & PERF_CGROUP_SWIN) { + WARN_ON_ONCE(cpuctx->cgrp); + /* set cgrp before ctxsw in to + * allow event_filter_match() to not + * have to pass task around + */ + cpuctx->cgrp = perf_cgroup_from_task(task); + cpu_ctx_sched_in(cpuctx, EVENT_ALL, task); + } + } + + perf_pmu_enable(cpuctx->ctx.pmu); + } + + rcu_read_unlock(); + + local_irq_restore(flags); +} + +static inline void perf_cgroup_sched_out(struct task_struct *task) +{ + perf_cgroup_switch(task, PERF_CGROUP_SWOUT); +} + +static inline void perf_cgroup_sched_in(struct task_struct *task) +{ + perf_cgroup_switch(task, PERF_CGROUP_SWIN); +} + +static inline int perf_cgroup_connect(int fd, struct perf_event *event, + struct perf_event_attr *attr, + struct perf_event *group_leader) +{ + struct perf_cgroup *cgrp; + struct cgroup_subsys_state *css; + struct file *file; + int ret = 0, fput_needed; + + file = fget_light(fd, &fput_needed); + if (!file) + return -EBADF; + + css = cgroup_css_from_dir(file, perf_subsys_id); + if (IS_ERR(css)) { + ret = PTR_ERR(css); + goto out; + } + + cgrp = container_of(css, struct perf_cgroup, css); + event->cgrp = cgrp; + + /* must be done before we fput() the file */ + perf_get_cgroup(event); + + /* + * all events in a group must monitor + * the same cgroup because a task belongs + * to only one perf cgroup at a time + */ + if (group_leader && group_leader->cgrp != cgrp) { + perf_detach_cgroup(event); + ret = -EINVAL; + } +out: + fput_light(file, fput_needed); + return ret; +} + +static inline void +perf_cgroup_set_shadow_time(struct perf_event *event, u64 now) +{ + struct perf_cgroup_info *t; + t = per_cpu_ptr(event->cgrp->info, event->cpu); + event->shadow_ctx_time = now - t->timestamp; +} + +static inline void +perf_cgroup_defer_enabled(struct perf_event *event) +{ + /* + * when the current task's perf cgroup does not match + * the event's, we need to remember to call the + * perf_mark_enable() function the first time a task with + * a matching perf cgroup is scheduled in. + */ + if (is_cgroup_event(event) && !perf_cgroup_match(event)) + event->cgrp_defer_enabled = 1; +} + +static inline void +perf_cgroup_mark_enabled(struct perf_event *event, + struct perf_event_context *ctx) +{ + struct perf_event *sub; + u64 tstamp = perf_event_time(event); + + if (!event->cgrp_defer_enabled) + return; + + event->cgrp_defer_enabled = 0; + + event->tstamp_enabled = tstamp - event->total_time_enabled; + list_for_each_entry(sub, &event->sibling_list, group_entry) { + if (sub->state >= PERF_EVENT_STATE_INACTIVE) { + sub->tstamp_enabled = tstamp - sub->total_time_enabled; + sub->cgrp_defer_enabled = 0; + } + } +} +#else /* !CONFIG_CGROUP_PERF */ + +static inline bool +perf_cgroup_match(struct perf_event *event) +{ + return true; +} + +static inline void perf_detach_cgroup(struct perf_event *event) +{} + +static inline int is_cgroup_event(struct perf_event *event) +{ + return 0; +} + +static inline u64 perf_cgroup_event_cgrp_time(struct perf_event *event) +{ + return 0; +} + +static inline void update_cgrp_time_from_event(struct perf_event *event) +{ +} + +static inline void update_cgrp_time_from_cpuctx(struct perf_cpu_context *cpuctx) +{ +} + +static inline void perf_cgroup_sched_out(struct task_struct *task) +{ +} + +static inline void perf_cgroup_sched_in(struct task_struct *task) +{ +} + +static inline int perf_cgroup_connect(pid_t pid, struct perf_event *event, + struct perf_event_attr *attr, + struct perf_event *group_leader) +{ + return -EINVAL; +} + +static inline void +perf_cgroup_set_timestamp(struct task_struct *task, + struct perf_event_context *ctx) +{ +} + +void +perf_cgroup_switch(struct task_struct *task, struct task_struct *next) +{ +} + +static inline void +perf_cgroup_set_shadow_time(struct perf_event *event, u64 now) +{ +} + +static inline u64 perf_cgroup_event_time(struct perf_event *event) +{ + return 0; +} + +static inline void +perf_cgroup_defer_enabled(struct perf_event *event) +{ +} + +static inline void +perf_cgroup_mark_enabled(struct perf_event *event, + struct perf_event_context *ctx) +{ +} +#endif + +void perf_pmu_disable(struct pmu *pmu) +{ + int *count = this_cpu_ptr(pmu->pmu_disable_count); + if (!(*count)++) + pmu->pmu_disable(pmu); +} + +void perf_pmu_enable(struct pmu *pmu) +{ + int *count = this_cpu_ptr(pmu->pmu_disable_count); + if (!--(*count)) + pmu->pmu_enable(pmu); +} + +static DEFINE_PER_CPU(struct list_head, rotation_list); + +/* + * perf_pmu_rotate_start() and perf_rotate_context() are fully serialized + * because they're strictly cpu affine and rotate_start is called with IRQs + * disabled, while rotate_context is called from IRQ context. + */ +static void perf_pmu_rotate_start(struct pmu *pmu) +{ + struct perf_cpu_context *cpuctx = this_cpu_ptr(pmu->pmu_cpu_context); + struct list_head *head = &__get_cpu_var(rotation_list); + + WARN_ON(!irqs_disabled()); + + if (list_empty(&cpuctx->rotation_list)) + list_add(&cpuctx->rotation_list, head); +} + +static void get_ctx(struct perf_event_context *ctx) +{ + WARN_ON(!atomic_inc_not_zero(&ctx->refcount)); +} + +static void free_ctx(struct rcu_head *head) +{ + struct perf_event_context *ctx; + + ctx = container_of(head, struct perf_event_context, rcu_head); + kfree(ctx); +} + +static void put_ctx(struct perf_event_context *ctx) +{ + if (atomic_dec_and_test(&ctx->refcount)) { + if (ctx->parent_ctx) + put_ctx(ctx->parent_ctx); + if (ctx->task) + put_task_struct(ctx->task); + call_rcu(&ctx->rcu_head, free_ctx); + } +} + +static void unclone_ctx(struct perf_event_context *ctx) +{ + if (ctx->parent_ctx) { + put_ctx(ctx->parent_ctx); + ctx->parent_ctx = NULL; + } +} + +static u32 perf_event_pid(struct perf_event *event, struct task_struct *p) +{ + /* + * only top level events have the pid namespace they were created in + */ + if (event->parent) + event = event->parent; + + return task_tgid_nr_ns(p, event->ns); +} + +static u32 perf_event_tid(struct perf_event *event, struct task_struct *p) +{ + /* + * only top level events have the pid namespace they were created in + */ + if (event->parent) + event = event->parent; + + return task_pid_nr_ns(p, event->ns); +} + +/* + * If we inherit events we want to return the parent event id + * to userspace. + */ +static u64 primary_event_id(struct perf_event *event) +{ + u64 id = event->id; + + if (event->parent) + id = event->parent->id; + + return id; +} + +/* + * Get the perf_event_context for a task and lock it. + * This has to cope with with the fact that until it is locked, + * the context could get moved to another task. + */ +static struct perf_event_context * +perf_lock_task_context(struct task_struct *task, int ctxn, unsigned long *flags) +{ + struct perf_event_context *ctx; + + rcu_read_lock(); +retry: + ctx = rcu_dereference(task->perf_event_ctxp[ctxn]); + if (ctx) { + /* + * If this context is a clone of another, it might + * get swapped for another underneath us by + * perf_event_task_sched_out, though the + * rcu_read_lock() protects us from any context + * getting freed. Lock the context and check if it + * got swapped before we could get the lock, and retry + * if so. If we locked the right context, then it + * can't get swapped on us any more. + */ + raw_spin_lock_irqsave(&ctx->lock, *flags); + if (ctx != rcu_dereference(task->perf_event_ctxp[ctxn])) { + raw_spin_unlock_irqrestore(&ctx->lock, *flags); + goto retry; + } + + if (!atomic_inc_not_zero(&ctx->refcount)) { + raw_spin_unlock_irqrestore(&ctx->lock, *flags); + ctx = NULL; + } + } + rcu_read_unlock(); + return ctx; +} + +/* + * Get the context for a task and increment its pin_count so it + * can't get swapped to another task. This also increments its + * reference count so that the context can't get freed. + */ +static struct perf_event_context * +perf_pin_task_context(struct task_struct *task, int ctxn) +{ + struct perf_event_context *ctx; + unsigned long flags; + + ctx = perf_lock_task_context(task, ctxn, &flags); + if (ctx) { + ++ctx->pin_count; + raw_spin_unlock_irqrestore(&ctx->lock, flags); + } + return ctx; +} + +static void perf_unpin_context(struct perf_event_context *ctx) +{ + unsigned long flags; + + raw_spin_lock_irqsave(&ctx->lock, flags); + --ctx->pin_count; + raw_spin_unlock_irqrestore(&ctx->lock, flags); +} + +/* + * Update the record of the current time in a context. + */ +static void update_context_time(struct perf_event_context *ctx) +{ + u64 now = perf_clock(); + + ctx->time += now - ctx->timestamp; + ctx->timestamp = now; +} + +static u64 perf_event_time(struct perf_event *event) +{ + struct perf_event_context *ctx = event->ctx; + + if (is_cgroup_event(event)) + return perf_cgroup_event_time(event); + + return ctx ? ctx->time : 0; +} + +/* + * Update the total_time_enabled and total_time_running fields for a event. + */ +static void update_event_times(struct perf_event *event) +{ + struct perf_event_context *ctx = event->ctx; + u64 run_end; + + if (event->state < PERF_EVENT_STATE_INACTIVE || + event->group_leader->state < PERF_EVENT_STATE_INACTIVE) + return; + /* + * in cgroup mode, time_enabled represents + * the time the event was enabled AND active + * tasks were in the monitored cgroup. This is + * independent of the activity of the context as + * there may be a mix of cgroup and non-cgroup events. + * + * That is why we treat cgroup events differently + * here. + */ + if (is_cgroup_event(event)) + run_end = perf_event_time(event); + else if (ctx->is_active) + run_end = ctx->time; + else + run_end = event->tstamp_stopped; + + event->total_time_enabled = run_end - event->tstamp_enabled; + + if (event->state == PERF_EVENT_STATE_INACTIVE) + run_end = event->tstamp_stopped; + else + run_end = perf_event_time(event); + + event->total_time_running = run_end - event->tstamp_running; + +} + +/* + * Update total_time_enabled and total_time_running for all events in a group. + */ +static void update_group_times(struct perf_event *leader) +{ + struct perf_event *event; + + update_event_times(leader); + list_for_each_entry(event, &leader->sibling_list, group_entry) + update_event_times(event); +} + +static struct list_head * +ctx_group_list(struct perf_event *event, struct perf_event_context *ctx) +{ + if (event->attr.pinned) + return &ctx->pinned_groups; + else + return &ctx->flexible_groups; +} + +/* + * Add a event from the lists for its context. + * Must be called with ctx->mutex and ctx->lock held. + */ +static void +list_add_event(struct perf_event *event, struct perf_event_context *ctx) +{ + WARN_ON_ONCE(event->attach_state & PERF_ATTACH_CONTEXT); + event->attach_state |= PERF_ATTACH_CONTEXT; + + /* + * If we're a stand alone event or group leader, we go to the context + * list, group events are kept attached to the group so that + * perf_group_detach can, at all times, locate all siblings. + */ + if (event->group_leader == event) { + struct list_head *list; + + if (is_software_event(event)) + event->group_flags |= PERF_GROUP_SOFTWARE; + + list = ctx_group_list(event, ctx); + list_add_tail(&event->group_entry, list); + } + + if (is_cgroup_event(event)) + ctx->nr_cgroups++; + + list_add_rcu(&event->event_entry, &ctx->event_list); + if (!ctx->nr_events) + perf_pmu_rotate_start(ctx->pmu); + ctx->nr_events++; + if (event->attr.inherit_stat) + ctx->nr_stat++; +} + +/* + * Called at perf_event creation and when events are attached/detached from a + * group. + */ +static void perf_event__read_size(struct perf_event *event) +{ + int entry = sizeof(u64); /* value */ + int size = 0; + int nr = 1; + + if (event->attr.read_format & PERF_FORMAT_TOTAL_TIME_ENABLED) + size += sizeof(u64); + + if (event->attr.read_format & PERF_FORMAT_TOTAL_TIME_RUNNING) + size += sizeof(u64); + + if (event->attr.read_format & PERF_FORMAT_ID) + entry += sizeof(u64); + + if (event->attr.read_format & PERF_FORMAT_GROUP) { + nr += event->group_leader->nr_siblings; + size += sizeof(u64); + } + + size += entry * nr; + event->read_size = size; +} + +static void perf_event__header_size(struct perf_event *event) +{ + struct perf_sample_data *data; + u64 sample_type = event->attr.sample_type; + u16 size = 0; + + perf_event__read_size(event); + + if (sample_type & PERF_SAMPLE_IP) + size += sizeof(data->ip); + + if (sample_type & PERF_SAMPLE_ADDR) + size += sizeof(data->addr); + + if (sample_type & PERF_SAMPLE_PERIOD) + size += sizeof(data->period); + + if (sample_type & PERF_SAMPLE_READ) + size += event->read_size; + + event->header_size = size; +} + +static void perf_event__id_header_size(struct perf_event *event) +{ + struct perf_sample_data *data; + u64 sample_type = event->attr.sample_type; + u16 size = 0; + + if (sample_type & PERF_SAMPLE_TID) + size += sizeof(data->tid_entry); + + if (sample_type & PERF_SAMPLE_TIME) + size += sizeof(data->time); + + if (sample_type & PERF_SAMPLE_ID) + size += sizeof(data->id); + + if (sample_type & PERF_SAMPLE_STREAM_ID) + size += sizeof(data->stream_id); + + if (sample_type & PERF_SAMPLE_CPU) + size += sizeof(data->cpu_entry); + + event->id_header_size = size; +} + +static void perf_group_attach(struct perf_event *event) +{ + struct perf_event *group_leader = event->group_leader, *pos; + + /* + * We can have double attach due to group movement in perf_event_open. + */ + if (event->attach_state & PERF_ATTACH_GROUP) + return; + + event->attach_state |= PERF_ATTACH_GROUP; + + if (group_leader == event) + return; + + if (group_leader->group_flags & PERF_GROUP_SOFTWARE && + !is_software_event(event)) + group_leader->group_flags &= ~PERF_GROUP_SOFTWARE; + + list_add_tail(&event->group_entry, &group_leader->sibling_list); + group_leader->nr_siblings++; + + perf_event__header_size(group_leader); + + list_for_each_entry(pos, &group_leader->sibling_list, group_entry) + perf_event__header_size(pos); +} + +/* + * Remove a event from the lists for its context. + * Must be called with ctx->mutex and ctx->lock held. + */ +static void +list_del_event(struct perf_event *event, struct perf_event_context *ctx) +{ + struct perf_cpu_context *cpuctx; + /* + * We can have double detach due to exit/hot-unplug + close. + */ + if (!(event->attach_state & PERF_ATTACH_CONTEXT)) + return; + + event->attach_state &= ~PERF_ATTACH_CONTEXT; + + if (is_cgroup_event(event)) { + ctx->nr_cgroups--; + cpuctx = __get_cpu_context(ctx); + /* + * if there are no more cgroup events + * then cler cgrp to avoid stale pointer + * in update_cgrp_time_from_cpuctx() + */ + if (!ctx->nr_cgroups) + cpuctx->cgrp = NULL; + } + + ctx->nr_events--; + if (event->attr.inherit_stat) + ctx->nr_stat--; + + list_del_rcu(&event->event_entry); + + if (event->group_leader == event) + list_del_init(&event->group_entry); + + update_group_times(event); + + /* + * If event was in error state, then keep it + * that way, otherwise bogus counts will be + * returned on read(). The only way to get out + * of error state is by explicit re-enabling + * of the event + */ + if (event->state > PERF_EVENT_STATE_OFF) + event->state = PERF_EVENT_STATE_OFF; +} + +static void perf_group_detach(struct perf_event *event) +{ + struct perf_event *sibling, *tmp; + struct list_head *list = NULL; + + /* + * We can have double detach due to exit/hot-unplug + close. + */ + if (!(event->attach_state & PERF_ATTACH_GROUP)) + return; + + event->attach_state &= ~PERF_ATTACH_GROUP; + + /* + * If this is a sibling, remove it from its group. + */ + if (event->group_leader != event) { + list_del_init(&event->group_entry); + event->group_leader->nr_siblings--; + goto out; + } + + if (!list_empty(&event->group_entry)) + list = &event->group_entry; + + /* + * If this was a group event with sibling events then + * upgrade the siblings to singleton events by adding them + * to whatever list we are on. + */ + list_for_each_entry_safe(sibling, tmp, &event->sibling_list, group_entry) { + if (list) + list_move_tail(&sibling->group_entry, list); + sibling->group_leader = sibling; + + /* Inherit group flags from the previous leader */ + sibling->group_flags = event->group_flags; + } + +out: + perf_event__header_size(event->group_leader); + + list_for_each_entry(tmp, &event->group_leader->sibling_list, group_entry) + perf_event__header_size(tmp); +} + +static inline int +event_filter_match(struct perf_event *event) +{ + return (event->cpu == -1 || event->cpu == smp_processor_id()) + && perf_cgroup_match(event); +} + +static void +event_sched_out(struct perf_event *event, + struct perf_cpu_context *cpuctx, + struct perf_event_context *ctx) +{ + u64 tstamp = perf_event_time(event); + u64 delta; + /* + * An event which could not be activated because of + * filter mismatch still needs to have its timings + * maintained, otherwise bogus information is return + * via read() for time_enabled, time_running: + */ + if (event->state == PERF_EVENT_STATE_INACTIVE + && !event_filter_match(event)) { + delta = tstamp - event->tstamp_stopped; + event->tstamp_running += delta; + event->tstamp_stopped = tstamp; + } + + if (event->state != PERF_EVENT_STATE_ACTIVE) + return; + + event->state = PERF_EVENT_STATE_INACTIVE; + if (event->pending_disable) { + event->pending_disable = 0; + event->state = PERF_EVENT_STATE_OFF; + } + event->tstamp_stopped = tstamp; + event->pmu->del(event, 0); + event->oncpu = -1; + + if (!is_software_event(event)) + cpuctx->active_oncpu--; + ctx->nr_active--; + if (event->attr.exclusive || !cpuctx->active_oncpu) + cpuctx->exclusive = 0; +} + +static void +group_sched_out(struct perf_event *group_event, + struct perf_cpu_context *cpuctx, + struct perf_event_context *ctx) +{ + struct perf_event *event; + int state = group_event->state; + + event_sched_out(group_event, cpuctx, ctx); + + /* + * Schedule out siblings (if any): + */ + list_for_each_entry(event, &group_event->sibling_list, group_entry) + event_sched_out(event, cpuctx, ctx); + + if (state == PERF_EVENT_STATE_ACTIVE && group_event->attr.exclusive) + cpuctx->exclusive = 0; +} + +/* + * Cross CPU call to remove a performance event + * + * We disable the event on the hardware level first. After that we + * remove it from the context list. + */ +static int __perf_remove_from_context(void *info) +{ + struct perf_event *event = info; + struct perf_event_context *ctx = event->ctx; + struct perf_cpu_context *cpuctx = __get_cpu_context(ctx); + + raw_spin_lock(&ctx->lock); + event_sched_out(event, cpuctx, ctx); + list_del_event(event, ctx); + raw_spin_unlock(&ctx->lock); + + return 0; +} + + +/* + * Remove the event from a task's (or a CPU's) list of events. + * + * CPU events are removed with a smp call. For task events we only + * call when the task is on a CPU. + * + * If event->ctx is a cloned context, callers must make sure that + * every task struct that event->ctx->task could possibly point to + * remains valid. This is OK when called from perf_release since + * that only calls us on the top-level context, which can't be a clone. + * When called from perf_event_exit_task, it's OK because the + * context has been detached from its task. + */ +static void perf_remove_from_context(struct perf_event *event) +{ + struct perf_event_context *ctx = event->ctx; + struct task_struct *task = ctx->task; + + lockdep_assert_held(&ctx->mutex); + + if (!task) { + /* + * Per cpu events are removed via an smp call and + * the removal is always successful. + */ + cpu_function_call(event->cpu, __perf_remove_from_context, event); + return; + } + +retry: + if (!task_function_call(task, __perf_remove_from_context, event)) + return; + + raw_spin_lock_irq(&ctx->lock); + /* + * If we failed to find a running task, but find the context active now + * that we've acquired the ctx->lock, retry. + */ + if (ctx->is_active) { + raw_spin_unlock_irq(&ctx->lock); + goto retry; + } + + /* + * Since the task isn't running, its safe to remove the event, us + * holding the ctx->lock ensures the task won't get scheduled in. + */ + list_del_event(event, ctx); + raw_spin_unlock_irq(&ctx->lock); +} + +/* + * Cross CPU call to disable a performance event + */ +static int __perf_event_disable(void *info) +{ + struct perf_event *event = info; + struct perf_event_context *ctx = event->ctx; + struct perf_cpu_context *cpuctx = __get_cpu_context(ctx); + + /* + * If this is a per-task event, need to check whether this + * event's task is the current task on this cpu. + * + * Can trigger due to concurrent perf_event_context_sched_out() + * flipping contexts around. + */ + if (ctx->task && cpuctx->task_ctx != ctx) + return -EINVAL; + + raw_spin_lock(&ctx->lock); + + /* + * If the event is on, turn it off. + * If it is in error state, leave it in error state. + */ + if (event->state >= PERF_EVENT_STATE_INACTIVE) { + update_context_time(ctx); + update_cgrp_time_from_event(event); + update_group_times(event); + if (event == event->group_leader) + group_sched_out(event, cpuctx, ctx); + else + event_sched_out(event, cpuctx, ctx); + event->state = PERF_EVENT_STATE_OFF; + } + + raw_spin_unlock(&ctx->lock); + + return 0; +} + +/* + * Disable a event. + * + * If event->ctx is a cloned context, callers must make sure that + * every task struct that event->ctx->task could possibly point to + * remains valid. This condition is satisifed when called through + * perf_event_for_each_child or perf_event_for_each because they + * hold the top-level event's child_mutex, so any descendant that + * goes to exit will block in sync_child_event. + * When called from perf_pending_event it's OK because event->ctx + * is the current context on this CPU and preemption is disabled, + * hence we can't get into perf_event_task_sched_out for this context. + */ +void perf_event_disable(struct perf_event *event) +{ + struct perf_event_context *ctx = event->ctx; + struct task_struct *task = ctx->task; + + if (!task) { + /* + * Disable the event on the cpu that it's on + */ + cpu_function_call(event->cpu, __perf_event_disable, event); + return; + } + +retry: + if (!task_function_call(task, __perf_event_disable, event)) + return; + + raw_spin_lock_irq(&ctx->lock); + /* + * If the event is still active, we need to retry the cross-call. + */ + if (event->state == PERF_EVENT_STATE_ACTIVE) { + raw_spin_unlock_irq(&ctx->lock); + /* + * Reload the task pointer, it might have been changed by + * a concurrent perf_event_context_sched_out(). + */ + task = ctx->task; + goto retry; + } + + /* + * Since we have the lock this context can't be scheduled + * in, so we can change the state safely. + */ + if (event->state == PERF_EVENT_STATE_INACTIVE) { + update_group_times(event); + event->state = PERF_EVENT_STATE_OFF; + } + raw_spin_unlock_irq(&ctx->lock); +} + +static void perf_set_shadow_time(struct perf_event *event, + struct perf_event_context *ctx, + u64 tstamp) +{ + /* + * use the correct time source for the time snapshot + * + * We could get by without this by leveraging the + * fact that to get to this function, the caller + * has most likely already called update_context_time() + * and update_cgrp_time_xx() and thus both timestamp + * are identical (or very close). Given that tstamp is, + * already adjusted for cgroup, we could say that: + * tstamp - ctx->timestamp + * is equivalent to + * tstamp - cgrp->timestamp. + * + * Then, in perf_output_read(), the calculation would + * work with no changes because: + * - event is guaranteed scheduled in + * - no scheduled out in between + * - thus the timestamp would be the same + * + * But this is a bit hairy. + * + * So instead, we have an explicit cgroup call to remain + * within the time time source all along. We believe it + * is cleaner and simpler to understand. + */ + if (is_cgroup_event(event)) + perf_cgroup_set_shadow_time(event, tstamp); + else + event->shadow_ctx_time = tstamp - ctx->timestamp; +} + +#define MAX_INTERRUPTS (~0ULL) + +static void perf_log_throttle(struct perf_event *event, int enable); + +static int +event_sched_in(struct perf_event *event, + struct perf_cpu_context *cpuctx, + struct perf_event_context *ctx) +{ + u64 tstamp = perf_event_time(event); + + if (event->state <= PERF_EVENT_STATE_OFF) + return 0; + + event->state = PERF_EVENT_STATE_ACTIVE; + event->oncpu = smp_processor_id(); + + /* + * Unthrottle events, since we scheduled we might have missed several + * ticks already, also for a heavily scheduling task there is little + * guarantee it'll get a tick in a timely manner. + */ + if (unlikely(event->hw.interrupts == MAX_INTERRUPTS)) { + perf_log_throttle(event, 1); + event->hw.interrupts = 0; + } + + /* + * The new state must be visible before we turn it on in the hardware: + */ + smp_wmb(); + + if (event->pmu->add(event, PERF_EF_START)) { + event->state = PERF_EVENT_STATE_INACTIVE; + event->oncpu = -1; + return -EAGAIN; + } + + event->tstamp_running += tstamp - event->tstamp_stopped; + + perf_set_shadow_time(event, ctx, tstamp); + + if (!is_software_event(event)) + cpuctx->active_oncpu++; + ctx->nr_active++; + + if (event->attr.exclusive) + cpuctx->exclusive = 1; + + return 0; +} + +static int +group_sched_in(struct perf_event *group_event, + struct perf_cpu_context *cpuctx, + struct perf_event_context *ctx) +{ + struct perf_event *event, *partial_group = NULL; + struct pmu *pmu = group_event->pmu; + u64 now = ctx->time; + bool simulate = false; + + if (group_event->state == PERF_EVENT_STATE_OFF) + return 0; + + pmu->start_txn(pmu); + + if (event_sched_in(group_event, cpuctx, ctx)) { + pmu->cancel_txn(pmu); + return -EAGAIN; + } + + /* + * Schedule in siblings as one group (if any): + */ + list_for_each_entry(event, &group_event->sibling_list, group_entry) { + if (event_sched_in(event, cpuctx, ctx)) { + partial_group = event; + goto group_error; + } + } + + if (!pmu->commit_txn(pmu)) + return 0; + +group_error: + /* + * Groups can be scheduled in as one unit only, so undo any + * partial group before returning: + * The events up to the failed event are scheduled out normally, + * tstamp_stopped will be updated. + * + * The failed events and the remaining siblings need to have + * their timings updated as if they had gone thru event_sched_in() + * and event_sched_out(). This is required to get consistent timings + * across the group. This also takes care of the case where the group + * could never be scheduled by ensuring tstamp_stopped is set to mark + * the time the event was actually stopped, such that time delta + * calculation in update_event_times() is correct. + */ + list_for_each_entry(event, &group_event->sibling_list, group_entry) { + if (event == partial_group) + simulate = true; + + if (simulate) { + event->tstamp_running += now - event->tstamp_stopped; + event->tstamp_stopped = now; + } else { + event_sched_out(event, cpuctx, ctx); + } + } + event_sched_out(group_event, cpuctx, ctx); + + pmu->cancel_txn(pmu); + + return -EAGAIN; +} + +/* + * Work out whether we can put this event group on the CPU now. + */ +static int group_can_go_on(struct perf_event *event, + struct perf_cpu_context *cpuctx, + int can_add_hw) +{ + /* + * Groups consisting entirely of software events can always go on. + */ + if (event->group_flags & PERF_GROUP_SOFTWARE) + return 1; + /* + * If an exclusive group is already on, no other hardware + * events can go on. + */ + if (cpuctx->exclusive) + return 0; + /* + * If this group is exclusive and there are already + * events on the CPU, it can't go on. + */ + if (event->attr.exclusive && cpuctx->active_oncpu) + return 0; + /* + * Otherwise, try to add it if all previous groups were able + * to go on. + */ + return can_add_hw; +} + +static void add_event_to_ctx(struct perf_event *event, + struct perf_event_context *ctx) +{ + u64 tstamp = perf_event_time(event); + + list_add_event(event, ctx); + perf_group_attach(event); + event->tstamp_enabled = tstamp; + event->tstamp_running = tstamp; + event->tstamp_stopped = tstamp; +} + +static void perf_event_context_sched_in(struct perf_event_context *ctx, + struct task_struct *tsk); + +/* + * Cross CPU call to install and enable a performance event + * + * Must be called with ctx->mutex held + */ +static int __perf_install_in_context(void *info) +{ + struct perf_event *event = info; + struct perf_event_context *ctx = event->ctx; + struct perf_event *leader = event->group_leader; + struct perf_cpu_context *cpuctx = __get_cpu_context(ctx); + int err; + + /* + * In case we're installing a new context to an already running task, + * could also happen before perf_event_task_sched_in() on architectures + * which do context switches with IRQs enabled. + */ + if (ctx->task && !cpuctx->task_ctx) + perf_event_context_sched_in(ctx, ctx->task); + + raw_spin_lock(&ctx->lock); + ctx->is_active = 1; + update_context_time(ctx); + /* + * update cgrp time only if current cgrp + * matches event->cgrp. Must be done before + * calling add_event_to_ctx() + */ + update_cgrp_time_from_event(event); + + add_event_to_ctx(event, ctx); + + if (!event_filter_match(event)) + goto unlock; + + /* + * Don't put the event on if it is disabled or if + * it is in a group and the group isn't on. + */ + if (event->state != PERF_EVENT_STATE_INACTIVE || + (leader != event && leader->state != PERF_EVENT_STATE_ACTIVE)) + goto unlock; + + /* + * An exclusive event can't go on if there are already active + * hardware events, and no hardware event can go on if there + * is already an exclusive event on. + */ + if (!group_can_go_on(event, cpuctx, 1)) + err = -EEXIST; + else + err = event_sched_in(event, cpuctx, ctx); + + if (err) { + /* + * This event couldn't go on. If it is in a group + * then we have to pull the whole group off. + * If the event group is pinned then put it in error state. + */ + if (leader != event) + group_sched_out(leader, cpuctx, ctx); + if (leader->attr.pinned) { + update_group_times(leader); + leader->state = PERF_EVENT_STATE_ERROR; + } + } + +unlock: + raw_spin_unlock(&ctx->lock); + + return 0; +} + +/* + * Attach a performance event to a context + * + * First we add the event to the list with the hardware enable bit + * in event->hw_config cleared. + * + * If the event is attached to a task which is on a CPU we use a smp + * call to enable it in the task context. The task might have been + * scheduled away, but we check this in the smp call again. + */ +static void +perf_install_in_context(struct perf_event_context *ctx, + struct perf_event *event, + int cpu) +{ + struct task_struct *task = ctx->task; + + lockdep_assert_held(&ctx->mutex); + + event->ctx = ctx; + + if (!task) { + /* + * Per cpu events are installed via an smp call and + * the install is always successful. + */ + cpu_function_call(cpu, __perf_install_in_context, event); + return; + } + +retry: + if (!task_function_call(task, __perf_install_in_context, event)) + return; + + raw_spin_lock_irq(&ctx->lock); + /* + * If we failed to find a running task, but find the context active now + * that we've acquired the ctx->lock, retry. + */ + if (ctx->is_active) { + raw_spin_unlock_irq(&ctx->lock); + goto retry; + } + + /* + * Since the task isn't running, its safe to add the event, us holding + * the ctx->lock ensures the task won't get scheduled in. + */ + add_event_to_ctx(event, ctx); + raw_spin_unlock_irq(&ctx->lock); +} + +/* + * Put a event into inactive state and update time fields. + * Enabling the leader of a group effectively enables all + * the group members that aren't explicitly disabled, so we + * have to update their ->tstamp_enabled also. + * Note: this works for group members as well as group leaders + * since the non-leader members' sibling_lists will be empty. + */ +static void __perf_event_mark_enabled(struct perf_event *event, + struct perf_event_context *ctx) +{ + struct perf_event *sub; + u64 tstamp = perf_event_time(event); + + event->state = PERF_EVENT_STATE_INACTIVE; + event->tstamp_enabled = tstamp - event->total_time_enabled; + list_for_each_entry(sub, &event->sibling_list, group_entry) { + if (sub->state >= PERF_EVENT_STATE_INACTIVE) + sub->tstamp_enabled = tstamp - sub->total_time_enabled; + } +} + +/* + * Cross CPU call to enable a performance event + */ +static int __perf_event_enable(void *info) +{ + struct perf_event *event = info; + struct perf_event_context *ctx = event->ctx; + struct perf_event *leader = event->group_leader; + struct perf_cpu_context *cpuctx = __get_cpu_context(ctx); + int err; + + if (WARN_ON_ONCE(!ctx->is_active)) + return -EINVAL; + + raw_spin_lock(&ctx->lock); + update_context_time(ctx); + + if (event->state >= PERF_EVENT_STATE_INACTIVE) + goto unlock; + + /* + * set current task's cgroup time reference point + */ + perf_cgroup_set_timestamp(current, ctx); + + __perf_event_mark_enabled(event, ctx); + + if (!event_filter_match(event)) { + if (is_cgroup_event(event)) + perf_cgroup_defer_enabled(event); + goto unlock; + } + + /* + * If the event is in a group and isn't the group leader, + * then don't put it on unless the group is on. + */ + if (leader != event && leader->state != PERF_EVENT_STATE_ACTIVE) + goto unlock; + + if (!group_can_go_on(event, cpuctx, 1)) { + err = -EEXIST; + } else { + if (event == leader) + err = group_sched_in(event, cpuctx, ctx); + else + err = event_sched_in(event, cpuctx, ctx); + } + + if (err) { + /* + * If this event can't go on and it's part of a + * group, then the whole group has to come off. + */ + if (leader != event) + group_sched_out(leader, cpuctx, ctx); + if (leader->attr.pinned) { + update_group_times(leader); + leader->state = PERF_EVENT_STATE_ERROR; + } + } + +unlock: + raw_spin_unlock(&ctx->lock); + + return 0; +} + +/* + * Enable a event. + * + * If event->ctx is a cloned context, callers must make sure that + * every task struct that event->ctx->task could possibly point to + * remains valid. This condition is satisfied when called through + * perf_event_for_each_child or perf_event_for_each as described + * for perf_event_disable. + */ +void perf_event_enable(struct perf_event *event) +{ + struct perf_event_context *ctx = event->ctx; + struct task_struct *task = ctx->task; + + if (!task) { + /* + * Enable the event on the cpu that it's on + */ + cpu_function_call(event->cpu, __perf_event_enable, event); + return; + } + + raw_spin_lock_irq(&ctx->lock); + if (event->state >= PERF_EVENT_STATE_INACTIVE) + goto out; + + /* + * If the event is in error state, clear that first. + * That way, if we see the event in error state below, we + * know that it has gone back into error state, as distinct + * from the task having been scheduled away before the + * cross-call arrived. + */ + if (event->state == PERF_EVENT_STATE_ERROR) + event->state = PERF_EVENT_STATE_OFF; + +retry: + if (!ctx->is_active) { + __perf_event_mark_enabled(event, ctx); + goto out; + } + + raw_spin_unlock_irq(&ctx->lock); + + if (!task_function_call(task, __perf_event_enable, event)) + return; + + raw_spin_lock_irq(&ctx->lock); + + /* + * If the context is active and the event is still off, + * we need to retry the cross-call. + */ + if (ctx->is_active && event->state == PERF_EVENT_STATE_OFF) { + /* + * task could have been flipped by a concurrent + * perf_event_context_sched_out() + */ + task = ctx->task; + goto retry; + } + +out: + raw_spin_unlock_irq(&ctx->lock); +} + +static int perf_event_refresh(struct perf_event *event, int refresh) +{ + /* + * not supported on inherited events + */ + if (event->attr.inherit || !is_sampling_event(event)) + return -EINVAL; + + atomic_add(refresh, &event->event_limit); + perf_event_enable(event); + + return 0; +} + +static void ctx_sched_out(struct perf_event_context *ctx, + struct perf_cpu_context *cpuctx, + enum event_type_t event_type) +{ + struct perf_event *event; + + raw_spin_lock(&ctx->lock); + perf_pmu_disable(ctx->pmu); + ctx->is_active = 0; + if (likely(!ctx->nr_events)) + goto out; + update_context_time(ctx); + update_cgrp_time_from_cpuctx(cpuctx); + + if (!ctx->nr_active) + goto out; + + if (event_type & EVENT_PINNED) { + list_for_each_entry(event, &ctx->pinned_groups, group_entry) + group_sched_out(event, cpuctx, ctx); + } + + if (event_type & EVENT_FLEXIBLE) { + list_for_each_entry(event, &ctx->flexible_groups, group_entry) + group_sched_out(event, cpuctx, ctx); + } +out: + perf_pmu_enable(ctx->pmu); + raw_spin_unlock(&ctx->lock); +} + +/* + * Test whether two contexts are equivalent, i.e. whether they + * have both been cloned from the same version of the same context + * and they both have the same number of enabled events. + * If the number of enabled events is the same, then the set + * of enabled events should be the same, because these are both + * inherited contexts, therefore we can't access individual events + * in them directly with an fd; we can only enable/disable all + * events via prctl, or enable/disable all events in a family + * via ioctl, which will have the same effect on both contexts. + */ +static int context_equiv(struct perf_event_context *ctx1, + struct perf_event_context *ctx2) +{ + return ctx1->parent_ctx && ctx1->parent_ctx == ctx2->parent_ctx + && ctx1->parent_gen == ctx2->parent_gen + && !ctx1->pin_count && !ctx2->pin_count; +} + +static void __perf_event_sync_stat(struct perf_event *event, + struct perf_event *next_event) +{ + u64 value; + + if (!event->attr.inherit_stat) + return; + + /* + * Update the event value, we cannot use perf_event_read() + * because we're in the middle of a context switch and have IRQs + * disabled, which upsets smp_call_function_single(), however + * we know the event must be on the current CPU, therefore we + * don't need to use it. + */ + switch (event->state) { + case PERF_EVENT_STATE_ACTIVE: + event->pmu->read(event); + /* fall-through */ + + case PERF_EVENT_STATE_INACTIVE: + update_event_times(event); + break; + + default: + break; + } + + /* + * In order to keep per-task stats reliable we need to flip the event + * values when we flip the contexts. + */ + value = local64_read(&next_event->count); + value = local64_xchg(&event->count, value); + local64_set(&next_event->count, value); + + swap(event->total_time_enabled, next_event->total_time_enabled); + swap(event->total_time_running, next_event->total_time_running); + + /* + * Since we swizzled the values, update the user visible data too. + */ + perf_event_update_userpage(event); + perf_event_update_userpage(next_event); +} + +#define list_next_entry(pos, member) \ + list_entry(pos->member.next, typeof(*pos), member) + +static void perf_event_sync_stat(struct perf_event_context *ctx, + struct perf_event_context *next_ctx) +{ + struct perf_event *event, *next_event; + + if (!ctx->nr_stat) + return; + + update_context_time(ctx); + + event = list_first_entry(&ctx->event_list, + struct perf_event, event_entry); + + next_event = list_first_entry(&next_ctx->event_list, + struct perf_event, event_entry); + + while (&event->event_entry != &ctx->event_list && + &next_event->event_entry != &next_ctx->event_list) { + + __perf_event_sync_stat(event, next_event); + + event = list_next_entry(event, event_entry); + next_event = list_next_entry(next_event, event_entry); + } +} + +static void perf_event_context_sched_out(struct task_struct *task, int ctxn, + struct task_struct *next) +{ + struct perf_event_context *ctx = task->perf_event_ctxp[ctxn]; + struct perf_event_context *next_ctx; + struct perf_event_context *parent; + struct perf_cpu_context *cpuctx; + int do_switch = 1; + + if (likely(!ctx)) + return; + + cpuctx = __get_cpu_context(ctx); + if (!cpuctx->task_ctx) + return; + + rcu_read_lock(); + parent = rcu_dereference(ctx->parent_ctx); + next_ctx = next->perf_event_ctxp[ctxn]; + if (parent && next_ctx && + rcu_dereference(next_ctx->parent_ctx) == parent) { + /* + * Looks like the two contexts are clones, so we might be + * able to optimize the context switch. We lock both + * contexts and check that they are clones under the + * lock (including re-checking that neither has been + * uncloned in the meantime). It doesn't matter which + * order we take the locks because no other cpu could + * be trying to lock both of these tasks. + */ + raw_spin_lock(&ctx->lock); + raw_spin_lock_nested(&next_ctx->lock, SINGLE_DEPTH_NESTING); + if (context_equiv(ctx, next_ctx)) { + /* + * XXX do we need a memory barrier of sorts + * wrt to rcu_dereference() of perf_event_ctxp + */ + task->perf_event_ctxp[ctxn] = next_ctx; + next->perf_event_ctxp[ctxn] = ctx; + ctx->task = next; + next_ctx->task = task; + do_switch = 0; + + perf_event_sync_stat(ctx, next_ctx); + } + raw_spin_unlock(&next_ctx->lock); + raw_spin_unlock(&ctx->lock); + } + rcu_read_unlock(); + + if (do_switch) { + ctx_sched_out(ctx, cpuctx, EVENT_ALL); + cpuctx->task_ctx = NULL; + } +} + +#define for_each_task_context_nr(ctxn) \ + for ((ctxn) = 0; (ctxn) < perf_nr_task_contexts; (ctxn)++) + +/* + * Called from scheduler to remove the events of the current task, + * with interrupts disabled. + * + * We stop each event and update the event value in event->count. + * + * This does not protect us against NMI, but disable() + * sets the disabled bit in the control field of event _before_ + * accessing the event control register. If a NMI hits, then it will + * not restart the event. + */ +void __perf_event_task_sched_out(struct task_struct *task, + struct task_struct *next) +{ + int ctxn; + + for_each_task_context_nr(ctxn) + perf_event_context_sched_out(task, ctxn, next); + + /* + * if cgroup events exist on this CPU, then we need + * to check if we have to switch out PMU state. + * cgroup event are system-wide mode only + */ + if (atomic_read(&__get_cpu_var(perf_cgroup_events))) + perf_cgroup_sched_out(task); +} + +static void task_ctx_sched_out(struct perf_event_context *ctx, + enum event_type_t event_type) +{ + struct perf_cpu_context *cpuctx = __get_cpu_context(ctx); + + if (!cpuctx->task_ctx) + return; + + if (WARN_ON_ONCE(ctx != cpuctx->task_ctx)) + return; + + ctx_sched_out(ctx, cpuctx, event_type); + cpuctx->task_ctx = NULL; +} + +/* + * Called with IRQs disabled + */ +static void cpu_ctx_sched_out(struct perf_cpu_context *cpuctx, + enum event_type_t event_type) +{ + ctx_sched_out(&cpuctx->ctx, cpuctx, event_type); +} + +static void +ctx_pinned_sched_in(struct perf_event_context *ctx, + struct perf_cpu_context *cpuctx) +{ + struct perf_event *event; + + list_for_each_entry(event, &ctx->pinned_groups, group_entry) { + if (event->state <= PERF_EVENT_STATE_OFF) + continue; + if (!event_filter_match(event)) + continue; + + /* may need to reset tstamp_enabled */ + if (is_cgroup_event(event)) + perf_cgroup_mark_enabled(event, ctx); + + if (group_can_go_on(event, cpuctx, 1)) + group_sched_in(event, cpuctx, ctx); + + /* + * If this pinned group hasn't been scheduled, + * put it in error state. + */ + if (event->state == PERF_EVENT_STATE_INACTIVE) { + update_group_times(event); + event->state = PERF_EVENT_STATE_ERROR; + } + } +} + +static void +ctx_flexible_sched_in(struct perf_event_context *ctx, + struct perf_cpu_context *cpuctx) +{ + struct perf_event *event; + int can_add_hw = 1; + + list_for_each_entry(event, &ctx->flexible_groups, group_entry) { + /* Ignore events in OFF or ERROR state */ + if (event->state <= PERF_EVENT_STATE_OFF) + continue; + /* + * Listen to the 'cpu' scheduling filter constraint + * of events: + */ + if (!event_filter_match(event)) + continue; + + /* may need to reset tstamp_enabled */ + if (is_cgroup_event(event)) + perf_cgroup_mark_enabled(event, ctx); + + if (group_can_go_on(event, cpuctx, can_add_hw)) { + if (group_sched_in(event, cpuctx, ctx)) + can_add_hw = 0; + } + } +} + +static void +ctx_sched_in(struct perf_event_context *ctx, + struct perf_cpu_context *cpuctx, + enum event_type_t event_type, + struct task_struct *task) +{ + u64 now; + + raw_spin_lock(&ctx->lock); + ctx->is_active = 1; + if (likely(!ctx->nr_events)) + goto out; + + now = perf_clock(); + ctx->timestamp = now; + perf_cgroup_set_timestamp(task, ctx); + /* + * First go through the list and put on any pinned groups + * in order to give them the best chance of going on. + */ + if (event_type & EVENT_PINNED) + ctx_pinned_sched_in(ctx, cpuctx); + + /* Then walk through the lower prio flexible groups */ + if (event_type & EVENT_FLEXIBLE) + ctx_flexible_sched_in(ctx, cpuctx); + +out: + raw_spin_unlock(&ctx->lock); +} + +static void cpu_ctx_sched_in(struct perf_cpu_context *cpuctx, + enum event_type_t event_type, + struct task_struct *task) +{ + struct perf_event_context *ctx = &cpuctx->ctx; + + ctx_sched_in(ctx, cpuctx, event_type, task); +} + +static void task_ctx_sched_in(struct perf_event_context *ctx, + enum event_type_t event_type) +{ + struct perf_cpu_context *cpuctx; + + cpuctx = __get_cpu_context(ctx); + if (cpuctx->task_ctx == ctx) + return; + + ctx_sched_in(ctx, cpuctx, event_type, NULL); + cpuctx->task_ctx = ctx; +} + +static void perf_event_context_sched_in(struct perf_event_context *ctx, + struct task_struct *task) +{ + struct perf_cpu_context *cpuctx; + + cpuctx = __get_cpu_context(ctx); + if (cpuctx->task_ctx == ctx) + return; + + perf_pmu_disable(ctx->pmu); + /* + * We want to keep the following priority order: + * cpu pinned (that don't need to move), task pinned, + * cpu flexible, task flexible. + */ + cpu_ctx_sched_out(cpuctx, EVENT_FLEXIBLE); + + ctx_sched_in(ctx, cpuctx, EVENT_PINNED, task); + cpu_ctx_sched_in(cpuctx, EVENT_FLEXIBLE, task); + ctx_sched_in(ctx, cpuctx, EVENT_FLEXIBLE, task); + + cpuctx->task_ctx = ctx; + + /* + * Since these rotations are per-cpu, we need to ensure the + * cpu-context we got scheduled on is actually rotating. + */ + perf_pmu_rotate_start(ctx->pmu); + perf_pmu_enable(ctx->pmu); +} + +/* + * Called from scheduler to add the events of the current task + * with interrupts disabled. + * + * We restore the event value and then enable it. + * + * This does not protect us against NMI, but enable() + * sets the enabled bit in the control field of event _before_ + * accessing the event control register. If a NMI hits, then it will + * keep the event running. + */ +void __perf_event_task_sched_in(struct task_struct *task) +{ + struct perf_event_context *ctx; + int ctxn; + + for_each_task_context_nr(ctxn) { + ctx = task->perf_event_ctxp[ctxn]; + if (likely(!ctx)) + continue; + + perf_event_context_sched_in(ctx, task); + } + /* + * if cgroup events exist on this CPU, then we need + * to check if we have to switch in PMU state. + * cgroup event are system-wide mode only + */ + if (atomic_read(&__get_cpu_var(perf_cgroup_events))) + perf_cgroup_sched_in(task); +} + +static u64 perf_calculate_period(struct perf_event *event, u64 nsec, u64 count) +{ + u64 frequency = event->attr.sample_freq; + u64 sec = NSEC_PER_SEC; + u64 divisor, dividend; + + int count_fls, nsec_fls, frequency_fls, sec_fls; + + count_fls = fls64(count); + nsec_fls = fls64(nsec); + frequency_fls = fls64(frequency); + sec_fls = 30; + + /* + * We got @count in @nsec, with a target of sample_freq HZ + * the target period becomes: + * + * @count * 10^9 + * period = ------------------- + * @nsec * sample_freq + * + */ + + /* + * Reduce accuracy by one bit such that @a and @b converge + * to a similar magnitude. + */ +#define REDUCE_FLS(a, b) \ +do { \ + if (a##_fls > b##_fls) { \ + a >>= 1; \ + a##_fls--; \ + } else { \ + b >>= 1; \ + b##_fls--; \ + } \ +} while (0) + + /* + * Reduce accuracy until either term fits in a u64, then proceed with + * the other, so that finally we can do a u64/u64 division. + */ + while (count_fls + sec_fls > 64 && nsec_fls + frequency_fls > 64) { + REDUCE_FLS(nsec, frequency); + REDUCE_FLS(sec, count); + } + + if (count_fls + sec_fls > 64) { + divisor = nsec * frequency; + + while (count_fls + sec_fls > 64) { + REDUCE_FLS(count, sec); + divisor >>= 1; + } + + dividend = count * sec; + } else { + dividend = count * sec; + + while (nsec_fls + frequency_fls > 64) { + REDUCE_FLS(nsec, frequency); + dividend >>= 1; + } + + divisor = nsec * frequency; + } + + if (!divisor) + return dividend; + + return div64_u64(dividend, divisor); +} + +static void perf_adjust_period(struct perf_event *event, u64 nsec, u64 count) +{ + struct hw_perf_event *hwc = &event->hw; + s64 period, sample_period; + s64 delta; + + period = perf_calculate_period(event, nsec, count); + + delta = (s64)(period - hwc->sample_period); + delta = (delta + 7) / 8; /* low pass filter */ + + sample_period = hwc->sample_period + delta; + + if (!sample_period) + sample_period = 1; + + hwc->sample_period = sample_period; + + if (local64_read(&hwc->period_left) > 8*sample_period) { + event->pmu->stop(event, PERF_EF_UPDATE); + local64_set(&hwc->period_left, 0); + event->pmu->start(event, PERF_EF_RELOAD); + } +} + +static void perf_ctx_adjust_freq(struct perf_event_context *ctx, u64 period) +{ + struct perf_event *event; + struct hw_perf_event *hwc; + u64 interrupts, now; + s64 delta; + + raw_spin_lock(&ctx->lock); + list_for_each_entry_rcu(event, &ctx->event_list, event_entry) { + if (event->state != PERF_EVENT_STATE_ACTIVE) + continue; + + if (!event_filter_match(event)) + continue; + + hwc = &event->hw; + + interrupts = hwc->interrupts; + hwc->interrupts = 0; + + /* + * unthrottle events on the tick + */ + if (interrupts == MAX_INTERRUPTS) { + perf_log_throttle(event, 1); + event->pmu->start(event, 0); + } + + if (!event->attr.freq || !event->attr.sample_freq) + continue; + + event->pmu->read(event); + now = local64_read(&event->count); + delta = now - hwc->freq_count_stamp; + hwc->freq_count_stamp = now; + + if (delta > 0) + perf_adjust_period(event, period, delta); + } + raw_spin_unlock(&ctx->lock); +} + +/* + * Round-robin a context's events: + */ +static void rotate_ctx(struct perf_event_context *ctx) +{ + raw_spin_lock(&ctx->lock); + + /* + * Rotate the first entry last of non-pinned groups. Rotation might be + * disabled by the inheritance code. + */ + if (!ctx->rotate_disable) + list_rotate_left(&ctx->flexible_groups); + + raw_spin_unlock(&ctx->lock); +} + +/* + * perf_pmu_rotate_start() and perf_rotate_context() are fully serialized + * because they're strictly cpu affine and rotate_start is called with IRQs + * disabled, while rotate_context is called from IRQ context. + */ +static void perf_rotate_context(struct perf_cpu_context *cpuctx) +{ + u64 interval = (u64)cpuctx->jiffies_interval * TICK_NSEC; + struct perf_event_context *ctx = NULL; + int rotate = 0, remove = 1; + + if (cpuctx->ctx.nr_events) { + remove = 0; + if (cpuctx->ctx.nr_events != cpuctx->ctx.nr_active) + rotate = 1; + } + + ctx = cpuctx->task_ctx; + if (ctx && ctx->nr_events) { + remove = 0; + if (ctx->nr_events != ctx->nr_active) + rotate = 1; + } + + perf_pmu_disable(cpuctx->ctx.pmu); + perf_ctx_adjust_freq(&cpuctx->ctx, interval); + if (ctx) + perf_ctx_adjust_freq(ctx, interval); + + if (!rotate) + goto done; + + cpu_ctx_sched_out(cpuctx, EVENT_FLEXIBLE); + if (ctx) + task_ctx_sched_out(ctx, EVENT_FLEXIBLE); + + rotate_ctx(&cpuctx->ctx); + if (ctx) + rotate_ctx(ctx); + + cpu_ctx_sched_in(cpuctx, EVENT_FLEXIBLE, current); + if (ctx) + task_ctx_sched_in(ctx, EVENT_FLEXIBLE); + +done: + if (remove) + list_del_init(&cpuctx->rotation_list); + + perf_pmu_enable(cpuctx->ctx.pmu); +} + +void perf_event_task_tick(void) +{ + struct list_head *head = &__get_cpu_var(rotation_list); + struct perf_cpu_context *cpuctx, *tmp; + + WARN_ON(!irqs_disabled()); + + list_for_each_entry_safe(cpuctx, tmp, head, rotation_list) { + if (cpuctx->jiffies_interval == 1 || + !(jiffies % cpuctx->jiffies_interval)) + perf_rotate_context(cpuctx); + } +} + +static int event_enable_on_exec(struct perf_event *event, + struct perf_event_context *ctx) +{ + if (!event->attr.enable_on_exec) + return 0; + + event->attr.enable_on_exec = 0; + if (event->state >= PERF_EVENT_STATE_INACTIVE) + return 0; + + __perf_event_mark_enabled(event, ctx); + + return 1; +} + +/* + * Enable all of a task's events that have been marked enable-on-exec. + * This expects task == current. + */ +static void perf_event_enable_on_exec(struct perf_event_context *ctx) +{ + struct perf_event *event; + unsigned long flags; + int enabled = 0; + int ret; + + local_irq_save(flags); + if (!ctx || !ctx->nr_events) + goto out; + + /* + * We must ctxsw out cgroup events to avoid conflict + * when invoking perf_task_event_sched_in() later on + * in this function. Otherwise we end up trying to + * ctxswin cgroup events which are already scheduled + * in. + */ + perf_cgroup_sched_out(current); + task_ctx_sched_out(ctx, EVENT_ALL); + + raw_spin_lock(&ctx->lock); + + list_for_each_entry(event, &ctx->pinned_groups, group_entry) { + ret = event_enable_on_exec(event, ctx); + if (ret) + enabled = 1; + } + + list_for_each_entry(event, &ctx->flexible_groups, group_entry) { + ret = event_enable_on_exec(event, ctx); + if (ret) + enabled = 1; + } + + /* + * Unclone this context if we enabled any event. + */ + if (enabled) + unclone_ctx(ctx); + + raw_spin_unlock(&ctx->lock); + + /* + * Also calls ctxswin for cgroup events, if any: + */ + perf_event_context_sched_in(ctx, ctx->task); +out: + local_irq_restore(flags); +} + +/* + * Cross CPU call to read the hardware event + */ +static void __perf_event_read(void *info) +{ + struct perf_event *event = info; + struct perf_event_context *ctx = event->ctx; + struct perf_cpu_context *cpuctx = __get_cpu_context(ctx); + + /* + * If this is a task context, we need to check whether it is + * the current task context of this cpu. If not it has been + * scheduled out before the smp call arrived. In that case + * event->count would have been updated to a recent sample + * when the event was scheduled out. + */ + if (ctx->task && cpuctx->task_ctx != ctx) + return; + + raw_spin_lock(&ctx->lock); + if (ctx->is_active) { + update_context_time(ctx); + update_cgrp_time_from_event(event); + } + update_event_times(event); + if (event->state == PERF_EVENT_STATE_ACTIVE) + event->pmu->read(event); + raw_spin_unlock(&ctx->lock); +} + +static inline u64 perf_event_count(struct perf_event *event) +{ + return local64_read(&event->count) + atomic64_read(&event->child_count); +} + +static u64 perf_event_read(struct perf_event *event) +{ + /* + * If event is enabled and currently active on a CPU, update the + * value in the event structure: + */ + if (event->state == PERF_EVENT_STATE_ACTIVE) { + smp_call_function_single(event->oncpu, + __perf_event_read, event, 1); + } else if (event->state == PERF_EVENT_STATE_INACTIVE) { + struct perf_event_context *ctx = event->ctx; + unsigned long flags; + + raw_spin_lock_irqsave(&ctx->lock, flags); + /* + * may read while context is not active + * (e.g., thread is blocked), in that case + * we cannot update context time + */ + if (ctx->is_active) { + update_context_time(ctx); + update_cgrp_time_from_event(event); + } + update_event_times(event); + raw_spin_unlock_irqrestore(&ctx->lock, flags); + } + + return perf_event_count(event); +} + +/* + * Callchain support + */ + +struct callchain_cpus_entries { + struct rcu_head rcu_head; + struct perf_callchain_entry *cpu_entries[0]; +}; + +static DEFINE_PER_CPU(int, callchain_recursion[PERF_NR_CONTEXTS]); +static atomic_t nr_callchain_events; +static DEFINE_MUTEX(callchain_mutex); +struct callchain_cpus_entries *callchain_cpus_entries; + + +__weak void perf_callchain_kernel(struct perf_callchain_entry *entry, + struct pt_regs *regs) +{ +} + +__weak void perf_callchain_user(struct perf_callchain_entry *entry, + struct pt_regs *regs) +{ +} + +static void release_callchain_buffers_rcu(struct rcu_head *head) +{ + struct callchain_cpus_entries *entries; + int cpu; + + entries = container_of(head, struct callchain_cpus_entries, rcu_head); + + for_each_possible_cpu(cpu) + kfree(entries->cpu_entries[cpu]); + + kfree(entries); +} + +static void release_callchain_buffers(void) +{ + struct callchain_cpus_entries *entries; + + entries = callchain_cpus_entries; + rcu_assign_pointer(callchain_cpus_entries, NULL); + call_rcu(&entries->rcu_head, release_callchain_buffers_rcu); +} + +static int alloc_callchain_buffers(void) +{ + int cpu; + int size; + struct callchain_cpus_entries *entries; + + /* + * We can't use the percpu allocation API for data that can be + * accessed from NMI. Use a temporary manual per cpu allocation + * until that gets sorted out. + */ + size = offsetof(struct callchain_cpus_entries, cpu_entries[nr_cpu_ids]); + + entries = kzalloc(size, GFP_KERNEL); + if (!entries) + return -ENOMEM; + + size = sizeof(struct perf_callchain_entry) * PERF_NR_CONTEXTS; + + for_each_possible_cpu(cpu) { + entries->cpu_entries[cpu] = kmalloc_node(size, GFP_KERNEL, + cpu_to_node(cpu)); + if (!entries->cpu_entries[cpu]) + goto fail; + } + + rcu_assign_pointer(callchain_cpus_entries, entries); + + return 0; + +fail: + for_each_possible_cpu(cpu) + kfree(entries->cpu_entries[cpu]); + kfree(entries); + + return -ENOMEM; +} + +static int get_callchain_buffers(void) +{ + int err = 0; + int count; + + mutex_lock(&callchain_mutex); + + count = atomic_inc_return(&nr_callchain_events); + if (WARN_ON_ONCE(count < 1)) { + err = -EINVAL; + goto exit; + } + + if (count > 1) { + /* If the allocation failed, give up */ + if (!callchain_cpus_entries) + err = -ENOMEM; + goto exit; + } + + err = alloc_callchain_buffers(); + if (err) + release_callchain_buffers(); +exit: + mutex_unlock(&callchain_mutex); + + return err; +} + +static void put_callchain_buffers(void) +{ + if (atomic_dec_and_mutex_lock(&nr_callchain_events, &callchain_mutex)) { + release_callchain_buffers(); + mutex_unlock(&callchain_mutex); + } +} + +static int get_recursion_context(int *recursion) +{ + int rctx; + + if (in_nmi()) + rctx = 3; + else if (in_irq()) + rctx = 2; + else if (in_softirq()) + rctx = 1; + else + rctx = 0; + + if (recursion[rctx]) + return -1; + + recursion[rctx]++; + barrier(); + + return rctx; +} + +static inline void put_recursion_context(int *recursion, int rctx) +{ + barrier(); + recursion[rctx]--; +} + +static struct perf_callchain_entry *get_callchain_entry(int *rctx) +{ + int cpu; + struct callchain_cpus_entries *entries; + + *rctx = get_recursion_context(__get_cpu_var(callchain_recursion)); + if (*rctx == -1) + return NULL; + + entries = rcu_dereference(callchain_cpus_entries); + if (!entries) + return NULL; + + cpu = smp_processor_id(); + + return &entries->cpu_entries[cpu][*rctx]; +} + +static void +put_callchain_entry(int rctx) +{ + put_recursion_context(__get_cpu_var(callchain_recursion), rctx); +} + +static struct perf_callchain_entry *perf_callchain(struct pt_regs *regs) +{ + int rctx; + struct perf_callchain_entry *entry; + + + entry = get_callchain_entry(&rctx); + if (rctx == -1) + return NULL; + + if (!entry) + goto exit_put; + + entry->nr = 0; + + if (!user_mode(regs)) { + perf_callchain_store(entry, PERF_CONTEXT_KERNEL); + perf_callchain_kernel(entry, regs); + if (current->mm) + regs = task_pt_regs(current); + else + regs = NULL; + } + + if (regs) { + perf_callchain_store(entry, PERF_CONTEXT_USER); + perf_callchain_user(entry, regs); + } + +exit_put: + put_callchain_entry(rctx); + + return entry; +} + +/* + * Initialize the perf_event context in a task_struct: + */ +static void __perf_event_init_context(struct perf_event_context *ctx) +{ + raw_spin_lock_init(&ctx->lock); + mutex_init(&ctx->mutex); + INIT_LIST_HEAD(&ctx->pinned_groups); + INIT_LIST_HEAD(&ctx->flexible_groups); + INIT_LIST_HEAD(&ctx->event_list); + atomic_set(&ctx->refcount, 1); +} + +static struct perf_event_context * +alloc_perf_context(struct pmu *pmu, struct task_struct *task) +{ + struct perf_event_context *ctx; + + ctx = kzalloc(sizeof(struct perf_event_context), GFP_KERNEL); + if (!ctx) + return NULL; + + __perf_event_init_context(ctx); + if (task) { + ctx->task = task; + get_task_struct(task); + } + ctx->pmu = pmu; + + return ctx; +} + +static struct task_struct * +find_lively_task_by_vpid(pid_t vpid) +{ + struct task_struct *task; + int err; + + rcu_read_lock(); + if (!vpid) + task = current; + else + task = find_task_by_vpid(vpid); + if (task) + get_task_struct(task); + rcu_read_unlock(); + + if (!task) + return ERR_PTR(-ESRCH); + + /* Reuse ptrace permission checks for now. */ + err = -EACCES; + if (!ptrace_may_access(task, PTRACE_MODE_READ)) + goto errout; + + return task; +errout: + put_task_struct(task); + return ERR_PTR(err); + +} + +/* + * Returns a matching context with refcount and pincount. + */ +static struct perf_event_context * +find_get_context(struct pmu *pmu, struct task_struct *task, int cpu) +{ + struct perf_event_context *ctx; + struct perf_cpu_context *cpuctx; + unsigned long flags; + int ctxn, err; + + if (!task) { + /* Must be root to operate on a CPU event: */ + if (perf_paranoid_cpu() && !capable(CAP_SYS_ADMIN)) + return ERR_PTR(-EACCES); + + /* + * We could be clever and allow to attach a event to an + * offline CPU and activate it when the CPU comes up, but + * that's for later. + */ + if (!cpu_online(cpu)) + return ERR_PTR(-ENODEV); + + cpuctx = per_cpu_ptr(pmu->pmu_cpu_context, cpu); + ctx = &cpuctx->ctx; + get_ctx(ctx); + ++ctx->pin_count; + + return ctx; + } + + err = -EINVAL; + ctxn = pmu->task_ctx_nr; + if (ctxn < 0) + goto errout; + +retry: + ctx = perf_lock_task_context(task, ctxn, &flags); + if (ctx) { + unclone_ctx(ctx); + ++ctx->pin_count; + raw_spin_unlock_irqrestore(&ctx->lock, flags); + } + + if (!ctx) { + ctx = alloc_perf_context(pmu, task); + err = -ENOMEM; + if (!ctx) + goto errout; + + get_ctx(ctx); + + err = 0; + mutex_lock(&task->perf_event_mutex); + /* + * If it has already passed perf_event_exit_task(). + * we must see PF_EXITING, it takes this mutex too. + */ + if (task->flags & PF_EXITING) + err = -ESRCH; + else if (task->perf_event_ctxp[ctxn]) + err = -EAGAIN; + else { + ++ctx->pin_count; + rcu_assign_pointer(task->perf_event_ctxp[ctxn], ctx); + } + mutex_unlock(&task->perf_event_mutex); + + if (unlikely(err)) { + put_task_struct(task); + kfree(ctx); + + if (err == -EAGAIN) + goto retry; + goto errout; + } + } + + return ctx; + +errout: + return ERR_PTR(err); +} + +static void perf_event_free_filter(struct perf_event *event); + +static void free_event_rcu(struct rcu_head *head) +{ + struct perf_event *event; + + event = container_of(head, struct perf_event, rcu_head); + if (event->ns) + put_pid_ns(event->ns); + perf_event_free_filter(event); + kfree(event); +} + +static void perf_buffer_put(struct perf_buffer *buffer); + +static void free_event(struct perf_event *event) +{ + irq_work_sync(&event->pending); + + if (!event->parent) { + if (event->attach_state & PERF_ATTACH_TASK) + jump_label_dec(&perf_sched_events); + if (event->attr.mmap || event->attr.mmap_data) + atomic_dec(&nr_mmap_events); + if (event->attr.comm) + atomic_dec(&nr_comm_events); + if (event->attr.task) + atomic_dec(&nr_task_events); + if (event->attr.sample_type & PERF_SAMPLE_CALLCHAIN) + put_callchain_buffers(); + if (is_cgroup_event(event)) { + atomic_dec(&per_cpu(perf_cgroup_events, event->cpu)); + jump_label_dec(&perf_sched_events); + } + } + + if (event->buffer) { + perf_buffer_put(event->buffer); + event->buffer = NULL; + } + + if (is_cgroup_event(event)) + perf_detach_cgroup(event); + + if (event->destroy) + event->destroy(event); + + if (event->ctx) + put_ctx(event->ctx); + + call_rcu(&event->rcu_head, free_event_rcu); +} + +int perf_event_release_kernel(struct perf_event *event) +{ + struct perf_event_context *ctx = event->ctx; + + /* + * Remove from the PMU, can't get re-enabled since we got + * here because the last ref went. + */ + perf_event_disable(event); + + WARN_ON_ONCE(ctx->parent_ctx); + /* + * There are two ways this annotation is useful: + * + * 1) there is a lock recursion from perf_event_exit_task + * see the comment there. + * + * 2) there is a lock-inversion with mmap_sem through + * perf_event_read_group(), which takes faults while + * holding ctx->mutex, however this is called after + * the last filedesc died, so there is no possibility + * to trigger the AB-BA case. + */ + mutex_lock_nested(&ctx->mutex, SINGLE_DEPTH_NESTING); + raw_spin_lock_irq(&ctx->lock); + perf_group_detach(event); + list_del_event(event, ctx); + raw_spin_unlock_irq(&ctx->lock); + mutex_unlock(&ctx->mutex); + + free_event(event); + + return 0; +} +EXPORT_SYMBOL_GPL(perf_event_release_kernel); + +/* + * Called when the last reference to the file is gone. + */ +static int perf_release(struct inode *inode, struct file *file) +{ + struct perf_event *event = file->private_data; + struct task_struct *owner; + + file->private_data = NULL; + + rcu_read_lock(); + owner = ACCESS_ONCE(event->owner); + /* + * Matches the smp_wmb() in perf_event_exit_task(). If we observe + * !owner it means the list deletion is complete and we can indeed + * free this event, otherwise we need to serialize on + * owner->perf_event_mutex. + */ + smp_read_barrier_depends(); + if (owner) { + /* + * Since delayed_put_task_struct() also drops the last + * task reference we can safely take a new reference + * while holding the rcu_read_lock(). + */ + get_task_struct(owner); + } + rcu_read_unlock(); + + if (owner) { + mutex_lock(&owner->perf_event_mutex); + /* + * We have to re-check the event->owner field, if it is cleared + * we raced with perf_event_exit_task(), acquiring the mutex + * ensured they're done, and we can proceed with freeing the + * event. + */ + if (event->owner) + list_del_init(&event->owner_entry); + mutex_unlock(&owner->perf_event_mutex); + put_task_struct(owner); + } + + return perf_event_release_kernel(event); +} + +u64 perf_event_read_value(struct perf_event *event, u64 *enabled, u64 *running) +{ + struct perf_event *child; + u64 total = 0; + + *enabled = 0; + *running = 0; + + mutex_lock(&event->child_mutex); + total += perf_event_read(event); + *enabled += event->total_time_enabled + + atomic64_read(&event->child_total_time_enabled); + *running += event->total_time_running + + atomic64_read(&event->child_total_time_running); + + list_for_each_entry(child, &event->child_list, child_list) { + total += perf_event_read(child); + *enabled += child->total_time_enabled; + *running += child->total_time_running; + } + mutex_unlock(&event->child_mutex); + + return total; +} +EXPORT_SYMBOL_GPL(perf_event_read_value); + +static int perf_event_read_group(struct perf_event *event, + u64 read_format, char __user *buf) +{ + struct perf_event *leader = event->group_leader, *sub; + int n = 0, size = 0, ret = -EFAULT; + struct perf_event_context *ctx = leader->ctx; + u64 values[5]; + u64 count, enabled, running; + + mutex_lock(&ctx->mutex); + count = perf_event_read_value(leader, &enabled, &running); + + values[n++] = 1 + leader->nr_siblings; + if (read_format & PERF_FORMAT_TOTAL_TIME_ENABLED) + values[n++] = enabled; + if (read_format & PERF_FORMAT_TOTAL_TIME_RUNNING) + values[n++] = running; + values[n++] = count; + if (read_format & PERF_FORMAT_ID) + values[n++] = primary_event_id(leader); + + size = n * sizeof(u64); + + if (copy_to_user(buf, values, size)) + goto unlock; + + ret = size; + + list_for_each_entry(sub, &leader->sibling_list, group_entry) { + n = 0; + + values[n++] = perf_event_read_value(sub, &enabled, &running); + if (read_format & PERF_FORMAT_ID) + values[n++] = primary_event_id(sub); + + size = n * sizeof(u64); + + if (copy_to_user(buf + ret, values, size)) { + ret = -EFAULT; + goto unlock; + } + + ret += size; + } +unlock: + mutex_unlock(&ctx->mutex); + + return ret; +} + +static int perf_event_read_one(struct perf_event *event, + u64 read_format, char __user *buf) +{ + u64 enabled, running; + u64 values[4]; + int n = 0; + + values[n++] = perf_event_read_value(event, &enabled, &running); + if (read_format & PERF_FORMAT_TOTAL_TIME_ENABLED) + values[n++] = enabled; + if (read_format & PERF_FORMAT_TOTAL_TIME_RUNNING) + values[n++] = running; + if (read_format & PERF_FORMAT_ID) + values[n++] = primary_event_id(event); + + if (copy_to_user(buf, values, n * sizeof(u64))) + return -EFAULT; + + return n * sizeof(u64); +} + +/* + * Read the performance event - simple non blocking version for now + */ +static ssize_t +perf_read_hw(struct perf_event *event, char __user *buf, size_t count) +{ + u64 read_format = event->attr.read_format; + int ret; + + /* + * Return end-of-file for a read on a event that is in + * error state (i.e. because it was pinned but it couldn't be + * scheduled on to the CPU at some point). + */ + if (event->state == PERF_EVENT_STATE_ERROR) + return 0; + + if (count < event->read_size) + return -ENOSPC; + + WARN_ON_ONCE(event->ctx->parent_ctx); + if (read_format & PERF_FORMAT_GROUP) + ret = perf_event_read_group(event, read_format, buf); + else + ret = perf_event_read_one(event, read_format, buf); + + return ret; +} + +static ssize_t +perf_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) +{ + struct perf_event *event = file->private_data; + + return perf_read_hw(event, buf, count); +} + +static unsigned int perf_poll(struct file *file, poll_table *wait) +{ + struct perf_event *event = file->private_data; + struct perf_buffer *buffer; + unsigned int events = POLL_HUP; + + rcu_read_lock(); + buffer = rcu_dereference(event->buffer); + if (buffer) + events = atomic_xchg(&buffer->poll, 0); + rcu_read_unlock(); + + poll_wait(file, &event->waitq, wait); + + return events; +} + +static void perf_event_reset(struct perf_event *event) +{ + (void)perf_event_read(event); + local64_set(&event->count, 0); + perf_event_update_userpage(event); +} + +/* + * Holding the top-level event's child_mutex means that any + * descendant process that has inherited this event will block + * in sync_child_event if it goes to exit, thus satisfying the + * task existence requirements of perf_event_enable/disable. + */ +static void perf_event_for_each_child(struct perf_event *event, + void (*func)(struct perf_event *)) +{ + struct perf_event *child; + + WARN_ON_ONCE(event->ctx->parent_ctx); + mutex_lock(&event->child_mutex); + func(event); + list_for_each_entry(child, &event->child_list, child_list) + func(child); + mutex_unlock(&event->child_mutex); +} + +static void perf_event_for_each(struct perf_event *event, + void (*func)(struct perf_event *)) +{ + struct perf_event_context *ctx = event->ctx; + struct perf_event *sibling; + + WARN_ON_ONCE(ctx->parent_ctx); + mutex_lock(&ctx->mutex); + event = event->group_leader; + + perf_event_for_each_child(event, func); + func(event); + list_for_each_entry(sibling, &event->sibling_list, group_entry) + perf_event_for_each_child(event, func); + mutex_unlock(&ctx->mutex); +} + +static int perf_event_period(struct perf_event *event, u64 __user *arg) +{ + struct perf_event_context *ctx = event->ctx; + int ret = 0; + u64 value; + + if (!is_sampling_event(event)) + return -EINVAL; + + if (copy_from_user(&value, arg, sizeof(value))) + return -EFAULT; + + if (!value) + return -EINVAL; + + raw_spin_lock_irq(&ctx->lock); + if (event->attr.freq) { + if (value > sysctl_perf_event_sample_rate) { + ret = -EINVAL; + goto unlock; + } + + event->attr.sample_freq = value; + } else { + event->attr.sample_period = value; + event->hw.sample_period = value; + } +unlock: + raw_spin_unlock_irq(&ctx->lock); + + return ret; +} + +static const struct file_operations perf_fops; + +static struct perf_event *perf_fget_light(int fd, int *fput_needed) +{ + struct file *file; + + file = fget_light(fd, fput_needed); + if (!file) + return ERR_PTR(-EBADF); + + if (file->f_op != &perf_fops) { + fput_light(file, *fput_needed); + *fput_needed = 0; + return ERR_PTR(-EBADF); + } + + return file->private_data; +} + +static int perf_event_set_output(struct perf_event *event, + struct perf_event *output_event); +static int perf_event_set_filter(struct perf_event *event, void __user *arg); + +static long perf_ioctl(struct file *file, unsigned int cmd, unsigned long arg) +{ + struct perf_event *event = file->private_data; + void (*func)(struct perf_event *); + u32 flags = arg; + + switch (cmd) { + case PERF_EVENT_IOC_ENABLE: + func = perf_event_enable; + break; + case PERF_EVENT_IOC_DISABLE: + func = perf_event_disable; + break; + case PERF_EVENT_IOC_RESET: + func = perf_event_reset; + break; + + case PERF_EVENT_IOC_REFRESH: + return perf_event_refresh(event, arg); + + case PERF_EVENT_IOC_PERIOD: + return perf_event_period(event, (u64 __user *)arg); + + case PERF_EVENT_IOC_SET_OUTPUT: + { + struct perf_event *output_event = NULL; + int fput_needed = 0; + int ret; + + if (arg != -1) { + output_event = perf_fget_light(arg, &fput_needed); + if (IS_ERR(output_event)) + return PTR_ERR(output_event); + } + + ret = perf_event_set_output(event, output_event); + if (output_event) + fput_light(output_event->filp, fput_needed); + + return ret; + } + + case PERF_EVENT_IOC_SET_FILTER: + return perf_event_set_filter(event, (void __user *)arg); + + default: + return -ENOTTY; + } + + if (flags & PERF_IOC_FLAG_GROUP) + perf_event_for_each(event, func); + else + perf_event_for_each_child(event, func); + + return 0; +} + +int perf_event_task_enable(void) +{ + struct perf_event *event; + + mutex_lock(¤t->perf_event_mutex); + list_for_each_entry(event, ¤t->perf_event_list, owner_entry) + perf_event_for_each_child(event, perf_event_enable); + mutex_unlock(¤t->perf_event_mutex); + + return 0; +} + +int perf_event_task_disable(void) +{ + struct perf_event *event; + + mutex_lock(¤t->perf_event_mutex); + list_for_each_entry(event, ¤t->perf_event_list, owner_entry) + perf_event_for_each_child(event, perf_event_disable); + mutex_unlock(¤t->perf_event_mutex); + + return 0; +} + +#ifndef PERF_EVENT_INDEX_OFFSET +# define PERF_EVENT_INDEX_OFFSET 0 +#endif + +static int perf_event_index(struct perf_event *event) +{ + if (event->hw.state & PERF_HES_STOPPED) + return 0; + + if (event->state != PERF_EVENT_STATE_ACTIVE) + return 0; + + return event->hw.idx + 1 - PERF_EVENT_INDEX_OFFSET; +} + +/* + * Callers need to ensure there can be no nesting of this function, otherwise + * the seqlock logic goes bad. We can not serialize this because the arch + * code calls this from NMI context. + */ +void perf_event_update_userpage(struct perf_event *event) +{ + struct perf_event_mmap_page *userpg; + struct perf_buffer *buffer; + + rcu_read_lock(); + buffer = rcu_dereference(event->buffer); + if (!buffer) + goto unlock; + + userpg = buffer->user_page; + + /* + * Disable preemption so as to not let the corresponding user-space + * spin too long if we get preempted. + */ + preempt_disable(); + ++userpg->lock; + barrier(); + userpg->index = perf_event_index(event); + userpg->offset = perf_event_count(event); + if (event->state == PERF_EVENT_STATE_ACTIVE) + userpg->offset -= local64_read(&event->hw.prev_count); + + userpg->time_enabled = event->total_time_enabled + + atomic64_read(&event->child_total_time_enabled); + + userpg->time_running = event->total_time_running + + atomic64_read(&event->child_total_time_running); + + barrier(); + ++userpg->lock; + preempt_enable(); +unlock: + rcu_read_unlock(); +} + +static unsigned long perf_data_size(struct perf_buffer *buffer); + +static void +perf_buffer_init(struct perf_buffer *buffer, long watermark, int flags) +{ + long max_size = perf_data_size(buffer); + + if (watermark) + buffer->watermark = min(max_size, watermark); + + if (!buffer->watermark) + buffer->watermark = max_size / 2; + + if (flags & PERF_BUFFER_WRITABLE) + buffer->writable = 1; + + atomic_set(&buffer->refcount, 1); +} + +#ifndef CONFIG_PERF_USE_VMALLOC + +/* + * Back perf_mmap() with regular GFP_KERNEL-0 pages. + */ + +static struct page * +perf_mmap_to_page(struct perf_buffer *buffer, unsigned long pgoff) +{ + if (pgoff > buffer->nr_pages) + return NULL; + + if (pgoff == 0) + return virt_to_page(buffer->user_page); + + return virt_to_page(buffer->data_pages[pgoff - 1]); +} + +static void *perf_mmap_alloc_page(int cpu) +{ + struct page *page; + int node; + + node = (cpu == -1) ? cpu : cpu_to_node(cpu); + page = alloc_pages_node(node, GFP_KERNEL | __GFP_ZERO, 0); + if (!page) + return NULL; + + return page_address(page); +} + +static struct perf_buffer * +perf_buffer_alloc(int nr_pages, long watermark, int cpu, int flags) +{ + struct perf_buffer *buffer; + unsigned long size; + int i; + + size = sizeof(struct perf_buffer); + size += nr_pages * sizeof(void *); + + buffer = kzalloc(size, GFP_KERNEL); + if (!buffer) + goto fail; + + buffer->user_page = perf_mmap_alloc_page(cpu); + if (!buffer->user_page) + goto fail_user_page; + + for (i = 0; i < nr_pages; i++) { + buffer->data_pages[i] = perf_mmap_alloc_page(cpu); + if (!buffer->data_pages[i]) + goto fail_data_pages; + } + + buffer->nr_pages = nr_pages; + + perf_buffer_init(buffer, watermark, flags); + + return buffer; + +fail_data_pages: + for (i--; i >= 0; i--) + free_page((unsigned long)buffer->data_pages[i]); + + free_page((unsigned long)buffer->user_page); + +fail_user_page: + kfree(buffer); + +fail: + return NULL; +} + +static void perf_mmap_free_page(unsigned long addr) +{ + struct page *page = virt_to_page((void *)addr); + + page->mapping = NULL; + __free_page(page); +} + +static void perf_buffer_free(struct perf_buffer *buffer) +{ + int i; + + perf_mmap_free_page((unsigned long)buffer->user_page); + for (i = 0; i < buffer->nr_pages; i++) + perf_mmap_free_page((unsigned long)buffer->data_pages[i]); + kfree(buffer); +} + +static inline int page_order(struct perf_buffer *buffer) +{ + return 0; +} + +#else + +/* + * Back perf_mmap() with vmalloc memory. + * + * Required for architectures that have d-cache aliasing issues. + */ + +static inline int page_order(struct perf_buffer *buffer) +{ + return buffer->page_order; +} + +static struct page * +perf_mmap_to_page(struct perf_buffer *buffer, unsigned long pgoff) +{ + if (pgoff > (1UL << page_order(buffer))) + return NULL; + + return vmalloc_to_page((void *)buffer->user_page + pgoff * PAGE_SIZE); +} + +static void perf_mmap_unmark_page(void *addr) +{ + struct page *page = vmalloc_to_page(addr); + + page->mapping = NULL; +} + +static void perf_buffer_free_work(struct work_struct *work) +{ + struct perf_buffer *buffer; + void *base; + int i, nr; + + buffer = container_of(work, struct perf_buffer, work); + nr = 1 << page_order(buffer); + + base = buffer->user_page; + for (i = 0; i < nr + 1; i++) + perf_mmap_unmark_page(base + (i * PAGE_SIZE)); + + vfree(base); + kfree(buffer); +} + +static void perf_buffer_free(struct perf_buffer *buffer) +{ + schedule_work(&buffer->work); +} + +static struct perf_buffer * +perf_buffer_alloc(int nr_pages, long watermark, int cpu, int flags) +{ + struct perf_buffer *buffer; + unsigned long size; + void *all_buf; + + size = sizeof(struct perf_buffer); + size += sizeof(void *); + + buffer = kzalloc(size, GFP_KERNEL); + if (!buffer) + goto fail; + + INIT_WORK(&buffer->work, perf_buffer_free_work); + + all_buf = vmalloc_user((nr_pages + 1) * PAGE_SIZE); + if (!all_buf) + goto fail_all_buf; + + buffer->user_page = all_buf; + buffer->data_pages[0] = all_buf + PAGE_SIZE; + buffer->page_order = ilog2(nr_pages); + buffer->nr_pages = 1; + + perf_buffer_init(buffer, watermark, flags); + + return buffer; + +fail_all_buf: + kfree(buffer); + +fail: + return NULL; +} + +#endif + +static unsigned long perf_data_size(struct perf_buffer *buffer) +{ + return buffer->nr_pages << (PAGE_SHIFT + page_order(buffer)); +} + +static int perf_mmap_fault(struct vm_area_struct *vma, struct vm_fault *vmf) +{ + struct perf_event *event = vma->vm_file->private_data; + struct perf_buffer *buffer; + int ret = VM_FAULT_SIGBUS; + + if (vmf->flags & FAULT_FLAG_MKWRITE) { + if (vmf->pgoff == 0) + ret = 0; + return ret; + } + + rcu_read_lock(); + buffer = rcu_dereference(event->buffer); + if (!buffer) + goto unlock; + + if (vmf->pgoff && (vmf->flags & FAULT_FLAG_WRITE)) + goto unlock; + + vmf->page = perf_mmap_to_page(buffer, vmf->pgoff); + if (!vmf->page) + goto unlock; + + get_page(vmf->page); + vmf->page->mapping = vma->vm_file->f_mapping; + vmf->page->index = vmf->pgoff; + + ret = 0; +unlock: + rcu_read_unlock(); + + return ret; +} + +static void perf_buffer_free_rcu(struct rcu_head *rcu_head) +{ + struct perf_buffer *buffer; + + buffer = container_of(rcu_head, struct perf_buffer, rcu_head); + perf_buffer_free(buffer); +} + +static struct perf_buffer *perf_buffer_get(struct perf_event *event) +{ + struct perf_buffer *buffer; + + rcu_read_lock(); + buffer = rcu_dereference(event->buffer); + if (buffer) { + if (!atomic_inc_not_zero(&buffer->refcount)) + buffer = NULL; + } + rcu_read_unlock(); + + return buffer; +} + +static void perf_buffer_put(struct perf_buffer *buffer) +{ + if (!atomic_dec_and_test(&buffer->refcount)) + return; + + call_rcu(&buffer->rcu_head, perf_buffer_free_rcu); +} + +static void perf_mmap_open(struct vm_area_struct *vma) +{ + struct perf_event *event = vma->vm_file->private_data; + + atomic_inc(&event->mmap_count); +} + +static void perf_mmap_close(struct vm_area_struct *vma) +{ + struct perf_event *event = vma->vm_file->private_data; + + if (atomic_dec_and_mutex_lock(&event->mmap_count, &event->mmap_mutex)) { + unsigned long size = perf_data_size(event->buffer); + struct user_struct *user = event->mmap_user; + struct perf_buffer *buffer = event->buffer; + + atomic_long_sub((size >> PAGE_SHIFT) + 1, &user->locked_vm); + vma->vm_mm->locked_vm -= event->mmap_locked; + rcu_assign_pointer(event->buffer, NULL); + mutex_unlock(&event->mmap_mutex); + + perf_buffer_put(buffer); + free_uid(user); + } +} + +static const struct vm_operations_struct perf_mmap_vmops = { + .open = perf_mmap_open, + .close = perf_mmap_close, + .fault = perf_mmap_fault, + .page_mkwrite = perf_mmap_fault, +}; + +static int perf_mmap(struct file *file, struct vm_area_struct *vma) +{ + struct perf_event *event = file->private_data; + unsigned long user_locked, user_lock_limit; + struct user_struct *user = current_user(); + unsigned long locked, lock_limit; + struct perf_buffer *buffer; + unsigned long vma_size; + unsigned long nr_pages; + long user_extra, extra; + int ret = 0, flags = 0; + + /* + * Don't allow mmap() of inherited per-task counters. This would + * create a performance issue due to all children writing to the + * same buffer. + */ + if (event->cpu == -1 && event->attr.inherit) + return -EINVAL; + + if (!(vma->vm_flags & VM_SHARED)) + return -EINVAL; + + vma_size = vma->vm_end - vma->vm_start; + nr_pages = (vma_size / PAGE_SIZE) - 1; + + /* + * If we have buffer pages ensure they're a power-of-two number, so we + * can do bitmasks instead of modulo. + */ + if (nr_pages != 0 && !is_power_of_2(nr_pages)) + return -EINVAL; + + if (vma_size != PAGE_SIZE * (1 + nr_pages)) + return -EINVAL; + + if (vma->vm_pgoff != 0) + return -EINVAL; + + WARN_ON_ONCE(event->ctx->parent_ctx); + mutex_lock(&event->mmap_mutex); + if (event->buffer) { + if (event->buffer->nr_pages == nr_pages) + atomic_inc(&event->buffer->refcount); + else + ret = -EINVAL; + goto unlock; + } + + user_extra = nr_pages + 1; + user_lock_limit = sysctl_perf_event_mlock >> (PAGE_SHIFT - 10); + + /* + * Increase the limit linearly with more CPUs: + */ + user_lock_limit *= num_online_cpus(); + + user_locked = atomic_long_read(&user->locked_vm) + user_extra; + + extra = 0; + if (user_locked > user_lock_limit) + extra = user_locked - user_lock_limit; + + lock_limit = rlimit(RLIMIT_MEMLOCK); + lock_limit >>= PAGE_SHIFT; + locked = vma->vm_mm->locked_vm + extra; + + if ((locked > lock_limit) && perf_paranoid_tracepoint_raw() && + !capable(CAP_IPC_LOCK)) { + ret = -EPERM; + goto unlock; + } + + WARN_ON(event->buffer); + + if (vma->vm_flags & VM_WRITE) + flags |= PERF_BUFFER_WRITABLE; + + buffer = perf_buffer_alloc(nr_pages, event->attr.wakeup_watermark, + event->cpu, flags); + if (!buffer) { + ret = -ENOMEM; + goto unlock; + } + rcu_assign_pointer(event->buffer, buffer); + + atomic_long_add(user_extra, &user->locked_vm); + event->mmap_locked = extra; + event->mmap_user = get_current_user(); + vma->vm_mm->locked_vm += event->mmap_locked; + +unlock: + if (!ret) + atomic_inc(&event->mmap_count); + mutex_unlock(&event->mmap_mutex); + + vma->vm_flags |= VM_RESERVED; + vma->vm_ops = &perf_mmap_vmops; + + return ret; +} + +static int perf_fasync(int fd, struct file *filp, int on) +{ + struct inode *inode = filp->f_path.dentry->d_inode; + struct perf_event *event = filp->private_data; + int retval; + + mutex_lock(&inode->i_mutex); + retval = fasync_helper(fd, filp, on, &event->fasync); + mutex_unlock(&inode->i_mutex); + + if (retval < 0) + return retval; + + return 0; +} + +static const struct file_operations perf_fops = { + .llseek = no_llseek, + .release = perf_release, + .read = perf_read, + .poll = perf_poll, + .unlocked_ioctl = perf_ioctl, + .compat_ioctl = perf_ioctl, + .mmap = perf_mmap, + .fasync = perf_fasync, +}; + +/* + * Perf event wakeup + * + * If there's data, ensure we set the poll() state and publish everything + * to user-space before waking everybody up. + */ + +void perf_event_wakeup(struct perf_event *event) +{ + wake_up_all(&event->waitq); + + if (event->pending_kill) { + kill_fasync(&event->fasync, SIGIO, event->pending_kill); + event->pending_kill = 0; + } +} + +static void perf_pending_event(struct irq_work *entry) +{ + struct perf_event *event = container_of(entry, + struct perf_event, pending); + + if (event->pending_disable) { + event->pending_disable = 0; + __perf_event_disable(event); + } + + if (event->pending_wakeup) { + event->pending_wakeup = 0; + perf_event_wakeup(event); + } +} + +/* + * We assume there is only KVM supporting the callbacks. + * Later on, we might change it to a list if there is + * another virtualization implementation supporting the callbacks. + */ +struct perf_guest_info_callbacks *perf_guest_cbs; + +int perf_register_guest_info_callbacks(struct perf_guest_info_callbacks *cbs) +{ + perf_guest_cbs = cbs; + return 0; +} +EXPORT_SYMBOL_GPL(perf_register_guest_info_callbacks); + +int perf_unregister_guest_info_callbacks(struct perf_guest_info_callbacks *cbs) +{ + perf_guest_cbs = NULL; + return 0; +} +EXPORT_SYMBOL_GPL(perf_unregister_guest_info_callbacks); + +/* + * Output + */ +static bool perf_output_space(struct perf_buffer *buffer, unsigned long tail, + unsigned long offset, unsigned long head) +{ + unsigned long mask; + + if (!buffer->writable) + return true; + + mask = perf_data_size(buffer) - 1; + + offset = (offset - tail) & mask; + head = (head - tail) & mask; + + if ((int)(head - offset) < 0) + return false; + + return true; +} + +static void perf_output_wakeup(struct perf_output_handle *handle) +{ + atomic_set(&handle->buffer->poll, POLL_IN); + + if (handle->nmi) { + handle->event->pending_wakeup = 1; + irq_work_queue(&handle->event->pending); + } else + perf_event_wakeup(handle->event); +} + +/* + * We need to ensure a later event_id doesn't publish a head when a former + * event isn't done writing. However since we need to deal with NMIs we + * cannot fully serialize things. + * + * We only publish the head (and generate a wakeup) when the outer-most + * event completes. + */ +static void perf_output_get_handle(struct perf_output_handle *handle) +{ + struct perf_buffer *buffer = handle->buffer; + + preempt_disable(); + local_inc(&buffer->nest); + handle->wakeup = local_read(&buffer->wakeup); +} + +static void perf_output_put_handle(struct perf_output_handle *handle) +{ + struct perf_buffer *buffer = handle->buffer; + unsigned long head; + +again: + head = local_read(&buffer->head); + + /* + * IRQ/NMI can happen here, which means we can miss a head update. + */ + + if (!local_dec_and_test(&buffer->nest)) + goto out; + + /* + * Publish the known good head. Rely on the full barrier implied + * by atomic_dec_and_test() order the buffer->head read and this + * write. + */ + buffer->user_page->data_head = head; + + /* + * Now check if we missed an update, rely on the (compiler) + * barrier in atomic_dec_and_test() to re-read buffer->head. + */ + if (unlikely(head != local_read(&buffer->head))) { + local_inc(&buffer->nest); + goto again; + } + + if (handle->wakeup != local_read(&buffer->wakeup)) + perf_output_wakeup(handle); + +out: + preempt_enable(); +} + +__always_inline void perf_output_copy(struct perf_output_handle *handle, + const void *buf, unsigned int len) +{ + do { + unsigned long size = min_t(unsigned long, handle->size, len); + + memcpy(handle->addr, buf, size); + + len -= size; + handle->addr += size; + buf += size; + handle->size -= size; + if (!handle->size) { + struct perf_buffer *buffer = handle->buffer; + + handle->page++; + handle->page &= buffer->nr_pages - 1; + handle->addr = buffer->data_pages[handle->page]; + handle->size = PAGE_SIZE << page_order(buffer); + } + } while (len); +} + +static void __perf_event_header__init_id(struct perf_event_header *header, + struct perf_sample_data *data, + struct perf_event *event) +{ + u64 sample_type = event->attr.sample_type; + + data->type = sample_type; + header->size += event->id_header_size; + + if (sample_type & PERF_SAMPLE_TID) { + /* namespace issues */ + data->tid_entry.pid = perf_event_pid(event, current); + data->tid_entry.tid = perf_event_tid(event, current); + } + + if (sample_type & PERF_SAMPLE_TIME) + data->time = perf_clock(); + + if (sample_type & PERF_SAMPLE_ID) + data->id = primary_event_id(event); + + if (sample_type & PERF_SAMPLE_STREAM_ID) + data->stream_id = event->id; + + if (sample_type & PERF_SAMPLE_CPU) { + data->cpu_entry.cpu = raw_smp_processor_id(); + data->cpu_entry.reserved = 0; + } +} + +static void perf_event_header__init_id(struct perf_event_header *header, + struct perf_sample_data *data, + struct perf_event *event) +{ + if (event->attr.sample_id_all) + __perf_event_header__init_id(header, data, event); +} + +static void __perf_event__output_id_sample(struct perf_output_handle *handle, + struct perf_sample_data *data) +{ + u64 sample_type = data->type; + + if (sample_type & PERF_SAMPLE_TID) + perf_output_put(handle, data->tid_entry); + + if (sample_type & PERF_SAMPLE_TIME) + perf_output_put(handle, data->time); + + if (sample_type & PERF_SAMPLE_ID) + perf_output_put(handle, data->id); + + if (sample_type & PERF_SAMPLE_STREAM_ID) + perf_output_put(handle, data->stream_id); + + if (sample_type & PERF_SAMPLE_CPU) + perf_output_put(handle, data->cpu_entry); +} + +static void perf_event__output_id_sample(struct perf_event *event, + struct perf_output_handle *handle, + struct perf_sample_data *sample) +{ + if (event->attr.sample_id_all) + __perf_event__output_id_sample(handle, sample); +} + +int perf_output_begin(struct perf_output_handle *handle, + struct perf_event *event, unsigned int size, + int nmi, int sample) +{ + struct perf_buffer *buffer; + unsigned long tail, offset, head; + int have_lost; + struct perf_sample_data sample_data; + struct { + struct perf_event_header header; + u64 id; + u64 lost; + } lost_event; + + rcu_read_lock(); + /* + * For inherited events we send all the output towards the parent. + */ + if (event->parent) + event = event->parent; + + buffer = rcu_dereference(event->buffer); + if (!buffer) + goto out; + + handle->buffer = buffer; + handle->event = event; + handle->nmi = nmi; + handle->sample = sample; + + if (!buffer->nr_pages) + goto out; + + have_lost = local_read(&buffer->lost); + if (have_lost) { + lost_event.header.size = sizeof(lost_event); + perf_event_header__init_id(&lost_event.header, &sample_data, + event); + size += lost_event.header.size; + } + + perf_output_get_handle(handle); + + do { + /* + * Userspace could choose to issue a mb() before updating the + * tail pointer. So that all reads will be completed before the + * write is issued. + */ + tail = ACCESS_ONCE(buffer->user_page->data_tail); + smp_rmb(); + offset = head = local_read(&buffer->head); + head += size; + if (unlikely(!perf_output_space(buffer, tail, offset, head))) + goto fail; + } while (local_cmpxchg(&buffer->head, offset, head) != offset); + + if (head - local_read(&buffer->wakeup) > buffer->watermark) + local_add(buffer->watermark, &buffer->wakeup); + + handle->page = offset >> (PAGE_SHIFT + page_order(buffer)); + handle->page &= buffer->nr_pages - 1; + handle->size = offset & ((PAGE_SIZE << page_order(buffer)) - 1); + handle->addr = buffer->data_pages[handle->page]; + handle->addr += handle->size; + handle->size = (PAGE_SIZE << page_order(buffer)) - handle->size; + + if (have_lost) { + lost_event.header.type = PERF_RECORD_LOST; + lost_event.header.misc = 0; + lost_event.id = event->id; + lost_event.lost = local_xchg(&buffer->lost, 0); + + perf_output_put(handle, lost_event); + perf_event__output_id_sample(event, handle, &sample_data); + } + + return 0; + +fail: + local_inc(&buffer->lost); + perf_output_put_handle(handle); +out: + rcu_read_unlock(); + + return -ENOSPC; +} + +void perf_output_end(struct perf_output_handle *handle) +{ + struct perf_event *event = handle->event; + struct perf_buffer *buffer = handle->buffer; + + int wakeup_events = event->attr.wakeup_events; + + if (handle->sample && wakeup_events) { + int events = local_inc_return(&buffer->events); + if (events >= wakeup_events) { + local_sub(wakeup_events, &buffer->events); + local_inc(&buffer->wakeup); + } + } + + perf_output_put_handle(handle); + rcu_read_unlock(); +} + +static void perf_output_read_one(struct perf_output_handle *handle, + struct perf_event *event, + u64 enabled, u64 running) +{ + u64 read_format = event->attr.read_format; + u64 values[4]; + int n = 0; + + values[n++] = perf_event_count(event); + if (read_format & PERF_FORMAT_TOTAL_TIME_ENABLED) { + values[n++] = enabled + + atomic64_read(&event->child_total_time_enabled); + } + if (read_format & PERF_FORMAT_TOTAL_TIME_RUNNING) { + values[n++] = running + + atomic64_read(&event->child_total_time_running); + } + if (read_format & PERF_FORMAT_ID) + values[n++] = primary_event_id(event); + + perf_output_copy(handle, values, n * sizeof(u64)); +} + +/* + * XXX PERF_FORMAT_GROUP vs inherited events seems difficult. + */ +static void perf_output_read_group(struct perf_output_handle *handle, + struct perf_event *event, + u64 enabled, u64 running) +{ + struct perf_event *leader = event->group_leader, *sub; + u64 read_format = event->attr.read_format; + u64 values[5]; + int n = 0; + + values[n++] = 1 + leader->nr_siblings; + + if (read_format & PERF_FORMAT_TOTAL_TIME_ENABLED) + values[n++] = enabled; + + if (read_format & PERF_FORMAT_TOTAL_TIME_RUNNING) + values[n++] = running; + + if (leader != event) + leader->pmu->read(leader); + + values[n++] = perf_event_count(leader); + if (read_format & PERF_FORMAT_ID) + values[n++] = primary_event_id(leader); + + perf_output_copy(handle, values, n * sizeof(u64)); + + list_for_each_entry(sub, &leader->sibling_list, group_entry) { + n = 0; + + if (sub != event) + sub->pmu->read(sub); + + values[n++] = perf_event_count(sub); + if (read_format & PERF_FORMAT_ID) + values[n++] = primary_event_id(sub); + + perf_output_copy(handle, values, n * sizeof(u64)); + } +} + +#define PERF_FORMAT_TOTAL_TIMES (PERF_FORMAT_TOTAL_TIME_ENABLED|\ + PERF_FORMAT_TOTAL_TIME_RUNNING) + +static void perf_output_read(struct perf_output_handle *handle, + struct perf_event *event) +{ + u64 enabled = 0, running = 0, now, ctx_time; + u64 read_format = event->attr.read_format; + + /* + * compute total_time_enabled, total_time_running + * based on snapshot values taken when the event + * was last scheduled in. + * + * we cannot simply called update_context_time() + * because of locking issue as we are called in + * NMI context + */ + if (read_format & PERF_FORMAT_TOTAL_TIMES) { + now = perf_clock(); + ctx_time = event->shadow_ctx_time + now; + enabled = ctx_time - event->tstamp_enabled; + running = ctx_time - event->tstamp_running; + } + + if (event->attr.read_format & PERF_FORMAT_GROUP) + perf_output_read_group(handle, event, enabled, running); + else + perf_output_read_one(handle, event, enabled, running); +} + +void perf_output_sample(struct perf_output_handle *handle, + struct perf_event_header *header, + struct perf_sample_data *data, + struct perf_event *event) +{ + u64 sample_type = data->type; + + perf_output_put(handle, *header); + + if (sample_type & PERF_SAMPLE_IP) + perf_output_put(handle, data->ip); + + if (sample_type & PERF_SAMPLE_TID) + perf_output_put(handle, data->tid_entry); + + if (sample_type & PERF_SAMPLE_TIME) + perf_output_put(handle, data->time); + + if (sample_type & PERF_SAMPLE_ADDR) + perf_output_put(handle, data->addr); + + if (sample_type & PERF_SAMPLE_ID) + perf_output_put(handle, data->id); + + if (sample_type & PERF_SAMPLE_STREAM_ID) + perf_output_put(handle, data->stream_id); + + if (sample_type & PERF_SAMPLE_CPU) + perf_output_put(handle, data->cpu_entry); + + if (sample_type & PERF_SAMPLE_PERIOD) + perf_output_put(handle, data->period); + + if (sample_type & PERF_SAMPLE_READ) + perf_output_read(handle, event); + + if (sample_type & PERF_SAMPLE_CALLCHAIN) { + if (data->callchain) { + int size = 1; + + if (data->callchain) + size += data->callchain->nr; + + size *= sizeof(u64); + + perf_output_copy(handle, data->callchain, size); + } else { + u64 nr = 0; + perf_output_put(handle, nr); + } + } + + if (sample_type & PERF_SAMPLE_RAW) { + if (data->raw) { + perf_output_put(handle, data->raw->size); + perf_output_copy(handle, data->raw->data, + data->raw->size); + } else { + struct { + u32 size; + u32 data; + } raw = { + .size = sizeof(u32), + .data = 0, + }; + perf_output_put(handle, raw); + } + } +} + +void perf_prepare_sample(struct perf_event_header *header, + struct perf_sample_data *data, + struct perf_event *event, + struct pt_regs *regs) +{ + u64 sample_type = event->attr.sample_type; + + header->type = PERF_RECORD_SAMPLE; + header->size = sizeof(*header) + event->header_size; + + header->misc = 0; + header->misc |= perf_misc_flags(regs); + + __perf_event_header__init_id(header, data, event); + + if (sample_type & PERF_SAMPLE_IP) + data->ip = perf_instruction_pointer(regs); + + if (sample_type & PERF_SAMPLE_CALLCHAIN) { + int size = 1; + + data->callchain = perf_callchain(regs); + + if (data->callchain) + size += data->callchain->nr; + + header->size += size * sizeof(u64); + } + + if (sample_type & PERF_SAMPLE_RAW) { + int size = sizeof(u32); + + if (data->raw) + size += data->raw->size; + else + size += sizeof(u32); + + WARN_ON_ONCE(size & (sizeof(u64)-1)); + header->size += size; + } +} + +static void perf_event_output(struct perf_event *event, int nmi, + struct perf_sample_data *data, + struct pt_regs *regs) +{ + struct perf_output_handle handle; + struct perf_event_header header; + + /* protect the callchain buffers */ + rcu_read_lock(); + + perf_prepare_sample(&header, data, event, regs); + + if (perf_output_begin(&handle, event, header.size, nmi, 1)) + goto exit; + + perf_output_sample(&handle, &header, data, event); + + perf_output_end(&handle); + +exit: + rcu_read_unlock(); +} + +/* + * read event_id + */ + +struct perf_read_event { + struct perf_event_header header; + + u32 pid; + u32 tid; +}; + +static void +perf_event_read_event(struct perf_event *event, + struct task_struct *task) +{ + struct perf_output_handle handle; + struct perf_sample_data sample; + struct perf_read_event read_event = { + .header = { + .type = PERF_RECORD_READ, + .misc = 0, + .size = sizeof(read_event) + event->read_size, + }, + .pid = perf_event_pid(event, task), + .tid = perf_event_tid(event, task), + }; + int ret; + + perf_event_header__init_id(&read_event.header, &sample, event); + ret = perf_output_begin(&handle, event, read_event.header.size, 0, 0); + if (ret) + return; + + perf_output_put(&handle, read_event); + perf_output_read(&handle, event); + perf_event__output_id_sample(event, &handle, &sample); + + perf_output_end(&handle); +} + +/* + * task tracking -- fork/exit + * + * enabled by: attr.comm | attr.mmap | attr.mmap_data | attr.task + */ + +struct perf_task_event { + struct task_struct *task; + struct perf_event_context *task_ctx; + + struct { + struct perf_event_header header; + + u32 pid; + u32 ppid; + u32 tid; + u32 ptid; + u64 time; + } event_id; +}; + +static void perf_event_task_output(struct perf_event *event, + struct perf_task_event *task_event) +{ + struct perf_output_handle handle; + struct perf_sample_data sample; + struct task_struct *task = task_event->task; + int ret, size = task_event->event_id.header.size; + + perf_event_header__init_id(&task_event->event_id.header, &sample, event); + + ret = perf_output_begin(&handle, event, + task_event->event_id.header.size, 0, 0); + if (ret) + goto out; + + task_event->event_id.pid = perf_event_pid(event, task); + task_event->event_id.ppid = perf_event_pid(event, current); + + task_event->event_id.tid = perf_event_tid(event, task); + task_event->event_id.ptid = perf_event_tid(event, current); + + perf_output_put(&handle, task_event->event_id); + + perf_event__output_id_sample(event, &handle, &sample); + + perf_output_end(&handle); +out: + task_event->event_id.header.size = size; +} + +static int perf_event_task_match(struct perf_event *event) +{ + if (event->state < PERF_EVENT_STATE_INACTIVE) + return 0; + + if (!event_filter_match(event)) + return 0; + + if (event->attr.comm || event->attr.mmap || + event->attr.mmap_data || event->attr.task) + return 1; + + return 0; +} + +static void perf_event_task_ctx(struct perf_event_context *ctx, + struct perf_task_event *task_event) +{ + struct perf_event *event; + + list_for_each_entry_rcu(event, &ctx->event_list, event_entry) { + if (perf_event_task_match(event)) + perf_event_task_output(event, task_event); + } +} + +static void perf_event_task_event(struct perf_task_event *task_event) +{ + struct perf_cpu_context *cpuctx; + struct perf_event_context *ctx; + struct pmu *pmu; + int ctxn; + + rcu_read_lock(); + list_for_each_entry_rcu(pmu, &pmus, entry) { + cpuctx = get_cpu_ptr(pmu->pmu_cpu_context); + if (cpuctx->active_pmu != pmu) + goto next; + perf_event_task_ctx(&cpuctx->ctx, task_event); + + ctx = task_event->task_ctx; + if (!ctx) { + ctxn = pmu->task_ctx_nr; + if (ctxn < 0) + goto next; + ctx = rcu_dereference(current->perf_event_ctxp[ctxn]); + } + if (ctx) + perf_event_task_ctx(ctx, task_event); +next: + put_cpu_ptr(pmu->pmu_cpu_context); + } + rcu_read_unlock(); +} + +static void perf_event_task(struct task_struct *task, + struct perf_event_context *task_ctx, + int new) +{ + struct perf_task_event task_event; + + if (!atomic_read(&nr_comm_events) && + !atomic_read(&nr_mmap_events) && + !atomic_read(&nr_task_events)) + return; + + task_event = (struct perf_task_event){ + .task = task, + .task_ctx = task_ctx, + .event_id = { + .header = { + .type = new ? PERF_RECORD_FORK : PERF_RECORD_EXIT, + .misc = 0, + .size = sizeof(task_event.event_id), + }, + /* .pid */ + /* .ppid */ + /* .tid */ + /* .ptid */ + .time = perf_clock(), + }, + }; + + perf_event_task_event(&task_event); +} + +void perf_event_fork(struct task_struct *task) +{ + perf_event_task(task, NULL, 1); +} + +/* + * comm tracking + */ + +struct perf_comm_event { + struct task_struct *task; + char *comm; + int comm_size; + + struct { + struct perf_event_header header; + + u32 pid; + u32 tid; + } event_id; +}; + +static void perf_event_comm_output(struct perf_event *event, + struct perf_comm_event *comm_event) +{ + struct perf_output_handle handle; + struct perf_sample_data sample; + int size = comm_event->event_id.header.size; + int ret; + + perf_event_header__init_id(&comm_event->event_id.header, &sample, event); + ret = perf_output_begin(&handle, event, + comm_event->event_id.header.size, 0, 0); + + if (ret) + goto out; + + comm_event->event_id.pid = perf_event_pid(event, comm_event->task); + comm_event->event_id.tid = perf_event_tid(event, comm_event->task); + + perf_output_put(&handle, comm_event->event_id); + perf_output_copy(&handle, comm_event->comm, + comm_event->comm_size); + + perf_event__output_id_sample(event, &handle, &sample); + + perf_output_end(&handle); +out: + comm_event->event_id.header.size = size; +} + +static int perf_event_comm_match(struct perf_event *event) +{ + if (event->state < PERF_EVENT_STATE_INACTIVE) + return 0; + + if (!event_filter_match(event)) + return 0; + + if (event->attr.comm) + return 1; + + return 0; +} + +static void perf_event_comm_ctx(struct perf_event_context *ctx, + struct perf_comm_event *comm_event) +{ + struct perf_event *event; + + list_for_each_entry_rcu(event, &ctx->event_list, event_entry) { + if (perf_event_comm_match(event)) + perf_event_comm_output(event, comm_event); + } +} + +static void perf_event_comm_event(struct perf_comm_event *comm_event) +{ + struct perf_cpu_context *cpuctx; + struct perf_event_context *ctx; + char comm[TASK_COMM_LEN]; + unsigned int size; + struct pmu *pmu; + int ctxn; + + memset(comm, 0, sizeof(comm)); + strlcpy(comm, comm_event->task->comm, sizeof(comm)); + size = ALIGN(strlen(comm)+1, sizeof(u64)); + + comm_event->comm = comm; + comm_event->comm_size = size; + + comm_event->event_id.header.size = sizeof(comm_event->event_id) + size; + rcu_read_lock(); + list_for_each_entry_rcu(pmu, &pmus, entry) { + cpuctx = get_cpu_ptr(pmu->pmu_cpu_context); + if (cpuctx->active_pmu != pmu) + goto next; + perf_event_comm_ctx(&cpuctx->ctx, comm_event); + + ctxn = pmu->task_ctx_nr; + if (ctxn < 0) + goto next; + + ctx = rcu_dereference(current->perf_event_ctxp[ctxn]); + if (ctx) + perf_event_comm_ctx(ctx, comm_event); +next: + put_cpu_ptr(pmu->pmu_cpu_context); + } + rcu_read_unlock(); +} + +void perf_event_comm(struct task_struct *task) +{ + struct perf_comm_event comm_event; + struct perf_event_context *ctx; + int ctxn; + + for_each_task_context_nr(ctxn) { + ctx = task->perf_event_ctxp[ctxn]; + if (!ctx) + continue; + + perf_event_enable_on_exec(ctx); + } + + if (!atomic_read(&nr_comm_events)) + return; + + comm_event = (struct perf_comm_event){ + .task = task, + /* .comm */ + /* .comm_size */ + .event_id = { + .header = { + .type = PERF_RECORD_COMM, + .misc = 0, + /* .size */ + }, + /* .pid */ + /* .tid */ + }, + }; + + perf_event_comm_event(&comm_event); +} + +/* + * mmap tracking + */ + +struct perf_mmap_event { + struct vm_area_struct *vma; + + const char *file_name; + int file_size; + + struct { + struct perf_event_header header; + + u32 pid; + u32 tid; + u64 start; + u64 len; + u64 pgoff; + } event_id; +}; + +static void perf_event_mmap_output(struct perf_event *event, + struct perf_mmap_event *mmap_event) +{ + struct perf_output_handle handle; + struct perf_sample_data sample; + int size = mmap_event->event_id.header.size; + int ret; + + perf_event_header__init_id(&mmap_event->event_id.header, &sample, event); + ret = perf_output_begin(&handle, event, + mmap_event->event_id.header.size, 0, 0); + if (ret) + goto out; + + mmap_event->event_id.pid = perf_event_pid(event, current); + mmap_event->event_id.tid = perf_event_tid(event, current); + + perf_output_put(&handle, mmap_event->event_id); + perf_output_copy(&handle, mmap_event->file_name, + mmap_event->file_size); + + perf_event__output_id_sample(event, &handle, &sample); + + perf_output_end(&handle); +out: + mmap_event->event_id.header.size = size; +} + +static int perf_event_mmap_match(struct perf_event *event, + struct perf_mmap_event *mmap_event, + int executable) +{ + if (event->state < PERF_EVENT_STATE_INACTIVE) + return 0; + + if (!event_filter_match(event)) + return 0; + + if ((!executable && event->attr.mmap_data) || + (executable && event->attr.mmap)) + return 1; + + return 0; +} + +static void perf_event_mmap_ctx(struct perf_event_context *ctx, + struct perf_mmap_event *mmap_event, + int executable) +{ + struct perf_event *event; + + list_for_each_entry_rcu(event, &ctx->event_list, event_entry) { + if (perf_event_mmap_match(event, mmap_event, executable)) + perf_event_mmap_output(event, mmap_event); + } +} + +static void perf_event_mmap_event(struct perf_mmap_event *mmap_event) +{ + struct perf_cpu_context *cpuctx; + struct perf_event_context *ctx; + struct vm_area_struct *vma = mmap_event->vma; + struct file *file = vma->vm_file; + unsigned int size; + char tmp[16]; + char *buf = NULL; + const char *name; + struct pmu *pmu; + int ctxn; + + memset(tmp, 0, sizeof(tmp)); + + if (file) { + /* + * d_path works from the end of the buffer backwards, so we + * need to add enough zero bytes after the string to handle + * the 64bit alignment we do later. + */ + buf = kzalloc(PATH_MAX + sizeof(u64), GFP_KERNEL); + if (!buf) { + name = strncpy(tmp, "//enomem", sizeof(tmp)); + goto got_name; + } + name = d_path(&file->f_path, buf, PATH_MAX); + if (IS_ERR(name)) { + name = strncpy(tmp, "//toolong", sizeof(tmp)); + goto got_name; + } + } else { + if (arch_vma_name(mmap_event->vma)) { + name = strncpy(tmp, arch_vma_name(mmap_event->vma), + sizeof(tmp)); + goto got_name; + } + + if (!vma->vm_mm) { + name = strncpy(tmp, "[vdso]", sizeof(tmp)); + goto got_name; + } else if (vma->vm_start <= vma->vm_mm->start_brk && + vma->vm_end >= vma->vm_mm->brk) { + name = strncpy(tmp, "[heap]", sizeof(tmp)); + goto got_name; + } else if (vma->vm_start <= vma->vm_mm->start_stack && + vma->vm_end >= vma->vm_mm->start_stack) { + name = strncpy(tmp, "[stack]", sizeof(tmp)); + goto got_name; + } + + name = strncpy(tmp, "//anon", sizeof(tmp)); + goto got_name; + } + +got_name: + size = ALIGN(strlen(name)+1, sizeof(u64)); + + mmap_event->file_name = name; + mmap_event->file_size = size; + + mmap_event->event_id.header.size = sizeof(mmap_event->event_id) + size; + + rcu_read_lock(); + list_for_each_entry_rcu(pmu, &pmus, entry) { + cpuctx = get_cpu_ptr(pmu->pmu_cpu_context); + if (cpuctx->active_pmu != pmu) + goto next; + perf_event_mmap_ctx(&cpuctx->ctx, mmap_event, + vma->vm_flags & VM_EXEC); + + ctxn = pmu->task_ctx_nr; + if (ctxn < 0) + goto next; + + ctx = rcu_dereference(current->perf_event_ctxp[ctxn]); + if (ctx) { + perf_event_mmap_ctx(ctx, mmap_event, + vma->vm_flags & VM_EXEC); + } +next: + put_cpu_ptr(pmu->pmu_cpu_context); + } + rcu_read_unlock(); + + kfree(buf); +} + +void perf_event_mmap(struct vm_area_struct *vma) +{ + struct perf_mmap_event mmap_event; + + if (!atomic_read(&nr_mmap_events)) + return; + + mmap_event = (struct perf_mmap_event){ + .vma = vma, + /* .file_name */ + /* .file_size */ + .event_id = { + .header = { + .type = PERF_RECORD_MMAP, + .misc = PERF_RECORD_MISC_USER, + /* .size */ + }, + /* .pid */ + /* .tid */ + .start = vma->vm_start, + .len = vma->vm_end - vma->vm_start, + .pgoff = (u64)vma->vm_pgoff << PAGE_SHIFT, + }, + }; + + perf_event_mmap_event(&mmap_event); +} + +/* + * IRQ throttle logging + */ + +static void perf_log_throttle(struct perf_event *event, int enable) +{ + struct perf_output_handle handle; + struct perf_sample_data sample; + int ret; + + struct { + struct perf_event_header header; + u64 time; + u64 id; + u64 stream_id; + } throttle_event = { + .header = { + .type = PERF_RECORD_THROTTLE, + .misc = 0, + .size = sizeof(throttle_event), + }, + .time = perf_clock(), + .id = primary_event_id(event), + .stream_id = event->id, + }; + + if (enable) + throttle_event.header.type = PERF_RECORD_UNTHROTTLE; + + perf_event_header__init_id(&throttle_event.header, &sample, event); + + ret = perf_output_begin(&handle, event, + throttle_event.header.size, 1, 0); + if (ret) + return; + + perf_output_put(&handle, throttle_event); + perf_event__output_id_sample(event, &handle, &sample); + perf_output_end(&handle); +} + +/* + * Generic event overflow handling, sampling. + */ + +static int __perf_event_overflow(struct perf_event *event, int nmi, + int throttle, struct perf_sample_data *data, + struct pt_regs *regs) +{ + int events = atomic_read(&event->event_limit); + struct hw_perf_event *hwc = &event->hw; + int ret = 0; + + /* + * Non-sampling counters might still use the PMI to fold short + * hardware counters, ignore those. + */ + if (unlikely(!is_sampling_event(event))) + return 0; + + if (unlikely(hwc->interrupts >= max_samples_per_tick)) { + if (throttle) { + hwc->interrupts = MAX_INTERRUPTS; + perf_log_throttle(event, 0); + ret = 1; + } + } else + hwc->interrupts++; + + if (event->attr.freq) { + u64 now = perf_clock(); + s64 delta = now - hwc->freq_time_stamp; + + hwc->freq_time_stamp = now; + + if (delta > 0 && delta < 2*TICK_NSEC) + perf_adjust_period(event, delta, hwc->last_period); + } + + /* + * XXX event_limit might not quite work as expected on inherited + * events + */ + + event->pending_kill = POLL_IN; + if (events && atomic_dec_and_test(&event->event_limit)) { + ret = 1; + event->pending_kill = POLL_HUP; + if (nmi) { + event->pending_disable = 1; + irq_work_queue(&event->pending); + } else + perf_event_disable(event); + } + + if (event->overflow_handler) + event->overflow_handler(event, nmi, data, regs); + else + perf_event_output(event, nmi, data, regs); + + return ret; +} + +int perf_event_overflow(struct perf_event *event, int nmi, + struct perf_sample_data *data, + struct pt_regs *regs) +{ + return __perf_event_overflow(event, nmi, 1, data, regs); +} + +/* + * Generic software event infrastructure + */ + +struct swevent_htable { + struct swevent_hlist *swevent_hlist; + struct mutex hlist_mutex; + int hlist_refcount; + + /* Recursion avoidance in each contexts */ + int recursion[PERF_NR_CONTEXTS]; +}; + +static DEFINE_PER_CPU(struct swevent_htable, swevent_htable); + +/* + * We directly increment event->count and keep a second value in + * event->hw.period_left to count intervals. This period event + * is kept in the range [-sample_period, 0] so that we can use the + * sign as trigger. + */ + +static u64 perf_swevent_set_period(struct perf_event *event) +{ + struct hw_perf_event *hwc = &event->hw; + u64 period = hwc->last_period; + u64 nr, offset; + s64 old, val; + + hwc->last_period = hwc->sample_period; + +again: + old = val = local64_read(&hwc->period_left); + if (val < 0) + return 0; + + nr = div64_u64(period + val, period); + offset = nr * period; + val -= offset; + if (local64_cmpxchg(&hwc->period_left, old, val) != old) + goto again; + + return nr; +} + +static void perf_swevent_overflow(struct perf_event *event, u64 overflow, + int nmi, struct perf_sample_data *data, + struct pt_regs *regs) +{ + struct hw_perf_event *hwc = &event->hw; + int throttle = 0; + + data->period = event->hw.last_period; + if (!overflow) + overflow = perf_swevent_set_period(event); + + if (hwc->interrupts == MAX_INTERRUPTS) + return; + + for (; overflow; overflow--) { + if (__perf_event_overflow(event, nmi, throttle, + data, regs)) { + /* + * We inhibit the overflow from happening when + * hwc->interrupts == MAX_INTERRUPTS. + */ + break; + } + throttle = 1; + } +} + +static void perf_swevent_event(struct perf_event *event, u64 nr, + int nmi, struct perf_sample_data *data, + struct pt_regs *regs) +{ + struct hw_perf_event *hwc = &event->hw; + + local64_add(nr, &event->count); + + if (!regs) + return; + + if (!is_sampling_event(event)) + return; + + if (nr == 1 && hwc->sample_period == 1 && !event->attr.freq) + return perf_swevent_overflow(event, 1, nmi, data, regs); + + if (local64_add_negative(nr, &hwc->period_left)) + return; + + perf_swevent_overflow(event, 0, nmi, data, regs); +} + +static int perf_exclude_event(struct perf_event *event, + struct pt_regs *regs) +{ + if (event->hw.state & PERF_HES_STOPPED) + return 1; + + if (regs) { + if (event->attr.exclude_user && user_mode(regs)) + return 1; + + if (event->attr.exclude_kernel && !user_mode(regs)) + return 1; + } + + return 0; +} + +static int perf_swevent_match(struct perf_event *event, + enum perf_type_id type, + u32 event_id, + struct perf_sample_data *data, + struct pt_regs *regs) +{ + if (event->attr.type != type) + return 0; + + if (event->attr.config != event_id) + return 0; + + if (perf_exclude_event(event, regs)) + return 0; + + return 1; +} + +static inline u64 swevent_hash(u64 type, u32 event_id) +{ + u64 val = event_id | (type << 32); + + return hash_64(val, SWEVENT_HLIST_BITS); +} + +static inline struct hlist_head * +__find_swevent_head(struct swevent_hlist *hlist, u64 type, u32 event_id) +{ + u64 hash = swevent_hash(type, event_id); + + return &hlist->heads[hash]; +} + +/* For the read side: events when they trigger */ +static inline struct hlist_head * +find_swevent_head_rcu(struct swevent_htable *swhash, u64 type, u32 event_id) +{ + struct swevent_hlist *hlist; + + hlist = rcu_dereference(swhash->swevent_hlist); + if (!hlist) + return NULL; + + return __find_swevent_head(hlist, type, event_id); +} + +/* For the event head insertion and removal in the hlist */ +static inline struct hlist_head * +find_swevent_head(struct swevent_htable *swhash, struct perf_event *event) +{ + struct swevent_hlist *hlist; + u32 event_id = event->attr.config; + u64 type = event->attr.type; + + /* + * Event scheduling is always serialized against hlist allocation + * and release. Which makes the protected version suitable here. + * The context lock guarantees that. + */ + hlist = rcu_dereference_protected(swhash->swevent_hlist, + lockdep_is_held(&event->ctx->lock)); + if (!hlist) + return NULL; + + return __find_swevent_head(hlist, type, event_id); +} + +static void do_perf_sw_event(enum perf_type_id type, u32 event_id, + u64 nr, int nmi, + struct perf_sample_data *data, + struct pt_regs *regs) +{ + struct swevent_htable *swhash = &__get_cpu_var(swevent_htable); + struct perf_event *event; + struct hlist_node *node; + struct hlist_head *head; + + rcu_read_lock(); + head = find_swevent_head_rcu(swhash, type, event_id); + if (!head) + goto end; + + hlist_for_each_entry_rcu(event, node, head, hlist_entry) { + if (perf_swevent_match(event, type, event_id, data, regs)) + perf_swevent_event(event, nr, nmi, data, regs); + } +end: + rcu_read_unlock(); +} + +int perf_swevent_get_recursion_context(void) +{ + struct swevent_htable *swhash = &__get_cpu_var(swevent_htable); + + return get_recursion_context(swhash->recursion); +} +EXPORT_SYMBOL_GPL(perf_swevent_get_recursion_context); + +inline void perf_swevent_put_recursion_context(int rctx) +{ + struct swevent_htable *swhash = &__get_cpu_var(swevent_htable); + + put_recursion_context(swhash->recursion, rctx); +} + +void __perf_sw_event(u32 event_id, u64 nr, int nmi, + struct pt_regs *regs, u64 addr) +{ + struct perf_sample_data data; + int rctx; + + preempt_disable_notrace(); + rctx = perf_swevent_get_recursion_context(); + if (rctx < 0) + return; + + perf_sample_data_init(&data, addr); + + do_perf_sw_event(PERF_TYPE_SOFTWARE, event_id, nr, nmi, &data, regs); + + perf_swevent_put_recursion_context(rctx); + preempt_enable_notrace(); +} + +static void perf_swevent_read(struct perf_event *event) +{ +} + +static int perf_swevent_add(struct perf_event *event, int flags) +{ + struct swevent_htable *swhash = &__get_cpu_var(swevent_htable); + struct hw_perf_event *hwc = &event->hw; + struct hlist_head *head; + + if (is_sampling_event(event)) { + hwc->last_period = hwc->sample_period; + perf_swevent_set_period(event); + } + + hwc->state = !(flags & PERF_EF_START); + + head = find_swevent_head(swhash, event); + if (WARN_ON_ONCE(!head)) + return -EINVAL; + + hlist_add_head_rcu(&event->hlist_entry, head); + + return 0; +} + +static void perf_swevent_del(struct perf_event *event, int flags) +{ + hlist_del_rcu(&event->hlist_entry); +} + +static void perf_swevent_start(struct perf_event *event, int flags) +{ + event->hw.state = 0; +} + +static void perf_swevent_stop(struct perf_event *event, int flags) +{ + event->hw.state = PERF_HES_STOPPED; +} + +/* Deref the hlist from the update side */ +static inline struct swevent_hlist * +swevent_hlist_deref(struct swevent_htable *swhash) +{ + return rcu_dereference_protected(swhash->swevent_hlist, + lockdep_is_held(&swhash->hlist_mutex)); +} + +static void swevent_hlist_release_rcu(struct rcu_head *rcu_head) +{ + struct swevent_hlist *hlist; + + hlist = container_of(rcu_head, struct swevent_hlist, rcu_head); + kfree(hlist); +} + +static void swevent_hlist_release(struct swevent_htable *swhash) +{ + struct swevent_hlist *hlist = swevent_hlist_deref(swhash); + + if (!hlist) + return; + + rcu_assign_pointer(swhash->swevent_hlist, NULL); + call_rcu(&hlist->rcu_head, swevent_hlist_release_rcu); +} + +static void swevent_hlist_put_cpu(struct perf_event *event, int cpu) +{ + struct swevent_htable *swhash = &per_cpu(swevent_htable, cpu); + + mutex_lock(&swhash->hlist_mutex); + + if (!--swhash->hlist_refcount) + swevent_hlist_release(swhash); + + mutex_unlock(&swhash->hlist_mutex); +} + +static void swevent_hlist_put(struct perf_event *event) +{ + int cpu; + + if (event->cpu != -1) { + swevent_hlist_put_cpu(event, event->cpu); + return; + } + + for_each_possible_cpu(cpu) + swevent_hlist_put_cpu(event, cpu); +} + +static int swevent_hlist_get_cpu(struct perf_event *event, int cpu) +{ + struct swevent_htable *swhash = &per_cpu(swevent_htable, cpu); + int err = 0; + + mutex_lock(&swhash->hlist_mutex); + + if (!swevent_hlist_deref(swhash) && cpu_online(cpu)) { + struct swevent_hlist *hlist; + + hlist = kzalloc(sizeof(*hlist), GFP_KERNEL); + if (!hlist) { + err = -ENOMEM; + goto exit; + } + rcu_assign_pointer(swhash->swevent_hlist, hlist); + } + swhash->hlist_refcount++; +exit: + mutex_unlock(&swhash->hlist_mutex); + + return err; +} + +static int swevent_hlist_get(struct perf_event *event) +{ + int err; + int cpu, failed_cpu; + + if (event->cpu != -1) + return swevent_hlist_get_cpu(event, event->cpu); + + get_online_cpus(); + for_each_possible_cpu(cpu) { + err = swevent_hlist_get_cpu(event, cpu); + if (err) { + failed_cpu = cpu; + goto fail; + } + } + put_online_cpus(); + + return 0; +fail: + for_each_possible_cpu(cpu) { + if (cpu == failed_cpu) + break; + swevent_hlist_put_cpu(event, cpu); + } + + put_online_cpus(); + return err; +} + +struct jump_label_key perf_swevent_enabled[PERF_COUNT_SW_MAX]; + +static void sw_perf_event_destroy(struct perf_event *event) +{ + u64 event_id = event->attr.config; + + WARN_ON(event->parent); + + jump_label_dec(&perf_swevent_enabled[event_id]); + swevent_hlist_put(event); +} + +static int perf_swevent_init(struct perf_event *event) +{ + int event_id = event->attr.config; + + if (event->attr.type != PERF_TYPE_SOFTWARE) + return -ENOENT; + + switch (event_id) { + case PERF_COUNT_SW_CPU_CLOCK: + case PERF_COUNT_SW_TASK_CLOCK: + return -ENOENT; + + default: + break; + } + + if (event_id >= PERF_COUNT_SW_MAX) + return -ENOENT; + + if (!event->parent) { + int err; + + err = swevent_hlist_get(event); + if (err) + return err; + + jump_label_inc(&perf_swevent_enabled[event_id]); + event->destroy = sw_perf_event_destroy; + } + + return 0; +} + +static struct pmu perf_swevent = { + .task_ctx_nr = perf_sw_context, + + .event_init = perf_swevent_init, + .add = perf_swevent_add, + .del = perf_swevent_del, + .start = perf_swevent_start, + .stop = perf_swevent_stop, + .read = perf_swevent_read, +}; + +#ifdef CONFIG_EVENT_TRACING + +static int perf_tp_filter_match(struct perf_event *event, + struct perf_sample_data *data) +{ + void *record = data->raw->data; + + if (likely(!event->filter) || filter_match_preds(event->filter, record)) + return 1; + return 0; +} + +static int perf_tp_event_match(struct perf_event *event, + struct perf_sample_data *data, + struct pt_regs *regs) +{ + if (event->hw.state & PERF_HES_STOPPED) + return 0; + /* + * All tracepoints are from kernel-space. + */ + if (event->attr.exclude_kernel) + return 0; + + if (!perf_tp_filter_match(event, data)) + return 0; + + return 1; +} + +void perf_tp_event(u64 addr, u64 count, void *record, int entry_size, + struct pt_regs *regs, struct hlist_head *head, int rctx) +{ + struct perf_sample_data data; + struct perf_event *event; + struct hlist_node *node; + + struct perf_raw_record raw = { + .size = entry_size, + .data = record, + }; + + perf_sample_data_init(&data, addr); + data.raw = &raw; + + hlist_for_each_entry_rcu(event, node, head, hlist_entry) { + if (perf_tp_event_match(event, &data, regs)) + perf_swevent_event(event, count, 1, &data, regs); + } + + perf_swevent_put_recursion_context(rctx); +} +EXPORT_SYMBOL_GPL(perf_tp_event); + +static void tp_perf_event_destroy(struct perf_event *event) +{ + perf_trace_destroy(event); +} + +static int perf_tp_event_init(struct perf_event *event) +{ + int err; + + if (event->attr.type != PERF_TYPE_TRACEPOINT) + return -ENOENT; + + err = perf_trace_init(event); + if (err) + return err; + + event->destroy = tp_perf_event_destroy; + + return 0; +} + +static struct pmu perf_tracepoint = { + .task_ctx_nr = perf_sw_context, + + .event_init = perf_tp_event_init, + .add = perf_trace_add, + .del = perf_trace_del, + .start = perf_swevent_start, + .stop = perf_swevent_stop, + .read = perf_swevent_read, +}; + +static inline void perf_tp_register(void) +{ + perf_pmu_register(&perf_tracepoint, "tracepoint", PERF_TYPE_TRACEPOINT); +} + +static int perf_event_set_filter(struct perf_event *event, void __user *arg) +{ + char *filter_str; + int ret; + + if (event->attr.type != PERF_TYPE_TRACEPOINT) + return -EINVAL; + + filter_str = strndup_user(arg, PAGE_SIZE); + if (IS_ERR(filter_str)) + return PTR_ERR(filter_str); + + ret = ftrace_profile_set_filter(event, event->attr.config, filter_str); + + kfree(filter_str); + return ret; +} + +static void perf_event_free_filter(struct perf_event *event) +{ + ftrace_profile_free_filter(event); +} + +#else + +static inline void perf_tp_register(void) +{ +} + +static int perf_event_set_filter(struct perf_event *event, void __user *arg) +{ + return -ENOENT; +} + +static void perf_event_free_filter(struct perf_event *event) +{ +} + +#endif /* CONFIG_EVENT_TRACING */ + +#ifdef CONFIG_HAVE_HW_BREAKPOINT +void perf_bp_event(struct perf_event *bp, void *data) +{ + struct perf_sample_data sample; + struct pt_regs *regs = data; + + perf_sample_data_init(&sample, bp->attr.bp_addr); + + if (!bp->hw.state && !perf_exclude_event(bp, regs)) + perf_swevent_event(bp, 1, 1, &sample, regs); +} +#endif + +/* + * hrtimer based swevent callback + */ + +static enum hrtimer_restart perf_swevent_hrtimer(struct hrtimer *hrtimer) +{ + enum hrtimer_restart ret = HRTIMER_RESTART; + struct perf_sample_data data; + struct pt_regs *regs; + struct perf_event *event; + u64 period; + + event = container_of(hrtimer, struct perf_event, hw.hrtimer); + + if (event->state != PERF_EVENT_STATE_ACTIVE) + return HRTIMER_NORESTART; + + event->pmu->read(event); + + perf_sample_data_init(&data, 0); + data.period = event->hw.last_period; + regs = get_irq_regs(); + + if (regs && !perf_exclude_event(event, regs)) { + if (!(event->attr.exclude_idle && current->pid == 0)) + if (perf_event_overflow(event, 0, &data, regs)) + ret = HRTIMER_NORESTART; + } + + period = max_t(u64, 10000, event->hw.sample_period); + hrtimer_forward_now(hrtimer, ns_to_ktime(period)); + + return ret; +} + +static void perf_swevent_start_hrtimer(struct perf_event *event) +{ + struct hw_perf_event *hwc = &event->hw; + s64 period; + + if (!is_sampling_event(event)) + return; + + period = local64_read(&hwc->period_left); + if (period) { + if (period < 0) + period = 10000; + + local64_set(&hwc->period_left, 0); + } else { + period = max_t(u64, 10000, hwc->sample_period); + } + __hrtimer_start_range_ns(&hwc->hrtimer, + ns_to_ktime(period), 0, + HRTIMER_MODE_REL_PINNED, 0); +} + +static void perf_swevent_cancel_hrtimer(struct perf_event *event) +{ + struct hw_perf_event *hwc = &event->hw; + + if (is_sampling_event(event)) { + ktime_t remaining = hrtimer_get_remaining(&hwc->hrtimer); + local64_set(&hwc->period_left, ktime_to_ns(remaining)); + + hrtimer_cancel(&hwc->hrtimer); + } +} + +static void perf_swevent_init_hrtimer(struct perf_event *event) +{ + struct hw_perf_event *hwc = &event->hw; + + if (!is_sampling_event(event)) + return; + + hrtimer_init(&hwc->hrtimer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); + hwc->hrtimer.function = perf_swevent_hrtimer; + + /* + * Since hrtimers have a fixed rate, we can do a static freq->period + * mapping and avoid the whole period adjust feedback stuff. + */ + if (event->attr.freq) { + long freq = event->attr.sample_freq; + + event->attr.sample_period = NSEC_PER_SEC / freq; + hwc->sample_period = event->attr.sample_period; + local64_set(&hwc->period_left, hwc->sample_period); + event->attr.freq = 0; + } +} + +/* + * Software event: cpu wall time clock + */ + +static void cpu_clock_event_update(struct perf_event *event) +{ + s64 prev; + u64 now; + + now = local_clock(); + prev = local64_xchg(&event->hw.prev_count, now); + local64_add(now - prev, &event->count); +} + +static void cpu_clock_event_start(struct perf_event *event, int flags) +{ + local64_set(&event->hw.prev_count, local_clock()); + perf_swevent_start_hrtimer(event); +} + +static void cpu_clock_event_stop(struct perf_event *event, int flags) +{ + perf_swevent_cancel_hrtimer(event); + cpu_clock_event_update(event); +} + +static int cpu_clock_event_add(struct perf_event *event, int flags) +{ + if (flags & PERF_EF_START) + cpu_clock_event_start(event, flags); + + return 0; +} + +static void cpu_clock_event_del(struct perf_event *event, int flags) +{ + cpu_clock_event_stop(event, flags); +} + +static void cpu_clock_event_read(struct perf_event *event) +{ + cpu_clock_event_update(event); +} + +static int cpu_clock_event_init(struct perf_event *event) +{ + if (event->attr.type != PERF_TYPE_SOFTWARE) + return -ENOENT; + + if (event->attr.config != PERF_COUNT_SW_CPU_CLOCK) + return -ENOENT; + + perf_swevent_init_hrtimer(event); + + return 0; +} + +static struct pmu perf_cpu_clock = { + .task_ctx_nr = perf_sw_context, + + .event_init = cpu_clock_event_init, + .add = cpu_clock_event_add, + .del = cpu_clock_event_del, + .start = cpu_clock_event_start, + .stop = cpu_clock_event_stop, + .read = cpu_clock_event_read, +}; + +/* + * Software event: task time clock + */ + +static void task_clock_event_update(struct perf_event *event, u64 now) +{ + u64 prev; + s64 delta; + + prev = local64_xchg(&event->hw.prev_count, now); + delta = now - prev; + local64_add(delta, &event->count); +} + +static void task_clock_event_start(struct perf_event *event, int flags) +{ + local64_set(&event->hw.prev_count, event->ctx->time); + perf_swevent_start_hrtimer(event); +} + +static void task_clock_event_stop(struct perf_event *event, int flags) +{ + perf_swevent_cancel_hrtimer(event); + task_clock_event_update(event, event->ctx->time); +} + +static int task_clock_event_add(struct perf_event *event, int flags) +{ + if (flags & PERF_EF_START) + task_clock_event_start(event, flags); + + return 0; +} + +static void task_clock_event_del(struct perf_event *event, int flags) +{ + task_clock_event_stop(event, PERF_EF_UPDATE); +} + +static void task_clock_event_read(struct perf_event *event) +{ + u64 now = perf_clock(); + u64 delta = now - event->ctx->timestamp; + u64 time = event->ctx->time + delta; + + task_clock_event_update(event, time); +} + +static int task_clock_event_init(struct perf_event *event) +{ + if (event->attr.type != PERF_TYPE_SOFTWARE) + return -ENOENT; + + if (event->attr.config != PERF_COUNT_SW_TASK_CLOCK) + return -ENOENT; + + perf_swevent_init_hrtimer(event); + + return 0; +} + +static struct pmu perf_task_clock = { + .task_ctx_nr = perf_sw_context, + + .event_init = task_clock_event_init, + .add = task_clock_event_add, + .del = task_clock_event_del, + .start = task_clock_event_start, + .stop = task_clock_event_stop, + .read = task_clock_event_read, +}; + +static void perf_pmu_nop_void(struct pmu *pmu) +{ +} + +static int perf_pmu_nop_int(struct pmu *pmu) +{ + return 0; +} + +static void perf_pmu_start_txn(struct pmu *pmu) +{ + perf_pmu_disable(pmu); +} + +static int perf_pmu_commit_txn(struct pmu *pmu) +{ + perf_pmu_enable(pmu); + return 0; +} + +static void perf_pmu_cancel_txn(struct pmu *pmu) +{ + perf_pmu_enable(pmu); +} + +/* + * Ensures all contexts with the same task_ctx_nr have the same + * pmu_cpu_context too. + */ +static void *find_pmu_context(int ctxn) +{ + struct pmu *pmu; + + if (ctxn < 0) + return NULL; + + list_for_each_entry(pmu, &pmus, entry) { + if (pmu->task_ctx_nr == ctxn) + return pmu->pmu_cpu_context; + } + + return NULL; +} + +static void update_pmu_context(struct pmu *pmu, struct pmu *old_pmu) +{ + int cpu; + + for_each_possible_cpu(cpu) { + struct perf_cpu_context *cpuctx; + + cpuctx = per_cpu_ptr(pmu->pmu_cpu_context, cpu); + + if (cpuctx->active_pmu == old_pmu) + cpuctx->active_pmu = pmu; + } +} + +static void free_pmu_context(struct pmu *pmu) +{ + struct pmu *i; + + mutex_lock(&pmus_lock); + /* + * Like a real lame refcount. + */ + list_for_each_entry(i, &pmus, entry) { + if (i->pmu_cpu_context == pmu->pmu_cpu_context) { + update_pmu_context(i, pmu); + goto out; + } + } + + free_percpu(pmu->pmu_cpu_context); +out: + mutex_unlock(&pmus_lock); +} +static struct idr pmu_idr; + +static ssize_t +type_show(struct device *dev, struct device_attribute *attr, char *page) +{ + struct pmu *pmu = dev_get_drvdata(dev); + + return snprintf(page, PAGE_SIZE-1, "%d\n", pmu->type); +} + +static struct device_attribute pmu_dev_attrs[] = { + __ATTR_RO(type), + __ATTR_NULL, +}; + +static int pmu_bus_running; +static struct bus_type pmu_bus = { + .name = "event_source", + .dev_attrs = pmu_dev_attrs, +}; + +static void pmu_dev_release(struct device *dev) +{ + kfree(dev); +} + +static int pmu_dev_alloc(struct pmu *pmu) +{ + int ret = -ENOMEM; + + pmu->dev = kzalloc(sizeof(struct device), GFP_KERNEL); + if (!pmu->dev) + goto out; + + device_initialize(pmu->dev); + ret = dev_set_name(pmu->dev, "%s", pmu->name); + if (ret) + goto free_dev; + + dev_set_drvdata(pmu->dev, pmu); + pmu->dev->bus = &pmu_bus; + pmu->dev->release = pmu_dev_release; + ret = device_add(pmu->dev); + if (ret) + goto free_dev; + +out: + return ret; + +free_dev: + put_device(pmu->dev); + goto out; +} + +static struct lock_class_key cpuctx_mutex; + +int perf_pmu_register(struct pmu *pmu, char *name, int type) +{ + int cpu, ret; + + mutex_lock(&pmus_lock); + ret = -ENOMEM; + pmu->pmu_disable_count = alloc_percpu(int); + if (!pmu->pmu_disable_count) + goto unlock; + + pmu->type = -1; + if (!name) + goto skip_type; + pmu->name = name; + + if (type < 0) { + int err = idr_pre_get(&pmu_idr, GFP_KERNEL); + if (!err) + goto free_pdc; + + err = idr_get_new_above(&pmu_idr, pmu, PERF_TYPE_MAX, &type); + if (err) { + ret = err; + goto free_pdc; + } + } + pmu->type = type; + + if (pmu_bus_running) { + ret = pmu_dev_alloc(pmu); + if (ret) + goto free_idr; + } + +skip_type: + pmu->pmu_cpu_context = find_pmu_context(pmu->task_ctx_nr); + if (pmu->pmu_cpu_context) + goto got_cpu_context; + + pmu->pmu_cpu_context = alloc_percpu(struct perf_cpu_context); + if (!pmu->pmu_cpu_context) + goto free_dev; + + for_each_possible_cpu(cpu) { + struct perf_cpu_context *cpuctx; + + cpuctx = per_cpu_ptr(pmu->pmu_cpu_context, cpu); + __perf_event_init_context(&cpuctx->ctx); + lockdep_set_class(&cpuctx->ctx.mutex, &cpuctx_mutex); + cpuctx->ctx.type = cpu_context; + cpuctx->ctx.pmu = pmu; + cpuctx->jiffies_interval = 1; + INIT_LIST_HEAD(&cpuctx->rotation_list); + cpuctx->active_pmu = pmu; + } + +got_cpu_context: + if (!pmu->start_txn) { + if (pmu->pmu_enable) { + /* + * If we have pmu_enable/pmu_disable calls, install + * transaction stubs that use that to try and batch + * hardware accesses. + */ + pmu->start_txn = perf_pmu_start_txn; + pmu->commit_txn = perf_pmu_commit_txn; + pmu->cancel_txn = perf_pmu_cancel_txn; + } else { + pmu->start_txn = perf_pmu_nop_void; + pmu->commit_txn = perf_pmu_nop_int; + pmu->cancel_txn = perf_pmu_nop_void; + } + } + + if (!pmu->pmu_enable) { + pmu->pmu_enable = perf_pmu_nop_void; + pmu->pmu_disable = perf_pmu_nop_void; + } + + list_add_rcu(&pmu->entry, &pmus); + ret = 0; +unlock: + mutex_unlock(&pmus_lock); + + return ret; + +free_dev: + device_del(pmu->dev); + put_device(pmu->dev); + +free_idr: + if (pmu->type >= PERF_TYPE_MAX) + idr_remove(&pmu_idr, pmu->type); + +free_pdc: + free_percpu(pmu->pmu_disable_count); + goto unlock; +} + +void perf_pmu_unregister(struct pmu *pmu) +{ + mutex_lock(&pmus_lock); + list_del_rcu(&pmu->entry); + mutex_unlock(&pmus_lock); + + /* + * We dereference the pmu list under both SRCU and regular RCU, so + * synchronize against both of those. + */ + synchronize_srcu(&pmus_srcu); + synchronize_rcu(); + + free_percpu(pmu->pmu_disable_count); + if (pmu->type >= PERF_TYPE_MAX) + idr_remove(&pmu_idr, pmu->type); + device_del(pmu->dev); + put_device(pmu->dev); + free_pmu_context(pmu); +} + +struct pmu *perf_init_event(struct perf_event *event) +{ + struct pmu *pmu = NULL; + int idx; + int ret; + + idx = srcu_read_lock(&pmus_srcu); + + rcu_read_lock(); + pmu = idr_find(&pmu_idr, event->attr.type); + rcu_read_unlock(); + if (pmu) { + ret = pmu->event_init(event); + if (ret) + pmu = ERR_PTR(ret); + goto unlock; + } + + list_for_each_entry_rcu(pmu, &pmus, entry) { + ret = pmu->event_init(event); + if (!ret) + goto unlock; + + if (ret != -ENOENT) { + pmu = ERR_PTR(ret); + goto unlock; + } + } + pmu = ERR_PTR(-ENOENT); +unlock: + srcu_read_unlock(&pmus_srcu, idx); + + return pmu; +} + +/* + * Allocate and initialize a event structure + */ +static struct perf_event * +perf_event_alloc(struct perf_event_attr *attr, int cpu, + struct task_struct *task, + struct perf_event *group_leader, + struct perf_event *parent_event, + perf_overflow_handler_t overflow_handler) +{ + struct pmu *pmu; + struct perf_event *event; + struct hw_perf_event *hwc; + long err; + + if ((unsigned)cpu >= nr_cpu_ids) { + if (!task || cpu != -1) + return ERR_PTR(-EINVAL); + } + + event = kzalloc(sizeof(*event), GFP_KERNEL); + if (!event) + return ERR_PTR(-ENOMEM); + + /* + * Single events are their own group leaders, with an + * empty sibling list: + */ + if (!group_leader) + group_leader = event; + + mutex_init(&event->child_mutex); + INIT_LIST_HEAD(&event->child_list); + + INIT_LIST_HEAD(&event->group_entry); + INIT_LIST_HEAD(&event->event_entry); + INIT_LIST_HEAD(&event->sibling_list); + init_waitqueue_head(&event->waitq); + init_irq_work(&event->pending, perf_pending_event); + + mutex_init(&event->mmap_mutex); + + event->cpu = cpu; + event->attr = *attr; + event->group_leader = group_leader; + event->pmu = NULL; + event->oncpu = -1; + + event->parent = parent_event; + + event->ns = get_pid_ns(current->nsproxy->pid_ns); + event->id = atomic64_inc_return(&perf_event_id); + + event->state = PERF_EVENT_STATE_INACTIVE; + + if (task) { + event->attach_state = PERF_ATTACH_TASK; +#ifdef CONFIG_HAVE_HW_BREAKPOINT + /* + * hw_breakpoint is a bit difficult here.. + */ + if (attr->type == PERF_TYPE_BREAKPOINT) + event->hw.bp_target = task; +#endif + } + + if (!overflow_handler && parent_event) + overflow_handler = parent_event->overflow_handler; + + event->overflow_handler = overflow_handler; + + if (attr->disabled) + event->state = PERF_EVENT_STATE_OFF; + + pmu = NULL; + + hwc = &event->hw; + hwc->sample_period = attr->sample_period; + if (attr->freq && attr->sample_freq) + hwc->sample_period = 1; + hwc->last_period = hwc->sample_period; + + local64_set(&hwc->period_left, hwc->sample_period); + + /* + * we currently do not support PERF_FORMAT_GROUP on inherited events + */ + if (attr->inherit && (attr->read_format & PERF_FORMAT_GROUP)) + goto done; + + pmu = perf_init_event(event); + +done: + err = 0; + if (!pmu) + err = -EINVAL; + else if (IS_ERR(pmu)) + err = PTR_ERR(pmu); + + if (err) { + if (event->ns) + put_pid_ns(event->ns); + kfree(event); + return ERR_PTR(err); + } + + event->pmu = pmu; + + if (!event->parent) { + if (event->attach_state & PERF_ATTACH_TASK) + jump_label_inc(&perf_sched_events); + if (event->attr.mmap || event->attr.mmap_data) + atomic_inc(&nr_mmap_events); + if (event->attr.comm) + atomic_inc(&nr_comm_events); + if (event->attr.task) + atomic_inc(&nr_task_events); + if (event->attr.sample_type & PERF_SAMPLE_CALLCHAIN) { + err = get_callchain_buffers(); + if (err) { + free_event(event); + return ERR_PTR(err); + } + } + } + + return event; +} + +static int perf_copy_attr(struct perf_event_attr __user *uattr, + struct perf_event_attr *attr) +{ + u32 size; + int ret; + + if (!access_ok(VERIFY_WRITE, uattr, PERF_ATTR_SIZE_VER0)) + return -EFAULT; + + /* + * zero the full structure, so that a short copy will be nice. + */ + memset(attr, 0, sizeof(*attr)); + + ret = get_user(size, &uattr->size); + if (ret) + return ret; + + if (size > PAGE_SIZE) /* silly large */ + goto err_size; + + if (!size) /* abi compat */ + size = PERF_ATTR_SIZE_VER0; + + if (size < PERF_ATTR_SIZE_VER0) + goto err_size; + + /* + * If we're handed a bigger struct than we know of, + * ensure all the unknown bits are 0 - i.e. new + * user-space does not rely on any kernel feature + * extensions we dont know about yet. + */ + if (size > sizeof(*attr)) { + unsigned char __user *addr; + unsigned char __user *end; + unsigned char val; + + addr = (void __user *)uattr + sizeof(*attr); + end = (void __user *)uattr + size; + + for (; addr < end; addr++) { + ret = get_user(val, addr); + if (ret) + return ret; + if (val) + goto err_size; + } + size = sizeof(*attr); + } + + ret = copy_from_user(attr, uattr, size); + if (ret) + return -EFAULT; + + /* + * If the type exists, the corresponding creation will verify + * the attr->config. + */ + if (attr->type >= PERF_TYPE_MAX) + return -EINVAL; + + if (attr->__reserved_1) + return -EINVAL; + + if (attr->sample_type & ~(PERF_SAMPLE_MAX-1)) + return -EINVAL; + + if (attr->read_format & ~(PERF_FORMAT_MAX-1)) + return -EINVAL; + +out: + return ret; + +err_size: + put_user(sizeof(*attr), &uattr->size); + ret = -E2BIG; + goto out; +} + +static int +perf_event_set_output(struct perf_event *event, struct perf_event *output_event) +{ + struct perf_buffer *buffer = NULL, *old_buffer = NULL; + int ret = -EINVAL; + + if (!output_event) + goto set; + + /* don't allow circular references */ + if (event == output_event) + goto out; + + /* + * Don't allow cross-cpu buffers + */ + if (output_event->cpu != event->cpu) + goto out; + + /* + * If its not a per-cpu buffer, it must be the same task. + */ + if (output_event->cpu == -1 && output_event->ctx != event->ctx) + goto out; + +set: + mutex_lock(&event->mmap_mutex); + /* Can't redirect output if we've got an active mmap() */ + if (atomic_read(&event->mmap_count)) + goto unlock; + + if (output_event) { + /* get the buffer we want to redirect to */ + buffer = perf_buffer_get(output_event); + if (!buffer) + goto unlock; + } + + old_buffer = event->buffer; + rcu_assign_pointer(event->buffer, buffer); + ret = 0; +unlock: + mutex_unlock(&event->mmap_mutex); + + if (old_buffer) + perf_buffer_put(old_buffer); +out: + return ret; +} + +/** + * sys_perf_event_open - open a performance event, associate it to a task/cpu + * + * @attr_uptr: event_id type attributes for monitoring/sampling + * @pid: target pid + * @cpu: target cpu + * @group_fd: group leader event fd + */ +SYSCALL_DEFINE5(perf_event_open, + struct perf_event_attr __user *, attr_uptr, + pid_t, pid, int, cpu, int, group_fd, unsigned long, flags) +{ + struct perf_event *group_leader = NULL, *output_event = NULL; + struct perf_event *event, *sibling; + struct perf_event_attr attr; + struct perf_event_context *ctx; + struct file *event_file = NULL; + struct file *group_file = NULL; + struct task_struct *task = NULL; + struct pmu *pmu; + int event_fd; + int move_group = 0; + int fput_needed = 0; + int err; + + /* for future expandability... */ + if (flags & ~PERF_FLAG_ALL) + return -EINVAL; + + err = perf_copy_attr(attr_uptr, &attr); + if (err) + return err; + + if (!attr.exclude_kernel) { + if (perf_paranoid_kernel() && !capable(CAP_SYS_ADMIN)) + return -EACCES; + } + + if (attr.freq) { + if (attr.sample_freq > sysctl_perf_event_sample_rate) + return -EINVAL; + } + + /* + * In cgroup mode, the pid argument is used to pass the fd + * opened to the cgroup directory in cgroupfs. The cpu argument + * designates the cpu on which to monitor threads from that + * cgroup. + */ + if ((flags & PERF_FLAG_PID_CGROUP) && (pid == -1 || cpu == -1)) + return -EINVAL; + + event_fd = get_unused_fd_flags(O_RDWR); + if (event_fd < 0) + return event_fd; + + if (group_fd != -1) { + group_leader = perf_fget_light(group_fd, &fput_needed); + if (IS_ERR(group_leader)) { + err = PTR_ERR(group_leader); + goto err_fd; + } + group_file = group_leader->filp; + if (flags & PERF_FLAG_FD_OUTPUT) + output_event = group_leader; + if (flags & PERF_FLAG_FD_NO_GROUP) + group_leader = NULL; + } + + if (pid != -1 && !(flags & PERF_FLAG_PID_CGROUP)) { + task = find_lively_task_by_vpid(pid); + if (IS_ERR(task)) { + err = PTR_ERR(task); + goto err_group_fd; + } + } + + event = perf_event_alloc(&attr, cpu, task, group_leader, NULL, NULL); + if (IS_ERR(event)) { + err = PTR_ERR(event); + goto err_task; + } + + if (flags & PERF_FLAG_PID_CGROUP) { + err = perf_cgroup_connect(pid, event, &attr, group_leader); + if (err) + goto err_alloc; + /* + * one more event: + * - that has cgroup constraint on event->cpu + * - that may need work on context switch + */ + atomic_inc(&per_cpu(perf_cgroup_events, event->cpu)); + jump_label_inc(&perf_sched_events); + } + + /* + * Special case software events and allow them to be part of + * any hardware group. + */ + pmu = event->pmu; + + if (group_leader && + (is_software_event(event) != is_software_event(group_leader))) { + if (is_software_event(event)) { + /* + * If event and group_leader are not both a software + * event, and event is, then group leader is not. + * + * Allow the addition of software events to !software + * groups, this is safe because software events never + * fail to schedule. + */ + pmu = group_leader->pmu; + } else if (is_software_event(group_leader) && + (group_leader->group_flags & PERF_GROUP_SOFTWARE)) { + /* + * In case the group is a pure software group, and we + * try to add a hardware event, move the whole group to + * the hardware context. + */ + move_group = 1; + } + } + + /* + * Get the target context (task or percpu): + */ + ctx = find_get_context(pmu, task, cpu); + if (IS_ERR(ctx)) { + err = PTR_ERR(ctx); + goto err_alloc; + } + + if (task) { + put_task_struct(task); + task = NULL; + } + + /* + * Look up the group leader (we will attach this event to it): + */ + if (group_leader) { + err = -EINVAL; + + /* + * Do not allow a recursive hierarchy (this new sibling + * becoming part of another group-sibling): + */ + if (group_leader->group_leader != group_leader) + goto err_context; + /* + * Do not allow to attach to a group in a different + * task or CPU context: + */ + if (move_group) { + if (group_leader->ctx->type != ctx->type) + goto err_context; + } else { + if (group_leader->ctx != ctx) + goto err_context; + } + + /* + * Only a group leader can be exclusive or pinned + */ + if (attr.exclusive || attr.pinned) + goto err_context; + } + + if (output_event) { + err = perf_event_set_output(event, output_event); + if (err) + goto err_context; + } + + event_file = anon_inode_getfile("[perf_event]", &perf_fops, event, O_RDWR); + if (IS_ERR(event_file)) { + err = PTR_ERR(event_file); + goto err_context; + } + + if (move_group) { + struct perf_event_context *gctx = group_leader->ctx; + + mutex_lock(&gctx->mutex); + perf_remove_from_context(group_leader); + list_for_each_entry(sibling, &group_leader->sibling_list, + group_entry) { + perf_remove_from_context(sibling); + put_ctx(gctx); + } + mutex_unlock(&gctx->mutex); + put_ctx(gctx); + } + + event->filp = event_file; + WARN_ON_ONCE(ctx->parent_ctx); + mutex_lock(&ctx->mutex); + + if (move_group) { + perf_install_in_context(ctx, group_leader, cpu); + get_ctx(ctx); + list_for_each_entry(sibling, &group_leader->sibling_list, + group_entry) { + perf_install_in_context(ctx, sibling, cpu); + get_ctx(ctx); + } + } + + perf_install_in_context(ctx, event, cpu); + ++ctx->generation; + perf_unpin_context(ctx); + mutex_unlock(&ctx->mutex); + + event->owner = current; + + mutex_lock(¤t->perf_event_mutex); + list_add_tail(&event->owner_entry, ¤t->perf_event_list); + mutex_unlock(¤t->perf_event_mutex); + + /* + * Precalculate sample_data sizes + */ + perf_event__header_size(event); + perf_event__id_header_size(event); + + /* + * Drop the reference on the group_event after placing the + * new event on the sibling_list. This ensures destruction + * of the group leader will find the pointer to itself in + * perf_group_detach(). + */ + fput_light(group_file, fput_needed); + fd_install(event_fd, event_file); + return event_fd; + +err_context: + perf_unpin_context(ctx); + put_ctx(ctx); +err_alloc: + free_event(event); +err_task: + if (task) + put_task_struct(task); +err_group_fd: + fput_light(group_file, fput_needed); +err_fd: + put_unused_fd(event_fd); + return err; +} + +/** + * perf_event_create_kernel_counter + * + * @attr: attributes of the counter to create + * @cpu: cpu in which the counter is bound + * @task: task to profile (NULL for percpu) + */ +struct perf_event * +perf_event_create_kernel_counter(struct perf_event_attr *attr, int cpu, + struct task_struct *task, + perf_overflow_handler_t overflow_handler) +{ + struct perf_event_context *ctx; + struct perf_event *event; + int err; + + /* + * Get the target context (task or percpu): + */ + + event = perf_event_alloc(attr, cpu, task, NULL, NULL, overflow_handler); + if (IS_ERR(event)) { + err = PTR_ERR(event); + goto err; + } + + ctx = find_get_context(event->pmu, task, cpu); + if (IS_ERR(ctx)) { + err = PTR_ERR(ctx); + goto err_free; + } + + event->filp = NULL; + WARN_ON_ONCE(ctx->parent_ctx); + mutex_lock(&ctx->mutex); + perf_install_in_context(ctx, event, cpu); + ++ctx->generation; + perf_unpin_context(ctx); + mutex_unlock(&ctx->mutex); + + return event; + +err_free: + free_event(event); +err: + return ERR_PTR(err); +} +EXPORT_SYMBOL_GPL(perf_event_create_kernel_counter); + +static void sync_child_event(struct perf_event *child_event, + struct task_struct *child) +{ + struct perf_event *parent_event = child_event->parent; + u64 child_val; + + if (child_event->attr.inherit_stat) + perf_event_read_event(child_event, child); + + child_val = perf_event_count(child_event); + + /* + * Add back the child's count to the parent's count: + */ + atomic64_add(child_val, &parent_event->child_count); + atomic64_add(child_event->total_time_enabled, + &parent_event->child_total_time_enabled); + atomic64_add(child_event->total_time_running, + &parent_event->child_total_time_running); + + /* + * Remove this event from the parent's list + */ + WARN_ON_ONCE(parent_event->ctx->parent_ctx); + mutex_lock(&parent_event->child_mutex); + list_del_init(&child_event->child_list); + mutex_unlock(&parent_event->child_mutex); + + /* + * Release the parent event, if this was the last + * reference to it. + */ + fput(parent_event->filp); +} + +static void +__perf_event_exit_task(struct perf_event *child_event, + struct perf_event_context *child_ctx, + struct task_struct *child) +{ + if (child_event->parent) { + raw_spin_lock_irq(&child_ctx->lock); + perf_group_detach(child_event); + raw_spin_unlock_irq(&child_ctx->lock); + } + + perf_remove_from_context(child_event); + + /* + * It can happen that the parent exits first, and has events + * that are still around due to the child reference. These + * events need to be zapped. + */ + if (child_event->parent) { + sync_child_event(child_event, child); + free_event(child_event); + } +} + +static void perf_event_exit_task_context(struct task_struct *child, int ctxn) +{ + struct perf_event *child_event, *tmp; + struct perf_event_context *child_ctx; + unsigned long flags; + + if (likely(!child->perf_event_ctxp[ctxn])) { + perf_event_task(child, NULL, 0); + return; + } + + local_irq_save(flags); + /* + * We can't reschedule here because interrupts are disabled, + * and either child is current or it is a task that can't be + * scheduled, so we are now safe from rescheduling changing + * our context. + */ + child_ctx = rcu_dereference_raw(child->perf_event_ctxp[ctxn]); + task_ctx_sched_out(child_ctx, EVENT_ALL); + + /* + * Take the context lock here so that if find_get_context is + * reading child->perf_event_ctxp, we wait until it has + * incremented the context's refcount before we do put_ctx below. + */ + raw_spin_lock(&child_ctx->lock); + child->perf_event_ctxp[ctxn] = NULL; + /* + * If this context is a clone; unclone it so it can't get + * swapped to another process while we're removing all + * the events from it. + */ + unclone_ctx(child_ctx); + update_context_time(child_ctx); + raw_spin_unlock_irqrestore(&child_ctx->lock, flags); + + /* + * Report the task dead after unscheduling the events so that we + * won't get any samples after PERF_RECORD_EXIT. We can however still + * get a few PERF_RECORD_READ events. + */ + perf_event_task(child, child_ctx, 0); + + /* + * We can recurse on the same lock type through: + * + * __perf_event_exit_task() + * sync_child_event() + * fput(parent_event->filp) + * perf_release() + * mutex_lock(&ctx->mutex) + * + * But since its the parent context it won't be the same instance. + */ + mutex_lock(&child_ctx->mutex); + +again: + list_for_each_entry_safe(child_event, tmp, &child_ctx->pinned_groups, + group_entry) + __perf_event_exit_task(child_event, child_ctx, child); + + list_for_each_entry_safe(child_event, tmp, &child_ctx->flexible_groups, + group_entry) + __perf_event_exit_task(child_event, child_ctx, child); + + /* + * If the last event was a group event, it will have appended all + * its siblings to the list, but we obtained 'tmp' before that which + * will still point to the list head terminating the iteration. + */ + if (!list_empty(&child_ctx->pinned_groups) || + !list_empty(&child_ctx->flexible_groups)) + goto again; + + mutex_unlock(&child_ctx->mutex); + + put_ctx(child_ctx); +} + +/* + * When a child task exits, feed back event values to parent events. + */ +void perf_event_exit_task(struct task_struct *child) +{ + struct perf_event *event, *tmp; + int ctxn; + + mutex_lock(&child->perf_event_mutex); + list_for_each_entry_safe(event, tmp, &child->perf_event_list, + owner_entry) { + list_del_init(&event->owner_entry); + + /* + * Ensure the list deletion is visible before we clear + * the owner, closes a race against perf_release() where + * we need to serialize on the owner->perf_event_mutex. + */ + smp_wmb(); + event->owner = NULL; + } + mutex_unlock(&child->perf_event_mutex); + + for_each_task_context_nr(ctxn) + perf_event_exit_task_context(child, ctxn); +} + +static void perf_free_event(struct perf_event *event, + struct perf_event_context *ctx) +{ + struct perf_event *parent = event->parent; + + if (WARN_ON_ONCE(!parent)) + return; + + mutex_lock(&parent->child_mutex); + list_del_init(&event->child_list); + mutex_unlock(&parent->child_mutex); + + fput(parent->filp); + + perf_group_detach(event); + list_del_event(event, ctx); + free_event(event); +} + +/* + * free an unexposed, unused context as created by inheritance by + * perf_event_init_task below, used by fork() in case of fail. + */ +void perf_event_free_task(struct task_struct *task) +{ + struct perf_event_context *ctx; + struct perf_event *event, *tmp; + int ctxn; + + for_each_task_context_nr(ctxn) { + ctx = task->perf_event_ctxp[ctxn]; + if (!ctx) + continue; + + mutex_lock(&ctx->mutex); +again: + list_for_each_entry_safe(event, tmp, &ctx->pinned_groups, + group_entry) + perf_free_event(event, ctx); + + list_for_each_entry_safe(event, tmp, &ctx->flexible_groups, + group_entry) + perf_free_event(event, ctx); + + if (!list_empty(&ctx->pinned_groups) || + !list_empty(&ctx->flexible_groups)) + goto again; + + mutex_unlock(&ctx->mutex); + + put_ctx(ctx); + } +} + +void perf_event_delayed_put(struct task_struct *task) +{ + int ctxn; + + for_each_task_context_nr(ctxn) + WARN_ON_ONCE(task->perf_event_ctxp[ctxn]); +} + +/* + * inherit a event from parent task to child task: + */ +static struct perf_event * +inherit_event(struct perf_event *parent_event, + struct task_struct *parent, + struct perf_event_context *parent_ctx, + struct task_struct *child, + struct perf_event *group_leader, + struct perf_event_context *child_ctx) +{ + struct perf_event *child_event; + unsigned long flags; + + /* + * Instead of creating recursive hierarchies of events, + * we link inherited events back to the original parent, + * which has a filp for sure, which we use as the reference + * count: + */ + if (parent_event->parent) + parent_event = parent_event->parent; + + child_event = perf_event_alloc(&parent_event->attr, + parent_event->cpu, + child, + group_leader, parent_event, + NULL); + if (IS_ERR(child_event)) + return child_event; + get_ctx(child_ctx); + + /* + * Make the child state follow the state of the parent event, + * not its attr.disabled bit. We hold the parent's mutex, + * so we won't race with perf_event_{en, dis}able_family. + */ + if (parent_event->state >= PERF_EVENT_STATE_INACTIVE) + child_event->state = PERF_EVENT_STATE_INACTIVE; + else + child_event->state = PERF_EVENT_STATE_OFF; + + if (parent_event->attr.freq) { + u64 sample_period = parent_event->hw.sample_period; + struct hw_perf_event *hwc = &child_event->hw; + + hwc->sample_period = sample_period; + hwc->last_period = sample_period; + + local64_set(&hwc->period_left, sample_period); + } + + child_event->ctx = child_ctx; + child_event->overflow_handler = parent_event->overflow_handler; + + /* + * Precalculate sample_data sizes + */ + perf_event__header_size(child_event); + perf_event__id_header_size(child_event); + + /* + * Link it up in the child's context: + */ + raw_spin_lock_irqsave(&child_ctx->lock, flags); + add_event_to_ctx(child_event, child_ctx); + raw_spin_unlock_irqrestore(&child_ctx->lock, flags); + + /* + * Get a reference to the parent filp - we will fput it + * when the child event exits. This is safe to do because + * we are in the parent and we know that the filp still + * exists and has a nonzero count: + */ + atomic_long_inc(&parent_event->filp->f_count); + + /* + * Link this into the parent event's child list + */ + WARN_ON_ONCE(parent_event->ctx->parent_ctx); + mutex_lock(&parent_event->child_mutex); + list_add_tail(&child_event->child_list, &parent_event->child_list); + mutex_unlock(&parent_event->child_mutex); + + return child_event; +} + +static int inherit_group(struct perf_event *parent_event, + struct task_struct *parent, + struct perf_event_context *parent_ctx, + struct task_struct *child, + struct perf_event_context *child_ctx) +{ + struct perf_event *leader; + struct perf_event *sub; + struct perf_event *child_ctr; + + leader = inherit_event(parent_event, parent, parent_ctx, + child, NULL, child_ctx); + if (IS_ERR(leader)) + return PTR_ERR(leader); + list_for_each_entry(sub, &parent_event->sibling_list, group_entry) { + child_ctr = inherit_event(sub, parent, parent_ctx, + child, leader, child_ctx); + if (IS_ERR(child_ctr)) + return PTR_ERR(child_ctr); + } + return 0; +} + +static int +inherit_task_group(struct perf_event *event, struct task_struct *parent, + struct perf_event_context *parent_ctx, + struct task_struct *child, int ctxn, + int *inherited_all) +{ + int ret; + struct perf_event_context *child_ctx; + + if (!event->attr.inherit) { + *inherited_all = 0; + return 0; + } + + child_ctx = child->perf_event_ctxp[ctxn]; + if (!child_ctx) { + /* + * This is executed from the parent task context, so + * inherit events that have been marked for cloning. + * First allocate and initialize a context for the + * child. + */ + + child_ctx = alloc_perf_context(event->pmu, child); + if (!child_ctx) + return -ENOMEM; + + child->perf_event_ctxp[ctxn] = child_ctx; + } + + ret = inherit_group(event, parent, parent_ctx, + child, child_ctx); + + if (ret) + *inherited_all = 0; + + return ret; +} + +/* + * Initialize the perf_event context in task_struct + */ +int perf_event_init_context(struct task_struct *child, int ctxn) +{ + struct perf_event_context *child_ctx, *parent_ctx; + struct perf_event_context *cloned_ctx; + struct perf_event *event; + struct task_struct *parent = current; + int inherited_all = 1; + unsigned long flags; + int ret = 0; + + if (likely(!parent->perf_event_ctxp[ctxn])) + return 0; + + /* + * If the parent's context is a clone, pin it so it won't get + * swapped under us. + */ + parent_ctx = perf_pin_task_context(parent, ctxn); + + /* + * No need to check if parent_ctx != NULL here; since we saw + * it non-NULL earlier, the only reason for it to become NULL + * is if we exit, and since we're currently in the middle of + * a fork we can't be exiting at the same time. + */ + + /* + * Lock the parent list. No need to lock the child - not PID + * hashed yet and not running, so nobody can access it. + */ + mutex_lock(&parent_ctx->mutex); + + /* + * We dont have to disable NMIs - we are only looking at + * the list, not manipulating it: + */ + list_for_each_entry(event, &parent_ctx->pinned_groups, group_entry) { + ret = inherit_task_group(event, parent, parent_ctx, + child, ctxn, &inherited_all); + if (ret) + break; + } + + /* + * We can't hold ctx->lock when iterating the ->flexible_group list due + * to allocations, but we need to prevent rotation because + * rotate_ctx() will change the list from interrupt context. + */ + raw_spin_lock_irqsave(&parent_ctx->lock, flags); + parent_ctx->rotate_disable = 1; + raw_spin_unlock_irqrestore(&parent_ctx->lock, flags); + + list_for_each_entry(event, &parent_ctx->flexible_groups, group_entry) { + ret = inherit_task_group(event, parent, parent_ctx, + child, ctxn, &inherited_all); + if (ret) + break; + } + + raw_spin_lock_irqsave(&parent_ctx->lock, flags); + parent_ctx->rotate_disable = 0; + + child_ctx = child->perf_event_ctxp[ctxn]; + + if (child_ctx && inherited_all) { + /* + * Mark the child context as a clone of the parent + * context, or of whatever the parent is a clone of. + * + * Note that if the parent is a clone, the holding of + * parent_ctx->lock avoids it from being uncloned. + */ + cloned_ctx = parent_ctx->parent_ctx; + if (cloned_ctx) { + child_ctx->parent_ctx = cloned_ctx; + child_ctx->parent_gen = parent_ctx->parent_gen; + } else { + child_ctx->parent_ctx = parent_ctx; + child_ctx->parent_gen = parent_ctx->generation; + } + get_ctx(child_ctx->parent_ctx); + } + + raw_spin_unlock_irqrestore(&parent_ctx->lock, flags); + mutex_unlock(&parent_ctx->mutex); + + perf_unpin_context(parent_ctx); + put_ctx(parent_ctx); + + return ret; +} + +/* + * Initialize the perf_event context in task_struct + */ +int perf_event_init_task(struct task_struct *child) +{ + int ctxn, ret; + + memset(child->perf_event_ctxp, 0, sizeof(child->perf_event_ctxp)); + mutex_init(&child->perf_event_mutex); + INIT_LIST_HEAD(&child->perf_event_list); + + for_each_task_context_nr(ctxn) { + ret = perf_event_init_context(child, ctxn); + if (ret) + return ret; + } + + return 0; +} + +static void __init perf_event_init_all_cpus(void) +{ + struct swevent_htable *swhash; + int cpu; + + for_each_possible_cpu(cpu) { + swhash = &per_cpu(swevent_htable, cpu); + mutex_init(&swhash->hlist_mutex); + INIT_LIST_HEAD(&per_cpu(rotation_list, cpu)); + } +} + +static void __cpuinit perf_event_init_cpu(int cpu) +{ + struct swevent_htable *swhash = &per_cpu(swevent_htable, cpu); + + mutex_lock(&swhash->hlist_mutex); + if (swhash->hlist_refcount > 0) { + struct swevent_hlist *hlist; + + hlist = kzalloc_node(sizeof(*hlist), GFP_KERNEL, cpu_to_node(cpu)); + WARN_ON(!hlist); + rcu_assign_pointer(swhash->swevent_hlist, hlist); + } + mutex_unlock(&swhash->hlist_mutex); +} + +#if defined CONFIG_HOTPLUG_CPU || defined CONFIG_KEXEC +static void perf_pmu_rotate_stop(struct pmu *pmu) +{ + struct perf_cpu_context *cpuctx = this_cpu_ptr(pmu->pmu_cpu_context); + + WARN_ON(!irqs_disabled()); + + list_del_init(&cpuctx->rotation_list); +} + +static void __perf_event_exit_context(void *__info) +{ + struct perf_event_context *ctx = __info; + struct perf_event *event, *tmp; + + perf_pmu_rotate_stop(ctx->pmu); + + list_for_each_entry_safe(event, tmp, &ctx->pinned_groups, group_entry) + __perf_remove_from_context(event); + list_for_each_entry_safe(event, tmp, &ctx->flexible_groups, group_entry) + __perf_remove_from_context(event); +} + +static void perf_event_exit_cpu_context(int cpu) +{ + struct perf_event_context *ctx; + struct pmu *pmu; + int idx; + + idx = srcu_read_lock(&pmus_srcu); + list_for_each_entry_rcu(pmu, &pmus, entry) { + ctx = &per_cpu_ptr(pmu->pmu_cpu_context, cpu)->ctx; + + mutex_lock(&ctx->mutex); + smp_call_function_single(cpu, __perf_event_exit_context, ctx, 1); + mutex_unlock(&ctx->mutex); + } + srcu_read_unlock(&pmus_srcu, idx); +} + +static void perf_event_exit_cpu(int cpu) +{ + struct swevent_htable *swhash = &per_cpu(swevent_htable, cpu); + + mutex_lock(&swhash->hlist_mutex); + swevent_hlist_release(swhash); + mutex_unlock(&swhash->hlist_mutex); + + perf_event_exit_cpu_context(cpu); +} +#else +static inline void perf_event_exit_cpu(int cpu) { } +#endif + +static int +perf_reboot(struct notifier_block *notifier, unsigned long val, void *v) +{ + int cpu; + + for_each_online_cpu(cpu) + perf_event_exit_cpu(cpu); + + return NOTIFY_OK; +} + +/* + * Run the perf reboot notifier at the very last possible moment so that + * the generic watchdog code runs as long as possible. + */ +static struct notifier_block perf_reboot_notifier = { + .notifier_call = perf_reboot, + .priority = INT_MIN, +}; + +static int __cpuinit +perf_cpu_notify(struct notifier_block *self, unsigned long action, void *hcpu) +{ + unsigned int cpu = (long)hcpu; + + switch (action & ~CPU_TASKS_FROZEN) { + + case CPU_UP_PREPARE: + case CPU_DOWN_FAILED: + perf_event_init_cpu(cpu); + break; + + case CPU_UP_CANCELED: + case CPU_DOWN_PREPARE: + perf_event_exit_cpu(cpu); + break; + + default: + break; + } + + return NOTIFY_OK; +} + +void __init perf_event_init(void) +{ + int ret; + + idr_init(&pmu_idr); + + perf_event_init_all_cpus(); + init_srcu_struct(&pmus_srcu); + perf_pmu_register(&perf_swevent, "software", PERF_TYPE_SOFTWARE); + perf_pmu_register(&perf_cpu_clock, NULL, -1); + perf_pmu_register(&perf_task_clock, NULL, -1); + perf_tp_register(); + perf_cpu_notifier(perf_cpu_notify); + register_reboot_notifier(&perf_reboot_notifier); + + ret = init_hw_breakpoint(); + WARN(ret, "hw_breakpoint initialization failed with: %d", ret); +} + +static int __init perf_event_sysfs_init(void) +{ + struct pmu *pmu; + int ret; + + mutex_lock(&pmus_lock); + + ret = bus_register(&pmu_bus); + if (ret) + goto unlock; + + list_for_each_entry(pmu, &pmus, entry) { + if (!pmu->name || pmu->type < 0) + continue; + + ret = pmu_dev_alloc(pmu); + WARN(ret, "Failed to register pmu: %s, reason %d\n", pmu->name, ret); + } + pmu_bus_running = 1; + ret = 0; + +unlock: + mutex_unlock(&pmus_lock); + + return ret; +} +device_initcall(perf_event_sysfs_init); + +#ifdef CONFIG_CGROUP_PERF +static struct cgroup_subsys_state *perf_cgroup_create( + struct cgroup_subsys *ss, struct cgroup *cont) +{ + struct perf_cgroup *jc; + + jc = kzalloc(sizeof(*jc), GFP_KERNEL); + if (!jc) + return ERR_PTR(-ENOMEM); + + jc->info = alloc_percpu(struct perf_cgroup_info); + if (!jc->info) { + kfree(jc); + return ERR_PTR(-ENOMEM); + } + + return &jc->css; +} + +static void perf_cgroup_destroy(struct cgroup_subsys *ss, + struct cgroup *cont) +{ + struct perf_cgroup *jc; + jc = container_of(cgroup_subsys_state(cont, perf_subsys_id), + struct perf_cgroup, css); + free_percpu(jc->info); + kfree(jc); +} + +static int __perf_cgroup_move(void *info) +{ + struct task_struct *task = info; + perf_cgroup_switch(task, PERF_CGROUP_SWOUT | PERF_CGROUP_SWIN); + return 0; +} + +static void perf_cgroup_move(struct task_struct *task) +{ + task_function_call(task, __perf_cgroup_move, task); +} + +static void perf_cgroup_attach(struct cgroup_subsys *ss, struct cgroup *cgrp, + struct cgroup *old_cgrp, struct task_struct *task, + bool threadgroup) +{ + perf_cgroup_move(task); + if (threadgroup) { + struct task_struct *c; + rcu_read_lock(); + list_for_each_entry_rcu(c, &task->thread_group, thread_group) { + perf_cgroup_move(c); + } + rcu_read_unlock(); + } +} + +static void perf_cgroup_exit(struct cgroup_subsys *ss, struct cgroup *cgrp, + struct cgroup *old_cgrp, struct task_struct *task) +{ + /* + * cgroup_exit() is called in the copy_process() failure path. + * Ignore this case since the task hasn't ran yet, this avoids + * trying to poke a half freed task state from generic code. + */ + if (!(task->flags & PF_EXITING)) + return; + + perf_cgroup_move(task); +} + +struct cgroup_subsys perf_subsys = { + .name = "perf_event", + .subsys_id = perf_subsys_id, + .create = perf_cgroup_create, + .destroy = perf_cgroup_destroy, + .exit = perf_cgroup_exit, + .attach = perf_cgroup_attach, +}; +#endif /* CONFIG_CGROUP_PERF */ diff --git a/kernel/perf_event.c b/kernel/perf_event.c deleted file mode 100644 index 440bc48..0000000 --- a/kernel/perf_event.c +++ /dev/null @@ -1,7455 +0,0 @@ -/* - * Performance events core code: - * - * Copyright (C) 2008 Thomas Gleixner - * Copyright (C) 2008-2009 Red Hat, Inc., Ingo Molnar - * Copyright (C) 2008-2009 Red Hat, Inc., Peter Zijlstra - * Copyright © 2009 Paul Mackerras, IBM Corp. - * - * For licensing details see kernel-base/COPYING - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -struct remote_function_call { - struct task_struct *p; - int (*func)(void *info); - void *info; - int ret; -}; - -static void remote_function(void *data) -{ - struct remote_function_call *tfc = data; - struct task_struct *p = tfc->p; - - if (p) { - tfc->ret = -EAGAIN; - if (task_cpu(p) != smp_processor_id() || !task_curr(p)) - return; - } - - tfc->ret = tfc->func(tfc->info); -} - -/** - * task_function_call - call a function on the cpu on which a task runs - * @p: the task to evaluate - * @func: the function to be called - * @info: the function call argument - * - * Calls the function @func when the task is currently running. This might - * be on the current CPU, which just calls the function directly - * - * returns: @func return value, or - * -ESRCH - when the process isn't running - * -EAGAIN - when the process moved away - */ -static int -task_function_call(struct task_struct *p, int (*func) (void *info), void *info) -{ - struct remote_function_call data = { - .p = p, - .func = func, - .info = info, - .ret = -ESRCH, /* No such (running) process */ - }; - - if (task_curr(p)) - smp_call_function_single(task_cpu(p), remote_function, &data, 1); - - return data.ret; -} - -/** - * cpu_function_call - call a function on the cpu - * @func: the function to be called - * @info: the function call argument - * - * Calls the function @func on the remote cpu. - * - * returns: @func return value or -ENXIO when the cpu is offline - */ -static int cpu_function_call(int cpu, int (*func) (void *info), void *info) -{ - struct remote_function_call data = { - .p = NULL, - .func = func, - .info = info, - .ret = -ENXIO, /* No such CPU */ - }; - - smp_call_function_single(cpu, remote_function, &data, 1); - - return data.ret; -} - -#define PERF_FLAG_ALL (PERF_FLAG_FD_NO_GROUP |\ - PERF_FLAG_FD_OUTPUT |\ - PERF_FLAG_PID_CGROUP) - -enum event_type_t { - EVENT_FLEXIBLE = 0x1, - EVENT_PINNED = 0x2, - EVENT_ALL = EVENT_FLEXIBLE | EVENT_PINNED, -}; - -/* - * perf_sched_events : >0 events exist - * perf_cgroup_events: >0 per-cpu cgroup events exist on this cpu - */ -struct jump_label_key perf_sched_events __read_mostly; -static DEFINE_PER_CPU(atomic_t, perf_cgroup_events); - -static atomic_t nr_mmap_events __read_mostly; -static atomic_t nr_comm_events __read_mostly; -static atomic_t nr_task_events __read_mostly; - -static LIST_HEAD(pmus); -static DEFINE_MUTEX(pmus_lock); -static struct srcu_struct pmus_srcu; - -/* - * perf event paranoia level: - * -1 - not paranoid at all - * 0 - disallow raw tracepoint access for unpriv - * 1 - disallow cpu events for unpriv - * 2 - disallow kernel profiling for unpriv - */ -int sysctl_perf_event_paranoid __read_mostly = 1; - -/* Minimum for 512 kiB + 1 user control page */ -int sysctl_perf_event_mlock __read_mostly = 512 + (PAGE_SIZE / 1024); /* 'free' kiB per user */ - -/* - * max perf event sample rate - */ -#define DEFAULT_MAX_SAMPLE_RATE 100000 -int sysctl_perf_event_sample_rate __read_mostly = DEFAULT_MAX_SAMPLE_RATE; -static int max_samples_per_tick __read_mostly = - DIV_ROUND_UP(DEFAULT_MAX_SAMPLE_RATE, HZ); - -int perf_proc_update_handler(struct ctl_table *table, int write, - void __user *buffer, size_t *lenp, - loff_t *ppos) -{ - int ret = proc_dointvec(table, write, buffer, lenp, ppos); - - if (ret || !write) - return ret; - - max_samples_per_tick = DIV_ROUND_UP(sysctl_perf_event_sample_rate, HZ); - - return 0; -} - -static atomic64_t perf_event_id; - -static void cpu_ctx_sched_out(struct perf_cpu_context *cpuctx, - enum event_type_t event_type); - -static void cpu_ctx_sched_in(struct perf_cpu_context *cpuctx, - enum event_type_t event_type, - struct task_struct *task); - -static void update_context_time(struct perf_event_context *ctx); -static u64 perf_event_time(struct perf_event *event); - -void __weak perf_event_print_debug(void) { } - -extern __weak const char *perf_pmu_name(void) -{ - return "pmu"; -} - -static inline u64 perf_clock(void) -{ - return local_clock(); -} - -static inline struct perf_cpu_context * -__get_cpu_context(struct perf_event_context *ctx) -{ - return this_cpu_ptr(ctx->pmu->pmu_cpu_context); -} - -#ifdef CONFIG_CGROUP_PERF - -/* - * Must ensure cgroup is pinned (css_get) before calling - * this function. In other words, we cannot call this function - * if there is no cgroup event for the current CPU context. - */ -static inline struct perf_cgroup * -perf_cgroup_from_task(struct task_struct *task) -{ - return container_of(task_subsys_state(task, perf_subsys_id), - struct perf_cgroup, css); -} - -static inline bool -perf_cgroup_match(struct perf_event *event) -{ - struct perf_event_context *ctx = event->ctx; - struct perf_cpu_context *cpuctx = __get_cpu_context(ctx); - - return !event->cgrp || event->cgrp == cpuctx->cgrp; -} - -static inline void perf_get_cgroup(struct perf_event *event) -{ - css_get(&event->cgrp->css); -} - -static inline void perf_put_cgroup(struct perf_event *event) -{ - css_put(&event->cgrp->css); -} - -static inline void perf_detach_cgroup(struct perf_event *event) -{ - perf_put_cgroup(event); - event->cgrp = NULL; -} - -static inline int is_cgroup_event(struct perf_event *event) -{ - return event->cgrp != NULL; -} - -static inline u64 perf_cgroup_event_time(struct perf_event *event) -{ - struct perf_cgroup_info *t; - - t = per_cpu_ptr(event->cgrp->info, event->cpu); - return t->time; -} - -static inline void __update_cgrp_time(struct perf_cgroup *cgrp) -{ - struct perf_cgroup_info *info; - u64 now; - - now = perf_clock(); - - info = this_cpu_ptr(cgrp->info); - - info->time += now - info->timestamp; - info->timestamp = now; -} - -static inline void update_cgrp_time_from_cpuctx(struct perf_cpu_context *cpuctx) -{ - struct perf_cgroup *cgrp_out = cpuctx->cgrp; - if (cgrp_out) - __update_cgrp_time(cgrp_out); -} - -static inline void update_cgrp_time_from_event(struct perf_event *event) -{ - struct perf_cgroup *cgrp; - - /* - * ensure we access cgroup data only when needed and - * when we know the cgroup is pinned (css_get) - */ - if (!is_cgroup_event(event)) - return; - - cgrp = perf_cgroup_from_task(current); - /* - * Do not update time when cgroup is not active - */ - if (cgrp == event->cgrp) - __update_cgrp_time(event->cgrp); -} - -static inline void -perf_cgroup_set_timestamp(struct task_struct *task, - struct perf_event_context *ctx) -{ - struct perf_cgroup *cgrp; - struct perf_cgroup_info *info; - - /* - * ctx->lock held by caller - * ensure we do not access cgroup data - * unless we have the cgroup pinned (css_get) - */ - if (!task || !ctx->nr_cgroups) - return; - - cgrp = perf_cgroup_from_task(task); - info = this_cpu_ptr(cgrp->info); - info->timestamp = ctx->timestamp; -} - -#define PERF_CGROUP_SWOUT 0x1 /* cgroup switch out every event */ -#define PERF_CGROUP_SWIN 0x2 /* cgroup switch in events based on task */ - -/* - * reschedule events based on the cgroup constraint of task. - * - * mode SWOUT : schedule out everything - * mode SWIN : schedule in based on cgroup for next - */ -void perf_cgroup_switch(struct task_struct *task, int mode) -{ - struct perf_cpu_context *cpuctx; - struct pmu *pmu; - unsigned long flags; - - /* - * disable interrupts to avoid geting nr_cgroup - * changes via __perf_event_disable(). Also - * avoids preemption. - */ - local_irq_save(flags); - - /* - * we reschedule only in the presence of cgroup - * constrained events. - */ - rcu_read_lock(); - - list_for_each_entry_rcu(pmu, &pmus, entry) { - - cpuctx = this_cpu_ptr(pmu->pmu_cpu_context); - - perf_pmu_disable(cpuctx->ctx.pmu); - - /* - * perf_cgroup_events says at least one - * context on this CPU has cgroup events. - * - * ctx->nr_cgroups reports the number of cgroup - * events for a context. - */ - if (cpuctx->ctx.nr_cgroups > 0) { - - if (mode & PERF_CGROUP_SWOUT) { - cpu_ctx_sched_out(cpuctx, EVENT_ALL); - /* - * must not be done before ctxswout due - * to event_filter_match() in event_sched_out() - */ - cpuctx->cgrp = NULL; - } - - if (mode & PERF_CGROUP_SWIN) { - WARN_ON_ONCE(cpuctx->cgrp); - /* set cgrp before ctxsw in to - * allow event_filter_match() to not - * have to pass task around - */ - cpuctx->cgrp = perf_cgroup_from_task(task); - cpu_ctx_sched_in(cpuctx, EVENT_ALL, task); - } - } - - perf_pmu_enable(cpuctx->ctx.pmu); - } - - rcu_read_unlock(); - - local_irq_restore(flags); -} - -static inline void perf_cgroup_sched_out(struct task_struct *task) -{ - perf_cgroup_switch(task, PERF_CGROUP_SWOUT); -} - -static inline void perf_cgroup_sched_in(struct task_struct *task) -{ - perf_cgroup_switch(task, PERF_CGROUP_SWIN); -} - -static inline int perf_cgroup_connect(int fd, struct perf_event *event, - struct perf_event_attr *attr, - struct perf_event *group_leader) -{ - struct perf_cgroup *cgrp; - struct cgroup_subsys_state *css; - struct file *file; - int ret = 0, fput_needed; - - file = fget_light(fd, &fput_needed); - if (!file) - return -EBADF; - - css = cgroup_css_from_dir(file, perf_subsys_id); - if (IS_ERR(css)) { - ret = PTR_ERR(css); - goto out; - } - - cgrp = container_of(css, struct perf_cgroup, css); - event->cgrp = cgrp; - - /* must be done before we fput() the file */ - perf_get_cgroup(event); - - /* - * all events in a group must monitor - * the same cgroup because a task belongs - * to only one perf cgroup at a time - */ - if (group_leader && group_leader->cgrp != cgrp) { - perf_detach_cgroup(event); - ret = -EINVAL; - } -out: - fput_light(file, fput_needed); - return ret; -} - -static inline void -perf_cgroup_set_shadow_time(struct perf_event *event, u64 now) -{ - struct perf_cgroup_info *t; - t = per_cpu_ptr(event->cgrp->info, event->cpu); - event->shadow_ctx_time = now - t->timestamp; -} - -static inline void -perf_cgroup_defer_enabled(struct perf_event *event) -{ - /* - * when the current task's perf cgroup does not match - * the event's, we need to remember to call the - * perf_mark_enable() function the first time a task with - * a matching perf cgroup is scheduled in. - */ - if (is_cgroup_event(event) && !perf_cgroup_match(event)) - event->cgrp_defer_enabled = 1; -} - -static inline void -perf_cgroup_mark_enabled(struct perf_event *event, - struct perf_event_context *ctx) -{ - struct perf_event *sub; - u64 tstamp = perf_event_time(event); - - if (!event->cgrp_defer_enabled) - return; - - event->cgrp_defer_enabled = 0; - - event->tstamp_enabled = tstamp - event->total_time_enabled; - list_for_each_entry(sub, &event->sibling_list, group_entry) { - if (sub->state >= PERF_EVENT_STATE_INACTIVE) { - sub->tstamp_enabled = tstamp - sub->total_time_enabled; - sub->cgrp_defer_enabled = 0; - } - } -} -#else /* !CONFIG_CGROUP_PERF */ - -static inline bool -perf_cgroup_match(struct perf_event *event) -{ - return true; -} - -static inline void perf_detach_cgroup(struct perf_event *event) -{} - -static inline int is_cgroup_event(struct perf_event *event) -{ - return 0; -} - -static inline u64 perf_cgroup_event_cgrp_time(struct perf_event *event) -{ - return 0; -} - -static inline void update_cgrp_time_from_event(struct perf_event *event) -{ -} - -static inline void update_cgrp_time_from_cpuctx(struct perf_cpu_context *cpuctx) -{ -} - -static inline void perf_cgroup_sched_out(struct task_struct *task) -{ -} - -static inline void perf_cgroup_sched_in(struct task_struct *task) -{ -} - -static inline int perf_cgroup_connect(pid_t pid, struct perf_event *event, - struct perf_event_attr *attr, - struct perf_event *group_leader) -{ - return -EINVAL; -} - -static inline void -perf_cgroup_set_timestamp(struct task_struct *task, - struct perf_event_context *ctx) -{ -} - -void -perf_cgroup_switch(struct task_struct *task, struct task_struct *next) -{ -} - -static inline void -perf_cgroup_set_shadow_time(struct perf_event *event, u64 now) -{ -} - -static inline u64 perf_cgroup_event_time(struct perf_event *event) -{ - return 0; -} - -static inline void -perf_cgroup_defer_enabled(struct perf_event *event) -{ -} - -static inline void -perf_cgroup_mark_enabled(struct perf_event *event, - struct perf_event_context *ctx) -{ -} -#endif - -void perf_pmu_disable(struct pmu *pmu) -{ - int *count = this_cpu_ptr(pmu->pmu_disable_count); - if (!(*count)++) - pmu->pmu_disable(pmu); -} - -void perf_pmu_enable(struct pmu *pmu) -{ - int *count = this_cpu_ptr(pmu->pmu_disable_count); - if (!--(*count)) - pmu->pmu_enable(pmu); -} - -static DEFINE_PER_CPU(struct list_head, rotation_list); - -/* - * perf_pmu_rotate_start() and perf_rotate_context() are fully serialized - * because they're strictly cpu affine and rotate_start is called with IRQs - * disabled, while rotate_context is called from IRQ context. - */ -static void perf_pmu_rotate_start(struct pmu *pmu) -{ - struct perf_cpu_context *cpuctx = this_cpu_ptr(pmu->pmu_cpu_context); - struct list_head *head = &__get_cpu_var(rotation_list); - - WARN_ON(!irqs_disabled()); - - if (list_empty(&cpuctx->rotation_list)) - list_add(&cpuctx->rotation_list, head); -} - -static void get_ctx(struct perf_event_context *ctx) -{ - WARN_ON(!atomic_inc_not_zero(&ctx->refcount)); -} - -static void free_ctx(struct rcu_head *head) -{ - struct perf_event_context *ctx; - - ctx = container_of(head, struct perf_event_context, rcu_head); - kfree(ctx); -} - -static void put_ctx(struct perf_event_context *ctx) -{ - if (atomic_dec_and_test(&ctx->refcount)) { - if (ctx->parent_ctx) - put_ctx(ctx->parent_ctx); - if (ctx->task) - put_task_struct(ctx->task); - call_rcu(&ctx->rcu_head, free_ctx); - } -} - -static void unclone_ctx(struct perf_event_context *ctx) -{ - if (ctx->parent_ctx) { - put_ctx(ctx->parent_ctx); - ctx->parent_ctx = NULL; - } -} - -static u32 perf_event_pid(struct perf_event *event, struct task_struct *p) -{ - /* - * only top level events have the pid namespace they were created in - */ - if (event->parent) - event = event->parent; - - return task_tgid_nr_ns(p, event->ns); -} - -static u32 perf_event_tid(struct perf_event *event, struct task_struct *p) -{ - /* - * only top level events have the pid namespace they were created in - */ - if (event->parent) - event = event->parent; - - return task_pid_nr_ns(p, event->ns); -} - -/* - * If we inherit events we want to return the parent event id - * to userspace. - */ -static u64 primary_event_id(struct perf_event *event) -{ - u64 id = event->id; - - if (event->parent) - id = event->parent->id; - - return id; -} - -/* - * Get the perf_event_context for a task and lock it. - * This has to cope with with the fact that until it is locked, - * the context could get moved to another task. - */ -static struct perf_event_context * -perf_lock_task_context(struct task_struct *task, int ctxn, unsigned long *flags) -{ - struct perf_event_context *ctx; - - rcu_read_lock(); -retry: - ctx = rcu_dereference(task->perf_event_ctxp[ctxn]); - if (ctx) { - /* - * If this context is a clone of another, it might - * get swapped for another underneath us by - * perf_event_task_sched_out, though the - * rcu_read_lock() protects us from any context - * getting freed. Lock the context and check if it - * got swapped before we could get the lock, and retry - * if so. If we locked the right context, then it - * can't get swapped on us any more. - */ - raw_spin_lock_irqsave(&ctx->lock, *flags); - if (ctx != rcu_dereference(task->perf_event_ctxp[ctxn])) { - raw_spin_unlock_irqrestore(&ctx->lock, *flags); - goto retry; - } - - if (!atomic_inc_not_zero(&ctx->refcount)) { - raw_spin_unlock_irqrestore(&ctx->lock, *flags); - ctx = NULL; - } - } - rcu_read_unlock(); - return ctx; -} - -/* - * Get the context for a task and increment its pin_count so it - * can't get swapped to another task. This also increments its - * reference count so that the context can't get freed. - */ -static struct perf_event_context * -perf_pin_task_context(struct task_struct *task, int ctxn) -{ - struct perf_event_context *ctx; - unsigned long flags; - - ctx = perf_lock_task_context(task, ctxn, &flags); - if (ctx) { - ++ctx->pin_count; - raw_spin_unlock_irqrestore(&ctx->lock, flags); - } - return ctx; -} - -static void perf_unpin_context(struct perf_event_context *ctx) -{ - unsigned long flags; - - raw_spin_lock_irqsave(&ctx->lock, flags); - --ctx->pin_count; - raw_spin_unlock_irqrestore(&ctx->lock, flags); -} - -/* - * Update the record of the current time in a context. - */ -static void update_context_time(struct perf_event_context *ctx) -{ - u64 now = perf_clock(); - - ctx->time += now - ctx->timestamp; - ctx->timestamp = now; -} - -static u64 perf_event_time(struct perf_event *event) -{ - struct perf_event_context *ctx = event->ctx; - - if (is_cgroup_event(event)) - return perf_cgroup_event_time(event); - - return ctx ? ctx->time : 0; -} - -/* - * Update the total_time_enabled and total_time_running fields for a event. - */ -static void update_event_times(struct perf_event *event) -{ - struct perf_event_context *ctx = event->ctx; - u64 run_end; - - if (event->state < PERF_EVENT_STATE_INACTIVE || - event->group_leader->state < PERF_EVENT_STATE_INACTIVE) - return; - /* - * in cgroup mode, time_enabled represents - * the time the event was enabled AND active - * tasks were in the monitored cgroup. This is - * independent of the activity of the context as - * there may be a mix of cgroup and non-cgroup events. - * - * That is why we treat cgroup events differently - * here. - */ - if (is_cgroup_event(event)) - run_end = perf_event_time(event); - else if (ctx->is_active) - run_end = ctx->time; - else - run_end = event->tstamp_stopped; - - event->total_time_enabled = run_end - event->tstamp_enabled; - - if (event->state == PERF_EVENT_STATE_INACTIVE) - run_end = event->tstamp_stopped; - else - run_end = perf_event_time(event); - - event->total_time_running = run_end - event->tstamp_running; - -} - -/* - * Update total_time_enabled and total_time_running for all events in a group. - */ -static void update_group_times(struct perf_event *leader) -{ - struct perf_event *event; - - update_event_times(leader); - list_for_each_entry(event, &leader->sibling_list, group_entry) - update_event_times(event); -} - -static struct list_head * -ctx_group_list(struct perf_event *event, struct perf_event_context *ctx) -{ - if (event->attr.pinned) - return &ctx->pinned_groups; - else - return &ctx->flexible_groups; -} - -/* - * Add a event from the lists for its context. - * Must be called with ctx->mutex and ctx->lock held. - */ -static void -list_add_event(struct perf_event *event, struct perf_event_context *ctx) -{ - WARN_ON_ONCE(event->attach_state & PERF_ATTACH_CONTEXT); - event->attach_state |= PERF_ATTACH_CONTEXT; - - /* - * If we're a stand alone event or group leader, we go to the context - * list, group events are kept attached to the group so that - * perf_group_detach can, at all times, locate all siblings. - */ - if (event->group_leader == event) { - struct list_head *list; - - if (is_software_event(event)) - event->group_flags |= PERF_GROUP_SOFTWARE; - - list = ctx_group_list(event, ctx); - list_add_tail(&event->group_entry, list); - } - - if (is_cgroup_event(event)) - ctx->nr_cgroups++; - - list_add_rcu(&event->event_entry, &ctx->event_list); - if (!ctx->nr_events) - perf_pmu_rotate_start(ctx->pmu); - ctx->nr_events++; - if (event->attr.inherit_stat) - ctx->nr_stat++; -} - -/* - * Called at perf_event creation and when events are attached/detached from a - * group. - */ -static void perf_event__read_size(struct perf_event *event) -{ - int entry = sizeof(u64); /* value */ - int size = 0; - int nr = 1; - - if (event->attr.read_format & PERF_FORMAT_TOTAL_TIME_ENABLED) - size += sizeof(u64); - - if (event->attr.read_format & PERF_FORMAT_TOTAL_TIME_RUNNING) - size += sizeof(u64); - - if (event->attr.read_format & PERF_FORMAT_ID) - entry += sizeof(u64); - - if (event->attr.read_format & PERF_FORMAT_GROUP) { - nr += event->group_leader->nr_siblings; - size += sizeof(u64); - } - - size += entry * nr; - event->read_size = size; -} - -static void perf_event__header_size(struct perf_event *event) -{ - struct perf_sample_data *data; - u64 sample_type = event->attr.sample_type; - u16 size = 0; - - perf_event__read_size(event); - - if (sample_type & PERF_SAMPLE_IP) - size += sizeof(data->ip); - - if (sample_type & PERF_SAMPLE_ADDR) - size += sizeof(data->addr); - - if (sample_type & PERF_SAMPLE_PERIOD) - size += sizeof(data->period); - - if (sample_type & PERF_SAMPLE_READ) - size += event->read_size; - - event->header_size = size; -} - -static void perf_event__id_header_size(struct perf_event *event) -{ - struct perf_sample_data *data; - u64 sample_type = event->attr.sample_type; - u16 size = 0; - - if (sample_type & PERF_SAMPLE_TID) - size += sizeof(data->tid_entry); - - if (sample_type & PERF_SAMPLE_TIME) - size += sizeof(data->time); - - if (sample_type & PERF_SAMPLE_ID) - size += sizeof(data->id); - - if (sample_type & PERF_SAMPLE_STREAM_ID) - size += sizeof(data->stream_id); - - if (sample_type & PERF_SAMPLE_CPU) - size += sizeof(data->cpu_entry); - - event->id_header_size = size; -} - -static void perf_group_attach(struct perf_event *event) -{ - struct perf_event *group_leader = event->group_leader, *pos; - - /* - * We can have double attach due to group movement in perf_event_open. - */ - if (event->attach_state & PERF_ATTACH_GROUP) - return; - - event->attach_state |= PERF_ATTACH_GROUP; - - if (group_leader == event) - return; - - if (group_leader->group_flags & PERF_GROUP_SOFTWARE && - !is_software_event(event)) - group_leader->group_flags &= ~PERF_GROUP_SOFTWARE; - - list_add_tail(&event->group_entry, &group_leader->sibling_list); - group_leader->nr_siblings++; - - perf_event__header_size(group_leader); - - list_for_each_entry(pos, &group_leader->sibling_list, group_entry) - perf_event__header_size(pos); -} - -/* - * Remove a event from the lists for its context. - * Must be called with ctx->mutex and ctx->lock held. - */ -static void -list_del_event(struct perf_event *event, struct perf_event_context *ctx) -{ - struct perf_cpu_context *cpuctx; - /* - * We can have double detach due to exit/hot-unplug + close. - */ - if (!(event->attach_state & PERF_ATTACH_CONTEXT)) - return; - - event->attach_state &= ~PERF_ATTACH_CONTEXT; - - if (is_cgroup_event(event)) { - ctx->nr_cgroups--; - cpuctx = __get_cpu_context(ctx); - /* - * if there are no more cgroup events - * then cler cgrp to avoid stale pointer - * in update_cgrp_time_from_cpuctx() - */ - if (!ctx->nr_cgroups) - cpuctx->cgrp = NULL; - } - - ctx->nr_events--; - if (event->attr.inherit_stat) - ctx->nr_stat--; - - list_del_rcu(&event->event_entry); - - if (event->group_leader == event) - list_del_init(&event->group_entry); - - update_group_times(event); - - /* - * If event was in error state, then keep it - * that way, otherwise bogus counts will be - * returned on read(). The only way to get out - * of error state is by explicit re-enabling - * of the event - */ - if (event->state > PERF_EVENT_STATE_OFF) - event->state = PERF_EVENT_STATE_OFF; -} - -static void perf_group_detach(struct perf_event *event) -{ - struct perf_event *sibling, *tmp; - struct list_head *list = NULL; - - /* - * We can have double detach due to exit/hot-unplug + close. - */ - if (!(event->attach_state & PERF_ATTACH_GROUP)) - return; - - event->attach_state &= ~PERF_ATTACH_GROUP; - - /* - * If this is a sibling, remove it from its group. - */ - if (event->group_leader != event) { - list_del_init(&event->group_entry); - event->group_leader->nr_siblings--; - goto out; - } - - if (!list_empty(&event->group_entry)) - list = &event->group_entry; - - /* - * If this was a group event with sibling events then - * upgrade the siblings to singleton events by adding them - * to whatever list we are on. - */ - list_for_each_entry_safe(sibling, tmp, &event->sibling_list, group_entry) { - if (list) - list_move_tail(&sibling->group_entry, list); - sibling->group_leader = sibling; - - /* Inherit group flags from the previous leader */ - sibling->group_flags = event->group_flags; - } - -out: - perf_event__header_size(event->group_leader); - - list_for_each_entry(tmp, &event->group_leader->sibling_list, group_entry) - perf_event__header_size(tmp); -} - -static inline int -event_filter_match(struct perf_event *event) -{ - return (event->cpu == -1 || event->cpu == smp_processor_id()) - && perf_cgroup_match(event); -} - -static void -event_sched_out(struct perf_event *event, - struct perf_cpu_context *cpuctx, - struct perf_event_context *ctx) -{ - u64 tstamp = perf_event_time(event); - u64 delta; - /* - * An event which could not be activated because of - * filter mismatch still needs to have its timings - * maintained, otherwise bogus information is return - * via read() for time_enabled, time_running: - */ - if (event->state == PERF_EVENT_STATE_INACTIVE - && !event_filter_match(event)) { - delta = tstamp - event->tstamp_stopped; - event->tstamp_running += delta; - event->tstamp_stopped = tstamp; - } - - if (event->state != PERF_EVENT_STATE_ACTIVE) - return; - - event->state = PERF_EVENT_STATE_INACTIVE; - if (event->pending_disable) { - event->pending_disable = 0; - event->state = PERF_EVENT_STATE_OFF; - } - event->tstamp_stopped = tstamp; - event->pmu->del(event, 0); - event->oncpu = -1; - - if (!is_software_event(event)) - cpuctx->active_oncpu--; - ctx->nr_active--; - if (event->attr.exclusive || !cpuctx->active_oncpu) - cpuctx->exclusive = 0; -} - -static void -group_sched_out(struct perf_event *group_event, - struct perf_cpu_context *cpuctx, - struct perf_event_context *ctx) -{ - struct perf_event *event; - int state = group_event->state; - - event_sched_out(group_event, cpuctx, ctx); - - /* - * Schedule out siblings (if any): - */ - list_for_each_entry(event, &group_event->sibling_list, group_entry) - event_sched_out(event, cpuctx, ctx); - - if (state == PERF_EVENT_STATE_ACTIVE && group_event->attr.exclusive) - cpuctx->exclusive = 0; -} - -/* - * Cross CPU call to remove a performance event - * - * We disable the event on the hardware level first. After that we - * remove it from the context list. - */ -static int __perf_remove_from_context(void *info) -{ - struct perf_event *event = info; - struct perf_event_context *ctx = event->ctx; - struct perf_cpu_context *cpuctx = __get_cpu_context(ctx); - - raw_spin_lock(&ctx->lock); - event_sched_out(event, cpuctx, ctx); - list_del_event(event, ctx); - raw_spin_unlock(&ctx->lock); - - return 0; -} - - -/* - * Remove the event from a task's (or a CPU's) list of events. - * - * CPU events are removed with a smp call. For task events we only - * call when the task is on a CPU. - * - * If event->ctx is a cloned context, callers must make sure that - * every task struct that event->ctx->task could possibly point to - * remains valid. This is OK when called from perf_release since - * that only calls us on the top-level context, which can't be a clone. - * When called from perf_event_exit_task, it's OK because the - * context has been detached from its task. - */ -static void perf_remove_from_context(struct perf_event *event) -{ - struct perf_event_context *ctx = event->ctx; - struct task_struct *task = ctx->task; - - lockdep_assert_held(&ctx->mutex); - - if (!task) { - /* - * Per cpu events are removed via an smp call and - * the removal is always successful. - */ - cpu_function_call(event->cpu, __perf_remove_from_context, event); - return; - } - -retry: - if (!task_function_call(task, __perf_remove_from_context, event)) - return; - - raw_spin_lock_irq(&ctx->lock); - /* - * If we failed to find a running task, but find the context active now - * that we've acquired the ctx->lock, retry. - */ - if (ctx->is_active) { - raw_spin_unlock_irq(&ctx->lock); - goto retry; - } - - /* - * Since the task isn't running, its safe to remove the event, us - * holding the ctx->lock ensures the task won't get scheduled in. - */ - list_del_event(event, ctx); - raw_spin_unlock_irq(&ctx->lock); -} - -/* - * Cross CPU call to disable a performance event - */ -static int __perf_event_disable(void *info) -{ - struct perf_event *event = info; - struct perf_event_context *ctx = event->ctx; - struct perf_cpu_context *cpuctx = __get_cpu_context(ctx); - - /* - * If this is a per-task event, need to check whether this - * event's task is the current task on this cpu. - * - * Can trigger due to concurrent perf_event_context_sched_out() - * flipping contexts around. - */ - if (ctx->task && cpuctx->task_ctx != ctx) - return -EINVAL; - - raw_spin_lock(&ctx->lock); - - /* - * If the event is on, turn it off. - * If it is in error state, leave it in error state. - */ - if (event->state >= PERF_EVENT_STATE_INACTIVE) { - update_context_time(ctx); - update_cgrp_time_from_event(event); - update_group_times(event); - if (event == event->group_leader) - group_sched_out(event, cpuctx, ctx); - else - event_sched_out(event, cpuctx, ctx); - event->state = PERF_EVENT_STATE_OFF; - } - - raw_spin_unlock(&ctx->lock); - - return 0; -} - -/* - * Disable a event. - * - * If event->ctx is a cloned context, callers must make sure that - * every task struct that event->ctx->task could possibly point to - * remains valid. This condition is satisifed when called through - * perf_event_for_each_child or perf_event_for_each because they - * hold the top-level event's child_mutex, so any descendant that - * goes to exit will block in sync_child_event. - * When called from perf_pending_event it's OK because event->ctx - * is the current context on this CPU and preemption is disabled, - * hence we can't get into perf_event_task_sched_out for this context. - */ -void perf_event_disable(struct perf_event *event) -{ - struct perf_event_context *ctx = event->ctx; - struct task_struct *task = ctx->task; - - if (!task) { - /* - * Disable the event on the cpu that it's on - */ - cpu_function_call(event->cpu, __perf_event_disable, event); - return; - } - -retry: - if (!task_function_call(task, __perf_event_disable, event)) - return; - - raw_spin_lock_irq(&ctx->lock); - /* - * If the event is still active, we need to retry the cross-call. - */ - if (event->state == PERF_EVENT_STATE_ACTIVE) { - raw_spin_unlock_irq(&ctx->lock); - /* - * Reload the task pointer, it might have been changed by - * a concurrent perf_event_context_sched_out(). - */ - task = ctx->task; - goto retry; - } - - /* - * Since we have the lock this context can't be scheduled - * in, so we can change the state safely. - */ - if (event->state == PERF_EVENT_STATE_INACTIVE) { - update_group_times(event); - event->state = PERF_EVENT_STATE_OFF; - } - raw_spin_unlock_irq(&ctx->lock); -} - -static void perf_set_shadow_time(struct perf_event *event, - struct perf_event_context *ctx, - u64 tstamp) -{ - /* - * use the correct time source for the time snapshot - * - * We could get by without this by leveraging the - * fact that to get to this function, the caller - * has most likely already called update_context_time() - * and update_cgrp_time_xx() and thus both timestamp - * are identical (or very close). Given that tstamp is, - * already adjusted for cgroup, we could say that: - * tstamp - ctx->timestamp - * is equivalent to - * tstamp - cgrp->timestamp. - * - * Then, in perf_output_read(), the calculation would - * work with no changes because: - * - event is guaranteed scheduled in - * - no scheduled out in between - * - thus the timestamp would be the same - * - * But this is a bit hairy. - * - * So instead, we have an explicit cgroup call to remain - * within the time time source all along. We believe it - * is cleaner and simpler to understand. - */ - if (is_cgroup_event(event)) - perf_cgroup_set_shadow_time(event, tstamp); - else - event->shadow_ctx_time = tstamp - ctx->timestamp; -} - -#define MAX_INTERRUPTS (~0ULL) - -static void perf_log_throttle(struct perf_event *event, int enable); - -static int -event_sched_in(struct perf_event *event, - struct perf_cpu_context *cpuctx, - struct perf_event_context *ctx) -{ - u64 tstamp = perf_event_time(event); - - if (event->state <= PERF_EVENT_STATE_OFF) - return 0; - - event->state = PERF_EVENT_STATE_ACTIVE; - event->oncpu = smp_processor_id(); - - /* - * Unthrottle events, since we scheduled we might have missed several - * ticks already, also for a heavily scheduling task there is little - * guarantee it'll get a tick in a timely manner. - */ - if (unlikely(event->hw.interrupts == MAX_INTERRUPTS)) { - perf_log_throttle(event, 1); - event->hw.interrupts = 0; - } - - /* - * The new state must be visible before we turn it on in the hardware: - */ - smp_wmb(); - - if (event->pmu->add(event, PERF_EF_START)) { - event->state = PERF_EVENT_STATE_INACTIVE; - event->oncpu = -1; - return -EAGAIN; - } - - event->tstamp_running += tstamp - event->tstamp_stopped; - - perf_set_shadow_time(event, ctx, tstamp); - - if (!is_software_event(event)) - cpuctx->active_oncpu++; - ctx->nr_active++; - - if (event->attr.exclusive) - cpuctx->exclusive = 1; - - return 0; -} - -static int -group_sched_in(struct perf_event *group_event, - struct perf_cpu_context *cpuctx, - struct perf_event_context *ctx) -{ - struct perf_event *event, *partial_group = NULL; - struct pmu *pmu = group_event->pmu; - u64 now = ctx->time; - bool simulate = false; - - if (group_event->state == PERF_EVENT_STATE_OFF) - return 0; - - pmu->start_txn(pmu); - - if (event_sched_in(group_event, cpuctx, ctx)) { - pmu->cancel_txn(pmu); - return -EAGAIN; - } - - /* - * Schedule in siblings as one group (if any): - */ - list_for_each_entry(event, &group_event->sibling_list, group_entry) { - if (event_sched_in(event, cpuctx, ctx)) { - partial_group = event; - goto group_error; - } - } - - if (!pmu->commit_txn(pmu)) - return 0; - -group_error: - /* - * Groups can be scheduled in as one unit only, so undo any - * partial group before returning: - * The events up to the failed event are scheduled out normally, - * tstamp_stopped will be updated. - * - * The failed events and the remaining siblings need to have - * their timings updated as if they had gone thru event_sched_in() - * and event_sched_out(). This is required to get consistent timings - * across the group. This also takes care of the case where the group - * could never be scheduled by ensuring tstamp_stopped is set to mark - * the time the event was actually stopped, such that time delta - * calculation in update_event_times() is correct. - */ - list_for_each_entry(event, &group_event->sibling_list, group_entry) { - if (event == partial_group) - simulate = true; - - if (simulate) { - event->tstamp_running += now - event->tstamp_stopped; - event->tstamp_stopped = now; - } else { - event_sched_out(event, cpuctx, ctx); - } - } - event_sched_out(group_event, cpuctx, ctx); - - pmu->cancel_txn(pmu); - - return -EAGAIN; -} - -/* - * Work out whether we can put this event group on the CPU now. - */ -static int group_can_go_on(struct perf_event *event, - struct perf_cpu_context *cpuctx, - int can_add_hw) -{ - /* - * Groups consisting entirely of software events can always go on. - */ - if (event->group_flags & PERF_GROUP_SOFTWARE) - return 1; - /* - * If an exclusive group is already on, no other hardware - * events can go on. - */ - if (cpuctx->exclusive) - return 0; - /* - * If this group is exclusive and there are already - * events on the CPU, it can't go on. - */ - if (event->attr.exclusive && cpuctx->active_oncpu) - return 0; - /* - * Otherwise, try to add it if all previous groups were able - * to go on. - */ - return can_add_hw; -} - -static void add_event_to_ctx(struct perf_event *event, - struct perf_event_context *ctx) -{ - u64 tstamp = perf_event_time(event); - - list_add_event(event, ctx); - perf_group_attach(event); - event->tstamp_enabled = tstamp; - event->tstamp_running = tstamp; - event->tstamp_stopped = tstamp; -} - -static void perf_event_context_sched_in(struct perf_event_context *ctx, - struct task_struct *tsk); - -/* - * Cross CPU call to install and enable a performance event - * - * Must be called with ctx->mutex held - */ -static int __perf_install_in_context(void *info) -{ - struct perf_event *event = info; - struct perf_event_context *ctx = event->ctx; - struct perf_event *leader = event->group_leader; - struct perf_cpu_context *cpuctx = __get_cpu_context(ctx); - int err; - - /* - * In case we're installing a new context to an already running task, - * could also happen before perf_event_task_sched_in() on architectures - * which do context switches with IRQs enabled. - */ - if (ctx->task && !cpuctx->task_ctx) - perf_event_context_sched_in(ctx, ctx->task); - - raw_spin_lock(&ctx->lock); - ctx->is_active = 1; - update_context_time(ctx); - /* - * update cgrp time only if current cgrp - * matches event->cgrp. Must be done before - * calling add_event_to_ctx() - */ - update_cgrp_time_from_event(event); - - add_event_to_ctx(event, ctx); - - if (!event_filter_match(event)) - goto unlock; - - /* - * Don't put the event on if it is disabled or if - * it is in a group and the group isn't on. - */ - if (event->state != PERF_EVENT_STATE_INACTIVE || - (leader != event && leader->state != PERF_EVENT_STATE_ACTIVE)) - goto unlock; - - /* - * An exclusive event can't go on if there are already active - * hardware events, and no hardware event can go on if there - * is already an exclusive event on. - */ - if (!group_can_go_on(event, cpuctx, 1)) - err = -EEXIST; - else - err = event_sched_in(event, cpuctx, ctx); - - if (err) { - /* - * This event couldn't go on. If it is in a group - * then we have to pull the whole group off. - * If the event group is pinned then put it in error state. - */ - if (leader != event) - group_sched_out(leader, cpuctx, ctx); - if (leader->attr.pinned) { - update_group_times(leader); - leader->state = PERF_EVENT_STATE_ERROR; - } - } - -unlock: - raw_spin_unlock(&ctx->lock); - - return 0; -} - -/* - * Attach a performance event to a context - * - * First we add the event to the list with the hardware enable bit - * in event->hw_config cleared. - * - * If the event is attached to a task which is on a CPU we use a smp - * call to enable it in the task context. The task might have been - * scheduled away, but we check this in the smp call again. - */ -static void -perf_install_in_context(struct perf_event_context *ctx, - struct perf_event *event, - int cpu) -{ - struct task_struct *task = ctx->task; - - lockdep_assert_held(&ctx->mutex); - - event->ctx = ctx; - - if (!task) { - /* - * Per cpu events are installed via an smp call and - * the install is always successful. - */ - cpu_function_call(cpu, __perf_install_in_context, event); - return; - } - -retry: - if (!task_function_call(task, __perf_install_in_context, event)) - return; - - raw_spin_lock_irq(&ctx->lock); - /* - * If we failed to find a running task, but find the context active now - * that we've acquired the ctx->lock, retry. - */ - if (ctx->is_active) { - raw_spin_unlock_irq(&ctx->lock); - goto retry; - } - - /* - * Since the task isn't running, its safe to add the event, us holding - * the ctx->lock ensures the task won't get scheduled in. - */ - add_event_to_ctx(event, ctx); - raw_spin_unlock_irq(&ctx->lock); -} - -/* - * Put a event into inactive state and update time fields. - * Enabling the leader of a group effectively enables all - * the group members that aren't explicitly disabled, so we - * have to update their ->tstamp_enabled also. - * Note: this works for group members as well as group leaders - * since the non-leader members' sibling_lists will be empty. - */ -static void __perf_event_mark_enabled(struct perf_event *event, - struct perf_event_context *ctx) -{ - struct perf_event *sub; - u64 tstamp = perf_event_time(event); - - event->state = PERF_EVENT_STATE_INACTIVE; - event->tstamp_enabled = tstamp - event->total_time_enabled; - list_for_each_entry(sub, &event->sibling_list, group_entry) { - if (sub->state >= PERF_EVENT_STATE_INACTIVE) - sub->tstamp_enabled = tstamp - sub->total_time_enabled; - } -} - -/* - * Cross CPU call to enable a performance event - */ -static int __perf_event_enable(void *info) -{ - struct perf_event *event = info; - struct perf_event_context *ctx = event->ctx; - struct perf_event *leader = event->group_leader; - struct perf_cpu_context *cpuctx = __get_cpu_context(ctx); - int err; - - if (WARN_ON_ONCE(!ctx->is_active)) - return -EINVAL; - - raw_spin_lock(&ctx->lock); - update_context_time(ctx); - - if (event->state >= PERF_EVENT_STATE_INACTIVE) - goto unlock; - - /* - * set current task's cgroup time reference point - */ - perf_cgroup_set_timestamp(current, ctx); - - __perf_event_mark_enabled(event, ctx); - - if (!event_filter_match(event)) { - if (is_cgroup_event(event)) - perf_cgroup_defer_enabled(event); - goto unlock; - } - - /* - * If the event is in a group and isn't the group leader, - * then don't put it on unless the group is on. - */ - if (leader != event && leader->state != PERF_EVENT_STATE_ACTIVE) - goto unlock; - - if (!group_can_go_on(event, cpuctx, 1)) { - err = -EEXIST; - } else { - if (event == leader) - err = group_sched_in(event, cpuctx, ctx); - else - err = event_sched_in(event, cpuctx, ctx); - } - - if (err) { - /* - * If this event can't go on and it's part of a - * group, then the whole group has to come off. - */ - if (leader != event) - group_sched_out(leader, cpuctx, ctx); - if (leader->attr.pinned) { - update_group_times(leader); - leader->state = PERF_EVENT_STATE_ERROR; - } - } - -unlock: - raw_spin_unlock(&ctx->lock); - - return 0; -} - -/* - * Enable a event. - * - * If event->ctx is a cloned context, callers must make sure that - * every task struct that event->ctx->task could possibly point to - * remains valid. This condition is satisfied when called through - * perf_event_for_each_child or perf_event_for_each as described - * for perf_event_disable. - */ -void perf_event_enable(struct perf_event *event) -{ - struct perf_event_context *ctx = event->ctx; - struct task_struct *task = ctx->task; - - if (!task) { - /* - * Enable the event on the cpu that it's on - */ - cpu_function_call(event->cpu, __perf_event_enable, event); - return; - } - - raw_spin_lock_irq(&ctx->lock); - if (event->state >= PERF_EVENT_STATE_INACTIVE) - goto out; - - /* - * If the event is in error state, clear that first. - * That way, if we see the event in error state below, we - * know that it has gone back into error state, as distinct - * from the task having been scheduled away before the - * cross-call arrived. - */ - if (event->state == PERF_EVENT_STATE_ERROR) - event->state = PERF_EVENT_STATE_OFF; - -retry: - if (!ctx->is_active) { - __perf_event_mark_enabled(event, ctx); - goto out; - } - - raw_spin_unlock_irq(&ctx->lock); - - if (!task_function_call(task, __perf_event_enable, event)) - return; - - raw_spin_lock_irq(&ctx->lock); - - /* - * If the context is active and the event is still off, - * we need to retry the cross-call. - */ - if (ctx->is_active && event->state == PERF_EVENT_STATE_OFF) { - /* - * task could have been flipped by a concurrent - * perf_event_context_sched_out() - */ - task = ctx->task; - goto retry; - } - -out: - raw_spin_unlock_irq(&ctx->lock); -} - -static int perf_event_refresh(struct perf_event *event, int refresh) -{ - /* - * not supported on inherited events - */ - if (event->attr.inherit || !is_sampling_event(event)) - return -EINVAL; - - atomic_add(refresh, &event->event_limit); - perf_event_enable(event); - - return 0; -} - -static void ctx_sched_out(struct perf_event_context *ctx, - struct perf_cpu_context *cpuctx, - enum event_type_t event_type) -{ - struct perf_event *event; - - raw_spin_lock(&ctx->lock); - perf_pmu_disable(ctx->pmu); - ctx->is_active = 0; - if (likely(!ctx->nr_events)) - goto out; - update_context_time(ctx); - update_cgrp_time_from_cpuctx(cpuctx); - - if (!ctx->nr_active) - goto out; - - if (event_type & EVENT_PINNED) { - list_for_each_entry(event, &ctx->pinned_groups, group_entry) - group_sched_out(event, cpuctx, ctx); - } - - if (event_type & EVENT_FLEXIBLE) { - list_for_each_entry(event, &ctx->flexible_groups, group_entry) - group_sched_out(event, cpuctx, ctx); - } -out: - perf_pmu_enable(ctx->pmu); - raw_spin_unlock(&ctx->lock); -} - -/* - * Test whether two contexts are equivalent, i.e. whether they - * have both been cloned from the same version of the same context - * and they both have the same number of enabled events. - * If the number of enabled events is the same, then the set - * of enabled events should be the same, because these are both - * inherited contexts, therefore we can't access individual events - * in them directly with an fd; we can only enable/disable all - * events via prctl, or enable/disable all events in a family - * via ioctl, which will have the same effect on both contexts. - */ -static int context_equiv(struct perf_event_context *ctx1, - struct perf_event_context *ctx2) -{ - return ctx1->parent_ctx && ctx1->parent_ctx == ctx2->parent_ctx - && ctx1->parent_gen == ctx2->parent_gen - && !ctx1->pin_count && !ctx2->pin_count; -} - -static void __perf_event_sync_stat(struct perf_event *event, - struct perf_event *next_event) -{ - u64 value; - - if (!event->attr.inherit_stat) - return; - - /* - * Update the event value, we cannot use perf_event_read() - * because we're in the middle of a context switch and have IRQs - * disabled, which upsets smp_call_function_single(), however - * we know the event must be on the current CPU, therefore we - * don't need to use it. - */ - switch (event->state) { - case PERF_EVENT_STATE_ACTIVE: - event->pmu->read(event); - /* fall-through */ - - case PERF_EVENT_STATE_INACTIVE: - update_event_times(event); - break; - - default: - break; - } - - /* - * In order to keep per-task stats reliable we need to flip the event - * values when we flip the contexts. - */ - value = local64_read(&next_event->count); - value = local64_xchg(&event->count, value); - local64_set(&next_event->count, value); - - swap(event->total_time_enabled, next_event->total_time_enabled); - swap(event->total_time_running, next_event->total_time_running); - - /* - * Since we swizzled the values, update the user visible data too. - */ - perf_event_update_userpage(event); - perf_event_update_userpage(next_event); -} - -#define list_next_entry(pos, member) \ - list_entry(pos->member.next, typeof(*pos), member) - -static void perf_event_sync_stat(struct perf_event_context *ctx, - struct perf_event_context *next_ctx) -{ - struct perf_event *event, *next_event; - - if (!ctx->nr_stat) - return; - - update_context_time(ctx); - - event = list_first_entry(&ctx->event_list, - struct perf_event, event_entry); - - next_event = list_first_entry(&next_ctx->event_list, - struct perf_event, event_entry); - - while (&event->event_entry != &ctx->event_list && - &next_event->event_entry != &next_ctx->event_list) { - - __perf_event_sync_stat(event, next_event); - - event = list_next_entry(event, event_entry); - next_event = list_next_entry(next_event, event_entry); - } -} - -static void perf_event_context_sched_out(struct task_struct *task, int ctxn, - struct task_struct *next) -{ - struct perf_event_context *ctx = task->perf_event_ctxp[ctxn]; - struct perf_event_context *next_ctx; - struct perf_event_context *parent; - struct perf_cpu_context *cpuctx; - int do_switch = 1; - - if (likely(!ctx)) - return; - - cpuctx = __get_cpu_context(ctx); - if (!cpuctx->task_ctx) - return; - - rcu_read_lock(); - parent = rcu_dereference(ctx->parent_ctx); - next_ctx = next->perf_event_ctxp[ctxn]; - if (parent && next_ctx && - rcu_dereference(next_ctx->parent_ctx) == parent) { - /* - * Looks like the two contexts are clones, so we might be - * able to optimize the context switch. We lock both - * contexts and check that they are clones under the - * lock (including re-checking that neither has been - * uncloned in the meantime). It doesn't matter which - * order we take the locks because no other cpu could - * be trying to lock both of these tasks. - */ - raw_spin_lock(&ctx->lock); - raw_spin_lock_nested(&next_ctx->lock, SINGLE_DEPTH_NESTING); - if (context_equiv(ctx, next_ctx)) { - /* - * XXX do we need a memory barrier of sorts - * wrt to rcu_dereference() of perf_event_ctxp - */ - task->perf_event_ctxp[ctxn] = next_ctx; - next->perf_event_ctxp[ctxn] = ctx; - ctx->task = next; - next_ctx->task = task; - do_switch = 0; - - perf_event_sync_stat(ctx, next_ctx); - } - raw_spin_unlock(&next_ctx->lock); - raw_spin_unlock(&ctx->lock); - } - rcu_read_unlock(); - - if (do_switch) { - ctx_sched_out(ctx, cpuctx, EVENT_ALL); - cpuctx->task_ctx = NULL; - } -} - -#define for_each_task_context_nr(ctxn) \ - for ((ctxn) = 0; (ctxn) < perf_nr_task_contexts; (ctxn)++) - -/* - * Called from scheduler to remove the events of the current task, - * with interrupts disabled. - * - * We stop each event and update the event value in event->count. - * - * This does not protect us against NMI, but disable() - * sets the disabled bit in the control field of event _before_ - * accessing the event control register. If a NMI hits, then it will - * not restart the event. - */ -void __perf_event_task_sched_out(struct task_struct *task, - struct task_struct *next) -{ - int ctxn; - - for_each_task_context_nr(ctxn) - perf_event_context_sched_out(task, ctxn, next); - - /* - * if cgroup events exist on this CPU, then we need - * to check if we have to switch out PMU state. - * cgroup event are system-wide mode only - */ - if (atomic_read(&__get_cpu_var(perf_cgroup_events))) - perf_cgroup_sched_out(task); -} - -static void task_ctx_sched_out(struct perf_event_context *ctx, - enum event_type_t event_type) -{ - struct perf_cpu_context *cpuctx = __get_cpu_context(ctx); - - if (!cpuctx->task_ctx) - return; - - if (WARN_ON_ONCE(ctx != cpuctx->task_ctx)) - return; - - ctx_sched_out(ctx, cpuctx, event_type); - cpuctx->task_ctx = NULL; -} - -/* - * Called with IRQs disabled - */ -static void cpu_ctx_sched_out(struct perf_cpu_context *cpuctx, - enum event_type_t event_type) -{ - ctx_sched_out(&cpuctx->ctx, cpuctx, event_type); -} - -static void -ctx_pinned_sched_in(struct perf_event_context *ctx, - struct perf_cpu_context *cpuctx) -{ - struct perf_event *event; - - list_for_each_entry(event, &ctx->pinned_groups, group_entry) { - if (event->state <= PERF_EVENT_STATE_OFF) - continue; - if (!event_filter_match(event)) - continue; - - /* may need to reset tstamp_enabled */ - if (is_cgroup_event(event)) - perf_cgroup_mark_enabled(event, ctx); - - if (group_can_go_on(event, cpuctx, 1)) - group_sched_in(event, cpuctx, ctx); - - /* - * If this pinned group hasn't been scheduled, - * put it in error state. - */ - if (event->state == PERF_EVENT_STATE_INACTIVE) { - update_group_times(event); - event->state = PERF_EVENT_STATE_ERROR; - } - } -} - -static void -ctx_flexible_sched_in(struct perf_event_context *ctx, - struct perf_cpu_context *cpuctx) -{ - struct perf_event *event; - int can_add_hw = 1; - - list_for_each_entry(event, &ctx->flexible_groups, group_entry) { - /* Ignore events in OFF or ERROR state */ - if (event->state <= PERF_EVENT_STATE_OFF) - continue; - /* - * Listen to the 'cpu' scheduling filter constraint - * of events: - */ - if (!event_filter_match(event)) - continue; - - /* may need to reset tstamp_enabled */ - if (is_cgroup_event(event)) - perf_cgroup_mark_enabled(event, ctx); - - if (group_can_go_on(event, cpuctx, can_add_hw)) { - if (group_sched_in(event, cpuctx, ctx)) - can_add_hw = 0; - } - } -} - -static void -ctx_sched_in(struct perf_event_context *ctx, - struct perf_cpu_context *cpuctx, - enum event_type_t event_type, - struct task_struct *task) -{ - u64 now; - - raw_spin_lock(&ctx->lock); - ctx->is_active = 1; - if (likely(!ctx->nr_events)) - goto out; - - now = perf_clock(); - ctx->timestamp = now; - perf_cgroup_set_timestamp(task, ctx); - /* - * First go through the list and put on any pinned groups - * in order to give them the best chance of going on. - */ - if (event_type & EVENT_PINNED) - ctx_pinned_sched_in(ctx, cpuctx); - - /* Then walk through the lower prio flexible groups */ - if (event_type & EVENT_FLEXIBLE) - ctx_flexible_sched_in(ctx, cpuctx); - -out: - raw_spin_unlock(&ctx->lock); -} - -static void cpu_ctx_sched_in(struct perf_cpu_context *cpuctx, - enum event_type_t event_type, - struct task_struct *task) -{ - struct perf_event_context *ctx = &cpuctx->ctx; - - ctx_sched_in(ctx, cpuctx, event_type, task); -} - -static void task_ctx_sched_in(struct perf_event_context *ctx, - enum event_type_t event_type) -{ - struct perf_cpu_context *cpuctx; - - cpuctx = __get_cpu_context(ctx); - if (cpuctx->task_ctx == ctx) - return; - - ctx_sched_in(ctx, cpuctx, event_type, NULL); - cpuctx->task_ctx = ctx; -} - -static void perf_event_context_sched_in(struct perf_event_context *ctx, - struct task_struct *task) -{ - struct perf_cpu_context *cpuctx; - - cpuctx = __get_cpu_context(ctx); - if (cpuctx->task_ctx == ctx) - return; - - perf_pmu_disable(ctx->pmu); - /* - * We want to keep the following priority order: - * cpu pinned (that don't need to move), task pinned, - * cpu flexible, task flexible. - */ - cpu_ctx_sched_out(cpuctx, EVENT_FLEXIBLE); - - ctx_sched_in(ctx, cpuctx, EVENT_PINNED, task); - cpu_ctx_sched_in(cpuctx, EVENT_FLEXIBLE, task); - ctx_sched_in(ctx, cpuctx, EVENT_FLEXIBLE, task); - - cpuctx->task_ctx = ctx; - - /* - * Since these rotations are per-cpu, we need to ensure the - * cpu-context we got scheduled on is actually rotating. - */ - perf_pmu_rotate_start(ctx->pmu); - perf_pmu_enable(ctx->pmu); -} - -/* - * Called from scheduler to add the events of the current task - * with interrupts disabled. - * - * We restore the event value and then enable it. - * - * This does not protect us against NMI, but enable() - * sets the enabled bit in the control field of event _before_ - * accessing the event control register. If a NMI hits, then it will - * keep the event running. - */ -void __perf_event_task_sched_in(struct task_struct *task) -{ - struct perf_event_context *ctx; - int ctxn; - - for_each_task_context_nr(ctxn) { - ctx = task->perf_event_ctxp[ctxn]; - if (likely(!ctx)) - continue; - - perf_event_context_sched_in(ctx, task); - } - /* - * if cgroup events exist on this CPU, then we need - * to check if we have to switch in PMU state. - * cgroup event are system-wide mode only - */ - if (atomic_read(&__get_cpu_var(perf_cgroup_events))) - perf_cgroup_sched_in(task); -} - -static u64 perf_calculate_period(struct perf_event *event, u64 nsec, u64 count) -{ - u64 frequency = event->attr.sample_freq; - u64 sec = NSEC_PER_SEC; - u64 divisor, dividend; - - int count_fls, nsec_fls, frequency_fls, sec_fls; - - count_fls = fls64(count); - nsec_fls = fls64(nsec); - frequency_fls = fls64(frequency); - sec_fls = 30; - - /* - * We got @count in @nsec, with a target of sample_freq HZ - * the target period becomes: - * - * @count * 10^9 - * period = ------------------- - * @nsec * sample_freq - * - */ - - /* - * Reduce accuracy by one bit such that @a and @b converge - * to a similar magnitude. - */ -#define REDUCE_FLS(a, b) \ -do { \ - if (a##_fls > b##_fls) { \ - a >>= 1; \ - a##_fls--; \ - } else { \ - b >>= 1; \ - b##_fls--; \ - } \ -} while (0) - - /* - * Reduce accuracy until either term fits in a u64, then proceed with - * the other, so that finally we can do a u64/u64 division. - */ - while (count_fls + sec_fls > 64 && nsec_fls + frequency_fls > 64) { - REDUCE_FLS(nsec, frequency); - REDUCE_FLS(sec, count); - } - - if (count_fls + sec_fls > 64) { - divisor = nsec * frequency; - - while (count_fls + sec_fls > 64) { - REDUCE_FLS(count, sec); - divisor >>= 1; - } - - dividend = count * sec; - } else { - dividend = count * sec; - - while (nsec_fls + frequency_fls > 64) { - REDUCE_FLS(nsec, frequency); - dividend >>= 1; - } - - divisor = nsec * frequency; - } - - if (!divisor) - return dividend; - - return div64_u64(dividend, divisor); -} - -static void perf_adjust_period(struct perf_event *event, u64 nsec, u64 count) -{ - struct hw_perf_event *hwc = &event->hw; - s64 period, sample_period; - s64 delta; - - period = perf_calculate_period(event, nsec, count); - - delta = (s64)(period - hwc->sample_period); - delta = (delta + 7) / 8; /* low pass filter */ - - sample_period = hwc->sample_period + delta; - - if (!sample_period) - sample_period = 1; - - hwc->sample_period = sample_period; - - if (local64_read(&hwc->period_left) > 8*sample_period) { - event->pmu->stop(event, PERF_EF_UPDATE); - local64_set(&hwc->period_left, 0); - event->pmu->start(event, PERF_EF_RELOAD); - } -} - -static void perf_ctx_adjust_freq(struct perf_event_context *ctx, u64 period) -{ - struct perf_event *event; - struct hw_perf_event *hwc; - u64 interrupts, now; - s64 delta; - - raw_spin_lock(&ctx->lock); - list_for_each_entry_rcu(event, &ctx->event_list, event_entry) { - if (event->state != PERF_EVENT_STATE_ACTIVE) - continue; - - if (!event_filter_match(event)) - continue; - - hwc = &event->hw; - - interrupts = hwc->interrupts; - hwc->interrupts = 0; - - /* - * unthrottle events on the tick - */ - if (interrupts == MAX_INTERRUPTS) { - perf_log_throttle(event, 1); - event->pmu->start(event, 0); - } - - if (!event->attr.freq || !event->attr.sample_freq) - continue; - - event->pmu->read(event); - now = local64_read(&event->count); - delta = now - hwc->freq_count_stamp; - hwc->freq_count_stamp = now; - - if (delta > 0) - perf_adjust_period(event, period, delta); - } - raw_spin_unlock(&ctx->lock); -} - -/* - * Round-robin a context's events: - */ -static void rotate_ctx(struct perf_event_context *ctx) -{ - raw_spin_lock(&ctx->lock); - - /* - * Rotate the first entry last of non-pinned groups. Rotation might be - * disabled by the inheritance code. - */ - if (!ctx->rotate_disable) - list_rotate_left(&ctx->flexible_groups); - - raw_spin_unlock(&ctx->lock); -} - -/* - * perf_pmu_rotate_start() and perf_rotate_context() are fully serialized - * because they're strictly cpu affine and rotate_start is called with IRQs - * disabled, while rotate_context is called from IRQ context. - */ -static void perf_rotate_context(struct perf_cpu_context *cpuctx) -{ - u64 interval = (u64)cpuctx->jiffies_interval * TICK_NSEC; - struct perf_event_context *ctx = NULL; - int rotate = 0, remove = 1; - - if (cpuctx->ctx.nr_events) { - remove = 0; - if (cpuctx->ctx.nr_events != cpuctx->ctx.nr_active) - rotate = 1; - } - - ctx = cpuctx->task_ctx; - if (ctx && ctx->nr_events) { - remove = 0; - if (ctx->nr_events != ctx->nr_active) - rotate = 1; - } - - perf_pmu_disable(cpuctx->ctx.pmu); - perf_ctx_adjust_freq(&cpuctx->ctx, interval); - if (ctx) - perf_ctx_adjust_freq(ctx, interval); - - if (!rotate) - goto done; - - cpu_ctx_sched_out(cpuctx, EVENT_FLEXIBLE); - if (ctx) - task_ctx_sched_out(ctx, EVENT_FLEXIBLE); - - rotate_ctx(&cpuctx->ctx); - if (ctx) - rotate_ctx(ctx); - - cpu_ctx_sched_in(cpuctx, EVENT_FLEXIBLE, current); - if (ctx) - task_ctx_sched_in(ctx, EVENT_FLEXIBLE); - -done: - if (remove) - list_del_init(&cpuctx->rotation_list); - - perf_pmu_enable(cpuctx->ctx.pmu); -} - -void perf_event_task_tick(void) -{ - struct list_head *head = &__get_cpu_var(rotation_list); - struct perf_cpu_context *cpuctx, *tmp; - - WARN_ON(!irqs_disabled()); - - list_for_each_entry_safe(cpuctx, tmp, head, rotation_list) { - if (cpuctx->jiffies_interval == 1 || - !(jiffies % cpuctx->jiffies_interval)) - perf_rotate_context(cpuctx); - } -} - -static int event_enable_on_exec(struct perf_event *event, - struct perf_event_context *ctx) -{ - if (!event->attr.enable_on_exec) - return 0; - - event->attr.enable_on_exec = 0; - if (event->state >= PERF_EVENT_STATE_INACTIVE) - return 0; - - __perf_event_mark_enabled(event, ctx); - - return 1; -} - -/* - * Enable all of a task's events that have been marked enable-on-exec. - * This expects task == current. - */ -static void perf_event_enable_on_exec(struct perf_event_context *ctx) -{ - struct perf_event *event; - unsigned long flags; - int enabled = 0; - int ret; - - local_irq_save(flags); - if (!ctx || !ctx->nr_events) - goto out; - - /* - * We must ctxsw out cgroup events to avoid conflict - * when invoking perf_task_event_sched_in() later on - * in this function. Otherwise we end up trying to - * ctxswin cgroup events which are already scheduled - * in. - */ - perf_cgroup_sched_out(current); - task_ctx_sched_out(ctx, EVENT_ALL); - - raw_spin_lock(&ctx->lock); - - list_for_each_entry(event, &ctx->pinned_groups, group_entry) { - ret = event_enable_on_exec(event, ctx); - if (ret) - enabled = 1; - } - - list_for_each_entry(event, &ctx->flexible_groups, group_entry) { - ret = event_enable_on_exec(event, ctx); - if (ret) - enabled = 1; - } - - /* - * Unclone this context if we enabled any event. - */ - if (enabled) - unclone_ctx(ctx); - - raw_spin_unlock(&ctx->lock); - - /* - * Also calls ctxswin for cgroup events, if any: - */ - perf_event_context_sched_in(ctx, ctx->task); -out: - local_irq_restore(flags); -} - -/* - * Cross CPU call to read the hardware event - */ -static void __perf_event_read(void *info) -{ - struct perf_event *event = info; - struct perf_event_context *ctx = event->ctx; - struct perf_cpu_context *cpuctx = __get_cpu_context(ctx); - - /* - * If this is a task context, we need to check whether it is - * the current task context of this cpu. If not it has been - * scheduled out before the smp call arrived. In that case - * event->count would have been updated to a recent sample - * when the event was scheduled out. - */ - if (ctx->task && cpuctx->task_ctx != ctx) - return; - - raw_spin_lock(&ctx->lock); - if (ctx->is_active) { - update_context_time(ctx); - update_cgrp_time_from_event(event); - } - update_event_times(event); - if (event->state == PERF_EVENT_STATE_ACTIVE) - event->pmu->read(event); - raw_spin_unlock(&ctx->lock); -} - -static inline u64 perf_event_count(struct perf_event *event) -{ - return local64_read(&event->count) + atomic64_read(&event->child_count); -} - -static u64 perf_event_read(struct perf_event *event) -{ - /* - * If event is enabled and currently active on a CPU, update the - * value in the event structure: - */ - if (event->state == PERF_EVENT_STATE_ACTIVE) { - smp_call_function_single(event->oncpu, - __perf_event_read, event, 1); - } else if (event->state == PERF_EVENT_STATE_INACTIVE) { - struct perf_event_context *ctx = event->ctx; - unsigned long flags; - - raw_spin_lock_irqsave(&ctx->lock, flags); - /* - * may read while context is not active - * (e.g., thread is blocked), in that case - * we cannot update context time - */ - if (ctx->is_active) { - update_context_time(ctx); - update_cgrp_time_from_event(event); - } - update_event_times(event); - raw_spin_unlock_irqrestore(&ctx->lock, flags); - } - - return perf_event_count(event); -} - -/* - * Callchain support - */ - -struct callchain_cpus_entries { - struct rcu_head rcu_head; - struct perf_callchain_entry *cpu_entries[0]; -}; - -static DEFINE_PER_CPU(int, callchain_recursion[PERF_NR_CONTEXTS]); -static atomic_t nr_callchain_events; -static DEFINE_MUTEX(callchain_mutex); -struct callchain_cpus_entries *callchain_cpus_entries; - - -__weak void perf_callchain_kernel(struct perf_callchain_entry *entry, - struct pt_regs *regs) -{ -} - -__weak void perf_callchain_user(struct perf_callchain_entry *entry, - struct pt_regs *regs) -{ -} - -static void release_callchain_buffers_rcu(struct rcu_head *head) -{ - struct callchain_cpus_entries *entries; - int cpu; - - entries = container_of(head, struct callchain_cpus_entries, rcu_head); - - for_each_possible_cpu(cpu) - kfree(entries->cpu_entries[cpu]); - - kfree(entries); -} - -static void release_callchain_buffers(void) -{ - struct callchain_cpus_entries *entries; - - entries = callchain_cpus_entries; - rcu_assign_pointer(callchain_cpus_entries, NULL); - call_rcu(&entries->rcu_head, release_callchain_buffers_rcu); -} - -static int alloc_callchain_buffers(void) -{ - int cpu; - int size; - struct callchain_cpus_entries *entries; - - /* - * We can't use the percpu allocation API for data that can be - * accessed from NMI. Use a temporary manual per cpu allocation - * until that gets sorted out. - */ - size = offsetof(struct callchain_cpus_entries, cpu_entries[nr_cpu_ids]); - - entries = kzalloc(size, GFP_KERNEL); - if (!entries) - return -ENOMEM; - - size = sizeof(struct perf_callchain_entry) * PERF_NR_CONTEXTS; - - for_each_possible_cpu(cpu) { - entries->cpu_entries[cpu] = kmalloc_node(size, GFP_KERNEL, - cpu_to_node(cpu)); - if (!entries->cpu_entries[cpu]) - goto fail; - } - - rcu_assign_pointer(callchain_cpus_entries, entries); - - return 0; - -fail: - for_each_possible_cpu(cpu) - kfree(entries->cpu_entries[cpu]); - kfree(entries); - - return -ENOMEM; -} - -static int get_callchain_buffers(void) -{ - int err = 0; - int count; - - mutex_lock(&callchain_mutex); - - count = atomic_inc_return(&nr_callchain_events); - if (WARN_ON_ONCE(count < 1)) { - err = -EINVAL; - goto exit; - } - - if (count > 1) { - /* If the allocation failed, give up */ - if (!callchain_cpus_entries) - err = -ENOMEM; - goto exit; - } - - err = alloc_callchain_buffers(); - if (err) - release_callchain_buffers(); -exit: - mutex_unlock(&callchain_mutex); - - return err; -} - -static void put_callchain_buffers(void) -{ - if (atomic_dec_and_mutex_lock(&nr_callchain_events, &callchain_mutex)) { - release_callchain_buffers(); - mutex_unlock(&callchain_mutex); - } -} - -static int get_recursion_context(int *recursion) -{ - int rctx; - - if (in_nmi()) - rctx = 3; - else if (in_irq()) - rctx = 2; - else if (in_softirq()) - rctx = 1; - else - rctx = 0; - - if (recursion[rctx]) - return -1; - - recursion[rctx]++; - barrier(); - - return rctx; -} - -static inline void put_recursion_context(int *recursion, int rctx) -{ - barrier(); - recursion[rctx]--; -} - -static struct perf_callchain_entry *get_callchain_entry(int *rctx) -{ - int cpu; - struct callchain_cpus_entries *entries; - - *rctx = get_recursion_context(__get_cpu_var(callchain_recursion)); - if (*rctx == -1) - return NULL; - - entries = rcu_dereference(callchain_cpus_entries); - if (!entries) - return NULL; - - cpu = smp_processor_id(); - - return &entries->cpu_entries[cpu][*rctx]; -} - -static void -put_callchain_entry(int rctx) -{ - put_recursion_context(__get_cpu_var(callchain_recursion), rctx); -} - -static struct perf_callchain_entry *perf_callchain(struct pt_regs *regs) -{ - int rctx; - struct perf_callchain_entry *entry; - - - entry = get_callchain_entry(&rctx); - if (rctx == -1) - return NULL; - - if (!entry) - goto exit_put; - - entry->nr = 0; - - if (!user_mode(regs)) { - perf_callchain_store(entry, PERF_CONTEXT_KERNEL); - perf_callchain_kernel(entry, regs); - if (current->mm) - regs = task_pt_regs(current); - else - regs = NULL; - } - - if (regs) { - perf_callchain_store(entry, PERF_CONTEXT_USER); - perf_callchain_user(entry, regs); - } - -exit_put: - put_callchain_entry(rctx); - - return entry; -} - -/* - * Initialize the perf_event context in a task_struct: - */ -static void __perf_event_init_context(struct perf_event_context *ctx) -{ - raw_spin_lock_init(&ctx->lock); - mutex_init(&ctx->mutex); - INIT_LIST_HEAD(&ctx->pinned_groups); - INIT_LIST_HEAD(&ctx->flexible_groups); - INIT_LIST_HEAD(&ctx->event_list); - atomic_set(&ctx->refcount, 1); -} - -static struct perf_event_context * -alloc_perf_context(struct pmu *pmu, struct task_struct *task) -{ - struct perf_event_context *ctx; - - ctx = kzalloc(sizeof(struct perf_event_context), GFP_KERNEL); - if (!ctx) - return NULL; - - __perf_event_init_context(ctx); - if (task) { - ctx->task = task; - get_task_struct(task); - } - ctx->pmu = pmu; - - return ctx; -} - -static struct task_struct * -find_lively_task_by_vpid(pid_t vpid) -{ - struct task_struct *task; - int err; - - rcu_read_lock(); - if (!vpid) - task = current; - else - task = find_task_by_vpid(vpid); - if (task) - get_task_struct(task); - rcu_read_unlock(); - - if (!task) - return ERR_PTR(-ESRCH); - - /* Reuse ptrace permission checks for now. */ - err = -EACCES; - if (!ptrace_may_access(task, PTRACE_MODE_READ)) - goto errout; - - return task; -errout: - put_task_struct(task); - return ERR_PTR(err); - -} - -/* - * Returns a matching context with refcount and pincount. - */ -static struct perf_event_context * -find_get_context(struct pmu *pmu, struct task_struct *task, int cpu) -{ - struct perf_event_context *ctx; - struct perf_cpu_context *cpuctx; - unsigned long flags; - int ctxn, err; - - if (!task) { - /* Must be root to operate on a CPU event: */ - if (perf_paranoid_cpu() && !capable(CAP_SYS_ADMIN)) - return ERR_PTR(-EACCES); - - /* - * We could be clever and allow to attach a event to an - * offline CPU and activate it when the CPU comes up, but - * that's for later. - */ - if (!cpu_online(cpu)) - return ERR_PTR(-ENODEV); - - cpuctx = per_cpu_ptr(pmu->pmu_cpu_context, cpu); - ctx = &cpuctx->ctx; - get_ctx(ctx); - ++ctx->pin_count; - - return ctx; - } - - err = -EINVAL; - ctxn = pmu->task_ctx_nr; - if (ctxn < 0) - goto errout; - -retry: - ctx = perf_lock_task_context(task, ctxn, &flags); - if (ctx) { - unclone_ctx(ctx); - ++ctx->pin_count; - raw_spin_unlock_irqrestore(&ctx->lock, flags); - } - - if (!ctx) { - ctx = alloc_perf_context(pmu, task); - err = -ENOMEM; - if (!ctx) - goto errout; - - get_ctx(ctx); - - err = 0; - mutex_lock(&task->perf_event_mutex); - /* - * If it has already passed perf_event_exit_task(). - * we must see PF_EXITING, it takes this mutex too. - */ - if (task->flags & PF_EXITING) - err = -ESRCH; - else if (task->perf_event_ctxp[ctxn]) - err = -EAGAIN; - else { - ++ctx->pin_count; - rcu_assign_pointer(task->perf_event_ctxp[ctxn], ctx); - } - mutex_unlock(&task->perf_event_mutex); - - if (unlikely(err)) { - put_task_struct(task); - kfree(ctx); - - if (err == -EAGAIN) - goto retry; - goto errout; - } - } - - return ctx; - -errout: - return ERR_PTR(err); -} - -static void perf_event_free_filter(struct perf_event *event); - -static void free_event_rcu(struct rcu_head *head) -{ - struct perf_event *event; - - event = container_of(head, struct perf_event, rcu_head); - if (event->ns) - put_pid_ns(event->ns); - perf_event_free_filter(event); - kfree(event); -} - -static void perf_buffer_put(struct perf_buffer *buffer); - -static void free_event(struct perf_event *event) -{ - irq_work_sync(&event->pending); - - if (!event->parent) { - if (event->attach_state & PERF_ATTACH_TASK) - jump_label_dec(&perf_sched_events); - if (event->attr.mmap || event->attr.mmap_data) - atomic_dec(&nr_mmap_events); - if (event->attr.comm) - atomic_dec(&nr_comm_events); - if (event->attr.task) - atomic_dec(&nr_task_events); - if (event->attr.sample_type & PERF_SAMPLE_CALLCHAIN) - put_callchain_buffers(); - if (is_cgroup_event(event)) { - atomic_dec(&per_cpu(perf_cgroup_events, event->cpu)); - jump_label_dec(&perf_sched_events); - } - } - - if (event->buffer) { - perf_buffer_put(event->buffer); - event->buffer = NULL; - } - - if (is_cgroup_event(event)) - perf_detach_cgroup(event); - - if (event->destroy) - event->destroy(event); - - if (event->ctx) - put_ctx(event->ctx); - - call_rcu(&event->rcu_head, free_event_rcu); -} - -int perf_event_release_kernel(struct perf_event *event) -{ - struct perf_event_context *ctx = event->ctx; - - /* - * Remove from the PMU, can't get re-enabled since we got - * here because the last ref went. - */ - perf_event_disable(event); - - WARN_ON_ONCE(ctx->parent_ctx); - /* - * There are two ways this annotation is useful: - * - * 1) there is a lock recursion from perf_event_exit_task - * see the comment there. - * - * 2) there is a lock-inversion with mmap_sem through - * perf_event_read_group(), which takes faults while - * holding ctx->mutex, however this is called after - * the last filedesc died, so there is no possibility - * to trigger the AB-BA case. - */ - mutex_lock_nested(&ctx->mutex, SINGLE_DEPTH_NESTING); - raw_spin_lock_irq(&ctx->lock); - perf_group_detach(event); - list_del_event(event, ctx); - raw_spin_unlock_irq(&ctx->lock); - mutex_unlock(&ctx->mutex); - - free_event(event); - - return 0; -} -EXPORT_SYMBOL_GPL(perf_event_release_kernel); - -/* - * Called when the last reference to the file is gone. - */ -static int perf_release(struct inode *inode, struct file *file) -{ - struct perf_event *event = file->private_data; - struct task_struct *owner; - - file->private_data = NULL; - - rcu_read_lock(); - owner = ACCESS_ONCE(event->owner); - /* - * Matches the smp_wmb() in perf_event_exit_task(). If we observe - * !owner it means the list deletion is complete and we can indeed - * free this event, otherwise we need to serialize on - * owner->perf_event_mutex. - */ - smp_read_barrier_depends(); - if (owner) { - /* - * Since delayed_put_task_struct() also drops the last - * task reference we can safely take a new reference - * while holding the rcu_read_lock(). - */ - get_task_struct(owner); - } - rcu_read_unlock(); - - if (owner) { - mutex_lock(&owner->perf_event_mutex); - /* - * We have to re-check the event->owner field, if it is cleared - * we raced with perf_event_exit_task(), acquiring the mutex - * ensured they're done, and we can proceed with freeing the - * event. - */ - if (event->owner) - list_del_init(&event->owner_entry); - mutex_unlock(&owner->perf_event_mutex); - put_task_struct(owner); - } - - return perf_event_release_kernel(event); -} - -u64 perf_event_read_value(struct perf_event *event, u64 *enabled, u64 *running) -{ - struct perf_event *child; - u64 total = 0; - - *enabled = 0; - *running = 0; - - mutex_lock(&event->child_mutex); - total += perf_event_read(event); - *enabled += event->total_time_enabled + - atomic64_read(&event->child_total_time_enabled); - *running += event->total_time_running + - atomic64_read(&event->child_total_time_running); - - list_for_each_entry(child, &event->child_list, child_list) { - total += perf_event_read(child); - *enabled += child->total_time_enabled; - *running += child->total_time_running; - } - mutex_unlock(&event->child_mutex); - - return total; -} -EXPORT_SYMBOL_GPL(perf_event_read_value); - -static int perf_event_read_group(struct perf_event *event, - u64 read_format, char __user *buf) -{ - struct perf_event *leader = event->group_leader, *sub; - int n = 0, size = 0, ret = -EFAULT; - struct perf_event_context *ctx = leader->ctx; - u64 values[5]; - u64 count, enabled, running; - - mutex_lock(&ctx->mutex); - count = perf_event_read_value(leader, &enabled, &running); - - values[n++] = 1 + leader->nr_siblings; - if (read_format & PERF_FORMAT_TOTAL_TIME_ENABLED) - values[n++] = enabled; - if (read_format & PERF_FORMAT_TOTAL_TIME_RUNNING) - values[n++] = running; - values[n++] = count; - if (read_format & PERF_FORMAT_ID) - values[n++] = primary_event_id(leader); - - size = n * sizeof(u64); - - if (copy_to_user(buf, values, size)) - goto unlock; - - ret = size; - - list_for_each_entry(sub, &leader->sibling_list, group_entry) { - n = 0; - - values[n++] = perf_event_read_value(sub, &enabled, &running); - if (read_format & PERF_FORMAT_ID) - values[n++] = primary_event_id(sub); - - size = n * sizeof(u64); - - if (copy_to_user(buf + ret, values, size)) { - ret = -EFAULT; - goto unlock; - } - - ret += size; - } -unlock: - mutex_unlock(&ctx->mutex); - - return ret; -} - -static int perf_event_read_one(struct perf_event *event, - u64 read_format, char __user *buf) -{ - u64 enabled, running; - u64 values[4]; - int n = 0; - - values[n++] = perf_event_read_value(event, &enabled, &running); - if (read_format & PERF_FORMAT_TOTAL_TIME_ENABLED) - values[n++] = enabled; - if (read_format & PERF_FORMAT_TOTAL_TIME_RUNNING) - values[n++] = running; - if (read_format & PERF_FORMAT_ID) - values[n++] = primary_event_id(event); - - if (copy_to_user(buf, values, n * sizeof(u64))) - return -EFAULT; - - return n * sizeof(u64); -} - -/* - * Read the performance event - simple non blocking version for now - */ -static ssize_t -perf_read_hw(struct perf_event *event, char __user *buf, size_t count) -{ - u64 read_format = event->attr.read_format; - int ret; - - /* - * Return end-of-file for a read on a event that is in - * error state (i.e. because it was pinned but it couldn't be - * scheduled on to the CPU at some point). - */ - if (event->state == PERF_EVENT_STATE_ERROR) - return 0; - - if (count < event->read_size) - return -ENOSPC; - - WARN_ON_ONCE(event->ctx->parent_ctx); - if (read_format & PERF_FORMAT_GROUP) - ret = perf_event_read_group(event, read_format, buf); - else - ret = perf_event_read_one(event, read_format, buf); - - return ret; -} - -static ssize_t -perf_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) -{ - struct perf_event *event = file->private_data; - - return perf_read_hw(event, buf, count); -} - -static unsigned int perf_poll(struct file *file, poll_table *wait) -{ - struct perf_event *event = file->private_data; - struct perf_buffer *buffer; - unsigned int events = POLL_HUP; - - rcu_read_lock(); - buffer = rcu_dereference(event->buffer); - if (buffer) - events = atomic_xchg(&buffer->poll, 0); - rcu_read_unlock(); - - poll_wait(file, &event->waitq, wait); - - return events; -} - -static void perf_event_reset(struct perf_event *event) -{ - (void)perf_event_read(event); - local64_set(&event->count, 0); - perf_event_update_userpage(event); -} - -/* - * Holding the top-level event's child_mutex means that any - * descendant process that has inherited this event will block - * in sync_child_event if it goes to exit, thus satisfying the - * task existence requirements of perf_event_enable/disable. - */ -static void perf_event_for_each_child(struct perf_event *event, - void (*func)(struct perf_event *)) -{ - struct perf_event *child; - - WARN_ON_ONCE(event->ctx->parent_ctx); - mutex_lock(&event->child_mutex); - func(event); - list_for_each_entry(child, &event->child_list, child_list) - func(child); - mutex_unlock(&event->child_mutex); -} - -static void perf_event_for_each(struct perf_event *event, - void (*func)(struct perf_event *)) -{ - struct perf_event_context *ctx = event->ctx; - struct perf_event *sibling; - - WARN_ON_ONCE(ctx->parent_ctx); - mutex_lock(&ctx->mutex); - event = event->group_leader; - - perf_event_for_each_child(event, func); - func(event); - list_for_each_entry(sibling, &event->sibling_list, group_entry) - perf_event_for_each_child(event, func); - mutex_unlock(&ctx->mutex); -} - -static int perf_event_period(struct perf_event *event, u64 __user *arg) -{ - struct perf_event_context *ctx = event->ctx; - int ret = 0; - u64 value; - - if (!is_sampling_event(event)) - return -EINVAL; - - if (copy_from_user(&value, arg, sizeof(value))) - return -EFAULT; - - if (!value) - return -EINVAL; - - raw_spin_lock_irq(&ctx->lock); - if (event->attr.freq) { - if (value > sysctl_perf_event_sample_rate) { - ret = -EINVAL; - goto unlock; - } - - event->attr.sample_freq = value; - } else { - event->attr.sample_period = value; - event->hw.sample_period = value; - } -unlock: - raw_spin_unlock_irq(&ctx->lock); - - return ret; -} - -static const struct file_operations perf_fops; - -static struct perf_event *perf_fget_light(int fd, int *fput_needed) -{ - struct file *file; - - file = fget_light(fd, fput_needed); - if (!file) - return ERR_PTR(-EBADF); - - if (file->f_op != &perf_fops) { - fput_light(file, *fput_needed); - *fput_needed = 0; - return ERR_PTR(-EBADF); - } - - return file->private_data; -} - -static int perf_event_set_output(struct perf_event *event, - struct perf_event *output_event); -static int perf_event_set_filter(struct perf_event *event, void __user *arg); - -static long perf_ioctl(struct file *file, unsigned int cmd, unsigned long arg) -{ - struct perf_event *event = file->private_data; - void (*func)(struct perf_event *); - u32 flags = arg; - - switch (cmd) { - case PERF_EVENT_IOC_ENABLE: - func = perf_event_enable; - break; - case PERF_EVENT_IOC_DISABLE: - func = perf_event_disable; - break; - case PERF_EVENT_IOC_RESET: - func = perf_event_reset; - break; - - case PERF_EVENT_IOC_REFRESH: - return perf_event_refresh(event, arg); - - case PERF_EVENT_IOC_PERIOD: - return perf_event_period(event, (u64 __user *)arg); - - case PERF_EVENT_IOC_SET_OUTPUT: - { - struct perf_event *output_event = NULL; - int fput_needed = 0; - int ret; - - if (arg != -1) { - output_event = perf_fget_light(arg, &fput_needed); - if (IS_ERR(output_event)) - return PTR_ERR(output_event); - } - - ret = perf_event_set_output(event, output_event); - if (output_event) - fput_light(output_event->filp, fput_needed); - - return ret; - } - - case PERF_EVENT_IOC_SET_FILTER: - return perf_event_set_filter(event, (void __user *)arg); - - default: - return -ENOTTY; - } - - if (flags & PERF_IOC_FLAG_GROUP) - perf_event_for_each(event, func); - else - perf_event_for_each_child(event, func); - - return 0; -} - -int perf_event_task_enable(void) -{ - struct perf_event *event; - - mutex_lock(¤t->perf_event_mutex); - list_for_each_entry(event, ¤t->perf_event_list, owner_entry) - perf_event_for_each_child(event, perf_event_enable); - mutex_unlock(¤t->perf_event_mutex); - - return 0; -} - -int perf_event_task_disable(void) -{ - struct perf_event *event; - - mutex_lock(¤t->perf_event_mutex); - list_for_each_entry(event, ¤t->perf_event_list, owner_entry) - perf_event_for_each_child(event, perf_event_disable); - mutex_unlock(¤t->perf_event_mutex); - - return 0; -} - -#ifndef PERF_EVENT_INDEX_OFFSET -# define PERF_EVENT_INDEX_OFFSET 0 -#endif - -static int perf_event_index(struct perf_event *event) -{ - if (event->hw.state & PERF_HES_STOPPED) - return 0; - - if (event->state != PERF_EVENT_STATE_ACTIVE) - return 0; - - return event->hw.idx + 1 - PERF_EVENT_INDEX_OFFSET; -} - -/* - * Callers need to ensure there can be no nesting of this function, otherwise - * the seqlock logic goes bad. We can not serialize this because the arch - * code calls this from NMI context. - */ -void perf_event_update_userpage(struct perf_event *event) -{ - struct perf_event_mmap_page *userpg; - struct perf_buffer *buffer; - - rcu_read_lock(); - buffer = rcu_dereference(event->buffer); - if (!buffer) - goto unlock; - - userpg = buffer->user_page; - - /* - * Disable preemption so as to not let the corresponding user-space - * spin too long if we get preempted. - */ - preempt_disable(); - ++userpg->lock; - barrier(); - userpg->index = perf_event_index(event); - userpg->offset = perf_event_count(event); - if (event->state == PERF_EVENT_STATE_ACTIVE) - userpg->offset -= local64_read(&event->hw.prev_count); - - userpg->time_enabled = event->total_time_enabled + - atomic64_read(&event->child_total_time_enabled); - - userpg->time_running = event->total_time_running + - atomic64_read(&event->child_total_time_running); - - barrier(); - ++userpg->lock; - preempt_enable(); -unlock: - rcu_read_unlock(); -} - -static unsigned long perf_data_size(struct perf_buffer *buffer); - -static void -perf_buffer_init(struct perf_buffer *buffer, long watermark, int flags) -{ - long max_size = perf_data_size(buffer); - - if (watermark) - buffer->watermark = min(max_size, watermark); - - if (!buffer->watermark) - buffer->watermark = max_size / 2; - - if (flags & PERF_BUFFER_WRITABLE) - buffer->writable = 1; - - atomic_set(&buffer->refcount, 1); -} - -#ifndef CONFIG_PERF_USE_VMALLOC - -/* - * Back perf_mmap() with regular GFP_KERNEL-0 pages. - */ - -static struct page * -perf_mmap_to_page(struct perf_buffer *buffer, unsigned long pgoff) -{ - if (pgoff > buffer->nr_pages) - return NULL; - - if (pgoff == 0) - return virt_to_page(buffer->user_page); - - return virt_to_page(buffer->data_pages[pgoff - 1]); -} - -static void *perf_mmap_alloc_page(int cpu) -{ - struct page *page; - int node; - - node = (cpu == -1) ? cpu : cpu_to_node(cpu); - page = alloc_pages_node(node, GFP_KERNEL | __GFP_ZERO, 0); - if (!page) - return NULL; - - return page_address(page); -} - -static struct perf_buffer * -perf_buffer_alloc(int nr_pages, long watermark, int cpu, int flags) -{ - struct perf_buffer *buffer; - unsigned long size; - int i; - - size = sizeof(struct perf_buffer); - size += nr_pages * sizeof(void *); - - buffer = kzalloc(size, GFP_KERNEL); - if (!buffer) - goto fail; - - buffer->user_page = perf_mmap_alloc_page(cpu); - if (!buffer->user_page) - goto fail_user_page; - - for (i = 0; i < nr_pages; i++) { - buffer->data_pages[i] = perf_mmap_alloc_page(cpu); - if (!buffer->data_pages[i]) - goto fail_data_pages; - } - - buffer->nr_pages = nr_pages; - - perf_buffer_init(buffer, watermark, flags); - - return buffer; - -fail_data_pages: - for (i--; i >= 0; i--) - free_page((unsigned long)buffer->data_pages[i]); - - free_page((unsigned long)buffer->user_page); - -fail_user_page: - kfree(buffer); - -fail: - return NULL; -} - -static void perf_mmap_free_page(unsigned long addr) -{ - struct page *page = virt_to_page((void *)addr); - - page->mapping = NULL; - __free_page(page); -} - -static void perf_buffer_free(struct perf_buffer *buffer) -{ - int i; - - perf_mmap_free_page((unsigned long)buffer->user_page); - for (i = 0; i < buffer->nr_pages; i++) - perf_mmap_free_page((unsigned long)buffer->data_pages[i]); - kfree(buffer); -} - -static inline int page_order(struct perf_buffer *buffer) -{ - return 0; -} - -#else - -/* - * Back perf_mmap() with vmalloc memory. - * - * Required for architectures that have d-cache aliasing issues. - */ - -static inline int page_order(struct perf_buffer *buffer) -{ - return buffer->page_order; -} - -static struct page * -perf_mmap_to_page(struct perf_buffer *buffer, unsigned long pgoff) -{ - if (pgoff > (1UL << page_order(buffer))) - return NULL; - - return vmalloc_to_page((void *)buffer->user_page + pgoff * PAGE_SIZE); -} - -static void perf_mmap_unmark_page(void *addr) -{ - struct page *page = vmalloc_to_page(addr); - - page->mapping = NULL; -} - -static void perf_buffer_free_work(struct work_struct *work) -{ - struct perf_buffer *buffer; - void *base; - int i, nr; - - buffer = container_of(work, struct perf_buffer, work); - nr = 1 << page_order(buffer); - - base = buffer->user_page; - for (i = 0; i < nr + 1; i++) - perf_mmap_unmark_page(base + (i * PAGE_SIZE)); - - vfree(base); - kfree(buffer); -} - -static void perf_buffer_free(struct perf_buffer *buffer) -{ - schedule_work(&buffer->work); -} - -static struct perf_buffer * -perf_buffer_alloc(int nr_pages, long watermark, int cpu, int flags) -{ - struct perf_buffer *buffer; - unsigned long size; - void *all_buf; - - size = sizeof(struct perf_buffer); - size += sizeof(void *); - - buffer = kzalloc(size, GFP_KERNEL); - if (!buffer) - goto fail; - - INIT_WORK(&buffer->work, perf_buffer_free_work); - - all_buf = vmalloc_user((nr_pages + 1) * PAGE_SIZE); - if (!all_buf) - goto fail_all_buf; - - buffer->user_page = all_buf; - buffer->data_pages[0] = all_buf + PAGE_SIZE; - buffer->page_order = ilog2(nr_pages); - buffer->nr_pages = 1; - - perf_buffer_init(buffer, watermark, flags); - - return buffer; - -fail_all_buf: - kfree(buffer); - -fail: - return NULL; -} - -#endif - -static unsigned long perf_data_size(struct perf_buffer *buffer) -{ - return buffer->nr_pages << (PAGE_SHIFT + page_order(buffer)); -} - -static int perf_mmap_fault(struct vm_area_struct *vma, struct vm_fault *vmf) -{ - struct perf_event *event = vma->vm_file->private_data; - struct perf_buffer *buffer; - int ret = VM_FAULT_SIGBUS; - - if (vmf->flags & FAULT_FLAG_MKWRITE) { - if (vmf->pgoff == 0) - ret = 0; - return ret; - } - - rcu_read_lock(); - buffer = rcu_dereference(event->buffer); - if (!buffer) - goto unlock; - - if (vmf->pgoff && (vmf->flags & FAULT_FLAG_WRITE)) - goto unlock; - - vmf->page = perf_mmap_to_page(buffer, vmf->pgoff); - if (!vmf->page) - goto unlock; - - get_page(vmf->page); - vmf->page->mapping = vma->vm_file->f_mapping; - vmf->page->index = vmf->pgoff; - - ret = 0; -unlock: - rcu_read_unlock(); - - return ret; -} - -static void perf_buffer_free_rcu(struct rcu_head *rcu_head) -{ - struct perf_buffer *buffer; - - buffer = container_of(rcu_head, struct perf_buffer, rcu_head); - perf_buffer_free(buffer); -} - -static struct perf_buffer *perf_buffer_get(struct perf_event *event) -{ - struct perf_buffer *buffer; - - rcu_read_lock(); - buffer = rcu_dereference(event->buffer); - if (buffer) { - if (!atomic_inc_not_zero(&buffer->refcount)) - buffer = NULL; - } - rcu_read_unlock(); - - return buffer; -} - -static void perf_buffer_put(struct perf_buffer *buffer) -{ - if (!atomic_dec_and_test(&buffer->refcount)) - return; - - call_rcu(&buffer->rcu_head, perf_buffer_free_rcu); -} - -static void perf_mmap_open(struct vm_area_struct *vma) -{ - struct perf_event *event = vma->vm_file->private_data; - - atomic_inc(&event->mmap_count); -} - -static void perf_mmap_close(struct vm_area_struct *vma) -{ - struct perf_event *event = vma->vm_file->private_data; - - if (atomic_dec_and_mutex_lock(&event->mmap_count, &event->mmap_mutex)) { - unsigned long size = perf_data_size(event->buffer); - struct user_struct *user = event->mmap_user; - struct perf_buffer *buffer = event->buffer; - - atomic_long_sub((size >> PAGE_SHIFT) + 1, &user->locked_vm); - vma->vm_mm->locked_vm -= event->mmap_locked; - rcu_assign_pointer(event->buffer, NULL); - mutex_unlock(&event->mmap_mutex); - - perf_buffer_put(buffer); - free_uid(user); - } -} - -static const struct vm_operations_struct perf_mmap_vmops = { - .open = perf_mmap_open, - .close = perf_mmap_close, - .fault = perf_mmap_fault, - .page_mkwrite = perf_mmap_fault, -}; - -static int perf_mmap(struct file *file, struct vm_area_struct *vma) -{ - struct perf_event *event = file->private_data; - unsigned long user_locked, user_lock_limit; - struct user_struct *user = current_user(); - unsigned long locked, lock_limit; - struct perf_buffer *buffer; - unsigned long vma_size; - unsigned long nr_pages; - long user_extra, extra; - int ret = 0, flags = 0; - - /* - * Don't allow mmap() of inherited per-task counters. This would - * create a performance issue due to all children writing to the - * same buffer. - */ - if (event->cpu == -1 && event->attr.inherit) - return -EINVAL; - - if (!(vma->vm_flags & VM_SHARED)) - return -EINVAL; - - vma_size = vma->vm_end - vma->vm_start; - nr_pages = (vma_size / PAGE_SIZE) - 1; - - /* - * If we have buffer pages ensure they're a power-of-two number, so we - * can do bitmasks instead of modulo. - */ - if (nr_pages != 0 && !is_power_of_2(nr_pages)) - return -EINVAL; - - if (vma_size != PAGE_SIZE * (1 + nr_pages)) - return -EINVAL; - - if (vma->vm_pgoff != 0) - return -EINVAL; - - WARN_ON_ONCE(event->ctx->parent_ctx); - mutex_lock(&event->mmap_mutex); - if (event->buffer) { - if (event->buffer->nr_pages == nr_pages) - atomic_inc(&event->buffer->refcount); - else - ret = -EINVAL; - goto unlock; - } - - user_extra = nr_pages + 1; - user_lock_limit = sysctl_perf_event_mlock >> (PAGE_SHIFT - 10); - - /* - * Increase the limit linearly with more CPUs: - */ - user_lock_limit *= num_online_cpus(); - - user_locked = atomic_long_read(&user->locked_vm) + user_extra; - - extra = 0; - if (user_locked > user_lock_limit) - extra = user_locked - user_lock_limit; - - lock_limit = rlimit(RLIMIT_MEMLOCK); - lock_limit >>= PAGE_SHIFT; - locked = vma->vm_mm->locked_vm + extra; - - if ((locked > lock_limit) && perf_paranoid_tracepoint_raw() && - !capable(CAP_IPC_LOCK)) { - ret = -EPERM; - goto unlock; - } - - WARN_ON(event->buffer); - - if (vma->vm_flags & VM_WRITE) - flags |= PERF_BUFFER_WRITABLE; - - buffer = perf_buffer_alloc(nr_pages, event->attr.wakeup_watermark, - event->cpu, flags); - if (!buffer) { - ret = -ENOMEM; - goto unlock; - } - rcu_assign_pointer(event->buffer, buffer); - - atomic_long_add(user_extra, &user->locked_vm); - event->mmap_locked = extra; - event->mmap_user = get_current_user(); - vma->vm_mm->locked_vm += event->mmap_locked; - -unlock: - if (!ret) - atomic_inc(&event->mmap_count); - mutex_unlock(&event->mmap_mutex); - - vma->vm_flags |= VM_RESERVED; - vma->vm_ops = &perf_mmap_vmops; - - return ret; -} - -static int perf_fasync(int fd, struct file *filp, int on) -{ - struct inode *inode = filp->f_path.dentry->d_inode; - struct perf_event *event = filp->private_data; - int retval; - - mutex_lock(&inode->i_mutex); - retval = fasync_helper(fd, filp, on, &event->fasync); - mutex_unlock(&inode->i_mutex); - - if (retval < 0) - return retval; - - return 0; -} - -static const struct file_operations perf_fops = { - .llseek = no_llseek, - .release = perf_release, - .read = perf_read, - .poll = perf_poll, - .unlocked_ioctl = perf_ioctl, - .compat_ioctl = perf_ioctl, - .mmap = perf_mmap, - .fasync = perf_fasync, -}; - -/* - * Perf event wakeup - * - * If there's data, ensure we set the poll() state and publish everything - * to user-space before waking everybody up. - */ - -void perf_event_wakeup(struct perf_event *event) -{ - wake_up_all(&event->waitq); - - if (event->pending_kill) { - kill_fasync(&event->fasync, SIGIO, event->pending_kill); - event->pending_kill = 0; - } -} - -static void perf_pending_event(struct irq_work *entry) -{ - struct perf_event *event = container_of(entry, - struct perf_event, pending); - - if (event->pending_disable) { - event->pending_disable = 0; - __perf_event_disable(event); - } - - if (event->pending_wakeup) { - event->pending_wakeup = 0; - perf_event_wakeup(event); - } -} - -/* - * We assume there is only KVM supporting the callbacks. - * Later on, we might change it to a list if there is - * another virtualization implementation supporting the callbacks. - */ -struct perf_guest_info_callbacks *perf_guest_cbs; - -int perf_register_guest_info_callbacks(struct perf_guest_info_callbacks *cbs) -{ - perf_guest_cbs = cbs; - return 0; -} -EXPORT_SYMBOL_GPL(perf_register_guest_info_callbacks); - -int perf_unregister_guest_info_callbacks(struct perf_guest_info_callbacks *cbs) -{ - perf_guest_cbs = NULL; - return 0; -} -EXPORT_SYMBOL_GPL(perf_unregister_guest_info_callbacks); - -/* - * Output - */ -static bool perf_output_space(struct perf_buffer *buffer, unsigned long tail, - unsigned long offset, unsigned long head) -{ - unsigned long mask; - - if (!buffer->writable) - return true; - - mask = perf_data_size(buffer) - 1; - - offset = (offset - tail) & mask; - head = (head - tail) & mask; - - if ((int)(head - offset) < 0) - return false; - - return true; -} - -static void perf_output_wakeup(struct perf_output_handle *handle) -{ - atomic_set(&handle->buffer->poll, POLL_IN); - - if (handle->nmi) { - handle->event->pending_wakeup = 1; - irq_work_queue(&handle->event->pending); - } else - perf_event_wakeup(handle->event); -} - -/* - * We need to ensure a later event_id doesn't publish a head when a former - * event isn't done writing. However since we need to deal with NMIs we - * cannot fully serialize things. - * - * We only publish the head (and generate a wakeup) when the outer-most - * event completes. - */ -static void perf_output_get_handle(struct perf_output_handle *handle) -{ - struct perf_buffer *buffer = handle->buffer; - - preempt_disable(); - local_inc(&buffer->nest); - handle->wakeup = local_read(&buffer->wakeup); -} - -static void perf_output_put_handle(struct perf_output_handle *handle) -{ - struct perf_buffer *buffer = handle->buffer; - unsigned long head; - -again: - head = local_read(&buffer->head); - - /* - * IRQ/NMI can happen here, which means we can miss a head update. - */ - - if (!local_dec_and_test(&buffer->nest)) - goto out; - - /* - * Publish the known good head. Rely on the full barrier implied - * by atomic_dec_and_test() order the buffer->head read and this - * write. - */ - buffer->user_page->data_head = head; - - /* - * Now check if we missed an update, rely on the (compiler) - * barrier in atomic_dec_and_test() to re-read buffer->head. - */ - if (unlikely(head != local_read(&buffer->head))) { - local_inc(&buffer->nest); - goto again; - } - - if (handle->wakeup != local_read(&buffer->wakeup)) - perf_output_wakeup(handle); - -out: - preempt_enable(); -} - -__always_inline void perf_output_copy(struct perf_output_handle *handle, - const void *buf, unsigned int len) -{ - do { - unsigned long size = min_t(unsigned long, handle->size, len); - - memcpy(handle->addr, buf, size); - - len -= size; - handle->addr += size; - buf += size; - handle->size -= size; - if (!handle->size) { - struct perf_buffer *buffer = handle->buffer; - - handle->page++; - handle->page &= buffer->nr_pages - 1; - handle->addr = buffer->data_pages[handle->page]; - handle->size = PAGE_SIZE << page_order(buffer); - } - } while (len); -} - -static void __perf_event_header__init_id(struct perf_event_header *header, - struct perf_sample_data *data, - struct perf_event *event) -{ - u64 sample_type = event->attr.sample_type; - - data->type = sample_type; - header->size += event->id_header_size; - - if (sample_type & PERF_SAMPLE_TID) { - /* namespace issues */ - data->tid_entry.pid = perf_event_pid(event, current); - data->tid_entry.tid = perf_event_tid(event, current); - } - - if (sample_type & PERF_SAMPLE_TIME) - data->time = perf_clock(); - - if (sample_type & PERF_SAMPLE_ID) - data->id = primary_event_id(event); - - if (sample_type & PERF_SAMPLE_STREAM_ID) - data->stream_id = event->id; - - if (sample_type & PERF_SAMPLE_CPU) { - data->cpu_entry.cpu = raw_smp_processor_id(); - data->cpu_entry.reserved = 0; - } -} - -static void perf_event_header__init_id(struct perf_event_header *header, - struct perf_sample_data *data, - struct perf_event *event) -{ - if (event->attr.sample_id_all) - __perf_event_header__init_id(header, data, event); -} - -static void __perf_event__output_id_sample(struct perf_output_handle *handle, - struct perf_sample_data *data) -{ - u64 sample_type = data->type; - - if (sample_type & PERF_SAMPLE_TID) - perf_output_put(handle, data->tid_entry); - - if (sample_type & PERF_SAMPLE_TIME) - perf_output_put(handle, data->time); - - if (sample_type & PERF_SAMPLE_ID) - perf_output_put(handle, data->id); - - if (sample_type & PERF_SAMPLE_STREAM_ID) - perf_output_put(handle, data->stream_id); - - if (sample_type & PERF_SAMPLE_CPU) - perf_output_put(handle, data->cpu_entry); -} - -static void perf_event__output_id_sample(struct perf_event *event, - struct perf_output_handle *handle, - struct perf_sample_data *sample) -{ - if (event->attr.sample_id_all) - __perf_event__output_id_sample(handle, sample); -} - -int perf_output_begin(struct perf_output_handle *handle, - struct perf_event *event, unsigned int size, - int nmi, int sample) -{ - struct perf_buffer *buffer; - unsigned long tail, offset, head; - int have_lost; - struct perf_sample_data sample_data; - struct { - struct perf_event_header header; - u64 id; - u64 lost; - } lost_event; - - rcu_read_lock(); - /* - * For inherited events we send all the output towards the parent. - */ - if (event->parent) - event = event->parent; - - buffer = rcu_dereference(event->buffer); - if (!buffer) - goto out; - - handle->buffer = buffer; - handle->event = event; - handle->nmi = nmi; - handle->sample = sample; - - if (!buffer->nr_pages) - goto out; - - have_lost = local_read(&buffer->lost); - if (have_lost) { - lost_event.header.size = sizeof(lost_event); - perf_event_header__init_id(&lost_event.header, &sample_data, - event); - size += lost_event.header.size; - } - - perf_output_get_handle(handle); - - do { - /* - * Userspace could choose to issue a mb() before updating the - * tail pointer. So that all reads will be completed before the - * write is issued. - */ - tail = ACCESS_ONCE(buffer->user_page->data_tail); - smp_rmb(); - offset = head = local_read(&buffer->head); - head += size; - if (unlikely(!perf_output_space(buffer, tail, offset, head))) - goto fail; - } while (local_cmpxchg(&buffer->head, offset, head) != offset); - - if (head - local_read(&buffer->wakeup) > buffer->watermark) - local_add(buffer->watermark, &buffer->wakeup); - - handle->page = offset >> (PAGE_SHIFT + page_order(buffer)); - handle->page &= buffer->nr_pages - 1; - handle->size = offset & ((PAGE_SIZE << page_order(buffer)) - 1); - handle->addr = buffer->data_pages[handle->page]; - handle->addr += handle->size; - handle->size = (PAGE_SIZE << page_order(buffer)) - handle->size; - - if (have_lost) { - lost_event.header.type = PERF_RECORD_LOST; - lost_event.header.misc = 0; - lost_event.id = event->id; - lost_event.lost = local_xchg(&buffer->lost, 0); - - perf_output_put(handle, lost_event); - perf_event__output_id_sample(event, handle, &sample_data); - } - - return 0; - -fail: - local_inc(&buffer->lost); - perf_output_put_handle(handle); -out: - rcu_read_unlock(); - - return -ENOSPC; -} - -void perf_output_end(struct perf_output_handle *handle) -{ - struct perf_event *event = handle->event; - struct perf_buffer *buffer = handle->buffer; - - int wakeup_events = event->attr.wakeup_events; - - if (handle->sample && wakeup_events) { - int events = local_inc_return(&buffer->events); - if (events >= wakeup_events) { - local_sub(wakeup_events, &buffer->events); - local_inc(&buffer->wakeup); - } - } - - perf_output_put_handle(handle); - rcu_read_unlock(); -} - -static void perf_output_read_one(struct perf_output_handle *handle, - struct perf_event *event, - u64 enabled, u64 running) -{ - u64 read_format = event->attr.read_format; - u64 values[4]; - int n = 0; - - values[n++] = perf_event_count(event); - if (read_format & PERF_FORMAT_TOTAL_TIME_ENABLED) { - values[n++] = enabled + - atomic64_read(&event->child_total_time_enabled); - } - if (read_format & PERF_FORMAT_TOTAL_TIME_RUNNING) { - values[n++] = running + - atomic64_read(&event->child_total_time_running); - } - if (read_format & PERF_FORMAT_ID) - values[n++] = primary_event_id(event); - - perf_output_copy(handle, values, n * sizeof(u64)); -} - -/* - * XXX PERF_FORMAT_GROUP vs inherited events seems difficult. - */ -static void perf_output_read_group(struct perf_output_handle *handle, - struct perf_event *event, - u64 enabled, u64 running) -{ - struct perf_event *leader = event->group_leader, *sub; - u64 read_format = event->attr.read_format; - u64 values[5]; - int n = 0; - - values[n++] = 1 + leader->nr_siblings; - - if (read_format & PERF_FORMAT_TOTAL_TIME_ENABLED) - values[n++] = enabled; - - if (read_format & PERF_FORMAT_TOTAL_TIME_RUNNING) - values[n++] = running; - - if (leader != event) - leader->pmu->read(leader); - - values[n++] = perf_event_count(leader); - if (read_format & PERF_FORMAT_ID) - values[n++] = primary_event_id(leader); - - perf_output_copy(handle, values, n * sizeof(u64)); - - list_for_each_entry(sub, &leader->sibling_list, group_entry) { - n = 0; - - if (sub != event) - sub->pmu->read(sub); - - values[n++] = perf_event_count(sub); - if (read_format & PERF_FORMAT_ID) - values[n++] = primary_event_id(sub); - - perf_output_copy(handle, values, n * sizeof(u64)); - } -} - -#define PERF_FORMAT_TOTAL_TIMES (PERF_FORMAT_TOTAL_TIME_ENABLED|\ - PERF_FORMAT_TOTAL_TIME_RUNNING) - -static void perf_output_read(struct perf_output_handle *handle, - struct perf_event *event) -{ - u64 enabled = 0, running = 0, now, ctx_time; - u64 read_format = event->attr.read_format; - - /* - * compute total_time_enabled, total_time_running - * based on snapshot values taken when the event - * was last scheduled in. - * - * we cannot simply called update_context_time() - * because of locking issue as we are called in - * NMI context - */ - if (read_format & PERF_FORMAT_TOTAL_TIMES) { - now = perf_clock(); - ctx_time = event->shadow_ctx_time + now; - enabled = ctx_time - event->tstamp_enabled; - running = ctx_time - event->tstamp_running; - } - - if (event->attr.read_format & PERF_FORMAT_GROUP) - perf_output_read_group(handle, event, enabled, running); - else - perf_output_read_one(handle, event, enabled, running); -} - -void perf_output_sample(struct perf_output_handle *handle, - struct perf_event_header *header, - struct perf_sample_data *data, - struct perf_event *event) -{ - u64 sample_type = data->type; - - perf_output_put(handle, *header); - - if (sample_type & PERF_SAMPLE_IP) - perf_output_put(handle, data->ip); - - if (sample_type & PERF_SAMPLE_TID) - perf_output_put(handle, data->tid_entry); - - if (sample_type & PERF_SAMPLE_TIME) - perf_output_put(handle, data->time); - - if (sample_type & PERF_SAMPLE_ADDR) - perf_output_put(handle, data->addr); - - if (sample_type & PERF_SAMPLE_ID) - perf_output_put(handle, data->id); - - if (sample_type & PERF_SAMPLE_STREAM_ID) - perf_output_put(handle, data->stream_id); - - if (sample_type & PERF_SAMPLE_CPU) - perf_output_put(handle, data->cpu_entry); - - if (sample_type & PERF_SAMPLE_PERIOD) - perf_output_put(handle, data->period); - - if (sample_type & PERF_SAMPLE_READ) - perf_output_read(handle, event); - - if (sample_type & PERF_SAMPLE_CALLCHAIN) { - if (data->callchain) { - int size = 1; - - if (data->callchain) - size += data->callchain->nr; - - size *= sizeof(u64); - - perf_output_copy(handle, data->callchain, size); - } else { - u64 nr = 0; - perf_output_put(handle, nr); - } - } - - if (sample_type & PERF_SAMPLE_RAW) { - if (data->raw) { - perf_output_put(handle, data->raw->size); - perf_output_copy(handle, data->raw->data, - data->raw->size); - } else { - struct { - u32 size; - u32 data; - } raw = { - .size = sizeof(u32), - .data = 0, - }; - perf_output_put(handle, raw); - } - } -} - -void perf_prepare_sample(struct perf_event_header *header, - struct perf_sample_data *data, - struct perf_event *event, - struct pt_regs *regs) -{ - u64 sample_type = event->attr.sample_type; - - header->type = PERF_RECORD_SAMPLE; - header->size = sizeof(*header) + event->header_size; - - header->misc = 0; - header->misc |= perf_misc_flags(regs); - - __perf_event_header__init_id(header, data, event); - - if (sample_type & PERF_SAMPLE_IP) - data->ip = perf_instruction_pointer(regs); - - if (sample_type & PERF_SAMPLE_CALLCHAIN) { - int size = 1; - - data->callchain = perf_callchain(regs); - - if (data->callchain) - size += data->callchain->nr; - - header->size += size * sizeof(u64); - } - - if (sample_type & PERF_SAMPLE_RAW) { - int size = sizeof(u32); - - if (data->raw) - size += data->raw->size; - else - size += sizeof(u32); - - WARN_ON_ONCE(size & (sizeof(u64)-1)); - header->size += size; - } -} - -static void perf_event_output(struct perf_event *event, int nmi, - struct perf_sample_data *data, - struct pt_regs *regs) -{ - struct perf_output_handle handle; - struct perf_event_header header; - - /* protect the callchain buffers */ - rcu_read_lock(); - - perf_prepare_sample(&header, data, event, regs); - - if (perf_output_begin(&handle, event, header.size, nmi, 1)) - goto exit; - - perf_output_sample(&handle, &header, data, event); - - perf_output_end(&handle); - -exit: - rcu_read_unlock(); -} - -/* - * read event_id - */ - -struct perf_read_event { - struct perf_event_header header; - - u32 pid; - u32 tid; -}; - -static void -perf_event_read_event(struct perf_event *event, - struct task_struct *task) -{ - struct perf_output_handle handle; - struct perf_sample_data sample; - struct perf_read_event read_event = { - .header = { - .type = PERF_RECORD_READ, - .misc = 0, - .size = sizeof(read_event) + event->read_size, - }, - .pid = perf_event_pid(event, task), - .tid = perf_event_tid(event, task), - }; - int ret; - - perf_event_header__init_id(&read_event.header, &sample, event); - ret = perf_output_begin(&handle, event, read_event.header.size, 0, 0); - if (ret) - return; - - perf_output_put(&handle, read_event); - perf_output_read(&handle, event); - perf_event__output_id_sample(event, &handle, &sample); - - perf_output_end(&handle); -} - -/* - * task tracking -- fork/exit - * - * enabled by: attr.comm | attr.mmap | attr.mmap_data | attr.task - */ - -struct perf_task_event { - struct task_struct *task; - struct perf_event_context *task_ctx; - - struct { - struct perf_event_header header; - - u32 pid; - u32 ppid; - u32 tid; - u32 ptid; - u64 time; - } event_id; -}; - -static void perf_event_task_output(struct perf_event *event, - struct perf_task_event *task_event) -{ - struct perf_output_handle handle; - struct perf_sample_data sample; - struct task_struct *task = task_event->task; - int ret, size = task_event->event_id.header.size; - - perf_event_header__init_id(&task_event->event_id.header, &sample, event); - - ret = perf_output_begin(&handle, event, - task_event->event_id.header.size, 0, 0); - if (ret) - goto out; - - task_event->event_id.pid = perf_event_pid(event, task); - task_event->event_id.ppid = perf_event_pid(event, current); - - task_event->event_id.tid = perf_event_tid(event, task); - task_event->event_id.ptid = perf_event_tid(event, current); - - perf_output_put(&handle, task_event->event_id); - - perf_event__output_id_sample(event, &handle, &sample); - - perf_output_end(&handle); -out: - task_event->event_id.header.size = size; -} - -static int perf_event_task_match(struct perf_event *event) -{ - if (event->state < PERF_EVENT_STATE_INACTIVE) - return 0; - - if (!event_filter_match(event)) - return 0; - - if (event->attr.comm || event->attr.mmap || - event->attr.mmap_data || event->attr.task) - return 1; - - return 0; -} - -static void perf_event_task_ctx(struct perf_event_context *ctx, - struct perf_task_event *task_event) -{ - struct perf_event *event; - - list_for_each_entry_rcu(event, &ctx->event_list, event_entry) { - if (perf_event_task_match(event)) - perf_event_task_output(event, task_event); - } -} - -static void perf_event_task_event(struct perf_task_event *task_event) -{ - struct perf_cpu_context *cpuctx; - struct perf_event_context *ctx; - struct pmu *pmu; - int ctxn; - - rcu_read_lock(); - list_for_each_entry_rcu(pmu, &pmus, entry) { - cpuctx = get_cpu_ptr(pmu->pmu_cpu_context); - if (cpuctx->active_pmu != pmu) - goto next; - perf_event_task_ctx(&cpuctx->ctx, task_event); - - ctx = task_event->task_ctx; - if (!ctx) { - ctxn = pmu->task_ctx_nr; - if (ctxn < 0) - goto next; - ctx = rcu_dereference(current->perf_event_ctxp[ctxn]); - } - if (ctx) - perf_event_task_ctx(ctx, task_event); -next: - put_cpu_ptr(pmu->pmu_cpu_context); - } - rcu_read_unlock(); -} - -static void perf_event_task(struct task_struct *task, - struct perf_event_context *task_ctx, - int new) -{ - struct perf_task_event task_event; - - if (!atomic_read(&nr_comm_events) && - !atomic_read(&nr_mmap_events) && - !atomic_read(&nr_task_events)) - return; - - task_event = (struct perf_task_event){ - .task = task, - .task_ctx = task_ctx, - .event_id = { - .header = { - .type = new ? PERF_RECORD_FORK : PERF_RECORD_EXIT, - .misc = 0, - .size = sizeof(task_event.event_id), - }, - /* .pid */ - /* .ppid */ - /* .tid */ - /* .ptid */ - .time = perf_clock(), - }, - }; - - perf_event_task_event(&task_event); -} - -void perf_event_fork(struct task_struct *task) -{ - perf_event_task(task, NULL, 1); -} - -/* - * comm tracking - */ - -struct perf_comm_event { - struct task_struct *task; - char *comm; - int comm_size; - - struct { - struct perf_event_header header; - - u32 pid; - u32 tid; - } event_id; -}; - -static void perf_event_comm_output(struct perf_event *event, - struct perf_comm_event *comm_event) -{ - struct perf_output_handle handle; - struct perf_sample_data sample; - int size = comm_event->event_id.header.size; - int ret; - - perf_event_header__init_id(&comm_event->event_id.header, &sample, event); - ret = perf_output_begin(&handle, event, - comm_event->event_id.header.size, 0, 0); - - if (ret) - goto out; - - comm_event->event_id.pid = perf_event_pid(event, comm_event->task); - comm_event->event_id.tid = perf_event_tid(event, comm_event->task); - - perf_output_put(&handle, comm_event->event_id); - perf_output_copy(&handle, comm_event->comm, - comm_event->comm_size); - - perf_event__output_id_sample(event, &handle, &sample); - - perf_output_end(&handle); -out: - comm_event->event_id.header.size = size; -} - -static int perf_event_comm_match(struct perf_event *event) -{ - if (event->state < PERF_EVENT_STATE_INACTIVE) - return 0; - - if (!event_filter_match(event)) - return 0; - - if (event->attr.comm) - return 1; - - return 0; -} - -static void perf_event_comm_ctx(struct perf_event_context *ctx, - struct perf_comm_event *comm_event) -{ - struct perf_event *event; - - list_for_each_entry_rcu(event, &ctx->event_list, event_entry) { - if (perf_event_comm_match(event)) - perf_event_comm_output(event, comm_event); - } -} - -static void perf_event_comm_event(struct perf_comm_event *comm_event) -{ - struct perf_cpu_context *cpuctx; - struct perf_event_context *ctx; - char comm[TASK_COMM_LEN]; - unsigned int size; - struct pmu *pmu; - int ctxn; - - memset(comm, 0, sizeof(comm)); - strlcpy(comm, comm_event->task->comm, sizeof(comm)); - size = ALIGN(strlen(comm)+1, sizeof(u64)); - - comm_event->comm = comm; - comm_event->comm_size = size; - - comm_event->event_id.header.size = sizeof(comm_event->event_id) + size; - rcu_read_lock(); - list_for_each_entry_rcu(pmu, &pmus, entry) { - cpuctx = get_cpu_ptr(pmu->pmu_cpu_context); - if (cpuctx->active_pmu != pmu) - goto next; - perf_event_comm_ctx(&cpuctx->ctx, comm_event); - - ctxn = pmu->task_ctx_nr; - if (ctxn < 0) - goto next; - - ctx = rcu_dereference(current->perf_event_ctxp[ctxn]); - if (ctx) - perf_event_comm_ctx(ctx, comm_event); -next: - put_cpu_ptr(pmu->pmu_cpu_context); - } - rcu_read_unlock(); -} - -void perf_event_comm(struct task_struct *task) -{ - struct perf_comm_event comm_event; - struct perf_event_context *ctx; - int ctxn; - - for_each_task_context_nr(ctxn) { - ctx = task->perf_event_ctxp[ctxn]; - if (!ctx) - continue; - - perf_event_enable_on_exec(ctx); - } - - if (!atomic_read(&nr_comm_events)) - return; - - comm_event = (struct perf_comm_event){ - .task = task, - /* .comm */ - /* .comm_size */ - .event_id = { - .header = { - .type = PERF_RECORD_COMM, - .misc = 0, - /* .size */ - }, - /* .pid */ - /* .tid */ - }, - }; - - perf_event_comm_event(&comm_event); -} - -/* - * mmap tracking - */ - -struct perf_mmap_event { - struct vm_area_struct *vma; - - const char *file_name; - int file_size; - - struct { - struct perf_event_header header; - - u32 pid; - u32 tid; - u64 start; - u64 len; - u64 pgoff; - } event_id; -}; - -static void perf_event_mmap_output(struct perf_event *event, - struct perf_mmap_event *mmap_event) -{ - struct perf_output_handle handle; - struct perf_sample_data sample; - int size = mmap_event->event_id.header.size; - int ret; - - perf_event_header__init_id(&mmap_event->event_id.header, &sample, event); - ret = perf_output_begin(&handle, event, - mmap_event->event_id.header.size, 0, 0); - if (ret) - goto out; - - mmap_event->event_id.pid = perf_event_pid(event, current); - mmap_event->event_id.tid = perf_event_tid(event, current); - - perf_output_put(&handle, mmap_event->event_id); - perf_output_copy(&handle, mmap_event->file_name, - mmap_event->file_size); - - perf_event__output_id_sample(event, &handle, &sample); - - perf_output_end(&handle); -out: - mmap_event->event_id.header.size = size; -} - -static int perf_event_mmap_match(struct perf_event *event, - struct perf_mmap_event *mmap_event, - int executable) -{ - if (event->state < PERF_EVENT_STATE_INACTIVE) - return 0; - - if (!event_filter_match(event)) - return 0; - - if ((!executable && event->attr.mmap_data) || - (executable && event->attr.mmap)) - return 1; - - return 0; -} - -static void perf_event_mmap_ctx(struct perf_event_context *ctx, - struct perf_mmap_event *mmap_event, - int executable) -{ - struct perf_event *event; - - list_for_each_entry_rcu(event, &ctx->event_list, event_entry) { - if (perf_event_mmap_match(event, mmap_event, executable)) - perf_event_mmap_output(event, mmap_event); - } -} - -static void perf_event_mmap_event(struct perf_mmap_event *mmap_event) -{ - struct perf_cpu_context *cpuctx; - struct perf_event_context *ctx; - struct vm_area_struct *vma = mmap_event->vma; - struct file *file = vma->vm_file; - unsigned int size; - char tmp[16]; - char *buf = NULL; - const char *name; - struct pmu *pmu; - int ctxn; - - memset(tmp, 0, sizeof(tmp)); - - if (file) { - /* - * d_path works from the end of the buffer backwards, so we - * need to add enough zero bytes after the string to handle - * the 64bit alignment we do later. - */ - buf = kzalloc(PATH_MAX + sizeof(u64), GFP_KERNEL); - if (!buf) { - name = strncpy(tmp, "//enomem", sizeof(tmp)); - goto got_name; - } - name = d_path(&file->f_path, buf, PATH_MAX); - if (IS_ERR(name)) { - name = strncpy(tmp, "//toolong", sizeof(tmp)); - goto got_name; - } - } else { - if (arch_vma_name(mmap_event->vma)) { - name = strncpy(tmp, arch_vma_name(mmap_event->vma), - sizeof(tmp)); - goto got_name; - } - - if (!vma->vm_mm) { - name = strncpy(tmp, "[vdso]", sizeof(tmp)); - goto got_name; - } else if (vma->vm_start <= vma->vm_mm->start_brk && - vma->vm_end >= vma->vm_mm->brk) { - name = strncpy(tmp, "[heap]", sizeof(tmp)); - goto got_name; - } else if (vma->vm_start <= vma->vm_mm->start_stack && - vma->vm_end >= vma->vm_mm->start_stack) { - name = strncpy(tmp, "[stack]", sizeof(tmp)); - goto got_name; - } - - name = strncpy(tmp, "//anon", sizeof(tmp)); - goto got_name; - } - -got_name: - size = ALIGN(strlen(name)+1, sizeof(u64)); - - mmap_event->file_name = name; - mmap_event->file_size = size; - - mmap_event->event_id.header.size = sizeof(mmap_event->event_id) + size; - - rcu_read_lock(); - list_for_each_entry_rcu(pmu, &pmus, entry) { - cpuctx = get_cpu_ptr(pmu->pmu_cpu_context); - if (cpuctx->active_pmu != pmu) - goto next; - perf_event_mmap_ctx(&cpuctx->ctx, mmap_event, - vma->vm_flags & VM_EXEC); - - ctxn = pmu->task_ctx_nr; - if (ctxn < 0) - goto next; - - ctx = rcu_dereference(current->perf_event_ctxp[ctxn]); - if (ctx) { - perf_event_mmap_ctx(ctx, mmap_event, - vma->vm_flags & VM_EXEC); - } -next: - put_cpu_ptr(pmu->pmu_cpu_context); - } - rcu_read_unlock(); - - kfree(buf); -} - -void perf_event_mmap(struct vm_area_struct *vma) -{ - struct perf_mmap_event mmap_event; - - if (!atomic_read(&nr_mmap_events)) - return; - - mmap_event = (struct perf_mmap_event){ - .vma = vma, - /* .file_name */ - /* .file_size */ - .event_id = { - .header = { - .type = PERF_RECORD_MMAP, - .misc = PERF_RECORD_MISC_USER, - /* .size */ - }, - /* .pid */ - /* .tid */ - .start = vma->vm_start, - .len = vma->vm_end - vma->vm_start, - .pgoff = (u64)vma->vm_pgoff << PAGE_SHIFT, - }, - }; - - perf_event_mmap_event(&mmap_event); -} - -/* - * IRQ throttle logging - */ - -static void perf_log_throttle(struct perf_event *event, int enable) -{ - struct perf_output_handle handle; - struct perf_sample_data sample; - int ret; - - struct { - struct perf_event_header header; - u64 time; - u64 id; - u64 stream_id; - } throttle_event = { - .header = { - .type = PERF_RECORD_THROTTLE, - .misc = 0, - .size = sizeof(throttle_event), - }, - .time = perf_clock(), - .id = primary_event_id(event), - .stream_id = event->id, - }; - - if (enable) - throttle_event.header.type = PERF_RECORD_UNTHROTTLE; - - perf_event_header__init_id(&throttle_event.header, &sample, event); - - ret = perf_output_begin(&handle, event, - throttle_event.header.size, 1, 0); - if (ret) - return; - - perf_output_put(&handle, throttle_event); - perf_event__output_id_sample(event, &handle, &sample); - perf_output_end(&handle); -} - -/* - * Generic event overflow handling, sampling. - */ - -static int __perf_event_overflow(struct perf_event *event, int nmi, - int throttle, struct perf_sample_data *data, - struct pt_regs *regs) -{ - int events = atomic_read(&event->event_limit); - struct hw_perf_event *hwc = &event->hw; - int ret = 0; - - /* - * Non-sampling counters might still use the PMI to fold short - * hardware counters, ignore those. - */ - if (unlikely(!is_sampling_event(event))) - return 0; - - if (unlikely(hwc->interrupts >= max_samples_per_tick)) { - if (throttle) { - hwc->interrupts = MAX_INTERRUPTS; - perf_log_throttle(event, 0); - ret = 1; - } - } else - hwc->interrupts++; - - if (event->attr.freq) { - u64 now = perf_clock(); - s64 delta = now - hwc->freq_time_stamp; - - hwc->freq_time_stamp = now; - - if (delta > 0 && delta < 2*TICK_NSEC) - perf_adjust_period(event, delta, hwc->last_period); - } - - /* - * XXX event_limit might not quite work as expected on inherited - * events - */ - - event->pending_kill = POLL_IN; - if (events && atomic_dec_and_test(&event->event_limit)) { - ret = 1; - event->pending_kill = POLL_HUP; - if (nmi) { - event->pending_disable = 1; - irq_work_queue(&event->pending); - } else - perf_event_disable(event); - } - - if (event->overflow_handler) - event->overflow_handler(event, nmi, data, regs); - else - perf_event_output(event, nmi, data, regs); - - return ret; -} - -int perf_event_overflow(struct perf_event *event, int nmi, - struct perf_sample_data *data, - struct pt_regs *regs) -{ - return __perf_event_overflow(event, nmi, 1, data, regs); -} - -/* - * Generic software event infrastructure - */ - -struct swevent_htable { - struct swevent_hlist *swevent_hlist; - struct mutex hlist_mutex; - int hlist_refcount; - - /* Recursion avoidance in each contexts */ - int recursion[PERF_NR_CONTEXTS]; -}; - -static DEFINE_PER_CPU(struct swevent_htable, swevent_htable); - -/* - * We directly increment event->count and keep a second value in - * event->hw.period_left to count intervals. This period event - * is kept in the range [-sample_period, 0] so that we can use the - * sign as trigger. - */ - -static u64 perf_swevent_set_period(struct perf_event *event) -{ - struct hw_perf_event *hwc = &event->hw; - u64 period = hwc->last_period; - u64 nr, offset; - s64 old, val; - - hwc->last_period = hwc->sample_period; - -again: - old = val = local64_read(&hwc->period_left); - if (val < 0) - return 0; - - nr = div64_u64(period + val, period); - offset = nr * period; - val -= offset; - if (local64_cmpxchg(&hwc->period_left, old, val) != old) - goto again; - - return nr; -} - -static void perf_swevent_overflow(struct perf_event *event, u64 overflow, - int nmi, struct perf_sample_data *data, - struct pt_regs *regs) -{ - struct hw_perf_event *hwc = &event->hw; - int throttle = 0; - - data->period = event->hw.last_period; - if (!overflow) - overflow = perf_swevent_set_period(event); - - if (hwc->interrupts == MAX_INTERRUPTS) - return; - - for (; overflow; overflow--) { - if (__perf_event_overflow(event, nmi, throttle, - data, regs)) { - /* - * We inhibit the overflow from happening when - * hwc->interrupts == MAX_INTERRUPTS. - */ - break; - } - throttle = 1; - } -} - -static void perf_swevent_event(struct perf_event *event, u64 nr, - int nmi, struct perf_sample_data *data, - struct pt_regs *regs) -{ - struct hw_perf_event *hwc = &event->hw; - - local64_add(nr, &event->count); - - if (!regs) - return; - - if (!is_sampling_event(event)) - return; - - if (nr == 1 && hwc->sample_period == 1 && !event->attr.freq) - return perf_swevent_overflow(event, 1, nmi, data, regs); - - if (local64_add_negative(nr, &hwc->period_left)) - return; - - perf_swevent_overflow(event, 0, nmi, data, regs); -} - -static int perf_exclude_event(struct perf_event *event, - struct pt_regs *regs) -{ - if (event->hw.state & PERF_HES_STOPPED) - return 1; - - if (regs) { - if (event->attr.exclude_user && user_mode(regs)) - return 1; - - if (event->attr.exclude_kernel && !user_mode(regs)) - return 1; - } - - return 0; -} - -static int perf_swevent_match(struct perf_event *event, - enum perf_type_id type, - u32 event_id, - struct perf_sample_data *data, - struct pt_regs *regs) -{ - if (event->attr.type != type) - return 0; - - if (event->attr.config != event_id) - return 0; - - if (perf_exclude_event(event, regs)) - return 0; - - return 1; -} - -static inline u64 swevent_hash(u64 type, u32 event_id) -{ - u64 val = event_id | (type << 32); - - return hash_64(val, SWEVENT_HLIST_BITS); -} - -static inline struct hlist_head * -__find_swevent_head(struct swevent_hlist *hlist, u64 type, u32 event_id) -{ - u64 hash = swevent_hash(type, event_id); - - return &hlist->heads[hash]; -} - -/* For the read side: events when they trigger */ -static inline struct hlist_head * -find_swevent_head_rcu(struct swevent_htable *swhash, u64 type, u32 event_id) -{ - struct swevent_hlist *hlist; - - hlist = rcu_dereference(swhash->swevent_hlist); - if (!hlist) - return NULL; - - return __find_swevent_head(hlist, type, event_id); -} - -/* For the event head insertion and removal in the hlist */ -static inline struct hlist_head * -find_swevent_head(struct swevent_htable *swhash, struct perf_event *event) -{ - struct swevent_hlist *hlist; - u32 event_id = event->attr.config; - u64 type = event->attr.type; - - /* - * Event scheduling is always serialized against hlist allocation - * and release. Which makes the protected version suitable here. - * The context lock guarantees that. - */ - hlist = rcu_dereference_protected(swhash->swevent_hlist, - lockdep_is_held(&event->ctx->lock)); - if (!hlist) - return NULL; - - return __find_swevent_head(hlist, type, event_id); -} - -static void do_perf_sw_event(enum perf_type_id type, u32 event_id, - u64 nr, int nmi, - struct perf_sample_data *data, - struct pt_regs *regs) -{ - struct swevent_htable *swhash = &__get_cpu_var(swevent_htable); - struct perf_event *event; - struct hlist_node *node; - struct hlist_head *head; - - rcu_read_lock(); - head = find_swevent_head_rcu(swhash, type, event_id); - if (!head) - goto end; - - hlist_for_each_entry_rcu(event, node, head, hlist_entry) { - if (perf_swevent_match(event, type, event_id, data, regs)) - perf_swevent_event(event, nr, nmi, data, regs); - } -end: - rcu_read_unlock(); -} - -int perf_swevent_get_recursion_context(void) -{ - struct swevent_htable *swhash = &__get_cpu_var(swevent_htable); - - return get_recursion_context(swhash->recursion); -} -EXPORT_SYMBOL_GPL(perf_swevent_get_recursion_context); - -inline void perf_swevent_put_recursion_context(int rctx) -{ - struct swevent_htable *swhash = &__get_cpu_var(swevent_htable); - - put_recursion_context(swhash->recursion, rctx); -} - -void __perf_sw_event(u32 event_id, u64 nr, int nmi, - struct pt_regs *regs, u64 addr) -{ - struct perf_sample_data data; - int rctx; - - preempt_disable_notrace(); - rctx = perf_swevent_get_recursion_context(); - if (rctx < 0) - return; - - perf_sample_data_init(&data, addr); - - do_perf_sw_event(PERF_TYPE_SOFTWARE, event_id, nr, nmi, &data, regs); - - perf_swevent_put_recursion_context(rctx); - preempt_enable_notrace(); -} - -static void perf_swevent_read(struct perf_event *event) -{ -} - -static int perf_swevent_add(struct perf_event *event, int flags) -{ - struct swevent_htable *swhash = &__get_cpu_var(swevent_htable); - struct hw_perf_event *hwc = &event->hw; - struct hlist_head *head; - - if (is_sampling_event(event)) { - hwc->last_period = hwc->sample_period; - perf_swevent_set_period(event); - } - - hwc->state = !(flags & PERF_EF_START); - - head = find_swevent_head(swhash, event); - if (WARN_ON_ONCE(!head)) - return -EINVAL; - - hlist_add_head_rcu(&event->hlist_entry, head); - - return 0; -} - -static void perf_swevent_del(struct perf_event *event, int flags) -{ - hlist_del_rcu(&event->hlist_entry); -} - -static void perf_swevent_start(struct perf_event *event, int flags) -{ - event->hw.state = 0; -} - -static void perf_swevent_stop(struct perf_event *event, int flags) -{ - event->hw.state = PERF_HES_STOPPED; -} - -/* Deref the hlist from the update side */ -static inline struct swevent_hlist * -swevent_hlist_deref(struct swevent_htable *swhash) -{ - return rcu_dereference_protected(swhash->swevent_hlist, - lockdep_is_held(&swhash->hlist_mutex)); -} - -static void swevent_hlist_release_rcu(struct rcu_head *rcu_head) -{ - struct swevent_hlist *hlist; - - hlist = container_of(rcu_head, struct swevent_hlist, rcu_head); - kfree(hlist); -} - -static void swevent_hlist_release(struct swevent_htable *swhash) -{ - struct swevent_hlist *hlist = swevent_hlist_deref(swhash); - - if (!hlist) - return; - - rcu_assign_pointer(swhash->swevent_hlist, NULL); - call_rcu(&hlist->rcu_head, swevent_hlist_release_rcu); -} - -static void swevent_hlist_put_cpu(struct perf_event *event, int cpu) -{ - struct swevent_htable *swhash = &per_cpu(swevent_htable, cpu); - - mutex_lock(&swhash->hlist_mutex); - - if (!--swhash->hlist_refcount) - swevent_hlist_release(swhash); - - mutex_unlock(&swhash->hlist_mutex); -} - -static void swevent_hlist_put(struct perf_event *event) -{ - int cpu; - - if (event->cpu != -1) { - swevent_hlist_put_cpu(event, event->cpu); - return; - } - - for_each_possible_cpu(cpu) - swevent_hlist_put_cpu(event, cpu); -} - -static int swevent_hlist_get_cpu(struct perf_event *event, int cpu) -{ - struct swevent_htable *swhash = &per_cpu(swevent_htable, cpu); - int err = 0; - - mutex_lock(&swhash->hlist_mutex); - - if (!swevent_hlist_deref(swhash) && cpu_online(cpu)) { - struct swevent_hlist *hlist; - - hlist = kzalloc(sizeof(*hlist), GFP_KERNEL); - if (!hlist) { - err = -ENOMEM; - goto exit; - } - rcu_assign_pointer(swhash->swevent_hlist, hlist); - } - swhash->hlist_refcount++; -exit: - mutex_unlock(&swhash->hlist_mutex); - - return err; -} - -static int swevent_hlist_get(struct perf_event *event) -{ - int err; - int cpu, failed_cpu; - - if (event->cpu != -1) - return swevent_hlist_get_cpu(event, event->cpu); - - get_online_cpus(); - for_each_possible_cpu(cpu) { - err = swevent_hlist_get_cpu(event, cpu); - if (err) { - failed_cpu = cpu; - goto fail; - } - } - put_online_cpus(); - - return 0; -fail: - for_each_possible_cpu(cpu) { - if (cpu == failed_cpu) - break; - swevent_hlist_put_cpu(event, cpu); - } - - put_online_cpus(); - return err; -} - -struct jump_label_key perf_swevent_enabled[PERF_COUNT_SW_MAX]; - -static void sw_perf_event_destroy(struct perf_event *event) -{ - u64 event_id = event->attr.config; - - WARN_ON(event->parent); - - jump_label_dec(&perf_swevent_enabled[event_id]); - swevent_hlist_put(event); -} - -static int perf_swevent_init(struct perf_event *event) -{ - int event_id = event->attr.config; - - if (event->attr.type != PERF_TYPE_SOFTWARE) - return -ENOENT; - - switch (event_id) { - case PERF_COUNT_SW_CPU_CLOCK: - case PERF_COUNT_SW_TASK_CLOCK: - return -ENOENT; - - default: - break; - } - - if (event_id >= PERF_COUNT_SW_MAX) - return -ENOENT; - - if (!event->parent) { - int err; - - err = swevent_hlist_get(event); - if (err) - return err; - - jump_label_inc(&perf_swevent_enabled[event_id]); - event->destroy = sw_perf_event_destroy; - } - - return 0; -} - -static struct pmu perf_swevent = { - .task_ctx_nr = perf_sw_context, - - .event_init = perf_swevent_init, - .add = perf_swevent_add, - .del = perf_swevent_del, - .start = perf_swevent_start, - .stop = perf_swevent_stop, - .read = perf_swevent_read, -}; - -#ifdef CONFIG_EVENT_TRACING - -static int perf_tp_filter_match(struct perf_event *event, - struct perf_sample_data *data) -{ - void *record = data->raw->data; - - if (likely(!event->filter) || filter_match_preds(event->filter, record)) - return 1; - return 0; -} - -static int perf_tp_event_match(struct perf_event *event, - struct perf_sample_data *data, - struct pt_regs *regs) -{ - if (event->hw.state & PERF_HES_STOPPED) - return 0; - /* - * All tracepoints are from kernel-space. - */ - if (event->attr.exclude_kernel) - return 0; - - if (!perf_tp_filter_match(event, data)) - return 0; - - return 1; -} - -void perf_tp_event(u64 addr, u64 count, void *record, int entry_size, - struct pt_regs *regs, struct hlist_head *head, int rctx) -{ - struct perf_sample_data data; - struct perf_event *event; - struct hlist_node *node; - - struct perf_raw_record raw = { - .size = entry_size, - .data = record, - }; - - perf_sample_data_init(&data, addr); - data.raw = &raw; - - hlist_for_each_entry_rcu(event, node, head, hlist_entry) { - if (perf_tp_event_match(event, &data, regs)) - perf_swevent_event(event, count, 1, &data, regs); - } - - perf_swevent_put_recursion_context(rctx); -} -EXPORT_SYMBOL_GPL(perf_tp_event); - -static void tp_perf_event_destroy(struct perf_event *event) -{ - perf_trace_destroy(event); -} - -static int perf_tp_event_init(struct perf_event *event) -{ - int err; - - if (event->attr.type != PERF_TYPE_TRACEPOINT) - return -ENOENT; - - err = perf_trace_init(event); - if (err) - return err; - - event->destroy = tp_perf_event_destroy; - - return 0; -} - -static struct pmu perf_tracepoint = { - .task_ctx_nr = perf_sw_context, - - .event_init = perf_tp_event_init, - .add = perf_trace_add, - .del = perf_trace_del, - .start = perf_swevent_start, - .stop = perf_swevent_stop, - .read = perf_swevent_read, -}; - -static inline void perf_tp_register(void) -{ - perf_pmu_register(&perf_tracepoint, "tracepoint", PERF_TYPE_TRACEPOINT); -} - -static int perf_event_set_filter(struct perf_event *event, void __user *arg) -{ - char *filter_str; - int ret; - - if (event->attr.type != PERF_TYPE_TRACEPOINT) - return -EINVAL; - - filter_str = strndup_user(arg, PAGE_SIZE); - if (IS_ERR(filter_str)) - return PTR_ERR(filter_str); - - ret = ftrace_profile_set_filter(event, event->attr.config, filter_str); - - kfree(filter_str); - return ret; -} - -static void perf_event_free_filter(struct perf_event *event) -{ - ftrace_profile_free_filter(event); -} - -#else - -static inline void perf_tp_register(void) -{ -} - -static int perf_event_set_filter(struct perf_event *event, void __user *arg) -{ - return -ENOENT; -} - -static void perf_event_free_filter(struct perf_event *event) -{ -} - -#endif /* CONFIG_EVENT_TRACING */ - -#ifdef CONFIG_HAVE_HW_BREAKPOINT -void perf_bp_event(struct perf_event *bp, void *data) -{ - struct perf_sample_data sample; - struct pt_regs *regs = data; - - perf_sample_data_init(&sample, bp->attr.bp_addr); - - if (!bp->hw.state && !perf_exclude_event(bp, regs)) - perf_swevent_event(bp, 1, 1, &sample, regs); -} -#endif - -/* - * hrtimer based swevent callback - */ - -static enum hrtimer_restart perf_swevent_hrtimer(struct hrtimer *hrtimer) -{ - enum hrtimer_restart ret = HRTIMER_RESTART; - struct perf_sample_data data; - struct pt_regs *regs; - struct perf_event *event; - u64 period; - - event = container_of(hrtimer, struct perf_event, hw.hrtimer); - - if (event->state != PERF_EVENT_STATE_ACTIVE) - return HRTIMER_NORESTART; - - event->pmu->read(event); - - perf_sample_data_init(&data, 0); - data.period = event->hw.last_period; - regs = get_irq_regs(); - - if (regs && !perf_exclude_event(event, regs)) { - if (!(event->attr.exclude_idle && current->pid == 0)) - if (perf_event_overflow(event, 0, &data, regs)) - ret = HRTIMER_NORESTART; - } - - period = max_t(u64, 10000, event->hw.sample_period); - hrtimer_forward_now(hrtimer, ns_to_ktime(period)); - - return ret; -} - -static void perf_swevent_start_hrtimer(struct perf_event *event) -{ - struct hw_perf_event *hwc = &event->hw; - s64 period; - - if (!is_sampling_event(event)) - return; - - period = local64_read(&hwc->period_left); - if (period) { - if (period < 0) - period = 10000; - - local64_set(&hwc->period_left, 0); - } else { - period = max_t(u64, 10000, hwc->sample_period); - } - __hrtimer_start_range_ns(&hwc->hrtimer, - ns_to_ktime(period), 0, - HRTIMER_MODE_REL_PINNED, 0); -} - -static void perf_swevent_cancel_hrtimer(struct perf_event *event) -{ - struct hw_perf_event *hwc = &event->hw; - - if (is_sampling_event(event)) { - ktime_t remaining = hrtimer_get_remaining(&hwc->hrtimer); - local64_set(&hwc->period_left, ktime_to_ns(remaining)); - - hrtimer_cancel(&hwc->hrtimer); - } -} - -static void perf_swevent_init_hrtimer(struct perf_event *event) -{ - struct hw_perf_event *hwc = &event->hw; - - if (!is_sampling_event(event)) - return; - - hrtimer_init(&hwc->hrtimer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); - hwc->hrtimer.function = perf_swevent_hrtimer; - - /* - * Since hrtimers have a fixed rate, we can do a static freq->period - * mapping and avoid the whole period adjust feedback stuff. - */ - if (event->attr.freq) { - long freq = event->attr.sample_freq; - - event->attr.sample_period = NSEC_PER_SEC / freq; - hwc->sample_period = event->attr.sample_period; - local64_set(&hwc->period_left, hwc->sample_period); - event->attr.freq = 0; - } -} - -/* - * Software event: cpu wall time clock - */ - -static void cpu_clock_event_update(struct perf_event *event) -{ - s64 prev; - u64 now; - - now = local_clock(); - prev = local64_xchg(&event->hw.prev_count, now); - local64_add(now - prev, &event->count); -} - -static void cpu_clock_event_start(struct perf_event *event, int flags) -{ - local64_set(&event->hw.prev_count, local_clock()); - perf_swevent_start_hrtimer(event); -} - -static void cpu_clock_event_stop(struct perf_event *event, int flags) -{ - perf_swevent_cancel_hrtimer(event); - cpu_clock_event_update(event); -} - -static int cpu_clock_event_add(struct perf_event *event, int flags) -{ - if (flags & PERF_EF_START) - cpu_clock_event_start(event, flags); - - return 0; -} - -static void cpu_clock_event_del(struct perf_event *event, int flags) -{ - cpu_clock_event_stop(event, flags); -} - -static void cpu_clock_event_read(struct perf_event *event) -{ - cpu_clock_event_update(event); -} - -static int cpu_clock_event_init(struct perf_event *event) -{ - if (event->attr.type != PERF_TYPE_SOFTWARE) - return -ENOENT; - - if (event->attr.config != PERF_COUNT_SW_CPU_CLOCK) - return -ENOENT; - - perf_swevent_init_hrtimer(event); - - return 0; -} - -static struct pmu perf_cpu_clock = { - .task_ctx_nr = perf_sw_context, - - .event_init = cpu_clock_event_init, - .add = cpu_clock_event_add, - .del = cpu_clock_event_del, - .start = cpu_clock_event_start, - .stop = cpu_clock_event_stop, - .read = cpu_clock_event_read, -}; - -/* - * Software event: task time clock - */ - -static void task_clock_event_update(struct perf_event *event, u64 now) -{ - u64 prev; - s64 delta; - - prev = local64_xchg(&event->hw.prev_count, now); - delta = now - prev; - local64_add(delta, &event->count); -} - -static void task_clock_event_start(struct perf_event *event, int flags) -{ - local64_set(&event->hw.prev_count, event->ctx->time); - perf_swevent_start_hrtimer(event); -} - -static void task_clock_event_stop(struct perf_event *event, int flags) -{ - perf_swevent_cancel_hrtimer(event); - task_clock_event_update(event, event->ctx->time); -} - -static int task_clock_event_add(struct perf_event *event, int flags) -{ - if (flags & PERF_EF_START) - task_clock_event_start(event, flags); - - return 0; -} - -static void task_clock_event_del(struct perf_event *event, int flags) -{ - task_clock_event_stop(event, PERF_EF_UPDATE); -} - -static void task_clock_event_read(struct perf_event *event) -{ - u64 now = perf_clock(); - u64 delta = now - event->ctx->timestamp; - u64 time = event->ctx->time + delta; - - task_clock_event_update(event, time); -} - -static int task_clock_event_init(struct perf_event *event) -{ - if (event->attr.type != PERF_TYPE_SOFTWARE) - return -ENOENT; - - if (event->attr.config != PERF_COUNT_SW_TASK_CLOCK) - return -ENOENT; - - perf_swevent_init_hrtimer(event); - - return 0; -} - -static struct pmu perf_task_clock = { - .task_ctx_nr = perf_sw_context, - - .event_init = task_clock_event_init, - .add = task_clock_event_add, - .del = task_clock_event_del, - .start = task_clock_event_start, - .stop = task_clock_event_stop, - .read = task_clock_event_read, -}; - -static void perf_pmu_nop_void(struct pmu *pmu) -{ -} - -static int perf_pmu_nop_int(struct pmu *pmu) -{ - return 0; -} - -static void perf_pmu_start_txn(struct pmu *pmu) -{ - perf_pmu_disable(pmu); -} - -static int perf_pmu_commit_txn(struct pmu *pmu) -{ - perf_pmu_enable(pmu); - return 0; -} - -static void perf_pmu_cancel_txn(struct pmu *pmu) -{ - perf_pmu_enable(pmu); -} - -/* - * Ensures all contexts with the same task_ctx_nr have the same - * pmu_cpu_context too. - */ -static void *find_pmu_context(int ctxn) -{ - struct pmu *pmu; - - if (ctxn < 0) - return NULL; - - list_for_each_entry(pmu, &pmus, entry) { - if (pmu->task_ctx_nr == ctxn) - return pmu->pmu_cpu_context; - } - - return NULL; -} - -static void update_pmu_context(struct pmu *pmu, struct pmu *old_pmu) -{ - int cpu; - - for_each_possible_cpu(cpu) { - struct perf_cpu_context *cpuctx; - - cpuctx = per_cpu_ptr(pmu->pmu_cpu_context, cpu); - - if (cpuctx->active_pmu == old_pmu) - cpuctx->active_pmu = pmu; - } -} - -static void free_pmu_context(struct pmu *pmu) -{ - struct pmu *i; - - mutex_lock(&pmus_lock); - /* - * Like a real lame refcount. - */ - list_for_each_entry(i, &pmus, entry) { - if (i->pmu_cpu_context == pmu->pmu_cpu_context) { - update_pmu_context(i, pmu); - goto out; - } - } - - free_percpu(pmu->pmu_cpu_context); -out: - mutex_unlock(&pmus_lock); -} -static struct idr pmu_idr; - -static ssize_t -type_show(struct device *dev, struct device_attribute *attr, char *page) -{ - struct pmu *pmu = dev_get_drvdata(dev); - - return snprintf(page, PAGE_SIZE-1, "%d\n", pmu->type); -} - -static struct device_attribute pmu_dev_attrs[] = { - __ATTR_RO(type), - __ATTR_NULL, -}; - -static int pmu_bus_running; -static struct bus_type pmu_bus = { - .name = "event_source", - .dev_attrs = pmu_dev_attrs, -}; - -static void pmu_dev_release(struct device *dev) -{ - kfree(dev); -} - -static int pmu_dev_alloc(struct pmu *pmu) -{ - int ret = -ENOMEM; - - pmu->dev = kzalloc(sizeof(struct device), GFP_KERNEL); - if (!pmu->dev) - goto out; - - device_initialize(pmu->dev); - ret = dev_set_name(pmu->dev, "%s", pmu->name); - if (ret) - goto free_dev; - - dev_set_drvdata(pmu->dev, pmu); - pmu->dev->bus = &pmu_bus; - pmu->dev->release = pmu_dev_release; - ret = device_add(pmu->dev); - if (ret) - goto free_dev; - -out: - return ret; - -free_dev: - put_device(pmu->dev); - goto out; -} - -static struct lock_class_key cpuctx_mutex; - -int perf_pmu_register(struct pmu *pmu, char *name, int type) -{ - int cpu, ret; - - mutex_lock(&pmus_lock); - ret = -ENOMEM; - pmu->pmu_disable_count = alloc_percpu(int); - if (!pmu->pmu_disable_count) - goto unlock; - - pmu->type = -1; - if (!name) - goto skip_type; - pmu->name = name; - - if (type < 0) { - int err = idr_pre_get(&pmu_idr, GFP_KERNEL); - if (!err) - goto free_pdc; - - err = idr_get_new_above(&pmu_idr, pmu, PERF_TYPE_MAX, &type); - if (err) { - ret = err; - goto free_pdc; - } - } - pmu->type = type; - - if (pmu_bus_running) { - ret = pmu_dev_alloc(pmu); - if (ret) - goto free_idr; - } - -skip_type: - pmu->pmu_cpu_context = find_pmu_context(pmu->task_ctx_nr); - if (pmu->pmu_cpu_context) - goto got_cpu_context; - - pmu->pmu_cpu_context = alloc_percpu(struct perf_cpu_context); - if (!pmu->pmu_cpu_context) - goto free_dev; - - for_each_possible_cpu(cpu) { - struct perf_cpu_context *cpuctx; - - cpuctx = per_cpu_ptr(pmu->pmu_cpu_context, cpu); - __perf_event_init_context(&cpuctx->ctx); - lockdep_set_class(&cpuctx->ctx.mutex, &cpuctx_mutex); - cpuctx->ctx.type = cpu_context; - cpuctx->ctx.pmu = pmu; - cpuctx->jiffies_interval = 1; - INIT_LIST_HEAD(&cpuctx->rotation_list); - cpuctx->active_pmu = pmu; - } - -got_cpu_context: - if (!pmu->start_txn) { - if (pmu->pmu_enable) { - /* - * If we have pmu_enable/pmu_disable calls, install - * transaction stubs that use that to try and batch - * hardware accesses. - */ - pmu->start_txn = perf_pmu_start_txn; - pmu->commit_txn = perf_pmu_commit_txn; - pmu->cancel_txn = perf_pmu_cancel_txn; - } else { - pmu->start_txn = perf_pmu_nop_void; - pmu->commit_txn = perf_pmu_nop_int; - pmu->cancel_txn = perf_pmu_nop_void; - } - } - - if (!pmu->pmu_enable) { - pmu->pmu_enable = perf_pmu_nop_void; - pmu->pmu_disable = perf_pmu_nop_void; - } - - list_add_rcu(&pmu->entry, &pmus); - ret = 0; -unlock: - mutex_unlock(&pmus_lock); - - return ret; - -free_dev: - device_del(pmu->dev); - put_device(pmu->dev); - -free_idr: - if (pmu->type >= PERF_TYPE_MAX) - idr_remove(&pmu_idr, pmu->type); - -free_pdc: - free_percpu(pmu->pmu_disable_count); - goto unlock; -} - -void perf_pmu_unregister(struct pmu *pmu) -{ - mutex_lock(&pmus_lock); - list_del_rcu(&pmu->entry); - mutex_unlock(&pmus_lock); - - /* - * We dereference the pmu list under both SRCU and regular RCU, so - * synchronize against both of those. - */ - synchronize_srcu(&pmus_srcu); - synchronize_rcu(); - - free_percpu(pmu->pmu_disable_count); - if (pmu->type >= PERF_TYPE_MAX) - idr_remove(&pmu_idr, pmu->type); - device_del(pmu->dev); - put_device(pmu->dev); - free_pmu_context(pmu); -} - -struct pmu *perf_init_event(struct perf_event *event) -{ - struct pmu *pmu = NULL; - int idx; - int ret; - - idx = srcu_read_lock(&pmus_srcu); - - rcu_read_lock(); - pmu = idr_find(&pmu_idr, event->attr.type); - rcu_read_unlock(); - if (pmu) { - ret = pmu->event_init(event); - if (ret) - pmu = ERR_PTR(ret); - goto unlock; - } - - list_for_each_entry_rcu(pmu, &pmus, entry) { - ret = pmu->event_init(event); - if (!ret) - goto unlock; - - if (ret != -ENOENT) { - pmu = ERR_PTR(ret); - goto unlock; - } - } - pmu = ERR_PTR(-ENOENT); -unlock: - srcu_read_unlock(&pmus_srcu, idx); - - return pmu; -} - -/* - * Allocate and initialize a event structure - */ -static struct perf_event * -perf_event_alloc(struct perf_event_attr *attr, int cpu, - struct task_struct *task, - struct perf_event *group_leader, - struct perf_event *parent_event, - perf_overflow_handler_t overflow_handler) -{ - struct pmu *pmu; - struct perf_event *event; - struct hw_perf_event *hwc; - long err; - - if ((unsigned)cpu >= nr_cpu_ids) { - if (!task || cpu != -1) - return ERR_PTR(-EINVAL); - } - - event = kzalloc(sizeof(*event), GFP_KERNEL); - if (!event) - return ERR_PTR(-ENOMEM); - - /* - * Single events are their own group leaders, with an - * empty sibling list: - */ - if (!group_leader) - group_leader = event; - - mutex_init(&event->child_mutex); - INIT_LIST_HEAD(&event->child_list); - - INIT_LIST_HEAD(&event->group_entry); - INIT_LIST_HEAD(&event->event_entry); - INIT_LIST_HEAD(&event->sibling_list); - init_waitqueue_head(&event->waitq); - init_irq_work(&event->pending, perf_pending_event); - - mutex_init(&event->mmap_mutex); - - event->cpu = cpu; - event->attr = *attr; - event->group_leader = group_leader; - event->pmu = NULL; - event->oncpu = -1; - - event->parent = parent_event; - - event->ns = get_pid_ns(current->nsproxy->pid_ns); - event->id = atomic64_inc_return(&perf_event_id); - - event->state = PERF_EVENT_STATE_INACTIVE; - - if (task) { - event->attach_state = PERF_ATTACH_TASK; -#ifdef CONFIG_HAVE_HW_BREAKPOINT - /* - * hw_breakpoint is a bit difficult here.. - */ - if (attr->type == PERF_TYPE_BREAKPOINT) - event->hw.bp_target = task; -#endif - } - - if (!overflow_handler && parent_event) - overflow_handler = parent_event->overflow_handler; - - event->overflow_handler = overflow_handler; - - if (attr->disabled) - event->state = PERF_EVENT_STATE_OFF; - - pmu = NULL; - - hwc = &event->hw; - hwc->sample_period = attr->sample_period; - if (attr->freq && attr->sample_freq) - hwc->sample_period = 1; - hwc->last_period = hwc->sample_period; - - local64_set(&hwc->period_left, hwc->sample_period); - - /* - * we currently do not support PERF_FORMAT_GROUP on inherited events - */ - if (attr->inherit && (attr->read_format & PERF_FORMAT_GROUP)) - goto done; - - pmu = perf_init_event(event); - -done: - err = 0; - if (!pmu) - err = -EINVAL; - else if (IS_ERR(pmu)) - err = PTR_ERR(pmu); - - if (err) { - if (event->ns) - put_pid_ns(event->ns); - kfree(event); - return ERR_PTR(err); - } - - event->pmu = pmu; - - if (!event->parent) { - if (event->attach_state & PERF_ATTACH_TASK) - jump_label_inc(&perf_sched_events); - if (event->attr.mmap || event->attr.mmap_data) - atomic_inc(&nr_mmap_events); - if (event->attr.comm) - atomic_inc(&nr_comm_events); - if (event->attr.task) - atomic_inc(&nr_task_events); - if (event->attr.sample_type & PERF_SAMPLE_CALLCHAIN) { - err = get_callchain_buffers(); - if (err) { - free_event(event); - return ERR_PTR(err); - } - } - } - - return event; -} - -static int perf_copy_attr(struct perf_event_attr __user *uattr, - struct perf_event_attr *attr) -{ - u32 size; - int ret; - - if (!access_ok(VERIFY_WRITE, uattr, PERF_ATTR_SIZE_VER0)) - return -EFAULT; - - /* - * zero the full structure, so that a short copy will be nice. - */ - memset(attr, 0, sizeof(*attr)); - - ret = get_user(size, &uattr->size); - if (ret) - return ret; - - if (size > PAGE_SIZE) /* silly large */ - goto err_size; - - if (!size) /* abi compat */ - size = PERF_ATTR_SIZE_VER0; - - if (size < PERF_ATTR_SIZE_VER0) - goto err_size; - - /* - * If we're handed a bigger struct than we know of, - * ensure all the unknown bits are 0 - i.e. new - * user-space does not rely on any kernel feature - * extensions we dont know about yet. - */ - if (size > sizeof(*attr)) { - unsigned char __user *addr; - unsigned char __user *end; - unsigned char val; - - addr = (void __user *)uattr + sizeof(*attr); - end = (void __user *)uattr + size; - - for (; addr < end; addr++) { - ret = get_user(val, addr); - if (ret) - return ret; - if (val) - goto err_size; - } - size = sizeof(*attr); - } - - ret = copy_from_user(attr, uattr, size); - if (ret) - return -EFAULT; - - /* - * If the type exists, the corresponding creation will verify - * the attr->config. - */ - if (attr->type >= PERF_TYPE_MAX) - return -EINVAL; - - if (attr->__reserved_1) - return -EINVAL; - - if (attr->sample_type & ~(PERF_SAMPLE_MAX-1)) - return -EINVAL; - - if (attr->read_format & ~(PERF_FORMAT_MAX-1)) - return -EINVAL; - -out: - return ret; - -err_size: - put_user(sizeof(*attr), &uattr->size); - ret = -E2BIG; - goto out; -} - -static int -perf_event_set_output(struct perf_event *event, struct perf_event *output_event) -{ - struct perf_buffer *buffer = NULL, *old_buffer = NULL; - int ret = -EINVAL; - - if (!output_event) - goto set; - - /* don't allow circular references */ - if (event == output_event) - goto out; - - /* - * Don't allow cross-cpu buffers - */ - if (output_event->cpu != event->cpu) - goto out; - - /* - * If its not a per-cpu buffer, it must be the same task. - */ - if (output_event->cpu == -1 && output_event->ctx != event->ctx) - goto out; - -set: - mutex_lock(&event->mmap_mutex); - /* Can't redirect output if we've got an active mmap() */ - if (atomic_read(&event->mmap_count)) - goto unlock; - - if (output_event) { - /* get the buffer we want to redirect to */ - buffer = perf_buffer_get(output_event); - if (!buffer) - goto unlock; - } - - old_buffer = event->buffer; - rcu_assign_pointer(event->buffer, buffer); - ret = 0; -unlock: - mutex_unlock(&event->mmap_mutex); - - if (old_buffer) - perf_buffer_put(old_buffer); -out: - return ret; -} - -/** - * sys_perf_event_open - open a performance event, associate it to a task/cpu - * - * @attr_uptr: event_id type attributes for monitoring/sampling - * @pid: target pid - * @cpu: target cpu - * @group_fd: group leader event fd - */ -SYSCALL_DEFINE5(perf_event_open, - struct perf_event_attr __user *, attr_uptr, - pid_t, pid, int, cpu, int, group_fd, unsigned long, flags) -{ - struct perf_event *group_leader = NULL, *output_event = NULL; - struct perf_event *event, *sibling; - struct perf_event_attr attr; - struct perf_event_context *ctx; - struct file *event_file = NULL; - struct file *group_file = NULL; - struct task_struct *task = NULL; - struct pmu *pmu; - int event_fd; - int move_group = 0; - int fput_needed = 0; - int err; - - /* for future expandability... */ - if (flags & ~PERF_FLAG_ALL) - return -EINVAL; - - err = perf_copy_attr(attr_uptr, &attr); - if (err) - return err; - - if (!attr.exclude_kernel) { - if (perf_paranoid_kernel() && !capable(CAP_SYS_ADMIN)) - return -EACCES; - } - - if (attr.freq) { - if (attr.sample_freq > sysctl_perf_event_sample_rate) - return -EINVAL; - } - - /* - * In cgroup mode, the pid argument is used to pass the fd - * opened to the cgroup directory in cgroupfs. The cpu argument - * designates the cpu on which to monitor threads from that - * cgroup. - */ - if ((flags & PERF_FLAG_PID_CGROUP) && (pid == -1 || cpu == -1)) - return -EINVAL; - - event_fd = get_unused_fd_flags(O_RDWR); - if (event_fd < 0) - return event_fd; - - if (group_fd != -1) { - group_leader = perf_fget_light(group_fd, &fput_needed); - if (IS_ERR(group_leader)) { - err = PTR_ERR(group_leader); - goto err_fd; - } - group_file = group_leader->filp; - if (flags & PERF_FLAG_FD_OUTPUT) - output_event = group_leader; - if (flags & PERF_FLAG_FD_NO_GROUP) - group_leader = NULL; - } - - if (pid != -1 && !(flags & PERF_FLAG_PID_CGROUP)) { - task = find_lively_task_by_vpid(pid); - if (IS_ERR(task)) { - err = PTR_ERR(task); - goto err_group_fd; - } - } - - event = perf_event_alloc(&attr, cpu, task, group_leader, NULL, NULL); - if (IS_ERR(event)) { - err = PTR_ERR(event); - goto err_task; - } - - if (flags & PERF_FLAG_PID_CGROUP) { - err = perf_cgroup_connect(pid, event, &attr, group_leader); - if (err) - goto err_alloc; - /* - * one more event: - * - that has cgroup constraint on event->cpu - * - that may need work on context switch - */ - atomic_inc(&per_cpu(perf_cgroup_events, event->cpu)); - jump_label_inc(&perf_sched_events); - } - - /* - * Special case software events and allow them to be part of - * any hardware group. - */ - pmu = event->pmu; - - if (group_leader && - (is_software_event(event) != is_software_event(group_leader))) { - if (is_software_event(event)) { - /* - * If event and group_leader are not both a software - * event, and event is, then group leader is not. - * - * Allow the addition of software events to !software - * groups, this is safe because software events never - * fail to schedule. - */ - pmu = group_leader->pmu; - } else if (is_software_event(group_leader) && - (group_leader->group_flags & PERF_GROUP_SOFTWARE)) { - /* - * In case the group is a pure software group, and we - * try to add a hardware event, move the whole group to - * the hardware context. - */ - move_group = 1; - } - } - - /* - * Get the target context (task or percpu): - */ - ctx = find_get_context(pmu, task, cpu); - if (IS_ERR(ctx)) { - err = PTR_ERR(ctx); - goto err_alloc; - } - - if (task) { - put_task_struct(task); - task = NULL; - } - - /* - * Look up the group leader (we will attach this event to it): - */ - if (group_leader) { - err = -EINVAL; - - /* - * Do not allow a recursive hierarchy (this new sibling - * becoming part of another group-sibling): - */ - if (group_leader->group_leader != group_leader) - goto err_context; - /* - * Do not allow to attach to a group in a different - * task or CPU context: - */ - if (move_group) { - if (group_leader->ctx->type != ctx->type) - goto err_context; - } else { - if (group_leader->ctx != ctx) - goto err_context; - } - - /* - * Only a group leader can be exclusive or pinned - */ - if (attr.exclusive || attr.pinned) - goto err_context; - } - - if (output_event) { - err = perf_event_set_output(event, output_event); - if (err) - goto err_context; - } - - event_file = anon_inode_getfile("[perf_event]", &perf_fops, event, O_RDWR); - if (IS_ERR(event_file)) { - err = PTR_ERR(event_file); - goto err_context; - } - - if (move_group) { - struct perf_event_context *gctx = group_leader->ctx; - - mutex_lock(&gctx->mutex); - perf_remove_from_context(group_leader); - list_for_each_entry(sibling, &group_leader->sibling_list, - group_entry) { - perf_remove_from_context(sibling); - put_ctx(gctx); - } - mutex_unlock(&gctx->mutex); - put_ctx(gctx); - } - - event->filp = event_file; - WARN_ON_ONCE(ctx->parent_ctx); - mutex_lock(&ctx->mutex); - - if (move_group) { - perf_install_in_context(ctx, group_leader, cpu); - get_ctx(ctx); - list_for_each_entry(sibling, &group_leader->sibling_list, - group_entry) { - perf_install_in_context(ctx, sibling, cpu); - get_ctx(ctx); - } - } - - perf_install_in_context(ctx, event, cpu); - ++ctx->generation; - perf_unpin_context(ctx); - mutex_unlock(&ctx->mutex); - - event->owner = current; - - mutex_lock(¤t->perf_event_mutex); - list_add_tail(&event->owner_entry, ¤t->perf_event_list); - mutex_unlock(¤t->perf_event_mutex); - - /* - * Precalculate sample_data sizes - */ - perf_event__header_size(event); - perf_event__id_header_size(event); - - /* - * Drop the reference on the group_event after placing the - * new event on the sibling_list. This ensures destruction - * of the group leader will find the pointer to itself in - * perf_group_detach(). - */ - fput_light(group_file, fput_needed); - fd_install(event_fd, event_file); - return event_fd; - -err_context: - perf_unpin_context(ctx); - put_ctx(ctx); -err_alloc: - free_event(event); -err_task: - if (task) - put_task_struct(task); -err_group_fd: - fput_light(group_file, fput_needed); -err_fd: - put_unused_fd(event_fd); - return err; -} - -/** - * perf_event_create_kernel_counter - * - * @attr: attributes of the counter to create - * @cpu: cpu in which the counter is bound - * @task: task to profile (NULL for percpu) - */ -struct perf_event * -perf_event_create_kernel_counter(struct perf_event_attr *attr, int cpu, - struct task_struct *task, - perf_overflow_handler_t overflow_handler) -{ - struct perf_event_context *ctx; - struct perf_event *event; - int err; - - /* - * Get the target context (task or percpu): - */ - - event = perf_event_alloc(attr, cpu, task, NULL, NULL, overflow_handler); - if (IS_ERR(event)) { - err = PTR_ERR(event); - goto err; - } - - ctx = find_get_context(event->pmu, task, cpu); - if (IS_ERR(ctx)) { - err = PTR_ERR(ctx); - goto err_free; - } - - event->filp = NULL; - WARN_ON_ONCE(ctx->parent_ctx); - mutex_lock(&ctx->mutex); - perf_install_in_context(ctx, event, cpu); - ++ctx->generation; - perf_unpin_context(ctx); - mutex_unlock(&ctx->mutex); - - return event; - -err_free: - free_event(event); -err: - return ERR_PTR(err); -} -EXPORT_SYMBOL_GPL(perf_event_create_kernel_counter); - -static void sync_child_event(struct perf_event *child_event, - struct task_struct *child) -{ - struct perf_event *parent_event = child_event->parent; - u64 child_val; - - if (child_event->attr.inherit_stat) - perf_event_read_event(child_event, child); - - child_val = perf_event_count(child_event); - - /* - * Add back the child's count to the parent's count: - */ - atomic64_add(child_val, &parent_event->child_count); - atomic64_add(child_event->total_time_enabled, - &parent_event->child_total_time_enabled); - atomic64_add(child_event->total_time_running, - &parent_event->child_total_time_running); - - /* - * Remove this event from the parent's list - */ - WARN_ON_ONCE(parent_event->ctx->parent_ctx); - mutex_lock(&parent_event->child_mutex); - list_del_init(&child_event->child_list); - mutex_unlock(&parent_event->child_mutex); - - /* - * Release the parent event, if this was the last - * reference to it. - */ - fput(parent_event->filp); -} - -static void -__perf_event_exit_task(struct perf_event *child_event, - struct perf_event_context *child_ctx, - struct task_struct *child) -{ - if (child_event->parent) { - raw_spin_lock_irq(&child_ctx->lock); - perf_group_detach(child_event); - raw_spin_unlock_irq(&child_ctx->lock); - } - - perf_remove_from_context(child_event); - - /* - * It can happen that the parent exits first, and has events - * that are still around due to the child reference. These - * events need to be zapped. - */ - if (child_event->parent) { - sync_child_event(child_event, child); - free_event(child_event); - } -} - -static void perf_event_exit_task_context(struct task_struct *child, int ctxn) -{ - struct perf_event *child_event, *tmp; - struct perf_event_context *child_ctx; - unsigned long flags; - - if (likely(!child->perf_event_ctxp[ctxn])) { - perf_event_task(child, NULL, 0); - return; - } - - local_irq_save(flags); - /* - * We can't reschedule here because interrupts are disabled, - * and either child is current or it is a task that can't be - * scheduled, so we are now safe from rescheduling changing - * our context. - */ - child_ctx = rcu_dereference_raw(child->perf_event_ctxp[ctxn]); - task_ctx_sched_out(child_ctx, EVENT_ALL); - - /* - * Take the context lock here so that if find_get_context is - * reading child->perf_event_ctxp, we wait until it has - * incremented the context's refcount before we do put_ctx below. - */ - raw_spin_lock(&child_ctx->lock); - child->perf_event_ctxp[ctxn] = NULL; - /* - * If this context is a clone; unclone it so it can't get - * swapped to another process while we're removing all - * the events from it. - */ - unclone_ctx(child_ctx); - update_context_time(child_ctx); - raw_spin_unlock_irqrestore(&child_ctx->lock, flags); - - /* - * Report the task dead after unscheduling the events so that we - * won't get any samples after PERF_RECORD_EXIT. We can however still - * get a few PERF_RECORD_READ events. - */ - perf_event_task(child, child_ctx, 0); - - /* - * We can recurse on the same lock type through: - * - * __perf_event_exit_task() - * sync_child_event() - * fput(parent_event->filp) - * perf_release() - * mutex_lock(&ctx->mutex) - * - * But since its the parent context it won't be the same instance. - */ - mutex_lock(&child_ctx->mutex); - -again: - list_for_each_entry_safe(child_event, tmp, &child_ctx->pinned_groups, - group_entry) - __perf_event_exit_task(child_event, child_ctx, child); - - list_for_each_entry_safe(child_event, tmp, &child_ctx->flexible_groups, - group_entry) - __perf_event_exit_task(child_event, child_ctx, child); - - /* - * If the last event was a group event, it will have appended all - * its siblings to the list, but we obtained 'tmp' before that which - * will still point to the list head terminating the iteration. - */ - if (!list_empty(&child_ctx->pinned_groups) || - !list_empty(&child_ctx->flexible_groups)) - goto again; - - mutex_unlock(&child_ctx->mutex); - - put_ctx(child_ctx); -} - -/* - * When a child task exits, feed back event values to parent events. - */ -void perf_event_exit_task(struct task_struct *child) -{ - struct perf_event *event, *tmp; - int ctxn; - - mutex_lock(&child->perf_event_mutex); - list_for_each_entry_safe(event, tmp, &child->perf_event_list, - owner_entry) { - list_del_init(&event->owner_entry); - - /* - * Ensure the list deletion is visible before we clear - * the owner, closes a race against perf_release() where - * we need to serialize on the owner->perf_event_mutex. - */ - smp_wmb(); - event->owner = NULL; - } - mutex_unlock(&child->perf_event_mutex); - - for_each_task_context_nr(ctxn) - perf_event_exit_task_context(child, ctxn); -} - -static void perf_free_event(struct perf_event *event, - struct perf_event_context *ctx) -{ - struct perf_event *parent = event->parent; - - if (WARN_ON_ONCE(!parent)) - return; - - mutex_lock(&parent->child_mutex); - list_del_init(&event->child_list); - mutex_unlock(&parent->child_mutex); - - fput(parent->filp); - - perf_group_detach(event); - list_del_event(event, ctx); - free_event(event); -} - -/* - * free an unexposed, unused context as created by inheritance by - * perf_event_init_task below, used by fork() in case of fail. - */ -void perf_event_free_task(struct task_struct *task) -{ - struct perf_event_context *ctx; - struct perf_event *event, *tmp; - int ctxn; - - for_each_task_context_nr(ctxn) { - ctx = task->perf_event_ctxp[ctxn]; - if (!ctx) - continue; - - mutex_lock(&ctx->mutex); -again: - list_for_each_entry_safe(event, tmp, &ctx->pinned_groups, - group_entry) - perf_free_event(event, ctx); - - list_for_each_entry_safe(event, tmp, &ctx->flexible_groups, - group_entry) - perf_free_event(event, ctx); - - if (!list_empty(&ctx->pinned_groups) || - !list_empty(&ctx->flexible_groups)) - goto again; - - mutex_unlock(&ctx->mutex); - - put_ctx(ctx); - } -} - -void perf_event_delayed_put(struct task_struct *task) -{ - int ctxn; - - for_each_task_context_nr(ctxn) - WARN_ON_ONCE(task->perf_event_ctxp[ctxn]); -} - -/* - * inherit a event from parent task to child task: - */ -static struct perf_event * -inherit_event(struct perf_event *parent_event, - struct task_struct *parent, - struct perf_event_context *parent_ctx, - struct task_struct *child, - struct perf_event *group_leader, - struct perf_event_context *child_ctx) -{ - struct perf_event *child_event; - unsigned long flags; - - /* - * Instead of creating recursive hierarchies of events, - * we link inherited events back to the original parent, - * which has a filp for sure, which we use as the reference - * count: - */ - if (parent_event->parent) - parent_event = parent_event->parent; - - child_event = perf_event_alloc(&parent_event->attr, - parent_event->cpu, - child, - group_leader, parent_event, - NULL); - if (IS_ERR(child_event)) - return child_event; - get_ctx(child_ctx); - - /* - * Make the child state follow the state of the parent event, - * not its attr.disabled bit. We hold the parent's mutex, - * so we won't race with perf_event_{en, dis}able_family. - */ - if (parent_event->state >= PERF_EVENT_STATE_INACTIVE) - child_event->state = PERF_EVENT_STATE_INACTIVE; - else - child_event->state = PERF_EVENT_STATE_OFF; - - if (parent_event->attr.freq) { - u64 sample_period = parent_event->hw.sample_period; - struct hw_perf_event *hwc = &child_event->hw; - - hwc->sample_period = sample_period; - hwc->last_period = sample_period; - - local64_set(&hwc->period_left, sample_period); - } - - child_event->ctx = child_ctx; - child_event->overflow_handler = parent_event->overflow_handler; - - /* - * Precalculate sample_data sizes - */ - perf_event__header_size(child_event); - perf_event__id_header_size(child_event); - - /* - * Link it up in the child's context: - */ - raw_spin_lock_irqsave(&child_ctx->lock, flags); - add_event_to_ctx(child_event, child_ctx); - raw_spin_unlock_irqrestore(&child_ctx->lock, flags); - - /* - * Get a reference to the parent filp - we will fput it - * when the child event exits. This is safe to do because - * we are in the parent and we know that the filp still - * exists and has a nonzero count: - */ - atomic_long_inc(&parent_event->filp->f_count); - - /* - * Link this into the parent event's child list - */ - WARN_ON_ONCE(parent_event->ctx->parent_ctx); - mutex_lock(&parent_event->child_mutex); - list_add_tail(&child_event->child_list, &parent_event->child_list); - mutex_unlock(&parent_event->child_mutex); - - return child_event; -} - -static int inherit_group(struct perf_event *parent_event, - struct task_struct *parent, - struct perf_event_context *parent_ctx, - struct task_struct *child, - struct perf_event_context *child_ctx) -{ - struct perf_event *leader; - struct perf_event *sub; - struct perf_event *child_ctr; - - leader = inherit_event(parent_event, parent, parent_ctx, - child, NULL, child_ctx); - if (IS_ERR(leader)) - return PTR_ERR(leader); - list_for_each_entry(sub, &parent_event->sibling_list, group_entry) { - child_ctr = inherit_event(sub, parent, parent_ctx, - child, leader, child_ctx); - if (IS_ERR(child_ctr)) - return PTR_ERR(child_ctr); - } - return 0; -} - -static int -inherit_task_group(struct perf_event *event, struct task_struct *parent, - struct perf_event_context *parent_ctx, - struct task_struct *child, int ctxn, - int *inherited_all) -{ - int ret; - struct perf_event_context *child_ctx; - - if (!event->attr.inherit) { - *inherited_all = 0; - return 0; - } - - child_ctx = child->perf_event_ctxp[ctxn]; - if (!child_ctx) { - /* - * This is executed from the parent task context, so - * inherit events that have been marked for cloning. - * First allocate and initialize a context for the - * child. - */ - - child_ctx = alloc_perf_context(event->pmu, child); - if (!child_ctx) - return -ENOMEM; - - child->perf_event_ctxp[ctxn] = child_ctx; - } - - ret = inherit_group(event, parent, parent_ctx, - child, child_ctx); - - if (ret) - *inherited_all = 0; - - return ret; -} - -/* - * Initialize the perf_event context in task_struct - */ -int perf_event_init_context(struct task_struct *child, int ctxn) -{ - struct perf_event_context *child_ctx, *parent_ctx; - struct perf_event_context *cloned_ctx; - struct perf_event *event; - struct task_struct *parent = current; - int inherited_all = 1; - unsigned long flags; - int ret = 0; - - if (likely(!parent->perf_event_ctxp[ctxn])) - return 0; - - /* - * If the parent's context is a clone, pin it so it won't get - * swapped under us. - */ - parent_ctx = perf_pin_task_context(parent, ctxn); - - /* - * No need to check if parent_ctx != NULL here; since we saw - * it non-NULL earlier, the only reason for it to become NULL - * is if we exit, and since we're currently in the middle of - * a fork we can't be exiting at the same time. - */ - - /* - * Lock the parent list. No need to lock the child - not PID - * hashed yet and not running, so nobody can access it. - */ - mutex_lock(&parent_ctx->mutex); - - /* - * We dont have to disable NMIs - we are only looking at - * the list, not manipulating it: - */ - list_for_each_entry(event, &parent_ctx->pinned_groups, group_entry) { - ret = inherit_task_group(event, parent, parent_ctx, - child, ctxn, &inherited_all); - if (ret) - break; - } - - /* - * We can't hold ctx->lock when iterating the ->flexible_group list due - * to allocations, but we need to prevent rotation because - * rotate_ctx() will change the list from interrupt context. - */ - raw_spin_lock_irqsave(&parent_ctx->lock, flags); - parent_ctx->rotate_disable = 1; - raw_spin_unlock_irqrestore(&parent_ctx->lock, flags); - - list_for_each_entry(event, &parent_ctx->flexible_groups, group_entry) { - ret = inherit_task_group(event, parent, parent_ctx, - child, ctxn, &inherited_all); - if (ret) - break; - } - - raw_spin_lock_irqsave(&parent_ctx->lock, flags); - parent_ctx->rotate_disable = 0; - - child_ctx = child->perf_event_ctxp[ctxn]; - - if (child_ctx && inherited_all) { - /* - * Mark the child context as a clone of the parent - * context, or of whatever the parent is a clone of. - * - * Note that if the parent is a clone, the holding of - * parent_ctx->lock avoids it from being uncloned. - */ - cloned_ctx = parent_ctx->parent_ctx; - if (cloned_ctx) { - child_ctx->parent_ctx = cloned_ctx; - child_ctx->parent_gen = parent_ctx->parent_gen; - } else { - child_ctx->parent_ctx = parent_ctx; - child_ctx->parent_gen = parent_ctx->generation; - } - get_ctx(child_ctx->parent_ctx); - } - - raw_spin_unlock_irqrestore(&parent_ctx->lock, flags); - mutex_unlock(&parent_ctx->mutex); - - perf_unpin_context(parent_ctx); - put_ctx(parent_ctx); - - return ret; -} - -/* - * Initialize the perf_event context in task_struct - */ -int perf_event_init_task(struct task_struct *child) -{ - int ctxn, ret; - - memset(child->perf_event_ctxp, 0, sizeof(child->perf_event_ctxp)); - mutex_init(&child->perf_event_mutex); - INIT_LIST_HEAD(&child->perf_event_list); - - for_each_task_context_nr(ctxn) { - ret = perf_event_init_context(child, ctxn); - if (ret) - return ret; - } - - return 0; -} - -static void __init perf_event_init_all_cpus(void) -{ - struct swevent_htable *swhash; - int cpu; - - for_each_possible_cpu(cpu) { - swhash = &per_cpu(swevent_htable, cpu); - mutex_init(&swhash->hlist_mutex); - INIT_LIST_HEAD(&per_cpu(rotation_list, cpu)); - } -} - -static void __cpuinit perf_event_init_cpu(int cpu) -{ - struct swevent_htable *swhash = &per_cpu(swevent_htable, cpu); - - mutex_lock(&swhash->hlist_mutex); - if (swhash->hlist_refcount > 0) { - struct swevent_hlist *hlist; - - hlist = kzalloc_node(sizeof(*hlist), GFP_KERNEL, cpu_to_node(cpu)); - WARN_ON(!hlist); - rcu_assign_pointer(swhash->swevent_hlist, hlist); - } - mutex_unlock(&swhash->hlist_mutex); -} - -#if defined CONFIG_HOTPLUG_CPU || defined CONFIG_KEXEC -static void perf_pmu_rotate_stop(struct pmu *pmu) -{ - struct perf_cpu_context *cpuctx = this_cpu_ptr(pmu->pmu_cpu_context); - - WARN_ON(!irqs_disabled()); - - list_del_init(&cpuctx->rotation_list); -} - -static void __perf_event_exit_context(void *__info) -{ - struct perf_event_context *ctx = __info; - struct perf_event *event, *tmp; - - perf_pmu_rotate_stop(ctx->pmu); - - list_for_each_entry_safe(event, tmp, &ctx->pinned_groups, group_entry) - __perf_remove_from_context(event); - list_for_each_entry_safe(event, tmp, &ctx->flexible_groups, group_entry) - __perf_remove_from_context(event); -} - -static void perf_event_exit_cpu_context(int cpu) -{ - struct perf_event_context *ctx; - struct pmu *pmu; - int idx; - - idx = srcu_read_lock(&pmus_srcu); - list_for_each_entry_rcu(pmu, &pmus, entry) { - ctx = &per_cpu_ptr(pmu->pmu_cpu_context, cpu)->ctx; - - mutex_lock(&ctx->mutex); - smp_call_function_single(cpu, __perf_event_exit_context, ctx, 1); - mutex_unlock(&ctx->mutex); - } - srcu_read_unlock(&pmus_srcu, idx); -} - -static void perf_event_exit_cpu(int cpu) -{ - struct swevent_htable *swhash = &per_cpu(swevent_htable, cpu); - - mutex_lock(&swhash->hlist_mutex); - swevent_hlist_release(swhash); - mutex_unlock(&swhash->hlist_mutex); - - perf_event_exit_cpu_context(cpu); -} -#else -static inline void perf_event_exit_cpu(int cpu) { } -#endif - -static int -perf_reboot(struct notifier_block *notifier, unsigned long val, void *v) -{ - int cpu; - - for_each_online_cpu(cpu) - perf_event_exit_cpu(cpu); - - return NOTIFY_OK; -} - -/* - * Run the perf reboot notifier at the very last possible moment so that - * the generic watchdog code runs as long as possible. - */ -static struct notifier_block perf_reboot_notifier = { - .notifier_call = perf_reboot, - .priority = INT_MIN, -}; - -static int __cpuinit -perf_cpu_notify(struct notifier_block *self, unsigned long action, void *hcpu) -{ - unsigned int cpu = (long)hcpu; - - switch (action & ~CPU_TASKS_FROZEN) { - - case CPU_UP_PREPARE: - case CPU_DOWN_FAILED: - perf_event_init_cpu(cpu); - break; - - case CPU_UP_CANCELED: - case CPU_DOWN_PREPARE: - perf_event_exit_cpu(cpu); - break; - - default: - break; - } - - return NOTIFY_OK; -} - -void __init perf_event_init(void) -{ - int ret; - - idr_init(&pmu_idr); - - perf_event_init_all_cpus(); - init_srcu_struct(&pmus_srcu); - perf_pmu_register(&perf_swevent, "software", PERF_TYPE_SOFTWARE); - perf_pmu_register(&perf_cpu_clock, NULL, -1); - perf_pmu_register(&perf_task_clock, NULL, -1); - perf_tp_register(); - perf_cpu_notifier(perf_cpu_notify); - register_reboot_notifier(&perf_reboot_notifier); - - ret = init_hw_breakpoint(); - WARN(ret, "hw_breakpoint initialization failed with: %d", ret); -} - -static int __init perf_event_sysfs_init(void) -{ - struct pmu *pmu; - int ret; - - mutex_lock(&pmus_lock); - - ret = bus_register(&pmu_bus); - if (ret) - goto unlock; - - list_for_each_entry(pmu, &pmus, entry) { - if (!pmu->name || pmu->type < 0) - continue; - - ret = pmu_dev_alloc(pmu); - WARN(ret, "Failed to register pmu: %s, reason %d\n", pmu->name, ret); - } - pmu_bus_running = 1; - ret = 0; - -unlock: - mutex_unlock(&pmus_lock); - - return ret; -} -device_initcall(perf_event_sysfs_init); - -#ifdef CONFIG_CGROUP_PERF -static struct cgroup_subsys_state *perf_cgroup_create( - struct cgroup_subsys *ss, struct cgroup *cont) -{ - struct perf_cgroup *jc; - - jc = kzalloc(sizeof(*jc), GFP_KERNEL); - if (!jc) - return ERR_PTR(-ENOMEM); - - jc->info = alloc_percpu(struct perf_cgroup_info); - if (!jc->info) { - kfree(jc); - return ERR_PTR(-ENOMEM); - } - - return &jc->css; -} - -static void perf_cgroup_destroy(struct cgroup_subsys *ss, - struct cgroup *cont) -{ - struct perf_cgroup *jc; - jc = container_of(cgroup_subsys_state(cont, perf_subsys_id), - struct perf_cgroup, css); - free_percpu(jc->info); - kfree(jc); -} - -static int __perf_cgroup_move(void *info) -{ - struct task_struct *task = info; - perf_cgroup_switch(task, PERF_CGROUP_SWOUT | PERF_CGROUP_SWIN); - return 0; -} - -static void perf_cgroup_move(struct task_struct *task) -{ - task_function_call(task, __perf_cgroup_move, task); -} - -static void perf_cgroup_attach(struct cgroup_subsys *ss, struct cgroup *cgrp, - struct cgroup *old_cgrp, struct task_struct *task, - bool threadgroup) -{ - perf_cgroup_move(task); - if (threadgroup) { - struct task_struct *c; - rcu_read_lock(); - list_for_each_entry_rcu(c, &task->thread_group, thread_group) { - perf_cgroup_move(c); - } - rcu_read_unlock(); - } -} - -static void perf_cgroup_exit(struct cgroup_subsys *ss, struct cgroup *cgrp, - struct cgroup *old_cgrp, struct task_struct *task) -{ - /* - * cgroup_exit() is called in the copy_process() failure path. - * Ignore this case since the task hasn't ran yet, this avoids - * trying to poke a half freed task state from generic code. - */ - if (!(task->flags & PF_EXITING)) - return; - - perf_cgroup_move(task); -} - -struct cgroup_subsys perf_subsys = { - .name = "perf_event", - .subsys_id = perf_subsys_id, - .create = perf_cgroup_create, - .destroy = perf_cgroup_destroy, - .exit = perf_cgroup_exit, - .attach = perf_cgroup_attach, -}; -#endif /* CONFIG_CGROUP_PERF */ -- cgit v0.10.2 From 48dbb6dc86ca5d1b2224937d774c7ba98bc3a485 Mon Sep 17 00:00:00 2001 From: Borislav Petkov Date: Tue, 3 May 2011 15:26:43 +0200 Subject: hw breakpoints: Move to kernel/events/ As part of the events sybsystem unification, relocate hw_breakpoint.c into its new destination. Cc: Frederic Weisbecker Signed-off-by: Borislav Petkov diff --git a/kernel/Makefile b/kernel/Makefile index 7981530..e9cf191 100644 --- a/kernel/Makefile +++ b/kernel/Makefile @@ -105,7 +105,6 @@ obj-$(CONFIG_IRQ_WORK) += irq_work.o obj-$(CONFIG_PERF_EVENTS) += events/ -obj-$(CONFIG_HAVE_HW_BREAKPOINT) += hw_breakpoint.o obj-$(CONFIG_USER_RETURN_NOTIFIER) += user-return-notifier.o obj-$(CONFIG_PADATA) += padata.o obj-$(CONFIG_CRASH_DUMP) += crash_dump.o diff --git a/kernel/events/Makefile b/kernel/events/Makefile index 26c00e4..1ce23d3 100644 --- a/kernel/events/Makefile +++ b/kernel/events/Makefile @@ -2,4 +2,5 @@ ifdef CONFIG_FUNCTION_TRACER CFLAGS_REMOVE_core.o = -pg endif -obj-y += core.o +obj-y := core.o +obj-$(CONFIG_HAVE_HW_BREAKPOINT) += hw_breakpoint.o diff --git a/kernel/events/hw_breakpoint.c b/kernel/events/hw_breakpoint.c new file mode 100644 index 0000000..086adf2 --- /dev/null +++ b/kernel/events/hw_breakpoint.c @@ -0,0 +1,659 @@ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * Copyright (C) 2007 Alan Stern + * Copyright (C) IBM Corporation, 2009 + * Copyright (C) 2009, Frederic Weisbecker + * + * Thanks to Ingo Molnar for his many suggestions. + * + * Authors: Alan Stern + * K.Prasad + * Frederic Weisbecker + */ + +/* + * HW_breakpoint: a unified kernel/user-space hardware breakpoint facility, + * using the CPU's debug registers. + * This file contains the arch-independent routines. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + + +/* + * Constraints data + */ + +/* Number of pinned cpu breakpoints in a cpu */ +static DEFINE_PER_CPU(unsigned int, nr_cpu_bp_pinned[TYPE_MAX]); + +/* Number of pinned task breakpoints in a cpu */ +static DEFINE_PER_CPU(unsigned int *, nr_task_bp_pinned[TYPE_MAX]); + +/* Number of non-pinned cpu/task breakpoints in a cpu */ +static DEFINE_PER_CPU(unsigned int, nr_bp_flexible[TYPE_MAX]); + +static int nr_slots[TYPE_MAX]; + +/* Keep track of the breakpoints attached to tasks */ +static LIST_HEAD(bp_task_head); + +static int constraints_initialized; + +/* Gather the number of total pinned and un-pinned bp in a cpuset */ +struct bp_busy_slots { + unsigned int pinned; + unsigned int flexible; +}; + +/* Serialize accesses to the above constraints */ +static DEFINE_MUTEX(nr_bp_mutex); + +__weak int hw_breakpoint_weight(struct perf_event *bp) +{ + return 1; +} + +static inline enum bp_type_idx find_slot_idx(struct perf_event *bp) +{ + if (bp->attr.bp_type & HW_BREAKPOINT_RW) + return TYPE_DATA; + + return TYPE_INST; +} + +/* + * Report the maximum number of pinned breakpoints a task + * have in this cpu + */ +static unsigned int max_task_bp_pinned(int cpu, enum bp_type_idx type) +{ + int i; + unsigned int *tsk_pinned = per_cpu(nr_task_bp_pinned[type], cpu); + + for (i = nr_slots[type] - 1; i >= 0; i--) { + if (tsk_pinned[i] > 0) + return i + 1; + } + + return 0; +} + +/* + * Count the number of breakpoints of the same type and same task. + * The given event must be not on the list. + */ +static int task_bp_pinned(struct perf_event *bp, enum bp_type_idx type) +{ + struct task_struct *tsk = bp->hw.bp_target; + struct perf_event *iter; + int count = 0; + + list_for_each_entry(iter, &bp_task_head, hw.bp_list) { + if (iter->hw.bp_target == tsk && find_slot_idx(iter) == type) + count += hw_breakpoint_weight(iter); + } + + return count; +} + +/* + * Report the number of pinned/un-pinned breakpoints we have in + * a given cpu (cpu > -1) or in all of them (cpu = -1). + */ +static void +fetch_bp_busy_slots(struct bp_busy_slots *slots, struct perf_event *bp, + enum bp_type_idx type) +{ + int cpu = bp->cpu; + struct task_struct *tsk = bp->hw.bp_target; + + if (cpu >= 0) { + slots->pinned = per_cpu(nr_cpu_bp_pinned[type], cpu); + if (!tsk) + slots->pinned += max_task_bp_pinned(cpu, type); + else + slots->pinned += task_bp_pinned(bp, type); + slots->flexible = per_cpu(nr_bp_flexible[type], cpu); + + return; + } + + for_each_online_cpu(cpu) { + unsigned int nr; + + nr = per_cpu(nr_cpu_bp_pinned[type], cpu); + if (!tsk) + nr += max_task_bp_pinned(cpu, type); + else + nr += task_bp_pinned(bp, type); + + if (nr > slots->pinned) + slots->pinned = nr; + + nr = per_cpu(nr_bp_flexible[type], cpu); + + if (nr > slots->flexible) + slots->flexible = nr; + } +} + +/* + * For now, continue to consider flexible as pinned, until we can + * ensure no flexible event can ever be scheduled before a pinned event + * in a same cpu. + */ +static void +fetch_this_slot(struct bp_busy_slots *slots, int weight) +{ + slots->pinned += weight; +} + +/* + * Add a pinned breakpoint for the given task in our constraint table + */ +static void toggle_bp_task_slot(struct perf_event *bp, int cpu, bool enable, + enum bp_type_idx type, int weight) +{ + unsigned int *tsk_pinned; + int old_count = 0; + int old_idx = 0; + int idx = 0; + + old_count = task_bp_pinned(bp, type); + old_idx = old_count - 1; + idx = old_idx + weight; + + /* tsk_pinned[n] is the number of tasks having n breakpoints */ + tsk_pinned = per_cpu(nr_task_bp_pinned[type], cpu); + if (enable) { + tsk_pinned[idx]++; + if (old_count > 0) + tsk_pinned[old_idx]--; + } else { + tsk_pinned[idx]--; + if (old_count > 0) + tsk_pinned[old_idx]++; + } +} + +/* + * Add/remove the given breakpoint in our constraint table + */ +static void +toggle_bp_slot(struct perf_event *bp, bool enable, enum bp_type_idx type, + int weight) +{ + int cpu = bp->cpu; + struct task_struct *tsk = bp->hw.bp_target; + + /* Pinned counter cpu profiling */ + if (!tsk) { + + if (enable) + per_cpu(nr_cpu_bp_pinned[type], bp->cpu) += weight; + else + per_cpu(nr_cpu_bp_pinned[type], bp->cpu) -= weight; + return; + } + + /* Pinned counter task profiling */ + + if (!enable) + list_del(&bp->hw.bp_list); + + if (cpu >= 0) { + toggle_bp_task_slot(bp, cpu, enable, type, weight); + } else { + for_each_online_cpu(cpu) + toggle_bp_task_slot(bp, cpu, enable, type, weight); + } + + if (enable) + list_add_tail(&bp->hw.bp_list, &bp_task_head); +} + +/* + * Function to perform processor-specific cleanup during unregistration + */ +__weak void arch_unregister_hw_breakpoint(struct perf_event *bp) +{ + /* + * A weak stub function here for those archs that don't define + * it inside arch/.../kernel/hw_breakpoint.c + */ +} + +/* + * Contraints to check before allowing this new breakpoint counter: + * + * == Non-pinned counter == (Considered as pinned for now) + * + * - If attached to a single cpu, check: + * + * (per_cpu(nr_bp_flexible, cpu) || (per_cpu(nr_cpu_bp_pinned, cpu) + * + max(per_cpu(nr_task_bp_pinned, cpu)))) < HBP_NUM + * + * -> If there are already non-pinned counters in this cpu, it means + * there is already a free slot for them. + * Otherwise, we check that the maximum number of per task + * breakpoints (for this cpu) plus the number of per cpu breakpoint + * (for this cpu) doesn't cover every registers. + * + * - If attached to every cpus, check: + * + * (per_cpu(nr_bp_flexible, *) || (max(per_cpu(nr_cpu_bp_pinned, *)) + * + max(per_cpu(nr_task_bp_pinned, *)))) < HBP_NUM + * + * -> This is roughly the same, except we check the number of per cpu + * bp for every cpu and we keep the max one. Same for the per tasks + * breakpoints. + * + * + * == Pinned counter == + * + * - If attached to a single cpu, check: + * + * ((per_cpu(nr_bp_flexible, cpu) > 1) + per_cpu(nr_cpu_bp_pinned, cpu) + * + max(per_cpu(nr_task_bp_pinned, cpu))) < HBP_NUM + * + * -> Same checks as before. But now the nr_bp_flexible, if any, must keep + * one register at least (or they will never be fed). + * + * - If attached to every cpus, check: + * + * ((per_cpu(nr_bp_flexible, *) > 1) + max(per_cpu(nr_cpu_bp_pinned, *)) + * + max(per_cpu(nr_task_bp_pinned, *))) < HBP_NUM + */ +static int __reserve_bp_slot(struct perf_event *bp) +{ + struct bp_busy_slots slots = {0}; + enum bp_type_idx type; + int weight; + + /* We couldn't initialize breakpoint constraints on boot */ + if (!constraints_initialized) + return -ENOMEM; + + /* Basic checks */ + if (bp->attr.bp_type == HW_BREAKPOINT_EMPTY || + bp->attr.bp_type == HW_BREAKPOINT_INVALID) + return -EINVAL; + + type = find_slot_idx(bp); + weight = hw_breakpoint_weight(bp); + + fetch_bp_busy_slots(&slots, bp, type); + /* + * Simulate the addition of this breakpoint to the constraints + * and see the result. + */ + fetch_this_slot(&slots, weight); + + /* Flexible counters need to keep at least one slot */ + if (slots.pinned + (!!slots.flexible) > nr_slots[type]) + return -ENOSPC; + + toggle_bp_slot(bp, true, type, weight); + + return 0; +} + +int reserve_bp_slot(struct perf_event *bp) +{ + int ret; + + mutex_lock(&nr_bp_mutex); + + ret = __reserve_bp_slot(bp); + + mutex_unlock(&nr_bp_mutex); + + return ret; +} + +static void __release_bp_slot(struct perf_event *bp) +{ + enum bp_type_idx type; + int weight; + + type = find_slot_idx(bp); + weight = hw_breakpoint_weight(bp); + toggle_bp_slot(bp, false, type, weight); +} + +void release_bp_slot(struct perf_event *bp) +{ + mutex_lock(&nr_bp_mutex); + + arch_unregister_hw_breakpoint(bp); + __release_bp_slot(bp); + + mutex_unlock(&nr_bp_mutex); +} + +/* + * Allow the kernel debugger to reserve breakpoint slots without + * taking a lock using the dbg_* variant of for the reserve and + * release breakpoint slots. + */ +int dbg_reserve_bp_slot(struct perf_event *bp) +{ + if (mutex_is_locked(&nr_bp_mutex)) + return -1; + + return __reserve_bp_slot(bp); +} + +int dbg_release_bp_slot(struct perf_event *bp) +{ + if (mutex_is_locked(&nr_bp_mutex)) + return -1; + + __release_bp_slot(bp); + + return 0; +} + +static int validate_hw_breakpoint(struct perf_event *bp) +{ + int ret; + + ret = arch_validate_hwbkpt_settings(bp); + if (ret) + return ret; + + if (arch_check_bp_in_kernelspace(bp)) { + if (bp->attr.exclude_kernel) + return -EINVAL; + /* + * Don't let unprivileged users set a breakpoint in the trap + * path to avoid trap recursion attacks. + */ + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + } + + return 0; +} + +int register_perf_hw_breakpoint(struct perf_event *bp) +{ + int ret; + + ret = reserve_bp_slot(bp); + if (ret) + return ret; + + ret = validate_hw_breakpoint(bp); + + /* if arch_validate_hwbkpt_settings() fails then release bp slot */ + if (ret) + release_bp_slot(bp); + + return ret; +} + +/** + * register_user_hw_breakpoint - register a hardware breakpoint for user space + * @attr: breakpoint attributes + * @triggered: callback to trigger when we hit the breakpoint + * @tsk: pointer to 'task_struct' of the process to which the address belongs + */ +struct perf_event * +register_user_hw_breakpoint(struct perf_event_attr *attr, + perf_overflow_handler_t triggered, + struct task_struct *tsk) +{ + return perf_event_create_kernel_counter(attr, -1, tsk, triggered); +} +EXPORT_SYMBOL_GPL(register_user_hw_breakpoint); + +/** + * modify_user_hw_breakpoint - modify a user-space hardware breakpoint + * @bp: the breakpoint structure to modify + * @attr: new breakpoint attributes + * @triggered: callback to trigger when we hit the breakpoint + * @tsk: pointer to 'task_struct' of the process to which the address belongs + */ +int modify_user_hw_breakpoint(struct perf_event *bp, struct perf_event_attr *attr) +{ + u64 old_addr = bp->attr.bp_addr; + u64 old_len = bp->attr.bp_len; + int old_type = bp->attr.bp_type; + int err = 0; + + perf_event_disable(bp); + + bp->attr.bp_addr = attr->bp_addr; + bp->attr.bp_type = attr->bp_type; + bp->attr.bp_len = attr->bp_len; + + if (attr->disabled) + goto end; + + err = validate_hw_breakpoint(bp); + if (!err) + perf_event_enable(bp); + + if (err) { + bp->attr.bp_addr = old_addr; + bp->attr.bp_type = old_type; + bp->attr.bp_len = old_len; + if (!bp->attr.disabled) + perf_event_enable(bp); + + return err; + } + +end: + bp->attr.disabled = attr->disabled; + + return 0; +} +EXPORT_SYMBOL_GPL(modify_user_hw_breakpoint); + +/** + * unregister_hw_breakpoint - unregister a user-space hardware breakpoint + * @bp: the breakpoint structure to unregister + */ +void unregister_hw_breakpoint(struct perf_event *bp) +{ + if (!bp) + return; + perf_event_release_kernel(bp); +} +EXPORT_SYMBOL_GPL(unregister_hw_breakpoint); + +/** + * register_wide_hw_breakpoint - register a wide breakpoint in the kernel + * @attr: breakpoint attributes + * @triggered: callback to trigger when we hit the breakpoint + * + * @return a set of per_cpu pointers to perf events + */ +struct perf_event * __percpu * +register_wide_hw_breakpoint(struct perf_event_attr *attr, + perf_overflow_handler_t triggered) +{ + struct perf_event * __percpu *cpu_events, **pevent, *bp; + long err; + int cpu; + + cpu_events = alloc_percpu(typeof(*cpu_events)); + if (!cpu_events) + return (void __percpu __force *)ERR_PTR(-ENOMEM); + + get_online_cpus(); + for_each_online_cpu(cpu) { + pevent = per_cpu_ptr(cpu_events, cpu); + bp = perf_event_create_kernel_counter(attr, cpu, NULL, triggered); + + *pevent = bp; + + if (IS_ERR(bp)) { + err = PTR_ERR(bp); + goto fail; + } + } + put_online_cpus(); + + return cpu_events; + +fail: + for_each_online_cpu(cpu) { + pevent = per_cpu_ptr(cpu_events, cpu); + if (IS_ERR(*pevent)) + break; + unregister_hw_breakpoint(*pevent); + } + put_online_cpus(); + + free_percpu(cpu_events); + return (void __percpu __force *)ERR_PTR(err); +} +EXPORT_SYMBOL_GPL(register_wide_hw_breakpoint); + +/** + * unregister_wide_hw_breakpoint - unregister a wide breakpoint in the kernel + * @cpu_events: the per cpu set of events to unregister + */ +void unregister_wide_hw_breakpoint(struct perf_event * __percpu *cpu_events) +{ + int cpu; + struct perf_event **pevent; + + for_each_possible_cpu(cpu) { + pevent = per_cpu_ptr(cpu_events, cpu); + unregister_hw_breakpoint(*pevent); + } + free_percpu(cpu_events); +} +EXPORT_SYMBOL_GPL(unregister_wide_hw_breakpoint); + +static struct notifier_block hw_breakpoint_exceptions_nb = { + .notifier_call = hw_breakpoint_exceptions_notify, + /* we need to be notified first */ + .priority = 0x7fffffff +}; + +static void bp_perf_event_destroy(struct perf_event *event) +{ + release_bp_slot(event); +} + +static int hw_breakpoint_event_init(struct perf_event *bp) +{ + int err; + + if (bp->attr.type != PERF_TYPE_BREAKPOINT) + return -ENOENT; + + err = register_perf_hw_breakpoint(bp); + if (err) + return err; + + bp->destroy = bp_perf_event_destroy; + + return 0; +} + +static int hw_breakpoint_add(struct perf_event *bp, int flags) +{ + if (!(flags & PERF_EF_START)) + bp->hw.state = PERF_HES_STOPPED; + + return arch_install_hw_breakpoint(bp); +} + +static void hw_breakpoint_del(struct perf_event *bp, int flags) +{ + arch_uninstall_hw_breakpoint(bp); +} + +static void hw_breakpoint_start(struct perf_event *bp, int flags) +{ + bp->hw.state = 0; +} + +static void hw_breakpoint_stop(struct perf_event *bp, int flags) +{ + bp->hw.state = PERF_HES_STOPPED; +} + +static struct pmu perf_breakpoint = { + .task_ctx_nr = perf_sw_context, /* could eventually get its own */ + + .event_init = hw_breakpoint_event_init, + .add = hw_breakpoint_add, + .del = hw_breakpoint_del, + .start = hw_breakpoint_start, + .stop = hw_breakpoint_stop, + .read = hw_breakpoint_pmu_read, +}; + +int __init init_hw_breakpoint(void) +{ + unsigned int **task_bp_pinned; + int cpu, err_cpu; + int i; + + for (i = 0; i < TYPE_MAX; i++) + nr_slots[i] = hw_breakpoint_slots(i); + + for_each_possible_cpu(cpu) { + for (i = 0; i < TYPE_MAX; i++) { + task_bp_pinned = &per_cpu(nr_task_bp_pinned[i], cpu); + *task_bp_pinned = kzalloc(sizeof(int) * nr_slots[i], + GFP_KERNEL); + if (!*task_bp_pinned) + goto err_alloc; + } + } + + constraints_initialized = 1; + + perf_pmu_register(&perf_breakpoint, "breakpoint", PERF_TYPE_BREAKPOINT); + + return register_die_notifier(&hw_breakpoint_exceptions_nb); + + err_alloc: + for_each_possible_cpu(err_cpu) { + if (err_cpu == cpu) + break; + for (i = 0; i < TYPE_MAX; i++) + kfree(per_cpu(nr_task_bp_pinned[i], cpu)); + } + + return -ENOMEM; +} + + diff --git a/kernel/hw_breakpoint.c b/kernel/hw_breakpoint.c deleted file mode 100644 index 086adf2..0000000 --- a/kernel/hw_breakpoint.c +++ /dev/null @@ -1,659 +0,0 @@ -/* - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - * - * Copyright (C) 2007 Alan Stern - * Copyright (C) IBM Corporation, 2009 - * Copyright (C) 2009, Frederic Weisbecker - * - * Thanks to Ingo Molnar for his many suggestions. - * - * Authors: Alan Stern - * K.Prasad - * Frederic Weisbecker - */ - -/* - * HW_breakpoint: a unified kernel/user-space hardware breakpoint facility, - * using the CPU's debug registers. - * This file contains the arch-independent routines. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - - -/* - * Constraints data - */ - -/* Number of pinned cpu breakpoints in a cpu */ -static DEFINE_PER_CPU(unsigned int, nr_cpu_bp_pinned[TYPE_MAX]); - -/* Number of pinned task breakpoints in a cpu */ -static DEFINE_PER_CPU(unsigned int *, nr_task_bp_pinned[TYPE_MAX]); - -/* Number of non-pinned cpu/task breakpoints in a cpu */ -static DEFINE_PER_CPU(unsigned int, nr_bp_flexible[TYPE_MAX]); - -static int nr_slots[TYPE_MAX]; - -/* Keep track of the breakpoints attached to tasks */ -static LIST_HEAD(bp_task_head); - -static int constraints_initialized; - -/* Gather the number of total pinned and un-pinned bp in a cpuset */ -struct bp_busy_slots { - unsigned int pinned; - unsigned int flexible; -}; - -/* Serialize accesses to the above constraints */ -static DEFINE_MUTEX(nr_bp_mutex); - -__weak int hw_breakpoint_weight(struct perf_event *bp) -{ - return 1; -} - -static inline enum bp_type_idx find_slot_idx(struct perf_event *bp) -{ - if (bp->attr.bp_type & HW_BREAKPOINT_RW) - return TYPE_DATA; - - return TYPE_INST; -} - -/* - * Report the maximum number of pinned breakpoints a task - * have in this cpu - */ -static unsigned int max_task_bp_pinned(int cpu, enum bp_type_idx type) -{ - int i; - unsigned int *tsk_pinned = per_cpu(nr_task_bp_pinned[type], cpu); - - for (i = nr_slots[type] - 1; i >= 0; i--) { - if (tsk_pinned[i] > 0) - return i + 1; - } - - return 0; -} - -/* - * Count the number of breakpoints of the same type and same task. - * The given event must be not on the list. - */ -static int task_bp_pinned(struct perf_event *bp, enum bp_type_idx type) -{ - struct task_struct *tsk = bp->hw.bp_target; - struct perf_event *iter; - int count = 0; - - list_for_each_entry(iter, &bp_task_head, hw.bp_list) { - if (iter->hw.bp_target == tsk && find_slot_idx(iter) == type) - count += hw_breakpoint_weight(iter); - } - - return count; -} - -/* - * Report the number of pinned/un-pinned breakpoints we have in - * a given cpu (cpu > -1) or in all of them (cpu = -1). - */ -static void -fetch_bp_busy_slots(struct bp_busy_slots *slots, struct perf_event *bp, - enum bp_type_idx type) -{ - int cpu = bp->cpu; - struct task_struct *tsk = bp->hw.bp_target; - - if (cpu >= 0) { - slots->pinned = per_cpu(nr_cpu_bp_pinned[type], cpu); - if (!tsk) - slots->pinned += max_task_bp_pinned(cpu, type); - else - slots->pinned += task_bp_pinned(bp, type); - slots->flexible = per_cpu(nr_bp_flexible[type], cpu); - - return; - } - - for_each_online_cpu(cpu) { - unsigned int nr; - - nr = per_cpu(nr_cpu_bp_pinned[type], cpu); - if (!tsk) - nr += max_task_bp_pinned(cpu, type); - else - nr += task_bp_pinned(bp, type); - - if (nr > slots->pinned) - slots->pinned = nr; - - nr = per_cpu(nr_bp_flexible[type], cpu); - - if (nr > slots->flexible) - slots->flexible = nr; - } -} - -/* - * For now, continue to consider flexible as pinned, until we can - * ensure no flexible event can ever be scheduled before a pinned event - * in a same cpu. - */ -static void -fetch_this_slot(struct bp_busy_slots *slots, int weight) -{ - slots->pinned += weight; -} - -/* - * Add a pinned breakpoint for the given task in our constraint table - */ -static void toggle_bp_task_slot(struct perf_event *bp, int cpu, bool enable, - enum bp_type_idx type, int weight) -{ - unsigned int *tsk_pinned; - int old_count = 0; - int old_idx = 0; - int idx = 0; - - old_count = task_bp_pinned(bp, type); - old_idx = old_count - 1; - idx = old_idx + weight; - - /* tsk_pinned[n] is the number of tasks having n breakpoints */ - tsk_pinned = per_cpu(nr_task_bp_pinned[type], cpu); - if (enable) { - tsk_pinned[idx]++; - if (old_count > 0) - tsk_pinned[old_idx]--; - } else { - tsk_pinned[idx]--; - if (old_count > 0) - tsk_pinned[old_idx]++; - } -} - -/* - * Add/remove the given breakpoint in our constraint table - */ -static void -toggle_bp_slot(struct perf_event *bp, bool enable, enum bp_type_idx type, - int weight) -{ - int cpu = bp->cpu; - struct task_struct *tsk = bp->hw.bp_target; - - /* Pinned counter cpu profiling */ - if (!tsk) { - - if (enable) - per_cpu(nr_cpu_bp_pinned[type], bp->cpu) += weight; - else - per_cpu(nr_cpu_bp_pinned[type], bp->cpu) -= weight; - return; - } - - /* Pinned counter task profiling */ - - if (!enable) - list_del(&bp->hw.bp_list); - - if (cpu >= 0) { - toggle_bp_task_slot(bp, cpu, enable, type, weight); - } else { - for_each_online_cpu(cpu) - toggle_bp_task_slot(bp, cpu, enable, type, weight); - } - - if (enable) - list_add_tail(&bp->hw.bp_list, &bp_task_head); -} - -/* - * Function to perform processor-specific cleanup during unregistration - */ -__weak void arch_unregister_hw_breakpoint(struct perf_event *bp) -{ - /* - * A weak stub function here for those archs that don't define - * it inside arch/.../kernel/hw_breakpoint.c - */ -} - -/* - * Contraints to check before allowing this new breakpoint counter: - * - * == Non-pinned counter == (Considered as pinned for now) - * - * - If attached to a single cpu, check: - * - * (per_cpu(nr_bp_flexible, cpu) || (per_cpu(nr_cpu_bp_pinned, cpu) - * + max(per_cpu(nr_task_bp_pinned, cpu)))) < HBP_NUM - * - * -> If there are already non-pinned counters in this cpu, it means - * there is already a free slot for them. - * Otherwise, we check that the maximum number of per task - * breakpoints (for this cpu) plus the number of per cpu breakpoint - * (for this cpu) doesn't cover every registers. - * - * - If attached to every cpus, check: - * - * (per_cpu(nr_bp_flexible, *) || (max(per_cpu(nr_cpu_bp_pinned, *)) - * + max(per_cpu(nr_task_bp_pinned, *)))) < HBP_NUM - * - * -> This is roughly the same, except we check the number of per cpu - * bp for every cpu and we keep the max one. Same for the per tasks - * breakpoints. - * - * - * == Pinned counter == - * - * - If attached to a single cpu, check: - * - * ((per_cpu(nr_bp_flexible, cpu) > 1) + per_cpu(nr_cpu_bp_pinned, cpu) - * + max(per_cpu(nr_task_bp_pinned, cpu))) < HBP_NUM - * - * -> Same checks as before. But now the nr_bp_flexible, if any, must keep - * one register at least (or they will never be fed). - * - * - If attached to every cpus, check: - * - * ((per_cpu(nr_bp_flexible, *) > 1) + max(per_cpu(nr_cpu_bp_pinned, *)) - * + max(per_cpu(nr_task_bp_pinned, *))) < HBP_NUM - */ -static int __reserve_bp_slot(struct perf_event *bp) -{ - struct bp_busy_slots slots = {0}; - enum bp_type_idx type; - int weight; - - /* We couldn't initialize breakpoint constraints on boot */ - if (!constraints_initialized) - return -ENOMEM; - - /* Basic checks */ - if (bp->attr.bp_type == HW_BREAKPOINT_EMPTY || - bp->attr.bp_type == HW_BREAKPOINT_INVALID) - return -EINVAL; - - type = find_slot_idx(bp); - weight = hw_breakpoint_weight(bp); - - fetch_bp_busy_slots(&slots, bp, type); - /* - * Simulate the addition of this breakpoint to the constraints - * and see the result. - */ - fetch_this_slot(&slots, weight); - - /* Flexible counters need to keep at least one slot */ - if (slots.pinned + (!!slots.flexible) > nr_slots[type]) - return -ENOSPC; - - toggle_bp_slot(bp, true, type, weight); - - return 0; -} - -int reserve_bp_slot(struct perf_event *bp) -{ - int ret; - - mutex_lock(&nr_bp_mutex); - - ret = __reserve_bp_slot(bp); - - mutex_unlock(&nr_bp_mutex); - - return ret; -} - -static void __release_bp_slot(struct perf_event *bp) -{ - enum bp_type_idx type; - int weight; - - type = find_slot_idx(bp); - weight = hw_breakpoint_weight(bp); - toggle_bp_slot(bp, false, type, weight); -} - -void release_bp_slot(struct perf_event *bp) -{ - mutex_lock(&nr_bp_mutex); - - arch_unregister_hw_breakpoint(bp); - __release_bp_slot(bp); - - mutex_unlock(&nr_bp_mutex); -} - -/* - * Allow the kernel debugger to reserve breakpoint slots without - * taking a lock using the dbg_* variant of for the reserve and - * release breakpoint slots. - */ -int dbg_reserve_bp_slot(struct perf_event *bp) -{ - if (mutex_is_locked(&nr_bp_mutex)) - return -1; - - return __reserve_bp_slot(bp); -} - -int dbg_release_bp_slot(struct perf_event *bp) -{ - if (mutex_is_locked(&nr_bp_mutex)) - return -1; - - __release_bp_slot(bp); - - return 0; -} - -static int validate_hw_breakpoint(struct perf_event *bp) -{ - int ret; - - ret = arch_validate_hwbkpt_settings(bp); - if (ret) - return ret; - - if (arch_check_bp_in_kernelspace(bp)) { - if (bp->attr.exclude_kernel) - return -EINVAL; - /* - * Don't let unprivileged users set a breakpoint in the trap - * path to avoid trap recursion attacks. - */ - if (!capable(CAP_SYS_ADMIN)) - return -EPERM; - } - - return 0; -} - -int register_perf_hw_breakpoint(struct perf_event *bp) -{ - int ret; - - ret = reserve_bp_slot(bp); - if (ret) - return ret; - - ret = validate_hw_breakpoint(bp); - - /* if arch_validate_hwbkpt_settings() fails then release bp slot */ - if (ret) - release_bp_slot(bp); - - return ret; -} - -/** - * register_user_hw_breakpoint - register a hardware breakpoint for user space - * @attr: breakpoint attributes - * @triggered: callback to trigger when we hit the breakpoint - * @tsk: pointer to 'task_struct' of the process to which the address belongs - */ -struct perf_event * -register_user_hw_breakpoint(struct perf_event_attr *attr, - perf_overflow_handler_t triggered, - struct task_struct *tsk) -{ - return perf_event_create_kernel_counter(attr, -1, tsk, triggered); -} -EXPORT_SYMBOL_GPL(register_user_hw_breakpoint); - -/** - * modify_user_hw_breakpoint - modify a user-space hardware breakpoint - * @bp: the breakpoint structure to modify - * @attr: new breakpoint attributes - * @triggered: callback to trigger when we hit the breakpoint - * @tsk: pointer to 'task_struct' of the process to which the address belongs - */ -int modify_user_hw_breakpoint(struct perf_event *bp, struct perf_event_attr *attr) -{ - u64 old_addr = bp->attr.bp_addr; - u64 old_len = bp->attr.bp_len; - int old_type = bp->attr.bp_type; - int err = 0; - - perf_event_disable(bp); - - bp->attr.bp_addr = attr->bp_addr; - bp->attr.bp_type = attr->bp_type; - bp->attr.bp_len = attr->bp_len; - - if (attr->disabled) - goto end; - - err = validate_hw_breakpoint(bp); - if (!err) - perf_event_enable(bp); - - if (err) { - bp->attr.bp_addr = old_addr; - bp->attr.bp_type = old_type; - bp->attr.bp_len = old_len; - if (!bp->attr.disabled) - perf_event_enable(bp); - - return err; - } - -end: - bp->attr.disabled = attr->disabled; - - return 0; -} -EXPORT_SYMBOL_GPL(modify_user_hw_breakpoint); - -/** - * unregister_hw_breakpoint - unregister a user-space hardware breakpoint - * @bp: the breakpoint structure to unregister - */ -void unregister_hw_breakpoint(struct perf_event *bp) -{ - if (!bp) - return; - perf_event_release_kernel(bp); -} -EXPORT_SYMBOL_GPL(unregister_hw_breakpoint); - -/** - * register_wide_hw_breakpoint - register a wide breakpoint in the kernel - * @attr: breakpoint attributes - * @triggered: callback to trigger when we hit the breakpoint - * - * @return a set of per_cpu pointers to perf events - */ -struct perf_event * __percpu * -register_wide_hw_breakpoint(struct perf_event_attr *attr, - perf_overflow_handler_t triggered) -{ - struct perf_event * __percpu *cpu_events, **pevent, *bp; - long err; - int cpu; - - cpu_events = alloc_percpu(typeof(*cpu_events)); - if (!cpu_events) - return (void __percpu __force *)ERR_PTR(-ENOMEM); - - get_online_cpus(); - for_each_online_cpu(cpu) { - pevent = per_cpu_ptr(cpu_events, cpu); - bp = perf_event_create_kernel_counter(attr, cpu, NULL, triggered); - - *pevent = bp; - - if (IS_ERR(bp)) { - err = PTR_ERR(bp); - goto fail; - } - } - put_online_cpus(); - - return cpu_events; - -fail: - for_each_online_cpu(cpu) { - pevent = per_cpu_ptr(cpu_events, cpu); - if (IS_ERR(*pevent)) - break; - unregister_hw_breakpoint(*pevent); - } - put_online_cpus(); - - free_percpu(cpu_events); - return (void __percpu __force *)ERR_PTR(err); -} -EXPORT_SYMBOL_GPL(register_wide_hw_breakpoint); - -/** - * unregister_wide_hw_breakpoint - unregister a wide breakpoint in the kernel - * @cpu_events: the per cpu set of events to unregister - */ -void unregister_wide_hw_breakpoint(struct perf_event * __percpu *cpu_events) -{ - int cpu; - struct perf_event **pevent; - - for_each_possible_cpu(cpu) { - pevent = per_cpu_ptr(cpu_events, cpu); - unregister_hw_breakpoint(*pevent); - } - free_percpu(cpu_events); -} -EXPORT_SYMBOL_GPL(unregister_wide_hw_breakpoint); - -static struct notifier_block hw_breakpoint_exceptions_nb = { - .notifier_call = hw_breakpoint_exceptions_notify, - /* we need to be notified first */ - .priority = 0x7fffffff -}; - -static void bp_perf_event_destroy(struct perf_event *event) -{ - release_bp_slot(event); -} - -static int hw_breakpoint_event_init(struct perf_event *bp) -{ - int err; - - if (bp->attr.type != PERF_TYPE_BREAKPOINT) - return -ENOENT; - - err = register_perf_hw_breakpoint(bp); - if (err) - return err; - - bp->destroy = bp_perf_event_destroy; - - return 0; -} - -static int hw_breakpoint_add(struct perf_event *bp, int flags) -{ - if (!(flags & PERF_EF_START)) - bp->hw.state = PERF_HES_STOPPED; - - return arch_install_hw_breakpoint(bp); -} - -static void hw_breakpoint_del(struct perf_event *bp, int flags) -{ - arch_uninstall_hw_breakpoint(bp); -} - -static void hw_breakpoint_start(struct perf_event *bp, int flags) -{ - bp->hw.state = 0; -} - -static void hw_breakpoint_stop(struct perf_event *bp, int flags) -{ - bp->hw.state = PERF_HES_STOPPED; -} - -static struct pmu perf_breakpoint = { - .task_ctx_nr = perf_sw_context, /* could eventually get its own */ - - .event_init = hw_breakpoint_event_init, - .add = hw_breakpoint_add, - .del = hw_breakpoint_del, - .start = hw_breakpoint_start, - .stop = hw_breakpoint_stop, - .read = hw_breakpoint_pmu_read, -}; - -int __init init_hw_breakpoint(void) -{ - unsigned int **task_bp_pinned; - int cpu, err_cpu; - int i; - - for (i = 0; i < TYPE_MAX; i++) - nr_slots[i] = hw_breakpoint_slots(i); - - for_each_possible_cpu(cpu) { - for (i = 0; i < TYPE_MAX; i++) { - task_bp_pinned = &per_cpu(nr_task_bp_pinned[i], cpu); - *task_bp_pinned = kzalloc(sizeof(int) * nr_slots[i], - GFP_KERNEL); - if (!*task_bp_pinned) - goto err_alloc; - } - } - - constraints_initialized = 1; - - perf_pmu_register(&perf_breakpoint, "breakpoint", PERF_TYPE_BREAKPOINT); - - return register_die_notifier(&hw_breakpoint_exceptions_nb); - - err_alloc: - for_each_possible_cpu(err_cpu) { - if (err_cpu == cpu) - break; - for (i = 0; i < TYPE_MAX; i++) - kfree(per_cpu(nr_task_bp_pinned[i], cpu)); - } - - return -ENOMEM; -} - - -- cgit v0.10.2 From 3772d26d87efc2d91b2e4247e0001c89ed09a980 Mon Sep 17 00:00:00 2001 From: Sage Weil Date: Tue, 3 May 2011 09:28:08 -0700 Subject: ceph: use ihold() when i_lock is held See 0444d76ae64fffc7851797fc1b6ebdbb44ac504a. Signed-off-by: Sage Weil diff --git a/fs/ceph/caps.c b/fs/ceph/caps.c index 5323c33..010ba9c 100644 --- a/fs/ceph/caps.c +++ b/fs/ceph/caps.c @@ -1357,7 +1357,7 @@ void __ceph_mark_dirty_caps(struct ceph_inode_info *ci, int mask) list_add(&ci->i_dirty_item, &mdsc->cap_dirty); spin_unlock(&mdsc->cap_dirty_lock); if (ci->i_flushing_caps == 0) { - igrab(inode); + ihold(inode); dirty |= I_DIRTY_SYNC; } } @@ -1991,7 +1991,7 @@ static void __take_cap_refs(struct ceph_inode_info *ci, int got) ci->i_wr_ref++; if (got & CEPH_CAP_FILE_BUFFER) { if (ci->i_wrbuffer_ref == 0) - igrab(&ci->vfs_inode); + ihold(&ci->vfs_inode); ci->i_wrbuffer_ref++; dout("__take_cap_refs %p wrbuffer %d -> %d (?)\n", &ci->vfs_inode, ci->i_wrbuffer_ref-1, ci->i_wrbuffer_ref); -- cgit v0.10.2 From ca20892db7567c40e8ed0668f46cf0d085d7db6d Mon Sep 17 00:00:00 2001 From: Henry C Chang Date: Tue, 3 May 2011 02:29:56 +0000 Subject: libceph: fix ceph_msg_new error path If memory allocation failed, calling ceph_msg_put() will cause GPF since some of ceph_msg variables are not initialized first. Fix Bug #970. Signed-off-by: Henry C Chang Signed-off-by: Sage Weil diff --git a/net/ceph/messenger.c b/net/ceph/messenger.c index 05f3578..e15a82c 100644 --- a/net/ceph/messenger.c +++ b/net/ceph/messenger.c @@ -2267,6 +2267,19 @@ struct ceph_msg *ceph_msg_new(int type, int front_len, gfp_t flags) m->more_to_follow = false; m->pool = NULL; + /* middle */ + m->middle = NULL; + + /* data */ + m->nr_pages = 0; + m->page_alignment = 0; + m->pages = NULL; + m->pagelist = NULL; + m->bio = NULL; + m->bio_iter = NULL; + m->bio_seg = 0; + m->trail = NULL; + /* front */ if (front_len) { if (front_len > PAGE_CACHE_SIZE) { @@ -2286,19 +2299,6 @@ struct ceph_msg *ceph_msg_new(int type, int front_len, gfp_t flags) } m->front.iov_len = front_len; - /* middle */ - m->middle = NULL; - - /* data */ - m->nr_pages = 0; - m->page_alignment = 0; - m->pages = NULL; - m->pagelist = NULL; - m->bio = NULL; - m->bio_iter = NULL; - m->bio_seg = 0; - m->trail = NULL; - dout("ceph_msg_new %p front %d\n", m, front_len); return m; -- cgit v0.10.2 From 8c71897be2ddfd84969412635ca42fa9e137f7b6 Mon Sep 17 00:00:00 2001 From: Henry C Chang Date: Tue, 3 May 2011 09:45:16 +0000 Subject: ceph: handle ceph_osdc_new_request failure in ceph_writepages_start We should unlock the page and return -ENOMEM if ceph_osdc_new_request failed. Signed-off-by: Henry C Chang Signed-off-by: Sage Weil diff --git a/fs/ceph/addr.c b/fs/ceph/addr.c index e159c52..38b8ab5 100644 --- a/fs/ceph/addr.c +++ b/fs/ceph/addr.c @@ -775,6 +775,13 @@ get_more_pages: ci->i_truncate_seq, ci->i_truncate_size, &inode->i_mtime, true, 1, 0); + + if (!req) { + rc = -ENOMEM; + unlock_page(page); + break; + } + max_pages = req->r_num_pages; alloc_page_vec(fsc, req); -- cgit v0.10.2 From 4ad12621e442b7a072e81270808f617cb65c5672 Mon Sep 17 00:00:00 2001 From: Sage Weil Date: Tue, 3 May 2011 09:23:36 -0700 Subject: libceph: fix ceph_osdc_alloc_request error checks ceph_osdc_alloc_request returns NULL on failure. Signed-off-by: Sage Weil diff --git a/drivers/block/rbd.c b/drivers/block/rbd.c index 16dc364..3e90471 100644 --- a/drivers/block/rbd.c +++ b/drivers/block/rbd.c @@ -777,9 +777,9 @@ static int rbd_do_request(struct request *rq, ops, false, GFP_NOIO, pages, bio); - if (IS_ERR(req)) { + if (!req) { up_read(&header->snap_rwsem); - ret = PTR_ERR(req); + ret = -ENOMEM; goto done_pages; } diff --git a/net/ceph/osd_client.c b/net/ceph/osd_client.c index 5a80f41..6b5dda1 100644 --- a/net/ceph/osd_client.c +++ b/net/ceph/osd_client.c @@ -470,8 +470,8 @@ struct ceph_osd_request *ceph_osdc_new_request(struct ceph_osd_client *osdc, snapc, ops, use_mempool, GFP_NOFS, NULL, NULL); - if (IS_ERR(req)) - return req; + if (!req) + return NULL; /* calculate max write size */ calc_layout(osdc, vino, layout, off, plen, req, ops); -- cgit v0.10.2 From 005967a1df80980acb47c72d758ec05059105492 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Sat, 30 Apr 2011 22:28:20 +0200 Subject: ASoC: JZ4740: Fix i2s shutdown The i2s shutdown callback has the check whether it should be disabled reversed. Currently it is disabled if another stream is still active, but kept enabled if the last stream is closed. This patch fixes it. Signed-off-by: Lars-Peter Clausen Acked-by: Liam Girdwood Signed-off-by: Mark Brown diff --git a/sound/soc/jz4740/jz4740-i2s.c b/sound/soc/jz4740/jz4740-i2s.c index 419bf4f..cd22a54 100644 --- a/sound/soc/jz4740/jz4740-i2s.c +++ b/sound/soc/jz4740/jz4740-i2s.c @@ -133,7 +133,7 @@ static void jz4740_i2s_shutdown(struct snd_pcm_substream *substream, struct jz4740_i2s *i2s = snd_soc_dai_get_drvdata(dai); uint32_t conf; - if (!dai->active) + if (dai->active) return; conf = jz4740_i2s_read(i2s, JZ_REG_AIC_CONF); -- cgit v0.10.2 From 4f0871a6c7811a433513c3788a7cce27033bb8b8 Mon Sep 17 00:00:00 2001 From: Andiry Xu Date: Tue, 19 Apr 2011 17:17:39 +0800 Subject: xHCI: Clear PLC in xhci_bus_resume() This patch clears PORT_PLC if xhci_bus_resume() resumes a previous suspended port, because if a port transition from U3 to U0 state, it will report a port link state change, and software should clear the corresponding PLC bit. It also uses hcd->speed to check if a port is a USB2 protocol port. The patch fixes the issue that USB keyboard can not wakeup system from hibernation. Signed-off-by: Andiry Xu Signed-off-by: Sarah Sharp diff --git a/drivers/usb/host/xhci-hub.c b/drivers/usb/host/xhci-hub.c index a78f2eb..73f75d2 100644 --- a/drivers/usb/host/xhci-hub.c +++ b/drivers/usb/host/xhci-hub.c @@ -777,7 +777,7 @@ int xhci_bus_suspend(struct usb_hcd *hcd) if (t1 != t2) xhci_writel(xhci, t2, port_array[port_index]); - if (DEV_HIGHSPEED(t1)) { + if (hcd->speed != HCD_USB3) { /* enable remote wake up for USB 2.0 */ u32 __iomem *addr; u32 tmp; @@ -866,6 +866,21 @@ int xhci_bus_resume(struct usb_hcd *hcd) temp |= PORT_LINK_STROBE | XDEV_U0; xhci_writel(xhci, temp, port_array[port_index]); } + /* wait for the port to enter U0 and report port link + * state change. + */ + spin_unlock_irqrestore(&xhci->lock, flags); + msleep(20); + spin_lock_irqsave(&xhci->lock, flags); + + /* Clear PLC */ + temp = xhci_readl(xhci, port_array[port_index]); + if (temp & PORT_PLC) { + temp = xhci_port_state_to_neutral(temp); + temp |= PORT_PLC; + xhci_writel(xhci, temp, port_array[port_index]); + } + slot_id = xhci_find_slot_id_by_port(hcd, xhci, port_index + 1); if (slot_id) @@ -873,7 +888,7 @@ int xhci_bus_resume(struct usb_hcd *hcd) } else xhci_writel(xhci, temp, port_array[port_index]); - if (DEV_HIGHSPEED(temp)) { + if (hcd->speed != HCD_USB3) { /* disable remote wake up for USB 2.0 */ u32 __iomem *addr; u32 tmp; -- cgit v0.10.2 From 9005fcd89c24f2a0fa6f87588b9208aae6d4d6cd Mon Sep 17 00:00:00 2001 From: Harry Wei Date: Thu, 28 Apr 2011 09:30:01 +0800 Subject: staging: Remove a warning for drivers/staging/wlan-ng/cfg80211.c Hi us, When i was compiling kernel, a warning happened to me. The warning said like following. drivers/staging/wlan-ng/cfg80211.c:709: warning: initialization from incompatible pointer type. See http://s1202.photobucket.com/albums/bb364/harrywei/?action=view¤t=patched2.png for more details. So i patch like following. Signed-off-by: Harry Wei Acked-by: Randy Dunlap Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/staging/wlan-ng/cfg80211.c b/drivers/staging/wlan-ng/cfg80211.c index 6a71f52..7637839 100644 --- a/drivers/staging/wlan-ng/cfg80211.c +++ b/drivers/staging/wlan-ng/cfg80211.c @@ -273,7 +273,7 @@ exit: } int prism2_set_default_key(struct wiphy *wiphy, struct net_device *dev, - u8 key_index) + u8 key_index, bool unicast, bool multicast) { wlandevice_t *wlandev = dev->ml_priv; -- cgit v0.10.2 From c055f5b2614b4f758ae6cc86733f31fa4c2c5844 Mon Sep 17 00:00:00 2001 From: James Bottomley Date: Sun, 1 May 2011 09:42:07 -0500 Subject: [SCSI] fix oops in scsi_run_queue() The recent commit closing the race window in device teardown: commit 86cbfb5607d4b81b1a993ff689bbd2addd5d3a9b Author: James Bottomley Date: Fri Apr 22 10:39:59 2011 -0500 [SCSI] put stricter guards on queue dead checks is causing a potential NULL deref in scsi_run_queue() because the q->queuedata may already be NULL by the time this function is called. Since we shouldn't be running a queue that is being torn down, simply add a NULL check in scsi_run_queue() to forestall this. Tested-by: Jim Schutt Cc: stable@kernel.org Signed-off-by: James Bottomley diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c index e9901b8..0bac91e 100644 --- a/drivers/scsi/scsi_lib.c +++ b/drivers/scsi/scsi_lib.c @@ -400,10 +400,15 @@ static inline int scsi_host_is_busy(struct Scsi_Host *shost) static void scsi_run_queue(struct request_queue *q) { struct scsi_device *sdev = q->queuedata; - struct Scsi_Host *shost = sdev->host; + struct Scsi_Host *shost; LIST_HEAD(starved_list); unsigned long flags; + /* if the device is dead, sdev will be NULL, so no queue to run */ + if (!sdev) + return; + + shost = sdev->host; if (scsi_target(sdev)->single_lun) scsi_single_lun_run(sdev); -- cgit v0.10.2 From ed77cc122a8402db8f9c3492649aa0c3fee7b385 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Tue, 3 May 2011 18:25:34 +0100 Subject: ASoC: Don't crash on PM operations The move over to exposing snd_soc_register_card() let the initialisation of the driver data we use to find the card in PM operations go AWOL. Fix this by setting the driver data when we register the card. Signed-off-by: Mark Brown Acked-by: Liam Girdwood diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index d8562ce..dd55d10 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -3291,6 +3291,8 @@ int snd_soc_register_card(struct snd_soc_card *card) if (!card->name || !card->dev) return -EINVAL; + dev_set_drvdata(card->dev, card); + snd_soc_initialize_card_lists(card); soc_init_card_debugfs(card); -- cgit v0.10.2 From 9ab88434e8b5ffc5a638b5b1d3b9a67dceb28e5d Mon Sep 17 00:00:00 2001 From: xingchao Date: Wed, 27 Apr 2011 16:58:54 -0400 Subject: ASoC: sst_platform: add hw_free callback to fix resource leak Signed-off-by: xingchao Acked-by: Liam Girdwood Signed-off-by: Mark Brown diff --git a/sound/soc/mid-x86/sst_platform.c b/sound/soc/mid-x86/sst_platform.c index d567c32..6b1f9d3 100644 --- a/sound/soc/mid-x86/sst_platform.c +++ b/sound/soc/mid-x86/sst_platform.c @@ -376,6 +376,11 @@ static int sst_platform_pcm_hw_params(struct snd_pcm_substream *substream, return 0; } +static int sst_platform_pcm_hw_free(struct snd_pcm_substream *substream) +{ + return snd_pcm_lib_free_pages(substream); +} + static struct snd_pcm_ops sst_platform_ops = { .open = sst_platform_open, .close = sst_platform_close, @@ -384,6 +389,7 @@ static struct snd_pcm_ops sst_platform_ops = { .trigger = sst_platform_pcm_trigger, .pointer = sst_platform_pcm_pointer, .hw_params = sst_platform_pcm_hw_params, + .hw_free = sst_platform_pcm_hw_free, }; static void sst_pcm_free(struct snd_pcm *pcm) -- cgit v0.10.2 From 57a503c61db077b923e23f36050c02166a4a1db2 Mon Sep 17 00:00:00 2001 From: Viresh KUMAR Date: Mon, 2 May 2011 18:36:45 +0000 Subject: net/stmmac: Move "#include " to linux/stmmac.h MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit stmmac.h uses struct platform_device and doesn't include . Whereas drivers/net/stmmac/stmmac.h includes it, but doesn't directly use it. And so we get following compilation warning while using this file: warning: ‘struct platform_device’ declared inside parameter list This patch includes in linux/stmmac.h and removes it from drivers/net/stmmac/stmmac.h Signed-off-by: Viresh Kumar Acked-by: Giuseppe Cavallaro Signed-off-by: David S. Miller diff --git a/drivers/net/stmmac/stmmac.h b/drivers/net/stmmac/stmmac.h index 5f06c47..2b076b3 100644 --- a/drivers/net/stmmac/stmmac.h +++ b/drivers/net/stmmac/stmmac.h @@ -21,7 +21,6 @@ *******************************************************************************/ #define DRV_MODULE_VERSION "Nov_2010" -#include #include #include "common.h" diff --git a/include/linux/stmmac.h b/include/linux/stmmac.h index f29197a..9529e49 100644 --- a/include/linux/stmmac.h +++ b/include/linux/stmmac.h @@ -26,6 +26,8 @@ #ifndef __STMMAC_PLATFORM_DATA #define __STMMAC_PLATFORM_DATA +#include + /* platform data for platform device structure's platform_data field */ /* Private data for the STM on-board ethernet driver */ -- cgit v0.10.2 From cce2c56e7666199916525907dc817209dd58287c Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Tue, 3 May 2011 16:10:25 -0700 Subject: logfs: initialize superblock entries earlier In particular, s_freeing_list needs to be initialized early, since it is used on some of the error paths when mounts fail. The mapping inode, for example, would be initialized and then free'd on an error path before s_freeing_list was initialized, but the inode drop operation needs the s_freeing_list to be set up. Normally you'd never see this, because not only is logfs fairly rare, but a successful mount will never have any issues. Reported-by: werner Signed-off-by: Linus Torvalds diff --git a/fs/logfs/super.c b/fs/logfs/super.c index 33435e4..ce03a18 100644 --- a/fs/logfs/super.c +++ b/fs/logfs/super.c @@ -480,10 +480,6 @@ static int logfs_read_sb(struct super_block *sb, int read_only) !read_only) return -EIO; - mutex_init(&super->s_dirop_mutex); - mutex_init(&super->s_object_alias_mutex); - INIT_LIST_HEAD(&super->s_freeing_list); - ret = logfs_init_rw(sb); if (ret) return ret; @@ -601,6 +597,10 @@ static struct dentry *logfs_mount(struct file_system_type *type, int flags, if (!super) return ERR_PTR(-ENOMEM); + mutex_init(&super->s_dirop_mutex); + mutex_init(&super->s_object_alias_mutex); + INIT_LIST_HEAD(&super->s_freeing_list); + if (!devname) err = logfs_get_sb_bdev(super, type, devname); else if (strncmp(devname, "mtd", 3)) -- cgit v0.10.2 From e2c85d8e3974c9041ad7b080846b28d2243e771b Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Tue, 3 May 2011 15:15:55 -0400 Subject: drm/radeon/kms: add some new pci ids Signed-off-by: Alex Deucher Cc: stable@kernel.org Signed-off-by: Dave Airlie diff --git a/include/drm/drm_pciids.h b/include/drm/drm_pciids.h index 816e30c..f04b2a3 100644 --- a/include/drm/drm_pciids.h +++ b/include/drm/drm_pciids.h @@ -155,6 +155,7 @@ {0x1002, 0x6719, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_CAYMAN|RADEON_NEW_MEMMAP}, \ {0x1002, 0x671c, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_CAYMAN|RADEON_NEW_MEMMAP}, \ {0x1002, 0x671d, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_CAYMAN|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x671f, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_CAYMAN|RADEON_NEW_MEMMAP}, \ {0x1002, 0x6720, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_BARTS|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ {0x1002, 0x6721, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_BARTS|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ {0x1002, 0x6722, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_BARTS|RADEON_NEW_MEMMAP}, \ @@ -167,6 +168,7 @@ {0x1002, 0x6729, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_BARTS|RADEON_NEW_MEMMAP}, \ {0x1002, 0x6738, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_BARTS|RADEON_NEW_MEMMAP}, \ {0x1002, 0x6739, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_BARTS|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x673e, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_BARTS|RADEON_NEW_MEMMAP}, \ {0x1002, 0x6740, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_TURKS|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ {0x1002, 0x6741, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_TURKS|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ {0x1002, 0x6742, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_TURKS|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ @@ -199,6 +201,7 @@ {0x1002, 0x688D, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_CYPRESS|RADEON_NEW_MEMMAP}, \ {0x1002, 0x6898, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_CYPRESS|RADEON_NEW_MEMMAP}, \ {0x1002, 0x6899, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_CYPRESS|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x689b, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_CYPRESS|RADEON_NEW_MEMMAP}, \ {0x1002, 0x689c, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_HEMLOCK|RADEON_NEW_MEMMAP}, \ {0x1002, 0x689d, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_HEMLOCK|RADEON_NEW_MEMMAP}, \ {0x1002, 0x689e, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_CYPRESS|RADEON_NEW_MEMMAP}, \ @@ -209,7 +212,9 @@ {0x1002, 0x68b0, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_JUNIPER|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ {0x1002, 0x68b8, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_JUNIPER|RADEON_NEW_MEMMAP}, \ {0x1002, 0x68b9, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_JUNIPER|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x68ba, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_JUNIPER|RADEON_NEW_MEMMAP}, \ {0x1002, 0x68be, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_JUNIPER|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x68bf, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_JUNIPER|RADEON_NEW_MEMMAP}, \ {0x1002, 0x68c0, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_REDWOOD|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ {0x1002, 0x68c1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_REDWOOD|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ {0x1002, 0x68c7, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_REDWOOD|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ -- cgit v0.10.2 From eaa4f5e1d0b816291a59a47917e569c0384f2b6f Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Sun, 1 May 2011 20:16:30 +1000 Subject: drm/radeon: fix regression on atom cards with hardcoded EDID record. Since fafcf94e2b5732d1e13b440291c53115d2b172e9 introduced an edid size, it seems to have broken this path. This manifest as oops on T500 Lenovo laptops with dual graphics primarily. Fixes: https://bugzilla.kernel.org/show_bug.cgi?id=33812 cc: stable@kernel.org Reviewed-by: Alex Deucher Signed-off-by: Dave Airlie diff --git a/drivers/gpu/drm/radeon/radeon_atombios.c b/drivers/gpu/drm/radeon/radeon_atombios.c index f5d12fb..f116516 100644 --- a/drivers/gpu/drm/radeon/radeon_atombios.c +++ b/drivers/gpu/drm/radeon/radeon_atombios.c @@ -1599,9 +1599,10 @@ struct radeon_encoder_atom_dig *radeon_atombios_get_lvds_info(struct memcpy((u8 *)edid, (u8 *)&fake_edid_record->ucFakeEDIDString[0], fake_edid_record->ucFakeEDIDLength); - if (drm_edid_is_valid(edid)) + if (drm_edid_is_valid(edid)) { rdev->mode_info.bios_hardcoded_edid = edid; - else + rdev->mode_info.bios_hardcoded_edid_size = edid_size; + } else kfree(edid); } } -- cgit v0.10.2 From 498548ec69c6897fe4376b2ca90758762fa0b817 Mon Sep 17 00:00:00 2001 From: Christopher James Halse Rogers Date: Wed, 27 Apr 2011 16:10:57 +1000 Subject: drm: Send pending vblank events before disabling vblank. This is the least-bad behaviour. It means that we signal the vblank event before it actually happens, but since we're disabling vblanks there's no guarantee that it will *ever* happen otherwise. This prevents GL applications which use WaitMSC from hanging indefinitely. Signed-off-by: Christopher James Halse Rogers Signed-off-by: Dave Airlie diff --git a/drivers/gpu/drm/drm_irq.c b/drivers/gpu/drm/drm_irq.c index 741457b..a1f12cb 100644 --- a/drivers/gpu/drm/drm_irq.c +++ b/drivers/gpu/drm/drm_irq.c @@ -932,11 +932,34 @@ EXPORT_SYMBOL(drm_vblank_put); void drm_vblank_off(struct drm_device *dev, int crtc) { + struct drm_pending_vblank_event *e, *t; + struct timeval now; unsigned long irqflags; + unsigned int seq; spin_lock_irqsave(&dev->vbl_lock, irqflags); vblank_disable_and_save(dev, crtc); DRM_WAKEUP(&dev->vbl_queue[crtc]); + + /* Send any queued vblank events, lest the natives grow disquiet */ + seq = drm_vblank_count_and_time(dev, crtc, &now); + list_for_each_entry_safe(e, t, &dev->vblank_event_list, base.link) { + if (e->pipe != crtc) + continue; + DRM_DEBUG("Sending premature vblank event on disable: \ + wanted %d, current %d\n", + e->event.sequence, seq); + + e->event.sequence = seq; + e->event.tv_sec = now.tv_sec; + e->event.tv_usec = now.tv_usec; + drm_vblank_put(dev, e->pipe); + list_move_tail(&e->base.link, &e->base.file_priv->event_list); + wake_up_interruptible(&e->base.file_priv->event_wait); + trace_drm_vblank_event_delivered(e->base.pid, e->pipe, + e->event.sequence); + } + spin_unlock_irqrestore(&dev->vbl_lock, irqflags); } EXPORT_SYMBOL(drm_vblank_off); -- cgit v0.10.2 From 8aeb96f80232e9a701b5c4715504f4c9173978bd Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Tue, 3 May 2011 19:28:02 -0400 Subject: drm/radeon/kms: fix gart setup on fusion parts (v2) Out of the entire GART/VM subsystem, the hw designers changed the location of 3 regs. v2: airlied: add parameter for userspace to work from. Signed-off-by: Alex Deucher Signed-off-by: Jerome Glisse Cc: stable@kernel.org Signed-off-by: Dave Airlie diff --git a/drivers/gpu/drm/radeon/evergreen.c b/drivers/gpu/drm/radeon/evergreen.c index e9bc135..c20eac3 100644 --- a/drivers/gpu/drm/radeon/evergreen.c +++ b/drivers/gpu/drm/radeon/evergreen.c @@ -862,9 +862,15 @@ int evergreen_pcie_gart_enable(struct radeon_device *rdev) SYSTEM_ACCESS_MODE_NOT_IN_SYS | SYSTEM_APERTURE_UNMAPPED_ACCESS_PASS_THRU | EFFECTIVE_L1_TLB_SIZE(5) | EFFECTIVE_L1_QUEUE_SIZE(5); - WREG32(MC_VM_MD_L1_TLB0_CNTL, tmp); - WREG32(MC_VM_MD_L1_TLB1_CNTL, tmp); - WREG32(MC_VM_MD_L1_TLB2_CNTL, tmp); + if (rdev->flags & RADEON_IS_IGP) { + WREG32(FUS_MC_VM_MD_L1_TLB0_CNTL, tmp); + WREG32(FUS_MC_VM_MD_L1_TLB1_CNTL, tmp); + WREG32(FUS_MC_VM_MD_L1_TLB2_CNTL, tmp); + } else { + WREG32(MC_VM_MD_L1_TLB0_CNTL, tmp); + WREG32(MC_VM_MD_L1_TLB1_CNTL, tmp); + WREG32(MC_VM_MD_L1_TLB2_CNTL, tmp); + } WREG32(MC_VM_MB_L1_TLB0_CNTL, tmp); WREG32(MC_VM_MB_L1_TLB1_CNTL, tmp); WREG32(MC_VM_MB_L1_TLB2_CNTL, tmp); @@ -2923,11 +2929,6 @@ static int evergreen_startup(struct radeon_device *rdev) rdev->asic->copy = NULL; dev_warn(rdev->dev, "failed blitter (%d) falling back to memcpy\n", r); } - /* XXX: ontario has problems blitting to gart at the moment */ - if (rdev->family == CHIP_PALM) { - rdev->asic->copy = NULL; - radeon_ttm_set_active_vram_size(rdev, rdev->mc.visible_vram_size); - } /* allocate wb buffer */ r = radeon_wb_init(rdev); diff --git a/drivers/gpu/drm/radeon/evergreend.h b/drivers/gpu/drm/radeon/evergreend.h index 9aaa3f0..9453384 100644 --- a/drivers/gpu/drm/radeon/evergreend.h +++ b/drivers/gpu/drm/radeon/evergreend.h @@ -221,6 +221,11 @@ #define MC_VM_MD_L1_TLB0_CNTL 0x2654 #define MC_VM_MD_L1_TLB1_CNTL 0x2658 #define MC_VM_MD_L1_TLB2_CNTL 0x265C + +#define FUS_MC_VM_MD_L1_TLB0_CNTL 0x265C +#define FUS_MC_VM_MD_L1_TLB1_CNTL 0x2660 +#define FUS_MC_VM_MD_L1_TLB2_CNTL 0x2664 + #define MC_VM_SYSTEM_APERTURE_DEFAULT_ADDR 0x203C #define MC_VM_SYSTEM_APERTURE_HIGH_ADDR 0x2038 #define MC_VM_SYSTEM_APERTURE_LOW_ADDR 0x2034 diff --git a/drivers/gpu/drm/radeon/radeon_kms.c b/drivers/gpu/drm/radeon/radeon_kms.c index 871df03..bd58af6 100644 --- a/drivers/gpu/drm/radeon/radeon_kms.c +++ b/drivers/gpu/drm/radeon/radeon_kms.c @@ -234,6 +234,9 @@ int radeon_info_ioctl(struct drm_device *dev, void *data, struct drm_file *filp) return -EINVAL; } break; + case RADEON_INFO_FUSION_GART_WORKING: + value = 1; + break; default: DRM_DEBUG_KMS("Invalid request %d\n", info->request); return -EINVAL; diff --git a/include/drm/radeon_drm.h b/include/drm/radeon_drm.h index 7aa5ddd..787f7b6 100644 --- a/include/drm/radeon_drm.h +++ b/include/drm/radeon_drm.h @@ -910,6 +910,7 @@ struct drm_radeon_cs { #define RADEON_INFO_CLOCK_CRYSTAL_FREQ 0x09 /* clock crystal frequency */ #define RADEON_INFO_NUM_BACKENDS 0x0a /* DB/backends for r600+ - need for OQ */ #define RADEON_INFO_NUM_TILE_PIPES 0x0b /* tile pipes for r600+ */ +#define RADEON_INFO_FUSION_GART_WORKING 0x0c /* fusion writes to GTT were broken before this */ struct drm_radeon_info { uint32_t request; -- cgit v0.10.2 From 417da66fa9d2f14b1a90b04095413b87907d8183 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Tue, 3 May 2011 19:42:43 -0700 Subject: ipv4: Rework ipmr_rt_fib_lookup() flow key initialization. Use information from the skb as much as possible, currently this means daddr, saddr, and TOS. Signed-off-by: David S. Miller diff --git a/net/ipv4/ipmr.c b/net/ipv4/ipmr.c index c81b9b6..3ad38a4 100644 --- a/net/ipv4/ipmr.c +++ b/net/ipv4/ipmr.c @@ -1788,12 +1788,14 @@ dont_forward: return 0; } -static struct mr_table *ipmr_rt_fib_lookup(struct net *net, struct rtable *rt) +static struct mr_table *ipmr_rt_fib_lookup(struct net *net, struct sk_buff *skb) { + struct rtable *rt = skb_rtable(skb); + struct iphdr *iph = ip_hdr(skb); struct flowi4 fl4 = { - .daddr = rt->rt_key_dst, - .saddr = rt->rt_key_src, - .flowi4_tos = rt->rt_tos, + .daddr = iph->daddr, + .saddr = iph->saddr, + .flowi4_tos = iph->tos, .flowi4_oif = rt->rt_oif, .flowi4_iif = rt->rt_iif, .flowi4_mark = rt->rt_mark, @@ -1825,7 +1827,7 @@ int ip_mr_input(struct sk_buff *skb) if (IPCB(skb)->flags & IPSKB_FORWARDED) goto dont_forward; - mrt = ipmr_rt_fib_lookup(net, skb_rtable(skb)); + mrt = ipmr_rt_fib_lookup(net, skb); if (IS_ERR(mrt)) { kfree_skb(skb); return PTR_ERR(mrt); @@ -1957,7 +1959,7 @@ int pim_rcv_v1(struct sk_buff *skb) pim = igmp_hdr(skb); - mrt = ipmr_rt_fib_lookup(net, skb_rtable(skb)); + mrt = ipmr_rt_fib_lookup(net, skb); if (IS_ERR(mrt)) goto drop; if (!mrt->mroute_do_pim || @@ -1989,7 +1991,7 @@ static int pim_rcv(struct sk_buff *skb) csum_fold(skb_checksum(skb, 0, skb->len, 0)))) goto drop; - mrt = ipmr_rt_fib_lookup(net, skb_rtable(skb)); + mrt = ipmr_rt_fib_lookup(net, skb); if (IS_ERR(mrt)) goto drop; if (__pim_rcv(mrt, skb, sizeof(*pim))) { -- cgit v0.10.2 From 475949d8e86bbde5ea3ffa4d95e022ca69233b14 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Tue, 3 May 2011 19:45:15 -0700 Subject: ipv4: Renamt struct rtable's rt_tos to rt_key_tos. To more accurately reflect that it is purely a routing cache lookup key and is used in no other context. Signed-off-by: David S. Miller diff --git a/include/net/route.h b/include/net/route.h index 16eb59c..f07609e 100644 --- a/include/net/route.h +++ b/include/net/route.h @@ -52,7 +52,7 @@ struct rtable { int rt_genid; unsigned rt_flags; __u16 rt_type; - __u8 rt_tos; + __u8 rt_key_tos; __be32 rt_dst; /* Path destination */ __be32 rt_src; /* Path source */ diff --git a/net/ipv4/route.c b/net/ipv4/route.c index 64f360d..3bc6854 100644 --- a/net/ipv4/route.c +++ b/net/ipv4/route.c @@ -424,7 +424,7 @@ static int rt_cache_seq_show(struct seq_file *seq, void *v) dst_metric(&r->dst, RTAX_WINDOW), (int)((dst_metric(&r->dst, RTAX_RTT) >> 3) + dst_metric(&r->dst, RTAX_RTTVAR)), - r->rt_tos, + r->rt_key_tos, r->dst.hh ? atomic_read(&r->dst.hh->hh_refcnt) : -1, r->dst.hh ? (r->dst.hh->hh_output == dev_queue_xmit) : 0, @@ -724,7 +724,7 @@ static inline int compare_keys(struct rtable *rt1, struct rtable *rt2) return (((__force u32)rt1->rt_key_dst ^ (__force u32)rt2->rt_key_dst) | ((__force u32)rt1->rt_key_src ^ (__force u32)rt2->rt_key_src) | (rt1->rt_mark ^ rt2->rt_mark) | - (rt1->rt_tos ^ rt2->rt_tos) | + (rt1->rt_key_tos ^ rt2->rt_key_tos) | (rt1->rt_oif ^ rt2->rt_oif) | (rt1->rt_iif ^ rt2->rt_iif)) == 0; } @@ -1349,7 +1349,7 @@ static struct dst_entry *ipv4_negative_advice(struct dst_entry *dst) rt_genid(dev_net(dst->dev))); #if RT_CACHE_DEBUG >= 1 printk(KERN_DEBUG "ipv4_negative_advice: redirect to %pI4/%02x dropped\n", - &rt->rt_dst, rt->rt_tos); + &rt->rt_dst, rt->rt_key_tos); #endif rt_del(hash, rt); ret = NULL; @@ -1710,7 +1710,7 @@ void ip_rt_get_source(u8 *addr, struct rtable *rt) struct flowi4 fl4 = { .daddr = rt->rt_key_dst, .saddr = rt->rt_key_src, - .flowi4_tos = rt->rt_tos, + .flowi4_tos = rt->rt_key_tos, .flowi4_oif = rt->rt_oif, .flowi4_iif = rt->rt_iif, .flowi4_mark = rt->rt_mark, @@ -1886,7 +1886,7 @@ static int ip_route_input_mc(struct sk_buff *skb, __be32 daddr, __be32 saddr, rth->rt_genid = rt_genid(dev_net(dev)); rth->rt_flags = RTCF_MULTICAST; rth->rt_type = RTN_MULTICAST; - rth->rt_tos = tos; + rth->rt_key_tos = tos; rth->rt_dst = daddr; rth->rt_src = saddr; rth->rt_route_iif = dev->ifindex; @@ -2023,7 +2023,7 @@ static int __mkroute_input(struct sk_buff *skb, rth->rt_genid = rt_genid(dev_net(rth->dst.dev)); rth->rt_flags = flags; rth->rt_type = res->type; - rth->rt_tos = tos; + rth->rt_key_tos = tos; rth->rt_dst = daddr; rth->rt_src = saddr; rth->rt_route_iif = in_dev->dev->ifindex; @@ -2203,7 +2203,7 @@ local_input: rth->rt_genid = rt_genid(net); rth->rt_flags = flags|RTCF_LOCAL; rth->rt_type = res.type; - rth->rt_tos = tos; + rth->rt_key_tos = tos; rth->rt_dst = daddr; rth->rt_src = saddr; #ifdef CONFIG_IP_ROUTE_CLASSID @@ -2293,7 +2293,7 @@ int ip_route_input_common(struct sk_buff *skb, __be32 daddr, __be32 saddr, ((__force u32)rth->rt_key_src ^ (__force u32)saddr) | (rth->rt_iif ^ iif) | rth->rt_oif | - (rth->rt_tos ^ tos)) == 0 && + (rth->rt_key_tos ^ tos)) == 0 && rth->rt_mark == skb->mark && net_eq(dev_net(rth->dst.dev), net) && !rt_is_expired(rth)) { @@ -2410,7 +2410,7 @@ static struct rtable *__mkroute_output(const struct fib_result *res, rth->rt_genid = rt_genid(dev_net(dev_out)); rth->rt_flags = flags; rth->rt_type = type; - rth->rt_tos = tos; + rth->rt_key_tos = tos; rth->rt_dst = fl4->daddr; rth->rt_src = fl4->saddr; rth->rt_route_iif = 0; @@ -2668,7 +2668,7 @@ struct rtable *__ip_route_output_key(struct net *net, struct flowi4 *flp4) rt_is_output_route(rth) && rth->rt_oif == flp4->flowi4_oif && rth->rt_mark == flp4->flowi4_mark && - !((rth->rt_tos ^ flp4->flowi4_tos) & + !((rth->rt_key_tos ^ flp4->flowi4_tos) & (IPTOS_RT_MASK | RTO_ONLINK)) && net_eq(dev_net(rth->dst.dev), net) && !rt_is_expired(rth)) { @@ -2740,7 +2740,7 @@ struct dst_entry *ipv4_blackhole_route(struct net *net, struct dst_entry *dst_or rt->rt_key_dst = ort->rt_key_dst; rt->rt_key_src = ort->rt_key_src; - rt->rt_tos = ort->rt_tos; + rt->rt_key_tos = ort->rt_key_tos; rt->rt_route_iif = ort->rt_route_iif; rt->rt_iif = ort->rt_iif; rt->rt_oif = ort->rt_oif; @@ -2803,7 +2803,7 @@ static int rt_fill_info(struct net *net, r->rtm_family = AF_INET; r->rtm_dst_len = 32; r->rtm_src_len = 0; - r->rtm_tos = rt->rt_tos; + r->rtm_tos = rt->rt_key_tos; r->rtm_table = RT_TABLE_MAIN; NLA_PUT_U32(skb, RTA_TABLE, RT_TABLE_MAIN); r->rtm_type = rt->rt_type; diff --git a/net/ipv4/xfrm4_policy.c b/net/ipv4/xfrm4_policy.c index 59b1340..7ff973b 100644 --- a/net/ipv4/xfrm4_policy.c +++ b/net/ipv4/xfrm4_policy.c @@ -73,7 +73,7 @@ static int xfrm4_fill_dst(struct xfrm_dst *xdst, struct net_device *dev, rt->rt_key_dst = fl4->daddr; rt->rt_key_src = fl4->saddr; - rt->rt_tos = fl4->flowi4_tos; + rt->rt_key_tos = fl4->flowi4_tos; rt->rt_route_iif = fl4->flowi4_iif; rt->rt_iif = fl4->flowi4_iif; rt->rt_oif = fl4->flowi4_oif; -- cgit v0.10.2 From 0ee5623f9a6e52df90a78bd21179f8ab370e102e Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Tue, 3 May 2011 19:59:13 -0700 Subject: Linux 2.6.39-rc6 diff --git a/Makefile b/Makefile index 5a7a2e4..28820f7 100644 --- a/Makefile +++ b/Makefile @@ -1,7 +1,7 @@ VERSION = 2 PATCHLEVEL = 6 SUBLEVEL = 39 -EXTRAVERSION = -rc5 +EXTRAVERSION = -rc6 NAME = Flesh-Eating Bats with Fangs # *DOCUMENTATION* -- cgit v0.10.2 From f1390160ddcd64a3cfd48b3280d0a616a31b9520 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Tue, 3 May 2011 20:06:41 -0700 Subject: dccp: Use flowi4->saddr in dccp_v4_connect() Signed-off-by: David S. Miller diff --git a/net/dccp/ipv4.c b/net/dccp/ipv4.c index f4254bb..36700a46 100644 --- a/net/dccp/ipv4.c +++ b/net/dccp/ipv4.c @@ -86,7 +86,7 @@ int dccp_v4_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len) daddr = fl4.daddr; if (inet->inet_saddr == 0) - inet->inet_saddr = rt->rt_src; + inet->inet_saddr = fl4.saddr; inet->inet_rcv_saddr = inet->inet_saddr; inet->inet_dport = usin->sin_port; -- cgit v0.10.2 From 31e4543db29fb85496a122b965d6482c8d1a2bfe Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Tue, 3 May 2011 20:25:42 -0700 Subject: ipv4: Make caller provide on-stack flow key to ip_route_output_ports(). Signed-off-by: David S. Miller diff --git a/drivers/infiniband/hw/cxgb3/iwch_cm.c b/drivers/infiniband/hw/cxgb3/iwch_cm.c index 3216bca..2391841 100644 --- a/drivers/infiniband/hw/cxgb3/iwch_cm.c +++ b/drivers/infiniband/hw/cxgb3/iwch_cm.c @@ -338,8 +338,9 @@ static struct rtable *find_route(struct t3cdev *dev, __be32 local_ip, __be16 peer_port, u8 tos) { struct rtable *rt; + struct flowi4 fl4; - rt = ip_route_output_ports(&init_net, NULL, peer_ip, local_ip, + rt = ip_route_output_ports(&init_net, &fl4, NULL, peer_ip, local_ip, peer_port, local_port, IPPROTO_TCP, tos, 0); if (IS_ERR(rt)) diff --git a/drivers/infiniband/hw/cxgb4/cm.c b/drivers/infiniband/hw/cxgb4/cm.c index 9d8dcfa..6aa53cd 100644 --- a/drivers/infiniband/hw/cxgb4/cm.c +++ b/drivers/infiniband/hw/cxgb4/cm.c @@ -315,8 +315,9 @@ static struct rtable *find_route(struct c4iw_dev *dev, __be32 local_ip, __be16 peer_port, u8 tos) { struct rtable *rt; + struct flowi4 fl4; - rt = ip_route_output_ports(&init_net, NULL, peer_ip, local_ip, + rt = ip_route_output_ports(&init_net, &fl4, NULL, peer_ip, local_ip, peer_port, local_port, IPPROTO_TCP, tos, 0); if (IS_ERR(rt)) diff --git a/drivers/net/pptp.c b/drivers/net/pptp.c index 51dfcf8..e771e8d 100644 --- a/drivers/net/pptp.c +++ b/drivers/net/pptp.c @@ -175,6 +175,7 @@ static int pptp_xmit(struct ppp_channel *chan, struct sk_buff *skb) struct pptp_opt *opt = &po->proto.pptp; struct pptp_gre_header *hdr; unsigned int header_len = sizeof(*hdr); + struct flowi4 fl4; int islcp; int len; unsigned char *data; @@ -189,7 +190,7 @@ static int pptp_xmit(struct ppp_channel *chan, struct sk_buff *skb) if (sk_pppox(po)->sk_state & PPPOX_DEAD) goto tx_error; - rt = ip_route_output_ports(&init_net, NULL, + rt = ip_route_output_ports(&init_net, &fl4, NULL, opt->dst_addr.sin_addr.s_addr, opt->src_addr.sin_addr.s_addr, 0, 0, IPPROTO_GRE, @@ -434,6 +435,7 @@ static int pptp_connect(struct socket *sock, struct sockaddr *uservaddr, struct pppox_sock *po = pppox_sk(sk); struct pptp_opt *opt = &po->proto.pptp; struct rtable *rt; + struct flowi4 fl4; int error = 0; if (sp->sa_protocol != PX_PROTO_PPTP) @@ -463,7 +465,7 @@ static int pptp_connect(struct socket *sock, struct sockaddr *uservaddr, po->chan.private = sk; po->chan.ops = &pptp_chan_ops; - rt = ip_route_output_ports(&init_net, sk, + rt = ip_route_output_ports(&init_net, &fl4, sk, opt->dst_addr.sin_addr.s_addr, opt->src_addr.sin_addr.s_addr, 0, 0, diff --git a/drivers/scsi/cxgbi/libcxgbi.c b/drivers/scsi/cxgbi/libcxgbi.c index de764ea..0c33d25 100644 --- a/drivers/scsi/cxgbi/libcxgbi.c +++ b/drivers/scsi/cxgbi/libcxgbi.c @@ -454,8 +454,9 @@ static struct rtable *find_route_ipv4(__be32 saddr, __be32 daddr, __be16 sport, __be16 dport, u8 tos) { struct rtable *rt; + struct flowi4 fl4; - rt = ip_route_output_ports(&init_net, NULL, daddr, saddr, + rt = ip_route_output_ports(&init_net, &fl4, NULL, daddr, saddr, dport, sport, IPPROTO_TCP, tos, 0); if (IS_ERR(rt)) return NULL; diff --git a/include/net/route.h b/include/net/route.h index f07609e..8c02c87 100644 --- a/include/net/route.h +++ b/include/net/route.h @@ -137,20 +137,19 @@ static inline struct rtable *ip_route_output(struct net *net, __be32 daddr, return ip_route_output_key(net, &fl4); } -static inline struct rtable *ip_route_output_ports(struct net *net, struct sock *sk, +static inline struct rtable *ip_route_output_ports(struct net *net, struct flowi4 *fl4, + struct sock *sk, __be32 daddr, __be32 saddr, __be16 dport, __be16 sport, __u8 proto, __u8 tos, int oif) { - struct flowi4 fl4; - - flowi4_init_output(&fl4, oif, sk ? sk->sk_mark : 0, tos, + flowi4_init_output(fl4, oif, sk ? sk->sk_mark : 0, tos, RT_SCOPE_UNIVERSE, proto, sk ? inet_sk_flowi_flags(sk) : 0, daddr, saddr, dport, sport); if (sk) - security_sk_classify_flow(sk, flowi4_to_flowi(&fl4)); - return ip_route_output_flow(net, &fl4, sk); + security_sk_classify_flow(sk, flowi4_to_flowi(fl4)); + return ip_route_output_flow(net, fl4, sk); } static inline struct rtable *ip_route_output_gre(struct net *net, diff --git a/net/ipv4/af_inet.c b/net/ipv4/af_inet.c index 4e73499..7b91fa8 100644 --- a/net/ipv4/af_inet.c +++ b/net/ipv4/af_inet.c @@ -1152,6 +1152,7 @@ int inet_sk_rebuild_header(struct sock *sk) struct rtable *rt = (struct rtable *)__sk_dst_check(sk, 0); __be32 daddr; struct ip_options_rcu *inet_opt; + struct flowi4 fl4; int err; /* Route is OK, nothing to do. */ @@ -1165,7 +1166,7 @@ int inet_sk_rebuild_header(struct sock *sk) if (inet_opt && inet_opt->opt.srr) daddr = inet_opt->opt.faddr; rcu_read_unlock(); - rt = ip_route_output_ports(sock_net(sk), sk, daddr, inet->inet_saddr, + rt = ip_route_output_ports(sock_net(sk), &fl4, sk, daddr, inet->inet_saddr, inet->inet_dport, inet->inet_sport, sk->sk_protocol, RT_CONN_FLAGS(sk), sk->sk_bound_dev_if); diff --git a/net/ipv4/igmp.c b/net/ipv4/igmp.c index 8ae0a57..7c2ef59 100644 --- a/net/ipv4/igmp.c +++ b/net/ipv4/igmp.c @@ -309,6 +309,7 @@ static struct sk_buff *igmpv3_newpack(struct net_device *dev, int size) struct iphdr *pip; struct igmpv3_report *pig; struct net *net = dev_net(dev); + struct flowi4 fl4; while (1) { skb = alloc_skb(size + LL_ALLOCATED_SPACE(dev), @@ -321,7 +322,7 @@ static struct sk_buff *igmpv3_newpack(struct net_device *dev, int size) } igmp_skb_size(skb) = size; - rt = ip_route_output_ports(net, NULL, IGMPV3_ALL_MCR, 0, + rt = ip_route_output_ports(net, &fl4, NULL, IGMPV3_ALL_MCR, 0, 0, 0, IPPROTO_IGMP, 0, dev->ifindex); if (IS_ERR(rt)) { @@ -650,6 +651,7 @@ static int igmp_send_report(struct in_device *in_dev, struct ip_mc_list *pmc, struct net_device *dev = in_dev->dev; struct net *net = dev_net(dev); __be32 group = pmc ? pmc->multiaddr : 0; + struct flowi4 fl4; __be32 dst; if (type == IGMPV3_HOST_MEMBERSHIP_REPORT) @@ -659,7 +661,7 @@ static int igmp_send_report(struct in_device *in_dev, struct ip_mc_list *pmc, else dst = group; - rt = ip_route_output_ports(net, NULL, dst, 0, + rt = ip_route_output_ports(net, &fl4, NULL, dst, 0, 0, 0, IPPROTO_IGMP, 0, dev->ifindex); if (IS_ERR(rt)) diff --git a/net/ipv4/ip_output.c b/net/ipv4/ip_output.c index 362e66f..3aa4c31 100644 --- a/net/ipv4/ip_output.c +++ b/net/ipv4/ip_output.c @@ -333,6 +333,7 @@ int ip_queue_xmit(struct sk_buff *skb) /* Make sure we can route this packet. */ rt = (struct rtable *)__sk_dst_check(sk, 0); if (rt == NULL) { + struct flowi4 fl4; __be32 daddr; /* Use correct destination address if we have options. */ @@ -344,7 +345,7 @@ int ip_queue_xmit(struct sk_buff *skb) * keep trying until route appears or the connection times * itself out. */ - rt = ip_route_output_ports(sock_net(sk), sk, + rt = ip_route_output_ports(sock_net(sk), &fl4, sk, daddr, inet->inet_saddr, inet->inet_dport, inet->inet_sport, diff --git a/net/ipv4/ipip.c b/net/ipv4/ipip.c index ef16377..88d96bd 100644 --- a/net/ipv4/ipip.c +++ b/net/ipv4/ipip.c @@ -442,6 +442,7 @@ static netdev_tx_t ipip_tunnel_xmit(struct sk_buff *skb, struct net_device *dev) struct iphdr *iph; /* Our new IP header */ unsigned int max_headroom; /* The extra header space needed */ __be32 dst = tiph->daddr; + struct flowi4 fl4; int mtu; if (skb->protocol != htons(ETH_P_IP)) @@ -460,7 +461,7 @@ static netdev_tx_t ipip_tunnel_xmit(struct sk_buff *skb, struct net_device *dev) goto tx_error_icmp; } - rt = ip_route_output_ports(dev_net(dev), NULL, + rt = ip_route_output_ports(dev_net(dev), &fl4, NULL, dst, tiph->saddr, 0, 0, IPPROTO_IPIP, RT_TOS(tos), @@ -578,13 +579,15 @@ static void ipip_tunnel_bind_dev(struct net_device *dev) iph = &tunnel->parms.iph; if (iph->daddr) { - struct rtable *rt = ip_route_output_ports(dev_net(dev), NULL, - iph->daddr, iph->saddr, - 0, 0, - IPPROTO_IPIP, - RT_TOS(iph->tos), - tunnel->parms.link); - + struct rtable *rt; + struct flowi4 fl4; + + rt = ip_route_output_ports(dev_net(dev), &fl4, NULL, + iph->daddr, iph->saddr, + 0, 0, + IPPROTO_IPIP, + RT_TOS(iph->tos), + tunnel->parms.link); if (!IS_ERR(rt)) { tdev = rt->dst.dev; ip_rt_put(rt); diff --git a/net/ipv4/ipmr.c b/net/ipv4/ipmr.c index 3ad38a4..86033b7 100644 --- a/net/ipv4/ipmr.c +++ b/net/ipv4/ipmr.c @@ -1595,6 +1595,7 @@ static void ipmr_queue_xmit(struct net *net, struct mr_table *mrt, struct vif_device *vif = &mrt->vif_table[vifi]; struct net_device *dev; struct rtable *rt; + struct flowi4 fl4; int encap = 0; if (vif->dev == NULL) @@ -1612,7 +1613,7 @@ static void ipmr_queue_xmit(struct net *net, struct mr_table *mrt, #endif if (vif->flags & VIFF_TUNNEL) { - rt = ip_route_output_ports(net, NULL, + rt = ip_route_output_ports(net, &fl4, NULL, vif->remote, vif->local, 0, 0, IPPROTO_IPIP, @@ -1621,7 +1622,7 @@ static void ipmr_queue_xmit(struct net *net, struct mr_table *mrt, goto out_free; encap = sizeof(struct iphdr); } else { - rt = ip_route_output_ports(net, NULL, iph->daddr, 0, + rt = ip_route_output_ports(net, &fl4, NULL, iph->daddr, 0, 0, 0, IPPROTO_IPIP, RT_TOS(iph->tos), vif->link); diff --git a/net/ipv6/ip6_tunnel.c b/net/ipv6/ip6_tunnel.c index 9dd0e96..3dff27c 100644 --- a/net/ipv6/ip6_tunnel.c +++ b/net/ipv6/ip6_tunnel.c @@ -537,6 +537,7 @@ ip4ip6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, struct sk_buff *skb2; const struct iphdr *eiph; struct rtable *rt; + struct flowi4 fl4; err = ip6_tnl_err(skb, IPPROTO_IPIP, opt, &rel_type, &rel_code, &rel_msg, &rel_info, offset); @@ -577,7 +578,7 @@ ip4ip6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, eiph = ip_hdr(skb2); /* Try to guess incoming interface */ - rt = ip_route_output_ports(dev_net(skb->dev), NULL, + rt = ip_route_output_ports(dev_net(skb->dev), &fl4, NULL, eiph->saddr, 0, 0, 0, IPPROTO_IPIP, RT_TOS(eiph->tos), 0); @@ -590,7 +591,7 @@ ip4ip6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, if (rt->rt_flags & RTCF_LOCAL) { ip_rt_put(rt); rt = NULL; - rt = ip_route_output_ports(dev_net(skb->dev), NULL, + rt = ip_route_output_ports(dev_net(skb->dev), &fl4, NULL, eiph->daddr, eiph->saddr, 0, 0, IPPROTO_IPIP, diff --git a/net/ipv6/sit.c b/net/ipv6/sit.c index 34d8964..a24fb14 100644 --- a/net/ipv6/sit.c +++ b/net/ipv6/sit.c @@ -674,6 +674,7 @@ static netdev_tx_t ipip6_tunnel_xmit(struct sk_buff *skb, struct iphdr *iph; /* Our new IP header */ unsigned int max_headroom; /* The extra header space needed */ __be32 dst = tiph->daddr; + struct flowi4 fl4; int mtu; const struct in6_addr *addr6; int addr_type; @@ -733,7 +734,7 @@ static netdev_tx_t ipip6_tunnel_xmit(struct sk_buff *skb, dst = addr6->s6_addr32[3]; } - rt = ip_route_output_ports(dev_net(dev), NULL, + rt = ip_route_output_ports(dev_net(dev), &fl4, NULL, dst, tiph->saddr, 0, 0, IPPROTO_IPV6, RT_TOS(tos), @@ -851,12 +852,13 @@ static void ipip6_tunnel_bind_dev(struct net_device *dev) struct net_device *tdev = NULL; struct ip_tunnel *tunnel; const struct iphdr *iph; + struct flowi4 fl4; tunnel = netdev_priv(dev); iph = &tunnel->parms.iph; if (iph->daddr) { - struct rtable *rt = ip_route_output_ports(dev_net(dev), NULL, + struct rtable *rt = ip_route_output_ports(dev_net(dev), &fl4, NULL, iph->daddr, iph->saddr, 0, 0, IPPROTO_IPV6, diff --git a/net/l2tp/l2tp_ip.c b/net/l2tp/l2tp_ip.c index a4d2dfa..8189960 100644 --- a/net/l2tp/l2tp_ip.c +++ b/net/l2tp/l2tp_ip.c @@ -471,6 +471,7 @@ static int l2tp_ip_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *m if (rt == NULL) { struct ip_options_rcu *inet_opt; + struct flowi4 fl4; rcu_read_lock(); inet_opt = rcu_dereference(inet->inet_opt); @@ -485,7 +486,7 @@ static int l2tp_ip_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *m * keep trying until route appears or the connection times * itself out. */ - rt = ip_route_output_ports(sock_net(sk), sk, + rt = ip_route_output_ports(sock_net(sk), &fl4, sk, daddr, inet->inet_saddr, inet->inet_dport, inet->inet_sport, sk->sk_protocol, RT_CONN_FLAGS(sk), diff --git a/net/rxrpc/ar-peer.c b/net/rxrpc/ar-peer.c index 55b93dc..b6ff063 100644 --- a/net/rxrpc/ar-peer.c +++ b/net/rxrpc/ar-peer.c @@ -36,10 +36,11 @@ static void rxrpc_destroy_peer(struct work_struct *work); static void rxrpc_assess_MTU_size(struct rxrpc_peer *peer) { struct rtable *rt; + struct flowi4 fl4; peer->if_mtu = 1500; - rt = ip_route_output_ports(&init_net, NULL, + rt = ip_route_output_ports(&init_net, &fl4, NULL, peer->srx.transport.sin.sin_addr.s_addr, 0, htons(7000), htons(7001), IPPROTO_UDP, 0, 0); -- cgit v0.10.2 From 28c90da02ed7367fc5714adefce2a961e5bae306 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Tue, 3 May 2011 20:41:42 -0700 Subject: pptp: Use flowi4's daddr/saddr in pptp_xmit(). Instead of rt->rt_{src,dst} Signed-off-by: David S. Miller diff --git a/drivers/net/pptp.c b/drivers/net/pptp.c index e771e8d..1286fe2 100644 --- a/drivers/net/pptp.c +++ b/drivers/net/pptp.c @@ -271,8 +271,8 @@ static int pptp_xmit(struct ppp_channel *chan, struct sk_buff *skb) iph->frag_off = 0; iph->protocol = IPPROTO_GRE; iph->tos = 0; - iph->daddr = rt->rt_dst; - iph->saddr = rt->rt_src; + iph->daddr = fl4.daddr; + iph->saddr = fl4.saddr; iph->ttl = ip4_dst_hoplimit(&rt->dst); iph->tot_len = htons(skb->len); -- cgit v0.10.2 From f4bfd99f8519e2d35541cc4fc383b1b3141a657a Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Tue, 3 May 2011 20:43:40 -0700 Subject: libcxgbi: Use flowi4's saddr in cxgbi_check_route(). Instead of rt->rt_src Signed-off-by: David S. Miller diff --git a/drivers/scsi/cxgbi/libcxgbi.c b/drivers/scsi/cxgbi/libcxgbi.c index 0c33d25..a2a9c7c 100644 --- a/drivers/scsi/cxgbi/libcxgbi.c +++ b/drivers/scsi/cxgbi/libcxgbi.c @@ -450,13 +450,13 @@ static struct cxgbi_sock *cxgbi_sock_create(struct cxgbi_device *cdev) return csk; } -static struct rtable *find_route_ipv4(__be32 saddr, __be32 daddr, +static struct rtable *find_route_ipv4(struct flowi4 *fl4, + __be32 saddr, __be32 daddr, __be16 sport, __be16 dport, u8 tos) { struct rtable *rt; - struct flowi4 fl4; - rt = ip_route_output_ports(&init_net, &fl4, NULL, daddr, saddr, + rt = ip_route_output_ports(&init_net, fl4, NULL, daddr, saddr, dport, sport, IPPROTO_TCP, tos, 0); if (IS_ERR(rt)) return NULL; @@ -471,6 +471,7 @@ static struct cxgbi_sock *cxgbi_check_route(struct sockaddr *dst_addr) struct net_device *ndev; struct cxgbi_device *cdev; struct rtable *rt = NULL; + struct flowi4 fl4; struct cxgbi_sock *csk = NULL; unsigned int mtu = 0; int port = 0xFFFF; @@ -483,7 +484,7 @@ static struct cxgbi_sock *cxgbi_check_route(struct sockaddr *dst_addr) goto err_out; } - rt = find_route_ipv4(0, daddr->sin_addr.s_addr, 0, daddr->sin_port, 0); + rt = find_route_ipv4(&fl4, 0, daddr->sin_addr.s_addr, 0, daddr->sin_port, 0); if (!rt) { pr_info("no route to ipv4 0x%x, port %u.\n", daddr->sin_addr.s_addr, daddr->sin_port); @@ -532,7 +533,7 @@ static struct cxgbi_sock *cxgbi_check_route(struct sockaddr *dst_addr) csk->daddr.sin_addr.s_addr = daddr->sin_addr.s_addr; csk->daddr.sin_port = daddr->sin_port; csk->daddr.sin_family = daddr->sin_family; - csk->saddr.sin_addr.s_addr = rt->rt_src; + csk->saddr.sin_addr.s_addr = fl4.saddr; return csk; -- cgit v0.10.2 From 492f64ce12e259abd85714d05b885e105bd8aeef Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Tue, 3 May 2011 20:53:12 -0700 Subject: ipv4: Use flowi4's {saddr,daddr} in igmpv3_newpack() and igmp_send_report() Instead of rt->rt_{src,dst} Signed-off-by: David S. Miller diff --git a/net/ipv4/igmp.c b/net/ipv4/igmp.c index 7c2ef59..ec03c2f 100644 --- a/net/ipv4/igmp.c +++ b/net/ipv4/igmp.c @@ -344,8 +344,8 @@ static struct sk_buff *igmpv3_newpack(struct net_device *dev, int size) pip->tos = 0xc0; pip->frag_off = htons(IP_DF); pip->ttl = 1; - pip->daddr = rt->rt_dst; - pip->saddr = rt->rt_src; + pip->daddr = fl4.daddr; + pip->saddr = fl4.saddr; pip->protocol = IPPROTO_IGMP; pip->tot_len = 0; /* filled in later */ ip_select_ident(pip, &rt->dst, NULL); @@ -687,7 +687,7 @@ static int igmp_send_report(struct in_device *in_dev, struct ip_mc_list *pmc, iph->frag_off = htons(IP_DF); iph->ttl = 1; iph->daddr = dst; - iph->saddr = rt->rt_src; + iph->saddr = fl4.saddr; iph->protocol = IPPROTO_IGMP; ip_select_ident(iph, &rt->dst, NULL); ((u8*)&iph[1])[0] = IPOPT_RA; -- cgit v0.10.2 From 18a353f42817f08e3501162ceda9d2efddb08a40 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Tue, 3 May 2011 20:55:05 -0700 Subject: sctp: Use flowi4's {saddr,daddr} in sctp_v4_dst_saddr() and sctp_v4_get_dst() Instead of rt->rt_{src,dst} Signed-off-by: David S. Miller diff --git a/net/sctp/protocol.c b/net/sctp/protocol.c index 9d3f159..69fbc55 100644 --- a/net/sctp/protocol.c +++ b/net/sctp/protocol.c @@ -339,13 +339,12 @@ static int sctp_v4_to_addr_param(const union sctp_addr *addr, } /* Initialize a sctp_addr from a dst_entry. */ -static void sctp_v4_dst_saddr(union sctp_addr *saddr, struct dst_entry *dst, +static void sctp_v4_dst_saddr(union sctp_addr *saddr, struct flowi4 *fl4, __be16 port) { - struct rtable *rt = (struct rtable *)dst; saddr->v4.sin_family = AF_INET; saddr->v4.sin_port = port; - saddr->v4.sin_addr.s_addr = rt->rt_src; + saddr->v4.sin_addr.s_addr = fl4->saddr; } /* Compare two addresses exactly. */ @@ -508,7 +507,7 @@ static void sctp_v4_get_dst(struct sctp_transport *t, union sctp_addr *saddr, /* Walk through the bind address list and look for a bind * address that matches the source address of the returned dst. */ - sctp_v4_dst_saddr(&dst_saddr, dst, htons(bp->port)); + sctp_v4_dst_saddr(&dst_saddr, fl4, htons(bp->port)); rcu_read_lock(); list_for_each_entry_rcu(laddr, &bp->address_list, list) { if (!laddr->valid || (laddr->state != SCTP_ADDR_SRC)) @@ -550,7 +549,7 @@ out: t->dst = dst; if (dst) SCTP_DEBUG_PRINTK("rt_dst:%pI4, rt_src:%pI4\n", - &rt->rt_dst, &rt->rt_src); + &fl4->daddr, &fl4->saddr); else SCTP_DEBUG_PRINTK("NO ROUTE\n"); } -- cgit v0.10.2 From 476eb4912601a8c01e6702b9a029f476b4b131d2 Mon Sep 17 00:00:00 2001 From: Grant Likely Date: Wed, 4 May 2011 15:02:15 +1000 Subject: powerpc/irq: Stop exporting irq_map First step in eliminating irq_map[] table entirely Signed-off-by: Benjamin Herrenschmidt diff --git a/arch/powerpc/include/asm/irq.h b/arch/powerpc/include/asm/irq.h index 47b7905..e1983d5 100644 --- a/arch/powerpc/include/asm/irq.h +++ b/arch/powerpc/include/asm/irq.h @@ -128,25 +128,10 @@ struct irq_host { struct device_node *of_node; }; -/* The main irq map itself is an array of NR_IRQ entries containing the - * associate host and irq number. An entry with a host of NULL is free. - * An entry can be allocated if it's free, the allocator always then sets - * hwirq first to the host's invalid irq number and then fills ops. - */ -struct irq_map_entry { - irq_hw_number_t hwirq; - struct irq_host *host; -}; - -extern struct irq_map_entry irq_map[NR_IRQS]; - +struct irq_data; +extern irq_hw_number_t irqd_to_hwirq(struct irq_data *d); extern irq_hw_number_t virq_to_hw(unsigned int virq); - -/* This will eventually -replace- virq_to_hw if/when we stash the - * HW number in the irq_data itself. We use a macro so we can inline - * it as irq_data isn't defined yet - */ -#define irq_data_to_hw(d) (irq_map[(d)->irq].hwirq) +extern struct irq_host *virq_to_host(unsigned int virq); /** * irq_alloc_host - Allocate a new irq_host data structure diff --git a/arch/powerpc/kernel/irq.c b/arch/powerpc/kernel/irq.c index 4f5d6e7..a81dd74 100644 --- a/arch/powerpc/kernel/irq.c +++ b/arch/powerpc/kernel/irq.c @@ -481,20 +481,42 @@ void do_softirq(void) * IRQ controller and virtual interrupts */ +/* The main irq map itself is an array of NR_IRQ entries containing the + * associate host and irq number. An entry with a host of NULL is free. + * An entry can be allocated if it's free, the allocator always then sets + * hwirq first to the host's invalid irq number and then fills ops. + */ +struct irq_map_entry { + irq_hw_number_t hwirq; + struct irq_host *host; +}; + static LIST_HEAD(irq_hosts); static DEFINE_RAW_SPINLOCK(irq_big_lock); static unsigned int revmap_trees_allocated; static DEFINE_MUTEX(revmap_trees_mutex); -struct irq_map_entry irq_map[NR_IRQS]; +static struct irq_map_entry irq_map[NR_IRQS]; static unsigned int irq_virq_count = NR_IRQS; static struct irq_host *irq_default_host; +irq_hw_number_t irqd_to_hwirq(struct irq_data *d) +{ + return irq_map[d->irq].hwirq; +} +EXPORT_SYMBOL_GPL(irqd_to_hwirq); + irq_hw_number_t virq_to_hw(unsigned int virq) { return irq_map[virq].hwirq; } EXPORT_SYMBOL_GPL(virq_to_hw); +struct irq_host *virq_to_host(unsigned int virq) +{ + return irq_map[virq].host; +} +EXPORT_SYMBOL_GPL(virq_to_host); + static int default_irq_host_match(struct irq_host *h, struct device_node *np) { return h->of_node != NULL && h->of_node == np; @@ -1103,7 +1125,7 @@ static int virq_debug_show(struct seq_file *m, void *private) struct irq_chip *chip; seq_printf(m, "%5d ", i); - seq_printf(m, "0x%05lx ", virq_to_hw(i)); + seq_printf(m, "0x%05lx ", irq_map[i].hwirq); chip = irq_desc_get_chip(desc); if (chip && chip->name) diff --git a/arch/powerpc/platforms/512x/mpc5121_ads_cpld.c b/arch/powerpc/platforms/512x/mpc5121_ads_cpld.c index cfc4b20..a8bc0d4 100644 --- a/arch/powerpc/platforms/512x/mpc5121_ads_cpld.c +++ b/arch/powerpc/platforms/512x/mpc5121_ads_cpld.c @@ -61,7 +61,7 @@ irq_to_pic_bit(unsigned int irq) static void cpld_mask_irq(struct irq_data *d) { - unsigned int cpld_irq = (unsigned int)irq_map[d->irq].hwirq; + unsigned int cpld_irq = (unsigned int)irqd_to_hwirq(d); void __iomem *pic_mask = irq_to_pic_mask(cpld_irq); out_8(pic_mask, @@ -71,7 +71,7 @@ cpld_mask_irq(struct irq_data *d) static void cpld_unmask_irq(struct irq_data *d) { - unsigned int cpld_irq = (unsigned int)irq_map[d->irq].hwirq; + unsigned int cpld_irq = (unsigned int)irqd_to_hwirq(d); void __iomem *pic_mask = irq_to_pic_mask(cpld_irq); out_8(pic_mask, diff --git a/arch/powerpc/platforms/52xx/media5200.c b/arch/powerpc/platforms/52xx/media5200.c index 57a6a34..96f85e5 100644 --- a/arch/powerpc/platforms/52xx/media5200.c +++ b/arch/powerpc/platforms/52xx/media5200.c @@ -56,7 +56,7 @@ static void media5200_irq_unmask(struct irq_data *d) spin_lock_irqsave(&media5200_irq.lock, flags); val = in_be32(media5200_irq.regs + MEDIA5200_IRQ_ENABLE); - val |= 1 << (MEDIA5200_IRQ_SHIFT + irq_map[d->irq].hwirq); + val |= 1 << (MEDIA5200_IRQ_SHIFT + irqd_to_hwirq(d)); out_be32(media5200_irq.regs + MEDIA5200_IRQ_ENABLE, val); spin_unlock_irqrestore(&media5200_irq.lock, flags); } @@ -68,7 +68,7 @@ static void media5200_irq_mask(struct irq_data *d) spin_lock_irqsave(&media5200_irq.lock, flags); val = in_be32(media5200_irq.regs + MEDIA5200_IRQ_ENABLE); - val &= ~(1 << (MEDIA5200_IRQ_SHIFT + irq_map[d->irq].hwirq)); + val &= ~(1 << (MEDIA5200_IRQ_SHIFT + irqd_to_hwirq(d))); out_be32(media5200_irq.regs + MEDIA5200_IRQ_ENABLE, val); spin_unlock_irqrestore(&media5200_irq.lock, flags); } diff --git a/arch/powerpc/platforms/52xx/mpc52xx_pic.c b/arch/powerpc/platforms/52xx/mpc52xx_pic.c index 1dd1540..bb61181 100644 --- a/arch/powerpc/platforms/52xx/mpc52xx_pic.c +++ b/arch/powerpc/platforms/52xx/mpc52xx_pic.c @@ -157,48 +157,30 @@ static inline void io_be_clrbit(u32 __iomem *addr, int bitno) */ static void mpc52xx_extirq_mask(struct irq_data *d) { - int irq; - int l2irq; - - irq = irq_map[d->irq].hwirq; - l2irq = irq & MPC52xx_IRQ_L2_MASK; - + int l2irq = irqd_to_hwirq(d) & MPC52xx_IRQ_L2_MASK; io_be_clrbit(&intr->ctrl, 11 - l2irq); } static void mpc52xx_extirq_unmask(struct irq_data *d) { - int irq; - int l2irq; - - irq = irq_map[d->irq].hwirq; - l2irq = irq & MPC52xx_IRQ_L2_MASK; - + int l2irq = irqd_to_hwirq(d) & MPC52xx_IRQ_L2_MASK; io_be_setbit(&intr->ctrl, 11 - l2irq); } static void mpc52xx_extirq_ack(struct irq_data *d) { - int irq; - int l2irq; - - irq = irq_map[d->irq].hwirq; - l2irq = irq & MPC52xx_IRQ_L2_MASK; - + int l2irq = irqd_to_hwirq(d) & MPC52xx_IRQ_L2_MASK; io_be_setbit(&intr->ctrl, 27-l2irq); } static int mpc52xx_extirq_set_type(struct irq_data *d, unsigned int flow_type) { u32 ctrl_reg, type; - int irq; - int l2irq; + int l2irq = irqd_to_hwirq(d) & MPC52xx_IRQ_L2_MASK; void *handler = handle_level_irq; - irq = irq_map[d->irq].hwirq; - l2irq = irq & MPC52xx_IRQ_L2_MASK; - - pr_debug("%s: irq=%x. l2=%d flow_type=%d\n", __func__, irq, l2irq, flow_type); + pr_debug("%s: irq=%x. l2=%d flow_type=%d\n", __func__, + (int) irqd_to_hwirq(d), l2irq, flow_type); switch (flow_type) { case IRQF_TRIGGER_HIGH: type = 0; break; @@ -237,23 +219,13 @@ static int mpc52xx_null_set_type(struct irq_data *d, unsigned int flow_type) static void mpc52xx_main_mask(struct irq_data *d) { - int irq; - int l2irq; - - irq = irq_map[d->irq].hwirq; - l2irq = irq & MPC52xx_IRQ_L2_MASK; - + int l2irq = irqd_to_hwirq(d) & MPC52xx_IRQ_L2_MASK; io_be_setbit(&intr->main_mask, 16 - l2irq); } static void mpc52xx_main_unmask(struct irq_data *d) { - int irq; - int l2irq; - - irq = irq_map[d->irq].hwirq; - l2irq = irq & MPC52xx_IRQ_L2_MASK; - + int l2irq = irqd_to_hwirq(d) & MPC52xx_IRQ_L2_MASK; io_be_clrbit(&intr->main_mask, 16 - l2irq); } @@ -270,23 +242,13 @@ static struct irq_chip mpc52xx_main_irqchip = { */ static void mpc52xx_periph_mask(struct irq_data *d) { - int irq; - int l2irq; - - irq = irq_map[d->irq].hwirq; - l2irq = irq & MPC52xx_IRQ_L2_MASK; - + int l2irq = irqd_to_hwirq(d) & MPC52xx_IRQ_L2_MASK; io_be_setbit(&intr->per_mask, 31 - l2irq); } static void mpc52xx_periph_unmask(struct irq_data *d) { - int irq; - int l2irq; - - irq = irq_map[d->irq].hwirq; - l2irq = irq & MPC52xx_IRQ_L2_MASK; - + int l2irq = irqd_to_hwirq(d) & MPC52xx_IRQ_L2_MASK; io_be_clrbit(&intr->per_mask, 31 - l2irq); } @@ -303,34 +265,19 @@ static struct irq_chip mpc52xx_periph_irqchip = { */ static void mpc52xx_sdma_mask(struct irq_data *d) { - int irq; - int l2irq; - - irq = irq_map[d->irq].hwirq; - l2irq = irq & MPC52xx_IRQ_L2_MASK; - + int l2irq = irqd_to_hwirq(d) & MPC52xx_IRQ_L2_MASK; io_be_setbit(&sdma->IntMask, l2irq); } static void mpc52xx_sdma_unmask(struct irq_data *d) { - int irq; - int l2irq; - - irq = irq_map[d->irq].hwirq; - l2irq = irq & MPC52xx_IRQ_L2_MASK; - + int l2irq = irqd_to_hwirq(d) & MPC52xx_IRQ_L2_MASK; io_be_clrbit(&sdma->IntMask, l2irq); } static void mpc52xx_sdma_ack(struct irq_data *d) { - int irq; - int l2irq; - - irq = irq_map[d->irq].hwirq; - l2irq = irq & MPC52xx_IRQ_L2_MASK; - + int l2irq = irqd_to_hwirq(d) & MPC52xx_IRQ_L2_MASK; out_be32(&sdma->IntPend, 1 << l2irq); } diff --git a/arch/powerpc/platforms/82xx/pq2ads-pci-pic.c b/arch/powerpc/platforms/82xx/pq2ads-pci-pic.c index 4a4eb6f..5d6c34c 100644 --- a/arch/powerpc/platforms/82xx/pq2ads-pci-pic.c +++ b/arch/powerpc/platforms/82xx/pq2ads-pci-pic.c @@ -42,7 +42,7 @@ struct pq2ads_pci_pic { static void pq2ads_pci_mask_irq(struct irq_data *d) { struct pq2ads_pci_pic *priv = irq_data_get_irq_chip_data(d); - int irq = NUM_IRQS - virq_to_hw(d->irq) - 1; + int irq = NUM_IRQS - irqd_to_hwirq(d) - 1; if (irq != -1) { unsigned long flags; @@ -58,7 +58,7 @@ static void pq2ads_pci_mask_irq(struct irq_data *d) static void pq2ads_pci_unmask_irq(struct irq_data *d) { struct pq2ads_pci_pic *priv = irq_data_get_irq_chip_data(d); - int irq = NUM_IRQS - virq_to_hw(d->irq) - 1; + int irq = NUM_IRQS - irqd_to_hwirq(d) - 1; if (irq != -1) { unsigned long flags; diff --git a/arch/powerpc/platforms/85xx/socrates_fpga_pic.c b/arch/powerpc/platforms/85xx/socrates_fpga_pic.c index db86462..12cb9bb 100644 --- a/arch/powerpc/platforms/85xx/socrates_fpga_pic.c +++ b/arch/powerpc/platforms/85xx/socrates_fpga_pic.c @@ -48,8 +48,6 @@ static struct socrates_fpga_irq_info fpga_irqs[SOCRATES_FPGA_NUM_IRQS] = { [8] = {0, IRQ_TYPE_LEVEL_HIGH}, }; -#define socrates_fpga_irq_to_hw(virq) ((unsigned int)irq_map[virq].hwirq) - static DEFINE_RAW_SPINLOCK(socrates_fpga_pic_lock); static void __iomem *socrates_fpga_pic_iobase; @@ -110,11 +108,9 @@ void socrates_fpga_pic_cascade(unsigned int irq, struct irq_desc *desc) static void socrates_fpga_pic_ack(struct irq_data *d) { unsigned long flags; - unsigned int hwirq, irq_line; + unsigned int irq_line, hwirq = irqd_to_hwirq(d); uint32_t mask; - hwirq = socrates_fpga_irq_to_hw(d->irq); - irq_line = fpga_irqs[hwirq].irq_line; raw_spin_lock_irqsave(&socrates_fpga_pic_lock, flags); mask = socrates_fpga_pic_read(FPGA_PIC_IRQMASK(irq_line)) @@ -127,12 +123,10 @@ static void socrates_fpga_pic_ack(struct irq_data *d) static void socrates_fpga_pic_mask(struct irq_data *d) { unsigned long flags; - unsigned int hwirq; + unsigned int hwirq = irqd_to_hwirq(d); int irq_line; u32 mask; - hwirq = socrates_fpga_irq_to_hw(d->irq); - irq_line = fpga_irqs[hwirq].irq_line; raw_spin_lock_irqsave(&socrates_fpga_pic_lock, flags); mask = socrates_fpga_pic_read(FPGA_PIC_IRQMASK(irq_line)) @@ -145,12 +139,10 @@ static void socrates_fpga_pic_mask(struct irq_data *d) static void socrates_fpga_pic_mask_ack(struct irq_data *d) { unsigned long flags; - unsigned int hwirq; + unsigned int hwirq = irqd_to_hwirq(d); int irq_line; u32 mask; - hwirq = socrates_fpga_irq_to_hw(d->irq); - irq_line = fpga_irqs[hwirq].irq_line; raw_spin_lock_irqsave(&socrates_fpga_pic_lock, flags); mask = socrates_fpga_pic_read(FPGA_PIC_IRQMASK(irq_line)) @@ -164,12 +156,10 @@ static void socrates_fpga_pic_mask_ack(struct irq_data *d) static void socrates_fpga_pic_unmask(struct irq_data *d) { unsigned long flags; - unsigned int hwirq; + unsigned int hwirq = irqd_to_hwirq(d); int irq_line; u32 mask; - hwirq = socrates_fpga_irq_to_hw(d->irq); - irq_line = fpga_irqs[hwirq].irq_line; raw_spin_lock_irqsave(&socrates_fpga_pic_lock, flags); mask = socrates_fpga_pic_read(FPGA_PIC_IRQMASK(irq_line)) @@ -182,12 +172,10 @@ static void socrates_fpga_pic_unmask(struct irq_data *d) static void socrates_fpga_pic_eoi(struct irq_data *d) { unsigned long flags; - unsigned int hwirq; + unsigned int hwirq = irqd_to_hwirq(d); int irq_line; u32 mask; - hwirq = socrates_fpga_irq_to_hw(d->irq); - irq_line = fpga_irqs[hwirq].irq_line; raw_spin_lock_irqsave(&socrates_fpga_pic_lock, flags); mask = socrates_fpga_pic_read(FPGA_PIC_IRQMASK(irq_line)) @@ -201,12 +189,10 @@ static int socrates_fpga_pic_set_type(struct irq_data *d, unsigned int flow_type) { unsigned long flags; - unsigned int hwirq; + unsigned int hwirq = irqd_to_hwirq(d); int polarity; u32 mask; - hwirq = socrates_fpga_irq_to_hw(d->irq); - if (fpga_irqs[hwirq].type != IRQ_TYPE_NONE) return -EINVAL; diff --git a/arch/powerpc/platforms/86xx/gef_pic.c b/arch/powerpc/platforms/86xx/gef_pic.c index 0beec7d..94594e5 100644 --- a/arch/powerpc/platforms/86xx/gef_pic.c +++ b/arch/powerpc/platforms/86xx/gef_pic.c @@ -46,8 +46,6 @@ #define GEF_PIC_CPU0_MCP_MASK GEF_PIC_MCP_MASK(0) #define GEF_PIC_CPU1_MCP_MASK GEF_PIC_MCP_MASK(1) -#define gef_irq_to_hw(virq) ((unsigned int)irq_map[virq].hwirq) - static DEFINE_RAW_SPINLOCK(gef_pic_lock); @@ -113,11 +111,9 @@ void gef_pic_cascade(unsigned int irq, struct irq_desc *desc) static void gef_pic_mask(struct irq_data *d) { unsigned long flags; - unsigned int hwirq; + unsigned int hwirq = irqd_to_hwirq(d); u32 mask; - hwirq = gef_irq_to_hw(d->irq); - raw_spin_lock_irqsave(&gef_pic_lock, flags); mask = in_be32(gef_pic_irq_reg_base + GEF_PIC_INTR_MASK(0)); mask &= ~(1 << hwirq); @@ -136,11 +132,9 @@ static void gef_pic_mask_ack(struct irq_data *d) static void gef_pic_unmask(struct irq_data *d) { unsigned long flags; - unsigned int hwirq; + unsigned int hwirq = irqd_to_hwirq(d); u32 mask; - hwirq = gef_irq_to_hw(d->irq); - raw_spin_lock_irqsave(&gef_pic_lock, flags); mask = in_be32(gef_pic_irq_reg_base + GEF_PIC_INTR_MASK(0)); mask |= (1 << hwirq); diff --git a/arch/powerpc/platforms/8xx/m8xx_setup.c b/arch/powerpc/platforms/8xx/m8xx_setup.c index 9ecce99..1e12108 100644 --- a/arch/powerpc/platforms/8xx/m8xx_setup.c +++ b/arch/powerpc/platforms/8xx/m8xx_setup.c @@ -150,7 +150,7 @@ void __init mpc8xx_calibrate_decr(void) */ cpu = of_find_node_by_type(NULL, "cpu"); virq= irq_of_parse_and_map(cpu, 0); - irq = irq_map[virq].hwirq; + irq = virq_to_hw(virq); sys_tmr2 = immr_map(im_sit); out_be16(&sys_tmr2->sit_tbscr, ((1 << (7 - (irq/2))) << 8) | diff --git a/arch/powerpc/platforms/cell/axon_msi.c b/arch/powerpc/platforms/cell/axon_msi.c index bb5ebf8..1e3329e 100644 --- a/arch/powerpc/platforms/cell/axon_msi.c +++ b/arch/powerpc/platforms/cell/axon_msi.c @@ -113,7 +113,7 @@ static void axon_msi_cascade(unsigned int irq, struct irq_desc *desc) pr_devel("axon_msi: woff %x roff %x msi %x\n", write_offset, msic->read_offset, msi); - if (msi < NR_IRQS && irq_map[msi].host == msic->irq_host) { + if (msi < NR_IRQS && virq_to_host(msi) == msic->irq_host) { generic_handle_irq(msi); msic->fifo_virt[idx] = cpu_to_le32(0xffffffff); } else { diff --git a/arch/powerpc/platforms/cell/spider-pic.c b/arch/powerpc/platforms/cell/spider-pic.c index c5cf50e..34d2b99 100644 --- a/arch/powerpc/platforms/cell/spider-pic.c +++ b/arch/powerpc/platforms/cell/spider-pic.c @@ -70,7 +70,7 @@ static struct spider_pic spider_pics[SPIDER_CHIP_COUNT]; static struct spider_pic *spider_virq_to_pic(unsigned int virq) { - return irq_map[virq].host->host_data; + return virq_to_host(virq)->host_data; } static void __iomem *spider_get_irq_config(struct spider_pic *pic, @@ -82,7 +82,7 @@ static void __iomem *spider_get_irq_config(struct spider_pic *pic, static void spider_unmask_irq(struct irq_data *d) { struct spider_pic *pic = spider_virq_to_pic(d->irq); - void __iomem *cfg = spider_get_irq_config(pic, irq_map[d->irq].hwirq); + void __iomem *cfg = spider_get_irq_config(pic, irqd_to_hwirq(d)); out_be32(cfg, in_be32(cfg) | 0x30000000u); } @@ -90,7 +90,7 @@ static void spider_unmask_irq(struct irq_data *d) static void spider_mask_irq(struct irq_data *d) { struct spider_pic *pic = spider_virq_to_pic(d->irq); - void __iomem *cfg = spider_get_irq_config(pic, irq_map[d->irq].hwirq); + void __iomem *cfg = spider_get_irq_config(pic, irqd_to_hwirq(d)); out_be32(cfg, in_be32(cfg) & ~0x30000000u); } @@ -98,7 +98,7 @@ static void spider_mask_irq(struct irq_data *d) static void spider_ack_irq(struct irq_data *d) { struct spider_pic *pic = spider_virq_to_pic(d->irq); - unsigned int src = irq_map[d->irq].hwirq; + unsigned int src = irqd_to_hwirq(d); /* Reset edge detection logic if necessary */ @@ -117,7 +117,7 @@ static int spider_set_irq_type(struct irq_data *d, unsigned int type) { unsigned int sense = type & IRQ_TYPE_SENSE_MASK; struct spider_pic *pic = spider_virq_to_pic(d->irq); - unsigned int hw = irq_map[d->irq].hwirq; + unsigned int hw = irqd_to_hwirq(d); void __iomem *cfg = spider_get_irq_config(pic, hw); u32 old_mask; u32 ic; diff --git a/arch/powerpc/platforms/embedded6xx/flipper-pic.c b/arch/powerpc/platforms/embedded6xx/flipper-pic.c index 12aa62b..77cbe4c 100644 --- a/arch/powerpc/platforms/embedded6xx/flipper-pic.c +++ b/arch/powerpc/platforms/embedded6xx/flipper-pic.c @@ -48,7 +48,7 @@ static void flipper_pic_mask_and_ack(struct irq_data *d) { - int irq = virq_to_hw(d->irq); + int irq = irqd_to_hwirq(d); void __iomem *io_base = irq_data_get_irq_chip_data(d); u32 mask = 1 << irq; @@ -59,7 +59,7 @@ static void flipper_pic_mask_and_ack(struct irq_data *d) static void flipper_pic_ack(struct irq_data *d) { - int irq = virq_to_hw(d->irq); + int irq = irqd_to_hwirq(d); void __iomem *io_base = irq_data_get_irq_chip_data(d); /* this is at least needed for RSW */ @@ -68,7 +68,7 @@ static void flipper_pic_ack(struct irq_data *d) static void flipper_pic_mask(struct irq_data *d) { - int irq = virq_to_hw(d->irq); + int irq = irqd_to_hwirq(d); void __iomem *io_base = irq_data_get_irq_chip_data(d); clrbits32(io_base + FLIPPER_IMR, 1 << irq); @@ -76,7 +76,7 @@ static void flipper_pic_mask(struct irq_data *d) static void flipper_pic_unmask(struct irq_data *d) { - int irq = virq_to_hw(d->irq); + int irq = irqd_to_hwirq(d); void __iomem *io_base = irq_data_get_irq_chip_data(d); setbits32(io_base + FLIPPER_IMR, 1 << irq); diff --git a/arch/powerpc/platforms/embedded6xx/hlwd-pic.c b/arch/powerpc/platforms/embedded6xx/hlwd-pic.c index 2bdddfc..44b398b 100644 --- a/arch/powerpc/platforms/embedded6xx/hlwd-pic.c +++ b/arch/powerpc/platforms/embedded6xx/hlwd-pic.c @@ -43,7 +43,7 @@ static void hlwd_pic_mask_and_ack(struct irq_data *d) { - int irq = virq_to_hw(d->irq); + int irq = irqd_to_hwirq(d); void __iomem *io_base = irq_data_get_irq_chip_data(d); u32 mask = 1 << irq; @@ -53,7 +53,7 @@ static void hlwd_pic_mask_and_ack(struct irq_data *d) static void hlwd_pic_ack(struct irq_data *d) { - int irq = virq_to_hw(d->irq); + int irq = irqd_to_hwirq(d); void __iomem *io_base = irq_data_get_irq_chip_data(d); out_be32(io_base + HW_BROADWAY_ICR, 1 << irq); @@ -61,7 +61,7 @@ static void hlwd_pic_ack(struct irq_data *d) static void hlwd_pic_mask(struct irq_data *d) { - int irq = virq_to_hw(d->irq); + int irq = irqd_to_hwirq(d); void __iomem *io_base = irq_data_get_irq_chip_data(d); clrbits32(io_base + HW_BROADWAY_IMR, 1 << irq); @@ -69,7 +69,7 @@ static void hlwd_pic_mask(struct irq_data *d) static void hlwd_pic_unmask(struct irq_data *d) { - int irq = virq_to_hw(d->irq); + int irq = irqd_to_hwirq(d); void __iomem *io_base = irq_data_get_irq_chip_data(d); setbits32(io_base + HW_BROADWAY_IMR, 1 << irq); diff --git a/arch/powerpc/platforms/iseries/irq.c b/arch/powerpc/platforms/iseries/irq.c index 52a6889..375c21c 100644 --- a/arch/powerpc/platforms/iseries/irq.c +++ b/arch/powerpc/platforms/iseries/irq.c @@ -171,7 +171,7 @@ static void iseries_enable_IRQ(struct irq_data *d) { u32 bus, dev_id, function, mask; const u32 sub_bus = 0; - unsigned int rirq = (unsigned int)irq_map[d->irq].hwirq; + unsigned int rirq = (unsigned int)irqd_to_hwirq(d); /* The IRQ has already been locked by the caller */ bus = REAL_IRQ_TO_BUS(rirq); @@ -188,7 +188,7 @@ static unsigned int iseries_startup_IRQ(struct irq_data *d) { u32 bus, dev_id, function, mask; const u32 sub_bus = 0; - unsigned int rirq = (unsigned int)irq_map[d->irq].hwirq; + unsigned int rirq = (unsigned int)irqd_to_hwirq(d); bus = REAL_IRQ_TO_BUS(rirq); function = REAL_IRQ_TO_FUNC(rirq); @@ -234,7 +234,7 @@ static void iseries_shutdown_IRQ(struct irq_data *d) { u32 bus, dev_id, function, mask; const u32 sub_bus = 0; - unsigned int rirq = (unsigned int)irq_map[d->irq].hwirq; + unsigned int rirq = (unsigned int)irqd_to_hwirq(d); /* irq should be locked by the caller */ bus = REAL_IRQ_TO_BUS(rirq); @@ -257,7 +257,7 @@ static void iseries_disable_IRQ(struct irq_data *d) { u32 bus, dev_id, function, mask; const u32 sub_bus = 0; - unsigned int rirq = (unsigned int)irq_map[d->irq].hwirq; + unsigned int rirq = (unsigned int)irqd_to_hwirq(d); /* The IRQ has already been locked by the caller */ bus = REAL_IRQ_TO_BUS(rirq); @@ -271,7 +271,7 @@ static void iseries_disable_IRQ(struct irq_data *d) static void iseries_end_IRQ(struct irq_data *d) { - unsigned int rirq = (unsigned int)irq_map[d->irq].hwirq; + unsigned int rirq = (unsigned int)irqd_to_hwirq(d); HvCallPci_eoi(REAL_IRQ_TO_BUS(rirq), REAL_IRQ_TO_SUBBUS(rirq), (REAL_IRQ_TO_IDSEL(rirq) << 4) + REAL_IRQ_TO_FUNC(rirq)); diff --git a/arch/powerpc/platforms/powermac/pic.c b/arch/powerpc/platforms/powermac/pic.c index 023f240..2f34ad0 100644 --- a/arch/powerpc/platforms/powermac/pic.c +++ b/arch/powerpc/platforms/powermac/pic.c @@ -84,7 +84,7 @@ static void __pmac_retrigger(unsigned int irq_nr) static void pmac_mask_and_ack_irq(struct irq_data *d) { - unsigned int src = irq_map[d->irq].hwirq; + unsigned int src = irqd_to_hwirq(d); unsigned long bit = 1UL << (src & 0x1f); int i = src >> 5; unsigned long flags; @@ -106,7 +106,7 @@ static void pmac_mask_and_ack_irq(struct irq_data *d) static void pmac_ack_irq(struct irq_data *d) { - unsigned int src = irq_map[d->irq].hwirq; + unsigned int src = irqd_to_hwirq(d); unsigned long bit = 1UL << (src & 0x1f); int i = src >> 5; unsigned long flags; @@ -152,7 +152,7 @@ static void __pmac_set_irq_mask(unsigned int irq_nr, int nokicklost) static unsigned int pmac_startup_irq(struct irq_data *d) { unsigned long flags; - unsigned int src = irq_map[d->irq].hwirq; + unsigned int src = irqd_to_hwirq(d); unsigned long bit = 1UL << (src & 0x1f); int i = src >> 5; @@ -169,7 +169,7 @@ static unsigned int pmac_startup_irq(struct irq_data *d) static void pmac_mask_irq(struct irq_data *d) { unsigned long flags; - unsigned int src = irq_map[d->irq].hwirq; + unsigned int src = irqd_to_hwirq(d); raw_spin_lock_irqsave(&pmac_pic_lock, flags); __clear_bit(src, ppc_cached_irq_mask); @@ -180,7 +180,7 @@ static void pmac_mask_irq(struct irq_data *d) static void pmac_unmask_irq(struct irq_data *d) { unsigned long flags; - unsigned int src = irq_map[d->irq].hwirq; + unsigned int src = irqd_to_hwirq(d); raw_spin_lock_irqsave(&pmac_pic_lock, flags); __set_bit(src, ppc_cached_irq_mask); @@ -193,7 +193,7 @@ static int pmac_retrigger(struct irq_data *d) unsigned long flags; raw_spin_lock_irqsave(&pmac_pic_lock, flags); - __pmac_retrigger(irq_map[d->irq].hwirq); + __pmac_retrigger(irqd_to_hwirq(d)); raw_spin_unlock_irqrestore(&pmac_pic_lock, flags); return 1; } diff --git a/arch/powerpc/platforms/pseries/ras.c b/arch/powerpc/platforms/pseries/ras.c index c55d7ad..164a8eb 100644 --- a/arch/powerpc/platforms/pseries/ras.c +++ b/arch/powerpc/platforms/pseries/ras.c @@ -122,7 +122,7 @@ static irqreturn_t ras_epow_interrupt(int irq, void *dev_id) status = rtas_call(ras_check_exception_token, 6, 1, NULL, RTAS_VECTOR_EXTERNAL_INTERRUPT, - irq_map[irq].hwirq, + virq_to_hw(irq), RTAS_EPOW_WARNING | RTAS_POWERMGM_EVENTS, critical, __pa(&ras_log_buf), rtas_get_error_log_max()); @@ -157,7 +157,7 @@ static irqreturn_t ras_error_interrupt(int irq, void *dev_id) status = rtas_call(ras_check_exception_token, 6, 1, NULL, RTAS_VECTOR_EXTERNAL_INTERRUPT, - irq_map[irq].hwirq, + virq_to_hw(irq), RTAS_INTERNAL_ERROR, 1 /*Time Critical */, __pa(&ras_log_buf), rtas_get_error_log_max()); diff --git a/arch/powerpc/sysdev/cpm1.c b/arch/powerpc/sysdev/cpm1.c index e0bc944..350787c 100644 --- a/arch/powerpc/sysdev/cpm1.c +++ b/arch/powerpc/sysdev/cpm1.c @@ -58,21 +58,21 @@ static struct irq_host *cpm_pic_host; static void cpm_mask_irq(struct irq_data *d) { - unsigned int cpm_vec = (unsigned int)irq_map[d->irq].hwirq; + unsigned int cpm_vec = (unsigned int)irqd_to_hwirq(d); clrbits32(&cpic_reg->cpic_cimr, (1 << cpm_vec)); } static void cpm_unmask_irq(struct irq_data *d) { - unsigned int cpm_vec = (unsigned int)irq_map[d->irq].hwirq; + unsigned int cpm_vec = (unsigned int)irqd_to_hwirq(d); setbits32(&cpic_reg->cpic_cimr, (1 << cpm_vec)); } static void cpm_end_irq(struct irq_data *d) { - unsigned int cpm_vec = (unsigned int)irq_map[d->irq].hwirq; + unsigned int cpm_vec = (unsigned int)irqd_to_hwirq(d); out_be32(&cpic_reg->cpic_cisr, (1 << cpm_vec)); } @@ -157,7 +157,7 @@ unsigned int cpm_pic_init(void) goto end; /* Initialize the CPM interrupt controller. */ - hwirq = (unsigned int)irq_map[sirq].hwirq; + hwirq = (unsigned int)virq_to_hw(sirq); out_be32(&cpic_reg->cpic_cicr, (CICR_SCD_SCC4 | CICR_SCC_SCC3 | CICR_SCB_SCC2 | CICR_SCA_SCC1) | ((hwirq/2) << 13) | CICR_HP_MASK); diff --git a/arch/powerpc/sysdev/cpm2_pic.c b/arch/powerpc/sysdev/cpm2_pic.c index 5495c1b..bcab50e 100644 --- a/arch/powerpc/sysdev/cpm2_pic.c +++ b/arch/powerpc/sysdev/cpm2_pic.c @@ -81,7 +81,7 @@ static const u_char irq_to_siubit[] = { static void cpm2_mask_irq(struct irq_data *d) { int bit, word; - unsigned int irq_nr = virq_to_hw(d->irq); + unsigned int irq_nr = irqd_to_hwirq(d); bit = irq_to_siubit[irq_nr]; word = irq_to_siureg[irq_nr]; @@ -93,7 +93,7 @@ static void cpm2_mask_irq(struct irq_data *d) static void cpm2_unmask_irq(struct irq_data *d) { int bit, word; - unsigned int irq_nr = virq_to_hw(d->irq); + unsigned int irq_nr = irqd_to_hwirq(d); bit = irq_to_siubit[irq_nr]; word = irq_to_siureg[irq_nr]; @@ -105,7 +105,7 @@ static void cpm2_unmask_irq(struct irq_data *d) static void cpm2_ack(struct irq_data *d) { int bit, word; - unsigned int irq_nr = virq_to_hw(d->irq); + unsigned int irq_nr = irqd_to_hwirq(d); bit = irq_to_siubit[irq_nr]; word = irq_to_siureg[irq_nr]; @@ -116,7 +116,7 @@ static void cpm2_ack(struct irq_data *d) static void cpm2_end_irq(struct irq_data *d) { int bit, word; - unsigned int irq_nr = virq_to_hw(d->irq); + unsigned int irq_nr = irqd_to_hwirq(d); bit = irq_to_siubit[irq_nr]; word = irq_to_siureg[irq_nr]; @@ -133,7 +133,7 @@ static void cpm2_end_irq(struct irq_data *d) static int cpm2_set_irq_type(struct irq_data *d, unsigned int flow_type) { - unsigned int src = virq_to_hw(d->irq); + unsigned int src = irqd_to_hwirq(d); unsigned int vold, vnew, edibit; /* Port C interrupts are either IRQ_TYPE_EDGE_FALLING or diff --git a/arch/powerpc/sysdev/ipic.c b/arch/powerpc/sysdev/ipic.c index fa438be..f0ece79 100644 --- a/arch/powerpc/sysdev/ipic.c +++ b/arch/powerpc/sysdev/ipic.c @@ -521,12 +521,10 @@ static inline struct ipic * ipic_from_irq(unsigned int virq) return primary_ipic; } -#define ipic_irq_to_hw(virq) ((unsigned int)irq_map[virq].hwirq) - static void ipic_unmask_irq(struct irq_data *d) { struct ipic *ipic = ipic_from_irq(d->irq); - unsigned int src = ipic_irq_to_hw(d->irq); + unsigned int src = irqd_to_hwirq(d); unsigned long flags; u32 temp; @@ -542,7 +540,7 @@ static void ipic_unmask_irq(struct irq_data *d) static void ipic_mask_irq(struct irq_data *d) { struct ipic *ipic = ipic_from_irq(d->irq); - unsigned int src = ipic_irq_to_hw(d->irq); + unsigned int src = irqd_to_hwirq(d); unsigned long flags; u32 temp; @@ -562,7 +560,7 @@ static void ipic_mask_irq(struct irq_data *d) static void ipic_ack_irq(struct irq_data *d) { struct ipic *ipic = ipic_from_irq(d->irq); - unsigned int src = ipic_irq_to_hw(d->irq); + unsigned int src = irqd_to_hwirq(d); unsigned long flags; u32 temp; @@ -581,7 +579,7 @@ static void ipic_ack_irq(struct irq_data *d) static void ipic_mask_irq_and_ack(struct irq_data *d) { struct ipic *ipic = ipic_from_irq(d->irq); - unsigned int src = ipic_irq_to_hw(d->irq); + unsigned int src = irqd_to_hwirq(d); unsigned long flags; u32 temp; @@ -604,7 +602,7 @@ static void ipic_mask_irq_and_ack(struct irq_data *d) static int ipic_set_irq_type(struct irq_data *d, unsigned int flow_type) { struct ipic *ipic = ipic_from_irq(d->irq); - unsigned int src = ipic_irq_to_hw(d->irq); + unsigned int src = irqd_to_hwirq(d); unsigned int vold, vnew, edibit; if (flow_type == IRQ_TYPE_NONE) @@ -793,7 +791,7 @@ struct ipic * __init ipic_init(struct device_node *node, unsigned int flags) int ipic_set_priority(unsigned int virq, unsigned int priority) { struct ipic *ipic = ipic_from_irq(virq); - unsigned int src = ipic_irq_to_hw(virq); + unsigned int src = virq_to_hw(virq); u32 temp; if (priority > 7) @@ -821,7 +819,7 @@ int ipic_set_priority(unsigned int virq, unsigned int priority) void ipic_set_highest_priority(unsigned int virq) { struct ipic *ipic = ipic_from_irq(virq); - unsigned int src = ipic_irq_to_hw(virq); + unsigned int src = virq_to_hw(virq); u32 temp; temp = ipic_read(ipic->regs, IPIC_SICFR); diff --git a/arch/powerpc/sysdev/mpc8xx_pic.c b/arch/powerpc/sysdev/mpc8xx_pic.c index a88800f..20924f2 100644 --- a/arch/powerpc/sysdev/mpc8xx_pic.c +++ b/arch/powerpc/sysdev/mpc8xx_pic.c @@ -28,7 +28,7 @@ int cpm_get_irq(struct pt_regs *regs); static void mpc8xx_unmask_irq(struct irq_data *d) { int bit, word; - unsigned int irq_nr = (unsigned int)irq_map[d->irq].hwirq; + unsigned int irq_nr = (unsigned int)irqd_to_hwirq(d); bit = irq_nr & 0x1f; word = irq_nr >> 5; @@ -40,7 +40,7 @@ static void mpc8xx_unmask_irq(struct irq_data *d) static void mpc8xx_mask_irq(struct irq_data *d) { int bit, word; - unsigned int irq_nr = (unsigned int)irq_map[d->irq].hwirq; + unsigned int irq_nr = (unsigned int)irqd_to_hwirq(d); bit = irq_nr & 0x1f; word = irq_nr >> 5; @@ -52,7 +52,7 @@ static void mpc8xx_mask_irq(struct irq_data *d) static void mpc8xx_ack(struct irq_data *d) { int bit; - unsigned int irq_nr = (unsigned int)irq_map[d->irq].hwirq; + unsigned int irq_nr = (unsigned int)irqd_to_hwirq(d); bit = irq_nr & 0x1f; out_be32(&siu_reg->sc_sipend, 1 << (31-bit)); @@ -61,7 +61,7 @@ static void mpc8xx_ack(struct irq_data *d) static void mpc8xx_end_irq(struct irq_data *d) { int bit, word; - unsigned int irq_nr = (unsigned int)irq_map[d->irq].hwirq; + unsigned int irq_nr = (unsigned int)irqd_to_hwirq(d); bit = irq_nr & 0x1f; word = irq_nr >> 5; @@ -73,7 +73,7 @@ static void mpc8xx_end_irq(struct irq_data *d) static int mpc8xx_set_irq_type(struct irq_data *d, unsigned int flow_type) { if (flow_type & IRQ_TYPE_EDGE_FALLING) { - irq_hw_number_t hw = (unsigned int)irq_map[d->irq].hwirq; + irq_hw_number_t hw = (unsigned int)irqd_to_hwirq(d); unsigned int siel = in_be32(&siu_reg->sc_siel); /* only external IRQ senses are programmable */ diff --git a/arch/powerpc/sysdev/mpc8xxx_gpio.c b/arch/powerpc/sysdev/mpc8xxx_gpio.c index 0892a28..fb4963a 100644 --- a/arch/powerpc/sysdev/mpc8xxx_gpio.c +++ b/arch/powerpc/sysdev/mpc8xxx_gpio.c @@ -163,7 +163,7 @@ static void mpc8xxx_irq_unmask(struct irq_data *d) spin_lock_irqsave(&mpc8xxx_gc->lock, flags); - setbits32(mm->regs + GPIO_IMR, mpc8xxx_gpio2mask(virq_to_hw(d->irq))); + setbits32(mm->regs + GPIO_IMR, mpc8xxx_gpio2mask(irqd_to_hwirq(d))); spin_unlock_irqrestore(&mpc8xxx_gc->lock, flags); } @@ -176,7 +176,7 @@ static void mpc8xxx_irq_mask(struct irq_data *d) spin_lock_irqsave(&mpc8xxx_gc->lock, flags); - clrbits32(mm->regs + GPIO_IMR, mpc8xxx_gpio2mask(virq_to_hw(d->irq))); + clrbits32(mm->regs + GPIO_IMR, mpc8xxx_gpio2mask(irqd_to_hwirq(d))); spin_unlock_irqrestore(&mpc8xxx_gc->lock, flags); } @@ -186,7 +186,7 @@ static void mpc8xxx_irq_ack(struct irq_data *d) struct mpc8xxx_gpio_chip *mpc8xxx_gc = irq_data_get_irq_chip_data(d); struct of_mm_gpio_chip *mm = &mpc8xxx_gc->mm_gc; - out_be32(mm->regs + GPIO_IER, mpc8xxx_gpio2mask(virq_to_hw(d->irq))); + out_be32(mm->regs + GPIO_IER, mpc8xxx_gpio2mask(irqd_to_hwirq(d))); } static int mpc8xxx_irq_set_type(struct irq_data *d, unsigned int flow_type) @@ -199,14 +199,14 @@ static int mpc8xxx_irq_set_type(struct irq_data *d, unsigned int flow_type) case IRQ_TYPE_EDGE_FALLING: spin_lock_irqsave(&mpc8xxx_gc->lock, flags); setbits32(mm->regs + GPIO_ICR, - mpc8xxx_gpio2mask(virq_to_hw(d->irq))); + mpc8xxx_gpio2mask(irqd_to_hwirq(d))); spin_unlock_irqrestore(&mpc8xxx_gc->lock, flags); break; case IRQ_TYPE_EDGE_BOTH: spin_lock_irqsave(&mpc8xxx_gc->lock, flags); clrbits32(mm->regs + GPIO_ICR, - mpc8xxx_gpio2mask(virq_to_hw(d->irq))); + mpc8xxx_gpio2mask(irqd_to_hwirq(d))); spin_unlock_irqrestore(&mpc8xxx_gc->lock, flags); break; @@ -221,7 +221,7 @@ static int mpc512x_irq_set_type(struct irq_data *d, unsigned int flow_type) { struct mpc8xxx_gpio_chip *mpc8xxx_gc = irq_data_get_irq_chip_data(d); struct of_mm_gpio_chip *mm = &mpc8xxx_gc->mm_gc; - unsigned long gpio = virq_to_hw(d->irq); + unsigned long gpio = irqd_to_hwirq(d); void __iomem *reg; unsigned int shift; unsigned long flags; diff --git a/arch/powerpc/sysdev/mpic.c b/arch/powerpc/sysdev/mpic.c index f91c065..824a94f 100644 --- a/arch/powerpc/sysdev/mpic.c +++ b/arch/powerpc/sysdev/mpic.c @@ -607,8 +607,6 @@ static int irq_choose_cpu(const struct cpumask *mask) } #endif -#define mpic_irq_to_hw(virq) ((unsigned int)irq_map[virq].hwirq) - /* Find an mpic associated with a given linux interrupt */ static struct mpic *mpic_find(unsigned int irq) { @@ -621,7 +619,7 @@ static struct mpic *mpic_find(unsigned int irq) /* Determine if the linux irq is an IPI */ static unsigned int mpic_is_ipi(struct mpic *mpic, unsigned int irq) { - unsigned int src = mpic_irq_to_hw(irq); + unsigned int src = virq_to_hw(irq); return (src >= mpic->ipi_vecs[0] && src <= mpic->ipi_vecs[3]); } @@ -674,7 +672,7 @@ void mpic_unmask_irq(struct irq_data *d) { unsigned int loops = 100000; struct mpic *mpic = mpic_from_irq_data(d); - unsigned int src = mpic_irq_to_hw(d->irq); + unsigned int src = irqd_to_hwirq(d); DBG("%p: %s: enable_irq: %d (src %d)\n", mpic, mpic->name, d->irq, src); @@ -695,7 +693,7 @@ void mpic_mask_irq(struct irq_data *d) { unsigned int loops = 100000; struct mpic *mpic = mpic_from_irq_data(d); - unsigned int src = mpic_irq_to_hw(d->irq); + unsigned int src = irqd_to_hwirq(d); DBG("%s: disable_irq: %d (src %d)\n", mpic->name, d->irq, src); @@ -733,7 +731,7 @@ void mpic_end_irq(struct irq_data *d) static void mpic_unmask_ht_irq(struct irq_data *d) { struct mpic *mpic = mpic_from_irq_data(d); - unsigned int src = mpic_irq_to_hw(d->irq); + unsigned int src = irqd_to_hwirq(d); mpic_unmask_irq(d); @@ -744,7 +742,7 @@ static void mpic_unmask_ht_irq(struct irq_data *d) static unsigned int mpic_startup_ht_irq(struct irq_data *d) { struct mpic *mpic = mpic_from_irq_data(d); - unsigned int src = mpic_irq_to_hw(d->irq); + unsigned int src = irqd_to_hwirq(d); mpic_unmask_irq(d); mpic_startup_ht_interrupt(mpic, src, irqd_is_level_type(d)); @@ -755,7 +753,7 @@ static unsigned int mpic_startup_ht_irq(struct irq_data *d) static void mpic_shutdown_ht_irq(struct irq_data *d) { struct mpic *mpic = mpic_from_irq_data(d); - unsigned int src = mpic_irq_to_hw(d->irq); + unsigned int src = irqd_to_hwirq(d); mpic_shutdown_ht_interrupt(mpic, src); mpic_mask_irq(d); @@ -764,7 +762,7 @@ static void mpic_shutdown_ht_irq(struct irq_data *d) static void mpic_end_ht_irq(struct irq_data *d) { struct mpic *mpic = mpic_from_irq_data(d); - unsigned int src = mpic_irq_to_hw(d->irq); + unsigned int src = irqd_to_hwirq(d); #ifdef DEBUG_IRQ DBG("%s: end_irq: %d\n", mpic->name, d->irq); @@ -785,7 +783,7 @@ static void mpic_end_ht_irq(struct irq_data *d) static void mpic_unmask_ipi(struct irq_data *d) { struct mpic *mpic = mpic_from_ipi(d); - unsigned int src = mpic_irq_to_hw(d->irq) - mpic->ipi_vecs[0]; + unsigned int src = virq_to_hw(d->irq) - mpic->ipi_vecs[0]; DBG("%s: enable_ipi: %d (ipi %d)\n", mpic->name, d->irq, src); mpic_ipi_write(src, mpic_ipi_read(src) & ~MPIC_VECPRI_MASK); @@ -816,7 +814,7 @@ int mpic_set_affinity(struct irq_data *d, const struct cpumask *cpumask, bool force) { struct mpic *mpic = mpic_from_irq_data(d); - unsigned int src = mpic_irq_to_hw(d->irq); + unsigned int src = irqd_to_hwirq(d); if (mpic->flags & MPIC_SINGLE_DEST_CPU) { int cpuid = irq_choose_cpu(cpumask); @@ -862,7 +860,7 @@ static unsigned int mpic_type_to_vecpri(struct mpic *mpic, unsigned int type) int mpic_set_irq_type(struct irq_data *d, unsigned int flow_type) { struct mpic *mpic = mpic_from_irq_data(d); - unsigned int src = mpic_irq_to_hw(d->irq); + unsigned int src = irqd_to_hwirq(d); unsigned int vecpri, vold, vnew; DBG("mpic: set_irq_type(mpic:@%p,virq:%d,src:0x%x,type:0x%x)\n", @@ -898,7 +896,7 @@ int mpic_set_irq_type(struct irq_data *d, unsigned int flow_type) void mpic_set_vector(unsigned int virq, unsigned int vector) { struct mpic *mpic = mpic_from_irq(virq); - unsigned int src = mpic_irq_to_hw(virq); + unsigned int src = virq_to_hw(virq); unsigned int vecpri; DBG("mpic: set_vector(mpic:@%p,virq:%d,src:%d,vector:0x%x)\n", @@ -916,7 +914,7 @@ void mpic_set_vector(unsigned int virq, unsigned int vector) void mpic_set_destination(unsigned int virq, unsigned int cpuid) { struct mpic *mpic = mpic_from_irq(virq); - unsigned int src = mpic_irq_to_hw(virq); + unsigned int src = virq_to_hw(virq); DBG("mpic: set_destination(mpic:@%p,virq:%d,src:%d,cpuid:0x%x)\n", mpic, virq, src, cpuid); @@ -1427,7 +1425,7 @@ void __init mpic_set_serial_int(struct mpic *mpic, int enable) void mpic_irq_set_priority(unsigned int irq, unsigned int pri) { struct mpic *mpic = mpic_find(irq); - unsigned int src = mpic_irq_to_hw(irq); + unsigned int src = virq_to_hw(irq); unsigned long flags; u32 reg; diff --git a/arch/powerpc/sysdev/mv64x60_pic.c b/arch/powerpc/sysdev/mv64x60_pic.c index e9c633c..14d1302 100644 --- a/arch/powerpc/sysdev/mv64x60_pic.c +++ b/arch/powerpc/sysdev/mv64x60_pic.c @@ -78,7 +78,7 @@ static struct irq_host *mv64x60_irq_host; static void mv64x60_mask_low(struct irq_data *d) { - int level2 = irq_map[d->irq].hwirq & MV64x60_LEVEL2_MASK; + int level2 = irqd_to_hwirq(d) & MV64x60_LEVEL2_MASK; unsigned long flags; spin_lock_irqsave(&mv64x60_lock, flags); @@ -91,7 +91,7 @@ static void mv64x60_mask_low(struct irq_data *d) static void mv64x60_unmask_low(struct irq_data *d) { - int level2 = irq_map[d->irq].hwirq & MV64x60_LEVEL2_MASK; + int level2 = irqd_to_hwirq(d) & MV64x60_LEVEL2_MASK; unsigned long flags; spin_lock_irqsave(&mv64x60_lock, flags); @@ -115,7 +115,7 @@ static struct irq_chip mv64x60_chip_low = { static void mv64x60_mask_high(struct irq_data *d) { - int level2 = irq_map[d->irq].hwirq & MV64x60_LEVEL2_MASK; + int level2 = irqd_to_hwirq(d) & MV64x60_LEVEL2_MASK; unsigned long flags; spin_lock_irqsave(&mv64x60_lock, flags); @@ -128,7 +128,7 @@ static void mv64x60_mask_high(struct irq_data *d) static void mv64x60_unmask_high(struct irq_data *d) { - int level2 = irq_map[d->irq].hwirq & MV64x60_LEVEL2_MASK; + int level2 = irqd_to_hwirq(d) & MV64x60_LEVEL2_MASK; unsigned long flags; spin_lock_irqsave(&mv64x60_lock, flags); @@ -152,7 +152,7 @@ static struct irq_chip mv64x60_chip_high = { static void mv64x60_mask_gpp(struct irq_data *d) { - int level2 = irq_map[d->irq].hwirq & MV64x60_LEVEL2_MASK; + int level2 = irqd_to_hwirq(d) & MV64x60_LEVEL2_MASK; unsigned long flags; spin_lock_irqsave(&mv64x60_lock, flags); @@ -165,7 +165,7 @@ static void mv64x60_mask_gpp(struct irq_data *d) static void mv64x60_mask_ack_gpp(struct irq_data *d) { - int level2 = irq_map[d->irq].hwirq & MV64x60_LEVEL2_MASK; + int level2 = irqd_to_hwirq(d) & MV64x60_LEVEL2_MASK; unsigned long flags; spin_lock_irqsave(&mv64x60_lock, flags); @@ -180,7 +180,7 @@ static void mv64x60_mask_ack_gpp(struct irq_data *d) static void mv64x60_unmask_gpp(struct irq_data *d) { - int level2 = irq_map[d->irq].hwirq & MV64x60_LEVEL2_MASK; + int level2 = irqd_to_hwirq(d) & MV64x60_LEVEL2_MASK; unsigned long flags; spin_lock_irqsave(&mv64x60_lock, flags); diff --git a/arch/powerpc/sysdev/qe_lib/qe_ic.c b/arch/powerpc/sysdev/qe_lib/qe_ic.c index 832d692..b2acda0 100644 --- a/arch/powerpc/sysdev/qe_lib/qe_ic.c +++ b/arch/powerpc/sysdev/qe_lib/qe_ic.c @@ -197,12 +197,10 @@ static inline struct qe_ic *qe_ic_from_irq_data(struct irq_data *d) return irq_data_get_irq_chip_data(d); } -#define virq_to_hw(virq) ((unsigned int)irq_map[virq].hwirq) - static void qe_ic_unmask_irq(struct irq_data *d) { struct qe_ic *qe_ic = qe_ic_from_irq_data(d); - unsigned int src = virq_to_hw(d->irq); + unsigned int src = irqd_to_hwirq(d); unsigned long flags; u32 temp; @@ -218,7 +216,7 @@ static void qe_ic_unmask_irq(struct irq_data *d) static void qe_ic_mask_irq(struct irq_data *d) { struct qe_ic *qe_ic = qe_ic_from_irq_data(d); - unsigned int src = virq_to_hw(d->irq); + unsigned int src = irqd_to_hwirq(d); unsigned long flags; u32 temp; diff --git a/arch/powerpc/sysdev/uic.c b/arch/powerpc/sysdev/uic.c index 5d91385..984cd20 100644 --- a/arch/powerpc/sysdev/uic.c +++ b/arch/powerpc/sysdev/uic.c @@ -41,8 +41,6 @@ #define UIC_VR 0x7 #define UIC_VCR 0x8 -#define uic_irq_to_hw(virq) (irq_map[virq].hwirq) - struct uic *primary_uic; struct uic { @@ -58,7 +56,7 @@ struct uic { static void uic_unmask_irq(struct irq_data *d) { struct uic *uic = irq_data_get_irq_chip_data(d); - unsigned int src = uic_irq_to_hw(d->irq); + unsigned int src = irqd_to_hwirq(d); unsigned long flags; u32 er, sr; @@ -76,7 +74,7 @@ static void uic_unmask_irq(struct irq_data *d) static void uic_mask_irq(struct irq_data *d) { struct uic *uic = irq_data_get_irq_chip_data(d); - unsigned int src = uic_irq_to_hw(d->irq); + unsigned int src = irqd_to_hwirq(d); unsigned long flags; u32 er; @@ -90,7 +88,7 @@ static void uic_mask_irq(struct irq_data *d) static void uic_ack_irq(struct irq_data *d) { struct uic *uic = irq_data_get_irq_chip_data(d); - unsigned int src = uic_irq_to_hw(d->irq); + unsigned int src = irqd_to_hwirq(d); unsigned long flags; spin_lock_irqsave(&uic->lock, flags); @@ -101,7 +99,7 @@ static void uic_ack_irq(struct irq_data *d) static void uic_mask_ack_irq(struct irq_data *d) { struct uic *uic = irq_data_get_irq_chip_data(d); - unsigned int src = uic_irq_to_hw(d->irq); + unsigned int src = irqd_to_hwirq(d); unsigned long flags; u32 er, sr; @@ -126,7 +124,7 @@ static void uic_mask_ack_irq(struct irq_data *d) static int uic_set_irq_type(struct irq_data *d, unsigned int flow_type) { struct uic *uic = irq_data_get_irq_chip_data(d); - unsigned int src = uic_irq_to_hw(d->irq); + unsigned int src = irqd_to_hwirq(d); unsigned long flags; int trigger, polarity; u32 tr, pr, mask; diff --git a/arch/powerpc/sysdev/xics/icp-hv.c b/arch/powerpc/sysdev/xics/icp-hv.c index b03d348..76e8724 100644 --- a/arch/powerpc/sysdev/xics/icp-hv.c +++ b/arch/powerpc/sysdev/xics/icp-hv.c @@ -58,7 +58,7 @@ static inline void icp_hv_set_qirr(int n_cpu , u8 value) static void icp_hv_eoi(struct irq_data *d) { - unsigned int hw_irq = (unsigned int)irq_data_to_hw(d); + unsigned int hw_irq = (unsigned int)irqd_to_hwirq(d); iosync(); icp_hv_set_xirr((xics_pop_cppr() << 24) | hw_irq); diff --git a/arch/powerpc/sysdev/xics/icp-native.c b/arch/powerpc/sysdev/xics/icp-native.c index be5e3d7..d9e0515 100644 --- a/arch/powerpc/sysdev/xics/icp-native.c +++ b/arch/powerpc/sysdev/xics/icp-native.c @@ -80,7 +80,7 @@ static void icp_native_set_cpu_priority(unsigned char cppr) static void icp_native_eoi(struct irq_data *d) { - unsigned int hw_irq = (unsigned int)irq_data_to_hw(d); + unsigned int hw_irq = (unsigned int)irqd_to_hwirq(d); iosync(); icp_native_set_xirr((xics_pop_cppr() << 24) | hw_irq); diff --git a/arch/powerpc/sysdev/xics/ics-rtas.c b/arch/powerpc/sysdev/xics/ics-rtas.c index 610c148..c782f85 100644 --- a/arch/powerpc/sysdev/xics/ics-rtas.c +++ b/arch/powerpc/sysdev/xics/ics-rtas.c @@ -38,7 +38,7 @@ static struct ics ics_rtas = { static void ics_rtas_unmask_irq(struct irq_data *d) { - unsigned int hw_irq = (unsigned int)irq_data_to_hw(d); + unsigned int hw_irq = (unsigned int)irqd_to_hwirq(d); int call_status; int server; @@ -109,7 +109,7 @@ static void ics_rtas_mask_real_irq(unsigned int hw_irq) static void ics_rtas_mask_irq(struct irq_data *d) { - unsigned int hw_irq = (unsigned int)irq_data_to_hw(d); + unsigned int hw_irq = (unsigned int)irqd_to_hwirq(d); pr_devel("xics: mask virq %d [hw 0x%x]\n", d->irq, hw_irq); @@ -122,7 +122,7 @@ static int ics_rtas_set_affinity(struct irq_data *d, const struct cpumask *cpumask, bool force) { - unsigned int hw_irq = (unsigned int)irq_data_to_hw(d); + unsigned int hw_irq = (unsigned int)irqd_to_hwirq(d); int status; int xics_status[2]; int irq_server; @@ -171,7 +171,7 @@ static struct irq_chip ics_rtas_irq_chip = { static int ics_rtas_map(struct ics *ics, unsigned int virq) { - unsigned int hw_irq = (unsigned int)irq_map[virq].hwirq; + unsigned int hw_irq = (unsigned int)virq_to_hw(virq); int status[2]; int rc; diff --git a/arch/powerpc/sysdev/xics/xics-common.c b/arch/powerpc/sysdev/xics/xics-common.c index c58844d..a0576b7 100644 --- a/arch/powerpc/sysdev/xics/xics-common.c +++ b/arch/powerpc/sysdev/xics/xics-common.c @@ -240,9 +240,9 @@ void xics_migrate_irqs_away(void) /* We can't set affinity on ISA interrupts */ if (virq < NUM_ISA_INTERRUPTS) continue; - if (irq_map[virq].host != xics_host) + if (virq_to_host(virq) != xics_host) continue; - irq = (unsigned int)irq_map[virq].hwirq; + irq = (unsigned int)virq_to_hw(virq); /* We need to get IPIs still. */ if (irq == XICS_IPI || irq == XICS_IRQ_SPURIOUS) continue; diff --git a/arch/powerpc/sysdev/xilinx_intc.c b/arch/powerpc/sysdev/xilinx_intc.c index 0a13fc1..6183799 100644 --- a/arch/powerpc/sysdev/xilinx_intc.c +++ b/arch/powerpc/sysdev/xilinx_intc.c @@ -71,7 +71,7 @@ static unsigned char xilinx_intc_map_senses[] = { */ static void xilinx_intc_mask(struct irq_data *d) { - int irq = virq_to_hw(d->irq); + int irq = irqd_to_hwirq(d); void * regs = irq_data_get_irq_chip_data(d); pr_debug("mask: %d\n", irq); out_be32(regs + XINTC_CIE, 1 << irq); @@ -87,7 +87,7 @@ static int xilinx_intc_set_type(struct irq_data *d, unsigned int flow_type) */ static void xilinx_intc_level_unmask(struct irq_data *d) { - int irq = virq_to_hw(d->irq); + int irq = irqd_to_hwirq(d); void * regs = irq_data_get_irq_chip_data(d); pr_debug("unmask: %d\n", irq); out_be32(regs + XINTC_SIE, 1 << irq); @@ -112,7 +112,7 @@ static struct irq_chip xilinx_intc_level_irqchip = { */ static void xilinx_intc_edge_unmask(struct irq_data *d) { - int irq = virq_to_hw(d->irq); + int irq = irqd_to_hwirq(d); void *regs = irq_data_get_irq_chip_data(d); pr_debug("unmask: %d\n", irq); out_be32(regs + XINTC_SIE, 1 << irq); @@ -120,7 +120,7 @@ static void xilinx_intc_edge_unmask(struct irq_data *d) static void xilinx_intc_edge_ack(struct irq_data *d) { - int irq = virq_to_hw(d->irq); + int irq = irqd_to_hwirq(d); void * regs = irq_data_get_irq_chip_data(d); pr_debug("ack: %d\n", irq); out_be32(regs + XINTC_IAR, 1 << irq); -- cgit v0.10.2 From ba0e14acc417eceb895efda1ff46366f4d1728f8 Mon Sep 17 00:00:00 2001 From: Puneet Saxena Date: Wed, 4 May 2011 15:04:10 +1000 Subject: crypto: testmgr - add support for aes ofb mode the fix add testcase for testing aes ofb mode. Signed-off-by: Puneet Saxena Signed-off-by: Herbert Xu diff --git a/crypto/testmgr.c b/crypto/testmgr.c index 2854865..b6b93d4 100644 --- a/crypto/testmgr.c +++ b/crypto/testmgr.c @@ -2219,6 +2219,22 @@ static const struct alg_test_desc alg_test_descs[] = { } } }, { + .alg = "ofb(aes)", + .test = alg_test_skcipher, + .fips_allowed = 1, + .suite = { + .cipher = { + .enc = { + .vecs = aes_ofb_enc_tv_template, + .count = AES_OFB_ENC_TEST_VECTORS + }, + .dec = { + .vecs = aes_ofb_dec_tv_template, + .count = AES_OFB_DEC_TEST_VECTORS + } + } + } + }, { .alg = "pcbc(fcrypt)", .test = alg_test_skcipher, .suite = { diff --git a/crypto/testmgr.h b/crypto/testmgr.h index aa6dac0..27e6061 100644 --- a/crypto/testmgr.h +++ b/crypto/testmgr.h @@ -2980,6 +2980,8 @@ static struct cipher_testvec cast6_dec_tv_template[] = { #define AES_XTS_DEC_TEST_VECTORS 4 #define AES_CTR_ENC_TEST_VECTORS 3 #define AES_CTR_DEC_TEST_VECTORS 3 +#define AES_OFB_ENC_TEST_VECTORS 1 +#define AES_OFB_DEC_TEST_VECTORS 1 #define AES_CTR_3686_ENC_TEST_VECTORS 7 #define AES_CTR_3686_DEC_TEST_VECTORS 6 #define AES_GCM_ENC_TEST_VECTORS 9 @@ -5506,6 +5508,64 @@ static struct cipher_testvec aes_ctr_rfc3686_dec_tv_template[] = { }, }; +static struct cipher_testvec aes_ofb_enc_tv_template[] = { + /* From NIST Special Publication 800-38A, Appendix F.5 */ + { + .key = "\x2b\x7e\x15\x16\x28\xae\xd2\xa6" + "\xab\xf7\x15\x88\x09\xcf\x4f\x3c", + .klen = 16, + .iv = "\x00\x01\x02\x03\x04\x05\x06\x07\x08" + "\x09\x0a\x0b\x0c\x0d\x0e\x0f", + .input = "\x6b\xc1\xbe\xe2\x2e\x40\x9f\x96" + "\xe9\x3d\x7e\x11\x73\x93\x17\x2a" + "\xae\x2d\x8a\x57\x1e\x03\xac\x9c" + "\x9e\xb7\x6f\xac\x45\xaf\x8e\x51" + "\x30\xc8\x1c\x46\xa3\x5c\xe4\x11" + "\xe5\xfb\xc1\x19\x1a\x0a\x52\xef" + "\xf6\x9f\x24\x45\xdf\x4f\x9b\x17" + "\xad\x2b\x41\x7b\xe6\x6c\x37\x10", + .ilen = 64, + .result = "\x3b\x3f\xd9\x2e\xb7\x2d\xad\x20" + "\x33\x34\x49\xf8\xe8\x3c\xfb\x4a" + "\x77\x89\x50\x8d\x16\x91\x8f\x03\xf5" + "\x3c\x52\xda\xc5\x4e\xd8\x25" + "\x97\x40\x05\x1e\x9c\x5f\xec\xf6\x43" + "\x44\xf7\xa8\x22\x60\xed\xcc" + "\x30\x4c\x65\x28\xf6\x59\xc7\x78" + "\x66\xa5\x10\xd9\xc1\xd6\xae\x5e", + .rlen = 64, + } +}; + +static struct cipher_testvec aes_ofb_dec_tv_template[] = { + /* From NIST Special Publication 800-38A, Appendix F.5 */ + { + .key = "\x2b\x7e\x15\x16\x28\xae\xd2\xa6" + "\xab\xf7\x15\x88\x09\xcf\x4f\x3c", + .klen = 16, + .iv = "\x00\x01\x02\x03\x04\x05\x06\x07\x08" + "\x09\x0a\x0b\x0c\x0d\x0e\x0f", + .input = "\x3b\x3f\xd9\x2e\xb7\x2d\xad\x20" + "\x33\x34\x49\xf8\xe8\x3c\xfb\x4a" + "\x77\x89\x50\x8d\x16\x91\x8f\x03\xf5" + "\x3c\x52\xda\xc5\x4e\xd8\x25" + "\x97\x40\x05\x1e\x9c\x5f\xec\xf6\x43" + "\x44\xf7\xa8\x22\x60\xed\xcc" + "\x30\x4c\x65\x28\xf6\x59\xc7\x78" + "\x66\xa5\x10\xd9\xc1\xd6\xae\x5e", + .ilen = 64, + .result = "\x6b\xc1\xbe\xe2\x2e\x40\x9f\x96" + "\xe9\x3d\x7e\x11\x73\x93\x17\x2a" + "\xae\x2d\x8a\x57\x1e\x03\xac\x9c" + "\x9e\xb7\x6f\xac\x45\xaf\x8e\x51" + "\x30\xc8\x1c\x46\xa3\x5c\xe4\x11" + "\xe5\xfb\xc1\x19\x1a\x0a\x52\xef" + "\xf6\x9f\x24\x45\xdf\x4f\x9b\x17" + "\xad\x2b\x41\x7b\xe6\x6c\x37\x10", + .rlen = 64, + } +}; + static struct aead_testvec aes_gcm_enc_tv_template[] = { { /* From McGrew & Viega - http://citeseer.ist.psu.edu/656989.html */ .key = zeroed_string, -- cgit v0.10.2 From 1822bc9093e05059e4144d6041b0f5450ad275e1 Mon Sep 17 00:00:00 2001 From: Jan Glauber Date: Tue, 19 Apr 2011 21:29:14 +0200 Subject: crypto: s390 - extend crypto facility check The specification which crypto facility is required for an algorithm is added as a parameter to the availability check which is done before an algorithm is registered. With this change it is easier to add new algorithms that require different facilities. Signed-off-by: Jan Glauber Signed-off-by: Herbert Xu diff --git a/arch/s390/crypto/aes_s390.c b/arch/s390/crypto/aes_s390.c index 58f4673..fc97b94 100644 --- a/arch/s390/crypto/aes_s390.c +++ b/arch/s390/crypto/aes_s390.c @@ -508,11 +508,11 @@ static int __init aes_s390_init(void) { int ret; - if (crypt_s390_func_available(KM_AES_128_ENCRYPT)) + if (crypt_s390_func_available(KM_AES_128_ENCRYPT, CRYPT_S390_MSA)) keylen_flag |= AES_KEYLEN_128; - if (crypt_s390_func_available(KM_AES_192_ENCRYPT)) + if (crypt_s390_func_available(KM_AES_192_ENCRYPT, CRYPT_S390_MSA)) keylen_flag |= AES_KEYLEN_192; - if (crypt_s390_func_available(KM_AES_256_ENCRYPT)) + if (crypt_s390_func_available(KM_AES_256_ENCRYPT, CRYPT_S390_MSA)) keylen_flag |= AES_KEYLEN_256; if (!keylen_flag) diff --git a/arch/s390/crypto/crypt_s390.h b/arch/s390/crypto/crypt_s390.h index 7ee9a1b..4b8c96c 100644 --- a/arch/s390/crypto/crypt_s390.h +++ b/arch/s390/crypto/crypt_s390.h @@ -24,6 +24,10 @@ #define CRYPT_S390_PRIORITY 300 #define CRYPT_S390_COMPOSITE_PRIORITY 400 +#define CRYPT_S390_MSA 0x1 +#define CRYPT_S390_MSA3 0x2 +#define CRYPT_S390_MSA4 0x4 + /* s390 cryptographic operations */ enum crypt_s390_operations { CRYPT_S390_KM = 0x0100, @@ -291,13 +295,17 @@ static inline int crypt_s390_kmac(long func, void *param, * * Returns 1 if func available; 0 if func or op in general not available */ -static inline int crypt_s390_func_available(int func) +static inline int crypt_s390_func_available(int func, + unsigned int facility_mask) { unsigned char status[16]; int ret; - /* check if CPACF facility (bit 17) is available */ - if (!test_facility(17)) + if (facility_mask & CRYPT_S390_MSA && !test_facility(17)) + return 0; + if (facility_mask & CRYPT_S390_MSA3 && !test_facility(76)) + return 0; + if (facility_mask & CRYPT_S390_MSA4 && !test_facility(77)) return 0; switch (func & CRYPT_S390_OP_MASK) { diff --git a/arch/s390/crypto/des_s390.c b/arch/s390/crypto/des_s390.c index cc54201..1121e73 100644 --- a/arch/s390/crypto/des_s390.c +++ b/arch/s390/crypto/des_s390.c @@ -381,8 +381,8 @@ static int des_s390_init(void) { int ret; - if (!crypt_s390_func_available(KM_DEA_ENCRYPT) || - !crypt_s390_func_available(KM_TDEA_192_ENCRYPT)) + if (!crypt_s390_func_available(KM_DEA_ENCRYPT, CRYPT_S390_MSA) || + !crypt_s390_func_available(KM_TDEA_192_ENCRYPT, CRYPT_S390_MSA)) return -EOPNOTSUPP; ret = crypto_register_alg(&des_alg); diff --git a/arch/s390/crypto/prng.c b/arch/s390/crypto/prng.c index 975e3ab..0fc8115 100644 --- a/arch/s390/crypto/prng.c +++ b/arch/s390/crypto/prng.c @@ -166,7 +166,7 @@ static int __init prng_init(void) int ret; /* check if the CPU has a PRNG */ - if (!crypt_s390_func_available(KMC_PRNG)) + if (!crypt_s390_func_available(KMC_PRNG, CRYPT_S390_MSA)) return -EOPNOTSUPP; if (prng_chunk_size < 8) diff --git a/arch/s390/crypto/sha1_s390.c b/arch/s390/crypto/sha1_s390.c index f6de782..e9868c6 100644 --- a/arch/s390/crypto/sha1_s390.c +++ b/arch/s390/crypto/sha1_s390.c @@ -90,7 +90,7 @@ static struct shash_alg alg = { static int __init sha1_s390_init(void) { - if (!crypt_s390_func_available(KIMD_SHA_1)) + if (!crypt_s390_func_available(KIMD_SHA_1, CRYPT_S390_MSA)) return -EOPNOTSUPP; return crypto_register_shash(&alg); } diff --git a/arch/s390/crypto/sha256_s390.c b/arch/s390/crypto/sha256_s390.c index 61a7db3..5ed8d64 100644 --- a/arch/s390/crypto/sha256_s390.c +++ b/arch/s390/crypto/sha256_s390.c @@ -86,7 +86,7 @@ static struct shash_alg alg = { static int sha256_s390_init(void) { - if (!crypt_s390_func_available(KIMD_SHA_256)) + if (!crypt_s390_func_available(KIMD_SHA_256, CRYPT_S390_MSA)) return -EOPNOTSUPP; return crypto_register_shash(&alg); diff --git a/arch/s390/crypto/sha512_s390.c b/arch/s390/crypto/sha512_s390.c index 4bf73d0..32a8138 100644 --- a/arch/s390/crypto/sha512_s390.c +++ b/arch/s390/crypto/sha512_s390.c @@ -132,7 +132,7 @@ static int __init init(void) { int ret; - if (!crypt_s390_func_available(KIMD_SHA_512)) + if (!crypt_s390_func_available(KIMD_SHA_512, CRYPT_S390_MSA)) return -EOPNOTSUPP; if ((ret = crypto_register_shash(&sha512_alg)) < 0) goto out; -- cgit v0.10.2 From 98971f8439b1bb9a61682fe24a865ddd25167a6b Mon Sep 17 00:00:00 2001 From: Jan Glauber Date: Tue, 19 Apr 2011 21:29:15 +0200 Subject: crypto: s390 - cleanup DES code Remove a stale file left over from 1efbd15c3bc2b79d33e033e898211109c32159fa and and cleanup the DES code a bit to make it easier to add new code. Signed-off-by: Jan Glauber Signed-off-by: Herbert Xu diff --git a/arch/s390/crypto/des_check_key.c b/arch/s390/crypto/des_check_key.c deleted file mode 100644 index 5706af2..0000000 --- a/arch/s390/crypto/des_check_key.c +++ /dev/null @@ -1,132 +0,0 @@ -/* - * Cryptographic API. - * - * Function for checking keys for the DES and Tripple DES Encryption - * algorithms. - * - * Originally released as descore by Dana L. How . - * Modified by Raimar Falke for the Linux-Kernel. - * Derived from Cryptoapi and Nettle implementations, adapted for in-place - * scatterlist interface. Changed LGPL to GPL per section 3 of the LGPL. - * - * s390 Version: - * Copyright IBM Corp. 2003 - * Author(s): Thomas Spatzier - * Jan Glauber (jan.glauber@de.ibm.com) - * - * Derived from "crypto/des.c" - * Copyright (c) 1992 Dana L. How. - * Copyright (c) Raimar Falke - * Copyright (c) Gisle Sflensminde - * Copyright (C) 2001 Niels Mvller. - * Copyright (c) 2002 James Morris - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - */ -#include -#include -#include -#include -#include "crypto_des.h" - -#define ROR(d,c,o) ((d) = (d) >> (c) | (d) << (o)) - -static const u8 parity[] = { - 8,1,0,8,0,8,8,0,0,8,8,0,8,0,2,8,0,8,8,0,8,0,0,8,8,0,0,8,0,8,8,3, - 0,8,8,0,8,0,0,8,8,0,0,8,0,8,8,0,8,0,0,8,0,8,8,0,0,8,8,0,8,0,0,8, - 0,8,8,0,8,0,0,8,8,0,0,8,0,8,8,0,8,0,0,8,0,8,8,0,0,8,8,0,8,0,0,8, - 8,0,0,8,0,8,8,0,0,8,8,0,8,0,0,8,0,8,8,0,8,0,0,8,8,0,0,8,0,8,8,0, - 0,8,8,0,8,0,0,8,8,0,0,8,0,8,8,0,8,0,0,8,0,8,8,0,0,8,8,0,8,0,0,8, - 8,0,0,8,0,8,8,0,0,8,8,0,8,0,0,8,0,8,8,0,8,0,0,8,8,0,0,8,0,8,8,0, - 8,0,0,8,0,8,8,0,0,8,8,0,8,0,0,8,0,8,8,0,8,0,0,8,8,0,0,8,0,8,8,0, - 4,8,8,0,8,0,0,8,8,0,0,8,0,8,8,0,8,5,0,8,0,8,8,0,0,8,8,0,8,0,6,8, -}; - -/* - * RFC2451: Weak key checks SHOULD be performed. - */ -int -crypto_des_check_key(const u8 *key, unsigned int keylen, u32 *flags) -{ - u32 n, w; - - n = parity[key[0]]; n <<= 4; - n |= parity[key[1]]; n <<= 4; - n |= parity[key[2]]; n <<= 4; - n |= parity[key[3]]; n <<= 4; - n |= parity[key[4]]; n <<= 4; - n |= parity[key[5]]; n <<= 4; - n |= parity[key[6]]; n <<= 4; - n |= parity[key[7]]; - w = 0x88888888L; - - if ((*flags & CRYPTO_TFM_REQ_WEAK_KEY) - && !((n - (w >> 3)) & w)) { /* 1 in 10^10 keys passes this test */ - if (n < 0x41415151) { - if (n < 0x31312121) { - if (n < 0x14141515) { - /* 01 01 01 01 01 01 01 01 */ - if (n == 0x11111111) goto weak; - /* 01 1F 01 1F 01 0E 01 0E */ - if (n == 0x13131212) goto weak; - } else { - /* 01 E0 01 E0 01 F1 01 F1 */ - if (n == 0x14141515) goto weak; - /* 01 FE 01 FE 01 FE 01 FE */ - if (n == 0x16161616) goto weak; - } - } else { - if (n < 0x34342525) { - /* 1F 01 1F 01 0E 01 0E 01 */ - if (n == 0x31312121) goto weak; - /* 1F 1F 1F 1F 0E 0E 0E 0E (?) */ - if (n == 0x33332222) goto weak; - } else { - /* 1F E0 1F E0 0E F1 0E F1 */ - if (n == 0x34342525) goto weak; - /* 1F FE 1F FE 0E FE 0E FE */ - if (n == 0x36362626) goto weak; - } - } - } else { - if (n < 0x61616161) { - if (n < 0x44445555) { - /* E0 01 E0 01 F1 01 F1 01 */ - if (n == 0x41415151) goto weak; - /* E0 1F E0 1F F1 0E F1 0E */ - if (n == 0x43435252) goto weak; - } else { - /* E0 E0 E0 E0 F1 F1 F1 F1 (?) */ - if (n == 0x44445555) goto weak; - /* E0 FE E0 FE F1 FE F1 FE */ - if (n == 0x46465656) goto weak; - } - } else { - if (n < 0x64646565) { - /* FE 01 FE 01 FE 01 FE 01 */ - if (n == 0x61616161) goto weak; - /* FE 1F FE 1F FE 0E FE 0E */ - if (n == 0x63636262) goto weak; - } else { - /* FE E0 FE E0 FE F1 FE F1 */ - if (n == 0x64646565) goto weak; - /* FE FE FE FE FE FE FE FE */ - if (n == 0x66666666) goto weak; - } - } - } - } - return 0; -weak: - *flags |= CRYPTO_TFM_RES_WEAK_KEY; - return -EINVAL; -} - -EXPORT_SYMBOL(crypto_des_check_key); - -MODULE_LICENSE("GPL"); -MODULE_DESCRIPTION("Key Check function for DES & DES3 Cipher Algorithms"); diff --git a/arch/s390/crypto/des_s390.c b/arch/s390/crypto/des_s390.c index 1121e73..c36a01d 100644 --- a/arch/s390/crypto/des_s390.c +++ b/arch/s390/crypto/des_s390.c @@ -22,22 +22,17 @@ #include "crypt_s390.h" -#define DES3_192_KEY_SIZE (3 * DES_KEY_SIZE) +#define DES3_KEY_SIZE (3 * DES_KEY_SIZE) -struct crypt_s390_des_ctx { +struct s390_des_ctx { u8 iv[DES_BLOCK_SIZE]; - u8 key[DES_KEY_SIZE]; -}; - -struct crypt_s390_des3_192_ctx { - u8 iv[DES_BLOCK_SIZE]; - u8 key[DES3_192_KEY_SIZE]; + u8 key[DES3_KEY_SIZE]; }; static int des_setkey(struct crypto_tfm *tfm, const u8 *key, - unsigned int keylen) + unsigned int key_len) { - struct crypt_s390_des_ctx *dctx = crypto_tfm_ctx(tfm); + struct s390_des_ctx *ctx = crypto_tfm_ctx(tfm); u32 *flags = &tfm->crt_flags; u32 tmp[DES_EXPKEY_WORDS]; @@ -47,22 +42,22 @@ static int des_setkey(struct crypto_tfm *tfm, const u8 *key, return -EINVAL; } - memcpy(dctx->key, key, keylen); + memcpy(ctx->key, key, key_len); return 0; } static void des_encrypt(struct crypto_tfm *tfm, u8 *out, const u8 *in) { - struct crypt_s390_des_ctx *dctx = crypto_tfm_ctx(tfm); + struct s390_des_ctx *ctx = crypto_tfm_ctx(tfm); - crypt_s390_km(KM_DEA_ENCRYPT, dctx->key, out, in, DES_BLOCK_SIZE); + crypt_s390_km(KM_DEA_ENCRYPT, ctx->key, out, in, DES_BLOCK_SIZE); } static void des_decrypt(struct crypto_tfm *tfm, u8 *out, const u8 *in) { - struct crypt_s390_des_ctx *dctx = crypto_tfm_ctx(tfm); + struct s390_des_ctx *ctx = crypto_tfm_ctx(tfm); - crypt_s390_km(KM_DEA_DECRYPT, dctx->key, out, in, DES_BLOCK_SIZE); + crypt_s390_km(KM_DEA_DECRYPT, ctx->key, out, in, DES_BLOCK_SIZE); } static struct crypto_alg des_alg = { @@ -71,7 +66,7 @@ static struct crypto_alg des_alg = { .cra_priority = CRYPT_S390_PRIORITY, .cra_flags = CRYPTO_ALG_TYPE_CIPHER, .cra_blocksize = DES_BLOCK_SIZE, - .cra_ctxsize = sizeof(struct crypt_s390_des_ctx), + .cra_ctxsize = sizeof(struct s390_des_ctx), .cra_module = THIS_MODULE, .cra_list = LIST_HEAD_INIT(des_alg.cra_list), .cra_u = { @@ -86,7 +81,7 @@ static struct crypto_alg des_alg = { }; static int ecb_desall_crypt(struct blkcipher_desc *desc, long func, - void *param, struct blkcipher_walk *walk) + u8 *key, struct blkcipher_walk *walk) { int ret = blkcipher_walk_virt(desc, walk); unsigned int nbytes; @@ -97,7 +92,7 @@ static int ecb_desall_crypt(struct blkcipher_desc *desc, long func, u8 *out = walk->dst.virt.addr; u8 *in = walk->src.virt.addr; - ret = crypt_s390_km(func, param, out, in, n); + ret = crypt_s390_km(func, key, out, in, n); BUG_ON((ret < 0) || (ret != n)); nbytes &= DES_BLOCK_SIZE - 1; @@ -108,7 +103,7 @@ static int ecb_desall_crypt(struct blkcipher_desc *desc, long func, } static int cbc_desall_crypt(struct blkcipher_desc *desc, long func, - void *param, struct blkcipher_walk *walk) + u8 *iv, struct blkcipher_walk *walk) { int ret = blkcipher_walk_virt(desc, walk); unsigned int nbytes = walk->nbytes; @@ -116,20 +111,20 @@ static int cbc_desall_crypt(struct blkcipher_desc *desc, long func, if (!nbytes) goto out; - memcpy(param, walk->iv, DES_BLOCK_SIZE); + memcpy(iv, walk->iv, DES_BLOCK_SIZE); do { /* only use complete blocks */ unsigned int n = nbytes & ~(DES_BLOCK_SIZE - 1); u8 *out = walk->dst.virt.addr; u8 *in = walk->src.virt.addr; - ret = crypt_s390_kmc(func, param, out, in, n); + ret = crypt_s390_kmc(func, iv, out, in, n); BUG_ON((ret < 0) || (ret != n)); nbytes &= DES_BLOCK_SIZE - 1; ret = blkcipher_walk_done(desc, walk, nbytes); } while ((nbytes = walk->nbytes)); - memcpy(walk->iv, param, DES_BLOCK_SIZE); + memcpy(walk->iv, iv, DES_BLOCK_SIZE); out: return ret; @@ -139,22 +134,22 @@ static int ecb_des_encrypt(struct blkcipher_desc *desc, struct scatterlist *dst, struct scatterlist *src, unsigned int nbytes) { - struct crypt_s390_des_ctx *sctx = crypto_blkcipher_ctx(desc->tfm); + struct s390_des_ctx *ctx = crypto_blkcipher_ctx(desc->tfm); struct blkcipher_walk walk; blkcipher_walk_init(&walk, dst, src, nbytes); - return ecb_desall_crypt(desc, KM_DEA_ENCRYPT, sctx->key, &walk); + return ecb_desall_crypt(desc, KM_DEA_ENCRYPT, ctx->key, &walk); } static int ecb_des_decrypt(struct blkcipher_desc *desc, struct scatterlist *dst, struct scatterlist *src, unsigned int nbytes) { - struct crypt_s390_des_ctx *sctx = crypto_blkcipher_ctx(desc->tfm); + struct s390_des_ctx *ctx = crypto_blkcipher_ctx(desc->tfm); struct blkcipher_walk walk; blkcipher_walk_init(&walk, dst, src, nbytes); - return ecb_desall_crypt(desc, KM_DEA_DECRYPT, sctx->key, &walk); + return ecb_desall_crypt(desc, KM_DEA_DECRYPT, ctx->key, &walk); } static struct crypto_alg ecb_des_alg = { @@ -163,7 +158,7 @@ static struct crypto_alg ecb_des_alg = { .cra_priority = CRYPT_S390_COMPOSITE_PRIORITY, .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER, .cra_blocksize = DES_BLOCK_SIZE, - .cra_ctxsize = sizeof(struct crypt_s390_des_ctx), + .cra_ctxsize = sizeof(struct s390_des_ctx), .cra_type = &crypto_blkcipher_type, .cra_module = THIS_MODULE, .cra_list = LIST_HEAD_INIT(ecb_des_alg.cra_list), @@ -182,22 +177,22 @@ static int cbc_des_encrypt(struct blkcipher_desc *desc, struct scatterlist *dst, struct scatterlist *src, unsigned int nbytes) { - struct crypt_s390_des_ctx *sctx = crypto_blkcipher_ctx(desc->tfm); + struct s390_des_ctx *ctx = crypto_blkcipher_ctx(desc->tfm); struct blkcipher_walk walk; blkcipher_walk_init(&walk, dst, src, nbytes); - return cbc_desall_crypt(desc, KMC_DEA_ENCRYPT, sctx->iv, &walk); + return cbc_desall_crypt(desc, KMC_DEA_ENCRYPT, ctx->iv, &walk); } static int cbc_des_decrypt(struct blkcipher_desc *desc, struct scatterlist *dst, struct scatterlist *src, unsigned int nbytes) { - struct crypt_s390_des_ctx *sctx = crypto_blkcipher_ctx(desc->tfm); + struct s390_des_ctx *ctx = crypto_blkcipher_ctx(desc->tfm); struct blkcipher_walk walk; blkcipher_walk_init(&walk, dst, src, nbytes); - return cbc_desall_crypt(desc, KMC_DEA_DECRYPT, sctx->iv, &walk); + return cbc_desall_crypt(desc, KMC_DEA_DECRYPT, ctx->iv, &walk); } static struct crypto_alg cbc_des_alg = { @@ -206,7 +201,7 @@ static struct crypto_alg cbc_des_alg = { .cra_priority = CRYPT_S390_COMPOSITE_PRIORITY, .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER, .cra_blocksize = DES_BLOCK_SIZE, - .cra_ctxsize = sizeof(struct crypt_s390_des_ctx), + .cra_ctxsize = sizeof(struct s390_des_ctx), .cra_type = &crypto_blkcipher_type, .cra_module = THIS_MODULE, .cra_list = LIST_HEAD_INIT(cbc_des_alg.cra_list), @@ -235,10 +230,10 @@ static struct crypto_alg cbc_des_alg = { * property. * */ -static int des3_192_setkey(struct crypto_tfm *tfm, const u8 *key, - unsigned int keylen) +static int des3_setkey(struct crypto_tfm *tfm, const u8 *key, + unsigned int key_len) { - struct crypt_s390_des3_192_ctx *dctx = crypto_tfm_ctx(tfm); + struct s390_des_ctx *ctx = crypto_tfm_ctx(tfm); u32 *flags = &tfm->crt_flags; if (!(memcmp(key, &key[DES_KEY_SIZE], DES_KEY_SIZE) && @@ -248,136 +243,134 @@ static int des3_192_setkey(struct crypto_tfm *tfm, const u8 *key, *flags |= CRYPTO_TFM_RES_WEAK_KEY; return -EINVAL; } - memcpy(dctx->key, key, keylen); + memcpy(ctx->key, key, key_len); return 0; } -static void des3_192_encrypt(struct crypto_tfm *tfm, u8 *dst, const u8 *src) +static void des3_encrypt(struct crypto_tfm *tfm, u8 *dst, const u8 *src) { - struct crypt_s390_des3_192_ctx *dctx = crypto_tfm_ctx(tfm); + struct s390_des_ctx *ctx = crypto_tfm_ctx(tfm); - crypt_s390_km(KM_TDEA_192_ENCRYPT, dctx->key, dst, (void*)src, - DES_BLOCK_SIZE); + crypt_s390_km(KM_TDEA_192_ENCRYPT, ctx->key, dst, src, DES_BLOCK_SIZE); } -static void des3_192_decrypt(struct crypto_tfm *tfm, u8 *dst, const u8 *src) +static void des3_decrypt(struct crypto_tfm *tfm, u8 *dst, const u8 *src) { - struct crypt_s390_des3_192_ctx *dctx = crypto_tfm_ctx(tfm); + struct s390_des_ctx *ctx = crypto_tfm_ctx(tfm); - crypt_s390_km(KM_TDEA_192_DECRYPT, dctx->key, dst, (void*)src, - DES_BLOCK_SIZE); + crypt_s390_km(KM_TDEA_192_DECRYPT, ctx->key, dst, src, DES_BLOCK_SIZE); } -static struct crypto_alg des3_192_alg = { +static struct crypto_alg des3_alg = { .cra_name = "des3_ede", .cra_driver_name = "des3_ede-s390", .cra_priority = CRYPT_S390_PRIORITY, .cra_flags = CRYPTO_ALG_TYPE_CIPHER, .cra_blocksize = DES_BLOCK_SIZE, - .cra_ctxsize = sizeof(struct crypt_s390_des3_192_ctx), + .cra_ctxsize = sizeof(struct s390_des_ctx), .cra_module = THIS_MODULE, - .cra_list = LIST_HEAD_INIT(des3_192_alg.cra_list), + .cra_list = LIST_HEAD_INIT(des3_alg.cra_list), .cra_u = { .cipher = { - .cia_min_keysize = DES3_192_KEY_SIZE, - .cia_max_keysize = DES3_192_KEY_SIZE, - .cia_setkey = des3_192_setkey, - .cia_encrypt = des3_192_encrypt, - .cia_decrypt = des3_192_decrypt, + .cia_min_keysize = DES3_KEY_SIZE, + .cia_max_keysize = DES3_KEY_SIZE, + .cia_setkey = des3_setkey, + .cia_encrypt = des3_encrypt, + .cia_decrypt = des3_decrypt, } } }; -static int ecb_des3_192_encrypt(struct blkcipher_desc *desc, - struct scatterlist *dst, - struct scatterlist *src, unsigned int nbytes) +static int ecb_des3_encrypt(struct blkcipher_desc *desc, + struct scatterlist *dst, struct scatterlist *src, + unsigned int nbytes) { - struct crypt_s390_des3_192_ctx *sctx = crypto_blkcipher_ctx(desc->tfm); + struct s390_des_ctx *ctx = crypto_blkcipher_ctx(desc->tfm); struct blkcipher_walk walk; blkcipher_walk_init(&walk, dst, src, nbytes); - return ecb_desall_crypt(desc, KM_TDEA_192_ENCRYPT, sctx->key, &walk); + return ecb_desall_crypt(desc, KM_TDEA_192_ENCRYPT, ctx->key, &walk); } -static int ecb_des3_192_decrypt(struct blkcipher_desc *desc, - struct scatterlist *dst, - struct scatterlist *src, unsigned int nbytes) +static int ecb_des3_decrypt(struct blkcipher_desc *desc, + struct scatterlist *dst, struct scatterlist *src, + unsigned int nbytes) { - struct crypt_s390_des3_192_ctx *sctx = crypto_blkcipher_ctx(desc->tfm); + struct s390_des_ctx *ctx = crypto_blkcipher_ctx(desc->tfm); struct blkcipher_walk walk; blkcipher_walk_init(&walk, dst, src, nbytes); - return ecb_desall_crypt(desc, KM_TDEA_192_DECRYPT, sctx->key, &walk); + return ecb_desall_crypt(desc, KM_TDEA_192_DECRYPT, ctx->key, &walk); } -static struct crypto_alg ecb_des3_192_alg = { +static struct crypto_alg ecb_des3_alg = { .cra_name = "ecb(des3_ede)", .cra_driver_name = "ecb-des3_ede-s390", .cra_priority = CRYPT_S390_COMPOSITE_PRIORITY, .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER, .cra_blocksize = DES_BLOCK_SIZE, - .cra_ctxsize = sizeof(struct crypt_s390_des3_192_ctx), + .cra_ctxsize = sizeof(struct s390_des_ctx), .cra_type = &crypto_blkcipher_type, .cra_module = THIS_MODULE, .cra_list = LIST_HEAD_INIT( - ecb_des3_192_alg.cra_list), + ecb_des3_alg.cra_list), .cra_u = { .blkcipher = { - .min_keysize = DES3_192_KEY_SIZE, - .max_keysize = DES3_192_KEY_SIZE, - .setkey = des3_192_setkey, - .encrypt = ecb_des3_192_encrypt, - .decrypt = ecb_des3_192_decrypt, + .min_keysize = DES3_KEY_SIZE, + .max_keysize = DES3_KEY_SIZE, + .setkey = des3_setkey, + .encrypt = ecb_des3_encrypt, + .decrypt = ecb_des3_decrypt, } } }; -static int cbc_des3_192_encrypt(struct blkcipher_desc *desc, - struct scatterlist *dst, - struct scatterlist *src, unsigned int nbytes) +static int cbc_des3_encrypt(struct blkcipher_desc *desc, + struct scatterlist *dst, struct scatterlist *src, + unsigned int nbytes) { - struct crypt_s390_des3_192_ctx *sctx = crypto_blkcipher_ctx(desc->tfm); + struct s390_des_ctx *ctx = crypto_blkcipher_ctx(desc->tfm); struct blkcipher_walk walk; blkcipher_walk_init(&walk, dst, src, nbytes); - return cbc_desall_crypt(desc, KMC_TDEA_192_ENCRYPT, sctx->iv, &walk); + return cbc_desall_crypt(desc, KMC_TDEA_192_ENCRYPT, ctx->iv, &walk); } -static int cbc_des3_192_decrypt(struct blkcipher_desc *desc, - struct scatterlist *dst, - struct scatterlist *src, unsigned int nbytes) +static int cbc_des3_decrypt(struct blkcipher_desc *desc, + struct scatterlist *dst, struct scatterlist *src, + unsigned int nbytes) { - struct crypt_s390_des3_192_ctx *sctx = crypto_blkcipher_ctx(desc->tfm); + struct s390_des_ctx *ctx = crypto_blkcipher_ctx(desc->tfm); struct blkcipher_walk walk; blkcipher_walk_init(&walk, dst, src, nbytes); - return cbc_desall_crypt(desc, KMC_TDEA_192_DECRYPT, sctx->iv, &walk); + return cbc_desall_crypt(desc, KMC_TDEA_192_DECRYPT, ctx->iv, &walk); } -static struct crypto_alg cbc_des3_192_alg = { +static struct crypto_alg cbc_des3_alg = { .cra_name = "cbc(des3_ede)", .cra_driver_name = "cbc-des3_ede-s390", .cra_priority = CRYPT_S390_COMPOSITE_PRIORITY, .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER, .cra_blocksize = DES_BLOCK_SIZE, - .cra_ctxsize = sizeof(struct crypt_s390_des3_192_ctx), + .cra_ctxsize = sizeof(struct s390_des_ctx), .cra_type = &crypto_blkcipher_type, .cra_module = THIS_MODULE, .cra_list = LIST_HEAD_INIT( - cbc_des3_192_alg.cra_list), + cbc_des3_alg.cra_list), .cra_u = { .blkcipher = { - .min_keysize = DES3_192_KEY_SIZE, - .max_keysize = DES3_192_KEY_SIZE, + .min_keysize = DES3_KEY_SIZE, + .max_keysize = DES3_KEY_SIZE, .ivsize = DES_BLOCK_SIZE, - .setkey = des3_192_setkey, - .encrypt = cbc_des3_192_encrypt, - .decrypt = cbc_des3_192_decrypt, + .setkey = des3_setkey, + .encrypt = cbc_des3_encrypt, + .decrypt = cbc_des3_decrypt, } } }; -static int des_s390_init(void) +static int __init des_s390_init(void) { int ret; @@ -394,23 +387,23 @@ static int des_s390_init(void) ret = crypto_register_alg(&cbc_des_alg); if (ret) goto cbc_des_err; - ret = crypto_register_alg(&des3_192_alg); + ret = crypto_register_alg(&des3_alg); if (ret) - goto des3_192_err; - ret = crypto_register_alg(&ecb_des3_192_alg); + goto des3_err; + ret = crypto_register_alg(&ecb_des3_alg); if (ret) - goto ecb_des3_192_err; - ret = crypto_register_alg(&cbc_des3_192_alg); + goto ecb_des3_err; + ret = crypto_register_alg(&cbc_des3_alg); if (ret) - goto cbc_des3_192_err; + goto cbc_des3_err; out: return ret; -cbc_des3_192_err: - crypto_unregister_alg(&ecb_des3_192_alg); -ecb_des3_192_err: - crypto_unregister_alg(&des3_192_alg); -des3_192_err: +cbc_des3_err: + crypto_unregister_alg(&ecb_des3_alg); +ecb_des3_err: + crypto_unregister_alg(&des3_alg); +des3_err: crypto_unregister_alg(&cbc_des_alg); cbc_des_err: crypto_unregister_alg(&ecb_des_alg); @@ -422,9 +415,9 @@ des_err: static void __exit des_s390_exit(void) { - crypto_unregister_alg(&cbc_des3_192_alg); - crypto_unregister_alg(&ecb_des3_192_alg); - crypto_unregister_alg(&des3_192_alg); + crypto_unregister_alg(&cbc_des3_alg); + crypto_unregister_alg(&ecb_des3_alg); + crypto_unregister_alg(&des3_alg); crypto_unregister_alg(&cbc_des_alg); crypto_unregister_alg(&ecb_des_alg); crypto_unregister_alg(&des_alg); -- cgit v0.10.2 From 99d97222150a24e6096805530e141af94183b9a1 Mon Sep 17 00:00:00 2001 From: Gerald Schaefer Date: Tue, 26 Apr 2011 16:12:42 +1000 Subject: crypto: s390 - add System z hardware support for XTS mode This patch adds System z hardware acceleration support for the AES XTS mode. The hardware support is available beginning with System z196. Signed-off-by: Jan Glauber Signed-off-by: Gerald Schaefer Signed-off-by: Herbert Xu diff --git a/arch/s390/crypto/aes_s390.c b/arch/s390/crypto/aes_s390.c index fc97b94..8230e86 100644 --- a/arch/s390/crypto/aes_s390.c +++ b/arch/s390/crypto/aes_s390.c @@ -45,6 +45,24 @@ struct s390_aes_ctx { } fallback; }; +struct pcc_param { + u8 key[32]; + u8 tweak[16]; + u8 block[16]; + u8 bit[16]; + u8 xts[16]; +}; + +struct s390_xts_ctx { + u8 key[32]; + u8 xts_param[16]; + struct pcc_param pcc; + long enc; + long dec; + int key_len; + struct crypto_blkcipher *fallback; +}; + /* * Check if the key_len is supported by the HW. * Returns 0 if it is, a positive number if it is not and software fallback is @@ -504,8 +522,211 @@ static struct crypto_alg cbc_aes_alg = { } }; +static int xts_fallback_setkey(struct crypto_tfm *tfm, const u8 *key, + unsigned int len) +{ + struct s390_xts_ctx *xts_ctx = crypto_tfm_ctx(tfm); + unsigned int ret; + + xts_ctx->fallback->base.crt_flags &= ~CRYPTO_TFM_REQ_MASK; + xts_ctx->fallback->base.crt_flags |= (tfm->crt_flags & + CRYPTO_TFM_REQ_MASK); + + ret = crypto_blkcipher_setkey(xts_ctx->fallback, key, len); + if (ret) { + tfm->crt_flags &= ~CRYPTO_TFM_RES_MASK; + tfm->crt_flags |= (xts_ctx->fallback->base.crt_flags & + CRYPTO_TFM_RES_MASK); + } + return ret; +} + +static int xts_fallback_decrypt(struct blkcipher_desc *desc, + struct scatterlist *dst, struct scatterlist *src, + unsigned int nbytes) +{ + struct s390_xts_ctx *xts_ctx = crypto_blkcipher_ctx(desc->tfm); + struct crypto_blkcipher *tfm; + unsigned int ret; + + tfm = desc->tfm; + desc->tfm = xts_ctx->fallback; + + ret = crypto_blkcipher_decrypt_iv(desc, dst, src, nbytes); + + desc->tfm = tfm; + return ret; +} + +static int xts_fallback_encrypt(struct blkcipher_desc *desc, + struct scatterlist *dst, struct scatterlist *src, + unsigned int nbytes) +{ + struct s390_xts_ctx *xts_ctx = crypto_blkcipher_ctx(desc->tfm); + struct crypto_blkcipher *tfm; + unsigned int ret; + + tfm = desc->tfm; + desc->tfm = xts_ctx->fallback; + + ret = crypto_blkcipher_encrypt_iv(desc, dst, src, nbytes); + + desc->tfm = tfm; + return ret; +} + +static int xts_aes_set_key(struct crypto_tfm *tfm, const u8 *in_key, + unsigned int key_len) +{ + struct s390_xts_ctx *xts_ctx = crypto_tfm_ctx(tfm); + u32 *flags = &tfm->crt_flags; + + switch (key_len) { + case 32: + xts_ctx->enc = KM_XTS_128_ENCRYPT; + xts_ctx->dec = KM_XTS_128_DECRYPT; + memcpy(xts_ctx->key + 16, in_key, 16); + memcpy(xts_ctx->pcc.key + 16, in_key + 16, 16); + break; + case 48: + xts_ctx->enc = 0; + xts_ctx->dec = 0; + xts_fallback_setkey(tfm, in_key, key_len); + break; + case 64: + xts_ctx->enc = KM_XTS_256_ENCRYPT; + xts_ctx->dec = KM_XTS_256_DECRYPT; + memcpy(xts_ctx->key, in_key, 32); + memcpy(xts_ctx->pcc.key, in_key + 32, 32); + break; + default: + *flags |= CRYPTO_TFM_RES_BAD_KEY_LEN; + return -EINVAL; + } + xts_ctx->key_len = key_len; + return 0; +} + +static int xts_aes_crypt(struct blkcipher_desc *desc, long func, + struct s390_xts_ctx *xts_ctx, + struct blkcipher_walk *walk) +{ + unsigned int offset = (xts_ctx->key_len >> 1) & 0x10; + int ret = blkcipher_walk_virt(desc, walk); + unsigned int nbytes = walk->nbytes; + unsigned int n; + u8 *in, *out; + void *param; + + if (!nbytes) + goto out; + + memset(xts_ctx->pcc.block, 0, sizeof(xts_ctx->pcc.block)); + memset(xts_ctx->pcc.bit, 0, sizeof(xts_ctx->pcc.bit)); + memset(xts_ctx->pcc.xts, 0, sizeof(xts_ctx->pcc.xts)); + memcpy(xts_ctx->pcc.tweak, walk->iv, sizeof(xts_ctx->pcc.tweak)); + param = xts_ctx->pcc.key + offset; + ret = crypt_s390_pcc(func, param); + BUG_ON(ret < 0); + + memcpy(xts_ctx->xts_param, xts_ctx->pcc.xts, 16); + param = xts_ctx->key + offset; + do { + /* only use complete blocks */ + n = nbytes & ~(AES_BLOCK_SIZE - 1); + out = walk->dst.virt.addr; + in = walk->src.virt.addr; + + ret = crypt_s390_km(func, param, out, in, n); + BUG_ON(ret < 0 || ret != n); + + nbytes &= AES_BLOCK_SIZE - 1; + ret = blkcipher_walk_done(desc, walk, nbytes); + } while ((nbytes = walk->nbytes)); +out: + return ret; +} + +static int xts_aes_encrypt(struct blkcipher_desc *desc, + struct scatterlist *dst, struct scatterlist *src, + unsigned int nbytes) +{ + struct s390_xts_ctx *xts_ctx = crypto_blkcipher_ctx(desc->tfm); + struct blkcipher_walk walk; + + if (unlikely(xts_ctx->key_len == 48)) + return xts_fallback_encrypt(desc, dst, src, nbytes); + + blkcipher_walk_init(&walk, dst, src, nbytes); + return xts_aes_crypt(desc, xts_ctx->enc, xts_ctx, &walk); +} + +static int xts_aes_decrypt(struct blkcipher_desc *desc, + struct scatterlist *dst, struct scatterlist *src, + unsigned int nbytes) +{ + struct s390_xts_ctx *xts_ctx = crypto_blkcipher_ctx(desc->tfm); + struct blkcipher_walk walk; + + if (unlikely(xts_ctx->key_len == 48)) + return xts_fallback_decrypt(desc, dst, src, nbytes); + + blkcipher_walk_init(&walk, dst, src, nbytes); + return xts_aes_crypt(desc, xts_ctx->dec, xts_ctx, &walk); +} + +static int xts_fallback_init(struct crypto_tfm *tfm) +{ + const char *name = tfm->__crt_alg->cra_name; + struct s390_xts_ctx *xts_ctx = crypto_tfm_ctx(tfm); + + xts_ctx->fallback = crypto_alloc_blkcipher(name, 0, + CRYPTO_ALG_ASYNC | CRYPTO_ALG_NEED_FALLBACK); + + if (IS_ERR(xts_ctx->fallback)) { + pr_err("Allocating XTS fallback algorithm %s failed\n", + name); + return PTR_ERR(xts_ctx->fallback); + } + return 0; +} + +static void xts_fallback_exit(struct crypto_tfm *tfm) +{ + struct s390_xts_ctx *xts_ctx = crypto_tfm_ctx(tfm); + + crypto_free_blkcipher(xts_ctx->fallback); + xts_ctx->fallback = NULL; +} + +static struct crypto_alg xts_aes_alg = { + .cra_name = "xts(aes)", + .cra_driver_name = "xts-aes-s390", + .cra_priority = CRYPT_S390_COMPOSITE_PRIORITY, + .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER | + CRYPTO_ALG_NEED_FALLBACK, + .cra_blocksize = AES_BLOCK_SIZE, + .cra_ctxsize = sizeof(struct s390_xts_ctx), + .cra_type = &crypto_blkcipher_type, + .cra_module = THIS_MODULE, + .cra_list = LIST_HEAD_INIT(xts_aes_alg.cra_list), + .cra_init = xts_fallback_init, + .cra_exit = xts_fallback_exit, + .cra_u = { + .blkcipher = { + .min_keysize = 2 * AES_MIN_KEY_SIZE, + .max_keysize = 2 * AES_MAX_KEY_SIZE, + .ivsize = AES_BLOCK_SIZE, + .setkey = xts_aes_set_key, + .encrypt = xts_aes_encrypt, + .decrypt = xts_aes_decrypt, + } + } +}; + static int __init aes_s390_init(void) { + unsigned long long facility_bits[2]; int ret; if (crypt_s390_func_available(KM_AES_128_ENCRYPT, CRYPT_S390_MSA)) @@ -535,9 +756,20 @@ static int __init aes_s390_init(void) if (ret) goto cbc_aes_err; + if (crypt_s390_func_available(KM_XTS_128_ENCRYPT, + CRYPT_S390_MSA | CRYPT_S390_MSA4) && + crypt_s390_func_available(KM_XTS_256_ENCRYPT, + CRYPT_S390_MSA | CRYPT_S390_MSA4)) { + ret = crypto_register_alg(&xts_aes_alg); + if (ret) + goto xts_aes_err; + } + out: return ret; +xts_aes_err: + crypto_unregister_alg(&cbc_aes_alg); cbc_aes_err: crypto_unregister_alg(&ecb_aes_alg); ecb_aes_err: @@ -548,6 +780,7 @@ aes_err: static void __exit aes_s390_fini(void) { + crypto_unregister_alg(&xts_aes_alg); crypto_unregister_alg(&cbc_aes_alg); crypto_unregister_alg(&ecb_aes_alg); crypto_unregister_alg(&aes_alg); diff --git a/arch/s390/crypto/crypt_s390.h b/arch/s390/crypto/crypt_s390.h index 4b8c96c..7cbfaf0 100644 --- a/arch/s390/crypto/crypt_s390.h +++ b/arch/s390/crypto/crypt_s390.h @@ -55,6 +55,10 @@ enum crypt_s390_km_func { KM_AES_192_DECRYPT = CRYPT_S390_KM | 0x13 | 0x80, KM_AES_256_ENCRYPT = CRYPT_S390_KM | 0x14, KM_AES_256_DECRYPT = CRYPT_S390_KM | 0x14 | 0x80, + KM_XTS_128_ENCRYPT = CRYPT_S390_KM | 0x32, + KM_XTS_128_DECRYPT = CRYPT_S390_KM | 0x32 | 0x80, + KM_XTS_256_ENCRYPT = CRYPT_S390_KM | 0x34, + KM_XTS_256_DECRYPT = CRYPT_S390_KM | 0x34 | 0x80, }; /* @@ -334,4 +338,31 @@ static inline int crypt_s390_func_available(int func, return (status[func >> 3] & (0x80 >> (func & 7))) != 0; } +/** + * crypt_s390_pcc: + * @func: the function code passed to KM; see crypt_s390_km_func + * @param: address of parameter block; see POP for details on each func + * + * Executes the PCC (PERFORM CRYPTOGRAPHIC COMPUTATION) operation of the CPU. + * + * Returns -1 for failure, 0 for success. + */ +static inline int crypt_s390_pcc(long func, void *param) +{ + register long __func asm("0") = func & 0x7f; /* encrypt or decrypt */ + register void *__param asm("1") = param; + int ret = -1; + + asm volatile( + "0: .insn rre,0xb92c0000,0,0 \n" /* PCC opcode */ + "1: brc 1,0b \n" /* handle partial completion */ + " la %0,0\n" + "2:\n" + EX_TABLE(0b,2b) EX_TABLE(1b,2b) + : "+d" (ret) + : "d" (__func), "a" (__param) : "cc", "memory"); + return ret; +} + + #endif /* _CRYPTO_ARCH_S390_CRYPT_S390_H */ diff --git a/drivers/crypto/Kconfig b/drivers/crypto/Kconfig index 7957acb..78df36a 100644 --- a/drivers/crypto/Kconfig +++ b/drivers/crypto/Kconfig @@ -131,20 +131,14 @@ config CRYPTO_AES_S390 select CRYPTO_BLKCIPHER help This is the s390 hardware accelerated implementation of the - AES cipher algorithms (FIPS-197). AES uses the Rijndael - algorithm. - - Rijndael appears to be consistently a very good performer in - both hardware and software across a wide range of computing - environments regardless of its use in feedback or non-feedback - modes. Its key setup time is excellent, and its key agility is - good. Rijndael's very low memory requirements make it very well - suited for restricted-space environments, in which it also - demonstrates excellent performance. Rijndael's operations are - among the easiest to defend against power and timing attacks. - - On s390 the System z9-109 currently only supports the key size - of 128 bit. + AES cipher algorithms (FIPS-197). + + As of z9 the ECB and CBC modes are hardware accelerated + for 128 bit keys. + As of z10 the ECB and CBC modes are hardware accelerated + for all AES key sizes. + As of z196 the XTS mode is hardware accelerated for 256 and + 512 bit keys. config S390_PRNG tristate "Pseudo random number generator device driver" -- cgit v0.10.2 From df1309ce955a490eac6697a41159b43e24d35995 Mon Sep 17 00:00:00 2001 From: Gerald Schaefer Date: Tue, 19 Apr 2011 21:29:18 +0200 Subject: crypto: s390 - add System z hardware support for GHASH This patch adds System z hardware acceleration support for the GHASH algorithm for GCM (Galois/Counter Mode). The hardware support is available beginning with System z196. Signed-off-by: Jan Glauber Signed-off-by: Gerald Schaefer Signed-off-by: Herbert Xu diff --git a/arch/s390/crypto/Makefile b/arch/s390/crypto/Makefile index 1cf81d7..7f0b7cd 100644 --- a/arch/s390/crypto/Makefile +++ b/arch/s390/crypto/Makefile @@ -8,3 +8,4 @@ obj-$(CONFIG_CRYPTO_SHA512_S390) += sha512_s390.o sha_common.o obj-$(CONFIG_CRYPTO_DES_S390) += des_s390.o obj-$(CONFIG_CRYPTO_AES_S390) += aes_s390.o obj-$(CONFIG_S390_PRNG) += prng.o +obj-$(CONFIG_CRYPTO_GHASH_S390) += ghash_s390.o diff --git a/arch/s390/crypto/crypt_s390.h b/arch/s390/crypto/crypt_s390.h index 7cbfaf0..eb2e391 100644 --- a/arch/s390/crypto/crypt_s390.h +++ b/arch/s390/crypto/crypt_s390.h @@ -91,6 +91,7 @@ enum crypt_s390_kimd_func { KIMD_SHA_1 = CRYPT_S390_KIMD | 1, KIMD_SHA_256 = CRYPT_S390_KIMD | 2, KIMD_SHA_512 = CRYPT_S390_KIMD | 3, + KIMD_GHASH = CRYPT_S390_KIMD | 65, }; /* diff --git a/arch/s390/crypto/ghash_s390.c b/arch/s390/crypto/ghash_s390.c new file mode 100644 index 0000000..b1bd170 --- /dev/null +++ b/arch/s390/crypto/ghash_s390.c @@ -0,0 +1,162 @@ +/* + * Cryptographic API. + * + * s390 implementation of the GHASH algorithm for GCM (Galois/Counter Mode). + * + * Copyright IBM Corp. 2011 + * Author(s): Gerald Schaefer + */ + +#include +#include + +#include "crypt_s390.h" + +#define GHASH_BLOCK_SIZE 16 +#define GHASH_DIGEST_SIZE 16 + +struct ghash_ctx { + u8 icv[16]; + u8 key[16]; +}; + +struct ghash_desc_ctx { + u8 buffer[GHASH_BLOCK_SIZE]; + u32 bytes; +}; + +static int ghash_init(struct shash_desc *desc) +{ + struct ghash_desc_ctx *dctx = shash_desc_ctx(desc); + + memset(dctx, 0, sizeof(*dctx)); + + return 0; +} + +static int ghash_setkey(struct crypto_shash *tfm, + const u8 *key, unsigned int keylen) +{ + struct ghash_ctx *ctx = crypto_shash_ctx(tfm); + + if (keylen != GHASH_BLOCK_SIZE) { + crypto_shash_set_flags(tfm, CRYPTO_TFM_RES_BAD_KEY_LEN); + return -EINVAL; + } + + memcpy(ctx->key, key, GHASH_BLOCK_SIZE); + memset(ctx->icv, 0, GHASH_BLOCK_SIZE); + + return 0; +} + +static int ghash_update(struct shash_desc *desc, + const u8 *src, unsigned int srclen) +{ + struct ghash_desc_ctx *dctx = shash_desc_ctx(desc); + struct ghash_ctx *ctx = crypto_shash_ctx(desc->tfm); + unsigned int n; + u8 *buf = dctx->buffer; + int ret; + + if (dctx->bytes) { + u8 *pos = buf + (GHASH_BLOCK_SIZE - dctx->bytes); + + n = min(srclen, dctx->bytes); + dctx->bytes -= n; + srclen -= n; + + memcpy(pos, src, n); + src += n; + + if (!dctx->bytes) { + ret = crypt_s390_kimd(KIMD_GHASH, ctx, buf, + GHASH_BLOCK_SIZE); + BUG_ON(ret != GHASH_BLOCK_SIZE); + } + } + + n = srclen & ~(GHASH_BLOCK_SIZE - 1); + if (n) { + ret = crypt_s390_kimd(KIMD_GHASH, ctx, src, n); + BUG_ON(ret != n); + src += n; + srclen -= n; + } + + if (srclen) { + dctx->bytes = GHASH_BLOCK_SIZE - srclen; + memcpy(buf, src, srclen); + } + + return 0; +} + +static void ghash_flush(struct ghash_ctx *ctx, struct ghash_desc_ctx *dctx) +{ + u8 *buf = dctx->buffer; + int ret; + + if (dctx->bytes) { + u8 *pos = buf + (GHASH_BLOCK_SIZE - dctx->bytes); + + memset(pos, 0, dctx->bytes); + + ret = crypt_s390_kimd(KIMD_GHASH, ctx, buf, GHASH_BLOCK_SIZE); + BUG_ON(ret != GHASH_BLOCK_SIZE); + } + + dctx->bytes = 0; +} + +static int ghash_final(struct shash_desc *desc, u8 *dst) +{ + struct ghash_desc_ctx *dctx = shash_desc_ctx(desc); + struct ghash_ctx *ctx = crypto_shash_ctx(desc->tfm); + + ghash_flush(ctx, dctx); + memcpy(dst, ctx->icv, GHASH_BLOCK_SIZE); + + return 0; +} + +static struct shash_alg ghash_alg = { + .digestsize = GHASH_DIGEST_SIZE, + .init = ghash_init, + .update = ghash_update, + .final = ghash_final, + .setkey = ghash_setkey, + .descsize = sizeof(struct ghash_desc_ctx), + .base = { + .cra_name = "ghash", + .cra_driver_name = "ghash-s390", + .cra_priority = CRYPT_S390_PRIORITY, + .cra_flags = CRYPTO_ALG_TYPE_SHASH, + .cra_blocksize = GHASH_BLOCK_SIZE, + .cra_ctxsize = sizeof(struct ghash_ctx), + .cra_module = THIS_MODULE, + .cra_list = LIST_HEAD_INIT(ghash_alg.base.cra_list), + }, +}; + +static int __init ghash_mod_init(void) +{ + if (!crypt_s390_func_available(KIMD_GHASH, + CRYPT_S390_MSA | CRYPT_S390_MSA4)) + return -EOPNOTSUPP; + + return crypto_register_shash(&ghash_alg); +} + +static void __exit ghash_mod_exit(void) +{ + crypto_unregister_shash(&ghash_alg); +} + +module_init(ghash_mod_init); +module_exit(ghash_mod_exit); + +MODULE_ALIAS("ghash"); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("GHASH Message Digest Algorithm, s390 implementation"); diff --git a/drivers/crypto/Kconfig b/drivers/crypto/Kconfig index 78df36a..d459cc78 100644 --- a/drivers/crypto/Kconfig +++ b/drivers/crypto/Kconfig @@ -151,6 +151,16 @@ config S390_PRNG ANSI X9.17 standard. The PRNG is usable via the char device /dev/prandom. +config CRYPTO_GHASH_S390 + tristate "GHASH digest algorithm" + depends on S390 + select CRYPTO_HASH + help + This is the s390 hardware accelerated implementation of the + GHASH message digest algorithm for GCM (Galois/Counter Mode). + + It is available as of z196. + config CRYPTO_DEV_MV_CESA tristate "Marvell's Cryptographic Engine" depends on PLAT_ORION -- cgit v0.10.2 From d393d9b8ca7f3296b50cb6fd0dc550ed6f72cdbc Mon Sep 17 00:00:00 2001 From: Jan Glauber Date: Tue, 19 Apr 2011 21:29:19 +0200 Subject: crypto: s390 - cleanup s390 Kconfig options Cleanup the remaining s390 crypto options by mentioning the earliest machine type that supports an accelerated algorithm. Signed-off-by: Jan Glauber Signed-off-by: Herbert Xu diff --git a/drivers/crypto/Kconfig b/drivers/crypto/Kconfig index d459cc78..dc601ff 100644 --- a/drivers/crypto/Kconfig +++ b/drivers/crypto/Kconfig @@ -91,6 +91,8 @@ config CRYPTO_SHA1_S390 This is the s390 hardware accelerated implementation of the SHA-1 secure hash standard (FIPS 180-1/DFIPS 180-2). + It is available as of z990. + config CRYPTO_SHA256_S390 tristate "SHA256 digest algorithm" depends on S390 @@ -99,8 +101,7 @@ config CRYPTO_SHA256_S390 This is the s390 hardware accelerated implementation of the SHA256 secure hash standard (DFIPS 180-2). - This version of SHA implements a 256 bit hash with 128 bits of - security against collision attacks. + It is available as of z9. config CRYPTO_SHA512_S390 tristate "SHA384 and SHA512 digest algorithm" @@ -110,10 +111,7 @@ config CRYPTO_SHA512_S390 This is the s390 hardware accelerated implementation of the SHA512 secure hash standard. - This version of SHA implements a 512 bit hash with 256 bits of - security against collision attacks. The code also includes SHA-384, - a 384 bit hash with 192 bits of security against collision attacks. - + It is available as of z10. config CRYPTO_DES_S390 tristate "DES and Triple DES cipher algorithms" @@ -148,8 +146,10 @@ config S390_PRNG Select this option if you want to use the s390 pseudo random number generator. The PRNG is part of the cryptographic processor functions and uses triple-DES to generate secure random numbers like the - ANSI X9.17 standard. The PRNG is usable via the char device - /dev/prandom. + ANSI X9.17 standard. User-space programs access the + pseudo-random-number device through the char device /dev/prandom. + + It is available as of z9. config CRYPTO_GHASH_S390 tristate "GHASH digest algorithm" -- cgit v0.10.2 From 9996e3421cae20a17c99881b2ac0f7562f760e04 Mon Sep 17 00:00:00 2001 From: Jan Glauber Date: Tue, 26 Apr 2011 16:34:01 +1000 Subject: crypto: tcrypt - CTR mode speed test for AES Add the CTR mode speed test for AES. Signed-off-by: Jan Glauber Signed-off-by: Herbert Xu diff --git a/crypto/tcrypt.c b/crypto/tcrypt.c index e912ea5..2222617 100644 --- a/crypto/tcrypt.c +++ b/crypto/tcrypt.c @@ -1009,6 +1009,10 @@ static int do_test(int m) speed_template_32_48_64); test_cipher_speed("xts(aes)", DECRYPT, sec, NULL, 0, speed_template_32_48_64); + test_cipher_speed("ctr(aes)", ENCRYPT, sec, NULL, 0, + speed_template_16_24_32); + test_cipher_speed("ctr(aes)", DECRYPT, sec, NULL, 0, + speed_template_16_24_32); break; case 201: -- cgit v0.10.2 From 0200f3ecc19660bebeabbcbaf212957fcf1dbf8f Mon Sep 17 00:00:00 2001 From: Gerald Schaefer Date: Wed, 4 May 2011 15:09:44 +1000 Subject: crypto: s390 - add System z hardware support for CTR mode This patch adds System z hardware acceleration support for AES, DES and 3DES in CTR mode. The hardware support is available starting with System z196. Signed-off-by: Gerald Schaefer Signed-off-by: Jan Glauber Signed-off-by: Herbert Xu diff --git a/arch/s390/crypto/aes_s390.c b/arch/s390/crypto/aes_s390.c index 8230e86..a9ce135 100644 --- a/arch/s390/crypto/aes_s390.c +++ b/arch/s390/crypto/aes_s390.c @@ -31,7 +31,8 @@ #define AES_KEYLEN_192 2 #define AES_KEYLEN_256 4 -static char keylen_flag = 0; +static u8 *ctrblk; +static char keylen_flag; struct s390_aes_ctx { u8 iv[AES_BLOCK_SIZE]; @@ -724,9 +725,128 @@ static struct crypto_alg xts_aes_alg = { } }; +static int ctr_aes_set_key(struct crypto_tfm *tfm, const u8 *in_key, + unsigned int key_len) +{ + struct s390_aes_ctx *sctx = crypto_tfm_ctx(tfm); + + switch (key_len) { + case 16: + sctx->enc = KMCTR_AES_128_ENCRYPT; + sctx->dec = KMCTR_AES_128_DECRYPT; + break; + case 24: + sctx->enc = KMCTR_AES_192_ENCRYPT; + sctx->dec = KMCTR_AES_192_DECRYPT; + break; + case 32: + sctx->enc = KMCTR_AES_256_ENCRYPT; + sctx->dec = KMCTR_AES_256_DECRYPT; + break; + } + + return aes_set_key(tfm, in_key, key_len); +} + +static int ctr_aes_crypt(struct blkcipher_desc *desc, long func, + struct s390_aes_ctx *sctx, struct blkcipher_walk *walk) +{ + int ret = blkcipher_walk_virt_block(desc, walk, AES_BLOCK_SIZE); + unsigned int i, n, nbytes; + u8 buf[AES_BLOCK_SIZE]; + u8 *out, *in; + + if (!walk->nbytes) + return ret; + + memcpy(ctrblk, walk->iv, AES_BLOCK_SIZE); + while ((nbytes = walk->nbytes) >= AES_BLOCK_SIZE) { + out = walk->dst.virt.addr; + in = walk->src.virt.addr; + while (nbytes >= AES_BLOCK_SIZE) { + /* only use complete blocks, max. PAGE_SIZE */ + n = (nbytes > PAGE_SIZE) ? PAGE_SIZE : + nbytes & ~(AES_BLOCK_SIZE - 1); + for (i = AES_BLOCK_SIZE; i < n; i += AES_BLOCK_SIZE) { + memcpy(ctrblk + i, ctrblk + i - AES_BLOCK_SIZE, + AES_BLOCK_SIZE); + crypto_inc(ctrblk + i, AES_BLOCK_SIZE); + } + ret = crypt_s390_kmctr(func, sctx->key, out, in, n, ctrblk); + BUG_ON(ret < 0 || ret != n); + if (n > AES_BLOCK_SIZE) + memcpy(ctrblk, ctrblk + n - AES_BLOCK_SIZE, + AES_BLOCK_SIZE); + crypto_inc(ctrblk, AES_BLOCK_SIZE); + out += n; + in += n; + nbytes -= n; + } + ret = blkcipher_walk_done(desc, walk, nbytes); + } + /* + * final block may be < AES_BLOCK_SIZE, copy only nbytes + */ + if (nbytes) { + out = walk->dst.virt.addr; + in = walk->src.virt.addr; + ret = crypt_s390_kmctr(func, sctx->key, buf, in, + AES_BLOCK_SIZE, ctrblk); + BUG_ON(ret < 0 || ret != AES_BLOCK_SIZE); + memcpy(out, buf, nbytes); + crypto_inc(ctrblk, AES_BLOCK_SIZE); + ret = blkcipher_walk_done(desc, walk, 0); + } + memcpy(walk->iv, ctrblk, AES_BLOCK_SIZE); + return ret; +} + +static int ctr_aes_encrypt(struct blkcipher_desc *desc, + struct scatterlist *dst, struct scatterlist *src, + unsigned int nbytes) +{ + struct s390_aes_ctx *sctx = crypto_blkcipher_ctx(desc->tfm); + struct blkcipher_walk walk; + + blkcipher_walk_init(&walk, dst, src, nbytes); + return ctr_aes_crypt(desc, sctx->enc, sctx, &walk); +} + +static int ctr_aes_decrypt(struct blkcipher_desc *desc, + struct scatterlist *dst, struct scatterlist *src, + unsigned int nbytes) +{ + struct s390_aes_ctx *sctx = crypto_blkcipher_ctx(desc->tfm); + struct blkcipher_walk walk; + + blkcipher_walk_init(&walk, dst, src, nbytes); + return ctr_aes_crypt(desc, sctx->dec, sctx, &walk); +} + +static struct crypto_alg ctr_aes_alg = { + .cra_name = "ctr(aes)", + .cra_driver_name = "ctr-aes-s390", + .cra_priority = CRYPT_S390_COMPOSITE_PRIORITY, + .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER, + .cra_blocksize = 1, + .cra_ctxsize = sizeof(struct s390_aes_ctx), + .cra_type = &crypto_blkcipher_type, + .cra_module = THIS_MODULE, + .cra_list = LIST_HEAD_INIT(ctr_aes_alg.cra_list), + .cra_u = { + .blkcipher = { + .min_keysize = AES_MIN_KEY_SIZE, + .max_keysize = AES_MAX_KEY_SIZE, + .ivsize = AES_BLOCK_SIZE, + .setkey = ctr_aes_set_key, + .encrypt = ctr_aes_encrypt, + .decrypt = ctr_aes_decrypt, + } + } +}; + static int __init aes_s390_init(void) { - unsigned long long facility_bits[2]; int ret; if (crypt_s390_func_available(KM_AES_128_ENCRYPT, CRYPT_S390_MSA)) @@ -765,9 +885,29 @@ static int __init aes_s390_init(void) goto xts_aes_err; } + if (crypt_s390_func_available(KMCTR_AES_128_ENCRYPT, + CRYPT_S390_MSA | CRYPT_S390_MSA4) && + crypt_s390_func_available(KMCTR_AES_192_ENCRYPT, + CRYPT_S390_MSA | CRYPT_S390_MSA4) && + crypt_s390_func_available(KMCTR_AES_256_ENCRYPT, + CRYPT_S390_MSA | CRYPT_S390_MSA4)) { + ctrblk = (u8 *) __get_free_page(GFP_KERNEL); + if (!ctrblk) { + ret = -ENOMEM; + goto ctr_aes_err; + } + ret = crypto_register_alg(&ctr_aes_alg); + if (ret) { + free_page((unsigned long) ctrblk); + goto ctr_aes_err; + } + } + out: return ret; +ctr_aes_err: + crypto_unregister_alg(&xts_aes_alg); xts_aes_err: crypto_unregister_alg(&cbc_aes_alg); cbc_aes_err: @@ -780,6 +920,8 @@ aes_err: static void __exit aes_s390_fini(void) { + crypto_unregister_alg(&ctr_aes_alg); + free_page((unsigned long) ctrblk); crypto_unregister_alg(&xts_aes_alg); crypto_unregister_alg(&cbc_aes_alg); crypto_unregister_alg(&ecb_aes_alg); diff --git a/arch/s390/crypto/crypt_s390.h b/arch/s390/crypto/crypt_s390.h index eb2e391..4967677 100644 --- a/arch/s390/crypto/crypt_s390.h +++ b/arch/s390/crypto/crypt_s390.h @@ -34,7 +34,8 @@ enum crypt_s390_operations { CRYPT_S390_KMC = 0x0200, CRYPT_S390_KIMD = 0x0300, CRYPT_S390_KLMD = 0x0400, - CRYPT_S390_KMAC = 0x0500 + CRYPT_S390_KMAC = 0x0500, + CRYPT_S390_KMCTR = 0x0600 }; /* @@ -83,6 +84,26 @@ enum crypt_s390_kmc_func { }; /* + * function codes for KMCTR (CIPHER MESSAGE WITH COUNTER) + * instruction + */ +enum crypt_s390_kmctr_func { + KMCTR_QUERY = CRYPT_S390_KMCTR | 0x0, + KMCTR_DEA_ENCRYPT = CRYPT_S390_KMCTR | 0x1, + KMCTR_DEA_DECRYPT = CRYPT_S390_KMCTR | 0x1 | 0x80, + KMCTR_TDEA_128_ENCRYPT = CRYPT_S390_KMCTR | 0x2, + KMCTR_TDEA_128_DECRYPT = CRYPT_S390_KMCTR | 0x2 | 0x80, + KMCTR_TDEA_192_ENCRYPT = CRYPT_S390_KMCTR | 0x3, + KMCTR_TDEA_192_DECRYPT = CRYPT_S390_KMCTR | 0x3 | 0x80, + KMCTR_AES_128_ENCRYPT = CRYPT_S390_KMCTR | 0x12, + KMCTR_AES_128_DECRYPT = CRYPT_S390_KMCTR | 0x12 | 0x80, + KMCTR_AES_192_ENCRYPT = CRYPT_S390_KMCTR | 0x13, + KMCTR_AES_192_DECRYPT = CRYPT_S390_KMCTR | 0x13 | 0x80, + KMCTR_AES_256_ENCRYPT = CRYPT_S390_KMCTR | 0x14, + KMCTR_AES_256_DECRYPT = CRYPT_S390_KMCTR | 0x14 | 0x80, +}; + +/* * function codes for KIMD (COMPUTE INTERMEDIATE MESSAGE DIGEST) * instruction */ @@ -293,6 +314,45 @@ static inline int crypt_s390_kmac(long func, void *param, } /** + * crypt_s390_kmctr: + * @func: the function code passed to KMCTR; see crypt_s390_kmctr_func + * @param: address of parameter block; see POP for details on each func + * @dest: address of destination memory area + * @src: address of source memory area + * @src_len: length of src operand in bytes + * @counter: address of counter value + * + * Executes the KMCTR (CIPHER MESSAGE WITH COUNTER) operation of the CPU. + * + * Returns -1 for failure, 0 for the query func, number of processed + * bytes for encryption/decryption funcs + */ +static inline int crypt_s390_kmctr(long func, void *param, u8 *dest, + const u8 *src, long src_len, u8 *counter) +{ + register long __func asm("0") = func & CRYPT_S390_FUNC_MASK; + register void *__param asm("1") = param; + register const u8 *__src asm("2") = src; + register long __src_len asm("3") = src_len; + register u8 *__dest asm("4") = dest; + register u8 *__ctr asm("6") = counter; + int ret = -1; + + asm volatile( + "0: .insn rrf,0xb92d0000,%3,%1,%4,0 \n" /* KMCTR opcode */ + "1: brc 1,0b \n" /* handle partial completion */ + " la %0,0\n" + "2:\n" + EX_TABLE(0b,2b) EX_TABLE(1b,2b) + : "+d" (ret), "+a" (__src), "+d" (__src_len), "+a" (__dest), + "+a" (__ctr) + : "d" (__func), "a" (__param) : "cc", "memory"); + if (ret < 0) + return ret; + return (func & CRYPT_S390_FUNC_MASK) ? src_len - __src_len : __src_len; +} + +/** * crypt_s390_func_available: * @func: the function code of the specific function; 0 if op in general * @@ -329,6 +389,10 @@ static inline int crypt_s390_func_available(int func, case CRYPT_S390_KMAC: ret = crypt_s390_kmac(KMAC_QUERY, &status, NULL, 0); break; + case CRYPT_S390_KMCTR: + ret = crypt_s390_kmctr(KMCTR_QUERY, &status, NULL, NULL, 0, + NULL); + break; default: return 0; } diff --git a/arch/s390/crypto/des_s390.c b/arch/s390/crypto/des_s390.c index c36a01d..a52bfd1 100644 --- a/arch/s390/crypto/des_s390.c +++ b/arch/s390/crypto/des_s390.c @@ -3,7 +3,7 @@ * * s390 implementation of the DES Cipher Algorithm. * - * Copyright IBM Corp. 2003,2007 + * Copyright IBM Corp. 2003,2011 * Author(s): Thomas Spatzier * Jan Glauber (jan.glauber@de.ibm.com) * @@ -24,6 +24,8 @@ #define DES3_KEY_SIZE (3 * DES_KEY_SIZE) +static u8 *ctrblk; + struct s390_des_ctx { u8 iv[DES_BLOCK_SIZE]; u8 key[DES3_KEY_SIZE]; @@ -370,6 +372,143 @@ static struct crypto_alg cbc_des3_alg = { } }; +static int ctr_desall_crypt(struct blkcipher_desc *desc, long func, + struct s390_des_ctx *ctx, struct blkcipher_walk *walk) +{ + int ret = blkcipher_walk_virt_block(desc, walk, DES_BLOCK_SIZE); + unsigned int i, n, nbytes; + u8 buf[DES_BLOCK_SIZE]; + u8 *out, *in; + + memcpy(ctrblk, walk->iv, DES_BLOCK_SIZE); + while ((nbytes = walk->nbytes) >= DES_BLOCK_SIZE) { + out = walk->dst.virt.addr; + in = walk->src.virt.addr; + while (nbytes >= DES_BLOCK_SIZE) { + /* align to block size, max. PAGE_SIZE */ + n = (nbytes > PAGE_SIZE) ? PAGE_SIZE : + nbytes & ~(DES_BLOCK_SIZE - 1); + for (i = DES_BLOCK_SIZE; i < n; i += DES_BLOCK_SIZE) { + memcpy(ctrblk + i, ctrblk + i - DES_BLOCK_SIZE, + DES_BLOCK_SIZE); + crypto_inc(ctrblk + i, DES_BLOCK_SIZE); + } + ret = crypt_s390_kmctr(func, ctx->key, out, in, n, ctrblk); + BUG_ON((ret < 0) || (ret != n)); + if (n > DES_BLOCK_SIZE) + memcpy(ctrblk, ctrblk + n - DES_BLOCK_SIZE, + DES_BLOCK_SIZE); + crypto_inc(ctrblk, DES_BLOCK_SIZE); + out += n; + in += n; + nbytes -= n; + } + ret = blkcipher_walk_done(desc, walk, nbytes); + } + + /* final block may be < DES_BLOCK_SIZE, copy only nbytes */ + if (nbytes) { + out = walk->dst.virt.addr; + in = walk->src.virt.addr; + ret = crypt_s390_kmctr(func, ctx->key, buf, in, + DES_BLOCK_SIZE, ctrblk); + BUG_ON(ret < 0 || ret != DES_BLOCK_SIZE); + memcpy(out, buf, nbytes); + crypto_inc(ctrblk, DES_BLOCK_SIZE); + ret = blkcipher_walk_done(desc, walk, 0); + } + memcpy(walk->iv, ctrblk, DES_BLOCK_SIZE); + return ret; +} + +static int ctr_des_encrypt(struct blkcipher_desc *desc, + struct scatterlist *dst, struct scatterlist *src, + unsigned int nbytes) +{ + struct s390_des_ctx *ctx = crypto_blkcipher_ctx(desc->tfm); + struct blkcipher_walk walk; + + blkcipher_walk_init(&walk, dst, src, nbytes); + return ctr_desall_crypt(desc, KMCTR_DEA_ENCRYPT, ctx, &walk); +} + +static int ctr_des_decrypt(struct blkcipher_desc *desc, + struct scatterlist *dst, struct scatterlist *src, + unsigned int nbytes) +{ + struct s390_des_ctx *ctx = crypto_blkcipher_ctx(desc->tfm); + struct blkcipher_walk walk; + + blkcipher_walk_init(&walk, dst, src, nbytes); + return ctr_desall_crypt(desc, KMCTR_DEA_DECRYPT, ctx, &walk); +} + +static struct crypto_alg ctr_des_alg = { + .cra_name = "ctr(des)", + .cra_driver_name = "ctr-des-s390", + .cra_priority = CRYPT_S390_COMPOSITE_PRIORITY, + .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER, + .cra_blocksize = 1, + .cra_ctxsize = sizeof(struct s390_des_ctx), + .cra_type = &crypto_blkcipher_type, + .cra_module = THIS_MODULE, + .cra_list = LIST_HEAD_INIT(ctr_des_alg.cra_list), + .cra_u = { + .blkcipher = { + .min_keysize = DES_KEY_SIZE, + .max_keysize = DES_KEY_SIZE, + .ivsize = DES_BLOCK_SIZE, + .setkey = des_setkey, + .encrypt = ctr_des_encrypt, + .decrypt = ctr_des_decrypt, + } + } +}; + +static int ctr_des3_encrypt(struct blkcipher_desc *desc, + struct scatterlist *dst, struct scatterlist *src, + unsigned int nbytes) +{ + struct s390_des_ctx *ctx = crypto_blkcipher_ctx(desc->tfm); + struct blkcipher_walk walk; + + blkcipher_walk_init(&walk, dst, src, nbytes); + return ctr_desall_crypt(desc, KMCTR_TDEA_192_ENCRYPT, ctx, &walk); +} + +static int ctr_des3_decrypt(struct blkcipher_desc *desc, + struct scatterlist *dst, struct scatterlist *src, + unsigned int nbytes) +{ + struct s390_des_ctx *ctx = crypto_blkcipher_ctx(desc->tfm); + struct blkcipher_walk walk; + + blkcipher_walk_init(&walk, dst, src, nbytes); + return ctr_desall_crypt(desc, KMCTR_TDEA_192_DECRYPT, ctx, &walk); +} + +static struct crypto_alg ctr_des3_alg = { + .cra_name = "ctr(des3_ede)", + .cra_driver_name = "ctr-des3_ede-s390", + .cra_priority = CRYPT_S390_COMPOSITE_PRIORITY, + .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER, + .cra_blocksize = 1, + .cra_ctxsize = sizeof(struct s390_des_ctx), + .cra_type = &crypto_blkcipher_type, + .cra_module = THIS_MODULE, + .cra_list = LIST_HEAD_INIT(ctr_des3_alg.cra_list), + .cra_u = { + .blkcipher = { + .min_keysize = DES3_KEY_SIZE, + .max_keysize = DES3_KEY_SIZE, + .ivsize = DES_BLOCK_SIZE, + .setkey = des3_setkey, + .encrypt = ctr_des3_encrypt, + .decrypt = ctr_des3_decrypt, + } + } +}; + static int __init des_s390_init(void) { int ret; @@ -396,9 +535,32 @@ static int __init des_s390_init(void) ret = crypto_register_alg(&cbc_des3_alg); if (ret) goto cbc_des3_err; + + if (crypt_s390_func_available(KMCTR_DEA_ENCRYPT, + CRYPT_S390_MSA | CRYPT_S390_MSA4) && + crypt_s390_func_available(KMCTR_TDEA_192_ENCRYPT, + CRYPT_S390_MSA | CRYPT_S390_MSA4)) { + ret = crypto_register_alg(&ctr_des_alg); + if (ret) + goto ctr_des_err; + ret = crypto_register_alg(&ctr_des3_alg); + if (ret) + goto ctr_des3_err; + ctrblk = (u8 *) __get_free_page(GFP_KERNEL); + if (!ctrblk) { + ret = -ENOMEM; + goto ctr_mem_err; + } + } out: return ret; +ctr_mem_err: + crypto_unregister_alg(&ctr_des3_alg); +ctr_des3_err: + crypto_unregister_alg(&ctr_des_alg); +ctr_des_err: + crypto_unregister_alg(&cbc_des3_alg); cbc_des3_err: crypto_unregister_alg(&ecb_des3_alg); ecb_des3_err: @@ -415,6 +577,11 @@ des_err: static void __exit des_s390_exit(void) { + if (ctrblk) { + crypto_unregister_alg(&ctr_des_alg); + crypto_unregister_alg(&ctr_des3_alg); + free_page((unsigned long) ctrblk); + } crypto_unregister_alg(&cbc_des3_alg); crypto_unregister_alg(&ecb_des3_alg); crypto_unregister_alg(&des3_alg); diff --git a/drivers/crypto/Kconfig b/drivers/crypto/Kconfig index dc601ff..c64c380 100644 --- a/drivers/crypto/Kconfig +++ b/drivers/crypto/Kconfig @@ -119,9 +119,12 @@ config CRYPTO_DES_S390 select CRYPTO_ALGAPI select CRYPTO_BLKCIPHER help - This us the s390 hardware accelerated implementation of the + This is the s390 hardware accelerated implementation of the DES cipher algorithm (FIPS 46-2), and Triple DES EDE (FIPS 46-3). + As of z990 the ECB and CBC mode are hardware accelerated. + As of z196 the CTR mode is hardware accelerated. + config CRYPTO_AES_S390 tristate "AES cipher algorithms" depends on S390 @@ -135,7 +138,8 @@ config CRYPTO_AES_S390 for 128 bit keys. As of z10 the ECB and CBC modes are hardware accelerated for all AES key sizes. - As of z196 the XTS mode is hardware accelerated for 256 and + As of z196 the CTR mode is hardware accelerated for all AES + key sizes and XTS mode is hardware accelerated for 256 and 512 bit keys. config S390_PRNG -- cgit v0.10.2 From bd68ccb390f0d91e26e6f3252ba457ee4e06974a Mon Sep 17 00:00:00 2001 From: Dmitry Eremin-Solenikov Date: Wed, 27 Apr 2011 23:21:15 +0400 Subject: hwrng: amd - manage resource allocation As amd driver doesn't bind to PCI device, we'd better manage reource allocation on our own to disallow (possible) conflicts. Signed-off-by: Dmitry Eremin-Solenikov Acked-by: Matt Mackall Signed-off-by: Herbert Xu diff --git a/drivers/char/hw_random/amd-rng.c b/drivers/char/hw_random/amd-rng.c index 0d8c578..c6af038 100644 --- a/drivers/char/hw_random/amd-rng.c +++ b/drivers/char/hw_random/amd-rng.c @@ -133,6 +133,12 @@ found: pmbase &= 0x0000FF00; if (pmbase == 0) goto out; + if (!request_region(pmbase + 0xF0, 8, "AMD HWRNG")) { + dev_err(&pdev->dev, "AMD HWRNG region 0x%x already in use!\n", + pmbase + 0xF0); + err = -EBUSY; + goto out; + } amd_rng.priv = (unsigned long)pmbase; amd_pdev = pdev; @@ -141,6 +147,7 @@ found: if (err) { printk(KERN_ERR PFX "RNG registering failed (%d)\n", err); + release_region(pmbase + 0xF0, 8); goto out; } out: @@ -149,6 +156,8 @@ out: static void __exit mod_exit(void) { + u32 pmbase = (unsigned long)amd_rng.priv; + release_region(pmbase + 0xF0, 8); hwrng_unregister(&amd_rng); } -- cgit v0.10.2 From 3023b5b6f1d9e3f12827d0437f6bf096dddac944 Mon Sep 17 00:00:00 2001 From: Dmitry Eremin-Solenikov Date: Wed, 27 Apr 2011 23:21:16 +0400 Subject: hwrng: amd - enable AMD hw rnd driver for Maple PPC boards PPC 970FX Evaluation kit (Maple) boards bear AMD8111 southbridge. Allow this driver to be compiled in if PPC_MAPLE is selected. Signed-off-by: Dmitry Eremin-Solenikov Acked-by: Matt Mackall Signed-off-by: Herbert Xu diff --git a/drivers/char/hw_random/Kconfig b/drivers/char/hw_random/Kconfig index beecd1c..a60043b 100644 --- a/drivers/char/hw_random/Kconfig +++ b/drivers/char/hw_random/Kconfig @@ -49,7 +49,7 @@ config HW_RANDOM_INTEL config HW_RANDOM_AMD tristate "AMD HW Random Number Generator support" - depends on HW_RANDOM && X86 && PCI + depends on HW_RANDOM && (X86 || PPC_MAPLE) && PCI default HW_RANDOM ---help--- This driver provides kernel-side support for the Random Number -- cgit v0.10.2 From 701af31ce0cc6a1114001d792c21108c7f49ac86 Mon Sep 17 00:00:00 2001 From: Kim Phillips Date: Mon, 2 May 2011 18:27:41 -0500 Subject: crypto: caam - remove unused keylen from session context Signed-off-by: Kim Phillips Signed-off-by: Herbert Xu diff --git a/drivers/crypto/caam/caamalg.c b/drivers/crypto/caam/caamalg.c index 245cfe4..5c16019 100644 --- a/drivers/crypto/caam/caamalg.c +++ b/drivers/crypto/caam/caamalg.c @@ -82,7 +82,6 @@ struct caam_ctx { u32 alg_op; u8 *key; dma_addr_t key_phys; - unsigned int keylen; unsigned int enckeylen; unsigned int authkeylen; unsigned int split_key_len; @@ -330,7 +329,6 @@ static int aead_authenc_setkey(struct crypto_aead *aead, ctx->split_key_pad_len + enckeylen, 1); #endif - ctx->keylen = keylen; ctx->enckeylen = enckeylen; ctx->authkeylen = authkeylen; -- cgit v0.10.2 From de2954d66408da3ae34effda777bb564fd17781b Mon Sep 17 00:00:00 2001 From: Kim Phillips Date: Mon, 2 May 2011 18:29:17 -0500 Subject: crypto: caam - fix printk recursion for long error texts during recent descriptor development, an Invalid Sequence Command error triggered a: BUG: recent printk recursion! due to insufficient memory allocated for the error text. The Invalid Sequence Command error text is the longest. The length of the maximum error string is computed as the sum of: "DECO: ": 6 "jump tgt desc idx 255: ": 23 Invalid Sequence Command text: 272 zero termination character: 1 i.e, 302 characters. Define this maximum error string length in error.h and fix caam_jr_strstatus callsites. Signed-off-by: Kim Phillips Signed-off-by: Herbert Xu diff --git a/drivers/crypto/caam/caamalg.c b/drivers/crypto/caam/caamalg.c index 5c16019..b97575e 100644 --- a/drivers/crypto/caam/caamalg.c +++ b/drivers/crypto/caam/caamalg.c @@ -113,7 +113,7 @@ static void split_key_done(struct device *dev, u32 *desc, u32 err, dev_err(dev, "%s %d: err 0x%x\n", __func__, __LINE__, err); #endif if (err) { - char tmp[256]; + char tmp[CAAM_ERROR_STR_MAX]; dev_err(dev, "%08x: %s\n", err, caam_jr_strstatus(tmp, err)); } @@ -414,7 +414,7 @@ static void ipsec_esp_encrypt_done(struct device *jrdev, u32 *desc, u32 err, offsetof(struct ipsec_esp_edesc, hw_desc)); if (err) { - char tmp[256]; + char tmp[CAAM_ERROR_STR_MAX]; dev_err(jrdev, "%08x: %s\n", err, caam_jr_strstatus(tmp, err)); } @@ -454,7 +454,7 @@ static void ipsec_esp_decrypt_done(struct device *jrdev, u32 *desc, u32 err, offsetof(struct ipsec_esp_edesc, hw_desc)); if (err) { - char tmp[256]; + char tmp[CAAM_ERROR_STR_MAX]; dev_err(jrdev, "%08x: %s\n", err, caam_jr_strstatus(tmp, err)); } diff --git a/drivers/crypto/caam/error.h b/drivers/crypto/caam/error.h index 067afc1..02c7baa 100644 --- a/drivers/crypto/caam/error.h +++ b/drivers/crypto/caam/error.h @@ -6,5 +6,6 @@ #ifndef CAAM_ERROR_H #define CAAM_ERROR_H +#define CAAM_ERROR_STR_MAX 302 extern char *caam_jr_strstatus(char *outstr, u32 status); #endif /* CAAM_ERROR_H */ -- cgit v0.10.2 From a32e252f7cdfb3675a4e50215cfac356ed8952c4 Mon Sep 17 00:00:00 2001 From: Michael Neuling Date: Wed, 6 Apr 2011 18:23:29 +0000 Subject: powerpc: Use new CPU feature bit to select 2.06 tlbie This removes MMU_FTR_TLBIE_206 as we can now use CPU_FTR_HVMODE_206. It also changes the logic to select which tlbie to use to be based on this new CPU feature bit. This also duplicates the ASM_FTR_IF/SET/CLR defines for CPU features (copied from MMU features). Signed-off-by: Michael Neuling Signed-off-by: Benjamin Herrenschmidt diff --git a/arch/powerpc/include/asm/feature-fixups.h b/arch/powerpc/include/asm/feature-fixups.h index bdc0d68..9a67a38 100644 --- a/arch/powerpc/include/asm/feature-fixups.h +++ b/arch/powerpc/include/asm/feature-fixups.h @@ -146,6 +146,19 @@ label##5: \ #ifndef __ASSEMBLY__ +#define ASM_FTR_IF(section_if, section_else, msk, val) \ + stringify_in_c(BEGIN_FTR_SECTION) \ + section_if "; " \ + stringify_in_c(FTR_SECTION_ELSE) \ + section_else "; " \ + stringify_in_c(ALT_FTR_SECTION_END((msk), (val))) + +#define ASM_FTR_IFSET(section_if, section_else, msk) \ + ASM_FTR_IF(section_if, section_else, (msk), (msk)) + +#define ASM_FTR_IFCLR(section_if, section_else, msk) \ + ASM_FTR_IF(section_if, section_else, (msk), 0) + #define ASM_MMU_FTR_IF(section_if, section_else, msk, val) \ stringify_in_c(BEGIN_MMU_FTR_SECTION) \ section_if "; " \ diff --git a/arch/powerpc/include/asm/mmu.h b/arch/powerpc/include/asm/mmu.h index a39304b..4138b21 100644 --- a/arch/powerpc/include/asm/mmu.h +++ b/arch/powerpc/include/asm/mmu.h @@ -56,11 +56,6 @@ */ #define MMU_FTR_NEED_DTLB_SW_LRU ASM_CONST(0x00200000) -/* This indicates that the processor uses the ISA 2.06 server tlbie - * mnemonics - */ -#define MMU_FTR_TLBIE_206 ASM_CONST(0x00400000) - /* Enable use of TLB reservation. Processor should support tlbsrx. * instruction and MAS0[WQ]. */ @@ -105,8 +100,7 @@ #define MMU_FTRS_PPC970 MMU_FTRS_POWER4 #define MMU_FTRS_POWER5 MMU_FTRS_POWER4 | MMU_FTR_LOCKLESS_TLBIE #define MMU_FTRS_POWER6 MMU_FTRS_POWER4 | MMU_FTR_LOCKLESS_TLBIE -#define MMU_FTRS_POWER7 MMU_FTRS_POWER4 | MMU_FTR_LOCKLESS_TLBIE | \ - MMU_FTR_TLBIE_206 +#define MMU_FTRS_POWER7 MMU_FTRS_POWER4 | MMU_FTR_LOCKLESS_TLBIE #define MMU_FTRS_CELL MMU_FTRS_DEFAULT_HPTE_ARCH_V2 | \ MMU_FTR_CI_LARGE_PAGE #define MMU_FTRS_PA6T MMU_FTRS_DEFAULT_HPTE_ARCH_V2 | \ diff --git a/arch/powerpc/mm/hash_native_64.c b/arch/powerpc/mm/hash_native_64.c index c23eef2..dfd7648 100644 --- a/arch/powerpc/mm/hash_native_64.c +++ b/arch/powerpc/mm/hash_native_64.c @@ -50,9 +50,8 @@ static inline void __tlbie(unsigned long va, int psize, int ssize) case MMU_PAGE_4K: va &= ~0xffful; va |= ssize << 8; - asm volatile(ASM_MMU_FTR_IFCLR("tlbie %0,0", PPC_TLBIE(%1,%0), - %2) - : : "r" (va), "r"(0), "i" (MMU_FTR_TLBIE_206) + asm volatile(ASM_FTR_IFCLR("tlbie %0,0", PPC_TLBIE(%1,%0), %2) + : : "r" (va), "r"(0), "i" (CPU_FTR_HVMODE_206) : "memory"); break; default: @@ -61,9 +60,8 @@ static inline void __tlbie(unsigned long va, int psize, int ssize) va |= penc << 12; va |= ssize << 8; va |= 1; /* L */ - asm volatile(ASM_MMU_FTR_IFCLR("tlbie %0,1", PPC_TLBIE(%1,%0), - %2) - : : "r" (va), "r"(0), "i" (MMU_FTR_TLBIE_206) + asm volatile(ASM_FTR_IFCLR("tlbie %0,1", PPC_TLBIE(%1,%0), %2) + : : "r" (va), "r"(0), "i" (CPU_FTR_HVMODE_206) : "memory"); break; } -- cgit v0.10.2 From 851d2e2fe8dbcbe3afcad6fc4569c881d8ad4ce9 Mon Sep 17 00:00:00 2001 From: "Tseng-Hui (Frank) Lin" Date: Mon, 2 May 2011 20:43:04 +0000 Subject: powerpc: Add Initiate Coprocessor Store Word (icswx) support Icswx is a PowerPC instruction to send data to a co-processor. On Book-S processors the LPAR_ID and process ID (PID) of the owning process are registered in the window context of the co-processor at initialization time. When the icswx instruction is executed the L2 generates a cop-reg transaction on PowerBus. The transaction has no address and the processor does not perform an MMU access to authenticate the transaction. The co-processor compares the LPAR_ID and the PID included in the transaction and the LPAR_ID and PID held in the window context to determine if the process is authorized to generate the transaction. The OS needs to assign a 16-bit PID for the process. This cop-PID needs to be updated during context switch. The cop-PID needs to be destroyed when the context is destroyed. Signed-off-by: Sonny Rao Signed-off-by: Tseng-Hui (Frank) Lin Signed-off-by: Anton Blanchard Signed-off-by: Benjamin Herrenschmidt diff --git a/arch/powerpc/include/asm/cputable.h b/arch/powerpc/include/asm/cputable.h index 3db2476..a3e1a9e 100644 --- a/arch/powerpc/include/asm/cputable.h +++ b/arch/powerpc/include/asm/cputable.h @@ -197,6 +197,7 @@ extern const char *powerpc_base_platform; #define CPU_FTR_STCX_CHECKS_ADDRESS LONG_ASM_CONST(0x0200000000000000) #define CPU_FTR_POPCNTB LONG_ASM_CONST(0x0400000000000000) #define CPU_FTR_POPCNTD LONG_ASM_CONST(0x0800000000000000) +#define CPU_FTR_ICSWX LONG_ASM_CONST(0x1000000000000000) #ifndef __ASSEMBLY__ @@ -418,7 +419,8 @@ extern const char *powerpc_base_platform; CPU_FTR_COHERENT_ICACHE | \ CPU_FTR_PURR | CPU_FTR_SPURR | CPU_FTR_REAL_LE | \ CPU_FTR_DSCR | CPU_FTR_SAO | CPU_FTR_ASYM_SMT | \ - CPU_FTR_STCX_CHECKS_ADDRESS | CPU_FTR_POPCNTB | CPU_FTR_POPCNTD) + CPU_FTR_STCX_CHECKS_ADDRESS | CPU_FTR_POPCNTB | CPU_FTR_POPCNTD | \ + CPU_FTR_ICSWX) #define CPU_FTRS_CELL (CPU_FTR_USE_TB | CPU_FTR_LWSYNC | \ CPU_FTR_PPCAS_ARCH_V2 | CPU_FTR_CTRL | \ CPU_FTR_ALTIVEC_COMP | CPU_FTR_MMCRA | CPU_FTR_SMT | \ diff --git a/arch/powerpc/include/asm/mmu-hash64.h b/arch/powerpc/include/asm/mmu-hash64.h index ae7b3ef..d865bd9 100644 --- a/arch/powerpc/include/asm/mmu-hash64.h +++ b/arch/powerpc/include/asm/mmu-hash64.h @@ -408,6 +408,7 @@ static inline void subpage_prot_init_new_context(struct mm_struct *mm) { } #endif /* CONFIG_PPC_SUBPAGE_PROT */ typedef unsigned long mm_context_id_t; +struct spinlock; typedef struct { mm_context_id_t id; @@ -423,6 +424,11 @@ typedef struct { #ifdef CONFIG_PPC_SUBPAGE_PROT struct subpage_prot_table spt; #endif /* CONFIG_PPC_SUBPAGE_PROT */ +#ifdef CONFIG_PPC_ICSWX + struct spinlock *cop_lockp; /* guard acop and cop_pid */ + unsigned long acop; /* mask of enabled coprocessor types */ + unsigned int cop_pid; /* pid value used with coprocessors */ +#endif /* CONFIG_PPC_ICSWX */ } mm_context_t; diff --git a/arch/powerpc/include/asm/mmu_context.h b/arch/powerpc/include/asm/mmu_context.h index 8e13f65..a73668a 100644 --- a/arch/powerpc/include/asm/mmu_context.h +++ b/arch/powerpc/include/asm/mmu_context.h @@ -32,6 +32,10 @@ extern void __destroy_context(unsigned long context_id); extern void mmu_context_init(void); #endif +extern void switch_cop(struct mm_struct *next); +extern int use_cop(unsigned long acop, struct mm_struct *mm); +extern void drop_cop(unsigned long acop, struct mm_struct *mm); + /* * switch_mm is the entry point called from the architecture independent * code in kernel/sched.c @@ -55,6 +59,12 @@ static inline void switch_mm(struct mm_struct *prev, struct mm_struct *next, if (prev == next) return; +#ifdef CONFIG_PPC_ICSWX + /* Switch coprocessor context only if prev or next uses a coprocessor */ + if (prev->context.acop || next->context.acop) + switch_cop(next); +#endif /* CONFIG_PPC_ICSWX */ + /* We must stop all altivec streams before changing the HW * context */ diff --git a/arch/powerpc/include/asm/reg.h b/arch/powerpc/include/asm/reg.h index 1f9ac12..632e78e 100644 --- a/arch/powerpc/include/asm/reg.h +++ b/arch/powerpc/include/asm/reg.h @@ -188,6 +188,7 @@ #define SPRN_CTR 0x009 /* Count Register */ #define SPRN_DSCR 0x11 +#define SPRN_ACOP 0x1F /* Available Coprocessor Register */ #define SPRN_CTRLF 0x088 #define SPRN_CTRLT 0x098 #define CTRL_CT 0xc0000000 /* current thread */ diff --git a/arch/powerpc/mm/mmu_context_hash64.c b/arch/powerpc/mm/mmu_context_hash64.c index c585944..c517815 100644 --- a/arch/powerpc/mm/mmu_context_hash64.c +++ b/arch/powerpc/mm/mmu_context_hash64.c @@ -20,9 +20,205 @@ #include #include #include +#include #include +#ifdef CONFIG_PPC_ICSWX +/* + * The processor and its L2 cache cause the icswx instruction to + * generate a COP_REQ transaction on PowerBus. The transaction has + * no address, and the processor does not perform an MMU access + * to authenticate the transaction. The command portion of the + * PowerBus COP_REQ transaction includes the LPAR_ID (LPID) and + * the coprocessor Process ID (PID), which the coprocessor compares + * to the authorized LPID and PID held in the coprocessor, to determine + * if the process is authorized to generate the transaction. + * The data of the COP_REQ transaction is 128-byte or less and is + * placed in cacheable memory on a 128-byte cache line boundary. + * + * The task to use a coprocessor should use use_cop() to allocate + * a coprocessor PID before executing icswx instruction. use_cop() + * also enables the coprocessor context switching. Drop_cop() is + * used to free the coprocessor PID. + * + * Example: + * Host Fabric Interface (HFI) is a PowerPC network coprocessor. + * Each HFI have multiple windows. Each HFI window serves as a + * network device sending to and receiving from HFI network. + * HFI immediate send function uses icswx instruction. The immediate + * send function allows small (single cache-line) packets be sent + * without using the regular HFI send FIFO and doorbell, which are + * much slower than immediate send. + * + * For each task intending to use HFI immediate send, the HFI driver + * calls use_cop() to obtain a coprocessor PID for the task. + * The HFI driver then allocate a free HFI window and save the + * coprocessor PID to the HFI window to allow the task to use the + * HFI window. + * + * The HFI driver repeatedly creates immediate send packets and + * issues icswx instruction to send data through the HFI window. + * The HFI compares the coprocessor PID in the CPU PID register + * to the PID held in the HFI window to determine if the transaction + * is allowed. + * + * When the task to release the HFI window, the HFI driver calls + * drop_cop() to release the coprocessor PID. + */ + +#define COP_PID_NONE 0 +#define COP_PID_MIN (COP_PID_NONE + 1) +#define COP_PID_MAX (0xFFFF) + +static DEFINE_SPINLOCK(mmu_context_acop_lock); +static DEFINE_IDA(cop_ida); + +void switch_cop(struct mm_struct *next) +{ + mtspr(SPRN_PID, next->context.cop_pid); + mtspr(SPRN_ACOP, next->context.acop); +} + +static int new_cop_pid(struct ida *ida, int min_id, int max_id, + spinlock_t *lock) +{ + int index; + int err; + +again: + if (!ida_pre_get(ida, GFP_KERNEL)) + return -ENOMEM; + + spin_lock(lock); + err = ida_get_new_above(ida, min_id, &index); + spin_unlock(lock); + + if (err == -EAGAIN) + goto again; + else if (err) + return err; + + if (index > max_id) { + spin_lock(lock); + ida_remove(ida, index); + spin_unlock(lock); + return -ENOMEM; + } + + return index; +} + +static void sync_cop(void *arg) +{ + struct mm_struct *mm = arg; + + if (mm == current->active_mm) + switch_cop(current->active_mm); +} + +/** + * Start using a coprocessor. + * @acop: mask of coprocessor to be used. + * @mm: The mm the coprocessor to associate with. Most likely current mm. + * + * Return a positive PID if successful. Negative errno otherwise. + * The returned PID will be fed to the coprocessor to determine if an + * icswx transaction is authenticated. + */ +int use_cop(unsigned long acop, struct mm_struct *mm) +{ + int ret; + + if (!cpu_has_feature(CPU_FTR_ICSWX)) + return -ENODEV; + + if (!mm || !acop) + return -EINVAL; + + /* We need to make sure mm_users doesn't change */ + down_read(&mm->mmap_sem); + spin_lock(mm->context.cop_lockp); + + if (mm->context.cop_pid == COP_PID_NONE) { + ret = new_cop_pid(&cop_ida, COP_PID_MIN, COP_PID_MAX, + &mmu_context_acop_lock); + if (ret < 0) + goto out; + + mm->context.cop_pid = ret; + } + mm->context.acop |= acop; + + sync_cop(mm); + + /* + * If this is a threaded process then there might be other threads + * running. We need to send an IPI to force them to pick up any + * change in PID and ACOP. + */ + if (atomic_read(&mm->mm_users) > 1) + smp_call_function(sync_cop, mm, 1); + + ret = mm->context.cop_pid; + +out: + spin_unlock(mm->context.cop_lockp); + up_read(&mm->mmap_sem); + + return ret; +} +EXPORT_SYMBOL_GPL(use_cop); + +/** + * Stop using a coprocessor. + * @acop: mask of coprocessor to be stopped. + * @mm: The mm the coprocessor associated with. + */ +void drop_cop(unsigned long acop, struct mm_struct *mm) +{ + int free_pid = COP_PID_NONE; + + if (!cpu_has_feature(CPU_FTR_ICSWX)) + return; + + if (WARN_ON_ONCE(!mm)) + return; + + /* We need to make sure mm_users doesn't change */ + down_read(&mm->mmap_sem); + spin_lock(mm->context.cop_lockp); + + mm->context.acop &= ~acop; + + if ((!mm->context.acop) && (mm->context.cop_pid != COP_PID_NONE)) { + free_pid = mm->context.cop_pid; + mm->context.cop_pid = COP_PID_NONE; + } + + sync_cop(mm); + + /* + * If this is a threaded process then there might be other threads + * running. We need to send an IPI to force them to pick up any + * change in PID and ACOP. + */ + if (atomic_read(&mm->mm_users) > 1) + smp_call_function(sync_cop, mm, 1); + + if (free_pid != COP_PID_NONE) { + spin_lock(&mmu_context_acop_lock); + ida_remove(&cop_ida, free_pid); + spin_unlock(&mmu_context_acop_lock); + } + + spin_unlock(mm->context.cop_lockp); + up_read(&mm->mmap_sem); +} +EXPORT_SYMBOL_GPL(drop_cop); + +#endif /* CONFIG_PPC_ICSWX */ + static DEFINE_SPINLOCK(mmu_context_lock); static DEFINE_IDA(mmu_context_ida); @@ -78,6 +274,16 @@ int init_new_context(struct task_struct *tsk, struct mm_struct *mm) slice_set_user_psize(mm, mmu_virtual_psize); subpage_prot_init_new_context(mm); mm->context.id = index; +#ifdef CONFIG_PPC_ICSWX + mm->context.cop_lockp = kmalloc(sizeof(spinlock_t), GFP_KERNEL); + if (!mm->context.cop_lockp) { + __destroy_context(index); + subpage_prot_free(mm); + mm->context.id = NO_CONTEXT; + return -ENOMEM; + } + spin_lock_init(mm->context.cop_lockp); +#endif /* CONFIG_PPC_ICSWX */ return 0; } @@ -92,6 +298,11 @@ EXPORT_SYMBOL_GPL(__destroy_context); void destroy_context(struct mm_struct *mm) { +#ifdef CONFIG_PPC_ICSWX + drop_cop(mm->context.acop, mm); + kfree(mm->context.cop_lockp); + mm->context.cop_lockp = NULL; +#endif /* CONFIG_PPC_ICSWX */ __destroy_context(mm->context.id); subpage_prot_free(mm); mm->context.id = MMU_NO_CONTEXT; diff --git a/arch/powerpc/platforms/Kconfig.cputype b/arch/powerpc/platforms/Kconfig.cputype index 7c1e1c6..a1e6238 100644 --- a/arch/powerpc/platforms/Kconfig.cputype +++ b/arch/powerpc/platforms/Kconfig.cputype @@ -230,6 +230,24 @@ config VSX If in doubt, say Y here. +config PPC_ICSWX + bool "Support for PowerPC icswx coprocessor instruction" + depends on POWER4 + default n + ---help--- + + This option enables kernel support for the PowerPC Initiate + Coprocessor Store Word (icswx) coprocessor instruction on POWER7 + or newer processors. + + This option is only useful if you have a processor that supports + the icswx coprocessor instruction. It does not have any effect + on processors without the icswx coprocessor instruction. + + This option slightly increases kernel memory usage. + + If in doubt, say N here. + config SPE bool "SPE Support" depends on E200 || (E500 && !PPC_E500MC) -- cgit v0.10.2 From 1977b502120d44b9b4897703adfb2e2fab346880 Mon Sep 17 00:00:00 2001 From: Paul Mackerras Date: Sun, 1 May 2011 19:46:44 +0000 Subject: powerpc: Save register r9-r13 values accurately on interrupt with bad stack When we take an interrupt or exception from kernel mode and the stack pointer is obviously not a kernel address (i.e. the top bit is 0), we switch to an emergency stack, save register values and panic. However, on 64-bit server machines, we don't actually save the values of r9 - r13 at the time of the interrupt, but rather values corrupted by the exception entry code for r12-r13, and nothing at all for r9-r11. This fixes it by passing a pointer to the register save area in the paca through to the bad_stack code in r3. The register values are saved in one of the paca register save areas (depending on which exception this is). Using the pointer in r3, the bad_stack code now retrieves the saved values of r9 - r13 and stores them in the exception frame on the emergency stack. This also stores the normal exception frame marker ("regshere") in the exception frame. Signed-off-by: Paul Mackerras Signed-off-by: Benjamin Herrenschmidt diff --git a/arch/powerpc/include/asm/exception-64s.h b/arch/powerpc/include/asm/exception-64s.h index d6b4849..96ccef1 100644 --- a/arch/powerpc/include/asm/exception-64s.h +++ b/arch/powerpc/include/asm/exception-64s.h @@ -104,10 +104,11 @@ beq- 1f; \ ld r1,PACAKSAVE(r13); /* kernel stack to use */ \ 1: cmpdi cr1,r1,0; /* check if r1 is in userspace */ \ - bge- cr1,2f; /* abort if it is */ \ - b 3f; \ -2: li r1,(n); /* will be reloaded later */ \ + blt+ cr1,3f; /* abort if it is */ \ + li r1,(n); /* will be reloaded later */ \ sth r1,PACA_TRAP_SAVE(r13); \ + std r3,area+EX_R3(r13); \ + addi r3,r13,area; /* r3 -> where regs are saved*/ \ b bad_stack; \ 3: std r9,_CCR(r1); /* save CR in stackframe */ \ std r11,_NIP(r1); /* save SRR0 in stackframe */ \ diff --git a/arch/powerpc/kernel/exceptions-64s.S b/arch/powerpc/kernel/exceptions-64s.S index 226cc8c..27ca8b7 100644 --- a/arch/powerpc/kernel/exceptions-64s.S +++ b/arch/powerpc/kernel/exceptions-64s.S @@ -461,9 +461,20 @@ bad_stack: std r12,_XER(r1) SAVE_GPR(0,r1) SAVE_GPR(2,r1) - SAVE_4GPRS(3,r1) - SAVE_2GPRS(7,r1) - SAVE_10GPRS(12,r1) + ld r10,EX_R3(r3) + std r10,GPR3(r1) + SAVE_GPR(4,r1) + SAVE_4GPRS(5,r1) + ld r9,EX_R9(r3) + ld r10,EX_R10(r3) + SAVE_2GPRS(9,r1) + ld r9,EX_R11(r3) + ld r10,EX_R12(r3) + ld r11,EX_R13(r3) + std r9,GPR11(r1) + std r10,GPR12(r1) + std r11,GPR13(r1) + SAVE_8GPRS(14,r1) SAVE_10GPRS(22,r1) lhz r12,PACA_TRAP_SAVE(r13) std r12,_TRAP(r1) @@ -472,6 +483,9 @@ bad_stack: li r12,0 std r12,0(r11) ld r2,PACATOC(r13) + ld r11,exception_marker@toc(r2) + std r12,RESULT(r1) + std r11,STACK_FRAME_OVERHEAD-16(r1) 1: addi r3,r1,STACK_FRAME_OVERHEAD bl .kernel_bad_stack b 1b -- cgit v0.10.2 From 48404f2e95ef0ffd8134d89c8abcd1a15e15f1b0 Mon Sep 17 00:00:00 2001 From: Paul Mackerras Date: Sun, 1 May 2011 19:48:20 +0000 Subject: powerpc: Save Come-From Address Register (CFAR) in exception frame Recent 64-bit server processors (POWER6 and POWER7) have a "Come-From Address Register" (CFAR), that records the address of the most recent branch or rfid (return from interrupt) instruction for debugging purposes. This saves the value of the CFAR in the exception entry code and stores it in the exception frame. We also make xmon print the CFAR value in its register dump code. Rather than extend the pt_regs struct at this time, we steal the orig_gpr3 field, which is only used for system calls, and use it for the CFAR value for all exceptions/interrupts other than system calls. This means we don't save the CFAR on system calls, which is not a great problem since system calls tend not to happen unexpectedly, and also avoids adding the overhead of reading the CFAR to the system call entry path. Signed-off-by: Paul Mackerras Signed-off-by: Benjamin Herrenschmidt diff --git a/arch/powerpc/include/asm/cputable.h b/arch/powerpc/include/asm/cputable.h index a3e1a9e..4efbfb3 100644 --- a/arch/powerpc/include/asm/cputable.h +++ b/arch/powerpc/include/asm/cputable.h @@ -180,6 +180,7 @@ extern const char *powerpc_base_platform; #define CPU_FTR_HVMODE_206 LONG_ASM_CONST(0x0000000800000000) +#define CPU_FTR_CFAR LONG_ASM_CONST(0x0000001000000000) #define CPU_FTR_IABR LONG_ASM_CONST(0x0000002000000000) #define CPU_FTR_MMCRA LONG_ASM_CONST(0x0000004000000000) #define CPU_FTR_CTRL LONG_ASM_CONST(0x0000008000000000) @@ -412,7 +413,7 @@ extern const char *powerpc_base_platform; CPU_FTR_COHERENT_ICACHE | \ CPU_FTR_PURR | CPU_FTR_SPURR | CPU_FTR_REAL_LE | \ CPU_FTR_DSCR | CPU_FTR_UNALIGNED_LD_STD | \ - CPU_FTR_STCX_CHECKS_ADDRESS | CPU_FTR_POPCNTB) + CPU_FTR_STCX_CHECKS_ADDRESS | CPU_FTR_POPCNTB | CPU_FTR_CFAR) #define CPU_FTRS_POWER7 (CPU_FTR_USE_TB | CPU_FTR_LWSYNC | \ CPU_FTR_PPCAS_ARCH_V2 | CPU_FTR_CTRL | CPU_FTR_HVMODE_206 |\ CPU_FTR_MMCRA | CPU_FTR_SMT | \ @@ -420,7 +421,7 @@ extern const char *powerpc_base_platform; CPU_FTR_PURR | CPU_FTR_SPURR | CPU_FTR_REAL_LE | \ CPU_FTR_DSCR | CPU_FTR_SAO | CPU_FTR_ASYM_SMT | \ CPU_FTR_STCX_CHECKS_ADDRESS | CPU_FTR_POPCNTB | CPU_FTR_POPCNTD | \ - CPU_FTR_ICSWX) + CPU_FTR_ICSWX | CPU_FTR_CFAR) #define CPU_FTRS_CELL (CPU_FTR_USE_TB | CPU_FTR_LWSYNC | \ CPU_FTR_PPCAS_ARCH_V2 | CPU_FTR_CTRL | \ CPU_FTR_ALTIVEC_COMP | CPU_FTR_MMCRA | CPU_FTR_SMT | \ diff --git a/arch/powerpc/include/asm/exception-64s.h b/arch/powerpc/include/asm/exception-64s.h index 96ccef1..f5dfe34 100644 --- a/arch/powerpc/include/asm/exception-64s.h +++ b/arch/powerpc/include/asm/exception-64s.h @@ -46,6 +46,7 @@ #define EX_CCR 60 #define EX_R3 64 #define EX_LR 72 +#define EX_CFAR 80 /* * We're short on space and time in the exception prolog, so we can't @@ -66,6 +67,10 @@ std r10,area+EX_R10(r13); \ std r11,area+EX_R11(r13); \ std r12,area+EX_R12(r13); \ + BEGIN_FTR_SECTION_NESTED(66); \ + mfspr r10,SPRN_CFAR; \ + std r10,area+EX_CFAR(r13); \ + END_FTR_SECTION_NESTED(CPU_FTR_CFAR, CPU_FTR_CFAR, 66); \ GET_SCRATCH0(r9); \ std r9,area+EX_R13(r13); \ mfcr r9 @@ -130,6 +135,10 @@ std r9,GPR11(r1); \ std r10,GPR12(r1); \ std r11,GPR13(r1); \ + BEGIN_FTR_SECTION_NESTED(66); \ + ld r10,area+EX_CFAR(r13); \ + std r10,ORIG_GPR3(r1); \ + END_FTR_SECTION_NESTED(CPU_FTR_CFAR, CPU_FTR_CFAR, 66); \ ld r2,PACATOC(r13); /* get kernel TOC into r2 */ \ mflr r9; /* save LR in stackframe */ \ std r9,_LINK(r1); \ diff --git a/arch/powerpc/include/asm/paca.h b/arch/powerpc/include/asm/paca.h index 65c13c4..7412676 100644 --- a/arch/powerpc/include/asm/paca.h +++ b/arch/powerpc/include/asm/paca.h @@ -92,9 +92,9 @@ struct paca_struct { * Now, starting in cacheline 2, the exception save areas */ /* used for most interrupts/exceptions */ - u64 exgen[10] __attribute__((aligned(0x80))); - u64 exmc[10]; /* used for machine checks */ - u64 exslb[10]; /* used for SLB/segment table misses + u64 exgen[11] __attribute__((aligned(0x80))); + u64 exmc[11]; /* used for machine checks */ + u64 exslb[11]; /* used for SLB/segment table misses * on the linear mapping */ /* SLB related definitions */ u16 vmalloc_sllp; diff --git a/arch/powerpc/include/asm/reg.h b/arch/powerpc/include/asm/reg.h index 632e78e..fdec593 100644 --- a/arch/powerpc/include/asm/reg.h +++ b/arch/powerpc/include/asm/reg.h @@ -188,6 +188,7 @@ #define SPRN_CTR 0x009 /* Count Register */ #define SPRN_DSCR 0x11 +#define SPRN_CFAR 0x1c /* Come From Address Register */ #define SPRN_ACOP 0x1F /* Available Coprocessor Register */ #define SPRN_CTRLF 0x088 #define SPRN_CTRLT 0x098 diff --git a/arch/powerpc/kernel/exceptions-64s.S b/arch/powerpc/kernel/exceptions-64s.S index 27ca8b7..0ec3b42 100644 --- a/arch/powerpc/kernel/exceptions-64s.S +++ b/arch/powerpc/kernel/exceptions-64s.S @@ -474,6 +474,10 @@ bad_stack: std r9,GPR11(r1) std r10,GPR12(r1) std r11,GPR13(r1) +BEGIN_FTR_SECTION + ld r10,EX_CFAR(r3) + std r10,ORIG_GPR3(r1) +END_FTR_SECTION_IFSET(CPU_FTR_CFAR) SAVE_8GPRS(14,r1) SAVE_10GPRS(22,r1) lhz r12,PACA_TRAP_SAVE(r13) diff --git a/arch/powerpc/xmon/xmon.c b/arch/powerpc/xmon/xmon.c index 60593ad..909804a 100644 --- a/arch/powerpc/xmon/xmon.c +++ b/arch/powerpc/xmon/xmon.c @@ -1497,6 +1497,10 @@ static void prregs(struct pt_regs *fp) #endif printf("pc = "); xmon_print_symbol(fp->nip, " ", "\n"); + if (TRAP(fp) != 0xc00 && cpu_has_feature(CPU_FTR_CFAR)) { + printf("cfar= "); + xmon_print_symbol(fp->orig_gpr3, " ", "\n"); + } printf("lr = "); xmon_print_symbol(fp->link, " ", "\n"); printf("msr = "REG" cr = %.8lx\n", fp->msr, fp->ccr); -- cgit v0.10.2 From 104699c0ab473535793b5fea156adaf309afd29b Mon Sep 17 00:00:00 2001 From: KOSAKI Motohiro Date: Thu, 28 Apr 2011 05:07:23 +0000 Subject: powerpc: Convert old cpumask API into new one Adapt new API. Almost change is trivial. Most important change is the below line because we plan to change task->cpus_allowed implementation. - ctx->cpus_allowed = current->cpus_allowed; Signed-off-by: KOSAKI Motohiro Signed-off-by: Benjamin Herrenschmidt diff --git a/arch/powerpc/include/asm/cputhreads.h b/arch/powerpc/include/asm/cputhreads.h index f71bb4c..ce516e5 100644 --- a/arch/powerpc/include/asm/cputhreads.h +++ b/arch/powerpc/include/asm/cputhreads.h @@ -37,16 +37,16 @@ extern cpumask_t threads_core_mask; * This can typically be used for things like IPI for tlb invalidations * since those need to be done only once per core/TLB */ -static inline cpumask_t cpu_thread_mask_to_cores(cpumask_t threads) +static inline cpumask_t cpu_thread_mask_to_cores(const struct cpumask *threads) { cpumask_t tmp, res; int i; - res = CPU_MASK_NONE; + cpumask_clear(&res); for (i = 0; i < NR_CPUS; i += threads_per_core) { - cpus_shift_left(tmp, threads_core_mask, i); - if (cpus_intersects(threads, tmp)) - cpu_set(i, res); + cpumask_shift_left(&tmp, &threads_core_mask, i); + if (cpumask_intersects(threads, &tmp)) + cpumask_set_cpu(i, &res); } return res; } @@ -58,7 +58,7 @@ static inline int cpu_nr_cores(void) static inline cpumask_t cpu_online_cores_map(void) { - return cpu_thread_mask_to_cores(cpu_online_map); + return cpu_thread_mask_to_cores(cpu_online_mask); } #ifdef CONFIG_SMP diff --git a/arch/powerpc/include/asm/kexec.h b/arch/powerpc/include/asm/kexec.h index f54408d..8a33698 100644 --- a/arch/powerpc/include/asm/kexec.h +++ b/arch/powerpc/include/asm/kexec.h @@ -76,7 +76,7 @@ extern void crash_send_ipi(void (*crash_ipi_callback)(struct pt_regs *)); extern cpumask_t cpus_in_sr; static inline int kexec_sr_activated(int cpu) { - return cpu_isset(cpu,cpus_in_sr); + return cpumask_test_cpu(cpu, &cpus_in_sr); } struct kimage; diff --git a/arch/powerpc/kernel/crash.c b/arch/powerpc/kernel/crash.c index 5b5e1f0..ccc2198 100644 --- a/arch/powerpc/kernel/crash.c +++ b/arch/powerpc/kernel/crash.c @@ -64,9 +64,9 @@ void crash_ipi_callback(struct pt_regs *regs) return; hard_irq_disable(); - if (!cpu_isset(cpu, cpus_in_crash)) + if (!cpumask_test_cpu(cpu, &cpus_in_crash)) crash_save_cpu(regs, cpu); - cpu_set(cpu, cpus_in_crash); + cpumask_set_cpu(cpu, &cpus_in_crash); /* * Entered via soft-reset - could be the kdump @@ -77,8 +77,8 @@ void crash_ipi_callback(struct pt_regs *regs) * Tell the kexec CPU that entered via soft-reset and ready * to go down. */ - if (cpu_isset(cpu, cpus_in_sr)) { - cpu_clear(cpu, cpus_in_sr); + if (cpumask_test_cpu(cpu, &cpus_in_sr)) { + cpumask_clear_cpu(cpu, &cpus_in_sr); atomic_inc(&enter_on_soft_reset); } @@ -87,7 +87,7 @@ void crash_ipi_callback(struct pt_regs *regs) * This barrier is needed to make sure that all CPUs are stopped. * If not, soft-reset will be invoked to bring other CPUs. */ - while (!cpu_isset(crashing_cpu, cpus_in_crash)) + while (!cpumask_test_cpu(crashing_cpu, &cpus_in_crash)) cpu_relax(); if (ppc_md.kexec_cpu_down) @@ -109,7 +109,7 @@ static void crash_soft_reset_check(int cpu) { unsigned int ncpus = num_online_cpus() - 1;/* Excluding the panic cpu */ - cpu_clear(cpu, cpus_in_sr); + cpumask_clear_cpu(cpu, &cpus_in_sr); while (atomic_read(&enter_on_soft_reset) != ncpus) cpu_relax(); } @@ -132,7 +132,7 @@ static void crash_kexec_prepare_cpus(int cpu) */ printk(KERN_EMERG "Sending IPI to other cpus...\n"); msecs = 10000; - while ((cpus_weight(cpus_in_crash) < ncpus) && (--msecs > 0)) { + while ((cpumask_weight(&cpus_in_crash) < ncpus) && (--msecs > 0)) { cpu_relax(); mdelay(1); } @@ -144,20 +144,20 @@ static void crash_kexec_prepare_cpus(int cpu) * user to do soft reset such that we get all. * Soft-reset will be used until better mechanism is implemented. */ - if (cpus_weight(cpus_in_crash) < ncpus) { + if (cpumask_weight(&cpus_in_crash) < ncpus) { printk(KERN_EMERG "done waiting: %d cpu(s) not responding\n", - ncpus - cpus_weight(cpus_in_crash)); + ncpus - cpumask_weight(&cpus_in_crash)); printk(KERN_EMERG "Activate soft-reset to stop other cpu(s)\n"); - cpus_in_sr = CPU_MASK_NONE; + cpumask_clear(&cpus_in_sr); atomic_set(&enter_on_soft_reset, 0); - while (cpus_weight(cpus_in_crash) < ncpus) + while (cpumask_weight(&cpus_in_crash) < ncpus) cpu_relax(); } /* * Make sure all CPUs are entered via soft-reset if the kdump is * invoked using soft-reset. */ - if (cpu_isset(cpu, cpus_in_sr)) + if (cpumask_test_cpu(cpu, &cpus_in_sr)) crash_soft_reset_check(cpu); /* Leave the IPI callback set */ } @@ -210,7 +210,7 @@ void crash_kexec_secondary(struct pt_regs *regs) * exited using 'x'(exit and recover) or * kexec_should_crash() failed for all running tasks. */ - cpu_clear(cpu, cpus_in_sr); + cpumask_clear_cpu(cpu, &cpus_in_sr); local_irq_restore(flags); return; } @@ -224,7 +224,7 @@ void crash_kexec_secondary(struct pt_regs *regs) * then start kexec boot. */ crash_soft_reset_check(cpu); - cpu_set(crashing_cpu, cpus_in_crash); + cpumask_set_cpu(crashing_cpu, &cpus_in_crash); if (ppc_md.kexec_cpu_down) ppc_md.kexec_cpu_down(1, 0); machine_kexec(kexec_crash_image); @@ -253,7 +253,7 @@ static void crash_kexec_prepare_cpus(int cpu) void crash_kexec_secondary(struct pt_regs *regs) { - cpus_in_sr = CPU_MASK_NONE; + cpumask_clear(&cpus_in_sr); } #endif /* CONFIG_SMP */ @@ -345,7 +345,7 @@ void default_machine_crash_shutdown(struct pt_regs *regs) crashing_cpu = smp_processor_id(); crash_save_cpu(regs, crashing_cpu); crash_kexec_prepare_cpus(crashing_cpu); - cpu_set(crashing_cpu, cpus_in_crash); + cpumask_set_cpu(crashing_cpu, &cpus_in_crash); crash_kexec_wait_realmode(crashing_cpu); machine_kexec_mask_interrupts(); diff --git a/arch/powerpc/kernel/setup-common.c b/arch/powerpc/kernel/setup-common.c index 21f30cb..1475df6 100644 --- a/arch/powerpc/kernel/setup-common.c +++ b/arch/powerpc/kernel/setup-common.c @@ -381,7 +381,7 @@ static void __init cpu_init_thread_core_maps(int tpc) int i; threads_per_core = tpc; - threads_core_mask = CPU_MASK_NONE; + cpumask_clear(&threads_core_mask); /* This implementation only supports power of 2 number of threads * for simplicity and performance @@ -390,7 +390,7 @@ static void __init cpu_init_thread_core_maps(int tpc) BUG_ON(tpc != (1 << threads_shift)); for (i = 0; i < tpc; i++) - cpu_set(i, threads_core_mask); + cpumask_set_cpu(i, &threads_core_mask); printk(KERN_INFO "CPU maps initialized for %d thread%s per core\n", tpc, tpc > 1 ? "s" : ""); diff --git a/arch/powerpc/kernel/smp.c b/arch/powerpc/kernel/smp.c index b6083f4..87517ab 100644 --- a/arch/powerpc/kernel/smp.c +++ b/arch/powerpc/kernel/smp.c @@ -513,7 +513,7 @@ int cpu_first_thread_of_core(int core) } EXPORT_SYMBOL_GPL(cpu_first_thread_of_core); -/* Must be called when no change can occur to cpu_present_map, +/* Must be called when no change can occur to cpu_present_mask, * i.e. during cpu online or offline. */ static struct device_node *cpu_to_l2cache(int cpu) @@ -614,7 +614,7 @@ void __init smp_cpus_done(unsigned int max_cpus) * se we pin us down to CPU 0 for a short while */ alloc_cpumask_var(&old_mask, GFP_NOWAIT); - cpumask_copy(old_mask, ¤t->cpus_allowed); + cpumask_copy(old_mask, tsk_cpus_allowed(current)); set_cpus_allowed_ptr(current, cpumask_of(boot_cpuid)); if (smp_ops && smp_ops->setup_cpu) diff --git a/arch/powerpc/kernel/traps.c b/arch/powerpc/kernel/traps.c index 4a6a109..06b9d45 100644 --- a/arch/powerpc/kernel/traps.c +++ b/arch/powerpc/kernel/traps.c @@ -221,7 +221,7 @@ void system_reset_exception(struct pt_regs *regs) } #ifdef CONFIG_KEXEC - cpu_set(smp_processor_id(), cpus_in_sr); + cpumask_set_cpu(smp_processor_id(), &cpus_in_sr); #endif die("System Reset", regs, SIGABRT); diff --git a/arch/powerpc/mm/numa.c b/arch/powerpc/mm/numa.c index e49b799..2164006 100644 --- a/arch/powerpc/mm/numa.c +++ b/arch/powerpc/mm/numa.c @@ -1452,7 +1452,7 @@ int arch_update_cpu_topology(void) unsigned int associativity[VPHN_ASSOC_BUFSIZE] = {0}; struct sys_device *sysdev; - for_each_cpu_mask(cpu, cpu_associativity_changes_mask) { + for_each_cpu(cpu,&cpu_associativity_changes_mask) { vphn_get_associativity(cpu, associativity); nid = associativity_to_nid(associativity); diff --git a/arch/powerpc/platforms/cell/beat_smp.c b/arch/powerpc/platforms/cell/beat_smp.c index 996df33..3e86acb 100644 --- a/arch/powerpc/platforms/cell/beat_smp.c +++ b/arch/powerpc/platforms/cell/beat_smp.c @@ -85,7 +85,7 @@ static void smp_beatic_message_pass(int target, int msg) static int __init smp_beatic_probe(void) { - return cpus_weight(cpu_possible_map); + return cpumask_weight(cpu_possible_mask); } static void __devinit smp_beatic_setup_cpu(int cpu) diff --git a/arch/powerpc/platforms/cell/cbe_regs.c b/arch/powerpc/platforms/cell/cbe_regs.c index dbc338f..f3917e7 100644 --- a/arch/powerpc/platforms/cell/cbe_regs.c +++ b/arch/powerpc/platforms/cell/cbe_regs.c @@ -45,8 +45,8 @@ static struct cbe_thread_map unsigned int cbe_id; } cbe_thread_map[NR_CPUS]; -static cpumask_t cbe_local_mask[MAX_CBE] = { [0 ... MAX_CBE-1] = CPU_MASK_NONE }; -static cpumask_t cbe_first_online_cpu = CPU_MASK_NONE; +static cpumask_t cbe_local_mask[MAX_CBE] = { [0 ... MAX_CBE-1] = {CPU_BITS_NONE} }; +static cpumask_t cbe_first_online_cpu = { CPU_BITS_NONE }; static struct cbe_regs_map *cbe_find_map(struct device_node *np) { @@ -159,7 +159,8 @@ EXPORT_SYMBOL_GPL(cbe_cpu_to_node); u32 cbe_node_to_cpu(int node) { - return find_first_bit( (unsigned long *) &cbe_local_mask[node], sizeof(cpumask_t)); + return cpumask_first(&cbe_local_mask[node]); + } EXPORT_SYMBOL_GPL(cbe_node_to_cpu); @@ -268,9 +269,9 @@ void __init cbe_regs_init(void) thread->regs = map; thread->cbe_id = cbe_id; map->be_node = thread->be_node; - cpu_set(i, cbe_local_mask[cbe_id]); + cpumask_set_cpu(i, &cbe_local_mask[cbe_id]); if(thread->thread_id == 0) - cpu_set(i, cbe_first_online_cpu); + cpumask_set_cpu(i, &cbe_first_online_cpu); } } diff --git a/arch/powerpc/platforms/cell/smp.c b/arch/powerpc/platforms/cell/smp.c index 03d638e..a2161b9 100644 --- a/arch/powerpc/platforms/cell/smp.c +++ b/arch/powerpc/platforms/cell/smp.c @@ -77,7 +77,7 @@ static inline int __devinit smp_startup_cpu(unsigned int lcpu) unsigned int pcpu; int start_cpu; - if (cpu_isset(lcpu, of_spin_map)) + if (cpumask_test_cpu(lcpu, &of_spin_map)) /* Already started by OF and sitting in spin loop */ return 1; @@ -123,7 +123,7 @@ static int __init smp_iic_probe(void) { iic_request_IPIs(); - return cpus_weight(cpu_possible_map); + return cpumask_weight(cpu_possible_mask); } static void __devinit smp_cell_setup_cpu(int cpu) @@ -188,13 +188,12 @@ void __init smp_init_cell(void) if (cpu_has_feature(CPU_FTR_SMT)) { for_each_present_cpu(i) { if (cpu_thread_in_core(i) == 0) - cpu_set(i, of_spin_map); + cpumask_set_cpu(i, &of_spin_map); } - } else { - of_spin_map = cpu_present_map; - } + } else + cpumask_copy(&of_spin_map, cpu_present_mask); - cpu_clear(boot_cpuid, of_spin_map); + cpumask_clear_cpu(boot_cpuid, &of_spin_map); /* Non-lpar has additional take/give timebase */ if (rtas_token("freeze-time-base") != RTAS_UNKNOWN_SERVICE) { diff --git a/arch/powerpc/platforms/cell/spufs/sched.c b/arch/powerpc/platforms/cell/spufs/sched.c index 6520385..32cb4e6 100644 --- a/arch/powerpc/platforms/cell/spufs/sched.c +++ b/arch/powerpc/platforms/cell/spufs/sched.c @@ -141,7 +141,7 @@ void __spu_update_sched_info(struct spu_context *ctx) * runqueue. The context will be rescheduled on the proper node * if it is timesliced or preempted. */ - ctx->cpus_allowed = current->cpus_allowed; + cpumask_copy(&ctx->cpus_allowed, tsk_cpus_allowed(current)); /* Save the current cpu id for spu interrupt routing. */ ctx->last_ran = raw_smp_processor_id(); diff --git a/arch/powerpc/platforms/pseries/hotplug-cpu.c b/arch/powerpc/platforms/pseries/hotplug-cpu.c index ae6c27d..46f13a3 100644 --- a/arch/powerpc/platforms/pseries/hotplug-cpu.c +++ b/arch/powerpc/platforms/pseries/hotplug-cpu.c @@ -281,7 +281,7 @@ static int pseries_add_processor(struct device_node *np) } for_each_cpu(cpu, tmp) { - BUG_ON(cpumask_test_cpu(cpu, cpu_present_mask)); + BUG_ON(cpu_present(cpu)); set_cpu_present(cpu, true); set_hard_smp_processor_id(cpu, *intserv++); } diff --git a/arch/powerpc/xmon/xmon.c b/arch/powerpc/xmon/xmon.c index 909804a..91309c5 100644 --- a/arch/powerpc/xmon/xmon.c +++ b/arch/powerpc/xmon/xmon.c @@ -334,7 +334,7 @@ static void release_output_lock(void) int cpus_are_in_xmon(void) { - return !cpus_empty(cpus_in_xmon); + return !cpumask_empty(&cpus_in_xmon); } #endif @@ -373,7 +373,7 @@ static int xmon_core(struct pt_regs *regs, int fromipi) #ifdef CONFIG_SMP cpu = smp_processor_id(); - if (cpu_isset(cpu, cpus_in_xmon)) { + if (cpumask_test_cpu(cpu, &cpus_in_xmon)) { get_output_lock(); excprint(regs); printf("cpu 0x%x: Exception %lx %s in xmon, " @@ -396,7 +396,7 @@ static int xmon_core(struct pt_regs *regs, int fromipi) } xmon_fault_jmp[cpu] = recurse_jmp; - cpu_set(cpu, cpus_in_xmon); + cpumask_set_cpu(cpu, &cpus_in_xmon); bp = NULL; if ((regs->msr & (MSR_IR|MSR_PR|MSR_64BIT)) == (MSR_IR|MSR_64BIT)) @@ -440,7 +440,7 @@ static int xmon_core(struct pt_regs *regs, int fromipi) smp_send_debugger_break(MSG_ALL_BUT_SELF); /* wait for other cpus to come in */ for (timeout = 100000000; timeout != 0; --timeout) { - if (cpus_weight(cpus_in_xmon) >= ncpus) + if (cpumask_weight(&cpus_in_xmon) >= ncpus) break; barrier(); } @@ -484,7 +484,7 @@ static int xmon_core(struct pt_regs *regs, int fromipi) } } leave: - cpu_clear(cpu, cpus_in_xmon); + cpumask_clear_cpu(cpu, &cpus_in_xmon); xmon_fault_jmp[cpu] = NULL; #else /* UP is simple... */ @@ -630,7 +630,7 @@ static int xmon_iabr_match(struct pt_regs *regs) static int xmon_ipi(struct pt_regs *regs) { #ifdef CONFIG_SMP - if (in_xmon && !cpu_isset(smp_processor_id(), cpus_in_xmon)) + if (in_xmon && !cpumask_test_cpu(smp_processor_id(), &cpus_in_xmon)) xmon_core(regs, 1); #endif return 0; @@ -976,7 +976,7 @@ static int cpu_cmd(void) printf("cpus stopped:"); count = 0; for (cpu = 0; cpu < NR_CPUS; ++cpu) { - if (cpu_isset(cpu, cpus_in_xmon)) { + if (cpumask_test_cpu(cpu, &cpus_in_xmon)) { if (count == 0) printf(" %x", cpu); ++count; @@ -992,7 +992,7 @@ static int cpu_cmd(void) return 0; } /* try to switch to cpu specified */ - if (!cpu_isset(cpu, cpus_in_xmon)) { + if (!cpumask_test_cpu(cpu, &cpus_in_xmon)) { printf("cpu 0x%x isn't in xmon\n", cpu); return 0; } -- cgit v0.10.2 From 7707e4110e5692fe85e7e6c471c9bb2a9254d313 Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Sun, 24 Apr 2011 15:04:31 +0000 Subject: powerpc/kexec: Fix build failure on 32-bit SMP Commit b987812b3fcaf70fdf0037589e5d2f5f2453e6ce left crash_kexec_wait_realmode() undefined for UP. Commit 7c7a81b53e581d727d069cc45df5510516faac31 defined it for UP but left it undefined for 32-bit SMP. Seems like people are getting confused by nested #ifdef's, so move the definitions of crash_kexec_wait_realmode() after the #ifdef CONFIG_SMP section. Compile-tested with 32-bit UP, 32-bit SMP and 64-bit SMP configurations. Signed-off-by: Ben Hutchings Tested-by: Paul Gortmaker Signed-off-by: Benjamin Herrenschmidt diff --git a/arch/powerpc/kernel/crash.c b/arch/powerpc/kernel/crash.c index ccc2198..21f2c78 100644 --- a/arch/powerpc/kernel/crash.c +++ b/arch/powerpc/kernel/crash.c @@ -162,34 +162,6 @@ static void crash_kexec_prepare_cpus(int cpu) /* Leave the IPI callback set */ } -/* wait for all the CPUs to hit real mode but timeout if they don't come in */ -#ifdef CONFIG_PPC_STD_MMU_64 -static void crash_kexec_wait_realmode(int cpu) -{ - unsigned int msecs; - int i; - - msecs = 10000; - for (i=0; i < NR_CPUS && msecs > 0; i++) { - if (i == cpu) - continue; - - while (paca[i].kexec_state < KEXEC_STATE_REAL_MODE) { - barrier(); - if (!cpu_possible(i)) { - break; - } - if (!cpu_online(i)) { - break; - } - msecs--; - mdelay(1); - } - } - mb(); -} -#endif /* CONFIG_PPC_STD_MMU_64 */ - /* * This function will be called by secondary cpus or by kexec cpu * if soft-reset is activated to stop some CPUs. @@ -234,7 +206,6 @@ void crash_kexec_secondary(struct pt_regs *regs) } #else /* ! CONFIG_SMP */ -static inline void crash_kexec_wait_realmode(int cpu) {} static void crash_kexec_prepare_cpus(int cpu) { @@ -257,6 +228,36 @@ void crash_kexec_secondary(struct pt_regs *regs) } #endif /* CONFIG_SMP */ +/* wait for all the CPUs to hit real mode but timeout if they don't come in */ +#if defined(CONFIG_SMP) && defined(CONFIG_PPC_STD_MMU_64) +static void crash_kexec_wait_realmode(int cpu) +{ + unsigned int msecs; + int i; + + msecs = 10000; + for (i=0; i < NR_CPUS && msecs > 0; i++) { + if (i == cpu) + continue; + + while (paca[i].kexec_state < KEXEC_STATE_REAL_MODE) { + barrier(); + if (!cpu_possible(i)) { + break; + } + if (!cpu_online(i)) { + break; + } + msecs--; + mdelay(1); + } + } + mb(); +} +#else +static inline void crash_kexec_wait_realmode(int cpu) {} +#endif /* CONFIG_SMP && CONFIG_PPC_STD_MMU_64 */ + /* * Register a function to be called on shutdown. Only use this if you * can't reset your device in the second kernel. -- cgit v0.10.2 From 9ee820fa005254dfc816330f6654f14dcb2beee1 Mon Sep 17 00:00:00 2001 From: Brian King Date: Wed, 4 May 2011 16:01:20 +1000 Subject: powerpc/pseries: Add page coalescing support Adds support for page coalescing, which is a feature on IBM Power servers which allows for coalescing identical pages between logical partitions. Hint text pages as coalesce candidates, since they are the most likely pages to be able to be coalesced between partitions. This patch also exports some page coalescing statistics available from firmware via lparcfg. [BenH: Moved a couple of things around to fix compile problems] Signed-off-by: Brian King Signed-off-by: Benjamin Herrenschmidt diff --git a/arch/powerpc/include/asm/firmware.h b/arch/powerpc/include/asm/firmware.h index 4ef662e..3a6c586 100644 --- a/arch/powerpc/include/asm/firmware.h +++ b/arch/powerpc/include/asm/firmware.h @@ -47,6 +47,7 @@ #define FW_FEATURE_BEAT ASM_CONST(0x0000000001000000) #define FW_FEATURE_CMO ASM_CONST(0x0000000002000000) #define FW_FEATURE_VPHN ASM_CONST(0x0000000004000000) +#define FW_FEATURE_XCMO ASM_CONST(0x0000000008000000) #ifndef __ASSEMBLY__ @@ -60,7 +61,7 @@ enum { FW_FEATURE_VIO | FW_FEATURE_RDMA | FW_FEATURE_LLAN | FW_FEATURE_BULK_REMOVE | FW_FEATURE_XDABR | FW_FEATURE_MULTITCE | FW_FEATURE_SPLPAR | FW_FEATURE_LPAR | - FW_FEATURE_CMO | FW_FEATURE_VPHN, + FW_FEATURE_CMO | FW_FEATURE_VPHN | FW_FEATURE_XCMO, FW_FEATURE_PSERIES_ALWAYS = 0, FW_FEATURE_ISERIES_POSSIBLE = FW_FEATURE_ISERIES | FW_FEATURE_LPAR, FW_FEATURE_ISERIES_ALWAYS = FW_FEATURE_ISERIES | FW_FEATURE_LPAR, diff --git a/arch/powerpc/include/asm/hvcall.h b/arch/powerpc/include/asm/hvcall.h index 8edec71..852b8c1 100644 --- a/arch/powerpc/include/asm/hvcall.h +++ b/arch/powerpc/include/asm/hvcall.h @@ -102,6 +102,7 @@ #define H_ANDCOND (1UL<<(63-33)) #define H_ICACHE_INVALIDATE (1UL<<(63-40)) /* icbi, etc. (ignored for IO pages) */ #define H_ICACHE_SYNCHRONIZE (1UL<<(63-41)) /* dcbst, icbi, etc (ignored for IO pages */ +#define H_COALESCE_CAND (1UL<<(63-42)) /* page is a good candidate for coalescing */ #define H_ZERO_PAGE (1UL<<(63-48)) /* zero the page before mapping (ignored for IO pages) */ #define H_COPY_PAGE (1UL<<(63-49)) #define H_N (1UL<<(63-61)) @@ -234,6 +235,7 @@ #define H_GET_MPP 0x2D4 #define H_HOME_NODE_ASSOCIATIVITY 0x2EC #define H_BEST_ENERGY 0x2F4 +#define H_GET_MPP_X 0x314 #define MAX_HCALL_OPCODE H_BEST_ENERGY #ifndef __ASSEMBLY__ @@ -312,6 +314,16 @@ struct hvcall_mpp_data { int h_get_mpp(struct hvcall_mpp_data *); +struct hvcall_mpp_x_data { + unsigned long coalesced_bytes; + unsigned long pool_coalesced_bytes; + unsigned long pool_purr_cycles; + unsigned long pool_spurr_cycles; + unsigned long reserved[3]; +}; + +int h_get_mpp_x(struct hvcall_mpp_x_data *mpp_x_data); + #ifdef CONFIG_PPC_PSERIES extern int CMO_PrPSP; extern int CMO_SecPSP; diff --git a/arch/powerpc/include/asm/pSeries_reconfig.h b/arch/powerpc/include/asm/pSeries_reconfig.h index d4b4bfa..89d2f99 100644 --- a/arch/powerpc/include/asm/pSeries_reconfig.h +++ b/arch/powerpc/include/asm/pSeries_reconfig.h @@ -18,13 +18,18 @@ extern int pSeries_reconfig_notifier_register(struct notifier_block *); extern void pSeries_reconfig_notifier_unregister(struct notifier_block *); extern struct blocking_notifier_head pSeries_reconfig_chain; +/* Not the best place to put this, will be fixed when we move some + * of the rtas suspend-me stuff to pseries */ +extern void pSeries_coalesce_init(void); #else /* !CONFIG_PPC_PSERIES */ static inline int pSeries_reconfig_notifier_register(struct notifier_block *nb) { return 0; } static inline void pSeries_reconfig_notifier_unregister(struct notifier_block *nb) { } +static inline void pSeries_coalesce_init(void) { } #endif /* CONFIG_PPC_PSERIES */ + #endif /* __KERNEL__ */ #endif /* _PPC64_PSERIES_RECONFIG_H */ diff --git a/arch/powerpc/kernel/lparcfg.c b/arch/powerpc/kernel/lparcfg.c index 301db65..84daabe 100644 --- a/arch/powerpc/kernel/lparcfg.c +++ b/arch/powerpc/kernel/lparcfg.c @@ -132,34 +132,6 @@ static int iseries_lparcfg_data(struct seq_file *m, void *v) /* * Methods used to fetch LPAR data when running on a pSeries platform. */ -/** - * h_get_mpp - * H_GET_MPP hcall returns info in 7 parms - */ -int h_get_mpp(struct hvcall_mpp_data *mpp_data) -{ - int rc; - unsigned long retbuf[PLPAR_HCALL9_BUFSIZE]; - - rc = plpar_hcall9(H_GET_MPP, retbuf); - - mpp_data->entitled_mem = retbuf[0]; - mpp_data->mapped_mem = retbuf[1]; - - mpp_data->group_num = (retbuf[2] >> 2 * 8) & 0xffff; - mpp_data->pool_num = retbuf[2] & 0xffff; - - mpp_data->mem_weight = (retbuf[3] >> 7 * 8) & 0xff; - mpp_data->unallocated_mem_weight = (retbuf[3] >> 6 * 8) & 0xff; - mpp_data->unallocated_entitlement = retbuf[3] & 0xffffffffffff; - - mpp_data->pool_size = retbuf[4]; - mpp_data->loan_request = retbuf[5]; - mpp_data->backing_mem = retbuf[6]; - - return rc; -} -EXPORT_SYMBOL(h_get_mpp); struct hvcall_ppp_data { u64 entitlement; @@ -345,6 +317,30 @@ static void parse_mpp_data(struct seq_file *m) seq_printf(m, "backing_memory=%ld bytes\n", mpp_data.backing_mem); } +/** + * parse_mpp_x_data + * Parse out data returned from h_get_mpp_x + */ +static void parse_mpp_x_data(struct seq_file *m) +{ + struct hvcall_mpp_x_data mpp_x_data; + + if (!firmware_has_feature(FW_FEATURE_XCMO)) + return; + if (h_get_mpp_x(&mpp_x_data)) + return; + + seq_printf(m, "coalesced_bytes=%ld\n", mpp_x_data.coalesced_bytes); + + if (mpp_x_data.pool_coalesced_bytes) + seq_printf(m, "pool_coalesced_bytes=%ld\n", + mpp_x_data.pool_coalesced_bytes); + if (mpp_x_data.pool_purr_cycles) + seq_printf(m, "coalesce_pool_purr=%ld\n", mpp_x_data.pool_purr_cycles); + if (mpp_x_data.pool_spurr_cycles) + seq_printf(m, "coalesce_pool_spurr=%ld\n", mpp_x_data.pool_spurr_cycles); +} + #define SPLPAR_CHARACTERISTICS_TOKEN 20 #define SPLPAR_MAXLENGTH 1026*(sizeof(char)) @@ -520,6 +516,7 @@ static int pseries_lparcfg_data(struct seq_file *m, void *v) parse_system_parameter_string(m); parse_ppp_data(m); parse_mpp_data(m); + parse_mpp_x_data(m); pseries_cmo_data(m); splpar_dispatch_data(m); diff --git a/arch/powerpc/kernel/prom_init.c b/arch/powerpc/kernel/prom_init.c index 7839bd7..c016033 100644 --- a/arch/powerpc/kernel/prom_init.c +++ b/arch/powerpc/kernel/prom_init.c @@ -700,8 +700,10 @@ static void __init early_cmdline_parse(void) #endif /* CONFIG_PCI_MSI */ #ifdef CONFIG_PPC_SMLPAR #define OV5_CMO 0x80 /* Cooperative Memory Overcommitment */ +#define OV5_XCMO 0x40 /* Page Coalescing */ #else #define OV5_CMO 0x00 +#define OV5_XCMO 0x00 #endif #define OV5_TYPE1_AFFINITY 0x80 /* Type 1 NUMA affinity */ @@ -756,7 +758,7 @@ static unsigned char ibm_architecture_vec[] = { OV5_LPAR | OV5_SPLPAR | OV5_LARGE_PAGES | OV5_DRCONF_MEMORY | OV5_DONATE_DEDICATE_CPU | OV5_MSI, 0, - OV5_CMO, + OV5_CMO | OV5_XCMO, OV5_TYPE1_AFFINITY, 0, 0, diff --git a/arch/powerpc/kernel/rtas.c b/arch/powerpc/kernel/rtas.c index f484466..271ff63 100644 --- a/arch/powerpc/kernel/rtas.c +++ b/arch/powerpc/kernel/rtas.c @@ -42,6 +42,7 @@ #include #include #include +#include struct rtas_t rtas = { .lock = __ARCH_SPIN_LOCK_UNLOCKED @@ -731,6 +732,7 @@ static int __rtas_suspend_last_cpu(struct rtas_suspend_me_data *data, int wake_w atomic_set(&data->error, rc); start_topology_update(); + pSeries_coalesce_init(); if (wake_when_done) { atomic_set(&data->done, 1); diff --git a/arch/powerpc/platforms/pseries/lpar.c b/arch/powerpc/platforms/pseries/lpar.c index 6f0ed3a..39e6e0a 100644 --- a/arch/powerpc/platforms/pseries/lpar.c +++ b/arch/powerpc/platforms/pseries/lpar.c @@ -329,6 +329,8 @@ static long pSeries_lpar_hpte_insert(unsigned long hpte_group, /* Make pHyp happy */ if ((rflags & _PAGE_NO_CACHE) & !(rflags & _PAGE_WRITETHRU)) hpte_r &= ~_PAGE_COHERENT; + if (firmware_has_feature(FW_FEATURE_XCMO) && !(hpte_r & HPTE_R_N)) + flags |= H_COALESCE_CAND; lpar_rc = plpar_pte_enter(flags, hpte_group, hpte_v, hpte_r, &slot); if (unlikely(lpar_rc == H_PTEG_FULL)) { @@ -771,3 +773,47 @@ out: local_irq_restore(flags); } #endif + +/** + * h_get_mpp + * H_GET_MPP hcall returns info in 7 parms + */ +int h_get_mpp(struct hvcall_mpp_data *mpp_data) +{ + int rc; + unsigned long retbuf[PLPAR_HCALL9_BUFSIZE]; + + rc = plpar_hcall9(H_GET_MPP, retbuf); + + mpp_data->entitled_mem = retbuf[0]; + mpp_data->mapped_mem = retbuf[1]; + + mpp_data->group_num = (retbuf[2] >> 2 * 8) & 0xffff; + mpp_data->pool_num = retbuf[2] & 0xffff; + + mpp_data->mem_weight = (retbuf[3] >> 7 * 8) & 0xff; + mpp_data->unallocated_mem_weight = (retbuf[3] >> 6 * 8) & 0xff; + mpp_data->unallocated_entitlement = retbuf[3] & 0xffffffffffff; + + mpp_data->pool_size = retbuf[4]; + mpp_data->loan_request = retbuf[5]; + mpp_data->backing_mem = retbuf[6]; + + return rc; +} +EXPORT_SYMBOL(h_get_mpp); + +int h_get_mpp_x(struct hvcall_mpp_x_data *mpp_x_data) +{ + int rc; + unsigned long retbuf[PLPAR_HCALL9_BUFSIZE] = { 0 }; + + rc = plpar_hcall9(H_GET_MPP_X, retbuf); + + mpp_x_data->coalesced_bytes = retbuf[0]; + mpp_x_data->pool_coalesced_bytes = retbuf[1]; + mpp_x_data->pool_purr_cycles = retbuf[2]; + mpp_x_data->pool_spurr_cycles = retbuf[3]; + + return rc; +} diff --git a/arch/powerpc/platforms/pseries/setup.c b/arch/powerpc/platforms/pseries/setup.c index ab73ad2..1689adc 100644 --- a/arch/powerpc/platforms/pseries/setup.c +++ b/arch/powerpc/platforms/pseries/setup.c @@ -405,6 +405,16 @@ static int pseries_set_xdabr(unsigned long dabr) #define CMO_CHARACTERISTICS_TOKEN 44 #define CMO_MAXLENGTH 1026 +void pSeries_coalesce_init(void) +{ + struct hvcall_mpp_x_data mpp_x_data; + + if (firmware_has_feature(FW_FEATURE_CMO) && !h_get_mpp_x(&mpp_x_data)) + powerpc_firmware_features |= FW_FEATURE_XCMO; + else + powerpc_firmware_features &= ~FW_FEATURE_XCMO; +} + /** * fw_cmo_feature_init - FW_FEATURE_CMO is not stored in ibm,hypertas-functions, * handle that here. (Stolen from parse_system_parameter_string) @@ -474,6 +484,7 @@ void pSeries_cmo_feature_init(void) pr_debug("CMO enabled, PrPSP=%d, SecPSP=%d\n", CMO_PrPSP, CMO_SecPSP); powerpc_firmware_features |= FW_FEATURE_CMO; + pSeries_coalesce_init(); } else pr_debug("CMO not enabled, PrPSP=%d, SecPSP=%d\n", CMO_PrPSP, CMO_SecPSP); -- cgit v0.10.2 From 308fc4f8e10b5239cde46104bb9fca79b46230c8 Mon Sep 17 00:00:00 2001 From: Richard A Lary Date: Fri, 22 Apr 2011 09:59:47 +0000 Subject: powerpc/pseries/eeh: Propagate needs_freset flag to device at PE For multifunction adapters with a PCI bridge or switch as the device at the Partitionable Endpoint(PE), if one or more devices below PE sets dev->needs_freset, that value will be set for the PE device. In other words, if any device below PE requires a fundamental reset the PE will request a fundamental reset. Signed-off-by: Richard A Lary Signed-off-by: Benjamin Herrenschmidt diff --git a/arch/powerpc/platforms/pseries/eeh.c b/arch/powerpc/platforms/pseries/eeh.c index 22937305..6cb3e7bd 100644 --- a/arch/powerpc/platforms/pseries/eeh.c +++ b/arch/powerpc/platforms/pseries/eeh.c @@ -451,6 +451,39 @@ void eeh_clear_slot (struct device_node *dn, int mode_flag) raw_spin_unlock_irqrestore(&confirm_error_lock, flags); } +void __eeh_set_pe_freset(struct device_node *parent, unsigned int *freset) +{ + struct device_node *dn; + + for_each_child_of_node(parent, dn) { + if (PCI_DN(dn)) { + + struct pci_dev *dev = PCI_DN(dn)->pcidev; + + if (dev && dev->driver) + *freset |= dev->needs_freset; + + __eeh_set_pe_freset(dn, freset); + } + } +} + +void eeh_set_pe_freset(struct device_node *dn, unsigned int *freset) +{ + struct pci_dev *dev; + dn = find_device_pe(dn); + + /* Back up one, since config addrs might be shared */ + if (!pcibios_find_pci_bus(dn) && PCI_DN(dn->parent)) + dn = dn->parent; + + dev = PCI_DN(dn)->pcidev; + if (dev) + *freset |= dev->needs_freset; + + __eeh_set_pe_freset(dn, freset); +} + /** * eeh_dn_check_failure - check if all 1's data is due to EEH slot freeze * @dn device node @@ -739,18 +772,21 @@ int pcibios_set_pcie_reset_state(struct pci_dev *dev, enum pcie_reset_state stat /** * rtas_set_slot_reset -- assert the pci #RST line for 1/4 second * @pdn: pci device node to be reset. - * - * Return 0 if success, else a non-zero value. */ static void __rtas_set_slot_reset(struct pci_dn *pdn) { - struct pci_dev *dev = pdn->pcidev; + unsigned int freset = 0; - /* Determine type of EEH reset required by device, - * default hot reset or fundamental reset - */ - if (dev && dev->needs_freset) + /* Determine type of EEH reset required for + * Partitionable Endpoint, a hot-reset (1) + * or a fundamental reset (3). + * A fundamental reset required by any device under + * Partitionable Endpoint trumps hot-reset. + */ + eeh_set_pe_freset(pdn->node, &freset); + + if (freset) rtas_pci_slot_reset(pdn, 3); else rtas_pci_slot_reset(pdn, 1); -- cgit v0.10.2 From ecb7390211fe9cb14ff0bae116a3f4f1149c0b6c Mon Sep 17 00:00:00 2001 From: Richard A Lary Date: Fri, 22 Apr 2011 10:00:05 +0000 Subject: powerpc/pseries/eeh: Handle functional reset on non-PCIe device Fundamental reset is an optional reset type supported only by PCIe adapters. Handle the unexpected case where a non-PCIe device has requested a fundamental reset. Try hot-reset as a fallback to handle this case. Signed-off-by: Richard A Lary Signed-off-by: Benjamin Herrenschmidt diff --git a/arch/powerpc/platforms/pseries/eeh.c b/arch/powerpc/platforms/pseries/eeh.c index 6cb3e7bd..46b55cf 100644 --- a/arch/powerpc/platforms/pseries/eeh.c +++ b/arch/powerpc/platforms/pseries/eeh.c @@ -728,15 +728,24 @@ rtas_pci_slot_reset(struct pci_dn *pdn, int state) if (pdn->eeh_pe_config_addr) config_addr = pdn->eeh_pe_config_addr; - rc = rtas_call(ibm_set_slot_reset,4,1, NULL, + rc = rtas_call(ibm_set_slot_reset, 4, 1, NULL, config_addr, BUID_HI(pdn->phb->buid), BUID_LO(pdn->phb->buid), state); - if (rc) - printk (KERN_WARNING "EEH: Unable to reset the failed slot," - " (%d) #RST=%d dn=%s\n", - rc, state, pdn->node->full_name); + + /* Fundamental-reset not supported on this PE, try hot-reset */ + if (rc == -8 && state == 3) { + rc = rtas_call(ibm_set_slot_reset, 4, 1, NULL, + config_addr, + BUID_HI(pdn->phb->buid), + BUID_LO(pdn->phb->buid), 1); + if (rc) + printk(KERN_WARNING + "EEH: Unable to reset the failed slot," + " #RST=%d dn=%s\n", + rc, pdn->node->full_name); + } } /** -- cgit v0.10.2 From cce36444173b943f7b27e726ab38b3340cdebc41 Mon Sep 17 00:00:00 2001 From: "Robert P. J. Day" Date: Thu, 21 Apr 2011 10:00:18 +0000 Subject: powerpc/pseries/bsr: Remove redundant initialization of bsr dev_t declaration. Remove the unnecessary initialization of "dev_t bsr_dev" since it's subsequently used in an "alloc_chrdev_region()" call which uses that variable in an output-only fashion. Signed-off-by: Robert P. J. Day Signed-off-by: Benjamin Herrenschmidt diff --git a/drivers/char/bsr.c b/drivers/char/bsr.c index a4a6c2f..cf39bc0 100644 --- a/drivers/char/bsr.c +++ b/drivers/char/bsr.c @@ -295,7 +295,7 @@ static int bsr_create_devs(struct device_node *bn) static int __init bsr_init(void) { struct device_node *np; - dev_t bsr_dev = MKDEV(bsr_major, 0); + dev_t bsr_dev; int ret = -ENODEV; int result; -- cgit v0.10.2 From e7e7ee2eab2080248084d71fe0a115ab745eb2aa Mon Sep 17 00:00:00 2001 From: Ingo Molnar Date: Wed, 4 May 2011 08:42:29 +0200 Subject: perf events: Clean up definitions and initializers, update copyrights Fix a few inconsistent style bits that were added over the past few months. Cc: Peter Zijlstra Link: http://lkml.kernel.org/n/tip-yv4hwf9yhnzoada8pcpb3a97@git.kernel.org Signed-off-by: Ingo Molnar diff --git a/include/linux/perf_event.h b/include/linux/perf_event.h index 9eec53d..207c169 100644 --- a/include/linux/perf_event.h +++ b/include/linux/perf_event.h @@ -2,8 +2,8 @@ * Performance events: * * Copyright (C) 2008-2009, Thomas Gleixner - * Copyright (C) 2008-2009, Red Hat, Inc., Ingo Molnar - * Copyright (C) 2008-2009, Red Hat, Inc., Peter Zijlstra + * Copyright (C) 2008-2011, Red Hat, Inc., Ingo Molnar + * Copyright (C) 2008-2011, Red Hat, Inc., Peter Zijlstra * * Data type definitions, declarations, prototypes. * @@ -468,9 +468,9 @@ enum perf_callchain_context { PERF_CONTEXT_MAX = (__u64)-4095, }; -#define PERF_FLAG_FD_NO_GROUP (1U << 0) -#define PERF_FLAG_FD_OUTPUT (1U << 1) -#define PERF_FLAG_PID_CGROUP (1U << 2) /* pid=cgroup id, per-cpu mode only */ +#define PERF_FLAG_FD_NO_GROUP (1U << 0) +#define PERF_FLAG_FD_OUTPUT (1U << 1) +#define PERF_FLAG_PID_CGROUP (1U << 2) /* pid=cgroup id, per-cpu mode only */ #ifdef __KERNEL__ /* @@ -484,9 +484,9 @@ enum perf_callchain_context { #endif struct perf_guest_info_callbacks { - int (*is_in_guest) (void); - int (*is_user_mode) (void); - unsigned long (*get_guest_ip) (void); + int (*is_in_guest)(void); + int (*is_user_mode)(void); + unsigned long (*get_guest_ip)(void); }; #ifdef CONFIG_HAVE_HW_BREAKPOINT @@ -652,19 +652,19 @@ struct pmu { * Start the transaction, after this ->add() doesn't need to * do schedulability tests. */ - void (*start_txn) (struct pmu *pmu); /* optional */ + void (*start_txn) (struct pmu *pmu); /* optional */ /* * If ->start_txn() disabled the ->add() schedulability test * then ->commit_txn() is required to perform one. On success * the transaction is closed. On error the transaction is kept * open until ->cancel_txn() is called. */ - int (*commit_txn) (struct pmu *pmu); /* optional */ + int (*commit_txn) (struct pmu *pmu); /* optional */ /* * Will cancel the transaction, assumes ->del() is called * for each successful ->add() during the transaction. */ - void (*cancel_txn) (struct pmu *pmu); /* optional */ + void (*cancel_txn) (struct pmu *pmu); /* optional */ }; /** @@ -712,15 +712,15 @@ typedef void (*perf_overflow_handler_t)(struct perf_event *, int, struct pt_regs *regs); enum perf_group_flag { - PERF_GROUP_SOFTWARE = 0x1, + PERF_GROUP_SOFTWARE = 0x1, }; -#define SWEVENT_HLIST_BITS 8 -#define SWEVENT_HLIST_SIZE (1 << SWEVENT_HLIST_BITS) +#define SWEVENT_HLIST_BITS 8 +#define SWEVENT_HLIST_SIZE (1 << SWEVENT_HLIST_BITS) struct swevent_hlist { - struct hlist_head heads[SWEVENT_HLIST_SIZE]; - struct rcu_head rcu_head; + struct hlist_head heads[SWEVENT_HLIST_SIZE]; + struct rcu_head rcu_head; }; #define PERF_ATTACH_CONTEXT 0x01 @@ -733,13 +733,13 @@ struct swevent_hlist { * This is a per-cpu dynamically allocated data structure. */ struct perf_cgroup_info { - u64 time; - u64 timestamp; + u64 time; + u64 timestamp; }; struct perf_cgroup { - struct cgroup_subsys_state css; - struct perf_cgroup_info *info; /* timing info, one per cpu */ + struct cgroup_subsys_state css; + struct perf_cgroup_info *info; /* timing info, one per cpu */ }; #endif @@ -923,7 +923,7 @@ struct perf_event_context { /* * Number of contexts where an event can trigger: - * task, softirq, hardirq, nmi. + * task, softirq, hardirq, nmi. */ #define PERF_NR_CONTEXTS 4 @@ -1001,8 +1001,7 @@ struct perf_sample_data { struct perf_raw_record *raw; }; -static inline -void perf_sample_data_init(struct perf_sample_data *data, u64 addr) +static inline void perf_sample_data_init(struct perf_sample_data *data, u64 addr) { data->addr = addr; data->raw = NULL; @@ -1039,8 +1038,7 @@ extern struct jump_label_key perf_swevent_enabled[PERF_COUNT_SW_MAX]; extern void __perf_sw_event(u32, u64, int, struct pt_regs *, u64); #ifndef perf_arch_fetch_caller_regs -static inline void -perf_arch_fetch_caller_regs(struct pt_regs *regs, unsigned long ip) { } +static inline void perf_arch_fetch_caller_regs(struct pt_regs *regs, unsigned long ip) { } #endif /* @@ -1080,8 +1078,7 @@ static inline void perf_event_task_sched_in(struct task_struct *task) __perf_event_task_sched_in(task); } -static inline -void perf_event_task_sched_out(struct task_struct *task, struct task_struct *next) +static inline void perf_event_task_sched_out(struct task_struct *task, struct task_struct *next) { perf_sw_event(PERF_COUNT_SW_CONTEXT_SWITCHES, 1, 1, NULL, 0); @@ -1099,14 +1096,10 @@ extern void perf_event_fork(struct task_struct *tsk); /* Callchains */ DECLARE_PER_CPU(struct perf_callchain_entry, perf_callchain_entry); -extern void perf_callchain_user(struct perf_callchain_entry *entry, - struct pt_regs *regs); -extern void perf_callchain_kernel(struct perf_callchain_entry *entry, - struct pt_regs *regs); - +extern void perf_callchain_user(struct perf_callchain_entry *entry, struct pt_regs *regs); +extern void perf_callchain_kernel(struct perf_callchain_entry *entry, struct pt_regs *regs); -static inline void -perf_callchain_store(struct perf_callchain_entry *entry, u64 ip) +static inline void perf_callchain_store(struct perf_callchain_entry *entry, u64 ip) { if (entry->nr < PERF_MAX_STACK_DEPTH) entry->ip[entry->nr++] = ip; @@ -1142,9 +1135,9 @@ extern void perf_tp_event(u64 addr, u64 count, void *record, extern void perf_bp_event(struct perf_event *event, void *data); #ifndef perf_misc_flags -#define perf_misc_flags(regs) (user_mode(regs) ? PERF_RECORD_MISC_USER : \ - PERF_RECORD_MISC_KERNEL) -#define perf_instruction_pointer(regs) instruction_pointer(regs) +# define perf_misc_flags(regs) \ + (user_mode(regs) ? PERF_RECORD_MISC_USER : PERF_RECORD_MISC_KERNEL) +# define perf_instruction_pointer(regs) instruction_pointer(regs) #endif extern int perf_output_begin(struct perf_output_handle *handle, @@ -1179,9 +1172,9 @@ static inline void perf_bp_event(struct perf_event *event, void *data) { } static inline int perf_register_guest_info_callbacks -(struct perf_guest_info_callbacks *callbacks) { return 0; } +(struct perf_guest_info_callbacks *callbacks) { return 0; } static inline int perf_unregister_guest_info_callbacks -(struct perf_guest_info_callbacks *callbacks) { return 0; } +(struct perf_guest_info_callbacks *callbacks) { return 0; } static inline void perf_event_mmap(struct vm_area_struct *vma) { } static inline void perf_event_comm(struct task_struct *tsk) { } @@ -1194,23 +1187,22 @@ static inline void perf_event_disable(struct perf_event *event) { } static inline void perf_event_task_tick(void) { } #endif -#define perf_output_put(handle, x) \ - perf_output_copy((handle), &(x), sizeof(x)) +#define perf_output_put(handle, x) perf_output_copy((handle), &(x), sizeof(x)) /* * This has to have a higher priority than migration_notifier in sched.c. */ -#define perf_cpu_notifier(fn) \ -do { \ - static struct notifier_block fn##_nb __cpuinitdata = \ - { .notifier_call = fn, .priority = CPU_PRI_PERF }; \ - fn(&fn##_nb, (unsigned long)CPU_UP_PREPARE, \ - (void *)(unsigned long)smp_processor_id()); \ - fn(&fn##_nb, (unsigned long)CPU_STARTING, \ - (void *)(unsigned long)smp_processor_id()); \ - fn(&fn##_nb, (unsigned long)CPU_ONLINE, \ - (void *)(unsigned long)smp_processor_id()); \ - register_cpu_notifier(&fn##_nb); \ +#define perf_cpu_notifier(fn) \ +do { \ + static struct notifier_block fn##_nb __cpuinitdata = \ + { .notifier_call = fn, .priority = CPU_PRI_PERF }; \ + fn(&fn##_nb, (unsigned long)CPU_UP_PREPARE, \ + (void *)(unsigned long)smp_processor_id()); \ + fn(&fn##_nb, (unsigned long)CPU_STARTING, \ + (void *)(unsigned long)smp_processor_id()); \ + fn(&fn##_nb, (unsigned long)CPU_ONLINE, \ + (void *)(unsigned long)smp_processor_id()); \ + register_cpu_notifier(&fn##_nb); \ } while (0) #endif /* __KERNEL__ */ diff --git a/kernel/events/core.c b/kernel/events/core.c index 440bc48..0fc34a3 100644 --- a/kernel/events/core.c +++ b/kernel/events/core.c @@ -2,8 +2,8 @@ * Performance events core code: * * Copyright (C) 2008 Thomas Gleixner - * Copyright (C) 2008-2009 Red Hat, Inc., Ingo Molnar - * Copyright (C) 2008-2009 Red Hat, Inc., Peter Zijlstra + * Copyright (C) 2008-2011 Red Hat, Inc., Ingo Molnar + * Copyright (C) 2008-2011 Red Hat, Inc., Peter Zijlstra * Copyright © 2009 Paul Mackerras, IBM Corp. * * For licensing details see kernel-base/COPYING @@ -39,10 +39,10 @@ #include struct remote_function_call { - struct task_struct *p; - int (*func)(void *info); - void *info; - int ret; + struct task_struct *p; + int (*func)(void *info); + void *info; + int ret; }; static void remote_function(void *data) @@ -76,10 +76,10 @@ static int task_function_call(struct task_struct *p, int (*func) (void *info), void *info) { struct remote_function_call data = { - .p = p, - .func = func, - .info = info, - .ret = -ESRCH, /* No such (running) process */ + .p = p, + .func = func, + .info = info, + .ret = -ESRCH, /* No such (running) process */ }; if (task_curr(p)) @@ -100,10 +100,10 @@ task_function_call(struct task_struct *p, int (*func) (void *info), void *info) static int cpu_function_call(int cpu, int (*func) (void *info), void *info) { struct remote_function_call data = { - .p = NULL, - .func = func, - .info = info, - .ret = -ENXIO, /* No such CPU */ + .p = NULL, + .func = func, + .info = info, + .ret = -ENXIO, /* No such CPU */ }; smp_call_function_single(cpu, remote_function, &data, 1); @@ -7445,11 +7445,11 @@ static void perf_cgroup_exit(struct cgroup_subsys *ss, struct cgroup *cgrp, } struct cgroup_subsys perf_subsys = { - .name = "perf_event", - .subsys_id = perf_subsys_id, - .create = perf_cgroup_create, - .destroy = perf_cgroup_destroy, - .exit = perf_cgroup_exit, - .attach = perf_cgroup_attach, + .name = "perf_event", + .subsys_id = perf_subsys_id, + .create = perf_cgroup_create, + .destroy = perf_cgroup_destroy, + .exit = perf_cgroup_exit, + .attach = perf_cgroup_attach, }; #endif /* CONFIG_CGROUP_PERF */ -- cgit v0.10.2 From 931aeeda0dca81152aec48f30be01e86a268bf89 Mon Sep 17 00:00:00 2001 From: Vladimir Davydov Date: Tue, 3 May 2011 22:31:07 +0400 Subject: sched: Remove unused 'this_best_prio arg' from balance_tasks() It's passed across multiple functions but is never really used, so remove it. Signed-off-by: Vladimir Davydov Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/1304447467-29200-1-git-send-email-vdavydov@parallels.com Signed-off-by: Ingo Molnar diff --git a/kernel/sched_fair.c b/kernel/sched_fair.c index 5280272..37f2262 100644 --- a/kernel/sched_fair.c +++ b/kernel/sched_fair.c @@ -2142,7 +2142,7 @@ static unsigned long balance_tasks(struct rq *this_rq, int this_cpu, struct rq *busiest, unsigned long max_load_move, struct sched_domain *sd, enum cpu_idle_type idle, int *all_pinned, - int *this_best_prio, struct cfs_rq *busiest_cfs_rq) + struct cfs_rq *busiest_cfs_rq) { int loops = 0, pulled = 0; long rem_load_move = max_load_move; @@ -2180,9 +2180,6 @@ balance_tasks(struct rq *this_rq, int this_cpu, struct rq *busiest, */ if (rem_load_move <= 0) break; - - if (p->prio < *this_best_prio) - *this_best_prio = p->prio; } out: /* @@ -2242,7 +2239,7 @@ static unsigned long load_balance_fair(struct rq *this_rq, int this_cpu, struct rq *busiest, unsigned long max_load_move, struct sched_domain *sd, enum cpu_idle_type idle, - int *all_pinned, int *this_best_prio) + int *all_pinned) { long rem_load_move = max_load_move; int busiest_cpu = cpu_of(busiest); @@ -2267,7 +2264,7 @@ load_balance_fair(struct rq *this_rq, int this_cpu, struct rq *busiest, rem_load = div_u64(rem_load, busiest_h_load + 1); moved_load = balance_tasks(this_rq, this_cpu, busiest, - rem_load, sd, idle, all_pinned, this_best_prio, + rem_load, sd, idle, all_pinned, busiest_cfs_rq); if (!moved_load) @@ -2293,11 +2290,11 @@ static unsigned long load_balance_fair(struct rq *this_rq, int this_cpu, struct rq *busiest, unsigned long max_load_move, struct sched_domain *sd, enum cpu_idle_type idle, - int *all_pinned, int *this_best_prio) + int *all_pinned) { return balance_tasks(this_rq, this_cpu, busiest, max_load_move, sd, idle, all_pinned, - this_best_prio, &busiest->cfs); + &busiest->cfs); } #endif @@ -2314,12 +2311,11 @@ static int move_tasks(struct rq *this_rq, int this_cpu, struct rq *busiest, int *all_pinned) { unsigned long total_load_moved = 0, load_moved; - int this_best_prio = this_rq->curr->prio; do { load_moved = load_balance_fair(this_rq, this_cpu, busiest, max_load_move - total_load_moved, - sd, idle, all_pinned, &this_best_prio); + sd, idle, all_pinned); total_load_moved += load_moved; -- cgit v0.10.2 From 904cc1e637a00dba1b58e7752f485f90ebf2a568 Mon Sep 17 00:00:00 2001 From: Naga Chumbalkar Date: Tue, 26 Apr 2011 17:05:18 +0000 Subject: [CPUFREQ] Fix _OSC UUID in pcc-cpufreq UUID needs to be written out the way it is described in Sec 18.5.124 of ACPI 4.0a Specification. Platform firmware's use of this UUID/_OSC is optional, which is why we didn't notice this bug earlier. Signed-off-by: Naga Chumbalkar Signed-off-by: Dave Jones Cc: stable@kernel.org diff --git a/arch/x86/kernel/cpu/cpufreq/pcc-cpufreq.c b/arch/x86/kernel/cpu/cpufreq/pcc-cpufreq.c index 755a31e..907c8e6 100644 --- a/arch/x86/kernel/cpu/cpufreq/pcc-cpufreq.c +++ b/arch/x86/kernel/cpu/cpufreq/pcc-cpufreq.c @@ -39,7 +39,7 @@ #include -#define PCC_VERSION "1.00.00" +#define PCC_VERSION "1.10.00" #define POLL_LOOPS 300 #define CMD_COMPLETE 0x1 @@ -102,7 +102,7 @@ static struct acpi_generic_address doorbell; static u64 doorbell_preserve; static u64 doorbell_write; -static u8 OSC_UUID[16] = {0x63, 0x9B, 0x2C, 0x9F, 0x70, 0x91, 0x49, 0x1f, +static u8 OSC_UUID[16] = {0x9F, 0x2C, 0x9B, 0x63, 0x91, 0x70, 0x1f, 0x49, 0xBB, 0x4F, 0xA5, 0x98, 0x2F, 0xA1, 0xB5, 0x46}; struct pcc_cpu { -- cgit v0.10.2 From 27ecddc2a9f99ce4ac9a59a0acd77f7100b6d034 Mon Sep 17 00:00:00 2001 From: Jacob Shin Date: Wed, 27 Apr 2011 13:32:11 -0500 Subject: [CPUFREQ] CPU hotplug, re-create sysfs directory and symlinks When we discover CPUs that are affected by each other's frequency/voltage transitions, the first CPU gets a sysfs directory created, and rest of the siblings get symlinks. Currently, when we hotplug off only the first CPU, all of the symlinks and the sysfs directory gets removed. Even though rest of the siblings are still online and functional, they are orphaned, and no longer governed by cpufreq. This patch, given the above scenario, creates a sysfs directory for the first sibling and symlinks for the rest of the siblings. Please note the recursive call, it was rather too ugly to roll it out. And the removal of redundant NULL setting (it is already taken care of near the top of the function). Signed-off-by: Jacob Shin Acked-by: Mark Langsdorf Reviewed-by: Thomas Renninger Signed-off-by: Dave Jones Cc: stable@kernel.org diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c index 2dafc5c..7c10f96 100644 --- a/drivers/cpufreq/cpufreq.c +++ b/drivers/cpufreq/cpufreq.c @@ -1208,12 +1208,28 @@ static int __cpufreq_remove_dev(struct sys_device *sys_dev) cpufreq_driver->exit(data); unlock_policy_rwsem_write(cpu); + cpufreq_debug_enable_ratelimit(); + +#ifdef CONFIG_HOTPLUG_CPU + /* when the CPU which is the parent of the kobj is hotplugged + * offline, check for siblings, and create cpufreq sysfs interface + * and symlinks + */ + if (unlikely(cpumask_weight(data->cpus) > 1)) { + /* first sibling now owns the new sysfs dir */ + cpumask_clear_cpu(cpu, data->cpus); + cpufreq_add_dev(get_cpu_sysdev(cpumask_first(data->cpus))); + + /* finally remove our own symlink */ + lock_policy_rwsem_write(cpu); + __cpufreq_remove_dev(sys_dev); + } +#endif + free_cpumask_var(data->related_cpus); free_cpumask_var(data->cpus); kfree(data); - per_cpu(cpufreq_cpu_data, cpu) = NULL; - cpufreq_debug_enable_ratelimit(); return 0; } -- cgit v0.10.2 From 2d06d8c49afdcc9bb35a85039fa50f0fe35bd40e Mon Sep 17 00:00:00 2001 From: Dominik Brodowski Date: Sun, 27 Mar 2011 15:04:46 +0200 Subject: [CPUFREQ] use dynamic debug instead of custom infrastructure With dynamic debug having gained the capability to report debug messages also during the boot process, it offers a far superior interface for debug messages than the custom cpufreq infrastructure. As a first step, remove the old cpufreq_debug_printk() function and replace it with a call to the generic pr_debug() function. How can dynamic debug be used on cpufreq? You need a kernel which has CONFIG_DYNAMIC_DEBUG enabled. To enabled debugging during runtime, mount debugfs and $ echo -n 'module cpufreq +p' > /sys/kernel/debug/dynamic_debug/control for debugging the complete "cpufreq" module. To achieve the same goal during boot, append ddebug_query="module cpufreq +p" as a boot parameter to the kernel of your choice. For more detailled instructions, please see Documentation/dynamic-debug-howto.txt Signed-off-by: Dominik Brodowski Signed-off-by: Dave Jones diff --git a/arch/arm/mach-davinci/cpufreq.c b/arch/arm/mach-davinci/cpufreq.c index 0a95be1..41669ec 100644 --- a/arch/arm/mach-davinci/cpufreq.c +++ b/arch/arm/mach-davinci/cpufreq.c @@ -94,9 +94,7 @@ static int davinci_target(struct cpufreq_policy *policy, if (freqs.old == freqs.new) return ret; - cpufreq_debug_printk(CPUFREQ_DEBUG_DRIVER, - dev_driver_string(cpufreq.dev), - "transition: %u --> %u\n", freqs.old, freqs.new); + dev_dbg(&cpufreq.dev, "transition: %u --> %u\n", freqs.old, freqs.new); ret = cpufreq_frequency_table_target(policy, pdata->freq_table, freqs.new, relation, &idx); diff --git a/arch/blackfin/mach-common/dpmc.c b/arch/blackfin/mach-common/dpmc.c index 382099f..5e4112e 100644 --- a/arch/blackfin/mach-common/dpmc.c +++ b/arch/blackfin/mach-common/dpmc.c @@ -19,9 +19,6 @@ #define DRIVER_NAME "bfin dpmc" -#define dprintk(msg...) \ - cpufreq_debug_printk(CPUFREQ_DEBUG_DRIVER, DRIVER_NAME, msg) - struct bfin_dpmc_platform_data *pdata; /** diff --git a/arch/ia64/kernel/cpufreq/acpi-cpufreq.c b/arch/ia64/kernel/cpufreq/acpi-cpufreq.c index 22f6152..f09b1742 100644 --- a/arch/ia64/kernel/cpufreq/acpi-cpufreq.c +++ b/arch/ia64/kernel/cpufreq/acpi-cpufreq.c @@ -23,8 +23,6 @@ #include #include -#define dprintk(msg...) cpufreq_debug_printk(CPUFREQ_DEBUG_DRIVER, "acpi-cpufreq", msg) - MODULE_AUTHOR("Venkatesh Pallipadi"); MODULE_DESCRIPTION("ACPI Processor P-States Driver"); MODULE_LICENSE("GPL"); @@ -47,12 +45,12 @@ processor_set_pstate ( { s64 retval; - dprintk("processor_set_pstate\n"); + pr_debug("processor_set_pstate\n"); retval = ia64_pal_set_pstate((u64)value); if (retval) { - dprintk("Failed to set freq to 0x%x, with error 0x%lx\n", + pr_debug("Failed to set freq to 0x%x, with error 0x%lx\n", value, retval); return -ENODEV; } @@ -67,14 +65,14 @@ processor_get_pstate ( u64 pstate_index = 0; s64 retval; - dprintk("processor_get_pstate\n"); + pr_debug("processor_get_pstate\n"); retval = ia64_pal_get_pstate(&pstate_index, PAL_GET_PSTATE_TYPE_INSTANT); *value = (u32) pstate_index; if (retval) - dprintk("Failed to get current freq with " + pr_debug("Failed to get current freq with " "error 0x%lx, idx 0x%x\n", retval, *value); return (int)retval; @@ -90,7 +88,7 @@ extract_clock ( { unsigned long i; - dprintk("extract_clock\n"); + pr_debug("extract_clock\n"); for (i = 0; i < data->acpi_data.state_count; i++) { if (value == data->acpi_data.states[i].status) @@ -110,7 +108,7 @@ processor_get_freq ( cpumask_t saved_mask; unsigned long clock_freq; - dprintk("processor_get_freq\n"); + pr_debug("processor_get_freq\n"); saved_mask = current->cpus_allowed; set_cpus_allowed_ptr(current, cpumask_of(cpu)); @@ -148,7 +146,7 @@ processor_set_freq ( cpumask_t saved_mask; int retval; - dprintk("processor_set_freq\n"); + pr_debug("processor_set_freq\n"); saved_mask = current->cpus_allowed; set_cpus_allowed_ptr(current, cpumask_of(cpu)); @@ -159,16 +157,16 @@ processor_set_freq ( if (state == data->acpi_data.state) { if (unlikely(data->resume)) { - dprintk("Called after resume, resetting to P%d\n", state); + pr_debug("Called after resume, resetting to P%d\n", state); data->resume = 0; } else { - dprintk("Already at target state (P%d)\n", state); + pr_debug("Already at target state (P%d)\n", state); retval = 0; goto migrate_end; } } - dprintk("Transitioning from P%d to P%d\n", + pr_debug("Transitioning from P%d to P%d\n", data->acpi_data.state, state); /* cpufreq frequency struct */ @@ -186,7 +184,7 @@ processor_set_freq ( value = (u32) data->acpi_data.states[state].control; - dprintk("Transitioning to state: 0x%08x\n", value); + pr_debug("Transitioning to state: 0x%08x\n", value); ret = processor_set_pstate(value); if (ret) { @@ -219,7 +217,7 @@ acpi_cpufreq_get ( { struct cpufreq_acpi_io *data = acpi_io_data[cpu]; - dprintk("acpi_cpufreq_get\n"); + pr_debug("acpi_cpufreq_get\n"); return processor_get_freq(data, cpu); } @@ -235,7 +233,7 @@ acpi_cpufreq_target ( unsigned int next_state = 0; unsigned int result = 0; - dprintk("acpi_cpufreq_setpolicy\n"); + pr_debug("acpi_cpufreq_setpolicy\n"); result = cpufreq_frequency_table_target(policy, data->freq_table, target_freq, relation, &next_state); @@ -255,7 +253,7 @@ acpi_cpufreq_verify ( unsigned int result = 0; struct cpufreq_acpi_io *data = acpi_io_data[policy->cpu]; - dprintk("acpi_cpufreq_verify\n"); + pr_debug("acpi_cpufreq_verify\n"); result = cpufreq_frequency_table_verify(policy, data->freq_table); @@ -273,7 +271,7 @@ acpi_cpufreq_cpu_init ( struct cpufreq_acpi_io *data; unsigned int result = 0; - dprintk("acpi_cpufreq_cpu_init\n"); + pr_debug("acpi_cpufreq_cpu_init\n"); data = kzalloc(sizeof(struct cpufreq_acpi_io), GFP_KERNEL); if (!data) @@ -288,7 +286,7 @@ acpi_cpufreq_cpu_init ( /* capability check */ if (data->acpi_data.state_count <= 1) { - dprintk("No P-States\n"); + pr_debug("No P-States\n"); result = -ENODEV; goto err_unreg; } @@ -297,7 +295,7 @@ acpi_cpufreq_cpu_init ( ACPI_ADR_SPACE_FIXED_HARDWARE) || (data->acpi_data.status_register.space_id != ACPI_ADR_SPACE_FIXED_HARDWARE)) { - dprintk("Unsupported address space [%d, %d]\n", + pr_debug("Unsupported address space [%d, %d]\n", (u32) (data->acpi_data.control_register.space_id), (u32) (data->acpi_data.status_register.space_id)); result = -ENODEV; @@ -348,7 +346,7 @@ acpi_cpufreq_cpu_init ( "activated.\n", cpu); for (i = 0; i < data->acpi_data.state_count; i++) - dprintk(" %cP%d: %d MHz, %d mW, %d uS, %d uS, 0x%x 0x%x\n", + pr_debug(" %cP%d: %d MHz, %d mW, %d uS, %d uS, 0x%x 0x%x\n", (i == data->acpi_data.state?'*':' '), i, (u32) data->acpi_data.states[i].core_frequency, (u32) data->acpi_data.states[i].power, @@ -383,7 +381,7 @@ acpi_cpufreq_cpu_exit ( { struct cpufreq_acpi_io *data = acpi_io_data[policy->cpu]; - dprintk("acpi_cpufreq_cpu_exit\n"); + pr_debug("acpi_cpufreq_cpu_exit\n"); if (data) { cpufreq_frequency_table_put_attr(policy->cpu); @@ -418,7 +416,7 @@ static struct cpufreq_driver acpi_cpufreq_driver = { static int __init acpi_cpufreq_init (void) { - dprintk("acpi_cpufreq_init\n"); + pr_debug("acpi_cpufreq_init\n"); return cpufreq_register_driver(&acpi_cpufreq_driver); } @@ -427,7 +425,7 @@ acpi_cpufreq_init (void) static void __exit acpi_cpufreq_exit (void) { - dprintk("acpi_cpufreq_exit\n"); + pr_debug("acpi_cpufreq_exit\n"); cpufreq_unregister_driver(&acpi_cpufreq_driver); return; diff --git a/arch/x86/kernel/cpu/cpufreq/acpi-cpufreq.c b/arch/x86/kernel/cpu/cpufreq/acpi-cpufreq.c index a2baafb..4e04e12 100644 --- a/arch/x86/kernel/cpu/cpufreq/acpi-cpufreq.c +++ b/arch/x86/kernel/cpu/cpufreq/acpi-cpufreq.c @@ -47,9 +47,6 @@ #include #include "mperf.h" -#define dprintk(msg...) cpufreq_debug_printk(CPUFREQ_DEBUG_DRIVER, \ - "acpi-cpufreq", msg) - MODULE_AUTHOR("Paul Diefenbaugh, Dominik Brodowski"); MODULE_DESCRIPTION("ACPI Processor P-States Driver"); MODULE_LICENSE("GPL"); @@ -233,7 +230,7 @@ static u32 get_cur_val(const struct cpumask *mask) cmd.mask = mask; drv_read(&cmd); - dprintk("get_cur_val = %u\n", cmd.val); + pr_debug("get_cur_val = %u\n", cmd.val); return cmd.val; } @@ -244,7 +241,7 @@ static unsigned int get_cur_freq_on_cpu(unsigned int cpu) unsigned int freq; unsigned int cached_freq; - dprintk("get_cur_freq_on_cpu (%d)\n", cpu); + pr_debug("get_cur_freq_on_cpu (%d)\n", cpu); if (unlikely(data == NULL || data->acpi_data == NULL || data->freq_table == NULL)) { @@ -261,7 +258,7 @@ static unsigned int get_cur_freq_on_cpu(unsigned int cpu) data->resume = 1; } - dprintk("cur freq = %u\n", freq); + pr_debug("cur freq = %u\n", freq); return freq; } @@ -293,7 +290,7 @@ static int acpi_cpufreq_target(struct cpufreq_policy *policy, unsigned int i; int result = 0; - dprintk("acpi_cpufreq_target %d (%d)\n", target_freq, policy->cpu); + pr_debug("acpi_cpufreq_target %d (%d)\n", target_freq, policy->cpu); if (unlikely(data == NULL || data->acpi_data == NULL || data->freq_table == NULL)) { @@ -313,11 +310,11 @@ static int acpi_cpufreq_target(struct cpufreq_policy *policy, next_perf_state = data->freq_table[next_state].index; if (perf->state == next_perf_state) { if (unlikely(data->resume)) { - dprintk("Called after resume, resetting to P%d\n", + pr_debug("Called after resume, resetting to P%d\n", next_perf_state); data->resume = 0; } else { - dprintk("Already at target state (P%d)\n", + pr_debug("Already at target state (P%d)\n", next_perf_state); goto out; } @@ -357,7 +354,7 @@ static int acpi_cpufreq_target(struct cpufreq_policy *policy, if (acpi_pstate_strict) { if (!check_freqs(cmd.mask, freqs.new, data)) { - dprintk("acpi_cpufreq_target failed (%d)\n", + pr_debug("acpi_cpufreq_target failed (%d)\n", policy->cpu); result = -EAGAIN; goto out; @@ -378,7 +375,7 @@ static int acpi_cpufreq_verify(struct cpufreq_policy *policy) { struct acpi_cpufreq_data *data = per_cpu(acfreq_data, policy->cpu); - dprintk("acpi_cpufreq_verify\n"); + pr_debug("acpi_cpufreq_verify\n"); return cpufreq_frequency_table_verify(policy, data->freq_table); } @@ -433,11 +430,11 @@ static void free_acpi_perf_data(void) static int __init acpi_cpufreq_early_init(void) { unsigned int i; - dprintk("acpi_cpufreq_early_init\n"); + pr_debug("acpi_cpufreq_early_init\n"); acpi_perf_data = alloc_percpu(struct acpi_processor_performance); if (!acpi_perf_data) { - dprintk("Memory allocation error for acpi_perf_data.\n"); + pr_debug("Memory allocation error for acpi_perf_data.\n"); return -ENOMEM; } for_each_possible_cpu(i) { @@ -519,7 +516,7 @@ static int acpi_cpufreq_cpu_init(struct cpufreq_policy *policy) static int blacklisted; #endif - dprintk("acpi_cpufreq_cpu_init\n"); + pr_debug("acpi_cpufreq_cpu_init\n"); #ifdef CONFIG_SMP if (blacklisted) @@ -566,7 +563,7 @@ static int acpi_cpufreq_cpu_init(struct cpufreq_policy *policy) /* capability check */ if (perf->state_count <= 1) { - dprintk("No P-States\n"); + pr_debug("No P-States\n"); result = -ENODEV; goto err_unreg; } @@ -578,11 +575,11 @@ static int acpi_cpufreq_cpu_init(struct cpufreq_policy *policy) switch (perf->control_register.space_id) { case ACPI_ADR_SPACE_SYSTEM_IO: - dprintk("SYSTEM IO addr space\n"); + pr_debug("SYSTEM IO addr space\n"); data->cpu_feature = SYSTEM_IO_CAPABLE; break; case ACPI_ADR_SPACE_FIXED_HARDWARE: - dprintk("HARDWARE addr space\n"); + pr_debug("HARDWARE addr space\n"); if (!check_est_cpu(cpu)) { result = -ENODEV; goto err_unreg; @@ -590,7 +587,7 @@ static int acpi_cpufreq_cpu_init(struct cpufreq_policy *policy) data->cpu_feature = SYSTEM_INTEL_MSR_CAPABLE; break; default: - dprintk("Unknown addr space %d\n", + pr_debug("Unknown addr space %d\n", (u32) (perf->control_register.space_id)); result = -ENODEV; goto err_unreg; @@ -661,9 +658,9 @@ static int acpi_cpufreq_cpu_init(struct cpufreq_policy *policy) if (cpu_has(c, X86_FEATURE_APERFMPERF)) acpi_cpufreq_driver.getavg = cpufreq_get_measured_perf; - dprintk("CPU%u - ACPI performance management activated.\n", cpu); + pr_debug("CPU%u - ACPI performance management activated.\n", cpu); for (i = 0; i < perf->state_count; i++) - dprintk(" %cP%d: %d MHz, %d mW, %d uS\n", + pr_debug(" %cP%d: %d MHz, %d mW, %d uS\n", (i == perf->state ? '*' : ' '), i, (u32) perf->states[i].core_frequency, (u32) perf->states[i].power, @@ -694,7 +691,7 @@ static int acpi_cpufreq_cpu_exit(struct cpufreq_policy *policy) { struct acpi_cpufreq_data *data = per_cpu(acfreq_data, policy->cpu); - dprintk("acpi_cpufreq_cpu_exit\n"); + pr_debug("acpi_cpufreq_cpu_exit\n"); if (data) { cpufreq_frequency_table_put_attr(policy->cpu); @@ -712,7 +709,7 @@ static int acpi_cpufreq_resume(struct cpufreq_policy *policy) { struct acpi_cpufreq_data *data = per_cpu(acfreq_data, policy->cpu); - dprintk("acpi_cpufreq_resume\n"); + pr_debug("acpi_cpufreq_resume\n"); data->resume = 1; @@ -743,7 +740,7 @@ static int __init acpi_cpufreq_init(void) if (acpi_disabled) return 0; - dprintk("acpi_cpufreq_init\n"); + pr_debug("acpi_cpufreq_init\n"); ret = acpi_cpufreq_early_init(); if (ret) @@ -758,7 +755,7 @@ static int __init acpi_cpufreq_init(void) static void __exit acpi_cpufreq_exit(void) { - dprintk("acpi_cpufreq_exit\n"); + pr_debug("acpi_cpufreq_exit\n"); cpufreq_unregister_driver(&acpi_cpufreq_driver); diff --git a/arch/x86/kernel/cpu/cpufreq/cpufreq-nforce2.c b/arch/x86/kernel/cpu/cpufreq/cpufreq-nforce2.c index 141abeb..7bac808 100644 --- a/arch/x86/kernel/cpu/cpufreq/cpufreq-nforce2.c +++ b/arch/x86/kernel/cpu/cpufreq/cpufreq-nforce2.c @@ -57,8 +57,6 @@ MODULE_PARM_DESC(min_fsb, "Minimum FSB to use, if not defined: current FSB - 50"); #define PFX "cpufreq-nforce2: " -#define dprintk(msg...) cpufreq_debug_printk(CPUFREQ_DEBUG_DRIVER, \ - "cpufreq-nforce2", msg) /** * nforce2_calc_fsb - calculate FSB @@ -270,7 +268,7 @@ static int nforce2_target(struct cpufreq_policy *policy, if (freqs.old == freqs.new) return 0; - dprintk("Old CPU frequency %d kHz, new %d kHz\n", + pr_debug("Old CPU frequency %d kHz, new %d kHz\n", freqs.old, freqs.new); cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE); @@ -282,7 +280,7 @@ static int nforce2_target(struct cpufreq_policy *policy, printk(KERN_ERR PFX "Changing FSB to %d failed\n", target_fsb); else - dprintk("Changed FSB successfully to %d\n", + pr_debug("Changed FSB successfully to %d\n", target_fsb); /* Enable IRQs */ diff --git a/arch/x86/kernel/cpu/cpufreq/gx-suspmod.c b/arch/x86/kernel/cpu/cpufreq/gx-suspmod.c index 32974cf..ffe1f2c 100644 --- a/arch/x86/kernel/cpu/cpufreq/gx-suspmod.c +++ b/arch/x86/kernel/cpu/cpufreq/gx-suspmod.c @@ -142,9 +142,6 @@ module_param(max_duration, int, 0444); #define POLICY_MIN_DIV 20 -#define dprintk(msg...) cpufreq_debug_printk(CPUFREQ_DEBUG_DRIVER, \ - "gx-suspmod", msg) - /** * we can detect a core multipiler from dir0_lsb * from GX1 datasheet p.56, @@ -191,7 +188,7 @@ static __init struct pci_dev *gx_detect_chipset(void) /* check if CPU is a MediaGX or a Geode. */ if ((boot_cpu_data.x86_vendor != X86_VENDOR_NSC) && (boot_cpu_data.x86_vendor != X86_VENDOR_CYRIX)) { - dprintk("error: no MediaGX/Geode processor found!\n"); + pr_debug("error: no MediaGX/Geode processor found!\n"); return NULL; } @@ -201,7 +198,7 @@ static __init struct pci_dev *gx_detect_chipset(void) return gx_pci; } - dprintk("error: no supported chipset found!\n"); + pr_debug("error: no supported chipset found!\n"); return NULL; } @@ -305,14 +302,14 @@ static void gx_set_cpuspeed(unsigned int khz) break; default: local_irq_restore(flags); - dprintk("fatal: try to set unknown chipset.\n"); + pr_debug("fatal: try to set unknown chipset.\n"); return; } } else { suscfg = gx_params->pci_suscfg & ~(SUSMOD); gx_params->off_duration = 0; gx_params->on_duration = 0; - dprintk("suspend modulation disabled: cpu runs 100%% speed.\n"); + pr_debug("suspend modulation disabled: cpu runs 100%% speed.\n"); } gx_write_byte(PCI_MODOFF, gx_params->off_duration); @@ -327,9 +324,9 @@ static void gx_set_cpuspeed(unsigned int khz) cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE); - dprintk("suspend modulation w/ duration of ON:%d us, OFF:%d us\n", + pr_debug("suspend modulation w/ duration of ON:%d us, OFF:%d us\n", gx_params->on_duration * 32, gx_params->off_duration * 32); - dprintk("suspend modulation w/ clock speed: %d kHz.\n", freqs.new); + pr_debug("suspend modulation w/ clock speed: %d kHz.\n", freqs.new); } /**************************************************************** @@ -428,8 +425,8 @@ static int cpufreq_gx_cpu_init(struct cpufreq_policy *policy) stock_freq = maxfreq; curfreq = gx_get_cpuspeed(0); - dprintk("cpu max frequency is %d.\n", maxfreq); - dprintk("cpu current frequency is %dkHz.\n", curfreq); + pr_debug("cpu max frequency is %d.\n", maxfreq); + pr_debug("cpu current frequency is %dkHz.\n", curfreq); /* setup basic struct for cpufreq API */ policy->cpu = 0; @@ -475,7 +472,7 @@ static int __init cpufreq_gx_init(void) if (max_duration > 0xff) max_duration = 0xff; - dprintk("geode suspend modulation available.\n"); + pr_debug("geode suspend modulation available.\n"); params = kzalloc(sizeof(struct gxfreq_params), GFP_KERNEL); if (params == NULL) diff --git a/arch/x86/kernel/cpu/cpufreq/longhaul.c b/arch/x86/kernel/cpu/cpufreq/longhaul.c index cf48cdd..f47d26e 100644 --- a/arch/x86/kernel/cpu/cpufreq/longhaul.c +++ b/arch/x86/kernel/cpu/cpufreq/longhaul.c @@ -77,9 +77,6 @@ static int scale_voltage; static int disable_acpi_c3; static int revid_errata; -#define dprintk(msg...) cpufreq_debug_printk(CPUFREQ_DEBUG_DRIVER, \ - "longhaul", msg) - /* Clock ratios multiplied by 10 */ static int mults[32]; @@ -87,7 +84,6 @@ static int eblcr[32]; static int longhaul_version; static struct cpufreq_frequency_table *longhaul_table; -#ifdef CONFIG_CPU_FREQ_DEBUG static char speedbuffer[8]; static char *print_speed(int speed) @@ -106,7 +102,6 @@ static char *print_speed(int speed) return speedbuffer; } -#endif static unsigned int calc_speed(int mult) @@ -275,7 +270,7 @@ static void longhaul_setstate(unsigned int table_index) cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE); - dprintk("Setting to FSB:%dMHz Mult:%d.%dx (%s)\n", + pr_debug("Setting to FSB:%dMHz Mult:%d.%dx (%s)\n", fsb, mult/10, mult%10, print_speed(speed/1000)); retry_loop: preempt_disable(); @@ -460,12 +455,12 @@ static int __cpuinit longhaul_get_ranges(void) break; } - dprintk("MinMult:%d.%dx MaxMult:%d.%dx\n", + pr_debug("MinMult:%d.%dx MaxMult:%d.%dx\n", minmult/10, minmult%10, maxmult/10, maxmult%10); highest_speed = calc_speed(maxmult); lowest_speed = calc_speed(minmult); - dprintk("FSB:%dMHz Lowest speed: %s Highest speed:%s\n", fsb, + pr_debug("FSB:%dMHz Lowest speed: %s Highest speed:%s\n", fsb, print_speed(lowest_speed/1000), print_speed(highest_speed/1000)); diff --git a/arch/x86/kernel/cpu/cpufreq/longrun.c b/arch/x86/kernel/cpu/cpufreq/longrun.c index d9f5136..34ea359 100644 --- a/arch/x86/kernel/cpu/cpufreq/longrun.c +++ b/arch/x86/kernel/cpu/cpufreq/longrun.c @@ -15,9 +15,6 @@ #include #include -#define dprintk(msg...) cpufreq_debug_printk(CPUFREQ_DEBUG_DRIVER, \ - "longrun", msg) - static struct cpufreq_driver longrun_driver; /** @@ -40,14 +37,14 @@ static void __cpuinit longrun_get_policy(struct cpufreq_policy *policy) u32 msr_lo, msr_hi; rdmsr(MSR_TMTA_LONGRUN_FLAGS, msr_lo, msr_hi); - dprintk("longrun flags are %x - %x\n", msr_lo, msr_hi); + pr_debug("longrun flags are %x - %x\n", msr_lo, msr_hi); if (msr_lo & 0x01) policy->policy = CPUFREQ_POLICY_PERFORMANCE; else policy->policy = CPUFREQ_POLICY_POWERSAVE; rdmsr(MSR_TMTA_LONGRUN_CTRL, msr_lo, msr_hi); - dprintk("longrun ctrl is %x - %x\n", msr_lo, msr_hi); + pr_debug("longrun ctrl is %x - %x\n", msr_lo, msr_hi); msr_lo &= 0x0000007F; msr_hi &= 0x0000007F; @@ -150,7 +147,7 @@ static unsigned int longrun_get(unsigned int cpu) return 0; cpuid(0x80860007, &eax, &ebx, &ecx, &edx); - dprintk("cpuid eax is %u\n", eax); + pr_debug("cpuid eax is %u\n", eax); return eax * 1000; } @@ -196,7 +193,7 @@ static int __cpuinit longrun_determine_freqs(unsigned int *low_freq, rdmsr(MSR_TMTA_LRTI_VOLT_MHZ, msr_lo, msr_hi); *high_freq = msr_lo * 1000; /* to kHz */ - dprintk("longrun table interface told %u - %u kHz\n", + pr_debug("longrun table interface told %u - %u kHz\n", *low_freq, *high_freq); if (*low_freq > *high_freq) @@ -207,7 +204,7 @@ static int __cpuinit longrun_determine_freqs(unsigned int *low_freq, /* set the upper border to the value determined during TSC init */ *high_freq = (cpu_khz / 1000); *high_freq = *high_freq * 1000; - dprintk("high frequency is %u kHz\n", *high_freq); + pr_debug("high frequency is %u kHz\n", *high_freq); /* get current borders */ rdmsr(MSR_TMTA_LONGRUN_CTRL, msr_lo, msr_hi); @@ -233,7 +230,7 @@ static int __cpuinit longrun_determine_freqs(unsigned int *low_freq, /* restore values */ wrmsr(MSR_TMTA_LONGRUN_CTRL, save_lo, save_hi); } - dprintk("percentage is %u %%, freq is %u MHz\n", ecx, eax); + pr_debug("percentage is %u %%, freq is %u MHz\n", ecx, eax); /* performance_pctg = (current_freq - low_freq)/(high_freq - low_freq) * eqals @@ -249,7 +246,7 @@ static int __cpuinit longrun_determine_freqs(unsigned int *low_freq, edx = ((eax - ebx) * 100) / (100 - ecx); *low_freq = edx * 1000; /* back to kHz */ - dprintk("low frequency is %u kHz\n", *low_freq); + pr_debug("low frequency is %u kHz\n", *low_freq); if (*low_freq > *high_freq) *low_freq = *high_freq; diff --git a/arch/x86/kernel/cpu/cpufreq/p4-clockmod.c b/arch/x86/kernel/cpu/cpufreq/p4-clockmod.c index 52c9364..6be3e07 100644 --- a/arch/x86/kernel/cpu/cpufreq/p4-clockmod.c +++ b/arch/x86/kernel/cpu/cpufreq/p4-clockmod.c @@ -35,8 +35,6 @@ #include "speedstep-lib.h" #define PFX "p4-clockmod: " -#define dprintk(msg...) cpufreq_debug_printk(CPUFREQ_DEBUG_DRIVER, \ - "p4-clockmod", msg) /* * Duty Cycle (3bits), note DC_DISABLE is not specified in @@ -66,7 +64,7 @@ static int cpufreq_p4_setdc(unsigned int cpu, unsigned int newstate) rdmsr_on_cpu(cpu, MSR_IA32_THERM_STATUS, &l, &h); if (l & 0x01) - dprintk("CPU#%d currently thermal throttled\n", cpu); + pr_debug("CPU#%d currently thermal throttled\n", cpu); if (has_N44_O17_errata[cpu] && (newstate == DC_25PT || newstate == DC_DFLT)) @@ -74,10 +72,10 @@ static int cpufreq_p4_setdc(unsigned int cpu, unsigned int newstate) rdmsr_on_cpu(cpu, MSR_IA32_THERM_CONTROL, &l, &h); if (newstate == DC_DISABLE) { - dprintk("CPU#%d disabling modulation\n", cpu); + pr_debug("CPU#%d disabling modulation\n", cpu); wrmsr_on_cpu(cpu, MSR_IA32_THERM_CONTROL, l & ~(1<<4), h); } else { - dprintk("CPU#%d setting duty cycle to %d%%\n", + pr_debug("CPU#%d setting duty cycle to %d%%\n", cpu, ((125 * newstate) / 10)); /* bits 63 - 5 : reserved * bit 4 : enable/disable @@ -217,7 +215,7 @@ static int cpufreq_p4_cpu_init(struct cpufreq_policy *policy) case 0x0f11: case 0x0f12: has_N44_O17_errata[policy->cpu] = 1; - dprintk("has errata -- disabling low frequencies\n"); + pr_debug("has errata -- disabling low frequencies\n"); } if (speedstep_detect_processor() == SPEEDSTEP_CPU_P4D && diff --git a/arch/x86/kernel/cpu/cpufreq/pcc-cpufreq.c b/arch/x86/kernel/cpu/cpufreq/pcc-cpufreq.c index 907c8e6..7b0603e 100644 --- a/arch/x86/kernel/cpu/cpufreq/pcc-cpufreq.c +++ b/arch/x86/kernel/cpu/cpufreq/pcc-cpufreq.c @@ -48,9 +48,6 @@ #define BUF_SZ 4 -#define dprintk(msg...) cpufreq_debug_printk(CPUFREQ_DEBUG_DRIVER, \ - "pcc-cpufreq", msg) - struct pcc_register_resource { u8 descriptor; u16 length; @@ -152,7 +149,7 @@ static unsigned int pcc_get_freq(unsigned int cpu) spin_lock(&pcc_lock); - dprintk("get: get_freq for CPU %d\n", cpu); + pr_debug("get: get_freq for CPU %d\n", cpu); pcc_cpu_data = per_cpu_ptr(pcc_cpu_info, cpu); input_buffer = 0x1; @@ -170,7 +167,7 @@ static unsigned int pcc_get_freq(unsigned int cpu) status = ioread16(&pcch_hdr->status); if (status != CMD_COMPLETE) { - dprintk("get: FAILED: for CPU %d, status is %d\n", + pr_debug("get: FAILED: for CPU %d, status is %d\n", cpu, status); goto cmd_incomplete; } @@ -178,14 +175,14 @@ static unsigned int pcc_get_freq(unsigned int cpu) curr_freq = (((ioread32(&pcch_hdr->nominal) * (output_buffer & 0xff)) / 100) * 1000); - dprintk("get: SUCCESS: (virtual) output_offset for cpu %d is " - "0x%x, contains a value of: 0x%x. Speed is: %d MHz\n", + pr_debug("get: SUCCESS: (virtual) output_offset for cpu %d is " + "0x%p, contains a value of: 0x%x. Speed is: %d MHz\n", cpu, (pcch_virt_addr + pcc_cpu_data->output_offset), output_buffer, curr_freq); freq_limit = (output_buffer >> 8) & 0xff; if (freq_limit != 0xff) { - dprintk("get: frequency for cpu %d is being temporarily" + pr_debug("get: frequency for cpu %d is being temporarily" " capped at %d\n", cpu, curr_freq); } @@ -212,8 +209,8 @@ static int pcc_cpufreq_target(struct cpufreq_policy *policy, cpu = policy->cpu; pcc_cpu_data = per_cpu_ptr(pcc_cpu_info, cpu); - dprintk("target: CPU %d should go to target freq: %d " - "(virtual) input_offset is 0x%x\n", + pr_debug("target: CPU %d should go to target freq: %d " + "(virtual) input_offset is 0x%p\n", cpu, target_freq, (pcch_virt_addr + pcc_cpu_data->input_offset)); @@ -234,14 +231,14 @@ static int pcc_cpufreq_target(struct cpufreq_policy *policy, status = ioread16(&pcch_hdr->status); if (status != CMD_COMPLETE) { - dprintk("target: FAILED for cpu %d, with status: 0x%x\n", + pr_debug("target: FAILED for cpu %d, with status: 0x%x\n", cpu, status); goto cmd_incomplete; } iowrite16(0, &pcch_hdr->status); cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE); - dprintk("target: was SUCCESSFUL for cpu %d\n", cpu); + pr_debug("target: was SUCCESSFUL for cpu %d\n", cpu); spin_unlock(&pcc_lock); return 0; @@ -293,7 +290,7 @@ static int pcc_get_offset(int cpu) memset_io((pcch_virt_addr + pcc_cpu_data->input_offset), 0, BUF_SZ); memset_io((pcch_virt_addr + pcc_cpu_data->output_offset), 0, BUF_SZ); - dprintk("pcc_get_offset: for CPU %d: pcc_cpu_data " + pr_debug("pcc_get_offset: for CPU %d: pcc_cpu_data " "input_offset: 0x%x, pcc_cpu_data output_offset: 0x%x\n", cpu, pcc_cpu_data->input_offset, pcc_cpu_data->output_offset); out_free: @@ -410,7 +407,7 @@ static int __init pcc_cpufreq_probe(void) if (ACPI_SUCCESS(status)) { ret = pcc_cpufreq_do_osc(&osc_handle); if (ret) - dprintk("probe: _OSC evaluation did not succeed\n"); + pr_debug("probe: _OSC evaluation did not succeed\n"); /* Firmware's use of _OSC is optional */ ret = 0; } @@ -433,7 +430,7 @@ static int __init pcc_cpufreq_probe(void) mem_resource = (struct pcc_memory_resource *)member->buffer.pointer; - dprintk("probe: mem_resource descriptor: 0x%x," + pr_debug("probe: mem_resource descriptor: 0x%x," " length: %d, space_id: %d, resource_usage: %d," " type_specific: %d, granularity: 0x%llx," " minimum: 0x%llx, maximum: 0x%llx," @@ -453,13 +450,13 @@ static int __init pcc_cpufreq_probe(void) pcch_virt_addr = ioremap_nocache(mem_resource->minimum, mem_resource->address_length); if (pcch_virt_addr == NULL) { - dprintk("probe: could not map shared mem region\n"); + pr_debug("probe: could not map shared mem region\n"); goto out_free; } pcch_hdr = pcch_virt_addr; - dprintk("probe: PCCH header (virtual) addr: 0x%p\n", pcch_hdr); - dprintk("probe: PCCH header is at physical address: 0x%llx," + pr_debug("probe: PCCH header (virtual) addr: 0x%p\n", pcch_hdr); + pr_debug("probe: PCCH header is at physical address: 0x%llx," " signature: 0x%x, length: %d bytes, major: %d, minor: %d," " supported features: 0x%x, command field: 0x%x," " status field: 0x%x, nominal latency: %d us\n", @@ -469,7 +466,7 @@ static int __init pcc_cpufreq_probe(void) ioread16(&pcch_hdr->command), ioread16(&pcch_hdr->status), ioread32(&pcch_hdr->latency)); - dprintk("probe: min time between commands: %d us," + pr_debug("probe: min time between commands: %d us," " max time between commands: %d us," " nominal CPU frequency: %d MHz," " minimum CPU frequency: %d MHz," @@ -494,7 +491,7 @@ static int __init pcc_cpufreq_probe(void) doorbell.access_width = 64; doorbell.address = reg_resource->address; - dprintk("probe: doorbell: space_id is %d, bit_width is %d, " + pr_debug("probe: doorbell: space_id is %d, bit_width is %d, " "bit_offset is %d, access_width is %d, address is 0x%llx\n", doorbell.space_id, doorbell.bit_width, doorbell.bit_offset, doorbell.access_width, reg_resource->address); @@ -515,7 +512,7 @@ static int __init pcc_cpufreq_probe(void) doorbell_write = member->integer.value; - dprintk("probe: doorbell_preserve: 0x%llx," + pr_debug("probe: doorbell_preserve: 0x%llx," " doorbell_write: 0x%llx\n", doorbell_preserve, doorbell_write); @@ -550,7 +547,7 @@ static int pcc_cpufreq_cpu_init(struct cpufreq_policy *policy) result = pcc_get_offset(cpu); if (result) { - dprintk("init: PCCP evaluation failed\n"); + pr_debug("init: PCCP evaluation failed\n"); goto out; } @@ -561,12 +558,12 @@ static int pcc_cpufreq_cpu_init(struct cpufreq_policy *policy) policy->cur = pcc_get_freq(cpu); if (!policy->cur) { - dprintk("init: Unable to get current CPU frequency\n"); + pr_debug("init: Unable to get current CPU frequency\n"); result = -EINVAL; goto out; } - dprintk("init: policy->max is %d, policy->min is %d\n", + pr_debug("init: policy->max is %d, policy->min is %d\n", policy->max, policy->min); out: return result; @@ -597,7 +594,7 @@ static int __init pcc_cpufreq_init(void) ret = pcc_cpufreq_probe(); if (ret) { - dprintk("pcc_cpufreq_init: PCCH evaluation failed\n"); + pr_debug("pcc_cpufreq_init: PCCH evaluation failed\n"); return ret; } diff --git a/arch/x86/kernel/cpu/cpufreq/powernow-k7.c b/arch/x86/kernel/cpu/cpufreq/powernow-k7.c index 4a45fd6..d71d9f3 100644 --- a/arch/x86/kernel/cpu/cpufreq/powernow-k7.c +++ b/arch/x86/kernel/cpu/cpufreq/powernow-k7.c @@ -68,7 +68,6 @@ union powernow_acpi_control_t { }; #endif -#ifdef CONFIG_CPU_FREQ_DEBUG /* divide by 1000 to get VCore voltage in V. */ static const int mobile_vid_table[32] = { 2000, 1950, 1900, 1850, 1800, 1750, 1700, 1650, @@ -76,7 +75,6 @@ static const int mobile_vid_table[32] = { 1275, 1250, 1225, 1200, 1175, 1150, 1125, 1100, 1075, 1050, 1025, 1000, 975, 950, 925, 0, }; -#endif /* divide by 10 to get FID. */ static const int fid_codes[32] = { @@ -103,9 +101,6 @@ static unsigned int fsb; static unsigned int latency; static char have_a0; -#define dprintk(msg...) cpufreq_debug_printk(CPUFREQ_DEBUG_DRIVER, \ - "powernow-k7", msg) - static int check_fsb(unsigned int fsbspeed) { int delta; @@ -209,7 +204,7 @@ static int get_ranges(unsigned char *pst) vid = *pst++; powernow_table[j].index |= (vid << 8); /* upper 8 bits */ - dprintk(" FID: 0x%x (%d.%dx [%dMHz]) " + pr_debug(" FID: 0x%x (%d.%dx [%dMHz]) " "VID: 0x%x (%d.%03dV)\n", fid, fid_codes[fid] / 10, fid_codes[fid] % 10, speed/1000, vid, mobile_vid_table[vid]/1000, @@ -367,7 +362,7 @@ static int powernow_acpi_init(void) unsigned int speed, speed_mhz; pc.val = (unsigned long) state->control; - dprintk("acpi: P%d: %d MHz %d mW %d uS control %08x SGTC %d\n", + pr_debug("acpi: P%d: %d MHz %d mW %d uS control %08x SGTC %d\n", i, (u32) state->core_frequency, (u32) state->power, @@ -401,7 +396,7 @@ static int powernow_acpi_init(void) invalidate_entry(i); } - dprintk(" FID: 0x%x (%d.%dx [%dMHz]) " + pr_debug(" FID: 0x%x (%d.%dx [%dMHz]) " "VID: 0x%x (%d.%03dV)\n", fid, fid_codes[fid] / 10, fid_codes[fid] % 10, speed_mhz, vid, mobile_vid_table[vid]/1000, @@ -409,7 +404,7 @@ static int powernow_acpi_init(void) if (state->core_frequency != speed_mhz) { state->core_frequency = speed_mhz; - dprintk(" Corrected ACPI frequency to %d\n", + pr_debug(" Corrected ACPI frequency to %d\n", speed_mhz); } @@ -453,8 +448,8 @@ static int powernow_acpi_init(void) static void print_pst_entry(struct pst_s *pst, unsigned int j) { - dprintk("PST:%d (@%p)\n", j, pst); - dprintk(" cpuid: 0x%x fsb: %d maxFID: 0x%x startvid: 0x%x\n", + pr_debug("PST:%d (@%p)\n", j, pst); + pr_debug(" cpuid: 0x%x fsb: %d maxFID: 0x%x startvid: 0x%x\n", pst->cpuid, pst->fsbspeed, pst->maxfid, pst->startvid); } @@ -474,20 +469,20 @@ static int powernow_decode_bios(int maxfid, int startvid) p = phys_to_virt(i); if (memcmp(p, "AMDK7PNOW!", 10) == 0) { - dprintk("Found PSB header at %p\n", p); + pr_debug("Found PSB header at %p\n", p); psb = (struct psb_s *) p; - dprintk("Table version: 0x%x\n", psb->tableversion); + pr_debug("Table version: 0x%x\n", psb->tableversion); if (psb->tableversion != 0x12) { printk(KERN_INFO PFX "Sorry, only v1.2 tables" " supported right now\n"); return -ENODEV; } - dprintk("Flags: 0x%x\n", psb->flags); + pr_debug("Flags: 0x%x\n", psb->flags); if ((psb->flags & 1) == 0) - dprintk("Mobile voltage regulator\n"); + pr_debug("Mobile voltage regulator\n"); else - dprintk("Desktop voltage regulator\n"); + pr_debug("Desktop voltage regulator\n"); latency = psb->settlingtime; if (latency < 100) { @@ -497,9 +492,9 @@ static int powernow_decode_bios(int maxfid, int startvid) "Correcting.\n", latency); latency = 100; } - dprintk("Settling Time: %d microseconds.\n", + pr_debug("Settling Time: %d microseconds.\n", psb->settlingtime); - dprintk("Has %d PST tables. (Only dumping ones " + pr_debug("Has %d PST tables. (Only dumping ones " "relevant to this CPU).\n", psb->numpst); @@ -650,7 +645,7 @@ static int __cpuinit powernow_cpu_init(struct cpufreq_policy *policy) printk(KERN_WARNING PFX "can not determine bus frequency\n"); return -EINVAL; } - dprintk("FSB: %3dMHz\n", fsb/1000); + pr_debug("FSB: %3dMHz\n", fsb/1000); if (dmi_check_system(powernow_dmi_table) || acpi_force) { printk(KERN_INFO PFX "PSB/PST known to be broken. " diff --git a/arch/x86/kernel/cpu/cpufreq/powernow-k8.c b/arch/x86/kernel/cpu/cpufreq/powernow-k8.c index 2368e38..83479b6 100644 --- a/arch/x86/kernel/cpu/cpufreq/powernow-k8.c +++ b/arch/x86/kernel/cpu/cpufreq/powernow-k8.c @@ -139,7 +139,7 @@ static int query_current_values_with_pending_wait(struct powernow_k8_data *data) } do { if (i++ > 10000) { - dprintk("detected change pending stuck\n"); + pr_debug("detected change pending stuck\n"); return 1; } rdmsr(MSR_FIDVID_STATUS, lo, hi); @@ -176,7 +176,7 @@ static void fidvid_msr_init(void) fid = lo & MSR_S_LO_CURRENT_FID; lo = fid | (vid << MSR_C_LO_VID_SHIFT); hi = MSR_C_HI_STP_GNT_BENIGN; - dprintk("cpu%d, init lo 0x%x, hi 0x%x\n", smp_processor_id(), lo, hi); + pr_debug("cpu%d, init lo 0x%x, hi 0x%x\n", smp_processor_id(), lo, hi); wrmsr(MSR_FIDVID_CTL, lo, hi); } @@ -196,7 +196,7 @@ static int write_new_fid(struct powernow_k8_data *data, u32 fid) lo |= (data->currvid << MSR_C_LO_VID_SHIFT); lo |= MSR_C_LO_INIT_FID_VID; - dprintk("writing fid 0x%x, lo 0x%x, hi 0x%x\n", + pr_debug("writing fid 0x%x, lo 0x%x, hi 0x%x\n", fid, lo, data->plllock * PLL_LOCK_CONVERSION); do { @@ -244,7 +244,7 @@ static int write_new_vid(struct powernow_k8_data *data, u32 vid) lo |= (vid << MSR_C_LO_VID_SHIFT); lo |= MSR_C_LO_INIT_FID_VID; - dprintk("writing vid 0x%x, lo 0x%x, hi 0x%x\n", + pr_debug("writing vid 0x%x, lo 0x%x, hi 0x%x\n", vid, lo, STOP_GRANT_5NS); do { @@ -325,7 +325,7 @@ static int transition_fid_vid(struct powernow_k8_data *data, return 1; } - dprintk("transitioned (cpu%d): new fid 0x%x, vid 0x%x\n", + pr_debug("transitioned (cpu%d): new fid 0x%x, vid 0x%x\n", smp_processor_id(), data->currfid, data->currvid); return 0; @@ -339,7 +339,7 @@ static int core_voltage_pre_transition(struct powernow_k8_data *data, u32 savefid = data->currfid; u32 maxvid, lo, rvomult = 1; - dprintk("ph1 (cpu%d): start, currfid 0x%x, currvid 0x%x, " + pr_debug("ph1 (cpu%d): start, currfid 0x%x, currvid 0x%x, " "reqvid 0x%x, rvo 0x%x\n", smp_processor_id(), data->currfid, data->currvid, reqvid, data->rvo); @@ -349,12 +349,12 @@ static int core_voltage_pre_transition(struct powernow_k8_data *data, rvosteps *= rvomult; rdmsr(MSR_FIDVID_STATUS, lo, maxvid); maxvid = 0x1f & (maxvid >> 16); - dprintk("ph1 maxvid=0x%x\n", maxvid); + pr_debug("ph1 maxvid=0x%x\n", maxvid); if (reqvid < maxvid) /* lower numbers are higher voltages */ reqvid = maxvid; while (data->currvid > reqvid) { - dprintk("ph1: curr 0x%x, req vid 0x%x\n", + pr_debug("ph1: curr 0x%x, req vid 0x%x\n", data->currvid, reqvid); if (decrease_vid_code_by_step(data, reqvid, data->vidmvs)) return 1; @@ -365,7 +365,7 @@ static int core_voltage_pre_transition(struct powernow_k8_data *data, if (data->currvid == maxvid) { rvosteps = 0; } else { - dprintk("ph1: changing vid for rvo, req 0x%x\n", + pr_debug("ph1: changing vid for rvo, req 0x%x\n", data->currvid - 1); if (decrease_vid_code_by_step(data, data->currvid-1, 1)) return 1; @@ -382,7 +382,7 @@ static int core_voltage_pre_transition(struct powernow_k8_data *data, return 1; } - dprintk("ph1 complete, currfid 0x%x, currvid 0x%x\n", + pr_debug("ph1 complete, currfid 0x%x, currvid 0x%x\n", data->currfid, data->currvid); return 0; @@ -400,7 +400,7 @@ static int core_frequency_transition(struct powernow_k8_data *data, u32 reqfid) return 0; } - dprintk("ph2 (cpu%d): starting, currfid 0x%x, currvid 0x%x, " + pr_debug("ph2 (cpu%d): starting, currfid 0x%x, currvid 0x%x, " "reqfid 0x%x\n", smp_processor_id(), data->currfid, data->currvid, reqfid); @@ -457,7 +457,7 @@ static int core_frequency_transition(struct powernow_k8_data *data, u32 reqfid) return 1; } - dprintk("ph2 complete, currfid 0x%x, currvid 0x%x\n", + pr_debug("ph2 complete, currfid 0x%x, currvid 0x%x\n", data->currfid, data->currvid); return 0; @@ -470,7 +470,7 @@ static int core_voltage_post_transition(struct powernow_k8_data *data, u32 savefid = data->currfid; u32 savereqvid = reqvid; - dprintk("ph3 (cpu%d): starting, currfid 0x%x, currvid 0x%x\n", + pr_debug("ph3 (cpu%d): starting, currfid 0x%x, currvid 0x%x\n", smp_processor_id(), data->currfid, data->currvid); @@ -498,17 +498,17 @@ static int core_voltage_post_transition(struct powernow_k8_data *data, return 1; if (savereqvid != data->currvid) { - dprintk("ph3 failed, currvid 0x%x\n", data->currvid); + pr_debug("ph3 failed, currvid 0x%x\n", data->currvid); return 1; } if (savefid != data->currfid) { - dprintk("ph3 failed, currfid changed 0x%x\n", + pr_debug("ph3 failed, currfid changed 0x%x\n", data->currfid); return 1; } - dprintk("ph3 complete, currfid 0x%x, currvid 0x%x\n", + pr_debug("ph3 complete, currfid 0x%x, currvid 0x%x\n", data->currfid, data->currvid); return 0; @@ -707,7 +707,7 @@ static int fill_powernow_table(struct powernow_k8_data *data, return -EIO; } - dprintk("cfid 0x%x, cvid 0x%x\n", data->currfid, data->currvid); + pr_debug("cfid 0x%x, cvid 0x%x\n", data->currfid, data->currvid); data->powernow_table = powernow_table; if (cpumask_first(cpu_core_mask(data->cpu)) == data->cpu) print_basics(data); @@ -717,7 +717,7 @@ static int fill_powernow_table(struct powernow_k8_data *data, (pst[j].vid == data->currvid)) return 0; - dprintk("currfid/vid do not match PST, ignoring\n"); + pr_debug("currfid/vid do not match PST, ignoring\n"); return 0; } @@ -739,36 +739,36 @@ static int find_psb_table(struct powernow_k8_data *data) if (memcmp(psb, PSB_ID_STRING, PSB_ID_STRING_LEN) != 0) continue; - dprintk("found PSB header at 0x%p\n", psb); + pr_debug("found PSB header at 0x%p\n", psb); - dprintk("table vers: 0x%x\n", psb->tableversion); + pr_debug("table vers: 0x%x\n", psb->tableversion); if (psb->tableversion != PSB_VERSION_1_4) { printk(KERN_ERR FW_BUG PFX "PSB table is not v1.4\n"); return -ENODEV; } - dprintk("flags: 0x%x\n", psb->flags1); + pr_debug("flags: 0x%x\n", psb->flags1); if (psb->flags1) { printk(KERN_ERR FW_BUG PFX "unknown flags\n"); return -ENODEV; } data->vstable = psb->vstable; - dprintk("voltage stabilization time: %d(*20us)\n", + pr_debug("voltage stabilization time: %d(*20us)\n", data->vstable); - dprintk("flags2: 0x%x\n", psb->flags2); + pr_debug("flags2: 0x%x\n", psb->flags2); data->rvo = psb->flags2 & 3; data->irt = ((psb->flags2) >> 2) & 3; mvs = ((psb->flags2) >> 4) & 3; data->vidmvs = 1 << mvs; data->batps = ((psb->flags2) >> 6) & 3; - dprintk("ramp voltage offset: %d\n", data->rvo); - dprintk("isochronous relief time: %d\n", data->irt); - dprintk("maximum voltage step: %d - 0x%x\n", mvs, data->vidmvs); + pr_debug("ramp voltage offset: %d\n", data->rvo); + pr_debug("isochronous relief time: %d\n", data->irt); + pr_debug("maximum voltage step: %d - 0x%x\n", mvs, data->vidmvs); - dprintk("numpst: 0x%x\n", psb->num_tables); + pr_debug("numpst: 0x%x\n", psb->num_tables); cpst = psb->num_tables; if ((psb->cpuid == 0x00000fc0) || (psb->cpuid == 0x00000fe0)) { @@ -783,13 +783,13 @@ static int find_psb_table(struct powernow_k8_data *data) } data->plllock = psb->plllocktime; - dprintk("plllocktime: 0x%x (units 1us)\n", psb->plllocktime); - dprintk("maxfid: 0x%x\n", psb->maxfid); - dprintk("maxvid: 0x%x\n", psb->maxvid); + pr_debug("plllocktime: 0x%x (units 1us)\n", psb->plllocktime); + pr_debug("maxfid: 0x%x\n", psb->maxfid); + pr_debug("maxvid: 0x%x\n", psb->maxvid); maxvid = psb->maxvid; data->numps = psb->numps; - dprintk("numpstates: 0x%x\n", data->numps); + pr_debug("numpstates: 0x%x\n", data->numps); return fill_powernow_table(data, (struct pst_s *)(psb+1), maxvid); } @@ -834,13 +834,13 @@ static int powernow_k8_cpu_init_acpi(struct powernow_k8_data *data) u64 control, status; if (acpi_processor_register_performance(&data->acpi_data, data->cpu)) { - dprintk("register performance failed: bad ACPI data\n"); + pr_debug("register performance failed: bad ACPI data\n"); return -EIO; } /* verify the data contained in the ACPI structures */ if (data->acpi_data.state_count <= 1) { - dprintk("No ACPI P-States\n"); + pr_debug("No ACPI P-States\n"); goto err_out; } @@ -849,7 +849,7 @@ static int powernow_k8_cpu_init_acpi(struct powernow_k8_data *data) if ((control != ACPI_ADR_SPACE_FIXED_HARDWARE) || (status != ACPI_ADR_SPACE_FIXED_HARDWARE)) { - dprintk("Invalid control/status registers (%x - %x)\n", + pr_debug("Invalid control/status registers (%llx - %llx)\n", control, status); goto err_out; } @@ -858,7 +858,7 @@ static int powernow_k8_cpu_init_acpi(struct powernow_k8_data *data) powernow_table = kmalloc((sizeof(struct cpufreq_frequency_table) * (data->acpi_data.state_count + 1)), GFP_KERNEL); if (!powernow_table) { - dprintk("powernow_table memory alloc failure\n"); + pr_debug("powernow_table memory alloc failure\n"); goto err_out; } @@ -928,7 +928,7 @@ static int fill_powernow_table_pstate(struct powernow_k8_data *data, } rdmsr(MSR_PSTATE_DEF_BASE + index, lo, hi); if (!(hi & HW_PSTATE_VALID_MASK)) { - dprintk("invalid pstate %d, ignoring\n", index); + pr_debug("invalid pstate %d, ignoring\n", index); invalidate_entry(powernow_table, i); continue; } @@ -968,7 +968,7 @@ static int fill_powernow_table_fidvid(struct powernow_k8_data *data, vid = (control >> VID_SHIFT) & VID_MASK; } - dprintk(" %d : fid 0x%x, vid 0x%x\n", i, fid, vid); + pr_debug(" %d : fid 0x%x, vid 0x%x\n", i, fid, vid); index = fid | (vid<<8); powernow_table[i].index = index; @@ -978,7 +978,7 @@ static int fill_powernow_table_fidvid(struct powernow_k8_data *data, /* verify frequency is OK */ if ((freq > (MAX_FREQ * 1000)) || (freq < (MIN_FREQ * 1000))) { - dprintk("invalid freq %u kHz, ignoring\n", freq); + pr_debug("invalid freq %u kHz, ignoring\n", freq); invalidate_entry(powernow_table, i); continue; } @@ -986,7 +986,7 @@ static int fill_powernow_table_fidvid(struct powernow_k8_data *data, /* verify voltage is OK - * BIOSs are using "off" to indicate invalid */ if (vid == VID_OFF) { - dprintk("invalid vid %u, ignoring\n", vid); + pr_debug("invalid vid %u, ignoring\n", vid); invalidate_entry(powernow_table, i); continue; } @@ -1047,7 +1047,7 @@ static int transition_frequency_fidvid(struct powernow_k8_data *data, int res, i; struct cpufreq_freqs freqs; - dprintk("cpu %d transition to index %u\n", smp_processor_id(), index); + pr_debug("cpu %d transition to index %u\n", smp_processor_id(), index); /* fid/vid correctness check for k8 */ /* fid are the lower 8 bits of the index we stored into @@ -1057,18 +1057,18 @@ static int transition_frequency_fidvid(struct powernow_k8_data *data, fid = data->powernow_table[index].index & 0xFF; vid = (data->powernow_table[index].index & 0xFF00) >> 8; - dprintk("table matched fid 0x%x, giving vid 0x%x\n", fid, vid); + pr_debug("table matched fid 0x%x, giving vid 0x%x\n", fid, vid); if (query_current_values_with_pending_wait(data)) return 1; if ((data->currvid == vid) && (data->currfid == fid)) { - dprintk("target matches current values (fid 0x%x, vid 0x%x)\n", + pr_debug("target matches current values (fid 0x%x, vid 0x%x)\n", fid, vid); return 0; } - dprintk("cpu %d, changing to fid 0x%x, vid 0x%x\n", + pr_debug("cpu %d, changing to fid 0x%x, vid 0x%x\n", smp_processor_id(), fid, vid); freqs.old = find_khz_freq_from_fid(data->currfid); freqs.new = find_khz_freq_from_fid(fid); @@ -1096,7 +1096,7 @@ static int transition_frequency_pstate(struct powernow_k8_data *data, int res, i; struct cpufreq_freqs freqs; - dprintk("cpu %d transition to index %u\n", smp_processor_id(), index); + pr_debug("cpu %d transition to index %u\n", smp_processor_id(), index); /* get MSR index for hardware pstate transition */ pstate = index & HW_PSTATE_MASK; @@ -1156,14 +1156,14 @@ static int powernowk8_target(struct cpufreq_policy *pol, goto err_out; } - dprintk("targ: cpu %d, %d kHz, min %d, max %d, relation %d\n", + pr_debug("targ: cpu %d, %d kHz, min %d, max %d, relation %d\n", pol->cpu, targfreq, pol->min, pol->max, relation); if (query_current_values_with_pending_wait(data)) goto err_out; if (cpu_family != CPU_HW_PSTATE) { - dprintk("targ: curr fid 0x%x, vid 0x%x\n", + pr_debug("targ: curr fid 0x%x, vid 0x%x\n", data->currfid, data->currvid); if ((checkvid != data->currvid) || @@ -1319,7 +1319,7 @@ static int __cpuinit powernowk8_cpu_init(struct cpufreq_policy *pol) data->currpstate); else pol->cur = find_khz_freq_from_fid(data->currfid); - dprintk("policy current frequency %d kHz\n", pol->cur); + pr_debug("policy current frequency %d kHz\n", pol->cur); /* min/max the cpu is capable of */ if (cpufreq_frequency_table_cpuinfo(pol, data->powernow_table)) { @@ -1337,10 +1337,10 @@ static int __cpuinit powernowk8_cpu_init(struct cpufreq_policy *pol) cpufreq_frequency_table_get_attr(data->powernow_table, pol->cpu); if (cpu_family == CPU_HW_PSTATE) - dprintk("cpu_init done, current pstate 0x%x\n", + pr_debug("cpu_init done, current pstate 0x%x\n", data->currpstate); else - dprintk("cpu_init done, current fid 0x%x, vid 0x%x\n", + pr_debug("cpu_init done, current fid 0x%x, vid 0x%x\n", data->currfid, data->currvid); per_cpu(powernow_data, pol->cpu) = data; @@ -1586,7 +1586,7 @@ static int __cpuinit powernowk8_init(void) /* driver entry point for term */ static void __exit powernowk8_exit(void) { - dprintk("exit\n"); + pr_debug("exit\n"); if (boot_cpu_has(X86_FEATURE_CPB)) { msrs_free(msrs); diff --git a/arch/x86/kernel/cpu/cpufreq/powernow-k8.h b/arch/x86/kernel/cpu/cpufreq/powernow-k8.h index df3529b..3744d26 100644 --- a/arch/x86/kernel/cpu/cpufreq/powernow-k8.h +++ b/arch/x86/kernel/cpu/cpufreq/powernow-k8.h @@ -211,8 +211,6 @@ struct pst_s { u8 vid; }; -#define dprintk(msg...) cpufreq_debug_printk(CPUFREQ_DEBUG_DRIVER, "powernow-k8", msg) - static int core_voltage_pre_transition(struct powernow_k8_data *data, u32 reqvid, u32 regfid); static int core_voltage_post_transition(struct powernow_k8_data *data, u32 reqvid); diff --git a/arch/x86/kernel/cpu/cpufreq/sc520_freq.c b/arch/x86/kernel/cpu/cpufreq/sc520_freq.c index 435a996..1e205e6 100644 --- a/arch/x86/kernel/cpu/cpufreq/sc520_freq.c +++ b/arch/x86/kernel/cpu/cpufreq/sc520_freq.c @@ -29,8 +29,6 @@ static __u8 __iomem *cpuctl; -#define dprintk(msg...) cpufreq_debug_printk(CPUFREQ_DEBUG_DRIVER, \ - "sc520_freq", msg) #define PFX "sc520_freq: " static struct cpufreq_frequency_table sc520_freq_table[] = { @@ -66,7 +64,7 @@ static void sc520_freq_set_cpu_state(unsigned int state) cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE); - dprintk("attempting to set frequency to %i kHz\n", + pr_debug("attempting to set frequency to %i kHz\n", sc520_freq_table[state].frequency); local_irq_disable(); @@ -161,7 +159,7 @@ static int __init sc520_freq_init(void) /* Test if we have the right hardware */ if (c->x86_vendor != X86_VENDOR_AMD || c->x86 != 4 || c->x86_model != 9) { - dprintk("no Elan SC520 processor found!\n"); + pr_debug("no Elan SC520 processor found!\n"); return -ENODEV; } cpuctl = ioremap((unsigned long)(MMCR_BASE + OFFS_CPUCTL), 1); diff --git a/arch/x86/kernel/cpu/cpufreq/speedstep-centrino.c b/arch/x86/kernel/cpu/cpufreq/speedstep-centrino.c index 9b1ff37..6ea3455 100644 --- a/arch/x86/kernel/cpu/cpufreq/speedstep-centrino.c +++ b/arch/x86/kernel/cpu/cpufreq/speedstep-centrino.c @@ -29,9 +29,6 @@ #define PFX "speedstep-centrino: " #define MAINTAINER "cpufreq@vger.kernel.org" -#define dprintk(msg...) \ - cpufreq_debug_printk(CPUFREQ_DEBUG_DRIVER, "speedstep-centrino", msg) - #define INTEL_MSR_RANGE (0xffff) struct cpu_id @@ -244,7 +241,7 @@ static int centrino_cpu_init_table(struct cpufreq_policy *policy) if (model->cpu_id == NULL) { /* No match at all */ - dprintk("no support for CPU model \"%s\": " + pr_debug("no support for CPU model \"%s\": " "send /proc/cpuinfo to " MAINTAINER "\n", cpu->x86_model_id); return -ENOENT; @@ -252,15 +249,15 @@ static int centrino_cpu_init_table(struct cpufreq_policy *policy) if (model->op_points == NULL) { /* Matched a non-match */ - dprintk("no table support for CPU model \"%s\"\n", + pr_debug("no table support for CPU model \"%s\"\n", cpu->x86_model_id); - dprintk("try using the acpi-cpufreq driver\n"); + pr_debug("try using the acpi-cpufreq driver\n"); return -ENOENT; } per_cpu(centrino_model, policy->cpu) = model; - dprintk("found \"%s\": max frequency: %dkHz\n", + pr_debug("found \"%s\": max frequency: %dkHz\n", model->model_name, model->max_freq); return 0; @@ -369,7 +366,7 @@ static int centrino_cpu_init(struct cpufreq_policy *policy) per_cpu(centrino_cpu, policy->cpu) = &cpu_ids[i]; if (!per_cpu(centrino_cpu, policy->cpu)) { - dprintk("found unsupported CPU with " + pr_debug("found unsupported CPU with " "Enhanced SpeedStep: send /proc/cpuinfo to " MAINTAINER "\n"); return -ENODEV; @@ -385,7 +382,7 @@ static int centrino_cpu_init(struct cpufreq_policy *policy) if (!(l & MSR_IA32_MISC_ENABLE_ENHANCED_SPEEDSTEP)) { l |= MSR_IA32_MISC_ENABLE_ENHANCED_SPEEDSTEP; - dprintk("trying to enable Enhanced SpeedStep (%x)\n", l); + pr_debug("trying to enable Enhanced SpeedStep (%x)\n", l); wrmsr(MSR_IA32_MISC_ENABLE, l, h); /* check to see if it stuck */ @@ -402,7 +399,7 @@ static int centrino_cpu_init(struct cpufreq_policy *policy) /* 10uS transition latency */ policy->cur = freq; - dprintk("centrino_cpu_init: cur=%dkHz\n", policy->cur); + pr_debug("centrino_cpu_init: cur=%dkHz\n", policy->cur); ret = cpufreq_frequency_table_cpuinfo(policy, per_cpu(centrino_model, policy->cpu)->op_points); @@ -498,7 +495,7 @@ static int centrino_target (struct cpufreq_policy *policy, good_cpu = j; if (good_cpu >= nr_cpu_ids) { - dprintk("couldn't limit to CPUs in this domain\n"); + pr_debug("couldn't limit to CPUs in this domain\n"); retval = -EAGAIN; if (first_cpu) { /* We haven't started the transition yet. */ @@ -512,7 +509,7 @@ static int centrino_target (struct cpufreq_policy *policy, if (first_cpu) { rdmsr_on_cpu(good_cpu, MSR_IA32_PERF_CTL, &oldmsr, &h); if (msr == (oldmsr & 0xffff)) { - dprintk("no change needed - msr was and needs " + pr_debug("no change needed - msr was and needs " "to be %x\n", oldmsr); retval = 0; goto out; @@ -521,7 +518,7 @@ static int centrino_target (struct cpufreq_policy *policy, freqs.old = extract_clock(oldmsr, cpu, 0); freqs.new = extract_clock(msr, cpu, 0); - dprintk("target=%dkHz old=%d new=%d msr=%04x\n", + pr_debug("target=%dkHz old=%d new=%d msr=%04x\n", target_freq, freqs.old, freqs.new, msr); for_each_cpu(k, policy->cpus) { diff --git a/arch/x86/kernel/cpu/cpufreq/speedstep-ich.c b/arch/x86/kernel/cpu/cpufreq/speedstep-ich.c index 561758e..a748ce7 100644 --- a/arch/x86/kernel/cpu/cpufreq/speedstep-ich.c +++ b/arch/x86/kernel/cpu/cpufreq/speedstep-ich.c @@ -53,10 +53,6 @@ static struct cpufreq_frequency_table speedstep_freqs[] = { }; -#define dprintk(msg...) cpufreq_debug_printk(CPUFREQ_DEBUG_DRIVER, \ - "speedstep-ich", msg) - - /** * speedstep_find_register - read the PMBASE address * @@ -80,7 +76,7 @@ static int speedstep_find_register(void) return -ENODEV; } - dprintk("pmbase is 0x%x\n", pmbase); + pr_debug("pmbase is 0x%x\n", pmbase); return 0; } @@ -106,13 +102,13 @@ static void speedstep_set_state(unsigned int state) /* read state */ value = inb(pmbase + 0x50); - dprintk("read at pmbase 0x%x + 0x50 returned 0x%x\n", pmbase, value); + pr_debug("read at pmbase 0x%x + 0x50 returned 0x%x\n", pmbase, value); /* write new state */ value &= 0xFE; value |= state; - dprintk("writing 0x%x to pmbase 0x%x + 0x50\n", value, pmbase); + pr_debug("writing 0x%x to pmbase 0x%x + 0x50\n", value, pmbase); /* Disable bus master arbitration */ pm2_blk = inb(pmbase + 0x20); @@ -132,10 +128,10 @@ static void speedstep_set_state(unsigned int state) /* Enable IRQs */ local_irq_restore(flags); - dprintk("read at pmbase 0x%x + 0x50 returned 0x%x\n", pmbase, value); + pr_debug("read at pmbase 0x%x + 0x50 returned 0x%x\n", pmbase, value); if (state == (value & 0x1)) - dprintk("change to %u MHz succeeded\n", + pr_debug("change to %u MHz succeeded\n", speedstep_get_frequency(speedstep_processor) / 1000); else printk(KERN_ERR "cpufreq: change failed - I/O error\n"); @@ -165,7 +161,7 @@ static int speedstep_activate(void) pci_read_config_word(speedstep_chipset_dev, 0x00A0, &value); if (!(value & 0x08)) { value |= 0x08; - dprintk("activating SpeedStep (TM) registers\n"); + pr_debug("activating SpeedStep (TM) registers\n"); pci_write_config_word(speedstep_chipset_dev, 0x00A0, value); } @@ -218,7 +214,7 @@ static unsigned int speedstep_detect_chipset(void) return 2; /* 2-M */ if (hostbridge->revision < 5) { - dprintk("hostbridge does not support speedstep\n"); + pr_debug("hostbridge does not support speedstep\n"); speedstep_chipset_dev = NULL; pci_dev_put(hostbridge); return 0; @@ -246,7 +242,7 @@ static unsigned int speedstep_get(unsigned int cpu) if (smp_call_function_single(cpu, get_freq_data, &speed, 1) != 0) BUG(); - dprintk("detected %u kHz as current frequency\n", speed); + pr_debug("detected %u kHz as current frequency\n", speed); return speed; } @@ -276,7 +272,7 @@ static int speedstep_target(struct cpufreq_policy *policy, freqs.new = speedstep_freqs[newstate].frequency; freqs.cpu = policy->cpu; - dprintk("transiting from %u to %u kHz\n", freqs.old, freqs.new); + pr_debug("transiting from %u to %u kHz\n", freqs.old, freqs.new); /* no transition necessary */ if (freqs.old == freqs.new) @@ -351,7 +347,7 @@ static int speedstep_cpu_init(struct cpufreq_policy *policy) if (!speed) return -EIO; - dprintk("currently at %s speed setting - %i MHz\n", + pr_debug("currently at %s speed setting - %i MHz\n", (speed == speedstep_freqs[SPEEDSTEP_LOW].frequency) ? "low" : "high", (speed / 1000)); @@ -405,14 +401,14 @@ static int __init speedstep_init(void) /* detect processor */ speedstep_processor = speedstep_detect_processor(); if (!speedstep_processor) { - dprintk("Intel(R) SpeedStep(TM) capable processor " + pr_debug("Intel(R) SpeedStep(TM) capable processor " "not found\n"); return -ENODEV; } /* detect chipset */ if (!speedstep_detect_chipset()) { - dprintk("Intel(R) SpeedStep(TM) for this chipset not " + pr_debug("Intel(R) SpeedStep(TM) for this chipset not " "(yet) available.\n"); return -ENODEV; } diff --git a/arch/x86/kernel/cpu/cpufreq/speedstep-lib.c b/arch/x86/kernel/cpu/cpufreq/speedstep-lib.c index a94ec6b..8af2d2f 100644 --- a/arch/x86/kernel/cpu/cpufreq/speedstep-lib.c +++ b/arch/x86/kernel/cpu/cpufreq/speedstep-lib.c @@ -18,9 +18,6 @@ #include #include "speedstep-lib.h" -#define dprintk(msg...) cpufreq_debug_printk(CPUFREQ_DEBUG_DRIVER, \ - "speedstep-lib", msg) - #define PFX "speedstep-lib: " #ifdef CONFIG_X86_SPEEDSTEP_RELAXED_CAP_CHECK @@ -75,7 +72,7 @@ static unsigned int pentium3_get_frequency(enum speedstep_processor processor) /* read MSR 0x2a - we only need the low 32 bits */ rdmsr(MSR_IA32_EBL_CR_POWERON, msr_lo, msr_tmp); - dprintk("P3 - MSR_IA32_EBL_CR_POWERON: 0x%x 0x%x\n", msr_lo, msr_tmp); + pr_debug("P3 - MSR_IA32_EBL_CR_POWERON: 0x%x 0x%x\n", msr_lo, msr_tmp); msr_tmp = msr_lo; /* decode the FSB */ @@ -89,7 +86,7 @@ static unsigned int pentium3_get_frequency(enum speedstep_processor processor) /* decode the multiplier */ if (processor == SPEEDSTEP_CPU_PIII_C_EARLY) { - dprintk("workaround for early PIIIs\n"); + pr_debug("workaround for early PIIIs\n"); msr_lo &= 0x03c00000; } else msr_lo &= 0x0bc00000; @@ -100,7 +97,7 @@ static unsigned int pentium3_get_frequency(enum speedstep_processor processor) j++; } - dprintk("speed is %u\n", + pr_debug("speed is %u\n", (msr_decode_mult[j].ratio * msr_decode_fsb[i].value * 100)); return msr_decode_mult[j].ratio * msr_decode_fsb[i].value * 100; @@ -112,7 +109,7 @@ static unsigned int pentiumM_get_frequency(void) u32 msr_lo, msr_tmp; rdmsr(MSR_IA32_EBL_CR_POWERON, msr_lo, msr_tmp); - dprintk("PM - MSR_IA32_EBL_CR_POWERON: 0x%x 0x%x\n", msr_lo, msr_tmp); + pr_debug("PM - MSR_IA32_EBL_CR_POWERON: 0x%x 0x%x\n", msr_lo, msr_tmp); /* see table B-2 of 24547212.pdf */ if (msr_lo & 0x00040000) { @@ -122,7 +119,7 @@ static unsigned int pentiumM_get_frequency(void) } msr_tmp = (msr_lo >> 22) & 0x1f; - dprintk("bits 22-26 are 0x%x, speed is %u\n", + pr_debug("bits 22-26 are 0x%x, speed is %u\n", msr_tmp, (msr_tmp * 100 * 1000)); return msr_tmp * 100 * 1000; @@ -160,11 +157,11 @@ static unsigned int pentium_core_get_frequency(void) } rdmsr(MSR_IA32_EBL_CR_POWERON, msr_lo, msr_tmp); - dprintk("PCORE - MSR_IA32_EBL_CR_POWERON: 0x%x 0x%x\n", + pr_debug("PCORE - MSR_IA32_EBL_CR_POWERON: 0x%x 0x%x\n", msr_lo, msr_tmp); msr_tmp = (msr_lo >> 22) & 0x1f; - dprintk("bits 22-26 are 0x%x, speed is %u\n", + pr_debug("bits 22-26 are 0x%x, speed is %u\n", msr_tmp, (msr_tmp * fsb)); ret = (msr_tmp * fsb); @@ -190,7 +187,7 @@ static unsigned int pentium4_get_frequency(void) rdmsr(0x2c, msr_lo, msr_hi); - dprintk("P4 - MSR_EBC_FREQUENCY_ID: 0x%x 0x%x\n", msr_lo, msr_hi); + pr_debug("P4 - MSR_EBC_FREQUENCY_ID: 0x%x 0x%x\n", msr_lo, msr_hi); /* decode the FSB: see IA-32 Intel (C) Architecture Software * Developer's Manual, Volume 3: System Prgramming Guide, @@ -217,7 +214,7 @@ static unsigned int pentium4_get_frequency(void) /* Multiplier. */ mult = msr_lo >> 24; - dprintk("P4 - FSB %u kHz; Multiplier %u; Speed %u kHz\n", + pr_debug("P4 - FSB %u kHz; Multiplier %u; Speed %u kHz\n", fsb, mult, (fsb * mult)); ret = (fsb * mult); @@ -257,7 +254,7 @@ unsigned int speedstep_detect_processor(void) struct cpuinfo_x86 *c = &cpu_data(0); u32 ebx, msr_lo, msr_hi; - dprintk("x86: %x, model: %x\n", c->x86, c->x86_model); + pr_debug("x86: %x, model: %x\n", c->x86, c->x86_model); if ((c->x86_vendor != X86_VENDOR_INTEL) || ((c->x86 != 6) && (c->x86 != 0xF))) @@ -272,7 +269,7 @@ unsigned int speedstep_detect_processor(void) ebx = cpuid_ebx(0x00000001); ebx &= 0x000000FF; - dprintk("ebx value is %x, x86_mask is %x\n", ebx, c->x86_mask); + pr_debug("ebx value is %x, x86_mask is %x\n", ebx, c->x86_mask); switch (c->x86_mask) { case 4: @@ -327,7 +324,7 @@ unsigned int speedstep_detect_processor(void) /* cpuid_ebx(1) is 0x04 for desktop PIII, * 0x06 for mobile PIII-M */ ebx = cpuid_ebx(0x00000001); - dprintk("ebx is %x\n", ebx); + pr_debug("ebx is %x\n", ebx); ebx &= 0x000000FF; @@ -344,7 +341,7 @@ unsigned int speedstep_detect_processor(void) /* all mobile PIII Coppermines have FSB 100 MHz * ==> sort out a few desktop PIIIs. */ rdmsr(MSR_IA32_EBL_CR_POWERON, msr_lo, msr_hi); - dprintk("Coppermine: MSR_IA32_EBL_CR_POWERON is 0x%x, 0x%x\n", + pr_debug("Coppermine: MSR_IA32_EBL_CR_POWERON is 0x%x, 0x%x\n", msr_lo, msr_hi); msr_lo &= 0x00c0000; if (msr_lo != 0x0080000) @@ -357,12 +354,12 @@ unsigned int speedstep_detect_processor(void) * bit 56 or 57 is set */ rdmsr(MSR_IA32_PLATFORM_ID, msr_lo, msr_hi); - dprintk("Coppermine: MSR_IA32_PLATFORM ID is 0x%x, 0x%x\n", + pr_debug("Coppermine: MSR_IA32_PLATFORM ID is 0x%x, 0x%x\n", msr_lo, msr_hi); if ((msr_hi & (1<<18)) && (relaxed_check ? 1 : (msr_hi & (3<<24)))) { if (c->x86_mask == 0x01) { - dprintk("early PIII version\n"); + pr_debug("early PIII version\n"); return SPEEDSTEP_CPU_PIII_C_EARLY; } else return SPEEDSTEP_CPU_PIII_C; @@ -393,14 +390,14 @@ unsigned int speedstep_get_freqs(enum speedstep_processor processor, if ((!processor) || (!low_speed) || (!high_speed) || (!set_state)) return -EINVAL; - dprintk("trying to determine both speeds\n"); + pr_debug("trying to determine both speeds\n"); /* get current speed */ prev_speed = speedstep_get_frequency(processor); if (!prev_speed) return -EIO; - dprintk("previous speed is %u\n", prev_speed); + pr_debug("previous speed is %u\n", prev_speed); local_irq_save(flags); @@ -412,7 +409,7 @@ unsigned int speedstep_get_freqs(enum speedstep_processor processor, goto out; } - dprintk("low speed is %u\n", *low_speed); + pr_debug("low speed is %u\n", *low_speed); /* start latency measurement */ if (transition_latency) @@ -431,7 +428,7 @@ unsigned int speedstep_get_freqs(enum speedstep_processor processor, goto out; } - dprintk("high speed is %u\n", *high_speed); + pr_debug("high speed is %u\n", *high_speed); if (*low_speed == *high_speed) { ret = -ENODEV; @@ -445,7 +442,7 @@ unsigned int speedstep_get_freqs(enum speedstep_processor processor, if (transition_latency) { *transition_latency = (tv2.tv_sec - tv1.tv_sec) * USEC_PER_SEC + tv2.tv_usec - tv1.tv_usec; - dprintk("transition latency is %u uSec\n", *transition_latency); + pr_debug("transition latency is %u uSec\n", *transition_latency); /* convert uSec to nSec and add 20% for safety reasons */ *transition_latency *= 1200; diff --git a/arch/x86/kernel/cpu/cpufreq/speedstep-smi.c b/arch/x86/kernel/cpu/cpufreq/speedstep-smi.c index 91bc25b..c76ead3 100644 --- a/arch/x86/kernel/cpu/cpufreq/speedstep-smi.c +++ b/arch/x86/kernel/cpu/cpufreq/speedstep-smi.c @@ -55,9 +55,6 @@ static struct cpufreq_frequency_table speedstep_freqs[] = { * of DMA activity going on? */ #define SMI_TRIES 5 -#define dprintk(msg...) cpufreq_debug_printk(CPUFREQ_DEBUG_DRIVER, \ - "speedstep-smi", msg) - /** * speedstep_smi_ownership */ @@ -70,7 +67,7 @@ static int speedstep_smi_ownership(void) command = (smi_sig & 0xffffff00) | (smi_cmd & 0xff); magic = virt_to_phys(magic_data); - dprintk("trying to obtain ownership with command %x at port %x\n", + pr_debug("trying to obtain ownership with command %x at port %x\n", command, smi_port); __asm__ __volatile__( @@ -85,7 +82,7 @@ static int speedstep_smi_ownership(void) : "memory" ); - dprintk("result is %x\n", result); + pr_debug("result is %x\n", result); return result; } @@ -106,13 +103,13 @@ static int speedstep_smi_get_freqs(unsigned int *low, unsigned int *high) u32 function = GET_SPEEDSTEP_FREQS; if (!(ist_info.event & 0xFFFF)) { - dprintk("bug #1422 -- can't read freqs from BIOS\n"); + pr_debug("bug #1422 -- can't read freqs from BIOS\n"); return -ENODEV; } command = (smi_sig & 0xffffff00) | (smi_cmd & 0xff); - dprintk("trying to determine frequencies with command %x at port %x\n", + pr_debug("trying to determine frequencies with command %x at port %x\n", command, smi_port); __asm__ __volatile__( @@ -129,7 +126,7 @@ static int speedstep_smi_get_freqs(unsigned int *low, unsigned int *high) "d" (smi_port), "S" (0), "D" (0) ); - dprintk("result %x, low_freq %u, high_freq %u\n", + pr_debug("result %x, low_freq %u, high_freq %u\n", result, low_mhz, high_mhz); /* abort if results are obviously incorrect... */ @@ -154,7 +151,7 @@ static int speedstep_get_state(void) command = (smi_sig & 0xffffff00) | (smi_cmd & 0xff); - dprintk("trying to determine current setting with command %x " + pr_debug("trying to determine current setting with command %x " "at port %x\n", command, smi_port); __asm__ __volatile__( @@ -168,7 +165,7 @@ static int speedstep_get_state(void) "d" (smi_port), "S" (0), "D" (0) ); - dprintk("state is %x, result is %x\n", state, result); + pr_debug("state is %x, result is %x\n", state, result); return state & 1; } @@ -194,13 +191,13 @@ static void speedstep_set_state(unsigned int state) command = (smi_sig & 0xffffff00) | (smi_cmd & 0xff); - dprintk("trying to set frequency to state %u " + pr_debug("trying to set frequency to state %u " "with command %x at port %x\n", state, command, smi_port); do { if (retry) { - dprintk("retry %u, previous result %u, waiting...\n", + pr_debug("retry %u, previous result %u, waiting...\n", retry, result); mdelay(retry * 50); } @@ -221,7 +218,7 @@ static void speedstep_set_state(unsigned int state) local_irq_restore(flags); if (new_state == state) - dprintk("change to %u MHz succeeded after %u tries " + pr_debug("change to %u MHz succeeded after %u tries " "with result %u\n", (speedstep_freqs[new_state].frequency / 1000), retry, result); @@ -292,7 +289,7 @@ static int speedstep_cpu_init(struct cpufreq_policy *policy) result = speedstep_smi_ownership(); if (result) { - dprintk("fails in acquiring ownership of a SMI interface.\n"); + pr_debug("fails in acquiring ownership of a SMI interface.\n"); return -EINVAL; } @@ -304,7 +301,7 @@ static int speedstep_cpu_init(struct cpufreq_policy *policy) if (result) { /* fall back to speedstep_lib.c dection mechanism: * try both states out */ - dprintk("could not detect low and high frequencies " + pr_debug("could not detect low and high frequencies " "by SMI call.\n"); result = speedstep_get_freqs(speedstep_processor, low, high, @@ -312,18 +309,18 @@ static int speedstep_cpu_init(struct cpufreq_policy *policy) &speedstep_set_state); if (result) { - dprintk("could not detect two different speeds" + pr_debug("could not detect two different speeds" " -- aborting.\n"); return result; } else - dprintk("workaround worked.\n"); + pr_debug("workaround worked.\n"); } /* get current speed setting */ state = speedstep_get_state(); speed = speedstep_freqs[state].frequency; - dprintk("currently at %s speed setting - %i MHz\n", + pr_debug("currently at %s speed setting - %i MHz\n", (speed == speedstep_freqs[SPEEDSTEP_LOW].frequency) ? "low" : "high", (speed / 1000)); @@ -360,7 +357,7 @@ static int speedstep_resume(struct cpufreq_policy *policy) int result = speedstep_smi_ownership(); if (result) - dprintk("fails in re-acquiring ownership of a SMI interface.\n"); + pr_debug("fails in re-acquiring ownership of a SMI interface.\n"); return result; } @@ -403,12 +400,12 @@ static int __init speedstep_init(void) } if (!speedstep_processor) { - dprintk("No supported Intel CPU detected.\n"); + pr_debug("No supported Intel CPU detected.\n"); return -ENODEV; } - dprintk("signature:0x%.8lx, command:0x%.8lx, " - "event:0x%.8lx, perf_level:0x%.8lx.\n", + pr_debug("signature:0x%.8ulx, command:0x%.8ulx, " + "event:0x%.8ulx, perf_level:0x%.8ulx.\n", ist_info.signature, ist_info.command, ist_info.event, ist_info.perf_level); diff --git a/drivers/acpi/processor_perflib.c b/drivers/acpi/processor_perflib.c index 3a73a93..85b3237 100644 --- a/drivers/acpi/processor_perflib.c +++ b/drivers/acpi/processor_perflib.c @@ -49,10 +49,6 @@ ACPI_MODULE_NAME("processor_perflib"); static DEFINE_MUTEX(performance_mutex); -/* Use cpufreq debug layer for _PPC changes. */ -#define cpufreq_printk(msg...) cpufreq_debug_printk(CPUFREQ_DEBUG_CORE, \ - "cpufreq-core", msg) - /* * _PPC support is implemented as a CPUfreq policy notifier: * This means each time a CPUfreq driver registered also with @@ -145,7 +141,7 @@ static int acpi_processor_get_platform_limit(struct acpi_processor *pr) return -ENODEV; } - cpufreq_printk("CPU %d: _PPC is %d - frequency %s limited\n", pr->id, + pr_debug("CPU %d: _PPC is %d - frequency %s limited\n", pr->id, (int)ppc, ppc ? "" : "not"); pr->performance_platform_limit = (int)ppc; diff --git a/drivers/cpufreq/Kconfig b/drivers/cpufreq/Kconfig index ca8ee80..b78baa54 100644 --- a/drivers/cpufreq/Kconfig +++ b/drivers/cpufreq/Kconfig @@ -18,19 +18,6 @@ if CPU_FREQ config CPU_FREQ_TABLE tristate -config CPU_FREQ_DEBUG - bool "Enable CPUfreq debugging" - help - Say Y here to enable CPUfreq subsystem (including drivers) - debugging. You will need to activate it via the kernel - command line by passing - cpufreq.debug= - - To get , add - 1 to activate CPUfreq core debugging, - 2 to activate CPUfreq drivers debugging, and - 4 to activate CPUfreq governor debugging - config CPU_FREQ_STAT tristate "CPU frequency translation statistics" select CPU_FREQ_TABLE diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c index 7c10f96..1e08af4 100644 --- a/drivers/cpufreq/cpufreq.c +++ b/drivers/cpufreq/cpufreq.c @@ -32,9 +32,6 @@ #include -#define dprintk(msg...) cpufreq_debug_printk(CPUFREQ_DEBUG_CORE, \ - "cpufreq-core", msg) - /** * The "cpufreq driver" - the arch- or hardware-dependent low * level driver of CPUFreq support, and its spinlock. This lock @@ -181,93 +178,6 @@ EXPORT_SYMBOL_GPL(cpufreq_cpu_put); /********************************************************************* - * UNIFIED DEBUG HELPERS * - *********************************************************************/ -#ifdef CONFIG_CPU_FREQ_DEBUG - -/* what part(s) of the CPUfreq subsystem are debugged? */ -static unsigned int debug; - -/* is the debug output ratelimit'ed using printk_ratelimit? User can - * set or modify this value. - */ -static unsigned int debug_ratelimit = 1; - -/* is the printk_ratelimit'ing enabled? It's enabled after a successful - * loading of a cpufreq driver, temporarily disabled when a new policy - * is set, and disabled upon cpufreq driver removal - */ -static unsigned int disable_ratelimit = 1; -static DEFINE_SPINLOCK(disable_ratelimit_lock); - -static void cpufreq_debug_enable_ratelimit(void) -{ - unsigned long flags; - - spin_lock_irqsave(&disable_ratelimit_lock, flags); - if (disable_ratelimit) - disable_ratelimit--; - spin_unlock_irqrestore(&disable_ratelimit_lock, flags); -} - -static void cpufreq_debug_disable_ratelimit(void) -{ - unsigned long flags; - - spin_lock_irqsave(&disable_ratelimit_lock, flags); - disable_ratelimit++; - spin_unlock_irqrestore(&disable_ratelimit_lock, flags); -} - -void cpufreq_debug_printk(unsigned int type, const char *prefix, - const char *fmt, ...) -{ - char s[256]; - va_list args; - unsigned int len; - unsigned long flags; - - WARN_ON(!prefix); - if (type & debug) { - spin_lock_irqsave(&disable_ratelimit_lock, flags); - if (!disable_ratelimit && debug_ratelimit - && !printk_ratelimit()) { - spin_unlock_irqrestore(&disable_ratelimit_lock, flags); - return; - } - spin_unlock_irqrestore(&disable_ratelimit_lock, flags); - - len = snprintf(s, 256, KERN_DEBUG "%s: ", prefix); - - va_start(args, fmt); - len += vsnprintf(&s[len], (256 - len), fmt, args); - va_end(args); - - printk(s); - - WARN_ON(len < 5); - } -} -EXPORT_SYMBOL(cpufreq_debug_printk); - - -module_param(debug, uint, 0644); -MODULE_PARM_DESC(debug, "CPUfreq debugging: add 1 to debug core," - " 2 to debug drivers, and 4 to debug governors."); - -module_param(debug_ratelimit, uint, 0644); -MODULE_PARM_DESC(debug_ratelimit, "CPUfreq debugging:" - " set to 0 to disable ratelimiting."); - -#else /* !CONFIG_CPU_FREQ_DEBUG */ - -static inline void cpufreq_debug_enable_ratelimit(void) { return; } -static inline void cpufreq_debug_disable_ratelimit(void) { return; } - -#endif /* CONFIG_CPU_FREQ_DEBUG */ - - -/********************************************************************* * EXTERNALLY AFFECTING FREQUENCY CHANGES * *********************************************************************/ @@ -291,7 +201,7 @@ static void adjust_jiffies(unsigned long val, struct cpufreq_freqs *ci) if (!l_p_j_ref_freq) { l_p_j_ref = loops_per_jiffy; l_p_j_ref_freq = ci->old; - dprintk("saving %lu as reference value for loops_per_jiffy; " + pr_debug("saving %lu as reference value for loops_per_jiffy; " "freq is %u kHz\n", l_p_j_ref, l_p_j_ref_freq); } if ((val == CPUFREQ_PRECHANGE && ci->old < ci->new) || @@ -299,7 +209,7 @@ static void adjust_jiffies(unsigned long val, struct cpufreq_freqs *ci) (val == CPUFREQ_RESUMECHANGE || val == CPUFREQ_SUSPENDCHANGE)) { loops_per_jiffy = cpufreq_scale(l_p_j_ref, l_p_j_ref_freq, ci->new); - dprintk("scaling loops_per_jiffy to %lu " + pr_debug("scaling loops_per_jiffy to %lu " "for frequency %u kHz\n", loops_per_jiffy, ci->new); } } @@ -326,7 +236,7 @@ void cpufreq_notify_transition(struct cpufreq_freqs *freqs, unsigned int state) BUG_ON(irqs_disabled()); freqs->flags = cpufreq_driver->flags; - dprintk("notification %u of frequency transition to %u kHz\n", + pr_debug("notification %u of frequency transition to %u kHz\n", state, freqs->new); policy = per_cpu(cpufreq_cpu_data, freqs->cpu); @@ -340,7 +250,7 @@ void cpufreq_notify_transition(struct cpufreq_freqs *freqs, unsigned int state) if (!(cpufreq_driver->flags & CPUFREQ_CONST_LOOPS)) { if ((policy) && (policy->cpu == freqs->cpu) && (policy->cur) && (policy->cur != freqs->old)) { - dprintk("Warning: CPU frequency is" + pr_debug("Warning: CPU frequency is" " %u, cpufreq assumed %u kHz.\n", freqs->old, policy->cur); freqs->old = policy->cur; @@ -353,7 +263,7 @@ void cpufreq_notify_transition(struct cpufreq_freqs *freqs, unsigned int state) case CPUFREQ_POSTCHANGE: adjust_jiffies(CPUFREQ_POSTCHANGE, freqs); - dprintk("FREQ: %lu - CPU: %lu", (unsigned long)freqs->new, + pr_debug("FREQ: %lu - CPU: %lu", (unsigned long)freqs->new, (unsigned long)freqs->cpu); trace_power_frequency(POWER_PSTATE, freqs->new, freqs->cpu); trace_cpu_frequency(freqs->new, freqs->cpu); @@ -753,7 +663,7 @@ no_policy: static void cpufreq_sysfs_release(struct kobject *kobj) { struct cpufreq_policy *policy = to_policy(kobj); - dprintk("last reference is dropped\n"); + pr_debug("last reference is dropped\n"); complete(&policy->kobj_unregister); } @@ -788,7 +698,7 @@ static int cpufreq_add_dev_policy(unsigned int cpu, gov = __find_governor(per_cpu(cpufreq_cpu_governor, cpu)); if (gov) { policy->governor = gov; - dprintk("Restoring governor %s for cpu %d\n", + pr_debug("Restoring governor %s for cpu %d\n", policy->governor->name, cpu); } #endif @@ -824,7 +734,7 @@ static int cpufreq_add_dev_policy(unsigned int cpu, per_cpu(cpufreq_cpu_data, cpu) = managed_policy; spin_unlock_irqrestore(&cpufreq_driver_lock, flags); - dprintk("CPU already managed, adding link\n"); + pr_debug("CPU already managed, adding link\n"); ret = sysfs_create_link(&sys_dev->kobj, &managed_policy->kobj, "cpufreq"); @@ -865,7 +775,7 @@ static int cpufreq_add_dev_symlink(unsigned int cpu, if (!cpu_online(j)) continue; - dprintk("CPU %u already managed, adding link\n", j); + pr_debug("CPU %u already managed, adding link\n", j); managed_policy = cpufreq_cpu_get(cpu); cpu_sys_dev = get_cpu_sysdev(j); ret = sysfs_create_link(&cpu_sys_dev->kobj, &policy->kobj, @@ -941,7 +851,7 @@ static int cpufreq_add_dev_interface(unsigned int cpu, policy->user_policy.governor = policy->governor; if (ret) { - dprintk("setting policy failed\n"); + pr_debug("setting policy failed\n"); if (cpufreq_driver->exit) cpufreq_driver->exit(policy); } @@ -977,8 +887,7 @@ static int cpufreq_add_dev(struct sys_device *sys_dev) if (cpu_is_offline(cpu)) return 0; - cpufreq_debug_disable_ratelimit(); - dprintk("adding CPU %u\n", cpu); + pr_debug("adding CPU %u\n", cpu); #ifdef CONFIG_SMP /* check whether a different CPU already registered this @@ -986,7 +895,6 @@ static int cpufreq_add_dev(struct sys_device *sys_dev) policy = cpufreq_cpu_get(cpu); if (unlikely(policy)) { cpufreq_cpu_put(policy); - cpufreq_debug_enable_ratelimit(); return 0; } #endif @@ -1037,7 +945,7 @@ static int cpufreq_add_dev(struct sys_device *sys_dev) */ ret = cpufreq_driver->init(policy); if (ret) { - dprintk("initialization failed\n"); + pr_debug("initialization failed\n"); goto err_unlock_policy; } policy->user_policy.min = policy->min; @@ -1063,8 +971,7 @@ static int cpufreq_add_dev(struct sys_device *sys_dev) kobject_uevent(&policy->kobj, KOBJ_ADD); module_put(cpufreq_driver->owner); - dprintk("initialization complete\n"); - cpufreq_debug_enable_ratelimit(); + pr_debug("initialization complete\n"); return 0; @@ -1088,7 +995,6 @@ err_free_policy: nomem_out: module_put(cpufreq_driver->owner); module_out: - cpufreq_debug_enable_ratelimit(); return ret; } @@ -1112,15 +1018,13 @@ static int __cpufreq_remove_dev(struct sys_device *sys_dev) unsigned int j; #endif - cpufreq_debug_disable_ratelimit(); - dprintk("unregistering CPU %u\n", cpu); + pr_debug("unregistering CPU %u\n", cpu); spin_lock_irqsave(&cpufreq_driver_lock, flags); data = per_cpu(cpufreq_cpu_data, cpu); if (!data) { spin_unlock_irqrestore(&cpufreq_driver_lock, flags); - cpufreq_debug_enable_ratelimit(); unlock_policy_rwsem_write(cpu); return -EINVAL; } @@ -1132,12 +1036,11 @@ static int __cpufreq_remove_dev(struct sys_device *sys_dev) * only need to unlink, put and exit */ if (unlikely(cpu != data->cpu)) { - dprintk("removing link\n"); + pr_debug("removing link\n"); cpumask_clear_cpu(cpu, data->cpus); spin_unlock_irqrestore(&cpufreq_driver_lock, flags); kobj = &sys_dev->kobj; cpufreq_cpu_put(data); - cpufreq_debug_enable_ratelimit(); unlock_policy_rwsem_write(cpu); sysfs_remove_link(kobj, "cpufreq"); return 0; @@ -1170,7 +1073,7 @@ static int __cpufreq_remove_dev(struct sys_device *sys_dev) for_each_cpu(j, data->cpus) { if (j == cpu) continue; - dprintk("removing link for cpu %u\n", j); + pr_debug("removing link for cpu %u\n", j); #ifdef CONFIG_HOTPLUG_CPU strncpy(per_cpu(cpufreq_cpu_governor, j), data->governor->name, CPUFREQ_NAME_LEN); @@ -1199,17 +1102,15 @@ static int __cpufreq_remove_dev(struct sys_device *sys_dev) * not referenced anymore by anybody before we proceed with * unloading. */ - dprintk("waiting for dropping of refcount\n"); + pr_debug("waiting for dropping of refcount\n"); wait_for_completion(cmp); - dprintk("wait complete\n"); + pr_debug("wait complete\n"); lock_policy_rwsem_write(cpu); if (cpufreq_driver->exit) cpufreq_driver->exit(data); unlock_policy_rwsem_write(cpu); - cpufreq_debug_enable_ratelimit(); - #ifdef CONFIG_HOTPLUG_CPU /* when the CPU which is the parent of the kobj is hotplugged * offline, check for siblings, and create cpufreq sysfs interface @@ -1255,7 +1156,7 @@ static void handle_update(struct work_struct *work) struct cpufreq_policy *policy = container_of(work, struct cpufreq_policy, update); unsigned int cpu = policy->cpu; - dprintk("handle_update for cpu %u called\n", cpu); + pr_debug("handle_update for cpu %u called\n", cpu); cpufreq_update_policy(cpu); } @@ -1273,7 +1174,7 @@ static void cpufreq_out_of_sync(unsigned int cpu, unsigned int old_freq, { struct cpufreq_freqs freqs; - dprintk("Warning: CPU frequency out of sync: cpufreq and timing " + pr_debug("Warning: CPU frequency out of sync: cpufreq and timing " "core thinks of %u, is %u kHz.\n", old_freq, new_freq); freqs.cpu = cpu; @@ -1376,7 +1277,7 @@ static int cpufreq_bp_suspend(void) int cpu = smp_processor_id(); struct cpufreq_policy *cpu_policy; - dprintk("suspending cpu %u\n", cpu); + pr_debug("suspending cpu %u\n", cpu); /* If there's no policy for the boot CPU, we have nothing to do. */ cpu_policy = cpufreq_cpu_get(cpu); @@ -1414,7 +1315,7 @@ static void cpufreq_bp_resume(void) int cpu = smp_processor_id(); struct cpufreq_policy *cpu_policy; - dprintk("resuming cpu %u\n", cpu); + pr_debug("resuming cpu %u\n", cpu); /* If there's no policy for the boot CPU, we have nothing to do. */ cpu_policy = cpufreq_cpu_get(cpu); @@ -1526,7 +1427,7 @@ int __cpufreq_driver_target(struct cpufreq_policy *policy, { int retval = -EINVAL; - dprintk("target for CPU %u: %u kHz, relation %u\n", policy->cpu, + pr_debug("target for CPU %u: %u kHz, relation %u\n", policy->cpu, target_freq, relation); if (cpu_online(policy->cpu) && cpufreq_driver->target) retval = cpufreq_driver->target(policy, target_freq, relation); @@ -1612,7 +1513,7 @@ static int __cpufreq_governor(struct cpufreq_policy *policy, if (!try_module_get(policy->governor->owner)) return -EINVAL; - dprintk("__cpufreq_governor for CPU %u, event %u\n", + pr_debug("__cpufreq_governor for CPU %u, event %u\n", policy->cpu, event); ret = policy->governor->governor(policy, event); @@ -1713,8 +1614,7 @@ static int __cpufreq_set_policy(struct cpufreq_policy *data, { int ret = 0; - cpufreq_debug_disable_ratelimit(); - dprintk("setting new policy for CPU %u: %u - %u kHz\n", policy->cpu, + pr_debug("setting new policy for CPU %u: %u - %u kHz\n", policy->cpu, policy->min, policy->max); memcpy(&policy->cpuinfo, &data->cpuinfo, @@ -1751,19 +1651,19 @@ static int __cpufreq_set_policy(struct cpufreq_policy *data, data->min = policy->min; data->max = policy->max; - dprintk("new min and max freqs are %u - %u kHz\n", + pr_debug("new min and max freqs are %u - %u kHz\n", data->min, data->max); if (cpufreq_driver->setpolicy) { data->policy = policy->policy; - dprintk("setting range\n"); + pr_debug("setting range\n"); ret = cpufreq_driver->setpolicy(policy); } else { if (policy->governor != data->governor) { /* save old, working values */ struct cpufreq_governor *old_gov = data->governor; - dprintk("governor switch\n"); + pr_debug("governor switch\n"); /* end old governor */ if (data->governor) @@ -1773,7 +1673,7 @@ static int __cpufreq_set_policy(struct cpufreq_policy *data, data->governor = policy->governor; if (__cpufreq_governor(data, CPUFREQ_GOV_START)) { /* new governor failed, so re-start old one */ - dprintk("starting governor %s failed\n", + pr_debug("starting governor %s failed\n", data->governor->name); if (old_gov) { data->governor = old_gov; @@ -1785,12 +1685,11 @@ static int __cpufreq_set_policy(struct cpufreq_policy *data, } /* might be a policy change, too, so fall through */ } - dprintk("governor: change or update limits\n"); + pr_debug("governor: change or update limits\n"); __cpufreq_governor(data, CPUFREQ_GOV_LIMITS); } error_out: - cpufreq_debug_enable_ratelimit(); return ret; } @@ -1817,7 +1716,7 @@ int cpufreq_update_policy(unsigned int cpu) goto fail; } - dprintk("updating policy for CPU %u\n", cpu); + pr_debug("updating policy for CPU %u\n", cpu); memcpy(&policy, data, sizeof(struct cpufreq_policy)); policy.min = data->user_policy.min; policy.max = data->user_policy.max; @@ -1829,7 +1728,7 @@ int cpufreq_update_policy(unsigned int cpu) if (cpufreq_driver->get) { policy.cur = cpufreq_driver->get(cpu); if (!data->cur) { - dprintk("Driver did not initialize current freq"); + pr_debug("Driver did not initialize current freq"); data->cur = policy.cur; } else { if (data->cur != policy.cur) @@ -1905,7 +1804,7 @@ int cpufreq_register_driver(struct cpufreq_driver *driver_data) ((!driver_data->setpolicy) && (!driver_data->target))) return -EINVAL; - dprintk("trying to register driver %s\n", driver_data->name); + pr_debug("trying to register driver %s\n", driver_data->name); if (driver_data->setpolicy) driver_data->flags |= CPUFREQ_CONST_LOOPS; @@ -1936,15 +1835,14 @@ int cpufreq_register_driver(struct cpufreq_driver *driver_data) /* if all ->init() calls failed, unregister */ if (ret) { - dprintk("no CPU initialized for driver %s\n", + pr_debug("no CPU initialized for driver %s\n", driver_data->name); goto err_sysdev_unreg; } } register_hotcpu_notifier(&cpufreq_cpu_notifier); - dprintk("driver %s up and running\n", driver_data->name); - cpufreq_debug_enable_ratelimit(); + pr_debug("driver %s up and running\n", driver_data->name); return 0; err_sysdev_unreg: @@ -1971,14 +1869,10 @@ int cpufreq_unregister_driver(struct cpufreq_driver *driver) { unsigned long flags; - cpufreq_debug_disable_ratelimit(); - - if (!cpufreq_driver || (driver != cpufreq_driver)) { - cpufreq_debug_enable_ratelimit(); + if (!cpufreq_driver || (driver != cpufreq_driver)) return -EINVAL; - } - dprintk("unregistering driver %s\n", driver->name); + pr_debug("unregistering driver %s\n", driver->name); sysdev_driver_unregister(&cpu_sysdev_class, &cpufreq_sysdev_driver); unregister_hotcpu_notifier(&cpufreq_cpu_notifier); diff --git a/drivers/cpufreq/cpufreq_performance.c b/drivers/cpufreq/cpufreq_performance.c index 7e2e515..f13a8a9 100644 --- a/drivers/cpufreq/cpufreq_performance.c +++ b/drivers/cpufreq/cpufreq_performance.c @@ -15,9 +15,6 @@ #include #include -#define dprintk(msg...) \ - cpufreq_debug_printk(CPUFREQ_DEBUG_GOVERNOR, "performance", msg) - static int cpufreq_governor_performance(struct cpufreq_policy *policy, unsigned int event) @@ -25,7 +22,7 @@ static int cpufreq_governor_performance(struct cpufreq_policy *policy, switch (event) { case CPUFREQ_GOV_START: case CPUFREQ_GOV_LIMITS: - dprintk("setting to %u kHz because of event %u\n", + pr_debug("setting to %u kHz because of event %u\n", policy->max, event); __cpufreq_driver_target(policy, policy->max, CPUFREQ_RELATION_H); diff --git a/drivers/cpufreq/cpufreq_powersave.c b/drivers/cpufreq/cpufreq_powersave.c index e6db5fa..4c2eb51 100644 --- a/drivers/cpufreq/cpufreq_powersave.c +++ b/drivers/cpufreq/cpufreq_powersave.c @@ -15,16 +15,13 @@ #include #include -#define dprintk(msg...) \ - cpufreq_debug_printk(CPUFREQ_DEBUG_GOVERNOR, "powersave", msg) - static int cpufreq_governor_powersave(struct cpufreq_policy *policy, unsigned int event) { switch (event) { case CPUFREQ_GOV_START: case CPUFREQ_GOV_LIMITS: - dprintk("setting to %u kHz because of event %u\n", + pr_debug("setting to %u kHz because of event %u\n", policy->min, event); __cpufreq_driver_target(policy, policy->min, CPUFREQ_RELATION_L); diff --git a/drivers/cpufreq/cpufreq_userspace.c b/drivers/cpufreq/cpufreq_userspace.c index 66d2d1d..f231015 100644 --- a/drivers/cpufreq/cpufreq_userspace.c +++ b/drivers/cpufreq/cpufreq_userspace.c @@ -37,9 +37,6 @@ static DEFINE_PER_CPU(unsigned int, cpu_is_managed); static DEFINE_MUTEX(userspace_mutex); static int cpus_using_userspace_governor; -#define dprintk(msg...) \ - cpufreq_debug_printk(CPUFREQ_DEBUG_GOVERNOR, "userspace", msg) - /* keep track of frequency transitions */ static int userspace_cpufreq_notifier(struct notifier_block *nb, unsigned long val, @@ -50,7 +47,7 @@ userspace_cpufreq_notifier(struct notifier_block *nb, unsigned long val, if (!per_cpu(cpu_is_managed, freq->cpu)) return 0; - dprintk("saving cpu_cur_freq of cpu %u to be %u kHz\n", + pr_debug("saving cpu_cur_freq of cpu %u to be %u kHz\n", freq->cpu, freq->new); per_cpu(cpu_cur_freq, freq->cpu) = freq->new; @@ -73,7 +70,7 @@ static int cpufreq_set(struct cpufreq_policy *policy, unsigned int freq) { int ret = -EINVAL; - dprintk("cpufreq_set for cpu %u, freq %u kHz\n", policy->cpu, freq); + pr_debug("cpufreq_set for cpu %u, freq %u kHz\n", policy->cpu, freq); mutex_lock(&userspace_mutex); if (!per_cpu(cpu_is_managed, policy->cpu)) @@ -134,7 +131,7 @@ static int cpufreq_governor_userspace(struct cpufreq_policy *policy, per_cpu(cpu_max_freq, cpu) = policy->max; per_cpu(cpu_cur_freq, cpu) = policy->cur; per_cpu(cpu_set_freq, cpu) = policy->cur; - dprintk("managing cpu %u started " + pr_debug("managing cpu %u started " "(%u - %u kHz, currently %u kHz)\n", cpu, per_cpu(cpu_min_freq, cpu), @@ -156,12 +153,12 @@ static int cpufreq_governor_userspace(struct cpufreq_policy *policy, per_cpu(cpu_min_freq, cpu) = 0; per_cpu(cpu_max_freq, cpu) = 0; per_cpu(cpu_set_freq, cpu) = 0; - dprintk("managing cpu %u stopped\n", cpu); + pr_debug("managing cpu %u stopped\n", cpu); mutex_unlock(&userspace_mutex); break; case CPUFREQ_GOV_LIMITS: mutex_lock(&userspace_mutex); - dprintk("limit event for cpu %u: %u - %u kHz, " + pr_debug("limit event for cpu %u: %u - %u kHz, " "currently %u kHz, last set to %u kHz\n", cpu, policy->min, policy->max, per_cpu(cpu_cur_freq, cpu), diff --git a/drivers/cpufreq/freq_table.c b/drivers/cpufreq/freq_table.c index 0543221..90431cb 100644 --- a/drivers/cpufreq/freq_table.c +++ b/drivers/cpufreq/freq_table.c @@ -14,9 +14,6 @@ #include #include -#define dprintk(msg...) \ - cpufreq_debug_printk(CPUFREQ_DEBUG_CORE, "freq-table", msg) - /********************************************************************* * FREQUENCY TABLE HELPERS * *********************************************************************/ @@ -31,11 +28,11 @@ int cpufreq_frequency_table_cpuinfo(struct cpufreq_policy *policy, for (i = 0; (table[i].frequency != CPUFREQ_TABLE_END); i++) { unsigned int freq = table[i].frequency; if (freq == CPUFREQ_ENTRY_INVALID) { - dprintk("table entry %u is invalid, skipping\n", i); + pr_debug("table entry %u is invalid, skipping\n", i); continue; } - dprintk("table entry %u: %u kHz, %u index\n", + pr_debug("table entry %u: %u kHz, %u index\n", i, freq, table[i].index); if (freq < min_freq) min_freq = freq; @@ -61,7 +58,7 @@ int cpufreq_frequency_table_verify(struct cpufreq_policy *policy, unsigned int i; unsigned int count = 0; - dprintk("request for verification of policy (%u - %u kHz) for cpu %u\n", + pr_debug("request for verification of policy (%u - %u kHz) for cpu %u\n", policy->min, policy->max, policy->cpu); if (!cpu_online(policy->cpu)) @@ -86,7 +83,7 @@ int cpufreq_frequency_table_verify(struct cpufreq_policy *policy, cpufreq_verify_within_limits(policy, policy->cpuinfo.min_freq, policy->cpuinfo.max_freq); - dprintk("verification lead to (%u - %u kHz) for cpu %u\n", + pr_debug("verification lead to (%u - %u kHz) for cpu %u\n", policy->min, policy->max, policy->cpu); return 0; @@ -110,7 +107,7 @@ int cpufreq_frequency_table_target(struct cpufreq_policy *policy, }; unsigned int i; - dprintk("request for target %u kHz (relation: %u) for cpu %u\n", + pr_debug("request for target %u kHz (relation: %u) for cpu %u\n", target_freq, relation, policy->cpu); switch (relation) { @@ -167,7 +164,7 @@ int cpufreq_frequency_table_target(struct cpufreq_policy *policy, } else *index = optimal.index; - dprintk("target is %u (%u kHz, %u)\n", *index, table[*index].frequency, + pr_debug("target is %u (%u kHz, %u)\n", *index, table[*index].frequency, table[*index].index); return 0; @@ -216,14 +213,14 @@ EXPORT_SYMBOL_GPL(cpufreq_freq_attr_scaling_available_freqs); void cpufreq_frequency_table_get_attr(struct cpufreq_frequency_table *table, unsigned int cpu) { - dprintk("setting show_table for cpu %u to %p\n", cpu, table); + pr_debug("setting show_table for cpu %u to %p\n", cpu, table); per_cpu(cpufreq_show_table, cpu) = table; } EXPORT_SYMBOL_GPL(cpufreq_frequency_table_get_attr); void cpufreq_frequency_table_put_attr(unsigned int cpu) { - dprintk("clearing show_table for cpu %u\n", cpu); + pr_debug("clearing show_table for cpu %u\n", cpu); per_cpu(cpufreq_show_table, cpu) = NULL; } EXPORT_SYMBOL_GPL(cpufreq_frequency_table_put_attr); diff --git a/include/linux/cpufreq.h b/include/linux/cpufreq.h index 9343dd3..2845f6e6 100644 --- a/include/linux/cpufreq.h +++ b/include/linux/cpufreq.h @@ -397,23 +397,4 @@ void cpufreq_frequency_table_get_attr(struct cpufreq_frequency_table *table, void cpufreq_frequency_table_put_attr(unsigned int cpu); -/********************************************************************* - * UNIFIED DEBUG HELPERS * - *********************************************************************/ - -#define CPUFREQ_DEBUG_CORE 1 -#define CPUFREQ_DEBUG_DRIVER 2 -#define CPUFREQ_DEBUG_GOVERNOR 4 - -#ifdef CONFIG_CPU_FREQ_DEBUG - -extern void cpufreq_debug_printk(unsigned int type, const char *prefix, - const char *fmt, ...); - -#else - -#define cpufreq_debug_printk(msg...) do { } while(0) - -#endif /* CONFIG_CPU_FREQ_DEBUG */ - #endif /* _LINUX_CPUFREQ_H */ -- cgit v0.10.2 From 335dc3335ff692173bc766b248f7a97f3a23b30a Mon Sep 17 00:00:00 2001 From: Thiago Farina Date: Thu, 28 Apr 2011 20:42:53 -0300 Subject: [CPUFREQ] cpufreq.h: Fix some checkpatch.pl coding style issues. Before: $ scripts/checkpatch.pl --file --terse include/linux/cpufreq.h total: 14 errors, 11 warnings, 419 lines checked After: $ scripts/checkpatch.pl --file --terse include/linux/cpufreq.h total: 2 errors, 4 warnings, 422 lines checked Signed-off-by: Thiago Farina Signed-off-by: Dave Jones diff --git a/include/linux/cpufreq.h b/include/linux/cpufreq.h index 2845f6e6..11be48e 100644 --- a/include/linux/cpufreq.h +++ b/include/linux/cpufreq.h @@ -3,7 +3,7 @@ * * Copyright (C) 2001 Russell King * (C) 2002 - 2003 Dominik Brodowski - * + * * 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. @@ -56,9 +56,9 @@ static inline int cpufreq_unregister_notifier(struct notifier_block *nb, #define CPUFREQ_POLICY_POWERSAVE (1) #define CPUFREQ_POLICY_PERFORMANCE (2) -/* Frequency values here are CPU kHz so that hardware which doesn't run - * with some frequencies can complain without having to guess what per - * cent / per mille means. +/* Frequency values here are CPU kHz so that hardware which doesn't run + * with some frequencies can complain without having to guess what per + * cent / per mille means. * Maximum transition latency is in nanoseconds - if it's unknown, * CPUFREQ_ETERNAL shall be used. */ @@ -72,13 +72,15 @@ extern struct kobject *cpufreq_global_kobject; struct cpufreq_cpuinfo { unsigned int max_freq; unsigned int min_freq; - unsigned int transition_latency; /* in 10^(-9) s = nanoseconds */ + + /* in 10^(-9) s = nanoseconds */ + unsigned int transition_latency; }; struct cpufreq_real_policy { unsigned int min; /* in kHz */ unsigned int max; /* in kHz */ - unsigned int policy; /* see above */ + unsigned int policy; /* see above */ struct cpufreq_governor *governor; /* see below */ }; @@ -94,7 +96,7 @@ struct cpufreq_policy { unsigned int max; /* in kHz */ unsigned int cur; /* in kHz, only needed if cpufreq * governors are used */ - unsigned int policy; /* see above */ + unsigned int policy; /* see above */ struct cpufreq_governor *governor; /* see below */ struct work_struct update; /* if update_policy() needs to be @@ -167,11 +169,11 @@ static inline unsigned long cpufreq_scale(unsigned long old, u_int div, u_int mu struct cpufreq_governor { char name[CPUFREQ_NAME_LEN]; - int (*governor) (struct cpufreq_policy *policy, + int (*governor) (struct cpufreq_policy *policy, unsigned int event); ssize_t (*show_setspeed) (struct cpufreq_policy *policy, char *buf); - int (*store_setspeed) (struct cpufreq_policy *policy, + int (*store_setspeed) (struct cpufreq_policy *policy, unsigned int freq); unsigned int max_transition_latency; /* HW must be able to switch to next freq faster than this value in nano secs or we @@ -180,7 +182,8 @@ struct cpufreq_governor { struct module *owner; }; -/* pass a target to the cpufreq driver +/* + * Pass a target to the cpufreq driver. */ extern int cpufreq_driver_target(struct cpufreq_policy *policy, unsigned int target_freq, @@ -237,9 +240,9 @@ struct cpufreq_driver { /* flags */ -#define CPUFREQ_STICKY 0x01 /* the driver isn't removed even if +#define CPUFREQ_STICKY 0x01 /* the driver isn't removed even if * all ->init() calls failed */ -#define CPUFREQ_CONST_LOOPS 0x02 /* loops_per_jiffy or other kernel +#define CPUFREQ_CONST_LOOPS 0x02 /* loops_per_jiffy or other kernel * "constants" aren't affected by * frequency transitions */ #define CPUFREQ_PM_NO_WARN 0x04 /* don't warn on suspend/resume speed @@ -252,7 +255,7 @@ int cpufreq_unregister_driver(struct cpufreq_driver *driver_data); void cpufreq_notify_transition(struct cpufreq_freqs *freqs, unsigned int state); -static inline void cpufreq_verify_within_limits(struct cpufreq_policy *policy, unsigned int min, unsigned int max) +static inline void cpufreq_verify_within_limits(struct cpufreq_policy *policy, unsigned int min, unsigned int max) { if (policy->min < min) policy->min = min; @@ -386,12 +389,12 @@ int cpufreq_frequency_table_target(struct cpufreq_policy *policy, /* the following 3 funtions are for cpufreq core use only */ struct cpufreq_frequency_table *cpufreq_frequency_get_table(unsigned int cpu); struct cpufreq_policy *cpufreq_cpu_get(unsigned int cpu); -void cpufreq_cpu_put (struct cpufreq_policy *data); +void cpufreq_cpu_put(struct cpufreq_policy *data); /* the following are really really optional */ extern struct freq_attr cpufreq_freq_attr_scaling_available_freqs; -void cpufreq_frequency_table_get_attr(struct cpufreq_frequency_table *table, +void cpufreq_frequency_table_get_attr(struct cpufreq_frequency_table *table, unsigned int cpu); void cpufreq_frequency_table_put_attr(unsigned int cpu); -- cgit v0.10.2 From 98586ed8b8878e10691203687e89a42fa3355300 Mon Sep 17 00:00:00 2001 From: steven finney Date: Mon, 2 May 2011 11:29:17 -0700 Subject: [CPUFREQ] Fix memory leak in cpufreq_stat When a CPU is taken offline in an SMP system, cpufreq_remove_dev() nulls out the per-cpu policy before cpufreq_stats_free_table() can make use of it. cpufreq_stats_free_table() then skips the call to sysfs_remove_group(), leaving about 100 bytes of sysfs-related memory unclaimed each time a CPU-removal occurs. Break up cpu_stats_free_table into sysfs and table portions, and call the sysfs portion early. Signed-off-by: Steven Finney Signed-off-by: Dave Jones Cc: stable@kernel.org diff --git a/drivers/cpufreq/cpufreq_stats.c b/drivers/cpufreq/cpufreq_stats.c index 00d73fc..4f1b8de 100644 --- a/drivers/cpufreq/cpufreq_stats.c +++ b/drivers/cpufreq/cpufreq_stats.c @@ -165,17 +165,27 @@ static int freq_table_get_index(struct cpufreq_stats *stat, unsigned int freq) return -1; } +/* should be called late in the CPU removal sequence so that the stats + * memory is still available in case someone tries to use it. + */ static void cpufreq_stats_free_table(unsigned int cpu) { struct cpufreq_stats *stat = per_cpu(cpufreq_stats_table, cpu); - struct cpufreq_policy *policy = cpufreq_cpu_get(cpu); - if (policy && policy->cpu == cpu) - sysfs_remove_group(&policy->kobj, &stats_attr_group); if (stat) { kfree(stat->time_in_state); kfree(stat); } per_cpu(cpufreq_stats_table, cpu) = NULL; +} + +/* must be called early in the CPU removal sequence (before + * cpufreq_remove_dev) so that policy is still valid. + */ +static void cpufreq_stats_free_sysfs(unsigned int cpu) +{ + struct cpufreq_policy *policy = cpufreq_cpu_get(cpu); + if (policy && policy->cpu == cpu) + sysfs_remove_group(&policy->kobj, &stats_attr_group); if (policy) cpufreq_cpu_put(policy); } @@ -316,6 +326,9 @@ static int __cpuinit cpufreq_stat_cpu_callback(struct notifier_block *nfb, case CPU_ONLINE_FROZEN: cpufreq_update_policy(cpu); break; + case CPU_DOWN_PREPARE: + cpufreq_stats_free_sysfs(cpu); + break; case CPU_DEAD: case CPU_DEAD_FROZEN: cpufreq_stats_free_table(cpu); @@ -324,9 +337,11 @@ static int __cpuinit cpufreq_stat_cpu_callback(struct notifier_block *nfb, return NOTIFY_OK; } +/* priority=1 so this will get called before cpufreq_remove_dev */ static struct notifier_block cpufreq_stat_cpu_notifier __refdata = { .notifier_call = cpufreq_stat_cpu_callback, + .priority = 1, }; static struct notifier_block notifier_policy_block = { -- cgit v0.10.2 From 469057d587a9de2cd6087d71a008b908e785a5b6 Mon Sep 17 00:00:00 2001 From: Karthigan Srinivasan Date: Fri, 1 Apr 2011 17:34:47 -0500 Subject: [CPUFREQ] cpufreq_stats.c: Fixed brace coding style issue Fixed brace coding style issue. Signed-off-by: Karthigan Srinivasan Signed-off-by: Dave Jones diff --git a/drivers/cpufreq/cpufreq_stats.c b/drivers/cpufreq/cpufreq_stats.c index 4f1b8de..b60a4c2 100644 --- a/drivers/cpufreq/cpufreq_stats.c +++ b/drivers/cpufreq/cpufreq_stats.c @@ -338,8 +338,7 @@ static int __cpuinit cpufreq_stat_cpu_callback(struct notifier_block *nfb, } /* priority=1 so this will get called before cpufreq_remove_dev */ -static struct notifier_block cpufreq_stat_cpu_notifier __refdata = -{ +static struct notifier_block cpufreq_stat_cpu_notifier __refdata = { .notifier_call = cpufreq_stat_cpu_callback, .priority = 1, }; -- cgit v0.10.2 From 1a8e1463a49aaa452da1cefe184a00d4df47f1ef Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Wed, 4 May 2011 08:38:56 -0700 Subject: [CPUFREQ] remove redundant sprintf from request_module call. Since format string handling is part of request_module, there is no need to construct the module name. As such, drop the redundant sprintf and heap usage. Signed-off-by: Kees Cook Signed-off-by: Dave Jones diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c index 1e08af4..0a5bea9 100644 --- a/drivers/cpufreq/cpufreq.c +++ b/drivers/cpufreq/cpufreq.c @@ -321,21 +321,14 @@ static int cpufreq_parse_governor(char *str_governor, unsigned int *policy, t = __find_governor(str_governor); if (t == NULL) { - char *name = kasprintf(GFP_KERNEL, "cpufreq_%s", - str_governor); + int ret; - if (name) { - int ret; + mutex_unlock(&cpufreq_governor_mutex); + ret = request_module("cpufreq_%s", str_governor); + mutex_lock(&cpufreq_governor_mutex); - mutex_unlock(&cpufreq_governor_mutex); - ret = request_module("%s", name); - mutex_lock(&cpufreq_governor_mutex); - - if (ret == 0) - t = __find_governor(str_governor); - } - - kfree(name); + if (ret == 0) + t = __find_governor(str_governor); } if (t != NULL) { -- cgit v0.10.2 From 9cddf15f18865c4f7124d829be41799f59aaa5cf Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Wed, 4 May 2011 11:06:05 -0700 Subject: x86/net: only select BPF_JIT when NET is enabled Fix kconfig unmet dependency warning: HAVE_BPF_JIT depends on NET, so make the "select" of it depend on NET also. warning: (X86) selects HAVE_BPF_JIT which has unmet direct dependencies (NET) Signed-off-by: Randy Dunlap Signed-off-by: David S. Miller diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig index 855a1bd..2096cf1 100644 --- a/arch/x86/Kconfig +++ b/arch/x86/Kconfig @@ -72,7 +72,7 @@ config X86 select IRQ_FORCED_THREADING select USE_GENERIC_SMP_HELPERS if SMP select ARCH_NO_SYSDEV_OPS - select HAVE_BPF_JIT if X86_64 + select HAVE_BPF_JIT if (X86_64 && NET) config INSTRUCTION_DECODER def_bool (KPROBES || PERF_EVENTS) -- cgit v0.10.2 From 69458cb194e82972347a004054e0baed719ed008 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Wed, 4 May 2011 11:10:28 -0700 Subject: ipv4: Use flowi4->{daddr,saddr} in ipip_tunnel_xmit(). Instead of rt->rt_{dst,src} Signed-off-by: David S. Miller diff --git a/net/ipv4/ipip.c b/net/ipv4/ipip.c index 88d96bd..bfa0b98 100644 --- a/net/ipv4/ipip.c +++ b/net/ipv4/ipip.c @@ -550,8 +550,8 @@ static netdev_tx_t ipip_tunnel_xmit(struct sk_buff *skb, struct net_device *dev) iph->frag_off = df; iph->protocol = IPPROTO_IPIP; iph->tos = INET_ECN_encapsulate(tos, old_iph->tos); - iph->daddr = rt->rt_dst; - iph->saddr = rt->rt_src; + iph->daddr = fl4.daddr; + iph->saddr = fl4.saddr; if ((iph->ttl = tiph->ttl) == 0) iph->ttl = old_iph->ttl; -- cgit v0.10.2 From dca97ad2ec37aa98c45dfe1d531d9ba7048e814e Mon Sep 17 00:00:00 2001 From: Emil Tantilov Date: Wed, 27 Apr 2011 08:51:29 +0000 Subject: e100: fix build warning In function 'e100_hw_init': warning: 'err' may be used uninitialized in this function Signed-off-by: Emil Tantilov Tested-by: Aaron Brown Signed-off-by: Jeff Kirsher diff --git a/drivers/net/e100.c b/drivers/net/e100.c index c810cda..29f812d 100644 --- a/drivers/net/e100.c +++ b/drivers/net/e100.c @@ -1512,7 +1512,7 @@ static int e100_phy_init(struct nic *nic) static int e100_hw_init(struct nic *nic) { - int err; + int err = 0; e100_hw_reset(nic); -- cgit v0.10.2 From dd927a2694ee412b440284dd72dd8e32caada3fc Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Wed, 4 May 2011 12:03:30 -0700 Subject: ipv4: In ip_build_and_send_pkt() use 'saddr' and 'daddr' args passed in. Instead of rt->rt_{dst,src} The only tricky part is source route option handling. If the source route option is enabled we can't just use plain 'daddr', we have to use opt->opt.faddr. Signed-off-by: David S. Miller diff --git a/net/ipv4/ip_output.c b/net/ipv4/ip_output.c index 3aa4c31..db38c18 100644 --- a/net/ipv4/ip_output.c +++ b/net/ipv4/ip_output.c @@ -158,8 +158,8 @@ int ip_build_and_send_pkt(struct sk_buff *skb, struct sock *sk, else iph->frag_off = 0; iph->ttl = ip_select_ttl(inet, &rt->dst); - iph->daddr = rt->rt_dst; - iph->saddr = rt->rt_src; + iph->daddr = (opt && opt->opt.srr ? opt->opt.faddr : daddr); + iph->saddr = saddr; iph->protocol = sk->sk_protocol; ip_select_ident(iph, &rt->dst, sk); -- cgit v0.10.2 From ec7e97e9a0265255485e217f4f2d3513949e7083 Mon Sep 17 00:00:00 2001 From: Jeff Kirsher Date: Tue, 3 May 2011 05:17:34 +0000 Subject: ixgb: convert to set_phys_id Based on the original patch sent by Stephen Hemminger. This version incorporates the ethtool changes that Bruce Allan submitted. CC: Stephen Hemminger Signed-off-by: Jeff Kirsher Tested-by: Evan Swanson diff --git a/drivers/net/ixgb/ixgb.h b/drivers/net/ixgb/ixgb.h index 8f3df04..49e8408 100644 --- a/drivers/net/ixgb/ixgb.h +++ b/drivers/net/ixgb/ixgb.h @@ -157,9 +157,6 @@ struct ixgb_adapter { u16 link_duplex; struct work_struct tx_timeout_task; - struct timer_list blink_timer; - unsigned long led_status; - /* TX */ struct ixgb_desc_ring tx_ring ____cacheline_aligned_in_smp; unsigned int restart_queue; diff --git a/drivers/net/ixgb/ixgb_ethtool.c b/drivers/net/ixgb/ixgb_ethtool.c index 5f224c3..6da890b 100644 --- a/drivers/net/ixgb/ixgb_ethtool.c +++ b/drivers/net/ixgb/ixgb_ethtool.c @@ -611,45 +611,23 @@ err_setup_rx: return err; } -/* toggle LED 4 times per second = 2 "blinks" per second */ -#define IXGB_ID_INTERVAL (HZ/4) - -/* bit defines for adapter->led_status */ -#define IXGB_LED_ON 0 - -static void -ixgb_led_blink_callback(unsigned long data) -{ - struct ixgb_adapter *adapter = (struct ixgb_adapter *)data; - - if (test_and_change_bit(IXGB_LED_ON, &adapter->led_status)) - ixgb_led_off(&adapter->hw); - else - ixgb_led_on(&adapter->hw); - - mod_timer(&adapter->blink_timer, jiffies + IXGB_ID_INTERVAL); -} - static int -ixgb_phys_id(struct net_device *netdev, u32 data) +ixgb_set_phys_id(struct net_device *netdev, enum ethtool_phys_id_state state) { struct ixgb_adapter *adapter = netdev_priv(netdev); - if (!data) - data = INT_MAX; - - if (!adapter->blink_timer.function) { - init_timer(&adapter->blink_timer); - adapter->blink_timer.function = ixgb_led_blink_callback; - adapter->blink_timer.data = (unsigned long)adapter; - } + switch (state) { + case ETHTOOL_ID_ACTIVE: + return 2; - mod_timer(&adapter->blink_timer, jiffies); + case ETHTOOL_ID_ON: + ixgb_led_on(&adapter->hw); + break; - msleep_interruptible(data * 1000); - del_timer_sync(&adapter->blink_timer); - ixgb_led_off(&adapter->hw); - clear_bit(IXGB_LED_ON, &adapter->led_status); + case ETHTOOL_ID_OFF: + case ETHTOOL_ID_INACTIVE: + ixgb_led_off(&adapter->hw); + } return 0; } @@ -767,7 +745,7 @@ static const struct ethtool_ops ixgb_ethtool_ops = { .set_msglevel = ixgb_set_msglevel, .set_tso = ixgb_set_tso, .get_strings = ixgb_get_strings, - .phys_id = ixgb_phys_id, + .set_phys_id = ixgb_set_phys_id, .get_sset_count = ixgb_get_sset_count, .get_ethtool_stats = ixgb_get_ethtool_stats, .get_flags = ethtool_op_get_flags, -- cgit v0.10.2 From f6b1bfd17d42f9dc1d799b7e0eed817ed75005ec Mon Sep 17 00:00:00 2001 From: Carolyn Wyborny Date: Wed, 4 May 2011 04:29:51 +0000 Subject: igb: Add check for invalid size to igb_get_invariants_82575() Recent commits have changed how EEPROM size is checked and if the size word is misconfigured, the driver will fail to load. This patch adds a check for invalid size word in the EEPROM and uses default size instead for 82576 parts. Reported-by: Stefan Assmann Signed-off-by: Carolyn Wyborny Tested-by: Jeff Pieper Signed-off-by: Jeff Kirsher diff --git a/drivers/net/igb/e1000_82575.c b/drivers/net/igb/e1000_82575.c index 0cd41c4..0f563c8 100644 --- a/drivers/net/igb/e1000_82575.c +++ b/drivers/net/igb/e1000_82575.c @@ -244,6 +244,14 @@ static s32 igb_get_invariants_82575(struct e1000_hw *hw) */ size += NVM_WORD_SIZE_BASE_SHIFT; + /* + * Check for invalid size + */ + if ((hw->mac.type == e1000_82576) && (size > 15)) { + printk("igb: The NVM size is not valid, " + "defaulting to 32K.\n"); + size = 15; + } nvm->word_size = 1 << size; if (nvm->word_size == (1 << 15)) nvm->page_size = 128; -- cgit v0.10.2 From 97322b3303a1de979b973dc1d0a43091f27258ac Mon Sep 17 00:00:00 2001 From: stephen hemminger Date: Tue, 5 Apr 2011 04:26:27 +0000 Subject: igbvf: remove bogus phys_id This device lies about supporting phys_id. Remove it and just let the upper layer report not supported. Signed-off-by: Stephen Hemminger Tested-by: Signed-off-by: Jeff Kirsher diff --git a/drivers/net/igbvf/ethtool.c b/drivers/net/igbvf/ethtool.c index 112ae15b..b0b14d6 100644 --- a/drivers/net/igbvf/ethtool.c +++ b/drivers/net/igbvf/ethtool.c @@ -391,11 +391,6 @@ static int igbvf_set_wol(struct net_device *netdev, return -EOPNOTSUPP; } -static int igbvf_phys_id(struct net_device *netdev, u32 data) -{ - return 0; -} - static int igbvf_get_coalesce(struct net_device *netdev, struct ethtool_coalesce *ec) { @@ -527,7 +522,6 @@ static const struct ethtool_ops igbvf_ethtool_ops = { .self_test = igbvf_diag_test, .get_sset_count = igbvf_get_sset_count, .get_strings = igbvf_get_strings, - .phys_id = igbvf_phys_id, .get_ethtool_stats = igbvf_get_ethtool_stats, .get_coalesce = igbvf_get_coalesce, .set_coalesce = igbvf_set_coalesce, -- cgit v0.10.2 From 6d980c3e50189e5437fdb5ef2c6e6d3c282035dc Mon Sep 17 00:00:00 2001 From: Emil Tantilov Date: Wed, 13 Apr 2011 04:56:15 +0000 Subject: ixgbe: Use function pointer for ixgbe_acquire/release_swfw_sync() Change remaining direct calls to function pointers. Signed-off-by: Emil Tantilov Tested-by: Evan Swanson Signed-off-by: Jeff Kirsher diff --git a/drivers/net/ixgbe/ixgbe_82599.c b/drivers/net/ixgbe/ixgbe_82599.c index d1cda36..5b8e17e 100644 --- a/drivers/net/ixgbe/ixgbe_82599.c +++ b/drivers/net/ixgbe/ixgbe_82599.c @@ -110,7 +110,6 @@ static s32 ixgbe_setup_sfp_modules_82599(struct ixgbe_hw *hw) ret_val = ixgbe_get_sfp_init_sequence_offsets(hw, &list_offset, &data_offset); - if (ret_val != 0) goto setup_sfp_out; @@ -130,7 +129,7 @@ static s32 ixgbe_setup_sfp_modules_82599(struct ixgbe_hw *hw) } /* Release the semaphore */ - ixgbe_release_swfw_sync(hw, IXGBE_GSSR_MAC_CSR_SM); + hw->mac.ops.release_swfw_sync(hw, IXGBE_GSSR_MAC_CSR_SM); /* * Delay obtaining semaphore again to allow FW access, * semaphore_delay is in ms usleep_range needs us. diff --git a/drivers/net/ixgbe/ixgbe_phy.c b/drivers/net/ixgbe/ixgbe_phy.c index edcaaeb..735f686 100644 --- a/drivers/net/ixgbe/ixgbe_phy.c +++ b/drivers/net/ixgbe/ixgbe_phy.c @@ -1222,7 +1222,7 @@ s32 ixgbe_read_i2c_byte_generic(struct ixgbe_hw *hw, u8 byte_offset, swfw_mask = IXGBE_GSSR_PHY0_SM; do { - if (ixgbe_acquire_swfw_sync(hw, swfw_mask) != 0) { + if (hw->mac.ops.acquire_swfw_sync(hw, swfw_mask) != 0) { status = IXGBE_ERR_SWFW_SYNC; goto read_byte_out; } @@ -1269,7 +1269,7 @@ s32 ixgbe_read_i2c_byte_generic(struct ixgbe_hw *hw, u8 byte_offset, break; fail: - ixgbe_release_swfw_sync(hw, swfw_mask); + hw->mac.ops.release_swfw_sync(hw, swfw_mask); msleep(100); ixgbe_i2c_bus_clear(hw); retry++; @@ -1280,7 +1280,7 @@ fail: } while (retry < max_retry); - ixgbe_release_swfw_sync(hw, swfw_mask); + hw->mac.ops.release_swfw_sync(hw, swfw_mask); read_byte_out: return status; @@ -1308,7 +1308,7 @@ s32 ixgbe_write_i2c_byte_generic(struct ixgbe_hw *hw, u8 byte_offset, else swfw_mask = IXGBE_GSSR_PHY0_SM; - if (ixgbe_acquire_swfw_sync(hw, swfw_mask) != 0) { + if (hw->mac.ops.acquire_swfw_sync(hw, swfw_mask) != 0) { status = IXGBE_ERR_SWFW_SYNC; goto write_byte_out; } @@ -1352,7 +1352,7 @@ fail: hw_dbg(hw, "I2C byte write error.\n"); } while (retry < max_retry); - ixgbe_release_swfw_sync(hw, swfw_mask); + hw->mac.ops.release_swfw_sync(hw, swfw_mask); write_byte_out: return status; diff --git a/drivers/net/ixgbe/ixgbe_x540.c b/drivers/net/ixgbe/ixgbe_x540.c index 75c6465..179ee82 100644 --- a/drivers/net/ixgbe/ixgbe_x540.c +++ b/drivers/net/ixgbe/ixgbe_x540.c @@ -318,7 +318,7 @@ static s32 ixgbe_read_eerd_X540(struct ixgbe_hw *hw, u16 offset, u16 *data) else status = IXGBE_ERR_SWFW_SYNC; - ixgbe_release_swfw_sync_X540(hw, IXGBE_GSSR_EEP_SM); + hw->mac.ops.release_swfw_sync(hw, IXGBE_GSSR_EEP_SM); return status; } -- cgit v0.10.2 From 2698b20842884d7d4de55ea559baa57e2f2ebea4 Mon Sep 17 00:00:00 2001 From: Don Skidmore Date: Wed, 13 Apr 2011 07:01:52 +0000 Subject: ixgbe: fix typo error with software defined pins on 82599 Correcting a simple typo with enabling software defined pins. I don't believe this was causing any issues but this is how it was meant to be implemented. Signed-off-by: Don Skidmore Tested-by: Evan Swanson Signed-off-by: Jeff Kirsher diff --git a/drivers/net/ixgbe/ixgbe_main.c b/drivers/net/ixgbe/ixgbe_main.c index 9160811..bd3d21d 100644 --- a/drivers/net/ixgbe/ixgbe_main.c +++ b/drivers/net/ixgbe/ixgbe_main.c @@ -3862,9 +3862,10 @@ static void ixgbe_setup_gpie(struct ixgbe_adapter *adapter) if (adapter->flags & IXGBE_FLAG_FAN_FAIL_CAPABLE) gpie |= IXGBE_SDP1_GPIEN; - if (hw->mac.type == ixgbe_mac_82599EB) + if (hw->mac.type == ixgbe_mac_82599EB) { gpie |= IXGBE_SDP1_GPIEN; gpie |= IXGBE_SDP2_GPIEN; + } IXGBE_WRITE_REG(hw, IXGBE_GPIE, gpie); } -- cgit v0.10.2 From 95a46011843a3c49e1a002eddb6b2735c201e378 Mon Sep 17 00:00:00 2001 From: Emil Tantilov Date: Thu, 14 Apr 2011 07:46:41 +0000 Subject: ixgbe: fix sparse warning warning: symbol 'before' shadows an earlier one Convert large macros to functions similar to e1000e. Signed-off-by: Emil Tantilov Acked-by: Don Skidmore Tested-by: Evan Swanson Signed-off-by: Jeff Kirsher diff --git a/drivers/net/ixgbe/ixgbe_ethtool.c b/drivers/net/ixgbe/ixgbe_ethtool.c index bcba057..410c298 100644 --- a/drivers/net/ixgbe/ixgbe_ethtool.c +++ b/drivers/net/ixgbe/ixgbe_ethtool.c @@ -1236,46 +1236,62 @@ static const struct ixgbe_reg_test reg_test_82598[] = { { 0, 0, 0, 0 } }; -static const u32 register_test_patterns[] = { - 0x5A5A5A5A, 0xA5A5A5A5, 0x00000000, 0xFFFFFFFF -}; - -#define REG_PATTERN_TEST(R, M, W) \ -{ \ - u32 pat, val, before; \ - for (pat = 0; pat < ARRAY_SIZE(register_test_patterns); pat++) { \ - before = readl(adapter->hw.hw_addr + R); \ - writel((register_test_patterns[pat] & W), \ - (adapter->hw.hw_addr + R)); \ - val = readl(adapter->hw.hw_addr + R); \ - if (val != (register_test_patterns[pat] & W & M)) { \ - e_err(drv, "pattern test reg %04X failed: got " \ - "0x%08X expected 0x%08X\n", \ - R, val, (register_test_patterns[pat] & W & M)); \ - *data = R; \ - writel(before, adapter->hw.hw_addr + R); \ - return 1; \ - } \ - writel(before, adapter->hw.hw_addr + R); \ - } \ +static bool reg_pattern_test(struct ixgbe_adapter *adapter, u64 *data, int reg, + u32 mask, u32 write) +{ + u32 pat, val, before; + static const u32 test_pattern[] = { + 0x5A5A5A5A, 0xA5A5A5A5, 0x00000000, 0xFFFFFFFF}; + + for (pat = 0; pat < ARRAY_SIZE(test_pattern); pat++) { + before = readl(adapter->hw.hw_addr + reg); + writel((test_pattern[pat] & write), + (adapter->hw.hw_addr + reg)); + val = readl(adapter->hw.hw_addr + reg); + if (val != (test_pattern[pat] & write & mask)) { + e_err(drv, "pattern test reg %04X failed: got " + "0x%08X expected 0x%08X\n", + reg, val, (test_pattern[pat] & write & mask)); + *data = reg; + writel(before, adapter->hw.hw_addr + reg); + return 1; + } + writel(before, adapter->hw.hw_addr + reg); + } + return 0; } -#define REG_SET_AND_CHECK(R, M, W) \ -{ \ - u32 val, before; \ - before = readl(adapter->hw.hw_addr + R); \ - writel((W & M), (adapter->hw.hw_addr + R)); \ - val = readl(adapter->hw.hw_addr + R); \ - if ((W & M) != (val & M)) { \ - e_err(drv, "set/check reg %04X test failed: got 0x%08X " \ - "expected 0x%08X\n", R, (val & M), (W & M)); \ - *data = R; \ - writel(before, (adapter->hw.hw_addr + R)); \ - return 1; \ - } \ - writel(before, (adapter->hw.hw_addr + R)); \ +static bool reg_set_and_check(struct ixgbe_adapter *adapter, u64 *data, int reg, + u32 mask, u32 write) +{ + u32 val, before; + before = readl(adapter->hw.hw_addr + reg); + writel((write & mask), (adapter->hw.hw_addr + reg)); + val = readl(adapter->hw.hw_addr + reg); + if ((write & mask) != (val & mask)) { + e_err(drv, "set/check reg %04X test failed: got 0x%08X " + "expected 0x%08X\n", reg, (val & mask), (write & mask)); + *data = reg; + writel(before, (adapter->hw.hw_addr + reg)); + return 1; + } + writel(before, (adapter->hw.hw_addr + reg)); + return 0; } +#define REG_PATTERN_TEST(reg, mask, write) \ + do { \ + if (reg_pattern_test(adapter, data, reg, mask, write)) \ + return 1; \ + } while (0) \ + + +#define REG_SET_AND_CHECK(reg, mask, write) \ + do { \ + if (reg_set_and_check(adapter, data, reg, mask, write)) \ + return 1; \ + } while (0) \ + static int ixgbe_reg_test(struct ixgbe_adapter *adapter, u64 *data) { const struct ixgbe_reg_test *test; @@ -1326,13 +1342,13 @@ static int ixgbe_reg_test(struct ixgbe_adapter *adapter, u64 *data) switch (test->test_type) { case PATTERN_TEST: REG_PATTERN_TEST(test->reg + (i * 0x40), - test->mask, - test->write); + test->mask, + test->write); break; case SET_READ_TEST: REG_SET_AND_CHECK(test->reg + (i * 0x40), - test->mask, - test->write); + test->mask, + test->write); break; case WRITE_NO_TEST: writel(test->write, @@ -1341,18 +1357,18 @@ static int ixgbe_reg_test(struct ixgbe_adapter *adapter, u64 *data) break; case TABLE32_TEST: REG_PATTERN_TEST(test->reg + (i * 4), - test->mask, - test->write); + test->mask, + test->write); break; case TABLE64_TEST_LO: REG_PATTERN_TEST(test->reg + (i * 8), - test->mask, - test->write); + test->mask, + test->write); break; case TABLE64_TEST_HI: REG_PATTERN_TEST((test->reg + 4) + (i * 8), - test->mask, - test->write); + test->mask, + test->write); break; } } -- cgit v0.10.2 From 68c7005d664724eab87627b042e149a736622d54 Mon Sep 17 00:00:00 2001 From: Emil Tantilov Date: Wed, 20 Apr 2011 08:49:06 +0000 Subject: ixgbe: improve EEPROM read/write operations Introduce buffered read/writes which greatly improves performance on parts with large EEPROMs. Previously reading/writing a word requires taking/releasing of synchronization semaphores which adds 10ms to each operation. The optimization is to read/write in buffers, but make sure the semaphore is not held for >500ms according to the datasheet. Since we can't read the EEPROM page size ixgbe_detect_eeprom_page_size() is used to discover the EEPROM size when needed and keeps the result in word_page_size for the rest of the run time. Use buffered reads for ethtool -e. Signed-off-by: Emil Tantilov Tested-by: Evan Swanson Signed-off-by: Jeff Kirsher diff --git a/drivers/net/ixgbe/ixgbe_82598.c b/drivers/net/ixgbe/ixgbe_82598.c index 7a64f50..8179e50 100644 --- a/drivers/net/ixgbe/ixgbe_82598.c +++ b/drivers/net/ixgbe/ixgbe_82598.c @@ -1281,6 +1281,7 @@ static struct ixgbe_mac_operations mac_ops_82598 = { static struct ixgbe_eeprom_operations eeprom_ops_82598 = { .init_params = &ixgbe_init_eeprom_params_generic, .read = &ixgbe_read_eerd_generic, + .read_buffer = &ixgbe_read_eerd_buffer_generic, .calc_checksum = &ixgbe_calc_eeprom_checksum_generic, .validate_checksum = &ixgbe_validate_eeprom_checksum_generic, .update_checksum = &ixgbe_update_eeprom_checksum_generic, diff --git a/drivers/net/ixgbe/ixgbe_82599.c b/drivers/net/ixgbe/ixgbe_82599.c index 5b8e17e..dba5ca6 100644 --- a/drivers/net/ixgbe/ixgbe_82599.c +++ b/drivers/net/ixgbe/ixgbe_82599.c @@ -2064,6 +2064,39 @@ out: } /** + * ixgbe_read_eeprom_buffer_82599 - Read EEPROM word(s) using + * fastest available method + * + * @hw: pointer to hardware structure + * @offset: offset of word in EEPROM to read + * @words: number of words + * @data: word(s) read from the EEPROM + * + * Retrieves 16 bit word(s) read from EEPROM + **/ +static s32 ixgbe_read_eeprom_buffer_82599(struct ixgbe_hw *hw, u16 offset, + u16 words, u16 *data) +{ + struct ixgbe_eeprom_info *eeprom = &hw->eeprom; + s32 ret_val = IXGBE_ERR_CONFIG; + + /* + * If EEPROM is detected and can be addressed using 14 bits, + * use EERD otherwise use bit bang + */ + if ((eeprom->type == ixgbe_eeprom_spi) && + (offset + (words - 1) <= IXGBE_EERD_MAX_ADDR)) + ret_val = ixgbe_read_eerd_buffer_generic(hw, offset, words, + data); + else + ret_val = ixgbe_read_eeprom_buffer_bit_bang_generic(hw, offset, + words, + data); + + return ret_val; +} + +/** * ixgbe_read_eeprom_82599 - Read EEPROM word using * fastest available method * @@ -2139,7 +2172,9 @@ static struct ixgbe_mac_operations mac_ops_82599 = { static struct ixgbe_eeprom_operations eeprom_ops_82599 = { .init_params = &ixgbe_init_eeprom_params_generic, .read = &ixgbe_read_eeprom_82599, + .read_buffer = &ixgbe_read_eeprom_buffer_82599, .write = &ixgbe_write_eeprom_generic, + .write_buffer = &ixgbe_write_eeprom_buffer_bit_bang_generic, .calc_checksum = &ixgbe_calc_eeprom_checksum_generic, .validate_checksum = &ixgbe_validate_eeprom_checksum_generic, .update_checksum = &ixgbe_update_eeprom_checksum_generic, diff --git a/drivers/net/ixgbe/ixgbe_common.c b/drivers/net/ixgbe/ixgbe_common.c index cb2e8e1..c4730cd 100644 --- a/drivers/net/ixgbe/ixgbe_common.c +++ b/drivers/net/ixgbe/ixgbe_common.c @@ -55,6 +55,12 @@ static s32 ixgbe_negotiate_fc(struct ixgbe_hw *hw, u32 adv_reg, u32 lp_reg, u32 adv_sym, u32 adv_asm, u32 lp_sym, u32 lp_asm); static s32 ixgbe_setup_fc(struct ixgbe_hw *hw, s32 packetbuf_num); static s32 ixgbe_poll_eerd_eewr_done(struct ixgbe_hw *hw, u32 ee_reg); +static s32 ixgbe_read_eeprom_buffer_bit_bang(struct ixgbe_hw *hw, u16 offset, + u16 words, u16 *data); +static s32 ixgbe_write_eeprom_buffer_bit_bang(struct ixgbe_hw *hw, u16 offset, + u16 words, u16 *data); +static s32 ixgbe_detect_eeprom_page_size_generic(struct ixgbe_hw *hw, + u16 offset); /** * ixgbe_start_hw_generic - Prepare hardware for Tx/Rx @@ -585,6 +591,8 @@ s32 ixgbe_init_eeprom_params_generic(struct ixgbe_hw *hw) /* Set default semaphore delay to 10ms which is a well * tested value */ eeprom->semaphore_delay = 10; + /* Clear EEPROM page size, it will be initialized as needed */ + eeprom->word_page_size = 0; /* * Check for EEPROM present first. @@ -617,26 +625,78 @@ s32 ixgbe_init_eeprom_params_generic(struct ixgbe_hw *hw) } /** - * ixgbe_write_eeprom_generic - Writes 16 bit value to EEPROM + * ixgbe_write_eeprom_buffer_bit_bang_generic - Write EEPROM using bit-bang * @hw: pointer to hardware structure - * @offset: offset within the EEPROM to be written to - * @data: 16 bit word to be written to the EEPROM + * @offset: offset within the EEPROM to write + * @words: number of words + * @data: 16 bit word(s) to write to EEPROM * - * If ixgbe_eeprom_update_checksum is not called after this function, the - * EEPROM will most likely contain an invalid checksum. + * Reads 16 bit word(s) from EEPROM through bit-bang method **/ -s32 ixgbe_write_eeprom_generic(struct ixgbe_hw *hw, u16 offset, u16 data) +s32 ixgbe_write_eeprom_buffer_bit_bang_generic(struct ixgbe_hw *hw, u16 offset, + u16 words, u16 *data) { - s32 status; - u8 write_opcode = IXGBE_EEPROM_WRITE_OPCODE_SPI; + s32 status = 0; + u16 i, count; hw->eeprom.ops.init_params(hw); - if (offset >= hw->eeprom.word_size) { + if (words == 0) { + status = IXGBE_ERR_INVALID_ARGUMENT; + goto out; + } + + if (offset + words > hw->eeprom.word_size) { status = IXGBE_ERR_EEPROM; goto out; } + /* + * The EEPROM page size cannot be queried from the chip. We do lazy + * initialization. It is worth to do that when we write large buffer. + */ + if ((hw->eeprom.word_page_size == 0) && + (words > IXGBE_EEPROM_PAGE_SIZE_MAX)) + ixgbe_detect_eeprom_page_size_generic(hw, offset); + + /* + * We cannot hold synchronization semaphores for too long + * to avoid other entity starvation. However it is more efficient + * to read in bursts than synchronizing access for each word. + */ + for (i = 0; i < words; i += IXGBE_EEPROM_RD_BUFFER_MAX_COUNT) { + count = (words - i) / IXGBE_EEPROM_RD_BUFFER_MAX_COUNT > 0 ? + IXGBE_EEPROM_RD_BUFFER_MAX_COUNT : (words - i); + status = ixgbe_write_eeprom_buffer_bit_bang(hw, offset + i, + count, &data[i]); + + if (status != 0) + break; + } + +out: + return status; +} + +/** + * ixgbe_write_eeprom_buffer_bit_bang - Writes 16 bit word(s) to EEPROM + * @hw: pointer to hardware structure + * @offset: offset within the EEPROM to be written to + * @words: number of word(s) + * @data: 16 bit word(s) to be written to the EEPROM + * + * If ixgbe_eeprom_update_checksum is not called after this function, the + * EEPROM will most likely contain an invalid checksum. + **/ +static s32 ixgbe_write_eeprom_buffer_bit_bang(struct ixgbe_hw *hw, u16 offset, + u16 words, u16 *data) +{ + s32 status; + u16 word; + u16 page_size; + u16 i; + u8 write_opcode = IXGBE_EEPROM_WRITE_OPCODE_SPI; + /* Prepare the EEPROM for writing */ status = ixgbe_acquire_eeprom(hw); @@ -648,62 +708,147 @@ s32 ixgbe_write_eeprom_generic(struct ixgbe_hw *hw, u16 offset, u16 data) } if (status == 0) { - ixgbe_standby_eeprom(hw); + for (i = 0; i < words; i++) { + ixgbe_standby_eeprom(hw); - /* Send the WRITE ENABLE command (8 bit opcode ) */ - ixgbe_shift_out_eeprom_bits(hw, IXGBE_EEPROM_WREN_OPCODE_SPI, - IXGBE_EEPROM_OPCODE_BITS); + /* Send the WRITE ENABLE command (8 bit opcode ) */ + ixgbe_shift_out_eeprom_bits(hw, + IXGBE_EEPROM_WREN_OPCODE_SPI, + IXGBE_EEPROM_OPCODE_BITS); - ixgbe_standby_eeprom(hw); + ixgbe_standby_eeprom(hw); - /* - * Some SPI eeproms use the 8th address bit embedded in the - * opcode - */ - if ((hw->eeprom.address_bits == 8) && (offset >= 128)) - write_opcode |= IXGBE_EEPROM_A8_OPCODE_SPI; + /* + * Some SPI eeproms use the 8th address bit embedded + * in the opcode + */ + if ((hw->eeprom.address_bits == 8) && + ((offset + i) >= 128)) + write_opcode |= IXGBE_EEPROM_A8_OPCODE_SPI; + + /* Send the Write command (8-bit opcode + addr) */ + ixgbe_shift_out_eeprom_bits(hw, write_opcode, + IXGBE_EEPROM_OPCODE_BITS); + ixgbe_shift_out_eeprom_bits(hw, (u16)((offset + i) * 2), + hw->eeprom.address_bits); + + page_size = hw->eeprom.word_page_size; + + /* Send the data in burst via SPI*/ + do { + word = data[i]; + word = (word >> 8) | (word << 8); + ixgbe_shift_out_eeprom_bits(hw, word, 16); + + if (page_size == 0) + break; + + /* do not wrap around page */ + if (((offset + i) & (page_size - 1)) == + (page_size - 1)) + break; + } while (++i < words); + + ixgbe_standby_eeprom(hw); + usleep_range(10000, 20000); + } + /* Done with writing - release the EEPROM */ + ixgbe_release_eeprom(hw); + } - /* Send the Write command (8-bit opcode + addr) */ - ixgbe_shift_out_eeprom_bits(hw, write_opcode, - IXGBE_EEPROM_OPCODE_BITS); - ixgbe_shift_out_eeprom_bits(hw, (u16)(offset*2), - hw->eeprom.address_bits); + return status; +} - /* Send the data */ - data = (data >> 8) | (data << 8); - ixgbe_shift_out_eeprom_bits(hw, data, 16); - ixgbe_standby_eeprom(hw); +/** + * ixgbe_write_eeprom_generic - Writes 16 bit value to EEPROM + * @hw: pointer to hardware structure + * @offset: offset within the EEPROM to be written to + * @data: 16 bit word to be written to the EEPROM + * + * If ixgbe_eeprom_update_checksum is not called after this function, the + * EEPROM will most likely contain an invalid checksum. + **/ +s32 ixgbe_write_eeprom_generic(struct ixgbe_hw *hw, u16 offset, u16 data) +{ + s32 status; - /* Done with writing - release the EEPROM */ - ixgbe_release_eeprom(hw); + hw->eeprom.ops.init_params(hw); + + if (offset >= hw->eeprom.word_size) { + status = IXGBE_ERR_EEPROM; + goto out; } + status = ixgbe_write_eeprom_buffer_bit_bang(hw, offset, 1, &data); + out: return status; } /** - * ixgbe_read_eeprom_bit_bang_generic - Read EEPROM word using bit-bang + * ixgbe_read_eeprom_buffer_bit_bang_generic - Read EEPROM using bit-bang * @hw: pointer to hardware structure * @offset: offset within the EEPROM to be read - * @data: read 16 bit value from EEPROM + * @words: number of word(s) + * @data: read 16 bit words(s) from EEPROM * - * Reads 16 bit value from EEPROM through bit-bang method + * Reads 16 bit word(s) from EEPROM through bit-bang method **/ -s32 ixgbe_read_eeprom_bit_bang_generic(struct ixgbe_hw *hw, u16 offset, - u16 *data) +s32 ixgbe_read_eeprom_buffer_bit_bang_generic(struct ixgbe_hw *hw, u16 offset, + u16 words, u16 *data) { - s32 status; - u16 word_in; - u8 read_opcode = IXGBE_EEPROM_READ_OPCODE_SPI; + s32 status = 0; + u16 i, count; hw->eeprom.ops.init_params(hw); - if (offset >= hw->eeprom.word_size) { + if (words == 0) { + status = IXGBE_ERR_INVALID_ARGUMENT; + goto out; + } + + if (offset + words > hw->eeprom.word_size) { status = IXGBE_ERR_EEPROM; goto out; } + /* + * We cannot hold synchronization semaphores for too long + * to avoid other entity starvation. However it is more efficient + * to read in bursts than synchronizing access for each word. + */ + for (i = 0; i < words; i += IXGBE_EEPROM_RD_BUFFER_MAX_COUNT) { + count = (words - i) / IXGBE_EEPROM_RD_BUFFER_MAX_COUNT > 0 ? + IXGBE_EEPROM_RD_BUFFER_MAX_COUNT : (words - i); + + status = ixgbe_read_eeprom_buffer_bit_bang(hw, offset + i, + count, &data[i]); + + if (status != 0) + break; + } + +out: + return status; +} + +/** + * ixgbe_read_eeprom_buffer_bit_bang - Read EEPROM using bit-bang + * @hw: pointer to hardware structure + * @offset: offset within the EEPROM to be read + * @words: number of word(s) + * @data: read 16 bit word(s) from EEPROM + * + * Reads 16 bit word(s) from EEPROM through bit-bang method + **/ +static s32 ixgbe_read_eeprom_buffer_bit_bang(struct ixgbe_hw *hw, u16 offset, + u16 words, u16 *data) +{ + s32 status; + u16 word_in; + u8 read_opcode = IXGBE_EEPROM_READ_OPCODE_SPI; + u16 i; + /* Prepare the EEPROM for reading */ status = ixgbe_acquire_eeprom(hw); @@ -715,104 +860,208 @@ s32 ixgbe_read_eeprom_bit_bang_generic(struct ixgbe_hw *hw, u16 offset, } if (status == 0) { - ixgbe_standby_eeprom(hw); + for (i = 0; i < words; i++) { + ixgbe_standby_eeprom(hw); + /* + * Some SPI eeproms use the 8th address bit embedded + * in the opcode + */ + if ((hw->eeprom.address_bits == 8) && + ((offset + i) >= 128)) + read_opcode |= IXGBE_EEPROM_A8_OPCODE_SPI; + + /* Send the READ command (opcode + addr) */ + ixgbe_shift_out_eeprom_bits(hw, read_opcode, + IXGBE_EEPROM_OPCODE_BITS); + ixgbe_shift_out_eeprom_bits(hw, (u16)((offset + i) * 2), + hw->eeprom.address_bits); + + /* Read the data. */ + word_in = ixgbe_shift_in_eeprom_bits(hw, 16); + data[i] = (word_in >> 8) | (word_in << 8); + } - /* - * Some SPI eeproms use the 8th address bit embedded in the - * opcode - */ - if ((hw->eeprom.address_bits == 8) && (offset >= 128)) - read_opcode |= IXGBE_EEPROM_A8_OPCODE_SPI; + /* End this read operation */ + ixgbe_release_eeprom(hw); + } - /* Send the READ command (opcode + addr) */ - ixgbe_shift_out_eeprom_bits(hw, read_opcode, - IXGBE_EEPROM_OPCODE_BITS); - ixgbe_shift_out_eeprom_bits(hw, (u16)(offset*2), - hw->eeprom.address_bits); + return status; +} - /* Read the data. */ - word_in = ixgbe_shift_in_eeprom_bits(hw, 16); - *data = (word_in >> 8) | (word_in << 8); +/** + * ixgbe_read_eeprom_bit_bang_generic - Read EEPROM word using bit-bang + * @hw: pointer to hardware structure + * @offset: offset within the EEPROM to be read + * @data: read 16 bit value from EEPROM + * + * Reads 16 bit value from EEPROM through bit-bang method + **/ +s32 ixgbe_read_eeprom_bit_bang_generic(struct ixgbe_hw *hw, u16 offset, + u16 *data) +{ + s32 status; - /* End this read operation */ - ixgbe_release_eeprom(hw); + hw->eeprom.ops.init_params(hw); + + if (offset >= hw->eeprom.word_size) { + status = IXGBE_ERR_EEPROM; + goto out; } + status = ixgbe_read_eeprom_buffer_bit_bang(hw, offset, 1, data); + out: return status; } /** - * ixgbe_read_eerd_generic - Read EEPROM word using EERD + * ixgbe_read_eerd_buffer_generic - Read EEPROM word(s) using EERD * @hw: pointer to hardware structure - * @offset: offset of word in the EEPROM to read - * @data: word read from the EEPROM + * @offset: offset of word in the EEPROM to read + * @words: number of word(s) + * @data: 16 bit word(s) from the EEPROM * - * Reads a 16 bit word from the EEPROM using the EERD register. + * Reads a 16 bit word(s) from the EEPROM using the EERD register. **/ -s32 ixgbe_read_eerd_generic(struct ixgbe_hw *hw, u16 offset, u16 *data) +s32 ixgbe_read_eerd_buffer_generic(struct ixgbe_hw *hw, u16 offset, + u16 words, u16 *data) { u32 eerd; - s32 status; + s32 status = 0; + u32 i; hw->eeprom.ops.init_params(hw); + if (words == 0) { + status = IXGBE_ERR_INVALID_ARGUMENT; + goto out; + } + if (offset >= hw->eeprom.word_size) { status = IXGBE_ERR_EEPROM; goto out; } - eerd = (offset << IXGBE_EEPROM_RW_ADDR_SHIFT) + - IXGBE_EEPROM_RW_REG_START; + for (i = 0; i < words; i++) { + eerd = ((offset + i) << IXGBE_EEPROM_RW_ADDR_SHIFT) + + IXGBE_EEPROM_RW_REG_START; - IXGBE_WRITE_REG(hw, IXGBE_EERD, eerd); - status = ixgbe_poll_eerd_eewr_done(hw, IXGBE_NVM_POLL_READ); + IXGBE_WRITE_REG(hw, IXGBE_EERD, eerd); + status = ixgbe_poll_eerd_eewr_done(hw, IXGBE_NVM_POLL_READ); - if (status == 0) - *data = (IXGBE_READ_REG(hw, IXGBE_EERD) >> - IXGBE_EEPROM_RW_REG_DATA); - else - hw_dbg(hw, "Eeprom read timed out\n"); + if (status == 0) { + data[i] = (IXGBE_READ_REG(hw, IXGBE_EERD) >> + IXGBE_EEPROM_RW_REG_DATA); + } else { + hw_dbg(hw, "Eeprom read timed out\n"); + goto out; + } + } +out: + return status; +} +/** + * ixgbe_detect_eeprom_page_size_generic - Detect EEPROM page size + * @hw: pointer to hardware structure + * @offset: offset within the EEPROM to be used as a scratch pad + * + * Discover EEPROM page size by writing marching data at given offset. + * This function is called only when we are writing a new large buffer + * at given offset so the data would be overwritten anyway. + **/ +static s32 ixgbe_detect_eeprom_page_size_generic(struct ixgbe_hw *hw, + u16 offset) +{ + u16 data[IXGBE_EEPROM_PAGE_SIZE_MAX]; + s32 status = 0; + u16 i; + + for (i = 0; i < IXGBE_EEPROM_PAGE_SIZE_MAX; i++) + data[i] = i; + + hw->eeprom.word_page_size = IXGBE_EEPROM_PAGE_SIZE_MAX; + status = ixgbe_write_eeprom_buffer_bit_bang(hw, offset, + IXGBE_EEPROM_PAGE_SIZE_MAX, data); + hw->eeprom.word_page_size = 0; + if (status != 0) + goto out; + + status = ixgbe_read_eeprom_buffer_bit_bang(hw, offset, 1, data); + if (status != 0) + goto out; + + /* + * When writing in burst more than the actual page size + * EEPROM address wraps around current page. + */ + hw->eeprom.word_page_size = IXGBE_EEPROM_PAGE_SIZE_MAX - data[0]; + + hw_dbg(hw, "Detected EEPROM page size = %d words.", + hw->eeprom.word_page_size); out: return status; } /** - * ixgbe_write_eewr_generic - Write EEPROM word using EEWR + * ixgbe_read_eerd_generic - Read EEPROM word using EERD + * @hw: pointer to hardware structure + * @offset: offset of word in the EEPROM to read + * @data: word read from the EEPROM + * + * Reads a 16 bit word from the EEPROM using the EERD register. + **/ +s32 ixgbe_read_eerd_generic(struct ixgbe_hw *hw, u16 offset, u16 *data) +{ + return ixgbe_read_eerd_buffer_generic(hw, offset, 1, data); +} + +/** + * ixgbe_write_eewr_buffer_generic - Write EEPROM word(s) using EEWR * @hw: pointer to hardware structure * @offset: offset of word in the EEPROM to write - * @data: word write to the EEPROM + * @words: number of words + * @data: word(s) write to the EEPROM * - * Write a 16 bit word to the EEPROM using the EEWR register. + * Write a 16 bit word(s) to the EEPROM using the EEWR register. **/ -s32 ixgbe_write_eewr_generic(struct ixgbe_hw *hw, u16 offset, u16 data) +s32 ixgbe_write_eewr_buffer_generic(struct ixgbe_hw *hw, u16 offset, + u16 words, u16 *data) { u32 eewr; - s32 status; + s32 status = 0; + u16 i; hw->eeprom.ops.init_params(hw); + if (words == 0) { + status = IXGBE_ERR_INVALID_ARGUMENT; + goto out; + } + if (offset >= hw->eeprom.word_size) { status = IXGBE_ERR_EEPROM; goto out; } - eewr = (offset << IXGBE_EEPROM_RW_ADDR_SHIFT) | - (data << IXGBE_EEPROM_RW_REG_DATA) | IXGBE_EEPROM_RW_REG_START; + for (i = 0; i < words; i++) { + eewr = ((offset + i) << IXGBE_EEPROM_RW_ADDR_SHIFT) | + (data[i] << IXGBE_EEPROM_RW_REG_DATA) | + IXGBE_EEPROM_RW_REG_START; - status = ixgbe_poll_eerd_eewr_done(hw, IXGBE_NVM_POLL_WRITE); - if (status != 0) { - hw_dbg(hw, "Eeprom write EEWR timed out\n"); - goto out; - } + status = ixgbe_poll_eerd_eewr_done(hw, IXGBE_NVM_POLL_WRITE); + if (status != 0) { + hw_dbg(hw, "Eeprom write EEWR timed out\n"); + goto out; + } - IXGBE_WRITE_REG(hw, IXGBE_EEWR, eewr); + IXGBE_WRITE_REG(hw, IXGBE_EEWR, eewr); - status = ixgbe_poll_eerd_eewr_done(hw, IXGBE_NVM_POLL_WRITE); - if (status != 0) { - hw_dbg(hw, "Eeprom write EEWR timed out\n"); - goto out; + status = ixgbe_poll_eerd_eewr_done(hw, IXGBE_NVM_POLL_WRITE); + if (status != 0) { + hw_dbg(hw, "Eeprom write EEWR timed out\n"); + goto out; + } } out: @@ -820,6 +1069,19 @@ out: } /** + * ixgbe_write_eewr_generic - Write EEPROM word using EEWR + * @hw: pointer to hardware structure + * @offset: offset of word in the EEPROM to write + * @data: word write to the EEPROM + * + * Write a 16 bit word to the EEPROM using the EEWR register. + **/ +s32 ixgbe_write_eewr_generic(struct ixgbe_hw *hw, u16 offset, u16 data) +{ + return ixgbe_write_eewr_buffer_generic(hw, offset, 1, &data); +} + +/** * ixgbe_poll_eerd_eewr_done - Poll EERD read or EEWR write status * @hw: pointer to hardware structure * @ee_reg: EEPROM flag for polling diff --git a/drivers/net/ixgbe/ixgbe_common.h b/drivers/net/ixgbe/ixgbe_common.h index e850adb..46be83c 100644 --- a/drivers/net/ixgbe/ixgbe_common.h +++ b/drivers/net/ixgbe/ixgbe_common.h @@ -49,10 +49,18 @@ s32 ixgbe_led_off_generic(struct ixgbe_hw *hw, u32 index); s32 ixgbe_init_eeprom_params_generic(struct ixgbe_hw *hw); s32 ixgbe_write_eeprom_generic(struct ixgbe_hw *hw, u16 offset, u16 data); +s32 ixgbe_write_eeprom_buffer_bit_bang_generic(struct ixgbe_hw *hw, u16 offset, + u16 words, u16 *data); s32 ixgbe_read_eerd_generic(struct ixgbe_hw *hw, u16 offset, u16 *data); +s32 ixgbe_read_eerd_buffer_generic(struct ixgbe_hw *hw, u16 offset, + u16 words, u16 *data); s32 ixgbe_write_eewr_generic(struct ixgbe_hw *hw, u16 offset, u16 data); +s32 ixgbe_write_eewr_buffer_generic(struct ixgbe_hw *hw, u16 offset, + u16 words, u16 *data); s32 ixgbe_read_eeprom_bit_bang_generic(struct ixgbe_hw *hw, u16 offset, u16 *data); +s32 ixgbe_read_eeprom_buffer_bit_bang_generic(struct ixgbe_hw *hw, u16 offset, + u16 words, u16 *data); u16 ixgbe_calc_eeprom_checksum_generic(struct ixgbe_hw *hw); s32 ixgbe_validate_eeprom_checksum_generic(struct ixgbe_hw *hw, u16 *checksum_val); diff --git a/drivers/net/ixgbe/ixgbe_ethtool.c b/drivers/net/ixgbe/ixgbe_ethtool.c index 410c298..f2efa32 100644 --- a/drivers/net/ixgbe/ixgbe_ethtool.c +++ b/drivers/net/ixgbe/ixgbe_ethtool.c @@ -847,11 +847,8 @@ static int ixgbe_get_eeprom(struct net_device *netdev, if (!eeprom_buff) return -ENOMEM; - for (i = 0; i < eeprom_len; i++) { - if ((ret_val = hw->eeprom.ops.read(hw, first_word + i, - &eeprom_buff[i]))) - break; - } + ret_val = hw->eeprom.ops.read_buffer(hw, first_word, eeprom_len, + eeprom_buff); /* Device's eeprom is always little-endian, word addressable */ for (i = 0; i < eeprom_len; i++) diff --git a/drivers/net/ixgbe/ixgbe_type.h b/drivers/net/ixgbe/ixgbe_type.h index fab9737..b1d523c 100644 --- a/drivers/net/ixgbe/ixgbe_type.h +++ b/drivers/net/ixgbe/ixgbe_type.h @@ -1668,6 +1668,10 @@ #define IXGBE_ETH_LENGTH_OF_ADDRESS 6 +#define IXGBE_EEPROM_PAGE_SIZE_MAX 128 +#define IXGBE_EEPROM_RD_BUFFER_MAX_COUNT 512 /* EEPROM words # read in burst */ +#define IXGBE_EEPROM_WR_BUFFER_MAX_COUNT 256 /* EEPROM words # wr in burst */ + #ifndef IXGBE_EEPROM_GRANT_ATTEMPTS #define IXGBE_EEPROM_GRANT_ATTEMPTS 1000 /* EEPROM # attempts to gain grant */ #endif @@ -2563,7 +2567,9 @@ typedef u8* (*ixgbe_mc_addr_itr) (struct ixgbe_hw *hw, u8 **mc_addr_ptr, struct ixgbe_eeprom_operations { s32 (*init_params)(struct ixgbe_hw *); s32 (*read)(struct ixgbe_hw *, u16, u16 *); + s32 (*read_buffer)(struct ixgbe_hw *, u16, u16, u16 *); s32 (*write)(struct ixgbe_hw *, u16, u16); + s32 (*write_buffer)(struct ixgbe_hw *, u16, u16, u16 *); s32 (*validate_checksum)(struct ixgbe_hw *, u16 *); s32 (*update_checksum)(struct ixgbe_hw *); u16 (*calc_checksum)(struct ixgbe_hw *); @@ -2649,6 +2655,7 @@ struct ixgbe_eeprom_info { u32 semaphore_delay; u16 word_size; u16 address_bits; + u16 word_page_size; }; #define IXGBE_FLAGS_DOUBLE_RESET_REQUIRED 0x01 diff --git a/drivers/net/ixgbe/ixgbe_x540.c b/drivers/net/ixgbe/ixgbe_x540.c index 179ee82..4ed687b 100644 --- a/drivers/net/ixgbe/ixgbe_x540.c +++ b/drivers/net/ixgbe/ixgbe_x540.c @@ -304,16 +304,19 @@ static s32 ixgbe_init_eeprom_params_X540(struct ixgbe_hw *hw) } /** - * ixgbe_read_eerd_X540 - Read EEPROM word using EERD - * @hw: pointer to hardware structure - * @offset: offset of word in the EEPROM to read - * @data: word read from the EERPOM + * ixgbe_read_eerd_X540- Read EEPROM word using EERD + * @hw: pointer to hardware structure + * @offset: offset of word in the EEPROM to read + * @data: word read from the EEPROM + * + * Reads a 16 bit word from the EEPROM using the EERD register. **/ static s32 ixgbe_read_eerd_X540(struct ixgbe_hw *hw, u16 offset, u16 *data) { - s32 status; + s32 status = 0; - if (hw->mac.ops.acquire_swfw_sync(hw, IXGBE_GSSR_EEP_SM) == 0) + if (hw->mac.ops.acquire_swfw_sync(hw, IXGBE_GSSR_EEP_SM) == + 0) status = ixgbe_read_eerd_generic(hw, offset, data); else status = IXGBE_ERR_SWFW_SYNC; @@ -323,6 +326,31 @@ static s32 ixgbe_read_eerd_X540(struct ixgbe_hw *hw, u16 offset, u16 *data) } /** + * ixgbe_read_eerd_buffer_X540 - Read EEPROM word(s) using EERD + * @hw: pointer to hardware structure + * @offset: offset of word in the EEPROM to read + * @words: number of words + * @data: word(s) read from the EEPROM + * + * Reads a 16 bit word(s) from the EEPROM using the EERD register. + **/ +static s32 ixgbe_read_eerd_buffer_X540(struct ixgbe_hw *hw, + u16 offset, u16 words, u16 *data) +{ + s32 status = 0; + + if (hw->mac.ops.acquire_swfw_sync(hw, IXGBE_GSSR_EEP_SM) == + 0) + status = ixgbe_read_eerd_buffer_generic(hw, offset, + words, data); + else + status = IXGBE_ERR_SWFW_SYNC; + + hw->mac.ops.release_swfw_sync(hw, IXGBE_GSSR_EEP_SM); + return status; +} + +/** * ixgbe_write_eewr_X540 - Write EEPROM word using EEWR * @hw: pointer to hardware structure * @offset: offset of word in the EEPROM to write @@ -344,6 +372,31 @@ static s32 ixgbe_write_eewr_X540(struct ixgbe_hw *hw, u16 offset, u16 data) } /** + * ixgbe_write_eewr_buffer_X540 - Write EEPROM word(s) using EEWR + * @hw: pointer to hardware structure + * @offset: offset of word in the EEPROM to write + * @words: number of words + * @data: word(s) write to the EEPROM + * + * Write a 16 bit word(s) to the EEPROM using the EEWR register. + **/ +static s32 ixgbe_write_eewr_buffer_X540(struct ixgbe_hw *hw, + u16 offset, u16 words, u16 *data) +{ + s32 status = 0; + + if (hw->mac.ops.acquire_swfw_sync(hw, IXGBE_GSSR_EEP_SM) == + 0) + status = ixgbe_write_eewr_buffer_generic(hw, offset, + words, data); + else + status = IXGBE_ERR_SWFW_SYNC; + + hw->mac.ops.release_swfw_sync(hw, IXGBE_GSSR_EEP_SM); + return status; +} + +/** * ixgbe_calc_eeprom_checksum_X540 - Calculates and returns the checksum * * This function does not use synchronization for EERD and EEWR. It can @@ -851,7 +904,9 @@ static struct ixgbe_mac_operations mac_ops_X540 = { static struct ixgbe_eeprom_operations eeprom_ops_X540 = { .init_params = &ixgbe_init_eeprom_params_X540, .read = &ixgbe_read_eerd_X540, + .read_buffer = &ixgbe_read_eerd_buffer_X540, .write = &ixgbe_write_eewr_X540, + .write_buffer = &ixgbe_write_eewr_buffer_X540, .calc_checksum = &ixgbe_calc_eeprom_checksum_X540, .validate_checksum = &ixgbe_validate_eeprom_checksum_X540, .update_checksum = &ixgbe_update_eeprom_checksum_X540, -- cgit v0.10.2 From 6716344c521bb585c1b89987c918d4b83b81adbe Mon Sep 17 00:00:00 2001 From: Don Skidmore Date: Tue, 26 Apr 2011 08:00:00 +0000 Subject: ixgbe: Cleanup PCIe bus speed info PCIe connections should be expressed as GT/s (GigaTransfers per second) instead of the current Gb/s (Gigabits per second). In addition, it is incorrect because (due to PCIe gen 1 & 2 having a 20% overhead) the actually data rate, when expressed in Gb/s, is only 80% of the rate of GT/s. Signed-off-by: Don Skidmore Tested-by: Evan Swanson Signed-off-by: Jeff Kirsher diff --git a/drivers/net/ixgbe/ixgbe_main.c b/drivers/net/ixgbe/ixgbe_main.c index bd3d21d..eebb192 100644 --- a/drivers/net/ixgbe/ixgbe_main.c +++ b/drivers/net/ixgbe/ixgbe_main.c @@ -7469,8 +7469,8 @@ static int __devinit ixgbe_probe(struct pci_dev *pdev, /* print bus type/speed/width info */ e_dev_info("(PCI Express:%s:%s) %pM\n", - (hw->bus.speed == ixgbe_bus_speed_5000 ? "5.0Gb/s" : - hw->bus.speed == ixgbe_bus_speed_2500 ? "2.5Gb/s" : + (hw->bus.speed == ixgbe_bus_speed_5000 ? "5.0GT/s" : + hw->bus.speed == ixgbe_bus_speed_2500 ? "2.5GT/s" : "Unknown"), (hw->bus.width == ixgbe_bus_width_pcie_x8 ? "Width x8" : hw->bus.width == ixgbe_bus_width_pcie_x4 ? "Width x4" : -- cgit v0.10.2 From 9a1b9496cd2b013f74885218947fa7120d53e74c Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Wed, 4 May 2011 12:18:54 -0700 Subject: ipv4: Pass explicit saddr/daddr args to ipmr_get_route(). This eliminates the need to use rt->rt_{src,dst}. Signed-off-by: David S. Miller diff --git a/include/linux/mroute.h b/include/linux/mroute.h index b21d567..46caaf4 100644 --- a/include/linux/mroute.h +++ b/include/linux/mroute.h @@ -244,6 +244,7 @@ struct mfc_cache { #ifdef __KERNEL__ struct rtmsg; extern int ipmr_get_route(struct net *net, struct sk_buff *skb, + __be32 saddr, __be32 daddr, struct rtmsg *rtm, int nowait); #endif diff --git a/net/ipv4/ipmr.c b/net/ipv4/ipmr.c index 86033b7..30a7763 100644 --- a/net/ipv4/ipmr.c +++ b/net/ipv4/ipmr.c @@ -2041,20 +2041,20 @@ rtattr_failure: return -EMSGSIZE; } -int ipmr_get_route(struct net *net, - struct sk_buff *skb, struct rtmsg *rtm, int nowait) +int ipmr_get_route(struct net *net, struct sk_buff *skb, + __be32 saddr, __be32 daddr, + struct rtmsg *rtm, int nowait) { - int err; - struct mr_table *mrt; struct mfc_cache *cache; - struct rtable *rt = skb_rtable(skb); + struct mr_table *mrt; + int err; mrt = ipmr_get_table(net, RT_TABLE_DEFAULT); if (mrt == NULL) return -ENOENT; rcu_read_lock(); - cache = ipmr_cache_find(mrt, rt->rt_src, rt->rt_dst); + cache = ipmr_cache_find(mrt, saddr, daddr); if (cache == NULL) { struct sk_buff *skb2; @@ -2087,8 +2087,8 @@ int ipmr_get_route(struct net *net, skb_reset_network_header(skb2); iph = ip_hdr(skb2); iph->ihl = sizeof(struct iphdr) >> 2; - iph->saddr = rt->rt_src; - iph->daddr = rt->rt_dst; + iph->saddr = saddr; + iph->daddr = daddr; iph->version = 0; err = ipmr_cache_unresolved(mrt, vif, skb2); read_unlock(&mrt_lock); diff --git a/net/ipv4/route.c b/net/ipv4/route.c index 3bc6854..6a83840 100644 --- a/net/ipv4/route.c +++ b/net/ipv4/route.c @@ -2857,7 +2857,9 @@ static int rt_fill_info(struct net *net, if (ipv4_is_multicast(dst) && !ipv4_is_local_multicast(dst) && IPV4_DEVCONF_ALL(net, MC_FORWARDING)) { - int err = ipmr_get_route(net, skb, r, nowait); + int err = ipmr_get_route(net, skb, + rt->rt_src, rt->rt_dst, + r, nowait); if (err <= 0) { if (!nowait) { if (err == 0) -- cgit v0.10.2 From b7534f002d3c81d18abfbf57179d07d3ec763bb5 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Sat, 30 Apr 2011 10:34:05 -0300 Subject: [media] v4l: Release module if subdev registration fails If v4l2_device_register_subdev() fails, the reference to the subdev module taken by the function isn't released. Fix this. Signed-off-by: Laurent Pinchart Cc: stable@kernel.org Acked-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/video/v4l2-device.c b/drivers/media/video/v4l2-device.c index 5aeaf87..4aae501 100644 --- a/drivers/media/video/v4l2-device.c +++ b/drivers/media/video/v4l2-device.c @@ -155,8 +155,10 @@ int v4l2_device_register_subdev(struct v4l2_device *v4l2_dev, sd->v4l2_dev = v4l2_dev; if (sd->internal_ops && sd->internal_ops->registered) { err = sd->internal_ops->registered(sd); - if (err) + if (err) { + module_put(sd->owner); return err; + } } /* This just returns 0 if either of the two args is NULL */ @@ -164,6 +166,7 @@ int v4l2_device_register_subdev(struct v4l2_device *v4l2_dev, if (err) { if (sd->internal_ops && sd->internal_ops->unregistered) sd->internal_ops->unregistered(sd); + module_put(sd->owner); return err; } -- cgit v0.10.2 From 2a164d02dd34c6b49a3f0995900e0f8af102b804 Mon Sep 17 00:00:00 2001 From: Lawrence Rust Date: Fri, 8 Apr 2011 09:50:45 -0300 Subject: [media] Fix cx88 remote control input In the IR interrupt handler of cx88-input.c there's a 32-bit multiply overflow which causes IR pulse durations to be incorrectly calculated. This is a regression caused by commit 2997137be8eba. Cc: stable@kernel.org Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/video/cx88/cx88-input.c b/drivers/media/video/cx88/cx88-input.c index c820e2f..3f44200 100644 --- a/drivers/media/video/cx88/cx88-input.c +++ b/drivers/media/video/cx88/cx88-input.c @@ -524,7 +524,7 @@ void cx88_ir_irq(struct cx88_core *core) for (todo = 32; todo > 0; todo -= bits) { ev.pulse = samples & 0x80000000 ? false : true; bits = min(todo, 32U - fls(ev.pulse ? samples : ~samples)); - ev.duration = (bits * NSEC_PER_SEC) / (1000 * ir_samplerate); + ev.duration = (bits * (NSEC_PER_SEC / 1000)) / ir_samplerate; ir_raw_event_store_with_filter(ir->dev, &ev); samples <<= bits; } -- cgit v0.10.2 From 2dd251f0a294300a1cf8f4b63768145fa6153c4d Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sat, 16 Apr 2011 10:23:51 +0100 Subject: drm/i915: Release object along create user fb error path Reported-by: Alan Cox Signed-off-by: Chris Wilson Cc: stable@kernel.org Signed-off-by: Keith Packard diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index e522c70..aab06cf 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -6579,8 +6579,10 @@ intel_user_framebuffer_create(struct drm_device *dev, return ERR_PTR(-ENOENT); intel_fb = kzalloc(sizeof(*intel_fb), GFP_KERNEL); - if (!intel_fb) + if (!intel_fb) { + drm_gem_object_unreference_unlocked(&obj->base); return ERR_PTR(-ENOMEM); + } ret = intel_framebuffer_init(dev, intel_fb, mode_cmd, obj); if (ret) { -- cgit v0.10.2 From 31acbcc408f412d1ba73765b846c38642be553c3 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sun, 17 Apr 2011 06:38:35 +0100 Subject: drm/i915/dp: Be paranoid in case we disable a DP before it is attached Given that the hardware may be left in a random condition by the BIOS, it is conceivable that we then attempt to clear the DP_PIPEB_SELECT bit without us ever enabling/attaching the DP encoder to a pipe. Thus causing a NULL deference when we attempt to wait for a vblank on that crtc. Reported-and-tested-by: Bryan Christ Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=36314 Signed-off-by: Chris Wilson Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=36456 Reported-and-tested-by: Bo Wang Cc: stable@kernel.org Signed-off-by: Keith Packard diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index cb8578b..a4d8031 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -1470,7 +1470,8 @@ intel_dp_link_down(struct intel_dp *intel_dp) if (!HAS_PCH_CPT(dev) && I915_READ(intel_dp->output_reg) & DP_PIPEB_SELECT) { - struct intel_crtc *intel_crtc = to_intel_crtc(intel_dp->base.base.crtc); + struct drm_crtc *crtc = intel_dp->base.base.crtc; + /* Hardware workaround: leaving our transcoder select * set to transcoder B while it's off will prevent the * corresponding HDMI output on transcoder A. @@ -1485,7 +1486,19 @@ intel_dp_link_down(struct intel_dp *intel_dp) /* Changes to enable or select take place the vblank * after being written. */ - intel_wait_for_vblank(dev, intel_crtc->pipe); + if (crtc == NULL) { + /* We can arrive here never having been attached + * to a CRTC, for instance, due to inheriting + * random state from the BIOS. + * + * If the pipe is not running, play safe and + * wait for the clocks to stabilise before + * continuing. + */ + POSTING_READ(intel_dp->output_reg); + msleep(50); + } else + intel_wait_for_vblank(dev, to_intel_crtc(crtc)->pipe); } I915_WRITE(intel_dp->output_reg, DP & ~DP_PORT_EN); -- cgit v0.10.2 From 0b84834a5a9f5fe8f3760560ef8c5b1536d22bd1 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Mon, 2 May 2011 08:09:25 -0300 Subject: [media] v4l2-subdev: fix broken subdev control enumeration The v4l2_subdev_* functions are meant for older V4L2 drivers that do not use the control framework yet. These functions should not be used by subdev_do_ioctl. Most of those backwards compatibility functions are just stubs, but commit 87a0c94ce616b231f3c0bd09d7dbd39d43b0557a actually changed the behavior of v4l2_subdev_queryctrl, so calling that one from subdev_do_ioctl broke the control enumeration in subdev nodes. The fix is simply not to use those compatibility functions in v4l2-subdev.c. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/video/v4l2-subdev.c b/drivers/media/video/v4l2-subdev.c index 0b80644..812729e 100644 --- a/drivers/media/video/v4l2-subdev.c +++ b/drivers/media/video/v4l2-subdev.c @@ -155,25 +155,25 @@ static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg) switch (cmd) { case VIDIOC_QUERYCTRL: - return v4l2_subdev_queryctrl(sd, arg); + return v4l2_queryctrl(sd->ctrl_handler, arg); case VIDIOC_QUERYMENU: - return v4l2_subdev_querymenu(sd, arg); + return v4l2_querymenu(sd->ctrl_handler, arg); case VIDIOC_G_CTRL: - return v4l2_subdev_g_ctrl(sd, arg); + return v4l2_g_ctrl(sd->ctrl_handler, arg); case VIDIOC_S_CTRL: - return v4l2_subdev_s_ctrl(sd, arg); + return v4l2_s_ctrl(sd->ctrl_handler, arg); case VIDIOC_G_EXT_CTRLS: - return v4l2_subdev_g_ext_ctrls(sd, arg); + return v4l2_g_ext_ctrls(sd->ctrl_handler, arg); case VIDIOC_S_EXT_CTRLS: - return v4l2_subdev_s_ext_ctrls(sd, arg); + return v4l2_s_ext_ctrls(sd->ctrl_handler, arg); case VIDIOC_TRY_EXT_CTRLS: - return v4l2_subdev_try_ext_ctrls(sd, arg); + return v4l2_try_ext_ctrls(sd->ctrl_handler, arg); case VIDIOC_DQEVENT: if (!(sd->flags & V4L2_SUBDEV_FL_HAS_EVENTS)) -- cgit v0.10.2 From dca6b6d18fa4428c4539e45f7a43040e388ab99e Mon Sep 17 00:00:00 2001 From: Sergio Aguirre Date: Mon, 11 Apr 2011 13:14:33 -0300 Subject: [media] V4L: soc-camera: regression fix: calculate .sizeimage in soc_camera.c A recent patch has given individual soc-camera host drivers a possibility to calculate .sizeimage and .bytesperline pixel format fields internally, however, some drivers relied on the core calculating these values for them, following a default algorithm. This patch restores the default calculation for such drivers. Based on initial patch by Guennadi Liakhovetski, found here: http://www.spinics.net/lists/linux-media/msg31282.html Except that this covers try_fmt aswell. Signed-off-by: Sergio Aguirre Signed-off-by: Guennadi Liakhovetski Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/video/soc_camera.c b/drivers/media/video/soc_camera.c index 3973f9a..ddb4c09 100644 --- a/drivers/media/video/soc_camera.c +++ b/drivers/media/video/soc_camera.c @@ -136,11 +136,50 @@ unsigned long soc_camera_apply_sensor_flags(struct soc_camera_link *icl, } EXPORT_SYMBOL(soc_camera_apply_sensor_flags); +#define pixfmtstr(x) (x) & 0xff, ((x) >> 8) & 0xff, ((x) >> 16) & 0xff, \ + ((x) >> 24) & 0xff + +static int soc_camera_try_fmt(struct soc_camera_device *icd, + struct v4l2_format *f) +{ + struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); + struct v4l2_pix_format *pix = &f->fmt.pix; + int ret; + + dev_dbg(&icd->dev, "TRY_FMT(%c%c%c%c, %ux%u)\n", + pixfmtstr(pix->pixelformat), pix->width, pix->height); + + pix->bytesperline = 0; + pix->sizeimage = 0; + + ret = ici->ops->try_fmt(icd, f); + if (ret < 0) + return ret; + + if (!pix->sizeimage) { + if (!pix->bytesperline) { + const struct soc_camera_format_xlate *xlate; + + xlate = soc_camera_xlate_by_fourcc(icd, pix->pixelformat); + if (!xlate) + return -EINVAL; + + ret = soc_mbus_bytes_per_line(pix->width, + xlate->host_fmt); + if (ret > 0) + pix->bytesperline = ret; + } + if (pix->bytesperline) + pix->sizeimage = pix->bytesperline * pix->height; + } + + return 0; +} + static int soc_camera_try_fmt_vid_cap(struct file *file, void *priv, struct v4l2_format *f) { struct soc_camera_device *icd = file->private_data; - struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); WARN_ON(priv != file->private_data); @@ -149,7 +188,7 @@ static int soc_camera_try_fmt_vid_cap(struct file *file, void *priv, return -EINVAL; /* limit format to hardware capabilities */ - return ici->ops->try_fmt(icd, f); + return soc_camera_try_fmt(icd, f); } static int soc_camera_enum_input(struct file *file, void *priv, @@ -362,9 +401,6 @@ static void soc_camera_free_user_formats(struct soc_camera_device *icd) icd->user_formats = NULL; } -#define pixfmtstr(x) (x) & 0xff, ((x) >> 8) & 0xff, ((x) >> 16) & 0xff, \ - ((x) >> 24) & 0xff - /* Called with .vb_lock held, or from the first open(2), see comment there */ static int soc_camera_set_fmt(struct soc_camera_device *icd, struct v4l2_format *f) @@ -377,7 +413,7 @@ static int soc_camera_set_fmt(struct soc_camera_device *icd, pixfmtstr(pix->pixelformat), pix->width, pix->height); /* We always call try_fmt() before set_fmt() or set_crop() */ - ret = ici->ops->try_fmt(icd, f); + ret = soc_camera_try_fmt(icd, f); if (ret < 0) return ret; -- cgit v0.10.2 From cbb1e85f9cfd2bd9b7edfd21d167e89a4279faf0 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Wed, 4 May 2011 12:33:34 -0700 Subject: ipv4: Kill rt->rt_{src, dst} usage in IP GRE tunnels. First, make callers pass on-stack flowi4 to ip_route_output_gre() so they can get at the fully resolved flow key. Next, use that in ipgre_tunnel_xmit() to avoid the need to use rt->rt_{dst,src}. Signed-off-by: David S. Miller diff --git a/include/net/route.h b/include/net/route.h index 8c02c87..9f8070b 100644 --- a/include/net/route.h +++ b/include/net/route.h @@ -152,19 +152,18 @@ static inline struct rtable *ip_route_output_ports(struct net *net, struct flowi return ip_route_output_flow(net, fl4, sk); } -static inline struct rtable *ip_route_output_gre(struct net *net, +static inline struct rtable *ip_route_output_gre(struct net *net, struct flowi4 *fl4, __be32 daddr, __be32 saddr, __be32 gre_key, __u8 tos, int oif) { - struct flowi4 fl4 = { - .flowi4_oif = oif, - .daddr = daddr, - .saddr = saddr, - .flowi4_tos = tos, - .flowi4_proto = IPPROTO_GRE, - .fl4_gre_key = gre_key, - }; - return ip_route_output_key(net, &fl4); + memset(fl4, 0, sizeof(*fl4)); + fl4->flowi4_oif = oif; + fl4->daddr = daddr; + fl4->saddr = saddr; + fl4->flowi4_tos = tos; + fl4->flowi4_proto = IPPROTO_GRE; + fl4->fl4_gre_key = gre_key; + return ip_route_output_key(net, fl4); } extern int ip_route_input_common(struct sk_buff *skb, __be32 dst, __be32 src, diff --git a/net/ipv4/ip_gre.c b/net/ipv4/ip_gre.c index 24efd35..10e9b5a 100644 --- a/net/ipv4/ip_gre.c +++ b/net/ipv4/ip_gre.c @@ -699,6 +699,7 @@ static netdev_tx_t ipgre_tunnel_xmit(struct sk_buff *skb, struct net_device *dev struct pcpu_tstats *tstats; const struct iphdr *old_iph = ip_hdr(skb); const struct iphdr *tiph; + struct flowi4 fl4; u8 tos; __be16 df; struct rtable *rt; /* Route to the other host */ @@ -769,7 +770,7 @@ static netdev_tx_t ipgre_tunnel_xmit(struct sk_buff *skb, struct net_device *dev tos = ipv6_get_dsfield((const struct ipv6hdr *)old_iph); } - rt = ip_route_output_gre(dev_net(dev), dst, tiph->saddr, + rt = ip_route_output_gre(dev_net(dev), &fl4, dst, tiph->saddr, tunnel->parms.o_key, RT_TOS(tos), tunnel->parms.link); if (IS_ERR(rt)) { @@ -873,8 +874,8 @@ static netdev_tx_t ipgre_tunnel_xmit(struct sk_buff *skb, struct net_device *dev iph->frag_off = df; iph->protocol = IPPROTO_GRE; iph->tos = ipgre_ecn_encapsulate(tos, old_iph, skb); - iph->daddr = rt->rt_dst; - iph->saddr = rt->rt_src; + iph->daddr = fl4.daddr; + iph->saddr = fl4.saddr; if ((iph->ttl = tiph->ttl) == 0) { if (skb->protocol == htons(ETH_P_IP)) @@ -938,12 +939,14 @@ static int ipgre_tunnel_bind_dev(struct net_device *dev) /* Guess output device to choose reasonable mtu and needed_headroom */ if (iph->daddr) { - struct rtable *rt = ip_route_output_gre(dev_net(dev), - iph->daddr, iph->saddr, - tunnel->parms.o_key, - RT_TOS(iph->tos), - tunnel->parms.link); - + struct flowi4 fl4; + struct rtable *rt; + + rt = ip_route_output_gre(dev_net(dev), &fl4, + iph->daddr, iph->saddr, + tunnel->parms.o_key, + RT_TOS(iph->tos), + tunnel->parms.link); if (!IS_ERR(rt)) { tdev = rt->dst.dev; ip_rt_put(rt); @@ -1196,13 +1199,15 @@ static int ipgre_open(struct net_device *dev) struct ip_tunnel *t = netdev_priv(dev); if (ipv4_is_multicast(t->parms.iph.daddr)) { - struct rtable *rt = ip_route_output_gre(dev_net(dev), - t->parms.iph.daddr, - t->parms.iph.saddr, - t->parms.o_key, - RT_TOS(t->parms.iph.tos), - t->parms.link); - + struct flowi4 fl4; + struct rtable *rt; + + rt = ip_route_output_gre(dev_net(dev), &fl4, + t->parms.iph.daddr, + t->parms.iph.saddr, + t->parms.o_key, + RT_TOS(t->parms.iph.tos), + t->parms.link); if (IS_ERR(rt)) return -EADDRNOTAVAIL; dev = rt->dst.dev; -- cgit v0.10.2 From 301102cc832f9f3e24c5748705f152eaa7c307f6 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Wed, 4 May 2011 12:46:24 -0700 Subject: ipv6: Use flowi4->{daddr,saddr} in ipip6_tunnel_xmit(). Instead of rt->rt_{dst,src} Signed-off-by: David S. Miller diff --git a/net/ipv6/sit.c b/net/ipv6/sit.c index a24fb14..c53abcf 100644 --- a/net/ipv6/sit.c +++ b/net/ipv6/sit.c @@ -828,8 +828,8 @@ static netdev_tx_t ipip6_tunnel_xmit(struct sk_buff *skb, iph->frag_off = df; iph->protocol = IPPROTO_IPV6; iph->tos = INET_ECN_encapsulate(tos, ipv6_get_dsfield(iph6)); - iph->daddr = rt->rt_dst; - iph->saddr = rt->rt_src; + iph->daddr = fl4.daddr; + iph->saddr = fl4.saddr; if ((iph->ttl = tiph->ttl) == 0) iph->ttl = iph6->hop_limit; -- cgit v0.10.2 From fca65b4ad72d28cbb43a029114d04b89f06faadb Mon Sep 17 00:00:00 2001 From: Sage Weil Date: Wed, 4 May 2011 11:33:47 -0700 Subject: ceph: do not call __mark_dirty_inode under i_lock The __mark_dirty_inode helper now takes i_lock as of 250df6ed. Fix the one ceph callers that held i_lock (__ceph_mark_dirty_caps) to return the flags value so that the callers can do it outside of i_lock. Signed-off-by: Sage Weil diff --git a/fs/ceph/caps.c b/fs/ceph/caps.c index 010ba9c..9fa0866 100644 --- a/fs/ceph/caps.c +++ b/fs/ceph/caps.c @@ -1331,10 +1331,11 @@ static void ceph_flush_snaps(struct ceph_inode_info *ci) } /* - * Mark caps dirty. If inode is newly dirty, add to the global dirty - * list. + * Mark caps dirty. If inode is newly dirty, return the dirty flags. + * Caller is then responsible for calling __mark_inode_dirty with the + * returned flags value. */ -void __ceph_mark_dirty_caps(struct ceph_inode_info *ci, int mask) +int __ceph_mark_dirty_caps(struct ceph_inode_info *ci, int mask) { struct ceph_mds_client *mdsc = ceph_sb_to_client(ci->vfs_inode.i_sb)->mdsc; @@ -1365,9 +1366,8 @@ void __ceph_mark_dirty_caps(struct ceph_inode_info *ci, int mask) if (((was | ci->i_flushing_caps) & CEPH_CAP_FILE_BUFFER) && (mask & CEPH_CAP_FILE_BUFFER)) dirty |= I_DIRTY_DATASYNC; - if (dirty) - __mark_inode_dirty(inode, dirty); __cap_delay_requeue(mdsc, ci); + return dirty; } /* diff --git a/fs/ceph/file.c b/fs/ceph/file.c index 159b512..203252d 100644 --- a/fs/ceph/file.c +++ b/fs/ceph/file.c @@ -734,9 +734,12 @@ retry_snap: } } if (ret >= 0) { + int dirty; spin_lock(&inode->i_lock); - __ceph_mark_dirty_caps(ci, CEPH_CAP_FILE_WR); + dirty = __ceph_mark_dirty_caps(ci, CEPH_CAP_FILE_WR); spin_unlock(&inode->i_lock); + if (dirty) + __mark_inode_dirty(inode, dirty); } out: diff --git a/fs/ceph/inode.c b/fs/ceph/inode.c index b54c97da..03d6daf 100644 --- a/fs/ceph/inode.c +++ b/fs/ceph/inode.c @@ -1567,6 +1567,7 @@ int ceph_setattr(struct dentry *dentry, struct iattr *attr) int release = 0, dirtied = 0; int mask = 0; int err = 0; + int inode_dirty_flags = 0; if (ceph_snap(inode) != CEPH_NOSNAP) return -EROFS; @@ -1725,13 +1726,16 @@ int ceph_setattr(struct dentry *dentry, struct iattr *attr) dout("setattr %p ATTR_FILE ... hrm!\n", inode); if (dirtied) { - __ceph_mark_dirty_caps(ci, dirtied); + inode_dirty_flags = __ceph_mark_dirty_caps(ci, dirtied); inode->i_ctime = CURRENT_TIME; } release &= issued; spin_unlock(&inode->i_lock); + if (inode_dirty_flags) + __mark_inode_dirty(inode, inode_dirty_flags); + if (mask) { req->r_inode = igrab(inode); req->r_inode_drop = release; diff --git a/fs/ceph/super.h b/fs/ceph/super.h index 619fe71..b1f1b8b 100644 --- a/fs/ceph/super.h +++ b/fs/ceph/super.h @@ -506,7 +506,7 @@ static inline int __ceph_caps_dirty(struct ceph_inode_info *ci) { return ci->i_dirty_caps | ci->i_flushing_caps; } -extern void __ceph_mark_dirty_caps(struct ceph_inode_info *ci, int mask); +extern int __ceph_mark_dirty_caps(struct ceph_inode_info *ci, int mask); extern int ceph_caps_revoking(struct ceph_inode_info *ci, int mask); extern int __ceph_caps_used(struct ceph_inode_info *ci); diff --git a/fs/ceph/xattr.c b/fs/ceph/xattr.c index 8c9eba6..f2b6286 100644 --- a/fs/ceph/xattr.c +++ b/fs/ceph/xattr.c @@ -703,6 +703,7 @@ int ceph_setxattr(struct dentry *dentry, const char *name, struct ceph_inode_xattr *xattr = NULL; int issued; int required_blob_size; + int dirty; if (ceph_snap(inode) != CEPH_NOSNAP) return -EROFS; @@ -763,11 +764,12 @@ retry: dout("setxattr %p issued %s\n", inode, ceph_cap_string(issued)); err = __set_xattr(ci, newname, name_len, newval, val_len, 1, 1, 1, &xattr); - __ceph_mark_dirty_caps(ci, CEPH_CAP_XATTR_EXCL); + dirty = __ceph_mark_dirty_caps(ci, CEPH_CAP_XATTR_EXCL); ci->i_xattrs.dirty = true; inode->i_ctime = CURRENT_TIME; spin_unlock(&inode->i_lock); - + if (dirty) + __mark_inode_dirty(inode, dirty); return err; do_sync: @@ -810,6 +812,7 @@ int ceph_removexattr(struct dentry *dentry, const char *name) struct ceph_vxattr_cb *vxattrs = ceph_inode_vxattrs(inode); int issued; int err; + int dirty; if (ceph_snap(inode) != CEPH_NOSNAP) return -EROFS; @@ -833,12 +836,13 @@ int ceph_removexattr(struct dentry *dentry, const char *name) goto do_sync; err = __remove_xattr_by_name(ceph_inode(inode), name); - __ceph_mark_dirty_caps(ci, CEPH_CAP_XATTR_EXCL); + dirty = __ceph_mark_dirty_caps(ci, CEPH_CAP_XATTR_EXCL); ci->i_xattrs.dirty = true; inode->i_ctime = CURRENT_TIME; spin_unlock(&inode->i_lock); - + if (dirty) + __mark_inode_dirty(inode, dirty); return err; do_sync: spin_unlock(&inode->i_lock); -- cgit v0.10.2 From 64f3b9e203bd06855072e295557dca1485a2ecba Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Wed, 4 May 2011 10:02:26 +0000 Subject: net: ip_expire() must revalidate route Commit 4a94445c9a5c (net: Use ip_route_input_noref() in input path) added a bug in IP defragmentation handling, in case timeout is fired. When a frame is defragmented, we use last skb dst field when building final skb. Its dst is valid, since we are in rcu read section. But if a timeout occurs, we take first queued fragment to build one ICMP TIME EXCEEDED message. Problem is all queued skb have weak dst pointers, since we escaped RCU critical section after their queueing. icmp_send() might dereference a now freed (and possibly reused) part of memory. Calling skb_dst_drop() and ip_route_input_noref() to revalidate route is the only possible choice. Reported-by: Denys Fedoryshchenko Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller diff --git a/net/ipv4/ip_fragment.c b/net/ipv4/ip_fragment.c index a1151b8..b1d282f 100644 --- a/net/ipv4/ip_fragment.c +++ b/net/ipv4/ip_fragment.c @@ -223,31 +223,30 @@ static void ip_expire(unsigned long arg) if ((qp->q.last_in & INET_FRAG_FIRST_IN) && qp->q.fragments != NULL) { struct sk_buff *head = qp->q.fragments; + const struct iphdr *iph; + int err; rcu_read_lock(); head->dev = dev_get_by_index_rcu(net, qp->iif); if (!head->dev) goto out_rcu_unlock; + /* skb dst is stale, drop it, and perform route lookup again */ + skb_dst_drop(head); + iph = ip_hdr(head); + err = ip_route_input_noref(head, iph->daddr, iph->saddr, + iph->tos, head->dev); + if (err) + goto out_rcu_unlock; + /* - * Only search router table for the head fragment, - * when defraging timeout at PRE_ROUTING HOOK. + * Only an end host needs to send an ICMP + * "Fragment Reassembly Timeout" message, per RFC792. */ - if (qp->user == IP_DEFRAG_CONNTRACK_IN && !skb_dst(head)) { - const struct iphdr *iph = ip_hdr(head); - int err = ip_route_input(head, iph->daddr, iph->saddr, - iph->tos, head->dev); - if (unlikely(err)) - goto out_rcu_unlock; - - /* - * Only an end host needs to send an ICMP - * "Fragment Reassembly Timeout" message, per RFC792. - */ - if (skb_rtable(head)->rt_type != RTN_LOCAL) - goto out_rcu_unlock; + if (qp->user == IP_DEFRAG_CONNTRACK_IN && + skb_rtable(head)->rt_type != RTN_LOCAL) + goto out_rcu_unlock; - } /* Send an ICMP "Fragment Reassembly Timeout" message. */ icmp_send(head, ICMP_TIME_EXCEEDED, ICMP_EXC_FRAGTIME, 0); -- cgit v0.10.2 From 1650629d1800bf05ad775f974e931ca2fa03b0ff Mon Sep 17 00:00:00 2001 From: Kurt Van Dijck Date: Tue, 3 May 2011 18:40:57 +0000 Subject: can: make struct can_proto const commit 53914b67993c724cec585863755c9ebc8446e83b had the same message. That commit did put everything in place but did not make can_proto const itself. Signed-off-by: Kurt Van Dijck Acked-by: Oliver Hartkopp Signed-off-by: David S. Miller diff --git a/include/linux/can/core.h b/include/linux/can/core.h index 6f70a6d..5ce6b5d 100644 --- a/include/linux/can/core.h +++ b/include/linux/can/core.h @@ -44,8 +44,8 @@ struct can_proto { /* function prototypes for the CAN networklayer core (af_can.c) */ -extern int can_proto_register(struct can_proto *cp); -extern void can_proto_unregister(struct can_proto *cp); +extern int can_proto_register(const struct can_proto *cp); +extern void can_proto_unregister(const struct can_proto *cp); extern int can_rx_register(struct net_device *dev, canid_t can_id, canid_t mask, diff --git a/net/can/af_can.c b/net/can/af_can.c index a8dcaa4..5b52762 100644 --- a/net/can/af_can.c +++ b/net/can/af_can.c @@ -84,7 +84,7 @@ static DEFINE_SPINLOCK(can_rcvlists_lock); static struct kmem_cache *rcv_cache __read_mostly; /* table of registered CAN protocols */ -static struct can_proto *proto_tab[CAN_NPROTO] __read_mostly; +static const struct can_proto *proto_tab[CAN_NPROTO] __read_mostly; static DEFINE_MUTEX(proto_tab_lock); struct timer_list can_stattimer; /* timer for statistics update */ @@ -115,9 +115,9 @@ static void can_sock_destruct(struct sock *sk) skb_queue_purge(&sk->sk_receive_queue); } -static struct can_proto *can_try_module_get(int protocol) +static const struct can_proto *can_try_module_get(int protocol) { - struct can_proto *cp; + const struct can_proto *cp; rcu_read_lock(); cp = rcu_dereference(proto_tab[protocol]); @@ -132,7 +132,7 @@ static int can_create(struct net *net, struct socket *sock, int protocol, int kern) { struct sock *sk; - struct can_proto *cp; + const struct can_proto *cp; int err = 0; sock->state = SS_UNCONNECTED; @@ -691,7 +691,7 @@ drop: * -EBUSY protocol already in use * -ENOBUF if proto_register() fails */ -int can_proto_register(struct can_proto *cp) +int can_proto_register(const struct can_proto *cp) { int proto = cp->protocol; int err = 0; @@ -728,7 +728,7 @@ EXPORT_SYMBOL(can_proto_register); * can_proto_unregister - unregister CAN transport protocol * @cp: pointer to CAN protocol structure */ -void can_proto_unregister(struct can_proto *cp) +void can_proto_unregister(const struct can_proto *cp) { int proto = cp->protocol; diff --git a/net/can/bcm.c b/net/can/bcm.c index 8a6a05e..cced806 100644 --- a/net/can/bcm.c +++ b/net/can/bcm.c @@ -1601,7 +1601,7 @@ static struct proto bcm_proto __read_mostly = { .init = bcm_init, }; -static struct can_proto bcm_can_proto __read_mostly = { +static const struct can_proto bcm_can_proto = { .type = SOCK_DGRAM, .protocol = CAN_BCM, .ops = &bcm_ops, diff --git a/net/can/raw.c b/net/can/raw.c index 0eb39a7..dea99a6 100644 --- a/net/can/raw.c +++ b/net/can/raw.c @@ -774,7 +774,7 @@ static struct proto raw_proto __read_mostly = { .init = raw_init, }; -static struct can_proto raw_can_proto __read_mostly = { +static const struct can_proto raw_can_proto = { .type = SOCK_RAW, .protocol = CAN_RAW, .ops = &raw_ops, -- cgit v0.10.2 From c8d55a9d9e257e67d02a6f673a943dd77e6bf24e Mon Sep 17 00:00:00 2001 From: Kurt Van Dijck Date: Tue, 3 May 2011 18:42:04 +0000 Subject: can: rename can_try_module_get to can_get_proto can: rename can_try_module_get to can_get_proto can_try_module_get does return a struct can_proto. The name explains what is done in so much detail that a caller may not notice that a struct can_proto is locked/unlocked. Signed-off-by: Kurt Van Dijck Acked-by: Oliver Hartkopp Signed-off-by: David S. Miller diff --git a/net/can/af_can.c b/net/can/af_can.c index 5b52762..094fc53 100644 --- a/net/can/af_can.c +++ b/net/can/af_can.c @@ -115,7 +115,7 @@ static void can_sock_destruct(struct sock *sk) skb_queue_purge(&sk->sk_receive_queue); } -static const struct can_proto *can_try_module_get(int protocol) +static const struct can_proto *can_get_proto(int protocol) { const struct can_proto *cp; @@ -128,6 +128,11 @@ static const struct can_proto *can_try_module_get(int protocol) return cp; } +static inline void can_put_proto(const struct can_proto *cp) +{ + module_put(cp->prot->owner); +} + static int can_create(struct net *net, struct socket *sock, int protocol, int kern) { @@ -143,7 +148,7 @@ static int can_create(struct net *net, struct socket *sock, int protocol, if (!net_eq(net, &init_net)) return -EAFNOSUPPORT; - cp = can_try_module_get(protocol); + cp = can_get_proto(protocol); #ifdef CONFIG_MODULES if (!cp) { @@ -160,7 +165,7 @@ static int can_create(struct net *net, struct socket *sock, int protocol, printk(KERN_ERR "can: request_module " "(can-proto-%d) failed.\n", protocol); - cp = can_try_module_get(protocol); + cp = can_get_proto(protocol); } #endif @@ -195,7 +200,7 @@ static int can_create(struct net *net, struct socket *sock, int protocol, } errout: - module_put(cp->prot->owner); + can_put_proto(cp); return err; } -- cgit v0.10.2 From 30106b8ce2cc2243514116d6f29086e6deecc754 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Wed, 4 May 2011 15:38:19 +0200 Subject: slub: Fix the lockless code on 32-bit platforms with no 64-bit cmpxchg The SLUB allocator use of the cmpxchg_double logic was wrong: it actually needs the irq-safe one. That happens automatically when we use the native unlocked 'cmpxchg8b' instruction, but when compiling the kernel for older x86 CPUs that do not support that instruction, we fall back to the generic emulation code. And if you don't specify that you want the irq-safe version, the generic code ends up just open-coding the cmpxchg8b equivalent without any protection against interrupts or preemption. Which definitely doesn't work for SLUB. This was reported by Werner Landgraf , who saw instability with his distro-kernel that was compiled to support pretty much everything under the sun. Most big Linux distributions tend to compile for PPro and later, and would never have noticed this problem. This also fixes the prototypes for the irqsafe cmpxchg_double functions to use 'bool' like they should. [ Btw, that whole "generic code defaults to no protection" design just sounds stupid - if the code needs no protection, there is no reason to use "cmpxchg_double" to begin with. So we should probably just remove the unprotected version entirely as pointless. - Linus ] Signed-off-by: Thomas Gleixner Reported-and-tested-by: werner Acked-and-tested-by: Ingo Molnar Acked-by: Christoph Lameter Cc: Pekka Enberg Cc: Jens Axboe Cc: Tejun Heo Link: http://lkml.kernel.org/r/alpine.LFD.2.02.1105041539050.3005@ionos Signed-off-by: Ingo Molnar Signed-off-by: Linus Torvalds diff --git a/include/linux/percpu.h b/include/linux/percpu.h index 3a5c444..8b97308 100644 --- a/include/linux/percpu.h +++ b/include/linux/percpu.h @@ -948,7 +948,7 @@ do { \ irqsafe_generic_cpu_cmpxchg_double(pcp1, pcp2, oval1, oval2, nval1, nval2) # endif # define irqsafe_cpu_cmpxchg_double(pcp1, pcp2, oval1, oval2, nval1, nval2) \ - __pcpu_double_call_return_int(irqsafe_cpu_cmpxchg_double_, (pcp1), (pcp2), (oval1), (oval2), (nval1), (nval2)) + __pcpu_double_call_return_bool(irqsafe_cpu_cmpxchg_double_, (pcp1), (pcp2), (oval1), (oval2), (nval1), (nval2)) #endif #endif /* __LINUX_PERCPU_H */ diff --git a/mm/slub.c b/mm/slub.c index 94d2a33..9d2e5e4 100644 --- a/mm/slub.c +++ b/mm/slub.c @@ -1940,7 +1940,7 @@ redo: * Since this is without lock semantics the protection is only against * code executing on this cpu *not* from access by other cpus. */ - if (unlikely(!this_cpu_cmpxchg_double( + if (unlikely(!irqsafe_cpu_cmpxchg_double( s->cpu_slab->freelist, s->cpu_slab->tid, object, tid, get_freepointer(s, object), next_tid(tid)))) { @@ -2145,7 +2145,7 @@ redo: set_freepointer(s, object, c->freelist); #ifdef CONFIG_CMPXCHG_LOCAL - if (unlikely(!this_cpu_cmpxchg_double( + if (unlikely(!irqsafe_cpu_cmpxchg_double( s->cpu_slab->freelist, s->cpu_slab->tid, c->freelist, tid, object, next_tid(tid)))) { -- cgit v0.10.2 From a1fde08c74e90accd62d4cfdbf580d2ede938fe7 Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Wed, 4 May 2011 21:30:28 -0700 Subject: VM: skip the stack guard page lookup in get_user_pages only for mlock The logic in __get_user_pages() used to skip the stack guard page lookup whenever the caller wasn't interested in seeing what the actual page was. But Michel Lespinasse points out that there are cases where we don't care about the physical page itself (so 'pages' may be NULL), but do want to make sure a page is mapped into the virtual address space. So using the existence of the "pages" array as an indication of whether to look up the guard page or not isn't actually so great, and we really should just use the FOLL_MLOCK bit. But because that bit was only set for the VM_LOCKED case (and not all vma's necessarily have it, even for mlock()), we couldn't do that originally. Fix that by moving the VM_LOCKED check deeper into the call-chain, which actually simplifies many things. Now mlock() gets simpler, and we can also check for FOLL_MLOCK in __get_user_pages() and the code ends up much more straightforward. Reported-and-reviewed-by: Michel Lespinasse Cc: stable@kernel.org Signed-off-by: Linus Torvalds diff --git a/mm/memory.c b/mm/memory.c index 607098d4..27f4253 100644 --- a/mm/memory.c +++ b/mm/memory.c @@ -1359,7 +1359,7 @@ split_fallthrough: */ mark_page_accessed(page); } - if (flags & FOLL_MLOCK) { + if ((flags & FOLL_MLOCK) && (vma->vm_flags & VM_LOCKED)) { /* * The preliminary mapping check is mainly to avoid the * pointless overhead of lock_page on the ZERO_PAGE @@ -1552,10 +1552,9 @@ int __get_user_pages(struct task_struct *tsk, struct mm_struct *mm, } /* - * If we don't actually want the page itself, - * and it's the stack guard page, just skip it. + * For mlock, just skip the stack guard page. */ - if (!pages && stack_guard_page(vma, start)) + if ((gup_flags & FOLL_MLOCK) && stack_guard_page(vma, start)) goto next_page; do { diff --git a/mm/mlock.c b/mm/mlock.c index 6b55e3e..516b2c2 100644 --- a/mm/mlock.c +++ b/mm/mlock.c @@ -162,7 +162,7 @@ static long __mlock_vma_pages_range(struct vm_area_struct *vma, VM_BUG_ON(end > vma->vm_end); VM_BUG_ON(!rwsem_is_locked(&mm->mmap_sem)); - gup_flags = FOLL_TOUCH; + gup_flags = FOLL_TOUCH | FOLL_MLOCK; /* * We want to touch writable mappings with a write fault in order * to break COW, except for shared mappings because these don't COW @@ -178,9 +178,6 @@ static long __mlock_vma_pages_range(struct vm_area_struct *vma, if (vma->vm_flags & (VM_READ | VM_WRITE | VM_EXEC)) gup_flags |= FOLL_FORCE; - if (vma->vm_flags & VM_LOCKED) - gup_flags |= FOLL_MLOCK; - return __get_user_pages(current, mm, addr, nr_pages, gup_flags, NULL, NULL, nonblocking); } -- cgit v0.10.2 From d192a8e5c6fec4fe8cdafebccc415db4074dee88 Mon Sep 17 00:00:00 2001 From: Steven Whitehouse Date: Thu, 5 May 2011 12:35:40 +0100 Subject: GFS2: Double check link count under glock To avoid any possible races relating to the link count, we need to recheck it under the inode's glock in all cases where it matters. Also to ensure we never get any nasty surprises, this patch also ensures that once the link count has hit zero it can never be elevated by rereading in data from disk. The only place we cannot provide a proper solution is in rename in the case where we are removing a target inode and we discover that the target inode has been already unlinked on another node. The race window is very small, and we return EAGAIN in this case to indicate what has happened. The proper solution would be to move the lookup parts of rename from the vfs into library calls which the fs could call directly, but that is potentially a very big job and this fix should cover most cases for now. Signed-off-by: Steven Whitehouse diff --git a/fs/gfs2/inode.c b/fs/gfs2/inode.c index 94c3a7d..5a02606 100644 --- a/fs/gfs2/inode.c +++ b/fs/gfs2/inode.c @@ -248,6 +248,32 @@ fail_iput: goto fail; } +/** + * gfs2_set_nlink - Set the inode's link count based on on-disk info + * @inode: The inode in question + * @nlink: The link count + * + * If the link count has hit zero, it must never be raised, whatever the + * on-disk inode might say. When new struct inodes are created the link + * count is set to 1, so that we can safely use this test even when reading + * in on disk information for the first time. + */ + +static void gfs2_set_nlink(struct inode *inode, u32 nlink) +{ + /* + * We will need to review setting the nlink count here in the + * light of the forthcoming ro bind mount work. This is a reminder + * to do that. + */ + if ((inode->i_nlink != nlink) && (inode->i_nlink != 0)) { + if (nlink == 0) + clear_nlink(inode); + else + inode->i_nlink = nlink; + } +} + static int gfs2_dinode_in(struct gfs2_inode *ip, const void *buf) { const struct gfs2_dinode *str = buf; @@ -269,12 +295,7 @@ static int gfs2_dinode_in(struct gfs2_inode *ip, const void *buf) ip->i_inode.i_uid = be32_to_cpu(str->di_uid); ip->i_inode.i_gid = be32_to_cpu(str->di_gid); - /* - * We will need to review setting the nlink count here in the - * light of the forthcoming ro bind mount work. This is a reminder - * to do that. - */ - ip->i_inode.i_nlink = be32_to_cpu(str->di_nlink); + gfs2_set_nlink(&ip->i_inode, be32_to_cpu(str->di_nlink)); i_size_write(&ip->i_inode, be64_to_cpu(str->di_size)); gfs2_set_inode_blocks(&ip->i_inode, be64_to_cpu(str->di_blocks)); atime.tv_sec = be64_to_cpu(str->di_atime); @@ -484,7 +505,7 @@ static int create_ok(struct gfs2_inode *dip, const struct qstr *name, /* Don't create entries in an unlinked directory */ if (!dip->i_inode.i_nlink) - return -EPERM; + return -ENOENT; error = gfs2_dir_check(&dip->i_inode, name, NULL); switch (error) { diff --git a/fs/gfs2/ops_inode.c b/fs/gfs2/ops_inode.c index 09e436a..1005f9e 100644 --- a/fs/gfs2/ops_inode.c +++ b/fs/gfs2/ops_inode.c @@ -162,6 +162,10 @@ static int gfs2_link(struct dentry *old_dentry, struct inode *dir, if (error) goto out_child; + error = -ENOENT; + if (inode->i_nlink == 0) + goto out_gunlock; + error = gfs2_permission(dir, MAY_WRITE | MAY_EXEC, 0); if (error) goto out_gunlock; @@ -335,6 +339,10 @@ static int gfs2_unlink(struct inode *dir, struct dentry *dentry) if (error) goto out_child; + error = -ENOENT; + if (ip->i_inode.i_nlink == 0) + goto out_rgrp; + error = gfs2_glock_nq(ghs + 2); /* rgrp */ if (error) goto out_rgrp; @@ -589,6 +597,10 @@ static int gfs2_rmdir(struct inode *dir, struct dentry *dentry) if (error) goto out_child; + error = -ENOENT; + if (ip->i_inode.i_nlink == 0) + goto out_rgrp; + error = gfs2_glock_nq(ghs + 2); /* rgrp */ if (error) goto out_rgrp; @@ -792,6 +804,10 @@ static int gfs2_rename(struct inode *odir, struct dentry *odentry, goto out_gunlock; } + error = -ENOENT; + if (ip->i_inode.i_nlink == 0) + goto out_gunlock; + /* Check out the old directory */ error = gfs2_unlink_ok(odip, &odentry->d_name, ip); @@ -805,6 +821,11 @@ static int gfs2_rename(struct inode *odir, struct dentry *odentry, if (error) goto out_gunlock; + if (nip->i_inode.i_nlink == 0) { + error = -EAGAIN; + goto out_gunlock; + } + if (S_ISDIR(nip->i_inode.i_mode)) { if (nip->i_entries < 2) { if (gfs2_consist_inode(nip)) @@ -835,7 +856,7 @@ static int gfs2_rename(struct inode *odir, struct dentry *odentry, if (odip != ndip) { if (!ndip->i_inode.i_nlink) { - error = -EINVAL; + error = -ENOENT; goto out_gunlock; } if (ndip->i_entries == (u32)-1) { -- cgit v0.10.2 From 588da3b3be8b3225c2dd192aa782bf6c5c32eb84 Mon Sep 17 00:00:00 2001 From: Steven Whitehouse Date: Thu, 5 May 2011 12:36:38 +0100 Subject: GFS2: Don't use a try lock when promoting to a higher mode Previously we marked all locks being promoted to a higher mode with the try flag to avoid any potential deadlocks issues. The DLM is able to detect these and report them in way that GFS2 can deal with them correctly. So we can just request the required mode and wait for a response without needing to perform this check. Signed-off-by: Steven Whitehouse diff --git a/fs/gfs2/glock.c b/fs/gfs2/glock.c index eed4b68..ee2178d 100644 --- a/fs/gfs2/glock.c +++ b/fs/gfs2/glock.c @@ -543,11 +543,6 @@ __acquires(&gl->gl_spin) clear_bit(GLF_INVALIDATE_IN_PROGRESS, &gl->gl_flags); gfs2_glock_hold(gl); - if (target != LM_ST_UNLOCKED && (gl->gl_state == LM_ST_SHARED || - gl->gl_state == LM_ST_DEFERRED) && - !(lck_flags & (LM_FLAG_TRY | LM_FLAG_TRY_1CB))) - lck_flags |= LM_FLAG_TRY_1CB; - if (sdp->sd_lockstruct.ls_ops->lm_lock) { /* lock_dlm */ ret = sdp->sd_lockstruct.ls_ops->lm_lock(gl, target, lck_flags); -- cgit v0.10.2 From e05b2efb82596905ebfe88e8612ee81dec9b6592 Mon Sep 17 00:00:00 2001 From: john stultz Date: Wed, 4 May 2011 18:16:50 -0700 Subject: clocksource: Install completely before selecting Christian Hoffmann reported that the command line clocksource override with acpi_pm timer fails: Kernel command line: clocksource=acpi_pm hpet clockevent registered Switching to clocksource hpet Override clocksource acpi_pm is not HRT compatible. Cannot switch while in HRT/NOHZ mode. The watchdog code is what enables CLOCK_SOURCE_VALID_FOR_HRES, but we actually end up selecting the clocksource before we enqueue it into the watchdog list, so that's why we see the warning and fail to switch to acpi_pm timer as requested. That's particularly bad when we want to debug timekeeping related problems in early boot. Put the selection call last. Reported-by: Christian Hoffmann Signed-off-by: John Stultz Cc: stable@kernel.org # 32... Link: http://lkml.kernel.org/r/%3C1304558210.2943.24.camel%40work-vm%3E Signed-off-by: Thomas Gleixner diff --git a/kernel/time/clocksource.c b/kernel/time/clocksource.c index 6519cf6..0e17c10 100644 --- a/kernel/time/clocksource.c +++ b/kernel/time/clocksource.c @@ -685,8 +685,8 @@ int __clocksource_register_scale(struct clocksource *cs, u32 scale, u32 freq) /* Add clocksource to the clcoksource list */ mutex_lock(&clocksource_mutex); clocksource_enqueue(cs); - clocksource_select(); clocksource_enqueue_watchdog(cs); + clocksource_select(); mutex_unlock(&clocksource_mutex); return 0; } @@ -706,8 +706,8 @@ int clocksource_register(struct clocksource *cs) mutex_lock(&clocksource_mutex); clocksource_enqueue(cs); - clocksource_select(); clocksource_enqueue_watchdog(cs); + clocksource_select(); mutex_unlock(&clocksource_mutex); return 0; } -- cgit v0.10.2 From eaef6a93bd52a2cc47b9fce201310010707afdb4 Mon Sep 17 00:00:00 2001 From: Mohammed Shafi Shajakhan Date: Thu, 5 May 2011 10:59:24 +0530 Subject: mac80211: Fix a warning due to skipping tailroom reservation for IV The devices that require IV generation in software need tailroom reservation for ICVs used in TKIP or WEP encryptions. Currently, decision to skip the tailroom reservation in the tx path was taken only on whether driver wants MMIC to be generated in software or not. Following patch appends IV generation check for such decisions and fixes the following warning. WARNING: at net/mac80211/wep.c:101 ieee80211_wep_add_iv+0x56/0xf3() Hardware name: 64756D6 Modules linked in: ath9k ath9k_common ath9k_hw Pid: 0, comm: swapper Tainted: G W 2.6.39-rc5-wl Call Trace: [] warn_slowpath_common+0x65/0x7a [] ? ieee80211_wep_add_iv+0x56/0xf3 [] warn_slowpath_null+0xf/0x13 [] ieee80211_wep_add_iv+0x56/0xf3 [] ieee80211_crypto_wep_encrypt+0x63/0x88 [] ieee80211_tx_h_encrypt+0x2f/0x63 [] invoke_tx_handlers+0x93/0xe1 [] ieee80211_tx+0x4b/0x6d [] ieee80211_xmit+0x180/0x188 [] ? ieee80211_skb_resize+0x95/0xd9 [] ieee80211_subif_start_xmit+0x64f/0x668 [] dev_hard_start_xmit+0x368/0x48c [] sch_direct_xmit+0x4d/0x101 [] dev_queue_xmit+0x2c1/0x43f [] ? eth_header+0x1e/0x90 [] ? eth_type_trans+0x91/0xc2 [] ? eth_rebuild_header+0x53/0x53 [] neigh_resolve_output+0x223/0x27e [] ip_finish_output2+0x1d4/0x1fe [] ip_finish_output+0x79/0x7d [] T.1075+0x43/0x48 [] ip_output+0x75/0x7b [] dst_output+0xc/0xe [] ip_local_out+0x17/0x1a [] ip_queue_xmit+0x2aa/0x2f8 [] ? sk_setup_caps+0x21/0x92 [] ? __tcp_v4_send_check+0x7e/0xb7 [] tcp_transmit_skb+0x6a1/0x6d7 [] ? tcp_established_options+0x20/0x8b [] tcp_retransmit_skb+0x43a/0x527 [] tcp_retransmit_timer+0x32e/0x45d [] tcp_write_timer+0x87/0x16c [] run_timer_softirq+0x156/0x1f9 [] ? tcp_retransmit_timer+0x45d/0x45d [] __do_softirq+0x97/0x14a [] ? irq_enter+0x4d/0x4d Cc: Yogesh Powar Reported-by: Fabio Rossi Tested-by: Fabio Rossi Signed-off-by: Mohammed Shafi Shajakhan Signed-off-by: John W. Linville diff --git a/net/mac80211/key.c b/net/mac80211/key.c index ca3c626..b510721 100644 --- a/net/mac80211/key.c +++ b/net/mac80211/key.c @@ -102,7 +102,8 @@ static int ieee80211_key_enable_hw_accel(struct ieee80211_key *key) if (!ret) { key->flags |= KEY_FLAG_UPLOADED_TO_HARDWARE; - if (!(key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_MMIC)) + if (!((key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_MMIC) || + (key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_IV))) key->local->crypto_tx_tailroom_needed_cnt--; return 0; @@ -161,7 +162,8 @@ static void ieee80211_key_disable_hw_accel(struct ieee80211_key *key) key->flags &= ~KEY_FLAG_UPLOADED_TO_HARDWARE; - if (!(key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_MMIC)) + if (!((key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_MMIC) || + (key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_IV))) key->local->crypto_tx_tailroom_needed_cnt++; } -- cgit v0.10.2 From 1dbe7dada2d03d1313183d439068f1f951a91244 Mon Sep 17 00:00:00 2001 From: Alexander Stein Date: Thu, 5 May 2011 08:40:14 -0700 Subject: Input: ads7846 - make transfer buffers DMA safe req.sample needs its own cacheline otherwise accessing req.msg fetches it in again. Note: This effect doesn't occur if the underlying SPI driver doesn't use DMA at all. Signed-off-by: Alexander Stein Acked-by: Jonathan Cameron Signed-off-by: Dmitry Torokhov diff --git a/drivers/input/touchscreen/ads7846.c b/drivers/input/touchscreen/ads7846.c index c24946f..ab51a8db 100644 --- a/drivers/input/touchscreen/ads7846.c +++ b/drivers/input/touchscreen/ads7846.c @@ -281,17 +281,25 @@ struct ser_req { u8 command; u8 ref_off; u16 scratch; - __be16 sample; struct spi_message msg; struct spi_transfer xfer[6]; + /* + * DMA (thus cache coherency maintenance) requires the + * transfer buffers to live in their own cache lines. + */ + __be16 sample ____cacheline_aligned; }; struct ads7845_ser_req { u8 command[3]; u8 pwrdown[3]; - u8 sample[3]; struct spi_message msg; struct spi_transfer xfer[2]; + /* + * DMA (thus cache coherency maintenance) requires the + * transfer buffers to live in their own cache lines. + */ + u8 sample[3] ____cacheline_aligned; }; static int ads7846_read12_ser(struct device *dev, unsigned command) -- cgit v0.10.2 From 28350e330cfab46b60a1dbf763b678d859f9f3d9 Mon Sep 17 00:00:00 2001 From: Alexander Stein Date: Thu, 5 May 2011 08:40:46 -0700 Subject: Input: ads7846 - remove unused variable from struct ads7845_ser_req Signed-off-by: Alexander Stein Signed-off-by: Dmitry Torokhov diff --git a/drivers/input/touchscreen/ads7846.c b/drivers/input/touchscreen/ads7846.c index ab51a8db..1de1c19 100644 --- a/drivers/input/touchscreen/ads7846.c +++ b/drivers/input/touchscreen/ads7846.c @@ -292,7 +292,6 @@ struct ser_req { struct ads7845_ser_req { u8 command[3]; - u8 pwrdown[3]; struct spi_message msg; struct spi_transfer xfer[2]; /* -- cgit v0.10.2 From 9e4425fff9e0a0fb6a8c705777ed861f991f8747 Mon Sep 17 00:00:00 2001 From: "Gustavo F. Padovan" Date: Mon, 18 Apr 2011 18:38:43 -0300 Subject: Bluetooth: Add l2cap_add_psm() and l2cap_add_scid() The intention is to get rid of the l2cap_sk_list usage inside l2cap_core.c. l2cap_sk_list will soon be replaced by a list that does not depend on socket usage. Signed-off-by: Gustavo F. Padovan diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h index c34b1c1..f5f3c2c 100644 --- a/include/net/bluetooth/l2cap.h +++ b/include/net/bluetooth/l2cap.h @@ -458,6 +458,10 @@ void l2cap_do_send(struct l2cap_chan *chan, struct sk_buff *skb); void l2cap_streaming_send(struct l2cap_chan *chan); int l2cap_ertm_send(struct l2cap_chan *chan); +struct sock *__l2cap_get_sock_by_addr(__le16 psm, bdaddr_t *src); +int l2cap_add_psm(struct l2cap_chan *chan, bdaddr_t *src, __le16 psm); +int l2cap_add_scid(struct l2cap_chan *chan, __u16 scid); + void l2cap_sock_set_timer(struct sock *sk, long timeout); void l2cap_sock_clear_timer(struct sock *sk); void __l2cap_sock_close(struct sock *sk, int reason); diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index 338d8c3..98ddd86 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -135,6 +135,50 @@ static inline struct l2cap_chan *l2cap_get_chan_by_ident(struct l2cap_conn *conn return c; } +struct sock *__l2cap_get_sock_by_addr(__le16 psm, bdaddr_t *src) +{ + struct sock *sk; + struct hlist_node *node; + sk_for_each(sk, node, &l2cap_sk_list.head) { + struct l2cap_chan *chan = l2cap_pi(sk)->chan; + + if (chan->sport == psm && !bacmp(&bt_sk(sk)->src, src)) + goto found; + } + + sk = NULL; +found: + return sk; +} + +int l2cap_add_psm(struct l2cap_chan *chan, bdaddr_t *src, __le16 psm) +{ + write_lock_bh(&l2cap_sk_list.lock); + + if (__l2cap_get_sock_by_addr(psm, src)) { + write_unlock_bh(&l2cap_sk_list.lock); + return -EADDRINUSE; + } + + chan->psm = psm; + chan->sport = psm; + + write_unlock_bh(&l2cap_sk_list.lock); + + return 0; +} + +int l2cap_add_scid(struct l2cap_chan *chan, __u16 scid) +{ + write_lock_bh(&l2cap_sk_list.lock); + + chan->scid = scid; + + write_unlock_bh(&l2cap_sk_list.lock); + + return 0; +} + static u16 l2cap_alloc_cid(struct l2cap_conn *conn) { u16 cid = L2CAP_CID_DYN_START; diff --git a/net/bluetooth/l2cap_sock.c b/net/bluetooth/l2cap_sock.c index 09cc7a0..2156dce 100644 --- a/net/bluetooth/l2cap_sock.c +++ b/net/bluetooth/l2cap_sock.c @@ -78,22 +78,6 @@ void l2cap_sock_clear_timer(struct sock *sk) sk_stop_timer(sk, &sk->sk_timer); } -static struct sock *__l2cap_get_sock_by_addr(__le16 psm, bdaddr_t *src) -{ - struct sock *sk; - struct hlist_node *node; - sk_for_each(sk, node, &l2cap_sk_list.head) { - struct l2cap_chan *chan = l2cap_pi(sk)->chan; - - if (chan->sport == psm && !bacmp(&bt_sk(sk)->src, src)) - goto found; - } - - sk = NULL; -found: - return sk; -} - static int l2cap_sock_bind(struct socket *sock, struct sockaddr *addr, int alen) { struct sock *sk = sock->sk; @@ -136,26 +120,20 @@ static int l2cap_sock_bind(struct socket *sock, struct sockaddr *addr, int alen) } } - write_lock_bh(&l2cap_sk_list.lock); + if (la.l2_cid) + err = l2cap_add_scid(chan, la.l2_cid); + else + err = l2cap_add_psm(chan, &la.l2_bdaddr, la.l2_psm); - if (la.l2_psm && __l2cap_get_sock_by_addr(la.l2_psm, &la.l2_bdaddr)) { - err = -EADDRINUSE; - } else { - /* Save source address */ - bacpy(&bt_sk(sk)->src, &la.l2_bdaddr); - chan->psm = la.l2_psm; - chan->sport = la.l2_psm; - sk->sk_state = BT_BOUND; - - if (__le16_to_cpu(la.l2_psm) == 0x0001 || - __le16_to_cpu(la.l2_psm) == 0x0003) - chan->sec_level = BT_SECURITY_SDP; - } + if (err < 0) + goto done; - if (la.l2_cid) - chan->scid = la.l2_cid; + if (__le16_to_cpu(la.l2_psm) == 0x0001 || + __le16_to_cpu(la.l2_psm) == 0x0003) + chan->sec_level = BT_SECURITY_SDP; - write_unlock_bh(&l2cap_sk_list.lock); + bacpy(&bt_sk(sk)->src, &la.l2_bdaddr); + sk->sk_state = BT_BOUND; done: release_sock(sk); -- cgit v0.10.2 From 73b2ec18532f45e9028ce4c7bc8d7f8818eabd2a Mon Sep 17 00:00:00 2001 From: "Gustavo F. Padovan" Date: Mon, 18 Apr 2011 19:36:44 -0300 Subject: Bluetooth: Handle psm == 0 case inside l2cap_add_psm() When the user doesn't specify a psm we have the choose one for the channel. Now we do this inside l2cap_add_psm(). Signed-off-by: Gustavo F. Padovan diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h index f5f3c2c..fb3f90ea 100644 --- a/include/net/bluetooth/l2cap.h +++ b/include/net/bluetooth/l2cap.h @@ -458,7 +458,6 @@ void l2cap_do_send(struct l2cap_chan *chan, struct sk_buff *skb); void l2cap_streaming_send(struct l2cap_chan *chan); int l2cap_ertm_send(struct l2cap_chan *chan); -struct sock *__l2cap_get_sock_by_addr(__le16 psm, bdaddr_t *src); int l2cap_add_psm(struct l2cap_chan *chan, bdaddr_t *src, __le16 psm); int l2cap_add_scid(struct l2cap_chan *chan, __u16 scid); diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index 98ddd86..9e3f64f 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -135,7 +135,7 @@ static inline struct l2cap_chan *l2cap_get_chan_by_ident(struct l2cap_conn *conn return c; } -struct sock *__l2cap_get_sock_by_addr(__le16 psm, bdaddr_t *src) +static struct sock *__l2cap_get_sock_by_addr(__le16 psm, bdaddr_t *src) { struct sock *sk; struct hlist_node *node; @@ -153,19 +153,35 @@ found: int l2cap_add_psm(struct l2cap_chan *chan, bdaddr_t *src, __le16 psm) { + int err; + write_lock_bh(&l2cap_sk_list.lock); - if (__l2cap_get_sock_by_addr(psm, src)) { - write_unlock_bh(&l2cap_sk_list.lock); - return -EADDRINUSE; + if (psm && __l2cap_get_sock_by_addr(psm, src)) { + err = -EADDRINUSE; + goto done; } - chan->psm = psm; - chan->sport = psm; + if (psm) { + chan->psm = psm; + chan->sport = psm; + err = 0; + } else { + u16 p; - write_unlock_bh(&l2cap_sk_list.lock); + err = -EINVAL; + for (p = 0x1001; p < 0x1100; p += 2) + if (!__l2cap_get_sock_by_addr(cpu_to_le16(p), src)) { + chan->psm = cpu_to_le16(p); + chan->sport = cpu_to_le16(p); + err = 0; + break; + } + } - return 0; +done: + write_unlock_bh(&l2cap_sk_list.lock); + return err; } int l2cap_add_scid(struct l2cap_chan *chan, __u16 scid) diff --git a/net/bluetooth/l2cap_sock.c b/net/bluetooth/l2cap_sock.c index 2156dce..aca99cd 100644 --- a/net/bluetooth/l2cap_sock.c +++ b/net/bluetooth/l2cap_sock.c @@ -256,28 +256,6 @@ static int l2cap_sock_listen(struct socket *sock, int backlog) goto done; } - if (!chan->psm && !chan->scid) { - bdaddr_t *src = &bt_sk(sk)->src; - u16 psm; - - err = -EINVAL; - - write_lock_bh(&l2cap_sk_list.lock); - - for (psm = 0x1001; psm < 0x1100; psm += 2) - if (!__l2cap_get_sock_by_addr(cpu_to_le16(psm), src)) { - chan->psm = cpu_to_le16(psm); - chan->sport = cpu_to_le16(psm); - err = 0; - break; - } - - write_unlock_bh(&l2cap_sk_list.lock); - - if (err < 0) - goto done; - } - sk->sk_max_ack_backlog = backlog; sk->sk_ack_backlog = 0; sk->sk_state = BT_LISTEN; -- cgit v0.10.2 From 23691d75cdc69c3b285211b4d77746aa20a17d18 Mon Sep 17 00:00:00 2001 From: "Gustavo F. Padovan" Date: Wed, 27 Apr 2011 18:26:32 -0300 Subject: Bluetooth: Remove l2cap_sk_list A new list was added to replace the socket based one. This new list doesn't depent on sock and then fits better inside l2cap_core.c code. It also rename l2cap_chan_alloc() to l2cap_chan_create() and l2cap_chan_free() to l2cap_chan_destroy) Signed-off-by: Gustavo F. Padovan diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h index fb3f90ea..d09c9b1 100644 --- a/include/net/bluetooth/l2cap.h +++ b/include/net/bluetooth/l2cap.h @@ -350,6 +350,7 @@ struct l2cap_chan { struct list_head srej_l; struct list_head list; + struct list_head global_l; }; struct l2cap_conn { @@ -441,7 +442,6 @@ static inline int l2cap_tx_window_full(struct l2cap_chan *ch) #define __is_sar_start(ctrl) (((ctrl) & L2CAP_CTRL_SAR) == L2CAP_SDU_START) extern int disable_ertm; -extern struct bt_sock_list l2cap_sk_list; int l2cap_init_sockets(void); void l2cap_cleanup_sockets(void); @@ -469,9 +469,9 @@ void l2cap_sock_init(struct sock *sk, struct sock *parent); struct sock *l2cap_sock_alloc(struct net *net, struct socket *sock, int proto, gfp_t prio); void l2cap_send_disconn_req(struct l2cap_conn *conn, struct l2cap_chan *chan, int err); -struct l2cap_chan *l2cap_chan_alloc(struct sock *sk); +struct l2cap_chan *l2cap_chan_create(struct sock *sk); void l2cap_chan_del(struct l2cap_chan *chan, int err); -void l2cap_chan_free(struct l2cap_chan *chan); +void l2cap_chan_destroy(struct l2cap_chan *chan); int l2cap_chan_connect(struct l2cap_chan *chan); #endif /* __L2CAP_H */ diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index 9e3f64f..d0769a8 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -62,9 +62,8 @@ static u8 l2cap_fixed_chan[8] = { 0x02, }; static struct workqueue_struct *_busy_wq; -struct bt_sock_list l2cap_sk_list = { - .lock = __RW_LOCK_UNLOCKED(l2cap_sk_list.lock) -}; +LIST_HEAD(chan_list); +DEFINE_RWLOCK(chan_list_lock); static void l2cap_busy_work(struct work_struct *work); @@ -135,29 +134,27 @@ static inline struct l2cap_chan *l2cap_get_chan_by_ident(struct l2cap_conn *conn return c; } -static struct sock *__l2cap_get_sock_by_addr(__le16 psm, bdaddr_t *src) +static struct l2cap_chan *__l2cap_global_chan_by_addr(__le16 psm, bdaddr_t *src) { - struct sock *sk; - struct hlist_node *node; - sk_for_each(sk, node, &l2cap_sk_list.head) { - struct l2cap_chan *chan = l2cap_pi(sk)->chan; + struct l2cap_chan *c; - if (chan->sport == psm && !bacmp(&bt_sk(sk)->src, src)) + list_for_each_entry(c, &chan_list, global_l) { + if (c->sport == psm && !bacmp(&bt_sk(c->sk)->src, src)) goto found; } - sk = NULL; + c = NULL; found: - return sk; + return c; } int l2cap_add_psm(struct l2cap_chan *chan, bdaddr_t *src, __le16 psm) { int err; - write_lock_bh(&l2cap_sk_list.lock); + write_lock_bh(&chan_list_lock); - if (psm && __l2cap_get_sock_by_addr(psm, src)) { + if (psm && __l2cap_global_chan_by_addr(psm, src)) { err = -EADDRINUSE; goto done; } @@ -171,7 +168,7 @@ int l2cap_add_psm(struct l2cap_chan *chan, bdaddr_t *src, __le16 psm) err = -EINVAL; for (p = 0x1001; p < 0x1100; p += 2) - if (!__l2cap_get_sock_by_addr(cpu_to_le16(p), src)) { + if (!__l2cap_global_chan_by_addr(cpu_to_le16(p), src)) { chan->psm = cpu_to_le16(p); chan->sport = cpu_to_le16(p); err = 0; @@ -180,17 +177,17 @@ int l2cap_add_psm(struct l2cap_chan *chan, bdaddr_t *src, __le16 psm) } done: - write_unlock_bh(&l2cap_sk_list.lock); + write_unlock_bh(&chan_list_lock); return err; } int l2cap_add_scid(struct l2cap_chan *chan, __u16 scid) { - write_lock_bh(&l2cap_sk_list.lock); + write_lock_bh(&chan_list_lock); chan->scid = scid; - write_unlock_bh(&l2cap_sk_list.lock); + write_unlock_bh(&chan_list_lock); return 0; } @@ -207,7 +204,7 @@ static u16 l2cap_alloc_cid(struct l2cap_conn *conn) return 0; } -struct l2cap_chan *l2cap_chan_alloc(struct sock *sk) +struct l2cap_chan *l2cap_chan_create(struct sock *sk) { struct l2cap_chan *chan; @@ -217,11 +214,19 @@ struct l2cap_chan *l2cap_chan_alloc(struct sock *sk) chan->sk = sk; + write_lock_bh(&chan_list_lock); + list_add(&chan->global_l, &chan_list); + write_unlock_bh(&chan_list_lock); + return chan; } -void l2cap_chan_free(struct l2cap_chan *chan) +void l2cap_chan_destroy(struct l2cap_chan *chan) { + write_lock_bh(&chan_list_lock); + list_del(&chan->global_l); + write_unlock_bh(&chan_list_lock); + kfree(chan); } @@ -651,48 +656,51 @@ static void l2cap_conn_start(struct l2cap_conn *conn) /* Find socket with cid and source bdaddr. * Returns closest match, locked. */ -static struct sock *l2cap_get_sock_by_scid(int state, __le16 cid, bdaddr_t *src) +static struct l2cap_chan *l2cap_global_chan_by_scid(int state, __le16 cid, bdaddr_t *src) { - struct sock *sk = NULL, *sk1 = NULL; - struct hlist_node *node; + struct l2cap_chan *c, *c1 = NULL; - read_lock(&l2cap_sk_list.lock); + read_lock(&chan_list_lock); - sk_for_each(sk, node, &l2cap_sk_list.head) { - struct l2cap_chan *chan = l2cap_pi(sk)->chan; + list_for_each_entry(c, &chan_list, global_l) { + struct sock *sk = c->sk; if (state && sk->sk_state != state) continue; - if (chan->scid == cid) { + if (c->scid == cid) { /* Exact match. */ - if (!bacmp(&bt_sk(sk)->src, src)) - break; + if (!bacmp(&bt_sk(sk)->src, src)) { + read_unlock(&chan_list_lock); + return c; + } /* Closest match */ if (!bacmp(&bt_sk(sk)->src, BDADDR_ANY)) - sk1 = sk; + c1 = c; } } - read_unlock(&l2cap_sk_list.lock); + read_unlock(&chan_list_lock); - return node ? sk : sk1; + return c1; } static void l2cap_le_conn_ready(struct l2cap_conn *conn) { struct sock *parent, *sk; - struct l2cap_chan *chan; + struct l2cap_chan *chan, *pchan; BT_DBG(""); /* Check if we have socket listening on cid */ - parent = l2cap_get_sock_by_scid(BT_LISTEN, L2CAP_CID_LE_DATA, + pchan = l2cap_global_chan_by_scid(BT_LISTEN, L2CAP_CID_LE_DATA, conn->src); - if (!parent) + if (!pchan) return; + parent = pchan->sk; + bh_lock_sock(parent); /* Check for backlog size */ @@ -705,7 +713,7 @@ static void l2cap_le_conn_ready(struct l2cap_conn *conn) if (!sk) goto clean; - chan = l2cap_chan_alloc(sk); + chan = l2cap_chan_create(sk); if (!chan) { l2cap_sock_kill(sk); goto clean; @@ -883,33 +891,34 @@ static inline void l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *ch /* Find socket with psm and source bdaddr. * Returns closest match. */ -static struct sock *l2cap_get_sock_by_psm(int state, __le16 psm, bdaddr_t *src) +static struct l2cap_chan *l2cap_global_chan_by_psm(int state, __le16 psm, bdaddr_t *src) { - struct sock *sk = NULL, *sk1 = NULL; - struct hlist_node *node; + struct l2cap_chan *c, *c1 = NULL; - read_lock(&l2cap_sk_list.lock); + read_lock(&chan_list_lock); - sk_for_each(sk, node, &l2cap_sk_list.head) { - struct l2cap_chan *chan = l2cap_pi(sk)->chan; + list_for_each_entry(c, &chan_list, global_l) { + struct sock *sk = c->sk; if (state && sk->sk_state != state) continue; - if (chan->psm == psm) { + if (c->psm == psm) { /* Exact match. */ - if (!bacmp(&bt_sk(sk)->src, src)) - break; + if (!bacmp(&bt_sk(sk)->src, src)) { + read_unlock_bh(&chan_list_lock); + return c; + } /* Closest match */ if (!bacmp(&bt_sk(sk)->src, BDADDR_ANY)) - sk1 = sk; + c1 = c; } } - read_unlock(&l2cap_sk_list.lock); + read_unlock(&chan_list_lock); - return node ? sk : sk1; + return c1; } int l2cap_chan_connect(struct l2cap_chan *chan) @@ -2079,22 +2088,26 @@ static inline int l2cap_connect_req(struct l2cap_conn *conn, struct l2cap_cmd_hd { struct l2cap_conn_req *req = (struct l2cap_conn_req *) data; struct l2cap_conn_rsp rsp; - struct l2cap_chan *chan = NULL; + struct l2cap_chan *chan = NULL, *pchan; struct sock *parent, *sk = NULL; int result, status = L2CAP_CS_NO_INFO; u16 dcid = 0, scid = __le16_to_cpu(req->scid); __le16 psm = req->psm; - BT_DBG("psm 0x%2.2x scid 0x%4.4x", psm, scid); + BT_ERR("psm 0x%2.2x scid 0x%4.4x", psm, scid); /* Check if we have socket listening on psm */ - parent = l2cap_get_sock_by_psm(BT_LISTEN, psm, conn->src); - if (!parent) { + pchan = l2cap_global_chan_by_psm(BT_LISTEN, psm, conn->src); + if (!pchan) { result = L2CAP_CR_BAD_PSM; goto sendresp; } + BT_ERR("%p 0x%2.2x", pchan, pchan->psm); + + parent = pchan->sk; + bh_lock_sock(parent); /* Check if the ACL is secure enough (if not SDP) */ @@ -2117,7 +2130,7 @@ static inline int l2cap_connect_req(struct l2cap_conn *conn, struct l2cap_cmd_hd if (!sk) goto response; - chan = l2cap_chan_alloc(sk); + chan = l2cap_chan_create(sk); if (!chan) { l2cap_sock_kill(sk); goto response; @@ -3745,11 +3758,14 @@ done: static inline int l2cap_conless_channel(struct l2cap_conn *conn, __le16 psm, struct sk_buff *skb) { struct sock *sk; + struct l2cap_chan *chan; - sk = l2cap_get_sock_by_psm(0, psm, conn->src); - if (!sk) + chan = l2cap_global_chan_by_psm(0, psm, conn->src); + if (!chan) goto drop; + sk = chan->sk; + bh_lock_sock(sk); BT_DBG("sk %p, len %d", sk, skb->len); @@ -3775,11 +3791,14 @@ done: static inline int l2cap_att_channel(struct l2cap_conn *conn, __le16 cid, struct sk_buff *skb) { struct sock *sk; + struct l2cap_chan *chan; - sk = l2cap_get_sock_by_scid(0, cid, conn->src); - if (!sk) + chan = l2cap_global_chan_by_scid(0, cid, conn->src); + if (!chan) goto drop; + sk = chan->sk; + bh_lock_sock(sk); BT_DBG("sk %p, len %d", sk, skb->len); @@ -3846,8 +3865,7 @@ static void l2cap_recv_frame(struct l2cap_conn *conn, struct sk_buff *skb) static int l2cap_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type) { int exact = 0, lm1 = 0, lm2 = 0; - register struct sock *sk; - struct hlist_node *node; + struct l2cap_chan *c; if (type != ACL_LINK) return -EINVAL; @@ -3855,25 +3873,25 @@ static int l2cap_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type) BT_DBG("hdev %s, bdaddr %s", hdev->name, batostr(bdaddr)); /* Find listening sockets and check their link_mode */ - read_lock(&l2cap_sk_list.lock); - sk_for_each(sk, node, &l2cap_sk_list.head) { - struct l2cap_chan *chan = l2cap_pi(sk)->chan; + read_lock(&chan_list_lock); + list_for_each_entry(c, &chan_list, global_l) { + struct sock *sk = c->sk; if (sk->sk_state != BT_LISTEN) continue; if (!bacmp(&bt_sk(sk)->src, &hdev->bdaddr)) { lm1 |= HCI_LM_ACCEPT; - if (chan->role_switch) + if (c->role_switch) lm1 |= HCI_LM_MASTER; exact++; } else if (!bacmp(&bt_sk(sk)->src, BDADDR_ANY)) { lm2 |= HCI_LM_ACCEPT; - if (chan->role_switch) + if (c->role_switch) lm2 |= HCI_LM_MASTER; } } - read_unlock(&l2cap_sk_list.lock); + read_unlock(&chan_list_lock); return exact ? lm1 : lm2; } @@ -4126,25 +4144,22 @@ drop: static int l2cap_debugfs_show(struct seq_file *f, void *p) { - struct sock *sk; - struct hlist_node *node; + struct l2cap_chan *c; - read_lock_bh(&l2cap_sk_list.lock); + read_lock_bh(&chan_list_lock); - sk_for_each(sk, node, &l2cap_sk_list.head) { - struct l2cap_pinfo *pi = l2cap_pi(sk); - struct l2cap_chan *chan = pi->chan; + list_for_each_entry(c, &chan_list, global_l) { + struct sock *sk = c->sk; seq_printf(f, "%s %s %d %d 0x%4.4x 0x%4.4x %d %d %d %d\n", batostr(&bt_sk(sk)->src), batostr(&bt_sk(sk)->dst), - sk->sk_state, __le16_to_cpu(chan->psm), - chan->scid, chan->dcid, - chan->imtu, chan->omtu, chan->sec_level, - chan->mode); + sk->sk_state, __le16_to_cpu(c->psm), + c->scid, c->dcid, c->imtu, c->omtu, + c->sec_level, c->mode); } - read_unlock_bh(&l2cap_sk_list.lock); + read_unlock_bh(&chan_list_lock); return 0; } diff --git a/net/bluetooth/l2cap_sock.c b/net/bluetooth/l2cap_sock.c index aca99cd..c98360d 100644 --- a/net/bluetooth/l2cap_sock.c +++ b/net/bluetooth/l2cap_sock.c @@ -808,8 +808,7 @@ void l2cap_sock_kill(struct sock *sk) /* Kill poor orphan */ - l2cap_chan_free(l2cap_pi(sk)->chan); - bt_sock_unlink(&l2cap_sk_list, sk); + l2cap_chan_destroy(l2cap_pi(sk)->chan); sock_set_flag(sk, SOCK_DEAD); sock_put(sk); } @@ -1025,7 +1024,6 @@ struct sock *l2cap_sock_alloc(struct net *net, struct socket *sock, int proto, g setup_timer(&sk->sk_timer, l2cap_sock_timeout, (unsigned long) sk); - bt_sock_link(&l2cap_sk_list, sk); return sk; } @@ -1052,7 +1050,7 @@ static int l2cap_sock_create(struct net *net, struct socket *sock, int protocol, if (!sk) return -ENOMEM; - chan = l2cap_chan_alloc(sk); + chan = l2cap_chan_create(sk); if (!chan) { l2cap_sock_kill(sk); return -ENOMEM; -- cgit v0.10.2 From 75bd0cbdc21d80859c80bdd5dd00125c1a3ccbca Mon Sep 17 00:00:00 2001 From: Ming Lei Date: Thu, 28 Apr 2011 22:37:09 +0000 Subject: usbnet: runtime pm: fix out of memory This patch makes use of the EVENT_DEV_OPEN flag introduced recently to fix one out of memory issue, which can be reproduced on omap3/4 based pandaboard/beagle XM easily with steps below: - enable runtime pm echo auto > /sys/devices/platform/usbhs-omap.0/ehci-omap.0/usb1/1-1/1-1.1/power/control - ifconfig eth0 up - then out of memroy happened, see [1] for kernel message. Follows my analysis: - 'ifconfig eth0 up' brings eth0 out of suspend, and usbnet_resume is called to schedule dev->bh, then rx urbs are submited to prepare for recieving data; - some usbnet devices will produce garbage rx packets flood if info->reset is not called in usbnet_open. - so there is no enough chances for usbnet_bh to handle and release recieved skb buffers since many rx interrupts consumes cpu, so out of memory for atomic allocation in rx_submit happened. This patch fixes the issue by simply not allowing schedule of usbnet_bh until device is opened. [1], dmesg [ 234.712005] smsc95xx 1-1.1:1.0: rpm_resume flags 0x4 [ 234.712066] usb 1-1.1: rpm_resume flags 0x0 [ 234.712066] usb 1-1: rpm_resume flags 0x0 [ 234.712097] usb usb1: rpm_resume flags 0x0 [ 234.712127] usb usb1: usb auto-resume [ 234.712158] ehci-omap ehci-omap.0: resume root hub [ 234.754028] hub 1-0:1.0: hub_resume [ 234.754821] hub 1-0:1.0: port 1: status 0507 change 0000 [ 234.756011] hub 1-0:1.0: state 7 ports 3 chg 0000 evt 0000 [ 234.756042] hub 1-0:1.0: rpm_resume flags 0x4 [ 234.756072] usb usb1: rpm_resume flags 0x0 [ 234.756164] usb usb1: rpm_resume returns 1 [ 234.756195] hub 1-0:1.0: rpm_resume returns 0 [ 234.756195] hub 1-0:1.0: rpm_suspend flags 0x4 [ 234.756225] hub 1-0:1.0: rpm_suspend returns 0 [ 234.756256] usb usb1: rpm_resume returns 0 [ 234.757141] usb 1-1: usb auto-resume [ 234.793151] ehci-omap ehci-omap.0: GetStatus port:1 status 001005 0 ACK POWER sig=se0 PE CONNECT [ 234.816558] usb 1-1: finish resume [ 234.817871] hub 1-1:1.0: hub_resume [ 234.818420] hub 1-1:1.0: port 1: status 0507 change 0000 [ 234.820495] ehci-omap ehci-omap.0: reused qh eec50220 schedule [ 234.820495] usb 1-1: link qh256-0001/eec50220 start 1 [1/0 us] [ 234.820587] usb 1-1: rpm_resume returns 0 [ 234.820800] hub 1-1:1.0: state 7 ports 5 chg 0000 evt 0000 [ 234.820800] hub 1-1:1.0: rpm_resume flags 0x4 [ 234.820831] hub 1-1:1.0: rpm_resume returns 0 [ 234.820861] hub 1-1:1.0: rpm_suspend flags 0x4 [ 234.820861] hub 1-1:1.0: rpm_suspend returns 0 [ 234.821777] usb 1-1.1: usb auto-resume [ 234.868591] hub 1-1:1.0: state 7 ports 5 chg 0000 evt 0002 [ 234.868591] hub 1-1:1.0: rpm_resume flags 0x4 [ 234.868621] hub 1-1:1.0: rpm_resume returns 0 [ 234.868652] hub 1-1:1.0: rpm_suspend flags 0x4 [ 234.868652] hub 1-1:1.0: rpm_suspend returns 0 [ 234.879486] usb 1-1.1: finish resume [ 234.880279] usb 1-1.1: rpm_resume returns 0 [ 234.880310] smsc95xx 1-1.1:1.0: rpm_resume returns 0 [ 238.880187] ksoftirqd/0: page allocation failure. order:0, mode:0x20 [ 238.880218] Backtrace: [ 238.880249] [] (dump_backtrace+0x0/0xf8) from [] (dump_stack+0x18/0x1c) [ 238.880249] r6:00000000 r5:00000000 r4:00000020 r3:00000002 [ 238.880310] [] (dump_stack+0x0/0x1c) from [] (__alloc_pages_nodemask+0x620/0x724) [ 238.880340] [] (__alloc_pages_nodemask+0x0/0x724) from [] (kmem_getpages.clone.34+0x34/0xc8) [ 238.880371] [] (kmem_getpages.clone.34+0x0/0xc8) from [] (cache_grow.clone.42+0x84/0x154) [ 238.880371] r6:ef871aa4 r5:ef871a80 r4:ef81fd40 r3:00000020 [ 238.880401] [] (cache_grow.clone.42+0x0/0x154) from [] (cache_alloc_refill+0x19c/0x1f0) [ 238.880432] [] (cache_alloc_refill+0x0/0x1f0) from [] (kmem_cache_alloc+0x90/0x190) [ 238.880462] [] (kmem_cache_alloc+0x0/0x190) from [] (__alloc_skb+0x34/0xe8) [ 238.880493] [] (__alloc_skb+0x0/0xe8) from [] (rx_submit+0x2c/0x1d4 [usbnet]) [ 238.880523] [] (rx_submit+0x0/0x1d4 [usbnet]) from [] (rx_complete+0x19c/0x1b0 [usbnet]) [ 238.880737] [] (rx_complete+0x0/0x1b0 [usbnet]) from [] (usb_hcd_giveback_urb+0xa8/0xf4 [usbcore]) [ 238.880737] r8:eeeced34 r7:eeecec00 r6:eeecec00 r5:00000000 r4:eec2dd20 [ 238.880767] r3:bf050b9c [ 238.880859] [] (usb_hcd_giveback_urb+0x0/0xf4 [usbcore]) from [] (ehci_urb_done+0xb0/0xbc [ehci_hcd]) [ 238.880859] r6:00000000 r5:eec2dd20 r4:eeeced44 r3:eec2dd34 [ 238.880920] [] (ehci_urb_done+0x0/0xbc [ehci_hcd]) from [] (qh_completions+0x308/0x3bc [ehci_hcd]) [ 238.880920] r7:00000000 r6:eeda21a0 r5:ffdfe3c0 r4:eeda21ac [ 238.880981] [] (qh_completions+0x0/0x3bc [ehci_hcd]) from [] (scan_async+0xb0/0x16c [ehci_hcd]) [ 238.881011] [] (scan_async+0x0/0x16c [ehci_hcd]) from [] (ehci_work+0x38/0x90 [ehci_hcd]) [ 238.881042] [] (ehci_work+0x0/0x90 [ehci_hcd]) from [] (ehci_irq+0x300/0x34c [ehci_hcd]) [ 238.881072] r4:eeeced34 r3:00000001 [ 238.881134] [] (ehci_irq+0x0/0x34c [ehci_hcd]) from [] (usb_hcd_irq+0x40/0xac [usbcore]) [ 238.881195] [] (usb_hcd_irq+0x0/0xac [usbcore]) from [] (handle_irq_event_percpu+0xb8/0x240) [ 238.881225] r6:eec504e0 r5:0000006d r4:eec504e0 r3:bf0067e8 [ 238.881256] [] (handle_irq_event_percpu+0x0/0x240) from [] (handle_irq_event+0x44/0x64) [ 238.881256] [] (handle_irq_event+0x0/0x64) from [] (handle_level_irq+0xe0/0x114) [ 238.881286] r6:0000006d r5:c080c14c r4:c080c100 r3:00020000 [ 238.881317] [] (handle_level_irq+0x0/0x114) from [] (asm_do_IRQ+0x90/0xd0) [ 238.881317] r5:00000000 r4:0000006d [ 238.881347] [] (asm_do_IRQ+0x0/0xd0) from [] (__irq_svc+0x50/0x134) [ 238.881378] Exception stack(0xef837e20 to 0xef837e68) [ 238.881378] 7e20: 00000001 00185610 016cc000 c00490c0 eb380000 ef800540 00000020 00004ae0 [ 238.881408] 7e40: 00000020 bf0509f4 60000013 ef837e9c ef837e40 ef837e68 c0226f0c c0298ca0 [ 238.881408] 7e60: 20000013 ffffffff [ 238.881408] r5:fa240100 r4:ffffffff [ 238.881439] [] (__kmalloc_track_caller+0x0/0x1d0) from [] (__alloc_skb+0x58/0xe8) [ 238.881469] [] (__alloc_skb+0x0/0xe8) from [] (rx_submit+0x2c/0x1d4 [usbnet]) [ 238.881500] [] (rx_submit+0x0/0x1d4 [usbnet]) from [] (usbnet_bh+0x1b4/0x250 [usbnet]) [ 238.881530] [] (usbnet_bh+0x0/0x250 [usbnet]) from [] (tasklet_action+0xb0/0x1f8) [ 238.881530] r6:00000000 r5:ef9757f0 r4:ef9757ec r3:bf051224 [ 238.881561] [] (tasklet_action+0x0/0x1f8) from [] (__do_softirq+0x140/0x290) [ 238.881561] r8:00000006 r7:00000101 r6:00000000 r5:c0806098 r4:00000001 [ 238.881591] r3:c01f907c [ 238.881622] [] (__do_softirq+0x0/0x290) from [] (run_ksoftirqd+0xd0/0x1f4) [ 238.881622] [] (run_ksoftirqd+0x0/0x1f4) from [] (kthread+0x90/0x98) [ 238.881652] r7:00000013 r6:c01f98fc r5:00000000 r4:ef831efc [ 238.881683] [] (kthread+0x0/0x98) from [] (do_exit+0x0/0x374) [ 238.881713] r6:c01f62f4 r5:c0211320 r4:ef831efc [ 238.881713] Mem-info: [ 238.881744] Normal per-cpu: [ 238.881744] CPU 0: hi: 186, btch: 31 usd: 38 [ 238.881744] CPU 1: hi: 186, btch: 31 usd: 169 [ 238.881774] HighMem per-cpu: [ 238.881774] CPU 0: hi: 90, btch: 15 usd: 66 [ 238.881774] CPU 1: hi: 90, btch: 15 usd: 86 [ 238.881805] active_anon:544 inactive_anon:71 isolated_anon:0 [ 238.881805] active_file:926 inactive_file:2538 isolated_file:0 [ 238.881805] unevictable:0 dirty:10 writeback:0 unstable:0 [ 238.881805] free:57782 slab_reclaimable:864 slab_unreclaimable:186898 [ 238.881805] mapped:632 shmem:144 pagetables:50 bounce:0 [ 238.881835] Normal free:1328kB min:3532kB low:4412kB high:5296kB active_anon:0kB inactive_anon:0kB active_file:880kB inactive_file:848kB unevictable:0kB isolated(anon):0kB isolated(file):0kB present:780288kB mlocked:0kB dirty:36kB writeback:0kB mapped:0kB shmem:0kB slab_reclaimable:3456kB slab_unreclaimable:747592kB kernel_stack:392kB pagetables:200kB unstable:0kB bounce:0kB writeback_tmp:0kB pages_scanned:0 all_unreclaimable? no [ 238.881866] lowmem_reserve[]: 0 1904 1904 [ 238.881896] HighMem free:229800kB min:236kB low:508kB high:784kB active_anon:2176kB inactive_anon:284kB active_file:2824kB inactive_file:9304kB unevictable:0kB isolated(anon):0kB isolated(file):0kB present:243712kB mlocked:0kB dirty:4kB writeback:0kB mapped:2528kB shmem:576kB slab_reclaimable:0kB slab_unreclaimable:0kB kernel_stack:0kB pagetables:0kB unstable:0kB bounce:0kB writeback_tmp:0kB pages_scanned:0 all_unreclaimable? no [ 238.881927] lowmem_reserve[]: 0 0 0 [ 238.881958] Normal: 0*4kB 4*8kB 6*16kB 0*32kB 1*64kB 1*128kB 0*256kB 2*512kB 0*1024kB 0*2048kB 0*4096kB = 1344kB [ 238.882019] HighMem: 6*4kB 2*8kB 4*16kB 4*32kB 1*64kB 1*128kB 0*256kB 2*512kB 3*1024kB 0*2048kB 55*4096kB = 229800kB [ 238.882080] 3610 total pagecache pages [ 238.882080] 0 pages in swap cache [ 238.882080] Swap cache stats: add 0, delete 0, find 0/0 [ 238.882110] Free swap = 0kB [ 238.882110] Total swap = 0kB [ 238.933776] 262144 pages of RAM [ 238.933776] 58240 free pages [ 238.933776] 10503 reserved pages [ 238.933776] 187773 slab pages [ 238.933807] 2475 pages shared [ 238.933807] 0 pages swap cached Signed-off-by: Ming Lei Acked-by: Oliver Neukum Signed-off-by: David S. Miller diff --git a/drivers/net/usb/usbnet.c b/drivers/net/usb/usbnet.c index 009bba3..9ab439d 100644 --- a/drivers/net/usb/usbnet.c +++ b/drivers/net/usb/usbnet.c @@ -645,6 +645,7 @@ int usbnet_stop (struct net_device *net) struct driver_info *info = dev->driver_info; int retval; + clear_bit(EVENT_DEV_OPEN, &dev->flags); netif_stop_queue (net); netif_info(dev, ifdown, dev->net, @@ -1524,9 +1525,12 @@ int usbnet_resume (struct usb_interface *intf) smp_mb(); clear_bit(EVENT_DEV_ASLEEP, &dev->flags); spin_unlock_irq(&dev->txq.lock); - if (!(dev->txq.qlen >= TX_QLEN(dev))) - netif_start_queue(dev->net); - tasklet_schedule (&dev->bh); + + if (test_bit(EVENT_DEV_OPEN, &dev->flags)) { + if (!(dev->txq.qlen >= TX_QLEN(dev))) + netif_start_queue(dev->net); + tasklet_schedule (&dev->bh); + } } return 0; } -- cgit v0.10.2 From 34da9e50e908c4553ddefb38da2c5bacbe2bba58 Mon Sep 17 00:00:00 2001 From: Giuseppe CAVALLARO Date: Thu, 5 May 2011 00:10:50 +0000 Subject: stmmac: removed not used definitions Reported-by: Karim Hamiti Signed-off-by: Giuseppe Cavallaro Signed-off-by: David S. Miller diff --git a/drivers/net/stmmac/stmmac_main.c b/drivers/net/stmmac/stmmac_main.c index ba9daec..e15c4a0 100644 --- a/drivers/net/stmmac/stmmac_main.c +++ b/drivers/net/stmmac/stmmac_main.c @@ -116,9 +116,6 @@ static int tc = TC_DEFAULT; module_param(tc, int, S_IRUGO | S_IWUSR); MODULE_PARM_DESC(tc, "DMA threshold control value"); -#define RX_NO_COALESCE 1 /* Always interrupt on completion */ -#define TX_NO_COALESCE -1 /* No moderation by default */ - /* Pay attention to tune this parameter; take care of both * hardware capability and network stabitily/performance impact. * Many tests showed that ~4ms latency seems to be good enough. */ -- cgit v0.10.2 From 2ae17f666099c952053eea7c64cac8189dd76f72 Mon Sep 17 00:00:00 2001 From: Vladislav Zolotarov Date: Wed, 4 May 2011 23:48:23 +0000 Subject: bnx2x: link report improvements To avoid link notification duplication Signed-off-by: Dmitry Kravkov Signed-off-by: Vladislav Zolotarov Signed-off-by: Eilon Greenstein Signed-off-by: David S. Miller diff --git a/drivers/net/bnx2x/bnx2x.h b/drivers/net/bnx2x/bnx2x.h index 9e87417..1a005a4 100644 --- a/drivers/net/bnx2x/bnx2x.h +++ b/drivers/net/bnx2x/bnx2x.h @@ -893,6 +893,22 @@ typedef enum { (&bp->def_status_blk->sp_sb.\ index_values[HC_SP_INDEX_EQ_CONS]) +/* This is a data that will be used to create a link report message. + * We will keep the data used for the last link report in order + * to prevent reporting the same link parameters twice. + */ +struct bnx2x_link_report_data { + u16 line_speed; /* Effective line speed */ + unsigned long link_report_flags;/* BNX2X_LINK_REPORT_XXX flags */ +}; + +enum { + BNX2X_LINK_REPORT_FD, /* Full DUPLEX */ + BNX2X_LINK_REPORT_LINK_DOWN, + BNX2X_LINK_REPORT_RX_FC_ON, + BNX2X_LINK_REPORT_TX_FC_ON, +}; + struct bnx2x { /* Fields used in the tx and intr/napi performance paths * are grouped together in the beginning of the structure @@ -1025,6 +1041,9 @@ struct bnx2x { struct link_params link_params; struct link_vars link_vars; + u32 link_cnt; + struct bnx2x_link_report_data last_reported_link; + struct mdio_if_info mdio; struct bnx2x_common common; @@ -1441,6 +1460,8 @@ struct bnx2x_func_init_params { #define WAIT_RAMROD_POLL 0x01 #define WAIT_RAMROD_COMMON 0x02 +void bnx2x_read_mf_cfg(struct bnx2x *bp); + /* dmae */ void bnx2x_read_dmae(struct bnx2x *bp, u32 src_addr, u32 len32); void bnx2x_write_dmae(struct bnx2x *bp, dma_addr_t dma_addr, u32 dst_addr, diff --git a/drivers/net/bnx2x/bnx2x_cmn.c b/drivers/net/bnx2x/bnx2x_cmn.c index 8729061..8853ae2 100644 --- a/drivers/net/bnx2x/bnx2x_cmn.c +++ b/drivers/net/bnx2x/bnx2x_cmn.c @@ -758,35 +758,119 @@ u16 bnx2x_get_mf_speed(struct bnx2x *bp) return line_speed; } +/** + * bnx2x_fill_report_data - fill link report data to report + * + * @bp: driver handle + * @data: link state to update + * + * It uses a none-atomic bit operations because is called under the mutex. + */ +static inline void bnx2x_fill_report_data(struct bnx2x *bp, + struct bnx2x_link_report_data *data) +{ + u16 line_speed = bnx2x_get_mf_speed(bp); + + memset(data, 0, sizeof(*data)); + + /* Fill the report data: efective line speed */ + data->line_speed = line_speed; + + /* Link is down */ + if (!bp->link_vars.link_up || (bp->flags & MF_FUNC_DIS)) + __set_bit(BNX2X_LINK_REPORT_LINK_DOWN, + &data->link_report_flags); + + /* Full DUPLEX */ + if (bp->link_vars.duplex == DUPLEX_FULL) + __set_bit(BNX2X_LINK_REPORT_FD, &data->link_report_flags); + + /* Rx Flow Control is ON */ + if (bp->link_vars.flow_ctrl & BNX2X_FLOW_CTRL_RX) + __set_bit(BNX2X_LINK_REPORT_RX_FC_ON, &data->link_report_flags); + + /* Tx Flow Control is ON */ + if (bp->link_vars.flow_ctrl & BNX2X_FLOW_CTRL_TX) + __set_bit(BNX2X_LINK_REPORT_TX_FC_ON, &data->link_report_flags); +} + +/** + * bnx2x_link_report - report link status to OS. + * + * @bp: driver handle + * + * Calls the __bnx2x_link_report() under the same locking scheme + * as a link/PHY state managing code to ensure a consistent link + * reporting. + */ + void bnx2x_link_report(struct bnx2x *bp) { - if (bp->flags & MF_FUNC_DIS) { - netif_carrier_off(bp->dev); - netdev_err(bp->dev, "NIC Link is Down\n"); - return; - } + bnx2x_acquire_phy_lock(bp); + __bnx2x_link_report(bp); + bnx2x_release_phy_lock(bp); +} - if (bp->link_vars.link_up) { - u16 line_speed; +/** + * __bnx2x_link_report - report link status to OS. + * + * @bp: driver handle + * + * None atomic inmlementation. + * Should be called under the phy_lock. + */ +void __bnx2x_link_report(struct bnx2x *bp) +{ + struct bnx2x_link_report_data cur_data; - if (bp->state == BNX2X_STATE_OPEN) - netif_carrier_on(bp->dev); - netdev_info(bp->dev, "NIC Link is Up, "); + /* reread mf_cfg */ + if (!CHIP_IS_E1(bp)) + bnx2x_read_mf_cfg(bp); + + /* Read the current link report info */ + bnx2x_fill_report_data(bp, &cur_data); + + /* Don't report link down or exactly the same link status twice */ + if (!memcmp(&cur_data, &bp->last_reported_link, sizeof(cur_data)) || + (test_bit(BNX2X_LINK_REPORT_LINK_DOWN, + &bp->last_reported_link.link_report_flags) && + test_bit(BNX2X_LINK_REPORT_LINK_DOWN, + &cur_data.link_report_flags))) + return; + + bp->link_cnt++; - line_speed = bnx2x_get_mf_speed(bp); + /* We are going to report a new link parameters now - + * remember the current data for the next time. + */ + memcpy(&bp->last_reported_link, &cur_data, sizeof(cur_data)); - pr_cont("%d Mbps ", line_speed); + if (test_bit(BNX2X_LINK_REPORT_LINK_DOWN, + &cur_data.link_report_flags)) { + netif_carrier_off(bp->dev); + netdev_err(bp->dev, "NIC Link is Down\n"); + return; + } else { + netif_carrier_on(bp->dev); + netdev_info(bp->dev, "NIC Link is Up, "); + pr_cont("%d Mbps ", cur_data.line_speed); - if (bp->link_vars.duplex == DUPLEX_FULL) + if (test_and_clear_bit(BNX2X_LINK_REPORT_FD, + &cur_data.link_report_flags)) pr_cont("full duplex"); else pr_cont("half duplex"); - if (bp->link_vars.flow_ctrl != BNX2X_FLOW_CTRL_NONE) { - if (bp->link_vars.flow_ctrl & BNX2X_FLOW_CTRL_RX) { + /* Handle the FC at the end so that only these flags would be + * possibly set. This way we may easily check if there is no FC + * enabled. + */ + if (cur_data.link_report_flags) { + if (test_bit(BNX2X_LINK_REPORT_RX_FC_ON, + &cur_data.link_report_flags)) { pr_cont(", receive "); - if (bp->link_vars.flow_ctrl & - BNX2X_FLOW_CTRL_TX) + if (test_bit(BNX2X_LINK_REPORT_TX_FC_ON, + &cur_data.link_report_flags)) pr_cont("& transmit "); } else { pr_cont(", transmit "); @@ -794,10 +878,6 @@ void bnx2x_link_report(struct bnx2x *bp) pr_cont("flow control ON"); } pr_cont("\n"); - - } else { /* link_down */ - netif_carrier_off(bp->dev); - netdev_err(bp->dev, "NIC Link is Down\n"); } } @@ -1345,6 +1425,13 @@ int bnx2x_nic_load(struct bnx2x *bp, int load_mode) bp->state = BNX2X_STATE_OPENING_WAIT4_LOAD; + /* Set the initial link reported state to link down */ + bnx2x_acquire_phy_lock(bp); + memset(&bp->last_reported_link, 0, sizeof(bp->last_reported_link)); + __set_bit(BNX2X_LINK_REPORT_LINK_DOWN, + &bp->last_reported_link.link_report_flags); + bnx2x_release_phy_lock(bp); + /* must be called before memory allocation and HW init */ bnx2x_ilt_set_info(bp); diff --git a/drivers/net/bnx2x/bnx2x_cmn.h b/drivers/net/bnx2x/bnx2x_cmn.h index 1cdab69..007f294 100644 --- a/drivers/net/bnx2x/bnx2x_cmn.h +++ b/drivers/net/bnx2x/bnx2x_cmn.h @@ -67,11 +67,12 @@ void bnx2x__link_status_update(struct bnx2x *bp); * Report link status to upper layer * * @param bp - * - * @return int */ void bnx2x_link_report(struct bnx2x *bp); +/* None-atomic version of bnx2x_link_report() */ +void __bnx2x_link_report(struct bnx2x *bp); + /** * calculates MF speed according to current linespeed and MF * configuration diff --git a/drivers/net/bnx2x/bnx2x_main.c b/drivers/net/bnx2x/bnx2x_main.c index bfd7ac9..3f4ff41 100644 --- a/drivers/net/bnx2x/bnx2x_main.c +++ b/drivers/net/bnx2x/bnx2x_main.c @@ -2036,7 +2036,7 @@ static int bnx2x_get_cmng_fns_mode(struct bnx2x *bp) return CMNG_FNS_NONE; } -static void bnx2x_read_mf_cfg(struct bnx2x *bp) +void bnx2x_read_mf_cfg(struct bnx2x *bp) { int vn, n = (CHIP_MODE_IS_4_PORT(bp) ? 2 : 1); @@ -2123,7 +2123,6 @@ static inline void bnx2x_link_sync_notify(struct bnx2x *bp) /* This function is called upon link interrupt */ static void bnx2x_link_attn(struct bnx2x *bp) { - u32 prev_link_status = bp->link_vars.link_status; /* Make sure that we are synced with the current statistics */ bnx2x_stats_handle(bp, STATS_EVENT_STOP); @@ -2168,17 +2167,15 @@ static void bnx2x_link_attn(struct bnx2x *bp) "single function mode without fairness\n"); } + __bnx2x_link_report(bp); + if (IS_MF(bp)) bnx2x_link_sync_notify(bp); - - /* indicate link status only if link status actually changed */ - if (prev_link_status != bp->link_vars.link_status) - bnx2x_link_report(bp); } void bnx2x__link_status_update(struct bnx2x *bp) { - if ((bp->state != BNX2X_STATE_OPEN) || (bp->flags & MF_FUNC_DIS)) + if (bp->state != BNX2X_STATE_OPEN) return; bnx2x_link_status_update(&bp->link_params, &bp->link_vars); @@ -2188,10 +2185,6 @@ void bnx2x__link_status_update(struct bnx2x *bp) else bnx2x_stats_handle(bp, STATS_EVENT_STOP); - /* the link status update could be the result of a DCC event - hence re-read the shmem mf configuration */ - bnx2x_read_mf_cfg(bp); - /* indicate link status */ bnx2x_link_report(bp); } @@ -3120,10 +3113,14 @@ static inline void bnx2x_attn_int_deasserted3(struct bnx2x *bp, u32 attn) if (val & DRV_STATUS_SET_MF_BW) bnx2x_set_mf_bw(bp); - bnx2x__link_status_update(bp); if ((bp->port.pmf == 0) && (val & DRV_STATUS_PMF)) bnx2x_pmf_update(bp); + /* Always call it here: bnx2x_link_report() will + * prevent the link indication duplication. + */ + bnx2x__link_status_update(bp); + if (bp->port.pmf && (val & DRV_STATUS_DCBX_NEGOTIATION_RESULTS) && bp->dcbx_enabled > 0) -- cgit v0.10.2 From f9a3ebbe657b5dcd562224b32d1703da499063db Mon Sep 17 00:00:00 2001 From: Dmitry Kravkov Date: Wed, 4 May 2011 23:49:11 +0000 Subject: bnx2x: allow WoL on every function in MF modes Signed-off-by: Dmitry Kravkov Signed-off-by: Eilon Greenstein Signed-off-by: David S. Miller diff --git a/drivers/net/bnx2x/bnx2x_main.c b/drivers/net/bnx2x/bnx2x_main.c index 3f4ff41..1b3c9f6 100644 --- a/drivers/net/bnx2x/bnx2x_main.c +++ b/drivers/net/bnx2x/bnx2x_main.c @@ -8052,13 +8052,9 @@ static void __devinit bnx2x_get_common_hwinfo(struct bnx2x *bp) (val >= REQ_BC_VER_4_VRFY_SPECIFIC_PHY_OPT_MDL) ? FEATURE_CONFIG_BC_SUPPORTS_DUAL_PHY_OPT_MDL_VRFY : 0; - if (BP_E1HVN(bp) == 0) { - pci_read_config_word(bp->pdev, bp->pm_cap + PCI_PM_PMC, &pmc); - bp->flags |= (pmc & PCI_PM_CAP_PME_D3cold) ? 0 : NO_WOL_FLAG; - } else { - /* no WOL capability for E1HVN != 0 */ - bp->flags |= NO_WOL_FLAG; - } + pci_read_config_word(bp->pdev, bp->pm_cap + PCI_PM_PMC, &pmc); + bp->flags |= (pmc & PCI_PM_CAP_PME_D3cold) ? 0 : NO_WOL_FLAG; + BNX2X_DEV_INFO("%sWoL capable\n", (bp->flags & NO_WOL_FLAG) ? "not " : ""); -- cgit v0.10.2 From 426b92415074d6d268c7aac4561efecd3785d0b1 Mon Sep 17 00:00:00 2001 From: Dmitry Kravkov Date: Wed, 4 May 2011 23:49:53 +0000 Subject: bnx2x: Do storage mac address validation for SF mode. Signed-off-by: Dmitry Kravkov Signed-off-by: Eilon Greenstein Signed-off-by: David S. Miller diff --git a/drivers/net/bnx2x/bnx2x_main.c b/drivers/net/bnx2x/bnx2x_main.c index 1b3c9f6..660c945 100644 --- a/drivers/net/bnx2x/bnx2x_main.c +++ b/drivers/net/bnx2x/bnx2x_main.c @@ -8560,15 +8560,6 @@ static void __devinit bnx2x_get_mac_hwinfo(struct bnx2x *bp) BNX2X_DEV_INFO("Read iSCSI MAC: " "0x%x:0x%04x\n", val2, val); bnx2x_set_mac_buf(iscsi_mac, val, val2); - - /* Disable iSCSI OOO if MAC configuration is - * invalid. - */ - if (!is_valid_ether_addr(iscsi_mac)) { - bp->flags |= NO_ISCSI_OOO_FLAG | - NO_ISCSI_FLAG; - memset(iscsi_mac, 0, ETH_ALEN); - } } else bp->flags |= NO_ISCSI_OOO_FLAG | NO_ISCSI_FLAG; @@ -8581,13 +8572,6 @@ static void __devinit bnx2x_get_mac_hwinfo(struct bnx2x *bp) "0x%x:0x%04x\n", val2, val); bnx2x_set_mac_buf(fip_mac, val, val2); - /* Disable FCoE if MAC configuration is - * invalid. - */ - if (!is_valid_ether_addr(fip_mac)) { - bp->flags |= NO_FCOE_FLAG; - memset(bp->fip_mac, 0, ETH_ALEN); - } } else bp->flags |= NO_FCOE_FLAG; } @@ -8618,6 +8602,22 @@ static void __devinit bnx2x_get_mac_hwinfo(struct bnx2x *bp) else if (!IS_MF(bp)) memcpy(fip_mac, iscsi_mac, ETH_ALEN); } + + /* Disable iSCSI if MAC configuration is + * invalid. + */ + if (!is_valid_ether_addr(iscsi_mac)) { + bp->flags |= NO_ISCSI_FLAG; + memset(iscsi_mac, 0, ETH_ALEN); + } + + /* Disable FCoE if MAC configuration is + * invalid. + */ + if (!is_valid_ether_addr(fip_mac)) { + bp->flags |= NO_FCOE_FLAG; + memset(bp->fip_mac, 0, ETH_ALEN); + } #endif } -- cgit v0.10.2 From b3b83c3f3c640b239f1f1dfc49c0ecafbc074fdb Mon Sep 17 00:00:00 2001 From: Dmitry Kravkov Date: Wed, 4 May 2011 23:50:33 +0000 Subject: bnx2x: improve memory handling, low memory recovery flows Signed-off-by: Dmitry Kravkov Signed-off-by: Eilon Greenstein Signed-off-by: David S. Miller diff --git a/drivers/net/bnx2x/bnx2x.h b/drivers/net/bnx2x/bnx2x.h index 1a005a4..498a100 100644 --- a/drivers/net/bnx2x/bnx2x.h +++ b/drivers/net/bnx2x/bnx2x.h @@ -473,7 +473,8 @@ struct bnx2x_fastpath { #define NUM_RX_BD (RX_DESC_CNT * NUM_RX_RINGS) #define MAX_RX_BD (NUM_RX_BD - 1) #define MAX_RX_AVAIL (MAX_RX_DESC_CNT * NUM_RX_RINGS - 2) -#define MIN_RX_AVAIL 128 +#define MIN_RX_SIZE_TPA 72 +#define MIN_RX_SIZE_NONTPA 10 #define INIT_JUMBO_RX_RING_SIZE MAX_RX_AVAIL #define INIT_RX_RING_SIZE MAX_RX_AVAIL #define NEXT_RX_IDX(x) ((((x) & RX_DESC_MASK) == \ diff --git a/drivers/net/bnx2x/bnx2x_cmn.c b/drivers/net/bnx2x/bnx2x_cmn.c index 8853ae2..218a7ad 100644 --- a/drivers/net/bnx2x/bnx2x_cmn.c +++ b/drivers/net/bnx2x/bnx2x_cmn.c @@ -27,6 +27,49 @@ static int bnx2x_setup_irqs(struct bnx2x *bp); +/** + * bnx2x_bz_fp - zero content of the fastpath structure. + * + * @bp: driver handle + * @index: fastpath index to be zeroed + * + * Makes sure the contents of the bp->fp[index].napi is kept + * intact. + */ +static inline void bnx2x_bz_fp(struct bnx2x *bp, int index) +{ + struct bnx2x_fastpath *fp = &bp->fp[index]; + struct napi_struct orig_napi = fp->napi; + /* bzero bnx2x_fastpath contents */ + memset(fp, 0, sizeof(*fp)); + + /* Restore the NAPI object as it has been already initialized */ + fp->napi = orig_napi; +} + +/** + * bnx2x_move_fp - move content of the fastpath structure. + * + * @bp: driver handle + * @from: source FP index + * @to: destination FP index + * + * Makes sure the contents of the bp->fp[to].napi is kept + * intact. + */ +static inline void bnx2x_move_fp(struct bnx2x *bp, int from, int to) +{ + struct bnx2x_fastpath *from_fp = &bp->fp[from]; + struct bnx2x_fastpath *to_fp = &bp->fp[to]; + struct napi_struct orig_napi = to_fp->napi; + /* Move bnx2x_fastpath contents */ + memcpy(to_fp, from_fp, sizeof(*to_fp)); + to_fp->index = to; + + /* Restore the NAPI object as it has been already initialized */ + to_fp->napi = orig_napi; +} + /* free skb in the packet ring at pos idx * return idx of last bd freed */ @@ -881,55 +924,6 @@ void __bnx2x_link_report(struct bnx2x *bp) } } -/* Returns the number of actually allocated BDs */ -static inline int bnx2x_alloc_rx_bds(struct bnx2x_fastpath *fp, - int rx_ring_size) -{ - struct bnx2x *bp = fp->bp; - u16 ring_prod, cqe_ring_prod; - int i; - - fp->rx_comp_cons = 0; - cqe_ring_prod = ring_prod = 0; - for (i = 0; i < rx_ring_size; i++) { - if (bnx2x_alloc_rx_skb(bp, fp, ring_prod) < 0) { - BNX2X_ERR("was only able to allocate " - "%d rx skbs on queue[%d]\n", i, fp->index); - fp->eth_q_stats.rx_skb_alloc_failed++; - break; - } - ring_prod = NEXT_RX_IDX(ring_prod); - cqe_ring_prod = NEXT_RCQ_IDX(cqe_ring_prod); - WARN_ON(ring_prod <= i); - } - - fp->rx_bd_prod = ring_prod; - /* Limit the CQE producer by the CQE ring size */ - fp->rx_comp_prod = min_t(u16, NUM_RCQ_RINGS*RCQ_DESC_CNT, - cqe_ring_prod); - fp->rx_pkt = fp->rx_calls = 0; - - return i; -} - -static inline void bnx2x_alloc_rx_bd_ring(struct bnx2x_fastpath *fp) -{ - struct bnx2x *bp = fp->bp; - int rx_ring_size = bp->rx_ring_size ? bp->rx_ring_size : - MAX_RX_AVAIL/bp->num_queues; - - rx_ring_size = max_t(int, MIN_RX_AVAIL, rx_ring_size); - - bnx2x_alloc_rx_bds(fp, rx_ring_size); - - /* Warning! - * this will generate an interrupt (to the TSTORM) - * must only be done after chip is initialized - */ - bnx2x_update_rx_prod(bp, fp, fp->rx_bd_prod, fp->rx_comp_prod, - fp->rx_sge_prod); -} - void bnx2x_init_rx_rings(struct bnx2x *bp) { int func = BP_FUNC(bp); @@ -938,6 +932,7 @@ void bnx2x_init_rx_rings(struct bnx2x *bp) u16 ring_prod; int i, j; + /* Allocate TPA resources */ for_each_rx_queue(bp, j) { struct bnx2x_fastpath *fp = &bp->fp[j]; @@ -945,6 +940,7 @@ void bnx2x_init_rx_rings(struct bnx2x *bp) "mtu %d rx_buf_size %d\n", bp->dev->mtu, fp->rx_buf_size); if (!fp->disable_tpa) { + /* Fill the per-aggregation pool */ for (i = 0; i < max_agg_queues; i++) { fp->tpa_pool[i].skb = netdev_alloc_skb(bp->dev, fp->rx_buf_size); @@ -999,13 +995,13 @@ void bnx2x_init_rx_rings(struct bnx2x *bp) fp->rx_bd_cons = 0; - bnx2x_set_next_page_rx_bd(fp); - - /* CQ ring */ - bnx2x_set_next_page_rx_cq(fp); - - /* Allocate BDs and initialize BD ring */ - bnx2x_alloc_rx_bd_ring(fp); + /* Activate BD ring */ + /* Warning! + * this will generate an interrupt (to the TSTORM) + * must only be done after chip is initialized + */ + bnx2x_update_rx_prod(bp, fp, fp->rx_bd_prod, fp->rx_comp_prod, + fp->rx_sge_prod); if (j != 0) continue; @@ -1039,27 +1035,40 @@ static void bnx2x_free_tx_skbs(struct bnx2x *bp) } } +static void bnx2x_free_rx_bds(struct bnx2x_fastpath *fp) +{ + struct bnx2x *bp = fp->bp; + int i; + + /* ring wasn't allocated */ + if (fp->rx_buf_ring == NULL) + return; + + for (i = 0; i < NUM_RX_BD; i++) { + struct sw_rx_bd *rx_buf = &fp->rx_buf_ring[i]; + struct sk_buff *skb = rx_buf->skb; + + if (skb == NULL) + continue; + + dma_unmap_single(&bp->pdev->dev, + dma_unmap_addr(rx_buf, mapping), + fp->rx_buf_size, DMA_FROM_DEVICE); + + rx_buf->skb = NULL; + dev_kfree_skb(skb); + } +} + static void bnx2x_free_rx_skbs(struct bnx2x *bp) { - int i, j; + int j; for_each_rx_queue(bp, j) { struct bnx2x_fastpath *fp = &bp->fp[j]; - for (i = 0; i < NUM_RX_BD; i++) { - struct sw_rx_bd *rx_buf = &fp->rx_buf_ring[i]; - struct sk_buff *skb = rx_buf->skb; + bnx2x_free_rx_bds(fp); - if (skb == NULL) - continue; - - dma_unmap_single(&bp->pdev->dev, - dma_unmap_addr(rx_buf, mapping), - fp->rx_buf_size, DMA_FROM_DEVICE); - - rx_buf->skb = NULL; - dev_kfree_skb(skb); - } if (!fp->disable_tpa) bnx2x_free_tpa_pool(bp, fp, CHIP_IS_E1(bp) ? ETH_MAX_AGGREGATION_QUEUES_E1 : @@ -1435,26 +1444,37 @@ int bnx2x_nic_load(struct bnx2x *bp, int load_mode) /* must be called before memory allocation and HW init */ bnx2x_ilt_set_info(bp); + /* zero fastpath structures preserving invariants like napi which are + * allocated only once + */ + for_each_queue(bp, i) + bnx2x_bz_fp(bp, i); + /* Set the receive queues buffer size */ bnx2x_set_rx_buf_size(bp); + for_each_queue(bp, i) + bnx2x_fp(bp, i, disable_tpa) = + ((bp->flags & TPA_ENABLE_FLAG) == 0); + +#ifdef BCM_CNIC + /* We don't want TPA on FCoE L2 ring */ + bnx2x_fcoe(bp, disable_tpa) = 1; +#endif + if (bnx2x_alloc_mem(bp)) return -ENOMEM; + /* As long as bnx2x_alloc_mem() may possibly update + * bp->num_queues, bnx2x_set_real_num_queues() should always + * come after it. + */ rc = bnx2x_set_real_num_queues(bp); if (rc) { BNX2X_ERR("Unable to set real_num_queues\n"); goto load_error0; } - for_each_queue(bp, i) - bnx2x_fp(bp, i, disable_tpa) = - ((bp->flags & TPA_ENABLE_FLAG) == 0); - -#ifdef BCM_CNIC - /* We don't want TPA on FCoE L2 ring */ - bnx2x_fcoe(bp, disable_tpa) = 1; -#endif bnx2x_napi_enable(bp); /* Send LOAD_REQUEST command to MCP @@ -2480,6 +2500,232 @@ int bnx2x_change_mac_addr(struct net_device *dev, void *p) return 0; } +static void bnx2x_free_fp_mem_at(struct bnx2x *bp, int fp_index) +{ + union host_hc_status_block *sb = &bnx2x_fp(bp, fp_index, status_blk); + struct bnx2x_fastpath *fp = &bp->fp[fp_index]; + + /* Common */ +#ifdef BCM_CNIC + if (IS_FCOE_IDX(fp_index)) { + memset(sb, 0, sizeof(union host_hc_status_block)); + fp->status_blk_mapping = 0; + + } else { +#endif + /* status blocks */ + if (CHIP_IS_E2(bp)) + BNX2X_PCI_FREE(sb->e2_sb, + bnx2x_fp(bp, fp_index, + status_blk_mapping), + sizeof(struct host_hc_status_block_e2)); + else + BNX2X_PCI_FREE(sb->e1x_sb, + bnx2x_fp(bp, fp_index, + status_blk_mapping), + sizeof(struct host_hc_status_block_e1x)); +#ifdef BCM_CNIC + } +#endif + /* Rx */ + if (!skip_rx_queue(bp, fp_index)) { + bnx2x_free_rx_bds(fp); + + /* fastpath rx rings: rx_buf rx_desc rx_comp */ + BNX2X_FREE(bnx2x_fp(bp, fp_index, rx_buf_ring)); + BNX2X_PCI_FREE(bnx2x_fp(bp, fp_index, rx_desc_ring), + bnx2x_fp(bp, fp_index, rx_desc_mapping), + sizeof(struct eth_rx_bd) * NUM_RX_BD); + + BNX2X_PCI_FREE(bnx2x_fp(bp, fp_index, rx_comp_ring), + bnx2x_fp(bp, fp_index, rx_comp_mapping), + sizeof(struct eth_fast_path_rx_cqe) * + NUM_RCQ_BD); + + /* SGE ring */ + BNX2X_FREE(bnx2x_fp(bp, fp_index, rx_page_ring)); + BNX2X_PCI_FREE(bnx2x_fp(bp, fp_index, rx_sge_ring), + bnx2x_fp(bp, fp_index, rx_sge_mapping), + BCM_PAGE_SIZE * NUM_RX_SGE_PAGES); + } + + /* Tx */ + if (!skip_tx_queue(bp, fp_index)) { + /* fastpath tx rings: tx_buf tx_desc */ + BNX2X_FREE(bnx2x_fp(bp, fp_index, tx_buf_ring)); + BNX2X_PCI_FREE(bnx2x_fp(bp, fp_index, tx_desc_ring), + bnx2x_fp(bp, fp_index, tx_desc_mapping), + sizeof(union eth_tx_bd_types) * NUM_TX_BD); + } + /* end of fastpath */ +} + +void bnx2x_free_fp_mem(struct bnx2x *bp) +{ + int i; + for_each_queue(bp, i) + bnx2x_free_fp_mem_at(bp, i); +} + +static inline void set_sb_shortcuts(struct bnx2x *bp, int index) +{ + union host_hc_status_block status_blk = bnx2x_fp(bp, index, status_blk); + if (CHIP_IS_E2(bp)) { + bnx2x_fp(bp, index, sb_index_values) = + (__le16 *)status_blk.e2_sb->sb.index_values; + bnx2x_fp(bp, index, sb_running_index) = + (__le16 *)status_blk.e2_sb->sb.running_index; + } else { + bnx2x_fp(bp, index, sb_index_values) = + (__le16 *)status_blk.e1x_sb->sb.index_values; + bnx2x_fp(bp, index, sb_running_index) = + (__le16 *)status_blk.e1x_sb->sb.running_index; + } +} + +static int bnx2x_alloc_fp_mem_at(struct bnx2x *bp, int index) +{ + union host_hc_status_block *sb; + struct bnx2x_fastpath *fp = &bp->fp[index]; + int ring_size = 0; + + /* if rx_ring_size specified - use it */ + int rx_ring_size = bp->rx_ring_size ? bp->rx_ring_size : + MAX_RX_AVAIL/bp->num_queues; + + /* allocate at least number of buffers required by FW */ + rx_ring_size = max_t(int, fp->disable_tpa ? MIN_RX_SIZE_NONTPA : + MIN_RX_SIZE_TPA, + rx_ring_size); + + bnx2x_fp(bp, index, bp) = bp; + bnx2x_fp(bp, index, index) = index; + + /* Common */ + sb = &bnx2x_fp(bp, index, status_blk); +#ifdef BCM_CNIC + if (!IS_FCOE_IDX(index)) { +#endif + /* status blocks */ + if (CHIP_IS_E2(bp)) + BNX2X_PCI_ALLOC(sb->e2_sb, + &bnx2x_fp(bp, index, status_blk_mapping), + sizeof(struct host_hc_status_block_e2)); + else + BNX2X_PCI_ALLOC(sb->e1x_sb, + &bnx2x_fp(bp, index, status_blk_mapping), + sizeof(struct host_hc_status_block_e1x)); +#ifdef BCM_CNIC + } +#endif + set_sb_shortcuts(bp, index); + + /* Tx */ + if (!skip_tx_queue(bp, index)) { + /* fastpath tx rings: tx_buf tx_desc */ + BNX2X_ALLOC(bnx2x_fp(bp, index, tx_buf_ring), + sizeof(struct sw_tx_bd) * NUM_TX_BD); + BNX2X_PCI_ALLOC(bnx2x_fp(bp, index, tx_desc_ring), + &bnx2x_fp(bp, index, tx_desc_mapping), + sizeof(union eth_tx_bd_types) * NUM_TX_BD); + } + + /* Rx */ + if (!skip_rx_queue(bp, index)) { + /* fastpath rx rings: rx_buf rx_desc rx_comp */ + BNX2X_ALLOC(bnx2x_fp(bp, index, rx_buf_ring), + sizeof(struct sw_rx_bd) * NUM_RX_BD); + BNX2X_PCI_ALLOC(bnx2x_fp(bp, index, rx_desc_ring), + &bnx2x_fp(bp, index, rx_desc_mapping), + sizeof(struct eth_rx_bd) * NUM_RX_BD); + + BNX2X_PCI_ALLOC(bnx2x_fp(bp, index, rx_comp_ring), + &bnx2x_fp(bp, index, rx_comp_mapping), + sizeof(struct eth_fast_path_rx_cqe) * + NUM_RCQ_BD); + + /* SGE ring */ + BNX2X_ALLOC(bnx2x_fp(bp, index, rx_page_ring), + sizeof(struct sw_rx_page) * NUM_RX_SGE); + BNX2X_PCI_ALLOC(bnx2x_fp(bp, index, rx_sge_ring), + &bnx2x_fp(bp, index, rx_sge_mapping), + BCM_PAGE_SIZE * NUM_RX_SGE_PAGES); + /* RX BD ring */ + bnx2x_set_next_page_rx_bd(fp); + + /* CQ ring */ + bnx2x_set_next_page_rx_cq(fp); + + /* BDs */ + ring_size = bnx2x_alloc_rx_bds(fp, rx_ring_size); + if (ring_size < rx_ring_size) + goto alloc_mem_err; + } + + return 0; + +/* handles low memory cases */ +alloc_mem_err: + BNX2X_ERR("Unable to allocate full memory for queue %d (size %d)\n", + index, ring_size); + /* FW will drop all packets if queue is not big enough, + * In these cases we disable the queue + * Min size diferent for TPA and non-TPA queues + */ + if (ring_size < (fp->disable_tpa ? + MIN_RX_SIZE_TPA : MIN_RX_SIZE_NONTPA)) { + /* release memory allocated for this queue */ + bnx2x_free_fp_mem_at(bp, index); + return -ENOMEM; + } + return 0; +} + +int bnx2x_alloc_fp_mem(struct bnx2x *bp) +{ + int i; + + /** + * 1. Allocate FP for leading - fatal if error + * 2. {CNIC} Allocate FCoE FP - fatal if error + * 3. Allocate RSS - fix number of queues if error + */ + + /* leading */ + if (bnx2x_alloc_fp_mem_at(bp, 0)) + return -ENOMEM; +#ifdef BCM_CNIC + /* FCoE */ + if (bnx2x_alloc_fp_mem_at(bp, FCOE_IDX)) + return -ENOMEM; +#endif + /* RSS */ + for_each_nondefault_eth_queue(bp, i) + if (bnx2x_alloc_fp_mem_at(bp, i)) + break; + + /* handle memory failures */ + if (i != BNX2X_NUM_ETH_QUEUES(bp)) { + int delta = BNX2X_NUM_ETH_QUEUES(bp) - i; + + WARN_ON(delta < 0); +#ifdef BCM_CNIC + /** + * move non eth FPs next to last eth FP + * must be done in that order + * FCOE_IDX < FWD_IDX < OOO_IDX + */ + + /* move FCoE fp */ + bnx2x_move_fp(bp, FCOE_IDX, FCOE_IDX - delta); +#endif + bp->num_queues -= delta; + BNX2X_ERR("Adjusted num of queues from %d to %d\n", + bp->num_queues + delta, bp->num_queues); + } + + return 0; +} static int bnx2x_setup_irqs(struct bnx2x *bp) { diff --git a/drivers/net/bnx2x/bnx2x_cmn.h b/drivers/net/bnx2x/bnx2x_cmn.h index 007f294..68b79a1 100644 --- a/drivers/net/bnx2x/bnx2x_cmn.h +++ b/drivers/net/bnx2x/bnx2x_cmn.h @@ -25,6 +25,39 @@ extern int num_queues; +/************************ Macros ********************************/ +#define BNX2X_PCI_FREE(x, y, size) \ + do { \ + if (x) { \ + dma_free_coherent(&bp->pdev->dev, size, (void *)x, y); \ + x = NULL; \ + y = 0; \ + } \ + } while (0) + +#define BNX2X_FREE(x) \ + do { \ + if (x) { \ + kfree((void *)x); \ + x = NULL; \ + } \ + } while (0) + +#define BNX2X_PCI_ALLOC(x, y, size) \ + do { \ + x = dma_alloc_coherent(&bp->pdev->dev, size, y, GFP_KERNEL); \ + if (x == NULL) \ + goto alloc_mem_err; \ + memset((void *)x, 0, size); \ + } while (0) + +#define BNX2X_ALLOC(x, size) \ + do { \ + x = kzalloc(size, GFP_KERNEL); \ + if (x == NULL) \ + goto alloc_mem_err; \ + } while (0) + /*********************** Interfaces **************************** * Functions that need to be implemented by each driver version */ @@ -378,6 +411,9 @@ int bnx2x_resume(struct pci_dev *pdev); /* Release IRQ vectors */ void bnx2x_free_irq(struct bnx2x *bp); +void bnx2x_free_fp_mem(struct bnx2x *bp); +int bnx2x_alloc_fp_mem(struct bnx2x *bp); + void bnx2x_init_rx_rings(struct bnx2x *bp); void bnx2x_free_skbs(struct bnx2x *bp); void bnx2x_netif_stop(struct bnx2x *bp, int disable_hw); @@ -884,6 +920,9 @@ static inline void bnx2x_free_rx_sge_range(struct bnx2x *bp, { int i; + if (fp->disable_tpa) + return; + for (i = 0; i < last; i++) bnx2x_free_rx_sge(bp, fp, i); } @@ -912,36 +951,39 @@ static inline void bnx2x_free_tpa_pool(struct bnx2x *bp, } } - -static inline void bnx2x_init_tx_rings(struct bnx2x *bp) +static inline void bnx2x_init_tx_ring_one(struct bnx2x_fastpath *fp) { - int i, j; + int i; - for_each_tx_queue(bp, j) { - struct bnx2x_fastpath *fp = &bp->fp[j]; + for (i = 1; i <= NUM_TX_RINGS; i++) { + struct eth_tx_next_bd *tx_next_bd = + &fp->tx_desc_ring[TX_DESC_CNT * i - 1].next_bd; - for (i = 1; i <= NUM_TX_RINGS; i++) { - struct eth_tx_next_bd *tx_next_bd = - &fp->tx_desc_ring[TX_DESC_CNT * i - 1].next_bd; + tx_next_bd->addr_hi = + cpu_to_le32(U64_HI(fp->tx_desc_mapping + + BCM_PAGE_SIZE*(i % NUM_TX_RINGS))); + tx_next_bd->addr_lo = + cpu_to_le32(U64_LO(fp->tx_desc_mapping + + BCM_PAGE_SIZE*(i % NUM_TX_RINGS))); + } - tx_next_bd->addr_hi = - cpu_to_le32(U64_HI(fp->tx_desc_mapping + - BCM_PAGE_SIZE*(i % NUM_TX_RINGS))); - tx_next_bd->addr_lo = - cpu_to_le32(U64_LO(fp->tx_desc_mapping + - BCM_PAGE_SIZE*(i % NUM_TX_RINGS))); - } + SET_FLAG(fp->tx_db.data.header.header, DOORBELL_HDR_DB_TYPE, 1); + fp->tx_db.data.zero_fill1 = 0; + fp->tx_db.data.prod = 0; - SET_FLAG(fp->tx_db.data.header.header, DOORBELL_HDR_DB_TYPE, 1); - fp->tx_db.data.zero_fill1 = 0; - fp->tx_db.data.prod = 0; + fp->tx_pkt_prod = 0; + fp->tx_pkt_cons = 0; + fp->tx_bd_prod = 0; + fp->tx_bd_cons = 0; + fp->tx_pkt = 0; +} - fp->tx_pkt_prod = 0; - fp->tx_pkt_cons = 0; - fp->tx_bd_prod = 0; - fp->tx_bd_cons = 0; - fp->tx_pkt = 0; - } +static inline void bnx2x_init_tx_rings(struct bnx2x *bp) +{ + int i; + + for_each_tx_queue(bp, i) + bnx2x_init_tx_ring_one(&bp->fp[i]); } static inline void bnx2x_set_next_page_rx_bd(struct bnx2x_fastpath *fp) @@ -996,6 +1038,44 @@ static inline void bnx2x_set_next_page_rx_cq(struct bnx2x_fastpath *fp) } } +/* Returns the number of actually allocated BDs */ +static inline int bnx2x_alloc_rx_bds(struct bnx2x_fastpath *fp, + int rx_ring_size) +{ + struct bnx2x *bp = fp->bp; + u16 ring_prod, cqe_ring_prod; + int i; + + fp->rx_comp_cons = 0; + cqe_ring_prod = ring_prod = 0; + + /* This routine is called only during fo init so + * fp->eth_q_stats.rx_skb_alloc_failed = 0 + */ + for (i = 0; i < rx_ring_size; i++) { + if (bnx2x_alloc_rx_skb(bp, fp, ring_prod) < 0) { + fp->eth_q_stats.rx_skb_alloc_failed++; + continue; + } + ring_prod = NEXT_RX_IDX(ring_prod); + cqe_ring_prod = NEXT_RCQ_IDX(cqe_ring_prod); + WARN_ON(ring_prod <= (i - fp->eth_q_stats.rx_skb_alloc_failed)); + } + + if (fp->eth_q_stats.rx_skb_alloc_failed) + BNX2X_ERR("was only able to allocate " + "%d rx skbs on queue[%d]\n", + (i - fp->eth_q_stats.rx_skb_alloc_failed), fp->index); + + fp->rx_bd_prod = ring_prod; + /* Limit the CQE producer by the CQE ring size */ + fp->rx_comp_prod = min_t(u16, NUM_RCQ_RINGS*RCQ_DESC_CNT, + cqe_ring_prod); + fp->rx_pkt = fp->rx_calls = 0; + + return i - fp->eth_q_stats.rx_skb_alloc_failed; +} + #ifdef BCM_CNIC static inline void bnx2x_init_fcoe_fp(struct bnx2x *bp) { diff --git a/drivers/net/bnx2x/bnx2x_ethtool.c b/drivers/net/bnx2x/bnx2x_ethtool.c index 4f42c31..7556fde 100644 --- a/drivers/net/bnx2x/bnx2x_ethtool.c +++ b/drivers/net/bnx2x/bnx2x_ethtool.c @@ -1220,7 +1220,8 @@ static int bnx2x_set_ringparam(struct net_device *dev, } if ((ering->rx_pending > MAX_RX_AVAIL) || - (ering->rx_pending < MIN_RX_AVAIL) || + (ering->rx_pending < (bp->disable_tpa ? MIN_RX_SIZE_NONTPA : + MIN_RX_SIZE_TPA)) || (ering->tx_pending > MAX_TX_AVAIL) || (ering->tx_pending <= MAX_SKB_FRAGS + 4)) return -EINVAL; diff --git a/drivers/net/bnx2x/bnx2x_main.c b/drivers/net/bnx2x/bnx2x_main.c index 660c945..4be5480 100644 --- a/drivers/net/bnx2x/bnx2x_main.c +++ b/drivers/net/bnx2x/bnx2x_main.c @@ -4447,7 +4447,7 @@ static void bnx2x_init_fp_sb(struct bnx2x *bp, int fp_idx) fp->state = BNX2X_FP_STATE_CLOSED; - fp->index = fp->cid = fp_idx; + fp->cid = fp_idx; fp->cl_id = BP_L_ID(bp) + fp_idx; fp->fw_sb_id = bp->base_fw_ndsb + fp->cl_id + CNIC_CONTEXT_USE; fp->igu_sb_id = bp->igu_base_sb + fp_idx + CNIC_CONTEXT_USE; @@ -4559,9 +4559,11 @@ gunzip_nomem1: static void bnx2x_gunzip_end(struct bnx2x *bp) { - kfree(bp->strm->workspace); - kfree(bp->strm); - bp->strm = NULL; + if (bp->strm) { + kfree(bp->strm->workspace); + kfree(bp->strm); + bp->strm = NULL; + } if (bp->gunzip_buf) { dma_free_coherent(&bp->pdev->dev, FW_BUF_SIZE, bp->gunzip_buf, @@ -5869,9 +5871,6 @@ int bnx2x_init_hw(struct bnx2x *bp, u32 load_code) bp->dmae_ready = 0; spin_lock_init(&bp->dmae_lock); - rc = bnx2x_gunzip_init(bp); - if (rc) - return rc; switch (load_code) { case FW_MSG_CODE_DRV_LOAD_COMMON: @@ -5915,80 +5914,10 @@ init_hw_err: void bnx2x_free_mem(struct bnx2x *bp) { - -#define BNX2X_PCI_FREE(x, y, size) \ - do { \ - if (x) { \ - dma_free_coherent(&bp->pdev->dev, size, (void *)x, y); \ - x = NULL; \ - y = 0; \ - } \ - } while (0) - -#define BNX2X_FREE(x) \ - do { \ - if (x) { \ - kfree((void *)x); \ - x = NULL; \ - } \ - } while (0) - - int i; + bnx2x_gunzip_end(bp); /* fastpath */ - /* Common */ - for_each_queue(bp, i) { -#ifdef BCM_CNIC - /* FCoE client uses default status block */ - if (IS_FCOE_IDX(i)) { - union host_hc_status_block *sb = - &bnx2x_fp(bp, i, status_blk); - memset(sb, 0, sizeof(union host_hc_status_block)); - bnx2x_fp(bp, i, status_blk_mapping) = 0; - } else { -#endif - /* status blocks */ - if (CHIP_IS_E2(bp)) - BNX2X_PCI_FREE(bnx2x_fp(bp, i, status_blk.e2_sb), - bnx2x_fp(bp, i, status_blk_mapping), - sizeof(struct host_hc_status_block_e2)); - else - BNX2X_PCI_FREE(bnx2x_fp(bp, i, status_blk.e1x_sb), - bnx2x_fp(bp, i, status_blk_mapping), - sizeof(struct host_hc_status_block_e1x)); -#ifdef BCM_CNIC - } -#endif - } - /* Rx */ - for_each_rx_queue(bp, i) { - - /* fastpath rx rings: rx_buf rx_desc rx_comp */ - BNX2X_FREE(bnx2x_fp(bp, i, rx_buf_ring)); - BNX2X_PCI_FREE(bnx2x_fp(bp, i, rx_desc_ring), - bnx2x_fp(bp, i, rx_desc_mapping), - sizeof(struct eth_rx_bd) * NUM_RX_BD); - - BNX2X_PCI_FREE(bnx2x_fp(bp, i, rx_comp_ring), - bnx2x_fp(bp, i, rx_comp_mapping), - sizeof(struct eth_fast_path_rx_cqe) * - NUM_RCQ_BD); - - /* SGE ring */ - BNX2X_FREE(bnx2x_fp(bp, i, rx_page_ring)); - BNX2X_PCI_FREE(bnx2x_fp(bp, i, rx_sge_ring), - bnx2x_fp(bp, i, rx_sge_mapping), - BCM_PAGE_SIZE * NUM_RX_SGE_PAGES); - } - /* Tx */ - for_each_tx_queue(bp, i) { - - /* fastpath tx rings: tx_buf tx_desc */ - BNX2X_FREE(bnx2x_fp(bp, i, tx_buf_ring)); - BNX2X_PCI_FREE(bnx2x_fp(bp, i, tx_desc_ring), - bnx2x_fp(bp, i, tx_desc_mapping), - sizeof(union eth_tx_bd_types) * NUM_TX_BD); - } + bnx2x_free_fp_mem(bp); /* end of fastpath */ BNX2X_PCI_FREE(bp->def_status_blk, bp->def_status_blk_mapping, @@ -6021,101 +5950,13 @@ void bnx2x_free_mem(struct bnx2x *bp) BCM_PAGE_SIZE * NUM_EQ_PAGES); BNX2X_FREE(bp->rx_indir_table); - -#undef BNX2X_PCI_FREE -#undef BNX2X_KFREE } -static inline void set_sb_shortcuts(struct bnx2x *bp, int index) -{ - union host_hc_status_block status_blk = bnx2x_fp(bp, index, status_blk); - if (CHIP_IS_E2(bp)) { - bnx2x_fp(bp, index, sb_index_values) = - (__le16 *)status_blk.e2_sb->sb.index_values; - bnx2x_fp(bp, index, sb_running_index) = - (__le16 *)status_blk.e2_sb->sb.running_index; - } else { - bnx2x_fp(bp, index, sb_index_values) = - (__le16 *)status_blk.e1x_sb->sb.index_values; - bnx2x_fp(bp, index, sb_running_index) = - (__le16 *)status_blk.e1x_sb->sb.running_index; - } -} int bnx2x_alloc_mem(struct bnx2x *bp) { -#define BNX2X_PCI_ALLOC(x, y, size) \ - do { \ - x = dma_alloc_coherent(&bp->pdev->dev, size, y, GFP_KERNEL); \ - if (x == NULL) \ - goto alloc_mem_err; \ - memset(x, 0, size); \ - } while (0) - -#define BNX2X_ALLOC(x, size) \ - do { \ - x = kzalloc(size, GFP_KERNEL); \ - if (x == NULL) \ - goto alloc_mem_err; \ - } while (0) - - int i; - - /* fastpath */ - /* Common */ - for_each_queue(bp, i) { - union host_hc_status_block *sb = &bnx2x_fp(bp, i, status_blk); - bnx2x_fp(bp, i, bp) = bp; - /* status blocks */ -#ifdef BCM_CNIC - if (!IS_FCOE_IDX(i)) { -#endif - if (CHIP_IS_E2(bp)) - BNX2X_PCI_ALLOC(sb->e2_sb, - &bnx2x_fp(bp, i, status_blk_mapping), - sizeof(struct host_hc_status_block_e2)); - else - BNX2X_PCI_ALLOC(sb->e1x_sb, - &bnx2x_fp(bp, i, status_blk_mapping), - sizeof(struct host_hc_status_block_e1x)); -#ifdef BCM_CNIC - } -#endif - set_sb_shortcuts(bp, i); - } - /* Rx */ - for_each_queue(bp, i) { - - /* fastpath rx rings: rx_buf rx_desc rx_comp */ - BNX2X_ALLOC(bnx2x_fp(bp, i, rx_buf_ring), - sizeof(struct sw_rx_bd) * NUM_RX_BD); - BNX2X_PCI_ALLOC(bnx2x_fp(bp, i, rx_desc_ring), - &bnx2x_fp(bp, i, rx_desc_mapping), - sizeof(struct eth_rx_bd) * NUM_RX_BD); - - BNX2X_PCI_ALLOC(bnx2x_fp(bp, i, rx_comp_ring), - &bnx2x_fp(bp, i, rx_comp_mapping), - sizeof(struct eth_fast_path_rx_cqe) * - NUM_RCQ_BD); - - /* SGE ring */ - BNX2X_ALLOC(bnx2x_fp(bp, i, rx_page_ring), - sizeof(struct sw_rx_page) * NUM_RX_SGE); - BNX2X_PCI_ALLOC(bnx2x_fp(bp, i, rx_sge_ring), - &bnx2x_fp(bp, i, rx_sge_mapping), - BCM_PAGE_SIZE * NUM_RX_SGE_PAGES); - } - /* Tx */ - for_each_queue(bp, i) { - - /* fastpath tx rings: tx_buf tx_desc */ - BNX2X_ALLOC(bnx2x_fp(bp, i, tx_buf_ring), - sizeof(struct sw_tx_bd) * NUM_TX_BD); - BNX2X_PCI_ALLOC(bnx2x_fp(bp, i, tx_desc_ring), - &bnx2x_fp(bp, i, tx_desc_mapping), - sizeof(union eth_tx_bd_types) * NUM_TX_BD); - } - /* end of fastpath */ + if (bnx2x_gunzip_init(bp)) + return -ENOMEM; #ifdef BCM_CNIC if (CHIP_IS_E2(bp)) @@ -6155,14 +5996,18 @@ int bnx2x_alloc_mem(struct bnx2x *bp) BNX2X_ALLOC(bp->rx_indir_table, sizeof(bp->rx_indir_table[0]) * TSTORM_INDIRECTION_TABLE_SIZE); + + /* fastpath */ + /* need to be done at the end, since it's self adjusting to amount + * of memory available for RSS queues + */ + if (bnx2x_alloc_fp_mem(bp)) + goto alloc_mem_err; return 0; alloc_mem_err: bnx2x_free_mem(bp); return -ENOMEM; - -#undef BNX2X_PCI_ALLOC -#undef BNX2X_ALLOC } /* -- cgit v0.10.2 From 5de924086aca9f17eee9ad569e0af2f699f591b3 Mon Sep 17 00:00:00 2001 From: Dmitry Kravkov Date: Wed, 4 May 2011 23:51:13 +0000 Subject: bnx2x: update year to 2011 and version to 1.62.12-0 Signed-off-by: Dmitry Kravkov Signed-off-by: Eilon Greenstein Signed-off-by: David S. Miller diff --git a/drivers/net/bnx2x/bnx2x.h b/drivers/net/bnx2x/bnx2x.h index 498a100..16a76f0 100644 --- a/drivers/net/bnx2x/bnx2x.h +++ b/drivers/net/bnx2x/bnx2x.h @@ -1,6 +1,6 @@ /* bnx2x.h: Broadcom Everest network driver. * - * Copyright (c) 2007-2010 Broadcom Corporation + * Copyright (c) 2007-2011 Broadcom Corporation * * 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 @@ -22,8 +22,8 @@ * (you will need to reboot afterwards) */ /* #define BNX2X_STOP_ON_ERROR */ -#define DRV_MODULE_VERSION "1.62.11-0" -#define DRV_MODULE_RELDATE "2011/01/31" +#define DRV_MODULE_VERSION "1.62.12-0" +#define DRV_MODULE_RELDATE "2011/03/20" #define BNX2X_BC_VER 0x040200 #define BNX2X_MULTI_QUEUE diff --git a/drivers/net/bnx2x/bnx2x_cmn.c b/drivers/net/bnx2x/bnx2x_cmn.c index 218a7ad..269d6d1 100644 --- a/drivers/net/bnx2x/bnx2x_cmn.c +++ b/drivers/net/bnx2x/bnx2x_cmn.c @@ -1,6 +1,6 @@ /* bnx2x_cmn.c: Broadcom Everest network driver. * - * Copyright (c) 2007-2010 Broadcom Corporation + * Copyright (c) 2007-2011 Broadcom Corporation * * 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 diff --git a/drivers/net/bnx2x/bnx2x_cmn.h b/drivers/net/bnx2x/bnx2x_cmn.h index 68b79a1..72f206e 100644 --- a/drivers/net/bnx2x/bnx2x_cmn.h +++ b/drivers/net/bnx2x/bnx2x_cmn.h @@ -1,6 +1,6 @@ /* bnx2x_cmn.h: Broadcom Everest network driver. * - * Copyright (c) 2007-2010 Broadcom Corporation + * Copyright (c) 2007-2011 Broadcom Corporation * * 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 diff --git a/drivers/net/bnx2x/bnx2x_dcb.c b/drivers/net/bnx2x/bnx2x_dcb.c index 1214907..3396ff2 100644 --- a/drivers/net/bnx2x/bnx2x_dcb.c +++ b/drivers/net/bnx2x/bnx2x_dcb.c @@ -1,6 +1,6 @@ /* bnx2x_dcb.c: Broadcom Everest network driver. * - * Copyright 2009-2010 Broadcom Corporation + * Copyright 2009-2011 Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/bnx2x/bnx2x_dcb.h b/drivers/net/bnx2x/bnx2x_dcb.h index 1e14775..bb6e9a5b 100644 --- a/drivers/net/bnx2x/bnx2x_dcb.h +++ b/drivers/net/bnx2x/bnx2x_dcb.h @@ -1,6 +1,6 @@ /* bnx2x_dcb.h: Broadcom Everest network driver. * - * Copyright 2009-2010 Broadcom Corporation + * Copyright 2009-2011 Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you diff --git a/drivers/net/bnx2x/bnx2x_ethtool.c b/drivers/net/bnx2x/bnx2x_ethtool.c index 7556fde..727fe89 100644 --- a/drivers/net/bnx2x/bnx2x_ethtool.c +++ b/drivers/net/bnx2x/bnx2x_ethtool.c @@ -1,6 +1,6 @@ /* bnx2x_ethtool.c: Broadcom Everest network driver. * - * Copyright (c) 2007-2010 Broadcom Corporation + * Copyright (c) 2007-2011 Broadcom Corporation * * 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 diff --git a/drivers/net/bnx2x/bnx2x_fw_defs.h b/drivers/net/bnx2x/bnx2x_fw_defs.h index f4e5b1c..9fe3678 100644 --- a/drivers/net/bnx2x/bnx2x_fw_defs.h +++ b/drivers/net/bnx2x/bnx2x_fw_defs.h @@ -1,6 +1,6 @@ /* bnx2x_fw_defs.h: Broadcom Everest network driver. * - * Copyright (c) 2007-2010 Broadcom Corporation + * Copyright (c) 2007-2011 Broadcom Corporation * * 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 diff --git a/drivers/net/bnx2x/bnx2x_fw_file_hdr.h b/drivers/net/bnx2x/bnx2x_fw_file_hdr.h index f807262..f4a07fb 100644 --- a/drivers/net/bnx2x/bnx2x_fw_file_hdr.h +++ b/drivers/net/bnx2x/bnx2x_fw_file_hdr.h @@ -1,6 +1,6 @@ /* bnx2x_fw_file_hdr.h: FW binary file header structure. * - * Copyright (c) 2007-2009 Broadcom Corporation + * Copyright (c) 2007-2011 Broadcom Corporation * * 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 diff --git a/drivers/net/bnx2x/bnx2x_hsi.h b/drivers/net/bnx2x/bnx2x_hsi.h index 2b5940a..cdf19fe 100644 --- a/drivers/net/bnx2x/bnx2x_hsi.h +++ b/drivers/net/bnx2x/bnx2x_hsi.h @@ -1,6 +1,6 @@ /* bnx2x_hsi.h: Broadcom Everest network driver. * - * Copyright (c) 2007-2010 Broadcom Corporation + * Copyright (c) 2007-2011 Broadcom Corporation * * 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 diff --git a/drivers/net/bnx2x/bnx2x_init.h b/drivers/net/bnx2x/bnx2x_init.h index fa6dbe3..d539920 100644 --- a/drivers/net/bnx2x/bnx2x_init.h +++ b/drivers/net/bnx2x/bnx2x_init.h @@ -1,7 +1,7 @@ /* bnx2x_init.h: Broadcom Everest network driver. * Structures and macroes needed during the initialization. * - * Copyright (c) 2007-2009 Broadcom Corporation + * Copyright (c) 2007-2011 Broadcom Corporation * * 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 diff --git a/drivers/net/bnx2x/bnx2x_init_ops.h b/drivers/net/bnx2x/bnx2x_init_ops.h index 66df29f..aafd023 100644 --- a/drivers/net/bnx2x/bnx2x_init_ops.h +++ b/drivers/net/bnx2x/bnx2x_init_ops.h @@ -2,7 +2,7 @@ * Static functions needed during the initialization. * This file is "included" in bnx2x_main.c. * - * Copyright (c) 2007-2010 Broadcom Corporation + * Copyright (c) 2007-2011 Broadcom Corporation * * 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 diff --git a/drivers/net/bnx2x/bnx2x_main.c b/drivers/net/bnx2x/bnx2x_main.c index 4be5480..0c31b91 100644 --- a/drivers/net/bnx2x/bnx2x_main.c +++ b/drivers/net/bnx2x/bnx2x_main.c @@ -1,6 +1,6 @@ /* bnx2x_main.c: Broadcom Everest network driver. * - * Copyright (c) 2007-2010 Broadcom Corporation + * Copyright (c) 2007-2011 Broadcom Corporation * * 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 diff --git a/drivers/net/bnx2x/bnx2x_reg.h b/drivers/net/bnx2x/bnx2x_reg.h index 1509a23..86bba25 100644 --- a/drivers/net/bnx2x/bnx2x_reg.h +++ b/drivers/net/bnx2x/bnx2x_reg.h @@ -1,6 +1,6 @@ /* bnx2x_reg.h: Broadcom Everest network driver. * - * Copyright (c) 2007-2010 Broadcom Corporation + * Copyright (c) 2007-2011 Broadcom Corporation * * 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 diff --git a/drivers/net/bnx2x/bnx2x_stats.c b/drivers/net/bnx2x/bnx2x_stats.c index 3445ded..e535bfa 100644 --- a/drivers/net/bnx2x/bnx2x_stats.c +++ b/drivers/net/bnx2x/bnx2x_stats.c @@ -1,6 +1,6 @@ /* bnx2x_stats.c: Broadcom Everest network driver. * - * Copyright (c) 2007-2010 Broadcom Corporation + * Copyright (c) 2007-2011 Broadcom Corporation * * 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 diff --git a/drivers/net/bnx2x/bnx2x_stats.h b/drivers/net/bnx2x/bnx2x_stats.h index 596798c..45d14d8 100644 --- a/drivers/net/bnx2x/bnx2x_stats.h +++ b/drivers/net/bnx2x/bnx2x_stats.h @@ -1,6 +1,6 @@ /* bnx2x_stats.h: Broadcom Everest network driver. * - * Copyright (c) 2007-2010 Broadcom Corporation + * Copyright (c) 2007-2011 Broadcom Corporation * * 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 -- cgit v0.10.2 From e8920674979705392abc4db4ebbe78feb68a4da1 Mon Sep 17 00:00:00 2001 From: Dmitry Kravkov Date: Wed, 4 May 2011 23:52:40 +0000 Subject: bnx2x: function descriptions format fixed Signed-off-by: Dmitry Kravkov Signed-off-by: Eilon Greenstein Signed-off-by: David S. Miller diff --git a/drivers/net/bnx2x/bnx2x_cmn.c b/drivers/net/bnx2x/bnx2x_cmn.c index 269d6d1..6ee6601 100644 --- a/drivers/net/bnx2x/bnx2x_cmn.c +++ b/drivers/net/bnx2x/bnx2x_cmn.c @@ -308,13 +308,15 @@ static void bnx2x_tpa_start(struct bnx2x_fastpath *fp, u16 queue, */ #define TPA_TSTAMP_OPT_LEN 12 /** - * Calculate the approximate value of the MSS for this - * aggregation using the first packet of it. + * bnx2x_set_lro_mss - calculate the approximate value of the MSS * - * @param bp - * @param parsing_flags Parsing flags from the START CQE - * @param len_on_bd Total length of the first packet for the - * aggregation. + * @bp: driver handle + * @parsing_flags: parsing flags from the START CQE + * @len_on_bd: total length of the first packet for the + * aggregation. + * + * Approximate value of the MSS for this aggregation calculated using + * the first packet of it. */ static inline u16 bnx2x_set_lro_mss(struct bnx2x *bp, u16 parsing_flags, u16 len_on_bd) @@ -2083,12 +2085,11 @@ static inline void bnx2x_set_pbd_gso_e2(struct sk_buff *skb, u32 *parsing_data, } /** - * Update PBD in GSO case. + * bnx2x_set_pbd_gso - update PBD in GSO case. * - * @param skb - * @param tx_start_bd - * @param pbd - * @param xmit_type + * @skb: packet skb + * @pbd: parse BD + * @xmit_type: xmit flags */ static inline void bnx2x_set_pbd_gso(struct sk_buff *skb, struct eth_tx_parse_bd_e1x *pbd, @@ -2115,13 +2116,14 @@ static inline void bnx2x_set_pbd_gso(struct sk_buff *skb, } /** + * bnx2x_set_pbd_csum_e2 - update PBD with checksum and return header length * - * @param skb - * @param tx_start_bd - * @param pbd_e2 - * @param xmit_type + * @bp: driver handle + * @skb: packet skb + * @parsing_data: data to be updated + * @xmit_type: xmit flags * - * @return header len + * 57712 related */ static inline u8 bnx2x_set_pbd_csum_e2(struct bnx2x *bp, struct sk_buff *skb, u32 *parsing_data, u32 xmit_type) @@ -2146,13 +2148,12 @@ static inline u8 bnx2x_set_pbd_csum_e2(struct bnx2x *bp, struct sk_buff *skb, } /** + * bnx2x_set_pbd_csum - update PBD with checksum and return header length * - * @param skb - * @param tx_start_bd - * @param pbd - * @param xmit_type - * - * @return Header length + * @bp: driver handle + * @skb: packet skb + * @pbd: parse BD to be updated + * @xmit_type: xmit flags */ static inline u8 bnx2x_set_pbd_csum(struct bnx2x *bp, struct sk_buff *skb, struct eth_tx_parse_bd_e1x *pbd, diff --git a/drivers/net/bnx2x/bnx2x_cmn.h b/drivers/net/bnx2x/bnx2x_cmn.h index 72f206e..fab161e 100644 --- a/drivers/net/bnx2x/bnx2x_cmn.h +++ b/drivers/net/bnx2x/bnx2x_cmn.h @@ -63,43 +63,41 @@ extern int num_queues; */ /** - * Initialize link parameters structure variables. + * bnx2x_initial_phy_init - initialize link parameters structure variables. * - * @param bp - * @param load_mode - * - * @return u8 + * @bp: driver handle + * @load_mode: current mode */ u8 bnx2x_initial_phy_init(struct bnx2x *bp, int load_mode); /** - * Configure hw according to link parameters structure. + * bnx2x_link_set - configure hw according to link parameters structure. * - * @param bp + * @bp: driver handle */ void bnx2x_link_set(struct bnx2x *bp); /** - * Query link status + * bnx2x_link_test - query link status. * - * @param bp - * @param is_serdes + * @bp: driver handle + * @is_serdes: bool * - * @return 0 - link is UP + * Returns 0 if link is UP. */ u8 bnx2x_link_test(struct bnx2x *bp, u8 is_serdes); /** - * Handles link status change + * bnx2x__link_status_update - handles link status change. * - * @param bp + * @bp: driver handle */ void bnx2x__link_status_update(struct bnx2x *bp); /** - * Report link status to upper layer + * bnx2x_link_report - report link status to upper layer. * - * @param bp + * @bp: driver handle */ void bnx2x_link_report(struct bnx2x *bp); @@ -107,212 +105,197 @@ void bnx2x_link_report(struct bnx2x *bp); void __bnx2x_link_report(struct bnx2x *bp); /** - * calculates MF speed according to current linespeed and MF - * configuration + * bnx2x_get_mf_speed - calculate MF speed. * - * @param bp + * @bp: driver handle * - * @return u16 + * Takes into account current linespeed and MF configuration. */ u16 bnx2x_get_mf_speed(struct bnx2x *bp); /** - * MSI-X slowpath interrupt handler - * - * @param irq - * @param dev_instance + * bnx2x_msix_sp_int - MSI-X slowpath interrupt handler * - * @return irqreturn_t + * @irq: irq number + * @dev_instance: private instance */ irqreturn_t bnx2x_msix_sp_int(int irq, void *dev_instance); /** - * non MSI-X interrupt handler - * - * @param irq - * @param dev_instance + * bnx2x_interrupt - non MSI-X interrupt handler * - * @return irqreturn_t + * @irq: irq number + * @dev_instance: private instance */ irqreturn_t bnx2x_interrupt(int irq, void *dev_instance); #ifdef BCM_CNIC /** - * Send command to cnic driver + * bnx2x_cnic_notify - send command to cnic driver * - * @param bp - * @param cmd + * @bp: driver handle + * @cmd: command */ int bnx2x_cnic_notify(struct bnx2x *bp, int cmd); /** - * Provides cnic information for proper interrupt handling + * bnx2x_setup_cnic_irq_info - provides cnic with IRQ information * - * @param bp + * @bp: driver handle */ void bnx2x_setup_cnic_irq_info(struct bnx2x *bp); #endif /** - * Enable HW interrupts. + * bnx2x_int_enable - enable HW interrupts. * - * @param bp + * @bp: driver handle */ void bnx2x_int_enable(struct bnx2x *bp); /** - * Disable interrupts. This function ensures that there are no - * ISRs or SP DPCs (sp_task) are running after it returns. + * bnx2x_int_disable_sync - disable interrupts. + * + * @bp: driver handle + * @disable_hw: true, disable HW interrupts. * - * @param bp - * @param disable_hw if true, disable HW interrupts. + * This function ensures that there are no + * ISRs or SP DPCs (sp_task) are running after it returns. */ void bnx2x_int_disable_sync(struct bnx2x *bp, int disable_hw); /** - * Loads device firmware - * - * @param bp + * bnx2x_init_firmware - loads device firmware * - * @return int + * @bp: driver handle */ int bnx2x_init_firmware(struct bnx2x *bp); /** - * Init HW blocks according to current initialization stage: - * COMMON, PORT or FUNCTION. + * bnx2x_init_hw - init HW blocks according to current initialization stage. * - * @param bp - * @param load_code: COMMON, PORT or FUNCTION - * - * @return int + * @bp: driver handle + * @load_code: COMMON, PORT or FUNCTION */ int bnx2x_init_hw(struct bnx2x *bp, u32 load_code); /** - * Init driver internals: + * bnx2x_nic_init - init driver internals. + * + * @bp: driver handle + * @load_code: COMMON, PORT or FUNCTION + * + * Initializes: * - rings * - status blocks * - etc. - * - * @param bp - * @param load_code COMMON, PORT or FUNCTION */ void bnx2x_nic_init(struct bnx2x *bp, u32 load_code); /** - * Allocate driver's memory. - * - * @param bp + * bnx2x_alloc_mem - allocate driver's memory. * - * @return int + * @bp: driver handle */ int bnx2x_alloc_mem(struct bnx2x *bp); /** - * Release driver's memory. + * bnx2x_free_mem - release driver's memory. * - * @param bp + * @bp: driver handle */ void bnx2x_free_mem(struct bnx2x *bp); /** - * Setup eth Client. + * bnx2x_setup_client - setup eth client. * - * @param bp - * @param fp - * @param is_leading - * - * @return int + * @bp: driver handle + * @fp: pointer to fastpath structure + * @is_leading: boolean */ int bnx2x_setup_client(struct bnx2x *bp, struct bnx2x_fastpath *fp, int is_leading); /** - * Set number of queues according to mode - * - * @param bp + * bnx2x_set_num_queues - set number of queues according to mode. * + * @bp: driver handle */ void bnx2x_set_num_queues(struct bnx2x *bp); /** - * Cleanup chip internals: + * bnx2x_chip_cleanup - cleanup chip internals. + * + * @bp: driver handle + * @unload_mode: COMMON, PORT, FUNCTION + * * - Cleanup MAC configuration. - * - Close clients. + * - Closes clients. * - etc. - * - * @param bp - * @param unload_mode */ void bnx2x_chip_cleanup(struct bnx2x *bp, int unload_mode); /** - * Acquire HW lock. - * - * @param bp - * @param resource Resource bit which was locked + * bnx2x_acquire_hw_lock - acquire HW lock. * - * @return int + * @bp: driver handle + * @resource: resource bit which was locked */ int bnx2x_acquire_hw_lock(struct bnx2x *bp, u32 resource); /** - * Release HW lock. + * bnx2x_release_hw_lock - release HW lock. * - * @param bp driver handle - * @param resource Resource bit which was locked - * - * @return int + * @bp: driver handle + * @resource: resource bit which was locked */ int bnx2x_release_hw_lock(struct bnx2x *bp, u32 resource); /** - * Configure eth MAC address in the HW according to the value in - * netdev->dev_addr. + * bnx2x_set_eth_mac - configure eth MAC address in the HW + * + * @bp: driver handle + * @set: set or clear * - * @param bp driver handle - * @param set + * Configures according to the value in netdev->dev_addr. */ void bnx2x_set_eth_mac(struct bnx2x *bp, int set); #ifdef BCM_CNIC /** - * Set/Clear FIP MAC(s) at the next enties in the CAM after the ETH - * MAC(s). This function will wait until the ramdord completion - * returns. + * bnx2x_set_fip_eth_mac_addr - Set/Clear FIP MAC(s) * - * @param bp driver handle - * @param set set or clear the CAM entry + * @bp: driver handle + * @set: set or clear the CAM entry * - * @return 0 if cussess, -ENODEV if ramrod doesn't return. + * Used next enties in the CAM after the ETH MAC(s). + * This function will wait until the ramdord completion returns. + * Return 0 if cussess, -ENODEV if ramrod doesn't return. */ int bnx2x_set_fip_eth_mac_addr(struct bnx2x *bp, int set); /** - * Set/Clear ALL_ENODE mcast MAC. - * - * @param bp - * @param set + * bnx2x_set_all_enode_macs - Set/Clear ALL_ENODE mcast MAC. * - * @return int + * @bp: driver handle + * @set: set or clear */ int bnx2x_set_all_enode_macs(struct bnx2x *bp, int set); #endif /** - * Set MAC filtering configurations. + * bnx2x_set_rx_mode - set MAC filtering configurations. * - * @remarks called with netif_tx_lock from dev_mcast.c + * @dev: netdevice * - * @param dev net_device + * called with netif_tx_lock from dev_mcast.c */ void bnx2x_set_rx_mode(struct net_device *dev); /** - * Configure MAC filtering rules in a FW. + * bnx2x_set_storm_rx_mode - configure MAC filtering rules in a FW. * - * @param bp driver handle + * @bp: driver handle */ void bnx2x_set_storm_rx_mode(struct bnx2x *bp); @@ -324,63 +307,59 @@ bool bnx2x_reset_is_done(struct bnx2x *bp); void bnx2x_disable_close_the_gate(struct bnx2x *bp); /** - * Perform statistics handling according to event + * bnx2x_stats_handle - perform statistics handling according to event. * - * @param bp driver handle - * @param event bnx2x_stats_event + * @bp: driver handle + * @event: bnx2x_stats_event */ void bnx2x_stats_handle(struct bnx2x *bp, enum bnx2x_stats_event event); /** - * Handle ramrods completion + * bnx2x_sp_event - handle ramrods completion. * - * @param fp fastpath handle for the event - * @param rr_cqe eth_rx_cqe + * @fp: fastpath handle for the event + * @rr_cqe: eth_rx_cqe */ void bnx2x_sp_event(struct bnx2x_fastpath *fp, union eth_rx_cqe *rr_cqe); /** - * Init/halt function before/after sending - * CLIENT_SETUP/CFC_DEL for the first/last client. + * bnx2x_func_start - init function * - * @param bp + * @bp: driver handle * - * @return int + * Must be called before sending CLIENT_SETUP for the first client. */ int bnx2x_func_start(struct bnx2x *bp); /** - * Prepare ILT configurations according to current driver - * parameters. + * bnx2x_ilt_set_info - prepare ILT configurations. * - * @param bp + * @bp: driver handle */ void bnx2x_ilt_set_info(struct bnx2x *bp); /** - * Inintialize dcbx protocol + * bnx2x_dcbx_init - initialize dcbx protocol. * - * @param bp + * @bp: driver handle */ void bnx2x_dcbx_init(struct bnx2x *bp); /** - * Set power state to the requested value. Currently only D0 and - * D3hot are supported. + * bnx2x_set_power_state - set power state to the requested value. * - * @param bp - * @param state D0 or D3hot + * @bp: driver handle + * @state: required state D0 or D3hot * - * @return int + * Currently only D0 and D3hot are supported. */ int bnx2x_set_power_state(struct bnx2x *bp, pci_power_t state); /** - * Updates MAX part of MF configuration in HW - * (if required) + * bnx2x_update_max_mf_config - update MAX part of MF configuration in HW. * - * @param bp - * @param value + * @bp: driver handle + * @value: new value */ void bnx2x_update_max_mf_config(struct bnx2x *bp, u32 value); @@ -420,51 +399,51 @@ void bnx2x_netif_stop(struct bnx2x *bp, int disable_hw); void bnx2x_netif_start(struct bnx2x *bp); /** - * Fill msix_table, request vectors, update num_queues according - * to number of available vectors + * bnx2x_enable_msix - set msix configuration. * - * @param bp + * @bp: driver handle * - * @return int + * fills msix_table, requests vectors, updates num_queues + * according to number of available vectors. */ int bnx2x_enable_msix(struct bnx2x *bp); /** - * Request msi mode from OS, updated internals accordingly + * bnx2x_enable_msi - request msi mode from OS, updated internals accordingly * - * @param bp - * - * @return int + * @bp: driver handle */ int bnx2x_enable_msi(struct bnx2x *bp); /** - * NAPI callback + * bnx2x_poll - NAPI callback * - * @param napi - * @param budget + * @napi: napi structure + * @budget: * - * @return int */ int bnx2x_poll(struct napi_struct *napi, int budget); /** - * Allocate/release memories outsize main driver structure - * - * @param bp + * bnx2x_alloc_mem_bp - allocate memories outsize main driver structure * - * @return int + * @bp: driver handle */ int __devinit bnx2x_alloc_mem_bp(struct bnx2x *bp); + +/** + * bnx2x_free_mem_bp - release memories outsize main driver structure + * + * @bp: driver handle + */ void bnx2x_free_mem_bp(struct bnx2x *bp); /** - * Change mtu netdev callback + * bnx2x_change_mtu - change mtu netdev callback * - * @param dev - * @param new_mtu + * @dev: net device + * @new_mtu: requested mtu * - * @return int */ int bnx2x_change_mtu(struct net_device *dev, int new_mtu); @@ -472,29 +451,12 @@ u32 bnx2x_fix_features(struct net_device *dev, u32 features); int bnx2x_set_features(struct net_device *dev, u32 features); /** - * tx timeout netdev callback + * bnx2x_tx_timeout - tx timeout netdev callback * - * @param dev - * @param new_mtu - * - * @return int + * @dev: net device */ void bnx2x_tx_timeout(struct net_device *dev); -#ifdef BCM_VLAN -/** - * vlan rx register netdev callback - * - * @param dev - * @param new_mtu - * - * @return int - */ -void bnx2x_vlan_rx_register(struct net_device *dev, - struct vlan_group *vlgrp); - -#endif - static inline void bnx2x_update_fpsb_idx(struct bnx2x_fastpath *fp) { barrier(); /* status block is written to by the chip */ @@ -745,7 +707,7 @@ static inline int bnx2x_has_rx_work(struct bnx2x_fastpath *fp) /** * disables tx from stack point of view * - * @param bp + * @bp: driver handle */ static inline void bnx2x_tx_disable(struct bnx2x *bp) { @@ -1149,12 +1111,11 @@ void bnx2x_acquire_phy_lock(struct bnx2x *bp); void bnx2x_release_phy_lock(struct bnx2x *bp); /** - * Extracts MAX BW part from MF configuration. + * bnx2x_extract_max_cfg - extract MAX BW part from MF configuration. * - * @param bp - * @param mf_cfg + * @bp: driver handle + * @mf_cfg: MF configuration * - * @return u16 */ static inline u16 bnx2x_extract_max_cfg(struct bnx2x *bp, u32 mf_cfg) { diff --git a/drivers/net/bnx2x/bnx2x_dcb.c b/drivers/net/bnx2x/bnx2x_dcb.c index 3396ff2..0f83092 100644 --- a/drivers/net/bnx2x/bnx2x_dcb.c +++ b/drivers/net/bnx2x/bnx2x_dcb.c @@ -1079,12 +1079,6 @@ static void bnx2x_dcbx_get_num_pg_traf_type(struct bnx2x *bp, } } - -/******************************************************************************* - * Description: single priority group - * - * Return: - ******************************************************************************/ static void bnx2x_dcbx_ets_disabled_entry_data(struct bnx2x *bp, struct cos_help_data *cos_data, u32 pri_join_mask) @@ -1097,11 +1091,6 @@ static void bnx2x_dcbx_ets_disabled_entry_data(struct bnx2x *bp, cos_data->num_of_cos = 1; } -/******************************************************************************* - * Description: updating the cos bw - * - * Return: - ******************************************************************************/ static inline void bnx2x_dcbx_add_to_cos_bw(struct bnx2x *bp, struct cos_entry_help_data *data, u8 pg_bw) @@ -1112,11 +1101,6 @@ static inline void bnx2x_dcbx_add_to_cos_bw(struct bnx2x *bp, data->cos_bw += pg_bw; } -/******************************************************************************* - * Description: single priority group - * - * Return: - ******************************************************************************/ static void bnx2x_dcbx_separate_pauseable_from_non(struct bnx2x *bp, struct cos_help_data *cos_data, u32 *pg_pri_orginal_spread, @@ -1369,11 +1353,6 @@ static void bnx2x_dcbx_two_pg_to_cos_params( } } -/******************************************************************************* - * Description: Still - * - * Return: - ******************************************************************************/ static void bnx2x_dcbx_three_pg_to_cos_params( struct bnx2x *bp, struct pg_help_data *pg_help_data, @@ -1561,11 +1540,6 @@ static void bnx2x_dcbx_get_ets_pri_pg_tbl(struct bnx2x *bp, } } -/******************************************************************************* - * Description: Fill pfc_config struct that will be sent in DCBX start ramrod - * - * Return: - ******************************************************************************/ static void bnx2x_pfc_fw_struct_e2(struct bnx2x *bp) { struct flow_control_configuration *pfc_fw_cfg = NULL; diff --git a/drivers/net/bnx2x/bnx2x_dcb.h b/drivers/net/bnx2x/bnx2x_dcb.h index bb6e9a5b..bed369d 100644 --- a/drivers/net/bnx2x/bnx2x_dcb.h +++ b/drivers/net/bnx2x/bnx2x_dcb.h @@ -61,9 +61,6 @@ struct bnx2x_dcbx_port_params { #define BNX2X_DCBX_OVERWRITE_SETTINGS_ENABLE 1 #define BNX2X_DCBX_OVERWRITE_SETTINGS_INVALID (BNX2X_DCBX_CONFIG_INV_VALUE) -/******************************************************************************* - * LLDP protocol configuration parameters. - ******************************************************************************/ struct bnx2x_config_lldp_params { u32 overwrite_settings; u32 msg_tx_hold; @@ -83,9 +80,6 @@ struct bnx2x_admin_priority_app_table { u32 app_id; }; -/******************************************************************************* - * DCBX protocol configuration parameters. - ******************************************************************************/ struct bnx2x_config_dcbx_params { u32 overwrite_settings; u32 admin_dcbx_version; diff --git a/drivers/net/bnx2x/bnx2x_link.c b/drivers/net/bnx2x/bnx2x_link.c index 974ef2b..076e11f 100644 --- a/drivers/net/bnx2x/bnx2x_link.c +++ b/drivers/net/bnx2x/bnx2x_link.c @@ -385,7 +385,7 @@ u8 bnx2x_ets_strict(const struct link_params *params, const u8 strict_cos) return 0; } /******************************************************************/ -/* ETS section */ +/* PFC section */ /******************************************************************/ static void bnx2x_bmac2_get_pfc_stat(struct link_params *params, @@ -1301,14 +1301,12 @@ static u8 bnx2x_pbf_update(struct link_params *params, u32 flow_ctrl, return 0; } -/* - * get_emac_base - * - * @param cb - * @param mdc_mdio_access - * @param port +/** + * bnx2x_get_emac_base - retrive emac base address * - * @return u32 + * @bp: driver handle + * @mdc_mdio_access: access type + * @port: port id * * This function selects the MDC/MDIO access (through emac0 or * emac1) depend on the mdc_mdio_access, port, port swapped. Each diff --git a/drivers/net/bnx2x/bnx2x_main.c b/drivers/net/bnx2x/bnx2x_main.c index 0c31b91..2762edf 100644 --- a/drivers/net/bnx2x/bnx2x_main.c +++ b/drivers/net/bnx2x/bnx2x_main.c @@ -6035,14 +6035,14 @@ static int bnx2x_func_stop(struct bnx2x *bp) } /** - * Sets a MAC in a CAM for a few L2 Clients for E1x chips + * bnx2x_set_mac_addr_gen - set a MAC in a CAM for a few L2 Clients for E1x chips * - * @param bp driver descriptor - * @param set set or clear an entry (1 or 0) - * @param mac pointer to a buffer containing a MAC - * @param cl_bit_vec bit vector of clients to register a MAC for - * @param cam_offset offset in a CAM to use - * @param is_bcast is the set MAC a broadcast address (for E1 only) + * @bp: driver handle + * @set: set or clear an entry (1 or 0) + * @mac: pointer to a buffer containing a MAC + * @cl_bit_vec: bit vector of clients to register a MAC for + * @cam_offset: offset in a CAM to use + * @is_bcast: is the set MAC a broadcast address (for E1 only) */ static void bnx2x_set_mac_addr_gen(struct bnx2x *bp, int set, const u8 *mac, u32 cl_bit_vec, u8 cam_offset, @@ -6402,14 +6402,13 @@ void bnx2x_invalidate_e1h_mc_list(struct bnx2x *bp) #ifdef BCM_CNIC /** - * Set iSCSI MAC(s) at the next enties in the CAM after the ETH - * MAC(s). This function will wait until the ramdord completion - * returns. + * bnx2x_set_iscsi_eth_mac_addr - set iSCSI MAC(s). * - * @param bp driver handle - * @param set set or clear the CAM entry + * @bp: driver handle + * @set: set or clear the CAM entry * - * @return 0 if cussess, -ENODEV if ramrod doesn't return. + * This function will wait until the ramdord completion returns. + * Return 0 if success, -ENODEV if ramrod doesn't return. */ static int bnx2x_set_iscsi_eth_mac_addr(struct bnx2x *bp, int set) { @@ -6430,14 +6429,13 @@ static int bnx2x_set_iscsi_eth_mac_addr(struct bnx2x *bp, int set) } /** - * Set FCoE L2 MAC(s) at the next enties in the CAM after the - * ETH MAC(s). This function will wait until the ramdord - * completion returns. + * bnx2x_set_fip_eth_mac_addr - set FCoE L2 MAC(s) * - * @param bp driver handle - * @param set set or clear the CAM entry + * @bp: driver handle + * @set: set or clear the CAM entry * - * @return 0 if cussess, -ENODEV if ramrod doesn't return. + * This function will wait until the ramrod completion returns. + * Returns 0 if success, -ENODEV if ramrod doesn't return. */ int bnx2x_set_fip_eth_mac_addr(struct bnx2x *bp, int set) { @@ -6641,12 +6639,11 @@ static int bnx2x_setup_fw_client(struct bnx2x *bp, } /** - * Configure interrupt mode according to current configuration. - * In case of MSI-X it will also try to enable MSI-X. + * bnx2x_set_int_mode - configure interrupt mode * - * @param bp + * @bp: driver handle * - * @return int + * In case of MSI-X it will also try to enable MSI-X. */ static int __devinit bnx2x_set_int_mode(struct bnx2x *bp) { @@ -7230,10 +7227,11 @@ static void bnx2x_clp_reset_prep(struct bnx2x *bp, u32 *magic_val) MF_CFG_WR(bp, shared_mf_config.clp_mb, val | SHARED_MF_CLP_MAGIC); } -/* Restore the value of the `magic' bit. +/** + * bnx2x_clp_reset_done - restore the value of the `magic' bit. * - * @param pdev Device handle. - * @param magic_val Old value of the `magic' bit. + * @bp: driver handle + * @magic_val: old value of the `magic' bit. */ static void bnx2x_clp_reset_done(struct bnx2x *bp, u32 magic_val) { @@ -7244,10 +7242,12 @@ static void bnx2x_clp_reset_done(struct bnx2x *bp, u32 magic_val) } /** - * Prepares for MCP reset: takes care of CLP configurations. + * bnx2x_reset_mcp_prep - prepare for MCP reset. * - * @param bp - * @param magic_val Old value of 'magic' bit. + * @bp: driver handle + * @magic_val: old value of 'magic' bit. + * + * Takes care of CLP configurations. */ static void bnx2x_reset_mcp_prep(struct bnx2x *bp, u32 *magic_val) { @@ -7272,10 +7272,10 @@ static void bnx2x_reset_mcp_prep(struct bnx2x *bp, u32 *magic_val) #define MCP_TIMEOUT 5000 /* 5 seconds (in ms) */ #define MCP_ONE_TIMEOUT 100 /* 100 ms */ -/* Waits for MCP_ONE_TIMEOUT or MCP_ONE_TIMEOUT*10, - * depending on the HW type. +/** + * bnx2x_mcp_wait_one - wait for MCP_ONE_TIMEOUT * - * @param bp + * @bp: driver handle */ static inline void bnx2x_mcp_wait_one(struct bnx2x *bp) { -- cgit v0.10.2 From 1c5cae815d19ffe02bdfda1260949ef2b1806171 Mon Sep 17 00:00:00 2001 From: Jiri Pirko Date: Sat, 30 Apr 2011 01:21:32 +0000 Subject: net: call dev_alloc_name from register_netdevice Force dev_alloc_name() to be called from register_netdevice() by dev_get_valid_name(). That allows to remove multiple explicit dev_alloc_name() calls. The possibility to call dev_alloc_name in advance remains. This also fixes veth creation regresion caused by 84c49d8c3e4abefb0a41a77b25aa37ebe8d6b743 Signed-off-by: Jiri Pirko Signed-off-by: David S. Miller diff --git a/drivers/ieee802154/fakehard.c b/drivers/ieee802154/fakehard.c index d9d0e13..a5a49a1 100644 --- a/drivers/ieee802154/fakehard.c +++ b/drivers/ieee802154/fakehard.c @@ -393,16 +393,6 @@ static int __devinit ieee802154fake_probe(struct platform_device *pdev) priv = netdev_priv(dev); priv->phy = phy; - /* - * If the name is a format string the caller wants us to do a - * name allocation. - */ - if (strchr(dev->name, '%')) { - err = dev_alloc_name(dev, dev->name); - if (err < 0) - goto out; - } - wpan_phy_set_dev(phy, &pdev->dev); SET_NETDEV_DEV(dev, &phy->dev); diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index 22bd03b..9a5feaf 100644 --- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c @@ -4917,8 +4917,9 @@ int bond_create(struct net *net, const char *name) rtnl_lock(); - bond_dev = alloc_netdev_mq(sizeof(struct bonding), name ? name : "", - bond_setup, tx_queues); + bond_dev = alloc_netdev_mq(sizeof(struct bonding), + name ? name : "bond%d", + bond_setup, tx_queues); if (!bond_dev) { pr_err("%s: eek! can't alloc netdev!\n", name); rtnl_unlock(); @@ -4928,26 +4929,10 @@ int bond_create(struct net *net, const char *name) dev_net_set(bond_dev, net); bond_dev->rtnl_link_ops = &bond_link_ops; - if (!name) { - res = dev_alloc_name(bond_dev, "bond%d"); - if (res < 0) - goto out; - } else { - /* - * If we're given a name to register - * we need to ensure that its not already - * registered - */ - res = -EEXIST; - if (__dev_get_by_name(net, name) != NULL) - goto out; - } - res = register_netdevice(bond_dev); netif_carrier_off(bond_dev); -out: rtnl_unlock(); if (res < 0) bond_destructor(bond_dev); diff --git a/drivers/net/dummy.c b/drivers/net/dummy.c index ff2d29b..39cf9b9 100644 --- a/drivers/net/dummy.c +++ b/drivers/net/dummy.c @@ -168,10 +168,6 @@ static int __init dummy_init_one(void) if (!dev_dummy) return -ENOMEM; - err = dev_alloc_name(dev_dummy, dev_dummy->name); - if (err < 0) - goto err; - dev_dummy->rtnl_link_ops = &dummy_link_ops; err = register_netdevice(dev_dummy); if (err < 0) diff --git a/drivers/net/hamradio/bpqether.c b/drivers/net/hamradio/bpqether.c index 8931168..18d8aff 100644 --- a/drivers/net/hamradio/bpqether.c +++ b/drivers/net/hamradio/bpqether.c @@ -516,10 +516,6 @@ static int bpq_new_device(struct net_device *edev) memcpy(bpq->dest_addr, bcast_addr, sizeof(bpq_eth_addr)); memcpy(bpq->acpt_addr, bcast_addr, sizeof(bpq_eth_addr)); - err = dev_alloc_name(ndev, ndev->name); - if (err < 0) - goto error; - err = register_netdevice(ndev); if (err) goto error; diff --git a/drivers/net/ifb.c b/drivers/net/ifb.c index e07d487..4fecaed6 100644 --- a/drivers/net/ifb.c +++ b/drivers/net/ifb.c @@ -233,10 +233,6 @@ static int __init ifb_init_one(int index) if (!dev_ifb) return -ENOMEM; - err = dev_alloc_name(dev_ifb, dev_ifb->name); - if (err < 0) - goto err; - dev_ifb->rtnl_link_ops = &ifb_link_ops; err = register_netdevice(dev_ifb); if (err < 0) diff --git a/drivers/net/tun.c b/drivers/net/tun.c index 0636f70..74e9405 100644 --- a/drivers/net/tun.c +++ b/drivers/net/tun.c @@ -1099,12 +1099,6 @@ static int tun_set_iff(struct net *net, struct file *file, struct ifreq *ifr) tun_net_init(dev); - if (strchr(dev->name, '%')) { - err = dev_alloc_name(dev, dev->name); - if (err < 0) - goto err_free_sk; - } - dev->hw_features = NETIF_F_SG | NETIF_F_FRAGLIST | TUN_USER_FEATURES; dev->features = dev->hw_features; diff --git a/drivers/net/wan/dlci.c b/drivers/net/wan/dlci.c index 1481a44..21b104d 100644 --- a/drivers/net/wan/dlci.c +++ b/drivers/net/wan/dlci.c @@ -341,10 +341,6 @@ static int dlci_add(struct dlci_add *dlci) } } - err = dev_alloc_name(master, master->name); - if (err < 0) - goto err2; - *(short *)(master->dev_addr) = dlci->dlci; dlp = netdev_priv(master); diff --git a/drivers/net/wan/hdlc_fr.c b/drivers/net/wan/hdlc_fr.c index 0edb535..fc433f2 100644 --- a/drivers/net/wan/hdlc_fr.c +++ b/drivers/net/wan/hdlc_fr.c @@ -1070,7 +1070,7 @@ static int fr_add_pvc(struct net_device *frad, unsigned int dlci, int type) hdlc_device *hdlc = dev_to_hdlc(frad); pvc_device *pvc; struct net_device *dev; - int result, used; + int used; if ((pvc = add_pvc(frad, dlci)) == NULL) { printk(KERN_WARNING "%s: Memory squeeze on fr_add_pvc()\n", @@ -1106,13 +1106,6 @@ static int fr_add_pvc(struct net_device *frad, unsigned int dlci, int type) dev->tx_queue_len = 0; dev->ml_priv = pvc; - result = dev_alloc_name(dev, dev->name); - if (result < 0) { - free_netdev(dev); - delete_unused_pvcs(hdlc); - return result; - } - if (register_netdevice(dev) != 0) { free_netdev(dev); delete_unused_pvcs(hdlc); diff --git a/drivers/net/wan/lapbether.c b/drivers/net/wan/lapbether.c index 7f5bb91..eec463f 100644 --- a/drivers/net/wan/lapbether.c +++ b/drivers/net/wan/lapbether.c @@ -338,10 +338,6 @@ static int lapbeth_new_device(struct net_device *dev) dev_hold(dev); lapbeth->ethdev = dev; - rc = dev_alloc_name(ndev, ndev->name); - if (rc < 0) - goto fail; - rc = -EIO; if (register_netdevice(ndev)) goto fail; diff --git a/drivers/net/wireless/hostap/hostap_main.c b/drivers/net/wireless/hostap/hostap_main.c index 1d9aed6..d508482 100644 --- a/drivers/net/wireless/hostap/hostap_main.c +++ b/drivers/net/wireless/hostap/hostap_main.c @@ -79,13 +79,8 @@ struct net_device * hostap_add_interface(struct local_info *local, if (!rtnl_locked) rtnl_lock(); - ret = 0; - if (strchr(dev->name, '%')) - ret = dev_alloc_name(dev, dev->name); - SET_NETDEV_DEV(dev, mdev->dev.parent); - if (ret >= 0) - ret = register_netdevice(dev); + ret = register_netdevice(dev); if (!rtnl_locked) rtnl_unlock(); diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c index f4f4257..9d4a40e 100644 --- a/drivers/net/wireless/mac80211_hwsim.c +++ b/drivers/net/wireless/mac80211_hwsim.c @@ -1515,19 +1515,10 @@ static int __init init_mac80211_hwsim(void) if (hwsim_mon == NULL) goto failed; - rtnl_lock(); - - err = dev_alloc_name(hwsim_mon, hwsim_mon->name); + err = register_netdev(hwsim_mon); if (err < 0) goto failed_mon; - - err = register_netdevice(hwsim_mon); - if (err < 0) - goto failed_mon; - - rtnl_unlock(); - return 0; failed_mon: diff --git a/drivers/net/wireless/mwifiex/main.c b/drivers/net/wireless/mwifiex/main.c index c597188..d16cea7 100644 --- a/drivers/net/wireless/mwifiex/main.c +++ b/drivers/net/wireless/mwifiex/main.c @@ -706,10 +706,6 @@ static struct mwifiex_private *mwifiex_add_interface( dev_err(adapter->dev, "no memory available for netdevice\n"); goto error; } - if (dev_alloc_name(dev, dev->name)) { - dev_err(adapter->dev, "unable to alloc name for netdevice\n"); - goto error; - } if (mwifiex_register_cfg80211(dev, adapter->priv[bss_index]->curr_addr, adapter->priv[bss_index]) != 0) { diff --git a/drivers/s390/net/netiucv.c b/drivers/s390/net/netiucv.c index b6a6356..3251333 100644 --- a/drivers/s390/net/netiucv.c +++ b/drivers/s390/net/netiucv.c @@ -1994,8 +1994,6 @@ static struct net_device *netiucv_init_netdevice(char *username) netiucv_setup_netdevice); if (!dev) return NULL; - if (dev_alloc_name(dev, dev->name) < 0) - goto out_netdev; privptr = netdev_priv(dev); privptr->fsm = init_fsm("netiucvdev", dev_state_names, diff --git a/net/core/dev.c b/net/core/dev.c index e95dc30..3b79bad 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -948,7 +948,7 @@ int dev_alloc_name(struct net_device *dev, const char *name) } EXPORT_SYMBOL(dev_alloc_name); -static int dev_get_valid_name(struct net_device *dev, const char *name, bool fmt) +static int dev_get_valid_name(struct net_device *dev, const char *name) { struct net *net; @@ -958,7 +958,7 @@ static int dev_get_valid_name(struct net_device *dev, const char *name, bool fmt if (!dev_valid_name(name)) return -EINVAL; - if (fmt && strchr(name, '%')) + if (strchr(name, '%')) return dev_alloc_name(dev, name); else if (__dev_get_by_name(net, name)) return -EEXIST; @@ -995,7 +995,7 @@ int dev_change_name(struct net_device *dev, const char *newname) memcpy(oldname, dev->name, IFNAMSIZ); - err = dev_get_valid_name(dev, newname, 1); + err = dev_get_valid_name(dev, newname); if (err < 0) return err; @@ -5420,8 +5420,8 @@ int register_netdevice(struct net_device *dev) } } - ret = dev_get_valid_name(dev, dev->name, 0); - if (ret) + ret = dev_get_valid_name(dev, dev->name); + if (ret < 0) goto err_uninit; dev->ifindex = dev_new_index(net); @@ -5562,19 +5562,7 @@ int register_netdev(struct net_device *dev) int err; rtnl_lock(); - - /* - * If the name is a format string the caller wants us to do a - * name allocation. - */ - if (strchr(dev->name, '%')) { - err = dev_alloc_name(dev, dev->name); - if (err < 0) - goto out; - } - err = register_netdevice(dev); -out: rtnl_unlock(); return err; } @@ -6056,7 +6044,7 @@ int dev_change_net_namespace(struct net_device *dev, struct net *net, const char /* We get here if we can't use the current device name */ if (!pat) goto out; - if (dev_get_valid_name(dev, pat, 1)) + if (dev_get_valid_name(dev, pat) < 0) goto out; } diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c index 29633125..5a160f4 100644 --- a/net/core/rtnetlink.c +++ b/net/core/rtnetlink.c @@ -1572,12 +1572,6 @@ struct net_device *rtnl_create_link(struct net *src_net, struct net *net, dev->rtnl_link_state = RTNL_LINK_INITIALIZING; dev->real_num_tx_queues = real_num_queues; - if (strchr(dev->name, '%')) { - err = dev_alloc_name(dev, dev->name); - if (err < 0) - goto err_free; - } - if (tb[IFLA_MTU]) dev->mtu = nla_get_u32(tb[IFLA_MTU]); if (tb[IFLA_ADDRESS]) @@ -1597,8 +1591,6 @@ struct net_device *rtnl_create_link(struct net *src_net, struct net *net, return dev; -err_free: - free_netdev(dev); err: return ERR_PTR(err); } diff --git a/net/ipv4/ip_gre.c b/net/ipv4/ip_gre.c index 10e9b5a..8871067 100644 --- a/net/ipv4/ip_gre.c +++ b/net/ipv4/ip_gre.c @@ -413,11 +413,6 @@ static struct ip_tunnel *ipgre_tunnel_locate(struct net *net, dev_net_set(dev, net); - if (strchr(name, '%')) { - if (dev_alloc_name(dev, name) < 0) - goto failed_free; - } - nt = netdev_priv(dev); nt->parms = *parms; dev->rtnl_link_ops = &ipgre_link_ops; diff --git a/net/ipv4/ipip.c b/net/ipv4/ipip.c index bfa0b98..378b20b 100644 --- a/net/ipv4/ipip.c +++ b/net/ipv4/ipip.c @@ -276,11 +276,6 @@ static struct ip_tunnel * ipip_tunnel_locate(struct net *net, dev_net_set(dev, net); - if (strchr(name, '%')) { - if (dev_alloc_name(dev, name) < 0) - goto failed_free; - } - nt = netdev_priv(dev); nt->parms = *parms; diff --git a/net/ipv6/ip6_tunnel.c b/net/ipv6/ip6_tunnel.c index 3dff27c..36c2842 100644 --- a/net/ipv6/ip6_tunnel.c +++ b/net/ipv6/ip6_tunnel.c @@ -280,11 +280,6 @@ static struct ip6_tnl *ip6_tnl_create(struct net *net, struct ip6_tnl_parm *p) dev_net_set(dev, net); - if (strchr(name, '%')) { - if (dev_alloc_name(dev, name) < 0) - goto failed_free; - } - t = netdev_priv(dev); t->parms = *p; err = ip6_tnl_dev_init(dev); diff --git a/net/ipv6/sit.c b/net/ipv6/sit.c index c53abcf..a6a32b3 100644 --- a/net/ipv6/sit.c +++ b/net/ipv6/sit.c @@ -250,11 +250,6 @@ static struct ip_tunnel *ipip6_tunnel_locate(struct net *net, dev_net_set(dev, net); - if (strchr(name, '%')) { - if (dev_alloc_name(dev, name) < 0) - goto failed_free; - } - nt = netdev_priv(dev); nt->parms = *parms; diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c index 4054399..80c29d6 100644 --- a/net/mac80211/iface.c +++ b/net/mac80211/iface.c @@ -1144,10 +1144,6 @@ int ieee80211_if_add(struct ieee80211_local *local, const char *name, + IEEE80211_ENCRYPT_HEADROOM; ndev->needed_tailroom = IEEE80211_ENCRYPT_TAILROOM; - ret = dev_alloc_name(ndev, ndev->name); - if (ret < 0) - goto fail; - ieee80211_assign_perm_addr(local, ndev, type); memcpy(ndev->dev_addr, ndev->perm_addr, ETH_ALEN); SET_NETDEV_DEV(ndev, wiphy_dev(local->hw.wiphy)); -- cgit v0.10.2 From 87e9af6cc67d842cd92b52b81f3f14e665e7ab05 Mon Sep 17 00:00:00 2001 From: Kurt Van Dijck Date: Mon, 2 May 2011 04:50:48 +0000 Subject: can: fix SJA1000 dlc for RTR packets RTR frames do have a valid data length code on CAN. The driver for SJA1000 did not handle that situation properly. Signed-off-by: Kurt Van Dijck Acked-by: Marc Kleine-Budde Signed-off-by: David S. Miller diff --git a/drivers/net/can/sja1000/sja1000.c b/drivers/net/can/sja1000/sja1000.c index a358ea9..f501bba 100644 --- a/drivers/net/can/sja1000/sja1000.c +++ b/drivers/net/can/sja1000/sja1000.c @@ -346,10 +346,10 @@ static void sja1000_rx(struct net_device *dev) | (priv->read_reg(priv, REG_ID2) >> 5); } + cf->can_dlc = get_can_dlc(fi & 0x0F); if (fi & FI_RTR) { id |= CAN_RTR_FLAG; } else { - cf->can_dlc = get_can_dlc(fi & 0x0F); for (i = 0; i < cf->can_dlc; i++) cf->data[i] = priv->read_reg(priv, dreg++); } -- cgit v0.10.2 From 228e548e602061b08ee8e8966f567c12aa079682 Mon Sep 17 00:00:00 2001 From: Anton Blanchard Date: Mon, 2 May 2011 20:21:35 +0000 Subject: net: Add sendmmsg socket system call This patch adds a multiple message send syscall and is the send version of the existing recvmmsg syscall. This is heavily based on the patch by Arnaldo that added recvmmsg. I wrote a microbenchmark to test the performance gains of using this new syscall: http://ozlabs.org/~anton/junkcode/sendmmsg_test.c The test was run on a ppc64 box with a 10 Gbit network card. The benchmark can send both UDP and RAW ethernet packets. 64B UDP batch pkts/sec 1 804570 2 872800 (+ 8 %) 4 916556 (+14 %) 8 939712 (+17 %) 16 952688 (+18 %) 32 956448 (+19 %) 64 964800 (+20 %) 64B raw socket batch pkts/sec 1 1201449 2 1350028 (+12 %) 4 1461416 (+22 %) 8 1513080 (+26 %) 16 1541216 (+28 %) 32 1553440 (+29 %) 64 1557888 (+30 %) We see a 20% improvement in throughput on UDP send and 30% on raw socket send. [ Add sparc syscall entries. -DaveM ] Signed-off-by: Anton Blanchard Signed-off-by: David S. Miller diff --git a/arch/powerpc/include/asm/systbl.h b/arch/powerpc/include/asm/systbl.h index 60f64b1..8489d37 100644 --- a/arch/powerpc/include/asm/systbl.h +++ b/arch/powerpc/include/asm/systbl.h @@ -352,3 +352,4 @@ SYSCALL_SPU(name_to_handle_at) COMPAT_SYS_SPU(open_by_handle_at) COMPAT_SYS_SPU(clock_adjtime) SYSCALL_SPU(syncfs) +COMPAT_SYS_SPU(sendmmsg) diff --git a/arch/powerpc/include/asm/unistd.h b/arch/powerpc/include/asm/unistd.h index 3c21564..6d23c81 100644 --- a/arch/powerpc/include/asm/unistd.h +++ b/arch/powerpc/include/asm/unistd.h @@ -371,10 +371,11 @@ #define __NR_open_by_handle_at 346 #define __NR_clock_adjtime 347 #define __NR_syncfs 348 +#define __NR_sendmmsg 349 #ifdef __KERNEL__ -#define __NR_syscalls 349 +#define __NR_syscalls 350 #define __NR__exit __NR_exit #define NR_syscalls __NR_syscalls diff --git a/arch/sparc/include/asm/unistd.h b/arch/sparc/include/asm/unistd.h index 9d897b6..c5387ed 100644 --- a/arch/sparc/include/asm/unistd.h +++ b/arch/sparc/include/asm/unistd.h @@ -404,8 +404,9 @@ #define __NR_open_by_handle_at 333 #define __NR_clock_adjtime 334 #define __NR_syncfs 335 +#define __NR_sendmmsg 336 -#define NR_syscalls 336 +#define NR_syscalls 337 #ifdef __32bit_syscall_numbers__ /* Sparc 32-bit only has the "setresuid32", "getresuid32" variants, diff --git a/arch/sparc/kernel/systbls_32.S b/arch/sparc/kernel/systbls_32.S index 47ac73c..332c83f 100644 --- a/arch/sparc/kernel/systbls_32.S +++ b/arch/sparc/kernel/systbls_32.S @@ -84,4 +84,4 @@ sys_call_table: /*320*/ .long sys_dup3, sys_pipe2, sys_inotify_init1, sys_accept4, sys_preadv /*325*/ .long sys_pwritev, sys_rt_tgsigqueueinfo, sys_perf_event_open, sys_recvmmsg, sys_fanotify_init /*330*/ .long sys_fanotify_mark, sys_prlimit64, sys_name_to_handle_at, sys_open_by_handle_at, sys_clock_adjtime -/*335*/ .long sys_syncfs +/*335*/ .long sys_syncfs, sys_sendmmsg diff --git a/arch/sparc/kernel/systbls_64.S b/arch/sparc/kernel/systbls_64.S index 4f3170c..43887ca 100644 --- a/arch/sparc/kernel/systbls_64.S +++ b/arch/sparc/kernel/systbls_64.S @@ -85,7 +85,7 @@ sys_call_table32: /*320*/ .word sys_dup3, sys_pipe2, sys_inotify_init1, sys_accept4, compat_sys_preadv .word compat_sys_pwritev, compat_sys_rt_tgsigqueueinfo, sys_perf_event_open, compat_sys_recvmmsg, sys_fanotify_init /*330*/ .word sys32_fanotify_mark, sys_prlimit64, sys_name_to_handle_at, compat_sys_open_by_handle_at, compat_sys_clock_adjtime - .word sys_syncfs + .word sys_syncfs, compat_sys_sendmmsg #endif /* CONFIG_COMPAT */ @@ -162,4 +162,4 @@ sys_call_table: /*320*/ .word sys_dup3, sys_pipe2, sys_inotify_init1, sys_accept4, sys_preadv .word sys_pwritev, sys_rt_tgsigqueueinfo, sys_perf_event_open, sys_recvmmsg, sys_fanotify_init /*330*/ .word sys_fanotify_mark, sys_prlimit64, sys_name_to_handle_at, sys_open_by_handle_at, sys_clock_adjtime - .word sys_syncfs + .word sys_syncfs, sys_sendmmsg diff --git a/arch/x86/ia32/ia32entry.S b/arch/x86/ia32/ia32entry.S index 849a9d2..95f5826 100644 --- a/arch/x86/ia32/ia32entry.S +++ b/arch/x86/ia32/ia32entry.S @@ -848,4 +848,5 @@ ia32_sys_call_table: .quad compat_sys_open_by_handle_at .quad compat_sys_clock_adjtime .quad sys_syncfs + .quad compat_sys_sendmmsg /* 345 */ ia32_syscall_end: diff --git a/arch/x86/include/asm/unistd_32.h b/arch/x86/include/asm/unistd_32.h index a755ef5..fb6a625 100644 --- a/arch/x86/include/asm/unistd_32.h +++ b/arch/x86/include/asm/unistd_32.h @@ -350,10 +350,11 @@ #define __NR_open_by_handle_at 342 #define __NR_clock_adjtime 343 #define __NR_syncfs 344 +#define __NR_sendmmsg 345 #ifdef __KERNEL__ -#define NR_syscalls 345 +#define NR_syscalls 346 #define __ARCH_WANT_IPC_PARSE_VERSION #define __ARCH_WANT_OLD_READDIR diff --git a/arch/x86/include/asm/unistd_64.h b/arch/x86/include/asm/unistd_64.h index 160fa76..79f90eb 100644 --- a/arch/x86/include/asm/unistd_64.h +++ b/arch/x86/include/asm/unistd_64.h @@ -677,6 +677,8 @@ __SYSCALL(__NR_open_by_handle_at, sys_open_by_handle_at) __SYSCALL(__NR_clock_adjtime, sys_clock_adjtime) #define __NR_syncfs 306 __SYSCALL(__NR_syncfs, sys_syncfs) +#define __NR_sendmmsg 307 +__SYSCALL(__NR_sendmmsg, sys_sendmmsg) #ifndef __NO_STUBS #define __ARCH_WANT_OLD_READDIR diff --git a/arch/x86/kernel/syscall_table_32.S b/arch/x86/kernel/syscall_table_32.S index abce34d..32cbffb 100644 --- a/arch/x86/kernel/syscall_table_32.S +++ b/arch/x86/kernel/syscall_table_32.S @@ -344,3 +344,4 @@ ENTRY(sys_call_table) .long sys_open_by_handle_at .long sys_clock_adjtime .long sys_syncfs + .long sys_sendmmsg /* 345 */ diff --git a/include/linux/net.h b/include/linux/net.h index 94de83c..1da55e9 100644 --- a/include/linux/net.h +++ b/include/linux/net.h @@ -42,6 +42,7 @@ #define SYS_RECVMSG 17 /* sys_recvmsg(2) */ #define SYS_ACCEPT4 18 /* sys_accept4(2) */ #define SYS_RECVMMSG 19 /* sys_recvmmsg(2) */ +#define SYS_SENDMMSG 20 /* sys_sendmmsg(2) */ typedef enum { SS_FREE = 0, /* not allocated */ diff --git a/include/linux/socket.h b/include/linux/socket.h index d2b5e98..4ef98e4 100644 --- a/include/linux/socket.h +++ b/include/linux/socket.h @@ -333,5 +333,7 @@ struct timespec; extern int __sys_recvmmsg(int fd, struct mmsghdr __user *mmsg, unsigned int vlen, unsigned int flags, struct timespec *timeout); +extern int __sys_sendmmsg(int fd, struct mmsghdr __user *mmsg, + unsigned int vlen, unsigned int flags); #endif /* not kernel and not glibc */ #endif /* _LINUX_SOCKET_H */ diff --git a/include/linux/syscalls.h b/include/linux/syscalls.h index 83ecc17..ab71447 100644 --- a/include/linux/syscalls.h +++ b/include/linux/syscalls.h @@ -610,6 +610,8 @@ asmlinkage long sys_send(int, void __user *, size_t, unsigned); asmlinkage long sys_sendto(int, void __user *, size_t, unsigned, struct sockaddr __user *, int); asmlinkage long sys_sendmsg(int fd, struct msghdr __user *msg, unsigned flags); +asmlinkage long sys_sendmmsg(int fd, struct mmsghdr __user *msg, + unsigned int vlen, unsigned flags); asmlinkage long sys_recv(int, void __user *, size_t, unsigned); asmlinkage long sys_recvfrom(int, void __user *, size_t, unsigned, struct sockaddr __user *, int __user *); diff --git a/include/net/compat.h b/include/net/compat.h index 28d5428..9ee75ed 100644 --- a/include/net/compat.h +++ b/include/net/compat.h @@ -43,6 +43,8 @@ extern int compat_sock_get_timestampns(struct sock *, struct timespec __user *); extern int get_compat_msghdr(struct msghdr *, struct compat_msghdr __user *); extern int verify_compat_iovec(struct msghdr *, struct iovec *, struct sockaddr *, int); extern asmlinkage long compat_sys_sendmsg(int,struct compat_msghdr __user *,unsigned); +extern asmlinkage long compat_sys_sendmmsg(int, struct compat_mmsghdr __user *, + unsigned, unsigned); extern asmlinkage long compat_sys_recvmsg(int,struct compat_msghdr __user *,unsigned); extern asmlinkage long compat_sys_recvmmsg(int, struct compat_mmsghdr __user *, unsigned, unsigned, diff --git a/kernel/sys_ni.c b/kernel/sys_ni.c index 25cc41c..97e966f 100644 --- a/kernel/sys_ni.c +++ b/kernel/sys_ni.c @@ -46,7 +46,9 @@ cond_syscall(sys_getsockopt); cond_syscall(compat_sys_getsockopt); cond_syscall(sys_shutdown); cond_syscall(sys_sendmsg); +cond_syscall(sys_sendmmsg); cond_syscall(compat_sys_sendmsg); +cond_syscall(compat_sys_sendmmsg); cond_syscall(sys_recvmsg); cond_syscall(sys_recvmmsg); cond_syscall(compat_sys_recvmsg); diff --git a/net/compat.c b/net/compat.c index 3649d58..c578d93 100644 --- a/net/compat.c +++ b/net/compat.c @@ -722,11 +722,11 @@ EXPORT_SYMBOL(compat_mc_getsockopt); /* Argument list sizes for compat_sys_socketcall */ #define AL(x) ((x) * sizeof(u32)) -static unsigned char nas[20] = { +static unsigned char nas[21] = { AL(0), AL(3), AL(3), AL(3), AL(2), AL(3), AL(3), AL(3), AL(4), AL(4), AL(4), AL(6), AL(6), AL(2), AL(5), AL(5), AL(3), AL(3), - AL(4), AL(5) + AL(4), AL(5), AL(4) }; #undef AL @@ -735,6 +735,13 @@ asmlinkage long compat_sys_sendmsg(int fd, struct compat_msghdr __user *msg, uns return sys_sendmsg(fd, (struct msghdr __user *)msg, flags | MSG_CMSG_COMPAT); } +asmlinkage long compat_sys_sendmmsg(int fd, struct compat_mmsghdr __user *mmsg, + unsigned vlen, unsigned int flags) +{ + return __sys_sendmmsg(fd, (struct mmsghdr __user *)mmsg, vlen, + flags | MSG_CMSG_COMPAT); +} + asmlinkage long compat_sys_recvmsg(int fd, struct compat_msghdr __user *msg, unsigned int flags) { return sys_recvmsg(fd, (struct msghdr __user *)msg, flags | MSG_CMSG_COMPAT); @@ -780,7 +787,7 @@ asmlinkage long compat_sys_socketcall(int call, u32 __user *args) u32 a[6]; u32 a0, a1; - if (call < SYS_SOCKET || call > SYS_RECVMMSG) + if (call < SYS_SOCKET || call > SYS_SENDMMSG) return -EINVAL; if (copy_from_user(a, args, nas[call])) return -EFAULT; @@ -839,6 +846,9 @@ asmlinkage long compat_sys_socketcall(int call, u32 __user *args) case SYS_SENDMSG: ret = compat_sys_sendmsg(a0, compat_ptr(a1), a[2]); break; + case SYS_SENDMMSG: + ret = compat_sys_sendmmsg(a0, compat_ptr(a1), a[2], a[3]); + break; case SYS_RECVMSG: ret = compat_sys_recvmsg(a0, compat_ptr(a1), a[2]); break; diff --git a/net/socket.c b/net/socket.c index d25f5a9..ed50255 100644 --- a/net/socket.c +++ b/net/socket.c @@ -551,11 +551,10 @@ int sock_tx_timestamp(struct sock *sk, __u8 *tx_flags) } EXPORT_SYMBOL(sock_tx_timestamp); -static inline int __sock_sendmsg(struct kiocb *iocb, struct socket *sock, - struct msghdr *msg, size_t size) +static inline int __sock_sendmsg_nosec(struct kiocb *iocb, struct socket *sock, + struct msghdr *msg, size_t size) { struct sock_iocb *si = kiocb_to_siocb(iocb); - int err; sock_update_classid(sock->sk); @@ -564,13 +563,17 @@ static inline int __sock_sendmsg(struct kiocb *iocb, struct socket *sock, si->msg = msg; si->size = size; - err = security_socket_sendmsg(sock, msg, size); - if (err) - return err; - return sock->ops->sendmsg(iocb, sock, msg, size); } +static inline int __sock_sendmsg(struct kiocb *iocb, struct socket *sock, + struct msghdr *msg, size_t size) +{ + int err = security_socket_sendmsg(sock, msg, size); + + return err ?: __sock_sendmsg_nosec(iocb, sock, msg, size); +} + int sock_sendmsg(struct socket *sock, struct msghdr *msg, size_t size) { struct kiocb iocb; @@ -586,6 +589,20 @@ int sock_sendmsg(struct socket *sock, struct msghdr *msg, size_t size) } EXPORT_SYMBOL(sock_sendmsg); +int sock_sendmsg_nosec(struct socket *sock, struct msghdr *msg, size_t size) +{ + struct kiocb iocb; + struct sock_iocb siocb; + int ret; + + init_sync_kiocb(&iocb, NULL); + iocb.private = &siocb; + ret = __sock_sendmsg_nosec(&iocb, sock, msg, size); + if (-EIOCBQUEUED == ret) + ret = wait_on_sync_kiocb(&iocb); + return ret; +} + int kernel_sendmsg(struct socket *sock, struct msghdr *msg, struct kvec *vec, size_t num, size_t size) { @@ -1863,57 +1880,47 @@ SYSCALL_DEFINE2(shutdown, int, fd, int, how) #define COMPAT_NAMELEN(msg) COMPAT_MSG(msg, msg_namelen) #define COMPAT_FLAGS(msg) COMPAT_MSG(msg, msg_flags) -/* - * BSD sendmsg interface - */ - -SYSCALL_DEFINE3(sendmsg, int, fd, struct msghdr __user *, msg, unsigned, flags) +static int __sys_sendmsg(struct socket *sock, struct msghdr __user *msg, + struct msghdr *msg_sys, unsigned flags, int nosec) { struct compat_msghdr __user *msg_compat = (struct compat_msghdr __user *)msg; - struct socket *sock; struct sockaddr_storage address; struct iovec iovstack[UIO_FASTIOV], *iov = iovstack; unsigned char ctl[sizeof(struct cmsghdr) + 20] __attribute__ ((aligned(sizeof(__kernel_size_t)))); /* 20 is size of ipv6_pktinfo */ unsigned char *ctl_buf = ctl; - struct msghdr msg_sys; int err, ctl_len, iov_size, total_len; - int fput_needed; err = -EFAULT; if (MSG_CMSG_COMPAT & flags) { - if (get_compat_msghdr(&msg_sys, msg_compat)) + if (get_compat_msghdr(msg_sys, msg_compat)) return -EFAULT; - } else if (copy_from_user(&msg_sys, msg, sizeof(struct msghdr))) + } else if (copy_from_user(msg_sys, msg, sizeof(struct msghdr))) return -EFAULT; - sock = sockfd_lookup_light(fd, &err, &fput_needed); - if (!sock) - goto out; - /* do not move before msg_sys is valid */ err = -EMSGSIZE; - if (msg_sys.msg_iovlen > UIO_MAXIOV) - goto out_put; + if (msg_sys->msg_iovlen > UIO_MAXIOV) + goto out; /* Check whether to allocate the iovec area */ err = -ENOMEM; - iov_size = msg_sys.msg_iovlen * sizeof(struct iovec); - if (msg_sys.msg_iovlen > UIO_FASTIOV) { + iov_size = msg_sys->msg_iovlen * sizeof(struct iovec); + if (msg_sys->msg_iovlen > UIO_FASTIOV) { iov = sock_kmalloc(sock->sk, iov_size, GFP_KERNEL); if (!iov) - goto out_put; + goto out; } /* This will also move the address data into kernel space */ if (MSG_CMSG_COMPAT & flags) { - err = verify_compat_iovec(&msg_sys, iov, + err = verify_compat_iovec(msg_sys, iov, (struct sockaddr *)&address, VERIFY_READ); } else - err = verify_iovec(&msg_sys, iov, + err = verify_iovec(msg_sys, iov, (struct sockaddr *)&address, VERIFY_READ); if (err < 0) @@ -1922,17 +1929,17 @@ SYSCALL_DEFINE3(sendmsg, int, fd, struct msghdr __user *, msg, unsigned, flags) err = -ENOBUFS; - if (msg_sys.msg_controllen > INT_MAX) + if (msg_sys->msg_controllen > INT_MAX) goto out_freeiov; - ctl_len = msg_sys.msg_controllen; + ctl_len = msg_sys->msg_controllen; if ((MSG_CMSG_COMPAT & flags) && ctl_len) { err = - cmsghdr_from_user_compat_to_kern(&msg_sys, sock->sk, ctl, + cmsghdr_from_user_compat_to_kern(msg_sys, sock->sk, ctl, sizeof(ctl)); if (err) goto out_freeiov; - ctl_buf = msg_sys.msg_control; - ctl_len = msg_sys.msg_controllen; + ctl_buf = msg_sys->msg_control; + ctl_len = msg_sys->msg_controllen; } else if (ctl_len) { if (ctl_len > sizeof(ctl)) { ctl_buf = sock_kmalloc(sock->sk, ctl_len, GFP_KERNEL); @@ -1941,21 +1948,22 @@ SYSCALL_DEFINE3(sendmsg, int, fd, struct msghdr __user *, msg, unsigned, flags) } err = -EFAULT; /* - * Careful! Before this, msg_sys.msg_control contains a user pointer. + * Careful! Before this, msg_sys->msg_control contains a user pointer. * Afterwards, it will be a kernel pointer. Thus the compiler-assisted * checking falls down on this. */ if (copy_from_user(ctl_buf, - (void __user __force *)msg_sys.msg_control, + (void __user __force *)msg_sys->msg_control, ctl_len)) goto out_freectl; - msg_sys.msg_control = ctl_buf; + msg_sys->msg_control = ctl_buf; } - msg_sys.msg_flags = flags; + msg_sys->msg_flags = flags; if (sock->file->f_flags & O_NONBLOCK) - msg_sys.msg_flags |= MSG_DONTWAIT; - err = sock_sendmsg(sock, &msg_sys, total_len); + msg_sys->msg_flags |= MSG_DONTWAIT; + err = (nosec ? sock_sendmsg_nosec : sock_sendmsg)(sock, msg_sys, + total_len); out_freectl: if (ctl_buf != ctl) @@ -1963,12 +1971,114 @@ out_freectl: out_freeiov: if (iov != iovstack) sock_kfree_s(sock->sk, iov, iov_size); -out_put: +out: + return err; +} + +/* + * BSD sendmsg interface + */ + +SYSCALL_DEFINE3(sendmsg, int, fd, struct msghdr __user *, msg, unsigned, flags) +{ + int fput_needed, err; + struct msghdr msg_sys; + struct socket *sock = sockfd_lookup_light(fd, &err, &fput_needed); + + if (!sock) + goto out; + + err = __sys_sendmsg(sock, msg, &msg_sys, flags, 0); + fput_light(sock->file, fput_needed); out: return err; } +/* + * Linux sendmmsg interface + */ + +int __sys_sendmmsg(int fd, struct mmsghdr __user *mmsg, unsigned int vlen, + unsigned int flags) +{ + int fput_needed, err, datagrams; + struct socket *sock; + struct mmsghdr __user *entry; + struct compat_mmsghdr __user *compat_entry; + struct msghdr msg_sys; + + datagrams = 0; + + sock = sockfd_lookup_light(fd, &err, &fput_needed); + if (!sock) + return err; + + err = sock_error(sock->sk); + if (err) + goto out_put; + + entry = mmsg; + compat_entry = (struct compat_mmsghdr __user *)mmsg; + + while (datagrams < vlen) { + /* + * No need to ask LSM for more than the first datagram. + */ + if (MSG_CMSG_COMPAT & flags) { + err = __sys_sendmsg(sock, (struct msghdr __user *)compat_entry, + &msg_sys, flags, datagrams); + if (err < 0) + break; + err = __put_user(err, &compat_entry->msg_len); + ++compat_entry; + } else { + err = __sys_sendmsg(sock, (struct msghdr __user *)entry, + &msg_sys, flags, datagrams); + if (err < 0) + break; + err = put_user(err, &entry->msg_len); + ++entry; + } + + if (err) + break; + ++datagrams; + } + +out_put: + fput_light(sock->file, fput_needed); + + if (err == 0) + return datagrams; + + if (datagrams != 0) { + /* + * We may send less entries than requested (vlen) if the + * sock is non blocking... + */ + if (err != -EAGAIN) { + /* + * ... or if sendmsg returns an error after we + * send some datagrams, where we record the + * error to return on the next call or if the + * app asks about it using getsockopt(SO_ERROR). + */ + sock->sk->sk_err = -err; + } + + return datagrams; + } + + return err; +} + +SYSCALL_DEFINE4(sendmmsg, int, fd, struct mmsghdr __user *, mmsg, + unsigned int, vlen, unsigned int, flags) +{ + return __sys_sendmmsg(fd, mmsg, vlen, flags); +} + static int __sys_recvmsg(struct socket *sock, struct msghdr __user *msg, struct msghdr *msg_sys, unsigned flags, int nosec) { @@ -2214,11 +2324,11 @@ SYSCALL_DEFINE5(recvmmsg, int, fd, struct mmsghdr __user *, mmsg, #ifdef __ARCH_WANT_SYS_SOCKETCALL /* Argument list sizes for sys_socketcall */ #define AL(x) ((x) * sizeof(unsigned long)) -static const unsigned char nargs[20] = { +static const unsigned char nargs[21] = { AL(0), AL(3), AL(3), AL(3), AL(2), AL(3), AL(3), AL(3), AL(4), AL(4), AL(4), AL(6), AL(6), AL(2), AL(5), AL(5), AL(3), AL(3), - AL(4), AL(5) + AL(4), AL(5), AL(4) }; #undef AL @@ -2238,7 +2348,7 @@ SYSCALL_DEFINE2(socketcall, int, call, unsigned long __user *, args) int err; unsigned int len; - if (call < 1 || call > SYS_RECVMMSG) + if (call < 1 || call > SYS_SENDMMSG) return -EINVAL; len = nargs[call]; @@ -2313,6 +2423,9 @@ SYSCALL_DEFINE2(socketcall, int, call, unsigned long __user *, args) case SYS_SENDMSG: err = sys_sendmsg(a0, (struct msghdr __user *)a1, a[2]); break; + case SYS_SENDMMSG: + err = sys_sendmmsg(a0, (struct mmsghdr __user *)a1, a[2], a[3]); + break; case SYS_RECVMSG: err = sys_recvmsg(a0, (struct msghdr __user *)a1, a[2]); break; -- cgit v0.10.2 From 2f6fc351e6e8c1b6a95140e733607e32bc3a4322 Mon Sep 17 00:00:00 2001 From: Rajkumar Manoharan Date: Thu, 28 Apr 2011 15:31:57 +0530 Subject: ath9k: Fix drain txq failure in flush While draining the txq in flush, the buffers can be added into the tx queue by tx_tasklet which leads to unneccesary chip reset. This issue was originially found with AR9382 and running heavy uplink udp traffic with higher bandwidth and doing frequent bgscan. Cc: stable@kernel.org Signed-off-by: Vasanthakumar Thiagarajan Signed-off-by: Rajkumar Manoharan Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index c3dbf26..efdafd2 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -2261,6 +2261,7 @@ static void ath9k_flush(struct ieee80211_hw *hw, bool drop) struct ath_softc *sc = hw->priv; int timeout = 200; /* ms */ int i, j; + bool drain_txq; mutex_lock(&sc->mutex); cancel_delayed_work_sync(&sc->tx_complete_work); @@ -2286,7 +2287,10 @@ static void ath9k_flush(struct ieee80211_hw *hw, bool drop) } ath9k_ps_wakeup(sc); - if (!ath_drain_all_txq(sc, false)) + spin_lock_bh(&sc->sc_pcu_lock); + drain_txq = ath_drain_all_txq(sc, false); + spin_unlock_bh(&sc->sc_pcu_lock); + if (!drain_txq) ath_reset(sc, false); ath9k_ps_restore(sc); ieee80211_wake_queues(hw); -- cgit v0.10.2 From 470ab2a23b453518ac86937572b4531d8925ca55 Mon Sep 17 00:00:00 2001 From: Rajkumar Manoharan Date: Fri, 29 Apr 2011 14:48:45 +0530 Subject: mac80211: use wake_queue to restart trasmit netif_tx_start_all_queues is used to allow the upper layer to transmit frames but it does not restart transmission. To restart the trasmission use netif_tx_wake_all_queues. Not doing so, sometimes stalls the transmission and the application has to be restarted to proceed further. This issue was originally found while sending udp traffic in higer bandwidth in open environment without bgscan. Cc: stable@kernel.org Signed-off-by: Rajkumar Manoharan Signed-off-by: John W. Linville diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index a41f234..8d752b4 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -781,7 +781,7 @@ void ieee80211_dynamic_ps_enable_work(struct work_struct *work) ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_PS); } - netif_tx_start_all_queues(sdata->dev); + netif_tx_wake_all_queues(sdata->dev); } void ieee80211_dynamic_ps_timer(unsigned long data) -- cgit v0.10.2 From 7e4b4eecedb3c6bd5f9fec479ef33ccc6ce72375 Mon Sep 17 00:00:00 2001 From: Daniel Drake Date: Mon, 2 May 2011 21:38:16 +0100 Subject: libertas: remove tx_timeout handler As described at http://marc.info/?l=linux-netdev&m=130428493104730&w=2 libertas frequently generates spurious tx timeouts, because the tx queue is brought down for extended periods during scanning. The net layer takes a look and incorrectly assumes the queue has been down for several seconds, and generates a tx_timeout. One way to fix this is to bump the trans_start counter while scanning so that the network layer knows that the device is still alive, but I think the tx_timeout handler is implemented wrongly here and not of any real use, so I vote to remove it. As explained at http://marc.info/?l=linux-wireless&m=130430311115755&w=2 the watchdog is primarily meant to deal with lockup on the hardware TX path (detected by the tx queue being stopped for an extended period of time), but this is unlikely to happen with libertas. In this case, the tx queue is stopped only while waiting for lbs_thread to send the queued frame to the driver, and lbs_thread wakes up the queue immediately after, even if the frame could not be sent correctly. So, the only hardware-related possibility that this catches is if hw_host_to_card hangs - this is something I have never seen. And if it were to happen, nothing done by lbs_tx_timeout would actually wake up lbs_thread any quicker than otherwise. Removing this oddly-behaving spuriously-firing tx_timeout handler should fix an occasional kernel crash during resume (http://dev.laptop.org/ticket/10748) Signed-off-by: Daniel Drake Acked-by: Dan Williams Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/libertas/main.c b/drivers/net/wireless/libertas/main.c index ed57cf8..ae02e6b 100644 --- a/drivers/net/wireless/libertas/main.c +++ b/drivers/net/wireless/libertas/main.c @@ -149,28 +149,6 @@ static int lbs_eth_stop(struct net_device *dev) return 0; } -static void lbs_tx_timeout(struct net_device *dev) -{ - struct lbs_private *priv = dev->ml_priv; - - lbs_deb_enter(LBS_DEB_TX); - - lbs_pr_err("tx watch dog timeout\n"); - - dev->trans_start = jiffies; /* prevent tx timeout */ - - if (priv->currenttxskb) - lbs_send_tx_feedback(priv, 0); - - /* XX: Shouldn't we also call into the hw-specific driver - to kick it somehow? */ - lbs_host_to_card_done(priv); - - /* FIXME: reset the card */ - - lbs_deb_leave(LBS_DEB_TX); -} - void lbs_host_to_card_done(struct lbs_private *priv) { unsigned long flags; @@ -791,7 +769,6 @@ static const struct net_device_ops lbs_netdev_ops = { .ndo_stop = lbs_eth_stop, .ndo_start_xmit = lbs_hard_start_xmit, .ndo_set_mac_address = lbs_set_mac_address, - .ndo_tx_timeout = lbs_tx_timeout, .ndo_set_multicast_list = lbs_set_multicast_list, .ndo_change_mtu = eth_change_mtu, .ndo_validate_addr = eth_validate_addr, -- cgit v0.10.2 From cbe8c735f1af88037c3dab570f816e3a77896cc7 Mon Sep 17 00:00:00 2001 From: Mohammed Shafi Shajakhan Date: Tue, 3 May 2011 13:14:06 +0530 Subject: ath9k_hw: remove aggregation protection mode when aggregation protection mode is enabled the hardware needs to send RTS/CTS for each HT frame. Currently its disabled so remove the unused call backs. Signed-off-by: Mohammed Shafi Shajakhan Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/ar9002_mac.c b/drivers/net/wireless/ath/ath9k/ar9002_mac.c index c338efb..7a332f1 100644 --- a/drivers/net/wireless/ath/ath9k/ar9002_mac.c +++ b/drivers/net/wireless/ath/ath9k/ar9002_mac.c @@ -415,15 +415,6 @@ static void ar9002_hw_clr11n_aggr(struct ath_hw *ah, void *ds) ads->ds_ctl1 &= (~AR_IsAggr & ~AR_MoreAggr); } -static void ar9002_hw_set11n_burstduration(struct ath_hw *ah, void *ds, - u32 burstDuration) -{ - struct ar5416_desc *ads = AR5416DESC(ds); - - ads->ds_ctl2 &= ~AR_BurstDur; - ads->ds_ctl2 |= SM(burstDuration, AR_BurstDur); -} - void ath9k_hw_setuprxdesc(struct ath_hw *ah, struct ath_desc *ds, u32 size, u32 flags) { @@ -456,6 +447,5 @@ void ar9002_hw_attach_mac_ops(struct ath_hw *ah) ops->set11n_aggr_middle = ar9002_hw_set11n_aggr_middle; ops->set11n_aggr_last = ar9002_hw_set11n_aggr_last; ops->clr11n_aggr = ar9002_hw_clr11n_aggr; - ops->set11n_burstduration = ar9002_hw_set11n_burstduration; ops->set_clrdmask = ar9002_hw_set_clrdmask; } diff --git a/drivers/net/wireless/ath/ath9k/ar9003_mac.c b/drivers/net/wireless/ath/ath9k/ar9003_mac.c index c1264d6..be6adec 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_mac.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_mac.c @@ -484,16 +484,6 @@ static void ar9003_hw_clr11n_aggr(struct ath_hw *ah, void *ds) ads->ctl12 &= (~AR_IsAggr & ~AR_MoreAggr); } -static void ar9003_hw_set11n_burstduration(struct ath_hw *ah, void *ds, - u32 burstDuration) -{ - struct ar9003_txc *ads = (struct ar9003_txc *) ds; - - ads->ctl13 &= ~AR_BurstDur; - ads->ctl13 |= SM(burstDuration, AR_BurstDur); - -} - void ar9003_hw_set_paprd_txdesc(struct ath_hw *ah, void *ds, u8 chains) { struct ar9003_txc *ads = ds; @@ -518,7 +508,6 @@ void ar9003_hw_attach_mac_ops(struct ath_hw *hw) ops->set11n_aggr_middle = ar9003_hw_set11n_aggr_middle; ops->set11n_aggr_last = ar9003_hw_set11n_aggr_last; ops->clr11n_aggr = ar9003_hw_clr11n_aggr; - ops->set11n_burstduration = ar9003_hw_set11n_burstduration; ops->set_clrdmask = ar9003_hw_set_clrdmask; } diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h index 0312aa0..1bffd15 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h @@ -62,7 +62,6 @@ struct ath_node; #define ATH_TXQ_SETUP(sc, i) ((sc)->tx.txqsetup & (1<clr11n_aggr(ah, ds); } -static inline void ath9k_hw_set11n_burstduration(struct ath_hw *ah, void *ds, - u32 burstDuration) -{ - ath9k_hw_ops(ah)->set11n_burstduration(ah, ds, burstDuration); -} - static inline void ath9k_hw_set_clrdmask(struct ath_hw *ah, void *ds, bool val) { ath9k_hw_ops(ah)->set_clrdmask(ah, ds, val); diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h index 34ed1bd..b2248bb 100644 --- a/drivers/net/wireless/ath/ath9k/hw.h +++ b/drivers/net/wireless/ath/ath9k/hw.h @@ -628,8 +628,6 @@ struct ath_hw_ops { u32 numDelims); void (*set11n_aggr_last)(struct ath_hw *ah, void *ds); void (*clr11n_aggr)(struct ath_hw *ah, void *ds); - void (*set11n_burstduration)(struct ath_hw *ah, void *ds, - u32 burstDuration); void (*set_clrdmask)(struct ath_hw *ah, void *ds, bool val); }; diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index efdafd2..3de115d 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -2039,9 +2039,6 @@ static void ath9k_bss_info_changed(struct ieee80211_hw *hw, if (changed & BSS_CHANGED_BSSID) { ath9k_config_bss(sc, vif); - /* Set aggregation protection mode parameters */ - sc->config.ath_aggr_prot = 0; - ath_dbg(common, ATH_DBG_CONFIG, "BSSID: %pM aid: 0x%x\n", common->curbssid, common->curaid); } diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c index 55960fa..947d5b3 100644 --- a/drivers/net/wireless/ath/ath9k/xmit.c +++ b/drivers/net/wireless/ath/ath9k/xmit.c @@ -1663,8 +1663,7 @@ static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf, int len) rix = rates[i].idx; series[i].Tries = rates[i].count; - if ((sc->config.ath_aggr_prot && bf_isaggr(bf)) || - (rates[i].flags & IEEE80211_TX_RC_USE_RTS_CTS)) { + if (rates[i].flags & IEEE80211_TX_RC_USE_RTS_CTS) { series[i].RateFlags |= ATH9K_RATESERIES_RTS_CTS; flags |= ATH9K_TXDESC_RTSENA; } else if (rates[i].flags & IEEE80211_TX_RC_USE_CTS_PROTECT) { @@ -1733,8 +1732,6 @@ static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf, int len) !is_pspoll, ctsrate, 0, series, 4, flags); - if (sc->config.ath_aggr_prot && flags) - ath9k_hw_set11n_burstduration(sc->sc_ah, bf->bf_desc, 8192); } static struct ath_buf *ath_tx_setup_buffer(struct ieee80211_hw *hw, -- cgit v0.10.2 From 4c468fe559f7910b1c6b10d3d223943fdd1b653c Mon Sep 17 00:00:00 2001 From: Arik Nemtsov Date: Tue, 3 May 2011 11:53:07 +0300 Subject: mac80211: set TID of internal mgmt packets to 7 The queue mapping of internal mgmt packets is set to VO. Set the TID value to match the queue mapping. Otherwise drivers that only look at the TID might get confused. Signed-off-by: Arik Nemtsov Signed-off-by: John W. Linville diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index e3e3aa1..e1a39ed 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -2534,8 +2534,9 @@ void ieee80211_tx_skb(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb) skb_set_network_header(skb, 0); skb_set_transport_header(skb, 0); - /* send all internal mgmt frames on VO */ - skb_set_queue_mapping(skb, 0); + /* Send all internal mgmt frames on VO. Accordingly set TID to 7. */ + skb_set_queue_mapping(skb, IEEE80211_AC_VO); + skb->priority = 7; /* * The other path calling ieee80211_xmit is from the tasklet, -- cgit v0.10.2 From 1ddc286731134ad52a74b6956d9bc2a4369219a8 Mon Sep 17 00:00:00 2001 From: Rajkumar Manoharan Date: Tue, 3 May 2011 17:03:59 +0530 Subject: mac80211: Postpond ps timer if tx is stopped by others Whenever the driver's queue depth reaches the max, the queues are stopped by the driver till the driver can accept the frames. At the mean time dynamic_ps_timer can be expired due to not receiving packet from upper layer which could restart the transmission at the end of ps work. Due to the mismatch with driver state, mac80211 is unneccesarity buffering all the frames till the driver wakes up the queue. Check whether there is no transmit or the tx queues were stopped by some reasons. If any of the queue was stopped, the postpond ps timer and do not restart netif_tx. Signed-off-by: Rajkumar Manoharan Signed-off-by: John W. Linville diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 8d752b4..4f6b267 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -750,6 +750,8 @@ void ieee80211_dynamic_ps_enable_work(struct work_struct *work) dynamic_ps_enable_work); struct ieee80211_sub_if_data *sdata = local->ps_sdata; struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; + unsigned long flags; + int q; /* can only happen when PS was just disabled anyway */ if (!sdata) @@ -758,6 +760,24 @@ void ieee80211_dynamic_ps_enable_work(struct work_struct *work) if (local->hw.conf.flags & IEEE80211_CONF_PS) return; + /* + * transmission can be stopped by others which leads to + * dynamic_ps_timer expiry. Postpond the ps timer if it + * is not the actual idle state. + */ + spin_lock_irqsave(&local->queue_stop_reason_lock, flags); + for (q = 0; q < local->hw.queues; q++) { + if (local->queue_stop_reasons[q]) { + spin_unlock_irqrestore(&local->queue_stop_reason_lock, + flags); + mod_timer(&local->dynamic_ps_timer, jiffies + + msecs_to_jiffies( + local->hw.conf.dynamic_ps_timeout)); + return; + } + } + spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags); + if ((local->hw.flags & IEEE80211_HW_PS_NULLFUNC_STACK) && (!(ifmgd->flags & IEEE80211_STA_NULLFUNC_ACKED))) { netif_tx_stop_all_queues(sdata->dev); -- cgit v0.10.2 From e52dadb341c9c5ac25d6abd9216dd62752784f03 Mon Sep 17 00:00:00 2001 From: Chaoming Li Date: Tue, 3 May 2011 09:47:45 -0500 Subject: rtlwifi: rtl8192se: Merge def.h Introduce routine def.h for rtl8192se. Signed-off-by: Chaoming_Li Signed-off-by: Larry Finger Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/rtlwifi/rtl8192se/def.h b/drivers/net/wireless/rtlwifi/rtl8192se/def.h new file mode 100644 index 0000000..69828f2 --- /dev/null +++ b/drivers/net/wireless/rtlwifi/rtl8192se/def.h @@ -0,0 +1,598 @@ +/****************************************************************************** + * + * Copyright(c) 2009-2010 Realtek Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger + * + *****************************************************************************/ +#ifndef __REALTEK_92S_DEF_H__ +#define __REALTEK_92S_DEF_H__ + +#define RX_MPDU_QUEUE 0 +#define RX_CMD_QUEUE 1 +#define RX_MAX_QUEUE 2 + +#define DESC92S_RATE1M 0x00 +#define DESC92S_RATE2M 0x01 +#define DESC92S_RATE5_5M 0x02 +#define DESC92S_RATE11M 0x03 +#define DESC92S_RATE6M 0x04 +#define DESC92S_RATE9M 0x05 +#define DESC92S_RATE12M 0x06 +#define DESC92S_RATE18M 0x07 +#define DESC92S_RATE24M 0x08 +#define DESC92S_RATE36M 0x09 +#define DESC92S_RATE48M 0x0a +#define DESC92S_RATE54M 0x0b +#define DESC92S_RATEMCS0 0x0c +#define DESC92S_RATEMCS1 0x0d +#define DESC92S_RATEMCS2 0x0e +#define DESC92S_RATEMCS3 0x0f +#define DESC92S_RATEMCS4 0x10 +#define DESC92S_RATEMCS5 0x11 +#define DESC92S_RATEMCS6 0x12 +#define DESC92S_RATEMCS7 0x13 +#define DESC92S_RATEMCS8 0x14 +#define DESC92S_RATEMCS9 0x15 +#define DESC92S_RATEMCS10 0x16 +#define DESC92S_RATEMCS11 0x17 +#define DESC92S_RATEMCS12 0x18 +#define DESC92S_RATEMCS13 0x19 +#define DESC92S_RATEMCS14 0x1a +#define DESC92S_RATEMCS15 0x1b +#define DESC92S_RATEMCS15_SG 0x1c +#define DESC92S_RATEMCS32 0x20 + +#define SHORT_SLOT_TIME 9 +#define NON_SHORT_SLOT_TIME 20 + +/* Rx smooth factor */ +#define RX_SMOOTH_FACTOR 20 + +/* Queue Select Value in TxDesc */ +#define QSLT_BK 0x2 +#define QSLT_BE 0x0 +#define QSLT_VI 0x5 +#define QSLT_VO 0x6 +#define QSLT_BEACON 0x10 +#define QSLT_HIGH 0x11 +#define QSLT_MGNT 0x12 +#define QSLT_CMD 0x13 + +#define PHY_RSSI_SLID_WIN_MAX 100 +#define PHY_LINKQUALITY_SLID_WIN_MAX 20 +#define PHY_BEACON_RSSI_SLID_WIN_MAX 10 + +/* Tx Desc */ +#define TX_DESC_SIZE_RTL8192S (16 * 4) +#define TX_CMDDESC_SIZE_RTL8192S (16 * 4) + +/* Define a macro that takes a le32 word, converts it to host ordering, + * right shifts by a specified count, creates a mask of the specified + * bit count, and extracts that number of bits. + */ + +#define SHIFT_AND_MASK_LE(__pdesc, __shift, __mask) \ + ((le32_to_cpu(*(((__le32 *)(__pdesc)))) >> (__shift)) & \ + BIT_LEN_MASK_32(__mask)) + +/* Define a macro that clears a bit field in an le32 word and + * sets the specified value into that bit field. The resulting + * value remains in le32 ordering; however, it is properly converted + * to host ordering for the clear and set operations before conversion + * back to le32. + */ + +#define SET_BITS_OFFSET_LE(__pdesc, __shift, __len, __val) \ + (*(__le32 *)(__pdesc) = \ + (cpu_to_le32((le32_to_cpu(*((__le32 *)(__pdesc))) & \ + (~(BIT_OFFSET_LEN_MASK_32((__shift), __len)))) | \ + (((u32)(__val) & BIT_LEN_MASK_32(__len)) << (__shift))))); + +/* macros to read/write various fields in RX or TX descriptors */ + +/* Dword 0 */ +#define SET_TX_DESC_PKT_SIZE(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc, 0, 16, __val) +#define SET_TX_DESC_OFFSET(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc, 16, 8, __val) +#define SET_TX_DESC_TYPE(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc, 24, 2, __val) +#define SET_TX_DESC_LAST_SEG(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc, 26, 1, __val) +#define SET_TX_DESC_FIRST_SEG(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc, 27, 1, __val) +#define SET_TX_DESC_LINIP(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc, 28, 1, __val) +#define SET_TX_DESC_AMSDU(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc, 29, 1, __val) +#define SET_TX_DESC_GREEN_FIELD(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc, 30, 1, __val) +#define SET_TX_DESC_OWN(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc, 31, 1, __val) + +#define GET_TX_DESC_OWN(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc, 31, 1) + +/* Dword 1 */ +#define SET_TX_DESC_MACID(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc + 4, 0, 5, __val) +#define SET_TX_DESC_MORE_DATA(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc + 4, 5, 1, __val) +#define SET_TX_DESC_MORE_FRAG(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc + 4, 6, 1, __val) +#define SET_TX_DESC_PIFS(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc + 4, 7, 1, __val) +#define SET_TX_DESC_QUEUE_SEL(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc + 4, 8, 5, __val) +#define SET_TX_DESC_ACK_POLICY(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc + 4, 13, 2, __val) +#define SET_TX_DESC_NO_ACM(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc + 4, 15, 1, __val) +#define SET_TX_DESC_NON_QOS(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc + 4, 16, 1, __val) +#define SET_TX_DESC_KEY_ID(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc + 4, 17, 2, __val) +#define SET_TX_DESC_OUI(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc + 4, 19, 1, __val) +#define SET_TX_DESC_PKT_TYPE(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc + 4, 20, 1, __val) +#define SET_TX_DESC_EN_DESC_ID(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc + 4, 21, 1, __val) +#define SET_TX_DESC_SEC_TYPE(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc + 4, 22, 2, __val) +#define SET_TX_DESC_WDS(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc + 4, 24, 1, __val) +#define SET_TX_DESC_HTC(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc + 4, 25, 1, __val) +#define SET_TX_DESC_PKT_OFFSET(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc + 4, 26, 5, __val) +#define SET_TX_DESC_HWPC(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc + 4, 27, 1, __val) + +/* Dword 2 */ +#define SET_TX_DESC_DATA_RETRY_LIMIT(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc + 8, 0, 6, __val) +#define SET_TX_DESC_RETRY_LIMIT_ENABLE(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc + 8, 6, 1, __val) +#define SET_TX_DESC_TSFL(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc + 8, 7, 5, __val) +#define SET_TX_DESC_RTS_RETRY_COUNT(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc + 8, 12, 6, __val) +#define SET_TX_DESC_DATA_RETRY_COUNT(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc + 8, 18, 6, __val) +#define SET_TX_DESC_RSVD_MACID(__pdesc, __val) \ + SET_BITS_OFFSET_LE(((__pdesc) + 8), 24, 5, __val) +#define SET_TX_DESC_AGG_ENABLE(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc + 8, 29, 1, __val) +#define SET_TX_DESC_AGG_BREAK(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc + 8, 30, 1, __val) +#define SET_TX_DESC_OWN_MAC(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc + 8, 31, 1, __val) + +/* Dword 3 */ +#define SET_TX_DESC_NEXT_HEAP_PAGE(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc + 12, 0, 8, __val) +#define SET_TX_DESC_TAIL_PAGE(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc + 12, 8, 8, __val) +#define SET_TX_DESC_SEQ(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc + 12, 16, 12, __val) +#define SET_TX_DESC_FRAG(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc + 12, 28, 4, __val) + +/* Dword 4 */ +#define SET_TX_DESC_RTS_RATE(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc + 16, 0, 6, __val) +#define SET_TX_DESC_DISABLE_RTS_FB(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc + 16, 6, 1, __val) +#define SET_TX_DESC_RTS_RATE_FB_LIMIT(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc + 16, 7, 4, __val) +#define SET_TX_DESC_CTS_ENABLE(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc + 16, 11, 1, __val) +#define SET_TX_DESC_RTS_ENABLE(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc + 16, 12, 1, __val) +#define SET_TX_DESC_RA_BRSR_ID(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc + 16, 13, 3, __val) +#define SET_TX_DESC_TXHT(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc + 16, 16, 1, __val) +#define SET_TX_DESC_TX_SHORT(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc + 16, 17, 1, __val) +#define SET_TX_DESC_TX_BANDWIDTH(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc + 16, 18, 1, __val) +#define SET_TX_DESC_TX_SUB_CARRIER(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc + 16, 19, 2, __val) +#define SET_TX_DESC_TX_STBC(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc + 16, 21, 2, __val) +#define SET_TX_DESC_TX_REVERSE_DIRECTION(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc + 16, 23, 1, __val) +#define SET_TX_DESC_RTS_HT(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc + 16, 24, 1, __val) +#define SET_TX_DESC_RTS_SHORT(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc + 16, 25, 1, __val) +#define SET_TX_DESC_RTS_BANDWIDTH(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc + 16, 26, 1, __val) +#define SET_TX_DESC_RTS_SUB_CARRIER(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc + 16, 27, 2, __val) +#define SET_TX_DESC_RTS_STBC(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc + 16, 29, 2, __val) +#define SET_TX_DESC_USER_RATE(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc + 16, 31, 1, __val) + +/* Dword 5 */ +#define SET_TX_DESC_PACKET_ID(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc + 20, 0, 9, __val) +#define SET_TX_DESC_TX_RATE(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc + 20, 9, 6, __val) +#define SET_TX_DESC_DISABLE_FB(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc + 20, 15, 1, __val) +#define SET_TX_DESC_DATA_RATE_FB_LIMIT(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc + 20, 16, 5, __val) +#define SET_TX_DESC_TX_AGC(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc + 20, 21, 11, __val) + +/* Dword 6 */ +#define SET_TX_DESC_IP_CHECK_SUM(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc + 24, 0, 16, __val) +#define SET_TX_DESC_TCP_CHECK_SUM(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc + 24, 16, 16, __val) + +/* Dword 7 */ +#define SET_TX_DESC_TX_BUFFER_SIZE(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc + 28, 0, 16, __val) +#define SET_TX_DESC_IP_HEADER_OFFSET(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc + 28, 16, 8, __val) +#define SET_TX_DESC_TCP_ENABLE(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc + 28, 31, 1, __val) + +/* Dword 8 */ +#define SET_TX_DESC_TX_BUFFER_ADDRESS(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc + 32, 0, 32, __val) +#define GET_TX_DESC_TX_BUFFER_ADDRESS(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc + 32, 0, 32) + +/* Dword 9 */ +#define SET_TX_DESC_NEXT_DESC_ADDRESS(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc + 36, 0, 32, __val) + +/* Because the PCI Tx descriptors are chaied at the + * initialization and all the NextDescAddresses in + * these descriptors cannot not be cleared (,or + * driver/HW cannot find the next descriptor), the + * offset 36 (NextDescAddresses) is reserved when + * the desc is cleared. */ +#define TX_DESC_NEXT_DESC_OFFSET 36 +#define CLEAR_PCI_TX_DESC_CONTENT(__pdesc, _size) \ +do { \ + if (_size > TX_DESC_NEXT_DESC_OFFSET) \ + memset(__pdesc, 0, TX_DESC_NEXT_DESC_OFFSET); \ + else \ + memset(__pdesc, 0, _size); \ +} while (0); + +/* Rx Desc */ +#define RX_STATUS_DESC_SIZE 24 +#define RX_DRV_INFO_SIZE_UNIT 8 + +/* DWORD 0 */ +#define SET_RX_STATUS_DESC_PKT_LEN(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc, 0, 14, __val) +#define SET_RX_STATUS_DESC_CRC32(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc, 14, 1, __val) +#define SET_RX_STATUS_DESC_ICV(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc, 15, 1, __val) +#define SET_RX_STATUS_DESC_DRVINFO_SIZE(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc, 16, 4, __val) +#define SET_RX_STATUS_DESC_SECURITY(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc, 20, 3, __val) +#define SET_RX_STATUS_DESC_QOS(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc, 23, 1, __val) +#define SET_RX_STATUS_DESC_SHIFT(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc, 24, 2, __val) +#define SET_RX_STATUS_DESC_PHY_STATUS(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc, 26, 1, __val) +#define SET_RX_STATUS_DESC_SWDEC(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc, 27, 1, __val) +#define SET_RX_STATUS_DESC_LAST_SEG(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc, 28, 1, __val) +#define SET_RX_STATUS_DESC_FIRST_SEG(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc, 29, 1, __val) +#define SET_RX_STATUS_DESC_EOR(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc, 30, 1, __val) +#define SET_RX_STATUS_DESC_OWN(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc, 31, 1, __val) + +#define GET_RX_STATUS_DESC_PKT_LEN(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc, 0, 14) +#define GET_RX_STATUS_DESC_CRC32(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc, 14, 1) +#define GET_RX_STATUS_DESC_ICV(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc, 15, 1) +#define GET_RX_STATUS_DESC_DRVINFO_SIZE(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc, 16, 4) +#define GET_RX_STATUS_DESC_SECURITY(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc, 20, 3) +#define GET_RX_STATUS_DESC_QOS(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc, 23, 1) +#define GET_RX_STATUS_DESC_SHIFT(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc, 24, 2) +#define GET_RX_STATUS_DESC_PHY_STATUS(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc, 26, 1) +#define GET_RX_STATUS_DESC_SWDEC(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc, 27, 1) +#define GET_RX_STATUS_DESC_LAST_SEG(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc, 28, 1) +#define GET_RX_STATUS_DESC_FIRST_SEG(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc, 29, 1) +#define GET_RX_STATUS_DESC_EOR(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc, 30, 1) +#define GET_RX_STATUS_DESC_OWN(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc, 31, 1) + +/* DWORD 1 */ +#define SET_RX_STATUS_DESC_MACID(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc + 4, 0, 5, __val) +#define SET_RX_STATUS_DESC_TID(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc + 4, 5, 4, __val) +#define SET_RX_STATUS_DESC_PAGGR(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc + 4, 14, 1, __val) +#define SET_RX_STATUS_DESC_FAGGR(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc + 4, 15, 1, __val) +#define SET_RX_STATUS_DESC_A1_FIT(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc + 4, 16, 4, __val) +#define SET_RX_STATUS_DESC_A2_FIT(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc + 4, 20, 4, __val) +#define SET_RX_STATUS_DESC_PAM(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc + 4, 24, 1, __val) +#define SET_RX_STATUS_DESC_PWR(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc + 4, 25, 1, __val) +#define SET_RX_STATUS_DESC_MOREDATA(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc + 4, 26, 1, __val) +#define SET_RX_STATUS_DESC_MOREFRAG(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc + 4, 27, 1, __val) +#define SET_RX_STATUS_DESC_TYPE(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc + 4, 28, 2, __val) +#define SET_RX_STATUS_DESC_MC(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc + 4, 30, 1, __val) +#define SET_RX_STATUS_DESC_BC(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc + 4, 31, 1, __val) + +#define GET_RX_STATUS_DEC_MACID(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc + 4, 0, 5) +#define GET_RX_STATUS_DESC_TID(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc + 4, 5, 4) +#define GET_RX_STATUS_DESC_PAGGR(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc + 4, 14, 1) +#define GET_RX_STATUS_DESC_FAGGR(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc + 4, 15, 1) +#define GET_RX_STATUS_DESC_A1_FIT(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc + 4, 16, 4) +#define GET_RX_STATUS_DESC_A2_FIT(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc + 4, 20, 4) +#define GET_RX_STATUS_DESC_PAM(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc + 4, 24, 1) +#define GET_RX_STATUS_DESC_PWR(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc + 4, 25, 1) +#define GET_RX_STATUS_DESC_MORE_DATA(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc + 4, 26, 1) +#define GET_RX_STATUS_DESC_MORE_FRAG(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc + 4, 27, 1) +#define GET_RX_STATUS_DESC_TYPE(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc + 4, 28, 2) +#define GET_RX_STATUS_DESC_MC(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc + 4, 30, 1) +#define GET_RX_STATUS_DESC_BC(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc + 4, 31, 1) + +/* DWORD 2 */ +#define SET_RX_STATUS_DESC_SEQ(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc + 8, 0, 12, __val) +#define SET_RX_STATUS_DESC_FRAG(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc + 8, 12, 4, __val) +#define SET_RX_STATUS_DESC_NEXT_PKTLEN(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc + 8, 16, 8, __val) +#define SET_RX_STATUS_DESC_NEXT_IND(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc + 8, 30, 1, __val) + +#define GET_RX_STATUS_DESC_SEQ(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc + 8, 0, 12) +#define GET_RX_STATUS_DESC_FRAG(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc + 8, 12, 4) +#define GET_RX_STATUS_DESC_NEXT_PKTLEN(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc + 8, 16, 8) +#define GET_RX_STATUS_DESC_NEXT_IND(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc + 8, 30, 1) + +/* DWORD 3 */ +#define SET_RX_STATUS_DESC_RX_MCS(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc + 12, 0, 6, __val) +#define SET_RX_STATUS_DESC_RX_HT(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc + 12, 6, 1, __val) +#define SET_RX_STATUS_DESC_AMSDU(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc + 12, 7, 1, __val) +#define SET_RX_STATUS_DESC_SPLCP(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc + 12, 8, 1, __val) +#define SET_RX_STATUS_DESC_BW(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc + 12, 9, 1, __val) +#define SET_RX_STATUS_DESC_HTC(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc + 12, 10, 1, __val) +#define SET_RX_STATUS_DESC_TCP_CHK_RPT(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc + 12, 11, 1, __val) +#define SET_RX_STATUS_DESC_IP_CHK_RPT(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc + 12, 12, 1, __val) +#define SET_RX_STATUS_DESC_TCP_CHK_VALID(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc + 12, 13, 1, __val) +#define SET_RX_STATUS_DESC_HWPC_ERR(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc + 12, 14, 1, __val) +#define SET_RX_STATUS_DESC_HWPC_IND(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc + 12, 15, 1, __val) +#define SET_RX_STATUS_DESC_IV0(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc + 12, 16, 16, __val) + +#define GET_RX_STATUS_DESC_RX_MCS(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc + 12, 0, 6) +#define GET_RX_STATUS_DESC_RX_HT(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc + 12, 6, 1) +#define GET_RX_STATUS_DESC_AMSDU(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc + 12, 7, 1) +#define GET_RX_STATUS_DESC_SPLCP(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc + 12, 8, 1) +#define GET_RX_STATUS_DESC_BW(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc + 12, 9, 1) +#define GET_RX_STATUS_DESC_HTC(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc + 12, 10, 1) +#define GET_RX_STATUS_DESC_TCP_CHK_RPT(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc + 12, 11, 1) +#define GET_RX_STATUS_DESC_IP_CHK_RPT(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc + 12, 12, 1) +#define GET_RX_STATUS_DESC_TCP_CHK_VALID(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc + 12, 13, 1) +#define GET_RX_STATUS_DESC_HWPC_ERR(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc + 12, 14, 1) +#define GET_RX_STATUS_DESC_HWPC_IND(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc + 12, 15, 1) +#define GET_RX_STATUS_DESC_IV0(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc + 12, 16, 16) + +/* DWORD 4 */ +#define SET_RX_STATUS_DESC_IV1(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc + 16, 0, 32, __val) +#define GET_RX_STATUS_DESC_IV1(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc + 16, 0, 32) + +/* DWORD 5 */ +#define SET_RX_STATUS_DESC_TSFL(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc + 20, 0, 32, __val) +#define GET_RX_STATUS_DESC_TSFL(__pdesc) \ + SHIFT_AND_MASK_LE(__pdesc + 20, 0, 32) + +/* DWORD 6 */ +#define SET_RX_STATUS__DESC_BUFF_ADDR(__pdesc, __val) \ + SET_BITS_OFFSET_LE(__pdesc + 24, 0, 32, __val) + +#define RX_HAL_IS_CCK_RATE(_pdesc)\ + (GET_RX_STATUS_DESC_RX_MCS(_pdesc) == DESC92S_RATE1M || \ + GET_RX_STATUS_DESC_RX_MCS(_pdesc) == DESC92S_RATE2M || \ + GET_RX_STATUS_DESC_RX_MCS(_pdesc) == DESC92S_RATE5_5M ||\ + GET_RX_STATUS_DESC_RX_MCS(_pdesc) == DESC92S_RATE11M) + +enum rf_optype { + RF_OP_BY_SW_3WIRE = 0, + RF_OP_BY_FW, + RF_OP_MAX +}; + +enum ic_inferiority { + IC_INFERIORITY_A = 0, + IC_INFERIORITY_B = 1, +}; + +enum fwcmd_iotype { + /* For DIG DM */ + FW_CMD_DIG_ENABLE = 0, + FW_CMD_DIG_DISABLE = 1, + FW_CMD_DIG_HALT = 2, + FW_CMD_DIG_RESUME = 3, + /* For High Power DM */ + FW_CMD_HIGH_PWR_ENABLE = 4, + FW_CMD_HIGH_PWR_DISABLE = 5, + /* For Rate adaptive DM */ + FW_CMD_RA_RESET = 6, + FW_CMD_RA_ACTIVE = 7, + FW_CMD_RA_REFRESH_N = 8, + FW_CMD_RA_REFRESH_BG = 9, + FW_CMD_RA_INIT = 10, + /* For FW supported IQK */ + FW_CMD_IQK_INIT = 11, + /* Tx power tracking switch, + * MP driver only */ + FW_CMD_TXPWR_TRACK_ENABLE = 12, + /* Tx power tracking switch, + * MP driver only */ + FW_CMD_TXPWR_TRACK_DISABLE = 13, + /* Tx power tracking with thermal + * indication, for Normal driver */ + FW_CMD_TXPWR_TRACK_THERMAL = 14, + FW_CMD_PAUSE_DM_BY_SCAN = 15, + FW_CMD_RESUME_DM_BY_SCAN = 16, + FW_CMD_RA_REFRESH_N_COMB = 17, + FW_CMD_RA_REFRESH_BG_COMB = 18, + FW_CMD_ANTENNA_SW_ENABLE = 19, + FW_CMD_ANTENNA_SW_DISABLE = 20, + /* Tx Status report for CCX from FW */ + FW_CMD_TX_FEEDBACK_CCX_ENABLE = 21, + /* Indifate firmware that driver + * enters LPS, For PS-Poll issue */ + FW_CMD_LPS_ENTER = 22, + /* Indicate firmware that driver + * leave LPS*/ + FW_CMD_LPS_LEAVE = 23, + /* Set DIG mode to signal strength */ + FW_CMD_DIG_MODE_SS = 24, + /* Set DIG mode to false alarm. */ + FW_CMD_DIG_MODE_FA = 25, + FW_CMD_ADD_A2_ENTRY = 26, + FW_CMD_CTRL_DM_BY_DRIVER = 27, + FW_CMD_CTRL_DM_BY_DRIVER_NEW = 28, + FW_CMD_PAPE_CONTROL = 29, + FW_CMD_IQK_ENABLE = 30, +}; + +/* + * Driver info contain PHY status + * and other variabel size info + * PHY Status content as below + */ +struct rx_fwinfo { + /* DWORD 0 */ + u8 gain_trsw[4]; + /* DWORD 1 */ + u8 pwdb_all; + u8 cfosho[4]; + /* DWORD 2 */ + u8 cfotail[4]; + /* DWORD 3 */ + s8 rxevm[2]; + s8 rxsnr[4]; + /* DWORD 4 */ + u8 pdsnr[2]; + /* DWORD 5 */ + u8 csi_current[2]; + u8 csi_target[2]; + /* DWORD 6 */ + u8 sigevm; + u8 max_ex_pwr; + u8 ex_intf_flag:1; + u8 sgi_en:1; + u8 rxsc:2; + u8 reserve:4; +}; + +struct phy_sts_cck_8192s_t { + u8 adc_pwdb_x[4]; + u8 sq_rpt; + u8 cck_agc_rpt; +}; + +#endif + -- cgit v0.10.2 From 9fe255ee3c0dd81c134b354e4b328c51f863ac40 Mon Sep 17 00:00:00 2001 From: Chaoming Li Date: Tue, 3 May 2011 09:47:55 -0500 Subject: rtlwifi: rtl8192se: Merge dynamic management routines Merge routines dm.c and dm.h for RTL8192SE. Signed-off-by: Larry Finger Signed-off-by: Chaoming_Li Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/rtlwifi/rtl8192se/dm.c b/drivers/net/wireless/rtlwifi/rtl8192se/dm.c new file mode 100644 index 0000000..da86db8 --- /dev/null +++ b/drivers/net/wireless/rtlwifi/rtl8192se/dm.c @@ -0,0 +1,733 @@ +/****************************************************************************** + * + * Copyright(c) 2009-2010 Realtek Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger + * + *****************************************************************************/ + +#include "../wifi.h" +#include "../base.h" +#include "reg.h" +#include "def.h" +#include "phy.h" +#include "dm.h" +#include "fw.h" + +struct dig_t digtable; +static const u32 edca_setting_dl[PEER_MAX] = { + 0xa44f, /* 0 UNKNOWN */ + 0x5ea44f, /* 1 REALTEK_90 */ + 0x5ea44f, /* 2 REALTEK_92SE */ + 0xa630, /* 3 BROAD */ + 0xa44f, /* 4 RAL */ + 0xa630, /* 5 ATH */ + 0xa630, /* 6 CISCO */ + 0xa42b, /* 7 MARV */ +}; + +static const u32 edca_setting_dl_gmode[PEER_MAX] = { + 0x4322, /* 0 UNKNOWN */ + 0xa44f, /* 1 REALTEK_90 */ + 0x5ea44f, /* 2 REALTEK_92SE */ + 0xa42b, /* 3 BROAD */ + 0x5e4322, /* 4 RAL */ + 0x4322, /* 5 ATH */ + 0xa430, /* 6 CISCO */ + 0x5ea44f, /* 7 MARV */ +}; + +static const u32 edca_setting_ul[PEER_MAX] = { + 0x5e4322, /* 0 UNKNOWN */ + 0xa44f, /* 1 REALTEK_90 */ + 0x5ea44f, /* 2 REALTEK_92SE */ + 0x5ea322, /* 3 BROAD */ + 0x5ea422, /* 4 RAL */ + 0x5ea322, /* 5 ATH */ + 0x3ea44f, /* 6 CISCO */ + 0x5ea44f, /* 7 MARV */ +}; + +static void _rtl92s_dm_check_edca_turbo(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); + + static u64 last_txok_cnt; + static u64 last_rxok_cnt; + u64 cur_txok_cnt = 0; + u64 cur_rxok_cnt = 0; + + u32 edca_be_ul = edca_setting_ul[mac->vendor]; + u32 edca_be_dl = edca_setting_dl[mac->vendor]; + u32 edca_gmode = edca_setting_dl_gmode[mac->vendor]; + + if (mac->link_state != MAC80211_LINKED) { + rtlpriv->dm.current_turbo_edca = false; + goto dm_checkedcaturbo_exit; + } + + if ((!rtlpriv->dm.is_any_nonbepkts) && + (!rtlpriv->dm.disable_framebursting)) { + cur_txok_cnt = rtlpriv->stats.txbytesunicast - last_txok_cnt; + cur_rxok_cnt = rtlpriv->stats.rxbytesunicast - last_rxok_cnt; + + if (rtlpriv->phy.rf_type == RF_1T2R) { + if (cur_txok_cnt > 4 * cur_rxok_cnt) { + /* Uplink TP is present. */ + if (rtlpriv->dm.is_cur_rdlstate || + !rtlpriv->dm.current_turbo_edca) { + rtl_write_dword(rtlpriv, EDCAPARA_BE, + edca_be_ul); + rtlpriv->dm.is_cur_rdlstate = false; + } + } else {/* Balance TP is present. */ + if (!rtlpriv->dm.is_cur_rdlstate || + !rtlpriv->dm.current_turbo_edca) { + if (mac->mode == WIRELESS_MODE_G || + mac->mode == WIRELESS_MODE_B) + rtl_write_dword(rtlpriv, + EDCAPARA_BE, + edca_gmode); + else + rtl_write_dword(rtlpriv, + EDCAPARA_BE, + edca_be_dl); + rtlpriv->dm.is_cur_rdlstate = true; + } + } + rtlpriv->dm.current_turbo_edca = true; + } else { + if (cur_rxok_cnt > 4 * cur_txok_cnt) { + if (!rtlpriv->dm.is_cur_rdlstate || + !rtlpriv->dm.current_turbo_edca) { + if (mac->mode == WIRELESS_MODE_G || + mac->mode == WIRELESS_MODE_B) + rtl_write_dword(rtlpriv, + EDCAPARA_BE, + edca_gmode); + else + rtl_write_dword(rtlpriv, + EDCAPARA_BE, + edca_be_dl); + rtlpriv->dm.is_cur_rdlstate = true; + } + } else { + if (rtlpriv->dm.is_cur_rdlstate || + !rtlpriv->dm.current_turbo_edca) { + rtl_write_dword(rtlpriv, EDCAPARA_BE, + edca_be_ul); + rtlpriv->dm.is_cur_rdlstate = false; + } + } + rtlpriv->dm.current_turbo_edca = true; + } + } else { + if (rtlpriv->dm.current_turbo_edca) { + u8 tmp = AC0_BE; + rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_AC_PARAM, + (u8 *)(&tmp)); + rtlpriv->dm.current_turbo_edca = false; + } + } + +dm_checkedcaturbo_exit: + rtlpriv->dm.is_any_nonbepkts = false; + last_txok_cnt = rtlpriv->stats.txbytesunicast; + last_rxok_cnt = rtlpriv->stats.rxbytesunicast; +} + +static void _rtl92s_dm_txpowertracking_callback_thermalmeter( + struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw)); + u8 thermalvalue = 0; + + rtlpriv->dm.txpower_trackinginit = true; + + thermalvalue = (u8)rtl_get_rfreg(hw, RF90_PATH_A, RF_T_METER, 0x1f); + + RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD, + ("Readback Thermal Meter = 0x%x pre thermal meter 0x%x " + "eeprom_thermalmeter 0x%x\n", thermalvalue, + rtlpriv->dm.thermalvalue, rtlefuse->eeprom_thermalmeter)); + + if (thermalvalue) { + rtlpriv->dm.thermalvalue = thermalvalue; + rtl92s_phy_set_fw_cmd(hw, FW_CMD_TXPWR_TRACK_THERMAL); + } + + rtlpriv->dm.txpowercount = 0; +} + +static void _rtl92s_dm_check_txpowertracking_thermalmeter( + struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_phy *rtlphy = &(rtlpriv->phy); + static u8 tm_trigger; + u8 tx_power_checkcnt = 5; + + /* 2T2R TP issue */ + if (rtlphy->rf_type == RF_2T2R) + return; + + if (!rtlpriv->dm.txpower_tracking) + return; + + if (rtlpriv->dm.txpowercount <= tx_power_checkcnt) { + rtlpriv->dm.txpowercount++; + return; + } + + if (!tm_trigger) { + rtl_set_rfreg(hw, RF90_PATH_A, RF_T_METER, + RFREG_OFFSET_MASK, 0x60); + tm_trigger = 1; + } else { + _rtl92s_dm_txpowertracking_callback_thermalmeter(hw); + tm_trigger = 0; + } +} + +static void _rtl92s_dm_refresh_rateadaptive_mask(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); + struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); + struct rate_adaptive *ra = &(rtlpriv->ra); + + u32 low_rssi_thresh = 0; + u32 middle_rssi_thresh = 0; + u32 high_rssi_thresh = 0; + u8 rssi_level; + struct ieee80211_sta *sta = NULL; + + if (is_hal_stop(rtlhal)) + return; + + if (!rtlpriv->dm.useramask) + return; + + if (!rtlpriv->dm.inform_fw_driverctrldm) { + rtl92s_phy_set_fw_cmd(hw, FW_CMD_CTRL_DM_BY_DRIVER); + rtlpriv->dm.inform_fw_driverctrldm = true; + } + + rcu_read_lock(); + if (mac->opmode == NL80211_IFTYPE_STATION) + sta = get_sta(hw, mac->vif, mac->bssid); + if ((mac->link_state == MAC80211_LINKED) && + (mac->opmode == NL80211_IFTYPE_STATION)) { + switch (ra->pre_ratr_state) { + case DM_RATR_STA_HIGH: + high_rssi_thresh = 40; + middle_rssi_thresh = 30; + low_rssi_thresh = 20; + break; + case DM_RATR_STA_MIDDLE: + high_rssi_thresh = 44; + middle_rssi_thresh = 30; + low_rssi_thresh = 20; + break; + case DM_RATR_STA_LOW: + high_rssi_thresh = 44; + middle_rssi_thresh = 34; + low_rssi_thresh = 20; + break; + case DM_RATR_STA_ULTRALOW: + high_rssi_thresh = 44; + middle_rssi_thresh = 34; + low_rssi_thresh = 24; + break; + default: + high_rssi_thresh = 44; + middle_rssi_thresh = 34; + low_rssi_thresh = 24; + break; + } + + if (rtlpriv->dm.undecorated_smoothed_pwdb > + (long)high_rssi_thresh) { + ra->ratr_state = DM_RATR_STA_HIGH; + rssi_level = 1; + } else if (rtlpriv->dm.undecorated_smoothed_pwdb > + (long)middle_rssi_thresh) { + ra->ratr_state = DM_RATR_STA_LOW; + rssi_level = 3; + } else if (rtlpriv->dm.undecorated_smoothed_pwdb > + (long)low_rssi_thresh) { + ra->ratr_state = DM_RATR_STA_LOW; + rssi_level = 5; + } else { + ra->ratr_state = DM_RATR_STA_ULTRALOW; + rssi_level = 6; + } + + if (ra->pre_ratr_state != ra->ratr_state) { + RT_TRACE(rtlpriv, COMP_RATE, DBG_LOUD, ("RSSI = %ld " + "RSSI_LEVEL = %d PreState = %d, CurState = %d\n", + rtlpriv->dm.undecorated_smoothed_pwdb, + ra->ratr_state, + ra->pre_ratr_state, ra->ratr_state)); + + rtlpriv->cfg->ops->update_rate_tbl(hw, sta, + ra->ratr_state); + ra->pre_ratr_state = ra->ratr_state; + } + } + rcu_read_unlock(); +} + +static void _rtl92s_dm_switch_baseband_mrc(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); + struct rtl_phy *rtlphy = &(rtlpriv->phy); + struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); + bool current_mrc; + bool enable_mrc = true; + long tmpentry_maxpwdb = 0; + u8 rssi_a = 0; + u8 rssi_b = 0; + + if (is_hal_stop(rtlhal)) + return; + + if ((rtlphy->rf_type == RF_1T1R) || (rtlphy->rf_type == RF_2T2R)) + return; + + rtlpriv->cfg->ops->get_hw_reg(hw, HW_VAR_MRC, (u8 *)(¤t_mrc)); + + if (mac->link_state >= MAC80211_LINKED) { + if (rtlpriv->dm.undecorated_smoothed_pwdb > tmpentry_maxpwdb) { + rssi_a = rtlpriv->stats.rx_rssi_percentage[RF90_PATH_A]; + rssi_b = rtlpriv->stats.rx_rssi_percentage[RF90_PATH_B]; + } + } + + /* MRC settings would NOT affect TP on Wireless B mode. */ + if (mac->mode != WIRELESS_MODE_B) { + if ((rssi_a == 0) && (rssi_b == 0)) { + enable_mrc = true; + } else if (rssi_b > 30) { + /* Turn on B-Path */ + enable_mrc = true; + } else if (rssi_b < 5) { + /* Turn off B-path */ + enable_mrc = false; + /* Take care of RSSI differentiation. */ + } else if (rssi_a > 15 && (rssi_a >= rssi_b)) { + if ((rssi_a - rssi_b) > 15) + /* Turn off B-path */ + enable_mrc = false; + else if ((rssi_a - rssi_b) < 10) + /* Turn on B-Path */ + enable_mrc = true; + else + enable_mrc = current_mrc; + } else { + /* Turn on B-Path */ + enable_mrc = true; + } + } + + /* Update MRC settings if needed. */ + if (enable_mrc != current_mrc) + rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_MRC, + (u8 *)&enable_mrc); + +} + +void rtl92s_dm_init_edca_turbo(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + + rtlpriv->dm.current_turbo_edca = false; + rtlpriv->dm.is_any_nonbepkts = false; + rtlpriv->dm.is_cur_rdlstate = false; +} + +static void _rtl92s_dm_init_rate_adaptive_mask(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rate_adaptive *ra = &(rtlpriv->ra); + + ra->ratr_state = DM_RATR_STA_MAX; + ra->pre_ratr_state = DM_RATR_STA_MAX; + + if (rtlpriv->dm.dm_type == DM_TYPE_BYDRIVER) + rtlpriv->dm.useramask = true; + else + rtlpriv->dm.useramask = false; + + rtlpriv->dm.useramask = false; + rtlpriv->dm.inform_fw_driverctrldm = false; +} + +static void _rtl92s_dm_init_txpowertracking_thermalmeter( + struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + + rtlpriv->dm.txpower_tracking = true; + rtlpriv->dm.txpowercount = 0; + rtlpriv->dm.txpower_trackinginit = false; +} + +static void _rtl92s_dm_false_alarm_counter_statistics(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct false_alarm_statistics *falsealm_cnt = &(rtlpriv->falsealm_cnt); + u32 ret_value; + + ret_value = rtl_get_bbreg(hw, ROFDM_PHYCOUNTER1, MASKDWORD); + falsealm_cnt->cnt_parity_fail = ((ret_value & 0xffff0000) >> 16); + + ret_value = rtl_get_bbreg(hw, ROFDM_PHYCOUNTER2, MASKDWORD); + falsealm_cnt->cnt_rate_illegal = (ret_value & 0xffff); + falsealm_cnt->cnt_crc8_fail = ((ret_value & 0xffff0000) >> 16); + ret_value = rtl_get_bbreg(hw, ROFDM_PHYCOUNTER3, MASKDWORD); + falsealm_cnt->cnt_mcs_fail = (ret_value & 0xffff); + + falsealm_cnt->cnt_ofdm_fail = falsealm_cnt->cnt_parity_fail + + falsealm_cnt->cnt_rate_illegal + falsealm_cnt->cnt_crc8_fail + + falsealm_cnt->cnt_mcs_fail; + + /* read CCK false alarm */ + ret_value = rtl_get_bbreg(hw, 0xc64, MASKDWORD); + falsealm_cnt->cnt_cck_fail = (ret_value & 0xffff); + falsealm_cnt->cnt_all = falsealm_cnt->cnt_ofdm_fail + + falsealm_cnt->cnt_cck_fail; +} + +static void rtl92s_backoff_enable_flag(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct false_alarm_statistics *falsealm_cnt = &(rtlpriv->falsealm_cnt); + + if (falsealm_cnt->cnt_all > digtable.fa_highthresh) { + if ((digtable.backoff_val - 6) < + digtable.backoffval_range_min) + digtable.backoff_val = digtable.backoffval_range_min; + else + digtable.backoff_val -= 6; + } else if (falsealm_cnt->cnt_all < digtable.fa_lowthresh) { + if ((digtable.backoff_val + 6) > + digtable.backoffval_range_max) + digtable.backoff_val = + digtable.backoffval_range_max; + else + digtable.backoff_val += 6; + } +} + +static void _rtl92s_dm_initial_gain_sta_beforeconnect(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct false_alarm_statistics *falsealm_cnt = &(rtlpriv->falsealm_cnt); + static u8 initialized, force_write; + u8 initial_gain = 0; + + if ((digtable.pre_sta_connectstate == digtable.cur_sta_connectstate) || + (digtable.cur_sta_connectstate == DIG_STA_BEFORE_CONNECT)) { + if (digtable.cur_sta_connectstate == DIG_STA_BEFORE_CONNECT) { + if (rtlpriv->psc.rfpwr_state != ERFON) + return; + + if (digtable.backoff_enable_flag == true) + rtl92s_backoff_enable_flag(hw); + else + digtable.backoff_val = DM_DIG_BACKOFF; + + if ((digtable.rssi_val + 10 - digtable.backoff_val) > + digtable.rx_gain_range_max) + digtable.cur_igvalue = + digtable.rx_gain_range_max; + else if ((digtable.rssi_val + 10 - digtable.backoff_val) + < digtable.rx_gain_range_min) + digtable.cur_igvalue = + digtable.rx_gain_range_min; + else + digtable.cur_igvalue = digtable.rssi_val + 10 - + digtable.backoff_val; + + if (falsealm_cnt->cnt_all > 10000) + digtable.cur_igvalue = + (digtable.cur_igvalue > 0x33) ? + digtable.cur_igvalue : 0x33; + + if (falsealm_cnt->cnt_all > 16000) + digtable.cur_igvalue = + digtable.rx_gain_range_max; + /* connected -> connected or disconnected -> disconnected */ + } else { + /* Firmware control DIG, do nothing in driver dm */ + return; + } + /* disconnected -> connected or connected -> + * disconnected or beforeconnect->(dis)connected */ + } else { + /* Enable FW DIG */ + digtable.dig_ext_port_stage = DIG_EXT_PORT_STAGE_MAX; + rtl92s_phy_set_fw_cmd(hw, FW_CMD_DIG_ENABLE); + + digtable.backoff_val = DM_DIG_BACKOFF; + digtable.cur_igvalue = rtlpriv->phy.default_initialgain[0]; + digtable.pre_igvalue = 0; + return; + } + + /* Forced writing to prevent from fw-dig overwriting. */ + if (digtable.pre_igvalue != rtl_get_bbreg(hw, ROFDM0_XAAGCCORE1, + MASKBYTE0)) + force_write = 1; + + if ((digtable.pre_igvalue != digtable.cur_igvalue) || + !initialized || force_write) { + /* Disable FW DIG */ + rtl92s_phy_set_fw_cmd(hw, FW_CMD_DIG_DISABLE); + + initial_gain = (u8)digtable.cur_igvalue; + + /* Set initial gain. */ + rtl_set_bbreg(hw, ROFDM0_XAAGCCORE1, MASKBYTE0, initial_gain); + rtl_set_bbreg(hw, ROFDM0_XBAGCCORE1, MASKBYTE0, initial_gain); + digtable.pre_igvalue = digtable.cur_igvalue; + initialized = 1; + force_write = 0; + } +} + +static void _rtl92s_dm_ctrl_initgain_bytwoport(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + + if (rtlpriv->mac80211.act_scanning) + return; + + /* Decide the current status and if modify initial gain or not */ + if (rtlpriv->mac80211.link_state >= MAC80211_LINKED || + rtlpriv->mac80211.opmode == NL80211_IFTYPE_ADHOC) + digtable.cur_sta_connectstate = DIG_STA_CONNECT; + else + digtable.cur_sta_connectstate = DIG_STA_DISCONNECT; + + digtable.rssi_val = rtlpriv->dm.undecorated_smoothed_pwdb; + + /* Change dig mode to rssi */ + if (digtable.cur_sta_connectstate != DIG_STA_DISCONNECT) { + if (digtable.dig_twoport_algorithm == + DIG_TWO_PORT_ALGO_FALSE_ALARM) { + digtable.dig_twoport_algorithm = DIG_TWO_PORT_ALGO_RSSI; + rtl92s_phy_set_fw_cmd(hw, FW_CMD_DIG_MODE_SS); + } + } + + _rtl92s_dm_false_alarm_counter_statistics(hw); + _rtl92s_dm_initial_gain_sta_beforeconnect(hw); + + digtable.pre_sta_connectstate = digtable.cur_sta_connectstate; +} + +static void _rtl92s_dm_ctrl_initgain_byrssi(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_phy *rtlphy = &(rtlpriv->phy); + + /* 2T2R TP issue */ + if (rtlphy->rf_type == RF_2T2R) + return; + + if (!rtlpriv->dm.dm_initialgain_enable) + return; + + if (digtable.dig_enable_flag == false) + return; + + _rtl92s_dm_ctrl_initgain_bytwoport(hw); +} + +static void _rtl92s_dm_dynamic_txpower(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_phy *rtlphy = &(rtlpriv->phy); + struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); + long undecorated_smoothed_pwdb; + long txpwr_threshold_lv1, txpwr_threshold_lv2; + + /* 2T2R TP issue */ + if (rtlphy->rf_type == RF_2T2R) + return; + + if (!rtlpriv->dm.dynamic_txpower_enable || + rtlpriv->dm.dm_flag & HAL_DM_HIPWR_DISABLE) { + rtlpriv->dm.dynamic_txhighpower_lvl = TX_HIGHPWR_LEVEL_NORMAL; + return; + } + + if ((mac->link_state < MAC80211_LINKED) && + (rtlpriv->dm.entry_min_undecoratedsmoothed_pwdb == 0)) { + RT_TRACE(rtlpriv, COMP_POWER, DBG_TRACE, + ("Not connected to any\n")); + + rtlpriv->dm.dynamic_txhighpower_lvl = TX_HIGHPWR_LEVEL_NORMAL; + + rtlpriv->dm.last_dtp_lvl = TX_HIGHPWR_LEVEL_NORMAL; + return; + } + + if (mac->link_state >= MAC80211_LINKED) { + if (mac->opmode == NL80211_IFTYPE_ADHOC) { + undecorated_smoothed_pwdb = + rtlpriv->dm.entry_min_undecoratedsmoothed_pwdb; + RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD, + ("AP Client PWDB = 0x%lx\n", + undecorated_smoothed_pwdb)); + } else { + undecorated_smoothed_pwdb = + rtlpriv->dm.undecorated_smoothed_pwdb; + RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD, + ("STA Default Port PWDB = 0x%lx\n", + undecorated_smoothed_pwdb)); + } + } else { + undecorated_smoothed_pwdb = + rtlpriv->dm.entry_min_undecoratedsmoothed_pwdb; + + RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD, + ("AP Ext Port PWDB = 0x%lx\n", + undecorated_smoothed_pwdb)); + } + + txpwr_threshold_lv2 = TX_POWER_NEAR_FIELD_THRESH_LVL2; + txpwr_threshold_lv1 = TX_POWER_NEAR_FIELD_THRESH_LVL1; + + if (rtl_get_bbreg(hw, 0xc90, MASKBYTE0) == 1) + rtlpriv->dm.dynamic_txhighpower_lvl = TX_HIGHPWR_LEVEL_NORMAL; + else if (undecorated_smoothed_pwdb >= txpwr_threshold_lv2) + rtlpriv->dm.dynamic_txhighpower_lvl = TX_HIGHPWR_LEVEL_NORMAL2; + else if ((undecorated_smoothed_pwdb < (txpwr_threshold_lv2 - 3)) && + (undecorated_smoothed_pwdb >= txpwr_threshold_lv1)) + rtlpriv->dm.dynamic_txhighpower_lvl = TX_HIGHPWR_LEVEL_NORMAL1; + else if (undecorated_smoothed_pwdb < (txpwr_threshold_lv1 - 3)) + rtlpriv->dm.dynamic_txhighpower_lvl = TX_HIGHPWR_LEVEL_NORMAL; + + if ((rtlpriv->dm.dynamic_txhighpower_lvl != rtlpriv->dm.last_dtp_lvl)) + rtl92s_phy_set_txpower(hw, rtlphy->current_channel); + + rtlpriv->dm.last_dtp_lvl = rtlpriv->dm.dynamic_txhighpower_lvl; +} + +static void _rtl92s_dm_init_dig(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + + /* Disable DIG scheme now.*/ + digtable.dig_enable_flag = true; + digtable.backoff_enable_flag = true; + + if ((rtlpriv->dm.dm_type == DM_TYPE_BYDRIVER) && + (hal_get_firmwareversion(rtlpriv) >= 0x3c)) + digtable.dig_algorithm = DIG_ALGO_BY_TOW_PORT; + else + digtable.dig_algorithm = + DIG_ALGO_BEFORE_CONNECT_BY_RSSI_AND_ALARM; + + digtable.dig_twoport_algorithm = DIG_TWO_PORT_ALGO_RSSI; + digtable.dig_ext_port_stage = DIG_EXT_PORT_STAGE_MAX; + /* off=by real rssi value, on=by digtable.rssi_val for new dig */ + digtable.dig_dbgmode = DM_DBG_OFF; + digtable.dig_slgorithm_switch = 0; + + /* 2007/10/04 MH Define init gain threshol. */ + digtable.dig_state = DM_STA_DIG_MAX; + digtable.dig_highpwrstate = DM_STA_DIG_MAX; + + digtable.cur_sta_connectstate = DIG_STA_DISCONNECT; + digtable.pre_sta_connectstate = DIG_STA_DISCONNECT; + digtable.cur_ap_connectstate = DIG_AP_DISCONNECT; + digtable.pre_ap_connectstate = DIG_AP_DISCONNECT; + + digtable.rssi_lowthresh = DM_DIG_THRESH_LOW; + digtable.rssi_highthresh = DM_DIG_THRESH_HIGH; + + digtable.fa_lowthresh = DM_FALSEALARM_THRESH_LOW; + digtable.fa_highthresh = DM_FALSEALARM_THRESH_HIGH; + + digtable.rssi_highpower_lowthresh = DM_DIG_HIGH_PWR_THRESH_LOW; + digtable.rssi_highpower_highthresh = DM_DIG_HIGH_PWR_THRESH_HIGH; + + /* for dig debug rssi value */ + digtable.rssi_val = 50; + digtable.backoff_val = DM_DIG_BACKOFF; + digtable.rx_gain_range_max = DM_DIG_MAX; + + digtable.rx_gain_range_min = DM_DIG_MIN; + + digtable.backoffval_range_max = DM_DIG_BACKOFF_MAX; + digtable.backoffval_range_min = DM_DIG_BACKOFF_MIN; +} + +static void _rtl92s_dm_init_dynamic_txpower(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + + if ((hal_get_firmwareversion(rtlpriv) >= 60) && + (rtlpriv->dm.dm_type == DM_TYPE_BYDRIVER)) + rtlpriv->dm.dynamic_txpower_enable = true; + else + rtlpriv->dm.dynamic_txpower_enable = false; + + rtlpriv->dm.last_dtp_lvl = TX_HIGHPWR_LEVEL_NORMAL; + rtlpriv->dm.dynamic_txhighpower_lvl = TX_HIGHPWR_LEVEL_NORMAL; +} + +void rtl92s_dm_init(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + + rtlpriv->dm.dm_type = DM_TYPE_BYDRIVER; + rtlpriv->dm.undecorated_smoothed_pwdb = -1; + + _rtl92s_dm_init_dynamic_txpower(hw); + rtl92s_dm_init_edca_turbo(hw); + _rtl92s_dm_init_rate_adaptive_mask(hw); + _rtl92s_dm_init_txpowertracking_thermalmeter(hw); + _rtl92s_dm_init_dig(hw); + + rtl_write_dword(rtlpriv, WFM5, FW_CCA_CHK_ENABLE); +} + +void rtl92s_dm_watchdog(struct ieee80211_hw *hw) +{ + _rtl92s_dm_check_edca_turbo(hw); + _rtl92s_dm_check_txpowertracking_thermalmeter(hw); + _rtl92s_dm_ctrl_initgain_byrssi(hw); + _rtl92s_dm_dynamic_txpower(hw); + _rtl92s_dm_refresh_rateadaptive_mask(hw); + _rtl92s_dm_switch_baseband_mrc(hw); +} + diff --git a/drivers/net/wireless/rtlwifi/rtl8192se/dm.h b/drivers/net/wireless/rtlwifi/rtl8192se/dm.h new file mode 100644 index 0000000..9051a55 --- /dev/null +++ b/drivers/net/wireless/rtlwifi/rtl8192se/dm.h @@ -0,0 +1,164 @@ +/****************************************************************************** + * + * Copyright(c) 2009-2010 Realtek Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger + * + *****************************************************************************/ +#ifndef __RTL_92S_DM_H__ +#define __RTL_92S_DM_H__ + +struct dig_t { + u8 dig_enable_flag; + u8 dig_algorithm; + u8 dig_twoport_algorithm; + u8 dig_ext_port_stage; + u8 dig_dbgmode; + u8 dig_slgorithm_switch; + + long rssi_lowthresh; + long rssi_highthresh; + + u32 fa_lowthresh; + u32 fa_highthresh; + + long rssi_highpower_lowthresh; + long rssi_highpower_highthresh; + + u8 dig_state; + u8 dig_highpwrstate; + u8 cur_sta_connectstate; + u8 pre_sta_connectstate; + u8 cur_ap_connectstate; + u8 pre_ap_connectstate; + + u8 cur_pd_thstate; + u8 pre_pd_thstate; + u8 cur_cs_ratiostate; + u8 pre_cs_ratiostate; + + u32 pre_igvalue; + u32 cur_igvalue; + + u8 backoff_enable_flag; + char backoff_val; + char backoffval_range_max; + char backoffval_range_min; + u8 rx_gain_range_max; + u8 rx_gain_range_min; + + long rssi_val; +}; + +enum dm_dig_alg { + DIG_ALGO_BY_FALSE_ALARM = 0, + DIG_ALGO_BY_RSSI = 1, + DIG_ALGO_BEFORE_CONNECT_BY_RSSI_AND_ALARM = 2, + DIG_ALGO_BY_TOW_PORT = 3, + DIG_ALGO_MAX +}; + +enum dm_dig_two_port_alg { + DIG_TWO_PORT_ALGO_RSSI = 0, + DIG_TWO_PORT_ALGO_FALSE_ALARM = 1, +}; + +enum dm_dig_dbg { + DM_DBG_OFF = 0, + DM_DBG_ON = 1, + DM_DBG_MAX +}; + +enum dm_dig_sta { + DM_STA_DIG_OFF = 0, + DM_STA_DIG_ON, + DM_STA_DIG_MAX +}; + +enum dm_dig_connect { + DIG_STA_DISCONNECT = 0, + DIG_STA_CONNECT = 1, + DIG_STA_BEFORE_CONNECT = 2, + DIG_AP_DISCONNECT = 3, + DIG_AP_CONNECT = 4, + DIG_AP_ADD_STATION = 5, + DIG_CONNECT_MAX +}; + +enum dm_dig_ext_port_alg { + DIG_EXT_PORT_STAGE_0 = 0, + DIG_EXT_PORT_STAGE_1 = 1, + DIG_EXT_PORT_STAGE_2 = 2, + DIG_EXT_PORT_STAGE_3 = 3, + DIG_EXT_PORT_STAGE_MAX = 4, +}; + +enum dm_ratr_sta { + DM_RATR_STA_HIGH = 0, + DM_RATR_STA_MIDDLEHIGH = 1, + DM_RATR_STA_MIDDLE = 2, + DM_RATR_STA_MIDDLELOW = 3, + DM_RATR_STA_LOW = 4, + DM_RATR_STA_ULTRALOW = 5, + DM_RATR_STA_MAX +}; + +#define DM_TYPE_BYFW 0 +#define DM_TYPE_BYDRIVER 1 + +#define TX_HIGH_PWR_LEVEL_NORMAL 0 +#define TX_HIGH_PWR_LEVEL_LEVEL1 1 +#define TX_HIGH_PWR_LEVEL_LEVEL2 2 + +#define HAL_DM_DIG_DISABLE BIT(0) /* Disable Dig */ +#define HAL_DM_HIPWR_DISABLE BIT(1) /* Disable High Power */ + +#define TX_HIGHPWR_LEVEL_NORMAL 0 +#define TX_HIGHPWR_LEVEL_NORMAL1 1 +#define TX_HIGHPWR_LEVEL_NORMAL2 2 + +#define TX_POWER_NEAR_FIELD_THRESH_LVL2 74 +#define TX_POWER_NEAR_FIELD_THRESH_LVL1 67 + +#define DM_DIG_THRESH_HIGH 40 +#define DM_DIG_THRESH_LOW 35 +#define DM_FALSEALARM_THRESH_LOW 40 +#define DM_FALSEALARM_THRESH_HIGH 1000 +#define DM_DIG_HIGH_PWR_THRESH_HIGH 75 +#define DM_DIG_HIGH_PWR_THRESH_LOW 70 +#define DM_DIG_BACKOFF 12 +#define DM_DIG_MAX 0x3e +#define DM_DIG_MIN 0x1c +#define DM_DIG_MIN_Netcore 0x12 +#define DM_DIG_BACKOFF_MAX 12 +#define DM_DIG_BACKOFF_MIN -4 + +extern struct dig_t digtable; + +void rtl92s_dm_watchdog(struct ieee80211_hw *hw); +void rtl92s_dm_init(struct ieee80211_hw *hw); +void rtl92s_dm_init_edca_turbo(struct ieee80211_hw *hw); + +#endif + -- cgit v0.10.2 From 701307a885b13a1790b94e232923de1d199e3cc9 Mon Sep 17 00:00:00 2001 From: Chaoming Li Date: Tue, 3 May 2011 09:48:05 -0500 Subject: rtlwifi: rtl8192se: Merge firmware routines Merge routines fw.c and fw.h for RTL8192SE. In addition, make changes to rtlwifi/wifi.h to support RTL8192SE. Signed-off-by: Chaoming_Li Signed-off-by: Larry Finger Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/rtlwifi/rtl8192se/fw.c b/drivers/net/wireless/rtlwifi/rtl8192se/fw.c new file mode 100644 index 0000000..3b5af01 --- /dev/null +++ b/drivers/net/wireless/rtlwifi/rtl8192se/fw.c @@ -0,0 +1,654 @@ +/****************************************************************************** + * + * Copyright(c) 2009-2010 Realtek Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger + * + *****************************************************************************/ + +#include "../wifi.h" +#include "../pci.h" +#include "../base.h" +#include "reg.h" +#include "def.h" +#include "fw.h" + +static void _rtl92s_fw_set_rqpn(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + + rtl_write_dword(rtlpriv, RQPN, 0xffffffff); + rtl_write_dword(rtlpriv, RQPN + 4, 0xffffffff); + rtl_write_byte(rtlpriv, RQPN + 8, 0xff); + rtl_write_byte(rtlpriv, RQPN + 0xB, 0x80); +} + +static bool _rtl92s_firmware_enable_cpu(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + u32 ichecktime = 200; + u16 tmpu2b; + u8 tmpu1b, cpustatus = 0; + + _rtl92s_fw_set_rqpn(hw); + + /* Enable CPU. */ + tmpu1b = rtl_read_byte(rtlpriv, SYS_CLKR); + /* AFE source */ + rtl_write_byte(rtlpriv, SYS_CLKR, (tmpu1b | SYS_CPU_CLKSEL)); + + tmpu2b = rtl_read_word(rtlpriv, REG_SYS_FUNC_EN); + rtl_write_word(rtlpriv, REG_SYS_FUNC_EN, (tmpu2b | FEN_CPUEN)); + + /* Polling IMEM Ready after CPU has refilled. */ + do { + cpustatus = rtl_read_byte(rtlpriv, TCR); + if (cpustatus & IMEM_RDY) { + RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, + ("IMEM Ready after CPU has refilled.\n")); + break; + } + + udelay(100); + } while (ichecktime--); + + if (!(cpustatus & IMEM_RDY)) + return false; + + return true; +} + +static enum fw_status _rtl92s_firmware_get_nextstatus( + enum fw_status fw_currentstatus) +{ + enum fw_status next_fwstatus = 0; + + switch (fw_currentstatus) { + case FW_STATUS_INIT: + next_fwstatus = FW_STATUS_LOAD_IMEM; + break; + case FW_STATUS_LOAD_IMEM: + next_fwstatus = FW_STATUS_LOAD_EMEM; + break; + case FW_STATUS_LOAD_EMEM: + next_fwstatus = FW_STATUS_LOAD_DMEM; + break; + case FW_STATUS_LOAD_DMEM: + next_fwstatus = FW_STATUS_READY; + break; + default: + break; + } + + return next_fwstatus; +} + +static u8 _rtl92s_firmware_header_map_rftype(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_phy *rtlphy = &(rtlpriv->phy); + + switch (rtlphy->rf_type) { + case RF_1T1R: + return 0x11; + break; + case RF_1T2R: + return 0x12; + break; + case RF_2T2R: + return 0x22; + break; + default: + RT_TRACE(rtlpriv, COMP_INIT, DBG_EMERG, + ("Unknown RF type(%x)\n", + rtlphy->rf_type)); + break; + } + return 0x22; +} + +static void _rtl92s_firmwareheader_priveupdate(struct ieee80211_hw *hw, + struct fw_priv *pfw_priv) +{ + /* Update RF types for RATR settings. */ + pfw_priv->rf_config = _rtl92s_firmware_header_map_rftype(hw); +} + + + +static bool _rtl92s_cmd_send_packet(struct ieee80211_hw *hw, + struct sk_buff *skb, u8 last) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); + struct rtl8192_tx_ring *ring; + struct rtl_tx_desc *pdesc; + unsigned long flags; + u8 idx = 0; + + ring = &rtlpci->tx_ring[TXCMD_QUEUE]; + + spin_lock_irqsave(&rtlpriv->locks.irq_th_lock, flags); + + idx = (ring->idx + skb_queue_len(&ring->queue)) % ring->entries; + pdesc = &ring->desc[idx]; + rtlpriv->cfg->ops->fill_tx_cmddesc(hw, (u8 *)pdesc, 1, 1, skb); + __skb_queue_tail(&ring->queue, skb); + + spin_unlock_irqrestore(&rtlpriv->locks.irq_th_lock, flags); + + return true; +} + +static bool _rtl92s_firmware_downloadcode(struct ieee80211_hw *hw, + u8 *code_virtual_address, u32 buffer_len) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct sk_buff *skb; + struct rtl_tcb_desc *tcb_desc; + unsigned char *seg_ptr; + u16 frag_threshold = MAX_FIRMWARE_CODE_SIZE; + u16 frag_length, frag_offset = 0; + u16 extra_descoffset = 0; + u8 last_inipkt = 0; + + _rtl92s_fw_set_rqpn(hw); + + if (buffer_len >= MAX_FIRMWARE_CODE_SIZE) { + RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, + ("Size over FIRMWARE_CODE_SIZE!\n")); + + return false; + } + + extra_descoffset = 0; + + do { + if ((buffer_len - frag_offset) > frag_threshold) { + frag_length = frag_threshold + extra_descoffset; + } else { + frag_length = (u16)(buffer_len - frag_offset + + extra_descoffset); + last_inipkt = 1; + } + + /* Allocate skb buffer to contain firmware */ + /* info and tx descriptor info. */ + skb = dev_alloc_skb(frag_length); + skb_reserve(skb, extra_descoffset); + seg_ptr = (u8 *)skb_put(skb, (u32)(frag_length - + extra_descoffset)); + memcpy(seg_ptr, code_virtual_address + frag_offset, + (u32)(frag_length - extra_descoffset)); + + tcb_desc = (struct rtl_tcb_desc *)(skb->cb); + tcb_desc->queue_index = TXCMD_QUEUE; + tcb_desc->cmd_or_init = DESC_PACKET_TYPE_INIT; + tcb_desc->last_inipkt = last_inipkt; + + _rtl92s_cmd_send_packet(hw, skb, last_inipkt); + + frag_offset += (frag_length - extra_descoffset); + + } while (frag_offset < buffer_len); + + rtl_write_byte(rtlpriv, TP_POLL, TPPOLL_CQ); + + return true ; +} + +static bool _rtl92s_firmware_checkready(struct ieee80211_hw *hw, + u8 loadfw_status) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); + struct rt_firmware *firmware = (struct rt_firmware *)rtlhal->pfirmware; + u32 tmpu4b; + u8 cpustatus = 0; + short pollingcnt = 1000; + bool rtstatus = true; + + RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, ("LoadStaus(%d)\n", + loadfw_status)); + + firmware->fwstatus = (enum fw_status)loadfw_status; + + switch (loadfw_status) { + case FW_STATUS_LOAD_IMEM: + /* Polling IMEM code done. */ + do { + cpustatus = rtl_read_byte(rtlpriv, TCR); + if (cpustatus & IMEM_CODE_DONE) + break; + udelay(5); + } while (pollingcnt--); + + if (!(cpustatus & IMEM_CHK_RPT) || (pollingcnt <= 0)) { + RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, + ("FW_STATUS_LOAD_IMEM" + " FAIL CPU, Status=%x\r\n", cpustatus)); + goto status_check_fail; + } + break; + + case FW_STATUS_LOAD_EMEM: + /* Check Put Code OK and Turn On CPU */ + /* Polling EMEM code done. */ + do { + cpustatus = rtl_read_byte(rtlpriv, TCR); + if (cpustatus & EMEM_CODE_DONE) + break; + udelay(5); + } while (pollingcnt--); + + if (!(cpustatus & EMEM_CHK_RPT) || (pollingcnt <= 0)) { + RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, + ("FW_STATUS_LOAD_EMEM" + " FAIL CPU, Status=%x\r\n", cpustatus)); + goto status_check_fail; + } + + /* Turn On CPU */ + rtstatus = _rtl92s_firmware_enable_cpu(hw); + if (rtstatus != true) { + RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, + ("Enable CPU fail!\n")); + goto status_check_fail; + } + break; + + case FW_STATUS_LOAD_DMEM: + /* Polling DMEM code done */ + do { + cpustatus = rtl_read_byte(rtlpriv, TCR); + if (cpustatus & DMEM_CODE_DONE) + break; + udelay(5); + } while (pollingcnt--); + + if (!(cpustatus & DMEM_CODE_DONE) || (pollingcnt <= 0)) { + RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, + ("Polling DMEM code done" + " fail ! cpustatus(%#x)\n", cpustatus)); + goto status_check_fail; + } + + RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, + ("DMEM code download success," + " cpustatus(%#x)\n", cpustatus)); + + /* Prevent Delay too much and being scheduled out */ + /* Polling Load Firmware ready */ + pollingcnt = 2000; + do { + cpustatus = rtl_read_byte(rtlpriv, TCR); + if (cpustatus & FWRDY) + break; + udelay(40); + } while (pollingcnt--); + + RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, + ("Polling Load Firmware ready," + " cpustatus(%x)\n", cpustatus)); + + if (((cpustatus & LOAD_FW_READY) != LOAD_FW_READY) || + (pollingcnt <= 0)) { + RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, + ("Polling Load Firmware" + " ready fail ! cpustatus(%x)\n", cpustatus)); + goto status_check_fail; + } + + /* If right here, we can set TCR/RCR to desired value */ + /* and config MAC lookback mode to normal mode */ + tmpu4b = rtl_read_dword(rtlpriv, TCR); + rtl_write_dword(rtlpriv, TCR, (tmpu4b & (~TCR_ICV))); + + tmpu4b = rtl_read_dword(rtlpriv, RCR); + rtl_write_dword(rtlpriv, RCR, (tmpu4b | RCR_APPFCS | + RCR_APP_ICV | RCR_APP_MIC)); + + RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, + ("Current RCR settings(%#x)\n", tmpu4b)); + + /* Set to normal mode. */ + rtl_write_byte(rtlpriv, LBKMD_SEL, LBK_NORMAL); + break; + + default: + RT_TRACE(rtlpriv, COMP_INIT, DBG_EMERG, + ("Unknown status check!\n")); + rtstatus = false; + break; + } + +status_check_fail: + RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, ("loadfw_status(%d), " + "rtstatus(%x)\n", loadfw_status, rtstatus)); + return rtstatus; +} + +int rtl92s_download_fw(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); + struct rt_firmware *firmware = NULL; + struct fw_hdr *pfwheader; + struct fw_priv *pfw_priv = NULL; + u8 *puc_mappedfile = NULL; + u32 ul_filelength = 0; + u32 file_length = 0; + u8 fwhdr_size = RT_8192S_FIRMWARE_HDR_SIZE; + u8 fwstatus = FW_STATUS_INIT; + bool rtstatus = true; + + if (!rtlhal->pfirmware) + return 1; + + firmware = (struct rt_firmware *)rtlhal->pfirmware; + firmware->fwstatus = FW_STATUS_INIT; + + puc_mappedfile = firmware->sz_fw_tmpbuffer; + file_length = firmware->sz_fw_tmpbufferlen; + + /* 1. Retrieve FW header. */ + firmware->pfwheader = (struct fw_hdr *) puc_mappedfile; + pfwheader = firmware->pfwheader; + firmware->firmwareversion = byte(pfwheader->version, 0); + firmware->pfwheader->fwpriv.hci_sel = 1;/* pcie */ + + RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, ("signature:%x, version:" + "%x, size:%x," + "imemsize:%x, sram size:%x\n", pfwheader->signature, + pfwheader->version, pfwheader->dmem_size, + pfwheader->img_imem_size, pfwheader->img_sram_size)); + + /* 2. Retrieve IMEM image. */ + if ((pfwheader->img_imem_size == 0) || (pfwheader->img_imem_size > + sizeof(firmware->fw_imem))) { + RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, + ("memory for data image is less than IMEM required\n")); + goto fail; + } else { + puc_mappedfile += fwhdr_size; + + memcpy(firmware->fw_imem, puc_mappedfile, + pfwheader->img_imem_size); + firmware->fw_imem_len = pfwheader->img_imem_size; + } + + /* 3. Retriecve EMEM image. */ + if (pfwheader->img_sram_size > sizeof(firmware->fw_emem)) { + RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, + ("memory for data image is less than EMEM required\n")); + goto fail; + } else { + puc_mappedfile += firmware->fw_imem_len; + + memcpy(firmware->fw_emem, puc_mappedfile, + pfwheader->img_sram_size); + firmware->fw_emem_len = pfwheader->img_sram_size; + } + + /* 4. download fw now */ + fwstatus = _rtl92s_firmware_get_nextstatus(firmware->fwstatus); + while (fwstatus != FW_STATUS_READY) { + /* Image buffer redirection. */ + switch (fwstatus) { + case FW_STATUS_LOAD_IMEM: + puc_mappedfile = firmware->fw_imem; + ul_filelength = firmware->fw_imem_len; + break; + case FW_STATUS_LOAD_EMEM: + puc_mappedfile = firmware->fw_emem; + ul_filelength = firmware->fw_emem_len; + break; + case FW_STATUS_LOAD_DMEM: + /* Partial update the content of header private. */ + pfwheader = firmware->pfwheader; + pfw_priv = &pfwheader->fwpriv; + _rtl92s_firmwareheader_priveupdate(hw, pfw_priv); + puc_mappedfile = (u8 *)(firmware->pfwheader) + + RT_8192S_FIRMWARE_HDR_EXCLUDE_PRI_SIZE; + ul_filelength = fwhdr_size - + RT_8192S_FIRMWARE_HDR_EXCLUDE_PRI_SIZE; + break; + default: + RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, + ("Unexpected Download step!!\n")); + goto fail; + break; + } + + /* <2> Download image file */ + rtstatus = _rtl92s_firmware_downloadcode(hw, puc_mappedfile, + ul_filelength); + + if (rtstatus != true) { + RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, ("fail!\n")); + goto fail; + } + + /* <3> Check whether load FW process is ready */ + rtstatus = _rtl92s_firmware_checkready(hw, fwstatus); + if (rtstatus != true) { + RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, ("fail!\n")); + goto fail; + } + + fwstatus = _rtl92s_firmware_get_nextstatus(firmware->fwstatus); + } + + return rtstatus; +fail: + return 0; +} + +static u32 _rtl92s_fill_h2c_cmd(struct sk_buff *skb, u32 h2cbufferlen, + u32 cmd_num, u32 *pelement_id, u32 *pcmd_len, + u8 **pcmb_buffer, u8 *cmd_start_seq) +{ + u32 totallen = 0, len = 0, tx_desclen = 0; + u32 pre_continueoffset = 0; + u8 *ph2c_buffer; + u8 i = 0; + + do { + /* 8 - Byte aligment */ + len = H2C_TX_CMD_HDR_LEN + N_BYTE_ALIGMENT(pcmd_len[i], 8); + + /* Buffer length is not enough */ + if (h2cbufferlen < totallen + len + tx_desclen) + break; + + /* Clear content */ + ph2c_buffer = (u8 *)skb_put(skb, (u32)len); + memset((ph2c_buffer + totallen + tx_desclen), 0, len); + + /* CMD len */ + SET_BITS_TO_LE_4BYTE((ph2c_buffer + totallen + tx_desclen), + 0, 16, pcmd_len[i]); + + /* CMD ID */ + SET_BITS_TO_LE_4BYTE((ph2c_buffer + totallen + tx_desclen), + 16, 8, pelement_id[i]); + + /* CMD Sequence */ + *cmd_start_seq = *cmd_start_seq % 0x80; + SET_BITS_TO_LE_4BYTE((ph2c_buffer + totallen + tx_desclen), + 24, 7, *cmd_start_seq); + ++*cmd_start_seq; + + /* Copy memory */ + memcpy((ph2c_buffer + totallen + tx_desclen + + H2C_TX_CMD_HDR_LEN), pcmb_buffer[i], pcmd_len[i]); + + /* CMD continue */ + /* set the continue in prevoius cmd. */ + if (i < cmd_num - 1) + SET_BITS_TO_LE_4BYTE((ph2c_buffer + pre_continueoffset), + 31, 1, 1); + + pre_continueoffset = totallen; + + totallen += len; + } while (++i < cmd_num); + + return totallen; +} + +static u32 _rtl92s_get_h2c_cmdlen(u32 h2cbufferlen, u32 cmd_num, u32 *pcmd_len) +{ + u32 totallen = 0, len = 0, tx_desclen = 0; + u8 i = 0; + + do { + /* 8 - Byte aligment */ + len = H2C_TX_CMD_HDR_LEN + N_BYTE_ALIGMENT(pcmd_len[i], 8); + + /* Buffer length is not enough */ + if (h2cbufferlen < totallen + len + tx_desclen) + break; + + totallen += len; + } while (++i < cmd_num); + + return totallen + tx_desclen; +} + +static bool _rtl92s_firmware_set_h2c_cmd(struct ieee80211_hw *hw, u8 h2c_cmd, + u8 *pcmd_buffer) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); + struct rtl_tcb_desc *cb_desc; + struct sk_buff *skb; + u32 element_id = 0; + u32 cmd_len = 0; + u32 len; + + switch (h2c_cmd) { + case FW_H2C_SETPWRMODE: + element_id = H2C_SETPWRMODE_CMD ; + cmd_len = sizeof(struct h2c_set_pwrmode_parm); + break; + case FW_H2C_JOINBSSRPT: + element_id = H2C_JOINBSSRPT_CMD; + cmd_len = sizeof(struct h2c_joinbss_rpt_parm); + break; + case FW_H2C_WOWLAN_UPDATE_GTK: + element_id = H2C_WOWLAN_UPDATE_GTK_CMD; + cmd_len = sizeof(struct h2c_wpa_two_way_parm); + break; + case FW_H2C_WOWLAN_UPDATE_IV: + element_id = H2C_WOWLAN_UPDATE_IV_CMD; + cmd_len = sizeof(unsigned long long); + break; + case FW_H2C_WOWLAN_OFFLOAD: + element_id = H2C_WOWLAN_FW_OFFLOAD; + cmd_len = sizeof(u8); + break; + default: + break; + } + + len = _rtl92s_get_h2c_cmdlen(MAX_TRANSMIT_BUFFER_SIZE, 1, &cmd_len); + skb = dev_alloc_skb(len); + cb_desc = (struct rtl_tcb_desc *)(skb->cb); + cb_desc->queue_index = TXCMD_QUEUE; + cb_desc->cmd_or_init = DESC_PACKET_TYPE_NORMAL; + cb_desc->last_inipkt = false; + + _rtl92s_fill_h2c_cmd(skb, MAX_TRANSMIT_BUFFER_SIZE, 1, &element_id, + &cmd_len, &pcmd_buffer, &rtlhal->h2c_txcmd_seq); + _rtl92s_cmd_send_packet(hw, skb, false); + rtlpriv->cfg->ops->tx_polling(hw, TXCMD_QUEUE); + + return true; +} + +void rtl92s_set_fw_pwrmode_cmd(struct ieee80211_hw *hw, u8 Mode) +{ + struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); + struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); + struct h2c_set_pwrmode_parm pwrmode; + u16 max_wakeup_period = 0; + + pwrmode.mode = Mode; + pwrmode.flag_low_traffic_en = 0; + pwrmode.flag_lpnav_en = 0; + pwrmode.flag_rf_low_snr_en = 0; + pwrmode.flag_dps_en = 0; + pwrmode.bcn_rx_en = 0; + pwrmode.bcn_to = 0; + SET_BITS_TO_LE_2BYTE((u8 *)(&pwrmode) + 8, 0, 16, + mac->vif->bss_conf.beacon_int); + pwrmode.app_itv = 0; + pwrmode.awake_bcn_itvl = ppsc->reg_max_lps_awakeintvl; + pwrmode.smart_ps = 1; + pwrmode.bcn_pass_period = 10; + + /* Set beacon pass count */ + if (pwrmode.mode == FW_PS_MIN_MODE) + max_wakeup_period = mac->vif->bss_conf.beacon_int; + else if (pwrmode.mode == FW_PS_MAX_MODE) + max_wakeup_period = mac->vif->bss_conf.beacon_int * + mac->vif->bss_conf.dtim_period; + + if (max_wakeup_period >= 500) + pwrmode.bcn_pass_cnt = 1; + else if ((max_wakeup_period >= 300) && (max_wakeup_period < 500)) + pwrmode.bcn_pass_cnt = 2; + else if ((max_wakeup_period >= 200) && (max_wakeup_period < 300)) + pwrmode.bcn_pass_cnt = 3; + else if ((max_wakeup_period >= 20) && (max_wakeup_period < 200)) + pwrmode.bcn_pass_cnt = 5; + else + pwrmode.bcn_pass_cnt = 1; + + _rtl92s_firmware_set_h2c_cmd(hw, FW_H2C_SETPWRMODE, (u8 *)&pwrmode); + +} + +void rtl92s_set_fw_joinbss_report_cmd(struct ieee80211_hw *hw, + u8 mstatus, u8 ps_qosinfo) +{ + struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); + struct h2c_joinbss_rpt_parm joinbss_rpt; + + joinbss_rpt.opmode = mstatus; + joinbss_rpt.ps_qos_info = ps_qosinfo; + joinbss_rpt.bssid[0] = mac->bssid[0]; + joinbss_rpt.bssid[1] = mac->bssid[1]; + joinbss_rpt.bssid[2] = mac->bssid[2]; + joinbss_rpt.bssid[3] = mac->bssid[3]; + joinbss_rpt.bssid[4] = mac->bssid[4]; + joinbss_rpt.bssid[5] = mac->bssid[5]; + SET_BITS_TO_LE_2BYTE((u8 *)(&joinbss_rpt) + 8, 0, 16, + mac->vif->bss_conf.beacon_int); + SET_BITS_TO_LE_2BYTE((u8 *)(&joinbss_rpt) + 10, 0, 16, mac->assoc_id); + + _rtl92s_firmware_set_h2c_cmd(hw, FW_H2C_JOINBSSRPT, (u8 *)&joinbss_rpt); +} + diff --git a/drivers/net/wireless/rtlwifi/rtl8192se/fw.h b/drivers/net/wireless/rtlwifi/rtl8192se/fw.h new file mode 100644 index 0000000..74cc503 --- /dev/null +++ b/drivers/net/wireless/rtlwifi/rtl8192se/fw.h @@ -0,0 +1,375 @@ +/****************************************************************************** + * + * Copyright(c) 2009-2010 Realtek Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger + * + *****************************************************************************/ +#ifndef __REALTEK_FIRMWARE92S_H__ +#define __REALTEK_FIRMWARE92S_H__ + +#define RTL8190_MAX_FIRMWARE_CODE_SIZE 64000 +#define RTL8190_CPU_START_OFFSET 0x80 +/* Firmware Local buffer size. 64k */ +#define MAX_FIRMWARE_CODE_SIZE 0xFF00 + +#define RT_8192S_FIRMWARE_HDR_SIZE 80 +#define RT_8192S_FIRMWARE_HDR_EXCLUDE_PRI_SIZE 32 + +/* support till 64 bit bus width OS */ +#define MAX_DEV_ADDR_SIZE 8 +#define MAX_FIRMWARE_INFORMATION_SIZE 32 +#define MAX_802_11_HEADER_LENGTH (40 + \ + MAX_FIRMWARE_INFORMATION_SIZE) +#define ENCRYPTION_MAX_OVERHEAD 128 +#define MAX_FRAGMENT_COUNT 8 +#define MAX_TRANSMIT_BUFFER_SIZE (1600 + \ + (MAX_802_11_HEADER_LENGTH + \ + ENCRYPTION_MAX_OVERHEAD) *\ + MAX_FRAGMENT_COUNT) + +#define H2C_TX_CMD_HDR_LEN 8 + +/* The following DM control code are for Reg0x364, */ +#define FW_DIG_ENABLE_CTL BIT(0) +#define FW_HIGH_PWR_ENABLE_CTL BIT(1) +#define FW_SS_CTL BIT(2) +#define FW_RA_INIT_CTL BIT(3) +#define FW_RA_BG_CTL BIT(4) +#define FW_RA_N_CTL BIT(5) +#define FW_PWR_TRK_CTL BIT(6) +#define FW_IQK_CTL BIT(7) +#define FW_FA_CTL BIT(8) +#define FW_DRIVER_CTRL_DM_CTL BIT(9) +#define FW_PAPE_CTL_BY_SW_HW BIT(10) +#define FW_DISABLE_ALL_DM 0 +#define FW_PWR_TRK_PARAM_CLR 0x0000ffff +#define FW_RA_PARAM_CLR 0xffff0000 + +enum desc_packet_type { + DESC_PACKET_TYPE_INIT = 0, + DESC_PACKET_TYPE_NORMAL = 1, +}; + +/* 8-bytes alignment required */ +struct fw_priv { + /* --- long word 0 ---- */ + /* 0x12: CE product, 0x92: IT product */ + u8 signature_0; + /* 0x87: CE product, 0x81: IT product */ + u8 signature_1; + /* 0x81: PCI-AP, 01:PCIe, 02: 92S-U, + * 0x82: USB-AP, 0x12: 72S-U, 03:SDIO */ + u8 hci_sel; + /* the same value as reigster value */ + u8 chip_version; + /* customer ID low byte */ + u8 customer_id_0; + /* customer ID high byte */ + u8 customer_id_1; + /* 0x11: 1T1R, 0x12: 1T2R, + * 0x92: 1T2R turbo, 0x22: 2T2R */ + u8 rf_config; + /* 4: 4EP, 6: 6EP, 11: 11EP */ + u8 usb_ep_num; + + /* --- long word 1 ---- */ + /* regulatory class bit map 0 */ + u8 regulatory_class_0; + /* regulatory class bit map 1 */ + u8 regulatory_class_1; + /* regulatory class bit map 2 */ + u8 regulatory_class_2; + /* regulatory class bit map 3 */ + u8 regulatory_class_3; + /* 0:SWSI, 1:HWSI, 2:HWPI */ + u8 rfintfs; + u8 def_nettype; + u8 rsvd010; + u8 rsvd011; + + /* --- long word 2 ---- */ + /* 0x00: normal, 0x03: MACLBK, 0x01: PHYLBK */ + u8 lbk_mode; + /* 1: for MP use, 0: for normal + * driver (to be discussed) */ + u8 mp_mode; + u8 rsvd020; + u8 rsvd021; + u8 rsvd022; + u8 rsvd023; + u8 rsvd024; + u8 rsvd025; + + /* --- long word 3 ---- */ + /* QoS enable */ + u8 qos_en; + /* 40MHz BW enable */ + /* 4181 convert AMSDU to AMPDU, 0: disable */ + u8 bw_40mhz_en; + u8 amsdu2ampdu_en; + /* 11n AMPDU enable */ + u8 ampdu_en; + /* FW offloads, 0: driver handles */ + u8 rate_control_offload; + /* FW offloads, 0: driver handles */ + u8 aggregation_offload; + u8 rsvd030; + u8 rsvd031; + + /* --- long word 4 ---- */ + /* 1. FW offloads, 0: driver handles */ + u8 beacon_offload; + /* 2. FW offloads, 0: driver handles */ + u8 mlme_offload; + /* 3. FW offloads, 0: driver handles */ + u8 hwpc_offload; + /* 4. FW offloads, 0: driver handles */ + u8 tcp_checksum_offload; + /* 5. FW offloads, 0: driver handles */ + u8 tcp_offload; + /* 6. FW offloads, 0: driver handles */ + u8 ps_control_offload; + /* 7. FW offloads, 0: driver handles */ + u8 wwlan_offload; + u8 rsvd040; + + /* --- long word 5 ---- */ + /* tcp tx packet length low byte */ + u8 tcp_tx_frame_len_L; + /* tcp tx packet length high byte */ + u8 tcp_tx_frame_len_H; + /* tcp rx packet length low byte */ + u8 tcp_rx_frame_len_L; + /* tcp rx packet length high byte */ + u8 tcp_rx_frame_len_H; + u8 rsvd050; + u8 rsvd051; + u8 rsvd052; + u8 rsvd053; +}; + +/* 8-byte alinment required */ +struct fw_hdr { + + /* --- LONG WORD 0 ---- */ + u16 signature; + /* 0x8000 ~ 0x8FFF for FPGA version, + * 0x0000 ~ 0x7FFF for ASIC version, */ + u16 version; + /* define the size of boot loader */ + u32 dmem_size; + + + /* --- LONG WORD 1 ---- */ + /* define the size of FW in IMEM */ + u32 img_imem_size; + /* define the size of FW in SRAM */ + u32 img_sram_size; + + /* --- LONG WORD 2 ---- */ + /* define the size of DMEM variable */ + u32 fw_priv_size; + u32 rsvd0; + + /* --- LONG WORD 3 ---- */ + u32 rsvd1; + u32 rsvd2; + + struct fw_priv fwpriv; + +} ; + +enum fw_status { + FW_STATUS_INIT = 0, + FW_STATUS_LOAD_IMEM = 1, + FW_STATUS_LOAD_EMEM = 2, + FW_STATUS_LOAD_DMEM = 3, + FW_STATUS_READY = 4, +}; + +struct rt_firmware { + struct fw_hdr *pfwheader; + enum fw_status fwstatus; + u16 firmwareversion; + u8 fw_imem[RTL8190_MAX_FIRMWARE_CODE_SIZE]; + u8 fw_emem[RTL8190_MAX_FIRMWARE_CODE_SIZE]; + u32 fw_imem_len; + u32 fw_emem_len; + u8 sz_fw_tmpbuffer[164000]; + u32 sz_fw_tmpbufferlen; + u16 cmdpacket_fragthresold; +}; + +struct h2c_set_pwrmode_parm { + u8 mode; + u8 flag_low_traffic_en; + u8 flag_lpnav_en; + u8 flag_rf_low_snr_en; + /* 1: dps, 0: 32k */ + u8 flag_dps_en; + u8 bcn_rx_en; + u8 bcn_pass_cnt; + /* beacon TO (ms). ¡§=0¡¨ no limit. */ + u8 bcn_to; + u16 bcn_itv; + /* only for VOIP mode. */ + u8 app_itv; + u8 awake_bcn_itvl; + u8 smart_ps; + /* unit: 100 ms */ + u8 bcn_pass_period; +}; + +struct h2c_joinbss_rpt_parm { + u8 opmode; + u8 ps_qos_info; + u8 bssid[6]; + u16 bcnitv; + u16 aid; +} ; + +struct h2c_wpa_ptk { + /* EAPOL-Key Key Confirmation Key (KCK) */ + u8 kck[16]; + /* EAPOL-Key Key Encryption Key (KEK) */ + u8 kek[16]; + /* Temporal Key 1 (TK1) */ + u8 tk1[16]; + union { + /* Temporal Key 2 (TK2) */ + u8 tk2[16]; + struct { + u8 tx_mic_key[8]; + u8 rx_mic_key[8]; + } athu; + } u; +}; + +struct h2c_wpa_two_way_parm { + /* algorithm TKIP or AES */ + u8 pairwise_en_alg; + u8 group_en_alg; + struct h2c_wpa_ptk wpa_ptk_value; +} ; + +enum h2c_cmd { + FW_H2C_SETPWRMODE = 0, + FW_H2C_JOINBSSRPT = 1, + FW_H2C_WOWLAN_UPDATE_GTK = 2, + FW_H2C_WOWLAN_UPDATE_IV = 3, + FW_H2C_WOWLAN_OFFLOAD = 4, +}; + +enum fw_h2c_cmd { + H2C_READ_MACREG_CMD, /*0*/ + H2C_WRITE_MACREG_CMD, + H2C_READBB_CMD, + H2C_WRITEBB_CMD, + H2C_READRF_CMD, + H2C_WRITERF_CMD, /*5*/ + H2C_READ_EEPROM_CMD, + H2C_WRITE_EEPROM_CMD, + H2C_READ_EFUSE_CMD, + H2C_WRITE_EFUSE_CMD, + H2C_READ_CAM_CMD, /*10*/ + H2C_WRITE_CAM_CMD, + H2C_SETBCNITV_CMD, + H2C_SETMBIDCFG_CMD, + H2C_JOINBSS_CMD, + H2C_DISCONNECT_CMD, /*15*/ + H2C_CREATEBSS_CMD, + H2C_SETOPMode_CMD, + H2C_SITESURVEY_CMD, + H2C_SETAUTH_CMD, + H2C_SETKEY_CMD, /*20*/ + H2C_SETSTAKEY_CMD, + H2C_SETASSOCSTA_CMD, + H2C_DELASSOCSTA_CMD, + H2C_SETSTAPWRSTATE_CMD, + H2C_SETBASICRATE_CMD, /*25*/ + H2C_GETBASICRATE_CMD, + H2C_SETDATARATE_CMD, + H2C_GETDATARATE_CMD, + H2C_SETPHYINFO_CMD, + H2C_GETPHYINFO_CMD, /*30*/ + H2C_SETPHY_CMD, + H2C_GETPHY_CMD, + H2C_READRSSI_CMD, + H2C_READGAIN_CMD, + H2C_SETATIM_CMD, /*35*/ + H2C_SETPWRMODE_CMD, + H2C_JOINBSSRPT_CMD, + H2C_SETRATABLE_CMD, + H2C_GETRATABLE_CMD, + H2C_GETCCXREPORT_CMD, /*40*/ + H2C_GETDTMREPORT_CMD, + H2C_GETTXRATESTATICS_CMD, + H2C_SETUSBSUSPEND_CMD, + H2C_SETH2CLBK_CMD, + H2C_TMP1, /*45*/ + H2C_WOWLAN_UPDATE_GTK_CMD, + H2C_WOWLAN_FW_OFFLOAD, + H2C_TMP2, + H2C_TMP3, + H2C_WOWLAN_UPDATE_IV_CMD, /*50*/ + H2C_TMP4, + MAX_H2CCMD /*52*/ +}; + +/* The following macros are used for FW + * CMD map and parameter updated. */ +#define FW_CMD_IO_CLR(rtlpriv, _Bit) \ + do { \ + udelay(1000); \ + rtlpriv->rtlhal.fwcmd_iomap &= (~_Bit); \ + } while (0); + +#define FW_CMD_IO_UPDATE(rtlpriv, _val) \ + rtlpriv->rtlhal.fwcmd_iomap = _val; + +#define FW_CMD_IO_SET(rtlpriv, _val) \ + do { \ + rtl_write_word(rtlpriv, LBUS_MON_ADDR, (u16)_val); \ + FW_CMD_IO_UPDATE(rtlpriv, _val); \ + } while (0); + +#define FW_CMD_PARA_SET(rtlpriv, _val) \ + do { \ + rtl_write_dword(rtlpriv, LBUS_ADDR_MASK, _val); \ + rtlpriv->rtlhal.fwcmd_ioparam = _val; \ + } while (0); + +#define FW_CMD_IO_QUERY(rtlpriv) \ + (u16)(rtlpriv->rtlhal.fwcmd_iomap) +#define FW_CMD_IO_PARA_QUERY(rtlpriv) \ + ((u32)(rtlpriv->rtlhal.fwcmd_ioparam)) + +int rtl92s_download_fw(struct ieee80211_hw *hw); +void rtl92s_set_fw_pwrmode_cmd(struct ieee80211_hw *hw, u8 mode); +void rtl92s_set_fw_joinbss_report_cmd(struct ieee80211_hw *hw, + u8 mstatus, u8 ps_qosinfo); + +#endif + -- cgit v0.10.2 From 24284531497def77d0c3c0de9046880b1c4e6b13 Mon Sep 17 00:00:00 2001 From: Chaoming Li Date: Tue, 3 May 2011 09:48:15 -0500 Subject: rtlwifi: rtl8192se: Merge hardware routines Merge routines hw.c and hw.h for RTL8192SE. Signed-off-by: Chaoming_Li Signed-off-by: Larry Finger Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/rtlwifi/rtl8192se/hw.c b/drivers/net/wireless/rtlwifi/rtl8192se/hw.c new file mode 100644 index 0000000..2e9005d --- /dev/null +++ b/drivers/net/wireless/rtlwifi/rtl8192se/hw.c @@ -0,0 +1,2512 @@ +/****************************************************************************** + * + * Copyright(c) 2009-2010 Realtek Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger + * + *****************************************************************************/ + +#include "../wifi.h" +#include "../efuse.h" +#include "../base.h" +#include "../regd.h" +#include "../cam.h" +#include "../ps.h" +#include "../pci.h" +#include "reg.h" +#include "def.h" +#include "phy.h" +#include "dm.h" +#include "fw.h" +#include "led.h" +#include "hw.h" + +void rtl92se_get_hw_reg(struct ieee80211_hw *hw, u8 variable, u8 *val) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); + struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); + + switch (variable) { + case HW_VAR_RCR: { + *((u32 *) (val)) = rtlpci->receive_config; + break; + } + case HW_VAR_RF_STATE: { + *((enum rf_pwrstate *)(val)) = ppsc->rfpwr_state; + break; + } + case HW_VAR_FW_PSMODE_STATUS: { + *((bool *) (val)) = ppsc->fw_current_inpsmode; + break; + } + case HW_VAR_CORRECT_TSF: { + u64 tsf; + u32 *ptsf_low = (u32 *)&tsf; + u32 *ptsf_high = ((u32 *)&tsf) + 1; + + *ptsf_high = rtl_read_dword(rtlpriv, (TSFR + 4)); + *ptsf_low = rtl_read_dword(rtlpriv, TSFR); + + *((u64 *) (val)) = tsf; + + break; + } + case HW_VAR_MRC: { + *((bool *)(val)) = rtlpriv->dm.current_mrc_switch; + break; + } + default: { + RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, + ("switch case not process\n")); + break; + } + } +} + +void rtl92se_set_hw_reg(struct ieee80211_hw *hw, u8 variable, u8 *val) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); + struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); + struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); + struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw)); + struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); + + switch (variable) { + case HW_VAR_ETHER_ADDR:{ + rtl_write_dword(rtlpriv, IDR0, ((u32 *)(val))[0]); + rtl_write_word(rtlpriv, IDR4, ((u16 *)(val + 4))[0]); + break; + } + case HW_VAR_BASIC_RATE:{ + u16 rate_cfg = ((u16 *) val)[0]; + u8 rate_index = 0; + + if (rtlhal->version == VERSION_8192S_ACUT) + rate_cfg = rate_cfg & 0x150; + else + rate_cfg = rate_cfg & 0x15f; + + rate_cfg |= 0x01; + + rtl_write_byte(rtlpriv, RRSR, rate_cfg & 0xff); + rtl_write_byte(rtlpriv, RRSR + 1, + (rate_cfg >> 8) & 0xff); + + while (rate_cfg > 0x1) { + rate_cfg = (rate_cfg >> 1); + rate_index++; + } + rtl_write_byte(rtlpriv, INIRTSMCS_SEL, rate_index); + + break; + } + case HW_VAR_BSSID:{ + rtl_write_dword(rtlpriv, BSSIDR, ((u32 *)(val))[0]); + rtl_write_word(rtlpriv, BSSIDR + 4, + ((u16 *)(val + 4))[0]); + break; + } + case HW_VAR_SIFS:{ + rtl_write_byte(rtlpriv, SIFS_OFDM, val[0]); + rtl_write_byte(rtlpriv, SIFS_OFDM + 1, val[1]); + break; + } + case HW_VAR_SLOT_TIME:{ + u8 e_aci; + + RT_TRACE(rtlpriv, COMP_MLME, DBG_LOUD, + ("HW_VAR_SLOT_TIME %x\n", val[0])); + + rtl_write_byte(rtlpriv, SLOT_TIME, val[0]); + + for (e_aci = 0; e_aci < AC_MAX; e_aci++) { + rtlpriv->cfg->ops->set_hw_reg(hw, + HW_VAR_AC_PARAM, + (u8 *)(&e_aci)); + } + break; + } + case HW_VAR_ACK_PREAMBLE:{ + u8 reg_tmp; + u8 short_preamble = (bool) (*(u8 *) val); + reg_tmp = (mac->cur_40_prime_sc) << 5; + if (short_preamble) + reg_tmp |= 0x80; + + rtl_write_byte(rtlpriv, RRSR + 2, reg_tmp); + break; + } + case HW_VAR_AMPDU_MIN_SPACE:{ + u8 min_spacing_to_set; + u8 sec_min_space; + + min_spacing_to_set = *((u8 *)val); + if (min_spacing_to_set <= 7) { + if (rtlpriv->sec.pairwise_enc_algorithm == + NO_ENCRYPTION) + sec_min_space = 0; + else + sec_min_space = 1; + + if (min_spacing_to_set < sec_min_space) + min_spacing_to_set = sec_min_space; + if (min_spacing_to_set > 5) + min_spacing_to_set = 5; + + mac->min_space_cfg = + ((mac->min_space_cfg & 0xf8) | + min_spacing_to_set); + + *val = min_spacing_to_set; + + RT_TRACE(rtlpriv, COMP_MLME, DBG_LOUD, + ("Set HW_VAR_AMPDU_MIN_SPACE: %#x\n", + mac->min_space_cfg)); + + rtl_write_byte(rtlpriv, AMPDU_MIN_SPACE, + mac->min_space_cfg); + } + break; + } + case HW_VAR_SHORTGI_DENSITY:{ + u8 density_to_set; + + density_to_set = *((u8 *) val); + mac->min_space_cfg = rtlpriv->rtlhal.minspace_cfg; + mac->min_space_cfg |= (density_to_set << 3); + + RT_TRACE(rtlpriv, COMP_MLME, DBG_LOUD, + ("Set HW_VAR_SHORTGI_DENSITY: %#x\n", + mac->min_space_cfg)); + + rtl_write_byte(rtlpriv, AMPDU_MIN_SPACE, + mac->min_space_cfg); + + break; + } + case HW_VAR_AMPDU_FACTOR:{ + u8 factor_toset; + u8 regtoset; + u8 factorlevel[18] = { + 2, 4, 4, 7, 7, 13, 13, + 13, 2, 7, 7, 13, 13, + 15, 15, 15, 15, 0}; + u8 index = 0; + + factor_toset = *((u8 *) val); + if (factor_toset <= 3) { + factor_toset = (1 << (factor_toset + 2)); + if (factor_toset > 0xf) + factor_toset = 0xf; + + for (index = 0; index < 17; index++) { + if (factorlevel[index] > factor_toset) + factorlevel[index] = + factor_toset; + } + + for (index = 0; index < 8; index++) { + regtoset = ((factorlevel[index * 2]) | + (factorlevel[index * + 2 + 1] << 4)); + rtl_write_byte(rtlpriv, + AGGLEN_LMT_L + index, + regtoset); + } + + regtoset = ((factorlevel[16]) | + (factorlevel[17] << 4)); + rtl_write_byte(rtlpriv, AGGLEN_LMT_H, regtoset); + + RT_TRACE(rtlpriv, COMP_MLME, DBG_LOUD, + ("Set HW_VAR_AMPDU_FACTOR: %#x\n", + factor_toset)); + } + break; + } + case HW_VAR_AC_PARAM:{ + u8 e_aci = *((u8 *) val); + rtl92s_dm_init_edca_turbo(hw); + + if (rtlpci->acm_method != eAcmWay2_SW) + rtlpriv->cfg->ops->set_hw_reg(hw, + HW_VAR_ACM_CTRL, + (u8 *)(&e_aci)); + break; + } + case HW_VAR_ACM_CTRL:{ + u8 e_aci = *((u8 *) val); + union aci_aifsn *p_aci_aifsn = (union aci_aifsn *)(&( + mac->ac[0].aifs)); + u8 acm = p_aci_aifsn->f.acm; + u8 acm_ctrl = rtl_read_byte(rtlpriv, AcmHwCtrl); + + acm_ctrl = acm_ctrl | ((rtlpci->acm_method == 2) ? + 0x0 : 0x1); + + if (acm) { + switch (e_aci) { + case AC0_BE: + acm_ctrl |= AcmHw_BeqEn; + break; + case AC2_VI: + acm_ctrl |= AcmHw_ViqEn; + break; + case AC3_VO: + acm_ctrl |= AcmHw_VoqEn; + break; + default: + RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING, + ("HW_VAR_ACM_CTRL acm set " + "failed: eACI is %d\n", acm)); + break; + } + } else { + switch (e_aci) { + case AC0_BE: + acm_ctrl &= (~AcmHw_BeqEn); + break; + case AC2_VI: + acm_ctrl &= (~AcmHw_ViqEn); + break; + case AC3_VO: + acm_ctrl &= (~AcmHw_BeqEn); + break; + default: + RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, + ("switch case not process\n")); + break; + } + } + + RT_TRACE(rtlpriv, COMP_QOS, DBG_TRACE, + ("HW_VAR_ACM_CTRL Write 0x%X\n", acm_ctrl)); + rtl_write_byte(rtlpriv, AcmHwCtrl, acm_ctrl); + break; + } + case HW_VAR_RCR:{ + rtl_write_dword(rtlpriv, RCR, ((u32 *) (val))[0]); + rtlpci->receive_config = ((u32 *) (val))[0]; + break; + } + case HW_VAR_RETRY_LIMIT:{ + u8 retry_limit = ((u8 *) (val))[0]; + + rtl_write_word(rtlpriv, RETRY_LIMIT, + retry_limit << RETRY_LIMIT_SHORT_SHIFT | + retry_limit << RETRY_LIMIT_LONG_SHIFT); + break; + } + case HW_VAR_DUAL_TSF_RST: { + break; + } + case HW_VAR_EFUSE_BYTES: { + rtlefuse->efuse_usedbytes = *((u16 *) val); + break; + } + case HW_VAR_EFUSE_USAGE: { + rtlefuse->efuse_usedpercentage = *((u8 *) val); + break; + } + case HW_VAR_IO_CMD: { + break; + } + case HW_VAR_WPA_CONFIG: { + rtl_write_byte(rtlpriv, REG_SECR, *((u8 *) val)); + break; + } + case HW_VAR_SET_RPWM:{ + break; + } + case HW_VAR_H2C_FW_PWRMODE:{ + break; + } + case HW_VAR_FW_PSMODE_STATUS: { + ppsc->fw_current_inpsmode = *((bool *) val); + break; + } + case HW_VAR_H2C_FW_JOINBSSRPT:{ + break; + } + case HW_VAR_AID:{ + break; + } + case HW_VAR_CORRECT_TSF:{ + break; + } + case HW_VAR_MRC: { + bool bmrc_toset = *((bool *)val); + u8 u1bdata = 0; + + if (bmrc_toset) { + rtl_set_bbreg(hw, ROFDM0_TRXPATHENABLE, + MASKBYTE0, 0x33); + u1bdata = (u8)rtl_get_bbreg(hw, + ROFDM1_TRXPATHENABLE, + MASKBYTE0); + rtl_set_bbreg(hw, ROFDM1_TRXPATHENABLE, + MASKBYTE0, + ((u1bdata & 0xf0) | 0x03)); + u1bdata = (u8)rtl_get_bbreg(hw, + ROFDM0_TRXPATHENABLE, + MASKBYTE1); + rtl_set_bbreg(hw, ROFDM0_TRXPATHENABLE, + MASKBYTE1, + (u1bdata | 0x04)); + + /* Update current settings. */ + rtlpriv->dm.current_mrc_switch = bmrc_toset; + } else { + rtl_set_bbreg(hw, ROFDM0_TRXPATHENABLE, + MASKBYTE0, 0x13); + u1bdata = (u8)rtl_get_bbreg(hw, + ROFDM1_TRXPATHENABLE, + MASKBYTE0); + rtl_set_bbreg(hw, ROFDM1_TRXPATHENABLE, + MASKBYTE0, + ((u1bdata & 0xf0) | 0x01)); + u1bdata = (u8)rtl_get_bbreg(hw, + ROFDM0_TRXPATHENABLE, + MASKBYTE1); + rtl_set_bbreg(hw, ROFDM0_TRXPATHENABLE, + MASKBYTE1, (u1bdata & 0xfb)); + + /* Update current settings. */ + rtlpriv->dm.current_mrc_switch = bmrc_toset; + } + + break; + } + default: + RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, + ("switch case not process\n")); + break; + } + +} + +void rtl92se_enable_hw_security_config(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + u8 sec_reg_value = 0x0; + + RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, ("PairwiseEncAlgorithm = %d " + "GroupEncAlgorithm = %d\n", + rtlpriv->sec.pairwise_enc_algorithm, + rtlpriv->sec.group_enc_algorithm)); + + if (rtlpriv->cfg->mod_params->sw_crypto || rtlpriv->sec.use_sw_sec) { + RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG, + ("not open hw encryption\n")); + return; + } + + sec_reg_value = SCR_TXENCENABLE | SCR_RXENCENABLE; + + if (rtlpriv->sec.use_defaultkey) { + sec_reg_value |= SCR_TXUSEDK; + sec_reg_value |= SCR_RXUSEDK; + } + + RT_TRACE(rtlpriv, COMP_SEC, DBG_LOUD, ("The SECR-value %x\n", + sec_reg_value)); + + rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_WPA_CONFIG, &sec_reg_value); + +} + +static u8 _rtl92ce_halset_sysclk(struct ieee80211_hw *hw, u8 data) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + u8 waitcount = 100; + bool bresult = false; + u8 tmpvalue; + + rtl_write_byte(rtlpriv, SYS_CLKR + 1, data); + + /* Wait the MAC synchronized. */ + udelay(400); + + /* Check if it is set ready. */ + tmpvalue = rtl_read_byte(rtlpriv, SYS_CLKR + 1); + bresult = ((tmpvalue & BIT(7)) == (data & BIT(7))); + + if ((data & (BIT(6) | BIT(7))) == false) { + waitcount = 100; + tmpvalue = 0; + + while (1) { + waitcount--; + + tmpvalue = rtl_read_byte(rtlpriv, SYS_CLKR + 1); + if ((tmpvalue & BIT(6))) + break; + + printk(KERN_ERR "wait for BIT(6) return value %x\n", + tmpvalue); + if (waitcount == 0) + break; + + udelay(10); + } + + if (waitcount == 0) + bresult = false; + else + bresult = true; + } + + return bresult; +} + +void rtl8192se_gpiobit3_cfg_inputmode(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + u8 u1tmp; + + /* The following config GPIO function */ + rtl_write_byte(rtlpriv, MAC_PINMUX_CFG, (GPIOMUX_EN | GPIOSEL_GPIO)); + u1tmp = rtl_read_byte(rtlpriv, GPIO_IO_SEL); + + /* config GPIO3 to input */ + u1tmp &= HAL_8192S_HW_GPIO_OFF_MASK; + rtl_write_byte(rtlpriv, GPIO_IO_SEL, u1tmp); + +} + +static u8 _rtl92se_rf_onoff_detect(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + u8 u1tmp; + u8 retval = ERFON; + + /* The following config GPIO function */ + rtl_write_byte(rtlpriv, MAC_PINMUX_CFG, (GPIOMUX_EN | GPIOSEL_GPIO)); + u1tmp = rtl_read_byte(rtlpriv, GPIO_IO_SEL); + + /* config GPIO3 to input */ + u1tmp &= HAL_8192S_HW_GPIO_OFF_MASK; + rtl_write_byte(rtlpriv, GPIO_IO_SEL, u1tmp); + + /* On some of the platform, driver cannot read correct + * value without delay between Write_GPIO_SEL and Read_GPIO_IN */ + mdelay(10); + + /* check GPIO3 */ + u1tmp = rtl_read_byte(rtlpriv, GPIO_IN); + retval = (u1tmp & HAL_8192S_HW_GPIO_OFF_BIT) ? ERFON : ERFOFF; + + return retval; +} + +static void _rtl92se_macconfig_before_fwdownload(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); + struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); + + u8 i; + u8 tmpu1b; + u16 tmpu2b; + u8 pollingcnt = 20; + + if (rtlpci->first_init) { + /* Reset PCIE Digital */ + tmpu1b = rtl_read_byte(rtlpriv, REG_SYS_FUNC_EN + 1); + tmpu1b &= 0xFE; + rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN + 1, tmpu1b); + udelay(1); + rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN + 1, tmpu1b | BIT(0)); + } + + /* Switch to SW IO control */ + tmpu1b = rtl_read_byte(rtlpriv, (SYS_CLKR + 1)); + if (tmpu1b & BIT(7)) { + tmpu1b &= ~(BIT(6) | BIT(7)); + + /* Set failed, return to prevent hang. */ + if (!_rtl92ce_halset_sysclk(hw, tmpu1b)) + return; + } + + rtl_write_byte(rtlpriv, AFE_PLL_CTRL, 0x0); + udelay(50); + rtl_write_byte(rtlpriv, LDOA15_CTRL, 0x34); + udelay(50); + + /* Clear FW RPWM for FW control LPS.*/ + rtl_write_byte(rtlpriv, RPWM, 0x0); + + /* Reset MAC-IO and CPU and Core Digital BIT(10)/11/15 */ + tmpu1b = rtl_read_byte(rtlpriv, REG_SYS_FUNC_EN + 1); + tmpu1b &= 0x73; + rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN + 1, tmpu1b); + /* wait for BIT 10/11/15 to pull high automatically!! */ + mdelay(1); + + rtl_write_byte(rtlpriv, CMDR, 0); + rtl_write_byte(rtlpriv, TCR, 0); + + /* Data sheet not define 0x562!!! Copy from WMAC!!!!! */ + tmpu1b = rtl_read_byte(rtlpriv, 0x562); + tmpu1b |= 0x08; + rtl_write_byte(rtlpriv, 0x562, tmpu1b); + tmpu1b &= ~(BIT(3)); + rtl_write_byte(rtlpriv, 0x562, tmpu1b); + + /* Enable AFE clock source */ + tmpu1b = rtl_read_byte(rtlpriv, AFE_XTAL_CTRL); + rtl_write_byte(rtlpriv, AFE_XTAL_CTRL, (tmpu1b | 0x01)); + /* Delay 1.5ms */ + mdelay(2); + tmpu1b = rtl_read_byte(rtlpriv, AFE_XTAL_CTRL + 1); + rtl_write_byte(rtlpriv, AFE_XTAL_CTRL + 1, (tmpu1b & 0xfb)); + + /* Enable AFE Macro Block's Bandgap */ + tmpu1b = rtl_read_byte(rtlpriv, AFE_MISC); + rtl_write_byte(rtlpriv, AFE_MISC, (tmpu1b | BIT(0))); + mdelay(1); + + /* Enable AFE Mbias */ + tmpu1b = rtl_read_byte(rtlpriv, AFE_MISC); + rtl_write_byte(rtlpriv, AFE_MISC, (tmpu1b | 0x02)); + mdelay(1); + + /* Enable LDOA15 block */ + tmpu1b = rtl_read_byte(rtlpriv, LDOA15_CTRL); + rtl_write_byte(rtlpriv, LDOA15_CTRL, (tmpu1b | BIT(0))); + + /* Set Digital Vdd to Retention isolation Path. */ + tmpu2b = rtl_read_word(rtlpriv, REG_SYS_ISO_CTRL); + rtl_write_word(rtlpriv, REG_SYS_ISO_CTRL, (tmpu2b | BIT(11))); + + /* For warm reboot NIC disappera bug. */ + tmpu2b = rtl_read_word(rtlpriv, REG_SYS_FUNC_EN); + rtl_write_word(rtlpriv, REG_SYS_FUNC_EN, (tmpu2b | BIT(13))); + + rtl_write_byte(rtlpriv, REG_SYS_ISO_CTRL + 1, 0x68); + + /* Enable AFE PLL Macro Block */ + /* We need to delay 100u before enabling PLL. */ + udelay(200); + tmpu1b = rtl_read_byte(rtlpriv, AFE_PLL_CTRL); + rtl_write_byte(rtlpriv, AFE_PLL_CTRL, (tmpu1b | BIT(0) | BIT(4))); + + /* for divider reset */ + udelay(100); + rtl_write_byte(rtlpriv, AFE_PLL_CTRL, (tmpu1b | BIT(0) | + BIT(4) | BIT(6))); + udelay(10); + rtl_write_byte(rtlpriv, AFE_PLL_CTRL, (tmpu1b | BIT(0) | BIT(4))); + udelay(10); + + /* Enable MAC 80MHZ clock */ + tmpu1b = rtl_read_byte(rtlpriv, AFE_PLL_CTRL + 1); + rtl_write_byte(rtlpriv, AFE_PLL_CTRL + 1, (tmpu1b | BIT(0))); + mdelay(1); + + /* Release isolation AFE PLL & MD */ + rtl_write_byte(rtlpriv, REG_SYS_ISO_CTRL, 0xA6); + + /* Enable MAC clock */ + tmpu2b = rtl_read_word(rtlpriv, SYS_CLKR); + rtl_write_word(rtlpriv, SYS_CLKR, (tmpu2b | BIT(12) | BIT(11))); + + /* Enable Core digital and enable IOREG R/W */ + tmpu2b = rtl_read_word(rtlpriv, REG_SYS_FUNC_EN); + rtl_write_word(rtlpriv, REG_SYS_FUNC_EN, (tmpu2b | BIT(11))); + + tmpu1b = rtl_read_byte(rtlpriv, REG_SYS_FUNC_EN + 1); + rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN + 1, tmpu1b & ~(BIT(7))); + + /* enable REG_EN */ + rtl_write_word(rtlpriv, REG_SYS_FUNC_EN, (tmpu2b | BIT(11) | BIT(15))); + + /* Switch the control path. */ + tmpu2b = rtl_read_word(rtlpriv, SYS_CLKR); + rtl_write_word(rtlpriv, SYS_CLKR, (tmpu2b & (~BIT(2)))); + + tmpu1b = rtl_read_byte(rtlpriv, (SYS_CLKR + 1)); + tmpu1b = ((tmpu1b | BIT(7)) & (~BIT(6))); + if (!_rtl92ce_halset_sysclk(hw, tmpu1b)) + return; /* Set failed, return to prevent hang. */ + + rtl_write_word(rtlpriv, CMDR, 0x07FC); + + /* MH We must enable the section of code to prevent load IMEM fail. */ + /* Load MAC register from WMAc temporarily We simulate macreg. */ + /* txt HW will provide MAC txt later */ + rtl_write_byte(rtlpriv, 0x6, 0x30); + rtl_write_byte(rtlpriv, 0x49, 0xf0); + + rtl_write_byte(rtlpriv, 0x4b, 0x81); + + rtl_write_byte(rtlpriv, 0xb5, 0x21); + + rtl_write_byte(rtlpriv, 0xdc, 0xff); + rtl_write_byte(rtlpriv, 0xdd, 0xff); + rtl_write_byte(rtlpriv, 0xde, 0xff); + rtl_write_byte(rtlpriv, 0xdf, 0xff); + + rtl_write_byte(rtlpriv, 0x11a, 0x00); + rtl_write_byte(rtlpriv, 0x11b, 0x00); + + for (i = 0; i < 32; i++) + rtl_write_byte(rtlpriv, INIMCS_SEL + i, 0x1b); + + rtl_write_byte(rtlpriv, 0x236, 0xff); + + rtl_write_byte(rtlpriv, 0x503, 0x22); + + if (ppsc->support_aspm && !ppsc->support_backdoor) + rtl_write_byte(rtlpriv, 0x560, 0x40); + else + rtl_write_byte(rtlpriv, 0x560, 0x00); + + rtl_write_byte(rtlpriv, DBG_PORT, 0x91); + + /* Set RX Desc Address */ + rtl_write_dword(rtlpriv, RDQDA, rtlpci->rx_ring[RX_MPDU_QUEUE].dma); + rtl_write_dword(rtlpriv, RCDA, rtlpci->rx_ring[RX_CMD_QUEUE].dma); + + /* Set TX Desc Address */ + rtl_write_dword(rtlpriv, TBKDA, rtlpci->tx_ring[BK_QUEUE].dma); + rtl_write_dword(rtlpriv, TBEDA, rtlpci->tx_ring[BE_QUEUE].dma); + rtl_write_dword(rtlpriv, TVIDA, rtlpci->tx_ring[VI_QUEUE].dma); + rtl_write_dword(rtlpriv, TVODA, rtlpci->tx_ring[VO_QUEUE].dma); + rtl_write_dword(rtlpriv, TBDA, rtlpci->tx_ring[BEACON_QUEUE].dma); + rtl_write_dword(rtlpriv, TCDA, rtlpci->tx_ring[TXCMD_QUEUE].dma); + rtl_write_dword(rtlpriv, TMDA, rtlpci->tx_ring[MGNT_QUEUE].dma); + rtl_write_dword(rtlpriv, THPDA, rtlpci->tx_ring[HIGH_QUEUE].dma); + rtl_write_dword(rtlpriv, HDA, rtlpci->tx_ring[HCCA_QUEUE].dma); + + rtl_write_word(rtlpriv, CMDR, 0x37FC); + + /* To make sure that TxDMA can ready to download FW. */ + /* We should reset TxDMA if IMEM RPT was not ready. */ + do { + tmpu1b = rtl_read_byte(rtlpriv, TCR); + if ((tmpu1b & TXDMA_INIT_VALUE) == TXDMA_INIT_VALUE) + break; + + udelay(5); + } while (pollingcnt--); + + if (pollingcnt <= 0) { + RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, + ("Polling TXDMA_INIT_VALUE " + "timeout!! Current TCR(%#x)\n", tmpu1b)); + tmpu1b = rtl_read_byte(rtlpriv, CMDR); + rtl_write_byte(rtlpriv, CMDR, tmpu1b & (~TXDMA_EN)); + udelay(2); + /* Reset TxDMA */ + rtl_write_byte(rtlpriv, CMDR, tmpu1b | TXDMA_EN); + } + + /* After MACIO reset,we must refresh LED state. */ + if ((ppsc->rfoff_reason == RF_CHANGE_BY_IPS) || + (ppsc->rfoff_reason == 0)) { + struct rtl_pci_priv *pcipriv = rtl_pcipriv(hw); + struct rtl_led *pLed0 = &(pcipriv->ledctl.sw_led0); + enum rf_pwrstate rfpwr_state_toset; + rfpwr_state_toset = _rtl92se_rf_onoff_detect(hw); + + if (rfpwr_state_toset == ERFON) + rtl92se_sw_led_on(hw, pLed0); + } +} + +static void _rtl92se_macconfig_after_fwdownload(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); + struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw)); + struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); + u8 i; + u16 tmpu2b; + + /* 1. System Configure Register (Offset: 0x0000 - 0x003F) */ + + /* 2. Command Control Register (Offset: 0x0040 - 0x004F) */ + /* Turn on 0x40 Command register */ + rtl_write_word(rtlpriv, CMDR, (BBRSTN | BB_GLB_RSTN | + SCHEDULE_EN | MACRXEN | MACTXEN | DDMA_EN | FW2HW_EN | + RXDMA_EN | TXDMA_EN | HCI_RXDMA_EN | HCI_TXDMA_EN)); + + /* Set TCR TX DMA pre 2 FULL enable bit */ + rtl_write_dword(rtlpriv, TCR, rtl_read_dword(rtlpriv, TCR) | + TXDMAPRE2FULL); + + /* Set RCR */ + rtl_write_dword(rtlpriv, RCR, rtlpci->receive_config); + + /* 3. MACID Setting Register (Offset: 0x0050 - 0x007F) */ + + /* 4. Timing Control Register (Offset: 0x0080 - 0x009F) */ + /* Set CCK/OFDM SIFS */ + /* CCK SIFS shall always be 10us. */ + rtl_write_word(rtlpriv, SIFS_CCK, 0x0a0a); + rtl_write_word(rtlpriv, SIFS_OFDM, 0x1010); + + /* Set AckTimeout */ + rtl_write_byte(rtlpriv, ACK_TIMEOUT, 0x40); + + /* Beacon related */ + rtl_write_word(rtlpriv, BCN_INTERVAL, 100); + rtl_write_word(rtlpriv, ATIMWND, 2); + + /* 5. FIFO Control Register (Offset: 0x00A0 - 0x015F) */ + /* 5.1 Initialize Number of Reserved Pages in Firmware Queue */ + /* Firmware allocate now, associate with FW internal setting.!!! */ + + /* 5.2 Setting TX/RX page size 0/1/2/3/4=64/128/256/512/1024 */ + /* 5.3 Set driver info, we only accept PHY status now. */ + /* 5.4 Set RXDMA arbitration to control RXDMA/MAC/FW R/W for RXFIFO */ + rtl_write_byte(rtlpriv, RXDMA, rtl_read_byte(rtlpriv, RXDMA) | BIT(6)); + + /* 6. Adaptive Control Register (Offset: 0x0160 - 0x01CF) */ + /* Set RRSR to all legacy rate and HT rate + * CCK rate is supported by default. + * CCK rate will be filtered out only when associated + * AP does not support it. + * Only enable ACK rate to OFDM 24M + * Disable RRSR for CCK rate in A-Cut */ + + if (rtlhal->version == VERSION_8192S_ACUT) + rtl_write_byte(rtlpriv, RRSR, 0xf0); + else if (rtlhal->version == VERSION_8192S_BCUT) + rtl_write_byte(rtlpriv, RRSR, 0xff); + rtl_write_byte(rtlpriv, RRSR + 1, 0x01); + rtl_write_byte(rtlpriv, RRSR + 2, 0x00); + + /* A-Cut IC do not support CCK rate. We forbid ARFR to */ + /* fallback to CCK rate */ + for (i = 0; i < 8; i++) { + /*Disable RRSR for CCK rate in A-Cut */ + if (rtlhal->version == VERSION_8192S_ACUT) + rtl_write_dword(rtlpriv, ARFR0 + i * 4, 0x1f0ff0f0); + } + + /* Different rate use different AMPDU size */ + /* MCS32/ MCS15_SG use max AMPDU size 15*2=30K */ + rtl_write_byte(rtlpriv, AGGLEN_LMT_H, 0x0f); + /* MCS0/1/2/3 use max AMPDU size 4*2=8K */ + rtl_write_word(rtlpriv, AGGLEN_LMT_L, 0x7442); + /* MCS4/5 use max AMPDU size 8*2=16K 6/7 use 10*2=20K */ + rtl_write_word(rtlpriv, AGGLEN_LMT_L + 2, 0xddd7); + /* MCS8/9 use max AMPDU size 8*2=16K 10/11 use 10*2=20K */ + rtl_write_word(rtlpriv, AGGLEN_LMT_L + 4, 0xd772); + /* MCS12/13/14/15 use max AMPDU size 15*2=30K */ + rtl_write_word(rtlpriv, AGGLEN_LMT_L + 6, 0xfffd); + + /* Set Data / Response auto rate fallack retry count */ + rtl_write_dword(rtlpriv, DARFRC, 0x04010000); + rtl_write_dword(rtlpriv, DARFRC + 4, 0x09070605); + rtl_write_dword(rtlpriv, RARFRC, 0x04010000); + rtl_write_dword(rtlpriv, RARFRC + 4, 0x09070605); + + /* 7. EDCA Setting Register (Offset: 0x01D0 - 0x01FF) */ + /* Set all rate to support SG */ + rtl_write_word(rtlpriv, SG_RATE, 0xFFFF); + + /* 8. WMAC, BA, and CCX related Register (Offset: 0x0200 - 0x023F) */ + /* Set NAV protection length */ + rtl_write_word(rtlpriv, NAV_PROT_LEN, 0x0080); + /* CF-END Threshold */ + rtl_write_byte(rtlpriv, CFEND_TH, 0xFF); + /* Set AMPDU minimum space */ + rtl_write_byte(rtlpriv, AMPDU_MIN_SPACE, 0x07); + /* Set TXOP stall control for several queue/HI/BCN/MGT/ */ + rtl_write_byte(rtlpriv, TXOP_STALL_CTRL, 0x00); + + /* 9. Security Control Register (Offset: 0x0240 - 0x025F) */ + /* 10. Power Save Control Register (Offset: 0x0260 - 0x02DF) */ + /* 11. General Purpose Register (Offset: 0x02E0 - 0x02FF) */ + /* 12. Host Interrupt Status Register (Offset: 0x0300 - 0x030F) */ + /* 13. Test Mode and Debug Control Register (Offset: 0x0310 - 0x034F) */ + + /* 14. Set driver info, we only accept PHY status now. */ + rtl_write_byte(rtlpriv, RXDRVINFO_SZ, 4); + + /* 15. For EEPROM R/W Workaround */ + /* 16. For EFUSE to share REG_SYS_FUNC_EN with EEPROM!!! */ + tmpu2b = rtl_read_byte(rtlpriv, REG_SYS_FUNC_EN); + rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN, tmpu2b | BIT(13)); + tmpu2b = rtl_read_byte(rtlpriv, REG_SYS_ISO_CTRL); + rtl_write_byte(rtlpriv, REG_SYS_ISO_CTRL, tmpu2b & (~BIT(8))); + + /* 17. For EFUSE */ + /* We may R/W EFUSE in EEPROM mode */ + if (rtlefuse->epromtype == EEPROM_BOOT_EFUSE) { + u8 tempval; + + tempval = rtl_read_byte(rtlpriv, REG_SYS_ISO_CTRL + 1); + tempval &= 0xFE; + rtl_write_byte(rtlpriv, REG_SYS_ISO_CTRL + 1, tempval); + + /* Change Program timing */ + rtl_write_byte(rtlpriv, REG_EFUSE_CTRL + 3, 0x72); + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, ("EFUSE CONFIG OK\n")); + } + + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, ("OK\n")); + +} + +static void _rtl92se_hw_configure(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); + struct rtl_phy *rtlphy = &(rtlpriv->phy); + struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); + + u8 reg_bw_opmode = 0; + u32 reg_ratr = 0, reg_rrsr = 0; + u8 regtmp = 0; + + reg_bw_opmode = BW_OPMODE_20MHZ; + reg_ratr = RATE_ALL_CCK | RATE_ALL_OFDM_AG | RATE_ALL_OFDM_1SS | + RATE_ALL_OFDM_2SS; + reg_rrsr = RATE_ALL_CCK | RATE_ALL_OFDM_AG; + + regtmp = rtl_read_byte(rtlpriv, INIRTSMCS_SEL); + reg_rrsr = ((reg_rrsr & 0x000fffff) << 8) | regtmp; + rtl_write_dword(rtlpriv, INIRTSMCS_SEL, reg_rrsr); + rtl_write_byte(rtlpriv, BW_OPMODE, reg_bw_opmode); + + /* Set Retry Limit here */ + rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_RETRY_LIMIT, + (u8 *)(&rtlpci->shortretry_limit)); + + rtl_write_byte(rtlpriv, MLT, 0x8f); + + /* For Min Spacing configuration. */ + switch (rtlphy->rf_type) { + case RF_1T2R: + case RF_1T1R: + rtlhal->minspace_cfg = (MAX_MSS_DENSITY_1T << 3); + break; + case RF_2T2R: + case RF_2T2R_GREEN: + rtlhal->minspace_cfg = (MAX_MSS_DENSITY_2T << 3); + break; + } + rtl_write_byte(rtlpriv, AMPDU_MIN_SPACE, rtlhal->minspace_cfg); +} + +int rtl92se_hw_init(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); + struct rtl_phy *rtlphy = &(rtlpriv->phy); + struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); + struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw)); + u8 tmp_byte = 0; + + bool rtstatus = true; + u8 tmp_u1b; + int err = false; + u8 i; + int wdcapra_add[] = { + EDCAPARA_BE, EDCAPARA_BK, + EDCAPARA_VI, EDCAPARA_VO}; + u8 secr_value = 0x0; + + rtlpci->being_init_adapter = true; + + rtlpriv->intf_ops->disable_aspm(hw); + + /* 1. MAC Initialize */ + /* Before FW download, we have to set some MAC register */ + _rtl92se_macconfig_before_fwdownload(hw); + + rtlhal->version = (enum version_8192s)((rtl_read_dword(rtlpriv, + PMC_FSM) >> 16) & 0xF); + + rtl8192se_gpiobit3_cfg_inputmode(hw); + + /* 2. download firmware */ + rtstatus = rtl92s_download_fw(hw); + if (!rtstatus) { + RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING, + ("Failed to download FW. " + "Init HW without FW now.., Please copy FW into" + "/lib/firmware/rtlwifi\n")); + rtlhal->fw_ready = false; + } else { + rtlhal->fw_ready = true; + } + + /* After FW download, we have to reset MAC register */ + _rtl92se_macconfig_after_fwdownload(hw); + + /*Retrieve default FW Cmd IO map. */ + rtlhal->fwcmd_iomap = rtl_read_word(rtlpriv, LBUS_MON_ADDR); + rtlhal->fwcmd_ioparam = rtl_read_dword(rtlpriv, LBUS_ADDR_MASK); + + /* 3. Initialize MAC/PHY Config by MACPHY_reg.txt */ + if (rtl92s_phy_mac_config(hw) != true) { + RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, ("MAC Config failed\n")); + return rtstatus; + } + + /* Make sure BB/RF write OK. We should prevent enter IPS. radio off. */ + /* We must set flag avoid BB/RF config period later!! */ + rtl_write_dword(rtlpriv, CMDR, 0x37FC); + + /* 4. Initialize BB After MAC Config PHY_reg.txt, AGC_Tab.txt */ + if (rtl92s_phy_bb_config(hw) != true) { + RT_TRACE(rtlpriv, COMP_INIT, DBG_EMERG, ("BB Config failed\n")); + return rtstatus; + } + + /* 5. Initiailze RF RAIO_A.txt RF RAIO_B.txt */ + /* Before initalizing RF. We can not use FW to do RF-R/W. */ + + rtlphy->rf_mode = RF_OP_BY_SW_3WIRE; + + /* RF Power Save */ +#if 0 + /* H/W or S/W RF OFF before sleep. */ + if (rtlpriv->psc.rfoff_reason > RF_CHANGE_BY_PS) { + u32 rfoffreason = rtlpriv->psc.rfoff_reason; + + rtlpriv->psc.rfoff_reason = RF_CHANGE_BY_INIT; + rtlpriv->psc.rfpwr_state = ERFON; + rtl_ps_set_rf_state(hw, ERFOFF, rfoffreason, true); + } else { + /* gpio radio on/off is out of adapter start */ + if (rtlpriv->psc.hwradiooff == false) { + rtlpriv->psc.rfpwr_state = ERFON; + rtlpriv->psc.rfoff_reason = 0; + } + } +#endif + + /* Before RF-R/W we must execute the IO from Scott's suggestion. */ + rtl_write_byte(rtlpriv, AFE_XTAL_CTRL + 1, 0xDB); + if (rtlhal->version == VERSION_8192S_ACUT) + rtl_write_byte(rtlpriv, SPS1_CTRL + 3, 0x07); + else + rtl_write_byte(rtlpriv, RF_CTRL, 0x07); + + if (rtl92s_phy_rf_config(hw) != true) { + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, ("RF Config failed\n")); + return rtstatus; + } + + /* After read predefined TXT, we must set BB/MAC/RF + * register as our requirement */ + + rtlphy->rfreg_chnlval[0] = rtl92s_phy_query_rf_reg(hw, + (enum radio_path)0, + RF_CHNLBW, + RFREG_OFFSET_MASK); + rtlphy->rfreg_chnlval[1] = rtl92s_phy_query_rf_reg(hw, + (enum radio_path)1, + RF_CHNLBW, + RFREG_OFFSET_MASK); + + /*---- Set CCK and OFDM Block "ON"----*/ + rtl_set_bbreg(hw, RFPGA0_RFMOD, BCCKEN, 0x1); + rtl_set_bbreg(hw, RFPGA0_RFMOD, BOFDMEN, 0x1); + + /*3 Set Hardware(Do nothing now) */ + _rtl92se_hw_configure(hw); + + /* Read EEPROM TX power index and PHY_REG_PG.txt to capture correct */ + /* TX power index for different rate set. */ + /* Get original hw reg values */ + rtl92s_phy_get_hw_reg_originalvalue(hw); + /* Write correct tx power index */ + rtl92s_phy_set_txpower(hw, rtlphy->current_channel); + + /* We must set MAC address after firmware download. */ + for (i = 0; i < 6; i++) + rtl_write_byte(rtlpriv, MACIDR0 + i, rtlefuse->dev_addr[i]); + + /* EEPROM R/W workaround */ + tmp_u1b = rtl_read_byte(rtlpriv, MAC_PINMUX_CFG); + rtl_write_byte(rtlpriv, MAC_PINMUX_CFG, tmp_u1b & (~BIT(3))); + + rtl_write_byte(rtlpriv, 0x4d, 0x0); + + if (hal_get_firmwareversion(rtlpriv) >= 0x49) { + tmp_byte = rtl_read_byte(rtlpriv, FW_RSVD_PG_CRTL) & (~BIT(4)); + tmp_byte = tmp_byte | BIT(5); + rtl_write_byte(rtlpriv, FW_RSVD_PG_CRTL, tmp_byte); + rtl_write_dword(rtlpriv, TXDESC_MSK, 0xFFFFCFFF); + } + + /* We enable high power and RA related mechanism after NIC + * initialized. */ + rtl92s_phy_set_fw_cmd(hw, FW_CMD_RA_INIT); + + /* Add to prevent ASPM bug. */ + /* Always enable hst and NIC clock request. */ + rtl92s_phy_switch_ephy_parameter(hw); + + /* Security related + * 1. Clear all H/W keys. + * 2. Enable H/W encryption/decryption. */ + rtl_cam_reset_all_entry(hw); + secr_value |= SCR_TXENCENABLE; + secr_value |= SCR_RXENCENABLE; + secr_value |= SCR_NOSKMC; + rtl_write_byte(rtlpriv, REG_SECR, secr_value); + + for (i = 0; i < 4; i++) + rtl_write_dword(rtlpriv, wdcapra_add[i], 0x5e4322); + + if (rtlphy->rf_type == RF_1T2R) { + bool mrc2set = true; + /* Turn on B-Path */ + rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_MRC, (u8 *)&mrc2set); + } + + rtlpriv->cfg->ops->led_control(hw, LED_CTL_POWER_ON); + rtl92s_dm_init(hw); + rtlpci->being_init_adapter = false; + + return err; +} + +void rtl92se_set_mac_addr(struct rtl_io *io, const u8 * addr) +{ +} + +void rtl92se_set_check_bssid(struct ieee80211_hw *hw, bool check_bssid) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); + u32 reg_rcr = rtlpci->receive_config; + + if (rtlpriv->psc.rfpwr_state != ERFON) + return; + + if (check_bssid == true) { + reg_rcr |= (RCR_CBSSID); + rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_RCR, (u8 *)(®_rcr)); + } else if (check_bssid == false) { + reg_rcr &= (~RCR_CBSSID); + rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_RCR, (u8 *)(®_rcr)); + } + +} + +static int _rtl92se_set_media_status(struct ieee80211_hw *hw, + enum nl80211_iftype type) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + u8 bt_msr = rtl_read_byte(rtlpriv, MSR); + enum led_ctl_mode ledaction = LED_CTL_NO_LINK; + u32 temp; + bt_msr &= ~MSR_LINK_MASK; + + switch (type) { + case NL80211_IFTYPE_UNSPECIFIED: + bt_msr |= (MSR_LINK_NONE << MSR_LINK_SHIFT); + ledaction = LED_CTL_LINK; + RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, + ("Set Network type to NO LINK!\n")); + break; + case NL80211_IFTYPE_ADHOC: + bt_msr |= (MSR_LINK_ADHOC << MSR_LINK_SHIFT); + RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, + ("Set Network type to Ad Hoc!\n")); + break; + case NL80211_IFTYPE_STATION: + bt_msr |= (MSR_LINK_MANAGED << MSR_LINK_SHIFT); + ledaction = LED_CTL_LINK; + RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, + ("Set Network type to STA!\n")); + break; + case NL80211_IFTYPE_AP: + bt_msr |= (MSR_LINK_MASTER << MSR_LINK_SHIFT); + RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, + ("Set Network type to AP!\n")); + break; + default: + RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, + ("Network type %d not support!\n", type)); + return 1; + break; + + } + + rtl_write_byte(rtlpriv, (MSR), bt_msr); + + temp = rtl_read_dword(rtlpriv, TCR); + rtl_write_dword(rtlpriv, TCR, temp & (~BIT(8))); + rtl_write_dword(rtlpriv, TCR, temp | BIT(8)); + + + return 0; +} + +/* HW_VAR_MEDIA_STATUS & HW_VAR_CECHK_BSSID */ +int rtl92se_set_network_type(struct ieee80211_hw *hw, enum nl80211_iftype type) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + + if (_rtl92se_set_media_status(hw, type)) + return -EOPNOTSUPP; + + if (rtlpriv->mac80211.link_state == MAC80211_LINKED) { + if (type != NL80211_IFTYPE_AP) + rtl92se_set_check_bssid(hw, true); + } else { + rtl92se_set_check_bssid(hw, false); + } + + return 0; +} + +/* don't set REG_EDCA_BE_PARAM here because mac80211 will send pkt when scan */ +void rtl92se_set_qos(struct ieee80211_hw *hw, int aci) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + rtl92s_dm_init_edca_turbo(hw); + + switch (aci) { + case AC1_BK: + rtl_write_dword(rtlpriv, EDCAPARA_BK, 0xa44f); + break; + case AC0_BE: + /* rtl_write_dword(rtlpriv, EDCAPARA_BE, u4b_ac_param); */ + break; + case AC2_VI: + rtl_write_dword(rtlpriv, EDCAPARA_VI, 0x5e4322); + break; + case AC3_VO: + rtl_write_dword(rtlpriv, EDCAPARA_VO, 0x2f3222); + break; + default: + RT_ASSERT(false, ("invalid aci: %d !\n", aci)); + break; + } +} + +void rtl92se_enable_interrupt(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); + + rtl_write_dword(rtlpriv, INTA_MASK, rtlpci->irq_mask[0]); + /* Support Bit 32-37(Assign as Bit 0-5) interrupt setting now */ + rtl_write_dword(rtlpriv, INTA_MASK + 4, rtlpci->irq_mask[1] & 0x3F); + + rtlpci->irq_enabled = true; +} + +void rtl92se_disable_interrupt(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); + + rtl_write_dword(rtlpriv, INTA_MASK, 0); + rtl_write_dword(rtlpriv, INTA_MASK + 4, 0); + + rtlpci->irq_enabled = false; +} + + +static u8 _rtl92s_set_sysclk(struct ieee80211_hw *hw, u8 data) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + u8 waitcnt = 100; + bool result = false; + u8 tmp; + + rtl_write_byte(rtlpriv, SYS_CLKR + 1, data); + + /* Wait the MAC synchronized. */ + udelay(400); + + /* Check if it is set ready. */ + tmp = rtl_read_byte(rtlpriv, SYS_CLKR + 1); + result = ((tmp & BIT(7)) == (data & BIT(7))); + + if ((data & (BIT(6) | BIT(7))) == false) { + waitcnt = 100; + tmp = 0; + + while (1) { + waitcnt--; + tmp = rtl_read_byte(rtlpriv, SYS_CLKR + 1); + + if ((tmp & BIT(6))) + break; + + printk(KERN_ERR "wait for BIT(6) return value %x\n", + tmp); + + if (waitcnt == 0) + break; + udelay(10); + } + + if (waitcnt == 0) + result = false; + else + result = true; + } + + return result; +} + +static void _rtl92s_phy_set_rfhalt(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); + struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); + u8 u1btmp; + + if (rtlhal->driver_going2unload) + rtl_write_byte(rtlpriv, 0x560, 0x0); + + /* Power save for BB/RF */ + u1btmp = rtl_read_byte(rtlpriv, LDOV12D_CTRL); + u1btmp |= BIT(0); + rtl_write_byte(rtlpriv, LDOV12D_CTRL, u1btmp); + rtl_write_byte(rtlpriv, SPS1_CTRL, 0x0); + rtl_write_byte(rtlpriv, TXPAUSE, 0xFF); + rtl_write_word(rtlpriv, CMDR, 0x57FC); + udelay(100); + rtl_write_word(rtlpriv, CMDR, 0x77FC); + rtl_write_byte(rtlpriv, PHY_CCA, 0x0); + udelay(10); + rtl_write_word(rtlpriv, CMDR, 0x37FC); + udelay(10); + rtl_write_word(rtlpriv, CMDR, 0x77FC); + udelay(10); + rtl_write_word(rtlpriv, CMDR, 0x57FC); + rtl_write_word(rtlpriv, CMDR, 0x0000); + + if (rtlhal->driver_going2unload) { + u1btmp = rtl_read_byte(rtlpriv, (REG_SYS_FUNC_EN + 1)); + u1btmp &= ~(BIT(0)); + rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN + 1, u1btmp); + } + + u1btmp = rtl_read_byte(rtlpriv, (SYS_CLKR + 1)); + + /* Add description. After switch control path. register + * after page1 will be invisible. We can not do any IO + * for register>0x40. After resume&MACIO reset, we need + * to remember previous reg content. */ + if (u1btmp & BIT(7)) { + u1btmp &= ~(BIT(6) | BIT(7)); + if (!_rtl92s_set_sysclk(hw, u1btmp)) { + printk(KERN_ERR "Switch ctrl path fail\n"); + return; + } + } + + /* Power save for MAC */ + if (ppsc->rfoff_reason == RF_CHANGE_BY_IPS && + !rtlhal->driver_going2unload) { + /* enable LED function */ + rtl_write_byte(rtlpriv, 0x03, 0xF9); + /* SW/HW radio off or halt adapter!! For example S3/S4 */ + } else { + /* LED function disable. Power range is about 8mA now. */ + /* if write 0xF1 disconnet_pci power + * ifconfig wlan0 down power are both high 35:70 */ + /* if write oxF9 disconnet_pci power + * ifconfig wlan0 down power are both low 12:45*/ + rtl_write_byte(rtlpriv, 0x03, 0xF9); + } + + rtl_write_byte(rtlpriv, SYS_CLKR + 1, 0x70); + rtl_write_byte(rtlpriv, AFE_PLL_CTRL + 1, 0x68); + rtl_write_byte(rtlpriv, AFE_PLL_CTRL, 0x00); + rtl_write_byte(rtlpriv, LDOA15_CTRL, 0x34); + rtl_write_byte(rtlpriv, AFE_XTAL_CTRL, 0x0E); + RT_SET_PS_LEVEL(ppsc, RT_RF_OFF_LEVL_HALT_NIC); + +} + +static void _rtl92se_gen_refreshledstate(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); + struct rtl_pci_priv *pcipriv = rtl_pcipriv(hw); + struct rtl_led *pLed0 = &(pcipriv->ledctl.sw_led0); + + if (rtlpci->up_first_time == 1) + return; + + if (rtlpriv->psc.rfoff_reason == RF_CHANGE_BY_IPS) + rtl92se_sw_led_on(hw, pLed0); + else + rtl92se_sw_led_off(hw, pLed0); +} + + +static void _rtl92se_power_domain_init(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + u16 tmpu2b; + u8 tmpu1b; + + rtlpriv->psc.pwrdomain_protect = true; + + tmpu1b = rtl_read_byte(rtlpriv, (SYS_CLKR + 1)); + if (tmpu1b & BIT(7)) { + tmpu1b &= ~(BIT(6) | BIT(7)); + if (!_rtl92s_set_sysclk(hw, tmpu1b)) { + rtlpriv->psc.pwrdomain_protect = false; + return; + } + } + + rtl_write_byte(rtlpriv, AFE_PLL_CTRL, 0x0); + rtl_write_byte(rtlpriv, LDOA15_CTRL, 0x34); + + /* Reset MAC-IO and CPU and Core Digital BIT10/11/15 */ + tmpu1b = rtl_read_byte(rtlpriv, SYS_FUNC_EN + 1); + + /* If IPS we need to turn LED on. So we not + * not disable BIT 3/7 of reg3. */ + if (rtlpriv->psc.rfoff_reason & (RF_CHANGE_BY_IPS | RF_CHANGE_BY_HW)) + tmpu1b &= 0xFB; + else + tmpu1b &= 0x73; + + rtl_write_byte(rtlpriv, SYS_FUNC_EN + 1, tmpu1b); + /* wait for BIT 10/11/15 to pull high automatically!! */ + mdelay(1); + + rtl_write_byte(rtlpriv, CMDR, 0); + rtl_write_byte(rtlpriv, TCR, 0); + + /* Data sheet not define 0x562!!! Copy from WMAC!!!!! */ + tmpu1b = rtl_read_byte(rtlpriv, 0x562); + tmpu1b |= 0x08; + rtl_write_byte(rtlpriv, 0x562, tmpu1b); + tmpu1b &= ~(BIT(3)); + rtl_write_byte(rtlpriv, 0x562, tmpu1b); + + /* Enable AFE clock source */ + tmpu1b = rtl_read_byte(rtlpriv, AFE_XTAL_CTRL); + rtl_write_byte(rtlpriv, AFE_XTAL_CTRL, (tmpu1b | 0x01)); + /* Delay 1.5ms */ + udelay(1500); + tmpu1b = rtl_read_byte(rtlpriv, AFE_XTAL_CTRL + 1); + rtl_write_byte(rtlpriv, AFE_XTAL_CTRL + 1, (tmpu1b & 0xfb)); + + /* Enable AFE Macro Block's Bandgap */ + tmpu1b = rtl_read_byte(rtlpriv, AFE_MISC); + rtl_write_byte(rtlpriv, AFE_MISC, (tmpu1b | BIT(0))); + mdelay(1); + + /* Enable AFE Mbias */ + tmpu1b = rtl_read_byte(rtlpriv, AFE_MISC); + rtl_write_byte(rtlpriv, AFE_MISC, (tmpu1b | 0x02)); + mdelay(1); + + /* Enable LDOA15 block */ + tmpu1b = rtl_read_byte(rtlpriv, LDOA15_CTRL); + rtl_write_byte(rtlpriv, LDOA15_CTRL, (tmpu1b | BIT(0))); + + /* Set Digital Vdd to Retention isolation Path. */ + tmpu2b = rtl_read_word(rtlpriv, SYS_ISO_CTRL); + rtl_write_word(rtlpriv, SYS_ISO_CTRL, (tmpu2b | BIT(11))); + + + /* For warm reboot NIC disappera bug. */ + tmpu2b = rtl_read_word(rtlpriv, SYS_FUNC_EN); + rtl_write_word(rtlpriv, SYS_FUNC_EN, (tmpu2b | BIT(13))); + + rtl_write_byte(rtlpriv, SYS_ISO_CTRL + 1, 0x68); + + /* Enable AFE PLL Macro Block */ + tmpu1b = rtl_read_byte(rtlpriv, AFE_PLL_CTRL); + rtl_write_byte(rtlpriv, AFE_PLL_CTRL, (tmpu1b | BIT(0) | BIT(4))); + /* Enable MAC 80MHZ clock */ + tmpu1b = rtl_read_byte(rtlpriv, AFE_PLL_CTRL + 1); + rtl_write_byte(rtlpriv, AFE_PLL_CTRL + 1, (tmpu1b | BIT(0))); + mdelay(1); + + /* Release isolation AFE PLL & MD */ + rtl_write_byte(rtlpriv, SYS_ISO_CTRL, 0xA6); + + /* Enable MAC clock */ + tmpu2b = rtl_read_word(rtlpriv, SYS_CLKR); + rtl_write_word(rtlpriv, SYS_CLKR, (tmpu2b | BIT(12) | BIT(11))); + + /* Enable Core digital and enable IOREG R/W */ + tmpu2b = rtl_read_word(rtlpriv, SYS_FUNC_EN); + rtl_write_word(rtlpriv, SYS_FUNC_EN, (tmpu2b | BIT(11))); + /* enable REG_EN */ + rtl_write_word(rtlpriv, SYS_FUNC_EN, (tmpu2b | BIT(11) | BIT(15))); + + /* Switch the control path. */ + tmpu2b = rtl_read_word(rtlpriv, SYS_CLKR); + rtl_write_word(rtlpriv, SYS_CLKR, (tmpu2b & (~BIT(2)))); + + tmpu1b = rtl_read_byte(rtlpriv, (SYS_CLKR + 1)); + tmpu1b = ((tmpu1b | BIT(7)) & (~BIT(6))); + if (!_rtl92s_set_sysclk(hw, tmpu1b)) { + rtlpriv->psc.pwrdomain_protect = false; + return; + } + + rtl_write_word(rtlpriv, CMDR, 0x37FC); + + /* After MACIO reset,we must refresh LED state. */ + _rtl92se_gen_refreshledstate(hw); + + rtlpriv->psc.pwrdomain_protect = false; +} + +void rtl92se_card_disable(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); + struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); + struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); + enum nl80211_iftype opmode; + u8 wait = 30; + + rtlpriv->intf_ops->enable_aspm(hw); + + if (rtlpci->driver_is_goingto_unload || + ppsc->rfoff_reason > RF_CHANGE_BY_PS) + rtlpriv->cfg->ops->led_control(hw, LED_CTL_POWER_OFF); + + /* we should chnge GPIO to input mode + * this will drop away current about 25mA*/ + rtl8192se_gpiobit3_cfg_inputmode(hw); + + /* this is very important for ips power save */ + while (wait-- >= 10 && rtlpriv->psc.pwrdomain_protect) { + if (rtlpriv->psc.pwrdomain_protect) + mdelay(20); + else + break; + } + + mac->link_state = MAC80211_NOLINK; + opmode = NL80211_IFTYPE_UNSPECIFIED; + _rtl92se_set_media_status(hw, opmode); + + _rtl92s_phy_set_rfhalt(hw); + udelay(100); +} + +void rtl92se_interrupt_recognized(struct ieee80211_hw *hw, u32 *p_inta, + u32 *p_intb) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); + + *p_inta = rtl_read_dword(rtlpriv, ISR) & rtlpci->irq_mask[0]; + rtl_write_dword(rtlpriv, ISR, *p_inta); + + *p_intb = rtl_read_dword(rtlpriv, ISR + 4) & rtlpci->irq_mask[1]; + rtl_write_dword(rtlpriv, ISR + 4, *p_intb); +} + +void rtl92se_set_beacon_related_registers(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); + u16 bcntime_cfg = 0; + u16 bcn_cw = 6, bcn_ifs = 0xf; + u16 atim_window = 2; + + /* ATIM Window (in unit of TU). */ + rtl_write_word(rtlpriv, ATIMWND, atim_window); + + /* Beacon interval (in unit of TU). */ + rtl_write_word(rtlpriv, BCN_INTERVAL, mac->beacon_interval); + + /* DrvErlyInt (in unit of TU). (Time to send + * interrupt to notify driver to change + * beacon content) */ + rtl_write_word(rtlpriv, BCN_DRV_EARLY_INT, 10 << 4); + + /* BcnDMATIM(in unit of us). Indicates the + * time before TBTT to perform beacon queue DMA */ + rtl_write_word(rtlpriv, BCN_DMATIME, 256); + + /* Force beacon frame transmission even + * after receiving beacon frame from + * other ad hoc STA */ + rtl_write_byte(rtlpriv, BCN_ERR_THRESH, 100); + + /* Beacon Time Configuration */ + if (mac->opmode == NL80211_IFTYPE_ADHOC) + bcntime_cfg |= (bcn_cw << BCN_TCFG_CW_SHIFT); + + /* TODO: bcn_ifs may required to be changed on ASIC */ + bcntime_cfg |= bcn_ifs << BCN_TCFG_IFS; + + /*for beacon changed */ + rtl92s_phy_set_beacon_hwreg(hw, mac->beacon_interval); +} + +void rtl92se_set_beacon_interval(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); + u16 bcn_interval = mac->beacon_interval; + + /* Beacon interval (in unit of TU). */ + rtl_write_word(rtlpriv, BCN_INTERVAL, bcn_interval); + /* 2008.10.24 added by tynli for beacon changed. */ + rtl92s_phy_set_beacon_hwreg(hw, bcn_interval); +} + +void rtl92se_update_interrupt_mask(struct ieee80211_hw *hw, + u32 add_msr, u32 rm_msr) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); + + RT_TRACE(rtlpriv, COMP_INTR, DBG_LOUD, + ("add_msr:%x, rm_msr:%x\n", add_msr, rm_msr)); + + if (add_msr) + rtlpci->irq_mask[0] |= add_msr; + + if (rm_msr) + rtlpci->irq_mask[0] &= (~rm_msr); + + rtl92se_disable_interrupt(hw); + rtl92se_enable_interrupt(hw); +} + +static void _rtl8192se_get_IC_Inferiority(struct ieee80211_hw *hw) +{ + struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw)); + struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); + u8 efuse_id; + + rtlhal->ic_class = IC_INFERIORITY_A; + + /* Only retrieving while using EFUSE. */ + if ((rtlefuse->epromtype == EEPROM_BOOT_EFUSE) && + !rtlefuse->autoload_failflag) { + efuse_id = efuse_read_1byte(hw, EFUSE_IC_ID_OFFSET); + + if (efuse_id == 0xfe) + rtlhal->ic_class = IC_INFERIORITY_B; + } +} + +static void _rtl92se_read_adapter_info(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw)); + struct rtl_phy *rtlphy = &(rtlpriv->phy); + u16 i, usvalue; + u16 eeprom_id; + u8 tempval; + u8 hwinfo[HWSET_MAX_SIZE_92S]; + u8 rf_path, index; + + if (rtlefuse->epromtype == EEPROM_93C46) { + RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, + ("RTL819X Not boot from eeprom, check it !!")); + } else if (rtlefuse->epromtype == EEPROM_BOOT_EFUSE) { + rtl_efuse_shadow_map_update(hw); + + memcpy((void *)hwinfo, (void *) + &rtlefuse->efuse_map[EFUSE_INIT_MAP][0], + HWSET_MAX_SIZE_92S); + } + + RT_PRINT_DATA(rtlpriv, COMP_INIT, DBG_DMESG, ("MAP\n"), + hwinfo, HWSET_MAX_SIZE_92S); + + eeprom_id = *((u16 *)&hwinfo[0]); + if (eeprom_id != RTL8190_EEPROM_ID) { + RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING, + ("EEPROM ID(%#x) is invalid!!\n", eeprom_id)); + rtlefuse->autoload_failflag = true; + } else { + RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, ("Autoload OK\n")); + rtlefuse->autoload_failflag = false; + } + + if (rtlefuse->autoload_failflag == true) + return; + + _rtl8192se_get_IC_Inferiority(hw); + + /* Read IC Version && Channel Plan */ + /* VID, DID SE 0xA-D */ + rtlefuse->eeprom_vid = *(u16 *)&hwinfo[EEPROM_VID]; + rtlefuse->eeprom_did = *(u16 *)&hwinfo[EEPROM_DID]; + rtlefuse->eeprom_svid = *(u16 *)&hwinfo[EEPROM_SVID]; + rtlefuse->eeprom_smid = *(u16 *)&hwinfo[EEPROM_SMID]; + rtlefuse->eeprom_version = *(u16 *)&hwinfo[EEPROM_VERSION]; + + RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, + ("EEPROMId = 0x%4x\n", eeprom_id)); + RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, + ("EEPROM VID = 0x%4x\n", rtlefuse->eeprom_vid)); + RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, + ("EEPROM DID = 0x%4x\n", rtlefuse->eeprom_did)); + RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, + ("EEPROM SVID = 0x%4x\n", rtlefuse->eeprom_svid)); + RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, + ("EEPROM SMID = 0x%4x\n", rtlefuse->eeprom_smid)); + + for (i = 0; i < 6; i += 2) { + usvalue = *(u16 *)&hwinfo[EEPROM_MAC_ADDR + i]; + *((u16 *) (&rtlefuse->dev_addr[i])) = usvalue; + } + + for (i = 0; i < 6; i++) + rtl_write_byte(rtlpriv, MACIDR0 + i, rtlefuse->dev_addr[i]); + + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, + (MAC_FMT "\n", MAC_ARG(rtlefuse->dev_addr))); + + /* Get Tx Power Level by Channel */ + /* Read Tx power of Channel 1 ~ 14 from EEPROM. */ + /* 92S suupport RF A & B */ + for (rf_path = 0; rf_path < 2; rf_path++) { + for (i = 0; i < 3; i++) { + /* Read CCK RF A & B Tx power */ + rtlefuse->eeprom_chnlarea_txpwr_cck[rf_path][i] = + hwinfo[EEPROM_TXPOWERBASE + rf_path * 3 + i]; + + /* Read OFDM RF A & B Tx power for 1T */ + rtlefuse->eeprom_chnlarea_txpwr_ht40_1s[rf_path][i] = + hwinfo[EEPROM_TXPOWERBASE + 6 + rf_path * 3 + i]; + + /* Read OFDM RF A & B Tx power for 2T */ + rtlefuse->eeprom_chnlarea_txpwr_ht40_2sdiif[rf_path][i] + = hwinfo[EEPROM_TXPOWERBASE + 12 + + rf_path * 3 + i]; + } + } + + for (rf_path = 0; rf_path < 2; rf_path++) + for (i = 0; i < 3; i++) + RTPRINT(rtlpriv, FINIT, INIT_EEPROM, + ("RF(%d) EEPROM CCK Area(%d) = 0x%x\n", rf_path, + i, rtlefuse->eeprom_chnlarea_txpwr_cck + [rf_path][i])); + for (rf_path = 0; rf_path < 2; rf_path++) + for (i = 0; i < 3; i++) + RTPRINT(rtlpriv, FINIT, INIT_EEPROM, + ("RF(%d) EEPROM HT40 1S Area(%d) = 0x%x\n", + rf_path, i, + rtlefuse->eeprom_chnlarea_txpwr_ht40_1s + [rf_path][i])); + for (rf_path = 0; rf_path < 2; rf_path++) + for (i = 0; i < 3; i++) + RTPRINT(rtlpriv, FINIT, INIT_EEPROM, + ("RF(%d) EEPROM HT40 2S Diff Area(%d) = 0x%x\n", + rf_path, i, + rtlefuse->eeprom_chnlarea_txpwr_ht40_2sdiif + [rf_path][i])); + + for (rf_path = 0; rf_path < 2; rf_path++) { + + /* Assign dedicated channel tx power */ + for (i = 0; i < 14; i++) { + /* channel 1~3 use the same Tx Power Level. */ + if (i < 3) + index = 0; + /* Channel 4-8 */ + else if (i < 8) + index = 1; + /* Channel 9-14 */ + else + index = 2; + + /* Record A & B CCK /OFDM - 1T/2T Channel area + * tx power */ + rtlefuse->txpwrlevel_cck[rf_path][i] = + rtlefuse->eeprom_chnlarea_txpwr_cck + [rf_path][index]; + rtlefuse->txpwrlevel_ht40_1s[rf_path][i] = + rtlefuse->eeprom_chnlarea_txpwr_ht40_1s + [rf_path][index]; + rtlefuse->txpwrlevel_ht40_2s[rf_path][i] = + rtlefuse->eeprom_chnlarea_txpwr_ht40_2sdiif + [rf_path][index]; + } + + for (i = 0; i < 14; i++) { + RTPRINT(rtlpriv, FINIT, INIT_TxPower, + ("RF(%d)-Ch(%d) [CCK / HT40_1S / HT40_2S] = " + "[0x%x / 0x%x / 0x%x]\n", rf_path, i, + rtlefuse->txpwrlevel_cck[rf_path][i], + rtlefuse->txpwrlevel_ht40_1s[rf_path][i], + rtlefuse->txpwrlevel_ht40_2s[rf_path][i])); + } + } + + for (rf_path = 0; rf_path < 2; rf_path++) { + for (i = 0; i < 3; i++) { + /* Read Power diff limit. */ + rtlefuse->eeprom_pwrgroup[rf_path][i] = + hwinfo[EEPROM_TXPWRGROUP + rf_path * 3 + i]; + } + } + + for (rf_path = 0; rf_path < 2; rf_path++) { + /* Fill Pwr group */ + for (i = 0; i < 14; i++) { + /* Chanel 1-3 */ + if (i < 3) + index = 0; + /* Channel 4-8 */ + else if (i < 8) + index = 1; + /* Channel 9-13 */ + else + index = 2; + + rtlefuse->pwrgroup_ht20[rf_path][i] = + (rtlefuse->eeprom_pwrgroup[rf_path][index] & + 0xf); + rtlefuse->pwrgroup_ht40[rf_path][i] = + ((rtlefuse->eeprom_pwrgroup[rf_path][index] & + 0xf0) >> 4); + + RTPRINT(rtlpriv, FINIT, INIT_TxPower, + ("RF-%d pwrgroup_ht20[%d] = 0x%x\n", + rf_path, i, + rtlefuse->pwrgroup_ht20[rf_path][i])); + RTPRINT(rtlpriv, FINIT, INIT_TxPower, + ("RF-%d pwrgroup_ht40[%d] = 0x%x\n", + rf_path, i, + rtlefuse->pwrgroup_ht40[rf_path][i])); + } + } + + for (i = 0; i < 14; i++) { + /* Read tx power difference between HT OFDM 20/40 MHZ */ + /* channel 1-3 */ + if (i < 3) + index = 0; + /* Channel 4-8 */ + else if (i < 8) + index = 1; + /* Channel 9-14 */ + else + index = 2; + + tempval = (*(u8 *)&hwinfo[EEPROM_TX_PWR_HT20_DIFF + + index]) & 0xff; + rtlefuse->txpwr_ht20diff[RF90_PATH_A][i] = (tempval & 0xF); + rtlefuse->txpwr_ht20diff[RF90_PATH_B][i] = + ((tempval >> 4) & 0xF); + + /* Read OFDM<->HT tx power diff */ + /* Channel 1-3 */ + if (i < 3) + index = 0; + /* Channel 4-8 */ + else if (i < 8) + index = 0x11; + /* Channel 9-14 */ + else + index = 1; + + tempval = (*(u8 *)&hwinfo[EEPROM_TX_PWR_OFDM_DIFF + index]) + & 0xff; + rtlefuse->txpwr_legacyhtdiff[RF90_PATH_A][i] = + (tempval & 0xF); + rtlefuse->txpwr_legacyhtdiff[RF90_PATH_B][i] = + ((tempval >> 4) & 0xF); + + tempval = (*(u8 *)&hwinfo[TX_PWR_SAFETY_CHK]); + rtlefuse->txpwr_safetyflag = (tempval & 0x01); + } + + rtlefuse->eeprom_regulatory = 0; + if (rtlefuse->eeprom_version >= 2) { + /* BIT(0)~2 */ + if (rtlefuse->eeprom_version >= 4) + rtlefuse->eeprom_regulatory = + (hwinfo[EEPROM_REGULATORY] & 0x7); + else /* BIT(0) */ + rtlefuse->eeprom_regulatory = + (hwinfo[EEPROM_REGULATORY] & 0x1); + } + RTPRINT(rtlpriv, FINIT, INIT_TxPower, + ("eeprom_regulatory = 0x%x\n", rtlefuse->eeprom_regulatory)); + + for (i = 0; i < 14; i++) + RTPRINT(rtlpriv, FINIT, INIT_TxPower, + ("RF-A Ht20 to HT40 Diff[%d] = 0x%x\n", i, + rtlefuse->txpwr_ht20diff[RF90_PATH_A][i])); + for (i = 0; i < 14; i++) + RTPRINT(rtlpriv, FINIT, INIT_TxPower, + ("RF-A Legacy to Ht40 Diff[%d] = 0x%x\n", i, + rtlefuse->txpwr_legacyhtdiff[RF90_PATH_A][i])); + for (i = 0; i < 14; i++) + RTPRINT(rtlpriv, FINIT, INIT_TxPower, + ("RF-B Ht20 to HT40 Diff[%d] = 0x%x\n", i, + rtlefuse->txpwr_ht20diff[RF90_PATH_B][i])); + for (i = 0; i < 14; i++) + RTPRINT(rtlpriv, FINIT, INIT_TxPower, + ("RF-B Legacy to HT40 Diff[%d] = 0x%x\n", i, + rtlefuse->txpwr_legacyhtdiff[RF90_PATH_B][i])); + + RTPRINT(rtlpriv, FINIT, INIT_TxPower, ("TxPwrSafetyFlag = %d\n", + rtlefuse->txpwr_safetyflag)); + + /* Read RF-indication and Tx Power gain + * index diff of legacy to HT OFDM rate. */ + tempval = (*(u8 *)&hwinfo[EEPROM_RFIND_POWERDIFF]) & 0xff; + rtlefuse->eeprom_txpowerdiff = tempval; + rtlefuse->legacy_httxpowerdiff = + rtlefuse->txpwr_legacyhtdiff[RF90_PATH_A][0]; + + RTPRINT(rtlpriv, FINIT, INIT_TxPower, ("TxPowerDiff = %#x\n", + rtlefuse->eeprom_txpowerdiff)); + + /* Get TSSI value for each path. */ + usvalue = *(u16 *)&hwinfo[EEPROM_TSSI_A]; + rtlefuse->eeprom_tssi[RF90_PATH_A] = (u8)((usvalue & 0xff00) >> 8); + usvalue = *(u8 *)&hwinfo[EEPROM_TSSI_B]; + rtlefuse->eeprom_tssi[RF90_PATH_B] = (u8)(usvalue & 0xff); + + RTPRINT(rtlpriv, FINIT, INIT_TxPower, ("TSSI_A = 0x%x, TSSI_B = 0x%x\n", + rtlefuse->eeprom_tssi[RF90_PATH_A], + rtlefuse->eeprom_tssi[RF90_PATH_B])); + + /* Read antenna tx power offset of B/C/D to A from EEPROM */ + /* and read ThermalMeter from EEPROM */ + tempval = *(u8 *)&hwinfo[EEPROM_THERMALMETER]; + rtlefuse->eeprom_thermalmeter = tempval; + RTPRINT(rtlpriv, FINIT, INIT_TxPower, ("thermalmeter = 0x%x\n", + rtlefuse->eeprom_thermalmeter)); + + /* ThermalMeter, BIT(0)~3 for RFIC1, BIT(4)~7 for RFIC2 */ + rtlefuse->thermalmeter[0] = (rtlefuse->eeprom_thermalmeter & 0x1f); + rtlefuse->tssi_13dbm = rtlefuse->eeprom_thermalmeter * 100; + + /* Read CrystalCap from EEPROM */ + tempval = (*(u8 *)&hwinfo[EEPROM_CRYSTALCAP]) >> 4; + rtlefuse->eeprom_crystalcap = tempval; + /* CrystalCap, BIT(12)~15 */ + rtlefuse->crystalcap = rtlefuse->eeprom_crystalcap; + + /* Read IC Version && Channel Plan */ + /* Version ID, Channel plan */ + rtlefuse->eeprom_channelplan = *(u8 *)&hwinfo[EEPROM_CHANNELPLAN]; + rtlefuse->txpwr_fromeprom = true; + RTPRINT(rtlpriv, FINIT, INIT_TxPower, ("EEPROM ChannelPlan = 0x%4x\n", + rtlefuse->eeprom_channelplan)); + + /* Read Customer ID or Board Type!!! */ + tempval = *(u8 *)&hwinfo[EEPROM_BOARDTYPE]; + /* Change RF type definition */ + if (tempval == 0) + rtlphy->rf_type = RF_2T2R; + else if (tempval == 1) + rtlphy->rf_type = RF_1T2R; + else if (tempval == 2) + rtlphy->rf_type = RF_1T2R; + else if (tempval == 3) + rtlphy->rf_type = RF_1T1R; + + /* 1T2R but 1SS (1x1 receive combining) */ + rtlefuse->b1x1_recvcombine = false; + if (rtlphy->rf_type == RF_1T2R) { + tempval = rtl_read_byte(rtlpriv, 0x07); + if (!(tempval & BIT(0))) { + rtlefuse->b1x1_recvcombine = true; + RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, + ("RF_TYPE=1T2R but only 1SS\n")); + } + } + rtlefuse->b1ss_support = rtlefuse->b1x1_recvcombine; + rtlefuse->eeprom_oemid = *(u8 *)&hwinfo[EEPROM_CUSTOMID]; + + RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, ("EEPROM Customer ID: 0x%2x", + rtlefuse->eeprom_oemid)); + + /* set channel paln to world wide 13 */ + rtlefuse->channel_plan = COUNTRY_CODE_WORLD_WIDE_13; +} + +void rtl92se_read_eeprom_info(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw)); + u8 tmp_u1b = 0; + + tmp_u1b = rtl_read_byte(rtlpriv, EPROM_CMD); + + if (tmp_u1b & BIT(4)) { + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, ("Boot from EEPROM\n")); + rtlefuse->epromtype = EEPROM_93C46; + } else { + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, ("Boot from EFUSE\n")); + rtlefuse->epromtype = EEPROM_BOOT_EFUSE; + } + + if (tmp_u1b & BIT(5)) { + RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, ("Autoload OK\n")); + rtlefuse->autoload_failflag = false; + _rtl92se_read_adapter_info(hw); + } else { + RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, ("Autoload ERR!!\n")); + rtlefuse->autoload_failflag = true; + } +} + +static void rtl92se_update_hal_rate_table(struct ieee80211_hw *hw, + struct ieee80211_sta *sta) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_phy *rtlphy = &(rtlpriv->phy); + struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); + struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); + u32 ratr_value; + u8 ratr_index = 0; + u8 nmode = mac->ht_enable; + u8 mimo_ps = IEEE80211_SMPS_OFF; + u16 shortgi_rate = 0; + u32 tmp_ratr_value = 0; + u8 curtxbw_40mhz = mac->bw_40; + u8 curshortgi_40mhz = (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_40) ? + 1 : 0; + u8 curshortgi_20mhz = (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_20) ? + 1 : 0; + enum wireless_mode wirelessmode = mac->mode; + + if (rtlhal->current_bandtype == BAND_ON_5G) + ratr_value = sta->supp_rates[1] << 4; + else + ratr_value = sta->supp_rates[0]; + ratr_value |= (sta->ht_cap.mcs.rx_mask[1] << 20 | + sta->ht_cap.mcs.rx_mask[0] << 12); + switch (wirelessmode) { + case WIRELESS_MODE_B: + ratr_value &= 0x0000000D; + break; + case WIRELESS_MODE_G: + ratr_value &= 0x00000FF5; + break; + case WIRELESS_MODE_N_24G: + case WIRELESS_MODE_N_5G: + nmode = 1; + if (mimo_ps == IEEE80211_SMPS_STATIC) { + ratr_value &= 0x0007F005; + } else { + u32 ratr_mask; + + if (get_rf_type(rtlphy) == RF_1T2R || + get_rf_type(rtlphy) == RF_1T1R) { + if (curtxbw_40mhz) + ratr_mask = 0x000ff015; + else + ratr_mask = 0x000ff005; + } else { + if (curtxbw_40mhz) + ratr_mask = 0x0f0ff015; + else + ratr_mask = 0x0f0ff005; + } + + ratr_value &= ratr_mask; + } + break; + default: + if (rtlphy->rf_type == RF_1T2R) + ratr_value &= 0x000ff0ff; + else + ratr_value &= 0x0f0ff0ff; + + break; + } + + if (rtlpriv->rtlhal.version >= VERSION_8192S_BCUT) + ratr_value &= 0x0FFFFFFF; + else if (rtlpriv->rtlhal.version == VERSION_8192S_ACUT) + ratr_value &= 0x0FFFFFF0; + + if (nmode && ((curtxbw_40mhz && + curshortgi_40mhz) || (!curtxbw_40mhz && + curshortgi_20mhz))) { + + ratr_value |= 0x10000000; + tmp_ratr_value = (ratr_value >> 12); + + for (shortgi_rate = 15; shortgi_rate > 0; shortgi_rate--) { + if ((1 << shortgi_rate) & tmp_ratr_value) + break; + } + + shortgi_rate = (shortgi_rate << 12) | (shortgi_rate << 8) | + (shortgi_rate << 4) | (shortgi_rate); + + rtl_write_byte(rtlpriv, SG_RATE, shortgi_rate); + } + + rtl_write_dword(rtlpriv, ARFR0 + ratr_index * 4, ratr_value); + if (ratr_value & 0xfffff000) + rtl92s_phy_set_fw_cmd(hw, FW_CMD_RA_REFRESH_N); + else + rtl92s_phy_set_fw_cmd(hw, FW_CMD_RA_REFRESH_BG); + + RT_TRACE(rtlpriv, COMP_RATR, DBG_DMESG, + ("%x\n", rtl_read_dword(rtlpriv, ARFR0))); +} + +static void rtl92se_update_hal_rate_mask(struct ieee80211_hw *hw, + struct ieee80211_sta *sta, + u8 rssi_level) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_phy *rtlphy = &(rtlpriv->phy); + struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); + struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); + struct rtl_sta_info *sta_entry = NULL; + u32 ratr_bitmap; + u8 ratr_index = 0; + u8 curtxbw_40mhz = (sta->ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40) + ? 1 : 0; + u8 curshortgi_40mhz = (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_40) ? + 1 : 0; + u8 curshortgi_20mhz = (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_20) ? + 1 : 0; + enum wireless_mode wirelessmode = 0; + bool shortgi = false; + u32 ratr_value = 0; + u8 shortgi_rate = 0; + u32 mask = 0; + u32 band = 0; + bool bmulticast = false; + u8 macid = 0; + u8 mimo_ps = IEEE80211_SMPS_OFF; + + sta_entry = (struct rtl_sta_info *) sta->drv_priv; + wirelessmode = sta_entry->wireless_mode; + if (mac->opmode == NL80211_IFTYPE_STATION) + curtxbw_40mhz = mac->bw_40; + else if (mac->opmode == NL80211_IFTYPE_AP || + mac->opmode == NL80211_IFTYPE_ADHOC) + macid = sta->aid + 1; + + if (rtlhal->current_bandtype == BAND_ON_5G) + ratr_bitmap = sta->supp_rates[1] << 4; + else + ratr_bitmap = sta->supp_rates[0]; + ratr_bitmap |= (sta->ht_cap.mcs.rx_mask[1] << 20 | + sta->ht_cap.mcs.rx_mask[0] << 12); + switch (wirelessmode) { + case WIRELESS_MODE_B: + band |= WIRELESS_11B; + ratr_index = RATR_INX_WIRELESS_B; + if (ratr_bitmap & 0x0000000c) + ratr_bitmap &= 0x0000000d; + else + ratr_bitmap &= 0x0000000f; + break; + case WIRELESS_MODE_G: + band |= (WIRELESS_11G | WIRELESS_11B); + ratr_index = RATR_INX_WIRELESS_GB; + + if (rssi_level == 1) + ratr_bitmap &= 0x00000f00; + else if (rssi_level == 2) + ratr_bitmap &= 0x00000ff0; + else + ratr_bitmap &= 0x00000ff5; + break; + case WIRELESS_MODE_A: + band |= WIRELESS_11A; + ratr_index = RATR_INX_WIRELESS_A; + ratr_bitmap &= 0x00000ff0; + break; + case WIRELESS_MODE_N_24G: + case WIRELESS_MODE_N_5G: + band |= (WIRELESS_11N | WIRELESS_11G | WIRELESS_11B); + ratr_index = RATR_INX_WIRELESS_NGB; + + if (mimo_ps == IEEE80211_SMPS_STATIC) { + if (rssi_level == 1) + ratr_bitmap &= 0x00070000; + else if (rssi_level == 2) + ratr_bitmap &= 0x0007f000; + else + ratr_bitmap &= 0x0007f005; + } else { + if (rtlphy->rf_type == RF_1T2R || + rtlphy->rf_type == RF_1T1R) { + if (rssi_level == 1) { + ratr_bitmap &= 0x000f0000; + } else if (rssi_level == 3) { + ratr_bitmap &= 0x000fc000; + } else if (rssi_level == 5) { + ratr_bitmap &= 0x000ff000; + } else { + if (curtxbw_40mhz) + ratr_bitmap &= 0x000ff015; + else + ratr_bitmap &= 0x000ff005; + } + } else { + if (rssi_level == 1) { + ratr_bitmap &= 0x0f8f0000; + } else if (rssi_level == 3) { + ratr_bitmap &= 0x0f8fc000; + } else if (rssi_level == 5) { + ratr_bitmap &= 0x0f8ff000; + } else { + if (curtxbw_40mhz) + ratr_bitmap &= 0x0f8ff015; + else + ratr_bitmap &= 0x0f8ff005; + } + } + } + + if ((curtxbw_40mhz && curshortgi_40mhz) || + (!curtxbw_40mhz && curshortgi_20mhz)) { + if (macid == 0) + shortgi = true; + else if (macid == 1) + shortgi = false; + } + break; + default: + band |= (WIRELESS_11N | WIRELESS_11G | WIRELESS_11B); + ratr_index = RATR_INX_WIRELESS_NGB; + + if (rtlphy->rf_type == RF_1T2R) + ratr_bitmap &= 0x000ff0ff; + else + ratr_bitmap &= 0x0f8ff0ff; + break; + } + + if (rtlpriv->rtlhal.version >= VERSION_8192S_BCUT) + ratr_bitmap &= 0x0FFFFFFF; + else if (rtlpriv->rtlhal.version == VERSION_8192S_ACUT) + ratr_bitmap &= 0x0FFFFFF0; + + if (shortgi) { + ratr_bitmap |= 0x10000000; + /* Get MAX MCS available. */ + ratr_value = (ratr_bitmap >> 12); + for (shortgi_rate = 15; shortgi_rate > 0; shortgi_rate--) { + if ((1 << shortgi_rate) & ratr_value) + break; + } + + shortgi_rate = (shortgi_rate << 12) | (shortgi_rate << 8) | + (shortgi_rate << 4) | (shortgi_rate); + rtl_write_byte(rtlpriv, SG_RATE, shortgi_rate); + } + + mask |= (bmulticast ? 1 : 0) << 9 | (macid & 0x1f) << 4 | (band & 0xf); + + RT_TRACE(rtlpriv, COMP_RATR, DBG_TRACE, ("mask = %x, bitmap = %x\n", + mask, ratr_bitmap)); + rtl_write_dword(rtlpriv, 0x2c4, ratr_bitmap); + rtl_write_dword(rtlpriv, WFM5, (FW_RA_UPDATE_MASK | (mask << 8))); + + if (macid != 0) + sta_entry->ratr_index = ratr_index; +} + +void rtl92se_update_hal_rate_tbl(struct ieee80211_hw *hw, + struct ieee80211_sta *sta, u8 rssi_level) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + + if (rtlpriv->dm.useramask) + rtl92se_update_hal_rate_mask(hw, sta, rssi_level); + else + rtl92se_update_hal_rate_table(hw, sta); +} + +void rtl92se_update_channel_access_setting(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); + u16 sifs_timer; + + rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_SLOT_TIME, + (u8 *)&mac->slot_time); + sifs_timer = 0x0e0e; + rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_SIFS, (u8 *)&sifs_timer); + +} + +/* this ifunction is for RFKILL, it's different with windows, + * because UI will disable wireless when GPIO Radio Off. + * And here we not check or Disable/Enable ASPM like windows*/ +bool rtl92se_gpio_radio_on_off_checking(struct ieee80211_hw *hw, u8 *valid) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); + struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); + enum rf_pwrstate rfpwr_toset, cur_rfstate; + unsigned long flag = 0; + bool actuallyset = false; + bool turnonbypowerdomain = false; + + /* just 8191se can check gpio before firstup, 92c/92d have fixed it */ + if ((rtlpci->up_first_time == 1) || (rtlpci->being_init_adapter)) + return false; + + if (ppsc->swrf_processing) + return false; + + spin_lock_irqsave(&rtlpriv->locks.rf_ps_lock, flag); + if (ppsc->rfchange_inprogress) { + spin_unlock_irqrestore(&rtlpriv->locks.rf_ps_lock, flag); + return false; + } else { + ppsc->rfchange_inprogress = true; + spin_unlock_irqrestore(&rtlpriv->locks.rf_ps_lock, flag); + } + + cur_rfstate = ppsc->rfpwr_state; + + /* because after _rtl92s_phy_set_rfhalt, all power + * closed, so we must open some power for GPIO check, + * or we will always check GPIO RFOFF here, + * And we should close power after GPIO check */ + if (RT_IN_PS_LEVEL(ppsc, RT_RF_OFF_LEVL_HALT_NIC)) { + _rtl92se_power_domain_init(hw); + turnonbypowerdomain = true; + } + + rfpwr_toset = _rtl92se_rf_onoff_detect(hw); + + if ((ppsc->hwradiooff == true) && (rfpwr_toset == ERFON)) { + RT_TRACE(rtlpriv, COMP_RF, DBG_DMESG, + ("RFKILL-HW Radio ON, RF ON\n")); + + rfpwr_toset = ERFON; + ppsc->hwradiooff = false; + actuallyset = true; + } else if ((ppsc->hwradiooff == false) && (rfpwr_toset == ERFOFF)) { + RT_TRACE(rtlpriv, COMP_RF, DBG_DMESG, + ("RFKILL-HW Radio OFF, RF OFF\n")); + + rfpwr_toset = ERFOFF; + ppsc->hwradiooff = true; + actuallyset = true; + } + + if (actuallyset) { + spin_lock_irqsave(&rtlpriv->locks.rf_ps_lock, flag); + ppsc->rfchange_inprogress = false; + spin_unlock_irqrestore(&rtlpriv->locks.rf_ps_lock, flag); + + /* this not include ifconfig wlan0 down case */ + /* } else if (rfpwr_toset == ERFOFF || cur_rfstate == ERFOFF) { */ + } else { + /* because power_domain_init may be happen when + * _rtl92s_phy_set_rfhalt, this will open some powers + * and cause current increasing about 40 mA for ips, + * rfoff and ifconfig down, so we set + * _rtl92s_phy_set_rfhalt again here */ + if (ppsc->reg_rfps_level & RT_RF_OFF_LEVL_HALT_NIC && + turnonbypowerdomain) { + _rtl92s_phy_set_rfhalt(hw); + RT_SET_PS_LEVEL(ppsc, RT_RF_OFF_LEVL_HALT_NIC); + } + + spin_lock_irqsave(&rtlpriv->locks.rf_ps_lock, flag); + ppsc->rfchange_inprogress = false; + spin_unlock_irqrestore(&rtlpriv->locks.rf_ps_lock, flag); + } + + *valid = 1; + return !ppsc->hwradiooff; + +} + +/* Is_wepkey just used for WEP used as group & pairwise key + * if pairwise is AES ang group is WEP Is_wepkey == false.*/ +void rtl92se_set_key(struct ieee80211_hw *hw, u32 key_index, u8 *p_macaddr, + bool is_group, u8 enc_algo, bool is_wepkey, bool clear_all) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); + struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw)); + u8 *macaddr = p_macaddr; + + u32 entry_id = 0; + bool is_pairwise = false; + + static u8 cam_const_addr[4][6] = { + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x01}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x02}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x03} + }; + static u8 cam_const_broad[] = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff + }; + + if (clear_all) { + u8 idx = 0; + u8 cam_offset = 0; + u8 clear_number = 5; + + RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG, ("clear_all\n")); + + for (idx = 0; idx < clear_number; idx++) { + rtl_cam_mark_invalid(hw, cam_offset + idx); + rtl_cam_empty_entry(hw, cam_offset + idx); + + if (idx < 5) { + memset(rtlpriv->sec.key_buf[idx], 0, + MAX_KEY_LEN); + rtlpriv->sec.key_len[idx] = 0; + } + } + + } else { + switch (enc_algo) { + case WEP40_ENCRYPTION: + enc_algo = CAM_WEP40; + break; + case WEP104_ENCRYPTION: + enc_algo = CAM_WEP104; + break; + case TKIP_ENCRYPTION: + enc_algo = CAM_TKIP; + break; + case AESCCMP_ENCRYPTION: + enc_algo = CAM_AES; + break; + default: + RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, + ("switch case not process\n")); + enc_algo = CAM_TKIP; + break; + } + + if (is_wepkey || rtlpriv->sec.use_defaultkey) { + macaddr = cam_const_addr[key_index]; + entry_id = key_index; + } else { + if (is_group) { + macaddr = cam_const_broad; + entry_id = key_index; + } else { + if (mac->opmode == NL80211_IFTYPE_AP) { + entry_id = rtl_cam_get_free_entry(hw, + p_macaddr); + if (entry_id >= TOTAL_CAM_ENTRY) { + RT_TRACE(rtlpriv, + COMP_SEC, DBG_EMERG, + ("Can not find free hw" + " security cam entry\n")); + return; + } + } else { + entry_id = CAM_PAIRWISE_KEY_POSITION; + } + + key_index = PAIRWISE_KEYIDX; + is_pairwise = true; + } + } + + if (rtlpriv->sec.key_len[key_index] == 0) { + RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG, + ("delete one entry, entry_id is %d\n", + entry_id)); + if (mac->opmode == NL80211_IFTYPE_AP) + rtl_cam_del_entry(hw, p_macaddr); + rtl_cam_delete_one_entry(hw, p_macaddr, entry_id); + } else { + RT_TRACE(rtlpriv, COMP_SEC, DBG_LOUD, + ("The insert KEY length is %d\n", + rtlpriv->sec.key_len[PAIRWISE_KEYIDX])); + RT_TRACE(rtlpriv, COMP_SEC, DBG_LOUD, + ("The insert KEY is %x %x\n", + rtlpriv->sec.key_buf[0][0], + rtlpriv->sec.key_buf[0][1])); + + RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG, + ("add one entry\n")); + if (is_pairwise) { + RT_PRINT_DATA(rtlpriv, COMP_SEC, DBG_LOUD, + "Pairwiase Key content :", + rtlpriv->sec.pairwise_key, + rtlpriv->sec.key_len[PAIRWISE_KEYIDX]); + + RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG, + ("set Pairwiase key\n")); + + rtl_cam_add_one_entry(hw, macaddr, key_index, + entry_id, enc_algo, + CAM_CONFIG_NO_USEDK, + rtlpriv->sec.key_buf[key_index]); + } else { + RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG, + ("set group key\n")); + + if (mac->opmode == NL80211_IFTYPE_ADHOC) { + rtl_cam_add_one_entry(hw, + rtlefuse->dev_addr, + PAIRWISE_KEYIDX, + CAM_PAIRWISE_KEY_POSITION, + enc_algo, CAM_CONFIG_NO_USEDK, + rtlpriv->sec.key_buf[entry_id]); + } + + rtl_cam_add_one_entry(hw, macaddr, key_index, + entry_id, enc_algo, + CAM_CONFIG_NO_USEDK, + rtlpriv->sec.key_buf[entry_id]); + } + + } + } +} + +void rtl92se_suspend(struct ieee80211_hw *hw) +{ + struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); + + rtlpci->up_first_time = true; +} + +void rtl92se_resume(struct ieee80211_hw *hw) +{ + struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); + u32 val; + + pci_read_config_dword(rtlpci->pdev, 0x40, &val); + if ((val & 0x0000ff00) != 0) + pci_write_config_dword(rtlpci->pdev, 0x40, + val & 0xffff00ff); +} diff --git a/drivers/net/wireless/rtlwifi/rtl8192se/hw.h b/drivers/net/wireless/rtlwifi/rtl8192se/hw.h new file mode 100644 index 0000000..6160a9b --- /dev/null +++ b/drivers/net/wireless/rtlwifi/rtl8192se/hw.h @@ -0,0 +1,79 @@ +/****************************************************************************** + * + * Copyright(c) 2009-2010 Realtek Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger + * + *****************************************************************************/ +#ifndef __REALTEK_PCI92SE_HW_H__ +#define __REALTEK_PCI92SE_HW_H__ + +#define MSR_LINK_MANAGED 2 +#define MSR_LINK_NONE 0 +#define MSR_LINK_SHIFT 0 +#define MSR_LINK_ADHOC 1 +#define MSR_LINK_MASTER 3 + +enum WIRELESS_NETWORK_TYPE { + WIRELESS_11B = 1, + WIRELESS_11G = 2, + WIRELESS_11A = 4, + WIRELESS_11N = 8 +}; + +void rtl92se_get_hw_reg(struct ieee80211_hw *hw, + u8 variable, u8 *val); +void rtl92se_read_eeprom_info(struct ieee80211_hw *hw); +void rtl92se_interrupt_recognized(struct ieee80211_hw *hw, + u32 *inta, u32 *intb); +int rtl92se_hw_init(struct ieee80211_hw *hw); +void rtl92se_card_disable(struct ieee80211_hw *hw); +void rtl92se_enable_interrupt(struct ieee80211_hw *hw); +void rtl92se_disable_interrupt(struct ieee80211_hw *hw); +int rtl92se_set_network_type(struct ieee80211_hw *hw, + enum nl80211_iftype type); +void rtl92se_set_check_bssid(struct ieee80211_hw *hw, bool check_bssid); +void rtl92se_set_mac_addr(struct rtl_io *io, const u8 * addr); +void rtl92se_set_qos(struct ieee80211_hw *hw, int aci); +void rtl92se_set_beacon_related_registers(struct ieee80211_hw *hw); +void rtl92se_set_beacon_interval(struct ieee80211_hw *hw); +void rtl92se_update_interrupt_mask(struct ieee80211_hw *hw, + u32 add_msr, u32 rm_msr); +void rtl92se_set_hw_reg(struct ieee80211_hw *hw, u8 variable, + u8 *val); +void rtl92se_update_hal_rate_tbl(struct ieee80211_hw *hw, + struct ieee80211_sta *sta, u8 rssi_level); +void rtl92se_update_channel_access_setting(struct ieee80211_hw *hw); +bool rtl92se_gpio_radio_on_off_checking(struct ieee80211_hw *hw, + u8 *valid); +void rtl8192se_gpiobit3_cfg_inputmode(struct ieee80211_hw *hw); +void rtl92se_enable_hw_security_config(struct ieee80211_hw *hw); +void rtl92se_set_key(struct ieee80211_hw *hw, + u32 key_index, u8 *macaddr, bool is_group, + u8 enc_algo, bool is_wepkey, bool clear_all); +void rtl92se_suspend(struct ieee80211_hw *hw); +void rtl92se_resume(struct ieee80211_hw *hw); + +#endif + -- cgit v0.10.2 From 293380046bf1a80872d611143a5ee6a23f662472 Mon Sep 17 00:00:00 2001 From: Chaoming Li Date: Tue, 3 May 2011 09:48:25 -0500 Subject: rtlwifi: rtl8192se: Merge led routines Merge routines led.c and led.h for RTL8192SE. Signed-off-by: Chaoming_Li Signed-off-by: Larry Finger Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/rtlwifi/rtl8192se/led.c b/drivers/net/wireless/rtlwifi/rtl8192se/led.c new file mode 100644 index 0000000..6d4f666 --- /dev/null +++ b/drivers/net/wireless/rtlwifi/rtl8192se/led.c @@ -0,0 +1,149 @@ +/****************************************************************************** + * + * Copyright(c) 2009-2010 Realtek Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger + * + *****************************************************************************/ + +#include "../wifi.h" +#include "../pci.h" +#include "reg.h" +#include "led.h" + +static void _rtl92se_init_led(struct ieee80211_hw *hw, + struct rtl_led *pled, enum rtl_led_pin ledpin) +{ + pled->hw = hw; + pled->ledpin = ledpin; + pled->ledon = false; +} + +void rtl92se_init_sw_leds(struct ieee80211_hw *hw) +{ + struct rtl_pci_priv *pcipriv = rtl_pcipriv(hw); + _rtl92se_init_led(hw, &(pcipriv->ledctl.sw_led0), LED_PIN_LED0); + _rtl92se_init_led(hw, &(pcipriv->ledctl.sw_led1), LED_PIN_LED1); +} + +void rtl92se_sw_led_on(struct ieee80211_hw *hw, struct rtl_led *pled) +{ + u8 ledcfg; + struct rtl_priv *rtlpriv = rtl_priv(hw); + + RT_TRACE(rtlpriv, COMP_LED, DBG_LOUD, + ("LedAddr:%X ledpin=%d\n", LEDCFG, pled->ledpin)); + + ledcfg = rtl_read_byte(rtlpriv, LEDCFG); + + switch (pled->ledpin) { + case LED_PIN_GPIO0: + break; + case LED_PIN_LED0: + rtl_write_byte(rtlpriv, LEDCFG, ledcfg & 0xf0); + break; + case LED_PIN_LED1: + rtl_write_byte(rtlpriv, LEDCFG, ledcfg & 0x0f); + break; + default: + RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, + ("switch case not process\n")); + break; + } + pled->ledon = true; +} + +void rtl92se_sw_led_off(struct ieee80211_hw *hw, struct rtl_led *pled) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_pci_priv *pcipriv = rtl_pcipriv(hw); + u8 ledcfg; + + RT_TRACE(rtlpriv, COMP_LED, DBG_LOUD, + ("LedAddr:%X ledpin=%d\n", LEDCFG, pled->ledpin)); + + ledcfg = rtl_read_byte(rtlpriv, LEDCFG); + + switch (pled->ledpin) { + case LED_PIN_GPIO0: + break; + case LED_PIN_LED0: + ledcfg &= 0xf0; + if (pcipriv->ledctl.led_opendrain == true) + rtl_write_byte(rtlpriv, LEDCFG, (ledcfg | BIT(1))); + else + rtl_write_byte(rtlpriv, LEDCFG, (ledcfg | BIT(3))); + break; + case LED_PIN_LED1: + ledcfg &= 0x0f; + rtl_write_byte(rtlpriv, LEDCFG, (ledcfg | BIT(3))); + break; + default: + RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, + ("switch case not process\n")); + break; + } + pled->ledon = false; +} + +static void _rtl92se_sw_led_control(struct ieee80211_hw *hw, + enum led_ctl_mode ledaction) +{ + struct rtl_pci_priv *pcipriv = rtl_pcipriv(hw); + struct rtl_led *pLed0 = &(pcipriv->ledctl.sw_led0); + switch (ledaction) { + case LED_CTL_POWER_ON: + case LED_CTL_LINK: + case LED_CTL_NO_LINK: + rtl92se_sw_led_on(hw, pLed0); + break; + case LED_CTL_POWER_OFF: + rtl92se_sw_led_off(hw, pLed0); + break; + default: + break; + } +} + +void rtl92se_led_control(struct ieee80211_hw *hw, enum led_ctl_mode ledaction) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); + + if ((ppsc->rfoff_reason > RF_CHANGE_BY_PS) && + (ledaction == LED_CTL_TX || + ledaction == LED_CTL_RX || + ledaction == LED_CTL_SITE_SURVEY || + ledaction == LED_CTL_LINK || + ledaction == LED_CTL_NO_LINK || + ledaction == LED_CTL_START_TO_LINK || + ledaction == LED_CTL_POWER_ON)) { + return; + } + RT_TRACE(rtlpriv, COMP_LED, DBG_LOUD, ("ledaction %d,\n", + ledaction)); + + _rtl92se_sw_led_control(hw, ledaction); +} + diff --git a/drivers/net/wireless/rtlwifi/rtl8192se/led.h b/drivers/net/wireless/rtlwifi/rtl8192se/led.h new file mode 100644 index 0000000..8cce387 --- /dev/null +++ b/drivers/net/wireless/rtlwifi/rtl8192se/led.h @@ -0,0 +1,37 @@ +/****************************************************************************** + * + * Copyright(c) 2009-2010 Realtek Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger + * + *****************************************************************************/ +#ifndef __REALTEK_PCI92SE_LED_H__ +#define __REALTEK_PCI92SE_LED_H__ + +void rtl92se_init_sw_leds(struct ieee80211_hw *hw); +void rtl92se_sw_led_on(struct ieee80211_hw *hw, struct rtl_led *pled); +void rtl92se_sw_led_off(struct ieee80211_hw *hw, struct rtl_led *pled); +void rtl92se_led_control(struct ieee80211_hw *hw, enum led_ctl_mode ledaction); + +#endif -- cgit v0.10.2 From d15853163bea3d31c3b2cc9c74d018a861c128cf Mon Sep 17 00:00:00 2001 From: Chaoming Li Date: Tue, 3 May 2011 09:48:35 -0500 Subject: rtlwifi: rtl8192se: Merge phy routines Merge routines phy.c and phy.h for RTL8192SE. Signed-off-by: Chaoming_Li Signed-off-by: Larry Finger Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/rtlwifi/rtl8192se/phy.c b/drivers/net/wireless/rtlwifi/rtl8192se/phy.c new file mode 100644 index 0000000..63b45e6 --- /dev/null +++ b/drivers/net/wireless/rtlwifi/rtl8192se/phy.c @@ -0,0 +1,1740 @@ +/****************************************************************************** + * + * Copyright(c) 2009-2010 Realtek Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger + * + *****************************************************************************/ + +#include "../wifi.h" +#include "../pci.h" +#include "../ps.h" +#include "reg.h" +#include "def.h" +#include "phy.h" +#include "rf.h" +#include "dm.h" +#include "fw.h" +#include "hw.h" +#include "table.h" + +static u32 _rtl92s_phy_calculate_bit_shift(u32 bitmask) +{ + u32 i; + + for (i = 0; i <= 31; i++) { + if (((bitmask >> i) & 0x1) == 1) + break; + } + + return i; +} + +u32 rtl92s_phy_query_bb_reg(struct ieee80211_hw *hw, u32 regaddr, u32 bitmask) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + u32 returnvalue = 0, originalvalue, bitshift; + + RT_TRACE(rtlpriv, COMP_RF, DBG_TRACE, ("regaddr(%#x), bitmask(%#x)\n", + regaddr, bitmask)); + + originalvalue = rtl_read_dword(rtlpriv, regaddr); + bitshift = _rtl92s_phy_calculate_bit_shift(bitmask); + returnvalue = (originalvalue & bitmask) >> bitshift; + + RT_TRACE(rtlpriv, COMP_RF, DBG_TRACE, + ("BBR MASK=0x%x Addr[0x%x]=0x%x\n", + bitmask, regaddr, originalvalue)); + + return returnvalue; + +} + +void rtl92s_phy_set_bb_reg(struct ieee80211_hw *hw, u32 regaddr, u32 bitmask, + u32 data) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + u32 originalvalue, bitshift; + + RT_TRACE(rtlpriv, COMP_RF, DBG_TRACE, ("regaddr(%#x), bitmask(%#x)," + " data(%#x)\n", regaddr, bitmask, data)); + + if (bitmask != MASKDWORD) { + originalvalue = rtl_read_dword(rtlpriv, regaddr); + bitshift = _rtl92s_phy_calculate_bit_shift(bitmask); + data = ((originalvalue & (~bitmask)) | (data << bitshift)); + } + + rtl_write_dword(rtlpriv, regaddr, data); + + RT_TRACE(rtlpriv, COMP_RF, DBG_TRACE, ("regaddr(%#x), bitmask(%#x)," + " data(%#x)\n", regaddr, bitmask, data)); + +} + +static u32 _rtl92s_phy_rf_serial_read(struct ieee80211_hw *hw, + enum radio_path rfpath, u32 offset) +{ + + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_phy *rtlphy = &(rtlpriv->phy); + struct bb_reg_def *pphyreg = &rtlphy->phyreg_def[rfpath]; + u32 newoffset; + u32 tmplong, tmplong2; + u8 rfpi_enable = 0; + u32 retvalue = 0; + + offset &= 0x3f; + newoffset = offset; + + tmplong = rtl_get_bbreg(hw, RFPGA0_XA_HSSIPARAMETER2, MASKDWORD); + + if (rfpath == RF90_PATH_A) + tmplong2 = tmplong; + else + tmplong2 = rtl_get_bbreg(hw, pphyreg->rfhssi_para2, MASKDWORD); + + tmplong2 = (tmplong2 & (~BLSSI_READADDRESS)) | (newoffset << 23) | + BLSSI_READEDGE; + + rtl_set_bbreg(hw, RFPGA0_XA_HSSIPARAMETER2, MASKDWORD, + tmplong & (~BLSSI_READEDGE)); + + mdelay(1); + + rtl_set_bbreg(hw, pphyreg->rfhssi_para2, MASKDWORD, tmplong2); + mdelay(1); + + rtl_set_bbreg(hw, RFPGA0_XA_HSSIPARAMETER2, MASKDWORD, tmplong | + BLSSI_READEDGE); + mdelay(1); + + if (rfpath == RF90_PATH_A) + rfpi_enable = (u8)rtl_get_bbreg(hw, RFPGA0_XA_HSSIPARAMETER1, + BIT(8)); + else if (rfpath == RF90_PATH_B) + rfpi_enable = (u8)rtl_get_bbreg(hw, RFPGA0_XB_HSSIPARAMETER1, + BIT(8)); + + if (rfpi_enable) + retvalue = rtl_get_bbreg(hw, pphyreg->rflssi_readbackpi, + BLSSI_READBACK_DATA); + else + retvalue = rtl_get_bbreg(hw, pphyreg->rflssi_readback, + BLSSI_READBACK_DATA); + + retvalue = rtl_get_bbreg(hw, pphyreg->rflssi_readback, + BLSSI_READBACK_DATA); + + RT_TRACE(rtlpriv, COMP_RF, DBG_TRACE, ("RFR-%d Addr[0x%x]=0x%x\n", + rfpath, pphyreg->rflssi_readback, retvalue)); + + return retvalue; + +} + +static void _rtl92s_phy_rf_serial_write(struct ieee80211_hw *hw, + enum radio_path rfpath, u32 offset, + u32 data) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_phy *rtlphy = &(rtlpriv->phy); + struct bb_reg_def *pphyreg = &rtlphy->phyreg_def[rfpath]; + u32 data_and_addr = 0; + u32 newoffset; + + offset &= 0x3f; + newoffset = offset; + + data_and_addr = ((newoffset << 20) | (data & 0x000fffff)) & 0x0fffffff; + rtl_set_bbreg(hw, pphyreg->rf3wire_offset, MASKDWORD, data_and_addr); + + RT_TRACE(rtlpriv, COMP_RF, DBG_TRACE, ("RFW-%d Addr[0x%x]=0x%x\n", + rfpath, pphyreg->rf3wire_offset, data_and_addr)); +} + + +u32 rtl92s_phy_query_rf_reg(struct ieee80211_hw *hw, enum radio_path rfpath, + u32 regaddr, u32 bitmask) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + u32 original_value, readback_value, bitshift; + unsigned long flags; + + RT_TRACE(rtlpriv, COMP_RF, DBG_TRACE, ("regaddr(%#x), rfpath(%#x), " + "bitmask(%#x)\n", regaddr, rfpath, bitmask)); + + spin_lock_irqsave(&rtlpriv->locks.rf_lock, flags); + + original_value = _rtl92s_phy_rf_serial_read(hw, rfpath, regaddr); + + bitshift = _rtl92s_phy_calculate_bit_shift(bitmask); + readback_value = (original_value & bitmask) >> bitshift; + + spin_unlock_irqrestore(&rtlpriv->locks.rf_lock, flags); + + RT_TRACE(rtlpriv, COMP_RF, DBG_TRACE, ("regaddr(%#x), rfpath(%#x), " + "bitmask(%#x), original_value(%#x)\n", regaddr, rfpath, + bitmask, original_value)); + + return readback_value; +} + +void rtl92s_phy_set_rf_reg(struct ieee80211_hw *hw, enum radio_path rfpath, + u32 regaddr, u32 bitmask, u32 data) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_phy *rtlphy = &(rtlpriv->phy); + u32 original_value, bitshift; + unsigned long flags; + + if (!((rtlphy->rf_pathmap >> rfpath) & 0x1)) + return; + + RT_TRACE(rtlpriv, COMP_RF, DBG_TRACE, ("regaddr(%#x), bitmask(%#x)," + " data(%#x), rfpath(%#x)\n", regaddr, bitmask, data, rfpath)); + + spin_lock_irqsave(&rtlpriv->locks.rf_lock, flags); + + if (bitmask != RFREG_OFFSET_MASK) { + original_value = _rtl92s_phy_rf_serial_read(hw, rfpath, + regaddr); + bitshift = _rtl92s_phy_calculate_bit_shift(bitmask); + data = ((original_value & (~bitmask)) | (data << bitshift)); + } + + _rtl92s_phy_rf_serial_write(hw, rfpath, regaddr, data); + + spin_unlock_irqrestore(&rtlpriv->locks.rf_lock, flags); + + RT_TRACE(rtlpriv, COMP_RF, DBG_TRACE, ("regaddr(%#x), bitmask(%#x), " + "data(%#x), rfpath(%#x)\n", regaddr, bitmask, data, rfpath)); + +} + +void rtl92s_phy_scan_operation_backup(struct ieee80211_hw *hw, + u8 operation) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); + + if (!is_hal_stop(rtlhal)) { + switch (operation) { + case SCAN_OPT_BACKUP: + rtl92s_phy_set_fw_cmd(hw, FW_CMD_PAUSE_DM_BY_SCAN); + break; + case SCAN_OPT_RESTORE: + rtl92s_phy_set_fw_cmd(hw, FW_CMD_RESUME_DM_BY_SCAN); + break; + default: + RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, + ("Unknown operation.\n")); + break; + } + } +} + +void rtl92s_phy_set_bw_mode(struct ieee80211_hw *hw, + enum nl80211_channel_type ch_type) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); + struct rtl_phy *rtlphy = &(rtlpriv->phy); + struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); + u8 reg_bw_opmode; + u8 reg_prsr_rsc; + + RT_TRACE(rtlpriv, COMP_SCAN, DBG_TRACE, ("Switch to %s bandwidth\n", + rtlphy->current_chan_bw == HT_CHANNEL_WIDTH_20 ? + "20MHz" : "40MHz")); + + if (rtlphy->set_bwmode_inprogress) + return; + if (is_hal_stop(rtlhal)) + return; + + rtlphy->set_bwmode_inprogress = true; + + reg_bw_opmode = rtl_read_byte(rtlpriv, BW_OPMODE); + reg_prsr_rsc = rtl_read_byte(rtlpriv, RRSR + 2); + + switch (rtlphy->current_chan_bw) { + case HT_CHANNEL_WIDTH_20: + reg_bw_opmode |= BW_OPMODE_20MHZ; + rtl_write_byte(rtlpriv, BW_OPMODE, reg_bw_opmode); + break; + case HT_CHANNEL_WIDTH_20_40: + reg_bw_opmode &= ~BW_OPMODE_20MHZ; + rtl_write_byte(rtlpriv, BW_OPMODE, reg_bw_opmode); + break; + default: + RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, + ("unknown bandwidth: %#X\n", + rtlphy->current_chan_bw)); + break; + } + + switch (rtlphy->current_chan_bw) { + case HT_CHANNEL_WIDTH_20: + rtl_set_bbreg(hw, RFPGA0_RFMOD, BRFMOD, 0x0); + rtl_set_bbreg(hw, RFPGA1_RFMOD, BRFMOD, 0x0); + + if (rtlhal->version >= VERSION_8192S_BCUT) + rtl_write_byte(rtlpriv, RFPGA0_ANALOGPARAMETER2, 0x58); + break; + case HT_CHANNEL_WIDTH_20_40: + rtl_set_bbreg(hw, RFPGA0_RFMOD, BRFMOD, 0x1); + rtl_set_bbreg(hw, RFPGA1_RFMOD, BRFMOD, 0x1); + + rtl_set_bbreg(hw, RCCK0_SYSTEM, BCCK_SIDEBAND, + (mac->cur_40_prime_sc >> 1)); + rtl_set_bbreg(hw, ROFDM1_LSTF, 0xC00, mac->cur_40_prime_sc); + + if (rtlhal->version >= VERSION_8192S_BCUT) + rtl_write_byte(rtlpriv, RFPGA0_ANALOGPARAMETER2, 0x18); + break; + default: + RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, + ("unknown bandwidth: %#X\n", rtlphy->current_chan_bw)); + break; + } + + rtl92s_phy_rf6052_set_bandwidth(hw, rtlphy->current_chan_bw); + rtlphy->set_bwmode_inprogress = false; + RT_TRACE(rtlpriv, COMP_SCAN, DBG_TRACE, ("<==\n")); +} + +static bool _rtl92s_phy_set_sw_chnl_cmdarray(struct swchnlcmd *cmdtable, + u32 cmdtableidx, u32 cmdtablesz, enum swchnlcmd_id cmdid, + u32 para1, u32 para2, u32 msdelay) +{ + struct swchnlcmd *pcmd; + + if (cmdtable == NULL) { + RT_ASSERT(false, ("cmdtable cannot be NULL.\n")); + return false; + } + + if (cmdtableidx >= cmdtablesz) + return false; + + pcmd = cmdtable + cmdtableidx; + pcmd->cmdid = cmdid; + pcmd->para1 = para1; + pcmd->para2 = para2; + pcmd->msdelay = msdelay; + + return true; +} + +static bool _rtl92s_phy_sw_chnl_step_by_step(struct ieee80211_hw *hw, + u8 channel, u8 *stage, u8 *step, u32 *delay) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_phy *rtlphy = &(rtlpriv->phy); + struct swchnlcmd precommoncmd[MAX_PRECMD_CNT]; + u32 precommoncmdcnt; + struct swchnlcmd postcommoncmd[MAX_POSTCMD_CNT]; + u32 postcommoncmdcnt; + struct swchnlcmd rfdependcmd[MAX_RFDEPENDCMD_CNT]; + u32 rfdependcmdcnt; + struct swchnlcmd *currentcmd = NULL; + u8 rfpath; + u8 num_total_rfpath = rtlphy->num_total_rfpath; + + precommoncmdcnt = 0; + _rtl92s_phy_set_sw_chnl_cmdarray(precommoncmd, precommoncmdcnt++, + MAX_PRECMD_CNT, CMDID_SET_TXPOWEROWER_LEVEL, 0, 0, 0); + _rtl92s_phy_set_sw_chnl_cmdarray(precommoncmd, precommoncmdcnt++, + MAX_PRECMD_CNT, CMDID_END, 0, 0, 0); + + postcommoncmdcnt = 0; + + _rtl92s_phy_set_sw_chnl_cmdarray(postcommoncmd, postcommoncmdcnt++, + MAX_POSTCMD_CNT, CMDID_END, 0, 0, 0); + + rfdependcmdcnt = 0; + + RT_ASSERT((channel >= 1 && channel <= 14), + ("illegal channel for Zebra: %d\n", channel)); + + _rtl92s_phy_set_sw_chnl_cmdarray(rfdependcmd, rfdependcmdcnt++, + MAX_RFDEPENDCMD_CNT, CMDID_RF_WRITEREG, + RF_CHNLBW, channel, 10); + + _rtl92s_phy_set_sw_chnl_cmdarray(rfdependcmd, rfdependcmdcnt++, + MAX_RFDEPENDCMD_CNT, CMDID_END, 0, 0, 0); + + do { + switch (*stage) { + case 0: + currentcmd = &precommoncmd[*step]; + break; + case 1: + currentcmd = &rfdependcmd[*step]; + break; + case 2: + currentcmd = &postcommoncmd[*step]; + break; + } + + if (currentcmd->cmdid == CMDID_END) { + if ((*stage) == 2) { + return true; + } else { + (*stage)++; + (*step) = 0; + continue; + } + } + + switch (currentcmd->cmdid) { + case CMDID_SET_TXPOWEROWER_LEVEL: + rtl92s_phy_set_txpower(hw, channel); + break; + case CMDID_WRITEPORT_ULONG: + rtl_write_dword(rtlpriv, currentcmd->para1, + currentcmd->para2); + break; + case CMDID_WRITEPORT_USHORT: + rtl_write_word(rtlpriv, currentcmd->para1, + (u16)currentcmd->para2); + break; + case CMDID_WRITEPORT_UCHAR: + rtl_write_byte(rtlpriv, currentcmd->para1, + (u8)currentcmd->para2); + break; + case CMDID_RF_WRITEREG: + for (rfpath = 0; rfpath < num_total_rfpath; rfpath++) { + rtlphy->rfreg_chnlval[rfpath] = + ((rtlphy->rfreg_chnlval[rfpath] & + 0xfffffc00) | currentcmd->para2); + rtl_set_rfreg(hw, (enum radio_path)rfpath, + currentcmd->para1, + RFREG_OFFSET_MASK, + rtlphy->rfreg_chnlval[rfpath]); + } + break; + default: + RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, + ("switch case not process\n")); + break; + } + + break; + } while (true); + + (*delay) = currentcmd->msdelay; + (*step)++; + return false; +} + +u8 rtl92s_phy_sw_chnl(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); + struct rtl_phy *rtlphy = &(rtlpriv->phy); + u32 delay; + bool ret; + + RT_TRACE(rtlpriv, COMP_SCAN, DBG_TRACE, + ("switch to channel%d\n", + rtlphy->current_channel)); + + if (rtlphy->sw_chnl_inprogress) + return 0; + + if (rtlphy->set_bwmode_inprogress) + return 0; + + if (is_hal_stop(rtlhal)) + return 0; + + rtlphy->sw_chnl_inprogress = true; + rtlphy->sw_chnl_stage = 0; + rtlphy->sw_chnl_step = 0; + + do { + if (!rtlphy->sw_chnl_inprogress) + break; + + ret = _rtl92s_phy_sw_chnl_step_by_step(hw, + rtlphy->current_channel, + &rtlphy->sw_chnl_stage, + &rtlphy->sw_chnl_step, &delay); + if (!ret) { + if (delay > 0) + mdelay(delay); + else + continue; + } else { + rtlphy->sw_chnl_inprogress = false; + } + break; + } while (true); + + rtlphy->sw_chnl_inprogress = false; + + RT_TRACE(rtlpriv, COMP_SCAN, DBG_TRACE, ("<==\n")); + + return 1; +} + +static void _rtl92se_phy_set_rf_sleep(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + u8 u1btmp; + + u1btmp = rtl_read_byte(rtlpriv, LDOV12D_CTRL); + u1btmp |= BIT(0); + + rtl_write_byte(rtlpriv, LDOV12D_CTRL, u1btmp); + rtl_write_byte(rtlpriv, SPS1_CTRL, 0x0); + rtl_write_byte(rtlpriv, TXPAUSE, 0xFF); + rtl_write_word(rtlpriv, CMDR, 0x57FC); + udelay(100); + + rtl_write_word(rtlpriv, CMDR, 0x77FC); + rtl_write_byte(rtlpriv, PHY_CCA, 0x0); + udelay(10); + + rtl_write_word(rtlpriv, CMDR, 0x37FC); + udelay(10); + + rtl_write_word(rtlpriv, CMDR, 0x77FC); + udelay(10); + + rtl_write_word(rtlpriv, CMDR, 0x57FC); + + /* we should chnge GPIO to input mode + * this will drop away current about 25mA*/ + rtl8192se_gpiobit3_cfg_inputmode(hw); +} + +bool rtl92s_phy_set_rf_power_state(struct ieee80211_hw *hw, + enum rf_pwrstate rfpwr_state) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_pci_priv *pcipriv = rtl_pcipriv(hw); + struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); + struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); + bool bresult = true; + u8 i, queue_id; + struct rtl8192_tx_ring *ring = NULL; + + if (rfpwr_state == ppsc->rfpwr_state) + return false; + + ppsc->set_rfpowerstate_inprogress = true; + + switch (rfpwr_state) { + case ERFON:{ + if ((ppsc->rfpwr_state == ERFOFF) && + RT_IN_PS_LEVEL(ppsc, RT_RF_OFF_LEVL_HALT_NIC)) { + + bool rtstatus; + u32 InitializeCount = 0; + do { + InitializeCount++; + RT_TRACE(rtlpriv, COMP_RF, DBG_DMESG, + ("IPS Set eRf nic enable\n")); + rtstatus = rtl_ps_enable_nic(hw); + } while ((rtstatus != true) && + (InitializeCount < 10)); + + RT_CLEAR_PS_LEVEL(ppsc, + RT_RF_OFF_LEVL_HALT_NIC); + } else { + RT_TRACE(rtlpriv, COMP_POWER, DBG_DMESG, + ("awake, sleeped:%d ms " + "state_inap:%x\n", + jiffies_to_msecs(jiffies - + ppsc->last_sleep_jiffies), + rtlpriv->psc.state_inap)); + ppsc->last_awake_jiffies = jiffies; + rtl_write_word(rtlpriv, CMDR, 0x37FC); + rtl_write_byte(rtlpriv, TXPAUSE, 0x00); + rtl_write_byte(rtlpriv, PHY_CCA, 0x3); + } + + if (mac->link_state == MAC80211_LINKED) + rtlpriv->cfg->ops->led_control(hw, + LED_CTL_LINK); + else + rtlpriv->cfg->ops->led_control(hw, + LED_CTL_NO_LINK); + break; + } + case ERFOFF:{ + if (ppsc->reg_rfps_level & RT_RF_OFF_LEVL_HALT_NIC) { + RT_TRACE(rtlpriv, COMP_RF, DBG_DMESG, + ("IPS Set eRf nic disable\n")); + rtl_ps_disable_nic(hw); + RT_SET_PS_LEVEL(ppsc, RT_RF_OFF_LEVL_HALT_NIC); + } else { + if (ppsc->rfoff_reason == RF_CHANGE_BY_IPS) + rtlpriv->cfg->ops->led_control(hw, + LED_CTL_NO_LINK); + else + rtlpriv->cfg->ops->led_control(hw, + LED_CTL_POWER_OFF); + } + break; + } + case ERFSLEEP: + if (ppsc->rfpwr_state == ERFOFF) + break; + + for (queue_id = 0, i = 0; + queue_id < RTL_PCI_MAX_TX_QUEUE_COUNT;) { + ring = &pcipriv->dev.tx_ring[queue_id]; + if (skb_queue_len(&ring->queue) == 0 || + queue_id == BEACON_QUEUE) { + queue_id++; + continue; + } else { + RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING, + ("eRf Off/Sleep: " + "%d times TcbBusyQueue[%d] = " + "%d before doze!\n", + (i + 1), queue_id, + skb_queue_len(&ring->queue))); + + udelay(10); + i++; + } + + if (i >= MAX_DOZE_WAITING_TIMES_9x) { + RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING, + ("\nERFOFF: %d times" + "TcbBusyQueue[%d] = %d !\n", + MAX_DOZE_WAITING_TIMES_9x, + queue_id, + skb_queue_len(&ring->queue))); + break; + } + } + + RT_TRACE(rtlpriv, COMP_POWER, DBG_DMESG, + ("Set ERFSLEEP awaked:%d ms\n", + jiffies_to_msecs(jiffies - + ppsc->last_awake_jiffies))); + + RT_TRACE(rtlpriv, COMP_POWER, DBG_DMESG, + ("sleep awaked:%d ms " + "state_inap:%x\n", jiffies_to_msecs(jiffies - + ppsc->last_awake_jiffies), + rtlpriv->psc.state_inap)); + ppsc->last_sleep_jiffies = jiffies; + _rtl92se_phy_set_rf_sleep(hw); + break; + default: + RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, + ("switch case not process\n")); + bresult = false; + break; + } + + if (bresult) + ppsc->rfpwr_state = rfpwr_state; + + ppsc->set_rfpowerstate_inprogress = false; + + return bresult; +} + +static bool _rtl92s_phy_config_rfpa_bias_current(struct ieee80211_hw *hw, + enum radio_path rfpath) +{ + struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); + bool rtstatus = true; + u32 tmpval = 0; + + /* If inferiority IC, we have to increase the PA bias current */ + if (rtlhal->ic_class != IC_INFERIORITY_A) { + tmpval = rtl92s_phy_query_rf_reg(hw, rfpath, RF_IPA, 0xf); + rtl92s_phy_set_rf_reg(hw, rfpath, RF_IPA, 0xf, tmpval + 1); + } + + return rtstatus; +} + +static void _rtl92s_store_pwrindex_diffrate_offset(struct ieee80211_hw *hw, + u32 reg_addr, u32 bitmask, u32 data) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_phy *rtlphy = &(rtlpriv->phy); + + if (reg_addr == RTXAGC_RATE18_06) + rtlphy->mcs_txpwrlevel_origoffset[rtlphy->pwrgroup_cnt][0] = + data; + if (reg_addr == RTXAGC_RATE54_24) + rtlphy->mcs_txpwrlevel_origoffset[rtlphy->pwrgroup_cnt][1] = + data; + if (reg_addr == RTXAGC_CCK_MCS32) + rtlphy->mcs_txpwrlevel_origoffset[rtlphy->pwrgroup_cnt][6] = + data; + if (reg_addr == RTXAGC_MCS03_MCS00) + rtlphy->mcs_txpwrlevel_origoffset[rtlphy->pwrgroup_cnt][2] = + data; + if (reg_addr == RTXAGC_MCS07_MCS04) + rtlphy->mcs_txpwrlevel_origoffset[rtlphy->pwrgroup_cnt][3] = + data; + if (reg_addr == RTXAGC_MCS11_MCS08) + rtlphy->mcs_txpwrlevel_origoffset[rtlphy->pwrgroup_cnt][4] = + data; + if (reg_addr == RTXAGC_MCS15_MCS12) { + rtlphy->mcs_txpwrlevel_origoffset[rtlphy->pwrgroup_cnt][5] = + data; + rtlphy->pwrgroup_cnt++; + } +} + +static void _rtl92s_phy_init_register_definition(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_phy *rtlphy = &(rtlpriv->phy); + + /*RF Interface Sowrtware Control */ + rtlphy->phyreg_def[RF90_PATH_A].rfintfs = RFPGA0_XAB_RFINTERFACESW; + rtlphy->phyreg_def[RF90_PATH_B].rfintfs = RFPGA0_XAB_RFINTERFACESW; + rtlphy->phyreg_def[RF90_PATH_C].rfintfs = RFPGA0_XCD_RFINTERFACESW; + rtlphy->phyreg_def[RF90_PATH_D].rfintfs = RFPGA0_XCD_RFINTERFACESW; + + /* RF Interface Readback Value */ + rtlphy->phyreg_def[RF90_PATH_A].rfintfi = RFPGA0_XAB_RFINTERFACERB; + rtlphy->phyreg_def[RF90_PATH_B].rfintfi = RFPGA0_XAB_RFINTERFACERB; + rtlphy->phyreg_def[RF90_PATH_C].rfintfi = RFPGA0_XCD_RFINTERFACERB; + rtlphy->phyreg_def[RF90_PATH_D].rfintfi = RFPGA0_XCD_RFINTERFACERB; + + /* RF Interface Output (and Enable) */ + rtlphy->phyreg_def[RF90_PATH_A].rfintfo = RFPGA0_XA_RFINTERFACEOE; + rtlphy->phyreg_def[RF90_PATH_B].rfintfo = RFPGA0_XB_RFINTERFACEOE; + rtlphy->phyreg_def[RF90_PATH_C].rfintfo = RFPGA0_XC_RFINTERFACEOE; + rtlphy->phyreg_def[RF90_PATH_D].rfintfo = RFPGA0_XD_RFINTERFACEOE; + + /* RF Interface (Output and) Enable */ + rtlphy->phyreg_def[RF90_PATH_A].rfintfe = RFPGA0_XA_RFINTERFACEOE; + rtlphy->phyreg_def[RF90_PATH_B].rfintfe = RFPGA0_XB_RFINTERFACEOE; + rtlphy->phyreg_def[RF90_PATH_C].rfintfe = RFPGA0_XC_RFINTERFACEOE; + rtlphy->phyreg_def[RF90_PATH_D].rfintfe = RFPGA0_XD_RFINTERFACEOE; + + /* Addr of LSSI. Wirte RF register by driver */ + rtlphy->phyreg_def[RF90_PATH_A].rf3wire_offset = + RFPGA0_XA_LSSIPARAMETER; + rtlphy->phyreg_def[RF90_PATH_B].rf3wire_offset = + RFPGA0_XB_LSSIPARAMETER; + rtlphy->phyreg_def[RF90_PATH_C].rf3wire_offset = + RFPGA0_XC_LSSIPARAMETER; + rtlphy->phyreg_def[RF90_PATH_D].rf3wire_offset = + RFPGA0_XD_LSSIPARAMETER; + + /* RF parameter */ + rtlphy->phyreg_def[RF90_PATH_A].rflssi_select = RFPGA0_XAB_RFPARAMETER; + rtlphy->phyreg_def[RF90_PATH_B].rflssi_select = RFPGA0_XAB_RFPARAMETER; + rtlphy->phyreg_def[RF90_PATH_C].rflssi_select = RFPGA0_XCD_RFPARAMETER; + rtlphy->phyreg_def[RF90_PATH_D].rflssi_select = RFPGA0_XCD_RFPARAMETER; + + /* Tx AGC Gain Stage (same for all path. Should we remove this?) */ + rtlphy->phyreg_def[RF90_PATH_A].rftxgain_stage = RFPGA0_TXGAINSTAGE; + rtlphy->phyreg_def[RF90_PATH_B].rftxgain_stage = RFPGA0_TXGAINSTAGE; + rtlphy->phyreg_def[RF90_PATH_C].rftxgain_stage = RFPGA0_TXGAINSTAGE; + rtlphy->phyreg_def[RF90_PATH_D].rftxgain_stage = RFPGA0_TXGAINSTAGE; + + /* Tranceiver A~D HSSI Parameter-1 */ + rtlphy->phyreg_def[RF90_PATH_A].rfhssi_para1 = RFPGA0_XA_HSSIPARAMETER1; + rtlphy->phyreg_def[RF90_PATH_B].rfhssi_para1 = RFPGA0_XB_HSSIPARAMETER1; + rtlphy->phyreg_def[RF90_PATH_C].rfhssi_para1 = RFPGA0_XC_HSSIPARAMETER1; + rtlphy->phyreg_def[RF90_PATH_D].rfhssi_para1 = RFPGA0_XD_HSSIPARAMETER1; + + /* Tranceiver A~D HSSI Parameter-2 */ + rtlphy->phyreg_def[RF90_PATH_A].rfhssi_para2 = RFPGA0_XA_HSSIPARAMETER2; + rtlphy->phyreg_def[RF90_PATH_B].rfhssi_para2 = RFPGA0_XB_HSSIPARAMETER2; + rtlphy->phyreg_def[RF90_PATH_C].rfhssi_para2 = RFPGA0_XC_HSSIPARAMETER2; + rtlphy->phyreg_def[RF90_PATH_D].rfhssi_para2 = RFPGA0_XD_HSSIPARAMETER2; + + /* RF switch Control */ + rtlphy->phyreg_def[RF90_PATH_A].rfswitch_control = + RFPGA0_XAB_SWITCHCONTROL; + rtlphy->phyreg_def[RF90_PATH_B].rfswitch_control = + RFPGA0_XAB_SWITCHCONTROL; + rtlphy->phyreg_def[RF90_PATH_C].rfswitch_control = + RFPGA0_XCD_SWITCHCONTROL; + rtlphy->phyreg_def[RF90_PATH_D].rfswitch_control = + RFPGA0_XCD_SWITCHCONTROL; + + /* AGC control 1 */ + rtlphy->phyreg_def[RF90_PATH_A].rfagc_control1 = ROFDM0_XAAGCCORE1; + rtlphy->phyreg_def[RF90_PATH_B].rfagc_control1 = ROFDM0_XBAGCCORE1; + rtlphy->phyreg_def[RF90_PATH_C].rfagc_control1 = ROFDM0_XCAGCCORE1; + rtlphy->phyreg_def[RF90_PATH_D].rfagc_control1 = ROFDM0_XDAGCCORE1; + + /* AGC control 2 */ + rtlphy->phyreg_def[RF90_PATH_A].rfagc_control2 = ROFDM0_XAAGCCORE2; + rtlphy->phyreg_def[RF90_PATH_B].rfagc_control2 = ROFDM0_XBAGCCORE2; + rtlphy->phyreg_def[RF90_PATH_C].rfagc_control2 = ROFDM0_XCAGCCORE2; + rtlphy->phyreg_def[RF90_PATH_D].rfagc_control2 = ROFDM0_XDAGCCORE2; + + /* RX AFE control 1 */ + rtlphy->phyreg_def[RF90_PATH_A].rfrxiq_imbalance = + ROFDM0_XARXIQIMBALANCE; + rtlphy->phyreg_def[RF90_PATH_B].rfrxiq_imbalance = + ROFDM0_XBRXIQIMBALANCE; + rtlphy->phyreg_def[RF90_PATH_C].rfrxiq_imbalance = + ROFDM0_XCRXIQIMBALANCE; + rtlphy->phyreg_def[RF90_PATH_D].rfrxiq_imbalance = + ROFDM0_XDRXIQIMBALANCE; + + /* RX AFE control 1 */ + rtlphy->phyreg_def[RF90_PATH_A].rfrx_afe = ROFDM0_XARXAFE; + rtlphy->phyreg_def[RF90_PATH_B].rfrx_afe = ROFDM0_XBRXAFE; + rtlphy->phyreg_def[RF90_PATH_C].rfrx_afe = ROFDM0_XCRXAFE; + rtlphy->phyreg_def[RF90_PATH_D].rfrx_afe = ROFDM0_XDRXAFE; + + /* Tx AFE control 1 */ + rtlphy->phyreg_def[RF90_PATH_A].rftxiq_imbalance = + ROFDM0_XATXIQIMBALANCE; + rtlphy->phyreg_def[RF90_PATH_B].rftxiq_imbalance = + ROFDM0_XBTXIQIMBALANCE; + rtlphy->phyreg_def[RF90_PATH_C].rftxiq_imbalance = + ROFDM0_XCTXIQIMBALANCE; + rtlphy->phyreg_def[RF90_PATH_D].rftxiq_imbalance = + ROFDM0_XDTXIQIMBALANCE; + + /* Tx AFE control 2 */ + rtlphy->phyreg_def[RF90_PATH_A].rftx_afe = ROFDM0_XATXAFE; + rtlphy->phyreg_def[RF90_PATH_B].rftx_afe = ROFDM0_XBTXAFE; + rtlphy->phyreg_def[RF90_PATH_C].rftx_afe = ROFDM0_XCTXAFE; + rtlphy->phyreg_def[RF90_PATH_D].rftx_afe = ROFDM0_XDTXAFE; + + /* Tranceiver LSSI Readback */ + rtlphy->phyreg_def[RF90_PATH_A].rflssi_readback = + RFPGA0_XA_LSSIREADBACK; + rtlphy->phyreg_def[RF90_PATH_B].rflssi_readback = + RFPGA0_XB_LSSIREADBACK; + rtlphy->phyreg_def[RF90_PATH_C].rflssi_readback = + RFPGA0_XC_LSSIREADBACK; + rtlphy->phyreg_def[RF90_PATH_D].rflssi_readback = + RFPGA0_XD_LSSIREADBACK; + + /* Tranceiver LSSI Readback PI mode */ + rtlphy->phyreg_def[RF90_PATH_A].rflssi_readbackpi = + TRANSCEIVERA_HSPI_READBACK; + rtlphy->phyreg_def[RF90_PATH_B].rflssi_readbackpi = + TRANSCEIVERB_HSPI_READBACK; +} + + +static bool _rtl92s_phy_config_bb(struct ieee80211_hw *hw, u8 configtype) +{ + int i; + u32 *phy_reg_table; + u32 *agc_table; + u16 phy_reg_len, agc_len; + + agc_len = AGCTAB_ARRAYLENGTH; + agc_table = rtl8192seagctab_array; + /* Default RF_type: 2T2R */ + phy_reg_len = PHY_REG_2T2RARRAYLENGTH; + phy_reg_table = rtl8192sephy_reg_2t2rarray; + + if (configtype == BASEBAND_CONFIG_PHY_REG) { + for (i = 0; i < phy_reg_len; i = i + 2) { + if (phy_reg_table[i] == 0xfe) + mdelay(50); + else if (phy_reg_table[i] == 0xfd) + mdelay(5); + else if (phy_reg_table[i] == 0xfc) + mdelay(1); + else if (phy_reg_table[i] == 0xfb) + udelay(50); + else if (phy_reg_table[i] == 0xfa) + udelay(5); + else if (phy_reg_table[i] == 0xf9) + udelay(1); + + /* Add delay for ECS T20 & LG malow platform, */ + udelay(1); + + rtl92s_phy_set_bb_reg(hw, phy_reg_table[i], MASKDWORD, + phy_reg_table[i + 1]); + } + } else if (configtype == BASEBAND_CONFIG_AGC_TAB) { + for (i = 0; i < agc_len; i = i + 2) { + rtl92s_phy_set_bb_reg(hw, agc_table[i], MASKDWORD, + agc_table[i + 1]); + + /* Add delay for ECS T20 & LG malow platform */ + udelay(1); + } + } + + return true; +} + +static bool _rtl92s_phy_set_bb_to_diff_rf(struct ieee80211_hw *hw, + u8 configtype) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_phy *rtlphy = &(rtlpriv->phy); + u32 *phy_regarray2xtxr_table; + u16 phy_regarray2xtxr_len; + int i; + + if (rtlphy->rf_type == RF_1T1R) { + phy_regarray2xtxr_table = rtl8192sephy_changeto_1t1rarray; + phy_regarray2xtxr_len = PHY_CHANGETO_1T1RARRAYLENGTH; + } else if (rtlphy->rf_type == RF_1T2R) { + phy_regarray2xtxr_table = rtl8192sephy_changeto_1t2rarray; + phy_regarray2xtxr_len = PHY_CHANGETO_1T2RARRAYLENGTH; + } else { + return false; + } + + if (configtype == BASEBAND_CONFIG_PHY_REG) { + for (i = 0; i < phy_regarray2xtxr_len; i = i + 3) { + if (phy_regarray2xtxr_table[i] == 0xfe) + mdelay(50); + else if (phy_regarray2xtxr_table[i] == 0xfd) + mdelay(5); + else if (phy_regarray2xtxr_table[i] == 0xfc) + mdelay(1); + else if (phy_regarray2xtxr_table[i] == 0xfb) + udelay(50); + else if (phy_regarray2xtxr_table[i] == 0xfa) + udelay(5); + else if (phy_regarray2xtxr_table[i] == 0xf9) + udelay(1); + + rtl92s_phy_set_bb_reg(hw, phy_regarray2xtxr_table[i], + phy_regarray2xtxr_table[i + 1], + phy_regarray2xtxr_table[i + 2]); + } + } + + return true; +} + +static bool _rtl92s_phy_config_bb_with_pg(struct ieee80211_hw *hw, + u8 configtype) +{ + int i; + u32 *phy_table_pg; + u16 phy_pg_len; + + phy_pg_len = PHY_REG_ARRAY_PGLENGTH; + phy_table_pg = rtl8192sephy_reg_array_pg; + + if (configtype == BASEBAND_CONFIG_PHY_REG) { + for (i = 0; i < phy_pg_len; i = i + 3) { + if (phy_table_pg[i] == 0xfe) + mdelay(50); + else if (phy_table_pg[i] == 0xfd) + mdelay(5); + else if (phy_table_pg[i] == 0xfc) + mdelay(1); + else if (phy_table_pg[i] == 0xfb) + udelay(50); + else if (phy_table_pg[i] == 0xfa) + udelay(5); + else if (phy_table_pg[i] == 0xf9) + udelay(1); + + _rtl92s_store_pwrindex_diffrate_offset(hw, + phy_table_pg[i], + phy_table_pg[i + 1], + phy_table_pg[i + 2]); + rtl92s_phy_set_bb_reg(hw, phy_table_pg[i], + phy_table_pg[i + 1], + phy_table_pg[i + 2]); + } + } + + return true; +} + +static bool _rtl92s_phy_bb_config_parafile(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_phy *rtlphy = &(rtlpriv->phy); + struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw)); + bool rtstatus = true; + + /* 1. Read PHY_REG.TXT BB INIT!! */ + /* We will separate as 1T1R/1T2R/1T2R_GREEN/2T2R */ + if (rtlphy->rf_type == RF_1T2R || rtlphy->rf_type == RF_2T2R || + rtlphy->rf_type == RF_1T1R || rtlphy->rf_type == RF_2T2R_GREEN) { + rtstatus = _rtl92s_phy_config_bb(hw, BASEBAND_CONFIG_PHY_REG); + + if (rtlphy->rf_type != RF_2T2R && + rtlphy->rf_type != RF_2T2R_GREEN) + /* so we should reconfig BB reg with the right + * PHY parameters. */ + rtstatus = _rtl92s_phy_set_bb_to_diff_rf(hw, + BASEBAND_CONFIG_PHY_REG); + } else { + rtstatus = false; + } + + if (rtstatus != true) { + RT_TRACE(rtlpriv, COMP_INIT, DBG_EMERG, + ("Write BB Reg Fail!!")); + goto phy_BB8190_Config_ParaFile_Fail; + } + + /* 2. If EEPROM or EFUSE autoload OK, We must config by + * PHY_REG_PG.txt */ + if (rtlefuse->autoload_failflag == false) { + rtlphy->pwrgroup_cnt = 0; + + rtstatus = _rtl92s_phy_config_bb_with_pg(hw, + BASEBAND_CONFIG_PHY_REG); + } + if (rtstatus != true) { + RT_TRACE(rtlpriv, COMP_INIT, DBG_EMERG, + ("_rtl92s_phy_bb_config_parafile(): " + "BB_PG Reg Fail!!")); + goto phy_BB8190_Config_ParaFile_Fail; + } + + /* 3. BB AGC table Initialization */ + rtstatus = _rtl92s_phy_config_bb(hw, BASEBAND_CONFIG_AGC_TAB); + + if (rtstatus != true) { + printk(KERN_ERR "_rtl92s_phy_bb_config_parafile(): " + "AGC Table Fail\n"); + goto phy_BB8190_Config_ParaFile_Fail; + } + + /* Check if the CCK HighPower is turned ON. */ + /* This is used to calculate PWDB. */ + rtlphy->cck_high_power = (bool)(rtl92s_phy_query_bb_reg(hw, + RFPGA0_XA_HSSIPARAMETER2, 0x200)); + +phy_BB8190_Config_ParaFile_Fail: + return rtstatus; +} + +u8 rtl92s_phy_config_rf(struct ieee80211_hw *hw, enum radio_path rfpath) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_phy *rtlphy = &(rtlpriv->phy); + int i; + bool rtstatus = true; + u32 *radio_a_table; + u32 *radio_b_table; + u16 radio_a_tblen, radio_b_tblen; + + radio_a_tblen = RADIOA_1T_ARRAYLENGTH; + radio_a_table = rtl8192seradioa_1t_array; + + /* Using Green mode array table for RF_2T2R_GREEN */ + if (rtlphy->rf_type == RF_2T2R_GREEN) { + radio_b_table = rtl8192seradiob_gm_array; + radio_b_tblen = RADIOB_GM_ARRAYLENGTH; + } else { + radio_b_table = rtl8192seradiob_array; + radio_b_tblen = RADIOB_ARRAYLENGTH; + } + + RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, ("Radio No %x\n", rfpath)); + rtstatus = true; + + switch (rfpath) { + case RF90_PATH_A: + for (i = 0; i < radio_a_tblen; i = i + 2) { + if (radio_a_table[i] == 0xfe) + /* Delay specific ms. Only RF configuration + * requires delay. */ + mdelay(50); + else if (radio_a_table[i] == 0xfd) + mdelay(5); + else if (radio_a_table[i] == 0xfc) + mdelay(1); + else if (radio_a_table[i] == 0xfb) + udelay(50); + else if (radio_a_table[i] == 0xfa) + udelay(5); + else if (radio_a_table[i] == 0xf9) + udelay(1); + else + rtl92s_phy_set_rf_reg(hw, rfpath, + radio_a_table[i], + MASK20BITS, + radio_a_table[i + 1]); + + /* Add delay for ECS T20 & LG malow platform */ + udelay(1); + } + + /* PA Bias current for inferiority IC */ + _rtl92s_phy_config_rfpa_bias_current(hw, rfpath); + break; + case RF90_PATH_B: + for (i = 0; i < radio_b_tblen; i = i + 2) { + if (radio_b_table[i] == 0xfe) + /* Delay specific ms. Only RF configuration + * requires delay.*/ + mdelay(50); + else if (radio_b_table[i] == 0xfd) + mdelay(5); + else if (radio_b_table[i] == 0xfc) + mdelay(1); + else if (radio_b_table[i] == 0xfb) + udelay(50); + else if (radio_b_table[i] == 0xfa) + udelay(5); + else if (radio_b_table[i] == 0xf9) + udelay(1); + else + rtl92s_phy_set_rf_reg(hw, rfpath, + radio_b_table[i], + MASK20BITS, + radio_b_table[i + 1]); + + /* Add delay for ECS T20 & LG malow platform */ + udelay(1); + } + break; + case RF90_PATH_C: + ; + break; + case RF90_PATH_D: + ; + break; + default: + break; + } + + return rtstatus; +} + + +bool rtl92s_phy_mac_config(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + u32 i; + u32 arraylength; + u32 *ptraArray; + + arraylength = MAC_2T_ARRAYLENGTH; + ptraArray = rtl8192semac_2t_array; + + for (i = 0; i < arraylength; i = i + 2) + rtl_write_byte(rtlpriv, ptraArray[i], (u8)ptraArray[i + 1]); + + return true; +} + + +bool rtl92s_phy_bb_config(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_phy *rtlphy = &(rtlpriv->phy); + bool rtstatus = true; + u8 pathmap, index, rf_num = 0; + u8 path1, path2; + + _rtl92s_phy_init_register_definition(hw); + + /* Config BB and AGC */ + rtstatus = _rtl92s_phy_bb_config_parafile(hw); + + + /* Check BB/RF confiuration setting. */ + /* We only need to configure RF which is turned on. */ + path1 = (u8)(rtl92s_phy_query_bb_reg(hw, RFPGA0_TXINFO, 0xf)); + mdelay(10); + path2 = (u8)(rtl92s_phy_query_bb_reg(hw, ROFDM0_TRXPATHENABLE, 0xf)); + pathmap = path1 | path2; + + rtlphy->rf_pathmap = pathmap; + for (index = 0; index < 4; index++) { + if ((pathmap >> index) & 0x1) + rf_num++; + } + + if ((rtlphy->rf_type == RF_1T1R && rf_num != 1) || + (rtlphy->rf_type == RF_1T2R && rf_num != 2) || + (rtlphy->rf_type == RF_2T2R && rf_num != 2) || + (rtlphy->rf_type == RF_2T2R_GREEN && rf_num != 2)) { + RT_TRACE(rtlpriv, COMP_INIT, DBG_EMERG, + ("RF_Type(%x) does not match " + "RF_Num(%x)!!\n", rtlphy->rf_type, rf_num)); + RT_TRACE(rtlpriv, COMP_INIT, DBG_EMERG, + ("path1 0x%x, path2 0x%x, pathmap " + "0x%x\n", path1, path2, pathmap)); + } + + return rtstatus; +} + +bool rtl92s_phy_rf_config(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_phy *rtlphy = &(rtlpriv->phy); + + /* Initialize general global value */ + if (rtlphy->rf_type == RF_1T1R) + rtlphy->num_total_rfpath = 1; + else + rtlphy->num_total_rfpath = 2; + + /* Config BB and RF */ + return rtl92s_phy_rf6052_config(hw); +} + +void rtl92s_phy_get_hw_reg_originalvalue(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_phy *rtlphy = &(rtlpriv->phy); + + /* read rx initial gain */ + rtlphy->default_initialgain[0] = rtl_get_bbreg(hw, + ROFDM0_XAAGCCORE1, MASKBYTE0); + rtlphy->default_initialgain[1] = rtl_get_bbreg(hw, + ROFDM0_XBAGCCORE1, MASKBYTE0); + rtlphy->default_initialgain[2] = rtl_get_bbreg(hw, + ROFDM0_XCAGCCORE1, MASKBYTE0); + rtlphy->default_initialgain[3] = rtl_get_bbreg(hw, + ROFDM0_XDAGCCORE1, MASKBYTE0); + RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, ("Default initial gain " + "(c50=0x%x, c58=0x%x, c60=0x%x, c68=0x%x)\n", + rtlphy->default_initialgain[0], + rtlphy->default_initialgain[1], + rtlphy->default_initialgain[2], + rtlphy->default_initialgain[3])); + + /* read framesync */ + rtlphy->framesync = rtl_get_bbreg(hw, ROFDM0_RXDETECTOR3, MASKBYTE0); + rtlphy->framesync_c34 = rtl_get_bbreg(hw, ROFDM0_RXDETECTOR2, + MASKDWORD); + RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, + ("Default framesync (0x%x) = 0x%x\n", + ROFDM0_RXDETECTOR3, rtlphy->framesync)); + +} + +static void _rtl92s_phy_get_txpower_index(struct ieee80211_hw *hw, u8 channel, + u8 *cckpowerlevel, u8 *ofdmpowerLevel) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_phy *rtlphy = &(rtlpriv->phy); + struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw)); + u8 index = (channel - 1); + + /* 1. CCK */ + /* RF-A */ + cckpowerlevel[0] = rtlefuse->txpwrlevel_cck[0][index]; + /* RF-B */ + cckpowerlevel[1] = rtlefuse->txpwrlevel_cck[1][index]; + + /* 2. OFDM for 1T or 2T */ + if (rtlphy->rf_type == RF_1T2R || rtlphy->rf_type == RF_1T1R) { + /* Read HT 40 OFDM TX power */ + ofdmpowerLevel[0] = rtlefuse->txpwrlevel_ht40_1s[0][index]; + ofdmpowerLevel[1] = rtlefuse->txpwrlevel_ht40_1s[1][index]; + } else if (rtlphy->rf_type == RF_2T2R) { + /* Read HT 40 OFDM TX power */ + ofdmpowerLevel[0] = rtlefuse->txpwrlevel_ht40_2s[0][index]; + ofdmpowerLevel[1] = rtlefuse->txpwrlevel_ht40_2s[1][index]; + } +} + +static void _rtl92s_phy_ccxpower_indexcheck(struct ieee80211_hw *hw, + u8 channel, u8 *cckpowerlevel, u8 *ofdmpowerlevel) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_phy *rtlphy = &(rtlpriv->phy); + + rtlphy->cur_cck_txpwridx = cckpowerlevel[0]; + rtlphy->cur_ofdm24g_txpwridx = ofdmpowerlevel[0]; +} + +void rtl92s_phy_set_txpower(struct ieee80211_hw *hw, u8 channel) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw)); + /* [0]:RF-A, [1]:RF-B */ + u8 cckpowerlevel[2], ofdmpowerLevel[2]; + + if (rtlefuse->txpwr_fromeprom == false) + return; + + /* Mainly we use RF-A Tx Power to write the Tx Power registers, + * but the RF-B Tx Power must be calculated by the antenna diff. + * So we have to rewrite Antenna gain offset register here. + * Please refer to BB register 0x80c + * 1. For CCK. + * 2. For OFDM 1T or 2T */ + _rtl92s_phy_get_txpower_index(hw, channel, &cckpowerlevel[0], + &ofdmpowerLevel[0]); + + RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD, + ("Channel-%d, cckPowerLevel (A / B) = " + "0x%x / 0x%x, ofdmPowerLevel (A / B) = 0x%x / 0x%x\n", + channel, cckpowerlevel[0], cckpowerlevel[1], + ofdmpowerLevel[0], ofdmpowerLevel[1])); + + _rtl92s_phy_ccxpower_indexcheck(hw, channel, &cckpowerlevel[0], + &ofdmpowerLevel[0]); + + rtl92s_phy_rf6052_set_ccktxpower(hw, cckpowerlevel[0]); + rtl92s_phy_rf6052_set_ofdmtxpower(hw, &ofdmpowerLevel[0], channel); + +} + +void rtl92s_phy_chk_fwcmd_iodone(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + u16 pollingcnt = 10000; + u32 tmpvalue; + + /* Make sure that CMD IO has be accepted by FW. */ + do { + udelay(10); + + tmpvalue = rtl_read_dword(rtlpriv, WFM5); + if (tmpvalue == 0) + break; + } while (--pollingcnt); + + if (pollingcnt == 0) + RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, ("Set FW Cmd fail!!\n")); +} + + +static void _rtl92s_phy_set_fwcmd_io(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); + struct rtl_phy *rtlphy = &(rtlpriv->phy); + u32 input, current_aid = 0; + + if (is_hal_stop(rtlhal)) + return; + + /* We re-map RA related CMD IO to combinational ones */ + /* if FW version is v.52 or later. */ + switch (rtlhal->current_fwcmd_io) { + case FW_CMD_RA_REFRESH_N: + rtlhal->current_fwcmd_io = FW_CMD_RA_REFRESH_N_COMB; + break; + case FW_CMD_RA_REFRESH_BG: + rtlhal->current_fwcmd_io = FW_CMD_RA_REFRESH_BG_COMB; + break; + default: + break; + } + + switch (rtlhal->current_fwcmd_io) { + case FW_CMD_RA_RESET: + RT_TRACE(rtlpriv, COMP_CMD, DBG_DMESG, + ("FW_CMD_RA_RESET\n")); + rtl_write_dword(rtlpriv, WFM5, FW_RA_RESET); + rtl92s_phy_chk_fwcmd_iodone(hw); + break; + case FW_CMD_RA_ACTIVE: + RT_TRACE(rtlpriv, COMP_CMD, DBG_DMESG, + ("FW_CMD_RA_ACTIVE\n")); + rtl_write_dword(rtlpriv, WFM5, FW_RA_ACTIVE); + rtl92s_phy_chk_fwcmd_iodone(hw); + break; + case FW_CMD_RA_REFRESH_N: + RT_TRACE(rtlpriv, COMP_CMD, DBG_DMESG, + ("FW_CMD_RA_REFRESH_N\n")); + input = FW_RA_REFRESH; + rtl_write_dword(rtlpriv, WFM5, input); + rtl92s_phy_chk_fwcmd_iodone(hw); + rtl_write_dword(rtlpriv, WFM5, FW_RA_ENABLE_RSSI_MASK); + rtl92s_phy_chk_fwcmd_iodone(hw); + break; + case FW_CMD_RA_REFRESH_BG: + RT_TRACE(rtlpriv, COMP_CMD, DBG_DMESG, + ("FW_CMD_RA_REFRESH_BG\n")); + rtl_write_dword(rtlpriv, WFM5, FW_RA_REFRESH); + rtl92s_phy_chk_fwcmd_iodone(hw); + rtl_write_dword(rtlpriv, WFM5, FW_RA_DISABLE_RSSI_MASK); + rtl92s_phy_chk_fwcmd_iodone(hw); + break; + case FW_CMD_RA_REFRESH_N_COMB: + RT_TRACE(rtlpriv, COMP_CMD, DBG_DMESG, + ("FW_CMD_RA_REFRESH_N_COMB\n")); + input = FW_RA_IOT_N_COMB; + rtl_write_dword(rtlpriv, WFM5, input); + rtl92s_phy_chk_fwcmd_iodone(hw); + break; + case FW_CMD_RA_REFRESH_BG_COMB: + RT_TRACE(rtlpriv, COMP_CMD, DBG_DMESG, + ("FW_CMD_RA_REFRESH_BG_COMB\n")); + input = FW_RA_IOT_BG_COMB; + rtl_write_dword(rtlpriv, WFM5, input); + rtl92s_phy_chk_fwcmd_iodone(hw); + break; + case FW_CMD_IQK_ENABLE: + RT_TRACE(rtlpriv, COMP_CMD, DBG_DMESG, + ("FW_CMD_IQK_ENABLE\n")); + rtl_write_dword(rtlpriv, WFM5, FW_IQK_ENABLE); + rtl92s_phy_chk_fwcmd_iodone(hw); + break; + case FW_CMD_PAUSE_DM_BY_SCAN: + /* Lower initial gain */ + rtl_set_bbreg(hw, ROFDM0_XAAGCCORE1, MASKBYTE0, 0x17); + rtl_set_bbreg(hw, ROFDM0_XBAGCCORE1, MASKBYTE0, 0x17); + /* CCA threshold */ + rtl_set_bbreg(hw, RCCK0_CCA, MASKBYTE2, 0x40); + break; + case FW_CMD_RESUME_DM_BY_SCAN: + /* CCA threshold */ + rtl_set_bbreg(hw, RCCK0_CCA, MASKBYTE2, 0xcd); + rtl92s_phy_set_txpower(hw, rtlphy->current_channel); + break; + case FW_CMD_HIGH_PWR_DISABLE: + if (rtlpriv->dm.dm_flag & HAL_DM_HIPWR_DISABLE) + break; + + /* Lower initial gain */ + rtl_set_bbreg(hw, ROFDM0_XAAGCCORE1, MASKBYTE0, 0x17); + rtl_set_bbreg(hw, ROFDM0_XBAGCCORE1, MASKBYTE0, 0x17); + /* CCA threshold */ + rtl_set_bbreg(hw, RCCK0_CCA, MASKBYTE2, 0x40); + break; + case FW_CMD_HIGH_PWR_ENABLE: + if ((rtlpriv->dm.dm_flag & HAL_DM_HIPWR_DISABLE) || + (rtlpriv->dm.dynamic_txpower_enable == true)) + break; + + /* CCA threshold */ + rtl_set_bbreg(hw, RCCK0_CCA, MASKBYTE2, 0xcd); + break; + case FW_CMD_LPS_ENTER: + RT_TRACE(rtlpriv, COMP_CMD, DBG_DMESG, + ("FW_CMD_LPS_ENTER\n")); + current_aid = rtlpriv->mac80211.assoc_id; + rtl_write_dword(rtlpriv, WFM5, (FW_LPS_ENTER | + ((current_aid | 0xc000) << 8))); + rtl92s_phy_chk_fwcmd_iodone(hw); + /* FW set TXOP disable here, so disable EDCA + * turbo mode until driver leave LPS */ + break; + case FW_CMD_LPS_LEAVE: + RT_TRACE(rtlpriv, COMP_CMD, DBG_DMESG, + ("FW_CMD_LPS_LEAVE\n")); + rtl_write_dword(rtlpriv, WFM5, FW_LPS_LEAVE); + rtl92s_phy_chk_fwcmd_iodone(hw); + break; + case FW_CMD_ADD_A2_ENTRY: + RT_TRACE(rtlpriv, COMP_CMD, DBG_DMESG, + ("FW_CMD_ADD_A2_ENTRY\n")); + rtl_write_dword(rtlpriv, WFM5, FW_ADD_A2_ENTRY); + rtl92s_phy_chk_fwcmd_iodone(hw); + break; + case FW_CMD_CTRL_DM_BY_DRIVER: + RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD, + ("FW_CMD_CTRL_DM_BY_DRIVER\n")); + rtl_write_dword(rtlpriv, WFM5, FW_CTRL_DM_BY_DRIVER); + rtl92s_phy_chk_fwcmd_iodone(hw); + break; + + default: + break; + } + + rtl92s_phy_chk_fwcmd_iodone(hw); + + /* Clear FW CMD operation flag. */ + rtlhal->set_fwcmd_inprogress = false; +} + +bool rtl92s_phy_set_fw_cmd(struct ieee80211_hw *hw, enum fwcmd_iotype fw_cmdio) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); + struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw)); + u32 fw_param = FW_CMD_IO_PARA_QUERY(rtlpriv); + u16 fw_cmdmap = FW_CMD_IO_QUERY(rtlpriv); + bool bPostProcessing = false; + + RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD, + ("Set FW Cmd(%#x), set_fwcmd_inprogress(%d)\n", + fw_cmdio, rtlhal->set_fwcmd_inprogress)); + + do { + /* We re-map to combined FW CMD ones if firmware version */ + /* is v.53 or later. */ + switch (fw_cmdio) { + case FW_CMD_RA_REFRESH_N: + fw_cmdio = FW_CMD_RA_REFRESH_N_COMB; + break; + case FW_CMD_RA_REFRESH_BG: + fw_cmdio = FW_CMD_RA_REFRESH_BG_COMB; + break; + default: + break; + } + + /* If firmware version is v.62 or later, + * use FW_CMD_IO_SET for FW_CMD_CTRL_DM_BY_DRIVER */ + if (hal_get_firmwareversion(rtlpriv) >= 0x3E) { + if (fw_cmdio == FW_CMD_CTRL_DM_BY_DRIVER) + fw_cmdio = FW_CMD_CTRL_DM_BY_DRIVER_NEW; + } + + + /* We shall revise all FW Cmd IO into Reg0x364 + * DM map table in the future. */ + switch (fw_cmdio) { + case FW_CMD_RA_INIT: + RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD, ("RA init!!\n")); + fw_cmdmap |= FW_RA_INIT_CTL; + FW_CMD_IO_SET(rtlpriv, fw_cmdmap); + /* Clear control flag to sync with FW. */ + FW_CMD_IO_CLR(rtlpriv, FW_RA_INIT_CTL); + break; + case FW_CMD_DIG_DISABLE: + RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD, + ("Set DIG disable!!\n")); + fw_cmdmap &= ~FW_DIG_ENABLE_CTL; + FW_CMD_IO_SET(rtlpriv, fw_cmdmap); + break; + case FW_CMD_DIG_ENABLE: + case FW_CMD_DIG_RESUME: + if (!(rtlpriv->dm.dm_flag & HAL_DM_DIG_DISABLE)) { + RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD, + ("Set DIG enable or resume!!\n")); + fw_cmdmap |= (FW_DIG_ENABLE_CTL | FW_SS_CTL); + FW_CMD_IO_SET(rtlpriv, fw_cmdmap); + } + break; + case FW_CMD_DIG_HALT: + RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD, + ("Set DIG halt!!\n")); + fw_cmdmap &= ~(FW_DIG_ENABLE_CTL | FW_SS_CTL); + FW_CMD_IO_SET(rtlpriv, fw_cmdmap); + break; + case FW_CMD_TXPWR_TRACK_THERMAL: { + u8 thermalval = 0; + fw_cmdmap |= FW_PWR_TRK_CTL; + + /* Clear FW parameter in terms of thermal parts. */ + fw_param &= FW_PWR_TRK_PARAM_CLR; + + thermalval = rtlpriv->dm.thermalvalue; + fw_param |= ((thermalval << 24) | + (rtlefuse->thermalmeter[0] << 16)); + + RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD, + ("Set TxPwr tracking!! " + "FwCmdMap(%#x), FwParam(%#x)\n", + fw_cmdmap, fw_param)); + + FW_CMD_PARA_SET(rtlpriv, fw_param); + FW_CMD_IO_SET(rtlpriv, fw_cmdmap); + + /* Clear control flag to sync with FW. */ + FW_CMD_IO_CLR(rtlpriv, FW_PWR_TRK_CTL); + } + break; + /* The following FW CMDs are only compatible to + * v.53 or later. */ + case FW_CMD_RA_REFRESH_N_COMB: + fw_cmdmap |= FW_RA_N_CTL; + + /* Clear RA BG mode control. */ + fw_cmdmap &= ~(FW_RA_BG_CTL | FW_RA_INIT_CTL); + + /* Clear FW parameter in terms of RA parts. */ + fw_param &= FW_RA_PARAM_CLR; + + RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD, + ("[FW CMD] [New Version] " + "Set RA/IOT Comb in n mode!! FwCmdMap(%#x), " + "FwParam(%#x)\n", fw_cmdmap, fw_param)); + + FW_CMD_PARA_SET(rtlpriv, fw_param); + FW_CMD_IO_SET(rtlpriv, fw_cmdmap); + + /* Clear control flag to sync with FW. */ + FW_CMD_IO_CLR(rtlpriv, FW_RA_N_CTL); + break; + case FW_CMD_RA_REFRESH_BG_COMB: + fw_cmdmap |= FW_RA_BG_CTL; + + /* Clear RA n-mode control. */ + fw_cmdmap &= ~(FW_RA_N_CTL | FW_RA_INIT_CTL); + /* Clear FW parameter in terms of RA parts. */ + fw_param &= FW_RA_PARAM_CLR; + + FW_CMD_PARA_SET(rtlpriv, fw_param); + FW_CMD_IO_SET(rtlpriv, fw_cmdmap); + + /* Clear control flag to sync with FW. */ + FW_CMD_IO_CLR(rtlpriv, FW_RA_BG_CTL); + break; + case FW_CMD_IQK_ENABLE: + fw_cmdmap |= FW_IQK_CTL; + FW_CMD_IO_SET(rtlpriv, fw_cmdmap); + /* Clear control flag to sync with FW. */ + FW_CMD_IO_CLR(rtlpriv, FW_IQK_CTL); + break; + /* The following FW CMD is compatible to v.62 or later. */ + case FW_CMD_CTRL_DM_BY_DRIVER_NEW: + fw_cmdmap |= FW_DRIVER_CTRL_DM_CTL; + FW_CMD_IO_SET(rtlpriv, fw_cmdmap); + break; + /* The followed FW Cmds needs post-processing later. */ + case FW_CMD_RESUME_DM_BY_SCAN: + fw_cmdmap |= (FW_DIG_ENABLE_CTL | + FW_HIGH_PWR_ENABLE_CTL | + FW_SS_CTL); + + if (rtlpriv->dm.dm_flag & HAL_DM_DIG_DISABLE || + !digtable.dig_enable_flag) + fw_cmdmap &= ~FW_DIG_ENABLE_CTL; + + if ((rtlpriv->dm.dm_flag & HAL_DM_HIPWR_DISABLE) || + (rtlpriv->dm.dynamic_txpower_enable == true)) + fw_cmdmap &= ~FW_HIGH_PWR_ENABLE_CTL; + + if ((digtable.dig_ext_port_stage == + DIG_EXT_PORT_STAGE_0) || + (digtable.dig_ext_port_stage == + DIG_EXT_PORT_STAGE_1)) + fw_cmdmap &= ~FW_DIG_ENABLE_CTL; + + FW_CMD_IO_SET(rtlpriv, fw_cmdmap); + bPostProcessing = true; + break; + case FW_CMD_PAUSE_DM_BY_SCAN: + fw_cmdmap &= ~(FW_DIG_ENABLE_CTL | + FW_HIGH_PWR_ENABLE_CTL | + FW_SS_CTL); + FW_CMD_IO_SET(rtlpriv, fw_cmdmap); + bPostProcessing = true; + break; + case FW_CMD_HIGH_PWR_DISABLE: + fw_cmdmap &= ~FW_HIGH_PWR_ENABLE_CTL; + FW_CMD_IO_SET(rtlpriv, fw_cmdmap); + bPostProcessing = true; + break; + case FW_CMD_HIGH_PWR_ENABLE: + if (!(rtlpriv->dm.dm_flag & HAL_DM_HIPWR_DISABLE) && + (rtlpriv->dm.dynamic_txpower_enable != true)) { + fw_cmdmap |= (FW_HIGH_PWR_ENABLE_CTL | + FW_SS_CTL); + FW_CMD_IO_SET(rtlpriv, fw_cmdmap); + bPostProcessing = true; + } + break; + case FW_CMD_DIG_MODE_FA: + fw_cmdmap |= FW_FA_CTL; + FW_CMD_IO_SET(rtlpriv, fw_cmdmap); + break; + case FW_CMD_DIG_MODE_SS: + fw_cmdmap &= ~FW_FA_CTL; + FW_CMD_IO_SET(rtlpriv, fw_cmdmap); + break; + case FW_CMD_PAPE_CONTROL: + RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD, + ("[FW CMD] Set PAPE Control\n")); + fw_cmdmap &= ~FW_PAPE_CTL_BY_SW_HW; + + FW_CMD_IO_SET(rtlpriv, fw_cmdmap); + break; + default: + /* Pass to original FW CMD processing callback + * routine. */ + bPostProcessing = true; + break; + } + } while (false); + + /* We shall post processing these FW CMD if + * variable bPostProcessing is set. */ + if (bPostProcessing && !rtlhal->set_fwcmd_inprogress) { + rtlhal->set_fwcmd_inprogress = true; + /* Update current FW Cmd for callback use. */ + rtlhal->current_fwcmd_io = fw_cmdio; + } else { + return false; + } + + _rtl92s_phy_set_fwcmd_io(hw); + return true; +} + +static void _rtl92s_phy_check_ephy_switchready(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + u32 delay = 100; + u8 regu1; + + regu1 = rtl_read_byte(rtlpriv, 0x554); + while ((regu1 & BIT(5)) && (delay > 0)) { + regu1 = rtl_read_byte(rtlpriv, 0x554); + delay--; + /* We delay only 50us to prevent + * being scheduled out. */ + udelay(50); + } +} + +void rtl92s_phy_switch_ephy_parameter(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); + + /* The way to be capable to switch clock request + * when the PG setting does not support clock request. + * This is the backdoor solution to switch clock + * request before ASPM or D3. */ + rtl_write_dword(rtlpriv, 0x540, 0x73c11); + rtl_write_dword(rtlpriv, 0x548, 0x2407c); + + /* Switch EPHY parameter!!!! */ + rtl_write_word(rtlpriv, 0x550, 0x1000); + rtl_write_byte(rtlpriv, 0x554, 0x20); + _rtl92s_phy_check_ephy_switchready(hw); + + rtl_write_word(rtlpriv, 0x550, 0xa0eb); + rtl_write_byte(rtlpriv, 0x554, 0x3e); + _rtl92s_phy_check_ephy_switchready(hw); + + rtl_write_word(rtlpriv, 0x550, 0xff80); + rtl_write_byte(rtlpriv, 0x554, 0x39); + _rtl92s_phy_check_ephy_switchready(hw); + + /* Delay L1 enter time */ + if (ppsc->support_aspm && !ppsc->support_backdoor) + rtl_write_byte(rtlpriv, 0x560, 0x40); + else + rtl_write_byte(rtlpriv, 0x560, 0x00); + +} + +void rtl92s_phy_set_beacon_hwreg(struct ieee80211_hw *hw, u16 BeaconInterval) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + rtl_write_dword(rtlpriv, WFM5, 0xF1000000 | (BeaconInterval << 8)); +} diff --git a/drivers/net/wireless/rtlwifi/rtl8192se/phy.h b/drivers/net/wireless/rtlwifi/rtl8192se/phy.h new file mode 100644 index 0000000..37e504a --- /dev/null +++ b/drivers/net/wireless/rtlwifi/rtl8192se/phy.h @@ -0,0 +1,101 @@ +/****************************************************************************** + * + * Copyright(c) 2009-2010 Realtek Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger + * + *****************************************************************************/ +#ifndef __RTL92S_PHY_H__ +#define __RTL92S_PHY_H__ + +#define MAX_TXPWR_IDX_NMODE_92S 63 +#define MAX_DOZE_WAITING_TIMES_9x 64 + +/* Channel switch:The size of + * command tables for switch channel */ +#define MAX_PRECMD_CNT 16 +#define MAX_RFDEPENDCMD_CNT 16 +#define MAX_POSTCMD_CNT 16 + +#define RF90_PATH_MAX 4 + +enum version_8192s { + VERSION_8192S_ACUT, + VERSION_8192S_BCUT, + VERSION_8192S_CCUT +}; + +enum swchnlcmd_id { + CMDID_END, + CMDID_SET_TXPOWEROWER_LEVEL, + CMDID_BBREGWRITE10, + CMDID_WRITEPORT_ULONG, + CMDID_WRITEPORT_USHORT, + CMDID_WRITEPORT_UCHAR, + CMDID_RF_WRITEREG, +}; + +struct swchnlcmd { + enum swchnlcmd_id cmdid; + u32 para1; + u32 para2; + u32 msdelay; +}; + +enum baseband_config_type { + /* Radio Path A */ + BASEBAND_CONFIG_PHY_REG = 0, + /* Radio Path B */ + BASEBAND_CONFIG_AGC_TAB = 1, +}; + +#define hal_get_firmwareversion(rtlpriv) \ + (((struct rt_firmware *)(rtlpriv->rtlhal.pfirmware))->firmwareversion) + +u32 rtl92s_phy_query_bb_reg(struct ieee80211_hw *hw, u32 regaddr, u32 bitmask); +void rtl92s_phy_set_bb_reg(struct ieee80211_hw *hw, u32 regaddr, u32 bitmask, + u32 data); +void rtl92s_phy_scan_operation_backup(struct ieee80211_hw *hw, u8 operation); +u32 rtl92s_phy_query_rf_reg(struct ieee80211_hw *hw, enum radio_path rfpath, + u32 regaddr, u32 bitmask); +void rtl92s_phy_set_rf_reg(struct ieee80211_hw *hw, enum radio_path rfpath, + u32 regaddr, u32 bitmask, u32 data); +void rtl92s_phy_set_bw_mode(struct ieee80211_hw *hw, + enum nl80211_channel_type ch_type); +u8 rtl92s_phy_sw_chnl(struct ieee80211_hw *hw); +bool rtl92s_phy_set_rf_power_state(struct ieee80211_hw *hw, + enum rf_pwrstate rfpower_state); +bool rtl92s_phy_mac_config(struct ieee80211_hw *hw); +void rtl92s_phy_switch_ephy_parameter(struct ieee80211_hw *hw); +bool rtl92s_phy_bb_config(struct ieee80211_hw *hw); +bool rtl92s_phy_rf_config(struct ieee80211_hw *hw); +void rtl92s_phy_get_hw_reg_originalvalue(struct ieee80211_hw *hw); +void rtl92s_phy_set_txpower(struct ieee80211_hw *hw, u8 channel); +bool rtl92s_phy_set_fw_cmd(struct ieee80211_hw *hw, enum fwcmd_iotype fwcmd_io); +void rtl92s_phy_chk_fwcmd_iodone(struct ieee80211_hw *hw); +void rtl92s_phy_set_beacon_hwreg(struct ieee80211_hw *hw, u16 beaconinterval); +u8 rtl92s_phy_config_rf(struct ieee80211_hw *hw, enum radio_path rfpath) ; + +#endif + -- cgit v0.10.2 From cf76bbf7c0d0315ec17c950d14de939a81465f6b Mon Sep 17 00:00:00 2001 From: Chaoming Li Date: Tue, 3 May 2011 09:48:45 -0500 Subject: rtlwifi: rtl8192se: Merge register definitions Merge routines reg.h for RTL8192SE. Signed-off-by: Chaoming_Li Signed-off-by: Larry Finger Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/rtlwifi/rtl8192se/reg.h b/drivers/net/wireless/rtlwifi/rtl8192se/reg.h new file mode 100644 index 0000000..0116ead --- /dev/null +++ b/drivers/net/wireless/rtlwifi/rtl8192se/reg.h @@ -0,0 +1,1188 @@ +/****************************************************************************** + * + * Copyright(c) 2009-2010 Realtek Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger + * + *****************************************************************************/ +#ifndef __REALTEK_92S_REG_H__ +#define __REALTEK_92S_REG_H__ + +/* 1. System Configuration Registers */ +#define REG_SYS_ISO_CTRL 0x0000 +#define REG_SYS_FUNC_EN 0x0002 +#define PMC_FSM 0x0004 +#define SYS_CLKR 0x0008 +#define EPROM_CMD 0x000A +#define EE_VPD 0x000C +#define AFE_MISC 0x0010 +#define SPS0_CTRL 0x0011 +#define SPS1_CTRL 0x0018 +#define RF_CTRL 0x001F +#define LDOA15_CTRL 0x0020 +#define LDOV12D_CTRL 0x0021 +#define LDOHCI12_CTRL 0x0022 +#define LDO_USB_SDIO 0x0023 +#define LPLDO_CTRL 0x0024 +#define AFE_XTAL_CTRL 0x0026 +#define AFE_PLL_CTRL 0x0028 +#define REG_EFUSE_CTRL 0x0030 +#define REG_EFUSE_TEST 0x0034 +#define PWR_DATA 0x0038 +#define DBG_PORT 0x003A +#define DPS_TIMER 0x003C +#define RCLK_MON 0x003E + +/* 2. Command Control Registers */ +#define CMDR 0x0040 +#define TXPAUSE 0x0042 +#define LBKMD_SEL 0x0043 +#define TCR 0x0044 +#define RCR 0x0048 +#define MSR 0x004C +#define SYSF_CFG 0x004D +#define RX_PKY_LIMIT 0x004E +#define MBIDCTRL 0x004F + +/* 3. MACID Setting Registers */ +#define MACIDR 0x0050 +#define MACIDR0 0x0050 +#define MACIDR4 0x0054 +#define BSSIDR 0x0058 +#define HWVID 0x005E +#define MAR 0x0060 +#define MBIDCAMCONTENT 0x0068 +#define MBIDCAMCFG 0x0070 +#define BUILDTIME 0x0074 +#define BUILDUSER 0x0078 + +#define IDR0 MACIDR0 +#define IDR4 MACIDR4 + +/* 4. Timing Control Registers */ +#define TSFR 0x0080 +#define SLOT_TIME 0x0089 +#define USTIME 0x008A +#define SIFS_CCK 0x008C +#define SIFS_OFDM 0x008E +#define PIFS_TIME 0x0090 +#define ACK_TIMEOUT 0x0091 +#define EIFSTR 0x0092 +#define BCN_INTERVAL 0x0094 +#define ATIMWND 0x0096 +#define BCN_DRV_EARLY_INT 0x0098 +#define BCN_DMATIME 0x009A +#define BCN_ERR_THRESH 0x009C +#define MLT 0x009D +#define RSVD_MAC_TUNE_US 0x009E + +/* 5. FIFO Control Registers */ +#define RQPN 0x00A0 +#define RQPN1 0x00A0 +#define RQPN2 0x00A1 +#define RQPN3 0x00A2 +#define RQPN4 0x00A3 +#define RQPN5 0x00A4 +#define RQPN6 0x00A5 +#define RQPN7 0x00A6 +#define RQPN8 0x00A7 +#define RQPN9 0x00A8 +#define RQPN10 0x00A9 +#define LD_RQPN 0x00AB +#define RXFF_BNDY 0x00AC +#define RXRPT_BNDY 0x00B0 +#define TXPKTBUF_PGBNDY 0x00B4 +#define PBP 0x00B5 +#define RXDRVINFO_SZ 0x00B6 +#define TXFF_STATUS 0x00B7 +#define RXFF_STATUS 0x00B8 +#define TXFF_EMPTY_TH 0x00B9 +#define SDIO_RX_BLKSZ 0x00BC +#define RXDMA 0x00BD +#define RXPKT_NUM 0x00BE +#define C2HCMD_UDT_SIZE 0x00C0 +#define C2HCMD_UDT_ADDR 0x00C2 +#define FIFOPAGE1 0x00C4 +#define FIFOPAGE2 0x00C8 +#define FIFOPAGE3 0x00CC +#define FIFOPAGE4 0x00D0 +#define FIFOPAGE5 0x00D4 +#define FW_RSVD_PG_CRTL 0x00D8 +#define RXDMA_AGG_PG_TH 0x00D9 +#define TXDESC_MSK 0x00DC +#define TXRPTFF_RDPTR 0x00E0 +#define TXRPTFF_WTPTR 0x00E4 +#define C2HFF_RDPTR 0x00E8 +#define C2HFF_WTPTR 0x00EC +#define RXFF0_RDPTR 0x00F0 +#define RXFF0_WTPTR 0x00F4 +#define RXFF1_RDPTR 0x00F8 +#define RXFF1_WTPTR 0x00FC +#define RXRPT0_RDPTR 0x0100 +#define RXRPT0_WTPTR 0x0104 +#define RXRPT1_RDPTR 0x0108 +#define RXRPT1_WTPTR 0x010C +#define RX0_UDT_SIZE 0x0110 +#define RX1PKTNUM 0x0114 +#define RXFILTERMAP 0x0116 +#define RXFILTERMAP_GP1 0x0118 +#define RXFILTERMAP_GP2 0x011A +#define RXFILTERMAP_GP3 0x011C +#define BCNQ_CTRL 0x0120 +#define MGTQ_CTRL 0x0124 +#define HIQ_CTRL 0x0128 +#define VOTID7_CTRL 0x012c +#define VOTID6_CTRL 0x0130 +#define VITID5_CTRL 0x0134 +#define VITID4_CTRL 0x0138 +#define BETID3_CTRL 0x013c +#define BETID0_CTRL 0x0140 +#define BKTID2_CTRL 0x0144 +#define BKTID1_CTRL 0x0148 +#define CMDQ_CTRL 0x014c +#define TXPKT_NUM_CTRL 0x0150 +#define TXQ_PGADD 0x0152 +#define TXFF_PG_NUM 0x0154 +#define TRXDMA_STATUS 0x0156 + +/* 6. Adaptive Control Registers */ +#define INIMCS_SEL 0x0160 +#define TX_RATE_REG INIMCS_SEL +#define INIRTSMCS_SEL 0x0180 +#define RRSR 0x0181 +#define ARFR0 0x0184 +#define ARFR1 0x0188 +#define ARFR2 0x018C +#define ARFR3 0x0190 +#define ARFR4 0x0194 +#define ARFR5 0x0198 +#define ARFR6 0x019C +#define ARFR7 0x01A0 +#define AGGLEN_LMT_H 0x01A7 +#define AGGLEN_LMT_L 0x01A8 +#define DARFRC 0x01B0 +#define RARFRC 0x01B8 +#define MCS_TXAGC 0x01C0 +#define CCK_TXAGC 0x01C8 + +/* 7. EDCA Setting Registers */ +#define EDCAPARA_VO 0x01D0 +#define EDCAPARA_VI 0x01D4 +#define EDCAPARA_BE 0x01D8 +#define EDCAPARA_BK 0x01DC +#define BCNTCFG 0x01E0 +#define CWRR 0x01E2 +#define ACMAVG 0x01E4 +#define AcmHwCtrl 0x01E7 +#define VO_ADMTM 0x01E8 +#define VI_ADMTM 0x01EC +#define BE_ADMTM 0x01F0 +#define RETRY_LIMIT 0x01F4 +#define SG_RATE 0x01F6 + +/* 8. WMAC, BA and CCX related Register. */ +#define NAV_CTRL 0x0200 +#define BW_OPMODE 0x0203 +#define BACAMCMD 0x0204 +#define BACAMCONTENT 0x0208 + +/* the 0x2xx register WMAC definition */ +#define LBDLY 0x0210 +#define FWDLY 0x0211 +#define HWPC_RX_CTRL 0x0218 +#define MQIR 0x0220 +#define MAIR 0x0222 +#define MSIR 0x0224 +#define CLM_RESULT 0x0227 +#define NHM_RPI_CNT 0x0228 +#define RXERR_RPT 0x0230 +#define NAV_PROT_LEN 0x0234 +#define CFEND_TH 0x0236 +#define AMPDU_MIN_SPACE 0x0237 +#define TXOP_STALL_CTRL 0x0238 + +/* 9. Security Control Registers */ +#define REG_RWCAM 0x0240 +#define REG_WCAMI 0x0244 +#define REG_RCAMO 0x0248 +#define REG_CAMDBG 0x024C +#define REG_SECR 0x0250 + +/* 10. Power Save Control Registers */ +#define WOW_CTRL 0x0260 +#define PSSTATUS 0x0261 +#define PSSWITCH 0x0262 +#define MIMOPS_WAIT_PERIOD 0x0263 +#define LPNAV_CTRL 0x0264 +#define WFM0 0x0270 +#define WFM1 0x0280 +#define WFM2 0x0290 +#define WFM3 0x02A0 +#define WFM4 0x02B0 +#define WFM5 0x02C0 +#define WFCRC 0x02D0 +#define FW_RPT_REG 0x02c4 + +/* 11. General Purpose Registers */ +#define PSTIME 0x02E0 +#define TIMER0 0x02E4 +#define TIMER1 0x02E8 +#define GPIO_CTRL 0x02EC +#define GPIO_IN 0x02EC +#define GPIO_OUT 0x02ED +#define GPIO_IO_SEL 0x02EE +#define GPIO_MOD 0x02EF +#define GPIO_INTCTRL 0x02F0 +#define MAC_PINMUX_CFG 0x02F1 +#define LEDCFG 0x02F2 +#define PHY_REG 0x02F3 +#define PHY_REG_DATA 0x02F4 +#define REG_EFUSE_CLK 0x02F8 + +/* 12. Host Interrupt Status Registers */ +#define INTA_MASK 0x0300 +#define ISR 0x0308 + +/* 13. Test Mode and Debug Control Registers */ +#define DBG_PORT_SWITCH 0x003A +#define BIST 0x0310 +#define DBS 0x0314 +#define CPUINST 0x0318 +#define CPUCAUSE 0x031C +#define LBUS_ERR_ADDR 0x0320 +#define LBUS_ERR_CMD 0x0324 +#define LBUS_ERR_DATA_L 0x0328 +#define LBUS_ERR_DATA_H 0x032C +#define LX_EXCEPTION_ADDR 0x0330 +#define WDG_CTRL 0x0334 +#define INTMTU 0x0338 +#define INTM 0x033A +#define FDLOCKTURN0 0x033C +#define FDLOCKTURN1 0x033D +#define TRXPKTBUF_DBG_DATA 0x0340 +#define TRXPKTBUF_DBG_CTRL 0x0348 +#define DPLL 0x034A +#define CBUS_ERR_ADDR 0x0350 +#define CBUS_ERR_CMD 0x0354 +#define CBUS_ERR_DATA_L 0x0358 +#define CBUS_ERR_DATA_H 0x035C +#define USB_SIE_INTF_ADDR 0x0360 +#define USB_SIE_INTF_WD 0x0361 +#define USB_SIE_INTF_RD 0x0362 +#define USB_SIE_INTF_CTRL 0x0363 +#define LBUS_MON_ADDR 0x0364 +#define LBUS_ADDR_MASK 0x0368 + +/* Boundary is 0x37F */ + +/* 14. PCIE config register */ +#define TP_POLL 0x0500 +#define PM_CTRL 0x0502 +#define PCIF 0x0503 + +#define THPDA 0x0514 +#define TMDA 0x0518 +#define TCDA 0x051C +#define HDA 0x0520 +#define TVODA 0x0524 +#define TVIDA 0x0528 +#define TBEDA 0x052C +#define TBKDA 0x0530 +#define TBDA 0x0534 +#define RCDA 0x0538 +#define RDQDA 0x053C +#define DBI_WDATA 0x0540 +#define DBI_RDATA 0x0544 +#define DBI_CTRL 0x0548 +#define MDIO_DATA 0x0550 +#define MDIO_CTRL 0x0554 +#define PCI_RPWM 0x0561 +#define PCI_CPWM 0x0563 + +/* Config register (Offset 0x800-) */ +#define PHY_CCA 0x803 + +/* Min Spacing related settings. */ +#define MAX_MSS_DENSITY_2T 0x13 +#define MAX_MSS_DENSITY_1T 0x0A + +/* Rx DMA Control related settings */ +#define RXDMA_AGG_EN BIT(7) + +#define RPWM PCI_RPWM + +/* Regsiter Bit and Content definition */ + +#define ISO_MD2PP BIT(0) +#define ISO_PA2PCIE BIT(3) +#define ISO_PLL2MD BIT(4) +#define ISO_PWC_DV2RP BIT(11) +#define ISO_PWC_RV2RP BIT(12) + + +#define FEN_MREGEN BIT(15) +#define FEN_DCORE BIT(11) +#define FEN_CPUEN BIT(10) + +#define PAD_HWPD_IDN BIT(22) + +#define SYS_CLKSEL_80M BIT(0) +#define SYS_PS_CLKSEL BIT(1) +#define SYS_CPU_CLKSEL BIT(2) +#define SYS_MAC_CLK_EN BIT(11) +#define SYS_SWHW_SEL BIT(14) +#define SYS_FWHW_SEL BIT(15) + +#define CmdEEPROM_En BIT(5) +#define CmdEERPOMSEL BIT(4) +#define Cmd9346CR_9356SEL BIT(4) + +#define AFE_MBEN BIT(1) +#define AFE_BGEN BIT(0) + +#define SPS1_SWEN BIT(1) +#define SPS1_LDEN BIT(0) + +#define RF_EN BIT(0) +#define RF_RSTB BIT(1) +#define RF_SDMRSTB BIT(2) + +#define LDA15_EN BIT(0) + +#define LDV12_EN BIT(0) +#define LDV12_SDBY BIT(1) + +#define XTAL_GATE_AFE BIT(10) + +#define APLL_EN BIT(0) + +#define AFR_CardBEn BIT(0) +#define AFR_CLKRUN_SEL BIT(1) +#define AFR_FuncRegEn BIT(2) + +#define APSDOFF_STATUS BIT(15) +#define APSDOFF BIT(14) +#define BBRSTN BIT(13) +#define BB_GLB_RSTN BIT(12) +#define SCHEDULE_EN BIT(10) +#define MACRXEN BIT(9) +#define MACTXEN BIT(8) +#define DDMA_EN BIT(7) +#define FW2HW_EN BIT(6) +#define RXDMA_EN BIT(5) +#define TXDMA_EN BIT(4) +#define HCI_RXDMA_EN BIT(3) +#define HCI_TXDMA_EN BIT(2) + +#define StopHCCA BIT(6) +#define StopHigh BIT(5) +#define StopMgt BIT(4) +#define StopVO BIT(3) +#define StopVI BIT(2) +#define StopBE BIT(1) +#define StopBK BIT(0) + +#define LBK_NORMAL 0x00 +#define LBK_MAC_LB (BIT(0) | BIT(1) | BIT(3)) +#define LBK_MAC_DLB (BIT(0) | BIT(1)) +#define LBK_DMA_LB (BIT(0) | BIT(1) | BIT(2)) + +#define TCP_OFDL_EN BIT(25) +#define HWPC_TX_EN BIT(24) +#define TXDMAPRE2FULL BIT(23) +#define DISCW BIT(20) +#define TCRICV BIT(19) +#define CfendForm BIT(17) +#define TCRCRC BIT(16) +#define FAKE_IMEM_EN BIT(15) +#define TSFRST BIT(9) +#define TSFEN BIT(8) +#define FWALLRDY (BIT(0) | BIT(1) | BIT(2) | \ + BIT(3) | BIT(4) | BIT(5) | \ + BIT(6) | BIT(7)) +#define FWRDY BIT(7) +#define BASECHG BIT(6) +#define IMEM BIT(5) +#define DMEM_CODE_DONE BIT(4) +#define EXT_IMEM_CHK_RPT BIT(3) +#define EXT_IMEM_CODE_DONE BIT(2) +#define IMEM_CHK_RPT BIT(1) +#define IMEM_CODE_DONE BIT(0) +#define IMEM_CODE_DONE BIT(0) +#define IMEM_CHK_RPT BIT(1) +#define EMEM_CODE_DONE BIT(2) +#define EMEM_CHK_RPT BIT(3) +#define DMEM_CODE_DONE BIT(4) +#define IMEM_RDY BIT(5) +#define BASECHG BIT(6) +#define FWRDY BIT(7) +#define LOAD_FW_READY (IMEM_CODE_DONE | \ + IMEM_CHK_RPT | \ + EMEM_CODE_DONE | \ + EMEM_CHK_RPT | \ + DMEM_CODE_DONE | \ + IMEM_RDY | \ + BASECHG | \ + FWRDY) +#define TCR_TSFEN BIT(8) +#define TCR_TSFRST BIT(9) +#define TCR_FAKE_IMEM_EN BIT(15) +#define TCR_CRC BIT(16) +#define TCR_ICV BIT(19) +#define TCR_DISCW BIT(20) +#define TCR_HWPC_TX_EN BIT(24) +#define TCR_TCP_OFDL_EN BIT(25) +#define TXDMA_INIT_VALUE (IMEM_CHK_RPT | \ + EXT_IMEM_CHK_RPT) + +#define RCR_APPFCS BIT(31) +#define RCR_DIS_ENC_2BYTE BIT(30) +#define RCR_DIS_AES_2BYTE BIT(29) +#define RCR_HTC_LOC_CTRL BIT(28) +#define RCR_ENMBID BIT(27) +#define RCR_RX_TCPOFDL_EN BIT(26) +#define RCR_APP_PHYST_RXFF BIT(25) +#define RCR_APP_PHYST_STAFF BIT(24) +#define RCR_CBSSID BIT(23) +#define RCR_APWRMGT BIT(22) +#define RCR_ADD3 BIT(21) +#define RCR_AMF BIT(20) +#define RCR_ACF BIT(19) +#define RCR_ADF BIT(18) +#define RCR_APP_MIC BIT(17) +#define RCR_APP_ICV BIT(16) +#define RCR_RXFTH BIT(13) +#define RCR_AICV BIT(12) +#define RCR_RXDESC_LK_EN BIT(11) +#define RCR_APP_BA_SSN BIT(6) +#define RCR_ACRC32 BIT(5) +#define RCR_RXSHFT_EN BIT(4) +#define RCR_AB BIT(3) +#define RCR_AM BIT(2) +#define RCR_APM BIT(1) +#define RCR_AAP BIT(0) +#define RCR_MXDMA_OFFSET 8 +#define RCR_FIFO_OFFSET 13 + + +#define MSR_LINK_MASK ((1 << 0) | (1 << 1)) +#define MSR_LINK_MANAGED 2 +#define MSR_LINK_NONE 0 +#define MSR_LINK_SHIFT 0 +#define MSR_LINK_ADHOC 1 +#define MSR_LINK_MASTER 3 +#define MSR_NOLINK 0x00 +#define MSR_ADHOC 0x01 +#define MSR_INFRA 0x02 +#define MSR_AP 0x03 + +#define ENUART BIT(7) +#define ENJTAG BIT(3) +#define BTMODE (BIT(2) | BIT(1)) +#define ENBT BIT(0) + +#define ENMBID BIT(7) +#define BCNUM (BIT(6) | BIT(5) | BIT(4)) + +#define USTIME_EDCA 0xFF00 +#define USTIME_TSF 0x00FF + +#define SIFS_TRX 0xFF00 +#define SIFS_CTX 0x00FF + +#define ENSWBCN BIT(15) +#define DRVERLY_TU 0x0FF0 +#define DRVERLY_US 0x000F +#define BCN_TCFG_CW_SHIFT 8 +#define BCN_TCFG_IFS 0 + +#define RRSR_RSC_OFFSET 21 +#define RRSR_SHORT_OFFSET 23 +#define RRSR_RSC_BW_40M 0x600000 +#define RRSR_RSC_UPSUBCHNL 0x400000 +#define RRSR_RSC_LOWSUBCHNL 0x200000 +#define RRSR_SHORT 0x800000 +#define RRSR_1M BIT(0) +#define RRSR_2M BIT(1) +#define RRSR_5_5M BIT(2) +#define RRSR_11M BIT(3) +#define RRSR_6M BIT(4) +#define RRSR_9M BIT(5) +#define RRSR_12M BIT(6) +#define RRSR_18M BIT(7) +#define RRSR_24M BIT(8) +#define RRSR_36M BIT(9) +#define RRSR_48M BIT(10) +#define RRSR_54M BIT(11) +#define RRSR_MCS0 BIT(12) +#define RRSR_MCS1 BIT(13) +#define RRSR_MCS2 BIT(14) +#define RRSR_MCS3 BIT(15) +#define RRSR_MCS4 BIT(16) +#define RRSR_MCS5 BIT(17) +#define RRSR_MCS6 BIT(18) +#define RRSR_MCS7 BIT(19) +#define BRSR_AckShortPmb BIT(23) + +#define RATR_1M 0x00000001 +#define RATR_2M 0x00000002 +#define RATR_55M 0x00000004 +#define RATR_11M 0x00000008 +#define RATR_6M 0x00000010 +#define RATR_9M 0x00000020 +#define RATR_12M 0x00000040 +#define RATR_18M 0x00000080 +#define RATR_24M 0x00000100 +#define RATR_36M 0x00000200 +#define RATR_48M 0x00000400 +#define RATR_54M 0x00000800 +#define RATR_MCS0 0x00001000 +#define RATR_MCS1 0x00002000 +#define RATR_MCS2 0x00004000 +#define RATR_MCS3 0x00008000 +#define RATR_MCS4 0x00010000 +#define RATR_MCS5 0x00020000 +#define RATR_MCS6 0x00040000 +#define RATR_MCS7 0x00080000 +#define RATR_MCS8 0x00100000 +#define RATR_MCS9 0x00200000 +#define RATR_MCS10 0x00400000 +#define RATR_MCS11 0x00800000 +#define RATR_MCS12 0x01000000 +#define RATR_MCS13 0x02000000 +#define RATR_MCS14 0x04000000 +#define RATR_MCS15 0x08000000 + +#define RATE_ALL_CCK (RATR_1M | RATR_2M | \ + RATR_55M | RATR_11M) +#define RATE_ALL_OFDM_AG (RATR_6M | RATR_9M | \ + RATR_12M | RATR_18M | \ + RATR_24M | RATR_36M | \ + RATR_48M | RATR_54M) +#define RATE_ALL_OFDM_1SS (RATR_MCS0 | RATR_MCS1 | \ + RATR_MCS2 | RATR_MCS3 | \ + RATR_MCS4 | RATR_MCS5 | \ + RATR_MCS6 | RATR_MCS7) +#define RATE_ALL_OFDM_2SS (RATR_MCS8 | RATR_MCS9 | \ + RATR_MCS10 | RATR_MCS11 | \ + RATR_MCS12 | RATR_MCS13 | \ + RATR_MCS14 | RATR_MCS15) + +#define AC_PARAM_TXOP_LIMIT_OFFSET 16 +#define AC_PARAM_ECW_MAX_OFFSET 12 +#define AC_PARAM_ECW_MIN_OFFSET 8 +#define AC_PARAM_AIFS_OFFSET 0 + +#define AcmHw_HwEn BIT(0) +#define AcmHw_BeqEn BIT(1) +#define AcmHw_ViqEn BIT(2) +#define AcmHw_VoqEn BIT(3) +#define AcmHw_BeqStatus BIT(4) +#define AcmHw_ViqStatus BIT(5) +#define AcmHw_VoqStatus BIT(6) + +#define RETRY_LIMIT_SHORT_SHIFT 8 +#define RETRY_LIMIT_LONG_SHIFT 0 + +#define NAV_UPPER_EN BIT(16) +#define NAV_UPPER 0xFF00 +#define NAV_RTSRST 0xFF + +#define BW_OPMODE_20MHZ BIT(2) +#define BW_OPMODE_5G BIT(1) +#define BW_OPMODE_11J BIT(0) + +#define RXERR_RPT_RST BIT(27) +#define RXERR_OFDM_PPDU 0 +#define RXERR_OFDM_FALSE_ALARM 1 +#define RXERR_OFDM_MPDU_OK 2 +#define RXERR_OFDM_MPDU_FAIL 3 +#define RXERR_CCK_PPDU 4 +#define RXERR_CCK_FALSE_ALARM 5 +#define RXERR_CCK_MPDU_OK 6 +#define RXERR_CCK_MPDU_FAIL 7 +#define RXERR_HT_PPDU 8 +#define RXERR_HT_FALSE_ALARM 9 +#define RXERR_HT_MPDU_TOTAL 10 +#define RXERR_HT_MPDU_OK 11 +#define RXERR_HT_MPDU_FAIL 12 +#define RXERR_RX_FULL_DROP 15 + +#define SCR_TXUSEDK BIT(0) +#define SCR_RXUSEDK BIT(1) +#define SCR_TXENCENABLE BIT(2) +#define SCR_RXENCENABLE BIT(3) +#define SCR_SKBYA2 BIT(4) +#define SCR_NOSKMC BIT(5) + +#define CAM_VALID BIT(15) +#define CAM_NOTVALID 0x0000 +#define CAM_USEDK BIT(5) + +#define CAM_NONE 0x0 +#define CAM_WEP40 0x01 +#define CAM_TKIP 0x02 +#define CAM_AES 0x04 +#define CAM_WEP104 0x05 + +#define TOTAL_CAM_ENTRY 32 +#define HALF_CAM_ENTRY 16 + +#define CAM_WRITE BIT(16) +#define CAM_READ 0x00000000 +#define CAM_POLLINIG BIT(31) + +#define WOW_PMEN BIT(0) +#define WOW_WOMEN BIT(1) +#define WOW_MAGIC BIT(2) +#define WOW_UWF BIT(3) + +#define GPIOMUX_EN BIT(3) +#define GPIOSEL_GPIO 0 +#define GPIOSEL_PHYDBG 1 +#define GPIOSEL_BT 2 +#define GPIOSEL_WLANDBG 3 +#define GPIOSEL_GPIO_MASK (~(BIT(0)|BIT(1))) + +#define HST_RDBUSY BIT(0) +#define CPU_WTBUSY BIT(1) + +#define IMR8190_DISABLED 0x0 +#define IMR_CPUERR BIT(5) +#define IMR_ATIMEND BIT(4) +#define IMR_TBDOK BIT(3) +#define IMR_TBDER BIT(2) +#define IMR_BCNDMAINT8 BIT(1) +#define IMR_BCNDMAINT7 BIT(0) +#define IMR_BCNDMAINT6 BIT(31) +#define IMR_BCNDMAINT5 BIT(30) +#define IMR_BCNDMAINT4 BIT(29) +#define IMR_BCNDMAINT3 BIT(28) +#define IMR_BCNDMAINT2 BIT(27) +#define IMR_BCNDMAINT1 BIT(26) +#define IMR_BCNDOK8 BIT(25) +#define IMR_BCNDOK7 BIT(24) +#define IMR_BCNDOK6 BIT(23) +#define IMR_BCNDOK5 BIT(22) +#define IMR_BCNDOK4 BIT(21) +#define IMR_BCNDOK3 BIT(20) +#define IMR_BCNDOK2 BIT(19) +#define IMR_BCNDOK1 BIT(18) +#define IMR_TIMEOUT2 BIT(17) +#define IMR_TIMEOUT1 BIT(16) +#define IMR_TXFOVW BIT(15) +#define IMR_PSTIMEOUT BIT(14) +#define IMR_BCNINT BIT(13) +#define IMR_RXFOVW BIT(12) +#define IMR_RDU BIT(11) +#define IMR_RXCMDOK BIT(10) +#define IMR_BDOK BIT(9) +#define IMR_HIGHDOK BIT(8) +#define IMR_COMDOK BIT(7) +#define IMR_MGNTDOK BIT(6) +#define IMR_HCCADOK BIT(5) +#define IMR_BKDOK BIT(4) +#define IMR_BEDOK BIT(3) +#define IMR_VIDOK BIT(2) +#define IMR_VODOK BIT(1) +#define IMR_ROK BIT(0) + +#define TPPOLL_BKQ BIT(0) +#define TPPOLL_BEQ BIT(1) +#define TPPOLL_VIQ BIT(2) +#define TPPOLL_VOQ BIT(3) +#define TPPOLL_BQ BIT(4) +#define TPPOLL_CQ BIT(5) +#define TPPOLL_MQ BIT(6) +#define TPPOLL_HQ BIT(7) +#define TPPOLL_HCCAQ BIT(8) +#define TPPOLL_STOPBK BIT(9) +#define TPPOLL_STOPBE BIT(10) +#define TPPOLL_STOPVI BIT(11) +#define TPPOLL_STOPVO BIT(12) +#define TPPOLL_STOPMGT BIT(13) +#define TPPOLL_STOPHIGH BIT(14) +#define TPPOLL_STOPHCCA BIT(15) +#define TPPOLL_SHIFT 8 + +#define CCX_CMD_CLM_ENABLE BIT(0) +#define CCX_CMD_NHM_ENABLE BIT(1) +#define CCX_CMD_FUNCTION_ENABLE BIT(8) +#define CCX_CMD_IGNORE_CCA BIT(9) +#define CCX_CMD_IGNORE_TXON BIT(10) +#define CCX_CLM_RESULT_READY BIT(16) +#define CCX_NHM_RESULT_READY BIT(16) +#define CCX_CMD_RESET 0x0 + + +#define HWSET_MAX_SIZE_92S 128 +#define EFUSE_MAX_SECTION 16 +#define EFUSE_REAL_CONTENT_LEN 512 + +#define RTL8190_EEPROM_ID 0x8129 +#define EEPROM_HPON 0x02 +#define EEPROM_CLK 0x06 +#define EEPROM_TESTR 0x08 + +#define EEPROM_VID 0x0A +#define EEPROM_DID 0x0C +#define EEPROM_SVID 0x0E +#define EEPROM_SMID 0x10 + +#define EEPROM_MAC_ADDR 0x12 +#define EEPROM_NODE_ADDRESS_BYTE_0 0x12 + +#define EEPROM_PWDIFF 0x54 + +#define EEPROM_TXPOWERBASE 0x50 +#define EEPROM_TX_PWR_INDEX_RANGE 28 + +#define EEPROM_TX_PWR_HT20_DIFF 0x62 +#define DEFAULT_HT20_TXPWR_DIFF 2 +#define EEPROM_TX_PWR_OFDM_DIFF 0x65 + +#define EEPROM_TXPWRGROUP 0x67 +#define EEPROM_REGULATORY 0x6D + +#define TX_PWR_SAFETY_CHK 0x6D +#define EEPROM_TXPWINDEX_CCK_24G 0x5D +#define EEPROM_TXPWINDEX_OFDM_24G 0x6B +#define EEPROM_HT2T_CH1_A 0x6c +#define EEPROM_HT2T_CH7_A 0x6d +#define EEPROM_HT2T_CH13_A 0x6e +#define EEPROM_HT2T_CH1_B 0x6f +#define EEPROM_HT2T_CH7_B 0x70 +#define EEPROM_HT2T_CH13_B 0x71 + +#define EEPROM_TSSI_A 0x74 +#define EEPROM_TSSI_B 0x75 + +#define EEPROM_RFIND_POWERDIFF 0x76 +#define EEPROM_DEFAULT_LEGACYHTTXPOWERDIFF 0x3 + +#define EEPROM_THERMALMETER 0x77 +#define EEPROM_BLUETOOTH_COEXIST 0x78 +#define EEPROM_BLUETOOTH_TYPE 0x4f + +#define EEPROM_OPTIONAL 0x78 +#define EEPROM_WOWLAN 0x78 + +#define EEPROM_CRYSTALCAP 0x79 +#define EEPROM_CHANNELPLAN 0x7B +#define EEPROM_VERSION 0x7C +#define EEPROM_CUSTOMID 0x7A +#define EEPROM_BOARDTYPE 0x7E + +#define EEPROM_CHANNEL_PLAN_FCC 0x0 +#define EEPROM_CHANNEL_PLAN_IC 0x1 +#define EEPROM_CHANNEL_PLAN_ETSI 0x2 +#define EEPROM_CHANNEL_PLAN_SPAIN 0x3 +#define EEPROM_CHANNEL_PLAN_FRANCE 0x4 +#define EEPROM_CHANNEL_PLAN_MKK 0x5 +#define EEPROM_CHANNEL_PLAN_MKK1 0x6 +#define EEPROM_CHANNEL_PLAN_ISRAEL 0x7 +#define EEPROM_CHANNEL_PLAN_TELEC 0x8 +#define EEPROM_CHANNEL_PLAN_GLOBAL_DOMAIN 0x9 +#define EEPROM_CHANNEL_PLAN_WORLD_WIDE_13 0xA +#define EEPROM_CHANNEL_PLAN_NCC 0xB +#define EEPROM_CHANNEL_PLAN_BY_HW_MASK 0x80 + +#define FW_DIG_DISABLE 0xfd00cc00 +#define FW_DIG_ENABLE 0xfd000000 +#define FW_DIG_HALT 0xfd000001 +#define FW_DIG_RESUME 0xfd000002 +#define FW_HIGH_PWR_DISABLE 0xfd000008 +#define FW_HIGH_PWR_ENABLE 0xfd000009 +#define FW_ADD_A2_ENTRY 0xfd000016 +#define FW_TXPWR_TRACK_ENABLE 0xfd000017 +#define FW_TXPWR_TRACK_DISABLE 0xfd000018 +#define FW_TXPWR_TRACK_THERMAL 0xfd000019 +#define FW_TXANT_SWITCH_ENABLE 0xfd000023 +#define FW_TXANT_SWITCH_DISABLE 0xfd000024 +#define FW_RA_INIT 0xfd000026 +#define FW_CTRL_DM_BY_DRIVER 0Xfd00002a +#define FW_RA_IOT_BG_COMB 0xfd000030 +#define FW_RA_IOT_N_COMB 0xfd000031 +#define FW_RA_REFRESH 0xfd0000a0 +#define FW_RA_UPDATE_MASK 0xfd0000a2 +#define FW_RA_DISABLE 0xfd0000a4 +#define FW_RA_ACTIVE 0xfd0000a6 +#define FW_RA_DISABLE_RSSI_MASK 0xfd0000ac +#define FW_RA_ENABLE_RSSI_MASK 0xfd0000ad +#define FW_RA_RESET 0xfd0000af +#define FW_DM_DISABLE 0xfd00aa00 +#define FW_IQK_ENABLE 0xf0000020 +#define FW_IQK_SUCCESS 0x0000dddd +#define FW_IQK_FAIL 0x0000ffff +#define FW_OP_FAILURE 0xffffffff +#define FW_TX_FEEDBACK_NONE 0xfb000000 +#define FW_TX_FEEDBACK_DTM_ENABLE (FW_TX_FEEDBACK_NONE | 0x1) +#define FW_TX_FEEDBACK_CCX_ENABL (FW_TX_FEEDBACK_NONE | 0x2) +#define FW_BB_RESET_ENABLE 0xff00000d +#define FW_BB_RESET_DISABLE 0xff00000e +#define FW_CCA_CHK_ENABLE 0xff000011 +#define FW_CCK_RESET_CNT 0xff000013 +#define FW_LPS_ENTER 0xfe000010 +#define FW_LPS_LEAVE 0xfe000011 +#define FW_INDIRECT_READ 0xf2000000 +#define FW_INDIRECT_WRITE 0xf2000001 +#define FW_CHAN_SET 0xf3000001 + +#define RFPC 0x5F +#define RCR_9356SEL BIT(6) +#define TCR_LRL_OFFSET 0 +#define TCR_SRL_OFFSET 8 +#define TCR_MXDMA_OFFSET 21 +#define TCR_SAT BIT(24) +#define RCR_MXDMA_OFFSET 8 +#define RCR_FIFO_OFFSET 13 +#define RCR_OnlyErlPkt BIT(31) +#define CWR 0xDC +#define RETRYCTR 0xDE + +#define CPU_GEN_SYSTEM_RESET 0x00000001 + +#define CCX_COMMAND_REG 0x890 +#define CLM_PERIOD_REG 0x894 +#define NHM_PERIOD_REG 0x896 + +#define NHM_THRESHOLD0 0x898 +#define NHM_THRESHOLD1 0x899 +#define NHM_THRESHOLD2 0x89A +#define NHM_THRESHOLD3 0x89B +#define NHM_THRESHOLD4 0x89C +#define NHM_THRESHOLD5 0x89D +#define NHM_THRESHOLD6 0x89E +#define CLM_RESULT_REG 0x8D0 +#define NHM_RESULT_REG 0x8D4 +#define NHM_RPI_COUNTER0 0x8D8 +#define NHM_RPI_COUNTER1 0x8D9 +#define NHM_RPI_COUNTER2 0x8DA +#define NHM_RPI_COUNTER3 0x8DB +#define NHM_RPI_COUNTER4 0x8DC +#define NHM_RPI_COUNTER5 0x8DD +#define NHM_RPI_COUNTER6 0x8DE +#define NHM_RPI_COUNTER7 0x8DF + +#define HAL_8192S_HW_GPIO_OFF_BIT BIT(3) +#define HAL_8192S_HW_GPIO_OFF_MASK 0xF7 +#define HAL_8192S_HW_GPIO_WPS_BIT BIT(4) + +#define RPMAC_RESET 0x100 +#define RPMAC_TXSTART 0x104 +#define RPMAC_TXLEGACYSIG 0x108 +#define RPMAC_TXHTSIG1 0x10c +#define RPMAC_TXHTSIG2 0x110 +#define RPMAC_PHYDEBUG 0x114 +#define RPMAC_TXPACKETNNM 0x118 +#define RPMAC_TXIDLE 0x11c +#define RPMAC_TXMACHEADER0 0x120 +#define RPMAC_TXMACHEADER1 0x124 +#define RPMAC_TXMACHEADER2 0x128 +#define RPMAC_TXMACHEADER3 0x12c +#define RPMAC_TXMACHEADER4 0x130 +#define RPMAC_TXMACHEADER5 0x134 +#define RPMAC_TXDATATYPE 0x138 +#define RPMAC_TXRANDOMSEED 0x13c +#define RPMAC_CCKPLCPPREAMBLE 0x140 +#define RPMAC_CCKPLCPHEADER 0x144 +#define RPMAC_CCKCRC16 0x148 +#define RPMAC_OFDMRXCRC32OK 0x170 +#define RPMAC_OFDMRXCRC32ER 0x174 +#define RPMAC_OFDMRXPARITYER 0x178 +#define RPMAC_OFDMRXCRC8ER 0x17c +#define RPMAC_CCKCRXRC16ER 0x180 +#define RPMAC_CCKCRXRC32ER 0x184 +#define RPMAC_CCKCRXRC32OK 0x188 +#define RPMAC_TXSTATUS 0x18c + +#define RF_BB_CMD_ADDR 0x02c0 +#define RF_BB_CMD_DATA 0x02c4 + +#define RFPGA0_RFMOD 0x800 + +#define RFPGA0_TXINFO 0x804 +#define RFPGA0_PSDFUNCTION 0x808 + +#define RFPGA0_TXGAINSTAGE 0x80c + +#define RFPGA0_RFTIMING1 0x810 +#define RFPGA0_RFTIMING2 0x814 +#define RFPGA0_XA_HSSIPARAMETER1 0x820 +#define RFPGA0_XA_HSSIPARAMETER2 0x824 +#define RFPGA0_XB_HSSIPARAMETER1 0x828 +#define RFPGA0_XB_HSSIPARAMETER2 0x82c +#define RFPGA0_XC_HSSIPARAMETER1 0x830 +#define RFPGA0_XC_HSSIPARAMETER2 0x834 +#define RFPGA0_XD_HSSIPARAMETER1 0x838 +#define RFPGA0_XD_HSSIPARAMETER2 0x83c +#define RFPGA0_XA_LSSIPARAMETER 0x840 +#define RFPGA0_XB_LSSIPARAMETER 0x844 +#define RFPGA0_XC_LSSIPARAMETER 0x848 +#define RFPGA0_XD_LSSIPARAMETER 0x84c + +#define RFPGA0_RFWAKEUP_PARAMETER 0x850 +#define RFPGA0_RFSLEEPUP_PARAMETER 0x854 + +#define RFPGA0_XAB_SWITCHCONTROL 0x858 +#define RFPGA0_XCD_SWITCHCONTROL 0x85c + +#define RFPGA0_XA_RFINTERFACEOE 0x860 +#define RFPGA0_XB_RFINTERFACEOE 0x864 +#define RFPGA0_XC_RFINTERFACEOE 0x868 +#define RFPGA0_XD_RFINTERFACEOE 0x86c + +#define RFPGA0_XAB_RFINTERFACESW 0x870 +#define RFPGA0_XCD_RFINTERFACESW 0x874 + +#define RFPGA0_XAB_RFPARAMETER 0x878 +#define RFPGA0_XCD_RFPARAMETER 0x87c + +#define RFPGA0_ANALOGPARAMETER1 0x880 +#define RFPGA0_ANALOGPARAMETER2 0x884 +#define RFPGA0_ANALOGPARAMETER3 0x888 +#define RFPGA0_ANALOGPARAMETER4 0x88c + +#define RFPGA0_XA_LSSIREADBACK 0x8a0 +#define RFPGA0_XB_LSSIREADBACK 0x8a4 +#define RFPGA0_XC_LSSIREADBACK 0x8a8 +#define RFPGA0_XD_LSSIREADBACK 0x8ac + +#define RFPGA0_PSDREPORT 0x8b4 +#define TRANSCEIVERA_HSPI_READBACK 0x8b8 +#define TRANSCEIVERB_HSPI_READBACK 0x8bc +#define RFPGA0_XAB_RFINTERFACERB 0x8e0 +#define RFPGA0_XCD_RFINTERFACERB 0x8e4 +#define RFPGA1_RFMOD 0x900 + +#define RFPGA1_TXBLOCK 0x904 +#define RFPGA1_DEBUGSELECT 0x908 +#define RFPGA1_TXINFO 0x90c + +#define RCCK0_SYSTEM 0xa00 + +#define RCCK0_AFESETTING 0xa04 +#define RCCK0_CCA 0xa08 + +#define RCCK0_RXAGC1 0xa0c +#define RCCK0_RXAGC2 0xa10 + +#define RCCK0_RXHP 0xa14 + +#define RCCK0_DSPPARAMETER1 0xa18 +#define RCCK0_DSPPARAMETER2 0xa1c + +#define RCCK0_TXFILTER1 0xa20 +#define RCCK0_TXFILTER2 0xa24 +#define RCCK0_DEBUGPORT 0xa28 +#define RCCK0_FALSEALARMREPORT 0xa2c +#define RCCK0_TRSSIREPORT 0xa50 +#define RCCK0_RXREPORT 0xa54 +#define RCCK0_FACOUNTERLOWER 0xa5c +#define RCCK0_FACOUNTERUPPER 0xa58 + +#define ROFDM0_LSTF 0xc00 + +#define ROFDM0_TRXPATHENABLE 0xc04 +#define ROFDM0_TRMUXPAR 0xc08 +#define ROFDM0_TRSWISOLATION 0xc0c + +#define ROFDM0_XARXAFE 0xc10 +#define ROFDM0_XARXIQIMBALANCE 0xc14 +#define ROFDM0_XBRXAFE 0xc18 +#define ROFDM0_XBRXIQIMBALANCE 0xc1c +#define ROFDM0_XCRXAFE 0xc20 +#define ROFDM0_XCRXIQIMBALANCE 0xc24 +#define ROFDM0_XDRXAFE 0xc28 +#define ROFDM0_XDRXIQIMBALANCE 0xc2c + +#define ROFDM0_RXDETECTOR1 0xc30 +#define ROFDM0_RXDETECTOR2 0xc34 +#define ROFDM0_RXDETECTOR3 0xc38 +#define ROFDM0_RXDETECTOR4 0xc3c + +#define ROFDM0_RXDSP 0xc40 +#define ROFDM0_CFO_AND_DAGC 0xc44 +#define ROFDM0_CCADROP_THRESHOLD 0xc48 +#define ROFDM0_ECCA_THRESHOLD 0xc4c + +#define ROFDM0_XAAGCCORE1 0xc50 +#define ROFDM0_XAAGCCORE2 0xc54 +#define ROFDM0_XBAGCCORE1 0xc58 +#define ROFDM0_XBAGCCORE2 0xc5c +#define ROFDM0_XCAGCCORE1 0xc60 +#define ROFDM0_XCAGCCORE2 0xc64 +#define ROFDM0_XDAGCCORE1 0xc68 +#define ROFDM0_XDAGCCORE2 0xc6c + +#define ROFDM0_AGCPARAMETER1 0xc70 +#define ROFDM0_AGCPARAMETER2 0xc74 +#define ROFDM0_AGCRSSITABLE 0xc78 +#define ROFDM0_HTSTFAGC 0xc7c + +#define ROFDM0_XATXIQIMBALANCE 0xc80 +#define ROFDM0_XATXAFE 0xc84 +#define ROFDM0_XBTXIQIMBALANCE 0xc88 +#define ROFDM0_XBTXAFE 0xc8c +#define ROFDM0_XCTXIQIMBALANCE 0xc90 +#define ROFDM0_XCTXAFE 0xc94 +#define ROFDM0_XDTXIQIMBALANCE 0xc98 +#define ROFDM0_XDTXAFE 0xc9c + +#define ROFDM0_RXHP_PARAMETER 0xce0 +#define ROFDM0_TXPSEUDO_NOISE_WGT 0xce4 +#define ROFDM0_FRAME_SYNC 0xcf0 +#define ROFDM0_DFSREPORT 0xcf4 +#define ROFDM0_TXCOEFF1 0xca4 +#define ROFDM0_TXCOEFF2 0xca8 +#define ROFDM0_TXCOEFF3 0xcac +#define ROFDM0_TXCOEFF4 0xcb0 +#define ROFDM0_TXCOEFF5 0xcb4 +#define ROFDM0_TXCOEFF6 0xcb8 + + +#define ROFDM1_LSTF 0xd00 +#define ROFDM1_TRXPATHENABLE 0xd04 + +#define ROFDM1_CFO 0xd08 +#define ROFDM1_CSI1 0xd10 +#define ROFDM1_SBD 0xd14 +#define ROFDM1_CSI2 0xd18 +#define ROFDM1_CFOTRACKING 0xd2c +#define ROFDM1_TRXMESAURE1 0xd34 +#define ROFDM1_INTF_DET 0xd3c +#define ROFDM1_PSEUDO_NOISESTATEAB 0xd50 +#define ROFDM1_PSEUDO_NOISESTATECD 0xd54 +#define ROFDM1_RX_PSEUDO_NOISE_WGT 0xd58 + +#define ROFDM_PHYCOUNTER1 0xda0 +#define ROFDM_PHYCOUNTER2 0xda4 +#define ROFDM_PHYCOUNTER3 0xda8 + +#define ROFDM_SHORT_CFOAB 0xdac +#define ROFDM_SHORT_CFOCD 0xdb0 +#define ROFDM_LONG_CFOAB 0xdb4 +#define ROFDM_LONG_CFOCD 0xdb8 +#define ROFDM_TAIL_CFOAB 0xdbc +#define ROFDM_TAIL_CFOCD 0xdc0 +#define ROFDM_PW_MEASURE1 0xdc4 +#define ROFDM_PW_MEASURE2 0xdc8 +#define ROFDM_BW_REPORT 0xdcc +#define ROFDM_AGC_REPORT 0xdd0 +#define ROFDM_RXSNR 0xdd4 +#define ROFDM_RXEVMCSI 0xdd8 +#define ROFDM_SIG_REPORT 0xddc + + +#define RTXAGC_RATE18_06 0xe00 +#define RTXAGC_RATE54_24 0xe04 +#define RTXAGC_CCK_MCS32 0xe08 +#define RTXAGC_MCS03_MCS00 0xe10 +#define RTXAGC_MCS07_MCS04 0xe14 +#define RTXAGC_MCS11_MCS08 0xe18 +#define RTXAGC_MCS15_MCS12 0xe1c + + +#define RF_AC 0x00 +#define RF_IQADJ_G1 0x01 +#define RF_IQADJ_G2 0x02 +#define RF_POW_TRSW 0x05 +#define RF_GAIN_RX 0x06 +#define RF_GAIN_TX 0x07 +#define RF_TXM_IDAC 0x08 +#define RF_BS_IQGEN 0x0F + +#define RF_MODE1 0x10 +#define RF_MODE2 0x11 +#define RF_RX_AGC_HP 0x12 +#define RF_TX_AGC 0x13 +#define RF_BIAS 0x14 +#define RF_IPA 0x15 +#define RF_POW_ABILITY 0x17 +#define RF_MODE_AG 0x18 +#define RF_CHANNEL 0x18 +#define RF_CHNLBW 0x18 +#define RF_TOP 0x19 +#define RF_RX_G1 0x1A +#define RF_RX_G2 0x1B +#define RF_RX_BB2 0x1C +#define RF_RX_BB1 0x1D +#define RF_RCK1 0x1E +#define RF_RCK2 0x1F + +#define RF_TX_G1 0x20 +#define RF_TX_G2 0x21 +#define RF_TX_G3 0x22 +#define RF_TX_BB1 0x23 +#define RF_T_METER 0x24 +#define RF_SYN_G1 0x25 +#define RF_SYN_G2 0x26 +#define RF_SYN_G3 0x27 +#define RF_SYN_G4 0x28 +#define RF_SYN_G5 0x29 +#define RF_SYN_G6 0x2A +#define RF_SYN_G7 0x2B +#define RF_SYN_G8 0x2C + +#define RF_RCK_OS 0x30 +#define RF_TXPA_G1 0x31 +#define RF_TXPA_G2 0x32 +#define RF_TXPA_G3 0x33 + +#define BRFMOD 0x1 +#define BCCKEN 0x1000000 +#define BOFDMEN 0x2000000 + +#define BXBTXAGC 0xf00 +#define BXCTXAGC 0xf000 +#define BXDTXAGC 0xf0000 + +#define B3WIRE_DATALENGTH 0x800 +#define B3WIRE_ADDRESSLENGTH 0x400 + +#define BRFSI_RFENV 0x10 + +#define BLSSI_READADDRESS 0x7f800000 +#define BLSSI_READEDGE 0x80000000 +#define BLSSI_READBACK_DATA 0xfffff + +#define BADCLKPHASE 0x4000000 + +#define BCCK_SIDEBAND 0x10 + +#define BTX_AGCRATECCK 0x7f00 + +#define MASKBYTE0 0xff +#define MASKBYTE1 0xff00 +#define MASKBYTE2 0xff0000 +#define MASKBYTE3 0xff000000 +#define MASKHWORD 0xffff0000 +#define MASKLWORD 0x0000ffff +#define MASKDWORD 0xffffffff + +#define MAKS12BITS 0xfffff +#define MASK20BITS 0xfffff +#define RFREG_OFFSET_MASK 0xfffff + +#endif -- cgit v0.10.2 From e5e8cd76511cb62391a5b64fa4ffdf88b09b6826 Mon Sep 17 00:00:00 2001 From: Chaoming Li Date: Tue, 3 May 2011 09:48:56 -0500 Subject: rtlwifi: rtl8192se: Merge rf routines Merge routines rf.c and rf.h for RTL8192SE. Signed-off-by: Chaoming_Li Signed-off-by: Larry Finger Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/rtlwifi/rtl8192se/rf.c b/drivers/net/wireless/rtlwifi/rtl8192se/rf.c new file mode 100644 index 0000000..1d3a483 --- /dev/null +++ b/drivers/net/wireless/rtlwifi/rtl8192se/rf.c @@ -0,0 +1,546 @@ +/****************************************************************************** + * + * Copyright(c) 2009-2010 Realtek Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger + * + *****************************************************************************/ + +#include "../wifi.h" +#include "reg.h" +#include "def.h" +#include "phy.h" +#include "rf.h" +#include "dm.h" + + +static void _rtl92s_get_powerbase(struct ieee80211_hw *hw, u8 *p_pwrlevel, + u8 chnl, u32 *ofdmbase, u32 *mcsbase, + u8 *p_final_pwridx) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_phy *rtlphy = &(rtlpriv->phy); + struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw)); + u32 pwrbase0, pwrbase1; + u8 legacy_pwrdiff = 0, ht20_pwrdiff = 0; + u8 i, pwrlevel[4]; + + for (i = 0; i < 2; i++) + pwrlevel[i] = p_pwrlevel[i]; + + /* We only care about the path A for legacy. */ + if (rtlefuse->eeprom_version < 2) { + pwrbase0 = pwrlevel[0] + (rtlefuse->legacy_httxpowerdiff & 0xf); + } else if (rtlefuse->eeprom_version >= 2) { + legacy_pwrdiff = rtlefuse->txpwr_legacyhtdiff + [RF90_PATH_A][chnl - 1]; + + /* For legacy OFDM, tx pwr always > HT OFDM pwr. + * We do not care Path B + * legacy OFDM pwr diff. NO BB register + * to notify HW. */ + pwrbase0 = pwrlevel[0] + legacy_pwrdiff; + } + + pwrbase0 = (pwrbase0 << 24) | (pwrbase0 << 16) | (pwrbase0 << 8) | + pwrbase0; + *ofdmbase = pwrbase0; + + /* MCS rates */ + if (rtlefuse->eeprom_version >= 2) { + /* Check HT20 to HT40 diff */ + if (rtlphy->current_chan_bw == HT_CHANNEL_WIDTH_20) { + for (i = 0; i < 2; i++) { + /* rf-A, rf-B */ + /* HT 20<->40 pwr diff */ + ht20_pwrdiff = rtlefuse->txpwr_ht20diff + [i][chnl - 1]; + + if (ht20_pwrdiff < 8) /* 0~+7 */ + pwrlevel[i] += ht20_pwrdiff; + else /* index8-15=-8~-1 */ + pwrlevel[i] -= (16 - ht20_pwrdiff); + } + } + } + + /* use index of rf-A */ + pwrbase1 = pwrlevel[0]; + pwrbase1 = (pwrbase1 << 24) | (pwrbase1 << 16) | (pwrbase1 << 8) | + pwrbase1; + *mcsbase = pwrbase1; + + /* The following is for Antenna + * diff from Ant-B to Ant-A */ + p_final_pwridx[0] = pwrlevel[0]; + p_final_pwridx[1] = pwrlevel[1]; + + switch (rtlefuse->eeprom_regulatory) { + case 3: + /* The following is for calculation + * of the power diff for Ant-B to Ant-A. */ + if (rtlphy->current_chan_bw == HT_CHANNEL_WIDTH_20_40) { + p_final_pwridx[0] += rtlefuse->pwrgroup_ht40 + [RF90_PATH_A][ + chnl - 1]; + p_final_pwridx[1] += rtlefuse->pwrgroup_ht40 + [RF90_PATH_B][ + chnl - 1]; + } else { + p_final_pwridx[0] += rtlefuse->pwrgroup_ht20 + [RF90_PATH_A][ + chnl - 1]; + p_final_pwridx[1] += rtlefuse->pwrgroup_ht20 + [RF90_PATH_B][ + chnl - 1]; + } + break; + default: + break; + } + + if (rtlphy->current_chan_bw == HT_CHANNEL_WIDTH_20_40) { + RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD, ("40MHz finalpwr_idx " + "(A / B) = 0x%x / 0x%x\n", p_final_pwridx[0], + p_final_pwridx[1])); + } else { + RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD, ("20MHz finalpwr_idx " + "(A / B) = 0x%x / 0x%x\n", p_final_pwridx[0], + p_final_pwridx[1])); + } +} + +static void _rtl92s_set_antennadiff(struct ieee80211_hw *hw, + u8 *p_final_pwridx) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw)); + struct rtl_phy *rtlphy = &(rtlpriv->phy); + char ant_pwr_diff = 0; + u32 u4reg_val = 0; + + if (rtlphy->rf_type == RF_2T2R) { + ant_pwr_diff = p_final_pwridx[1] - p_final_pwridx[0]; + + /* range is from 7~-8, + * index = 0x0~0xf */ + if (ant_pwr_diff > 7) + ant_pwr_diff = 7; + if (ant_pwr_diff < -8) + ant_pwr_diff = -8; + + RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD, + ("Antenna Diff from RF-B " + "to RF-A = %d (0x%x)\n", ant_pwr_diff, + ant_pwr_diff & 0xf)); + + ant_pwr_diff &= 0xf; + } + + /* Antenna TX power difference */ + rtlefuse->antenna_txpwdiff[2] = 0;/* RF-D, don't care */ + rtlefuse->antenna_txpwdiff[1] = 0;/* RF-C, don't care */ + rtlefuse->antenna_txpwdiff[0] = (u8)(ant_pwr_diff); /* RF-B */ + + u4reg_val = rtlefuse->antenna_txpwdiff[2] << 8 | + rtlefuse->antenna_txpwdiff[1] << 4 | + rtlefuse->antenna_txpwdiff[0]; + + rtl_set_bbreg(hw, RFPGA0_TXGAINSTAGE, (BXBTXAGC | BXCTXAGC | BXDTXAGC), + u4reg_val); + + RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD, + ("Write BCD-Diff(0x%x) = 0x%x\n", + RFPGA0_TXGAINSTAGE, u4reg_val)); +} + +static void _rtl92s_get_txpower_writeval_byregulatory(struct ieee80211_hw *hw, + u8 chnl, u8 index, + u32 pwrbase0, + u32 pwrbase1, + u32 *p_outwrite_val) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_phy *rtlphy = &(rtlpriv->phy); + struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw)); + u8 i, chnlgroup, pwrdiff_limit[4]; + u32 writeval, customer_limit; + + /* Index 0 & 1= legacy OFDM, 2-5=HT_MCS rate */ + switch (rtlefuse->eeprom_regulatory) { + case 0: + /* Realtek better performance increase power diff + * defined by Realtek for large power */ + chnlgroup = 0; + + writeval = rtlphy->mcs_txpwrlevel_origoffset + [chnlgroup][index] + + ((index < 2) ? pwrbase0 : pwrbase1); + + RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD, + ("RTK better performance, " + "writeval = 0x%x\n", writeval)); + break; + case 1: + /* Realtek regulatory increase power diff defined + * by Realtek for regulatory */ + if (rtlphy->current_chan_bw == HT_CHANNEL_WIDTH_20_40) { + writeval = ((index < 2) ? pwrbase0 : pwrbase1); + + RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD, + ("Realtek regulatory, " + "40MHz, writeval = 0x%x\n", writeval)); + } else { + if (rtlphy->pwrgroup_cnt == 1) + chnlgroup = 0; + + if (rtlphy->pwrgroup_cnt >= 3) { + if (chnl <= 3) + chnlgroup = 0; + else if (chnl >= 4 && chnl <= 8) + chnlgroup = 1; + else if (chnl > 8) + chnlgroup = 2; + if (rtlphy->pwrgroup_cnt == 4) + chnlgroup++; + } + + writeval = rtlphy->mcs_txpwrlevel_origoffset + [chnlgroup][index] + + ((index < 2) ? + pwrbase0 : pwrbase1); + + RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD, + ("Realtek regulatory, " + "20MHz, writeval = 0x%x\n", writeval)); + } + break; + case 2: + /* Better regulatory don't increase any power diff */ + writeval = ((index < 2) ? pwrbase0 : pwrbase1); + RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD, + ("Better regulatory, " + "writeval = 0x%x\n", writeval)); + break; + case 3: + /* Customer defined power diff. increase power diff + defined by customer. */ + chnlgroup = 0; + + if (rtlphy->current_chan_bw == HT_CHANNEL_WIDTH_20_40) { + RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD, + ("customer's limit, 40MHz = 0x%x\n", + rtlefuse->pwrgroup_ht40 + [RF90_PATH_A][chnl - 1])); + } else { + RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD, + ("customer's limit, 20MHz = 0x%x\n", + rtlefuse->pwrgroup_ht20 + [RF90_PATH_A][chnl - 1])); + } + + for (i = 0; i < 4; i++) { + pwrdiff_limit[i] = + (u8)((rtlphy->mcs_txpwrlevel_origoffset + [chnlgroup][index] & (0x7f << (i * 8))) + >> (i * 8)); + + if (rtlphy->current_chan_bw == + HT_CHANNEL_WIDTH_20_40) { + if (pwrdiff_limit[i] > + rtlefuse->pwrgroup_ht40 + [RF90_PATH_A][chnl - 1]) { + pwrdiff_limit[i] = + rtlefuse->pwrgroup_ht20 + [RF90_PATH_A][chnl - 1]; + } + } else { + if (pwrdiff_limit[i] > + rtlefuse->pwrgroup_ht20 + [RF90_PATH_A][chnl - 1]) { + pwrdiff_limit[i] = + rtlefuse->pwrgroup_ht20 + [RF90_PATH_A][chnl - 1]; + } + } + } + + customer_limit = (pwrdiff_limit[3] << 24) | + (pwrdiff_limit[2] << 16) | + (pwrdiff_limit[1] << 8) | + (pwrdiff_limit[0]); + RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD, + ("Customer's limit = 0x%x\n", + customer_limit)); + + writeval = customer_limit + ((index < 2) ? + pwrbase0 : pwrbase1); + RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD, + ("Customer, writeval = " + "0x%x\n", writeval)); + break; + default: + chnlgroup = 0; + writeval = rtlphy->mcs_txpwrlevel_origoffset[chnlgroup][index] + + ((index < 2) ? pwrbase0 : pwrbase1); + RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD, + ("RTK better performance, " + "writeval = 0x%x\n", writeval)); + break; + } + + if (rtlpriv->dm.dynamic_txhighpower_lvl == TX_HIGH_PWR_LEVEL_LEVEL1) + writeval = 0x10101010; + else if (rtlpriv->dm.dynamic_txhighpower_lvl == + TX_HIGH_PWR_LEVEL_LEVEL2) + writeval = 0x0; + + *p_outwrite_val = writeval; + +} + +static void _rtl92s_write_ofdm_powerreg(struct ieee80211_hw *hw, + u8 index, u32 val) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_phy *rtlphy = &(rtlpriv->phy); + struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw)); + u16 regoffset[6] = {0xe00, 0xe04, 0xe10, 0xe14, 0xe18, 0xe1c}; + u8 i, rfa_pwr[4]; + u8 rfa_lower_bound = 0, rfa_upper_bound = 0, rf_pwr_diff = 0; + u32 writeval = val; + + /* If path A and Path B coexist, we must limit Path A tx power. + * Protect Path B pwr over or under flow. We need to calculate + * upper and lower bound of path A tx power. */ + if (rtlphy->rf_type == RF_2T2R) { + rf_pwr_diff = rtlefuse->antenna_txpwdiff[0]; + + /* Diff=-8~-1 */ + if (rf_pwr_diff >= 8) { + /* Prevent underflow!! */ + rfa_lower_bound = 0x10 - rf_pwr_diff; + /* if (rf_pwr_diff >= 0) Diff = 0-7 */ + } else { + rfa_upper_bound = RF6052_MAX_TX_PWR - rf_pwr_diff; + } + } + + for (i = 0; i < 4; i++) { + rfa_pwr[i] = (u8)((writeval & (0x7f << (i * 8))) >> (i * 8)); + if (rfa_pwr[i] > RF6052_MAX_TX_PWR) + rfa_pwr[i] = RF6052_MAX_TX_PWR; + + /* If path A and Path B coexist, we must limit Path A tx power. + * Protect Path B pwr over or under flow. We need to calculate + * upper and lower bound of path A tx power. */ + if (rtlphy->rf_type == RF_2T2R) { + /* Diff=-8~-1 */ + if (rf_pwr_diff >= 8) { + /* Prevent underflow!! */ + if (rfa_pwr[i] < rfa_lower_bound) + rfa_pwr[i] = rfa_lower_bound; + /* Diff = 0-7 */ + } else if (rf_pwr_diff >= 1) { + /* Prevent overflow */ + if (rfa_pwr[i] > rfa_upper_bound) + rfa_pwr[i] = rfa_upper_bound; + } + } + + } + + writeval = (rfa_pwr[3] << 24) | (rfa_pwr[2] << 16) | (rfa_pwr[1] << 8) | + rfa_pwr[0]; + + rtl_set_bbreg(hw, regoffset[index], 0x7f7f7f7f, writeval); +} + +void rtl92s_phy_rf6052_set_ofdmtxpower(struct ieee80211_hw *hw, + u8 *p_pwrlevel, u8 chnl) +{ + u32 writeval, pwrbase0, pwrbase1; + u8 index = 0; + u8 finalpwr_idx[4]; + + _rtl92s_get_powerbase(hw, p_pwrlevel, chnl, &pwrbase0, &pwrbase1, + &finalpwr_idx[0]); + _rtl92s_set_antennadiff(hw, &finalpwr_idx[0]); + + for (index = 0; index < 6; index++) { + _rtl92s_get_txpower_writeval_byregulatory(hw, chnl, index, + pwrbase0, pwrbase1, &writeval); + + _rtl92s_write_ofdm_powerreg(hw, index, writeval); + } +} + +void rtl92s_phy_rf6052_set_ccktxpower(struct ieee80211_hw *hw, u8 pwrlevel) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); + struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw)); + u32 txagc = 0; + bool dont_inc_cck_or_turboscanoff = false; + + if (((rtlefuse->eeprom_version >= 2) && + (rtlefuse->txpwr_safetyflag == 1)) || + ((rtlefuse->eeprom_version >= 2) && + (rtlefuse->eeprom_regulatory != 0))) + dont_inc_cck_or_turboscanoff = true; + + if (mac->act_scanning == true) { + txagc = 0x3f; + if (dont_inc_cck_or_turboscanoff) + txagc = pwrlevel; + } else { + txagc = pwrlevel; + + if (rtlpriv->dm.dynamic_txhighpower_lvl == + TX_HIGH_PWR_LEVEL_LEVEL1) + txagc = 0x10; + else if (rtlpriv->dm.dynamic_txhighpower_lvl == + TX_HIGH_PWR_LEVEL_LEVEL2) + txagc = 0x0; + } + + if (txagc > RF6052_MAX_TX_PWR) + txagc = RF6052_MAX_TX_PWR; + + rtl_set_bbreg(hw, RTXAGC_CCK_MCS32, BTX_AGCRATECCK, txagc); + +} + +bool rtl92s_phy_rf6052_config(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_phy *rtlphy = &(rtlpriv->phy); + u32 u4reg_val = 0; + u8 rfpath; + bool rtstatus = true; + struct bb_reg_def *pphyreg; + + /* Initialize RF */ + for (rfpath = 0; rfpath < rtlphy->num_total_rfpath; rfpath++) { + + pphyreg = &rtlphy->phyreg_def[rfpath]; + + /* Store original RFENV control type */ + switch (rfpath) { + case RF90_PATH_A: + case RF90_PATH_C: + u4reg_val = rtl92s_phy_query_bb_reg(hw, + pphyreg->rfintfs, + BRFSI_RFENV); + break; + case RF90_PATH_B: + case RF90_PATH_D: + u4reg_val = rtl92s_phy_query_bb_reg(hw, + pphyreg->rfintfs, + BRFSI_RFENV << 16); + break; + } + + /* Set RF_ENV enable */ + rtl92s_phy_set_bb_reg(hw, pphyreg->rfintfe, + BRFSI_RFENV << 16, 0x1); + + /* Set RF_ENV output high */ + rtl92s_phy_set_bb_reg(hw, pphyreg->rfintfo, BRFSI_RFENV, 0x1); + + /* Set bit number of Address and Data for RF register */ + rtl92s_phy_set_bb_reg(hw, pphyreg->rfhssi_para2, + B3WIRE_ADDRESSLENGTH, 0x0); + rtl92s_phy_set_bb_reg(hw, pphyreg->rfhssi_para2, + B3WIRE_DATALENGTH, 0x0); + + /* Initialize RF fom connfiguration file */ + switch (rfpath) { + case RF90_PATH_A: + rtstatus = rtl92s_phy_config_rf(hw, + (enum radio_path)rfpath); + break; + case RF90_PATH_B: + rtstatus = rtl92s_phy_config_rf(hw, + (enum radio_path)rfpath); + break; + case RF90_PATH_C: + break; + case RF90_PATH_D: + break; + } + + /* Restore RFENV control type */ + switch (rfpath) { + case RF90_PATH_A: + case RF90_PATH_C: + rtl92s_phy_set_bb_reg(hw, pphyreg->rfintfs, BRFSI_RFENV, + u4reg_val); + break; + case RF90_PATH_B: + case RF90_PATH_D: + rtl92s_phy_set_bb_reg(hw, pphyreg->rfintfs, + BRFSI_RFENV << 16, + u4reg_val); + break; + } + + if (rtstatus != true) { + printk(KERN_ERR "Radio[%d] Fail!!", rfpath); + goto fail; + } + + } + + return rtstatus; + +fail: + return rtstatus; +} + +void rtl92s_phy_rf6052_set_bandwidth(struct ieee80211_hw *hw, u8 bandwidth) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_phy *rtlphy = &(rtlpriv->phy); + + switch (bandwidth) { + case HT_CHANNEL_WIDTH_20: + rtlphy->rfreg_chnlval[0] = ((rtlphy->rfreg_chnlval[0] & + 0xfffff3ff) | 0x0400); + rtl_set_rfreg(hw, RF90_PATH_A, RF_CHNLBW, RFREG_OFFSET_MASK, + rtlphy->rfreg_chnlval[0]); + break; + case HT_CHANNEL_WIDTH_20_40: + rtlphy->rfreg_chnlval[0] = ((rtlphy->rfreg_chnlval[0] & + 0xfffff3ff)); + rtl_set_rfreg(hw, RF90_PATH_A, RF_CHNLBW, RFREG_OFFSET_MASK, + rtlphy->rfreg_chnlval[0]); + break; + default: + RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, + ("unknown bandwidth: %#X\n", + bandwidth)); + break; + } +} diff --git a/drivers/net/wireless/rtlwifi/rtl8192se/rf.h b/drivers/net/wireless/rtlwifi/rtl8192se/rf.h new file mode 100644 index 0000000..3843baa --- /dev/null +++ b/drivers/net/wireless/rtlwifi/rtl8192se/rf.h @@ -0,0 +1,43 @@ +/****************************************************************************** + * + * Copyright(c) 2009-2010 Realtek Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger + * + *****************************************************************************/ +#ifndef __INC_RTL92S_RF_H +#define __INC_RTL92S_RF_H + +#define RF6052_MAX_TX_PWR 0x3F + +void rtl92s_phy_rf6052_set_bandwidth(struct ieee80211_hw *hw, + u8 bandwidth); +bool rtl92s_phy_rf6052_config(struct ieee80211_hw *hw) ; +void rtl92s_phy_rf6052_set_ccktxpower(struct ieee80211_hw *hw, + u8 powerlevel); +void rtl92s_phy_rf6052_set_ofdmtxpower(struct ieee80211_hw *hw, + u8 *p_pwrlevel, u8 chnl); + +#endif + -- cgit v0.10.2 From 5a183eec6247d3d992afbd3a1a9658571d9c4970 Mon Sep 17 00:00:00 2001 From: Chaoming Li Date: Tue, 3 May 2011 09:49:06 -0500 Subject: rtlwifi: rtl8192se: Merge main (sw) routines Merge routines sw.c and sw.h for RTL8192SE. Signed-off-by: Chaoming_Li Signed-off-by: Larry Finger Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/rtlwifi/rtl8192se/sw.c b/drivers/net/wireless/rtlwifi/rtl8192se/sw.c new file mode 100644 index 0000000..c5351b6 --- /dev/null +++ b/drivers/net/wireless/rtlwifi/rtl8192se/sw.c @@ -0,0 +1,421 @@ +/****************************************************************************** + * + * Copyright(c) 2009-2010 Realtek Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger + * + *****************************************************************************/ + +#include + +#include "../wifi.h" +#include "../core.h" +#include "../pci.h" +#include "reg.h" +#include "def.h" +#include "phy.h" +#include "dm.h" +#include "fw.h" +#include "hw.h" +#include "sw.h" +#include "trx.h" +#include "led.h" + +static void rtl92s_init_aspm_vars(struct ieee80211_hw *hw) +{ + struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); + + /*close ASPM for AMD defaultly */ + rtlpci->const_amdpci_aspm = 0; + + /* + * ASPM PS mode. + * 0 - Disable ASPM, + * 1 - Enable ASPM without Clock Req, + * 2 - Enable ASPM with Clock Req, + * 3 - Alwyas Enable ASPM with Clock Req, + * 4 - Always Enable ASPM without Clock Req. + * set defult to RTL8192CE:3 RTL8192E:2 + * */ + rtlpci->const_pci_aspm = 2; + + /*Setting for PCI-E device */ + rtlpci->const_devicepci_aspm_setting = 0x03; + + /*Setting for PCI-E bridge */ + rtlpci->const_hostpci_aspm_setting = 0x02; + + /* + * In Hw/Sw Radio Off situation. + * 0 - Default, + * 1 - From ASPM setting without low Mac Pwr, + * 2 - From ASPM setting with low Mac Pwr, + * 3 - Bus D3 + * set default to RTL8192CE:0 RTL8192SE:2 + */ + rtlpci->const_hwsw_rfoff_d3 = 2; + + /* + * This setting works for those device with + * backdoor ASPM setting such as EPHY setting. + * 0 - Not support ASPM, + * 1 - Support ASPM, + * 2 - According to chipset. + */ + rtlpci->const_support_pciaspm = 2; +} + +static int rtl92s_init_sw_vars(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); + const struct firmware *firmware; + struct rt_firmware *pfirmware = NULL; + int err = 0; + u16 earlyrxthreshold = 7; + + rtlpriv->dm.dm_initialgain_enable = 1; + rtlpriv->dm.dm_flag = 0; + rtlpriv->dm.disable_framebursting = 0; + rtlpriv->dm.thermalvalue = 0; + rtlpriv->dm.useramask = true; + + /* compatible 5G band 91se just 2.4G band & smsp */ + rtlpriv->rtlhal.current_bandtype = BAND_ON_2_4G; + rtlpriv->rtlhal.bandset = BAND_ON_2_4G; + rtlpriv->rtlhal.macphymode = SINGLEMAC_SINGLEPHY; + + rtlpci->transmit_config = 0; + + rtlpci->receive_config = + RCR_APPFCS | + RCR_APWRMGT | + /*RCR_ADD3 |*/ + RCR_AMF | + RCR_ADF | + RCR_APP_MIC | + RCR_APP_ICV | + RCR_AICV | + /* Accept ICV error, CRC32 Error */ + RCR_ACRC32 | + RCR_AB | + /* Accept Broadcast, Multicast */ + RCR_AM | + /* Accept Physical match */ + RCR_APM | + /* Accept Destination Address packets */ + /*RCR_AAP |*/ + RCR_APP_PHYST_STAFF | + /* Accept PHY status */ + RCR_APP_PHYST_RXFF | + (earlyrxthreshold << RCR_FIFO_OFFSET); + + rtlpci->irq_mask[0] = (u32) + (IMR_ROK | + IMR_VODOK | + IMR_VIDOK | + IMR_BEDOK | + IMR_BKDOK | + IMR_HCCADOK | + IMR_MGNTDOK | + IMR_COMDOK | + IMR_HIGHDOK | + IMR_BDOK | + IMR_RXCMDOK | + /*IMR_TIMEOUT0 |*/ + IMR_RDU | + IMR_RXFOVW | + IMR_BCNINT + /*| IMR_TXFOVW*/ + /*| IMR_TBDOK | + IMR_TBDER*/); + + rtlpci->irq_mask[1] = (u32) 0; + + rtlpci->shortretry_limit = 0x30; + rtlpci->longretry_limit = 0x30; + + rtlpci->first_init = true; + + /* for LPS & IPS */ + rtlpriv->psc.inactiveps = rtlpriv->cfg->mod_params->inactiveps; + rtlpriv->psc.swctrl_lps = rtlpriv->cfg->mod_params->swctrl_lps; + rtlpriv->psc.fwctrl_lps = rtlpriv->cfg->mod_params->fwctrl_lps; + rtlpriv->psc.reg_fwctrl_lps = 3; + rtlpriv->psc.reg_max_lps_awakeintvl = 5; + /* for ASPM, you can close aspm through + * set const_support_pciaspm = 0 */ + rtl92s_init_aspm_vars(hw); + + if (rtlpriv->psc.reg_fwctrl_lps == 1) + rtlpriv->psc.fwctrl_psmode = FW_PS_MIN_MODE; + else if (rtlpriv->psc.reg_fwctrl_lps == 2) + rtlpriv->psc.fwctrl_psmode = FW_PS_MAX_MODE; + else if (rtlpriv->psc.reg_fwctrl_lps == 3) + rtlpriv->psc.fwctrl_psmode = FW_PS_DTIM_MODE; + + /* for firmware buf */ + rtlpriv->rtlhal.pfirmware = vzalloc(sizeof(struct rt_firmware)); + if (!rtlpriv->rtlhal.pfirmware) { + RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, + ("Can't alloc buffer for fw.\n")); + return 1; + } + + /* request fw */ + err = request_firmware(&firmware, rtlpriv->cfg->fw_name, + rtlpriv->io.dev); + if (err) { + RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, + ("Failed to request firmware!\n")); + return 1; + } + if (firmware->size > sizeof(struct rt_firmware)) { + RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, + ("Firmware is too big!\n")); + release_firmware(firmware); + return 1; + } + + pfirmware = (struct rt_firmware *)rtlpriv->rtlhal.pfirmware; + memcpy(pfirmware->sz_fw_tmpbuffer, firmware->data, firmware->size); + pfirmware->sz_fw_tmpbufferlen = firmware->size; + release_firmware(firmware); + + return err; +} + +static void rtl92s_deinit_sw_vars(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + + if (rtlpriv->rtlhal.pfirmware) { + vfree(rtlpriv->rtlhal.pfirmware); + rtlpriv->rtlhal.pfirmware = NULL; + } +} + +static struct rtl_hal_ops rtl8192se_hal_ops = { + .init_sw_vars = rtl92s_init_sw_vars, + .deinit_sw_vars = rtl92s_deinit_sw_vars, + .read_eeprom_info = rtl92se_read_eeprom_info, + .interrupt_recognized = rtl92se_interrupt_recognized, + .hw_init = rtl92se_hw_init, + .hw_disable = rtl92se_card_disable, + .hw_suspend = rtl92se_suspend, + .hw_resume = rtl92se_resume, + .enable_interrupt = rtl92se_enable_interrupt, + .disable_interrupt = rtl92se_disable_interrupt, + .set_network_type = rtl92se_set_network_type, + .set_chk_bssid = rtl92se_set_check_bssid, + .set_qos = rtl92se_set_qos, + .set_bcn_reg = rtl92se_set_beacon_related_registers, + .set_bcn_intv = rtl92se_set_beacon_interval, + .update_interrupt_mask = rtl92se_update_interrupt_mask, + .get_hw_reg = rtl92se_get_hw_reg, + .set_hw_reg = rtl92se_set_hw_reg, + .update_rate_tbl = rtl92se_update_hal_rate_tbl, + .fill_tx_desc = rtl92se_tx_fill_desc, + .fill_tx_cmddesc = rtl92se_tx_fill_cmddesc, + .query_rx_desc = rtl92se_rx_query_desc, + .set_channel_access = rtl92se_update_channel_access_setting, + .radio_onoff_checking = rtl92se_gpio_radio_on_off_checking, + .set_bw_mode = rtl92s_phy_set_bw_mode, + .switch_channel = rtl92s_phy_sw_chnl, + .dm_watchdog = rtl92s_dm_watchdog, + .scan_operation_backup = rtl92s_phy_scan_operation_backup, + .set_rf_power_state = rtl92s_phy_set_rf_power_state, + .led_control = rtl92se_led_control, + .set_desc = rtl92se_set_desc, + .get_desc = rtl92se_get_desc, + .tx_polling = rtl92se_tx_polling, + .enable_hw_sec = rtl92se_enable_hw_security_config, + .set_key = rtl92se_set_key, + .init_sw_leds = rtl92se_init_sw_leds, + .get_bbreg = rtl92s_phy_query_bb_reg, + .set_bbreg = rtl92s_phy_set_bb_reg, + .get_rfreg = rtl92s_phy_query_rf_reg, + .set_rfreg = rtl92s_phy_set_rf_reg, +}; + +static struct rtl_mod_params rtl92se_mod_params = { + .sw_crypto = false, + .inactiveps = true, + .swctrl_lps = true, + .fwctrl_lps = false, +}; + +/* Because memory R/W bursting will cause system hang/crash + * for 92se, so we don't read back after every write action */ +static struct rtl_hal_cfg rtl92se_hal_cfg = { + .bar_id = 1, + .write_readback = false, + .name = "rtl92s_pci", + .fw_name = "rtlwifi/rtl8192sefw.bin", + .ops = &rtl8192se_hal_ops, + .mod_params = &rtl92se_mod_params, + + .maps[SYS_ISO_CTRL] = REG_SYS_ISO_CTRL, + .maps[SYS_FUNC_EN] = REG_SYS_FUNC_EN, + .maps[SYS_CLK] = SYS_CLKR, + .maps[MAC_RCR_AM] = RCR_AM, + .maps[MAC_RCR_AB] = RCR_AB, + .maps[MAC_RCR_ACRC32] = RCR_ACRC32, + .maps[MAC_RCR_ACF] = RCR_ACF, + .maps[MAC_RCR_AAP] = RCR_AAP, + + .maps[EFUSE_TEST] = REG_EFUSE_TEST, + .maps[EFUSE_CTRL] = REG_EFUSE_CTRL, + .maps[EFUSE_CLK] = REG_EFUSE_CLK, + .maps[EFUSE_CLK_CTRL] = REG_EFUSE_CTRL, + .maps[EFUSE_PWC_EV12V] = 0, /* nouse for 8192se */ + .maps[EFUSE_FEN_ELDR] = 0, /* nouse for 8192se */ + .maps[EFUSE_LOADER_CLK_EN] = 0,/* nouse for 8192se */ + .maps[EFUSE_ANA8M] = EFUSE_ANA8M, + .maps[EFUSE_HWSET_MAX_SIZE] = HWSET_MAX_SIZE_92S, + .maps[EFUSE_MAX_SECTION_MAP] = EFUSE_MAX_SECTION, + .maps[EFUSE_REAL_CONTENT_SIZE] = EFUSE_REAL_CONTENT_LEN, + + .maps[RWCAM] = REG_RWCAM, + .maps[WCAMI] = REG_WCAMI, + .maps[RCAMO] = REG_RCAMO, + .maps[CAMDBG] = REG_CAMDBG, + .maps[SECR] = REG_SECR, + .maps[SEC_CAM_NONE] = CAM_NONE, + .maps[SEC_CAM_WEP40] = CAM_WEP40, + .maps[SEC_CAM_TKIP] = CAM_TKIP, + .maps[SEC_CAM_AES] = CAM_AES, + .maps[SEC_CAM_WEP104] = CAM_WEP104, + + .maps[RTL_IMR_BCNDMAINT6] = IMR_BCNDMAINT6, + .maps[RTL_IMR_BCNDMAINT5] = IMR_BCNDMAINT5, + .maps[RTL_IMR_BCNDMAINT4] = IMR_BCNDMAINT4, + .maps[RTL_IMR_BCNDMAINT3] = IMR_BCNDMAINT3, + .maps[RTL_IMR_BCNDMAINT2] = IMR_BCNDMAINT2, + .maps[RTL_IMR_BCNDMAINT1] = IMR_BCNDMAINT1, + .maps[RTL_IMR_BCNDOK8] = IMR_BCNDOK8, + .maps[RTL_IMR_BCNDOK7] = IMR_BCNDOK7, + .maps[RTL_IMR_BCNDOK6] = IMR_BCNDOK6, + .maps[RTL_IMR_BCNDOK5] = IMR_BCNDOK5, + .maps[RTL_IMR_BCNDOK4] = IMR_BCNDOK4, + .maps[RTL_IMR_BCNDOK3] = IMR_BCNDOK3, + .maps[RTL_IMR_BCNDOK2] = IMR_BCNDOK2, + .maps[RTL_IMR_BCNDOK1] = IMR_BCNDOK1, + .maps[RTL_IMR_TIMEOUT2] = IMR_TIMEOUT2, + .maps[RTL_IMR_TIMEOUT1] = IMR_TIMEOUT1, + + .maps[RTL_IMR_TXFOVW] = IMR_TXFOVW, + .maps[RTL_IMR_PSTIMEOUT] = IMR_PSTIMEOUT, + .maps[RTL_IMR_BcnInt] = IMR_BCNINT, + .maps[RTL_IMR_RXFOVW] = IMR_RXFOVW, + .maps[RTL_IMR_RDU] = IMR_RDU, + .maps[RTL_IMR_ATIMEND] = IMR_ATIMEND, + .maps[RTL_IMR_BDOK] = IMR_BDOK, + .maps[RTL_IMR_MGNTDOK] = IMR_MGNTDOK, + .maps[RTL_IMR_TBDER] = IMR_TBDER, + .maps[RTL_IMR_HIGHDOK] = IMR_HIGHDOK, + .maps[RTL_IMR_COMDOK] = IMR_COMDOK, + .maps[RTL_IMR_TBDOK] = IMR_TBDOK, + .maps[RTL_IMR_BKDOK] = IMR_BKDOK, + .maps[RTL_IMR_BEDOK] = IMR_BEDOK, + .maps[RTL_IMR_VIDOK] = IMR_VIDOK, + .maps[RTL_IMR_VODOK] = IMR_VODOK, + .maps[RTL_IMR_ROK] = IMR_ROK, + .maps[RTL_IBSS_INT_MASKS] = (IMR_BCNINT | IMR_TBDOK | IMR_TBDER), + + .maps[RTL_RC_CCK_RATE1M] = DESC92S_RATE1M, + .maps[RTL_RC_CCK_RATE2M] = DESC92S_RATE2M, + .maps[RTL_RC_CCK_RATE5_5M] = DESC92S_RATE5_5M, + .maps[RTL_RC_CCK_RATE11M] = DESC92S_RATE11M, + .maps[RTL_RC_OFDM_RATE6M] = DESC92S_RATE6M, + .maps[RTL_RC_OFDM_RATE9M] = DESC92S_RATE9M, + .maps[RTL_RC_OFDM_RATE12M] = DESC92S_RATE12M, + .maps[RTL_RC_OFDM_RATE18M] = DESC92S_RATE18M, + .maps[RTL_RC_OFDM_RATE24M] = DESC92S_RATE24M, + .maps[RTL_RC_OFDM_RATE36M] = DESC92S_RATE36M, + .maps[RTL_RC_OFDM_RATE48M] = DESC92S_RATE48M, + .maps[RTL_RC_OFDM_RATE54M] = DESC92S_RATE54M, + + .maps[RTL_RC_HT_RATEMCS7] = DESC92S_RATEMCS7, + .maps[RTL_RC_HT_RATEMCS15] = DESC92S_RATEMCS15, +}; + +static struct pci_device_id rtl92se_pci_ids[] __devinitdata = { + {RTL_PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0x8192, rtl92se_hal_cfg)}, + {RTL_PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0x8171, rtl92se_hal_cfg)}, + {RTL_PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0x8172, rtl92se_hal_cfg)}, + {RTL_PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0x8173, rtl92se_hal_cfg)}, + {RTL_PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0x8174, rtl92se_hal_cfg)}, + {}, +}; + +MODULE_DEVICE_TABLE(pci, rtl92se_pci_ids); + +MODULE_AUTHOR("lizhaoming "); +MODULE_AUTHOR("Realtek WlanFAE "); +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("Realtek 8192S/8191S 802.11n PCI wireless"); +MODULE_FIRMWARE("rtlwifi/rtl8192sefw.bin"); + +module_param_named(swenc, rtl92se_mod_params.sw_crypto, bool, 0444); +module_param_named(ips, rtl92se_mod_params.inactiveps, bool, 0444); +module_param_named(swlps, rtl92se_mod_params.swctrl_lps, bool, 0444); +module_param_named(fwlps, rtl92se_mod_params.fwctrl_lps, bool, 0444); +MODULE_PARM_DESC(swenc, "using hardware crypto (default 0 [hardware])\n"); +MODULE_PARM_DESC(ips, "using no link power save (default 1 is open)\n"); +MODULE_PARM_DESC(swlps, "using linked sw control power save (default 1 is " + "open)\n"); + + +static struct pci_driver rtl92se_driver = { + .name = KBUILD_MODNAME, + .id_table = rtl92se_pci_ids, + .probe = rtl_pci_probe, + .remove = rtl_pci_disconnect, + +#ifdef CONFIG_PM + .suspend = rtl_pci_suspend, + .resume = rtl_pci_resume, +#endif + +}; + +static int __init rtl92se_module_init(void) +{ + int ret = 0; + + ret = pci_register_driver(&rtl92se_driver); + if (ret) + RT_ASSERT(false, (": No device found\n")); + + return ret; +} + +static void __exit rtl92se_module_exit(void) +{ + pci_unregister_driver(&rtl92se_driver); +} + +module_init(rtl92se_module_init); +module_exit(rtl92se_module_exit); diff --git a/drivers/net/wireless/rtlwifi/rtl8192se/sw.h b/drivers/net/wireless/rtlwifi/rtl8192se/sw.h new file mode 100644 index 0000000..fc4eb28 --- /dev/null +++ b/drivers/net/wireless/rtlwifi/rtl8192se/sw.h @@ -0,0 +1,36 @@ +/****************************************************************************** + * + * Copyright(c) 2009-2010 Realtek Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + *****************************************************************************/ +#ifndef __REALTEK_PCI92SE_SW_H__ +#define __REALTEK_PCI92SE_SW_H__ + +#define EFUSE_MAX_SECTION 16 + +int rtl92se_init_sw(struct ieee80211_hw *hw); +void rtl92se_deinit_sw(struct ieee80211_hw *hw); +void rtl92se_init_var_map(struct ieee80211_hw *hw); + +#endif -- cgit v0.10.2 From 18906ae27d233914d54f41e5fcf3fdfdf2fb69a9 Mon Sep 17 00:00:00 2001 From: Chaoming Li Date: Tue, 3 May 2011 09:49:16 -0500 Subject: rtlwifi: rtl8192se: Merge table routines Merge routines table.c and table.h for RTL8192SE. Signed-off-by: Chaoming_Li Signed-off-by: Larry Finger Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/rtlwifi/rtl8192se/table.c b/drivers/net/wireless/rtlwifi/rtl8192se/table.c new file mode 100644 index 0000000..154185b --- /dev/null +++ b/drivers/net/wireless/rtlwifi/rtl8192se/table.c @@ -0,0 +1,634 @@ +/****************************************************************************** + * + * Copyright(c) 2009-2010 Realtek Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger + * + * Created on 2010/ 5/18, 1:41 + *****************************************************************************/ + +#include "table.h" + +u32 rtl8192sephy_reg_2t2rarray[PHY_REG_2T2RARRAYLENGTH] = { + 0x01c, 0x07000000, + 0x800, 0x00040000, + 0x804, 0x00008003, + 0x808, 0x0000fc00, + 0x80c, 0x0000000a, + 0x810, 0x10005088, + 0x814, 0x020c3d10, + 0x818, 0x00200185, + 0x81c, 0x00000000, + 0x820, 0x01000000, + 0x824, 0x00390004, + 0x828, 0x01000000, + 0x82c, 0x00390004, + 0x830, 0x00000004, + 0x834, 0x00690200, + 0x838, 0x00000004, + 0x83c, 0x00690200, + 0x840, 0x00010000, + 0x844, 0x00010000, + 0x848, 0x00000000, + 0x84c, 0x00000000, + 0x850, 0x00000000, + 0x854, 0x00000000, + 0x858, 0x48484848, + 0x85c, 0x65a965a9, + 0x860, 0x0f7f0130, + 0x864, 0x0f7f0130, + 0x868, 0x0f7f0130, + 0x86c, 0x0f7f0130, + 0x870, 0x03000700, + 0x874, 0x03000300, + 0x878, 0x00020002, + 0x87c, 0x004f0201, + 0x880, 0xa8300ac1, + 0x884, 0x00000058, + 0x888, 0x00000008, + 0x88c, 0x00000004, + 0x890, 0x00000000, + 0x894, 0xfffffffe, + 0x898, 0x40302010, + 0x89c, 0x00706050, + 0x8b0, 0x00000000, + 0x8e0, 0x00000000, + 0x8e4, 0x00000000, + 0xe00, 0x30333333, + 0xe04, 0x2a2d2e2f, + 0xe08, 0x00003232, + 0xe10, 0x30333333, + 0xe14, 0x2a2d2e2f, + 0xe18, 0x30333333, + 0xe1c, 0x2a2d2e2f, + 0xe30, 0x01007c00, + 0xe34, 0x01004800, + 0xe38, 0x1000dc1f, + 0xe3c, 0x10008c1f, + 0xe40, 0x021400a0, + 0xe44, 0x281600a0, + 0xe48, 0xf8000001, + 0xe4c, 0x00002910, + 0xe50, 0x01007c00, + 0xe54, 0x01004800, + 0xe58, 0x1000dc1f, + 0xe5c, 0x10008c1f, + 0xe60, 0x021400a0, + 0xe64, 0x281600a0, + 0xe6c, 0x00002910, + 0xe70, 0x31ed92fb, + 0xe74, 0x361536fb, + 0xe78, 0x361536fb, + 0xe7c, 0x361536fb, + 0xe80, 0x361536fb, + 0xe84, 0x000d92fb, + 0xe88, 0x000d92fb, + 0xe8c, 0x31ed92fb, + 0xed0, 0x31ed92fb, + 0xed4, 0x31ed92fb, + 0xed8, 0x000d92fb, + 0xedc, 0x000d92fb, + 0xee0, 0x000d92fb, + 0xee4, 0x015e5448, + 0xee8, 0x21555448, + 0x900, 0x00000000, + 0x904, 0x00000023, + 0x908, 0x00000000, + 0x90c, 0x01121313, + 0xa00, 0x00d047c8, + 0xa04, 0x80ff0008, + 0xa08, 0x8ccd8300, + 0xa0c, 0x2e62120f, + 0xa10, 0x9500bb78, + 0xa14, 0x11144028, + 0xa18, 0x00881117, + 0xa1c, 0x89140f00, + 0xa20, 0x1a1b0000, + 0xa24, 0x090e1317, + 0xa28, 0x00000204, + 0xa2c, 0x10d30000, + 0xc00, 0x40071d40, + 0xc04, 0x00a05633, + 0xc08, 0x000000e4, + 0xc0c, 0x6c6c6c6c, + 0xc10, 0x08800000, + 0xc14, 0x40000100, + 0xc18, 0x08000000, + 0xc1c, 0x40000100, + 0xc20, 0x08000000, + 0xc24, 0x40000100, + 0xc28, 0x08000000, + 0xc2c, 0x40000100, + 0xc30, 0x6de9ac44, + 0xc34, 0x469652cf, + 0xc38, 0x49795994, + 0xc3c, 0x0a979764, + 0xc40, 0x1f7c403f, + 0xc44, 0x000100b7, + 0xc48, 0xec020000, + 0xc4c, 0x007f037f, + 0xc50, 0x69543420, + 0xc54, 0x433c0094, + 0xc58, 0x69543420, + 0xc5c, 0x433c0094, + 0xc60, 0x69543420, + 0xc64, 0x433c0094, + 0xc68, 0x69543420, + 0xc6c, 0x433c0094, + 0xc70, 0x2c7f000d, + 0xc74, 0x0186155b, + 0xc78, 0x0000001f, + 0xc7c, 0x00b91612, + 0xc80, 0x40000100, + 0xc84, 0x20f60000, + 0xc88, 0x20000080, + 0xc8c, 0x20200000, + 0xc90, 0x40000100, + 0xc94, 0x00000000, + 0xc98, 0x40000100, + 0xc9c, 0x00000000, + 0xca0, 0x00492492, + 0xca4, 0x00000000, + 0xca8, 0x00000000, + 0xcac, 0x00000000, + 0xcb0, 0x00000000, + 0xcb4, 0x00000000, + 0xcb8, 0x00000000, + 0xcbc, 0x28000000, + 0xcc0, 0x00000000, + 0xcc4, 0x00000000, + 0xcc8, 0x00000000, + 0xccc, 0x00000000, + 0xcd0, 0x00000000, + 0xcd4, 0x00000000, + 0xcd8, 0x64b22427, + 0xcdc, 0x00766932, + 0xce0, 0x00222222, + 0xce4, 0x00000000, + 0xce8, 0x37644302, + 0xcec, 0x2f97d40c, + 0xd00, 0x00000750, + 0xd04, 0x00000403, + 0xd08, 0x0000907f, + 0xd0c, 0x00000001, + 0xd10, 0xa0633333, + 0xd14, 0x33333c63, + 0xd18, 0x6a8f5b6b, + 0xd1c, 0x00000000, + 0xd20, 0x00000000, + 0xd24, 0x00000000, + 0xd28, 0x00000000, + 0xd2c, 0xcc979975, + 0xd30, 0x00000000, + 0xd34, 0x00000000, + 0xd38, 0x00000000, + 0xd3c, 0x00027293, + 0xd40, 0x00000000, + 0xd44, 0x00000000, + 0xd48, 0x00000000, + 0xd50, 0x6437140a, + 0xd54, 0x024dbd02, + 0xd58, 0x00000000, + 0xd5c, 0x30032064, + 0xd60, 0x4653de68, + 0xd64, 0x00518a3c, + 0xd68, 0x00002101, + 0xf14, 0x00000003, + 0xf4c, 0x00000000, + 0xf00, 0x00000300, +}; + +u32 rtl8192sephy_changeto_1t1rarray[PHY_CHANGETO_1T1RARRAYLENGTH] = { + 0x844, 0xffffffff, 0x00010000, + 0x804, 0x0000000f, 0x00000001, + 0x824, 0x00f0000f, 0x00300004, + 0x82c, 0x00f0000f, 0x00100002, + 0x870, 0x04000000, 0x00000001, + 0x864, 0x00000400, 0x00000000, + 0x878, 0x000f000f, 0x00000002, + 0xe74, 0x0f000000, 0x00000002, + 0xe78, 0x0f000000, 0x00000002, + 0xe7c, 0x0f000000, 0x00000002, + 0xe80, 0x0f000000, 0x00000002, + 0x90c, 0x000000ff, 0x00000011, + 0xc04, 0x000000ff, 0x00000011, + 0xd04, 0x0000000f, 0x00000001, + 0x1f4, 0xffff0000, 0x00007777, + 0x234, 0xf8000000, 0x0000000a, +}; + +u32 rtl8192sephy_changeto_1t2rarray[PHY_CHANGETO_1T2RARRAYLENGTH] = { + 0x804, 0x0000000f, 0x00000003, + 0x824, 0x00f0000f, 0x00300004, + 0x82c, 0x00f0000f, 0x00300002, + 0x870, 0x04000000, 0x00000001, + 0x864, 0x00000400, 0x00000000, + 0x878, 0x000f000f, 0x00000002, + 0xe74, 0x0f000000, 0x00000002, + 0xe78, 0x0f000000, 0x00000002, + 0xe7c, 0x0f000000, 0x00000002, + 0xe80, 0x0f000000, 0x00000002, + 0x90c, 0x000000ff, 0x00000011, + 0xc04, 0x000000ff, 0x00000033, + 0xd04, 0x0000000f, 0x00000003, + 0x1f4, 0xffff0000, 0x00007777, + 0x234, 0xf8000000, 0x0000000a, +}; + +u32 rtl8192sephy_reg_array_pg[PHY_REG_ARRAY_PGLENGTH] = { + 0xe00, 0xffffffff, 0x06090909, + 0xe04, 0xffffffff, 0x00030406, + 0xe08, 0x0000ff00, 0x00000000, + 0xe10, 0xffffffff, 0x0a0c0d0e, + 0xe14, 0xffffffff, 0x04070809, + 0xe18, 0xffffffff, 0x0a0c0d0e, + 0xe1c, 0xffffffff, 0x04070809, + 0xe00, 0xffffffff, 0x04040404, + 0xe04, 0xffffffff, 0x00020204, + 0xe08, 0x0000ff00, 0x00000000, + 0xe10, 0xffffffff, 0x02040404, + 0xe14, 0xffffffff, 0x00000002, + 0xe18, 0xffffffff, 0x02040404, + 0xe1c, 0xffffffff, 0x00000002, + 0xe00, 0xffffffff, 0x04040404, + 0xe04, 0xffffffff, 0x00020204, + 0xe08, 0x0000ff00, 0x00000000, + 0xe10, 0xffffffff, 0x02040404, + 0xe14, 0xffffffff, 0x00000002, + 0xe18, 0xffffffff, 0x02040404, + 0xe1c, 0xffffffff, 0x00000002, + 0xe00, 0xffffffff, 0x02020202, + 0xe04, 0xffffffff, 0x00020202, + 0xe08, 0x0000ff00, 0x00000000, + 0xe10, 0xffffffff, 0x02020202, + 0xe14, 0xffffffff, 0x00000002, + 0xe18, 0xffffffff, 0x02020202, + 0xe1c, 0xffffffff, 0x00000002, +}; + +u32 rtl8192seradioa_1t_array[RADIOA_1T_ARRAYLENGTH] = { + 0x000, 0x00030159, + 0x001, 0x00030250, + 0x002, 0x00010000, + 0x010, 0x0008000f, + 0x011, 0x000231fc, + 0x010, 0x000c000f, + 0x011, 0x0003f9f8, + 0x010, 0x0002000f, + 0x011, 0x00020101, + 0x014, 0x0001093e, + 0x014, 0x0009093e, + 0x015, 0x0000f8f4, + 0x017, 0x000f6500, + 0x01a, 0x00013056, + 0x01b, 0x00060000, + 0x01c, 0x00000300, + 0x01e, 0x00031059, + 0x021, 0x00054000, + 0x022, 0x0000083c, + 0x023, 0x00001558, + 0x024, 0x00000060, + 0x025, 0x00022583, + 0x026, 0x0000f200, + 0x027, 0x000eacf1, + 0x028, 0x0009bd54, + 0x029, 0x00004582, + 0x02a, 0x00000001, + 0x02b, 0x00021334, + 0x02a, 0x00000000, + 0x02b, 0x0000000a, + 0x02a, 0x00000001, + 0x02b, 0x00000808, + 0x02b, 0x00053333, + 0x02c, 0x0000000c, + 0x02a, 0x00000002, + 0x02b, 0x00000808, + 0x02b, 0x0005b333, + 0x02c, 0x0000000d, + 0x02a, 0x00000003, + 0x02b, 0x00000808, + 0x02b, 0x00063333, + 0x02c, 0x0000000d, + 0x02a, 0x00000004, + 0x02b, 0x00000808, + 0x02b, 0x0006b333, + 0x02c, 0x0000000d, + 0x02a, 0x00000005, + 0x02b, 0x00000709, + 0x02b, 0x00053333, + 0x02c, 0x0000000d, + 0x02a, 0x00000006, + 0x02b, 0x00000709, + 0x02b, 0x0005b333, + 0x02c, 0x0000000d, + 0x02a, 0x00000007, + 0x02b, 0x00000709, + 0x02b, 0x00063333, + 0x02c, 0x0000000d, + 0x02a, 0x00000008, + 0x02b, 0x00000709, + 0x02b, 0x0006b333, + 0x02c, 0x0000000d, + 0x02a, 0x00000009, + 0x02b, 0x0000060a, + 0x02b, 0x00053333, + 0x02c, 0x0000000d, + 0x02a, 0x0000000a, + 0x02b, 0x0000060a, + 0x02b, 0x0005b333, + 0x02c, 0x0000000d, + 0x02a, 0x0000000b, + 0x02b, 0x0000060a, + 0x02b, 0x00063333, + 0x02c, 0x0000000d, + 0x02a, 0x0000000c, + 0x02b, 0x0000060a, + 0x02b, 0x0006b333, + 0x02c, 0x0000000d, + 0x02a, 0x0000000d, + 0x02b, 0x0000050b, + 0x02b, 0x00053333, + 0x02c, 0x0000000d, + 0x02a, 0x0000000e, + 0x02b, 0x0000050b, + 0x02b, 0x00066623, + 0x02c, 0x0000001a, + 0x02a, 0x000e4000, + 0x030, 0x00020000, + 0x031, 0x000b9631, + 0x032, 0x0000130d, + 0x033, 0x00000187, + 0x013, 0x00019e6c, + 0x013, 0x00015e94, + 0x000, 0x00010159, + 0x018, 0x0000f401, + 0x0fe, 0x00000000, + 0x01e, 0x0003105b, + 0x0fe, 0x00000000, + 0x000, 0x00030159, + 0x010, 0x0004000f, + 0x011, 0x000203f9, +}; + +u32 rtl8192seradiob_array[RADIOB_ARRAYLENGTH] = { + 0x000, 0x00030159, + 0x001, 0x00001041, + 0x002, 0x00011000, + 0x005, 0x00080fc0, + 0x007, 0x000fc803, + 0x013, 0x00017cb0, + 0x013, 0x00011cc0, + 0x013, 0x0000dc60, + 0x013, 0x00008c60, + 0x013, 0x00004450, + 0x013, 0x00000020, +}; + +u32 rtl8192seradiob_gm_array[RADIOB_GM_ARRAYLENGTH] = { + 0x000, 0x00030159, + 0x001, 0x00001041, + 0x002, 0x00011000, + 0x005, 0x00080fc0, + 0x007, 0x000fc803, +}; + +u32 rtl8192semac_2t_array[MAC_2T_ARRAYLENGTH] = { + 0x020, 0x00000035, + 0x048, 0x0000000e, + 0x049, 0x000000f0, + 0x04a, 0x00000077, + 0x04b, 0x00000083, + 0x0b5, 0x00000021, + 0x0dc, 0x000000ff, + 0x0dd, 0x000000ff, + 0x0de, 0x000000ff, + 0x0df, 0x000000ff, + 0x116, 0x00000000, + 0x117, 0x00000000, + 0x118, 0x00000000, + 0x119, 0x00000000, + 0x11a, 0x00000000, + 0x11b, 0x00000000, + 0x11c, 0x00000000, + 0x11d, 0x00000000, + 0x160, 0x0000000b, + 0x161, 0x0000000b, + 0x162, 0x0000000b, + 0x163, 0x0000000b, + 0x164, 0x0000000b, + 0x165, 0x0000000b, + 0x166, 0x0000000b, + 0x167, 0x0000000b, + 0x168, 0x0000000b, + 0x169, 0x0000000b, + 0x16a, 0x0000000b, + 0x16b, 0x0000000b, + 0x16c, 0x0000000b, + 0x16d, 0x0000000b, + 0x16e, 0x0000000b, + 0x16f, 0x0000000b, + 0x170, 0x0000000b, + 0x171, 0x0000000b, + 0x172, 0x0000000b, + 0x173, 0x0000000b, + 0x174, 0x0000000b, + 0x175, 0x0000000b, + 0x176, 0x0000000b, + 0x177, 0x0000000b, + 0x178, 0x0000000b, + 0x179, 0x0000000b, + 0x17a, 0x0000000b, + 0x17b, 0x0000000b, + 0x17c, 0x0000000b, + 0x17d, 0x0000000b, + 0x17e, 0x0000000b, + 0x17f, 0x0000000b, + 0x236, 0x0000000c, + 0x503, 0x00000022, + 0x560, 0x00000000, +}; + +u32 rtl8192seagctab_array[AGCTAB_ARRAYLENGTH] = { + 0xc78, 0x7f000001, + 0xc78, 0x7f010001, + 0xc78, 0x7e020001, + 0xc78, 0x7d030001, + 0xc78, 0x7c040001, + 0xc78, 0x7b050001, + 0xc78, 0x7a060001, + 0xc78, 0x79070001, + 0xc78, 0x78080001, + 0xc78, 0x77090001, + 0xc78, 0x760a0001, + 0xc78, 0x750b0001, + 0xc78, 0x740c0001, + 0xc78, 0x730d0001, + 0xc78, 0x720e0001, + 0xc78, 0x710f0001, + 0xc78, 0x70100001, + 0xc78, 0x6f110001, + 0xc78, 0x6f120001, + 0xc78, 0x6e130001, + 0xc78, 0x6d140001, + 0xc78, 0x6d150001, + 0xc78, 0x6c160001, + 0xc78, 0x6b170001, + 0xc78, 0x6a180001, + 0xc78, 0x6a190001, + 0xc78, 0x691a0001, + 0xc78, 0x681b0001, + 0xc78, 0x671c0001, + 0xc78, 0x661d0001, + 0xc78, 0x651e0001, + 0xc78, 0x641f0001, + 0xc78, 0x63200001, + 0xc78, 0x4c210001, + 0xc78, 0x4b220001, + 0xc78, 0x4a230001, + 0xc78, 0x49240001, + 0xc78, 0x48250001, + 0xc78, 0x47260001, + 0xc78, 0x46270001, + 0xc78, 0x45280001, + 0xc78, 0x44290001, + 0xc78, 0x2c2a0001, + 0xc78, 0x2b2b0001, + 0xc78, 0x2a2c0001, + 0xc78, 0x292d0001, + 0xc78, 0x282e0001, + 0xc78, 0x272f0001, + 0xc78, 0x26300001, + 0xc78, 0x25310001, + 0xc78, 0x24320001, + 0xc78, 0x23330001, + 0xc78, 0x22340001, + 0xc78, 0x09350001, + 0xc78, 0x08360001, + 0xc78, 0x07370001, + 0xc78, 0x06380001, + 0xc78, 0x05390001, + 0xc78, 0x043a0001, + 0xc78, 0x033b0001, + 0xc78, 0x023c0001, + 0xc78, 0x013d0001, + 0xc78, 0x003e0001, + 0xc78, 0x003f0001, + 0xc78, 0x7f400001, + 0xc78, 0x7f410001, + 0xc78, 0x7e420001, + 0xc78, 0x7d430001, + 0xc78, 0x7c440001, + 0xc78, 0x7b450001, + 0xc78, 0x7a460001, + 0xc78, 0x79470001, + 0xc78, 0x78480001, + 0xc78, 0x77490001, + 0xc78, 0x764a0001, + 0xc78, 0x754b0001, + 0xc78, 0x744c0001, + 0xc78, 0x734d0001, + 0xc78, 0x724e0001, + 0xc78, 0x714f0001, + 0xc78, 0x70500001, + 0xc78, 0x6f510001, + 0xc78, 0x6f520001, + 0xc78, 0x6e530001, + 0xc78, 0x6d540001, + 0xc78, 0x6d550001, + 0xc78, 0x6c560001, + 0xc78, 0x6b570001, + 0xc78, 0x6a580001, + 0xc78, 0x6a590001, + 0xc78, 0x695a0001, + 0xc78, 0x685b0001, + 0xc78, 0x675c0001, + 0xc78, 0x665d0001, + 0xc78, 0x655e0001, + 0xc78, 0x645f0001, + 0xc78, 0x63600001, + 0xc78, 0x4c610001, + 0xc78, 0x4b620001, + 0xc78, 0x4a630001, + 0xc78, 0x49640001, + 0xc78, 0x48650001, + 0xc78, 0x47660001, + 0xc78, 0x46670001, + 0xc78, 0x45680001, + 0xc78, 0x44690001, + 0xc78, 0x2c6a0001, + 0xc78, 0x2b6b0001, + 0xc78, 0x2a6c0001, + 0xc78, 0x296d0001, + 0xc78, 0x286e0001, + 0xc78, 0x276f0001, + 0xc78, 0x26700001, + 0xc78, 0x25710001, + 0xc78, 0x24720001, + 0xc78, 0x23730001, + 0xc78, 0x22740001, + 0xc78, 0x09750001, + 0xc78, 0x08760001, + 0xc78, 0x07770001, + 0xc78, 0x06780001, + 0xc78, 0x05790001, + 0xc78, 0x047a0001, + 0xc78, 0x037b0001, + 0xc78, 0x027c0001, + 0xc78, 0x017d0001, + 0xc78, 0x007e0001, + 0xc78, 0x007f0001, + 0xc78, 0x3000001e, + 0xc78, 0x3001001e, + 0xc78, 0x3002001e, + 0xc78, 0x3003001e, + 0xc78, 0x3004001e, + 0xc78, 0x3405001e, + 0xc78, 0x3806001e, + 0xc78, 0x3e07001e, + 0xc78, 0x3e08001e, + 0xc78, 0x4409001e, + 0xc78, 0x460a001e, + 0xc78, 0x480b001e, + 0xc78, 0x480c001e, + 0xc78, 0x4e0d001e, + 0xc78, 0x560e001e, + 0xc78, 0x5a0f001e, + 0xc78, 0x5e10001e, + 0xc78, 0x6211001e, + 0xc78, 0x6c12001e, + 0xc78, 0x7213001e, + 0xc78, 0x7214001e, + 0xc78, 0x7215001e, + 0xc78, 0x7216001e, + 0xc78, 0x7217001e, + 0xc78, 0x7218001e, + 0xc78, 0x7219001e, + 0xc78, 0x721a001e, + 0xc78, 0x721b001e, + 0xc78, 0x721c001e, + 0xc78, 0x721d001e, + 0xc78, 0x721e001e, + 0xc78, 0x721f001e, +}; + diff --git a/drivers/net/wireless/rtlwifi/rtl8192se/table.h b/drivers/net/wireless/rtlwifi/rtl8192se/table.h new file mode 100644 index 0000000..b4ed6d95 --- /dev/null +++ b/drivers/net/wireless/rtlwifi/rtl8192se/table.h @@ -0,0 +1,49 @@ +/****************************************************************************** + * Copyright(c) 2008 - 2010 Realtek Corporation. All rights reserved. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae + * + * Larry Finger + * + ******************************************************************************/ +#ifndef __INC_HAL8192SE_FW_IMG_H +#define __INC_HAL8192SE_FW_IMG_H + +#include + +/*Created on 2010/ 4/12, 5:56*/ + +#define PHY_REG_2T2RARRAYLENGTH 372 +extern u32 rtl8192sephy_reg_2t2rarray[PHY_REG_2T2RARRAYLENGTH]; +#define PHY_CHANGETO_1T1RARRAYLENGTH 48 +extern u32 rtl8192sephy_changeto_1t1rarray[PHY_CHANGETO_1T1RARRAYLENGTH]; +#define PHY_CHANGETO_1T2RARRAYLENGTH 45 +extern u32 rtl8192sephy_changeto_1t2rarray[PHY_CHANGETO_1T2RARRAYLENGTH]; +#define PHY_REG_ARRAY_PGLENGTH 84 +extern u32 rtl8192sephy_reg_array_pg[PHY_REG_ARRAY_PGLENGTH]; +#define RADIOA_1T_ARRAYLENGTH 202 +extern u32 rtl8192seradioa_1t_array[RADIOA_1T_ARRAYLENGTH]; +#define RADIOB_ARRAYLENGTH 22 +extern u32 rtl8192seradiob_array[RADIOB_ARRAYLENGTH]; +#define RADIOB_GM_ARRAYLENGTH 10 +extern u32 rtl8192seradiob_gm_array[RADIOB_GM_ARRAYLENGTH]; +#define MAC_2T_ARRAYLENGTH 106 +extern u32 rtl8192semac_2t_array[MAC_2T_ARRAYLENGTH]; +#define AGCTAB_ARRAYLENGTH 320 +extern u32 rtl8192seagctab_array[AGCTAB_ARRAYLENGTH]; + +#endif + -- cgit v0.10.2 From 84f494cef7d98d67aa7d50ede12784464aa0c274 Mon Sep 17 00:00:00 2001 From: Chaoming Li Date: Tue, 3 May 2011 09:49:26 -0500 Subject: rtlwifi: rtl8192se: Merge TX and RX routines Merge routines trx.c and trx.h for RTL8192SE. Signed-off-by: Chaoming_Li Signed-off-by: Larry Finger Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/rtlwifi/rtl8192se/trx.c b/drivers/net/wireless/rtlwifi/rtl8192se/trx.c new file mode 100644 index 0000000..5cf4423 --- /dev/null +++ b/drivers/net/wireless/rtlwifi/rtl8192se/trx.c @@ -0,0 +1,976 @@ +/****************************************************************************** + * + * Copyright(c) 2009-2010 Realtek Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger + * + *****************************************************************************/ + +#include "../wifi.h" +#include "../pci.h" +#include "../base.h" +#include "reg.h" +#include "def.h" +#include "phy.h" +#include "fw.h" +#include "trx.h" +#include "led.h" + +static u8 _rtl92se_map_hwqueue_to_fwqueue(struct sk_buff *skb, u8 skb_queue) +{ + __le16 fc = rtl_get_fc(skb); + + if (unlikely(ieee80211_is_beacon(fc))) + return QSLT_BEACON; + if (ieee80211_is_mgmt(fc)) + return QSLT_MGNT; + if (ieee80211_is_nullfunc(fc)) + return QSLT_HIGH; + + return skb->priority; +} + +static int _rtl92se_rate_mapping(bool isht, u8 desc_rate, bool first_ampdu) +{ + int rate_idx = 0; + + if (first_ampdu) { + if (false == isht) { + switch (desc_rate) { + case DESC92S_RATE1M: + rate_idx = 0; + break; + case DESC92S_RATE2M: + rate_idx = 1; + break; + case DESC92S_RATE5_5M: + rate_idx = 2; + break; + case DESC92S_RATE11M: + rate_idx = 3; + break; + case DESC92S_RATE6M: + rate_idx = 4; + break; + case DESC92S_RATE9M: + rate_idx = 5; + break; + case DESC92S_RATE12M: + rate_idx = 6; + break; + case DESC92S_RATE18M: + rate_idx = 7; + break; + case DESC92S_RATE24M: + rate_idx = 8; + break; + case DESC92S_RATE36M: + rate_idx = 9; + break; + case DESC92S_RATE48M: + rate_idx = 10; + break; + case DESC92S_RATE54M: + rate_idx = 11; + break; + default: + rate_idx = 0; + break; + } + } else { + rate_idx = 11; + } + + return rate_idx; + } + + switch (desc_rate) { + case DESC92S_RATE1M: + rate_idx = 0; + break; + case DESC92S_RATE2M: + rate_idx = 1; + break; + case DESC92S_RATE5_5M: + rate_idx = 2; + break; + case DESC92S_RATE11M: + rate_idx = 3; + break; + case DESC92S_RATE6M: + rate_idx = 4; + break; + case DESC92S_RATE9M: + rate_idx = 5; + break; + case DESC92S_RATE12M: + rate_idx = 6; + break; + case DESC92S_RATE18M: + rate_idx = 7; + break; + case DESC92S_RATE24M: + rate_idx = 8; + break; + case DESC92S_RATE36M: + rate_idx = 9; + break; + case DESC92S_RATE48M: + rate_idx = 10; + break; + case DESC92S_RATE54M: + rate_idx = 11; + break; + default: + rate_idx = 11; + break; + } + return rate_idx; +} + +static u8 _rtl92s_query_rxpwrpercentage(char antpower) +{ + if ((antpower <= -100) || (antpower >= 20)) + return 0; + else if (antpower >= 0) + return 100; + else + return 100 + antpower; +} + +static u8 _rtl92s_evm_db_to_percentage(char value) +{ + char ret_val; + ret_val = value; + + if (ret_val >= 0) + ret_val = 0; + + if (ret_val <= -33) + ret_val = -33; + + ret_val = 0 - ret_val; + ret_val *= 3; + + if (ret_val == 99) + ret_val = 100; + + return ret_val; +} + +static long _rtl92se_translate_todbm(struct ieee80211_hw *hw, + u8 signal_strength_index) +{ + long signal_power; + + signal_power = (long)((signal_strength_index + 1) >> 1); + signal_power -= 95; + return signal_power; +} + +static long _rtl92se_signal_scale_mapping(struct ieee80211_hw *hw, + long currsig) +{ + long retsig = 0; + + /* Step 1. Scale mapping. */ + if (currsig > 47) + retsig = 100; + else if (currsig > 14 && currsig <= 47) + retsig = 100 - ((47 - currsig) * 3) / 2; + else if (currsig > 2 && currsig <= 14) + retsig = 48 - ((14 - currsig) * 15) / 7; + else if (currsig >= 0) + retsig = currsig * 9 + 1; + + return retsig; +} + + +static void _rtl92se_query_rxphystatus(struct ieee80211_hw *hw, + struct rtl_stats *pstats, u8 *pdesc, + struct rx_fwinfo *p_drvinfo, + bool packet_match_bssid, + bool packet_toself, + bool packet_beacon) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct phy_sts_cck_8192s_t *cck_buf; + s8 rx_pwr_all = 0, rx_pwr[4]; + u8 rf_rx_num = 0, evm, pwdb_all; + u8 i, max_spatial_stream; + u32 rssi, total_rssi = 0; + bool in_powersavemode = false; + bool is_cck_rate; + + is_cck_rate = RX_HAL_IS_CCK_RATE(pdesc); + pstats->packet_matchbssid = packet_match_bssid; + pstats->packet_toself = packet_toself; + pstats->is_cck = is_cck_rate; + pstats->packet_beacon = packet_beacon; + pstats->is_cck = is_cck_rate; + pstats->rx_mimo_signalquality[0] = -1; + pstats->rx_mimo_signalquality[1] = -1; + + if (is_cck_rate) { + u8 report, cck_highpwr; + cck_buf = (struct phy_sts_cck_8192s_t *)p_drvinfo; + + if (!in_powersavemode) + cck_highpwr = (u8) rtl_get_bbreg(hw, + RFPGA0_XA_HSSIPARAMETER2, + 0x200); + else + cck_highpwr = false; + + if (!cck_highpwr) { + u8 cck_agc_rpt = cck_buf->cck_agc_rpt; + report = cck_buf->cck_agc_rpt & 0xc0; + report = report >> 6; + switch (report) { + case 0x3: + rx_pwr_all = -40 - (cck_agc_rpt & 0x3e); + break; + case 0x2: + rx_pwr_all = -20 - (cck_agc_rpt & 0x3e); + break; + case 0x1: + rx_pwr_all = -2 - (cck_agc_rpt & 0x3e); + break; + case 0x0: + rx_pwr_all = 14 - (cck_agc_rpt & 0x3e); + break; + } + } else { + u8 cck_agc_rpt = cck_buf->cck_agc_rpt; + report = p_drvinfo->cfosho[0] & 0x60; + report = report >> 5; + switch (report) { + case 0x3: + rx_pwr_all = -40 - ((cck_agc_rpt & 0x1f) << 1); + break; + case 0x2: + rx_pwr_all = -20 - ((cck_agc_rpt & 0x1f) << 1); + break; + case 0x1: + rx_pwr_all = -2 - ((cck_agc_rpt & 0x1f) << 1); + break; + case 0x0: + rx_pwr_all = 14 - ((cck_agc_rpt & 0x1f) << 1); + break; + } + } + + pwdb_all = _rtl92s_query_rxpwrpercentage(rx_pwr_all); + + /* CCK gain is smaller than OFDM/MCS gain, */ + /* so we add gain diff by experiences, the val is 6 */ + pwdb_all += 6; + if (pwdb_all > 100) + pwdb_all = 100; + /* modify the offset to make the same gain index with OFDM. */ + if (pwdb_all > 34 && pwdb_all <= 42) + pwdb_all -= 2; + else if (pwdb_all > 26 && pwdb_all <= 34) + pwdb_all -= 6; + else if (pwdb_all > 14 && pwdb_all <= 26) + pwdb_all -= 8; + else if (pwdb_all > 4 && pwdb_all <= 14) + pwdb_all -= 4; + + pstats->rx_pwdb_all = pwdb_all; + pstats->recvsignalpower = rx_pwr_all; + + if (packet_match_bssid) { + u8 sq; + if (pstats->rx_pwdb_all > 40) { + sq = 100; + } else { + sq = cck_buf->sq_rpt; + if (sq > 64) + sq = 0; + else if (sq < 20) + sq = 100; + else + sq = ((64 - sq) * 100) / 44; + } + + pstats->signalquality = sq; + pstats->rx_mimo_signalquality[0] = sq; + pstats->rx_mimo_signalquality[1] = -1; + } + } else { + rtlpriv->dm.rfpath_rxenable[0] = + rtlpriv->dm.rfpath_rxenable[1] = true; + for (i = RF90_PATH_A; i < RF90_PATH_MAX; i++) { + if (rtlpriv->dm.rfpath_rxenable[i]) + rf_rx_num++; + + rx_pwr[i] = ((p_drvinfo->gain_trsw[i] & + 0x3f) * 2) - 110; + rssi = _rtl92s_query_rxpwrpercentage(rx_pwr[i]); + total_rssi += rssi; + rtlpriv->stats.rx_snr_db[i] = + (long)(p_drvinfo->rxsnr[i] / 2); + + if (packet_match_bssid) + pstats->rx_mimo_signalstrength[i] = (u8) rssi; + } + + rx_pwr_all = ((p_drvinfo->pwdb_all >> 1) & 0x7f) - 110; + pwdb_all = _rtl92s_query_rxpwrpercentage(rx_pwr_all); + pstats->rx_pwdb_all = pwdb_all; + pstats->rxpower = rx_pwr_all; + pstats->recvsignalpower = rx_pwr_all; + + if (GET_RX_STATUS_DESC_RX_HT(pdesc) && + GET_RX_STATUS_DESC_RX_MCS(pdesc) >= DESC92S_RATEMCS8 && + GET_RX_STATUS_DESC_RX_MCS(pdesc) <= DESC92S_RATEMCS15) + max_spatial_stream = 2; + else + max_spatial_stream = 1; + + for (i = 0; i < max_spatial_stream; i++) { + evm = _rtl92s_evm_db_to_percentage(p_drvinfo->rxevm[i]); + + if (packet_match_bssid) { + if (i == 0) + pstats->signalquality = (u8)(evm & + 0xff); + pstats->rx_mimo_signalquality[i] = + (u8) (evm & 0xff); + } + } + } + + if (is_cck_rate) + pstats->signalstrength = (u8)(_rtl92se_signal_scale_mapping(hw, + pwdb_all)); + else if (rf_rx_num != 0) + pstats->signalstrength = (u8) (_rtl92se_signal_scale_mapping(hw, + total_rssi /= rf_rx_num)); +} + +static void _rtl92se_process_ui_rssi(struct ieee80211_hw *hw, + struct rtl_stats *pstats) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_phy *rtlphy = &(rtlpriv->phy); + u8 rfpath; + u32 last_rssi, tmpval; + + if (pstats->packet_toself || pstats->packet_beacon) { + rtlpriv->stats.rssi_calculate_cnt++; + + if (rtlpriv->stats.ui_rssi.total_num++ >= + PHY_RSSI_SLID_WIN_MAX) { + rtlpriv->stats.ui_rssi.total_num = + PHY_RSSI_SLID_WIN_MAX; + last_rssi = rtlpriv->stats.ui_rssi.elements[ + rtlpriv->stats.ui_rssi.index]; + rtlpriv->stats.ui_rssi.total_val -= last_rssi; + } + + rtlpriv->stats.ui_rssi.total_val += pstats->signalstrength; + rtlpriv->stats.ui_rssi.elements[rtlpriv->stats.ui_rssi.index++] + = pstats->signalstrength; + + if (rtlpriv->stats.ui_rssi.index >= PHY_RSSI_SLID_WIN_MAX) + rtlpriv->stats.ui_rssi.index = 0; + + tmpval = rtlpriv->stats.ui_rssi.total_val / + rtlpriv->stats.ui_rssi.total_num; + rtlpriv->stats.signal_strength = _rtl92se_translate_todbm(hw, + (u8) tmpval); + pstats->rssi = rtlpriv->stats.signal_strength; + } + + if (!pstats->is_cck && pstats->packet_toself) { + for (rfpath = RF90_PATH_A; rfpath < rtlphy->num_total_rfpath; + rfpath++) { + if (rtlpriv->stats.rx_rssi_percentage[rfpath] == 0) { + rtlpriv->stats.rx_rssi_percentage[rfpath] = + pstats->rx_mimo_signalstrength[rfpath]; + + } + + if (pstats->rx_mimo_signalstrength[rfpath] > + rtlpriv->stats.rx_rssi_percentage[rfpath]) { + rtlpriv->stats.rx_rssi_percentage[rfpath] = + ((rtlpriv->stats.rx_rssi_percentage[rfpath] + * (RX_SMOOTH_FACTOR - 1)) + + (pstats->rx_mimo_signalstrength[rfpath])) / + (RX_SMOOTH_FACTOR); + + rtlpriv->stats.rx_rssi_percentage[rfpath] = + rtlpriv->stats.rx_rssi_percentage[rfpath] + + 1; + } else { + rtlpriv->stats.rx_rssi_percentage[rfpath] = + ((rtlpriv->stats.rx_rssi_percentage[rfpath] + * (RX_SMOOTH_FACTOR - 1)) + + (pstats->rx_mimo_signalstrength[rfpath])) / + (RX_SMOOTH_FACTOR); + } + + } + } +} + +static void _rtl92se_update_rxsignalstatistics(struct ieee80211_hw *hw, + struct rtl_stats *pstats) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + int weighting = 0; + + if (rtlpriv->stats.recv_signal_power == 0) + rtlpriv->stats.recv_signal_power = pstats->recvsignalpower; + + if (pstats->recvsignalpower > rtlpriv->stats.recv_signal_power) + weighting = 5; + else if (pstats->recvsignalpower < rtlpriv->stats.recv_signal_power) + weighting = (-5); + + rtlpriv->stats.recv_signal_power = (rtlpriv->stats.recv_signal_power * 5 + + pstats->recvsignalpower + + weighting) / 6; +} + +static void _rtl92se_process_pwdb(struct ieee80211_hw *hw, + struct rtl_stats *pstats) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); + long undec_sm_pwdb = 0; + + if (mac->opmode == NL80211_IFTYPE_ADHOC) { + return; + } else { + undec_sm_pwdb = + rtlpriv->dm.undecorated_smoothed_pwdb; + } + + if (pstats->packet_toself || pstats->packet_beacon) { + if (undec_sm_pwdb < 0) + undec_sm_pwdb = pstats->rx_pwdb_all; + + if (pstats->rx_pwdb_all > (u32) undec_sm_pwdb) { + undec_sm_pwdb = + (((undec_sm_pwdb) * + (RX_SMOOTH_FACTOR - 1)) + + (pstats->rx_pwdb_all)) / (RX_SMOOTH_FACTOR); + + undec_sm_pwdb = undec_sm_pwdb + 1; + } else { + undec_sm_pwdb = (((undec_sm_pwdb) * + (RX_SMOOTH_FACTOR - 1)) + (pstats->rx_pwdb_all)) / + (RX_SMOOTH_FACTOR); + } + + rtlpriv->dm.undecorated_smoothed_pwdb = undec_sm_pwdb; + _rtl92se_update_rxsignalstatistics(hw, pstats); + } +} + +static void rtl_92s_process_streams(struct ieee80211_hw *hw, + struct rtl_stats *pstats) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + u32 stream; + + for (stream = 0; stream < 2; stream++) { + if (pstats->rx_mimo_signalquality[stream] != -1) { + if (rtlpriv->stats.rx_evm_percentage[stream] == 0) { + rtlpriv->stats.rx_evm_percentage[stream] = + pstats->rx_mimo_signalquality[stream]; + } + + rtlpriv->stats.rx_evm_percentage[stream] = + ((rtlpriv->stats.rx_evm_percentage[stream] * + (RX_SMOOTH_FACTOR - 1)) + + (pstats->rx_mimo_signalquality[stream] * + 1)) / (RX_SMOOTH_FACTOR); + } + } +} + +static void _rtl92se_process_ui_link_quality(struct ieee80211_hw *hw, + struct rtl_stats *pstats) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + u32 last_evm = 0, tmpval; + + if (pstats->signalquality != 0) { + if (pstats->packet_toself || pstats->packet_beacon) { + + if (rtlpriv->stats.ui_link_quality.total_num++ >= + PHY_LINKQUALITY_SLID_WIN_MAX) { + rtlpriv->stats.ui_link_quality.total_num = + PHY_LINKQUALITY_SLID_WIN_MAX; + last_evm = + rtlpriv->stats.ui_link_quality.elements[ + rtlpriv->stats.ui_link_quality.index]; + rtlpriv->stats.ui_link_quality.total_val -= + last_evm; + } + + rtlpriv->stats.ui_link_quality.total_val += + pstats->signalquality; + rtlpriv->stats.ui_link_quality.elements[ + rtlpriv->stats.ui_link_quality.index++] = + pstats->signalquality; + + if (rtlpriv->stats.ui_link_quality.index >= + PHY_LINKQUALITY_SLID_WIN_MAX) + rtlpriv->stats.ui_link_quality.index = 0; + + tmpval = rtlpriv->stats.ui_link_quality.total_val / + rtlpriv->stats.ui_link_quality.total_num; + rtlpriv->stats.signal_quality = tmpval; + + rtlpriv->stats.last_sigstrength_inpercent = tmpval; + + rtl_92s_process_streams(hw, pstats); + + } + } +} + +static void _rtl92se_process_phyinfo(struct ieee80211_hw *hw, + u8 *buffer, + struct rtl_stats *pcurrent_stats) +{ + + if (!pcurrent_stats->packet_matchbssid && + !pcurrent_stats->packet_beacon) + return; + + _rtl92se_process_ui_rssi(hw, pcurrent_stats); + _rtl92se_process_pwdb(hw, pcurrent_stats); + _rtl92se_process_ui_link_quality(hw, pcurrent_stats); +} + +static void _rtl92se_translate_rx_signal_stuff(struct ieee80211_hw *hw, + struct sk_buff *skb, struct rtl_stats *pstats, + u8 *pdesc, struct rx_fwinfo *p_drvinfo) +{ + struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); + struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw)); + + struct ieee80211_hdr *hdr; + u8 *tmp_buf; + u8 *praddr; + u8 *psaddr; + __le16 fc; + u16 type, cfc; + bool packet_matchbssid, packet_toself, packet_beacon; + + tmp_buf = skb->data + pstats->rx_drvinfo_size + pstats->rx_bufshift; + + hdr = (struct ieee80211_hdr *)tmp_buf; + fc = hdr->frame_control; + cfc = le16_to_cpu(fc); + type = WLAN_FC_GET_TYPE(fc); + praddr = hdr->addr1; + psaddr = hdr->addr2; + + packet_matchbssid = ((IEEE80211_FTYPE_CTL != type) && + (!compare_ether_addr(mac->bssid, (cfc & IEEE80211_FCTL_TODS) ? + hdr->addr1 : (cfc & IEEE80211_FCTL_FROMDS) ? + hdr->addr2 : hdr->addr3)) && (!pstats->hwerror) && + (!pstats->crc) && (!pstats->icv)); + + packet_toself = packet_matchbssid && + (!compare_ether_addr(praddr, rtlefuse->dev_addr)); + + if (ieee80211_is_beacon(fc)) + packet_beacon = true; + + _rtl92se_query_rxphystatus(hw, pstats, pdesc, p_drvinfo, + packet_matchbssid, packet_toself, packet_beacon); + _rtl92se_process_phyinfo(hw, tmp_buf, pstats); +} + +bool rtl92se_rx_query_desc(struct ieee80211_hw *hw, struct rtl_stats *stats, + struct ieee80211_rx_status *rx_status, u8 *pdesc, + struct sk_buff *skb) +{ + struct rx_fwinfo *p_drvinfo; + u32 phystatus = (u32)GET_RX_STATUS_DESC_PHY_STATUS(pdesc); + + stats->length = (u16)GET_RX_STATUS_DESC_PKT_LEN(pdesc); + stats->rx_drvinfo_size = (u8)GET_RX_STATUS_DESC_DRVINFO_SIZE(pdesc) * 8; + stats->rx_bufshift = (u8)(GET_RX_STATUS_DESC_SHIFT(pdesc) & 0x03); + stats->icv = (u16)GET_RX_STATUS_DESC_ICV(pdesc); + stats->crc = (u16)GET_RX_STATUS_DESC_CRC32(pdesc); + stats->hwerror = (u16)(stats->crc | stats->icv); + stats->decrypted = !GET_RX_STATUS_DESC_SWDEC(pdesc); + + stats->rate = (u8)GET_RX_STATUS_DESC_RX_MCS(pdesc); + stats->shortpreamble = (u16)GET_RX_STATUS_DESC_SPLCP(pdesc); + stats->isampdu = (bool)(GET_RX_STATUS_DESC_PAGGR(pdesc) == 1); + stats->timestamp_low = GET_RX_STATUS_DESC_TSFL(pdesc); + stats->rx_is40Mhzpacket = (bool)GET_RX_STATUS_DESC_BW(pdesc); + + if (stats->hwerror) + return false; + + rx_status->freq = hw->conf.channel->center_freq; + rx_status->band = hw->conf.channel->band; + + if (GET_RX_STATUS_DESC_CRC32(pdesc)) + rx_status->flag |= RX_FLAG_FAILED_FCS_CRC; + + if (!GET_RX_STATUS_DESC_SWDEC(pdesc)) + rx_status->flag |= RX_FLAG_DECRYPTED; + + if (GET_RX_STATUS_DESC_BW(pdesc)) + rx_status->flag |= RX_FLAG_40MHZ; + + if (GET_RX_STATUS_DESC_RX_HT(pdesc)) + rx_status->flag |= RX_FLAG_HT; + + rx_status->flag |= RX_FLAG_MACTIME_MPDU; + + if (stats->decrypted) + rx_status->flag |= RX_FLAG_DECRYPTED; + + rx_status->rate_idx = _rtl92se_rate_mapping((bool) + GET_RX_STATUS_DESC_RX_HT(pdesc), + (u8)GET_RX_STATUS_DESC_RX_MCS(pdesc), + (bool)GET_RX_STATUS_DESC_PAGGR(pdesc)); + + + rx_status->mactime = GET_RX_STATUS_DESC_TSFL(pdesc); + if (phystatus == true) { + p_drvinfo = (struct rx_fwinfo *)(skb->data + + stats->rx_bufshift); + _rtl92se_translate_rx_signal_stuff(hw, skb, stats, pdesc, + p_drvinfo); + } + + /*rx_status->qual = stats->signal; */ + rx_status->signal = stats->rssi + 10; + /*rx_status->noise = -stats->noise; */ + + return true; +} + +void rtl92se_tx_fill_desc(struct ieee80211_hw *hw, + struct ieee80211_hdr *hdr, u8 *pdesc_tx, + struct ieee80211_tx_info *info, struct sk_buff *skb, + u8 hw_queue, struct rtl_tcb_desc *ptcb_desc) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); + struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); + struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); + struct ieee80211_sta *sta = info->control.sta; + u8 *pdesc = (u8 *) pdesc_tx; + u16 seq_number; + __le16 fc = hdr->frame_control; + u8 reserved_macid = 0; + u8 fw_qsel = _rtl92se_map_hwqueue_to_fwqueue(skb, hw_queue); + bool firstseg = (!(hdr->seq_ctrl & cpu_to_le16(IEEE80211_SCTL_FRAG))); + bool lastseg = (!(hdr->frame_control & + cpu_to_le16(IEEE80211_FCTL_MOREFRAGS))); + dma_addr_t mapping = pci_map_single(rtlpci->pdev, skb->data, skb->len, + PCI_DMA_TODEVICE); + u8 bw_40 = 0; + + if (mac->opmode == NL80211_IFTYPE_STATION) { + bw_40 = mac->bw_40; + } else if (mac->opmode == NL80211_IFTYPE_AP || + mac->opmode == NL80211_IFTYPE_ADHOC) { + if (sta) + bw_40 = sta->ht_cap.cap & + IEEE80211_HT_CAP_SUP_WIDTH_20_40; + } + + seq_number = (le16_to_cpu(hdr->seq_ctrl) & IEEE80211_SCTL_SEQ) >> 4; + + rtl_get_tcb_desc(hw, info, sta, skb, ptcb_desc); + + CLEAR_PCI_TX_DESC_CONTENT(pdesc, TX_DESC_SIZE_RTL8192S); + + if (firstseg) { + if (rtlpriv->dm.useramask) { + /* set txdesc macId */ + if (ptcb_desc->mac_id < 32) { + SET_TX_DESC_MACID(pdesc, ptcb_desc->mac_id); + reserved_macid |= ptcb_desc->mac_id; + } + } + SET_TX_DESC_RSVD_MACID(pdesc, reserved_macid); + + SET_TX_DESC_TXHT(pdesc, ((ptcb_desc->hw_rate >= + DESC92S_RATEMCS0) ? 1 : 0)); + + if (rtlhal->version == VERSION_8192S_ACUT) { + if (ptcb_desc->hw_rate == DESC92S_RATE1M || + ptcb_desc->hw_rate == DESC92S_RATE2M || + ptcb_desc->hw_rate == DESC92S_RATE5_5M || + ptcb_desc->hw_rate == DESC92S_RATE11M) { + ptcb_desc->hw_rate = DESC92S_RATE12M; + } + } + + SET_TX_DESC_TX_RATE(pdesc, ptcb_desc->hw_rate); + + if (ptcb_desc->use_shortgi || ptcb_desc->use_shortpreamble) + SET_TX_DESC_TX_SHORT(pdesc, 0); + + /* Aggregation related */ + if (info->flags & IEEE80211_TX_CTL_AMPDU) + SET_TX_DESC_AGG_ENABLE(pdesc, 1); + + /* For AMPDU, we must insert SSN into TX_DESC */ + SET_TX_DESC_SEQ(pdesc, seq_number); + + /* Protection mode related */ + /* For 92S, if RTS/CTS are set, HW will execute RTS. */ + /* We choose only one protection mode to execute */ + SET_TX_DESC_RTS_ENABLE(pdesc, ((ptcb_desc->rts_enable && + !ptcb_desc->cts_enable) ? 1 : 0)); + SET_TX_DESC_CTS_ENABLE(pdesc, ((ptcb_desc->cts_enable) ? + 1 : 0)); + SET_TX_DESC_RTS_STBC(pdesc, ((ptcb_desc->rts_stbc) ? 1 : 0)); + + SET_TX_DESC_RTS_RATE(pdesc, ptcb_desc->rts_rate); + SET_TX_DESC_RTS_BANDWIDTH(pdesc, 0); + SET_TX_DESC_RTS_SUB_CARRIER(pdesc, ptcb_desc->rts_sc); + SET_TX_DESC_RTS_SHORT(pdesc, ((ptcb_desc->rts_rate <= + DESC92S_RATE54M) ? + (ptcb_desc->rts_use_shortpreamble ? 1 : 0) + : (ptcb_desc->rts_use_shortgi ? 1 : 0))); + + + /* Set Bandwidth and sub-channel settings. */ + if (bw_40) { + if (ptcb_desc->packet_bw) { + SET_TX_DESC_TX_BANDWIDTH(pdesc, 1); + /* use duplicated mode */ + SET_TX_DESC_TX_SUB_CARRIER(pdesc, 0); + } else { + SET_TX_DESC_TX_BANDWIDTH(pdesc, 0); + SET_TX_DESC_TX_SUB_CARRIER(pdesc, + mac->cur_40_prime_sc); + } + } else { + SET_TX_DESC_TX_BANDWIDTH(pdesc, 0); + SET_TX_DESC_TX_SUB_CARRIER(pdesc, 0); + } + + /* 3 Fill necessary field in First Descriptor */ + /*DWORD 0*/ + SET_TX_DESC_LINIP(pdesc, 0); + SET_TX_DESC_OFFSET(pdesc, 32); + SET_TX_DESC_PKT_SIZE(pdesc, (u16) skb->len); + + /*DWORD 1*/ + SET_TX_DESC_RA_BRSR_ID(pdesc, ptcb_desc->ratr_index); + + /* Fill security related */ + if (info->control.hw_key) { + struct ieee80211_key_conf *keyconf; + + keyconf = info->control.hw_key; + switch (keyconf->cipher) { + case WLAN_CIPHER_SUITE_WEP40: + case WLAN_CIPHER_SUITE_WEP104: + SET_TX_DESC_SEC_TYPE(pdesc, 0x1); + break; + case WLAN_CIPHER_SUITE_TKIP: + SET_TX_DESC_SEC_TYPE(pdesc, 0x2); + break; + case WLAN_CIPHER_SUITE_CCMP: + SET_TX_DESC_SEC_TYPE(pdesc, 0x3); + break; + default: + SET_TX_DESC_SEC_TYPE(pdesc, 0x0); + break; + + } + } + + /* Set Packet ID */ + SET_TX_DESC_PACKET_ID(pdesc, 0); + + /* We will assign magement queue to BK. */ + SET_TX_DESC_QUEUE_SEL(pdesc, fw_qsel); + + /* Alwasy enable all rate fallback range */ + SET_TX_DESC_DATA_RATE_FB_LIMIT(pdesc, 0x1F); + + /* Fix: I don't kown why hw use 6.5M to tx when set it */ + SET_TX_DESC_USER_RATE(pdesc, + ptcb_desc->use_driver_rate ? 1 : 0); + + /* Set NON_QOS bit. */ + if (!ieee80211_is_data_qos(fc)) + SET_TX_DESC_NON_QOS(pdesc, 1); + + } + + /* Fill fields that are required to be initialized + * in all of the descriptors */ + /*DWORD 0 */ + SET_TX_DESC_FIRST_SEG(pdesc, (firstseg ? 1 : 0)); + SET_TX_DESC_LAST_SEG(pdesc, (lastseg ? 1 : 0)); + + /* DWORD 7 */ + SET_TX_DESC_TX_BUFFER_SIZE(pdesc, (u16) skb->len); + + /* DOWRD 8 */ + SET_TX_DESC_TX_BUFFER_ADDRESS(pdesc, cpu_to_le32(mapping)); + + RT_TRACE(rtlpriv, COMP_SEND, DBG_TRACE, ("\n")); +} + +void rtl92se_tx_fill_cmddesc(struct ieee80211_hw *hw, u8 *pdesc, + bool firstseg, bool lastseg, struct sk_buff *skb) +{ + struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); + struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); + struct rtl_tcb_desc *tcb_desc = (struct rtl_tcb_desc *)(skb->cb); + + dma_addr_t mapping = pci_map_single(rtlpci->pdev, skb->data, skb->len, + PCI_DMA_TODEVICE); + + /* Clear all status */ + CLEAR_PCI_TX_DESC_CONTENT(pdesc, TX_CMDDESC_SIZE_RTL8192S); + + /* This bit indicate this packet is used for FW download. */ + if (tcb_desc->cmd_or_init == DESC_PACKET_TYPE_INIT) { + /* For firmware downlaod we only need to set LINIP */ + SET_TX_DESC_LINIP(pdesc, tcb_desc->last_inipkt); + + /* 92SE must set as 1 for firmware download HW DMA error */ + SET_TX_DESC_FIRST_SEG(pdesc, 1); + SET_TX_DESC_LAST_SEG(pdesc, 1); + + /* 92SE need not to set TX packet size when firmware download */ + SET_TX_DESC_PKT_SIZE(pdesc, (u16)(skb->len)); + SET_TX_DESC_TX_BUFFER_SIZE(pdesc, (u16)(skb->len)); + SET_TX_DESC_TX_BUFFER_ADDRESS(pdesc, cpu_to_le32(mapping)); + + SET_TX_DESC_OWN(pdesc, 1); + } else { /* H2C Command Desc format (Host TXCMD) */ + /* 92SE must set as 1 for firmware download HW DMA error */ + SET_TX_DESC_FIRST_SEG(pdesc, 1); + SET_TX_DESC_LAST_SEG(pdesc, 1); + + SET_TX_DESC_OFFSET(pdesc, 0x20); + + /* Buffer size + command header */ + SET_TX_DESC_PKT_SIZE(pdesc, (u16)(skb->len)); + /* Fixed queue of H2C command */ + SET_TX_DESC_QUEUE_SEL(pdesc, 0x13); + + SET_BITS_TO_LE_4BYTE(skb->data, 24, 7, rtlhal->h2c_txcmd_seq); + + SET_TX_DESC_TX_BUFFER_SIZE(pdesc, (u16)(skb->len)); + SET_TX_DESC_TX_BUFFER_ADDRESS(pdesc, cpu_to_le32(mapping)); + + SET_TX_DESC_OWN(pdesc, 1); + + } +} + +void rtl92se_set_desc(u8 *pdesc, bool istx, u8 desc_name, u8 *val) +{ + if (istx == true) { + switch (desc_name) { + case HW_DESC_OWN: + SET_TX_DESC_OWN(pdesc, 1); + break; + case HW_DESC_TX_NEXTDESC_ADDR: + SET_TX_DESC_NEXT_DESC_ADDRESS(pdesc, *(u32 *) val); + break; + default: + RT_ASSERT(false, ("ERR txdesc :%d not process\n", + desc_name)); + break; + } + } else { + switch (desc_name) { + case HW_DESC_RXOWN: + SET_RX_STATUS_DESC_OWN(pdesc, 1); + break; + case HW_DESC_RXBUFF_ADDR: + SET_RX_STATUS__DESC_BUFF_ADDR(pdesc, *(u32 *) val); + break; + case HW_DESC_RXPKT_LEN: + SET_RX_STATUS_DESC_PKT_LEN(pdesc, *(u32 *) val); + break; + case HW_DESC_RXERO: + SET_RX_STATUS_DESC_EOR(pdesc, 1); + break; + default: + RT_ASSERT(false, ("ERR rxdesc :%d not process\n", + desc_name)); + break; + } + } +} + +u32 rtl92se_get_desc(u8 *desc, bool istx, u8 desc_name) +{ + u32 ret = 0; + + if (istx == true) { + switch (desc_name) { + case HW_DESC_OWN: + ret = GET_TX_DESC_OWN(desc); + break; + case HW_DESC_TXBUFF_ADDR: + ret = GET_TX_DESC_TX_BUFFER_ADDRESS(desc); + break; + default: + RT_ASSERT(false, ("ERR txdesc :%d not process\n", + desc_name)); + break; + } + } else { + switch (desc_name) { + case HW_DESC_OWN: + ret = GET_RX_STATUS_DESC_OWN(desc); + break; + case HW_DESC_RXPKT_LEN: + ret = GET_RX_STATUS_DESC_PKT_LEN(desc); + break; + default: + RT_ASSERT(false, ("ERR rxdesc :%d not process\n", + desc_name)); + break; + } + } + return ret; +} + +void rtl92se_tx_polling(struct ieee80211_hw *hw, u8 hw_queue) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + rtl_write_word(rtlpriv, TP_POLL, BIT(0) << (hw_queue)); +} diff --git a/drivers/net/wireless/rtlwifi/rtl8192se/trx.h b/drivers/net/wireless/rtlwifi/rtl8192se/trx.h new file mode 100644 index 0000000..05862c5 --- /dev/null +++ b/drivers/net/wireless/rtlwifi/rtl8192se/trx.h @@ -0,0 +1,45 @@ +/****************************************************************************** + * + * Copyright(c) 2009-2010 Realtek Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger + * + *****************************************************************************/ +#ifndef __REALTEK_PCI92SE_TRX_H__ +#define __REALTEK_PCI92SE_TRX_H__ + +void rtl92se_tx_fill_desc(struct ieee80211_hw *hw, struct ieee80211_hdr *hdr, + u8 *pdesc, struct ieee80211_tx_info *info, + struct sk_buff *skb, u8 hw_queue, + struct rtl_tcb_desc *ptcb_desc); +void rtl92se_tx_fill_cmddesc(struct ieee80211_hw *hw, u8 *pdesc, bool firstseg, + bool lastseg, struct sk_buff *skb); +bool rtl92se_rx_query_desc(struct ieee80211_hw *hw, struct rtl_stats *stats, + struct ieee80211_rx_status *rx_status, u8 *pdesc, + struct sk_buff *skb); +void rtl92se_set_desc(u8 *pdesc, bool istx, u8 desc_name, u8 *val); +u32 rtl92se_get_desc(u8 *pdesc, bool istx, u8 desc_name); +void rtl92se_tx_polling(struct ieee80211_hw *hw, u8 hw_queue); + +#endif -- cgit v0.10.2 From 85e09b40405b44b049500702beb6856646b4be46 Mon Sep 17 00:00:00 2001 From: Chaoming Li Date: Tue, 3 May 2011 09:49:36 -0500 Subject: rtlwifi: rtl8192se: Modify Kconfig and Makefile routines for new driver Modify rtlwifi routines for rtl8192se and set up Kconfig and Makefile for new driver. This patch also disables ASPM for the RTL8192SE to prevent some strange crashes on LF's system. Signed-off-by: Chaoming_Li Signed-off-by: Larry Finger Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/rtlwifi/Kconfig b/drivers/net/wireless/rtlwifi/Kconfig index ce49e0c..5aee8b2 100644 --- a/drivers/net/wireless/rtlwifi/Kconfig +++ b/drivers/net/wireless/rtlwifi/Kconfig @@ -10,6 +10,17 @@ config RTL8192CE If you choose to build it as a module, it will be called rtl8192ce +config RTL8192SE + tristate "Realtek RTL8192SE/RTL8191SE PCIe Wireless Network Adapter" + depends on MAC80211 && EXPERIMENTAL + select FW_LOADER + select RTLWIFI + ---help--- + This is the driver for Realtek RTL8192SE/RTL8191SE 802.11n PCIe + wireless network adapters. + + If you choose to build it as a module, it will be called rtl8192se + config RTL8192CU tristate "Realtek RTL8192CU/RTL8188CU USB Wireless Network Adapter" depends on MAC80211 && USB && EXPERIMENTAL @@ -24,10 +35,10 @@ config RTL8192CU config RTLWIFI tristate - depends on RTL8192CE || RTL8192CU + depends on RTL8192CE || RTL8192CU || RTL8192SE default m config RTL8192C_COMMON tristate - depends on RTL8192CE || RTL8192CU + depends on RTL8192CE || RTL8192CU || RTL8192SE default m diff --git a/drivers/net/wireless/rtlwifi/Makefile b/drivers/net/wireless/rtlwifi/Makefile index ec9393f..7acce83 100644 --- a/drivers/net/wireless/rtlwifi/Makefile +++ b/drivers/net/wireless/rtlwifi/Makefile @@ -22,5 +22,6 @@ endif obj-$(CONFIG_RTL8192C_COMMON) += rtl8192c/ obj-$(CONFIG_RTL8192CE) += rtl8192ce/ obj-$(CONFIG_RTL8192CU) += rtl8192cu/ +obj-$(CONFIG_RTL8192SE) += rtl8192se/ ccflags-y += -D__CHECK_ENDIAN__ diff --git a/drivers/net/wireless/rtlwifi/rtl8192se/Makefile b/drivers/net/wireless/rtlwifi/rtl8192se/Makefile new file mode 100644 index 0000000..b7eb138 --- /dev/null +++ b/drivers/net/wireless/rtlwifi/rtl8192se/Makefile @@ -0,0 +1,15 @@ +rtl8192se-objs := \ + dm.o \ + fw.o \ + hw.o \ + led.o \ + phy.o \ + rf.o \ + sw.o \ + table.o \ + trx.o + +obj-$(CONFIG_RTL8192SE) += rtl8192se.o + +ccflags-y += -D__CHECK_ENDIAN__ + diff --git a/drivers/net/wireless/rtlwifi/rtl8192se/sw.c b/drivers/net/wireless/rtlwifi/rtl8192se/sw.c index c5351b6..7cfd6a2c 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192se/sw.c +++ b/drivers/net/wireless/rtlwifi/rtl8192se/sw.c @@ -58,7 +58,7 @@ static void rtl92s_init_aspm_vars(struct ieee80211_hw *hw) * 4 - Always Enable ASPM without Clock Req. * set defult to RTL8192CE:3 RTL8192E:2 * */ - rtlpci->const_pci_aspm = 2; + rtlpci->const_pci_aspm = 0; /* changed from 2 due to crashes */ /*Setting for PCI-E device */ rtlpci->const_devicepci_aspm_setting = 0x03; -- cgit v0.10.2 From 57f16b5da03784d1660133fbec7281ea5735da69 Mon Sep 17 00:00:00 2001 From: Amitkumar Karwar Date: Tue, 3 May 2011 20:11:45 -0700 Subject: mwifiex: fix simultaneous assoc and scan issue When scan and assoc (infra/ibss) commands are simultaneously given in two terminals, association response is erroneously served while serving the scan response. mwifiex_cfg80211_results() is the common routine for sending ioctl (scan, assoc etc.) results to cfg80211 stack. In above scenario even if the common routine is called for scan ioctl context, it also tries to send information about assoc ioctl to cfg80211 because "priv->assoc_request/priv->ibss_join_request" flag is on at that time. Fix the issue by updating request variable after assoc handling and modifying the variable check in mwifiex_cfg80211_results. Signed-off-by: Amitkumar Karwar Signed-off-by: Kiran Divekar Signed-off-by: Bing Zhao Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/mwifiex/cfg80211.c b/drivers/net/wireless/mwifiex/cfg80211.c index 98009e2..77a8029 100644 --- a/drivers/net/wireless/mwifiex/cfg80211.c +++ b/drivers/net/wireless/mwifiex/cfg80211.c @@ -1044,7 +1044,7 @@ mwifiex_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev, goto done; } - priv->assoc_request = 1; + priv->assoc_request = -EINPROGRESS; wiphy_dbg(wiphy, "info: Trying to associate to %s and bssid %pM\n", (char *) sme->ssid, sme->bssid); @@ -1052,6 +1052,7 @@ mwifiex_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev, ret = mwifiex_cfg80211_assoc(priv, sme->ssid_len, sme->ssid, sme->bssid, priv->bss_mode, sme->channel, sme, 0); + priv->assoc_request = 1; done: priv->assoc_result = ret; queue_work(priv->workqueue, &priv->cfg_workqueue); @@ -1080,7 +1081,7 @@ mwifiex_cfg80211_join_ibss(struct wiphy *wiphy, struct net_device *dev, goto done; } - priv->ibss_join_request = 1; + priv->ibss_join_request = -EINPROGRESS; wiphy_dbg(wiphy, "info: trying to join to %s and bssid %pM\n", (char *) params->ssid, params->bssid); @@ -1088,6 +1089,8 @@ mwifiex_cfg80211_join_ibss(struct wiphy *wiphy, struct net_device *dev, ret = mwifiex_cfg80211_assoc(priv, params->ssid_len, params->ssid, params->bssid, priv->bss_mode, params->channel, NULL, params->privacy); + + priv->ibss_join_request = 1; done: priv->ibss_join_result = ret; queue_work(priv->workqueue, &priv->cfg_workqueue); @@ -1380,7 +1383,7 @@ done: kfree(scan_req); } - if (priv->assoc_request) { + if (priv->assoc_request == 1) { if (!priv->assoc_result) { cfg80211_connect_result(priv->netdev, priv->cfg_bssid, NULL, 0, NULL, 0, @@ -1399,7 +1402,7 @@ done: priv->assoc_result = 0; } - if (priv->ibss_join_request) { + if (priv->ibss_join_request == 1) { if (!priv->ibss_join_result) { cfg80211_ibss_joined(priv->netdev, priv->cfg_bssid, GFP_KERNEL); diff --git a/drivers/net/wireless/mwifiex/main.h b/drivers/net/wireless/mwifiex/main.h index 5043fcd..b4bb5ec 100644 --- a/drivers/net/wireless/mwifiex/main.h +++ b/drivers/net/wireless/mwifiex/main.h @@ -479,9 +479,9 @@ struct mwifiex_private { u8 report_scan_result; struct cfg80211_scan_request *scan_request; int scan_result_status; - bool assoc_request; + int assoc_request; u16 assoc_result; - bool ibss_join_request; + int ibss_join_request; u16 ibss_join_result; bool disconnect; u8 cfg_bssid[6]; -- cgit v0.10.2 From 270e58e8898c8be40451ebee45b6c9b5bd5db04b Mon Sep 17 00:00:00 2001 From: Yogesh Ashok Powar Date: Tue, 3 May 2011 20:11:46 -0700 Subject: mwifiex: remove unnecessary variable initialization Skip initialization of local variables with some default values if the values are not going to be used further down the code path. Signed-off-by: Yogesh Ashok Powar Signed-off-by: Bing Zhao Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/mwifiex/11n.c b/drivers/net/wireless/mwifiex/11n.c index 1d294cf..916183d 100644 --- a/drivers/net/wireless/mwifiex/11n.c +++ b/drivers/net/wireless/mwifiex/11n.c @@ -187,7 +187,7 @@ int mwifiex_ret_11n_addba_req(struct mwifiex_private *priv, */ int mwifiex_ret_11n_cfg(struct host_cmd_ds_command *resp, void *data_buf) { - struct mwifiex_ds_11n_tx_cfg *tx_cfg = NULL; + struct mwifiex_ds_11n_tx_cfg *tx_cfg; struct host_cmd_ds_11n_cfg *htcfg = &resp->params.htcfg; if (data_buf) { @@ -274,7 +274,7 @@ int mwifiex_cmd_amsdu_aggr_ctrl(struct host_cmd_ds_command *cmd, int mwifiex_ret_amsdu_aggr_ctrl(struct host_cmd_ds_command *resp, void *data_buf) { - struct mwifiex_ds_11n_amsdu_aggr_ctrl *amsdu_aggr_ctrl = NULL; + struct mwifiex_ds_11n_amsdu_aggr_ctrl *amsdu_aggr_ctrl; struct host_cmd_ds_amsdu_aggr_ctrl *amsdu_ctrl = &resp->params.amsdu_aggr_ctrl; @@ -461,8 +461,7 @@ mwifiex_cfg_tx_buf(struct mwifiex_private *priv, struct mwifiex_bssdescriptor *bss_desc) { u16 max_amsdu = MWIFIEX_TX_DATA_BUF_SIZE_2K; - u16 tx_buf = 0; - u16 curr_tx_buf_size = 0; + u16 tx_buf, curr_tx_buf_size = 0; if (bss_desc->bcn_ht_cap) { if (le16_to_cpu(bss_desc->bcn_ht_cap->cap_info) & diff --git a/drivers/net/wireless/mwifiex/11n_aggr.c b/drivers/net/wireless/mwifiex/11n_aggr.c index c9fb062..12cf424 100644 --- a/drivers/net/wireless/mwifiex/11n_aggr.c +++ b/drivers/net/wireless/mwifiex/11n_aggr.c @@ -60,7 +60,7 @@ mwifiex_11n_form_amsdu_pkt(struct sk_buff *skb_aggr, * later with ethertype */ }; - struct tx_packet_hdr *tx_header = NULL; + struct tx_packet_hdr *tx_header; skb_put(skb_aggr, sizeof(*tx_header)); @@ -182,7 +182,7 @@ int mwifiex_11n_deaggregate_pkt(struct mwifiex_private *priv, struct mwifiex_rxinfo *rx_info = MWIFIEX_SKB_RXCB(skb); struct rxpd *local_rx_pd = (struct rxpd *) skb->data; struct sk_buff *skb_daggr; - struct mwifiex_rxinfo *rx_info_daggr = NULL; + struct mwifiex_rxinfo *rx_info_daggr; int ret = -1; struct rx_packet_hdr *rx_pkt_hdr; struct mwifiex_adapter *adapter = priv->adapter; @@ -285,8 +285,7 @@ mwifiex_11n_aggregate_pkt(struct mwifiex_private *priv, struct mwifiex_adapter *adapter = priv->adapter; struct sk_buff *skb_aggr, *skb_src; struct mwifiex_txinfo *tx_info_aggr, *tx_info_src; - int pad = 0; - int ret = 0; + int pad = 0, ret; struct mwifiex_tx_param tx_param; struct txpd *ptx_pd = NULL; diff --git a/drivers/net/wireless/mwifiex/11n_rxreorder.c b/drivers/net/wireless/mwifiex/11n_rxreorder.c index a93c03f..e5dfdc3 100644 --- a/drivers/net/wireless/mwifiex/11n_rxreorder.c +++ b/drivers/net/wireless/mwifiex/11n_rxreorder.c @@ -39,7 +39,7 @@ mwifiex_11n_dispatch_pkt_until_start_win(struct mwifiex_private *priv, *rx_reor_tbl_ptr, int start_win) { int no_pkt_to_send, i; - void *rx_tmp_ptr = NULL; + void *rx_tmp_ptr; unsigned long flags; no_pkt_to_send = (start_win > rx_reor_tbl_ptr->start_win) ? @@ -88,7 +88,7 @@ mwifiex_11n_scan_and_dispatch(struct mwifiex_private *priv, struct mwifiex_rx_reorder_tbl *rx_reor_tbl_ptr) { int i, j, xchg; - void *rx_tmp_ptr = NULL; + void *rx_tmp_ptr; unsigned long flags; for (i = 0; i < rx_reor_tbl_ptr->win_size; ++i) { @@ -335,8 +335,8 @@ int mwifiex_cmd_11n_addba_rsp_gen(struct mwifiex_private *priv, &cmd->params.add_ba_rsp; struct host_cmd_ds_11n_addba_req *cmd_addba_req = (struct host_cmd_ds_11n_addba_req *) data_buf; - u8 tid = 0; - int win_size = 0; + u8 tid; + int win_size; uint16_t block_ack_param_set; cmd->command = cpu_to_le16(HostCmd_CMD_11N_ADDBA_RSP); @@ -406,9 +406,8 @@ int mwifiex_11n_rx_reorder_pkt(struct mwifiex_private *priv, u8 *ta, u8 pkt_type, void *payload) { struct mwifiex_rx_reorder_tbl *rx_reor_tbl_ptr; - int start_win, end_win, win_size; - int ret = 0; - u16 pkt_index = 0; + int start_win, end_win, win_size, ret; + u16 pkt_index; rx_reor_tbl_ptr = mwifiex_11n_get_rx_reorder_tbl((struct mwifiex_private *) priv, @@ -540,7 +539,7 @@ int mwifiex_ret_11n_addba_resp(struct mwifiex_private *priv, (struct host_cmd_ds_11n_addba_rsp *) &resp->params.add_ba_rsp; int tid, win_size; - struct mwifiex_rx_reorder_tbl *rx_reor_tbl_ptr = NULL; + struct mwifiex_rx_reorder_tbl *rx_reor_tbl_ptr; uint16_t block_ack_param_set; block_ack_param_set = le16_to_cpu(add_ba_rsp->block_ack_param_set); diff --git a/drivers/net/wireless/mwifiex/cfg80211.c b/drivers/net/wireless/mwifiex/cfg80211.c index 77a8029..0c011637 100644 --- a/drivers/net/wireless/mwifiex/cfg80211.c +++ b/drivers/net/wireless/mwifiex/cfg80211.c @@ -77,18 +77,15 @@ mwifiex_channels_to_cfg80211_channel_type(int channel_type) static int mwifiex_is_alg_wep(u32 cipher) { - int alg = 0; - switch (cipher) { case WLAN_CIPHER_SUITE_WEP40: case WLAN_CIPHER_SUITE_WEP104: - alg = 1; - break; + return 1; default: - alg = 0; break; } - return alg; + + return 0; } /* @@ -408,7 +405,7 @@ mwifiex_cfg80211_set_channel(struct wiphy *wiphy, struct net_device *dev, static int mwifiex_set_frag(struct mwifiex_private *priv, u32 frag_thr) { - int ret = 0; + int ret; if (frag_thr < MWIFIEX_FRAG_MIN_VALUE || frag_thr > MWIFIEX_FRAG_MAX_VALUE) @@ -449,7 +446,6 @@ static int mwifiex_cfg80211_set_wiphy_params(struct wiphy *wiphy, u32 changed) { struct mwifiex_private *priv = mwifiex_cfg80211_get_priv(wiphy); - int ret = 0; if (changed & WIPHY_PARAM_RTS_THRESHOLD) { @@ -473,7 +469,7 @@ mwifiex_cfg80211_change_virtual_intf(struct wiphy *wiphy, enum nl80211_iftype type, u32 *flags, struct vif_params *params) { - int ret = 0; + int ret; struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev); if (priv->bss_mode == type) { @@ -717,7 +713,7 @@ static int mwifiex_cfg80211_inform_ibss_bss(struct mwifiex_private *priv) { struct ieee80211_channel *chan; struct mwifiex_bss_info bss_info; - int ie_len = 0; + int ie_len; u8 ie_buf[IEEE80211_MAX_SSID_LEN + sizeof(struct ieee_types_header)]; if (mwifiex_get_bss_info(priv, &bss_info)) @@ -903,8 +899,7 @@ mwifiex_cfg80211_assoc(struct mwifiex_private *priv, size_t ssid_len, u8 *ssid, { struct mwifiex_802_11_ssid req_ssid; struct mwifiex_ssid_bssid ssid_bssid; - int ret = 0; - int auth_type = 0; + int ret, auth_type = 0; memset(&req_ssid, 0, sizeof(struct mwifiex_802_11_ssid)); memset(&ssid_bssid, 0, sizeof(struct mwifiex_ssid_bssid)); @@ -1247,8 +1242,8 @@ static struct cfg80211_ops mwifiex_cfg80211_ops = { int mwifiex_register_cfg80211(struct net_device *dev, u8 *mac, struct mwifiex_private *priv) { - int ret = 0; - void *wdev_priv = NULL; + int ret; + void *wdev_priv; struct wireless_dev *wdev; wdev = kzalloc(sizeof(struct wireless_dev), GFP_KERNEL); diff --git a/drivers/net/wireless/mwifiex/cmdevt.c b/drivers/net/wireless/mwifiex/cmdevt.c index 776146a..b75cc92 100644 --- a/drivers/net/wireless/mwifiex/cmdevt.c +++ b/drivers/net/wireless/mwifiex/cmdevt.c @@ -128,7 +128,7 @@ static int mwifiex_dnld_cmd_to_fw(struct mwifiex_private *priv, { struct mwifiex_adapter *adapter = priv->adapter; - int ret = 0; + int ret; struct host_cmd_ds_command *host_cmd; uint16_t cmd_code; uint16_t cmd_size; @@ -222,8 +222,8 @@ static int mwifiex_dnld_cmd_to_fw(struct mwifiex_private *priv, */ static int mwifiex_dnld_sleep_confirm_cmd(struct mwifiex_adapter *adapter) { - int ret = 0; - u16 cmd_len = 0; + int ret; + u16 cmd_len; struct mwifiex_private *priv; struct mwifiex_opt_sleep_confirm_buffer *sleep_cfm_buf = (struct mwifiex_opt_sleep_confirm_buffer *) @@ -364,13 +364,13 @@ int mwifiex_free_cmd_buffer(struct mwifiex_adapter *adapter) */ int mwifiex_process_event(struct mwifiex_adapter *adapter) { - int ret = 0; + int ret; struct mwifiex_private *priv = mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_ANY); struct sk_buff *skb = adapter->event_skb; u32 eventcause = adapter->event_cause; struct timeval tstamp; - struct mwifiex_rxinfo *rx_info = NULL; + struct mwifiex_rxinfo *rx_info; /* Save the last event to debug log */ adapter->dbg.last_event_index = @@ -446,10 +446,10 @@ int mwifiex_send_cmd_sync(struct mwifiex_private *priv, uint16_t cmd_no, int mwifiex_send_cmd_async(struct mwifiex_private *priv, uint16_t cmd_no, u16 cmd_action, u32 cmd_oid, void *data_buf) { - int ret = 0; + int ret; struct mwifiex_adapter *adapter = priv->adapter; - struct cmd_ctrl_node *cmd_node = NULL; - struct host_cmd_ds_command *cmd_ptr = NULL; + struct cmd_ctrl_node *cmd_node; + struct host_cmd_ds_command *cmd_ptr; if (!adapter) { pr_err("PREP_CMD: adapter is NULL\n"); @@ -605,8 +605,8 @@ mwifiex_insert_cmd_to_pending_q(struct mwifiex_adapter *adapter, */ int mwifiex_exec_next_cmd(struct mwifiex_adapter *adapter) { - struct mwifiex_private *priv = NULL; - struct cmd_ctrl_node *cmd_node = NULL; + struct mwifiex_private *priv; + struct cmd_ctrl_node *cmd_node; int ret = 0; struct host_cmd_ds_command *host_cmd; unsigned long cmd_flags; @@ -673,7 +673,7 @@ int mwifiex_exec_next_cmd(struct mwifiex_adapter *adapter) */ int mwifiex_process_cmdresp(struct mwifiex_adapter *adapter) { - struct host_cmd_ds_command *resp = NULL; + struct host_cmd_ds_command *resp; struct mwifiex_private *priv = mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_ANY); int ret = 0; @@ -805,7 +805,7 @@ mwifiex_cmd_timeout_func(unsigned long function_context) { struct mwifiex_adapter *adapter = (struct mwifiex_adapter *) function_context; - struct cmd_ctrl_node *cmd_node = NULL; + struct cmd_ctrl_node *cmd_node; struct timeval tstamp; adapter->num_cmd_timeout++; @@ -877,7 +877,7 @@ mwifiex_cmd_timeout_func(unsigned long function_context) void mwifiex_cancel_all_pending_cmd(struct mwifiex_adapter *adapter) { - struct cmd_ctrl_node *cmd_node = NULL, *tmp_node = NULL; + struct cmd_ctrl_node *cmd_node = NULL, *tmp_node; unsigned long flags; /* Cancel current cmd */ @@ -1160,7 +1160,7 @@ int mwifiex_cmd_enh_power_mode(struct mwifiex_private *priv, { struct host_cmd_ds_802_11_ps_mode_enh *psmode_enh = &cmd->params.psmode_enh; - u8 *tlv = NULL; + u8 *tlv; u16 cmd_size = 0; cmd->command = cpu_to_le16(HostCmd_CMD_802_11_PS_MODE_ENH); diff --git a/drivers/net/wireless/mwifiex/debugfs.c b/drivers/net/wireless/mwifiex/debugfs.c index 7ddcb06..46d65e0 100644 --- a/drivers/net/wireless/mwifiex/debugfs.c +++ b/drivers/net/wireless/mwifiex/debugfs.c @@ -193,7 +193,7 @@ mwifiex_info_read(struct file *file, char __user *ubuf, unsigned long page = get_zeroed_page(GFP_KERNEL); char *p = (char *) page, fmt[64]; struct mwifiex_bss_info info; - ssize_t ret = 0; + ssize_t ret; int i = 0; if (!p) @@ -288,7 +288,7 @@ mwifiex_getlog_read(struct file *file, char __user *ubuf, (struct mwifiex_private *) file->private_data; unsigned long page = get_zeroed_page(GFP_KERNEL); char *p = (char *) page; - ssize_t ret = 0; + ssize_t ret; struct mwifiex_ds_get_stats stats; if (!p) @@ -400,7 +400,7 @@ mwifiex_debug_read(struct file *file, char __user *ubuf, struct mwifiex_debug_data *d = &items[0]; unsigned long page = get_zeroed_page(GFP_KERNEL); char *p = (char *) page; - ssize_t ret = 0; + ssize_t ret; size_t size, addr; long val; int i, j; @@ -507,7 +507,7 @@ mwifiex_regrdwr_write(struct file *file, unsigned long addr = get_zeroed_page(GFP_KERNEL); char *buf = (char *) addr; size_t buf_size = min(count, (size_t) (PAGE_SIZE - 1)); - int ret = 0; + int ret; u32 reg_type = 0, reg_offset = 0, reg_value = UINT_MAX; if (!buf) @@ -650,7 +650,7 @@ mwifiex_rdeeprom_read(struct file *file, char __user *ubuf, (struct mwifiex_private *) file->private_data; unsigned long addr = get_zeroed_page(GFP_KERNEL); char *buf = (char *) addr; - int pos = 0, ret = 0, i = 0; + int pos = 0, ret = 0, i; u8 value[MAX_EEPROM_DATA]; if (!buf) diff --git a/drivers/net/wireless/mwifiex/init.c b/drivers/net/wireless/mwifiex/init.c index fc2c0c5..27ad72b 100644 --- a/drivers/net/wireless/mwifiex/init.c +++ b/drivers/net/wireless/mwifiex/init.c @@ -151,7 +151,7 @@ static int mwifiex_init_priv(struct mwifiex_private *priv) */ static int mwifiex_allocate_adapter(struct mwifiex_adapter *adapter) { - int ret = 0; + int ret; u32 buf_size; struct mwifiex_bssdescriptor *temp_scan_table; @@ -342,9 +342,8 @@ mwifiex_free_adapter(struct mwifiex_adapter *adapter) */ int mwifiex_init_lock_list(struct mwifiex_adapter *adapter) { - struct mwifiex_private *priv = NULL; - s32 i = 0; - u32 j = 0; + struct mwifiex_private *priv; + s32 i, j; spin_lock_init(&adapter->mwifiex_lock); spin_lock_init(&adapter->int_lock); @@ -400,9 +399,8 @@ int mwifiex_init_lock_list(struct mwifiex_adapter *adapter) */ void mwifiex_free_lock_list(struct mwifiex_adapter *adapter) { - struct mwifiex_private *priv = NULL; - s32 i = 0; - s32 j = 0; + struct mwifiex_private *priv; + s32 i, j; /* Free lists */ list_del(&adapter->cmd_free_q); @@ -436,10 +434,9 @@ void mwifiex_free_lock_list(struct mwifiex_adapter *adapter) */ int mwifiex_init_fw(struct mwifiex_adapter *adapter) { - int ret = 0; - struct mwifiex_private *priv = NULL; - u8 i = 0; - u8 first_sta = true; + int ret; + struct mwifiex_private *priv; + u8 i, first_sta = true; int is_cmd_pend_q_empty; unsigned long flags; @@ -497,8 +494,7 @@ static void mwifiex_delete_bss_prio_tbl(struct mwifiex_private *priv) { int i; struct mwifiex_adapter *adapter = priv->adapter; - struct mwifiex_bss_prio_node *bssprio_node = NULL, *tmp_node = NULL, - **cur = NULL; + struct mwifiex_bss_prio_node *bssprio_node, *tmp_node, **cur; struct list_head *head; spinlock_t *lock; unsigned long flags; @@ -552,8 +548,8 @@ int mwifiex_shutdown_drv(struct mwifiex_adapter *adapter) { int ret = -EINPROGRESS; - struct mwifiex_private *priv = NULL; - s32 i = 0; + struct mwifiex_private *priv; + s32 i; unsigned long flags; /* mwifiex already shutdown */ @@ -608,9 +604,8 @@ mwifiex_shutdown_drv(struct mwifiex_adapter *adapter) int mwifiex_dnld_fw(struct mwifiex_adapter *adapter, struct mwifiex_fw_image *pmfw) { - int ret = 0; + int ret, winner; u32 poll_num = 1; - int winner; /* Check if firmware is already running */ ret = adapter->if_ops.check_fw_status(adapter, poll_num, &winner); diff --git a/drivers/net/wireless/mwifiex/join.c b/drivers/net/wireless/mwifiex/join.c index 85fca5e..5eab3dc 100644 --- a/drivers/net/wireless/mwifiex/join.c +++ b/drivers/net/wireless/mwifiex/join.c @@ -143,9 +143,8 @@ mwifiex_cmd_append_tsf_tlv(struct mwifiex_private *priv, u8 **buffer, static int mwifiex_get_common_rates(struct mwifiex_private *priv, u8 *rate1, u32 rate1_size, u8 *rate2, u32 rate2_size) { - int ret = 0; - u8 *ptr = rate1; - u8 *tmp = NULL; + int ret; + u8 *ptr = rate1, *tmp; u32 i, j; tmp = kmalloc(rate1_size, GFP_KERNEL); @@ -203,7 +202,7 @@ mwifiex_setup_rates_from_bssdesc(struct mwifiex_private *priv, u8 *out_rates, u32 *out_rates_size) { u8 card_rates[MWIFIEX_SUPPORTED_RATES]; - u32 card_rates_size = 0; + u32 card_rates_size; /* Copy AP supported rates */ memcpy(out_rates, bss_desc->supported_rates, MWIFIEX_SUPPORTED_RATES); @@ -1359,7 +1358,7 @@ int mwifiex_adhoc_join(struct mwifiex_private *priv, static int mwifiex_deauthenticate_infra(struct mwifiex_private *priv, u8 *mac) { u8 mac_address[ETH_ALEN]; - int ret = 0; + int ret; u8 zero_mac[ETH_ALEN] = { 0, 0, 0, 0, 0, 0 }; if (mac) { diff --git a/drivers/net/wireless/mwifiex/main.c b/drivers/net/wireless/mwifiex/main.c index c597188..38f912b 100644 --- a/drivers/net/wireless/mwifiex/main.c +++ b/drivers/net/wireless/mwifiex/main.c @@ -150,7 +150,7 @@ error: */ static int mwifiex_unregister(struct mwifiex_adapter *adapter) { - s32 i = 0; + s32 i; del_timer(&adapter->cmd_timer); @@ -379,8 +379,7 @@ static void mwifiex_free_adapter(struct mwifiex_adapter *adapter) */ static int mwifiex_init_hw_fw(struct mwifiex_adapter *adapter) { - int ret = 0; - int err; + int ret, err; struct mwifiex_fw_image fw; memset(&fw, 0, sizeof(struct mwifiex_fw_image)); @@ -449,7 +448,7 @@ done: static void mwifiex_fill_buffer(struct sk_buff *skb) { - struct ethhdr *eth = NULL; + struct ethhdr *eth; struct iphdr *iph; struct timeval tv; u8 tid = 0; @@ -510,7 +509,7 @@ static int mwifiex_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) { struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev); - struct sk_buff *new_skb = NULL; + struct sk_buff *new_skb; struct mwifiex_txinfo *tx_info; dev_dbg(priv->adapter->dev, "data: %lu BSS(%d): Data <= kernel\n", @@ -571,7 +570,7 @@ mwifiex_set_mac_address(struct net_device *dev, void *addr) { struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev); struct sockaddr *hw_addr = (struct sockaddr *) addr; - int ret = 0; + int ret; memcpy(priv->curr_addr, hw_addr->sa_data, ETH_ALEN); @@ -696,9 +695,9 @@ static struct mwifiex_private *mwifiex_add_interface( struct mwifiex_adapter *adapter, u8 bss_index, u8 bss_type) { - struct net_device *dev = NULL; - struct mwifiex_private *priv = NULL; - void *mdev_priv = NULL; + struct net_device *dev; + struct mwifiex_private *priv; + void *mdev_priv; dev = alloc_netdev_mq(sizeof(struct mwifiex_private *), "mlan%d", ether_setup, 1); @@ -763,7 +762,7 @@ error: static void mwifiex_remove_interface(struct mwifiex_adapter *adapter, u8 bss_index) { - struct net_device *dev = NULL; + struct net_device *dev; struct mwifiex_private *priv = adapter->priv[bss_index]; if (!priv) diff --git a/drivers/net/wireless/mwifiex/scan.c b/drivers/net/wireless/mwifiex/scan.c index 31a5295..4968974 100644 --- a/drivers/net/wireless/mwifiex/scan.c +++ b/drivers/net/wireless/mwifiex/scan.c @@ -117,8 +117,8 @@ mwifiex_search_oui_in_ie(struct ie_body *iebody, u8 *oui) static u8 mwifiex_is_rsn_oui_present(struct mwifiex_bssdescriptor *bss_desc, u32 cipher) { - u8 *oui = NULL; - struct ie_body *iebody = NULL; + u8 *oui; + struct ie_body *iebody; u8 ret = MWIFIEX_OUI_NOT_PRESENT; if (((bss_desc->bcn_rsn_ie) && ((*(bss_desc->bcn_rsn_ie)). @@ -144,8 +144,8 @@ mwifiex_is_rsn_oui_present(struct mwifiex_bssdescriptor *bss_desc, u32 cipher) static u8 mwifiex_is_wpa_oui_present(struct mwifiex_bssdescriptor *bss_desc, u32 cipher) { - u8 *oui = NULL; - struct ie_body *iebody = NULL; + u8 *oui; + struct ie_body *iebody; u8 ret = MWIFIEX_OUI_NOT_PRESENT; if (((bss_desc->bcn_wpa_ie) && ((*(bss_desc->bcn_wpa_ie)). @@ -181,7 +181,7 @@ int mwifiex_find_best_bss(struct mwifiex_private *priv, struct mwifiex_ssid_bssid *ssid_bssid) { struct mwifiex_ssid_bssid tmp_ssid_bssid; - u8 *mac = NULL; + u8 *mac; if (!ssid_bssid) return -1; @@ -213,7 +213,7 @@ int mwifiex_find_best_bss(struct mwifiex_private *priv, int mwifiex_set_user_scan_ioctl(struct mwifiex_private *priv, struct mwifiex_user_scan_cfg *scan_req) { - int status = 0; + int status; priv->adapter->cmd_wait_q.condition = false; @@ -2253,8 +2253,8 @@ int mwifiex_scan_networks(struct mwifiex_private *priv, { int ret = 0; struct mwifiex_adapter *adapter = priv->adapter; - struct cmd_ctrl_node *cmd_node = NULL; - union mwifiex_scan_cmd_config_tlv *scan_cfg_out = NULL; + struct cmd_ctrl_node *cmd_node; + union mwifiex_scan_cmd_config_tlv *scan_cfg_out; struct mwifiex_ie_types_chan_list_param_set *chan_list_out; u32 buf_size; struct mwifiex_chan_scan_param_set *scan_chan_list; @@ -2404,8 +2404,8 @@ int mwifiex_ret_802_11_scan(struct mwifiex_private *priv, { int ret = 0; struct mwifiex_adapter *adapter = priv->adapter; - struct cmd_ctrl_node *cmd_node = NULL; - struct host_cmd_ds_802_11_scan_rsp *scan_rsp = NULL; + struct cmd_ctrl_node *cmd_node; + struct host_cmd_ds_802_11_scan_rsp *scan_rsp; struct mwifiex_bssdescriptor *bss_new_entry = NULL; struct mwifiex_ie_types_data *tlv_data; struct mwifiex_ie_types_tsf_timestamp *tsf_tlv; @@ -2906,7 +2906,7 @@ static int mwifiex_scan_specific_ssid(struct mwifiex_private *priv, int mwifiex_request_scan(struct mwifiex_private *priv, struct mwifiex_802_11_ssid *req_ssid) { - int ret = 0; + int ret; if (down_interruptible(&priv->async_sem)) { dev_err(priv->adapter->dev, "%s: acquire semaphore\n", diff --git a/drivers/net/wireless/mwifiex/sdio.c b/drivers/net/wireless/mwifiex/sdio.c index 5148d0e..470dbaa 100644 --- a/drivers/net/wireless/mwifiex/sdio.c +++ b/drivers/net/wireless/mwifiex/sdio.c @@ -46,7 +46,7 @@ static struct semaphore add_remove_card_sem; static int mwifiex_sdio_probe(struct sdio_func *func, const struct sdio_device_id *id) { - int ret = 0; + int ret; struct sdio_mmc_card *card = NULL; pr_debug("info: vendor=0x%4.04X device=0x%4.04X class=%d function=%d\n", @@ -119,7 +119,7 @@ static int mwifiex_sdio_suspend(struct device *dev) { struct sdio_func *func = dev_to_sdio_func(dev); struct sdio_mmc_card *card; - struct mwifiex_adapter *adapter = NULL; + struct mwifiex_adapter *adapter; mmc_pm_flag_t pm_flag = 0; int hs_actived = 0; int i; @@ -177,7 +177,7 @@ static int mwifiex_sdio_resume(struct device *dev) { struct sdio_func *func = dev_to_sdio_func(dev); struct sdio_mmc_card *card; - struct mwifiex_adapter *adapter = NULL; + struct mwifiex_adapter *adapter; mmc_pm_flag_t pm_flag = 0; int i; @@ -420,7 +420,7 @@ static int mwifiex_write_data_to_card(struct mwifiex_adapter *adapter, u8 *payload, u32 pkt_len, u32 port) { u32 i = 0; - int ret = 0; + int ret; do { ret = mwifiex_write_data_sync(adapter, payload, pkt_len, port); @@ -531,7 +531,7 @@ static int mwifiex_sdio_poll_card_status(struct mwifiex_adapter *adapter, u8 bits) { u32 tries; - u32 cs = 0; + u32 cs; for (tries = 0; tries < MAX_POLL_TRIES; tries++) { if (mwifiex_read_reg(adapter, CARD_STATUS_REG, &cs)) @@ -553,7 +553,7 @@ mwifiex_sdio_poll_card_status(struct mwifiex_adapter *adapter, u8 bits) static int mwifiex_sdio_read_fw_status(struct mwifiex_adapter *adapter, u16 *dat) { - u32 fws0 = 0, fws1 = 0; + u32 fws0, fws1; if (mwifiex_read_reg(adapter, CARD_FW_STATUS0_REG, &fws0)) return -1; @@ -574,7 +574,7 @@ mwifiex_sdio_read_fw_status(struct mwifiex_adapter *adapter, u16 *dat) */ static int mwifiex_sdio_disable_host_int(struct mwifiex_adapter *adapter) { - u32 host_int_mask = 0; + u32 host_int_mask; /* Read back the host_int_mask register */ if (mwifiex_read_reg(adapter, HOST_INT_MASK_REG, &host_int_mask)) @@ -614,7 +614,7 @@ static int mwifiex_sdio_card_to_host(struct mwifiex_adapter *adapter, u32 *type, u8 *buffer, u32 npayload, u32 ioport) { - int ret = 0; + int ret; u32 nb; if (!buffer) { @@ -652,14 +652,14 @@ static int mwifiex_sdio_card_to_host(struct mwifiex_adapter *adapter, static int mwifiex_prog_fw_w_helper(struct mwifiex_adapter *adapter, struct mwifiex_fw_image *fw) { - int ret = 0; + int ret; u8 *firmware = fw->fw_buf; u32 firmware_len = fw->fw_len; u32 offset = 0; u32 base0, base1; u8 *fwbuf; u16 len = 0; - u32 txlen = 0, tx_blocks = 0, tries = 0; + u32 txlen, tx_blocks = 0, tries; u32 i = 0; if (!firmware_len) { @@ -830,7 +830,7 @@ static int mwifiex_check_fw_status(struct mwifiex_adapter *adapter, static void mwifiex_interrupt_status(struct mwifiex_adapter *adapter) { struct sdio_mmc_card *card = adapter->card; - u32 sdio_ireg = 0; + u32 sdio_ireg; unsigned long flags; if (mwifiex_read_data_sync(adapter, card->mp_regs, MAX_MP_REGS, @@ -964,7 +964,7 @@ static int mwifiex_sdio_card_to_host_mp_aggr(struct mwifiex_adapter *adapter, s32 f_do_rx_cur = 0; s32 f_aggr_cur = 0; struct sk_buff *skb_deaggr; - u32 pind = 0; + u32 pind; u32 pkt_len, pkt_type = 0; u8 *curr_ptr; u32 rx_len = skb->len; @@ -1114,7 +1114,7 @@ static int mwifiex_process_int_status(struct mwifiex_adapter *adapter) struct sdio_mmc_card *card = adapter->card; int ret = 0; u8 sdio_ireg; - struct sk_buff *skb = NULL; + struct sk_buff *skb; u8 port = CTRL_PORT; u32 len_reg_l, len_reg_u; u32 rx_blocks; @@ -1377,7 +1377,7 @@ static int mwifiex_sdio_host_to_card(struct mwifiex_adapter *adapter, struct mwifiex_tx_param *tx_param) { struct sdio_mmc_card *card = adapter->card; - int ret = 0; + int ret; u32 buf_block_len; u32 blk_size; u8 port = CTRL_PORT; @@ -1560,7 +1560,7 @@ static int mwifiex_init_sdio(struct mwifiex_adapter *adapter) { struct sdio_mmc_card *card = adapter->card; int ret; - u32 sdio_ireg = 0; + u32 sdio_ireg; /* * Read the HOST_INT_STATUS_REG for ACK the first interrupt got diff --git a/drivers/net/wireless/mwifiex/sta_cmd.c b/drivers/net/wireless/mwifiex/sta_cmd.c index 33c8ba1..8af3a78 100644 --- a/drivers/net/wireless/mwifiex/sta_cmd.c +++ b/drivers/net/wireless/mwifiex/sta_cmd.c @@ -274,8 +274,8 @@ static int mwifiex_cmd_tx_rate_cfg(struct mwifiex_private *priv, static int mwifiex_cmd_tx_power_cfg(struct host_cmd_ds_command *cmd, u16 cmd_action, void *data_buf) { - struct mwifiex_types_power_group *pg_tlv = NULL; - struct host_cmd_ds_txpwr_cfg *txp = NULL; + struct mwifiex_types_power_group *pg_tlv; + struct host_cmd_ds_txpwr_cfg *txp; struct host_cmd_ds_txpwr_cfg *cmd_txp_cfg = &cmd->params.txp_cfg; cmd->command = cpu_to_le16(HostCmd_CMD_TXPWR_CFG); @@ -478,7 +478,7 @@ mwifiex_set_keyparamset_wep(struct mwifiex_private *priv, struct mwifiex_ie_type_key_param_set *key_param_set, u16 *key_param_len) { - int cur_key_param_len = 0; + int cur_key_param_len; u8 i; /* Multi-key_param_set TLV is supported */ @@ -1121,7 +1121,7 @@ int mwifiex_sta_prepare_cmd(struct mwifiex_private *priv, uint16_t cmd_no, */ int mwifiex_sta_init_cmd(struct mwifiex_private *priv, u8 first_sta) { - int ret = 0; + int ret; u16 enable = true; struct mwifiex_ds_11n_amsdu_aggr_ctrl amsdu_aggr_ctrl; struct mwifiex_ds_auto_ds auto_ds; diff --git a/drivers/net/wireless/mwifiex/sta_cmdresp.c b/drivers/net/wireless/mwifiex/sta_cmdresp.c index 7f4f10b..d08f764 100644 --- a/drivers/net/wireless/mwifiex/sta_cmdresp.c +++ b/drivers/net/wireless/mwifiex/sta_cmdresp.c @@ -43,7 +43,7 @@ static void mwifiex_process_cmdresp_error(struct mwifiex_private *priv, struct host_cmd_ds_command *resp) { - struct cmd_ctrl_node *cmd_node = NULL, *tmp_node = NULL; + struct cmd_ctrl_node *cmd_node = NULL, *tmp_node; struct mwifiex_adapter *adapter = priv->adapter; struct host_cmd_ds_802_11_ps_mode_enh *pm; unsigned long flags; @@ -124,7 +124,7 @@ static int mwifiex_ret_802_11_rssi_info(struct mwifiex_private *priv, { struct host_cmd_ds_802_11_rssi_info_rsp *rssi_info_rsp = &resp->params.rssi_info_rsp; - struct mwifiex_ds_get_signal *signal = NULL; + struct mwifiex_ds_get_signal *signal; priv->data_rssi_last = le16_to_cpu(rssi_info_rsp->data_rssi_last); priv->data_nf_last = le16_to_cpu(rssi_info_rsp->data_nf_last); @@ -232,7 +232,7 @@ static int mwifiex_ret_get_log(struct mwifiex_private *priv, { struct host_cmd_ds_802_11_get_log *get_log = (struct host_cmd_ds_802_11_get_log *) &resp->params.get_log; - struct mwifiex_ds_get_stats *stats = NULL; + struct mwifiex_ds_get_stats *stats; if (data_buf) { stats = (struct mwifiex_ds_get_stats *) data_buf; @@ -280,10 +280,10 @@ static int mwifiex_ret_tx_rate_cfg(struct mwifiex_private *priv, struct host_cmd_ds_command *resp, void *data_buf) { - struct mwifiex_rate_cfg *ds_rate = NULL; + struct mwifiex_rate_cfg *ds_rate; struct host_cmd_ds_tx_rate_cfg *rate_cfg = &resp->params.tx_rate_cfg; struct mwifiex_rate_scope *rate_scope; - struct mwifiex_ie_types_header *head = NULL; + struct mwifiex_ie_types_header *head; u16 tlv, tlv_buf_len; u8 *tlv_buf; u32 i; @@ -368,9 +368,9 @@ static int mwifiex_ret_tx_rate_cfg(struct mwifiex_private *priv, */ static int mwifiex_get_power_level(struct mwifiex_private *priv, void *data_buf) { - int length = -1, max_power = -1, min_power = -1; - struct mwifiex_types_power_group *pg_tlv_hdr = NULL; - struct mwifiex_power_group *pg = NULL; + int length, max_power = -1, min_power = -1; + struct mwifiex_types_power_group *pg_tlv_hdr; + struct mwifiex_power_group *pg; if (data_buf) { pg_tlv_hdr = @@ -418,8 +418,8 @@ static int mwifiex_ret_tx_power_cfg(struct mwifiex_private *priv, { struct mwifiex_adapter *adapter = priv->adapter; struct host_cmd_ds_txpwr_cfg *txp_cfg = &resp->params.txp_cfg; - struct mwifiex_types_power_group *pg_tlv_hdr = NULL; - struct mwifiex_power_group *pg = NULL; + struct mwifiex_types_power_group *pg_tlv_hdr; + struct mwifiex_power_group *pg; u16 action = le16_to_cpu(txp_cfg->action); switch (action) { @@ -593,7 +593,7 @@ static int mwifiex_ret_802_11d_domain_info(struct mwifiex_private *priv, &resp->params.domain_info_resp; struct mwifiex_ietypes_domain_param_set *domain = &domain_info->domain; u16 action = le16_to_cpu(domain_info->action); - u8 no_of_triplet = 0; + u8 no_of_triplet; no_of_triplet = (u8) ((le16_to_cpu(domain->header.len) - IEEE80211_COUNTRY_STRING_LEN) / @@ -661,7 +661,7 @@ static int mwifiex_ret_ver_ext(struct mwifiex_private *priv, void *data_buf) { struct host_cmd_ds_version_ext *ver_ext = &resp->params.verext; - struct host_cmd_ds_version_ext *version_ext = NULL; + struct host_cmd_ds_version_ext *version_ext; if (data_buf) { version_ext = (struct host_cmd_ds_version_ext *)data_buf; @@ -682,8 +682,8 @@ static int mwifiex_ret_ver_ext(struct mwifiex_private *priv, static int mwifiex_ret_reg_access(u16 type, struct host_cmd_ds_command *resp, void *data_buf) { - struct mwifiex_ds_reg_rw *reg_rw = NULL; - struct mwifiex_ds_read_eeprom *eeprom = NULL; + struct mwifiex_ds_reg_rw *reg_rw; + struct mwifiex_ds_read_eeprom *eeprom; if (data_buf) { reg_rw = (struct mwifiex_ds_reg_rw *) data_buf; diff --git a/drivers/net/wireless/mwifiex/sta_ioctl.c b/drivers/net/wireless/mwifiex/sta_ioctl.c index e7adaab..4585c1b 100644 --- a/drivers/net/wireless/mwifiex/sta_ioctl.c +++ b/drivers/net/wireless/mwifiex/sta_ioctl.c @@ -149,7 +149,7 @@ int mwifiex_request_set_multicast_list(struct mwifiex_private *priv, int mwifiex_bss_start(struct mwifiex_private *priv, struct mwifiex_ssid_bssid *ssid_bssid) { - int ret = 0; + int ret; struct mwifiex_adapter *adapter = priv->adapter; s32 i = -1; @@ -376,7 +376,7 @@ int mwifiex_get_bss_info(struct mwifiex_private *priv, { struct mwifiex_adapter *adapter = priv->adapter; struct mwifiex_bssdescriptor *bss_desc; - s32 tbl_idx = 0; + s32 tbl_idx; if (!info) return -1; @@ -436,9 +436,8 @@ int mwifiex_set_radio_band_cfg(struct mwifiex_private *priv, struct mwifiex_ds_band_cfg *radio_cfg) { struct mwifiex_adapter *adapter = priv->adapter; - u8 infra_band = 0; - u8 adhoc_band = 0; - u32 adhoc_channel = 0; + u8 infra_band, adhoc_band; + u32 adhoc_channel; infra_band = (u8) radio_cfg->config_bands; adhoc_band = (u8) radio_cfg->adhoc_start_band; @@ -636,7 +635,7 @@ int mwifiex_bss_ioctl_find_bss(struct mwifiex_private *priv, int mwifiex_drv_change_adhoc_chan(struct mwifiex_private *priv, int channel) { - int ret = 0; + int ret; struct mwifiex_bss_info bss_info; struct mwifiex_ssid_bssid ssid_bssid; u16 curr_chan = 0; @@ -755,11 +754,10 @@ static int mwifiex_rate_ioctl_set_rate_value(struct mwifiex_private *priv, struct mwifiex_rate_cfg *rate_cfg) { u8 rates[MWIFIEX_SUPPORTED_RATES]; - u8 *rate = NULL; - int rate_index = 0; + u8 *rate; + int rate_index, ret; u16 bitmap_rates[MAX_BITMAP_RATES_SIZE]; - u32 i = 0; - int ret = 0; + u32 i; struct mwifiex_adapter *adapter = priv->adapter; if (rate_cfg->is_rate_auto) { @@ -819,7 +817,7 @@ static int mwifiex_rate_ioctl_set_rate_value(struct mwifiex_private *priv, static int mwifiex_rate_ioctl_cfg(struct mwifiex_private *priv, struct mwifiex_rate_cfg *rate_cfg) { - int status = 0; + int status; if (!rate_cfg) return -1; @@ -841,7 +839,7 @@ static int mwifiex_rate_ioctl_cfg(struct mwifiex_private *priv, int mwifiex_drv_get_data_rate(struct mwifiex_private *priv, struct mwifiex_rate_cfg *rate) { - int ret = 0; + int ret; memset(rate, 0, sizeof(struct mwifiex_rate_cfg)); rate->action = HostCmd_ACT_GEN_GET; @@ -875,11 +873,11 @@ int mwifiex_drv_get_data_rate(struct mwifiex_private *priv, int mwifiex_set_tx_power(struct mwifiex_private *priv, struct mwifiex_power_cfg *power_cfg) { - int ret = 0; - struct host_cmd_ds_txpwr_cfg *txp_cfg = NULL; - struct mwifiex_types_power_group *pg_tlv = NULL; - struct mwifiex_power_group *pg = NULL; - u8 *buf = NULL; + int ret; + struct host_cmd_ds_txpwr_cfg *txp_cfg; + struct mwifiex_types_power_group *pg_tlv; + struct mwifiex_power_group *pg; + u8 *buf; u16 dbm = 0; if (!power_cfg->is_power_auto) { @@ -960,7 +958,7 @@ int mwifiex_set_tx_power(struct mwifiex_private *priv, */ int mwifiex_drv_set_power(struct mwifiex_private *priv, u32 *ps_mode) { - int ret = 0; + int ret; struct mwifiex_adapter *adapter = priv->adapter; u16 sub_cmd; @@ -1078,8 +1076,8 @@ static int mwifiex_sec_ioctl_set_wapi_key(struct mwifiex_private *priv, static int mwifiex_sec_ioctl_set_wep_key(struct mwifiex_private *priv, struct mwifiex_ds_encrypt_key *encrypt_key) { - int ret = 0; - struct mwifiex_wep_key *wep_key = NULL; + int ret; + struct mwifiex_wep_key *wep_key; int index; if (priv->wep_key_curr_index >= NUM_WEP_KEYS) @@ -1142,7 +1140,7 @@ static int mwifiex_sec_ioctl_set_wep_key(struct mwifiex_private *priv, static int mwifiex_sec_ioctl_set_wpa_key(struct mwifiex_private *priv, struct mwifiex_ds_encrypt_key *encrypt_key) { - int ret = 0; + int ret; u8 remove_key = false; struct host_cmd_ds_802_11_key_material *ibss_key; @@ -1209,7 +1207,7 @@ static int mwifiex_sec_ioctl_encrypt_key(struct mwifiex_private *priv, struct mwifiex_ds_encrypt_key *encrypt_key) { - int status = 0; + int status; if (encrypt_key->is_wapi_key) status = mwifiex_sec_ioctl_set_wapi_key(priv, encrypt_key); @@ -1253,7 +1251,7 @@ int mwifiex_get_signal_info(struct mwifiex_private *priv, struct mwifiex_ds_get_signal *signal) { struct mwifiex_ds_get_signal info; - int status = 0; + int status; memset(&info, 0, sizeof(struct mwifiex_ds_get_signal)); info.selector = ALL_RSSI_INFO_MASK; @@ -1334,7 +1332,7 @@ int mwifiex_get_stats_info(struct mwifiex_private *priv, struct mwifiex_ds_get_stats *log) { - int ret = 0; + int ret; struct mwifiex_ds_get_stats get_log; memset(&get_log, 0, sizeof(struct mwifiex_ds_get_stats)); @@ -1425,7 +1423,7 @@ int mwifiex_reg_read(struct mwifiex_private *priv, u32 reg_type, u32 reg_offset, u32 *value) { - int ret = 0; + int ret; struct mwifiex_ds_reg_rw reg_rw; reg_rw.type = cpu_to_le32(reg_type); @@ -1451,7 +1449,7 @@ int mwifiex_eeprom_read(struct mwifiex_private *priv, u16 offset, u16 bytes, u8 *value) { - int ret = 0; + int ret; struct mwifiex_ds_read_eeprom rd_eeprom; rd_eeprom.offset = cpu_to_le16((u16) offset); diff --git a/drivers/net/wireless/mwifiex/sta_rx.c b/drivers/net/wireless/mwifiex/sta_rx.c index 8282679..e047f0d 100644 --- a/drivers/net/wireless/mwifiex/sta_rx.c +++ b/drivers/net/wireless/mwifiex/sta_rx.c @@ -41,7 +41,7 @@ int mwifiex_process_rx_packet(struct mwifiex_adapter *adapter, struct sk_buff *skb) { - int ret = 0; + int ret; struct mwifiex_rxinfo *rx_info = MWIFIEX_SKB_RXCB(skb); struct mwifiex_private *priv = adapter->priv[rx_info->bss_index]; struct rx_packet_hdr *rx_pkt_hdr; @@ -123,7 +123,7 @@ int mwifiex_process_sta_rx_packet(struct mwifiex_adapter *adapter, struct mwifiex_rxinfo *rx_info = MWIFIEX_SKB_RXCB(skb); struct rx_packet_hdr *rx_pkt_hdr; u8 ta[ETH_ALEN]; - u16 rx_pkt_type = 0; + u16 rx_pkt_type; struct mwifiex_private *priv = adapter->priv[rx_info->bss_index]; local_rx_pd = (struct rxpd *) (skb->data); diff --git a/drivers/net/wireless/mwifiex/sta_tx.c b/drivers/net/wireless/mwifiex/sta_tx.c index 5d37ef1..fa6221b 100644 --- a/drivers/net/wireless/mwifiex/sta_tx.c +++ b/drivers/net/wireless/mwifiex/sta_tx.c @@ -113,8 +113,8 @@ int mwifiex_send_null_packet(struct mwifiex_private *priv, u8 flags) /* sizeof(struct txpd) + Interface specific header */ #define NULL_PACKET_HDR 64 u32 data_len = NULL_PACKET_HDR; - struct sk_buff *skb = NULL; - int ret = 0; + struct sk_buff *skb; + int ret; struct mwifiex_txinfo *tx_info = NULL; if (adapter->surprise_removed) diff --git a/drivers/net/wireless/mwifiex/txrx.c b/drivers/net/wireless/mwifiex/txrx.c index ce772e0..2101208 100644 --- a/drivers/net/wireless/mwifiex/txrx.c +++ b/drivers/net/wireless/mwifiex/txrx.c @@ -68,7 +68,7 @@ int mwifiex_process_tx(struct mwifiex_private *priv, struct sk_buff *skb, { int ret = -1; struct mwifiex_adapter *adapter = priv->adapter; - u8 *head_ptr = NULL; + u8 *head_ptr; struct txpd *local_tx_pd = NULL; head_ptr = (u8 *) mwifiex_process_sta_txpd(priv, skb); @@ -121,8 +121,8 @@ int mwifiex_process_tx(struct mwifiex_private *priv, struct sk_buff *skb, int mwifiex_write_data_complete(struct mwifiex_adapter *adapter, struct sk_buff *skb, int status) { - struct mwifiex_private *priv = NULL, *tpriv = NULL; - struct mwifiex_txinfo *tx_info = NULL; + struct mwifiex_private *priv, *tpriv; + struct mwifiex_txinfo *tx_info; int i; if (!skb) @@ -169,9 +169,9 @@ int mwifiex_recv_packet_complete(struct mwifiex_adapter *adapter, struct sk_buff *skb, int status) { struct mwifiex_rxinfo *rx_info = MWIFIEX_SKB_RXCB(skb); - struct mwifiex_rxinfo *rx_info_parent = NULL; + struct mwifiex_rxinfo *rx_info_parent; struct mwifiex_private *priv; - struct sk_buff *skb_parent = NULL; + struct sk_buff *skb_parent; unsigned long flags; priv = adapter->priv[rx_info->bss_index]; diff --git a/drivers/net/wireless/mwifiex/util.c b/drivers/net/wireless/mwifiex/util.c index 7ab4fb2..a8d53aa7 100644 --- a/drivers/net/wireless/mwifiex/util.c +++ b/drivers/net/wireless/mwifiex/util.c @@ -152,8 +152,8 @@ int mwifiex_get_debug_info(struct mwifiex_private *priv, */ int mwifiex_recv_packet(struct mwifiex_adapter *adapter, struct sk_buff *skb) { - struct mwifiex_rxinfo *rx_info = NULL; - struct mwifiex_private *priv = NULL; + struct mwifiex_rxinfo *rx_info; + struct mwifiex_private *priv; if (!skb) return -1; @@ -184,8 +184,8 @@ int mwifiex_recv_packet(struct mwifiex_adapter *adapter, struct sk_buff *skb) int mwifiex_recv_complete(struct mwifiex_adapter *adapter, struct sk_buff *skb, int status) { - struct mwifiex_private *priv = NULL; - struct mwifiex_rxinfo *rx_info = NULL; + struct mwifiex_private *priv; + struct mwifiex_rxinfo *rx_info; if (!skb) return 0; diff --git a/drivers/net/wireless/mwifiex/wmm.c b/drivers/net/wireless/mwifiex/wmm.c index c009370..faa09e3 100644 --- a/drivers/net/wireless/mwifiex/wmm.c +++ b/drivers/net/wireless/mwifiex/wmm.c @@ -799,7 +799,7 @@ u8 mwifiex_wmm_compute_drv_pkt_delay(struct mwifiex_private *priv, const struct sk_buff *skb) { - u8 ret_val = 0; + u8 ret_val; struct timeval out_tstamp, in_tstamp; u32 queue_delay; -- cgit v0.10.2 From 0e579d6a8f4aea346da818f13ee71401c125e639 Mon Sep 17 00:00:00 2001 From: Jouni Malinen Date: Tue, 3 May 2011 22:45:16 -0700 Subject: nl80211: Fix set_key regression with some drivers Commit dbd2fd656f2060abfd3a16257f8b51ec60f6d2ed added a mechanism for user space to indicate whether a default key is being configured for only unicast or only multicast frames instead of all frames. This commit added a driver capability flag for indicating whether separate default keys are supported and validation of the set_key command based on that capability. However, this single capability flag is not enough to cover possible difference based on mode (AP/IBSS/STA) and the way this change was introduced resulted in a regression with drivers that do not indicate the new capability (i.e.., more or less any non-mac80211 driver using cfg80211) when using a recent wpa_supplicant snapshot. Fix the regression by removing the new check which is not strictly speaking needed. The new separate default key functionality is needed only for RSN IBSS which has a separate capability indication. Cc: stable@kernel.org Signed-off-by: Jouni Malinen Signed-off-by: John W. Linville diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 0efa7fd..ab77f94 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -1682,14 +1682,6 @@ static int nl80211_set_key(struct sk_buff *skb, struct genl_info *info) if (err) goto out; - if (!(rdev->wiphy.flags & - WIPHY_FLAG_SUPPORTS_SEPARATE_DEFAULT_KEYS)) { - if (!key.def_uni || !key.def_multi) { - err = -EOPNOTSUPP; - goto out; - } - } - err = rdev->ops->set_default_key(&rdev->wiphy, dev, key.idx, key.def_uni, key.def_multi); -- cgit v0.10.2 From f0dc7999b54ae0464d7144b81d21e1d39a389d49 Mon Sep 17 00:00:00 2001 From: Jouni Malinen Date: Tue, 3 May 2011 22:50:15 -0700 Subject: cfg80211: Remove unused wiphy flag The only user of WIPHY_FLAG_SUPPORTS_SEPARATE_DEFAULT_KEYS was removed and consequently, this flag can be removed, too. In addition, a single capability flag was not enough to indicate this capability clearly since the device behavior may be different based on which operating mode is being used. Signed-off-by: Jouni Malinen Signed-off-by: John W. Linville diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index d30eada..4932dfc 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -1455,8 +1455,6 @@ struct cfg80211_ops { * control port protocol ethertype. The device also honours the * control_port_no_encrypt flag. * @WIPHY_FLAG_IBSS_RSN: The device supports IBSS RSN. - * @WIPHY_FLAG_SUPPORTS_SEPARATE_DEFAULT_KEYS: The device supports separate - * unicast and multicast TX keys. * @WIPHY_FLAG_MESH_AUTH: The device supports mesh authentication by routing * auth frames to userspace. See @NL80211_MESH_SETUP_USERSPACE_AUTH. */ @@ -1470,7 +1468,6 @@ enum wiphy_flags { WIPHY_FLAG_4ADDR_STATION = BIT(6), WIPHY_FLAG_CONTROL_PORT_PROTOCOL = BIT(7), WIPHY_FLAG_IBSS_RSN = BIT(8), - WIPHY_FLAG_SUPPORTS_SEPARATE_DEFAULT_KEYS= BIT(9), WIPHY_FLAG_MESH_AUTH = BIT(10), }; diff --git a/net/mac80211/main.c b/net/mac80211/main.c index 6187766..d8be198 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c @@ -580,8 +580,7 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len, wiphy->flags |= WIPHY_FLAG_NETNS_OK | WIPHY_FLAG_4ADDR_AP | - WIPHY_FLAG_4ADDR_STATION | - WIPHY_FLAG_SUPPORTS_SEPARATE_DEFAULT_KEYS; + WIPHY_FLAG_4ADDR_STATION; if (!ops->set_key) wiphy->flags |= WIPHY_FLAG_IBSS_RSN; -- cgit v0.10.2 From 9b571e24a9922f79ed2440b4482cb9f11a8f1889 Mon Sep 17 00:00:00 2001 From: Yogesh Ashok Powar Date: Wed, 4 May 2011 17:22:16 +0530 Subject: mwl8k: Fix broken WEP The WEP key length was being set to 0 erroneously which broke WEP support. Fix the same by setting the key length appropriately. Signed-off-by: Yogesh Ashok Powar Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c index 9f5ecef..d06591a 100644 --- a/drivers/net/wireless/mwl8k.c +++ b/drivers/net/wireless/mwl8k.c @@ -3997,7 +3997,7 @@ static int mwl8k_cmd_encryption_set_key(struct ieee80211_hw *hw, mwl8k_vif->wep_key_conf[idx].enabled = 1; } - keymlen = 0; + keymlen = key->keylen; action = MWL8K_ENCR_SET_KEY; break; case WLAN_CIPHER_SUITE_TKIP: -- cgit v0.10.2 From 8f7f3b2fcc4ccbba0be776049df41a2f96c986ac Mon Sep 17 00:00:00 2001 From: Nicolas Cavallari Date: Wed, 4 May 2011 15:26:52 +0200 Subject: carl9170: fix allmulticast mode Currently, the driver only disable multicast filtering when the FIF_ALLMULTI driver flag has been just set (ie, if changed_flags& FIF_ALLMULTI and *new_flags& FIF_ALLMULTI) or else it will reenable multicast filtering. But next time, this condition will be false and multicast filtering will be reenabled, even through FIF_ALLMULTI is still set. This mean that allmulticast only works for less than two minutes in ad-hoc mode. This patch fixes that to disable multicast filtering as long as FIF_ALLMULTI is set. Signed-off-by: Nicolas Cavallari Acked-by: Christian Lamparter Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/carl9170/main.c b/drivers/net/wireless/ath/carl9170/main.c index 1638468..7d5c65e 100644 --- a/drivers/net/wireless/ath/carl9170/main.c +++ b/drivers/net/wireless/ath/carl9170/main.c @@ -883,7 +883,7 @@ static void carl9170_op_configure_filter(struct ieee80211_hw *hw, * then checking the error flags, later. */ - if (changed_flags & FIF_ALLMULTI && *new_flags & FIF_ALLMULTI) + if (*new_flags & FIF_ALLMULTI) multicast = ~0ULL; if (multicast != ar->cur_mc_hash) -- cgit v0.10.2 From ff1b6e69ad4f31fb3c9c6da2665655f2e798dd70 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 4 May 2011 15:37:28 +0200 Subject: nl80211/cfg80211: WoWLAN support This is based on (but now quite far from) the original work from Luis and Eliad. Add support for configuring WoWLAN triggers, and getting the configuration out again. Changes from the original patchset are too numerous to list, but one important change needs highlighting: the suspend() callback is passed NULL for the trigger configuration if userspace has not configured WoWLAN at all. Signed-off-by: Luis R. Rodriguez Signed-off-by: Eliad Peller Signed-off-by: Johannes Berg Signed-off-by: John W. Linville diff --git a/include/linux/nl80211.h b/include/linux/nl80211.h index be8df57..a75dea9 100644 --- a/include/linux/nl80211.h +++ b/include/linux/nl80211.h @@ -420,6 +420,14 @@ * new station with the AUTHENTICATED flag unset and maybe change it later * depending on the authentication result. * + * @NL80211_CMD_GET_WOWLAN: get Wake-on-Wireless-LAN (WoWLAN) settings. + * @NL80211_CMD_SET_WOWLAN: set Wake-on-Wireless-LAN (WoWLAN) settings. + * Since wireless is more complex than wired ethernet, it supports + * various triggers. These triggers can be configured through this + * command with the %NL80211_ATTR_WOWLAN_TRIGGERS attribute. For + * more background information, see + * http://wireless.kernel.org/en/users/Documentation/WoWLAN. + * * @NL80211_CMD_MAX: highest used command number * @__NL80211_CMD_AFTER_LAST: internal use */ @@ -534,6 +542,9 @@ enum nl80211_commands { NL80211_CMD_NEW_PEER_CANDIDATE, + NL80211_CMD_GET_WOWLAN, + NL80211_CMD_SET_WOWLAN, + /* add new commands above here */ /* used to define NL80211_CMD_MAX below */ @@ -903,6 +914,13 @@ enum nl80211_commands { * allows auth frames in a mesh to be passed to userspace for processing via * the @NL80211_MESH_SETUP_USERSPACE_AUTH flag. * + * @NL80211_ATTR_WOWLAN_SUPPORTED: indicates, as part of the wiphy capabilities, + * the supported WoWLAN triggers + * @NL80211_ATTR_WOWLAN_TRIGGERS: used by %NL80211_CMD_SET_WOWLAN to + * indicate which WoW triggers should be enabled. This is also + * used by %NL80211_CMD_GET_WOWLAN to get the currently enabled WoWLAN + * triggers. + * * @NL80211_ATTR_MAX: highest attribute number currently defined * @__NL80211_ATTR_AFTER_LAST: internal use */ @@ -1092,6 +1110,9 @@ enum nl80211_attrs { NL80211_ATTR_SUPPORT_MESH_AUTH, + NL80211_ATTR_WOWLAN_TRIGGERS, + NL80211_ATTR_WOWLAN_TRIGGERS_SUPPORTED, + /* add attributes here, update the policy in nl80211.c */ __NL80211_ATTR_AFTER_LAST, @@ -2061,4 +2082,82 @@ enum nl80211_tx_power_setting { NL80211_TX_POWER_FIXED, }; +/** + * enum nl80211_wowlan_packet_pattern_attr - WoWLAN packet pattern attribute + * @__NL80211_WOWLAN_PKTPAT_INVALID: invalid number for nested attribute + * @NL80211_WOWLAN_PKTPAT_PATTERN: the pattern, values where the mask has + * a zero bit are ignored + * @NL80211_WOWLAN_PKTPAT_MASK: pattern mask, must be long enough to have + * a bit for each byte in the pattern. The lowest-order bit corresponds + * to the first byte of the pattern, but the bytes of the pattern are + * in a little-endian-like format, i.e. the 9th byte of the pattern + * corresponds to the lowest-order bit in the second byte of the mask. + * For example: The match 00:xx:00:00:xx:00:00:00:00:xx:xx:xx (where + * xx indicates "don't care") would be represented by a pattern of + * twelve zero bytes, and a mask of "0xed,0x07". + * Note that the pattern matching is done as though frames were not + * 802.11 frames but 802.3 frames, i.e. the frame is fully unpacked + * first (including SNAP header unpacking) and then matched. + * @NUM_NL80211_WOWLAN_PKTPAT: number of attributes + * @MAX_NL80211_WOWLAN_PKTPAT: max attribute number + */ +enum nl80211_wowlan_packet_pattern_attr { + __NL80211_WOWLAN_PKTPAT_INVALID, + NL80211_WOWLAN_PKTPAT_MASK, + NL80211_WOWLAN_PKTPAT_PATTERN, + + NUM_NL80211_WOWLAN_PKTPAT, + MAX_NL80211_WOWLAN_PKTPAT = NUM_NL80211_WOWLAN_PKTPAT - 1, +}; + +/** + * struct nl80211_wowlan_pattern_support - pattern support information + * @max_patterns: maximum number of patterns supported + * @min_pattern_len: minimum length of each pattern + * @max_pattern_len: maximum length of each pattern + * + * This struct is carried in %NL80211_WOWLAN_TRIG_PKT_PATTERN when + * that is part of %NL80211_ATTR_WOWLAN_TRIGGERS_SUPPORTED in the + * capability information given by the kernel to userspace. + */ +struct nl80211_wowlan_pattern_support { + __u32 max_patterns; + __u32 min_pattern_len; + __u32 max_pattern_len; +} __attribute__((packed)); + +/** + * enum nl80211_wowlan_triggers - WoWLAN trigger definitions + * @__NL80211_WOWLAN_TRIG_INVALID: invalid number for nested attributes + * @NL80211_WOWLAN_TRIG_ANY: wake up on any activity, do not really put + * the chip into a special state -- works best with chips that have + * support for low-power operation already (flag) + * @NL80211_WOWLAN_TRIG_DISCONNECT: wake up on disconnect, the way disconnect + * is detected is implementation-specific (flag) + * @NL80211_WOWLAN_TRIG_MAGIC_PKT: wake up on magic packet (6x 0xff, followed + * by 16 repetitions of MAC addr, anywhere in payload) (flag) + * @NL80211_WOWLAN_TRIG_PKT_PATTERN: wake up on the specified packet patterns + * which are passed in an array of nested attributes, each nested attribute + * defining a with attributes from &struct nl80211_wowlan_trig_pkt_pattern. + * Each pattern defines a wakeup packet. The matching is done on the MSDU, + * i.e. as though the packet was an 802.3 packet, so the pattern matching + * is done after the packet is converted to the MSDU. + * + * In %NL80211_ATTR_WOWLAN_TRIGGERS_SUPPORTED, it is a binary attribute + * carrying a &struct nl80211_wowlan_pattern_support. + * @NUM_NL80211_WOWLAN_TRIG: number of wake on wireless triggers + * @MAX_NL80211_WOWLAN_TRIG: highest wowlan trigger attribute number + */ +enum nl80211_wowlan_triggers { + __NL80211_WOWLAN_TRIG_INVALID, + NL80211_WOWLAN_TRIG_ANY, + NL80211_WOWLAN_TRIG_DISCONNECT, + NL80211_WOWLAN_TRIG_MAGIC_PKT, + NL80211_WOWLAN_TRIG_PKT_PATTERN, + + /* keep last */ + NUM_NL80211_WOWLAN_TRIG, + MAX_NL80211_WOWLAN_TRIG = NUM_NL80211_WOWLAN_TRIG - 1 +}; + #endif /* __LINUX_NL80211_H */ diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index 4932dfc..0920daf 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -1088,6 +1088,38 @@ struct cfg80211_pmksa { }; /** + * struct cfg80211_wowlan_trig_pkt_pattern - packet pattern + * @mask: bitmask where to match pattern and where to ignore bytes, + * one bit per byte, in same format as nl80211 + * @pattern: bytes to match where bitmask is 1 + * @pattern_len: length of pattern (in bytes) + * + * Internal note: @mask and @pattern are allocated in one chunk of + * memory, free @mask only! + */ +struct cfg80211_wowlan_trig_pkt_pattern { + u8 *mask, *pattern; + int pattern_len; +}; + +/** + * struct cfg80211_wowlan - Wake on Wireless-LAN support info + * + * This structure defines the enabled WoWLAN triggers for the device. + * @any: wake up on any activity -- special trigger if device continues + * operating as normal during suspend + * @disconnect: wake up if getting disconnected + * @magic_pkt: wake up on receiving magic packet + * @patterns: wake up on receiving packet matching a pattern + * @n_patterns: number of patterns + */ +struct cfg80211_wowlan { + bool any, disconnect, magic_pkt; + struct cfg80211_wowlan_trig_pkt_pattern *patterns; + int n_patterns; +}; + +/** * struct cfg80211_ops - backend description for wireless configuration * * This struct is registered by fullmac card drivers and/or wireless stacks @@ -1100,7 +1132,9 @@ struct cfg80211_pmksa { * wireless extensions but this is subject to reevaluation as soon as this * code is used more widely and we have a first user without wext. * - * @suspend: wiphy device needs to be suspended + * @suspend: wiphy device needs to be suspended. The variable @wow will + * be %NULL or contain the enabled Wake-on-Wireless triggers that are + * configured for the device. * @resume: wiphy device needs to be resumed * * @add_virtual_intf: create a new virtual interface with the given name, @@ -1244,7 +1278,7 @@ struct cfg80211_pmksa { * @get_ringparam: Get tx and rx ring current and maximum sizes. */ struct cfg80211_ops { - int (*suspend)(struct wiphy *wiphy); + int (*suspend)(struct wiphy *wiphy, struct cfg80211_wowlan *wow); int (*resume)(struct wiphy *wiphy); struct net_device * (*add_virtual_intf)(struct wiphy *wiphy, @@ -1480,6 +1514,38 @@ struct ieee80211_txrx_stypes { }; /** + * enum wiphy_wowlan_support_flags - WoWLAN support flags + * @WIPHY_WOWLAN_ANY: supports wakeup for the special "any" + * trigger that keeps the device operating as-is and + * wakes up the host on any activity, for example a + * received packet that passed filtering; note that the + * packet should be preserved in that case + * @WIPHY_WOWLAN_MAGIC_PKT: supports wakeup on magic packet + * (see nl80211.h) + * @WIPHY_WOWLAN_DISCONNECT: supports wakeup on disconnect + */ +enum wiphy_wowlan_support_flags { + WIPHY_WOWLAN_ANY = BIT(0), + WIPHY_WOWLAN_MAGIC_PKT = BIT(1), + WIPHY_WOWLAN_DISCONNECT = BIT(2), +}; + +/** + * struct wiphy_wowlan_support - WoWLAN support data + * @flags: see &enum wiphy_wowlan_support_flags + * @n_patterns: number of supported wakeup patterns + * (see nl80211.h for the pattern definition) + * @pattern_max_len: maximum length of each pattern + * @pattern_min_len: minimum length of each pattern + */ +struct wiphy_wowlan_support { + u32 flags; + int n_patterns; + int pattern_max_len; + int pattern_min_len; +}; + +/** * struct wiphy - wireless hardware description * @reg_notifier: the driver's regulatory notification callback, * note that if your driver uses wiphy_apply_custom_regulatory() @@ -1546,6 +1612,8 @@ struct ieee80211_txrx_stypes { * * @max_remain_on_channel_duration: Maximum time a remain-on-channel operation * may request, if implemented. + * + * @wowlan: WoWLAN support information */ struct wiphy { /* assign these fields before you register the wiphy */ @@ -1583,6 +1651,8 @@ struct wiphy { char fw_version[ETHTOOL_BUSINFO_LEN]; u32 hw_version; + struct wiphy_wowlan_support wowlan; + u16 max_remain_on_channel_duration; u8 max_num_pmkids; diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index 12d52ce..321d598 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -1297,7 +1297,8 @@ static int ieee80211_set_channel(struct wiphy *wiphy, } #ifdef CONFIG_PM -static int ieee80211_suspend(struct wiphy *wiphy) +static int ieee80211_suspend(struct wiphy *wiphy, + struct cfg80211_wowlan *wowlan) { return __ieee80211_suspend(wiphy_priv(wiphy)); } diff --git a/net/wireless/core.c b/net/wireless/core.c index bbf1fa1..bea0d80 100644 --- a/net/wireless/core.c +++ b/net/wireless/core.c @@ -493,6 +493,13 @@ int wiphy_register(struct wiphy *wiphy) return -EINVAL; } + if (rdev->wiphy.wowlan.n_patterns) { + if (WARN_ON(!rdev->wiphy.wowlan.pattern_min_len || + rdev->wiphy.wowlan.pattern_min_len > + rdev->wiphy.wowlan.pattern_max_len)) + return -EINVAL; + } + /* check and set up bitrates */ ieee80211_set_bitrate_flags(wiphy); @@ -631,6 +638,7 @@ void cfg80211_dev_free(struct cfg80211_registered_device *rdev) mutex_destroy(&rdev->devlist_mtx); list_for_each_entry_safe(scan, tmp, &rdev->bss_list, list) cfg80211_put_bss(&scan->pub); + cfg80211_rdev_free_wowlan(rdev); kfree(rdev); } diff --git a/net/wireless/core.h b/net/wireless/core.h index 26a0a08..7a18c10 100644 --- a/net/wireless/core.h +++ b/net/wireless/core.h @@ -70,6 +70,8 @@ struct cfg80211_registered_device { struct work_struct conn_work; struct work_struct event_work; + struct cfg80211_wowlan *wowlan; + /* must be last because of the way we do wiphy_priv(), * and it should at least be aligned to NETDEV_ALIGN */ struct wiphy wiphy __attribute__((__aligned__(NETDEV_ALIGN))); @@ -89,6 +91,18 @@ bool wiphy_idx_valid(int wiphy_idx) return wiphy_idx >= 0; } +static inline void +cfg80211_rdev_free_wowlan(struct cfg80211_registered_device *rdev) +{ + int i; + + if (!rdev->wowlan) + return; + for (i = 0; i < rdev->wowlan->n_patterns; i++) + kfree(rdev->wowlan->patterns[i].mask); + kfree(rdev->wowlan->patterns); + kfree(rdev->wowlan); +} extern struct workqueue_struct *cfg80211_wq; extern struct mutex cfg80211_mutex; diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index ab77f94..0a199a1 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -173,6 +173,7 @@ static const struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] = { [NL80211_ATTR_MCAST_RATE] = { .type = NLA_U32 }, [NL80211_ATTR_OFFCHANNEL_TX_OK] = { .type = NLA_FLAG }, [NL80211_ATTR_KEY_DEFAULT_TYPES] = { .type = NLA_NESTED }, + [NL80211_ATTR_WOWLAN_TRIGGERS] = { .type = NLA_NESTED }, }; /* policy for the key attributes */ @@ -194,6 +195,15 @@ nl80211_key_default_policy[NUM_NL80211_KEY_DEFAULT_TYPES] = { [NL80211_KEY_DEFAULT_TYPE_MULTICAST] = { .type = NLA_FLAG }, }; +/* policy for WoWLAN attributes */ +static const struct nla_policy +nl80211_wowlan_policy[NUM_NL80211_WOWLAN_TRIG] = { + [NL80211_WOWLAN_TRIG_ANY] = { .type = NLA_FLAG }, + [NL80211_WOWLAN_TRIG_DISCONNECT] = { .type = NLA_FLAG }, + [NL80211_WOWLAN_TRIG_MAGIC_PKT] = { .type = NLA_FLAG }, + [NL80211_WOWLAN_TRIG_PKT_PATTERN] = { .type = NLA_NESTED }, +}; + /* ifidx get helper */ static int nl80211_get_ifidx(struct netlink_callback *cb) { @@ -821,6 +831,35 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags, nla_nest_end(msg, nl_ifs); } + if (dev->wiphy.wowlan.flags || dev->wiphy.wowlan.n_patterns) { + struct nlattr *nl_wowlan; + + nl_wowlan = nla_nest_start(msg, + NL80211_ATTR_WOWLAN_TRIGGERS_SUPPORTED); + if (!nl_wowlan) + goto nla_put_failure; + + if (dev->wiphy.wowlan.flags & WIPHY_WOWLAN_ANY) + NLA_PUT_FLAG(msg, NL80211_WOWLAN_TRIG_ANY); + if (dev->wiphy.wowlan.flags & WIPHY_WOWLAN_DISCONNECT) + NLA_PUT_FLAG(msg, NL80211_WOWLAN_TRIG_DISCONNECT); + if (dev->wiphy.wowlan.flags & WIPHY_WOWLAN_MAGIC_PKT) + NLA_PUT_FLAG(msg, NL80211_WOWLAN_TRIG_MAGIC_PKT); + if (dev->wiphy.wowlan.n_patterns) { + struct nl80211_wowlan_pattern_support pat = { + .max_patterns = dev->wiphy.wowlan.n_patterns, + .min_pattern_len = + dev->wiphy.wowlan.pattern_min_len, + .max_pattern_len = + dev->wiphy.wowlan.pattern_max_len, + }; + NLA_PUT(msg, NL80211_WOWLAN_TRIG_PKT_PATTERN, + sizeof(pat), &pat); + } + + nla_nest_end(msg, nl_wowlan); + } + return genlmsg_end(msg, hdr); nla_put_failure: @@ -4808,6 +4847,194 @@ static int nl80211_leave_mesh(struct sk_buff *skb, struct genl_info *info) return cfg80211_leave_mesh(rdev, dev); } +static int nl80211_get_wowlan(struct sk_buff *skb, struct genl_info *info) +{ + struct cfg80211_registered_device *rdev = info->user_ptr[0]; + struct sk_buff *msg; + void *hdr; + + if (!rdev->wiphy.wowlan.flags && !rdev->wiphy.wowlan.n_patterns) + return -EOPNOTSUPP; + + msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); + if (!msg) + return -ENOMEM; + + hdr = nl80211hdr_put(msg, info->snd_pid, info->snd_seq, 0, + NL80211_CMD_GET_WOWLAN); + if (!hdr) + goto nla_put_failure; + + if (rdev->wowlan) { + struct nlattr *nl_wowlan; + + nl_wowlan = nla_nest_start(msg, NL80211_ATTR_WOWLAN_TRIGGERS); + if (!nl_wowlan) + goto nla_put_failure; + + if (rdev->wowlan->any) + NLA_PUT_FLAG(msg, NL80211_WOWLAN_TRIG_ANY); + if (rdev->wowlan->disconnect) + NLA_PUT_FLAG(msg, NL80211_WOWLAN_TRIG_DISCONNECT); + if (rdev->wowlan->magic_pkt) + NLA_PUT_FLAG(msg, NL80211_WOWLAN_TRIG_MAGIC_PKT); + if (rdev->wowlan->n_patterns) { + struct nlattr *nl_pats, *nl_pat; + int i, pat_len; + + nl_pats = nla_nest_start(msg, + NL80211_WOWLAN_TRIG_PKT_PATTERN); + if (!nl_pats) + goto nla_put_failure; + + for (i = 0; i < rdev->wowlan->n_patterns; i++) { + nl_pat = nla_nest_start(msg, i + 1); + if (!nl_pat) + goto nla_put_failure; + pat_len = rdev->wowlan->patterns[i].pattern_len; + NLA_PUT(msg, NL80211_WOWLAN_PKTPAT_MASK, + DIV_ROUND_UP(pat_len, 8), + rdev->wowlan->patterns[i].mask); + NLA_PUT(msg, NL80211_WOWLAN_PKTPAT_PATTERN, + pat_len, + rdev->wowlan->patterns[i].pattern); + nla_nest_end(msg, nl_pat); + } + nla_nest_end(msg, nl_pats); + } + + nla_nest_end(msg, nl_wowlan); + } + + genlmsg_end(msg, hdr); + return genlmsg_reply(msg, info); + +nla_put_failure: + nlmsg_free(msg); + return -ENOBUFS; +} + +static int nl80211_set_wowlan(struct sk_buff *skb, struct genl_info *info) +{ + struct cfg80211_registered_device *rdev = info->user_ptr[0]; + struct nlattr *tb[NUM_NL80211_WOWLAN_TRIG]; + struct cfg80211_wowlan no_triggers = {}; + struct cfg80211_wowlan new_triggers = {}; + struct wiphy_wowlan_support *wowlan = &rdev->wiphy.wowlan; + int err, i; + + if (!rdev->wiphy.wowlan.flags && !rdev->wiphy.wowlan.n_patterns) + return -EOPNOTSUPP; + + if (!info->attrs[NL80211_ATTR_WOWLAN_TRIGGERS]) + goto no_triggers; + + err = nla_parse(tb, MAX_NL80211_WOWLAN_TRIG, + nla_data(info->attrs[NL80211_ATTR_WOWLAN_TRIGGERS]), + nla_len(info->attrs[NL80211_ATTR_WOWLAN_TRIGGERS]), + nl80211_wowlan_policy); + if (err) + return err; + + if (tb[NL80211_WOWLAN_TRIG_ANY]) { + if (!(wowlan->flags & WIPHY_WOWLAN_ANY)) + return -EINVAL; + new_triggers.any = true; + } + + if (tb[NL80211_WOWLAN_TRIG_DISCONNECT]) { + if (!(wowlan->flags & WIPHY_WOWLAN_DISCONNECT)) + return -EINVAL; + new_triggers.disconnect = true; + } + + if (tb[NL80211_WOWLAN_TRIG_MAGIC_PKT]) { + if (!(wowlan->flags & WIPHY_WOWLAN_MAGIC_PKT)) + return -EINVAL; + new_triggers.magic_pkt = true; + } + + if (tb[NL80211_WOWLAN_TRIG_PKT_PATTERN]) { + struct nlattr *pat; + int n_patterns = 0; + int rem, pat_len, mask_len; + struct nlattr *pat_tb[NUM_NL80211_WOWLAN_PKTPAT]; + + nla_for_each_nested(pat, tb[NL80211_WOWLAN_TRIG_PKT_PATTERN], + rem) + n_patterns++; + if (n_patterns > wowlan->n_patterns) + return -EINVAL; + + new_triggers.patterns = kcalloc(n_patterns, + sizeof(new_triggers.patterns[0]), + GFP_KERNEL); + if (!new_triggers.patterns) + return -ENOMEM; + + new_triggers.n_patterns = n_patterns; + i = 0; + + nla_for_each_nested(pat, tb[NL80211_WOWLAN_TRIG_PKT_PATTERN], + rem) { + nla_parse(pat_tb, MAX_NL80211_WOWLAN_PKTPAT, + nla_data(pat), nla_len(pat), NULL); + err = -EINVAL; + if (!pat_tb[NL80211_WOWLAN_PKTPAT_MASK] || + !pat_tb[NL80211_WOWLAN_PKTPAT_PATTERN]) + goto error; + pat_len = nla_len(pat_tb[NL80211_WOWLAN_PKTPAT_PATTERN]); + mask_len = DIV_ROUND_UP(pat_len, 8); + if (nla_len(pat_tb[NL80211_WOWLAN_PKTPAT_MASK]) != + mask_len) + goto error; + if (pat_len > wowlan->pattern_max_len || + pat_len < wowlan->pattern_min_len) + goto error; + + new_triggers.patterns[i].mask = + kmalloc(mask_len + pat_len, GFP_KERNEL); + if (!new_triggers.patterns[i].mask) { + err = -ENOMEM; + goto error; + } + new_triggers.patterns[i].pattern = + new_triggers.patterns[i].mask + mask_len; + memcpy(new_triggers.patterns[i].mask, + nla_data(pat_tb[NL80211_WOWLAN_PKTPAT_MASK]), + mask_len); + new_triggers.patterns[i].pattern_len = pat_len; + memcpy(new_triggers.patterns[i].pattern, + nla_data(pat_tb[NL80211_WOWLAN_PKTPAT_PATTERN]), + pat_len); + i++; + } + } + + if (memcmp(&new_triggers, &no_triggers, sizeof(new_triggers))) { + struct cfg80211_wowlan *ntrig; + ntrig = kmemdup(&new_triggers, sizeof(new_triggers), + GFP_KERNEL); + if (!ntrig) { + err = -ENOMEM; + goto error; + } + cfg80211_rdev_free_wowlan(rdev); + rdev->wowlan = ntrig; + } else { + no_triggers: + cfg80211_rdev_free_wowlan(rdev); + rdev->wowlan = NULL; + } + + return 0; + error: + for (i = 0; i < new_triggers.n_patterns; i++) + kfree(new_triggers.patterns[i].mask); + kfree(new_triggers.patterns); + return err; +} + #define NL80211_FLAG_NEED_WIPHY 0x01 #define NL80211_FLAG_NEED_NETDEV 0x02 #define NL80211_FLAG_NEED_RTNL 0x04 @@ -5306,6 +5533,22 @@ static struct genl_ops nl80211_ops[] = { .internal_flags = NL80211_FLAG_NEED_NETDEV_UP | NL80211_FLAG_NEED_RTNL, }, + { + .cmd = NL80211_CMD_GET_WOWLAN, + .doit = nl80211_get_wowlan, + .policy = nl80211_policy, + /* can be retrieved by unprivileged users */ + .internal_flags = NL80211_FLAG_NEED_WIPHY | + NL80211_FLAG_NEED_RTNL, + }, + { + .cmd = NL80211_CMD_SET_WOWLAN, + .doit = nl80211_set_wowlan, + .policy = nl80211_policy, + .flags = GENL_ADMIN_PERM, + .internal_flags = NL80211_FLAG_NEED_WIPHY | + NL80211_FLAG_NEED_RTNL, + }, }; static struct genl_multicast_group nl80211_mlme_mcgrp = { diff --git a/net/wireless/sysfs.c b/net/wireless/sysfs.c index 4294fa2..c6e4ca6 100644 --- a/net/wireless/sysfs.c +++ b/net/wireless/sysfs.c @@ -93,7 +93,7 @@ static int wiphy_suspend(struct device *dev, pm_message_t state) if (rdev->ops->suspend) { rtnl_lock(); - ret = rdev->ops->suspend(&rdev->wiphy); + ret = rdev->ops->suspend(&rdev->wiphy, rdev->wowlan); rtnl_unlock(); } -- cgit v0.10.2 From eecc48000afe2ca6da22122d553b7cad294e42fc Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 4 May 2011 15:37:29 +0200 Subject: mac80211: add basic support for WoWLAN This adds basic support for the new WoWLAN configuration in mac80211. The behaviour is completely offloaded to the driver though, with two new callbacks (suspend/resume). Options for the driver include a complete reconfiguration after wakeup, and exposing all the triggers it wants to support. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville diff --git a/include/net/mac80211.h b/include/net/mac80211.h index 63f75a0..9e55427 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -1606,6 +1606,18 @@ enum ieee80211_ampdu_mlme_action { * you should ensure to cancel it on this callback. * Must be implemented and can sleep. * + * @suspend: Suspend the device; mac80211 itself will quiesce before and + * stop transmitting and doing any other configuration, and then + * ask the device to suspend. This is only invoked when WoWLAN is + * configured, otherwise the device is deconfigured completely and + * reconfigured at resume time. + * + * @resume: If WoWLAN was configured, this indicates that mac80211 is + * now resuming its operation, after this the device must be fully + * functional again. If this returns an error, the only way out is + * to also unregister the device. If it returns 1, then mac80211 + * will also go through the regular complete restart on resume. + * * @add_interface: Called when a netdevice attached to the hardware is * enabled. Because it is not called for monitor mode devices, @start * and @stop must be implemented. @@ -1831,6 +1843,10 @@ struct ieee80211_ops { void (*tx)(struct ieee80211_hw *hw, struct sk_buff *skb); int (*start)(struct ieee80211_hw *hw); void (*stop)(struct ieee80211_hw *hw); +#ifdef CONFIG_PM + int (*suspend)(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan); + int (*resume)(struct ieee80211_hw *hw); +#endif int (*add_interface)(struct ieee80211_hw *hw, struct ieee80211_vif *vif); int (*change_interface)(struct ieee80211_hw *hw, diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index 321d598..1ebc133 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -1300,7 +1300,7 @@ static int ieee80211_set_channel(struct wiphy *wiphy, static int ieee80211_suspend(struct wiphy *wiphy, struct cfg80211_wowlan *wowlan) { - return __ieee80211_suspend(wiphy_priv(wiphy)); + return __ieee80211_suspend(wiphy_priv(wiphy), wowlan); } static int ieee80211_resume(struct wiphy *wiphy) diff --git a/net/mac80211/debugfs.c b/net/mac80211/debugfs.c index 0a602db..186e02f 100644 --- a/net/mac80211/debugfs.c +++ b/net/mac80211/debugfs.c @@ -135,7 +135,7 @@ static ssize_t reset_write(struct file *file, const char __user *user_buf, struct ieee80211_local *local = file->private_data; rtnl_lock(); - __ieee80211_suspend(&local->hw); + __ieee80211_suspend(&local->hw, NULL); __ieee80211_resume(&local->hw); rtnl_unlock(); diff --git a/net/mac80211/driver-ops.h b/net/mac80211/driver-ops.h index 2ddb56e..aa16bd8 100644 --- a/net/mac80211/driver-ops.h +++ b/net/mac80211/driver-ops.h @@ -41,6 +41,33 @@ static inline void drv_stop(struct ieee80211_local *local) local->started = false; } +#ifdef CONFIG_PM +static inline int drv_suspend(struct ieee80211_local *local, + struct cfg80211_wowlan *wowlan) +{ + int ret; + + might_sleep(); + + trace_drv_suspend(local); + ret = local->ops->suspend(&local->hw, wowlan); + trace_drv_return_int(local, ret); + return ret; +} + +static inline int drv_resume(struct ieee80211_local *local) +{ + int ret; + + might_sleep(); + + trace_drv_resume(local); + ret = local->ops->resume(&local->hw); + trace_drv_return_int(local, ret); + return ret; +} +#endif + static inline int drv_add_interface(struct ieee80211_local *local, struct ieee80211_vif *vif) { diff --git a/net/mac80211/driver-trace.h b/net/mac80211/driver-trace.h index 191e834..11e1ea5 100644 --- a/net/mac80211/driver-trace.h +++ b/net/mac80211/driver-trace.h @@ -108,6 +108,16 @@ DEFINE_EVENT(local_only_evt, drv_start, TP_ARGS(local) ); +DEFINE_EVENT(local_only_evt, drv_suspend, + TP_PROTO(struct ieee80211_local *local), + TP_ARGS(local) +); + +DEFINE_EVENT(local_only_evt, drv_resume, + TP_PROTO(struct ieee80211_local *local), + TP_ARGS(local) +); + DEFINE_EVENT(local_only_evt, drv_stop, TP_PROTO(struct ieee80211_local *local), TP_ARGS(local) diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 9e3b4f0..e89bc27 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -764,6 +764,9 @@ struct ieee80211_local { /* device is started */ bool started; + /* wowlan is enabled -- don't reconfig on resume */ + bool wowlan; + int tx_headroom; /* required headroom for hardware/radiotap */ /* count for keys needing tailroom space allocation */ @@ -1250,7 +1253,8 @@ int ieee80211_reconfig(struct ieee80211_local *local); void ieee80211_stop_device(struct ieee80211_local *local); #ifdef CONFIG_PM -int __ieee80211_suspend(struct ieee80211_hw *hw); +int __ieee80211_suspend(struct ieee80211_hw *hw, + struct cfg80211_wowlan *wowlan); static inline int __ieee80211_resume(struct ieee80211_hw *hw) { @@ -1263,7 +1267,8 @@ static inline int __ieee80211_resume(struct ieee80211_hw *hw) return ieee80211_reconfig(hw_to_local(hw)); } #else -static inline int __ieee80211_suspend(struct ieee80211_hw *hw) +static inline int __ieee80211_suspend(struct ieee80211_hw *hw, + struct cfg80211_wowlan *wowlan) { return 0; } diff --git a/net/mac80211/main.c b/net/mac80211/main.c index d8be198..cb326d3 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c @@ -696,6 +696,10 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) WLAN_CIPHER_SUITE_AES_CMAC }; + if ((hw->wiphy->wowlan.flags || hw->wiphy->wowlan.n_patterns) && + (!local->ops->suspend || !local->ops->resume)) + return -EINVAL; + if (hw->max_report_rates == 0) hw->max_report_rates = hw->max_rates; diff --git a/net/mac80211/pm.c b/net/mac80211/pm.c index 0424617..730778a 100644 --- a/net/mac80211/pm.c +++ b/net/mac80211/pm.c @@ -6,7 +6,7 @@ #include "driver-ops.h" #include "led.h" -int __ieee80211_suspend(struct ieee80211_hw *hw) +int __ieee80211_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan) { struct ieee80211_local *local = hw_to_local(hw); struct ieee80211_sub_if_data *sdata; @@ -47,6 +47,16 @@ int __ieee80211_suspend(struct ieee80211_hw *hw) cancel_work_sync(&local->dynamic_ps_enable_work); del_timer_sync(&local->dynamic_ps_timer); + local->wowlan = wowlan && local->open_count; + if (local->wowlan) { + int err = drv_suspend(local, wowlan); + if (err) { + local->quiescing = false; + return err; + } + goto suspend; + } + /* disable keys */ list_for_each_entry(sdata, &local->interfaces, list) ieee80211_disable_keys(sdata); @@ -104,6 +114,7 @@ int __ieee80211_suspend(struct ieee80211_hw *hw) if (local->open_count) ieee80211_stop_device(local); + suspend: local->suspended = true; /* need suspended to be visible before quiescing is false */ barrier(); diff --git a/net/mac80211/util.c b/net/mac80211/util.c index ef0560a..d3fe2d2 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c @@ -1125,9 +1125,27 @@ int ieee80211_reconfig(struct ieee80211_local *local) struct sta_info *sta; int res; +#ifdef CONFIG_PM if (local->suspended) local->resuming = true; + if (local->wowlan) { + local->wowlan = false; + res = drv_resume(local); + if (res < 0) { + local->resuming = false; + return res; + } + if (res == 0) + goto wake_up; + WARN_ON(res > 1); + /* + * res is 1, which means the driver requested + * to go through a regular reset on wakeup. + */ + } +#endif + /* restart hardware */ if (local->open_count) { /* @@ -1258,6 +1276,7 @@ int ieee80211_reconfig(struct ieee80211_local *local) if (ieee80211_sdata_running(sdata)) ieee80211_enable_keys(sdata); + wake_up: ieee80211_wake_queues_by_reason(hw, IEEE80211_QUEUE_STOP_REASON_SUSPEND); -- cgit v0.10.2 From 28ef6450f0182f95c4f50aaa0ab2043a09c72b0a Mon Sep 17 00:00:00 2001 From: Rajkumar Manoharan Date: Wed, 4 May 2011 19:37:17 +0530 Subject: ath9k_hw: do noise floor calibration only on required chains At present the noise floor calibration is processed in supported control and extension chains rather than required chains. Unnccesarily doing nfcal in all supported chains leads to invalid nf readings on extn chains and these invalid values got updated into history buffer. While loading those values from history buffer is moving the chip to deaf state. This issue was observed in AR9002/AR9003 chips while doing associate/dissociate in HT40 mode and interface up/down in iterative manner. After some iterations, the chip was moved to deaf state. Somehow the pci devices are recovered by poll work after chip reset. Raading the nf values in all supported extension chains when the hw is not yet configured in HT40 mode results invalid values. Cc: stable@kernel.org Signed-off-by: Rajkumar Manoharan Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/calib.c b/drivers/net/wireless/ath/ath9k/calib.c index 8649581..fe3c10e 100644 --- a/drivers/net/wireless/ath/ath9k/calib.c +++ b/drivers/net/wireless/ath/ath9k/calib.c @@ -69,15 +69,21 @@ static void ath9k_hw_update_nfcal_hist_buffer(struct ath_hw *ah, int16_t *nfarray) { struct ath_common *common = ath9k_hw_common(ah); + struct ieee80211_conf *conf = &common->hw->conf; struct ath_nf_limits *limit; struct ath9k_nfcal_hist *h; bool high_nf_mid = false; + u8 chainmask = (ah->rxchainmask << 3) | ah->rxchainmask; int i; h = cal->nfCalHist; limit = ath9k_hw_get_nf_limits(ah, ah->curchan); for (i = 0; i < NUM_NF_READINGS; i++) { + if (!(chainmask & (1 << i)) || + ((i >= AR5416_MAX_CHAINS) && !conf_is_ht40(conf))) + continue; + h[i].nfCalBuffer[h[i].currIndex] = nfarray[i]; if (++h[i].currIndex >= ATH9K_NF_CAL_HIST_MAX) @@ -225,6 +231,7 @@ void ath9k_hw_loadnf(struct ath_hw *ah, struct ath9k_channel *chan) int32_t val; u8 chainmask = (ah->rxchainmask << 3) | ah->rxchainmask; struct ath_common *common = ath9k_hw_common(ah); + struct ieee80211_conf *conf = &common->hw->conf; s16 default_nf = ath9k_hw_get_default_nf(ah, chan); if (ah->caldata) @@ -234,6 +241,9 @@ void ath9k_hw_loadnf(struct ath_hw *ah, struct ath9k_channel *chan) if (chainmask & (1 << i)) { s16 nfval; + if ((i >= AR5416_MAX_CHAINS) && !conf_is_ht40(conf)) + continue; + if (h) nfval = h[i].privNF; else @@ -293,6 +303,9 @@ void ath9k_hw_loadnf(struct ath_hw *ah, struct ath9k_channel *chan) ENABLE_REGWRITE_BUFFER(ah); for (i = 0; i < NUM_NF_READINGS; i++) { if (chainmask & (1 << i)) { + if ((i >= AR5416_MAX_CHAINS) && !conf_is_ht40(conf)) + continue; + val = REG_READ(ah, ah->nf_regs[i]); val &= 0xFFFFFE00; val |= (((u32) (-50) << 1) & 0x1ff); -- cgit v0.10.2 From aca355b9784fbc960c9caa6b30f953a965296420 Mon Sep 17 00:00:00 2001 From: Gertjan van Wingerde Date: Wed, 4 May 2011 21:41:36 +0200 Subject: rt2x00: Initial support for RT5370 USB devices. Add necessary RF chipset define and basic support for these devices. Tested-by: Juan Carlos Garza Signed-off-by: Gertjan van Wingerde Signed-off-by: Ivo van Doorn Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/rt2x00/Kconfig b/drivers/net/wireless/rt2x00/Kconfig index c457731..9def1e5 100644 --- a/drivers/net/wireless/rt2x00/Kconfig +++ b/drivers/net/wireless/rt2x00/Kconfig @@ -93,7 +93,7 @@ config RT2800PCI_RT35XX intended for testers and developers. config RT2800PCI_RT53XX - bool "rt2800-pci - Include support for rt53xx devices (EXPERIMENTAL)" + bool "rt2800pci - Include support for rt53xx devices (EXPERIMENTAL)" depends on EXPERIMENTAL default y ---help--- @@ -163,6 +163,15 @@ config RT2800USB_RT35XX Support for these devices is non-functional at the moment and is intended for testers and developers. +config RT2800USB_RT53XX + bool "rt2800usb - Include support for rt53xx devices (EXPERIMENTAL)" + depends on EXPERIMENTAL + default y + ---help--- + This adds support for rt53xx wireless chipset family to the + rt2800pci driver. + Supported chips: RT5370 + config RT2800USB_UNKNOWN bool "rt2800usb - Include support for unknown (USB) devices" default n diff --git a/drivers/net/wireless/rt2x00/rt2800.h b/drivers/net/wireless/rt2x00/rt2800.h index 3b3d851..47a04d2 100644 --- a/drivers/net/wireless/rt2x00/rt2800.h +++ b/drivers/net/wireless/rt2x00/rt2800.h @@ -51,6 +51,7 @@ * RF3320 2.4G 1T1R(RT3350/RT3370/RT3390) * RF3322 2.4G 2T2R(RT3352/RT3371/RT3372/RT3391/RT3392) * RF3853 2.4G/5G 3T3R(RT3883/RT3563/RT3573/RT3593/RT3662) + * RF5370 2.4G 1T1R * RF5390 2.4G 1T1R */ #define RF2820 0x0001 @@ -66,6 +67,7 @@ #define RF3320 0x000b #define RF3322 0x000c #define RF3853 0x000d +#define RF5370 0x5370 #define RF5390 0x5390 /* diff --git a/drivers/net/wireless/rt2x00/rt2800lib.c b/drivers/net/wireless/rt2x00/rt2800lib.c index 6ed646a..93fb674 100644 --- a/drivers/net/wireless/rt2x00/rt2800lib.c +++ b/drivers/net/wireless/rt2x00/rt2800lib.c @@ -1751,7 +1751,8 @@ static void rt2800_config_channel(struct rt2x00_dev *rt2x00dev, rt2x00_rf(rt2x00dev, RF3052) || rt2x00_rf(rt2x00dev, RF3320)) rt2800_config_channel_rf3xxx(rt2x00dev, conf, rf, info); - else if (rt2x00_rf(rt2x00dev, RF5390)) + else if (rt2x00_rf(rt2x00dev, RF5370) || + rt2x00_rf(rt2x00dev, RF5390)) rt2800_config_channel_rf53xx(rt2x00dev, conf, rf, info); else rt2800_config_channel_rf2xxx(rt2x00dev, conf, rf, info); @@ -3686,6 +3687,7 @@ int rt2800_init_eeprom(struct rt2x00_dev *rt2x00dev) !rt2x00_rf(rt2x00dev, RF3022) && !rt2x00_rf(rt2x00dev, RF3052) && !rt2x00_rf(rt2x00dev, RF3320) && + !rt2x00_rf(rt2x00dev, RF5370) && !rt2x00_rf(rt2x00dev, RF5390)) { ERROR(rt2x00dev, "Invalid RF chipset detected.\n"); return -ENODEV; @@ -3988,6 +3990,7 @@ int rt2800_probe_hw_mode(struct rt2x00_dev *rt2x00dev) rt2x00_rf(rt2x00dev, RF3021) || rt2x00_rf(rt2x00dev, RF3022) || rt2x00_rf(rt2x00dev, RF3320) || + rt2x00_rf(rt2x00dev, RF5370) || rt2x00_rf(rt2x00dev, RF5390)) { spec->num_channels = 14; spec->channels = rf_vals_3x; diff --git a/drivers/net/wireless/rt2x00/rt2800usb.c b/drivers/net/wireless/rt2x00/rt2800usb.c index 0eb44cf..ba82c97 100644 --- a/drivers/net/wireless/rt2x00/rt2800usb.c +++ b/drivers/net/wireless/rt2x00/rt2800usb.c @@ -1000,6 +1000,14 @@ static struct usb_device_id rt2800usb_device_table[] = { /* Zinwell */ { USB_DEVICE(0x5a57, 0x0284) }, #endif +#ifdef CONFIG_RT2800USB_RT53XX + /* Azurewave */ + { USB_DEVICE(0x13d3, 0x3329) }, + { USB_DEVICE(0x13d3, 0x3365) }, + /* Ralink */ + { USB_DEVICE(0x148f, 0x5370) }, + { USB_DEVICE(0x148f, 0x5372) }, +#endif #ifdef CONFIG_RT2800USB_UNKNOWN /* * Unclear what kind of devices these are (they aren't supported by the -- cgit v0.10.2 From 4268d8ed64ed918384954924284ba396cdb0e388 Mon Sep 17 00:00:00 2001 From: Ivo van Doorn Date: Wed, 4 May 2011 21:42:05 +0200 Subject: rt2x00: Fix transfer speed regression for USB hardware Patch: rt2x00: Make rt2x00_queue_entry_for_each more flexible commit: 10e11568ca8b8a15f7478f6a4ceebabcbdba1018 introduced a severe regression on the throughput for USB hardware. It turns out that the exiting of the rt2x00queue_for_each_entry() was done too early. The exact cause for this regression is unknown, but by disabling the premature exiting of the loop seems to resolve the issue. Signed-off-by: Ivo van Doorn Reported-by: Yasushi SHOJI Reported-by: Balint Viragh Tested-by: Balint Viragh Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/rt2x00/rt2x00usb.c b/drivers/net/wireless/rt2x00/rt2x00usb.c index e027ebd..dc6b662 100644 --- a/drivers/net/wireless/rt2x00/rt2x00usb.c +++ b/drivers/net/wireless/rt2x00/rt2x00usb.c @@ -298,7 +298,7 @@ static bool rt2x00usb_kick_tx_entry(struct queue_entry *entry, void* data) if (!test_and_clear_bit(ENTRY_DATA_PENDING, &entry->flags) || test_bit(ENTRY_DATA_STATUS_PENDING, &entry->flags)) - return true; + return false; /* * USB devices cannot blindly pass the skb->len as the @@ -392,7 +392,7 @@ static bool rt2x00usb_kick_rx_entry(struct queue_entry *entry, void* data) if (test_and_set_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags) || test_bit(ENTRY_DATA_STATUS_PENDING, &entry->flags)) - return true; + return false; rt2x00lib_dmastart(entry); @@ -447,7 +447,7 @@ static bool rt2x00usb_flush_entry(struct queue_entry *entry, void* data) struct queue_entry_priv_usb_bcn *bcn_priv = entry->priv_data; if (!test_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags)) - return true; + return false; usb_kill_urb(entry_priv->urb); -- cgit v0.10.2 From cf3a03b9c99a0b2715741d116f50f513f545bb2d Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Wed, 4 May 2011 14:01:26 -0700 Subject: ath9k_hw: fix power for the HT40 duplicate frames With AR9003 at about ~ 10 feet from an AP that uses RTS / CTS you will be able to associate but not not get data through given that the power for the rates used was set too low. This increases the power and permits data connectivity at longer distances from access points when connected with HT40. Without this you will not get any data through when associated to APs configured in HT40 at about more than 10 feet away. Cc: stable@kernel.org Cc: Fiona Cain Cc: Zhen Xie Cc: Kathy Giori Cc: Neha Choksi Cc: Wayne Daniel Cc: Gaurav Jauhar Cc: Samira Naraghi CC: Ashok Chennupati Cc: Lance Zimmerman Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c b/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c index 97f970c..a9dd3a4 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c @@ -4005,6 +4005,16 @@ static int ar9003_hw_tx_power_regwrite(struct ath_hw *ah, u8 * pPwrArray) POW_SM(pPwrArray[ALL_TARGET_LEGACY_1L_5L], 0) ); + /* Write the power for duplicated frames - HT40 */ + + /* dup40_cck (LSB), dup40_ofdm, ext20_cck, ext20_ofdm (MSB) */ + REG_WRITE(ah, 0xa3e0, + POW_SM(pPwrArray[ALL_TARGET_LEGACY_6_24], 24) | + POW_SM(pPwrArray[ALL_TARGET_LEGACY_1L_5L], 16) | + POW_SM(pPwrArray[ALL_TARGET_LEGACY_6_24], 8) | + POW_SM(pPwrArray[ALL_TARGET_LEGACY_1L_5L], 0) + ); + /* Write the HT20 power per rate set */ /* 0/8/16 (LSB), 1-3/9-11/17-19, 4, 5 (MSB) */ -- cgit v0.10.2 From fc2b1e0cfe9b4cabde8afeacc2bb81a95bf83afb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= Date: Thu, 5 May 2011 12:45:52 +0200 Subject: b43: drop invalid IMCFGLO workaround MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We were performing it on wrong core, it was outdated and is already implemented in ssb. Signed-off-by: RafaÅ‚ MiÅ‚ecki Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c index 57eb5b6..675e288 100644 --- a/drivers/net/wireless/b43/main.c +++ b/drivers/net/wireless/b43/main.c @@ -4212,33 +4212,7 @@ static void b43_bluetooth_coext_disable(struct b43_wldev *dev) static void b43_imcfglo_timeouts_workaround(struct b43_wldev *dev) { -#ifdef CONFIG_SSB_DRIVER_PCICORE - struct ssb_bus *bus = dev->dev->bus; - u32 tmp; - - if (bus->pcicore.dev && - bus->pcicore.dev->id.coreid == SSB_DEV_PCI && - bus->pcicore.dev->id.revision <= 5) { - /* IMCFGLO timeouts workaround. */ - tmp = ssb_read32(dev->dev, SSB_IMCFGLO); - switch (bus->bustype) { - case SSB_BUSTYPE_PCI: - case SSB_BUSTYPE_PCMCIA: - tmp &= ~SSB_IMCFGLO_REQTO; - tmp &= ~SSB_IMCFGLO_SERTO; - tmp |= 0x32; - break; - case SSB_BUSTYPE_SSB: - tmp &= ~SSB_IMCFGLO_REQTO; - tmp &= ~SSB_IMCFGLO_SERTO; - tmp |= 0x53; - break; - default: - break; - } - ssb_write32(dev->dev, SSB_IMCFGLO, tmp); - } -#endif /* CONFIG_SSB_DRIVER_PCICORE */ + /* TODO: implement 80211 core workaround here */ } static void b43_set_synth_pu_delay(struct b43_wldev *dev, bool idle) -- cgit v0.10.2 From eee40820e95e6dbd7b0709e7b8cca453004ae7b1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= Date: Thu, 5 May 2011 12:46:04 +0200 Subject: b43legacy: drop invalid IMCFGLO workaround MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We were performing it on wrong core, it was outdated and is already implemented in ssb. Signed-off-by: RafaÅ‚ MiÅ‚ecki Tested-by: Larry Finger Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/b43legacy/main.c b/drivers/net/wireless/b43legacy/main.c index c7fd73e..2162663 100644 --- a/drivers/net/wireless/b43legacy/main.c +++ b/drivers/net/wireless/b43legacy/main.c @@ -3104,37 +3104,6 @@ static void setup_struct_wldev_for_init(struct b43legacy_wldev *dev) memset(&dev->noisecalc, 0, sizeof(dev->noisecalc)); } -static void b43legacy_imcfglo_timeouts_workaround(struct b43legacy_wldev *dev) -{ -#ifdef CONFIG_SSB_DRIVER_PCICORE - struct ssb_bus *bus = dev->dev->bus; - u32 tmp; - - if (bus->pcicore.dev && - bus->pcicore.dev->id.coreid == SSB_DEV_PCI && - bus->pcicore.dev->id.revision <= 5) { - /* IMCFGLO timeouts workaround. */ - tmp = ssb_read32(dev->dev, SSB_IMCFGLO); - switch (bus->bustype) { - case SSB_BUSTYPE_PCI: - case SSB_BUSTYPE_PCMCIA: - tmp &= ~SSB_IMCFGLO_REQTO; - tmp &= ~SSB_IMCFGLO_SERTO; - tmp |= 0x32; - break; - case SSB_BUSTYPE_SSB: - tmp &= ~SSB_IMCFGLO_REQTO; - tmp &= ~SSB_IMCFGLO_SERTO; - tmp |= 0x53; - break; - default: - break; - } - ssb_write32(dev->dev, SSB_IMCFGLO, tmp); - } -#endif /* CONFIG_SSB_DRIVER_PCICORE */ -} - static void b43legacy_set_synth_pu_delay(struct b43legacy_wldev *dev, bool idle) { u16 pu_delay = 1050; @@ -3278,7 +3247,6 @@ static int b43legacy_wireless_core_init(struct b43legacy_wldev *dev) /* Enable IRQ routing to this device. */ ssb_pcicore_dev_irqvecs_enable(&bus->pcicore, dev->dev); - b43legacy_imcfglo_timeouts_workaround(dev); prepare_phy_data_for_init(dev); b43legacy_phy_calibrate(dev); err = b43legacy_chip_init(dev); -- cgit v0.10.2 From e4eefec73ea0a740bfe8736e3ac30dfe92fe392b Mon Sep 17 00:00:00 2001 From: Yogesh Ashok Powar Date: Thu, 5 May 2011 16:30:48 +0530 Subject: mwl8k: Do not ask mac80211 to generate IV for crypto keys Since firmware is capable of generating IV's for all crypto suits (TKIP, CCMP and WEP), do not ask mac80211 to generate IV when HW crypto is being used. Instead only reserve appropriate space in tx skb's in the driver, so that the firmware can write IV's values. Signed-off-by: Yogesh Ashok Powar Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c index d06591a..3226118 100644 --- a/drivers/net/wireless/mwl8k.c +++ b/drivers/net/wireless/mwl8k.c @@ -784,7 +784,8 @@ static inline void mwl8k_remove_dma_header(struct sk_buff *skb, __le16 qos) #define REDUCED_TX_HEADROOM 8 static void -mwl8k_add_dma_header(struct mwl8k_priv *priv, struct sk_buff *skb, int tail_pad) +mwl8k_add_dma_header(struct mwl8k_priv *priv, struct sk_buff *skb, + int head_pad, int tail_pad) { struct ieee80211_hdr *wh; int hdrlen; @@ -816,7 +817,7 @@ mwl8k_add_dma_header(struct mwl8k_priv *priv, struct sk_buff *skb, int tail_pad) skb->truesize += REDUCED_TX_HEADROOM; } - reqd_hdrlen = sizeof(*tr); + reqd_hdrlen = sizeof(*tr) + head_pad; if (hdrlen != reqd_hdrlen) skb_push(skb, reqd_hdrlen - hdrlen); @@ -845,6 +846,7 @@ static void mwl8k_encapsulate_tx_frame(struct mwl8k_priv *priv, struct ieee80211_tx_info *tx_info; struct ieee80211_key_conf *key_conf; int data_pad; + int head_pad = 0; wh = (struct ieee80211_hdr *)skb->data; @@ -856,9 +858,7 @@ static void mwl8k_encapsulate_tx_frame(struct mwl8k_priv *priv, /* * Make sure the packet header is in the DMA header format (4-address - * without QoS), the necessary crypto padding between the header and the - * payload has already been provided by mac80211, but it doesn't add - * tail padding when HW crypto is enabled. + * without QoS), and add head & tail padding when HW crypto is enabled. * * We have the following trailer padding requirements: * - WEP: 4 trailer bytes (ICV) @@ -867,6 +867,7 @@ static void mwl8k_encapsulate_tx_frame(struct mwl8k_priv *priv, */ data_pad = 0; if (key_conf != NULL) { + head_pad = key_conf->iv_len; switch (key_conf->cipher) { case WLAN_CIPHER_SUITE_WEP40: case WLAN_CIPHER_SUITE_WEP104: @@ -880,7 +881,7 @@ static void mwl8k_encapsulate_tx_frame(struct mwl8k_priv *priv, break; } } - mwl8k_add_dma_header(priv, skb, data_pad); + mwl8k_add_dma_header(priv, skb, head_pad, data_pad); } /* @@ -1837,7 +1838,7 @@ mwl8k_txq_xmit(struct ieee80211_hw *hw, int index, struct sk_buff *skb) if (priv->ap_fw) mwl8k_encapsulate_tx_frame(priv, skb); else - mwl8k_add_dma_header(priv, skb, 0); + mwl8k_add_dma_header(priv, skb, 0, 0); wh = &((struct mwl8k_dma_data *)skb->data)->wh; @@ -4071,7 +4072,6 @@ static int mwl8k_set_key(struct ieee80211_hw *hw, addr = sta->addr; if (cmd_param == SET_KEY) { - key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV; rc = mwl8k_cmd_encryption_set_key(hw, vif, addr, key); if (rc) goto out; -- cgit v0.10.2 From 79af2187fa27442e89437d8ee637578cdb1a036c Mon Sep 17 00:00:00 2001 From: Stephen Rothwell Date: Fri, 6 May 2011 10:39:08 +1000 Subject: powerpc: Fix compile with icwsx support Due to a collision between NO_CONTEXT->MMU_NO_CONTEXT change and Anton's patch. Signed-off-by: Stephen Rothwell Signed-off-by: Benjamin Herrenschmidt diff --git a/arch/powerpc/mm/mmu_context_hash64.c b/arch/powerpc/mm/mmu_context_hash64.c index c517815..3bafc3d 100644 --- a/arch/powerpc/mm/mmu_context_hash64.c +++ b/arch/powerpc/mm/mmu_context_hash64.c @@ -279,7 +279,7 @@ int init_new_context(struct task_struct *tsk, struct mm_struct *mm) if (!mm->context.cop_lockp) { __destroy_context(index); subpage_prot_free(mm); - mm->context.id = NO_CONTEXT; + mm->context.id = MMU_NO_CONTEXT; return -ENOMEM; } spin_lock_init(mm->context.cop_lockp); -- cgit v0.10.2 From 4cb4638079a487627232ffee5b48ca19c127aed8 Mon Sep 17 00:00:00 2001 From: "Tseng-Hui (Frank) Lin" Date: Tue, 3 May 2011 18:28:43 +0000 Subject: powerpc/pseries: Add RTAS event log v6 definition This patch adds definitions of non-IBM specific v6 extended log definitions to rtas.h. Signed-off-by: Tseng-Hui (Frank) Lin Signed-off-by: Benjamin Herrenschmidt diff --git a/arch/powerpc/include/asm/rtas.h b/arch/powerpc/include/asm/rtas.h index 9a1193e..58625d1 100644 --- a/arch/powerpc/include/asm/rtas.h +++ b/arch/powerpc/include/asm/rtas.h @@ -158,7 +158,50 @@ struct rtas_error_log { unsigned long target:4; /* Target of failed operation */ unsigned long type:8; /* General event or error*/ unsigned long extended_log_length:32; /* length in bytes */ - unsigned char buffer[1]; + unsigned char buffer[1]; /* Start of extended log */ + /* Variable length. */ +}; + +#define RTAS_V6EXT_LOG_FORMAT_EVENT_LOG 14 + +#define RTAS_V6EXT_COMPANY_ID_IBM (('I' << 24) | ('B' << 16) | ('M' << 8)) + +/* RTAS general extended event log, Version 6. The extended log starts + * from "buffer" field of struct rtas_error_log defined above. + */ +struct rtas_ext_event_log_v6 { + /* Byte 0 */ + uint32_t log_valid:1; /* 1:Log valid */ + uint32_t unrecoverable_error:1; /* 1:Unrecoverable error */ + uint32_t recoverable_error:1; /* 1:recoverable (correctable */ + /* or successfully retried) */ + uint32_t degraded_operation:1; /* 1:Unrecoverable err, bypassed*/ + /* - degraded operation (e.g. */ + /* CPU or mem taken off-line) */ + uint32_t predictive_error:1; + uint32_t new_log:1; /* 1:"New" log (Always 1 for */ + /* data returned from RTAS */ + uint32_t big_endian:1; /* 1: Big endian */ + uint32_t :1; /* reserved */ + /* Byte 1 */ + uint32_t :8; /* reserved */ + /* Byte 2 */ + uint32_t powerpc_format:1; /* Set to 1 (indicating log is */ + /* in PowerPC format */ + uint32_t :3; /* reserved */ + uint32_t log_format:4; /* Log format indicator. Define */ + /* format used for byte 12-2047 */ + /* Byte 3 */ + uint32_t :8; /* reserved */ + /* Byte 4-11 */ + uint8_t reserved[8]; /* reserved */ + /* Byte 12-15 */ + uint32_t company_id; /* Company ID of the company */ + /* that defines the format for */ + /* the vendor specific log type */ + /* Byte 16-end of log */ + uint8_t vendor_log[1]; /* Start of vendor specific log */ + /* Variable length. */ }; /* -- cgit v0.10.2 From 77eafe101a65b609b0693ee4eda381f60a4a5bab Mon Sep 17 00:00:00 2001 From: "Tseng-Hui (Frank) Lin" Date: Thu, 5 May 2011 12:32:48 +0000 Subject: powerpc/pseries: Add support for IO event interrupts This patch adds support for handling IO Event interrupts which come through at the /event-sources/ibm,io-events device tree node. The interrupts come through ibm,io-events device tree node are generated by the firmware to report IO events. The firmware uses the same interrupt to report multiple types of events for multiple devices. Each device may have its own event handler. This patch implements a plateform interrupt handler that is triggered by the IO event interrupts come through ibm,io-events device tree node, pull in the IO events from RTAS and call device event handlers registered in the notifier list. Device event handlers are expected to use atomic_notifier_chain_register() and atomic_notifier_chain_unregister() to register/unregister their event handler in pseries_ioei_notifier_list list with IO event interrupt. Device event handlers are responsible to identify if the event belongs to the device event handler. The device event handle should return NOTIFY_OK after the event is handled if the event belongs to the device event handler, or NOTIFY_DONE otherwise. Signed-off-by: Tseng-Hui (Frank) Lin Signed-off-by: Benjamin Herrenschmidt diff --git a/arch/powerpc/include/asm/io_event_irq.h b/arch/powerpc/include/asm/io_event_irq.h new file mode 100644 index 0000000..b1a9a1b --- /dev/null +++ b/arch/powerpc/include/asm/io_event_irq.h @@ -0,0 +1,54 @@ +/* + * Copyright 2010, 2011 Mark Nelson and Tseng-Hui (Frank) Lin, IBM Corporation + * + * 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 _ASM_POWERPC_IO_EVENT_IRQ_H +#define _ASM_POWERPC_IO_EVENT_IRQ_H + +#include +#include + +#define PSERIES_IOEI_RPC_MAX_LEN 216 + +#define PSERIES_IOEI_TYPE_ERR_DETECTED 0x01 +#define PSERIES_IOEI_TYPE_ERR_RECOVERED 0x02 +#define PSERIES_IOEI_TYPE_EVENT 0x03 +#define PSERIES_IOEI_TYPE_RPC_PASS_THRU 0x04 + +#define PSERIES_IOEI_SUBTYPE_NOT_APP 0x00 +#define PSERIES_IOEI_SUBTYPE_REBALANCE_REQ 0x01 +#define PSERIES_IOEI_SUBTYPE_NODE_ONLINE 0x03 +#define PSERIES_IOEI_SUBTYPE_NODE_OFFLINE 0x04 +#define PSERIES_IOEI_SUBTYPE_DUMP_SIZE_CHANGE 0x05 +#define PSERIES_IOEI_SUBTYPE_TORRENT_IRV_UPDATE 0x06 +#define PSERIES_IOEI_SUBTYPE_TORRENT_HFI_CFGED 0x07 + +#define PSERIES_IOEI_SCOPE_NOT_APP 0x00 +#define PSERIES_IOEI_SCOPE_RIO_HUB 0x36 +#define PSERIES_IOEI_SCOPE_RIO_BRIDGE 0x37 +#define PSERIES_IOEI_SCOPE_PHB 0x38 +#define PSERIES_IOEI_SCOPE_EADS_GLOBAL 0x39 +#define PSERIES_IOEI_SCOPE_EADS_SLOT 0x3A +#define PSERIES_IOEI_SCOPE_TORRENT_HUB 0x3B +#define PSERIES_IOEI_SCOPE_SERVICE_PROC 0x51 + +/* Platform Event Log Format, Version 6, data portition of IO event section */ +struct pseries_io_event { + uint8_t event_type; /* 0x00 IO-Event Type */ + uint8_t rpc_data_len; /* 0x01 RPC data length */ + uint8_t scope; /* 0x02 Error/Event Scope */ + uint8_t event_subtype; /* 0x03 I/O-Event Sub-Type */ + uint32_t drc_index; /* 0x04 DRC Index */ + uint8_t rpc_data[PSERIES_IOEI_RPC_MAX_LEN]; + /* 0x08 RPC Data (0-216 bytes, */ + /* padded to 4 bytes alignment) */ +}; + +extern struct atomic_notifier_head pseries_ioei_notifier_list; + +#endif /* _ASM_POWERPC_IO_EVENT_IRQ_H */ diff --git a/arch/powerpc/platforms/pseries/Kconfig b/arch/powerpc/platforms/pseries/Kconfig index b044922..71af4c5 100644 --- a/arch/powerpc/platforms/pseries/Kconfig +++ b/arch/powerpc/platforms/pseries/Kconfig @@ -50,6 +50,24 @@ config SCANLOG tristate "Scanlog dump interface" depends on RTAS_PROC && PPC_PSERIES +config IO_EVENT_IRQ + bool "IO Event Interrupt support" + depends on PPC_PSERIES + default y + help + Select this option, if you want to enable support for IO Event + interrupts. IO event interrupt is a mechanism provided by RTAS + to return information about hardware error and non-error events + which may need OS attention. RTAS returns events for multiple + event types and scopes. Device drivers can register their handlers + to receive events. + + This option will only enable the IO event platform code. You + will still need to enable or compile the actual drivers + that use this infrastruture to handle IO event interrupts. + + Say Y if you are unsure. + config LPARCFG bool "LPAR Configuration Data" depends on PPC_PSERIES || PPC_ISERIES diff --git a/arch/powerpc/platforms/pseries/Makefile b/arch/powerpc/platforms/pseries/Makefile index 4cfefba..3556e40 100644 --- a/arch/powerpc/platforms/pseries/Makefile +++ b/arch/powerpc/platforms/pseries/Makefile @@ -21,6 +21,7 @@ obj-$(CONFIG_HCALL_STATS) += hvCall_inst.o obj-$(CONFIG_PHYP_DUMP) += phyp_dump.o obj-$(CONFIG_CMM) += cmm.o obj-$(CONFIG_DTL) += dtl.o +obj-$(CONFIG_IO_EVENT_IRQ) += io_event_irq.o ifeq ($(CONFIG_PPC_PSERIES),y) obj-$(CONFIG_SUSPEND) += suspend.o diff --git a/arch/powerpc/platforms/pseries/io_event_irq.c b/arch/powerpc/platforms/pseries/io_event_irq.c new file mode 100644 index 0000000..c829e60 --- /dev/null +++ b/arch/powerpc/platforms/pseries/io_event_irq.c @@ -0,0 +1,231 @@ +/* + * Copyright 2010 2011 Mark Nelson and Tseng-Hui (Frank) Lin, IBM Corporation + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "pseries.h" + +/* + * IO event interrupt is a mechanism provided by RTAS to return + * information about hardware error and non-error events. Device + * drivers can register their event handlers to receive events. + * Device drivers are expected to use atomic_notifier_chain_register() + * and atomic_notifier_chain_unregister() to register and unregister + * their event handlers. Since multiple IO event types and scopes + * share an IO event interrupt, the event handlers are called one + * by one until the IO event is claimed by one of the handlers. + * The event handlers are expected to return NOTIFY_OK if the + * event is handled by the event handler or NOTIFY_DONE if the + * event does not belong to the handler. + * + * Usage: + * + * Notifier function: + * #include + * int event_handler(struct notifier_block *nb, unsigned long val, void *data) { + * p = (struct pseries_io_event_sect_data *) data; + * if (! is_my_event(p->scope, p->event_type)) return NOTIFY_DONE; + * : + * : + * return NOTIFY_OK; + * } + * struct notifier_block event_nb = { + * .notifier_call = event_handler, + * } + * + * Registration: + * atomic_notifier_chain_register(&pseries_ioei_notifier_list, &event_nb); + * + * Unregistration: + * atomic_notifier_chain_unregister(&pseries_ioei_notifier_list, &event_nb); + */ + +ATOMIC_NOTIFIER_HEAD(pseries_ioei_notifier_list); +EXPORT_SYMBOL_GPL(pseries_ioei_notifier_list); + +static int ioei_check_exception_token; + +/* pSeries event log format */ + +/* Two bytes ASCII section IDs */ +#define PSERIES_ELOG_SECT_ID_PRIV_HDR (('P' << 8) | 'H') +#define PSERIES_ELOG_SECT_ID_USER_HDR (('U' << 8) | 'H') +#define PSERIES_ELOG_SECT_ID_PRIMARY_SRC (('P' << 8) | 'S') +#define PSERIES_ELOG_SECT_ID_EXTENDED_UH (('E' << 8) | 'H') +#define PSERIES_ELOG_SECT_ID_FAILING_MTMS (('M' << 8) | 'T') +#define PSERIES_ELOG_SECT_ID_SECONDARY_SRC (('S' << 8) | 'S') +#define PSERIES_ELOG_SECT_ID_DUMP_LOCATOR (('D' << 8) | 'H') +#define PSERIES_ELOG_SECT_ID_FW_ERROR (('S' << 8) | 'W') +#define PSERIES_ELOG_SECT_ID_IMPACT_PART_ID (('L' << 8) | 'P') +#define PSERIES_ELOG_SECT_ID_LOGIC_RESOURCE_ID (('L' << 8) | 'R') +#define PSERIES_ELOG_SECT_ID_HMC_ID (('H' << 8) | 'M') +#define PSERIES_ELOG_SECT_ID_EPOW (('E' << 8) | 'P') +#define PSERIES_ELOG_SECT_ID_IO_EVENT (('I' << 8) | 'E') +#define PSERIES_ELOG_SECT_ID_MANUFACT_INFO (('M' << 8) | 'I') +#define PSERIES_ELOG_SECT_ID_CALL_HOME (('C' << 8) | 'H') +#define PSERIES_ELOG_SECT_ID_USER_DEF (('U' << 8) | 'D') + +/* Vendor specific Platform Event Log Format, Version 6, section header */ +struct pseries_elog_section { + uint16_t id; /* 0x00 2-byte ASCII section ID */ + uint16_t length; /* 0x02 Section length in bytes */ + uint8_t version; /* 0x04 Section version */ + uint8_t subtype; /* 0x05 Section subtype */ + uint16_t creator_component; /* 0x06 Creator component ID */ + uint8_t data[]; /* 0x08 Start of section data */ +}; + +static char ioei_rtas_buf[RTAS_DATA_BUF_SIZE] __cacheline_aligned; + +/** + * Find data portion of a specific section in RTAS extended event log. + * @elog: RTAS error/event log. + * @sect_id: secsion ID. + * + * Return: + * pointer to the section data of the specified section + * NULL if not found + */ +static struct pseries_elog_section *find_xelog_section(struct rtas_error_log *elog, + uint16_t sect_id) +{ + struct rtas_ext_event_log_v6 *xelog = + (struct rtas_ext_event_log_v6 *) elog->buffer; + struct pseries_elog_section *sect; + unsigned char *p, *log_end; + + /* Check that we understand the format */ + if (elog->extended_log_length < sizeof(struct rtas_ext_event_log_v6) || + xelog->log_format != RTAS_V6EXT_LOG_FORMAT_EVENT_LOG || + xelog->company_id != RTAS_V6EXT_COMPANY_ID_IBM) + return NULL; + + log_end = elog->buffer + elog->extended_log_length; + p = xelog->vendor_log; + while (p < log_end) { + sect = (struct pseries_elog_section *)p; + if (sect->id == sect_id) + return sect; + p += sect->length; + } + return NULL; +} + +/** + * Find the data portion of an IO Event section from event log. + * @elog: RTAS error/event log. + * + * Return: + * pointer to a valid IO event section data. NULL if not found. + */ +static struct pseries_io_event * ioei_find_event(struct rtas_error_log *elog) +{ + struct pseries_elog_section *sect; + + /* We should only ever get called for io-event interrupts, but if + * we do get called for another type then something went wrong so + * make some noise about it. + * RTAS_TYPE_IO only exists in extended event log version 6 or later. + * No need to check event log version. + */ + if (unlikely(elog->type != RTAS_TYPE_IO)) { + printk_once(KERN_WARNING "io_event_irq: Unexpected event type %d", + elog->type); + return NULL; + } + + sect = find_xelog_section(elog, PSERIES_ELOG_SECT_ID_IO_EVENT); + if (unlikely(!sect)) { + printk_once(KERN_WARNING "io_event_irq: RTAS extended event " + "log does not contain an IO Event section. " + "Could be a bug in system firmware!\n"); + return NULL; + } + return (struct pseries_io_event *) §->data; +} + +/* + * PAPR: + * - check-exception returns the first found error or event and clear that + * error or event so it is reported once. + * - Each interrupt returns one event. If a plateform chooses to report + * multiple events through a single interrupt, it must ensure that the + * interrupt remains asserted until check-exception has been used to + * process all out-standing events for that interrupt. + * + * Implementation notes: + * - Events must be processed in the order they are returned. Hence, + * sequential in nature. + * - The owner of an event is determined by combinations of scope, + * event type, and sub-type. There is no easy way to pre-sort clients + * by scope or event type alone. For example, Torrent ISR route change + * event is reported with scope 0x00 (Not Applicatable) rather than + * 0x3B (Torrent-hub). It is better to let the clients to identify + * who owns the the event. + */ + +static irqreturn_t ioei_interrupt(int irq, void *dev_id) +{ + struct pseries_io_event *event; + int rtas_rc; + + for (;;) { + rtas_rc = rtas_call(ioei_check_exception_token, 6, 1, NULL, + RTAS_VECTOR_EXTERNAL_INTERRUPT, + virq_to_hw(irq), + RTAS_IO_EVENTS, 1 /* Time Critical */, + __pa(ioei_rtas_buf), + RTAS_DATA_BUF_SIZE); + if (rtas_rc != 0) + break; + + event = ioei_find_event((struct rtas_error_log *)ioei_rtas_buf); + if (!event) + continue; + + atomic_notifier_call_chain(&pseries_ioei_notifier_list, + 0, event); + } + return IRQ_HANDLED; +} + +static int __init ioei_init(void) +{ + struct device_node *np; + + ioei_check_exception_token = rtas_token("check-exception"); + if (ioei_check_exception_token == RTAS_UNKNOWN_SERVICE) { + pr_warning("IO Event IRQ not supported on this system !\n"); + return -ENODEV; + } + np = of_find_node_by_path("/event-sources/ibm,io-events"); + if (np) { + request_event_sources_irqs(np, ioei_interrupt, "IO_EVENT"); + of_node_put(np); + } else { + pr_err("io_event_irq: No ibm,io-events on system! " + "IO Event interrupt disabled.\n"); + return -ENODEV; + } + return 0; +} +machine_subsys_initcall(pseries, ioei_init); + -- cgit v0.10.2 From 40bd587a88fcd425f489f3d9f0be7daa84014141 Mon Sep 17 00:00:00 2001 From: Benjamin Herrenschmidt Date: Tue, 3 May 2011 14:07:01 +0000 Subject: powerpc: Rename slb0_limit() to safe_stack_limit() and add Book3E support slb0_limit() wasn't a very descriptive name. This changes it along with a comment explaining what it's used for, and provides a 64-bit BookE implementation. Signed-off-by: Benjamin Herrenschmidt diff --git a/arch/powerpc/include/asm/mmu-book3e.h b/arch/powerpc/include/asm/mmu-book3e.h index ec61e7b..3ea0f9a 100644 --- a/arch/powerpc/include/asm/mmu-book3e.h +++ b/arch/powerpc/include/asm/mmu-book3e.h @@ -245,6 +245,10 @@ extern struct mmu_psize_def mmu_psize_defs[MMU_PAGE_COUNT]; extern int mmu_linear_psize; extern int mmu_vmemmap_psize; +#ifdef CONFIG_PPC64 +extern unsigned long linear_map_top; +#endif + #endif /* !__ASSEMBLY__ */ #endif /* _ASM_POWERPC_MMU_BOOK3E_H_ */ diff --git a/arch/powerpc/kernel/setup_64.c b/arch/powerpc/kernel/setup_64.c index 959c63c..c2ec0a1 100644 --- a/arch/powerpc/kernel/setup_64.c +++ b/arch/powerpc/kernel/setup_64.c @@ -434,17 +434,30 @@ void __init setup_system(void) DBG(" <- setup_system()\n"); } -static u64 slb0_limit(void) +/* This returns the limit below which memory accesses to the linear + * mapping are guarnateed not to cause a TLB or SLB miss. This is + * used to allocate interrupt or emergency stacks for which our + * exception entry path doesn't deal with being interrupted. + */ +static u64 safe_stack_limit(void) { - if (mmu_has_feature(MMU_FTR_1T_SEGMENT)) { +#ifdef CONFIG_PPC_BOOK3E + /* Freescale BookE bolts the entire linear mapping */ + if (mmu_has_feature(MMU_FTR_TYPE_FSL_E)) + return linear_map_top; + /* Other BookE, we assume the first GB is bolted */ + return 1ul << 30; +#else + /* BookS, the first segment is bolted */ + if (mmu_has_feature(MMU_FTR_1T_SEGMENT)) return 1UL << SID_SHIFT_1T; - } return 1UL << SID_SHIFT; +#endif } static void __init irqstack_early_init(void) { - u64 limit = slb0_limit(); + u64 limit = safe_stack_limit(); unsigned int i; /* @@ -497,7 +510,7 @@ static void __init emergency_stack_init(void) * bringup, we need to get at them in real mode. This means they * must also be within the RMO region. */ - limit = min(slb0_limit(), ppc64_rma_size); + limit = min(safe_stack_limit(), ppc64_rma_size); for_each_possible_cpu(i) { unsigned long sp; -- cgit v0.10.2 From 82578e192bb837b984ed5d8389245ea1fee09dd5 Mon Sep 17 00:00:00 2001 From: Richard A Lary Date: Wed, 4 May 2011 12:57:18 +0000 Subject: powerpc/eeh: Display eeh error location for bus and device For adapters which have devices under a PCIe switch/bridge it is informative to display information for both the PCIe switch/bridge and the device on which the bus error was detected. rebased to powerpc-next Signed-off-by: Richard A Lary Signed-off-by: Benjamin Herrenschmidt diff --git a/arch/powerpc/platforms/pseries/eeh_driver.c b/arch/powerpc/platforms/pseries/eeh_driver.c index b8d70f5..1b6cb10 100644 --- a/arch/powerpc/platforms/pseries/eeh_driver.c +++ b/arch/powerpc/platforms/pseries/eeh_driver.c @@ -328,7 +328,7 @@ struct pci_dn * handle_eeh_events (struct eeh_event *event) struct pci_bus *frozen_bus; int rc = 0; enum pci_ers_result result = PCI_ERS_RESULT_NONE; - const char *location, *pci_str, *drv_str; + const char *location, *pci_str, *drv_str, *bus_pci_str, *bus_drv_str; frozen_dn = find_device_pe(event->dn); if (!frozen_dn) { @@ -364,13 +364,8 @@ struct pci_dn * handle_eeh_events (struct eeh_event *event) frozen_pdn = PCI_DN(frozen_dn); frozen_pdn->eeh_freeze_count++; - if (frozen_pdn->pcidev) { - pci_str = pci_name (frozen_pdn->pcidev); - drv_str = pcid_name (frozen_pdn->pcidev); - } else { - pci_str = eeh_pci_name(event->dev); - drv_str = pcid_name (event->dev); - } + pci_str = eeh_pci_name(event->dev); + drv_str = pcid_name(event->dev); if (frozen_pdn->eeh_freeze_count > EEH_MAX_ALLOWED_FREEZES) goto excess_failures; @@ -378,8 +373,17 @@ struct pci_dn * handle_eeh_events (struct eeh_event *event) printk(KERN_WARNING "EEH: This PCI device has failed %d times in the last hour:\n", frozen_pdn->eeh_freeze_count); + + if (frozen_pdn->pcidev) { + bus_pci_str = pci_name(frozen_pdn->pcidev); + bus_drv_str = pcid_name(frozen_pdn->pcidev); + printk(KERN_WARNING + "EEH: Bus location=%s driver=%s pci addr=%s\n", + location, bus_drv_str, bus_pci_str); + } + printk(KERN_WARNING - "EEH: location=%s driver=%s pci addr=%s\n", + "EEH: Device location=%s driver=%s pci addr=%s\n", location, drv_str, pci_str); /* Walk the various device drivers attached to this slot through -- cgit v0.10.2 From a1d0d98daf6ce580d017a43b09fe30a375cde3e8 Mon Sep 17 00:00:00 2001 From: David Gibson Date: Thu, 14 Apr 2011 22:32:06 +0000 Subject: powerpc: Add WSP platform Add a platform for the Wire Speed Processor, based on the PPC A2. This includes code for the ICS & OPB interrupt controllers, as well as a SCOM backend, and SCOM based cpu bringup. Signed-off-by: Benjamin Herrenschmidt Signed-off-by: David Gibson Signed-off-by: Jack Miller Signed-off-by: Ian Munsie Signed-off-by: Michael Ellerman Signed-off-by: Benjamin Herrenschmidt diff --git a/arch/powerpc/include/asm/wsp.h b/arch/powerpc/include/asm/wsp.h new file mode 100644 index 0000000..c7dc830 --- /dev/null +++ b/arch/powerpc/include/asm/wsp.h @@ -0,0 +1,14 @@ +/* + * Copyright 2011 Michael Ellerman, IBM Corp. + * + * 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 __ASM_POWERPC_WSP_H +#define __ASM_POWERPC_WSP_H + +extern int wsp_get_chip_id(struct device_node *dn); + +#endif /* __ASM_POWERPC_WSP_H */ diff --git a/arch/powerpc/kernel/exceptions-64e.S b/arch/powerpc/kernel/exceptions-64e.S index 23bd83b..c98e9d2 100644 --- a/arch/powerpc/kernel/exceptions-64e.S +++ b/arch/powerpc/kernel/exceptions-64e.S @@ -864,6 +864,20 @@ have_hes: * that will have to be made dependent on whether we are running under * a hypervisor I suppose. */ + + /* BEWARE, MAGIC + * This code is called as an ordinary function on the boot CPU. But to + * avoid duplication, this code is also used in SCOM bringup of + * secondary CPUs. We read the code between the initial_tlb_code_start + * and initial_tlb_code_end labels one instruction at a time and RAM it + * into the new core via SCOM. That doesn't process branches, so there + * must be none between those two labels. It also means if this code + * ever takes any parameters, the SCOM code must also be updated to + * provide them. + */ + .globl a2_tlbinit_code_start +a2_tlbinit_code_start: + ori r11,r3,MAS0_WQ_ALLWAYS oris r11,r11,MAS0_ESEL(3)@h /* Use way 3: workaround A2 erratum 376 */ mtspr SPRN_MAS0,r11 @@ -880,6 +894,9 @@ have_hes: /* Write the TLB entry */ tlbwe + .globl a2_tlbinit_after_linear_map +a2_tlbinit_after_linear_map: + /* Now we branch the new virtual address mapped by this entry */ LOAD_REG_IMMEDIATE(r3,1f) mtctr r3 @@ -931,10 +948,16 @@ have_hes: cmpw r3,r9 blt 2b + .globl a2_tlbinit_after_iprot_flush +a2_tlbinit_after_iprot_flush: + PPC_TLBILX(0,0,0) sync isync + .globl a2_tlbinit_code_end +a2_tlbinit_code_end: + /* We translate LR and return */ mflr r3 tovirt(r3,r3) diff --git a/arch/powerpc/platforms/Kconfig b/arch/powerpc/platforms/Kconfig index f2352fc..6059053 100644 --- a/arch/powerpc/platforms/Kconfig +++ b/arch/powerpc/platforms/Kconfig @@ -20,6 +20,7 @@ source "arch/powerpc/platforms/embedded6xx/Kconfig" source "arch/powerpc/platforms/44x/Kconfig" source "arch/powerpc/platforms/40x/Kconfig" source "arch/powerpc/platforms/amigaone/Kconfig" +source "arch/powerpc/platforms/wsp/Kconfig" config KVM_GUEST bool "KVM Guest support" diff --git a/arch/powerpc/platforms/Makefile b/arch/powerpc/platforms/Makefile index fdb9f0b..73e2116 100644 --- a/arch/powerpc/platforms/Makefile +++ b/arch/powerpc/platforms/Makefile @@ -22,3 +22,4 @@ obj-$(CONFIG_PPC_CELL) += cell/ obj-$(CONFIG_PPC_PS3) += ps3/ obj-$(CONFIG_EMBEDDED6xx) += embedded6xx/ obj-$(CONFIG_AMIGAONE) += amigaone/ +obj-$(CONFIG_PPC_WSP) += wsp/ diff --git a/arch/powerpc/platforms/wsp/Kconfig b/arch/powerpc/platforms/wsp/Kconfig new file mode 100644 index 0000000..c3c48eb --- /dev/null +++ b/arch/powerpc/platforms/wsp/Kconfig @@ -0,0 +1,28 @@ +config PPC_WSP + bool + default n + +menu "WSP platform selection" + depends on PPC_BOOK3E_64 + +config PPC_PSR2 + bool "PSR-2 platform" + select PPC_A2 + select GENERIC_TBSYNC + select PPC_SCOM + select EPAPR_BOOT + select PPC_WSP + select PPC_XICS + select PPC_ICP_NATIVE + default y + +endmenu + +config PPC_A2_DD2 + bool "Support for DD2 based A2/WSP systems" + depends on PPC_A2 + +config WORKAROUND_ERRATUM_463 + depends on PPC_A2_DD2 + bool "Workaround erratum 463" + default y diff --git a/arch/powerpc/platforms/wsp/Makefile b/arch/powerpc/platforms/wsp/Makefile new file mode 100644 index 0000000..095be73 --- /dev/null +++ b/arch/powerpc/platforms/wsp/Makefile @@ -0,0 +1,6 @@ +ccflags-y += -mno-minimal-toc + +obj-y += setup.o ics.o +obj-$(CONFIG_PPC_PSR2) += psr2.o opb_pic.o +obj-$(CONFIG_PPC_WSP) += scom_wsp.o +obj-$(CONFIG_SMP) += smp.o scom_smp.o diff --git a/arch/powerpc/platforms/wsp/ics.c b/arch/powerpc/platforms/wsp/ics.c new file mode 100644 index 0000000..e53bd9e --- /dev/null +++ b/arch/powerpc/platforms/wsp/ics.c @@ -0,0 +1,712 @@ +/* + * Copyright 2008-2011 IBM Corporation. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "wsp.h" +#include "ics.h" + + +/* WSP ICS */ + +struct wsp_ics { + struct ics ics; + struct device_node *dn; + void __iomem *regs; + spinlock_t lock; + unsigned long *bitmap; + u32 chip_id; + u32 lsi_base; + u32 lsi_count; + u64 hwirq_start; + u64 count; +#ifdef CONFIG_SMP + int *hwirq_cpu_map; +#endif +}; + +#define to_wsp_ics(ics) container_of(ics, struct wsp_ics, ics) + +#define INT_SRC_LAYER_BUID_REG(base) ((base) + 0x00) +#define IODA_TBL_ADDR_REG(base) ((base) + 0x18) +#define IODA_TBL_DATA_REG(base) ((base) + 0x20) +#define XIVE_UPDATE_REG(base) ((base) + 0x28) +#define ICS_INT_CAPS_REG(base) ((base) + 0x30) + +#define TBL_AUTO_INCREMENT ((1UL << 63) | (1UL << 15)) +#define TBL_SELECT_XIST (1UL << 48) +#define TBL_SELECT_XIVT (1UL << 49) + +#define IODA_IRQ(irq) ((irq) & (0x7FFULL)) /* HRM 5.1.3.4 */ + +#define XIST_REQUIRED 0x8 +#define XIST_REJECTED 0x4 +#define XIST_PRESENTED 0x2 +#define XIST_PENDING 0x1 + +#define XIVE_SERVER_SHIFT 42 +#define XIVE_SERVER_MASK 0xFFFFULL +#define XIVE_PRIORITY_MASK 0xFFULL +#define XIVE_PRIORITY_SHIFT 32 +#define XIVE_WRITE_ENABLE (1ULL << 63) + +/* + * The docs refer to a 6 bit field called ChipID, which consists of a + * 3 bit NodeID and a 3 bit ChipID. On WSP the ChipID is always zero + * so we ignore it, and every where we use "chip id" in this code we + * mean the NodeID. + */ +#define WSP_ICS_CHIP_SHIFT 17 + + +static struct wsp_ics *ics_list; +static int num_ics; + +/* ICS Source controller accessors */ + +static u64 wsp_ics_get_xive(struct wsp_ics *ics, unsigned int irq) +{ + unsigned long flags; + u64 xive; + + spin_lock_irqsave(&ics->lock, flags); + out_be64(IODA_TBL_ADDR_REG(ics->regs), TBL_SELECT_XIVT | IODA_IRQ(irq)); + xive = in_be64(IODA_TBL_DATA_REG(ics->regs)); + spin_unlock_irqrestore(&ics->lock, flags); + + return xive; +} + +static void wsp_ics_set_xive(struct wsp_ics *ics, unsigned int irq, u64 xive) +{ + xive &= ~XIVE_ADDR_MASK; + xive |= (irq & XIVE_ADDR_MASK); + xive |= XIVE_WRITE_ENABLE; + + out_be64(XIVE_UPDATE_REG(ics->regs), xive); +} + +static u64 xive_set_server(u64 xive, unsigned int server) +{ + u64 mask = ~(XIVE_SERVER_MASK << XIVE_SERVER_SHIFT); + + xive &= mask; + xive |= (server & XIVE_SERVER_MASK) << XIVE_SERVER_SHIFT; + + return xive; +} + +static u64 xive_set_priority(u64 xive, unsigned int priority) +{ + u64 mask = ~(XIVE_PRIORITY_MASK << XIVE_PRIORITY_SHIFT); + + xive &= mask; + xive |= (priority & XIVE_PRIORITY_MASK) << XIVE_PRIORITY_SHIFT; + + return xive; +} + + +#ifdef CONFIG_SMP +/* Find logical CPUs within mask on a given chip and store result in ret */ +void cpus_on_chip(int chip_id, cpumask_t *mask, cpumask_t *ret) +{ + int cpu, chip; + struct device_node *cpu_dn, *dn; + const u32 *prop; + + cpumask_clear(ret); + for_each_cpu(cpu, mask) { + cpu_dn = of_get_cpu_node(cpu, NULL); + if (!cpu_dn) + continue; + + prop = of_get_property(cpu_dn, "at-node", NULL); + if (!prop) { + of_node_put(cpu_dn); + continue; + } + + dn = of_find_node_by_phandle(*prop); + of_node_put(cpu_dn); + + chip = wsp_get_chip_id(dn); + if (chip == chip_id) + cpumask_set_cpu(cpu, ret); + + of_node_put(dn); + } +} + +/* Store a suitable CPU to handle a hwirq in the ics->hwirq_cpu_map cache */ +static int cache_hwirq_map(struct wsp_ics *ics, unsigned int hwirq, + const cpumask_t *affinity) +{ + cpumask_var_t avail, newmask; + int ret = -ENOMEM, cpu, cpu_rover = 0, target; + int index = hwirq - ics->hwirq_start; + unsigned int nodeid; + + BUG_ON(index < 0 || index >= ics->count); + + if (!ics->hwirq_cpu_map) + return -ENOMEM; + + if (!distribute_irqs) { + ics->hwirq_cpu_map[hwirq - ics->hwirq_start] = xics_default_server; + return 0; + } + + /* Allocate needed CPU masks */ + if (!alloc_cpumask_var(&avail, GFP_KERNEL)) + goto ret; + if (!alloc_cpumask_var(&newmask, GFP_KERNEL)) + goto freeavail; + + /* Find PBus attached to the source of this IRQ */ + nodeid = (hwirq >> WSP_ICS_CHIP_SHIFT) & 0x3; /* 12:14 */ + + /* Find CPUs that could handle this IRQ */ + if (affinity) + cpumask_and(avail, cpu_online_mask, affinity); + else + cpumask_copy(avail, cpu_online_mask); + + /* Narrow selection down to logical CPUs on the same chip */ + cpus_on_chip(nodeid, avail, newmask); + + /* Ensure we haven't narrowed it down to 0 */ + if (unlikely(cpumask_empty(newmask))) { + if (unlikely(cpumask_empty(avail))) { + ret = -1; + goto out; + } + cpumask_copy(newmask, avail); + } + + /* Choose a CPU out of those we narrowed it down to in round robin */ + target = hwirq % cpumask_weight(newmask); + for_each_cpu(cpu, newmask) { + if (cpu_rover++ >= target) { + ics->hwirq_cpu_map[index] = get_hard_smp_processor_id(cpu); + ret = 0; + goto out; + } + } + + /* Shouldn't happen */ + WARN_ON(1); + +out: + free_cpumask_var(newmask); +freeavail: + free_cpumask_var(avail); +ret: + if (ret < 0) { + ics->hwirq_cpu_map[index] = cpumask_first(cpu_online_mask); + pr_warning("Error, falling hwirq 0x%x routing back to CPU %i\n", + hwirq, ics->hwirq_cpu_map[index]); + } + return ret; +} + +static void alloc_irq_map(struct wsp_ics *ics) +{ + int i; + + ics->hwirq_cpu_map = kmalloc(sizeof(int) * ics->count, GFP_KERNEL); + if (!ics->hwirq_cpu_map) { + pr_warning("Allocate hwirq_cpu_map failed, " + "IRQ balancing disabled\n"); + return; + } + + for (i=0; i < ics->count; i++) + ics->hwirq_cpu_map[i] = xics_default_server; +} + +static int get_irq_server(struct wsp_ics *ics, unsigned int hwirq) +{ + int index = hwirq - ics->hwirq_start; + + BUG_ON(index < 0 || index >= ics->count); + + if (!ics->hwirq_cpu_map) + return xics_default_server; + + return ics->hwirq_cpu_map[index]; +} +#else /* !CONFIG_SMP */ +static int cache_hwirq_map(struct wsp_ics *ics, unsigned int hwirq, + const cpumask_t *affinity) +{ + return 0; +} + +static int get_irq_server(struct wsp_ics *ics, unsigned int hwirq) +{ + return xics_default_server; +} + +static void alloc_irq_map(struct wsp_ics *ics) { } +#endif + +static void wsp_chip_unmask_irq(struct irq_data *d) +{ + unsigned int hw_irq = (unsigned int)irqd_to_hwirq(d); + struct wsp_ics *ics; + int server; + u64 xive; + + if (hw_irq == XICS_IPI || hw_irq == XICS_IRQ_SPURIOUS) + return; + + ics = d->chip_data; + if (WARN_ON(!ics)) + return; + + server = get_irq_server(ics, hw_irq); + + xive = wsp_ics_get_xive(ics, hw_irq); + xive = xive_set_server(xive, server); + xive = xive_set_priority(xive, DEFAULT_PRIORITY); + wsp_ics_set_xive(ics, hw_irq, xive); +} + +static unsigned int wsp_chip_startup(struct irq_data *d) +{ + /* unmask it */ + wsp_chip_unmask_irq(d); + return 0; +} + +static void wsp_mask_real_irq(unsigned int hw_irq, struct wsp_ics *ics) +{ + u64 xive; + + if (hw_irq == XICS_IPI) + return; + + if (WARN_ON(!ics)) + return; + xive = wsp_ics_get_xive(ics, hw_irq); + xive = xive_set_server(xive, xics_default_server); + xive = xive_set_priority(xive, LOWEST_PRIORITY); + wsp_ics_set_xive(ics, hw_irq, xive); +} + +static void wsp_chip_mask_irq(struct irq_data *d) +{ + unsigned int hw_irq = (unsigned int)irqd_to_hwirq(d); + struct wsp_ics *ics = d->chip_data; + + if (hw_irq == XICS_IPI || hw_irq == XICS_IRQ_SPURIOUS) + return; + + wsp_mask_real_irq(hw_irq, ics); +} + +static int wsp_chip_set_affinity(struct irq_data *d, + const struct cpumask *cpumask, bool force) +{ + unsigned int hw_irq = (unsigned int)irqd_to_hwirq(d); + struct wsp_ics *ics; + int ret; + u64 xive; + + if (hw_irq == XICS_IPI || hw_irq == XICS_IRQ_SPURIOUS) + return -1; + + ics = d->chip_data; + if (WARN_ON(!ics)) + return -1; + xive = wsp_ics_get_xive(ics, hw_irq); + + /* + * For the moment only implement delivery to all cpus or one cpu. + * Get current irq_server for the given irq + */ + ret = cache_hwirq_map(ics, d->irq, cpumask); + if (ret == -1) { + char cpulist[128]; + cpumask_scnprintf(cpulist, sizeof(cpulist), cpumask); + pr_warning("%s: No online cpus in the mask %s for irq %d\n", + __func__, cpulist, d->irq); + return -1; + } else if (ret == -ENOMEM) { + pr_warning("%s: Out of memory\n", __func__); + return -1; + } + + xive = xive_set_server(xive, get_irq_server(ics, hw_irq)); + wsp_ics_set_xive(ics, hw_irq, xive); + + return 0; +} + +static struct irq_chip wsp_irq_chip = { + .name = "WSP ICS", + .irq_startup = wsp_chip_startup, + .irq_mask = wsp_chip_mask_irq, + .irq_unmask = wsp_chip_unmask_irq, + .irq_set_affinity = wsp_chip_set_affinity +}; + +static int wsp_ics_host_match(struct ics *ics, struct device_node *dn) +{ + /* All ICSs in the system implement a global irq number space, + * so match against them all. */ + return of_device_is_compatible(dn, "ibm,ppc-xics"); +} + +static int wsp_ics_match_hwirq(struct wsp_ics *wsp_ics, unsigned int hwirq) +{ + if (hwirq >= wsp_ics->hwirq_start && + hwirq < wsp_ics->hwirq_start + wsp_ics->count) + return 1; + + return 0; +} + +static int wsp_ics_map(struct ics *ics, unsigned int virq) +{ + struct wsp_ics *wsp_ics = to_wsp_ics(ics); + unsigned int hw_irq = virq_to_hw(virq); + unsigned long flags; + + if (!wsp_ics_match_hwirq(wsp_ics, hw_irq)) + return -ENOENT; + + irq_set_chip_and_handler(virq, &wsp_irq_chip, handle_fasteoi_irq); + + irq_set_chip_data(virq, wsp_ics); + + spin_lock_irqsave(&wsp_ics->lock, flags); + bitmap_allocate_region(wsp_ics->bitmap, hw_irq - wsp_ics->hwirq_start, 0); + spin_unlock_irqrestore(&wsp_ics->lock, flags); + + return 0; +} + +static void wsp_ics_mask_unknown(struct ics *ics, unsigned long hw_irq) +{ + struct wsp_ics *wsp_ics = to_wsp_ics(ics); + + if (!wsp_ics_match_hwirq(wsp_ics, hw_irq)) + return; + + pr_err("%s: IRQ %lu (real) is invalid, disabling it.\n", __func__, hw_irq); + wsp_mask_real_irq(hw_irq, wsp_ics); +} + +static long wsp_ics_get_server(struct ics *ics, unsigned long hw_irq) +{ + struct wsp_ics *wsp_ics = to_wsp_ics(ics); + + if (!wsp_ics_match_hwirq(wsp_ics, hw_irq)) + return -ENOENT; + + return get_irq_server(wsp_ics, hw_irq); +} + +/* HW Number allocation API */ + +static struct wsp_ics *wsp_ics_find_dn_ics(struct device_node *dn) +{ + struct device_node *iparent; + int i; + + iparent = of_irq_find_parent(dn); + if (!iparent) { + pr_err("wsp_ics: Failed to find interrupt parent!\n"); + return NULL; + } + + for(i = 0; i < num_ics; i++) { + if(ics_list[i].dn == iparent) + break; + } + + if (i >= num_ics) { + pr_err("wsp_ics: Unable to find parent bitmap!\n"); + return NULL; + } + + return &ics_list[i]; +} + +int wsp_ics_alloc_irq(struct device_node *dn, int num) +{ + struct wsp_ics *ics; + int order, offset; + + ics = wsp_ics_find_dn_ics(dn); + if (!ics) + return -ENODEV; + + /* Fast, but overly strict if num isn't a power of two */ + order = get_count_order(num); + + spin_lock_irq(&ics->lock); + offset = bitmap_find_free_region(ics->bitmap, ics->count, order); + spin_unlock_irq(&ics->lock); + + if (offset < 0) + return offset; + + return offset + ics->hwirq_start; +} + +void wsp_ics_free_irq(struct device_node *dn, unsigned int irq) +{ + struct wsp_ics *ics; + + ics = wsp_ics_find_dn_ics(dn); + if (WARN_ON(!ics)) + return; + + spin_lock_irq(&ics->lock); + bitmap_release_region(ics->bitmap, irq, 0); + spin_unlock_irq(&ics->lock); +} + +/* Initialisation */ + +static int __init wsp_ics_bitmap_setup(struct wsp_ics *ics, + struct device_node *dn) +{ + int len, i, j, size; + u32 start, count; + const u32 *p; + + size = BITS_TO_LONGS(ics->count) * sizeof(long); + ics->bitmap = kzalloc(size, GFP_KERNEL); + if (!ics->bitmap) { + pr_err("wsp_ics: ENOMEM allocating IRQ bitmap!\n"); + return -ENOMEM; + } + + spin_lock_init(&ics->lock); + + p = of_get_property(dn, "available-ranges", &len); + if (!p || !len) { + /* FIXME this should be a WARN() once mambo is updated */ + pr_err("wsp_ics: No available-ranges defined for %s\n", + dn->full_name); + return 0; + } + + if (len % (2 * sizeof(u32)) != 0) { + /* FIXME this should be a WARN() once mambo is updated */ + pr_err("wsp_ics: Invalid available-ranges for %s\n", + dn->full_name); + return 0; + } + + bitmap_fill(ics->bitmap, ics->count); + + for (i = 0; i < len / sizeof(u32); i += 2) { + start = of_read_number(p + i, 1); + count = of_read_number(p + i + 1, 1); + + pr_devel("%s: start: %d count: %d\n", __func__, start, count); + + if ((start + count) > (ics->hwirq_start + ics->count) || + start < ics->hwirq_start) { + pr_err("wsp_ics: Invalid range! -> %d to %d\n", + start, start + count); + break; + } + + for (j = 0; j < count; j++) + bitmap_release_region(ics->bitmap, + (start + j) - ics->hwirq_start, 0); + } + + /* Ensure LSIs are not available for allocation */ + bitmap_allocate_region(ics->bitmap, ics->lsi_base, + get_count_order(ics->lsi_count)); + + return 0; +} + +static int __init wsp_ics_setup(struct wsp_ics *ics, struct device_node *dn) +{ + u32 lsi_buid, msi_buid, msi_base, msi_count; + void __iomem *regs; + const u32 *p; + int rc, len, i; + u64 caps, buid; + + p = of_get_property(dn, "interrupt-ranges", &len); + if (!p || len < (2 * sizeof(u32))) { + pr_err("wsp_ics: No/bad interrupt-ranges found on %s\n", + dn->full_name); + return -ENOENT; + } + + if (len > (2 * sizeof(u32))) { + pr_err("wsp_ics: Multiple ics ranges not supported.\n"); + return -EINVAL; + } + + regs = of_iomap(dn, 0); + if (!regs) { + pr_err("wsp_ics: of_iomap(%s) failed\n", dn->full_name); + return -ENXIO; + } + + ics->hwirq_start = of_read_number(p, 1); + ics->count = of_read_number(p + 1, 1); + ics->regs = regs; + + ics->chip_id = wsp_get_chip_id(dn); + if (WARN_ON(ics->chip_id < 0)) + ics->chip_id = 0; + + /* Get some informations about the critter */ + caps = in_be64(ICS_INT_CAPS_REG(ics->regs)); + buid = in_be64(INT_SRC_LAYER_BUID_REG(ics->regs)); + ics->lsi_count = caps >> 56; + msi_count = (caps >> 44) & 0x7ff; + + /* Note: LSI BUID is 9 bits, but really only 3 are BUID and the + * rest is mixed in the interrupt number. We store the whole + * thing though + */ + lsi_buid = (buid >> 48) & 0x1ff; + ics->lsi_base = (ics->chip_id << WSP_ICS_CHIP_SHIFT) | lsi_buid << 5; + msi_buid = (buid >> 37) & 0x7; + msi_base = (ics->chip_id << WSP_ICS_CHIP_SHIFT) | msi_buid << 11; + + pr_info("wsp_ics: Found %s\n", dn->full_name); + pr_info("wsp_ics: irq range : 0x%06llx..0x%06llx\n", + ics->hwirq_start, ics->hwirq_start + ics->count - 1); + pr_info("wsp_ics: %4d LSIs : 0x%06x..0x%06x\n", + ics->lsi_count, ics->lsi_base, + ics->lsi_base + ics->lsi_count - 1); + pr_info("wsp_ics: %4d MSIs : 0x%06x..0x%06x\n", + msi_count, msi_base, + msi_base + msi_count - 1); + + /* Let's check the HW config is sane */ + if (ics->lsi_base < ics->hwirq_start || + (ics->lsi_base + ics->lsi_count) > (ics->hwirq_start + ics->count)) + pr_warning("wsp_ics: WARNING ! LSIs out of interrupt-ranges !\n"); + if (msi_base < ics->hwirq_start || + (msi_base + msi_count) > (ics->hwirq_start + ics->count)) + pr_warning("wsp_ics: WARNING ! MSIs out of interrupt-ranges !\n"); + + /* We don't check for overlap between LSI and MSI, which will happen + * if we use the same BUID, I'm not sure yet how legit that is. + */ + + rc = wsp_ics_bitmap_setup(ics, dn); + if (rc) { + iounmap(regs); + return rc; + } + + ics->dn = of_node_get(dn); + alloc_irq_map(ics); + + for(i = 0; i < ics->count; i++) + wsp_mask_real_irq(ics->hwirq_start + i, ics); + + ics->ics.map = wsp_ics_map; + ics->ics.mask_unknown = wsp_ics_mask_unknown; + ics->ics.get_server = wsp_ics_get_server; + ics->ics.host_match = wsp_ics_host_match; + + xics_register_ics(&ics->ics); + + return 0; +} + +static void __init wsp_ics_set_default_server(void) +{ + struct device_node *np; + u32 hwid; + + /* Find the server number for the boot cpu. */ + np = of_get_cpu_node(boot_cpuid, NULL); + BUG_ON(!np); + + hwid = get_hard_smp_processor_id(boot_cpuid); + + pr_info("wsp_ics: default server is %#x, CPU %s\n", hwid, np->full_name); + xics_default_server = hwid; + + of_node_put(np); +} + +static int __init wsp_ics_init(void) +{ + struct device_node *dn; + struct wsp_ics *ics; + int rc, found; + + wsp_ics_set_default_server(); + + found = 0; + for_each_compatible_node(dn, NULL, "ibm,ppc-xics") + found++; + + if (found == 0) { + pr_err("wsp_ics: No ICS's found!\n"); + return -ENODEV; + } + + ics_list = kmalloc(sizeof(*ics) * found, GFP_KERNEL); + if (!ics_list) { + pr_err("wsp_ics: No memory for structs.\n"); + return -ENOMEM; + } + + num_ics = 0; + ics = ics_list; + for_each_compatible_node(dn, NULL, "ibm,wsp-xics") { + rc = wsp_ics_setup(ics, dn); + if (rc == 0) { + ics++; + num_ics++; + } + } + + if (found != num_ics) { + pr_err("wsp_ics: Failed setting up %d ICS's\n", + found - num_ics); + return -1; + } + + return 0; +} + +void __init wsp_init_irq(void) +{ + wsp_ics_init(); + xics_init(); + + /* We need to patch our irq chip's EOI to point to the right ICP */ + wsp_irq_chip.irq_eoi = icp_ops->eoi; +} diff --git a/arch/powerpc/platforms/wsp/ics.h b/arch/powerpc/platforms/wsp/ics.h new file mode 100644 index 0000000..e34d531 --- /dev/null +++ b/arch/powerpc/platforms/wsp/ics.h @@ -0,0 +1,20 @@ +/* + * Copyright 2009 IBM Corporation. + * + * 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 __ICS_H +#define __ICS_H + +#define XIVE_ADDR_MASK 0x7FFULL + +extern void wsp_init_irq(void); + +extern int wsp_ics_alloc_irq(struct device_node *dn, int num); +extern void wsp_ics_free_irq(struct device_node *dn, unsigned int irq); + +#endif /* __ICS_H */ diff --git a/arch/powerpc/platforms/wsp/opb_pic.c b/arch/powerpc/platforms/wsp/opb_pic.c new file mode 100644 index 0000000..be05631 --- /dev/null +++ b/arch/powerpc/platforms/wsp/opb_pic.c @@ -0,0 +1,332 @@ +/* + * IBM Onboard Peripheral Bus Interrupt Controller + * + * Copyright 2010 Jack Miller, IBM Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ + +#include +#include +#include +#include +#include +#include + +#include +#include + +#define OPB_NR_IRQS 32 + +#define OPB_MLSASIER 0x04 /* MLS Accumulated Status IER */ +#define OPB_MLSIR 0x50 /* MLS Interrupt Register */ +#define OPB_MLSIER 0x54 /* MLS Interrupt Enable Register */ +#define OPB_MLSIPR 0x58 /* MLS Interrupt Polarity Register */ +#define OPB_MLSIIR 0x5c /* MLS Interrupt Inputs Register */ + +static int opb_index = 0; + +struct opb_pic { + struct irq_host *host; + void *regs; + int index; + spinlock_t lock; +}; + +static u32 opb_in(struct opb_pic *opb, int offset) +{ + return in_be32(opb->regs + offset); +} + +static void opb_out(struct opb_pic *opb, int offset, u32 val) +{ + out_be32(opb->regs + offset, val); +} + +static void opb_unmask_irq(struct irq_data *d) +{ + struct opb_pic *opb; + unsigned long flags; + u32 ier, bitset; + + opb = d->chip_data; + bitset = (1 << (31 - irqd_to_hwirq(d))); + + spin_lock_irqsave(&opb->lock, flags); + + ier = opb_in(opb, OPB_MLSIER); + opb_out(opb, OPB_MLSIER, ier | bitset); + ier = opb_in(opb, OPB_MLSIER); + + spin_unlock_irqrestore(&opb->lock, flags); +} + +static void opb_mask_irq(struct irq_data *d) +{ + struct opb_pic *opb; + unsigned long flags; + u32 ier, mask; + + opb = d->chip_data; + mask = ~(1 << (31 - irqd_to_hwirq(d))); + + spin_lock_irqsave(&opb->lock, flags); + + ier = opb_in(opb, OPB_MLSIER); + opb_out(opb, OPB_MLSIER, ier & mask); + ier = opb_in(opb, OPB_MLSIER); // Flush posted writes + + spin_unlock_irqrestore(&opb->lock, flags); +} + +static void opb_ack_irq(struct irq_data *d) +{ + struct opb_pic *opb; + unsigned long flags; + u32 bitset; + + opb = d->chip_data; + bitset = (1 << (31 - irqd_to_hwirq(d))); + + spin_lock_irqsave(&opb->lock, flags); + + opb_out(opb, OPB_MLSIR, bitset); + opb_in(opb, OPB_MLSIR); // Flush posted writes + + spin_unlock_irqrestore(&opb->lock, flags); +} + +static void opb_mask_ack_irq(struct irq_data *d) +{ + struct opb_pic *opb; + unsigned long flags; + u32 bitset; + u32 ier, ir; + + opb = d->chip_data; + bitset = (1 << (31 - irqd_to_hwirq(d))); + + spin_lock_irqsave(&opb->lock, flags); + + ier = opb_in(opb, OPB_MLSIER); + opb_out(opb, OPB_MLSIER, ier & ~bitset); + ier = opb_in(opb, OPB_MLSIER); // Flush posted writes + + opb_out(opb, OPB_MLSIR, bitset); + ir = opb_in(opb, OPB_MLSIR); // Flush posted writes + + spin_unlock_irqrestore(&opb->lock, flags); +} + +static int opb_set_irq_type(struct irq_data *d, unsigned int flow) +{ + struct opb_pic *opb; + unsigned long flags; + int invert, ipr, mask, bit; + + opb = d->chip_data; + + /* The only information we're interested in in the type is whether it's + * a high or low trigger. For high triggered interrupts, the polarity + * set for it in the MLS Interrupt Polarity Register is 0, for low + * interrupts it's 1 so that the proper input in the MLS Interrupt Input + * Register is interrupted as asserting the interrupt. */ + + switch (flow) { + case IRQ_TYPE_NONE: + opb_mask_irq(d); + return 0; + + case IRQ_TYPE_LEVEL_HIGH: + invert = 0; + break; + + case IRQ_TYPE_LEVEL_LOW: + invert = 1; + break; + + default: + return -EINVAL; + } + + bit = (1 << (31 - irqd_to_hwirq(d))); + mask = ~bit; + + spin_lock_irqsave(&opb->lock, flags); + + ipr = opb_in(opb, OPB_MLSIPR); + ipr = (ipr & mask) | (invert ? bit : 0); + opb_out(opb, OPB_MLSIPR, ipr); + ipr = opb_in(opb, OPB_MLSIPR); // Flush posted writes + + spin_unlock_irqrestore(&opb->lock, flags); + + /* Record the type in the interrupt descriptor */ + irqd_set_trigger_type(d, flow); + + return 0; +} + +static struct irq_chip opb_irq_chip = { + .name = "OPB", + .irq_mask = opb_mask_irq, + .irq_unmask = opb_unmask_irq, + .irq_mask_ack = opb_mask_ack_irq, + .irq_ack = opb_ack_irq, + .irq_set_type = opb_set_irq_type +}; + +static int opb_host_map(struct irq_host *host, unsigned int virq, + irq_hw_number_t hwirq) +{ + struct opb_pic *opb; + + opb = host->host_data; + + /* Most of the important stuff is handled by the generic host code, like + * the lookup, so just attach some info to the virtual irq */ + + irq_set_chip_data(virq, opb); + irq_set_chip_and_handler(virq, &opb_irq_chip, handle_level_irq); + irq_set_irq_type(virq, IRQ_TYPE_NONE); + + return 0; +} + +static int opb_host_xlate(struct irq_host *host, struct device_node *dn, + const u32 *intspec, unsigned int intsize, + irq_hw_number_t *out_hwirq, unsigned int *out_type) +{ + /* Interrupt size must == 2 */ + BUG_ON(intsize != 2); + *out_hwirq = intspec[0]; + *out_type = intspec[1]; + return 0; +} + +static struct irq_host_ops opb_host_ops = { + .map = opb_host_map, + .xlate = opb_host_xlate, +}; + +irqreturn_t opb_irq_handler(int irq, void *private) +{ + struct opb_pic *opb; + u32 ir, src, subvirq; + + opb = (struct opb_pic *) private; + + /* Read the OPB MLS Interrupt Register for + * asserted interrupts */ + ir = opb_in(opb, OPB_MLSIR); + if (!ir) + return IRQ_NONE; + + do { + /* Get 1 - 32 source, *NOT* bit */ + src = 32 - ffs(ir); + + /* Translate from the OPB's conception of interrupt number to + * Linux's virtual IRQ */ + + subvirq = irq_linear_revmap(opb->host, src); + + generic_handle_irq(subvirq); + } while ((ir = opb_in(opb, OPB_MLSIR))); + + return IRQ_HANDLED; +} + +struct opb_pic *opb_pic_init_one(struct device_node *dn) +{ + struct opb_pic *opb; + struct resource res; + + if (of_address_to_resource(dn, 0, &res)) { + printk(KERN_ERR "opb: Couldn't translate resource\n"); + return NULL; + } + + opb = kzalloc(sizeof(struct opb_pic), GFP_KERNEL); + if (!opb) { + printk(KERN_ERR "opb: Failed to allocate opb struct!\n"); + return NULL; + } + + /* Get access to the OPB MMIO registers */ + opb->regs = ioremap(res.start + 0x10000, 0x1000); + if (!opb->regs) { + printk(KERN_ERR "opb: Failed to allocate register space!\n"); + goto free_opb; + } + + /* Allocate an irq host so that Linux knows that despite only + * having one interrupt to issue, we're the controller for multiple + * hardware IRQs, so later we can lookup their virtual IRQs. */ + + opb->host = irq_alloc_host(dn, IRQ_HOST_MAP_LINEAR, + OPB_NR_IRQS, &opb_host_ops, -1); + + if (!opb->host) { + printk(KERN_ERR "opb: Failed to allocate IRQ host!\n"); + goto free_regs; + } + + opb->index = opb_index++; + spin_lock_init(&opb->lock); + opb->host->host_data = opb; + + /* Disable all interrupts by default */ + opb_out(opb, OPB_MLSASIER, 0); + opb_out(opb, OPB_MLSIER, 0); + + /* ACK any interrupts left by FW */ + opb_out(opb, OPB_MLSIR, 0xFFFFFFFF); + + return opb; + +free_regs: + iounmap(opb->regs); +free_opb: + kfree(opb); + return NULL; +} + +void __init opb_pic_init(void) +{ + struct device_node *dn; + struct opb_pic *opb; + int virq; + int rc; + + /* Call init_one for each OPB device */ + for_each_compatible_node(dn, NULL, "ibm,opb") { + + /* Fill in an OPB struct */ + opb = opb_pic_init_one(dn); + if (!opb) { + printk(KERN_WARNING "opb: Failed to init node, skipped!\n"); + continue; + } + + /* Map / get opb's hardware virtual irq */ + virq = irq_of_parse_and_map(dn, 0); + if (virq <= 0) { + printk("opb: irq_op_parse_and_map failed!\n"); + continue; + } + + /* Attach opb interrupt handler to new virtual IRQ */ + rc = request_irq(virq, opb_irq_handler, 0, "OPB LS Cascade", opb); + if (rc) { + printk("opb: request_irq failed: %d\n", rc); + continue; + } + + printk("OPB%d init with %d IRQs at %p\n", opb->index, + OPB_NR_IRQS, opb->regs); + } +} diff --git a/arch/powerpc/platforms/wsp/psr2.c b/arch/powerpc/platforms/wsp/psr2.c new file mode 100644 index 0000000..40f2891 --- /dev/null +++ b/arch/powerpc/platforms/wsp/psr2.c @@ -0,0 +1,95 @@ +/* + * Copyright 2008-2011, IBM Corporation + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "ics.h" +#include "wsp.h" + + +static void psr2_spin(void) +{ + hard_irq_disable(); + for (;;) ; +} + +static void psr2_restart(char *cmd) +{ + psr2_spin(); +} + +static int psr2_probe_devices(void) +{ + struct device_node *np; + + /* Our RTC is a ds1500. It seems to be programatically compatible + * with the ds1511 for which we have a driver so let's use that + */ + np = of_find_compatible_node(NULL, NULL, "dallas,ds1500"); + if (np != NULL) { + struct resource res; + if (of_address_to_resource(np, 0, &res) == 0) + platform_device_register_simple("ds1511", 0, &res, 1); + } + return 0; +} +machine_arch_initcall(psr2_md, psr2_probe_devices); + +static void __init psr2_setup_arch(void) +{ + /* init to some ~sane value until calibrate_delay() runs */ + loops_per_jiffy = 50000000; + + scom_init_wsp(); + + /* Setup SMP callback */ +#ifdef CONFIG_SMP + a2_setup_smp(); +#endif +} + +static int __init psr2_probe(void) +{ + unsigned long root = of_get_flat_dt_root(); + + if (!of_flat_dt_is_compatible(root, "ibm,psr2")) + return 0; + + return 1; +} + +static void __init psr2_init_irq(void) +{ + wsp_init_irq(); + opb_pic_init(); +} + +define_machine(psr2_md) { + .name = "PSR2 A2", + .probe = psr2_probe, + .setup_arch = psr2_setup_arch, + .restart = psr2_restart, + .power_off = psr2_spin, + .halt = psr2_spin, + .calibrate_decr = generic_calibrate_decr, + .init_IRQ = psr2_init_irq, + .progress = udbg_progress, + .power_save = book3e_idle, +}; diff --git a/arch/powerpc/platforms/wsp/scom_smp.c b/arch/powerpc/platforms/wsp/scom_smp.c new file mode 100644 index 0000000..141e780 --- /dev/null +++ b/arch/powerpc/platforms/wsp/scom_smp.c @@ -0,0 +1,427 @@ +/* + * SCOM support for A2 platforms + * + * Copyright 2007-2011 Benjamin Herrenschmidt, David Gibson, + * Michael Ellerman, IBM Corp. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ + +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "wsp.h" + +#define SCOM_RAMC 0x2a /* Ram Command */ +#define SCOM_RAMC_TGT1_EXT 0x80000000 +#define SCOM_RAMC_SRC1_EXT 0x40000000 +#define SCOM_RAMC_SRC2_EXT 0x20000000 +#define SCOM_RAMC_SRC3_EXT 0x10000000 +#define SCOM_RAMC_ENABLE 0x00080000 +#define SCOM_RAMC_THREADSEL 0x00060000 +#define SCOM_RAMC_EXECUTE 0x00010000 +#define SCOM_RAMC_MSR_OVERRIDE 0x00008000 +#define SCOM_RAMC_MSR_PR 0x00004000 +#define SCOM_RAMC_MSR_GS 0x00002000 +#define SCOM_RAMC_FORCE 0x00001000 +#define SCOM_RAMC_FLUSH 0x00000800 +#define SCOM_RAMC_INTERRUPT 0x00000004 +#define SCOM_RAMC_ERROR 0x00000002 +#define SCOM_RAMC_DONE 0x00000001 +#define SCOM_RAMI 0x29 /* Ram Instruction */ +#define SCOM_RAMIC 0x28 /* Ram Instruction and Command */ +#define SCOM_RAMIC_INSN 0xffffffff00000000 +#define SCOM_RAMD 0x2d /* Ram Data */ +#define SCOM_RAMDH 0x2e /* Ram Data High */ +#define SCOM_RAMDL 0x2f /* Ram Data Low */ +#define SCOM_PCCR0 0x33 /* PC Configuration Register 0 */ +#define SCOM_PCCR0_ENABLE_DEBUG 0x80000000 +#define SCOM_PCCR0_ENABLE_RAM 0x40000000 +#define SCOM_THRCTL 0x30 /* Thread Control and Status */ +#define SCOM_THRCTL_T0_STOP 0x80000000 +#define SCOM_THRCTL_T1_STOP 0x40000000 +#define SCOM_THRCTL_T2_STOP 0x20000000 +#define SCOM_THRCTL_T3_STOP 0x10000000 +#define SCOM_THRCTL_T0_STEP 0x08000000 +#define SCOM_THRCTL_T1_STEP 0x04000000 +#define SCOM_THRCTL_T2_STEP 0x02000000 +#define SCOM_THRCTL_T3_STEP 0x01000000 +#define SCOM_THRCTL_T0_RUN 0x00800000 +#define SCOM_THRCTL_T1_RUN 0x00400000 +#define SCOM_THRCTL_T2_RUN 0x00200000 +#define SCOM_THRCTL_T3_RUN 0x00100000 +#define SCOM_THRCTL_T0_PM 0x00080000 +#define SCOM_THRCTL_T1_PM 0x00040000 +#define SCOM_THRCTL_T2_PM 0x00020000 +#define SCOM_THRCTL_T3_PM 0x00010000 +#define SCOM_THRCTL_T0_UDE 0x00008000 +#define SCOM_THRCTL_T1_UDE 0x00004000 +#define SCOM_THRCTL_T2_UDE 0x00002000 +#define SCOM_THRCTL_T3_UDE 0x00001000 +#define SCOM_THRCTL_ASYNC_DIS 0x00000800 +#define SCOM_THRCTL_TB_DIS 0x00000400 +#define SCOM_THRCTL_DEC_DIS 0x00000200 +#define SCOM_THRCTL_AND 0x31 /* Thread Control and Status */ +#define SCOM_THRCTL_OR 0x32 /* Thread Control and Status */ + + +static DEFINE_PER_CPU(scom_map_t, scom_ptrs); + +static scom_map_t get_scom(int cpu, struct device_node *np, int *first_thread) +{ + scom_map_t scom = per_cpu(scom_ptrs, cpu); + int tcpu; + + if (scom_map_ok(scom)) { + *first_thread = 0; + return scom; + } + + *first_thread = 1; + + scom = scom_map_device(np, 0); + + for (tcpu = cpu_first_thread_sibling(cpu); + tcpu <= cpu_last_thread_sibling(cpu); tcpu++) + per_cpu(scom_ptrs, tcpu) = scom; + + /* Hack: for the boot core, this will actually get called on + * the second thread up, not the first so our test above will + * set first_thread incorrectly. */ + if (cpu_first_thread_sibling(cpu) == 0) + *first_thread = 0; + + return scom; +} + +static int a2_scom_ram(scom_map_t scom, int thread, u32 insn, int extmask) +{ + u64 cmd, mask, val; + int n = 0; + + cmd = ((u64)insn << 32) | (((u64)extmask & 0xf) << 28) + | ((u64)thread << 17) | SCOM_RAMC_ENABLE | SCOM_RAMC_EXECUTE; + mask = SCOM_RAMC_DONE | SCOM_RAMC_INTERRUPT | SCOM_RAMC_ERROR; + + scom_write(scom, SCOM_RAMIC, cmd); + + while (!((val = scom_read(scom, SCOM_RAMC)) & mask)) { + pr_devel("Waiting on RAMC = 0x%llx\n", val); + if (++n == 3) { + pr_err("RAMC timeout on instruction 0x%08x, thread %d\n", + insn, thread); + return -1; + } + } + + if (val & SCOM_RAMC_INTERRUPT) { + pr_err("RAMC interrupt on instruction 0x%08x, thread %d\n", + insn, thread); + return -SCOM_RAMC_INTERRUPT; + } + + if (val & SCOM_RAMC_ERROR) { + pr_err("RAMC error on instruction 0x%08x, thread %d\n", + insn, thread); + return -SCOM_RAMC_ERROR; + } + + return 0; +} + +static int a2_scom_getgpr(scom_map_t scom, int thread, int gpr, int alt, + u64 *out_gpr) +{ + int rc; + + /* or rN, rN, rN */ + u32 insn = 0x7c000378 | (gpr << 21) | (gpr << 16) | (gpr << 11); + rc = a2_scom_ram(scom, thread, insn, alt ? 0xf : 0x0); + if (rc) + return rc; + + *out_gpr = scom_read(scom, SCOM_RAMD); + + return 0; +} + +static int a2_scom_getspr(scom_map_t scom, int thread, int spr, u64 *out_spr) +{ + int rc, sprhi, sprlo; + u32 insn; + + sprhi = spr >> 5; + sprlo = spr & 0x1f; + insn = 0x7c2002a6 | (sprlo << 16) | (sprhi << 11); /* mfspr r1,spr */ + + if (spr == 0x0ff0) + insn = 0x7c2000a6; /* mfmsr r1 */ + + rc = a2_scom_ram(scom, thread, insn, 0xf); + if (rc) + return rc; + return a2_scom_getgpr(scom, thread, 1, 1, out_spr); +} + +static int a2_scom_setgpr(scom_map_t scom, int thread, int gpr, + int alt, u64 val) +{ + u32 lis = 0x3c000000 | (gpr << 21); + u32 li = 0x38000000 | (gpr << 21); + u32 oris = 0x64000000 | (gpr << 21) | (gpr << 16); + u32 ori = 0x60000000 | (gpr << 21) | (gpr << 16); + u32 rldicr32 = 0x780007c6 | (gpr << 21) | (gpr << 16); + u32 highest = val >> 48; + u32 higher = (val >> 32) & 0xffff; + u32 high = (val >> 16) & 0xffff; + u32 low = val & 0xffff; + int lext = alt ? 0x8 : 0x0; + int oext = alt ? 0xf : 0x0; + int rc = 0; + + if (highest) + rc |= a2_scom_ram(scom, thread, lis | highest, lext); + + if (higher) { + if (highest) + rc |= a2_scom_ram(scom, thread, oris | higher, oext); + else + rc |= a2_scom_ram(scom, thread, li | higher, lext); + } + + if (highest || higher) + rc |= a2_scom_ram(scom, thread, rldicr32, oext); + + if (high) { + if (highest || higher) + rc |= a2_scom_ram(scom, thread, oris | high, oext); + else + rc |= a2_scom_ram(scom, thread, lis | high, lext); + } + + if (highest || higher || high) + rc |= a2_scom_ram(scom, thread, ori | low, oext); + else + rc |= a2_scom_ram(scom, thread, li | low, lext); + + return rc; +} + +static int a2_scom_setspr(scom_map_t scom, int thread, int spr, u64 val) +{ + int sprhi = spr >> 5; + int sprlo = spr & 0x1f; + /* mtspr spr, r1 */ + u32 insn = 0x7c2003a6 | (sprlo << 16) | (sprhi << 11); + + if (spr == 0x0ff0) + insn = 0x7c200124; /* mtmsr r1 */ + + if (a2_scom_setgpr(scom, thread, 1, 1, val)) + return -1; + + return a2_scom_ram(scom, thread, insn, 0xf); +} + +static int a2_scom_initial_tlb(scom_map_t scom, int thread) +{ + extern u32 a2_tlbinit_code_start[], a2_tlbinit_code_end[]; + extern u32 a2_tlbinit_after_iprot_flush[]; + extern u32 a2_tlbinit_after_linear_map[]; + u32 assoc, entries, i; + u64 epn, tlbcfg; + u32 *p; + int rc; + + /* Invalidate all entries (including iprot) */ + + rc = a2_scom_getspr(scom, thread, SPRN_TLB0CFG, &tlbcfg); + if (rc) + goto scom_fail; + entries = tlbcfg & TLBnCFG_N_ENTRY; + assoc = (tlbcfg & TLBnCFG_ASSOC) >> 24; + epn = 0; + + /* Set MMUCR2 to enable 4K, 64K, 1M, 16M and 1G pages */ + a2_scom_setspr(scom, thread, SPRN_MMUCR2, 0x000a7531); + /* Set MMUCR3 to write all thids bit to the TLB */ + a2_scom_setspr(scom, thread, SPRN_MMUCR3, 0x0000000f); + + /* Set MAS1 for 1G page size, and MAS2 to our initial EPN */ + a2_scom_setspr(scom, thread, SPRN_MAS1, MAS1_TSIZE(BOOK3E_PAGESZ_1GB)); + a2_scom_setspr(scom, thread, SPRN_MAS2, epn); + for (i = 0; i < entries; i++) { + + a2_scom_setspr(scom, thread, SPRN_MAS0, MAS0_ESEL(i % assoc)); + + /* tlbwe */ + rc = a2_scom_ram(scom, thread, 0x7c0007a4, 0); + if (rc) + goto scom_fail; + + /* Next entry is new address? */ + if((i + 1) % assoc == 0) { + epn += (1 << 30); + a2_scom_setspr(scom, thread, SPRN_MAS2, epn); + } + } + + /* Setup args for linear mapping */ + rc = a2_scom_setgpr(scom, thread, 3, 0, MAS0_TLBSEL(0)); + if (rc) + goto scom_fail; + + /* Linear mapping */ + for (p = a2_tlbinit_code_start; p < a2_tlbinit_after_linear_map; p++) { + rc = a2_scom_ram(scom, thread, *p, 0); + if (rc) + goto scom_fail; + } + + /* + * For the boot thread, between the linear mapping and the debug + * mappings there is a loop to flush iprot mappings. Ramming doesn't do + * branches, but the secondary threads don't need to be nearly as smart + * (i.e. we don't need to worry about invalidating the mapping we're + * standing on). + */ + + /* Debug mappings. Expects r11 = MAS0 from linear map (set above) */ + for (p = a2_tlbinit_after_iprot_flush; p < a2_tlbinit_code_end; p++) { + rc = a2_scom_ram(scom, thread, *p, 0); + if (rc) + goto scom_fail; + } + +scom_fail: + if (rc) + pr_err("Setting up initial TLB failed, err %d\n", rc); + + if (rc == -SCOM_RAMC_INTERRUPT) { + /* Interrupt, dump some status */ + int rc[10]; + u64 iar, srr0, srr1, esr, mas0, mas1, mas2, mas7_3, mas8, ccr2; + rc[0] = a2_scom_getspr(scom, thread, SPRN_IAR, &iar); + rc[1] = a2_scom_getspr(scom, thread, SPRN_SRR0, &srr0); + rc[2] = a2_scom_getspr(scom, thread, SPRN_SRR1, &srr1); + rc[3] = a2_scom_getspr(scom, thread, SPRN_ESR, &esr); + rc[4] = a2_scom_getspr(scom, thread, SPRN_MAS0, &mas0); + rc[5] = a2_scom_getspr(scom, thread, SPRN_MAS1, &mas1); + rc[6] = a2_scom_getspr(scom, thread, SPRN_MAS2, &mas2); + rc[7] = a2_scom_getspr(scom, thread, SPRN_MAS7_MAS3, &mas7_3); + rc[8] = a2_scom_getspr(scom, thread, SPRN_MAS8, &mas8); + rc[9] = a2_scom_getspr(scom, thread, SPRN_A2_CCR2, &ccr2); + pr_err(" -> retreived IAR =0x%llx (err %d)\n", iar, rc[0]); + pr_err(" retreived SRR0=0x%llx (err %d)\n", srr0, rc[1]); + pr_err(" retreived SRR1=0x%llx (err %d)\n", srr1, rc[2]); + pr_err(" retreived ESR =0x%llx (err %d)\n", esr, rc[3]); + pr_err(" retreived MAS0=0x%llx (err %d)\n", mas0, rc[4]); + pr_err(" retreived MAS1=0x%llx (err %d)\n", mas1, rc[5]); + pr_err(" retreived MAS2=0x%llx (err %d)\n", mas2, rc[6]); + pr_err(" retreived MS73=0x%llx (err %d)\n", mas7_3, rc[7]); + pr_err(" retreived MAS8=0x%llx (err %d)\n", mas8, rc[8]); + pr_err(" retreived CCR2=0x%llx (err %d)\n", ccr2, rc[9]); + } + + return rc; +} + +int __devinit a2_scom_startup_cpu(unsigned int lcpu, int thr_idx, + struct device_node *np) +{ + u64 init_iar, init_msr, init_ccr2; + unsigned long start_here; + int rc, core_setup; + scom_map_t scom; + u64 pccr0; + + scom = get_scom(lcpu, np, &core_setup); + if (!scom) { + printk(KERN_ERR "Couldn't map SCOM for CPU%d\n", lcpu); + return -1; + } + + pr_devel("Bringing up CPU%d using SCOM...\n", lcpu); + + pccr0 = scom_read(scom, SCOM_PCCR0); + scom_write(scom, SCOM_PCCR0, pccr0 | SCOM_PCCR0_ENABLE_DEBUG | + SCOM_PCCR0_ENABLE_RAM); + + /* Stop the thead with THRCTL. If we are setting up the TLB we stop all + * threads. We also disable asynchronous interrupts while RAMing. + */ + if (core_setup) + scom_write(scom, SCOM_THRCTL_OR, + SCOM_THRCTL_T0_STOP | + SCOM_THRCTL_T1_STOP | + SCOM_THRCTL_T2_STOP | + SCOM_THRCTL_T3_STOP | + SCOM_THRCTL_ASYNC_DIS); + else + scom_write(scom, SCOM_THRCTL_OR, SCOM_THRCTL_T0_STOP >> thr_idx); + + /* Flush its pipeline just in case */ + scom_write(scom, SCOM_RAMC, ((u64)thr_idx << 17) | + SCOM_RAMC_FLUSH | SCOM_RAMC_ENABLE); + + a2_scom_getspr(scom, thr_idx, SPRN_IAR, &init_iar); + a2_scom_getspr(scom, thr_idx, 0x0ff0, &init_msr); + a2_scom_getspr(scom, thr_idx, SPRN_A2_CCR2, &init_ccr2); + + /* Set MSR to MSR_CM (0x0ff0 is magic value for MSR_CM) */ + rc = a2_scom_setspr(scom, thr_idx, 0x0ff0, MSR_CM); + if (rc) { + pr_err("Failed to set MSR ! err %d\n", rc); + return rc; + } + + /* RAM in an sync/isync for the sake of it */ + a2_scom_ram(scom, thr_idx, 0x7c0004ac, 0); + a2_scom_ram(scom, thr_idx, 0x4c00012c, 0); + + if (core_setup) { + pr_devel("CPU%d is first thread in core, initializing TLB...\n", + lcpu); + rc = a2_scom_initial_tlb(scom, thr_idx); + if (rc) + goto fail; + } + + start_here = *(unsigned long *)(core_setup ? generic_secondary_smp_init + : generic_secondary_thread_init); + pr_devel("CPU%d entry point at 0x%lx...\n", lcpu, start_here); + + rc |= a2_scom_setspr(scom, thr_idx, SPRN_IAR, start_here); + rc |= a2_scom_setgpr(scom, thr_idx, 3, 0, + get_hard_smp_processor_id(lcpu)); + /* + * Tell book3e_secondary_core_init not to set up the TLB, we've + * already done that. + */ + rc |= a2_scom_setgpr(scom, thr_idx, 4, 0, 1); + + rc |= a2_scom_setspr(scom, thr_idx, SPRN_TENS, 0x1 << thr_idx); + + scom_write(scom, SCOM_RAMC, 0); + scom_write(scom, SCOM_THRCTL_AND, ~(SCOM_THRCTL_T0_STOP >> thr_idx)); + scom_write(scom, SCOM_PCCR0, pccr0); +fail: + pr_devel(" SCOM initialization %s\n", rc ? "failed" : "succeeded"); + if (rc) { + pr_err("Old IAR=0x%08llx MSR=0x%08llx CCR2=0x%08llx\n", + init_iar, init_msr, init_ccr2); + } + + return rc; +} diff --git a/arch/powerpc/platforms/wsp/scom_wsp.c b/arch/powerpc/platforms/wsp/scom_wsp.c new file mode 100644 index 0000000..4052e22 --- /dev/null +++ b/arch/powerpc/platforms/wsp/scom_wsp.c @@ -0,0 +1,77 @@ +/* + * SCOM backend for WSP + * + * Copyright 2010 Benjamin Herrenschmidt, IBM Corp. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ + +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "wsp.h" + + +static scom_map_t wsp_scom_map(struct device_node *dev, u64 reg, u64 count) +{ + struct resource r; + u64 xscom_addr; + + if (!of_get_property(dev, "scom-controller", NULL)) { + pr_err("%s: device %s is not a SCOM controller\n", + __func__, dev->full_name); + return SCOM_MAP_INVALID; + } + + if (of_address_to_resource(dev, 0, &r)) { + pr_debug("Failed to find SCOM controller address\n"); + return 0; + } + + /* Transform the SCOM address into an XSCOM offset */ + xscom_addr = ((reg & 0x7f000000) >> 1) | ((reg & 0xfffff) << 3); + + return (scom_map_t)ioremap(r.start + xscom_addr, count << 3); +} + +static void wsp_scom_unmap(scom_map_t map) +{ + iounmap((void *)map); +} + +static u64 wsp_scom_read(scom_map_t map, u32 reg) +{ + u64 __iomem *addr = (u64 __iomem *)map; + + return in_be64(addr + reg); +} + +static void wsp_scom_write(scom_map_t map, u32 reg, u64 value) +{ + u64 __iomem *addr = (u64 __iomem *)map; + + return out_be64(addr + reg, value); +} + +static const struct scom_controller wsp_scom_controller = { + .map = wsp_scom_map, + .unmap = wsp_scom_unmap, + .read = wsp_scom_read, + .write = wsp_scom_write +}; + +void scom_init_wsp(void) +{ + scom_init(&wsp_scom_controller); +} diff --git a/arch/powerpc/platforms/wsp/setup.c b/arch/powerpc/platforms/wsp/setup.c new file mode 100644 index 0000000..11ac2f0 --- /dev/null +++ b/arch/powerpc/platforms/wsp/setup.c @@ -0,0 +1,36 @@ +/* + * Copyright 2010 Michael Ellerman, IBM Corporation + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ + +#include +#include + +#include "wsp.h" + +/* + * Find chip-id by walking up device tree looking for ibm,wsp-chip-id property. + * Won't work for nodes that are not a descendant of a wsp node. + */ +int wsp_get_chip_id(struct device_node *dn) +{ + const u32 *p; + int rc; + + /* Start looking at the specified node, not its parent */ + dn = of_node_get(dn); + while (dn && !(p = of_get_property(dn, "ibm,wsp-chip-id", NULL))) + dn = of_get_next_parent(dn); + + if (!dn) + return -1; + + rc = *p; + of_node_put(dn); + + return rc; +} diff --git a/arch/powerpc/platforms/wsp/smp.c b/arch/powerpc/platforms/wsp/smp.c new file mode 100644 index 0000000..c7b8db9 --- /dev/null +++ b/arch/powerpc/platforms/wsp/smp.c @@ -0,0 +1,87 @@ +/* + * SMP Support for A2 platforms + * + * Copyright 2007 Benjamin Herrenschmidt, IBM Corp. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + * + */ + +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "ics.h" +#include "wsp.h" + +static void __devinit smp_a2_setup_cpu(int cpu) +{ + doorbell_setup_this_cpu(); + + if (cpu != boot_cpuid) + xics_setup_cpu(); +} + +int __devinit smp_a2_kick_cpu(int nr) +{ + const char *enable_method; + struct device_node *np; + int thr_idx; + + if (nr < 0 || nr >= NR_CPUS) + return -ENOENT; + + np = of_get_cpu_node(nr, &thr_idx); + if (!np) + return -ENODEV; + + enable_method = of_get_property(np, "enable-method", NULL); + pr_devel("CPU%d has enable-method: \"%s\"\n", nr, enable_method); + + if (!enable_method) { + printk(KERN_ERR "CPU%d has no enable-method\n", nr); + return -ENOENT; + } else if (strcmp(enable_method, "ibm,a2-scom") == 0) { + if (a2_scom_startup_cpu(nr, thr_idx, np)) + return -1; + } else { + printk(KERN_ERR "CPU%d: Don't understand enable-method \"%s\"\n", + nr, enable_method); + return -EINVAL; + } + + /* + * The processor is currently spinning, waiting for the + * cpu_start field to become non-zero After we set cpu_start, + * the processor will continue on to secondary_start + */ + paca[nr].cpu_start = 1; + + return 0; +} + +static int __init smp_a2_probe(void) +{ + return cpus_weight(cpu_possible_map); +} + +static struct smp_ops_t a2_smp_ops = { + .message_pass = doorbell_message_pass, + .probe = smp_a2_probe, + .kick_cpu = smp_a2_kick_cpu, + .setup_cpu = smp_a2_setup_cpu, +}; + +void __init a2_setup_smp(void) +{ + smp_ops = &a2_smp_ops; +} diff --git a/arch/powerpc/platforms/wsp/wsp.h b/arch/powerpc/platforms/wsp/wsp.h new file mode 100644 index 0000000..7c3e087 --- /dev/null +++ b/arch/powerpc/platforms/wsp/wsp.h @@ -0,0 +1,17 @@ +#ifndef __WSP_H +#define __WSP_H + +#include + +extern void wsp_setup_pci(void); +extern void scom_init_wsp(void); + +extern void a2_setup_smp(void); +extern int a2_scom_startup_cpu(unsigned int lcpu, int thr_idx, + struct device_node *np); +int smp_a2_cpu_bootable(unsigned int nr); +int __devinit smp_a2_kick_cpu(int nr); + +void opb_pic_init(void); + +#endif /* __WSP_H */ diff --git a/arch/powerpc/sysdev/xics/icp-native.c b/arch/powerpc/sysdev/xics/icp-native.c index d9e0515..3508321 100644 --- a/arch/powerpc/sysdev/xics/icp-native.c +++ b/arch/powerpc/sysdev/xics/icp-native.c @@ -7,6 +7,7 @@ * 2 of the License, or (at your option) any later version. * */ + #include #include #include -- cgit v0.10.2 From a0496d450ab8c17f6c4d86979b1f6ba486fe9365 Mon Sep 17 00:00:00 2001 From: Jack Miller Date: Thu, 14 Apr 2011 22:32:08 +0000 Subject: powerpc: Add early debug for WSP platforms Signed-off-by: Jack Miller Signed-off-by: Michael Ellerman Signed-off-by: Benjamin Herrenschmidt diff --git a/arch/powerpc/Kconfig.debug b/arch/powerpc/Kconfig.debug index 2d38a50..a597dd7 100644 --- a/arch/powerpc/Kconfig.debug +++ b/arch/powerpc/Kconfig.debug @@ -267,6 +267,11 @@ config PPC_EARLY_DEBUG_USBGECKO Select this to enable early debugging for Nintendo GameCube/Wii consoles via an external USB Gecko adapter. +config PPC_EARLY_DEBUG_WSP + bool "Early debugging via WSP's internal UART" + depends on PPC_WSP + select PPC_UDBG_16550 + endchoice config PPC_EARLY_DEBUG_44x_PHYSLOW diff --git a/arch/powerpc/include/asm/reg_a2.h b/arch/powerpc/include/asm/reg_a2.h index 3ba9c6f..3d52a11 100644 --- a/arch/powerpc/include/asm/reg_a2.h +++ b/arch/powerpc/include/asm/reg_a2.h @@ -110,6 +110,15 @@ #define TLB1_UR ASM_CONST(0x0000000000000002) #define TLB1_SR ASM_CONST(0x0000000000000001) +#ifdef CONFIG_PPC_EARLY_DEBUG_WSP +#define WSP_UART_PHYS 0xffc000c000 +/* This needs to be careful chosen to hit a !0 congruence class + * in the TLB since we bolt it in way 3, which is already occupied + * by our linear mapping primary bolted entry in CC 0. + */ +#define WSP_UART_VIRT 0xf000000000001000 +#endif + /* A2 erativax attributes definitions */ #define ERATIVAX_RS_IS_ALL 0x000 #define ERATIVAX_RS_IS_TID 0x040 diff --git a/arch/powerpc/include/asm/udbg.h b/arch/powerpc/include/asm/udbg.h index 11ae699..58580e9 100644 --- a/arch/powerpc/include/asm/udbg.h +++ b/arch/powerpc/include/asm/udbg.h @@ -52,6 +52,7 @@ extern void __init udbg_init_44x_as1(void); extern void __init udbg_init_40x_realmode(void); extern void __init udbg_init_cpm(void); extern void __init udbg_init_usbgecko(void); +extern void __init udbg_init_wsp(void); #endif /* __KERNEL__ */ #endif /* _ASM_POWERPC_UDBG_H */ diff --git a/arch/powerpc/kernel/exceptions-64e.S b/arch/powerpc/kernel/exceptions-64e.S index c98e9d2..4d0abb4 100644 --- a/arch/powerpc/kernel/exceptions-64e.S +++ b/arch/powerpc/kernel/exceptions-64e.S @@ -17,6 +17,7 @@ #include #include #include +#include #include #include #include @@ -951,6 +952,22 @@ a2_tlbinit_after_linear_map: .globl a2_tlbinit_after_iprot_flush a2_tlbinit_after_iprot_flush: +#ifdef CONFIG_PPC_EARLY_DEBUG_WSP + /* Now establish early debug mappings if applicable */ + /* Restore the MAS0 we used for linear mapping load */ + mtspr SPRN_MAS0,r11 + + lis r3,(MAS1_VALID | MAS1_IPROT)@h + ori r3,r3,(BOOK3E_PAGESZ_4K << MAS1_TSIZE_SHIFT) + mtspr SPRN_MAS1,r3 + LOAD_REG_IMMEDIATE(r3, WSP_UART_VIRT | MAS2_I | MAS2_G) + mtspr SPRN_MAS2,r3 + LOAD_REG_IMMEDIATE(r3, WSP_UART_PHYS | MAS3_SR | MAS3_SW) + mtspr SPRN_MAS7_MAS3,r3 + /* re-use the MAS8 value from the linear mapping */ + tlbwe +#endif /* CONFIG_PPC_EARLY_DEBUG_WSP */ + PPC_TLBILX(0,0,0) sync isync diff --git a/arch/powerpc/kernel/udbg.c b/arch/powerpc/kernel/udbg.c index e39cad8..23d65ab 100644 --- a/arch/powerpc/kernel/udbg.c +++ b/arch/powerpc/kernel/udbg.c @@ -62,6 +62,8 @@ void __init udbg_early_init(void) udbg_init_cpm(); #elif defined(CONFIG_PPC_EARLY_DEBUG_USBGECKO) udbg_init_usbgecko(); +#elif defined(CONFIG_PPC_EARLY_DEBUG_WSP) + udbg_init_wsp(); #endif #ifdef CONFIG_PPC_EARLY_DEBUG diff --git a/arch/powerpc/kernel/udbg_16550.c b/arch/powerpc/kernel/udbg_16550.c index baa33a7..6837f83 100644 --- a/arch/powerpc/kernel/udbg_16550.c +++ b/arch/powerpc/kernel/udbg_16550.c @@ -11,6 +11,7 @@ #include #include #include +#include extern u8 real_readb(volatile u8 __iomem *addr); extern void real_writeb(u8 data, volatile u8 __iomem *addr); @@ -298,3 +299,53 @@ void __init udbg_init_40x_realmode(void) udbg_getc_poll = NULL; } #endif /* CONFIG_PPC_EARLY_DEBUG_40x */ + +#ifdef CONFIG_PPC_EARLY_DEBUG_WSP +static void udbg_wsp_flush(void) +{ + if (udbg_comport) { + while ((readb(&udbg_comport->lsr) & LSR_THRE) == 0) + /* wait for idle */; + } +} + +static void udbg_wsp_putc(char c) +{ + if (udbg_comport) { + if (c == '\n') + udbg_wsp_putc('\r'); + udbg_wsp_flush(); + writeb(c, &udbg_comport->thr); eieio(); + } +} + +static int udbg_wsp_getc(void) +{ + if (udbg_comport) { + while ((readb(&udbg_comport->lsr) & LSR_DR) == 0) + ; /* wait for char */ + return readb(&udbg_comport->rbr); + } + return -1; +} + +static int udbg_wsp_getc_poll(void) +{ + if (udbg_comport) + if (readb(&udbg_comport->lsr) & LSR_DR) + return readb(&udbg_comport->rbr); + return -1; +} + +void __init udbg_init_wsp(void) +{ + udbg_comport = (struct NS16550 __iomem *)WSP_UART_VIRT; + + udbg_init_uart(udbg_comport, 57600, 50000000); + + udbg_putc = udbg_wsp_putc; + udbg_flush = udbg_wsp_flush; + udbg_getc = udbg_wsp_getc; + udbg_getc_poll = udbg_wsp_getc_poll; +} +#endif /* CONFIG_PPC_EARLY_DEBUG_WSP */ -- cgit v0.10.2 From a00e0d714fbded07a7a2254391ce9ed5a5cb9d82 Mon Sep 17 00:00:00 2001 From: "Paul E. McKenney" Date: Tue, 8 Feb 2011 17:14:39 -0800 Subject: rcu: Remove conditional compilation for RCU CPU stall warnings The RCU CPU stall warnings can now be controlled using the rcu_cpu_stall_suppress boot-time parameter or via the same parameter from sysfs. There is therefore no longer any reason to have kernel config parameters for this feature. This commit therefore removes the RCU_CPU_STALL_DETECTOR and RCU_CPU_STALL_DETECTOR_RUNNABLE kernel config parameters. The RCU_CPU_STALL_TIMEOUT parameter remains to allow the timeout to be tuned and the RCU_CPU_STALL_VERBOSE parameter remains to allow task-stall information to be suppressed if desired. Signed-off-by: Paul E. McKenney Reviewed-by: Josh Triplett diff --git a/Documentation/RCU/00-INDEX b/Documentation/RCU/00-INDEX index 71b6f50..1d7a885 100644 --- a/Documentation/RCU/00-INDEX +++ b/Documentation/RCU/00-INDEX @@ -21,7 +21,7 @@ rcu.txt RTFP.txt - List of RCU papers (bibliography) going back to 1980. stallwarn.txt - - RCU CPU stall warnings (CONFIG_RCU_CPU_STALL_DETECTOR) + - RCU CPU stall warnings (module parameter rcu_cpu_stall_suppress) torture.txt - RCU Torture Test Operation (CONFIG_RCU_TORTURE_TEST) trace.txt diff --git a/Documentation/RCU/stallwarn.txt b/Documentation/RCU/stallwarn.txt index 862c08e..4e95920 100644 --- a/Documentation/RCU/stallwarn.txt +++ b/Documentation/RCU/stallwarn.txt @@ -1,22 +1,25 @@ Using RCU's CPU Stall Detector -The CONFIG_RCU_CPU_STALL_DETECTOR kernel config parameter enables -RCU's CPU stall detector, which detects conditions that unduly delay -RCU grace periods. The stall detector's idea of what constitutes -"unduly delayed" is controlled by a set of C preprocessor macros: +The rcu_cpu_stall_suppress module parameter enables RCU's CPU stall +detector, which detects conditions that unduly delay RCU grace periods. +This module parameter enables CPU stall detection by default, but +may be overridden via boot-time parameter or at runtime via sysfs. +The stall detector's idea of what constitutes "unduly delayed" is +controlled by a set of kernel configuration variables and cpp macros: -RCU_SECONDS_TILL_STALL_CHECK +CONFIG_RCU_CPU_STALL_TIMEOUT - This macro defines the period of time that RCU will wait from - the beginning of a grace period until it issues an RCU CPU - stall warning. This time period is normally ten seconds. + This kernel configuration parameter defines the period of time + that RCU will wait from the beginning of a grace period until it + issues an RCU CPU stall warning. This time period is normally + ten seconds. RCU_SECONDS_TILL_STALL_RECHECK This macro defines the period of time that RCU will wait after issuing a stall warning until it issues another stall warning - for the same stall. This time period is normally set to thirty - seconds. + for the same stall. This time period is normally set to three + times the check interval plus thirty seconds. RCU_STALL_RAT_DELAY diff --git a/kernel/rcutree.c b/kernel/rcutree.c index dd4aea8..18f7a59 100644 --- a/kernel/rcutree.c +++ b/kernel/rcutree.c @@ -140,10 +140,8 @@ module_param(blimit, int, 0); module_param(qhimark, int, 0); module_param(qlowmark, int, 0); -#ifdef CONFIG_RCU_CPU_STALL_DETECTOR -int rcu_cpu_stall_suppress __read_mostly = RCU_CPU_STALL_SUPPRESS_INIT; +int rcu_cpu_stall_suppress __read_mostly; module_param(rcu_cpu_stall_suppress, int, 0644); -#endif /* #ifdef CONFIG_RCU_CPU_STALL_DETECTOR */ static void force_quiescent_state(struct rcu_state *rsp, int relaxed); static int rcu_pending(int cpu); @@ -450,8 +448,6 @@ static int rcu_implicit_dynticks_qs(struct rcu_data *rdp) #endif /* #else #ifdef CONFIG_NO_HZ */ -#ifdef CONFIG_RCU_CPU_STALL_DETECTOR - int rcu_cpu_stall_suppress __read_mostly; static void record_gp_stall_check_time(struct rcu_state *rsp) @@ -587,26 +583,6 @@ static void __init check_cpu_stall_init(void) atomic_notifier_chain_register(&panic_notifier_list, &rcu_panic_block); } -#else /* #ifdef CONFIG_RCU_CPU_STALL_DETECTOR */ - -static void record_gp_stall_check_time(struct rcu_state *rsp) -{ -} - -static void check_cpu_stall(struct rcu_state *rsp, struct rcu_data *rdp) -{ -} - -void rcu_cpu_stall_reset(void) -{ -} - -static void __init check_cpu_stall_init(void) -{ -} - -#endif /* #else #ifdef CONFIG_RCU_CPU_STALL_DETECTOR */ - /* * Update CPU-local rcu_data state to record the newly noticed grace period. * This is used both when we started the grace period and when we notice diff --git a/kernel/rcutree.h b/kernel/rcutree.h index e8f057e..e1a6663 100644 --- a/kernel/rcutree.h +++ b/kernel/rcutree.h @@ -254,7 +254,6 @@ struct rcu_data { #endif /* #else #ifdef CONFIG_NO_HZ */ #define RCU_JIFFIES_TILL_FORCE_QS 3 /* for rsp->jiffies_force_qs */ -#ifdef CONFIG_RCU_CPU_STALL_DETECTOR #ifdef CONFIG_PROVE_RCU #define RCU_STALL_DELAY_DELTA (5 * HZ) @@ -272,13 +271,6 @@ struct rcu_data { /* scheduling clock irq */ /* before ratting on them. */ -#ifdef CONFIG_RCU_CPU_STALL_DETECTOR_RUNNABLE -#define RCU_CPU_STALL_SUPPRESS_INIT 0 -#else -#define RCU_CPU_STALL_SUPPRESS_INIT 1 -#endif - -#endif /* #ifdef CONFIG_RCU_CPU_STALL_DETECTOR */ /* * RCU global state, including node hierarchy. This hierarchy is @@ -325,12 +317,10 @@ struct rcu_state { /* due to lock unavailable. */ unsigned long n_force_qs_ngp; /* Number of calls leaving */ /* due to no GP active. */ -#ifdef CONFIG_RCU_CPU_STALL_DETECTOR unsigned long gp_start; /* Time at which GP started, */ /* but in jiffies. */ unsigned long jiffies_stall; /* Time at which to check */ /* for CPU stalls. */ -#endif /* #ifdef CONFIG_RCU_CPU_STALL_DETECTOR */ char *name; /* Name of structure. */ }; @@ -366,11 +356,9 @@ static int rcu_preempted_readers(struct rcu_node *rnp); static void rcu_report_unblock_qs_rnp(struct rcu_node *rnp, unsigned long flags); #endif /* #ifdef CONFIG_HOTPLUG_CPU */ -#ifdef CONFIG_RCU_CPU_STALL_DETECTOR static void rcu_print_detail_task_stall(struct rcu_state *rsp); static void rcu_print_task_stall(struct rcu_node *rnp); static void rcu_preempt_stall_reset(void); -#endif /* #ifdef CONFIG_RCU_CPU_STALL_DETECTOR */ static void rcu_preempt_check_blocked_tasks(struct rcu_node *rnp); #ifdef CONFIG_HOTPLUG_CPU static int rcu_preempt_offline_tasks(struct rcu_state *rsp, diff --git a/kernel/rcutree_plugin.h b/kernel/rcutree_plugin.h index a363871..38426ef 100644 --- a/kernel/rcutree_plugin.h +++ b/kernel/rcutree_plugin.h @@ -54,10 +54,6 @@ static void __init rcu_bootup_announce_oddness(void) #ifdef CONFIG_RCU_TORTURE_TEST_RUNNABLE printk(KERN_INFO "\tRCU torture testing starts during boot.\n"); #endif -#ifndef CONFIG_RCU_CPU_STALL_DETECTOR - printk(KERN_INFO - "\tRCU-based detection of stalled CPUs is disabled.\n"); -#endif #if defined(CONFIG_TREE_PREEMPT_RCU) && !defined(CONFIG_RCU_CPU_STALL_VERBOSE) printk(KERN_INFO "\tVerbose stalled-CPUs detection is disabled.\n"); #endif @@ -356,8 +352,6 @@ void __rcu_read_unlock(void) } EXPORT_SYMBOL_GPL(__rcu_read_unlock); -#ifdef CONFIG_RCU_CPU_STALL_DETECTOR - #ifdef CONFIG_RCU_CPU_STALL_VERBOSE /* @@ -430,8 +424,6 @@ static void rcu_preempt_stall_reset(void) rcu_preempt_state.jiffies_stall = jiffies + ULONG_MAX / 2; } -#endif /* #ifdef CONFIG_RCU_CPU_STALL_DETECTOR */ - /* * Check that the list of blocked tasks for the newly completed grace * period is in fact empty. It is a serious bug to complete a grace @@ -862,8 +854,6 @@ static void rcu_report_unblock_qs_rnp(struct rcu_node *rnp, unsigned long flags) #endif /* #ifdef CONFIG_HOTPLUG_CPU */ -#ifdef CONFIG_RCU_CPU_STALL_DETECTOR - /* * Because preemptable RCU does not exist, we never have to check for * tasks blocked within RCU read-side critical sections. @@ -888,8 +878,6 @@ static void rcu_preempt_stall_reset(void) { } -#endif /* #ifdef CONFIG_RCU_CPU_STALL_DETECTOR */ - /* * Because there is no preemptable RCU, there can be no readers blocked, * so there is no need to check for blocked tasks. So check only for diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug index c768bcd..93ce6de3 100644 --- a/lib/Kconfig.debug +++ b/lib/Kconfig.debug @@ -875,22 +875,9 @@ config RCU_TORTURE_TEST_RUNNABLE Say N here if you want the RCU torture tests to start only after being manually enabled via /proc. -config RCU_CPU_STALL_DETECTOR - bool "Check for stalled CPUs delaying RCU grace periods" - depends on TREE_RCU || TREE_PREEMPT_RCU - default y - help - This option causes RCU to printk information on which - CPUs are delaying the current grace period, but only when - the grace period extends for excessive time periods. - - Say N if you want to disable such checks. - - Say Y if you are unsure. - config RCU_CPU_STALL_TIMEOUT int "RCU CPU stall timeout in seconds" - depends on RCU_CPU_STALL_DETECTOR + depends on TREE_RCU || TREE_PREEMPT_RCU range 3 300 default 60 help @@ -899,22 +886,9 @@ config RCU_CPU_STALL_TIMEOUT RCU grace period persists, additional CPU stall warnings are printed at more widely spaced intervals. -config RCU_CPU_STALL_DETECTOR_RUNNABLE - bool "RCU CPU stall checking starts automatically at boot" - depends on RCU_CPU_STALL_DETECTOR - default y - help - If set, start checking for RCU CPU stalls immediately on - boot. Otherwise, RCU CPU stall checking must be manually - enabled. - - Say Y if you are unsure. - - Say N if you wish to suppress RCU CPU stall checking during boot. - config RCU_CPU_STALL_VERBOSE bool "Print additional per-task information for RCU_CPU_STALL_DETECTOR" - depends on RCU_CPU_STALL_DETECTOR && TREE_PREEMPT_RCU + depends on TREE_PREEMPT_RCU default y help This option causes RCU to printk detailed per-task information -- cgit v0.10.2 From e59fb3120becfb36b22ddb8bd27d065d3cdca499 Mon Sep 17 00:00:00 2001 From: "Paul E. McKenney" Date: Tue, 7 Sep 2010 10:38:22 -0700 Subject: rcu: Decrease memory-barrier usage based on semi-formal proof Commit d09b62d fixed grace-period synchronization, but left some smp_mb() invocations in rcu_process_callbacks() that are no longer needed, but sheer paranoia prevented them from being removed. This commit removes them and provides a proof of correctness in their absence. It also adds a memory barrier to rcu_report_qs_rsp() immediately before the update to rsp->completed in order to handle the theoretical possibility that the compiler or CPU might move massive quantities of code into a lock-based critical section. This also proves that the sheer paranoia was not entirely unjustified, at least from a theoretical point of view. In addition, the old dyntick-idle synchronization depended on the fact that grace periods were many milliseconds in duration, so that it could be assumed that no dyntick-idle CPU could reorder a memory reference across an entire grace period. Unfortunately for this design, the addition of expedited grace periods breaks this assumption, which has the unfortunate side-effect of requiring atomic operations in the functions that track dyntick-idle state for RCU. (There is some hope that the algorithms used in user-level RCU might be applied here, but some work is required to handle the NMIs that user-space applications can happily ignore. For the short term, better safe than sorry.) This proof assumes that neither compiler nor CPU will allow a lock acquisition and release to be reordered, as doing so can result in deadlock. The proof is as follows: 1. A given CPU declares a quiescent state under the protection of its leaf rcu_node's lock. 2. If there is more than one level of rcu_node hierarchy, the last CPU to declare a quiescent state will also acquire the ->lock of the next rcu_node up in the hierarchy, but only after releasing the lower level's lock. The acquisition of this lock clearly cannot occur prior to the acquisition of the leaf node's lock. 3. Step 2 repeats until we reach the root rcu_node structure. Please note again that only one lock is held at a time through this process. The acquisition of the root rcu_node's ->lock must occur after the release of that of the leaf rcu_node. 4. At this point, we set the ->completed field in the rcu_state structure in rcu_report_qs_rsp(). However, if the rcu_node hierarchy contains only one rcu_node, then in theory the code preceding the quiescent state could leak into the critical section. We therefore precede the update of ->completed with a memory barrier. All CPUs will therefore agree that any updates preceding any report of a quiescent state will have happened before the update of ->completed. 5. Regardless of whether a new grace period is needed, rcu_start_gp() will propagate the new value of ->completed to all of the leaf rcu_node structures, under the protection of each rcu_node's ->lock. If a new grace period is needed immediately, this propagation will occur in the same critical section that ->completed was set in, but courtesy of the memory barrier in #4 above, is still seen to follow any pre-quiescent-state activity. 6. When a given CPU invokes __rcu_process_gp_end(), it becomes aware of the end of the old grace period and therefore makes any RCU callbacks that were waiting on that grace period eligible for invocation. If this CPU is the same one that detected the end of the grace period, and if there is but a single rcu_node in the hierarchy, we will still be in the single critical section. In this case, the memory barrier in step #4 guarantees that all callbacks will be seen to execute after each CPU's quiescent state. On the other hand, if this is a different CPU, it will acquire the leaf rcu_node's ->lock, and will again be serialized after each CPU's quiescent state for the old grace period. On the strength of this proof, this commit therefore removes the memory barriers from rcu_process_callbacks() and adds one to rcu_report_qs_rsp(). The effect is to reduce the number of memory barriers by one and to reduce the frequency of execution from about once per scheduling tick per CPU to once per grace period. Signed-off-by: Paul E. McKenney Reviewed-by: Josh Triplett diff --git a/Documentation/RCU/trace.txt b/Documentation/RCU/trace.txt index 6a8c73f..e731ad2 100644 --- a/Documentation/RCU/trace.txt +++ b/Documentation/RCU/trace.txt @@ -21,23 +21,23 @@ rcu_pending() function decided that there was core RCU work to do). The output of "cat rcu/rcudata" looks as follows: rcu_sched: - 0 c=17829 g=17829 pq=1 pqc=17829 qp=0 dt=10951/1 dn=0 df=1101 of=0 ri=36 ql=0 b=10 - 1 c=17829 g=17829 pq=1 pqc=17829 qp=0 dt=16117/1 dn=0 df=1015 of=0 ri=0 ql=0 b=10 - 2 c=17829 g=17829 pq=1 pqc=17829 qp=0 dt=1445/1 dn=0 df=1839 of=0 ri=0 ql=0 b=10 - 3 c=17829 g=17829 pq=1 pqc=17829 qp=0 dt=6681/1 dn=0 df=1545 of=0 ri=0 ql=0 b=10 - 4 c=17829 g=17829 pq=1 pqc=17829 qp=0 dt=1003/1 dn=0 df=1992 of=0 ri=0 ql=0 b=10 - 5 c=17829 g=17830 pq=1 pqc=17829 qp=1 dt=3887/1 dn=0 df=3331 of=0 ri=4 ql=2 b=10 - 6 c=17829 g=17829 pq=1 pqc=17829 qp=0 dt=859/1 dn=0 df=3224 of=0 ri=0 ql=0 b=10 - 7 c=17829 g=17830 pq=0 pqc=17829 qp=1 dt=3761/1 dn=0 df=1818 of=0 ri=0 ql=2 b=10 + 0 c=17829 g=17829 pq=1 pqc=17829 qp=0 dt=10951/1/0 df=1101 of=0 ri=36 ql=0 b=10 + 1 c=17829 g=17829 pq=1 pqc=17829 qp=0 dt=16117/1/0 df=1015 of=0 ri=0 ql=0 b=10 + 2 c=17829 g=17829 pq=1 pqc=17829 qp=0 dt=1445/1/0 df=1839 of=0 ri=0 ql=0 b=10 + 3 c=17829 g=17829 pq=1 pqc=17829 qp=0 dt=6681/1/0 df=1545 of=0 ri=0 ql=0 b=10 + 4 c=17829 g=17829 pq=1 pqc=17829 qp=0 dt=1003/1/0 df=1992 of=0 ri=0 ql=0 b=10 + 5 c=17829 g=17830 pq=1 pqc=17829 qp=1 dt=3887/1/0 df=3331 of=0 ri=4 ql=2 b=10 + 6 c=17829 g=17829 pq=1 pqc=17829 qp=0 dt=859/1/0 df=3224 of=0 ri=0 ql=0 b=10 + 7 c=17829 g=17830 pq=0 pqc=17829 qp=1 dt=3761/1/0 df=1818 of=0 ri=0 ql=2 b=10 rcu_bh: - 0 c=-275 g=-275 pq=1 pqc=-275 qp=0 dt=10951/1 dn=0 df=0 of=0 ri=0 ql=0 b=10 - 1 c=-275 g=-275 pq=1 pqc=-275 qp=0 dt=16117/1 dn=0 df=13 of=0 ri=0 ql=0 b=10 - 2 c=-275 g=-275 pq=1 pqc=-275 qp=0 dt=1445/1 dn=0 df=15 of=0 ri=0 ql=0 b=10 - 3 c=-275 g=-275 pq=1 pqc=-275 qp=0 dt=6681/1 dn=0 df=9 of=0 ri=0 ql=0 b=10 - 4 c=-275 g=-275 pq=1 pqc=-275 qp=0 dt=1003/1 dn=0 df=15 of=0 ri=0 ql=0 b=10 - 5 c=-275 g=-275 pq=1 pqc=-275 qp=0 dt=3887/1 dn=0 df=15 of=0 ri=0 ql=0 b=10 - 6 c=-275 g=-275 pq=1 pqc=-275 qp=0 dt=859/1 dn=0 df=15 of=0 ri=0 ql=0 b=10 - 7 c=-275 g=-275 pq=1 pqc=-275 qp=0 dt=3761/1 dn=0 df=15 of=0 ri=0 ql=0 b=10 + 0 c=-275 g=-275 pq=1 pqc=-275 qp=0 dt=10951/1/0 df=0 of=0 ri=0 ql=0 b=10 + 1 c=-275 g=-275 pq=1 pqc=-275 qp=0 dt=16117/1/0 df=13 of=0 ri=0 ql=0 b=10 + 2 c=-275 g=-275 pq=1 pqc=-275 qp=0 dt=1445/1/0 df=15 of=0 ri=0 ql=0 b=10 + 3 c=-275 g=-275 pq=1 pqc=-275 qp=0 dt=6681/1/0 df=9 of=0 ri=0 ql=0 b=10 + 4 c=-275 g=-275 pq=1 pqc=-275 qp=0 dt=1003/1/0 df=15 of=0 ri=0 ql=0 b=10 + 5 c=-275 g=-275 pq=1 pqc=-275 qp=0 dt=3887/1/0 df=15 of=0 ri=0 ql=0 b=10 + 6 c=-275 g=-275 pq=1 pqc=-275 qp=0 dt=859/1/0 df=15 of=0 ri=0 ql=0 b=10 + 7 c=-275 g=-275 pq=1 pqc=-275 qp=0 dt=3761/1/0 df=15 of=0 ri=0 ql=0 b=10 The first section lists the rcu_data structures for rcu_sched, the second for rcu_bh. Note that CONFIG_TREE_PREEMPT_RCU kernels will have an @@ -85,18 +85,10 @@ o "qp" indicates that RCU still expects a quiescent state from o "dt" is the current value of the dyntick counter that is incremented when entering or leaving dynticks idle state, either by the - scheduler or by irq. The number after the "/" is the interrupt - nesting depth when in dyntick-idle state, or one greater than - the interrupt-nesting depth otherwise. - - This field is displayed only for CONFIG_NO_HZ kernels. - -o "dn" is the current value of the dyntick counter that is incremented - when entering or leaving dynticks idle state via NMI. If both - the "dt" and "dn" values are even, then this CPU is in dynticks - idle mode and may be ignored by RCU. If either of these two - counters is odd, then RCU must be alert to the possibility of - an RCU read-side critical section running on this CPU. + scheduler or by irq. The number after the first "/" is the + interrupt nesting depth when in dyntick-idle state, or one + greater than the interrupt-nesting depth otherwise. The number + after the second "/" is the NMI nesting depth. This field is displayed only for CONFIG_NO_HZ kernels. diff --git a/kernel/rcutree.c b/kernel/rcutree.c index 18f7a59..90104a1 100644 --- a/kernel/rcutree.c +++ b/kernel/rcutree.c @@ -128,7 +128,7 @@ void rcu_note_context_switch(int cpu) #ifdef CONFIG_NO_HZ DEFINE_PER_CPU(struct rcu_dynticks, rcu_dynticks) = { .dynticks_nesting = 1, - .dynticks = 1, + .dynticks = ATOMIC_INIT(1), }; #endif /* #ifdef CONFIG_NO_HZ */ @@ -262,13 +262,25 @@ void rcu_enter_nohz(void) unsigned long flags; struct rcu_dynticks *rdtp; - smp_mb(); /* CPUs seeing ++ must see prior RCU read-side crit sects */ local_irq_save(flags); rdtp = &__get_cpu_var(rcu_dynticks); - rdtp->dynticks++; - rdtp->dynticks_nesting--; - WARN_ON_ONCE(rdtp->dynticks & 0x1); + if (--rdtp->dynticks_nesting) { + local_irq_restore(flags); + return; + } + /* CPUs seeing atomic_inc() must see prior RCU read-side crit sects */ + smp_mb__before_atomic_inc(); /* See above. */ + atomic_inc(&rdtp->dynticks); + smp_mb__after_atomic_inc(); /* Force ordering with next sojourn. */ + WARN_ON_ONCE(atomic_read(&rdtp->dynticks) & 0x1); local_irq_restore(flags); + + /* If the interrupt queued a callback, get out of dyntick mode. */ + if (in_irq() && + (__get_cpu_var(rcu_sched_data).nxtlist || + __get_cpu_var(rcu_bh_data).nxtlist || + rcu_preempt_needs_cpu(smp_processor_id()))) + set_need_resched(); } /* @@ -284,11 +296,16 @@ void rcu_exit_nohz(void) local_irq_save(flags); rdtp = &__get_cpu_var(rcu_dynticks); - rdtp->dynticks++; - rdtp->dynticks_nesting++; - WARN_ON_ONCE(!(rdtp->dynticks & 0x1)); + if (rdtp->dynticks_nesting++) { + local_irq_restore(flags); + return; + } + smp_mb__before_atomic_inc(); /* Force ordering w/previous sojourn. */ + atomic_inc(&rdtp->dynticks); + /* CPUs seeing atomic_inc() must see later RCU read-side crit sects */ + smp_mb__after_atomic_inc(); /* See above. */ + WARN_ON_ONCE(!(atomic_read(&rdtp->dynticks) & 0x1)); local_irq_restore(flags); - smp_mb(); /* CPUs seeing ++ must see later RCU read-side crit sects */ } /** @@ -302,11 +319,15 @@ void rcu_nmi_enter(void) { struct rcu_dynticks *rdtp = &__get_cpu_var(rcu_dynticks); - if (rdtp->dynticks & 0x1) + if (rdtp->dynticks_nmi_nesting == 0 && + (atomic_read(&rdtp->dynticks) & 0x1)) return; - rdtp->dynticks_nmi++; - WARN_ON_ONCE(!(rdtp->dynticks_nmi & 0x1)); - smp_mb(); /* CPUs seeing ++ must see later RCU read-side crit sects */ + rdtp->dynticks_nmi_nesting++; + smp_mb__before_atomic_inc(); /* Force delay from prior write. */ + atomic_inc(&rdtp->dynticks); + /* CPUs seeing atomic_inc() must see later RCU read-side crit sects */ + smp_mb__after_atomic_inc(); /* See above. */ + WARN_ON_ONCE(!(atomic_read(&rdtp->dynticks) & 0x1)); } /** @@ -320,11 +341,14 @@ void rcu_nmi_exit(void) { struct rcu_dynticks *rdtp = &__get_cpu_var(rcu_dynticks); - if (rdtp->dynticks & 0x1) + if (rdtp->dynticks_nmi_nesting == 0 || + --rdtp->dynticks_nmi_nesting != 0) return; - smp_mb(); /* CPUs seeing ++ must see prior RCU read-side crit sects */ - rdtp->dynticks_nmi++; - WARN_ON_ONCE(rdtp->dynticks_nmi & 0x1); + /* CPUs seeing atomic_inc() must see prior RCU read-side crit sects */ + smp_mb__before_atomic_inc(); /* See above. */ + atomic_inc(&rdtp->dynticks); + smp_mb__after_atomic_inc(); /* Force delay to next write. */ + WARN_ON_ONCE(atomic_read(&rdtp->dynticks) & 0x1); } /** @@ -335,13 +359,7 @@ void rcu_nmi_exit(void) */ void rcu_irq_enter(void) { - struct rcu_dynticks *rdtp = &__get_cpu_var(rcu_dynticks); - - if (rdtp->dynticks_nesting++) - return; - rdtp->dynticks++; - WARN_ON_ONCE(!(rdtp->dynticks & 0x1)); - smp_mb(); /* CPUs seeing ++ must see later RCU read-side crit sects */ + rcu_exit_nohz(); } /** @@ -353,18 +371,7 @@ void rcu_irq_enter(void) */ void rcu_irq_exit(void) { - struct rcu_dynticks *rdtp = &__get_cpu_var(rcu_dynticks); - - if (--rdtp->dynticks_nesting) - return; - smp_mb(); /* CPUs seeing ++ must see prior RCU read-side crit sects */ - rdtp->dynticks++; - WARN_ON_ONCE(rdtp->dynticks & 0x1); - - /* If the interrupt queued a callback, get out of dyntick mode. */ - if (__this_cpu_read(rcu_sched_data.nxtlist) || - __this_cpu_read(rcu_bh_data.nxtlist)) - set_need_resched(); + rcu_enter_nohz(); } #ifdef CONFIG_SMP @@ -376,19 +383,8 @@ void rcu_irq_exit(void) */ static int dyntick_save_progress_counter(struct rcu_data *rdp) { - int ret; - int snap; - int snap_nmi; - - snap = rdp->dynticks->dynticks; - snap_nmi = rdp->dynticks->dynticks_nmi; - smp_mb(); /* Order sampling of snap with end of grace period. */ - rdp->dynticks_snap = snap; - rdp->dynticks_nmi_snap = snap_nmi; - ret = ((snap & 0x1) == 0) && ((snap_nmi & 0x1) == 0); - if (ret) - rdp->dynticks_fqs++; - return ret; + rdp->dynticks_snap = atomic_add_return(0, &rdp->dynticks->dynticks); + return 0; } /* @@ -399,16 +395,11 @@ static int dyntick_save_progress_counter(struct rcu_data *rdp) */ static int rcu_implicit_dynticks_qs(struct rcu_data *rdp) { - long curr; - long curr_nmi; - long snap; - long snap_nmi; + unsigned long curr; + unsigned long snap; - curr = rdp->dynticks->dynticks; - snap = rdp->dynticks_snap; - curr_nmi = rdp->dynticks->dynticks_nmi; - snap_nmi = rdp->dynticks_nmi_snap; - smp_mb(); /* force ordering with cpu entering/leaving dynticks. */ + curr = (unsigned long)atomic_add_return(0, &rdp->dynticks->dynticks); + snap = (unsigned long)rdp->dynticks_snap; /* * If the CPU passed through or entered a dynticks idle phase with @@ -418,8 +409,7 @@ static int rcu_implicit_dynticks_qs(struct rcu_data *rdp) * read-side critical section that started before the beginning * of the current RCU grace period. */ - if ((curr != snap || (curr & 0x1) == 0) && - (curr_nmi != snap_nmi || (curr_nmi & 0x1) == 0)) { + if ((curr & 0x1) == 0 || ULONG_CMP_GE(curr, snap + 2)) { rdp->dynticks_fqs++; return 1; } @@ -841,6 +831,12 @@ static void rcu_report_qs_rsp(struct rcu_state *rsp, unsigned long flags) __releases(rcu_get_root(rsp)->lock) { WARN_ON_ONCE(!rcu_gp_in_progress(rsp)); + + /* + * Ensure that all grace-period and pre-grace-period activity + * is seen before the assignment to rsp->completed. + */ + smp_mb(); /* See above block comment. */ rsp->completed = rsp->gpnum; rsp->signaled = RCU_GP_IDLE; rcu_start_gp(rsp, flags); /* releases root node's rnp->lock. */ @@ -1367,25 +1363,11 @@ __rcu_process_callbacks(struct rcu_state *rsp, struct rcu_data *rdp) */ static void rcu_process_callbacks(struct softirq_action *unused) { - /* - * Memory references from any prior RCU read-side critical sections - * executed by the interrupted code must be seen before any RCU - * grace-period manipulations below. - */ - smp_mb(); /* See above block comment. */ - __rcu_process_callbacks(&rcu_sched_state, &__get_cpu_var(rcu_sched_data)); __rcu_process_callbacks(&rcu_bh_state, &__get_cpu_var(rcu_bh_data)); rcu_preempt_process_callbacks(); - /* - * Memory references from any later RCU read-side critical sections - * executed by the interrupted code must be seen after any RCU - * grace-period manipulations above. - */ - smp_mb(); /* See above block comment. */ - /* If we are last CPU on way to dyntick-idle mode, accelerate it. */ rcu_needs_cpu_flush(); } diff --git a/kernel/rcutree.h b/kernel/rcutree.h index e1a6663..bd891de 100644 --- a/kernel/rcutree.h +++ b/kernel/rcutree.h @@ -84,11 +84,9 @@ * Dynticks per-CPU state. */ struct rcu_dynticks { - int dynticks_nesting; /* Track nesting level, sort of. */ - int dynticks; /* Even value for dynticks-idle, else odd. */ - int dynticks_nmi; /* Even value for either dynticks-idle or */ - /* not in nmi handler, else odd. So this */ - /* remains even for nmi from irq handler. */ + int dynticks_nesting; /* Track irq/process nesting level. */ + int dynticks_nmi_nesting; /* Track NMI nesting level. */ + atomic_t dynticks; /* Even value for dynticks-idle, else odd. */ }; /* @@ -218,7 +216,6 @@ struct rcu_data { /* 3) dynticks interface. */ struct rcu_dynticks *dynticks; /* Shared per-CPU dynticks state. */ int dynticks_snap; /* Per-GP tracking for dynticks. */ - int dynticks_nmi_snap; /* Per-GP tracking for dynticks_nmi. */ #endif /* #ifdef CONFIG_NO_HZ */ /* 4) reasons this CPU needed to be kicked by force_quiescent_state */ diff --git a/kernel/rcutree_plugin.h b/kernel/rcutree_plugin.h index 38426ef..764b5fc 100644 --- a/kernel/rcutree_plugin.h +++ b/kernel/rcutree_plugin.h @@ -1182,7 +1182,6 @@ int rcu_needs_cpu(int cpu) { int c = 0; int snap; - int snap_nmi; int thatcpu; /* Check for being in the holdoff period. */ @@ -1193,10 +1192,10 @@ int rcu_needs_cpu(int cpu) for_each_online_cpu(thatcpu) { if (thatcpu == cpu) continue; - snap = per_cpu(rcu_dynticks, thatcpu).dynticks; - snap_nmi = per_cpu(rcu_dynticks, thatcpu).dynticks_nmi; + snap = atomic_add_return(0, &per_cpu(rcu_dynticks, + thatcpu).dynticks); smp_mb(); /* Order sampling of snap with end of grace period. */ - if (((snap & 0x1) != 0) || ((snap_nmi & 0x1) != 0)) { + if ((snap & 0x1) != 0) { per_cpu(rcu_dyntick_drain, cpu) = 0; per_cpu(rcu_dyntick_holdoff, cpu) = jiffies - 1; return rcu_needs_cpu_quick_check(cpu); diff --git a/kernel/rcutree_trace.c b/kernel/rcutree_trace.c index c8e9785..4a21ca5 100644 --- a/kernel/rcutree_trace.c +++ b/kernel/rcutree_trace.c @@ -57,10 +57,10 @@ static void print_one_rcu_data(struct seq_file *m, struct rcu_data *rdp) rdp->passed_quiesc, rdp->passed_quiesc_completed, rdp->qs_pending); #ifdef CONFIG_NO_HZ - seq_printf(m, " dt=%d/%d dn=%d df=%lu", - rdp->dynticks->dynticks, + seq_printf(m, " dt=%d/%d/%d df=%lu", + atomic_read(&rdp->dynticks->dynticks), rdp->dynticks->dynticks_nesting, - rdp->dynticks->dynticks_nmi, + rdp->dynticks->dynticks_nmi_nesting, rdp->dynticks_fqs); #endif /* #ifdef CONFIG_NO_HZ */ seq_printf(m, " of=%lu ri=%lu", rdp->offline_fqs, rdp->resched_ipi); @@ -115,9 +115,9 @@ static void print_one_rcu_data_csv(struct seq_file *m, struct rcu_data *rdp) rdp->qs_pending); #ifdef CONFIG_NO_HZ seq_printf(m, ",%d,%d,%d,%lu", - rdp->dynticks->dynticks, + atomic_read(&rdp->dynticks->dynticks), rdp->dynticks->dynticks_nesting, - rdp->dynticks->dynticks_nmi, + rdp->dynticks->dynticks_nmi_nesting, rdp->dynticks_fqs); #endif /* #ifdef CONFIG_NO_HZ */ seq_printf(m, ",%lu,%lu", rdp->offline_fqs, rdp->resched_ipi); @@ -130,7 +130,7 @@ static int show_rcudata_csv(struct seq_file *m, void *unused) { seq_puts(m, "\"CPU\",\"Online?\",\"c\",\"g\",\"pq\",\"pqc\",\"pq\","); #ifdef CONFIG_NO_HZ - seq_puts(m, "\"dt\",\"dt nesting\",\"dn\",\"df\","); + seq_puts(m, "\"dt\",\"dt nesting\",\"dt NMI nesting\",\"df\","); #endif /* #ifdef CONFIG_NO_HZ */ seq_puts(m, "\"of\",\"ri\",\"ql\",\"b\",\"ci\",\"co\",\"ca\"\n"); #ifdef CONFIG_TREE_PREEMPT_RCU -- cgit v0.10.2 From 12f5f524cafef3ab689929b118f2dfb8bf2be321 Mon Sep 17 00:00:00 2001 From: "Paul E. McKenney" Date: Mon, 29 Nov 2010 21:56:39 -0800 Subject: rcu: merge TREE_PREEPT_RCU blocked_tasks[] lists Combine the current TREE_PREEMPT_RCU ->blocked_tasks[] lists in the rcu_node structure into a single ->blkd_tasks list with ->gp_tasks and ->exp_tasks tail pointers. This is in preparation for RCU priority boosting, which will add a third dimension to the combinatorial explosion in the ->blocked_tasks[] case, but simply a third pointer in the new ->blkd_tasks case. Also update documentation to reflect blocked_tasks[] merge Signed-off-by: Paul E. McKenney Signed-off-by: Paul E. McKenney Reviewed-by: Josh Triplett diff --git a/Documentation/RCU/trace.txt b/Documentation/RCU/trace.txt index e731ad2..5a704ff 100644 --- a/Documentation/RCU/trace.txt +++ b/Documentation/RCU/trace.txt @@ -166,14 +166,14 @@ o "gpnum" is the number of grace periods that have started. It is The output of "cat rcu/rcuhier" looks as follows, with very long lines: c=6902 g=6903 s=2 jfq=3 j=72c7 nfqs=13142/nfqsng=0(13142) fqlh=6 -1/1 .>. 0:127 ^0 -3/3 .>. 0:35 ^0 0/0 .>. 36:71 ^1 0/0 .>. 72:107 ^2 0/0 .>. 108:127 ^3 -3/3f .>. 0:5 ^0 2/3 .>. 6:11 ^1 0/0 .>. 12:17 ^2 0/0 .>. 18:23 ^3 0/0 .>. 24:29 ^4 0/0 .>. 30:35 ^5 0/0 .>. 36:41 ^0 0/0 .>. 42:47 ^1 0/0 .>. 48:53 ^2 0/0 .>. 54:59 ^3 0/0 .>. 60:65 ^4 0/0 .>. 66:71 ^5 0/0 .>. 72:77 ^0 0/0 .>. 78:83 ^1 0/0 .>. 84:89 ^2 0/0 .>. 90:95 ^3 0/0 .>. 96:101 ^4 0/0 .>. 102:107 ^5 0/0 .>. 108:113 ^0 0/0 .>. 114:119 ^1 0/0 .>. 120:125 ^2 0/0 .>. 126:127 ^3 +1/1 ..>. 0:127 ^0 +3/3 ..>. 0:35 ^0 0/0 ..>. 36:71 ^1 0/0 ..>. 72:107 ^2 0/0 ..>. 108:127 ^3 +3/3f ..>. 0:5 ^0 2/3 ..>. 6:11 ^1 0/0 ..>. 12:17 ^2 0/0 ..>. 18:23 ^3 0/0 ..>. 24:29 ^4 0/0 ..>. 30:35 ^5 0/0 ..>. 36:41 ^0 0/0 ..>. 42:47 ^1 0/0 ..>. 48:53 ^2 0/0 ..>. 54:59 ^3 0/0 ..>. 60:65 ^4 0/0 ..>. 66:71 ^5 0/0 ..>. 72:77 ^0 0/0 ..>. 78:83 ^1 0/0 ..>. 84:89 ^2 0/0 ..>. 90:95 ^3 0/0 ..>. 96:101 ^4 0/0 ..>. 102:107 ^5 0/0 ..>. 108:113 ^0 0/0 ..>. 114:119 ^1 0/0 ..>. 120:125 ^2 0/0 ..>. 126:127 ^3 rcu_bh: c=-226 g=-226 s=1 jfq=-5701 j=72c7 nfqs=88/nfqsng=0(88) fqlh=0 -0/1 .>. 0:127 ^0 -0/3 .>. 0:35 ^0 0/0 .>. 36:71 ^1 0/0 .>. 72:107 ^2 0/0 .>. 108:127 ^3 -0/3f .>. 0:5 ^0 0/3 .>. 6:11 ^1 0/0 .>. 12:17 ^2 0/0 .>. 18:23 ^3 0/0 .>. 24:29 ^4 0/0 .>. 30:35 ^5 0/0 .>. 36:41 ^0 0/0 .>. 42:47 ^1 0/0 .>. 48:53 ^2 0/0 .>. 54:59 ^3 0/0 .>. 60:65 ^4 0/0 .>. 66:71 ^5 0/0 .>. 72:77 ^0 0/0 .>. 78:83 ^1 0/0 .>. 84:89 ^2 0/0 .>. 90:95 ^3 0/0 .>. 96:101 ^4 0/0 .>. 102:107 ^5 0/0 .>. 108:113 ^0 0/0 .>. 114:119 ^1 0/0 .>. 120:125 ^2 0/0 .>. 126:127 ^3 +0/1 ..>. 0:127 ^0 +0/3 ..>. 0:35 ^0 0/0 ..>. 36:71 ^1 0/0 ..>. 72:107 ^2 0/0 ..>. 108:127 ^3 +0/3f ..>. 0:5 ^0 0/3 ..>. 6:11 ^1 0/0 ..>. 12:17 ^2 0/0 ..>. 18:23 ^3 0/0 ..>. 24:29 ^4 0/0 ..>. 30:35 ^5 0/0 ..>. 36:41 ^0 0/0 ..>. 42:47 ^1 0/0 ..>. 48:53 ^2 0/0 ..>. 54:59 ^3 0/0 ..>. 60:65 ^4 0/0 ..>. 66:71 ^5 0/0 ..>. 72:77 ^0 0/0 ..>. 78:83 ^1 0/0 ..>. 84:89 ^2 0/0 ..>. 90:95 ^3 0/0 ..>. 96:101 ^4 0/0 ..>. 102:107 ^5 0/0 ..>. 108:113 ^0 0/0 ..>. 114:119 ^1 0/0 ..>. 120:125 ^2 0/0 ..>. 126:127 ^3 This is once again split into "rcu_sched" and "rcu_bh" portions, and CONFIG_TREE_PREEMPT_RCU kernels will again have an additional @@ -232,13 +232,20 @@ o Each element of the form "1/1 0:127 ^0" represents one struct current grace period. o The characters separated by the ">" indicate the state - of the blocked-tasks lists. A "T" preceding the ">" + of the blocked-tasks lists. A "G" preceding the ">" indicates that at least one task blocked in an RCU read-side critical section blocks the current grace - period, while a "." preceding the ">" indicates otherwise. - The character following the ">" indicates similarly for - the next grace period. A "T" should appear in this - field only for rcu-preempt. + period, while a "E" preceding the ">" indicates that + at least one task blocked in an RCU read-side critical + section blocks the current expedited grace period. + A "T" character following the ">" indicates that at + least one task is blocked within an RCU read-side + critical section, regardless of whether any current + grace period (expedited or normal) is inconvenienced. + A "." character appears if the corresponding condition + does not hold, so that "..>." indicates that no tasks + are blocked. In contrast, "GE>T" indicates maximal + inconvenience from blocked tasks. o The numbers separated by the ":" are the range of CPUs served by this struct rcu_node. This can be helpful diff --git a/kernel/rcutree.c b/kernel/rcutree.c index 90104a1..0ac1cc0 100644 --- a/kernel/rcutree.c +++ b/kernel/rcutree.c @@ -1901,10 +1901,7 @@ static void __init rcu_init_one(struct rcu_state *rsp, j / rsp->levelspread[i - 1]; } rnp->level = i; - INIT_LIST_HEAD(&rnp->blocked_tasks[0]); - INIT_LIST_HEAD(&rnp->blocked_tasks[1]); - INIT_LIST_HEAD(&rnp->blocked_tasks[2]); - INIT_LIST_HEAD(&rnp->blocked_tasks[3]); + INIT_LIST_HEAD(&rnp->blkd_tasks); } } diff --git a/kernel/rcutree.h b/kernel/rcutree.h index bd891de..5a439c1 100644 --- a/kernel/rcutree.h +++ b/kernel/rcutree.h @@ -107,7 +107,7 @@ struct rcu_node { /* an rcu_data structure, otherwise, each */ /* bit corresponds to a child rcu_node */ /* structure. */ - unsigned long expmask; /* Groups that have ->blocked_tasks[] */ + unsigned long expmask; /* Groups that have ->blkd_tasks */ /* elements that need to drain to allow the */ /* current expedited grace period to */ /* complete (only for TREE_PREEMPT_RCU). */ @@ -120,11 +120,20 @@ struct rcu_node { u8 grpnum; /* CPU/group number for next level up. */ u8 level; /* root is at level 0. */ struct rcu_node *parent; - struct list_head blocked_tasks[4]; - /* Tasks blocked in RCU read-side critsect. */ - /* Grace period number (->gpnum) x blocked */ - /* by tasks on the (x & 0x1) element of the */ - /* blocked_tasks[] array. */ + struct list_head blkd_tasks; + /* Tasks blocked in RCU read-side critical */ + /* section. Tasks are placed at the head */ + /* of this list and age towards the tail. */ + struct list_head *gp_tasks; + /* Pointer to the first task blocking the */ + /* current grace period, or NULL if there */ + /* is no such task. */ + struct list_head *exp_tasks; + /* Pointer to the first task blocking the */ + /* current expedited grace period, or NULL */ + /* if there is no such task. If there */ + /* is no current expedited grace period, */ + /* then there can cannot be any such task. */ } ____cacheline_internodealigned_in_smp; /* diff --git a/kernel/rcutree_plugin.h b/kernel/rcutree_plugin.h index 764b5fc..774f010 100644 --- a/kernel/rcutree_plugin.h +++ b/kernel/rcutree_plugin.h @@ -130,12 +130,12 @@ static void rcu_preempt_qs(int cpu) * We have entered the scheduler, and the current task might soon be * context-switched away from. If this task is in an RCU read-side * critical section, we will no longer be able to rely on the CPU to - * record that fact, so we enqueue the task on the appropriate entry - * of the blocked_tasks[] array. The task will dequeue itself when - * it exits the outermost enclosing RCU read-side critical section. - * Therefore, the current grace period cannot be permitted to complete - * until the blocked_tasks[] entry indexed by the low-order bit of - * rnp->gpnum empties. + * record that fact, so we enqueue the task on the blkd_tasks list. + * The task will dequeue itself when it exits the outermost enclosing + * RCU read-side critical section. Therefore, the current grace period + * cannot be permitted to complete until the blkd_tasks list entries + * predating the current grace period drain, in other words, until + * rnp->gp_tasks becomes NULL. * * Caller must disable preemption. */ @@ -143,7 +143,6 @@ static void rcu_preempt_note_context_switch(int cpu) { struct task_struct *t = current; unsigned long flags; - int phase; struct rcu_data *rdp; struct rcu_node *rnp; @@ -165,15 +164,26 @@ static void rcu_preempt_note_context_switch(int cpu) * (i.e., this CPU has not yet passed through a quiescent * state for the current grace period), then as long * as that task remains queued, the current grace period - * cannot end. + * cannot end. Note that there is some uncertainty as + * to exactly when the current grace period started. + * We take a conservative approach, which can result + * in unnecessarily waiting on tasks that started very + * slightly after the current grace period began. C'est + * la vie!!! * * But first, note that the current CPU must still be * on line! */ WARN_ON_ONCE((rdp->grpmask & rnp->qsmaskinit) == 0); WARN_ON_ONCE(!list_empty(&t->rcu_node_entry)); - phase = (rnp->gpnum + !(rnp->qsmask & rdp->grpmask)) & 0x1; - list_add(&t->rcu_node_entry, &rnp->blocked_tasks[phase]); + if ((rnp->qsmask & rdp->grpmask) && rnp->gp_tasks != NULL) { + list_add(&t->rcu_node_entry, rnp->gp_tasks->prev); + rnp->gp_tasks = &t->rcu_node_entry; + } else { + list_add(&t->rcu_node_entry, &rnp->blkd_tasks); + if (rnp->qsmask & rdp->grpmask) + rnp->gp_tasks = &t->rcu_node_entry; + } raw_spin_unlock_irqrestore(&rnp->lock, flags); } @@ -210,10 +220,7 @@ EXPORT_SYMBOL_GPL(__rcu_read_lock); */ static int rcu_preempted_readers(struct rcu_node *rnp) { - int phase = rnp->gpnum & 0x1; - - return !list_empty(&rnp->blocked_tasks[phase]) || - !list_empty(&rnp->blocked_tasks[phase + 2]); + return rnp->gp_tasks != NULL; } /* @@ -253,6 +260,21 @@ static void rcu_report_unblock_qs_rnp(struct rcu_node *rnp, unsigned long flags) } /* + * Advance a ->blkd_tasks-list pointer to the next entry, instead + * returning NULL if at the end of the list. + */ +static struct list_head *rcu_next_node_entry(struct task_struct *t, + struct rcu_node *rnp) +{ + struct list_head *np; + + np = t->rcu_node_entry.next; + if (np == &rnp->blkd_tasks) + np = NULL; + return np; +} + +/* * Handle special cases during rcu_read_unlock(), such as needing to * notify RCU core processing or task having blocked during the RCU * read-side critical section. @@ -262,6 +284,7 @@ static void rcu_read_unlock_special(struct task_struct *t) int empty; int empty_exp; unsigned long flags; + struct list_head *np; struct rcu_node *rnp; int special; @@ -305,7 +328,12 @@ static void rcu_read_unlock_special(struct task_struct *t) empty = !rcu_preempted_readers(rnp); empty_exp = !rcu_preempted_readers_exp(rnp); smp_mb(); /* ensure expedited fastpath sees end of RCU c-s. */ + np = rcu_next_node_entry(t, rnp); list_del_init(&t->rcu_node_entry); + if (&t->rcu_node_entry == rnp->gp_tasks) + rnp->gp_tasks = np; + if (&t->rcu_node_entry == rnp->exp_tasks) + rnp->exp_tasks = np; t->rcu_blocked_node = NULL; /* @@ -361,18 +389,16 @@ EXPORT_SYMBOL_GPL(__rcu_read_unlock); static void rcu_print_detail_task_stall_rnp(struct rcu_node *rnp) { unsigned long flags; - struct list_head *lp; - int phase; struct task_struct *t; - if (rcu_preempted_readers(rnp)) { - raw_spin_lock_irqsave(&rnp->lock, flags); - phase = rnp->gpnum & 0x1; - lp = &rnp->blocked_tasks[phase]; - list_for_each_entry(t, lp, rcu_node_entry) - sched_show_task(t); - raw_spin_unlock_irqrestore(&rnp->lock, flags); - } + if (!rcu_preempted_readers(rnp)) + return; + raw_spin_lock_irqsave(&rnp->lock, flags); + t = list_entry(rnp->gp_tasks, + struct task_struct, rcu_node_entry); + list_for_each_entry_continue(t, &rnp->blkd_tasks, rcu_node_entry) + sched_show_task(t); + raw_spin_unlock_irqrestore(&rnp->lock, flags); } /* @@ -402,16 +428,14 @@ static void rcu_print_detail_task_stall(struct rcu_state *rsp) */ static void rcu_print_task_stall(struct rcu_node *rnp) { - struct list_head *lp; - int phase; struct task_struct *t; - if (rcu_preempted_readers(rnp)) { - phase = rnp->gpnum & 0x1; - lp = &rnp->blocked_tasks[phase]; - list_for_each_entry(t, lp, rcu_node_entry) - printk(" P%d", t->pid); - } + if (!rcu_preempted_readers(rnp)) + return; + t = list_entry(rnp->gp_tasks, + struct task_struct, rcu_node_entry); + list_for_each_entry_continue(t, &rnp->blkd_tasks, rcu_node_entry) + printk(" P%d", t->pid); } /* @@ -430,10 +454,15 @@ static void rcu_preempt_stall_reset(void) * period that still has RCU readers blocked! This function must be * invoked -before- updating this rnp's ->gpnum, and the rnp's ->lock * must be held by the caller. + * + * Also, if there are blocked tasks on the list, they automatically + * block the newly created grace period, so set up ->gp_tasks accordingly. */ static void rcu_preempt_check_blocked_tasks(struct rcu_node *rnp) { WARN_ON_ONCE(rcu_preempted_readers(rnp)); + if (!list_empty(&rnp->blkd_tasks)) + rnp->gp_tasks = rnp->blkd_tasks.next; WARN_ON_ONCE(rnp->qsmask); } @@ -457,45 +486,49 @@ static int rcu_preempt_offline_tasks(struct rcu_state *rsp, struct rcu_node *rnp, struct rcu_data *rdp) { - int i; struct list_head *lp; struct list_head *lp_root; int retval = 0; struct rcu_node *rnp_root = rcu_get_root(rsp); - struct task_struct *tp; + struct task_struct *t; if (rnp == rnp_root) { WARN_ONCE(1, "Last CPU thought to be offlined?"); return 0; /* Shouldn't happen: at least one CPU online. */ } - WARN_ON_ONCE(rnp != rdp->mynode && - (!list_empty(&rnp->blocked_tasks[0]) || - !list_empty(&rnp->blocked_tasks[1]) || - !list_empty(&rnp->blocked_tasks[2]) || - !list_empty(&rnp->blocked_tasks[3]))); + + /* If we are on an internal node, complain bitterly. */ + WARN_ON_ONCE(rnp != rdp->mynode); /* - * Move tasks up to root rcu_node. Rely on the fact that the - * root rcu_node can be at most one ahead of the rest of the - * rcu_nodes in terms of gp_num value. This fact allows us to - * move the blocked_tasks[] array directly, element by element. + * Move tasks up to root rcu_node. Don't try to get fancy for + * this corner-case operation -- just put this node's tasks + * at the head of the root node's list, and update the root node's + * ->gp_tasks and ->exp_tasks pointers to those of this node's, + * if non-NULL. This might result in waiting for more tasks than + * absolutely necessary, but this is a good performance/complexity + * tradeoff. */ if (rcu_preempted_readers(rnp)) retval |= RCU_OFL_TASKS_NORM_GP; if (rcu_preempted_readers_exp(rnp)) retval |= RCU_OFL_TASKS_EXP_GP; - for (i = 0; i < 4; i++) { - lp = &rnp->blocked_tasks[i]; - lp_root = &rnp_root->blocked_tasks[i]; - while (!list_empty(lp)) { - tp = list_entry(lp->next, typeof(*tp), rcu_node_entry); - raw_spin_lock(&rnp_root->lock); /* irqs already disabled */ - list_del(&tp->rcu_node_entry); - tp->rcu_blocked_node = rnp_root; - list_add(&tp->rcu_node_entry, lp_root); - raw_spin_unlock(&rnp_root->lock); /* irqs remain disabled */ - } + lp = &rnp->blkd_tasks; + lp_root = &rnp_root->blkd_tasks; + while (!list_empty(lp)) { + t = list_entry(lp->next, typeof(*t), rcu_node_entry); + raw_spin_lock(&rnp_root->lock); /* irqs already disabled */ + list_del(&t->rcu_node_entry); + t->rcu_blocked_node = rnp_root; + list_add(&t->rcu_node_entry, lp_root); + if (&t->rcu_node_entry == rnp->gp_tasks) + rnp_root->gp_tasks = rnp->gp_tasks; + if (&t->rcu_node_entry == rnp->exp_tasks) + rnp_root->exp_tasks = rnp->exp_tasks; + raw_spin_unlock(&rnp_root->lock); /* irqs still disabled */ } + rnp->gp_tasks = NULL; + rnp->exp_tasks = NULL; return retval; } @@ -586,8 +619,7 @@ static DEFINE_MUTEX(sync_rcu_preempt_exp_mutex); */ static int rcu_preempted_readers_exp(struct rcu_node *rnp) { - return !list_empty(&rnp->blocked_tasks[2]) || - !list_empty(&rnp->blocked_tasks[3]); + return rnp->exp_tasks != NULL; } /* @@ -647,12 +679,13 @@ static void rcu_report_exp_rnp(struct rcu_state *rsp, struct rcu_node *rnp) static void sync_rcu_preempt_exp_init(struct rcu_state *rsp, struct rcu_node *rnp) { - int must_wait; + int must_wait = 0; raw_spin_lock(&rnp->lock); /* irqs already disabled */ - list_splice_init(&rnp->blocked_tasks[0], &rnp->blocked_tasks[2]); - list_splice_init(&rnp->blocked_tasks[1], &rnp->blocked_tasks[3]); - must_wait = rcu_preempted_readers_exp(rnp); + if (!list_empty(&rnp->blkd_tasks)) { + rnp->exp_tasks = rnp->blkd_tasks.next; + must_wait = 1; + } raw_spin_unlock(&rnp->lock); /* irqs remain disabled */ if (!must_wait) rcu_report_exp_rnp(rsp, rnp); @@ -661,9 +694,7 @@ sync_rcu_preempt_exp_init(struct rcu_state *rsp, struct rcu_node *rnp) /* * Wait for an rcu-preempt grace period, but expedite it. The basic idea * is to invoke synchronize_sched_expedited() to push all the tasks to - * the ->blocked_tasks[] lists, move all entries from the first set of - * ->blocked_tasks[] lists to the second set, and finally wait for this - * second set to drain. + * the ->blkd_tasks lists and wait for this list to drain. */ void synchronize_rcu_expedited(void) { @@ -695,7 +726,7 @@ void synchronize_rcu_expedited(void) if ((ACCESS_ONCE(sync_rcu_preempt_exp_count) - snap) > 0) goto unlock_mb_ret; /* Others did our work for us. */ - /* force all RCU readers onto blocked_tasks[]. */ + /* force all RCU readers onto ->blkd_tasks lists. */ synchronize_sched_expedited(); raw_spin_lock_irqsave(&rsp->onofflock, flags); @@ -707,7 +738,7 @@ void synchronize_rcu_expedited(void) raw_spin_unlock(&rnp->lock); /* irqs remain disabled. */ } - /* Snapshot current state of ->blocked_tasks[] lists. */ + /* Snapshot current state of ->blkd_tasks lists. */ rcu_for_each_leaf_node(rsp, rnp) sync_rcu_preempt_exp_init(rsp, rnp); if (NUM_RCU_NODES > 1) @@ -715,7 +746,7 @@ void synchronize_rcu_expedited(void) raw_spin_unlock_irqrestore(&rsp->onofflock, flags); - /* Wait for snapshotted ->blocked_tasks[] lists to drain. */ + /* Wait for snapshotted ->blkd_tasks lists to drain. */ rnp = rcu_get_root(rsp); wait_event(sync_rcu_preempt_exp_wq, sync_rcu_preempt_exp_done(rnp)); diff --git a/kernel/rcutree_trace.c b/kernel/rcutree_trace.c index 4a21ca5..1cedf94 100644 --- a/kernel/rcutree_trace.c +++ b/kernel/rcutree_trace.c @@ -161,7 +161,6 @@ static void print_one_rcu_state(struct seq_file *m, struct rcu_state *rsp) { unsigned long gpnum; int level = 0; - int phase; struct rcu_node *rnp; gpnum = rsp->gpnum; @@ -178,13 +177,11 @@ static void print_one_rcu_state(struct seq_file *m, struct rcu_state *rsp) seq_puts(m, "\n"); level = rnp->level; } - phase = gpnum & 0x1; - seq_printf(m, "%lx/%lx %c%c>%c%c %d:%d ^%d ", + seq_printf(m, "%lx/%lx %c%c>%c %d:%d ^%d ", rnp->qsmask, rnp->qsmaskinit, - "T."[list_empty(&rnp->blocked_tasks[phase])], - "E."[list_empty(&rnp->blocked_tasks[phase + 2])], - "T."[list_empty(&rnp->blocked_tasks[!phase])], - "E."[list_empty(&rnp->blocked_tasks[!phase + 2])], + ".G"[rnp->gp_tasks != NULL], + ".E"[rnp->exp_tasks != NULL], + ".T"[!list_empty(&rnp->blkd_tasks)], rnp->grplo, rnp->grphi, rnp->grpnum); } seq_puts(m, "\n"); -- cgit v0.10.2 From a26ac2455ffcf3be5c6ef92bc6df7182700f2114 Mon Sep 17 00:00:00 2001 From: "Paul E. McKenney" Date: Wed, 12 Jan 2011 14:10:23 -0800 Subject: rcu: move TREE_RCU from softirq to kthread If RCU priority boosting is to be meaningful, callback invocation must be boosted in addition to preempted RCU readers. Otherwise, in presence of CPU real-time threads, the grace period ends, but the callbacks don't get invoked. If the callbacks don't get invoked, the associated memory doesn't get freed, so the system is still subject to OOM. But it is not reasonable to priority-boost RCU_SOFTIRQ, so this commit moves the callback invocations to a kthread, which can be boosted easily. Also add comments and properly synchronized all accesses to rcu_cpu_kthread_task, as suggested by Lai Jiangshan. Signed-off-by: Paul E. McKenney Signed-off-by: Paul E. McKenney Reviewed-by: Josh Triplett diff --git a/Documentation/filesystems/proc.txt b/Documentation/filesystems/proc.txt index b0b814d..60740e8 100644 --- a/Documentation/filesystems/proc.txt +++ b/Documentation/filesystems/proc.txt @@ -836,7 +836,6 @@ Provides counts of softirq handlers serviced since boot time, for each cpu. TASKLET: 0 0 0 290 SCHED: 27035 26983 26971 26746 HRTIMER: 0 0 0 0 - RCU: 1678 1769 2178 2250 1.3 IDE devices in /proc/ide diff --git a/include/linux/interrupt.h b/include/linux/interrupt.h index bea0ac7..6c12989 100644 --- a/include/linux/interrupt.h +++ b/include/linux/interrupt.h @@ -414,7 +414,6 @@ enum TASKLET_SOFTIRQ, SCHED_SOFTIRQ, HRTIMER_SOFTIRQ, - RCU_SOFTIRQ, /* Preferable RCU should always be the last softirq */ NR_SOFTIRQS }; diff --git a/include/trace/events/irq.h b/include/trace/events/irq.h index 1c09820..ae045ca 100644 --- a/include/trace/events/irq.h +++ b/include/trace/events/irq.h @@ -20,8 +20,7 @@ struct softirq_action; softirq_name(BLOCK_IOPOLL), \ softirq_name(TASKLET), \ softirq_name(SCHED), \ - softirq_name(HRTIMER), \ - softirq_name(RCU)) + softirq_name(HRTIMER)) /** * irq_handler_entry - called immediately before the irq action handler diff --git a/kernel/rcutree.c b/kernel/rcutree.c index 0ac1cc0..18e3331 100644 --- a/kernel/rcutree.c +++ b/kernel/rcutree.c @@ -47,6 +47,8 @@ #include #include #include +#include +#include #include "rcutree.h" @@ -83,6 +85,20 @@ int rcu_scheduler_active __read_mostly; EXPORT_SYMBOL_GPL(rcu_scheduler_active); /* + * Control variables for per-CPU and per-rcu_node kthreads. These + * handle all flavors of RCU. + */ +static DEFINE_PER_CPU(struct task_struct *, rcu_cpu_kthread_task); +static DEFINE_PER_CPU(wait_queue_head_t, rcu_cpu_wq); +static DEFINE_PER_CPU(char, rcu_cpu_has_work); +static char rcu_kthreads_spawnable; + +static void rcu_node_kthread_setaffinity(struct rcu_node *rnp); +static void invoke_rcu_kthread(void); + +#define RCU_KTHREAD_PRIO 1 /* RT priority for per-CPU kthreads. */ + +/* * Return true if an RCU grace period is in progress. The ACCESS_ONCE()s * permit this function to be invoked without holding the root rcu_node * structure's ->lock, but of course results can be subject to change. @@ -1009,6 +1025,8 @@ static void rcu_send_cbs_to_online(struct rcu_state *rsp) /* * Remove the outgoing CPU from the bitmasks in the rcu_node hierarchy * and move all callbacks from the outgoing CPU to the current one. + * There can only be one CPU hotplug operation at a time, so no other + * CPU can be attempting to update rcu_cpu_kthread_task. */ static void __rcu_offline_cpu(int cpu, struct rcu_state *rsp) { @@ -1017,6 +1035,14 @@ static void __rcu_offline_cpu(int cpu, struct rcu_state *rsp) int need_report = 0; struct rcu_data *rdp = per_cpu_ptr(rsp->rda, cpu); struct rcu_node *rnp; + struct task_struct *t; + + /* Stop the CPU's kthread. */ + t = per_cpu(rcu_cpu_kthread_task, cpu); + if (t != NULL) { + per_cpu(rcu_cpu_kthread_task, cpu) = NULL; + kthread_stop(t); + } /* Exclude any attempts to start a new grace period. */ raw_spin_lock_irqsave(&rsp->onofflock, flags); @@ -1054,6 +1080,19 @@ static void __rcu_offline_cpu(int cpu, struct rcu_state *rsp) raw_spin_unlock_irqrestore(&rnp->lock, flags); if (need_report & RCU_OFL_TASKS_EXP_GP) rcu_report_exp_rnp(rsp, rnp); + + /* + * If there are no more online CPUs for this rcu_node structure, + * kill the rcu_node structure's kthread. Otherwise, adjust its + * affinity. + */ + t = rnp->node_kthread_task; + if (t != NULL && + rnp->qsmaskinit == 0) { + kthread_stop(t); + rnp->node_kthread_task = NULL; + } else + rcu_node_kthread_setaffinity(rnp); } /* @@ -1151,7 +1190,7 @@ static void rcu_do_batch(struct rcu_state *rsp, struct rcu_data *rdp) /* Re-raise the RCU softirq if there are callbacks remaining. */ if (cpu_has_callbacks_ready_to_invoke(rdp)) - raise_softirq(RCU_SOFTIRQ); + invoke_rcu_kthread(); } /* @@ -1197,7 +1236,7 @@ void rcu_check_callbacks(int cpu, int user) } rcu_preempt_check_callbacks(cpu); if (rcu_pending(cpu)) - raise_softirq(RCU_SOFTIRQ); + invoke_rcu_kthread(); } #ifdef CONFIG_SMP @@ -1361,7 +1400,7 @@ __rcu_process_callbacks(struct rcu_state *rsp, struct rcu_data *rdp) /* * Do softirq processing for the current CPU. */ -static void rcu_process_callbacks(struct softirq_action *unused) +static void rcu_process_callbacks(void) { __rcu_process_callbacks(&rcu_sched_state, &__get_cpu_var(rcu_sched_data)); @@ -1372,6 +1411,281 @@ static void rcu_process_callbacks(struct softirq_action *unused) rcu_needs_cpu_flush(); } +/* + * Wake up the current CPU's kthread. This replaces raise_softirq() + * in earlier versions of RCU. Note that because we are running on + * the current CPU with interrupts disabled, the rcu_cpu_kthread_task + * cannot disappear out from under us. + */ +static void invoke_rcu_kthread(void) +{ + unsigned long flags; + wait_queue_head_t *q; + int cpu; + + local_irq_save(flags); + cpu = smp_processor_id(); + per_cpu(rcu_cpu_has_work, cpu) = 1; + if (per_cpu(rcu_cpu_kthread_task, cpu) == NULL) { + local_irq_restore(flags); + return; + } + q = &per_cpu(rcu_cpu_wq, cpu); + wake_up(q); + local_irq_restore(flags); +} + +/* + * Timer handler to initiate the waking up of per-CPU kthreads that + * have yielded the CPU due to excess numbers of RCU callbacks. + */ +static void rcu_cpu_kthread_timer(unsigned long arg) +{ + unsigned long flags; + struct rcu_data *rdp = (struct rcu_data *)arg; + struct rcu_node *rnp = rdp->mynode; + struct task_struct *t; + + raw_spin_lock_irqsave(&rnp->lock, flags); + rnp->wakemask |= rdp->grpmask; + t = rnp->node_kthread_task; + if (t == NULL) { + raw_spin_unlock_irqrestore(&rnp->lock, flags); + return; + } + wake_up_process(t); + raw_spin_unlock_irqrestore(&rnp->lock, flags); +} + +/* + * Drop to non-real-time priority and yield, but only after posting a + * timer that will cause us to regain our real-time priority if we + * remain preempted. Either way, we restore our real-time priority + * before returning. + */ +static void rcu_yield(int cpu) +{ + struct rcu_data *rdp = per_cpu_ptr(rcu_sched_state.rda, cpu); + struct sched_param sp; + struct timer_list yield_timer; + + setup_timer_on_stack(&yield_timer, rcu_cpu_kthread_timer, (unsigned long)rdp); + mod_timer(&yield_timer, jiffies + 2); + sp.sched_priority = 0; + sched_setscheduler_nocheck(current, SCHED_NORMAL, &sp); + schedule(); + sp.sched_priority = RCU_KTHREAD_PRIO; + sched_setscheduler_nocheck(current, SCHED_FIFO, &sp); + del_timer(&yield_timer); +} + +/* + * Handle cases where the rcu_cpu_kthread() ends up on the wrong CPU. + * This can happen while the corresponding CPU is either coming online + * or going offline. We cannot wait until the CPU is fully online + * before starting the kthread, because the various notifier functions + * can wait for RCU grace periods. So we park rcu_cpu_kthread() until + * the corresponding CPU is online. + * + * Return 1 if the kthread needs to stop, 0 otherwise. + * + * Caller must disable bh. This function can momentarily enable it. + */ +static int rcu_cpu_kthread_should_stop(int cpu) +{ + while (cpu_is_offline(cpu) || + !cpumask_equal(¤t->cpus_allowed, cpumask_of(cpu)) || + smp_processor_id() != cpu) { + if (kthread_should_stop()) + return 1; + local_bh_enable(); + schedule_timeout_uninterruptible(1); + if (!cpumask_equal(¤t->cpus_allowed, cpumask_of(cpu))) + set_cpus_allowed_ptr(current, cpumask_of(cpu)); + local_bh_disable(); + } + return 0; +} + +/* + * Per-CPU kernel thread that invokes RCU callbacks. This replaces the + * earlier RCU softirq. + */ +static int rcu_cpu_kthread(void *arg) +{ + int cpu = (int)(long)arg; + unsigned long flags; + int spincnt = 0; + wait_queue_head_t *wqp = &per_cpu(rcu_cpu_wq, cpu); + char work; + char *workp = &per_cpu(rcu_cpu_has_work, cpu); + + for (;;) { + wait_event_interruptible(*wqp, + *workp != 0 || kthread_should_stop()); + local_bh_disable(); + if (rcu_cpu_kthread_should_stop(cpu)) { + local_bh_enable(); + break; + } + local_irq_save(flags); + work = *workp; + *workp = 0; + local_irq_restore(flags); + if (work) + rcu_process_callbacks(); + local_bh_enable(); + if (*workp != 0) + spincnt++; + else + spincnt = 0; + if (spincnt > 10) { + rcu_yield(cpu); + spincnt = 0; + } + } + return 0; +} + +/* + * Spawn a per-CPU kthread, setting up affinity and priority. + * Because the CPU hotplug lock is held, no other CPU will be attempting + * to manipulate rcu_cpu_kthread_task. There might be another CPU + * attempting to access it during boot, but the locking in kthread_bind() + * will enforce sufficient ordering. + */ +static int __cpuinit rcu_spawn_one_cpu_kthread(int cpu) +{ + struct sched_param sp; + struct task_struct *t; + + if (!rcu_kthreads_spawnable || + per_cpu(rcu_cpu_kthread_task, cpu) != NULL) + return 0; + t = kthread_create(rcu_cpu_kthread, (void *)(long)cpu, "rcuc%d", cpu); + if (IS_ERR(t)) + return PTR_ERR(t); + kthread_bind(t, cpu); + WARN_ON_ONCE(per_cpu(rcu_cpu_kthread_task, cpu) != NULL); + per_cpu(rcu_cpu_kthread_task, cpu) = t; + wake_up_process(t); + sp.sched_priority = RCU_KTHREAD_PRIO; + sched_setscheduler_nocheck(t, SCHED_FIFO, &sp); + return 0; +} + +/* + * Per-rcu_node kthread, which is in charge of waking up the per-CPU + * kthreads when needed. We ignore requests to wake up kthreads + * for offline CPUs, which is OK because force_quiescent_state() + * takes care of this case. + */ +static int rcu_node_kthread(void *arg) +{ + int cpu; + unsigned long flags; + unsigned long mask; + struct rcu_node *rnp = (struct rcu_node *)arg; + struct sched_param sp; + struct task_struct *t; + + for (;;) { + wait_event_interruptible(rnp->node_wq, rnp->wakemask != 0 || + kthread_should_stop()); + if (kthread_should_stop()) + break; + raw_spin_lock_irqsave(&rnp->lock, flags); + mask = rnp->wakemask; + rnp->wakemask = 0; + raw_spin_unlock_irqrestore(&rnp->lock, flags); + for (cpu = rnp->grplo; cpu <= rnp->grphi; cpu++, mask >>= 1) { + if ((mask & 0x1) == 0) + continue; + preempt_disable(); + t = per_cpu(rcu_cpu_kthread_task, cpu); + if (!cpu_online(cpu) || t == NULL) { + preempt_enable(); + continue; + } + per_cpu(rcu_cpu_has_work, cpu) = 1; + sp.sched_priority = RCU_KTHREAD_PRIO; + sched_setscheduler_nocheck(t, SCHED_FIFO, &sp); + preempt_enable(); + } + } + return 0; +} + +/* + * Set the per-rcu_node kthread's affinity to cover all CPUs that are + * served by the rcu_node in question. + */ +static void rcu_node_kthread_setaffinity(struct rcu_node *rnp) +{ + cpumask_var_t cm; + int cpu; + unsigned long mask = rnp->qsmaskinit; + + if (rnp->node_kthread_task == NULL || + rnp->qsmaskinit == 0) + return; + if (!alloc_cpumask_var(&cm, GFP_KERNEL)) + return; + cpumask_clear(cm); + for (cpu = rnp->grplo; cpu <= rnp->grphi; cpu++, mask >>= 1) + if (mask & 0x1) + cpumask_set_cpu(cpu, cm); + set_cpus_allowed_ptr(rnp->node_kthread_task, cm); + free_cpumask_var(cm); +} + +/* + * Spawn a per-rcu_node kthread, setting priority and affinity. + */ +static int __cpuinit rcu_spawn_one_node_kthread(struct rcu_state *rsp, + struct rcu_node *rnp) +{ + int rnp_index = rnp - &rsp->node[0]; + struct sched_param sp; + struct task_struct *t; + + if (!rcu_kthreads_spawnable || + rnp->qsmaskinit == 0 || + rnp->node_kthread_task != NULL) + return 0; + t = kthread_create(rcu_node_kthread, (void *)rnp, "rcun%d", rnp_index); + if (IS_ERR(t)) + return PTR_ERR(t); + rnp->node_kthread_task = t; + wake_up_process(t); + sp.sched_priority = 99; + sched_setscheduler_nocheck(t, SCHED_FIFO, &sp); + return 0; +} + +/* + * Spawn all kthreads -- called as soon as the scheduler is running. + */ +static int __init rcu_spawn_kthreads(void) +{ + int cpu; + struct rcu_node *rnp; + + rcu_kthreads_spawnable = 1; + for_each_possible_cpu(cpu) { + init_waitqueue_head(&per_cpu(rcu_cpu_wq, cpu)); + per_cpu(rcu_cpu_has_work, cpu) = 0; + if (cpu_online(cpu)) + (void)rcu_spawn_one_cpu_kthread(cpu); + } + rcu_for_each_leaf_node(&rcu_sched_state, rnp) { + init_waitqueue_head(&rnp->node_wq); + (void)rcu_spawn_one_node_kthread(&rcu_sched_state, rnp); + } + return 0; +} +early_initcall(rcu_spawn_kthreads); + static void __call_rcu(struct rcu_head *head, void (*func)(struct rcu_head *rcu), struct rcu_state *rsp) @@ -1771,6 +2085,19 @@ static void __cpuinit rcu_online_cpu(int cpu) rcu_preempt_init_percpu_data(cpu); } +static void __cpuinit rcu_online_kthreads(int cpu) +{ + struct rcu_data *rdp = per_cpu_ptr(rcu_sched_state.rda, cpu); + struct rcu_node *rnp = rdp->mynode; + + /* Fire up the incoming CPU's kthread and leaf rcu_node kthread. */ + if (rcu_kthreads_spawnable) { + (void)rcu_spawn_one_cpu_kthread(cpu); + if (rnp->node_kthread_task == NULL) + (void)rcu_spawn_one_node_kthread(&rcu_sched_state, rnp); + } +} + /* * Handle CPU online/offline notification events. */ @@ -1778,11 +2105,17 @@ static int __cpuinit rcu_cpu_notify(struct notifier_block *self, unsigned long action, void *hcpu) { long cpu = (long)hcpu; + struct rcu_data *rdp = per_cpu_ptr(rcu_sched_state.rda, cpu); + struct rcu_node *rnp = rdp->mynode; switch (action) { case CPU_UP_PREPARE: case CPU_UP_PREPARE_FROZEN: rcu_online_cpu(cpu); + rcu_online_kthreads(cpu); + break; + case CPU_ONLINE: + rcu_node_kthread_setaffinity(rnp); break; case CPU_DYING: case CPU_DYING_FROZEN: @@ -1923,7 +2256,6 @@ void __init rcu_init(void) rcu_init_one(&rcu_sched_state, &rcu_sched_data); rcu_init_one(&rcu_bh_state, &rcu_bh_data); __rcu_init_preempt(); - open_softirq(RCU_SOFTIRQ, rcu_process_callbacks); /* * We don't need protection against CPU-hotplug here because diff --git a/kernel/rcutree.h b/kernel/rcutree.h index 5a439c1..c021380 100644 --- a/kernel/rcutree.h +++ b/kernel/rcutree.h @@ -111,6 +111,7 @@ struct rcu_node { /* elements that need to drain to allow the */ /* current expedited grace period to */ /* complete (only for TREE_PREEMPT_RCU). */ + unsigned long wakemask; /* CPUs whose kthread needs to be awakened. */ unsigned long qsmaskinit; /* Per-GP initial value for qsmask & expmask. */ unsigned long grpmask; /* Mask to apply to parent qsmask. */ @@ -134,6 +135,13 @@ struct rcu_node { /* if there is no such task. If there */ /* is no current expedited grace period, */ /* then there can cannot be any such task. */ + struct task_struct *node_kthread_task; + /* kthread that takes care of this rcu_node */ + /* structure, for example, awakening the */ + /* per-CPU kthreads as needed. */ + wait_queue_head_t node_wq; + /* Wait queue on which to park the per-node */ + /* kthread. */ } ____cacheline_internodealigned_in_smp; /* diff --git a/kernel/rcutree_plugin.h b/kernel/rcutree_plugin.h index 774f010..b9bd69a 100644 --- a/kernel/rcutree_plugin.h +++ b/kernel/rcutree_plugin.h @@ -1206,7 +1206,7 @@ static DEFINE_PER_CPU(unsigned long, rcu_dyntick_holdoff); * * Because it is not legal to invoke rcu_process_callbacks() with irqs * disabled, we do one pass of force_quiescent_state(), then do a - * raise_softirq() to cause rcu_process_callbacks() to be invoked later. + * invoke_rcu_kthread() to cause rcu_process_callbacks() to be invoked later. * The per-cpu rcu_dyntick_drain variable controls the sequencing. */ int rcu_needs_cpu(int cpu) @@ -1257,7 +1257,7 @@ int rcu_needs_cpu(int cpu) /* If RCU callbacks are still pending, RCU still needs this CPU. */ if (c) - raise_softirq(RCU_SOFTIRQ); + invoke_rcu_kthread(); return c; } diff --git a/kernel/softirq.c b/kernel/softirq.c index 174f976..1396017 100644 --- a/kernel/softirq.c +++ b/kernel/softirq.c @@ -58,7 +58,7 @@ DEFINE_PER_CPU(struct task_struct *, ksoftirqd); char *softirq_to_name[NR_SOFTIRQS] = { "HI", "TIMER", "NET_TX", "NET_RX", "BLOCK", "BLOCK_IOPOLL", - "TASKLET", "SCHED", "HRTIMER", "RCU" + "TASKLET", "SCHED", "HRTIMER" }; /* diff --git a/tools/perf/util/trace-event-parse.c b/tools/perf/util/trace-event-parse.c index 0a7ed5b..1e88485 100644 --- a/tools/perf/util/trace-event-parse.c +++ b/tools/perf/util/trace-event-parse.c @@ -2187,7 +2187,6 @@ static const struct flag flags[] = { { "TASKLET_SOFTIRQ", 6 }, { "SCHED_SOFTIRQ", 7 }, { "HRTIMER_SOFTIRQ", 8 }, - { "RCU_SOFTIRQ", 9 }, { "HRTIMER_NORESTART", 0 }, { "HRTIMER_RESTART", 1 }, -- cgit v0.10.2 From 27f4d28057adf98750cf863c40baefb12f5b6d21 Mon Sep 17 00:00:00 2001 From: "Paul E. McKenney" Date: Mon, 7 Feb 2011 12:47:15 -0800 Subject: rcu: priority boosting for TREE_PREEMPT_RCU Add priority boosting for TREE_PREEMPT_RCU, similar to that for TINY_PREEMPT_RCU. This is enabled by the default-off RCU_BOOST kernel parameter. The priority to which to boost preempted RCU readers is controlled by the RCU_BOOST_PRIO kernel parameter (defaulting to real-time priority 1) and the time to wait before boosting the readers who are blocking a given grace period is controlled by the RCU_BOOST_DELAY kernel parameter (defaulting to 500 milliseconds). Signed-off-by: Paul E. McKenney Signed-off-by: Paul E. McKenney Reviewed-by: Josh Triplett diff --git a/init/Kconfig b/init/Kconfig index d886b1e..2d964fa 100644 --- a/init/Kconfig +++ b/init/Kconfig @@ -485,7 +485,7 @@ config TREE_RCU_TRACE config RCU_BOOST bool "Enable RCU priority boosting" - depends on RT_MUTEXES && TINY_PREEMPT_RCU + depends on RT_MUTEXES && PREEMPT_RCU default n help This option boosts the priority of preempted RCU readers that diff --git a/kernel/rcutree.c b/kernel/rcutree.c index 18e3331..28fd92a 100644 --- a/kernel/rcutree.c +++ b/kernel/rcutree.c @@ -81,6 +81,8 @@ DEFINE_PER_CPU(struct rcu_data, rcu_sched_data); struct rcu_state rcu_bh_state = RCU_STATE_INITIALIZER(rcu_bh_state); DEFINE_PER_CPU(struct rcu_data, rcu_bh_data); +static struct rcu_state *rcu_state; + int rcu_scheduler_active __read_mostly; EXPORT_SYMBOL_GPL(rcu_scheduler_active); @@ -94,7 +96,7 @@ static DEFINE_PER_CPU(char, rcu_cpu_has_work); static char rcu_kthreads_spawnable; static void rcu_node_kthread_setaffinity(struct rcu_node *rnp); -static void invoke_rcu_kthread(void); +static void invoke_rcu_cpu_kthread(void); #define RCU_KTHREAD_PRIO 1 /* RT priority for per-CPU kthreads. */ @@ -791,6 +793,7 @@ rcu_start_gp(struct rcu_state *rsp, unsigned long flags) rnp->completed = rsp->completed; rsp->signaled = RCU_SIGNAL_INIT; /* force_quiescent_state OK. */ rcu_start_gp_per_cpu(rsp, rnp, rdp); + rcu_preempt_boost_start_gp(rnp); raw_spin_unlock_irqrestore(&rnp->lock, flags); return; } @@ -826,6 +829,7 @@ rcu_start_gp(struct rcu_state *rsp, unsigned long flags) rnp->completed = rsp->completed; if (rnp == rdp->mynode) rcu_start_gp_per_cpu(rsp, rnp, rdp); + rcu_preempt_boost_start_gp(rnp); raw_spin_unlock(&rnp->lock); /* irqs remain disabled. */ } @@ -882,7 +886,7 @@ rcu_report_qs_rnp(unsigned long mask, struct rcu_state *rsp, return; } rnp->qsmask &= ~mask; - if (rnp->qsmask != 0 || rcu_preempted_readers(rnp)) { + if (rnp->qsmask != 0 || rcu_preempt_blocked_readers_cgp(rnp)) { /* Other bits still set at this level, so done. */ raw_spin_unlock_irqrestore(&rnp->lock, flags); @@ -1089,8 +1093,11 @@ static void __rcu_offline_cpu(int cpu, struct rcu_state *rsp) t = rnp->node_kthread_task; if (t != NULL && rnp->qsmaskinit == 0) { - kthread_stop(t); + raw_spin_lock_irqsave(&rnp->lock, flags); rnp->node_kthread_task = NULL; + raw_spin_unlock_irqrestore(&rnp->lock, flags); + kthread_stop(t); + rcu_stop_boost_kthread(rnp); } else rcu_node_kthread_setaffinity(rnp); } @@ -1190,7 +1197,7 @@ static void rcu_do_batch(struct rcu_state *rsp, struct rcu_data *rdp) /* Re-raise the RCU softirq if there are callbacks remaining. */ if (cpu_has_callbacks_ready_to_invoke(rdp)) - invoke_rcu_kthread(); + invoke_rcu_cpu_kthread(); } /* @@ -1236,7 +1243,7 @@ void rcu_check_callbacks(int cpu, int user) } rcu_preempt_check_callbacks(cpu); if (rcu_pending(cpu)) - invoke_rcu_kthread(); + invoke_rcu_cpu_kthread(); } #ifdef CONFIG_SMP @@ -1244,6 +1251,8 @@ void rcu_check_callbacks(int cpu, int user) /* * Scan the leaf rcu_node structures, processing dyntick state for any that * have not yet encountered a quiescent state, using the function specified. + * Also initiate boosting for any threads blocked on the root rcu_node. + * * The caller must have suppressed start of new grace periods. */ static void force_qs_rnp(struct rcu_state *rsp, int (*f)(struct rcu_data *)) @@ -1262,6 +1271,7 @@ static void force_qs_rnp(struct rcu_state *rsp, int (*f)(struct rcu_data *)) return; } if (rnp->qsmask == 0) { + rcu_initiate_boost(rnp); raw_spin_unlock_irqrestore(&rnp->lock, flags); continue; } @@ -1280,6 +1290,11 @@ static void force_qs_rnp(struct rcu_state *rsp, int (*f)(struct rcu_data *)) } raw_spin_unlock_irqrestore(&rnp->lock, flags); } + rnp = rcu_get_root(rsp); + raw_spin_lock_irqsave(&rnp->lock, flags); + if (rnp->qsmask == 0) + rcu_initiate_boost(rnp); + raw_spin_unlock_irqrestore(&rnp->lock, flags); } /* @@ -1417,7 +1432,7 @@ static void rcu_process_callbacks(void) * the current CPU with interrupts disabled, the rcu_cpu_kthread_task * cannot disappear out from under us. */ -static void invoke_rcu_kthread(void) +static void invoke_rcu_cpu_kthread(void) { unsigned long flags; wait_queue_head_t *q; @@ -1436,24 +1451,33 @@ static void invoke_rcu_kthread(void) } /* + * Wake up the specified per-rcu_node-structure kthread. + * The caller must hold ->lock. + */ +static void invoke_rcu_node_kthread(struct rcu_node *rnp) +{ + struct task_struct *t; + + t = rnp->node_kthread_task; + if (t != NULL) + wake_up_process(t); +} + +/* * Timer handler to initiate the waking up of per-CPU kthreads that * have yielded the CPU due to excess numbers of RCU callbacks. + * We wake up the per-rcu_node kthread, which in turn will wake up + * the booster kthread. */ static void rcu_cpu_kthread_timer(unsigned long arg) { unsigned long flags; - struct rcu_data *rdp = (struct rcu_data *)arg; + struct rcu_data *rdp = per_cpu_ptr(rcu_state->rda, arg); struct rcu_node *rnp = rdp->mynode; - struct task_struct *t; raw_spin_lock_irqsave(&rnp->lock, flags); rnp->wakemask |= rdp->grpmask; - t = rnp->node_kthread_task; - if (t == NULL) { - raw_spin_unlock_irqrestore(&rnp->lock, flags); - return; - } - wake_up_process(t); + invoke_rcu_node_kthread(rnp); raw_spin_unlock_irqrestore(&rnp->lock, flags); } @@ -1463,13 +1487,12 @@ static void rcu_cpu_kthread_timer(unsigned long arg) * remain preempted. Either way, we restore our real-time priority * before returning. */ -static void rcu_yield(int cpu) +static void rcu_yield(void (*f)(unsigned long), unsigned long arg) { - struct rcu_data *rdp = per_cpu_ptr(rcu_sched_state.rda, cpu); struct sched_param sp; struct timer_list yield_timer; - setup_timer_on_stack(&yield_timer, rcu_cpu_kthread_timer, (unsigned long)rdp); + setup_timer_on_stack(&yield_timer, f, arg); mod_timer(&yield_timer, jiffies + 2); sp.sched_priority = 0; sched_setscheduler_nocheck(current, SCHED_NORMAL, &sp); @@ -1540,7 +1563,7 @@ static int rcu_cpu_kthread(void *arg) else spincnt = 0; if (spincnt > 10) { - rcu_yield(cpu); + rcu_yield(rcu_cpu_kthread_timer, (unsigned long)cpu); spincnt = 0; } } @@ -1597,6 +1620,7 @@ static int rcu_node_kthread(void *arg) raw_spin_lock_irqsave(&rnp->lock, flags); mask = rnp->wakemask; rnp->wakemask = 0; + rcu_initiate_boost(rnp); raw_spin_unlock_irqrestore(&rnp->lock, flags); for (cpu = rnp->grplo; cpu <= rnp->grphi; cpu++, mask >>= 1) { if ((mask & 0x1) == 0) @@ -1618,7 +1642,8 @@ static int rcu_node_kthread(void *arg) /* * Set the per-rcu_node kthread's affinity to cover all CPUs that are - * served by the rcu_node in question. + * served by the rcu_node in question. The CPU hotplug lock is still + * held, so the value of rnp->qsmaskinit will be stable. */ static void rcu_node_kthread_setaffinity(struct rcu_node *rnp) { @@ -1626,8 +1651,7 @@ static void rcu_node_kthread_setaffinity(struct rcu_node *rnp) int cpu; unsigned long mask = rnp->qsmaskinit; - if (rnp->node_kthread_task == NULL || - rnp->qsmaskinit == 0) + if (rnp->node_kthread_task == NULL || mask == 0) return; if (!alloc_cpumask_var(&cm, GFP_KERNEL)) return; @@ -1636,31 +1660,40 @@ static void rcu_node_kthread_setaffinity(struct rcu_node *rnp) if (mask & 0x1) cpumask_set_cpu(cpu, cm); set_cpus_allowed_ptr(rnp->node_kthread_task, cm); + rcu_boost_kthread_setaffinity(rnp, cm); free_cpumask_var(cm); } /* * Spawn a per-rcu_node kthread, setting priority and affinity. + * Called during boot before online/offline can happen, or, if + * during runtime, with the main CPU-hotplug locks held. So only + * one of these can be executing at a time. */ static int __cpuinit rcu_spawn_one_node_kthread(struct rcu_state *rsp, struct rcu_node *rnp) { + unsigned long flags; int rnp_index = rnp - &rsp->node[0]; struct sched_param sp; struct task_struct *t; if (!rcu_kthreads_spawnable || - rnp->qsmaskinit == 0 || - rnp->node_kthread_task != NULL) + rnp->qsmaskinit == 0) return 0; - t = kthread_create(rcu_node_kthread, (void *)rnp, "rcun%d", rnp_index); - if (IS_ERR(t)) - return PTR_ERR(t); - rnp->node_kthread_task = t; - wake_up_process(t); - sp.sched_priority = 99; - sched_setscheduler_nocheck(t, SCHED_FIFO, &sp); - return 0; + if (rnp->node_kthread_task == NULL) { + t = kthread_create(rcu_node_kthread, (void *)rnp, + "rcun%d", rnp_index); + if (IS_ERR(t)) + return PTR_ERR(t); + raw_spin_lock_irqsave(&rnp->lock, flags); + rnp->node_kthread_task = t; + raw_spin_unlock_irqrestore(&rnp->lock, flags); + wake_up_process(t); + sp.sched_priority = 99; + sched_setscheduler_nocheck(t, SCHED_FIFO, &sp); + } + return rcu_spawn_one_boost_kthread(rsp, rnp, rnp_index); } /* @@ -1678,10 +1711,16 @@ static int __init rcu_spawn_kthreads(void) if (cpu_online(cpu)) (void)rcu_spawn_one_cpu_kthread(cpu); } - rcu_for_each_leaf_node(&rcu_sched_state, rnp) { - init_waitqueue_head(&rnp->node_wq); - (void)rcu_spawn_one_node_kthread(&rcu_sched_state, rnp); - } + rnp = rcu_get_root(rcu_state); + init_waitqueue_head(&rnp->node_wq); + rcu_init_boost_waitqueue(rnp); + (void)rcu_spawn_one_node_kthread(rcu_state, rnp); + if (NUM_RCU_NODES > 1) + rcu_for_each_leaf_node(rcu_state, rnp) { + init_waitqueue_head(&rnp->node_wq); + rcu_init_boost_waitqueue(rnp); + (void)rcu_spawn_one_node_kthread(rcu_state, rnp); + } return 0; } early_initcall(rcu_spawn_kthreads); @@ -2087,14 +2126,14 @@ static void __cpuinit rcu_online_cpu(int cpu) static void __cpuinit rcu_online_kthreads(int cpu) { - struct rcu_data *rdp = per_cpu_ptr(rcu_sched_state.rda, cpu); + struct rcu_data *rdp = per_cpu_ptr(rcu_state->rda, cpu); struct rcu_node *rnp = rdp->mynode; /* Fire up the incoming CPU's kthread and leaf rcu_node kthread. */ if (rcu_kthreads_spawnable) { (void)rcu_spawn_one_cpu_kthread(cpu); if (rnp->node_kthread_task == NULL) - (void)rcu_spawn_one_node_kthread(&rcu_sched_state, rnp); + (void)rcu_spawn_one_node_kthread(rcu_state, rnp); } } @@ -2105,7 +2144,7 @@ static int __cpuinit rcu_cpu_notify(struct notifier_block *self, unsigned long action, void *hcpu) { long cpu = (long)hcpu; - struct rcu_data *rdp = per_cpu_ptr(rcu_sched_state.rda, cpu); + struct rcu_data *rdp = per_cpu_ptr(rcu_state->rda, cpu); struct rcu_node *rnp = rdp->mynode; switch (action) { diff --git a/kernel/rcutree.h b/kernel/rcutree.h index c021380..8db0cdc 100644 --- a/kernel/rcutree.h +++ b/kernel/rcutree.h @@ -135,6 +135,24 @@ struct rcu_node { /* if there is no such task. If there */ /* is no current expedited grace period, */ /* then there can cannot be any such task. */ +#ifdef CONFIG_RCU_BOOST + struct list_head *boost_tasks; + /* Pointer to first task that needs to be */ + /* priority boosted, or NULL if no priority */ + /* boosting is needed for this rcu_node */ + /* structure. If there are no tasks */ + /* queued on this rcu_node structure that */ + /* are blocking the current grace period, */ + /* there can be no such task. */ + unsigned long boost_time; + /* When to start boosting (jiffies). */ + struct task_struct *boost_kthread_task; + /* kthread that takes care of priority */ + /* boosting for this rcu_node structure. */ + wait_queue_head_t boost_wq; + /* Wait queue on which to park the boost */ + /* kthread. */ +#endif /* #ifdef CONFIG_RCU_BOOST */ struct task_struct *node_kthread_task; /* kthread that takes care of this rcu_node */ /* structure, for example, awakening the */ @@ -365,7 +383,7 @@ DECLARE_PER_CPU(struct rcu_data, rcu_preempt_data); static void rcu_bootup_announce(void); long rcu_batches_completed(void); static void rcu_preempt_note_context_switch(int cpu); -static int rcu_preempted_readers(struct rcu_node *rnp); +static int rcu_preempt_blocked_readers_cgp(struct rcu_node *rnp); #ifdef CONFIG_HOTPLUG_CPU static void rcu_report_unblock_qs_rnp(struct rcu_node *rnp, unsigned long flags); @@ -392,5 +410,16 @@ static void __cpuinit rcu_preempt_init_percpu_data(int cpu); static void rcu_preempt_send_cbs_to_online(void); static void __init __rcu_init_preempt(void); static void rcu_needs_cpu_flush(void); +static void __init rcu_init_boost_waitqueue(struct rcu_node *rnp); +static void rcu_initiate_boost(struct rcu_node *rnp); +static void rcu_boost_kthread_setaffinity(struct rcu_node *rnp, + cpumask_var_t cm); +static void rcu_preempt_boost_start_gp(struct rcu_node *rnp); +static int __cpuinit rcu_spawn_one_boost_kthread(struct rcu_state *rsp, + struct rcu_node *rnp, + int rnp_index); +#ifdef CONFIG_HOTPLUG_CPU +static void rcu_stop_boost_kthread(struct rcu_node *rnp); +#endif /* #ifdef CONFIG_HOTPLUG_CPU */ #endif /* #ifndef RCU_TREE_NONCORE */ diff --git a/kernel/rcutree_plugin.h b/kernel/rcutree_plugin.h index b9bd69a..5964f82 100644 --- a/kernel/rcutree_plugin.h +++ b/kernel/rcutree_plugin.h @@ -66,6 +66,7 @@ static void __init rcu_bootup_announce_oddness(void) struct rcu_state rcu_preempt_state = RCU_STATE_INITIALIZER(rcu_preempt_state); DEFINE_PER_CPU(struct rcu_data, rcu_preempt_data); +static struct rcu_state *rcu_state = &rcu_preempt_state; static int rcu_preempted_readers_exp(struct rcu_node *rnp); @@ -179,6 +180,10 @@ static void rcu_preempt_note_context_switch(int cpu) if ((rnp->qsmask & rdp->grpmask) && rnp->gp_tasks != NULL) { list_add(&t->rcu_node_entry, rnp->gp_tasks->prev); rnp->gp_tasks = &t->rcu_node_entry; +#ifdef CONFIG_RCU_BOOST + if (rnp->boost_tasks != NULL) + rnp->boost_tasks = rnp->gp_tasks; +#endif /* #ifdef CONFIG_RCU_BOOST */ } else { list_add(&t->rcu_node_entry, &rnp->blkd_tasks); if (rnp->qsmask & rdp->grpmask) @@ -218,7 +223,7 @@ EXPORT_SYMBOL_GPL(__rcu_read_lock); * for the specified rcu_node structure. If the caller needs a reliable * answer, it must hold the rcu_node's ->lock. */ -static int rcu_preempted_readers(struct rcu_node *rnp) +static int rcu_preempt_blocked_readers_cgp(struct rcu_node *rnp) { return rnp->gp_tasks != NULL; } @@ -236,7 +241,7 @@ static void rcu_report_unblock_qs_rnp(struct rcu_node *rnp, unsigned long flags) unsigned long mask; struct rcu_node *rnp_p; - if (rnp->qsmask != 0 || rcu_preempted_readers(rnp)) { + if (rnp->qsmask != 0 || rcu_preempt_blocked_readers_cgp(rnp)) { raw_spin_unlock_irqrestore(&rnp->lock, flags); return; /* Still need more quiescent states! */ } @@ -325,7 +330,7 @@ static void rcu_read_unlock_special(struct task_struct *t) break; raw_spin_unlock(&rnp->lock); /* irqs remain disabled. */ } - empty = !rcu_preempted_readers(rnp); + empty = !rcu_preempt_blocked_readers_cgp(rnp); empty_exp = !rcu_preempted_readers_exp(rnp); smp_mb(); /* ensure expedited fastpath sees end of RCU c-s. */ np = rcu_next_node_entry(t, rnp); @@ -334,6 +339,10 @@ static void rcu_read_unlock_special(struct task_struct *t) rnp->gp_tasks = np; if (&t->rcu_node_entry == rnp->exp_tasks) rnp->exp_tasks = np; +#ifdef CONFIG_RCU_BOOST + if (&t->rcu_node_entry == rnp->boost_tasks) + rnp->boost_tasks = np; +#endif /* #ifdef CONFIG_RCU_BOOST */ t->rcu_blocked_node = NULL; /* @@ -346,6 +355,15 @@ static void rcu_read_unlock_special(struct task_struct *t) else rcu_report_unblock_qs_rnp(rnp, flags); +#ifdef CONFIG_RCU_BOOST + /* Unboost if we were boosted. */ + if (special & RCU_READ_UNLOCK_BOOSTED) { + t->rcu_read_unlock_special &= ~RCU_READ_UNLOCK_BOOSTED; + rt_mutex_unlock(t->rcu_boost_mutex); + t->rcu_boost_mutex = NULL; + } +#endif /* #ifdef CONFIG_RCU_BOOST */ + /* * If this was the last task on the expedited lists, * then we need to report up the rcu_node hierarchy. @@ -391,7 +409,7 @@ static void rcu_print_detail_task_stall_rnp(struct rcu_node *rnp) unsigned long flags; struct task_struct *t; - if (!rcu_preempted_readers(rnp)) + if (!rcu_preempt_blocked_readers_cgp(rnp)) return; raw_spin_lock_irqsave(&rnp->lock, flags); t = list_entry(rnp->gp_tasks, @@ -430,7 +448,7 @@ static void rcu_print_task_stall(struct rcu_node *rnp) { struct task_struct *t; - if (!rcu_preempted_readers(rnp)) + if (!rcu_preempt_blocked_readers_cgp(rnp)) return; t = list_entry(rnp->gp_tasks, struct task_struct, rcu_node_entry); @@ -460,7 +478,7 @@ static void rcu_preempt_stall_reset(void) */ static void rcu_preempt_check_blocked_tasks(struct rcu_node *rnp) { - WARN_ON_ONCE(rcu_preempted_readers(rnp)); + WARN_ON_ONCE(rcu_preempt_blocked_readers_cgp(rnp)); if (!list_empty(&rnp->blkd_tasks)) rnp->gp_tasks = rnp->blkd_tasks.next; WARN_ON_ONCE(rnp->qsmask); @@ -509,7 +527,7 @@ static int rcu_preempt_offline_tasks(struct rcu_state *rsp, * absolutely necessary, but this is a good performance/complexity * tradeoff. */ - if (rcu_preempted_readers(rnp)) + if (rcu_preempt_blocked_readers_cgp(rnp)) retval |= RCU_OFL_TASKS_NORM_GP; if (rcu_preempted_readers_exp(rnp)) retval |= RCU_OFL_TASKS_EXP_GP; @@ -525,8 +543,22 @@ static int rcu_preempt_offline_tasks(struct rcu_state *rsp, rnp_root->gp_tasks = rnp->gp_tasks; if (&t->rcu_node_entry == rnp->exp_tasks) rnp_root->exp_tasks = rnp->exp_tasks; +#ifdef CONFIG_RCU_BOOST + if (&t->rcu_node_entry == rnp->boost_tasks) + rnp_root->boost_tasks = rnp->boost_tasks; +#endif /* #ifdef CONFIG_RCU_BOOST */ raw_spin_unlock(&rnp_root->lock); /* irqs still disabled */ } + +#ifdef CONFIG_RCU_BOOST + /* In case root is being boosted and leaf is not. */ + raw_spin_lock(&rnp_root->lock); /* irqs already disabled */ + if (rnp_root->boost_tasks != NULL && + rnp_root->boost_tasks != rnp_root->gp_tasks) + rnp_root->boost_tasks = rnp_root->gp_tasks; + raw_spin_unlock(&rnp_root->lock); /* irqs still disabled */ +#endif /* #ifdef CONFIG_RCU_BOOST */ + rnp->gp_tasks = NULL; rnp->exp_tasks = NULL; return retval; @@ -684,6 +716,7 @@ sync_rcu_preempt_exp_init(struct rcu_state *rsp, struct rcu_node *rnp) raw_spin_lock(&rnp->lock); /* irqs already disabled */ if (!list_empty(&rnp->blkd_tasks)) { rnp->exp_tasks = rnp->blkd_tasks.next; + rcu_initiate_boost(rnp); must_wait = 1; } raw_spin_unlock(&rnp->lock); /* irqs remain disabled */ @@ -830,6 +863,8 @@ void exit_rcu(void) #else /* #ifdef CONFIG_TREE_PREEMPT_RCU */ +static struct rcu_state *rcu_state = &rcu_sched_state; + /* * Tell them what RCU they are running. */ @@ -870,7 +905,7 @@ static void rcu_preempt_note_context_switch(int cpu) * Because preemptable RCU does not exist, there are never any preempted * RCU readers. */ -static int rcu_preempted_readers(struct rcu_node *rnp) +static int rcu_preempt_blocked_readers_cgp(struct rcu_node *rnp) { return 0; } @@ -1034,6 +1069,263 @@ static void __init __rcu_init_preempt(void) #endif /* #else #ifdef CONFIG_TREE_PREEMPT_RCU */ +#ifdef CONFIG_RCU_BOOST + +#include "rtmutex_common.h" + +/* + * Carry out RCU priority boosting on the task indicated by ->exp_tasks + * or ->boost_tasks, advancing the pointer to the next task in the + * ->blkd_tasks list. + * + * Note that irqs must be enabled: boosting the task can block. + * Returns 1 if there are more tasks needing to be boosted. + */ +static int rcu_boost(struct rcu_node *rnp) +{ + unsigned long flags; + struct rt_mutex mtx; + struct task_struct *t; + struct list_head *tb; + + if (rnp->exp_tasks == NULL && rnp->boost_tasks == NULL) + return 0; /* Nothing left to boost. */ + + raw_spin_lock_irqsave(&rnp->lock, flags); + + /* + * Recheck under the lock: all tasks in need of boosting + * might exit their RCU read-side critical sections on their own. + */ + if (rnp->exp_tasks == NULL && rnp->boost_tasks == NULL) { + raw_spin_unlock_irqrestore(&rnp->lock, flags); + return 0; + } + + /* + * Preferentially boost tasks blocking expedited grace periods. + * This cannot starve the normal grace periods because a second + * expedited grace period must boost all blocked tasks, including + * those blocking the pre-existing normal grace period. + */ + if (rnp->exp_tasks != NULL) + tb = rnp->exp_tasks; + else + tb = rnp->boost_tasks; + + /* + * We boost task t by manufacturing an rt_mutex that appears to + * be held by task t. We leave a pointer to that rt_mutex where + * task t can find it, and task t will release the mutex when it + * exits its outermost RCU read-side critical section. Then + * simply acquiring this artificial rt_mutex will boost task + * t's priority. (Thanks to tglx for suggesting this approach!) + * + * Note that task t must acquire rnp->lock to remove itself from + * the ->blkd_tasks list, which it will do from exit() if from + * nowhere else. We therefore are guaranteed that task t will + * stay around at least until we drop rnp->lock. Note that + * rnp->lock also resolves races between our priority boosting + * and task t's exiting its outermost RCU read-side critical + * section. + */ + t = container_of(tb, struct task_struct, rcu_node_entry); + rt_mutex_init_proxy_locked(&mtx, t); + t->rcu_boost_mutex = &mtx; + t->rcu_read_unlock_special |= RCU_READ_UNLOCK_BOOSTED; + raw_spin_unlock_irqrestore(&rnp->lock, flags); + rt_mutex_lock(&mtx); /* Side effect: boosts task t's priority. */ + rt_mutex_unlock(&mtx); /* Keep lockdep happy. */ + + return rnp->exp_tasks != NULL || rnp->boost_tasks != NULL; +} + +/* + * Timer handler to initiate waking up of boost kthreads that + * have yielded the CPU due to excessive numbers of tasks to + * boost. We wake up the per-rcu_node kthread, which in turn + * will wake up the booster kthread. + */ +static void rcu_boost_kthread_timer(unsigned long arg) +{ + unsigned long flags; + struct rcu_node *rnp = (struct rcu_node *)arg; + + raw_spin_lock_irqsave(&rnp->lock, flags); + invoke_rcu_node_kthread(rnp); + raw_spin_unlock_irqrestore(&rnp->lock, flags); +} + +/* + * Priority-boosting kthread. One per leaf rcu_node and one for the + * root rcu_node. + */ +static int rcu_boost_kthread(void *arg) +{ + struct rcu_node *rnp = (struct rcu_node *)arg; + int spincnt = 0; + int more2boost; + + for (;;) { + wait_event_interruptible(rnp->boost_wq, rnp->boost_tasks || + rnp->exp_tasks || + kthread_should_stop()); + if (kthread_should_stop()) + break; + more2boost = rcu_boost(rnp); + if (more2boost) + spincnt++; + else + spincnt = 0; + if (spincnt > 10) { + rcu_yield(rcu_boost_kthread_timer, (unsigned long)rnp); + spincnt = 0; + } + } + return 0; +} + +/* + * Check to see if it is time to start boosting RCU readers that are + * blocking the current grace period, and, if so, tell the per-rcu_node + * kthread to start boosting them. If there is an expedited grace + * period in progress, it is always time to boost. + * + * The caller must hold rnp->lock. + */ +static void rcu_initiate_boost(struct rcu_node *rnp) +{ + struct task_struct *t; + + if (!rcu_preempt_blocked_readers_cgp(rnp) && rnp->exp_tasks == NULL) + return; + if (rnp->exp_tasks != NULL || + (rnp->gp_tasks != NULL && + rnp->boost_tasks == NULL && + rnp->qsmask == 0 && + ULONG_CMP_GE(jiffies, rnp->boost_time))) { + if (rnp->exp_tasks == NULL) + rnp->boost_tasks = rnp->gp_tasks; + t = rnp->boost_kthread_task; + if (t != NULL) + wake_up_process(t); + } +} + +static void rcu_boost_kthread_setaffinity(struct rcu_node *rnp, + cpumask_var_t cm) +{ + unsigned long flags; + struct task_struct *t; + + raw_spin_lock_irqsave(&rnp->lock, flags); + t = rnp->boost_kthread_task; + if (t != NULL) + set_cpus_allowed_ptr(rnp->boost_kthread_task, cm); + raw_spin_unlock_irqrestore(&rnp->lock, flags); +} + +#define RCU_BOOST_DELAY_JIFFIES DIV_ROUND_UP(CONFIG_RCU_BOOST_DELAY * HZ, 1000) + +/* + * Do priority-boost accounting for the start of a new grace period. + */ +static void rcu_preempt_boost_start_gp(struct rcu_node *rnp) +{ + rnp->boost_time = jiffies + RCU_BOOST_DELAY_JIFFIES; +} + +/* + * Initialize the RCU-boost waitqueue. + */ +static void __init rcu_init_boost_waitqueue(struct rcu_node *rnp) +{ + init_waitqueue_head(&rnp->boost_wq); +} + +/* + * Create an RCU-boost kthread for the specified node if one does not + * already exist. We only create this kthread for preemptible RCU. + * Returns zero if all is well, a negated errno otherwise. + */ +static int __cpuinit rcu_spawn_one_boost_kthread(struct rcu_state *rsp, + struct rcu_node *rnp, + int rnp_index) +{ + unsigned long flags; + struct sched_param sp; + struct task_struct *t; + + if (&rcu_preempt_state != rsp) + return 0; + if (rnp->boost_kthread_task != NULL) + return 0; + t = kthread_create(rcu_boost_kthread, (void *)rnp, + "rcub%d", rnp_index); + if (IS_ERR(t)) + return PTR_ERR(t); + raw_spin_lock_irqsave(&rnp->lock, flags); + rnp->boost_kthread_task = t; + raw_spin_unlock_irqrestore(&rnp->lock, flags); + wake_up_process(t); + sp.sched_priority = RCU_KTHREAD_PRIO; + sched_setscheduler_nocheck(t, SCHED_FIFO, &sp); + return 0; +} + +#ifdef CONFIG_HOTPLUG_CPU + +static void rcu_stop_boost_kthread(struct rcu_node *rnp) +{ + unsigned long flags; + struct task_struct *t; + + raw_spin_lock_irqsave(&rnp->lock, flags); + t = rnp->boost_kthread_task; + rnp->boost_kthread_task = NULL; + raw_spin_unlock_irqrestore(&rnp->lock, flags); + if (t != NULL) + kthread_stop(t); +} + +#endif /* #ifdef CONFIG_HOTPLUG_CPU */ + +#else /* #ifdef CONFIG_RCU_BOOST */ + +static void rcu_initiate_boost(struct rcu_node *rnp) +{ +} + +static void rcu_boost_kthread_setaffinity(struct rcu_node *rnp, + cpumask_var_t cm) +{ +} + +static void rcu_preempt_boost_start_gp(struct rcu_node *rnp) +{ +} + +static void __init rcu_init_boost_waitqueue(struct rcu_node *rnp) +{ +} + +static int __cpuinit rcu_spawn_one_boost_kthread(struct rcu_state *rsp, + struct rcu_node *rnp, + int rnp_index) +{ + return 0; +} + +#ifdef CONFIG_HOTPLUG_CPU + +static void rcu_stop_boost_kthread(struct rcu_node *rnp) +{ +} + +#endif /* #ifdef CONFIG_HOTPLUG_CPU */ + +#endif /* #else #ifdef CONFIG_RCU_BOOST */ + #ifndef CONFIG_SMP void synchronize_sched_expedited(void) @@ -1206,8 +1498,8 @@ static DEFINE_PER_CPU(unsigned long, rcu_dyntick_holdoff); * * Because it is not legal to invoke rcu_process_callbacks() with irqs * disabled, we do one pass of force_quiescent_state(), then do a - * invoke_rcu_kthread() to cause rcu_process_callbacks() to be invoked later. - * The per-cpu rcu_dyntick_drain variable controls the sequencing. + * invoke_rcu_cpu_kthread() to cause rcu_process_callbacks() to be invoked + * later. The per-cpu rcu_dyntick_drain variable controls the sequencing. */ int rcu_needs_cpu(int cpu) { @@ -1257,7 +1549,7 @@ int rcu_needs_cpu(int cpu) /* If RCU callbacks are still pending, RCU still needs this CPU. */ if (c) - invoke_rcu_kthread(); + invoke_rcu_cpu_kthread(); return c; } -- cgit v0.10.2 From 0f962a5e7277c34987b77dc82fc9aefcedc95e27 Mon Sep 17 00:00:00 2001 From: "Paul E. McKenney" Date: Thu, 14 Apr 2011 12:13:53 -0700 Subject: rcu: Force per-rcu_node kthreads off of the outgoing CPU The scheduler has had some heartburn in the past when too many real-time kthreads were affinitied to the outgoing CPU. So, this commit lightens the load by forcing the per-rcu_node and the boost kthreads off of the outgoing CPU. Note that RCU's per-CPU kthread remains on the outgoing CPU until the bitter end, as it must in order to preserve correctness. Also avoid disabling hardirqs across calls to set_cpus_allowed_ptr(), given that this function can block. Signed-off-by: Paul E. McKenney Signed-off-by: Paul E. McKenney diff --git a/kernel/rcutree.c b/kernel/rcutree.c index 28fd92a..51eef41 100644 --- a/kernel/rcutree.c +++ b/kernel/rcutree.c @@ -95,7 +95,7 @@ static DEFINE_PER_CPU(wait_queue_head_t, rcu_cpu_wq); static DEFINE_PER_CPU(char, rcu_cpu_has_work); static char rcu_kthreads_spawnable; -static void rcu_node_kthread_setaffinity(struct rcu_node *rnp); +static void rcu_node_kthread_setaffinity(struct rcu_node *rnp, int outgoingcpu); static void invoke_rcu_cpu_kthread(void); #define RCU_KTHREAD_PRIO 1 /* RT priority for per-CPU kthreads. */ @@ -1099,7 +1099,7 @@ static void __rcu_offline_cpu(int cpu, struct rcu_state *rsp) kthread_stop(t); rcu_stop_boost_kthread(rnp); } else - rcu_node_kthread_setaffinity(rnp); + rcu_node_kthread_setaffinity(rnp, -1); } /* @@ -1644,8 +1644,12 @@ static int rcu_node_kthread(void *arg) * Set the per-rcu_node kthread's affinity to cover all CPUs that are * served by the rcu_node in question. The CPU hotplug lock is still * held, so the value of rnp->qsmaskinit will be stable. + * + * We don't include outgoingcpu in the affinity set, use -1 if there is + * no outgoing CPU. If there are no CPUs left in the affinity set, + * this function allows the kthread to execute on any CPU. */ -static void rcu_node_kthread_setaffinity(struct rcu_node *rnp) +static void rcu_node_kthread_setaffinity(struct rcu_node *rnp, int outgoingcpu) { cpumask_var_t cm; int cpu; @@ -1657,8 +1661,14 @@ static void rcu_node_kthread_setaffinity(struct rcu_node *rnp) return; cpumask_clear(cm); for (cpu = rnp->grplo; cpu <= rnp->grphi; cpu++, mask >>= 1) - if (mask & 0x1) + if ((mask & 0x1) && cpu != outgoingcpu) cpumask_set_cpu(cpu, cm); + if (cpumask_weight(cm) == 0) { + cpumask_setall(cm); + for (cpu = rnp->grplo; cpu <= rnp->grphi; cpu++) + cpumask_clear_cpu(cpu, cm); + WARN_ON_ONCE(cpumask_weight(cm) == 0); + } set_cpus_allowed_ptr(rnp->node_kthread_task, cm); rcu_boost_kthread_setaffinity(rnp, cm); free_cpumask_var(cm); @@ -2154,7 +2164,11 @@ static int __cpuinit rcu_cpu_notify(struct notifier_block *self, rcu_online_kthreads(cpu); break; case CPU_ONLINE: - rcu_node_kthread_setaffinity(rnp); + case CPU_DOWN_FAILED: + rcu_node_kthread_setaffinity(rnp, -1); + break; + case CPU_DOWN_PREPARE: + rcu_node_kthread_setaffinity(rnp, cpu); break; case CPU_DYING: case CPU_DYING_FROZEN: diff --git a/kernel/rcutree_plugin.h b/kernel/rcutree_plugin.h index 5964f82..4e48625 100644 --- a/kernel/rcutree_plugin.h +++ b/kernel/rcutree_plugin.h @@ -1212,17 +1212,19 @@ static void rcu_initiate_boost(struct rcu_node *rnp) } } +/* + * Set the affinity of the boost kthread. The CPU-hotplug locks are + * held, so no one should be messing with the existence of the boost + * kthread. + */ static void rcu_boost_kthread_setaffinity(struct rcu_node *rnp, cpumask_var_t cm) { - unsigned long flags; struct task_struct *t; - raw_spin_lock_irqsave(&rnp->lock, flags); t = rnp->boost_kthread_task; if (t != NULL) set_cpus_allowed_ptr(rnp->boost_kthread_task, cm); - raw_spin_unlock_irqrestore(&rnp->lock, flags); } #define RCU_BOOST_DELAY_JIFFIES DIV_ROUND_UP(CONFIG_RCU_BOOST_DELAY * HZ, 1000) -- cgit v0.10.2 From e3995a25fa361ce987a7d0ade00b17e3151519d7 Mon Sep 17 00:00:00 2001 From: "Paul E. McKenney" Date: Mon, 18 Apr 2011 15:31:26 -0700 Subject: rcu: put per-CPU kthread at non-RT priority during CPU hotplug operations If you are doing CPU hotplug operations, it is best not to have CPU-bound realtime tasks running CPU-bound on the outgoing CPU. So this commit makes per-CPU kthreads run at non-realtime priority during that time. Signed-off-by: Paul E. McKenney Signed-off-by: Paul E. McKenney Reviewed-by: Josh Triplett diff --git a/kernel/rcutree.c b/kernel/rcutree.c index 51eef41..198e4df 100644 --- a/kernel/rcutree.c +++ b/kernel/rcutree.c @@ -1464,6 +1464,30 @@ static void invoke_rcu_node_kthread(struct rcu_node *rnp) } /* + * Set the specified CPU's kthread to run RT or not, as specified by + * the to_rt argument. The CPU-hotplug locks are held, so the task + * is not going away. + */ +static void rcu_cpu_kthread_setrt(int cpu, int to_rt) +{ + int policy; + struct sched_param sp; + struct task_struct *t; + + t = per_cpu(rcu_cpu_kthread_task, cpu); + if (t == NULL) + return; + if (to_rt) { + policy = SCHED_FIFO; + sp.sched_priority = RCU_KTHREAD_PRIO; + } else { + policy = SCHED_NORMAL; + sp.sched_priority = 0; + } + sched_setscheduler_nocheck(t, policy, &sp); +} + +/* * Timer handler to initiate the waking up of per-CPU kthreads that * have yielded the CPU due to excess numbers of RCU callbacks. * We wake up the per-rcu_node kthread, which in turn will wake up @@ -2166,9 +2190,11 @@ static int __cpuinit rcu_cpu_notify(struct notifier_block *self, case CPU_ONLINE: case CPU_DOWN_FAILED: rcu_node_kthread_setaffinity(rnp, -1); + rcu_cpu_kthread_setrt(cpu, 1); break; case CPU_DOWN_PREPARE: rcu_node_kthread_setaffinity(rnp, cpu); + rcu_cpu_kthread_setrt(cpu, 0); break; case CPU_DYING: case CPU_DYING_FROZEN: -- cgit v0.10.2 From 3acf4a9a3d63f23430f940842829175b0778a1b8 Mon Sep 17 00:00:00 2001 From: "Paul E. McKenney" Date: Sun, 17 Apr 2011 23:45:23 -0700 Subject: rcu: avoid hammering sched with yet another bound RT kthread The scheduler does not appear to take kindly to having multiple real-time threads bound to a CPU that is going offline. So this commit is a temporary hack-around to avoid that happening. Signed-off-by: Paul E. McKenney Signed-off-by: Paul E. McKenney diff --git a/kernel/rcutorture.c b/kernel/rcutorture.c index c224da4..4d256db 100644 --- a/kernel/rcutorture.c +++ b/kernel/rcutorture.c @@ -163,11 +163,11 @@ static int stutter_pause_test; #endif int rcutorture_runnable = RCUTORTURE_RUNNABLE_INIT; -#ifdef CONFIG_RCU_BOOST +#if defined(CONFIG_RCU_BOOST) && !defined(CONFIG_HOTPLUG_CPU) #define rcu_can_boost() 1 -#else /* #ifdef CONFIG_RCU_BOOST */ +#else /* #if defined(CONFIG_RCU_BOOST) && !defined(CONFIG_HOTPLUG_CPU) */ #define rcu_can_boost() 0 -#endif /* #else #ifdef CONFIG_RCU_BOOST */ +#endif /* #else #if defined(CONFIG_RCU_BOOST) && !defined(CONFIG_HOTPLUG_CPU) */ static unsigned long boost_starttime; /* jiffies of next boost test start. */ DEFINE_MUTEX(boost_mutex); /* protect setting boost_starttime */ -- cgit v0.10.2 From 67b98dba474f293c389fc2b7254dcf7c0492e3bd Mon Sep 17 00:00:00 2001 From: "Paul E. McKenney" Date: Mon, 21 Feb 2011 13:31:55 -0800 Subject: rcu: eliminate unused boosting statistics The n_rcu_torture_boost_allocerror and n_rcu_torture_boost_afferror statistics are not actually incremented anymore, so eliminate them. Signed-off-by: Paul E. McKenney Signed-off-by: Paul E. McKenney Reviewed-by: Josh Triplett diff --git a/kernel/rcutorture.c b/kernel/rcutorture.c index 4d256db..22b0e74 100644 --- a/kernel/rcutorture.c +++ b/kernel/rcutorture.c @@ -146,8 +146,6 @@ static atomic_t n_rcu_torture_mberror; static atomic_t n_rcu_torture_error; static long n_rcu_torture_boost_ktrerror; static long n_rcu_torture_boost_rterror; -static long n_rcu_torture_boost_allocerror; -static long n_rcu_torture_boost_afferror; static long n_rcu_torture_boost_failure; static long n_rcu_torture_boosts; static long n_rcu_torture_timers; @@ -1067,7 +1065,7 @@ rcu_torture_printk(char *page) cnt += sprintf(&page[cnt], "%s%s ", torture_type, TORTURE_FLAG); cnt += sprintf(&page[cnt], "rtc: %p ver: %ld tfle: %d rta: %d rtaf: %d rtf: %d " - "rtmbe: %d rtbke: %ld rtbre: %ld rtbae: %ld rtbafe: %ld " + "rtmbe: %d rtbke: %ld rtbre: %ld " "rtbf: %ld rtb: %ld nt: %ld", rcu_torture_current, rcu_torture_current_version, @@ -1078,16 +1076,12 @@ rcu_torture_printk(char *page) atomic_read(&n_rcu_torture_mberror), n_rcu_torture_boost_ktrerror, n_rcu_torture_boost_rterror, - n_rcu_torture_boost_allocerror, - n_rcu_torture_boost_afferror, n_rcu_torture_boost_failure, n_rcu_torture_boosts, n_rcu_torture_timers); if (atomic_read(&n_rcu_torture_mberror) != 0 || n_rcu_torture_boost_ktrerror != 0 || n_rcu_torture_boost_rterror != 0 || - n_rcu_torture_boost_allocerror != 0 || - n_rcu_torture_boost_afferror != 0 || n_rcu_torture_boost_failure != 0) cnt += sprintf(&page[cnt], " !!!"); cnt += sprintf(&page[cnt], "\n%s%s ", torture_type, TORTURE_FLAG); @@ -1486,8 +1480,6 @@ rcu_torture_init(void) atomic_set(&n_rcu_torture_error, 0); n_rcu_torture_boost_ktrerror = 0; n_rcu_torture_boost_rterror = 0; - n_rcu_torture_boost_allocerror = 0; - n_rcu_torture_boost_afferror = 0; n_rcu_torture_boost_failure = 0; n_rcu_torture_boosts = 0; for (i = 0; i < RCU_TORTURE_PIPE_LEN + 1; i++) -- cgit v0.10.2 From 0ea1f2ebeb217d38770aebf91c4ecaa8e01b3305 Mon Sep 17 00:00:00 2001 From: "Paul E. McKenney" Date: Tue, 22 Feb 2011 13:42:43 -0800 Subject: rcu: Add boosting to TREE_PREEMPT_RCU tracing Includes total number of tasks boosted, number boosted on behalf of each of normal and expedited grace periods, and statistics on attempts to initiate boosting that failed for various reasons. Signed-off-by: Paul E. McKenney Signed-off-by: Paul E. McKenney Reviewed-by: Josh Triplett diff --git a/kernel/rcutree.h b/kernel/rcutree.h index 8db0cdc..d49046c 100644 --- a/kernel/rcutree.h +++ b/kernel/rcutree.h @@ -152,6 +152,25 @@ struct rcu_node { wait_queue_head_t boost_wq; /* Wait queue on which to park the boost */ /* kthread. */ + unsigned long n_tasks_boosted; + /* Total number of tasks boosted. */ + unsigned long n_exp_boosts; + /* Number of tasks boosted for expedited GP. */ + unsigned long n_normal_boosts; + /* Number of tasks boosted for normal GP. */ + unsigned long n_balk_blkd_tasks; + /* Refused to boost: no blocked tasks. */ + unsigned long n_balk_exp_gp_tasks; + /* Refused to boost: nothing blocking GP. */ + unsigned long n_balk_boost_tasks; + /* Refused to boost: already boosting. */ + unsigned long n_balk_notblocked; + /* Refused to boost: RCU RS CS still running. */ + unsigned long n_balk_notyet; + /* Refused to boost: not yet time. */ + unsigned long n_balk_nos; + /* Refused to boost: not sure why, though. */ + /* This can happen due to race conditions. */ #endif /* #ifdef CONFIG_RCU_BOOST */ struct task_struct *node_kthread_task; /* kthread that takes care of this rcu_node */ diff --git a/kernel/rcutree_plugin.h b/kernel/rcutree_plugin.h index 4e48625..07d3464 100644 --- a/kernel/rcutree_plugin.h +++ b/kernel/rcutree_plugin.h @@ -1073,6 +1073,33 @@ static void __init __rcu_init_preempt(void) #include "rtmutex_common.h" +#ifdef CONFIG_RCU_TRACE + +static void rcu_initiate_boost_trace(struct rcu_node *rnp) +{ + if (list_empty(&rnp->blkd_tasks)) + rnp->n_balk_blkd_tasks++; + else if (rnp->exp_tasks == NULL && rnp->gp_tasks == NULL) + rnp->n_balk_exp_gp_tasks++; + else if (rnp->gp_tasks != NULL && rnp->boost_tasks != NULL) + rnp->n_balk_boost_tasks++; + else if (rnp->gp_tasks != NULL && rnp->qsmask != 0) + rnp->n_balk_notblocked++; + else if (rnp->gp_tasks != NULL && + ULONG_CMP_GE(jiffies, rnp->boost_time)) + rnp->n_balk_notyet++; + else + rnp->n_balk_nos++; +} + +#else /* #ifdef CONFIG_RCU_TRACE */ + +static void rcu_initiate_boost_trace(struct rcu_node *rnp) +{ +} + +#endif /* #else #ifdef CONFIG_RCU_TRACE */ + /* * Carry out RCU priority boosting on the task indicated by ->exp_tasks * or ->boost_tasks, advancing the pointer to the next task in the @@ -1108,10 +1135,14 @@ static int rcu_boost(struct rcu_node *rnp) * expedited grace period must boost all blocked tasks, including * those blocking the pre-existing normal grace period. */ - if (rnp->exp_tasks != NULL) + if (rnp->exp_tasks != NULL) { tb = rnp->exp_tasks; - else + rnp->n_exp_boosts++; + } else { tb = rnp->boost_tasks; + rnp->n_normal_boosts++; + } + rnp->n_tasks_boosted++; /* * We boost task t by manufacturing an rt_mutex that appears to @@ -1197,8 +1228,10 @@ static void rcu_initiate_boost(struct rcu_node *rnp) { struct task_struct *t; - if (!rcu_preempt_blocked_readers_cgp(rnp) && rnp->exp_tasks == NULL) + if (!rcu_preempt_blocked_readers_cgp(rnp) && rnp->exp_tasks == NULL) { + rnp->n_balk_exp_gp_tasks++; return; + } if (rnp->exp_tasks != NULL || (rnp->gp_tasks != NULL && rnp->boost_tasks == NULL && @@ -1209,7 +1242,8 @@ static void rcu_initiate_boost(struct rcu_node *rnp) t = rnp->boost_kthread_task; if (t != NULL) wake_up_process(t); - } + } else + rcu_initiate_boost_trace(rnp); } /* diff --git a/kernel/rcutree_trace.c b/kernel/rcutree_trace.c index 1cedf94..ead5736 100644 --- a/kernel/rcutree_trace.c +++ b/kernel/rcutree_trace.c @@ -157,6 +157,71 @@ static const struct file_operations rcudata_csv_fops = { .release = single_release, }; +#ifdef CONFIG_RCU_BOOST + +static void print_one_rcu_node_boost(struct seq_file *m, struct rcu_node *rnp) +{ + seq_printf(m, "%d:%d tasks=%c%c%c%c ntb=%lu neb=%lu nnb=%lu " + "j=%04x bt=%04x\n", + rnp->grplo, rnp->grphi, + "T."[list_empty(&rnp->blkd_tasks)], + "N."[!rnp->gp_tasks], + "E."[!rnp->exp_tasks], + "B."[!rnp->boost_tasks], + rnp->n_tasks_boosted, rnp->n_exp_boosts, + rnp->n_normal_boosts, + (int)(jiffies & 0xffff), + (int)(rnp->boost_time & 0xffff)); + seq_printf(m, "%s: nt=%lu egt=%lu bt=%lu nb=%lu ny=%lu nos=%lu\n", + " balk", + rnp->n_balk_blkd_tasks, + rnp->n_balk_exp_gp_tasks, + rnp->n_balk_boost_tasks, + rnp->n_balk_notblocked, + rnp->n_balk_notyet, + rnp->n_balk_nos); +} + +static int show_rcu_node_boost(struct seq_file *m, void *unused) +{ + struct rcu_node *rnp; + + rcu_for_each_leaf_node(&rcu_preempt_state, rnp) + print_one_rcu_node_boost(m, rnp); + return 0; +} + +static int rcu_node_boost_open(struct inode *inode, struct file *file) +{ + return single_open(file, show_rcu_node_boost, NULL); +} + +static const struct file_operations rcu_node_boost_fops = { + .owner = THIS_MODULE, + .open = rcu_node_boost_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + +/* + * Create the rcuboost debugfs entry. Standard error return. + */ +static int rcu_boost_trace_create_file(struct dentry *rcudir) +{ + return !debugfs_create_file("rcuboost", 0444, rcudir, NULL, + &rcu_node_boost_fops); +} + +#else /* #ifdef CONFIG_RCU_BOOST */ + +static int rcu_boost_trace_create_file(struct dentry *rcudir) +{ + return 0; /* There cannot be an error if we didn't create it! */ +} + +#endif /* #else #ifdef CONFIG_RCU_BOOST */ + static void print_one_rcu_state(struct seq_file *m, struct rcu_state *rsp) { unsigned long gpnum; @@ -315,6 +380,9 @@ static int __init rcutree_trace_init(void) if (!retval) goto free_out; + if (rcu_boost_trace_create_file(rcudir)) + goto free_out; + retval = debugfs_create_file("rcugp", 0444, rcudir, NULL, &rcugp_fops); if (!retval) goto free_out; -- cgit v0.10.2 From 2fa218d8bbcff239302f9f36e19d7187077dd636 Mon Sep 17 00:00:00 2001 From: "Paul E. McKenney" Date: Sun, 27 Mar 2011 21:37:58 -0700 Subject: rcu: Update RCU's trace.txt documentation for new format The trace.txt file had obsolete output for the debugfs rcu/rcudata file, so update it. Signed-off-by: Paul E. McKenney Signed-off-by: Paul E. McKenney Reviewed-by: Josh Triplett diff --git a/Documentation/RCU/trace.txt b/Documentation/RCU/trace.txt index 5a704ff..13dbf9b 100644 --- a/Documentation/RCU/trace.txt +++ b/Documentation/RCU/trace.txt @@ -21,23 +21,23 @@ rcu_pending() function decided that there was core RCU work to do). The output of "cat rcu/rcudata" looks as follows: rcu_sched: - 0 c=17829 g=17829 pq=1 pqc=17829 qp=0 dt=10951/1/0 df=1101 of=0 ri=36 ql=0 b=10 - 1 c=17829 g=17829 pq=1 pqc=17829 qp=0 dt=16117/1/0 df=1015 of=0 ri=0 ql=0 b=10 - 2 c=17829 g=17829 pq=1 pqc=17829 qp=0 dt=1445/1/0 df=1839 of=0 ri=0 ql=0 b=10 - 3 c=17829 g=17829 pq=1 pqc=17829 qp=0 dt=6681/1/0 df=1545 of=0 ri=0 ql=0 b=10 - 4 c=17829 g=17829 pq=1 pqc=17829 qp=0 dt=1003/1/0 df=1992 of=0 ri=0 ql=0 b=10 - 5 c=17829 g=17830 pq=1 pqc=17829 qp=1 dt=3887/1/0 df=3331 of=0 ri=4 ql=2 b=10 - 6 c=17829 g=17829 pq=1 pqc=17829 qp=0 dt=859/1/0 df=3224 of=0 ri=0 ql=0 b=10 - 7 c=17829 g=17830 pq=0 pqc=17829 qp=1 dt=3761/1/0 df=1818 of=0 ri=0 ql=2 b=10 + 0!c=423090 g=423091 pq=1 pqc=423090 qp=1 dt=86475/1/0 df=16319 of=163 ri=1519 ql=0 b=10 ci=1460693 co=1648 ca=6448 + 1!c=423329 g=423330 pq=1 pqc=423329 qp=1 dt=90875/1/0 df=16231 of=157 ri=1249 ql=0 b=10 ci=1459002 co=1614 ca=3310 + 2!c=423370 g=423371 pq=1 pqc=423370 qp=1 dt=69661/1/0 df=16125 of=163 ri=1469 ql=0 b=10 ci=1610701 co=2015 ca=2378 + 3!c=422967 g=422968 pq=1 pqc=422967 qp=1 dt=70349/1/0 df=12528 of=163 ri=1450 ql=0 b=10 ci=1427543 co=1430 ca=897 + 4!c=423196 g=423197 pq=1 pqc=423196 qp=0 dt=38935/1/0 df=10959 of=177 ri=1657 ql=0 b=10 ci=1562249 co=1896 ca=533 + 5!c=422950 g=422951 pq=1 pqc=422950 qp=0 dt=25127/1/0 df=5895 of=167 ri=1549 ql=0 b=10 ci=1777260 co=2137 ca=274 + 6!c=423396 g=423397 pq=1 pqc=423396 qp=1 dt=22639/1/0 df=4590 of=149 ri=1572 ql=0 b=10 ci=1471186 co=1530 ca=243 + 7 c=460203 g=460203 pq=1 pqc=460202 qp=0 dt=937087/1/0 df=3298 of=149 ri=1584 ql=6 b=10 ci=4026154 co=1948 ca=135 rcu_bh: - 0 c=-275 g=-275 pq=1 pqc=-275 qp=0 dt=10951/1/0 df=0 of=0 ri=0 ql=0 b=10 - 1 c=-275 g=-275 pq=1 pqc=-275 qp=0 dt=16117/1/0 df=13 of=0 ri=0 ql=0 b=10 - 2 c=-275 g=-275 pq=1 pqc=-275 qp=0 dt=1445/1/0 df=15 of=0 ri=0 ql=0 b=10 - 3 c=-275 g=-275 pq=1 pqc=-275 qp=0 dt=6681/1/0 df=9 of=0 ri=0 ql=0 b=10 - 4 c=-275 g=-275 pq=1 pqc=-275 qp=0 dt=1003/1/0 df=15 of=0 ri=0 ql=0 b=10 - 5 c=-275 g=-275 pq=1 pqc=-275 qp=0 dt=3887/1/0 df=15 of=0 ri=0 ql=0 b=10 - 6 c=-275 g=-275 pq=1 pqc=-275 qp=0 dt=859/1/0 df=15 of=0 ri=0 ql=0 b=10 - 7 c=-275 g=-275 pq=1 pqc=-275 qp=0 dt=3761/1/0 df=15 of=0 ri=0 ql=0 b=10 + 0!c=18446744073709551494 g=18446744073709551494 pq=0 pqc=18446744073709551493 qp=1 dt=86475/1/0 df=11 of=0 ri=0 ql=0 b=10 ci=112 co=0 ca=0 + 1!c=18446744073709551496 g=18446744073709551496 pq=1 pqc=18446744073709551495 qp=0 dt=90875/1/0 df=15 of=0 ri=0 ql=0 b=10 ci=143 co=0 ca=0 + 2!c=18446744073709551496 g=18446744073709551496 pq=1 pqc=18446744073709551495 qp=0 dt=69661/1/0 df=21 of=0 ri=1 ql=0 b=10 ci=88 co=0 ca=0 + 3!c=18446744073709551494 g=18446744073709551494 pq=1 pqc=18446744073709551493 qp=0 dt=70349/1/0 df=13 of=0 ri=0 ql=0 b=10 ci=100 co=0 ca=0 + 4!c=18446744073709551494 g=18446744073709551494 pq=0 pqc=18446744073709551493 qp=1 dt=38935/1/0 df=17 of=0 ri=0 ql=0 b=10 ci=36 co=0 ca=0 + 5!c=18446744073709551494 g=18446744073709551494 pq=0 pqc=18446744073709551493 qp=1 dt=25127/1/0 df=7 of=0 ri=0 ql=0 b=10 ci=32 co=0 ca=0 + 6!c=18446744073709551496 g=18446744073709551496 pq=1 pqc=18446744073709551495 qp=0 dt=22639/1/0 df=9 of=0 ri=0 ql=0 b=10 ci=44 co=0 ca=0 + 7 c=182 g=182 pq=1 pqc=181 qp=0 dt=937087/1/0 df=14 of=0 ri=1 ql=0 b=10 ci=627 co=0 ca=0 The first section lists the rcu_data structures for rcu_sched, the second for rcu_bh. Note that CONFIG_TREE_PREEMPT_RCU kernels will have an @@ -52,17 +52,18 @@ o The number at the beginning of each line is the CPU number. substantially larger than the number of actual CPUs. o "c" is the count of grace periods that this CPU believes have - completed. CPUs in dynticks idle mode may lag quite a ways - behind, for example, CPU 4 under "rcu_sched" above, which has - slept through the past 25 RCU grace periods. It is not unusual - to see CPUs lagging by thousands of grace periods. + completed. Offlined CPUs and CPUs in dynticks idle mode may + lag quite a ways behind, for example, CPU 6 under "rcu_sched" + above, which has been offline through not quite 40,000 RCU grace + periods. It is not unusual to see CPUs lagging by thousands of + grace periods. o "g" is the count of grace periods that this CPU believes have - started. Again, CPUs in dynticks idle mode may lag behind. - If the "c" and "g" values are equal, this CPU has already - reported a quiescent state for the last RCU grace period that - it is aware of, otherwise, the CPU believes that it owes RCU a - quiescent state. + started. Again, offlined CPUs and CPUs in dynticks idle mode + may lag behind. If the "c" and "g" values are equal, this CPU + has already reported a quiescent state for the last RCU grace + period that it is aware of, otherwise, the CPU believes that it + owes RCU a quiescent state. o "pq" indicates that this CPU has passed through a quiescent state for the current grace period. It is possible for "pq" to be @@ -81,14 +82,16 @@ o "pqc" indicates which grace period the last-observed quiescent the next grace period! o "qp" indicates that RCU still expects a quiescent state from - this CPU. + this CPU. Offlined CPUs and CPUs in dyntick idle mode might + well have qp=1, which is OK: RCU is still ignoring them. o "dt" is the current value of the dyntick counter that is incremented when entering or leaving dynticks idle state, either by the - scheduler or by irq. The number after the first "/" is the - interrupt nesting depth when in dyntick-idle state, or one - greater than the interrupt-nesting depth otherwise. The number - after the second "/" is the NMI nesting depth. + scheduler or by irq. This number is even if the CPU is in + dyntick idle mode and odd otherwise. The number after the first + "/" is the interrupt nesting depth when in dyntick-idle state, + or one greater than the interrupt-nesting depth otherwise. + The number after the second "/" is the NMI nesting depth. This field is displayed only for CONFIG_NO_HZ kernels. @@ -100,7 +103,7 @@ o "df" is the number of times that some other CPU has forced a o "of" is the number of times that some other CPU has forced a quiescent state on behalf of this CPU due to this CPU being - offline. In a perfect world, this might neve happen, but it + offline. In a perfect world, this might never happen, but it turns out that offlining and onlining a CPU can take several grace periods, and so there is likely to be an extended period of time when RCU believes that the CPU is online when it really is not. -- cgit v0.10.2 From 0ac3d136b2e3cdf1161178223bc5da14a06241d0 Mon Sep 17 00:00:00 2001 From: "Paul E. McKenney" Date: Mon, 28 Mar 2011 15:47:07 -0700 Subject: rcu: add callback-queue information to rcudata output This commit adds an indication of the state of the callback queue using a string of four characters following the "ql=" integer queue length. The first character is "N" if there are callbacks that have been queued that are not yet ready to be handled by the next grace period, or "." otherwise. The second character is "R" if there are callbacks queued that are ready to be handled by the next grace period, or "." otherwise. The third character is "W" if there are callbacks waiting for the current grace period, or "." otherwise. Finally, the fourth character is "D" if there are callbacks that have been handled by a prior grace period and are waiting to be invoked, or ".". Note that callbacks that are in the process of being invoked are not shown. These callbacks would have been removed from the rcu_data structure's list by rcu_do_batch() prior to being executed. (These callbacks are also not reflected in the "ql=" total, FWIW.) Also, document the new callback-queue trace information. Signed-off-by: Paul E. McKenney Signed-off-by: Paul E. McKenney Reviewed-by: Josh Triplett diff --git a/Documentation/RCU/trace.txt b/Documentation/RCU/trace.txt index 13dbf9b..5aefd5f 100644 --- a/Documentation/RCU/trace.txt +++ b/Documentation/RCU/trace.txt @@ -21,23 +21,23 @@ rcu_pending() function decided that there was core RCU work to do). The output of "cat rcu/rcudata" looks as follows: rcu_sched: - 0!c=423090 g=423091 pq=1 pqc=423090 qp=1 dt=86475/1/0 df=16319 of=163 ri=1519 ql=0 b=10 ci=1460693 co=1648 ca=6448 - 1!c=423329 g=423330 pq=1 pqc=423329 qp=1 dt=90875/1/0 df=16231 of=157 ri=1249 ql=0 b=10 ci=1459002 co=1614 ca=3310 - 2!c=423370 g=423371 pq=1 pqc=423370 qp=1 dt=69661/1/0 df=16125 of=163 ri=1469 ql=0 b=10 ci=1610701 co=2015 ca=2378 - 3!c=422967 g=422968 pq=1 pqc=422967 qp=1 dt=70349/1/0 df=12528 of=163 ri=1450 ql=0 b=10 ci=1427543 co=1430 ca=897 - 4!c=423196 g=423197 pq=1 pqc=423196 qp=0 dt=38935/1/0 df=10959 of=177 ri=1657 ql=0 b=10 ci=1562249 co=1896 ca=533 - 5!c=422950 g=422951 pq=1 pqc=422950 qp=0 dt=25127/1/0 df=5895 of=167 ri=1549 ql=0 b=10 ci=1777260 co=2137 ca=274 - 6!c=423396 g=423397 pq=1 pqc=423396 qp=1 dt=22639/1/0 df=4590 of=149 ri=1572 ql=0 b=10 ci=1471186 co=1530 ca=243 - 7 c=460203 g=460203 pq=1 pqc=460202 qp=0 dt=937087/1/0 df=3298 of=149 ri=1584 ql=6 b=10 ci=4026154 co=1948 ca=135 + 0!c=423090 g=423091 pq=1 pqc=423090 qp=1 dt=86475/1/0 df=16319 of=163 ri=1519 ql=0 qs=.... b=10 ci=1460693 co=1648 ca=6448 + 1!c=423329 g=423330 pq=1 pqc=423329 qp=1 dt=90875/1/0 df=16231 of=157 ri=1249 ql=0 qs=.... b=10 ci=1459002 co=1614 ca=3310 + 2!c=423370 g=423371 pq=1 pqc=423370 qp=1 dt=69661/1/0 df=16125 of=163 ri=1469 ql=0 qs=.... b=10 ci=1610701 co=2015 ca=2378 + 3!c=422967 g=422968 pq=1 pqc=422967 qp=1 dt=70349/1/0 df=12528 of=163 ri=1450 ql=0 qs=.... b=10 ci=1427543 co=1430 ca=897 + 4!c=423196 g=423197 pq=1 pqc=423196 qp=0 dt=38935/1/0 df=10959 of=177 ri=1657 ql=0 qs=.... b=10 ci=1562249 co=1896 ca=533 + 5!c=422950 g=422951 pq=1 pqc=422950 qp=0 dt=25127/1/0 df=5895 of=167 ri=1549 ql=0 qs=.... b=10 ci=1777260 co=2137 ca=274 + 6!c=423396 g=423397 pq=1 pqc=423396 qp=1 dt=22639/1/0 df=4590 of=149 ri=1572 ql=0 qs=.... b=10 ci=1471186 co=1530 ca=243 + 7 c=460203 g=460203 pq=1 pqc=460202 qp=0 dt=937087/1/0 df=3298 of=149 ri=1584 ql=6 qs=N.W. b=10 ci=4026154 co=1948 ca=135 rcu_bh: - 0!c=18446744073709551494 g=18446744073709551494 pq=0 pqc=18446744073709551493 qp=1 dt=86475/1/0 df=11 of=0 ri=0 ql=0 b=10 ci=112 co=0 ca=0 - 1!c=18446744073709551496 g=18446744073709551496 pq=1 pqc=18446744073709551495 qp=0 dt=90875/1/0 df=15 of=0 ri=0 ql=0 b=10 ci=143 co=0 ca=0 - 2!c=18446744073709551496 g=18446744073709551496 pq=1 pqc=18446744073709551495 qp=0 dt=69661/1/0 df=21 of=0 ri=1 ql=0 b=10 ci=88 co=0 ca=0 - 3!c=18446744073709551494 g=18446744073709551494 pq=1 pqc=18446744073709551493 qp=0 dt=70349/1/0 df=13 of=0 ri=0 ql=0 b=10 ci=100 co=0 ca=0 - 4!c=18446744073709551494 g=18446744073709551494 pq=0 pqc=18446744073709551493 qp=1 dt=38935/1/0 df=17 of=0 ri=0 ql=0 b=10 ci=36 co=0 ca=0 - 5!c=18446744073709551494 g=18446744073709551494 pq=0 pqc=18446744073709551493 qp=1 dt=25127/1/0 df=7 of=0 ri=0 ql=0 b=10 ci=32 co=0 ca=0 - 6!c=18446744073709551496 g=18446744073709551496 pq=1 pqc=18446744073709551495 qp=0 dt=22639/1/0 df=9 of=0 ri=0 ql=0 b=10 ci=44 co=0 ca=0 - 7 c=182 g=182 pq=1 pqc=181 qp=0 dt=937087/1/0 df=14 of=0 ri=1 ql=0 b=10 ci=627 co=0 ca=0 + 0!c=18446744073709551494 g=18446744073709551494 pq=0 pqc=18446744073709551493 qp=1 dt=86475/1/0 df=11 of=0 ri=0 ql=0 qs=.... b=10 ci=112 co=0 ca=0 + 1!c=18446744073709551496 g=18446744073709551496 pq=1 pqc=18446744073709551495 qp=0 dt=90875/1/0 df=15 of=0 ri=0 ql=0 qs=.... b=10 ci=143 co=0 ca=0 + 2!c=18446744073709551496 g=18446744073709551496 pq=1 pqc=18446744073709551495 qp=0 dt=69661/1/0 df=21 of=0 ri=1 ql=0 qs=.... b=10 ci=88 co=0 ca=0 + 3!c=18446744073709551494 g=18446744073709551494 pq=1 pqc=18446744073709551493 qp=0 dt=70349/1/0 df=13 of=0 ri=0 ql=0 qs=.... b=10 ci=100 co=0 ca=0 + 4!c=18446744073709551494 g=18446744073709551494 pq=0 pqc=18446744073709551493 qp=1 dt=38935/1/0 df=17 of=0 ri=0 ql=0 qs=.... b=10 ci=36 co=0 ca=0 + 5!c=18446744073709551494 g=18446744073709551494 pq=0 pqc=18446744073709551493 qp=1 dt=25127/1/0 df=7 of=0 ri=0 ql=0 qs=.... b=10 ci=32 co=0 ca=0 + 6!c=18446744073709551496 g=18446744073709551496 pq=1 pqc=18446744073709551495 qp=0 dt=22639/1/0 df=9 of=0 ri=0 ql=0 qs=.... b=10 ci=44 co=0 ca=0 + 7 c=182 g=182 pq=1 pqc=181 qp=0 dt=937087/1/0 df=14 of=0 ri=1 ql=0 qs=.... b=10 ci=627 co=0 ca=0 The first section lists the rcu_data structures for rcu_sched, the second for rcu_bh. Note that CONFIG_TREE_PREEMPT_RCU kernels will have an @@ -120,6 +120,32 @@ o "ql" is the number of RCU callbacks currently residing on of what state they are in (new, waiting for grace period to start, waiting for grace period to end, ready to invoke). +o "qs" gives an indication of the state of the callback queue + with four characters: + + "N" Indicates that there are callbacks queued that are not + ready to be handled by the next grace period, and thus + will be handled by the grace period following the next + one. + + "R" Indicates that there are callbacks queued that are + ready to be handled by the next grace period. + + "W" Indicates that there are callbacks queued that are + waiting on the current grace period. + + "D" Indicates that there are callbacks queued that have + already been handled by a prior grace period, and are + thus waiting to be invoked. Note that callbacks in + the process of being invoked are not counted here. + Callbacks in the process of being invoked are those + that have been removed from the rcu_data structures + queues by rcu_do_batch(), but which have not yet been + invoked. + + If there are no callbacks in a given one of the above states, + the corresponding character is replaced by ".". + o "b" is the batch limit for this CPU. If more than this number of RCU callbacks is ready to invoke, then the remainder will be deferred. diff --git a/kernel/rcutree_trace.c b/kernel/rcutree_trace.c index ead5736..afd262f 100644 --- a/kernel/rcutree_trace.c +++ b/kernel/rcutree_trace.c @@ -64,7 +64,16 @@ static void print_one_rcu_data(struct seq_file *m, struct rcu_data *rdp) rdp->dynticks_fqs); #endif /* #ifdef CONFIG_NO_HZ */ seq_printf(m, " of=%lu ri=%lu", rdp->offline_fqs, rdp->resched_ipi); - seq_printf(m, " ql=%ld b=%ld", rdp->qlen, rdp->blimit); + seq_printf(m, " ql=%ld qs=%c%c%c%c b=%ld", + rdp->qlen, + ".N"[rdp->nxttail[RCU_NEXT_READY_TAIL] != + rdp->nxttail[RCU_NEXT_TAIL]], + ".R"[rdp->nxttail[RCU_WAIT_TAIL] != + rdp->nxttail[RCU_NEXT_READY_TAIL]], + ".W"[rdp->nxttail[RCU_DONE_TAIL] != + rdp->nxttail[RCU_WAIT_TAIL]], + ".D"[&rdp->nxtlist != rdp->nxttail[RCU_DONE_TAIL]], + rdp->blimit); seq_printf(m, " ci=%lu co=%lu ca=%lu\n", rdp->n_cbs_invoked, rdp->n_cbs_orphaned, rdp->n_cbs_adopted); } @@ -121,7 +130,15 @@ static void print_one_rcu_data_csv(struct seq_file *m, struct rcu_data *rdp) rdp->dynticks_fqs); #endif /* #ifdef CONFIG_NO_HZ */ seq_printf(m, ",%lu,%lu", rdp->offline_fqs, rdp->resched_ipi); - seq_printf(m, ",%ld,%ld", rdp->qlen, rdp->blimit); + seq_printf(m, ",%ld,\"%c%c%c%c\",%ld", rdp->qlen, + ".N"[rdp->nxttail[RCU_NEXT_READY_TAIL] != + rdp->nxttail[RCU_NEXT_TAIL]], + ".R"[rdp->nxttail[RCU_WAIT_TAIL] != + rdp->nxttail[RCU_NEXT_READY_TAIL]], + ".W"[rdp->nxttail[RCU_DONE_TAIL] != + rdp->nxttail[RCU_WAIT_TAIL]], + ".D"[&rdp->nxtlist != rdp->nxttail[RCU_DONE_TAIL]], + rdp->blimit); seq_printf(m, ",%lu,%lu,%lu\n", rdp->n_cbs_invoked, rdp->n_cbs_orphaned, rdp->n_cbs_adopted); } -- cgit v0.10.2 From d71df90eadfc35aa549ff9a850842673febca71f Mon Sep 17 00:00:00 2001 From: "Paul E. McKenney" Date: Tue, 29 Mar 2011 17:48:28 -0700 Subject: rcu: add tracing for RCU's kthread run states. Add tracing to help debugging situations when RCU's kthreads are not running but are supposed to be. Signed-off-by: Paul E. McKenney Signed-off-by: Paul E. McKenney Reviewed-by: Josh Triplett diff --git a/kernel/rcutree.c b/kernel/rcutree.c index 198e4df..d891740 100644 --- a/kernel/rcutree.c +++ b/kernel/rcutree.c @@ -91,8 +91,9 @@ EXPORT_SYMBOL_GPL(rcu_scheduler_active); * handle all flavors of RCU. */ static DEFINE_PER_CPU(struct task_struct *, rcu_cpu_kthread_task); +DEFINE_PER_CPU(unsigned int, rcu_cpu_kthread_status); static DEFINE_PER_CPU(wait_queue_head_t, rcu_cpu_wq); -static DEFINE_PER_CPU(char, rcu_cpu_has_work); +DEFINE_PER_CPU(char, rcu_cpu_has_work); static char rcu_kthreads_spawnable; static void rcu_node_kthread_setaffinity(struct rcu_node *rnp, int outgoingcpu); @@ -1563,11 +1564,13 @@ static int rcu_cpu_kthread(void *arg) int cpu = (int)(long)arg; unsigned long flags; int spincnt = 0; + unsigned int *statusp = &per_cpu(rcu_cpu_kthread_status, cpu); wait_queue_head_t *wqp = &per_cpu(rcu_cpu_wq, cpu); char work; char *workp = &per_cpu(rcu_cpu_has_work, cpu); for (;;) { + *statusp = RCU_KTHREAD_WAITING; wait_event_interruptible(*wqp, *workp != 0 || kthread_should_stop()); local_bh_disable(); @@ -1575,6 +1578,7 @@ static int rcu_cpu_kthread(void *arg) local_bh_enable(); break; } + *statusp = RCU_KTHREAD_RUNNING; local_irq_save(flags); work = *workp; *workp = 0; @@ -1587,10 +1591,12 @@ static int rcu_cpu_kthread(void *arg) else spincnt = 0; if (spincnt > 10) { + *statusp = RCU_KTHREAD_YIELDING; rcu_yield(rcu_cpu_kthread_timer, (unsigned long)cpu); spincnt = 0; } } + *statusp = RCU_KTHREAD_STOPPED; return 0; } @@ -1637,10 +1643,12 @@ static int rcu_node_kthread(void *arg) struct task_struct *t; for (;;) { + rnp->node_kthread_status = RCU_KTHREAD_WAITING; wait_event_interruptible(rnp->node_wq, rnp->wakemask != 0 || kthread_should_stop()); if (kthread_should_stop()) break; + rnp->node_kthread_status = RCU_KTHREAD_RUNNING; raw_spin_lock_irqsave(&rnp->lock, flags); mask = rnp->wakemask; rnp->wakemask = 0; @@ -1661,6 +1669,7 @@ static int rcu_node_kthread(void *arg) preempt_enable(); } } + rnp->node_kthread_status = RCU_KTHREAD_STOPPED; return 0; } diff --git a/kernel/rcutree.h b/kernel/rcutree.h index d49046c..67341db 100644 --- a/kernel/rcutree.h +++ b/kernel/rcutree.h @@ -89,6 +89,13 @@ struct rcu_dynticks { atomic_t dynticks; /* Even value for dynticks-idle, else odd. */ }; +/* RCU's kthread states for tracing. */ +#define RCU_KTHREAD_STOPPED 0 +#define RCU_KTHREAD_RUNNING 1 +#define RCU_KTHREAD_WAITING 2 +#define RCU_KTHREAD_YIELDING 3 +#define RCU_KTHREAD_MAX 3 + /* * Definition for node within the RCU grace-period-detection hierarchy. */ @@ -152,6 +159,8 @@ struct rcu_node { wait_queue_head_t boost_wq; /* Wait queue on which to park the boost */ /* kthread. */ + unsigned int boost_kthread_status; + /* State of boost_kthread_task for tracing. */ unsigned long n_tasks_boosted; /* Total number of tasks boosted. */ unsigned long n_exp_boosts; @@ -179,6 +188,8 @@ struct rcu_node { wait_queue_head_t node_wq; /* Wait queue on which to park the per-node */ /* kthread. */ + unsigned int node_kthread_status; + /* State of node_kthread_task for tracing. */ } ____cacheline_internodealigned_in_smp; /* diff --git a/kernel/rcutree_plugin.h b/kernel/rcutree_plugin.h index 07d3464..22a6a46 100644 --- a/kernel/rcutree_plugin.h +++ b/kernel/rcutree_plugin.h @@ -1198,11 +1198,13 @@ static int rcu_boost_kthread(void *arg) int more2boost; for (;;) { + rnp->boost_kthread_status = RCU_KTHREAD_WAITING; wait_event_interruptible(rnp->boost_wq, rnp->boost_tasks || rnp->exp_tasks || kthread_should_stop()); if (kthread_should_stop()) break; + rnp->boost_kthread_status = RCU_KTHREAD_RUNNING; more2boost = rcu_boost(rnp); if (more2boost) spincnt++; @@ -1213,6 +1215,7 @@ static int rcu_boost_kthread(void *arg) spincnt = 0; } } + rnp->boost_kthread_status = RCU_KTHREAD_STOPPED; return 0; } diff --git a/kernel/rcutree_trace.c b/kernel/rcutree_trace.c index afd262f..fc40e89 100644 --- a/kernel/rcutree_trace.c +++ b/kernel/rcutree_trace.c @@ -46,6 +46,16 @@ #define RCU_TREE_NONCORE #include "rcutree.h" +DECLARE_PER_CPU(unsigned int, rcu_cpu_kthread_status); +DECLARE_PER_CPU(char, rcu_cpu_has_work); + +static char convert_kthread_status(unsigned int kthread_status) +{ + if (kthread_status > RCU_KTHREAD_MAX) + return '?'; + return "SRWY"[kthread_status]; +} + static void print_one_rcu_data(struct seq_file *m, struct rcu_data *rdp) { if (!rdp->beenonline) @@ -64,7 +74,7 @@ static void print_one_rcu_data(struct seq_file *m, struct rcu_data *rdp) rdp->dynticks_fqs); #endif /* #ifdef CONFIG_NO_HZ */ seq_printf(m, " of=%lu ri=%lu", rdp->offline_fqs, rdp->resched_ipi); - seq_printf(m, " ql=%ld qs=%c%c%c%c b=%ld", + seq_printf(m, " ql=%ld qs=%c%c%c%c kt=%d/%c b=%ld", rdp->qlen, ".N"[rdp->nxttail[RCU_NEXT_READY_TAIL] != rdp->nxttail[RCU_NEXT_TAIL]], @@ -73,6 +83,9 @@ static void print_one_rcu_data(struct seq_file *m, struct rcu_data *rdp) ".W"[rdp->nxttail[RCU_DONE_TAIL] != rdp->nxttail[RCU_WAIT_TAIL]], ".D"[&rdp->nxtlist != rdp->nxttail[RCU_DONE_TAIL]], + per_cpu(rcu_cpu_has_work, rdp->cpu), + convert_kthread_status(per_cpu(rcu_cpu_kthread_status, + rdp->cpu)), rdp->blimit); seq_printf(m, " ci=%lu co=%lu ca=%lu\n", rdp->n_cbs_invoked, rdp->n_cbs_orphaned, rdp->n_cbs_adopted); @@ -130,7 +143,7 @@ static void print_one_rcu_data_csv(struct seq_file *m, struct rcu_data *rdp) rdp->dynticks_fqs); #endif /* #ifdef CONFIG_NO_HZ */ seq_printf(m, ",%lu,%lu", rdp->offline_fqs, rdp->resched_ipi); - seq_printf(m, ",%ld,\"%c%c%c%c\",%ld", rdp->qlen, + seq_printf(m, ",%ld,\"%c%c%c%c\",%d,\"%c\",%ld", rdp->qlen, ".N"[rdp->nxttail[RCU_NEXT_READY_TAIL] != rdp->nxttail[RCU_NEXT_TAIL]], ".R"[rdp->nxttail[RCU_WAIT_TAIL] != @@ -138,6 +151,9 @@ static void print_one_rcu_data_csv(struct seq_file *m, struct rcu_data *rdp) ".W"[rdp->nxttail[RCU_DONE_TAIL] != rdp->nxttail[RCU_WAIT_TAIL]], ".D"[&rdp->nxtlist != rdp->nxttail[RCU_DONE_TAIL]], + per_cpu(rcu_cpu_has_work, rdp->cpu), + convert_kthread_status(per_cpu(rcu_cpu_kthread_status, + rdp->cpu)), rdp->blimit); seq_printf(m, ",%lu,%lu,%lu\n", rdp->n_cbs_invoked, rdp->n_cbs_orphaned, rdp->n_cbs_adopted); @@ -178,13 +194,14 @@ static const struct file_operations rcudata_csv_fops = { static void print_one_rcu_node_boost(struct seq_file *m, struct rcu_node *rnp) { - seq_printf(m, "%d:%d tasks=%c%c%c%c ntb=%lu neb=%lu nnb=%lu " + seq_printf(m, "%d:%d tasks=%c%c%c%c kt=%c ntb=%lu neb=%lu nnb=%lu " "j=%04x bt=%04x\n", rnp->grplo, rnp->grphi, "T."[list_empty(&rnp->blkd_tasks)], "N."[!rnp->gp_tasks], "E."[!rnp->exp_tasks], "B."[!rnp->boost_tasks], + convert_kthread_status(rnp->boost_kthread_status), rnp->n_tasks_boosted, rnp->n_exp_boosts, rnp->n_normal_boosts, (int)(jiffies & 0xffff), -- cgit v0.10.2 From 4a29865689dbb87a02e3b0fff4a4ae5041273173 Mon Sep 17 00:00:00 2001 From: "Paul E. McKenney" Date: Sun, 3 Apr 2011 21:33:51 -0700 Subject: rcu: make rcutorture version numbers available through debugfs It is not possible to accurately correlate rcutorture output with that of debugfs. This patch therefore adds a debugfs file that prints out the rcutorture version number, permitting easy correlation. Signed-off-by: Paul E. McKenney Signed-off-by: Paul E. McKenney Reviewed-by: Josh Triplett diff --git a/include/linux/rcupdate.h b/include/linux/rcupdate.h index ff422d2..9e169c2 100644 --- a/include/linux/rcupdate.h +++ b/include/linux/rcupdate.h @@ -47,6 +47,18 @@ extern int rcutorture_runnable; /* for sysctl */ #endif /* #ifdef CONFIG_RCU_TORTURE_TEST */ +#if defined(CONFIG_TREE_RCU) || defined(CONFIG_TREE_PREEMPT_RCU) +extern void rcutorture_record_test_transition(void); +extern void rcutorture_record_progress(unsigned long vernum); +#else +static inline void rcutorture_record_test_transition(void) +{ +} +static inline void rcutorture_record_progress(unsigned long vernum) +{ +} +#endif + #define UINT_CMP_GE(a, b) (UINT_MAX / 2 >= (a) - (b)) #define UINT_CMP_LT(a, b) (UINT_MAX / 2 < (a) - (b)) #define ULONG_CMP_GE(a, b) (ULONG_MAX / 2 >= (a) - (b)) @@ -68,7 +80,6 @@ extern void call_rcu_sched(struct rcu_head *head, extern void synchronize_sched(void); extern void rcu_barrier_bh(void); extern void rcu_barrier_sched(void); -extern int sched_expedited_torture_stats(char *page); static inline void __rcu_read_lock_bh(void) { diff --git a/include/linux/rcutree.h b/include/linux/rcutree.h index 3a93348..284dad1 100644 --- a/include/linux/rcutree.h +++ b/include/linux/rcutree.h @@ -58,9 +58,12 @@ static inline void synchronize_rcu_bh_expedited(void) extern void rcu_barrier(void); +extern unsigned long rcutorture_testseq; +extern unsigned long rcutorture_vernum; extern long rcu_batches_completed(void); extern long rcu_batches_completed_bh(void); extern long rcu_batches_completed_sched(void); + extern void rcu_force_quiescent_state(void); extern void rcu_bh_force_quiescent_state(void); extern void rcu_sched_force_quiescent_state(void); diff --git a/kernel/rcutorture.c b/kernel/rcutorture.c index 22b0e74..c2f58ec 100644 --- a/kernel/rcutorture.c +++ b/kernel/rcutorture.c @@ -131,7 +131,7 @@ struct rcu_torture { static LIST_HEAD(rcu_torture_freelist); static struct rcu_torture __rcu *rcu_torture_current; -static long rcu_torture_current_version; +static unsigned long rcu_torture_current_version; static struct rcu_torture rcu_tortures[10 * RCU_TORTURE_PIPE_LEN]; static DEFINE_SPINLOCK(rcu_torture_lock); static DEFINE_PER_CPU(long [RCU_TORTURE_PIPE_LEN + 1], rcu_torture_count) = @@ -884,7 +884,7 @@ rcu_torture_writer(void *arg) old_rp->rtort_pipe_count++; cur_ops->deferred_free(old_rp); } - rcu_torture_current_version++; + rcutorture_record_progress(++rcu_torture_current_version); oldbatch = cur_ops->completed(); rcu_stutter_wait("rcu_torture_writer"); } while (!kthread_should_stop() && fullstop == FULLSTOP_DONTSTOP); @@ -1064,7 +1064,7 @@ rcu_torture_printk(char *page) } cnt += sprintf(&page[cnt], "%s%s ", torture_type, TORTURE_FLAG); cnt += sprintf(&page[cnt], - "rtc: %p ver: %ld tfle: %d rta: %d rtaf: %d rtf: %d " + "rtc: %p ver: %lu tfle: %d rta: %d rtaf: %d rtf: %d " "rtmbe: %d rtbke: %ld rtbre: %ld " "rtbf: %ld rtb: %ld nt: %ld", rcu_torture_current, @@ -1325,6 +1325,7 @@ rcu_torture_cleanup(void) int i; mutex_lock(&fullstop_mutex); + rcutorture_record_test_transition(); if (fullstop == FULLSTOP_SHUTDOWN) { printk(KERN_WARNING /* but going down anyway, so... */ "Concurrent 'rmmod rcutorture' and shutdown illegal!\n"); @@ -1616,6 +1617,7 @@ rcu_torture_init(void) } } register_reboot_notifier(&rcutorture_shutdown_nb); + rcutorture_record_test_transition(); mutex_unlock(&fullstop_mutex); return 0; diff --git a/kernel/rcutree.c b/kernel/rcutree.c index d891740..bb84dec 100644 --- a/kernel/rcutree.c +++ b/kernel/rcutree.c @@ -102,6 +102,18 @@ static void invoke_rcu_cpu_kthread(void); #define RCU_KTHREAD_PRIO 1 /* RT priority for per-CPU kthreads. */ /* + * Track the rcutorture test sequence number and the update version + * number within a given test. The rcutorture_testseq is incremented + * on every rcutorture module load and unload, so has an odd value + * when a test is running. The rcutorture_vernum is set to zero + * when rcutorture starts and is incremented on each rcutorture update. + * These variables enable correlating rcutorture output with the + * RCU tracing information. + */ +unsigned long rcutorture_testseq; +unsigned long rcutorture_vernum; + +/* * Return true if an RCU grace period is in progress. The ACCESS_ONCE()s * permit this function to be invoked without holding the root rcu_node * structure's ->lock, but of course results can be subject to change. @@ -193,6 +205,31 @@ void rcu_bh_force_quiescent_state(void) EXPORT_SYMBOL_GPL(rcu_bh_force_quiescent_state); /* + * Record the number of times rcutorture tests have been initiated and + * terminated. This information allows the debugfs tracing stats to be + * correlated to the rcutorture messages, even when the rcutorture module + * is being repeatedly loaded and unloaded. In other words, we cannot + * store this state in rcutorture itself. + */ +void rcutorture_record_test_transition(void) +{ + rcutorture_testseq++; + rcutorture_vernum = 0; +} +EXPORT_SYMBOL_GPL(rcutorture_record_test_transition); + +/* + * Record the number of writer passes through the current rcutorture test. + * This is also used to correlate debugfs tracing stats with the rcutorture + * messages. + */ +void rcutorture_record_progress(unsigned long vernum) +{ + rcutorture_vernum++; +} +EXPORT_SYMBOL_GPL(rcutorture_record_progress); + +/* * Force a quiescent state for RCU-sched. */ void rcu_sched_force_quiescent_state(void) diff --git a/kernel/rcutree_trace.c b/kernel/rcutree_trace.c index fc40e89..3baa235 100644 --- a/kernel/rcutree_trace.c +++ b/kernel/rcutree_trace.c @@ -394,6 +394,29 @@ static const struct file_operations rcu_pending_fops = { .release = single_release, }; +static int show_rcutorture(struct seq_file *m, void *unused) +{ + seq_printf(m, "rcutorture test sequence: %lu %s\n", + rcutorture_testseq >> 1, + (rcutorture_testseq & 0x1) ? "(test in progress)" : ""); + seq_printf(m, "rcutorture update version number: %lu\n", + rcutorture_vernum); + return 0; +} + +static int rcutorture_open(struct inode *inode, struct file *file) +{ + return single_open(file, show_rcutorture, NULL); +} + +static const struct file_operations rcutorture_fops = { + .owner = THIS_MODULE, + .open = rcutorture_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + static struct dentry *rcudir; static int __init rcutree_trace_init(void) @@ -430,6 +453,11 @@ static int __init rcutree_trace_init(void) NULL, &rcu_pending_fops); if (!retval) goto free_out; + + retval = debugfs_create_file("rcutorture", 0444, rcudir, + NULL, &rcutorture_fops); + if (!retval) + goto free_out; return 0; free_out: debugfs_remove_recursive(rcudir); -- cgit v0.10.2 From 90e6ac3657fd3b0446d585082000af3cf46439a7 Mon Sep 17 00:00:00 2001 From: "Paul E. McKenney" Date: Wed, 6 Apr 2011 15:20:47 -0700 Subject: rcu: update tracing documentation for new rcutorture and rcuboost This commit documents the new debugfs rcu/rcutorture and rcu/rcuboost trace files. The description has been updated as suggested by Josh Triplett. Signed-off-by: Paul E. McKenney Signed-off-by: Paul E. McKenney diff --git a/Documentation/RCU/trace.txt b/Documentation/RCU/trace.txt index 5aefd5f..40b530d 100644 --- a/Documentation/RCU/trace.txt +++ b/Documentation/RCU/trace.txt @@ -10,34 +10,46 @@ for rcutree and next for rcutiny. CONFIG_TREE_RCU and CONFIG_TREE_PREEMPT_RCU debugfs Files and Formats -These implementations of RCU provides five debugfs files under the -top-level directory RCU: rcu/rcudata (which displays fields in struct -rcu_data), rcu/rcudata.csv (which is a .csv spreadsheet version of -rcu/rcudata), rcu/rcugp (which displays grace-period counters), -rcu/rcuhier (which displays the struct rcu_node hierarchy), and -rcu/rcu_pending (which displays counts of the reasons that the -rcu_pending() function decided that there was core RCU work to do). +These implementations of RCU provides several debugfs files under the +top-level directory "rcu": + +rcu/rcudata: + Displays fields in struct rcu_data. +rcu/rcudata.csv: + Comma-separated values spreadsheet version of rcudata. +rcu/rcugp: + Displays grace-period counters. +rcu/rcuhier: + Displays the struct rcu_node hierarchy. +rcu/rcu_pending: + Displays counts of the reasons rcu_pending() decided that RCU had + work to do. +rcu/rcutorture: + Displays rcutorture test progress. +rcu/rcuboost: + Displays RCU boosting statistics. Only present if + CONFIG_RCU_BOOST=y. The output of "cat rcu/rcudata" looks as follows: rcu_sched: - 0!c=423090 g=423091 pq=1 pqc=423090 qp=1 dt=86475/1/0 df=16319 of=163 ri=1519 ql=0 qs=.... b=10 ci=1460693 co=1648 ca=6448 - 1!c=423329 g=423330 pq=1 pqc=423329 qp=1 dt=90875/1/0 df=16231 of=157 ri=1249 ql=0 qs=.... b=10 ci=1459002 co=1614 ca=3310 - 2!c=423370 g=423371 pq=1 pqc=423370 qp=1 dt=69661/1/0 df=16125 of=163 ri=1469 ql=0 qs=.... b=10 ci=1610701 co=2015 ca=2378 - 3!c=422967 g=422968 pq=1 pqc=422967 qp=1 dt=70349/1/0 df=12528 of=163 ri=1450 ql=0 qs=.... b=10 ci=1427543 co=1430 ca=897 - 4!c=423196 g=423197 pq=1 pqc=423196 qp=0 dt=38935/1/0 df=10959 of=177 ri=1657 ql=0 qs=.... b=10 ci=1562249 co=1896 ca=533 - 5!c=422950 g=422951 pq=1 pqc=422950 qp=0 dt=25127/1/0 df=5895 of=167 ri=1549 ql=0 qs=.... b=10 ci=1777260 co=2137 ca=274 - 6!c=423396 g=423397 pq=1 pqc=423396 qp=1 dt=22639/1/0 df=4590 of=149 ri=1572 ql=0 qs=.... b=10 ci=1471186 co=1530 ca=243 - 7 c=460203 g=460203 pq=1 pqc=460202 qp=0 dt=937087/1/0 df=3298 of=149 ri=1584 ql=6 qs=N.W. b=10 ci=4026154 co=1948 ca=135 + 0!c=423090 g=423091 pq=1 pqc=423090 qp=1 dt=86475/1/0 df=16319 of=163 ri=1519 ql=0 qs=.... kt=0/W b=10 ci=1460693 co=1648 ca=6448 + 1!c=423329 g=423330 pq=1 pqc=423329 qp=1 dt=90875/1/0 df=16231 of=157 ri=1249 ql=0 qs=.... kt=0/W b=10 ci=1459002 co=1614 ca=3310 + 2!c=423370 g=423371 pq=1 pqc=423370 qp=1 dt=69661/1/0 df=16125 of=163 ri=1469 ql=0 qs=.... kt=0/W b=10 ci=1610701 co=2015 ca=2378 + 3!c=422967 g=422968 pq=1 pqc=422967 qp=1 dt=70349/1/0 df=12528 of=163 ri=1450 ql=0 qs=.... kt=0/W b=10 ci=1427543 co=1430 ca=897 + 4!c=423196 g=423197 pq=1 pqc=423196 qp=0 dt=38935/1/0 df=10959 of=177 ri=1657 ql=0 qs=.... kt=0/W b=10 ci=1562249 co=1896 ca=533 + 5!c=422950 g=422951 pq=1 pqc=422950 qp=0 dt=25127/1/0 df=5895 of=167 ri=1549 ql=0 qs=.... kt=0/W b=10 ci=1777260 co=2137 ca=274 + 6!c=423396 g=423397 pq=1 pqc=423396 qp=1 dt=22639/1/0 df=4590 of=149 ri=1572 ql=0 qs=.... kt=0/W b=10 ci=1471186 co=1530 ca=243 + 7 c=460203 g=460203 pq=1 pqc=460202 qp=0 dt=937087/1/0 df=3298 of=149 ri=1584 ql=6 qs=N.W. kt=0/W b=10 ci=4026154 co=1948 ca=135 rcu_bh: - 0!c=18446744073709551494 g=18446744073709551494 pq=0 pqc=18446744073709551493 qp=1 dt=86475/1/0 df=11 of=0 ri=0 ql=0 qs=.... b=10 ci=112 co=0 ca=0 - 1!c=18446744073709551496 g=18446744073709551496 pq=1 pqc=18446744073709551495 qp=0 dt=90875/1/0 df=15 of=0 ri=0 ql=0 qs=.... b=10 ci=143 co=0 ca=0 - 2!c=18446744073709551496 g=18446744073709551496 pq=1 pqc=18446744073709551495 qp=0 dt=69661/1/0 df=21 of=0 ri=1 ql=0 qs=.... b=10 ci=88 co=0 ca=0 - 3!c=18446744073709551494 g=18446744073709551494 pq=1 pqc=18446744073709551493 qp=0 dt=70349/1/0 df=13 of=0 ri=0 ql=0 qs=.... b=10 ci=100 co=0 ca=0 - 4!c=18446744073709551494 g=18446744073709551494 pq=0 pqc=18446744073709551493 qp=1 dt=38935/1/0 df=17 of=0 ri=0 ql=0 qs=.... b=10 ci=36 co=0 ca=0 - 5!c=18446744073709551494 g=18446744073709551494 pq=0 pqc=18446744073709551493 qp=1 dt=25127/1/0 df=7 of=0 ri=0 ql=0 qs=.... b=10 ci=32 co=0 ca=0 - 6!c=18446744073709551496 g=18446744073709551496 pq=1 pqc=18446744073709551495 qp=0 dt=22639/1/0 df=9 of=0 ri=0 ql=0 qs=.... b=10 ci=44 co=0 ca=0 - 7 c=182 g=182 pq=1 pqc=181 qp=0 dt=937087/1/0 df=14 of=0 ri=1 ql=0 qs=.... b=10 ci=627 co=0 ca=0 + 0!c=18446744073709551494 g=18446744073709551494 pq=0 pqc=18446744073709551493 qp=1 dt=86475/1/0 df=11 of=0 ri=0 ql=0 qs=.... kt=0/W b=10 ci=112 co=0 ca=0 + 1!c=18446744073709551496 g=18446744073709551496 pq=1 pqc=18446744073709551495 qp=0 dt=90875/1/0 df=15 of=0 ri=0 ql=0 qs=.... kt=0/W b=10 ci=143 co=0 ca=0 + 2!c=18446744073709551496 g=18446744073709551496 pq=1 pqc=18446744073709551495 qp=0 dt=69661/1/0 df=21 of=0 ri=1 ql=0 qs=.... kt=0/W b=10 ci=88 co=0 ca=0 + 3!c=18446744073709551494 g=18446744073709551494 pq=1 pqc=18446744073709551493 qp=0 dt=70349/1/0 df=13 of=0 ri=0 ql=0 qs=.... kt=0/W b=10 ci=100 co=0 ca=0 + 4!c=18446744073709551494 g=18446744073709551494 pq=0 pqc=18446744073709551493 qp=1 dt=38935/1/0 df=17 of=0 ri=0 ql=0 qs=.... kt=0/W b=10 ci=36 co=0 ca=0 + 5!c=18446744073709551494 g=18446744073709551494 pq=0 pqc=18446744073709551493 qp=1 dt=25127/1/0 df=7 of=0 ri=0 ql=0 qs=.... kt=0/W b=10 ci=32 co=0 ca=0 + 6!c=18446744073709551496 g=18446744073709551496 pq=1 pqc=18446744073709551495 qp=0 dt=22639/1/0 df=9 of=0 ri=0 ql=0 qs=.... kt=0/W b=10 ci=44 co=0 ca=0 + 7 c=182 g=182 pq=1 pqc=181 qp=0 dt=937087/1/0 df=14 of=0 ri=1 ql=0 qs=.... kt=0/W b=10 ci=627 co=0 ca=0 The first section lists the rcu_data structures for rcu_sched, the second for rcu_bh. Note that CONFIG_TREE_PREEMPT_RCU kernels will have an @@ -146,6 +158,23 @@ o "qs" gives an indication of the state of the callback queue If there are no callbacks in a given one of the above states, the corresponding character is replaced by ".". +o "kt" is the per-CPU kernel-thread state. The digit preceding + the slash is zero if there is no work pending and 1 otherwise. + The character after the slash is as follows: + + "S" The kernel thread is stopped, in other words, all + CPUs corresponding to this rcu_node structure are + offline. + + "R" The kernel thread is running. + + "W" The kernel thread is waiting because there is no work + for it to do. + + "Y" The kernel thread is yielding to avoid hogging CPU. + + "?" Unknown value, indicates a bug. + o "b" is the batch limit for this CPU. If more than this number of RCU callbacks is ready to invoke, then the remainder will be deferred. @@ -356,6 +385,113 @@ o "nn" is the number of times that this CPU needed nothing. Alert is due to short-circuit evaluation in rcu_pending(). +The output of "cat rcu/rcutorture" looks as follows: + +rcutorture test sequence: 0 (test in progress) +rcutorture update version number: 615 + +The first line shows the number of rcutorture tests that have completed +since boot. If a test is currently running, the "(test in progress)" +string will appear as shown above. The second line shows the number of +update cycles that the current test has started, or zero if there is +no test in progress. + + +The output of "cat rcu/rcuboost" looks as follows: + +0:5 tasks=.... kt=W ntb=0 neb=0 nnb=0 j=2f95 bt=300f + balk: nt=0 egt=989 bt=0 nb=0 ny=0 nos=16 +6:7 tasks=.... kt=W ntb=0 neb=0 nnb=0 j=2f95 bt=300f + balk: nt=0 egt=225 bt=0 nb=0 ny=0 nos=6 + +This information is output only for rcu_preempt. Each two-line entry +corresponds to a leaf rcu_node strcuture. The fields are as follows: + +o "n:m" is the CPU-number range for the corresponding two-line + entry. In the sample output above, the first entry covers + CPUs zero through five and the second entry covers CPUs 6 + and 7. + +o "tasks=TNEB" gives the state of the various segments of the + rnp->blocked_tasks list: + + "T" This indicates that there are some tasks that blocked + while running on one of the corresponding CPUs while + in an RCU read-side critical section. + + "N" This indicates that some of the blocked tasks are preventing + the current normal (non-expedited) grace period from + completing. + + "E" This indicates that some of the blocked tasks are preventing + the current expedited grace period from completing. + + "B" This indicates that some of the blocked tasks are in + need of RCU priority boosting. + + Each character is replaced with "." if the corresponding + condition does not hold. + +o "kt" is the state of the RCU priority-boosting kernel + thread associated with the corresponding rcu_node structure. + The state can be one of the following: + + "S" The kernel thread is stopped, in other words, all + CPUs corresponding to this rcu_node structure are + offline. + + "R" The kernel thread is running. + + "W" The kernel thread is waiting because there is no work + for it to do. + + "Y" The kernel thread is yielding to avoid hogging CPU. + + "?" Unknown value, indicates a bug. + +o "ntb" is the number of tasks boosted. + +o "neb" is the number of tasks boosted in order to complete an + expedited grace period. + +o "nnb" is the number of tasks boosted in order to complete a + normal (non-expedited) grace period. When boosting a task + that was blocking both an expedited and a normal grace period, + it is counted against the expedited total above. + +o "j" is the low-order 16 bits of the jiffies counter in + hexadecimal. + +o "bt" is the low-order 16 bits of the value that the jiffies + counter will have when we next start boosting, assuming that + the current grace period does not end beforehand. This is + also in hexadecimal. + +o "balk: nt" counts the number of times we didn't boost (in + other words, we balked) even though it was time to boost because + there were no blocked tasks to boost. This situation occurs + when there is one blocked task on one rcu_node structure and + none on some other rcu_node structure. + +o "egt" counts the number of times we balked because although + there were blocked tasks, none of them were blocking the + current grace period, whether expedited or otherwise. + +o "bt" counts the number of times we balked because boosting + had already been initiated for the current grace period. + +o "nb" counts the number of times we balked because there + was at least one task blocking the current non-expedited grace + period that never had blocked. If it is already running, it + just won't help to boost its priority! + +o "ny" counts the number of times we balked because it was + not yet time to start boosting. + +o "nos" counts the number of times we balked for other + reasons, e.g., the grace period ended first. + + CONFIG_TINY_RCU and CONFIG_TINY_PREEMPT_RCU debugfs Files and Formats These implementations of RCU provides a single debugfs file under the @@ -422,9 +558,9 @@ o "neb" is the number of expedited grace periods that have had o "nnb" is the number of normal grace periods that have had to resort to RCU priority boosting since boot. -o "j" is the low-order 12 bits of the jiffies counter in hexadecimal. +o "j" is the low-order 16 bits of the jiffies counter in hexadecimal. -o "bt" is the low-order 12 bits of the value that the jiffies counter +o "bt" is the low-order 16 bits of the value that the jiffies counter will have at the next time that boosting is scheduled to begin. o In the line beginning with "normal balk", the fields are as follows: -- cgit v0.10.2 From a9f4793d8900dc5dc09b3951bdcd4731290e06fe Mon Sep 17 00:00:00 2001 From: "Paul E. McKenney" Date: Mon, 2 May 2011 03:46:10 -0700 Subject: rcu: fix tracing bug thinko on boost-balk attribution The rcu_initiate_boost_trace() function mis-attributed refusals to initiate RCU priority boosting that were in fact due to its not yet being time to boost. This patch fixes the faulty comparison. Signed-off-by: Paul E. McKenney Signed-off-by: Paul E. McKenney diff --git a/kernel/rcutree_plugin.h b/kernel/rcutree_plugin.h index 22a6a46..a21413d 100644 --- a/kernel/rcutree_plugin.h +++ b/kernel/rcutree_plugin.h @@ -1086,7 +1086,7 @@ static void rcu_initiate_boost_trace(struct rcu_node *rnp) else if (rnp->gp_tasks != NULL && rnp->qsmask != 0) rnp->n_balk_notblocked++; else if (rnp->gp_tasks != NULL && - ULONG_CMP_GE(jiffies, rnp->boost_time)) + ULONG_CMP_LT(jiffies, rnp->boost_time)) rnp->n_balk_notyet++; else rnp->n_balk_nos++; -- cgit v0.10.2 From 15ba0ba860871cf74b48b1bb47c26c91a66126f3 Mon Sep 17 00:00:00 2001 From: "Paul E. McKenney" Date: Wed, 6 Apr 2011 16:01:16 -0700 Subject: rcu: add grace-period age and more kthread state to tracing This commit adds the age in jiffies of the current grace period along with the duration in jiffies of the longest grace period since boot to the rcu/rcugp debugfs file. It also adds an additional "O" state to kthread tracing to differentiate between the kthread waiting due to having nothing to do on the one hand and waiting due to being on the wrong CPU on the other hand. Signed-off-by: Paul E. McKenney Signed-off-by: Paul E. McKenney diff --git a/Documentation/RCU/trace.txt b/Documentation/RCU/trace.txt index 40b530d..fd4bffb 100644 --- a/Documentation/RCU/trace.txt +++ b/Documentation/RCU/trace.txt @@ -159,8 +159,8 @@ o "qs" gives an indication of the state of the callback queue the corresponding character is replaced by ".". o "kt" is the per-CPU kernel-thread state. The digit preceding - the slash is zero if there is no work pending and 1 otherwise. - The character after the slash is as follows: + the first slash is zero if there is no work pending and 1 + otherwise. The character between the slashes is as follows: "S" The kernel thread is stopped, in other words, all CPUs corresponding to this rcu_node structure are @@ -171,10 +171,18 @@ o "kt" is the per-CPU kernel-thread state. The digit preceding "W" The kernel thread is waiting because there is no work for it to do. + "O" The kernel thread is waiting because it has been + forced off of its designated CPU or because its + ->cpus_allowed mask permits it to run on other than + its designated CPU. + "Y" The kernel thread is yielding to avoid hogging CPU. "?" Unknown value, indicates a bug. + The number after the final slash is the CPU that the kthread + is actually running on. + o "b" is the batch limit for this CPU. If more than this number of RCU callbacks is ready to invoke, then the remainder will be deferred. diff --git a/kernel/rcutree.c b/kernel/rcutree.c index bb84dec..27b6d8d 100644 --- a/kernel/rcutree.c +++ b/kernel/rcutree.c @@ -92,6 +92,7 @@ EXPORT_SYMBOL_GPL(rcu_scheduler_active); */ static DEFINE_PER_CPU(struct task_struct *, rcu_cpu_kthread_task); DEFINE_PER_CPU(unsigned int, rcu_cpu_kthread_status); +DEFINE_PER_CPU(int, rcu_cpu_kthread_cpu); static DEFINE_PER_CPU(wait_queue_head_t, rcu_cpu_wq); DEFINE_PER_CPU(char, rcu_cpu_has_work); static char rcu_kthreads_spawnable; @@ -888,6 +889,8 @@ rcu_start_gp(struct rcu_state *rsp, unsigned long flags) static void rcu_report_qs_rsp(struct rcu_state *rsp, unsigned long flags) __releases(rcu_get_root(rsp)->lock) { + unsigned long gp_duration; + WARN_ON_ONCE(!rcu_gp_in_progress(rsp)); /* @@ -895,6 +898,9 @@ static void rcu_report_qs_rsp(struct rcu_state *rsp, unsigned long flags) * is seen before the assignment to rsp->completed. */ smp_mb(); /* See above block comment. */ + gp_duration = jiffies - rsp->gp_start; + if (gp_duration > rsp->gp_max) + rsp->gp_max = gp_duration; rsp->completed = rsp->gpnum; rsp->signaled = RCU_GP_IDLE; rcu_start_gp(rsp, flags); /* releases root node's rnp->lock. */ @@ -1583,12 +1589,15 @@ static int rcu_cpu_kthread_should_stop(int cpu) smp_processor_id() != cpu) { if (kthread_should_stop()) return 1; + per_cpu(rcu_cpu_kthread_status, cpu) = RCU_KTHREAD_OFFCPU; + per_cpu(rcu_cpu_kthread_cpu, cpu) = raw_smp_processor_id(); local_bh_enable(); schedule_timeout_uninterruptible(1); if (!cpumask_equal(¤t->cpus_allowed, cpumask_of(cpu))) set_cpus_allowed_ptr(current, cpumask_of(cpu)); local_bh_disable(); } + per_cpu(rcu_cpu_kthread_cpu, cpu) = cpu; return 0; } @@ -1656,6 +1665,7 @@ static int __cpuinit rcu_spawn_one_cpu_kthread(int cpu) if (IS_ERR(t)) return PTR_ERR(t); kthread_bind(t, cpu); + per_cpu(rcu_cpu_kthread_cpu, cpu) = cpu; WARN_ON_ONCE(per_cpu(rcu_cpu_kthread_task, cpu) != NULL); per_cpu(rcu_cpu_kthread_task, cpu) = t; wake_up_process(t); diff --git a/kernel/rcutree.h b/kernel/rcutree.h index 67341db..37502a2 100644 --- a/kernel/rcutree.h +++ b/kernel/rcutree.h @@ -93,8 +93,9 @@ struct rcu_dynticks { #define RCU_KTHREAD_STOPPED 0 #define RCU_KTHREAD_RUNNING 1 #define RCU_KTHREAD_WAITING 2 -#define RCU_KTHREAD_YIELDING 3 -#define RCU_KTHREAD_MAX 3 +#define RCU_KTHREAD_OFFCPU 3 +#define RCU_KTHREAD_YIELDING 4 +#define RCU_KTHREAD_MAX 4 /* * Definition for node within the RCU grace-period-detection hierarchy. @@ -383,6 +384,8 @@ struct rcu_state { /* but in jiffies. */ unsigned long jiffies_stall; /* Time at which to check */ /* for CPU stalls. */ + unsigned long gp_max; /* Maximum GP duration in */ + /* jiffies. */ char *name; /* Name of structure. */ }; diff --git a/kernel/rcutree_trace.c b/kernel/rcutree_trace.c index 3baa235..564b8fe 100644 --- a/kernel/rcutree_trace.c +++ b/kernel/rcutree_trace.c @@ -47,13 +47,14 @@ #include "rcutree.h" DECLARE_PER_CPU(unsigned int, rcu_cpu_kthread_status); +DECLARE_PER_CPU(unsigned int, rcu_cpu_kthread_cpu); DECLARE_PER_CPU(char, rcu_cpu_has_work); static char convert_kthread_status(unsigned int kthread_status) { if (kthread_status > RCU_KTHREAD_MAX) return '?'; - return "SRWY"[kthread_status]; + return "SRWOY"[kthread_status]; } static void print_one_rcu_data(struct seq_file *m, struct rcu_data *rdp) @@ -74,7 +75,7 @@ static void print_one_rcu_data(struct seq_file *m, struct rcu_data *rdp) rdp->dynticks_fqs); #endif /* #ifdef CONFIG_NO_HZ */ seq_printf(m, " of=%lu ri=%lu", rdp->offline_fqs, rdp->resched_ipi); - seq_printf(m, " ql=%ld qs=%c%c%c%c kt=%d/%c b=%ld", + seq_printf(m, " ql=%ld qs=%c%c%c%c kt=%d/%c/%d b=%ld", rdp->qlen, ".N"[rdp->nxttail[RCU_NEXT_READY_TAIL] != rdp->nxttail[RCU_NEXT_TAIL]], @@ -86,6 +87,7 @@ static void print_one_rcu_data(struct seq_file *m, struct rcu_data *rdp) per_cpu(rcu_cpu_has_work, rdp->cpu), convert_kthread_status(per_cpu(rcu_cpu_kthread_status, rdp->cpu)), + per_cpu(rcu_cpu_kthread_cpu, rdp->cpu), rdp->blimit); seq_printf(m, " ci=%lu co=%lu ca=%lu\n", rdp->n_cbs_invoked, rdp->n_cbs_orphaned, rdp->n_cbs_adopted); @@ -312,16 +314,35 @@ static const struct file_operations rcuhier_fops = { .release = single_release, }; +static void show_one_rcugp(struct seq_file *m, struct rcu_state *rsp) +{ + unsigned long flags; + unsigned long completed; + unsigned long gpnum; + unsigned long gpage; + unsigned long gpmax; + struct rcu_node *rnp = &rsp->node[0]; + + raw_spin_lock_irqsave(&rnp->lock, flags); + completed = rsp->completed; + gpnum = rsp->gpnum; + if (rsp->completed == rsp->gpnum) + gpage = 0; + else + gpage = jiffies - rsp->gp_start; + gpmax = rsp->gp_max; + raw_spin_unlock_irqrestore(&rnp->lock, flags); + seq_printf(m, "%s: completed=%ld gpnum=%lu age=%ld max=%ld\n", + rsp->name, completed, gpnum, gpage, gpmax); +} + static int show_rcugp(struct seq_file *m, void *unused) { #ifdef CONFIG_TREE_PREEMPT_RCU - seq_printf(m, "rcu_preempt: completed=%ld gpnum=%lu\n", - rcu_preempt_state.completed, rcu_preempt_state.gpnum); + show_one_rcugp(m, &rcu_preempt_state); #endif /* #ifdef CONFIG_TREE_PREEMPT_RCU */ - seq_printf(m, "rcu_sched: completed=%ld gpnum=%lu\n", - rcu_sched_state.completed, rcu_sched_state.gpnum); - seq_printf(m, "rcu_bh: completed=%ld gpnum=%lu\n", - rcu_bh_state.completed, rcu_bh_state.gpnum); + show_one_rcugp(m, &rcu_sched_state); + show_one_rcugp(m, &rcu_bh_state); return 0; } -- cgit v0.10.2 From 5ece5bab3ed8594ce2c85c6c6e6b82109db36ca7 Mon Sep 17 00:00:00 2001 From: "Paul E. McKenney" Date: Fri, 22 Apr 2011 18:08:51 -0700 Subject: rcu: Add forward-progress diagnostic for per-CPU kthreads Increment a per-CPU counter on each pass through rcu_cpu_kthread()'s service loop, and add it to the rcudata trace output. Signed-off-by: Paul E. McKenney Signed-off-by: Paul E. McKenney Reviewed-by: Josh Triplett diff --git a/Documentation/RCU/trace.txt b/Documentation/RCU/trace.txt index fd4bffb..8173cec 100644 --- a/Documentation/RCU/trace.txt +++ b/Documentation/RCU/trace.txt @@ -33,23 +33,23 @@ rcu/rcuboost: The output of "cat rcu/rcudata" looks as follows: rcu_sched: - 0!c=423090 g=423091 pq=1 pqc=423090 qp=1 dt=86475/1/0 df=16319 of=163 ri=1519 ql=0 qs=.... kt=0/W b=10 ci=1460693 co=1648 ca=6448 - 1!c=423329 g=423330 pq=1 pqc=423329 qp=1 dt=90875/1/0 df=16231 of=157 ri=1249 ql=0 qs=.... kt=0/W b=10 ci=1459002 co=1614 ca=3310 - 2!c=423370 g=423371 pq=1 pqc=423370 qp=1 dt=69661/1/0 df=16125 of=163 ri=1469 ql=0 qs=.... kt=0/W b=10 ci=1610701 co=2015 ca=2378 - 3!c=422967 g=422968 pq=1 pqc=422967 qp=1 dt=70349/1/0 df=12528 of=163 ri=1450 ql=0 qs=.... kt=0/W b=10 ci=1427543 co=1430 ca=897 - 4!c=423196 g=423197 pq=1 pqc=423196 qp=0 dt=38935/1/0 df=10959 of=177 ri=1657 ql=0 qs=.... kt=0/W b=10 ci=1562249 co=1896 ca=533 - 5!c=422950 g=422951 pq=1 pqc=422950 qp=0 dt=25127/1/0 df=5895 of=167 ri=1549 ql=0 qs=.... kt=0/W b=10 ci=1777260 co=2137 ca=274 - 6!c=423396 g=423397 pq=1 pqc=423396 qp=1 dt=22639/1/0 df=4590 of=149 ri=1572 ql=0 qs=.... kt=0/W b=10 ci=1471186 co=1530 ca=243 - 7 c=460203 g=460203 pq=1 pqc=460202 qp=0 dt=937087/1/0 df=3298 of=149 ri=1584 ql=6 qs=N.W. kt=0/W b=10 ci=4026154 co=1948 ca=135 + 0 c=20972 g=20973 pq=1 pqc=20972 qp=0 dt=545/1/0 df=50 of=0 ri=0 ql=163 qs=NRW. kt=0/W/0 ktl=ebc3 b=10 ci=153737 co=0 ca=0 + 1 c=20972 g=20973 pq=1 pqc=20972 qp=0 dt=967/1/0 df=58 of=0 ri=0 ql=634 qs=NRW. kt=0/W/1 ktl=58c b=10 ci=191037 co=0 ca=0 + 2 c=20972 g=20973 pq=1 pqc=20972 qp=0 dt=1081/1/0 df=175 of=0 ri=0 ql=74 qs=N.W. kt=0/W/2 ktl=da94 b=10 ci=75991 co=0 ca=0 + 3 c=20942 g=20943 pq=1 pqc=20942 qp=1 dt=1846/0/0 df=404 of=0 ri=0 ql=0 qs=.... kt=0/W/3 ktl=d1cd b=10 ci=72261 co=0 ca=0 + 4 c=20972 g=20973 pq=1 pqc=20972 qp=0 dt=369/1/0 df=83 of=0 ri=0 ql=48 qs=N.W. kt=0/W/4 ktl=e0e7 b=10 ci=128365 co=0 ca=0 + 5 c=20972 g=20973 pq=1 pqc=20972 qp=0 dt=381/1/0 df=64 of=0 ri=0 ql=169 qs=NRW. kt=0/W/5 ktl=fb2f b=10 ci=164360 co=0 ca=0 + 6 c=20972 g=20973 pq=1 pqc=20972 qp=0 dt=1037/1/0 df=183 of=0 ri=0 ql=62 qs=N.W. kt=0/W/6 ktl=d2ad b=10 ci=65663 co=0 ca=0 + 7 c=20897 g=20897 pq=1 pqc=20896 qp=0 dt=1572/0/0 df=382 of=0 ri=0 ql=0 qs=.... kt=0/W/7 ktl=cf15 b=10 ci=75006 co=0 ca=0 rcu_bh: - 0!c=18446744073709551494 g=18446744073709551494 pq=0 pqc=18446744073709551493 qp=1 dt=86475/1/0 df=11 of=0 ri=0 ql=0 qs=.... kt=0/W b=10 ci=112 co=0 ca=0 - 1!c=18446744073709551496 g=18446744073709551496 pq=1 pqc=18446744073709551495 qp=0 dt=90875/1/0 df=15 of=0 ri=0 ql=0 qs=.... kt=0/W b=10 ci=143 co=0 ca=0 - 2!c=18446744073709551496 g=18446744073709551496 pq=1 pqc=18446744073709551495 qp=0 dt=69661/1/0 df=21 of=0 ri=1 ql=0 qs=.... kt=0/W b=10 ci=88 co=0 ca=0 - 3!c=18446744073709551494 g=18446744073709551494 pq=1 pqc=18446744073709551493 qp=0 dt=70349/1/0 df=13 of=0 ri=0 ql=0 qs=.... kt=0/W b=10 ci=100 co=0 ca=0 - 4!c=18446744073709551494 g=18446744073709551494 pq=0 pqc=18446744073709551493 qp=1 dt=38935/1/0 df=17 of=0 ri=0 ql=0 qs=.... kt=0/W b=10 ci=36 co=0 ca=0 - 5!c=18446744073709551494 g=18446744073709551494 pq=0 pqc=18446744073709551493 qp=1 dt=25127/1/0 df=7 of=0 ri=0 ql=0 qs=.... kt=0/W b=10 ci=32 co=0 ca=0 - 6!c=18446744073709551496 g=18446744073709551496 pq=1 pqc=18446744073709551495 qp=0 dt=22639/1/0 df=9 of=0 ri=0 ql=0 qs=.... kt=0/W b=10 ci=44 co=0 ca=0 - 7 c=182 g=182 pq=1 pqc=181 qp=0 dt=937087/1/0 df=14 of=0 ri=1 ql=0 qs=.... kt=0/W b=10 ci=627 co=0 ca=0 + 0 c=1480 g=1480 pq=1 pqc=1479 qp=0 dt=545/1/0 df=6 of=0 ri=1 ql=0 qs=.... kt=0/W/0 ktl=ebc3 b=10 ci=0 co=0 ca=0 + 1 c=1480 g=1480 pq=1 pqc=1479 qp=0 dt=967/1/0 df=3 of=0 ri=1 ql=0 qs=.... kt=0/W/1 ktl=58c b=10 ci=151 co=0 ca=0 + 2 c=1480 g=1480 pq=1 pqc=1479 qp=0 dt=1081/1/0 df=6 of=0 ri=1 ql=0 qs=.... kt=0/W/2 ktl=da94 b=10 ci=0 co=0 ca=0 + 3 c=1480 g=1480 pq=1 pqc=1479 qp=0 dt=1846/0/0 df=8 of=0 ri=1 ql=0 qs=.... kt=0/W/3 ktl=d1cd b=10 ci=0 co=0 ca=0 + 4 c=1480 g=1480 pq=1 pqc=1479 qp=0 dt=369/1/0 df=6 of=0 ri=1 ql=0 qs=.... kt=0/W/4 ktl=e0e7 b=10 ci=0 co=0 ca=0 + 5 c=1480 g=1480 pq=1 pqc=1479 qp=0 dt=381/1/0 df=4 of=0 ri=1 ql=0 qs=.... kt=0/W/5 ktl=fb2f b=10 ci=0 co=0 ca=0 + 6 c=1480 g=1480 pq=1 pqc=1479 qp=0 dt=1037/1/0 df=6 of=0 ri=1 ql=0 qs=.... kt=0/W/6 ktl=d2ad b=10 ci=0 co=0 ca=0 + 7 c=1474 g=1474 pq=1 pqc=1473 qp=0 dt=1572/0/0 df=8 of=0 ri=1 ql=0 qs=.... kt=0/W/7 ktl=cf15 b=10 ci=0 co=0 ca=0 The first section lists the rcu_data structures for rcu_sched, the second for rcu_bh. Note that CONFIG_TREE_PREEMPT_RCU kernels will have an @@ -160,7 +160,8 @@ o "qs" gives an indication of the state of the callback queue o "kt" is the per-CPU kernel-thread state. The digit preceding the first slash is zero if there is no work pending and 1 - otherwise. The character between the slashes is as follows: + otherwise. The character between the first pair of slashes is + as follows: "S" The kernel thread is stopped, in other words, all CPUs corresponding to this rcu_node structure are @@ -183,6 +184,10 @@ o "kt" is the per-CPU kernel-thread state. The digit preceding The number after the final slash is the CPU that the kthread is actually running on. +o "ktl" is the low-order 16 bits (in hexadecimal) of the count of + the number of times that this CPU's per-CPU kthread has gone + through its loop servicing invoke_rcu_cpu_kthread() requests. + o "b" is the batch limit for this CPU. If more than this number of RCU callbacks is ready to invoke, then the remainder will be deferred. diff --git a/kernel/rcutree.c b/kernel/rcutree.c index 27b6d8d..575d641 100644 --- a/kernel/rcutree.c +++ b/kernel/rcutree.c @@ -93,6 +93,7 @@ EXPORT_SYMBOL_GPL(rcu_scheduler_active); static DEFINE_PER_CPU(struct task_struct *, rcu_cpu_kthread_task); DEFINE_PER_CPU(unsigned int, rcu_cpu_kthread_status); DEFINE_PER_CPU(int, rcu_cpu_kthread_cpu); +DEFINE_PER_CPU(unsigned int, rcu_cpu_kthread_loops); static DEFINE_PER_CPU(wait_queue_head_t, rcu_cpu_wq); DEFINE_PER_CPU(char, rcu_cpu_has_work); static char rcu_kthreads_spawnable; @@ -1625,6 +1626,7 @@ static int rcu_cpu_kthread(void *arg) break; } *statusp = RCU_KTHREAD_RUNNING; + per_cpu(rcu_cpu_kthread_loops, cpu)++; local_irq_save(flags); work = *workp; *workp = 0; diff --git a/kernel/rcutree_trace.c b/kernel/rcutree_trace.c index 564b8fe..9678cc3 100644 --- a/kernel/rcutree_trace.c +++ b/kernel/rcutree_trace.c @@ -48,6 +48,7 @@ DECLARE_PER_CPU(unsigned int, rcu_cpu_kthread_status); DECLARE_PER_CPU(unsigned int, rcu_cpu_kthread_cpu); +DECLARE_PER_CPU(unsigned int, rcu_cpu_kthread_loops); DECLARE_PER_CPU(char, rcu_cpu_has_work); static char convert_kthread_status(unsigned int kthread_status) @@ -75,7 +76,7 @@ static void print_one_rcu_data(struct seq_file *m, struct rcu_data *rdp) rdp->dynticks_fqs); #endif /* #ifdef CONFIG_NO_HZ */ seq_printf(m, " of=%lu ri=%lu", rdp->offline_fqs, rdp->resched_ipi); - seq_printf(m, " ql=%ld qs=%c%c%c%c kt=%d/%c/%d b=%ld", + seq_printf(m, " ql=%ld qs=%c%c%c%c kt=%d/%c/%d ktl=%x b=%ld", rdp->qlen, ".N"[rdp->nxttail[RCU_NEXT_READY_TAIL] != rdp->nxttail[RCU_NEXT_TAIL]], @@ -88,6 +89,7 @@ static void print_one_rcu_data(struct seq_file *m, struct rcu_data *rdp) convert_kthread_status(per_cpu(rcu_cpu_kthread_status, rdp->cpu)), per_cpu(rcu_cpu_kthread_cpu, rdp->cpu), + per_cpu(rcu_cpu_kthread_loops, rdp->cpu) & 0xffff, rdp->blimit); seq_printf(m, " ci=%lu co=%lu ca=%lu\n", rdp->n_cbs_invoked, rdp->n_cbs_orphaned, rdp->n_cbs_adopted); -- cgit v0.10.2 From fc2ecf7ec76c5ee150b83dcefc863fa03fd365fb Mon Sep 17 00:00:00 2001 From: Mathieu Desnoyers Date: Wed, 23 Feb 2011 09:42:14 -0800 Subject: rcu: Enable DEBUG_OBJECTS_RCU_HEAD from !PREEMPT The prohibition of DEBUG_OBJECTS_RCU_HEAD from !PREEMPT was due to the fixup actions. So just produce a warning from !PREEMPT. Signed-off-by: Mathieu Desnoyers Signed-off-by: Paul E. McKenney Reviewed-by: Josh Triplett diff --git a/kernel/rcupdate.c b/kernel/rcupdate.c index f3240e9..b54d6d1 100644 --- a/kernel/rcupdate.c +++ b/kernel/rcupdate.c @@ -142,7 +142,14 @@ static int rcuhead_fixup_init(void *addr, enum debug_obj_state state) * Ensure that queued callbacks are all executed. * If we detect that we are nested in a RCU read-side critical * section, we should simply fail, otherwise we would deadlock. + * In !PREEMPT configurations, there is no way to tell if we are + * in a RCU read-side critical section or not, so we never + * attempt any fixup and just print a warning. */ +#ifndef CONFIG_PREEMPT + WARN_ON(1); + return 0; +#endif if (rcu_preempt_depth() != 0 || preempt_count() != 0 || irqs_disabled()) { WARN_ON(1); @@ -184,7 +191,14 @@ static int rcuhead_fixup_activate(void *addr, enum debug_obj_state state) * Ensure that queued callbacks are all executed. * If we detect that we are nested in a RCU read-side critical * section, we should simply fail, otherwise we would deadlock. + * In !PREEMPT configurations, there is no way to tell if we are + * in a RCU read-side critical section or not, so we never + * attempt any fixup and just print a warning. */ +#ifndef CONFIG_PREEMPT + WARN_ON(1); + return 0; +#endif if (rcu_preempt_depth() != 0 || preempt_count() != 0 || irqs_disabled()) { WARN_ON(1); @@ -214,12 +228,14 @@ static int rcuhead_fixup_free(void *addr, enum debug_obj_state state) * Ensure that queued callbacks are all executed. * If we detect that we are nested in a RCU read-side critical * section, we should simply fail, otherwise we would deadlock. - * Note that the machinery to reliably determine whether - * or not we are in an RCU read-side critical section - * exists only in the preemptible RCU implementations - * (TINY_PREEMPT_RCU and TREE_PREEMPT_RCU), which is why - * DEBUG_OBJECTS_RCU_HEAD is disallowed if !PREEMPT. + * In !PREEMPT configurations, there is no way to tell if we are + * in a RCU read-side critical section or not, so we never + * attempt any fixup and just print a warning. */ +#ifndef CONFIG_PREEMPT + WARN_ON(1); + return 0; +#endif if (rcu_preempt_depth() != 0 || preempt_count() != 0 || irqs_disabled()) { WARN_ON(1); diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug index 93ce6de3..3aa2780 100644 --- a/lib/Kconfig.debug +++ b/lib/Kconfig.debug @@ -337,7 +337,7 @@ config DEBUG_OBJECTS_WORK config DEBUG_OBJECTS_RCU_HEAD bool "Debug RCU callbacks objects" - depends on DEBUG_OBJECTS && PREEMPT + depends on DEBUG_OBJECTS help Enable this to turn on debugging of RCU list heads (call_rcu() usage). -- cgit v0.10.2 From b0c9d7ff2793502650ad987c3f237d5fe5587a1e Mon Sep 17 00:00:00 2001 From: "Paul E. McKenney" Date: Tue, 29 Mar 2011 12:56:56 -0700 Subject: rcu: add DEBUG_OBJECTS_RCU_HEAD check for alignment Verify that rcu_head structures are aligned to a four-byte boundary. This check is enabled by CONFIG_DEBUG_OBJECTS_RCU_HEAD. Signed-off-by: Paul E. McKenney Reviewed-by: Josh Triplett diff --git a/include/linux/rcupdate.h b/include/linux/rcupdate.h index 9e169c2..c7aeacf 100644 --- a/include/linux/rcupdate.h +++ b/include/linux/rcupdate.h @@ -785,6 +785,7 @@ extern struct debug_obj_descr rcuhead_debug_descr; static inline void debug_rcu_head_queue(struct rcu_head *head) { + WARN_ON_ONCE((unsigned long)head & 0x3); debug_object_activate(head, &rcuhead_debug_descr); debug_object_active_state(head, &rcuhead_debug_descr, STATE_RCU_HEAD_READY, -- cgit v0.10.2 From 561190e3b3db372403fb6a327b0121b4cae1b87e Mon Sep 17 00:00:00 2001 From: "Paul E. McKenney" Date: Wed, 30 Mar 2011 09:10:44 -0700 Subject: rcu: mark rcutorture boosting callback as being on-stack The CONFIG_DEBUG_OBJECTS_RCU_HEAD facility requires that on-stack RCU callbacks be flagged explicitly to debug-objects using the init_rcu_head_on_stack() and destroy_rcu_head_on_stack() functions. This commit applies those functions to the rcutorture code that tests RCU priority boosting. Signed-off-by: Paul E. McKenney Signed-off-by: Paul E. McKenney Reviewed-by: Josh Triplett diff --git a/kernel/rcutorture.c b/kernel/rcutorture.c index c2f58ec..2e138db 100644 --- a/kernel/rcutorture.c +++ b/kernel/rcutorture.c @@ -749,6 +749,7 @@ static int rcu_torture_boost(void *arg) n_rcu_torture_boost_rterror++; } + init_rcu_head_on_stack(&rbi.rcu); /* Each pass through the following loop does one boost-test cycle. */ do { /* Wait for the next test interval. */ @@ -808,6 +809,7 @@ checkwait: rcu_stutter_wait("rcu_torture_boost"); /* Clean up and exit. */ VERBOSE_PRINTK_STRING("rcu_torture_boost task stopping"); + destroy_rcu_head_on_stack(&rbi.rcu); rcutorture_shutdown_absorb("rcu_torture_boost"); while (!kthread_should_stop() || rbi.inflight) schedule_timeout_uninterruptible(1); -- cgit v0.10.2 From 108aae22339f445c134aeb48eca25df1014ab08d Mon Sep 17 00:00:00 2001 From: "Paul E. McKenney" Date: Wed, 23 Feb 2011 09:56:00 -0800 Subject: rcu: Use WARN_ON_ONCE for DEBUG_OBJECTS_RCU_HEAD warnings Avoid additional multiple-warning confusion in memory-corruption scenarios. Signed-off-by: Paul E. McKenney Reviewed-by: Josh Triplett diff --git a/kernel/rcupdate.c b/kernel/rcupdate.c index b54d6d1..7784bd2 100644 --- a/kernel/rcupdate.c +++ b/kernel/rcupdate.c @@ -147,12 +147,12 @@ static int rcuhead_fixup_init(void *addr, enum debug_obj_state state) * attempt any fixup and just print a warning. */ #ifndef CONFIG_PREEMPT - WARN_ON(1); + WARN_ON_ONCE(1); return 0; #endif if (rcu_preempt_depth() != 0 || preempt_count() != 0 || irqs_disabled()) { - WARN_ON(1); + WARN_ON_ONCE(1); return 0; } rcu_barrier(); @@ -196,12 +196,12 @@ static int rcuhead_fixup_activate(void *addr, enum debug_obj_state state) * attempt any fixup and just print a warning. */ #ifndef CONFIG_PREEMPT - WARN_ON(1); + WARN_ON_ONCE(1); return 0; #endif if (rcu_preempt_depth() != 0 || preempt_count() != 0 || irqs_disabled()) { - WARN_ON(1); + WARN_ON_ONCE(1); return 0; } rcu_barrier(); @@ -233,12 +233,12 @@ static int rcuhead_fixup_free(void *addr, enum debug_obj_state state) * attempt any fixup and just print a warning. */ #ifndef CONFIG_PREEMPT - WARN_ON(1); + WARN_ON_ONCE(1); return 0; #endif if (rcu_preempt_depth() != 0 || preempt_count() != 0 || irqs_disabled()) { - WARN_ON(1); + WARN_ON_ONCE(1); return 0; } rcu_barrier(); -- cgit v0.10.2 From f0a07aeaf8935b7e9ef8032ce6546169f143951c Mon Sep 17 00:00:00 2001 From: "Paul E. McKenney" Date: Wed, 23 Feb 2011 11:10:52 -0800 Subject: rcu: Switch to this_cpu() primitives This removes a couple of lines from invoke_rcu_cpu_kthread(), improving readability. Reported-by: Christoph Lameter Signed-off-by: Paul E. McKenney Signed-off-by: Paul E. McKenney Reviewed-by: Josh Triplett diff --git a/kernel/rcutree.c b/kernel/rcutree.c index 575d641..27304bc 100644 --- a/kernel/rcutree.c +++ b/kernel/rcutree.c @@ -1480,18 +1480,14 @@ static void rcu_process_callbacks(void) static void invoke_rcu_cpu_kthread(void) { unsigned long flags; - wait_queue_head_t *q; - int cpu; local_irq_save(flags); - cpu = smp_processor_id(); - per_cpu(rcu_cpu_has_work, cpu) = 1; - if (per_cpu(rcu_cpu_kthread_task, cpu) == NULL) { + __this_cpu_write(rcu_cpu_has_work, 1); + if (__this_cpu_read(rcu_cpu_kthread_task) == NULL) { local_irq_restore(flags); return; } - q = &per_cpu(rcu_cpu_wq, cpu); - wake_up(q); + wake_up(&__get_cpu_var(rcu_cpu_wq)); local_irq_restore(flags); } -- cgit v0.10.2 From ddeb75814f09205df795121d9e373e82de7f2aca Mon Sep 17 00:00:00 2001 From: "Paul E. McKenney" Date: Wed, 23 Feb 2011 17:03:06 -0800 Subject: rcu: code cleanups in TINY_RCU priority boosting. Extraneous semicolon, bad comment, and fold INIT_LIST_HEAD() into list_del() to get list_del_init(). Signed-off-by: Paul E. McKenney Signed-off-by: Paul E. McKenney Reviewed-by: Josh Triplett diff --git a/kernel/rcutiny_plugin.h b/kernel/rcutiny_plugin.h index 3cb8e36..0bc9f73 100644 --- a/kernel/rcutiny_plugin.h +++ b/kernel/rcutiny_plugin.h @@ -339,7 +339,7 @@ static void rcu_initiate_expedited_boost(void) raw_local_irq_restore(flags); } -#define RCU_BOOST_DELAY_JIFFIES DIV_ROUND_UP(CONFIG_RCU_BOOST_DELAY * HZ, 1000); +#define RCU_BOOST_DELAY_JIFFIES DIV_ROUND_UP(CONFIG_RCU_BOOST_DELAY * HZ, 1000) /* * Do priority-boost accounting for the start of a new grace period. @@ -418,7 +418,7 @@ static void rcu_preempt_cpu_qs(void) if (!rcu_preempt_gp_in_progress()) return; /* - * Check up on boosting. If there are no readers blocking the + * Check up on boosting. If there are readers blocking the * current grace period, leave. */ if (rcu_initiate_boost()) @@ -578,7 +578,7 @@ static void rcu_read_unlock_special(struct task_struct *t) empty = !rcu_preempt_blocked_readers_cgp(); empty_exp = rcu_preempt_ctrlblk.exp_tasks == NULL; np = rcu_next_node_entry(t); - list_del(&t->rcu_node_entry); + list_del_init(&t->rcu_node_entry); if (&t->rcu_node_entry == rcu_preempt_ctrlblk.gp_tasks) rcu_preempt_ctrlblk.gp_tasks = np; if (&t->rcu_node_entry == rcu_preempt_ctrlblk.exp_tasks) @@ -587,7 +587,6 @@ static void rcu_read_unlock_special(struct task_struct *t) if (&t->rcu_node_entry == rcu_preempt_ctrlblk.boost_tasks) rcu_preempt_ctrlblk.boost_tasks = np; #endif /* #ifdef CONFIG_RCU_BOOST */ - INIT_LIST_HEAD(&t->rcu_node_entry); /* * If this was the last task on the current list, and if -- cgit v0.10.2 From 203373c81b83e98da82836c4b8b5dd1e6fc9011f Mon Sep 17 00:00:00 2001 From: "Paul E. McKenney" Date: Thu, 24 Feb 2011 15:25:21 -0800 Subject: rcu: remove useless ->boosted_this_gp field The ->boosted_this_gp field is a holdover from an earlier design that was to carry out multiple boost operations in parallel. It is not required by the current design, which boosts one task at a time. Signed-off-by: Paul E. McKenney Signed-off-by: Paul E. McKenney diff --git a/kernel/rcutiny_plugin.h b/kernel/rcutiny_plugin.h index 0bc9f73..2b8d529 100644 --- a/kernel/rcutiny_plugin.h +++ b/kernel/rcutiny_plugin.h @@ -100,7 +100,6 @@ struct rcu_preempt_ctrlblk { u8 completed; /* Last grace period completed. */ /* If all three are equal, RCU is idle. */ #ifdef CONFIG_RCU_BOOST - s8 boosted_this_gp; /* Has boosting already happened? */ unsigned long boost_time; /* When to start boosting (jiffies) */ #endif /* #ifdef CONFIG_RCU_BOOST */ #ifdef CONFIG_RCU_TRACE @@ -112,7 +111,6 @@ struct rcu_preempt_ctrlblk { unsigned long n_normal_balk_blkd_tasks; unsigned long n_normal_balk_gp_tasks; unsigned long n_normal_balk_boost_tasks; - unsigned long n_normal_balk_boosted; unsigned long n_normal_balk_notyet; unsigned long n_normal_balk_nos; unsigned long n_exp_balk_blkd_tasks; @@ -219,36 +217,19 @@ static void show_tiny_preempt_stats(struct seq_file *m) "N."[!rcu_preempt_ctrlblk.gp_tasks], "E."[!rcu_preempt_ctrlblk.exp_tasks]); #ifdef CONFIG_RCU_BOOST - seq_printf(m, " ttb=%c btg=", - "B."[!rcu_preempt_ctrlblk.boost_tasks]); - switch (rcu_preempt_ctrlblk.boosted_this_gp) { - case -1: - seq_puts(m, "exp"); - break; - case 0: - seq_puts(m, "no"); - break; - case 1: - seq_puts(m, "begun"); - break; - case 2: - seq_puts(m, "done"); - break; - default: - seq_printf(m, "?%d?", rcu_preempt_ctrlblk.boosted_this_gp); - } - seq_printf(m, " ntb=%lu neb=%lu nnb=%lu j=%04x bt=%04x\n", + seq_printf(m, "%sttb=%c ntb=%lu neb=%lu nnb=%lu j=%04x bt=%04x\n", + " ", + "B."[!rcu_preempt_ctrlblk.boost_tasks], rcu_preempt_ctrlblk.n_tasks_boosted, rcu_preempt_ctrlblk.n_exp_boosts, rcu_preempt_ctrlblk.n_normal_boosts, (int)(jiffies & 0xffff), (int)(rcu_preempt_ctrlblk.boost_time & 0xffff)); - seq_printf(m, " %s: nt=%lu gt=%lu bt=%lu b=%lu ny=%lu nos=%lu\n", + seq_printf(m, " %s: nt=%lu gt=%lu bt=%lu ny=%lu nos=%lu\n", "normal balk", rcu_preempt_ctrlblk.n_normal_balk_blkd_tasks, rcu_preempt_ctrlblk.n_normal_balk_gp_tasks, rcu_preempt_ctrlblk.n_normal_balk_boost_tasks, - rcu_preempt_ctrlblk.n_normal_balk_boosted, rcu_preempt_ctrlblk.n_normal_balk_notyet, rcu_preempt_ctrlblk.n_normal_balk_nos); seq_printf(m, " exp balk: bt=%lu nos=%lu\n", @@ -277,7 +258,6 @@ static int rcu_boost(void) if (rcu_preempt_ctrlblk.boost_tasks == NULL) return 0; /* Nothing to boost. */ raw_local_irq_save(flags); - rcu_preempt_ctrlblk.boosted_this_gp++; t = container_of(rcu_preempt_ctrlblk.boost_tasks, struct task_struct, rcu_node_entry); np = rcu_next_node_entry(t); @@ -287,7 +267,6 @@ static int rcu_boost(void) raw_local_irq_restore(flags); rt_mutex_lock(&mtx); RCU_TRACE(rcu_preempt_ctrlblk.n_tasks_boosted++); - rcu_preempt_ctrlblk.boosted_this_gp++; rt_mutex_unlock(&mtx); return rcu_preempt_ctrlblk.boost_tasks != NULL; } @@ -310,7 +289,6 @@ static int rcu_initiate_boost(void) } if (rcu_preempt_ctrlblk.gp_tasks != NULL && rcu_preempt_ctrlblk.boost_tasks == NULL && - rcu_preempt_ctrlblk.boosted_this_gp == 0 && ULONG_CMP_GE(jiffies, rcu_preempt_ctrlblk.boost_time)) { rcu_preempt_ctrlblk.boost_tasks = rcu_preempt_ctrlblk.gp_tasks; invoke_rcu_kthread(); @@ -331,7 +309,6 @@ static void rcu_initiate_expedited_boost(void) if (!list_empty(&rcu_preempt_ctrlblk.blkd_tasks)) { rcu_preempt_ctrlblk.boost_tasks = rcu_preempt_ctrlblk.blkd_tasks.next; - rcu_preempt_ctrlblk.boosted_this_gp = -1; invoke_rcu_kthread(); RCU_TRACE(rcu_preempt_ctrlblk.n_exp_boosts++); } else @@ -347,8 +324,6 @@ static void rcu_initiate_expedited_boost(void) static void rcu_preempt_boost_start_gp(void) { rcu_preempt_ctrlblk.boost_time = jiffies + RCU_BOOST_DELAY_JIFFIES; - if (rcu_preempt_ctrlblk.boosted_this_gp > 0) - rcu_preempt_ctrlblk.boosted_this_gp = 0; } #else /* #ifdef CONFIG_RCU_BOOST */ @@ -934,8 +909,6 @@ static void rcu_initiate_boost_trace(void) rcu_preempt_ctrlblk.n_normal_balk_gp_tasks++; else if (rcu_preempt_ctrlblk.boost_tasks != NULL) rcu_preempt_ctrlblk.n_normal_balk_boost_tasks++; - else if (rcu_preempt_ctrlblk.boosted_this_gp != 0) - rcu_preempt_ctrlblk.n_normal_balk_boosted++; else if (!ULONG_CMP_GE(jiffies, rcu_preempt_ctrlblk.boost_time)) rcu_preempt_ctrlblk.n_normal_balk_notyet++; else -- cgit v0.10.2 From 7e8b4c72344e0d904b0e3fa9fd2eb116f04b3d41 Mon Sep 17 00:00:00 2001 From: "Paul E. McKenney" Date: Thu, 24 Feb 2011 19:26:21 -0800 Subject: rcu: Converge TINY_RCU expedited and normal boosting This applies a trick from TREE_RCU boosting to TINY_RCU, eliminating code and adding comments. The key point is that it is possible for the booster thread itself to work out whether there is a normal or expedited boost required based solely on local information. There is therefore no need for boost initiation to know or care what type of boosting is required. In addition, when boosting is complete for a given grace period, then by definition there cannot be any more boosting for that grace period. This allows eliminating yet more state and statistics. Signed-off-by: Paul E. McKenney Signed-off-by: Paul E. McKenney Reviewed-by: Josh Triplett diff --git a/kernel/rcutiny_plugin.h b/kernel/rcutiny_plugin.h index 2b8d529..f259c67 100644 --- a/kernel/rcutiny_plugin.h +++ b/kernel/rcutiny_plugin.h @@ -106,15 +106,22 @@ struct rcu_preempt_ctrlblk { unsigned long n_grace_periods; #ifdef CONFIG_RCU_BOOST unsigned long n_tasks_boosted; + /* Total number of tasks boosted. */ unsigned long n_exp_boosts; + /* Number of tasks boosted for expedited GP. */ unsigned long n_normal_boosts; - unsigned long n_normal_balk_blkd_tasks; - unsigned long n_normal_balk_gp_tasks; - unsigned long n_normal_balk_boost_tasks; - unsigned long n_normal_balk_notyet; - unsigned long n_normal_balk_nos; - unsigned long n_exp_balk_blkd_tasks; - unsigned long n_exp_balk_nos; + /* Number of tasks boosted for normal GP. */ + unsigned long n_balk_blkd_tasks; + /* Refused to boost: no blocked tasks. */ + unsigned long n_balk_exp_gp_tasks; + /* Refused to boost: nothing blocking GP. */ + unsigned long n_balk_boost_tasks; + /* Refused to boost: already boosting. */ + unsigned long n_balk_notyet; + /* Refused to boost: not yet time. */ + unsigned long n_balk_nos; + /* Refused to boost: not sure why, though. */ + /* This can happen due to race conditions. */ #endif /* #ifdef CONFIG_RCU_BOOST */ #endif /* #ifdef CONFIG_RCU_TRACE */ }; @@ -199,7 +206,6 @@ static struct list_head *rcu_next_node_entry(struct task_struct *t) #ifdef CONFIG_RCU_BOOST static void rcu_initiate_boost_trace(void); -static void rcu_initiate_exp_boost_trace(void); #endif /* #ifdef CONFIG_RCU_BOOST */ /* @@ -225,16 +231,13 @@ static void show_tiny_preempt_stats(struct seq_file *m) rcu_preempt_ctrlblk.n_normal_boosts, (int)(jiffies & 0xffff), (int)(rcu_preempt_ctrlblk.boost_time & 0xffff)); - seq_printf(m, " %s: nt=%lu gt=%lu bt=%lu ny=%lu nos=%lu\n", - "normal balk", - rcu_preempt_ctrlblk.n_normal_balk_blkd_tasks, - rcu_preempt_ctrlblk.n_normal_balk_gp_tasks, - rcu_preempt_ctrlblk.n_normal_balk_boost_tasks, - rcu_preempt_ctrlblk.n_normal_balk_notyet, - rcu_preempt_ctrlblk.n_normal_balk_nos); - seq_printf(m, " exp balk: bt=%lu nos=%lu\n", - rcu_preempt_ctrlblk.n_exp_balk_blkd_tasks, - rcu_preempt_ctrlblk.n_exp_balk_nos); + seq_printf(m, "%s: nt=%lu egt=%lu bt=%lu ny=%lu nos=%lu\n", + " balk", + rcu_preempt_ctrlblk.n_balk_blkd_tasks, + rcu_preempt_ctrlblk.n_balk_exp_gp_tasks, + rcu_preempt_ctrlblk.n_balk_boost_tasks, + rcu_preempt_ctrlblk.n_balk_notyet, + rcu_preempt_ctrlblk.n_balk_nos); #endif /* #ifdef CONFIG_RCU_BOOST */ } @@ -252,23 +255,59 @@ static int rcu_boost(void) { unsigned long flags; struct rt_mutex mtx; - struct list_head *np; struct task_struct *t; + struct list_head *tb; - if (rcu_preempt_ctrlblk.boost_tasks == NULL) + if (rcu_preempt_ctrlblk.boost_tasks == NULL && + rcu_preempt_ctrlblk.exp_tasks == NULL) return 0; /* Nothing to boost. */ + raw_local_irq_save(flags); - t = container_of(rcu_preempt_ctrlblk.boost_tasks, struct task_struct, - rcu_node_entry); - np = rcu_next_node_entry(t); + + /* + * Recheck with irqs disabled: all tasks in need of boosting + * might exit their RCU read-side critical sections on their own + * if we are preempted just before disabling irqs. + */ + if (rcu_preempt_ctrlblk.boost_tasks == NULL && + rcu_preempt_ctrlblk.exp_tasks == NULL) { + raw_local_irq_restore(flags); + return 0; + } + + /* + * Preferentially boost tasks blocking expedited grace periods. + * This cannot starve the normal grace periods because a second + * expedited grace period must boost all blocked tasks, including + * those blocking the pre-existing normal grace period. + */ + if (rcu_preempt_ctrlblk.exp_tasks != NULL) { + tb = rcu_preempt_ctrlblk.exp_tasks; + RCU_TRACE(rcu_preempt_ctrlblk.n_exp_boosts++); + } else { + tb = rcu_preempt_ctrlblk.boost_tasks; + RCU_TRACE(rcu_preempt_ctrlblk.n_normal_boosts++); + } + RCU_TRACE(rcu_preempt_ctrlblk.n_tasks_boosted++); + + /* + * We boost task t by manufacturing an rt_mutex that appears to + * be held by task t. We leave a pointer to that rt_mutex where + * task t can find it, and task t will release the mutex when it + * exits its outermost RCU read-side critical section. Then + * simply acquiring this artificial rt_mutex will boost task + * t's priority. (Thanks to tglx for suggesting this approach!) + */ + t = container_of(tb, struct task_struct, rcu_node_entry); rt_mutex_init_proxy_locked(&mtx, t); t->rcu_boost_mutex = &mtx; t->rcu_read_unlock_special |= RCU_READ_UNLOCK_BOOSTED; raw_local_irq_restore(flags); rt_mutex_lock(&mtx); - RCU_TRACE(rcu_preempt_ctrlblk.n_tasks_boosted++); - rt_mutex_unlock(&mtx); - return rcu_preempt_ctrlblk.boost_tasks != NULL; + rt_mutex_unlock(&mtx); /* Keep lockdep happy. */ + + return rcu_preempt_ctrlblk.boost_tasks != NULL || + rcu_preempt_ctrlblk.exp_tasks != NULL; } /* @@ -283,39 +322,24 @@ static int rcu_boost(void) */ static int rcu_initiate_boost(void) { - if (!rcu_preempt_blocked_readers_cgp()) { - RCU_TRACE(rcu_preempt_ctrlblk.n_normal_balk_blkd_tasks++); + if (!rcu_preempt_blocked_readers_cgp() && + rcu_preempt_ctrlblk.exp_tasks == NULL) { + RCU_TRACE(rcu_preempt_ctrlblk.n_balk_exp_gp_tasks++); return 0; } - if (rcu_preempt_ctrlblk.gp_tasks != NULL && - rcu_preempt_ctrlblk.boost_tasks == NULL && - ULONG_CMP_GE(jiffies, rcu_preempt_ctrlblk.boost_time)) { - rcu_preempt_ctrlblk.boost_tasks = rcu_preempt_ctrlblk.gp_tasks; + if (rcu_preempt_ctrlblk.exp_tasks != NULL || + (rcu_preempt_ctrlblk.gp_tasks != NULL && + rcu_preempt_ctrlblk.boost_tasks == NULL && + ULONG_CMP_GE(jiffies, rcu_preempt_ctrlblk.boost_time))) { + if (rcu_preempt_ctrlblk.exp_tasks == NULL) + rcu_preempt_ctrlblk.boost_tasks = + rcu_preempt_ctrlblk.gp_tasks; invoke_rcu_kthread(); - RCU_TRACE(rcu_preempt_ctrlblk.n_normal_boosts++); } else RCU_TRACE(rcu_initiate_boost_trace()); return 1; } -/* - * Initiate boosting for an expedited grace period. - */ -static void rcu_initiate_expedited_boost(void) -{ - unsigned long flags; - - raw_local_irq_save(flags); - if (!list_empty(&rcu_preempt_ctrlblk.blkd_tasks)) { - rcu_preempt_ctrlblk.boost_tasks = - rcu_preempt_ctrlblk.blkd_tasks.next; - invoke_rcu_kthread(); - RCU_TRACE(rcu_preempt_ctrlblk.n_exp_boosts++); - } else - RCU_TRACE(rcu_initiate_exp_boost_trace()); - raw_local_irq_restore(flags); -} - #define RCU_BOOST_DELAY_JIFFIES DIV_ROUND_UP(CONFIG_RCU_BOOST_DELAY * HZ, 1000) /* @@ -347,13 +371,6 @@ static int rcu_initiate_boost(void) } /* - * If there is no RCU priority boosting, we don't initiate expedited boosting. - */ -static void rcu_initiate_expedited_boost(void) -{ -} - -/* * If there is no RCU priority boosting, nothing to do at grace-period start. */ static void rcu_preempt_boost_start_gp(void) @@ -786,13 +803,16 @@ void synchronize_rcu_expedited(void) rpcp->exp_tasks = rpcp->blkd_tasks.next; if (rpcp->exp_tasks == &rpcp->blkd_tasks) rpcp->exp_tasks = NULL; - local_irq_restore(flags); /* Wait for tail of ->blkd_tasks list to drain. */ - if (rcu_preempted_readers_exp()) - rcu_initiate_expedited_boost(); + if (!rcu_preempted_readers_exp()) + local_irq_restore(flags); + else { + rcu_initiate_boost(); + local_irq_restore(flags); wait_event(sync_rcu_preempt_exp_wq, !rcu_preempted_readers_exp()); + } /* Clean up and exit. */ barrier(); /* ensure expedited GP seen before counter increment. */ @@ -905,22 +925,17 @@ void __init rcu_scheduler_starting(void) static void rcu_initiate_boost_trace(void) { - if (rcu_preempt_ctrlblk.gp_tasks == NULL) - rcu_preempt_ctrlblk.n_normal_balk_gp_tasks++; + if (list_empty(&rcu_preempt_ctrlblk.blkd_tasks)) + rcu_preempt_ctrlblk.n_balk_blkd_tasks++; + else if (rcu_preempt_ctrlblk.gp_tasks == NULL && + rcu_preempt_ctrlblk.exp_tasks == NULL) + rcu_preempt_ctrlblk.n_balk_exp_gp_tasks++; else if (rcu_preempt_ctrlblk.boost_tasks != NULL) - rcu_preempt_ctrlblk.n_normal_balk_boost_tasks++; + rcu_preempt_ctrlblk.n_balk_boost_tasks++; else if (!ULONG_CMP_GE(jiffies, rcu_preempt_ctrlblk.boost_time)) - rcu_preempt_ctrlblk.n_normal_balk_notyet++; - else - rcu_preempt_ctrlblk.n_normal_balk_nos++; -} - -static void rcu_initiate_exp_boost_trace(void) -{ - if (list_empty(&rcu_preempt_ctrlblk.blkd_tasks)) - rcu_preempt_ctrlblk.n_exp_balk_blkd_tasks++; + rcu_preempt_ctrlblk.n_balk_notyet++; else - rcu_preempt_ctrlblk.n_exp_balk_nos++; + rcu_preempt_ctrlblk.n_balk_nos++; } #endif /* #ifdef CONFIG_RCU_BOOST */ -- cgit v0.10.2 From 13491a0ee1ef862b6c842132b6eb9c5e721af5ad Mon Sep 17 00:00:00 2001 From: Lai Jiangshan Date: Fri, 25 Feb 2011 11:37:59 -0800 Subject: rcu: call __rcu_read_unlock() in exit_rcu for tree RCU Using __rcu_read_lock() in place of rcu_read_lock() leaves any debug state as it really should be, namely with the lock still held. Signed-off-by: Lai Jiangshan Signed-off-by: Paul E. McKenney Reviewed-by: Josh Triplett diff --git a/kernel/rcutree_plugin.h b/kernel/rcutree_plugin.h index a21413d..11b27f3 100644 --- a/kernel/rcutree_plugin.h +++ b/kernel/rcutree_plugin.h @@ -858,7 +858,7 @@ void exit_rcu(void) if (t->rcu_read_lock_nesting == 0) return; t->rcu_read_lock_nesting = 1; - rcu_read_unlock(); + __rcu_read_unlock(); } #else /* #ifdef CONFIG_TREE_PREEMPT_RCU */ -- cgit v0.10.2 From 6cc68793e380bb51f447d8d02af873b7bc01f222 Mon Sep 17 00:00:00 2001 From: "Paul E. McKenney" Date: Wed, 2 Mar 2011 13:15:15 -0800 Subject: rcu: fix spelling The "preemptible" spelling is preferable. May as well fix it. Signed-off-by: Paul E. McKenney Reviewed-by: Josh Triplett diff --git a/kernel/rcutree.c b/kernel/rcutree.c index 27304bc..b579e4f 100644 --- a/kernel/rcutree.c +++ b/kernel/rcutree.c @@ -290,8 +290,8 @@ static int rcu_implicit_offline_qs(struct rcu_data *rdp) return 1; } - /* If preemptable RCU, no point in sending reschedule IPI. */ - if (rdp->preemptable) + /* If preemptible RCU, no point in sending reschedule IPI. */ + if (rdp->preemptible) return 0; /* The CPU is online, so send it a reschedule IPI. */ @@ -1982,7 +1982,7 @@ static int __rcu_pending(struct rcu_state *rsp, struct rcu_data *rdp) * or RCU-bh, force a local reschedule. */ rdp->n_rp_qs_pending++; - if (!rdp->preemptable && + if (!rdp->preemptible && ULONG_CMP_LT(ACCESS_ONCE(rsp->jiffies_force_qs) - 1, jiffies)) set_need_resched(); @@ -2159,7 +2159,7 @@ rcu_boot_init_percpu_data(int cpu, struct rcu_state *rsp) * that this CPU cannot possibly have any RCU callbacks in flight yet. */ static void __cpuinit -rcu_init_percpu_data(int cpu, struct rcu_state *rsp, int preemptable) +rcu_init_percpu_data(int cpu, struct rcu_state *rsp, int preemptible) { unsigned long flags; unsigned long mask; @@ -2171,7 +2171,7 @@ rcu_init_percpu_data(int cpu, struct rcu_state *rsp, int preemptable) rdp->passed_quiesc = 0; /* We could be racing with new GP, */ rdp->qs_pending = 1; /* so set up to respond to current GP. */ rdp->beenonline = 1; /* We have now been online. */ - rdp->preemptable = preemptable; + rdp->preemptible = preemptible; rdp->qlen_last_fqs_check = 0; rdp->n_force_qs_snap = rsp->n_force_qs; rdp->blimit = blimit; diff --git a/kernel/rcutree.h b/kernel/rcutree.h index 37502a2..a6a9717 100644 --- a/kernel/rcutree.h +++ b/kernel/rcutree.h @@ -239,7 +239,7 @@ struct rcu_data { bool passed_quiesc; /* User-mode/idle loop etc. */ bool qs_pending; /* Core waits for quiesc state. */ bool beenonline; /* CPU online at least once. */ - bool preemptable; /* Preemptable RCU? */ + bool preemptible; /* Preemptible RCU? */ struct rcu_node *mynode; /* This CPU's leaf of hierarchy */ unsigned long grpmask; /* Mask to apply to leaf qsmask. */ diff --git a/kernel/rcutree_plugin.h b/kernel/rcutree_plugin.h index 11b27f3..f629479 100644 --- a/kernel/rcutree_plugin.h +++ b/kernel/rcutree_plugin.h @@ -1,7 +1,7 @@ /* * Read-Copy Update mechanism for mutual exclusion (tree-based version) * Internal non-public definitions that provide either classic - * or preemptable semantics. + * or preemptible semantics. * * 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 @@ -75,7 +75,7 @@ static int rcu_preempted_readers_exp(struct rcu_node *rnp); */ static void __init rcu_bootup_announce(void) { - printk(KERN_INFO "Preemptable hierarchical RCU implementation.\n"); + printk(KERN_INFO "Preemptible hierarchical RCU implementation.\n"); rcu_bootup_announce_oddness(); } @@ -108,7 +108,7 @@ void rcu_force_quiescent_state(void) EXPORT_SYMBOL_GPL(rcu_force_quiescent_state); /* - * Record a preemptable-RCU quiescent state for the specified CPU. Note + * Record a preemptible-RCU quiescent state for the specified CPU. Note * that this just means that the task currently running on the CPU is * not in a quiescent state. There might be any number of tasks blocked * while in an RCU read-side critical section. @@ -207,7 +207,7 @@ static void rcu_preempt_note_context_switch(int cpu) } /* - * Tree-preemptable RCU implementation for rcu_read_lock(). + * Tree-preemptible RCU implementation for rcu_read_lock(). * Just increment ->rcu_read_lock_nesting, shared state will be updated * if we block. */ @@ -376,7 +376,7 @@ static void rcu_read_unlock_special(struct task_struct *t) } /* - * Tree-preemptable RCU implementation for rcu_read_unlock(). + * Tree-preemptible RCU implementation for rcu_read_unlock(). * Decrement ->rcu_read_lock_nesting. If the result is zero (outermost * rcu_read_unlock()) and ->rcu_read_unlock_special is non-zero, then * invoke rcu_read_unlock_special() to clean up after a context switch @@ -565,7 +565,7 @@ static int rcu_preempt_offline_tasks(struct rcu_state *rsp, } /* - * Do CPU-offline processing for preemptable RCU. + * Do CPU-offline processing for preemptible RCU. */ static void rcu_preempt_offline_cpu(int cpu) { @@ -594,7 +594,7 @@ static void rcu_preempt_check_callbacks(int cpu) } /* - * Process callbacks for preemptable RCU. + * Process callbacks for preemptible RCU. */ static void rcu_preempt_process_callbacks(void) { @@ -603,7 +603,7 @@ static void rcu_preempt_process_callbacks(void) } /* - * Queue a preemptable-RCU callback for invocation after a grace period. + * Queue a preemptible-RCU callback for invocation after a grace period. */ void call_rcu(struct rcu_head *head, void (*func)(struct rcu_head *rcu)) { @@ -795,7 +795,7 @@ mb_ret: EXPORT_SYMBOL_GPL(synchronize_rcu_expedited); /* - * Check to see if there is any immediate preemptable-RCU-related work + * Check to see if there is any immediate preemptible-RCU-related work * to be done. */ static int rcu_preempt_pending(int cpu) @@ -805,7 +805,7 @@ static int rcu_preempt_pending(int cpu) } /* - * Does preemptable RCU need the CPU to stay out of dynticks mode? + * Does preemptible RCU need the CPU to stay out of dynticks mode? */ static int rcu_preempt_needs_cpu(int cpu) { @@ -822,7 +822,7 @@ void rcu_barrier(void) EXPORT_SYMBOL_GPL(rcu_barrier); /* - * Initialize preemptable RCU's per-CPU data. + * Initialize preemptible RCU's per-CPU data. */ static void __cpuinit rcu_preempt_init_percpu_data(int cpu) { @@ -830,7 +830,7 @@ static void __cpuinit rcu_preempt_init_percpu_data(int cpu) } /* - * Move preemptable RCU's callbacks from dying CPU to other online CPU. + * Move preemptible RCU's callbacks from dying CPU to other online CPU. */ static void rcu_preempt_send_cbs_to_online(void) { @@ -838,7 +838,7 @@ static void rcu_preempt_send_cbs_to_online(void) } /* - * Initialize preemptable RCU's state structures. + * Initialize preemptible RCU's state structures. */ static void __init __rcu_init_preempt(void) { @@ -846,7 +846,7 @@ static void __init __rcu_init_preempt(void) } /* - * Check for a task exiting while in a preemptable-RCU read-side + * Check for a task exiting while in a preemptible-RCU read-side * critical section, clean up if so. No need to issue warnings, * as debug_check_no_locks_held() already does this if lockdep * is enabled. @@ -894,7 +894,7 @@ void rcu_force_quiescent_state(void) EXPORT_SYMBOL_GPL(rcu_force_quiescent_state); /* - * Because preemptable RCU does not exist, we never have to check for + * Because preemptible RCU does not exist, we never have to check for * CPUs being in quiescent states. */ static void rcu_preempt_note_context_switch(int cpu) @@ -902,7 +902,7 @@ static void rcu_preempt_note_context_switch(int cpu) } /* - * Because preemptable RCU does not exist, there are never any preempted + * Because preemptible RCU does not exist, there are never any preempted * RCU readers. */ static int rcu_preempt_blocked_readers_cgp(struct rcu_node *rnp) @@ -921,7 +921,7 @@ static void rcu_report_unblock_qs_rnp(struct rcu_node *rnp, unsigned long flags) #endif /* #ifdef CONFIG_HOTPLUG_CPU */ /* - * Because preemptable RCU does not exist, we never have to check for + * Because preemptible RCU does not exist, we never have to check for * tasks blocked within RCU read-side critical sections. */ static void rcu_print_detail_task_stall(struct rcu_state *rsp) @@ -929,7 +929,7 @@ static void rcu_print_detail_task_stall(struct rcu_state *rsp) } /* - * Because preemptable RCU does not exist, we never have to check for + * Because preemptible RCU does not exist, we never have to check for * tasks blocked within RCU read-side critical sections. */ static void rcu_print_task_stall(struct rcu_node *rnp) @@ -945,7 +945,7 @@ static void rcu_preempt_stall_reset(void) } /* - * Because there is no preemptable RCU, there can be no readers blocked, + * Because there is no preemptible RCU, there can be no readers blocked, * so there is no need to check for blocked tasks. So check only for * bogus qsmask values. */ @@ -957,7 +957,7 @@ static void rcu_preempt_check_blocked_tasks(struct rcu_node *rnp) #ifdef CONFIG_HOTPLUG_CPU /* - * Because preemptable RCU does not exist, it never needs to migrate + * Because preemptible RCU does not exist, it never needs to migrate * tasks that were blocked within RCU read-side critical sections, and * such non-existent tasks cannot possibly have been blocking the current * grace period. @@ -970,7 +970,7 @@ static int rcu_preempt_offline_tasks(struct rcu_state *rsp, } /* - * Because preemptable RCU does not exist, it never needs CPU-offline + * Because preemptible RCU does not exist, it never needs CPU-offline * processing. */ static void rcu_preempt_offline_cpu(int cpu) @@ -980,7 +980,7 @@ static void rcu_preempt_offline_cpu(int cpu) #endif /* #ifdef CONFIG_HOTPLUG_CPU */ /* - * Because preemptable RCU does not exist, it never has any callbacks + * Because preemptible RCU does not exist, it never has any callbacks * to check. */ static void rcu_preempt_check_callbacks(int cpu) @@ -988,7 +988,7 @@ static void rcu_preempt_check_callbacks(int cpu) } /* - * Because preemptable RCU does not exist, it never has any callbacks + * Because preemptible RCU does not exist, it never has any callbacks * to process. */ static void rcu_preempt_process_callbacks(void) @@ -997,7 +997,7 @@ static void rcu_preempt_process_callbacks(void) /* * Wait for an rcu-preempt grace period, but make it happen quickly. - * But because preemptable RCU does not exist, map to rcu-sched. + * But because preemptible RCU does not exist, map to rcu-sched. */ void synchronize_rcu_expedited(void) { @@ -1008,7 +1008,7 @@ EXPORT_SYMBOL_GPL(synchronize_rcu_expedited); #ifdef CONFIG_HOTPLUG_CPU /* - * Because preemptable RCU does not exist, there is never any need to + * Because preemptible RCU does not exist, there is never any need to * report on tasks preempted in RCU read-side critical sections during * expedited RCU grace periods. */ @@ -1020,7 +1020,7 @@ static void rcu_report_exp_rnp(struct rcu_state *rsp, struct rcu_node *rnp) #endif /* #ifdef CONFIG_HOTPLUG_CPU */ /* - * Because preemptable RCU does not exist, it never has any work to do. + * Because preemptible RCU does not exist, it never has any work to do. */ static int rcu_preempt_pending(int cpu) { @@ -1028,7 +1028,7 @@ static int rcu_preempt_pending(int cpu) } /* - * Because preemptable RCU does not exist, it never needs any CPU. + * Because preemptible RCU does not exist, it never needs any CPU. */ static int rcu_preempt_needs_cpu(int cpu) { @@ -1036,7 +1036,7 @@ static int rcu_preempt_needs_cpu(int cpu) } /* - * Because preemptable RCU does not exist, rcu_barrier() is just + * Because preemptible RCU does not exist, rcu_barrier() is just * another name for rcu_barrier_sched(). */ void rcu_barrier(void) @@ -1046,7 +1046,7 @@ void rcu_barrier(void) EXPORT_SYMBOL_GPL(rcu_barrier); /* - * Because preemptable RCU does not exist, there is no per-CPU + * Because preemptible RCU does not exist, there is no per-CPU * data to initialize. */ static void __cpuinit rcu_preempt_init_percpu_data(int cpu) @@ -1054,14 +1054,14 @@ static void __cpuinit rcu_preempt_init_percpu_data(int cpu) } /* - * Because there is no preemptable RCU, there are no callbacks to move. + * Because there is no preemptible RCU, there are no callbacks to move. */ static void rcu_preempt_send_cbs_to_online(void) { } /* - * Because preemptable RCU does not exist, it need not be initialized. + * Because preemptible RCU does not exist, it need not be initialized. */ static void __init __rcu_init_preempt(void) { -- cgit v0.10.2 From 9ab1544eb4196ca8d05c433b2eb56f74496b1ee3 Mon Sep 17 00:00:00 2001 From: Lai Jiangshan Date: Fri, 18 Mar 2011 11:15:47 +0800 Subject: rcu: introduce kfree_rcu() Many rcu callbacks functions just call kfree() on the base structure. These functions are trivial, but their size adds up, and furthermore when they are used in a kernel module, that module must invoke the high-latency rcu_barrier() function at module-unload time. The kfree_rcu() function introduced by this commit addresses this issue. Rather than encoding a function address in the embedded rcu_head structure, kfree_rcu() instead encodes the offset of the rcu_head structure within the base structure. Because the functions are not allowed in the low-order 4096 bytes of kernel virtual memory, offsets up to 4095 bytes can be accommodated. If the offset is larger than 4095 bytes, a compile-time error will be generated in __kfree_rcu(). If this error is triggered, you can either fall back to use of call_rcu() or rearrange the structure to position the rcu_head structure into the first 4096 bytes. Note that the allowable offset might decrease in the future, for example, to allow something like kmem_cache_free_rcu(). The new kfree_rcu() function can replace code as follows: call_rcu(&p->rcu, simple_kfree_callback); where "simple_kfree_callback()" might be defined as follows: void simple_kfree_callback(struct rcu_head *p) { struct foo *q = container_of(p, struct foo, rcu); kfree(q); } with the following: kfree_rcu(&p->rcu, rcu); Note that the "rcu" is the name of a field in the structure being freed. The reason for using this rather than passing in a pointer to the base structure is that the above approach allows better type checking. This commit is based on earlier work by Lai Jiangshan and Manfred Spraul: Lai's V1 patch: http://lkml.org/lkml/2008/9/18/1 Manfred's patch: http://lkml.org/lkml/2009/1/2/115 Signed-off-by: Lai Jiangshan Signed-off-by: Manfred Spraul Signed-off-by: Paul E. McKenney Reviewed-by: David Howells Reviewed-by: Josh Triplett diff --git a/include/linux/rcupdate.h b/include/linux/rcupdate.h index c7aeacf..99f9aa7 100644 --- a/include/linux/rcupdate.h +++ b/include/linux/rcupdate.h @@ -809,4 +809,60 @@ static inline void debug_rcu_head_unqueue(struct rcu_head *head) } #endif /* #else !CONFIG_DEBUG_OBJECTS_RCU_HEAD */ +static __always_inline bool __is_kfree_rcu_offset(unsigned long offset) +{ + return offset < 4096; +} + +static __always_inline +void __kfree_rcu(struct rcu_head *head, unsigned long offset) +{ + typedef void (*rcu_callback)(struct rcu_head *); + + BUILD_BUG_ON(!__builtin_constant_p(offset)); + + /* See the kfree_rcu() header comment. */ + BUILD_BUG_ON(!__is_kfree_rcu_offset(offset)); + + call_rcu(head, (rcu_callback)offset); +} + +extern void kfree(const void *); + +static inline void __rcu_reclaim(struct rcu_head *head) +{ + unsigned long offset = (unsigned long)head->func; + + if (__is_kfree_rcu_offset(offset)) + kfree((void *)head - offset); + else + head->func(head); +} + +/** + * kfree_rcu() - kfree an object after a grace period. + * @ptr: pointer to kfree + * @rcu_head: the name of the struct rcu_head within the type of @ptr. + * + * Many rcu callbacks functions just call kfree() on the base structure. + * These functions are trivial, but their size adds up, and furthermore + * when they are used in a kernel module, that module must invoke the + * high-latency rcu_barrier() function at module-unload time. + * + * The kfree_rcu() function handles this issue. Rather than encoding a + * function address in the embedded rcu_head structure, kfree_rcu() instead + * encodes the offset of the rcu_head structure within the base structure. + * Because the functions are not allowed in the low-order 4096 bytes of + * kernel virtual memory, offsets up to 4095 bytes can be accommodated. + * If the offset is larger than 4095 bytes, a compile-time error will + * be generated in __kfree_rcu(). If this error is triggered, you can + * either fall back to use of call_rcu() or rearrange the structure to + * position the rcu_head structure into the first 4096 bytes. + * + * Note that the allowable offset might decrease in the future, for example, + * to allow something like kmem_cache_free_rcu(). + */ +#define kfree_rcu(ptr, rcu_head) \ + __kfree_rcu(&((ptr)->rcu_head), offsetof(typeof(*(ptr)), rcu_head)) + #endif /* __LINUX_RCUPDATE_H */ diff --git a/kernel/rcutiny.c b/kernel/rcutiny.c index 0c343b9..4d60fbc 100644 --- a/kernel/rcutiny.c +++ b/kernel/rcutiny.c @@ -167,7 +167,7 @@ static void rcu_process_callbacks(struct rcu_ctrlblk *rcp) prefetch(next); debug_rcu_head_unqueue(list); local_bh_disable(); - list->func(list); + __rcu_reclaim(list); local_bh_enable(); list = next; RCU_TRACE(cb_count++); diff --git a/kernel/rcutree.c b/kernel/rcutree.c index b579e4f..2c07adb 100644 --- a/kernel/rcutree.c +++ b/kernel/rcutree.c @@ -1206,7 +1206,7 @@ static void rcu_do_batch(struct rcu_state *rsp, struct rcu_data *rdp) next = list->next; prefetch(next); debug_rcu_head_unqueue(list); - list->func(list); + __rcu_reclaim(list); list = next; if (++count >= rdp->blimit) break; -- cgit v0.10.2 From baa1ae0c9f1c618bc60706efa75fef3508bcee58 Mon Sep 17 00:00:00 2001 From: "Paul E. McKenney" Date: Sat, 26 Mar 2011 22:01:35 -0700 Subject: rcu: further lower priority in rcu_yield() Although rcu_yield() dropped from real-time to normal priority, there is always the possibility that the competing tasks have been niced. So nice to 19 in rcu_yield() to help ensure that other tasks have a better chance of running. Signed-off-by: Paul E. McKenney Signed-off-by: Paul E. McKenney Reviewed-by: Josh Triplett diff --git a/kernel/rcutree.c b/kernel/rcutree.c index 2c07adb..fe85600 100644 --- a/kernel/rcutree.c +++ b/kernel/rcutree.c @@ -1561,6 +1561,7 @@ static void rcu_yield(void (*f)(unsigned long), unsigned long arg) mod_timer(&yield_timer, jiffies + 2); sp.sched_priority = 0; sched_setscheduler_nocheck(current, SCHED_NORMAL, &sp); + set_user_nice(current, 19); schedule(); sp.sched_priority = RCU_KTHREAD_PRIO; sched_setscheduler_nocheck(current, SCHED_FIFO, &sp); -- cgit v0.10.2 From 2655d57ef35aa327a2e58a1c5dc7b65c65003f4e Mon Sep 17 00:00:00 2001 From: "Paul E. McKenney" Date: Thu, 7 Apr 2011 22:47:23 -0700 Subject: rcu: prevent call_rcu() from diving into rcu core if irqs disabled This commit marks a first step towards making call_rcu() have real-time behavior. If irqs are disabled, don't dive into the RCU core. Later on, this new early exit will wake up the per-CPU kthread, which first must be modified to handle the cases involving callback storms. Signed-off-by: Paul E. McKenney Reviewed-by: Josh Triplett diff --git a/kernel/rcutree.c b/kernel/rcutree.c index fe85600..78923a5 100644 --- a/kernel/rcutree.c +++ b/kernel/rcutree.c @@ -1839,6 +1839,13 @@ __call_rcu(struct rcu_head *head, void (*func)(struct rcu_head *rcu), /* Add the callback to our list. */ *rdp->nxttail[RCU_NEXT_TAIL] = head; rdp->nxttail[RCU_NEXT_TAIL] = &head->next; + rdp->qlen++; + + /* If interrupts were disabled, don't dive into RCU core. */ + if (irqs_disabled_flags(flags)) { + local_irq_restore(flags); + return; + } /* * Force the grace period if too many callbacks or too long waiting. @@ -1847,7 +1854,7 @@ __call_rcu(struct rcu_head *head, void (*func)(struct rcu_head *rcu), * invoking force_quiescent_state() if the newly enqueued callback * is the only one waiting for a grace period to complete. */ - if (unlikely(++rdp->qlen > rdp->qlen_last_fqs_check + qhimark)) { + if (unlikely(rdp->qlen > rdp->qlen_last_fqs_check + qhimark)) { /* Are we ignoring a completed grace period? */ rcu_process_gp_end(rsp, rdp); -- cgit v0.10.2 From b554d7de8d112fca4188da3bf0d7f8b56f42fb95 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Thu, 28 Apr 2011 07:23:45 +0200 Subject: rcu: optimize rcutiny rcu_sched_qs() currently calls local_irq_save()/local_irq_restore() up to three times. Remove irq masking from rcu_qsctr_help() / invoke_rcu_kthread() and do it once in rcu_sched_qs() / rcu_bh_qs() This generates smaller code as well. text data bss dec hex filename 2314 156 24 2494 9be kernel/rcutiny.old.o 2250 156 24 2430 97e kernel/rcutiny.new.o Fix an outdated comment for rcu_qsctr_help() Move invoke_rcu_kthread() definition before its use. Signed-off-by: Eric Dumazet Signed-off-by: Paul E. McKenney Reviewed-by: Josh Triplett diff --git a/kernel/rcutiny.c b/kernel/rcutiny.c index 4d60fbc..421abfd 100644 --- a/kernel/rcutiny.c +++ b/kernel/rcutiny.c @@ -40,10 +40,10 @@ static struct task_struct *rcu_kthread_task; static DECLARE_WAIT_QUEUE_HEAD(rcu_kthread_wq); static unsigned long have_rcu_kthread_work; -static void invoke_rcu_kthread(void); /* Forward declarations for rcutiny_plugin.h. */ struct rcu_ctrlblk; +static void invoke_rcu_kthread(void); static void rcu_process_callbacks(struct rcu_ctrlblk *rcp); static int rcu_kthread(void *arg); static void __call_rcu(struct rcu_head *head, @@ -79,36 +79,45 @@ void rcu_exit_nohz(void) #endif /* #ifdef CONFIG_NO_HZ */ /* - * Helper function for rcu_qsctr_inc() and rcu_bh_qsctr_inc(). - * Also disable irqs to avoid confusion due to interrupt handlers + * Helper function for rcu_sched_qs() and rcu_bh_qs(). + * Also irqs are disabled to avoid confusion due to interrupt handlers * invoking call_rcu(). */ static int rcu_qsctr_help(struct rcu_ctrlblk *rcp) { - unsigned long flags; - - local_irq_save(flags); if (rcp->rcucblist != NULL && rcp->donetail != rcp->curtail) { rcp->donetail = rcp->curtail; - local_irq_restore(flags); return 1; } - local_irq_restore(flags); return 0; } /* + * Wake up rcu_kthread() to process callbacks now eligible for invocation + * or to boost readers. + */ +static void invoke_rcu_kthread(void) +{ + have_rcu_kthread_work = 1; + wake_up(&rcu_kthread_wq); +} + +/* * Record an rcu quiescent state. And an rcu_bh quiescent state while we * are at it, given that any rcu quiescent state is also an rcu_bh * quiescent state. Use "+" instead of "||" to defeat short circuiting. */ void rcu_sched_qs(int cpu) { + unsigned long flags; + + local_irq_save(flags); if (rcu_qsctr_help(&rcu_sched_ctrlblk) + rcu_qsctr_help(&rcu_bh_ctrlblk)) invoke_rcu_kthread(); + local_irq_restore(flags); } /* @@ -116,8 +125,12 @@ void rcu_sched_qs(int cpu) */ void rcu_bh_qs(int cpu) { + unsigned long flags; + + local_irq_save(flags); if (rcu_qsctr_help(&rcu_bh_ctrlblk)) invoke_rcu_kthread(); + local_irq_restore(flags); } /* @@ -208,20 +221,6 @@ static int rcu_kthread(void *arg) } /* - * Wake up rcu_kthread() to process callbacks now eligible for invocation - * or to boost readers. - */ -static void invoke_rcu_kthread(void) -{ - unsigned long flags; - - local_irq_save(flags); - have_rcu_kthread_work = 1; - wake_up(&rcu_kthread_wq); - local_irq_restore(flags); -} - -/* * Wait for a grace period to elapse. But it is illegal to invoke * synchronize_sched() from within an RCU read-side critical section. * Therefore, any legal call to synchronize_sched() is a quiescent -- cgit v0.10.2 From bad6e1393cb505fe17747344a23666464daa3fa7 Mon Sep 17 00:00:00 2001 From: "Paul E. McKenney" Date: Mon, 2 May 2011 23:40:04 -0700 Subject: rcu: get rid of signed overflow in check_cpu_stall() Signed integer overflow is undefined by the C standard, so move calculations to unsigned. Signed-off-by: Paul E. McKenney diff --git a/kernel/rcutree.c b/kernel/rcutree.c index 78923a5..b2fe2a2 100644 --- a/kernel/rcutree.c +++ b/kernel/rcutree.c @@ -581,21 +581,24 @@ static void print_cpu_stall(struct rcu_state *rsp) static void check_cpu_stall(struct rcu_state *rsp, struct rcu_data *rdp) { - long delta; + unsigned long j; + unsigned long js; struct rcu_node *rnp; if (rcu_cpu_stall_suppress) return; - delta = jiffies - ACCESS_ONCE(rsp->jiffies_stall); + j = ACCESS_ONCE(jiffies); + js = ACCESS_ONCE(rsp->jiffies_stall); rnp = rdp->mynode; - if ((ACCESS_ONCE(rnp->qsmask) & rdp->grpmask) && delta >= 0) { + if ((ACCESS_ONCE(rnp->qsmask) & rdp->grpmask) && ULONG_CMP_GE(j, js)) { /* We haven't checked in, so go dump stack. */ print_cpu_stall(rsp); - } else if (rcu_gp_in_progress(rsp) && delta >= RCU_STALL_RAT_DELAY) { + } else if (rcu_gp_in_progress(rsp) && + ULONG_CMP_GE(j, js + RCU_STALL_RAT_DELAY)) { - /* They had two time units to dump stack, so complain. */ + /* They had a few time units to dump stack, so complain. */ print_other_cpu_stall(rsp); } } -- cgit v0.10.2 From 29ce831000081dd757d3116bf774aafffc4b6b20 Mon Sep 17 00:00:00 2001 From: Gleb Natapov Date: Wed, 4 May 2011 16:31:03 +0300 Subject: rcu: provide rcu_virt_note_context_switch() function. Provide rcu_virt_note_context_switch() for vitalization use to note quiescent state during guest entry. Signed-off-by: Gleb Natapov Signed-off-by: Paul E. McKenney diff --git a/include/linux/rcutiny.h b/include/linux/rcutiny.h index 30ebd7c..52b3e02 100644 --- a/include/linux/rcutiny.h +++ b/include/linux/rcutiny.h @@ -100,6 +100,14 @@ static inline void rcu_note_context_switch(int cpu) } /* + * Take advantage of the fact that there is only one CPU, which + * allows us to ignore virtualization-based context switches. + */ +static inline void rcu_virt_note_context_switch(int cpu) +{ +} + +/* * Return the number of grace periods. */ static inline long rcu_batches_completed(void) diff --git a/include/linux/rcutree.h b/include/linux/rcutree.h index 284dad1..e65d066 100644 --- a/include/linux/rcutree.h +++ b/include/linux/rcutree.h @@ -35,6 +35,16 @@ extern void rcu_note_context_switch(int cpu); extern int rcu_needs_cpu(int cpu); extern void rcu_cpu_stall_reset(void); +/* + * Note a virtualization-based context switch. This is simply a + * wrapper around rcu_note_context_switch(), which allows TINY_RCU + * to save a few bytes. + */ +static inline void rcu_virt_note_context_switch(int cpu) +{ + rcu_note_context_switch(cpu); +} + #ifdef CONFIG_TREE_PREEMPT_RCU extern void exit_rcu(void); diff --git a/kernel/rcutree.c b/kernel/rcutree.c index b2fe2a2..54ff7eb 100644 --- a/kernel/rcutree.c +++ b/kernel/rcutree.c @@ -157,6 +157,7 @@ void rcu_note_context_switch(int cpu) rcu_sched_qs(cpu); rcu_preempt_note_context_switch(cpu); } +EXPORT_SYMBOL_GPL(rcu_note_context_switch); #ifdef CONFIG_NO_HZ DEFINE_PER_CPU(struct rcu_dynticks, rcu_dynticks) = { -- cgit v0.10.2 From 4934a4d3d3fa775601a9f1b35cc0e2aa93f81355 Mon Sep 17 00:00:00 2001 From: Rakib Mullick Date: Wed, 4 May 2011 22:53:46 +0600 Subject: sched: Wrap the 'cfs_rq->nr_spread_over' field with CONFIG_SCHED_DEBUG cfs_rq->nr_spread_over is only used when CONFIG_SCHED_DEBUG is set. So wrap it with CONFIG_SCHED_DEBUG. Signed-off-by: Rakib Mullick Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/1304528026.15681.3.camel@localhost.localdomain Signed-off-by: Ingo Molnar diff --git a/kernel/sched.c b/kernel/sched.c index f11a2a5..3d8a1b2 100644 --- a/kernel/sched.c +++ b/kernel/sched.c @@ -328,7 +328,9 @@ struct cfs_rq { */ struct sched_entity *curr, *next, *last, *skip; +#ifdef CONFIG_SCHED_DEBUG unsigned int nr_spread_over; +#endif #ifdef CONFIG_FAIR_GROUP_SCHED struct rq *rq; /* cpu runqueue to which this cfs_rq is attached */ -- cgit v0.10.2 From 7142d17e8f935fa842e9f6eece2281b6d41625d6 Mon Sep 17 00:00:00 2001 From: Hillf Danton Date: Thu, 5 May 2011 20:53:20 +0800 Subject: sched: Shorten the construction of the span cpu mask of sched domain For a given node, when constructing the cpumask for its sched_domain to span, if there is no best node available after searching, further efforts could be saved, based on small change in the return value of find_next_best_node(). Signed-off-by: Hillf Danton Cc: Peter Zijlstra Cc: Mike Galbraith Cc: Yong Zhang Link: http://lkml.kernel.org/r/BANLkTi%3DqPWxRAa6%2BdT3ohEP6Z%3D0v%2Be4EXA@mail.gmail.com Signed-off-by: Ingo Molnar diff --git a/kernel/sched.c b/kernel/sched.c index 3d8a1b2..da93381 100644 --- a/kernel/sched.c +++ b/kernel/sched.c @@ -6807,7 +6807,7 @@ __setup("isolcpus=", isolated_cpu_setup); */ static int find_next_best_node(int node, nodemask_t *used_nodes) { - int i, n, val, min_val, best_node = 0; + int i, n, val, min_val, best_node = -1; min_val = INT_MAX; @@ -6831,7 +6831,8 @@ static int find_next_best_node(int node, nodemask_t *used_nodes) } } - node_set(best_node, *used_nodes); + if (best_node != -1) + node_set(best_node, *used_nodes); return best_node; } @@ -6857,7 +6858,8 @@ static void sched_domain_node_span(int node, struct cpumask *span) for (i = 1; i < SD_NODES_PER_DOMAIN; i++) { int next_node = find_next_best_node(node, &used_nodes); - + if (next_node < 0) + break; cpumask_or(span, span, cpumask_of_node(next_node)); } } -- cgit v0.10.2 From 56f3aeb2c14b9d000dfc77f352250bc3b67af5c0 Mon Sep 17 00:00:00 2001 From: Russell King Date: Fri, 6 May 2011 08:14:57 +0100 Subject: ARM: RiscPC: etherh: fix section mismatches WARNING: drivers/net/arm/built-in.o(.data+0x0): Section mismatch in reference from the variable etherh_driver to the function .init.text:etherh_probe() The variable etherh_driver references the function __init etherh_probe() If the reference is valid then annotate the variable with __init* or __refdata (see linux/init.h) or name the variable: *_template, *_timer, *_sht, *_ops, *_probe, *_probe_one, *_console Signed-off-by: Russell King diff --git a/drivers/net/arm/etherh.c b/drivers/net/arm/etherh.c index 4af235d..fbfb5b4 100644 --- a/drivers/net/arm/etherh.c +++ b/drivers/net/arm/etherh.c @@ -527,7 +527,7 @@ static void __init etherh_banner(void) * Read the ethernet address string from the on board rom. * This is an ascii string... */ -static int __init etherh_addr(char *addr, struct expansion_card *ec) +static int __devinit etherh_addr(char *addr, struct expansion_card *ec) { struct in_chunk_dir cd; char *s; @@ -655,7 +655,7 @@ static const struct net_device_ops etherh_netdev_ops = { static u32 etherh_regoffsets[16]; static u32 etherm_regoffsets[16]; -static int __init +static int __devinit etherh_probe(struct expansion_card *ec, const struct ecard_id *id) { const struct etherh_data *data = id->data; -- cgit v0.10.2 From 52fe116376129b29572f55acc9c73ebd485052c9 Mon Sep 17 00:00:00 2001 From: Russell King Date: Fri, 6 May 2011 08:16:51 +0100 Subject: ARM: RiscPC: acornfb: fix section mismatches WARNING: drivers/video/built-in.o(.devinit.text+0x38): Section mismatch in reference from the function acornfb_probe() to the function .init.text:acornfb_setup() The function __devinit acornfb_probe() references a function __init acornfb_setup(). If acornfb_setup is only used by acornfb_probe then annotate acornfb_setup with a matching annotation. WARNING: drivers/video/built-in.o(.devinit.text+0x3c): Section mismatch in reference from the function acornfb_probe() to the function .init.text:acornfb_init_fbinfo() The function __devinit acornfb_probe() references a function __init acornfb_init_fbinfo(). If acornfb_init_fbinfo is only used by acornfb_probe then annotate acornfb_init_fbinfo with a matching annotation. WARNING: drivers/video/built-in.o(.devinit.text+0x4c0): Section mismatch in reference from the function acornfb_probe() to the (unknown reference) .init.data:(unknown) The function __devinit acornfb_probe() references a (unknown reference) __initdata (unknown). If (unknown) is only used by acornfb_probe then annotate (unknown) with a matching annotation. WARNING: drivers/video/built-in.o(.devinit.text+0x4c8): Section mismatch in reference from the function acornfb_probe() to the (unknown reference) .init.data:(unknown) The function __devinit acornfb_probe() references a (unknown reference) __initdata (unknown). If (unknown) is only used by acornfb_probe then annotate (unknown) with a matching annotation. WARNING: drivers/video/built-in.o(.devinit.text+0x4cc): Section mismatch in reference from the function acornfb_probe() to the (unknown reference) .init.data:(unknown) The function __devinit acornfb_probe() references a (unknown reference) __initdata (unknown). If (unknown) is only used by acornfb_probe then annotate (unknown) with a matching annotation. Signed-off-by: Russell King diff --git a/drivers/video/acornfb.c b/drivers/video/acornfb.c index 82acb8d..6183a57 100644 --- a/drivers/video/acornfb.c +++ b/drivers/video/acornfb.c @@ -66,7 +66,7 @@ * have. Allow 1% either way on the nominal for TVs. */ #define NR_MONTYPES 6 -static struct fb_monspecs monspecs[NR_MONTYPES] __initdata = { +static struct fb_monspecs monspecs[NR_MONTYPES] __devinitdata = { { /* TV */ .hfmin = 15469, .hfmax = 15781, @@ -873,7 +873,7 @@ static struct fb_ops acornfb_ops = { /* * Everything after here is initialisation!!! */ -static struct fb_videomode modedb[] __initdata = { +static struct fb_videomode modedb[] __devinitdata = { { /* 320x256 @ 50Hz */ NULL, 50, 320, 256, 125000, 92, 62, 35, 19, 38, 2, FB_SYNC_COMP_HIGH_ACT, @@ -925,8 +925,7 @@ static struct fb_videomode modedb[] __initdata = { } }; -static struct fb_videomode __initdata -acornfb_default_mode = { +static struct fb_videomode acornfb_default_mode __devinitdata = { .name = NULL, .refresh = 60, .xres = 640, @@ -942,7 +941,7 @@ acornfb_default_mode = { .vmode = FB_VMODE_NONINTERLACED }; -static void __init acornfb_init_fbinfo(void) +static void __devinit acornfb_init_fbinfo(void) { static int first = 1; @@ -1018,8 +1017,7 @@ static void __init acornfb_init_fbinfo(void) * size can optionally be followed by 'M' or 'K' for * MB or KB respectively. */ -static void __init -acornfb_parse_mon(char *opt) +static void __devinit acornfb_parse_mon(char *opt) { char *p = opt; @@ -1066,8 +1064,7 @@ bad: current_par.montype = -1; } -static void __init -acornfb_parse_montype(char *opt) +static void __devinit acornfb_parse_montype(char *opt) { current_par.montype = -2; @@ -1108,8 +1105,7 @@ acornfb_parse_montype(char *opt) } } -static void __init -acornfb_parse_dram(char *opt) +static void __devinit acornfb_parse_dram(char *opt) { unsigned int size; @@ -1134,15 +1130,14 @@ acornfb_parse_dram(char *opt) static struct options { char *name; void (*parse)(char *opt); -} opt_table[] __initdata = { +} opt_table[] __devinitdata = { { "mon", acornfb_parse_mon }, { "montype", acornfb_parse_montype }, { "dram", acornfb_parse_dram }, { NULL, NULL } }; -int __init -acornfb_setup(char *options) +static int __devinit acornfb_setup(char *options) { struct options *optp; char *opt; @@ -1179,8 +1174,7 @@ acornfb_setup(char *options) * Detect type of monitor connected * For now, we just assume SVGA */ -static int __init -acornfb_detect_monitortype(void) +static int __devinit acornfb_detect_monitortype(void) { return 4; } -- cgit v0.10.2 From e04d1b23f9706186187dcb0be1a752e48dcc540b Mon Sep 17 00:00:00 2001 From: Lin Ming Date: Fri, 6 May 2011 07:14:02 +0000 Subject: perf events, x86: Add SandyBridge stalled-cycles-frontend/backend events Extend the Intel SandyBridge PMU driver with definitions for generic front-end and back-end stall events. ( As commit 3011203 "perf events, x86: Add Westmere stalled-cycles-frontend/backend events" says, these are only approximations. ) Signed-off-by: Lin Ming Cc: Peter Zijlstra Cc: Arnaldo Carvalho de Melo Cc: Frederic Weisbecker Cc: Mike Galbraith Cc: Steven Rostedt Link: http://lkml.kernel.org/r/1304666042-17577-1-git-send-email-ming.m.lin@intel.com Signed-off-by: Ingo Molnar diff --git a/arch/x86/kernel/cpu/perf_event_intel.c b/arch/x86/kernel/cpu/perf_event_intel.c index e61539b..7cf2ec5 100644 --- a/arch/x86/kernel/cpu/perf_event_intel.c +++ b/arch/x86/kernel/cpu/perf_event_intel.c @@ -1474,6 +1474,12 @@ static __init int intel_pmu_init(void) x86_pmu.event_constraints = intel_snb_event_constraints; x86_pmu.pebs_constraints = intel_snb_pebs_events; + + /* UOPS_ISSUED.ANY,c=1,i=1 to count stall cycles */ + intel_perfmon_event_map[PERF_COUNT_HW_STALLED_CYCLES_FRONTEND] = 0x180010e; + /* UOPS_DISPATCHED.THREAD,c=1,i=1 to count stall cycles*/ + intel_perfmon_event_map[PERF_COUNT_HW_STALLED_CYCLES_BACKEND] = 0x18001b1; + pr_cont("SandyBridge events, "); break; -- cgit v0.10.2 From 925f83c085e1bb08435556c5b4844a60de002e31 Mon Sep 17 00:00:00 2001 From: Frederic Weisbecker Date: Fri, 6 May 2011 01:53:18 +0200 Subject: hw_breakpoints, powerpc: Fix CONFIG_HAVE_HW_BREAKPOINT off-case in ptrace_set_debugreg() We make use of ptrace_get_breakpoints() / ptrace_put_breakpoints() to protect ptrace_set_debugreg() even if CONFIG_HAVE_HW_BREAKPOINT if off. However in this case, these APIs are not implemented. To fix this, push the protection down inside the relevant ifdef. Best would be to export the code inside CONFIG_HAVE_HW_BREAKPOINT into a standalone function to cleanup the ifdefury there and call the breakpoint ref API inside. But as it is more invasive, this should be rather made in an -rc1. Fixes this build error: arch/powerpc/kernel/ptrace.c:1594: error: implicit declaration of function 'ptrace_get_breakpoints' make[2]: *** Reported-by: Ingo Molnar Signed-off-by: Frederic Weisbecker Cc: LPPC Cc: Prasad Cc: v2.6.33.. Link: http://lkml.kernel.org/r/1304639598-4707-1-git-send-email-fweisbec@gmail.com Signed-off-by: Ingo Molnar diff --git a/arch/powerpc/kernel/ptrace.c b/arch/powerpc/kernel/ptrace.c index 4edeeb3..a6ae1cf 100644 --- a/arch/powerpc/kernel/ptrace.c +++ b/arch/powerpc/kernel/ptrace.c @@ -933,12 +933,16 @@ int ptrace_set_debugreg(struct task_struct *task, unsigned long addr, if (data && !(data & DABR_TRANSLATION)) return -EIO; #ifdef CONFIG_HAVE_HW_BREAKPOINT + if (ptrace_get_breakpoints(task) < 0) + return -ESRCH; + bp = thread->ptrace_bps[0]; if ((!data) || !(data & (DABR_DATA_WRITE | DABR_DATA_READ))) { if (bp) { unregister_hw_breakpoint(bp); thread->ptrace_bps[0] = NULL; } + ptrace_put_breakpoints(task); return 0; } if (bp) { @@ -948,9 +952,12 @@ int ptrace_set_debugreg(struct task_struct *task, unsigned long addr, (DABR_DATA_WRITE | DABR_DATA_READ), &attr.bp_type); ret = modify_user_hw_breakpoint(bp, &attr); - if (ret) + if (ret) { + ptrace_put_breakpoints(task); return ret; + } thread->ptrace_bps[0] = bp; + ptrace_put_breakpoints(task); thread->dabr = data; return 0; } @@ -965,9 +972,12 @@ int ptrace_set_debugreg(struct task_struct *task, unsigned long addr, ptrace_triggered, task); if (IS_ERR(bp)) { thread->ptrace_bps[0] = NULL; + ptrace_put_breakpoints(task); return PTR_ERR(bp); } + ptrace_put_breakpoints(task); + #endif /* CONFIG_HAVE_HW_BREAKPOINT */ /* Move contents to the DABR register */ @@ -1591,10 +1601,7 @@ long arch_ptrace(struct task_struct *child, long request, } case PTRACE_SET_DEBUGREG: - if (ptrace_get_breakpoints(child) < 0) - return -ESRCH; ret = ptrace_set_debugreg(child, addr, data); - ptrace_put_breakpoints(child); break; #ifdef CONFIG_PPC64 -- cgit v0.10.2 From 63b6a6758eede2f9283c3594265b6e32e75d7456 Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Sat, 23 Apr 2011 00:57:42 +0200 Subject: perf events, x86: Fix Intel Nehalem and Westmere last level cache event definitions The Intel Nehalem offcore bits implemented in: e994d7d23a0b: perf: Fix LLC-* events on Intel Nehalem/Westmere ... are wrong: they implemented _ACCESS as _HIT and counted OTHER_CORE_HIT* as MISS even though its clearly documented as an L3 hit ... Fix them and the Westmere definitions as well. Cc: Andi Kleen Cc: Lin Ming Cc: Arnaldo Carvalho de Melo Cc: Frederic Weisbecker Cc: Mike Galbraith Cc: Steven Rostedt Link: http://lkml.kernel.org/r/1299119690-13991-3-git-send-email-ming.m.lin@intel.com Signed-off-by: Ingo Molnar diff --git a/arch/x86/kernel/cpu/perf_event_intel.c b/arch/x86/kernel/cpu/perf_event_intel.c index e61539b..447a28d 100644 --- a/arch/x86/kernel/cpu/perf_event_intel.c +++ b/arch/x86/kernel/cpu/perf_event_intel.c @@ -184,26 +184,23 @@ static __initconst const u64 snb_hw_cache_event_ids }, }, [ C(LL ) ] = { - /* - * TBD: Need Off-core Response Performance Monitoring support - */ [ C(OP_READ) ] = { - /* OFFCORE_RESPONSE_0.ANY_DATA.LOCAL_CACHE */ + /* OFFCORE_RESPONSE.ANY_DATA.LOCAL_CACHE */ [ C(RESULT_ACCESS) ] = 0x01b7, - /* OFFCORE_RESPONSE_1.ANY_DATA.ANY_LLC_MISS */ - [ C(RESULT_MISS) ] = 0x01bb, + /* OFFCORE_RESPONSE.ANY_DATA.ANY_LLC_MISS */ + [ C(RESULT_MISS) ] = 0x01b7, }, [ C(OP_WRITE) ] = { - /* OFFCORE_RESPONSE_0.ANY_RFO.LOCAL_CACHE */ + /* OFFCORE_RESPONSE.ANY_RFO.LOCAL_CACHE */ [ C(RESULT_ACCESS) ] = 0x01b7, - /* OFFCORE_RESPONSE_1.ANY_RFO.ANY_LLC_MISS */ - [ C(RESULT_MISS) ] = 0x01bb, + /* OFFCORE_RESPONSE.ANY_RFO.ANY_LLC_MISS */ + [ C(RESULT_MISS) ] = 0x01b7, }, [ C(OP_PREFETCH) ] = { - /* OFFCORE_RESPONSE_0.PREFETCH.LOCAL_CACHE */ + /* OFFCORE_RESPONSE.PREFETCH.LOCAL_CACHE */ [ C(RESULT_ACCESS) ] = 0x01b7, - /* OFFCORE_RESPONSE_1.PREFETCH.ANY_LLC_MISS */ - [ C(RESULT_MISS) ] = 0x01bb, + /* OFFCORE_RESPONSE.PREFETCH.ANY_LLC_MISS */ + [ C(RESULT_MISS) ] = 0x01b7, }, }, [ C(DTLB) ] = { @@ -285,26 +282,26 @@ static __initconst const u64 westmere_hw_cache_event_ids }, [ C(LL ) ] = { [ C(OP_READ) ] = { - /* OFFCORE_RESPONSE_0.ANY_DATA.LOCAL_CACHE */ + /* OFFCORE_RESPONSE.ANY_DATA.LOCAL_CACHE */ [ C(RESULT_ACCESS) ] = 0x01b7, - /* OFFCORE_RESPONSE_1.ANY_DATA.ANY_LLC_MISS */ - [ C(RESULT_MISS) ] = 0x01bb, + /* OFFCORE_RESPONSE.ANY_DATA.ANY_LLC_MISS */ + [ C(RESULT_MISS) ] = 0x01b7, }, /* * Use RFO, not WRITEBACK, because a write miss would typically occur * on RFO. */ [ C(OP_WRITE) ] = { - /* OFFCORE_RESPONSE_1.ANY_RFO.LOCAL_CACHE */ - [ C(RESULT_ACCESS) ] = 0x01bb, - /* OFFCORE_RESPONSE_0.ANY_RFO.ANY_LLC_MISS */ + /* OFFCORE_RESPONSE.ANY_RFO.LOCAL_CACHE */ + [ C(RESULT_ACCESS) ] = 0x01b7, + /* OFFCORE_RESPONSE.ANY_RFO.ANY_LLC_MISS */ [ C(RESULT_MISS) ] = 0x01b7, }, [ C(OP_PREFETCH) ] = { - /* OFFCORE_RESPONSE_0.PREFETCH.LOCAL_CACHE */ + /* OFFCORE_RESPONSE.PREFETCH.LOCAL_CACHE */ [ C(RESULT_ACCESS) ] = 0x01b7, - /* OFFCORE_RESPONSE_1.PREFETCH.ANY_LLC_MISS */ - [ C(RESULT_MISS) ] = 0x01bb, + /* OFFCORE_RESPONSE.PREFETCH.ANY_LLC_MISS */ + [ C(RESULT_MISS) ] = 0x01b7, }, }, [ C(DTLB) ] = { @@ -352,16 +349,36 @@ static __initconst const u64 westmere_hw_cache_event_ids }; /* - * OFFCORE_RESPONSE MSR bits (subset), See IA32 SDM Vol 3 30.6.1.3 + * Nehalem/Westmere MSR_OFFCORE_RESPONSE bits; + * See IA32 SDM Vol 3B 30.6.1.3 */ -#define DMND_DATA_RD (1 << 0) -#define DMND_RFO (1 << 1) -#define DMND_WB (1 << 3) -#define PF_DATA_RD (1 << 4) -#define PF_DATA_RFO (1 << 5) -#define RESP_UNCORE_HIT (1 << 8) -#define RESP_MISS (0xf600) /* non uncore hit */ +#define NHM_DMND_DATA_RD (1 << 0) +#define NHM_DMND_RFO (1 << 1) +#define NHM_DMND_IFETCH (1 << 2) +#define NHM_DMND_WB (1 << 3) +#define NHM_PF_DATA_RD (1 << 4) +#define NHM_PF_DATA_RFO (1 << 5) +#define NHM_PF_IFETCH (1 << 6) +#define NHM_OFFCORE_OTHER (1 << 7) +#define NHM_UNCORE_HIT (1 << 8) +#define NHM_OTHER_CORE_HIT_SNP (1 << 9) +#define NHM_OTHER_CORE_HITM (1 << 10) + /* reserved */ +#define NHM_REMOTE_CACHE_FWD (1 << 12) +#define NHM_REMOTE_DRAM (1 << 13) +#define NHM_LOCAL_DRAM (1 << 14) +#define NHM_NON_DRAM (1 << 15) + +#define NHM_ALL_DRAM (NHM_REMOTE_DRAM|NHM_LOCAL_DRAM) + +#define NHM_DMND_READ (NHM_DMND_DATA_RD) +#define NHM_DMND_WRITE (NHM_DMND_RFO|NHM_DMND_WB) +#define NHM_DMND_PREFETCH (NHM_PF_DATA_RD|NHM_PF_DATA_RFO) + +#define NHM_L3_HIT (NHM_UNCORE_HIT|NHM_OTHER_CORE_HIT_SNP|NHM_OTHER_CORE_HITM) +#define NHM_L3_MISS (NHM_NON_DRAM|NHM_ALL_DRAM|NHM_REMOTE_CACHE_FWD) +#define NHM_L3_ACCESS (NHM_L3_HIT|NHM_L3_MISS) static __initconst const u64 nehalem_hw_cache_extra_regs [PERF_COUNT_HW_CACHE_MAX] @@ -370,16 +387,16 @@ static __initconst const u64 nehalem_hw_cache_extra_regs { [ C(LL ) ] = { [ C(OP_READ) ] = { - [ C(RESULT_ACCESS) ] = DMND_DATA_RD|RESP_UNCORE_HIT, - [ C(RESULT_MISS) ] = DMND_DATA_RD|RESP_MISS, + [ C(RESULT_ACCESS) ] = NHM_DMND_READ|NHM_L3_ACCESS, + [ C(RESULT_MISS) ] = NHM_DMND_READ|NHM_L3_MISS, }, [ C(OP_WRITE) ] = { - [ C(RESULT_ACCESS) ] = DMND_RFO|DMND_WB|RESP_UNCORE_HIT, - [ C(RESULT_MISS) ] = DMND_RFO|DMND_WB|RESP_MISS, + [ C(RESULT_ACCESS) ] = NHM_DMND_WRITE|NHM_L3_ACCESS, + [ C(RESULT_MISS) ] = NHM_DMND_WRITE|NHM_L3_MISS, }, [ C(OP_PREFETCH) ] = { - [ C(RESULT_ACCESS) ] = PF_DATA_RD|PF_DATA_RFO|RESP_UNCORE_HIT, - [ C(RESULT_MISS) ] = PF_DATA_RD|PF_DATA_RFO|RESP_MISS, + [ C(RESULT_ACCESS) ] = NHM_DMND_PREFETCH|NHM_L3_ACCESS, + [ C(RESULT_MISS) ] = NHM_DMND_PREFETCH|NHM_L3_MISS, }, } }; -- cgit v0.10.2 From fa039d5f6b126fbd65eefa05db2f67e44df8f121 Mon Sep 17 00:00:00 2001 From: Timo Warns Date: Fri, 6 May 2011 13:47:35 +0200 Subject: Validate size of EFI GUID partition entries. Otherwise corrupted EFI partition tables can cause total confusion. Signed-off-by: Timo Warns Cc: stable@kernel.org Signed-off-by: Linus Torvalds diff --git a/fs/partitions/efi.c b/fs/partitions/efi.c index ac0ccb5..19d6750 100644 --- a/fs/partitions/efi.c +++ b/fs/partitions/efi.c @@ -348,6 +348,12 @@ static int is_gpt_valid(struct parsed_partitions *state, u64 lba, goto fail; } + /* Check that sizeof_partition_entry has the correct value */ + if (le32_to_cpu((*gpt)->sizeof_partition_entry) != sizeof(gpt_entry)) { + pr_debug("GUID Partitition Entry Size check failed.\n"); + goto fail; + } + if (!(*ptes = alloc_read_gpt_entries(state, *gpt))) goto fail; -- cgit v0.10.2 From ed16648eb5b86917f0b90bdcdbc857202da72f90 Mon Sep 17 00:00:00 2001 From: Rob Landley Date: Fri, 6 May 2011 09:22:02 -0700 Subject: Move kvm, uml, and lguest subdirectories under a common "virtual" directory, I.E: cd Documentation mkdir virtual git mv kvm uml lguest virtual Signed-off-by: Rob Landley Signed-off-by: Randy Dunlap diff --git a/Documentation/kvm/api.txt b/Documentation/kvm/api.txt deleted file mode 100644 index 9bef4e4..0000000 --- a/Documentation/kvm/api.txt +++ /dev/null @@ -1,1451 +0,0 @@ -The Definitive KVM (Kernel-based Virtual Machine) API Documentation -=================================================================== - -1. General description - -The kvm API is a set of ioctls that are issued to control various aspects -of a virtual machine. The ioctls belong to three classes - - - System ioctls: These query and set global attributes which affect the - whole kvm subsystem. In addition a system ioctl is used to create - virtual machines - - - VM ioctls: These query and set attributes that affect an entire virtual - machine, for example memory layout. In addition a VM ioctl is used to - create virtual cpus (vcpus). - - Only run VM ioctls from the same process (address space) that was used - to create the VM. - - - vcpu ioctls: These query and set attributes that control the operation - of a single virtual cpu. - - Only run vcpu ioctls from the same thread that was used to create the - vcpu. - -2. File descriptors - -The kvm API is centered around file descriptors. An initial -open("/dev/kvm") obtains a handle to the kvm subsystem; this handle -can be used to issue system ioctls. A KVM_CREATE_VM ioctl on this -handle will create a VM file descriptor which can be used to issue VM -ioctls. A KVM_CREATE_VCPU ioctl on a VM fd will create a virtual cpu -and return a file descriptor pointing to it. Finally, ioctls on a vcpu -fd can be used to control the vcpu, including the important task of -actually running guest code. - -In general file descriptors can be migrated among processes by means -of fork() and the SCM_RIGHTS facility of unix domain socket. These -kinds of tricks are explicitly not supported by kvm. While they will -not cause harm to the host, their actual behavior is not guaranteed by -the API. The only supported use is one virtual machine per process, -and one vcpu per thread. - -3. Extensions - -As of Linux 2.6.22, the KVM ABI has been stabilized: no backward -incompatible change are allowed. However, there is an extension -facility that allows backward-compatible extensions to the API to be -queried and used. - -The extension mechanism is not based on on the Linux version number. -Instead, kvm defines extension identifiers and a facility to query -whether a particular extension identifier is available. If it is, a -set of ioctls is available for application use. - -4. API description - -This section describes ioctls that can be used to control kvm guests. -For each ioctl, the following information is provided along with a -description: - - Capability: which KVM extension provides this ioctl. Can be 'basic', - which means that is will be provided by any kernel that supports - API version 12 (see section 4.1), or a KVM_CAP_xyz constant, which - means availability needs to be checked with KVM_CHECK_EXTENSION - (see section 4.4). - - Architectures: which instruction set architectures provide this ioctl. - x86 includes both i386 and x86_64. - - Type: system, vm, or vcpu. - - Parameters: what parameters are accepted by the ioctl. - - Returns: the return value. General error numbers (EBADF, ENOMEM, EINVAL) - are not detailed, but errors with specific meanings are. - -4.1 KVM_GET_API_VERSION - -Capability: basic -Architectures: all -Type: system ioctl -Parameters: none -Returns: the constant KVM_API_VERSION (=12) - -This identifies the API version as the stable kvm API. It is not -expected that this number will change. However, Linux 2.6.20 and -2.6.21 report earlier versions; these are not documented and not -supported. Applications should refuse to run if KVM_GET_API_VERSION -returns a value other than 12. If this check passes, all ioctls -described as 'basic' will be available. - -4.2 KVM_CREATE_VM - -Capability: basic -Architectures: all -Type: system ioctl -Parameters: none -Returns: a VM fd that can be used to control the new virtual machine. - -The new VM has no virtual cpus and no memory. An mmap() of a VM fd -will access the virtual machine's physical address space; offset zero -corresponds to guest physical address zero. Use of mmap() on a VM fd -is discouraged if userspace memory allocation (KVM_CAP_USER_MEMORY) is -available. - -4.3 KVM_GET_MSR_INDEX_LIST - -Capability: basic -Architectures: x86 -Type: system -Parameters: struct kvm_msr_list (in/out) -Returns: 0 on success; -1 on error -Errors: - E2BIG: the msr index list is to be to fit in the array specified by - the user. - -struct kvm_msr_list { - __u32 nmsrs; /* number of msrs in entries */ - __u32 indices[0]; -}; - -This ioctl returns the guest msrs that are supported. The list varies -by kvm version and host processor, but does not change otherwise. The -user fills in the size of the indices array in nmsrs, and in return -kvm adjusts nmsrs to reflect the actual number of msrs and fills in -the indices array with their numbers. - -Note: if kvm indicates supports MCE (KVM_CAP_MCE), then the MCE bank MSRs are -not returned in the MSR list, as different vcpus can have a different number -of banks, as set via the KVM_X86_SETUP_MCE ioctl. - -4.4 KVM_CHECK_EXTENSION - -Capability: basic -Architectures: all -Type: system ioctl -Parameters: extension identifier (KVM_CAP_*) -Returns: 0 if unsupported; 1 (or some other positive integer) if supported - -The API allows the application to query about extensions to the core -kvm API. Userspace passes an extension identifier (an integer) and -receives an integer that describes the extension availability. -Generally 0 means no and 1 means yes, but some extensions may report -additional information in the integer return value. - -4.5 KVM_GET_VCPU_MMAP_SIZE - -Capability: basic -Architectures: all -Type: system ioctl -Parameters: none -Returns: size of vcpu mmap area, in bytes - -The KVM_RUN ioctl (cf.) communicates with userspace via a shared -memory region. This ioctl returns the size of that region. See the -KVM_RUN documentation for details. - -4.6 KVM_SET_MEMORY_REGION - -Capability: basic -Architectures: all -Type: vm ioctl -Parameters: struct kvm_memory_region (in) -Returns: 0 on success, -1 on error - -This ioctl is obsolete and has been removed. - -4.7 KVM_CREATE_VCPU - -Capability: basic -Architectures: all -Type: vm ioctl -Parameters: vcpu id (apic id on x86) -Returns: vcpu fd on success, -1 on error - -This API adds a vcpu to a virtual machine. The vcpu id is a small integer -in the range [0, max_vcpus). - -4.8 KVM_GET_DIRTY_LOG (vm ioctl) - -Capability: basic -Architectures: x86 -Type: vm ioctl -Parameters: struct kvm_dirty_log (in/out) -Returns: 0 on success, -1 on error - -/* for KVM_GET_DIRTY_LOG */ -struct kvm_dirty_log { - __u32 slot; - __u32 padding; - union { - void __user *dirty_bitmap; /* one bit per page */ - __u64 padding; - }; -}; - -Given a memory slot, return a bitmap containing any pages dirtied -since the last call to this ioctl. Bit 0 is the first page in the -memory slot. Ensure the entire structure is cleared to avoid padding -issues. - -4.9 KVM_SET_MEMORY_ALIAS - -Capability: basic -Architectures: x86 -Type: vm ioctl -Parameters: struct kvm_memory_alias (in) -Returns: 0 (success), -1 (error) - -This ioctl is obsolete and has been removed. - -4.10 KVM_RUN - -Capability: basic -Architectures: all -Type: vcpu ioctl -Parameters: none -Returns: 0 on success, -1 on error -Errors: - EINTR: an unmasked signal is pending - -This ioctl is used to run a guest virtual cpu. While there are no -explicit parameters, there is an implicit parameter block that can be -obtained by mmap()ing the vcpu fd at offset 0, with the size given by -KVM_GET_VCPU_MMAP_SIZE. The parameter block is formatted as a 'struct -kvm_run' (see below). - -4.11 KVM_GET_REGS - -Capability: basic -Architectures: all -Type: vcpu ioctl -Parameters: struct kvm_regs (out) -Returns: 0 on success, -1 on error - -Reads the general purpose registers from the vcpu. - -/* x86 */ -struct kvm_regs { - /* out (KVM_GET_REGS) / in (KVM_SET_REGS) */ - __u64 rax, rbx, rcx, rdx; - __u64 rsi, rdi, rsp, rbp; - __u64 r8, r9, r10, r11; - __u64 r12, r13, r14, r15; - __u64 rip, rflags; -}; - -4.12 KVM_SET_REGS - -Capability: basic -Architectures: all -Type: vcpu ioctl -Parameters: struct kvm_regs (in) -Returns: 0 on success, -1 on error - -Writes the general purpose registers into the vcpu. - -See KVM_GET_REGS for the data structure. - -4.13 KVM_GET_SREGS - -Capability: basic -Architectures: x86 -Type: vcpu ioctl -Parameters: struct kvm_sregs (out) -Returns: 0 on success, -1 on error - -Reads special registers from the vcpu. - -/* x86 */ -struct kvm_sregs { - struct kvm_segment cs, ds, es, fs, gs, ss; - struct kvm_segment tr, ldt; - struct kvm_dtable gdt, idt; - __u64 cr0, cr2, cr3, cr4, cr8; - __u64 efer; - __u64 apic_base; - __u64 interrupt_bitmap[(KVM_NR_INTERRUPTS + 63) / 64]; -}; - -interrupt_bitmap is a bitmap of pending external interrupts. At most -one bit may be set. This interrupt has been acknowledged by the APIC -but not yet injected into the cpu core. - -4.14 KVM_SET_SREGS - -Capability: basic -Architectures: x86 -Type: vcpu ioctl -Parameters: struct kvm_sregs (in) -Returns: 0 on success, -1 on error - -Writes special registers into the vcpu. See KVM_GET_SREGS for the -data structures. - -4.15 KVM_TRANSLATE - -Capability: basic -Architectures: x86 -Type: vcpu ioctl -Parameters: struct kvm_translation (in/out) -Returns: 0 on success, -1 on error - -Translates a virtual address according to the vcpu's current address -translation mode. - -struct kvm_translation { - /* in */ - __u64 linear_address; - - /* out */ - __u64 physical_address; - __u8 valid; - __u8 writeable; - __u8 usermode; - __u8 pad[5]; -}; - -4.16 KVM_INTERRUPT - -Capability: basic -Architectures: x86, ppc -Type: vcpu ioctl -Parameters: struct kvm_interrupt (in) -Returns: 0 on success, -1 on error - -Queues a hardware interrupt vector to be injected. This is only -useful if in-kernel local APIC or equivalent is not used. - -/* for KVM_INTERRUPT */ -struct kvm_interrupt { - /* in */ - __u32 irq; -}; - -X86: - -Note 'irq' is an interrupt vector, not an interrupt pin or line. - -PPC: - -Queues an external interrupt to be injected. This ioctl is overleaded -with 3 different irq values: - -a) KVM_INTERRUPT_SET - - This injects an edge type external interrupt into the guest once it's ready - to receive interrupts. When injected, the interrupt is done. - -b) KVM_INTERRUPT_UNSET - - This unsets any pending interrupt. - - Only available with KVM_CAP_PPC_UNSET_IRQ. - -c) KVM_INTERRUPT_SET_LEVEL - - This injects a level type external interrupt into the guest context. The - interrupt stays pending until a specific ioctl with KVM_INTERRUPT_UNSET - is triggered. - - Only available with KVM_CAP_PPC_IRQ_LEVEL. - -Note that any value for 'irq' other than the ones stated above is invalid -and incurs unexpected behavior. - -4.17 KVM_DEBUG_GUEST - -Capability: basic -Architectures: none -Type: vcpu ioctl -Parameters: none) -Returns: -1 on error - -Support for this has been removed. Use KVM_SET_GUEST_DEBUG instead. - -4.18 KVM_GET_MSRS - -Capability: basic -Architectures: x86 -Type: vcpu ioctl -Parameters: struct kvm_msrs (in/out) -Returns: 0 on success, -1 on error - -Reads model-specific registers from the vcpu. Supported msr indices can -be obtained using KVM_GET_MSR_INDEX_LIST. - -struct kvm_msrs { - __u32 nmsrs; /* number of msrs in entries */ - __u32 pad; - - struct kvm_msr_entry entries[0]; -}; - -struct kvm_msr_entry { - __u32 index; - __u32 reserved; - __u64 data; -}; - -Application code should set the 'nmsrs' member (which indicates the -size of the entries array) and the 'index' member of each array entry. -kvm will fill in the 'data' member. - -4.19 KVM_SET_MSRS - -Capability: basic -Architectures: x86 -Type: vcpu ioctl -Parameters: struct kvm_msrs (in) -Returns: 0 on success, -1 on error - -Writes model-specific registers to the vcpu. See KVM_GET_MSRS for the -data structures. - -Application code should set the 'nmsrs' member (which indicates the -size of the entries array), and the 'index' and 'data' members of each -array entry. - -4.20 KVM_SET_CPUID - -Capability: basic -Architectures: x86 -Type: vcpu ioctl -Parameters: struct kvm_cpuid (in) -Returns: 0 on success, -1 on error - -Defines the vcpu responses to the cpuid instruction. Applications -should use the KVM_SET_CPUID2 ioctl if available. - - -struct kvm_cpuid_entry { - __u32 function; - __u32 eax; - __u32 ebx; - __u32 ecx; - __u32 edx; - __u32 padding; -}; - -/* for KVM_SET_CPUID */ -struct kvm_cpuid { - __u32 nent; - __u32 padding; - struct kvm_cpuid_entry entries[0]; -}; - -4.21 KVM_SET_SIGNAL_MASK - -Capability: basic -Architectures: x86 -Type: vcpu ioctl -Parameters: struct kvm_signal_mask (in) -Returns: 0 on success, -1 on error - -Defines which signals are blocked during execution of KVM_RUN. This -signal mask temporarily overrides the threads signal mask. Any -unblocked signal received (except SIGKILL and SIGSTOP, which retain -their traditional behaviour) will cause KVM_RUN to return with -EINTR. - -Note the signal will only be delivered if not blocked by the original -signal mask. - -/* for KVM_SET_SIGNAL_MASK */ -struct kvm_signal_mask { - __u32 len; - __u8 sigset[0]; -}; - -4.22 KVM_GET_FPU - -Capability: basic -Architectures: x86 -Type: vcpu ioctl -Parameters: struct kvm_fpu (out) -Returns: 0 on success, -1 on error - -Reads the floating point state from the vcpu. - -/* for KVM_GET_FPU and KVM_SET_FPU */ -struct kvm_fpu { - __u8 fpr[8][16]; - __u16 fcw; - __u16 fsw; - __u8 ftwx; /* in fxsave format */ - __u8 pad1; - __u16 last_opcode; - __u64 last_ip; - __u64 last_dp; - __u8 xmm[16][16]; - __u32 mxcsr; - __u32 pad2; -}; - -4.23 KVM_SET_FPU - -Capability: basic -Architectures: x86 -Type: vcpu ioctl -Parameters: struct kvm_fpu (in) -Returns: 0 on success, -1 on error - -Writes the floating point state to the vcpu. - -/* for KVM_GET_FPU and KVM_SET_FPU */ -struct kvm_fpu { - __u8 fpr[8][16]; - __u16 fcw; - __u16 fsw; - __u8 ftwx; /* in fxsave format */ - __u8 pad1; - __u16 last_opcode; - __u64 last_ip; - __u64 last_dp; - __u8 xmm[16][16]; - __u32 mxcsr; - __u32 pad2; -}; - -4.24 KVM_CREATE_IRQCHIP - -Capability: KVM_CAP_IRQCHIP -Architectures: x86, ia64 -Type: vm ioctl -Parameters: none -Returns: 0 on success, -1 on error - -Creates an interrupt controller model in the kernel. On x86, creates a virtual -ioapic, a virtual PIC (two PICs, nested), and sets up future vcpus to have a -local APIC. IRQ routing for GSIs 0-15 is set to both PIC and IOAPIC; GSI 16-23 -only go to the IOAPIC. On ia64, a IOSAPIC is created. - -4.25 KVM_IRQ_LINE - -Capability: KVM_CAP_IRQCHIP -Architectures: x86, ia64 -Type: vm ioctl -Parameters: struct kvm_irq_level -Returns: 0 on success, -1 on error - -Sets the level of a GSI input to the interrupt controller model in the kernel. -Requires that an interrupt controller model has been previously created with -KVM_CREATE_IRQCHIP. Note that edge-triggered interrupts require the level -to be set to 1 and then back to 0. - -struct kvm_irq_level { - union { - __u32 irq; /* GSI */ - __s32 status; /* not used for KVM_IRQ_LEVEL */ - }; - __u32 level; /* 0 or 1 */ -}; - -4.26 KVM_GET_IRQCHIP - -Capability: KVM_CAP_IRQCHIP -Architectures: x86, ia64 -Type: vm ioctl -Parameters: struct kvm_irqchip (in/out) -Returns: 0 on success, -1 on error - -Reads the state of a kernel interrupt controller created with -KVM_CREATE_IRQCHIP into a buffer provided by the caller. - -struct kvm_irqchip { - __u32 chip_id; /* 0 = PIC1, 1 = PIC2, 2 = IOAPIC */ - __u32 pad; - union { - char dummy[512]; /* reserving space */ - struct kvm_pic_state pic; - struct kvm_ioapic_state ioapic; - } chip; -}; - -4.27 KVM_SET_IRQCHIP - -Capability: KVM_CAP_IRQCHIP -Architectures: x86, ia64 -Type: vm ioctl -Parameters: struct kvm_irqchip (in) -Returns: 0 on success, -1 on error - -Sets the state of a kernel interrupt controller created with -KVM_CREATE_IRQCHIP from a buffer provided by the caller. - -struct kvm_irqchip { - __u32 chip_id; /* 0 = PIC1, 1 = PIC2, 2 = IOAPIC */ - __u32 pad; - union { - char dummy[512]; /* reserving space */ - struct kvm_pic_state pic; - struct kvm_ioapic_state ioapic; - } chip; -}; - -4.28 KVM_XEN_HVM_CONFIG - -Capability: KVM_CAP_XEN_HVM -Architectures: x86 -Type: vm ioctl -Parameters: struct kvm_xen_hvm_config (in) -Returns: 0 on success, -1 on error - -Sets the MSR that the Xen HVM guest uses to initialize its hypercall -page, and provides the starting address and size of the hypercall -blobs in userspace. When the guest writes the MSR, kvm copies one -page of a blob (32- or 64-bit, depending on the vcpu mode) to guest -memory. - -struct kvm_xen_hvm_config { - __u32 flags; - __u32 msr; - __u64 blob_addr_32; - __u64 blob_addr_64; - __u8 blob_size_32; - __u8 blob_size_64; - __u8 pad2[30]; -}; - -4.29 KVM_GET_CLOCK - -Capability: KVM_CAP_ADJUST_CLOCK -Architectures: x86 -Type: vm ioctl -Parameters: struct kvm_clock_data (out) -Returns: 0 on success, -1 on error - -Gets the current timestamp of kvmclock as seen by the current guest. In -conjunction with KVM_SET_CLOCK, it is used to ensure monotonicity on scenarios -such as migration. - -struct kvm_clock_data { - __u64 clock; /* kvmclock current value */ - __u32 flags; - __u32 pad[9]; -}; - -4.30 KVM_SET_CLOCK - -Capability: KVM_CAP_ADJUST_CLOCK -Architectures: x86 -Type: vm ioctl -Parameters: struct kvm_clock_data (in) -Returns: 0 on success, -1 on error - -Sets the current timestamp of kvmclock to the value specified in its parameter. -In conjunction with KVM_GET_CLOCK, it is used to ensure monotonicity on scenarios -such as migration. - -struct kvm_clock_data { - __u64 clock; /* kvmclock current value */ - __u32 flags; - __u32 pad[9]; -}; - -4.31 KVM_GET_VCPU_EVENTS - -Capability: KVM_CAP_VCPU_EVENTS -Extended by: KVM_CAP_INTR_SHADOW -Architectures: x86 -Type: vm ioctl -Parameters: struct kvm_vcpu_event (out) -Returns: 0 on success, -1 on error - -Gets currently pending exceptions, interrupts, and NMIs as well as related -states of the vcpu. - -struct kvm_vcpu_events { - struct { - __u8 injected; - __u8 nr; - __u8 has_error_code; - __u8 pad; - __u32 error_code; - } exception; - struct { - __u8 injected; - __u8 nr; - __u8 soft; - __u8 shadow; - } interrupt; - struct { - __u8 injected; - __u8 pending; - __u8 masked; - __u8 pad; - } nmi; - __u32 sipi_vector; - __u32 flags; -}; - -KVM_VCPUEVENT_VALID_SHADOW may be set in the flags field to signal that -interrupt.shadow contains a valid state. Otherwise, this field is undefined. - -4.32 KVM_SET_VCPU_EVENTS - -Capability: KVM_CAP_VCPU_EVENTS -Extended by: KVM_CAP_INTR_SHADOW -Architectures: x86 -Type: vm ioctl -Parameters: struct kvm_vcpu_event (in) -Returns: 0 on success, -1 on error - -Set pending exceptions, interrupts, and NMIs as well as related states of the -vcpu. - -See KVM_GET_VCPU_EVENTS for the data structure. - -Fields that may be modified asynchronously by running VCPUs can be excluded -from the update. These fields are nmi.pending and sipi_vector. Keep the -corresponding bits in the flags field cleared to suppress overwriting the -current in-kernel state. The bits are: - -KVM_VCPUEVENT_VALID_NMI_PENDING - transfer nmi.pending to the kernel -KVM_VCPUEVENT_VALID_SIPI_VECTOR - transfer sipi_vector - -If KVM_CAP_INTR_SHADOW is available, KVM_VCPUEVENT_VALID_SHADOW can be set in -the flags field to signal that interrupt.shadow contains a valid state and -shall be written into the VCPU. - -4.33 KVM_GET_DEBUGREGS - -Capability: KVM_CAP_DEBUGREGS -Architectures: x86 -Type: vm ioctl -Parameters: struct kvm_debugregs (out) -Returns: 0 on success, -1 on error - -Reads debug registers from the vcpu. - -struct kvm_debugregs { - __u64 db[4]; - __u64 dr6; - __u64 dr7; - __u64 flags; - __u64 reserved[9]; -}; - -4.34 KVM_SET_DEBUGREGS - -Capability: KVM_CAP_DEBUGREGS -Architectures: x86 -Type: vm ioctl -Parameters: struct kvm_debugregs (in) -Returns: 0 on success, -1 on error - -Writes debug registers into the vcpu. - -See KVM_GET_DEBUGREGS for the data structure. The flags field is unused -yet and must be cleared on entry. - -4.35 KVM_SET_USER_MEMORY_REGION - -Capability: KVM_CAP_USER_MEM -Architectures: all -Type: vm ioctl -Parameters: struct kvm_userspace_memory_region (in) -Returns: 0 on success, -1 on error - -struct kvm_userspace_memory_region { - __u32 slot; - __u32 flags; - __u64 guest_phys_addr; - __u64 memory_size; /* bytes */ - __u64 userspace_addr; /* start of the userspace allocated memory */ -}; - -/* for kvm_memory_region::flags */ -#define KVM_MEM_LOG_DIRTY_PAGES 1UL - -This ioctl allows the user to create or modify a guest physical memory -slot. When changing an existing slot, it may be moved in the guest -physical memory space, or its flags may be modified. It may not be -resized. Slots may not overlap in guest physical address space. - -Memory for the region is taken starting at the address denoted by the -field userspace_addr, which must point at user addressable memory for -the entire memory slot size. Any object may back this memory, including -anonymous memory, ordinary files, and hugetlbfs. - -It is recommended that the lower 21 bits of guest_phys_addr and userspace_addr -be identical. This allows large pages in the guest to be backed by large -pages in the host. - -The flags field supports just one flag, KVM_MEM_LOG_DIRTY_PAGES, which -instructs kvm to keep track of writes to memory within the slot. See -the KVM_GET_DIRTY_LOG ioctl. - -When the KVM_CAP_SYNC_MMU capability, changes in the backing of the memory -region are automatically reflected into the guest. For example, an mmap() -that affects the region will be made visible immediately. Another example -is madvise(MADV_DROP). - -It is recommended to use this API instead of the KVM_SET_MEMORY_REGION ioctl. -The KVM_SET_MEMORY_REGION does not allow fine grained control over memory -allocation and is deprecated. - -4.36 KVM_SET_TSS_ADDR - -Capability: KVM_CAP_SET_TSS_ADDR -Architectures: x86 -Type: vm ioctl -Parameters: unsigned long tss_address (in) -Returns: 0 on success, -1 on error - -This ioctl defines the physical address of a three-page region in the guest -physical address space. The region must be within the first 4GB of the -guest physical address space and must not conflict with any memory slot -or any mmio address. The guest may malfunction if it accesses this memory -region. - -This ioctl is required on Intel-based hosts. This is needed on Intel hardware -because of a quirk in the virtualization implementation (see the internals -documentation when it pops into existence). - -4.37 KVM_ENABLE_CAP - -Capability: KVM_CAP_ENABLE_CAP -Architectures: ppc -Type: vcpu ioctl -Parameters: struct kvm_enable_cap (in) -Returns: 0 on success; -1 on error - -+Not all extensions are enabled by default. Using this ioctl the application -can enable an extension, making it available to the guest. - -On systems that do not support this ioctl, it always fails. On systems that -do support it, it only works for extensions that are supported for enablement. - -To check if a capability can be enabled, the KVM_CHECK_EXTENSION ioctl should -be used. - -struct kvm_enable_cap { - /* in */ - __u32 cap; - -The capability that is supposed to get enabled. - - __u32 flags; - -A bitfield indicating future enhancements. Has to be 0 for now. - - __u64 args[4]; - -Arguments for enabling a feature. If a feature needs initial values to -function properly, this is the place to put them. - - __u8 pad[64]; -}; - -4.38 KVM_GET_MP_STATE - -Capability: KVM_CAP_MP_STATE -Architectures: x86, ia64 -Type: vcpu ioctl -Parameters: struct kvm_mp_state (out) -Returns: 0 on success; -1 on error - -struct kvm_mp_state { - __u32 mp_state; -}; - -Returns the vcpu's current "multiprocessing state" (though also valid on -uniprocessor guests). - -Possible values are: - - - KVM_MP_STATE_RUNNABLE: the vcpu is currently running - - KVM_MP_STATE_UNINITIALIZED: the vcpu is an application processor (AP) - which has not yet received an INIT signal - - KVM_MP_STATE_INIT_RECEIVED: the vcpu has received an INIT signal, and is - now ready for a SIPI - - KVM_MP_STATE_HALTED: the vcpu has executed a HLT instruction and - is waiting for an interrupt - - KVM_MP_STATE_SIPI_RECEIVED: the vcpu has just received a SIPI (vector - accessible via KVM_GET_VCPU_EVENTS) - -This ioctl is only useful after KVM_CREATE_IRQCHIP. Without an in-kernel -irqchip, the multiprocessing state must be maintained by userspace. - -4.39 KVM_SET_MP_STATE - -Capability: KVM_CAP_MP_STATE -Architectures: x86, ia64 -Type: vcpu ioctl -Parameters: struct kvm_mp_state (in) -Returns: 0 on success; -1 on error - -Sets the vcpu's current "multiprocessing state"; see KVM_GET_MP_STATE for -arguments. - -This ioctl is only useful after KVM_CREATE_IRQCHIP. Without an in-kernel -irqchip, the multiprocessing state must be maintained by userspace. - -4.40 KVM_SET_IDENTITY_MAP_ADDR - -Capability: KVM_CAP_SET_IDENTITY_MAP_ADDR -Architectures: x86 -Type: vm ioctl -Parameters: unsigned long identity (in) -Returns: 0 on success, -1 on error - -This ioctl defines the physical address of a one-page region in the guest -physical address space. The region must be within the first 4GB of the -guest physical address space and must not conflict with any memory slot -or any mmio address. The guest may malfunction if it accesses this memory -region. - -This ioctl is required on Intel-based hosts. This is needed on Intel hardware -because of a quirk in the virtualization implementation (see the internals -documentation when it pops into existence). - -4.41 KVM_SET_BOOT_CPU_ID - -Capability: KVM_CAP_SET_BOOT_CPU_ID -Architectures: x86, ia64 -Type: vm ioctl -Parameters: unsigned long vcpu_id -Returns: 0 on success, -1 on error - -Define which vcpu is the Bootstrap Processor (BSP). Values are the same -as the vcpu id in KVM_CREATE_VCPU. If this ioctl is not called, the default -is vcpu 0. - -4.42 KVM_GET_XSAVE - -Capability: KVM_CAP_XSAVE -Architectures: x86 -Type: vcpu ioctl -Parameters: struct kvm_xsave (out) -Returns: 0 on success, -1 on error - -struct kvm_xsave { - __u32 region[1024]; -}; - -This ioctl would copy current vcpu's xsave struct to the userspace. - -4.43 KVM_SET_XSAVE - -Capability: KVM_CAP_XSAVE -Architectures: x86 -Type: vcpu ioctl -Parameters: struct kvm_xsave (in) -Returns: 0 on success, -1 on error - -struct kvm_xsave { - __u32 region[1024]; -}; - -This ioctl would copy userspace's xsave struct to the kernel. - -4.44 KVM_GET_XCRS - -Capability: KVM_CAP_XCRS -Architectures: x86 -Type: vcpu ioctl -Parameters: struct kvm_xcrs (out) -Returns: 0 on success, -1 on error - -struct kvm_xcr { - __u32 xcr; - __u32 reserved; - __u64 value; -}; - -struct kvm_xcrs { - __u32 nr_xcrs; - __u32 flags; - struct kvm_xcr xcrs[KVM_MAX_XCRS]; - __u64 padding[16]; -}; - -This ioctl would copy current vcpu's xcrs to the userspace. - -4.45 KVM_SET_XCRS - -Capability: KVM_CAP_XCRS -Architectures: x86 -Type: vcpu ioctl -Parameters: struct kvm_xcrs (in) -Returns: 0 on success, -1 on error - -struct kvm_xcr { - __u32 xcr; - __u32 reserved; - __u64 value; -}; - -struct kvm_xcrs { - __u32 nr_xcrs; - __u32 flags; - struct kvm_xcr xcrs[KVM_MAX_XCRS]; - __u64 padding[16]; -}; - -This ioctl would set vcpu's xcr to the value userspace specified. - -4.46 KVM_GET_SUPPORTED_CPUID - -Capability: KVM_CAP_EXT_CPUID -Architectures: x86 -Type: system ioctl -Parameters: struct kvm_cpuid2 (in/out) -Returns: 0 on success, -1 on error - -struct kvm_cpuid2 { - __u32 nent; - __u32 padding; - struct kvm_cpuid_entry2 entries[0]; -}; - -#define KVM_CPUID_FLAG_SIGNIFCANT_INDEX 1 -#define KVM_CPUID_FLAG_STATEFUL_FUNC 2 -#define KVM_CPUID_FLAG_STATE_READ_NEXT 4 - -struct kvm_cpuid_entry2 { - __u32 function; - __u32 index; - __u32 flags; - __u32 eax; - __u32 ebx; - __u32 ecx; - __u32 edx; - __u32 padding[3]; -}; - -This ioctl returns x86 cpuid features which are supported by both the hardware -and kvm. Userspace can use the information returned by this ioctl to -construct cpuid information (for KVM_SET_CPUID2) that is consistent with -hardware, kernel, and userspace capabilities, and with user requirements (for -example, the user may wish to constrain cpuid to emulate older hardware, -or for feature consistency across a cluster). - -Userspace invokes KVM_GET_SUPPORTED_CPUID by passing a kvm_cpuid2 structure -with the 'nent' field indicating the number of entries in the variable-size -array 'entries'. If the number of entries is too low to describe the cpu -capabilities, an error (E2BIG) is returned. If the number is too high, -the 'nent' field is adjusted and an error (ENOMEM) is returned. If the -number is just right, the 'nent' field is adjusted to the number of valid -entries in the 'entries' array, which is then filled. - -The entries returned are the host cpuid as returned by the cpuid instruction, -with unknown or unsupported features masked out. Some features (for example, -x2apic), may not be present in the host cpu, but are exposed by kvm if it can -emulate them efficiently. The fields in each entry are defined as follows: - - function: the eax value used to obtain the entry - index: the ecx value used to obtain the entry (for entries that are - affected by ecx) - flags: an OR of zero or more of the following: - KVM_CPUID_FLAG_SIGNIFCANT_INDEX: - if the index field is valid - KVM_CPUID_FLAG_STATEFUL_FUNC: - if cpuid for this function returns different values for successive - invocations; there will be several entries with the same function, - all with this flag set - KVM_CPUID_FLAG_STATE_READ_NEXT: - for KVM_CPUID_FLAG_STATEFUL_FUNC entries, set if this entry is - the first entry to be read by a cpu - eax, ebx, ecx, edx: the values returned by the cpuid instruction for - this function/index combination - -4.47 KVM_PPC_GET_PVINFO - -Capability: KVM_CAP_PPC_GET_PVINFO -Architectures: ppc -Type: vm ioctl -Parameters: struct kvm_ppc_pvinfo (out) -Returns: 0 on success, !0 on error - -struct kvm_ppc_pvinfo { - __u32 flags; - __u32 hcall[4]; - __u8 pad[108]; -}; - -This ioctl fetches PV specific information that need to be passed to the guest -using the device tree or other means from vm context. - -For now the only implemented piece of information distributed here is an array -of 4 instructions that make up a hypercall. - -If any additional field gets added to this structure later on, a bit for that -additional piece of information will be set in the flags bitmap. - -4.48 KVM_ASSIGN_PCI_DEVICE - -Capability: KVM_CAP_DEVICE_ASSIGNMENT -Architectures: x86 ia64 -Type: vm ioctl -Parameters: struct kvm_assigned_pci_dev (in) -Returns: 0 on success, -1 on error - -Assigns a host PCI device to the VM. - -struct kvm_assigned_pci_dev { - __u32 assigned_dev_id; - __u32 busnr; - __u32 devfn; - __u32 flags; - __u32 segnr; - union { - __u32 reserved[11]; - }; -}; - -The PCI device is specified by the triple segnr, busnr, and devfn. -Identification in succeeding service requests is done via assigned_dev_id. The -following flags are specified: - -/* Depends on KVM_CAP_IOMMU */ -#define KVM_DEV_ASSIGN_ENABLE_IOMMU (1 << 0) - -4.49 KVM_DEASSIGN_PCI_DEVICE - -Capability: KVM_CAP_DEVICE_DEASSIGNMENT -Architectures: x86 ia64 -Type: vm ioctl -Parameters: struct kvm_assigned_pci_dev (in) -Returns: 0 on success, -1 on error - -Ends PCI device assignment, releasing all associated resources. - -See KVM_CAP_DEVICE_ASSIGNMENT for the data structure. Only assigned_dev_id is -used in kvm_assigned_pci_dev to identify the device. - -4.50 KVM_ASSIGN_DEV_IRQ - -Capability: KVM_CAP_ASSIGN_DEV_IRQ -Architectures: x86 ia64 -Type: vm ioctl -Parameters: struct kvm_assigned_irq (in) -Returns: 0 on success, -1 on error - -Assigns an IRQ to a passed-through device. - -struct kvm_assigned_irq { - __u32 assigned_dev_id; - __u32 host_irq; - __u32 guest_irq; - __u32 flags; - union { - struct { - __u32 addr_lo; - __u32 addr_hi; - __u32 data; - } guest_msi; - __u32 reserved[12]; - }; -}; - -The following flags are defined: - -#define KVM_DEV_IRQ_HOST_INTX (1 << 0) -#define KVM_DEV_IRQ_HOST_MSI (1 << 1) -#define KVM_DEV_IRQ_HOST_MSIX (1 << 2) - -#define KVM_DEV_IRQ_GUEST_INTX (1 << 8) -#define KVM_DEV_IRQ_GUEST_MSI (1 << 9) -#define KVM_DEV_IRQ_GUEST_MSIX (1 << 10) - -It is not valid to specify multiple types per host or guest IRQ. However, the -IRQ type of host and guest can differ or can even be null. - -4.51 KVM_DEASSIGN_DEV_IRQ - -Capability: KVM_CAP_ASSIGN_DEV_IRQ -Architectures: x86 ia64 -Type: vm ioctl -Parameters: struct kvm_assigned_irq (in) -Returns: 0 on success, -1 on error - -Ends an IRQ assignment to a passed-through device. - -See KVM_ASSIGN_DEV_IRQ for the data structure. The target device is specified -by assigned_dev_id, flags must correspond to the IRQ type specified on -KVM_ASSIGN_DEV_IRQ. Partial deassignment of host or guest IRQ is allowed. - -4.52 KVM_SET_GSI_ROUTING - -Capability: KVM_CAP_IRQ_ROUTING -Architectures: x86 ia64 -Type: vm ioctl -Parameters: struct kvm_irq_routing (in) -Returns: 0 on success, -1 on error - -Sets the GSI routing table entries, overwriting any previously set entries. - -struct kvm_irq_routing { - __u32 nr; - __u32 flags; - struct kvm_irq_routing_entry entries[0]; -}; - -No flags are specified so far, the corresponding field must be set to zero. - -struct kvm_irq_routing_entry { - __u32 gsi; - __u32 type; - __u32 flags; - __u32 pad; - union { - struct kvm_irq_routing_irqchip irqchip; - struct kvm_irq_routing_msi msi; - __u32 pad[8]; - } u; -}; - -/* gsi routing entry types */ -#define KVM_IRQ_ROUTING_IRQCHIP 1 -#define KVM_IRQ_ROUTING_MSI 2 - -No flags are specified so far, the corresponding field must be set to zero. - -struct kvm_irq_routing_irqchip { - __u32 irqchip; - __u32 pin; -}; - -struct kvm_irq_routing_msi { - __u32 address_lo; - __u32 address_hi; - __u32 data; - __u32 pad; -}; - -4.53 KVM_ASSIGN_SET_MSIX_NR - -Capability: KVM_CAP_DEVICE_MSIX -Architectures: x86 ia64 -Type: vm ioctl -Parameters: struct kvm_assigned_msix_nr (in) -Returns: 0 on success, -1 on error - -Set the number of MSI-X interrupts for an assigned device. This service can -only be called once in the lifetime of an assigned device. - -struct kvm_assigned_msix_nr { - __u32 assigned_dev_id; - __u16 entry_nr; - __u16 padding; -}; - -#define KVM_MAX_MSIX_PER_DEV 256 - -4.54 KVM_ASSIGN_SET_MSIX_ENTRY - -Capability: KVM_CAP_DEVICE_MSIX -Architectures: x86 ia64 -Type: vm ioctl -Parameters: struct kvm_assigned_msix_entry (in) -Returns: 0 on success, -1 on error - -Specifies the routing of an MSI-X assigned device interrupt to a GSI. Setting -the GSI vector to zero means disabling the interrupt. - -struct kvm_assigned_msix_entry { - __u32 assigned_dev_id; - __u32 gsi; - __u16 entry; /* The index of entry in the MSI-X table */ - __u16 padding[3]; -}; - -5. The kvm_run structure - -Application code obtains a pointer to the kvm_run structure by -mmap()ing a vcpu fd. From that point, application code can control -execution by changing fields in kvm_run prior to calling the KVM_RUN -ioctl, and obtain information about the reason KVM_RUN returned by -looking up structure members. - -struct kvm_run { - /* in */ - __u8 request_interrupt_window; - -Request that KVM_RUN return when it becomes possible to inject external -interrupts into the guest. Useful in conjunction with KVM_INTERRUPT. - - __u8 padding1[7]; - - /* out */ - __u32 exit_reason; - -When KVM_RUN has returned successfully (return value 0), this informs -application code why KVM_RUN has returned. Allowable values for this -field are detailed below. - - __u8 ready_for_interrupt_injection; - -If request_interrupt_window has been specified, this field indicates -an interrupt can be injected now with KVM_INTERRUPT. - - __u8 if_flag; - -The value of the current interrupt flag. Only valid if in-kernel -local APIC is not used. - - __u8 padding2[2]; - - /* in (pre_kvm_run), out (post_kvm_run) */ - __u64 cr8; - -The value of the cr8 register. Only valid if in-kernel local APIC is -not used. Both input and output. - - __u64 apic_base; - -The value of the APIC BASE msr. Only valid if in-kernel local -APIC is not used. Both input and output. - - union { - /* KVM_EXIT_UNKNOWN */ - struct { - __u64 hardware_exit_reason; - } hw; - -If exit_reason is KVM_EXIT_UNKNOWN, the vcpu has exited due to unknown -reasons. Further architecture-specific information is available in -hardware_exit_reason. - - /* KVM_EXIT_FAIL_ENTRY */ - struct { - __u64 hardware_entry_failure_reason; - } fail_entry; - -If exit_reason is KVM_EXIT_FAIL_ENTRY, the vcpu could not be run due -to unknown reasons. Further architecture-specific information is -available in hardware_entry_failure_reason. - - /* KVM_EXIT_EXCEPTION */ - struct { - __u32 exception; - __u32 error_code; - } ex; - -Unused. - - /* KVM_EXIT_IO */ - struct { -#define KVM_EXIT_IO_IN 0 -#define KVM_EXIT_IO_OUT 1 - __u8 direction; - __u8 size; /* bytes */ - __u16 port; - __u32 count; - __u64 data_offset; /* relative to kvm_run start */ - } io; - -If exit_reason is KVM_EXIT_IO, then the vcpu has -executed a port I/O instruction which could not be satisfied by kvm. -data_offset describes where the data is located (KVM_EXIT_IO_OUT) or -where kvm expects application code to place the data for the next -KVM_RUN invocation (KVM_EXIT_IO_IN). Data format is a packed array. - - struct { - struct kvm_debug_exit_arch arch; - } debug; - -Unused. - - /* KVM_EXIT_MMIO */ - struct { - __u64 phys_addr; - __u8 data[8]; - __u32 len; - __u8 is_write; - } mmio; - -If exit_reason is KVM_EXIT_MMIO, then the vcpu has -executed a memory-mapped I/O instruction which could not be satisfied -by kvm. The 'data' member contains the written data if 'is_write' is -true, and should be filled by application code otherwise. - -NOTE: For KVM_EXIT_IO, KVM_EXIT_MMIO and KVM_EXIT_OSI, the corresponding -operations are complete (and guest state is consistent) only after userspace -has re-entered the kernel with KVM_RUN. The kernel side will first finish -incomplete operations and then check for pending signals. Userspace -can re-enter the guest with an unmasked signal pending to complete -pending operations. - - /* KVM_EXIT_HYPERCALL */ - struct { - __u64 nr; - __u64 args[6]; - __u64 ret; - __u32 longmode; - __u32 pad; - } hypercall; - -Unused. This was once used for 'hypercall to userspace'. To implement -such functionality, use KVM_EXIT_IO (x86) or KVM_EXIT_MMIO (all except s390). -Note KVM_EXIT_IO is significantly faster than KVM_EXIT_MMIO. - - /* KVM_EXIT_TPR_ACCESS */ - struct { - __u64 rip; - __u32 is_write; - __u32 pad; - } tpr_access; - -To be documented (KVM_TPR_ACCESS_REPORTING). - - /* KVM_EXIT_S390_SIEIC */ - struct { - __u8 icptcode; - __u64 mask; /* psw upper half */ - __u64 addr; /* psw lower half */ - __u16 ipa; - __u32 ipb; - } s390_sieic; - -s390 specific. - - /* KVM_EXIT_S390_RESET */ -#define KVM_S390_RESET_POR 1 -#define KVM_S390_RESET_CLEAR 2 -#define KVM_S390_RESET_SUBSYSTEM 4 -#define KVM_S390_RESET_CPU_INIT 8 -#define KVM_S390_RESET_IPL 16 - __u64 s390_reset_flags; - -s390 specific. - - /* KVM_EXIT_DCR */ - struct { - __u32 dcrn; - __u32 data; - __u8 is_write; - } dcr; - -powerpc specific. - - /* KVM_EXIT_OSI */ - struct { - __u64 gprs[32]; - } osi; - -MOL uses a special hypercall interface it calls 'OSI'. To enable it, we catch -hypercalls and exit with this exit struct that contains all the guest gprs. - -If exit_reason is KVM_EXIT_OSI, then the vcpu has triggered such a hypercall. -Userspace can now handle the hypercall and when it's done modify the gprs as -necessary. Upon guest entry all guest GPRs will then be replaced by the values -in this struct. - - /* Fix the size of the union. */ - char padding[256]; - }; -}; diff --git a/Documentation/kvm/cpuid.txt b/Documentation/kvm/cpuid.txt deleted file mode 100644 index 8820685..0000000 --- a/Documentation/kvm/cpuid.txt +++ /dev/null @@ -1,45 +0,0 @@ -KVM CPUID bits -Glauber Costa , Red Hat Inc, 2010 -===================================================== - -A guest running on a kvm host, can check some of its features using -cpuid. This is not always guaranteed to work, since userspace can -mask-out some, or even all KVM-related cpuid features before launching -a guest. - -KVM cpuid functions are: - -function: KVM_CPUID_SIGNATURE (0x40000000) -returns : eax = 0, - ebx = 0x4b4d564b, - ecx = 0x564b4d56, - edx = 0x4d. -Note that this value in ebx, ecx and edx corresponds to the string "KVMKVMKVM". -This function queries the presence of KVM cpuid leafs. - - -function: define KVM_CPUID_FEATURES (0x40000001) -returns : ebx, ecx, edx = 0 - eax = and OR'ed group of (1 << flag), where each flags is: - - -flag || value || meaning -============================================================================= -KVM_FEATURE_CLOCKSOURCE || 0 || kvmclock available at msrs - || || 0x11 and 0x12. ------------------------------------------------------------------------------- -KVM_FEATURE_NOP_IO_DELAY || 1 || not necessary to perform delays - || || on PIO operations. ------------------------------------------------------------------------------- -KVM_FEATURE_MMU_OP || 2 || deprecated. ------------------------------------------------------------------------------- -KVM_FEATURE_CLOCKSOURCE2 || 3 || kvmclock available at msrs - || || 0x4b564d00 and 0x4b564d01 ------------------------------------------------------------------------------- -KVM_FEATURE_ASYNC_PF || 4 || async pf can be enabled by - || || writing to msr 0x4b564d02 ------------------------------------------------------------------------------- -KVM_FEATURE_CLOCKSOURCE_STABLE_BIT || 24 || host will warn if no guest-side - || || per-cpu warps are expected in - || || kvmclock. ------------------------------------------------------------------------------- diff --git a/Documentation/kvm/locking.txt b/Documentation/kvm/locking.txt deleted file mode 100644 index 3b4cd3b..0000000 --- a/Documentation/kvm/locking.txt +++ /dev/null @@ -1,25 +0,0 @@ -KVM Lock Overview -================= - -1. Acquisition Orders ---------------------- - -(to be written) - -2. Reference ------------- - -Name: kvm_lock -Type: raw_spinlock -Arch: any -Protects: - vm_list - - hardware virtualization enable/disable -Comment: 'raw' because hardware enabling/disabling must be atomic /wrt - migration. - -Name: kvm_arch::tsc_write_lock -Type: raw_spinlock -Arch: x86 -Protects: - kvm_arch::{last_tsc_write,last_tsc_nsec,last_tsc_offset} - - tsc offset in vmcb -Comment: 'raw' because updating the tsc offsets must not be preempted. diff --git a/Documentation/kvm/mmu.txt b/Documentation/kvm/mmu.txt deleted file mode 100644 index f46aa58..0000000 --- a/Documentation/kvm/mmu.txt +++ /dev/null @@ -1,348 +0,0 @@ -The x86 kvm shadow mmu -====================== - -The mmu (in arch/x86/kvm, files mmu.[ch] and paging_tmpl.h) is responsible -for presenting a standard x86 mmu to the guest, while translating guest -physical addresses to host physical addresses. - -The mmu code attempts to satisfy the following requirements: - -- correctness: the guest should not be able to determine that it is running - on an emulated mmu except for timing (we attempt to comply - with the specification, not emulate the characteristics of - a particular implementation such as tlb size) -- security: the guest must not be able to touch host memory not assigned - to it -- performance: minimize the performance penalty imposed by the mmu -- scaling: need to scale to large memory and large vcpu guests -- hardware: support the full range of x86 virtualization hardware -- integration: Linux memory management code must be in control of guest memory - so that swapping, page migration, page merging, transparent - hugepages, and similar features work without change -- dirty tracking: report writes to guest memory to enable live migration - and framebuffer-based displays -- footprint: keep the amount of pinned kernel memory low (most memory - should be shrinkable) -- reliability: avoid multipage or GFP_ATOMIC allocations - -Acronyms -======== - -pfn host page frame number -hpa host physical address -hva host virtual address -gfn guest frame number -gpa guest physical address -gva guest virtual address -ngpa nested guest physical address -ngva nested guest virtual address -pte page table entry (used also to refer generically to paging structure - entries) -gpte guest pte (referring to gfns) -spte shadow pte (referring to pfns) -tdp two dimensional paging (vendor neutral term for NPT and EPT) - -Virtual and real hardware supported -=================================== - -The mmu supports first-generation mmu hardware, which allows an atomic switch -of the current paging mode and cr3 during guest entry, as well as -two-dimensional paging (AMD's NPT and Intel's EPT). The emulated hardware -it exposes is the traditional 2/3/4 level x86 mmu, with support for global -pages, pae, pse, pse36, cr0.wp, and 1GB pages. Work is in progress to support -exposing NPT capable hardware on NPT capable hosts. - -Translation -=========== - -The primary job of the mmu is to program the processor's mmu to translate -addresses for the guest. Different translations are required at different -times: - -- when guest paging is disabled, we translate guest physical addresses to - host physical addresses (gpa->hpa) -- when guest paging is enabled, we translate guest virtual addresses, to - guest physical addresses, to host physical addresses (gva->gpa->hpa) -- when the guest launches a guest of its own, we translate nested guest - virtual addresses, to nested guest physical addresses, to guest physical - addresses, to host physical addresses (ngva->ngpa->gpa->hpa) - -The primary challenge is to encode between 1 and 3 translations into hardware -that support only 1 (traditional) and 2 (tdp) translations. When the -number of required translations matches the hardware, the mmu operates in -direct mode; otherwise it operates in shadow mode (see below). - -Memory -====== - -Guest memory (gpa) is part of the user address space of the process that is -using kvm. Userspace defines the translation between guest addresses and user -addresses (gpa->hva); note that two gpas may alias to the same hva, but not -vice versa. - -These hvas may be backed using any method available to the host: anonymous -memory, file backed memory, and device memory. Memory might be paged by the -host at any time. - -Events -====== - -The mmu is driven by events, some from the guest, some from the host. - -Guest generated events: -- writes to control registers (especially cr3) -- invlpg/invlpga instruction execution -- access to missing or protected translations - -Host generated events: -- changes in the gpa->hpa translation (either through gpa->hva changes or - through hva->hpa changes) -- memory pressure (the shrinker) - -Shadow pages -============ - -The principal data structure is the shadow page, 'struct kvm_mmu_page'. A -shadow page contains 512 sptes, which can be either leaf or nonleaf sptes. A -shadow page may contain a mix of leaf and nonleaf sptes. - -A nonleaf spte allows the hardware mmu to reach the leaf pages and -is not related to a translation directly. It points to other shadow pages. - -A leaf spte corresponds to either one or two translations encoded into -one paging structure entry. These are always the lowest level of the -translation stack, with optional higher level translations left to NPT/EPT. -Leaf ptes point at guest pages. - -The following table shows translations encoded by leaf ptes, with higher-level -translations in parentheses: - - Non-nested guests: - nonpaging: gpa->hpa - paging: gva->gpa->hpa - paging, tdp: (gva->)gpa->hpa - Nested guests: - non-tdp: ngva->gpa->hpa (*) - tdp: (ngva->)ngpa->gpa->hpa - -(*) the guest hypervisor will encode the ngva->gpa translation into its page - tables if npt is not present - -Shadow pages contain the following information: - role.level: - The level in the shadow paging hierarchy that this shadow page belongs to. - 1=4k sptes, 2=2M sptes, 3=1G sptes, etc. - role.direct: - If set, leaf sptes reachable from this page are for a linear range. - Examples include real mode translation, large guest pages backed by small - host pages, and gpa->hpa translations when NPT or EPT is active. - The linear range starts at (gfn << PAGE_SHIFT) and its size is determined - by role.level (2MB for first level, 1GB for second level, 0.5TB for third - level, 256TB for fourth level) - If clear, this page corresponds to a guest page table denoted by the gfn - field. - role.quadrant: - When role.cr4_pae=0, the guest uses 32-bit gptes while the host uses 64-bit - sptes. That means a guest page table contains more ptes than the host, - so multiple shadow pages are needed to shadow one guest page. - For first-level shadow pages, role.quadrant can be 0 or 1 and denotes the - first or second 512-gpte block in the guest page table. For second-level - page tables, each 32-bit gpte is converted to two 64-bit sptes - (since each first-level guest page is shadowed by two first-level - shadow pages) so role.quadrant takes values in the range 0..3. Each - quadrant maps 1GB virtual address space. - role.access: - Inherited guest access permissions in the form uwx. Note execute - permission is positive, not negative. - role.invalid: - The page is invalid and should not be used. It is a root page that is - currently pinned (by a cpu hardware register pointing to it); once it is - unpinned it will be destroyed. - role.cr4_pae: - Contains the value of cr4.pae for which the page is valid (e.g. whether - 32-bit or 64-bit gptes are in use). - role.nxe: - Contains the value of efer.nxe for which the page is valid. - role.cr0_wp: - Contains the value of cr0.wp for which the page is valid. - gfn: - Either the guest page table containing the translations shadowed by this - page, or the base page frame for linear translations. See role.direct. - spt: - A pageful of 64-bit sptes containing the translations for this page. - Accessed by both kvm and hardware. - The page pointed to by spt will have its page->private pointing back - at the shadow page structure. - sptes in spt point either at guest pages, or at lower-level shadow pages. - Specifically, if sp1 and sp2 are shadow pages, then sp1->spt[n] may point - at __pa(sp2->spt). sp2 will point back at sp1 through parent_pte. - The spt array forms a DAG structure with the shadow page as a node, and - guest pages as leaves. - gfns: - An array of 512 guest frame numbers, one for each present pte. Used to - perform a reverse map from a pte to a gfn. When role.direct is set, any - element of this array can be calculated from the gfn field when used, in - this case, the array of gfns is not allocated. See role.direct and gfn. - slot_bitmap: - A bitmap containing one bit per memory slot. If the page contains a pte - mapping a page from memory slot n, then bit n of slot_bitmap will be set - (if a page is aliased among several slots, then it is not guaranteed that - all slots will be marked). - Used during dirty logging to avoid scanning a shadow page if none if its - pages need tracking. - root_count: - A counter keeping track of how many hardware registers (guest cr3 or - pdptrs) are now pointing at the page. While this counter is nonzero, the - page cannot be destroyed. See role.invalid. - multimapped: - Whether there exist multiple sptes pointing at this page. - parent_pte/parent_ptes: - If multimapped is zero, parent_pte points at the single spte that points at - this page's spt. Otherwise, parent_ptes points at a data structure - with a list of parent_ptes. - unsync: - If true, then the translations in this page may not match the guest's - translation. This is equivalent to the state of the tlb when a pte is - changed but before the tlb entry is flushed. Accordingly, unsync ptes - are synchronized when the guest executes invlpg or flushes its tlb by - other means. Valid for leaf pages. - unsync_children: - How many sptes in the page point at pages that are unsync (or have - unsynchronized children). - unsync_child_bitmap: - A bitmap indicating which sptes in spt point (directly or indirectly) at - pages that may be unsynchronized. Used to quickly locate all unsychronized - pages reachable from a given page. - -Reverse map -=========== - -The mmu maintains a reverse mapping whereby all ptes mapping a page can be -reached given its gfn. This is used, for example, when swapping out a page. - -Synchronized and unsynchronized pages -===================================== - -The guest uses two events to synchronize its tlb and page tables: tlb flushes -and page invalidations (invlpg). - -A tlb flush means that we need to synchronize all sptes reachable from the -guest's cr3. This is expensive, so we keep all guest page tables write -protected, and synchronize sptes to gptes when a gpte is written. - -A special case is when a guest page table is reachable from the current -guest cr3. In this case, the guest is obliged to issue an invlpg instruction -before using the translation. We take advantage of that by removing write -protection from the guest page, and allowing the guest to modify it freely. -We synchronize modified gptes when the guest invokes invlpg. This reduces -the amount of emulation we have to do when the guest modifies multiple gptes, -or when the a guest page is no longer used as a page table and is used for -random guest data. - -As a side effect we have to resynchronize all reachable unsynchronized shadow -pages on a tlb flush. - - -Reaction to events -================== - -- guest page fault (or npt page fault, or ept violation) - -This is the most complicated event. The cause of a page fault can be: - - - a true guest fault (the guest translation won't allow the access) (*) - - access to a missing translation - - access to a protected translation - - when logging dirty pages, memory is write protected - - synchronized shadow pages are write protected (*) - - access to untranslatable memory (mmio) - - (*) not applicable in direct mode - -Handling a page fault is performed as follows: - - - if needed, walk the guest page tables to determine the guest translation - (gva->gpa or ngpa->gpa) - - if permissions are insufficient, reflect the fault back to the guest - - determine the host page - - if this is an mmio request, there is no host page; call the emulator - to emulate the instruction instead - - walk the shadow page table to find the spte for the translation, - instantiating missing intermediate page tables as necessary - - try to unsynchronize the page - - if successful, we can let the guest continue and modify the gpte - - emulate the instruction - - if failed, unshadow the page and let the guest continue - - update any translations that were modified by the instruction - -invlpg handling: - - - walk the shadow page hierarchy and drop affected translations - - try to reinstantiate the indicated translation in the hope that the - guest will use it in the near future - -Guest control register updates: - -- mov to cr3 - - look up new shadow roots - - synchronize newly reachable shadow pages - -- mov to cr0/cr4/efer - - set up mmu context for new paging mode - - look up new shadow roots - - synchronize newly reachable shadow pages - -Host translation updates: - - - mmu notifier called with updated hva - - look up affected sptes through reverse map - - drop (or update) translations - -Emulating cr0.wp -================ - -If tdp is not enabled, the host must keep cr0.wp=1 so page write protection -works for the guest kernel, not guest guest userspace. When the guest -cr0.wp=1, this does not present a problem. However when the guest cr0.wp=0, -we cannot map the permissions for gpte.u=1, gpte.w=0 to any spte (the -semantics require allowing any guest kernel access plus user read access). - -We handle this by mapping the permissions to two possible sptes, depending -on fault type: - -- kernel write fault: spte.u=0, spte.w=1 (allows full kernel access, - disallows user access) -- read fault: spte.u=1, spte.w=0 (allows full read access, disallows kernel - write access) - -(user write faults generate a #PF) - -Large pages -=========== - -The mmu supports all combinations of large and small guest and host pages. -Supported page sizes include 4k, 2M, 4M, and 1G. 4M pages are treated as -two separate 2M pages, on both guest and host, since the mmu always uses PAE -paging. - -To instantiate a large spte, four constraints must be satisfied: - -- the spte must point to a large host page -- the guest pte must be a large pte of at least equivalent size (if tdp is - enabled, there is no guest pte and this condition is satisified) -- if the spte will be writeable, the large page frame may not overlap any - write-protected pages -- the guest page must be wholly contained by a single memory slot - -To check the last two conditions, the mmu maintains a ->write_count set of -arrays for each memory slot and large page size. Every write protected page -causes its write_count to be incremented, thus preventing instantiation of -a large spte. The frames at the end of an unaligned memory slot have -artificically inflated ->write_counts so they can never be instantiated. - -Further reading -=============== - -- NPT presentation from KVM Forum 2008 - http://www.linux-kvm.org/wiki/images/c/c8/KvmForum2008%24kdf2008_21.pdf - diff --git a/Documentation/kvm/msr.txt b/Documentation/kvm/msr.txt deleted file mode 100644 index d079aed..0000000 --- a/Documentation/kvm/msr.txt +++ /dev/null @@ -1,187 +0,0 @@ -KVM-specific MSRs. -Glauber Costa , Red Hat Inc, 2010 -===================================================== - -KVM makes use of some custom MSRs to service some requests. - -Custom MSRs have a range reserved for them, that goes from -0x4b564d00 to 0x4b564dff. There are MSRs outside this area, -but they are deprecated and their use is discouraged. - -Custom MSR list --------- - -The current supported Custom MSR list is: - -MSR_KVM_WALL_CLOCK_NEW: 0x4b564d00 - - data: 4-byte alignment physical address of a memory area which must be - in guest RAM. This memory is expected to hold a copy of the following - structure: - - struct pvclock_wall_clock { - u32 version; - u32 sec; - u32 nsec; - } __attribute__((__packed__)); - - whose data will be filled in by the hypervisor. The hypervisor is only - guaranteed to update this data at the moment of MSR write. - Users that want to reliably query this information more than once have - to write more than once to this MSR. Fields have the following meanings: - - version: guest has to check version before and after grabbing - time information and check that they are both equal and even. - An odd version indicates an in-progress update. - - sec: number of seconds for wallclock. - - nsec: number of nanoseconds for wallclock. - - Note that although MSRs are per-CPU entities, the effect of this - particular MSR is global. - - Availability of this MSR must be checked via bit 3 in 0x4000001 cpuid - leaf prior to usage. - -MSR_KVM_SYSTEM_TIME_NEW: 0x4b564d01 - - data: 4-byte aligned physical address of a memory area which must be in - guest RAM, plus an enable bit in bit 0. This memory is expected to hold - a copy of the following structure: - - struct pvclock_vcpu_time_info { - u32 version; - u32 pad0; - u64 tsc_timestamp; - u64 system_time; - u32 tsc_to_system_mul; - s8 tsc_shift; - u8 flags; - u8 pad[2]; - } __attribute__((__packed__)); /* 32 bytes */ - - whose data will be filled in by the hypervisor periodically. Only one - write, or registration, is needed for each VCPU. The interval between - updates of this structure is arbitrary and implementation-dependent. - The hypervisor may update this structure at any time it sees fit until - anything with bit0 == 0 is written to it. - - Fields have the following meanings: - - version: guest has to check version before and after grabbing - time information and check that they are both equal and even. - An odd version indicates an in-progress update. - - tsc_timestamp: the tsc value at the current VCPU at the time - of the update of this structure. Guests can subtract this value - from current tsc to derive a notion of elapsed time since the - structure update. - - system_time: a host notion of monotonic time, including sleep - time at the time this structure was last updated. Unit is - nanoseconds. - - tsc_to_system_mul: a function of the tsc frequency. One has - to multiply any tsc-related quantity by this value to get - a value in nanoseconds, besides dividing by 2^tsc_shift - - tsc_shift: cycle to nanosecond divider, as a power of two, to - allow for shift rights. One has to shift right any tsc-related - quantity by this value to get a value in nanoseconds, besides - multiplying by tsc_to_system_mul. - - With this information, guests can derive per-CPU time by - doing: - - time = (current_tsc - tsc_timestamp) - time = (time * tsc_to_system_mul) >> tsc_shift - time = time + system_time - - flags: bits in this field indicate extended capabilities - coordinated between the guest and the hypervisor. Availability - of specific flags has to be checked in 0x40000001 cpuid leaf. - Current flags are: - - flag bit | cpuid bit | meaning - ------------------------------------------------------------- - | | time measures taken across - 0 | 24 | multiple cpus are guaranteed to - | | be monotonic - ------------------------------------------------------------- - - Availability of this MSR must be checked via bit 3 in 0x4000001 cpuid - leaf prior to usage. - - -MSR_KVM_WALL_CLOCK: 0x11 - - data and functioning: same as MSR_KVM_WALL_CLOCK_NEW. Use that instead. - - This MSR falls outside the reserved KVM range and may be removed in the - future. Its usage is deprecated. - - Availability of this MSR must be checked via bit 0 in 0x4000001 cpuid - leaf prior to usage. - -MSR_KVM_SYSTEM_TIME: 0x12 - - data and functioning: same as MSR_KVM_SYSTEM_TIME_NEW. Use that instead. - - This MSR falls outside the reserved KVM range and may be removed in the - future. Its usage is deprecated. - - Availability of this MSR must be checked via bit 0 in 0x4000001 cpuid - leaf prior to usage. - - The suggested algorithm for detecting kvmclock presence is then: - - if (!kvm_para_available()) /* refer to cpuid.txt */ - return NON_PRESENT; - - flags = cpuid_eax(0x40000001); - if (flags & 3) { - msr_kvm_system_time = MSR_KVM_SYSTEM_TIME_NEW; - msr_kvm_wall_clock = MSR_KVM_WALL_CLOCK_NEW; - return PRESENT; - } else if (flags & 0) { - msr_kvm_system_time = MSR_KVM_SYSTEM_TIME; - msr_kvm_wall_clock = MSR_KVM_WALL_CLOCK; - return PRESENT; - } else - return NON_PRESENT; - -MSR_KVM_ASYNC_PF_EN: 0x4b564d02 - data: Bits 63-6 hold 64-byte aligned physical address of a - 64 byte memory area which must be in guest RAM and must be - zeroed. Bits 5-2 are reserved and should be zero. Bit 0 is 1 - when asynchronous page faults are enabled on the vcpu 0 when - disabled. Bit 2 is 1 if asynchronous page faults can be injected - when vcpu is in cpl == 0. - - First 4 byte of 64 byte memory location will be written to by - the hypervisor at the time of asynchronous page fault (APF) - injection to indicate type of asynchronous page fault. Value - of 1 means that the page referred to by the page fault is not - present. Value 2 means that the page is now available. Disabling - interrupt inhibits APFs. Guest must not enable interrupt - before the reason is read, or it may be overwritten by another - APF. Since APF uses the same exception vector as regular page - fault guest must reset the reason to 0 before it does - something that can generate normal page fault. If during page - fault APF reason is 0 it means that this is regular page - fault. - - During delivery of type 1 APF cr2 contains a token that will - be used to notify a guest when missing page becomes - available. When page becomes available type 2 APF is sent with - cr2 set to the token associated with the page. There is special - kind of token 0xffffffff which tells vcpu that it should wake - up all processes waiting for APFs and no individual type 2 APFs - will be sent. - - If APF is disabled while there are outstanding APFs, they will - not be delivered. - - Currently type 2 APF will be always delivered on the same vcpu as - type 1 was, but guest should not rely on that. diff --git a/Documentation/kvm/ppc-pv.txt b/Documentation/kvm/ppc-pv.txt deleted file mode 100644 index 3ab969c..0000000 --- a/Documentation/kvm/ppc-pv.txt +++ /dev/null @@ -1,196 +0,0 @@ -The PPC KVM paravirtual interface -================================= - -The basic execution principle by which KVM on PowerPC works is to run all kernel -space code in PR=1 which is user space. This way we trap all privileged -instructions and can emulate them accordingly. - -Unfortunately that is also the downfall. There are quite some privileged -instructions that needlessly return us to the hypervisor even though they -could be handled differently. - -This is what the PPC PV interface helps with. It takes privileged instructions -and transforms them into unprivileged ones with some help from the hypervisor. -This cuts down virtualization costs by about 50% on some of my benchmarks. - -The code for that interface can be found in arch/powerpc/kernel/kvm* - -Querying for existence -====================== - -To find out if we're running on KVM or not, we leverage the device tree. When -Linux is running on KVM, a node /hypervisor exists. That node contains a -compatible property with the value "linux,kvm". - -Once you determined you're running under a PV capable KVM, you can now use -hypercalls as described below. - -KVM hypercalls -============== - -Inside the device tree's /hypervisor node there's a property called -'hypercall-instructions'. This property contains at most 4 opcodes that make -up the hypercall. To call a hypercall, just call these instructions. - -The parameters are as follows: - - Register IN OUT - - r0 - volatile - r3 1st parameter Return code - r4 2nd parameter 1st output value - r5 3rd parameter 2nd output value - r6 4th parameter 3rd output value - r7 5th parameter 4th output value - r8 6th parameter 5th output value - r9 7th parameter 6th output value - r10 8th parameter 7th output value - r11 hypercall number 8th output value - r12 - volatile - -Hypercall definitions are shared in generic code, so the same hypercall numbers -apply for x86 and powerpc alike with the exception that each KVM hypercall -also needs to be ORed with the KVM vendor code which is (42 << 16). - -Return codes can be as follows: - - Code Meaning - - 0 Success - 12 Hypercall not implemented - <0 Error - -The magic page -============== - -To enable communication between the hypervisor and guest there is a new shared -page that contains parts of supervisor visible register state. The guest can -map this shared page using the KVM hypercall KVM_HC_PPC_MAP_MAGIC_PAGE. - -With this hypercall issued the guest always gets the magic page mapped at the -desired location in effective and physical address space. For now, we always -map the page to -4096. This way we can access it using absolute load and store -functions. The following instruction reads the first field of the magic page: - - ld rX, -4096(0) - -The interface is designed to be extensible should there be need later to add -additional registers to the magic page. If you add fields to the magic page, -also define a new hypercall feature to indicate that the host can give you more -registers. Only if the host supports the additional features, make use of them. - -The magic page has the following layout as described in -arch/powerpc/include/asm/kvm_para.h: - -struct kvm_vcpu_arch_shared { - __u64 scratch1; - __u64 scratch2; - __u64 scratch3; - __u64 critical; /* Guest may not get interrupts if == r1 */ - __u64 sprg0; - __u64 sprg1; - __u64 sprg2; - __u64 sprg3; - __u64 srr0; - __u64 srr1; - __u64 dar; - __u64 msr; - __u32 dsisr; - __u32 int_pending; /* Tells the guest if we have an interrupt */ -}; - -Additions to the page must only occur at the end. Struct fields are always 32 -or 64 bit aligned, depending on them being 32 or 64 bit wide respectively. - -Magic page features -=================== - -When mapping the magic page using the KVM hypercall KVM_HC_PPC_MAP_MAGIC_PAGE, -a second return value is passed to the guest. This second return value contains -a bitmap of available features inside the magic page. - -The following enhancements to the magic page are currently available: - - KVM_MAGIC_FEAT_SR Maps SR registers r/w in the magic page - -For enhanced features in the magic page, please check for the existence of the -feature before using them! - -MSR bits -======== - -The MSR contains bits that require hypervisor intervention and bits that do -not require direct hypervisor intervention because they only get interpreted -when entering the guest or don't have any impact on the hypervisor's behavior. - -The following bits are safe to be set inside the guest: - - MSR_EE - MSR_RI - MSR_CR - MSR_ME - -If any other bit changes in the MSR, please still use mtmsr(d). - -Patched instructions -==================== - -The "ld" and "std" instructions are transormed to "lwz" and "stw" instructions -respectively on 32 bit systems with an added offset of 4 to accommodate for big -endianness. - -The following is a list of mapping the Linux kernel performs when running as -guest. Implementing any of those mappings is optional, as the instruction traps -also act on the shared page. So calling privileged instructions still works as -before. - -From To -==== == - -mfmsr rX ld rX, magic_page->msr -mfsprg rX, 0 ld rX, magic_page->sprg0 -mfsprg rX, 1 ld rX, magic_page->sprg1 -mfsprg rX, 2 ld rX, magic_page->sprg2 -mfsprg rX, 3 ld rX, magic_page->sprg3 -mfsrr0 rX ld rX, magic_page->srr0 -mfsrr1 rX ld rX, magic_page->srr1 -mfdar rX ld rX, magic_page->dar -mfdsisr rX lwz rX, magic_page->dsisr - -mtmsr rX std rX, magic_page->msr -mtsprg 0, rX std rX, magic_page->sprg0 -mtsprg 1, rX std rX, magic_page->sprg1 -mtsprg 2, rX std rX, magic_page->sprg2 -mtsprg 3, rX std rX, magic_page->sprg3 -mtsrr0 rX std rX, magic_page->srr0 -mtsrr1 rX std rX, magic_page->srr1 -mtdar rX std rX, magic_page->dar -mtdsisr rX stw rX, magic_page->dsisr - -tlbsync nop - -mtmsrd rX, 0 b -mtmsr rX b - -mtmsrd rX, 1 b - -[Book3S only] -mtsrin rX, rY b - -[BookE only] -wrteei [0|1] b - - -Some instructions require more logic to determine what's going on than a load -or store instruction can deliver. To enable patching of those, we keep some -RAM around where we can live translate instructions to. What happens is the -following: - - 1) copy emulation code to memory - 2) patch that code to fit the emulated instruction - 3) patch that code to return to the original pc + 4 - 4) patch the original instruction to branch to the new code - -That way we can inject an arbitrary amount of code as replacement for a single -instruction. This allows us to check for pending interrupts when setting EE=1 -for example. diff --git a/Documentation/kvm/review-checklist.txt b/Documentation/kvm/review-checklist.txt deleted file mode 100644 index 730475a..0000000 --- a/Documentation/kvm/review-checklist.txt +++ /dev/null @@ -1,38 +0,0 @@ -Review checklist for kvm patches -================================ - -1. The patch must follow Documentation/CodingStyle and - Documentation/SubmittingPatches. - -2. Patches should be against kvm.git master branch. - -3. If the patch introduces or modifies a new userspace API: - - the API must be documented in Documentation/kvm/api.txt - - the API must be discoverable using KVM_CHECK_EXTENSION - -4. New state must include support for save/restore. - -5. New features must default to off (userspace should explicitly request them). - Performance improvements can and should default to on. - -6. New cpu features should be exposed via KVM_GET_SUPPORTED_CPUID2 - -7. Emulator changes should be accompanied by unit tests for qemu-kvm.git - kvm/test directory. - -8. Changes should be vendor neutral when possible. Changes to common code - are better than duplicating changes to vendor code. - -9. Similarly, prefer changes to arch independent code than to arch dependent - code. - -10. User/kernel interfaces and guest/host interfaces must be 64-bit clean - (all variables and sizes naturally aligned on 64-bit; use specific types - only - u64 rather than ulong). - -11. New guest visible features must either be documented in a hardware manual - or be accompanied by documentation. - -12. Features must be robust against reset and kexec - for example, shared - host/guest memory must be unshared to prevent the host from writing to - guest memory that the guest has not reserved for this purpose. diff --git a/Documentation/kvm/timekeeping.txt b/Documentation/kvm/timekeeping.txt deleted file mode 100644 index df894637..0000000 --- a/Documentation/kvm/timekeeping.txt +++ /dev/null @@ -1,612 +0,0 @@ - - Timekeeping Virtualization for X86-Based Architectures - - Zachary Amsden - Copyright (c) 2010, Red Hat. All rights reserved. - -1) Overview -2) Timing Devices -3) TSC Hardware -4) Virtualization Problems - -========================================================================= - -1) Overview - -One of the most complicated parts of the X86 platform, and specifically, -the virtualization of this platform is the plethora of timing devices available -and the complexity of emulating those devices. In addition, virtualization of -time introduces a new set of challenges because it introduces a multiplexed -division of time beyond the control of the guest CPU. - -First, we will describe the various timekeeping hardware available, then -present some of the problems which arise and solutions available, giving -specific recommendations for certain classes of KVM guests. - -The purpose of this document is to collect data and information relevant to -timekeeping which may be difficult to find elsewhere, specifically, -information relevant to KVM and hardware-based virtualization. - -========================================================================= - -2) Timing Devices - -First we discuss the basic hardware devices available. TSC and the related -KVM clock are special enough to warrant a full exposition and are described in -the following section. - -2.1) i8254 - PIT - -One of the first timer devices available is the programmable interrupt timer, -or PIT. The PIT has a fixed frequency 1.193182 MHz base clock and three -channels which can be programmed to deliver periodic or one-shot interrupts. -These three channels can be configured in different modes and have individual -counters. Channel 1 and 2 were not available for general use in the original -IBM PC, and historically were connected to control RAM refresh and the PC -speaker. Now the PIT is typically integrated as part of an emulated chipset -and a separate physical PIT is not used. - -The PIT uses I/O ports 0x40 - 0x43. Access to the 16-bit counters is done -using single or multiple byte access to the I/O ports. There are 6 modes -available, but not all modes are available to all timers, as only timer 2 -has a connected gate input, required for modes 1 and 5. The gate line is -controlled by port 61h, bit 0, as illustrated in the following diagram. - - -------------- ---------------- -| | | | -| 1.1932 MHz |---------->| CLOCK OUT | ---------> IRQ 0 -| Clock | | | | - -------------- | +->| GATE TIMER 0 | - | ---------------- - | - | ---------------- - | | | - |------>| CLOCK OUT | ---------> 66.3 KHZ DRAM - | | | (aka /dev/null) - | +->| GATE TIMER 1 | - | ---------------- - | - | ---------------- - | | | - |------>| CLOCK OUT | ---------> Port 61h, bit 5 - | | | -Port 61h, bit 0 ---------->| GATE TIMER 2 | \_.---- ____ - ---------------- _| )--|LPF|---Speaker - / *---- \___/ -Port 61h, bit 1 -----------------------------------/ - -The timer modes are now described. - -Mode 0: Single Timeout. This is a one-shot software timeout that counts down - when the gate is high (always true for timers 0 and 1). When the count - reaches zero, the output goes high. - -Mode 1: Triggered One-shot. The output is initially set high. When the gate - line is set high, a countdown is initiated (which does not stop if the gate is - lowered), during which the output is set low. When the count reaches zero, - the output goes high. - -Mode 2: Rate Generator. The output is initially set high. When the countdown - reaches 1, the output goes low for one count and then returns high. The value - is reloaded and the countdown automatically resumes. If the gate line goes - low, the count is halted. If the output is low when the gate is lowered, the - output automatically goes high (this only affects timer 2). - -Mode 3: Square Wave. This generates a high / low square wave. The count - determines the length of the pulse, which alternates between high and low - when zero is reached. The count only proceeds when gate is high and is - automatically reloaded on reaching zero. The count is decremented twice at - each clock to generate a full high / low cycle at the full periodic rate. - If the count is even, the clock remains high for N/2 counts and low for N/2 - counts; if the clock is odd, the clock is high for (N+1)/2 counts and low - for (N-1)/2 counts. Only even values are latched by the counter, so odd - values are not observed when reading. This is the intended mode for timer 2, - which generates sine-like tones by low-pass filtering the square wave output. - -Mode 4: Software Strobe. After programming this mode and loading the counter, - the output remains high until the counter reaches zero. Then the output - goes low for 1 clock cycle and returns high. The counter is not reloaded. - Counting only occurs when gate is high. - -Mode 5: Hardware Strobe. After programming and loading the counter, the - output remains high. When the gate is raised, a countdown is initiated - (which does not stop if the gate is lowered). When the counter reaches zero, - the output goes low for 1 clock cycle and then returns high. The counter is - not reloaded. - -In addition to normal binary counting, the PIT supports BCD counting. The -command port, 0x43 is used to set the counter and mode for each of the three -timers. - -PIT commands, issued to port 0x43, using the following bit encoding: - -Bit 7-4: Command (See table below) -Bit 3-1: Mode (000 = Mode 0, 101 = Mode 5, 11X = undefined) -Bit 0 : Binary (0) / BCD (1) - -Command table: - -0000 - Latch Timer 0 count for port 0x40 - sample and hold the count to be read in port 0x40; - additional commands ignored until counter is read; - mode bits ignored. - -0001 - Set Timer 0 LSB mode for port 0x40 - set timer to read LSB only and force MSB to zero; - mode bits set timer mode - -0010 - Set Timer 0 MSB mode for port 0x40 - set timer to read MSB only and force LSB to zero; - mode bits set timer mode - -0011 - Set Timer 0 16-bit mode for port 0x40 - set timer to read / write LSB first, then MSB; - mode bits set timer mode - -0100 - Latch Timer 1 count for port 0x41 - as described above -0101 - Set Timer 1 LSB mode for port 0x41 - as described above -0110 - Set Timer 1 MSB mode for port 0x41 - as described above -0111 - Set Timer 1 16-bit mode for port 0x41 - as described above - -1000 - Latch Timer 2 count for port 0x42 - as described above -1001 - Set Timer 2 LSB mode for port 0x42 - as described above -1010 - Set Timer 2 MSB mode for port 0x42 - as described above -1011 - Set Timer 2 16-bit mode for port 0x42 as described above - -1101 - General counter latch - Latch combination of counters into corresponding ports - Bit 3 = Counter 2 - Bit 2 = Counter 1 - Bit 1 = Counter 0 - Bit 0 = Unused - -1110 - Latch timer status - Latch combination of counter mode into corresponding ports - Bit 3 = Counter 2 - Bit 2 = Counter 1 - Bit 1 = Counter 0 - - The output of ports 0x40-0x42 following this command will be: - - Bit 7 = Output pin - Bit 6 = Count loaded (0 if timer has expired) - Bit 5-4 = Read / Write mode - 01 = MSB only - 10 = LSB only - 11 = LSB / MSB (16-bit) - Bit 3-1 = Mode - Bit 0 = Binary (0) / BCD mode (1) - -2.2) RTC - -The second device which was available in the original PC was the MC146818 real -time clock. The original device is now obsolete, and usually emulated by the -system chipset, sometimes by an HPET and some frankenstein IRQ routing. - -The RTC is accessed through CMOS variables, which uses an index register to -control which bytes are read. Since there is only one index register, read -of the CMOS and read of the RTC require lock protection (in addition, it is -dangerous to allow userspace utilities such as hwclock to have direct RTC -access, as they could corrupt kernel reads and writes of CMOS memory). - -The RTC generates an interrupt which is usually routed to IRQ 8. The interrupt -can function as a periodic timer, an additional once a day alarm, and can issue -interrupts after an update of the CMOS registers by the MC146818 is complete. -The type of interrupt is signalled in the RTC status registers. - -The RTC will update the current time fields by battery power even while the -system is off. The current time fields should not be read while an update is -in progress, as indicated in the status register. - -The clock uses a 32.768kHz crystal, so bits 6-4 of register A should be -programmed to a 32kHz divider if the RTC is to count seconds. - -This is the RAM map originally used for the RTC/CMOS: - -Location Size Description ------------------------------------------- -00h byte Current second (BCD) -01h byte Seconds alarm (BCD) -02h byte Current minute (BCD) -03h byte Minutes alarm (BCD) -04h byte Current hour (BCD) -05h byte Hours alarm (BCD) -06h byte Current day of week (BCD) -07h byte Current day of month (BCD) -08h byte Current month (BCD) -09h byte Current year (BCD) -0Ah byte Register A - bit 7 = Update in progress - bit 6-4 = Divider for clock - 000 = 4.194 MHz - 001 = 1.049 MHz - 010 = 32 kHz - 10X = test modes - 110 = reset / disable - 111 = reset / disable - bit 3-0 = Rate selection for periodic interrupt - 000 = periodic timer disabled - 001 = 3.90625 uS - 010 = 7.8125 uS - 011 = .122070 mS - 100 = .244141 mS - ... - 1101 = 125 mS - 1110 = 250 mS - 1111 = 500 mS -0Bh byte Register B - bit 7 = Run (0) / Halt (1) - bit 6 = Periodic interrupt enable - bit 5 = Alarm interrupt enable - bit 4 = Update-ended interrupt enable - bit 3 = Square wave interrupt enable - bit 2 = BCD calendar (0) / Binary (1) - bit 1 = 12-hour mode (0) / 24-hour mode (1) - bit 0 = 0 (DST off) / 1 (DST enabled) -OCh byte Register C (read only) - bit 7 = interrupt request flag (IRQF) - bit 6 = periodic interrupt flag (PF) - bit 5 = alarm interrupt flag (AF) - bit 4 = update interrupt flag (UF) - bit 3-0 = reserved -ODh byte Register D (read only) - bit 7 = RTC has power - bit 6-0 = reserved -32h byte Current century BCD (*) - (*) location vendor specific and now determined from ACPI global tables - -2.3) APIC - -On Pentium and later processors, an on-board timer is available to each CPU -as part of the Advanced Programmable Interrupt Controller. The APIC is -accessed through memory-mapped registers and provides interrupt service to each -CPU, used for IPIs and local timer interrupts. - -Although in theory the APIC is a safe and stable source for local interrupts, -in practice, many bugs and glitches have occurred due to the special nature of -the APIC CPU-local memory-mapped hardware. Beware that CPU errata may affect -the use of the APIC and that workarounds may be required. In addition, some of -these workarounds pose unique constraints for virtualization - requiring either -extra overhead incurred from extra reads of memory-mapped I/O or additional -functionality that may be more computationally expensive to implement. - -Since the APIC is documented quite well in the Intel and AMD manuals, we will -avoid repetition of the detail here. It should be pointed out that the APIC -timer is programmed through the LVT (local vector timer) register, is capable -of one-shot or periodic operation, and is based on the bus clock divided down -by the programmable divider register. - -2.4) HPET - -HPET is quite complex, and was originally intended to replace the PIT / RTC -support of the X86 PC. It remains to be seen whether that will be the case, as -the de facto standard of PC hardware is to emulate these older devices. Some -systems designated as legacy free may support only the HPET as a hardware timer -device. - -The HPET spec is rather loose and vague, requiring at least 3 hardware timers, -but allowing implementation freedom to support many more. It also imposes no -fixed rate on the timer frequency, but does impose some extremal values on -frequency, error and slew. - -In general, the HPET is recommended as a high precision (compared to PIT /RTC) -time source which is independent of local variation (as there is only one HPET -in any given system). The HPET is also memory-mapped, and its presence is -indicated through ACPI tables by the BIOS. - -Detailed specification of the HPET is beyond the current scope of this -document, as it is also very well documented elsewhere. - -2.5) Offboard Timers - -Several cards, both proprietary (watchdog boards) and commonplace (e1000) have -timing chips built into the cards which may have registers which are accessible -to kernel or user drivers. To the author's knowledge, using these to generate -a clocksource for a Linux or other kernel has not yet been attempted and is in -general frowned upon as not playing by the agreed rules of the game. Such a -timer device would require additional support to be virtualized properly and is -not considered important at this time as no known operating system does this. - -========================================================================= - -3) TSC Hardware - -The TSC or time stamp counter is relatively simple in theory; it counts -instruction cycles issued by the processor, which can be used as a measure of -time. In practice, due to a number of problems, it is the most complicated -timekeeping device to use. - -The TSC is represented internally as a 64-bit MSR which can be read with the -RDMSR, RDTSC, or RDTSCP (when available) instructions. In the past, hardware -limitations made it possible to write the TSC, but generally on old hardware it -was only possible to write the low 32-bits of the 64-bit counter, and the upper -32-bits of the counter were cleared. Now, however, on Intel processors family -0Fh, for models 3, 4 and 6, and family 06h, models e and f, this restriction -has been lifted and all 64-bits are writable. On AMD systems, the ability to -write the TSC MSR is not an architectural guarantee. - -The TSC is accessible from CPL-0 and conditionally, for CPL > 0 software by -means of the CR4.TSD bit, which when enabled, disables CPL > 0 TSC access. - -Some vendors have implemented an additional instruction, RDTSCP, which returns -atomically not just the TSC, but an indicator which corresponds to the -processor number. This can be used to index into an array of TSC variables to -determine offset information in SMP systems where TSCs are not synchronized. -The presence of this instruction must be determined by consulting CPUID feature -bits. - -Both VMX and SVM provide extension fields in the virtualization hardware which -allows the guest visible TSC to be offset by a constant. Newer implementations -promise to allow the TSC to additionally be scaled, but this hardware is not -yet widely available. - -3.1) TSC synchronization - -The TSC is a CPU-local clock in most implementations. This means, on SMP -platforms, the TSCs of different CPUs may start at different times depending -on when the CPUs are powered on. Generally, CPUs on the same die will share -the same clock, however, this is not always the case. - -The BIOS may attempt to resynchronize the TSCs during the poweron process and -the operating system or other system software may attempt to do this as well. -Several hardware limitations make the problem worse - if it is not possible to -write the full 64-bits of the TSC, it may be impossible to match the TSC in -newly arriving CPUs to that of the rest of the system, resulting in -unsynchronized TSCs. This may be done by BIOS or system software, but in -practice, getting a perfectly synchronized TSC will not be possible unless all -values are read from the same clock, which generally only is possible on single -socket systems or those with special hardware support. - -3.2) TSC and CPU hotplug - -As touched on already, CPUs which arrive later than the boot time of the system -may not have a TSC value that is synchronized with the rest of the system. -Either system software, BIOS, or SMM code may actually try to establish the TSC -to a value matching the rest of the system, but a perfect match is usually not -a guarantee. This can have the effect of bringing a system from a state where -TSC is synchronized back to a state where TSC synchronization flaws, however -small, may be exposed to the OS and any virtualization environment. - -3.3) TSC and multi-socket / NUMA - -Multi-socket systems, especially large multi-socket systems are likely to have -individual clocksources rather than a single, universally distributed clock. -Since these clocks are driven by different crystals, they will not have -perfectly matched frequency, and temperature and electrical variations will -cause the CPU clocks, and thus the TSCs to drift over time. Depending on the -exact clock and bus design, the drift may or may not be fixed in absolute -error, and may accumulate over time. - -In addition, very large systems may deliberately slew the clocks of individual -cores. This technique, known as spread-spectrum clocking, reduces EMI at the -clock frequency and harmonics of it, which may be required to pass FCC -standards for telecommunications and computer equipment. - -It is recommended not to trust the TSCs to remain synchronized on NUMA or -multiple socket systems for these reasons. - -3.4) TSC and C-states - -C-states, or idling states of the processor, especially C1E and deeper sleep -states may be problematic for TSC as well. The TSC may stop advancing in such -a state, resulting in a TSC which is behind that of other CPUs when execution -is resumed. Such CPUs must be detected and flagged by the operating system -based on CPU and chipset identifications. - -The TSC in such a case may be corrected by catching it up to a known external -clocksource. - -3.5) TSC frequency change / P-states - -To make things slightly more interesting, some CPUs may change frequency. They -may or may not run the TSC at the same rate, and because the frequency change -may be staggered or slewed, at some points in time, the TSC rate may not be -known other than falling within a range of values. In this case, the TSC will -not be a stable time source, and must be calibrated against a known, stable, -external clock to be a usable source of time. - -Whether the TSC runs at a constant rate or scales with the P-state is model -dependent and must be determined by inspecting CPUID, chipset or vendor -specific MSR fields. - -In addition, some vendors have known bugs where the P-state is actually -compensated for properly during normal operation, but when the processor is -inactive, the P-state may be raised temporarily to service cache misses from -other processors. In such cases, the TSC on halted CPUs could advance faster -than that of non-halted processors. AMD Turion processors are known to have -this problem. - -3.6) TSC and STPCLK / T-states - -External signals given to the processor may also have the effect of stopping -the TSC. This is typically done for thermal emergency power control to prevent -an overheating condition, and typically, there is no way to detect that this -condition has happened. - -3.7) TSC virtualization - VMX - -VMX provides conditional trapping of RDTSC, RDMSR, WRMSR and RDTSCP -instructions, which is enough for full virtualization of TSC in any manner. In -addition, VMX allows passing through the host TSC plus an additional TSC_OFFSET -field specified in the VMCS. Special instructions must be used to read and -write the VMCS field. - -3.8) TSC virtualization - SVM - -SVM provides conditional trapping of RDTSC, RDMSR, WRMSR and RDTSCP -instructions, which is enough for full virtualization of TSC in any manner. In -addition, SVM allows passing through the host TSC plus an additional offset -field specified in the SVM control block. - -3.9) TSC feature bits in Linux - -In summary, there is no way to guarantee the TSC remains in perfect -synchronization unless it is explicitly guaranteed by the architecture. Even -if so, the TSCs in multi-sockets or NUMA systems may still run independently -despite being locally consistent. - -The following feature bits are used by Linux to signal various TSC attributes, -but they can only be taken to be meaningful for UP or single node systems. - -X86_FEATURE_TSC : The TSC is available in hardware -X86_FEATURE_RDTSCP : The RDTSCP instruction is available -X86_FEATURE_CONSTANT_TSC : The TSC rate is unchanged with P-states -X86_FEATURE_NONSTOP_TSC : The TSC does not stop in C-states -X86_FEATURE_TSC_RELIABLE : TSC sync checks are skipped (VMware) - -4) Virtualization Problems - -Timekeeping is especially problematic for virtualization because a number of -challenges arise. The most obvious problem is that time is now shared between -the host and, potentially, a number of virtual machines. Thus the virtual -operating system does not run with 100% usage of the CPU, despite the fact that -it may very well make that assumption. It may expect it to remain true to very -exacting bounds when interrupt sources are disabled, but in reality only its -virtual interrupt sources are disabled, and the machine may still be preempted -at any time. This causes problems as the passage of real time, the injection -of machine interrupts and the associated clock sources are no longer completely -synchronized with real time. - -This same problem can occur on native harware to a degree, as SMM mode may -steal cycles from the naturally on X86 systems when SMM mode is used by the -BIOS, but not in such an extreme fashion. However, the fact that SMM mode may -cause similar problems to virtualization makes it a good justification for -solving many of these problems on bare metal. - -4.1) Interrupt clocking - -One of the most immediate problems that occurs with legacy operating systems -is that the system timekeeping routines are often designed to keep track of -time by counting periodic interrupts. These interrupts may come from the PIT -or the RTC, but the problem is the same: the host virtualization engine may not -be able to deliver the proper number of interrupts per second, and so guest -time may fall behind. This is especially problematic if a high interrupt rate -is selected, such as 1000 HZ, which is unfortunately the default for many Linux -guests. - -There are three approaches to solving this problem; first, it may be possible -to simply ignore it. Guests which have a separate time source for tracking -'wall clock' or 'real time' may not need any adjustment of their interrupts to -maintain proper time. If this is not sufficient, it may be necessary to inject -additional interrupts into the guest in order to increase the effective -interrupt rate. This approach leads to complications in extreme conditions, -where host load or guest lag is too much to compensate for, and thus another -solution to the problem has risen: the guest may need to become aware of lost -ticks and compensate for them internally. Although promising in theory, the -implementation of this policy in Linux has been extremely error prone, and a -number of buggy variants of lost tick compensation are distributed across -commonly used Linux systems. - -Windows uses periodic RTC clocking as a means of keeping time internally, and -thus requires interrupt slewing to keep proper time. It does use a low enough -rate (ed: is it 18.2 Hz?) however that it has not yet been a problem in -practice. - -4.2) TSC sampling and serialization - -As the highest precision time source available, the cycle counter of the CPU -has aroused much interest from developers. As explained above, this timer has -many problems unique to its nature as a local, potentially unstable and -potentially unsynchronized source. One issue which is not unique to the TSC, -but is highlighted because of its very precise nature is sampling delay. By -definition, the counter, once read is already old. However, it is also -possible for the counter to be read ahead of the actual use of the result. -This is a consequence of the superscalar execution of the instruction stream, -which may execute instructions out of order. Such execution is called -non-serialized. Forcing serialized execution is necessary for precise -measurement with the TSC, and requires a serializing instruction, such as CPUID -or an MSR read. - -Since CPUID may actually be virtualized by a trap and emulate mechanism, this -serialization can pose a performance issue for hardware virtualization. An -accurate time stamp counter reading may therefore not always be available, and -it may be necessary for an implementation to guard against "backwards" reads of -the TSC as seen from other CPUs, even in an otherwise perfectly synchronized -system. - -4.3) Timespec aliasing - -Additionally, this lack of serialization from the TSC poses another challenge -when using results of the TSC when measured against another time source. As -the TSC is much higher precision, many possible values of the TSC may be read -while another clock is still expressing the same value. - -That is, you may read (T,T+10) while external clock C maintains the same value. -Due to non-serialized reads, you may actually end up with a range which -fluctuates - from (T-1.. T+10). Thus, any time calculated from a TSC, but -calibrated against an external value may have a range of valid values. -Re-calibrating this computation may actually cause time, as computed after the -calibration, to go backwards, compared with time computed before the -calibration. - -This problem is particularly pronounced with an internal time source in Linux, -the kernel time, which is expressed in the theoretically high resolution -timespec - but which advances in much larger granularity intervals, sometimes -at the rate of jiffies, and possibly in catchup modes, at a much larger step. - -This aliasing requires care in the computation and recalibration of kvmclock -and any other values derived from TSC computation (such as TSC virtualization -itself). - -4.4) Migration - -Migration of a virtual machine raises problems for timekeeping in two ways. -First, the migration itself may take time, during which interrupts cannot be -delivered, and after which, the guest time may need to be caught up. NTP may -be able to help to some degree here, as the clock correction required is -typically small enough to fall in the NTP-correctable window. - -An additional concern is that timers based off the TSC (or HPET, if the raw bus -clock is exposed) may now be running at different rates, requiring compensation -in some way in the hypervisor by virtualizing these timers. In addition, -migrating to a faster machine may preclude the use of a passthrough TSC, as a -faster clock cannot be made visible to a guest without the potential of time -advancing faster than usual. A slower clock is less of a problem, as it can -always be caught up to the original rate. KVM clock avoids these problems by -simply storing multipliers and offsets against the TSC for the guest to convert -back into nanosecond resolution values. - -4.5) Scheduling - -Since scheduling may be based on precise timing and firing of interrupts, the -scheduling algorithms of an operating system may be adversely affected by -virtualization. In theory, the effect is random and should be universally -distributed, but in contrived as well as real scenarios (guest device access, -causes of virtualization exits, possible context switch), this may not always -be the case. The effect of this has not been well studied. - -In an attempt to work around this, several implementations have provided a -paravirtualized scheduler clock, which reveals the true amount of CPU time for -which a virtual machine has been running. - -4.6) Watchdogs - -Watchdog timers, such as the lock detector in Linux may fire accidentally when -running under hardware virtualization due to timer interrupts being delayed or -misinterpretation of the passage of real time. Usually, these warnings are -spurious and can be ignored, but in some circumstances it may be necessary to -disable such detection. - -4.7) Delays and precision timing - -Precise timing and delays may not be possible in a virtualized system. This -can happen if the system is controlling physical hardware, or issues delays to -compensate for slower I/O to and from devices. The first issue is not solvable -in general for a virtualized system; hardware control software can't be -adequately virtualized without a full real-time operating system, which would -require an RT aware virtualization platform. - -The second issue may cause performance problems, but this is unlikely to be a -significant issue. In many cases these delays may be eliminated through -configuration or paravirtualization. - -4.8) Covert channels and leaks - -In addition to the above problems, time information will inevitably leak to the -guest about the host in anything but a perfect implementation of virtualized -time. This may allow the guest to infer the presence of a hypervisor (as in a -red-pill type detection), and it may allow information to leak between guests -by using CPU utilization itself as a signalling channel. Preventing such -problems would require completely isolated virtual time which may not track -real time any longer. This may be useful in certain security or QA contexts, -but in general isn't recommended for real-world deployment scenarios. diff --git a/Documentation/lguest/.gitignore b/Documentation/lguest/.gitignore deleted file mode 100644 index 115587f..0000000 --- a/Documentation/lguest/.gitignore +++ /dev/null @@ -1 +0,0 @@ -lguest diff --git a/Documentation/lguest/Makefile b/Documentation/lguest/Makefile deleted file mode 100644 index bebac6b..0000000 --- a/Documentation/lguest/Makefile +++ /dev/null @@ -1,8 +0,0 @@ -# This creates the demonstration utility "lguest" which runs a Linux guest. -# Missing headers? Add "-I../../include -I../../arch/x86/include" -CFLAGS:=-m32 -Wall -Wmissing-declarations -Wmissing-prototypes -O3 -U_FORTIFY_SOURCE - -all: lguest - -clean: - rm -f lguest diff --git a/Documentation/lguest/extract b/Documentation/lguest/extract deleted file mode 100644 index 7730bb6..0000000 --- a/Documentation/lguest/extract +++ /dev/null @@ -1,58 +0,0 @@ -#! /bin/sh - -set -e - -PREFIX=$1 -shift - -trap 'rm -r $TMPDIR' 0 -TMPDIR=`mktemp -d` - -exec 3>/dev/null -for f; do - while IFS=" -" read -r LINE; do - case "$LINE" in - *$PREFIX:[0-9]*:\**) - NUM=`echo "$LINE" | sed "s/.*$PREFIX:\([0-9]*\).*/\1/"` - if [ -f $TMPDIR/$NUM ]; then - echo "$TMPDIR/$NUM already exits prior to $f" - exit 1 - fi - exec 3>>$TMPDIR/$NUM - echo $f | sed 's,\.\./,,g' > $TMPDIR/.$NUM - /bin/echo "$LINE" | sed -e "s/$PREFIX:[0-9]*//" -e "s/:\*/*/" >&3 - ;; - *$PREFIX:[0-9]*) - NUM=`echo "$LINE" | sed "s/.*$PREFIX:\([0-9]*\).*/\1/"` - if [ -f $TMPDIR/$NUM ]; then - echo "$TMPDIR/$NUM already exits prior to $f" - exit 1 - fi - exec 3>>$TMPDIR/$NUM - echo $f | sed 's,\.\./,,g' > $TMPDIR/.$NUM - /bin/echo "$LINE" | sed "s/$PREFIX:[0-9]*//" >&3 - ;; - *:\**) - /bin/echo "$LINE" | sed -e "s/:\*/*/" -e "s,/\*\*/,," >&3 - echo >&3 - exec 3>/dev/null - ;; - *) - /bin/echo "$LINE" >&3 - ;; - esac - done < $f - echo >&3 - exec 3>/dev/null -done - -LASTFILE="" -for f in $TMPDIR/*; do - if [ "$LASTFILE" != $(cat $TMPDIR/.$(basename $f) ) ]; then - LASTFILE=$(cat $TMPDIR/.$(basename $f) ) - echo "[ $LASTFILE ]" - fi - cat $f -done - diff --git a/Documentation/lguest/lguest.c b/Documentation/lguest/lguest.c deleted file mode 100644 index d9da7e1..0000000 --- a/Documentation/lguest/lguest.c +++ /dev/null @@ -1,2095 +0,0 @@ -/*P:100 - * This is the Launcher code, a simple program which lays out the "physical" - * memory for the new Guest by mapping the kernel image and the virtual - * devices, then opens /dev/lguest to tell the kernel about the Guest and - * control it. -:*/ -#define _LARGEFILE64_SOURCE -#define _GNU_SOURCE -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include "../../include/linux/lguest_launcher.h" -/*L:110 - * We can ignore the 42 include files we need for this program, but I do want - * to draw attention to the use of kernel-style types. - * - * As Linus said, "C is a Spartan language, and so should your naming be." I - * like these abbreviations, so we define them here. Note that u64 is always - * unsigned long long, which works on all Linux systems: this means that we can - * use %llu in printf for any u64. - */ -typedef unsigned long long u64; -typedef uint32_t u32; -typedef uint16_t u16; -typedef uint8_t u8; -/*:*/ - -#define PAGE_PRESENT 0x7 /* Present, RW, Execute */ -#define BRIDGE_PFX "bridge:" -#ifndef SIOCBRADDIF -#define SIOCBRADDIF 0x89a2 /* add interface to bridge */ -#endif -/* We can have up to 256 pages for devices. */ -#define DEVICE_PAGES 256 -/* This will occupy 3 pages: it must be a power of 2. */ -#define VIRTQUEUE_NUM 256 - -/*L:120 - * verbose is both a global flag and a macro. The C preprocessor allows - * this, and although I wouldn't recommend it, it works quite nicely here. - */ -static bool verbose; -#define verbose(args...) \ - do { if (verbose) printf(args); } while(0) -/*:*/ - -/* The pointer to the start of guest memory. */ -static void *guest_base; -/* The maximum guest physical address allowed, and maximum possible. */ -static unsigned long guest_limit, guest_max; -/* The /dev/lguest file descriptor. */ -static int lguest_fd; - -/* a per-cpu variable indicating whose vcpu is currently running */ -static unsigned int __thread cpu_id; - -/* This is our list of devices. */ -struct device_list { - /* Counter to assign interrupt numbers. */ - unsigned int next_irq; - - /* Counter to print out convenient device numbers. */ - unsigned int device_num; - - /* The descriptor page for the devices. */ - u8 *descpage; - - /* A single linked list of devices. */ - struct device *dev; - /* And a pointer to the last device for easy append. */ - struct device *lastdev; -}; - -/* The list of Guest devices, based on command line arguments. */ -static struct device_list devices; - -/* The device structure describes a single device. */ -struct device { - /* The linked-list pointer. */ - struct device *next; - - /* The device's descriptor, as mapped into the Guest. */ - struct lguest_device_desc *desc; - - /* We can't trust desc values once Guest has booted: we use these. */ - unsigned int feature_len; - unsigned int num_vq; - - /* The name of this device, for --verbose. */ - const char *name; - - /* Any queues attached to this device */ - struct virtqueue *vq; - - /* Is it operational */ - bool running; - - /* Does Guest want an intrrupt on empty? */ - bool irq_on_empty; - - /* Device-specific data. */ - void *priv; -}; - -/* The virtqueue structure describes a queue attached to a device. */ -struct virtqueue { - struct virtqueue *next; - - /* Which device owns me. */ - struct device *dev; - - /* The configuration for this queue. */ - struct lguest_vqconfig config; - - /* The actual ring of buffers. */ - struct vring vring; - - /* Last available index we saw. */ - u16 last_avail_idx; - - /* How many are used since we sent last irq? */ - unsigned int pending_used; - - /* Eventfd where Guest notifications arrive. */ - int eventfd; - - /* Function for the thread which is servicing this virtqueue. */ - void (*service)(struct virtqueue *vq); - pid_t thread; -}; - -/* Remember the arguments to the program so we can "reboot" */ -static char **main_args; - -/* The original tty settings to restore on exit. */ -static struct termios orig_term; - -/* - * We have to be careful with barriers: our devices are all run in separate - * threads and so we need to make sure that changes visible to the Guest happen - * in precise order. - */ -#define wmb() __asm__ __volatile__("" : : : "memory") -#define mb() __asm__ __volatile__("" : : : "memory") - -/* - * Convert an iovec element to the given type. - * - * This is a fairly ugly trick: we need to know the size of the type and - * alignment requirement to check the pointer is kosher. It's also nice to - * have the name of the type in case we report failure. - * - * Typing those three things all the time is cumbersome and error prone, so we - * have a macro which sets them all up and passes to the real function. - */ -#define convert(iov, type) \ - ((type *)_convert((iov), sizeof(type), __alignof__(type), #type)) - -static void *_convert(struct iovec *iov, size_t size, size_t align, - const char *name) -{ - if (iov->iov_len != size) - errx(1, "Bad iovec size %zu for %s", iov->iov_len, name); - if ((unsigned long)iov->iov_base % align != 0) - errx(1, "Bad alignment %p for %s", iov->iov_base, name); - return iov->iov_base; -} - -/* Wrapper for the last available index. Makes it easier to change. */ -#define lg_last_avail(vq) ((vq)->last_avail_idx) - -/* - * The virtio configuration space is defined to be little-endian. x86 is - * little-endian too, but it's nice to be explicit so we have these helpers. - */ -#define cpu_to_le16(v16) (v16) -#define cpu_to_le32(v32) (v32) -#define cpu_to_le64(v64) (v64) -#define le16_to_cpu(v16) (v16) -#define le32_to_cpu(v32) (v32) -#define le64_to_cpu(v64) (v64) - -/* Is this iovec empty? */ -static bool iov_empty(const struct iovec iov[], unsigned int num_iov) -{ - unsigned int i; - - for (i = 0; i < num_iov; i++) - if (iov[i].iov_len) - return false; - return true; -} - -/* Take len bytes from the front of this iovec. */ -static void iov_consume(struct iovec iov[], unsigned num_iov, unsigned len) -{ - unsigned int i; - - for (i = 0; i < num_iov; i++) { - unsigned int used; - - used = iov[i].iov_len < len ? iov[i].iov_len : len; - iov[i].iov_base += used; - iov[i].iov_len -= used; - len -= used; - } - assert(len == 0); -} - -/* The device virtqueue descriptors are followed by feature bitmasks. */ -static u8 *get_feature_bits(struct device *dev) -{ - return (u8 *)(dev->desc + 1) - + dev->num_vq * sizeof(struct lguest_vqconfig); -} - -/*L:100 - * The Launcher code itself takes us out into userspace, that scary place where - * pointers run wild and free! Unfortunately, like most userspace programs, - * it's quite boring (which is why everyone likes to hack on the kernel!). - * Perhaps if you make up an Lguest Drinking Game at this point, it will get - * you through this section. Or, maybe not. - * - * The Launcher sets up a big chunk of memory to be the Guest's "physical" - * memory and stores it in "guest_base". In other words, Guest physical == - * Launcher virtual with an offset. - * - * This can be tough to get your head around, but usually it just means that we - * use these trivial conversion functions when the Guest gives us its - * "physical" addresses: - */ -static void *from_guest_phys(unsigned long addr) -{ - return guest_base + addr; -} - -static unsigned long to_guest_phys(const void *addr) -{ - return (addr - guest_base); -} - -/*L:130 - * Loading the Kernel. - * - * We start with couple of simple helper routines. open_or_die() avoids - * error-checking code cluttering the callers: - */ -static int open_or_die(const char *name, int flags) -{ - int fd = open(name, flags); - if (fd < 0) - err(1, "Failed to open %s", name); - return fd; -} - -/* map_zeroed_pages() takes a number of pages. */ -static void *map_zeroed_pages(unsigned int num) -{ - int fd = open_or_die("/dev/zero", O_RDONLY); - void *addr; - - /* - * We use a private mapping (ie. if we write to the page, it will be - * copied). We allocate an extra two pages PROT_NONE to act as guard - * pages against read/write attempts that exceed allocated space. - */ - addr = mmap(NULL, getpagesize() * (num+2), - PROT_NONE, MAP_PRIVATE, fd, 0); - - if (addr == MAP_FAILED) - err(1, "Mmapping %u pages of /dev/zero", num); - - if (mprotect(addr + getpagesize(), getpagesize() * num, - PROT_READ|PROT_WRITE) == -1) - err(1, "mprotect rw %u pages failed", num); - - /* - * One neat mmap feature is that you can close the fd, and it - * stays mapped. - */ - close(fd); - - /* Return address after PROT_NONE page */ - return addr + getpagesize(); -} - -/* Get some more pages for a device. */ -static void *get_pages(unsigned int num) -{ - void *addr = from_guest_phys(guest_limit); - - guest_limit += num * getpagesize(); - if (guest_limit > guest_max) - errx(1, "Not enough memory for devices"); - return addr; -} - -/* - * This routine is used to load the kernel or initrd. It tries mmap, but if - * that fails (Plan 9's kernel file isn't nicely aligned on page boundaries), - * it falls back to reading the memory in. - */ -static void map_at(int fd, void *addr, unsigned long offset, unsigned long len) -{ - ssize_t r; - - /* - * We map writable even though for some segments are marked read-only. - * The kernel really wants to be writable: it patches its own - * instructions. - * - * MAP_PRIVATE means that the page won't be copied until a write is - * done to it. This allows us to share untouched memory between - * Guests. - */ - if (mmap(addr, len, PROT_READ|PROT_WRITE, - MAP_FIXED|MAP_PRIVATE, fd, offset) != MAP_FAILED) - return; - - /* pread does a seek and a read in one shot: saves a few lines. */ - r = pread(fd, addr, len, offset); - if (r != len) - err(1, "Reading offset %lu len %lu gave %zi", offset, len, r); -} - -/* - * This routine takes an open vmlinux image, which is in ELF, and maps it into - * the Guest memory. ELF = Embedded Linking Format, which is the format used - * by all modern binaries on Linux including the kernel. - * - * The ELF headers give *two* addresses: a physical address, and a virtual - * address. We use the physical address; the Guest will map itself to the - * virtual address. - * - * We return the starting address. - */ -static unsigned long map_elf(int elf_fd, const Elf32_Ehdr *ehdr) -{ - Elf32_Phdr phdr[ehdr->e_phnum]; - unsigned int i; - - /* - * Sanity checks on the main ELF header: an x86 executable with a - * reasonable number of correctly-sized program headers. - */ - if (ehdr->e_type != ET_EXEC - || ehdr->e_machine != EM_386 - || ehdr->e_phentsize != sizeof(Elf32_Phdr) - || ehdr->e_phnum < 1 || ehdr->e_phnum > 65536U/sizeof(Elf32_Phdr)) - errx(1, "Malformed elf header"); - - /* - * An ELF executable contains an ELF header and a number of "program" - * headers which indicate which parts ("segments") of the program to - * load where. - */ - - /* We read in all the program headers at once: */ - if (lseek(elf_fd, ehdr->e_phoff, SEEK_SET) < 0) - err(1, "Seeking to program headers"); - if (read(elf_fd, phdr, sizeof(phdr)) != sizeof(phdr)) - err(1, "Reading program headers"); - - /* - * Try all the headers: there are usually only three. A read-only one, - * a read-write one, and a "note" section which we don't load. - */ - for (i = 0; i < ehdr->e_phnum; i++) { - /* If this isn't a loadable segment, we ignore it */ - if (phdr[i].p_type != PT_LOAD) - continue; - - verbose("Section %i: size %i addr %p\n", - i, phdr[i].p_memsz, (void *)phdr[i].p_paddr); - - /* We map this section of the file at its physical address. */ - map_at(elf_fd, from_guest_phys(phdr[i].p_paddr), - phdr[i].p_offset, phdr[i].p_filesz); - } - - /* The entry point is given in the ELF header. */ - return ehdr->e_entry; -} - -/*L:150 - * A bzImage, unlike an ELF file, is not meant to be loaded. You're supposed - * to jump into it and it will unpack itself. We used to have to perform some - * hairy magic because the unpacking code scared me. - * - * Fortunately, Jeremy Fitzhardinge convinced me it wasn't that hard and wrote - * a small patch to jump over the tricky bits in the Guest, so now we just read - * the funky header so we know where in the file to load, and away we go! - */ -static unsigned long load_bzimage(int fd) -{ - struct boot_params boot; - int r; - /* Modern bzImages get loaded at 1M. */ - void *p = from_guest_phys(0x100000); - - /* - * Go back to the start of the file and read the header. It should be - * a Linux boot header (see Documentation/x86/i386/boot.txt) - */ - lseek(fd, 0, SEEK_SET); - read(fd, &boot, sizeof(boot)); - - /* Inside the setup_hdr, we expect the magic "HdrS" */ - if (memcmp(&boot.hdr.header, "HdrS", 4) != 0) - errx(1, "This doesn't look like a bzImage to me"); - - /* Skip over the extra sectors of the header. */ - lseek(fd, (boot.hdr.setup_sects+1) * 512, SEEK_SET); - - /* Now read everything into memory. in nice big chunks. */ - while ((r = read(fd, p, 65536)) > 0) - p += r; - - /* Finally, code32_start tells us where to enter the kernel. */ - return boot.hdr.code32_start; -} - -/*L:140 - * Loading the kernel is easy when it's a "vmlinux", but most kernels - * come wrapped up in the self-decompressing "bzImage" format. With a little - * work, we can load those, too. - */ -static unsigned long load_kernel(int fd) -{ - Elf32_Ehdr hdr; - - /* Read in the first few bytes. */ - if (read(fd, &hdr, sizeof(hdr)) != sizeof(hdr)) - err(1, "Reading kernel"); - - /* If it's an ELF file, it starts with "\177ELF" */ - if (memcmp(hdr.e_ident, ELFMAG, SELFMAG) == 0) - return map_elf(fd, &hdr); - - /* Otherwise we assume it's a bzImage, and try to load it. */ - return load_bzimage(fd); -} - -/* - * This is a trivial little helper to align pages. Andi Kleen hated it because - * it calls getpagesize() twice: "it's dumb code." - * - * Kernel guys get really het up about optimization, even when it's not - * necessary. I leave this code as a reaction against that. - */ -static inline unsigned long page_align(unsigned long addr) -{ - /* Add upwards and truncate downwards. */ - return ((addr + getpagesize()-1) & ~(getpagesize()-1)); -} - -/*L:180 - * An "initial ram disk" is a disk image loaded into memory along with the - * kernel which the kernel can use to boot from without needing any drivers. - * Most distributions now use this as standard: the initrd contains the code to - * load the appropriate driver modules for the current machine. - * - * Importantly, James Morris works for RedHat, and Fedora uses initrds for its - * kernels. He sent me this (and tells me when I break it). - */ -static unsigned long load_initrd(const char *name, unsigned long mem) -{ - int ifd; - struct stat st; - unsigned long len; - - ifd = open_or_die(name, O_RDONLY); - /* fstat() is needed to get the file size. */ - if (fstat(ifd, &st) < 0) - err(1, "fstat() on initrd '%s'", name); - - /* - * We map the initrd at the top of memory, but mmap wants it to be - * page-aligned, so we round the size up for that. - */ - len = page_align(st.st_size); - map_at(ifd, from_guest_phys(mem - len), 0, st.st_size); - /* - * Once a file is mapped, you can close the file descriptor. It's a - * little odd, but quite useful. - */ - close(ifd); - verbose("mapped initrd %s size=%lu @ %p\n", name, len, (void*)mem-len); - - /* We return the initrd size. */ - return len; -} -/*:*/ - -/* - * Simple routine to roll all the commandline arguments together with spaces - * between them. - */ -static void concat(char *dst, char *args[]) -{ - unsigned int i, len = 0; - - for (i = 0; args[i]; i++) { - if (i) { - strcat(dst+len, " "); - len++; - } - strcpy(dst+len, args[i]); - len += strlen(args[i]); - } - /* In case it's empty. */ - dst[len] = '\0'; -} - -/*L:185 - * This is where we actually tell the kernel to initialize the Guest. We - * saw the arguments it expects when we looked at initialize() in lguest_user.c: - * the base of Guest "physical" memory, the top physical page to allow and the - * entry point for the Guest. - */ -static void tell_kernel(unsigned long start) -{ - unsigned long args[] = { LHREQ_INITIALIZE, - (unsigned long)guest_base, - guest_limit / getpagesize(), start }; - verbose("Guest: %p - %p (%#lx)\n", - guest_base, guest_base + guest_limit, guest_limit); - lguest_fd = open_or_die("/dev/lguest", O_RDWR); - if (write(lguest_fd, args, sizeof(args)) < 0) - err(1, "Writing to /dev/lguest"); -} -/*:*/ - -/*L:200 - * Device Handling. - * - * When the Guest gives us a buffer, it sends an array of addresses and sizes. - * We need to make sure it's not trying to reach into the Launcher itself, so - * we have a convenient routine which checks it and exits with an error message - * if something funny is going on: - */ -static void *_check_pointer(unsigned long addr, unsigned int size, - unsigned int line) -{ - /* - * Check if the requested address and size exceeds the allocated memory, - * or addr + size wraps around. - */ - if ((addr + size) > guest_limit || (addr + size) < addr) - errx(1, "%s:%i: Invalid address %#lx", __FILE__, line, addr); - /* - * We return a pointer for the caller's convenience, now we know it's - * safe to use. - */ - return from_guest_phys(addr); -} -/* A macro which transparently hands the line number to the real function. */ -#define check_pointer(addr,size) _check_pointer(addr, size, __LINE__) - -/* - * Each buffer in the virtqueues is actually a chain of descriptors. This - * function returns the next descriptor in the chain, or vq->vring.num if we're - * at the end. - */ -static unsigned next_desc(struct vring_desc *desc, - unsigned int i, unsigned int max) -{ - unsigned int next; - - /* If this descriptor says it doesn't chain, we're done. */ - if (!(desc[i].flags & VRING_DESC_F_NEXT)) - return max; - - /* Check they're not leading us off end of descriptors. */ - next = desc[i].next; - /* Make sure compiler knows to grab that: we don't want it changing! */ - wmb(); - - if (next >= max) - errx(1, "Desc next is %u", next); - - return next; -} - -/* - * This actually sends the interrupt for this virtqueue, if we've used a - * buffer. - */ -static void trigger_irq(struct virtqueue *vq) -{ - unsigned long buf[] = { LHREQ_IRQ, vq->config.irq }; - - /* Don't inform them if nothing used. */ - if (!vq->pending_used) - return; - vq->pending_used = 0; - - /* If they don't want an interrupt, don't send one... */ - if (vq->vring.avail->flags & VRING_AVAIL_F_NO_INTERRUPT) { - /* ... unless they've asked us to force one on empty. */ - if (!vq->dev->irq_on_empty - || lg_last_avail(vq) != vq->vring.avail->idx) - return; - } - - /* Send the Guest an interrupt tell them we used something up. */ - if (write(lguest_fd, buf, sizeof(buf)) != 0) - err(1, "Triggering irq %i", vq->config.irq); -} - -/* - * This looks in the virtqueue for the first available buffer, and converts - * it to an iovec for convenient access. Since descriptors consist of some - * number of output then some number of input descriptors, it's actually two - * iovecs, but we pack them into one and note how many of each there were. - * - * This function waits if necessary, and returns the descriptor number found. - */ -static unsigned wait_for_vq_desc(struct virtqueue *vq, - struct iovec iov[], - unsigned int *out_num, unsigned int *in_num) -{ - unsigned int i, head, max; - struct vring_desc *desc; - u16 last_avail = lg_last_avail(vq); - - /* There's nothing available? */ - while (last_avail == vq->vring.avail->idx) { - u64 event; - - /* - * Since we're about to sleep, now is a good time to tell the - * Guest about what we've used up to now. - */ - trigger_irq(vq); - - /* OK, now we need to know about added descriptors. */ - vq->vring.used->flags &= ~VRING_USED_F_NO_NOTIFY; - - /* - * They could have slipped one in as we were doing that: make - * sure it's written, then check again. - */ - mb(); - if (last_avail != vq->vring.avail->idx) { - vq->vring.used->flags |= VRING_USED_F_NO_NOTIFY; - break; - } - - /* Nothing new? Wait for eventfd to tell us they refilled. */ - if (read(vq->eventfd, &event, sizeof(event)) != sizeof(event)) - errx(1, "Event read failed?"); - - /* We don't need to be notified again. */ - vq->vring.used->flags |= VRING_USED_F_NO_NOTIFY; - } - - /* Check it isn't doing very strange things with descriptor numbers. */ - if ((u16)(vq->vring.avail->idx - last_avail) > vq->vring.num) - errx(1, "Guest moved used index from %u to %u", - last_avail, vq->vring.avail->idx); - - /* - * Grab the next descriptor number they're advertising, and increment - * the index we've seen. - */ - head = vq->vring.avail->ring[last_avail % vq->vring.num]; - lg_last_avail(vq)++; - - /* If their number is silly, that's a fatal mistake. */ - if (head >= vq->vring.num) - errx(1, "Guest says index %u is available", head); - - /* When we start there are none of either input nor output. */ - *out_num = *in_num = 0; - - max = vq->vring.num; - desc = vq->vring.desc; - i = head; - - /* - * If this is an indirect entry, then this buffer contains a descriptor - * table which we handle as if it's any normal descriptor chain. - */ - if (desc[i].flags & VRING_DESC_F_INDIRECT) { - if (desc[i].len % sizeof(struct vring_desc)) - errx(1, "Invalid size for indirect buffer table"); - - max = desc[i].len / sizeof(struct vring_desc); - desc = check_pointer(desc[i].addr, desc[i].len); - i = 0; - } - - do { - /* Grab the first descriptor, and check it's OK. */ - iov[*out_num + *in_num].iov_len = desc[i].len; - iov[*out_num + *in_num].iov_base - = check_pointer(desc[i].addr, desc[i].len); - /* If this is an input descriptor, increment that count. */ - if (desc[i].flags & VRING_DESC_F_WRITE) - (*in_num)++; - else { - /* - * If it's an output descriptor, they're all supposed - * to come before any input descriptors. - */ - if (*in_num) - errx(1, "Descriptor has out after in"); - (*out_num)++; - } - - /* If we've got too many, that implies a descriptor loop. */ - if (*out_num + *in_num > max) - errx(1, "Looped descriptor"); - } while ((i = next_desc(desc, i, max)) != max); - - return head; -} - -/* - * After we've used one of their buffers, we tell the Guest about it. Sometime - * later we'll want to send them an interrupt using trigger_irq(); note that - * wait_for_vq_desc() does that for us if it has to wait. - */ -static void add_used(struct virtqueue *vq, unsigned int head, int len) -{ - struct vring_used_elem *used; - - /* - * The virtqueue contains a ring of used buffers. Get a pointer to the - * next entry in that used ring. - */ - used = &vq->vring.used->ring[vq->vring.used->idx % vq->vring.num]; - used->id = head; - used->len = len; - /* Make sure buffer is written before we update index. */ - wmb(); - vq->vring.used->idx++; - vq->pending_used++; -} - -/* And here's the combo meal deal. Supersize me! */ -static void add_used_and_trigger(struct virtqueue *vq, unsigned head, int len) -{ - add_used(vq, head, len); - trigger_irq(vq); -} - -/* - * The Console - * - * We associate some data with the console for our exit hack. - */ -struct console_abort { - /* How many times have they hit ^C? */ - int count; - /* When did they start? */ - struct timeval start; -}; - -/* This is the routine which handles console input (ie. stdin). */ -static void console_input(struct virtqueue *vq) -{ - int len; - unsigned int head, in_num, out_num; - struct console_abort *abort = vq->dev->priv; - struct iovec iov[vq->vring.num]; - - /* Make sure there's a descriptor available. */ - head = wait_for_vq_desc(vq, iov, &out_num, &in_num); - if (out_num) - errx(1, "Output buffers in console in queue?"); - - /* Read into it. This is where we usually wait. */ - len = readv(STDIN_FILENO, iov, in_num); - if (len <= 0) { - /* Ran out of input? */ - warnx("Failed to get console input, ignoring console."); - /* - * For simplicity, dying threads kill the whole Launcher. So - * just nap here. - */ - for (;;) - pause(); - } - - /* Tell the Guest we used a buffer. */ - add_used_and_trigger(vq, head, len); - - /* - * Three ^C within one second? Exit. - * - * This is such a hack, but works surprisingly well. Each ^C has to - * be in a buffer by itself, so they can't be too fast. But we check - * that we get three within about a second, so they can't be too - * slow. - */ - if (len != 1 || ((char *)iov[0].iov_base)[0] != 3) { - abort->count = 0; - return; - } - - abort->count++; - if (abort->count == 1) - gettimeofday(&abort->start, NULL); - else if (abort->count == 3) { - struct timeval now; - gettimeofday(&now, NULL); - /* Kill all Launcher processes with SIGINT, like normal ^C */ - if (now.tv_sec <= abort->start.tv_sec+1) - kill(0, SIGINT); - abort->count = 0; - } -} - -/* This is the routine which handles console output (ie. stdout). */ -static void console_output(struct virtqueue *vq) -{ - unsigned int head, out, in; - struct iovec iov[vq->vring.num]; - - /* We usually wait in here, for the Guest to give us something. */ - head = wait_for_vq_desc(vq, iov, &out, &in); - if (in) - errx(1, "Input buffers in console output queue?"); - - /* writev can return a partial write, so we loop here. */ - while (!iov_empty(iov, out)) { - int len = writev(STDOUT_FILENO, iov, out); - if (len <= 0) - err(1, "Write to stdout gave %i", len); - iov_consume(iov, out, len); - } - - /* - * We're finished with that buffer: if we're going to sleep, - * wait_for_vq_desc() will prod the Guest with an interrupt. - */ - add_used(vq, head, 0); -} - -/* - * The Network - * - * Handling output for network is also simple: we get all the output buffers - * and write them to /dev/net/tun. - */ -struct net_info { - int tunfd; -}; - -static void net_output(struct virtqueue *vq) -{ - struct net_info *net_info = vq->dev->priv; - unsigned int head, out, in; - struct iovec iov[vq->vring.num]; - - /* We usually wait in here for the Guest to give us a packet. */ - head = wait_for_vq_desc(vq, iov, &out, &in); - if (in) - errx(1, "Input buffers in net output queue?"); - /* - * Send the whole thing through to /dev/net/tun. It expects the exact - * same format: what a coincidence! - */ - if (writev(net_info->tunfd, iov, out) < 0) - errx(1, "Write to tun failed?"); - - /* - * Done with that one; wait_for_vq_desc() will send the interrupt if - * all packets are processed. - */ - add_used(vq, head, 0); -} - -/* - * Handling network input is a bit trickier, because I've tried to optimize it. - * - * First we have a helper routine which tells is if from this file descriptor - * (ie. the /dev/net/tun device) will block: - */ -static bool will_block(int fd) -{ - fd_set fdset; - struct timeval zero = { 0, 0 }; - FD_ZERO(&fdset); - FD_SET(fd, &fdset); - return select(fd+1, &fdset, NULL, NULL, &zero) != 1; -} - -/* - * This handles packets coming in from the tun device to our Guest. Like all - * service routines, it gets called again as soon as it returns, so you don't - * see a while(1) loop here. - */ -static void net_input(struct virtqueue *vq) -{ - int len; - unsigned int head, out, in; - struct iovec iov[vq->vring.num]; - struct net_info *net_info = vq->dev->priv; - - /* - * Get a descriptor to write an incoming packet into. This will also - * send an interrupt if they're out of descriptors. - */ - head = wait_for_vq_desc(vq, iov, &out, &in); - if (out) - errx(1, "Output buffers in net input queue?"); - - /* - * If it looks like we'll block reading from the tun device, send them - * an interrupt. - */ - if (vq->pending_used && will_block(net_info->tunfd)) - trigger_irq(vq); - - /* - * Read in the packet. This is where we normally wait (when there's no - * incoming network traffic). - */ - len = readv(net_info->tunfd, iov, in); - if (len <= 0) - err(1, "Failed to read from tun."); - - /* - * Mark that packet buffer as used, but don't interrupt here. We want - * to wait until we've done as much work as we can. - */ - add_used(vq, head, len); -} -/*:*/ - -/* This is the helper to create threads: run the service routine in a loop. */ -static int do_thread(void *_vq) -{ - struct virtqueue *vq = _vq; - - for (;;) - vq->service(vq); - return 0; -} - -/* - * When a child dies, we kill our entire process group with SIGTERM. This - * also has the side effect that the shell restores the console for us! - */ -static void kill_launcher(int signal) -{ - kill(0, SIGTERM); -} - -static void reset_device(struct device *dev) -{ - struct virtqueue *vq; - - verbose("Resetting device %s\n", dev->name); - - /* Clear any features they've acked. */ - memset(get_feature_bits(dev) + dev->feature_len, 0, dev->feature_len); - - /* We're going to be explicitly killing threads, so ignore them. */ - signal(SIGCHLD, SIG_IGN); - - /* Zero out the virtqueues, get rid of their threads */ - for (vq = dev->vq; vq; vq = vq->next) { - if (vq->thread != (pid_t)-1) { - kill(vq->thread, SIGTERM); - waitpid(vq->thread, NULL, 0); - vq->thread = (pid_t)-1; - } - memset(vq->vring.desc, 0, - vring_size(vq->config.num, LGUEST_VRING_ALIGN)); - lg_last_avail(vq) = 0; - } - dev->running = false; - - /* Now we care if threads die. */ - signal(SIGCHLD, (void *)kill_launcher); -} - -/*L:216 - * This actually creates the thread which services the virtqueue for a device. - */ -static void create_thread(struct virtqueue *vq) -{ - /* - * Create stack for thread. Since the stack grows upwards, we point - * the stack pointer to the end of this region. - */ - char *stack = malloc(32768); - unsigned long args[] = { LHREQ_EVENTFD, - vq->config.pfn*getpagesize(), 0 }; - - /* Create a zero-initialized eventfd. */ - vq->eventfd = eventfd(0, 0); - if (vq->eventfd < 0) - err(1, "Creating eventfd"); - args[2] = vq->eventfd; - - /* - * Attach an eventfd to this virtqueue: it will go off when the Guest - * does an LHCALL_NOTIFY for this vq. - */ - if (write(lguest_fd, &args, sizeof(args)) != 0) - err(1, "Attaching eventfd"); - - /* - * CLONE_VM: because it has to access the Guest memory, and SIGCHLD so - * we get a signal if it dies. - */ - vq->thread = clone(do_thread, stack + 32768, CLONE_VM | SIGCHLD, vq); - if (vq->thread == (pid_t)-1) - err(1, "Creating clone"); - - /* We close our local copy now the child has it. */ - close(vq->eventfd); -} - -static bool accepted_feature(struct device *dev, unsigned int bit) -{ - const u8 *features = get_feature_bits(dev) + dev->feature_len; - - if (dev->feature_len < bit / CHAR_BIT) - return false; - return features[bit / CHAR_BIT] & (1 << (bit % CHAR_BIT)); -} - -static void start_device(struct device *dev) -{ - unsigned int i; - struct virtqueue *vq; - - verbose("Device %s OK: offered", dev->name); - for (i = 0; i < dev->feature_len; i++) - verbose(" %02x", get_feature_bits(dev)[i]); - verbose(", accepted"); - for (i = 0; i < dev->feature_len; i++) - verbose(" %02x", get_feature_bits(dev) - [dev->feature_len+i]); - - dev->irq_on_empty = accepted_feature(dev, VIRTIO_F_NOTIFY_ON_EMPTY); - - for (vq = dev->vq; vq; vq = vq->next) { - if (vq->service) - create_thread(vq); - } - dev->running = true; -} - -static void cleanup_devices(void) -{ - struct device *dev; - - for (dev = devices.dev; dev; dev = dev->next) - reset_device(dev); - - /* If we saved off the original terminal settings, restore them now. */ - if (orig_term.c_lflag & (ISIG|ICANON|ECHO)) - tcsetattr(STDIN_FILENO, TCSANOW, &orig_term); -} - -/* When the Guest tells us they updated the status field, we handle it. */ -static void update_device_status(struct device *dev) -{ - /* A zero status is a reset, otherwise it's a set of flags. */ - if (dev->desc->status == 0) - reset_device(dev); - else if (dev->desc->status & VIRTIO_CONFIG_S_FAILED) { - warnx("Device %s configuration FAILED", dev->name); - if (dev->running) - reset_device(dev); - } else if (dev->desc->status & VIRTIO_CONFIG_S_DRIVER_OK) { - if (!dev->running) - start_device(dev); - } -} - -/*L:215 - * This is the generic routine we call when the Guest uses LHCALL_NOTIFY. In - * particular, it's used to notify us of device status changes during boot. - */ -static void handle_output(unsigned long addr) -{ - struct device *i; - - /* Check each device. */ - for (i = devices.dev; i; i = i->next) { - struct virtqueue *vq; - - /* - * Notifications to device descriptors mean they updated the - * device status. - */ - if (from_guest_phys(addr) == i->desc) { - update_device_status(i); - return; - } - - /* - * Devices *can* be used before status is set to DRIVER_OK. - * The original plan was that they would never do this: they - * would always finish setting up their status bits before - * actually touching the virtqueues. In practice, we allowed - * them to, and they do (eg. the disk probes for partition - * tables as part of initialization). - * - * If we see this, we start the device: once it's running, we - * expect the device to catch all the notifications. - */ - for (vq = i->vq; vq; vq = vq->next) { - if (addr != vq->config.pfn*getpagesize()) - continue; - if (i->running) - errx(1, "Notification on running %s", i->name); - /* This just calls create_thread() for each virtqueue */ - start_device(i); - return; - } - } - - /* - * Early console write is done using notify on a nul-terminated string - * in Guest memory. It's also great for hacking debugging messages - * into a Guest. - */ - if (addr >= guest_limit) - errx(1, "Bad NOTIFY %#lx", addr); - - write(STDOUT_FILENO, from_guest_phys(addr), - strnlen(from_guest_phys(addr), guest_limit - addr)); -} - -/*L:190 - * Device Setup - * - * All devices need a descriptor so the Guest knows it exists, and a "struct - * device" so the Launcher can keep track of it. We have common helper - * routines to allocate and manage them. - */ - -/* - * The layout of the device page is a "struct lguest_device_desc" followed by a - * number of virtqueue descriptors, then two sets of feature bits, then an - * array of configuration bytes. This routine returns the configuration - * pointer. - */ -static u8 *device_config(const struct device *dev) -{ - return (void *)(dev->desc + 1) - + dev->num_vq * sizeof(struct lguest_vqconfig) - + dev->feature_len * 2; -} - -/* - * This routine allocates a new "struct lguest_device_desc" from descriptor - * table page just above the Guest's normal memory. It returns a pointer to - * that descriptor. - */ -static struct lguest_device_desc *new_dev_desc(u16 type) -{ - struct lguest_device_desc d = { .type = type }; - void *p; - - /* Figure out where the next device config is, based on the last one. */ - if (devices.lastdev) - p = device_config(devices.lastdev) - + devices.lastdev->desc->config_len; - else - p = devices.descpage; - - /* We only have one page for all the descriptors. */ - if (p + sizeof(d) > (void *)devices.descpage + getpagesize()) - errx(1, "Too many devices"); - - /* p might not be aligned, so we memcpy in. */ - return memcpy(p, &d, sizeof(d)); -} - -/* - * Each device descriptor is followed by the description of its virtqueues. We - * specify how many descriptors the virtqueue is to have. - */ -static void add_virtqueue(struct device *dev, unsigned int num_descs, - void (*service)(struct virtqueue *)) -{ - unsigned int pages; - struct virtqueue **i, *vq = malloc(sizeof(*vq)); - void *p; - - /* First we need some memory for this virtqueue. */ - pages = (vring_size(num_descs, LGUEST_VRING_ALIGN) + getpagesize() - 1) - / getpagesize(); - p = get_pages(pages); - - /* Initialize the virtqueue */ - vq->next = NULL; - vq->last_avail_idx = 0; - vq->dev = dev; - - /* - * This is the routine the service thread will run, and its Process ID - * once it's running. - */ - vq->service = service; - vq->thread = (pid_t)-1; - - /* Initialize the configuration. */ - vq->config.num = num_descs; - vq->config.irq = devices.next_irq++; - vq->config.pfn = to_guest_phys(p) / getpagesize(); - - /* Initialize the vring. */ - vring_init(&vq->vring, num_descs, p, LGUEST_VRING_ALIGN); - - /* - * Append virtqueue to this device's descriptor. We use - * device_config() to get the end of the device's current virtqueues; - * we check that we haven't added any config or feature information - * yet, otherwise we'd be overwriting them. - */ - assert(dev->desc->config_len == 0 && dev->desc->feature_len == 0); - memcpy(device_config(dev), &vq->config, sizeof(vq->config)); - dev->num_vq++; - dev->desc->num_vq++; - - verbose("Virtqueue page %#lx\n", to_guest_phys(p)); - - /* - * Add to tail of list, so dev->vq is first vq, dev->vq->next is - * second. - */ - for (i = &dev->vq; *i; i = &(*i)->next); - *i = vq; -} - -/* - * The first half of the feature bitmask is for us to advertise features. The - * second half is for the Guest to accept features. - */ -static void add_feature(struct device *dev, unsigned bit) -{ - u8 *features = get_feature_bits(dev); - - /* We can't extend the feature bits once we've added config bytes */ - if (dev->desc->feature_len <= bit / CHAR_BIT) { - assert(dev->desc->config_len == 0); - dev->feature_len = dev->desc->feature_len = (bit/CHAR_BIT) + 1; - } - - features[bit / CHAR_BIT] |= (1 << (bit % CHAR_BIT)); -} - -/* - * This routine sets the configuration fields for an existing device's - * descriptor. It only works for the last device, but that's OK because that's - * how we use it. - */ -static void set_config(struct device *dev, unsigned len, const void *conf) -{ - /* Check we haven't overflowed our single page. */ - if (device_config(dev) + len > devices.descpage + getpagesize()) - errx(1, "Too many devices"); - - /* Copy in the config information, and store the length. */ - memcpy(device_config(dev), conf, len); - dev->desc->config_len = len; - - /* Size must fit in config_len field (8 bits)! */ - assert(dev->desc->config_len == len); -} - -/* - * This routine does all the creation and setup of a new device, including - * calling new_dev_desc() to allocate the descriptor and device memory. We - * don't actually start the service threads until later. - * - * See what I mean about userspace being boring? - */ -static struct device *new_device(const char *name, u16 type) -{ - struct device *dev = malloc(sizeof(*dev)); - - /* Now we populate the fields one at a time. */ - dev->desc = new_dev_desc(type); - dev->name = name; - dev->vq = NULL; - dev->feature_len = 0; - dev->num_vq = 0; - dev->running = false; - - /* - * Append to device list. Prepending to a single-linked list is - * easier, but the user expects the devices to be arranged on the bus - * in command-line order. The first network device on the command line - * is eth0, the first block device /dev/vda, etc. - */ - if (devices.lastdev) - devices.lastdev->next = dev; - else - devices.dev = dev; - devices.lastdev = dev; - - return dev; -} - -/* - * Our first setup routine is the console. It's a fairly simple device, but - * UNIX tty handling makes it uglier than it could be. - */ -static void setup_console(void) -{ - struct device *dev; - - /* If we can save the initial standard input settings... */ - if (tcgetattr(STDIN_FILENO, &orig_term) == 0) { - struct termios term = orig_term; - /* - * Then we turn off echo, line buffering and ^C etc: We want a - * raw input stream to the Guest. - */ - term.c_lflag &= ~(ISIG|ICANON|ECHO); - tcsetattr(STDIN_FILENO, TCSANOW, &term); - } - - dev = new_device("console", VIRTIO_ID_CONSOLE); - - /* We store the console state in dev->priv, and initialize it. */ - dev->priv = malloc(sizeof(struct console_abort)); - ((struct console_abort *)dev->priv)->count = 0; - - /* - * The console needs two virtqueues: the input then the output. When - * they put something the input queue, we make sure we're listening to - * stdin. When they put something in the output queue, we write it to - * stdout. - */ - add_virtqueue(dev, VIRTQUEUE_NUM, console_input); - add_virtqueue(dev, VIRTQUEUE_NUM, console_output); - - verbose("device %u: console\n", ++devices.device_num); -} -/*:*/ - -/*M:010 - * Inter-guest networking is an interesting area. Simplest is to have a - * --sharenet= option which opens or creates a named pipe. This can be - * used to send packets to another guest in a 1:1 manner. - * - * More sopisticated is to use one of the tools developed for project like UML - * to do networking. - * - * Faster is to do virtio bonding in kernel. Doing this 1:1 would be - * completely generic ("here's my vring, attach to your vring") and would work - * for any traffic. Of course, namespace and permissions issues need to be - * dealt with. A more sophisticated "multi-channel" virtio_net.c could hide - * multiple inter-guest channels behind one interface, although it would - * require some manner of hotplugging new virtio channels. - * - * Finally, we could implement a virtio network switch in the kernel. -:*/ - -static u32 str2ip(const char *ipaddr) -{ - unsigned int b[4]; - - if (sscanf(ipaddr, "%u.%u.%u.%u", &b[0], &b[1], &b[2], &b[3]) != 4) - errx(1, "Failed to parse IP address '%s'", ipaddr); - return (b[0] << 24) | (b[1] << 16) | (b[2] << 8) | b[3]; -} - -static void str2mac(const char *macaddr, unsigned char mac[6]) -{ - unsigned int m[6]; - if (sscanf(macaddr, "%02x:%02x:%02x:%02x:%02x:%02x", - &m[0], &m[1], &m[2], &m[3], &m[4], &m[5]) != 6) - errx(1, "Failed to parse mac address '%s'", macaddr); - mac[0] = m[0]; - mac[1] = m[1]; - mac[2] = m[2]; - mac[3] = m[3]; - mac[4] = m[4]; - mac[5] = m[5]; -} - -/* - * This code is "adapted" from libbridge: it attaches the Host end of the - * network device to the bridge device specified by the command line. - * - * This is yet another James Morris contribution (I'm an IP-level guy, so I - * dislike bridging), and I just try not to break it. - */ -static void add_to_bridge(int fd, const char *if_name, const char *br_name) -{ - int ifidx; - struct ifreq ifr; - - if (!*br_name) - errx(1, "must specify bridge name"); - - ifidx = if_nametoindex(if_name); - if (!ifidx) - errx(1, "interface %s does not exist!", if_name); - - strncpy(ifr.ifr_name, br_name, IFNAMSIZ); - ifr.ifr_name[IFNAMSIZ-1] = '\0'; - ifr.ifr_ifindex = ifidx; - if (ioctl(fd, SIOCBRADDIF, &ifr) < 0) - err(1, "can't add %s to bridge %s", if_name, br_name); -} - -/* - * This sets up the Host end of the network device with an IP address, brings - * it up so packets will flow, the copies the MAC address into the hwaddr - * pointer. - */ -static void configure_device(int fd, const char *tapif, u32 ipaddr) -{ - struct ifreq ifr; - struct sockaddr_in sin; - - memset(&ifr, 0, sizeof(ifr)); - strcpy(ifr.ifr_name, tapif); - - /* Don't read these incantations. Just cut & paste them like I did! */ - sin.sin_family = AF_INET; - sin.sin_addr.s_addr = htonl(ipaddr); - memcpy(&ifr.ifr_addr, &sin, sizeof(sin)); - if (ioctl(fd, SIOCSIFADDR, &ifr) != 0) - err(1, "Setting %s interface address", tapif); - ifr.ifr_flags = IFF_UP; - if (ioctl(fd, SIOCSIFFLAGS, &ifr) != 0) - err(1, "Bringing interface %s up", tapif); -} - -static int get_tun_device(char tapif[IFNAMSIZ]) -{ - struct ifreq ifr; - int netfd; - - /* Start with this zeroed. Messy but sure. */ - memset(&ifr, 0, sizeof(ifr)); - - /* - * We open the /dev/net/tun device and tell it we want a tap device. A - * tap device is like a tun device, only somehow different. To tell - * the truth, I completely blundered my way through this code, but it - * works now! - */ - netfd = open_or_die("/dev/net/tun", O_RDWR); - ifr.ifr_flags = IFF_TAP | IFF_NO_PI | IFF_VNET_HDR; - strcpy(ifr.ifr_name, "tap%d"); - if (ioctl(netfd, TUNSETIFF, &ifr) != 0) - err(1, "configuring /dev/net/tun"); - - if (ioctl(netfd, TUNSETOFFLOAD, - TUN_F_CSUM|TUN_F_TSO4|TUN_F_TSO6|TUN_F_TSO_ECN) != 0) - err(1, "Could not set features for tun device"); - - /* - * We don't need checksums calculated for packets coming in this - * device: trust us! - */ - ioctl(netfd, TUNSETNOCSUM, 1); - - memcpy(tapif, ifr.ifr_name, IFNAMSIZ); - return netfd; -} - -/*L:195 - * Our network is a Host<->Guest network. This can either use bridging or - * routing, but the principle is the same: it uses the "tun" device to inject - * packets into the Host as if they came in from a normal network card. We - * just shunt packets between the Guest and the tun device. - */ -static void setup_tun_net(char *arg) -{ - struct device *dev; - struct net_info *net_info = malloc(sizeof(*net_info)); - int ipfd; - u32 ip = INADDR_ANY; - bool bridging = false; - char tapif[IFNAMSIZ], *p; - struct virtio_net_config conf; - - net_info->tunfd = get_tun_device(tapif); - - /* First we create a new network device. */ - dev = new_device("net", VIRTIO_ID_NET); - dev->priv = net_info; - - /* Network devices need a recv and a send queue, just like console. */ - add_virtqueue(dev, VIRTQUEUE_NUM, net_input); - add_virtqueue(dev, VIRTQUEUE_NUM, net_output); - - /* - * We need a socket to perform the magic network ioctls to bring up the - * tap interface, connect to the bridge etc. Any socket will do! - */ - ipfd = socket(PF_INET, SOCK_DGRAM, IPPROTO_IP); - if (ipfd < 0) - err(1, "opening IP socket"); - - /* If the command line was --tunnet=bridge: do bridging. */ - if (!strncmp(BRIDGE_PFX, arg, strlen(BRIDGE_PFX))) { - arg += strlen(BRIDGE_PFX); - bridging = true; - } - - /* A mac address may follow the bridge name or IP address */ - p = strchr(arg, ':'); - if (p) { - str2mac(p+1, conf.mac); - add_feature(dev, VIRTIO_NET_F_MAC); - *p = '\0'; - } - - /* arg is now either an IP address or a bridge name */ - if (bridging) - add_to_bridge(ipfd, tapif, arg); - else - ip = str2ip(arg); - - /* Set up the tun device. */ - configure_device(ipfd, tapif, ip); - - add_feature(dev, VIRTIO_F_NOTIFY_ON_EMPTY); - /* Expect Guest to handle everything except UFO */ - add_feature(dev, VIRTIO_NET_F_CSUM); - add_feature(dev, VIRTIO_NET_F_GUEST_CSUM); - add_feature(dev, VIRTIO_NET_F_GUEST_TSO4); - add_feature(dev, VIRTIO_NET_F_GUEST_TSO6); - add_feature(dev, VIRTIO_NET_F_GUEST_ECN); - add_feature(dev, VIRTIO_NET_F_HOST_TSO4); - add_feature(dev, VIRTIO_NET_F_HOST_TSO6); - add_feature(dev, VIRTIO_NET_F_HOST_ECN); - /* We handle indirect ring entries */ - add_feature(dev, VIRTIO_RING_F_INDIRECT_DESC); - set_config(dev, sizeof(conf), &conf); - - /* We don't need the socket any more; setup is done. */ - close(ipfd); - - devices.device_num++; - - if (bridging) - verbose("device %u: tun %s attached to bridge: %s\n", - devices.device_num, tapif, arg); - else - verbose("device %u: tun %s: %s\n", - devices.device_num, tapif, arg); -} -/*:*/ - -/* This hangs off device->priv. */ -struct vblk_info { - /* The size of the file. */ - off64_t len; - - /* The file descriptor for the file. */ - int fd; - -}; - -/*L:210 - * The Disk - * - * The disk only has one virtqueue, so it only has one thread. It is really - * simple: the Guest asks for a block number and we read or write that position - * in the file. - * - * Before we serviced each virtqueue in a separate thread, that was unacceptably - * slow: the Guest waits until the read is finished before running anything - * else, even if it could have been doing useful work. - * - * We could have used async I/O, except it's reputed to suck so hard that - * characters actually go missing from your code when you try to use it. - */ -static void blk_request(struct virtqueue *vq) -{ - struct vblk_info *vblk = vq->dev->priv; - unsigned int head, out_num, in_num, wlen; - int ret; - u8 *in; - struct virtio_blk_outhdr *out; - struct iovec iov[vq->vring.num]; - off64_t off; - - /* - * Get the next request, where we normally wait. It triggers the - * interrupt to acknowledge previously serviced requests (if any). - */ - head = wait_for_vq_desc(vq, iov, &out_num, &in_num); - - /* - * Every block request should contain at least one output buffer - * (detailing the location on disk and the type of request) and one - * input buffer (to hold the result). - */ - if (out_num == 0 || in_num == 0) - errx(1, "Bad virtblk cmd %u out=%u in=%u", - head, out_num, in_num); - - out = convert(&iov[0], struct virtio_blk_outhdr); - in = convert(&iov[out_num+in_num-1], u8); - /* - * For historical reasons, block operations are expressed in 512 byte - * "sectors". - */ - off = out->sector * 512; - - /* - * In general the virtio block driver is allowed to try SCSI commands. - * It'd be nice if we supported eject, for example, but we don't. - */ - if (out->type & VIRTIO_BLK_T_SCSI_CMD) { - fprintf(stderr, "Scsi commands unsupported\n"); - *in = VIRTIO_BLK_S_UNSUPP; - wlen = sizeof(*in); - } else if (out->type & VIRTIO_BLK_T_OUT) { - /* - * Write - * - * Move to the right location in the block file. This can fail - * if they try to write past end. - */ - if (lseek64(vblk->fd, off, SEEK_SET) != off) - err(1, "Bad seek to sector %llu", out->sector); - - ret = writev(vblk->fd, iov+1, out_num-1); - verbose("WRITE to sector %llu: %i\n", out->sector, ret); - - /* - * Grr... Now we know how long the descriptor they sent was, we - * make sure they didn't try to write over the end of the block - * file (possibly extending it). - */ - if (ret > 0 && off + ret > vblk->len) { - /* Trim it back to the correct length */ - ftruncate64(vblk->fd, vblk->len); - /* Die, bad Guest, die. */ - errx(1, "Write past end %llu+%u", off, ret); - } - - wlen = sizeof(*in); - *in = (ret >= 0 ? VIRTIO_BLK_S_OK : VIRTIO_BLK_S_IOERR); - } else if (out->type & VIRTIO_BLK_T_FLUSH) { - /* Flush */ - ret = fdatasync(vblk->fd); - verbose("FLUSH fdatasync: %i\n", ret); - wlen = sizeof(*in); - *in = (ret >= 0 ? VIRTIO_BLK_S_OK : VIRTIO_BLK_S_IOERR); - } else { - /* - * Read - * - * Move to the right location in the block file. This can fail - * if they try to read past end. - */ - if (lseek64(vblk->fd, off, SEEK_SET) != off) - err(1, "Bad seek to sector %llu", out->sector); - - ret = readv(vblk->fd, iov+1, in_num-1); - verbose("READ from sector %llu: %i\n", out->sector, ret); - if (ret >= 0) { - wlen = sizeof(*in) + ret; - *in = VIRTIO_BLK_S_OK; - } else { - wlen = sizeof(*in); - *in = VIRTIO_BLK_S_IOERR; - } - } - - /* Finished that request. */ - add_used(vq, head, wlen); -} - -/*L:198 This actually sets up a virtual block device. */ -static void setup_block_file(const char *filename) -{ - struct device *dev; - struct vblk_info *vblk; - struct virtio_blk_config conf; - - /* Creat the device. */ - dev = new_device("block", VIRTIO_ID_BLOCK); - - /* The device has one virtqueue, where the Guest places requests. */ - add_virtqueue(dev, VIRTQUEUE_NUM, blk_request); - - /* Allocate the room for our own bookkeeping */ - vblk = dev->priv = malloc(sizeof(*vblk)); - - /* First we open the file and store the length. */ - vblk->fd = open_or_die(filename, O_RDWR|O_LARGEFILE); - vblk->len = lseek64(vblk->fd, 0, SEEK_END); - - /* We support FLUSH. */ - add_feature(dev, VIRTIO_BLK_F_FLUSH); - - /* Tell Guest how many sectors this device has. */ - conf.capacity = cpu_to_le64(vblk->len / 512); - - /* - * Tell Guest not to put in too many descriptors at once: two are used - * for the in and out elements. - */ - add_feature(dev, VIRTIO_BLK_F_SEG_MAX); - conf.seg_max = cpu_to_le32(VIRTQUEUE_NUM - 2); - - /* Don't try to put whole struct: we have 8 bit limit. */ - set_config(dev, offsetof(struct virtio_blk_config, geometry), &conf); - - verbose("device %u: virtblock %llu sectors\n", - ++devices.device_num, le64_to_cpu(conf.capacity)); -} - -/*L:211 - * Our random number generator device reads from /dev/random into the Guest's - * input buffers. The usual case is that the Guest doesn't want random numbers - * and so has no buffers although /dev/random is still readable, whereas - * console is the reverse. - * - * The same logic applies, however. - */ -struct rng_info { - int rfd; -}; - -static void rng_input(struct virtqueue *vq) -{ - int len; - unsigned int head, in_num, out_num, totlen = 0; - struct rng_info *rng_info = vq->dev->priv; - struct iovec iov[vq->vring.num]; - - /* First we need a buffer from the Guests's virtqueue. */ - head = wait_for_vq_desc(vq, iov, &out_num, &in_num); - if (out_num) - errx(1, "Output buffers in rng?"); - - /* - * Just like the console write, we loop to cover the whole iovec. - * In this case, short reads actually happen quite a bit. - */ - while (!iov_empty(iov, in_num)) { - len = readv(rng_info->rfd, iov, in_num); - if (len <= 0) - err(1, "Read from /dev/random gave %i", len); - iov_consume(iov, in_num, len); - totlen += len; - } - - /* Tell the Guest about the new input. */ - add_used(vq, head, totlen); -} - -/*L:199 - * This creates a "hardware" random number device for the Guest. - */ -static void setup_rng(void) -{ - struct device *dev; - struct rng_info *rng_info = malloc(sizeof(*rng_info)); - - /* Our device's privat info simply contains the /dev/random fd. */ - rng_info->rfd = open_or_die("/dev/random", O_RDONLY); - - /* Create the new device. */ - dev = new_device("rng", VIRTIO_ID_RNG); - dev->priv = rng_info; - - /* The device has one virtqueue, where the Guest places inbufs. */ - add_virtqueue(dev, VIRTQUEUE_NUM, rng_input); - - verbose("device %u: rng\n", devices.device_num++); -} -/* That's the end of device setup. */ - -/*L:230 Reboot is pretty easy: clean up and exec() the Launcher afresh. */ -static void __attribute__((noreturn)) restart_guest(void) -{ - unsigned int i; - - /* - * Since we don't track all open fds, we simply close everything beyond - * stderr. - */ - for (i = 3; i < FD_SETSIZE; i++) - close(i); - - /* Reset all the devices (kills all threads). */ - cleanup_devices(); - - execv(main_args[0], main_args); - err(1, "Could not exec %s", main_args[0]); -} - -/*L:220 - * Finally we reach the core of the Launcher which runs the Guest, serves - * its input and output, and finally, lays it to rest. - */ -static void __attribute__((noreturn)) run_guest(void) -{ - for (;;) { - unsigned long notify_addr; - int readval; - - /* We read from the /dev/lguest device to run the Guest. */ - readval = pread(lguest_fd, ¬ify_addr, - sizeof(notify_addr), cpu_id); - - /* One unsigned long means the Guest did HCALL_NOTIFY */ - if (readval == sizeof(notify_addr)) { - verbose("Notify on address %#lx\n", notify_addr); - handle_output(notify_addr); - /* ENOENT means the Guest died. Reading tells us why. */ - } else if (errno == ENOENT) { - char reason[1024] = { 0 }; - pread(lguest_fd, reason, sizeof(reason)-1, cpu_id); - errx(1, "%s", reason); - /* ERESTART means that we need to reboot the guest */ - } else if (errno == ERESTART) { - restart_guest(); - /* Anything else means a bug or incompatible change. */ - } else - err(1, "Running guest failed"); - } -} -/*L:240 - * This is the end of the Launcher. The good news: we are over halfway - * through! The bad news: the most fiendish part of the code still lies ahead - * of us. - * - * Are you ready? Take a deep breath and join me in the core of the Host, in - * "make Host". -:*/ - -static struct option opts[] = { - { "verbose", 0, NULL, 'v' }, - { "tunnet", 1, NULL, 't' }, - { "block", 1, NULL, 'b' }, - { "rng", 0, NULL, 'r' }, - { "initrd", 1, NULL, 'i' }, - { "username", 1, NULL, 'u' }, - { "chroot", 1, NULL, 'c' }, - { NULL }, -}; -static void usage(void) -{ - errx(1, "Usage: lguest [--verbose] " - "[--tunnet=(:|bridge::)\n" - "|--block=|--initrd=]...\n" - " vmlinux [args...]"); -} - -/*L:105 The main routine is where the real work begins: */ -int main(int argc, char *argv[]) -{ - /* Memory, code startpoint and size of the (optional) initrd. */ - unsigned long mem = 0, start, initrd_size = 0; - /* Two temporaries. */ - int i, c; - /* The boot information for the Guest. */ - struct boot_params *boot; - /* If they specify an initrd file to load. */ - const char *initrd_name = NULL; - - /* Password structure for initgroups/setres[gu]id */ - struct passwd *user_details = NULL; - - /* Directory to chroot to */ - char *chroot_path = NULL; - - /* Save the args: we "reboot" by execing ourselves again. */ - main_args = argv; - - /* - * First we initialize the device list. We keep a pointer to the last - * device, and the next interrupt number to use for devices (1: - * remember that 0 is used by the timer). - */ - devices.lastdev = NULL; - devices.next_irq = 1; - - /* We're CPU 0. In fact, that's the only CPU possible right now. */ - cpu_id = 0; - - /* - * We need to know how much memory so we can set up the device - * descriptor and memory pages for the devices as we parse the command - * line. So we quickly look through the arguments to find the amount - * of memory now. - */ - for (i = 1; i < argc; i++) { - if (argv[i][0] != '-') { - mem = atoi(argv[i]) * 1024 * 1024; - /* - * We start by mapping anonymous pages over all of - * guest-physical memory range. This fills it with 0, - * and ensures that the Guest won't be killed when it - * tries to access it. - */ - guest_base = map_zeroed_pages(mem / getpagesize() - + DEVICE_PAGES); - guest_limit = mem; - guest_max = mem + DEVICE_PAGES*getpagesize(); - devices.descpage = get_pages(1); - break; - } - } - - /* The options are fairly straight-forward */ - while ((c = getopt_long(argc, argv, "v", opts, NULL)) != EOF) { - switch (c) { - case 'v': - verbose = true; - break; - case 't': - setup_tun_net(optarg); - break; - case 'b': - setup_block_file(optarg); - break; - case 'r': - setup_rng(); - break; - case 'i': - initrd_name = optarg; - break; - case 'u': - user_details = getpwnam(optarg); - if (!user_details) - err(1, "getpwnam failed, incorrect username?"); - break; - case 'c': - chroot_path = optarg; - break; - default: - warnx("Unknown argument %s", argv[optind]); - usage(); - } - } - /* - * After the other arguments we expect memory and kernel image name, - * followed by command line arguments for the kernel. - */ - if (optind + 2 > argc) - usage(); - - verbose("Guest base is at %p\n", guest_base); - - /* We always have a console device */ - setup_console(); - - /* Now we load the kernel */ - start = load_kernel(open_or_die(argv[optind+1], O_RDONLY)); - - /* Boot information is stashed at physical address 0 */ - boot = from_guest_phys(0); - - /* Map the initrd image if requested (at top of physical memory) */ - if (initrd_name) { - initrd_size = load_initrd(initrd_name, mem); - /* - * These are the location in the Linux boot header where the - * start and size of the initrd are expected to be found. - */ - boot->hdr.ramdisk_image = mem - initrd_size; - boot->hdr.ramdisk_size = initrd_size; - /* The bootloader type 0xFF means "unknown"; that's OK. */ - boot->hdr.type_of_loader = 0xFF; - } - - /* - * The Linux boot header contains an "E820" memory map: ours is a - * simple, single region. - */ - boot->e820_entries = 1; - boot->e820_map[0] = ((struct e820entry) { 0, mem, E820_RAM }); - /* - * The boot header contains a command line pointer: we put the command - * line after the boot header. - */ - boot->hdr.cmd_line_ptr = to_guest_phys(boot + 1); - /* We use a simple helper to copy the arguments separated by spaces. */ - concat((char *)(boot + 1), argv+optind+2); - - /* Boot protocol version: 2.07 supports the fields for lguest. */ - boot->hdr.version = 0x207; - - /* The hardware_subarch value of "1" tells the Guest it's an lguest. */ - boot->hdr.hardware_subarch = 1; - - /* Tell the entry path not to try to reload segment registers. */ - boot->hdr.loadflags |= KEEP_SEGMENTS; - - /* - * We tell the kernel to initialize the Guest: this returns the open - * /dev/lguest file descriptor. - */ - tell_kernel(start); - - /* Ensure that we terminate if a device-servicing child dies. */ - signal(SIGCHLD, kill_launcher); - - /* If we exit via err(), this kills all the threads, restores tty. */ - atexit(cleanup_devices); - - /* If requested, chroot to a directory */ - if (chroot_path) { - if (chroot(chroot_path) != 0) - err(1, "chroot(\"%s\") failed", chroot_path); - - if (chdir("/") != 0) - err(1, "chdir(\"/\") failed"); - - verbose("chroot done\n"); - } - - /* If requested, drop privileges */ - if (user_details) { - uid_t u; - gid_t g; - - u = user_details->pw_uid; - g = user_details->pw_gid; - - if (initgroups(user_details->pw_name, g) != 0) - err(1, "initgroups failed"); - - if (setresgid(g, g, g) != 0) - err(1, "setresgid failed"); - - if (setresuid(u, u, u) != 0) - err(1, "setresuid failed"); - - verbose("Dropping privileges completed\n"); - } - - /* Finally, run the Guest. This doesn't return. */ - run_guest(); -} -/*:*/ - -/*M:999 - * Mastery is done: you now know everything I do. - * - * But surely you have seen code, features and bugs in your wanderings which - * you now yearn to attack? That is the real game, and I look forward to you - * patching and forking lguest into the Your-Name-Here-visor. - * - * Farewell, and good coding! - * Rusty Russell. - */ diff --git a/Documentation/lguest/lguest.txt b/Documentation/lguest/lguest.txt deleted file mode 100644 index dad9997..0000000 --- a/Documentation/lguest/lguest.txt +++ /dev/null @@ -1,128 +0,0 @@ - __ - (___()'`; Rusty's Remarkably Unreliable Guide to Lguest - /, /` - or, A Young Coder's Illustrated Hypervisor - \\"--\\ http://lguest.ozlabs.org - -Lguest is designed to be a minimal 32-bit x86 hypervisor for the Linux kernel, -for Linux developers and users to experiment with virtualization with the -minimum of complexity. Nonetheless, it should have sufficient features to -make it useful for specific tasks, and, of course, you are encouraged to fork -and enhance it (see drivers/lguest/README). - -Features: - -- Kernel module which runs in a normal kernel. -- Simple I/O model for communication. -- Simple program to create new guests. -- Logo contains cute puppies: http://lguest.ozlabs.org - -Developer features: - -- Fun to hack on. -- No ABI: being tied to a specific kernel anyway, you can change anything. -- Many opportunities for improvement or feature implementation. - -Running Lguest: - -- The easiest way to run lguest is to use same kernel as guest and host. - You can configure them differently, but usually it's easiest not to. - - You will need to configure your kernel with the following options: - - "General setup": - "Prompt for development and/or incomplete code/drivers" = Y - (CONFIG_EXPERIMENTAL=y) - - "Processor type and features": - "Paravirtualized guest support" = Y - "Lguest guest support" = Y - "High Memory Support" = off/4GB - "Alignment value to which kernel should be aligned" = 0x100000 - (CONFIG_PARAVIRT=y, CONFIG_LGUEST_GUEST=y, CONFIG_HIGHMEM64G=n and - CONFIG_PHYSICAL_ALIGN=0x100000) - - "Device Drivers": - "Block devices" - "Virtio block driver (EXPERIMENTAL)" = M/Y - "Network device support" - "Universal TUN/TAP device driver support" = M/Y - "Virtio network driver (EXPERIMENTAL)" = M/Y - (CONFIG_VIRTIO_BLK=m, CONFIG_VIRTIO_NET=m and CONFIG_TUN=m) - - "Virtualization" - "Linux hypervisor example code" = M/Y - (CONFIG_LGUEST=m) - -- A tool called "lguest" is available in this directory: type "make" - to build it. If you didn't build your kernel in-tree, use "make - O=". - -- Create or find a root disk image. There are several useful ones - around, such as the xm-test tiny root image at - http://xm-test.xensource.com/ramdisks/initrd-1.1-i386.img - - For more serious work, I usually use a distribution ISO image and - install it under qemu, then make multiple copies: - - dd if=/dev/zero of=rootfile bs=1M count=2048 - qemu -cdrom image.iso -hda rootfile -net user -net nic -boot d - - Make sure that you install a getty on /dev/hvc0 if you want to log in on the - console! - -- "modprobe lg" if you built it as a module. - -- Run an lguest as root: - - Documentation/lguest/lguest 64 vmlinux --tunnet=192.168.19.1 --block=rootfile root=/dev/vda - - Explanation: - 64: the amount of memory to use, in MB. - - vmlinux: the kernel image found in the top of your build directory. You - can also use a standard bzImage. - - --tunnet=192.168.19.1: configures a "tap" device for networking with this - IP address. - - --block=rootfile: a file or block device which becomes /dev/vda - inside the guest. - - root=/dev/vda: this (and anything else on the command line) are - kernel boot parameters. - -- Configuring networking. I usually have the host masquerade, using - "iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE" and "echo 1 > - /proc/sys/net/ipv4/ip_forward". In this example, I would configure - eth0 inside the guest at 192.168.19.2. - - Another method is to bridge the tap device to an external interface - using --tunnet=bridge:, and perhaps run dhcp on the guest - to obtain an IP address. The bridge needs to be configured first: - this option simply adds the tap interface to it. - - A simple example on my system: - - ifconfig eth0 0.0.0.0 - brctl addbr lg0 - ifconfig lg0 up - brctl addif lg0 eth0 - dhclient lg0 - - Then use --tunnet=bridge:lg0 when launching the guest. - - See: - - http://www.linuxfoundation.org/collaborate/workgroups/networking/bridge - - for general information on how to get bridging to work. - -- Random number generation. Using the --rng option will provide a - /dev/hwrng in the guest that will read from the host's /dev/random. - Use this option in conjunction with rng-tools (see ../hw_random.txt) - to provide entropy to the guest kernel's /dev/random. - -There is a helpful mailing list at http://ozlabs.org/mailman/listinfo/lguest - -Good luck! -Rusty Russell rusty@rustcorp.com.au. diff --git a/Documentation/uml/UserModeLinux-HOWTO.txt b/Documentation/uml/UserModeLinux-HOWTO.txt deleted file mode 100644 index 9b7e190..0000000 --- a/Documentation/uml/UserModeLinux-HOWTO.txt +++ /dev/null @@ -1,4579 +0,0 @@ - User Mode Linux HOWTO - User Mode Linux Core Team - Mon Nov 18 14:16:16 EST 2002 - - This document describes the use and abuse of Jeff Dike's User Mode - Linux: a port of the Linux kernel as a normal Intel Linux process. - ______________________________________________________________________ - - Table of Contents - - 1. Introduction - - 1.1 How is User Mode Linux Different? - 1.2 Why Would I Want User Mode Linux? - - 2. Compiling the kernel and modules - - 2.1 Compiling the kernel - 2.2 Compiling and installing kernel modules - 2.3 Compiling and installing uml_utilities - - 3. Running UML and logging in - - 3.1 Running UML - 3.2 Logging in - 3.3 Examples - - 4. UML on 2G/2G hosts - - 4.1 Introduction - 4.2 The problem - 4.3 The solution - - 5. Setting up serial lines and consoles - - 5.1 Specifying the device - 5.2 Specifying the channel - 5.3 Examples - - 6. Setting up the network - - 6.1 General setup - 6.2 Userspace daemons - 6.3 Specifying ethernet addresses - 6.4 UML interface setup - 6.5 Multicast - 6.6 TUN/TAP with the uml_net helper - 6.7 TUN/TAP with a preconfigured tap device - 6.8 Ethertap - 6.9 The switch daemon - 6.10 Slip - 6.11 Slirp - 6.12 pcap - 6.13 Setting up the host yourself - - 7. Sharing Filesystems between Virtual Machines - - 7.1 A warning - 7.2 Using layered block devices - 7.3 Note! - 7.4 Another warning - 7.5 uml_moo : Merging a COW file with its backing file - - 8. Creating filesystems - - 8.1 Create the filesystem file - 8.2 Assign the file to a UML device - 8.3 Creating and mounting the filesystem - - 9. Host file access - - 9.1 Using hostfs - 9.2 hostfs as the root filesystem - 9.3 Building hostfs - - 10. The Management Console - 10.1 version - 10.2 halt and reboot - 10.3 config - 10.4 remove - 10.5 sysrq - 10.6 help - 10.7 cad - 10.8 stop - 10.9 go - - 11. Kernel debugging - - 11.1 Starting the kernel under gdb - 11.2 Examining sleeping processes - 11.3 Running ddd on UML - 11.4 Debugging modules - 11.5 Attaching gdb to the kernel - 11.6 Using alternate debuggers - - 12. Kernel debugging examples - - 12.1 The case of the hung fsck - 12.2 Episode 2: The case of the hung fsck - - 13. What to do when UML doesn't work - - 13.1 Strange compilation errors when you build from source - 13.2 (obsolete) - 13.3 A variety of panics and hangs with /tmp on a reiserfs filesystem - 13.4 The compile fails with errors about conflicting types for 'open', 'dup', and 'waitpid' - 13.5 UML doesn't work when /tmp is an NFS filesystem - 13.6 UML hangs on boot when compiled with gprof support - 13.7 syslogd dies with a SIGTERM on startup - 13.8 TUN/TAP networking doesn't work on a 2.4 host - 13.9 You can network to the host but not to other machines on the net - 13.10 I have no root and I want to scream - 13.11 UML build conflict between ptrace.h and ucontext.h - 13.12 The UML BogoMips is exactly half the host's BogoMips - 13.13 When you run UML, it immediately segfaults - 13.14 xterms appear, then immediately disappear - 13.15 Any other panic, hang, or strange behavior - - 14. Diagnosing Problems - - 14.1 Case 1 : Normal kernel panics - 14.2 Case 2 : Tracing thread panics - 14.3 Case 3 : Tracing thread panics caused by other threads - 14.4 Case 4 : Hangs - - 15. Thanks - - 15.1 Code and Documentation - 15.2 Flushing out bugs - 15.3 Buglets and clean-ups - 15.4 Case Studies - 15.5 Other contributions - - - ______________________________________________________________________ - - 11.. IInnttrroodduuccttiioonn - - Welcome to User Mode Linux. It's going to be fun. - - - - 11..11.. HHooww iiss UUsseerr MMooddee LLiinnuuxx DDiiffffeerreenntt?? - - Normally, the Linux Kernel talks straight to your hardware (video - card, keyboard, hard drives, etc), and any programs which run ask the - kernel to operate the hardware, like so: - - - - +-----------+-----------+----+ - | Process 1 | Process 2 | ...| - +-----------+-----------+----+ - | Linux Kernel | - +----------------------------+ - | Hardware | - +----------------------------+ - - - - - The User Mode Linux Kernel is different; instead of talking to the - hardware, it talks to a `real' Linux kernel (called the `host kernel' - from now on), like any other program. Programs can then run inside - User-Mode Linux as if they were running under a normal kernel, like - so: - - - - +----------------+ - | Process 2 | ...| - +-----------+----------------+ - | Process 1 | User-Mode Linux| - +----------------------------+ - | Linux Kernel | - +----------------------------+ - | Hardware | - +----------------------------+ - - - - - - 11..22.. WWhhyy WWoouulldd II WWaanntt UUsseerr MMooddee LLiinnuuxx?? - - - 1. If User Mode Linux crashes, your host kernel is still fine. - - 2. You can run a usermode kernel as a non-root user. - - 3. You can debug the User Mode Linux like any normal process. - - 4. You can run gprof (profiling) and gcov (coverage testing). - - 5. You can play with your kernel without breaking things. - - 6. You can use it as a sandbox for testing new apps. - - 7. You can try new development kernels safely. - - 8. You can run different distributions simultaneously. - - 9. It's extremely fun. - - - - - - 22.. CCoommppiilliinngg tthhee kkeerrnneell aanndd mmoodduulleess - - - - - 22..11.. CCoommppiilliinngg tthhee kkeerrnneell - - - Compiling the user mode kernel is just like compiling any other - kernel. Let's go through the steps, using 2.4.0-prerelease (current - as of this writing) as an example: - - - 1. Download the latest UML patch from - - the download page - . - - - 3. Make a directory and unpack the kernel into it. - - - - host% - mkdir ~/uml - - - - - - - host% - cd ~/uml - - - - - - - host% - tar -xzvf linux-2.4.0-prerelease.tar.bz2 - - - - - - - 4. Apply the patch using - - - - host% - cd ~/uml/linux - - - - host% - bzcat uml-patch-2.4.0-prerelease.bz2 | patch -p1 - - - - - - - 5. Run your favorite config; `make xconfig ARCH=um' is the most - convenient. `make config ARCH=um' and 'make menuconfig ARCH=um' - will work as well. The defaults will give you a useful kernel. If - you want to change something, go ahead, it probably won't hurt - anything. - - - Note: If the host is configured with a 2G/2G address space split - rather than the usual 3G/1G split, then the packaged UML binaries - will not run. They will immediately segfault. See ``UML on 2G/2G - hosts'' for the scoop on running UML on your system. - - - - 6. Finish with `make linux ARCH=um': the result is a file called - `linux' in the top directory of your source tree. - - Make sure that you don't build this kernel in /usr/src/linux. On some - distributions, /usr/include/asm is a link into this pool. The user- - mode build changes the other end of that link, and things that include - stop compiling. - - The sources are also available from cvs at the project's cvs page, - which has directions on getting the sources. You can also browse the - CVS pool from there. - - If you get the CVS sources, you will have to check them out into an - empty directory. You will then have to copy each file into the - corresponding directory in the appropriate kernel pool. - - If you don't have the latest kernel pool, you can get the - corresponding user-mode sources with - - - host% cvs co -r v_2_3_x linux - - - - - where 'x' is the version in your pool. Note that you will not get the - bug fixes and enhancements that have gone into subsequent releases. - - - 22..22.. CCoommppiilliinngg aanndd iinnssttaalllliinngg kkeerrnneell mmoodduulleess - - UML modules are built in the same way as the native kernel (with the - exception of the 'ARCH=um' that you always need for UML): - - - host% make modules ARCH=um - - - - - Any modules that you want to load into this kernel need to be built in - the user-mode pool. Modules from the native kernel won't work. - - You can install them by using ftp or something to copy them into the - virtual machine and dropping them into /lib/modules/`uname -r`. - - You can also get the kernel build process to install them as follows: - - 1. with the kernel not booted, mount the root filesystem in the top - level of the kernel pool: - - - host% mount root_fs mnt -o loop - - - - - - - 2. run - - - host% - make modules_install INSTALL_MOD_PATH=`pwd`/mnt ARCH=um - - - - - - - 3. unmount the filesystem - - - host% umount mnt - - - - - - - 4. boot the kernel on it - - - When the system is booted, you can use insmod as usual to get the - modules into the kernel. A number of things have been loaded into UML - as modules, especially filesystems and network protocols and filters, - so most symbols which need to be exported probably already are. - However, if you do find symbols that need exporting, let us - know, and - they'll be "taken care of". - - - - 22..33.. CCoommppiilliinngg aanndd iinnssttaalllliinngg uummll__uuttiilliittiieess - - Many features of the UML kernel require a user-space helper program, - so a uml_utilities package is distributed separately from the kernel - patch which provides these helpers. Included within this is: - - +o port-helper - Used by consoles which connect to xterms or ports - - +o tunctl - Configuration tool to create and delete tap devices - - +o uml_net - Setuid binary for automatic tap device configuration - - +o uml_switch - User-space virtual switch required for daemon - transport - - The uml_utilities tree is compiled with: - - - host# - make && make install - - - - - Note that UML kernel patches may require a specific version of the - uml_utilities distribution. If you don't keep up with the mailing - lists, ensure that you have the latest release of uml_utilities if you - are experiencing problems with your UML kernel, particularly when - dealing with consoles or command-line switches to the helper programs - - - - - - - - - 33.. RRuunnnniinngg UUMMLL aanndd llooggggiinngg iinn - - - - 33..11.. RRuunnnniinngg UUMMLL - - It runs on 2.2.15 or later, and all 2.4 kernels. - - - Booting UML is straightforward. Simply run 'linux': it will try to - mount the file `root_fs' in the current directory. You do not need to - run it as root. If your root filesystem is not named `root_fs', then - you need to put a `ubd0=root_fs_whatever' switch on the linux command - line. - - - You will need a filesystem to boot UML from. There are a number - available for download from here . There are also several tools - which can be - used to generate UML-compatible filesystem images from media. - The kernel will boot up and present you with a login prompt. - - - Note: If the host is configured with a 2G/2G address space split - rather than the usual 3G/1G split, then the packaged UML binaries will - not run. They will immediately segfault. See ``UML on 2G/2G hosts'' - for the scoop on running UML on your system. - - - - 33..22.. LLooggggiinngg iinn - - - - The prepackaged filesystems have a root account with password 'root' - and a user account with password 'user'. The login banner will - generally tell you how to log in. So, you log in and you will find - yourself inside a little virtual machine. Our filesystems have a - variety of commands and utilities installed (and it is fairly easy to - add more), so you will have a lot of tools with which to poke around - the system. - - There are a couple of other ways to log in: - - +o On a virtual console - - - - Each virtual console that is configured (i.e. the device exists in - /dev and /etc/inittab runs a getty on it) will come up in its own - xterm. If you get tired of the xterms, read ``Setting up serial - lines and consoles'' to see how to attach the consoles to - something else, like host ptys. - - - - +o Over the serial line - - - In the boot output, find a line that looks like: - - - - serial line 0 assigned pty /dev/ptyp1 - - - - - Attach your favorite terminal program to the corresponding tty. I.e. - for minicom, the command would be - - - host% minicom -o -p /dev/ttyp1 - - - - - - - +o Over the net - - - If the network is running, then you can telnet to the virtual - machine and log in to it. See ``Setting up the network'' to learn - about setting up a virtual network. - - When you're done using it, run halt, and the kernel will bring itself - down and the process will exit. - - - 33..33.. EExxaammpplleess - - Here are some examples of UML in action: - - +o A login session - - +o A virtual network - - - - - - - - 44.. UUMMLL oonn 22GG//22GG hhoossttss - - - - - 44..11.. IInnttrroodduuccttiioonn - - - Most Linux machines are configured so that the kernel occupies the - upper 1G (0xc0000000 - 0xffffffff) of the 4G address space and - processes use the lower 3G (0x00000000 - 0xbfffffff). However, some - machine are configured with a 2G/2G split, with the kernel occupying - the upper 2G (0x80000000 - 0xffffffff) and processes using the lower - 2G (0x00000000 - 0x7fffffff). - - - - - 44..22.. TThhee pprroobblleemm - - - The prebuilt UML binaries on this site will not run on 2G/2G hosts - because UML occupies the upper .5G of the 3G process address space - (0xa0000000 - 0xbfffffff). Obviously, on 2G/2G hosts, this is right - in the middle of the kernel address space, so UML won't even load - it - will immediately segfault. - - - - - 44..33.. TThhee ssoolluuttiioonn - - - The fix for this is to rebuild UML from source after enabling - CONFIG_HOST_2G_2G (under 'General Setup'). This will cause UML to - load itself in the top .5G of that smaller process address space, - where it will run fine. See ``Compiling the kernel and modules'' if - you need help building UML from source. - - - - - - - - - - - 55.. SSeettttiinngg uupp sseerriiaall lliinneess aanndd ccoonnssoolleess - - - It is possible to attach UML serial lines and consoles to many types - of host I/O channels by specifying them on the command line. - - - You can attach them to host ptys, ttys, file descriptors, and ports. - This allows you to do things like - - +o have a UML console appear on an unused host console, - - +o hook two virtual machines together by having one attach to a pty - and having the other attach to the corresponding tty - - +o make a virtual machine accessible from the net by attaching a - console to a port on the host. - - - The general format of the command line option is device=channel. - - - - 55..11.. SSppeecciiffyyiinngg tthhee ddeevviiccee - - Devices are specified with "con" or "ssl" (console or serial line, - respectively), optionally with a device number if you are talking - about a specific device. - - - Using just "con" or "ssl" describes all of the consoles or serial - lines. If you want to talk about console #3 or serial line #10, they - would be "con3" and "ssl10", respectively. - - - A specific device name will override a less general "con=" or "ssl=". - So, for example, you can assign a pty to each of the serial lines - except for the first two like this: - - - ssl=pty ssl0=tty:/dev/tty0 ssl1=tty:/dev/tty1 - - - - - The specificity of the device name is all that matters; order on the - command line is irrelevant. - - - - 55..22.. SSppeecciiffyyiinngg tthhee cchhaannnneell - - There are a number of different types of channels to attach a UML - device to, each with a different way of specifying exactly what to - attach to. - - +o pseudo-terminals - device=pty pts terminals - device=pts - - - This will cause UML to allocate a free host pseudo-terminal for the - device. The terminal that it got will be announced in the boot - log. You access it by attaching a terminal program to the - corresponding tty: - - +o screen /dev/pts/n - - +o screen /dev/ttyxx - - +o minicom -o -p /dev/ttyxx - minicom seems not able to handle pts - devices - - +o kermit - start it up, 'open' the device, then 'connect' - - - - - - +o terminals - device=tty:tty device file - - - This will make UML attach the device to the specified tty (i.e - - - con1=tty:/dev/tty3 - - - - - will attach UML's console 1 to the host's /dev/tty3). If the tty that - you specify is the slave end of a tty/pty pair, something else must - have already opened the corresponding pty in order for this to work. - - - - - - +o xterms - device=xterm - - - UML will run an xterm and the device will be attached to it. - - - - - - +o Port - device=port:port number - - - This will attach the UML devices to the specified host port. - Attaching console 1 to the host's port 9000 would be done like - this: - - - con1=port:9000 - - - - - Attaching all the serial lines to that port would be done similarly: - - - ssl=port:9000 - - - - - You access these devices by telnetting to that port. Each active tel- - net session gets a different device. If there are more telnets to a - port than UML devices attached to it, then the extra telnet sessions - will block until an existing telnet detaches, or until another device - becomes active (i.e. by being activated in /etc/inittab). - - This channel has the advantage that you can both attach multiple UML - devices to it and know how to access them without reading the UML boot - log. It is also unique in allowing access to a UML from remote - machines without requiring that the UML be networked. This could be - useful in allowing public access to UMLs because they would be - accessible from the net, but wouldn't need any kind of network - filtering or access control because they would have no network access. - - - If you attach the main console to a portal, then the UML boot will - appear to hang. In reality, it's waiting for a telnet to connect, at - which point the boot will proceed. - - - - - - +o already-existing file descriptors - device=file descriptor - - - If you set up a file descriptor on the UML command line, you can - attach a UML device to it. This is most commonly used to put the - main console back on stdin and stdout after assigning all the other - consoles to something else: - - - con0=fd:0,fd:1 con=pts - - - - - - - - - +o Nothing - device=null - - - This allows the device to be opened, in contrast to 'none', but - reads will block, and writes will succeed and the data will be - thrown out. - - - - - - +o None - device=none - - - This causes the device to disappear. - - - - You can also specify different input and output channels for a device - by putting a comma between them: - - - ssl3=tty:/dev/tty2,xterm - - - - - will cause serial line 3 to accept input on the host's /dev/tty3 and - display output on an xterm. That's a silly example - the most common - use of this syntax is to reattach the main console to stdin and stdout - as shown above. - - - If you decide to move the main console away from stdin/stdout, the - initial boot output will appear in the terminal that you're running - UML in. However, once the console driver has been officially - initialized, then the boot output will start appearing wherever you - specified that console 0 should be. That device will receive all - subsequent output. - - - - 55..33.. EExxaammpplleess - - There are a number of interesting things you can do with this - capability. - - - First, this is how you get rid of those bleeding console xterms by - attaching them to host ptys: - - - con=pty con0=fd:0,fd:1 - - - - - This will make a UML console take over an unused host virtual console, - so that when you switch to it, you will see the UML login prompt - rather than the host login prompt: - - - con1=tty:/dev/tty6 - - - - - You can attach two virtual machines together with what amounts to a - serial line as follows: - - Run one UML with a serial line attached to a pty - - - - ssl1=pty - - - - - Look at the boot log to see what pty it got (this example will assume - that it got /dev/ptyp1). - - Boot the other UML with a serial line attached to the corresponding - tty - - - - ssl1=tty:/dev/ttyp1 - - - - - Log in, make sure that it has no getty on that serial line, attach a - terminal program like minicom to it, and you should see the login - prompt of the other virtual machine. - - - 66.. SSeettttiinngg uupp tthhee nneettwwoorrkk - - - - This page describes how to set up the various transports and to - provide a UML instance with network access to the host, other machines - on the local net, and the rest of the net. - - - As of 2.4.5, UML networking has been completely redone to make it much - easier to set up, fix bugs, and add new features. - - - There is a new helper, uml_net, which does the host setup that - requires root privileges. - - - There are currently five transport types available for a UML virtual - machine to exchange packets with other hosts: - - +o ethertap - - +o TUN/TAP - - +o Multicast - - +o a switch daemon - - +o slip - - +o slirp - - +o pcap - - The TUN/TAP, ethertap, slip, and slirp transports allow a UML - instance to exchange packets with the host. They may be directed - to the host or the host may just act as a router to provide access - to other physical or virtual machines. - - - The pcap transport is a synthetic read-only interface, using the - libpcap binary to collect packets from interfaces on the host and - filter them. This is useful for building preconfigured traffic - monitors or sniffers. - - - The daemon and multicast transports provide a completely virtual - network to other virtual machines. This network is completely - disconnected from the physical network unless one of the virtual - machines on it is acting as a gateway. - - - With so many host transports, which one should you use? Here's when - you should use each one: - - +o ethertap - if you want access to the host networking and it is - running 2.2 - - +o TUN/TAP - if you want access to the host networking and it is - running 2.4. Also, the TUN/TAP transport is able to use a - preconfigured device, allowing it to avoid using the setuid uml_net - helper, which is a security advantage. - - +o Multicast - if you want a purely virtual network and you don't want - to set up anything but the UML - - +o a switch daemon - if you want a purely virtual network and you - don't mind running the daemon in order to get somewhat better - performance - - +o slip - there is no particular reason to run the slip backend unless - ethertap and TUN/TAP are just not available for some reason - - +o slirp - if you don't have root access on the host to setup - networking, or if you don't want to allocate an IP to your UML - - +o pcap - not much use for actual network connectivity, but great for - monitoring traffic on the host - - Ethertap is available on 2.4 and works fine. TUN/TAP is preferred - to it because it has better performance and ethertap is officially - considered obsolete in 2.4. Also, the root helper only needs to - run occasionally for TUN/TAP, rather than handling every packet, as - it does with ethertap. This is a slight security advantage since - it provides fewer opportunities for a nasty UML user to somehow - exploit the helper's root privileges. - - - 66..11.. GGeenneerraall sseettuupp - - First, you must have the virtual network enabled in your UML. If are - running a prebuilt kernel from this site, everything is already - enabled. If you build the kernel yourself, under the "Network device - support" menu, enable "Network device support", and then the three - transports. - - - The next step is to provide a network device to the virtual machine. - This is done by describing it on the kernel command line. - - The general format is - - - eth = , - - - - - For example, a virtual ethernet device may be attached to a host - ethertap device as follows: - - - eth0=ethertap,tap0,fe:fd:0:0:0:1,192.168.0.254 - - - - - This sets up eth0 inside the virtual machine to attach itself to the - host /dev/tap0, assigns it an ethernet address, and assigns the host - tap0 interface an IP address. - - - - Note that the IP address you assign to the host end of the tap device - must be different than the IP you assign to the eth device inside UML. - If you are short on IPs and don't want to consume two per UML, then - you can reuse the host's eth IP address for the host ends of the tap - devices. Internally, the UMLs must still get unique IPs for their eth - devices. You can also give the UMLs non-routable IPs (192.168.x.x or - 10.x.x.x) and have the host masquerade them. This will let outgoing - connections work, but incoming connections won't without more work, - such as port forwarding from the host. - Also note that when you configure the host side of an interface, it is - only acting as a gateway. It will respond to pings sent to it - locally, but is not useful to do that since it's a host interface. - You are not talking to the UML when you ping that interface and get a - response. - - - You can also add devices to a UML and remove them at runtime. See the - ``The Management Console'' page for details. - - - The sections below describe this in more detail. - - - Once you've decided how you're going to set up the devices, you boot - UML, log in, configure the UML side of the devices, and set up routes - to the outside world. At that point, you will be able to talk to any - other machines, physical or virtual, on the net. - - - If ifconfig inside UML fails and the network refuses to come up, run - tell you what went wrong. - - - - 66..22.. UUsseerrssppaaccee ddaaeemmoonnss - - You will likely need the setuid helper, or the switch daemon, or both. - They are both installed with the RPM and deb, so if you've installed - either, you can skip the rest of this section. - - - If not, then you need to check them out of CVS, build them, and - install them. The helper is uml_net, in CVS /tools/uml_net, and the - daemon is uml_switch, in CVS /tools/uml_router. They are both built - with a plain 'make'. Both need to be installed in a directory that's - in your path - /usr/bin is recommend. On top of that, uml_net needs - to be setuid root. - - - - 66..33.. SSppeecciiffyyiinngg eetthheerrnneett aaddddrreesssseess - - Below, you will see that the TUN/TAP, ethertap, and daemon interfaces - allow you to specify hardware addresses for the virtual ethernet - devices. This is generally not necessary. If you don't have a - specific reason to do it, you probably shouldn't. If one is not - specified on the command line, the driver will assign one based on the - device IP address. It will provide the address fe:fd:nn:nn:nn:nn - where nn.nn.nn.nn is the device IP address. This is nearly always - sufficient to guarantee a unique hardware address for the device. A - couple of exceptions are: - - +o Another set of virtual ethernet devices are on the same network and - they are assigned hardware addresses using a different scheme which - may conflict with the UML IP address-based scheme - - +o You aren't going to use the device for IP networking, so you don't - assign the device an IP address - - If you let the driver provide the hardware address, you should make - sure that the device IP address is known before the interface is - brought up. So, inside UML, this will guarantee that: - - - - UML# - ifconfig eth0 192.168.0.250 up - - - - - If you decide to assign the hardware address yourself, make sure that - the first byte of the address is even. Addresses with an odd first - byte are broadcast addresses, which you don't want assigned to a - device. - - - - 66..44.. UUMMLL iinntteerrffaaccee sseettuupp - - Once the network devices have been described on the command line, you - should boot UML and log in. - - - The first thing to do is bring the interface up: - - - UML# ifconfig ethn ip-address up - - - - - You should be able to ping the host at this point. - - - To reach the rest of the world, you should set a default route to the - host: - - - UML# route add default gw host ip - - - - - Again, with host ip of 192.168.0.4: - - - UML# route add default gw 192.168.0.4 - - - - - This page used to recommend setting a network route to your local net. - This is wrong, because it will cause UML to try to figure out hardware - addresses of the local machines by arping on the interface to the - host. Since that interface is basically a single strand of ethernet - with two nodes on it (UML and the host) and arp requests don't cross - networks, they will fail to elicit any responses. So, what you want - is for UML to just blindly throw all packets at the host and let it - figure out what to do with them, which is what leaving out the network - route and adding the default route does. - - - Note: If you can't communicate with other hosts on your physical - ethernet, it's probably because of a network route that's - automatically set up. If you run 'route -n' and see a route that - looks like this: - - - - - Destination Gateway Genmask Flags Metric Ref Use Iface - 192.168.0.0 0.0.0.0 255.255.255.0 U 0 0 0 eth0 - - - - - with a mask that's not 255.255.255.255, then replace it with a route - to your host: - - - UML# - route del -net 192.168.0.0 dev eth0 netmask 255.255.255.0 - - - - - - - UML# - route add -host 192.168.0.4 dev eth0 - - - - - This, plus the default route to the host, will allow UML to exchange - packets with any machine on your ethernet. - - - - 66..55.. MMuullttiiccaasstt - - The simplest way to set up a virtual network between multiple UMLs is - to use the mcast transport. This was written by Harald Welte and is - present in UML version 2.4.5-5um and later. Your system must have - multicast enabled in the kernel and there must be a multicast-capable - network device on the host. Normally, this is eth0, but if there is - no ethernet card on the host, then you will likely get strange error - messages when you bring the device up inside UML. - - - To use it, run two UMLs with - - - eth0=mcast - - - - - on their command lines. Log in, configure the ethernet device in each - machine with different IP addresses: - - - UML1# ifconfig eth0 192.168.0.254 - - - - - - - UML2# ifconfig eth0 192.168.0.253 - - - - - and they should be able to talk to each other. - - The full set of command line options for this transport are - - - - ethn=mcast,ethernet address,multicast - address,multicast port,ttl - - - - - Harald's original README is here and explains these in detail, as well as - some other issues. - - - - 66..66.. TTUUNN//TTAAPP wwiitthh tthhee uummll__nneett hheellppeerr - - TUN/TAP is the preferred mechanism on 2.4 to exchange packets with the - host. The TUN/TAP backend has been in UML since 2.4.9-3um. - - - The easiest way to get up and running is to let the setuid uml_net - helper do the host setup for you. This involves insmod-ing the tun.o - module if necessary, configuring the device, and setting up IP - forwarding, routing, and proxy arp. If you are new to UML networking, - do this first. If you're concerned about the security implications of - the setuid helper, use it to get up and running, then read the next - section to see how to have UML use a preconfigured tap device, which - avoids the use of uml_net. - - - If you specify an IP address for the host side of the device, the - uml_net helper will do all necessary setup on the host - the only - requirement is that TUN/TAP be available, either built in to the host - kernel or as the tun.o module. - - The format of the command line switch to attach a device to a TUN/TAP - device is - - - eth =tuntap,,, - - - - - For example, this argument will attach the UML's eth0 to the next - available tap device and assign an ethernet address to it based on its - IP address - - - eth0=tuntap,,,192.168.0.254 - - - - - - - Note that the IP address that must be used for the eth device inside - UML is fixed by the routing and proxy arp that is set up on the - TUN/TAP device on the host. You can use a different one, but it won't - work because reply packets won't reach the UML. This is a feature. - It prevents a nasty UML user from doing things like setting the UML IP - to the same as the network's nameserver or mail server. - - - There are a couple potential problems with running the TUN/TAP - transport on a 2.4 host kernel - - +o TUN/TAP seems not to work on 2.4.3 and earlier. Upgrade the host - kernel or use the ethertap transport. - - +o With an upgraded kernel, TUN/TAP may fail with - - - File descriptor in bad state - - - - - This is due to a header mismatch between the upgraded kernel and the - kernel that was originally installed on the machine. The fix is to - make sure that /usr/src/linux points to the headers for the running - kernel. - - These were pointed out by Tim Robinson in - name="this uml- - user post"> . - - - - 66..77.. TTUUNN//TTAAPP wwiitthh aa pprreeccoonnffiigguurreedd ttaapp ddeevviiccee - - If you prefer not to have UML use uml_net (which is somewhat - insecure), with UML 2.4.17-11, you can set up a TUN/TAP device - beforehand. The setup needs to be done as root, but once that's done, - there is no need for root assistance. Setting up the device is done - as follows: - - +o Create the device with tunctl (available from the UML utilities - tarball) - - - - - host# tunctl -u uid - - - - - where uid is the user id or username that UML will be run as. This - will tell you what device was created. - - +o Configure the device IP (change IP addresses and device name to - suit) - - - - - host# ifconfig tap0 192.168.0.254 up - - - - - - +o Set up routing and arping if desired - this is my recipe, there are - other ways of doing the same thing - - - host# - bash -c 'echo 1 > /proc/sys/net/ipv4/ip_forward' - - host# - route add -host 192.168.0.253 dev tap0 - - - - - - - host# - bash -c 'echo 1 > /proc/sys/net/ipv4/conf/tap0/proxy_arp' - - - - - - - host# - arp -Ds 192.168.0.253 eth0 pub - - - - - Note that this must be done every time the host boots - this configu- - ration is not stored across host reboots. So, it's probably a good - idea to stick it in an rc file. An even better idea would be a little - utility which reads the information from a config file and sets up - devices at boot time. - - +o Rather than using up two IPs and ARPing for one of them, you can - also provide direct access to your LAN by the UML by using a - bridge. - - - host# - brctl addbr br0 - - - - - - - host# - ifconfig eth0 0.0.0.0 promisc up - - - - - - - host# - ifconfig tap0 0.0.0.0 promisc up - - - - - - - host# - ifconfig br0 192.168.0.1 netmask 255.255.255.0 up - - - - - - - - host# - brctl stp br0 off - - - - - - - host# - brctl setfd br0 1 - - - - - - - host# - brctl sethello br0 1 - - - - - - - host# - brctl addif br0 eth0 - - - - - - - host# - brctl addif br0 tap0 - - - - - Note that 'br0' should be setup using ifconfig with the existing IP - address of eth0, as eth0 no longer has its own IP. - - +o - - - Also, the /dev/net/tun device must be writable by the user running - UML in order for the UML to use the device that's been configured - for it. The simplest thing to do is - - - host# chmod 666 /dev/net/tun - - - - - Making it world-writable looks bad, but it seems not to be - exploitable as a security hole. However, it does allow anyone to cre- - ate useless tap devices (useless because they can't configure them), - which is a DOS attack. A somewhat more secure alternative would to be - to create a group containing all the users who have preconfigured tap - devices and chgrp /dev/net/tun to that group with mode 664 or 660. - - - +o Once the device is set up, run UML with 'eth0=tuntap,device name' - (i.e. 'eth0=tuntap,tap0') on the command line (or do it with the - mconsole config command). - - +o Bring the eth device up in UML and you're in business. - - If you don't want that tap device any more, you can make it non- - persistent with - - - host# tunctl -d tap device - - - - - Finally, tunctl has a -b (for brief mode) switch which causes it to - output only the name of the tap device it created. This makes it - suitable for capture by a script: - - - host# TAP=`tunctl -u 1000 -b` - - - - - - - 66..88.. EEtthheerrttaapp - - Ethertap is the general mechanism on 2.2 for userspace processes to - exchange packets with the kernel. - - - - To use this transport, you need to describe the virtual network device - on the UML command line. The general format for this is - - - eth =ethertap, , , - - - - - So, the previous example - - - eth0=ethertap,tap0,fe:fd:0:0:0:1,192.168.0.254 - - - - - attaches the UML eth0 device to the host /dev/tap0, assigns it the - ethernet address fe:fd:0:0:0:1, and assigns the IP address - 192.168.0.254 to the tap device. - - - - The tap device is mandatory, but the others are optional. If the - ethernet address is omitted, one will be assigned to it. - - - The presence of the tap IP address will cause the helper to run and do - whatever host setup is needed to allow the virtual machine to - communicate with the outside world. If you're not sure you know what - you're doing, this is the way to go. - - - If it is absent, then you must configure the tap device and whatever - arping and routing you will need on the host. However, even in this - case, the uml_net helper still needs to be in your path and it must be - setuid root if you're not running UML as root. This is because the - tap device doesn't support SIGIO, which UML needs in order to use - something as a source of input. So, the helper is used as a - convenient asynchronous IO thread. - - If you're using the uml_net helper, you can ignore the following host - setup - uml_net will do it for you. You just need to make sure you - have ethertap available, either built in to the host kernel or - available as a module. - - - If you want to set things up yourself, you need to make sure that the - appropriate /dev entry exists. If it doesn't, become root and create - it as follows: - - - mknod /dev/tap c 36 + 16 - - - - - For example, this is how to create /dev/tap0: - - - mknod /dev/tap0 c 36 0 + 16 - - - - - You also need to make sure that the host kernel has ethertap support. - If ethertap is enabled as a module, you apparently need to insmod - ethertap once for each ethertap device you want to enable. So, - - - host# - insmod ethertap - - - - - will give you the tap0 interface. To get the tap1 interface, you need - to run - - - host# - insmod ethertap unit=1 -o ethertap1 - - - - - - - - 66..99.. TThhee sswwiittcchh ddaaeemmoonn - - NNoottee: This is the daemon formerly known as uml_router, but which was - renamed so the network weenies of the world would stop growling at me. - - - The switch daemon, uml_switch, provides a mechanism for creating a - totally virtual network. By default, it provides no connection to the - host network (but see -tap, below). - - - The first thing you need to do is run the daemon. Running it with no - arguments will make it listen on a default pair of unix domain - sockets. - - - If you want it to listen on a different pair of sockets, use - - - -unix control socket data socket - - - - - - If you want it to act as a hub rather than a switch, use - - - -hub - - - - - - If you want the switch to be connected to host networking (allowing - the umls to get access to the outside world through the host), use - - - -tap tap0 - - - - - - Note that the tap device must be preconfigured (see "TUN/TAP with a - preconfigured tap device", above). If you're using a different tap - device than tap0, specify that instead of tap0. - - - uml_switch can be backgrounded as follows - - - host% - uml_switch [ options ] < /dev/null > /dev/null - - - - - The reason it doesn't background by default is that it listens to - stdin for EOF. When it sees that, it exits. - - - The general format of the kernel command line switch is - - - - ethn=daemon,ethernet address,socket - type,control socket,data socket - - - - - You can leave off everything except the 'daemon'. You only need to - specify the ethernet address if the one that will be assigned to it - isn't acceptable for some reason. The rest of the arguments describe - how to communicate with the daemon. You should only specify them if - you told the daemon to use different sockets than the default. So, if - you ran the daemon with no arguments, running the UML on the same - machine with - eth0=daemon - - - - - will cause the eth0 driver to attach itself to the daemon correctly. - - - - 66..1100.. SSlliipp - - Slip is another, less general, mechanism for a process to communicate - with the host networking. In contrast to the ethertap interface, - which exchanges ethernet frames with the host and can be used to - transport any higher-level protocol, it can only be used to transport - IP. - - - The general format of the command line switch is - - - - ethn=slip,slip IP - - - - - The slip IP argument is the IP address that will be assigned to the - host end of the slip device. If it is specified, the helper will run - and will set up the host so that the virtual machine can reach it and - the rest of the network. - - - There are some oddities with this interface that you should be aware - of. You should only specify one slip device on a given virtual - machine, and its name inside UML will be 'umn', not 'eth0' or whatever - you specified on the command line. These problems will be fixed at - some point. - - - - 66..1111.. SSlliirrpp - - slirp uses an external program, usually /usr/bin/slirp, to provide IP - only networking connectivity through the host. This is similar to IP - masquerading with a firewall, although the translation is performed in - user-space, rather than by the kernel. As slirp does not set up any - interfaces on the host, or changes routing, slirp does not require - root access or setuid binaries on the host. - - - The general format of the command line switch for slirp is: - - - - ethn=slirp,ethernet address,slirp path - - - - - The ethernet address is optional, as UML will set up the interface - with an ethernet address based upon the initial IP address of the - interface. The slirp path is generally /usr/bin/slirp, although it - will depend on distribution. - - - The slirp program can have a number of options passed to the command - line and we can't add them to the UML command line, as they will be - parsed incorrectly. Instead, a wrapper shell script can be written or - the options inserted into the /.slirprc file. More information on - all of the slirp options can be found in its man pages. - - - The eth0 interface on UML should be set up with the IP 10.2.0.15, - although you can use anything as long as it is not used by a network - you will be connecting to. The default route on UML should be set to - use - - - UML# - route add default dev eth0 - - - - - slirp provides a number of useful IP addresses which can be used by - UML, such as 10.0.2.3 which is an alias for the DNS server specified - in /etc/resolv.conf on the host or the IP given in the 'dns' option - for slirp. - - - Even with a baudrate setting higher than 115200, the slirp connection - is limited to 115200. If you need it to go faster, the slirp binary - needs to be compiled with FULL_BOLT defined in config.h. - - - - 66..1122.. ppccaapp - - The pcap transport is attached to a UML ethernet device on the command - line or with uml_mconsole with the following syntax: - - - - ethn=pcap,host interface,filter - expression,option1,option2 - - - - - The expression and options are optional. - - - The interface is whatever network device on the host you want to - sniff. The expression is a pcap filter expression, which is also what - tcpdump uses, so if you know how to specify tcpdump filters, you will - use the same expressions here. The options are up to two of - 'promisc', control whether pcap puts the host interface into - promiscuous mode. 'optimize' and 'nooptimize' control whether the pcap - expression optimizer is used. - - - Example: - - - - eth0=pcap,eth0,tcp - - eth1=pcap,eth0,!tcp - - - - will cause the UML eth0 to emit all tcp packets on the host eth0 and - the UML eth1 to emit all non-tcp packets on the host eth0. - - - - 66..1133.. SSeettttiinngg uupp tthhee hhoosstt yyoouurrsseellff - - If you don't specify an address for the host side of the ethertap or - slip device, UML won't do any setup on the host. So this is what is - needed to get things working (the examples use a host-side IP of - 192.168.0.251 and a UML-side IP of 192.168.0.250 - adjust to suit your - own network): - - +o The device needs to be configured with its IP address. Tap devices - are also configured with an mtu of 1484. Slip devices are - configured with a point-to-point address pointing at the UML ip - address. - - - host# ifconfig tap0 arp mtu 1484 192.168.0.251 up - - - - - - - host# - ifconfig sl0 192.168.0.251 pointopoint 192.168.0.250 up - - - - - - +o If a tap device is being set up, a route is set to the UML IP. - - - UML# route add -host 192.168.0.250 gw 192.168.0.251 - - - - - - +o To allow other hosts on your network to see the virtual machine, - proxy arp is set up for it. - - - host# arp -Ds 192.168.0.250 eth0 pub - - - - - - +o Finally, the host is set up to route packets. - - - host# echo 1 > /proc/sys/net/ipv4/ip_forward - - - - - - - - - - - 77.. SShhaarriinngg FFiilleessyysstteemmss bbeettwweeeenn VViirrttuuaall MMaacchhiinneess - - - - - 77..11.. AA wwaarrnniinngg - - Don't attempt to share filesystems simply by booting two UMLs from the - same file. That's the same thing as booting two physical machines - from a shared disk. It will result in filesystem corruption. - - - - 77..22.. UUssiinngg llaayyeerreedd bblloocckk ddeevviicceess - - The way to share a filesystem between two virtual machines is to use - the copy-on-write (COW) layering capability of the ubd block driver. - As of 2.4.6-2um, the driver supports layering a read-write private - device over a read-only shared device. A machine's writes are stored - in the private device, while reads come from either device - the - private one if the requested block is valid in it, the shared one if - not. Using this scheme, the majority of data which is unchanged is - shared between an arbitrary number of virtual machines, each of which - has a much smaller file containing the changes that it has made. With - a large number of UMLs booting from a large root filesystem, this - leads to a huge disk space saving. It will also help performance, - since the host will be able to cache the shared data using a much - smaller amount of memory, so UML disk requests will be served from the - host's memory rather than its disks. - - - - - To add a copy-on-write layer to an existing block device file, simply - add the name of the COW file to the appropriate ubd switch: - - - ubd0=root_fs_cow,root_fs_debian_22 - - - - - where 'root_fs_cow' is the private COW file and 'root_fs_debian_22' is - the existing shared filesystem. The COW file need not exist. If it - doesn't, the driver will create and initialize it. Once the COW file - has been initialized, it can be used on its own on the command line: - - - ubd0=root_fs_cow - - - - - The name of the backing file is stored in the COW file header, so it - would be redundant to continue specifying it on the command line. - - - - 77..33.. NNoottee!! - - When checking the size of the COW file in order to see the gobs of - space that you're saving, make sure you use 'ls -ls' to see the actual - disk consumption rather than the length of the file. The COW file is - sparse, so the length will be very different from the disk usage. - Here is a 'ls -l' of a COW file and backing file from one boot and - shutdown: - host% ls -l cow.debian debian2.2 - -rw-r--r-- 1 jdike jdike 492504064 Aug 6 21:16 cow.debian - -rwxrw-rw- 1 jdike jdike 537919488 Aug 6 20:42 debian2.2 - - - - - Doesn't look like much saved space, does it? Well, here's 'ls -ls': - - - host% ls -ls cow.debian debian2.2 - 880 -rw-r--r-- 1 jdike jdike 492504064 Aug 6 21:16 cow.debian - 525832 -rwxrw-rw- 1 jdike jdike 537919488 Aug 6 20:42 debian2.2 - - - - - Now, you can see that the COW file has less than a meg of disk, rather - than 492 meg. - - - - 77..44.. AAnnootthheerr wwaarrnniinngg - - Once a filesystem is being used as a readonly backing file for a COW - file, do not boot directly from it or modify it in any way. Doing so - will invalidate any COW files that are using it. The mtime and size - of the backing file are stored in the COW file header at its creation, - and they must continue to match. If they don't, the driver will - refuse to use the COW file. - - - - - If you attempt to evade this restriction by changing either the - backing file or the COW header by hand, you will get a corrupted - filesystem. - - - - - Among other things, this means that upgrading the distribution in a - backing file and expecting that all of the COW files using it will see - the upgrade will not work. - - - - - 77..55.. uummll__mmoooo :: MMeerrggiinngg aa CCOOWW ffiillee wwiitthh iittss bbaacckkiinngg ffiillee - - Depending on how you use UML and COW devices, it may be advisable to - merge the changes in the COW file into the backing file every once in - a while. - - - - - The utility that does this is uml_moo. Its usage is - - - host% uml_moo COW file new backing file - - - - - There's no need to specify the backing file since that information is - already in the COW file header. If you're paranoid, boot the new - merged file, and if you're happy with it, move it over the old backing - file. - - - - - uml_moo creates a new backing file by default as a safety measure. It - also has a destructive merge option which will merge the COW file - directly into its current backing file. This is really only usable - when the backing file only has one COW file associated with it. If - there are multiple COWs associated with a backing file, a -d merge of - one of them will invalidate all of the others. However, it is - convenient if you're short of disk space, and it should also be - noticeably faster than a non-destructive merge. - - - - - uml_moo is installed with the UML deb and RPM. If you didn't install - UML from one of those packages, you can also get it from the UML - utilities tar file in tools/moo. - - - - - - - - - 88.. CCrreeaattiinngg ffiilleessyysstteemmss - - - You may want to create and mount new UML filesystems, either because - your root filesystem isn't large enough or because you want to use a - filesystem other than ext2. - - - This was written on the occasion of reiserfs being included in the - 2.4.1 kernel pool, and therefore the 2.4.1 UML, so the examples will - talk about reiserfs. This information is generic, and the examples - should be easy to translate to the filesystem of your choice. - - - 88..11.. CCrreeaattee tthhee ffiilleessyysstteemm ffiillee - - dd is your friend. All you need to do is tell dd to create an empty - file of the appropriate size. I usually make it sparse to save time - and to avoid allocating disk space until it's actually used. For - example, the following command will create a sparse 100 meg file full - of zeroes. - - - host% - dd if=/dev/zero of=new_filesystem seek=100 count=1 bs=1M - - - - - - - 88..22.. AAssssiiggnn tthhee ffiillee ttoo aa UUMMLL ddeevviiccee - - Add an argument like the following to the UML command line: - - ubd4=new_filesystem - - - - - making sure that you use an unassigned ubd device number. - - - - 88..33.. CCrreeaattiinngg aanndd mmoouunnttiinngg tthhee ffiilleessyysstteemm - - Make sure that the filesystem is available, either by being built into - the kernel, or available as a module, then boot up UML and log in. If - the root filesystem doesn't have the filesystem utilities (mkfs, fsck, - etc), then get them into UML by way of the net or hostfs. - - - Make the new filesystem on the device assigned to the new file: - - - host# mkreiserfs /dev/ubd/4 - - - <----------- MKREISERFSv2 -----------> - - ReiserFS version 3.6.25 - Block size 4096 bytes - Block count 25856 - Used blocks 8212 - Journal - 8192 blocks (18-8209), journal header is in block 8210 - Bitmaps: 17 - Root block 8211 - Hash function "r5" - ATTENTION: ALL DATA WILL BE LOST ON '/dev/ubd/4'! (y/n)y - journal size 8192 (from 18) - Initializing journal - 0%....20%....40%....60%....80%....100% - Syncing..done. - - - - - Now, mount it: - - - UML# - mount /dev/ubd/4 /mnt - - - - - and you're in business. - - - - - - - - - - 99.. HHoosstt ffiillee aacccceessss - - - If you want to access files on the host machine from inside UML, you - can treat it as a separate machine and either nfs mount directories - from the host or copy files into the virtual machine with scp or rcp. - However, since UML is running on the host, it can access those - files just like any other process and make them available inside the - virtual machine without needing to use the network. - - - This is now possible with the hostfs virtual filesystem. With it, you - can mount a host directory into the UML filesystem and access the - files contained in it just as you would on the host. - - - 99..11.. UUssiinngg hhoossttffss - - To begin with, make sure that hostfs is available inside the virtual - machine with - - - UML# cat /proc/filesystems - - - - . hostfs should be listed. If it's not, either rebuild the kernel - with hostfs configured into it or make sure that hostfs is built as a - module and available inside the virtual machine, and insmod it. - - - Now all you need to do is run mount: - - - UML# mount none /mnt/host -t hostfs - - - - - will mount the host's / on the virtual machine's /mnt/host. - - - If you don't want to mount the host root directory, then you can - specify a subdirectory to mount with the -o switch to mount: - - - UML# mount none /mnt/home -t hostfs -o /home - - - - - will mount the hosts's /home on the virtual machine's /mnt/home. - - - - 99..22.. hhoossttffss aass tthhee rroooott ffiilleessyysstteemm - - It's possible to boot from a directory hierarchy on the host using - hostfs rather than using the standard filesystem in a file. - - To start, you need that hierarchy. The easiest way is to loop mount - an existing root_fs file: - - - host# mount root_fs uml_root_dir -o loop - - - - - You need to change the filesystem type of / in etc/fstab to be - 'hostfs', so that line looks like this: - - /dev/ubd/0 / hostfs defaults 1 1 - - - - - Then you need to chown to yourself all the files in that directory - that are owned by root. This worked for me: - - - host# find . -uid 0 -exec chown jdike {} \; - - - - - Next, make sure that your UML kernel has hostfs compiled in, not as a - module. Then run UML with the boot device pointing at that directory: - - - ubd0=/path/to/uml/root/directory - - - - - UML should then boot as it does normally. - - - 99..33.. BBuuiillddiinngg hhoossttffss - - If you need to build hostfs because it's not in your kernel, you have - two choices: - - - - +o Compiling hostfs into the kernel: - - - Reconfigure the kernel and set the 'Host filesystem' option under - - - +o Compiling hostfs as a module: - - - Reconfigure the kernel and set the 'Host filesystem' option under - be in arch/um/fs/hostfs/hostfs.o. Install that in - /lib/modules/`uname -r`/fs in the virtual machine, boot it up, and - - - UML# insmod hostfs - - - - - - - - - - - - - 1100.. TThhee MMaannaaggeemmeenntt CCoonnssoollee - - - - The UML management console is a low-level interface to the kernel, - somewhat like the i386 SysRq interface. Since there is a full-blown - operating system under UML, there is much greater flexibility possible - than with the SysRq mechanism. - - - There are a number of things you can do with the mconsole interface: - - +o get the kernel version - - +o add and remove devices - - +o halt or reboot the machine - - +o Send SysRq commands - - +o Pause and resume the UML - - - You need the mconsole client (uml_mconsole) which is present in CVS - (/tools/mconsole) in 2.4.5-9um and later, and will be in the RPM in - 2.4.6. - - - You also need CONFIG_MCONSOLE (under 'General Setup') enabled in UML. - When you boot UML, you'll see a line like: - - - mconsole initialized on /home/jdike/.uml/umlNJ32yL/mconsole - - - - - If you specify a unique machine id one the UML command line, i.e. - - - umid=debian - - - - - you'll see this - - - mconsole initialized on /home/jdike/.uml/debian/mconsole - - - - - That file is the socket that uml_mconsole will use to communicate with - UML. Run it with either the umid or the full path as its argument: - - - host% uml_mconsole debian - - - - - or - - - host% uml_mconsole /home/jdike/.uml/debian/mconsole - - - - - You'll get a prompt, at which you can run one of these commands: - - +o version - - +o halt - - +o reboot - - +o config - - +o remove - - +o sysrq - - +o help - - +o cad - - +o stop - - +o go - - - 1100..11.. vveerrssiioonn - - This takes no arguments. It prints the UML version. - - - (mconsole) version - OK Linux usermode 2.4.5-9um #1 Wed Jun 20 22:47:08 EDT 2001 i686 - - - - - There are a couple actual uses for this. It's a simple no-op which - can be used to check that a UML is running. It's also a way of - sending an interrupt to the UML. This is sometimes useful on SMP - hosts, where there's a bug which causes signals to UML to be lost, - often causing it to appear to hang. Sending such a UML the mconsole - version command is a good way to 'wake it up' before networking has - been enabled, as it does not do anything to the function of the UML. - - - - 1100..22.. hhaalltt aanndd rreebboooott - - These take no arguments. They shut the machine down immediately, with - no syncing of disks and no clean shutdown of userspace. So, they are - pretty close to crashing the machine. - - - (mconsole) halt - OK - - - - - - - 1100..33.. ccoonnffiigg - - "config" adds a new device to the virtual machine. Currently the ubd - and network drivers support this. It takes one argument, which is the - device to add, with the same syntax as the kernel command line. - - - - - (mconsole) - config ubd3=/home/jdike/incoming/roots/root_fs_debian22 - - OK - (mconsole) config eth1=mcast - OK - - - - - - - 1100..44.. rreemmoovvee - - "remove" deletes a device from the system. Its argument is just the - name of the device to be removed. The device must be idle in whatever - sense the driver considers necessary. In the case of the ubd driver, - the removed block device must not be mounted, swapped on, or otherwise - open, and in the case of the network driver, the device must be down. - - - (mconsole) remove ubd3 - OK - (mconsole) remove eth1 - OK - - - - - - - 1100..55.. ssyyssrrqq - - This takes one argument, which is a single letter. It calls the - generic kernel's SysRq driver, which does whatever is called for by - that argument. See the SysRq documentation in Documentation/sysrq.txt - in your favorite kernel tree to see what letters are valid and what - they do. - - - - 1100..66.. hheellpp - - "help" returns a string listing the valid commands and what each one - does. - - - - 1100..77.. ccaadd - - This invokes the Ctl-Alt-Del action on init. What exactly this ends - up doing is up to /etc/inittab. Normally, it reboots the machine. - With UML, this is usually not desired, so if a halt would be better, - then find the section of inittab that looks like this - - - # What to do when CTRL-ALT-DEL is pressed. - ca:12345:ctrlaltdel:/sbin/shutdown -t1 -a -r now - - - - - and change the command to halt. - - - - 1100..88.. ssttoopp - - This puts the UML in a loop reading mconsole requests until a 'go' - mconsole command is received. This is very useful for making backups - of UML filesystems, as the UML can be stopped, then synced via 'sysrq - s', so that everything is written to the filesystem. You can then copy - the filesystem and then send the UML 'go' via mconsole. - - - Note that a UML running with more than one CPU will have problems - after you send the 'stop' command, as only one CPU will be held in a - mconsole loop and all others will continue as normal. This is a bug, - and will be fixed. - - - - 1100..99.. ggoo - - This resumes a UML after being paused by a 'stop' command. Note that - when the UML has resumed, TCP connections may have timed out and if - the UML is paused for a long period of time, crond might go a little - crazy, running all the jobs it didn't do earlier. - - - - - - - - - 1111.. KKeerrnneell ddeebbuuggggiinngg - - - NNoottee:: The interface that makes debugging, as described here, possible - is present in 2.4.0-test6 kernels and later. - - - Since the user-mode kernel runs as a normal Linux process, it is - possible to debug it with gdb almost like any other process. It is - slightly different because the kernel's threads are already being - ptraced for system call interception, so gdb can't ptrace them. - However, a mechanism has been added to work around that problem. - - - In order to debug the kernel, you need build it from source. See - ``Compiling the kernel and modules'' for information on doing that. - Make sure that you enable CONFIG_DEBUGSYM and CONFIG_PT_PROXY during - the config. These will compile the kernel with -g, and enable the - ptrace proxy so that gdb works with UML, respectively. - - - - - 1111..11.. SSttaarrttiinngg tthhee kkeerrnneell uunnddeerr ggddbb - - You can have the kernel running under the control of gdb from the - beginning by putting 'debug' on the command line. You will get an - xterm with gdb running inside it. The kernel will send some commands - to gdb which will leave it stopped at the beginning of start_kernel. - At this point, you can get things going with 'next', 'step', or - 'cont'. - - - There is a transcript of a debugging session here , with breakpoints being set in the scheduler and in an - interrupt handler. - 1111..22.. EExxaammiinniinngg sslleeeeppiinngg pprroocceesssseess - - Not every bug is evident in the currently running process. Sometimes, - processes hang in the kernel when they shouldn't because they've - deadlocked on a semaphore or something similar. In this case, when - you ^C gdb and get a backtrace, you will see the idle thread, which - isn't very relevant. - - - What you want is the stack of whatever process is sleeping when it - shouldn't be. You need to figure out which process that is, which is - generally fairly easy. Then you need to get its host process id, - which you can do either by looking at ps on the host or at - task.thread.extern_pid in gdb. - - - Now what you do is this: - - +o detach from the current thread - - - (UML gdb) det - - - - - - +o attach to the thread you are interested in - - - (UML gdb) att - - - - - - +o look at its stack and anything else of interest - - - (UML gdb) bt - - - - - Note that you can't do anything at this point that requires that a - process execute, e.g. calling a function - - +o when you're done looking at that process, reattach to the current - thread and continue it - - - (UML gdb) - att 1 - - - - - - - (UML gdb) - c - - - - - Here, specifying any pid which is not the process id of a UML thread - will cause gdb to reattach to the current thread. I commonly use 1, - but any other invalid pid would work. - - - - 1111..33.. RRuunnnniinngg dddddd oonn UUMMLL - - ddd works on UML, but requires a special kludge. The process goes - like this: - - +o Start ddd - - - host% ddd linux - - - - - - +o With ps, get the pid of the gdb that ddd started. You can ask the - gdb to tell you, but for some reason that confuses things and - causes a hang. - - +o run UML with 'debug=parent gdb-pid=' added to the command line - - it will just sit there after you hit return - - +o type 'att 1' to the ddd gdb and you will see something like - - - 0xa013dc51 in __kill () - - - (gdb) - - - - - - +o At this point, type 'c', UML will boot up, and you can use ddd just - as you do on any other process. - - - - 1111..44.. DDeebbuuggggiinngg mmoodduulleess - - gdb has support for debugging code which is dynamically loaded into - the process. This support is what is needed to debug kernel modules - under UML. - - - Using that support is somewhat complicated. You have to tell gdb what - object file you just loaded into UML and where in memory it is. Then, - it can read the symbol table, and figure out where all the symbols are - from the load address that you provided. It gets more interesting - when you load the module again (i.e. after an rmmod). You have to - tell gdb to forget about all its symbols, including the main UML ones - for some reason, then load then all back in again. - - - There's an easy way and a hard way to do this. The easy way is to use - the umlgdb expect script written by Chandan Kudige. It basically - automates the process for you. - - - First, you must tell it where your modules are. There is a list in - the script that looks like this: - set MODULE_PATHS { - "fat" "/usr/src/uml/linux-2.4.18/fs/fat/fat.o" - "isofs" "/usr/src/uml/linux-2.4.18/fs/isofs/isofs.o" - "minix" "/usr/src/uml/linux-2.4.18/fs/minix/minix.o" - } - - - - - You change that to list the names and paths of the modules that you - are going to debug. Then you run it from the toplevel directory of - your UML pool and it basically tells you what to do: - - - - - ******** GDB pid is 21903 ******** - Start UML as: ./linux debug gdb-pid=21903 - - - - GNU gdb 5.0rh-5 Red Hat Linux 7.1 - Copyright 2001 Free Software Foundation, Inc. - GDB is free software, covered by the GNU General Public License, and you are - welcome to change it and/or distribute copies of it under certain conditions. - Type "show copying" to see the conditions. - There is absolutely no warranty for GDB. Type "show warranty" for details. - This GDB was configured as "i386-redhat-linux"... - (gdb) b sys_init_module - Breakpoint 1 at 0xa0011923: file module.c, line 349. - (gdb) att 1 - - - - - After you run UML and it sits there doing nothing, you hit return at - the 'att 1' and continue it: - - - Attaching to program: /home/jdike/linux/2.4/um/./linux, process 1 - 0xa00f4221 in __kill () - (UML gdb) c - Continuing. - - - - - At this point, you debug normally. When you insmod something, the - expect magic will kick in and you'll see something like: - - - - - - - - - - - - - - - - - - *** Module hostfs loaded *** - Breakpoint 1, sys_init_module (name_user=0x805abb0 "hostfs", - mod_user=0x8070e00) at module.c:349 - 349 char *name, *n_name, *name_tmp = NULL; - (UML gdb) finish - Run till exit from #0 sys_init_module (name_user=0x805abb0 "hostfs", - mod_user=0x8070e00) at module.c:349 - 0xa00e2e23 in execute_syscall (r=0xa8140284) at syscall_kern.c:411 - 411 else res = EXECUTE_SYSCALL(syscall, regs); - Value returned is $1 = 0 - (UML gdb) - p/x (int)module_list + module_list->size_of_struct - - $2 = 0xa9021054 - (UML gdb) symbol-file ./linux - Load new symbol table from "./linux"? (y or n) y - Reading symbols from ./linux... - done. - (UML gdb) - add-symbol-file /home/jdike/linux/2.4/um/arch/um/fs/hostfs/hostfs.o 0xa9021054 - - add symbol table from file "/home/jdike/linux/2.4/um/arch/um/fs/hostfs/hostfs.o" at - .text_addr = 0xa9021054 - (y or n) y - - Reading symbols from /home/jdike/linux/2.4/um/arch/um/fs/hostfs/hostfs.o... - done. - (UML gdb) p *module_list - $1 = {size_of_struct = 84, next = 0xa0178720, name = 0xa9022de0 "hostfs", - size = 9016, uc = {usecount = {counter = 0}, pad = 0}, flags = 1, - nsyms = 57, ndeps = 0, syms = 0xa9023170, deps = 0x0, refs = 0x0, - init = 0xa90221f0 , cleanup = 0xa902222c , - ex_table_start = 0x0, ex_table_end = 0x0, persist_start = 0x0, - persist_end = 0x0, can_unload = 0, runsize = 0, kallsyms_start = 0x0, - kallsyms_end = 0x0, - archdata_start = 0x1b855
, - archdata_end = 0xe5890000
, - kernel_data = 0xf689c35d
} - >> Finished loading symbols for hostfs ... - - - - - That's the easy way. It's highly recommended. The hard way is - described below in case you're interested in what's going on. - - - Boot the kernel under the debugger and load the module with insmod or - modprobe. With gdb, do: - - - (UML gdb) p module_list - - - - - This is a list of modules that have been loaded into the kernel, with - the most recently loaded module first. Normally, the module you want - is at module_list. If it's not, walk down the next links, looking at - the name fields until find the module you want to debug. Take the - address of that structure, and add module.size_of_struct (which in - 2.4.10 kernels is 96 (0x60)) to it. Gdb can make this hard addition - for you :-): - - - - (UML gdb) - printf "%#x\n", (int)module_list module_list->size_of_struct - - - - - The offset from the module start occasionally changes (before 2.4.0, - it was module.size_of_struct + 4), so it's a good idea to check the - init and cleanup addresses once in a while, as describe below. Now - do: - - - (UML gdb) - add-symbol-file /path/to/module/on/host that_address - - - - - Tell gdb you really want to do it, and you're in business. - - - If there's any doubt that you got the offset right, like breakpoints - appear not to work, or they're appearing in the wrong place, you can - check it by looking at the module structure. The init and cleanup - fields should look like: - - - init = 0x588066b0 , cleanup = 0x588066c0 - - - - - with no offsets on the symbol names. If the names are right, but they - are offset, then the offset tells you how much you need to add to the - address you gave to add-symbol-file. - - - When you want to load in a new version of the module, you need to get - gdb to forget about the old one. The only way I've found to do that - is to tell gdb to forget about all symbols that it knows about: - - - (UML gdb) symbol-file - - - - - Then reload the symbols from the kernel binary: - - - (UML gdb) symbol-file /path/to/kernel - - - - - and repeat the process above. You'll also need to re-enable break- - points. They were disabled when you dumped all the symbols because - gdb couldn't figure out where they should go. - - - - 1111..55.. AAttttaacchhiinngg ggddbb ttoo tthhee kkeerrnneell - - If you don't have the kernel running under gdb, you can attach gdb to - it later by sending the tracing thread a SIGUSR1. The first line of - the console output identifies its pid: - tracing thread pid = 20093 - - - - - When you send it the signal: - - - host% kill -USR1 20093 - - - - - you will get an xterm with gdb running in it. - - - If you have the mconsole compiled into UML, then the mconsole client - can be used to start gdb: - - - (mconsole) (mconsole) config gdb=xterm - - - - - will fire up an xterm with gdb running in it. - - - - 1111..66.. UUssiinngg aalltteerrnnaattee ddeebbuuggggeerrss - - UML has support for attaching to an already running debugger rather - than starting gdb itself. This is present in CVS as of 17 Apr 2001. - I sent it to Alan for inclusion in the ac tree, and it will be in my - 2.4.4 release. - - - This is useful when gdb is a subprocess of some UI, such as emacs or - ddd. It can also be used to run debuggers other than gdb on UML. - Below is an example of using strace as an alternate debugger. - - - To do this, you need to get the pid of the debugger and pass it in - with the - - - If you are using gdb under some UI, then tell it to 'att 1', and - you'll find yourself attached to UML. - - - If you are using something other than gdb as your debugger, then - you'll need to get it to do the equivalent of 'att 1' if it doesn't do - it automatically. - - - An example of an alternate debugger is strace. You can strace the - actual kernel as follows: - - +o Run the following in a shell - - - host% - sh -c 'echo pid=$$; echo -n hit return; read x; exec strace -p 1 -o strace.out' - - - - +o Run UML with 'debug' and 'gdb-pid=' with the pid printed out - by the previous command - - +o Hit return in the shell, and UML will start running, and strace - output will start accumulating in the output file. - - Note that this is different from running - - - host% strace ./linux - - - - - That will strace only the main UML thread, the tracing thread, which - doesn't do any of the actual kernel work. It just oversees the vir- - tual machine. In contrast, using strace as described above will show - you the low-level activity of the virtual machine. - - - - - - 1122.. KKeerrnneell ddeebbuuggggiinngg eexxaammpplleess - - 1122..11.. TThhee ccaassee ooff tthhee hhuunngg ffsscckk - - When booting up the kernel, fsck failed, and dropped me into a shell - to fix things up. I ran fsck -y, which hung: - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Setting hostname uml [ OK ] - Checking root filesystem - /dev/fhd0 was not cleanly unmounted, check forced. - Error reading block 86894 (Attempt to read block from filesystem resulted in short read) while reading indirect blocks of inode 19780. - - /dev/fhd0: UNEXPECTED INCONSISTENCY; RUN fsck MANUALLY. - (i.e., without -a or -p options) - [ FAILED ] - - *** An error occurred during the file system check. - *** Dropping you to a shell; the system will reboot - *** when you leave the shell. - Give root password for maintenance - (or type Control-D for normal startup): - - [root@uml /root]# fsck -y /dev/fhd0 - fsck -y /dev/fhd0 - Parallelizing fsck version 1.14 (9-Jan-1999) - e2fsck 1.14, 9-Jan-1999 for EXT2 FS 0.5b, 95/08/09 - /dev/fhd0 contains a file system with errors, check forced. - Pass 1: Checking inodes, blocks, and sizes - Error reading block 86894 (Attempt to read block from filesystem resulted in short read) while reading indirect blocks of inode 19780. Ignore error? yes - - Inode 19780, i_blocks is 1548, should be 540. Fix? yes - - Pass 2: Checking directory structure - Error reading block 49405 (Attempt to read block from filesystem resulted in short read). Ignore error? yes - - Directory inode 11858, block 0, offset 0: directory corrupted - Salvage? yes - - Missing '.' in directory inode 11858. - Fix? yes - - Missing '..' in directory inode 11858. - Fix? yes - - - - - - The standard drill in this sort of situation is to fire up gdb on the - signal thread, which, in this case, was pid 1935. In another window, - I run gdb and attach pid 1935. - - - - - ~/linux/2.3.26/um 1016: gdb linux - GNU gdb 4.17.0.11 with Linux support - Copyright 1998 Free Software Foundation, Inc. - GDB is free software, covered by the GNU General Public License, and you are - welcome to change it and/or distribute copies of it under certain conditions. - Type "show copying" to see the conditions. - There is absolutely no warranty for GDB. Type "show warranty" for details. - This GDB was configured as "i386-redhat-linux"... - - (gdb) att 1935 - Attaching to program `/home/dike/linux/2.3.26/um/linux', Pid 1935 - 0x100756d9 in __wait4 () - - - - - - - Let's see what's currently running: - - - - (gdb) p current_task.pid - $1 = 0 - - - - - - It's the idle thread, which means that fsck went to sleep for some - reason and never woke up. - - - Let's guess that the last process in the process list is fsck: - - - - (gdb) p current_task.prev_task.comm - $13 = "fsck.ext2\000\000\000\000\000\000" - - - - - - It is, so let's see what it thinks it's up to: - - - - (gdb) p current_task.prev_task.thread - $14 = {extern_pid = 1980, tracing = 0, want_tracing = 0, forking = 0, - kernel_stack_page = 0, signal_stack = 1342627840, syscall = {id = 4, args = { - 3, 134973440, 1024, 0, 1024}, have_result = 0, result = 50590720}, - request = {op = 2, u = {exec = {ip = 1350467584, sp = 2952789424}, fork = { - regs = {1350467584, 2952789424, 0 }, sigstack = 0, - pid = 0}, switch_to = 0x507e8000, thread = {proc = 0x507e8000, - arg = 0xaffffdb0, flags = 0, new_pid = 0}, input_request = { - op = 1350467584, fd = -1342177872, proc = 0, pid = 0}}}} - - - - - - The interesting things here are the fact that its .thread.syscall.id - is __NR_write (see the big switch in arch/um/kernel/syscall_kern.c or - the defines in include/asm-um/arch/unistd.h), and that it never - returned. Also, its .request.op is OP_SWITCH (see - arch/um/include/user_util.h). These mean that it went into a write, - and, for some reason, called schedule(). - - - The fact that it never returned from write means that its stack should - be fairly interesting. Its pid is 1980 (.thread.extern_pid). That - process is being ptraced by the signal thread, so it must be detached - before gdb can attach it: - - - - - - - - - - - (gdb) call detach(1980) - - Program received signal SIGSEGV, Segmentation fault. - - The program being debugged stopped while in a function called from GDB. - When the function (detach) is done executing, GDB will silently - stop (instead of continuing to evaluate the expression containing - the function call). - (gdb) call detach(1980) - $15 = 0 - - - - - - The first detach segfaults for some reason, and the second one - succeeds. - - - Now I detach from the signal thread, attach to the fsck thread, and - look at its stack: - - - (gdb) det - Detaching from program: /home/dike/linux/2.3.26/um/linux Pid 1935 - (gdb) att 1980 - Attaching to program `/home/dike/linux/2.3.26/um/linux', Pid 1980 - 0x10070451 in __kill () - (gdb) bt - #0 0x10070451 in __kill () - #1 0x10068ccd in usr1_pid (pid=1980) at process.c:30 - #2 0x1006a03f in _switch_to (prev=0x50072000, next=0x507e8000) - at process_kern.c:156 - #3 0x1006a052 in switch_to (prev=0x50072000, next=0x507e8000, last=0x50072000) - at process_kern.c:161 - #4 0x10001d12 in schedule () at sched.c:777 - #5 0x1006a744 in __down (sem=0x507d241c) at semaphore.c:71 - #6 0x1006aa10 in __down_failed () at semaphore.c:157 - #7 0x1006c5d8 in segv_handler (sc=0x5006e940) at trap_user.c:174 - #8 0x1006c5ec in kern_segv_handler (sig=11) at trap_user.c:182 - #9 - #10 0x10155404 in errno () - #11 0x1006c0aa in segv (address=1342179328, is_write=2) at trap_kern.c:50 - #12 0x1006c5d8 in segv_handler (sc=0x5006eaf8) at trap_user.c:174 - #13 0x1006c5ec in kern_segv_handler (sig=11) at trap_user.c:182 - #14 - #15 0xc0fd in ?? () - #16 0x10016647 in sys_write (fd=3, - buf=0x80b8800
, count=1024) - at read_write.c:159 - #17 0x1006d5b3 in execute_syscall (syscall=4, args=0x5006ef08) - at syscall_kern.c:254 - #18 0x1006af87 in really_do_syscall (sig=12) at syscall_user.c:35 - #19 - #20 0x400dc8b0 in ?? () - - - - - - The interesting things here are : - - +o There are two segfaults on this stack (frames 9 and 14) - - +o The first faulting address (frame 11) is 0x50000800 - - (gdb) p (void *)1342179328 - $16 = (void *) 0x50000800 - - - - - - The initial faulting address is interesting because it is on the idle - thread's stack. I had been seeing the idle thread segfault for no - apparent reason, and the cause looked like stack corruption. In hopes - of catching the culprit in the act, I had turned off all protections - to that stack while the idle thread wasn't running. This apparently - tripped that trap. - - - However, the more immediate problem is that second segfault and I'm - going to concentrate on that. First, I want to see where the fault - happened, so I have to go look at the sigcontent struct in frame 8: - - - - (gdb) up - #1 0x10068ccd in usr1_pid (pid=1980) at process.c:30 - 30 kill(pid, SIGUSR1); - (gdb) - #2 0x1006a03f in _switch_to (prev=0x50072000, next=0x507e8000) - at process_kern.c:156 - 156 usr1_pid(getpid()); - (gdb) - #3 0x1006a052 in switch_to (prev=0x50072000, next=0x507e8000, last=0x50072000) - at process_kern.c:161 - 161 _switch_to(prev, next); - (gdb) - #4 0x10001d12 in schedule () at sched.c:777 - 777 switch_to(prev, next, prev); - (gdb) - #5 0x1006a744 in __down (sem=0x507d241c) at semaphore.c:71 - 71 schedule(); - (gdb) - #6 0x1006aa10 in __down_failed () at semaphore.c:157 - 157 } - (gdb) - #7 0x1006c5d8 in segv_handler (sc=0x5006e940) at trap_user.c:174 - 174 segv(sc->cr2, sc->err & 2); - (gdb) - #8 0x1006c5ec in kern_segv_handler (sig=11) at trap_user.c:182 - 182 segv_handler(sc); - (gdb) p *sc - Cannot access memory at address 0x0. - - - - - That's not very useful, so I'll try a more manual method: - - - (gdb) p *((struct sigcontext *) (&sig + 1)) - $19 = {gs = 0, __gsh = 0, fs = 0, __fsh = 0, es = 43, __esh = 0, ds = 43, - __dsh = 0, edi = 1342179328, esi = 1350378548, ebp = 1342630440, - esp = 1342630420, ebx = 1348150624, edx = 1280, ecx = 0, eax = 0, - trapno = 14, err = 4, eip = 268480945, cs = 35, __csh = 0, eflags = 66118, - esp_at_signal = 1342630420, ss = 43, __ssh = 0, fpstate = 0x0, oldmask = 0, - cr2 = 1280} - - - - The ip is in handle_mm_fault: - - - (gdb) p (void *)268480945 - $20 = (void *) 0x1000b1b1 - (gdb) i sym $20 - handle_mm_fault + 57 in section .text - - - - - - Specifically, it's in pte_alloc: - - - (gdb) i line *$20 - Line 124 of "/home/dike/linux/2.3.26/um/include/asm/pgalloc.h" - starts at address 0x1000b1b1 - and ends at 0x1000b1b7 . - - - - - - To find where in handle_mm_fault this is, I'll jump forward in the - code until I see an address in that procedure: - - - - (gdb) i line *0x1000b1c0 - Line 126 of "/home/dike/linux/2.3.26/um/include/asm/pgalloc.h" - starts at address 0x1000b1b7 - and ends at 0x1000b1c3 . - (gdb) i line *0x1000b1d0 - Line 131 of "/home/dike/linux/2.3.26/um/include/asm/pgalloc.h" - starts at address 0x1000b1d0 - and ends at 0x1000b1da . - (gdb) i line *0x1000b1e0 - Line 61 of "/home/dike/linux/2.3.26/um/include/asm/pgalloc.h" - starts at address 0x1000b1da - and ends at 0x1000b1e1 . - (gdb) i line *0x1000b1f0 - Line 134 of "/home/dike/linux/2.3.26/um/include/asm/pgalloc.h" - starts at address 0x1000b1f0 - and ends at 0x1000b200 . - (gdb) i line *0x1000b200 - Line 135 of "/home/dike/linux/2.3.26/um/include/asm/pgalloc.h" - starts at address 0x1000b200 - and ends at 0x1000b208 . - (gdb) i line *0x1000b210 - Line 139 of "/home/dike/linux/2.3.26/um/include/asm/pgalloc.h" - starts at address 0x1000b210 - and ends at 0x1000b219 . - (gdb) i line *0x1000b220 - Line 1168 of "memory.c" starts at address 0x1000b21e - and ends at 0x1000b222 . - - - - - - Something is apparently wrong with the page tables or vma_structs, so - lets go back to frame 11 and have a look at them: - - - - #11 0x1006c0aa in segv (address=1342179328, is_write=2) at trap_kern.c:50 - 50 handle_mm_fault(current, vma, address, is_write); - (gdb) call pgd_offset_proc(vma->vm_mm, address) - $22 = (pgd_t *) 0x80a548c - - - - - - That's pretty bogus. Page tables aren't supposed to be in process - text or data areas. Let's see what's in the vma: - - - (gdb) p *vma - $23 = {vm_mm = 0x507d2434, vm_start = 0, vm_end = 134512640, - vm_next = 0x80a4f8c, vm_page_prot = {pgprot = 0}, vm_flags = 31200, - vm_avl_height = 2058, vm_avl_left = 0x80a8c94, vm_avl_right = 0x80d1000, - vm_next_share = 0xaffffdb0, vm_pprev_share = 0xaffffe63, - vm_ops = 0xaffffe7a, vm_pgoff = 2952789626, vm_file = 0xafffffec, - vm_private_data = 0x62} - (gdb) p *vma.vm_mm - $24 = {mmap = 0x507d2434, mmap_avl = 0x0, mmap_cache = 0x8048000, - pgd = 0x80a4f8c, mm_users = {counter = 0}, mm_count = {counter = 134904288}, - map_count = 134909076, mmap_sem = {count = {counter = 135073792}, - sleepers = -1342177872, wait = {lock = , - task_list = {next = 0xaffffe63, prev = 0xaffffe7a}, - __magic = -1342177670, __creator = -1342177300}, __magic = 98}, - page_table_lock = {}, context = 138, start_code = 0, end_code = 0, - start_data = 0, end_data = 0, start_brk = 0, brk = 0, start_stack = 0, - arg_start = 0, arg_end = 0, env_start = 0, env_end = 0, rss = 1350381536, - total_vm = 0, locked_vm = 0, def_flags = 0, cpu_vm_mask = 0, swap_cnt = 0, - swap_address = 0, segments = 0x0} - - - - - - This also pretty bogus. With all of the 0x80xxxxx and 0xaffffxxx - addresses, this is looking like a stack was plonked down on top of - these structures. Maybe it's a stack overflow from the next page: - - - - (gdb) p vma - $25 = (struct vm_area_struct *) 0x507d2434 - - - - - - That's towards the lower quarter of the page, so that would have to - have been pretty heavy stack overflow: - - - - - - - - - - - - - - - (gdb) x/100x $25 - 0x507d2434: 0x507d2434 0x00000000 0x08048000 0x080a4f8c - 0x507d2444: 0x00000000 0x080a79e0 0x080a8c94 0x080d1000 - 0x507d2454: 0xaffffdb0 0xaffffe63 0xaffffe7a 0xaffffe7a - 0x507d2464: 0xafffffec 0x00000062 0x0000008a 0x00000000 - 0x507d2474: 0x00000000 0x00000000 0x00000000 0x00000000 - 0x507d2484: 0x00000000 0x00000000 0x00000000 0x00000000 - 0x507d2494: 0x00000000 0x00000000 0x507d2fe0 0x00000000 - 0x507d24a4: 0x00000000 0x00000000 0x00000000 0x00000000 - 0x507d24b4: 0x00000000 0x00000000 0x00000000 0x00000000 - 0x507d24c4: 0x00000000 0x00000000 0x00000000 0x00000000 - 0x507d24d4: 0x00000000 0x00000000 0x00000000 0x00000000 - 0x507d24e4: 0x00000000 0x00000000 0x00000000 0x00000000 - 0x507d24f4: 0x00000000 0x00000000 0x00000000 0x00000000 - 0x507d2504: 0x00000000 0x00000000 0x00000000 0x00000000 - 0x507d2514: 0x00000000 0x00000000 0x00000000 0x00000000 - 0x507d2524: 0x00000000 0x00000000 0x00000000 0x00000000 - 0x507d2534: 0x00000000 0x00000000 0x507d25dc 0x00000000 - 0x507d2544: 0x00000000 0x00000000 0x00000000 0x00000000 - 0x507d2554: 0x00000000 0x00000000 0x00000000 0x00000000 - 0x507d2564: 0x00000000 0x00000000 0x00000000 0x00000000 - 0x507d2574: 0x00000000 0x00000000 0x00000000 0x00000000 - 0x507d2584: 0x00000000 0x00000000 0x00000000 0x00000000 - 0x507d2594: 0x00000000 0x00000000 0x00000000 0x00000000 - 0x507d25a4: 0x00000000 0x00000000 0x00000000 0x00000000 - 0x507d25b4: 0x00000000 0x00000000 0x00000000 0x00000000 - - - - - - It's not stack overflow. The only "stack-like" piece of this data is - the vma_struct itself. - - - At this point, I don't see any avenues to pursue, so I just have to - admit that I have no idea what's going on. What I will do, though, is - stick a trap on the segfault handler which will stop if it sees any - writes to the idle thread's stack. That was the thing that happened - first, and it may be that if I can catch it immediately, what's going - on will be somewhat clearer. - - - 1122..22.. EEppiissooddee 22:: TThhee ccaassee ooff tthhee hhuunngg ffsscckk - - After setting a trap in the SEGV handler for accesses to the signal - thread's stack, I reran the kernel. - - - fsck hung again, this time by hitting the trap: - - - - - - - - - - - - - - - - - Setting hostname uml [ OK ] - Checking root filesystem - /dev/fhd0 contains a file system with errors, check forced. - Error reading block 86894 (Attempt to read block from filesystem resulted in short read) while reading indirect blocks of inode 19780. - - /dev/fhd0: UNEXPECTED INCONSISTENCY; RUN fsck MANUALLY. - (i.e., without -a or -p options) - [ FAILED ] - - *** An error occurred during the file system check. - *** Dropping you to a shell; the system will reboot - *** when you leave the shell. - Give root password for maintenance - (or type Control-D for normal startup): - - [root@uml /root]# fsck -y /dev/fhd0 - fsck -y /dev/fhd0 - Parallelizing fsck version 1.14 (9-Jan-1999) - e2fsck 1.14, 9-Jan-1999 for EXT2 FS 0.5b, 95/08/09 - /dev/fhd0 contains a file system with errors, check forced. - Pass 1: Checking inodes, blocks, and sizes - Error reading block 86894 (Attempt to read block from filesystem resulted in short read) while reading indirect blocks of inode 19780. Ignore error? yes - - Pass 2: Checking directory structure - Error reading block 49405 (Attempt to read block from filesystem resulted in short read). Ignore error? yes - - Directory inode 11858, block 0, offset 0: directory corrupted - Salvage? yes - - Missing '.' in directory inode 11858. - Fix? yes - - Missing '..' in directory inode 11858. - Fix? yes - - Untested (4127) [100fe44c]: trap_kern.c line 31 - - - - - - I need to get the signal thread to detach from pid 4127 so that I can - attach to it with gdb. This is done by sending it a SIGUSR1, which is - caught by the signal thread, which detaches the process: - - - kill -USR1 4127 - - - - - - Now I can run gdb on it: - - - - - - - - - - - - - - ~/linux/2.3.26/um 1034: gdb linux - GNU gdb 4.17.0.11 with Linux support - Copyright 1998 Free Software Foundation, Inc. - GDB is free software, covered by the GNU General Public License, and you are - welcome to change it and/or distribute copies of it under certain conditions. - Type "show copying" to see the conditions. - There is absolutely no warranty for GDB. Type "show warranty" for details. - This GDB was configured as "i386-redhat-linux"... - (gdb) att 4127 - Attaching to program `/home/dike/linux/2.3.26/um/linux', Pid 4127 - 0x10075891 in __libc_nanosleep () - - - - - - The backtrace shows that it was in a write and that the fault address - (address in frame 3) is 0x50000800, which is right in the middle of - the signal thread's stack page: - - - (gdb) bt - #0 0x10075891 in __libc_nanosleep () - #1 0x1007584d in __sleep (seconds=1000000) - at ../sysdeps/unix/sysv/linux/sleep.c:78 - #2 0x1006ce9a in stop () at user_util.c:191 - #3 0x1006bf88 in segv (address=1342179328, is_write=2) at trap_kern.c:31 - #4 0x1006c628 in segv_handler (sc=0x5006eaf8) at trap_user.c:174 - #5 0x1006c63c in kern_segv_handler (sig=11) at trap_user.c:182 - #6 - #7 0xc0fd in ?? () - #8 0x10016647 in sys_write (fd=3, buf=0x80b8800 "R.", count=1024) - at read_write.c:159 - #9 0x1006d603 in execute_syscall (syscall=4, args=0x5006ef08) - at syscall_kern.c:254 - #10 0x1006af87 in really_do_syscall (sig=12) at syscall_user.c:35 - #11 - #12 0x400dc8b0 in ?? () - #13 - #14 0x400dc8b0 in ?? () - #15 0x80545fd in ?? () - #16 0x804daae in ?? () - #17 0x8054334 in ?? () - #18 0x804d23e in ?? () - #19 0x8049632 in ?? () - #20 0x80491d2 in ?? () - #21 0x80596b5 in ?? () - (gdb) p (void *)1342179328 - $3 = (void *) 0x50000800 - - - - - - Going up the stack to the segv_handler frame and looking at where in - the code the access happened shows that it happened near line 110 of - block_dev.c: - - - - - - - - - - (gdb) up - #1 0x1007584d in __sleep (seconds=1000000) - at ../sysdeps/unix/sysv/linux/sleep.c:78 - ../sysdeps/unix/sysv/linux/sleep.c:78: No such file or directory. - (gdb) - #2 0x1006ce9a in stop () at user_util.c:191 - 191 while(1) sleep(1000000); - (gdb) - #3 0x1006bf88 in segv (address=1342179328, is_write=2) at trap_kern.c:31 - 31 KERN_UNTESTED(); - (gdb) - #4 0x1006c628 in segv_handler (sc=0x5006eaf8) at trap_user.c:174 - 174 segv(sc->cr2, sc->err & 2); - (gdb) p *sc - $1 = {gs = 0, __gsh = 0, fs = 0, __fsh = 0, es = 43, __esh = 0, ds = 43, - __dsh = 0, edi = 1342179328, esi = 134973440, ebp = 1342631484, - esp = 1342630864, ebx = 256, edx = 0, ecx = 256, eax = 1024, trapno = 14, - err = 6, eip = 268550834, cs = 35, __csh = 0, eflags = 66070, - esp_at_signal = 1342630864, ss = 43, __ssh = 0, fpstate = 0x0, oldmask = 0, - cr2 = 1342179328} - (gdb) p (void *)268550834 - $2 = (void *) 0x1001c2b2 - (gdb) i sym $2 - block_write + 1090 in section .text - (gdb) i line *$2 - Line 209 of "/home/dike/linux/2.3.26/um/include/asm/arch/string.h" - starts at address 0x1001c2a1 - and ends at 0x1001c2bf . - (gdb) i line *0x1001c2c0 - Line 110 of "block_dev.c" starts at address 0x1001c2bf - and ends at 0x1001c2e3 . - - - - - - Looking at the source shows that the fault happened during a call to - copy_to_user to copy the data into the kernel: - - - 107 count -= chars; - 108 copy_from_user(p,buf,chars); - 109 p += chars; - 110 buf += chars; - - - - - - p is the pointer which must contain 0x50000800, since buf contains - 0x80b8800 (frame 8 above). It is defined as: - - - p = offset + bh->b_data; - - - - - - I need to figure out what bh is, and it just so happens that bh is - passed as an argument to mark_buffer_uptodate and mark_buffer_dirty a - few lines later, so I do a little disassembly: - - - - - (gdb) disas 0x1001c2bf 0x1001c2e0 - Dump of assembler code from 0x1001c2bf to 0x1001c2d0: - 0x1001c2bf : addl %eax,0xc(%ebp) - 0x1001c2c2 : movl 0xfffffdd4(%ebp),%edx - 0x1001c2c8 : btsl $0x0,0x18(%edx) - 0x1001c2cd : btsl $0x1,0x18(%edx) - 0x1001c2d2 : sbbl %ecx,%ecx - 0x1001c2d4 : testl %ecx,%ecx - 0x1001c2d6 : jne 0x1001c2e3 - 0x1001c2d8 : pushl $0x0 - 0x1001c2da : pushl %edx - 0x1001c2db : call 0x1001819c <__mark_buffer_dirty> - End of assembler dump. - - - - - - At that point, bh is in %edx (address 0x1001c2da), which is calculated - at 0x1001c2c2 as %ebp + 0xfffffdd4, so I figure exactly what that is, - taking %ebp from the sigcontext_struct above: - - - (gdb) p (void *)1342631484 - $5 = (void *) 0x5006ee3c - (gdb) p 0x5006ee3c+0xfffffdd4 - $6 = 1342630928 - (gdb) p (void *)$6 - $7 = (void *) 0x5006ec10 - (gdb) p *((void **)$7) - $8 = (void *) 0x50100200 - - - - - - Now, I look at the structure to see what's in it, and particularly, - what its b_data field contains: - - - (gdb) p *((struct buffer_head *)0x50100200) - $13 = {b_next = 0x50289380, b_blocknr = 49405, b_size = 1024, b_list = 0, - b_dev = 15872, b_count = {counter = 1}, b_rdev = 15872, b_state = 24, - b_flushtime = 0, b_next_free = 0x501001a0, b_prev_free = 0x50100260, - b_this_page = 0x501001a0, b_reqnext = 0x0, b_pprev = 0x507fcf58, - b_data = 0x50000800 "", b_page = 0x50004000, - b_end_io = 0x10017f60 , b_dev_id = 0x0, - b_rsector = 98810, b_wait = {lock = , - task_list = {next = 0x50100248, prev = 0x50100248}, __magic = 1343226448, - __creator = 0}, b_kiobuf = 0x0} - - - - - - The b_data field is indeed 0x50000800, so the question becomes how - that happened. The rest of the structure looks fine, so this probably - is not a case of data corruption. It happened on purpose somehow. - - - The b_page field is a pointer to the page_struct representing the - 0x50000000 page. Looking at it shows the kernel's idea of the state - of that page: - - - - (gdb) p *$13.b_page - $17 = {list = {next = 0x50004a5c, prev = 0x100c5174}, mapping = 0x0, - index = 0, next_hash = 0x0, count = {counter = 1}, flags = 132, lru = { - next = 0x50008460, prev = 0x50019350}, wait = { - lock = , task_list = {next = 0x50004024, - prev = 0x50004024}, __magic = 1342193708, __creator = 0}, - pprev_hash = 0x0, buffers = 0x501002c0, virtual = 1342177280, - zone = 0x100c5160} - - - - - - Some sanity-checking: the virtual field shows the "virtual" address of - this page, which in this kernel is the same as its "physical" address, - and the page_struct itself should be mem_map[0], since it represents - the first page of memory: - - - - (gdb) p (void *)1342177280 - $18 = (void *) 0x50000000 - (gdb) p mem_map - $19 = (mem_map_t *) 0x50004000 - - - - - - These check out fine. - - - Now to check out the page_struct itself. In particular, the flags - field shows whether the page is considered free or not: - - - (gdb) p (void *)132 - $21 = (void *) 0x84 - - - - - - The "reserved" bit is the high bit, which is definitely not set, so - the kernel considers the signal stack page to be free and available to - be used. - - - At this point, I jump to conclusions and start looking at my early - boot code, because that's where that page is supposed to be reserved. - - - In my setup_arch procedure, I have the following code which looks just - fine: - - - - bootmap_size = init_bootmem(start_pfn, end_pfn - start_pfn); - free_bootmem(__pa(low_physmem) + bootmap_size, high_physmem - low_physmem); - - - - - - Two stack pages have already been allocated, and low_physmem points to - the third page, which is the beginning of free memory. - The init_bootmem call declares the entire memory to the boot memory - manager, which marks it all reserved. The free_bootmem call frees up - all of it, except for the first two pages. This looks correct to me. - - - So, I decide to see init_bootmem run and make sure that it is marking - those first two pages as reserved. I never get that far. - - - Stepping into init_bootmem, and looking at bootmem_map before looking - at what it contains shows the following: - - - - (gdb) p bootmem_map - $3 = (void *) 0x50000000 - - - - - - Aha! The light dawns. That first page is doing double duty as a - stack and as the boot memory map. The last thing that the boot memory - manager does is to free the pages used by its memory map, so this page - is getting freed even its marked as reserved. - - - The fix was to initialize the boot memory manager before allocating - those two stack pages, and then allocate them through the boot memory - manager. After doing this, and fixing a couple of subsequent buglets, - the stack corruption problem disappeared. - - - - - - 1133.. WWhhaatt ttoo ddoo wwhheenn UUMMLL ddooeessnn''tt wwoorrkk - - - - - 1133..11.. SSttrraannggee ccoommppiillaattiioonn eerrrroorrss wwhheenn yyoouu bbuuiilldd ffrroomm ssoouurrccee - - As of test11, it is necessary to have "ARCH=um" in the environment or - on the make command line for all steps in building UML, including - clean, distclean, or mrproper, config, menuconfig, or xconfig, dep, - and linux. If you forget for any of them, the i386 build seems to - contaminate the UML build. If this happens, start from scratch with - - - host% - make mrproper ARCH=um - - - - - and repeat the build process with ARCH=um on all the steps. - - - See ``Compiling the kernel and modules'' for more details. - - - Another cause of strange compilation errors is building UML in - /usr/src/linux. If you do this, the first thing you need to do is - clean up the mess you made. The /usr/src/linux/asm link will now - point to /usr/src/linux/asm-um. Make it point back to - /usr/src/linux/asm-i386. Then, move your UML pool someplace else and - build it there. Also see below, where a more specific set of symptoms - is described. - - - - 1133..33.. AA vvaarriieettyy ooff ppaanniiccss aanndd hhaannggss wwiitthh //ttmmpp oonn aa rreeiisseerrffss ffiilleessyyss-- - tteemm - - I saw this on reiserfs 3.5.21 and it seems to be fixed in 3.5.27. - Panics preceded by - - - Detaching pid nnnn - - - - are diagnostic of this problem. This is a reiserfs bug which causes a - thread to occasionally read stale data from a mmapped page shared with - another thread. The fix is to upgrade the filesystem or to have /tmp - be an ext2 filesystem. - - - - 1133..44.. TThhee ccoommppiillee ffaaiillss wwiitthh eerrrroorrss aabboouutt ccoonnfflliiccttiinngg ttyyppeess ffoorr - ''ooppeenn'',, ''dduupp'',, aanndd ''wwaaiittppiidd'' - - This happens when you build in /usr/src/linux. The UML build makes - the include/asm link point to include/asm-um. /usr/include/asm points - to /usr/src/linux/include/asm, so when that link gets moved, files - which need to include the asm-i386 versions of headers get the - incompatible asm-um versions. The fix is to move the include/asm link - back to include/asm-i386 and to do UML builds someplace else. - - - - 1133..55.. UUMMLL ddooeessnn''tt wwoorrkk wwhheenn //ttmmpp iiss aann NNFFSS ffiilleessyysstteemm - - This seems to be a similar situation with the ReiserFS problem above. - Some versions of NFS seems not to handle mmap correctly, which UML - depends on. The workaround is have /tmp be a non-NFS directory. - - - 1133..66.. UUMMLL hhaannggss oonn bboooott wwhheenn ccoommppiilleedd wwiitthh ggpprrooff ssuuppppoorrtt - - If you build UML with gprof support and, early in the boot, it does - this - - - kernel BUG at page_alloc.c:100! - - - - - you have a buggy gcc. You can work around the problem by removing - UM_FASTCALL from CFLAGS in arch/um/Makefile-i386. This will open up - another bug, but that one is fairly hard to reproduce. - - - - 1133..77.. ssyyssllooggdd ddiieess wwiitthh aa SSIIGGTTEERRMM oonn ssttaarrttuupp - - The exact boot error depends on the distribution that you're booting, - but Debian produces this: - - - /etc/rc2.d/S10sysklogd: line 49: 93 Terminated - start-stop-daemon --start --quiet --exec /sbin/syslogd -- $SYSLOGD - - - - - This is a syslogd bug. There's a race between a parent process - installing a signal handler and its child sending the signal. See - this uml-devel post for the details. - - - - 1133..88.. TTUUNN//TTAAPP nneettwwoorrkkiinngg ddooeessnn''tt wwoorrkk oonn aa 22..44 hhoosstt - - There are a couple of problems which were - name="pointed - out"> by Tim Robinson - - +o It doesn't work on hosts running 2.4.7 (or thereabouts) or earlier. - The fix is to upgrade to something more recent and then read the - next item. - - +o If you see - - - File descriptor in bad state - - - - when you bring up the device inside UML, you have a header mismatch - between the original kernel and the upgraded one. Make /usr/src/linux - point at the new headers. This will only be a problem if you build - uml_net yourself. - - - - 1133..99.. YYoouu ccaann nneettwwoorrkk ttoo tthhee hhoosstt bbuutt nnoott ttoo ootthheerr mmaacchhiinneess oonn tthhee - nneett - - If you can connect to the host, and the host can connect to UML, but - you cannot connect to any other machines, then you may need to enable - IP Masquerading on the host. Usually this is only experienced when - using private IP addresses (192.168.x.x or 10.x.x.x) for host/UML - networking, rather than the public address space that your host is - connected to. UML does not enable IP Masquerading, so you will need - to create a static rule to enable it: - - - host% - iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE - - - - - Replace eth0 with the interface that you use to talk to the rest of - the world. - - - Documentation on IP Masquerading, and SNAT, can be found at - www.netfilter.org . - - - If you can reach the local net, but not the outside Internet, then - that is usually a routing problem. The UML needs a default route: - - - UML# - route add default gw gateway IP - - - - - The gateway IP can be any machine on the local net that knows how to - reach the outside world. Usually, this is the host or the local net- - work's gateway. - - - Occasionally, we hear from someone who can reach some machines, but - not others on the same net, or who can reach some ports on other - machines, but not others. These are usually caused by strange - firewalling somewhere between the UML and the other box. You track - this down by running tcpdump on every interface the packets travel - over and see where they disappear. When you find a machine that takes - the packets in, but does not send them onward, that's the culprit. - - - - 1133..1100.. II hhaavvee nnoo rroooott aanndd II wwaanntt ttoo ssccrreeaamm - - Thanks to Birgit Wahlich for telling me about this strange one. It - turns out that there's a limit of six environment variables on the - kernel command line. When that limit is reached or exceeded, argument - processing stops, which means that the 'root=' argument that UML - usually adds is not seen. So, the filesystem has no idea what the - root device is, so it panics. - - - The fix is to put less stuff on the command line. Glomming all your - setup variables into one is probably the best way to go. - - - - 1133..1111.. UUMMLL bbuuiilldd ccoonnfflliicctt bbeettwweeeenn ppttrraaccee..hh aanndd uuccoonntteexxtt..hh - - On some older systems, /usr/include/asm/ptrace.h and - /usr/include/sys/ucontext.h define the same names. So, when they're - included together, the defines from one completely mess up the parsing - of the other, producing errors like: - /usr/include/sys/ucontext.h:47: parse error before - `10' - - - - - plus a pile of warnings. - - - This is a libc botch, which has since been fixed, and I don't see any - way around it besides upgrading. - - - - 1133..1122.. TThhee UUMMLL BBooggooMMiippss iiss eexxaaccttllyy hhaallff tthhee hhoosstt''ss BBooggooMMiippss - - On i386 kernels, there are two ways of running the loop that is used - to calculate the BogoMips rating, using the TSC if it's there or using - a one-instruction loop. The TSC produces twice the BogoMips as the - loop. UML uses the loop, since it has nothing resembling a TSC, and - will get almost exactly the same BogoMips as a host using the loop. - However, on a host with a TSC, its BogoMips will be double the loop - BogoMips, and therefore double the UML BogoMips. - - - - 1133..1133.. WWhheenn yyoouu rruunn UUMMLL,, iitt iimmmmeeddiiaatteellyy sseeggffaauullttss - - If the host is configured with the 2G/2G address space split, that's - why. See ``UML on 2G/2G hosts'' for the details on getting UML to - run on your host. - - - - 1133..1144.. xxtteerrmmss aappppeeaarr,, tthheenn iimmmmeeddiiaatteellyy ddiissaappppeeaarr - - If you're running an up to date kernel with an old release of - uml_utilities, the port-helper program will not work properly, so - xterms will exit straight after they appear. The solution is to - upgrade to the latest release of uml_utilities. Usually this problem - occurs when you have installed a packaged release of UML then compiled - your own development kernel without upgrading the uml_utilities from - the source distribution. - - - - 1133..1155.. AAnnyy ootthheerr ppaanniicc,, hhaanngg,, oorr ssttrraannggee bbeehhaavviioorr - - If you're seeing truly strange behavior, such as hangs or panics that - happen in random places, or you try running the debugger to see what's - happening and it acts strangely, then it could be a problem in the - host kernel. If you're not running a stock Linus or -ac kernel, then - try that. An early version of the preemption patch and a 2.4.10 SuSE - kernel have caused very strange problems in UML. - - - Otherwise, let me know about it. Send a message to one of the UML - mailing lists - either the developer list - user-mode-linux-devel at - lists dot sourceforge dot net (subscription info) or the user list - - user-mode-linux-user at lists dot sourceforge do net (subscription - info), whichever you prefer. Don't assume that everyone knows about - it and that a fix is imminent. - - - If you want to be super-helpful, read ``Diagnosing Problems'' and - follow the instructions contained therein. - 1144.. DDiiaaggnnoossiinngg PPrroobblleemmss - - - If you get UML to crash, hang, or otherwise misbehave, you should - report this on one of the project mailing lists, either the developer - list - user-mode-linux-devel at lists dot sourceforge dot net - (subscription info) or the user list - user-mode-linux-user at lists - dot sourceforge dot net (subscription info). When you do, it is - likely that I will want more information. So, it would be helpful to - read the stuff below, do whatever is applicable in your case, and - report the results to the list. - - - For any diagnosis, you're going to need to build a debugging kernel. - The binaries from this site aren't debuggable. If you haven't done - this before, read about ``Compiling the kernel and modules'' and - ``Kernel debugging'' UML first. - - - 1144..11.. CCaassee 11 :: NNoorrmmaall kkeerrnneell ppaanniiccss - - The most common case is for a normal thread to panic. To debug this, - you will need to run it under the debugger (add 'debug' to the command - line). An xterm will start up with gdb running inside it. Continue - it when it stops in start_kernel and make it crash. Now ^C gdb and - - - If the panic was a "Kernel mode fault", then there will be a segv - frame on the stack and I'm going to want some more information. The - stack might look something like this: - - - (UML gdb) backtrace - #0 0x1009bf76 in __sigprocmask (how=1, set=0x5f347940, oset=0x0) - at ../sysdeps/unix/sysv/linux/sigprocmask.c:49 - #1 0x10091411 in change_sig (signal=10, on=1) at process.c:218 - #2 0x10094785 in timer_handler (sig=26) at time_kern.c:32 - #3 0x1009bf38 in __restore () - at ../sysdeps/unix/sysv/linux/i386/sigaction.c:125 - #4 0x1009534c in segv (address=8, ip=268849158, is_write=2, is_user=0) - at trap_kern.c:66 - #5 0x10095c04 in segv_handler (sig=11) at trap_user.c:285 - #6 0x1009bf38 in __restore () - - - - - I'm going to want to see the symbol and line information for the value - of ip in the segv frame. In this case, you would do the following: - - - (UML gdb) i sym 268849158 - - - - - and - - - (UML gdb) i line *268849158 - - - - - The reason for this is the __restore frame right above the segv_han- - dler frame is hiding the frame that actually segfaulted. So, I have - to get that information from the faulting ip. - - - 1144..22.. CCaassee 22 :: TTrraacciinngg tthhrreeaadd ppaanniiccss - - The less common and more painful case is when the tracing thread - panics. In this case, the kernel debugger will be useless because it - needs a healthy tracing thread in order to work. The first thing to - do is get a backtrace from the tracing thread. This is done by - figuring out what its pid is, firing up gdb, and attaching it to that - pid. You can figure out the tracing thread pid by looking at the - first line of the console output, which will look like this: - - - tracing thread pid = 15851 - - - - - or by running ps on the host and finding the line that looks like - this: - - - jdike 15851 4.5 0.4 132568 1104 pts/0 S 21:34 0:05 ./linux [(tracing thread)] - - - - - If the panic was 'segfault in signals', then follow the instructions - above for collecting information about the location of the seg fault. - - - If the tracing thread flaked out all by itself, then send that - backtrace in and wait for our crack debugging team to fix the problem. - - - 1144..33.. CCaassee 33 :: TTrraacciinngg tthhrreeaadd ppaanniiccss ccaauusseedd bbyy ootthheerr tthhrreeaaddss - - However, there are cases where the misbehavior of another thread - caused the problem. The most common panic of this type is: - - - wait_for_stop failed to wait for to stop with - - - - - In this case, you'll need to get a backtrace from the process men- - tioned in the panic, which is complicated by the fact that the kernel - debugger is defunct and without some fancy footwork, another gdb can't - attach to it. So, this is how the fancy footwork goes: - - In a shell: - - - host% kill -STOP pid - - - - - Run gdb on the tracing thread as described in case 2 and do: - - - (host gdb) call detach(pid) - - - If you get a segfault, do it again. It always works the second time. - - Detach from the tracing thread and attach to that other thread: - - - (host gdb) detach - - - - - - - (host gdb) attach pid - - - - - If gdb hangs when attaching to that process, go back to a shell and - do: - - - host% - kill -CONT pid - - - - - And then get the backtrace: - - - (host gdb) backtrace - - - - - - 1144..44.. CCaassee 44 :: HHaannggss - - Hangs seem to be fairly rare, but they sometimes happen. When a hang - happens, we need a backtrace from the offending process. Run the - kernel debugger as described in case 1 and get a backtrace. If the - current process is not the idle thread, then send in the backtrace. - You can tell that it's the idle thread if the stack looks like this: - - - #0 0x100b1401 in __libc_nanosleep () - #1 0x100a2885 in idle_sleep (secs=10) at time.c:122 - #2 0x100a546f in do_idle () at process_kern.c:445 - #3 0x100a5508 in cpu_idle () at process_kern.c:471 - #4 0x100ec18f in start_kernel () at init/main.c:592 - #5 0x100a3e10 in start_kernel_proc (unused=0x0) at um_arch.c:71 - #6 0x100a383f in signal_tramp (arg=0x100a3dd8) at trap_user.c:50 - - - - - If this is the case, then some other process is at fault, and went to - sleep when it shouldn't have. Run ps on the host and figure out which - process should not have gone to sleep and stayed asleep. Then attach - to it with gdb and get a backtrace as described in case 3. - - - - - - - 1155.. TThhaannkkss - - - A number of people have helped this project in various ways, and this - page gives recognition where recognition is due. - - - If you're listed here and you would prefer a real link on your name, - or no link at all, instead of the despammed email address pseudo-link, - let me know. - - - If you're not listed here and you think maybe you should be, please - let me know that as well. I try to get everyone, but sometimes my - bookkeeping lapses and I forget about contributions. - - - 1155..11.. CCooddee aanndd DDooccuummeennttaattiioonn - - Rusty Russell - - - +o wrote the HOWTO - - +o prodded me into making this project official and putting it on - SourceForge - - +o came up with the way cool UML logo - - +o redid the config process - - - Peter Moulder - Fixed my config and build - processes, and added some useful code to the block driver - - - Bill Stearns - - - +o HOWTO updates - - +o lots of bug reports - - +o lots of testing - - +o dedicated a box (uml.ists.dartmouth.edu) to support UML development - - +o wrote the mkrootfs script, which allows bootable filesystems of - RPM-based distributions to be cranked out - - +o cranked out a large number of filesystems with said script - - - Jim Leu - Wrote the virtual ethernet driver - and associated usermode tools - - Lars Brinkhoff - Contributed the ptrace - proxy from his own project to allow easier - kernel debugging - - - Andrea Arcangeli - Redid some of the early boot - code so that it would work on machines with Large File Support - - - Chris Emerson - Did - the first UML port to Linux/ppc - - - Harald Welte - Wrote the multicast - transport for the network driver - - - Jorgen Cederlof - Added special file support to hostfs - - - Greg Lonnon - Changed the ubd driver - to allow it to layer a COW file on a shared read-only filesystem and - wrote the iomem emulation support - - - Henrik Nordstrom - Provided a variety - of patches, fixes, and clues - - - Lennert Buytenhek - Contributed various patches, a rewrite of the - network driver, the first implementation of the mconsole driver, and - did the bulk of the work needed to get SMP working again. - - - Yon Uriarte - Fixed the TUN/TAP network backend while I slept. - - - Adam Heath - Made a bunch of nice cleanups to the initialization code, - plus various other small patches. - - - Matt Zimmerman - Matt volunteered to be the UML Debian maintainer and - is doing a real nice job of it. He also noticed and fixed a number of - actually and potentially exploitable security holes in uml_net. Plus - the occasional patch. I like patches. - - - James McMechan - James seems to have taken over maintenance of the ubd - driver and is doing a nice job of it. - - - Chandan Kudige - wrote the umlgdb script which automates the reloading - of module symbols. - - - Steve Schmidtke - wrote the UML slirp transport and hostaudio drivers, - enabling UML processes to access audio devices on the host. He also - submitted patches for the slip transport and lots of other things. - - - David Coulson - - - +o Set up the usermodelinux.org site, - which is a great way of keeping the UML user community on top of - UML goings-on. - - +o Site documentation and updates - - +o Nifty little UML management daemon UMLd - - - +o Lots of testing and bug reports - - - - - 1155..22.. FFlluusshhiinngg oouutt bbuuggss - - - - +o Yuri Pudgorodsky - - +o Gerald Britton - - +o Ian Wehrman - - +o Gord Lamb - - +o Eugene Koontz - - +o John H. Hartman - - +o Anders Karlsson - - +o Daniel Phillips - - +o John Fremlin - - +o Rainer Burgstaller - - +o James Stevenson - - +o Matt Clay - - +o Cliff Jefferies - - +o Geoff Hoff - - +o Lennert Buytenhek - - +o Al Viro - - +o Frank Klingenhoefer - - +o Livio Baldini Soares - - +o Jon Burgess - - +o Petru Paler - - +o Paul - - +o Chris Reahard - - +o Sverker Nilsson - - +o Gong Su - - +o johan verrept - - +o Bjorn Eriksson - - +o Lorenzo Allegrucci - - +o Muli Ben-Yehuda - - +o David Mansfield - - +o Howard Goff - - +o Mike Anderson - - +o John Byrne - - +o Sapan J. Batia - - +o Iris Huang - - +o Jan Hudec - - +o Voluspa - - - - - 1155..33.. BBuugglleettss aanndd cclleeaann--uuppss - - - - +o Dave Zarzycki - - +o Adam Lazur - - +o Boria Feigin - - +o Brian J. Murrell - - +o JS - - +o Roman Zippel - - +o Wil Cooley - - +o Ayelet Shemesh - - +o Will Dyson - - +o Sverker Nilsson - - +o dvorak - - +o v.naga srinivas - - +o Shlomi Fish - - +o Roger Binns - - +o johan verrept - - +o MrChuoi - - +o Peter Cleve - - +o Vincent Guffens - - +o Nathan Scott - - +o Patrick Caulfield - - +o jbearce - - +o Catalin Marinas - - +o Shane Spencer - - +o Zou Min - - - +o Ryan Boder - - +o Lorenzo Colitti - - +o Gwendal Grignou - - +o Andre' Breiler - - +o Tsutomu Yasuda - - - - 1155..44.. CCaassee SSttuuddiieess - - - +o Jon Wright - - +o William McEwan - - +o Michael Richardson - - - - 1155..55.. OOtthheerr ccoonnttrriibbuuttiioonnss - - - Bill Carr made the Red Hat mkrootfs script - work with RH 6.2. - - Michael Jennings sent in some material which - is now gracing the top of the index page of this site. - - SGI (and more specifically Ralf Baechle ) gave me an account on oss.sgi.com - . The bandwidth there made it possible to - produce most of the filesystems available on the project download - page. - - Laurent Bonnaud took the old grotty - Debian filesystem that I've been distributing and updated it to 2.2. - It is now available by itself here. - - Rik van Riel gave me some ftp space on ftp.nl.linux.org so I can make - releases even when Sourceforge is broken. - - Rodrigo de Castro looked at my broken pte code and told me what was - wrong with it, letting me fix a long-standing (several weeks) and - serious set of bugs. - - Chris Reahard built a specialized root filesystem for running a DNS - server jailed inside UML. It's available from the download - page in the Jail - Filesystems section. - - - - - - - - - - - - diff --git a/Documentation/virtual/kvm/api.txt b/Documentation/virtual/kvm/api.txt new file mode 100644 index 0000000..9bef4e4 --- /dev/null +++ b/Documentation/virtual/kvm/api.txt @@ -0,0 +1,1451 @@ +The Definitive KVM (Kernel-based Virtual Machine) API Documentation +=================================================================== + +1. General description + +The kvm API is a set of ioctls that are issued to control various aspects +of a virtual machine. The ioctls belong to three classes + + - System ioctls: These query and set global attributes which affect the + whole kvm subsystem. In addition a system ioctl is used to create + virtual machines + + - VM ioctls: These query and set attributes that affect an entire virtual + machine, for example memory layout. In addition a VM ioctl is used to + create virtual cpus (vcpus). + + Only run VM ioctls from the same process (address space) that was used + to create the VM. + + - vcpu ioctls: These query and set attributes that control the operation + of a single virtual cpu. + + Only run vcpu ioctls from the same thread that was used to create the + vcpu. + +2. File descriptors + +The kvm API is centered around file descriptors. An initial +open("/dev/kvm") obtains a handle to the kvm subsystem; this handle +can be used to issue system ioctls. A KVM_CREATE_VM ioctl on this +handle will create a VM file descriptor which can be used to issue VM +ioctls. A KVM_CREATE_VCPU ioctl on a VM fd will create a virtual cpu +and return a file descriptor pointing to it. Finally, ioctls on a vcpu +fd can be used to control the vcpu, including the important task of +actually running guest code. + +In general file descriptors can be migrated among processes by means +of fork() and the SCM_RIGHTS facility of unix domain socket. These +kinds of tricks are explicitly not supported by kvm. While they will +not cause harm to the host, their actual behavior is not guaranteed by +the API. The only supported use is one virtual machine per process, +and one vcpu per thread. + +3. Extensions + +As of Linux 2.6.22, the KVM ABI has been stabilized: no backward +incompatible change are allowed. However, there is an extension +facility that allows backward-compatible extensions to the API to be +queried and used. + +The extension mechanism is not based on on the Linux version number. +Instead, kvm defines extension identifiers and a facility to query +whether a particular extension identifier is available. If it is, a +set of ioctls is available for application use. + +4. API description + +This section describes ioctls that can be used to control kvm guests. +For each ioctl, the following information is provided along with a +description: + + Capability: which KVM extension provides this ioctl. Can be 'basic', + which means that is will be provided by any kernel that supports + API version 12 (see section 4.1), or a KVM_CAP_xyz constant, which + means availability needs to be checked with KVM_CHECK_EXTENSION + (see section 4.4). + + Architectures: which instruction set architectures provide this ioctl. + x86 includes both i386 and x86_64. + + Type: system, vm, or vcpu. + + Parameters: what parameters are accepted by the ioctl. + + Returns: the return value. General error numbers (EBADF, ENOMEM, EINVAL) + are not detailed, but errors with specific meanings are. + +4.1 KVM_GET_API_VERSION + +Capability: basic +Architectures: all +Type: system ioctl +Parameters: none +Returns: the constant KVM_API_VERSION (=12) + +This identifies the API version as the stable kvm API. It is not +expected that this number will change. However, Linux 2.6.20 and +2.6.21 report earlier versions; these are not documented and not +supported. Applications should refuse to run if KVM_GET_API_VERSION +returns a value other than 12. If this check passes, all ioctls +described as 'basic' will be available. + +4.2 KVM_CREATE_VM + +Capability: basic +Architectures: all +Type: system ioctl +Parameters: none +Returns: a VM fd that can be used to control the new virtual machine. + +The new VM has no virtual cpus and no memory. An mmap() of a VM fd +will access the virtual machine's physical address space; offset zero +corresponds to guest physical address zero. Use of mmap() on a VM fd +is discouraged if userspace memory allocation (KVM_CAP_USER_MEMORY) is +available. + +4.3 KVM_GET_MSR_INDEX_LIST + +Capability: basic +Architectures: x86 +Type: system +Parameters: struct kvm_msr_list (in/out) +Returns: 0 on success; -1 on error +Errors: + E2BIG: the msr index list is to be to fit in the array specified by + the user. + +struct kvm_msr_list { + __u32 nmsrs; /* number of msrs in entries */ + __u32 indices[0]; +}; + +This ioctl returns the guest msrs that are supported. The list varies +by kvm version and host processor, but does not change otherwise. The +user fills in the size of the indices array in nmsrs, and in return +kvm adjusts nmsrs to reflect the actual number of msrs and fills in +the indices array with their numbers. + +Note: if kvm indicates supports MCE (KVM_CAP_MCE), then the MCE bank MSRs are +not returned in the MSR list, as different vcpus can have a different number +of banks, as set via the KVM_X86_SETUP_MCE ioctl. + +4.4 KVM_CHECK_EXTENSION + +Capability: basic +Architectures: all +Type: system ioctl +Parameters: extension identifier (KVM_CAP_*) +Returns: 0 if unsupported; 1 (or some other positive integer) if supported + +The API allows the application to query about extensions to the core +kvm API. Userspace passes an extension identifier (an integer) and +receives an integer that describes the extension availability. +Generally 0 means no and 1 means yes, but some extensions may report +additional information in the integer return value. + +4.5 KVM_GET_VCPU_MMAP_SIZE + +Capability: basic +Architectures: all +Type: system ioctl +Parameters: none +Returns: size of vcpu mmap area, in bytes + +The KVM_RUN ioctl (cf.) communicates with userspace via a shared +memory region. This ioctl returns the size of that region. See the +KVM_RUN documentation for details. + +4.6 KVM_SET_MEMORY_REGION + +Capability: basic +Architectures: all +Type: vm ioctl +Parameters: struct kvm_memory_region (in) +Returns: 0 on success, -1 on error + +This ioctl is obsolete and has been removed. + +4.7 KVM_CREATE_VCPU + +Capability: basic +Architectures: all +Type: vm ioctl +Parameters: vcpu id (apic id on x86) +Returns: vcpu fd on success, -1 on error + +This API adds a vcpu to a virtual machine. The vcpu id is a small integer +in the range [0, max_vcpus). + +4.8 KVM_GET_DIRTY_LOG (vm ioctl) + +Capability: basic +Architectures: x86 +Type: vm ioctl +Parameters: struct kvm_dirty_log (in/out) +Returns: 0 on success, -1 on error + +/* for KVM_GET_DIRTY_LOG */ +struct kvm_dirty_log { + __u32 slot; + __u32 padding; + union { + void __user *dirty_bitmap; /* one bit per page */ + __u64 padding; + }; +}; + +Given a memory slot, return a bitmap containing any pages dirtied +since the last call to this ioctl. Bit 0 is the first page in the +memory slot. Ensure the entire structure is cleared to avoid padding +issues. + +4.9 KVM_SET_MEMORY_ALIAS + +Capability: basic +Architectures: x86 +Type: vm ioctl +Parameters: struct kvm_memory_alias (in) +Returns: 0 (success), -1 (error) + +This ioctl is obsolete and has been removed. + +4.10 KVM_RUN + +Capability: basic +Architectures: all +Type: vcpu ioctl +Parameters: none +Returns: 0 on success, -1 on error +Errors: + EINTR: an unmasked signal is pending + +This ioctl is used to run a guest virtual cpu. While there are no +explicit parameters, there is an implicit parameter block that can be +obtained by mmap()ing the vcpu fd at offset 0, with the size given by +KVM_GET_VCPU_MMAP_SIZE. The parameter block is formatted as a 'struct +kvm_run' (see below). + +4.11 KVM_GET_REGS + +Capability: basic +Architectures: all +Type: vcpu ioctl +Parameters: struct kvm_regs (out) +Returns: 0 on success, -1 on error + +Reads the general purpose registers from the vcpu. + +/* x86 */ +struct kvm_regs { + /* out (KVM_GET_REGS) / in (KVM_SET_REGS) */ + __u64 rax, rbx, rcx, rdx; + __u64 rsi, rdi, rsp, rbp; + __u64 r8, r9, r10, r11; + __u64 r12, r13, r14, r15; + __u64 rip, rflags; +}; + +4.12 KVM_SET_REGS + +Capability: basic +Architectures: all +Type: vcpu ioctl +Parameters: struct kvm_regs (in) +Returns: 0 on success, -1 on error + +Writes the general purpose registers into the vcpu. + +See KVM_GET_REGS for the data structure. + +4.13 KVM_GET_SREGS + +Capability: basic +Architectures: x86 +Type: vcpu ioctl +Parameters: struct kvm_sregs (out) +Returns: 0 on success, -1 on error + +Reads special registers from the vcpu. + +/* x86 */ +struct kvm_sregs { + struct kvm_segment cs, ds, es, fs, gs, ss; + struct kvm_segment tr, ldt; + struct kvm_dtable gdt, idt; + __u64 cr0, cr2, cr3, cr4, cr8; + __u64 efer; + __u64 apic_base; + __u64 interrupt_bitmap[(KVM_NR_INTERRUPTS + 63) / 64]; +}; + +interrupt_bitmap is a bitmap of pending external interrupts. At most +one bit may be set. This interrupt has been acknowledged by the APIC +but not yet injected into the cpu core. + +4.14 KVM_SET_SREGS + +Capability: basic +Architectures: x86 +Type: vcpu ioctl +Parameters: struct kvm_sregs (in) +Returns: 0 on success, -1 on error + +Writes special registers into the vcpu. See KVM_GET_SREGS for the +data structures. + +4.15 KVM_TRANSLATE + +Capability: basic +Architectures: x86 +Type: vcpu ioctl +Parameters: struct kvm_translation (in/out) +Returns: 0 on success, -1 on error + +Translates a virtual address according to the vcpu's current address +translation mode. + +struct kvm_translation { + /* in */ + __u64 linear_address; + + /* out */ + __u64 physical_address; + __u8 valid; + __u8 writeable; + __u8 usermode; + __u8 pad[5]; +}; + +4.16 KVM_INTERRUPT + +Capability: basic +Architectures: x86, ppc +Type: vcpu ioctl +Parameters: struct kvm_interrupt (in) +Returns: 0 on success, -1 on error + +Queues a hardware interrupt vector to be injected. This is only +useful if in-kernel local APIC or equivalent is not used. + +/* for KVM_INTERRUPT */ +struct kvm_interrupt { + /* in */ + __u32 irq; +}; + +X86: + +Note 'irq' is an interrupt vector, not an interrupt pin or line. + +PPC: + +Queues an external interrupt to be injected. This ioctl is overleaded +with 3 different irq values: + +a) KVM_INTERRUPT_SET + + This injects an edge type external interrupt into the guest once it's ready + to receive interrupts. When injected, the interrupt is done. + +b) KVM_INTERRUPT_UNSET + + This unsets any pending interrupt. + + Only available with KVM_CAP_PPC_UNSET_IRQ. + +c) KVM_INTERRUPT_SET_LEVEL + + This injects a level type external interrupt into the guest context. The + interrupt stays pending until a specific ioctl with KVM_INTERRUPT_UNSET + is triggered. + + Only available with KVM_CAP_PPC_IRQ_LEVEL. + +Note that any value for 'irq' other than the ones stated above is invalid +and incurs unexpected behavior. + +4.17 KVM_DEBUG_GUEST + +Capability: basic +Architectures: none +Type: vcpu ioctl +Parameters: none) +Returns: -1 on error + +Support for this has been removed. Use KVM_SET_GUEST_DEBUG instead. + +4.18 KVM_GET_MSRS + +Capability: basic +Architectures: x86 +Type: vcpu ioctl +Parameters: struct kvm_msrs (in/out) +Returns: 0 on success, -1 on error + +Reads model-specific registers from the vcpu. Supported msr indices can +be obtained using KVM_GET_MSR_INDEX_LIST. + +struct kvm_msrs { + __u32 nmsrs; /* number of msrs in entries */ + __u32 pad; + + struct kvm_msr_entry entries[0]; +}; + +struct kvm_msr_entry { + __u32 index; + __u32 reserved; + __u64 data; +}; + +Application code should set the 'nmsrs' member (which indicates the +size of the entries array) and the 'index' member of each array entry. +kvm will fill in the 'data' member. + +4.19 KVM_SET_MSRS + +Capability: basic +Architectures: x86 +Type: vcpu ioctl +Parameters: struct kvm_msrs (in) +Returns: 0 on success, -1 on error + +Writes model-specific registers to the vcpu. See KVM_GET_MSRS for the +data structures. + +Application code should set the 'nmsrs' member (which indicates the +size of the entries array), and the 'index' and 'data' members of each +array entry. + +4.20 KVM_SET_CPUID + +Capability: basic +Architectures: x86 +Type: vcpu ioctl +Parameters: struct kvm_cpuid (in) +Returns: 0 on success, -1 on error + +Defines the vcpu responses to the cpuid instruction. Applications +should use the KVM_SET_CPUID2 ioctl if available. + + +struct kvm_cpuid_entry { + __u32 function; + __u32 eax; + __u32 ebx; + __u32 ecx; + __u32 edx; + __u32 padding; +}; + +/* for KVM_SET_CPUID */ +struct kvm_cpuid { + __u32 nent; + __u32 padding; + struct kvm_cpuid_entry entries[0]; +}; + +4.21 KVM_SET_SIGNAL_MASK + +Capability: basic +Architectures: x86 +Type: vcpu ioctl +Parameters: struct kvm_signal_mask (in) +Returns: 0 on success, -1 on error + +Defines which signals are blocked during execution of KVM_RUN. This +signal mask temporarily overrides the threads signal mask. Any +unblocked signal received (except SIGKILL and SIGSTOP, which retain +their traditional behaviour) will cause KVM_RUN to return with -EINTR. + +Note the signal will only be delivered if not blocked by the original +signal mask. + +/* for KVM_SET_SIGNAL_MASK */ +struct kvm_signal_mask { + __u32 len; + __u8 sigset[0]; +}; + +4.22 KVM_GET_FPU + +Capability: basic +Architectures: x86 +Type: vcpu ioctl +Parameters: struct kvm_fpu (out) +Returns: 0 on success, -1 on error + +Reads the floating point state from the vcpu. + +/* for KVM_GET_FPU and KVM_SET_FPU */ +struct kvm_fpu { + __u8 fpr[8][16]; + __u16 fcw; + __u16 fsw; + __u8 ftwx; /* in fxsave format */ + __u8 pad1; + __u16 last_opcode; + __u64 last_ip; + __u64 last_dp; + __u8 xmm[16][16]; + __u32 mxcsr; + __u32 pad2; +}; + +4.23 KVM_SET_FPU + +Capability: basic +Architectures: x86 +Type: vcpu ioctl +Parameters: struct kvm_fpu (in) +Returns: 0 on success, -1 on error + +Writes the floating point state to the vcpu. + +/* for KVM_GET_FPU and KVM_SET_FPU */ +struct kvm_fpu { + __u8 fpr[8][16]; + __u16 fcw; + __u16 fsw; + __u8 ftwx; /* in fxsave format */ + __u8 pad1; + __u16 last_opcode; + __u64 last_ip; + __u64 last_dp; + __u8 xmm[16][16]; + __u32 mxcsr; + __u32 pad2; +}; + +4.24 KVM_CREATE_IRQCHIP + +Capability: KVM_CAP_IRQCHIP +Architectures: x86, ia64 +Type: vm ioctl +Parameters: none +Returns: 0 on success, -1 on error + +Creates an interrupt controller model in the kernel. On x86, creates a virtual +ioapic, a virtual PIC (two PICs, nested), and sets up future vcpus to have a +local APIC. IRQ routing for GSIs 0-15 is set to both PIC and IOAPIC; GSI 16-23 +only go to the IOAPIC. On ia64, a IOSAPIC is created. + +4.25 KVM_IRQ_LINE + +Capability: KVM_CAP_IRQCHIP +Architectures: x86, ia64 +Type: vm ioctl +Parameters: struct kvm_irq_level +Returns: 0 on success, -1 on error + +Sets the level of a GSI input to the interrupt controller model in the kernel. +Requires that an interrupt controller model has been previously created with +KVM_CREATE_IRQCHIP. Note that edge-triggered interrupts require the level +to be set to 1 and then back to 0. + +struct kvm_irq_level { + union { + __u32 irq; /* GSI */ + __s32 status; /* not used for KVM_IRQ_LEVEL */ + }; + __u32 level; /* 0 or 1 */ +}; + +4.26 KVM_GET_IRQCHIP + +Capability: KVM_CAP_IRQCHIP +Architectures: x86, ia64 +Type: vm ioctl +Parameters: struct kvm_irqchip (in/out) +Returns: 0 on success, -1 on error + +Reads the state of a kernel interrupt controller created with +KVM_CREATE_IRQCHIP into a buffer provided by the caller. + +struct kvm_irqchip { + __u32 chip_id; /* 0 = PIC1, 1 = PIC2, 2 = IOAPIC */ + __u32 pad; + union { + char dummy[512]; /* reserving space */ + struct kvm_pic_state pic; + struct kvm_ioapic_state ioapic; + } chip; +}; + +4.27 KVM_SET_IRQCHIP + +Capability: KVM_CAP_IRQCHIP +Architectures: x86, ia64 +Type: vm ioctl +Parameters: struct kvm_irqchip (in) +Returns: 0 on success, -1 on error + +Sets the state of a kernel interrupt controller created with +KVM_CREATE_IRQCHIP from a buffer provided by the caller. + +struct kvm_irqchip { + __u32 chip_id; /* 0 = PIC1, 1 = PIC2, 2 = IOAPIC */ + __u32 pad; + union { + char dummy[512]; /* reserving space */ + struct kvm_pic_state pic; + struct kvm_ioapic_state ioapic; + } chip; +}; + +4.28 KVM_XEN_HVM_CONFIG + +Capability: KVM_CAP_XEN_HVM +Architectures: x86 +Type: vm ioctl +Parameters: struct kvm_xen_hvm_config (in) +Returns: 0 on success, -1 on error + +Sets the MSR that the Xen HVM guest uses to initialize its hypercall +page, and provides the starting address and size of the hypercall +blobs in userspace. When the guest writes the MSR, kvm copies one +page of a blob (32- or 64-bit, depending on the vcpu mode) to guest +memory. + +struct kvm_xen_hvm_config { + __u32 flags; + __u32 msr; + __u64 blob_addr_32; + __u64 blob_addr_64; + __u8 blob_size_32; + __u8 blob_size_64; + __u8 pad2[30]; +}; + +4.29 KVM_GET_CLOCK + +Capability: KVM_CAP_ADJUST_CLOCK +Architectures: x86 +Type: vm ioctl +Parameters: struct kvm_clock_data (out) +Returns: 0 on success, -1 on error + +Gets the current timestamp of kvmclock as seen by the current guest. In +conjunction with KVM_SET_CLOCK, it is used to ensure monotonicity on scenarios +such as migration. + +struct kvm_clock_data { + __u64 clock; /* kvmclock current value */ + __u32 flags; + __u32 pad[9]; +}; + +4.30 KVM_SET_CLOCK + +Capability: KVM_CAP_ADJUST_CLOCK +Architectures: x86 +Type: vm ioctl +Parameters: struct kvm_clock_data (in) +Returns: 0 on success, -1 on error + +Sets the current timestamp of kvmclock to the value specified in its parameter. +In conjunction with KVM_GET_CLOCK, it is used to ensure monotonicity on scenarios +such as migration. + +struct kvm_clock_data { + __u64 clock; /* kvmclock current value */ + __u32 flags; + __u32 pad[9]; +}; + +4.31 KVM_GET_VCPU_EVENTS + +Capability: KVM_CAP_VCPU_EVENTS +Extended by: KVM_CAP_INTR_SHADOW +Architectures: x86 +Type: vm ioctl +Parameters: struct kvm_vcpu_event (out) +Returns: 0 on success, -1 on error + +Gets currently pending exceptions, interrupts, and NMIs as well as related +states of the vcpu. + +struct kvm_vcpu_events { + struct { + __u8 injected; + __u8 nr; + __u8 has_error_code; + __u8 pad; + __u32 error_code; + } exception; + struct { + __u8 injected; + __u8 nr; + __u8 soft; + __u8 shadow; + } interrupt; + struct { + __u8 injected; + __u8 pending; + __u8 masked; + __u8 pad; + } nmi; + __u32 sipi_vector; + __u32 flags; +}; + +KVM_VCPUEVENT_VALID_SHADOW may be set in the flags field to signal that +interrupt.shadow contains a valid state. Otherwise, this field is undefined. + +4.32 KVM_SET_VCPU_EVENTS + +Capability: KVM_CAP_VCPU_EVENTS +Extended by: KVM_CAP_INTR_SHADOW +Architectures: x86 +Type: vm ioctl +Parameters: struct kvm_vcpu_event (in) +Returns: 0 on success, -1 on error + +Set pending exceptions, interrupts, and NMIs as well as related states of the +vcpu. + +See KVM_GET_VCPU_EVENTS for the data structure. + +Fields that may be modified asynchronously by running VCPUs can be excluded +from the update. These fields are nmi.pending and sipi_vector. Keep the +corresponding bits in the flags field cleared to suppress overwriting the +current in-kernel state. The bits are: + +KVM_VCPUEVENT_VALID_NMI_PENDING - transfer nmi.pending to the kernel +KVM_VCPUEVENT_VALID_SIPI_VECTOR - transfer sipi_vector + +If KVM_CAP_INTR_SHADOW is available, KVM_VCPUEVENT_VALID_SHADOW can be set in +the flags field to signal that interrupt.shadow contains a valid state and +shall be written into the VCPU. + +4.33 KVM_GET_DEBUGREGS + +Capability: KVM_CAP_DEBUGREGS +Architectures: x86 +Type: vm ioctl +Parameters: struct kvm_debugregs (out) +Returns: 0 on success, -1 on error + +Reads debug registers from the vcpu. + +struct kvm_debugregs { + __u64 db[4]; + __u64 dr6; + __u64 dr7; + __u64 flags; + __u64 reserved[9]; +}; + +4.34 KVM_SET_DEBUGREGS + +Capability: KVM_CAP_DEBUGREGS +Architectures: x86 +Type: vm ioctl +Parameters: struct kvm_debugregs (in) +Returns: 0 on success, -1 on error + +Writes debug registers into the vcpu. + +See KVM_GET_DEBUGREGS for the data structure. The flags field is unused +yet and must be cleared on entry. + +4.35 KVM_SET_USER_MEMORY_REGION + +Capability: KVM_CAP_USER_MEM +Architectures: all +Type: vm ioctl +Parameters: struct kvm_userspace_memory_region (in) +Returns: 0 on success, -1 on error + +struct kvm_userspace_memory_region { + __u32 slot; + __u32 flags; + __u64 guest_phys_addr; + __u64 memory_size; /* bytes */ + __u64 userspace_addr; /* start of the userspace allocated memory */ +}; + +/* for kvm_memory_region::flags */ +#define KVM_MEM_LOG_DIRTY_PAGES 1UL + +This ioctl allows the user to create or modify a guest physical memory +slot. When changing an existing slot, it may be moved in the guest +physical memory space, or its flags may be modified. It may not be +resized. Slots may not overlap in guest physical address space. + +Memory for the region is taken starting at the address denoted by the +field userspace_addr, which must point at user addressable memory for +the entire memory slot size. Any object may back this memory, including +anonymous memory, ordinary files, and hugetlbfs. + +It is recommended that the lower 21 bits of guest_phys_addr and userspace_addr +be identical. This allows large pages in the guest to be backed by large +pages in the host. + +The flags field supports just one flag, KVM_MEM_LOG_DIRTY_PAGES, which +instructs kvm to keep track of writes to memory within the slot. See +the KVM_GET_DIRTY_LOG ioctl. + +When the KVM_CAP_SYNC_MMU capability, changes in the backing of the memory +region are automatically reflected into the guest. For example, an mmap() +that affects the region will be made visible immediately. Another example +is madvise(MADV_DROP). + +It is recommended to use this API instead of the KVM_SET_MEMORY_REGION ioctl. +The KVM_SET_MEMORY_REGION does not allow fine grained control over memory +allocation and is deprecated. + +4.36 KVM_SET_TSS_ADDR + +Capability: KVM_CAP_SET_TSS_ADDR +Architectures: x86 +Type: vm ioctl +Parameters: unsigned long tss_address (in) +Returns: 0 on success, -1 on error + +This ioctl defines the physical address of a three-page region in the guest +physical address space. The region must be within the first 4GB of the +guest physical address space and must not conflict with any memory slot +or any mmio address. The guest may malfunction if it accesses this memory +region. + +This ioctl is required on Intel-based hosts. This is needed on Intel hardware +because of a quirk in the virtualization implementation (see the internals +documentation when it pops into existence). + +4.37 KVM_ENABLE_CAP + +Capability: KVM_CAP_ENABLE_CAP +Architectures: ppc +Type: vcpu ioctl +Parameters: struct kvm_enable_cap (in) +Returns: 0 on success; -1 on error + ++Not all extensions are enabled by default. Using this ioctl the application +can enable an extension, making it available to the guest. + +On systems that do not support this ioctl, it always fails. On systems that +do support it, it only works for extensions that are supported for enablement. + +To check if a capability can be enabled, the KVM_CHECK_EXTENSION ioctl should +be used. + +struct kvm_enable_cap { + /* in */ + __u32 cap; + +The capability that is supposed to get enabled. + + __u32 flags; + +A bitfield indicating future enhancements. Has to be 0 for now. + + __u64 args[4]; + +Arguments for enabling a feature. If a feature needs initial values to +function properly, this is the place to put them. + + __u8 pad[64]; +}; + +4.38 KVM_GET_MP_STATE + +Capability: KVM_CAP_MP_STATE +Architectures: x86, ia64 +Type: vcpu ioctl +Parameters: struct kvm_mp_state (out) +Returns: 0 on success; -1 on error + +struct kvm_mp_state { + __u32 mp_state; +}; + +Returns the vcpu's current "multiprocessing state" (though also valid on +uniprocessor guests). + +Possible values are: + + - KVM_MP_STATE_RUNNABLE: the vcpu is currently running + - KVM_MP_STATE_UNINITIALIZED: the vcpu is an application processor (AP) + which has not yet received an INIT signal + - KVM_MP_STATE_INIT_RECEIVED: the vcpu has received an INIT signal, and is + now ready for a SIPI + - KVM_MP_STATE_HALTED: the vcpu has executed a HLT instruction and + is waiting for an interrupt + - KVM_MP_STATE_SIPI_RECEIVED: the vcpu has just received a SIPI (vector + accessible via KVM_GET_VCPU_EVENTS) + +This ioctl is only useful after KVM_CREATE_IRQCHIP. Without an in-kernel +irqchip, the multiprocessing state must be maintained by userspace. + +4.39 KVM_SET_MP_STATE + +Capability: KVM_CAP_MP_STATE +Architectures: x86, ia64 +Type: vcpu ioctl +Parameters: struct kvm_mp_state (in) +Returns: 0 on success; -1 on error + +Sets the vcpu's current "multiprocessing state"; see KVM_GET_MP_STATE for +arguments. + +This ioctl is only useful after KVM_CREATE_IRQCHIP. Without an in-kernel +irqchip, the multiprocessing state must be maintained by userspace. + +4.40 KVM_SET_IDENTITY_MAP_ADDR + +Capability: KVM_CAP_SET_IDENTITY_MAP_ADDR +Architectures: x86 +Type: vm ioctl +Parameters: unsigned long identity (in) +Returns: 0 on success, -1 on error + +This ioctl defines the physical address of a one-page region in the guest +physical address space. The region must be within the first 4GB of the +guest physical address space and must not conflict with any memory slot +or any mmio address. The guest may malfunction if it accesses this memory +region. + +This ioctl is required on Intel-based hosts. This is needed on Intel hardware +because of a quirk in the virtualization implementation (see the internals +documentation when it pops into existence). + +4.41 KVM_SET_BOOT_CPU_ID + +Capability: KVM_CAP_SET_BOOT_CPU_ID +Architectures: x86, ia64 +Type: vm ioctl +Parameters: unsigned long vcpu_id +Returns: 0 on success, -1 on error + +Define which vcpu is the Bootstrap Processor (BSP). Values are the same +as the vcpu id in KVM_CREATE_VCPU. If this ioctl is not called, the default +is vcpu 0. + +4.42 KVM_GET_XSAVE + +Capability: KVM_CAP_XSAVE +Architectures: x86 +Type: vcpu ioctl +Parameters: struct kvm_xsave (out) +Returns: 0 on success, -1 on error + +struct kvm_xsave { + __u32 region[1024]; +}; + +This ioctl would copy current vcpu's xsave struct to the userspace. + +4.43 KVM_SET_XSAVE + +Capability: KVM_CAP_XSAVE +Architectures: x86 +Type: vcpu ioctl +Parameters: struct kvm_xsave (in) +Returns: 0 on success, -1 on error + +struct kvm_xsave { + __u32 region[1024]; +}; + +This ioctl would copy userspace's xsave struct to the kernel. + +4.44 KVM_GET_XCRS + +Capability: KVM_CAP_XCRS +Architectures: x86 +Type: vcpu ioctl +Parameters: struct kvm_xcrs (out) +Returns: 0 on success, -1 on error + +struct kvm_xcr { + __u32 xcr; + __u32 reserved; + __u64 value; +}; + +struct kvm_xcrs { + __u32 nr_xcrs; + __u32 flags; + struct kvm_xcr xcrs[KVM_MAX_XCRS]; + __u64 padding[16]; +}; + +This ioctl would copy current vcpu's xcrs to the userspace. + +4.45 KVM_SET_XCRS + +Capability: KVM_CAP_XCRS +Architectures: x86 +Type: vcpu ioctl +Parameters: struct kvm_xcrs (in) +Returns: 0 on success, -1 on error + +struct kvm_xcr { + __u32 xcr; + __u32 reserved; + __u64 value; +}; + +struct kvm_xcrs { + __u32 nr_xcrs; + __u32 flags; + struct kvm_xcr xcrs[KVM_MAX_XCRS]; + __u64 padding[16]; +}; + +This ioctl would set vcpu's xcr to the value userspace specified. + +4.46 KVM_GET_SUPPORTED_CPUID + +Capability: KVM_CAP_EXT_CPUID +Architectures: x86 +Type: system ioctl +Parameters: struct kvm_cpuid2 (in/out) +Returns: 0 on success, -1 on error + +struct kvm_cpuid2 { + __u32 nent; + __u32 padding; + struct kvm_cpuid_entry2 entries[0]; +}; + +#define KVM_CPUID_FLAG_SIGNIFCANT_INDEX 1 +#define KVM_CPUID_FLAG_STATEFUL_FUNC 2 +#define KVM_CPUID_FLAG_STATE_READ_NEXT 4 + +struct kvm_cpuid_entry2 { + __u32 function; + __u32 index; + __u32 flags; + __u32 eax; + __u32 ebx; + __u32 ecx; + __u32 edx; + __u32 padding[3]; +}; + +This ioctl returns x86 cpuid features which are supported by both the hardware +and kvm. Userspace can use the information returned by this ioctl to +construct cpuid information (for KVM_SET_CPUID2) that is consistent with +hardware, kernel, and userspace capabilities, and with user requirements (for +example, the user may wish to constrain cpuid to emulate older hardware, +or for feature consistency across a cluster). + +Userspace invokes KVM_GET_SUPPORTED_CPUID by passing a kvm_cpuid2 structure +with the 'nent' field indicating the number of entries in the variable-size +array 'entries'. If the number of entries is too low to describe the cpu +capabilities, an error (E2BIG) is returned. If the number is too high, +the 'nent' field is adjusted and an error (ENOMEM) is returned. If the +number is just right, the 'nent' field is adjusted to the number of valid +entries in the 'entries' array, which is then filled. + +The entries returned are the host cpuid as returned by the cpuid instruction, +with unknown or unsupported features masked out. Some features (for example, +x2apic), may not be present in the host cpu, but are exposed by kvm if it can +emulate them efficiently. The fields in each entry are defined as follows: + + function: the eax value used to obtain the entry + index: the ecx value used to obtain the entry (for entries that are + affected by ecx) + flags: an OR of zero or more of the following: + KVM_CPUID_FLAG_SIGNIFCANT_INDEX: + if the index field is valid + KVM_CPUID_FLAG_STATEFUL_FUNC: + if cpuid for this function returns different values for successive + invocations; there will be several entries with the same function, + all with this flag set + KVM_CPUID_FLAG_STATE_READ_NEXT: + for KVM_CPUID_FLAG_STATEFUL_FUNC entries, set if this entry is + the first entry to be read by a cpu + eax, ebx, ecx, edx: the values returned by the cpuid instruction for + this function/index combination + +4.47 KVM_PPC_GET_PVINFO + +Capability: KVM_CAP_PPC_GET_PVINFO +Architectures: ppc +Type: vm ioctl +Parameters: struct kvm_ppc_pvinfo (out) +Returns: 0 on success, !0 on error + +struct kvm_ppc_pvinfo { + __u32 flags; + __u32 hcall[4]; + __u8 pad[108]; +}; + +This ioctl fetches PV specific information that need to be passed to the guest +using the device tree or other means from vm context. + +For now the only implemented piece of information distributed here is an array +of 4 instructions that make up a hypercall. + +If any additional field gets added to this structure later on, a bit for that +additional piece of information will be set in the flags bitmap. + +4.48 KVM_ASSIGN_PCI_DEVICE + +Capability: KVM_CAP_DEVICE_ASSIGNMENT +Architectures: x86 ia64 +Type: vm ioctl +Parameters: struct kvm_assigned_pci_dev (in) +Returns: 0 on success, -1 on error + +Assigns a host PCI device to the VM. + +struct kvm_assigned_pci_dev { + __u32 assigned_dev_id; + __u32 busnr; + __u32 devfn; + __u32 flags; + __u32 segnr; + union { + __u32 reserved[11]; + }; +}; + +The PCI device is specified by the triple segnr, busnr, and devfn. +Identification in succeeding service requests is done via assigned_dev_id. The +following flags are specified: + +/* Depends on KVM_CAP_IOMMU */ +#define KVM_DEV_ASSIGN_ENABLE_IOMMU (1 << 0) + +4.49 KVM_DEASSIGN_PCI_DEVICE + +Capability: KVM_CAP_DEVICE_DEASSIGNMENT +Architectures: x86 ia64 +Type: vm ioctl +Parameters: struct kvm_assigned_pci_dev (in) +Returns: 0 on success, -1 on error + +Ends PCI device assignment, releasing all associated resources. + +See KVM_CAP_DEVICE_ASSIGNMENT for the data structure. Only assigned_dev_id is +used in kvm_assigned_pci_dev to identify the device. + +4.50 KVM_ASSIGN_DEV_IRQ + +Capability: KVM_CAP_ASSIGN_DEV_IRQ +Architectures: x86 ia64 +Type: vm ioctl +Parameters: struct kvm_assigned_irq (in) +Returns: 0 on success, -1 on error + +Assigns an IRQ to a passed-through device. + +struct kvm_assigned_irq { + __u32 assigned_dev_id; + __u32 host_irq; + __u32 guest_irq; + __u32 flags; + union { + struct { + __u32 addr_lo; + __u32 addr_hi; + __u32 data; + } guest_msi; + __u32 reserved[12]; + }; +}; + +The following flags are defined: + +#define KVM_DEV_IRQ_HOST_INTX (1 << 0) +#define KVM_DEV_IRQ_HOST_MSI (1 << 1) +#define KVM_DEV_IRQ_HOST_MSIX (1 << 2) + +#define KVM_DEV_IRQ_GUEST_INTX (1 << 8) +#define KVM_DEV_IRQ_GUEST_MSI (1 << 9) +#define KVM_DEV_IRQ_GUEST_MSIX (1 << 10) + +It is not valid to specify multiple types per host or guest IRQ. However, the +IRQ type of host and guest can differ or can even be null. + +4.51 KVM_DEASSIGN_DEV_IRQ + +Capability: KVM_CAP_ASSIGN_DEV_IRQ +Architectures: x86 ia64 +Type: vm ioctl +Parameters: struct kvm_assigned_irq (in) +Returns: 0 on success, -1 on error + +Ends an IRQ assignment to a passed-through device. + +See KVM_ASSIGN_DEV_IRQ for the data structure. The target device is specified +by assigned_dev_id, flags must correspond to the IRQ type specified on +KVM_ASSIGN_DEV_IRQ. Partial deassignment of host or guest IRQ is allowed. + +4.52 KVM_SET_GSI_ROUTING + +Capability: KVM_CAP_IRQ_ROUTING +Architectures: x86 ia64 +Type: vm ioctl +Parameters: struct kvm_irq_routing (in) +Returns: 0 on success, -1 on error + +Sets the GSI routing table entries, overwriting any previously set entries. + +struct kvm_irq_routing { + __u32 nr; + __u32 flags; + struct kvm_irq_routing_entry entries[0]; +}; + +No flags are specified so far, the corresponding field must be set to zero. + +struct kvm_irq_routing_entry { + __u32 gsi; + __u32 type; + __u32 flags; + __u32 pad; + union { + struct kvm_irq_routing_irqchip irqchip; + struct kvm_irq_routing_msi msi; + __u32 pad[8]; + } u; +}; + +/* gsi routing entry types */ +#define KVM_IRQ_ROUTING_IRQCHIP 1 +#define KVM_IRQ_ROUTING_MSI 2 + +No flags are specified so far, the corresponding field must be set to zero. + +struct kvm_irq_routing_irqchip { + __u32 irqchip; + __u32 pin; +}; + +struct kvm_irq_routing_msi { + __u32 address_lo; + __u32 address_hi; + __u32 data; + __u32 pad; +}; + +4.53 KVM_ASSIGN_SET_MSIX_NR + +Capability: KVM_CAP_DEVICE_MSIX +Architectures: x86 ia64 +Type: vm ioctl +Parameters: struct kvm_assigned_msix_nr (in) +Returns: 0 on success, -1 on error + +Set the number of MSI-X interrupts for an assigned device. This service can +only be called once in the lifetime of an assigned device. + +struct kvm_assigned_msix_nr { + __u32 assigned_dev_id; + __u16 entry_nr; + __u16 padding; +}; + +#define KVM_MAX_MSIX_PER_DEV 256 + +4.54 KVM_ASSIGN_SET_MSIX_ENTRY + +Capability: KVM_CAP_DEVICE_MSIX +Architectures: x86 ia64 +Type: vm ioctl +Parameters: struct kvm_assigned_msix_entry (in) +Returns: 0 on success, -1 on error + +Specifies the routing of an MSI-X assigned device interrupt to a GSI. Setting +the GSI vector to zero means disabling the interrupt. + +struct kvm_assigned_msix_entry { + __u32 assigned_dev_id; + __u32 gsi; + __u16 entry; /* The index of entry in the MSI-X table */ + __u16 padding[3]; +}; + +5. The kvm_run structure + +Application code obtains a pointer to the kvm_run structure by +mmap()ing a vcpu fd. From that point, application code can control +execution by changing fields in kvm_run prior to calling the KVM_RUN +ioctl, and obtain information about the reason KVM_RUN returned by +looking up structure members. + +struct kvm_run { + /* in */ + __u8 request_interrupt_window; + +Request that KVM_RUN return when it becomes possible to inject external +interrupts into the guest. Useful in conjunction with KVM_INTERRUPT. + + __u8 padding1[7]; + + /* out */ + __u32 exit_reason; + +When KVM_RUN has returned successfully (return value 0), this informs +application code why KVM_RUN has returned. Allowable values for this +field are detailed below. + + __u8 ready_for_interrupt_injection; + +If request_interrupt_window has been specified, this field indicates +an interrupt can be injected now with KVM_INTERRUPT. + + __u8 if_flag; + +The value of the current interrupt flag. Only valid if in-kernel +local APIC is not used. + + __u8 padding2[2]; + + /* in (pre_kvm_run), out (post_kvm_run) */ + __u64 cr8; + +The value of the cr8 register. Only valid if in-kernel local APIC is +not used. Both input and output. + + __u64 apic_base; + +The value of the APIC BASE msr. Only valid if in-kernel local +APIC is not used. Both input and output. + + union { + /* KVM_EXIT_UNKNOWN */ + struct { + __u64 hardware_exit_reason; + } hw; + +If exit_reason is KVM_EXIT_UNKNOWN, the vcpu has exited due to unknown +reasons. Further architecture-specific information is available in +hardware_exit_reason. + + /* KVM_EXIT_FAIL_ENTRY */ + struct { + __u64 hardware_entry_failure_reason; + } fail_entry; + +If exit_reason is KVM_EXIT_FAIL_ENTRY, the vcpu could not be run due +to unknown reasons. Further architecture-specific information is +available in hardware_entry_failure_reason. + + /* KVM_EXIT_EXCEPTION */ + struct { + __u32 exception; + __u32 error_code; + } ex; + +Unused. + + /* KVM_EXIT_IO */ + struct { +#define KVM_EXIT_IO_IN 0 +#define KVM_EXIT_IO_OUT 1 + __u8 direction; + __u8 size; /* bytes */ + __u16 port; + __u32 count; + __u64 data_offset; /* relative to kvm_run start */ + } io; + +If exit_reason is KVM_EXIT_IO, then the vcpu has +executed a port I/O instruction which could not be satisfied by kvm. +data_offset describes where the data is located (KVM_EXIT_IO_OUT) or +where kvm expects application code to place the data for the next +KVM_RUN invocation (KVM_EXIT_IO_IN). Data format is a packed array. + + struct { + struct kvm_debug_exit_arch arch; + } debug; + +Unused. + + /* KVM_EXIT_MMIO */ + struct { + __u64 phys_addr; + __u8 data[8]; + __u32 len; + __u8 is_write; + } mmio; + +If exit_reason is KVM_EXIT_MMIO, then the vcpu has +executed a memory-mapped I/O instruction which could not be satisfied +by kvm. The 'data' member contains the written data if 'is_write' is +true, and should be filled by application code otherwise. + +NOTE: For KVM_EXIT_IO, KVM_EXIT_MMIO and KVM_EXIT_OSI, the corresponding +operations are complete (and guest state is consistent) only after userspace +has re-entered the kernel with KVM_RUN. The kernel side will first finish +incomplete operations and then check for pending signals. Userspace +can re-enter the guest with an unmasked signal pending to complete +pending operations. + + /* KVM_EXIT_HYPERCALL */ + struct { + __u64 nr; + __u64 args[6]; + __u64 ret; + __u32 longmode; + __u32 pad; + } hypercall; + +Unused. This was once used for 'hypercall to userspace'. To implement +such functionality, use KVM_EXIT_IO (x86) or KVM_EXIT_MMIO (all except s390). +Note KVM_EXIT_IO is significantly faster than KVM_EXIT_MMIO. + + /* KVM_EXIT_TPR_ACCESS */ + struct { + __u64 rip; + __u32 is_write; + __u32 pad; + } tpr_access; + +To be documented (KVM_TPR_ACCESS_REPORTING). + + /* KVM_EXIT_S390_SIEIC */ + struct { + __u8 icptcode; + __u64 mask; /* psw upper half */ + __u64 addr; /* psw lower half */ + __u16 ipa; + __u32 ipb; + } s390_sieic; + +s390 specific. + + /* KVM_EXIT_S390_RESET */ +#define KVM_S390_RESET_POR 1 +#define KVM_S390_RESET_CLEAR 2 +#define KVM_S390_RESET_SUBSYSTEM 4 +#define KVM_S390_RESET_CPU_INIT 8 +#define KVM_S390_RESET_IPL 16 + __u64 s390_reset_flags; + +s390 specific. + + /* KVM_EXIT_DCR */ + struct { + __u32 dcrn; + __u32 data; + __u8 is_write; + } dcr; + +powerpc specific. + + /* KVM_EXIT_OSI */ + struct { + __u64 gprs[32]; + } osi; + +MOL uses a special hypercall interface it calls 'OSI'. To enable it, we catch +hypercalls and exit with this exit struct that contains all the guest gprs. + +If exit_reason is KVM_EXIT_OSI, then the vcpu has triggered such a hypercall. +Userspace can now handle the hypercall and when it's done modify the gprs as +necessary. Upon guest entry all guest GPRs will then be replaced by the values +in this struct. + + /* Fix the size of the union. */ + char padding[256]; + }; +}; diff --git a/Documentation/virtual/kvm/cpuid.txt b/Documentation/virtual/kvm/cpuid.txt new file mode 100644 index 0000000..8820685 --- /dev/null +++ b/Documentation/virtual/kvm/cpuid.txt @@ -0,0 +1,45 @@ +KVM CPUID bits +Glauber Costa , Red Hat Inc, 2010 +===================================================== + +A guest running on a kvm host, can check some of its features using +cpuid. This is not always guaranteed to work, since userspace can +mask-out some, or even all KVM-related cpuid features before launching +a guest. + +KVM cpuid functions are: + +function: KVM_CPUID_SIGNATURE (0x40000000) +returns : eax = 0, + ebx = 0x4b4d564b, + ecx = 0x564b4d56, + edx = 0x4d. +Note that this value in ebx, ecx and edx corresponds to the string "KVMKVMKVM". +This function queries the presence of KVM cpuid leafs. + + +function: define KVM_CPUID_FEATURES (0x40000001) +returns : ebx, ecx, edx = 0 + eax = and OR'ed group of (1 << flag), where each flags is: + + +flag || value || meaning +============================================================================= +KVM_FEATURE_CLOCKSOURCE || 0 || kvmclock available at msrs + || || 0x11 and 0x12. +------------------------------------------------------------------------------ +KVM_FEATURE_NOP_IO_DELAY || 1 || not necessary to perform delays + || || on PIO operations. +------------------------------------------------------------------------------ +KVM_FEATURE_MMU_OP || 2 || deprecated. +------------------------------------------------------------------------------ +KVM_FEATURE_CLOCKSOURCE2 || 3 || kvmclock available at msrs + || || 0x4b564d00 and 0x4b564d01 +------------------------------------------------------------------------------ +KVM_FEATURE_ASYNC_PF || 4 || async pf can be enabled by + || || writing to msr 0x4b564d02 +------------------------------------------------------------------------------ +KVM_FEATURE_CLOCKSOURCE_STABLE_BIT || 24 || host will warn if no guest-side + || || per-cpu warps are expected in + || || kvmclock. +------------------------------------------------------------------------------ diff --git a/Documentation/virtual/kvm/locking.txt b/Documentation/virtual/kvm/locking.txt new file mode 100644 index 0000000..3b4cd3b --- /dev/null +++ b/Documentation/virtual/kvm/locking.txt @@ -0,0 +1,25 @@ +KVM Lock Overview +================= + +1. Acquisition Orders +--------------------- + +(to be written) + +2. Reference +------------ + +Name: kvm_lock +Type: raw_spinlock +Arch: any +Protects: - vm_list + - hardware virtualization enable/disable +Comment: 'raw' because hardware enabling/disabling must be atomic /wrt + migration. + +Name: kvm_arch::tsc_write_lock +Type: raw_spinlock +Arch: x86 +Protects: - kvm_arch::{last_tsc_write,last_tsc_nsec,last_tsc_offset} + - tsc offset in vmcb +Comment: 'raw' because updating the tsc offsets must not be preempted. diff --git a/Documentation/virtual/kvm/mmu.txt b/Documentation/virtual/kvm/mmu.txt new file mode 100644 index 0000000..f46aa58 --- /dev/null +++ b/Documentation/virtual/kvm/mmu.txt @@ -0,0 +1,348 @@ +The x86 kvm shadow mmu +====================== + +The mmu (in arch/x86/kvm, files mmu.[ch] and paging_tmpl.h) is responsible +for presenting a standard x86 mmu to the guest, while translating guest +physical addresses to host physical addresses. + +The mmu code attempts to satisfy the following requirements: + +- correctness: the guest should not be able to determine that it is running + on an emulated mmu except for timing (we attempt to comply + with the specification, not emulate the characteristics of + a particular implementation such as tlb size) +- security: the guest must not be able to touch host memory not assigned + to it +- performance: minimize the performance penalty imposed by the mmu +- scaling: need to scale to large memory and large vcpu guests +- hardware: support the full range of x86 virtualization hardware +- integration: Linux memory management code must be in control of guest memory + so that swapping, page migration, page merging, transparent + hugepages, and similar features work without change +- dirty tracking: report writes to guest memory to enable live migration + and framebuffer-based displays +- footprint: keep the amount of pinned kernel memory low (most memory + should be shrinkable) +- reliability: avoid multipage or GFP_ATOMIC allocations + +Acronyms +======== + +pfn host page frame number +hpa host physical address +hva host virtual address +gfn guest frame number +gpa guest physical address +gva guest virtual address +ngpa nested guest physical address +ngva nested guest virtual address +pte page table entry (used also to refer generically to paging structure + entries) +gpte guest pte (referring to gfns) +spte shadow pte (referring to pfns) +tdp two dimensional paging (vendor neutral term for NPT and EPT) + +Virtual and real hardware supported +=================================== + +The mmu supports first-generation mmu hardware, which allows an atomic switch +of the current paging mode and cr3 during guest entry, as well as +two-dimensional paging (AMD's NPT and Intel's EPT). The emulated hardware +it exposes is the traditional 2/3/4 level x86 mmu, with support for global +pages, pae, pse, pse36, cr0.wp, and 1GB pages. Work is in progress to support +exposing NPT capable hardware on NPT capable hosts. + +Translation +=========== + +The primary job of the mmu is to program the processor's mmu to translate +addresses for the guest. Different translations are required at different +times: + +- when guest paging is disabled, we translate guest physical addresses to + host physical addresses (gpa->hpa) +- when guest paging is enabled, we translate guest virtual addresses, to + guest physical addresses, to host physical addresses (gva->gpa->hpa) +- when the guest launches a guest of its own, we translate nested guest + virtual addresses, to nested guest physical addresses, to guest physical + addresses, to host physical addresses (ngva->ngpa->gpa->hpa) + +The primary challenge is to encode between 1 and 3 translations into hardware +that support only 1 (traditional) and 2 (tdp) translations. When the +number of required translations matches the hardware, the mmu operates in +direct mode; otherwise it operates in shadow mode (see below). + +Memory +====== + +Guest memory (gpa) is part of the user address space of the process that is +using kvm. Userspace defines the translation between guest addresses and user +addresses (gpa->hva); note that two gpas may alias to the same hva, but not +vice versa. + +These hvas may be backed using any method available to the host: anonymous +memory, file backed memory, and device memory. Memory might be paged by the +host at any time. + +Events +====== + +The mmu is driven by events, some from the guest, some from the host. + +Guest generated events: +- writes to control registers (especially cr3) +- invlpg/invlpga instruction execution +- access to missing or protected translations + +Host generated events: +- changes in the gpa->hpa translation (either through gpa->hva changes or + through hva->hpa changes) +- memory pressure (the shrinker) + +Shadow pages +============ + +The principal data structure is the shadow page, 'struct kvm_mmu_page'. A +shadow page contains 512 sptes, which can be either leaf or nonleaf sptes. A +shadow page may contain a mix of leaf and nonleaf sptes. + +A nonleaf spte allows the hardware mmu to reach the leaf pages and +is not related to a translation directly. It points to other shadow pages. + +A leaf spte corresponds to either one or two translations encoded into +one paging structure entry. These are always the lowest level of the +translation stack, with optional higher level translations left to NPT/EPT. +Leaf ptes point at guest pages. + +The following table shows translations encoded by leaf ptes, with higher-level +translations in parentheses: + + Non-nested guests: + nonpaging: gpa->hpa + paging: gva->gpa->hpa + paging, tdp: (gva->)gpa->hpa + Nested guests: + non-tdp: ngva->gpa->hpa (*) + tdp: (ngva->)ngpa->gpa->hpa + +(*) the guest hypervisor will encode the ngva->gpa translation into its page + tables if npt is not present + +Shadow pages contain the following information: + role.level: + The level in the shadow paging hierarchy that this shadow page belongs to. + 1=4k sptes, 2=2M sptes, 3=1G sptes, etc. + role.direct: + If set, leaf sptes reachable from this page are for a linear range. + Examples include real mode translation, large guest pages backed by small + host pages, and gpa->hpa translations when NPT or EPT is active. + The linear range starts at (gfn << PAGE_SHIFT) and its size is determined + by role.level (2MB for first level, 1GB for second level, 0.5TB for third + level, 256TB for fourth level) + If clear, this page corresponds to a guest page table denoted by the gfn + field. + role.quadrant: + When role.cr4_pae=0, the guest uses 32-bit gptes while the host uses 64-bit + sptes. That means a guest page table contains more ptes than the host, + so multiple shadow pages are needed to shadow one guest page. + For first-level shadow pages, role.quadrant can be 0 or 1 and denotes the + first or second 512-gpte block in the guest page table. For second-level + page tables, each 32-bit gpte is converted to two 64-bit sptes + (since each first-level guest page is shadowed by two first-level + shadow pages) so role.quadrant takes values in the range 0..3. Each + quadrant maps 1GB virtual address space. + role.access: + Inherited guest access permissions in the form uwx. Note execute + permission is positive, not negative. + role.invalid: + The page is invalid and should not be used. It is a root page that is + currently pinned (by a cpu hardware register pointing to it); once it is + unpinned it will be destroyed. + role.cr4_pae: + Contains the value of cr4.pae for which the page is valid (e.g. whether + 32-bit or 64-bit gptes are in use). + role.nxe: + Contains the value of efer.nxe for which the page is valid. + role.cr0_wp: + Contains the value of cr0.wp for which the page is valid. + gfn: + Either the guest page table containing the translations shadowed by this + page, or the base page frame for linear translations. See role.direct. + spt: + A pageful of 64-bit sptes containing the translations for this page. + Accessed by both kvm and hardware. + The page pointed to by spt will have its page->private pointing back + at the shadow page structure. + sptes in spt point either at guest pages, or at lower-level shadow pages. + Specifically, if sp1 and sp2 are shadow pages, then sp1->spt[n] may point + at __pa(sp2->spt). sp2 will point back at sp1 through parent_pte. + The spt array forms a DAG structure with the shadow page as a node, and + guest pages as leaves. + gfns: + An array of 512 guest frame numbers, one for each present pte. Used to + perform a reverse map from a pte to a gfn. When role.direct is set, any + element of this array can be calculated from the gfn field when used, in + this case, the array of gfns is not allocated. See role.direct and gfn. + slot_bitmap: + A bitmap containing one bit per memory slot. If the page contains a pte + mapping a page from memory slot n, then bit n of slot_bitmap will be set + (if a page is aliased among several slots, then it is not guaranteed that + all slots will be marked). + Used during dirty logging to avoid scanning a shadow page if none if its + pages need tracking. + root_count: + A counter keeping track of how many hardware registers (guest cr3 or + pdptrs) are now pointing at the page. While this counter is nonzero, the + page cannot be destroyed. See role.invalid. + multimapped: + Whether there exist multiple sptes pointing at this page. + parent_pte/parent_ptes: + If multimapped is zero, parent_pte points at the single spte that points at + this page's spt. Otherwise, parent_ptes points at a data structure + with a list of parent_ptes. + unsync: + If true, then the translations in this page may not match the guest's + translation. This is equivalent to the state of the tlb when a pte is + changed but before the tlb entry is flushed. Accordingly, unsync ptes + are synchronized when the guest executes invlpg or flushes its tlb by + other means. Valid for leaf pages. + unsync_children: + How many sptes in the page point at pages that are unsync (or have + unsynchronized children). + unsync_child_bitmap: + A bitmap indicating which sptes in spt point (directly or indirectly) at + pages that may be unsynchronized. Used to quickly locate all unsychronized + pages reachable from a given page. + +Reverse map +=========== + +The mmu maintains a reverse mapping whereby all ptes mapping a page can be +reached given its gfn. This is used, for example, when swapping out a page. + +Synchronized and unsynchronized pages +===================================== + +The guest uses two events to synchronize its tlb and page tables: tlb flushes +and page invalidations (invlpg). + +A tlb flush means that we need to synchronize all sptes reachable from the +guest's cr3. This is expensive, so we keep all guest page tables write +protected, and synchronize sptes to gptes when a gpte is written. + +A special case is when a guest page table is reachable from the current +guest cr3. In this case, the guest is obliged to issue an invlpg instruction +before using the translation. We take advantage of that by removing write +protection from the guest page, and allowing the guest to modify it freely. +We synchronize modified gptes when the guest invokes invlpg. This reduces +the amount of emulation we have to do when the guest modifies multiple gptes, +or when the a guest page is no longer used as a page table and is used for +random guest data. + +As a side effect we have to resynchronize all reachable unsynchronized shadow +pages on a tlb flush. + + +Reaction to events +================== + +- guest page fault (or npt page fault, or ept violation) + +This is the most complicated event. The cause of a page fault can be: + + - a true guest fault (the guest translation won't allow the access) (*) + - access to a missing translation + - access to a protected translation + - when logging dirty pages, memory is write protected + - synchronized shadow pages are write protected (*) + - access to untranslatable memory (mmio) + + (*) not applicable in direct mode + +Handling a page fault is performed as follows: + + - if needed, walk the guest page tables to determine the guest translation + (gva->gpa or ngpa->gpa) + - if permissions are insufficient, reflect the fault back to the guest + - determine the host page + - if this is an mmio request, there is no host page; call the emulator + to emulate the instruction instead + - walk the shadow page table to find the spte for the translation, + instantiating missing intermediate page tables as necessary + - try to unsynchronize the page + - if successful, we can let the guest continue and modify the gpte + - emulate the instruction + - if failed, unshadow the page and let the guest continue + - update any translations that were modified by the instruction + +invlpg handling: + + - walk the shadow page hierarchy and drop affected translations + - try to reinstantiate the indicated translation in the hope that the + guest will use it in the near future + +Guest control register updates: + +- mov to cr3 + - look up new shadow roots + - synchronize newly reachable shadow pages + +- mov to cr0/cr4/efer + - set up mmu context for new paging mode + - look up new shadow roots + - synchronize newly reachable shadow pages + +Host translation updates: + + - mmu notifier called with updated hva + - look up affected sptes through reverse map + - drop (or update) translations + +Emulating cr0.wp +================ + +If tdp is not enabled, the host must keep cr0.wp=1 so page write protection +works for the guest kernel, not guest guest userspace. When the guest +cr0.wp=1, this does not present a problem. However when the guest cr0.wp=0, +we cannot map the permissions for gpte.u=1, gpte.w=0 to any spte (the +semantics require allowing any guest kernel access plus user read access). + +We handle this by mapping the permissions to two possible sptes, depending +on fault type: + +- kernel write fault: spte.u=0, spte.w=1 (allows full kernel access, + disallows user access) +- read fault: spte.u=1, spte.w=0 (allows full read access, disallows kernel + write access) + +(user write faults generate a #PF) + +Large pages +=========== + +The mmu supports all combinations of large and small guest and host pages. +Supported page sizes include 4k, 2M, 4M, and 1G. 4M pages are treated as +two separate 2M pages, on both guest and host, since the mmu always uses PAE +paging. + +To instantiate a large spte, four constraints must be satisfied: + +- the spte must point to a large host page +- the guest pte must be a large pte of at least equivalent size (if tdp is + enabled, there is no guest pte and this condition is satisified) +- if the spte will be writeable, the large page frame may not overlap any + write-protected pages +- the guest page must be wholly contained by a single memory slot + +To check the last two conditions, the mmu maintains a ->write_count set of +arrays for each memory slot and large page size. Every write protected page +causes its write_count to be incremented, thus preventing instantiation of +a large spte. The frames at the end of an unaligned memory slot have +artificically inflated ->write_counts so they can never be instantiated. + +Further reading +=============== + +- NPT presentation from KVM Forum 2008 + http://www.linux-kvm.org/wiki/images/c/c8/KvmForum2008%24kdf2008_21.pdf + diff --git a/Documentation/virtual/kvm/msr.txt b/Documentation/virtual/kvm/msr.txt new file mode 100644 index 0000000..d079aed --- /dev/null +++ b/Documentation/virtual/kvm/msr.txt @@ -0,0 +1,187 @@ +KVM-specific MSRs. +Glauber Costa , Red Hat Inc, 2010 +===================================================== + +KVM makes use of some custom MSRs to service some requests. + +Custom MSRs have a range reserved for them, that goes from +0x4b564d00 to 0x4b564dff. There are MSRs outside this area, +but they are deprecated and their use is discouraged. + +Custom MSR list +-------- + +The current supported Custom MSR list is: + +MSR_KVM_WALL_CLOCK_NEW: 0x4b564d00 + + data: 4-byte alignment physical address of a memory area which must be + in guest RAM. This memory is expected to hold a copy of the following + structure: + + struct pvclock_wall_clock { + u32 version; + u32 sec; + u32 nsec; + } __attribute__((__packed__)); + + whose data will be filled in by the hypervisor. The hypervisor is only + guaranteed to update this data at the moment of MSR write. + Users that want to reliably query this information more than once have + to write more than once to this MSR. Fields have the following meanings: + + version: guest has to check version before and after grabbing + time information and check that they are both equal and even. + An odd version indicates an in-progress update. + + sec: number of seconds for wallclock. + + nsec: number of nanoseconds for wallclock. + + Note that although MSRs are per-CPU entities, the effect of this + particular MSR is global. + + Availability of this MSR must be checked via bit 3 in 0x4000001 cpuid + leaf prior to usage. + +MSR_KVM_SYSTEM_TIME_NEW: 0x4b564d01 + + data: 4-byte aligned physical address of a memory area which must be in + guest RAM, plus an enable bit in bit 0. This memory is expected to hold + a copy of the following structure: + + struct pvclock_vcpu_time_info { + u32 version; + u32 pad0; + u64 tsc_timestamp; + u64 system_time; + u32 tsc_to_system_mul; + s8 tsc_shift; + u8 flags; + u8 pad[2]; + } __attribute__((__packed__)); /* 32 bytes */ + + whose data will be filled in by the hypervisor periodically. Only one + write, or registration, is needed for each VCPU. The interval between + updates of this structure is arbitrary and implementation-dependent. + The hypervisor may update this structure at any time it sees fit until + anything with bit0 == 0 is written to it. + + Fields have the following meanings: + + version: guest has to check version before and after grabbing + time information and check that they are both equal and even. + An odd version indicates an in-progress update. + + tsc_timestamp: the tsc value at the current VCPU at the time + of the update of this structure. Guests can subtract this value + from current tsc to derive a notion of elapsed time since the + structure update. + + system_time: a host notion of monotonic time, including sleep + time at the time this structure was last updated. Unit is + nanoseconds. + + tsc_to_system_mul: a function of the tsc frequency. One has + to multiply any tsc-related quantity by this value to get + a value in nanoseconds, besides dividing by 2^tsc_shift + + tsc_shift: cycle to nanosecond divider, as a power of two, to + allow for shift rights. One has to shift right any tsc-related + quantity by this value to get a value in nanoseconds, besides + multiplying by tsc_to_system_mul. + + With this information, guests can derive per-CPU time by + doing: + + time = (current_tsc - tsc_timestamp) + time = (time * tsc_to_system_mul) >> tsc_shift + time = time + system_time + + flags: bits in this field indicate extended capabilities + coordinated between the guest and the hypervisor. Availability + of specific flags has to be checked in 0x40000001 cpuid leaf. + Current flags are: + + flag bit | cpuid bit | meaning + ------------------------------------------------------------- + | | time measures taken across + 0 | 24 | multiple cpus are guaranteed to + | | be monotonic + ------------------------------------------------------------- + + Availability of this MSR must be checked via bit 3 in 0x4000001 cpuid + leaf prior to usage. + + +MSR_KVM_WALL_CLOCK: 0x11 + + data and functioning: same as MSR_KVM_WALL_CLOCK_NEW. Use that instead. + + This MSR falls outside the reserved KVM range and may be removed in the + future. Its usage is deprecated. + + Availability of this MSR must be checked via bit 0 in 0x4000001 cpuid + leaf prior to usage. + +MSR_KVM_SYSTEM_TIME: 0x12 + + data and functioning: same as MSR_KVM_SYSTEM_TIME_NEW. Use that instead. + + This MSR falls outside the reserved KVM range and may be removed in the + future. Its usage is deprecated. + + Availability of this MSR must be checked via bit 0 in 0x4000001 cpuid + leaf prior to usage. + + The suggested algorithm for detecting kvmclock presence is then: + + if (!kvm_para_available()) /* refer to cpuid.txt */ + return NON_PRESENT; + + flags = cpuid_eax(0x40000001); + if (flags & 3) { + msr_kvm_system_time = MSR_KVM_SYSTEM_TIME_NEW; + msr_kvm_wall_clock = MSR_KVM_WALL_CLOCK_NEW; + return PRESENT; + } else if (flags & 0) { + msr_kvm_system_time = MSR_KVM_SYSTEM_TIME; + msr_kvm_wall_clock = MSR_KVM_WALL_CLOCK; + return PRESENT; + } else + return NON_PRESENT; + +MSR_KVM_ASYNC_PF_EN: 0x4b564d02 + data: Bits 63-6 hold 64-byte aligned physical address of a + 64 byte memory area which must be in guest RAM and must be + zeroed. Bits 5-2 are reserved and should be zero. Bit 0 is 1 + when asynchronous page faults are enabled on the vcpu 0 when + disabled. Bit 2 is 1 if asynchronous page faults can be injected + when vcpu is in cpl == 0. + + First 4 byte of 64 byte memory location will be written to by + the hypervisor at the time of asynchronous page fault (APF) + injection to indicate type of asynchronous page fault. Value + of 1 means that the page referred to by the page fault is not + present. Value 2 means that the page is now available. Disabling + interrupt inhibits APFs. Guest must not enable interrupt + before the reason is read, or it may be overwritten by another + APF. Since APF uses the same exception vector as regular page + fault guest must reset the reason to 0 before it does + something that can generate normal page fault. If during page + fault APF reason is 0 it means that this is regular page + fault. + + During delivery of type 1 APF cr2 contains a token that will + be used to notify a guest when missing page becomes + available. When page becomes available type 2 APF is sent with + cr2 set to the token associated with the page. There is special + kind of token 0xffffffff which tells vcpu that it should wake + up all processes waiting for APFs and no individual type 2 APFs + will be sent. + + If APF is disabled while there are outstanding APFs, they will + not be delivered. + + Currently type 2 APF will be always delivered on the same vcpu as + type 1 was, but guest should not rely on that. diff --git a/Documentation/virtual/kvm/ppc-pv.txt b/Documentation/virtual/kvm/ppc-pv.txt new file mode 100644 index 0000000..3ab969c --- /dev/null +++ b/Documentation/virtual/kvm/ppc-pv.txt @@ -0,0 +1,196 @@ +The PPC KVM paravirtual interface +================================= + +The basic execution principle by which KVM on PowerPC works is to run all kernel +space code in PR=1 which is user space. This way we trap all privileged +instructions and can emulate them accordingly. + +Unfortunately that is also the downfall. There are quite some privileged +instructions that needlessly return us to the hypervisor even though they +could be handled differently. + +This is what the PPC PV interface helps with. It takes privileged instructions +and transforms them into unprivileged ones with some help from the hypervisor. +This cuts down virtualization costs by about 50% on some of my benchmarks. + +The code for that interface can be found in arch/powerpc/kernel/kvm* + +Querying for existence +====================== + +To find out if we're running on KVM or not, we leverage the device tree. When +Linux is running on KVM, a node /hypervisor exists. That node contains a +compatible property with the value "linux,kvm". + +Once you determined you're running under a PV capable KVM, you can now use +hypercalls as described below. + +KVM hypercalls +============== + +Inside the device tree's /hypervisor node there's a property called +'hypercall-instructions'. This property contains at most 4 opcodes that make +up the hypercall. To call a hypercall, just call these instructions. + +The parameters are as follows: + + Register IN OUT + + r0 - volatile + r3 1st parameter Return code + r4 2nd parameter 1st output value + r5 3rd parameter 2nd output value + r6 4th parameter 3rd output value + r7 5th parameter 4th output value + r8 6th parameter 5th output value + r9 7th parameter 6th output value + r10 8th parameter 7th output value + r11 hypercall number 8th output value + r12 - volatile + +Hypercall definitions are shared in generic code, so the same hypercall numbers +apply for x86 and powerpc alike with the exception that each KVM hypercall +also needs to be ORed with the KVM vendor code which is (42 << 16). + +Return codes can be as follows: + + Code Meaning + + 0 Success + 12 Hypercall not implemented + <0 Error + +The magic page +============== + +To enable communication between the hypervisor and guest there is a new shared +page that contains parts of supervisor visible register state. The guest can +map this shared page using the KVM hypercall KVM_HC_PPC_MAP_MAGIC_PAGE. + +With this hypercall issued the guest always gets the magic page mapped at the +desired location in effective and physical address space. For now, we always +map the page to -4096. This way we can access it using absolute load and store +functions. The following instruction reads the first field of the magic page: + + ld rX, -4096(0) + +The interface is designed to be extensible should there be need later to add +additional registers to the magic page. If you add fields to the magic page, +also define a new hypercall feature to indicate that the host can give you more +registers. Only if the host supports the additional features, make use of them. + +The magic page has the following layout as described in +arch/powerpc/include/asm/kvm_para.h: + +struct kvm_vcpu_arch_shared { + __u64 scratch1; + __u64 scratch2; + __u64 scratch3; + __u64 critical; /* Guest may not get interrupts if == r1 */ + __u64 sprg0; + __u64 sprg1; + __u64 sprg2; + __u64 sprg3; + __u64 srr0; + __u64 srr1; + __u64 dar; + __u64 msr; + __u32 dsisr; + __u32 int_pending; /* Tells the guest if we have an interrupt */ +}; + +Additions to the page must only occur at the end. Struct fields are always 32 +or 64 bit aligned, depending on them being 32 or 64 bit wide respectively. + +Magic page features +=================== + +When mapping the magic page using the KVM hypercall KVM_HC_PPC_MAP_MAGIC_PAGE, +a second return value is passed to the guest. This second return value contains +a bitmap of available features inside the magic page. + +The following enhancements to the magic page are currently available: + + KVM_MAGIC_FEAT_SR Maps SR registers r/w in the magic page + +For enhanced features in the magic page, please check for the existence of the +feature before using them! + +MSR bits +======== + +The MSR contains bits that require hypervisor intervention and bits that do +not require direct hypervisor intervention because they only get interpreted +when entering the guest or don't have any impact on the hypervisor's behavior. + +The following bits are safe to be set inside the guest: + + MSR_EE + MSR_RI + MSR_CR + MSR_ME + +If any other bit changes in the MSR, please still use mtmsr(d). + +Patched instructions +==================== + +The "ld" and "std" instructions are transormed to "lwz" and "stw" instructions +respectively on 32 bit systems with an added offset of 4 to accommodate for big +endianness. + +The following is a list of mapping the Linux kernel performs when running as +guest. Implementing any of those mappings is optional, as the instruction traps +also act on the shared page. So calling privileged instructions still works as +before. + +From To +==== == + +mfmsr rX ld rX, magic_page->msr +mfsprg rX, 0 ld rX, magic_page->sprg0 +mfsprg rX, 1 ld rX, magic_page->sprg1 +mfsprg rX, 2 ld rX, magic_page->sprg2 +mfsprg rX, 3 ld rX, magic_page->sprg3 +mfsrr0 rX ld rX, magic_page->srr0 +mfsrr1 rX ld rX, magic_page->srr1 +mfdar rX ld rX, magic_page->dar +mfdsisr rX lwz rX, magic_page->dsisr + +mtmsr rX std rX, magic_page->msr +mtsprg 0, rX std rX, magic_page->sprg0 +mtsprg 1, rX std rX, magic_page->sprg1 +mtsprg 2, rX std rX, magic_page->sprg2 +mtsprg 3, rX std rX, magic_page->sprg3 +mtsrr0 rX std rX, magic_page->srr0 +mtsrr1 rX std rX, magic_page->srr1 +mtdar rX std rX, magic_page->dar +mtdsisr rX stw rX, magic_page->dsisr + +tlbsync nop + +mtmsrd rX, 0 b +mtmsr rX b + +mtmsrd rX, 1 b + +[Book3S only] +mtsrin rX, rY b + +[BookE only] +wrteei [0|1] b + + +Some instructions require more logic to determine what's going on than a load +or store instruction can deliver. To enable patching of those, we keep some +RAM around where we can live translate instructions to. What happens is the +following: + + 1) copy emulation code to memory + 2) patch that code to fit the emulated instruction + 3) patch that code to return to the original pc + 4 + 4) patch the original instruction to branch to the new code + +That way we can inject an arbitrary amount of code as replacement for a single +instruction. This allows us to check for pending interrupts when setting EE=1 +for example. diff --git a/Documentation/virtual/kvm/review-checklist.txt b/Documentation/virtual/kvm/review-checklist.txt new file mode 100644 index 0000000..730475a --- /dev/null +++ b/Documentation/virtual/kvm/review-checklist.txt @@ -0,0 +1,38 @@ +Review checklist for kvm patches +================================ + +1. The patch must follow Documentation/CodingStyle and + Documentation/SubmittingPatches. + +2. Patches should be against kvm.git master branch. + +3. If the patch introduces or modifies a new userspace API: + - the API must be documented in Documentation/kvm/api.txt + - the API must be discoverable using KVM_CHECK_EXTENSION + +4. New state must include support for save/restore. + +5. New features must default to off (userspace should explicitly request them). + Performance improvements can and should default to on. + +6. New cpu features should be exposed via KVM_GET_SUPPORTED_CPUID2 + +7. Emulator changes should be accompanied by unit tests for qemu-kvm.git + kvm/test directory. + +8. Changes should be vendor neutral when possible. Changes to common code + are better than duplicating changes to vendor code. + +9. Similarly, prefer changes to arch independent code than to arch dependent + code. + +10. User/kernel interfaces and guest/host interfaces must be 64-bit clean + (all variables and sizes naturally aligned on 64-bit; use specific types + only - u64 rather than ulong). + +11. New guest visible features must either be documented in a hardware manual + or be accompanied by documentation. + +12. Features must be robust against reset and kexec - for example, shared + host/guest memory must be unshared to prevent the host from writing to + guest memory that the guest has not reserved for this purpose. diff --git a/Documentation/virtual/kvm/timekeeping.txt b/Documentation/virtual/kvm/timekeeping.txt new file mode 100644 index 0000000..df894637 --- /dev/null +++ b/Documentation/virtual/kvm/timekeeping.txt @@ -0,0 +1,612 @@ + + Timekeeping Virtualization for X86-Based Architectures + + Zachary Amsden + Copyright (c) 2010, Red Hat. All rights reserved. + +1) Overview +2) Timing Devices +3) TSC Hardware +4) Virtualization Problems + +========================================================================= + +1) Overview + +One of the most complicated parts of the X86 platform, and specifically, +the virtualization of this platform is the plethora of timing devices available +and the complexity of emulating those devices. In addition, virtualization of +time introduces a new set of challenges because it introduces a multiplexed +division of time beyond the control of the guest CPU. + +First, we will describe the various timekeeping hardware available, then +present some of the problems which arise and solutions available, giving +specific recommendations for certain classes of KVM guests. + +The purpose of this document is to collect data and information relevant to +timekeeping which may be difficult to find elsewhere, specifically, +information relevant to KVM and hardware-based virtualization. + +========================================================================= + +2) Timing Devices + +First we discuss the basic hardware devices available. TSC and the related +KVM clock are special enough to warrant a full exposition and are described in +the following section. + +2.1) i8254 - PIT + +One of the first timer devices available is the programmable interrupt timer, +or PIT. The PIT has a fixed frequency 1.193182 MHz base clock and three +channels which can be programmed to deliver periodic or one-shot interrupts. +These three channels can be configured in different modes and have individual +counters. Channel 1 and 2 were not available for general use in the original +IBM PC, and historically were connected to control RAM refresh and the PC +speaker. Now the PIT is typically integrated as part of an emulated chipset +and a separate physical PIT is not used. + +The PIT uses I/O ports 0x40 - 0x43. Access to the 16-bit counters is done +using single or multiple byte access to the I/O ports. There are 6 modes +available, but not all modes are available to all timers, as only timer 2 +has a connected gate input, required for modes 1 and 5. The gate line is +controlled by port 61h, bit 0, as illustrated in the following diagram. + + -------------- ---------------- +| | | | +| 1.1932 MHz |---------->| CLOCK OUT | ---------> IRQ 0 +| Clock | | | | + -------------- | +->| GATE TIMER 0 | + | ---------------- + | + | ---------------- + | | | + |------>| CLOCK OUT | ---------> 66.3 KHZ DRAM + | | | (aka /dev/null) + | +->| GATE TIMER 1 | + | ---------------- + | + | ---------------- + | | | + |------>| CLOCK OUT | ---------> Port 61h, bit 5 + | | | +Port 61h, bit 0 ---------->| GATE TIMER 2 | \_.---- ____ + ---------------- _| )--|LPF|---Speaker + / *---- \___/ +Port 61h, bit 1 -----------------------------------/ + +The timer modes are now described. + +Mode 0: Single Timeout. This is a one-shot software timeout that counts down + when the gate is high (always true for timers 0 and 1). When the count + reaches zero, the output goes high. + +Mode 1: Triggered One-shot. The output is initially set high. When the gate + line is set high, a countdown is initiated (which does not stop if the gate is + lowered), during which the output is set low. When the count reaches zero, + the output goes high. + +Mode 2: Rate Generator. The output is initially set high. When the countdown + reaches 1, the output goes low for one count and then returns high. The value + is reloaded and the countdown automatically resumes. If the gate line goes + low, the count is halted. If the output is low when the gate is lowered, the + output automatically goes high (this only affects timer 2). + +Mode 3: Square Wave. This generates a high / low square wave. The count + determines the length of the pulse, which alternates between high and low + when zero is reached. The count only proceeds when gate is high and is + automatically reloaded on reaching zero. The count is decremented twice at + each clock to generate a full high / low cycle at the full periodic rate. + If the count is even, the clock remains high for N/2 counts and low for N/2 + counts; if the clock is odd, the clock is high for (N+1)/2 counts and low + for (N-1)/2 counts. Only even values are latched by the counter, so odd + values are not observed when reading. This is the intended mode for timer 2, + which generates sine-like tones by low-pass filtering the square wave output. + +Mode 4: Software Strobe. After programming this mode and loading the counter, + the output remains high until the counter reaches zero. Then the output + goes low for 1 clock cycle and returns high. The counter is not reloaded. + Counting only occurs when gate is high. + +Mode 5: Hardware Strobe. After programming and loading the counter, the + output remains high. When the gate is raised, a countdown is initiated + (which does not stop if the gate is lowered). When the counter reaches zero, + the output goes low for 1 clock cycle and then returns high. The counter is + not reloaded. + +In addition to normal binary counting, the PIT supports BCD counting. The +command port, 0x43 is used to set the counter and mode for each of the three +timers. + +PIT commands, issued to port 0x43, using the following bit encoding: + +Bit 7-4: Command (See table below) +Bit 3-1: Mode (000 = Mode 0, 101 = Mode 5, 11X = undefined) +Bit 0 : Binary (0) / BCD (1) + +Command table: + +0000 - Latch Timer 0 count for port 0x40 + sample and hold the count to be read in port 0x40; + additional commands ignored until counter is read; + mode bits ignored. + +0001 - Set Timer 0 LSB mode for port 0x40 + set timer to read LSB only and force MSB to zero; + mode bits set timer mode + +0010 - Set Timer 0 MSB mode for port 0x40 + set timer to read MSB only and force LSB to zero; + mode bits set timer mode + +0011 - Set Timer 0 16-bit mode for port 0x40 + set timer to read / write LSB first, then MSB; + mode bits set timer mode + +0100 - Latch Timer 1 count for port 0x41 - as described above +0101 - Set Timer 1 LSB mode for port 0x41 - as described above +0110 - Set Timer 1 MSB mode for port 0x41 - as described above +0111 - Set Timer 1 16-bit mode for port 0x41 - as described above + +1000 - Latch Timer 2 count for port 0x42 - as described above +1001 - Set Timer 2 LSB mode for port 0x42 - as described above +1010 - Set Timer 2 MSB mode for port 0x42 - as described above +1011 - Set Timer 2 16-bit mode for port 0x42 as described above + +1101 - General counter latch + Latch combination of counters into corresponding ports + Bit 3 = Counter 2 + Bit 2 = Counter 1 + Bit 1 = Counter 0 + Bit 0 = Unused + +1110 - Latch timer status + Latch combination of counter mode into corresponding ports + Bit 3 = Counter 2 + Bit 2 = Counter 1 + Bit 1 = Counter 0 + + The output of ports 0x40-0x42 following this command will be: + + Bit 7 = Output pin + Bit 6 = Count loaded (0 if timer has expired) + Bit 5-4 = Read / Write mode + 01 = MSB only + 10 = LSB only + 11 = LSB / MSB (16-bit) + Bit 3-1 = Mode + Bit 0 = Binary (0) / BCD mode (1) + +2.2) RTC + +The second device which was available in the original PC was the MC146818 real +time clock. The original device is now obsolete, and usually emulated by the +system chipset, sometimes by an HPET and some frankenstein IRQ routing. + +The RTC is accessed through CMOS variables, which uses an index register to +control which bytes are read. Since there is only one index register, read +of the CMOS and read of the RTC require lock protection (in addition, it is +dangerous to allow userspace utilities such as hwclock to have direct RTC +access, as they could corrupt kernel reads and writes of CMOS memory). + +The RTC generates an interrupt which is usually routed to IRQ 8. The interrupt +can function as a periodic timer, an additional once a day alarm, and can issue +interrupts after an update of the CMOS registers by the MC146818 is complete. +The type of interrupt is signalled in the RTC status registers. + +The RTC will update the current time fields by battery power even while the +system is off. The current time fields should not be read while an update is +in progress, as indicated in the status register. + +The clock uses a 32.768kHz crystal, so bits 6-4 of register A should be +programmed to a 32kHz divider if the RTC is to count seconds. + +This is the RAM map originally used for the RTC/CMOS: + +Location Size Description +------------------------------------------ +00h byte Current second (BCD) +01h byte Seconds alarm (BCD) +02h byte Current minute (BCD) +03h byte Minutes alarm (BCD) +04h byte Current hour (BCD) +05h byte Hours alarm (BCD) +06h byte Current day of week (BCD) +07h byte Current day of month (BCD) +08h byte Current month (BCD) +09h byte Current year (BCD) +0Ah byte Register A + bit 7 = Update in progress + bit 6-4 = Divider for clock + 000 = 4.194 MHz + 001 = 1.049 MHz + 010 = 32 kHz + 10X = test modes + 110 = reset / disable + 111 = reset / disable + bit 3-0 = Rate selection for periodic interrupt + 000 = periodic timer disabled + 001 = 3.90625 uS + 010 = 7.8125 uS + 011 = .122070 mS + 100 = .244141 mS + ... + 1101 = 125 mS + 1110 = 250 mS + 1111 = 500 mS +0Bh byte Register B + bit 7 = Run (0) / Halt (1) + bit 6 = Periodic interrupt enable + bit 5 = Alarm interrupt enable + bit 4 = Update-ended interrupt enable + bit 3 = Square wave interrupt enable + bit 2 = BCD calendar (0) / Binary (1) + bit 1 = 12-hour mode (0) / 24-hour mode (1) + bit 0 = 0 (DST off) / 1 (DST enabled) +OCh byte Register C (read only) + bit 7 = interrupt request flag (IRQF) + bit 6 = periodic interrupt flag (PF) + bit 5 = alarm interrupt flag (AF) + bit 4 = update interrupt flag (UF) + bit 3-0 = reserved +ODh byte Register D (read only) + bit 7 = RTC has power + bit 6-0 = reserved +32h byte Current century BCD (*) + (*) location vendor specific and now determined from ACPI global tables + +2.3) APIC + +On Pentium and later processors, an on-board timer is available to each CPU +as part of the Advanced Programmable Interrupt Controller. The APIC is +accessed through memory-mapped registers and provides interrupt service to each +CPU, used for IPIs and local timer interrupts. + +Although in theory the APIC is a safe and stable source for local interrupts, +in practice, many bugs and glitches have occurred due to the special nature of +the APIC CPU-local memory-mapped hardware. Beware that CPU errata may affect +the use of the APIC and that workarounds may be required. In addition, some of +these workarounds pose unique constraints for virtualization - requiring either +extra overhead incurred from extra reads of memory-mapped I/O or additional +functionality that may be more computationally expensive to implement. + +Since the APIC is documented quite well in the Intel and AMD manuals, we will +avoid repetition of the detail here. It should be pointed out that the APIC +timer is programmed through the LVT (local vector timer) register, is capable +of one-shot or periodic operation, and is based on the bus clock divided down +by the programmable divider register. + +2.4) HPET + +HPET is quite complex, and was originally intended to replace the PIT / RTC +support of the X86 PC. It remains to be seen whether that will be the case, as +the de facto standard of PC hardware is to emulate these older devices. Some +systems designated as legacy free may support only the HPET as a hardware timer +device. + +The HPET spec is rather loose and vague, requiring at least 3 hardware timers, +but allowing implementation freedom to support many more. It also imposes no +fixed rate on the timer frequency, but does impose some extremal values on +frequency, error and slew. + +In general, the HPET is recommended as a high precision (compared to PIT /RTC) +time source which is independent of local variation (as there is only one HPET +in any given system). The HPET is also memory-mapped, and its presence is +indicated through ACPI tables by the BIOS. + +Detailed specification of the HPET is beyond the current scope of this +document, as it is also very well documented elsewhere. + +2.5) Offboard Timers + +Several cards, both proprietary (watchdog boards) and commonplace (e1000) have +timing chips built into the cards which may have registers which are accessible +to kernel or user drivers. To the author's knowledge, using these to generate +a clocksource for a Linux or other kernel has not yet been attempted and is in +general frowned upon as not playing by the agreed rules of the game. Such a +timer device would require additional support to be virtualized properly and is +not considered important at this time as no known operating system does this. + +========================================================================= + +3) TSC Hardware + +The TSC or time stamp counter is relatively simple in theory; it counts +instruction cycles issued by the processor, which can be used as a measure of +time. In practice, due to a number of problems, it is the most complicated +timekeeping device to use. + +The TSC is represented internally as a 64-bit MSR which can be read with the +RDMSR, RDTSC, or RDTSCP (when available) instructions. In the past, hardware +limitations made it possible to write the TSC, but generally on old hardware it +was only possible to write the low 32-bits of the 64-bit counter, and the upper +32-bits of the counter were cleared. Now, however, on Intel processors family +0Fh, for models 3, 4 and 6, and family 06h, models e and f, this restriction +has been lifted and all 64-bits are writable. On AMD systems, the ability to +write the TSC MSR is not an architectural guarantee. + +The TSC is accessible from CPL-0 and conditionally, for CPL > 0 software by +means of the CR4.TSD bit, which when enabled, disables CPL > 0 TSC access. + +Some vendors have implemented an additional instruction, RDTSCP, which returns +atomically not just the TSC, but an indicator which corresponds to the +processor number. This can be used to index into an array of TSC variables to +determine offset information in SMP systems where TSCs are not synchronized. +The presence of this instruction must be determined by consulting CPUID feature +bits. + +Both VMX and SVM provide extension fields in the virtualization hardware which +allows the guest visible TSC to be offset by a constant. Newer implementations +promise to allow the TSC to additionally be scaled, but this hardware is not +yet widely available. + +3.1) TSC synchronization + +The TSC is a CPU-local clock in most implementations. This means, on SMP +platforms, the TSCs of different CPUs may start at different times depending +on when the CPUs are powered on. Generally, CPUs on the same die will share +the same clock, however, this is not always the case. + +The BIOS may attempt to resynchronize the TSCs during the poweron process and +the operating system or other system software may attempt to do this as well. +Several hardware limitations make the problem worse - if it is not possible to +write the full 64-bits of the TSC, it may be impossible to match the TSC in +newly arriving CPUs to that of the rest of the system, resulting in +unsynchronized TSCs. This may be done by BIOS or system software, but in +practice, getting a perfectly synchronized TSC will not be possible unless all +values are read from the same clock, which generally only is possible on single +socket systems or those with special hardware support. + +3.2) TSC and CPU hotplug + +As touched on already, CPUs which arrive later than the boot time of the system +may not have a TSC value that is synchronized with the rest of the system. +Either system software, BIOS, or SMM code may actually try to establish the TSC +to a value matching the rest of the system, but a perfect match is usually not +a guarantee. This can have the effect of bringing a system from a state where +TSC is synchronized back to a state where TSC synchronization flaws, however +small, may be exposed to the OS and any virtualization environment. + +3.3) TSC and multi-socket / NUMA + +Multi-socket systems, especially large multi-socket systems are likely to have +individual clocksources rather than a single, universally distributed clock. +Since these clocks are driven by different crystals, they will not have +perfectly matched frequency, and temperature and electrical variations will +cause the CPU clocks, and thus the TSCs to drift over time. Depending on the +exact clock and bus design, the drift may or may not be fixed in absolute +error, and may accumulate over time. + +In addition, very large systems may deliberately slew the clocks of individual +cores. This technique, known as spread-spectrum clocking, reduces EMI at the +clock frequency and harmonics of it, which may be required to pass FCC +standards for telecommunications and computer equipment. + +It is recommended not to trust the TSCs to remain synchronized on NUMA or +multiple socket systems for these reasons. + +3.4) TSC and C-states + +C-states, or idling states of the processor, especially C1E and deeper sleep +states may be problematic for TSC as well. The TSC may stop advancing in such +a state, resulting in a TSC which is behind that of other CPUs when execution +is resumed. Such CPUs must be detected and flagged by the operating system +based on CPU and chipset identifications. + +The TSC in such a case may be corrected by catching it up to a known external +clocksource. + +3.5) TSC frequency change / P-states + +To make things slightly more interesting, some CPUs may change frequency. They +may or may not run the TSC at the same rate, and because the frequency change +may be staggered or slewed, at some points in time, the TSC rate may not be +known other than falling within a range of values. In this case, the TSC will +not be a stable time source, and must be calibrated against a known, stable, +external clock to be a usable source of time. + +Whether the TSC runs at a constant rate or scales with the P-state is model +dependent and must be determined by inspecting CPUID, chipset or vendor +specific MSR fields. + +In addition, some vendors have known bugs where the P-state is actually +compensated for properly during normal operation, but when the processor is +inactive, the P-state may be raised temporarily to service cache misses from +other processors. In such cases, the TSC on halted CPUs could advance faster +than that of non-halted processors. AMD Turion processors are known to have +this problem. + +3.6) TSC and STPCLK / T-states + +External signals given to the processor may also have the effect of stopping +the TSC. This is typically done for thermal emergency power control to prevent +an overheating condition, and typically, there is no way to detect that this +condition has happened. + +3.7) TSC virtualization - VMX + +VMX provides conditional trapping of RDTSC, RDMSR, WRMSR and RDTSCP +instructions, which is enough for full virtualization of TSC in any manner. In +addition, VMX allows passing through the host TSC plus an additional TSC_OFFSET +field specified in the VMCS. Special instructions must be used to read and +write the VMCS field. + +3.8) TSC virtualization - SVM + +SVM provides conditional trapping of RDTSC, RDMSR, WRMSR and RDTSCP +instructions, which is enough for full virtualization of TSC in any manner. In +addition, SVM allows passing through the host TSC plus an additional offset +field specified in the SVM control block. + +3.9) TSC feature bits in Linux + +In summary, there is no way to guarantee the TSC remains in perfect +synchronization unless it is explicitly guaranteed by the architecture. Even +if so, the TSCs in multi-sockets or NUMA systems may still run independently +despite being locally consistent. + +The following feature bits are used by Linux to signal various TSC attributes, +but they can only be taken to be meaningful for UP or single node systems. + +X86_FEATURE_TSC : The TSC is available in hardware +X86_FEATURE_RDTSCP : The RDTSCP instruction is available +X86_FEATURE_CONSTANT_TSC : The TSC rate is unchanged with P-states +X86_FEATURE_NONSTOP_TSC : The TSC does not stop in C-states +X86_FEATURE_TSC_RELIABLE : TSC sync checks are skipped (VMware) + +4) Virtualization Problems + +Timekeeping is especially problematic for virtualization because a number of +challenges arise. The most obvious problem is that time is now shared between +the host and, potentially, a number of virtual machines. Thus the virtual +operating system does not run with 100% usage of the CPU, despite the fact that +it may very well make that assumption. It may expect it to remain true to very +exacting bounds when interrupt sources are disabled, but in reality only its +virtual interrupt sources are disabled, and the machine may still be preempted +at any time. This causes problems as the passage of real time, the injection +of machine interrupts and the associated clock sources are no longer completely +synchronized with real time. + +This same problem can occur on native harware to a degree, as SMM mode may +steal cycles from the naturally on X86 systems when SMM mode is used by the +BIOS, but not in such an extreme fashion. However, the fact that SMM mode may +cause similar problems to virtualization makes it a good justification for +solving many of these problems on bare metal. + +4.1) Interrupt clocking + +One of the most immediate problems that occurs with legacy operating systems +is that the system timekeeping routines are often designed to keep track of +time by counting periodic interrupts. These interrupts may come from the PIT +or the RTC, but the problem is the same: the host virtualization engine may not +be able to deliver the proper number of interrupts per second, and so guest +time may fall behind. This is especially problematic if a high interrupt rate +is selected, such as 1000 HZ, which is unfortunately the default for many Linux +guests. + +There are three approaches to solving this problem; first, it may be possible +to simply ignore it. Guests which have a separate time source for tracking +'wall clock' or 'real time' may not need any adjustment of their interrupts to +maintain proper time. If this is not sufficient, it may be necessary to inject +additional interrupts into the guest in order to increase the effective +interrupt rate. This approach leads to complications in extreme conditions, +where host load or guest lag is too much to compensate for, and thus another +solution to the problem has risen: the guest may need to become aware of lost +ticks and compensate for them internally. Although promising in theory, the +implementation of this policy in Linux has been extremely error prone, and a +number of buggy variants of lost tick compensation are distributed across +commonly used Linux systems. + +Windows uses periodic RTC clocking as a means of keeping time internally, and +thus requires interrupt slewing to keep proper time. It does use a low enough +rate (ed: is it 18.2 Hz?) however that it has not yet been a problem in +practice. + +4.2) TSC sampling and serialization + +As the highest precision time source available, the cycle counter of the CPU +has aroused much interest from developers. As explained above, this timer has +many problems unique to its nature as a local, potentially unstable and +potentially unsynchronized source. One issue which is not unique to the TSC, +but is highlighted because of its very precise nature is sampling delay. By +definition, the counter, once read is already old. However, it is also +possible for the counter to be read ahead of the actual use of the result. +This is a consequence of the superscalar execution of the instruction stream, +which may execute instructions out of order. Such execution is called +non-serialized. Forcing serialized execution is necessary for precise +measurement with the TSC, and requires a serializing instruction, such as CPUID +or an MSR read. + +Since CPUID may actually be virtualized by a trap and emulate mechanism, this +serialization can pose a performance issue for hardware virtualization. An +accurate time stamp counter reading may therefore not always be available, and +it may be necessary for an implementation to guard against "backwards" reads of +the TSC as seen from other CPUs, even in an otherwise perfectly synchronized +system. + +4.3) Timespec aliasing + +Additionally, this lack of serialization from the TSC poses another challenge +when using results of the TSC when measured against another time source. As +the TSC is much higher precision, many possible values of the TSC may be read +while another clock is still expressing the same value. + +That is, you may read (T,T+10) while external clock C maintains the same value. +Due to non-serialized reads, you may actually end up with a range which +fluctuates - from (T-1.. T+10). Thus, any time calculated from a TSC, but +calibrated against an external value may have a range of valid values. +Re-calibrating this computation may actually cause time, as computed after the +calibration, to go backwards, compared with time computed before the +calibration. + +This problem is particularly pronounced with an internal time source in Linux, +the kernel time, which is expressed in the theoretically high resolution +timespec - but which advances in much larger granularity intervals, sometimes +at the rate of jiffies, and possibly in catchup modes, at a much larger step. + +This aliasing requires care in the computation and recalibration of kvmclock +and any other values derived from TSC computation (such as TSC virtualization +itself). + +4.4) Migration + +Migration of a virtual machine raises problems for timekeeping in two ways. +First, the migration itself may take time, during which interrupts cannot be +delivered, and after which, the guest time may need to be caught up. NTP may +be able to help to some degree here, as the clock correction required is +typically small enough to fall in the NTP-correctable window. + +An additional concern is that timers based off the TSC (or HPET, if the raw bus +clock is exposed) may now be running at different rates, requiring compensation +in some way in the hypervisor by virtualizing these timers. In addition, +migrating to a faster machine may preclude the use of a passthrough TSC, as a +faster clock cannot be made visible to a guest without the potential of time +advancing faster than usual. A slower clock is less of a problem, as it can +always be caught up to the original rate. KVM clock avoids these problems by +simply storing multipliers and offsets against the TSC for the guest to convert +back into nanosecond resolution values. + +4.5) Scheduling + +Since scheduling may be based on precise timing and firing of interrupts, the +scheduling algorithms of an operating system may be adversely affected by +virtualization. In theory, the effect is random and should be universally +distributed, but in contrived as well as real scenarios (guest device access, +causes of virtualization exits, possible context switch), this may not always +be the case. The effect of this has not been well studied. + +In an attempt to work around this, several implementations have provided a +paravirtualized scheduler clock, which reveals the true amount of CPU time for +which a virtual machine has been running. + +4.6) Watchdogs + +Watchdog timers, such as the lock detector in Linux may fire accidentally when +running under hardware virtualization due to timer interrupts being delayed or +misinterpretation of the passage of real time. Usually, these warnings are +spurious and can be ignored, but in some circumstances it may be necessary to +disable such detection. + +4.7) Delays and precision timing + +Precise timing and delays may not be possible in a virtualized system. This +can happen if the system is controlling physical hardware, or issues delays to +compensate for slower I/O to and from devices. The first issue is not solvable +in general for a virtualized system; hardware control software can't be +adequately virtualized without a full real-time operating system, which would +require an RT aware virtualization platform. + +The second issue may cause performance problems, but this is unlikely to be a +significant issue. In many cases these delays may be eliminated through +configuration or paravirtualization. + +4.8) Covert channels and leaks + +In addition to the above problems, time information will inevitably leak to the +guest about the host in anything but a perfect implementation of virtualized +time. This may allow the guest to infer the presence of a hypervisor (as in a +red-pill type detection), and it may allow information to leak between guests +by using CPU utilization itself as a signalling channel. Preventing such +problems would require completely isolated virtual time which may not track +real time any longer. This may be useful in certain security or QA contexts, +but in general isn't recommended for real-world deployment scenarios. diff --git a/Documentation/virtual/lguest/.gitignore b/Documentation/virtual/lguest/.gitignore new file mode 100644 index 0000000..115587f --- /dev/null +++ b/Documentation/virtual/lguest/.gitignore @@ -0,0 +1 @@ +lguest diff --git a/Documentation/virtual/lguest/Makefile b/Documentation/virtual/lguest/Makefile new file mode 100644 index 0000000..bebac6b --- /dev/null +++ b/Documentation/virtual/lguest/Makefile @@ -0,0 +1,8 @@ +# This creates the demonstration utility "lguest" which runs a Linux guest. +# Missing headers? Add "-I../../include -I../../arch/x86/include" +CFLAGS:=-m32 -Wall -Wmissing-declarations -Wmissing-prototypes -O3 -U_FORTIFY_SOURCE + +all: lguest + +clean: + rm -f lguest diff --git a/Documentation/virtual/lguest/extract b/Documentation/virtual/lguest/extract new file mode 100644 index 0000000..7730bb6 --- /dev/null +++ b/Documentation/virtual/lguest/extract @@ -0,0 +1,58 @@ +#! /bin/sh + +set -e + +PREFIX=$1 +shift + +trap 'rm -r $TMPDIR' 0 +TMPDIR=`mktemp -d` + +exec 3>/dev/null +for f; do + while IFS=" +" read -r LINE; do + case "$LINE" in + *$PREFIX:[0-9]*:\**) + NUM=`echo "$LINE" | sed "s/.*$PREFIX:\([0-9]*\).*/\1/"` + if [ -f $TMPDIR/$NUM ]; then + echo "$TMPDIR/$NUM already exits prior to $f" + exit 1 + fi + exec 3>>$TMPDIR/$NUM + echo $f | sed 's,\.\./,,g' > $TMPDIR/.$NUM + /bin/echo "$LINE" | sed -e "s/$PREFIX:[0-9]*//" -e "s/:\*/*/" >&3 + ;; + *$PREFIX:[0-9]*) + NUM=`echo "$LINE" | sed "s/.*$PREFIX:\([0-9]*\).*/\1/"` + if [ -f $TMPDIR/$NUM ]; then + echo "$TMPDIR/$NUM already exits prior to $f" + exit 1 + fi + exec 3>>$TMPDIR/$NUM + echo $f | sed 's,\.\./,,g' > $TMPDIR/.$NUM + /bin/echo "$LINE" | sed "s/$PREFIX:[0-9]*//" >&3 + ;; + *:\**) + /bin/echo "$LINE" | sed -e "s/:\*/*/" -e "s,/\*\*/,," >&3 + echo >&3 + exec 3>/dev/null + ;; + *) + /bin/echo "$LINE" >&3 + ;; + esac + done < $f + echo >&3 + exec 3>/dev/null +done + +LASTFILE="" +for f in $TMPDIR/*; do + if [ "$LASTFILE" != $(cat $TMPDIR/.$(basename $f) ) ]; then + LASTFILE=$(cat $TMPDIR/.$(basename $f) ) + echo "[ $LASTFILE ]" + fi + cat $f +done + diff --git a/Documentation/virtual/lguest/lguest.c b/Documentation/virtual/lguest/lguest.c new file mode 100644 index 0000000..d9da7e1 --- /dev/null +++ b/Documentation/virtual/lguest/lguest.c @@ -0,0 +1,2095 @@ +/*P:100 + * This is the Launcher code, a simple program which lays out the "physical" + * memory for the new Guest by mapping the kernel image and the virtual + * devices, then opens /dev/lguest to tell the kernel about the Guest and + * control it. +:*/ +#define _LARGEFILE64_SOURCE +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include "../../include/linux/lguest_launcher.h" +/*L:110 + * We can ignore the 42 include files we need for this program, but I do want + * to draw attention to the use of kernel-style types. + * + * As Linus said, "C is a Spartan language, and so should your naming be." I + * like these abbreviations, so we define them here. Note that u64 is always + * unsigned long long, which works on all Linux systems: this means that we can + * use %llu in printf for any u64. + */ +typedef unsigned long long u64; +typedef uint32_t u32; +typedef uint16_t u16; +typedef uint8_t u8; +/*:*/ + +#define PAGE_PRESENT 0x7 /* Present, RW, Execute */ +#define BRIDGE_PFX "bridge:" +#ifndef SIOCBRADDIF +#define SIOCBRADDIF 0x89a2 /* add interface to bridge */ +#endif +/* We can have up to 256 pages for devices. */ +#define DEVICE_PAGES 256 +/* This will occupy 3 pages: it must be a power of 2. */ +#define VIRTQUEUE_NUM 256 + +/*L:120 + * verbose is both a global flag and a macro. The C preprocessor allows + * this, and although I wouldn't recommend it, it works quite nicely here. + */ +static bool verbose; +#define verbose(args...) \ + do { if (verbose) printf(args); } while(0) +/*:*/ + +/* The pointer to the start of guest memory. */ +static void *guest_base; +/* The maximum guest physical address allowed, and maximum possible. */ +static unsigned long guest_limit, guest_max; +/* The /dev/lguest file descriptor. */ +static int lguest_fd; + +/* a per-cpu variable indicating whose vcpu is currently running */ +static unsigned int __thread cpu_id; + +/* This is our list of devices. */ +struct device_list { + /* Counter to assign interrupt numbers. */ + unsigned int next_irq; + + /* Counter to print out convenient device numbers. */ + unsigned int device_num; + + /* The descriptor page for the devices. */ + u8 *descpage; + + /* A single linked list of devices. */ + struct device *dev; + /* And a pointer to the last device for easy append. */ + struct device *lastdev; +}; + +/* The list of Guest devices, based on command line arguments. */ +static struct device_list devices; + +/* The device structure describes a single device. */ +struct device { + /* The linked-list pointer. */ + struct device *next; + + /* The device's descriptor, as mapped into the Guest. */ + struct lguest_device_desc *desc; + + /* We can't trust desc values once Guest has booted: we use these. */ + unsigned int feature_len; + unsigned int num_vq; + + /* The name of this device, for --verbose. */ + const char *name; + + /* Any queues attached to this device */ + struct virtqueue *vq; + + /* Is it operational */ + bool running; + + /* Does Guest want an intrrupt on empty? */ + bool irq_on_empty; + + /* Device-specific data. */ + void *priv; +}; + +/* The virtqueue structure describes a queue attached to a device. */ +struct virtqueue { + struct virtqueue *next; + + /* Which device owns me. */ + struct device *dev; + + /* The configuration for this queue. */ + struct lguest_vqconfig config; + + /* The actual ring of buffers. */ + struct vring vring; + + /* Last available index we saw. */ + u16 last_avail_idx; + + /* How many are used since we sent last irq? */ + unsigned int pending_used; + + /* Eventfd where Guest notifications arrive. */ + int eventfd; + + /* Function for the thread which is servicing this virtqueue. */ + void (*service)(struct virtqueue *vq); + pid_t thread; +}; + +/* Remember the arguments to the program so we can "reboot" */ +static char **main_args; + +/* The original tty settings to restore on exit. */ +static struct termios orig_term; + +/* + * We have to be careful with barriers: our devices are all run in separate + * threads and so we need to make sure that changes visible to the Guest happen + * in precise order. + */ +#define wmb() __asm__ __volatile__("" : : : "memory") +#define mb() __asm__ __volatile__("" : : : "memory") + +/* + * Convert an iovec element to the given type. + * + * This is a fairly ugly trick: we need to know the size of the type and + * alignment requirement to check the pointer is kosher. It's also nice to + * have the name of the type in case we report failure. + * + * Typing those three things all the time is cumbersome and error prone, so we + * have a macro which sets them all up and passes to the real function. + */ +#define convert(iov, type) \ + ((type *)_convert((iov), sizeof(type), __alignof__(type), #type)) + +static void *_convert(struct iovec *iov, size_t size, size_t align, + const char *name) +{ + if (iov->iov_len != size) + errx(1, "Bad iovec size %zu for %s", iov->iov_len, name); + if ((unsigned long)iov->iov_base % align != 0) + errx(1, "Bad alignment %p for %s", iov->iov_base, name); + return iov->iov_base; +} + +/* Wrapper for the last available index. Makes it easier to change. */ +#define lg_last_avail(vq) ((vq)->last_avail_idx) + +/* + * The virtio configuration space is defined to be little-endian. x86 is + * little-endian too, but it's nice to be explicit so we have these helpers. + */ +#define cpu_to_le16(v16) (v16) +#define cpu_to_le32(v32) (v32) +#define cpu_to_le64(v64) (v64) +#define le16_to_cpu(v16) (v16) +#define le32_to_cpu(v32) (v32) +#define le64_to_cpu(v64) (v64) + +/* Is this iovec empty? */ +static bool iov_empty(const struct iovec iov[], unsigned int num_iov) +{ + unsigned int i; + + for (i = 0; i < num_iov; i++) + if (iov[i].iov_len) + return false; + return true; +} + +/* Take len bytes from the front of this iovec. */ +static void iov_consume(struct iovec iov[], unsigned num_iov, unsigned len) +{ + unsigned int i; + + for (i = 0; i < num_iov; i++) { + unsigned int used; + + used = iov[i].iov_len < len ? iov[i].iov_len : len; + iov[i].iov_base += used; + iov[i].iov_len -= used; + len -= used; + } + assert(len == 0); +} + +/* The device virtqueue descriptors are followed by feature bitmasks. */ +static u8 *get_feature_bits(struct device *dev) +{ + return (u8 *)(dev->desc + 1) + + dev->num_vq * sizeof(struct lguest_vqconfig); +} + +/*L:100 + * The Launcher code itself takes us out into userspace, that scary place where + * pointers run wild and free! Unfortunately, like most userspace programs, + * it's quite boring (which is why everyone likes to hack on the kernel!). + * Perhaps if you make up an Lguest Drinking Game at this point, it will get + * you through this section. Or, maybe not. + * + * The Launcher sets up a big chunk of memory to be the Guest's "physical" + * memory and stores it in "guest_base". In other words, Guest physical == + * Launcher virtual with an offset. + * + * This can be tough to get your head around, but usually it just means that we + * use these trivial conversion functions when the Guest gives us its + * "physical" addresses: + */ +static void *from_guest_phys(unsigned long addr) +{ + return guest_base + addr; +} + +static unsigned long to_guest_phys(const void *addr) +{ + return (addr - guest_base); +} + +/*L:130 + * Loading the Kernel. + * + * We start with couple of simple helper routines. open_or_die() avoids + * error-checking code cluttering the callers: + */ +static int open_or_die(const char *name, int flags) +{ + int fd = open(name, flags); + if (fd < 0) + err(1, "Failed to open %s", name); + return fd; +} + +/* map_zeroed_pages() takes a number of pages. */ +static void *map_zeroed_pages(unsigned int num) +{ + int fd = open_or_die("/dev/zero", O_RDONLY); + void *addr; + + /* + * We use a private mapping (ie. if we write to the page, it will be + * copied). We allocate an extra two pages PROT_NONE to act as guard + * pages against read/write attempts that exceed allocated space. + */ + addr = mmap(NULL, getpagesize() * (num+2), + PROT_NONE, MAP_PRIVATE, fd, 0); + + if (addr == MAP_FAILED) + err(1, "Mmapping %u pages of /dev/zero", num); + + if (mprotect(addr + getpagesize(), getpagesize() * num, + PROT_READ|PROT_WRITE) == -1) + err(1, "mprotect rw %u pages failed", num); + + /* + * One neat mmap feature is that you can close the fd, and it + * stays mapped. + */ + close(fd); + + /* Return address after PROT_NONE page */ + return addr + getpagesize(); +} + +/* Get some more pages for a device. */ +static void *get_pages(unsigned int num) +{ + void *addr = from_guest_phys(guest_limit); + + guest_limit += num * getpagesize(); + if (guest_limit > guest_max) + errx(1, "Not enough memory for devices"); + return addr; +} + +/* + * This routine is used to load the kernel or initrd. It tries mmap, but if + * that fails (Plan 9's kernel file isn't nicely aligned on page boundaries), + * it falls back to reading the memory in. + */ +static void map_at(int fd, void *addr, unsigned long offset, unsigned long len) +{ + ssize_t r; + + /* + * We map writable even though for some segments are marked read-only. + * The kernel really wants to be writable: it patches its own + * instructions. + * + * MAP_PRIVATE means that the page won't be copied until a write is + * done to it. This allows us to share untouched memory between + * Guests. + */ + if (mmap(addr, len, PROT_READ|PROT_WRITE, + MAP_FIXED|MAP_PRIVATE, fd, offset) != MAP_FAILED) + return; + + /* pread does a seek and a read in one shot: saves a few lines. */ + r = pread(fd, addr, len, offset); + if (r != len) + err(1, "Reading offset %lu len %lu gave %zi", offset, len, r); +} + +/* + * This routine takes an open vmlinux image, which is in ELF, and maps it into + * the Guest memory. ELF = Embedded Linking Format, which is the format used + * by all modern binaries on Linux including the kernel. + * + * The ELF headers give *two* addresses: a physical address, and a virtual + * address. We use the physical address; the Guest will map itself to the + * virtual address. + * + * We return the starting address. + */ +static unsigned long map_elf(int elf_fd, const Elf32_Ehdr *ehdr) +{ + Elf32_Phdr phdr[ehdr->e_phnum]; + unsigned int i; + + /* + * Sanity checks on the main ELF header: an x86 executable with a + * reasonable number of correctly-sized program headers. + */ + if (ehdr->e_type != ET_EXEC + || ehdr->e_machine != EM_386 + || ehdr->e_phentsize != sizeof(Elf32_Phdr) + || ehdr->e_phnum < 1 || ehdr->e_phnum > 65536U/sizeof(Elf32_Phdr)) + errx(1, "Malformed elf header"); + + /* + * An ELF executable contains an ELF header and a number of "program" + * headers which indicate which parts ("segments") of the program to + * load where. + */ + + /* We read in all the program headers at once: */ + if (lseek(elf_fd, ehdr->e_phoff, SEEK_SET) < 0) + err(1, "Seeking to program headers"); + if (read(elf_fd, phdr, sizeof(phdr)) != sizeof(phdr)) + err(1, "Reading program headers"); + + /* + * Try all the headers: there are usually only three. A read-only one, + * a read-write one, and a "note" section which we don't load. + */ + for (i = 0; i < ehdr->e_phnum; i++) { + /* If this isn't a loadable segment, we ignore it */ + if (phdr[i].p_type != PT_LOAD) + continue; + + verbose("Section %i: size %i addr %p\n", + i, phdr[i].p_memsz, (void *)phdr[i].p_paddr); + + /* We map this section of the file at its physical address. */ + map_at(elf_fd, from_guest_phys(phdr[i].p_paddr), + phdr[i].p_offset, phdr[i].p_filesz); + } + + /* The entry point is given in the ELF header. */ + return ehdr->e_entry; +} + +/*L:150 + * A bzImage, unlike an ELF file, is not meant to be loaded. You're supposed + * to jump into it and it will unpack itself. We used to have to perform some + * hairy magic because the unpacking code scared me. + * + * Fortunately, Jeremy Fitzhardinge convinced me it wasn't that hard and wrote + * a small patch to jump over the tricky bits in the Guest, so now we just read + * the funky header so we know where in the file to load, and away we go! + */ +static unsigned long load_bzimage(int fd) +{ + struct boot_params boot; + int r; + /* Modern bzImages get loaded at 1M. */ + void *p = from_guest_phys(0x100000); + + /* + * Go back to the start of the file and read the header. It should be + * a Linux boot header (see Documentation/x86/i386/boot.txt) + */ + lseek(fd, 0, SEEK_SET); + read(fd, &boot, sizeof(boot)); + + /* Inside the setup_hdr, we expect the magic "HdrS" */ + if (memcmp(&boot.hdr.header, "HdrS", 4) != 0) + errx(1, "This doesn't look like a bzImage to me"); + + /* Skip over the extra sectors of the header. */ + lseek(fd, (boot.hdr.setup_sects+1) * 512, SEEK_SET); + + /* Now read everything into memory. in nice big chunks. */ + while ((r = read(fd, p, 65536)) > 0) + p += r; + + /* Finally, code32_start tells us where to enter the kernel. */ + return boot.hdr.code32_start; +} + +/*L:140 + * Loading the kernel is easy when it's a "vmlinux", but most kernels + * come wrapped up in the self-decompressing "bzImage" format. With a little + * work, we can load those, too. + */ +static unsigned long load_kernel(int fd) +{ + Elf32_Ehdr hdr; + + /* Read in the first few bytes. */ + if (read(fd, &hdr, sizeof(hdr)) != sizeof(hdr)) + err(1, "Reading kernel"); + + /* If it's an ELF file, it starts with "\177ELF" */ + if (memcmp(hdr.e_ident, ELFMAG, SELFMAG) == 0) + return map_elf(fd, &hdr); + + /* Otherwise we assume it's a bzImage, and try to load it. */ + return load_bzimage(fd); +} + +/* + * This is a trivial little helper to align pages. Andi Kleen hated it because + * it calls getpagesize() twice: "it's dumb code." + * + * Kernel guys get really het up about optimization, even when it's not + * necessary. I leave this code as a reaction against that. + */ +static inline unsigned long page_align(unsigned long addr) +{ + /* Add upwards and truncate downwards. */ + return ((addr + getpagesize()-1) & ~(getpagesize()-1)); +} + +/*L:180 + * An "initial ram disk" is a disk image loaded into memory along with the + * kernel which the kernel can use to boot from without needing any drivers. + * Most distributions now use this as standard: the initrd contains the code to + * load the appropriate driver modules for the current machine. + * + * Importantly, James Morris works for RedHat, and Fedora uses initrds for its + * kernels. He sent me this (and tells me when I break it). + */ +static unsigned long load_initrd(const char *name, unsigned long mem) +{ + int ifd; + struct stat st; + unsigned long len; + + ifd = open_or_die(name, O_RDONLY); + /* fstat() is needed to get the file size. */ + if (fstat(ifd, &st) < 0) + err(1, "fstat() on initrd '%s'", name); + + /* + * We map the initrd at the top of memory, but mmap wants it to be + * page-aligned, so we round the size up for that. + */ + len = page_align(st.st_size); + map_at(ifd, from_guest_phys(mem - len), 0, st.st_size); + /* + * Once a file is mapped, you can close the file descriptor. It's a + * little odd, but quite useful. + */ + close(ifd); + verbose("mapped initrd %s size=%lu @ %p\n", name, len, (void*)mem-len); + + /* We return the initrd size. */ + return len; +} +/*:*/ + +/* + * Simple routine to roll all the commandline arguments together with spaces + * between them. + */ +static void concat(char *dst, char *args[]) +{ + unsigned int i, len = 0; + + for (i = 0; args[i]; i++) { + if (i) { + strcat(dst+len, " "); + len++; + } + strcpy(dst+len, args[i]); + len += strlen(args[i]); + } + /* In case it's empty. */ + dst[len] = '\0'; +} + +/*L:185 + * This is where we actually tell the kernel to initialize the Guest. We + * saw the arguments it expects when we looked at initialize() in lguest_user.c: + * the base of Guest "physical" memory, the top physical page to allow and the + * entry point for the Guest. + */ +static void tell_kernel(unsigned long start) +{ + unsigned long args[] = { LHREQ_INITIALIZE, + (unsigned long)guest_base, + guest_limit / getpagesize(), start }; + verbose("Guest: %p - %p (%#lx)\n", + guest_base, guest_base + guest_limit, guest_limit); + lguest_fd = open_or_die("/dev/lguest", O_RDWR); + if (write(lguest_fd, args, sizeof(args)) < 0) + err(1, "Writing to /dev/lguest"); +} +/*:*/ + +/*L:200 + * Device Handling. + * + * When the Guest gives us a buffer, it sends an array of addresses and sizes. + * We need to make sure it's not trying to reach into the Launcher itself, so + * we have a convenient routine which checks it and exits with an error message + * if something funny is going on: + */ +static void *_check_pointer(unsigned long addr, unsigned int size, + unsigned int line) +{ + /* + * Check if the requested address and size exceeds the allocated memory, + * or addr + size wraps around. + */ + if ((addr + size) > guest_limit || (addr + size) < addr) + errx(1, "%s:%i: Invalid address %#lx", __FILE__, line, addr); + /* + * We return a pointer for the caller's convenience, now we know it's + * safe to use. + */ + return from_guest_phys(addr); +} +/* A macro which transparently hands the line number to the real function. */ +#define check_pointer(addr,size) _check_pointer(addr, size, __LINE__) + +/* + * Each buffer in the virtqueues is actually a chain of descriptors. This + * function returns the next descriptor in the chain, or vq->vring.num if we're + * at the end. + */ +static unsigned next_desc(struct vring_desc *desc, + unsigned int i, unsigned int max) +{ + unsigned int next; + + /* If this descriptor says it doesn't chain, we're done. */ + if (!(desc[i].flags & VRING_DESC_F_NEXT)) + return max; + + /* Check they're not leading us off end of descriptors. */ + next = desc[i].next; + /* Make sure compiler knows to grab that: we don't want it changing! */ + wmb(); + + if (next >= max) + errx(1, "Desc next is %u", next); + + return next; +} + +/* + * This actually sends the interrupt for this virtqueue, if we've used a + * buffer. + */ +static void trigger_irq(struct virtqueue *vq) +{ + unsigned long buf[] = { LHREQ_IRQ, vq->config.irq }; + + /* Don't inform them if nothing used. */ + if (!vq->pending_used) + return; + vq->pending_used = 0; + + /* If they don't want an interrupt, don't send one... */ + if (vq->vring.avail->flags & VRING_AVAIL_F_NO_INTERRUPT) { + /* ... unless they've asked us to force one on empty. */ + if (!vq->dev->irq_on_empty + || lg_last_avail(vq) != vq->vring.avail->idx) + return; + } + + /* Send the Guest an interrupt tell them we used something up. */ + if (write(lguest_fd, buf, sizeof(buf)) != 0) + err(1, "Triggering irq %i", vq->config.irq); +} + +/* + * This looks in the virtqueue for the first available buffer, and converts + * it to an iovec for convenient access. Since descriptors consist of some + * number of output then some number of input descriptors, it's actually two + * iovecs, but we pack them into one and note how many of each there were. + * + * This function waits if necessary, and returns the descriptor number found. + */ +static unsigned wait_for_vq_desc(struct virtqueue *vq, + struct iovec iov[], + unsigned int *out_num, unsigned int *in_num) +{ + unsigned int i, head, max; + struct vring_desc *desc; + u16 last_avail = lg_last_avail(vq); + + /* There's nothing available? */ + while (last_avail == vq->vring.avail->idx) { + u64 event; + + /* + * Since we're about to sleep, now is a good time to tell the + * Guest about what we've used up to now. + */ + trigger_irq(vq); + + /* OK, now we need to know about added descriptors. */ + vq->vring.used->flags &= ~VRING_USED_F_NO_NOTIFY; + + /* + * They could have slipped one in as we were doing that: make + * sure it's written, then check again. + */ + mb(); + if (last_avail != vq->vring.avail->idx) { + vq->vring.used->flags |= VRING_USED_F_NO_NOTIFY; + break; + } + + /* Nothing new? Wait for eventfd to tell us they refilled. */ + if (read(vq->eventfd, &event, sizeof(event)) != sizeof(event)) + errx(1, "Event read failed?"); + + /* We don't need to be notified again. */ + vq->vring.used->flags |= VRING_USED_F_NO_NOTIFY; + } + + /* Check it isn't doing very strange things with descriptor numbers. */ + if ((u16)(vq->vring.avail->idx - last_avail) > vq->vring.num) + errx(1, "Guest moved used index from %u to %u", + last_avail, vq->vring.avail->idx); + + /* + * Grab the next descriptor number they're advertising, and increment + * the index we've seen. + */ + head = vq->vring.avail->ring[last_avail % vq->vring.num]; + lg_last_avail(vq)++; + + /* If their number is silly, that's a fatal mistake. */ + if (head >= vq->vring.num) + errx(1, "Guest says index %u is available", head); + + /* When we start there are none of either input nor output. */ + *out_num = *in_num = 0; + + max = vq->vring.num; + desc = vq->vring.desc; + i = head; + + /* + * If this is an indirect entry, then this buffer contains a descriptor + * table which we handle as if it's any normal descriptor chain. + */ + if (desc[i].flags & VRING_DESC_F_INDIRECT) { + if (desc[i].len % sizeof(struct vring_desc)) + errx(1, "Invalid size for indirect buffer table"); + + max = desc[i].len / sizeof(struct vring_desc); + desc = check_pointer(desc[i].addr, desc[i].len); + i = 0; + } + + do { + /* Grab the first descriptor, and check it's OK. */ + iov[*out_num + *in_num].iov_len = desc[i].len; + iov[*out_num + *in_num].iov_base + = check_pointer(desc[i].addr, desc[i].len); + /* If this is an input descriptor, increment that count. */ + if (desc[i].flags & VRING_DESC_F_WRITE) + (*in_num)++; + else { + /* + * If it's an output descriptor, they're all supposed + * to come before any input descriptors. + */ + if (*in_num) + errx(1, "Descriptor has out after in"); + (*out_num)++; + } + + /* If we've got too many, that implies a descriptor loop. */ + if (*out_num + *in_num > max) + errx(1, "Looped descriptor"); + } while ((i = next_desc(desc, i, max)) != max); + + return head; +} + +/* + * After we've used one of their buffers, we tell the Guest about it. Sometime + * later we'll want to send them an interrupt using trigger_irq(); note that + * wait_for_vq_desc() does that for us if it has to wait. + */ +static void add_used(struct virtqueue *vq, unsigned int head, int len) +{ + struct vring_used_elem *used; + + /* + * The virtqueue contains a ring of used buffers. Get a pointer to the + * next entry in that used ring. + */ + used = &vq->vring.used->ring[vq->vring.used->idx % vq->vring.num]; + used->id = head; + used->len = len; + /* Make sure buffer is written before we update index. */ + wmb(); + vq->vring.used->idx++; + vq->pending_used++; +} + +/* And here's the combo meal deal. Supersize me! */ +static void add_used_and_trigger(struct virtqueue *vq, unsigned head, int len) +{ + add_used(vq, head, len); + trigger_irq(vq); +} + +/* + * The Console + * + * We associate some data with the console for our exit hack. + */ +struct console_abort { + /* How many times have they hit ^C? */ + int count; + /* When did they start? */ + struct timeval start; +}; + +/* This is the routine which handles console input (ie. stdin). */ +static void console_input(struct virtqueue *vq) +{ + int len; + unsigned int head, in_num, out_num; + struct console_abort *abort = vq->dev->priv; + struct iovec iov[vq->vring.num]; + + /* Make sure there's a descriptor available. */ + head = wait_for_vq_desc(vq, iov, &out_num, &in_num); + if (out_num) + errx(1, "Output buffers in console in queue?"); + + /* Read into it. This is where we usually wait. */ + len = readv(STDIN_FILENO, iov, in_num); + if (len <= 0) { + /* Ran out of input? */ + warnx("Failed to get console input, ignoring console."); + /* + * For simplicity, dying threads kill the whole Launcher. So + * just nap here. + */ + for (;;) + pause(); + } + + /* Tell the Guest we used a buffer. */ + add_used_and_trigger(vq, head, len); + + /* + * Three ^C within one second? Exit. + * + * This is such a hack, but works surprisingly well. Each ^C has to + * be in a buffer by itself, so they can't be too fast. But we check + * that we get three within about a second, so they can't be too + * slow. + */ + if (len != 1 || ((char *)iov[0].iov_base)[0] != 3) { + abort->count = 0; + return; + } + + abort->count++; + if (abort->count == 1) + gettimeofday(&abort->start, NULL); + else if (abort->count == 3) { + struct timeval now; + gettimeofday(&now, NULL); + /* Kill all Launcher processes with SIGINT, like normal ^C */ + if (now.tv_sec <= abort->start.tv_sec+1) + kill(0, SIGINT); + abort->count = 0; + } +} + +/* This is the routine which handles console output (ie. stdout). */ +static void console_output(struct virtqueue *vq) +{ + unsigned int head, out, in; + struct iovec iov[vq->vring.num]; + + /* We usually wait in here, for the Guest to give us something. */ + head = wait_for_vq_desc(vq, iov, &out, &in); + if (in) + errx(1, "Input buffers in console output queue?"); + + /* writev can return a partial write, so we loop here. */ + while (!iov_empty(iov, out)) { + int len = writev(STDOUT_FILENO, iov, out); + if (len <= 0) + err(1, "Write to stdout gave %i", len); + iov_consume(iov, out, len); + } + + /* + * We're finished with that buffer: if we're going to sleep, + * wait_for_vq_desc() will prod the Guest with an interrupt. + */ + add_used(vq, head, 0); +} + +/* + * The Network + * + * Handling output for network is also simple: we get all the output buffers + * and write them to /dev/net/tun. + */ +struct net_info { + int tunfd; +}; + +static void net_output(struct virtqueue *vq) +{ + struct net_info *net_info = vq->dev->priv; + unsigned int head, out, in; + struct iovec iov[vq->vring.num]; + + /* We usually wait in here for the Guest to give us a packet. */ + head = wait_for_vq_desc(vq, iov, &out, &in); + if (in) + errx(1, "Input buffers in net output queue?"); + /* + * Send the whole thing through to /dev/net/tun. It expects the exact + * same format: what a coincidence! + */ + if (writev(net_info->tunfd, iov, out) < 0) + errx(1, "Write to tun failed?"); + + /* + * Done with that one; wait_for_vq_desc() will send the interrupt if + * all packets are processed. + */ + add_used(vq, head, 0); +} + +/* + * Handling network input is a bit trickier, because I've tried to optimize it. + * + * First we have a helper routine which tells is if from this file descriptor + * (ie. the /dev/net/tun device) will block: + */ +static bool will_block(int fd) +{ + fd_set fdset; + struct timeval zero = { 0, 0 }; + FD_ZERO(&fdset); + FD_SET(fd, &fdset); + return select(fd+1, &fdset, NULL, NULL, &zero) != 1; +} + +/* + * This handles packets coming in from the tun device to our Guest. Like all + * service routines, it gets called again as soon as it returns, so you don't + * see a while(1) loop here. + */ +static void net_input(struct virtqueue *vq) +{ + int len; + unsigned int head, out, in; + struct iovec iov[vq->vring.num]; + struct net_info *net_info = vq->dev->priv; + + /* + * Get a descriptor to write an incoming packet into. This will also + * send an interrupt if they're out of descriptors. + */ + head = wait_for_vq_desc(vq, iov, &out, &in); + if (out) + errx(1, "Output buffers in net input queue?"); + + /* + * If it looks like we'll block reading from the tun device, send them + * an interrupt. + */ + if (vq->pending_used && will_block(net_info->tunfd)) + trigger_irq(vq); + + /* + * Read in the packet. This is where we normally wait (when there's no + * incoming network traffic). + */ + len = readv(net_info->tunfd, iov, in); + if (len <= 0) + err(1, "Failed to read from tun."); + + /* + * Mark that packet buffer as used, but don't interrupt here. We want + * to wait until we've done as much work as we can. + */ + add_used(vq, head, len); +} +/*:*/ + +/* This is the helper to create threads: run the service routine in a loop. */ +static int do_thread(void *_vq) +{ + struct virtqueue *vq = _vq; + + for (;;) + vq->service(vq); + return 0; +} + +/* + * When a child dies, we kill our entire process group with SIGTERM. This + * also has the side effect that the shell restores the console for us! + */ +static void kill_launcher(int signal) +{ + kill(0, SIGTERM); +} + +static void reset_device(struct device *dev) +{ + struct virtqueue *vq; + + verbose("Resetting device %s\n", dev->name); + + /* Clear any features they've acked. */ + memset(get_feature_bits(dev) + dev->feature_len, 0, dev->feature_len); + + /* We're going to be explicitly killing threads, so ignore them. */ + signal(SIGCHLD, SIG_IGN); + + /* Zero out the virtqueues, get rid of their threads */ + for (vq = dev->vq; vq; vq = vq->next) { + if (vq->thread != (pid_t)-1) { + kill(vq->thread, SIGTERM); + waitpid(vq->thread, NULL, 0); + vq->thread = (pid_t)-1; + } + memset(vq->vring.desc, 0, + vring_size(vq->config.num, LGUEST_VRING_ALIGN)); + lg_last_avail(vq) = 0; + } + dev->running = false; + + /* Now we care if threads die. */ + signal(SIGCHLD, (void *)kill_launcher); +} + +/*L:216 + * This actually creates the thread which services the virtqueue for a device. + */ +static void create_thread(struct virtqueue *vq) +{ + /* + * Create stack for thread. Since the stack grows upwards, we point + * the stack pointer to the end of this region. + */ + char *stack = malloc(32768); + unsigned long args[] = { LHREQ_EVENTFD, + vq->config.pfn*getpagesize(), 0 }; + + /* Create a zero-initialized eventfd. */ + vq->eventfd = eventfd(0, 0); + if (vq->eventfd < 0) + err(1, "Creating eventfd"); + args[2] = vq->eventfd; + + /* + * Attach an eventfd to this virtqueue: it will go off when the Guest + * does an LHCALL_NOTIFY for this vq. + */ + if (write(lguest_fd, &args, sizeof(args)) != 0) + err(1, "Attaching eventfd"); + + /* + * CLONE_VM: because it has to access the Guest memory, and SIGCHLD so + * we get a signal if it dies. + */ + vq->thread = clone(do_thread, stack + 32768, CLONE_VM | SIGCHLD, vq); + if (vq->thread == (pid_t)-1) + err(1, "Creating clone"); + + /* We close our local copy now the child has it. */ + close(vq->eventfd); +} + +static bool accepted_feature(struct device *dev, unsigned int bit) +{ + const u8 *features = get_feature_bits(dev) + dev->feature_len; + + if (dev->feature_len < bit / CHAR_BIT) + return false; + return features[bit / CHAR_BIT] & (1 << (bit % CHAR_BIT)); +} + +static void start_device(struct device *dev) +{ + unsigned int i; + struct virtqueue *vq; + + verbose("Device %s OK: offered", dev->name); + for (i = 0; i < dev->feature_len; i++) + verbose(" %02x", get_feature_bits(dev)[i]); + verbose(", accepted"); + for (i = 0; i < dev->feature_len; i++) + verbose(" %02x", get_feature_bits(dev) + [dev->feature_len+i]); + + dev->irq_on_empty = accepted_feature(dev, VIRTIO_F_NOTIFY_ON_EMPTY); + + for (vq = dev->vq; vq; vq = vq->next) { + if (vq->service) + create_thread(vq); + } + dev->running = true; +} + +static void cleanup_devices(void) +{ + struct device *dev; + + for (dev = devices.dev; dev; dev = dev->next) + reset_device(dev); + + /* If we saved off the original terminal settings, restore them now. */ + if (orig_term.c_lflag & (ISIG|ICANON|ECHO)) + tcsetattr(STDIN_FILENO, TCSANOW, &orig_term); +} + +/* When the Guest tells us they updated the status field, we handle it. */ +static void update_device_status(struct device *dev) +{ + /* A zero status is a reset, otherwise it's a set of flags. */ + if (dev->desc->status == 0) + reset_device(dev); + else if (dev->desc->status & VIRTIO_CONFIG_S_FAILED) { + warnx("Device %s configuration FAILED", dev->name); + if (dev->running) + reset_device(dev); + } else if (dev->desc->status & VIRTIO_CONFIG_S_DRIVER_OK) { + if (!dev->running) + start_device(dev); + } +} + +/*L:215 + * This is the generic routine we call when the Guest uses LHCALL_NOTIFY. In + * particular, it's used to notify us of device status changes during boot. + */ +static void handle_output(unsigned long addr) +{ + struct device *i; + + /* Check each device. */ + for (i = devices.dev; i; i = i->next) { + struct virtqueue *vq; + + /* + * Notifications to device descriptors mean they updated the + * device status. + */ + if (from_guest_phys(addr) == i->desc) { + update_device_status(i); + return; + } + + /* + * Devices *can* be used before status is set to DRIVER_OK. + * The original plan was that they would never do this: they + * would always finish setting up their status bits before + * actually touching the virtqueues. In practice, we allowed + * them to, and they do (eg. the disk probes for partition + * tables as part of initialization). + * + * If we see this, we start the device: once it's running, we + * expect the device to catch all the notifications. + */ + for (vq = i->vq; vq; vq = vq->next) { + if (addr != vq->config.pfn*getpagesize()) + continue; + if (i->running) + errx(1, "Notification on running %s", i->name); + /* This just calls create_thread() for each virtqueue */ + start_device(i); + return; + } + } + + /* + * Early console write is done using notify on a nul-terminated string + * in Guest memory. It's also great for hacking debugging messages + * into a Guest. + */ + if (addr >= guest_limit) + errx(1, "Bad NOTIFY %#lx", addr); + + write(STDOUT_FILENO, from_guest_phys(addr), + strnlen(from_guest_phys(addr), guest_limit - addr)); +} + +/*L:190 + * Device Setup + * + * All devices need a descriptor so the Guest knows it exists, and a "struct + * device" so the Launcher can keep track of it. We have common helper + * routines to allocate and manage them. + */ + +/* + * The layout of the device page is a "struct lguest_device_desc" followed by a + * number of virtqueue descriptors, then two sets of feature bits, then an + * array of configuration bytes. This routine returns the configuration + * pointer. + */ +static u8 *device_config(const struct device *dev) +{ + return (void *)(dev->desc + 1) + + dev->num_vq * sizeof(struct lguest_vqconfig) + + dev->feature_len * 2; +} + +/* + * This routine allocates a new "struct lguest_device_desc" from descriptor + * table page just above the Guest's normal memory. It returns a pointer to + * that descriptor. + */ +static struct lguest_device_desc *new_dev_desc(u16 type) +{ + struct lguest_device_desc d = { .type = type }; + void *p; + + /* Figure out where the next device config is, based on the last one. */ + if (devices.lastdev) + p = device_config(devices.lastdev) + + devices.lastdev->desc->config_len; + else + p = devices.descpage; + + /* We only have one page for all the descriptors. */ + if (p + sizeof(d) > (void *)devices.descpage + getpagesize()) + errx(1, "Too many devices"); + + /* p might not be aligned, so we memcpy in. */ + return memcpy(p, &d, sizeof(d)); +} + +/* + * Each device descriptor is followed by the description of its virtqueues. We + * specify how many descriptors the virtqueue is to have. + */ +static void add_virtqueue(struct device *dev, unsigned int num_descs, + void (*service)(struct virtqueue *)) +{ + unsigned int pages; + struct virtqueue **i, *vq = malloc(sizeof(*vq)); + void *p; + + /* First we need some memory for this virtqueue. */ + pages = (vring_size(num_descs, LGUEST_VRING_ALIGN) + getpagesize() - 1) + / getpagesize(); + p = get_pages(pages); + + /* Initialize the virtqueue */ + vq->next = NULL; + vq->last_avail_idx = 0; + vq->dev = dev; + + /* + * This is the routine the service thread will run, and its Process ID + * once it's running. + */ + vq->service = service; + vq->thread = (pid_t)-1; + + /* Initialize the configuration. */ + vq->config.num = num_descs; + vq->config.irq = devices.next_irq++; + vq->config.pfn = to_guest_phys(p) / getpagesize(); + + /* Initialize the vring. */ + vring_init(&vq->vring, num_descs, p, LGUEST_VRING_ALIGN); + + /* + * Append virtqueue to this device's descriptor. We use + * device_config() to get the end of the device's current virtqueues; + * we check that we haven't added any config or feature information + * yet, otherwise we'd be overwriting them. + */ + assert(dev->desc->config_len == 0 && dev->desc->feature_len == 0); + memcpy(device_config(dev), &vq->config, sizeof(vq->config)); + dev->num_vq++; + dev->desc->num_vq++; + + verbose("Virtqueue page %#lx\n", to_guest_phys(p)); + + /* + * Add to tail of list, so dev->vq is first vq, dev->vq->next is + * second. + */ + for (i = &dev->vq; *i; i = &(*i)->next); + *i = vq; +} + +/* + * The first half of the feature bitmask is for us to advertise features. The + * second half is for the Guest to accept features. + */ +static void add_feature(struct device *dev, unsigned bit) +{ + u8 *features = get_feature_bits(dev); + + /* We can't extend the feature bits once we've added config bytes */ + if (dev->desc->feature_len <= bit / CHAR_BIT) { + assert(dev->desc->config_len == 0); + dev->feature_len = dev->desc->feature_len = (bit/CHAR_BIT) + 1; + } + + features[bit / CHAR_BIT] |= (1 << (bit % CHAR_BIT)); +} + +/* + * This routine sets the configuration fields for an existing device's + * descriptor. It only works for the last device, but that's OK because that's + * how we use it. + */ +static void set_config(struct device *dev, unsigned len, const void *conf) +{ + /* Check we haven't overflowed our single page. */ + if (device_config(dev) + len > devices.descpage + getpagesize()) + errx(1, "Too many devices"); + + /* Copy in the config information, and store the length. */ + memcpy(device_config(dev), conf, len); + dev->desc->config_len = len; + + /* Size must fit in config_len field (8 bits)! */ + assert(dev->desc->config_len == len); +} + +/* + * This routine does all the creation and setup of a new device, including + * calling new_dev_desc() to allocate the descriptor and device memory. We + * don't actually start the service threads until later. + * + * See what I mean about userspace being boring? + */ +static struct device *new_device(const char *name, u16 type) +{ + struct device *dev = malloc(sizeof(*dev)); + + /* Now we populate the fields one at a time. */ + dev->desc = new_dev_desc(type); + dev->name = name; + dev->vq = NULL; + dev->feature_len = 0; + dev->num_vq = 0; + dev->running = false; + + /* + * Append to device list. Prepending to a single-linked list is + * easier, but the user expects the devices to be arranged on the bus + * in command-line order. The first network device on the command line + * is eth0, the first block device /dev/vda, etc. + */ + if (devices.lastdev) + devices.lastdev->next = dev; + else + devices.dev = dev; + devices.lastdev = dev; + + return dev; +} + +/* + * Our first setup routine is the console. It's a fairly simple device, but + * UNIX tty handling makes it uglier than it could be. + */ +static void setup_console(void) +{ + struct device *dev; + + /* If we can save the initial standard input settings... */ + if (tcgetattr(STDIN_FILENO, &orig_term) == 0) { + struct termios term = orig_term; + /* + * Then we turn off echo, line buffering and ^C etc: We want a + * raw input stream to the Guest. + */ + term.c_lflag &= ~(ISIG|ICANON|ECHO); + tcsetattr(STDIN_FILENO, TCSANOW, &term); + } + + dev = new_device("console", VIRTIO_ID_CONSOLE); + + /* We store the console state in dev->priv, and initialize it. */ + dev->priv = malloc(sizeof(struct console_abort)); + ((struct console_abort *)dev->priv)->count = 0; + + /* + * The console needs two virtqueues: the input then the output. When + * they put something the input queue, we make sure we're listening to + * stdin. When they put something in the output queue, we write it to + * stdout. + */ + add_virtqueue(dev, VIRTQUEUE_NUM, console_input); + add_virtqueue(dev, VIRTQUEUE_NUM, console_output); + + verbose("device %u: console\n", ++devices.device_num); +} +/*:*/ + +/*M:010 + * Inter-guest networking is an interesting area. Simplest is to have a + * --sharenet= option which opens or creates a named pipe. This can be + * used to send packets to another guest in a 1:1 manner. + * + * More sopisticated is to use one of the tools developed for project like UML + * to do networking. + * + * Faster is to do virtio bonding in kernel. Doing this 1:1 would be + * completely generic ("here's my vring, attach to your vring") and would work + * for any traffic. Of course, namespace and permissions issues need to be + * dealt with. A more sophisticated "multi-channel" virtio_net.c could hide + * multiple inter-guest channels behind one interface, although it would + * require some manner of hotplugging new virtio channels. + * + * Finally, we could implement a virtio network switch in the kernel. +:*/ + +static u32 str2ip(const char *ipaddr) +{ + unsigned int b[4]; + + if (sscanf(ipaddr, "%u.%u.%u.%u", &b[0], &b[1], &b[2], &b[3]) != 4) + errx(1, "Failed to parse IP address '%s'", ipaddr); + return (b[0] << 24) | (b[1] << 16) | (b[2] << 8) | b[3]; +} + +static void str2mac(const char *macaddr, unsigned char mac[6]) +{ + unsigned int m[6]; + if (sscanf(macaddr, "%02x:%02x:%02x:%02x:%02x:%02x", + &m[0], &m[1], &m[2], &m[3], &m[4], &m[5]) != 6) + errx(1, "Failed to parse mac address '%s'", macaddr); + mac[0] = m[0]; + mac[1] = m[1]; + mac[2] = m[2]; + mac[3] = m[3]; + mac[4] = m[4]; + mac[5] = m[5]; +} + +/* + * This code is "adapted" from libbridge: it attaches the Host end of the + * network device to the bridge device specified by the command line. + * + * This is yet another James Morris contribution (I'm an IP-level guy, so I + * dislike bridging), and I just try not to break it. + */ +static void add_to_bridge(int fd, const char *if_name, const char *br_name) +{ + int ifidx; + struct ifreq ifr; + + if (!*br_name) + errx(1, "must specify bridge name"); + + ifidx = if_nametoindex(if_name); + if (!ifidx) + errx(1, "interface %s does not exist!", if_name); + + strncpy(ifr.ifr_name, br_name, IFNAMSIZ); + ifr.ifr_name[IFNAMSIZ-1] = '\0'; + ifr.ifr_ifindex = ifidx; + if (ioctl(fd, SIOCBRADDIF, &ifr) < 0) + err(1, "can't add %s to bridge %s", if_name, br_name); +} + +/* + * This sets up the Host end of the network device with an IP address, brings + * it up so packets will flow, the copies the MAC address into the hwaddr + * pointer. + */ +static void configure_device(int fd, const char *tapif, u32 ipaddr) +{ + struct ifreq ifr; + struct sockaddr_in sin; + + memset(&ifr, 0, sizeof(ifr)); + strcpy(ifr.ifr_name, tapif); + + /* Don't read these incantations. Just cut & paste them like I did! */ + sin.sin_family = AF_INET; + sin.sin_addr.s_addr = htonl(ipaddr); + memcpy(&ifr.ifr_addr, &sin, sizeof(sin)); + if (ioctl(fd, SIOCSIFADDR, &ifr) != 0) + err(1, "Setting %s interface address", tapif); + ifr.ifr_flags = IFF_UP; + if (ioctl(fd, SIOCSIFFLAGS, &ifr) != 0) + err(1, "Bringing interface %s up", tapif); +} + +static int get_tun_device(char tapif[IFNAMSIZ]) +{ + struct ifreq ifr; + int netfd; + + /* Start with this zeroed. Messy but sure. */ + memset(&ifr, 0, sizeof(ifr)); + + /* + * We open the /dev/net/tun device and tell it we want a tap device. A + * tap device is like a tun device, only somehow different. To tell + * the truth, I completely blundered my way through this code, but it + * works now! + */ + netfd = open_or_die("/dev/net/tun", O_RDWR); + ifr.ifr_flags = IFF_TAP | IFF_NO_PI | IFF_VNET_HDR; + strcpy(ifr.ifr_name, "tap%d"); + if (ioctl(netfd, TUNSETIFF, &ifr) != 0) + err(1, "configuring /dev/net/tun"); + + if (ioctl(netfd, TUNSETOFFLOAD, + TUN_F_CSUM|TUN_F_TSO4|TUN_F_TSO6|TUN_F_TSO_ECN) != 0) + err(1, "Could not set features for tun device"); + + /* + * We don't need checksums calculated for packets coming in this + * device: trust us! + */ + ioctl(netfd, TUNSETNOCSUM, 1); + + memcpy(tapif, ifr.ifr_name, IFNAMSIZ); + return netfd; +} + +/*L:195 + * Our network is a Host<->Guest network. This can either use bridging or + * routing, but the principle is the same: it uses the "tun" device to inject + * packets into the Host as if they came in from a normal network card. We + * just shunt packets between the Guest and the tun device. + */ +static void setup_tun_net(char *arg) +{ + struct device *dev; + struct net_info *net_info = malloc(sizeof(*net_info)); + int ipfd; + u32 ip = INADDR_ANY; + bool bridging = false; + char tapif[IFNAMSIZ], *p; + struct virtio_net_config conf; + + net_info->tunfd = get_tun_device(tapif); + + /* First we create a new network device. */ + dev = new_device("net", VIRTIO_ID_NET); + dev->priv = net_info; + + /* Network devices need a recv and a send queue, just like console. */ + add_virtqueue(dev, VIRTQUEUE_NUM, net_input); + add_virtqueue(dev, VIRTQUEUE_NUM, net_output); + + /* + * We need a socket to perform the magic network ioctls to bring up the + * tap interface, connect to the bridge etc. Any socket will do! + */ + ipfd = socket(PF_INET, SOCK_DGRAM, IPPROTO_IP); + if (ipfd < 0) + err(1, "opening IP socket"); + + /* If the command line was --tunnet=bridge: do bridging. */ + if (!strncmp(BRIDGE_PFX, arg, strlen(BRIDGE_PFX))) { + arg += strlen(BRIDGE_PFX); + bridging = true; + } + + /* A mac address may follow the bridge name or IP address */ + p = strchr(arg, ':'); + if (p) { + str2mac(p+1, conf.mac); + add_feature(dev, VIRTIO_NET_F_MAC); + *p = '\0'; + } + + /* arg is now either an IP address or a bridge name */ + if (bridging) + add_to_bridge(ipfd, tapif, arg); + else + ip = str2ip(arg); + + /* Set up the tun device. */ + configure_device(ipfd, tapif, ip); + + add_feature(dev, VIRTIO_F_NOTIFY_ON_EMPTY); + /* Expect Guest to handle everything except UFO */ + add_feature(dev, VIRTIO_NET_F_CSUM); + add_feature(dev, VIRTIO_NET_F_GUEST_CSUM); + add_feature(dev, VIRTIO_NET_F_GUEST_TSO4); + add_feature(dev, VIRTIO_NET_F_GUEST_TSO6); + add_feature(dev, VIRTIO_NET_F_GUEST_ECN); + add_feature(dev, VIRTIO_NET_F_HOST_TSO4); + add_feature(dev, VIRTIO_NET_F_HOST_TSO6); + add_feature(dev, VIRTIO_NET_F_HOST_ECN); + /* We handle indirect ring entries */ + add_feature(dev, VIRTIO_RING_F_INDIRECT_DESC); + set_config(dev, sizeof(conf), &conf); + + /* We don't need the socket any more; setup is done. */ + close(ipfd); + + devices.device_num++; + + if (bridging) + verbose("device %u: tun %s attached to bridge: %s\n", + devices.device_num, tapif, arg); + else + verbose("device %u: tun %s: %s\n", + devices.device_num, tapif, arg); +} +/*:*/ + +/* This hangs off device->priv. */ +struct vblk_info { + /* The size of the file. */ + off64_t len; + + /* The file descriptor for the file. */ + int fd; + +}; + +/*L:210 + * The Disk + * + * The disk only has one virtqueue, so it only has one thread. It is really + * simple: the Guest asks for a block number and we read or write that position + * in the file. + * + * Before we serviced each virtqueue in a separate thread, that was unacceptably + * slow: the Guest waits until the read is finished before running anything + * else, even if it could have been doing useful work. + * + * We could have used async I/O, except it's reputed to suck so hard that + * characters actually go missing from your code when you try to use it. + */ +static void blk_request(struct virtqueue *vq) +{ + struct vblk_info *vblk = vq->dev->priv; + unsigned int head, out_num, in_num, wlen; + int ret; + u8 *in; + struct virtio_blk_outhdr *out; + struct iovec iov[vq->vring.num]; + off64_t off; + + /* + * Get the next request, where we normally wait. It triggers the + * interrupt to acknowledge previously serviced requests (if any). + */ + head = wait_for_vq_desc(vq, iov, &out_num, &in_num); + + /* + * Every block request should contain at least one output buffer + * (detailing the location on disk and the type of request) and one + * input buffer (to hold the result). + */ + if (out_num == 0 || in_num == 0) + errx(1, "Bad virtblk cmd %u out=%u in=%u", + head, out_num, in_num); + + out = convert(&iov[0], struct virtio_blk_outhdr); + in = convert(&iov[out_num+in_num-1], u8); + /* + * For historical reasons, block operations are expressed in 512 byte + * "sectors". + */ + off = out->sector * 512; + + /* + * In general the virtio block driver is allowed to try SCSI commands. + * It'd be nice if we supported eject, for example, but we don't. + */ + if (out->type & VIRTIO_BLK_T_SCSI_CMD) { + fprintf(stderr, "Scsi commands unsupported\n"); + *in = VIRTIO_BLK_S_UNSUPP; + wlen = sizeof(*in); + } else if (out->type & VIRTIO_BLK_T_OUT) { + /* + * Write + * + * Move to the right location in the block file. This can fail + * if they try to write past end. + */ + if (lseek64(vblk->fd, off, SEEK_SET) != off) + err(1, "Bad seek to sector %llu", out->sector); + + ret = writev(vblk->fd, iov+1, out_num-1); + verbose("WRITE to sector %llu: %i\n", out->sector, ret); + + /* + * Grr... Now we know how long the descriptor they sent was, we + * make sure they didn't try to write over the end of the block + * file (possibly extending it). + */ + if (ret > 0 && off + ret > vblk->len) { + /* Trim it back to the correct length */ + ftruncate64(vblk->fd, vblk->len); + /* Die, bad Guest, die. */ + errx(1, "Write past end %llu+%u", off, ret); + } + + wlen = sizeof(*in); + *in = (ret >= 0 ? VIRTIO_BLK_S_OK : VIRTIO_BLK_S_IOERR); + } else if (out->type & VIRTIO_BLK_T_FLUSH) { + /* Flush */ + ret = fdatasync(vblk->fd); + verbose("FLUSH fdatasync: %i\n", ret); + wlen = sizeof(*in); + *in = (ret >= 0 ? VIRTIO_BLK_S_OK : VIRTIO_BLK_S_IOERR); + } else { + /* + * Read + * + * Move to the right location in the block file. This can fail + * if they try to read past end. + */ + if (lseek64(vblk->fd, off, SEEK_SET) != off) + err(1, "Bad seek to sector %llu", out->sector); + + ret = readv(vblk->fd, iov+1, in_num-1); + verbose("READ from sector %llu: %i\n", out->sector, ret); + if (ret >= 0) { + wlen = sizeof(*in) + ret; + *in = VIRTIO_BLK_S_OK; + } else { + wlen = sizeof(*in); + *in = VIRTIO_BLK_S_IOERR; + } + } + + /* Finished that request. */ + add_used(vq, head, wlen); +} + +/*L:198 This actually sets up a virtual block device. */ +static void setup_block_file(const char *filename) +{ + struct device *dev; + struct vblk_info *vblk; + struct virtio_blk_config conf; + + /* Creat the device. */ + dev = new_device("block", VIRTIO_ID_BLOCK); + + /* The device has one virtqueue, where the Guest places requests. */ + add_virtqueue(dev, VIRTQUEUE_NUM, blk_request); + + /* Allocate the room for our own bookkeeping */ + vblk = dev->priv = malloc(sizeof(*vblk)); + + /* First we open the file and store the length. */ + vblk->fd = open_or_die(filename, O_RDWR|O_LARGEFILE); + vblk->len = lseek64(vblk->fd, 0, SEEK_END); + + /* We support FLUSH. */ + add_feature(dev, VIRTIO_BLK_F_FLUSH); + + /* Tell Guest how many sectors this device has. */ + conf.capacity = cpu_to_le64(vblk->len / 512); + + /* + * Tell Guest not to put in too many descriptors at once: two are used + * for the in and out elements. + */ + add_feature(dev, VIRTIO_BLK_F_SEG_MAX); + conf.seg_max = cpu_to_le32(VIRTQUEUE_NUM - 2); + + /* Don't try to put whole struct: we have 8 bit limit. */ + set_config(dev, offsetof(struct virtio_blk_config, geometry), &conf); + + verbose("device %u: virtblock %llu sectors\n", + ++devices.device_num, le64_to_cpu(conf.capacity)); +} + +/*L:211 + * Our random number generator device reads from /dev/random into the Guest's + * input buffers. The usual case is that the Guest doesn't want random numbers + * and so has no buffers although /dev/random is still readable, whereas + * console is the reverse. + * + * The same logic applies, however. + */ +struct rng_info { + int rfd; +}; + +static void rng_input(struct virtqueue *vq) +{ + int len; + unsigned int head, in_num, out_num, totlen = 0; + struct rng_info *rng_info = vq->dev->priv; + struct iovec iov[vq->vring.num]; + + /* First we need a buffer from the Guests's virtqueue. */ + head = wait_for_vq_desc(vq, iov, &out_num, &in_num); + if (out_num) + errx(1, "Output buffers in rng?"); + + /* + * Just like the console write, we loop to cover the whole iovec. + * In this case, short reads actually happen quite a bit. + */ + while (!iov_empty(iov, in_num)) { + len = readv(rng_info->rfd, iov, in_num); + if (len <= 0) + err(1, "Read from /dev/random gave %i", len); + iov_consume(iov, in_num, len); + totlen += len; + } + + /* Tell the Guest about the new input. */ + add_used(vq, head, totlen); +} + +/*L:199 + * This creates a "hardware" random number device for the Guest. + */ +static void setup_rng(void) +{ + struct device *dev; + struct rng_info *rng_info = malloc(sizeof(*rng_info)); + + /* Our device's privat info simply contains the /dev/random fd. */ + rng_info->rfd = open_or_die("/dev/random", O_RDONLY); + + /* Create the new device. */ + dev = new_device("rng", VIRTIO_ID_RNG); + dev->priv = rng_info; + + /* The device has one virtqueue, where the Guest places inbufs. */ + add_virtqueue(dev, VIRTQUEUE_NUM, rng_input); + + verbose("device %u: rng\n", devices.device_num++); +} +/* That's the end of device setup. */ + +/*L:230 Reboot is pretty easy: clean up and exec() the Launcher afresh. */ +static void __attribute__((noreturn)) restart_guest(void) +{ + unsigned int i; + + /* + * Since we don't track all open fds, we simply close everything beyond + * stderr. + */ + for (i = 3; i < FD_SETSIZE; i++) + close(i); + + /* Reset all the devices (kills all threads). */ + cleanup_devices(); + + execv(main_args[0], main_args); + err(1, "Could not exec %s", main_args[0]); +} + +/*L:220 + * Finally we reach the core of the Launcher which runs the Guest, serves + * its input and output, and finally, lays it to rest. + */ +static void __attribute__((noreturn)) run_guest(void) +{ + for (;;) { + unsigned long notify_addr; + int readval; + + /* We read from the /dev/lguest device to run the Guest. */ + readval = pread(lguest_fd, ¬ify_addr, + sizeof(notify_addr), cpu_id); + + /* One unsigned long means the Guest did HCALL_NOTIFY */ + if (readval == sizeof(notify_addr)) { + verbose("Notify on address %#lx\n", notify_addr); + handle_output(notify_addr); + /* ENOENT means the Guest died. Reading tells us why. */ + } else if (errno == ENOENT) { + char reason[1024] = { 0 }; + pread(lguest_fd, reason, sizeof(reason)-1, cpu_id); + errx(1, "%s", reason); + /* ERESTART means that we need to reboot the guest */ + } else if (errno == ERESTART) { + restart_guest(); + /* Anything else means a bug or incompatible change. */ + } else + err(1, "Running guest failed"); + } +} +/*L:240 + * This is the end of the Launcher. The good news: we are over halfway + * through! The bad news: the most fiendish part of the code still lies ahead + * of us. + * + * Are you ready? Take a deep breath and join me in the core of the Host, in + * "make Host". +:*/ + +static struct option opts[] = { + { "verbose", 0, NULL, 'v' }, + { "tunnet", 1, NULL, 't' }, + { "block", 1, NULL, 'b' }, + { "rng", 0, NULL, 'r' }, + { "initrd", 1, NULL, 'i' }, + { "username", 1, NULL, 'u' }, + { "chroot", 1, NULL, 'c' }, + { NULL }, +}; +static void usage(void) +{ + errx(1, "Usage: lguest [--verbose] " + "[--tunnet=(:|bridge::)\n" + "|--block=|--initrd=]...\n" + " vmlinux [args...]"); +} + +/*L:105 The main routine is where the real work begins: */ +int main(int argc, char *argv[]) +{ + /* Memory, code startpoint and size of the (optional) initrd. */ + unsigned long mem = 0, start, initrd_size = 0; + /* Two temporaries. */ + int i, c; + /* The boot information for the Guest. */ + struct boot_params *boot; + /* If they specify an initrd file to load. */ + const char *initrd_name = NULL; + + /* Password structure for initgroups/setres[gu]id */ + struct passwd *user_details = NULL; + + /* Directory to chroot to */ + char *chroot_path = NULL; + + /* Save the args: we "reboot" by execing ourselves again. */ + main_args = argv; + + /* + * First we initialize the device list. We keep a pointer to the last + * device, and the next interrupt number to use for devices (1: + * remember that 0 is used by the timer). + */ + devices.lastdev = NULL; + devices.next_irq = 1; + + /* We're CPU 0. In fact, that's the only CPU possible right now. */ + cpu_id = 0; + + /* + * We need to know how much memory so we can set up the device + * descriptor and memory pages for the devices as we parse the command + * line. So we quickly look through the arguments to find the amount + * of memory now. + */ + for (i = 1; i < argc; i++) { + if (argv[i][0] != '-') { + mem = atoi(argv[i]) * 1024 * 1024; + /* + * We start by mapping anonymous pages over all of + * guest-physical memory range. This fills it with 0, + * and ensures that the Guest won't be killed when it + * tries to access it. + */ + guest_base = map_zeroed_pages(mem / getpagesize() + + DEVICE_PAGES); + guest_limit = mem; + guest_max = mem + DEVICE_PAGES*getpagesize(); + devices.descpage = get_pages(1); + break; + } + } + + /* The options are fairly straight-forward */ + while ((c = getopt_long(argc, argv, "v", opts, NULL)) != EOF) { + switch (c) { + case 'v': + verbose = true; + break; + case 't': + setup_tun_net(optarg); + break; + case 'b': + setup_block_file(optarg); + break; + case 'r': + setup_rng(); + break; + case 'i': + initrd_name = optarg; + break; + case 'u': + user_details = getpwnam(optarg); + if (!user_details) + err(1, "getpwnam failed, incorrect username?"); + break; + case 'c': + chroot_path = optarg; + break; + default: + warnx("Unknown argument %s", argv[optind]); + usage(); + } + } + /* + * After the other arguments we expect memory and kernel image name, + * followed by command line arguments for the kernel. + */ + if (optind + 2 > argc) + usage(); + + verbose("Guest base is at %p\n", guest_base); + + /* We always have a console device */ + setup_console(); + + /* Now we load the kernel */ + start = load_kernel(open_or_die(argv[optind+1], O_RDONLY)); + + /* Boot information is stashed at physical address 0 */ + boot = from_guest_phys(0); + + /* Map the initrd image if requested (at top of physical memory) */ + if (initrd_name) { + initrd_size = load_initrd(initrd_name, mem); + /* + * These are the location in the Linux boot header where the + * start and size of the initrd are expected to be found. + */ + boot->hdr.ramdisk_image = mem - initrd_size; + boot->hdr.ramdisk_size = initrd_size; + /* The bootloader type 0xFF means "unknown"; that's OK. */ + boot->hdr.type_of_loader = 0xFF; + } + + /* + * The Linux boot header contains an "E820" memory map: ours is a + * simple, single region. + */ + boot->e820_entries = 1; + boot->e820_map[0] = ((struct e820entry) { 0, mem, E820_RAM }); + /* + * The boot header contains a command line pointer: we put the command + * line after the boot header. + */ + boot->hdr.cmd_line_ptr = to_guest_phys(boot + 1); + /* We use a simple helper to copy the arguments separated by spaces. */ + concat((char *)(boot + 1), argv+optind+2); + + /* Boot protocol version: 2.07 supports the fields for lguest. */ + boot->hdr.version = 0x207; + + /* The hardware_subarch value of "1" tells the Guest it's an lguest. */ + boot->hdr.hardware_subarch = 1; + + /* Tell the entry path not to try to reload segment registers. */ + boot->hdr.loadflags |= KEEP_SEGMENTS; + + /* + * We tell the kernel to initialize the Guest: this returns the open + * /dev/lguest file descriptor. + */ + tell_kernel(start); + + /* Ensure that we terminate if a device-servicing child dies. */ + signal(SIGCHLD, kill_launcher); + + /* If we exit via err(), this kills all the threads, restores tty. */ + atexit(cleanup_devices); + + /* If requested, chroot to a directory */ + if (chroot_path) { + if (chroot(chroot_path) != 0) + err(1, "chroot(\"%s\") failed", chroot_path); + + if (chdir("/") != 0) + err(1, "chdir(\"/\") failed"); + + verbose("chroot done\n"); + } + + /* If requested, drop privileges */ + if (user_details) { + uid_t u; + gid_t g; + + u = user_details->pw_uid; + g = user_details->pw_gid; + + if (initgroups(user_details->pw_name, g) != 0) + err(1, "initgroups failed"); + + if (setresgid(g, g, g) != 0) + err(1, "setresgid failed"); + + if (setresuid(u, u, u) != 0) + err(1, "setresuid failed"); + + verbose("Dropping privileges completed\n"); + } + + /* Finally, run the Guest. This doesn't return. */ + run_guest(); +} +/*:*/ + +/*M:999 + * Mastery is done: you now know everything I do. + * + * But surely you have seen code, features and bugs in your wanderings which + * you now yearn to attack? That is the real game, and I look forward to you + * patching and forking lguest into the Your-Name-Here-visor. + * + * Farewell, and good coding! + * Rusty Russell. + */ diff --git a/Documentation/virtual/lguest/lguest.txt b/Documentation/virtual/lguest/lguest.txt new file mode 100644 index 0000000..dad9997 --- /dev/null +++ b/Documentation/virtual/lguest/lguest.txt @@ -0,0 +1,128 @@ + __ + (___()'`; Rusty's Remarkably Unreliable Guide to Lguest + /, /` - or, A Young Coder's Illustrated Hypervisor + \\"--\\ http://lguest.ozlabs.org + +Lguest is designed to be a minimal 32-bit x86 hypervisor for the Linux kernel, +for Linux developers and users to experiment with virtualization with the +minimum of complexity. Nonetheless, it should have sufficient features to +make it useful for specific tasks, and, of course, you are encouraged to fork +and enhance it (see drivers/lguest/README). + +Features: + +- Kernel module which runs in a normal kernel. +- Simple I/O model for communication. +- Simple program to create new guests. +- Logo contains cute puppies: http://lguest.ozlabs.org + +Developer features: + +- Fun to hack on. +- No ABI: being tied to a specific kernel anyway, you can change anything. +- Many opportunities for improvement or feature implementation. + +Running Lguest: + +- The easiest way to run lguest is to use same kernel as guest and host. + You can configure them differently, but usually it's easiest not to. + + You will need to configure your kernel with the following options: + + "General setup": + "Prompt for development and/or incomplete code/drivers" = Y + (CONFIG_EXPERIMENTAL=y) + + "Processor type and features": + "Paravirtualized guest support" = Y + "Lguest guest support" = Y + "High Memory Support" = off/4GB + "Alignment value to which kernel should be aligned" = 0x100000 + (CONFIG_PARAVIRT=y, CONFIG_LGUEST_GUEST=y, CONFIG_HIGHMEM64G=n and + CONFIG_PHYSICAL_ALIGN=0x100000) + + "Device Drivers": + "Block devices" + "Virtio block driver (EXPERIMENTAL)" = M/Y + "Network device support" + "Universal TUN/TAP device driver support" = M/Y + "Virtio network driver (EXPERIMENTAL)" = M/Y + (CONFIG_VIRTIO_BLK=m, CONFIG_VIRTIO_NET=m and CONFIG_TUN=m) + + "Virtualization" + "Linux hypervisor example code" = M/Y + (CONFIG_LGUEST=m) + +- A tool called "lguest" is available in this directory: type "make" + to build it. If you didn't build your kernel in-tree, use "make + O=". + +- Create or find a root disk image. There are several useful ones + around, such as the xm-test tiny root image at + http://xm-test.xensource.com/ramdisks/initrd-1.1-i386.img + + For more serious work, I usually use a distribution ISO image and + install it under qemu, then make multiple copies: + + dd if=/dev/zero of=rootfile bs=1M count=2048 + qemu -cdrom image.iso -hda rootfile -net user -net nic -boot d + + Make sure that you install a getty on /dev/hvc0 if you want to log in on the + console! + +- "modprobe lg" if you built it as a module. + +- Run an lguest as root: + + Documentation/lguest/lguest 64 vmlinux --tunnet=192.168.19.1 --block=rootfile root=/dev/vda + + Explanation: + 64: the amount of memory to use, in MB. + + vmlinux: the kernel image found in the top of your build directory. You + can also use a standard bzImage. + + --tunnet=192.168.19.1: configures a "tap" device for networking with this + IP address. + + --block=rootfile: a file or block device which becomes /dev/vda + inside the guest. + + root=/dev/vda: this (and anything else on the command line) are + kernel boot parameters. + +- Configuring networking. I usually have the host masquerade, using + "iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE" and "echo 1 > + /proc/sys/net/ipv4/ip_forward". In this example, I would configure + eth0 inside the guest at 192.168.19.2. + + Another method is to bridge the tap device to an external interface + using --tunnet=bridge:, and perhaps run dhcp on the guest + to obtain an IP address. The bridge needs to be configured first: + this option simply adds the tap interface to it. + + A simple example on my system: + + ifconfig eth0 0.0.0.0 + brctl addbr lg0 + ifconfig lg0 up + brctl addif lg0 eth0 + dhclient lg0 + + Then use --tunnet=bridge:lg0 when launching the guest. + + See: + + http://www.linuxfoundation.org/collaborate/workgroups/networking/bridge + + for general information on how to get bridging to work. + +- Random number generation. Using the --rng option will provide a + /dev/hwrng in the guest that will read from the host's /dev/random. + Use this option in conjunction with rng-tools (see ../hw_random.txt) + to provide entropy to the guest kernel's /dev/random. + +There is a helpful mailing list at http://ozlabs.org/mailman/listinfo/lguest + +Good luck! +Rusty Russell rusty@rustcorp.com.au. diff --git a/Documentation/virtual/uml/UserModeLinux-HOWTO.txt b/Documentation/virtual/uml/UserModeLinux-HOWTO.txt new file mode 100644 index 0000000..9b7e190 --- /dev/null +++ b/Documentation/virtual/uml/UserModeLinux-HOWTO.txt @@ -0,0 +1,4579 @@ + User Mode Linux HOWTO + User Mode Linux Core Team + Mon Nov 18 14:16:16 EST 2002 + + This document describes the use and abuse of Jeff Dike's User Mode + Linux: a port of the Linux kernel as a normal Intel Linux process. + ______________________________________________________________________ + + Table of Contents + + 1. Introduction + + 1.1 How is User Mode Linux Different? + 1.2 Why Would I Want User Mode Linux? + + 2. Compiling the kernel and modules + + 2.1 Compiling the kernel + 2.2 Compiling and installing kernel modules + 2.3 Compiling and installing uml_utilities + + 3. Running UML and logging in + + 3.1 Running UML + 3.2 Logging in + 3.3 Examples + + 4. UML on 2G/2G hosts + + 4.1 Introduction + 4.2 The problem + 4.3 The solution + + 5. Setting up serial lines and consoles + + 5.1 Specifying the device + 5.2 Specifying the channel + 5.3 Examples + + 6. Setting up the network + + 6.1 General setup + 6.2 Userspace daemons + 6.3 Specifying ethernet addresses + 6.4 UML interface setup + 6.5 Multicast + 6.6 TUN/TAP with the uml_net helper + 6.7 TUN/TAP with a preconfigured tap device + 6.8 Ethertap + 6.9 The switch daemon + 6.10 Slip + 6.11 Slirp + 6.12 pcap + 6.13 Setting up the host yourself + + 7. Sharing Filesystems between Virtual Machines + + 7.1 A warning + 7.2 Using layered block devices + 7.3 Note! + 7.4 Another warning + 7.5 uml_moo : Merging a COW file with its backing file + + 8. Creating filesystems + + 8.1 Create the filesystem file + 8.2 Assign the file to a UML device + 8.3 Creating and mounting the filesystem + + 9. Host file access + + 9.1 Using hostfs + 9.2 hostfs as the root filesystem + 9.3 Building hostfs + + 10. The Management Console + 10.1 version + 10.2 halt and reboot + 10.3 config + 10.4 remove + 10.5 sysrq + 10.6 help + 10.7 cad + 10.8 stop + 10.9 go + + 11. Kernel debugging + + 11.1 Starting the kernel under gdb + 11.2 Examining sleeping processes + 11.3 Running ddd on UML + 11.4 Debugging modules + 11.5 Attaching gdb to the kernel + 11.6 Using alternate debuggers + + 12. Kernel debugging examples + + 12.1 The case of the hung fsck + 12.2 Episode 2: The case of the hung fsck + + 13. What to do when UML doesn't work + + 13.1 Strange compilation errors when you build from source + 13.2 (obsolete) + 13.3 A variety of panics and hangs with /tmp on a reiserfs filesystem + 13.4 The compile fails with errors about conflicting types for 'open', 'dup', and 'waitpid' + 13.5 UML doesn't work when /tmp is an NFS filesystem + 13.6 UML hangs on boot when compiled with gprof support + 13.7 syslogd dies with a SIGTERM on startup + 13.8 TUN/TAP networking doesn't work on a 2.4 host + 13.9 You can network to the host but not to other machines on the net + 13.10 I have no root and I want to scream + 13.11 UML build conflict between ptrace.h and ucontext.h + 13.12 The UML BogoMips is exactly half the host's BogoMips + 13.13 When you run UML, it immediately segfaults + 13.14 xterms appear, then immediately disappear + 13.15 Any other panic, hang, or strange behavior + + 14. Diagnosing Problems + + 14.1 Case 1 : Normal kernel panics + 14.2 Case 2 : Tracing thread panics + 14.3 Case 3 : Tracing thread panics caused by other threads + 14.4 Case 4 : Hangs + + 15. Thanks + + 15.1 Code and Documentation + 15.2 Flushing out bugs + 15.3 Buglets and clean-ups + 15.4 Case Studies + 15.5 Other contributions + + + ______________________________________________________________________ + + 11.. IInnttrroodduuccttiioonn + + Welcome to User Mode Linux. It's going to be fun. + + + + 11..11.. HHooww iiss UUsseerr MMooddee LLiinnuuxx DDiiffffeerreenntt?? + + Normally, the Linux Kernel talks straight to your hardware (video + card, keyboard, hard drives, etc), and any programs which run ask the + kernel to operate the hardware, like so: + + + + +-----------+-----------+----+ + | Process 1 | Process 2 | ...| + +-----------+-----------+----+ + | Linux Kernel | + +----------------------------+ + | Hardware | + +----------------------------+ + + + + + The User Mode Linux Kernel is different; instead of talking to the + hardware, it talks to a `real' Linux kernel (called the `host kernel' + from now on), like any other program. Programs can then run inside + User-Mode Linux as if they were running under a normal kernel, like + so: + + + + +----------------+ + | Process 2 | ...| + +-----------+----------------+ + | Process 1 | User-Mode Linux| + +----------------------------+ + | Linux Kernel | + +----------------------------+ + | Hardware | + +----------------------------+ + + + + + + 11..22.. WWhhyy WWoouulldd II WWaanntt UUsseerr MMooddee LLiinnuuxx?? + + + 1. If User Mode Linux crashes, your host kernel is still fine. + + 2. You can run a usermode kernel as a non-root user. + + 3. You can debug the User Mode Linux like any normal process. + + 4. You can run gprof (profiling) and gcov (coverage testing). + + 5. You can play with your kernel without breaking things. + + 6. You can use it as a sandbox for testing new apps. + + 7. You can try new development kernels safely. + + 8. You can run different distributions simultaneously. + + 9. It's extremely fun. + + + + + + 22.. CCoommppiilliinngg tthhee kkeerrnneell aanndd mmoodduulleess + + + + + 22..11.. CCoommppiilliinngg tthhee kkeerrnneell + + + Compiling the user mode kernel is just like compiling any other + kernel. Let's go through the steps, using 2.4.0-prerelease (current + as of this writing) as an example: + + + 1. Download the latest UML patch from + + the download page + . + + + 3. Make a directory and unpack the kernel into it. + + + + host% + mkdir ~/uml + + + + + + + host% + cd ~/uml + + + + + + + host% + tar -xzvf linux-2.4.0-prerelease.tar.bz2 + + + + + + + 4. Apply the patch using + + + + host% + cd ~/uml/linux + + + + host% + bzcat uml-patch-2.4.0-prerelease.bz2 | patch -p1 + + + + + + + 5. Run your favorite config; `make xconfig ARCH=um' is the most + convenient. `make config ARCH=um' and 'make menuconfig ARCH=um' + will work as well. The defaults will give you a useful kernel. If + you want to change something, go ahead, it probably won't hurt + anything. + + + Note: If the host is configured with a 2G/2G address space split + rather than the usual 3G/1G split, then the packaged UML binaries + will not run. They will immediately segfault. See ``UML on 2G/2G + hosts'' for the scoop on running UML on your system. + + + + 6. Finish with `make linux ARCH=um': the result is a file called + `linux' in the top directory of your source tree. + + Make sure that you don't build this kernel in /usr/src/linux. On some + distributions, /usr/include/asm is a link into this pool. The user- + mode build changes the other end of that link, and things that include + stop compiling. + + The sources are also available from cvs at the project's cvs page, + which has directions on getting the sources. You can also browse the + CVS pool from there. + + If you get the CVS sources, you will have to check them out into an + empty directory. You will then have to copy each file into the + corresponding directory in the appropriate kernel pool. + + If you don't have the latest kernel pool, you can get the + corresponding user-mode sources with + + + host% cvs co -r v_2_3_x linux + + + + + where 'x' is the version in your pool. Note that you will not get the + bug fixes and enhancements that have gone into subsequent releases. + + + 22..22.. CCoommppiilliinngg aanndd iinnssttaalllliinngg kkeerrnneell mmoodduulleess + + UML modules are built in the same way as the native kernel (with the + exception of the 'ARCH=um' that you always need for UML): + + + host% make modules ARCH=um + + + + + Any modules that you want to load into this kernel need to be built in + the user-mode pool. Modules from the native kernel won't work. + + You can install them by using ftp or something to copy them into the + virtual machine and dropping them into /lib/modules/`uname -r`. + + You can also get the kernel build process to install them as follows: + + 1. with the kernel not booted, mount the root filesystem in the top + level of the kernel pool: + + + host% mount root_fs mnt -o loop + + + + + + + 2. run + + + host% + make modules_install INSTALL_MOD_PATH=`pwd`/mnt ARCH=um + + + + + + + 3. unmount the filesystem + + + host% umount mnt + + + + + + + 4. boot the kernel on it + + + When the system is booted, you can use insmod as usual to get the + modules into the kernel. A number of things have been loaded into UML + as modules, especially filesystems and network protocols and filters, + so most symbols which need to be exported probably already are. + However, if you do find symbols that need exporting, let us + know, and + they'll be "taken care of". + + + + 22..33.. CCoommppiilliinngg aanndd iinnssttaalllliinngg uummll__uuttiilliittiieess + + Many features of the UML kernel require a user-space helper program, + so a uml_utilities package is distributed separately from the kernel + patch which provides these helpers. Included within this is: + + +o port-helper - Used by consoles which connect to xterms or ports + + +o tunctl - Configuration tool to create and delete tap devices + + +o uml_net - Setuid binary for automatic tap device configuration + + +o uml_switch - User-space virtual switch required for daemon + transport + + The uml_utilities tree is compiled with: + + + host# + make && make install + + + + + Note that UML kernel patches may require a specific version of the + uml_utilities distribution. If you don't keep up with the mailing + lists, ensure that you have the latest release of uml_utilities if you + are experiencing problems with your UML kernel, particularly when + dealing with consoles or command-line switches to the helper programs + + + + + + + + + 33.. RRuunnnniinngg UUMMLL aanndd llooggggiinngg iinn + + + + 33..11.. RRuunnnniinngg UUMMLL + + It runs on 2.2.15 or later, and all 2.4 kernels. + + + Booting UML is straightforward. Simply run 'linux': it will try to + mount the file `root_fs' in the current directory. You do not need to + run it as root. If your root filesystem is not named `root_fs', then + you need to put a `ubd0=root_fs_whatever' switch on the linux command + line. + + + You will need a filesystem to boot UML from. There are a number + available for download from here . There are also several tools + which can be + used to generate UML-compatible filesystem images from media. + The kernel will boot up and present you with a login prompt. + + + Note: If the host is configured with a 2G/2G address space split + rather than the usual 3G/1G split, then the packaged UML binaries will + not run. They will immediately segfault. See ``UML on 2G/2G hosts'' + for the scoop on running UML on your system. + + + + 33..22.. LLooggggiinngg iinn + + + + The prepackaged filesystems have a root account with password 'root' + and a user account with password 'user'. The login banner will + generally tell you how to log in. So, you log in and you will find + yourself inside a little virtual machine. Our filesystems have a + variety of commands and utilities installed (and it is fairly easy to + add more), so you will have a lot of tools with which to poke around + the system. + + There are a couple of other ways to log in: + + +o On a virtual console + + + + Each virtual console that is configured (i.e. the device exists in + /dev and /etc/inittab runs a getty on it) will come up in its own + xterm. If you get tired of the xterms, read ``Setting up serial + lines and consoles'' to see how to attach the consoles to + something else, like host ptys. + + + + +o Over the serial line + + + In the boot output, find a line that looks like: + + + + serial line 0 assigned pty /dev/ptyp1 + + + + + Attach your favorite terminal program to the corresponding tty. I.e. + for minicom, the command would be + + + host% minicom -o -p /dev/ttyp1 + + + + + + + +o Over the net + + + If the network is running, then you can telnet to the virtual + machine and log in to it. See ``Setting up the network'' to learn + about setting up a virtual network. + + When you're done using it, run halt, and the kernel will bring itself + down and the process will exit. + + + 33..33.. EExxaammpplleess + + Here are some examples of UML in action: + + +o A login session + + +o A virtual network + + + + + + + + 44.. UUMMLL oonn 22GG//22GG hhoossttss + + + + + 44..11.. IInnttrroodduuccttiioonn + + + Most Linux machines are configured so that the kernel occupies the + upper 1G (0xc0000000 - 0xffffffff) of the 4G address space and + processes use the lower 3G (0x00000000 - 0xbfffffff). However, some + machine are configured with a 2G/2G split, with the kernel occupying + the upper 2G (0x80000000 - 0xffffffff) and processes using the lower + 2G (0x00000000 - 0x7fffffff). + + + + + 44..22.. TThhee pprroobblleemm + + + The prebuilt UML binaries on this site will not run on 2G/2G hosts + because UML occupies the upper .5G of the 3G process address space + (0xa0000000 - 0xbfffffff). Obviously, on 2G/2G hosts, this is right + in the middle of the kernel address space, so UML won't even load - it + will immediately segfault. + + + + + 44..33.. TThhee ssoolluuttiioonn + + + The fix for this is to rebuild UML from source after enabling + CONFIG_HOST_2G_2G (under 'General Setup'). This will cause UML to + load itself in the top .5G of that smaller process address space, + where it will run fine. See ``Compiling the kernel and modules'' if + you need help building UML from source. + + + + + + + + + + + 55.. SSeettttiinngg uupp sseerriiaall lliinneess aanndd ccoonnssoolleess + + + It is possible to attach UML serial lines and consoles to many types + of host I/O channels by specifying them on the command line. + + + You can attach them to host ptys, ttys, file descriptors, and ports. + This allows you to do things like + + +o have a UML console appear on an unused host console, + + +o hook two virtual machines together by having one attach to a pty + and having the other attach to the corresponding tty + + +o make a virtual machine accessible from the net by attaching a + console to a port on the host. + + + The general format of the command line option is device=channel. + + + + 55..11.. SSppeecciiffyyiinngg tthhee ddeevviiccee + + Devices are specified with "con" or "ssl" (console or serial line, + respectively), optionally with a device number if you are talking + about a specific device. + + + Using just "con" or "ssl" describes all of the consoles or serial + lines. If you want to talk about console #3 or serial line #10, they + would be "con3" and "ssl10", respectively. + + + A specific device name will override a less general "con=" or "ssl=". + So, for example, you can assign a pty to each of the serial lines + except for the first two like this: + + + ssl=pty ssl0=tty:/dev/tty0 ssl1=tty:/dev/tty1 + + + + + The specificity of the device name is all that matters; order on the + command line is irrelevant. + + + + 55..22.. SSppeecciiffyyiinngg tthhee cchhaannnneell + + There are a number of different types of channels to attach a UML + device to, each with a different way of specifying exactly what to + attach to. + + +o pseudo-terminals - device=pty pts terminals - device=pts + + + This will cause UML to allocate a free host pseudo-terminal for the + device. The terminal that it got will be announced in the boot + log. You access it by attaching a terminal program to the + corresponding tty: + + +o screen /dev/pts/n + + +o screen /dev/ttyxx + + +o minicom -o -p /dev/ttyxx - minicom seems not able to handle pts + devices + + +o kermit - start it up, 'open' the device, then 'connect' + + + + + + +o terminals - device=tty:tty device file + + + This will make UML attach the device to the specified tty (i.e + + + con1=tty:/dev/tty3 + + + + + will attach UML's console 1 to the host's /dev/tty3). If the tty that + you specify is the slave end of a tty/pty pair, something else must + have already opened the corresponding pty in order for this to work. + + + + + + +o xterms - device=xterm + + + UML will run an xterm and the device will be attached to it. + + + + + + +o Port - device=port:port number + + + This will attach the UML devices to the specified host port. + Attaching console 1 to the host's port 9000 would be done like + this: + + + con1=port:9000 + + + + + Attaching all the serial lines to that port would be done similarly: + + + ssl=port:9000 + + + + + You access these devices by telnetting to that port. Each active tel- + net session gets a different device. If there are more telnets to a + port than UML devices attached to it, then the extra telnet sessions + will block until an existing telnet detaches, or until another device + becomes active (i.e. by being activated in /etc/inittab). + + This channel has the advantage that you can both attach multiple UML + devices to it and know how to access them without reading the UML boot + log. It is also unique in allowing access to a UML from remote + machines without requiring that the UML be networked. This could be + useful in allowing public access to UMLs because they would be + accessible from the net, but wouldn't need any kind of network + filtering or access control because they would have no network access. + + + If you attach the main console to a portal, then the UML boot will + appear to hang. In reality, it's waiting for a telnet to connect, at + which point the boot will proceed. + + + + + + +o already-existing file descriptors - device=file descriptor + + + If you set up a file descriptor on the UML command line, you can + attach a UML device to it. This is most commonly used to put the + main console back on stdin and stdout after assigning all the other + consoles to something else: + + + con0=fd:0,fd:1 con=pts + + + + + + + + + +o Nothing - device=null + + + This allows the device to be opened, in contrast to 'none', but + reads will block, and writes will succeed and the data will be + thrown out. + + + + + + +o None - device=none + + + This causes the device to disappear. + + + + You can also specify different input and output channels for a device + by putting a comma between them: + + + ssl3=tty:/dev/tty2,xterm + + + + + will cause serial line 3 to accept input on the host's /dev/tty3 and + display output on an xterm. That's a silly example - the most common + use of this syntax is to reattach the main console to stdin and stdout + as shown above. + + + If you decide to move the main console away from stdin/stdout, the + initial boot output will appear in the terminal that you're running + UML in. However, once the console driver has been officially + initialized, then the boot output will start appearing wherever you + specified that console 0 should be. That device will receive all + subsequent output. + + + + 55..33.. EExxaammpplleess + + There are a number of interesting things you can do with this + capability. + + + First, this is how you get rid of those bleeding console xterms by + attaching them to host ptys: + + + con=pty con0=fd:0,fd:1 + + + + + This will make a UML console take over an unused host virtual console, + so that when you switch to it, you will see the UML login prompt + rather than the host login prompt: + + + con1=tty:/dev/tty6 + + + + + You can attach two virtual machines together with what amounts to a + serial line as follows: + + Run one UML with a serial line attached to a pty - + + + ssl1=pty + + + + + Look at the boot log to see what pty it got (this example will assume + that it got /dev/ptyp1). + + Boot the other UML with a serial line attached to the corresponding + tty - + + + ssl1=tty:/dev/ttyp1 + + + + + Log in, make sure that it has no getty on that serial line, attach a + terminal program like minicom to it, and you should see the login + prompt of the other virtual machine. + + + 66.. SSeettttiinngg uupp tthhee nneettwwoorrkk + + + + This page describes how to set up the various transports and to + provide a UML instance with network access to the host, other machines + on the local net, and the rest of the net. + + + As of 2.4.5, UML networking has been completely redone to make it much + easier to set up, fix bugs, and add new features. + + + There is a new helper, uml_net, which does the host setup that + requires root privileges. + + + There are currently five transport types available for a UML virtual + machine to exchange packets with other hosts: + + +o ethertap + + +o TUN/TAP + + +o Multicast + + +o a switch daemon + + +o slip + + +o slirp + + +o pcap + + The TUN/TAP, ethertap, slip, and slirp transports allow a UML + instance to exchange packets with the host. They may be directed + to the host or the host may just act as a router to provide access + to other physical or virtual machines. + + + The pcap transport is a synthetic read-only interface, using the + libpcap binary to collect packets from interfaces on the host and + filter them. This is useful for building preconfigured traffic + monitors or sniffers. + + + The daemon and multicast transports provide a completely virtual + network to other virtual machines. This network is completely + disconnected from the physical network unless one of the virtual + machines on it is acting as a gateway. + + + With so many host transports, which one should you use? Here's when + you should use each one: + + +o ethertap - if you want access to the host networking and it is + running 2.2 + + +o TUN/TAP - if you want access to the host networking and it is + running 2.4. Also, the TUN/TAP transport is able to use a + preconfigured device, allowing it to avoid using the setuid uml_net + helper, which is a security advantage. + + +o Multicast - if you want a purely virtual network and you don't want + to set up anything but the UML + + +o a switch daemon - if you want a purely virtual network and you + don't mind running the daemon in order to get somewhat better + performance + + +o slip - there is no particular reason to run the slip backend unless + ethertap and TUN/TAP are just not available for some reason + + +o slirp - if you don't have root access on the host to setup + networking, or if you don't want to allocate an IP to your UML + + +o pcap - not much use for actual network connectivity, but great for + monitoring traffic on the host + + Ethertap is available on 2.4 and works fine. TUN/TAP is preferred + to it because it has better performance and ethertap is officially + considered obsolete in 2.4. Also, the root helper only needs to + run occasionally for TUN/TAP, rather than handling every packet, as + it does with ethertap. This is a slight security advantage since + it provides fewer opportunities for a nasty UML user to somehow + exploit the helper's root privileges. + + + 66..11.. GGeenneerraall sseettuupp + + First, you must have the virtual network enabled in your UML. If are + running a prebuilt kernel from this site, everything is already + enabled. If you build the kernel yourself, under the "Network device + support" menu, enable "Network device support", and then the three + transports. + + + The next step is to provide a network device to the virtual machine. + This is done by describing it on the kernel command line. + + The general format is + + + eth = , + + + + + For example, a virtual ethernet device may be attached to a host + ethertap device as follows: + + + eth0=ethertap,tap0,fe:fd:0:0:0:1,192.168.0.254 + + + + + This sets up eth0 inside the virtual machine to attach itself to the + host /dev/tap0, assigns it an ethernet address, and assigns the host + tap0 interface an IP address. + + + + Note that the IP address you assign to the host end of the tap device + must be different than the IP you assign to the eth device inside UML. + If you are short on IPs and don't want to consume two per UML, then + you can reuse the host's eth IP address for the host ends of the tap + devices. Internally, the UMLs must still get unique IPs for their eth + devices. You can also give the UMLs non-routable IPs (192.168.x.x or + 10.x.x.x) and have the host masquerade them. This will let outgoing + connections work, but incoming connections won't without more work, + such as port forwarding from the host. + Also note that when you configure the host side of an interface, it is + only acting as a gateway. It will respond to pings sent to it + locally, but is not useful to do that since it's a host interface. + You are not talking to the UML when you ping that interface and get a + response. + + + You can also add devices to a UML and remove them at runtime. See the + ``The Management Console'' page for details. + + + The sections below describe this in more detail. + + + Once you've decided how you're going to set up the devices, you boot + UML, log in, configure the UML side of the devices, and set up routes + to the outside world. At that point, you will be able to talk to any + other machines, physical or virtual, on the net. + + + If ifconfig inside UML fails and the network refuses to come up, run + tell you what went wrong. + + + + 66..22.. UUsseerrssppaaccee ddaaeemmoonnss + + You will likely need the setuid helper, or the switch daemon, or both. + They are both installed with the RPM and deb, so if you've installed + either, you can skip the rest of this section. + + + If not, then you need to check them out of CVS, build them, and + install them. The helper is uml_net, in CVS /tools/uml_net, and the + daemon is uml_switch, in CVS /tools/uml_router. They are both built + with a plain 'make'. Both need to be installed in a directory that's + in your path - /usr/bin is recommend. On top of that, uml_net needs + to be setuid root. + + + + 66..33.. SSppeecciiffyyiinngg eetthheerrnneett aaddddrreesssseess + + Below, you will see that the TUN/TAP, ethertap, and daemon interfaces + allow you to specify hardware addresses for the virtual ethernet + devices. This is generally not necessary. If you don't have a + specific reason to do it, you probably shouldn't. If one is not + specified on the command line, the driver will assign one based on the + device IP address. It will provide the address fe:fd:nn:nn:nn:nn + where nn.nn.nn.nn is the device IP address. This is nearly always + sufficient to guarantee a unique hardware address for the device. A + couple of exceptions are: + + +o Another set of virtual ethernet devices are on the same network and + they are assigned hardware addresses using a different scheme which + may conflict with the UML IP address-based scheme + + +o You aren't going to use the device for IP networking, so you don't + assign the device an IP address + + If you let the driver provide the hardware address, you should make + sure that the device IP address is known before the interface is + brought up. So, inside UML, this will guarantee that: + + + + UML# + ifconfig eth0 192.168.0.250 up + + + + + If you decide to assign the hardware address yourself, make sure that + the first byte of the address is even. Addresses with an odd first + byte are broadcast addresses, which you don't want assigned to a + device. + + + + 66..44.. UUMMLL iinntteerrffaaccee sseettuupp + + Once the network devices have been described on the command line, you + should boot UML and log in. + + + The first thing to do is bring the interface up: + + + UML# ifconfig ethn ip-address up + + + + + You should be able to ping the host at this point. + + + To reach the rest of the world, you should set a default route to the + host: + + + UML# route add default gw host ip + + + + + Again, with host ip of 192.168.0.4: + + + UML# route add default gw 192.168.0.4 + + + + + This page used to recommend setting a network route to your local net. + This is wrong, because it will cause UML to try to figure out hardware + addresses of the local machines by arping on the interface to the + host. Since that interface is basically a single strand of ethernet + with two nodes on it (UML and the host) and arp requests don't cross + networks, they will fail to elicit any responses. So, what you want + is for UML to just blindly throw all packets at the host and let it + figure out what to do with them, which is what leaving out the network + route and adding the default route does. + + + Note: If you can't communicate with other hosts on your physical + ethernet, it's probably because of a network route that's + automatically set up. If you run 'route -n' and see a route that + looks like this: + + + + + Destination Gateway Genmask Flags Metric Ref Use Iface + 192.168.0.0 0.0.0.0 255.255.255.0 U 0 0 0 eth0 + + + + + with a mask that's not 255.255.255.255, then replace it with a route + to your host: + + + UML# + route del -net 192.168.0.0 dev eth0 netmask 255.255.255.0 + + + + + + + UML# + route add -host 192.168.0.4 dev eth0 + + + + + This, plus the default route to the host, will allow UML to exchange + packets with any machine on your ethernet. + + + + 66..55.. MMuullttiiccaasstt + + The simplest way to set up a virtual network between multiple UMLs is + to use the mcast transport. This was written by Harald Welte and is + present in UML version 2.4.5-5um and later. Your system must have + multicast enabled in the kernel and there must be a multicast-capable + network device on the host. Normally, this is eth0, but if there is + no ethernet card on the host, then you will likely get strange error + messages when you bring the device up inside UML. + + + To use it, run two UMLs with + + + eth0=mcast + + + + + on their command lines. Log in, configure the ethernet device in each + machine with different IP addresses: + + + UML1# ifconfig eth0 192.168.0.254 + + + + + + + UML2# ifconfig eth0 192.168.0.253 + + + + + and they should be able to talk to each other. + + The full set of command line options for this transport are + + + + ethn=mcast,ethernet address,multicast + address,multicast port,ttl + + + + + Harald's original README is here and explains these in detail, as well as + some other issues. + + + + 66..66.. TTUUNN//TTAAPP wwiitthh tthhee uummll__nneett hheellppeerr + + TUN/TAP is the preferred mechanism on 2.4 to exchange packets with the + host. The TUN/TAP backend has been in UML since 2.4.9-3um. + + + The easiest way to get up and running is to let the setuid uml_net + helper do the host setup for you. This involves insmod-ing the tun.o + module if necessary, configuring the device, and setting up IP + forwarding, routing, and proxy arp. If you are new to UML networking, + do this first. If you're concerned about the security implications of + the setuid helper, use it to get up and running, then read the next + section to see how to have UML use a preconfigured tap device, which + avoids the use of uml_net. + + + If you specify an IP address for the host side of the device, the + uml_net helper will do all necessary setup on the host - the only + requirement is that TUN/TAP be available, either built in to the host + kernel or as the tun.o module. + + The format of the command line switch to attach a device to a TUN/TAP + device is + + + eth =tuntap,,, + + + + + For example, this argument will attach the UML's eth0 to the next + available tap device and assign an ethernet address to it based on its + IP address + + + eth0=tuntap,,,192.168.0.254 + + + + + + + Note that the IP address that must be used for the eth device inside + UML is fixed by the routing and proxy arp that is set up on the + TUN/TAP device on the host. You can use a different one, but it won't + work because reply packets won't reach the UML. This is a feature. + It prevents a nasty UML user from doing things like setting the UML IP + to the same as the network's nameserver or mail server. + + + There are a couple potential problems with running the TUN/TAP + transport on a 2.4 host kernel + + +o TUN/TAP seems not to work on 2.4.3 and earlier. Upgrade the host + kernel or use the ethertap transport. + + +o With an upgraded kernel, TUN/TAP may fail with + + + File descriptor in bad state + + + + + This is due to a header mismatch between the upgraded kernel and the + kernel that was originally installed on the machine. The fix is to + make sure that /usr/src/linux points to the headers for the running + kernel. + + These were pointed out by Tim Robinson in + name="this uml- + user post"> . + + + + 66..77.. TTUUNN//TTAAPP wwiitthh aa pprreeccoonnffiigguurreedd ttaapp ddeevviiccee + + If you prefer not to have UML use uml_net (which is somewhat + insecure), with UML 2.4.17-11, you can set up a TUN/TAP device + beforehand. The setup needs to be done as root, but once that's done, + there is no need for root assistance. Setting up the device is done + as follows: + + +o Create the device with tunctl (available from the UML utilities + tarball) + + + + + host# tunctl -u uid + + + + + where uid is the user id or username that UML will be run as. This + will tell you what device was created. + + +o Configure the device IP (change IP addresses and device name to + suit) + + + + + host# ifconfig tap0 192.168.0.254 up + + + + + + +o Set up routing and arping if desired - this is my recipe, there are + other ways of doing the same thing + + + host# + bash -c 'echo 1 > /proc/sys/net/ipv4/ip_forward' + + host# + route add -host 192.168.0.253 dev tap0 + + + + + + + host# + bash -c 'echo 1 > /proc/sys/net/ipv4/conf/tap0/proxy_arp' + + + + + + + host# + arp -Ds 192.168.0.253 eth0 pub + + + + + Note that this must be done every time the host boots - this configu- + ration is not stored across host reboots. So, it's probably a good + idea to stick it in an rc file. An even better idea would be a little + utility which reads the information from a config file and sets up + devices at boot time. + + +o Rather than using up two IPs and ARPing for one of them, you can + also provide direct access to your LAN by the UML by using a + bridge. + + + host# + brctl addbr br0 + + + + + + + host# + ifconfig eth0 0.0.0.0 promisc up + + + + + + + host# + ifconfig tap0 0.0.0.0 promisc up + + + + + + + host# + ifconfig br0 192.168.0.1 netmask 255.255.255.0 up + + + + + + + + host# + brctl stp br0 off + + + + + + + host# + brctl setfd br0 1 + + + + + + + host# + brctl sethello br0 1 + + + + + + + host# + brctl addif br0 eth0 + + + + + + + host# + brctl addif br0 tap0 + + + + + Note that 'br0' should be setup using ifconfig with the existing IP + address of eth0, as eth0 no longer has its own IP. + + +o + + + Also, the /dev/net/tun device must be writable by the user running + UML in order for the UML to use the device that's been configured + for it. The simplest thing to do is + + + host# chmod 666 /dev/net/tun + + + + + Making it world-writable looks bad, but it seems not to be + exploitable as a security hole. However, it does allow anyone to cre- + ate useless tap devices (useless because they can't configure them), + which is a DOS attack. A somewhat more secure alternative would to be + to create a group containing all the users who have preconfigured tap + devices and chgrp /dev/net/tun to that group with mode 664 or 660. + + + +o Once the device is set up, run UML with 'eth0=tuntap,device name' + (i.e. 'eth0=tuntap,tap0') on the command line (or do it with the + mconsole config command). + + +o Bring the eth device up in UML and you're in business. + + If you don't want that tap device any more, you can make it non- + persistent with + + + host# tunctl -d tap device + + + + + Finally, tunctl has a -b (for brief mode) switch which causes it to + output only the name of the tap device it created. This makes it + suitable for capture by a script: + + + host# TAP=`tunctl -u 1000 -b` + + + + + + + 66..88.. EEtthheerrttaapp + + Ethertap is the general mechanism on 2.2 for userspace processes to + exchange packets with the kernel. + + + + To use this transport, you need to describe the virtual network device + on the UML command line. The general format for this is + + + eth =ethertap, , , + + + + + So, the previous example + + + eth0=ethertap,tap0,fe:fd:0:0:0:1,192.168.0.254 + + + + + attaches the UML eth0 device to the host /dev/tap0, assigns it the + ethernet address fe:fd:0:0:0:1, and assigns the IP address + 192.168.0.254 to the tap device. + + + + The tap device is mandatory, but the others are optional. If the + ethernet address is omitted, one will be assigned to it. + + + The presence of the tap IP address will cause the helper to run and do + whatever host setup is needed to allow the virtual machine to + communicate with the outside world. If you're not sure you know what + you're doing, this is the way to go. + + + If it is absent, then you must configure the tap device and whatever + arping and routing you will need on the host. However, even in this + case, the uml_net helper still needs to be in your path and it must be + setuid root if you're not running UML as root. This is because the + tap device doesn't support SIGIO, which UML needs in order to use + something as a source of input. So, the helper is used as a + convenient asynchronous IO thread. + + If you're using the uml_net helper, you can ignore the following host + setup - uml_net will do it for you. You just need to make sure you + have ethertap available, either built in to the host kernel or + available as a module. + + + If you want to set things up yourself, you need to make sure that the + appropriate /dev entry exists. If it doesn't, become root and create + it as follows: + + + mknod /dev/tap c 36 + 16 + + + + + For example, this is how to create /dev/tap0: + + + mknod /dev/tap0 c 36 0 + 16 + + + + + You also need to make sure that the host kernel has ethertap support. + If ethertap is enabled as a module, you apparently need to insmod + ethertap once for each ethertap device you want to enable. So, + + + host# + insmod ethertap + + + + + will give you the tap0 interface. To get the tap1 interface, you need + to run + + + host# + insmod ethertap unit=1 -o ethertap1 + + + + + + + + 66..99.. TThhee sswwiittcchh ddaaeemmoonn + + NNoottee: This is the daemon formerly known as uml_router, but which was + renamed so the network weenies of the world would stop growling at me. + + + The switch daemon, uml_switch, provides a mechanism for creating a + totally virtual network. By default, it provides no connection to the + host network (but see -tap, below). + + + The first thing you need to do is run the daemon. Running it with no + arguments will make it listen on a default pair of unix domain + sockets. + + + If you want it to listen on a different pair of sockets, use + + + -unix control socket data socket + + + + + + If you want it to act as a hub rather than a switch, use + + + -hub + + + + + + If you want the switch to be connected to host networking (allowing + the umls to get access to the outside world through the host), use + + + -tap tap0 + + + + + + Note that the tap device must be preconfigured (see "TUN/TAP with a + preconfigured tap device", above). If you're using a different tap + device than tap0, specify that instead of tap0. + + + uml_switch can be backgrounded as follows + + + host% + uml_switch [ options ] < /dev/null > /dev/null + + + + + The reason it doesn't background by default is that it listens to + stdin for EOF. When it sees that, it exits. + + + The general format of the kernel command line switch is + + + + ethn=daemon,ethernet address,socket + type,control socket,data socket + + + + + You can leave off everything except the 'daemon'. You only need to + specify the ethernet address if the one that will be assigned to it + isn't acceptable for some reason. The rest of the arguments describe + how to communicate with the daemon. You should only specify them if + you told the daemon to use different sockets than the default. So, if + you ran the daemon with no arguments, running the UML on the same + machine with + eth0=daemon + + + + + will cause the eth0 driver to attach itself to the daemon correctly. + + + + 66..1100.. SSlliipp + + Slip is another, less general, mechanism for a process to communicate + with the host networking. In contrast to the ethertap interface, + which exchanges ethernet frames with the host and can be used to + transport any higher-level protocol, it can only be used to transport + IP. + + + The general format of the command line switch is + + + + ethn=slip,slip IP + + + + + The slip IP argument is the IP address that will be assigned to the + host end of the slip device. If it is specified, the helper will run + and will set up the host so that the virtual machine can reach it and + the rest of the network. + + + There are some oddities with this interface that you should be aware + of. You should only specify one slip device on a given virtual + machine, and its name inside UML will be 'umn', not 'eth0' or whatever + you specified on the command line. These problems will be fixed at + some point. + + + + 66..1111.. SSlliirrpp + + slirp uses an external program, usually /usr/bin/slirp, to provide IP + only networking connectivity through the host. This is similar to IP + masquerading with a firewall, although the translation is performed in + user-space, rather than by the kernel. As slirp does not set up any + interfaces on the host, or changes routing, slirp does not require + root access or setuid binaries on the host. + + + The general format of the command line switch for slirp is: + + + + ethn=slirp,ethernet address,slirp path + + + + + The ethernet address is optional, as UML will set up the interface + with an ethernet address based upon the initial IP address of the + interface. The slirp path is generally /usr/bin/slirp, although it + will depend on distribution. + + + The slirp program can have a number of options passed to the command + line and we can't add them to the UML command line, as they will be + parsed incorrectly. Instead, a wrapper shell script can be written or + the options inserted into the /.slirprc file. More information on + all of the slirp options can be found in its man pages. + + + The eth0 interface on UML should be set up with the IP 10.2.0.15, + although you can use anything as long as it is not used by a network + you will be connecting to. The default route on UML should be set to + use + + + UML# + route add default dev eth0 + + + + + slirp provides a number of useful IP addresses which can be used by + UML, such as 10.0.2.3 which is an alias for the DNS server specified + in /etc/resolv.conf on the host or the IP given in the 'dns' option + for slirp. + + + Even with a baudrate setting higher than 115200, the slirp connection + is limited to 115200. If you need it to go faster, the slirp binary + needs to be compiled with FULL_BOLT defined in config.h. + + + + 66..1122.. ppccaapp + + The pcap transport is attached to a UML ethernet device on the command + line or with uml_mconsole with the following syntax: + + + + ethn=pcap,host interface,filter + expression,option1,option2 + + + + + The expression and options are optional. + + + The interface is whatever network device on the host you want to + sniff. The expression is a pcap filter expression, which is also what + tcpdump uses, so if you know how to specify tcpdump filters, you will + use the same expressions here. The options are up to two of + 'promisc', control whether pcap puts the host interface into + promiscuous mode. 'optimize' and 'nooptimize' control whether the pcap + expression optimizer is used. + + + Example: + + + + eth0=pcap,eth0,tcp + + eth1=pcap,eth0,!tcp + + + + will cause the UML eth0 to emit all tcp packets on the host eth0 and + the UML eth1 to emit all non-tcp packets on the host eth0. + + + + 66..1133.. SSeettttiinngg uupp tthhee hhoosstt yyoouurrsseellff + + If you don't specify an address for the host side of the ethertap or + slip device, UML won't do any setup on the host. So this is what is + needed to get things working (the examples use a host-side IP of + 192.168.0.251 and a UML-side IP of 192.168.0.250 - adjust to suit your + own network): + + +o The device needs to be configured with its IP address. Tap devices + are also configured with an mtu of 1484. Slip devices are + configured with a point-to-point address pointing at the UML ip + address. + + + host# ifconfig tap0 arp mtu 1484 192.168.0.251 up + + + + + + + host# + ifconfig sl0 192.168.0.251 pointopoint 192.168.0.250 up + + + + + + +o If a tap device is being set up, a route is set to the UML IP. + + + UML# route add -host 192.168.0.250 gw 192.168.0.251 + + + + + + +o To allow other hosts on your network to see the virtual machine, + proxy arp is set up for it. + + + host# arp -Ds 192.168.0.250 eth0 pub + + + + + + +o Finally, the host is set up to route packets. + + + host# echo 1 > /proc/sys/net/ipv4/ip_forward + + + + + + + + + + + 77.. SShhaarriinngg FFiilleessyysstteemmss bbeettwweeeenn VViirrttuuaall MMaacchhiinneess + + + + + 77..11.. AA wwaarrnniinngg + + Don't attempt to share filesystems simply by booting two UMLs from the + same file. That's the same thing as booting two physical machines + from a shared disk. It will result in filesystem corruption. + + + + 77..22.. UUssiinngg llaayyeerreedd bblloocckk ddeevviicceess + + The way to share a filesystem between two virtual machines is to use + the copy-on-write (COW) layering capability of the ubd block driver. + As of 2.4.6-2um, the driver supports layering a read-write private + device over a read-only shared device. A machine's writes are stored + in the private device, while reads come from either device - the + private one if the requested block is valid in it, the shared one if + not. Using this scheme, the majority of data which is unchanged is + shared between an arbitrary number of virtual machines, each of which + has a much smaller file containing the changes that it has made. With + a large number of UMLs booting from a large root filesystem, this + leads to a huge disk space saving. It will also help performance, + since the host will be able to cache the shared data using a much + smaller amount of memory, so UML disk requests will be served from the + host's memory rather than its disks. + + + + + To add a copy-on-write layer to an existing block device file, simply + add the name of the COW file to the appropriate ubd switch: + + + ubd0=root_fs_cow,root_fs_debian_22 + + + + + where 'root_fs_cow' is the private COW file and 'root_fs_debian_22' is + the existing shared filesystem. The COW file need not exist. If it + doesn't, the driver will create and initialize it. Once the COW file + has been initialized, it can be used on its own on the command line: + + + ubd0=root_fs_cow + + + + + The name of the backing file is stored in the COW file header, so it + would be redundant to continue specifying it on the command line. + + + + 77..33.. NNoottee!! + + When checking the size of the COW file in order to see the gobs of + space that you're saving, make sure you use 'ls -ls' to see the actual + disk consumption rather than the length of the file. The COW file is + sparse, so the length will be very different from the disk usage. + Here is a 'ls -l' of a COW file and backing file from one boot and + shutdown: + host% ls -l cow.debian debian2.2 + -rw-r--r-- 1 jdike jdike 492504064 Aug 6 21:16 cow.debian + -rwxrw-rw- 1 jdike jdike 537919488 Aug 6 20:42 debian2.2 + + + + + Doesn't look like much saved space, does it? Well, here's 'ls -ls': + + + host% ls -ls cow.debian debian2.2 + 880 -rw-r--r-- 1 jdike jdike 492504064 Aug 6 21:16 cow.debian + 525832 -rwxrw-rw- 1 jdike jdike 537919488 Aug 6 20:42 debian2.2 + + + + + Now, you can see that the COW file has less than a meg of disk, rather + than 492 meg. + + + + 77..44.. AAnnootthheerr wwaarrnniinngg + + Once a filesystem is being used as a readonly backing file for a COW + file, do not boot directly from it or modify it in any way. Doing so + will invalidate any COW files that are using it. The mtime and size + of the backing file are stored in the COW file header at its creation, + and they must continue to match. If they don't, the driver will + refuse to use the COW file. + + + + + If you attempt to evade this restriction by changing either the + backing file or the COW header by hand, you will get a corrupted + filesystem. + + + + + Among other things, this means that upgrading the distribution in a + backing file and expecting that all of the COW files using it will see + the upgrade will not work. + + + + + 77..55.. uummll__mmoooo :: MMeerrggiinngg aa CCOOWW ffiillee wwiitthh iittss bbaacckkiinngg ffiillee + + Depending on how you use UML and COW devices, it may be advisable to + merge the changes in the COW file into the backing file every once in + a while. + + + + + The utility that does this is uml_moo. Its usage is + + + host% uml_moo COW file new backing file + + + + + There's no need to specify the backing file since that information is + already in the COW file header. If you're paranoid, boot the new + merged file, and if you're happy with it, move it over the old backing + file. + + + + + uml_moo creates a new backing file by default as a safety measure. It + also has a destructive merge option which will merge the COW file + directly into its current backing file. This is really only usable + when the backing file only has one COW file associated with it. If + there are multiple COWs associated with a backing file, a -d merge of + one of them will invalidate all of the others. However, it is + convenient if you're short of disk space, and it should also be + noticeably faster than a non-destructive merge. + + + + + uml_moo is installed with the UML deb and RPM. If you didn't install + UML from one of those packages, you can also get it from the UML + utilities tar file in tools/moo. + + + + + + + + + 88.. CCrreeaattiinngg ffiilleessyysstteemmss + + + You may want to create and mount new UML filesystems, either because + your root filesystem isn't large enough or because you want to use a + filesystem other than ext2. + + + This was written on the occasion of reiserfs being included in the + 2.4.1 kernel pool, and therefore the 2.4.1 UML, so the examples will + talk about reiserfs. This information is generic, and the examples + should be easy to translate to the filesystem of your choice. + + + 88..11.. CCrreeaattee tthhee ffiilleessyysstteemm ffiillee + + dd is your friend. All you need to do is tell dd to create an empty + file of the appropriate size. I usually make it sparse to save time + and to avoid allocating disk space until it's actually used. For + example, the following command will create a sparse 100 meg file full + of zeroes. + + + host% + dd if=/dev/zero of=new_filesystem seek=100 count=1 bs=1M + + + + + + + 88..22.. AAssssiiggnn tthhee ffiillee ttoo aa UUMMLL ddeevviiccee + + Add an argument like the following to the UML command line: + + ubd4=new_filesystem + + + + + making sure that you use an unassigned ubd device number. + + + + 88..33.. CCrreeaattiinngg aanndd mmoouunnttiinngg tthhee ffiilleessyysstteemm + + Make sure that the filesystem is available, either by being built into + the kernel, or available as a module, then boot up UML and log in. If + the root filesystem doesn't have the filesystem utilities (mkfs, fsck, + etc), then get them into UML by way of the net or hostfs. + + + Make the new filesystem on the device assigned to the new file: + + + host# mkreiserfs /dev/ubd/4 + + + <----------- MKREISERFSv2 -----------> + + ReiserFS version 3.6.25 + Block size 4096 bytes + Block count 25856 + Used blocks 8212 + Journal - 8192 blocks (18-8209), journal header is in block 8210 + Bitmaps: 17 + Root block 8211 + Hash function "r5" + ATTENTION: ALL DATA WILL BE LOST ON '/dev/ubd/4'! (y/n)y + journal size 8192 (from 18) + Initializing journal - 0%....20%....40%....60%....80%....100% + Syncing..done. + + + + + Now, mount it: + + + UML# + mount /dev/ubd/4 /mnt + + + + + and you're in business. + + + + + + + + + + 99.. HHoosstt ffiillee aacccceessss + + + If you want to access files on the host machine from inside UML, you + can treat it as a separate machine and either nfs mount directories + from the host or copy files into the virtual machine with scp or rcp. + However, since UML is running on the host, it can access those + files just like any other process and make them available inside the + virtual machine without needing to use the network. + + + This is now possible with the hostfs virtual filesystem. With it, you + can mount a host directory into the UML filesystem and access the + files contained in it just as you would on the host. + + + 99..11.. UUssiinngg hhoossttffss + + To begin with, make sure that hostfs is available inside the virtual + machine with + + + UML# cat /proc/filesystems + + + + . hostfs should be listed. If it's not, either rebuild the kernel + with hostfs configured into it or make sure that hostfs is built as a + module and available inside the virtual machine, and insmod it. + + + Now all you need to do is run mount: + + + UML# mount none /mnt/host -t hostfs + + + + + will mount the host's / on the virtual machine's /mnt/host. + + + If you don't want to mount the host root directory, then you can + specify a subdirectory to mount with the -o switch to mount: + + + UML# mount none /mnt/home -t hostfs -o /home + + + + + will mount the hosts's /home on the virtual machine's /mnt/home. + + + + 99..22.. hhoossttffss aass tthhee rroooott ffiilleessyysstteemm + + It's possible to boot from a directory hierarchy on the host using + hostfs rather than using the standard filesystem in a file. + + To start, you need that hierarchy. The easiest way is to loop mount + an existing root_fs file: + + + host# mount root_fs uml_root_dir -o loop + + + + + You need to change the filesystem type of / in etc/fstab to be + 'hostfs', so that line looks like this: + + /dev/ubd/0 / hostfs defaults 1 1 + + + + + Then you need to chown to yourself all the files in that directory + that are owned by root. This worked for me: + + + host# find . -uid 0 -exec chown jdike {} \; + + + + + Next, make sure that your UML kernel has hostfs compiled in, not as a + module. Then run UML with the boot device pointing at that directory: + + + ubd0=/path/to/uml/root/directory + + + + + UML should then boot as it does normally. + + + 99..33.. BBuuiillddiinngg hhoossttffss + + If you need to build hostfs because it's not in your kernel, you have + two choices: + + + + +o Compiling hostfs into the kernel: + + + Reconfigure the kernel and set the 'Host filesystem' option under + + + +o Compiling hostfs as a module: + + + Reconfigure the kernel and set the 'Host filesystem' option under + be in arch/um/fs/hostfs/hostfs.o. Install that in + /lib/modules/`uname -r`/fs in the virtual machine, boot it up, and + + + UML# insmod hostfs + + + + + + + + + + + + + 1100.. TThhee MMaannaaggeemmeenntt CCoonnssoollee + + + + The UML management console is a low-level interface to the kernel, + somewhat like the i386 SysRq interface. Since there is a full-blown + operating system under UML, there is much greater flexibility possible + than with the SysRq mechanism. + + + There are a number of things you can do with the mconsole interface: + + +o get the kernel version + + +o add and remove devices + + +o halt or reboot the machine + + +o Send SysRq commands + + +o Pause and resume the UML + + + You need the mconsole client (uml_mconsole) which is present in CVS + (/tools/mconsole) in 2.4.5-9um and later, and will be in the RPM in + 2.4.6. + + + You also need CONFIG_MCONSOLE (under 'General Setup') enabled in UML. + When you boot UML, you'll see a line like: + + + mconsole initialized on /home/jdike/.uml/umlNJ32yL/mconsole + + + + + If you specify a unique machine id one the UML command line, i.e. + + + umid=debian + + + + + you'll see this + + + mconsole initialized on /home/jdike/.uml/debian/mconsole + + + + + That file is the socket that uml_mconsole will use to communicate with + UML. Run it with either the umid or the full path as its argument: + + + host% uml_mconsole debian + + + + + or + + + host% uml_mconsole /home/jdike/.uml/debian/mconsole + + + + + You'll get a prompt, at which you can run one of these commands: + + +o version + + +o halt + + +o reboot + + +o config + + +o remove + + +o sysrq + + +o help + + +o cad + + +o stop + + +o go + + + 1100..11.. vveerrssiioonn + + This takes no arguments. It prints the UML version. + + + (mconsole) version + OK Linux usermode 2.4.5-9um #1 Wed Jun 20 22:47:08 EDT 2001 i686 + + + + + There are a couple actual uses for this. It's a simple no-op which + can be used to check that a UML is running. It's also a way of + sending an interrupt to the UML. This is sometimes useful on SMP + hosts, where there's a bug which causes signals to UML to be lost, + often causing it to appear to hang. Sending such a UML the mconsole + version command is a good way to 'wake it up' before networking has + been enabled, as it does not do anything to the function of the UML. + + + + 1100..22.. hhaalltt aanndd rreebboooott + + These take no arguments. They shut the machine down immediately, with + no syncing of disks and no clean shutdown of userspace. So, they are + pretty close to crashing the machine. + + + (mconsole) halt + OK + + + + + + + 1100..33.. ccoonnffiigg + + "config" adds a new device to the virtual machine. Currently the ubd + and network drivers support this. It takes one argument, which is the + device to add, with the same syntax as the kernel command line. + + + + + (mconsole) + config ubd3=/home/jdike/incoming/roots/root_fs_debian22 + + OK + (mconsole) config eth1=mcast + OK + + + + + + + 1100..44.. rreemmoovvee + + "remove" deletes a device from the system. Its argument is just the + name of the device to be removed. The device must be idle in whatever + sense the driver considers necessary. In the case of the ubd driver, + the removed block device must not be mounted, swapped on, or otherwise + open, and in the case of the network driver, the device must be down. + + + (mconsole) remove ubd3 + OK + (mconsole) remove eth1 + OK + + + + + + + 1100..55.. ssyyssrrqq + + This takes one argument, which is a single letter. It calls the + generic kernel's SysRq driver, which does whatever is called for by + that argument. See the SysRq documentation in Documentation/sysrq.txt + in your favorite kernel tree to see what letters are valid and what + they do. + + + + 1100..66.. hheellpp + + "help" returns a string listing the valid commands and what each one + does. + + + + 1100..77.. ccaadd + + This invokes the Ctl-Alt-Del action on init. What exactly this ends + up doing is up to /etc/inittab. Normally, it reboots the machine. + With UML, this is usually not desired, so if a halt would be better, + then find the section of inittab that looks like this + + + # What to do when CTRL-ALT-DEL is pressed. + ca:12345:ctrlaltdel:/sbin/shutdown -t1 -a -r now + + + + + and change the command to halt. + + + + 1100..88.. ssttoopp + + This puts the UML in a loop reading mconsole requests until a 'go' + mconsole command is received. This is very useful for making backups + of UML filesystems, as the UML can be stopped, then synced via 'sysrq + s', so that everything is written to the filesystem. You can then copy + the filesystem and then send the UML 'go' via mconsole. + + + Note that a UML running with more than one CPU will have problems + after you send the 'stop' command, as only one CPU will be held in a + mconsole loop and all others will continue as normal. This is a bug, + and will be fixed. + + + + 1100..99.. ggoo + + This resumes a UML after being paused by a 'stop' command. Note that + when the UML has resumed, TCP connections may have timed out and if + the UML is paused for a long period of time, crond might go a little + crazy, running all the jobs it didn't do earlier. + + + + + + + + + 1111.. KKeerrnneell ddeebbuuggggiinngg + + + NNoottee:: The interface that makes debugging, as described here, possible + is present in 2.4.0-test6 kernels and later. + + + Since the user-mode kernel runs as a normal Linux process, it is + possible to debug it with gdb almost like any other process. It is + slightly different because the kernel's threads are already being + ptraced for system call interception, so gdb can't ptrace them. + However, a mechanism has been added to work around that problem. + + + In order to debug the kernel, you need build it from source. See + ``Compiling the kernel and modules'' for information on doing that. + Make sure that you enable CONFIG_DEBUGSYM and CONFIG_PT_PROXY during + the config. These will compile the kernel with -g, and enable the + ptrace proxy so that gdb works with UML, respectively. + + + + + 1111..11.. SSttaarrttiinngg tthhee kkeerrnneell uunnddeerr ggddbb + + You can have the kernel running under the control of gdb from the + beginning by putting 'debug' on the command line. You will get an + xterm with gdb running inside it. The kernel will send some commands + to gdb which will leave it stopped at the beginning of start_kernel. + At this point, you can get things going with 'next', 'step', or + 'cont'. + + + There is a transcript of a debugging session here , with breakpoints being set in the scheduler and in an + interrupt handler. + 1111..22.. EExxaammiinniinngg sslleeeeppiinngg pprroocceesssseess + + Not every bug is evident in the currently running process. Sometimes, + processes hang in the kernel when they shouldn't because they've + deadlocked on a semaphore or something similar. In this case, when + you ^C gdb and get a backtrace, you will see the idle thread, which + isn't very relevant. + + + What you want is the stack of whatever process is sleeping when it + shouldn't be. You need to figure out which process that is, which is + generally fairly easy. Then you need to get its host process id, + which you can do either by looking at ps on the host or at + task.thread.extern_pid in gdb. + + + Now what you do is this: + + +o detach from the current thread + + + (UML gdb) det + + + + + + +o attach to the thread you are interested in + + + (UML gdb) att + + + + + + +o look at its stack and anything else of interest + + + (UML gdb) bt + + + + + Note that you can't do anything at this point that requires that a + process execute, e.g. calling a function + + +o when you're done looking at that process, reattach to the current + thread and continue it + + + (UML gdb) + att 1 + + + + + + + (UML gdb) + c + + + + + Here, specifying any pid which is not the process id of a UML thread + will cause gdb to reattach to the current thread. I commonly use 1, + but any other invalid pid would work. + + + + 1111..33.. RRuunnnniinngg dddddd oonn UUMMLL + + ddd works on UML, but requires a special kludge. The process goes + like this: + + +o Start ddd + + + host% ddd linux + + + + + + +o With ps, get the pid of the gdb that ddd started. You can ask the + gdb to tell you, but for some reason that confuses things and + causes a hang. + + +o run UML with 'debug=parent gdb-pid=' added to the command line + - it will just sit there after you hit return + + +o type 'att 1' to the ddd gdb and you will see something like + + + 0xa013dc51 in __kill () + + + (gdb) + + + + + + +o At this point, type 'c', UML will boot up, and you can use ddd just + as you do on any other process. + + + + 1111..44.. DDeebbuuggggiinngg mmoodduulleess + + gdb has support for debugging code which is dynamically loaded into + the process. This support is what is needed to debug kernel modules + under UML. + + + Using that support is somewhat complicated. You have to tell gdb what + object file you just loaded into UML and where in memory it is. Then, + it can read the symbol table, and figure out where all the symbols are + from the load address that you provided. It gets more interesting + when you load the module again (i.e. after an rmmod). You have to + tell gdb to forget about all its symbols, including the main UML ones + for some reason, then load then all back in again. + + + There's an easy way and a hard way to do this. The easy way is to use + the umlgdb expect script written by Chandan Kudige. It basically + automates the process for you. + + + First, you must tell it where your modules are. There is a list in + the script that looks like this: + set MODULE_PATHS { + "fat" "/usr/src/uml/linux-2.4.18/fs/fat/fat.o" + "isofs" "/usr/src/uml/linux-2.4.18/fs/isofs/isofs.o" + "minix" "/usr/src/uml/linux-2.4.18/fs/minix/minix.o" + } + + + + + You change that to list the names and paths of the modules that you + are going to debug. Then you run it from the toplevel directory of + your UML pool and it basically tells you what to do: + + + + + ******** GDB pid is 21903 ******** + Start UML as: ./linux debug gdb-pid=21903 + + + + GNU gdb 5.0rh-5 Red Hat Linux 7.1 + Copyright 2001 Free Software Foundation, Inc. + GDB is free software, covered by the GNU General Public License, and you are + welcome to change it and/or distribute copies of it under certain conditions. + Type "show copying" to see the conditions. + There is absolutely no warranty for GDB. Type "show warranty" for details. + This GDB was configured as "i386-redhat-linux"... + (gdb) b sys_init_module + Breakpoint 1 at 0xa0011923: file module.c, line 349. + (gdb) att 1 + + + + + After you run UML and it sits there doing nothing, you hit return at + the 'att 1' and continue it: + + + Attaching to program: /home/jdike/linux/2.4/um/./linux, process 1 + 0xa00f4221 in __kill () + (UML gdb) c + Continuing. + + + + + At this point, you debug normally. When you insmod something, the + expect magic will kick in and you'll see something like: + + + + + + + + + + + + + + + + + + *** Module hostfs loaded *** + Breakpoint 1, sys_init_module (name_user=0x805abb0 "hostfs", + mod_user=0x8070e00) at module.c:349 + 349 char *name, *n_name, *name_tmp = NULL; + (UML gdb) finish + Run till exit from #0 sys_init_module (name_user=0x805abb0 "hostfs", + mod_user=0x8070e00) at module.c:349 + 0xa00e2e23 in execute_syscall (r=0xa8140284) at syscall_kern.c:411 + 411 else res = EXECUTE_SYSCALL(syscall, regs); + Value returned is $1 = 0 + (UML gdb) + p/x (int)module_list + module_list->size_of_struct + + $2 = 0xa9021054 + (UML gdb) symbol-file ./linux + Load new symbol table from "./linux"? (y or n) y + Reading symbols from ./linux... + done. + (UML gdb) + add-symbol-file /home/jdike/linux/2.4/um/arch/um/fs/hostfs/hostfs.o 0xa9021054 + + add symbol table from file "/home/jdike/linux/2.4/um/arch/um/fs/hostfs/hostfs.o" at + .text_addr = 0xa9021054 + (y or n) y + + Reading symbols from /home/jdike/linux/2.4/um/arch/um/fs/hostfs/hostfs.o... + done. + (UML gdb) p *module_list + $1 = {size_of_struct = 84, next = 0xa0178720, name = 0xa9022de0 "hostfs", + size = 9016, uc = {usecount = {counter = 0}, pad = 0}, flags = 1, + nsyms = 57, ndeps = 0, syms = 0xa9023170, deps = 0x0, refs = 0x0, + init = 0xa90221f0 , cleanup = 0xa902222c , + ex_table_start = 0x0, ex_table_end = 0x0, persist_start = 0x0, + persist_end = 0x0, can_unload = 0, runsize = 0, kallsyms_start = 0x0, + kallsyms_end = 0x0, + archdata_start = 0x1b855
, + archdata_end = 0xe5890000
, + kernel_data = 0xf689c35d
} + >> Finished loading symbols for hostfs ... + + + + + That's the easy way. It's highly recommended. The hard way is + described below in case you're interested in what's going on. + + + Boot the kernel under the debugger and load the module with insmod or + modprobe. With gdb, do: + + + (UML gdb) p module_list + + + + + This is a list of modules that have been loaded into the kernel, with + the most recently loaded module first. Normally, the module you want + is at module_list. If it's not, walk down the next links, looking at + the name fields until find the module you want to debug. Take the + address of that structure, and add module.size_of_struct (which in + 2.4.10 kernels is 96 (0x60)) to it. Gdb can make this hard addition + for you :-): + + + + (UML gdb) + printf "%#x\n", (int)module_list module_list->size_of_struct + + + + + The offset from the module start occasionally changes (before 2.4.0, + it was module.size_of_struct + 4), so it's a good idea to check the + init and cleanup addresses once in a while, as describe below. Now + do: + + + (UML gdb) + add-symbol-file /path/to/module/on/host that_address + + + + + Tell gdb you really want to do it, and you're in business. + + + If there's any doubt that you got the offset right, like breakpoints + appear not to work, or they're appearing in the wrong place, you can + check it by looking at the module structure. The init and cleanup + fields should look like: + + + init = 0x588066b0 , cleanup = 0x588066c0 + + + + + with no offsets on the symbol names. If the names are right, but they + are offset, then the offset tells you how much you need to add to the + address you gave to add-symbol-file. + + + When you want to load in a new version of the module, you need to get + gdb to forget about the old one. The only way I've found to do that + is to tell gdb to forget about all symbols that it knows about: + + + (UML gdb) symbol-file + + + + + Then reload the symbols from the kernel binary: + + + (UML gdb) symbol-file /path/to/kernel + + + + + and repeat the process above. You'll also need to re-enable break- + points. They were disabled when you dumped all the symbols because + gdb couldn't figure out where they should go. + + + + 1111..55.. AAttttaacchhiinngg ggddbb ttoo tthhee kkeerrnneell + + If you don't have the kernel running under gdb, you can attach gdb to + it later by sending the tracing thread a SIGUSR1. The first line of + the console output identifies its pid: + tracing thread pid = 20093 + + + + + When you send it the signal: + + + host% kill -USR1 20093 + + + + + you will get an xterm with gdb running in it. + + + If you have the mconsole compiled into UML, then the mconsole client + can be used to start gdb: + + + (mconsole) (mconsole) config gdb=xterm + + + + + will fire up an xterm with gdb running in it. + + + + 1111..66.. UUssiinngg aalltteerrnnaattee ddeebbuuggggeerrss + + UML has support for attaching to an already running debugger rather + than starting gdb itself. This is present in CVS as of 17 Apr 2001. + I sent it to Alan for inclusion in the ac tree, and it will be in my + 2.4.4 release. + + + This is useful when gdb is a subprocess of some UI, such as emacs or + ddd. It can also be used to run debuggers other than gdb on UML. + Below is an example of using strace as an alternate debugger. + + + To do this, you need to get the pid of the debugger and pass it in + with the + + + If you are using gdb under some UI, then tell it to 'att 1', and + you'll find yourself attached to UML. + + + If you are using something other than gdb as your debugger, then + you'll need to get it to do the equivalent of 'att 1' if it doesn't do + it automatically. + + + An example of an alternate debugger is strace. You can strace the + actual kernel as follows: + + +o Run the following in a shell + + + host% + sh -c 'echo pid=$$; echo -n hit return; read x; exec strace -p 1 -o strace.out' + + + + +o Run UML with 'debug' and 'gdb-pid=' with the pid printed out + by the previous command + + +o Hit return in the shell, and UML will start running, and strace + output will start accumulating in the output file. + + Note that this is different from running + + + host% strace ./linux + + + + + That will strace only the main UML thread, the tracing thread, which + doesn't do any of the actual kernel work. It just oversees the vir- + tual machine. In contrast, using strace as described above will show + you the low-level activity of the virtual machine. + + + + + + 1122.. KKeerrnneell ddeebbuuggggiinngg eexxaammpplleess + + 1122..11.. TThhee ccaassee ooff tthhee hhuunngg ffsscckk + + When booting up the kernel, fsck failed, and dropped me into a shell + to fix things up. I ran fsck -y, which hung: + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Setting hostname uml [ OK ] + Checking root filesystem + /dev/fhd0 was not cleanly unmounted, check forced. + Error reading block 86894 (Attempt to read block from filesystem resulted in short read) while reading indirect blocks of inode 19780. + + /dev/fhd0: UNEXPECTED INCONSISTENCY; RUN fsck MANUALLY. + (i.e., without -a or -p options) + [ FAILED ] + + *** An error occurred during the file system check. + *** Dropping you to a shell; the system will reboot + *** when you leave the shell. + Give root password for maintenance + (or type Control-D for normal startup): + + [root@uml /root]# fsck -y /dev/fhd0 + fsck -y /dev/fhd0 + Parallelizing fsck version 1.14 (9-Jan-1999) + e2fsck 1.14, 9-Jan-1999 for EXT2 FS 0.5b, 95/08/09 + /dev/fhd0 contains a file system with errors, check forced. + Pass 1: Checking inodes, blocks, and sizes + Error reading block 86894 (Attempt to read block from filesystem resulted in short read) while reading indirect blocks of inode 19780. Ignore error? yes + + Inode 19780, i_blocks is 1548, should be 540. Fix? yes + + Pass 2: Checking directory structure + Error reading block 49405 (Attempt to read block from filesystem resulted in short read). Ignore error? yes + + Directory inode 11858, block 0, offset 0: directory corrupted + Salvage? yes + + Missing '.' in directory inode 11858. + Fix? yes + + Missing '..' in directory inode 11858. + Fix? yes + + + + + + The standard drill in this sort of situation is to fire up gdb on the + signal thread, which, in this case, was pid 1935. In another window, + I run gdb and attach pid 1935. + + + + + ~/linux/2.3.26/um 1016: gdb linux + GNU gdb 4.17.0.11 with Linux support + Copyright 1998 Free Software Foundation, Inc. + GDB is free software, covered by the GNU General Public License, and you are + welcome to change it and/or distribute copies of it under certain conditions. + Type "show copying" to see the conditions. + There is absolutely no warranty for GDB. Type "show warranty" for details. + This GDB was configured as "i386-redhat-linux"... + + (gdb) att 1935 + Attaching to program `/home/dike/linux/2.3.26/um/linux', Pid 1935 + 0x100756d9 in __wait4 () + + + + + + + Let's see what's currently running: + + + + (gdb) p current_task.pid + $1 = 0 + + + + + + It's the idle thread, which means that fsck went to sleep for some + reason and never woke up. + + + Let's guess that the last process in the process list is fsck: + + + + (gdb) p current_task.prev_task.comm + $13 = "fsck.ext2\000\000\000\000\000\000" + + + + + + It is, so let's see what it thinks it's up to: + + + + (gdb) p current_task.prev_task.thread + $14 = {extern_pid = 1980, tracing = 0, want_tracing = 0, forking = 0, + kernel_stack_page = 0, signal_stack = 1342627840, syscall = {id = 4, args = { + 3, 134973440, 1024, 0, 1024}, have_result = 0, result = 50590720}, + request = {op = 2, u = {exec = {ip = 1350467584, sp = 2952789424}, fork = { + regs = {1350467584, 2952789424, 0 }, sigstack = 0, + pid = 0}, switch_to = 0x507e8000, thread = {proc = 0x507e8000, + arg = 0xaffffdb0, flags = 0, new_pid = 0}, input_request = { + op = 1350467584, fd = -1342177872, proc = 0, pid = 0}}}} + + + + + + The interesting things here are the fact that its .thread.syscall.id + is __NR_write (see the big switch in arch/um/kernel/syscall_kern.c or + the defines in include/asm-um/arch/unistd.h), and that it never + returned. Also, its .request.op is OP_SWITCH (see + arch/um/include/user_util.h). These mean that it went into a write, + and, for some reason, called schedule(). + + + The fact that it never returned from write means that its stack should + be fairly interesting. Its pid is 1980 (.thread.extern_pid). That + process is being ptraced by the signal thread, so it must be detached + before gdb can attach it: + + + + + + + + + + + (gdb) call detach(1980) + + Program received signal SIGSEGV, Segmentation fault. + + The program being debugged stopped while in a function called from GDB. + When the function (detach) is done executing, GDB will silently + stop (instead of continuing to evaluate the expression containing + the function call). + (gdb) call detach(1980) + $15 = 0 + + + + + + The first detach segfaults for some reason, and the second one + succeeds. + + + Now I detach from the signal thread, attach to the fsck thread, and + look at its stack: + + + (gdb) det + Detaching from program: /home/dike/linux/2.3.26/um/linux Pid 1935 + (gdb) att 1980 + Attaching to program `/home/dike/linux/2.3.26/um/linux', Pid 1980 + 0x10070451 in __kill () + (gdb) bt + #0 0x10070451 in __kill () + #1 0x10068ccd in usr1_pid (pid=1980) at process.c:30 + #2 0x1006a03f in _switch_to (prev=0x50072000, next=0x507e8000) + at process_kern.c:156 + #3 0x1006a052 in switch_to (prev=0x50072000, next=0x507e8000, last=0x50072000) + at process_kern.c:161 + #4 0x10001d12 in schedule () at sched.c:777 + #5 0x1006a744 in __down (sem=0x507d241c) at semaphore.c:71 + #6 0x1006aa10 in __down_failed () at semaphore.c:157 + #7 0x1006c5d8 in segv_handler (sc=0x5006e940) at trap_user.c:174 + #8 0x1006c5ec in kern_segv_handler (sig=11) at trap_user.c:182 + #9 + #10 0x10155404 in errno () + #11 0x1006c0aa in segv (address=1342179328, is_write=2) at trap_kern.c:50 + #12 0x1006c5d8 in segv_handler (sc=0x5006eaf8) at trap_user.c:174 + #13 0x1006c5ec in kern_segv_handler (sig=11) at trap_user.c:182 + #14 + #15 0xc0fd in ?? () + #16 0x10016647 in sys_write (fd=3, + buf=0x80b8800
, count=1024) + at read_write.c:159 + #17 0x1006d5b3 in execute_syscall (syscall=4, args=0x5006ef08) + at syscall_kern.c:254 + #18 0x1006af87 in really_do_syscall (sig=12) at syscall_user.c:35 + #19 + #20 0x400dc8b0 in ?? () + + + + + + The interesting things here are : + + +o There are two segfaults on this stack (frames 9 and 14) + + +o The first faulting address (frame 11) is 0x50000800 + + (gdb) p (void *)1342179328 + $16 = (void *) 0x50000800 + + + + + + The initial faulting address is interesting because it is on the idle + thread's stack. I had been seeing the idle thread segfault for no + apparent reason, and the cause looked like stack corruption. In hopes + of catching the culprit in the act, I had turned off all protections + to that stack while the idle thread wasn't running. This apparently + tripped that trap. + + + However, the more immediate problem is that second segfault and I'm + going to concentrate on that. First, I want to see where the fault + happened, so I have to go look at the sigcontent struct in frame 8: + + + + (gdb) up + #1 0x10068ccd in usr1_pid (pid=1980) at process.c:30 + 30 kill(pid, SIGUSR1); + (gdb) + #2 0x1006a03f in _switch_to (prev=0x50072000, next=0x507e8000) + at process_kern.c:156 + 156 usr1_pid(getpid()); + (gdb) + #3 0x1006a052 in switch_to (prev=0x50072000, next=0x507e8000, last=0x50072000) + at process_kern.c:161 + 161 _switch_to(prev, next); + (gdb) + #4 0x10001d12 in schedule () at sched.c:777 + 777 switch_to(prev, next, prev); + (gdb) + #5 0x1006a744 in __down (sem=0x507d241c) at semaphore.c:71 + 71 schedule(); + (gdb) + #6 0x1006aa10 in __down_failed () at semaphore.c:157 + 157 } + (gdb) + #7 0x1006c5d8 in segv_handler (sc=0x5006e940) at trap_user.c:174 + 174 segv(sc->cr2, sc->err & 2); + (gdb) + #8 0x1006c5ec in kern_segv_handler (sig=11) at trap_user.c:182 + 182 segv_handler(sc); + (gdb) p *sc + Cannot access memory at address 0x0. + + + + + That's not very useful, so I'll try a more manual method: + + + (gdb) p *((struct sigcontext *) (&sig + 1)) + $19 = {gs = 0, __gsh = 0, fs = 0, __fsh = 0, es = 43, __esh = 0, ds = 43, + __dsh = 0, edi = 1342179328, esi = 1350378548, ebp = 1342630440, + esp = 1342630420, ebx = 1348150624, edx = 1280, ecx = 0, eax = 0, + trapno = 14, err = 4, eip = 268480945, cs = 35, __csh = 0, eflags = 66118, + esp_at_signal = 1342630420, ss = 43, __ssh = 0, fpstate = 0x0, oldmask = 0, + cr2 = 1280} + + + + The ip is in handle_mm_fault: + + + (gdb) p (void *)268480945 + $20 = (void *) 0x1000b1b1 + (gdb) i sym $20 + handle_mm_fault + 57 in section .text + + + + + + Specifically, it's in pte_alloc: + + + (gdb) i line *$20 + Line 124 of "/home/dike/linux/2.3.26/um/include/asm/pgalloc.h" + starts at address 0x1000b1b1 + and ends at 0x1000b1b7 . + + + + + + To find where in handle_mm_fault this is, I'll jump forward in the + code until I see an address in that procedure: + + + + (gdb) i line *0x1000b1c0 + Line 126 of "/home/dike/linux/2.3.26/um/include/asm/pgalloc.h" + starts at address 0x1000b1b7 + and ends at 0x1000b1c3 . + (gdb) i line *0x1000b1d0 + Line 131 of "/home/dike/linux/2.3.26/um/include/asm/pgalloc.h" + starts at address 0x1000b1d0 + and ends at 0x1000b1da . + (gdb) i line *0x1000b1e0 + Line 61 of "/home/dike/linux/2.3.26/um/include/asm/pgalloc.h" + starts at address 0x1000b1da + and ends at 0x1000b1e1 . + (gdb) i line *0x1000b1f0 + Line 134 of "/home/dike/linux/2.3.26/um/include/asm/pgalloc.h" + starts at address 0x1000b1f0 + and ends at 0x1000b200 . + (gdb) i line *0x1000b200 + Line 135 of "/home/dike/linux/2.3.26/um/include/asm/pgalloc.h" + starts at address 0x1000b200 + and ends at 0x1000b208 . + (gdb) i line *0x1000b210 + Line 139 of "/home/dike/linux/2.3.26/um/include/asm/pgalloc.h" + starts at address 0x1000b210 + and ends at 0x1000b219 . + (gdb) i line *0x1000b220 + Line 1168 of "memory.c" starts at address 0x1000b21e + and ends at 0x1000b222 . + + + + + + Something is apparently wrong with the page tables or vma_structs, so + lets go back to frame 11 and have a look at them: + + + + #11 0x1006c0aa in segv (address=1342179328, is_write=2) at trap_kern.c:50 + 50 handle_mm_fault(current, vma, address, is_write); + (gdb) call pgd_offset_proc(vma->vm_mm, address) + $22 = (pgd_t *) 0x80a548c + + + + + + That's pretty bogus. Page tables aren't supposed to be in process + text or data areas. Let's see what's in the vma: + + + (gdb) p *vma + $23 = {vm_mm = 0x507d2434, vm_start = 0, vm_end = 134512640, + vm_next = 0x80a4f8c, vm_page_prot = {pgprot = 0}, vm_flags = 31200, + vm_avl_height = 2058, vm_avl_left = 0x80a8c94, vm_avl_right = 0x80d1000, + vm_next_share = 0xaffffdb0, vm_pprev_share = 0xaffffe63, + vm_ops = 0xaffffe7a, vm_pgoff = 2952789626, vm_file = 0xafffffec, + vm_private_data = 0x62} + (gdb) p *vma.vm_mm + $24 = {mmap = 0x507d2434, mmap_avl = 0x0, mmap_cache = 0x8048000, + pgd = 0x80a4f8c, mm_users = {counter = 0}, mm_count = {counter = 134904288}, + map_count = 134909076, mmap_sem = {count = {counter = 135073792}, + sleepers = -1342177872, wait = {lock = , + task_list = {next = 0xaffffe63, prev = 0xaffffe7a}, + __magic = -1342177670, __creator = -1342177300}, __magic = 98}, + page_table_lock = {}, context = 138, start_code = 0, end_code = 0, + start_data = 0, end_data = 0, start_brk = 0, brk = 0, start_stack = 0, + arg_start = 0, arg_end = 0, env_start = 0, env_end = 0, rss = 1350381536, + total_vm = 0, locked_vm = 0, def_flags = 0, cpu_vm_mask = 0, swap_cnt = 0, + swap_address = 0, segments = 0x0} + + + + + + This also pretty bogus. With all of the 0x80xxxxx and 0xaffffxxx + addresses, this is looking like a stack was plonked down on top of + these structures. Maybe it's a stack overflow from the next page: + + + + (gdb) p vma + $25 = (struct vm_area_struct *) 0x507d2434 + + + + + + That's towards the lower quarter of the page, so that would have to + have been pretty heavy stack overflow: + + + + + + + + + + + + + + + (gdb) x/100x $25 + 0x507d2434: 0x507d2434 0x00000000 0x08048000 0x080a4f8c + 0x507d2444: 0x00000000 0x080a79e0 0x080a8c94 0x080d1000 + 0x507d2454: 0xaffffdb0 0xaffffe63 0xaffffe7a 0xaffffe7a + 0x507d2464: 0xafffffec 0x00000062 0x0000008a 0x00000000 + 0x507d2474: 0x00000000 0x00000000 0x00000000 0x00000000 + 0x507d2484: 0x00000000 0x00000000 0x00000000 0x00000000 + 0x507d2494: 0x00000000 0x00000000 0x507d2fe0 0x00000000 + 0x507d24a4: 0x00000000 0x00000000 0x00000000 0x00000000 + 0x507d24b4: 0x00000000 0x00000000 0x00000000 0x00000000 + 0x507d24c4: 0x00000000 0x00000000 0x00000000 0x00000000 + 0x507d24d4: 0x00000000 0x00000000 0x00000000 0x00000000 + 0x507d24e4: 0x00000000 0x00000000 0x00000000 0x00000000 + 0x507d24f4: 0x00000000 0x00000000 0x00000000 0x00000000 + 0x507d2504: 0x00000000 0x00000000 0x00000000 0x00000000 + 0x507d2514: 0x00000000 0x00000000 0x00000000 0x00000000 + 0x507d2524: 0x00000000 0x00000000 0x00000000 0x00000000 + 0x507d2534: 0x00000000 0x00000000 0x507d25dc 0x00000000 + 0x507d2544: 0x00000000 0x00000000 0x00000000 0x00000000 + 0x507d2554: 0x00000000 0x00000000 0x00000000 0x00000000 + 0x507d2564: 0x00000000 0x00000000 0x00000000 0x00000000 + 0x507d2574: 0x00000000 0x00000000 0x00000000 0x00000000 + 0x507d2584: 0x00000000 0x00000000 0x00000000 0x00000000 + 0x507d2594: 0x00000000 0x00000000 0x00000000 0x00000000 + 0x507d25a4: 0x00000000 0x00000000 0x00000000 0x00000000 + 0x507d25b4: 0x00000000 0x00000000 0x00000000 0x00000000 + + + + + + It's not stack overflow. The only "stack-like" piece of this data is + the vma_struct itself. + + + At this point, I don't see any avenues to pursue, so I just have to + admit that I have no idea what's going on. What I will do, though, is + stick a trap on the segfault handler which will stop if it sees any + writes to the idle thread's stack. That was the thing that happened + first, and it may be that if I can catch it immediately, what's going + on will be somewhat clearer. + + + 1122..22.. EEppiissooddee 22:: TThhee ccaassee ooff tthhee hhuunngg ffsscckk + + After setting a trap in the SEGV handler for accesses to the signal + thread's stack, I reran the kernel. + + + fsck hung again, this time by hitting the trap: + + + + + + + + + + + + + + + + + Setting hostname uml [ OK ] + Checking root filesystem + /dev/fhd0 contains a file system with errors, check forced. + Error reading block 86894 (Attempt to read block from filesystem resulted in short read) while reading indirect blocks of inode 19780. + + /dev/fhd0: UNEXPECTED INCONSISTENCY; RUN fsck MANUALLY. + (i.e., without -a or -p options) + [ FAILED ] + + *** An error occurred during the file system check. + *** Dropping you to a shell; the system will reboot + *** when you leave the shell. + Give root password for maintenance + (or type Control-D for normal startup): + + [root@uml /root]# fsck -y /dev/fhd0 + fsck -y /dev/fhd0 + Parallelizing fsck version 1.14 (9-Jan-1999) + e2fsck 1.14, 9-Jan-1999 for EXT2 FS 0.5b, 95/08/09 + /dev/fhd0 contains a file system with errors, check forced. + Pass 1: Checking inodes, blocks, and sizes + Error reading block 86894 (Attempt to read block from filesystem resulted in short read) while reading indirect blocks of inode 19780. Ignore error? yes + + Pass 2: Checking directory structure + Error reading block 49405 (Attempt to read block from filesystem resulted in short read). Ignore error? yes + + Directory inode 11858, block 0, offset 0: directory corrupted + Salvage? yes + + Missing '.' in directory inode 11858. + Fix? yes + + Missing '..' in directory inode 11858. + Fix? yes + + Untested (4127) [100fe44c]: trap_kern.c line 31 + + + + + + I need to get the signal thread to detach from pid 4127 so that I can + attach to it with gdb. This is done by sending it a SIGUSR1, which is + caught by the signal thread, which detaches the process: + + + kill -USR1 4127 + + + + + + Now I can run gdb on it: + + + + + + + + + + + + + + ~/linux/2.3.26/um 1034: gdb linux + GNU gdb 4.17.0.11 with Linux support + Copyright 1998 Free Software Foundation, Inc. + GDB is free software, covered by the GNU General Public License, and you are + welcome to change it and/or distribute copies of it under certain conditions. + Type "show copying" to see the conditions. + There is absolutely no warranty for GDB. Type "show warranty" for details. + This GDB was configured as "i386-redhat-linux"... + (gdb) att 4127 + Attaching to program `/home/dike/linux/2.3.26/um/linux', Pid 4127 + 0x10075891 in __libc_nanosleep () + + + + + + The backtrace shows that it was in a write and that the fault address + (address in frame 3) is 0x50000800, which is right in the middle of + the signal thread's stack page: + + + (gdb) bt + #0 0x10075891 in __libc_nanosleep () + #1 0x1007584d in __sleep (seconds=1000000) + at ../sysdeps/unix/sysv/linux/sleep.c:78 + #2 0x1006ce9a in stop () at user_util.c:191 + #3 0x1006bf88 in segv (address=1342179328, is_write=2) at trap_kern.c:31 + #4 0x1006c628 in segv_handler (sc=0x5006eaf8) at trap_user.c:174 + #5 0x1006c63c in kern_segv_handler (sig=11) at trap_user.c:182 + #6 + #7 0xc0fd in ?? () + #8 0x10016647 in sys_write (fd=3, buf=0x80b8800 "R.", count=1024) + at read_write.c:159 + #9 0x1006d603 in execute_syscall (syscall=4, args=0x5006ef08) + at syscall_kern.c:254 + #10 0x1006af87 in really_do_syscall (sig=12) at syscall_user.c:35 + #11 + #12 0x400dc8b0 in ?? () + #13 + #14 0x400dc8b0 in ?? () + #15 0x80545fd in ?? () + #16 0x804daae in ?? () + #17 0x8054334 in ?? () + #18 0x804d23e in ?? () + #19 0x8049632 in ?? () + #20 0x80491d2 in ?? () + #21 0x80596b5 in ?? () + (gdb) p (void *)1342179328 + $3 = (void *) 0x50000800 + + + + + + Going up the stack to the segv_handler frame and looking at where in + the code the access happened shows that it happened near line 110 of + block_dev.c: + + + + + + + + + + (gdb) up + #1 0x1007584d in __sleep (seconds=1000000) + at ../sysdeps/unix/sysv/linux/sleep.c:78 + ../sysdeps/unix/sysv/linux/sleep.c:78: No such file or directory. + (gdb) + #2 0x1006ce9a in stop () at user_util.c:191 + 191 while(1) sleep(1000000); + (gdb) + #3 0x1006bf88 in segv (address=1342179328, is_write=2) at trap_kern.c:31 + 31 KERN_UNTESTED(); + (gdb) + #4 0x1006c628 in segv_handler (sc=0x5006eaf8) at trap_user.c:174 + 174 segv(sc->cr2, sc->err & 2); + (gdb) p *sc + $1 = {gs = 0, __gsh = 0, fs = 0, __fsh = 0, es = 43, __esh = 0, ds = 43, + __dsh = 0, edi = 1342179328, esi = 134973440, ebp = 1342631484, + esp = 1342630864, ebx = 256, edx = 0, ecx = 256, eax = 1024, trapno = 14, + err = 6, eip = 268550834, cs = 35, __csh = 0, eflags = 66070, + esp_at_signal = 1342630864, ss = 43, __ssh = 0, fpstate = 0x0, oldmask = 0, + cr2 = 1342179328} + (gdb) p (void *)268550834 + $2 = (void *) 0x1001c2b2 + (gdb) i sym $2 + block_write + 1090 in section .text + (gdb) i line *$2 + Line 209 of "/home/dike/linux/2.3.26/um/include/asm/arch/string.h" + starts at address 0x1001c2a1 + and ends at 0x1001c2bf . + (gdb) i line *0x1001c2c0 + Line 110 of "block_dev.c" starts at address 0x1001c2bf + and ends at 0x1001c2e3 . + + + + + + Looking at the source shows that the fault happened during a call to + copy_to_user to copy the data into the kernel: + + + 107 count -= chars; + 108 copy_from_user(p,buf,chars); + 109 p += chars; + 110 buf += chars; + + + + + + p is the pointer which must contain 0x50000800, since buf contains + 0x80b8800 (frame 8 above). It is defined as: + + + p = offset + bh->b_data; + + + + + + I need to figure out what bh is, and it just so happens that bh is + passed as an argument to mark_buffer_uptodate and mark_buffer_dirty a + few lines later, so I do a little disassembly: + + + + + (gdb) disas 0x1001c2bf 0x1001c2e0 + Dump of assembler code from 0x1001c2bf to 0x1001c2d0: + 0x1001c2bf : addl %eax,0xc(%ebp) + 0x1001c2c2 : movl 0xfffffdd4(%ebp),%edx + 0x1001c2c8 : btsl $0x0,0x18(%edx) + 0x1001c2cd : btsl $0x1,0x18(%edx) + 0x1001c2d2 : sbbl %ecx,%ecx + 0x1001c2d4 : testl %ecx,%ecx + 0x1001c2d6 : jne 0x1001c2e3 + 0x1001c2d8 : pushl $0x0 + 0x1001c2da : pushl %edx + 0x1001c2db : call 0x1001819c <__mark_buffer_dirty> + End of assembler dump. + + + + + + At that point, bh is in %edx (address 0x1001c2da), which is calculated + at 0x1001c2c2 as %ebp + 0xfffffdd4, so I figure exactly what that is, + taking %ebp from the sigcontext_struct above: + + + (gdb) p (void *)1342631484 + $5 = (void *) 0x5006ee3c + (gdb) p 0x5006ee3c+0xfffffdd4 + $6 = 1342630928 + (gdb) p (void *)$6 + $7 = (void *) 0x5006ec10 + (gdb) p *((void **)$7) + $8 = (void *) 0x50100200 + + + + + + Now, I look at the structure to see what's in it, and particularly, + what its b_data field contains: + + + (gdb) p *((struct buffer_head *)0x50100200) + $13 = {b_next = 0x50289380, b_blocknr = 49405, b_size = 1024, b_list = 0, + b_dev = 15872, b_count = {counter = 1}, b_rdev = 15872, b_state = 24, + b_flushtime = 0, b_next_free = 0x501001a0, b_prev_free = 0x50100260, + b_this_page = 0x501001a0, b_reqnext = 0x0, b_pprev = 0x507fcf58, + b_data = 0x50000800 "", b_page = 0x50004000, + b_end_io = 0x10017f60 , b_dev_id = 0x0, + b_rsector = 98810, b_wait = {lock = , + task_list = {next = 0x50100248, prev = 0x50100248}, __magic = 1343226448, + __creator = 0}, b_kiobuf = 0x0} + + + + + + The b_data field is indeed 0x50000800, so the question becomes how + that happened. The rest of the structure looks fine, so this probably + is not a case of data corruption. It happened on purpose somehow. + + + The b_page field is a pointer to the page_struct representing the + 0x50000000 page. Looking at it shows the kernel's idea of the state + of that page: + + + + (gdb) p *$13.b_page + $17 = {list = {next = 0x50004a5c, prev = 0x100c5174}, mapping = 0x0, + index = 0, next_hash = 0x0, count = {counter = 1}, flags = 132, lru = { + next = 0x50008460, prev = 0x50019350}, wait = { + lock = , task_list = {next = 0x50004024, + prev = 0x50004024}, __magic = 1342193708, __creator = 0}, + pprev_hash = 0x0, buffers = 0x501002c0, virtual = 1342177280, + zone = 0x100c5160} + + + + + + Some sanity-checking: the virtual field shows the "virtual" address of + this page, which in this kernel is the same as its "physical" address, + and the page_struct itself should be mem_map[0], since it represents + the first page of memory: + + + + (gdb) p (void *)1342177280 + $18 = (void *) 0x50000000 + (gdb) p mem_map + $19 = (mem_map_t *) 0x50004000 + + + + + + These check out fine. + + + Now to check out the page_struct itself. In particular, the flags + field shows whether the page is considered free or not: + + + (gdb) p (void *)132 + $21 = (void *) 0x84 + + + + + + The "reserved" bit is the high bit, which is definitely not set, so + the kernel considers the signal stack page to be free and available to + be used. + + + At this point, I jump to conclusions and start looking at my early + boot code, because that's where that page is supposed to be reserved. + + + In my setup_arch procedure, I have the following code which looks just + fine: + + + + bootmap_size = init_bootmem(start_pfn, end_pfn - start_pfn); + free_bootmem(__pa(low_physmem) + bootmap_size, high_physmem - low_physmem); + + + + + + Two stack pages have already been allocated, and low_physmem points to + the third page, which is the beginning of free memory. + The init_bootmem call declares the entire memory to the boot memory + manager, which marks it all reserved. The free_bootmem call frees up + all of it, except for the first two pages. This looks correct to me. + + + So, I decide to see init_bootmem run and make sure that it is marking + those first two pages as reserved. I never get that far. + + + Stepping into init_bootmem, and looking at bootmem_map before looking + at what it contains shows the following: + + + + (gdb) p bootmem_map + $3 = (void *) 0x50000000 + + + + + + Aha! The light dawns. That first page is doing double duty as a + stack and as the boot memory map. The last thing that the boot memory + manager does is to free the pages used by its memory map, so this page + is getting freed even its marked as reserved. + + + The fix was to initialize the boot memory manager before allocating + those two stack pages, and then allocate them through the boot memory + manager. After doing this, and fixing a couple of subsequent buglets, + the stack corruption problem disappeared. + + + + + + 1133.. WWhhaatt ttoo ddoo wwhheenn UUMMLL ddooeessnn''tt wwoorrkk + + + + + 1133..11.. SSttrraannggee ccoommppiillaattiioonn eerrrroorrss wwhheenn yyoouu bbuuiilldd ffrroomm ssoouurrccee + + As of test11, it is necessary to have "ARCH=um" in the environment or + on the make command line for all steps in building UML, including + clean, distclean, or mrproper, config, menuconfig, or xconfig, dep, + and linux. If you forget for any of them, the i386 build seems to + contaminate the UML build. If this happens, start from scratch with + + + host% + make mrproper ARCH=um + + + + + and repeat the build process with ARCH=um on all the steps. + + + See ``Compiling the kernel and modules'' for more details. + + + Another cause of strange compilation errors is building UML in + /usr/src/linux. If you do this, the first thing you need to do is + clean up the mess you made. The /usr/src/linux/asm link will now + point to /usr/src/linux/asm-um. Make it point back to + /usr/src/linux/asm-i386. Then, move your UML pool someplace else and + build it there. Also see below, where a more specific set of symptoms + is described. + + + + 1133..33.. AA vvaarriieettyy ooff ppaanniiccss aanndd hhaannggss wwiitthh //ttmmpp oonn aa rreeiisseerrffss ffiilleessyyss-- + tteemm + + I saw this on reiserfs 3.5.21 and it seems to be fixed in 3.5.27. + Panics preceded by + + + Detaching pid nnnn + + + + are diagnostic of this problem. This is a reiserfs bug which causes a + thread to occasionally read stale data from a mmapped page shared with + another thread. The fix is to upgrade the filesystem or to have /tmp + be an ext2 filesystem. + + + + 1133..44.. TThhee ccoommppiillee ffaaiillss wwiitthh eerrrroorrss aabboouutt ccoonnfflliiccttiinngg ttyyppeess ffoorr + ''ooppeenn'',, ''dduupp'',, aanndd ''wwaaiittppiidd'' + + This happens when you build in /usr/src/linux. The UML build makes + the include/asm link point to include/asm-um. /usr/include/asm points + to /usr/src/linux/include/asm, so when that link gets moved, files + which need to include the asm-i386 versions of headers get the + incompatible asm-um versions. The fix is to move the include/asm link + back to include/asm-i386 and to do UML builds someplace else. + + + + 1133..55.. UUMMLL ddooeessnn''tt wwoorrkk wwhheenn //ttmmpp iiss aann NNFFSS ffiilleessyysstteemm + + This seems to be a similar situation with the ReiserFS problem above. + Some versions of NFS seems not to handle mmap correctly, which UML + depends on. The workaround is have /tmp be a non-NFS directory. + + + 1133..66.. UUMMLL hhaannggss oonn bboooott wwhheenn ccoommppiilleedd wwiitthh ggpprrooff ssuuppppoorrtt + + If you build UML with gprof support and, early in the boot, it does + this + + + kernel BUG at page_alloc.c:100! + + + + + you have a buggy gcc. You can work around the problem by removing + UM_FASTCALL from CFLAGS in arch/um/Makefile-i386. This will open up + another bug, but that one is fairly hard to reproduce. + + + + 1133..77.. ssyyssllooggdd ddiieess wwiitthh aa SSIIGGTTEERRMM oonn ssttaarrttuupp + + The exact boot error depends on the distribution that you're booting, + but Debian produces this: + + + /etc/rc2.d/S10sysklogd: line 49: 93 Terminated + start-stop-daemon --start --quiet --exec /sbin/syslogd -- $SYSLOGD + + + + + This is a syslogd bug. There's a race between a parent process + installing a signal handler and its child sending the signal. See + this uml-devel post for the details. + + + + 1133..88.. TTUUNN//TTAAPP nneettwwoorrkkiinngg ddooeessnn''tt wwoorrkk oonn aa 22..44 hhoosstt + + There are a couple of problems which were + name="pointed + out"> by Tim Robinson + + +o It doesn't work on hosts running 2.4.7 (or thereabouts) or earlier. + The fix is to upgrade to something more recent and then read the + next item. + + +o If you see + + + File descriptor in bad state + + + + when you bring up the device inside UML, you have a header mismatch + between the original kernel and the upgraded one. Make /usr/src/linux + point at the new headers. This will only be a problem if you build + uml_net yourself. + + + + 1133..99.. YYoouu ccaann nneettwwoorrkk ttoo tthhee hhoosstt bbuutt nnoott ttoo ootthheerr mmaacchhiinneess oonn tthhee + nneett + + If you can connect to the host, and the host can connect to UML, but + you cannot connect to any other machines, then you may need to enable + IP Masquerading on the host. Usually this is only experienced when + using private IP addresses (192.168.x.x or 10.x.x.x) for host/UML + networking, rather than the public address space that your host is + connected to. UML does not enable IP Masquerading, so you will need + to create a static rule to enable it: + + + host% + iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE + + + + + Replace eth0 with the interface that you use to talk to the rest of + the world. + + + Documentation on IP Masquerading, and SNAT, can be found at + www.netfilter.org . + + + If you can reach the local net, but not the outside Internet, then + that is usually a routing problem. The UML needs a default route: + + + UML# + route add default gw gateway IP + + + + + The gateway IP can be any machine on the local net that knows how to + reach the outside world. Usually, this is the host or the local net- + work's gateway. + + + Occasionally, we hear from someone who can reach some machines, but + not others on the same net, or who can reach some ports on other + machines, but not others. These are usually caused by strange + firewalling somewhere between the UML and the other box. You track + this down by running tcpdump on every interface the packets travel + over and see where they disappear. When you find a machine that takes + the packets in, but does not send them onward, that's the culprit. + + + + 1133..1100.. II hhaavvee nnoo rroooott aanndd II wwaanntt ttoo ssccrreeaamm + + Thanks to Birgit Wahlich for telling me about this strange one. It + turns out that there's a limit of six environment variables on the + kernel command line. When that limit is reached or exceeded, argument + processing stops, which means that the 'root=' argument that UML + usually adds is not seen. So, the filesystem has no idea what the + root device is, so it panics. + + + The fix is to put less stuff on the command line. Glomming all your + setup variables into one is probably the best way to go. + + + + 1133..1111.. UUMMLL bbuuiilldd ccoonnfflliicctt bbeettwweeeenn ppttrraaccee..hh aanndd uuccoonntteexxtt..hh + + On some older systems, /usr/include/asm/ptrace.h and + /usr/include/sys/ucontext.h define the same names. So, when they're + included together, the defines from one completely mess up the parsing + of the other, producing errors like: + /usr/include/sys/ucontext.h:47: parse error before + `10' + + + + + plus a pile of warnings. + + + This is a libc botch, which has since been fixed, and I don't see any + way around it besides upgrading. + + + + 1133..1122.. TThhee UUMMLL BBooggooMMiippss iiss eexxaaccttllyy hhaallff tthhee hhoosstt''ss BBooggooMMiippss + + On i386 kernels, there are two ways of running the loop that is used + to calculate the BogoMips rating, using the TSC if it's there or using + a one-instruction loop. The TSC produces twice the BogoMips as the + loop. UML uses the loop, since it has nothing resembling a TSC, and + will get almost exactly the same BogoMips as a host using the loop. + However, on a host with a TSC, its BogoMips will be double the loop + BogoMips, and therefore double the UML BogoMips. + + + + 1133..1133.. WWhheenn yyoouu rruunn UUMMLL,, iitt iimmmmeeddiiaatteellyy sseeggffaauullttss + + If the host is configured with the 2G/2G address space split, that's + why. See ``UML on 2G/2G hosts'' for the details on getting UML to + run on your host. + + + + 1133..1144.. xxtteerrmmss aappppeeaarr,, tthheenn iimmmmeeddiiaatteellyy ddiissaappppeeaarr + + If you're running an up to date kernel with an old release of + uml_utilities, the port-helper program will not work properly, so + xterms will exit straight after they appear. The solution is to + upgrade to the latest release of uml_utilities. Usually this problem + occurs when you have installed a packaged release of UML then compiled + your own development kernel without upgrading the uml_utilities from + the source distribution. + + + + 1133..1155.. AAnnyy ootthheerr ppaanniicc,, hhaanngg,, oorr ssttrraannggee bbeehhaavviioorr + + If you're seeing truly strange behavior, such as hangs or panics that + happen in random places, or you try running the debugger to see what's + happening and it acts strangely, then it could be a problem in the + host kernel. If you're not running a stock Linus or -ac kernel, then + try that. An early version of the preemption patch and a 2.4.10 SuSE + kernel have caused very strange problems in UML. + + + Otherwise, let me know about it. Send a message to one of the UML + mailing lists - either the developer list - user-mode-linux-devel at + lists dot sourceforge dot net (subscription info) or the user list - + user-mode-linux-user at lists dot sourceforge do net (subscription + info), whichever you prefer. Don't assume that everyone knows about + it and that a fix is imminent. + + + If you want to be super-helpful, read ``Diagnosing Problems'' and + follow the instructions contained therein. + 1144.. DDiiaaggnnoossiinngg PPrroobblleemmss + + + If you get UML to crash, hang, or otherwise misbehave, you should + report this on one of the project mailing lists, either the developer + list - user-mode-linux-devel at lists dot sourceforge dot net + (subscription info) or the user list - user-mode-linux-user at lists + dot sourceforge dot net (subscription info). When you do, it is + likely that I will want more information. So, it would be helpful to + read the stuff below, do whatever is applicable in your case, and + report the results to the list. + + + For any diagnosis, you're going to need to build a debugging kernel. + The binaries from this site aren't debuggable. If you haven't done + this before, read about ``Compiling the kernel and modules'' and + ``Kernel debugging'' UML first. + + + 1144..11.. CCaassee 11 :: NNoorrmmaall kkeerrnneell ppaanniiccss + + The most common case is for a normal thread to panic. To debug this, + you will need to run it under the debugger (add 'debug' to the command + line). An xterm will start up with gdb running inside it. Continue + it when it stops in start_kernel and make it crash. Now ^C gdb and + + + If the panic was a "Kernel mode fault", then there will be a segv + frame on the stack and I'm going to want some more information. The + stack might look something like this: + + + (UML gdb) backtrace + #0 0x1009bf76 in __sigprocmask (how=1, set=0x5f347940, oset=0x0) + at ../sysdeps/unix/sysv/linux/sigprocmask.c:49 + #1 0x10091411 in change_sig (signal=10, on=1) at process.c:218 + #2 0x10094785 in timer_handler (sig=26) at time_kern.c:32 + #3 0x1009bf38 in __restore () + at ../sysdeps/unix/sysv/linux/i386/sigaction.c:125 + #4 0x1009534c in segv (address=8, ip=268849158, is_write=2, is_user=0) + at trap_kern.c:66 + #5 0x10095c04 in segv_handler (sig=11) at trap_user.c:285 + #6 0x1009bf38 in __restore () + + + + + I'm going to want to see the symbol and line information for the value + of ip in the segv frame. In this case, you would do the following: + + + (UML gdb) i sym 268849158 + + + + + and + + + (UML gdb) i line *268849158 + + + + + The reason for this is the __restore frame right above the segv_han- + dler frame is hiding the frame that actually segfaulted. So, I have + to get that information from the faulting ip. + + + 1144..22.. CCaassee 22 :: TTrraacciinngg tthhrreeaadd ppaanniiccss + + The less common and more painful case is when the tracing thread + panics. In this case, the kernel debugger will be useless because it + needs a healthy tracing thread in order to work. The first thing to + do is get a backtrace from the tracing thread. This is done by + figuring out what its pid is, firing up gdb, and attaching it to that + pid. You can figure out the tracing thread pid by looking at the + first line of the console output, which will look like this: + + + tracing thread pid = 15851 + + + + + or by running ps on the host and finding the line that looks like + this: + + + jdike 15851 4.5 0.4 132568 1104 pts/0 S 21:34 0:05 ./linux [(tracing thread)] + + + + + If the panic was 'segfault in signals', then follow the instructions + above for collecting information about the location of the seg fault. + + + If the tracing thread flaked out all by itself, then send that + backtrace in and wait for our crack debugging team to fix the problem. + + + 1144..33.. CCaassee 33 :: TTrraacciinngg tthhrreeaadd ppaanniiccss ccaauusseedd bbyy ootthheerr tthhrreeaaddss + + However, there are cases where the misbehavior of another thread + caused the problem. The most common panic of this type is: + + + wait_for_stop failed to wait for to stop with + + + + + In this case, you'll need to get a backtrace from the process men- + tioned in the panic, which is complicated by the fact that the kernel + debugger is defunct and without some fancy footwork, another gdb can't + attach to it. So, this is how the fancy footwork goes: + + In a shell: + + + host% kill -STOP pid + + + + + Run gdb on the tracing thread as described in case 2 and do: + + + (host gdb) call detach(pid) + + + If you get a segfault, do it again. It always works the second time. + + Detach from the tracing thread and attach to that other thread: + + + (host gdb) detach + + + + + + + (host gdb) attach pid + + + + + If gdb hangs when attaching to that process, go back to a shell and + do: + + + host% + kill -CONT pid + + + + + And then get the backtrace: + + + (host gdb) backtrace + + + + + + 1144..44.. CCaassee 44 :: HHaannggss + + Hangs seem to be fairly rare, but they sometimes happen. When a hang + happens, we need a backtrace from the offending process. Run the + kernel debugger as described in case 1 and get a backtrace. If the + current process is not the idle thread, then send in the backtrace. + You can tell that it's the idle thread if the stack looks like this: + + + #0 0x100b1401 in __libc_nanosleep () + #1 0x100a2885 in idle_sleep (secs=10) at time.c:122 + #2 0x100a546f in do_idle () at process_kern.c:445 + #3 0x100a5508 in cpu_idle () at process_kern.c:471 + #4 0x100ec18f in start_kernel () at init/main.c:592 + #5 0x100a3e10 in start_kernel_proc (unused=0x0) at um_arch.c:71 + #6 0x100a383f in signal_tramp (arg=0x100a3dd8) at trap_user.c:50 + + + + + If this is the case, then some other process is at fault, and went to + sleep when it shouldn't have. Run ps on the host and figure out which + process should not have gone to sleep and stayed asleep. Then attach + to it with gdb and get a backtrace as described in case 3. + + + + + + + 1155.. TThhaannkkss + + + A number of people have helped this project in various ways, and this + page gives recognition where recognition is due. + + + If you're listed here and you would prefer a real link on your name, + or no link at all, instead of the despammed email address pseudo-link, + let me know. + + + If you're not listed here and you think maybe you should be, please + let me know that as well. I try to get everyone, but sometimes my + bookkeeping lapses and I forget about contributions. + + + 1155..11.. CCooddee aanndd DDooccuummeennttaattiioonn + + Rusty Russell - + + +o wrote the HOWTO + + +o prodded me into making this project official and putting it on + SourceForge + + +o came up with the way cool UML logo + + +o redid the config process + + + Peter Moulder - Fixed my config and build + processes, and added some useful code to the block driver + + + Bill Stearns - + + +o HOWTO updates + + +o lots of bug reports + + +o lots of testing + + +o dedicated a box (uml.ists.dartmouth.edu) to support UML development + + +o wrote the mkrootfs script, which allows bootable filesystems of + RPM-based distributions to be cranked out + + +o cranked out a large number of filesystems with said script + + + Jim Leu - Wrote the virtual ethernet driver + and associated usermode tools + + Lars Brinkhoff - Contributed the ptrace + proxy from his own project to allow easier + kernel debugging + + + Andrea Arcangeli - Redid some of the early boot + code so that it would work on machines with Large File Support + + + Chris Emerson - Did + the first UML port to Linux/ppc + + + Harald Welte - Wrote the multicast + transport for the network driver + + + Jorgen Cederlof - Added special file support to hostfs + + + Greg Lonnon - Changed the ubd driver + to allow it to layer a COW file on a shared read-only filesystem and + wrote the iomem emulation support + + + Henrik Nordstrom - Provided a variety + of patches, fixes, and clues + + + Lennert Buytenhek - Contributed various patches, a rewrite of the + network driver, the first implementation of the mconsole driver, and + did the bulk of the work needed to get SMP working again. + + + Yon Uriarte - Fixed the TUN/TAP network backend while I slept. + + + Adam Heath - Made a bunch of nice cleanups to the initialization code, + plus various other small patches. + + + Matt Zimmerman - Matt volunteered to be the UML Debian maintainer and + is doing a real nice job of it. He also noticed and fixed a number of + actually and potentially exploitable security holes in uml_net. Plus + the occasional patch. I like patches. + + + James McMechan - James seems to have taken over maintenance of the ubd + driver and is doing a nice job of it. + + + Chandan Kudige - wrote the umlgdb script which automates the reloading + of module symbols. + + + Steve Schmidtke - wrote the UML slirp transport and hostaudio drivers, + enabling UML processes to access audio devices on the host. He also + submitted patches for the slip transport and lots of other things. + + + David Coulson - + + +o Set up the usermodelinux.org site, + which is a great way of keeping the UML user community on top of + UML goings-on. + + +o Site documentation and updates + + +o Nifty little UML management daemon UMLd + + + +o Lots of testing and bug reports + + + + + 1155..22.. FFlluusshhiinngg oouutt bbuuggss + + + + +o Yuri Pudgorodsky + + +o Gerald Britton + + +o Ian Wehrman + + +o Gord Lamb + + +o Eugene Koontz + + +o John H. Hartman + + +o Anders Karlsson + + +o Daniel Phillips + + +o John Fremlin + + +o Rainer Burgstaller + + +o James Stevenson + + +o Matt Clay + + +o Cliff Jefferies + + +o Geoff Hoff + + +o Lennert Buytenhek + + +o Al Viro + + +o Frank Klingenhoefer + + +o Livio Baldini Soares + + +o Jon Burgess + + +o Petru Paler + + +o Paul + + +o Chris Reahard + + +o Sverker Nilsson + + +o Gong Su + + +o johan verrept + + +o Bjorn Eriksson + + +o Lorenzo Allegrucci + + +o Muli Ben-Yehuda + + +o David Mansfield + + +o Howard Goff + + +o Mike Anderson + + +o John Byrne + + +o Sapan J. Batia + + +o Iris Huang + + +o Jan Hudec + + +o Voluspa + + + + + 1155..33.. BBuugglleettss aanndd cclleeaann--uuppss + + + + +o Dave Zarzycki + + +o Adam Lazur + + +o Boria Feigin + + +o Brian J. Murrell + + +o JS + + +o Roman Zippel + + +o Wil Cooley + + +o Ayelet Shemesh + + +o Will Dyson + + +o Sverker Nilsson + + +o dvorak + + +o v.naga srinivas + + +o Shlomi Fish + + +o Roger Binns + + +o johan verrept + + +o MrChuoi + + +o Peter Cleve + + +o Vincent Guffens + + +o Nathan Scott + + +o Patrick Caulfield + + +o jbearce + + +o Catalin Marinas + + +o Shane Spencer + + +o Zou Min + + + +o Ryan Boder + + +o Lorenzo Colitti + + +o Gwendal Grignou + + +o Andre' Breiler + + +o Tsutomu Yasuda + + + + 1155..44.. CCaassee SSttuuddiieess + + + +o Jon Wright + + +o William McEwan + + +o Michael Richardson + + + + 1155..55.. OOtthheerr ccoonnttrriibbuuttiioonnss + + + Bill Carr made the Red Hat mkrootfs script + work with RH 6.2. + + Michael Jennings sent in some material which + is now gracing the top of the index page of this site. + + SGI (and more specifically Ralf Baechle ) gave me an account on oss.sgi.com + . The bandwidth there made it possible to + produce most of the filesystems available on the project download + page. + + Laurent Bonnaud took the old grotty + Debian filesystem that I've been distributing and updated it to 2.2. + It is now available by itself here. + + Rik van Riel gave me some ftp space on ftp.nl.linux.org so I can make + releases even when Sourceforge is broken. + + Rodrigo de Castro looked at my broken pte code and told me what was + wrong with it, letting me fix a long-standing (several weeks) and + serious set of bugs. + + Chris Reahard built a specialized root filesystem for running a DNS + server jailed inside UML. It's available from the download + page in the Jail + Filesystems section. + + + + + + + + + + + + -- cgit v0.10.2 From 570aa13a5dbea9b905b4cd6315aa6e1b3a9fd2f8 Mon Sep 17 00:00:00 2001 From: Rob Landley Date: Fri, 6 May 2011 09:23:23 -0700 Subject: Add a 00-INDEX file to Documentation/virtual Remove uml from the top level 00-INDEX file. Signed-off-by: Rob Landley Signed-off-by: Randy Dunlap diff --git a/Documentation/00-INDEX b/Documentation/00-INDEX index c17cd4b..1b777b9 100644 --- a/Documentation/00-INDEX +++ b/Documentation/00-INDEX @@ -328,8 +328,6 @@ sysrq.txt - info on the magic SysRq key. telephony/ - directory with info on telephony (e.g. voice over IP) support. -uml/ - - directory with information about User Mode Linux. unicode.txt - info on the Unicode character/font mapping used in Linux. unshare.txt diff --git a/Documentation/virtual/00-INDEX b/Documentation/virtual/00-INDEX new file mode 100644 index 0000000..fe0251c --- /dev/null +++ b/Documentation/virtual/00-INDEX @@ -0,0 +1,10 @@ +Virtualization support in the Linux kernel. + +00-INDEX + - this file. +kvm/ + - Kernel Virtual Machine. See also http://linux-kvm.org +lguest/ + - Extremely simple hypervisor for experimental/educational use. +uml/ + - User Mode Linux, builds/runs Linux kernel as a userspace program. -- cgit v0.10.2 From 61516587513c84ac26e68e3ab008dc6e965d0378 Mon Sep 17 00:00:00 2001 From: Rob Landley Date: Fri, 6 May 2011 09:27:36 -0700 Subject: Correct occurrences of - Documentation/kvm/ to Documentation/virtual/kvm - Documentation/uml/ to Documentation/virtual/uml - Documentation/lguest/ to Documentation/virtual/lguest throughout the kernel source tree. Signed-off-by: Rob Landley Signed-off-by: Randy Dunlap diff --git a/Documentation/virtual/kvm/review-checklist.txt b/Documentation/virtual/kvm/review-checklist.txt index 730475a..a850986 100644 --- a/Documentation/virtual/kvm/review-checklist.txt +++ b/Documentation/virtual/kvm/review-checklist.txt @@ -7,7 +7,7 @@ Review checklist for kvm patches 2. Patches should be against kvm.git master branch. 3. If the patch introduces or modifies a new userspace API: - - the API must be documented in Documentation/kvm/api.txt + - the API must be documented in Documentation/virtual/kvm/api.txt - the API must be discoverable using KVM_CHECK_EXTENSION 4. New state must include support for save/restore. diff --git a/Documentation/virtual/lguest/lguest.txt b/Documentation/virtual/lguest/lguest.txt index dad9997..bff0c55 100644 --- a/Documentation/virtual/lguest/lguest.txt +++ b/Documentation/virtual/lguest/lguest.txt @@ -74,7 +74,8 @@ Running Lguest: - Run an lguest as root: - Documentation/lguest/lguest 64 vmlinux --tunnet=192.168.19.1 --block=rootfile root=/dev/vda + Documentation/virtual/lguest/lguest 64 vmlinux --tunnet=192.168.19.1 \ + --block=rootfile root=/dev/vda Explanation: 64: the amount of memory to use, in MB. diff --git a/MAINTAINERS b/MAINTAINERS index 16a5c5f..aa9bbd1 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -3807,7 +3807,7 @@ M: Rusty Russell L: lguest@lists.ozlabs.org W: http://lguest.ozlabs.org/ S: Odd Fixes -F: Documentation/lguest/ +F: Documentation/virtual/lguest/ F: arch/x86/lguest/ F: drivers/lguest/ F: include/linux/lguest*.h @@ -6618,7 +6618,7 @@ L: user-mode-linux-devel@lists.sourceforge.net L: user-mode-linux-user@lists.sourceforge.net W: http://user-mode-linux.sourceforge.net S: Maintained -F: Documentation/uml/ +F: Documentation/virtual/uml/ F: arch/um/ F: fs/hostfs/ F: fs/hppfs/ diff --git a/arch/x86/lguest/boot.c b/arch/x86/lguest/boot.c index 1cd6089..395bf01 100644 --- a/arch/x86/lguest/boot.c +++ b/arch/x86/lguest/boot.c @@ -7,7 +7,7 @@ * kernel and insert a module (lg.ko) which allows us to run other Linux * kernels the same way we'd run processes. We call the first kernel the Host, * and the others the Guests. The program which sets up and configures Guests - * (such as the example in Documentation/lguest/lguest.c) is called the + * (such as the example in Documentation/virtual/lguest/lguest.c) is called the * Launcher. * * Secondly, we only run specially modified Guests, not normal kernels: setting diff --git a/drivers/lguest/Kconfig b/drivers/lguest/Kconfig index 0aaa059..34ae49d 100644 --- a/drivers/lguest/Kconfig +++ b/drivers/lguest/Kconfig @@ -5,8 +5,10 @@ config LGUEST ---help--- This is a very simple module which allows you to run multiple instances of the same Linux kernel, using the - "lguest" command found in the Documentation/lguest directory. + "lguest" command found in the Documentation/virtual/lguest + directory. + Note that "lguest" is pronounced to rhyme with "fell quest", - not "rustyvisor". See Documentation/lguest/lguest.txt. + not "rustyvisor". See Documentation/virtual/lguest/lguest.txt. If unsure, say N. If curious, say M. If masochistic, say Y. diff --git a/drivers/lguest/Makefile b/drivers/lguest/Makefile index 7d463c2..8ac947c 100644 --- a/drivers/lguest/Makefile +++ b/drivers/lguest/Makefile @@ -18,7 +18,7 @@ Mastery: PREFIX=M Beer: @for f in Preparation Guest Drivers Launcher Host Switcher Mastery; do echo "{==- $$f -==}"; make -s $$f; done; echo "{==-==}" Preparation Preparation! Guest Drivers Launcher Host Switcher Mastery: - @sh ../../Documentation/lguest/extract $(PREFIX) `find ../../* -name '*.[chS]' -wholename '*lguest*'` + @sh ../../Documentation/virtual/lguest/extract $(PREFIX) `find ../../* -name '*.[chS]' -wholename '*lguest*'` Puppy: @clear @printf " __ \n (___()'\`;\n /, /\`\n \\\\\\\"--\\\\\\ \n" diff --git a/drivers/vhost/vhost.c b/drivers/vhost/vhost.c index 2ab2912..7aa4eea 100644 --- a/drivers/vhost/vhost.c +++ b/drivers/vhost/vhost.c @@ -4,7 +4,7 @@ * Author: Michael S. Tsirkin * * Inspiration, some code, and most witty comments come from - * Documentation/lguest/lguest.c, by Rusty Russell + * Documentation/virtual/lguest/lguest.c, by Rusty Russell * * This work is licensed under the terms of the GNU GPL, version 2. * -- cgit v0.10.2 From 4613e72dbdc9a44bfc4625d835511264121c4244 Mon Sep 17 00:00:00 2001 From: "Cindy H. Kao" Date: Fri, 6 May 2011 10:40:15 -0700 Subject: iwlwifi: support the svtool messages interactions through nl80211 test mode This patch adds the feature to support the test mode operation through the generic netlink channel NL80211_CMD_TESTMODE between intel wireless device iwlwifi and the user space application svtool. The main purpose is to create a transportation layer between the iwlwifi device and the user space application so that the interaction between the user space application svtool and the iwlwifi device in the kernel space is in a way of generic netlink messaging. The detail specific functions are: 1. The function iwl_testmode_cmd() is added to digest the svtool test command from the user space application. The svtool test commands are categorized to three types : commands to be processed by the device ucode, commands to access the registers, and commands to be processed at the driver level(such as reload the ucode). iwl_testmode_cmd() dispatches the commands the corresponding handlers and reply to user space regarding the command execution status. Extra data is returned to the user space application if there's any. 2. The function iwl_testmode_ucode_rx_pkt() is added to multicast all the spontaneous messages from the iwlwifi device to the user space. Regardless the message types, whenever there is a valid spontaneous message received by the iwlwifi ISR, iwl_testmode_ucode_rx_pkt() is invoked to multicast the message content to user space. The message content is not attacked and the message parsing is left to the user space application. Implementation guidelines: 1. The generic netlink messaging for iwliwif test mode is through NL80211_CMD_TESTMODE channel, therefore, the codes need to follow the regulations set by cfg80211.ko to get the actual device instance ieee80211_ops via cfg80211.ko, so that the iwlwifi device is indicated with ieee80211_ops and can be actually accessed. Therefore, a callback iwl_testmode_cmd() is added to the structure iwlagn_hw_ops in iwl-agn.c. 2. It intends to utilize those low level device access APIs from iwlwifi device driver (ie. iwlagn.ko) rather than creating it's own set of device access functions. For example, iwl_send_cmd(), iwl_read32(), iwl_write8(), and iwl_write32() are reused. 3. The main functions are maintained in new files instead of spreading all over the existing iwlwifi driver files. The new files added are : drivers/net/wireless/iwlwifi/iwl-sv-open.c - to handle the user space test mode application command and reply the respective command status to the user space application. - to multicast the spontaneous messages from device to user space. drivers/net/wireless/iwlwifi/iwl-testmode.h - the commonly referenced definitions for the TLVs used in the generic netlink messages Signed-off-by: Cindy H. Kao Signed-off-by: Johannes Berg Signed-off-by: Wey-Yi Guy diff --git a/drivers/net/wireless/iwlwifi/Kconfig b/drivers/net/wireless/iwlwifi/Kconfig index 17d555f..ad3bdba 100644 --- a/drivers/net/wireless/iwlwifi/Kconfig +++ b/drivers/net/wireless/iwlwifi/Kconfig @@ -102,6 +102,16 @@ config IWLWIFI_DEVICE_TRACING occur. endmenu +config IWLWIFI_DEVICE_SVTOOL + bool "iwlwifi device svtool support" + depends on IWLAGN + select NL80211_TESTMODE + help + This option enables the svtool support for iwlwifi device through + NL80211_TESTMODE. svtool is a software validation tool that runs in + the user space and interacts with the device in the kernel space + through the generic netlink message via NL80211_TESTMODE channel. + config IWL_P2P bool "iwlwifi experimental P2P support" depends on IWLAGN diff --git a/drivers/net/wireless/iwlwifi/Makefile b/drivers/net/wireless/iwlwifi/Makefile index 89a41d3..8226604 100644 --- a/drivers/net/wireless/iwlwifi/Makefile +++ b/drivers/net/wireless/iwlwifi/Makefile @@ -16,6 +16,7 @@ iwlagn-objs += iwl-2000.o iwlagn-$(CONFIG_IWLWIFI_DEBUGFS) += iwl-debugfs.o iwlagn-$(CONFIG_IWLWIFI_DEVICE_TRACING) += iwl-devtrace.o +iwlagn-$(CONFIG_IWLWIFI_DEVICE_SVTOOL) += iwl-sv-open.o CFLAGS_iwl-devtrace.o := -I$(src) diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-ucode.c b/drivers/net/wireless/iwlwifi/iwl-agn-ucode.c index c3ae2e4..8bda0e8 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-ucode.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-ucode.c @@ -269,7 +269,7 @@ void iwlagn_rx_calib_result(struct iwl_priv *priv, iwl_calib_set(&priv->calib_results[index], pkt->u.raw, len); } -static int iwlagn_init_alive_start(struct iwl_priv *priv) +int iwlagn_init_alive_start(struct iwl_priv *priv) { int ret; diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index 003d524..09fe841 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -776,6 +776,8 @@ static void iwl_rx_handle(struct iwl_priv *priv) wake_up_all(&priv->_agn.notif_waitq); } + if (priv->pre_rx_handler) + priv->pre_rx_handler(priv, rxb); /* Based on type of command response or notification, * handle those that need handling via function in @@ -2211,7 +2213,7 @@ static int iwlagn_send_calib_cfg_rt(struct iwl_priv *priv, u32 cfg) * from protocol/runtime uCode (initialization uCode's * Alive gets handled by iwl_init_alive_start()). */ -static int iwl_alive_start(struct iwl_priv *priv) +int iwl_alive_start(struct iwl_priv *priv) { int ret = 0; struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS]; @@ -3507,6 +3509,7 @@ struct ieee80211_ops iwlagn_hw_ops = { .cancel_remain_on_channel = iwl_mac_cancel_remain_on_channel, .offchannel_tx = iwl_mac_offchannel_tx, .offchannel_tx_cancel_wait = iwl_mac_offchannel_tx_cancel_wait, + CFG80211_TESTMODE_CMD(iwl_testmode_cmd) }; static u32 iwl_hw_detect(struct iwl_priv *priv) @@ -3816,6 +3819,7 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) iwl_setup_deferred_work(priv); iwl_setup_rx_handlers(priv); + iwl_testmode_init(priv); /********************************************* * 8. Enable interrupts and read RFKILL state diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.h b/drivers/net/wireless/iwlwifi/iwl-agn.h index b477336..aa398b6 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.h +++ b/drivers/net/wireless/iwlwifi/iwl-agn.h @@ -344,5 +344,22 @@ iwlagn_wait_notification(struct iwl_priv *priv, void __releases(wait_entry) iwlagn_remove_notification(struct iwl_priv *priv, struct iwl_notification_wait *wait_entry); +extern int iwlagn_init_alive_start(struct iwl_priv *priv); +extern int iwl_alive_start(struct iwl_priv *priv); +/* svtool */ +#ifdef CONFIG_IWLWIFI_DEVICE_SVTOOL +extern int iwl_testmode_cmd(struct ieee80211_hw *hw, void *data, int len); +extern void iwl_testmode_init(struct iwl_priv *priv); +#else +static inline +int iwl_testmode_cmd(struct ieee80211_hw *hw, void *data, int len) +{ + return -ENOSYS; +} +static inline +void iwl_testmode_init(struct iwl_priv *priv) +{ +} +#endif #endif /* __iwl_agn_h__ */ diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index f098eff..3d28ad2 100644 --- a/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h @@ -1194,6 +1194,8 @@ struct iwl_priv { enum ieee80211_band band; + void (*pre_rx_handler)(struct iwl_priv *priv, + struct iwl_rx_mem_buffer *rxb); void (*rx_handlers[REPLY_MAX])(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb); diff --git a/drivers/net/wireless/iwlwifi/iwl-sv-open.c b/drivers/net/wireless/iwlwifi/iwl-sv-open.c new file mode 100644 index 0000000..89b6696 --- /dev/null +++ b/drivers/net/wireless/iwlwifi/iwl-sv-open.c @@ -0,0 +1,469 @@ +/****************************************************************************** + * + * This file is provided under a dual BSD/GPLv2 license. When using or + * redistributing this file, you may do so under either license. + * + * GPL LICENSE SUMMARY + * + * Copyright(c) 2010 - 2011 Intel Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, + * USA + * + * The full GNU General Public License is included in this distribution + * in the file called LICENSE.GPL. + * + * Contact Information: + * Intel Linux Wireless + * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + * + * BSD LICENSE + * + * Copyright(c) 2010 - 2011 Intel Corporation. All rights reserved. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + *****************************************************************************/ +#include +#include +#include +#include +#include +#include +#include +#include + + +#include "iwl-dev.h" +#include "iwl-core.h" +#include "iwl-debug.h" +#include "iwl-fh.h" +#include "iwl-io.h" +#include "iwl-agn.h" +#include "iwl-testmode.h" + + +/* The TLVs used in the gnl message policy between the kernel module and + * user space application. iwl_testmode_gnl_msg_policy is to be carried + * through the NL80211_CMD_TESTMODE channel regulated by nl80211. + * See iwl-testmode.h + */ +static +struct nla_policy iwl_testmode_gnl_msg_policy[IWL_TM_ATTR_MAX] = { + [IWL_TM_ATTR_COMMAND] = { .type = NLA_U32, }, + + [IWL_TM_ATTR_UCODE_CMD_ID] = { .type = NLA_U8, }, + [IWL_TM_ATTR_UCODE_CMD_DATA] = { .type = NLA_UNSPEC, }, + + [IWL_TM_ATTR_REG_OFFSET] = { .type = NLA_U32, }, + [IWL_TM_ATTR_REG_VALUE8] = { .type = NLA_U8, }, + [IWL_TM_ATTR_REG_VALUE32] = { .type = NLA_U32, }, + + [IWL_TM_ATTR_SYNC_RSP] = { .type = NLA_UNSPEC, }, + [IWL_TM_ATTR_UCODE_RX_PKT] = { .type = NLA_UNSPEC, }, +}; + +/* + * See the struct iwl_rx_packet in iwl-commands.h for the format of the + * received events from the device + */ +static inline int get_event_length(struct iwl_rx_mem_buffer *rxb) +{ + struct iwl_rx_packet *pkt = rxb_addr(rxb); + if (pkt) + return le32_to_cpu(pkt->len_n_flags) & FH_RSCSR_FRAME_SIZE_MSK; + else + return 0; +} + + +/* + * This function multicasts the spontaneous messages from the device to the + * user space. It is invoked whenever there is a received messages + * from the device. This function is called within the ISR of the rx handlers + * in iwlagn driver. + * + * The parsing of the message content is left to the user space application, + * The message content is treated as unattacked raw data and is encapsulated + * with IWL_TM_ATTR_UCODE_RX_PKT multicasting to the user space. + * + * @priv: the instance of iwlwifi device + * @rxb: pointer to rx data content received by the ISR + * + * See the message policies and TLVs in iwl_testmode_gnl_msg_policy[]. + * For the messages multicasting to the user application, the mandatory + * TLV fields are : + * IWL_TM_ATTR_COMMAND must be IWL_TM_CMD_DEV2APP_UCODE_RX_PKT + * IWL_TM_ATTR_UCODE_RX_PKT for carrying the message content + */ + +static void iwl_testmode_ucode_rx_pkt(struct iwl_priv *priv, + struct iwl_rx_mem_buffer *rxb) +{ + struct ieee80211_hw *hw = priv->hw; + struct sk_buff *skb; + void *data; + int length; + + data = (void *)rxb_addr(rxb); + length = get_event_length(rxb); + + if (!data || length == 0) + return; + + skb = cfg80211_testmode_alloc_event_skb(hw->wiphy, 20 + length, + GFP_ATOMIC); + if (skb == NULL) { + IWL_DEBUG_INFO(priv, + "Run out of memory for messages to user space ?\n"); + return; + } + NLA_PUT_U32(skb, IWL_TM_ATTR_COMMAND, IWL_TM_CMD_DEV2APP_UCODE_RX_PKT); + NLA_PUT(skb, IWL_TM_ATTR_UCODE_RX_PKT, length, data); + cfg80211_testmode_event(skb, GFP_ATOMIC); + return; + +nla_put_failure: + kfree_skb(skb); + IWL_DEBUG_INFO(priv, "Ouch, overran buffer, check allocation!\n"); +} + +void iwl_testmode_init(struct iwl_priv *priv) +{ + priv->pre_rx_handler = iwl_testmode_ucode_rx_pkt; +} + +/* + * This function handles the user application commands to the ucode. + * + * It retrieves the mandatory fields IWL_TM_ATTR_UCODE_CMD_ID and + * IWL_TM_ATTR_UCODE_CMD_DATA and calls to the handler to send the + * host command to the ucode. + * + * If any mandatory field is missing, -ENOMSG is replied to the user space + * application; otherwise, the actual execution result of the host command to + * ucode is replied. + * + * @hw: ieee80211_hw object that represents the device + * @tb: gnl message fields from the user space + */ +static int iwl_testmode_ucode(struct ieee80211_hw *hw, struct nlattr **tb) +{ + struct iwl_priv *priv = hw->priv; + struct iwl_host_cmd cmd; + + memset(&cmd, 0, sizeof(struct iwl_host_cmd)); + + if (!tb[IWL_TM_ATTR_UCODE_CMD_ID] || + !tb[IWL_TM_ATTR_UCODE_CMD_DATA]) { + IWL_DEBUG_INFO(priv, + "Error finding ucode command mandatory fields\n"); + return -ENOMSG; + } + + cmd.id = nla_get_u8(tb[IWL_TM_ATTR_UCODE_CMD_ID]); + cmd.data = nla_data(tb[IWL_TM_ATTR_UCODE_CMD_DATA]); + cmd.len = nla_len(tb[IWL_TM_ATTR_UCODE_CMD_DATA]); + IWL_INFO(priv, "testmode ucode command ID 0x%x, flags 0x%x," + " len %d\n", cmd.id, cmd.flags, cmd.len); + /* ok, let's submit the command to ucode */ + return iwl_send_cmd(priv, &cmd); +} + + +/* + * This function handles the user application commands for register access. + * + * It retrieves command ID carried with IWL_TM_ATTR_COMMAND and calls to the + * handlers respectively. + * + * If it's an unknown commdn ID, -ENOSYS is returned; or -ENOMSG if the + * mandatory fields(IWL_TM_ATTR_REG_OFFSET,IWL_TM_ATTR_REG_VALUE32, + * IWL_TM_ATTR_REG_VALUE8) are missing; Otherwise 0 is replied indicating + * the success of the command execution. + * + * If IWL_TM_ATTR_COMMAND is IWL_TM_CMD_APP2DEV_REG_READ32, the register read + * value is returned with IWL_TM_ATTR_REG_VALUE32. + * + * @hw: ieee80211_hw object that represents the device + * @tb: gnl message fields from the user space + */ +static int iwl_testmode_reg(struct ieee80211_hw *hw, struct nlattr **tb) +{ + struct iwl_priv *priv = hw->priv; + u32 ofs, val32; + u8 val8; + struct sk_buff *skb; + int status = 0; + + if (!tb[IWL_TM_ATTR_REG_OFFSET]) { + IWL_DEBUG_INFO(priv, "Error finding register offset\n"); + return -ENOMSG; + } + ofs = nla_get_u32(tb[IWL_TM_ATTR_REG_OFFSET]); + IWL_INFO(priv, "testmode register access command offset 0x%x\n", ofs); + + switch (nla_get_u32(tb[IWL_TM_ATTR_COMMAND])) { + case IWL_TM_CMD_APP2DEV_REG_READ32: + val32 = iwl_read32(priv, ofs); + IWL_INFO(priv, "32bit value to read 0x%x\n", val32); + + skb = cfg80211_testmode_alloc_reply_skb(hw->wiphy, 20); + if (!skb) { + IWL_DEBUG_INFO(priv, "Error allocating memory\n"); + return -ENOMEM; + } + NLA_PUT_U32(skb, IWL_TM_ATTR_REG_VALUE32, val32); + status = cfg80211_testmode_reply(skb); + if (status < 0) + IWL_DEBUG_INFO(priv, + "Error sending msg : %d\n", status); + break; + case IWL_TM_CMD_APP2DEV_REG_WRITE32: + if (!tb[IWL_TM_ATTR_REG_VALUE32]) { + IWL_DEBUG_INFO(priv, + "Error finding value to write\n"); + return -ENOMSG; + } else { + val32 = nla_get_u32(tb[IWL_TM_ATTR_REG_VALUE32]); + IWL_INFO(priv, "32bit value to write 0x%x\n", val32); + iwl_write32(priv, ofs, val32); + } + break; + case IWL_TM_CMD_APP2DEV_REG_WRITE8: + if (!tb[IWL_TM_ATTR_REG_VALUE8]) { + IWL_DEBUG_INFO(priv, "Error finding value to write\n"); + return -ENOMSG; + } else { + val8 = nla_get_u8(tb[IWL_TM_ATTR_REG_VALUE8]); + IWL_INFO(priv, "8bit value to write 0x%x\n", val8); + iwl_write8(priv, ofs, val8); + } + break; + default: + IWL_DEBUG_INFO(priv, "Unknown testmode register command ID\n"); + return -ENOSYS; + } + + return status; + +nla_put_failure: + kfree_skb(skb); + return -EMSGSIZE; +} + + +static int iwl_testmode_cfg_init_calib(struct iwl_priv *priv) +{ + struct iwl_notification_wait calib_wait; + int ret; + + iwlagn_init_notification_wait(priv, &calib_wait, + CALIBRATION_COMPLETE_NOTIFICATION, + NULL, NULL); + ret = iwlagn_init_alive_start(priv); + if (ret) { + IWL_DEBUG_INFO(priv, + "Error configuring init calibration: %d\n", ret); + goto cfg_init_calib_error; + } + + ret = iwlagn_wait_notification(priv, &calib_wait, 2 * HZ); + if (ret) + IWL_DEBUG_INFO(priv, "Error detecting" + " CALIBRATION_COMPLETE_NOTIFICATION: %d\n", ret); + return ret; + +cfg_init_calib_error: + iwlagn_remove_notification(priv, &calib_wait); + return ret; +} + +/* + * This function handles the user application commands for driver. + * + * It retrieves command ID carried with IWL_TM_ATTR_COMMAND and calls to the + * handlers respectively. + * + * If it's an unknown commdn ID, -ENOSYS is replied; otherwise, the returned + * value of the actual command execution is replied to the user application. + * + * If there's any message responding to the user space, IWL_TM_ATTR_SYNC_RSP + * is used for carry the message while IWL_TM_ATTR_COMMAND must set to + * IWL_TM_CMD_DEV2APP_SYNC_RSP. + * + * @hw: ieee80211_hw object that represents the device + * @tb: gnl message fields from the user space + */ +static int iwl_testmode_driver(struct ieee80211_hw *hw, struct nlattr **tb) +{ + struct iwl_priv *priv = hw->priv; + struct sk_buff *skb; + unsigned char *rsp_data_ptr = NULL; + int status = 0, rsp_data_len = 0; + + switch (nla_get_u32(tb[IWL_TM_ATTR_COMMAND])) { + case IWL_TM_CMD_APP2DEV_GET_DEVICENAME: + rsp_data_ptr = (unsigned char *)priv->cfg->name; + rsp_data_len = strlen(priv->cfg->name); + skb = cfg80211_testmode_alloc_reply_skb(hw->wiphy, + rsp_data_len + 20); + if (!skb) { + IWL_DEBUG_INFO(priv, + "Error allocating memory\n"); + return -ENOMEM; + } + NLA_PUT_U32(skb, IWL_TM_ATTR_COMMAND, + IWL_TM_CMD_DEV2APP_SYNC_RSP); + NLA_PUT(skb, IWL_TM_ATTR_SYNC_RSP, + rsp_data_len, rsp_data_ptr); + status = cfg80211_testmode_reply(skb); + if (status < 0) + IWL_DEBUG_INFO(priv, "Error sending msg : %d\n", + status); + break; + + case IWL_TM_CMD_APP2DEV_LOAD_INIT_FW: + status = iwlagn_load_ucode_wait_alive(priv, &priv->ucode_init, + UCODE_SUBTYPE_INIT, -1); + if (status) + IWL_DEBUG_INFO(priv, + "Error loading init ucode: %d\n", status); + break; + + case IWL_TM_CMD_APP2DEV_CFG_INIT_CALIB: + iwl_testmode_cfg_init_calib(priv); + iwlagn_stop_device(priv); + break; + + case IWL_TM_CMD_APP2DEV_LOAD_RUNTIME_FW: + status = iwlagn_load_ucode_wait_alive(priv, + &priv->ucode_rt, + UCODE_SUBTYPE_REGULAR, + UCODE_SUBTYPE_REGULAR_NEW); + if (status) { + IWL_DEBUG_INFO(priv, + "Error loading runtime ucode: %d\n", status); + break; + } + status = iwl_alive_start(priv); + if (status) + IWL_DEBUG_INFO(priv, + "Error starting the device: %d\n", status); + break; + + default: + IWL_DEBUG_INFO(priv, "Unknown testmode driver command ID\n"); + return -ENOSYS; + } + return status; + +nla_put_failure: + kfree_skb(skb); + return -EMSGSIZE; +} + +/* The testmode gnl message handler that takes the gnl message from the + * user space and parses it per the policy iwl_testmode_gnl_msg_policy, then + * invoke the corresponding handlers. + * + * This function is invoked when there is user space application sending + * gnl message through the testmode tunnel NL80211_CMD_TESTMODE regulated + * by nl80211. + * + * It retrieves the mandatory field, IWL_TM_ATTR_COMMAND, before + * dispatching it to the corresponding handler. + * + * If IWL_TM_ATTR_COMMAND is missing, -ENOMSG is replied to user application; + * -ENOSYS is replied to the user application if the command is unknown; + * Otherwise, the command is dispatched to the respective handler. + * + * @hw: ieee80211_hw object that represents the device + * @data: pointer to user space message + * @len: length in byte of @data + */ +int iwl_testmode_cmd(struct ieee80211_hw *hw, void *data, int len) +{ + struct nlattr *tb[IWL_TM_ATTR_MAX - 1]; + struct iwl_priv *priv = hw->priv; + int result; + + result = nla_parse(tb, IWL_TM_ATTR_MAX - 1, data, len, + iwl_testmode_gnl_msg_policy); + if (result != 0) { + IWL_DEBUG_INFO(priv, + "Error parsing the gnl message : %d\n", result); + return result; + } + + /* IWL_TM_ATTR_COMMAND is absolutely mandatory */ + if (!tb[IWL_TM_ATTR_COMMAND]) { + IWL_DEBUG_INFO(priv, "Error finding testmode command type\n"); + return -ENOMSG; + } + /* in case multiple accesses to the device happens */ + mutex_lock(&priv->mutex); + + switch (nla_get_u32(tb[IWL_TM_ATTR_COMMAND])) { + case IWL_TM_CMD_APP2DEV_UCODE: + IWL_DEBUG_INFO(priv, "testmode cmd to uCode\n"); + result = iwl_testmode_ucode(hw, tb); + break; + case IWL_TM_CMD_APP2DEV_REG_READ32: + case IWL_TM_CMD_APP2DEV_REG_WRITE32: + case IWL_TM_CMD_APP2DEV_REG_WRITE8: + IWL_DEBUG_INFO(priv, "testmode cmd to register\n"); + result = iwl_testmode_reg(hw, tb); + break; + case IWL_TM_CMD_APP2DEV_GET_DEVICENAME: + case IWL_TM_CMD_APP2DEV_LOAD_INIT_FW: + case IWL_TM_CMD_APP2DEV_CFG_INIT_CALIB: + case IWL_TM_CMD_APP2DEV_LOAD_RUNTIME_FW: + IWL_DEBUG_INFO(priv, "testmode cmd to driver\n"); + result = iwl_testmode_driver(hw, tb); + break; + default: + IWL_DEBUG_INFO(priv, "Unknown testmode command\n"); + result = -ENOSYS; + break; + } + + mutex_unlock(&priv->mutex); + return result; +} diff --git a/drivers/net/wireless/iwlwifi/iwl-testmode.h b/drivers/net/wireless/iwlwifi/iwl-testmode.h new file mode 100644 index 0000000..31f8949 --- /dev/null +++ b/drivers/net/wireless/iwlwifi/iwl-testmode.h @@ -0,0 +1,151 @@ +/****************************************************************************** + * + * This file is provided under a dual BSD/GPLv2 license. When using or + * redistributing this file, you may do so under either license. + * + * GPL LICENSE SUMMARY + * + * Copyright(c) 2010 - 2011 Intel Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, + * USA + * + * The full GNU General Public License is included in this distribution + * in the file called LICENSE.GPL. + * + * Contact Information: + * Intel Linux Wireless + * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + * + * BSD LICENSE + * + * Copyright(c) 2010 - 2011 Intel Corporation. All rights reserved. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + *****************************************************************************/ +#ifndef __IWL_TESTMODE_H__ +#define __IWL_TESTMODE_H__ + +#include + + +/* Commands from user space to kernel space(IWL_TM_CMD_ID_APP2DEV_XX) and + * from and kernel space to user space(IWL_TM_CMD_ID_DEV2APP_XX). + * The command ID is carried with IWL_TM_ATTR_COMMAND. There are three types of + * of command from user space and two types of command from kernel space. + * See below. + */ +enum iwl_tm_cmd_t { + /* commands from user application to the uCode, + * the actual uCode host command ID is carried with + * IWL_TM_ATTR_UCODE_CMD_ID */ + IWL_TM_CMD_APP2DEV_UCODE = 1, + + /* commands from user applicaiton to access register */ + IWL_TM_CMD_APP2DEV_REG_READ32, + IWL_TM_CMD_APP2DEV_REG_WRITE32, + IWL_TM_CMD_APP2DEV_REG_WRITE8, + + /* commands fom user space for pure driver level operations */ + IWL_TM_CMD_APP2DEV_GET_DEVICENAME, + IWL_TM_CMD_APP2DEV_LOAD_INIT_FW, + IWL_TM_CMD_APP2DEV_CFG_INIT_CALIB, + IWL_TM_CMD_APP2DEV_LOAD_RUNTIME_FW, + /* if there is other new command for the driver layer operation, + * append them here */ + + + /* commands from kernel space to carry the synchronous response + * to user application */ + IWL_TM_CMD_DEV2APP_SYNC_RSP, + + /* commands from kernel space to multicast the spontaneous messages + * to user application */ + IWL_TM_CMD_DEV2APP_UCODE_RX_PKT, + IWL_TM_CMD_MAX, +}; + +enum iwl_tm_attr_t { + IWL_TM_ATTR_NOT_APPLICABLE = 0, + + /* From user space to kernel space: + * the command either destines to ucode, driver, or register; + * See enum iwl_tm_cmd_t. + * + * From kernel space to user space: + * the command either carries synchronous response, + * or the spontaneous message multicast from the device; + * See enum iwl_tm_cmd_t. */ + IWL_TM_ATTR_COMMAND, + + /* When IWL_TM_ATTR_COMMAND is IWL_TM_CMD_APP2DEV_UCODE, + * The mandatory fields are : + * IWL_TM_ATTR_UCODE_CMD_ID for recognizable command ID; + * IWL_TM_ATTR_COMMAND_FLAG for the flags of the commands; + * The optional fields are: + * IWL_TM_ATTR_UCODE_CMD_DATA for the actual command payload + * to the ucode */ + IWL_TM_ATTR_UCODE_CMD_ID, + IWL_TM_ATTR_UCODE_CMD_DATA, + + /* When IWL_TM_ATTR_COMMAND is IWL_TM_CMD_APP2DEV_REG_XXX, + * The mandatory fields are: + * IWL_TM_ATTR_REG_OFFSET for the offset of the target register; + * IWL_TM_ATTR_REG_VALUE8 or IWL_TM_ATTR_REG_VALUE32 for value */ + IWL_TM_ATTR_REG_OFFSET, + IWL_TM_ATTR_REG_VALUE8, + IWL_TM_ATTR_REG_VALUE32, + + /* When IWL_TM_ATTR_COMMAND is IWL_TM_CMD_DEV2APP_SYNC_RSP, + * The mandatory fields are: + * IWL_TM_ATTR_SYNC_RSP for the data content responding to the user + * application command */ + IWL_TM_ATTR_SYNC_RSP, + /* When IWL_TM_ATTR_COMMAND is IWL_TM_CMD_DEV2APP_UCODE_RX_PKT, + * The mandatory fields are: + * IWL_TM_ATTR_UCODE_RX_PKT for the data content multicast to the user + * application */ + IWL_TM_ATTR_UCODE_RX_PKT, + + IWL_TM_ATTR_MAX, +}; + + +#endif -- cgit v0.10.2 From 46975f78fe1f480682e51c9acb03a5089b784cb6 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 28 Apr 2011 07:27:05 -0700 Subject: iwlagn: remove get_hcmd_size indirection There's no need for this, all commands are the right size. Signed-off-by: Johannes Berg Signed-off-by: Wey-Yi Guy diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-hcmd.c b/drivers/net/wireless/iwlwifi/iwl-agn-hcmd.c index 49dd03f..b12c72d 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-hcmd.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-hcmd.c @@ -54,12 +54,6 @@ int iwlagn_send_tx_ant_config(struct iwl_priv *priv, u8 valid_tx_ant) } } -/* Currently this is the superset of everything */ -static u16 iwlagn_get_hcmd_size(u8 cmd_id, u16 len) -{ - return len; -} - static u16 iwlagn_build_addsta_hcmd(const struct iwl_addsta_cmd *cmd, u8 *data) { u16 size = (u16)sizeof(struct iwl_addsta_cmd); @@ -332,7 +326,6 @@ struct iwl_hcmd_ops iwlagn_bt_hcmd = { }; struct iwl_hcmd_utils_ops iwlagn_hcmd_utils = { - .get_hcmd_size = iwlagn_get_hcmd_size, .build_addsta_hcmd = iwlagn_build_addsta_hcmd, .gain_computation = iwlagn_gain_computation, .chain_noise_reset = iwlagn_chain_noise_reset, diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h index dec98207..9d7e36d 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.h +++ b/drivers/net/wireless/iwlwifi/iwl-core.h @@ -99,7 +99,6 @@ struct iwl_hcmd_ops { }; struct iwl_hcmd_utils_ops { - u16 (*get_hcmd_size)(u8 cmd_id, u16 len); u16 (*build_addsta_hcmd)(const struct iwl_addsta_cmd *cmd, u8 *data); void (*gain_computation)(struct iwl_priv *priv, u32 *average_noise, diff --git a/drivers/net/wireless/iwlwifi/iwl-tx.c b/drivers/net/wireless/iwlwifi/iwl-tx.c index 52b1b66..608d7a1 100644 --- a/drivers/net/wireless/iwlwifi/iwl-tx.c +++ b/drivers/net/wireless/iwlwifi/iwl-tx.c @@ -447,7 +447,6 @@ int iwl_enqueue_hcmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd) u16 fix_size; bool is_ct_kill = false; - cmd->len = priv->cfg->ops->utils->get_hcmd_size(cmd->id, cmd->len); fix_size = (u16)(cmd->len + sizeof(out_cmd->hdr)); /* -- cgit v0.10.2 From 8a98d49ec1f38d9f3eef7e34f148c3f1f5590fdf Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 29 Apr 2011 09:48:14 -0700 Subject: iwlagn: remove frame pre-allocation The frame pre-allocation is quite a bit of complex code, all to avoid a single allocation. Remove it and consolidate the beacon sending code. Signed-off-by: Johannes Berg Signed-off-by: Wey-Yi Guy diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index 09fe841..3ecc319 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -102,70 +102,6 @@ void iwl_update_chain_flags(struct iwl_priv *priv) } } -static void iwl_clear_free_frames(struct iwl_priv *priv) -{ - struct list_head *element; - - IWL_DEBUG_INFO(priv, "%d frames on pre-allocated heap on clear.\n", - priv->frames_count); - - while (!list_empty(&priv->free_frames)) { - element = priv->free_frames.next; - list_del(element); - kfree(list_entry(element, struct iwl_frame, list)); - priv->frames_count--; - } - - if (priv->frames_count) { - IWL_WARN(priv, "%d frames still in use. Did we lose one?\n", - priv->frames_count); - priv->frames_count = 0; - } -} - -static struct iwl_frame *iwl_get_free_frame(struct iwl_priv *priv) -{ - struct iwl_frame *frame; - struct list_head *element; - if (list_empty(&priv->free_frames)) { - frame = kzalloc(sizeof(*frame), GFP_KERNEL); - if (!frame) { - IWL_ERR(priv, "Could not allocate frame!\n"); - return NULL; - } - - priv->frames_count++; - return frame; - } - - element = priv->free_frames.next; - list_del(element); - return list_entry(element, struct iwl_frame, list); -} - -static void iwl_free_frame(struct iwl_priv *priv, struct iwl_frame *frame) -{ - memset(frame, 0, sizeof(*frame)); - list_add(&frame->list, &priv->free_frames); -} - -static u32 iwl_fill_beacon_frame(struct iwl_priv *priv, - struct ieee80211_hdr *hdr, - int left) -{ - lockdep_assert_held(&priv->mutex); - - if (!priv->beacon_skb) - return 0; - - if (priv->beacon_skb->len > left) - return 0; - - memcpy(hdr, priv->beacon_skb->data, priv->beacon_skb->len); - - return priv->beacon_skb->len; -} - /* Parse the beacon frame to find the TIM element and set tim_idx & tim_size */ static void iwl_set_beacon_tim(struct iwl_priv *priv, struct iwl_tx_beacon_cmd *tx_beacon_cmd, @@ -193,13 +129,18 @@ static void iwl_set_beacon_tim(struct iwl_priv *priv, IWL_WARN(priv, "Unable to find TIM Element in beacon\n"); } -static unsigned int iwl_hw_get_beacon_cmd(struct iwl_priv *priv, - struct iwl_frame *frame) +int iwlagn_send_beacon_cmd(struct iwl_priv *priv) { struct iwl_tx_beacon_cmd *tx_beacon_cmd; + struct iwl_host_cmd cmd = { + .id = REPLY_TX_BEACON, + .flags = CMD_SIZE_HUGE, + }; u32 frame_size; u32 rate_flags; u32 rate; + int err; + /* * We have to set up the TX command, the TX Beacon command, and the * beacon contents. @@ -212,17 +153,19 @@ static unsigned int iwl_hw_get_beacon_cmd(struct iwl_priv *priv, return 0; } - /* Initialize memory */ - tx_beacon_cmd = &frame->u.beacon; - memset(tx_beacon_cmd, 0, sizeof(*tx_beacon_cmd)); + if (WARN_ON(!priv->beacon_skb)) + return -EINVAL; + + /* Allocate beacon memory */ + tx_beacon_cmd = kzalloc(sizeof(*tx_beacon_cmd) + priv->beacon_skb->len, + GFP_KERNEL); + if (!tx_beacon_cmd) + return -ENOMEM; + + frame_size = priv->beacon_skb->len; /* Set up TX beacon contents */ - frame_size = iwl_fill_beacon_frame(priv, tx_beacon_cmd->frame, - sizeof(frame->u) - sizeof(*tx_beacon_cmd)); - if (WARN_ON_ONCE(frame_size > MAX_MPDU_SIZE)) - return 0; - if (!frame_size) - return 0; + memcpy(tx_beacon_cmd->frame, priv->beacon_skb->data, frame_size); /* Set up TX command fields */ tx_beacon_cmd->tx.len = cpu_to_le16((u16)frame_size); @@ -245,41 +188,16 @@ static unsigned int iwl_hw_get_beacon_cmd(struct iwl_priv *priv, tx_beacon_cmd->tx.rate_n_flags = iwl_hw_set_rate_n_flags(rate, rate_flags); - return sizeof(*tx_beacon_cmd) + frame_size; -} + /* Submit command */ + cmd.len = sizeof(*tx_beacon_cmd) + frame_size; + cmd.data = tx_beacon_cmd; -int iwlagn_send_beacon_cmd(struct iwl_priv *priv) -{ - struct iwl_frame *frame; - unsigned int frame_size; - int rc; - struct iwl_host_cmd cmd = { - .id = REPLY_TX_BEACON, - .flags = CMD_SIZE_HUGE, - }; - - frame = iwl_get_free_frame(priv); - if (!frame) { - IWL_ERR(priv, "Could not obtain free frame buffer for beacon " - "command.\n"); - return -ENOMEM; - } - - frame_size = iwl_hw_get_beacon_cmd(priv, frame); - if (!frame_size) { - IWL_ERR(priv, "Error configuring the beacon command\n"); - iwl_free_frame(priv, frame); - return -EINVAL; - } - - cmd.len = frame_size; - cmd.data = &frame->u.cmd[0]; - - rc = iwl_send_cmd_sync(priv, &cmd); + err = iwl_send_cmd_sync(priv, &cmd); - iwl_free_frame(priv, frame); + /* Free temporary storage */ + kfree(tx_beacon_cmd); - return rc; + return err; } static inline dma_addr_t iwl_tfd_tb_get_addr(struct iwl_tfd *tfd, u8 idx) @@ -2356,9 +2274,6 @@ static void __iwl_down(struct iwl_priv *priv) dev_kfree_skb(priv->beacon_skb); priv->beacon_skb = NULL; - - /* clear out any free frames */ - iwl_clear_free_frames(priv); } static void iwl_down(struct iwl_priv *priv) @@ -3416,8 +3331,6 @@ static int iwl_init_drv(struct iwl_priv *priv) spin_lock_init(&priv->sta_lock); spin_lock_init(&priv->hcmd_lock); - INIT_LIST_HEAD(&priv->free_frames); - mutex_init(&priv->mutex); priv->ieee_channels = NULL; diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index 3d28ad2..2fd752a 100644 --- a/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h @@ -238,15 +238,6 @@ struct iwl_channel_info { #define IEEE80211_HLEN (IEEE80211_4ADDR_LEN) #define IEEE80211_FRAME_LEN (IEEE80211_DATA_LEN + IEEE80211_HLEN) -struct iwl_frame { - union { - struct ieee80211_hdr frame; - struct iwl_tx_beacon_cmd beacon; - u8 raw[IEEE80211_FRAME_LEN]; - u8 cmd[360]; - } u; - struct list_head list; -}; #define SEQ_TO_SN(seq) (((seq) & IEEE80211_SCTL_SEQ) >> 4) #define SN_TO_SEQ(ssn) (((ssn) << 4) & IEEE80211_SCTL_SEQ) @@ -1188,10 +1179,6 @@ struct iwl_priv { struct ieee80211_rate *ieee_rates; struct iwl_cfg *cfg; - /* temporary frame storage list */ - struct list_head free_frames; - int frames_count; - enum ieee80211_band band; void (*pre_rx_handler)(struct iwl_priv *priv, -- cgit v0.10.2 From 4c2cde3b59d923d2952ef0accdde892e23b4997b Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 28 Apr 2011 07:27:07 -0700 Subject: iwlagn: remove unused variable The variable 'len' here is set but never used. Signed-off-by: Johannes Berg Signed-off-by: Wey-Yi Guy diff --git a/drivers/net/wireless/iwlwifi/iwl-tx.c b/drivers/net/wireless/iwlwifi/iwl-tx.c index 608d7a1..517d104 100644 --- a/drivers/net/wireless/iwlwifi/iwl-tx.c +++ b/drivers/net/wireless/iwlwifi/iwl-tx.c @@ -442,7 +442,6 @@ int iwl_enqueue_hcmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd) struct iwl_cmd_meta *out_meta; dma_addr_t phys_addr; unsigned long flags; - int len; u32 idx; u16 fix_size; bool is_ct_kill = false; @@ -518,9 +517,6 @@ int iwl_enqueue_hcmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd) INDEX_TO_SEQ(q->write_ptr)); if (cmd->flags & CMD_SIZE_HUGE) out_cmd->hdr.sequence |= SEQ_HUGE_FRAME; - len = sizeof(struct iwl_device_cmd); - if (idx == TFD_CMD_SLOTS) - len = IWL_MAX_CMD_SIZE; #ifdef CONFIG_IWLWIFI_DEBUG switch (out_cmd->hdr.cmd) { -- cgit v0.10.2 From ccb6c1c0ec2b76a41c8c85747b1a671e71b97e64 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 28 Apr 2011 07:27:08 -0700 Subject: iwlagn: dont update bytecount table for command queue The device doesn't use the bytecount table for the command queue, only for aggregation queues to make aggregation decisions. So don't update it for the command queue (and we even updated it with wrong values). Signed-off-by: Johannes Berg Signed-off-by: Wey-Yi Guy diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-tx.c b/drivers/net/wireless/iwlwifi/iwl-agn-tx.c index 494de0e..5445fd6 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-tx.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-tx.c @@ -112,21 +112,19 @@ void iwlagn_txq_update_byte_cnt_tbl(struct iwl_priv *priv, WARN_ON(len > 0xFFF || write_ptr >= TFD_QUEUE_SIZE_MAX); - if (txq_id != priv->cmd_queue) { - sta_id = txq->cmd[txq->q.write_ptr]->cmd.tx.sta_id; - sec_ctl = txq->cmd[txq->q.write_ptr]->cmd.tx.sec_ctl; - - switch (sec_ctl & TX_CMD_SEC_MSK) { - case TX_CMD_SEC_CCM: - len += CCMP_MIC_LEN; - break; - case TX_CMD_SEC_TKIP: - len += TKIP_ICV_LEN; - break; - case TX_CMD_SEC_WEP: - len += WEP_IV_LEN + WEP_ICV_LEN; - break; - } + sta_id = txq->cmd[txq->q.write_ptr]->cmd.tx.sta_id; + sec_ctl = txq->cmd[txq->q.write_ptr]->cmd.tx.sec_ctl; + + switch (sec_ctl & TX_CMD_SEC_MSK) { + case TX_CMD_SEC_CCM: + len += CCMP_MIC_LEN; + break; + case TX_CMD_SEC_TKIP: + len += TKIP_ICV_LEN; + break; + case TX_CMD_SEC_WEP: + len += WEP_IV_LEN + WEP_ICV_LEN; + break; } bc_ent = cpu_to_le16((len & 0xFFF) | (sta_id << 12)); diff --git a/drivers/net/wireless/iwlwifi/iwl-tx.c b/drivers/net/wireless/iwlwifi/iwl-tx.c index 517d104..5a7cd17 100644 --- a/drivers/net/wireless/iwlwifi/iwl-tx.c +++ b/drivers/net/wireless/iwlwifi/iwl-tx.c @@ -540,10 +540,6 @@ int iwl_enqueue_hcmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd) #endif txq->need_update = 1; - if (priv->cfg->ops->lib->txq_update_byte_cnt_tbl) - /* Set up entry in queue's byte count circular buffer */ - priv->cfg->ops->lib->txq_update_byte_cnt_tbl(priv, txq, 0); - phys_addr = pci_map_single(priv->pci_dev, &out_cmd->hdr, fix_size, PCI_DMA_BIDIRECTIONAL); dma_unmap_addr_set(out_meta, mapping, phys_addr); -- cgit v0.10.2 From 94b00658ffc719427c9c09d7920957bc35915c6f Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 28 Apr 2011 07:27:09 -0700 Subject: iwlagn: remove bytecount indirection All AGN devices need the bytecount table, so remove the indirection and make the functions static again. Signed-off-by: Johannes Berg Signed-off-by: Wey-Yi Guy diff --git a/drivers/net/wireless/iwlwifi/iwl-1000.c b/drivers/net/wireless/iwlwifi/iwl-1000.c index 3da8cf2..b4c8193 100644 --- a/drivers/net/wireless/iwlwifi/iwl-1000.c +++ b/drivers/net/wireless/iwlwifi/iwl-1000.c @@ -171,8 +171,6 @@ static int iwl1000_hw_set_hw_params(struct iwl_priv *priv) static struct iwl_lib_ops iwl1000_lib = { .set_hw_params = iwl1000_hw_set_hw_params, - .txq_update_byte_cnt_tbl = iwlagn_txq_update_byte_cnt_tbl, - .txq_inval_byte_cnt_tbl = iwlagn_txq_inval_byte_cnt_tbl, .txq_set_sched = iwlagn_txq_set_sched, .txq_attach_buf_to_tfd = iwl_hw_txq_attach_buf_to_tfd, .txq_free_tfd = iwl_hw_txq_free_tfd, diff --git a/drivers/net/wireless/iwlwifi/iwl-2000.c b/drivers/net/wireless/iwlwifi/iwl-2000.c index bca462c..89b8da7 100644 --- a/drivers/net/wireless/iwlwifi/iwl-2000.c +++ b/drivers/net/wireless/iwlwifi/iwl-2000.c @@ -252,8 +252,6 @@ static int iwl2030_hw_channel_switch(struct iwl_priv *priv, static struct iwl_lib_ops iwl2000_lib = { .set_hw_params = iwl2000_hw_set_hw_params, - .txq_update_byte_cnt_tbl = iwlagn_txq_update_byte_cnt_tbl, - .txq_inval_byte_cnt_tbl = iwlagn_txq_inval_byte_cnt_tbl, .txq_set_sched = iwlagn_txq_set_sched, .txq_attach_buf_to_tfd = iwl_hw_txq_attach_buf_to_tfd, .txq_free_tfd = iwl_hw_txq_free_tfd, diff --git a/drivers/net/wireless/iwlwifi/iwl-5000.c b/drivers/net/wireless/iwlwifi/iwl-5000.c index 561f2cd..98f81df 100644 --- a/drivers/net/wireless/iwlwifi/iwl-5000.c +++ b/drivers/net/wireless/iwlwifi/iwl-5000.c @@ -339,8 +339,6 @@ static int iwl5000_hw_channel_switch(struct iwl_priv *priv, static struct iwl_lib_ops iwl5000_lib = { .set_hw_params = iwl5000_hw_set_hw_params, - .txq_update_byte_cnt_tbl = iwlagn_txq_update_byte_cnt_tbl, - .txq_inval_byte_cnt_tbl = iwlagn_txq_inval_byte_cnt_tbl, .txq_set_sched = iwlagn_txq_set_sched, .txq_attach_buf_to_tfd = iwl_hw_txq_attach_buf_to_tfd, .txq_free_tfd = iwl_hw_txq_free_tfd, @@ -376,8 +374,6 @@ static struct iwl_lib_ops iwl5000_lib = { static struct iwl_lib_ops iwl5150_lib = { .set_hw_params = iwl5150_hw_set_hw_params, - .txq_update_byte_cnt_tbl = iwlagn_txq_update_byte_cnt_tbl, - .txq_inval_byte_cnt_tbl = iwlagn_txq_inval_byte_cnt_tbl, .txq_set_sched = iwlagn_txq_set_sched, .txq_attach_buf_to_tfd = iwl_hw_txq_attach_buf_to_tfd, .txq_free_tfd = iwl_hw_txq_free_tfd, diff --git a/drivers/net/wireless/iwlwifi/iwl-6000.c b/drivers/net/wireless/iwlwifi/iwl-6000.c index 6045457..a7921f9a 100644 --- a/drivers/net/wireless/iwlwifi/iwl-6000.c +++ b/drivers/net/wireless/iwlwifi/iwl-6000.c @@ -278,8 +278,6 @@ static int iwl6000_hw_channel_switch(struct iwl_priv *priv, static struct iwl_lib_ops iwl6000_lib = { .set_hw_params = iwl6000_hw_set_hw_params, - .txq_update_byte_cnt_tbl = iwlagn_txq_update_byte_cnt_tbl, - .txq_inval_byte_cnt_tbl = iwlagn_txq_inval_byte_cnt_tbl, .txq_set_sched = iwlagn_txq_set_sched, .txq_attach_buf_to_tfd = iwl_hw_txq_attach_buf_to_tfd, .txq_free_tfd = iwl_hw_txq_free_tfd, @@ -316,8 +314,6 @@ static struct iwl_lib_ops iwl6000_lib = { static struct iwl_lib_ops iwl6030_lib = { .set_hw_params = iwl6000_hw_set_hw_params, - .txq_update_byte_cnt_tbl = iwlagn_txq_update_byte_cnt_tbl, - .txq_inval_byte_cnt_tbl = iwlagn_txq_inval_byte_cnt_tbl, .txq_set_sched = iwlagn_txq_set_sched, .txq_attach_buf_to_tfd = iwl_hw_txq_attach_buf_to_tfd, .txq_free_tfd = iwl_hw_txq_free_tfd, diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-tx.c b/drivers/net/wireless/iwlwifi/iwl-agn-tx.c index 5445fd6..26601b7 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-tx.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-tx.c @@ -98,9 +98,9 @@ static inline int get_fifo_from_tid(struct iwl_rxon_context *ctx, u16 tid) /** * iwlagn_txq_update_byte_cnt_tbl - Set up entry in Tx byte-count array */ -void iwlagn_txq_update_byte_cnt_tbl(struct iwl_priv *priv, - struct iwl_tx_queue *txq, - u16 byte_cnt) +static void iwlagn_txq_update_byte_cnt_tbl(struct iwl_priv *priv, + struct iwl_tx_queue *txq, + u16 byte_cnt) { struct iwlagn_scd_bc_tbl *scd_bc_tbl = priv->scd_bc_tbls.addr; int write_ptr = txq->q.write_ptr; @@ -136,8 +136,8 @@ void iwlagn_txq_update_byte_cnt_tbl(struct iwl_priv *priv, tfd_offset[TFD_QUEUE_SIZE_MAX + write_ptr] = bc_ent; } -void iwlagn_txq_inval_byte_cnt_tbl(struct iwl_priv *priv, - struct iwl_tx_queue *txq) +static void iwlagn_txq_inval_byte_cnt_tbl(struct iwl_priv *priv, + struct iwl_tx_queue *txq) { struct iwlagn_scd_bc_tbl *scd_bc_tbl = priv->scd_bc_tbls.addr; int txq_id = txq->q.id; @@ -766,8 +766,8 @@ int iwlagn_tx_skb(struct iwl_priv *priv, struct sk_buff *skb) /* Set up entry for this TFD in Tx byte-count array */ if (info->flags & IEEE80211_TX_CTL_AMPDU) - priv->cfg->ops->lib->txq_update_byte_cnt_tbl(priv, txq, - le16_to_cpu(tx_cmd->len)); + iwlagn_txq_update_byte_cnt_tbl(priv, txq, + le16_to_cpu(tx_cmd->len)); pci_dma_sync_single_for_device(priv->pci_dev, txcmd_phys, firstlen, PCI_DMA_BIDIRECTIONAL); @@ -1246,8 +1246,7 @@ int iwlagn_tx_queue_reclaim(struct iwl_priv *priv, int txq_id, int index) txq_id >= IWLAGN_FIRST_AMPDU_QUEUE); tx_info->skb = NULL; - if (priv->cfg->ops->lib->txq_inval_byte_cnt_tbl) - priv->cfg->ops->lib->txq_inval_byte_cnt_tbl(priv, txq); + iwlagn_txq_inval_byte_cnt_tbl(priv, txq); priv->cfg->ops->lib->txq_free_tfd(priv, txq); } diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.h b/drivers/net/wireless/iwlwifi/iwl-agn.h index aa398b6..fe33fe8 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.h +++ b/drivers/net/wireless/iwlwifi/iwl-agn.h @@ -139,11 +139,6 @@ void iwlagn_set_wr_ptrs(struct iwl_priv *priv, void iwlagn_tx_queue_set_status(struct iwl_priv *priv, struct iwl_tx_queue *txq, int tx_fifo_id, int scd_retry); -void iwlagn_txq_update_byte_cnt_tbl(struct iwl_priv *priv, - struct iwl_tx_queue *txq, - u16 byte_cnt); -void iwlagn_txq_inval_byte_cnt_tbl(struct iwl_priv *priv, - struct iwl_tx_queue *txq); void iwlagn_txq_set_sched(struct iwl_priv *priv, u32 mask); void iwl_free_tfds_in_queue(struct iwl_priv *priv, int sta_id, int tid, int freed); diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h index 9d7e36d..5b5b0cce 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.h +++ b/drivers/net/wireless/iwlwifi/iwl-core.h @@ -128,11 +128,6 @@ struct iwl_lib_ops { /* set hw dependent parameters */ int (*set_hw_params)(struct iwl_priv *priv); /* Handling TX */ - void (*txq_update_byte_cnt_tbl)(struct iwl_priv *priv, - struct iwl_tx_queue *txq, - u16 byte_cnt); - void (*txq_inval_byte_cnt_tbl)(struct iwl_priv *priv, - struct iwl_tx_queue *txq); void (*txq_set_sched)(struct iwl_priv *priv, u32 mask); int (*txq_attach_buf_to_tfd)(struct iwl_priv *priv, struct iwl_tx_queue *txq, -- cgit v0.10.2 From 2c46f72e069eef5e98f2b04df08cde6bdc673aa7 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 28 Apr 2011 07:27:10 -0700 Subject: iwlagn: check DMA mapping errors DMA mappings can fail, but the current code doesn't check for that. Add checking, which requires some restructuring for proper error paths. Signed-off-by: Johannes Berg Signed-off-by: Wey-Yi Guy diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-tx.c b/drivers/net/wireless/iwlwifi/iwl-agn-tx.c index 26601b7..7c1becf 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-tx.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-tx.c @@ -537,7 +537,7 @@ int iwlagn_tx_skb(struct iwl_priv *priv, struct sk_buff *skb) struct iwl_tx_cmd *tx_cmd; struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS]; int txq_id; - dma_addr_t phys_addr; + dma_addr_t phys_addr = 0; dma_addr_t txcmd_phys; dma_addr_t scratch_phys; u16 len, firstlen, secondlen; @@ -564,7 +564,7 @@ int iwlagn_tx_skb(struct iwl_priv *priv, struct sk_buff *skb) spin_lock_irqsave(&priv->lock, flags); if (iwl_is_rfkill(priv)) { IWL_DEBUG_DROP(priv, "Dropping - RF KILL\n"); - goto drop_unlock; + goto drop_unlock_priv; } fc = hdr->frame_control; @@ -585,7 +585,7 @@ int iwlagn_tx_skb(struct iwl_priv *priv, struct sk_buff *skb) if (sta_id == IWL_INVALID_STATION) { IWL_DEBUG_DROP(priv, "Dropping - INVALID STATION: %pM\n", hdr->addr1); - goto drop_unlock; + goto drop_unlock_priv; } IWL_DEBUG_TX(priv, "station Id %d\n", sta_id); @@ -628,10 +628,10 @@ int iwlagn_tx_skb(struct iwl_priv *priv, struct sk_buff *skb) if (ieee80211_is_data_qos(fc)) { qc = ieee80211_get_qos_ctl(hdr); tid = qc[0] & IEEE80211_QOS_CTL_TID_MASK; - if (WARN_ON_ONCE(tid >= MAX_TID_COUNT)) { - spin_unlock(&priv->sta_lock); - goto drop_unlock; - } + + if (WARN_ON_ONCE(tid >= MAX_TID_COUNT)) + goto drop_unlock_sta; + seq_number = priv->stations[sta_id].tid[tid].seq_number; seq_number &= IEEE80211_SCTL_SEQ; hdr->seq_ctrl = hdr->seq_ctrl & @@ -649,18 +649,8 @@ int iwlagn_tx_skb(struct iwl_priv *priv, struct sk_buff *skb) txq = &priv->txq[txq_id]; q = &txq->q; - if (unlikely(iwl_queue_space(q) < q->high_mark)) { - spin_unlock(&priv->sta_lock); - goto drop_unlock; - } - - if (ieee80211_is_data_qos(fc)) { - priv->stations[sta_id].tid[tid].tfds_in_queue++; - if (!ieee80211_has_morefrags(fc)) - priv->stations[sta_id].tid[tid].seq_number = seq_number; - } - - spin_unlock(&priv->sta_lock); + if (unlikely(iwl_queue_space(q) < q->high_mark)) + goto drop_unlock_sta; /* Set up driver data for this TFD */ memset(&(txq->txb[q->write_ptr]), 0, sizeof(struct iwl_tx_info)); @@ -724,12 +714,10 @@ int iwlagn_tx_skb(struct iwl_priv *priv, struct sk_buff *skb) txcmd_phys = pci_map_single(priv->pci_dev, &out_cmd->hdr, firstlen, PCI_DMA_BIDIRECTIONAL); + if (unlikely(pci_dma_mapping_error(priv->pci_dev, txcmd_phys))) + goto drop_unlock_sta; dma_unmap_addr_set(out_meta, mapping, txcmd_phys); dma_unmap_len_set(out_meta, len, firstlen); - /* Add buffer containing Tx command and MAC(!) header to TFD's - * first entry */ - priv->cfg->ops->lib->txq_attach_buf_to_tfd(priv, txq, - txcmd_phys, firstlen, 1, 0); if (!ieee80211_has_morefrags(hdr->frame_control)) { txq->need_update = 1; @@ -744,10 +732,30 @@ int iwlagn_tx_skb(struct iwl_priv *priv, struct sk_buff *skb) if (secondlen > 0) { phys_addr = pci_map_single(priv->pci_dev, skb->data + hdr_len, secondlen, PCI_DMA_TODEVICE); + if (unlikely(pci_dma_mapping_error(priv->pci_dev, phys_addr))) { + pci_unmap_single(priv->pci_dev, + dma_unmap_addr(out_meta, mapping), + dma_unmap_len(out_meta, len), + PCI_DMA_BIDIRECTIONAL); + goto drop_unlock_sta; + } + } + + if (ieee80211_is_data_qos(fc)) { + priv->stations[sta_id].tid[tid].tfds_in_queue++; + if (!ieee80211_has_morefrags(fc)) + priv->stations[sta_id].tid[tid].seq_number = seq_number; + } + + spin_unlock(&priv->sta_lock); + + /* Attach buffers to TFD */ + priv->cfg->ops->lib->txq_attach_buf_to_tfd(priv, txq, + txcmd_phys, firstlen, 1, 0); + if (secondlen > 0) priv->cfg->ops->lib->txq_attach_buf_to_tfd(priv, txq, phys_addr, secondlen, 0, 0); - } scratch_phys = txcmd_phys + sizeof(struct iwl_cmd_header) + offsetof(struct iwl_tx_cmd, scratch); @@ -813,7 +821,9 @@ int iwlagn_tx_skb(struct iwl_priv *priv, struct sk_buff *skb) return 0; -drop_unlock: +drop_unlock_sta: + spin_unlock(&priv->sta_lock); +drop_unlock_priv: spin_unlock_irqrestore(&priv->lock, flags); return -1; } diff --git a/drivers/net/wireless/iwlwifi/iwl-tx.c b/drivers/net/wireless/iwlwifi/iwl-tx.c index 5a7cd17..e69597e 100644 --- a/drivers/net/wireless/iwlwifi/iwl-tx.c +++ b/drivers/net/wireless/iwlwifi/iwl-tx.c @@ -500,7 +500,6 @@ int iwl_enqueue_hcmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd) } memset(out_meta, 0, sizeof(*out_meta)); /* re-initialize to NULL */ - out_meta->flags = cmd->flags | CMD_MAPPED; if (cmd->flags & CMD_WANT_SKB) out_meta->source = cmd; if (cmd->flags & CMD_ASYNC) @@ -538,13 +537,20 @@ int iwl_enqueue_hcmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd) q->write_ptr, idx, priv->cmd_queue); } #endif - txq->need_update = 1; - phys_addr = pci_map_single(priv->pci_dev, &out_cmd->hdr, fix_size, PCI_DMA_BIDIRECTIONAL); + if (unlikely(pci_dma_mapping_error(priv->pci_dev, phys_addr))) { + idx = -ENOMEM; + goto out; + } + dma_unmap_addr_set(out_meta, mapping, phys_addr); dma_unmap_len_set(out_meta, len, fix_size); + out_meta->flags = cmd->flags | CMD_MAPPED; + + txq->need_update = 1; + trace_iwlwifi_dev_hcmd(priv, &out_cmd->hdr, fix_size, cmd->flags); priv->cfg->ops->lib->txq_attach_buf_to_tfd(priv, txq, @@ -555,6 +561,7 @@ int iwl_enqueue_hcmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd) q->write_ptr = iwl_queue_inc_wrap(q->write_ptr, q->n_bd); iwl_txq_update_write_ptr(priv, txq); + out: spin_unlock_irqrestore(&priv->hcmd_lock, flags); return idx; } -- cgit v0.10.2 From ad638bd16d91012a512979327b5c17c867d260c6 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Fri, 6 May 2011 11:58:55 -0700 Subject: hamachi: Delete TX checksumming code commented out since 1999 TX checksumming support has been ifdef commented out of this driver for more than 10 years, and it makes references to aspects of the IPv4 stack from back then as well. If someone has one of these rare cards and wants to properly resurrect TX checksumming support, they can still get at this code in the version control history. Signed-off-by: David S. Miller diff --git a/drivers/net/hamachi.c b/drivers/net/hamachi.c index 80d25ed..f5fba73c 100644 --- a/drivers/net/hamachi.c +++ b/drivers/net/hamachi.c @@ -132,14 +132,8 @@ static int tx_params[MAX_UNITS] = {-1, -1, -1, -1, -1, -1, -1, -1}; /* * RX_CHECKSUM turns on card-generated receive checksum generation for * TCP and UDP packets. Otherwise the upper layers do the calculation. - * TX_CHECKSUM won't do anything too useful, even if it works. There's no - * easy mechanism by which to tell the TCP/UDP stack that it need not - * generate checksums for this device. But if somebody can find a way - * to get that to work, most of the card work is in here already. * 3/10/1999 Pete Wyckoff */ -#undef TX_CHECKSUM -#define RX_CHECKSUM /* Operational parameters that usually are not changed. */ /* Time in jiffies before concluding the transmitter is hung. */ @@ -630,11 +624,6 @@ static int __devinit hamachi_init_one (struct pci_dev *pdev, SET_NETDEV_DEV(dev, &pdev->dev); -#ifdef TX_CHECKSUM - printk("check that skbcopy in ip_queue_xmit isn't happening\n"); - dev->hard_header_len += 8; /* for cksum tag */ -#endif - for (i = 0; i < 6; i++) dev->dev_addr[i] = 1 ? read_eeprom(ioaddr, 4 + i) : readb(ioaddr + StationAddr + i); @@ -937,11 +926,7 @@ static int hamachi_open(struct net_device *dev) /* always 1, takes no more time to do it */ writew(0x0001, ioaddr + RxChecksum); -#ifdef TX_CHECKSUM - writew(0x0001, ioaddr + TxChecksum); -#else writew(0x0000, ioaddr + TxChecksum); -#endif writew(0x8000, ioaddr + MACCnfg); /* Soft reset the MAC */ writew(0x215F, ioaddr + MACCnfg); writew(0x000C, ioaddr + FrameGap0); @@ -1226,40 +1211,6 @@ static void hamachi_init_ring(struct net_device *dev) } -#ifdef TX_CHECKSUM -#define csum_add(it, val) \ -do { \ - it += (u16) (val); \ - if (it & 0xffff0000) { \ - it &= 0xffff; \ - ++it; \ - } \ -} while (0) - /* printk("add %04x --> %04x\n", val, it); \ */ - -/* uh->len already network format, do not swap */ -#define pseudo_csum_udp(sum,ih,uh) do { \ - sum = 0; \ - csum_add(sum, (ih)->saddr >> 16); \ - csum_add(sum, (ih)->saddr & 0xffff); \ - csum_add(sum, (ih)->daddr >> 16); \ - csum_add(sum, (ih)->daddr & 0xffff); \ - csum_add(sum, cpu_to_be16(IPPROTO_UDP)); \ - csum_add(sum, (uh)->len); \ -} while (0) - -/* swap len */ -#define pseudo_csum_tcp(sum,ih,len) do { \ - sum = 0; \ - csum_add(sum, (ih)->saddr >> 16); \ - csum_add(sum, (ih)->saddr & 0xffff); \ - csum_add(sum, (ih)->daddr >> 16); \ - csum_add(sum, (ih)->daddr & 0xffff); \ - csum_add(sum, cpu_to_be16(IPPROTO_TCP)); \ - csum_add(sum, htons(len)); \ -} while (0) -#endif - static netdev_tx_t hamachi_start_xmit(struct sk_buff *skb, struct net_device *dev) { @@ -1292,36 +1243,6 @@ static netdev_tx_t hamachi_start_xmit(struct sk_buff *skb, hmp->tx_skbuff[entry] = skb; -#ifdef TX_CHECKSUM - { - /* tack on checksum tag */ - u32 tagval = 0; - struct ethhdr *eh = (struct ethhdr *)skb->data; - if (eh->h_proto == cpu_to_be16(ETH_P_IP)) { - struct iphdr *ih = (struct iphdr *)((char *)eh + ETH_HLEN); - if (ih->protocol == IPPROTO_UDP) { - struct udphdr *uh - = (struct udphdr *)((char *)ih + ih->ihl*4); - u32 offset = ((unsigned char *)uh + 6) - skb->data; - u32 pseudo; - pseudo_csum_udp(pseudo, ih, uh); - pseudo = htons(pseudo); - printk("udp cksum was %04x, sending pseudo %04x\n", - uh->check, pseudo); - uh->check = 0; /* zero out uh->check before card calc */ - /* - * start at 14 (skip ethhdr), store at offset (uh->check), - * use pseudo value given. - */ - tagval = (14 << 24) | (offset << 16) | pseudo; - } else if (ih->protocol == IPPROTO_TCP) { - printk("tcp, no auto cksum\n"); - } - } - *(u32 *)skb_push(skb, 8) = tagval; - } -#endif - hmp->tx_ring[entry].addr = cpu_to_leXX(pci_map_single(hmp->pci_dev, skb->data, skb->len, PCI_DMA_TODEVICE)); -- cgit v0.10.2 From a294865978b701e4d0d90135672749531b9a900d Mon Sep 17 00:00:00 2001 From: Dan Rosenberg Date: Fri, 6 May 2011 03:27:18 +0000 Subject: dccp: handle invalid feature options length A length of zero (after subtracting two for the type and len fields) for the DCCPO_{CHANGE,CONFIRM}_{L,R} options will cause an underflow due to the subtraction. The subsequent code may read past the end of the options value buffer when parsing. I'm unsure of what the consequences of this might be, but it's probably not good. Signed-off-by: Dan Rosenberg Cc: stable@kernel.org Acked-by: Gerrit Renker Signed-off-by: David S. Miller diff --git a/net/dccp/options.c b/net/dccp/options.c index f06ffcf..4b2ab65 100644 --- a/net/dccp/options.c +++ b/net/dccp/options.c @@ -123,6 +123,8 @@ int dccp_parse_options(struct sock *sk, struct dccp_request_sock *dreq, case DCCPO_CHANGE_L ... DCCPO_CONFIRM_R: if (pkt_type == DCCP_PKT_DATA) /* RFC 4340, 6 */ break; + if (len == 0) + goto out_invalid_option; rc = dccp_feat_parse_options(sk, dreq, mandatory, opt, *value, value + 1, len - 1); if (rc) -- cgit v0.10.2 From e328d410826d52e9ee348aff9064c4a207f2adb1 Mon Sep 17 00:00:00 2001 From: Roland Dreier Date: Fri, 6 May 2011 08:32:53 +0000 Subject: vmxnet3: Consistently disable irqs when taking adapter->cmd_lock Using the vmxnet3 driver produces a lockdep warning because vmxnet3_set_mc(), which is called with mc->mca_lock held, takes adapter->cmd_lock. However, there are a couple of places where adapter->cmd_lock is taken with softirqs enabled, lockdep warns that a softirq that tries to take mc->mca_lock could happen while adapter->cmd_lock is held, leading to an AB-BA deadlock. I'm not sure if this is a real potential deadlock or not, but the simplest and best fix seems to be simply to make sure we take cmd_lock with spin_lock_irqsave() everywhere -- the places with plain spin_lock just look like oversights. The full enormous lockdep warning is: ========================================================= [ INFO: possible irq lock inversion dependency detected ] 2.6.39-rc6+ #1 --------------------------------------------------------- ifconfig/567 just changed the state of lock: (&(&mc->mca_lock)->rlock){+.-...}, at: [] mld_ifc_timer_expire+0xff/0x280 but this lock took another, SOFTIRQ-unsafe lock in the past: (&(&adapter->cmd_lock)->rlock){+.+...} and interrupts could create inverse lock ordering between them. other info that might help us debug this: 4 locks held by ifconfig/567: #0: (rtnl_mutex){+.+.+.}, at: [] rtnl_lock+0x17/0x20 #1: ((inetaddr_chain).rwsem){.+.+.+}, at: [] __blocking_notifier_call_chain+0x5f/0xb0 #2: (&idev->mc_ifc_timer){+.-...}, at: [] run_timer_softirq+0xeb/0x3f0 #3: (&ndev->lock){++.-..}, at: [] mld_ifc_timer_expire+0x32/0x280 the shortest dependencies between 2nd lock and 1st lock: -> (&(&adapter->cmd_lock)->rlock){+.+...} ops: 11 { HARDIRQ-ON-W at: [] __lock_acquire+0x7f6/0x1e10 [] lock_acquire+0x9d/0x130 [] _raw_spin_lock+0x36/0x70 [] vmxnet3_alloc_intr_resources+0x22/0x230 [vmxnet3] [] vmxnet3_probe_device+0x5f6/0x15c5 [vmxnet3] [] local_pci_probe+0x5f/0xd0 [] pci_device_probe+0x119/0x120 [] driver_probe_device+0x96/0x1c0 [] __driver_attach+0xab/0xb0 [] bus_for_each_dev+0x5e/0x90 [] driver_attach+0x1e/0x20 [] bus_add_driver+0xc8/0x290 [] driver_register+0x76/0x140 [] __pci_register_driver+0x66/0xe0 [] serio_raw_poll+0x3a/0x60 [serio_raw] [] do_one_initcall+0x45/0x190 [] sys_init_module+0xfb/0x250 [] system_call_fastpath+0x16/0x1b SOFTIRQ-ON-W at: [] __lock_acquire+0x827/0x1e10 [] lock_acquire+0x9d/0x130 [] _raw_spin_lock+0x36/0x70 [] vmxnet3_alloc_intr_resources+0x22/0x230 [vmxnet3] [] vmxnet3_probe_device+0x5f6/0x15c5 [vmxnet3] [] local_pci_probe+0x5f/0xd0 [] pci_device_probe+0x119/0x120 [] driver_probe_device+0x96/0x1c0 [] __driver_attach+0xab/0xb0 [] bus_for_each_dev+0x5e/0x90 [] driver_attach+0x1e/0x20 [] bus_add_driver+0xc8/0x290 [] driver_register+0x76/0x140 [] __pci_register_driver+0x66/0xe0 [] serio_raw_poll+0x3a/0x60 [serio_raw] [] do_one_initcall+0x45/0x190 [] sys_init_module+0xfb/0x250 [] system_call_fastpath+0x16/0x1b INITIAL USE at: [] __lock_acquire+0x459/0x1e10 [] lock_acquire+0x9d/0x130 [] _raw_spin_lock+0x36/0x70 [] vmxnet3_alloc_intr_resources+0x22/0x230 [vmxnet3] [] vmxnet3_probe_device+0x5f6/0x15c5 [vmxnet3] [] local_pci_probe+0x5f/0xd0 [] pci_device_probe+0x119/0x120 [] driver_probe_device+0x96/0x1c0 [] __driver_attach+0xab/0xb0 [] bus_for_each_dev+0x5e/0x90 [] driver_attach+0x1e/0x20 [] bus_add_driver+0xc8/0x290 [] driver_register+0x76/0x140 [] __pci_register_driver+0x66/0xe0 [] serio_raw_poll+0x3a/0x60 [serio_raw] [] do_one_initcall+0x45/0x190 [] sys_init_module+0xfb/0x250 [] system_call_fastpath+0x16/0x1b } ... key at: [] __key.42516+0x0/0xffffffffffffda70 [vmxnet3] ... acquired at: [] lock_acquire+0x9d/0x130 [] _raw_spin_lock_irqsave+0x55/0xa0 [] vmxnet3_set_mc+0x97/0x1a0 [vmxnet3] [] __dev_set_rx_mode+0x40/0xb0 [] dev_set_rx_mode+0x30/0x50 [] __dev_open+0xc7/0x100 [] __dev_change_flags+0xa1/0x180 [] dev_change_flags+0x28/0x70 [] devinet_ioctl+0x730/0x800 [] inet_ioctl+0x88/0xa0 [] sock_do_ioctl+0x30/0x70 [] sock_ioctl+0x79/0x2f0 [] do_vfs_ioctl+0x98/0x570 [] sys_ioctl+0x91/0xa0 [] system_call_fastpath+0x16/0x1b -> (_xmit_ETHER){+.....} ops: 6 { HARDIRQ-ON-W at: [] __lock_acquire+0x7f6/0x1e10 [] lock_acquire+0x9d/0x130 [] _raw_spin_lock_bh+0x3b/0x70 [] __dev_mc_add+0x38/0x90 [] dev_mc_add+0x10/0x20 [] igmp6_group_added+0x10e/0x1b0 [] ipv6_dev_mc_inc+0x2cd/0x430 [] ipv6_add_dev+0x357/0x450 [] addrconf_notify+0x2f7/0xb10 [] notifier_call_chain+0x8c/0xc0 [] raw_notifier_call_chain+0x16/0x20 [] call_netdevice_notifiers+0x37/0x70 [] register_netdevice+0x244/0x2d0 [] register_netdev+0x3f/0x60 [] vmxnet3_probe_device+0x760/0x15c5 [vmxnet3] [] local_pci_probe+0x5f/0xd0 [] pci_device_probe+0x119/0x120 [] driver_probe_device+0x96/0x1c0 [] __driver_attach+0xab/0xb0 [] bus_for_each_dev+0x5e/0x90 [] driver_attach+0x1e/0x20 [] bus_add_driver+0xc8/0x290 [] driver_register+0x76/0x140 [] __pci_register_driver+0x66/0xe0 [] serio_raw_poll+0x3a/0x60 [serio_raw] [] do_one_initcall+0x45/0x190 [] sys_init_module+0xfb/0x250 [] system_call_fastpath+0x16/0x1b INITIAL USE at: [] __lock_acquire+0x459/0x1e10 [] lock_acquire+0x9d/0x130 [] _raw_spin_lock_bh+0x3b/0x70 [] __dev_mc_add+0x38/0x90 [] dev_mc_add+0x10/0x20 [] igmp6_group_added+0x10e/0x1b0 [] ipv6_dev_mc_inc+0x2cd/0x430 [] ipv6_add_dev+0x357/0x450 [] addrconf_notify+0x2f7/0xb10 [] notifier_call_chain+0x8c/0xc0 [] raw_notifier_call_chain+0x16/0x20 [] call_netdevice_notifiers+0x37/0x70 [] register_netdevice+0x244/0x2d0 [] register_netdev+0x3f/0x60 [] vmxnet3_probe_device+0x760/0x15c5 [vmxnet3] [] local_pci_probe+0x5f/0xd0 [] pci_device_probe+0x119/0x120 [] driver_probe_device+0x96/0x1c0 [] __driver_attach+0xab/0xb0 [] bus_for_each_dev+0x5e/0x90 [] driver_attach+0x1e/0x20 [] bus_add_driver+0xc8/0x290 [] driver_register+0x76/0x140 [] __pci_register_driver+0x66/0xe0 [] serio_raw_poll+0x3a/0x60 [serio_raw] [] do_one_initcall+0x45/0x190 [] sys_init_module+0xfb/0x250 [] system_call_fastpath+0x16/0x1b } ... key at: [] netdev_addr_lock_key+0x8/0x1e0 ... acquired at: [] lock_acquire+0x9d/0x130 [] _raw_spin_lock_bh+0x3b/0x70 [] __dev_mc_add+0x38/0x90 [] dev_mc_add+0x10/0x20 [] igmp6_group_added+0x10e/0x1b0 [] ipv6_dev_mc_inc+0x2cd/0x430 [] ipv6_add_dev+0x357/0x450 [] addrconf_notify+0x2f7/0xb10 [] notifier_call_chain+0x8c/0xc0 [] raw_notifier_call_chain+0x16/0x20 [] call_netdevice_notifiers+0x37/0x70 [] register_netdevice+0x244/0x2d0 [] register_netdev+0x3f/0x60 [] vmxnet3_probe_device+0x760/0x15c5 [vmxnet3] [] local_pci_probe+0x5f/0xd0 [] pci_device_probe+0x119/0x120 [] driver_probe_device+0x96/0x1c0 [] __driver_attach+0xab/0xb0 [] bus_for_each_dev+0x5e/0x90 [] driver_attach+0x1e/0x20 [] bus_add_driver+0xc8/0x290 [] driver_register+0x76/0x140 [] __pci_register_driver+0x66/0xe0 [] serio_raw_poll+0x3a/0x60 [serio_raw] [] do_one_initcall+0x45/0x190 [] sys_init_module+0xfb/0x250 [] system_call_fastpath+0x16/0x1b -> (&(&mc->mca_lock)->rlock){+.-...} ops: 6 { HARDIRQ-ON-W at: [] __lock_acquire+0x7f6/0x1e10 [] lock_acquire+0x9d/0x130 [] _raw_spin_lock_bh+0x3b/0x70 [] igmp6_group_added+0x45/0x1b0 [] ipv6_dev_mc_inc+0x2cd/0x430 [] ipv6_add_dev+0x357/0x450 [] addrconf_init+0x4e/0x183 [] inet6_init+0x191/0x2a6 [] do_one_initcall+0x45/0x190 [] kernel_init+0xe3/0x168 [] kernel_thread_helper+0x4/0x10 IN-SOFTIRQ-W at: [] __lock_acquire+0x7ce/0x1e10 [] lock_acquire+0x9d/0x130 [] _raw_spin_lock_bh+0x3b/0x70 [] mld_ifc_timer_expire+0xff/0x280 [] run_timer_softirq+0x179/0x3f0 [] __do_softirq+0xc0/0x210 [] call_softirq+0x1c/0x30 [] do_softirq+0xad/0xe0 [] irq_exit+0x9e/0xb0 [] smp_apic_timer_interrupt+0x70/0x9b [] apic_timer_interrupt+0x13/0x20 [] rt_do_flush+0x87/0x2a0 [] rt_cache_flush+0x46/0x60 [] fib_disable_ip+0x40/0x60 [] fib_inetaddr_event+0xd7/0xe0 [] notifier_call_chain+0x8c/0xc0 [] __blocking_notifier_call_chain+0x78/0xb0 [] blocking_notifier_call_chain+0x16/0x20 [] __inet_del_ifa+0xf1/0x2e0 [] inet_del_ifa+0x13/0x20 [] devinet_ioctl+0x501/0x800 [] inet_ioctl+0x88/0xa0 [] sock_do_ioctl+0x30/0x70 [] sock_ioctl+0x79/0x2f0 [] do_vfs_ioctl+0x98/0x570 [] sys_ioctl+0x91/0xa0 [] system_call_fastpath+0x16/0x1b INITIAL USE at: [] __lock_acquire+0x459/0x1e10 [] lock_acquire+0x9d/0x130 [] _raw_spin_lock_bh+0x3b/0x70 [] igmp6_group_added+0x45/0x1b0 [] ipv6_dev_mc_inc+0x2cd/0x430 [] ipv6_add_dev+0x357/0x450 [] addrconf_init+0x4e/0x183 [] inet6_init+0x191/0x2a6 [] do_one_initcall+0x45/0x190 [] kernel_init+0xe3/0x168 [] kernel_thread_helper+0x4/0x10 } ... key at: [] __key.40877+0x0/0x8 ... acquired at: [] check_usage_forwards+0x9c/0x110 [] mark_lock+0x19c/0x400 [] __lock_acquire+0x7ce/0x1e10 [] lock_acquire+0x9d/0x130 [] _raw_spin_lock_bh+0x3b/0x70 [] mld_ifc_timer_expire+0xff/0x280 [] run_timer_softirq+0x179/0x3f0 [] __do_softirq+0xc0/0x210 [] call_softirq+0x1c/0x30 [] do_softirq+0xad/0xe0 [] irq_exit+0x9e/0xb0 [] smp_apic_timer_interrupt+0x70/0x9b [] apic_timer_interrupt+0x13/0x20 [] rt_do_flush+0x87/0x2a0 [] rt_cache_flush+0x46/0x60 [] fib_disable_ip+0x40/0x60 [] fib_inetaddr_event+0xd7/0xe0 [] notifier_call_chain+0x8c/0xc0 [] __blocking_notifier_call_chain+0x78/0xb0 [] blocking_notifier_call_chain+0x16/0x20 [] __inet_del_ifa+0xf1/0x2e0 [] inet_del_ifa+0x13/0x20 [] devinet_ioctl+0x501/0x800 [] inet_ioctl+0x88/0xa0 [] sock_do_ioctl+0x30/0x70 [] sock_ioctl+0x79/0x2f0 [] do_vfs_ioctl+0x98/0x570 [] sys_ioctl+0x91/0xa0 [] system_call_fastpath+0x16/0x1b stack backtrace: Pid: 567, comm: ifconfig Not tainted 2.6.39-rc6+ #1 Call Trace: [] print_irq_inversion_bug+0x146/0x170 [] ? print_irq_inversion_bug+0x170/0x170 [] check_usage_forwards+0x9c/0x110 [] mark_lock+0x19c/0x400 [] __lock_acquire+0x7ce/0x1e10 [] ? mark_lock+0x1f3/0x400 [] ? __lock_acquire+0xf07/0x1e10 [] ? native_sched_clock+0x15/0x70 [] lock_acquire+0x9d/0x130 [] ? mld_ifc_timer_expire+0xff/0x280 [] ? lock_release_holdtime+0x3d/0x1a0 [] _raw_spin_lock_bh+0x3b/0x70 [] ? mld_ifc_timer_expire+0xff/0x280 [] ? _raw_spin_unlock+0x2b/0x40 [] mld_ifc_timer_expire+0xff/0x280 [] run_timer_softirq+0x179/0x3f0 [] ? run_timer_softirq+0xeb/0x3f0 [] ? sched_clock+0x9/0x10 [] ? mld_gq_timer_expire+0x30/0x30 [] __do_softirq+0xc0/0x210 [] ? tick_program_event+0x1f/0x30 [] call_softirq+0x1c/0x30 [] do_softirq+0xad/0xe0 [] irq_exit+0x9e/0xb0 [] smp_apic_timer_interrupt+0x70/0x9b [] apic_timer_interrupt+0x13/0x20 [] ? retint_restore_args+0x13/0x13 [] ? lock_is_held+0x17/0xd0 [] rt_do_flush+0x87/0x2a0 [] rt_cache_flush+0x46/0x60 [] fib_disable_ip+0x40/0x60 [] fib_inetaddr_event+0xd7/0xe0 [] notifier_call_chain+0x8c/0xc0 [] __blocking_notifier_call_chain+0x78/0xb0 [] blocking_notifier_call_chain+0x16/0x20 [] __inet_del_ifa+0xf1/0x2e0 [] inet_del_ifa+0x13/0x20 [] devinet_ioctl+0x501/0x800 [] ? local_clock+0x6f/0x80 [] ? do_page_fault+0x268/0x560 [] inet_ioctl+0x88/0xa0 [] sock_do_ioctl+0x30/0x70 [] sock_ioctl+0x79/0x2f0 [] ? __call_rcu+0xa7/0x190 [] do_vfs_ioctl+0x98/0x570 [] ? fget_light+0x33e/0x430 [] ? retint_swapgs+0x13/0x1b [] sys_ioctl+0x91/0xa0 [] system_call_fastpath+0x16/0x1b Signed-off-by: Roland Dreier Signed-off-by: Shreyas N Bhatewara Signed-off-by: Scott J. Goldman Signed-off-by: David S. Miller diff --git a/drivers/net/vmxnet3/vmxnet3_drv.c b/drivers/net/vmxnet3/vmxnet3_drv.c index 0d47c3a..c16ed96 100644 --- a/drivers/net/vmxnet3/vmxnet3_drv.c +++ b/drivers/net/vmxnet3/vmxnet3_drv.c @@ -178,6 +178,7 @@ static void vmxnet3_process_events(struct vmxnet3_adapter *adapter) { int i; + unsigned long flags; u32 events = le32_to_cpu(adapter->shared->ecr); if (!events) return; @@ -190,10 +191,10 @@ vmxnet3_process_events(struct vmxnet3_adapter *adapter) /* Check if there is an error on xmit/recv queues */ if (events & (VMXNET3_ECR_TQERR | VMXNET3_ECR_RQERR)) { - spin_lock(&adapter->cmd_lock); + spin_lock_irqsave(&adapter->cmd_lock, flags); VMXNET3_WRITE_BAR1_REG(adapter, VMXNET3_REG_CMD, VMXNET3_CMD_GET_QUEUE_STATUS); - spin_unlock(&adapter->cmd_lock); + spin_unlock_irqrestore(&adapter->cmd_lock, flags); for (i = 0; i < adapter->num_tx_queues; i++) if (adapter->tqd_start[i].status.stopped) @@ -2733,13 +2734,14 @@ static void vmxnet3_alloc_intr_resources(struct vmxnet3_adapter *adapter) { u32 cfg; + unsigned long flags; /* intr settings */ - spin_lock(&adapter->cmd_lock); + spin_lock_irqsave(&adapter->cmd_lock, flags); VMXNET3_WRITE_BAR1_REG(adapter, VMXNET3_REG_CMD, VMXNET3_CMD_GET_CONF_INTR); cfg = VMXNET3_READ_BAR1_REG(adapter, VMXNET3_REG_CMD); - spin_unlock(&adapter->cmd_lock); + spin_unlock_irqrestore(&adapter->cmd_lock, flags); adapter->intr.type = cfg & 0x3; adapter->intr.mask_mode = (cfg >> 2) & 0x3; -- cgit v0.10.2 From a3a4a5acd3bd2f6f1e102e1f1b9d2e2bb320a7fd Mon Sep 17 00:00:00 2001 From: Arjan van de Ven Date: Thu, 5 May 2011 23:55:18 -0400 Subject: Regression: partial revert "tracing: Remove lock_depth from event entry" This partially reverts commit e6e1e2593592a8f6f6380496655d8c6f67431266. That commit changed the structure layout of the trace structure, which in turn broke PowerTOP (1.9x generation) quite badly. I appreciate not wanting to expose the variable in question, and PowerTOP was not using it, so I've replaced the variable with just a padding field - that way if in the future a new field is needed it can just use this padding field. Signed-off-by: Arjan van de Ven Signed-off-by: Linus Torvalds diff --git a/include/linux/ftrace_event.h b/include/linux/ftrace_event.h index 22b32af..b5a550a 100644 --- a/include/linux/ftrace_event.h +++ b/include/linux/ftrace_event.h @@ -37,6 +37,7 @@ struct trace_entry { unsigned char flags; unsigned char preempt_count; int pid; + int padding; }; #define FTRACE_MAX_EVENT \ diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c index d38c16a..1cb49be 100644 --- a/kernel/trace/trace.c +++ b/kernel/trace/trace.c @@ -1110,6 +1110,7 @@ tracing_generic_entry_update(struct trace_entry *entry, unsigned long flags, entry->preempt_count = pc & 0xff; entry->pid = (tsk) ? tsk->pid : 0; + entry->padding = 0; entry->flags = #ifdef CONFIG_TRACE_IRQFLAGS_SUPPORT (irqs_disabled_flags(flags) ? TRACE_FLAG_IRQS_OFF : 0) | diff --git a/kernel/trace/trace_events.c b/kernel/trace/trace_events.c index e88f74f..2fe1103 100644 --- a/kernel/trace/trace_events.c +++ b/kernel/trace/trace_events.c @@ -116,6 +116,7 @@ static int trace_define_common_fields(void) __common_field(unsigned char, flags); __common_field(unsigned char, preempt_count); __common_field(int, pid); + __common_field(int, padding); return ret; } -- cgit v0.10.2 From bdc712b4c2baf9515887de3a52e7ecd89fafc0c7 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Fri, 6 May 2011 15:02:07 -0700 Subject: inet: Decrease overhead of on-stack inet_cork. When we fast path datagram sends to avoid locking by putting the inet_cork on the stack we use up lots of space that isn't necessary. This is because inet_cork contains a "struct flowi" which isn't used in these code paths. Split inet_cork to two parts, "inet_cork" and "inet_cork_full". Only the latter of which has the "struct flowi" and is what is stored in inet_sock. Signed-off-by: David S. Miller Acked-by: Eric Dumazet diff --git a/include/net/inet_sock.h b/include/net/inet_sock.h index ed2ba6e..caaff5f 100644 --- a/include/net/inet_sock.h +++ b/include/net/inet_sock.h @@ -96,17 +96,21 @@ static inline struct inet_request_sock *inet_rsk(const struct request_sock *sk) struct inet_cork { unsigned int flags; - unsigned int fragsize; + __be32 addr; struct ip_options *opt; + unsigned int fragsize; struct dst_entry *dst; int length; /* Total length of all frames */ - __be32 addr; - struct flowi fl; struct page *page; u32 off; u8 tx_flags; }; +struct inet_cork_full { + struct inet_cork base; + struct flowi fl; +}; + struct ip_mc_socklist; struct ipv6_pinfo; struct rtable; @@ -164,7 +168,7 @@ struct inet_sock { int mc_index; __be32 mc_addr; struct ip_mc_socklist __rcu *mc_list; - struct inet_cork cork; + struct inet_cork_full cork; }; #define IPCORK_OPT 1 /* ip-options has been held in ipcork.opt */ diff --git a/include/net/ip.h b/include/net/ip.h index 3a59bf9..095e392 100644 --- a/include/net/ip.h +++ b/include/net/ip.h @@ -132,7 +132,7 @@ extern struct sk_buff *ip_make_skb(struct sock *sk, static inline struct sk_buff *ip_finish_skb(struct sock *sk) { - return __ip_make_skb(sk, &sk->sk_write_queue, &inet_sk(sk)->cork); + return __ip_make_skb(sk, &sk->sk_write_queue, &inet_sk(sk)->cork.base); } /* datagram.c */ diff --git a/net/ipv4/ip_output.c b/net/ipv4/ip_output.c index db38c18..eb0647a 100644 --- a/net/ipv4/ip_output.c +++ b/net/ipv4/ip_output.c @@ -1096,14 +1096,14 @@ int ip_append_data(struct sock *sk, return 0; if (skb_queue_empty(&sk->sk_write_queue)) { - err = ip_setup_cork(sk, &inet->cork, ipc, rtp); + err = ip_setup_cork(sk, &inet->cork.base, ipc, rtp); if (err) return err; } else { transhdrlen = 0; } - return __ip_append_data(sk, &sk->sk_write_queue, &inet->cork, getfrag, + return __ip_append_data(sk, &sk->sk_write_queue, &inet->cork.base, getfrag, from, length, transhdrlen, flags); } @@ -1114,6 +1114,7 @@ ssize_t ip_append_page(struct sock *sk, struct page *page, struct sk_buff *skb; struct rtable *rt; struct ip_options *opt = NULL; + struct inet_cork *cork; int hh_len; int mtu; int len; @@ -1129,20 +1130,21 @@ ssize_t ip_append_page(struct sock *sk, struct page *page, if (skb_queue_empty(&sk->sk_write_queue)) return -EINVAL; - rt = (struct rtable *)inet->cork.dst; - if (inet->cork.flags & IPCORK_OPT) - opt = inet->cork.opt; + cork = &inet->cork.base; + rt = (struct rtable *)cork->dst; + if (cork->flags & IPCORK_OPT) + opt = cork->opt; if (!(rt->dst.dev->features&NETIF_F_SG)) return -EOPNOTSUPP; hh_len = LL_RESERVED_SPACE(rt->dst.dev); - mtu = inet->cork.fragsize; + mtu = cork->fragsize; fragheaderlen = sizeof(struct iphdr) + (opt ? opt->optlen : 0); maxfraglen = ((mtu - fragheaderlen) & ~7) + fragheaderlen; - if (inet->cork.length + size > 0xFFFF - fragheaderlen) { + if (cork->length + size > 0xFFFF - fragheaderlen) { ip_local_error(sk, EMSGSIZE, rt->rt_dst, inet->inet_dport, mtu); return -EMSGSIZE; } @@ -1150,7 +1152,7 @@ ssize_t ip_append_page(struct sock *sk, struct page *page, if ((skb = skb_peek_tail(&sk->sk_write_queue)) == NULL) return -EINVAL; - inet->cork.length += size; + cork->length += size; if ((size + skb->len > mtu) && (sk->sk_protocol == IPPROTO_UDP) && (rt->dst.dev->features & NETIF_F_UFO)) { @@ -1245,7 +1247,7 @@ ssize_t ip_append_page(struct sock *sk, struct page *page, return 0; error: - inet->cork.length -= size; + cork->length -= size; IP_INC_STATS(sock_net(sk), IPSTATS_MIB_OUTDISCARDS); return err; } @@ -1396,7 +1398,7 @@ static void __ip_flush_pending_frames(struct sock *sk, void ip_flush_pending_frames(struct sock *sk) { - __ip_flush_pending_frames(sk, &sk->sk_write_queue, &inet_sk(sk)->cork); + __ip_flush_pending_frames(sk, &sk->sk_write_queue, &inet_sk(sk)->cork.base); } struct sk_buff *ip_make_skb(struct sock *sk, diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c index 4cfbb24..9d4b165 100644 --- a/net/ipv6/ip6_output.c +++ b/net/ipv6/ip6_output.c @@ -1150,6 +1150,7 @@ int ip6_append_data(struct sock *sk, int getfrag(void *from, char *to, { struct inet_sock *inet = inet_sk(sk); struct ipv6_pinfo *np = inet6_sk(sk); + struct inet_cork *cork; struct sk_buff *skb; unsigned int maxfraglen, fragheaderlen; int exthdrlen; @@ -1163,6 +1164,7 @@ int ip6_append_data(struct sock *sk, int getfrag(void *from, char *to, if (flags&MSG_PROBE) return 0; + cork = &inet->cork.base; if (skb_queue_empty(&sk->sk_write_queue)) { /* * setup for corking @@ -1202,7 +1204,7 @@ int ip6_append_data(struct sock *sk, int getfrag(void *from, char *to, /* need source address above miyazawa*/ } dst_hold(&rt->dst); - inet->cork.dst = &rt->dst; + cork->dst = &rt->dst; inet->cork.fl.u.ip6 = *fl6; np->cork.hop_limit = hlimit; np->cork.tclass = tclass; @@ -1212,10 +1214,10 @@ int ip6_append_data(struct sock *sk, int getfrag(void *from, char *to, if (np->frag_size) mtu = np->frag_size; } - inet->cork.fragsize = mtu; + cork->fragsize = mtu; if (dst_allfrag(rt->dst.path)) - inet->cork.flags |= IPCORK_ALLFRAG; - inet->cork.length = 0; + cork->flags |= IPCORK_ALLFRAG; + cork->length = 0; sk->sk_sndmsg_page = NULL; sk->sk_sndmsg_off = 0; exthdrlen = rt->dst.header_len + (opt ? opt->opt_flen : 0) - @@ -1223,12 +1225,12 @@ int ip6_append_data(struct sock *sk, int getfrag(void *from, char *to, length += exthdrlen; transhdrlen += exthdrlen; } else { - rt = (struct rt6_info *)inet->cork.dst; + rt = (struct rt6_info *)cork->dst; fl6 = &inet->cork.fl.u.ip6; opt = np->cork.opt; transhdrlen = 0; exthdrlen = 0; - mtu = inet->cork.fragsize; + mtu = cork->fragsize; } hh_len = LL_RESERVED_SPACE(rt->dst.dev); @@ -1238,7 +1240,7 @@ int ip6_append_data(struct sock *sk, int getfrag(void *from, char *to, maxfraglen = ((mtu - fragheaderlen) & ~7) + fragheaderlen - sizeof(struct frag_hdr); if (mtu <= sizeof(struct ipv6hdr) + IPV6_MAXPLEN) { - if (inet->cork.length + length > sizeof(struct ipv6hdr) + IPV6_MAXPLEN - fragheaderlen) { + if (cork->length + length > sizeof(struct ipv6hdr) + IPV6_MAXPLEN - fragheaderlen) { ipv6_local_error(sk, EMSGSIZE, fl6, mtu-exthdrlen); return -EMSGSIZE; } @@ -1267,7 +1269,7 @@ int ip6_append_data(struct sock *sk, int getfrag(void *from, char *to, * --yoshfuji */ - inet->cork.length += length; + cork->length += length; if (length > mtu) { int proto = sk->sk_protocol; if (dontfrag && (proto == IPPROTO_UDP || proto == IPPROTO_RAW)){ @@ -1292,7 +1294,7 @@ int ip6_append_data(struct sock *sk, int getfrag(void *from, char *to, while (length > 0) { /* Check if the remaining data fits into current packet. */ - copy = (inet->cork.length <= mtu && !(inet->cork.flags & IPCORK_ALLFRAG) ? mtu : maxfraglen) - skb->len; + copy = (cork->length <= mtu && !(cork->flags & IPCORK_ALLFRAG) ? mtu : maxfraglen) - skb->len; if (copy < length) copy = maxfraglen - skb->len; @@ -1317,7 +1319,7 @@ alloc_new_skb: * we know we need more fragment(s). */ datalen = length + fraggap; - if (datalen > (inet->cork.length <= mtu && !(inet->cork.flags & IPCORK_ALLFRAG) ? mtu : maxfraglen) - fragheaderlen) + if (datalen > (cork->length <= mtu && !(cork->flags & IPCORK_ALLFRAG) ? mtu : maxfraglen) - fragheaderlen) datalen = maxfraglen - fragheaderlen; fraglen = datalen + fragheaderlen; @@ -1481,7 +1483,7 @@ alloc_new_skb: } return 0; error: - inet->cork.length -= length; + cork->length -= length; IP6_INC_STATS(sock_net(sk), rt->rt6i_idev, IPSTATS_MIB_OUTDISCARDS); return err; } @@ -1497,10 +1499,10 @@ static void ip6_cork_release(struct inet_sock *inet, struct ipv6_pinfo *np) np->cork.opt = NULL; } - if (inet->cork.dst) { - dst_release(inet->cork.dst); - inet->cork.dst = NULL; - inet->cork.flags &= ~IPCORK_ALLFRAG; + if (inet->cork.base.dst) { + dst_release(inet->cork.base.dst); + inet->cork.base.dst = NULL; + inet->cork.base.flags &= ~IPCORK_ALLFRAG; } memset(&inet->cork.fl, 0, sizeof(inet->cork.fl)); } @@ -1515,7 +1517,7 @@ int ip6_push_pending_frames(struct sock *sk) struct net *net = sock_net(sk); struct ipv6hdr *hdr; struct ipv6_txoptions *opt = np->cork.opt; - struct rt6_info *rt = (struct rt6_info *)inet->cork.dst; + struct rt6_info *rt = (struct rt6_info *)inet->cork.base.dst; struct flowi6 *fl6 = &inet->cork.fl.u.ip6; unsigned char proto = fl6->flowi6_proto; int err = 0; diff --git a/net/ipv6/raw.c b/net/ipv6/raw.c index e5e5425..ae64984 100644 --- a/net/ipv6/raw.c +++ b/net/ipv6/raw.c @@ -542,8 +542,8 @@ static int rawv6_push_pending_frames(struct sock *sk, struct flowi6 *fl6, goto out; offset = rp->offset; - total_len = inet_sk(sk)->cork.length - (skb_network_header(skb) - - skb->data); + total_len = inet_sk(sk)->cork.base.length - (skb_network_header(skb) - + skb->data); if (offset >= total_len - 1) { err = -EINVAL; ip6_flush_pending_frames(sk); -- cgit v0.10.2 From b80d72261aec5e763a76497eba5fddc84833a154 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Fri, 6 May 2011 15:06:01 -0700 Subject: ipv4: Initialize on-stack cork more efficiently. ip_setup_cork() explicitly initializes every member of inet_cork except flags, addr, and opt. So we can simply set those three members to zero instead of using a memset() via an empty struct assignment. Signed-off-by: David S. Miller Acked-by: Eric Dumazet diff --git a/net/ipv4/ip_output.c b/net/ipv4/ip_output.c index eb0647a..5f5fe4f 100644 --- a/net/ipv4/ip_output.c +++ b/net/ipv4/ip_output.c @@ -1408,7 +1408,7 @@ struct sk_buff *ip_make_skb(struct sock *sk, struct ipcm_cookie *ipc, struct rtable **rtp, unsigned int flags) { - struct inet_cork cork = {}; + struct inet_cork cork; struct sk_buff_head queue; int err; @@ -1417,6 +1417,9 @@ struct sk_buff *ip_make_skb(struct sock *sk, __skb_queue_head_init(&queue); + cork.flags = 0; + cork.addr = 0; + cork.opt = 0; err = ip_setup_cork(sk, &cork, ipc, rtp); if (err) return ERR_PTR(err); -- cgit v0.10.2 From 706527280ec38fcdcd0466f10b607105fd23801b Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Fri, 6 May 2011 16:01:15 -0700 Subject: ipv4: Initialize cork->opt using NULL not 0. Noticed by Joe Perches. Signed-off-by: David S. Miller diff --git a/net/ipv4/ip_output.c b/net/ipv4/ip_output.c index 5f5fe4f..0a2f49a 100644 --- a/net/ipv4/ip_output.c +++ b/net/ipv4/ip_output.c @@ -1419,7 +1419,7 @@ struct sk_buff *ip_make_skb(struct sock *sk, cork.flags = 0; cork.addr = 0; - cork.opt = 0; + cork.opt = NULL; err = ip_setup_cork(sk, &cork, ipc, rtp); if (err) return ERR_PTR(err); -- cgit v0.10.2 From 5f54c8a00af20e5cf38c3e5ef2f59b6848a17cd9 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Wed, 4 May 2011 17:31:27 +0200 Subject: rtc: mxc: Initialize drvdata before registering device Commit f44f7f96a20 ("RTC: Initialize kernel state from RTC") uncovered an issue in a number of RTC drivers, where the drivers call rtc_device_register before initializing the device or platform drvdata. This frequently results in null pointer dereferences when the rtc_device_register immediately makes use of the rtc device, calling rtc_read_alarm. The solution is to ensure the drvdata is initialized prior to registering the rtc device. CC: Alessandro Zummo CC: Thomas Gleixner CC: rtc-linux@googlegroups.com Signed-off-by: Wolfram Sang [fixed up commit log -jstultz] Signed-off-by: John Stultz diff --git a/drivers/rtc/rtc-mxc.c b/drivers/rtc/rtc-mxc.c index 826ab64..d814417 100644 --- a/drivers/rtc/rtc-mxc.c +++ b/drivers/rtc/rtc-mxc.c @@ -418,14 +418,6 @@ static int __init mxc_rtc_probe(struct platform_device *pdev) goto exit_put_clk; } - rtc = rtc_device_register(pdev->name, &pdev->dev, &mxc_rtc_ops, - THIS_MODULE); - if (IS_ERR(rtc)) { - ret = PTR_ERR(rtc); - goto exit_put_clk; - } - - pdata->rtc = rtc; platform_set_drvdata(pdev, pdata); /* Configure and enable the RTC */ @@ -438,8 +430,19 @@ static int __init mxc_rtc_probe(struct platform_device *pdev) pdata->irq = -1; } + rtc = rtc_device_register(pdev->name, &pdev->dev, &mxc_rtc_ops, + THIS_MODULE); + if (IS_ERR(rtc)) { + ret = PTR_ERR(rtc); + goto exit_clr_drvdata; + } + + pdata->rtc = rtc; + return 0; +exit_clr_drvdata: + platform_set_drvdata(pdev, NULL); exit_put_clk: clk_disable(pdata->clk); clk_put(pdata->clk); -- cgit v0.10.2 From f4e708ae8e5f3eb98f4c53036c0a470717bbc709 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Thu, 5 May 2011 11:46:14 +0200 Subject: rtc: davinci: Initialize drvdata before registering device Commit f44f7f96a20 ("RTC: Initialize kernel state from RTC") uncovered an issue in a number of RTC drivers, where the drivers call rtc_device_register before initializing the device or platform drvdata. This frequently results in null pointer dereferences when the rtc_device_register immediately makes use of the rtc device, calling rtc_read_alarm. The solution is to ensure the drvdata is initialized prior to registering the rtc device. CC: Alessandro Zummo CC: Thomas Gleixner CC: rtc-linux@googlegroups.com Signed-off-by: Wolfram Sang [fixed up commit log -jstultz] Signed-off-by: John Stultz diff --git a/drivers/rtc/rtc-davinci.c b/drivers/rtc/rtc-davinci.c index 8d46838..755e1fe 100644 --- a/drivers/rtc/rtc-davinci.c +++ b/drivers/rtc/rtc-davinci.c @@ -524,6 +524,8 @@ static int __init davinci_rtc_probe(struct platform_device *pdev) goto fail2; } + platform_set_drvdata(pdev, davinci_rtc); + davinci_rtc->rtc = rtc_device_register(pdev->name, &pdev->dev, &davinci_rtc_ops, THIS_MODULE); if (IS_ERR(davinci_rtc->rtc)) { @@ -553,8 +555,6 @@ static int __init davinci_rtc_probe(struct platform_device *pdev) rtcss_write(davinci_rtc, PRTCSS_RTC_CCTRL_CAEN, PRTCSS_RTC_CCTRL); - platform_set_drvdata(pdev, davinci_rtc); - device_init_wakeup(&pdev->dev, 0); return 0; @@ -562,6 +562,7 @@ static int __init davinci_rtc_probe(struct platform_device *pdev) fail4: rtc_device_unregister(davinci_rtc->rtc); fail3: + platform_set_drvdata(pdev, NULL); iounmap(davinci_rtc->base); fail2: release_mem_region(davinci_rtc->pbase, davinci_rtc->base_size); -- cgit v0.10.2 From 92d921c5def1a7b1411bc54859c0771b2cf2c08d Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Thu, 5 May 2011 11:46:15 +0200 Subject: rtc: ep93xx: Initialize drvdata before registering device Commit f44f7f96a20 ("RTC: Initialize kernel state from RTC") uncovered an issue in a number of RTC drivers, where the drivers call rtc_device_register before initializing the device or platform drvdata. This frequently results in null pointer dereferences when the rtc_device_register immediately makes use of the rtc device, calling rtc_read_alarm. The solution is to ensure the drvdata is initialized prior to registering the rtc device. CC: Alessandro Zummo CC: Thomas Gleixner CC: rtc-linux@googlegroups.com Signed-off-by: Wolfram Sang [Fixed up commit log -jstultz] Signed-off-by: John Stultz diff --git a/drivers/rtc/rtc-ep93xx.c b/drivers/rtc/rtc-ep93xx.c index 11ae64d..335551d 100644 --- a/drivers/rtc/rtc-ep93xx.c +++ b/drivers/rtc/rtc-ep93xx.c @@ -151,6 +151,7 @@ static int __init ep93xx_rtc_probe(struct platform_device *pdev) return -ENXIO; pdev->dev.platform_data = ep93xx_rtc; + platform_set_drvdata(pdev, rtc); rtc = rtc_device_register(pdev->name, &pdev->dev, &ep93xx_rtc_ops, THIS_MODULE); @@ -159,8 +160,6 @@ static int __init ep93xx_rtc_probe(struct platform_device *pdev) goto exit; } - platform_set_drvdata(pdev, rtc); - err = sysfs_create_group(&pdev->dev.kobj, &ep93xx_rtc_sysfs_files); if (err) goto fail; @@ -168,9 +167,9 @@ static int __init ep93xx_rtc_probe(struct platform_device *pdev) return 0; fail: - platform_set_drvdata(pdev, NULL); rtc_device_unregister(rtc); exit: + platform_set_drvdata(pdev, NULL); pdev->dev.platform_data = NULL; return err; } -- cgit v0.10.2 From 9a281a677c1dbf25943b5bc3225de21fcb4945ae Mon Sep 17 00:00:00 2001 From: John Stultz Date: Fri, 6 May 2011 17:21:12 -0700 Subject: rtc: ds1286: Initialize drvdata before registering device Commit f44f7f96a20 ("RTC: Initialize kernel state from RTC") uncovered an issue in a number of RTC drivers, where the drivers call rtc_device_register before initializing the device or platform drvdata. This frequently results in null pointer dereferences when the rtc_device_register immediately makes use of the rtc device, calling rtc_read_alarm. The solution is to ensure the drvdata is initialized prior to registering the rtc device. CC: Wolfram Sang CC: Alessandro Zummo CC: Thomas Gleixner CC: rtc-linux@googlegroups.com Signed-off-by: John Stultz diff --git a/drivers/rtc/rtc-ds1286.c b/drivers/rtc/rtc-ds1286.c index 60ce696..47e681d 100644 --- a/drivers/rtc/rtc-ds1286.c +++ b/drivers/rtc/rtc-ds1286.c @@ -355,6 +355,7 @@ static int __devinit ds1286_probe(struct platform_device *pdev) goto out; } spin_lock_init(&priv->lock); + platform_set_drvdata(pdev, priv); rtc = rtc_device_register("ds1286", &pdev->dev, &ds1286_ops, THIS_MODULE); if (IS_ERR(rtc)) { @@ -362,7 +363,6 @@ static int __devinit ds1286_probe(struct platform_device *pdev) goto out; } priv->rtc = rtc; - platform_set_drvdata(pdev, priv); return 0; out: -- cgit v0.10.2 From 0078bff5283d1fd6417b840eda6dab912b7a5560 Mon Sep 17 00:00:00 2001 From: Jan Kara Date: Fri, 29 Apr 2011 00:24:29 +0200 Subject: Allow setting of number of raw devices as a module parameter Allow setting of maximal number of raw devices as a module parameter. This requires changing of static array into a vmalloced one (the array is going to be too large for kmalloc). Signed-off-by: Jan Kara Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/char/Kconfig b/drivers/char/Kconfig index ad59b4e..49502bc 100644 --- a/drivers/char/Kconfig +++ b/drivers/char/Kconfig @@ -523,7 +523,7 @@ config RAW_DRIVER with the O_DIRECT flag. config MAX_RAW_DEVS - int "Maximum number of RAW devices to support (1-8192)" + int "Maximum number of RAW devices to support (1-65536)" depends on RAW_DRIVER default "256" help diff --git a/drivers/char/raw.c b/drivers/char/raw.c index b4b9d5a..6f9db62 100644 --- a/drivers/char/raw.c +++ b/drivers/char/raw.c @@ -21,6 +21,7 @@ #include #include #include +#include #include @@ -30,10 +31,15 @@ struct raw_device_data { }; static struct class *raw_class; -static struct raw_device_data raw_devices[MAX_RAW_MINORS]; +static struct raw_device_data *raw_devices; static DEFINE_MUTEX(raw_mutex); static const struct file_operations raw_ctl_fops; /* forward declaration */ +static int max_raw_minors = MAX_RAW_MINORS; + +module_param(max_raw_minors, int, 0); +MODULE_PARM_DESC(max_raw_minors, "Maximum number of raw devices (1-65536)"); + /* * Open/close code for raw IO. * @@ -125,7 +131,7 @@ static int bind_set(int number, u64 major, u64 minor) struct raw_device_data *rawdev; int err = 0; - if (number <= 0 || number >= MAX_RAW_MINORS) + if (number <= 0 || number >= max_raw_minors) return -EINVAL; if (MAJOR(dev) != major || MINOR(dev) != minor) @@ -312,12 +318,26 @@ static int __init raw_init(void) dev_t dev = MKDEV(RAW_MAJOR, 0); int ret; - ret = register_chrdev_region(dev, MAX_RAW_MINORS, "raw"); + if (max_raw_minors < 1 || max_raw_minors > 65536) { + printk(KERN_WARNING "raw: invalid max_raw_minors (must be" + " between 1 and 65536), using %d\n", MAX_RAW_MINORS); + max_raw_minors = MAX_RAW_MINORS; + } + + raw_devices = vmalloc(sizeof(struct raw_device_data) * max_raw_minors); + if (!raw_devices) { + printk(KERN_ERR "Not enough memory for raw device structures\n"); + ret = -ENOMEM; + goto error; + } + memset(raw_devices, 0, sizeof(struct raw_device_data) * max_raw_minors); + + ret = register_chrdev_region(dev, max_raw_minors, "raw"); if (ret) goto error; cdev_init(&raw_cdev, &raw_fops); - ret = cdev_add(&raw_cdev, dev, MAX_RAW_MINORS); + ret = cdev_add(&raw_cdev, dev, max_raw_minors); if (ret) { kobject_put(&raw_cdev.kobj); goto error_region; @@ -336,8 +356,9 @@ static int __init raw_init(void) return 0; error_region: - unregister_chrdev_region(dev, MAX_RAW_MINORS); + unregister_chrdev_region(dev, max_raw_minors); error: + vfree(raw_devices); return ret; } @@ -346,7 +367,7 @@ static void __exit raw_exit(void) device_destroy(raw_class, MKDEV(RAW_MAJOR, 0)); class_destroy(raw_class); cdev_del(&raw_cdev); - unregister_chrdev_region(MKDEV(RAW_MAJOR, 0), MAX_RAW_MINORS); + unregister_chrdev_region(MKDEV(RAW_MAJOR, 0), max_raw_minors); } module_init(raw_init); -- cgit v0.10.2 From aabb6e1531b0c78423dca6a39620892249fef7f9 Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Fri, 6 May 2011 13:27:41 -0700 Subject: efivars: prevent oops on unload when efi is not enabled efivars_exit() should check for efi_enabled and not undo allocations when efi is not enabled. Otherwise there is an Oops during module unload: calling efivars_init+0x0/0x1000 [efivars] @ 2810 EFI Variables Facility v0.08 2004-May-17 initcall efivars_init+0x0/0x1000 [efivars] returned 0 after 5120 usecs Oops: 0000 [#1] SMP DEBUG_PAGEALLOC last sysfs file: /sys/module/firmware_class/initstate CPU 1 Modules linked in: efivars(-) af_packet tun nfsd lockd nfs_acl auth_rpcgss sunrpc ipt_REJECT nf_conntrack_ipv4 nf_defrag_ipv4 iptable_filter ip_tables ip6t_REJECT xt_tcpudp nf_conntrack_ipv6 nf_defrag_ipv6 xt_state nf_conntrack ip6table_filter ip6_tables x_tables ipv6 cpufreq_ondemand acpi_cpufreq freq_table mperf binfmt_misc dm_mirror dm_region_hash dm_log dm_multipath scsi_dh dm_mod snd_hda_codec_analog snd_hda_intel snd_hda_codec snd_hwdep mousedev snd_seq joydev snd_seq_device mac_hid evdev snd_pcm usbkbd usbmouse usbhid snd_timer hid tg3 snd sr_mod pcspkr rtc_cmos soundcore cdrom iTCO_wdt processor sg dcdbas i2c_i801 rtc_core iTCO_vendor_support intel_agp snd_page_alloc thermal_sys rtc_lib intel_gtt 8250_pnp button hwmon unix ide_pci_generic ide_core ata_generic pata_acpi ata_piix sd_mod crc_t10dif ext3 jbd mbcache uhci_hcd ohci_hcd ssb mmc_core pcmcia pcmcia_core firmware_class ehci_hcd usbcore [last unloaded: dell_rbu] Pid: 2812, comm: rmmod Not tainted 2.6.39-rc6 #1 Dell Inc. OptiPlex 745 /0TY565 RIP: 0010:[] [] unregister_efivars+0x28/0x12c [efivars] RSP: 0018:ffff88005eedde98 EFLAGS: 00010283 RAX: ffffffffa06a23fc RBX: ffffffffa06a44c0 RCX: ffff88007c227a50 RDX: 0000000000000000 RSI: 00000055ac13db78 RDI: ffffffffa06a44c0 RBP: ffff88005eeddec8 R08: 0000000000000000 R09: ffff88005eeddd78 R10: ffffffffa06a4220 R11: ffff88005eeddd78 R12: fffffffffffff7d0 R13: 00007fff5a3aaec0 R14: 0000000000000000 R15: ffffffffa06a4508 FS: 00007fa8dcc4a6f0(0000) GS:ffff88007c200000(0000) knlGS:0000000000000000 CS: 0010 DS: 0000 ES: 0000 CR0: 000000008005003b CR2: 0000000000000000 CR3: 000000005d148000 CR4: 00000000000006e0 DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000 DR3: 0000000000000000 DR6: 00000000ffff0ff0 DR7: 0000000000000400 Process rmmod (pid: 2812, threadinfo ffff88005eedc000, task ffff88006754b000) Stack: ffff88005eeddec8 ffffffffa06a4220 0000000000000000 00007fff5a3aaec0 0000000000000000 0000000000000001 ffff88005eedded8 ffffffffa06a2418 ffff88005eeddf78 ffffffff810d3598 ffffffffa06a4220 0000000000000880 Call Trace: [] efivars_exit+0x1c/0xc04 [efivars] [] sys_delete_module+0x2d6/0x368 [] ? lockdep_sys_exit_thunk+0x35/0x67 [] ? audit_syscall_entry+0x172/0x1a5 [] system_call_fastpath+0x16/0x1b Code: 5c c9 c3 55 48 89 e5 41 57 41 56 41 55 41 54 53 48 83 ec 08 0f 1f 44 00 00 4c 8b 67 48 48 89 fb 4c 8d 7f 48 49 81 ec 30 08 00 00 <4d> 8b ac 24 30 08 00 00 49 81 ed 30 08 00 00 eb 59 48 89 df 48 RIP [] unregister_efivars+0x28/0x12c [efivars] RSP CR2: 0000000000000000 ---[ end trace aa99b99090f70baa ]--- Matt apparently removed such a check in 2004 (with no reason given): * 17 May 2004 - Matt Domsch * remove check for efi_enabled in exit but there have been several changes since then. Signed-off-by: Randy Dunlap Signed-off-by: Mike Waychison Tested-by: Randy Dunlap Cc: Matt Domsch Cc: Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/firmware/efivars.c b/drivers/firmware/efivars.c index 5d1ec68..a2d2f1f 100644 --- a/drivers/firmware/efivars.c +++ b/drivers/firmware/efivars.c @@ -827,8 +827,10 @@ err_put: static void __exit efivars_exit(void) { - unregister_efivars(&__efivars); - kobject_put(efi_kobj); + if (efi_enabled) { + unregister_efivars(&__efivars); + kobject_put(efi_kobj); + } } module_init(efivars_init); -- cgit v0.10.2 From b50fa7c8077c625919b1e0a75fc37b825f024518 Mon Sep 17 00:00:00 2001 From: Kay Sievers Date: Thu, 5 May 2011 13:32:05 +0200 Subject: reboot: disable usermodehelper to prevent fs access In case CONFIG_UEVENT_HELPER_PATH is not set to "", which it should be on every system, the kernel forks processes during shutdown, which try to access the rootfs, even when the binary does not exist. It causes exceptions and long delays in the disk driver, which gets read requests at the time it tries to shut down the disk. This patch disables all kernel-forked processes during reboot to allow a clean poweroff. Cc: Tejun Heo Tested-By: Anton Guda Signed-off-by: Kay Sievers Signed-off-by: Greg Kroah-Hartman diff --git a/kernel/sys.c b/kernel/sys.c index af468ed..70c4c51 100644 --- a/kernel/sys.c +++ b/kernel/sys.c @@ -314,6 +314,7 @@ void kernel_restart_prepare(char *cmd) { blocking_notifier_call_chain(&reboot_notifier_list, SYS_RESTART, cmd); system_state = SYSTEM_RESTART; + usermodehelper_disable(); device_shutdown(); sysdev_shutdown(); syscore_shutdown(); @@ -344,6 +345,7 @@ static void kernel_shutdown_prepare(enum system_states state) blocking_notifier_call_chain(&reboot_notifier_list, (state == SYSTEM_HALT)?SYS_HALT:SYS_POWER_OFF, NULL); system_state = state; + usermodehelper_disable(); device_shutdown(); } /** -- cgit v0.10.2 From 9333744dc7dcd85531cff13cabf1d5d6baf18e7d Mon Sep 17 00:00:00 2001 From: "Robert P. J. Day" Date: Wed, 4 May 2011 05:19:34 -0400 Subject: RAW driver: Remove call to kobject_put(). If cdev_add() fails, there is no justification for subsequently calling kobject_put(). Signed-off-by: Robert P. J. Day Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/char/raw.c b/drivers/char/raw.c index 6f9db62..b33e8ea 100644 --- a/drivers/char/raw.c +++ b/drivers/char/raw.c @@ -339,7 +339,6 @@ static int __init raw_init(void) cdev_init(&raw_cdev, &raw_fops); ret = cdev_add(&raw_cdev, dev, max_raw_minors); if (ret) { - kobject_put(&raw_cdev.kobj); goto error_region; } -- cgit v0.10.2 From 3ccff540070b5adde7eec443676cfee1dd6b89fd Mon Sep 17 00:00:00 2001 From: Harry Wei Date: Thu, 5 May 2011 09:47:48 +0800 Subject: Translated Documentation/email-clients.txt The patch includes the translation Documentation/email-clients.txt. If anyone has other problems, please let me know. Signed-off-by: Harry Wei Signed-off-by: Greg Kroah-Hartman diff --git a/Documentation/zh_CN/email-clients.txt b/Documentation/zh_CN/email-clients.txt new file mode 100644 index 0000000..5d65e32 --- /dev/null +++ b/Documentation/zh_CN/email-clients.txt @@ -0,0 +1,210 @@ +锘?Chinese translated version of Documentation/email-clients.txt + +If you have any comment or update to the content, please contact the +original document maintainer directly. However, if you have a problem +communicating in English you can also ask the Chinese maintainer for +help. Contact the Chinese maintainer if this translation is outdated +or if there is a problem with the translation. + +Chinese maintainer: Harry Wei +--------------------------------------------------------------------- +Documentation/email-clients.txt ???涓????缈æ˜?? + +æ¿¡??????å® ??ç’烘????å­˜?版???????????瀹癸??璇风?å­˜?ヨ??绯诲?????妗g??ç¼å­˜?よ?????æ¿¡????æµ£?浣跨?ㄨ?辨?? +浜ゆ???????ä¼´?剧??ç’‡?é”›?涔????浠ュ??涓???????ç¼å­˜?よ??姹???┿??æ¿¡???????缈æ˜????å­˜?é¢???????舵?????缈? +ç’‡?瀛???ã„©??棰?é”›?璇疯??绯讳腑??????ç¼å­˜?よ????? + +涓???????ç¼å­˜?よ??é”›? ç’惧??æ¿ž? Harry Wei +涓???????缈æ˜?????é”›? ç’惧??æ¿ž? Harry Wei +涓?????????¤?????é”›? Yinglin Luan + Xiaochen Wang + yaxinsn + +浠ヤ??涓烘?f?? +--------------------------------------------------------------------- + +Linux???æµ è·º?㈡?风?????缃?淇℃?? +====================================================================== + +?????????缃? +---------------------------------------------------------------------- +Linux?????歌ˉ涓???????æ©????浠惰?????浜ょ??é”›????濂芥??ç›ãƒ¤??æµ£?涓洪??浠朵????????宓?????????????浜?ç¼å­˜?よ?? +??ユ?å •??浠讹??æµ£???????æµ å‰?????瀹规?ç…Ž??æ´?璇ユ??"text/plain"?????惰??é”›????浠朵????????涓?ç’§???????é”›? +???涓鸿??æµ¼?浣胯ˉ涓????寮???ã„©?ã„¥????ㄨ??ç’鸿??绋?涓???????寰???ä¼´?俱?? + +??ㄦ?ュ?????Linux?????歌ˉ涓???????æµ è·º?㈡?风????ã„¥?????ç›ãƒ¤????è·º??璇ュ??浜?????????????æ¿®???舵?????渚?æ¿¡?é”›? +æµ ?æµ ?涓???芥?ç‘°?????????????ã‚…?惰〃绗???????绌烘?ç¡·???????虫????ㄦ??涓?ç›????寮?澶存?????ç¼?ç俱?? + +涓?ç‘•????æ©?"format=flowed"妯″????????ç›ãƒ¤?????æ©???蜂??寮?璧蜂?????棰????浠ュ?????瀹崇?????ç›???? + +涓?ç‘•?ç’â•€????????æµ è·º?㈡?风??æ©?ç›??????ㄦ?㈣?????æ©???蜂??æµ¼???æ‘??æµ£????ç›ãƒ¤????? + +???æµ è·º?㈡?风??涓???芥?ç‘°???????????瀛?ç»—????缂??????ç‘°?????ç‘•??????????ç›ãƒ¤???????芥??ASCII??????UTF-8缂??????ç‘°??é”›? +æ¿¡????æµ£?浣跨??UTF-8缂??????ç‘°???????????浠讹????d??æµ£?ç?æµ¼???åž®??涓?浜??????è—‰????????瀛?ç»—???????棰???? + +???æµ è·º?㈡?风??æ´?璇ュ舰???骞朵??æ·‡???? References: ?????? In-Reply-To: ???棰?é”›???d?? +???浠惰??棰?çå˜??æµ¼?涓??????? + +澶???å‰??甯?(?????????ç’寸??甯?)???甯é•????ç•Œ?ㄤ??ç›ãƒ¤??é”›????涓哄?惰〃绗?æµ¼?æž????涓虹┖??笺??浣跨??xclipboard, xclip +??????xcutsel涔?ç’稿??浠ワ??æµ£???????濂芥??ç’‡?涓?涓?????????åž®??浣跨?ã„¥????å‰??甯???? + +涓?ç‘•???ㄤ娇???PGP/GPG缃æ’????????浠朵腑??????ç›ãƒ¤?????æ©???蜂??浣垮??寰?澶???????涓???借?诲??????????ㄤ??æµ£????ç›ãƒ¤????? +é”›?æ©?涓????棰?æ´?璇ユ?????浠ヤ慨澶????é”›? + +??ㄧ???????æ??æµ è·º??ç›ã„¥?????ç›ãƒ¤??涔????é”›?ç¼????宸åž?????涓?涓?ç›ãƒ¤?????涓?涓???????涓绘??é”›?æ·‡?瀛???ユ?è·º?扮?? +???浠讹??ç?ç›ãƒ¤?????'patch'??戒护???涓?é”›?æ¿¡??????????浜?é”›????ç¼??????æ??æµ è·º??ç›ã„¥???????? + + +涓?浜????æµ è·º?㈡?风?????绀? +---------------------------------------------------------------------- +æ©????ç¼???è½°??浜?ç’‡?ç¼????MUA???缃????绀猴?????浠ョ?ㄤ??ç¼?Linux?????稿?????ç›ãƒ¤?????æ©?浜?骞朵???????虫?? +?????????æž?æµ è·º?????缃???è¤????? + +璇存??é”›? +TUI = 浠ユ?????涓哄?虹???????ㄦ?锋?ュ?? +GUI = ??惧舰?????㈢?ㄦ?锋?ュ?? + +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +Alpine (TUI) + +???缃????椤癸?? +???"Sending Preferences"??ã„¥??é”›? + +- "Do Not Send Flowed Text"蹇?椤诲????? +- "Strip Whitespace Before Sending"蹇?椤诲?抽?? + +褰???????浠舵?讹????????æ´?璇ユ?惧?ㄨˉ涓?æµ¼???虹?扮????版?癸????è·º?????涓?CTRL-Rç¼???????é”›?浣挎??瀹???? +ç›ãƒ¤?????æµ è·º????ュ?ä¼´??浠朵腑??? + +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +Evolution (GUI) + +涓?浜?寮????????????????浣跨?ã„¥????????ç›ãƒ¤?? + +褰??????â•…??æµ å •??椤癸??Preformat + æµ ?Format->Heading->Preformatted (Ctrl-7)??????宸ュ?锋?? + +??è·º??浣跨??é”›? + Insert->Text File... (Alt-n x)?????ヨˉ涓????浠躲?? + +æµ£?æ©????æµ ?"diff -Nru old.c new.c | xclip"é”›???????Preformaté”›???è·º??浣跨?ㄤ腑??æ’®??æ©?ç›?ç»®?甯???? + +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +Kmail (GUI) + +涓?浜?寮????????????????浣跨?ã„¥????????ç›ãƒ¤????? + +榛?ç’よ?剧疆涓?涓?HTML??ç…Ž??????????????é”›?涓?ç‘•??????ã„¥????? + +褰?涔????涓?ç????æµ å‰????è·º??é”›???ã„©??椤逛?????涓?ç‘•??????â•„????ㄦ?㈣????????涓????缂虹?ç‘°æ°¨???æµ£???ã„©??浠朵腑æˆ???ョ??浠讳???????? +??戒??æµ¼?çš??????ㄦ?㈣??é”›????å§ã‚„??蹇?椤诲?ã„¥?????ç›ãƒ¤??涔?????????ㄦ?㈣????????ç» ?????????规??ç辨???????ㄨ????ㄦ?㈣????ヤ功??????浠讹?? +??è·º?????瀹?æ·‡?瀛?涓鸿??绋裤??涓????æµ£???ㄨ??绋夸腑???娆℃??寮?瀹?é”›?瀹?宸茬????ã„©?ㄨ????ㄦ?㈣??浜?é”›???d??æµ£???????浠惰?ç•Œ?舵病??? +?????â•„????ㄦ?㈣??é”›?æµ£????æ©?涓?æµ¼?澶åž?诲凡???????????ㄦ?㈣????? + +??ã„©??æµ å‰??æ´????é”›??????ヨˉ涓?涔????é”›???å¥??甯哥?ㄧ??ç›ãƒ¤??瀹????ç»—?é”›?涓?涓?æ©?瀛????(---)??? + +??è·º?????"Message"????????$??é”›??????â•‚????ユ??浠讹????ョ????????æµ£????ç›ãƒ¤?????浠躲??æ©????涓?涓?棰?澶???????椤癸??æµ£????æµ ? +???æ©?瀹????缃?æµ£???????浠跺缓绔?宸ュ?锋????????é”›?æ©????浠ュ甫涓?"insert file"??炬????? + +æµ£????浠ュ????ã„¥?ä¼´??æ©?GPG???ç’ä¼´??浠讹??æµ£???????宓?ç›ãƒ¤?????濂戒??ç‘•?浣跨??GPG???ç’æ¿??æµ ????æµ£?涓哄??宓??????????绛惧??ç›ãƒ¤??é”›? +褰?æµ ?GPG涓???????7æµ£?缂??????朵??浣夸??æµ ?????????æ‘??澶??????? + +æ¿¡????æµ£????ç‘•?浠ラ??æµ å‰??褰㈠????????ç›ãƒ¤??é”›???d??çåž?抽????ç‘°?å©š??浠讹????è·º?????涓?çž???Ñ??ç»????"Suggest automatic +display"é”›?æ©???å³°??宓????浠舵?æ‘?规??ç’â•„?æ˜???????般?? + +褰?æµ£?ç‘•?æ·‡?瀛?ç?ç‘•?????????????宓???????ç›ãƒ¤??é”›?æµ£????浠ヤ??娑???????ç›ã„§????奸????â•?????ç›ãƒ¤????????浠讹????è·º????冲?å©š????? +"save as"???æµ£????浠ヤ娇??ㄤ??涓?娌℃????å­˜?圭????????ç›ãƒ¤????????浠讹??æ¿¡????瀹????浠ユ?g‘???褰㈠??ç¼???????褰?æµ£?å§ï½‡????ã„¥?? +???宸辩??ç»???d??涓?瀵????é”›???f?舵病??????椤瑰??浠ヤ??瀛????æµ ?--宸茬?????涓?涓?æ©???风??bugçš?姹???ュ?é¢??kmail???bugzilla +骞朵??甯????æ©?ç?æµ¼?çš?澶??????????浠舵??浠ュ?????瀵规??涓???ㄦ?å³°??璇诲???????????çš?æ·‡?瀛????é”›????浠ュ?????æµ£???虫?????æµ è·º????è·º?æ¿?朵????版?癸?? +æµ£?涓?寰?涓????æµ ?æµ ????????????逛负ç¼?????????ç¿ ?????璇汇?? + +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +Lotus Notes (GUI) + +涓?ç‘•?浣跨?ã„¥????? + +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +Mutt (TUI) + +寰?澶?Linux寮????浜哄??浣跨??mutt瀹㈡?风??é”›????浠ヨ?????瀹????瀹?宸ヤ????????甯告??浜???? + +Mutt涓????甯?缂?æˆ????é”›????浠ヤ??绠′??浣跨?ㄤ??涔?缂?æˆ???ã„©?戒??æ´?璇ュ甫????????ㄦ??ç›????澶у????扮??æˆ???ã„©?藉甫??? +涓?涓?"insert file"???椤癸??瀹????浠ラ??æ©?涓???ç‘°?????æµ è·º??瀹圭????ç‘°???????ユ??浠躲?? + +'vim'æµ£?涓?mutt???缂?æˆ????é”›? + set editor="vi" + + æ¿¡????浣跨??xclipé”›???æ’?ヤ互涓???戒护 + :set paste + ???涓????涔??????????shift-insert??????浣跨?? + :r filename + +æ¿¡??????å® ?????ç›ãƒ¤??æµ£?涓哄??宓?????????? +(a)ttach宸ヤ?????寰?æ¿‚æ–¤??涓?甯????"set paste"??? + +???缃????椤癸?? +瀹?æ´?璇ヤ互榛?ç’よ?剧疆???褰㈠??宸ヤ????? +??惰??é”›????"send_charset"ç’剧疆涓?"us-ascii::utf-8"涔????涓?涓?涓???????涓绘????? + +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +Pine (TUI) + +Pineæ©???绘??涓?浜?绌烘?ç…Ž????????棰?é”›?æµ£????æ©?浜???æ¿?ã„¥??璇ラ?借??æ·‡?澶?浜???? + +æ¿¡???????浠ワ??璇蜂娇???alpine(pine???ç¼Ñ„?胯??) + +???缃????椤癸?? +- ???æ©?????????????ç‘•?娑???ゆ??绋??????? +- "no-strip-whitespace-before-send"???椤逛????????ç‘•??????? + + +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +Sylpheed (GUI) + +- ???宓??????????浠ュ??æ¿‚ç•Œ??宸ヤ??é”›???????浣跨?ã„©??浠讹????? +- ???ç’é•å¨‡??ã„¥????ㄧ??缂?æˆ???ã„£?? +- 瀵逛?????褰?æˆ?澶???å •??甯告????? +- æ¿¡???????æ©?non-SSLæ©???ワ?????娉?浣跨??TLS SMTP????????? +- ??ㄧ?????ç»???d腑???涓?涓?寰??????ㄧ??ruler bar??? +- ç¼???æ¿?????涓?娣诲????æ¿??çå˜??æµ¼?å§ï½‡â€˜???浜?瑙f?剧ãš?????? + +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +Thunderbird (GUI) + +榛?ç’ゆ????å…¸??é”›?thunderbird寰?瀹规??????????????é”›?æµ£????æ©????涓?浜???规?????浠ュ己??è·º?????寰???æ‘ソ??? + +- ??ㄧ?ㄦ?å³°????ç–¯?剧疆???é”›?ç¼???????瀵诲??é”›?涓?ç‘•???????"Compose messages in HTML format"??? + +- 缂?æˆ?æµ£????Thunderbird???缃?ç’剧疆??ヤ娇瀹?涓?ç‘•????ç›?浣跨??é”›?user_pref("mailnews.wraplength", 0); + +- 缂?æˆ?æµ£????Thunderbird???缃?ç’剧疆锛?浣垮??涓?ç‘•?浣跨??"format=flowed"??ç…Ž??é”›?user_pref("mailnews. + send_plaintext_flowed", false); + +- æµ£????ç‘•?æµ£?Thunderbird???涓洪???????ç…Ž????ç‘°??é”›? + æ¿¡????榛?ç’ゆ????å…¸??æµ£?涔??????????HTML??ç…Ž??é”›???d?????寰???俱??æµ ?æµ ?æµ ????棰???????涓????妗?涓???????"Preformat"??ç…Ž????? + æ¿¡????榛?ç’ゆ????å…¸??æµ£?涔??????????????????ç…Ž??é”›?æµ£?涓?寰????瀹???逛负HTML??ç…Ž??é”›?æµ ?æµ ?æµ£?涓轰??娆℃?Ñ…??é”›???ヤ功?????扮??娑????é”›? + ??è·º??寮哄?朵娇瀹??????版???????ç…Ž??é”›???????瀹?çå˜?????ç›????ç‘•?瀹???æ¿??é”›???ã„¥??淇$????炬??涓?浣跨??shift?????ヤ娇瀹????涓?HTML + ??ç…Ž??é”›???è·º?????棰???????涓????妗?涓???????"Preformat"??ç…Ž????? + +- ???ç’é•å¨‡??ã„¥????ㄧ??缂?æˆ????é”›? + ???瀵?Thunderbird???ç›ãƒ¤?????ç» ?????????规??ç辨??浣跨?ㄤ??涓?"external editor"??â•??é”›???è·º??浣跨?ㄤ????????娆㈢?? + $EDITOR??ヨ?诲???????????骞惰ˉ涓???版?????涓????ç‘•?瀹???æ¿??é”›????浠ヤ??æžè—‰è‹Ÿæ¶“?瀹?ç‘?æ©?涓???â•??é”›???è·º??娣诲??涓?涓?浣跨?ã„¥????? + ??????View->Toolbars->Customize...??????褰?æµ£?涔????淇℃???????è·º??æµ ?æµ ???ç‘°?诲??çåž??浠ヤ????? + +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +TkRat (GUI) + +???浠ヤ娇??ã„¥?????浣跨??"Insert file..."??????澶???ㄧ??缂?æˆ???ã„£?? + +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +Gmail (Web GUI) + +涓?ç‘•?浣跨?ã„¥????????ç›ãƒ¤????? + +Gmail缃?椤é›?㈡?风???????ã„¥?版????惰〃绗?æž????涓虹┖??笺?? + +??ç•Œ?è·º?惰〃绗?æž????涓虹┖??奸??棰????浠ヨ??澶???ㄧ??æˆ???ㄨВ??ç­¹???????è·º??æ©?æµ¼?浣跨?ã„¥??æž???㈣?????姣?ç›???????涓?78涓?瀛?ç»—???? + +???涓?涓????棰????Gmailæ©?æµ¼????浠讳??涓????ASCII???瀛?ç»—????淇℃????逛负base64缂???????瀹????涓?ç‘—åž®????????娆ф床浜虹?????瀛???? + + ### -- cgit v0.10.2 From a015dbc110a97ed3147546a9c914f18f71d798d0 Mon Sep 17 00:00:00 2001 From: John Stultz Date: Fri, 6 May 2011 17:24:27 -0700 Subject: rtc: m41t80: Initialize clientdata before registering device Commit f44f7f96a20 ("RTC: Initialize kernel state from RTC") uncovered an issue in a number of RTC drivers, where the drivers call rtc_device_register before initializing the clientdata. This frequently results in null pointer dereferences when the rtc_device_register immediately makes use of the rtc device, calling rtc_read_alarm. The solution is to ensure the clientdata is initialized prior to registering the rtc device. CC: Wolfram Sang CC: Alessandro Zummo CC: Thomas Gleixner CC: rtc-linux@googlegroups.com Signed-off-by: John Stultz diff --git a/drivers/rtc/rtc-m41t80.c b/drivers/rtc/rtc-m41t80.c index 69fe664..eda128f 100644 --- a/drivers/rtc/rtc-m41t80.c +++ b/drivers/rtc/rtc-m41t80.c @@ -783,6 +783,9 @@ static int m41t80_probe(struct i2c_client *client, goto exit; } + clientdata->features = id->driver_data; + i2c_set_clientdata(client, clientdata); + rtc = rtc_device_register(client->name, &client->dev, &m41t80_rtc_ops, THIS_MODULE); if (IS_ERR(rtc)) { @@ -792,8 +795,6 @@ static int m41t80_probe(struct i2c_client *client, } clientdata->rtc = rtc; - clientdata->features = id->driver_data; - i2c_set_clientdata(client, clientdata); /* Make sure HT (Halt Update) bit is cleared */ rc = i2c_smbus_read_byte_data(client, M41T80_REG_ALARM_HOUR); -- cgit v0.10.2 From 880ffb5c6c5c8c8c6efd9efe9355317322b4603b Mon Sep 17 00:00:00 2001 From: Wanlong Gao Date: Thu, 5 May 2011 07:55:36 +0800 Subject: driver core: Add the device driver-model structures to kerneldoc Add the comments to the structure bus_type, device_driver, device, class to device.h for generating the driver-model kerneldoc. With another patch these all removed from the files in Documentation/driver-model/ since they are out of date. That will keep things up to date and provide a better way to document this stuff. Signed-off-by: Wanlong Gao Acked-by: Harry Wei Signed-off-by: Greg Kroah-Hartman diff --git a/Documentation/DocBook/device-drivers.tmpl b/Documentation/DocBook/device-drivers.tmpl index 36f63d4..b638e50 100644 --- a/Documentation/DocBook/device-drivers.tmpl +++ b/Documentation/DocBook/device-drivers.tmpl @@ -96,10 +96,10 @@ X!Iinclude/linux/kobject.h Device drivers infrastructure + The Basic Device Driver-Model Structures +!Iinclude/linux/device.h + Device Drivers Base - !Edrivers/base/driver.c !Edrivers/base/core.c !Edrivers/base/class.c diff --git a/include/linux/device.h b/include/linux/device.h index 2215d01..4236506 100644 --- a/include/linux/device.h +++ b/include/linux/device.h @@ -47,6 +47,38 @@ extern int __must_check bus_create_file(struct bus_type *, struct bus_attribute *); extern void bus_remove_file(struct bus_type *, struct bus_attribute *); +/** + * struct bus_type - The bus type of the device + * + * @name: The name of the bus. + * @bus_attrs: Default attributes of the bus. + * @dev_attrs: Default attributes of the devices on the bus. + * @drv_attrs: Default attributes of the device drivers on the bus. + * @match: Called, perhaps multiple times, whenever a new device or driver + * is added for this bus. It should return a nonzero value if the + * given device can be handled by the given driver. + * @uevent: Called when a device is added, removed, or a few other things + * that generate uevents to add the environment variables. + * @probe: Called when a new device or driver add to this bus, and callback + * the specific driver's probe to initial the matched device. + * @remove: Called when a device removed from this bus. + * @shutdown: Called at shut-down time to quiesce the device. + * @suspend: Called when a device on this bus wants to go to sleep mode. + * @resume: Called to bring a device on this bus out of sleep mode. + * @pm: Power management operations of this bus, callback the specific + * device driver's pm-ops. + * @p: The private data of the driver core, only the driver core can + * touch this. + * + * A bus is a channel between the processor and one or more devices. For the + * purposes of the device model, all devices are connected via a bus, even if + * it is an internal, virtual, "platform" bus. Buses can plug into each other. + * A USB controller is usually a PCI device, for example. The device model + * represents the actual connections between buses and the devices they control. + * A bus is represented by the bus_type structure. It contains the name, the + * default attributes, the bus' methods, PM operations, and the driver core's + * private data. + */ struct bus_type { const char *name; struct bus_attribute *bus_attrs; @@ -119,6 +151,37 @@ extern int bus_unregister_notifier(struct bus_type *bus, extern struct kset *bus_get_kset(struct bus_type *bus); extern struct klist *bus_get_device_klist(struct bus_type *bus); +/** + * struct device_driver - The basic device driver structure + * @name: Name of the device driver. + * @bus: The bus which the device of this driver belongs to. + * @owner: The module owner. + * @mod_name: Used for built-in modules. + * @suppress_bind_attrs: Disables bind/unbind via sysfs. + * @of_match_table: The open firmware table. + * @probe: Called to query the existence of a specific device, + * whether this driver can work with it, and bind the driver + * to a specific device. + * @remove: Called when the device is removed from the system to + * unbind a device from this driver. + * @shutdown: Called at shut-down time to quiesce the device. + * @suspend: Called to put the device to sleep mode. Usually to a + * low power state. + * @resume: Called to bring a device from sleep mode. + * @groups: Default attributes that get created by the driver core + * automatically. + * @pm: Power management operations of the device which matched + * this driver. + * @p: Driver core's private data, no one other than the driver + * core can touch this. + * + * The device driver-model tracks all of the drivers known to the system. + * The main reason for this tracking is to enable the driver core to match + * up drivers with new devices. Once drivers are known objects within the + * system, however, a number of other things become possible. Device drivers + * can export information and configuration variables that are independent + * of any specific device. + */ struct device_driver { const char *name; struct bus_type *bus; @@ -185,8 +248,34 @@ struct device *driver_find_device(struct device_driver *drv, struct device *start, void *data, int (*match)(struct device *dev, void *data)); -/* - * device classes +/** + * struct class - device classes + * @name: Name of the class. + * @owner: The module owner. + * @class_attrs: Default attributes of this class. + * @dev_attrs: Default attributes of the devices belong to the class. + * @dev_bin_attrs: Default binary attributes of the devices belong to the class. + * @dev_kobj: The kobject that represents this class and links it into the hierarchy. + * @dev_uevent: Called when a device is added, removed from this class, or a + * few other things that generate uevents to add the environment + * variables. + * @devnode: Callback to provide the devtmpfs. + * @class_release: Called to release this class. + * @dev_release: Called to release the device. + * @suspend: Used to put the device to sleep mode, usually to a low power + * state. + * @resume: Used to bring the device from the sleep mode. + * @ns_type: Callbacks so sysfs can detemine namespaces. + * @namespace: Namespace of the device belongs to this class. + * @pm: The default device power management operations of this class. + * @p: The private data of the driver core, no one other than the + * driver core can touch this. + * + * A class is a higher-level view of a device that abstracts out low-level + * implementation details. Drivers may see a SCSI disk or an ATA disk, but, + * at the class level, they are all simply disks. Classes allow user space + * to work with devices based on what they do, rather than how they are + * connected or how they work. */ struct class { const char *name; @@ -401,6 +490,65 @@ struct device_dma_parameters { unsigned long segment_boundary_mask; }; +/** + * struct device - The basic device structure + * @parent: The device's "parent" device, the device to which it is attached. + * In most cases, a parent device is some sort of bus or host + * controller. If parent is NULL, the device, is a top-level device, + * which is not usually what you want. + * @p: Holds the private data of the driver core portions of the device. + * See the comment of the struct device_private for detail. + * @kobj: A top-level, abstract class from which other classes are derived. + * @init_name: Initial name of the device. + * @type: The type of device. + * This identifies the device type and carries type-specific + * information. + * @mutex: Mutex to synchronize calls to its driver. + * @bus: Type of bus device is on. + * @driver: Which driver has allocated this + * @platform_data: Platform data specific to the device. + * Example: For devices on custom boards, as typical of embedded + * and SOC based hardware, Linux often uses platform_data to point + * to board-specific structures describing devices and how they + * are wired. That can include what ports are available, chip + * variants, which GPIO pins act in what additional roles, and so + * on. This shrinks the "Board Support Packages" (BSPs) and + * minimizes board-specific #ifdefs in drivers. + * @power: For device power management. + * See Documentation/power/devices.txt for details. + * @pwr_domain: Provide callbacks that are executed during system suspend, + * hibernation, system resume and during runtime PM transitions + * along with subsystem-level and driver-level callbacks. + * @numa_node: NUMA node this device is close to. + * @dma_mask: Dma mask (if dma'ble device). + * @coherent_dma_mask: Like dma_mask, but for alloc_coherent mapping as not all + * hardware supports 64-bit addresses for consistent allocations + * such descriptors. + * @dma_parms: A low level driver may set these to teach IOMMU code about + * segment limitations. + * @dma_pools: Dma pools (if dma'ble device). + * @dma_mem: Internal for coherent mem override. + * @archdata: For arch-specific additions. + * @of_node: Associated device tree node. + * @of_match: Matching of_device_id from driver. + * @devt: For creating the sysfs "dev". + * @devres_lock: Spinlock to protect the resource of the device. + * @devres_head: The resources list of the device. + * @knode_class: The node used to add the device to the class list. + * @class: The class of the device. + * @groups: Optional attribute groups. + * @release: Callback to free the device after all references have + * gone away. This should be set by the allocator of the + * device (i.e. the bus driver that discovered the device). + * + * At the lowest level, every device in a Linux system is represented by an + * instance of struct device. The device structure contains the information + * that the device model core needs to model the system. Most subsystems, + * however, track additional information about the devices they host. As a + * result, it is rare for devices to be represented by bare device structures; + * instead, that structure, like kobject structures, is usually embedded within + * a higher-level representation of the device. + */ struct device { struct device *parent; @@ -611,7 +759,7 @@ extern int (*platform_notify)(struct device *dev); extern int (*platform_notify_remove)(struct device *dev); -/** +/* * get_device - atomically increment the reference count for the device. * */ -- cgit v0.10.2 From 63dc355a5a8cf296e2b1cc2e4192190dca221129 Mon Sep 17 00:00:00 2001 From: Wanlong Gao Date: Thu, 5 May 2011 07:55:37 +0800 Subject: driver core: remove the driver-model structures from the documentation Remove the struct bus_type, class, device, device_driver from the driver-model docs. With another patch add them to device.h, since they are out of date. That will keep things up to date and provide a better way to document this stuff. Signed-off-by: Wanlong Gao Acked-by: Harry Wei Signed-off-by: Greg Kroah-Hartman diff --git a/Documentation/driver-model/bus.txt b/Documentation/driver-model/bus.txt index 5001b75..6754b2d 100644 --- a/Documentation/driver-model/bus.txt +++ b/Documentation/driver-model/bus.txt @@ -3,24 +3,7 @@ Bus Types Definition ~~~~~~~~~~ - -struct bus_type { - char * name; - - struct subsystem subsys; - struct kset drivers; - struct kset devices; - - struct bus_attribute * bus_attrs; - struct device_attribute * dev_attrs; - struct driver_attribute * drv_attrs; - - int (*match)(struct device * dev, struct device_driver * drv); - int (*hotplug) (struct device *dev, char **envp, - int num_envp, char *buffer, int buffer_size); - int (*suspend)(struct device * dev, pm_message_t state); - int (*resume)(struct device * dev); -}; +See the kerneldoc for the struct bus_type. int bus_register(struct bus_type * bus); diff --git a/Documentation/driver-model/class.txt b/Documentation/driver-model/class.txt index 548505f..1fefc48 100644 --- a/Documentation/driver-model/class.txt +++ b/Documentation/driver-model/class.txt @@ -27,22 +27,7 @@ The device class structure looks like: typedef int (*devclass_add)(struct device *); typedef void (*devclass_remove)(struct device *); -struct device_class { - char * name; - rwlock_t lock; - u32 devnum; - struct list_head node; - - struct list_head drivers; - struct list_head intf_list; - - struct driver_dir_entry dir; - struct driver_dir_entry device_dir; - struct driver_dir_entry driver_dir; - - devclass_add add_device; - devclass_remove remove_device; -}; +See the kerneldoc for the struct class. A typical device class definition would look like: diff --git a/Documentation/driver-model/device.txt b/Documentation/driver-model/device.txt index a124f31..b2ff426 100644 --- a/Documentation/driver-model/device.txt +++ b/Documentation/driver-model/device.txt @@ -2,96 +2,7 @@ The Basic Device Structure ~~~~~~~~~~~~~~~~~~~~~~~~~~ -struct device { - struct list_head g_list; - struct list_head node; - struct list_head bus_list; - struct list_head driver_list; - struct list_head intf_list; - struct list_head children; - struct device * parent; - - char name[DEVICE_NAME_SIZE]; - char bus_id[BUS_ID_SIZE]; - - spinlock_t lock; - atomic_t refcount; - - struct bus_type * bus; - struct driver_dir_entry dir; - - u32 class_num; - - struct device_driver *driver; - void *driver_data; - void *platform_data; - - u32 current_state; - unsigned char *saved_state; - - void (*release)(struct device * dev); -}; - -Fields -~~~~~~ -g_list: Node in the global device list. - -node: Node in device's parent's children list. - -bus_list: Node in device's bus's devices list. - -driver_list: Node in device's driver's devices list. - -intf_list: List of intf_data. There is one structure allocated for - each interface that the device supports. - -children: List of child devices. - -parent: *** FIXME *** - -name: ASCII description of device. - Example: " 3Com Corporation 3c905 100BaseTX [Boomerang]" - -bus_id: ASCII representation of device's bus position. This - field should be a name unique across all devices on the - bus type the device belongs to. - - Example: PCI bus_ids are in the form of - :. - This name is unique across all PCI devices in the system. - -lock: Spinlock for the device. - -refcount: Reference count on the device. - -bus: Pointer to struct bus_type that device belongs to. - -dir: Device's sysfs directory. - -class_num: Class-enumerated value of the device. - -driver: Pointer to struct device_driver that controls the device. - -driver_data: Driver-specific data. - -platform_data: Platform data specific to the device. - - Example: for devices on custom boards, as typical of embedded - and SOC based hardware, Linux often uses platform_data to point - to board-specific structures describing devices and how they - are wired. That can include what ports are available, chip - variants, which GPIO pins act in what additional roles, and so - on. This shrinks the "Board Support Packages" (BSPs) and - minimizes board-specific #ifdefs in drivers. - -current_state: Current power state of the device. - -saved_state: Pointer to saved state of the device. This is usable by - the device driver controlling the device. - -release: Callback to free the device after all references have - gone away. This should be set by the allocator of the - device (i.e. the bus driver that discovered the device). +See the kerneldoc for the struct device. Programming Interface diff --git a/Documentation/driver-model/driver.txt b/Documentation/driver-model/driver.txt index d2cd6fb..4421135 100644 --- a/Documentation/driver-model/driver.txt +++ b/Documentation/driver-model/driver.txt @@ -1,23 +1,7 @@ Device Drivers -struct device_driver { - char * name; - struct bus_type * bus; - - struct completion unloaded; - struct kobject kobj; - list_t devices; - - struct module *owner; - - int (*probe) (struct device * dev); - int (*remove) (struct device * dev); - - int (*suspend) (struct device * dev, pm_message_t state); - int (*resume) (struct device * dev); -}; - +See the kerneldoc for the struct device_driver. Allocation -- cgit v0.10.2 From 2f5c4fe8f9811152d69ef5cd020e095a1f84ca65 Mon Sep 17 00:00:00 2001 From: John Stultz Date: Fri, 6 May 2011 17:26:25 -0700 Subject: rtc: max8925: Initialize drvdata before registering device Commit f44f7f96a20 ("RTC: Initialize kernel state from RTC") uncovered an issue in a number of RTC drivers, where the drivers call rtc_device_register before initializing the device or platform drvdata. This frequently results in null pointer dereferences when the rtc_device_register immediately makes use of the rtc device, calling rtc_read_alarm. The solution is to ensure the drvdata is initialized prior to registering the rtc device. CC: Wolfram Sang CC: Alessandro Zummo CC: Thomas Gleixner CC: rtc-linux@googlegroups.com Signed-off-by: John Stultz diff --git a/drivers/rtc/rtc-max8925.c b/drivers/rtc/rtc-max8925.c index 20494b5..3bc046f 100644 --- a/drivers/rtc/rtc-max8925.c +++ b/drivers/rtc/rtc-max8925.c @@ -258,6 +258,8 @@ static int __devinit max8925_rtc_probe(struct platform_device *pdev) } dev_set_drvdata(&pdev->dev, info); + /* XXX - isn't this redundant? */ + platform_set_drvdata(pdev, info); info->rtc_dev = rtc_device_register("max8925-rtc", &pdev->dev, &max8925_rtc_ops, THIS_MODULE); @@ -267,10 +269,9 @@ static int __devinit max8925_rtc_probe(struct platform_device *pdev) goto out_rtc; } - platform_set_drvdata(pdev, info); - return 0; out_rtc: + platform_set_drvdata(pdev, NULL); free_irq(chip->irq_base + MAX8925_IRQ_RTC_ALARM0, info); out_irq: kfree(info); -- cgit v0.10.2 From 03cf7c477de8cb47658ba93f33dc93242985acff Mon Sep 17 00:00:00 2001 From: John Stultz Date: Fri, 6 May 2011 17:27:07 -0700 Subject: rtc: max8998: Initialize drvdata before registering device Commit f44f7f96a20 ("RTC: Initialize kernel state from RTC") uncovered an issue in a number of RTC drivers, where the drivers call rtc_device_register before initializing the device or platform drvdata. This frequently results in null pointer dereferences when the rtc_device_register immediately makes use of the rtc device, calling rtc_read_alarm. The solution is to ensure the drvdata is initialized prior to registering the rtc device. CC: Wolfram Sang CC: Alessandro Zummo CC: Thomas Gleixner CC: rtc-linux@googlegroups.com Signed-off-by: John Stultz diff --git a/drivers/rtc/rtc-max8998.c b/drivers/rtc/rtc-max8998.c index 3f7bc6b..2e48aa6 100644 --- a/drivers/rtc/rtc-max8998.c +++ b/drivers/rtc/rtc-max8998.c @@ -265,6 +265,8 @@ static int __devinit max8998_rtc_probe(struct platform_device *pdev) info->rtc = max8998->rtc; info->irq = max8998->irq_base + MAX8998_IRQ_ALARM0; + platform_set_drvdata(pdev, info); + info->rtc_dev = rtc_device_register("max8998-rtc", &pdev->dev, &max8998_rtc_ops, THIS_MODULE); @@ -274,8 +276,6 @@ static int __devinit max8998_rtc_probe(struct platform_device *pdev) goto out_rtc; } - platform_set_drvdata(pdev, info); - ret = request_threaded_irq(info->irq, NULL, max8998_rtc_alarm_irq, 0, "rtc-alarm0", info); @@ -293,6 +293,7 @@ static int __devinit max8998_rtc_probe(struct platform_device *pdev) return 0; out_rtc: + platform_set_drvdata(pdev, NULL); kfree(info); return ret; } -- cgit v0.10.2 From 93015236d92bf9ea746c0b10c3c1d9058cb11f82 Mon Sep 17 00:00:00 2001 From: John Stultz Date: Fri, 6 May 2011 17:28:36 -0700 Subject: rtc: msm6242: Initialize drvdata before registering device Commit f44f7f96a20 ("RTC: Initialize kernel state from RTC") uncovered an issue in a number of RTC drivers, where the drivers call rtc_device_register before initializing the device or platform drvdata. This frequently results in null pointer dereferences when the rtc_device_register immediately makes use of the rtc device, calling rtc_read_alarm. The solution is to ensure the drvdata is initialized prior to registering the rtc device. CC: Wolfram Sang CC: Alessandro Zummo CC: Thomas Gleixner CC: rtc-linux@googlegroups.com Signed-off-by: John Stultz diff --git a/drivers/rtc/rtc-msm6242.c b/drivers/rtc/rtc-msm6242.c index 6782062..fcb113c 100644 --- a/drivers/rtc/rtc-msm6242.c +++ b/drivers/rtc/rtc-msm6242.c @@ -214,6 +214,7 @@ static int __init msm6242_rtc_probe(struct platform_device *dev) error = -ENOMEM; goto out_free_priv; } + platform_set_drvdata(dev, priv); rtc = rtc_device_register("rtc-msm6242", &dev->dev, &msm6242_rtc_ops, THIS_MODULE); @@ -223,10 +224,10 @@ static int __init msm6242_rtc_probe(struct platform_device *dev) } priv->rtc = rtc; - platform_set_drvdata(dev, priv); return 0; out_unmap: + platform_set_drvdata(dev, NULL); iounmap(priv->regs); out_free_priv: kfree(priv); -- cgit v0.10.2 From 4b3687f9c18156cdb71729fe4e0c3000f7e4d7de Mon Sep 17 00:00:00 2001 From: John Stultz Date: Fri, 6 May 2011 17:30:57 -0700 Subject: rtc: pcap: Initialize drvdata before registering device Commit f44f7f96a20 ("RTC: Initialize kernel state from RTC") uncovered an issue in a number of RTC drivers, where the drivers call rtc_device_register before initializing the device or platform drvdata. This frequently results in null pointer dereferences when the rtc_device_register immediately makes use of the rtc device, calling rtc_read_alarm. The solution is to ensure the drvdata is initialized prior to registering the rtc device. CC: Wolfram Sang CC: Alessandro Zummo CC: Thomas Gleixner CC: rtc-linux@googlegroups.com Signed-off-by: John Stultz diff --git a/drivers/rtc/rtc-pcap.c b/drivers/rtc/rtc-pcap.c index a633abc..cd4f198 100644 --- a/drivers/rtc/rtc-pcap.c +++ b/drivers/rtc/rtc-pcap.c @@ -151,6 +151,8 @@ static int __devinit pcap_rtc_probe(struct platform_device *pdev) pcap_rtc->pcap = dev_get_drvdata(pdev->dev.parent); + platform_set_drvdata(pdev, pcap_rtc); + pcap_rtc->rtc = rtc_device_register("pcap", &pdev->dev, &pcap_rtc_ops, THIS_MODULE); if (IS_ERR(pcap_rtc->rtc)) { @@ -158,7 +160,6 @@ static int __devinit pcap_rtc_probe(struct platform_device *pdev) goto fail_rtc; } - platform_set_drvdata(pdev, pcap_rtc); timer_irq = pcap_to_irq(pcap_rtc->pcap, PCAP_IRQ_1HZ); alarm_irq = pcap_to_irq(pcap_rtc->pcap, PCAP_IRQ_TODA); @@ -177,6 +178,7 @@ fail_alarm: fail_timer: rtc_device_unregister(pcap_rtc->rtc); fail_rtc: + platform_set_drvdata(pdev, NULL); kfree(pcap_rtc); return err; } -- cgit v0.10.2 From 130107b270f9a8ef1b50e02140a381c44a6abd68 Mon Sep 17 00:00:00 2001 From: John Stultz Date: Fri, 6 May 2011 17:31:20 -0700 Subject: rtc: rp5c01: Initialize drvdata before registering device Commit f44f7f96a20 ("RTC: Initialize kernel state from RTC") uncovered an issue in a number of RTC drivers, where the drivers call rtc_device_register before initializing the device or platform drvdata. This frequently results in null pointer dereferences when the rtc_device_register immediately makes use of the rtc device, calling rtc_read_alarm. The solution is to ensure the drvdata is initialized prior to registering the rtc device. CC: Wolfram Sang CC: Alessandro Zummo CC: Thomas Gleixner CC: rtc-linux@googlegroups.com Signed-off-by: John Stultz diff --git a/drivers/rtc/rtc-rp5c01.c b/drivers/rtc/rtc-rp5c01.c index 694da39..359da6d 100644 --- a/drivers/rtc/rtc-rp5c01.c +++ b/drivers/rtc/rtc-rp5c01.c @@ -249,15 +249,15 @@ static int __init rp5c01_rtc_probe(struct platform_device *dev) spin_lock_init(&priv->lock); + platform_set_drvdata(dev, priv); + rtc = rtc_device_register("rtc-rp5c01", &dev->dev, &rp5c01_rtc_ops, THIS_MODULE); if (IS_ERR(rtc)) { error = PTR_ERR(rtc); goto out_unmap; } - priv->rtc = rtc; - platform_set_drvdata(dev, priv); error = sysfs_create_bin_file(&dev->dev.kobj, &priv->nvram_attr); if (error) @@ -268,6 +268,7 @@ static int __init rp5c01_rtc_probe(struct platform_device *dev) out_unregister: rtc_device_unregister(rtc); out_unmap: + platform_set_drvdata(dev, NULL); iounmap(priv->regs); out_free_priv: kfree(priv); -- cgit v0.10.2 From 156229b352b999cafb86a21b50912975e39b7f44 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Fri, 6 May 2011 11:57:47 +0200 Subject: rtc: mc13xxx: Don't call rtc_device_register while holding lock MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Since commit f44f7f9 (RTC: Initialize kernel state from RTC) rtc_device_register reads the programmed alarm. As reading the alarm needs to take the mc13xxx lock, release it before calling rtc_device_register. This fixes a deadlock during boot: INFO: task swapper:1 blocked for more than 120 seconds. "echo 0 > /proc/sys/kernel/hung_task_timeout_secs" disables this message. swapper D c02b175c 0 1 0 0x00000000 [] (schedule+0x304/0x4f4) from [] (__mutex_lock_slowpath+0x7c/0x110) [] (__mutex_lock_slowpath+0x7c/0x110) from [] (mc13xxx_rtc_read_time+0x1c/0x118) [] (mc13xxx_rtc_read_time+0x1c/0x118) from [] (__rtc_read_time+0x58/0x5c) [] (__rtc_read_time+0x58/0x5c) from [] (rtc_read_time+0x30/0x48) [] (rtc_read_time+0x30/0x48) from [] (__rtc_read_alarm+0x1c/0x290) [] (__rtc_read_alarm+0x1c/0x290) from [] (rtc_device_register+0x150/0x27c) [] (rtc_device_register+0x150/0x27c) from [] (mc13xxx_rtc_probe+0x128/0x17c) [] (mc13xxx_rtc_probe+0x128/0x17c) from [] (platform_drv_probe+0x1c/0x24) [] (platform_drv_probe+0x1c/0x24) from [] (driver_probe_device+0x80/0x1a8) [] (driver_probe_device+0x80/0x1a8) from [] (__driver_attach+0x8c/0x90) [] (__driver_attach+0x8c/0x90) from [] (bus_for_each_dev+0x60/0x8c) [] (bus_for_each_dev+0x60/0x8c) from [] (bus_add_driver+0x180/0x248) [] (bus_add_driver+0x180/0x248) from [] (driver_register+0x70/0x15c) [] (driver_register+0x70/0x15c) from [] (platform_driver_probe+0x18/0x98) [] (platform_driver_probe+0x18/0x98) from [] (do_one_initcall+0x2c/0x168) [] (do_one_initcall+0x2c/0x168) from [] (kernel_init+0xa0/0x150) [] (kernel_init+0xa0/0x150) from [] (kernel_thread_exit+0x0/0x8) Reported-by: Vagrant Cascadian Signed-off-by: Uwe Kleine-König Closes: http://bugs.debian.org/625804 [Tweaked commit log -jstultz] Signed-off-by: John Stultz diff --git a/drivers/rtc/rtc-mc13xxx.c b/drivers/rtc/rtc-mc13xxx.c index c5ac037..a1a278b 100644 --- a/drivers/rtc/rtc-mc13xxx.c +++ b/drivers/rtc/rtc-mc13xxx.c @@ -349,11 +349,15 @@ static int __devinit mc13xxx_rtc_probe(struct platform_device *pdev) if (ret) goto err_alarm_irq_request; + mc13xxx_unlock(mc13xxx); + priv->rtc = rtc_device_register(pdev->name, &pdev->dev, &mc13xxx_rtc_ops, THIS_MODULE); if (IS_ERR(priv->rtc)) { ret = PTR_ERR(priv->rtc); + mc13xxx_lock(mc13xxx); + mc13xxx_irq_free(mc13xxx, MC13XXX_IRQ_TODA, priv); err_alarm_irq_request: @@ -365,12 +369,12 @@ err_reset_irq_status: mc13xxx_irq_free(mc13xxx, MC13XXX_IRQ_RTCRST, priv); err_reset_irq_request: + mc13xxx_unlock(mc13xxx); + platform_set_drvdata(pdev, NULL); kfree(priv); } - mc13xxx_unlock(mc13xxx); - return ret; } -- cgit v0.10.2 From 3bd2cbb95543acf44fe123eb9f038de54e655eb4 Mon Sep 17 00:00:00 2001 From: Nicolas Pitre Date: Thu, 21 Apr 2011 21:45:08 -0400 Subject: ARM: zImage: make sure the stack is 64-bit aligned With ARMv5+ and EABI, the compiler expects a 64-bit aligned stack so instructions like STRD and LDRD can be used. Without this, mysterious boot failures were seen semi randomly with the LZMA decompressor. While at it, let's align .bss as well. Signed-off-by: Nicolas Pitre Tested-by: Shawn Guo Acked-by: Tony Lindgren CC: stable@kernel.org diff --git a/arch/arm/boot/compressed/Makefile b/arch/arm/boot/compressed/Makefile index 8ebbb51..0c6852d 100644 --- a/arch/arm/boot/compressed/Makefile +++ b/arch/arm/boot/compressed/Makefile @@ -74,7 +74,7 @@ ZTEXTADDR := $(CONFIG_ZBOOT_ROM_TEXT) ZBSSADDR := $(CONFIG_ZBOOT_ROM_BSS) else ZTEXTADDR := 0 -ZBSSADDR := ALIGN(4) +ZBSSADDR := ALIGN(8) endif SEDFLAGS = s/TEXT_START/$(ZTEXTADDR)/;s/BSS_START/$(ZBSSADDR)/ diff --git a/arch/arm/boot/compressed/vmlinux.lds.in b/arch/arm/boot/compressed/vmlinux.lds.in index 5309909..ea80abe 100644 --- a/arch/arm/boot/compressed/vmlinux.lds.in +++ b/arch/arm/boot/compressed/vmlinux.lds.in @@ -54,6 +54,7 @@ SECTIONS .bss : { *(.bss) } _end = .; + . = ALIGN(8); /* the stack must be 64-bit aligned */ .stack : { *(.stack) } .stab 0 : { *(.stab) } -- cgit v0.10.2 From 7c2527f0c4bf6bd096f58296597e1373387d69fd Mon Sep 17 00:00:00 2001 From: Tony Lindgren Date: Tue, 26 Apr 2011 05:37:46 -0700 Subject: ARM: zImage: Fix bad SP address after relocating kernel Otherwise cache_clean_flush can overwrite some of the relocated area depending on where the kernel image gets loaded. This fixes booting on n900 after commit 6d7d0ae51574943bf571d269da3243257a2d15db (ARM: 6750/1: improvements to compressed/head.S). Thanks to Aaro Koskinen for debugging the address of the relocated area that gets corrupted, and to Nicolas Pitre for the other uncompress related fixes. Signed-off-by: Tony Lindgren Signed-off-by: Nicolas Pitre diff --git a/arch/arm/boot/compressed/head.S b/arch/arm/boot/compressed/head.S index 84ac4d6..55a5bcb 100644 --- a/arch/arm/boot/compressed/head.S +++ b/arch/arm/boot/compressed/head.S @@ -253,6 +253,11 @@ restart: adr r0, LC0 /* Preserve offset to relocated code. */ sub r6, r9, r6 +#ifndef CONFIG_ZBOOT_ROM + /* cache_clean_flush may use the stack, so relocate it */ + add sp, sp, r6 +#endif + bl cache_clean_flush adr r0, BSYM(restart) -- cgit v0.10.2 From adcc25915b98e5752d51d66774ec4a61e50af3c5 Mon Sep 17 00:00:00 2001 From: Nicolas Pitre Date: Wed, 27 Apr 2011 16:15:11 -0400 Subject: ARM: zImage: make sure not to relocate on top of the relocation code If the zImage load address is slightly below the relocation address, there is a risk for the copied data to overwrite the copy loop or cache flush code that the relocation process requires. Always bump the relocation address by the size of that code to avoid this issue. Noticed by Tony Lindgren . While at it, let's start the copy from the restart symbol which makes the above code size computation possible by the assembler directly (same sections), given that we don't need to preserve the code before that point anyway. And therefore we don't need to carry the _start pointer in r5 anymore. Signed-off-by: Nicolas Pitre Tested-by: Tony Lindgren diff --git a/arch/arm/boot/compressed/head.S b/arch/arm/boot/compressed/head.S index 55a5bcb..53dd5da 100644 --- a/arch/arm/boot/compressed/head.S +++ b/arch/arm/boot/compressed/head.S @@ -187,15 +187,14 @@ not_angel: bl cache_on restart: adr r0, LC0 - ldmia r0, {r1, r2, r3, r5, r6, r9, r11, r12} - ldr sp, [r0, #32] + ldmia r0, {r1, r2, r3, r6, r9, r11, r12} + ldr sp, [r0, #28] /* * We might be running at a different address. We need * to fix up various pointers. */ sub r0, r0, r1 @ calculate the delta offset - add r5, r5, r0 @ _start add r6, r6, r0 @ _edata #ifndef CONFIG_ZBOOT_ROM @@ -214,31 +213,39 @@ restart: adr r0, LC0 /* * Check to see if we will overwrite ourselves. * r4 = final kernel address - * r5 = start of this image * r9 = size of decompressed image * r10 = end of this image, including bss/stack/malloc space if non XIP * We basically want: * r4 >= r10 -> OK - * r4 + image length <= r5 -> OK + * r4 + image length <= current position (pc) -> OK */ cmp r4, r10 bhs wont_overwrite add r10, r4, r9 - cmp r10, r5 + ARM( cmp r10, pc ) + THUMB( mov lr, pc ) + THUMB( cmp r10, lr ) bls wont_overwrite /* * Relocate ourselves past the end of the decompressed kernel. - * r5 = start of this image * r6 = _edata * r10 = end of the decompressed kernel * Because we always copy ahead, we need to do it from the end and go * backward in case the source and destination overlap. */ - /* Round up to next 256-byte boundary. */ - add r10, r10, #256 + /* + * Bump to the next 256-byte boundary with the size of + * the relocation code added. This avoids overwriting + * ourself when the offset is small. + */ + add r10, r10, #((reloc_code_end - restart + 256) & ~255) bic r10, r10, #255 + /* Get start of code we want to copy and align it down. */ + adr r5, restart + bic r5, r5, #31 + sub r9, r6, r5 @ size to copy add r9, r9, #31 @ rounded up to a multiple bic r9, r9, #31 @ ... of 32 bytes @@ -346,7 +353,6 @@ not_relocated: mov r0, #0 LC0: .word LC0 @ r1 .word __bss_start @ r2 .word _end @ r3 - .word _start @ r5 .word _edata @ r6 .word _image_size @ r9 .word _got_start @ r11 @@ -1075,6 +1081,7 @@ memdump: mov r12, r0 #endif .ltorg +reloc_code_end: .align .section ".stack", "aw", %nobits -- cgit v0.10.2 From ea9df3b168e641e87dbf889afae16390119e4179 Mon Sep 17 00:00:00 2001 From: Nicolas Pitre Date: Thu, 21 Apr 2011 22:52:06 -0400 Subject: ARM: zImage: the page table memory must be considered before relocation For correctness, the initial page table located right before the decompressed kernel should be considered when determining if relocation is required. Signed-off-by: Nicolas Pitre Tested-by: Shawn Guo Acked-by: Tony Lindgren diff --git a/arch/arm/boot/compressed/head.S b/arch/arm/boot/compressed/head.S index 53dd5da..d1fd1cf 100644 --- a/arch/arm/boot/compressed/head.S +++ b/arch/arm/boot/compressed/head.S @@ -216,9 +216,10 @@ restart: adr r0, LC0 * r9 = size of decompressed image * r10 = end of this image, including bss/stack/malloc space if non XIP * We basically want: - * r4 >= r10 -> OK + * r4 - 16k page directory >= r10 -> OK * r4 + image length <= current position (pc) -> OK */ + add r10, r10, #16384 cmp r4, r10 bhs wont_overwrite add r10, r4, r9 -- cgit v0.10.2 From 8fab6af2156c0100f953fd61f4e0b2f82c9776dc Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Fri, 6 May 2011 15:00:09 -0700 Subject: x86: Fix mrst sparse complaints Fix these Sparse complaints: CHECK arch/x86/platform/mrst/mrst.c arch/x86/platform/mrst/mrst.c:197:13: warning: symbol 'mrst_time_init' was not declared. Should it be static? arch/x86/platform/mrst/mrst.c:219:16: warning: symbol 'mrst_arch_setup' was not declared. Should it be static? Acked-by: Alan Cox Cc: Roman Gezikov Cc: Joonas Viskari Cc: Andrew Morton Cc: Allen Kao Signed-off-by: Luis R. Rodriguez Link: http://lkml.kernel.org/r/1304719209-26913-1-git-send-email-lrodriguez@atheros.com Signed-off-by: Ingo Molnar diff --git a/arch/x86/platform/mrst/mrst.c b/arch/x86/platform/mrst/mrst.c index 275dbc1..7000e74b 100644 --- a/arch/x86/platform/mrst/mrst.c +++ b/arch/x86/platform/mrst/mrst.c @@ -194,7 +194,7 @@ static unsigned long __init mrst_calibrate_tsc(void) return 0; } -void __init mrst_time_init(void) +static void __init mrst_time_init(void) { sfi_table_parse(SFI_SIG_MTMR, NULL, NULL, sfi_parse_mtmr); switch (mrst_timer_options) { @@ -216,7 +216,7 @@ void __init mrst_time_init(void) apbt_time_init(); } -void __cpuinit mrst_arch_setup(void) +static void __cpuinit mrst_arch_setup(void) { if (boot_cpu_data.x86 == 6 && boot_cpu_data.x86_model == 0x27) __mrst_cpu_chip = MRST_CPU_CHIP_PENWELL; -- cgit v0.10.2 From 174a7b1f9692acad7f0ca2b02f696894201a6d94 Mon Sep 17 00:00:00 2001 From: Lin Ming Date: Sat, 7 May 2011 12:41:14 +0800 Subject: perf tools: Makefile: Use gcc to determine ARCH The original Makefile uses "uname -m" to determine ARCH. This causes problem on x86 when compile perf tool on 32 bit userspace with a 64 bit kernel. bench/../../../arch/x86/lib/memcpy_64.S: Assembler messages: bench/../../../arch/x86/lib/memcpy_64.S:28: Error: bad register name `%rdi' This is because "uname -m" returns x86_64 and memcpy_64.S is included in 32 bit build. Reported-by: Riccardo Magliocchetti Signed-off-by: Lin Ming Cc: Peter Zijlstra Cc: Arnaldo Carvalho de Melo Link: http://lkml.kernel.org/r/1304743274.3132.17.camel@localhost Signed-off-by: Ingo Molnar diff --git a/tools/perf/Makefile b/tools/perf/Makefile index 207dee5..0c54256 100644 --- a/tools/perf/Makefile +++ b/tools/perf/Makefile @@ -35,15 +35,21 @@ ARCH ?= $(shell echo $(uname_M) | sed -e s/i.86/i386/ -e s/sun4u/sparc64/ \ -e s/ppc.*/powerpc/ -e s/mips.*/mips/ \ -e s/sh[234].*/sh/ ) +CC = $(CROSS_COMPILE)gcc +AR = $(CROSS_COMPILE)ar + # Additional ARCH settings for x86 ifeq ($(ARCH),i386) ARCH := x86 endif ifeq ($(ARCH),x86_64) - RAW_ARCH := x86_64 - ARCH := x86 - ARCH_CFLAGS := -DARCH_X86_64 - ARCH_INCLUDE = ../../arch/x86/lib/memcpy_64.S + ARCH := x86 + IS_X86_64 := $(shell echo __x86_64__ | ${CC} -E -xc - | tail -n 1) + ifeq (${IS_X86_64}, 1) + RAW_ARCH := x86_64 + ARCH_CFLAGS := -DARCH_X86_64 + ARCH_INCLUDE = ../../arch/x86/lib/memcpy_64.S + endif endif # @@ -119,8 +125,6 @@ lib = lib export prefix bindir sharedir sysconfdir -CC = $(CROSS_COMPILE)gcc -AR = $(CROSS_COMPILE)ar RM = rm -f MKDIR = mkdir FIND = find -- cgit v0.10.2 From a70b86ae206fdd3bef13c5ac148c22a805e83896 Mon Sep 17 00:00:00 2001 From: Jeff Kirsher Date: Tue, 3 May 2011 05:28:23 +0000 Subject: e100: implemenet set_phys_id Based on the original patch from Stephen Hemminger. Implement set_phys_id to control LED. CC: Stephen Hemminger Tested-by: Aaron Brown Signed-off-by: Jeff Kirsher diff --git a/drivers/net/e100.c b/drivers/net/e100.c index 29f812d..e336c79 100644 --- a/drivers/net/e100.c +++ b/drivers/net/e100.c @@ -593,7 +593,6 @@ struct nic { enum phy phy; struct params params; struct timer_list watchdog; - struct timer_list blink_timer; struct mii_if_info mii; struct work_struct tx_timeout_task; enum loopback loopback; @@ -618,7 +617,6 @@ struct nic { u32 rx_tco_frames; u32 rx_over_length_errors; - u16 leds; u16 eeprom_wc; __le16 eeprom[256]; spinlock_t mdio_lock; @@ -2353,30 +2351,6 @@ err_clean_rx: #define E100_82552_LED_OVERRIDE 0x19 #define E100_82552_LED_ON 0x000F /* LEDTX and LED_RX both on */ #define E100_82552_LED_OFF 0x000A /* LEDTX and LED_RX both off */ -static void e100_blink_led(unsigned long data) -{ - struct nic *nic = (struct nic *)data; - enum led_state { - led_on = 0x01, - led_off = 0x04, - led_on_559 = 0x05, - led_on_557 = 0x07, - }; - u16 led_reg = MII_LED_CONTROL; - - if (nic->phy == phy_82552_v) { - led_reg = E100_82552_LED_OVERRIDE; - - nic->leds = (nic->leds == E100_82552_LED_ON) ? - E100_82552_LED_OFF : E100_82552_LED_ON; - } else { - nic->leds = (nic->leds & led_on) ? led_off : - (nic->mac < mac_82559_D101M) ? led_on_557 : - led_on_559; - } - mdio_write(nic->netdev, nic->mii.phy_id, led_reg, nic->leds); - mod_timer(&nic->blink_timer, jiffies + HZ / 4); -} static int e100_get_settings(struct net_device *netdev, struct ethtool_cmd *cmd) { @@ -2600,19 +2574,38 @@ static void e100_diag_test(struct net_device *netdev, msleep_interruptible(4 * 1000); } -static int e100_phys_id(struct net_device *netdev, u32 data) +static int e100_set_phys_id(struct net_device *netdev, + enum ethtool_phys_id_state state) { struct nic *nic = netdev_priv(netdev); + enum led_state { + led_on = 0x01, + led_off = 0x04, + led_on_559 = 0x05, + led_on_557 = 0x07, + }; u16 led_reg = (nic->phy == phy_82552_v) ? E100_82552_LED_OVERRIDE : - MII_LED_CONTROL; + MII_LED_CONTROL; + u16 leds = 0; + + switch (state) { + case ETHTOOL_ID_ACTIVE: + return 2; - if (!data || data > (u32)(MAX_SCHEDULE_TIMEOUT / HZ)) - data = (u32)(MAX_SCHEDULE_TIMEOUT / HZ); - mod_timer(&nic->blink_timer, jiffies); - msleep_interruptible(data * 1000); - del_timer_sync(&nic->blink_timer); - mdio_write(netdev, nic->mii.phy_id, led_reg, 0); + case ETHTOOL_ID_ON: + leds = (nic->phy == phy_82552_v) ? E100_82552_LED_ON : + (nic->mac < mac_82559_D101M) ? led_on_557 : led_on_559; + break; + + case ETHTOOL_ID_OFF: + leds = (nic->phy == phy_82552_v) ? E100_82552_LED_OFF : led_off; + break; + + case ETHTOOL_ID_INACTIVE: + break; + } + mdio_write(netdev, nic->mii.phy_id, led_reg, leds); return 0; } @@ -2693,7 +2686,7 @@ static const struct ethtool_ops e100_ethtool_ops = { .set_ringparam = e100_set_ringparam, .self_test = e100_diag_test, .get_strings = e100_get_strings, - .phys_id = e100_phys_id, + .set_phys_id = e100_set_phys_id, .get_ethtool_stats = e100_get_ethtool_stats, .get_sset_count = e100_get_sset_count, }; @@ -2834,9 +2827,6 @@ static int __devinit e100_probe(struct pci_dev *pdev, init_timer(&nic->watchdog); nic->watchdog.function = e100_watchdog; nic->watchdog.data = (unsigned long)nic; - init_timer(&nic->blink_timer); - nic->blink_timer.function = e100_blink_led; - nic->blink_timer.data = (unsigned long)nic; INIT_WORK(&nic->tx_timeout_task, e100_tx_timeout_task); -- cgit v0.10.2 From 6435909199c2d1b0aad3ebbfa01f641aaa24fa2a Mon Sep 17 00:00:00 2001 From: Jeff Kirsher Date: Tue, 3 May 2011 05:26:13 +0000 Subject: e1000: convert to set_phys_id Based on the original patch from Stephen Hemminger. Convert to new LED control infrastucture and remove no longer necessary bits. CC: Stephen Hemminger Tested-by: Jeff Pieper Signed-off-by: Jeff Kirsher diff --git a/drivers/net/e1000/e1000.h b/drivers/net/e1000/e1000.h index b1b23dd..8676899 100644 --- a/drivers/net/e1000/e1000.h +++ b/drivers/net/e1000/e1000.h @@ -238,9 +238,6 @@ struct e1000_adapter { struct work_struct reset_task; u8 fc_autoneg; - struct timer_list blink_timer; - unsigned long led_status; - /* TX */ struct e1000_tx_ring *tx_ring; /* One per active queue */ unsigned int restart_queue; diff --git a/drivers/net/e1000/e1000_ethtool.c b/drivers/net/e1000/e1000_ethtool.c index 4fa727c..ec0fa42 100644 --- a/drivers/net/e1000/e1000_ethtool.c +++ b/drivers/net/e1000/e1000_ethtool.c @@ -1755,46 +1755,28 @@ static int e1000_set_wol(struct net_device *netdev, struct ethtool_wolinfo *wol) return 0; } -/* toggle LED 4 times per second = 2 "blinks" per second */ -#define E1000_ID_INTERVAL (HZ/4) - -/* bit defines for adapter->led_status */ -#define E1000_LED_ON 0 - -static void e1000_led_blink_callback(unsigned long data) +static int e1000_set_phys_id(struct net_device *netdev, + enum ethtool_phys_id_state state) { - struct e1000_adapter *adapter = (struct e1000_adapter *) data; + struct e1000_adapter *adapter = netdev_priv(netdev); struct e1000_hw *hw = &adapter->hw; - if (test_and_change_bit(E1000_LED_ON, &adapter->led_status)) - e1000_led_off(hw); - else - e1000_led_on(hw); - - mod_timer(&adapter->blink_timer, jiffies + E1000_ID_INTERVAL); -} + switch (state) { + case ETHTOOL_ID_ACTIVE: + e1000_setup_led(hw); + return 2; -static int e1000_phys_id(struct net_device *netdev, u32 data) -{ - struct e1000_adapter *adapter = netdev_priv(netdev); - struct e1000_hw *hw = &adapter->hw; + case ETHTOOL_ID_ON: + e1000_led_on(hw); + break; - if (!data) - data = INT_MAX; + case ETHTOOL_ID_OFF: + e1000_led_off(hw); + break; - if (!adapter->blink_timer.function) { - init_timer(&adapter->blink_timer); - adapter->blink_timer.function = e1000_led_blink_callback; - adapter->blink_timer.data = (unsigned long)adapter; + case ETHTOOL_ID_INACTIVE: + e1000_cleanup_led(hw); } - e1000_setup_led(hw); - mod_timer(&adapter->blink_timer, jiffies); - msleep_interruptible(data * 1000); - del_timer_sync(&adapter->blink_timer); - - e1000_led_off(hw); - clear_bit(E1000_LED_ON, &adapter->led_status); - e1000_cleanup_led(hw); return 0; } @@ -1931,7 +1913,7 @@ static const struct ethtool_ops e1000_ethtool_ops = { .set_tso = e1000_set_tso, .self_test = e1000_diag_test, .get_strings = e1000_get_strings, - .phys_id = e1000_phys_id, + .set_phys_id = e1000_set_phys_id, .get_ethtool_stats = e1000_get_ethtool_stats, .get_sset_count = e1000_get_sset_count, .get_coalesce = e1000_get_coalesce, -- cgit v0.10.2 From 936db3559fc4f6d2892234cadcbd88b8a7d34898 Mon Sep 17 00:00:00 2001 From: Jeff Kirsher Date: Sat, 7 May 2011 06:37:14 +0000 Subject: igb: convert to ethtool set_phys_id Based on patch from Stephen Hemminger. Convert igb driver to use new set_phys_id ethtool interface. CC: Stephen Hemminger Signed-off-by: Jeff Kirsher diff --git a/drivers/net/igb/igb_ethtool.c b/drivers/net/igb/igb_ethtool.c index 6e29634..fdc895e 100644 --- a/drivers/net/igb/igb_ethtool.c +++ b/drivers/net/igb/igb_ethtool.c @@ -1964,27 +1964,28 @@ static int igb_set_wol(struct net_device *netdev, struct ethtool_wolinfo *wol) /* bit defines for adapter->led_status */ #define IGB_LED_ON 0 -static int igb_phys_id(struct net_device *netdev, u32 data) +static int igb_set_phys_id(struct net_device *netdev, + enum ethtool_phys_id_state state) { struct igb_adapter *adapter = netdev_priv(netdev); struct e1000_hw *hw = &adapter->hw; - unsigned long timeout; - timeout = data * 1000; - - /* - * msleep_interruptable only accepts unsigned int so we are limited - * in how long a duration we can wait - */ - if (!timeout || timeout > UINT_MAX) - timeout = UINT_MAX; - - igb_blink_led(hw); - msleep_interruptible(timeout); - - igb_led_off(hw); - clear_bit(IGB_LED_ON, &adapter->led_status); - igb_cleanup_led(hw); + switch (state) { + case ETHTOOL_ID_ACTIVE: + igb_blink_led(hw); + return 2; + case ETHTOOL_ID_ON: + igb_blink_led(hw); + break; + case ETHTOOL_ID_OFF: + igb_led_off(hw); + break; + case ETHTOOL_ID_INACTIVE: + igb_led_off(hw); + clear_bit(IGB_LED_ON, &adapter->led_status); + igb_cleanup_led(hw); + break; + } return 0; } @@ -2216,7 +2217,7 @@ static const struct ethtool_ops igb_ethtool_ops = { .set_tso = igb_set_tso, .self_test = igb_diag_test, .get_strings = igb_get_strings, - .phys_id = igb_phys_id, + .set_phys_id = igb_set_phys_id, .get_sset_count = igb_get_sset_count, .get_ethtool_stats = igb_get_ethtool_stats, .get_coalesce = igb_get_coalesce, -- cgit v0.10.2 From 67a74ee2a24957012661dc4400e4f8e363d25fbb Mon Sep 17 00:00:00 2001 From: Emil Tantilov Date: Sat, 23 Apr 2011 04:50:40 +0000 Subject: ixgbe: add rxhash support feed RSS hash into skb->rxhash Signed-off-by: Emil Tantilov Tested-by: Evan Swanson Signed-off-by: Jeff Kirsher diff --git a/drivers/net/ixgbe/ixgbe_ethtool.c b/drivers/net/ixgbe/ixgbe_ethtool.c index f2efa32..545b231 100644 --- a/drivers/net/ixgbe/ixgbe_ethtool.c +++ b/drivers/net/ixgbe/ixgbe_ethtool.c @@ -2253,8 +2253,13 @@ static int ixgbe_set_flags(struct net_device *netdev, u32 data) need_reset = (data & ETH_FLAG_RXVLAN) != (netdev->features & NETIF_F_HW_VLAN_RX); + if ((data & ETH_FLAG_RXHASH) && + !(adapter->flags & IXGBE_FLAG_RSS_ENABLED)) + return -EOPNOTSUPP; + rc = ethtool_op_set_flags(netdev, data, ETH_FLAG_LRO | ETH_FLAG_NTUPLE | - ETH_FLAG_RXVLAN | ETH_FLAG_TXVLAN); + ETH_FLAG_RXVLAN | ETH_FLAG_TXVLAN | + ETH_FLAG_RXHASH); if (rc) return rc; diff --git a/drivers/net/ixgbe/ixgbe_main.c b/drivers/net/ixgbe/ixgbe_main.c index eebb192..56cc9a1 100644 --- a/drivers/net/ixgbe/ixgbe_main.c +++ b/drivers/net/ixgbe/ixgbe_main.c @@ -1063,8 +1063,14 @@ static int __ixgbe_notify_dca(struct device *dev, void *data) return 0; } - #endif /* CONFIG_IXGBE_DCA */ + +static inline void ixgbe_rx_hash(union ixgbe_adv_rx_desc *rx_desc, + struct sk_buff *skb) +{ + skb->rxhash = le32_to_cpu(rx_desc->wb.lower.hi_dword.rss); +} + /** * ixgbe_receive_skb - Send a completed packet up the stack * @adapter: board private structure @@ -1456,6 +1462,8 @@ static void ixgbe_clean_rx_irq(struct ixgbe_q_vector *q_vector, } ixgbe_rx_checksum(adapter, rx_desc, skb); + if (adapter->netdev->features & NETIF_F_RXHASH) + ixgbe_rx_hash(rx_desc, skb); /* probably a little skewed due to removing CRC */ total_rx_bytes += skb->len; @@ -7361,6 +7369,7 @@ static int __devinit ixgbe_probe(struct pci_dev *pdev, netdev->features |= NETIF_F_TSO; netdev->features |= NETIF_F_TSO6; netdev->features |= NETIF_F_GRO; + netdev->features |= NETIF_F_RXHASH; switch (adapter->hw.mac.type) { case ixgbe_mac_82599EB: @@ -7441,6 +7450,9 @@ static int __devinit ixgbe_probe(struct pci_dev *pdev, if (err) goto err_sw_init; + if (!(adapter->flags & IXGBE_FLAG_RSS_ENABLED)) + netdev->features &= ~NETIF_F_RXHASH; + switch (pdev->device) { case IXGBE_DEV_ID_82599_SFP: /* Only this subdevice supports WOL */ -- cgit v0.10.2 From 58f6bcf96e95f042a2bee6ace238365cb8fb1ce6 Mon Sep 17 00:00:00 2001 From: Emil Tantilov Date: Thu, 21 Apr 2011 08:43:43 +0000 Subject: ixgbe: add ethtool counters for OS2BMC OS2BMC registers are available for X540. This patch adds ethtool counters based on those registers. Signed-off-by: Emil Tantilov Tested-by: Evan Swanson Signed-off-by: Jeff Kirsher diff --git a/drivers/net/ixgbe/ixgbe_ethtool.c b/drivers/net/ixgbe/ixgbe_ethtool.c index 545b231..1fdd075 100644 --- a/drivers/net/ixgbe/ixgbe_ethtool.c +++ b/drivers/net/ixgbe/ixgbe_ethtool.c @@ -102,6 +102,10 @@ static struct ixgbe_stats ixgbe_gstrings_stats[] = { {"alloc_rx_page_failed", IXGBE_STAT(alloc_rx_page_failed)}, {"alloc_rx_buff_failed", IXGBE_STAT(alloc_rx_buff_failed)}, {"rx_no_dma_resources", IXGBE_STAT(hw_rx_no_dma_resources)}, + {"os2bmc_rx_by_bmc", IXGBE_STAT(stats.o2bgptc)}, + {"os2bmc_tx_by_bmc", IXGBE_STAT(stats.b2ospc)}, + {"os2bmc_tx_by_host", IXGBE_STAT(stats.o2bspc)}, + {"os2bmc_rx_by_host", IXGBE_STAT(stats.b2ogprc)}, #ifdef IXGBE_FCOE {"fcoe_bad_fccrc", IXGBE_STAT(stats.fccrc)}, {"rx_fcoe_dropped", IXGBE_STAT(stats.fcoerpdc)}, diff --git a/drivers/net/ixgbe/ixgbe_main.c b/drivers/net/ixgbe/ixgbe_main.c index 56cc9a1..a3e384b 100644 --- a/drivers/net/ixgbe/ixgbe_main.c +++ b/drivers/net/ixgbe/ixgbe_main.c @@ -5912,8 +5912,13 @@ void ixgbe_update_stats(struct ixgbe_adapter *adapter) hwstats->gotc += IXGBE_READ_REG(hw, IXGBE_GOTCH); hwstats->tor += IXGBE_READ_REG(hw, IXGBE_TORH); break; - case ixgbe_mac_82599EB: case ixgbe_mac_X540: + /* OS2BMC stats are X540 only*/ + hwstats->o2bgptc += IXGBE_READ_REG(hw, IXGBE_O2BGPTC); + hwstats->o2bspc += IXGBE_READ_REG(hw, IXGBE_O2BSPC); + hwstats->b2ospc += IXGBE_READ_REG(hw, IXGBE_B2OSPC); + hwstats->b2ogprc += IXGBE_READ_REG(hw, IXGBE_B2OGPRC); + case ixgbe_mac_82599EB: hwstats->gorc += IXGBE_READ_REG(hw, IXGBE_GORCL); IXGBE_READ_REG(hw, IXGBE_GORCH); /* to clear */ hwstats->gotc += IXGBE_READ_REG(hw, IXGBE_GOTCL); diff --git a/drivers/net/ixgbe/ixgbe_type.h b/drivers/net/ixgbe/ixgbe_type.h index b1d523c..70e6870 100644 --- a/drivers/net/ixgbe/ixgbe_type.h +++ b/drivers/net/ixgbe/ixgbe_type.h @@ -672,6 +672,10 @@ #define IXGBE_FCOEDWRC 0x0242C /* Number of FCoE DWords Received */ #define IXGBE_FCOEPTC 0x08784 /* Number of FCoE Packets Transmitted */ #define IXGBE_FCOEDWTC 0x08788 /* Number of FCoE DWords Transmitted */ +#define IXGBE_O2BGPTC 0x041C4 +#define IXGBE_O2BSPC 0x087B0 +#define IXGBE_B2OSPC 0x041C0 +#define IXGBE_B2OGPRC 0x02F90 #define IXGBE_PCRC8ECL 0x0E810 #define IXGBE_PCRC8ECH 0x0E811 #define IXGBE_PCRC8ECH_MASK 0x1F @@ -2554,6 +2558,10 @@ struct ixgbe_hw_stats { u64 fcoeptc; u64 fcoedwrc; u64 fcoedwtc; + u64 b2ospc; + u64 b2ogprc; + u64 o2bgptc; + u64 o2bspc; }; /* forward declaration */ -- cgit v0.10.2 From 0f020dec545629bb068310e8ee374648867e391c Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Sat, 7 May 2011 01:02:28 -0700 Subject: hamachi: Put back RX_CHECKSUM MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit I deleted it by mistake in the TX_CHECKSUM removal commit. Reported-by: MichaÅ‚ MirosÅ‚aw Signed-off-by: David S. Miller diff --git a/drivers/net/hamachi.c b/drivers/net/hamachi.c index f5fba73c..a09041a 100644 --- a/drivers/net/hamachi.c +++ b/drivers/net/hamachi.c @@ -134,6 +134,7 @@ static int tx_params[MAX_UNITS] = {-1, -1, -1, -1, -1, -1, -1, -1}; * TCP and UDP packets. Otherwise the upper layers do the calculation. * 3/10/1999 Pete Wyckoff */ +#define RX_CHECKSUM /* Operational parameters that usually are not changed. */ /* Time in jiffies before concluding the transmitter is hung. */ -- cgit v0.10.2 From 1217ed1ba5c67393293dfb0f03c353b118dadeb4 Mon Sep 17 00:00:00 2001 From: "Paul E. McKenney" Date: Wed, 4 May 2011 21:43:49 -0700 Subject: rcu: permit rcu_read_unlock() to be called while holding runqueue locks Avoid calling into the scheduler while holding core RCU locks. This allows rcu_read_unlock() to be called while holding the runqueue locks, but only as long as there was no chance of the RCU read-side critical section having been preempted. (Otherwise, if RCU priority boosting is enabled, rcu_read_unlock() might call into the scheduler in order to unboost itself, which might allows self-deadlock on the runqueue locks within the scheduler.) Signed-off-by: Paul E. McKenney Signed-off-by: Paul E. McKenney diff --git a/kernel/rcutree.c b/kernel/rcutree.c index 54ff7eb..5616b17 100644 --- a/kernel/rcutree.c +++ b/kernel/rcutree.c @@ -1133,22 +1133,7 @@ static void __rcu_offline_cpu(int cpu, struct rcu_state *rsp) raw_spin_unlock_irqrestore(&rnp->lock, flags); if (need_report & RCU_OFL_TASKS_EXP_GP) rcu_report_exp_rnp(rsp, rnp); - - /* - * If there are no more online CPUs for this rcu_node structure, - * kill the rcu_node structure's kthread. Otherwise, adjust its - * affinity. - */ - t = rnp->node_kthread_task; - if (t != NULL && - rnp->qsmaskinit == 0) { - raw_spin_lock_irqsave(&rnp->lock, flags); - rnp->node_kthread_task = NULL; - raw_spin_unlock_irqrestore(&rnp->lock, flags); - kthread_stop(t); - rcu_stop_boost_kthread(rnp); - } else - rcu_node_kthread_setaffinity(rnp, -1); + rcu_node_kthread_setaffinity(rnp, -1); } /* @@ -1320,8 +1305,7 @@ static void force_qs_rnp(struct rcu_state *rsp, int (*f)(struct rcu_data *)) return; } if (rnp->qsmask == 0) { - rcu_initiate_boost(rnp); - raw_spin_unlock_irqrestore(&rnp->lock, flags); + rcu_initiate_boost(rnp, flags); /* releases rnp->lock */ continue; } cpu = rnp->grplo; @@ -1340,10 +1324,10 @@ static void force_qs_rnp(struct rcu_state *rsp, int (*f)(struct rcu_data *)) raw_spin_unlock_irqrestore(&rnp->lock, flags); } rnp = rcu_get_root(rsp); - raw_spin_lock_irqsave(&rnp->lock, flags); - if (rnp->qsmask == 0) - rcu_initiate_boost(rnp); - raw_spin_unlock_irqrestore(&rnp->lock, flags); + if (rnp->qsmask == 0) { + raw_spin_lock_irqsave(&rnp->lock, flags); + rcu_initiate_boost(rnp, flags); /* releases rnp->lock. */ + } } /* @@ -1497,7 +1481,8 @@ static void invoke_rcu_cpu_kthread(void) /* * Wake up the specified per-rcu_node-structure kthread. - * The caller must hold ->lock. + * Because the per-rcu_node kthreads are immortal, we don't need + * to do anything to keep them alive. */ static void invoke_rcu_node_kthread(struct rcu_node *rnp) { @@ -1546,8 +1531,8 @@ static void rcu_cpu_kthread_timer(unsigned long arg) raw_spin_lock_irqsave(&rnp->lock, flags); rnp->wakemask |= rdp->grpmask; - invoke_rcu_node_kthread(rnp); raw_spin_unlock_irqrestore(&rnp->lock, flags); + invoke_rcu_node_kthread(rnp); } /* @@ -1694,16 +1679,12 @@ static int rcu_node_kthread(void *arg) for (;;) { rnp->node_kthread_status = RCU_KTHREAD_WAITING; - wait_event_interruptible(rnp->node_wq, rnp->wakemask != 0 || - kthread_should_stop()); - if (kthread_should_stop()) - break; + wait_event_interruptible(rnp->node_wq, rnp->wakemask != 0); rnp->node_kthread_status = RCU_KTHREAD_RUNNING; raw_spin_lock_irqsave(&rnp->lock, flags); mask = rnp->wakemask; rnp->wakemask = 0; - rcu_initiate_boost(rnp); - raw_spin_unlock_irqrestore(&rnp->lock, flags); + rcu_initiate_boost(rnp, flags); /* releases rnp->lock. */ for (cpu = rnp->grplo; cpu <= rnp->grphi; cpu++, mask >>= 1) { if ((mask & 0x1) == 0) continue; @@ -1719,6 +1700,7 @@ static int rcu_node_kthread(void *arg) preempt_enable(); } } + /* NOTREACHED */ rnp->node_kthread_status = RCU_KTHREAD_STOPPED; return 0; } @@ -1738,7 +1720,7 @@ static void rcu_node_kthread_setaffinity(struct rcu_node *rnp, int outgoingcpu) int cpu; unsigned long mask = rnp->qsmaskinit; - if (rnp->node_kthread_task == NULL || mask == 0) + if (rnp->node_kthread_task == NULL) return; if (!alloc_cpumask_var(&cm, GFP_KERNEL)) return; diff --git a/kernel/rcutree.h b/kernel/rcutree.h index a6a9717..93d4a1c 100644 --- a/kernel/rcutree.h +++ b/kernel/rcutree.h @@ -444,15 +444,12 @@ static void rcu_preempt_send_cbs_to_online(void); static void __init __rcu_init_preempt(void); static void rcu_needs_cpu_flush(void); static void __init rcu_init_boost_waitqueue(struct rcu_node *rnp); -static void rcu_initiate_boost(struct rcu_node *rnp); +static void rcu_initiate_boost(struct rcu_node *rnp, unsigned long flags); static void rcu_boost_kthread_setaffinity(struct rcu_node *rnp, cpumask_var_t cm); static void rcu_preempt_boost_start_gp(struct rcu_node *rnp); static int __cpuinit rcu_spawn_one_boost_kthread(struct rcu_state *rsp, struct rcu_node *rnp, int rnp_index); -#ifdef CONFIG_HOTPLUG_CPU -static void rcu_stop_boost_kthread(struct rcu_node *rnp); -#endif /* #ifdef CONFIG_HOTPLUG_CPU */ #endif /* #ifndef RCU_TREE_NONCORE */ diff --git a/kernel/rcutree_plugin.h b/kernel/rcutree_plugin.h index f629479..ed339702 100644 --- a/kernel/rcutree_plugin.h +++ b/kernel/rcutree_plugin.h @@ -711,15 +711,17 @@ static void rcu_report_exp_rnp(struct rcu_state *rsp, struct rcu_node *rnp) static void sync_rcu_preempt_exp_init(struct rcu_state *rsp, struct rcu_node *rnp) { + unsigned long flags; int must_wait = 0; - raw_spin_lock(&rnp->lock); /* irqs already disabled */ - if (!list_empty(&rnp->blkd_tasks)) { + raw_spin_lock_irqsave(&rnp->lock, flags); + if (list_empty(&rnp->blkd_tasks)) + raw_spin_unlock_irqrestore(&rnp->lock, flags); + else { rnp->exp_tasks = rnp->blkd_tasks.next; - rcu_initiate_boost(rnp); + rcu_initiate_boost(rnp, flags); /* releases rnp->lock */ must_wait = 1; } - raw_spin_unlock(&rnp->lock); /* irqs remain disabled */ if (!must_wait) rcu_report_exp_rnp(rsp, rnp); } @@ -1179,12 +1181,7 @@ static int rcu_boost(struct rcu_node *rnp) */ static void rcu_boost_kthread_timer(unsigned long arg) { - unsigned long flags; - struct rcu_node *rnp = (struct rcu_node *)arg; - - raw_spin_lock_irqsave(&rnp->lock, flags); - invoke_rcu_node_kthread(rnp); - raw_spin_unlock_irqrestore(&rnp->lock, flags); + invoke_rcu_node_kthread((struct rcu_node *)arg); } /* @@ -1200,10 +1197,7 @@ static int rcu_boost_kthread(void *arg) for (;;) { rnp->boost_kthread_status = RCU_KTHREAD_WAITING; wait_event_interruptible(rnp->boost_wq, rnp->boost_tasks || - rnp->exp_tasks || - kthread_should_stop()); - if (kthread_should_stop()) - break; + rnp->exp_tasks); rnp->boost_kthread_status = RCU_KTHREAD_RUNNING; more2boost = rcu_boost(rnp); if (more2boost) @@ -1215,7 +1209,7 @@ static int rcu_boost_kthread(void *arg) spincnt = 0; } } - rnp->boost_kthread_status = RCU_KTHREAD_STOPPED; + /* NOTREACHED */ return 0; } @@ -1225,14 +1219,17 @@ static int rcu_boost_kthread(void *arg) * kthread to start boosting them. If there is an expedited grace * period in progress, it is always time to boost. * - * The caller must hold rnp->lock. + * The caller must hold rnp->lock, which this function releases, + * but irqs remain disabled. The ->boost_kthread_task is immortal, + * so we don't need to worry about it going away. */ -static void rcu_initiate_boost(struct rcu_node *rnp) +static void rcu_initiate_boost(struct rcu_node *rnp, unsigned long flags) { struct task_struct *t; if (!rcu_preempt_blocked_readers_cgp(rnp) && rnp->exp_tasks == NULL) { rnp->n_balk_exp_gp_tasks++; + raw_spin_unlock_irqrestore(&rnp->lock, flags); return; } if (rnp->exp_tasks != NULL || @@ -1242,11 +1239,14 @@ static void rcu_initiate_boost(struct rcu_node *rnp) ULONG_CMP_GE(jiffies, rnp->boost_time))) { if (rnp->exp_tasks == NULL) rnp->boost_tasks = rnp->gp_tasks; + raw_spin_unlock_irqrestore(&rnp->lock, flags); t = rnp->boost_kthread_task; if (t != NULL) wake_up_process(t); - } else + } else { rcu_initiate_boost_trace(rnp); + raw_spin_unlock_irqrestore(&rnp->lock, flags); + } } /* @@ -1312,27 +1312,11 @@ static int __cpuinit rcu_spawn_one_boost_kthread(struct rcu_state *rsp, return 0; } -#ifdef CONFIG_HOTPLUG_CPU - -static void rcu_stop_boost_kthread(struct rcu_node *rnp) -{ - unsigned long flags; - struct task_struct *t; - - raw_spin_lock_irqsave(&rnp->lock, flags); - t = rnp->boost_kthread_task; - rnp->boost_kthread_task = NULL; - raw_spin_unlock_irqrestore(&rnp->lock, flags); - if (t != NULL) - kthread_stop(t); -} - -#endif /* #ifdef CONFIG_HOTPLUG_CPU */ - #else /* #ifdef CONFIG_RCU_BOOST */ -static void rcu_initiate_boost(struct rcu_node *rnp) +static void rcu_initiate_boost(struct rcu_node *rnp, unsigned long flags) { + raw_spin_unlock_irqrestore(&rnp->lock, flags); } static void rcu_boost_kthread_setaffinity(struct rcu_node *rnp, @@ -1355,14 +1339,6 @@ static int __cpuinit rcu_spawn_one_boost_kthread(struct rcu_state *rsp, return 0; } -#ifdef CONFIG_HOTPLUG_CPU - -static void rcu_stop_boost_kthread(struct rcu_node *rnp) -{ -} - -#endif /* #ifdef CONFIG_HOTPLUG_CPU */ - #endif /* #else #ifdef CONFIG_RCU_BOOST */ #ifndef CONFIG_SMP -- cgit v0.10.2 From 30088ad815802f850f26114920ccf9effd4bc520 Mon Sep 17 00:00:00 2001 From: Lai Jiangshan Date: Tue, 15 Mar 2011 17:53:46 +0800 Subject: cgroup,rcu: convert call_rcu(free_css_set_rcu) to kfree_rcu() The rcu callback free_css_set_rcu() just calls a kfree(), so we use kfree_rcu() instead of the call_rcu(free_css_set_rcu). Signed-off-by: Lai Jiangshan Acked-by: Paul Menage Signed-off-by: Paul E. McKenney Reviewed-by: Josh Triplett diff --git a/kernel/cgroup.c b/kernel/cgroup.c index 25c7eb5..d5160a8 100644 --- a/kernel/cgroup.c +++ b/kernel/cgroup.c @@ -326,12 +326,6 @@ static struct hlist_head *css_set_hash(struct cgroup_subsys_state *css[]) return &css_set_table[index]; } -static void free_css_set_rcu(struct rcu_head *obj) -{ - struct css_set *cg = container_of(obj, struct css_set, rcu_head); - kfree(cg); -} - /* We don't maintain the lists running through each css_set to its * task until after the first call to cgroup_iter_start(). This * reduces the fork()/exit() overhead for people who have cgroups @@ -375,7 +369,7 @@ static void __put_css_set(struct css_set *cg, int taskexit) } write_unlock(&css_set_lock); - call_rcu(&cg->rcu_head, free_css_set_rcu); + kfree_rcu(cg, rcu_head); } /* -- cgit v0.10.2 From f2da1c40dc003939f616f27a103b2592f1424b07 Mon Sep 17 00:00:00 2001 From: Lai Jiangshan Date: Tue, 15 Mar 2011 17:55:16 +0800 Subject: cgroup,rcu: convert call_rcu(free_cgroup_rcu) to kfree_rcu() The rcu callback free_cgroup_rcu() just calls a kfree(), so we use kfree_rcu() instead of the call_rcu(free_cgroup_rcu). Signed-off-by: Lai Jiangshan Acked-by: Paul Menage Signed-off-by: Paul E. McKenney Reviewed-by: Josh Triplett diff --git a/kernel/cgroup.c b/kernel/cgroup.c index d5160a8..20451ce 100644 --- a/kernel/cgroup.c +++ b/kernel/cgroup.c @@ -806,13 +806,6 @@ static int cgroup_call_pre_destroy(struct cgroup *cgrp) return ret; } -static void free_cgroup_rcu(struct rcu_head *obj) -{ - struct cgroup *cgrp = container_of(obj, struct cgroup, rcu_head); - - kfree(cgrp); -} - static void cgroup_diput(struct dentry *dentry, struct inode *inode) { /* is dentry a directory ? if so, kfree() associated cgroup */ @@ -850,7 +843,7 @@ static void cgroup_diput(struct dentry *dentry, struct inode *inode) */ BUG_ON(!list_empty(&cgrp->pidlists)); - call_rcu(&cgrp->rcu_head, free_cgroup_rcu); + kfree_rcu(cgrp, rcu_head); } iput(inode); } -- cgit v0.10.2 From 025cea99db3fb110ebc8ede5ff647833fab9574f Mon Sep 17 00:00:00 2001 From: Lai Jiangshan Date: Tue, 15 Mar 2011 17:56:10 +0800 Subject: cgroup,rcu: convert call_rcu(__free_css_id_cb) to kfree_rcu() The rcu callback __free_css_id_cb() just calls a kfree(), so we use kfree_rcu() instead of the call_rcu(__free_css_id_cb). Signed-off-by: Lai Jiangshan Acked-by: Paul Menage Signed-off-by: Paul E. McKenney Reviewed-by: Josh Triplett diff --git a/kernel/cgroup.c b/kernel/cgroup.c index 20451ce..909a355 100644 --- a/kernel/cgroup.c +++ b/kernel/cgroup.c @@ -4610,14 +4610,6 @@ bool css_is_ancestor(struct cgroup_subsys_state *child, return ret; } -static void __free_css_id_cb(struct rcu_head *head) -{ - struct css_id *id; - - id = container_of(head, struct css_id, rcu_head); - kfree(id); -} - void free_css_id(struct cgroup_subsys *ss, struct cgroup_subsys_state *css) { struct css_id *id = css->id; @@ -4632,7 +4624,7 @@ void free_css_id(struct cgroup_subsys *ss, struct cgroup_subsys_state *css) spin_lock(&ss->id_lock); idr_remove(&ss->idr, id->id); spin_unlock(&ss->id_lock); - call_rcu(&id->rcu_head, __free_css_id_cb); + kfree_rcu(id, rcu_head); } EXPORT_SYMBOL_GPL(free_css_id); -- cgit v0.10.2 From f5c8593c107500979909bd51c85e74bb2eaffbaa Mon Sep 17 00:00:00 2001 From: Lai Jiangshan Date: Tue, 15 Mar 2011 17:57:04 +0800 Subject: net,rcu: convert call_rcu(tcf_common_free_rcu) to kfree_rcu() The rcu callback tcf_common_free_rcu() just calls a kfree(), so we use kfree_rcu() instead of the call_rcu(tcf_common_free_rcu). Signed-off-by: Lai Jiangshan Acked-by: David S. Miller Signed-off-by: Paul E. McKenney Reviewed-by: Josh Triplett diff --git a/net/sched/act_api.c b/net/sched/act_api.c index 14b42f4..a606025 100644 --- a/net/sched/act_api.c +++ b/net/sched/act_api.c @@ -26,11 +26,6 @@ #include #include -static void tcf_common_free_rcu(struct rcu_head *head) -{ - kfree(container_of(head, struct tcf_common, tcfc_rcu)); -} - void tcf_hash_destroy(struct tcf_common *p, struct tcf_hashinfo *hinfo) { unsigned int h = tcf_hash(p->tcfc_index, hinfo->hmask); @@ -47,7 +42,7 @@ void tcf_hash_destroy(struct tcf_common *p, struct tcf_hashinfo *hinfo) * gen_estimator est_timer() might access p->tcfc_lock * or bstats, wait a RCU grace period before freeing p */ - call_rcu(&p->tcfc_rcu, tcf_common_free_rcu); + kfree_rcu(p, tcfc_rcu); return; } } -- cgit v0.10.2 From 5957b1ac52c5fde2afe5d80abe2a1cb82a9b4f20 Mon Sep 17 00:00:00 2001 From: Lai Jiangshan Date: Tue, 15 Mar 2011 17:58:00 +0800 Subject: net,rcu: convert call_rcu(tcf_police_free_rcu) to kfree_rcu() [PATCH 05/17] net,rcu: convert call_rcu(tcf_police_free_rcu) to kfree_rcu() The rcu callback tcf_police_free_rcu() just calls a kfree(), so we use kfree_rcu() instead of the call_rcu(tcf_police_free_rcu). Signed-off-by: Lai Jiangshan Acked-by: David S. Miller Signed-off-by: Paul E. McKenney Reviewed-by: Josh Triplett diff --git a/net/sched/act_police.c b/net/sched/act_police.c index 8a16307..d6bcd64 100644 --- a/net/sched/act_police.c +++ b/net/sched/act_police.c @@ -96,11 +96,6 @@ nla_put_failure: goto done; } -static void tcf_police_free_rcu(struct rcu_head *head) -{ - kfree(container_of(head, struct tcf_police, tcf_rcu)); -} - static void tcf_police_destroy(struct tcf_police *p) { unsigned int h = tcf_hash(p->tcf_index, POL_TAB_MASK); @@ -121,7 +116,7 @@ static void tcf_police_destroy(struct tcf_police *p) * gen_estimator est_timer() might access p->tcf_lock * or bstats, wait a RCU grace period before freeing p */ - call_rcu(&p->tcf_rcu, tcf_police_free_rcu); + kfree_rcu(p, tcf_rcu); return; } } -- cgit v0.10.2 From 38f57d1a4b4c13db92c7f6300a4e4ae70ff94d2b Mon Sep 17 00:00:00 2001 From: Lai Jiangshan Date: Tue, 15 Mar 2011 17:59:14 +0800 Subject: net,rcu: convert call_rcu(in6_dev_finish_destroy_rcu) to kfree_rcu() The rcu callback in6_dev_finish_destroy_rcu() just calls a kfree(), so we use kfree_rcu() instead of the call_rcu(in6_dev_finish_destroy_rcu). Signed-off-by: Lai Jiangshan Acked-by: David S. Miller Signed-off-by: Paul E. McKenney Reviewed-by: Josh Triplett diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c index a7bda07..c406f56 100644 --- a/net/ipv6/addrconf.c +++ b/net/ipv6/addrconf.c @@ -317,12 +317,6 @@ static void snmp6_free_dev(struct inet6_dev *idev) /* Nobody refers to this device, we may destroy it. */ -static void in6_dev_finish_destroy_rcu(struct rcu_head *head) -{ - struct inet6_dev *idev = container_of(head, struct inet6_dev, rcu); - kfree(idev); -} - void in6_dev_finish_destroy(struct inet6_dev *idev) { struct net_device *dev = idev->dev; @@ -339,7 +333,7 @@ void in6_dev_finish_destroy(struct inet6_dev *idev) return; } snmp6_free_dev(idev); - call_rcu(&idev->rcu, in6_dev_finish_destroy_rcu); + kfree_rcu(idev, rcu); } EXPORT_SYMBOL(in6_dev_finish_destroy); -- cgit v0.10.2 From e57859854aaac9b7ce0db3fe4959190a1a80b60a Mon Sep 17 00:00:00 2001 From: Lai Jiangshan Date: Tue, 15 Mar 2011 18:00:14 +0800 Subject: net,rcu: convert call_rcu(inet6_ifa_finish_destroy_rcu) to kfree_rcu() The rcu callback inet6_ifa_finish_destroy_rcu() just calls a kfree(), so we use kfree_rcu() instead of the call_rcu(inet6_ifa_finish_destroy_rcu). Signed-off-by: Lai Jiangshan Acked-by: David S. Miller Signed-off-by: Paul E. McKenney Reviewed-by: Josh Triplett diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c index c406f56..8f13d88 100644 --- a/net/ipv6/addrconf.c +++ b/net/ipv6/addrconf.c @@ -529,12 +529,6 @@ static int addrconf_fixup_forwarding(struct ctl_table *table, int *p, int old) } #endif -static void inet6_ifa_finish_destroy_rcu(struct rcu_head *head) -{ - struct inet6_ifaddr *ifp = container_of(head, struct inet6_ifaddr, rcu); - kfree(ifp); -} - /* Nobody refers to this ifaddr, destroy it */ void inet6_ifa_finish_destroy(struct inet6_ifaddr *ifp) { @@ -555,7 +549,7 @@ void inet6_ifa_finish_destroy(struct inet6_ifaddr *ifp) } dst_release(&ifp->rt->dst); - call_rcu(&ifp->rcu, inet6_ifa_finish_destroy_rcu); + kfree_rcu(ifp, rcu); } static void -- cgit v0.10.2 From 37b6b935e96e837ccc60812c03e9f92e7dce2e61 Mon Sep 17 00:00:00 2001 From: Lai Jiangshan Date: Tue, 15 Mar 2011 18:01:42 +0800 Subject: net,rcu: convert call_rcu(listeners_free_rcu) to kfree_rcu() The rcu callback listeners_free_rcu() just calls a kfree(), so we use kfree_rcu() instead of the call_rcu(listeners_free_rcu). Signed-off-by: Lai Jiangshan Acked-by: David S. Miller Signed-off-by: Paul E. McKenney Reviewed-by: Josh Triplett diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c index c8f35b5..5fe4f3b 100644 --- a/net/netlink/af_netlink.c +++ b/net/netlink/af_netlink.c @@ -1566,12 +1566,6 @@ netlink_kernel_release(struct sock *sk) } EXPORT_SYMBOL(netlink_kernel_release); - -static void listeners_free_rcu(struct rcu_head *head) -{ - kfree(container_of(head, struct listeners, rcu)); -} - int __netlink_change_ngroups(struct sock *sk, unsigned int groups) { struct listeners *new, *old; @@ -1588,7 +1582,7 @@ int __netlink_change_ngroups(struct sock *sk, unsigned int groups) memcpy(new->masks, old->masks, NLGRPSZ(tbl->groups)); rcu_assign_pointer(tbl->listeners, new); - call_rcu(&old->rcu, listeners_free_rcu); + kfree_rcu(old, rcu); } tbl->groups = groups; -- cgit v0.10.2 From 1231f0baa547a541a7481119323b7f964dda4788 Mon Sep 17 00:00:00 2001 From: Lai Jiangshan Date: Tue, 15 Mar 2011 18:05:02 +0800 Subject: net,rcu: convert call_rcu(sctp_local_addr_free) to kfree_rcu() The rcu callback sctp_local_addr_free() just calls a kfree(), so we use kfree_rcu() instead of the call_rcu(sctp_local_addr_free). Signed-off-by: Lai Jiangshan Acked-by: David S. Miller Signed-off-by: Paul E. McKenney Reviewed-by: Josh Triplett diff --git a/include/net/sctp/sctp.h b/include/net/sctp/sctp.h index 505845d..01e094c 100644 --- a/include/net/sctp/sctp.h +++ b/include/net/sctp/sctp.h @@ -115,7 +115,6 @@ * sctp/protocol.c */ extern struct sock *sctp_get_ctl_sock(void); -extern void sctp_local_addr_free(struct rcu_head *head); extern int sctp_copy_local_addr_list(struct sctp_bind_addr *, sctp_scope_t, gfp_t gfp, int flags); diff --git a/net/sctp/bind_addr.c b/net/sctp/bind_addr.c index faf71d1..3c06c87 100644 --- a/net/sctp/bind_addr.c +++ b/net/sctp/bind_addr.c @@ -219,7 +219,7 @@ int sctp_del_bind_addr(struct sctp_bind_addr *bp, union sctp_addr *del_addr) } if (found) { - call_rcu(&addr->rcu, sctp_local_addr_free); + kfree_rcu(addr, rcu); SCTP_DBG_OBJCNT_DEC(addr); return 0; } diff --git a/net/sctp/ipv6.c b/net/sctp/ipv6.c index 865ce7b..185fe05 100644 --- a/net/sctp/ipv6.c +++ b/net/sctp/ipv6.c @@ -123,7 +123,7 @@ static int sctp_inet6addr_event(struct notifier_block *this, unsigned long ev, } spin_unlock_bh(&sctp_local_addr_lock); if (found) - call_rcu(&addr->rcu, sctp_local_addr_free); + kfree_rcu(addr, rcu); break; } diff --git a/net/sctp/protocol.c b/net/sctp/protocol.c index d5bf91d..065d999 100644 --- a/net/sctp/protocol.c +++ b/net/sctp/protocol.c @@ -230,13 +230,6 @@ static void sctp_free_local_addr_list(void) } } -void sctp_local_addr_free(struct rcu_head *head) -{ - struct sctp_sockaddr_entry *e = container_of(head, - struct sctp_sockaddr_entry, rcu); - kfree(e); -} - /* Copy the local addresses which are valid for 'scope' into 'bp'. */ int sctp_copy_local_addr_list(struct sctp_bind_addr *bp, sctp_scope_t scope, gfp_t gfp, int copy_flags) @@ -681,7 +674,7 @@ static int sctp_inetaddr_event(struct notifier_block *this, unsigned long ev, } spin_unlock_bh(&sctp_local_addr_lock); if (found) - call_rcu(&addr->rcu, sctp_local_addr_free); + kfree_rcu(addr, rcu); break; } -- cgit v0.10.2 From 217f18639bc18ba4bbb67481113037344c148938 Mon Sep 17 00:00:00 2001 From: Lai Jiangshan Date: Tue, 15 Mar 2011 18:08:58 +0800 Subject: net,rcu: convert call_rcu(ha_rcu_free) to kfree_rcu() The rcu callback ha_rcu_free() just calls a kfree(), so we use kfree_rcu() instead of the call_rcu(ha_rcu_free). Signed-off-by: Lai Jiangshan Acked-by: David S. Miller Signed-off-by: Paul E. McKenney Reviewed-by: Josh Triplett diff --git a/net/core/dev_addr_lists.c b/net/core/dev_addr_lists.c index 7b39f3e..e2e6693 100644 --- a/net/core/dev_addr_lists.c +++ b/net/core/dev_addr_lists.c @@ -68,14 +68,6 @@ static int __hw_addr_add(struct netdev_hw_addr_list *list, unsigned char *addr, return __hw_addr_add_ex(list, addr, addr_len, addr_type, false); } -static void ha_rcu_free(struct rcu_head *head) -{ - struct netdev_hw_addr *ha; - - ha = container_of(head, struct netdev_hw_addr, rcu_head); - kfree(ha); -} - static int __hw_addr_del_ex(struct netdev_hw_addr_list *list, unsigned char *addr, int addr_len, unsigned char addr_type, bool global) @@ -94,7 +86,7 @@ static int __hw_addr_del_ex(struct netdev_hw_addr_list *list, if (--ha->refcount) return 0; list_del_rcu(&ha->list); - call_rcu(&ha->rcu_head, ha_rcu_free); + kfree_rcu(ha, rcu_head); list->count--; return 0; } @@ -197,7 +189,7 @@ void __hw_addr_flush(struct netdev_hw_addr_list *list) list_for_each_entry_safe(ha, tmp, &list->list, list) { list_del_rcu(&ha->list); - call_rcu(&ha->rcu_head, ha_rcu_free); + kfree_rcu(ha, rcu_head); } list->count = 0; } -- cgit v0.10.2 From 1e547757eca3c30eeeac526716e4ae833c2a9a2f Mon Sep 17 00:00:00 2001 From: Lai Jiangshan Date: Tue, 15 Mar 2011 18:10:12 +0800 Subject: net,rcu: convert call_rcu(dn_dev_free_ifa_rcu) to kfree_rcu() The rcu callback dn_dev_free_ifa_rcu() just calls a kfree(), so we use kfree_rcu() instead of the call_rcu(dn_dev_free_ifa_rcu). Signed-off-by: Lai Jiangshan Acked-by: David S. Miller Signed-off-by: Paul E. McKenney Reviewed-by: Josh Triplett diff --git a/net/decnet/dn_dev.c b/net/decnet/dn_dev.c index 0dcaa90..4c27615 100644 --- a/net/decnet/dn_dev.c +++ b/net/decnet/dn_dev.c @@ -332,14 +332,9 @@ static struct dn_ifaddr *dn_dev_alloc_ifa(void) return ifa; } -static void dn_dev_free_ifa_rcu(struct rcu_head *head) -{ - kfree(container_of(head, struct dn_ifaddr, rcu)); -} - static void dn_dev_free_ifa(struct dn_ifaddr *ifa) { - call_rcu(&ifa->rcu, dn_dev_free_ifa_rcu); + kfree_rcu(ifa, rcu); } static void dn_dev_del_ifa(struct dn_dev *dn_db, struct dn_ifaddr __rcu **ifap, int destroy) -- cgit v0.10.2 From 75ef0368d182785c7c5c06ac11081e31257a313e Mon Sep 17 00:00:00 2001 From: Lai Jiangshan Date: Tue, 15 Mar 2011 18:11:46 +0800 Subject: net,act_police,rcu: remove rcu_barrier() There is no callback of this module maybe queued since we use kfree_rcu(), we can safely remove the rcu_barrier(). Signed-off-by: Lai Jiangshan Acked-by: David S. Miller Signed-off-by: Paul E. McKenney Reviewed-by: Josh Triplett diff --git a/net/sched/act_police.c b/net/sched/act_police.c index d6bcd64..b3b9b32 100644 --- a/net/sched/act_police.c +++ b/net/sched/act_police.c @@ -396,7 +396,6 @@ static void __exit police_cleanup_module(void) { tcf_unregister_action(&act_police_ops); - rcu_barrier(); /* Wait for completion of call_rcu()'s (tcf_police_free_rcu) */ } module_init(police_init_module); -- cgit v0.10.2 From 3acb458c32293405cf68985b7b3ac5dc0a5e7929 Mon Sep 17 00:00:00 2001 From: Lai Jiangshan Date: Fri, 18 Mar 2011 12:11:07 +0800 Subject: security,rcu: convert call_rcu(user_update_rcu_disposal) to kfree_rcu() The rcu callback user_update_rcu_disposal() just calls a kfree(), so we use kfree_rcu() instead of the call_rcu(user_update_rcu_disposal). Signed-off-by: Lai Jiangshan Signed-off-by: Paul E. McKenney Acked-by: David Howells Reviewed-by: Josh Triplett diff --git a/security/keys/user_defined.c b/security/keys/user_defined.c index c6ca866..f66baf4 100644 --- a/security/keys/user_defined.c +++ b/security/keys/user_defined.c @@ -69,18 +69,6 @@ error: EXPORT_SYMBOL_GPL(user_instantiate); /* - * dispose of the old data from an updated user defined key - */ -static void user_update_rcu_disposal(struct rcu_head *rcu) -{ - struct user_key_payload *upayload; - - upayload = container_of(rcu, struct user_key_payload, rcu); - - kfree(upayload); -} - -/* * update a user defined key * - the key's semaphore is write-locked */ @@ -114,7 +102,7 @@ int user_update(struct key *key, const void *data, size_t datalen) key->expiry = 0; } - call_rcu(&zap->rcu, user_update_rcu_disposal); + kfree_rcu(zap, rcu); error: return ret; @@ -145,7 +133,7 @@ void user_revoke(struct key *key) if (upayload) { rcu_assign_pointer(key->payload.data, NULL); - call_rcu(&upayload->rcu, user_update_rcu_disposal); + kfree_rcu(upayload, rcu); } } -- cgit v0.10.2 From 4670994d150a86ebd53ab353a2af517c5465bfaf Mon Sep 17 00:00:00 2001 From: Lai Jiangshan Date: Fri, 18 Mar 2011 11:42:11 +0800 Subject: net,rcu: convert call_rcu(fc_rport_free_rcu) to kfree_rcu() The rcu callback fc_rport_free_rcu() just calls a kfree(), so we use kfree_rcu() instead of the call_rcu(fc_rport_free_rcu). Signed-off-by: Lai Jiangshan Acked-by: David S. Miller Signed-off-by: Paul E. McKenney Reviewed-by: Josh Triplett diff --git a/net/ipv4/fib_semantics.c b/net/ipv4/fib_semantics.c index 641a5a2..33e2c35 100644 --- a/net/ipv4/fib_semantics.c +++ b/net/ipv4/fib_semantics.c @@ -141,18 +141,8 @@ const struct fib_prop fib_props[RTN_MAX + 1] = { }, }; - /* Release a nexthop info record */ -static void free_fib_info_rcu(struct rcu_head *head) -{ - struct fib_info *fi = container_of(head, struct fib_info, rcu); - - if (fi->fib_metrics != (u32 *) dst_default_metrics) - kfree(fi->fib_metrics); - kfree(fi); -} - void free_fib_info(struct fib_info *fi) { if (fi->fib_dead == 0) { @@ -166,7 +156,7 @@ void free_fib_info(struct fib_info *fi) } endfor_nexthops(fi); fib_info_cnt--; release_net(fi->fib_net); - call_rcu(&fi->rcu, free_fib_info_rcu); + kfree_rcu(fi, rcu); } void fib_release_info(struct fib_info *fi) -- cgit v0.10.2 From bceb0f4512d448763fe98c9f37504c98bbebbed6 Mon Sep 17 00:00:00 2001 From: Lai Jiangshan Date: Fri, 18 Mar 2011 11:42:34 +0800 Subject: net,rcu: convert call_rcu(__leaf_info_free_rcu) to kfree_rcu() The rcu callback __leaf_info_free_rcu() just calls a kfree(), so we use kfree_rcu() instead of the call_rcu(__leaf_info_free_rcu). Signed-off-by: Lai Jiangshan Acked-by: David S. Miller Signed-off-by: Paul E. McKenney Reviewed-by: Josh Triplett diff --git a/net/ipv4/fib_trie.c b/net/ipv4/fib_trie.c index 5fe9b8b..11d4d28 100644 --- a/net/ipv4/fib_trie.c +++ b/net/ipv4/fib_trie.c @@ -350,14 +350,9 @@ static inline void free_leaf(struct leaf *l) call_rcu_bh(&l->rcu, __leaf_free_rcu); } -static void __leaf_info_free_rcu(struct rcu_head *head) -{ - kfree(container_of(head, struct leaf_info, rcu)); -} - static inline void free_leaf_info(struct leaf_info *leaf) { - call_rcu(&leaf->rcu, __leaf_info_free_rcu); + kfree_rcu(leaf, rcu); } static struct tnode *tnode_alloc(size_t size) -- cgit v0.10.2 From dad178fcd5b295f5f350a46a5eaf2f28e847bb5a Mon Sep 17 00:00:00 2001 From: Lai Jiangshan Date: Fri, 18 Mar 2011 11:43:26 +0800 Subject: net,rcu: convert call_rcu(__gen_kill_estimator) to kfree_rcu() The rcu callback __gen_kill_estimator() just calls a kfree(), so we use kfree_rcu() instead of the call_rcu(__gen_kill_estimator). Signed-off-by: Lai Jiangshan Acked-by: David S. Miller Signed-off-by: Paul E. McKenney Reviewed-by: Josh Triplett diff --git a/net/core/gen_estimator.c b/net/core/gen_estimator.c index 7c23733..43b03dd 100644 --- a/net/core/gen_estimator.c +++ b/net/core/gen_estimator.c @@ -249,13 +249,6 @@ int gen_new_estimator(struct gnet_stats_basic_packed *bstats, } EXPORT_SYMBOL(gen_new_estimator); -static void __gen_kill_estimator(struct rcu_head *head) -{ - struct gen_estimator *e = container_of(head, - struct gen_estimator, e_rcu); - kfree(e); -} - /** * gen_kill_estimator - remove a rate estimator * @bstats: basic statistics @@ -279,7 +272,7 @@ void gen_kill_estimator(struct gnet_stats_basic_packed *bstats, write_unlock(&est_lock); list_del_rcu(&e->list); - call_rcu(&e->e_rcu, __gen_kill_estimator); + kfree_rcu(e, e_rcu); } spin_unlock_bh(&est_tree_lock); } -- cgit v0.10.2 From 42ea299d3f1941f8c3dbc1fe031d682f8ad45005 Mon Sep 17 00:00:00 2001 From: Lai Jiangshan Date: Fri, 18 Mar 2011 11:44:08 +0800 Subject: net,rcu: convert call_rcu(ip_mc_list_reclaim) to kfree_rcu() The rcu callback ip_mc_list_reclaim() just calls a kfree(), so we use kfree_rcu() instead of the call_rcu(ip_mc_list_reclaim). Signed-off-by: Lai Jiangshan Acked-by: David S. Miller Signed-off-by: Paul E. McKenney Reviewed-by: Josh Triplett diff --git a/net/ipv4/igmp.c b/net/ipv4/igmp.c index 1fd3d9c..f22f30e 100644 --- a/net/ipv4/igmp.c +++ b/net/ipv4/igmp.c @@ -149,17 +149,11 @@ static void ip_mc_clear_src(struct ip_mc_list *pmc); static int ip_mc_add_src(struct in_device *in_dev, __be32 *pmca, int sfmode, int sfcount, __be32 *psfsrc, int delta); - -static void ip_mc_list_reclaim(struct rcu_head *head) -{ - kfree(container_of(head, struct ip_mc_list, rcu)); -} - static void ip_ma_put(struct ip_mc_list *im) { if (atomic_dec_and_test(&im->refcnt)) { in_dev_put(im->interface); - call_rcu(&im->rcu, ip_mc_list_reclaim); + kfree_rcu(im, rcu); } } -- cgit v0.10.2 From 7519cce48fb0a314dac473bdfba203b787435857 Mon Sep 17 00:00:00 2001 From: Lai Jiangshan Date: Fri, 18 Mar 2011 11:44:46 +0800 Subject: net,rcu: convert call_rcu(ip_sf_socklist_reclaim) to kfree_rcu() The rcu callback ip_sf_socklist_reclaim() just calls a kfree(), so we use kfree_rcu() instead of the call_rcu(ip_sf_socklist_reclaim). Signed-off-by: Lai Jiangshan Acked-by: David S. Miller Signed-off-by: Paul E. McKenney Reviewed-by: Josh Triplett diff --git a/net/ipv4/igmp.c b/net/ipv4/igmp.c index f22f30e..85a6e5d 100644 --- a/net/ipv4/igmp.c +++ b/net/ipv4/igmp.c @@ -1830,12 +1830,6 @@ done: } EXPORT_SYMBOL(ip_mc_join_group); -static void ip_sf_socklist_reclaim(struct rcu_head *rp) -{ - kfree(container_of(rp, struct ip_sf_socklist, rcu)); - /* sk_omem_alloc should have been decreased by the caller*/ -} - static int ip_mc_leave_src(struct sock *sk, struct ip_mc_socklist *iml, struct in_device *in_dev) { @@ -1852,7 +1846,7 @@ static int ip_mc_leave_src(struct sock *sk, struct ip_mc_socklist *iml, rcu_assign_pointer(iml->sflist, NULL); /* decrease mem now to avoid the memleak warning */ atomic_sub(IP_SFLSIZE(psf->sl_max), &sk->sk_omem_alloc); - call_rcu(&psf->rcu, ip_sf_socklist_reclaim); + kfree_rcu(psf, rcu); return err; } @@ -2020,7 +2014,7 @@ int ip_mc_source(int add, int omode, struct sock *sk, struct newpsl->sl_addr[i] = psl->sl_addr[i]; /* decrease mem now to avoid the memleak warning */ atomic_sub(IP_SFLSIZE(psl->sl_max), &sk->sk_omem_alloc); - call_rcu(&psl->rcu, ip_sf_socklist_reclaim); + kfree_rcu(psl, rcu); } rcu_assign_pointer(pmc->sflist, newpsl); psl = newpsl; @@ -2121,7 +2115,7 @@ int ip_mc_msfilter(struct sock *sk, struct ip_msfilter *msf, int ifindex) psl->sl_count, psl->sl_addr, 0); /* decrease mem now to avoid the memleak warning */ atomic_sub(IP_SFLSIZE(psl->sl_max), &sk->sk_omem_alloc); - call_rcu(&psl->rcu, ip_sf_socklist_reclaim); + kfree_rcu(psl, rcu); } else (void) ip_mc_del_src(in_dev, &msf->imsf_multiaddr, pmc->sfmode, 0, NULL, 0); -- cgit v0.10.2 From 10d50e748d983ff1003e0cf556ea17fa8f32c382 Mon Sep 17 00:00:00 2001 From: Lai Jiangshan Date: Fri, 18 Mar 2011 11:45:08 +0800 Subject: net,rcu: convert call_rcu(ip_mc_socklist_reclaim) to kfree_rcu() The rcu callback ip_mc_socklist_reclaim() just calls a kfree(), so we use kfree_rcu() instead of the call_rcu(ip_mc_socklist_reclaim). Signed-off-by: Lai Jiangshan Acked-by: David S. Miller Signed-off-by: Paul E. McKenney Reviewed-by: Josh Triplett diff --git a/net/ipv4/igmp.c b/net/ipv4/igmp.c index 85a6e5d..8f62d66 100644 --- a/net/ipv4/igmp.c +++ b/net/ipv4/igmp.c @@ -1850,14 +1850,6 @@ static int ip_mc_leave_src(struct sock *sk, struct ip_mc_socklist *iml, return err; } - -static void ip_mc_socklist_reclaim(struct rcu_head *rp) -{ - kfree(container_of(rp, struct ip_mc_socklist, rcu)); - /* sk_omem_alloc should have been decreased by the caller*/ -} - - /* * Ask a socket to leave a group. */ @@ -1897,7 +1889,7 @@ int ip_mc_leave_group(struct sock *sk, struct ip_mreqn *imr) rtnl_unlock(); /* decrease mem now to avoid the memleak warning */ atomic_sub(sizeof(*iml), &sk->sk_omem_alloc); - call_rcu(&iml->rcu, ip_mc_socklist_reclaim); + kfree_rcu(iml, rcu); return 0; } if (!in_dev) @@ -2312,7 +2304,7 @@ void ip_mc_drop_socket(struct sock *sk) ip_mc_dec_group(in_dev, iml->multi.imr_multiaddr.s_addr); /* decrease mem now to avoid the memleak warning */ atomic_sub(sizeof(*iml), &sk->sk_omem_alloc); - call_rcu(&iml->rcu, ip_mc_socklist_reclaim); + kfree_rcu(iml, rcu); } rtnl_unlock(); } -- cgit v0.10.2 From fa81c0e1d2d2176f1136c72c080c9ea4a98be347 Mon Sep 17 00:00:00 2001 From: Lai Jiangshan Date: Fri, 18 Mar 2011 11:39:43 +0800 Subject: net,rcu: convert call_rcu(free_dm_hw_stat) to kfree_rcu() The rcu callback free_dm_hw_stat() just calls a kfree(), so we use kfree_rcu() instead of the call_rcu(free_dm_hw_stat). Signed-off-by: Lai Jiangshan Acked-by: Neil Horman Acked-by: David S. Miller Signed-off-by: Paul E. McKenney Reviewed-by: Josh Triplett diff --git a/net/core/drop_monitor.c b/net/core/drop_monitor.c index 706502f..7f36b38 100644 --- a/net/core/drop_monitor.c +++ b/net/core/drop_monitor.c @@ -207,14 +207,6 @@ static void trace_napi_poll_hit(void *ignore, struct napi_struct *napi) rcu_read_unlock(); } - -static void free_dm_hw_stat(struct rcu_head *head) -{ - struct dm_hw_stat_delta *n; - n = container_of(head, struct dm_hw_stat_delta, rcu); - kfree(n); -} - static int set_all_monitor_traces(int state) { int rc = 0; @@ -245,7 +237,7 @@ static int set_all_monitor_traces(int state) list_for_each_entry_safe(new_stat, temp, &hw_stats_list, list) { if (new_stat->dev == NULL) { list_del_rcu(&new_stat->list); - call_rcu(&new_stat->rcu, free_dm_hw_stat); + kfree_rcu(new_stat, rcu); } } break; @@ -314,7 +306,7 @@ static int dropmon_net_event(struct notifier_block *ev_block, new_stat->dev = NULL; if (trace_state == TRACE_OFF) { list_del_rcu(&new_stat->list); - call_rcu(&new_stat->rcu, free_dm_hw_stat); + kfree_rcu(new_stat, rcu); break; } } -- cgit v0.10.2 From bcec8b6531d481ced35506517af69adb2399f2a4 Mon Sep 17 00:00:00 2001 From: Lai Jiangshan Date: Fri, 18 Mar 2011 11:57:21 +0800 Subject: ixgbe,rcu: convert call_rcu(ring_free_rcu) to kfree_rcu() The rcu callback ring_free_rcu() just calls a kfree(), so we use kfree_rcu() instead of the call_rcu(ring_free_rcu). Signed-off-by: Lai Jiangshan Acked-by: David S. Miller Signed-off-by: Paul E. McKenney Reviewed-by: Josh Triplett diff --git a/drivers/net/ixgbe/ixgbe_main.c b/drivers/net/ixgbe/ixgbe_main.c index 6f8adc7..e145f2c 100644 --- a/drivers/net/ixgbe/ixgbe_main.c +++ b/drivers/net/ixgbe/ixgbe_main.c @@ -5100,11 +5100,6 @@ err_set_interrupt: return err; } -static void ring_free_rcu(struct rcu_head *head) -{ - kfree(container_of(head, struct ixgbe_ring, rcu)); -} - /** * ixgbe_clear_interrupt_scheme - Clear the current interrupt scheme settings * @adapter: board private structure to clear interrupt scheme on @@ -5126,7 +5121,7 @@ void ixgbe_clear_interrupt_scheme(struct ixgbe_adapter *adapter) /* ixgbe_get_stats64() might access this ring, we must wait * a grace period before freeing it. */ - call_rcu(&ring->rcu, ring_free_rcu); + kfree_rcu(ring, rcu); adapter->rx_ring[i] = NULL; } -- cgit v0.10.2 From 6e070aecd9e304264a6b8655f49aa7e6db0e55f2 Mon Sep 17 00:00:00 2001 From: Lai Jiangshan Date: Fri, 18 Mar 2011 12:00:07 +0800 Subject: macvlan,rcu: convert call_rcu(macvlan_port_rcu_free) to kfree_rcu() The rcu callback macvlan_port_rcu_free() just calls a kfree(), so we use kfree_rcu() instead of the call_rcu(macvlan_port_rcu_free). Signed-off-by: Lai Jiangshan Acked-by: David S. Miller Signed-off-by: Paul E. McKenney Reviewed-by: Josh Triplett diff --git a/drivers/net/macvlan.c b/drivers/net/macvlan.c index 78e34e9..d8e4e69 100644 --- a/drivers/net/macvlan.c +++ b/drivers/net/macvlan.c @@ -603,21 +603,13 @@ static int macvlan_port_create(struct net_device *dev) return err; } -static void macvlan_port_rcu_free(struct rcu_head *head) -{ - struct macvlan_port *port; - - port = container_of(head, struct macvlan_port, rcu); - kfree(port); -} - static void macvlan_port_destroy(struct net_device *dev) { struct macvlan_port *port = macvlan_port_get(dev); dev->priv_flags &= ~IFF_MACVLAN_PORT; netdev_rx_handler_unregister(dev); - call_rcu(&port->rcu, macvlan_port_rcu_free); + kfree_rcu(port, rcu); } static int macvlan_validate(struct nlattr *tb[], struct nlattr *data[]) -- cgit v0.10.2 From e3cbf28fa61456bd2f0ba39846ffd905257eb4b0 Mon Sep 17 00:00:00 2001 From: Lai Jiangshan Date: Fri, 18 Mar 2011 12:00:50 +0800 Subject: net,rcu: convert call_rcu(ipv6_mc_socklist_reclaim) to kfree_rcu() The rcu callback ipv6_mc_socklist_reclaim() just calls a kfree(), so we use kfree_rcu() instead of the call_rcu(ipv6_mc_socklist_reclaim). Signed-off-by: Lai Jiangshan Acked-by: David S. Miller Signed-off-by: Paul E. McKenney Reviewed-by: Josh Triplett diff --git a/net/ipv6/mcast.c b/net/ipv6/mcast.c index 76b8937..f2d98ca 100644 --- a/net/ipv6/mcast.c +++ b/net/ipv6/mcast.c @@ -201,10 +201,6 @@ int ipv6_sock_mc_join(struct sock *sk, int ifindex, const struct in6_addr *addr) return 0; } -static void ipv6_mc_socklist_reclaim(struct rcu_head *head) -{ - kfree(container_of(head, struct ipv6_mc_socklist, rcu)); -} /* * socket leave on multicast group */ @@ -239,7 +235,7 @@ int ipv6_sock_mc_drop(struct sock *sk, int ifindex, const struct in6_addr *addr) (void) ip6_mc_leave_src(sk, mc_lst, NULL); rcu_read_unlock(); atomic_sub(sizeof(*mc_lst), &sk->sk_omem_alloc); - call_rcu(&mc_lst->rcu, ipv6_mc_socklist_reclaim); + kfree_rcu(mc_lst, rcu); return 0; } } @@ -307,7 +303,7 @@ void ipv6_sock_mc_close(struct sock *sk) rcu_read_unlock(); atomic_sub(sizeof(*mc_lst), &sk->sk_omem_alloc); - call_rcu(&mc_lst->rcu, ipv6_mc_socklist_reclaim); + kfree_rcu(mc_lst, rcu); spin_lock(&ipv6_sk_mc_lock); } -- cgit v0.10.2 From f6f80238fab1ad19c44b4a12501528d50fc7fcd6 Mon Sep 17 00:00:00 2001 From: Lai Jiangshan Date: Fri, 18 Mar 2011 12:01:31 +0800 Subject: net,rcu: convert call_rcu(rps_map_release) to kfree_rcu() The rcu callback rps_map_release() just calls a kfree(), so we use kfree_rcu() instead of the call_rcu(rps_map_release). Signed-off-by: Lai Jiangshan Acked-by: David S. Miller Signed-off-by: Paul E. McKenney Reviewed-by: Josh Triplett diff --git a/net/core/net-sysfs.c b/net/core/net-sysfs.c index 5ceb257..c410f28 100644 --- a/net/core/net-sysfs.c +++ b/net/core/net-sysfs.c @@ -565,13 +565,6 @@ static ssize_t show_rps_map(struct netdev_rx_queue *queue, return len; } -static void rps_map_release(struct rcu_head *rcu) -{ - struct rps_map *map = container_of(rcu, struct rps_map, rcu); - - kfree(map); -} - static ssize_t store_rps_map(struct netdev_rx_queue *queue, struct rx_queue_attribute *attribute, const char *buf, size_t len) @@ -619,7 +612,7 @@ static ssize_t store_rps_map(struct netdev_rx_queue *queue, spin_unlock(&rps_map_lock); if (old_map) - call_rcu(&old_map->rcu, rps_map_release); + kfree_rcu(old_map, rcu); free_cpumask_var(mask); return len; @@ -728,7 +721,7 @@ static void rx_queue_release(struct kobject *kobj) map = rcu_dereference_raw(queue->rps_map); if (map) { RCU_INIT_POINTER(queue->rps_map, NULL); - call_rcu(&map->rcu, rps_map_release); + kfree_rcu(map, rcu); } flow_table = rcu_dereference_raw(queue->rps_flow_table); -- cgit v0.10.2 From edc86d8a1c824cca1df676f47fc713232885561f Mon Sep 17 00:00:00 2001 From: Lai Jiangshan Date: Fri, 18 Mar 2011 12:02:20 +0800 Subject: net,rcu: convert call_rcu(xps_map_release) to kfree_rcu() The rcu callback xps_map_release() just calls a kfree(), so we use kfree_rcu() instead of the call_rcu(xps_map_release). Signed-off-by: Lai Jiangshan Acked-by: David S. Miller Signed-off-by: Paul E. McKenney Reviewed-by: Josh Triplett diff --git a/net/core/net-sysfs.c b/net/core/net-sysfs.c index c410f28..48ffc21 100644 --- a/net/core/net-sysfs.c +++ b/net/core/net-sysfs.c @@ -891,13 +891,6 @@ static ssize_t show_xps_map(struct netdev_queue *queue, return len; } -static void xps_map_release(struct rcu_head *rcu) -{ - struct xps_map *map = container_of(rcu, struct xps_map, rcu); - - kfree(map); -} - static void xps_dev_maps_release(struct rcu_head *rcu) { struct xps_dev_maps *dev_maps = @@ -1002,7 +995,7 @@ static ssize_t store_xps_map(struct netdev_queue *queue, map = dev_maps ? xmap_dereference(dev_maps->cpu_map[cpu]) : NULL; if (map && xmap_dereference(new_dev_maps->cpu_map[cpu]) != map) - call_rcu(&map->rcu, xps_map_release); + kfree_rcu(map, rcu); if (new_dev_maps->cpu_map[cpu]) nonempty = 1; } @@ -1077,7 +1070,7 @@ static void netdev_queue_release(struct kobject *kobj) else { RCU_INIT_POINTER(dev_maps->cpu_map[i], NULL); - call_rcu(&map->rcu, xps_map_release); + kfree_rcu(map, rcu); map = NULL; } } -- cgit v0.10.2 From b55071eb6011413af3b9c434ae77dea8832069c8 Mon Sep 17 00:00:00 2001 From: Lai Jiangshan Date: Fri, 18 Mar 2011 12:02:47 +0800 Subject: net,rcu: convert call_rcu(xps_dev_maps_release) to kfree_rcu() The rcu callback xps_dev_maps_release() just calls a kfree(), so we use kfree_rcu() instead of the call_rcu(xps_dev_maps_release). Signed-off-by: Lai Jiangshan Acked-by: David S. Miller Signed-off-by: Paul E. McKenney Reviewed-by: Josh Triplett diff --git a/net/core/net-sysfs.c b/net/core/net-sysfs.c index 48ffc21..80b2aad 100644 --- a/net/core/net-sysfs.c +++ b/net/core/net-sysfs.c @@ -891,14 +891,6 @@ static ssize_t show_xps_map(struct netdev_queue *queue, return len; } -static void xps_dev_maps_release(struct rcu_head *rcu) -{ - struct xps_dev_maps *dev_maps = - container_of(rcu, struct xps_dev_maps, rcu); - - kfree(dev_maps); -} - static DEFINE_MUTEX(xps_map_mutex); #define xmap_dereference(P) \ rcu_dereference_protected((P), lockdep_is_held(&xps_map_mutex)) @@ -1008,7 +1000,7 @@ static ssize_t store_xps_map(struct netdev_queue *queue, } if (dev_maps) - call_rcu(&dev_maps->rcu, xps_dev_maps_release); + kfree_rcu(dev_maps, rcu); netdev_queue_numa_node_write(queue, (numa_node >= 0) ? numa_node : NUMA_NO_NODE); @@ -1080,7 +1072,7 @@ static void netdev_queue_release(struct kobject *kobj) if (!nonempty) { RCU_INIT_POINTER(dev->xps_maps, NULL); - call_rcu(&dev_maps->rcu, xps_dev_maps_release); + kfree_rcu(dev_maps, rcu); } } -- cgit v0.10.2 From 690273fc70e94a07d70044881e5e52926301bcd3 Mon Sep 17 00:00:00 2001 From: Lai Jiangshan Date: Fri, 18 Mar 2011 12:03:19 +0800 Subject: security,rcu: convert call_rcu(sel_netif_free) to kfree_rcu() The rcu callback sel_netif_free() just calls a kfree(), so we use kfree_rcu() instead of the call_rcu(sel_netif_free). Signed-off-by: Lai Jiangshan Acked-by: David S. Miller Signed-off-by: Paul E. McKenney Reviewed-by: Josh Triplett diff --git a/security/selinux/netif.c b/security/selinux/netif.c index d6095d6..58cc481 100644 --- a/security/selinux/netif.c +++ b/security/selinux/netif.c @@ -104,22 +104,6 @@ static int sel_netif_insert(struct sel_netif *netif) } /** - * sel_netif_free - Frees an interface entry - * @p: the entry's RCU field - * - * Description: - * This function is designed to be used as a callback to the call_rcu() - * function so that memory allocated to a hash table interface entry can be - * released safely. - * - */ -static void sel_netif_free(struct rcu_head *p) -{ - struct sel_netif *netif = container_of(p, struct sel_netif, rcu_head); - kfree(netif); -} - -/** * sel_netif_destroy - Remove an interface record from the table * @netif: the existing interface record * @@ -131,7 +115,7 @@ static void sel_netif_destroy(struct sel_netif *netif) { list_del_rcu(&netif->list); sel_netif_total--; - call_rcu(&netif->rcu_head, sel_netif_free); + kfree_rcu(netif, rcu_head); } /** -- cgit v0.10.2 From c3b494209cc6084bd76d823d185a60ee5bd40b0d Mon Sep 17 00:00:00 2001 From: Lai Jiangshan Date: Fri, 18 Mar 2011 12:03:56 +0800 Subject: net,rcu: convert call_rcu(netlbl_unlhsh_free_addr4) to kfree_rcu() The rcu callback netlbl_unlhsh_free_addr4() just calls a kfree(), so we use kfree_rcu() instead of the call_rcu(netlbl_unlhsh_free_addr4). Signed-off-by: Lai Jiangshan Acked-by: David S. Miller Acked-by: Paul Moore Signed-off-by: Paul E. McKenney Reviewed-by: Josh Triplett diff --git a/net/netlabel/netlabel_unlabeled.c b/net/netlabel/netlabel_unlabeled.c index e2b0a68..4e5ad90 100644 --- a/net/netlabel/netlabel_unlabeled.c +++ b/net/netlabel/netlabel_unlabeled.c @@ -153,24 +153,6 @@ static const struct nla_policy netlbl_unlabel_genl_policy[NLBL_UNLABEL_A_MAX + 1 * Unlabeled Connection Hash Table Functions */ -/** - * netlbl_unlhsh_free_addr4 - Frees an IPv4 address entry from the hash table - * @entry: the entry's RCU field - * - * Description: - * This function is designed to be used as a callback to the call_rcu() - * function so that memory allocated to a hash table address entry can be - * released safely. - * - */ -static void netlbl_unlhsh_free_addr4(struct rcu_head *entry) -{ - struct netlbl_unlhsh_addr4 *ptr; - - ptr = container_of(entry, struct netlbl_unlhsh_addr4, rcu); - kfree(ptr); -} - #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) /** * netlbl_unlhsh_free_addr6 - Frees an IPv6 address entry from the hash table @@ -568,7 +550,7 @@ static int netlbl_unlhsh_remove_addr4(struct net *net, if (entry == NULL) return -ENOENT; - call_rcu(&entry->rcu, netlbl_unlhsh_free_addr4); + kfree_rcu(entry, rcu); return 0; } -- cgit v0.10.2 From 6b2622328110b9c1094a4f644a6cdc9b6d5450ac Mon Sep 17 00:00:00 2001 From: Lai Jiangshan Date: Fri, 18 Mar 2011 12:04:50 +0800 Subject: net,rcu: convert call_rcu(netlbl_unlhsh_free_addr6) to kfree_rcu() The rcu callback netlbl_unlhsh_free_addr6() just calls a kfree(), so we use kfree_rcu() instead of the call_rcu(netlbl_unlhsh_free_addr6). Signed-off-by: Lai Jiangshan Acked-by: Paul Moore Signed-off-by: Paul E. McKenney Reviewed-by: Josh Triplett diff --git a/net/netlabel/netlabel_unlabeled.c b/net/netlabel/netlabel_unlabeled.c index 4e5ad90..9c38658 100644 --- a/net/netlabel/netlabel_unlabeled.c +++ b/net/netlabel/netlabel_unlabeled.c @@ -153,26 +153,6 @@ static const struct nla_policy netlbl_unlabel_genl_policy[NLBL_UNLABEL_A_MAX + 1 * Unlabeled Connection Hash Table Functions */ -#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) -/** - * netlbl_unlhsh_free_addr6 - Frees an IPv6 address entry from the hash table - * @entry: the entry's RCU field - * - * Description: - * This function is designed to be used as a callback to the call_rcu() - * function so that memory allocated to a hash table address entry can be - * released safely. - * - */ -static void netlbl_unlhsh_free_addr6(struct rcu_head *entry) -{ - struct netlbl_unlhsh_addr6 *ptr; - - ptr = container_of(entry, struct netlbl_unlhsh_addr6, rcu); - kfree(ptr); -} -#endif /* IPv6 */ - /** * netlbl_unlhsh_free_iface - Frees an interface entry from the hash table * @entry: the entry's RCU field @@ -611,7 +591,7 @@ static int netlbl_unlhsh_remove_addr6(struct net *net, if (entry == NULL) return -ENOENT; - call_rcu(&entry->rcu, netlbl_unlhsh_free_addr6); + kfree_rcu(entry, rcu); return 0; } #endif /* IPv6 */ -- cgit v0.10.2 From 04d4dfed8e64f65d672502a614a4bb9093d1affd Mon Sep 17 00:00:00 2001 From: Lai Jiangshan Date: Fri, 18 Mar 2011 12:06:32 +0800 Subject: net,rcu: convert call_rcu(net_generic_release) to kfree_rcu() The rcu callback net_generic_release() just calls a kfree(), so we use kfree_rcu() instead of the call_rcu(net_generic_release). Signed-off-by: Lai Jiangshan Acked-by: David S. Miller Signed-off-by: Paul E. McKenney Reviewed-by: Josh Triplett diff --git a/net/core/net_namespace.c b/net/core/net_namespace.c index 3f86026..297bb92 100644 --- a/net/core/net_namespace.c +++ b/net/core/net_namespace.c @@ -27,14 +27,6 @@ EXPORT_SYMBOL(init_net); #define INITIAL_NET_GEN_PTRS 13 /* +1 for len +2 for rcu_head */ -static void net_generic_release(struct rcu_head *rcu) -{ - struct net_generic *ng; - - ng = container_of(rcu, struct net_generic, rcu); - kfree(ng); -} - static int net_assign_generic(struct net *net, int id, void *data) { struct net_generic *ng, *old_ng; @@ -68,7 +60,7 @@ static int net_assign_generic(struct net *net, int id, void *data) memcpy(&ng->ptr, &old_ng->ptr, old_ng->len * sizeof(void*)); rcu_assign_pointer(net->gen, ng); - call_rcu(&old_ng->rcu, net_generic_release); + kfree_rcu(old_ng, rcu); assign: ng->ptr[id - 1] = data; return 0; -- cgit v0.10.2 From 1f8d36a1869f5efae4fadf6baf01f02211040b97 Mon Sep 17 00:00:00 2001 From: Lai Jiangshan Date: Fri, 18 Mar 2011 12:07:09 +0800 Subject: net,rcu: convert call_rcu(__nf_ct_ext_free_rcu) to kfree_rcu() The rcu callback __nf_ct_ext_free_rcu() just calls a kfree(), so we use kfree_rcu() instead of the call_rcu(__nf_ct_ext_free_rcu). Signed-off-by: Lai Jiangshan Acked-by: David S. Miller Signed-off-by: Paul E. McKenney Reviewed-by: Josh Triplett diff --git a/net/netfilter/nf_conntrack_extend.c b/net/netfilter/nf_conntrack_extend.c index 80a23ed..05ecdc2 100644 --- a/net/netfilter/nf_conntrack_extend.c +++ b/net/netfilter/nf_conntrack_extend.c @@ -68,12 +68,6 @@ nf_ct_ext_create(struct nf_ct_ext **ext, enum nf_ct_ext_id id, gfp_t gfp) return (void *)(*ext) + off; } -static void __nf_ct_ext_free_rcu(struct rcu_head *head) -{ - struct nf_ct_ext *ext = container_of(head, struct nf_ct_ext, rcu); - kfree(ext); -} - void *__nf_ct_ext_add(struct nf_conn *ct, enum nf_ct_ext_id id, gfp_t gfp) { struct nf_ct_ext *old, *new; @@ -114,7 +108,7 @@ void *__nf_ct_ext_add(struct nf_conn *ct, enum nf_ct_ext_id id, gfp_t gfp) (void *)old + old->offset[i]); rcu_read_unlock(); } - call_rcu(&old->rcu, __nf_ct_ext_free_rcu); + kfree_rcu(old, rcu); ct->ext = new; } -- cgit v0.10.2 From cb796ff338db9f064f4ecb7d41898e8bedcad4d9 Mon Sep 17 00:00:00 2001 From: Lai Jiangshan Date: Fri, 18 Mar 2011 12:07:41 +0800 Subject: perf,rcu: convert call_rcu(free_ctx) to kfree_rcu() The rcu callback free_ctx() just calls a kfree(), so we use kfree_rcu() instead of the call_rcu(free_ctx). Signed-off-by: Lai Jiangshan Acked-by: Peter Zijlstra Signed-off-by: Paul E. McKenney Reviewed-by: Josh Triplett diff --git a/kernel/perf_event.c b/kernel/perf_event.c index 8e81a98..17a176f 100644 --- a/kernel/perf_event.c +++ b/kernel/perf_event.c @@ -586,14 +586,6 @@ static void get_ctx(struct perf_event_context *ctx) WARN_ON(!atomic_inc_not_zero(&ctx->refcount)); } -static void free_ctx(struct rcu_head *head) -{ - struct perf_event_context *ctx; - - ctx = container_of(head, struct perf_event_context, rcu_head); - kfree(ctx); -} - static void put_ctx(struct perf_event_context *ctx) { if (atomic_dec_and_test(&ctx->refcount)) { @@ -601,7 +593,7 @@ static void put_ctx(struct perf_event_context *ctx) put_ctx(ctx->parent_ctx); if (ctx->task) put_task_struct(ctx->task); - call_rcu(&ctx->rcu_head, free_ctx); + kfree_rcu(ctx, rcu_head); } } -- cgit v0.10.2 From fa4bbc4ca5795fbf1303b98c924e51a21a920f14 Mon Sep 17 00:00:00 2001 From: Lai Jiangshan Date: Fri, 18 Mar 2011 12:08:29 +0800 Subject: perf,rcu: convert call_rcu(swevent_hlist_release_rcu) to kfree_rcu() The rcu callback swevent_hlist_release_rcu() just calls a kfree(), so we use kfree_rcu() instead of the call_rcu(swevent_hlist_release_rcu). Signed-off-by: Lai Jiangshan Acked-by: Peter Zijlstra Signed-off-by: Paul E. McKenney Reviewed-by: Josh Triplett diff --git a/kernel/perf_event.c b/kernel/perf_event.c index 17a176f..b90d660 100644 --- a/kernel/perf_event.c +++ b/kernel/perf_event.c @@ -5323,14 +5323,6 @@ swevent_hlist_deref(struct swevent_htable *swhash) lockdep_is_held(&swhash->hlist_mutex)); } -static void swevent_hlist_release_rcu(struct rcu_head *rcu_head) -{ - struct swevent_hlist *hlist; - - hlist = container_of(rcu_head, struct swevent_hlist, rcu_head); - kfree(hlist); -} - static void swevent_hlist_release(struct swevent_htable *swhash) { struct swevent_hlist *hlist = swevent_hlist_deref(swhash); @@ -5339,7 +5331,7 @@ static void swevent_hlist_release(struct swevent_htable *swhash) return; rcu_assign_pointer(swhash->swevent_hlist, NULL); - call_rcu(&hlist->rcu_head, swevent_hlist_release_rcu); + kfree_rcu(hlist, rcu_head); } static void swevent_hlist_put_cpu(struct perf_event *event, int cpu) -- cgit v0.10.2 From 7e113a9c759d1918fcbe456c5eb8890a4da62eaa Mon Sep 17 00:00:00 2001 From: Lai Jiangshan Date: Fri, 18 Mar 2011 12:09:03 +0800 Subject: net,rcu: convert call_rcu(phonet_device_rcu_free) to kfree_rcu() The rcu callback phonet_device_rcu_free() just calls a kfree(), so we use kfree_rcu() instead of the call_rcu(phonet_device_rcu_free). Signed-off-by: Lai Jiangshan Acked-by: David S. Miller Signed-off-by: Paul E. McKenney Reviewed-by: Josh Triplett diff --git a/net/phonet/pn_dev.c b/net/phonet/pn_dev.c index 947038d..1566672 100644 --- a/net/phonet/pn_dev.c +++ b/net/phonet/pn_dev.c @@ -162,14 +162,6 @@ int phonet_address_add(struct net_device *dev, u8 addr) return err; } -static void phonet_device_rcu_free(struct rcu_head *head) -{ - struct phonet_device *pnd; - - pnd = container_of(head, struct phonet_device, rcu); - kfree(pnd); -} - int phonet_address_del(struct net_device *dev, u8 addr) { struct phonet_device_list *pndevs = phonet_device_list(dev_net(dev)); @@ -188,7 +180,7 @@ int phonet_address_del(struct net_device *dev, u8 addr) mutex_unlock(&pndevs->lock); if (pnd) - call_rcu(&pnd->rcu, phonet_device_rcu_free); + kfree_rcu(pnd, rcu); return err; } -- cgit v0.10.2 From 61845220248c2368095158420b029683fad5570a Mon Sep 17 00:00:00 2001 From: Lai Jiangshan Date: Fri, 18 Mar 2011 12:10:25 +0800 Subject: net,rcu: convert call_rcu(wq_free_rcu) to kfree_rcu() The rcu callback wq_free_rcu() just calls a kfree(), so we use kfree_rcu() instead of the call_rcu(wq_free_rcu). Signed-off-by: Lai Jiangshan Acked-by: David S. Miller Signed-off-by: Paul E. McKenney Reviewed-by: Josh Triplett diff --git a/net/socket.c b/net/socket.c index 310d16b..c2ed7c9 100644 --- a/net/socket.c +++ b/net/socket.c @@ -263,15 +263,6 @@ static struct inode *sock_alloc_inode(struct super_block *sb) return &ei->vfs_inode; } - - -static void wq_free_rcu(struct rcu_head *head) -{ - struct socket_wq *wq = container_of(head, struct socket_wq, rcu); - - kfree(wq); -} - static void sock_destroy_inode(struct inode *inode) { struct socket_alloc *ei; @@ -279,7 +270,7 @@ static void sock_destroy_inode(struct inode *inode) ei = container_of(inode, struct socket_alloc, vfs_inode); wq = rcu_dereference_protected(ei->socket.wq, 1); - call_rcu(&wq->rcu, wq_free_rcu); + kfree_rcu(wq, rcu); kmem_cache_free(sock_inode_cachep, ei); } -- cgit v0.10.2 From a74ce1425e4f6075de443274a5e917c84357eac4 Mon Sep 17 00:00:00 2001 From: Lai Jiangshan Date: Fri, 18 Mar 2011 12:14:15 +0800 Subject: net/mac80211,rcu: convert call_rcu(work_free_rcu) to kfree_rcu() The rcu callback work_free_rcu() just calls a kfree(), so we use kfree_rcu() instead of the call_rcu(work_free_rcu). Signed-off-by: Lai Jiangshan Acked-by: "John W. Linville" Signed-off-by: Paul E. McKenney Reviewed-by: Josh Triplett diff --git a/net/mac80211/work.c b/net/mac80211/work.c index e73c8ca..ac35496 100644 --- a/net/mac80211/work.c +++ b/net/mac80211/work.c @@ -65,17 +65,9 @@ static void run_again(struct ieee80211_local *local, mod_timer(&local->work_timer, timeout); } -static void work_free_rcu(struct rcu_head *head) -{ - struct ieee80211_work *wk = - container_of(head, struct ieee80211_work, rcu_head); - - kfree(wk); -} - void free_work(struct ieee80211_work *wk) { - call_rcu(&wk->rcu_head, work_free_rcu); + kfree_rcu(wk, rcu_head); } static int ieee80211_compatible_rates(const u8 *supp_rates, int supp_rates_len, -- cgit v0.10.2 From 88b4a0347a81539884df5ad535e10cf9fa87d8d4 Mon Sep 17 00:00:00 2001 From: Lai Jiangshan Date: Fri, 18 Mar 2011 12:15:02 +0800 Subject: net,rcu: convert call_rcu(xt_osf_finger_free_rcu) to kfree_rcu() The rcu callback xt_osf_finger_free_rcu() just calls a kfree(), so we use kfree_rcu() instead of the call_rcu(xt_osf_finger_free_rcu). Signed-off-by: Lai Jiangshan Acked-by: David S. Miller Signed-off-by: Paul E. McKenney Reviewed-by: Josh Triplett diff --git a/net/netfilter/xt_osf.c b/net/netfilter/xt_osf.c index 4327e10..846f895 100644 --- a/net/netfilter/xt_osf.c +++ b/net/netfilter/xt_osf.c @@ -62,13 +62,6 @@ static const struct nla_policy xt_osf_policy[OSF_ATTR_MAX + 1] = { [OSF_ATTR_FINGER] = { .len = sizeof(struct xt_osf_user_finger) }, }; -static void xt_osf_finger_free_rcu(struct rcu_head *rcu_head) -{ - struct xt_osf_finger *f = container_of(rcu_head, struct xt_osf_finger, rcu_head); - - kfree(f); -} - static int xt_osf_add_callback(struct sock *ctnl, struct sk_buff *skb, const struct nlmsghdr *nlh, const struct nlattr * const osf_attrs[]) @@ -133,7 +126,7 @@ static int xt_osf_remove_callback(struct sock *ctnl, struct sk_buff *skb, * We are protected by nfnl mutex. */ list_del_rcu(&sf->finger_entry); - call_rcu(&sf->rcu_head, xt_osf_finger_free_rcu); + kfree_rcu(sf, rcu_head); err = 0; break; @@ -414,7 +407,7 @@ static void __exit xt_osf_fini(void) list_for_each_entry_rcu(f, &xt_osf_fingers[i], finger_entry) { list_del_rcu(&f->finger_entry); - call_rcu(&f->rcu_head, xt_osf_finger_free_rcu); + kfree_rcu(f, rcu_head); } } rcu_read_unlock(); -- cgit v0.10.2 From 0744371aeba7a5004006c2309971ee026c0b2000 Mon Sep 17 00:00:00 2001 From: Lai Jiangshan Date: Tue, 15 Mar 2011 18:02:42 +0800 Subject: net,rcu: convert call_rcu(kfree_tid_tx) to kfree_rcu() The rcu callback kfree_tid_tx() just calls a kfree(), so we use kfree_rcu() instead of the call_rcu(kfree_tid_tx). Signed-off-by: Lai Jiangshan Signed-off-by: Paul E. McKenney Cc: "John W. Linville" Cc: Johannes Berg Reviewed-by: Josh Triplett Acked-by: "David S. Miller" diff --git a/net/mac80211/agg-tx.c b/net/mac80211/agg-tx.c index 63d852c..53defaf 100644 --- a/net/mac80211/agg-tx.c +++ b/net/mac80211/agg-tx.c @@ -136,14 +136,6 @@ void ieee80211_send_bar(struct ieee80211_sub_if_data *sdata, u8 *ra, u16 tid, u1 ieee80211_tx_skb(sdata, skb); } -static void kfree_tid_tx(struct rcu_head *rcu_head) -{ - struct tid_ampdu_tx *tid_tx = - container_of(rcu_head, struct tid_ampdu_tx, rcu_head); - - kfree(tid_tx); -} - int ___ieee80211_stop_tx_ba_session(struct sta_info *sta, u16 tid, enum ieee80211_back_parties initiator, bool tx) @@ -163,7 +155,7 @@ int ___ieee80211_stop_tx_ba_session(struct sta_info *sta, u16 tid, /* not even started yet! */ rcu_assign_pointer(sta->ampdu_mlme.tid_tx[tid], NULL); spin_unlock_bh(&sta->lock); - call_rcu(&tid_tx->rcu_head, kfree_tid_tx); + kfree_rcu(tid_tx, rcu_head); return 0; } @@ -322,7 +314,7 @@ void ieee80211_tx_ba_session_handle_start(struct sta_info *sta, int tid) spin_unlock_bh(&sta->lock); ieee80211_wake_queue_agg(local, tid); - call_rcu(&tid_tx->rcu_head, kfree_tid_tx); + kfree_rcu(tid_tx, rcu_head); return; } @@ -701,7 +693,7 @@ void ieee80211_stop_tx_ba_cb(struct ieee80211_vif *vif, u8 *ra, u8 tid) ieee80211_agg_splice_finish(local, tid); - call_rcu(&tid_tx->rcu_head, kfree_tid_tx); + kfree_rcu(tid_tx, rcu_head); unlock_sta: spin_unlock_bh(&sta->lock); -- cgit v0.10.2 From eb340b2f804860a51a0b92e35fd36742b6c2d6b7 Mon Sep 17 00:00:00 2001 From: "Paul E. McKenney" Date: Sun, 1 May 2011 23:25:02 -0700 Subject: batman,rcu: convert call_rcu(gw_node_free_rcu) to kfree_rcu The RCU callback gw_node_free_rcu() just calls kfree(), so we can use kfree_rcu() instead of call_rcu(). Signed-off-by: Paul E. McKenney Cc: Marek Lindner Cc: Simon Wunderlich Acked-by: David S. Miller Reviewed-by: Josh Triplett Acked-by: Sven Eckelmann diff --git a/net/batman-adv/gateway_client.c b/net/batman-adv/gateway_client.c index 3cc4355..150b6ce 100644 --- a/net/batman-adv/gateway_client.c +++ b/net/batman-adv/gateway_client.c @@ -28,18 +28,10 @@ #include #include -static void gw_node_free_rcu(struct rcu_head *rcu) -{ - struct gw_node *gw_node; - - gw_node = container_of(rcu, struct gw_node, rcu); - kfree(gw_node); -} - static void gw_node_free_ref(struct gw_node *gw_node) { if (atomic_dec_and_test(&gw_node->refcount)) - call_rcu(&gw_node->rcu, gw_node_free_rcu); + kfree_rcu(gw_node, rcu); } void *gw_get_selected(struct bat_priv *bat_priv) -- cgit v0.10.2 From ae179ae433bb4ef6b6179c5c1c7b6cc7dc01c670 Mon Sep 17 00:00:00 2001 From: "Paul E. McKenney" Date: Sun, 1 May 2011 23:27:50 -0700 Subject: batman,rcu: convert call_rcu(neigh_node_free_rcu) to kfree() The RCU callback neigh_node_free_rcu() just calls kfree(), so we can use kfree_rcu() instead of call_rcu(). Signed-off-by: Paul E. McKenney Cc: Marek Lindner Cc: Simon Wunderlich Acked-by: David S. Miller Reviewed-by: Josh Triplett Acked-by: Sven Eckelmann diff --git a/net/batman-adv/originator.c b/net/batman-adv/originator.c index 0b91330..ed23a589 100644 --- a/net/batman-adv/originator.c +++ b/net/batman-adv/originator.c @@ -56,18 +56,10 @@ err: return 0; } -static void neigh_node_free_rcu(struct rcu_head *rcu) -{ - struct neigh_node *neigh_node; - - neigh_node = container_of(rcu, struct neigh_node, rcu); - kfree(neigh_node); -} - void neigh_node_free_ref(struct neigh_node *neigh_node) { if (atomic_dec_and_test(&neigh_node->refcount)) - call_rcu(&neigh_node->rcu, neigh_node_free_rcu); + kfree_rcu(neigh_node, rcu); } struct neigh_node *create_neighbor(struct orig_node *orig_node, -- cgit v0.10.2 From 8e3572cff70ee19a0a1f2e2dde0bca0b7c8b54dc Mon Sep 17 00:00:00 2001 From: "Paul E. McKenney" Date: Mon, 2 May 2011 00:52:23 -0700 Subject: batman,rcu: convert call_rcu(softif_neigh_free_rcu) to kfree_rcu The RCU callback softif_neigh_free_rcu() just calls kfree(), so we can use kfree_rcu() instead of call_rcu(). Signed-off-by: Paul E. McKenney Cc: Marek Lindner Cc: Simon Wunderlich Acked-by: David S. Miller Reviewed-by: Josh Triplett Acked-by: Sven Eckelmann diff --git a/net/batman-adv/soft-interface.c b/net/batman-adv/soft-interface.c index 824e1f6..04efe02 100644 --- a/net/batman-adv/soft-interface.c +++ b/net/batman-adv/soft-interface.c @@ -76,18 +76,10 @@ int my_skb_head_push(struct sk_buff *skb, unsigned int len) return 0; } -static void softif_neigh_free_rcu(struct rcu_head *rcu) -{ - struct softif_neigh *softif_neigh; - - softif_neigh = container_of(rcu, struct softif_neigh, rcu); - kfree(softif_neigh); -} - static void softif_neigh_free_ref(struct softif_neigh *softif_neigh) { if (atomic_dec_and_test(&softif_neigh->refcount)) - call_rcu(&softif_neigh->rcu, softif_neigh_free_rcu); + kfree_rcu(softif_neigh, rcu); } void softif_neigh_purge(struct bat_priv *bat_priv) -- cgit v0.10.2 From 11c476f31a0fabc6e604da5b09a6590b57c3fb20 Mon Sep 17 00:00:00 2001 From: "Paul E. McKenney" Date: Mon, 2 May 2011 00:56:57 -0700 Subject: net,rcu: convert call_rcu(prl_entry_destroy_rcu) to kfree The RCU callback prl_entry_destroy_rcu() just calls kfree(), so we can use kfree_rcu() instead of call_rcu(). Signed-off-by: Paul E. McKenney Cc: Alexey Kuznetsov Cc: "Pekka Savola (ipv6)" Cc: James Morris Cc: Hideaki YOSHIFUJI Cc: Patrick McHardy Acked-by: David S. Miller Reviewed-by: Josh Triplett diff --git a/net/ipv6/sit.c b/net/ipv6/sit.c index 43b3337..5f35d59 100644 --- a/net/ipv6/sit.c +++ b/net/ipv6/sit.c @@ -401,11 +401,6 @@ out: return err; } -static void prl_entry_destroy_rcu(struct rcu_head *head) -{ - kfree(container_of(head, struct ip_tunnel_prl_entry, rcu_head)); -} - static void prl_list_destroy_rcu(struct rcu_head *head) { struct ip_tunnel_prl_entry *p, *n; @@ -433,7 +428,7 @@ ipip6_tunnel_del_prl(struct ip_tunnel *t, struct ip_tunnel_prl *a) p = &x->next) { if (x->addr == a->addr) { *p = x->next; - call_rcu(&x->rcu_head, prl_entry_destroy_rcu); + kfree_rcu(x, rcu_head); t->prl_count--; goto out; } -- cgit v0.10.2 From 04b894553fd6e6fd7439e8440fd6bf5b6a17d9ae Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Thu, 5 May 2011 16:59:12 +0200 Subject: ASoC: SSM2602: Properly annotate i2c probe and remove functions Annotate the i2c probe and remove functions with __devinit and __devexit. Signed-off-by: Lars-Peter Clausen Acked-by: Liam Girdwood Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/ssm2602.c b/sound/soc/codecs/ssm2602.c index 2727bef..f7c1ce5 100644 --- a/sound/soc/codecs/ssm2602.c +++ b/sound/soc/codecs/ssm2602.c @@ -614,7 +614,7 @@ static struct snd_soc_codec_driver soc_codec_dev_ssm2602 = { * low = 0x1a * high = 0x1b */ -static int ssm2602_i2c_probe(struct i2c_client *i2c, +static int __devinit ssm2602_i2c_probe(struct i2c_client *i2c, const struct i2c_device_id *id) { struct ssm2602_priv *ssm2602; @@ -635,7 +635,7 @@ static int ssm2602_i2c_probe(struct i2c_client *i2c, return ret; } -static int ssm2602_i2c_remove(struct i2c_client *client) +static int __devexit ssm2602_i2c_remove(struct i2c_client *client) { snd_soc_unregister_codec(&client->dev); kfree(i2c_get_clientdata(client)); @@ -655,7 +655,7 @@ static struct i2c_driver ssm2602_i2c_driver = { .owner = THIS_MODULE, }, .probe = ssm2602_i2c_probe, - .remove = ssm2602_i2c_remove, + .remove = __devexit_p(ssm2602_i2c_remove), .id_table = ssm2602_i2c_id, }; #endif -- cgit v0.10.2 From 36c90ab33feabbd63da775bd92ad356e5bd5cf56 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Thu, 5 May 2011 16:59:16 +0200 Subject: ASoC: SSM2602: Fix 'Mic Boost2' control The 'Mic Boost2' control's shift was off by one and thus was not working. Signed-off-by: Lars-Peter Clausen Acked-by: Liam Girdwood Signed-off-by: Mark Brown Cc: stable@kernel.org diff --git a/sound/soc/codecs/ssm2602.c b/sound/soc/codecs/ssm2602.c index f7c1ce5..946797d 100644 --- a/sound/soc/codecs/ssm2602.c +++ b/sound/soc/codecs/ssm2602.c @@ -139,7 +139,7 @@ SOC_DOUBLE_R("Capture Volume", SSM2602_LINVOL, SSM2602_RINVOL, 0, 31, 0), SOC_DOUBLE_R("Capture Switch", SSM2602_LINVOL, SSM2602_RINVOL, 7, 1, 1), SOC_SINGLE("Mic Boost (+20dB)", SSM2602_APANA, 0, 1, 0), -SOC_SINGLE("Mic Boost2 (+20dB)", SSM2602_APANA, 7, 1, 0), +SOC_SINGLE("Mic Boost2 (+20dB)", SSM2602_APANA, 8, 1, 0), SOC_SINGLE("Mic Switch", SSM2602_APANA, 1, 1, 1), SOC_SINGLE("Sidetone Playback Volume", SSM2602_APANA, 6, 3, 1), -- cgit v0.10.2 From 8fc63fe9412634c72676db42649f357eaac04566 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Thu, 5 May 2011 16:59:14 +0200 Subject: ASoC: SSM2602: Fix reg_cache_size reg_cache_size is supposed to be the number of elements in the register cache, not the size in bytes. Signed-off-by: Lars-Peter Clausen Acked-by: Liam Girdwood Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/ssm2602.c b/sound/soc/codecs/ssm2602.c index 946797d..b04d280 100644 --- a/sound/soc/codecs/ssm2602.c +++ b/sound/soc/codecs/ssm2602.c @@ -602,7 +602,7 @@ static struct snd_soc_codec_driver soc_codec_dev_ssm2602 = { .read = ssm2602_read_reg_cache, .write = ssm2602_write, .set_bias_level = ssm2602_set_bias_level, - .reg_cache_size = sizeof(ssm2602_reg), + .reg_cache_size = ARRAY_SIZE(ssm2602_reg), .reg_word_size = sizeof(u16), .reg_cache_default = ssm2602_reg, }; -- cgit v0.10.2 From 28f8e546e6bc4c2bc6687d7c8dcbe9934cebe639 Mon Sep 17 00:00:00 2001 From: Marek Lindner Date: Mon, 2 May 2011 16:37:13 +0200 Subject: batman-adv: remove misplaced comment Signed-off-by: Marek Lindner Signed-off-by: Sven Eckelmann diff --git a/net/batman-adv/originator.c b/net/batman-adv/originator.c index ef4a9be..51af91b 100644 --- a/net/batman-adv/originator.c +++ b/net/batman-adv/originator.c @@ -19,8 +19,6 @@ * */ -/* increase the reference counter for this originator */ - #include "main.h" #include "originator.h" #include "hash.h" -- cgit v0.10.2 From 61906ae86d8989e5bd3bc1f51b2fb8d32ffde2c5 Mon Sep 17 00:00:00 2001 From: Marek Lindner Date: Thu, 21 Apr 2011 15:52:17 +0200 Subject: batman-adv: multi vlan support for bridge loop detection The bridge loop detection for batman-adv allows the bat0 interface to be bridged into an ethernet segment which other batman-adv nodes are connected to. In order to also allow multiple VLANs on top of the bat0 interface to be bridged into the ethernet segment this patch extends the aforementioned bridge loop detection. Signed-off-by: Marek Lindner Signed-off-by: Sven Eckelmann diff --git a/net/batman-adv/main.c b/net/batman-adv/main.c index 709b33b..705e8be 100644 --- a/net/batman-adv/main.c +++ b/net/batman-adv/main.c @@ -87,11 +87,12 @@ int mesh_init(struct net_device *soft_iface) spin_lock_init(&bat_priv->vis_hash_lock); spin_lock_init(&bat_priv->vis_list_lock); spin_lock_init(&bat_priv->softif_neigh_lock); + spin_lock_init(&bat_priv->softif_neigh_vid_lock); INIT_HLIST_HEAD(&bat_priv->forw_bat_list); INIT_HLIST_HEAD(&bat_priv->forw_bcast_list); INIT_HLIST_HEAD(&bat_priv->gw_list); - INIT_HLIST_HEAD(&bat_priv->softif_neigh_list); + INIT_HLIST_HEAD(&bat_priv->softif_neigh_vids); if (originator_init(bat_priv) < 1) goto err; diff --git a/net/batman-adv/soft-interface.c b/net/batman-adv/soft-interface.c index ea5e58c..8cb13a0 100644 --- a/net/batman-adv/soft-interface.c +++ b/net/batman-adv/soft-interface.c @@ -90,135 +90,251 @@ static void softif_neigh_free_ref(struct softif_neigh *softif_neigh) call_rcu(&softif_neigh->rcu, softif_neigh_free_rcu); } -static struct softif_neigh *softif_neigh_get_selected(struct bat_priv *bat_priv) +static void softif_neigh_vid_free_rcu(struct rcu_head *rcu) { - struct softif_neigh *neigh; - - rcu_read_lock(); - neigh = rcu_dereference(bat_priv->softif_neigh); - - if (neigh && !atomic_inc_not_zero(&neigh->refcount)) - neigh = NULL; - - rcu_read_unlock(); - return neigh; -} + struct softif_neigh_vid *softif_neigh_vid; + struct softif_neigh *softif_neigh; + struct hlist_node *node, *node_tmp; + struct bat_priv *bat_priv; -static void softif_neigh_select(struct bat_priv *bat_priv, - struct softif_neigh *new_neigh) -{ - struct softif_neigh *curr_neigh; + softif_neigh_vid = container_of(rcu, struct softif_neigh_vid, rcu); + bat_priv = softif_neigh_vid->bat_priv; spin_lock_bh(&bat_priv->softif_neigh_lock); - - if (new_neigh && !atomic_inc_not_zero(&new_neigh->refcount)) - new_neigh = NULL; - - curr_neigh = bat_priv->softif_neigh; - rcu_assign_pointer(bat_priv->softif_neigh, new_neigh); - - if (curr_neigh) - softif_neigh_free_ref(curr_neigh); - + hlist_for_each_entry_safe(softif_neigh, node, node_tmp, + &softif_neigh_vid->softif_neigh_list, list) { + hlist_del_rcu(&softif_neigh->list); + softif_neigh_free_ref(softif_neigh); + } spin_unlock_bh(&bat_priv->softif_neigh_lock); + + kfree(softif_neigh_vid); } -static void softif_neigh_deselect(struct bat_priv *bat_priv) +static void softif_neigh_vid_free_ref(struct softif_neigh_vid *softif_neigh_vid) { - softif_neigh_select(bat_priv, NULL); + if (atomic_dec_and_test(&softif_neigh_vid->refcount)) + call_rcu(&softif_neigh_vid->rcu, softif_neigh_vid_free_rcu); } -void softif_neigh_purge(struct bat_priv *bat_priv) +static struct softif_neigh_vid *softif_neigh_vid_get(struct bat_priv *bat_priv, + short vid) { - struct softif_neigh *softif_neigh, *curr_softif_neigh; - struct hlist_node *node, *node_tmp; - char do_deselect = 0; - - curr_softif_neigh = softif_neigh_get_selected(bat_priv); - - spin_lock_bh(&bat_priv->softif_neigh_lock); - - hlist_for_each_entry_safe(softif_neigh, node, node_tmp, - &bat_priv->softif_neigh_list, list) { + struct softif_neigh_vid *softif_neigh_vid; + struct hlist_node *node; - if ((!time_after(jiffies, softif_neigh->last_seen + - msecs_to_jiffies(SOFTIF_NEIGH_TIMEOUT))) && - (atomic_read(&bat_priv->mesh_state) == MESH_ACTIVE)) + rcu_read_lock(); + hlist_for_each_entry_rcu(softif_neigh_vid, node, + &bat_priv->softif_neigh_vids, list) { + if (softif_neigh_vid->vid != vid) continue; - if (curr_softif_neigh == softif_neigh) { - bat_dbg(DBG_ROUTES, bat_priv, - "Current mesh exit point '%pM' vanished " - "(vid: %d).\n", - softif_neigh->addr, softif_neigh->vid); - do_deselect = 1; - } + if (!atomic_inc_not_zero(&softif_neigh_vid->refcount)) + continue; - hlist_del_rcu(&softif_neigh->list); - softif_neigh_free_ref(softif_neigh); + goto out; } - spin_unlock_bh(&bat_priv->softif_neigh_lock); + softif_neigh_vid = kzalloc(sizeof(struct softif_neigh_vid), + GFP_ATOMIC); + if (!softif_neigh_vid) + goto out; - /* soft_neigh_deselect() needs to acquire the softif_neigh_lock */ - if (do_deselect) - softif_neigh_deselect(bat_priv); + softif_neigh_vid->vid = vid; + softif_neigh_vid->bat_priv = bat_priv; - if (curr_softif_neigh) - softif_neigh_free_ref(curr_softif_neigh); + /* initialize with 2 - caller decrements counter by one */ + atomic_set(&softif_neigh_vid->refcount, 2); + INIT_HLIST_HEAD(&softif_neigh_vid->softif_neigh_list); + INIT_HLIST_NODE(&softif_neigh_vid->list); + spin_lock_bh(&bat_priv->softif_neigh_vid_lock); + hlist_add_head_rcu(&softif_neigh_vid->list, + &bat_priv->softif_neigh_vids); + spin_unlock_bh(&bat_priv->softif_neigh_vid_lock); + +out: + rcu_read_unlock(); + return softif_neigh_vid; } static struct softif_neigh *softif_neigh_get(struct bat_priv *bat_priv, uint8_t *addr, short vid) { - struct softif_neigh *softif_neigh; + struct softif_neigh_vid *softif_neigh_vid; + struct softif_neigh *softif_neigh = NULL; struct hlist_node *node; + softif_neigh_vid = softif_neigh_vid_get(bat_priv, vid); + if (!softif_neigh_vid) + goto out; + rcu_read_lock(); hlist_for_each_entry_rcu(softif_neigh, node, - &bat_priv->softif_neigh_list, list) { + &softif_neigh_vid->softif_neigh_list, + list) { if (!compare_eth(softif_neigh->addr, addr)) continue; - if (softif_neigh->vid != vid) - continue; - if (!atomic_inc_not_zero(&softif_neigh->refcount)) continue; softif_neigh->last_seen = jiffies; - goto out; + goto unlock; } softif_neigh = kzalloc(sizeof(struct softif_neigh), GFP_ATOMIC); if (!softif_neigh) - goto out; + goto unlock; memcpy(softif_neigh->addr, addr, ETH_ALEN); - softif_neigh->vid = vid; softif_neigh->last_seen = jiffies; /* initialize with 2 - caller decrements counter by one */ atomic_set(&softif_neigh->refcount, 2); INIT_HLIST_NODE(&softif_neigh->list); spin_lock_bh(&bat_priv->softif_neigh_lock); - hlist_add_head_rcu(&softif_neigh->list, &bat_priv->softif_neigh_list); + hlist_add_head_rcu(&softif_neigh->list, + &softif_neigh_vid->softif_neigh_list); spin_unlock_bh(&bat_priv->softif_neigh_lock); +unlock: + rcu_read_unlock(); out: + if (softif_neigh_vid) + softif_neigh_vid_free_ref(softif_neigh_vid); + return softif_neigh; +} + +static struct softif_neigh *softif_neigh_get_selected( + struct softif_neigh_vid *softif_neigh_vid) +{ + struct softif_neigh *softif_neigh; + + rcu_read_lock(); + softif_neigh = rcu_dereference(softif_neigh_vid->softif_neigh); + + if (softif_neigh && !atomic_inc_not_zero(&softif_neigh->refcount)) + softif_neigh = NULL; + rcu_read_unlock(); return softif_neigh; } +static struct softif_neigh *softif_neigh_vid_get_selected( + struct bat_priv *bat_priv, + short vid) +{ + struct softif_neigh_vid *softif_neigh_vid; + struct softif_neigh *softif_neigh = NULL; + + softif_neigh_vid = softif_neigh_vid_get(bat_priv, vid); + if (!softif_neigh_vid) + goto out; + + softif_neigh = softif_neigh_get_selected(softif_neigh_vid); +out: + if (softif_neigh_vid) + softif_neigh_vid_free_ref(softif_neigh_vid); + return softif_neigh; +} + +static void softif_neigh_vid_select(struct bat_priv *bat_priv, + struct softif_neigh *new_neigh, + short vid) +{ + struct softif_neigh_vid *softif_neigh_vid; + struct softif_neigh *curr_neigh; + + softif_neigh_vid = softif_neigh_vid_get(bat_priv, vid); + if (!softif_neigh_vid) + goto out; + + spin_lock_bh(&bat_priv->softif_neigh_lock); + + if (new_neigh && !atomic_inc_not_zero(&new_neigh->refcount)) + new_neigh = NULL; + + curr_neigh = softif_neigh_vid->softif_neigh; + rcu_assign_pointer(softif_neigh_vid->softif_neigh, new_neigh); + + if ((curr_neigh) && (!new_neigh)) + bat_dbg(DBG_ROUTES, bat_priv, + "Removing mesh exit point on vid: %d (prev: %pM).\n", + vid, curr_neigh->addr); + else if ((curr_neigh) && (new_neigh)) + bat_dbg(DBG_ROUTES, bat_priv, + "Changing mesh exit point on vid: %d from %pM " + "to %pM.\n", vid, curr_neigh->addr, new_neigh->addr); + else if ((!curr_neigh) && (new_neigh)) + bat_dbg(DBG_ROUTES, bat_priv, + "Setting mesh exit point on vid: %d to %pM.\n", + vid, new_neigh->addr); + + if (curr_neigh) + softif_neigh_free_ref(curr_neigh); + + spin_unlock_bh(&bat_priv->softif_neigh_lock); + +out: + if (softif_neigh_vid) + softif_neigh_vid_free_ref(softif_neigh_vid); +} + +static void softif_neigh_vid_deselect(struct bat_priv *bat_priv, + struct softif_neigh_vid *softif_neigh_vid) +{ + struct softif_neigh *curr_neigh; + struct softif_neigh *softif_neigh = NULL, *softif_neigh_tmp; + struct hard_iface *primary_if = NULL; + struct hlist_node *node; + + primary_if = primary_if_get_selected(bat_priv); + if (!primary_if) + goto out; + + /* find new softif_neigh immediately to avoid temporary loops */ + rcu_read_lock(); + curr_neigh = rcu_dereference(softif_neigh_vid->softif_neigh); + + hlist_for_each_entry_rcu(softif_neigh_tmp, node, + &softif_neigh_vid->softif_neigh_list, + list) { + if (softif_neigh_tmp == curr_neigh) + continue; + + /* we got a neighbor but its mac is 'bigger' than ours */ + if (memcmp(primary_if->net_dev->dev_addr, + softif_neigh_tmp->addr, ETH_ALEN) < 0) + continue; + + if (!atomic_inc_not_zero(&softif_neigh_tmp->refcount)) + continue; + + softif_neigh = softif_neigh_tmp; + goto unlock; + } + +unlock: + rcu_read_unlock(); +out: + softif_neigh_vid_select(bat_priv, softif_neigh, softif_neigh_vid->vid); + + if (primary_if) + hardif_free_ref(primary_if); + if (softif_neigh) + softif_neigh_free_ref(softif_neigh); +} + int softif_neigh_seq_print_text(struct seq_file *seq, void *offset) { struct net_device *net_dev = (struct net_device *)seq->private; struct bat_priv *bat_priv = netdev_priv(net_dev); + struct softif_neigh_vid *softif_neigh_vid; struct softif_neigh *softif_neigh; struct hard_iface *primary_if; - struct hlist_node *node; + struct hlist_node *node, *node_tmp; struct softif_neigh *curr_softif_neigh; - int ret = 0; + int ret = 0, last_seen_secs, last_seen_msecs; primary_if = primary_if_get_selected(bat_priv); if (!primary_if) { @@ -237,17 +353,33 @@ int softif_neigh_seq_print_text(struct seq_file *seq, void *offset) seq_printf(seq, "Softif neighbor list (%s)\n", net_dev->name); - curr_softif_neigh = softif_neigh_get_selected(bat_priv); rcu_read_lock(); - hlist_for_each_entry_rcu(softif_neigh, node, - &bat_priv->softif_neigh_list, list) - seq_printf(seq, "%s %pM (vid: %d)\n", - curr_softif_neigh == softif_neigh - ? "=>" : " ", softif_neigh->addr, - softif_neigh->vid); + hlist_for_each_entry_rcu(softif_neigh_vid, node, + &bat_priv->softif_neigh_vids, list) { + seq_printf(seq, " %-15s %s on vid: %d\n", + "Originator", "last-seen", softif_neigh_vid->vid); + + curr_softif_neigh = softif_neigh_get_selected(softif_neigh_vid); + + hlist_for_each_entry_rcu(softif_neigh, node_tmp, + &softif_neigh_vid->softif_neigh_list, + list) { + last_seen_secs = jiffies_to_msecs(jiffies - + softif_neigh->last_seen) / 1000; + last_seen_msecs = jiffies_to_msecs(jiffies - + softif_neigh->last_seen) % 1000; + seq_printf(seq, "%s %pM %3i.%03is\n", + curr_softif_neigh == softif_neigh + ? "=>" : " ", softif_neigh->addr, + last_seen_secs, last_seen_msecs); + } + + if (curr_softif_neigh) + softif_neigh_free_ref(curr_softif_neigh); + + seq_printf(seq, "\n"); + } rcu_read_unlock(); - if (curr_softif_neigh) - softif_neigh_free_ref(curr_softif_neigh); out: if (primary_if) @@ -255,6 +387,70 @@ out: return ret; } +void softif_neigh_purge(struct bat_priv *bat_priv) +{ + struct softif_neigh *softif_neigh, *curr_softif_neigh; + struct softif_neigh_vid *softif_neigh_vid; + struct hlist_node *node, *node_tmp, *node_tmp2; + char do_deselect; + + rcu_read_lock(); + hlist_for_each_entry_rcu(softif_neigh_vid, node, + &bat_priv->softif_neigh_vids, list) { + if (!atomic_inc_not_zero(&softif_neigh_vid->refcount)) + continue; + + curr_softif_neigh = softif_neigh_get_selected(softif_neigh_vid); + do_deselect = 0; + + spin_lock_bh(&bat_priv->softif_neigh_lock); + hlist_for_each_entry_safe(softif_neigh, node_tmp, node_tmp2, + &softif_neigh_vid->softif_neigh_list, + list) { + if ((!time_after(jiffies, softif_neigh->last_seen + + msecs_to_jiffies(SOFTIF_NEIGH_TIMEOUT))) && + (atomic_read(&bat_priv->mesh_state) == MESH_ACTIVE)) + continue; + + if (curr_softif_neigh == softif_neigh) { + bat_dbg(DBG_ROUTES, bat_priv, + "Current mesh exit point on vid: %d " + "'%pM' vanished.\n", + softif_neigh_vid->vid, + softif_neigh->addr); + do_deselect = 1; + } + + hlist_del_rcu(&softif_neigh->list); + softif_neigh_free_ref(softif_neigh); + } + spin_unlock_bh(&bat_priv->softif_neigh_lock); + + /* soft_neigh_vid_deselect() needs to acquire the + * softif_neigh_lock */ + if (do_deselect) + softif_neigh_vid_deselect(bat_priv, softif_neigh_vid); + + if (curr_softif_neigh) + softif_neigh_free_ref(curr_softif_neigh); + + softif_neigh_vid_free_ref(softif_neigh_vid); + } + rcu_read_unlock(); + + spin_lock_bh(&bat_priv->softif_neigh_vid_lock); + hlist_for_each_entry_safe(softif_neigh_vid, node, node_tmp, + &bat_priv->softif_neigh_vids, list) { + if (!hlist_empty(&softif_neigh_vid->softif_neigh_list)) + continue; + + hlist_del_rcu(&softif_neigh_vid->list); + softif_neigh_vid_free_ref(softif_neigh_vid); + } + spin_unlock_bh(&bat_priv->softif_neigh_vid_lock); + +} + static void softif_batman_recv(struct sk_buff *skb, struct net_device *dev, short vid) { @@ -287,10 +483,7 @@ static void softif_batman_recv(struct sk_buff *skb, struct net_device *dev, if (!softif_neigh) goto out; - curr_softif_neigh = softif_neigh_get_selected(bat_priv); - if (!curr_softif_neigh) - goto out; - + curr_softif_neigh = softif_neigh_vid_get_selected(bat_priv, vid); if (curr_softif_neigh == softif_neigh) goto out; @@ -303,33 +496,16 @@ static void softif_batman_recv(struct sk_buff *skb, struct net_device *dev, softif_neigh->addr, ETH_ALEN) < 0) goto out; - /* switch to new 'smallest neighbor' */ - if ((curr_softif_neigh) && - (memcmp(softif_neigh->addr, curr_softif_neigh->addr, - ETH_ALEN) < 0)) { - bat_dbg(DBG_ROUTES, bat_priv, - "Changing mesh exit point from %pM (vid: %d) " - "to %pM (vid: %d).\n", - curr_softif_neigh->addr, - curr_softif_neigh->vid, - softif_neigh->addr, softif_neigh->vid); - - softif_neigh_select(bat_priv, softif_neigh); - goto out; - } - /* close own batX device and use softif_neigh as exit node */ - if ((!curr_softif_neigh) && - (memcmp(softif_neigh->addr, - primary_if->net_dev->dev_addr, ETH_ALEN) < 0)) { - bat_dbg(DBG_ROUTES, bat_priv, - "Setting mesh exit point to %pM (vid: %d).\n", - softif_neigh->addr, softif_neigh->vid); - - softif_neigh_select(bat_priv, softif_neigh); + if (!curr_softif_neigh) { + softif_neigh_vid_select(bat_priv, softif_neigh, vid); goto out; } + /* switch to new 'smallest neighbor' */ + if (memcmp(softif_neigh->addr, curr_softif_neigh->addr, ETH_ALEN) < 0) + softif_neigh_vid_select(bat_priv, softif_neigh, vid); + out: kfree_skb(skb); if (softif_neigh) @@ -424,8 +600,8 @@ int interface_tx(struct sk_buff *skb, struct net_device *soft_iface) * if we have a another chosen mesh exit node in range * it will transport the packets to the mesh */ - curr_softif_neigh = softif_neigh_get_selected(bat_priv); - if ((curr_softif_neigh) && (curr_softif_neigh->vid == vid)) + curr_softif_neigh = softif_neigh_vid_get_selected(bat_priv, vid); + if (curr_softif_neigh) goto dropped; /* TODO: check this for locks */ @@ -533,8 +709,8 @@ void interface_rx(struct net_device *soft_iface, * if we have a another chosen mesh exit node in range * it will transport the packets to the non-mesh network */ - curr_softif_neigh = softif_neigh_get_selected(bat_priv); - if (curr_softif_neigh && (curr_softif_neigh->vid == vid)) { + curr_softif_neigh = softif_neigh_vid_get_selected(bat_priv, vid); + if (curr_softif_neigh) { skb_push(skb, hdr_size); unicast_packet = (struct unicast_packet *)skb->data; @@ -671,7 +847,6 @@ struct net_device *softif_create(char *name) bat_priv->primary_if = NULL; bat_priv->num_ifaces = 0; - bat_priv->softif_neigh = NULL; ret = sysfs_add_meshif(soft_iface); if (ret < 0) diff --git a/net/batman-adv/types.h b/net/batman-adv/types.h index 947bafc..9ae507a 100644 --- a/net/batman-adv/types.h +++ b/net/batman-adv/types.h @@ -146,14 +146,13 @@ struct bat_priv { atomic_t bcast_queue_left; atomic_t batman_queue_left; char num_ifaces; - struct hlist_head softif_neigh_list; - struct softif_neigh __rcu *softif_neigh; struct debug_log *debug_log; struct kobject *mesh_obj; struct dentry *debug_dir; struct hlist_head forw_bat_list; struct hlist_head forw_bcast_list; struct hlist_head gw_list; + struct hlist_head softif_neigh_vids; struct list_head vis_send_list; struct hashtable_t *orig_hash; struct hashtable_t *hna_local_hash; @@ -167,6 +166,7 @@ struct bat_priv { spinlock_t vis_hash_lock; /* protects vis_hash */ spinlock_t vis_list_lock; /* protects vis_info::recv_list */ spinlock_t softif_neigh_lock; /* protects soft-interface neigh list */ + spinlock_t softif_neigh_vid_lock; /* protects soft-interface vid list */ int16_t num_local_hna; atomic_t hna_local_changed; struct delayed_work hna_work; @@ -270,11 +270,20 @@ struct recvlist_node { uint8_t mac[ETH_ALEN]; }; +struct softif_neigh_vid { + struct hlist_node list; + struct bat_priv *bat_priv; + short vid; + atomic_t refcount; + struct softif_neigh __rcu *softif_neigh; + struct rcu_head rcu; + struct hlist_head softif_neigh_list; +}; + struct softif_neigh { struct hlist_node list; uint8_t addr[ETH_ALEN]; unsigned long last_seen; - short vid; atomic_t refcount; struct rcu_head rcu; }; -- cgit v0.10.2 From c3caf5196c47a5d1c325308d8eb7f6b020ba12df Mon Sep 17 00:00:00 2001 From: Sven Eckelmann Date: Tue, 3 May 2011 11:51:38 +0200 Subject: batman-adv: Remove unnecessary hardif_list_lock MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit hardif_list_lock is unneccessary because we already ensure that no multiple admin operations can take place through rtnl_lock. hardif_list_lock only adds additional overhead and complexity. Critical functions now check whether they are called with rtnl_lock using ASSERT_RTNL. It indirectly fixes the problem that orig_hash_del_if() expects that only one interface is deleted from hardif_list at a time, but hardif_remove_interfaces() removes all at once and then calls orig_hash_del_if(). Reported-by: Linus Lüssing Signed-off-by: Sven Eckelmann diff --git a/net/batman-adv/bat_sysfs.c b/net/batman-adv/bat_sysfs.c index e449bf6..85ba20d 100644 --- a/net/batman-adv/bat_sysfs.c +++ b/net/batman-adv/bat_sysfs.c @@ -502,7 +502,9 @@ static ssize_t store_mesh_iface(struct kobject *kobj, struct attribute *attr, rtnl_unlock(); } + rtnl_lock(); ret = hardif_enable_interface(hard_iface, buff); + rtnl_unlock(); out: hardif_free_ref(hard_iface); diff --git a/net/batman-adv/hard-interface.c b/net/batman-adv/hard-interface.c index 3e888f1..7e2f772 100644 --- a/net/batman-adv/hard-interface.c +++ b/net/batman-adv/hard-interface.c @@ -31,9 +31,6 @@ #include -/* protect update critical side of hardif_list - but not the content */ -static DEFINE_SPINLOCK(hardif_list_lock); - static int batman_skb_recv(struct sk_buff *skb, struct net_device *dev, @@ -136,7 +133,7 @@ static void primary_if_select(struct bat_priv *bat_priv, struct hard_iface *curr_hard_iface; struct batman_packet *batman_packet; - spin_lock_bh(&hardif_list_lock); + ASSERT_RTNL(); if (new_hard_iface && !atomic_inc_not_zero(&new_hard_iface->refcount)) new_hard_iface = NULL; @@ -148,7 +145,7 @@ static void primary_if_select(struct bat_priv *bat_priv, hardif_free_ref(curr_hard_iface); if (!new_hard_iface) - goto out; + return; batman_packet = (struct batman_packet *)(new_hard_iface->packet_buff); batman_packet->flags = PRIMARIES_FIRST_HOP; @@ -161,9 +158,6 @@ static void primary_if_select(struct bat_priv *bat_priv, * our new primary interface */ atomic_set(&bat_priv->hna_local_changed, 1); - -out: - spin_unlock_bh(&hardif_list_lock); } static bool hardif_is_iface_up(struct hard_iface *hard_iface) @@ -456,6 +450,8 @@ static struct hard_iface *hardif_add_interface(struct net_device *net_dev) struct hard_iface *hard_iface; int ret; + ASSERT_RTNL(); + ret = is_valid_iface(net_dev); if (ret != 1) goto out; @@ -482,10 +478,7 @@ static struct hard_iface *hardif_add_interface(struct net_device *net_dev) atomic_set(&hard_iface->refcount, 2); check_known_mac_addr(hard_iface->net_dev); - - spin_lock(&hardif_list_lock); list_add_tail_rcu(&hard_iface->list, &hardif_list); - spin_unlock(&hardif_list_lock); return hard_iface; @@ -499,6 +492,8 @@ out: static void hardif_remove_interface(struct hard_iface *hard_iface) { + ASSERT_RTNL(); + /* first deactivate interface */ if (hard_iface->if_status != IF_NOT_IN_USE) hardif_disable_interface(hard_iface); @@ -514,20 +509,11 @@ static void hardif_remove_interface(struct hard_iface *hard_iface) void hardif_remove_interfaces(void) { struct hard_iface *hard_iface, *hard_iface_tmp; - struct list_head if_queue; - - INIT_LIST_HEAD(&if_queue); - spin_lock(&hardif_list_lock); + rtnl_lock(); list_for_each_entry_safe(hard_iface, hard_iface_tmp, &hardif_list, list) { list_del_rcu(&hard_iface->list); - list_add_tail(&hard_iface->list, &if_queue); - } - spin_unlock(&hardif_list_lock); - - rtnl_lock(); - list_for_each_entry_safe(hard_iface, hard_iface_tmp, &if_queue, list) { hardif_remove_interface(hard_iface); } rtnl_unlock(); @@ -556,9 +542,7 @@ static int hard_if_event(struct notifier_block *this, hardif_deactivate_interface(hard_iface); break; case NETDEV_UNREGISTER: - spin_lock(&hardif_list_lock); list_del_rcu(&hard_iface->list); - spin_unlock(&hardif_list_lock); hardif_remove_interface(hard_iface); break; diff --git a/net/batman-adv/main.c b/net/batman-adv/main.c index 705e8be..7edf8d7 100644 --- a/net/batman-adv/main.c +++ b/net/batman-adv/main.c @@ -33,6 +33,9 @@ #include "vis.h" #include "hash.h" + +/* List manipulations on hardif_list have to be rtnl_lock()'ed, + * list traversals just rcu-locked */ struct list_head hardif_list; unsigned char broadcast_addr[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; diff --git a/net/batman-adv/soft-interface.c b/net/batman-adv/soft-interface.c index 8cb13a0..9301e21 100644 --- a/net/batman-adv/soft-interface.c +++ b/net/batman-adv/soft-interface.c @@ -819,7 +819,7 @@ struct net_device *softif_create(char *name) goto out; } - ret = register_netdev(soft_iface); + ret = register_netdevice(soft_iface); if (ret < 0) { pr_err("Unable to register the batman interface '%s': %i\n", name, ret); -- cgit v0.10.2 From 3a4375a9f0080e6ae40af63e2e2c1e70a6dcb775 Mon Sep 17 00:00:00 2001 From: Sven Eckelmann Date: Tue, 3 May 2011 13:10:06 +0200 Subject: batman-adv: Avoid deadlock between rtnl_lock and s_active The hard_if_event is called by the notifier with rtnl_lock and tries to remove sysfs entries when a NETDEV_UNREGISTER event is received. This will automatically take the s_active lock. The s_active lock is also used when a new interface is added to a meshif through sysfs. In that situation we cannot wait for the rntl_lock before creating the actual batman-adv interface to prevent a deadlock. It is still possible to try to get the rtnl_lock and immediately abort the current operation when the trylock call failed. Signed-off-by: Sven Eckelmann diff --git a/net/batman-adv/bat_sysfs.c b/net/batman-adv/bat_sysfs.c index 85ba20d..497a070 100644 --- a/net/batman-adv/bat_sysfs.c +++ b/net/batman-adv/bat_sysfs.c @@ -488,24 +488,24 @@ static ssize_t store_mesh_iface(struct kobject *kobj, struct attribute *attr, (strncmp(hard_iface->soft_iface->name, buff, IFNAMSIZ) == 0)) goto out; + if (!rtnl_trylock()) { + ret = -ERESTARTSYS; + goto out; + } + if (status_tmp == IF_NOT_IN_USE) { - rtnl_lock(); hardif_disable_interface(hard_iface); - rtnl_unlock(); - goto out; + goto unlock; } /* if the interface already is in use */ - if (hard_iface->if_status != IF_NOT_IN_USE) { - rtnl_lock(); + if (hard_iface->if_status != IF_NOT_IN_USE) hardif_disable_interface(hard_iface); - rtnl_unlock(); - } - rtnl_lock(); ret = hardif_enable_interface(hard_iface, buff); - rtnl_unlock(); +unlock: + rtnl_unlock(); out: hardif_free_ref(hard_iface); return ret; -- cgit v0.10.2 From 01df2b65e97735547ce37844f4134b5ea99b4037 Mon Sep 17 00:00:00 2001 From: Marek Lindner Date: Thu, 5 May 2011 14:14:46 +0200 Subject: batman-adv: Fix refcount imbalance in find_router Signed-off-by: Marek Lindner Signed-off-by: Sven Eckelmann diff --git a/net/batman-adv/routing.c b/net/batman-adv/routing.c index 49f5715..d8cde2b 100644 --- a/net/batman-adv/routing.c +++ b/net/batman-adv/routing.c @@ -1213,7 +1213,7 @@ struct neigh_node *find_router(struct bat_priv *bat_priv, router = orig_node_get_router(orig_node); if (!router) - return NULL; + goto err; /* without bonding, the first node should * always choose the default router. */ @@ -1222,10 +1222,8 @@ struct neigh_node *find_router(struct bat_priv *bat_priv, rcu_read_lock(); /* select default router to output */ router_orig = router->orig_node; - if (!router_orig) { - rcu_read_unlock(); - return NULL; - } + if (!router_orig) + goto err_unlock; if ((!recv_if) && (!bonding_enabled)) goto return_router; @@ -1268,6 +1266,12 @@ struct neigh_node *find_router(struct bat_priv *bat_priv, return_router: rcu_read_unlock(); return router; +err_unlock: + rcu_read_unlock(); +err: + if (router) + neigh_node_free_ref(router); + return NULL; } static int check_unicast_packet(struct sk_buff *skb, int hdr_size) -- cgit v0.10.2 From 2dafb49d84a9195193b28ac5047df1bbab6053b9 Mon Sep 17 00:00:00 2001 From: Antonio Quartulli Date: Thu, 5 May 2011 08:42:45 +0200 Subject: batman-adv: rename everything from *hna* into *tt* (translation table) To be coherent, all the functions/variables/constants have been renamed to the TranslationTable style Signed-off-by: Antonio Quartulli Signed-off-by: Sven Eckelmann diff --git a/Documentation/networking/batman-adv.txt b/Documentation/networking/batman-adv.txt index 18afcd8..713f7c0 100644 --- a/Documentation/networking/batman-adv.txt +++ b/Documentation/networking/batman-adv.txt @@ -1,4 +1,4 @@ -[state: 27-01-2011] +[state: 17-04-2011] BATMAN-ADV ---------- @@ -19,6 +19,7 @@ duce the overhead to a minimum. It does not depend on any (other) network driver, and can be used on wifi as well as ethernet lan, vpn, etc ... (anything with ethernet-style layer 2). + CONFIGURATION ------------- @@ -160,13 +161,13 @@ face. Each entry can/has to have the following values: -> "TQ mac value" - src mac's link quality towards mac address of a neighbor originator's interface which is being used for routing --> "HNA mac" - HNA announced by source mac +-> "TT mac" - TT announced by source mac -> "PRIMARY" - this is a primary interface -> "SEC mac" - secondary mac address of source (requires preceding PRIMARY) The TQ value has a range from 4 to 255 with 255 being the best. -The HNA entries are showing which hosts are connected to the mesh +The TT entries are showing which hosts are connected to the mesh via bat0 or being bridged into the mesh network. The PRIMARY/SEC values are only applied on primary interfaces @@ -199,7 +200,7 @@ abled during run time. Following log_levels are defined: 0 - All debug output disabled 1 - Enable messages related to routing / flooding / broadcasting -2 - Enable route or hna added / changed / deleted +2 - Enable route or tt entry added / changed / deleted 3 - Enable all messages The debug output can be changed at runtime using the file @@ -207,7 +208,7 @@ The debug output can be changed at runtime using the file # echo 2 > /sys/class/net/bat0/mesh/log_level -will enable debug messages for when routes or HNAs change. +will enable debug messages for when routes or TTs change. BATCTL diff --git a/net/batman-adv/aggregation.c b/net/batman-adv/aggregation.c index c11788c..9b94590 100644 --- a/net/batman-adv/aggregation.c +++ b/net/batman-adv/aggregation.c @@ -24,10 +24,10 @@ #include "send.h" #include "routing.h" -/* calculate the size of the hna information for a given packet */ -static int hna_len(struct batman_packet *batman_packet) +/* calculate the size of the tt information for a given packet */ +static int tt_len(struct batman_packet *batman_packet) { - return batman_packet->num_hna * ETH_ALEN; + return batman_packet->num_tt * ETH_ALEN; } /* return true if new_packet can be aggregated with forw_packet */ @@ -250,7 +250,7 @@ void receive_aggr_bat_packet(struct ethhdr *ethhdr, unsigned char *packet_buff, { struct batman_packet *batman_packet; int buff_pos = 0; - unsigned char *hna_buff; + unsigned char *tt_buff; batman_packet = (struct batman_packet *)packet_buff; @@ -259,14 +259,14 @@ void receive_aggr_bat_packet(struct ethhdr *ethhdr, unsigned char *packet_buff, orig_interval. */ batman_packet->seqno = ntohl(batman_packet->seqno); - hna_buff = packet_buff + buff_pos + BAT_PACKET_LEN; + tt_buff = packet_buff + buff_pos + BAT_PACKET_LEN; receive_bat_packet(ethhdr, batman_packet, - hna_buff, hna_len(batman_packet), + tt_buff, tt_len(batman_packet), if_incoming); - buff_pos += BAT_PACKET_LEN + hna_len(batman_packet); + buff_pos += BAT_PACKET_LEN + tt_len(batman_packet); batman_packet = (struct batman_packet *) (packet_buff + buff_pos); } while (aggregated_packet(buff_pos, packet_len, - batman_packet->num_hna)); + batman_packet->num_tt)); } diff --git a/net/batman-adv/aggregation.h b/net/batman-adv/aggregation.h index 0622042..7e6d72f 100644 --- a/net/batman-adv/aggregation.h +++ b/net/batman-adv/aggregation.h @@ -25,9 +25,9 @@ #include "main.h" /* is there another aggregated packet here? */ -static inline int aggregated_packet(int buff_pos, int packet_len, int num_hna) +static inline int aggregated_packet(int buff_pos, int packet_len, int num_tt) { - int next_buff_pos = buff_pos + BAT_PACKET_LEN + (num_hna * ETH_ALEN); + int next_buff_pos = buff_pos + BAT_PACKET_LEN + (num_tt * ETH_ALEN); return (next_buff_pos <= packet_len) && (next_buff_pos <= MAX_AGGREGATION_BYTES); diff --git a/net/batman-adv/bat_debugfs.c b/net/batman-adv/bat_debugfs.c index 0e9d435..abaeec5 100644 --- a/net/batman-adv/bat_debugfs.c +++ b/net/batman-adv/bat_debugfs.c @@ -241,13 +241,13 @@ static int softif_neigh_open(struct inode *inode, struct file *file) static int transtable_global_open(struct inode *inode, struct file *file) { struct net_device *net_dev = (struct net_device *)inode->i_private; - return single_open(file, hna_global_seq_print_text, net_dev); + return single_open(file, tt_global_seq_print_text, net_dev); } static int transtable_local_open(struct inode *inode, struct file *file) { struct net_device *net_dev = (struct net_device *)inode->i_private; - return single_open(file, hna_local_seq_print_text, net_dev); + return single_open(file, tt_local_seq_print_text, net_dev); } static int vis_data_open(struct inode *inode, struct file *file) diff --git a/net/batman-adv/hard-interface.c b/net/batman-adv/hard-interface.c index 7e2f772..dfbfccc 100644 --- a/net/batman-adv/hard-interface.c +++ b/net/batman-adv/hard-interface.c @@ -154,10 +154,10 @@ static void primary_if_select(struct bat_priv *bat_priv, primary_if_update_addr(bat_priv); /*** - * hacky trick to make sure that we send the HNA information via + * hacky trick to make sure that we send the TT information via * our new primary interface */ - atomic_set(&bat_priv->hna_local_changed, 1); + atomic_set(&bat_priv->tt_local_changed, 1); } static bool hardif_is_iface_up(struct hard_iface *hard_iface) @@ -339,7 +339,7 @@ int hardif_enable_interface(struct hard_iface *hard_iface, char *iface_name) batman_packet->flags = 0; batman_packet->ttl = 2; batman_packet->tq = TQ_MAX_VALUE; - batman_packet->num_hna = 0; + batman_packet->num_tt = 0; hard_iface->if_num = bat_priv->num_ifaces; bat_priv->num_ifaces++; diff --git a/net/batman-adv/main.c b/net/batman-adv/main.c index 7edf8d7..0a7cee0 100644 --- a/net/batman-adv/main.c +++ b/net/batman-adv/main.c @@ -84,8 +84,8 @@ int mesh_init(struct net_device *soft_iface) spin_lock_init(&bat_priv->forw_bat_list_lock); spin_lock_init(&bat_priv->forw_bcast_list_lock); - spin_lock_init(&bat_priv->hna_lhash_lock); - spin_lock_init(&bat_priv->hna_ghash_lock); + spin_lock_init(&bat_priv->tt_lhash_lock); + spin_lock_init(&bat_priv->tt_ghash_lock); spin_lock_init(&bat_priv->gw_list_lock); spin_lock_init(&bat_priv->vis_hash_lock); spin_lock_init(&bat_priv->vis_list_lock); @@ -100,13 +100,13 @@ int mesh_init(struct net_device *soft_iface) if (originator_init(bat_priv) < 1) goto err; - if (hna_local_init(bat_priv) < 1) + if (tt_local_init(bat_priv) < 1) goto err; - if (hna_global_init(bat_priv) < 1) + if (tt_global_init(bat_priv) < 1) goto err; - hna_local_add(soft_iface, soft_iface->dev_addr); + tt_local_add(soft_iface, soft_iface->dev_addr); if (vis_init(bat_priv) < 1) goto err; @@ -137,8 +137,8 @@ void mesh_free(struct net_device *soft_iface) gw_node_purge(bat_priv); originator_free(bat_priv); - hna_local_free(bat_priv); - hna_global_free(bat_priv); + tt_local_free(bat_priv); + tt_global_free(bat_priv); softif_neigh_purge(bat_priv); diff --git a/net/batman-adv/main.h b/net/batman-adv/main.h index ace7285..9ef6ef9 100644 --- a/net/batman-adv/main.h +++ b/net/batman-adv/main.h @@ -39,7 +39,7 @@ #define PURGE_TIMEOUT 200 /* purge originators after time in seconds if no * valid packet comes in -> TODO: check * influence on TQ_LOCAL_WINDOW_SIZE */ -#define LOCAL_HNA_TIMEOUT 3600 /* in seconds */ +#define TT_LOCAL_TIMEOUT 3600 /* in seconds */ #define TQ_LOCAL_WINDOW_SIZE 64 /* sliding packet range of received originator * messages in squence numbers (should be a @@ -89,7 +89,7 @@ #define DBG_BATMAN 1 /* all messages related to routing / flooding / * broadcasting / etc */ -#define DBG_ROUTES 2 /* route or hna added / changed / deleted */ +#define DBG_ROUTES 2 /* route or tt entry added / changed / deleted */ #define DBG_ALL 3 diff --git a/net/batman-adv/originator.c b/net/batman-adv/originator.c index 51af91b..080ec883 100644 --- a/net/batman-adv/originator.c +++ b/net/batman-adv/originator.c @@ -142,7 +142,7 @@ static void orig_node_free_rcu(struct rcu_head *rcu) spin_unlock_bh(&orig_node->neigh_list_lock); frag_list_free(&orig_node->frag_list); - hna_global_del_orig(orig_node->bat_priv, orig_node, + tt_global_del_orig(orig_node->bat_priv, orig_node, "originator timed out"); kfree(orig_node->bcast_own); @@ -220,7 +220,7 @@ struct orig_node *get_orig_node(struct bat_priv *bat_priv, uint8_t *addr) orig_node->bat_priv = bat_priv; memcpy(orig_node->orig, addr, ETH_ALEN); orig_node->router = NULL; - orig_node->hna_buff = NULL; + orig_node->tt_buff = NULL; orig_node->bcast_seqno_reset = jiffies - 1 - msecs_to_jiffies(RESET_PROTECTION_MS); orig_node->batman_seqno_reset = jiffies - 1 @@ -331,8 +331,8 @@ static bool purge_orig_node(struct bat_priv *bat_priv, &best_neigh_node)) { update_routes(bat_priv, orig_node, best_neigh_node, - orig_node->hna_buff, - orig_node->hna_buff_len); + orig_node->tt_buff, + orig_node->tt_buff_len); } } diff --git a/net/batman-adv/packet.h b/net/batman-adv/packet.h index e757187..c225c3a 100644 --- a/net/batman-adv/packet.h +++ b/net/batman-adv/packet.h @@ -61,7 +61,7 @@ struct batman_packet { uint8_t orig[6]; uint8_t prev_sender[6]; uint8_t ttl; - uint8_t num_hna; + uint8_t num_tt; uint8_t gw_flags; /* flags related to gateway class */ uint8_t align; } __packed; diff --git a/net/batman-adv/routing.c b/net/batman-adv/routing.c index d8cde2b..7648b92 100644 --- a/net/batman-adv/routing.c +++ b/net/batman-adv/routing.c @@ -64,28 +64,28 @@ void slide_own_bcast_window(struct hard_iface *hard_iface) } } -static void update_HNA(struct bat_priv *bat_priv, struct orig_node *orig_node, - unsigned char *hna_buff, int hna_buff_len) +static void update_TT(struct bat_priv *bat_priv, struct orig_node *orig_node, + unsigned char *tt_buff, int tt_buff_len) { - if ((hna_buff_len != orig_node->hna_buff_len) || - ((hna_buff_len > 0) && - (orig_node->hna_buff_len > 0) && - (memcmp(orig_node->hna_buff, hna_buff, hna_buff_len) != 0))) { - - if (orig_node->hna_buff_len > 0) - hna_global_del_orig(bat_priv, orig_node, - "originator changed hna"); - - if ((hna_buff_len > 0) && (hna_buff)) - hna_global_add_orig(bat_priv, orig_node, - hna_buff, hna_buff_len); + if ((tt_buff_len != orig_node->tt_buff_len) || + ((tt_buff_len > 0) && + (orig_node->tt_buff_len > 0) && + (memcmp(orig_node->tt_buff, tt_buff, tt_buff_len) != 0))) { + + if (orig_node->tt_buff_len > 0) + tt_global_del_orig(bat_priv, orig_node, + "originator changed tt"); + + if ((tt_buff_len > 0) && (tt_buff)) + tt_global_add_orig(bat_priv, orig_node, + tt_buff, tt_buff_len); } } static void update_route(struct bat_priv *bat_priv, struct orig_node *orig_node, struct neigh_node *neigh_node, - unsigned char *hna_buff, int hna_buff_len) + unsigned char *tt_buff, int tt_buff_len) { struct neigh_node *curr_router; @@ -96,7 +96,7 @@ static void update_route(struct bat_priv *bat_priv, bat_dbg(DBG_ROUTES, bat_priv, "Deleting route towards: %pM\n", orig_node->orig); - hna_global_del_orig(bat_priv, orig_node, + tt_global_del_orig(bat_priv, orig_node, "originator timed out"); /* route added */ @@ -105,8 +105,8 @@ static void update_route(struct bat_priv *bat_priv, bat_dbg(DBG_ROUTES, bat_priv, "Adding route towards: %pM (via %pM)\n", orig_node->orig, neigh_node->addr); - hna_global_add_orig(bat_priv, orig_node, - hna_buff, hna_buff_len); + tt_global_add_orig(bat_priv, orig_node, + tt_buff, tt_buff_len); /* route changed */ } else { @@ -135,8 +135,8 @@ static void update_route(struct bat_priv *bat_priv, void update_routes(struct bat_priv *bat_priv, struct orig_node *orig_node, - struct neigh_node *neigh_node, unsigned char *hna_buff, - int hna_buff_len) + struct neigh_node *neigh_node, unsigned char *tt_buff, + int tt_buff_len) { struct neigh_node *router = NULL; @@ -147,10 +147,10 @@ void update_routes(struct bat_priv *bat_priv, struct orig_node *orig_node, if (router != neigh_node) update_route(bat_priv, orig_node, neigh_node, - hna_buff, hna_buff_len); - /* may be just HNA changed */ + tt_buff, tt_buff_len); + /* may be just TT changed */ else - update_HNA(bat_priv, orig_node, hna_buff, hna_buff_len); + update_TT(bat_priv, orig_node, tt_buff, tt_buff_len); out: if (router) @@ -387,14 +387,14 @@ static void update_orig(struct bat_priv *bat_priv, struct ethhdr *ethhdr, struct batman_packet *batman_packet, struct hard_iface *if_incoming, - unsigned char *hna_buff, int hna_buff_len, + unsigned char *tt_buff, int tt_buff_len, char is_duplicate) { struct neigh_node *neigh_node = NULL, *tmp_neigh_node = NULL; struct neigh_node *router = NULL; struct orig_node *orig_node_tmp; struct hlist_node *node; - int tmp_hna_buff_len; + int tmp_tt_buff_len; uint8_t bcast_own_sum_orig, bcast_own_sum_neigh; bat_dbg(DBG_BATMAN, bat_priv, "update_originator(): " @@ -459,18 +459,18 @@ static void update_orig(struct bat_priv *bat_priv, bonding_candidate_add(orig_node, neigh_node); - tmp_hna_buff_len = (hna_buff_len > batman_packet->num_hna * ETH_ALEN ? - batman_packet->num_hna * ETH_ALEN : hna_buff_len); + tmp_tt_buff_len = (tt_buff_len > batman_packet->num_tt * ETH_ALEN ? + batman_packet->num_tt * ETH_ALEN : tt_buff_len); /* if this neighbor already is our next hop there is nothing * to change */ router = orig_node_get_router(orig_node); if (router == neigh_node) - goto update_hna; + goto update_tt; /* if this neighbor does not offer a better TQ we won't consider it */ if (router && (router->tq_avg > neigh_node->tq_avg)) - goto update_hna; + goto update_tt; /* if the TQ is the same and the link not more symetric we * won't consider it either */ @@ -488,16 +488,16 @@ static void update_orig(struct bat_priv *bat_priv, spin_unlock_bh(&orig_node_tmp->ogm_cnt_lock); if (bcast_own_sum_orig >= bcast_own_sum_neigh) - goto update_hna; + goto update_tt; } update_routes(bat_priv, orig_node, neigh_node, - hna_buff, tmp_hna_buff_len); + tt_buff, tmp_tt_buff_len); goto update_gw; -update_hna: +update_tt: update_routes(bat_priv, orig_node, router, - hna_buff, tmp_hna_buff_len); + tt_buff, tmp_tt_buff_len); update_gw: if (orig_node->gw_flags != batman_packet->gw_flags) @@ -621,7 +621,7 @@ out: void receive_bat_packet(struct ethhdr *ethhdr, struct batman_packet *batman_packet, - unsigned char *hna_buff, int hna_buff_len, + unsigned char *tt_buff, int tt_buff_len, struct hard_iface *if_incoming) { struct bat_priv *bat_priv = netdev_priv(if_incoming->soft_iface); @@ -818,14 +818,14 @@ void receive_bat_packet(struct ethhdr *ethhdr, ((orig_node->last_real_seqno == batman_packet->seqno) && (orig_node->last_ttl - 3 <= batman_packet->ttl)))) update_orig(bat_priv, orig_node, ethhdr, batman_packet, - if_incoming, hna_buff, hna_buff_len, is_duplicate); + if_incoming, tt_buff, tt_buff_len, is_duplicate); /* is single hop (direct) neighbor */ if (is_single_hop_neigh) { /* mark direct link on incoming interface */ schedule_forward_packet(orig_node, ethhdr, batman_packet, - 1, hna_buff_len, if_incoming); + 1, tt_buff_len, if_incoming); bat_dbg(DBG_BATMAN, bat_priv, "Forwarding packet: " "rebroadcast neighbor packet with direct link flag\n"); @@ -848,7 +848,7 @@ void receive_bat_packet(struct ethhdr *ethhdr, bat_dbg(DBG_BATMAN, bat_priv, "Forwarding packet: rebroadcast originator packet\n"); schedule_forward_packet(orig_node, ethhdr, batman_packet, - 0, hna_buff_len, if_incoming); + 0, tt_buff_len, if_incoming); out_neigh: if ((orig_neigh_node) && (!is_single_hop_neigh)) diff --git a/net/batman-adv/routing.h b/net/batman-adv/routing.h index b5a064c..870f298 100644 --- a/net/batman-adv/routing.h +++ b/net/batman-adv/routing.h @@ -25,11 +25,11 @@ void slide_own_bcast_window(struct hard_iface *hard_iface); void receive_bat_packet(struct ethhdr *ethhdr, struct batman_packet *batman_packet, - unsigned char *hna_buff, int hna_buff_len, + unsigned char *tt_buff, int tt_buff_len, struct hard_iface *if_incoming); void update_routes(struct bat_priv *bat_priv, struct orig_node *orig_node, - struct neigh_node *neigh_node, unsigned char *hna_buff, - int hna_buff_len); + struct neigh_node *neigh_node, unsigned char *tt_buff, + int tt_buff_len); int route_unicast_packet(struct sk_buff *skb, struct hard_iface *recv_if); int recv_icmp_packet(struct sk_buff *skb, struct hard_iface *recv_if); int recv_unicast_packet(struct sk_buff *skb, struct hard_iface *recv_if); diff --git a/net/batman-adv/send.c b/net/batman-adv/send.c index 02b541a6..f30d0c6 100644 --- a/net/batman-adv/send.c +++ b/net/batman-adv/send.c @@ -121,7 +121,7 @@ static void send_packet_to_if(struct forw_packet *forw_packet, /* adjust all flags and log packets */ while (aggregated_packet(buff_pos, forw_packet->packet_len, - batman_packet->num_hna)) { + batman_packet->num_tt)) { /* we might have aggregated direct link packets with an * ordinary base packet */ @@ -146,7 +146,7 @@ static void send_packet_to_if(struct forw_packet *forw_packet, hard_iface->net_dev->dev_addr); buff_pos += sizeof(struct batman_packet) + - (batman_packet->num_hna * ETH_ALEN); + (batman_packet->num_tt * ETH_ALEN); packet_num++; batman_packet = (struct batman_packet *) (forw_packet->skb->data + buff_pos); @@ -222,7 +222,7 @@ static void rebuild_batman_packet(struct bat_priv *bat_priv, struct batman_packet *batman_packet; new_len = sizeof(struct batman_packet) + - (bat_priv->num_local_hna * ETH_ALEN); + (bat_priv->num_local_tt * ETH_ALEN); new_buff = kmalloc(new_len, GFP_ATOMIC); /* keep old buffer if kmalloc should fail */ @@ -231,7 +231,7 @@ static void rebuild_batman_packet(struct bat_priv *bat_priv, sizeof(struct batman_packet)); batman_packet = (struct batman_packet *)new_buff; - batman_packet->num_hna = hna_local_fill_buffer(bat_priv, + batman_packet->num_tt = tt_local_fill_buffer(bat_priv, new_buff + sizeof(struct batman_packet), new_len - sizeof(struct batman_packet)); @@ -266,8 +266,8 @@ void schedule_own_packet(struct hard_iface *hard_iface) if (hard_iface->if_status == IF_TO_BE_ACTIVATED) hard_iface->if_status = IF_ACTIVE; - /* if local hna has changed and interface is a primary interface */ - if ((atomic_read(&bat_priv->hna_local_changed)) && + /* if local tt has changed and interface is a primary interface */ + if ((atomic_read(&bat_priv->tt_local_changed)) && (hard_iface == primary_if)) rebuild_batman_packet(bat_priv, hard_iface); @@ -309,7 +309,7 @@ void schedule_own_packet(struct hard_iface *hard_iface) void schedule_forward_packet(struct orig_node *orig_node, struct ethhdr *ethhdr, struct batman_packet *batman_packet, - uint8_t directlink, int hna_buff_len, + uint8_t directlink, int tt_buff_len, struct hard_iface *if_incoming) { struct bat_priv *bat_priv = netdev_priv(if_incoming->soft_iface); @@ -369,7 +369,7 @@ void schedule_forward_packet(struct orig_node *orig_node, send_time = forward_send_time(); add_bat_packet_to_list(bat_priv, (unsigned char *)batman_packet, - sizeof(struct batman_packet) + hna_buff_len, + sizeof(struct batman_packet) + tt_buff_len, if_incoming, 0, send_time); } diff --git a/net/batman-adv/send.h b/net/batman-adv/send.h index 7b2ff19..247172d 100644 --- a/net/batman-adv/send.h +++ b/net/batman-adv/send.h @@ -29,7 +29,7 @@ void schedule_own_packet(struct hard_iface *hard_iface); void schedule_forward_packet(struct orig_node *orig_node, struct ethhdr *ethhdr, struct batman_packet *batman_packet, - uint8_t directlink, int hna_buff_len, + uint8_t directlink, int tt_buff_len, struct hard_iface *if_outgoing); int add_bcast_packet_to_list(struct bat_priv *bat_priv, struct sk_buff *skb); void send_outstanding_bat_packet(struct work_struct *work); diff --git a/net/batman-adv/soft-interface.c b/net/batman-adv/soft-interface.c index 9301e21..d6aaf9f 100644 --- a/net/batman-adv/soft-interface.c +++ b/net/batman-adv/soft-interface.c @@ -543,11 +543,11 @@ static int interface_set_mac_addr(struct net_device *dev, void *p) if (!is_valid_ether_addr(addr->sa_data)) return -EADDRNOTAVAIL; - /* only modify hna-table if it has been initialised before */ + /* only modify transtable if it has been initialised before */ if (atomic_read(&bat_priv->mesh_state) == MESH_ACTIVE) { - hna_local_remove(bat_priv, dev->dev_addr, + tt_local_remove(bat_priv, dev->dev_addr, "mac address changed"); - hna_local_add(dev, addr->sa_data); + tt_local_add(dev, addr->sa_data); } memcpy(dev->dev_addr, addr->sa_data, ETH_ALEN); @@ -605,7 +605,7 @@ int interface_tx(struct sk_buff *skb, struct net_device *soft_iface) goto dropped; /* TODO: check this for locks */ - hna_local_add(soft_iface, ethhdr->h_source); + tt_local_add(soft_iface, ethhdr->h_source); if (is_multicast_ether_addr(ethhdr->h_dest)) { ret = gw_is_target(bat_priv, skb); @@ -843,7 +843,7 @@ struct net_device *softif_create(char *name) atomic_set(&bat_priv->mesh_state, MESH_INACTIVE); atomic_set(&bat_priv->bcast_seqno, 1); - atomic_set(&bat_priv->hna_local_changed, 0); + atomic_set(&bat_priv->tt_local_changed, 0); bat_priv->primary_if = NULL; bat_priv->num_ifaces = 0; diff --git a/net/batman-adv/translation-table.c b/net/batman-adv/translation-table.c index f931830..7b72966 100644 --- a/net/batman-adv/translation-table.c +++ b/net/batman-adv/translation-table.c @@ -26,40 +26,40 @@ #include "hash.h" #include "originator.h" -static void hna_local_purge(struct work_struct *work); -static void _hna_global_del_orig(struct bat_priv *bat_priv, - struct hna_global_entry *hna_global_entry, +static void tt_local_purge(struct work_struct *work); +static void _tt_global_del_orig(struct bat_priv *bat_priv, + struct tt_global_entry *tt_global_entry, char *message); /* returns 1 if they are the same mac addr */ -static int compare_lhna(struct hlist_node *node, void *data2) +static int compare_ltt(struct hlist_node *node, void *data2) { - void *data1 = container_of(node, struct hna_local_entry, hash_entry); + void *data1 = container_of(node, struct tt_local_entry, hash_entry); return (memcmp(data1, data2, ETH_ALEN) == 0 ? 1 : 0); } /* returns 1 if they are the same mac addr */ -static int compare_ghna(struct hlist_node *node, void *data2) +static int compare_gtt(struct hlist_node *node, void *data2) { - void *data1 = container_of(node, struct hna_global_entry, hash_entry); + void *data1 = container_of(node, struct tt_global_entry, hash_entry); return (memcmp(data1, data2, ETH_ALEN) == 0 ? 1 : 0); } -static void hna_local_start_timer(struct bat_priv *bat_priv) +static void tt_local_start_timer(struct bat_priv *bat_priv) { - INIT_DELAYED_WORK(&bat_priv->hna_work, hna_local_purge); - queue_delayed_work(bat_event_workqueue, &bat_priv->hna_work, 10 * HZ); + INIT_DELAYED_WORK(&bat_priv->tt_work, tt_local_purge); + queue_delayed_work(bat_event_workqueue, &bat_priv->tt_work, 10 * HZ); } -static struct hna_local_entry *hna_local_hash_find(struct bat_priv *bat_priv, +static struct tt_local_entry *tt_local_hash_find(struct bat_priv *bat_priv, void *data) { - struct hashtable_t *hash = bat_priv->hna_local_hash; + struct hashtable_t *hash = bat_priv->tt_local_hash; struct hlist_head *head; struct hlist_node *node; - struct hna_local_entry *hna_local_entry, *hna_local_entry_tmp = NULL; + struct tt_local_entry *tt_local_entry, *tt_local_entry_tmp = NULL; int index; if (!hash) @@ -69,26 +69,26 @@ static struct hna_local_entry *hna_local_hash_find(struct bat_priv *bat_priv, head = &hash->table[index]; rcu_read_lock(); - hlist_for_each_entry_rcu(hna_local_entry, node, head, hash_entry) { - if (!compare_eth(hna_local_entry, data)) + hlist_for_each_entry_rcu(tt_local_entry, node, head, hash_entry) { + if (!compare_eth(tt_local_entry, data)) continue; - hna_local_entry_tmp = hna_local_entry; + tt_local_entry_tmp = tt_local_entry; break; } rcu_read_unlock(); - return hna_local_entry_tmp; + return tt_local_entry_tmp; } -static struct hna_global_entry *hna_global_hash_find(struct bat_priv *bat_priv, +static struct tt_global_entry *tt_global_hash_find(struct bat_priv *bat_priv, void *data) { - struct hashtable_t *hash = bat_priv->hna_global_hash; + struct hashtable_t *hash = bat_priv->tt_global_hash; struct hlist_head *head; struct hlist_node *node; - struct hna_global_entry *hna_global_entry; - struct hna_global_entry *hna_global_entry_tmp = NULL; + struct tt_global_entry *tt_global_entry; + struct tt_global_entry *tt_global_entry_tmp = NULL; int index; if (!hash) @@ -98,125 +98,125 @@ static struct hna_global_entry *hna_global_hash_find(struct bat_priv *bat_priv, head = &hash->table[index]; rcu_read_lock(); - hlist_for_each_entry_rcu(hna_global_entry, node, head, hash_entry) { - if (!compare_eth(hna_global_entry, data)) + hlist_for_each_entry_rcu(tt_global_entry, node, head, hash_entry) { + if (!compare_eth(tt_global_entry, data)) continue; - hna_global_entry_tmp = hna_global_entry; + tt_global_entry_tmp = tt_global_entry; break; } rcu_read_unlock(); - return hna_global_entry_tmp; + return tt_global_entry_tmp; } -int hna_local_init(struct bat_priv *bat_priv) +int tt_local_init(struct bat_priv *bat_priv) { - if (bat_priv->hna_local_hash) + if (bat_priv->tt_local_hash) return 1; - bat_priv->hna_local_hash = hash_new(1024); + bat_priv->tt_local_hash = hash_new(1024); - if (!bat_priv->hna_local_hash) + if (!bat_priv->tt_local_hash) return 0; - atomic_set(&bat_priv->hna_local_changed, 0); - hna_local_start_timer(bat_priv); + atomic_set(&bat_priv->tt_local_changed, 0); + tt_local_start_timer(bat_priv); return 1; } -void hna_local_add(struct net_device *soft_iface, uint8_t *addr) +void tt_local_add(struct net_device *soft_iface, uint8_t *addr) { struct bat_priv *bat_priv = netdev_priv(soft_iface); - struct hna_local_entry *hna_local_entry; - struct hna_global_entry *hna_global_entry; + struct tt_local_entry *tt_local_entry; + struct tt_global_entry *tt_global_entry; int required_bytes; - spin_lock_bh(&bat_priv->hna_lhash_lock); - hna_local_entry = hna_local_hash_find(bat_priv, addr); - spin_unlock_bh(&bat_priv->hna_lhash_lock); + spin_lock_bh(&bat_priv->tt_lhash_lock); + tt_local_entry = tt_local_hash_find(bat_priv, addr); + spin_unlock_bh(&bat_priv->tt_lhash_lock); - if (hna_local_entry) { - hna_local_entry->last_seen = jiffies; + if (tt_local_entry) { + tt_local_entry->last_seen = jiffies; return; } /* only announce as many hosts as possible in the batman-packet and - space in batman_packet->num_hna That also should give a limit to + space in batman_packet->num_tt That also should give a limit to MAC-flooding. */ - required_bytes = (bat_priv->num_local_hna + 1) * ETH_ALEN; + required_bytes = (bat_priv->num_local_tt + 1) * ETH_ALEN; required_bytes += BAT_PACKET_LEN; if ((required_bytes > ETH_DATA_LEN) || (atomic_read(&bat_priv->aggregated_ogms) && required_bytes > MAX_AGGREGATION_BYTES) || - (bat_priv->num_local_hna + 1 > 255)) { + (bat_priv->num_local_tt + 1 > 255)) { bat_dbg(DBG_ROUTES, bat_priv, - "Can't add new local hna entry (%pM): " - "number of local hna entries exceeds packet size\n", + "Can't add new local tt entry (%pM): " + "number of local tt entries exceeds packet size\n", addr); return; } bat_dbg(DBG_ROUTES, bat_priv, - "Creating new local hna entry: %pM\n", addr); + "Creating new local tt entry: %pM\n", addr); - hna_local_entry = kmalloc(sizeof(struct hna_local_entry), GFP_ATOMIC); - if (!hna_local_entry) + tt_local_entry = kmalloc(sizeof(struct tt_local_entry), GFP_ATOMIC); + if (!tt_local_entry) return; - memcpy(hna_local_entry->addr, addr, ETH_ALEN); - hna_local_entry->last_seen = jiffies; + memcpy(tt_local_entry->addr, addr, ETH_ALEN); + tt_local_entry->last_seen = jiffies; /* the batman interface mac address should never be purged */ if (compare_eth(addr, soft_iface->dev_addr)) - hna_local_entry->never_purge = 1; + tt_local_entry->never_purge = 1; else - hna_local_entry->never_purge = 0; + tt_local_entry->never_purge = 0; - spin_lock_bh(&bat_priv->hna_lhash_lock); + spin_lock_bh(&bat_priv->tt_lhash_lock); - hash_add(bat_priv->hna_local_hash, compare_lhna, choose_orig, - hna_local_entry, &hna_local_entry->hash_entry); - bat_priv->num_local_hna++; - atomic_set(&bat_priv->hna_local_changed, 1); + hash_add(bat_priv->tt_local_hash, compare_ltt, choose_orig, + tt_local_entry, &tt_local_entry->hash_entry); + bat_priv->num_local_tt++; + atomic_set(&bat_priv->tt_local_changed, 1); - spin_unlock_bh(&bat_priv->hna_lhash_lock); + spin_unlock_bh(&bat_priv->tt_lhash_lock); /* remove address from global hash if present */ - spin_lock_bh(&bat_priv->hna_ghash_lock); + spin_lock_bh(&bat_priv->tt_ghash_lock); - hna_global_entry = hna_global_hash_find(bat_priv, addr); + tt_global_entry = tt_global_hash_find(bat_priv, addr); - if (hna_global_entry) - _hna_global_del_orig(bat_priv, hna_global_entry, - "local hna received"); + if (tt_global_entry) + _tt_global_del_orig(bat_priv, tt_global_entry, + "local tt received"); - spin_unlock_bh(&bat_priv->hna_ghash_lock); + spin_unlock_bh(&bat_priv->tt_ghash_lock); } -int hna_local_fill_buffer(struct bat_priv *bat_priv, +int tt_local_fill_buffer(struct bat_priv *bat_priv, unsigned char *buff, int buff_len) { - struct hashtable_t *hash = bat_priv->hna_local_hash; - struct hna_local_entry *hna_local_entry; + struct hashtable_t *hash = bat_priv->tt_local_hash; + struct tt_local_entry *tt_local_entry; struct hlist_node *node; struct hlist_head *head; int i, count = 0; - spin_lock_bh(&bat_priv->hna_lhash_lock); + spin_lock_bh(&bat_priv->tt_lhash_lock); for (i = 0; i < hash->size; i++) { head = &hash->table[i]; rcu_read_lock(); - hlist_for_each_entry_rcu(hna_local_entry, node, + hlist_for_each_entry_rcu(tt_local_entry, node, head, hash_entry) { if (buff_len < (count + 1) * ETH_ALEN) break; - memcpy(buff + (count * ETH_ALEN), hna_local_entry->addr, + memcpy(buff + (count * ETH_ALEN), tt_local_entry->addr, ETH_ALEN); count++; @@ -224,20 +224,20 @@ int hna_local_fill_buffer(struct bat_priv *bat_priv, rcu_read_unlock(); } - /* if we did not get all new local hnas see you next time ;-) */ - if (count == bat_priv->num_local_hna) - atomic_set(&bat_priv->hna_local_changed, 0); + /* if we did not get all new local tts see you next time ;-) */ + if (count == bat_priv->num_local_tt) + atomic_set(&bat_priv->tt_local_changed, 0); - spin_unlock_bh(&bat_priv->hna_lhash_lock); + spin_unlock_bh(&bat_priv->tt_lhash_lock); return count; } -int hna_local_seq_print_text(struct seq_file *seq, void *offset) +int tt_local_seq_print_text(struct seq_file *seq, void *offset) { struct net_device *net_dev = (struct net_device *)seq->private; struct bat_priv *bat_priv = netdev_priv(net_dev); - struct hashtable_t *hash = bat_priv->hna_local_hash; - struct hna_local_entry *hna_local_entry; + struct hashtable_t *hash = bat_priv->tt_local_hash; + struct tt_local_entry *tt_local_entry; struct hard_iface *primary_if; struct hlist_node *node; struct hlist_head *head; @@ -261,10 +261,10 @@ int hna_local_seq_print_text(struct seq_file *seq, void *offset) } seq_printf(seq, "Locally retrieved addresses (from %s) " - "announced via HNA:\n", + "announced via TT:\n", net_dev->name); - spin_lock_bh(&bat_priv->hna_lhash_lock); + spin_lock_bh(&bat_priv->tt_lhash_lock); buf_size = 1; /* Estimate length for: " * xx:xx:xx:xx:xx:xx\n" */ @@ -279,7 +279,7 @@ int hna_local_seq_print_text(struct seq_file *seq, void *offset) buff = kmalloc(buf_size, GFP_ATOMIC); if (!buff) { - spin_unlock_bh(&bat_priv->hna_lhash_lock); + spin_unlock_bh(&bat_priv->tt_lhash_lock); ret = -ENOMEM; goto out; } @@ -291,15 +291,15 @@ int hna_local_seq_print_text(struct seq_file *seq, void *offset) head = &hash->table[i]; rcu_read_lock(); - hlist_for_each_entry_rcu(hna_local_entry, node, + hlist_for_each_entry_rcu(tt_local_entry, node, head, hash_entry) { pos += snprintf(buff + pos, 22, " * %pM\n", - hna_local_entry->addr); + tt_local_entry->addr); } rcu_read_unlock(); } - spin_unlock_bh(&bat_priv->hna_lhash_lock); + spin_unlock_bh(&bat_priv->tt_lhash_lock); seq_printf(seq, "%s", buff); kfree(buff); @@ -309,180 +309,180 @@ out: return ret; } -static void _hna_local_del(struct hlist_node *node, void *arg) +static void _tt_local_del(struct hlist_node *node, void *arg) { struct bat_priv *bat_priv = (struct bat_priv *)arg; - void *data = container_of(node, struct hna_local_entry, hash_entry); + void *data = container_of(node, struct tt_local_entry, hash_entry); kfree(data); - bat_priv->num_local_hna--; - atomic_set(&bat_priv->hna_local_changed, 1); + bat_priv->num_local_tt--; + atomic_set(&bat_priv->tt_local_changed, 1); } -static void hna_local_del(struct bat_priv *bat_priv, - struct hna_local_entry *hna_local_entry, +static void tt_local_del(struct bat_priv *bat_priv, + struct tt_local_entry *tt_local_entry, char *message) { - bat_dbg(DBG_ROUTES, bat_priv, "Deleting local hna entry (%pM): %s\n", - hna_local_entry->addr, message); + bat_dbg(DBG_ROUTES, bat_priv, "Deleting local tt entry (%pM): %s\n", + tt_local_entry->addr, message); - hash_remove(bat_priv->hna_local_hash, compare_lhna, choose_orig, - hna_local_entry->addr); - _hna_local_del(&hna_local_entry->hash_entry, bat_priv); + hash_remove(bat_priv->tt_local_hash, compare_ltt, choose_orig, + tt_local_entry->addr); + _tt_local_del(&tt_local_entry->hash_entry, bat_priv); } -void hna_local_remove(struct bat_priv *bat_priv, +void tt_local_remove(struct bat_priv *bat_priv, uint8_t *addr, char *message) { - struct hna_local_entry *hna_local_entry; + struct tt_local_entry *tt_local_entry; - spin_lock_bh(&bat_priv->hna_lhash_lock); + spin_lock_bh(&bat_priv->tt_lhash_lock); - hna_local_entry = hna_local_hash_find(bat_priv, addr); + tt_local_entry = tt_local_hash_find(bat_priv, addr); - if (hna_local_entry) - hna_local_del(bat_priv, hna_local_entry, message); + if (tt_local_entry) + tt_local_del(bat_priv, tt_local_entry, message); - spin_unlock_bh(&bat_priv->hna_lhash_lock); + spin_unlock_bh(&bat_priv->tt_lhash_lock); } -static void hna_local_purge(struct work_struct *work) +static void tt_local_purge(struct work_struct *work) { struct delayed_work *delayed_work = container_of(work, struct delayed_work, work); struct bat_priv *bat_priv = - container_of(delayed_work, struct bat_priv, hna_work); - struct hashtable_t *hash = bat_priv->hna_local_hash; - struct hna_local_entry *hna_local_entry; + container_of(delayed_work, struct bat_priv, tt_work); + struct hashtable_t *hash = bat_priv->tt_local_hash; + struct tt_local_entry *tt_local_entry; struct hlist_node *node, *node_tmp; struct hlist_head *head; unsigned long timeout; int i; - spin_lock_bh(&bat_priv->hna_lhash_lock); + spin_lock_bh(&bat_priv->tt_lhash_lock); for (i = 0; i < hash->size; i++) { head = &hash->table[i]; - hlist_for_each_entry_safe(hna_local_entry, node, node_tmp, + hlist_for_each_entry_safe(tt_local_entry, node, node_tmp, head, hash_entry) { - if (hna_local_entry->never_purge) + if (tt_local_entry->never_purge) continue; - timeout = hna_local_entry->last_seen; - timeout += LOCAL_HNA_TIMEOUT * HZ; + timeout = tt_local_entry->last_seen; + timeout += TT_LOCAL_TIMEOUT * HZ; if (time_before(jiffies, timeout)) continue; - hna_local_del(bat_priv, hna_local_entry, + tt_local_del(bat_priv, tt_local_entry, "address timed out"); } } - spin_unlock_bh(&bat_priv->hna_lhash_lock); - hna_local_start_timer(bat_priv); + spin_unlock_bh(&bat_priv->tt_lhash_lock); + tt_local_start_timer(bat_priv); } -void hna_local_free(struct bat_priv *bat_priv) +void tt_local_free(struct bat_priv *bat_priv) { - if (!bat_priv->hna_local_hash) + if (!bat_priv->tt_local_hash) return; - cancel_delayed_work_sync(&bat_priv->hna_work); - hash_delete(bat_priv->hna_local_hash, _hna_local_del, bat_priv); - bat_priv->hna_local_hash = NULL; + cancel_delayed_work_sync(&bat_priv->tt_work); + hash_delete(bat_priv->tt_local_hash, _tt_local_del, bat_priv); + bat_priv->tt_local_hash = NULL; } -int hna_global_init(struct bat_priv *bat_priv) +int tt_global_init(struct bat_priv *bat_priv) { - if (bat_priv->hna_global_hash) + if (bat_priv->tt_global_hash) return 1; - bat_priv->hna_global_hash = hash_new(1024); + bat_priv->tt_global_hash = hash_new(1024); - if (!bat_priv->hna_global_hash) + if (!bat_priv->tt_global_hash) return 0; return 1; } -void hna_global_add_orig(struct bat_priv *bat_priv, +void tt_global_add_orig(struct bat_priv *bat_priv, struct orig_node *orig_node, - unsigned char *hna_buff, int hna_buff_len) + unsigned char *tt_buff, int tt_buff_len) { - struct hna_global_entry *hna_global_entry; - struct hna_local_entry *hna_local_entry; - int hna_buff_count = 0; - unsigned char *hna_ptr; + struct tt_global_entry *tt_global_entry; + struct tt_local_entry *tt_local_entry; + int tt_buff_count = 0; + unsigned char *tt_ptr; - while ((hna_buff_count + 1) * ETH_ALEN <= hna_buff_len) { - spin_lock_bh(&bat_priv->hna_ghash_lock); + while ((tt_buff_count + 1) * ETH_ALEN <= tt_buff_len) { + spin_lock_bh(&bat_priv->tt_ghash_lock); - hna_ptr = hna_buff + (hna_buff_count * ETH_ALEN); - hna_global_entry = hna_global_hash_find(bat_priv, hna_ptr); + tt_ptr = tt_buff + (tt_buff_count * ETH_ALEN); + tt_global_entry = tt_global_hash_find(bat_priv, tt_ptr); - if (!hna_global_entry) { - spin_unlock_bh(&bat_priv->hna_ghash_lock); + if (!tt_global_entry) { + spin_unlock_bh(&bat_priv->tt_ghash_lock); - hna_global_entry = - kmalloc(sizeof(struct hna_global_entry), + tt_global_entry = + kmalloc(sizeof(struct tt_global_entry), GFP_ATOMIC); - if (!hna_global_entry) + if (!tt_global_entry) break; - memcpy(hna_global_entry->addr, hna_ptr, ETH_ALEN); + memcpy(tt_global_entry->addr, tt_ptr, ETH_ALEN); bat_dbg(DBG_ROUTES, bat_priv, - "Creating new global hna entry: " + "Creating new global tt entry: " "%pM (via %pM)\n", - hna_global_entry->addr, orig_node->orig); + tt_global_entry->addr, orig_node->orig); - spin_lock_bh(&bat_priv->hna_ghash_lock); - hash_add(bat_priv->hna_global_hash, compare_ghna, - choose_orig, hna_global_entry, - &hna_global_entry->hash_entry); + spin_lock_bh(&bat_priv->tt_ghash_lock); + hash_add(bat_priv->tt_global_hash, compare_gtt, + choose_orig, tt_global_entry, + &tt_global_entry->hash_entry); } - hna_global_entry->orig_node = orig_node; - spin_unlock_bh(&bat_priv->hna_ghash_lock); + tt_global_entry->orig_node = orig_node; + spin_unlock_bh(&bat_priv->tt_ghash_lock); /* remove address from local hash if present */ - spin_lock_bh(&bat_priv->hna_lhash_lock); + spin_lock_bh(&bat_priv->tt_lhash_lock); - hna_ptr = hna_buff + (hna_buff_count * ETH_ALEN); - hna_local_entry = hna_local_hash_find(bat_priv, hna_ptr); + tt_ptr = tt_buff + (tt_buff_count * ETH_ALEN); + tt_local_entry = tt_local_hash_find(bat_priv, tt_ptr); - if (hna_local_entry) - hna_local_del(bat_priv, hna_local_entry, - "global hna received"); + if (tt_local_entry) + tt_local_del(bat_priv, tt_local_entry, + "global tt received"); - spin_unlock_bh(&bat_priv->hna_lhash_lock); + spin_unlock_bh(&bat_priv->tt_lhash_lock); - hna_buff_count++; + tt_buff_count++; } /* initialize, and overwrite if malloc succeeds */ - orig_node->hna_buff = NULL; - orig_node->hna_buff_len = 0; - - if (hna_buff_len > 0) { - orig_node->hna_buff = kmalloc(hna_buff_len, GFP_ATOMIC); - if (orig_node->hna_buff) { - memcpy(orig_node->hna_buff, hna_buff, hna_buff_len); - orig_node->hna_buff_len = hna_buff_len; + orig_node->tt_buff = NULL; + orig_node->tt_buff_len = 0; + + if (tt_buff_len > 0) { + orig_node->tt_buff = kmalloc(tt_buff_len, GFP_ATOMIC); + if (orig_node->tt_buff) { + memcpy(orig_node->tt_buff, tt_buff, tt_buff_len); + orig_node->tt_buff_len = tt_buff_len; } } } -int hna_global_seq_print_text(struct seq_file *seq, void *offset) +int tt_global_seq_print_text(struct seq_file *seq, void *offset) { struct net_device *net_dev = (struct net_device *)seq->private; struct bat_priv *bat_priv = netdev_priv(net_dev); - struct hashtable_t *hash = bat_priv->hna_global_hash; - struct hna_global_entry *hna_global_entry; + struct hashtable_t *hash = bat_priv->tt_global_hash; + struct tt_global_entry *tt_global_entry; struct hard_iface *primary_if; struct hlist_node *node; struct hlist_head *head; @@ -505,10 +505,11 @@ int hna_global_seq_print_text(struct seq_file *seq, void *offset) goto out; } - seq_printf(seq, "Globally announced HNAs received via the mesh %s\n", + seq_printf(seq, + "Globally announced TT entries received via the mesh %s\n", net_dev->name); - spin_lock_bh(&bat_priv->hna_ghash_lock); + spin_lock_bh(&bat_priv->tt_ghash_lock); buf_size = 1; /* Estimate length for: " * xx:xx:xx:xx:xx:xx via xx:xx:xx:xx:xx:xx\n"*/ @@ -523,7 +524,7 @@ int hna_global_seq_print_text(struct seq_file *seq, void *offset) buff = kmalloc(buf_size, GFP_ATOMIC); if (!buff) { - spin_unlock_bh(&bat_priv->hna_ghash_lock); + spin_unlock_bh(&bat_priv->tt_ghash_lock); ret = -ENOMEM; goto out; } @@ -534,17 +535,17 @@ int hna_global_seq_print_text(struct seq_file *seq, void *offset) head = &hash->table[i]; rcu_read_lock(); - hlist_for_each_entry_rcu(hna_global_entry, node, + hlist_for_each_entry_rcu(tt_global_entry, node, head, hash_entry) { pos += snprintf(buff + pos, 44, " * %pM via %pM\n", - hna_global_entry->addr, - hna_global_entry->orig_node->orig); + tt_global_entry->addr, + tt_global_entry->orig_node->orig); } rcu_read_unlock(); } - spin_unlock_bh(&bat_priv->hna_ghash_lock); + spin_unlock_bh(&bat_priv->tt_ghash_lock); seq_printf(seq, "%s", buff); kfree(buff); @@ -554,84 +555,84 @@ out: return ret; } -static void _hna_global_del_orig(struct bat_priv *bat_priv, - struct hna_global_entry *hna_global_entry, +static void _tt_global_del_orig(struct bat_priv *bat_priv, + struct tt_global_entry *tt_global_entry, char *message) { bat_dbg(DBG_ROUTES, bat_priv, - "Deleting global hna entry %pM (via %pM): %s\n", - hna_global_entry->addr, hna_global_entry->orig_node->orig, + "Deleting global tt entry %pM (via %pM): %s\n", + tt_global_entry->addr, tt_global_entry->orig_node->orig, message); - hash_remove(bat_priv->hna_global_hash, compare_ghna, choose_orig, - hna_global_entry->addr); - kfree(hna_global_entry); + hash_remove(bat_priv->tt_global_hash, compare_gtt, choose_orig, + tt_global_entry->addr); + kfree(tt_global_entry); } -void hna_global_del_orig(struct bat_priv *bat_priv, +void tt_global_del_orig(struct bat_priv *bat_priv, struct orig_node *orig_node, char *message) { - struct hna_global_entry *hna_global_entry; - int hna_buff_count = 0; - unsigned char *hna_ptr; + struct tt_global_entry *tt_global_entry; + int tt_buff_count = 0; + unsigned char *tt_ptr; - if (orig_node->hna_buff_len == 0) + if (orig_node->tt_buff_len == 0) return; - spin_lock_bh(&bat_priv->hna_ghash_lock); + spin_lock_bh(&bat_priv->tt_ghash_lock); - while ((hna_buff_count + 1) * ETH_ALEN <= orig_node->hna_buff_len) { - hna_ptr = orig_node->hna_buff + (hna_buff_count * ETH_ALEN); - hna_global_entry = hna_global_hash_find(bat_priv, hna_ptr); + while ((tt_buff_count + 1) * ETH_ALEN <= orig_node->tt_buff_len) { + tt_ptr = orig_node->tt_buff + (tt_buff_count * ETH_ALEN); + tt_global_entry = tt_global_hash_find(bat_priv, tt_ptr); - if ((hna_global_entry) && - (hna_global_entry->orig_node == orig_node)) - _hna_global_del_orig(bat_priv, hna_global_entry, + if ((tt_global_entry) && + (tt_global_entry->orig_node == orig_node)) + _tt_global_del_orig(bat_priv, tt_global_entry, message); - hna_buff_count++; + tt_buff_count++; } - spin_unlock_bh(&bat_priv->hna_ghash_lock); + spin_unlock_bh(&bat_priv->tt_ghash_lock); - orig_node->hna_buff_len = 0; - kfree(orig_node->hna_buff); - orig_node->hna_buff = NULL; + orig_node->tt_buff_len = 0; + kfree(orig_node->tt_buff); + orig_node->tt_buff = NULL; } -static void hna_global_del(struct hlist_node *node, void *arg) +static void tt_global_del(struct hlist_node *node, void *arg) { - void *data = container_of(node, struct hna_global_entry, hash_entry); + void *data = container_of(node, struct tt_global_entry, hash_entry); kfree(data); } -void hna_global_free(struct bat_priv *bat_priv) +void tt_global_free(struct bat_priv *bat_priv) { - if (!bat_priv->hna_global_hash) + if (!bat_priv->tt_global_hash) return; - hash_delete(bat_priv->hna_global_hash, hna_global_del, NULL); - bat_priv->hna_global_hash = NULL; + hash_delete(bat_priv->tt_global_hash, tt_global_del, NULL); + bat_priv->tt_global_hash = NULL; } struct orig_node *transtable_search(struct bat_priv *bat_priv, uint8_t *addr) { - struct hna_global_entry *hna_global_entry; + struct tt_global_entry *tt_global_entry; struct orig_node *orig_node = NULL; - spin_lock_bh(&bat_priv->hna_ghash_lock); - hna_global_entry = hna_global_hash_find(bat_priv, addr); + spin_lock_bh(&bat_priv->tt_ghash_lock); + tt_global_entry = tt_global_hash_find(bat_priv, addr); - if (!hna_global_entry) + if (!tt_global_entry) goto out; - if (!atomic_inc_not_zero(&hna_global_entry->orig_node->refcount)) + if (!atomic_inc_not_zero(&tt_global_entry->orig_node->refcount)) goto out; - orig_node = hna_global_entry->orig_node; + orig_node = tt_global_entry->orig_node; out: - spin_unlock_bh(&bat_priv->hna_ghash_lock); + spin_unlock_bh(&bat_priv->tt_ghash_lock); return orig_node; } diff --git a/net/batman-adv/translation-table.h b/net/batman-adv/translation-table.h index f19931c..46152c3 100644 --- a/net/batman-adv/translation-table.h +++ b/net/batman-adv/translation-table.h @@ -22,22 +22,22 @@ #ifndef _NET_BATMAN_ADV_TRANSLATION_TABLE_H_ #define _NET_BATMAN_ADV_TRANSLATION_TABLE_H_ -int hna_local_init(struct bat_priv *bat_priv); -void hna_local_add(struct net_device *soft_iface, uint8_t *addr); -void hna_local_remove(struct bat_priv *bat_priv, +int tt_local_init(struct bat_priv *bat_priv); +void tt_local_add(struct net_device *soft_iface, uint8_t *addr); +void tt_local_remove(struct bat_priv *bat_priv, uint8_t *addr, char *message); -int hna_local_fill_buffer(struct bat_priv *bat_priv, +int tt_local_fill_buffer(struct bat_priv *bat_priv, unsigned char *buff, int buff_len); -int hna_local_seq_print_text(struct seq_file *seq, void *offset); -void hna_local_free(struct bat_priv *bat_priv); -int hna_global_init(struct bat_priv *bat_priv); -void hna_global_add_orig(struct bat_priv *bat_priv, +int tt_local_seq_print_text(struct seq_file *seq, void *offset); +void tt_local_free(struct bat_priv *bat_priv); +int tt_global_init(struct bat_priv *bat_priv); +void tt_global_add_orig(struct bat_priv *bat_priv, struct orig_node *orig_node, - unsigned char *hna_buff, int hna_buff_len); -int hna_global_seq_print_text(struct seq_file *seq, void *offset); -void hna_global_del_orig(struct bat_priv *bat_priv, + unsigned char *tt_buff, int tt_buff_len); +int tt_global_seq_print_text(struct seq_file *seq, void *offset); +void tt_global_del_orig(struct bat_priv *bat_priv, struct orig_node *orig_node, char *message); -void hna_global_free(struct bat_priv *bat_priv); +void tt_global_free(struct bat_priv *bat_priv); struct orig_node *transtable_search(struct bat_priv *bat_priv, uint8_t *addr); #endif /* _NET_BATMAN_ADV_TRANSLATION_TABLE_H_ */ diff --git a/net/batman-adv/types.h b/net/batman-adv/types.h index 9ae507a..6b6c32e 100644 --- a/net/batman-adv/types.h +++ b/net/batman-adv/types.h @@ -75,8 +75,8 @@ struct orig_node { unsigned long batman_seqno_reset; uint8_t gw_flags; uint8_t flags; - unsigned char *hna_buff; - int16_t hna_buff_len; + unsigned char *tt_buff; + int16_t tt_buff_len; uint32_t last_real_seqno; uint8_t last_ttl; unsigned long bcast_bits[NUM_WORDS]; @@ -155,21 +155,21 @@ struct bat_priv { struct hlist_head softif_neigh_vids; struct list_head vis_send_list; struct hashtable_t *orig_hash; - struct hashtable_t *hna_local_hash; - struct hashtable_t *hna_global_hash; + struct hashtable_t *tt_local_hash; + struct hashtable_t *tt_global_hash; struct hashtable_t *vis_hash; spinlock_t forw_bat_list_lock; /* protects forw_bat_list */ spinlock_t forw_bcast_list_lock; /* protects */ - spinlock_t hna_lhash_lock; /* protects hna_local_hash */ - spinlock_t hna_ghash_lock; /* protects hna_global_hash */ + spinlock_t tt_lhash_lock; /* protects tt_local_hash */ + spinlock_t tt_ghash_lock; /* protects tt_global_hash */ spinlock_t gw_list_lock; /* protects gw_list and curr_gw */ spinlock_t vis_hash_lock; /* protects vis_hash */ spinlock_t vis_list_lock; /* protects vis_info::recv_list */ spinlock_t softif_neigh_lock; /* protects soft-interface neigh list */ spinlock_t softif_neigh_vid_lock; /* protects soft-interface vid list */ - int16_t num_local_hna; - atomic_t hna_local_changed; - struct delayed_work hna_work; + int16_t num_local_tt; + atomic_t tt_local_changed; + struct delayed_work tt_work; struct delayed_work orig_work; struct delayed_work vis_work; struct gw_node __rcu *curr_gw; /* rcu protected pointer */ @@ -192,14 +192,14 @@ struct socket_packet { struct icmp_packet_rr icmp_packet; }; -struct hna_local_entry { +struct tt_local_entry { uint8_t addr[ETH_ALEN]; unsigned long last_seen; char never_purge; struct hlist_node hash_entry; }; -struct hna_global_entry { +struct tt_global_entry { uint8_t addr[ETH_ALEN]; struct orig_node *orig_node; struct hlist_node hash_entry; @@ -262,7 +262,7 @@ struct vis_info { struct vis_info_entry { uint8_t src[ETH_ALEN]; uint8_t dest[ETH_ALEN]; - uint8_t quality; /* quality = 0 means HNA */ + uint8_t quality; /* quality = 0 client */ } __packed; struct recvlist_node { diff --git a/net/batman-adv/unicast.c b/net/batman-adv/unicast.c index b46cbf1..19c3daf 100644 --- a/net/batman-adv/unicast.c +++ b/net/batman-adv/unicast.c @@ -300,7 +300,7 @@ int unicast_send_skb(struct sk_buff *skb, struct bat_priv *bat_priv) goto find_router; } - /* check for hna host - increases orig_node refcount */ + /* check for tt host - increases orig_node refcount */ orig_node = transtable_search(bat_priv, ethhdr->h_dest); find_router: diff --git a/net/batman-adv/vis.c b/net/batman-adv/vis.c index c8f571d..c39f20c 100644 --- a/net/batman-adv/vis.c +++ b/net/batman-adv/vis.c @@ -194,7 +194,7 @@ static ssize_t vis_data_read_entry(char *buff, struct vis_info_entry *entry, { /* maximal length: max(4+17+2, 3+17+1+3+2) == 26 */ if (primary && entry->quality == 0) - return sprintf(buff, "HNA %pM, ", entry->dest); + return sprintf(buff, "TT %pM, ", entry->dest); else if (compare_eth(entry->src, src)) return sprintf(buff, "TQ %pM %d, ", entry->dest, entry->quality); @@ -622,7 +622,7 @@ static int generate_vis_packet(struct bat_priv *bat_priv) struct vis_info *info = (struct vis_info *)bat_priv->my_vis_info; struct vis_packet *packet = (struct vis_packet *)info->skb_packet->data; struct vis_info_entry *entry; - struct hna_local_entry *hna_local_entry; + struct tt_local_entry *tt_local_entry; int best_tq = -1, i; info->first_seen = jiffies; @@ -678,29 +678,29 @@ next: rcu_read_unlock(); } - hash = bat_priv->hna_local_hash; + hash = bat_priv->tt_local_hash; - spin_lock_bh(&bat_priv->hna_lhash_lock); + spin_lock_bh(&bat_priv->tt_lhash_lock); for (i = 0; i < hash->size; i++) { head = &hash->table[i]; - hlist_for_each_entry(hna_local_entry, node, head, hash_entry) { + hlist_for_each_entry(tt_local_entry, node, head, hash_entry) { entry = (struct vis_info_entry *) skb_put(info->skb_packet, sizeof(*entry)); memset(entry->src, 0, ETH_ALEN); - memcpy(entry->dest, hna_local_entry->addr, ETH_ALEN); - entry->quality = 0; /* 0 means HNA */ + memcpy(entry->dest, tt_local_entry->addr, ETH_ALEN); + entry->quality = 0; /* 0 means TT */ packet->entries++; if (vis_packet_full(info)) { - spin_unlock_bh(&bat_priv->hna_lhash_lock); + spin_unlock_bh(&bat_priv->tt_lhash_lock); return 0; } } } - spin_unlock_bh(&bat_priv->hna_lhash_lock); + spin_unlock_bh(&bat_priv->tt_lhash_lock); return 0; unlock: -- cgit v0.10.2 From 6e215fd8eb4930373d01da0fac16a0889804fac3 Mon Sep 17 00:00:00 2001 From: Sven Eckelmann Date: Sun, 8 May 2011 12:45:45 +0200 Subject: batman-adv: Remove multiline comments from line ending It is slightly irritating that comments after a long line span over multiple lines without any code. It is easier to put them before the actual code and reduce the number of lines which the eye has to read. Signed-off-by: Sven Eckelmann diff --git a/net/batman-adv/main.h b/net/batman-adv/main.h index 9ef6ef9..148b49e 100644 --- a/net/batman-adv/main.h +++ b/net/batman-adv/main.h @@ -34,16 +34,18 @@ #define TQ_MAX_VALUE 255 #define JITTER 20 -#define TTL 50 /* Time To Live of broadcast messages */ -#define PURGE_TIMEOUT 200 /* purge originators after time in seconds if no - * valid packet comes in -> TODO: check - * influence on TQ_LOCAL_WINDOW_SIZE */ + /* Time To Live of broadcast messages */ +#define TTL 50 + +/* purge originators after time in seconds if no valid packet comes in + * -> TODO: check influence on TQ_LOCAL_WINDOW_SIZE */ +#define PURGE_TIMEOUT 200 #define TT_LOCAL_TIMEOUT 3600 /* in seconds */ -#define TQ_LOCAL_WINDOW_SIZE 64 /* sliding packet range of received originator - * messages in squence numbers (should be a - * multiple of our word size) */ +/* sliding packet range of received originator messages in squence numbers + * (should be a multiple of our word size) */ +#define TQ_LOCAL_WINDOW_SIZE 64 #define TQ_GLOBAL_WINDOW_SIZE 5 #define TQ_LOCAL_BIDRECT_SEND_MINIMUM 1 #define TQ_LOCAL_BIDRECT_RECV_MINIMUM 1 @@ -55,21 +57,20 @@ #define VIS_INTERVAL 5000 /* 5 seconds */ -/* how much worse secondary interfaces may be to - * to be considered as bonding candidates */ - +/* how much worse secondary interfaces may be to be considered as bonding + * candidates */ #define BONDING_TQ_THRESHOLD 50 -#define MAX_AGGREGATION_BYTES 512 /* should not be bigger than 512 bytes or - * change the size of - * forw_packet->direct_link_flags */ +/* should not be bigger than 512 bytes or change the size of + * forw_packet->direct_link_flags */ +#define MAX_AGGREGATION_BYTES 512 #define MAX_AGGREGATION_MS 100 #define SOFTIF_NEIGH_TIMEOUT 180000 /* 3 minutes */ +/* don't reset again within 30 seconds */ #define RESET_PROTECTION_MS 30000 #define EXPECTED_SEQNO_RANGE 65536 -/* don't reset again within 30 seconds */ #define MESH_INACTIVE 0 #define MESH_ACTIVE 1 @@ -84,12 +85,13 @@ #ifdef pr_fmt #undef pr_fmt #endif -#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt /* Append 'batman-adv: ' before - * kernel messages */ +/* Append 'batman-adv: ' before kernel messages */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt -#define DBG_BATMAN 1 /* all messages related to routing / flooding / - * broadcasting / etc */ -#define DBG_ROUTES 2 /* route or tt entry added / changed / deleted */ +/* all messages related to routing / flooding / broadcasting / etc */ +#define DBG_BATMAN 1 +/* route or tt entry added / changed / deleted */ +#define DBG_ROUTES 2 #define DBG_ALL 3 diff --git a/net/batman-adv/packet.h b/net/batman-adv/packet.h index c225c3a..eda9965 100644 --- a/net/batman-adv/packet.h +++ b/net/batman-adv/packet.h @@ -128,8 +128,7 @@ struct vis_packet { uint8_t entries; /* number of entries behind this struct */ uint32_t seqno; /* sequence number */ uint8_t ttl; /* TTL */ - uint8_t vis_orig[6]; /* originator that informs about its - * neighbors */ + uint8_t vis_orig[6]; /* originator that announces its neighbors */ uint8_t target_orig[6]; /* who should receive this packet */ uint8_t sender_orig[6]; /* who sent or rebroadcasted this packet */ } __packed; diff --git a/net/batman-adv/soft-interface.c b/net/batman-adv/soft-interface.c index d6aaf9f..8e962e3 100644 --- a/net/batman-adv/soft-interface.c +++ b/net/batman-adv/soft-interface.c @@ -793,8 +793,8 @@ static void interface_setup(struct net_device *dev) * have not been initialized yet */ dev->mtu = ETH_DATA_LEN; - dev->hard_header_len = BAT_HEADER_LEN; /* reserve more space in the - * skbuff for our header */ + /* reserve more space in the skbuff for our header */ + dev->hard_header_len = BAT_HEADER_LEN; /* generate random address */ random_ether_addr(dev_addr); diff --git a/net/batman-adv/types.h b/net/batman-adv/types.h index 6b6c32e..fab70e8 100644 --- a/net/batman-adv/types.h +++ b/net/batman-adv/types.h @@ -89,11 +89,11 @@ struct orig_node { struct hlist_node hash_entry; struct bat_priv *bat_priv; unsigned long last_frag_packet; - spinlock_t ogm_cnt_lock; /* protects: bcast_own, bcast_own_sum, - * neigh_node->real_bits, - * neigh_node->real_packet_count */ - spinlock_t bcast_seqno_lock; /* protects bcast_bits, - * last_bcast_seqno */ + /* ogm_cnt_lock protects: bcast_own, bcast_own_sum, + * neigh_node->real_bits, neigh_node->real_packet_count */ + spinlock_t ogm_cnt_lock; + /* bcast_seqno_lock protects bcast_bits, last_bcast_seqno */ + spinlock_t bcast_seqno_lock; atomic_t bond_candidates; struct list_head bond_list; }; -- cgit v0.10.2 From 27aea2128ec09924dfe08e97739b2bf8b15c8619 Mon Sep 17 00:00:00 2001 From: Daniele Furlan Date: Sat, 7 May 2011 22:45:19 +0200 Subject: batman-adv: remove duplicate code from function is_bidirectional_neigh() In function is_bidirectional_neigh the code that find out the one hop neighbor is duplicated. Signed-off-by: Daniele Furlan Signed-off-by: Sven Eckelmann diff --git a/net/batman-adv/routing.c b/net/batman-adv/routing.c index 7648b92..bb1c3ec 100644 --- a/net/batman-adv/routing.c +++ b/net/batman-adv/routing.c @@ -169,65 +169,41 @@ static int is_bidirectional_neigh(struct orig_node *orig_node, uint8_t orig_eq_count, neigh_rq_count, tq_own; int tq_asym_penalty, ret = 0; - if (orig_node == orig_neigh_node) { - rcu_read_lock(); - hlist_for_each_entry_rcu(tmp_neigh_node, node, - &orig_node->neigh_list, list) { - - if (!compare_eth(tmp_neigh_node->addr, - orig_neigh_node->orig)) - continue; - - if (tmp_neigh_node->if_incoming != if_incoming) - continue; - - if (!atomic_inc_not_zero(&tmp_neigh_node->refcount)) - continue; - - neigh_node = tmp_neigh_node; - } - rcu_read_unlock(); + /* find corresponding one hop neighbor */ + rcu_read_lock(); + hlist_for_each_entry_rcu(tmp_neigh_node, node, + &orig_neigh_node->neigh_list, list) { - if (!neigh_node) - neigh_node = create_neighbor(orig_node, - orig_neigh_node, - orig_neigh_node->orig, - if_incoming); - if (!neigh_node) - goto out; + if (!compare_eth(tmp_neigh_node->addr, orig_neigh_node->orig)) + continue; - neigh_node->last_valid = jiffies; - } else { - /* find packet count of corresponding one hop neighbor */ - rcu_read_lock(); - hlist_for_each_entry_rcu(tmp_neigh_node, node, - &orig_neigh_node->neigh_list, list) { + if (tmp_neigh_node->if_incoming != if_incoming) + continue; - if (!compare_eth(tmp_neigh_node->addr, - orig_neigh_node->orig)) - continue; + if (!atomic_inc_not_zero(&tmp_neigh_node->refcount)) + continue; - if (tmp_neigh_node->if_incoming != if_incoming) - continue; + neigh_node = tmp_neigh_node; + break; + } + rcu_read_unlock(); - if (!atomic_inc_not_zero(&tmp_neigh_node->refcount)) - continue; + if (!neigh_node) + neigh_node = create_neighbor(orig_neigh_node, + orig_neigh_node, + orig_neigh_node->orig, + if_incoming); - neigh_node = tmp_neigh_node; - } - rcu_read_unlock(); + if (!neigh_node) + goto out; - if (!neigh_node) - neigh_node = create_neighbor(orig_neigh_node, - orig_neigh_node, - orig_neigh_node->orig, - if_incoming); - if (!neigh_node) - goto out; - } + /* if orig_node is direct neighbour update neigh_node last_valid */ + if (orig_node == orig_neigh_node) + neigh_node->last_valid = jiffies; orig_node->last_valid = jiffies; + /* find packet count of corresponding one hop neighbor */ spin_lock_bh(&orig_node->ogm_cnt_lock); orig_eq_count = orig_neigh_node->bcast_own_sum[if_incoming->if_num]; neigh_rq_count = neigh_node->real_packet_count; -- cgit v0.10.2 From bf707de21fec7bb203dace2d0a2bbd124d1b36ca Mon Sep 17 00:00:00 2001 From: Marek Belisko Date: Tue, 3 May 2011 14:46:32 +0200 Subject: ASoC: UDA134x: Remove POWER_OFF_ON_STANDBY define. Define POWER_OFF_ON_STANDBY cause trobles when trying to get some sound from codec because code for bias setup was not compiled (define wasn't defined). This define was removed in commit: cc3202f5 but again introduced by commit: f0fba2ad1 which then completely break codec functionality so remove it again. Signed-off-by: Marek Belisko Acked-by: Liam Girdwood Signed-off-by: Mark Brown Cc: stable@kernel.org diff --git a/sound/soc/codecs/uda134x.c b/sound/soc/codecs/uda134x.c index 48ffd40..a7b8f30 100644 --- a/sound/soc/codecs/uda134x.c +++ b/sound/soc/codecs/uda134x.c @@ -601,9 +601,7 @@ static struct snd_soc_codec_driver soc_codec_dev_uda134x = { .reg_cache_step = 1, .read = uda134x_read_reg_cache, .write = uda134x_write, -#ifdef POWER_OFF_ON_STANDBY .set_bias_level = uda134x_set_bias_level, -#endif }; static int __devinit uda134x_codec_probe(struct platform_device *pdev) -- cgit v0.10.2 From 1ab7b6ac2709d0eb05a7144cd0e14faa3a7ea162 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Thu, 14 Apr 2011 23:46:06 -0700 Subject: ethtool: remove phys_id from ethtool_ops After that all the upstream kernel drivers now use phys_id, and the old ethtool_ops interface (phys_id) can be removed. Signed-off-by: Stephen Hemminger Signed-off-by: David S. Miller diff --git a/include/linux/ethtool.h b/include/linux/ethtool.h index 4194a20..d659fdc 100644 --- a/include/linux/ethtool.h +++ b/include/linux/ethtool.h @@ -814,12 +814,6 @@ bool ethtool_invalid_flags(struct net_device *dev, u32 data, u32 supported); * the indicator accordingly. Finally, it is called with the argument * %ETHTOOL_ID_INACTIVE and must deactivate the indicator. Returns a * negative error code or zero. - * @phys_id: Deprecated in favour of @set_phys_id. - * Identify the physical device, e.g. by flashing an LED - * attached to it until interrupted by a signal or the given time - * (in seconds) elapses. If the given time is zero, use a default - * time limit. Returns a negative error code or zero. Being - * interrupted by a signal is not an error. * @get_ethtool_stats: Return extended statistics about the device. * This is only useful if the device maintains statistics not * included in &struct rtnl_link_stats64. @@ -908,7 +902,6 @@ struct ethtool_ops { void (*self_test)(struct net_device *, struct ethtool_test *, u64 *); void (*get_strings)(struct net_device *, u32 stringset, u8 *); int (*set_phys_id)(struct net_device *, enum ethtool_phys_id_state); - int (*phys_id)(struct net_device *, u32); void (*get_ethtool_stats)(struct net_device *, struct ethtool_stats *, u64 *); int (*begin)(struct net_device *); diff --git a/net/core/ethtool.c b/net/core/ethtool.c index d8b1a8d..927819d 100644 --- a/net/core/ethtool.c +++ b/net/core/ethtool.c @@ -1655,7 +1655,7 @@ static int ethtool_phys_id(struct net_device *dev, void __user *useraddr) static bool busy; int rc; - if (!dev->ethtool_ops->set_phys_id && !dev->ethtool_ops->phys_id) + if (!dev->ethtool_ops->set_phys_id) return -EOPNOTSUPP; if (busy) @@ -1664,10 +1664,6 @@ static int ethtool_phys_id(struct net_device *dev, void __user *useraddr) if (copy_from_user(&id, useraddr, sizeof(id))) return -EFAULT; - if (!dev->ethtool_ops->set_phys_id) - /* Do it the old way */ - return dev->ethtool_ops->phys_id(dev, id.data); - rc = dev->ethtool_ops->set_phys_id(dev, ETHTOOL_ID_ACTIVE); if (rc < 0) return rc; -- cgit v0.10.2 From 2c42758cf6683e9c1657d20dcf2a7edd323d98ca Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Fri, 6 May 2011 16:10:41 -0700 Subject: dccp: Use cork flow in dccp_v4_connect() Since this is invoked from inet_stream_connect() the socket is locked and therefore this usage is safe. Signed-off-by: David S. Miller diff --git a/net/dccp/ipv4.c b/net/dccp/ipv4.c index 36700a46..4ac1a72 100644 --- a/net/dccp/ipv4.c +++ b/net/dccp/ipv4.c @@ -45,7 +45,7 @@ int dccp_v4_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len) struct dccp_sock *dp = dccp_sk(sk); __be16 orig_sport, orig_dport; __be32 daddr, nexthop; - struct flowi4 fl4; + struct flowi4 *fl4; struct rtable *rt; int err; struct ip_options_rcu *inet_opt; @@ -70,7 +70,8 @@ int dccp_v4_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len) orig_sport = inet->inet_sport; orig_dport = usin->sin_port; - rt = ip_route_connect(&fl4, nexthop, inet->inet_saddr, + fl4 = &inet->cork.fl.u.ip4; + rt = ip_route_connect(fl4, nexthop, inet->inet_saddr, RT_CONN_FLAGS(sk), sk->sk_bound_dev_if, IPPROTO_DCCP, orig_sport, orig_dport, sk, true); @@ -83,10 +84,10 @@ int dccp_v4_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len) } if (inet_opt == NULL || !inet_opt->opt.srr) - daddr = fl4.daddr; + daddr = fl4->daddr; if (inet->inet_saddr == 0) - inet->inet_saddr = fl4.saddr; + inet->inet_saddr = fl4->saddr; inet->inet_rcv_saddr = inet->inet_saddr; inet->inet_dport = usin->sin_port; @@ -106,7 +107,7 @@ int dccp_v4_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len) if (err != 0) goto failure; - rt = ip_route_newports(&fl4, rt, orig_sport, orig_dport, + rt = ip_route_newports(fl4, rt, orig_sport, orig_dport, inet->inet_sport, inet->inet_dport, sk); if (IS_ERR(rt)) { rt = NULL; -- cgit v0.10.2 From da905bd1d5a6480d206f4b3dc61243f95adfae2c Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Fri, 6 May 2011 16:11:19 -0700 Subject: tcp: Use cork flow in tcp_v4_connect() Since this is invoked from inet_stream_connect() the socket is locked and therefore this usage is safe. Signed-off-by: David S. Miller diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c index f3d16d8..a712171 100644 --- a/net/ipv4/tcp_ipv4.c +++ b/net/ipv4/tcp_ipv4.c @@ -151,7 +151,7 @@ int tcp_v4_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len) struct tcp_sock *tp = tcp_sk(sk); __be16 orig_sport, orig_dport; __be32 daddr, nexthop; - struct flowi4 fl4; + struct flowi4 *fl4; struct rtable *rt; int err; struct ip_options_rcu *inet_opt; @@ -173,7 +173,8 @@ int tcp_v4_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len) orig_sport = inet->inet_sport; orig_dport = usin->sin_port; - rt = ip_route_connect(&fl4, nexthop, inet->inet_saddr, + fl4 = &inet->cork.fl.u.ip4; + rt = ip_route_connect(fl4, nexthop, inet->inet_saddr, RT_CONN_FLAGS(sk), sk->sk_bound_dev_if, IPPROTO_TCP, orig_sport, orig_dport, sk, true); @@ -190,10 +191,10 @@ int tcp_v4_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len) } if (!inet_opt || !inet_opt->opt.srr) - daddr = fl4.daddr; + daddr = fl4->daddr; if (!inet->inet_saddr) - inet->inet_saddr = fl4.saddr; + inet->inet_saddr = fl4->saddr; inet->inet_rcv_saddr = inet->inet_saddr; if (tp->rx_opt.ts_recent_stamp && inet->inet_daddr != daddr) { @@ -204,7 +205,7 @@ int tcp_v4_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len) } if (tcp_death_row.sysctl_tw_recycle && - !tp->rx_opt.ts_recent_stamp && fl4.daddr == daddr) { + !tp->rx_opt.ts_recent_stamp && fl4->daddr == daddr) { struct inet_peer *peer = rt_get_peer(rt); /* * VJ's idea. We save last timestamp seen from @@ -240,7 +241,7 @@ int tcp_v4_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len) if (err) goto failure; - rt = ip_route_newports(&fl4, rt, orig_sport, orig_dport, + rt = ip_route_newports(fl4, rt, orig_sport, orig_dport, inet->inet_sport, inet->inet_dport, sk); if (IS_ERR(rt)) { err = PTR_ERR(rt); -- cgit v0.10.2 From 2f16270f41e1499e23e6be25c51be87d950ffc91 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Sun, 8 May 2011 13:39:01 -0700 Subject: l2tp: Fix locking in l2tp_ip.c Both l2tp_ip_connect() and l2tp_ip_sendmsg() must take the socket lock. They both modify socket state non-atomically, and in particular l2tp_ip_sendmsg() increments socket private counters without using atomic operations. Signed-off-by: David S. Miller diff --git a/net/l2tp/l2tp_ip.c b/net/l2tp/l2tp_ip.c index 8189960..bd0cc0b 100644 --- a/net/l2tp/l2tp_ip.c +++ b/net/l2tp/l2tp_ip.c @@ -311,6 +311,8 @@ static int l2tp_ip_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len if (lsa->l2tp_family != AF_INET) goto out; + lock_sock(sk); + sk_dst_reset(sk); oif = sk->sk_bound_dev_if; @@ -356,6 +358,7 @@ static int l2tp_ip_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len rc = 0; out: + release_sock(sk); return rc; } @@ -420,18 +423,23 @@ static int l2tp_ip_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *m int connected = 0; __be32 daddr; + lock_sock(sk); + + rc = -ENOTCONN; if (sock_flag(sk, SOCK_DEAD)) - return -ENOTCONN; + goto out; /* Get and verify the address. */ if (msg->msg_name) { struct sockaddr_l2tpip *lip = (struct sockaddr_l2tpip *) msg->msg_name; + rc = -EINVAL; if (msg->msg_namelen < sizeof(*lip)) - return -EINVAL; + goto out; if (lip->l2tp_family != AF_INET) { + rc = -EAFNOSUPPORT; if (lip->l2tp_family != AF_UNSPEC) - return -EAFNOSUPPORT; + goto out; } daddr = lip->l2tp_addr.s_addr; @@ -510,12 +518,15 @@ error: lsa->tx_errors++; } +out: + release_sock(sk); return rc; no_route: IP_INC_STATS(sock_net(sk), IPSTATS_MIB_OUTNOROUTES); kfree_skb(skb); - return -EHOSTUNREACH; + rc = -EHOSTUNREACH; + goto out; } static int l2tp_ip_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, -- cgit v0.10.2 From 6af88da14ee284aaad6e4326da09a89191ab6165 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Sun, 8 May 2011 13:45:20 -0700 Subject: l2tp: Fix locking in l2tp_core.c l2tp_xmit_skb() must take the socket lock. It makes use of ip_queue_xmit() which expects to execute in a socket atomic context. Since we execute this function in software interrupts, we cannot use the usual lock_sock()/release_sock() sequence, instead we have to use bh_lock_sock() and see if a user has the socket locked, and if so drop the packet. Signed-off-by: David S. Miller diff --git a/net/l2tp/l2tp_core.c b/net/l2tp/l2tp_core.c index c64ce0a..7853029 100644 --- a/net/l2tp/l2tp_core.c +++ b/net/l2tp/l2tp_core.c @@ -1060,6 +1060,12 @@ int l2tp_xmit_skb(struct l2tp_session *session, struct sk_buff *skb, int hdr_len IPSKB_REROUTED); nf_reset(skb); + bh_lock_sock(sk); + if (sock_owned_by_user(sk)) { + dev_kfree_skb(skb); + goto out_unlock; + } + /* Get routing info from the tunnel socket */ skb_dst_drop(skb); skb_dst_set(skb, dst_clone(__sk_dst_get(sk))); @@ -1106,6 +1112,8 @@ int l2tp_xmit_skb(struct l2tp_session *session, struct sk_buff *skb, int hdr_len l2tp_skb_set_owner_w(skb, sk); l2tp_xmit_core(session, skb, data_len); +out_unlock: + bh_unlock_sock(sk); abort: return 0; -- cgit v0.10.2 From fdbb0f076b065a0c753ba26925f10357505f1d42 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Sun, 8 May 2011 13:48:37 -0700 Subject: l2tp: Use cork flow in l2tp_ip_connect() and l2tp_ip_sendmsg() Now that the socket is consistently locked in these two routines, this transformation is legal. Signed-off-by: David S. Miller diff --git a/net/l2tp/l2tp_ip.c b/net/l2tp/l2tp_ip.c index bd0cc0b..1ca7489 100644 --- a/net/l2tp/l2tp_ip.c +++ b/net/l2tp/l2tp_ip.c @@ -298,7 +298,7 @@ static int l2tp_ip_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len { struct sockaddr_l2tpip *lsa = (struct sockaddr_l2tpip *) uaddr; struct inet_sock *inet = inet_sk(sk); - struct flowi4 fl4; + struct flowi4 *fl4; struct rtable *rt; __be32 saddr; int oif, rc; @@ -322,7 +322,8 @@ static int l2tp_ip_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len if (ipv4_is_multicast(lsa->l2tp_addr.s_addr)) goto out; - rt = ip_route_connect(&fl4, lsa->l2tp_addr.s_addr, saddr, + fl4 = &inet->cork.fl.u.ip4; + rt = ip_route_connect(fl4, lsa->l2tp_addr.s_addr, saddr, RT_CONN_FLAGS(sk), oif, IPPROTO_L2TP, 0, 0, sk, true); @@ -342,10 +343,10 @@ static int l2tp_ip_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len l2tp_ip_sk(sk)->peer_conn_id = lsa->l2tp_conn_id; if (!inet->inet_saddr) - inet->inet_saddr = fl4.saddr; + inet->inet_saddr = fl4->saddr; if (!inet->inet_rcv_saddr) - inet->inet_rcv_saddr = fl4.saddr; - inet->inet_daddr = fl4.daddr; + inet->inet_rcv_saddr = fl4->saddr; + inet->inet_daddr = fl4->daddr; sk->sk_state = TCP_ESTABLISHED; inet->inet_id = jiffies; @@ -420,6 +421,7 @@ static int l2tp_ip_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *m struct l2tp_ip_sock *lsa = l2tp_ip_sk(sk); struct inet_sock *inet = inet_sk(sk); struct rtable *rt = NULL; + struct flowi4 *fl4; int connected = 0; __be32 daddr; @@ -474,12 +476,12 @@ static int l2tp_ip_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *m goto error; } + fl4 = &inet->cork.fl.u.ip4; if (connected) rt = (struct rtable *) __sk_dst_check(sk, 0); if (rt == NULL) { struct ip_options_rcu *inet_opt; - struct flowi4 fl4; rcu_read_lock(); inet_opt = rcu_dereference(inet->inet_opt); @@ -494,7 +496,7 @@ static int l2tp_ip_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *m * keep trying until route appears or the connection times * itself out. */ - rt = ip_route_output_ports(sock_net(sk), &fl4, sk, + rt = ip_route_output_ports(sock_net(sk), fl4, sk, daddr, inet->inet_saddr, inet->inet_dport, inet->inet_sport, sk->sk_protocol, RT_CONN_FLAGS(sk), -- cgit v0.10.2 From 3038eeac027d8ec62e4936143498f2b37baf4cb5 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Fri, 6 May 2011 22:27:25 -0700 Subject: ipv4: Lock socket and use cork flow in ip4_datagram_connect(). This is to make sure that an l2tp socket's inet cork flow is fully filled in, when it's encapsulated in UDP. Signed-off-by: David S. Miller diff --git a/net/ipv4/datagram.c b/net/ipv4/datagram.c index d5a2e69..424fafb 100644 --- a/net/ipv4/datagram.c +++ b/net/ipv4/datagram.c @@ -24,7 +24,7 @@ int ip4_datagram_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len) { struct inet_sock *inet = inet_sk(sk); struct sockaddr_in *usin = (struct sockaddr_in *) uaddr; - struct flowi4 fl4; + struct flowi4 *fl4; struct rtable *rt; __be32 saddr; int oif; @@ -39,6 +39,8 @@ int ip4_datagram_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len) sk_dst_reset(sk); + lock_sock(sk); + oif = sk->sk_bound_dev_if; saddr = inet->inet_saddr; if (ipv4_is_multicast(usin->sin_addr.s_addr)) { @@ -47,7 +49,8 @@ int ip4_datagram_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len) if (!saddr) saddr = inet->mc_addr; } - rt = ip_route_connect(&fl4, usin->sin_addr.s_addr, saddr, + fl4 = &inet->cork.fl.u.ip4; + rt = ip_route_connect(fl4, usin->sin_addr.s_addr, saddr, RT_CONN_FLAGS(sk), oif, sk->sk_protocol, inet->inet_sport, usin->sin_port, sk, true); @@ -55,26 +58,30 @@ int ip4_datagram_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len) err = PTR_ERR(rt); if (err == -ENETUNREACH) IP_INC_STATS_BH(sock_net(sk), IPSTATS_MIB_OUTNOROUTES); - return err; + goto out; } if ((rt->rt_flags & RTCF_BROADCAST) && !sock_flag(sk, SOCK_BROADCAST)) { ip_rt_put(rt); - return -EACCES; + err = -EACCES; + goto out; } if (!inet->inet_saddr) - inet->inet_saddr = fl4.saddr; /* Update source address */ + inet->inet_saddr = fl4->saddr; /* Update source address */ if (!inet->inet_rcv_saddr) { - inet->inet_rcv_saddr = fl4.saddr; + inet->inet_rcv_saddr = fl4->saddr; if (sk->sk_prot->rehash) sk->sk_prot->rehash(sk); } - inet->inet_daddr = fl4.daddr; + inet->inet_daddr = fl4->daddr; inet->inet_dport = usin->sin_port; sk->sk_state = TCP_ESTABLISHED; inet->inet_id = jiffies; sk_dst_set(sk, &rt->dst); - return 0; + err = 0; +out: + release_sock(sk); + return err; } EXPORT_SYMBOL(ip4_datagram_connect); -- cgit v0.10.2 From 6e869138101bc607e4780187210b79d531f9b2ce Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Fri, 6 May 2011 16:18:04 -0700 Subject: ipv4: Use cork flow in inet_sk_{reselect_saddr,rebuild_header}() These two functions must be invoked only when the socket is locked (because socket identity modifications are made non-atomically). Therefore we can use the cork flow for output route lookups. Signed-off-by: David S. Miller diff --git a/net/ipv4/af_inet.c b/net/ipv4/af_inet.c index 7b91fa8..851aa05 100644 --- a/net/ipv4/af_inet.c +++ b/net/ipv4/af_inet.c @@ -1103,7 +1103,7 @@ static int inet_sk_reselect_saddr(struct sock *sk) struct inet_sock *inet = inet_sk(sk); __be32 old_saddr = inet->inet_saddr; __be32 daddr = inet->inet_daddr; - struct flowi4 fl4; + struct flowi4 *fl4; struct rtable *rt; __be32 new_saddr; struct ip_options_rcu *inet_opt; @@ -1114,7 +1114,8 @@ static int inet_sk_reselect_saddr(struct sock *sk) daddr = inet_opt->opt.faddr; /* Query new route. */ - rt = ip_route_connect(&fl4, daddr, 0, RT_CONN_FLAGS(sk), + fl4 = &inet->cork.fl.u.ip4; + rt = ip_route_connect(fl4, daddr, 0, RT_CONN_FLAGS(sk), sk->sk_bound_dev_if, sk->sk_protocol, inet->inet_sport, inet->inet_dport, sk, false); if (IS_ERR(rt)) @@ -1122,7 +1123,7 @@ static int inet_sk_reselect_saddr(struct sock *sk) sk_setup_caps(sk, &rt->dst); - new_saddr = fl4.saddr; + new_saddr = fl4->saddr; if (new_saddr == old_saddr) return 0; @@ -1152,7 +1153,7 @@ int inet_sk_rebuild_header(struct sock *sk) struct rtable *rt = (struct rtable *)__sk_dst_check(sk, 0); __be32 daddr; struct ip_options_rcu *inet_opt; - struct flowi4 fl4; + struct flowi4 *fl4; int err; /* Route is OK, nothing to do. */ @@ -1166,7 +1167,8 @@ int inet_sk_rebuild_header(struct sock *sk) if (inet_opt && inet_opt->opt.srr) daddr = inet_opt->opt.faddr; rcu_read_unlock(); - rt = ip_route_output_ports(sock_net(sk), &fl4, sk, daddr, inet->inet_saddr, + fl4 = &inet->cork.fl.u.ip4; + rt = ip_route_output_ports(sock_net(sk), fl4, sk, daddr, inet->inet_saddr, inet->inet_dport, inet->inet_sport, sk->sk_protocol, RT_CONN_FLAGS(sk), sk->sk_bound_dev_if); -- cgit v0.10.2 From b57ae01a8a8446dbbed7365c9b05aef1fc6dea20 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Fri, 6 May 2011 16:24:06 -0700 Subject: ipv4: Use cork flow in ip_queue_xmit() All invokers of ip_queue_xmit() must make certain that the socket is locked. All of SCTP, TCP, DCCP, and L2TP now make sure this is the case. Therefore we can use the cork flow during output route lookup in ip_queue_xmit() when the socket route check fails. Signed-off-by: David S. Miller diff --git a/net/ipv4/ip_output.c b/net/ipv4/ip_output.c index 0a2f49a..4ba26d4 100644 --- a/net/ipv4/ip_output.c +++ b/net/ipv4/ip_output.c @@ -317,6 +317,7 @@ int ip_queue_xmit(struct sk_buff *skb) struct sock *sk = skb->sk; struct inet_sock *inet = inet_sk(sk); struct ip_options_rcu *inet_opt; + struct flowi4 *fl4; struct rtable *rt; struct iphdr *iph; int res; @@ -331,9 +332,9 @@ int ip_queue_xmit(struct sk_buff *skb) goto packet_routed; /* Make sure we can route this packet. */ + fl4 = &inet->cork.fl.u.ip4; rt = (struct rtable *)__sk_dst_check(sk, 0); if (rt == NULL) { - struct flowi4 fl4; __be32 daddr; /* Use correct destination address if we have options. */ @@ -345,7 +346,7 @@ int ip_queue_xmit(struct sk_buff *skb) * keep trying until route appears or the connection times * itself out. */ - rt = ip_route_output_ports(sock_net(sk), &fl4, sk, + rt = ip_route_output_ports(sock_net(sk), fl4, sk, daddr, inet->inet_saddr, inet->inet_dport, inet->inet_sport, -- cgit v0.10.2 From 8663c938ceb72f47941c95ff0ea491ebbdd68f26 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Fri, 6 May 2011 16:32:47 -0700 Subject: sctp: Store a flowi in transports to provide persistent keying. Several future simplifications are possible now because of this. For example, the sctp_addr unions can simply refer directly to the flowi information. Signed-off-by: David S. Miller diff --git a/include/net/sctp/structs.h b/include/net/sctp/structs.h index ff3e8cc..795f488 100644 --- a/include/net/sctp/structs.h +++ b/include/net/sctp/structs.h @@ -894,6 +894,7 @@ struct sctp_transport { /* Is this structure kfree()able? */ malloced:1; + struct flowi fl; /* This is the peer's IP address and port. */ union sctp_addr ipaddr; diff --git a/net/sctp/transport.c b/net/sctp/transport.c index d8595dd..394c57c 100644 --- a/net/sctp/transport.c +++ b/net/sctp/transport.c @@ -213,13 +213,11 @@ void sctp_transport_set_owner(struct sctp_transport *transport, /* Initialize the pmtu of a transport. */ void sctp_transport_pmtu(struct sctp_transport *transport, struct sock *sk) { - struct flowi fl; - /* If we don't have a fresh route, look one up */ if (!transport->dst || transport->dst->obsolete > 1) { dst_release(transport->dst); transport->af_specific->get_dst(transport, &transport->saddr, - &fl, sk); + &transport->fl, sk); } if (transport->dst) { @@ -274,14 +272,13 @@ void sctp_transport_route(struct sctp_transport *transport, { struct sctp_association *asoc = transport->asoc; struct sctp_af *af = transport->af_specific; - struct flowi fl; - af->get_dst(transport, saddr, &fl, sctp_opt2sk(opt)); + af->get_dst(transport, saddr, &transport->fl, sctp_opt2sk(opt)); if (saddr) memcpy(&transport->saddr, saddr, sizeof(union sctp_addr)); else - af->get_saddr(opt, transport, &fl); + af->get_saddr(opt, transport, &transport->fl); if ((transport->param_flags & SPP_PMTUD_DISABLE) && transport->pathmtu) { return; -- cgit v0.10.2 From 77357a95522ba645bbfd65253b34317c824103f9 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Sun, 8 May 2011 14:34:22 -0700 Subject: ipv4: Create inet_csk_route_child_sock(). This is just like inet_csk_route_req() except that it operates after we've created the new child socket. In this way we can use the new socket's cork flow for proper route key storage. This will be used by DCCP and TCP child socket creation handling. Signed-off-by: David S. Miller diff --git a/include/net/inet_connection_sock.h b/include/net/inet_connection_sock.h index 6ac4e3b..4367d91 100644 --- a/include/net/inet_connection_sock.h +++ b/include/net/inet_connection_sock.h @@ -250,6 +250,9 @@ extern int inet_csk_get_port(struct sock *sk, unsigned short snum); extern struct dst_entry* inet_csk_route_req(struct sock *sk, const struct request_sock *req); +extern struct dst_entry* inet_csk_route_child_sock(struct sock *sk, + struct sock *newsk, + const struct request_sock *req); static inline void inet_csk_reqsk_queue_add(struct sock *sk, struct request_sock *req, diff --git a/net/ipv4/inet_connection_sock.c b/net/ipv4/inet_connection_sock.c index 54944da..3a2ba56 100644 --- a/net/ipv4/inet_connection_sock.c +++ b/net/ipv4/inet_connection_sock.c @@ -379,6 +379,39 @@ no_route: } EXPORT_SYMBOL_GPL(inet_csk_route_req); +struct dst_entry *inet_csk_route_child_sock(struct sock *sk, + struct sock *newsk, + const struct request_sock *req) +{ + const struct inet_request_sock *ireq = inet_rsk(req); + struct inet_sock *newinet = inet_sk(newsk); + struct ip_options_rcu *opt = ireq->opt; + struct net *net = sock_net(sk); + struct flowi4 *fl4; + struct rtable *rt; + + fl4 = &newinet->cork.fl.u.ip4; + flowi4_init_output(fl4, sk->sk_bound_dev_if, sk->sk_mark, + RT_CONN_FLAGS(sk), RT_SCOPE_UNIVERSE, + sk->sk_protocol, inet_sk_flowi_flags(sk), + (opt && opt->opt.srr) ? opt->opt.faddr : ireq->rmt_addr, + ireq->loc_addr, ireq->rmt_port, inet_sk(sk)->inet_sport); + security_req_classify_flow(req, flowi4_to_flowi(fl4)); + rt = ip_route_output_flow(net, fl4, sk); + if (IS_ERR(rt)) + goto no_route; + if (opt && opt->opt.is_strictroute && fl4->daddr != rt->rt_gateway) + goto route_err; + return &rt->dst; + +route_err: + ip_rt_put(rt); +no_route: + IP_INC_STATS_BH(net, IPSTATS_MIB_OUTNOROUTES); + return NULL; +} +EXPORT_SYMBOL_GPL(inet_csk_route_child_sock); + static inline u32 inet_synq_hash(const __be32 raddr, const __be16 rport, const u32 rnd, const u32 synq_hsize) { -- cgit v0.10.2 From 421eab4cf318ce47c1daae391e54d1b427c6687b Mon Sep 17 00:00:00 2001 From: Hans Schillstrom Date: Tue, 3 May 2011 22:09:30 +0200 Subject: IPVS: Change of socket usage to enable name space exit. If the sync daemons run in a name space while it crashes or get killed, there is no way to stop them except for a reboot. When all patches are there, ip_vs_core will handle register_pernet_(), i.e. ip_vs_sync_init() and ip_vs_sync_cleanup() will be removed. Kernel threads should not increment the use count of a socket. By calling sk_change_net() after creating a socket this is avoided. sock_release cant be used intead sk_release_kernel() should be used. Thanks Eric W Biederman for your advices. Signed-off-by: Hans Schillstrom [horms@verge.net.au: minor edit to changelog] Signed-off-by: Simon Horman diff --git a/net/netfilter/ipvs/ip_vs_core.c b/net/netfilter/ipvs/ip_vs_core.c index 07accf6..a0791dc 100644 --- a/net/netfilter/ipvs/ip_vs_core.c +++ b/net/netfilter/ipvs/ip_vs_core.c @@ -1896,7 +1896,7 @@ static int __net_init __ip_vs_init(struct net *net) static void __net_exit __ip_vs_cleanup(struct net *net) { - IP_VS_DBG(10, "ipvs netns %d released\n", net_ipvs(net)->gen); + IP_VS_DBG(2, "ipvs netns %d released\n", net_ipvs(net)->gen); } static struct pernet_operations ipvs_core_ops = { diff --git a/net/netfilter/ipvs/ip_vs_sync.c b/net/netfilter/ipvs/ip_vs_sync.c index 3e7961e..0cce953 100644 --- a/net/netfilter/ipvs/ip_vs_sync.c +++ b/net/netfilter/ipvs/ip_vs_sync.c @@ -1303,13 +1303,18 @@ static struct socket *make_send_sock(struct net *net) struct socket *sock; int result; - /* First create a socket */ - result = __sock_create(net, PF_INET, SOCK_DGRAM, IPPROTO_UDP, &sock, 1); + /* First create a socket move it to right name space later */ + result = sock_create_kern(PF_INET, SOCK_DGRAM, IPPROTO_UDP, &sock); if (result < 0) { pr_err("Error during creation of socket; terminating\n"); return ERR_PTR(result); } - + /* + * Kernel sockets that are a part of a namespace, should not + * hold a reference to a namespace in order to allow to stop it. + * After sk_change_net should be released using sk_release_kernel. + */ + sk_change_net(sock->sk, net); result = set_mcast_if(sock->sk, ipvs->master_mcast_ifn); if (result < 0) { pr_err("Error setting outbound mcast interface\n"); @@ -1334,8 +1339,8 @@ static struct socket *make_send_sock(struct net *net) return sock; - error: - sock_release(sock); +error: + sk_release_kernel(sock->sk); return ERR_PTR(result); } @@ -1350,12 +1355,17 @@ static struct socket *make_receive_sock(struct net *net) int result; /* First create a socket */ - result = __sock_create(net, PF_INET, SOCK_DGRAM, IPPROTO_UDP, &sock, 1); + result = sock_create_kern(PF_INET, SOCK_DGRAM, IPPROTO_UDP, &sock); if (result < 0) { pr_err("Error during creation of socket; terminating\n"); return ERR_PTR(result); } - + /* + * Kernel sockets that are a part of a namespace, should not + * hold a reference to a namespace in order to allow to stop it. + * After sk_change_net should be released using sk_release_kernel. + */ + sk_change_net(sock->sk, net); /* it is equivalent to the REUSEADDR option in user-space */ sock->sk->sk_reuse = 1; @@ -1377,8 +1387,8 @@ static struct socket *make_receive_sock(struct net *net) return sock; - error: - sock_release(sock); +error: + sk_release_kernel(sock->sk); return ERR_PTR(result); } @@ -1473,7 +1483,7 @@ static int sync_thread_master(void *data) ip_vs_sync_buff_release(sb); /* release the sending multicast socket */ - sock_release(tinfo->sock); + sk_release_kernel(tinfo->sock->sk); kfree(tinfo); return 0; @@ -1513,7 +1523,7 @@ static int sync_thread_backup(void *data) } /* release the sending multicast socket */ - sock_release(tinfo->sock); + sk_release_kernel(tinfo->sock->sk); kfree(tinfo->buf); kfree(tinfo); @@ -1601,7 +1611,7 @@ outtinfo: outbuf: kfree(buf); outsocket: - sock_release(sock); + sk_release_kernel(sock->sk); out: return result; } @@ -1610,6 +1620,7 @@ out: int stop_sync_thread(struct net *net, int state) { struct netns_ipvs *ipvs = net_ipvs(net); + int retc = -EINVAL; IP_VS_DBG(7, "%s(): pid %d\n", __func__, task_pid_nr(current)); @@ -1629,7 +1640,7 @@ int stop_sync_thread(struct net *net, int state) spin_lock_bh(&ipvs->sync_lock); ipvs->sync_state &= ~IP_VS_STATE_MASTER; spin_unlock_bh(&ipvs->sync_lock); - kthread_stop(ipvs->master_thread); + retc = kthread_stop(ipvs->master_thread); ipvs->master_thread = NULL; } else if (state == IP_VS_STATE_BACKUP) { if (!ipvs->backup_thread) @@ -1639,16 +1650,14 @@ int stop_sync_thread(struct net *net, int state) task_pid_nr(ipvs->backup_thread)); ipvs->sync_state &= ~IP_VS_STATE_BACKUP; - kthread_stop(ipvs->backup_thread); + retc = kthread_stop(ipvs->backup_thread); ipvs->backup_thread = NULL; - } else { - return -EINVAL; } /* decrease the module use count */ ip_vs_use_count_dec(); - return 0; + return retc; } /* @@ -1670,8 +1679,15 @@ static int __net_init __ip_vs_sync_init(struct net *net) static void __ip_vs_sync_cleanup(struct net *net) { - stop_sync_thread(net, IP_VS_STATE_MASTER); - stop_sync_thread(net, IP_VS_STATE_BACKUP); + int retc; + + retc = stop_sync_thread(net, IP_VS_STATE_MASTER); + if (retc && retc != -ESRCH) + pr_err("Failed to stop Master Daemon\n"); + + retc = stop_sync_thread(net, IP_VS_STATE_BACKUP); + if (retc && retc != -ESRCH) + pr_err("Failed to stop Backup Daemon\n"); } static struct pernet_operations ipvs_sync_ops = { @@ -1682,10 +1698,10 @@ static struct pernet_operations ipvs_sync_ops = { int __init ip_vs_sync_init(void) { - return register_pernet_subsys(&ipvs_sync_ops); + return register_pernet_device(&ipvs_sync_ops); } void ip_vs_sync_cleanup(void) { - unregister_pernet_subsys(&ipvs_sync_ops); + unregister_pernet_device(&ipvs_sync_ops); } -- cgit v0.10.2 From 74973f6fbfcd1b084c3ccc75b783a6dacac94a10 Mon Sep 17 00:00:00 2001 From: Hans Schillstrom Date: Tue, 3 May 2011 22:09:31 +0200 Subject: IPVS: init and cleanup restructuring DESCRIPTION This patch tries to restore the initial init and cleanup sequences that was before namspace patch. Netns also requires action when net devices unregister which has never been implemented. I.e this patch also covers when a device moves into a network namespace, and has to be released. IMPLEMENTATION The number of calls to register_pernet_device have been reduced to one for the ip_vs.ko Schedulers still have their own calls. This patch adds a function __ip_vs_service_cleanup() and an enable flag for the netfilter hooks. The nf hooks will be enabled when the first service is loaded and never disabled again, except when a namespace exit starts. Signed-off-by: Hans Schillstrom Acked-by: Julian Anastasov [horms@verge.net.au: minor edit to changelog] Signed-off-by: Simon Horman diff --git a/include/net/ip_vs.h b/include/net/ip_vs.h index 4d1b71a..02f6702 100644 --- a/include/net/ip_vs.h +++ b/include/net/ip_vs.h @@ -791,6 +791,7 @@ struct ip_vs_app { /* IPVS in network namespace */ struct netns_ipvs { int gen; /* Generation */ + int enable; /* enable like nf_hooks do */ /* * Hash table: for real service lookups */ @@ -1089,6 +1090,22 @@ ip_vs_control_add(struct ip_vs_conn *cp, struct ip_vs_conn *ctl_cp) atomic_inc(&ctl_cp->n_control); } +/* + * IPVS netns init & cleanup functions + */ +extern int __ip_vs_estimator_init(struct net *net); +extern int __ip_vs_control_init(struct net *net); +extern int __ip_vs_protocol_init(struct net *net); +extern int __ip_vs_app_init(struct net *net); +extern int __ip_vs_conn_init(struct net *net); +extern int __ip_vs_sync_init(struct net *net); +extern void __ip_vs_conn_cleanup(struct net *net); +extern void __ip_vs_app_cleanup(struct net *net); +extern void __ip_vs_protocol_cleanup(struct net *net); +extern void __ip_vs_control_cleanup(struct net *net); +extern void __ip_vs_estimator_cleanup(struct net *net); +extern void __ip_vs_sync_cleanup(struct net *net); +extern void __ip_vs_service_cleanup(struct net *net); /* * IPVS application functions diff --git a/net/netfilter/ipvs/ip_vs_app.c b/net/netfilter/ipvs/ip_vs_app.c index 2dc6de1..51f3af7 100644 --- a/net/netfilter/ipvs/ip_vs_app.c +++ b/net/netfilter/ipvs/ip_vs_app.c @@ -576,7 +576,7 @@ static const struct file_operations ip_vs_app_fops = { }; #endif -static int __net_init __ip_vs_app_init(struct net *net) +int __net_init __ip_vs_app_init(struct net *net) { struct netns_ipvs *ipvs = net_ipvs(net); @@ -585,26 +585,17 @@ static int __net_init __ip_vs_app_init(struct net *net) return 0; } -static void __net_exit __ip_vs_app_cleanup(struct net *net) +void __net_exit __ip_vs_app_cleanup(struct net *net) { proc_net_remove(net, "ip_vs_app"); } -static struct pernet_operations ip_vs_app_ops = { - .init = __ip_vs_app_init, - .exit = __ip_vs_app_cleanup, -}; - int __init ip_vs_app_init(void) { - int rv; - - rv = register_pernet_subsys(&ip_vs_app_ops); - return rv; + return 0; } void ip_vs_app_cleanup(void) { - unregister_pernet_subsys(&ip_vs_app_ops); } diff --git a/net/netfilter/ipvs/ip_vs_conn.c b/net/netfilter/ipvs/ip_vs_conn.c index f289306..5092505 100644 --- a/net/netfilter/ipvs/ip_vs_conn.c +++ b/net/netfilter/ipvs/ip_vs_conn.c @@ -1258,22 +1258,17 @@ int __net_init __ip_vs_conn_init(struct net *net) return 0; } -static void __net_exit __ip_vs_conn_cleanup(struct net *net) +void __net_exit __ip_vs_conn_cleanup(struct net *net) { /* flush all the connection entries first */ ip_vs_conn_flush(net); proc_net_remove(net, "ip_vs_conn"); proc_net_remove(net, "ip_vs_conn_sync"); } -static struct pernet_operations ipvs_conn_ops = { - .init = __ip_vs_conn_init, - .exit = __ip_vs_conn_cleanup, -}; int __init ip_vs_conn_init(void) { int idx; - int retc; /* Compute size and mask */ ip_vs_conn_tab_size = 1 << ip_vs_conn_tab_bits; @@ -1309,17 +1304,14 @@ int __init ip_vs_conn_init(void) rwlock_init(&__ip_vs_conntbl_lock_array[idx].l); } - retc = register_pernet_subsys(&ipvs_conn_ops); - /* calculate the random value for connection hash */ get_random_bytes(&ip_vs_conn_rnd, sizeof(ip_vs_conn_rnd)); - return retc; + return 0; } void ip_vs_conn_cleanup(void) { - unregister_pernet_subsys(&ipvs_conn_ops); /* Release the empty cache */ kmem_cache_destroy(ip_vs_conn_cachep); vfree(ip_vs_conn_tab); diff --git a/net/netfilter/ipvs/ip_vs_core.c b/net/netfilter/ipvs/ip_vs_core.c index a0791dc..a74dae6 100644 --- a/net/netfilter/ipvs/ip_vs_core.c +++ b/net/netfilter/ipvs/ip_vs_core.c @@ -1113,6 +1113,9 @@ ip_vs_out(unsigned int hooknum, struct sk_buff *skb, int af) return NF_ACCEPT; net = skb_net(skb); + if (!net_ipvs(net)->enable) + return NF_ACCEPT; + ip_vs_fill_iphdr(af, skb_network_header(skb), &iph); #ifdef CONFIG_IP_VS_IPV6 if (af == AF_INET6) { @@ -1343,6 +1346,7 @@ ip_vs_in_icmp(struct sk_buff *skb, int *related, unsigned int hooknum) return NF_ACCEPT; /* The packet looks wrong, ignore */ net = skb_net(skb); + pd = ip_vs_proto_data_get(net, cih->protocol); if (!pd) return NF_ACCEPT; @@ -1529,6 +1533,11 @@ ip_vs_in(unsigned int hooknum, struct sk_buff *skb, int af) IP_VS_DBG_ADDR(af, &iph.daddr), hooknum); return NF_ACCEPT; } + /* ipvs enabled in this netns ? */ + net = skb_net(skb); + if (!net_ipvs(net)->enable) + return NF_ACCEPT; + ip_vs_fill_iphdr(af, skb_network_header(skb), &iph); /* Bad... Do not break raw sockets */ @@ -1562,7 +1571,6 @@ ip_vs_in(unsigned int hooknum, struct sk_buff *skb, int af) ip_vs_fill_iphdr(af, skb_network_header(skb), &iph); } - net = skb_net(skb); /* Protocol supported? */ pd = ip_vs_proto_data_get(net, iph.protocol); if (unlikely(!pd)) @@ -1588,7 +1596,6 @@ ip_vs_in(unsigned int hooknum, struct sk_buff *skb, int af) } IP_VS_DBG_PKT(11, af, pp, skb, 0, "Incoming packet"); - net = skb_net(skb); ipvs = net_ipvs(net); /* Check the server status */ if (cp->dest && !(cp->dest->flags & IP_VS_DEST_F_AVAILABLE)) { @@ -1743,10 +1750,16 @@ ip_vs_forward_icmp(unsigned int hooknum, struct sk_buff *skb, int (*okfn)(struct sk_buff *)) { int r; + struct net *net; if (ip_hdr(skb)->protocol != IPPROTO_ICMP) return NF_ACCEPT; + /* ipvs enabled in this netns ? */ + net = skb_net(skb); + if (!net_ipvs(net)->enable) + return NF_ACCEPT; + return ip_vs_in_icmp(skb, &r, hooknum); } @@ -1757,10 +1770,16 @@ ip_vs_forward_icmp_v6(unsigned int hooknum, struct sk_buff *skb, int (*okfn)(struct sk_buff *)) { int r; + struct net *net; if (ipv6_hdr(skb)->nexthdr != IPPROTO_ICMPV6) return NF_ACCEPT; + /* ipvs enabled in this netns ? */ + net = skb_net(skb); + if (!net_ipvs(net)->enable) + return NF_ACCEPT; + return ip_vs_in_icmp_v6(skb, &r, hooknum); } #endif @@ -1884,21 +1903,72 @@ static int __net_init __ip_vs_init(struct net *net) pr_err("%s(): no memory.\n", __func__); return -ENOMEM; } + /* Hold the beast until a service is registerd */ + ipvs->enable = 0; ipvs->net = net; /* Counters used for creating unique names */ ipvs->gen = atomic_read(&ipvs_netns_cnt); atomic_inc(&ipvs_netns_cnt); net->ipvs = ipvs; + + if (__ip_vs_estimator_init(net) < 0) + goto estimator_fail; + + if (__ip_vs_control_init(net) < 0) + goto control_fail; + + if (__ip_vs_protocol_init(net) < 0) + goto protocol_fail; + + if (__ip_vs_app_init(net) < 0) + goto app_fail; + + if (__ip_vs_conn_init(net) < 0) + goto conn_fail; + + if (__ip_vs_sync_init(net) < 0) + goto sync_fail; + printk(KERN_INFO "IPVS: Creating netns size=%zu id=%d\n", sizeof(struct netns_ipvs), ipvs->gen); return 0; +/* + * Error handling + */ + +sync_fail: + __ip_vs_conn_cleanup(net); +conn_fail: + __ip_vs_app_cleanup(net); +app_fail: + __ip_vs_protocol_cleanup(net); +protocol_fail: + __ip_vs_control_cleanup(net); +control_fail: + __ip_vs_estimator_cleanup(net); +estimator_fail: + return -ENOMEM; } static void __net_exit __ip_vs_cleanup(struct net *net) { + __ip_vs_service_cleanup(net); /* ip_vs_flush() with locks */ + __ip_vs_conn_cleanup(net); + __ip_vs_app_cleanup(net); + __ip_vs_protocol_cleanup(net); + __ip_vs_control_cleanup(net); + __ip_vs_estimator_cleanup(net); IP_VS_DBG(2, "ipvs netns %d released\n", net_ipvs(net)->gen); } +static void __net_exit __ip_vs_dev_cleanup(struct net *net) +{ + EnterFunction(2); + net_ipvs(net)->enable = 0; /* Disable packet reception */ + __ip_vs_sync_cleanup(net); + LeaveFunction(2); +} + static struct pernet_operations ipvs_core_ops = { .init = __ip_vs_init, .exit = __ip_vs_cleanup, @@ -1906,6 +1976,10 @@ static struct pernet_operations ipvs_core_ops = { .size = sizeof(struct netns_ipvs), }; +static struct pernet_operations ipvs_core_dev_ops = { + .exit = __ip_vs_dev_cleanup, +}; + /* * Initialize IP Virtual Server */ @@ -1913,10 +1987,6 @@ static int __init ip_vs_init(void) { int ret; - ret = register_pernet_subsys(&ipvs_core_ops); /* Alloc ip_vs struct */ - if (ret < 0) - return ret; - ip_vs_estimator_init(); ret = ip_vs_control_init(); if (ret < 0) { @@ -1944,15 +2014,28 @@ static int __init ip_vs_init(void) goto cleanup_conn; } + ret = register_pernet_subsys(&ipvs_core_ops); /* Alloc ip_vs struct */ + if (ret < 0) + goto cleanup_sync; + + ret = register_pernet_device(&ipvs_core_dev_ops); + if (ret < 0) + goto cleanup_sub; + ret = nf_register_hooks(ip_vs_ops, ARRAY_SIZE(ip_vs_ops)); if (ret < 0) { pr_err("can't register hooks.\n"); - goto cleanup_sync; + goto cleanup_dev; } pr_info("ipvs loaded.\n"); + return ret; +cleanup_dev: + unregister_pernet_device(&ipvs_core_dev_ops); +cleanup_sub: + unregister_pernet_subsys(&ipvs_core_ops); cleanup_sync: ip_vs_sync_cleanup(); cleanup_conn: @@ -1964,20 +2047,20 @@ cleanup_sync: ip_vs_control_cleanup(); cleanup_estimator: ip_vs_estimator_cleanup(); - unregister_pernet_subsys(&ipvs_core_ops); /* free ip_vs struct */ return ret; } static void __exit ip_vs_cleanup(void) { nf_unregister_hooks(ip_vs_ops, ARRAY_SIZE(ip_vs_ops)); + unregister_pernet_device(&ipvs_core_dev_ops); + unregister_pernet_subsys(&ipvs_core_ops); /* free ip_vs struct */ ip_vs_sync_cleanup(); ip_vs_conn_cleanup(); ip_vs_app_cleanup(); ip_vs_protocol_cleanup(); ip_vs_control_cleanup(); ip_vs_estimator_cleanup(); - unregister_pernet_subsys(&ipvs_core_ops); /* free ip_vs struct */ pr_info("ipvs unloaded.\n"); } diff --git a/net/netfilter/ipvs/ip_vs_ctl.c b/net/netfilter/ipvs/ip_vs_ctl.c index ae47090..ea72281 100644 --- a/net/netfilter/ipvs/ip_vs_ctl.c +++ b/net/netfilter/ipvs/ip_vs_ctl.c @@ -69,6 +69,11 @@ int ip_vs_get_debug_level(void) } #endif + +/* Protos */ +static void __ip_vs_del_service(struct ip_vs_service *svc); + + #ifdef CONFIG_IP_VS_IPV6 /* Taken from rt6_fill_node() in net/ipv6/route.c, is there a better way? */ static int __ip_vs_addr_is_local_v6(struct net *net, @@ -1214,6 +1219,8 @@ ip_vs_add_service(struct net *net, struct ip_vs_service_user_kern *u, write_unlock_bh(&__ip_vs_svc_lock); *svc_p = svc; + /* Now there is a service - full throttle */ + ipvs->enable = 1; return 0; @@ -1472,6 +1479,84 @@ static int ip_vs_flush(struct net *net) return 0; } +/* + * Delete service by {netns} in the service table. + * Called by __ip_vs_cleanup() + */ +void __ip_vs_service_cleanup(struct net *net) +{ + EnterFunction(2); + /* Check for "full" addressed entries */ + mutex_lock(&__ip_vs_mutex); + ip_vs_flush(net); + mutex_unlock(&__ip_vs_mutex); + LeaveFunction(2); +} +/* + * Release dst hold by dst_cache + */ +static inline void +__ip_vs_dev_reset(struct ip_vs_dest *dest, struct net_device *dev) +{ + spin_lock_bh(&dest->dst_lock); + if (dest->dst_cache && dest->dst_cache->dev == dev) { + IP_VS_DBG_BUF(3, "Reset dev:%s dest %s:%u ,dest->refcnt=%d\n", + dev->name, + IP_VS_DBG_ADDR(dest->af, &dest->addr), + ntohs(dest->port), + atomic_read(&dest->refcnt)); + ip_vs_dst_reset(dest); + } + spin_unlock_bh(&dest->dst_lock); + +} +/* + * Netdev event receiver + * Currently only NETDEV_UNREGISTER is handled, i.e. if we hold a reference to + * a device that is "unregister" it must be released. + */ +static int ip_vs_dst_event(struct notifier_block *this, unsigned long event, + void *ptr) +{ + struct net_device *dev = ptr; + struct net *net = dev_net(dev); + struct ip_vs_service *svc; + struct ip_vs_dest *dest; + unsigned int idx; + + if (event != NETDEV_UNREGISTER) + return NOTIFY_DONE; + IP_VS_DBG(3, "%s() dev=%s\n", __func__, dev->name); + EnterFunction(2); + mutex_lock(&__ip_vs_mutex); + for (idx = 0; idx < IP_VS_SVC_TAB_SIZE; idx++) { + list_for_each_entry(svc, &ip_vs_svc_table[idx], s_list) { + if (net_eq(svc->net, net)) { + list_for_each_entry(dest, &svc->destinations, + n_list) { + __ip_vs_dev_reset(dest, dev); + } + } + } + + list_for_each_entry(svc, &ip_vs_svc_fwm_table[idx], f_list) { + if (net_eq(svc->net, net)) { + list_for_each_entry(dest, &svc->destinations, + n_list) { + __ip_vs_dev_reset(dest, dev); + } + } + + } + } + + list_for_each_entry(dest, &net_ipvs(net)->dest_trash, n_list) { + __ip_vs_dev_reset(dest, dev); + } + mutex_unlock(&__ip_vs_mutex); + LeaveFunction(2); + return NOTIFY_DONE; +} /* * Zero counters in a service or all services @@ -3588,6 +3673,10 @@ void __net_init __ip_vs_control_cleanup_sysctl(struct net *net) { } #endif +static struct notifier_block ip_vs_dst_notifier = { + .notifier_call = ip_vs_dst_event, +}; + int __net_init __ip_vs_control_init(struct net *net) { int idx; @@ -3626,7 +3715,7 @@ err: return -ENOMEM; } -static void __net_exit __ip_vs_control_cleanup(struct net *net) +void __net_exit __ip_vs_control_cleanup(struct net *net) { struct netns_ipvs *ipvs = net_ipvs(net); @@ -3639,11 +3728,6 @@ static void __net_exit __ip_vs_control_cleanup(struct net *net) free_percpu(ipvs->tot_stats.cpustats); } -static struct pernet_operations ipvs_control_ops = { - .init = __ip_vs_control_init, - .exit = __ip_vs_control_cleanup, -}; - int __init ip_vs_control_init(void) { int idx; @@ -3657,33 +3741,32 @@ int __init ip_vs_control_init(void) INIT_LIST_HEAD(&ip_vs_svc_fwm_table[idx]); } - ret = register_pernet_subsys(&ipvs_control_ops); - if (ret) { - pr_err("cannot register namespace.\n"); - goto err; - } - smp_wmb(); /* Do we really need it now ? */ ret = nf_register_sockopt(&ip_vs_sockopts); if (ret) { pr_err("cannot register sockopt.\n"); - goto err_net; + goto err_sock; } ret = ip_vs_genl_register(); if (ret) { pr_err("cannot register Generic Netlink interface.\n"); - nf_unregister_sockopt(&ip_vs_sockopts); - goto err_net; + goto err_genl; } + ret = register_netdevice_notifier(&ip_vs_dst_notifier); + if (ret < 0) + goto err_notf; + LeaveFunction(2); return 0; -err_net: - unregister_pernet_subsys(&ipvs_control_ops); -err: +err_notf: + ip_vs_genl_unregister(); +err_genl: + nf_unregister_sockopt(&ip_vs_sockopts); +err_sock: return ret; } @@ -3691,7 +3774,6 @@ err: void ip_vs_control_cleanup(void) { EnterFunction(2); - unregister_pernet_subsys(&ipvs_control_ops); ip_vs_genl_unregister(); nf_unregister_sockopt(&ip_vs_sockopts); LeaveFunction(2); diff --git a/net/netfilter/ipvs/ip_vs_est.c b/net/netfilter/ipvs/ip_vs_est.c index 8c8766c..508cce9 100644 --- a/net/netfilter/ipvs/ip_vs_est.c +++ b/net/netfilter/ipvs/ip_vs_est.c @@ -192,7 +192,7 @@ void ip_vs_read_estimator(struct ip_vs_stats_user *dst, dst->outbps = (e->outbps + 0xF) >> 5; } -static int __net_init __ip_vs_estimator_init(struct net *net) +int __net_init __ip_vs_estimator_init(struct net *net) { struct netns_ipvs *ipvs = net_ipvs(net); @@ -203,24 +203,16 @@ static int __net_init __ip_vs_estimator_init(struct net *net) return 0; } -static void __net_exit __ip_vs_estimator_exit(struct net *net) +void __net_exit __ip_vs_estimator_cleanup(struct net *net) { del_timer_sync(&net_ipvs(net)->est_timer); } -static struct pernet_operations ip_vs_app_ops = { - .init = __ip_vs_estimator_init, - .exit = __ip_vs_estimator_exit, -}; int __init ip_vs_estimator_init(void) { - int rv; - - rv = register_pernet_subsys(&ip_vs_app_ops); - return rv; + return 0; } void ip_vs_estimator_cleanup(void) { - unregister_pernet_subsys(&ip_vs_app_ops); } diff --git a/net/netfilter/ipvs/ip_vs_proto.c b/net/netfilter/ipvs/ip_vs_proto.c index 17484a4..eb86028 100644 --- a/net/netfilter/ipvs/ip_vs_proto.c +++ b/net/netfilter/ipvs/ip_vs_proto.c @@ -316,7 +316,7 @@ ip_vs_tcpudp_debug_packet(int af, struct ip_vs_protocol *pp, /* * per network name-space init */ -static int __net_init __ip_vs_protocol_init(struct net *net) +int __net_init __ip_vs_protocol_init(struct net *net) { #ifdef CONFIG_IP_VS_PROTO_TCP register_ip_vs_proto_netns(net, &ip_vs_protocol_tcp); @@ -336,7 +336,7 @@ static int __net_init __ip_vs_protocol_init(struct net *net) return 0; } -static void __net_exit __ip_vs_protocol_cleanup(struct net *net) +void __net_exit __ip_vs_protocol_cleanup(struct net *net) { struct netns_ipvs *ipvs = net_ipvs(net); struct ip_vs_proto_data *pd; @@ -349,11 +349,6 @@ static void __net_exit __ip_vs_protocol_cleanup(struct net *net) } } -static struct pernet_operations ipvs_proto_ops = { - .init = __ip_vs_protocol_init, - .exit = __ip_vs_protocol_cleanup, -}; - int __init ip_vs_protocol_init(void) { char protocols[64]; @@ -382,7 +377,6 @@ int __init ip_vs_protocol_init(void) REGISTER_PROTOCOL(&ip_vs_protocol_esp); #endif pr_info("Registered protocols (%s)\n", &protocols[2]); - return register_pernet_subsys(&ipvs_proto_ops); return 0; } @@ -393,7 +387,6 @@ void ip_vs_protocol_cleanup(void) struct ip_vs_protocol *pp; int i; - unregister_pernet_subsys(&ipvs_proto_ops); /* unregister all the ipvs protocols */ for (i = 0; i < IP_VS_PROTO_TAB_SIZE; i++) { while ((pp = ip_vs_proto_table[i]) != NULL) diff --git a/net/netfilter/ipvs/ip_vs_sync.c b/net/netfilter/ipvs/ip_vs_sync.c index 0cce953..e292e5b 100644 --- a/net/netfilter/ipvs/ip_vs_sync.c +++ b/net/netfilter/ipvs/ip_vs_sync.c @@ -1663,7 +1663,7 @@ int stop_sync_thread(struct net *net, int state) /* * Initialize data struct for each netns */ -static int __net_init __ip_vs_sync_init(struct net *net) +int __net_init __ip_vs_sync_init(struct net *net) { struct netns_ipvs *ipvs = net_ipvs(net); @@ -1677,7 +1677,7 @@ static int __net_init __ip_vs_sync_init(struct net *net) return 0; } -static void __ip_vs_sync_cleanup(struct net *net) +void __ip_vs_sync_cleanup(struct net *net) { int retc; @@ -1690,18 +1690,11 @@ static void __ip_vs_sync_cleanup(struct net *net) pr_err("Failed to stop Backup Daemon\n"); } -static struct pernet_operations ipvs_sync_ops = { - .init = __ip_vs_sync_init, - .exit = __ip_vs_sync_cleanup, -}; - - int __init ip_vs_sync_init(void) { - return register_pernet_device(&ipvs_sync_ops); + return 0; } void ip_vs_sync_cleanup(void) { - unregister_pernet_device(&ipvs_sync_ops); } -- cgit v0.10.2 From 0e734419923bd8e599858f8fc196c7804bb85564 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Sun, 8 May 2011 15:28:03 -0700 Subject: ipv4: Use inet_csk_route_child_sock() in DCCP and TCP. Operation order is now transposed, we first create the child socket then we try to hook up the route. Signed-off-by: David S. Miller diff --git a/net/dccp/ipv4.c b/net/dccp/ipv4.c index 4ac1a72..46b15e9 100644 --- a/net/dccp/ipv4.c +++ b/net/dccp/ipv4.c @@ -396,15 +396,10 @@ struct sock *dccp_v4_request_recv_sock(struct sock *sk, struct sk_buff *skb, if (sk_acceptq_is_full(sk)) goto exit_overflow; - if (dst == NULL && (dst = inet_csk_route_req(sk, req)) == NULL) - goto exit; - newsk = dccp_create_openreq_child(sk, req, skb); if (newsk == NULL) goto exit_nonewsk; - sk_setup_caps(newsk, dst); - newinet = inet_sk(newsk); ireq = inet_rsk(req); newinet->inet_daddr = ireq->rmt_addr; @@ -416,12 +411,15 @@ struct sock *dccp_v4_request_recv_sock(struct sock *sk, struct sk_buff *skb, newinet->mc_ttl = ip_hdr(skb)->ttl; newinet->inet_id = jiffies; + if (dst == NULL && (dst = inet_csk_route_child_sock(sk, newsk, req)) == NULL) + goto put_and_exit; + + sk_setup_caps(newsk, dst); + dccp_sync_mss(newsk, dst_mtu(dst)); - if (__inet_inherit_port(sk, newsk) < 0) { - sock_put(newsk); - goto exit; - } + if (__inet_inherit_port(sk, newsk) < 0) + goto put_and_exit; __inet_hash_nolisten(newsk, NULL); return newsk; @@ -433,6 +431,9 @@ exit_nonewsk: exit: NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_LISTENDROPS); return NULL; +put_and_exit: + sock_put(newsk); + goto exit; } EXPORT_SYMBOL_GPL(dccp_v4_request_recv_sock); diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c index a712171..374de3c 100644 --- a/net/ipv4/tcp_ipv4.c +++ b/net/ipv4/tcp_ipv4.c @@ -1421,15 +1421,11 @@ struct sock *tcp_v4_syn_recv_sock(struct sock *sk, struct sk_buff *skb, if (sk_acceptq_is_full(sk)) goto exit_overflow; - if (!dst && (dst = inet_csk_route_req(sk, req)) == NULL) - goto exit; - newsk = tcp_create_openreq_child(sk, req, skb); if (!newsk) goto exit_nonewsk; newsk->sk_gso_type = SKB_GSO_TCPV4; - sk_setup_caps(newsk, dst); newtp = tcp_sk(newsk); newinet = inet_sk(newsk); @@ -1447,6 +1443,11 @@ struct sock *tcp_v4_syn_recv_sock(struct sock *sk, struct sk_buff *skb, inet_csk(newsk)->icsk_ext_hdr_len = inet_opt->opt.optlen; newinet->inet_id = newtp->write_seq ^ jiffies; + if (!dst && (dst = inet_csk_route_child_sock(sk, newsk, req)) == NULL) + goto put_and_exit; + + sk_setup_caps(newsk, dst); + tcp_mtup_init(newsk); tcp_sync_mss(newsk, dst_mtu(dst)); newtp->advmss = dst_metric_advmss(dst); @@ -1474,10 +1475,8 @@ struct sock *tcp_v4_syn_recv_sock(struct sock *sk, struct sk_buff *skb, } #endif - if (__inet_inherit_port(sk, newsk) < 0) { - sock_put(newsk); - goto exit; - } + if (__inet_inherit_port(sk, newsk) < 0) + goto put_and_exit; __inet_hash_nolisten(newsk, NULL); return newsk; @@ -1489,6 +1488,9 @@ exit_nonewsk: exit: NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_LISTENDROPS); return NULL; +put_and_exit: + sock_put(newsk); + goto exit; } EXPORT_SYMBOL(tcp_v4_syn_recv_sock); -- cgit v0.10.2 From d9d8da805dcb503ef8ee49918a94d49085060f23 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Fri, 6 May 2011 22:23:20 -0700 Subject: inet: Pass flowi to ->queue_xmit(). This allows us to acquire the exact route keying information from the protocol, however that might be managed. It handles all of the possibilities, from the simplest case of storing the key in inet->cork.fl to the more complex setup SCTP has where individual transports determine the flow. Signed-off-by: David S. Miller diff --git a/include/net/inet6_connection_sock.h b/include/net/inet6_connection_sock.h index ff01350..3207e58 100644 --- a/include/net/inet6_connection_sock.h +++ b/include/net/inet6_connection_sock.h @@ -41,5 +41,5 @@ extern void inet6_csk_reqsk_queue_hash_add(struct sock *sk, extern void inet6_csk_addr2sockaddr(struct sock *sk, struct sockaddr *uaddr); -extern int inet6_csk_xmit(struct sk_buff *skb); +extern int inet6_csk_xmit(struct sk_buff *skb, struct flowi *fl); #endif /* _INET6_CONNECTION_SOCK_H */ diff --git a/include/net/inet_connection_sock.h b/include/net/inet_connection_sock.h index 4367d91..96546ca 100644 --- a/include/net/inet_connection_sock.h +++ b/include/net/inet_connection_sock.h @@ -36,7 +36,7 @@ struct tcp_congestion_ops; * (i.e. things that depend on the address family) */ struct inet_connection_sock_af_ops { - int (*queue_xmit)(struct sk_buff *skb); + int (*queue_xmit)(struct sk_buff *skb, struct flowi *fl); void (*send_check)(struct sock *sk, struct sk_buff *skb); int (*rebuild_header)(struct sock *sk); int (*conn_request)(struct sock *sk, struct sk_buff *skb); diff --git a/include/net/ip.h b/include/net/ip.h index 095e392..acf8b78 100644 --- a/include/net/ip.h +++ b/include/net/ip.h @@ -104,7 +104,7 @@ extern int ip_do_nat(struct sk_buff *skb); extern void ip_send_check(struct iphdr *ip); extern int __ip_local_out(struct sk_buff *skb); extern int ip_local_out(struct sk_buff *skb); -extern int ip_queue_xmit(struct sk_buff *skb); +extern int ip_queue_xmit(struct sk_buff *skb, struct flowi *fl); extern void ip_init(void); extern int ip_append_data(struct sock *sk, int getfrag(void *from, char *to, int offset, int len, diff --git a/net/dccp/output.c b/net/dccp/output.c index 136d41c..fab108e 100644 --- a/net/dccp/output.c +++ b/net/dccp/output.c @@ -43,7 +43,7 @@ static void dccp_skb_entail(struct sock *sk, struct sk_buff *skb) static int dccp_transmit_skb(struct sock *sk, struct sk_buff *skb) { if (likely(skb != NULL)) { - const struct inet_sock *inet = inet_sk(sk); + struct inet_sock *inet = inet_sk(sk); const struct inet_connection_sock *icsk = inet_csk(sk); struct dccp_sock *dp = dccp_sk(sk); struct dccp_skb_cb *dcb = DCCP_SKB_CB(skb); @@ -136,7 +136,7 @@ static int dccp_transmit_skb(struct sock *sk, struct sk_buff *skb) DCCP_INC_STATS(DCCP_MIB_OUTSEGS); - err = icsk->icsk_af_ops->queue_xmit(skb); + err = icsk->icsk_af_ops->queue_xmit(skb, &inet->cork.fl); return net_xmit_eval(err); } return -ENOBUFS; diff --git a/net/ipv4/ip_output.c b/net/ipv4/ip_output.c index 4ba26d4..14ee1e4 100644 --- a/net/ipv4/ip_output.c +++ b/net/ipv4/ip_output.c @@ -312,7 +312,7 @@ int ip_output(struct sk_buff *skb) !(IPCB(skb)->flags & IPSKB_REROUTED)); } -int ip_queue_xmit(struct sk_buff *skb) +int ip_queue_xmit(struct sk_buff *skb, struct flowi *fl) { struct sock *sk = skb->sk; struct inet_sock *inet = inet_sk(sk); @@ -332,7 +332,7 @@ int ip_queue_xmit(struct sk_buff *skb) goto packet_routed; /* Make sure we can route this packet. */ - fl4 = &inet->cork.fl.u.ip4; + fl4 = &fl->u.ip4; rt = (struct rtable *)__sk_dst_check(sk, 0); if (rt == NULL) { __be32 daddr; diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c index 17388c7..882e0b0 100644 --- a/net/ipv4/tcp_output.c +++ b/net/ipv4/tcp_output.c @@ -899,7 +899,7 @@ static int tcp_transmit_skb(struct sock *sk, struct sk_buff *skb, int clone_it, TCP_ADD_STATS(sock_net(sk), TCP_MIB_OUTSEGS, tcp_skb_pcount(skb)); - err = icsk->icsk_af_ops->queue_xmit(skb); + err = icsk->icsk_af_ops->queue_xmit(skb, &inet->cork.fl); if (likely(err <= 0)) return err; diff --git a/net/ipv6/inet6_connection_sock.c b/net/ipv6/inet6_connection_sock.c index f2c5b0f..8a58e8c 100644 --- a/net/ipv6/inet6_connection_sock.c +++ b/net/ipv6/inet6_connection_sock.c @@ -203,7 +203,7 @@ struct dst_entry *__inet6_csk_dst_check(struct sock *sk, u32 cookie) return dst; } -int inet6_csk_xmit(struct sk_buff *skb) +int inet6_csk_xmit(struct sk_buff *skb, struct flowi *fl_unused) { struct sock *sk = skb->sk; struct inet_sock *inet = inet_sk(sk); diff --git a/net/l2tp/l2tp_core.c b/net/l2tp/l2tp_core.c index 7853029..9be095e 100644 --- a/net/l2tp/l2tp_core.c +++ b/net/l2tp/l2tp_core.c @@ -954,7 +954,7 @@ static int l2tp_build_l2tpv3_header(struct l2tp_session *session, void *buf) } static int l2tp_xmit_core(struct l2tp_session *session, struct sk_buff *skb, - size_t data_len) + struct flowi *fl, size_t data_len) { struct l2tp_tunnel *tunnel = session->tunnel; unsigned int len = skb->len; @@ -987,7 +987,7 @@ static int l2tp_xmit_core(struct l2tp_session *session, struct sk_buff *skb, /* Queue the packet to IP for output */ skb->local_df = 1; - error = ip_queue_xmit(skb); + error = ip_queue_xmit(skb, fl); /* Update stats */ if (error >= 0) { @@ -1028,6 +1028,7 @@ int l2tp_xmit_skb(struct l2tp_session *session, struct sk_buff *skb, int hdr_len int data_len = skb->len; struct l2tp_tunnel *tunnel = session->tunnel; struct sock *sk = tunnel->sock; + struct flowi *fl; struct udphdr *uh; struct inet_sock *inet; __wsum csum; @@ -1070,10 +1071,11 @@ int l2tp_xmit_skb(struct l2tp_session *session, struct sk_buff *skb, int hdr_len skb_dst_drop(skb); skb_dst_set(skb, dst_clone(__sk_dst_get(sk))); + inet = inet_sk(sk); + fl = &inet->cork.fl; switch (tunnel->encap) { case L2TP_ENCAPTYPE_UDP: /* Setup UDP header */ - inet = inet_sk(sk); __skb_push(skb, sizeof(*uh)); skb_reset_transport_header(skb); uh = udp_hdr(skb); @@ -1111,7 +1113,7 @@ int l2tp_xmit_skb(struct l2tp_session *session, struct sk_buff *skb, int hdr_len l2tp_skb_set_owner_w(skb, sk); - l2tp_xmit_core(session, skb, data_len); + l2tp_xmit_core(session, skb, fl, data_len); out_unlock: bh_unlock_sock(sk); diff --git a/net/l2tp/l2tp_ip.c b/net/l2tp/l2tp_ip.c index 1ca7489..f7fb09e 100644 --- a/net/l2tp/l2tp_ip.c +++ b/net/l2tp/l2tp_ip.c @@ -508,7 +508,7 @@ static int l2tp_ip_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *m skb_dst_set(skb, dst_clone(&rt->dst)); /* Queue the packet to IP for output */ - rc = ip_queue_xmit(skb); + rc = ip_queue_xmit(skb, &inet->cork.fl); error: /* Update stats */ diff --git a/net/sctp/protocol.c b/net/sctp/protocol.c index 69fbc55..847193b 100644 --- a/net/sctp/protocol.c +++ b/net/sctp/protocol.c @@ -855,7 +855,7 @@ static inline int sctp_v4_xmit(struct sk_buff *skb, IP_PMTUDISC_DO : IP_PMTUDISC_DONT; SCTP_INC_STATS(SCTP_MIB_OUTSCTPPACKS); - return ip_queue_xmit(skb); + return ip_queue_xmit(skb, &transport->fl); } static struct sctp_af sctp_af_inet; -- cgit v0.10.2 From ea4fc0d6193ff56fcef39b0d2210d402a7acb5f0 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Fri, 6 May 2011 22:30:20 -0700 Subject: ipv4: Don't use rt->rt_{src,dst} in ip_queue_xmit(). Now we can pick it out of the provided flow key. Signed-off-by: David S. Miller diff --git a/net/ipv4/ip_output.c b/net/ipv4/ip_output.c index 14ee1e4..b88ee5f 100644 --- a/net/ipv4/ip_output.c +++ b/net/ipv4/ip_output.c @@ -327,12 +327,12 @@ int ip_queue_xmit(struct sk_buff *skb, struct flowi *fl) */ rcu_read_lock(); inet_opt = rcu_dereference(inet->inet_opt); + fl4 = &fl->u.ip4; rt = skb_rtable(skb); if (rt != NULL) goto packet_routed; /* Make sure we can route this packet. */ - fl4 = &fl->u.ip4; rt = (struct rtable *)__sk_dst_check(sk, 0); if (rt == NULL) { __be32 daddr; @@ -360,7 +360,7 @@ int ip_queue_xmit(struct sk_buff *skb, struct flowi *fl) skb_dst_set_noref(skb, &rt->dst); packet_routed: - if (inet_opt && inet_opt->opt.is_strictroute && rt->rt_dst != rt->rt_gateway) + if (inet_opt && inet_opt->opt.is_strictroute && fl4->daddr != rt->rt_gateway) goto no_route; /* OK, we know where to send it, allocate and build IP header. */ @@ -374,8 +374,8 @@ packet_routed: iph->frag_off = 0; iph->ttl = ip_select_ttl(inet, &rt->dst); iph->protocol = sk->sk_protocol; - iph->saddr = rt->rt_src; - iph->daddr = rt->rt_dst; + iph->saddr = fl4->saddr; + iph->daddr = fl4->daddr; /* Transport layer set skb->h.foo itself. */ if (inet_opt && inet_opt->opt.optlen) { -- cgit v0.10.2 From f1c0a276ea1786213bda2313cd9034f3a23f2e77 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Fri, 6 May 2011 22:34:29 -0700 Subject: sctp: Don't use rt->rt_{src,dst} in sctp_v4_xmit() Now we can pick it out of the transport's flow key. Signed-off-by: David S. Miller diff --git a/net/sctp/protocol.c b/net/sctp/protocol.c index 847193b..acb2ee7 100644 --- a/net/sctp/protocol.c +++ b/net/sctp/protocol.c @@ -848,8 +848,8 @@ static inline int sctp_v4_xmit(struct sk_buff *skb, SCTP_DEBUG_PRINTK("%s: skb:%p, len:%d, src:%pI4, dst:%pI4\n", __func__, skb, skb->len, - &skb_rtable(skb)->rt_src, - &skb_rtable(skb)->rt_dst); + transport->fl.u.ip4.saddr, + transport->fl.u.ip4.daddr); inet->pmtudisc = transport->param_flags & SPP_PMTUD_ENABLE ? IP_PMTUDISC_DO : IP_PMTUDISC_DONT; -- cgit v0.10.2 From c5216cc70fa769e5a51837f2cf07c4a0aa734fcf Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Fri, 6 May 2011 22:36:30 -0700 Subject: tcp: Use cork flow info instead of rt->rt_dst in tcp_v4_get_peer() Signed-off-by: David S. Miller diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c index 374de3c..2b65503 100644 --- a/net/ipv4/tcp_ipv4.c +++ b/net/ipv4/tcp_ipv4.c @@ -1773,7 +1773,8 @@ struct inet_peer *tcp_v4_get_peer(struct sock *sk, bool *release_it) struct inet_sock *inet = inet_sk(sk); struct inet_peer *peer; - if (!rt || rt->rt_dst != inet->inet_daddr) { + if (!rt || + inet->cork.fl.u.ip4.daddr != inet->inet_daddr) { peer = inet_getpeer_v4(inet->inet_daddr, 1); *release_it = true; } else { -- cgit v0.10.2 From 57cc71bc3c0cf18bfd1b7bc8cd0eb6c303da24c5 Mon Sep 17 00:00:00 2001 From: Yaniv Rosner Date: Mon, 2 May 2011 21:30:08 +0000 Subject: ethtool: Add 20G bit definitions Add 20G supported and advertising bit definitions. 20G will be supported with the 57840 chips. Signed-off-by: Yaniv Rosner Signed-off-by: Eilon Greenstein ------ include/linux/ethtool.h | 4 ++++ 1 files changed, 4 insertions(+), 0 deletions(-) Signed-off-by: David S. Miller diff --git a/include/linux/ethtool.h b/include/linux/ethtool.h index d659fdc..bd0b50b 100644 --- a/include/linux/ethtool.h +++ b/include/linux/ethtool.h @@ -1025,6 +1025,8 @@ struct ethtool_ops { #define SUPPORTED_10000baseKX4_Full (1 << 18) #define SUPPORTED_10000baseKR_Full (1 << 19) #define SUPPORTED_10000baseR_FEC (1 << 20) +#define SUPPORTED_20000baseMLD2_Full (1 << 21) +#define SUPPORTED_20000baseKR2_Full (1 << 22) /* Indicates what features are advertised by the interface. */ #define ADVERTISED_10baseT_Half (1 << 0) @@ -1048,6 +1050,8 @@ struct ethtool_ops { #define ADVERTISED_10000baseKX4_Full (1 << 18) #define ADVERTISED_10000baseKR_Full (1 << 19) #define ADVERTISED_10000baseR_FEC (1 << 20) +#define ADVERTISED_20000baseMLD2_Full (1 << 21) +#define ADVERTISED_20000baseKR2_Full (1 << 22) /* The following are all involved in forcing a particular link * mode for the device for setting things. When getting the -- cgit v0.10.2 From 7a7b94ad8ce3e24d4dd97b45583911e0f03aecd6 Mon Sep 17 00:00:00 2001 From: Jimmy Rentz Date: Sun, 17 Apr 2011 16:15:09 -0400 Subject: drm/nouveau: Fix a crash at card takedown for NV40 and older cards NV40 and older cards (pre NV50) reserve a vram bo for the vga memory at card init. This bo is then freed at card shutdown. The problem is that the ttm bo vram manager was already freed. So a crash occurs when the vga bo is freed. The fix is to free the vga bo prior to freeing the ttm bo vram manager. There might be other solutions but this seemed the simplest to me. Signed-off-by: Jimmy Rentz Signed-off-by: Ben Skeggs diff --git a/drivers/gpu/drm/nouveau/nouveau_mem.c b/drivers/gpu/drm/nouveau/nouveau_mem.c index 5045f8b..c3e953b 100644 --- a/drivers/gpu/drm/nouveau/nouveau_mem.c +++ b/drivers/gpu/drm/nouveau/nouveau_mem.c @@ -152,8 +152,6 @@ nouveau_mem_vram_fini(struct drm_device *dev) { struct drm_nouveau_private *dev_priv = dev->dev_private; - nouveau_bo_ref(NULL, &dev_priv->vga_ram); - ttm_bo_device_release(&dev_priv->ttm.bdev); nouveau_ttm_global_release(dev_priv); diff --git a/drivers/gpu/drm/nouveau/nouveau_state.c b/drivers/gpu/drm/nouveau/nouveau_state.c index a30adec..915fbce 100644 --- a/drivers/gpu/drm/nouveau/nouveau_state.c +++ b/drivers/gpu/drm/nouveau/nouveau_state.c @@ -768,6 +768,11 @@ static void nouveau_card_takedown(struct drm_device *dev) engine->mc.takedown(dev); engine->display.late_takedown(dev); + if (dev_priv->vga_ram) { + nouveau_bo_unpin(dev_priv->vga_ram); + nouveau_bo_ref(NULL, &dev_priv->vga_ram); + } + mutex_lock(&dev->struct_mutex); ttm_bo_clean_mm(&dev_priv->ttm.bdev, TTM_PL_VRAM); ttm_bo_clean_mm(&dev_priv->ttm.bdev, TTM_PL_TT); -- cgit v0.10.2 From 9c412942a0bb19ba18f7bd939d42eff1e132a901 Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Tue, 3 May 2011 07:49:25 +0000 Subject: ipheth: Properly distinguish length and alignment in URBs and skbs The USB protocol this driver implements appears to require 2 bytes of padding in front of each received packet. This used to be equal to the value of NET_IP_ALIGN on x86, so the driver abused that constant and mostly worked, but this is no longer the case. The driver also mixed up the URB and packet lengths, resulting in 2 bytes of junk at the end of the skb. Introduce a private constant for the 2 bytes of padding; fix this confusion and check for the under-length case. Signed-off-by: Ben Hutchings Signed-off-by: David S. Miller diff --git a/drivers/net/usb/ipheth.c b/drivers/net/usb/ipheth.c index 7d42f9a..81126ff 100644 --- a/drivers/net/usb/ipheth.c +++ b/drivers/net/usb/ipheth.c @@ -65,6 +65,7 @@ #define IPHETH_USBINTF_PROTO 1 #define IPHETH_BUF_SIZE 1516 +#define IPHETH_IP_ALIGN 2 /* padding at front of URB */ #define IPHETH_TX_TIMEOUT (5 * HZ) #define IPHETH_INTFNUM 2 @@ -202,18 +203,21 @@ static void ipheth_rcvbulk_callback(struct urb *urb) return; } - len = urb->actual_length; - buf = urb->transfer_buffer; + if (urb->actual_length <= IPHETH_IP_ALIGN) { + dev->net->stats.rx_length_errors++; + return; + } + len = urb->actual_length - IPHETH_IP_ALIGN; + buf = urb->transfer_buffer + IPHETH_IP_ALIGN; - skb = dev_alloc_skb(NET_IP_ALIGN + len); + skb = dev_alloc_skb(len); if (!skb) { err("%s: dev_alloc_skb: -ENOMEM", __func__); dev->net->stats.rx_dropped++; return; } - skb_reserve(skb, NET_IP_ALIGN); - memcpy(skb_put(skb, len), buf + NET_IP_ALIGN, len - NET_IP_ALIGN); + memcpy(skb_put(skb, len), buf, len); skb->dev = dev->net; skb->protocol = eth_type_trans(skb, dev->net); -- cgit v0.10.2 From 47a0200d535f08ac8f784a709c48995ca0b10288 Mon Sep 17 00:00:00 2001 From: Alexey Dobriyan Date: Tue, 3 May 2011 11:23:40 +0000 Subject: pktgen: use %pI6c for printing IPv6 addresses I don't know why %pI6 doesn't compress, but the format specifier is kernel-standard, so use it. Signed-off-by: Alexey Dobriyan Signed-off-by: David S. Miller diff --git a/net/core/pktgen.c b/net/core/pktgen.c index ff79d94..d41d88b 100644 --- a/net/core/pktgen.c +++ b/net/core/pktgen.c @@ -449,7 +449,6 @@ static void pktgen_stop(struct pktgen_thread *t); static void pktgen_clear_counters(struct pktgen_dev *pkt_dev); static unsigned int scan_ip6(const char *s, char ip[16]); -static unsigned int fmt_ip6(char *s, const char ip[16]); /* Module parameters, defaults. */ static int pg_count_d __read_mostly = 1000; @@ -556,21 +555,13 @@ static int pktgen_if_show(struct seq_file *seq, void *v) pkt_dev->skb_priority); if (pkt_dev->flags & F_IPV6) { - char b1[128], b2[128], b3[128]; - fmt_ip6(b1, pkt_dev->in6_saddr.s6_addr); - fmt_ip6(b2, pkt_dev->min_in6_saddr.s6_addr); - fmt_ip6(b3, pkt_dev->max_in6_saddr.s6_addr); seq_printf(seq, - " saddr: %s min_saddr: %s max_saddr: %s\n", b1, - b2, b3); - - fmt_ip6(b1, pkt_dev->in6_daddr.s6_addr); - fmt_ip6(b2, pkt_dev->min_in6_daddr.s6_addr); - fmt_ip6(b3, pkt_dev->max_in6_daddr.s6_addr); - seq_printf(seq, - " daddr: %s min_daddr: %s max_daddr: %s\n", b1, - b2, b3); - + " saddr: %pI6c min_saddr: %pI6c max_saddr: %pI6c\n" + " daddr: %pI6c min_daddr: %pI6c max_daddr: %pI6c\n", + &pkt_dev->in6_saddr, + &pkt_dev->min_in6_saddr, &pkt_dev->max_in6_saddr, + &pkt_dev->in6_daddr, + &pkt_dev->min_in6_daddr, &pkt_dev->max_in6_daddr); } else { seq_printf(seq, " dst_min: %s dst_max: %s\n", @@ -706,10 +697,9 @@ static int pktgen_if_show(struct seq_file *seq, void *v) pkt_dev->cur_src_mac_offset); if (pkt_dev->flags & F_IPV6) { - char b1[128], b2[128]; - fmt_ip6(b1, pkt_dev->cur_in6_daddr.s6_addr); - fmt_ip6(b2, pkt_dev->cur_in6_saddr.s6_addr); - seq_printf(seq, " cur_saddr: %s cur_daddr: %s\n", b2, b1); + seq_printf(seq, " cur_saddr: %pI6c cur_daddr: %pI6c\n", + &pkt_dev->cur_in6_saddr, + &pkt_dev->cur_in6_daddr); } else seq_printf(seq, " cur_saddr: 0x%x cur_daddr: 0x%x\n", pkt_dev->cur_saddr, pkt_dev->cur_daddr); @@ -1309,7 +1299,7 @@ static ssize_t pktgen_if_write(struct file *file, buf[len] = 0; scan_ip6(buf, pkt_dev->in6_daddr.s6_addr); - fmt_ip6(buf, pkt_dev->in6_daddr.s6_addr); + snprintf(buf, sizeof(buf), "%pI6c", &pkt_dev->in6_daddr); ipv6_addr_copy(&pkt_dev->cur_in6_daddr, &pkt_dev->in6_daddr); @@ -1332,7 +1322,7 @@ static ssize_t pktgen_if_write(struct file *file, buf[len] = 0; scan_ip6(buf, pkt_dev->min_in6_daddr.s6_addr); - fmt_ip6(buf, pkt_dev->min_in6_daddr.s6_addr); + snprintf(buf, sizeof(buf), "%pI6c", &pkt_dev->min_in6_daddr); ipv6_addr_copy(&pkt_dev->cur_in6_daddr, &pkt_dev->min_in6_daddr); @@ -1355,7 +1345,7 @@ static ssize_t pktgen_if_write(struct file *file, buf[len] = 0; scan_ip6(buf, pkt_dev->max_in6_daddr.s6_addr); - fmt_ip6(buf, pkt_dev->max_in6_daddr.s6_addr); + snprintf(buf, sizeof(buf), "%pI6c", &pkt_dev->max_in6_daddr); if (debug) printk(KERN_DEBUG "pktgen: dst6_max set to: %s\n", buf); @@ -1376,7 +1366,7 @@ static ssize_t pktgen_if_write(struct file *file, buf[len] = 0; scan_ip6(buf, pkt_dev->in6_saddr.s6_addr); - fmt_ip6(buf, pkt_dev->in6_saddr.s6_addr); + snprintf(buf, sizeof(buf), "%pI6c", &pkt_dev->in6_saddr); ipv6_addr_copy(&pkt_dev->cur_in6_saddr, &pkt_dev->in6_saddr); @@ -2898,79 +2888,6 @@ static unsigned int scan_ip6(const char *s, char ip[16]) return len; } -static char tohex(char hexdigit) -{ - return hexdigit > 9 ? hexdigit + 'a' - 10 : hexdigit + '0'; -} - -static int fmt_xlong(char *s, unsigned int i) -{ - char *bak = s; - *s = tohex((i >> 12) & 0xf); - if (s != bak || *s != '0') - ++s; - *s = tohex((i >> 8) & 0xf); - if (s != bak || *s != '0') - ++s; - *s = tohex((i >> 4) & 0xf); - if (s != bak || *s != '0') - ++s; - *s = tohex(i & 0xf); - return s - bak + 1; -} - -static unsigned int fmt_ip6(char *s, const char ip[16]) -{ - unsigned int len; - unsigned int i; - unsigned int temp; - unsigned int compressing; - int j; - - len = 0; - compressing = 0; - for (j = 0; j < 16; j += 2) { - -#ifdef V4MAPPEDPREFIX - if (j == 12 && !memcmp(ip, V4mappedprefix, 12)) { - inet_ntoa_r(*(struct in_addr *)(ip + 12), s); - temp = strlen(s); - return len + temp; - } -#endif - temp = ((unsigned long)(unsigned char)ip[j] << 8) + - (unsigned long)(unsigned char)ip[j + 1]; - if (temp == 0) { - if (!compressing) { - compressing = 1; - if (j == 0) { - *s++ = ':'; - ++len; - } - } - } else { - if (compressing) { - compressing = 0; - *s++ = ':'; - ++len; - } - i = fmt_xlong(s, temp); - len += i; - s += i; - if (j < 14) { - *s++ = ':'; - ++len; - } - } - } - if (compressing) { - *s++ = ':'; - ++len; - } - *s = 0; - return len; -} - static struct sk_buff *fill_packet_ipv6(struct net_device *odev, struct pktgen_dev *pkt_dev) { -- cgit v0.10.2 From b9f47a3aaeabdce3b42829bbb27765fa340f76ba Mon Sep 17 00:00:00 2001 From: stephen hemminger Date: Wed, 4 May 2011 10:04:56 +0000 Subject: tcp_cubic: limit delayed_ack ratio to prevent divide error TCP Cubic keeps a metric that estimates the amount of delayed acknowledgements to use in adjusting the window. If an abnormally large number of packets are acknowledged at once, then the update could wrap and reach zero. This kind of ACK could only happen when there was a large window and huge number of ACK's were lost. This patch limits the value of delayed ack ratio. The choice of 32 is just a conservative value since normally it should be range of 1 to 4 packets. Signed-off-by: Stephen Hemminger Signed-off-by: David S. Miller diff --git a/net/ipv4/tcp_cubic.c b/net/ipv4/tcp_cubic.c index 34340c9..f376b05 100644 --- a/net/ipv4/tcp_cubic.c +++ b/net/ipv4/tcp_cubic.c @@ -93,6 +93,7 @@ struct bictcp { u32 ack_cnt; /* number of acks */ u32 tcp_cwnd; /* estimated tcp cwnd */ #define ACK_RATIO_SHIFT 4 +#define ACK_RATIO_LIMIT (32u << ACK_RATIO_SHIFT) u16 delayed_ack; /* estimate the ratio of Packets/ACKs << 4 */ u8 sample_cnt; /* number of samples to decide curr_rtt */ u8 found; /* the exit point is found? */ @@ -398,8 +399,12 @@ static void bictcp_acked(struct sock *sk, u32 cnt, s32 rtt_us) u32 delay; if (icsk->icsk_ca_state == TCP_CA_Open) { - cnt -= ca->delayed_ack >> ACK_RATIO_SHIFT; - ca->delayed_ack += cnt; + u32 ratio = ca->delayed_ack; + + ratio -= ca->delayed_ack >> ACK_RATIO_SHIFT; + ratio += cnt; + + ca->delayed_ack = min(ratio, ACK_RATIO_LIMIT); } /* Some calls are for duplicates without timetamps */ -- cgit v0.10.2 From eed2a12f1ed9aabf0676f4d0db34aad51976c5c6 Mon Sep 17 00:00:00 2001 From: Mahesh Bandewar Date: Wed, 4 May 2011 15:30:11 +0000 Subject: net: Allow ethtool to set interface in loopback mode. This patch enables ethtool to set the loopback mode on a given interface. By configuring the interface in loopback mode in conjunction with a policy route / rule, a userland application can stress the egress / ingress path exposing the flows of the change in progress and potentially help developer(s) understand the impact of those changes without even sending a packet out on the network. Following set of commands illustrates one such example - a) ip -4 addr add 192.168.1.1/24 dev eth1 b) ip -4 rule add from all iif eth1 lookup 250 c) ip -4 route add local 0/0 dev lo proto kernel scope host table 250 d) arp -Ds 192.168.1.100 eth1 e) arp -Ds 192.168.1.200 eth1 f) sysctl -w net.ipv4.ip_nonlocal_bind=1 g) sysctl -w net.ipv4.conf.all.accept_local=1 # Assuming that the machine has 8 cores h) taskset 000f netserver -L 192.168.1.200 i) taskset 00f0 netperf -t TCP_CRR -L 192.168.1.100 -H 192.168.1.200 -l 30 Signed-off-by: Mahesh Bandewar Acked-by: Ben Hutchings Signed-off-by: David S. Miller diff --git a/drivers/net/loopback.c b/drivers/net/loopback.c index d70fb76..4ce9e5f 100644 --- a/drivers/net/loopback.c +++ b/drivers/net/loopback.c @@ -174,7 +174,8 @@ static void loopback_setup(struct net_device *dev) | NETIF_F_HIGHDMA | NETIF_F_LLTX | NETIF_F_NETNS_LOCAL - | NETIF_F_VLAN_CHALLENGED; + | NETIF_F_VLAN_CHALLENGED + | NETIF_F_LOOPBACK; dev->ethtool_ops = &loopback_ethtool_ops; dev->header_ops = ð_header_ops; dev->netdev_ops = &loopback_ops; diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index d5de66a..e7244ed 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -1067,6 +1067,7 @@ struct net_device { #define NETIF_F_RXHASH (1 << 28) /* Receive hashing offload */ #define NETIF_F_RXCSUM (1 << 29) /* Receive checksumming offload */ #define NETIF_F_NOCACHE_COPY (1 << 30) /* Use no-cache copyfromuser */ +#define NETIF_F_LOOPBACK (1 << 31) /* Enable loopback */ /* Segmentation offload features */ #define NETIF_F_GSO_SHIFT 16 @@ -1082,7 +1083,7 @@ struct net_device { /* = all defined minus driver/device-class-related */ #define NETIF_F_NEVER_CHANGE (NETIF_F_VLAN_CHALLENGED | \ NETIF_F_LLTX | NETIF_F_NETNS_LOCAL) -#define NETIF_F_ETHTOOL_BITS (0x7f3fffff & ~NETIF_F_NEVER_CHANGE) +#define NETIF_F_ETHTOOL_BITS (0xff3fffff & ~NETIF_F_NEVER_CHANGE) /* List of features with software fallbacks. */ #define NETIF_F_GSO_SOFTWARE (NETIF_F_TSO | NETIF_F_TSO_ECN | \ diff --git a/net/core/ethtool.c b/net/core/ethtool.c index 927819d..b6f4058 100644 --- a/net/core/ethtool.c +++ b/net/core/ethtool.c @@ -362,7 +362,7 @@ static const char netdev_features_strings[ETHTOOL_DEV_FEATURE_WORDS * 32][ETH_GS /* NETIF_F_RXHASH */ "rx-hashing", /* NETIF_F_RXCSUM */ "rx-checksum", /* NETIF_F_NOCACHE_COPY */ "tx-nocache-copy" - "", + /* NETIF_F_LOOPBACK */ "loopback", }; static int __ethtool_get_sset_count(struct net_device *dev, int sset) -- cgit v0.10.2 From 58e73811c85d0c0e74b8d300547bbc9abaf40a38 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Fri, 6 May 2011 01:42:49 -0400 Subject: drm/radeon/kms: ATPX switcheroo fixes When we switch the display mux, also switch the i2c mux. Also use the start and finish methods to let the sbios know that the switch is happening. Should fix: https://bugs.freedesktop.org/show_bug.cgi?id=35398 Signed-off-by: Alex Deucher Signed-off-by: Dave Airlie diff --git a/drivers/gpu/drm/radeon/radeon_atpx_handler.c b/drivers/gpu/drm/radeon/radeon_atpx_handler.c index ed5dfe5..9d95792 100644 --- a/drivers/gpu/drm/radeon/radeon_atpx_handler.c +++ b/drivers/gpu/drm/radeon/radeon_atpx_handler.c @@ -15,6 +15,9 @@ #define ATPX_VERSION 0 #define ATPX_GPU_PWR 2 #define ATPX_MUX_SELECT 3 +#define ATPX_I2C_MUX_SELECT 4 +#define ATPX_SWITCH_START 5 +#define ATPX_SWITCH_END 6 #define ATPX_INTEGRATED 0 #define ATPX_DISCRETE 1 @@ -149,13 +152,35 @@ static int radeon_atpx_switch_mux(acpi_handle handle, int mux_id) return radeon_atpx_execute(handle, ATPX_MUX_SELECT, mux_id); } +static int radeon_atpx_switch_i2c_mux(acpi_handle handle, int mux_id) +{ + return radeon_atpx_execute(handle, ATPX_I2C_MUX_SELECT, mux_id); +} + +static int radeon_atpx_switch_start(acpi_handle handle, int gpu_id) +{ + return radeon_atpx_execute(handle, ATPX_SWITCH_START, gpu_id); +} + +static int radeon_atpx_switch_end(acpi_handle handle, int gpu_id) +{ + return radeon_atpx_execute(handle, ATPX_SWITCH_END, gpu_id); +} static int radeon_atpx_switchto(enum vga_switcheroo_client_id id) { + int gpu_id; + if (id == VGA_SWITCHEROO_IGD) - radeon_atpx_switch_mux(radeon_atpx_priv.atpx_handle, 0); + gpu_id = ATPX_INTEGRATED; else - radeon_atpx_switch_mux(radeon_atpx_priv.atpx_handle, 1); + gpu_id = ATPX_DISCRETE; + + radeon_atpx_switch_start(radeon_atpx_priv.atpx_handle, gpu_id); + radeon_atpx_switch_mux(radeon_atpx_priv.atpx_handle, gpu_id); + radeon_atpx_switch_i2c_mux(radeon_atpx_priv.atpx_handle, gpu_id); + radeon_atpx_switch_end(radeon_atpx_priv.atpx_handle, gpu_id); + return 0; } -- cgit v0.10.2 From 2bbd4492552867053b5a618a2474297e2b1c355d Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Fri, 6 May 2011 23:47:53 +0200 Subject: drm: mm: fix debug output The looping helper didn't do anything due to a superficial semicolon. Furthermore one of the two dump functions suffered from copy&paste fail. While staring at the code I've also noticed that the replace helper (currently unused) is a bit broken. Signed-off-by: Daniel Vetter Signed-off-by: Dave Airlie diff --git a/drivers/gpu/drm/drm_mm.c b/drivers/gpu/drm/drm_mm.c index 5d00b0f..959186c 100644 --- a/drivers/gpu/drm/drm_mm.c +++ b/drivers/gpu/drm/drm_mm.c @@ -431,7 +431,7 @@ EXPORT_SYMBOL(drm_mm_search_free_in_range); void drm_mm_replace_node(struct drm_mm_node *old, struct drm_mm_node *new) { list_replace(&old->node_list, &new->node_list); - list_replace(&old->node_list, &new->hole_stack); + list_replace(&old->hole_stack, &new->hole_stack); new->hole_follows = old->hole_follows; new->mm = old->mm; new->start = old->start; @@ -699,8 +699,8 @@ int drm_mm_dump_table(struct seq_file *m, struct drm_mm *mm) entry->size); total_used += entry->size; if (entry->hole_follows) { - hole_start = drm_mm_hole_node_start(&mm->head_node); - hole_end = drm_mm_hole_node_end(&mm->head_node); + hole_start = drm_mm_hole_node_start(entry); + hole_end = drm_mm_hole_node_end(entry); hole_size = hole_end - hole_start; seq_printf(m, "0x%08lx-0x%08lx: 0x%08lx: free\n", hole_start, hole_end, hole_size); diff --git a/include/drm/drm_mm.h b/include/drm/drm_mm.h index c2f93a8..564b14a 100644 --- a/include/drm/drm_mm.h +++ b/include/drm/drm_mm.h @@ -86,7 +86,7 @@ static inline bool drm_mm_initialized(struct drm_mm *mm) } #define drm_mm_for_each_node(entry, mm) list_for_each_entry(entry, \ &(mm)->head_node.node_list, \ - node_list); + node_list) #define drm_mm_for_each_scanned_node_reverse(entry, n, mm) \ for (entry = (mm)->prev_scanned_node, \ next = entry ? list_entry(entry->node_list.next, \ -- cgit v0.10.2 From 45e5f6a2ee6aac20e393d44f8a6762104426c81b Mon Sep 17 00:00:00 2001 From: Ilija Hadzic Date: Wed, 4 May 2011 20:15:03 -0400 Subject: drm/radeon: fix order of doing things in radeon_crtc_cursor_set if object pin or object lookup in radeon_cursor_set fail, the function could leave inconsistent mouse width and hight values in radeon_crtc fixed by moving cursor width and height assignments after all checks have passed Signed-off-by: Ilija Hadzic Reviewed-by: Alex Deucher Signed-off-by: Dave Airlie diff --git a/drivers/gpu/drm/radeon/radeon_cursor.c b/drivers/gpu/drm/radeon/radeon_cursor.c index bdf2fa1..3189a7e 100644 --- a/drivers/gpu/drm/radeon/radeon_cursor.c +++ b/drivers/gpu/drm/radeon/radeon_cursor.c @@ -167,9 +167,6 @@ int radeon_crtc_cursor_set(struct drm_crtc *crtc, return -EINVAL; } - radeon_crtc->cursor_width = width; - radeon_crtc->cursor_height = height; - obj = drm_gem_object_lookup(crtc->dev, file_priv, handle); if (!obj) { DRM_ERROR("Cannot find cursor object %x for crtc %d\n", handle, radeon_crtc->crtc_id); @@ -180,6 +177,9 @@ int radeon_crtc_cursor_set(struct drm_crtc *crtc, if (ret) goto fail; + radeon_crtc->cursor_width = width; + radeon_crtc->cursor_height = height; + radeon_lock_cursor(crtc, true); /* XXX only 27 bit offset for legacy cursor */ radeon_set_cursor(crtc, obj, gpu_addr); -- cgit v0.10.2 From 4f87af46107499415afd238be104587b5a9d7ac3 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Wed, 4 May 2011 11:41:47 -0400 Subject: drm/radeon/kms: add pci id to acer travelmate quirk for 5730 Fixes: https://bugzilla.kernel.org/show_bug.cgi?id=34082 Reported by: Sampo Laaksonen Signed-off-by: Alex Deucher Cc: stable@kernel.org Signed-off-by: Dave Airlie diff --git a/drivers/gpu/drm/radeon/radeon_atombios.c b/drivers/gpu/drm/radeon/radeon_atombios.c index f116516..dd881d0 100644 --- a/drivers/gpu/drm/radeon/radeon_atombios.c +++ b/drivers/gpu/drm/radeon/radeon_atombios.c @@ -431,7 +431,7 @@ static bool radeon_atom_apply_quirks(struct drm_device *dev, } } - /* Acer laptop (Acer TravelMate 5730G) has an HDMI port + /* Acer laptop (Acer TravelMate 5730/5730G) has an HDMI port * on the laptop and a DVI port on the docking station and * both share the same encoder, hpd pin, and ddc line. * So while the bios table is technically correct, @@ -440,7 +440,7 @@ static bool radeon_atom_apply_quirks(struct drm_device *dev, * with different crtcs which isn't possible on the hardware * side and leaves no crtcs for LVDS or VGA. */ - if ((dev->pdev->device == 0x95c4) && + if (((dev->pdev->device == 0x95c4) || (dev->pdev->device == 0x9591)) && (dev->pdev->subsystem_vendor == 0x1025) && (dev->pdev->subsystem_device == 0x013c)) { if ((*connector_type == DRM_MODE_CONNECTOR_DVII) && -- cgit v0.10.2 From e474995f290ff7bc236b549aa9a89ae445ee5b1b Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Sun, 8 May 2011 16:38:45 -0700 Subject: udp: Use flow key information instead of rt->rt_{src,dst} We have two cases. Either the socket is in TCP_ESTABLISHED state and connect() filled in the inet socket cork flow, or we looked up the route here and used an on-stack flow. Track which one it was, and use it to obtain src/dst addrs. Signed-off-by: David S. Miller diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c index 544f435..ba9f137 100644 --- a/net/ipv4/udp.c +++ b/net/ipv4/udp.c @@ -791,6 +791,7 @@ int udp_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, { struct inet_sock *inet = inet_sk(sk); struct udp_sock *up = udp_sk(sk); + struct flowi4 fl4_stack; struct flowi4 *fl4; int ulen = len; struct ipcm_cookie ipc; @@ -919,17 +920,18 @@ int udp_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, if (connected) rt = (struct rtable *)sk_dst_check(sk, 0); + fl4 = &inet->cork.fl.u.ip4; if (rt == NULL) { - struct flowi4 fl4; struct net *net = sock_net(sk); - flowi4_init_output(&fl4, ipc.oif, sk->sk_mark, tos, + fl4 = &fl4_stack; + flowi4_init_output(fl4, ipc.oif, sk->sk_mark, tos, RT_SCOPE_UNIVERSE, sk->sk_protocol, inet_sk_flowi_flags(sk)|FLOWI_FLAG_CAN_SLEEP, faddr, saddr, dport, inet->inet_sport); - security_sk_classify_flow(sk, flowi4_to_flowi(&fl4)); - rt = ip_route_output_flow(net, &fl4, sk); + security_sk_classify_flow(sk, flowi4_to_flowi(fl4)); + rt = ip_route_output_flow(net, fl4, sk); if (IS_ERR(rt)) { err = PTR_ERR(rt); rt = NULL; @@ -950,9 +952,9 @@ int udp_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, goto do_confirm; back_from_confirm: - saddr = rt->rt_src; + saddr = fl4->saddr; if (!ipc.addr) - daddr = ipc.addr = rt->rt_dst; + daddr = ipc.addr = fl4->daddr; /* Lockless fast path for the non-corking case. */ if (!corkreq) { -- cgit v0.10.2 From 77968b78242ee25e2a4d759f0fca8dd52df6d479 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Sun, 8 May 2011 17:12:19 -0700 Subject: ipv4: Pass flow keys down into datagram packet building engine. This way ip_output.c no longer needs rt->rt_{src,dst}. We already have these keys sitting, ready and waiting, on the stack or in a socket structure. Signed-off-by: David S. Miller diff --git a/include/net/ip.h b/include/net/ip.h index acf8b78..a425379 100644 --- a/include/net/ip.h +++ b/include/net/ip.h @@ -117,12 +117,14 @@ extern int ip_generic_getfrag(void *from, char *to, int offset, int len, int od extern ssize_t ip_append_page(struct sock *sk, struct page *page, int offset, size_t size, int flags); extern struct sk_buff *__ip_make_skb(struct sock *sk, + struct flowi4 *fl4, struct sk_buff_head *queue, struct inet_cork *cork); extern int ip_send_skb(struct sk_buff *skb); -extern int ip_push_pending_frames(struct sock *sk); +extern int ip_push_pending_frames(struct sock *sk, struct flowi4 *fl4); extern void ip_flush_pending_frames(struct sock *sk); extern struct sk_buff *ip_make_skb(struct sock *sk, + struct flowi4 *fl4, int getfrag(void *from, char *to, int offset, int len, int odd, struct sk_buff *skb), void *from, int length, int transhdrlen, @@ -130,9 +132,9 @@ extern struct sk_buff *ip_make_skb(struct sock *sk, struct rtable **rtp, unsigned int flags); -static inline struct sk_buff *ip_finish_skb(struct sock *sk) +static inline struct sk_buff *ip_finish_skb(struct sock *sk, struct flowi4 *fl4) { - return __ip_make_skb(sk, &sk->sk_write_queue, &inet_sk(sk)->cork.base); + return __ip_make_skb(sk, fl4, &sk->sk_write_queue, &inet_sk(sk)->cork.base); } /* datagram.c */ diff --git a/net/ipv4/icmp.c b/net/ipv4/icmp.c index cfeca3c..be5cc8d 100644 --- a/net/ipv4/icmp.c +++ b/net/ipv4/icmp.c @@ -290,6 +290,7 @@ static int icmp_glue_bits(void *from, char *to, int offset, int len, int odd, } static void icmp_push_reply(struct icmp_bxm *icmp_param, + struct flowi4 *fl4, struct ipcm_cookie *ipc, struct rtable **rt) { struct sock *sk; @@ -315,7 +316,7 @@ static void icmp_push_reply(struct icmp_bxm *icmp_param, icmp_param->head_len, csum); icmph->checksum = csum_fold(csum); skb->ip_summed = CHECKSUM_NONE; - ip_push_pending_frames(sk); + ip_push_pending_frames(sk, fl4); } } @@ -328,6 +329,7 @@ static void icmp_reply(struct icmp_bxm *icmp_param, struct sk_buff *skb) struct ipcm_cookie ipc; struct rtable *rt = skb_rtable(skb); struct net *net = dev_net(rt->dst.dev); + struct flowi4 fl4; struct sock *sk; struct inet_sock *inet; __be32 daddr; @@ -351,57 +353,52 @@ static void icmp_reply(struct icmp_bxm *icmp_param, struct sk_buff *skb) if (ipc.opt->opt.srr) daddr = icmp_param->replyopts.opt.opt.faddr; } - { - struct flowi4 fl4 = { - .daddr = daddr, - .saddr = rt->rt_spec_dst, - .flowi4_tos = RT_TOS(ip_hdr(skb)->tos), - .flowi4_proto = IPPROTO_ICMP, - }; - security_skb_classify_flow(skb, flowi4_to_flowi(&fl4)); - rt = ip_route_output_key(net, &fl4); - if (IS_ERR(rt)) - goto out_unlock; - } + memset(&fl4, 0, sizeof(fl4)); + fl4.daddr = daddr; + fl4.saddr = rt->rt_spec_dst; + fl4.flowi4_tos = RT_TOS(ip_hdr(skb)->tos); + fl4.flowi4_proto = IPPROTO_ICMP; + security_skb_classify_flow(skb, flowi4_to_flowi(&fl4)); + rt = ip_route_output_key(net, &fl4); + if (IS_ERR(rt)) + goto out_unlock; if (icmpv4_xrlim_allow(net, rt, icmp_param->data.icmph.type, icmp_param->data.icmph.code)) - icmp_push_reply(icmp_param, &ipc, &rt); + icmp_push_reply(icmp_param, &fl4, &ipc, &rt); ip_rt_put(rt); out_unlock: icmp_xmit_unlock(sk); } -static struct rtable *icmp_route_lookup(struct net *net, struct sk_buff *skb_in, +static struct rtable *icmp_route_lookup(struct net *net, + struct flowi4 *fl4, + struct sk_buff *skb_in, const struct iphdr *iph, __be32 saddr, u8 tos, int type, int code, struct icmp_bxm *param) { - struct flowi4 fl4 = { - .daddr = (param->replyopts.opt.opt.srr ? - param->replyopts.opt.opt.faddr : iph->saddr), - .saddr = saddr, - .flowi4_tos = RT_TOS(tos), - .flowi4_proto = IPPROTO_ICMP, - .fl4_icmp_type = type, - .fl4_icmp_code = code, - }; struct rtable *rt, *rt2; int err; - security_skb_classify_flow(skb_in, flowi4_to_flowi(&fl4)); - rt = __ip_route_output_key(net, &fl4); + memset(fl4, 0, sizeof(*fl4)); + fl4->daddr = (param->replyopts.opt.opt.srr ? + param->replyopts.opt.opt.faddr : iph->saddr); + fl4->saddr = saddr; + fl4->flowi4_tos = RT_TOS(tos); + fl4->flowi4_proto = IPPROTO_ICMP; + fl4->fl4_icmp_type = type; + fl4->fl4_icmp_code = code; + security_skb_classify_flow(skb_in, flowi4_to_flowi(fl4)); + rt = __ip_route_output_key(net, fl4); if (IS_ERR(rt)) return rt; /* No need to clone since we're just using its address. */ rt2 = rt; - if (!fl4.saddr) - fl4.saddr = rt->rt_src; - rt = (struct rtable *) xfrm_lookup(net, &rt->dst, - flowi4_to_flowi(&fl4), NULL, 0); + flowi4_to_flowi(fl4), NULL, 0); if (!IS_ERR(rt)) { if (rt != rt2) return rt; @@ -410,19 +407,19 @@ static struct rtable *icmp_route_lookup(struct net *net, struct sk_buff *skb_in, } else return rt; - err = xfrm_decode_session_reverse(skb_in, flowi4_to_flowi(&fl4), AF_INET); + err = xfrm_decode_session_reverse(skb_in, flowi4_to_flowi(fl4), AF_INET); if (err) goto relookup_failed; - if (inet_addr_type(net, fl4.saddr) == RTN_LOCAL) { - rt2 = __ip_route_output_key(net, &fl4); + if (inet_addr_type(net, fl4->saddr) == RTN_LOCAL) { + rt2 = __ip_route_output_key(net, fl4); if (IS_ERR(rt2)) err = PTR_ERR(rt2); } else { struct flowi4 fl4_2 = {}; unsigned long orefdst; - fl4_2.daddr = fl4.saddr; + fl4_2.daddr = fl4->saddr; rt2 = ip_route_output_key(net, &fl4_2); if (IS_ERR(rt2)) { err = PTR_ERR(rt2); @@ -430,7 +427,7 @@ static struct rtable *icmp_route_lookup(struct net *net, struct sk_buff *skb_in, } /* Ugh! */ orefdst = skb_in->_skb_refdst; /* save old refdst */ - err = ip_route_input(skb_in, fl4.daddr, fl4.saddr, + err = ip_route_input(skb_in, fl4->daddr, fl4->saddr, RT_TOS(tos), rt2->dst.dev); dst_release(&rt2->dst); @@ -442,7 +439,7 @@ static struct rtable *icmp_route_lookup(struct net *net, struct sk_buff *skb_in, goto relookup_failed; rt2 = (struct rtable *) xfrm_lookup(net, &rt2->dst, - flowi4_to_flowi(&fl4), NULL, + flowi4_to_flowi(fl4), NULL, XFRM_LOOKUP_ICMP); if (!IS_ERR(rt2)) { dst_release(&rt->dst); @@ -481,6 +478,7 @@ void icmp_send(struct sk_buff *skb_in, int type, int code, __be32 info) struct icmp_bxm icmp_param; struct rtable *rt = skb_rtable(skb_in); struct ipcm_cookie ipc; + struct flowi4 fl4; __be32 saddr; u8 tos; struct net *net; @@ -599,7 +597,7 @@ void icmp_send(struct sk_buff *skb_in, int type, int code, __be32 info) ipc.opt = &icmp_param.replyopts.opt; ipc.tx_flags = 0; - rt = icmp_route_lookup(net, skb_in, iph, saddr, tos, + rt = icmp_route_lookup(net, &fl4, skb_in, iph, saddr, tos, type, code, &icmp_param); if (IS_ERR(rt)) goto out_unlock; @@ -620,7 +618,7 @@ void icmp_send(struct sk_buff *skb_in, int type, int code, __be32 info) icmp_param.data_len = room; icmp_param.head_len = sizeof(struct icmphdr); - icmp_push_reply(&icmp_param, &ipc, &rt); + icmp_push_reply(&icmp_param, &fl4, &ipc, &rt); ende: ip_rt_put(rt); out_unlock: diff --git a/net/ipv4/ip_output.c b/net/ipv4/ip_output.c index b88ee5f..dca637b 100644 --- a/net/ipv4/ip_output.c +++ b/net/ipv4/ip_output.c @@ -1267,6 +1267,7 @@ static void ip_cork_release(struct inet_cork *cork) * and push them out. */ struct sk_buff *__ip_make_skb(struct sock *sk, + struct flowi4 *fl4, struct sk_buff_head *queue, struct inet_cork *cork) { @@ -1333,8 +1334,8 @@ struct sk_buff *__ip_make_skb(struct sock *sk, ip_select_ident(iph, &rt->dst, sk); iph->ttl = ttl; iph->protocol = sk->sk_protocol; - iph->saddr = rt->rt_src; - iph->daddr = rt->rt_dst; + iph->saddr = fl4->saddr; + iph->daddr = fl4->daddr; skb->priority = sk->sk_priority; skb->mark = sk->sk_mark; @@ -1370,11 +1371,11 @@ int ip_send_skb(struct sk_buff *skb) return err; } -int ip_push_pending_frames(struct sock *sk) +int ip_push_pending_frames(struct sock *sk, struct flowi4 *fl4) { struct sk_buff *skb; - skb = ip_finish_skb(sk); + skb = ip_finish_skb(sk, fl4); if (!skb) return 0; @@ -1403,6 +1404,7 @@ void ip_flush_pending_frames(struct sock *sk) } struct sk_buff *ip_make_skb(struct sock *sk, + struct flowi4 *fl4, int getfrag(void *from, char *to, int offset, int len, int odd, struct sk_buff *skb), void *from, int length, int transhdrlen, @@ -1432,7 +1434,7 @@ struct sk_buff *ip_make_skb(struct sock *sk, return ERR_PTR(err); } - return __ip_make_skb(sk, &queue, &cork); + return __ip_make_skb(sk, fl4, &queue, &cork); } /* @@ -1461,6 +1463,7 @@ void ip_send_reply(struct sock *sk, struct sk_buff *skb, struct ip_reply_arg *ar struct inet_sock *inet = inet_sk(sk); struct ip_options_data replyopts; struct ipcm_cookie ipc; + struct flowi4 fl4; __be32 daddr; struct rtable *rt = skb_rtable(skb); @@ -1478,20 +1481,16 @@ void ip_send_reply(struct sock *sk, struct sk_buff *skb, struct ip_reply_arg *ar daddr = replyopts.opt.opt.faddr; } - { - struct flowi4 fl4; - - flowi4_init_output(&fl4, arg->bound_dev_if, 0, - RT_TOS(ip_hdr(skb)->tos), - RT_SCOPE_UNIVERSE, sk->sk_protocol, - ip_reply_arg_flowi_flags(arg), - daddr, rt->rt_spec_dst, - tcp_hdr(skb)->source, tcp_hdr(skb)->dest); - security_skb_classify_flow(skb, flowi4_to_flowi(&fl4)); - rt = ip_route_output_key(sock_net(sk), &fl4); - if (IS_ERR(rt)) - return; - } + flowi4_init_output(&fl4, arg->bound_dev_if, 0, + RT_TOS(ip_hdr(skb)->tos), + RT_SCOPE_UNIVERSE, sk->sk_protocol, + ip_reply_arg_flowi_flags(arg), + daddr, rt->rt_spec_dst, + tcp_hdr(skb)->source, tcp_hdr(skb)->dest); + security_skb_classify_flow(skb, flowi4_to_flowi(&fl4)); + rt = ip_route_output_key(sock_net(sk), &fl4); + if (IS_ERR(rt)) + return; /* And let IP do all the hard work. @@ -1512,7 +1511,7 @@ void ip_send_reply(struct sock *sk, struct sk_buff *skb, struct ip_reply_arg *ar arg->csumoffset) = csum_fold(csum_add(skb->csum, arg->csum)); skb->ip_summed = CHECKSUM_NONE; - ip_push_pending_frames(sk); + ip_push_pending_frames(sk, &fl4); } bh_unlock_sock(sk); diff --git a/net/ipv4/raw.c b/net/ipv4/raw.c index a8659e0..6fee91f 100644 --- a/net/ipv4/raw.c +++ b/net/ipv4/raw.c @@ -314,9 +314,10 @@ int raw_rcv(struct sock *sk, struct sk_buff *skb) return 0; } -static int raw_send_hdrinc(struct sock *sk, void *from, size_t length, - struct rtable **rtp, - unsigned int flags) +static int raw_send_hdrinc(struct sock *sk, struct flowi4 *fl4, + void *from, size_t length, + struct rtable **rtp, + unsigned int flags) { struct inet_sock *inet = inet_sk(sk); struct net *net = sock_net(sk); @@ -327,7 +328,7 @@ static int raw_send_hdrinc(struct sock *sk, void *from, size_t length, struct rtable *rt = *rtp; if (length > rt->dst.dev->mtu) { - ip_local_error(sk, EMSGSIZE, rt->rt_dst, inet->inet_dport, + ip_local_error(sk, EMSGSIZE, fl4->daddr, inet->inet_dport, rt->dst.dev->mtu); return -EMSGSIZE; } @@ -372,7 +373,7 @@ static int raw_send_hdrinc(struct sock *sk, void *from, size_t length, if (iphlen >= sizeof(*iph)) { if (!iph->saddr) - iph->saddr = rt->rt_src; + iph->saddr = fl4->saddr; iph->check = 0; iph->tot_len = htons(length); if (!iph->id) @@ -455,6 +456,7 @@ static int raw_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, struct inet_sock *inet = inet_sk(sk); struct ipcm_cookie ipc; struct rtable *rt = NULL; + struct flowi4 fl4; int free = 0; __be32 daddr; __be32 saddr; @@ -558,27 +560,23 @@ static int raw_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, saddr = inet->mc_addr; } - { - struct flowi4 fl4; + flowi4_init_output(&fl4, ipc.oif, sk->sk_mark, tos, + RT_SCOPE_UNIVERSE, + inet->hdrincl ? IPPROTO_RAW : sk->sk_protocol, + FLOWI_FLAG_CAN_SLEEP, daddr, saddr, 0, 0); - flowi4_init_output(&fl4, ipc.oif, sk->sk_mark, tos, - RT_SCOPE_UNIVERSE, - inet->hdrincl ? IPPROTO_RAW : sk->sk_protocol, - FLOWI_FLAG_CAN_SLEEP, daddr, saddr, 0, 0); - - if (!inet->hdrincl) { - err = raw_probe_proto_opt(&fl4, msg); - if (err) - goto done; - } - - security_sk_classify_flow(sk, flowi4_to_flowi(&fl4)); - rt = ip_route_output_flow(sock_net(sk), &fl4, sk); - if (IS_ERR(rt)) { - err = PTR_ERR(rt); - rt = NULL; + if (!inet->hdrincl) { + err = raw_probe_proto_opt(&fl4, msg); + if (err) goto done; - } + } + + security_sk_classify_flow(sk, flowi4_to_flowi(&fl4)); + rt = ip_route_output_flow(sock_net(sk), &fl4, sk); + if (IS_ERR(rt)) { + err = PTR_ERR(rt); + rt = NULL; + goto done; } err = -EACCES; @@ -590,19 +588,20 @@ static int raw_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, back_from_confirm: if (inet->hdrincl) - err = raw_send_hdrinc(sk, msg->msg_iov, len, - &rt, msg->msg_flags); + err = raw_send_hdrinc(sk, &fl4, msg->msg_iov, len, + &rt, msg->msg_flags); else { if (!ipc.addr) - ipc.addr = rt->rt_dst; + ipc.addr = fl4.daddr; lock_sock(sk); - err = ip_append_data(sk, ip_generic_getfrag, msg->msg_iov, len, 0, - &ipc, &rt, msg->msg_flags); + err = ip_append_data(sk, ip_generic_getfrag, + msg->msg_iov, len, 0, + &ipc, &rt, msg->msg_flags); if (err) ip_flush_pending_frames(sk); else if (!(msg->msg_flags & MSG_MORE)) { - err = ip_push_pending_frames(sk); + err = ip_push_pending_frames(sk, &fl4); if (err == -ENOBUFS && !inet->recverr) err = 0; } diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c index ba9f137..006e2cc 100644 --- a/net/ipv4/udp.c +++ b/net/ipv4/udp.c @@ -774,7 +774,7 @@ static int udp_push_pending_frames(struct sock *sk) struct sk_buff *skb; int err = 0; - skb = ip_finish_skb(sk); + skb = ip_finish_skb(sk, fl4); if (!skb) goto out; @@ -958,7 +958,7 @@ back_from_confirm: /* Lockless fast path for the non-corking case. */ if (!corkreq) { - skb = ip_make_skb(sk, getfrag, msg->msg_iov, ulen, + skb = ip_make_skb(sk, fl4, getfrag, msg->msg_iov, ulen, sizeof(struct udphdr), &ipc, &rt, msg->msg_flags); err = PTR_ERR(skb); -- cgit v0.10.2 From f5fca6086511294653a9e821f8e22f041415ba7b Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Sun, 8 May 2011 17:24:10 -0700 Subject: ipv4: Pass flow key down into ip_append_*(). This way rt->rt_dst accesses are unnecessary. Signed-off-by: David S. Miller diff --git a/include/net/ip.h b/include/net/ip.h index a425379..0b30d3a 100644 --- a/include/net/ip.h +++ b/include/net/ip.h @@ -106,7 +106,7 @@ extern int __ip_local_out(struct sk_buff *skb); extern int ip_local_out(struct sk_buff *skb); extern int ip_queue_xmit(struct sk_buff *skb, struct flowi *fl); extern void ip_init(void); -extern int ip_append_data(struct sock *sk, +extern int ip_append_data(struct sock *sk, struct flowi4 *fl4, int getfrag(void *from, char *to, int offset, int len, int odd, struct sk_buff *skb), void *from, int len, int protolen, @@ -114,7 +114,7 @@ extern int ip_append_data(struct sock *sk, struct rtable **rt, unsigned int flags); extern int ip_generic_getfrag(void *from, char *to, int offset, int len, int odd, struct sk_buff *skb); -extern ssize_t ip_append_page(struct sock *sk, struct page *page, +extern ssize_t ip_append_page(struct sock *sk, struct flowi4 *fl4, struct page *page, int offset, size_t size, int flags); extern struct sk_buff *__ip_make_skb(struct sock *sk, struct flowi4 *fl4, diff --git a/net/ipv4/icmp.c b/net/ipv4/icmp.c index be5cc8d..853a670 100644 --- a/net/ipv4/icmp.c +++ b/net/ipv4/icmp.c @@ -297,7 +297,7 @@ static void icmp_push_reply(struct icmp_bxm *icmp_param, struct sk_buff *skb; sk = icmp_sk(dev_net((*rt)->dst.dev)); - if (ip_append_data(sk, icmp_glue_bits, icmp_param, + if (ip_append_data(sk, fl4, icmp_glue_bits, icmp_param, icmp_param->data_len+icmp_param->head_len, icmp_param->head_len, ipc, rt, MSG_DONTWAIT) < 0) { diff --git a/net/ipv4/ip_output.c b/net/ipv4/ip_output.c index dca637b..cd89d22 100644 --- a/net/ipv4/ip_output.c +++ b/net/ipv4/ip_output.c @@ -776,7 +776,9 @@ static inline int ip_ufo_append_data(struct sock *sk, (length - transhdrlen)); } -static int __ip_append_data(struct sock *sk, struct sk_buff_head *queue, +static int __ip_append_data(struct sock *sk, + struct flowi4 *fl4, + struct sk_buff_head *queue, struct inet_cork *cork, int getfrag(void *from, char *to, int offset, int len, int odd, struct sk_buff *skb), @@ -808,7 +810,7 @@ static int __ip_append_data(struct sock *sk, struct sk_buff_head *queue, maxfraglen = ((mtu - fragheaderlen) & ~7) + fragheaderlen; if (cork->length + length > 0xFFFF - fragheaderlen) { - ip_local_error(sk, EMSGSIZE, rt->rt_dst, inet->inet_dport, + ip_local_error(sk, EMSGSIZE, fl4->daddr, inet->inet_dport, mtu-exthdrlen); return -EMSGSIZE; } @@ -1083,7 +1085,7 @@ static int ip_setup_cork(struct sock *sk, struct inet_cork *cork, * * LATER: length must be adjusted by pad at tail, when it is required. */ -int ip_append_data(struct sock *sk, +int ip_append_data(struct sock *sk, struct flowi4 *fl4, int getfrag(void *from, char *to, int offset, int len, int odd, struct sk_buff *skb), void *from, int length, int transhdrlen, @@ -1104,11 +1106,11 @@ int ip_append_data(struct sock *sk, transhdrlen = 0; } - return __ip_append_data(sk, &sk->sk_write_queue, &inet->cork.base, getfrag, + return __ip_append_data(sk, fl4, &sk->sk_write_queue, &inet->cork.base, getfrag, from, length, transhdrlen, flags); } -ssize_t ip_append_page(struct sock *sk, struct page *page, +ssize_t ip_append_page(struct sock *sk, struct flowi4 *fl4, struct page *page, int offset, size_t size, int flags) { struct inet_sock *inet = inet_sk(sk); @@ -1146,7 +1148,7 @@ ssize_t ip_append_page(struct sock *sk, struct page *page, maxfraglen = ((mtu - fragheaderlen) & ~7) + fragheaderlen; if (cork->length + size > 0xFFFF - fragheaderlen) { - ip_local_error(sk, EMSGSIZE, rt->rt_dst, inet->inet_dport, mtu); + ip_local_error(sk, EMSGSIZE, fl4->daddr, inet->inet_dport, mtu); return -EMSGSIZE; } @@ -1427,7 +1429,7 @@ struct sk_buff *ip_make_skb(struct sock *sk, if (err) return ERR_PTR(err); - err = __ip_append_data(sk, &queue, &cork, getfrag, + err = __ip_append_data(sk, fl4, &queue, &cork, getfrag, from, length, transhdrlen, flags); if (err) { __ip_flush_pending_frames(sk, &queue, &cork); @@ -1503,7 +1505,7 @@ void ip_send_reply(struct sock *sk, struct sk_buff *skb, struct ip_reply_arg *ar sk->sk_priority = skb->priority; sk->sk_protocol = ip_hdr(skb)->protocol; sk->sk_bound_dev_if = arg->bound_dev_if; - ip_append_data(sk, ip_reply_glue_bits, arg->iov->iov_base, len, 0, + ip_append_data(sk, &fl4, ip_reply_glue_bits, arg->iov->iov_base, len, 0, &ipc, &rt, MSG_DONTWAIT); if ((skb = skb_peek(&sk->sk_write_queue)) != NULL) { if (arg->csumoffset >= 0) diff --git a/net/ipv4/raw.c b/net/ipv4/raw.c index 6fee91f..11e17804 100644 --- a/net/ipv4/raw.c +++ b/net/ipv4/raw.c @@ -595,7 +595,7 @@ back_from_confirm: if (!ipc.addr) ipc.addr = fl4.daddr; lock_sock(sk); - err = ip_append_data(sk, ip_generic_getfrag, + err = ip_append_data(sk, &fl4, ip_generic_getfrag, msg->msg_iov, len, 0, &ipc, &rt, msg->msg_flags); if (err) diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c index 006e2cc..66341a3 100644 --- a/net/ipv4/udp.c +++ b/net/ipv4/udp.c @@ -822,6 +822,7 @@ int udp_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, getfrag = is_udplite ? udplite_getfrag : ip_generic_getfrag; + fl4 = &inet->cork.fl.u.ip4; if (up->pending) { /* * There are pending frames. @@ -920,7 +921,6 @@ int udp_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, if (connected) rt = (struct rtable *)sk_dst_check(sk, 0); - fl4 = &inet->cork.fl.u.ip4; if (rt == NULL) { struct net *net = sock_net(sk); @@ -989,9 +989,9 @@ back_from_confirm: do_append_data: up->len += ulen; - err = ip_append_data(sk, getfrag, msg->msg_iov, ulen, - sizeof(struct udphdr), &ipc, &rt, - corkreq ? msg->msg_flags|MSG_MORE : msg->msg_flags); + err = ip_append_data(sk, fl4, getfrag, msg->msg_iov, ulen, + sizeof(struct udphdr), &ipc, &rt, + corkreq ? msg->msg_flags|MSG_MORE : msg->msg_flags); if (err) udp_flush_pending_frames(sk); else if (!corkreq) @@ -1031,6 +1031,7 @@ EXPORT_SYMBOL(udp_sendmsg); int udp_sendpage(struct sock *sk, struct page *page, int offset, size_t size, int flags) { + struct inet_sock *inet = inet_sk(sk); struct udp_sock *up = udp_sk(sk); int ret; @@ -1055,7 +1056,8 @@ int udp_sendpage(struct sock *sk, struct page *page, int offset, return -EINVAL; } - ret = ip_append_page(sk, page, offset, size, flags); + ret = ip_append_page(sk, &inet->cork.fl.u.ip4, + page, offset, size, flags); if (ret == -EOPNOTSUPP) { release_sock(sk); return sock_no_sendpage(sk->sk_socket, page, offset, -- cgit v0.10.2 From 7ef73bca731fea9d4b706db2acb96b6488aa1b0e Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Sun, 8 May 2011 21:14:41 -0700 Subject: sctp: Fix debug message args. I messed things up when I converted over to the transport flow, I passed the ipv4 address value instead of it's address. Reported-by: Stephen Rothwell Signed-off-by: David S. Miller diff --git a/net/sctp/protocol.c b/net/sctp/protocol.c index acb2ee7..4f270ac 100644 --- a/net/sctp/protocol.c +++ b/net/sctp/protocol.c @@ -848,8 +848,8 @@ static inline int sctp_v4_xmit(struct sk_buff *skb, SCTP_DEBUG_PRINTK("%s: skb:%p, len:%d, src:%pI4, dst:%pI4\n", __func__, skb, skb->len, - transport->fl.u.ip4.saddr, - transport->fl.u.ip4.daddr); + &transport->fl.u.ip4.saddr, + &transport->fl.u.ip4.daddr); inet->pmtudisc = transport->param_flags & SPP_PMTUD_ENABLE ? IP_PMTUDISC_DO : IP_PMTUDISC_DONT; -- cgit v0.10.2 From 2e4f7c7769a0b8b6b3e88b0436c6c634f146a4ef Mon Sep 17 00:00:00 2001 From: Oleg Nesterov Date: Mon, 9 May 2011 13:48:56 +0200 Subject: signal: sys_sigprocmask() needs retarget_shared_pending() sys_sigprocmask() changes current->blocked by hand. Convert this code to use set_current_blocked(). Signed-off-by: Oleg Nesterov diff --git a/kernel/signal.c b/kernel/signal.c index c0af959..b87780e 100644 --- a/kernel/signal.c +++ b/kernel/signal.c @@ -2900,7 +2900,7 @@ SYSCALL_DEFINE3(sigprocmask, int, how, old_sigset_t __user *, nset, old_sigset_t __user *, oset) { old_sigset_t old_set, new_set; - int error; + sigset_t new_blocked; old_set = current->blocked.sig[0]; @@ -2909,27 +2909,23 @@ SYSCALL_DEFINE3(sigprocmask, int, how, old_sigset_t __user *, nset, return -EFAULT; new_set &= ~(sigmask(SIGKILL) | sigmask(SIGSTOP)); - error = 0; - spin_lock_irq(¤t->sighand->siglock); + new_blocked = current->blocked; + switch (how) { - default: - error = -EINVAL; - break; case SIG_BLOCK: - sigaddsetmask(¤t->blocked, new_set); + sigaddsetmask(&new_blocked, new_set); break; case SIG_UNBLOCK: - sigdelsetmask(¤t->blocked, new_set); + sigdelsetmask(&new_blocked, new_set); break; case SIG_SETMASK: - current->blocked.sig[0] = new_set; + new_blocked.sig[0] = new_set; break; + default: + return -EINVAL; } - recalc_sigpending(); - spin_unlock_irq(¤t->sighand->siglock); - if (error) - return error; + set_current_blocked(&new_blocked); } if (oset) { -- cgit v0.10.2 From 40ae717d1e78d982bd469b2013a4cbf4ec1ca434 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Fri, 6 May 2011 11:52:22 +0200 Subject: ptrace: fix signal->wait_chldexit usage in task_clear_group_stop_trapping() GROUP_STOP_TRAPPING waiting mechanism piggybacks on signal->wait_chldexit which is primarily used to implement waiting for wait(2) and friends. When do_wait() waits on signal->wait_chldexit, it uses a custom wake up callback, child_wait_callback(), which expects the child task which is waking up the parent to be passed in as @key to filter out spurious wakeups. task_clear_group_stop_trapping() used __wake_up_sync() which uses NULL @key causing the following oops if the parent was doing do_wait(). BUG: unable to handle kernel NULL pointer dereference at 00000000000002d8 IP: [] child_wait_callback+0x29/0x80 PGD 1d899067 PUD 1e418067 PMD 0 Oops: 0000 [#1] PREEMPT SMP last sysfs file: /sys/devices/pci0000:00/0000:00:03.0/local_cpus CPU 2 Modules linked in: Pid: 4498, comm: test-continued Not tainted 2.6.39-rc6-work+ #32 Bochs Bochs RIP: 0010:[] [] child_wait_callback+0x29/0x80 RSP: 0000:ffff88001b889bf8 EFLAGS: 00010046 RAX: 0000000000000000 RBX: ffff88001fab3af8 RCX: 0000000000000000 RDX: 0000000000000001 RSI: 0000000000000002 RDI: ffff88001d91df20 RBP: ffff88001b889c08 R08: 0000000000000000 R09: 0000000000000000 R10: 0000000000000000 R11: 0000000000000001 R12: 0000000000000000 R13: ffff88001fb70550 R14: 0000000000000000 R15: 0000000000000001 FS: 00007f26ccae4700(0000) GS:ffff88001fd00000(0000) knlGS:0000000000000000 CS: 0010 DS: 0000 ES: 0000 CR0: 000000008005003b CR2: 00000000000002d8 CR3: 000000001b8ac000 CR4: 00000000000006e0 DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000 DR3: 0000000000000000 DR6: 00000000ffff0ff0 DR7: 0000000000000400 Process test-continued (pid: 4498, threadinfo ffff88001b888000, task ffff88001fb88000) Stack: ffff88001b889c18 ffff88001fb70538 ffff88001b889c58 ffffffff810312f9 0000000000000001 0000000200000001 ffff88001b889c58 ffff88001fb70518 0000000000000002 0000000000000082 0000000000000001 0000000000000000 Call Trace: [] __wake_up_common+0x59/0x90 [] __wake_up_sync_key+0x53/0x80 [] __wake_up_sync+0x10/0x20 [] task_clear_jobctl_trapping+0x44/0x50 [] ptrace_stop+0x7c/0x290 [] do_signal_stop+0x28a/0x2d0 [] get_signal_to_deliver+0x14f/0x5a0 [] do_signal+0x75/0x7b0 [] do_notify_resume+0x5d/0x70 [] retint_signal+0x46/0x8c Code: 00 00 55 48 89 e5 53 48 83 ec 08 0f 1f 44 00 00 8b 47 d8 83 f8 03 74 3a 85 c0 49 89 c8 75 23 89 c0 48 8b 5f e0 4c 8d 0c 40 31 c0 <4b> 39 9c c8 d8 02 00 00 74 1d 48 83 c4 08 5b c9 c3 66 0f 1f 44 Fix it by using __wake_up_sync_key() and passing in the child as @key. I still think it's a mistake to piggyback on wait_chldexit for this. Given the relative low frequency of ptrace use, we would be much better off leaving already complex wait_chldexit alone and using bit waitqueue. Signed-off-by: Tejun Heo Reviewed-by: Oleg Nesterov diff --git a/kernel/signal.c b/kernel/signal.c index b87780e..35c5f4b 100644 --- a/kernel/signal.c +++ b/kernel/signal.c @@ -238,8 +238,8 @@ static void task_clear_group_stop_trapping(struct task_struct *task) { if (unlikely(task->group_stop & GROUP_STOP_TRAPPING)) { task->group_stop &= ~GROUP_STOP_TRAPPING; - __wake_up_sync(&task->parent->signal->wait_chldexit, - TASK_UNINTERRUPTIBLE, 1); + __wake_up_sync_key(&task->parent->signal->wait_chldexit, + TASK_UNINTERRUPTIBLE, 1, task); } } -- cgit v0.10.2 From 9fbdaeb4f4dd14a0caa9fc35c496d5440c251a3a Mon Sep 17 00:00:00 2001 From: Manoj Iyer Date: Sun, 8 May 2011 18:04:29 -0400 Subject: thinkpad-acpi: module autoloading for newer Lenovo ThinkPads. The newer Lenovo ThinkPads have HKEY HID of LEN0068 instead of IBM0068. Added new HID so that thinkpad_acpi module will auto load on these newer Lenovo ThinkPads. Acked-by: Henrique de Moraes Holschuh Cc: stable@kernel.org Signed-off-by: Manoj Iyer Signed-off-by: Andy Lutomirski Signed-off-by: Matthew Garrett diff --git a/drivers/platform/x86/thinkpad_acpi.c b/drivers/platform/x86/thinkpad_acpi.c index efb3b6b..562fcf0 100644 --- a/drivers/platform/x86/thinkpad_acpi.c +++ b/drivers/platform/x86/thinkpad_acpi.c @@ -128,7 +128,8 @@ enum { }; /* ACPI HIDs */ -#define TPACPI_ACPI_HKEY_HID "IBM0068" +#define TPACPI_ACPI_IBM_HKEY_HID "IBM0068" +#define TPACPI_ACPI_LENOVO_HKEY_HID "LEN0068" #define TPACPI_ACPI_EC_HID "PNP0C09" /* Input IDs */ @@ -3879,7 +3880,8 @@ errexit: } static const struct acpi_device_id ibm_htk_device_ids[] = { - {TPACPI_ACPI_HKEY_HID, 0}, + {TPACPI_ACPI_IBM_HKEY_HID, 0}, + {TPACPI_ACPI_LENOVO_HKEY_HID, 0}, {"", 0}, }; -- cgit v0.10.2 From 6192fa7109fb33591fa1078c8c1981e39da02d2d Mon Sep 17 00:00:00 2001 From: Mattia Dongili Date: Tue, 5 Apr 2011 23:38:36 +0900 Subject: sony-laptop: report failures on setting LCD brightness Check if we were successful in setting the requested brightness and report failure in that case. Signed-off-by: Mattia Dongili Signed-off-by: Matthew Garrett diff --git a/drivers/platform/x86/sony-laptop.c b/drivers/platform/x86/sony-laptop.c index 8f709ae..9d80ae4 100644 --- a/drivers/platform/x86/sony-laptop.c +++ b/drivers/platform/x86/sony-laptop.c @@ -966,9 +966,10 @@ static int sony_nc_update_status_ng(struct backlight_device *bd) int *handle = (int *)bl_get_data(bd); value = bd->props.brightness; - sony_call_snc_handle(*handle, 0x0100 | (value << 16), &result); + if (sony_call_snc_handle(*handle, 0x0100 | (value << 16), &result)) + return -EIO; - return sony_nc_get_brightness_ng(bd); + return value; } static const struct backlight_ops sony_backlight_ops = { -- cgit v0.10.2 From 62d2f23e8bce3e7da4db53928e810fc8a474ce70 Mon Sep 17 00:00:00 2001 From: Mattia Dongili Date: Mon, 9 May 2011 10:20:29 -0400 Subject: [PATCH] sony-laptop: limit brightness range to DSDT provided ones The new style brightness control provides an operating range of 9 values (seems consistent over a large number of models sharing the same brightness control methods). Read and use the minimum and maximum values to limit the backlight interface between those boundaries. Signed-off-by: Mattia Dongili Signed-off-by: Matthew Garrett diff --git a/drivers/platform/x86/sony-laptop.c b/drivers/platform/x86/sony-laptop.c index 9d80ae4..6fe8cd6 100644 --- a/drivers/platform/x86/sony-laptop.c +++ b/drivers/platform/x86/sony-laptop.c @@ -934,6 +934,14 @@ static ssize_t sony_nc_sysfs_store(struct device *dev, /* * Backlight device */ +struct sony_backlight_props { + struct backlight_device *dev; + int handle; + u8 offset; + u8 maxlvl; +}; +struct sony_backlight_props sony_bl_props; + static int sony_backlight_update_status(struct backlight_device *bd) { return acpi_callsetfunc(sony_nc_acpi_handle, "SBRT", @@ -954,19 +962,23 @@ static int sony_nc_get_brightness_ng(struct backlight_device *bd) { int result; int *handle = (int *)bl_get_data(bd); + struct sony_backlight_props *sdev = + (struct sony_backlight_props *)bl_get_data(bd); - sony_call_snc_handle(*handle, 0x0200, &result); + sony_call_snc_handle(sdev->handle, 0x0200, &result); - return result & 0xff; + return (result & 0xff) - sdev->offset; } static int sony_nc_update_status_ng(struct backlight_device *bd) { int value, result; int *handle = (int *)bl_get_data(bd); + struct sony_backlight_props *sdev = + (struct sony_backlight_props *)bl_get_data(bd); - value = bd->props.brightness; - if (sony_call_snc_handle(*handle, 0x0100 | (value << 16), &result)) + value = bd->props.brightness + sdev->offset; + if (sony_call_snc_handle(sdev->handle, 0x0100 | (value << 16), &result)) return -EIO; return value; @@ -982,8 +994,6 @@ static const struct backlight_ops sony_backlight_ng_ops = { .update_status = sony_nc_update_status_ng, .get_brightness = sony_nc_get_brightness_ng, }; -static int backlight_ng_handle; -static struct backlight_device *sony_backlight_device; /* * New SNC-only Vaios event mapping to driver known keys @@ -1550,6 +1560,75 @@ static void sony_nc_kbd_backlight_resume(void) &ignore); } +static void sony_nc_backlight_ng_read_limits(int handle, + struct sony_backlight_props *props) +{ + int offset; + acpi_status status; + u8 brlvl, i; + u8 min = 0xff, max = 0x00; + struct acpi_object_list params; + union acpi_object in_obj; + union acpi_object *lvl_enum; + struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; + + props->handle = handle; + props->offset = 0; + props->maxlvl = 0xff; + + offset = sony_find_snc_handle(handle); + if (offset < 0) + return; + + /* try to read the boundaries from ACPI tables, if we fail the above + * defaults should be reasonable + */ + params.count = 1; + params.pointer = &in_obj; + in_obj.type = ACPI_TYPE_INTEGER; + in_obj.integer.value = offset; + status = acpi_evaluate_object(sony_nc_acpi_handle, "SN06", ¶ms, + &buffer); + if (ACPI_FAILURE(status)) + return; + + lvl_enum = (union acpi_object *) buffer.pointer; + if (!lvl_enum) { + pr_err("No SN06 return object."); + return; + } + if (lvl_enum->type != ACPI_TYPE_BUFFER) { + pr_err("Invalid SN06 return object 0x%.2x\n", + lvl_enum->type); + goto out_invalid; + } + + /* the buffer lists brightness levels available, brightness levels are + * from 0 to 8 in the array, other values are used by ALS control. + */ + for (i = 0; i < 9 && i < lvl_enum->buffer.length; i++) { + + brlvl = *(lvl_enum->buffer.pointer + i); + dprintk("Brightness level: %d\n", brlvl); + + if (!brlvl) + break; + + if (brlvl > max) + max = brlvl; + if (brlvl < min) + min = brlvl; + } + props->offset = min; + props->maxlvl = max; + dprintk("Brightness levels: min=%d max=%d\n", props->offset, + props->maxlvl); + +out_invalid: + kfree(buffer.pointer); + return; +} + static void sony_nc_backlight_setup(void) { acpi_handle unused; @@ -1558,14 +1637,14 @@ static void sony_nc_backlight_setup(void) struct backlight_properties props; if (sony_find_snc_handle(0x12f) != -1) { - backlight_ng_handle = 0x12f; ops = &sony_backlight_ng_ops; - max_brightness = 0xff; + sony_nc_backlight_ng_read_limits(0x12f, &sony_bl_props); + max_brightness = sony_bl_props.maxlvl - sony_bl_props.offset; } else if (sony_find_snc_handle(0x137) != -1) { - backlight_ng_handle = 0x137; ops = &sony_backlight_ng_ops; - max_brightness = 0xff; + sony_nc_backlight_ng_read_limits(0x137, &sony_bl_props); + max_brightness = sony_bl_props.maxlvl - sony_bl_props.offset; } else if (ACPI_SUCCESS(acpi_get_handle(sony_nc_acpi_handle, "GBRT", &unused))) { @@ -1578,22 +1657,22 @@ static void sony_nc_backlight_setup(void) memset(&props, 0, sizeof(struct backlight_properties)); props.type = BACKLIGHT_PLATFORM; props.max_brightness = max_brightness; - sony_backlight_device = backlight_device_register("sony", NULL, - &backlight_ng_handle, - ops, &props); + sony_bl_props.dev = backlight_device_register("sony", NULL, + &sony_bl_props, + ops, &props); - if (IS_ERR(sony_backlight_device)) { - pr_warning(DRV_PFX "unable to register backlight device\n"); - sony_backlight_device = NULL; + if (IS_ERR(sony_bl_props.dev)) { + pr_warn(DRV_PFX "unable to register backlight device\n"); + sony_bl_props.dev = NULL; } else - sony_backlight_device->props.brightness = - ops->get_brightness(sony_backlight_device); + sony_bl_props.dev->props.brightness = + ops->get_brightness(sony_bl_props.dev); } static void sony_nc_backlight_cleanup(void) { - if (sony_backlight_device) - backlight_device_unregister(sony_backlight_device); + if (sony_bl_props.dev) + backlight_device_unregister(sony_bl_props.dev); } static int sony_nc_add(struct acpi_device *device) @@ -2591,7 +2670,7 @@ static long sonypi_misc_ioctl(struct file *fp, unsigned int cmd, mutex_lock(&spic_dev.lock); switch (cmd) { case SONYPI_IOCGBRT: - if (sony_backlight_device == NULL) { + if (sony_bl_props.dev == NULL) { ret = -EIO; break; } @@ -2604,7 +2683,7 @@ static long sonypi_misc_ioctl(struct file *fp, unsigned int cmd, ret = -EFAULT; break; case SONYPI_IOCSBRT: - if (sony_backlight_device == NULL) { + if (sony_bl_props.dev == NULL) { ret = -EIO; break; } @@ -2618,8 +2697,8 @@ static long sonypi_misc_ioctl(struct file *fp, unsigned int cmd, break; } /* sync the backlight device status */ - sony_backlight_device->props.brightness = - sony_backlight_get_brightness(sony_backlight_device); + sony_bl_props.dev->props.brightness = + sony_backlight_get_brightness(sony_bl_props.dev); break; case SONYPI_IOCGBAT1CAP: if (ec_read16(SONYPI_BAT1_FULL, &val16)) { -- cgit v0.10.2 From 14fdb152416c0fab80ecddf492c129d7da1bb8ef Mon Sep 17 00:00:00 2001 From: Matthew Garrett Date: Mon, 9 May 2011 10:44:01 -0400 Subject: eeepc-laptop: Use ACPI handle to identify rfkill port The ACPI notification we get from rfkill events on these machines gives us all the information we need to identify the port that's changed. Do so rather than assuming that it's always bus 1. Signed-off-by: Matthew Garrett diff --git a/drivers/platform/x86/eeepc-laptop.c b/drivers/platform/x86/eeepc-laptop.c index 5f2dd38..2c1abf6 100644 --- a/drivers/platform/x86/eeepc-laptop.c +++ b/drivers/platform/x86/eeepc-laptop.c @@ -585,8 +585,9 @@ static bool eeepc_wlan_rfkill_blocked(struct eeepc_laptop *eeepc) return true; } -static void eeepc_rfkill_hotplug(struct eeepc_laptop *eeepc) +static void eeepc_rfkill_hotplug(struct eeepc_laptop *eeepc, acpi_handle handle) { + struct pci_dev *port; struct pci_dev *dev; struct pci_bus *bus; bool blocked = eeepc_wlan_rfkill_blocked(eeepc); @@ -599,9 +600,16 @@ static void eeepc_rfkill_hotplug(struct eeepc_laptop *eeepc) mutex_lock(&eeepc->hotplug_lock); if (eeepc->hotplug_slot) { - bus = pci_find_bus(0, 1); + port = acpi_get_pci_dev(handle); + if (!port) { + pr_warning("Unable to find port\n"); + goto out_unlock; + } + + bus = port->subordinate; + if (!bus) { - pr_warning("Unable to find PCI bus 1?\n"); + pr_warning("Unable to find PCI bus?\n"); goto out_unlock; } @@ -609,6 +617,7 @@ static void eeepc_rfkill_hotplug(struct eeepc_laptop *eeepc) pr_err("Unable to read PCI config space?\n"); goto out_unlock; } + absent = (l == 0xffffffff); if (blocked != absent) { @@ -647,6 +656,17 @@ out_unlock: mutex_unlock(&eeepc->hotplug_lock); } +static void eeepc_rfkill_hotplug_update(struct eeepc_laptop *eeepc, char *node) +{ + acpi_status status = AE_OK; + acpi_handle handle; + + status = acpi_get_handle(NULL, node, &handle); + + if (ACPI_SUCCESS(status)) + eeepc_rfkill_hotplug(eeepc, handle); +} + static void eeepc_rfkill_notify(acpi_handle handle, u32 event, void *data) { struct eeepc_laptop *eeepc = data; @@ -654,7 +674,7 @@ static void eeepc_rfkill_notify(acpi_handle handle, u32 event, void *data) if (event != ACPI_NOTIFY_BUS_CHECK) return; - eeepc_rfkill_hotplug(eeepc); + eeepc_rfkill_hotplug(eeepc, handle); } static int eeepc_register_rfkill_notifier(struct eeepc_laptop *eeepc, @@ -672,6 +692,11 @@ static int eeepc_register_rfkill_notifier(struct eeepc_laptop *eeepc, eeepc); if (ACPI_FAILURE(status)) pr_warning("Failed to register notify on %s\n", node); + /* + * Refresh pci hotplug in case the rfkill state was + * changed during setup. + */ + eeepc_rfkill_hotplug(eeepc, handle); } else return -ENODEV; @@ -693,6 +718,12 @@ static void eeepc_unregister_rfkill_notifier(struct eeepc_laptop *eeepc, if (ACPI_FAILURE(status)) pr_err("Error removing rfkill notify handler %s\n", node); + /* + * Refresh pci hotplug in case the rfkill + * state was changed after + * eeepc_unregister_rfkill_notifier() + */ + eeepc_rfkill_hotplug(eeepc, handle); } } @@ -816,11 +847,7 @@ static void eeepc_rfkill_exit(struct eeepc_laptop *eeepc) rfkill_destroy(eeepc->wlan_rfkill); eeepc->wlan_rfkill = NULL; } - /* - * Refresh pci hotplug in case the rfkill state was changed after - * eeepc_unregister_rfkill_notifier() - */ - eeepc_rfkill_hotplug(eeepc); + if (eeepc->hotplug_slot) pci_hp_deregister(eeepc->hotplug_slot); @@ -889,11 +916,6 @@ static int eeepc_rfkill_init(struct eeepc_laptop *eeepc) eeepc_register_rfkill_notifier(eeepc, "\\_SB.PCI0.P0P5"); eeepc_register_rfkill_notifier(eeepc, "\\_SB.PCI0.P0P6"); eeepc_register_rfkill_notifier(eeepc, "\\_SB.PCI0.P0P7"); - /* - * Refresh pci hotplug in case the rfkill state was changed during - * setup. - */ - eeepc_rfkill_hotplug(eeepc); exit: if (result && result != -ENODEV) @@ -928,8 +950,11 @@ static int eeepc_hotk_restore(struct device *device) struct eeepc_laptop *eeepc = dev_get_drvdata(device); /* Refresh both wlan rfkill state and pci hotplug */ - if (eeepc->wlan_rfkill) - eeepc_rfkill_hotplug(eeepc); + if (eeepc->wlan_rfkill) { + eeepc_rfkill_hotplug_update(eeepc, "\\_SB.PCI0.P0P5"); + eeepc_rfkill_hotplug_update(eeepc, "\\_SB.PCI0.P0P6"); + eeepc_rfkill_hotplug_update(eeepc, "\\_SB.PCI0.P0P7"); + } if (eeepc->bluetooth_rfkill) rfkill_set_sw_state(eeepc->bluetooth_rfkill, -- cgit v0.10.2 From 2baee03fb916563d7cc597e5460e4cb938815c52 Mon Sep 17 00:00:00 2001 From: Steven Whitehouse Date: Mon, 9 May 2011 12:08:36 +0100 Subject: GFS2: Don't use gfs2_change_nlink in link syscall There are three users of gfs2_change_nlink which add to the link count. Two of these are about to be removed in later patches, so this means that there will no callers, when that happens allowing removal of that function, also in a later patch. Signed-off-by: Steven Whitehouse diff --git a/fs/gfs2/ops_inode.c b/fs/gfs2/ops_inode.c index 1005f9e..acb6f69 100644 --- a/fs/gfs2/ops_inode.c +++ b/fs/gfs2/ops_inode.c @@ -145,6 +145,7 @@ static int gfs2_link(struct dentry *old_dentry, struct inode *dir, struct inode *inode = old_dentry->d_inode; struct gfs2_inode *ip = GFS2_I(inode); struct gfs2_holder ghs[2]; + struct buffer_head *dibh; int alloc_required; int error; @@ -230,12 +231,22 @@ static int gfs2_link(struct dentry *old_dentry, struct inode *dir, goto out_ipres; } - error = gfs2_dir_add(dir, &dentry->d_name, ip, IF2DT(inode->i_mode)); + error = gfs2_meta_inode_buffer(ip, &dibh); if (error) goto out_end_trans; - error = gfs2_change_nlink(ip, +1); + error = gfs2_dir_add(dir, &dentry->d_name, ip, IF2DT(inode->i_mode)); + if (error) + goto out_brelse; + + gfs2_trans_add_bh(ip->i_gl, dibh, 1); + inc_nlink(&ip->i_inode); + ip->i_inode.i_ctime = CURRENT_TIME; + gfs2_dinode_out(ip, dibh->b_data); + mark_inode_dirty(&ip->i_inode); +out_brelse: + brelse(dibh); out_end_trans: gfs2_trans_end(sdp); out_ipres: -- cgit v0.10.2 From 855d23ce2665c56437bd88fa6a0d45b6713bd194 Mon Sep 17 00:00:00 2001 From: Steven Whitehouse Date: Mon, 9 May 2011 16:42:37 +0100 Subject: GFS2: Make gfs2_dir_del update link count when required When we remove an entry from a directory, we can save ourselves some trouble if we know the type of the entry in question, since if it is itself a directory, we can update the link count of the parent at the same time as removing the directory entry. In addition this patch also merges the rmdir and unlink code which was almost identical anyway. This eliminates the calls to remove the . and .. directory entries on each rmdir (not needed since the directory will be deallocated, anyway) which was the only thing preventing passing the dentry to gfs2_dir_del(). The passing of the dentry rather than just the name allows us to figure out the type of the entry which is being removed, and thus adjust the link count when required. Signed-off-by: Steven Whitehouse diff --git a/fs/gfs2/dir.c b/fs/gfs2/dir.c index f7a3137..4102651 100644 --- a/fs/gfs2/dir.c +++ b/fs/gfs2/dir.c @@ -1669,8 +1669,9 @@ int gfs2_dir_add(struct inode *inode, const struct qstr *name, * Returns: 0 on success, error code on failure */ -int gfs2_dir_del(struct gfs2_inode *dip, const struct qstr *name) +int gfs2_dir_del(struct gfs2_inode *dip, const struct dentry *dentry) { + const struct qstr *name = &dentry->d_name; struct gfs2_dirent *dent, *prev = NULL; struct buffer_head *bh; int error; @@ -1711,6 +1712,8 @@ int gfs2_dir_del(struct gfs2_inode *dip, const struct qstr *name) gfs2_trans_add_bh(dip->i_gl, bh, 1); dip->i_entries--; dip->i_inode.i_mtime = dip->i_inode.i_ctime = CURRENT_TIME; + if (S_ISDIR(dentry->d_inode->i_mode)) + drop_nlink(&dip->i_inode); gfs2_dinode_out(dip, bh->b_data); brelse(bh); mark_inode_dirty(&dip->i_inode); diff --git a/fs/gfs2/dir.h b/fs/gfs2/dir.h index a98f644..66831f1 100644 --- a/fs/gfs2/dir.h +++ b/fs/gfs2/dir.h @@ -23,7 +23,7 @@ extern int gfs2_dir_check(struct inode *dir, const struct qstr *filename, const struct gfs2_inode *ip); extern int gfs2_dir_add(struct inode *inode, const struct qstr *filename, const struct gfs2_inode *ip, unsigned int type); -extern int gfs2_dir_del(struct gfs2_inode *dip, const struct qstr *filename); +extern int gfs2_dir_del(struct gfs2_inode *dip, const struct dentry *dentry); extern int gfs2_dir_read(struct inode *inode, u64 *offset, void *opaque, filldir_t filldir); extern int gfs2_dir_mvino(struct gfs2_inode *dip, const struct qstr *filename, diff --git a/fs/gfs2/ops_inode.c b/fs/gfs2/ops_inode.c index acb6f69..765da06 100644 --- a/fs/gfs2/ops_inode.c +++ b/fs/gfs2/ops_inode.c @@ -312,11 +312,52 @@ static int gfs2_unlink_ok(struct gfs2_inode *dip, const struct qstr *name, } /** - * gfs2_unlink - Unlink a file - * @dir: The inode of the directory containing the file to unlink + * gfs2_unlink_inode - Removes an inode from its parent dir and unlinks it + * @dip: The parent directory + * @name: The name of the entry in the parent directory + * @bh: The inode buffer for the inode to be removed + * @inode: The inode to be removed + * + * Called with all the locks and in a transaction. This will only be + * called for a directory after it has been checked to ensure it is empty. + * + * Returns: 0 on success, or an error + */ + +static int gfs2_unlink_inode(struct gfs2_inode *dip, + const struct dentry *dentry, + struct buffer_head *bh) +{ + struct inode *inode = dentry->d_inode; + struct gfs2_inode *ip = GFS2_I(inode); + int error; + + error = gfs2_dir_del(dip, dentry); + if (error) + return error; + + ip->i_entries = 0; + inode->i_ctime = CURRENT_TIME; + if (S_ISDIR(inode->i_mode)) + clear_nlink(inode); + else + drop_nlink(inode); + gfs2_trans_add_bh(ip->i_gl, bh, 1); + gfs2_dinode_out(ip, bh->b_data); + mark_inode_dirty(inode); + if (inode->i_nlink == 0) + gfs2_unlink_di(inode); + return 0; +} + + +/** + * gfs2_unlink - Unlink an inode (this does rmdir as well) + * @dir: The inode of the directory containing the inode to unlink * @dentry: The file itself * - * Unlink a file. Call gfs2_unlinki() + * This routine uses the type of the inode as a flag to figure out + * whether this is an unlink or an rmdir. * * Returns: errno */ @@ -325,7 +366,9 @@ static int gfs2_unlink(struct inode *dir, struct dentry *dentry) { struct gfs2_inode *dip = GFS2_I(dir); struct gfs2_sbd *sdp = GFS2_SB(dir); - struct gfs2_inode *ip = GFS2_I(dentry->d_inode); + struct inode *inode = dentry->d_inode; + struct gfs2_inode *ip = GFS2_I(inode); + struct buffer_head *bh; struct gfs2_holder ghs[3]; struct gfs2_rgrpd *rgd; struct gfs2_holder ri_gh; @@ -351,9 +394,15 @@ static int gfs2_unlink(struct inode *dir, struct dentry *dentry) goto out_child; error = -ENOENT; - if (ip->i_inode.i_nlink == 0) + if (inode->i_nlink == 0) goto out_rgrp; + if (S_ISDIR(inode->i_mode)) { + error = -ENOTEMPTY; + if (ip->i_entries > 2 || inode->i_nlink > 2) + goto out_rgrp; + } + error = gfs2_glock_nq(ghs + 2); /* rgrp */ if (error) goto out_rgrp; @@ -362,15 +411,16 @@ static int gfs2_unlink(struct inode *dir, struct dentry *dentry) if (error) goto out_gunlock; - error = gfs2_trans_begin(sdp, 2*RES_DINODE + RES_LEAF + RES_RG_BIT, 0); + error = gfs2_trans_begin(sdp, 2*RES_DINODE + 3*RES_LEAF + RES_RG_BIT, 0); if (error) goto out_gunlock; - error = gfs2_dir_del(dip, &dentry->d_name); - if (error) - goto out_end_trans; + error = gfs2_meta_inode_buffer(ip, &bh); + if (error) + goto out_end_trans; - error = gfs2_change_nlink(ip, -1); + error = gfs2_unlink_inode(dip, dentry, bh); + brelse(bh); out_end_trans: gfs2_trans_end(sdp); @@ -522,138 +572,6 @@ static int gfs2_mkdir(struct inode *dir, struct dentry *dentry, int mode) } /** - * gfs2_rmdiri - Remove a directory - * @dip: The parent directory of the directory to be removed - * @name: The name of the directory to be removed - * @ip: The GFS2 inode of the directory to be removed - * - * Assumes Glocks on dip and ip are held - * - * Returns: errno - */ - -static int gfs2_rmdiri(struct gfs2_inode *dip, const struct qstr *name, - struct gfs2_inode *ip) -{ - int error; - - if (ip->i_entries != 2) { - if (gfs2_consist_inode(ip)) - gfs2_dinode_print(ip); - return -EIO; - } - - error = gfs2_dir_del(dip, name); - if (error) - return error; - - error = gfs2_change_nlink(dip, -1); - if (error) - return error; - - error = gfs2_dir_del(ip, &gfs2_qdot); - if (error) - return error; - - error = gfs2_dir_del(ip, &gfs2_qdotdot); - if (error) - return error; - - /* It looks odd, but it really should be done twice */ - error = gfs2_change_nlink(ip, -1); - if (error) - return error; - - error = gfs2_change_nlink(ip, -1); - if (error) - return error; - - return error; -} - -/** - * gfs2_rmdir - Remove a directory - * @dir: The parent directory of the directory to be removed - * @dentry: The dentry of the directory to remove - * - * Remove a directory. Call gfs2_rmdiri() - * - * Returns: errno - */ - -static int gfs2_rmdir(struct inode *dir, struct dentry *dentry) -{ - struct gfs2_inode *dip = GFS2_I(dir); - struct gfs2_sbd *sdp = GFS2_SB(dir); - struct gfs2_inode *ip = GFS2_I(dentry->d_inode); - struct gfs2_holder ghs[3]; - struct gfs2_rgrpd *rgd; - struct gfs2_holder ri_gh; - int error; - - error = gfs2_rindex_hold(sdp, &ri_gh); - if (error) - return error; - gfs2_holder_init(dip->i_gl, LM_ST_EXCLUSIVE, 0, ghs); - gfs2_holder_init(ip->i_gl, LM_ST_EXCLUSIVE, 0, ghs + 1); - - rgd = gfs2_blk2rgrpd(sdp, ip->i_no_addr); - gfs2_holder_init(rgd->rd_gl, LM_ST_EXCLUSIVE, 0, ghs + 2); - - error = gfs2_glock_nq(ghs); /* parent */ - if (error) - goto out_parent; - - error = gfs2_glock_nq(ghs + 1); /* child */ - if (error) - goto out_child; - - error = -ENOENT; - if (ip->i_inode.i_nlink == 0) - goto out_rgrp; - - error = gfs2_glock_nq(ghs + 2); /* rgrp */ - if (error) - goto out_rgrp; - - error = gfs2_unlink_ok(dip, &dentry->d_name, ip); - if (error) - goto out_gunlock; - - if (ip->i_entries < 2) { - if (gfs2_consist_inode(ip)) - gfs2_dinode_print(ip); - error = -EIO; - goto out_gunlock; - } - if (ip->i_entries > 2) { - error = -ENOTEMPTY; - goto out_gunlock; - } - - error = gfs2_trans_begin(sdp, 2 * RES_DINODE + 3 * RES_LEAF + RES_RG_BIT, 0); - if (error) - goto out_gunlock; - - error = gfs2_rmdiri(dip, &dentry->d_name, ip); - - gfs2_trans_end(sdp); - -out_gunlock: - gfs2_glock_dq(ghs + 2); -out_rgrp: - gfs2_holder_uninit(ghs + 2); - gfs2_glock_dq(ghs + 1); -out_child: - gfs2_holder_uninit(ghs + 1); - gfs2_glock_dq(ghs); -out_parent: - gfs2_holder_uninit(ghs); - gfs2_glock_dq_uninit(&ri_gh); - return error; -} - -/** * gfs2_mknod - Make a special file * @dir: The directory in which the special file will reside * @dentry: The dentry of the special file @@ -930,25 +848,18 @@ static int gfs2_rename(struct inode *odir, struct dentry *odentry, /* Remove the target file, if it exists */ if (nip) { - if (S_ISDIR(nip->i_inode.i_mode)) - error = gfs2_rmdiri(ndip, &ndentry->d_name, nip); - else { - error = gfs2_dir_del(ndip, &ndentry->d_name); - if (error) - goto out_end_trans; - error = gfs2_change_nlink(nip, -1); - } + struct buffer_head *bh; + error = gfs2_meta_inode_buffer(nip, &bh); if (error) goto out_end_trans; + error = gfs2_unlink_inode(ndip, ndentry, bh); + brelse(bh); } if (dir_rename) { error = gfs2_change_nlink(ndip, +1); if (error) goto out_end_trans; - error = gfs2_change_nlink(odip, -1); - if (error) - goto out_end_trans; error = gfs2_dir_mvino(ip, &gfs2_qdotdot, ndip, DT_DIR); if (error) @@ -964,7 +875,7 @@ static int gfs2_rename(struct inode *odir, struct dentry *odentry, brelse(dibh); } - error = gfs2_dir_del(odip, &odentry->d_name); + error = gfs2_dir_del(odip, odentry); if (error) goto out_end_trans; @@ -1347,7 +1258,7 @@ const struct inode_operations gfs2_dir_iops = { .unlink = gfs2_unlink, .symlink = gfs2_symlink, .mkdir = gfs2_mkdir, - .rmdir = gfs2_rmdir, + .rmdir = gfs2_unlink, .mknod = gfs2_mknod, .rename = gfs2_rename, .permission = gfs2_permission, -- cgit v0.10.2 From 3d6ecb7d16fd4248fce58387a982a0756ad3fcc2 Mon Sep 17 00:00:00 2001 From: Steven Whitehouse Date: Mon, 9 May 2011 13:30:08 +0100 Subject: GFS2: When adding a new dir entry, inc link count if it is a subdir This adds an increment of the link count when we add a new directory entry, if that entry is itself a directory. This means that we no longer need separate code to perform this operation. Now that both adding and removing directory entries automatically update the parent directory's link count if required, that makes the code shorter and simpler than before. Signed-off-by: Steven Whitehouse diff --git a/fs/gfs2/dir.c b/fs/gfs2/dir.c index 4102651..091ee47 100644 --- a/fs/gfs2/dir.c +++ b/fs/gfs2/dir.c @@ -1597,7 +1597,7 @@ static int dir_new_leaf(struct inode *inode, const struct qstr *name) */ int gfs2_dir_add(struct inode *inode, const struct qstr *name, - const struct gfs2_inode *nip, unsigned type) + const struct gfs2_inode *nip) { struct gfs2_inode *ip = GFS2_I(inode); struct buffer_head *bh; @@ -1613,7 +1613,7 @@ int gfs2_dir_add(struct inode *inode, const struct qstr *name, return PTR_ERR(dent); dent = gfs2_init_dirent(inode, dent, name, bh); gfs2_inum_out(nip, dent); - dent->de_type = cpu_to_be16(type); + dent->de_type = cpu_to_be16(IF2DT(nip->i_inode.i_mode)); if (ip->i_diskflags & GFS2_DIF_EXHASH) { leaf = (struct gfs2_leaf *)bh->b_data; be16_add_cpu(&leaf->lf_entries, 1); @@ -1625,6 +1625,8 @@ int gfs2_dir_add(struct inode *inode, const struct qstr *name, gfs2_trans_add_bh(ip->i_gl, bh, 1); ip->i_entries++; ip->i_inode.i_mtime = ip->i_inode.i_ctime = CURRENT_TIME; + if (S_ISDIR(nip->i_inode.i_mode)) + inc_nlink(&ip->i_inode); gfs2_dinode_out(ip, bh->b_data); brelse(bh); error = 0; diff --git a/fs/gfs2/dir.h b/fs/gfs2/dir.h index 66831f1..e686af1 100644 --- a/fs/gfs2/dir.h +++ b/fs/gfs2/dir.h @@ -22,7 +22,7 @@ extern struct inode *gfs2_dir_search(struct inode *dir, extern int gfs2_dir_check(struct inode *dir, const struct qstr *filename, const struct gfs2_inode *ip); extern int gfs2_dir_add(struct inode *inode, const struct qstr *filename, - const struct gfs2_inode *ip, unsigned int type); + const struct gfs2_inode *ip); extern int gfs2_dir_del(struct gfs2_inode *dip, const struct dentry *dentry); extern int gfs2_dir_read(struct inode *inode, u64 *offset, void *opaque, filldir_t filldir); diff --git a/fs/gfs2/inode.c b/fs/gfs2/inode.c index 5a02606..a8c14c9 100644 --- a/fs/gfs2/inode.c +++ b/fs/gfs2/inode.c @@ -362,52 +362,6 @@ int gfs2_inode_refresh(struct gfs2_inode *ip) return error; } -/** - * gfs2_change_nlink - Change nlink count on inode - * @ip: The GFS2 inode - * @diff: The change in the nlink count required - * - * Returns: errno - */ -int gfs2_change_nlink(struct gfs2_inode *ip, int diff) -{ - struct buffer_head *dibh; - u32 nlink; - int error; - - BUG_ON(diff != 1 && diff != -1); - nlink = ip->i_inode.i_nlink + diff; - - /* If we are reducing the nlink count, but the new value ends up being - bigger than the old one, we must have underflowed. */ - if (diff < 0 && nlink > ip->i_inode.i_nlink) { - if (gfs2_consist_inode(ip)) - gfs2_dinode_print(ip); - return -EIO; - } - - error = gfs2_meta_inode_buffer(ip, &dibh); - if (error) - return error; - - if (diff > 0) - inc_nlink(&ip->i_inode); - else - drop_nlink(&ip->i_inode); - - ip->i_inode.i_ctime = CURRENT_TIME; - - gfs2_trans_add_bh(ip->i_gl, dibh, 1); - gfs2_dinode_out(ip, dibh->b_data); - brelse(dibh); - mark_inode_dirty(&ip->i_inode); - - if (ip->i_inode.i_nlink == 0) - gfs2_unlink_di(&ip->i_inode); /* mark inode unlinked */ - - return error; -} - struct inode *gfs2_lookup_simple(struct inode *dip, const char *name) { struct qstr qstr; @@ -723,7 +677,7 @@ static int link_dinode(struct gfs2_inode *dip, const struct qstr *name, goto fail_quota_locks; } - error = gfs2_dir_add(&dip->i_inode, name, ip, IF2DT(ip->i_inode.i_mode)); + error = gfs2_dir_add(&dip->i_inode, name, ip); if (error) goto fail_end_trans; diff --git a/fs/gfs2/inode.h b/fs/gfs2/inode.h index 8d1344a..f9b8289 100644 --- a/fs/gfs2/inode.h +++ b/fs/gfs2/inode.h @@ -106,7 +106,6 @@ extern struct inode *gfs2_ilookup(struct super_block *sb, u64 no_addr, int nonbl extern int gfs2_inode_refresh(struct gfs2_inode *ip); -extern int gfs2_change_nlink(struct gfs2_inode *ip, int diff); extern struct inode *gfs2_lookupi(struct inode *dir, const struct qstr *name, int is_root); extern struct inode *gfs2_createi(struct gfs2_holder *ghs, diff --git a/fs/gfs2/ops_inode.c b/fs/gfs2/ops_inode.c index 765da06..6b8c2bd 100644 --- a/fs/gfs2/ops_inode.c +++ b/fs/gfs2/ops_inode.c @@ -235,7 +235,7 @@ static int gfs2_link(struct dentry *old_dentry, struct inode *dir, if (error) goto out_end_trans; - error = gfs2_dir_add(dir, &dentry->d_name, ip, IF2DT(inode->i_mode)); + error = gfs2_dir_add(dir, &dentry->d_name, ip); if (error) goto out_brelse; @@ -554,9 +554,6 @@ static int gfs2_mkdir(struct inode *dir, struct dentry *dentry, int mode) brelse(dibh); } - error = gfs2_change_nlink(dip, +1); - gfs2_assert_withdraw(sdp, !error); /* dip already pinned */ - gfs2_trans_end(sdp); if (dip->i_alloc->al_rgd) gfs2_inplace_release(dip); @@ -857,10 +854,6 @@ static int gfs2_rename(struct inode *odir, struct dentry *odentry, } if (dir_rename) { - error = gfs2_change_nlink(ndip, +1); - if (error) - goto out_end_trans; - error = gfs2_dir_mvino(ip, &gfs2_qdotdot, ndip, DT_DIR); if (error) goto out_end_trans; @@ -879,7 +872,7 @@ static int gfs2_rename(struct inode *odir, struct dentry *odentry, if (error) goto out_end_trans; - error = gfs2_dir_add(ndir, &ndentry->d_name, ip, IF2DT(ip->i_inode.i_mode)); + error = gfs2_dir_add(ndir, &ndentry->d_name, ip); if (error) goto out_end_trans; -- cgit v0.10.2 From 94fb763b1a76a2000ad21f3119b05c90040acaf0 Mon Sep 17 00:00:00 2001 From: Steven Whitehouse Date: Mon, 9 May 2011 13:36:10 +0100 Subject: GFS2: Remove gfs2_dinode_print() function This function was intended for debugging purposes, but it is not very useful. If we want to know what is on disk then all we need is a block number and gfs2_edit can give us much better information about what is there. Otherwise, if we are interested in what is stored in the in-core inode, it doesn't help us out there either. Signed-off-by: Steven Whitehouse diff --git a/fs/gfs2/inode.c b/fs/gfs2/inode.c index a8c14c9..7c2121f 100644 --- a/fs/gfs2/inode.c +++ b/fs/gfs2/inode.c @@ -329,8 +329,7 @@ static int gfs2_dinode_in(struct gfs2_inode *ip, const void *buf) return 0; corrupt: - if (gfs2_consist_inode(ip)) - gfs2_dinode_print(ip); + gfs2_consist_inode(ip); return -EIO; } @@ -901,24 +900,3 @@ void gfs2_dinode_out(const struct gfs2_inode *ip, void *buf) str->di_mtime_nsec = cpu_to_be32(ip->i_inode.i_mtime.tv_nsec); str->di_ctime_nsec = cpu_to_be32(ip->i_inode.i_ctime.tv_nsec); } - -void gfs2_dinode_print(const struct gfs2_inode *ip) -{ - printk(KERN_INFO " no_formal_ino = %llu\n", - (unsigned long long)ip->i_no_formal_ino); - printk(KERN_INFO " no_addr = %llu\n", - (unsigned long long)ip->i_no_addr); - printk(KERN_INFO " i_size = %llu\n", - (unsigned long long)i_size_read(&ip->i_inode)); - printk(KERN_INFO " blocks = %llu\n", - (unsigned long long)gfs2_get_inode_blocks(&ip->i_inode)); - printk(KERN_INFO " i_goal = %llu\n", - (unsigned long long)ip->i_goal); - printk(KERN_INFO " i_diskflags = 0x%.8X\n", ip->i_diskflags); - printk(KERN_INFO " i_height = %u\n", ip->i_height); - printk(KERN_INFO " i_depth = %u\n", ip->i_depth); - printk(KERN_INFO " i_entries = %u\n", ip->i_entries); - printk(KERN_INFO " i_eattr = %llu\n", - (unsigned long long)ip->i_eattr); -} - diff --git a/fs/gfs2/inode.h b/fs/gfs2/inode.h index f9b8289..7ed60aa 100644 --- a/fs/gfs2/inode.h +++ b/fs/gfs2/inode.h @@ -115,7 +115,6 @@ extern int gfs2_permission(struct inode *inode, int mask, unsigned int flags); extern int gfs2_setattr_simple(struct gfs2_inode *ip, struct iattr *attr); extern struct inode *gfs2_lookup_simple(struct inode *dip, const char *name); extern void gfs2_dinode_out(const struct gfs2_inode *ip, void *buf); -extern void gfs2_dinode_print(const struct gfs2_inode *ip); extern const struct inode_operations gfs2_file_iops; extern const struct inode_operations gfs2_dir_iops; diff --git a/fs/gfs2/ops_inode.c b/fs/gfs2/ops_inode.c index 6b8c2bd..2607c2c 100644 --- a/fs/gfs2/ops_inode.c +++ b/fs/gfs2/ops_inode.c @@ -754,8 +754,7 @@ static int gfs2_rename(struct inode *odir, struct dentry *odentry, if (S_ISDIR(nip->i_inode.i_mode)) { if (nip->i_entries < 2) { - if (gfs2_consist_inode(nip)) - gfs2_dinode_print(nip); + gfs2_consist_inode(nip); error = -EIO; goto out_gunlock; } diff --git a/fs/gfs2/super.c b/fs/gfs2/super.c index 58fe3a4..3061ac6 100644 --- a/fs/gfs2/super.c +++ b/fs/gfs2/super.c @@ -1341,8 +1341,7 @@ static int gfs2_dinode_dealloc(struct gfs2_inode *ip) int error; if (gfs2_get_inode_blocks(&ip->i_inode) != 1) { - if (gfs2_consist_inode(ip)) - gfs2_dinode_print(ip); + gfs2_consist_inode(ip); return -EIO; } -- cgit v0.10.2 From d4b2cf1b0566eebfe39a6d70e9e4b5fa01ddaace Mon Sep 17 00:00:00 2001 From: Steven Whitehouse Date: Mon, 9 May 2011 13:49:59 +0100 Subject: GFS2: Move gfs2_refresh_inode() and friends into glops.c Eventually there will only be a single caller of this code, so lets move it where it can be made static at some future date. Signed-off-by: Steven Whitehouse diff --git a/fs/gfs2/glops.c b/fs/gfs2/glops.c index 7c1b08f..8ef70f4 100644 --- a/fs/gfs2/glops.c +++ b/fs/gfs2/glops.c @@ -252,6 +252,119 @@ static int inode_go_demote_ok(const struct gfs2_glock *gl) } /** + * gfs2_set_nlink - Set the inode's link count based on on-disk info + * @inode: The inode in question + * @nlink: The link count + * + * If the link count has hit zero, it must never be raised, whatever the + * on-disk inode might say. When new struct inodes are created the link + * count is set to 1, so that we can safely use this test even when reading + * in on disk information for the first time. + */ + +static void gfs2_set_nlink(struct inode *inode, u32 nlink) +{ + /* + * We will need to review setting the nlink count here in the + * light of the forthcoming ro bind mount work. This is a reminder + * to do that. + */ + if ((inode->i_nlink != nlink) && (inode->i_nlink != 0)) { + if (nlink == 0) + clear_nlink(inode); + else + inode->i_nlink = nlink; + } +} + +static int gfs2_dinode_in(struct gfs2_inode *ip, const void *buf) +{ + const struct gfs2_dinode *str = buf; + struct timespec atime; + u16 height, depth; + + if (unlikely(ip->i_no_addr != be64_to_cpu(str->di_num.no_addr))) + goto corrupt; + ip->i_no_formal_ino = be64_to_cpu(str->di_num.no_formal_ino); + ip->i_inode.i_mode = be32_to_cpu(str->di_mode); + ip->i_inode.i_rdev = 0; + switch (ip->i_inode.i_mode & S_IFMT) { + case S_IFBLK: + case S_IFCHR: + ip->i_inode.i_rdev = MKDEV(be32_to_cpu(str->di_major), + be32_to_cpu(str->di_minor)); + break; + }; + + ip->i_inode.i_uid = be32_to_cpu(str->di_uid); + ip->i_inode.i_gid = be32_to_cpu(str->di_gid); + gfs2_set_nlink(&ip->i_inode, be32_to_cpu(str->di_nlink)); + i_size_write(&ip->i_inode, be64_to_cpu(str->di_size)); + gfs2_set_inode_blocks(&ip->i_inode, be64_to_cpu(str->di_blocks)); + atime.tv_sec = be64_to_cpu(str->di_atime); + atime.tv_nsec = be32_to_cpu(str->di_atime_nsec); + if (timespec_compare(&ip->i_inode.i_atime, &atime) < 0) + ip->i_inode.i_atime = atime; + ip->i_inode.i_mtime.tv_sec = be64_to_cpu(str->di_mtime); + ip->i_inode.i_mtime.tv_nsec = be32_to_cpu(str->di_mtime_nsec); + ip->i_inode.i_ctime.tv_sec = be64_to_cpu(str->di_ctime); + ip->i_inode.i_ctime.tv_nsec = be32_to_cpu(str->di_ctime_nsec); + + ip->i_goal = be64_to_cpu(str->di_goal_meta); + ip->i_generation = be64_to_cpu(str->di_generation); + + ip->i_diskflags = be32_to_cpu(str->di_flags); + gfs2_set_inode_flags(&ip->i_inode); + height = be16_to_cpu(str->di_height); + if (unlikely(height > GFS2_MAX_META_HEIGHT)) + goto corrupt; + ip->i_height = (u8)height; + + depth = be16_to_cpu(str->di_depth); + if (unlikely(depth > GFS2_DIR_MAX_DEPTH)) + goto corrupt; + ip->i_depth = (u8)depth; + ip->i_entries = be32_to_cpu(str->di_entries); + + ip->i_eattr = be64_to_cpu(str->di_eattr); + if (S_ISREG(ip->i_inode.i_mode)) + gfs2_set_aops(&ip->i_inode); + + return 0; +corrupt: + gfs2_consist_inode(ip); + return -EIO; +} + +/** + * gfs2_inode_refresh - Refresh the incore copy of the dinode + * @ip: The GFS2 inode + * + * Returns: errno + */ + +int gfs2_inode_refresh(struct gfs2_inode *ip) +{ + struct buffer_head *dibh; + int error; + + error = gfs2_meta_inode_buffer(ip, &dibh); + if (error) + return error; + + if (gfs2_metatype_check(GFS2_SB(&ip->i_inode), dibh, GFS2_METATYPE_DI)) { + brelse(dibh); + return -EIO; + } + + error = gfs2_dinode_in(ip, dibh->b_data); + brelse(dibh); + clear_bit(GIF_INVALID, &ip->i_flags); + + return error; +} + +/** * inode_go_lock - operation done after an inode lock is locked by a process * @gl: the glock * @flags: diff --git a/fs/gfs2/inode.c b/fs/gfs2/inode.c index 7c2121f..5d48baf 100644 --- a/fs/gfs2/inode.c +++ b/fs/gfs2/inode.c @@ -35,11 +35,6 @@ #include "trans.h" #include "util.h" -struct gfs2_inum_range_host { - u64 ir_start; - u64 ir_length; -}; - struct gfs2_skip_data { u64 no_addr; int skipped; @@ -248,118 +243,6 @@ fail_iput: goto fail; } -/** - * gfs2_set_nlink - Set the inode's link count based on on-disk info - * @inode: The inode in question - * @nlink: The link count - * - * If the link count has hit zero, it must never be raised, whatever the - * on-disk inode might say. When new struct inodes are created the link - * count is set to 1, so that we can safely use this test even when reading - * in on disk information for the first time. - */ - -static void gfs2_set_nlink(struct inode *inode, u32 nlink) -{ - /* - * We will need to review setting the nlink count here in the - * light of the forthcoming ro bind mount work. This is a reminder - * to do that. - */ - if ((inode->i_nlink != nlink) && (inode->i_nlink != 0)) { - if (nlink == 0) - clear_nlink(inode); - else - inode->i_nlink = nlink; - } -} - -static int gfs2_dinode_in(struct gfs2_inode *ip, const void *buf) -{ - const struct gfs2_dinode *str = buf; - struct timespec atime; - u16 height, depth; - - if (unlikely(ip->i_no_addr != be64_to_cpu(str->di_num.no_addr))) - goto corrupt; - ip->i_no_formal_ino = be64_to_cpu(str->di_num.no_formal_ino); - ip->i_inode.i_mode = be32_to_cpu(str->di_mode); - ip->i_inode.i_rdev = 0; - switch (ip->i_inode.i_mode & S_IFMT) { - case S_IFBLK: - case S_IFCHR: - ip->i_inode.i_rdev = MKDEV(be32_to_cpu(str->di_major), - be32_to_cpu(str->di_minor)); - break; - }; - - ip->i_inode.i_uid = be32_to_cpu(str->di_uid); - ip->i_inode.i_gid = be32_to_cpu(str->di_gid); - gfs2_set_nlink(&ip->i_inode, be32_to_cpu(str->di_nlink)); - i_size_write(&ip->i_inode, be64_to_cpu(str->di_size)); - gfs2_set_inode_blocks(&ip->i_inode, be64_to_cpu(str->di_blocks)); - atime.tv_sec = be64_to_cpu(str->di_atime); - atime.tv_nsec = be32_to_cpu(str->di_atime_nsec); - if (timespec_compare(&ip->i_inode.i_atime, &atime) < 0) - ip->i_inode.i_atime = atime; - ip->i_inode.i_mtime.tv_sec = be64_to_cpu(str->di_mtime); - ip->i_inode.i_mtime.tv_nsec = be32_to_cpu(str->di_mtime_nsec); - ip->i_inode.i_ctime.tv_sec = be64_to_cpu(str->di_ctime); - ip->i_inode.i_ctime.tv_nsec = be32_to_cpu(str->di_ctime_nsec); - - ip->i_goal = be64_to_cpu(str->di_goal_meta); - ip->i_generation = be64_to_cpu(str->di_generation); - - ip->i_diskflags = be32_to_cpu(str->di_flags); - gfs2_set_inode_flags(&ip->i_inode); - height = be16_to_cpu(str->di_height); - if (unlikely(height > GFS2_MAX_META_HEIGHT)) - goto corrupt; - ip->i_height = (u8)height; - - depth = be16_to_cpu(str->di_depth); - if (unlikely(depth > GFS2_DIR_MAX_DEPTH)) - goto corrupt; - ip->i_depth = (u8)depth; - ip->i_entries = be32_to_cpu(str->di_entries); - - ip->i_eattr = be64_to_cpu(str->di_eattr); - if (S_ISREG(ip->i_inode.i_mode)) - gfs2_set_aops(&ip->i_inode); - - return 0; -corrupt: - gfs2_consist_inode(ip); - return -EIO; -} - -/** - * gfs2_inode_refresh - Refresh the incore copy of the dinode - * @ip: The GFS2 inode - * - * Returns: errno - */ - -int gfs2_inode_refresh(struct gfs2_inode *ip) -{ - struct buffer_head *dibh; - int error; - - error = gfs2_meta_inode_buffer(ip, &dibh); - if (error) - return error; - - if (gfs2_metatype_check(GFS2_SB(&ip->i_inode), dibh, GFS2_METATYPE_DI)) { - brelse(dibh); - return -EIO; - } - - error = gfs2_dinode_in(ip, dibh->b_data); - brelse(dibh); - clear_bit(GIF_INVALID, &ip->i_flags); - - return error; -} struct inode *gfs2_lookup_simple(struct inode *dip, const char *name) { -- cgit v0.10.2 From 194c011fc4650d0dd1eecbc35bc26045108aca51 Mon Sep 17 00:00:00 2001 From: Steven Whitehouse Date: Mon, 9 May 2011 14:06:38 +0100 Subject: GFS2: Move most of the remaining inode.c into ops_inode.c This is in preparation to remove inode.c and rename ops_inode.c to inode.c. Also most of the functions which were left in inode.c relate to the creation and lookup of inodes. I'm intending to work on consolidating some of that code, and its easier when its all in one place. Signed-off-by: Steven Whitehouse diff --git a/fs/gfs2/inode.c b/fs/gfs2/inode.c index 5d48baf..b95ee5d 100644 --- a/fs/gfs2/inode.c +++ b/fs/gfs2/inode.c @@ -35,717 +35,6 @@ #include "trans.h" #include "util.h" -struct gfs2_skip_data { - u64 no_addr; - int skipped; - int non_block; -}; - -static int iget_test(struct inode *inode, void *opaque) -{ - struct gfs2_inode *ip = GFS2_I(inode); - struct gfs2_skip_data *data = opaque; - - if (ip->i_no_addr == data->no_addr) { - if (data->non_block && - inode->i_state & (I_FREEING|I_CLEAR|I_WILL_FREE)) { - data->skipped = 1; - return 0; - } - return 1; - } - return 0; -} - -static int iget_set(struct inode *inode, void *opaque) -{ - struct gfs2_inode *ip = GFS2_I(inode); - struct gfs2_skip_data *data = opaque; - - if (data->skipped) - return -ENOENT; - inode->i_ino = (unsigned long)(data->no_addr); - ip->i_no_addr = data->no_addr; - return 0; -} - -struct inode *gfs2_ilookup(struct super_block *sb, u64 no_addr, int non_block) -{ - unsigned long hash = (unsigned long)no_addr; - struct gfs2_skip_data data; - - data.no_addr = no_addr; - data.skipped = 0; - data.non_block = non_block; - return ilookup5(sb, hash, iget_test, &data); -} - -static struct inode *gfs2_iget(struct super_block *sb, u64 no_addr, - int non_block) -{ - struct gfs2_skip_data data; - unsigned long hash = (unsigned long)no_addr; - - data.no_addr = no_addr; - data.skipped = 0; - data.non_block = non_block; - return iget5_locked(sb, hash, iget_test, iget_set, &data); -} - -/** - * gfs2_set_iop - Sets inode operations - * @inode: The inode with correct i_mode filled in - * - * GFS2 lookup code fills in vfs inode contents based on info obtained - * from directory entry inside gfs2_inode_lookup(). - */ - -static void gfs2_set_iop(struct inode *inode) -{ - struct gfs2_sbd *sdp = GFS2_SB(inode); - umode_t mode = inode->i_mode; - - if (S_ISREG(mode)) { - inode->i_op = &gfs2_file_iops; - if (gfs2_localflocks(sdp)) - inode->i_fop = &gfs2_file_fops_nolock; - else - inode->i_fop = &gfs2_file_fops; - } else if (S_ISDIR(mode)) { - inode->i_op = &gfs2_dir_iops; - if (gfs2_localflocks(sdp)) - inode->i_fop = &gfs2_dir_fops_nolock; - else - inode->i_fop = &gfs2_dir_fops; - } else if (S_ISLNK(mode)) { - inode->i_op = &gfs2_symlink_iops; - } else { - inode->i_op = &gfs2_file_iops; - init_special_inode(inode, inode->i_mode, inode->i_rdev); - } -} - -/** - * gfs2_inode_lookup - Lookup an inode - * @sb: The super block - * @no_addr: The inode number - * @type: The type of the inode - * non_block: Can we block on inodes that are being freed? - * - * Returns: A VFS inode, or an error - */ - -struct inode *gfs2_inode_lookup(struct super_block *sb, unsigned int type, - u64 no_addr, u64 no_formal_ino, int non_block) -{ - struct inode *inode; - struct gfs2_inode *ip; - struct gfs2_glock *io_gl = NULL; - int error; - - inode = gfs2_iget(sb, no_addr, non_block); - ip = GFS2_I(inode); - - if (!inode) - return ERR_PTR(-ENOBUFS); - - if (inode->i_state & I_NEW) { - struct gfs2_sbd *sdp = GFS2_SB(inode); - ip->i_no_formal_ino = no_formal_ino; - - error = gfs2_glock_get(sdp, no_addr, &gfs2_inode_glops, CREATE, &ip->i_gl); - if (unlikely(error)) - goto fail; - ip->i_gl->gl_object = ip; - - error = gfs2_glock_get(sdp, no_addr, &gfs2_iopen_glops, CREATE, &io_gl); - if (unlikely(error)) - goto fail_put; - - set_bit(GIF_INVALID, &ip->i_flags); - error = gfs2_glock_nq_init(io_gl, LM_ST_SHARED, GL_EXACT, &ip->i_iopen_gh); - if (unlikely(error)) - goto fail_iopen; - - ip->i_iopen_gh.gh_gl->gl_object = ip; - gfs2_glock_put(io_gl); - io_gl = NULL; - - if (type == DT_UNKNOWN) { - /* Inode glock must be locked already */ - error = gfs2_inode_refresh(GFS2_I(inode)); - if (error) - goto fail_refresh; - } else { - inode->i_mode = DT2IF(type); - } - - gfs2_set_iop(inode); - unlock_new_inode(inode); - } - - return inode; - -fail_refresh: - ip->i_iopen_gh.gh_gl->gl_object = NULL; - gfs2_glock_dq_uninit(&ip->i_iopen_gh); -fail_iopen: - if (io_gl) - gfs2_glock_put(io_gl); -fail_put: - ip->i_gl->gl_object = NULL; - gfs2_glock_put(ip->i_gl); -fail: - iget_failed(inode); - return ERR_PTR(error); -} - -struct inode *gfs2_lookup_by_inum(struct gfs2_sbd *sdp, u64 no_addr, - u64 *no_formal_ino, unsigned int blktype) -{ - struct super_block *sb = sdp->sd_vfs; - struct gfs2_holder i_gh; - struct inode *inode = NULL; - int error; - - /* Must not read in block until block type is verified */ - error = gfs2_glock_nq_num(sdp, no_addr, &gfs2_inode_glops, - LM_ST_EXCLUSIVE, GL_SKIP, &i_gh); - if (error) - return ERR_PTR(error); - - error = gfs2_check_blk_type(sdp, no_addr, blktype); - if (error) - goto fail; - - inode = gfs2_inode_lookup(sb, DT_UNKNOWN, no_addr, 0, 1); - if (IS_ERR(inode)) - goto fail; - - /* Two extra checks for NFS only */ - if (no_formal_ino) { - error = -ESTALE; - if (GFS2_I(inode)->i_no_formal_ino != *no_formal_ino) - goto fail_iput; - - error = -EIO; - if (GFS2_I(inode)->i_diskflags & GFS2_DIF_SYSTEM) - goto fail_iput; - - error = 0; - } - -fail: - gfs2_glock_dq_uninit(&i_gh); - return error ? ERR_PTR(error) : inode; -fail_iput: - iput(inode); - goto fail; -} - - -struct inode *gfs2_lookup_simple(struct inode *dip, const char *name) -{ - struct qstr qstr; - struct inode *inode; - gfs2_str2qstr(&qstr, name); - inode = gfs2_lookupi(dip, &qstr, 1); - /* gfs2_lookupi has inconsistent callers: vfs - * related routines expect NULL for no entry found, - * gfs2_lookup_simple callers expect ENOENT - * and do not check for NULL. - */ - if (inode == NULL) - return ERR_PTR(-ENOENT); - else - return inode; -} - - -/** - * gfs2_lookupi - Look up a filename in a directory and return its inode - * @d_gh: An initialized holder for the directory glock - * @name: The name of the inode to look for - * @is_root: If 1, ignore the caller's permissions - * @i_gh: An uninitialized holder for the new inode glock - * - * This can be called via the VFS filldir function when NFS is doing - * a readdirplus and the inode which its intending to stat isn't - * already in cache. In this case we must not take the directory glock - * again, since the readdir call will have already taken that lock. - * - * Returns: errno - */ - -struct inode *gfs2_lookupi(struct inode *dir, const struct qstr *name, - int is_root) -{ - struct super_block *sb = dir->i_sb; - struct gfs2_inode *dip = GFS2_I(dir); - struct gfs2_holder d_gh; - int error = 0; - struct inode *inode = NULL; - int unlock = 0; - - if (!name->len || name->len > GFS2_FNAMESIZE) - return ERR_PTR(-ENAMETOOLONG); - - if ((name->len == 1 && memcmp(name->name, ".", 1) == 0) || - (name->len == 2 && memcmp(name->name, "..", 2) == 0 && - dir == sb->s_root->d_inode)) { - igrab(dir); - return dir; - } - - if (gfs2_glock_is_locked_by_me(dip->i_gl) == NULL) { - error = gfs2_glock_nq_init(dip->i_gl, LM_ST_SHARED, 0, &d_gh); - if (error) - return ERR_PTR(error); - unlock = 1; - } - - if (!is_root) { - error = gfs2_permission(dir, MAY_EXEC, 0); - if (error) - goto out; - } - - inode = gfs2_dir_search(dir, name); - if (IS_ERR(inode)) - error = PTR_ERR(inode); -out: - if (unlock) - gfs2_glock_dq_uninit(&d_gh); - if (error == -ENOENT) - return NULL; - return inode ? inode : ERR_PTR(error); -} - -/** - * create_ok - OK to create a new on-disk inode here? - * @dip: Directory in which dinode is to be created - * @name: Name of new dinode - * @mode: - * - * Returns: errno - */ - -static int create_ok(struct gfs2_inode *dip, const struct qstr *name, - unsigned int mode) -{ - int error; - - error = gfs2_permission(&dip->i_inode, MAY_WRITE | MAY_EXEC, 0); - if (error) - return error; - - /* Don't create entries in an unlinked directory */ - if (!dip->i_inode.i_nlink) - return -ENOENT; - - error = gfs2_dir_check(&dip->i_inode, name, NULL); - switch (error) { - case -ENOENT: - error = 0; - break; - case 0: - return -EEXIST; - default: - return error; - } - - if (dip->i_entries == (u32)-1) - return -EFBIG; - if (S_ISDIR(mode) && dip->i_inode.i_nlink == (u32)-1) - return -EMLINK; - - return 0; -} - -static void munge_mode_uid_gid(struct gfs2_inode *dip, unsigned int *mode, - unsigned int *uid, unsigned int *gid) -{ - if (GFS2_SB(&dip->i_inode)->sd_args.ar_suiddir && - (dip->i_inode.i_mode & S_ISUID) && dip->i_inode.i_uid) { - if (S_ISDIR(*mode)) - *mode |= S_ISUID; - else if (dip->i_inode.i_uid != current_fsuid()) - *mode &= ~07111; - *uid = dip->i_inode.i_uid; - } else - *uid = current_fsuid(); - - if (dip->i_inode.i_mode & S_ISGID) { - if (S_ISDIR(*mode)) - *mode |= S_ISGID; - *gid = dip->i_inode.i_gid; - } else - *gid = current_fsgid(); -} - -static int alloc_dinode(struct gfs2_inode *dip, u64 *no_addr, u64 *generation) -{ - struct gfs2_sbd *sdp = GFS2_SB(&dip->i_inode); - int error; - - if (gfs2_alloc_get(dip) == NULL) - return -ENOMEM; - - dip->i_alloc->al_requested = RES_DINODE; - error = gfs2_inplace_reserve(dip); - if (error) - goto out; - - error = gfs2_trans_begin(sdp, RES_RG_BIT + RES_STATFS, 0); - if (error) - goto out_ipreserv; - - error = gfs2_alloc_di(dip, no_addr, generation); - - gfs2_trans_end(sdp); - -out_ipreserv: - gfs2_inplace_release(dip); -out: - gfs2_alloc_put(dip); - return error; -} - -/** - * init_dinode - Fill in a new dinode structure - * @dip: the directory this inode is being created in - * @gl: The glock covering the new inode - * @inum: the inode number - * @mode: the file permissions - * @uid: - * @gid: - * - */ - -static void init_dinode(struct gfs2_inode *dip, struct gfs2_glock *gl, - const struct gfs2_inum_host *inum, unsigned int mode, - unsigned int uid, unsigned int gid, - const u64 *generation, dev_t dev, struct buffer_head **bhp) -{ - struct gfs2_sbd *sdp = GFS2_SB(&dip->i_inode); - struct gfs2_dinode *di; - struct buffer_head *dibh; - struct timespec tv = CURRENT_TIME; - - dibh = gfs2_meta_new(gl, inum->no_addr); - gfs2_trans_add_bh(gl, dibh, 1); - gfs2_metatype_set(dibh, GFS2_METATYPE_DI, GFS2_FORMAT_DI); - gfs2_buffer_clear_tail(dibh, sizeof(struct gfs2_dinode)); - di = (struct gfs2_dinode *)dibh->b_data; - - di->di_num.no_formal_ino = cpu_to_be64(inum->no_formal_ino); - di->di_num.no_addr = cpu_to_be64(inum->no_addr); - di->di_mode = cpu_to_be32(mode); - di->di_uid = cpu_to_be32(uid); - di->di_gid = cpu_to_be32(gid); - di->di_nlink = 0; - di->di_size = 0; - di->di_blocks = cpu_to_be64(1); - di->di_atime = di->di_mtime = di->di_ctime = cpu_to_be64(tv.tv_sec); - di->di_major = cpu_to_be32(MAJOR(dev)); - di->di_minor = cpu_to_be32(MINOR(dev)); - di->di_goal_meta = di->di_goal_data = cpu_to_be64(inum->no_addr); - di->di_generation = cpu_to_be64(*generation); - di->di_flags = 0; - - if (S_ISREG(mode)) { - if ((dip->i_diskflags & GFS2_DIF_INHERIT_JDATA) || - gfs2_tune_get(sdp, gt_new_files_jdata)) - di->di_flags |= cpu_to_be32(GFS2_DIF_JDATA); - } else if (S_ISDIR(mode)) { - di->di_flags |= cpu_to_be32(dip->i_diskflags & - GFS2_DIF_INHERIT_JDATA); - } - - di->__pad1 = 0; - di->di_payload_format = cpu_to_be32(S_ISDIR(mode) ? GFS2_FORMAT_DE : 0); - di->di_height = 0; - di->__pad2 = 0; - di->__pad3 = 0; - di->di_depth = 0; - di->di_entries = 0; - memset(&di->__pad4, 0, sizeof(di->__pad4)); - di->di_eattr = 0; - di->di_atime_nsec = cpu_to_be32(tv.tv_nsec); - di->di_mtime_nsec = cpu_to_be32(tv.tv_nsec); - di->di_ctime_nsec = cpu_to_be32(tv.tv_nsec); - memset(&di->di_reserved, 0, sizeof(di->di_reserved)); - - set_buffer_uptodate(dibh); - - *bhp = dibh; -} - -static int make_dinode(struct gfs2_inode *dip, struct gfs2_glock *gl, - unsigned int mode, const struct gfs2_inum_host *inum, - const u64 *generation, dev_t dev, struct buffer_head **bhp) -{ - struct gfs2_sbd *sdp = GFS2_SB(&dip->i_inode); - unsigned int uid, gid; - int error; - - munge_mode_uid_gid(dip, &mode, &uid, &gid); - if (!gfs2_alloc_get(dip)) - return -ENOMEM; - - error = gfs2_quota_lock(dip, uid, gid); - if (error) - goto out; - - error = gfs2_quota_check(dip, uid, gid); - if (error) - goto out_quota; - - error = gfs2_trans_begin(sdp, RES_DINODE + RES_QUOTA, 0); - if (error) - goto out_quota; - - init_dinode(dip, gl, inum, mode, uid, gid, generation, dev, bhp); - gfs2_quota_change(dip, +1, uid, gid); - gfs2_trans_end(sdp); - -out_quota: - gfs2_quota_unlock(dip); -out: - gfs2_alloc_put(dip); - return error; -} - -static int link_dinode(struct gfs2_inode *dip, const struct qstr *name, - struct gfs2_inode *ip) -{ - struct gfs2_sbd *sdp = GFS2_SB(&dip->i_inode); - struct gfs2_alloc *al; - int alloc_required; - struct buffer_head *dibh; - int error; - - al = gfs2_alloc_get(dip); - if (!al) - return -ENOMEM; - - error = gfs2_quota_lock(dip, NO_QUOTA_CHANGE, NO_QUOTA_CHANGE); - if (error) - goto fail; - - error = alloc_required = gfs2_diradd_alloc_required(&dip->i_inode, name); - if (alloc_required < 0) - goto fail_quota_locks; - if (alloc_required) { - error = gfs2_quota_check(dip, dip->i_inode.i_uid, dip->i_inode.i_gid); - if (error) - goto fail_quota_locks; - - al->al_requested = sdp->sd_max_dirres; - - error = gfs2_inplace_reserve(dip); - if (error) - goto fail_quota_locks; - - error = gfs2_trans_begin(sdp, sdp->sd_max_dirres + - al->al_rgd->rd_length + - 2 * RES_DINODE + - RES_STATFS + RES_QUOTA, 0); - if (error) - goto fail_ipreserv; - } else { - error = gfs2_trans_begin(sdp, RES_LEAF + 2 * RES_DINODE, 0); - if (error) - goto fail_quota_locks; - } - - error = gfs2_dir_add(&dip->i_inode, name, ip); - if (error) - goto fail_end_trans; - - error = gfs2_meta_inode_buffer(ip, &dibh); - if (error) - goto fail_end_trans; - ip->i_inode.i_nlink = 1; - gfs2_trans_add_bh(ip->i_gl, dibh, 1); - gfs2_dinode_out(ip, dibh->b_data); - brelse(dibh); - return 0; - -fail_end_trans: - gfs2_trans_end(sdp); - -fail_ipreserv: - if (dip->i_alloc->al_rgd) - gfs2_inplace_release(dip); - -fail_quota_locks: - gfs2_quota_unlock(dip); - -fail: - gfs2_alloc_put(dip); - return error; -} - -static int gfs2_security_init(struct gfs2_inode *dip, struct gfs2_inode *ip, - const struct qstr *qstr) -{ - int err; - size_t len; - void *value; - char *name; - - err = security_inode_init_security(&ip->i_inode, &dip->i_inode, qstr, - &name, &value, &len); - - if (err) { - if (err == -EOPNOTSUPP) - return 0; - return err; - } - - err = __gfs2_xattr_set(&ip->i_inode, name, value, len, 0, - GFS2_EATYPE_SECURITY); - kfree(value); - kfree(name); - - return err; -} - -/** - * gfs2_createi - Create a new inode - * @ghs: An array of two holders - * @name: The name of the new file - * @mode: the permissions on the new inode - * - * @ghs[0] is an initialized holder for the directory - * @ghs[1] is the holder for the inode lock - * - * If the return value is not NULL, the glocks on both the directory and the new - * file are held. A transaction has been started and an inplace reservation - * is held, as well. - * - * Returns: An inode - */ - -struct inode *gfs2_createi(struct gfs2_holder *ghs, const struct qstr *name, - unsigned int mode, dev_t dev) -{ - struct inode *inode = NULL; - struct gfs2_inode *dip = ghs->gh_gl->gl_object; - struct inode *dir = &dip->i_inode; - struct gfs2_sbd *sdp = GFS2_SB(&dip->i_inode); - struct gfs2_inum_host inum = { .no_addr = 0, .no_formal_ino = 0 }; - int error; - u64 generation; - struct buffer_head *bh = NULL; - - if (!name->len || name->len > GFS2_FNAMESIZE) - return ERR_PTR(-ENAMETOOLONG); - - gfs2_holder_reinit(LM_ST_EXCLUSIVE, 0, ghs); - error = gfs2_glock_nq(ghs); - if (error) - goto fail; - - error = create_ok(dip, name, mode); - if (error) - goto fail_gunlock; - - error = alloc_dinode(dip, &inum.no_addr, &generation); - if (error) - goto fail_gunlock; - inum.no_formal_ino = generation; - - error = gfs2_glock_nq_num(sdp, inum.no_addr, &gfs2_inode_glops, - LM_ST_EXCLUSIVE, GL_SKIP, ghs + 1); - if (error) - goto fail_gunlock; - - error = make_dinode(dip, ghs[1].gh_gl, mode, &inum, &generation, dev, &bh); - if (error) - goto fail_gunlock2; - - inode = gfs2_inode_lookup(dir->i_sb, IF2DT(mode), inum.no_addr, - inum.no_formal_ino, 0); - if (IS_ERR(inode)) - goto fail_gunlock2; - - error = gfs2_inode_refresh(GFS2_I(inode)); - if (error) - goto fail_gunlock2; - - error = gfs2_acl_create(dip, inode); - if (error) - goto fail_gunlock2; - - error = gfs2_security_init(dip, GFS2_I(inode), name); - if (error) - goto fail_gunlock2; - - error = link_dinode(dip, name, GFS2_I(inode)); - if (error) - goto fail_gunlock2; - - if (bh) - brelse(bh); - return inode; - -fail_gunlock2: - gfs2_glock_dq_uninit(ghs + 1); - if (inode && !IS_ERR(inode)) - iput(inode); -fail_gunlock: - gfs2_glock_dq(ghs); -fail: - if (bh) - brelse(bh); - return ERR_PTR(error); -} - -static int __gfs2_setattr_simple(struct gfs2_inode *ip, struct iattr *attr) -{ - struct inode *inode = &ip->i_inode; - struct buffer_head *dibh; - int error; - - error = gfs2_meta_inode_buffer(ip, &dibh); - if (error) - return error; - - setattr_copy(inode, attr); - mark_inode_dirty(inode); - gfs2_trans_add_bh(ip->i_gl, dibh, 1); - gfs2_dinode_out(ip, dibh->b_data); - brelse(dibh); - return 0; -} - -/** - * gfs2_setattr_simple - - * @ip: - * @attr: - * - * Called with a reference on the vnode. - * - * Returns: errno - */ - -int gfs2_setattr_simple(struct gfs2_inode *ip, struct iattr *attr) -{ - int error; - - if (current->journal_info) - return __gfs2_setattr_simple(ip, attr); - - error = gfs2_trans_begin(GFS2_SB(&ip->i_inode), RES_DINODE, 0); - if (error) - return error; - - error = __gfs2_setattr_simple(ip, attr); - gfs2_trans_end(GFS2_SB(&ip->i_inode)); - return error; -} void gfs2_dinode_out(const struct gfs2_inode *ip, void *buf) { diff --git a/fs/gfs2/ops_inode.c b/fs/gfs2/ops_inode.c index 2607c2c..a783a7a 100644 --- a/fs/gfs2/ops_inode.c +++ b/fs/gfs2/ops_inode.c @@ -18,6 +18,7 @@ #include #include #include +#include #include #include "gfs2.h" @@ -34,8 +35,676 @@ #include "trans.h" #include "util.h" #include "super.h" +#include "glops.h" + +struct gfs2_skip_data { + u64 no_addr; + int skipped; + int non_block; +}; + +static int iget_test(struct inode *inode, void *opaque) +{ + struct gfs2_inode *ip = GFS2_I(inode); + struct gfs2_skip_data *data = opaque; + + if (ip->i_no_addr == data->no_addr) { + if (data->non_block && + inode->i_state & (I_FREEING|I_CLEAR|I_WILL_FREE)) { + data->skipped = 1; + return 0; + } + return 1; + } + return 0; +} + +static int iget_set(struct inode *inode, void *opaque) +{ + struct gfs2_inode *ip = GFS2_I(inode); + struct gfs2_skip_data *data = opaque; + + if (data->skipped) + return -ENOENT; + inode->i_ino = (unsigned long)(data->no_addr); + ip->i_no_addr = data->no_addr; + return 0; +} + +struct inode *gfs2_ilookup(struct super_block *sb, u64 no_addr, int non_block) +{ + unsigned long hash = (unsigned long)no_addr; + struct gfs2_skip_data data; + + data.no_addr = no_addr; + data.skipped = 0; + data.non_block = non_block; + return ilookup5(sb, hash, iget_test, &data); +} + +static struct inode *gfs2_iget(struct super_block *sb, u64 no_addr, + int non_block) +{ + struct gfs2_skip_data data; + unsigned long hash = (unsigned long)no_addr; + + data.no_addr = no_addr; + data.skipped = 0; + data.non_block = non_block; + return iget5_locked(sb, hash, iget_test, iget_set, &data); +} /** + * gfs2_set_iop - Sets inode operations + * @inode: The inode with correct i_mode filled in + * + * GFS2 lookup code fills in vfs inode contents based on info obtained + * from directory entry inside gfs2_inode_lookup(). + */ + +static void gfs2_set_iop(struct inode *inode) +{ + struct gfs2_sbd *sdp = GFS2_SB(inode); + umode_t mode = inode->i_mode; + + if (S_ISREG(mode)) { + inode->i_op = &gfs2_file_iops; + if (gfs2_localflocks(sdp)) + inode->i_fop = &gfs2_file_fops_nolock; + else + inode->i_fop = &gfs2_file_fops; + } else if (S_ISDIR(mode)) { + inode->i_op = &gfs2_dir_iops; + if (gfs2_localflocks(sdp)) + inode->i_fop = &gfs2_dir_fops_nolock; + else + inode->i_fop = &gfs2_dir_fops; + } else if (S_ISLNK(mode)) { + inode->i_op = &gfs2_symlink_iops; + } else { + inode->i_op = &gfs2_file_iops; + init_special_inode(inode, inode->i_mode, inode->i_rdev); + } +} + +/** + * gfs2_inode_lookup - Lookup an inode + * @sb: The super block + * @no_addr: The inode number + * @type: The type of the inode + * non_block: Can we block on inodes that are being freed? + * + * Returns: A VFS inode, or an error + */ + +struct inode *gfs2_inode_lookup(struct super_block *sb, unsigned int type, + u64 no_addr, u64 no_formal_ino, int non_block) +{ + struct inode *inode; + struct gfs2_inode *ip; + struct gfs2_glock *io_gl = NULL; + int error; + + inode = gfs2_iget(sb, no_addr, non_block); + ip = GFS2_I(inode); + + if (!inode) + return ERR_PTR(-ENOBUFS); + + if (inode->i_state & I_NEW) { + struct gfs2_sbd *sdp = GFS2_SB(inode); + ip->i_no_formal_ino = no_formal_ino; + + error = gfs2_glock_get(sdp, no_addr, &gfs2_inode_glops, CREATE, &ip->i_gl); + if (unlikely(error)) + goto fail; + ip->i_gl->gl_object = ip; + + error = gfs2_glock_get(sdp, no_addr, &gfs2_iopen_glops, CREATE, &io_gl); + if (unlikely(error)) + goto fail_put; + + set_bit(GIF_INVALID, &ip->i_flags); + error = gfs2_glock_nq_init(io_gl, LM_ST_SHARED, GL_EXACT, &ip->i_iopen_gh); + if (unlikely(error)) + goto fail_iopen; + + ip->i_iopen_gh.gh_gl->gl_object = ip; + gfs2_glock_put(io_gl); + io_gl = NULL; + + if (type == DT_UNKNOWN) { + /* Inode glock must be locked already */ + error = gfs2_inode_refresh(GFS2_I(inode)); + if (error) + goto fail_refresh; + } else { + inode->i_mode = DT2IF(type); + } + + gfs2_set_iop(inode); + unlock_new_inode(inode); + } + + return inode; + +fail_refresh: + ip->i_iopen_gh.gh_gl->gl_object = NULL; + gfs2_glock_dq_uninit(&ip->i_iopen_gh); +fail_iopen: + if (io_gl) + gfs2_glock_put(io_gl); +fail_put: + ip->i_gl->gl_object = NULL; + gfs2_glock_put(ip->i_gl); +fail: + iget_failed(inode); + return ERR_PTR(error); +} + +struct inode *gfs2_lookup_by_inum(struct gfs2_sbd *sdp, u64 no_addr, + u64 *no_formal_ino, unsigned int blktype) +{ + struct super_block *sb = sdp->sd_vfs; + struct gfs2_holder i_gh; + struct inode *inode = NULL; + int error; + + /* Must not read in block until block type is verified */ + error = gfs2_glock_nq_num(sdp, no_addr, &gfs2_inode_glops, + LM_ST_EXCLUSIVE, GL_SKIP, &i_gh); + if (error) + return ERR_PTR(error); + + error = gfs2_check_blk_type(sdp, no_addr, blktype); + if (error) + goto fail; + + inode = gfs2_inode_lookup(sb, DT_UNKNOWN, no_addr, 0, 1); + if (IS_ERR(inode)) + goto fail; + + /* Two extra checks for NFS only */ + if (no_formal_ino) { + error = -ESTALE; + if (GFS2_I(inode)->i_no_formal_ino != *no_formal_ino) + goto fail_iput; + + error = -EIO; + if (GFS2_I(inode)->i_diskflags & GFS2_DIF_SYSTEM) + goto fail_iput; + + error = 0; + } + +fail: + gfs2_glock_dq_uninit(&i_gh); + return error ? ERR_PTR(error) : inode; +fail_iput: + iput(inode); + goto fail; +} + + +struct inode *gfs2_lookup_simple(struct inode *dip, const char *name) +{ + struct qstr qstr; + struct inode *inode; + gfs2_str2qstr(&qstr, name); + inode = gfs2_lookupi(dip, &qstr, 1); + /* gfs2_lookupi has inconsistent callers: vfs + * related routines expect NULL for no entry found, + * gfs2_lookup_simple callers expect ENOENT + * and do not check for NULL. + */ + if (inode == NULL) + return ERR_PTR(-ENOENT); + else + return inode; +} + + +/** + * gfs2_lookupi - Look up a filename in a directory and return its inode + * @d_gh: An initialized holder for the directory glock + * @name: The name of the inode to look for + * @is_root: If 1, ignore the caller's permissions + * @i_gh: An uninitialized holder for the new inode glock + * + * This can be called via the VFS filldir function when NFS is doing + * a readdirplus and the inode which its intending to stat isn't + * already in cache. In this case we must not take the directory glock + * again, since the readdir call will have already taken that lock. + * + * Returns: errno + */ + +struct inode *gfs2_lookupi(struct inode *dir, const struct qstr *name, + int is_root) +{ + struct super_block *sb = dir->i_sb; + struct gfs2_inode *dip = GFS2_I(dir); + struct gfs2_holder d_gh; + int error = 0; + struct inode *inode = NULL; + int unlock = 0; + + if (!name->len || name->len > GFS2_FNAMESIZE) + return ERR_PTR(-ENAMETOOLONG); + + if ((name->len == 1 && memcmp(name->name, ".", 1) == 0) || + (name->len == 2 && memcmp(name->name, "..", 2) == 0 && + dir == sb->s_root->d_inode)) { + igrab(dir); + return dir; + } + + if (gfs2_glock_is_locked_by_me(dip->i_gl) == NULL) { + error = gfs2_glock_nq_init(dip->i_gl, LM_ST_SHARED, 0, &d_gh); + if (error) + return ERR_PTR(error); + unlock = 1; + } + + if (!is_root) { + error = gfs2_permission(dir, MAY_EXEC, 0); + if (error) + goto out; + } + + inode = gfs2_dir_search(dir, name); + if (IS_ERR(inode)) + error = PTR_ERR(inode); +out: + if (unlock) + gfs2_glock_dq_uninit(&d_gh); + if (error == -ENOENT) + return NULL; + return inode ? inode : ERR_PTR(error); +} + +/** + * create_ok - OK to create a new on-disk inode here? + * @dip: Directory in which dinode is to be created + * @name: Name of new dinode + * @mode: + * + * Returns: errno + */ + +static int create_ok(struct gfs2_inode *dip, const struct qstr *name, + unsigned int mode) +{ + int error; + + error = gfs2_permission(&dip->i_inode, MAY_WRITE | MAY_EXEC, 0); + if (error) + return error; + + /* Don't create entries in an unlinked directory */ + if (!dip->i_inode.i_nlink) + return -ENOENT; + + error = gfs2_dir_check(&dip->i_inode, name, NULL); + switch (error) { + case -ENOENT: + error = 0; + break; + case 0: + return -EEXIST; + default: + return error; + } + + if (dip->i_entries == (u32)-1) + return -EFBIG; + if (S_ISDIR(mode) && dip->i_inode.i_nlink == (u32)-1) + return -EMLINK; + + return 0; +} + +static void munge_mode_uid_gid(struct gfs2_inode *dip, unsigned int *mode, + unsigned int *uid, unsigned int *gid) +{ + if (GFS2_SB(&dip->i_inode)->sd_args.ar_suiddir && + (dip->i_inode.i_mode & S_ISUID) && dip->i_inode.i_uid) { + if (S_ISDIR(*mode)) + *mode |= S_ISUID; + else if (dip->i_inode.i_uid != current_fsuid()) + *mode &= ~07111; + *uid = dip->i_inode.i_uid; + } else + *uid = current_fsuid(); + + if (dip->i_inode.i_mode & S_ISGID) { + if (S_ISDIR(*mode)) + *mode |= S_ISGID; + *gid = dip->i_inode.i_gid; + } else + *gid = current_fsgid(); +} + +static int alloc_dinode(struct gfs2_inode *dip, u64 *no_addr, u64 *generation) +{ + struct gfs2_sbd *sdp = GFS2_SB(&dip->i_inode); + int error; + + if (gfs2_alloc_get(dip) == NULL) + return -ENOMEM; + + dip->i_alloc->al_requested = RES_DINODE; + error = gfs2_inplace_reserve(dip); + if (error) + goto out; + + error = gfs2_trans_begin(sdp, RES_RG_BIT + RES_STATFS, 0); + if (error) + goto out_ipreserv; + + error = gfs2_alloc_di(dip, no_addr, generation); + + gfs2_trans_end(sdp); + +out_ipreserv: + gfs2_inplace_release(dip); +out: + gfs2_alloc_put(dip); + return error; +} + +/** + * init_dinode - Fill in a new dinode structure + * @dip: the directory this inode is being created in + * @gl: The glock covering the new inode + * @inum: the inode number + * @mode: the file permissions + * @uid: + * @gid: + * + */ + +static void init_dinode(struct gfs2_inode *dip, struct gfs2_glock *gl, + const struct gfs2_inum_host *inum, unsigned int mode, + unsigned int uid, unsigned int gid, + const u64 *generation, dev_t dev, struct buffer_head **bhp) +{ + struct gfs2_sbd *sdp = GFS2_SB(&dip->i_inode); + struct gfs2_dinode *di; + struct buffer_head *dibh; + struct timespec tv = CURRENT_TIME; + + dibh = gfs2_meta_new(gl, inum->no_addr); + gfs2_trans_add_bh(gl, dibh, 1); + gfs2_metatype_set(dibh, GFS2_METATYPE_DI, GFS2_FORMAT_DI); + gfs2_buffer_clear_tail(dibh, sizeof(struct gfs2_dinode)); + di = (struct gfs2_dinode *)dibh->b_data; + + di->di_num.no_formal_ino = cpu_to_be64(inum->no_formal_ino); + di->di_num.no_addr = cpu_to_be64(inum->no_addr); + di->di_mode = cpu_to_be32(mode); + di->di_uid = cpu_to_be32(uid); + di->di_gid = cpu_to_be32(gid); + di->di_nlink = 0; + di->di_size = 0; + di->di_blocks = cpu_to_be64(1); + di->di_atime = di->di_mtime = di->di_ctime = cpu_to_be64(tv.tv_sec); + di->di_major = cpu_to_be32(MAJOR(dev)); + di->di_minor = cpu_to_be32(MINOR(dev)); + di->di_goal_meta = di->di_goal_data = cpu_to_be64(inum->no_addr); + di->di_generation = cpu_to_be64(*generation); + di->di_flags = 0; + + if (S_ISREG(mode)) { + if ((dip->i_diskflags & GFS2_DIF_INHERIT_JDATA) || + gfs2_tune_get(sdp, gt_new_files_jdata)) + di->di_flags |= cpu_to_be32(GFS2_DIF_JDATA); + } else if (S_ISDIR(mode)) { + di->di_flags |= cpu_to_be32(dip->i_diskflags & + GFS2_DIF_INHERIT_JDATA); + } + + di->__pad1 = 0; + di->di_payload_format = cpu_to_be32(S_ISDIR(mode) ? GFS2_FORMAT_DE : 0); + di->di_height = 0; + di->__pad2 = 0; + di->__pad3 = 0; + di->di_depth = 0; + di->di_entries = 0; + memset(&di->__pad4, 0, sizeof(di->__pad4)); + di->di_eattr = 0; + di->di_atime_nsec = cpu_to_be32(tv.tv_nsec); + di->di_mtime_nsec = cpu_to_be32(tv.tv_nsec); + di->di_ctime_nsec = cpu_to_be32(tv.tv_nsec); + memset(&di->di_reserved, 0, sizeof(di->di_reserved)); + + set_buffer_uptodate(dibh); + + *bhp = dibh; +} + +static int make_dinode(struct gfs2_inode *dip, struct gfs2_glock *gl, + unsigned int mode, const struct gfs2_inum_host *inum, + const u64 *generation, dev_t dev, struct buffer_head **bhp) +{ + struct gfs2_sbd *sdp = GFS2_SB(&dip->i_inode); + unsigned int uid, gid; + int error; + + munge_mode_uid_gid(dip, &mode, &uid, &gid); + if (!gfs2_alloc_get(dip)) + return -ENOMEM; + + error = gfs2_quota_lock(dip, uid, gid); + if (error) + goto out; + + error = gfs2_quota_check(dip, uid, gid); + if (error) + goto out_quota; + + error = gfs2_trans_begin(sdp, RES_DINODE + RES_QUOTA, 0); + if (error) + goto out_quota; + + init_dinode(dip, gl, inum, mode, uid, gid, generation, dev, bhp); + gfs2_quota_change(dip, +1, uid, gid); + gfs2_trans_end(sdp); + +out_quota: + gfs2_quota_unlock(dip); +out: + gfs2_alloc_put(dip); + return error; +} + +static int link_dinode(struct gfs2_inode *dip, const struct qstr *name, + struct gfs2_inode *ip) +{ + struct gfs2_sbd *sdp = GFS2_SB(&dip->i_inode); + struct gfs2_alloc *al; + int alloc_required; + struct buffer_head *dibh; + int error; + + al = gfs2_alloc_get(dip); + if (!al) + return -ENOMEM; + + error = gfs2_quota_lock(dip, NO_QUOTA_CHANGE, NO_QUOTA_CHANGE); + if (error) + goto fail; + + error = alloc_required = gfs2_diradd_alloc_required(&dip->i_inode, name); + if (alloc_required < 0) + goto fail_quota_locks; + if (alloc_required) { + error = gfs2_quota_check(dip, dip->i_inode.i_uid, dip->i_inode.i_gid); + if (error) + goto fail_quota_locks; + + al->al_requested = sdp->sd_max_dirres; + + error = gfs2_inplace_reserve(dip); + if (error) + goto fail_quota_locks; + + error = gfs2_trans_begin(sdp, sdp->sd_max_dirres + + al->al_rgd->rd_length + + 2 * RES_DINODE + + RES_STATFS + RES_QUOTA, 0); + if (error) + goto fail_ipreserv; + } else { + error = gfs2_trans_begin(sdp, RES_LEAF + 2 * RES_DINODE, 0); + if (error) + goto fail_quota_locks; + } + + error = gfs2_dir_add(&dip->i_inode, name, ip); + if (error) + goto fail_end_trans; + + error = gfs2_meta_inode_buffer(ip, &dibh); + if (error) + goto fail_end_trans; + ip->i_inode.i_nlink = 1; + gfs2_trans_add_bh(ip->i_gl, dibh, 1); + gfs2_dinode_out(ip, dibh->b_data); + brelse(dibh); + return 0; + +fail_end_trans: + gfs2_trans_end(sdp); + +fail_ipreserv: + if (dip->i_alloc->al_rgd) + gfs2_inplace_release(dip); + +fail_quota_locks: + gfs2_quota_unlock(dip); + +fail: + gfs2_alloc_put(dip); + return error; +} + +static int gfs2_security_init(struct gfs2_inode *dip, struct gfs2_inode *ip, + const struct qstr *qstr) +{ + int err; + size_t len; + void *value; + char *name; + + err = security_inode_init_security(&ip->i_inode, &dip->i_inode, qstr, + &name, &value, &len); + + if (err) { + if (err == -EOPNOTSUPP) + return 0; + return err; + } + + err = __gfs2_xattr_set(&ip->i_inode, name, value, len, 0, + GFS2_EATYPE_SECURITY); + kfree(value); + kfree(name); + + return err; +} + +/** + * gfs2_createi - Create a new inode + * @ghs: An array of two holders + * @name: The name of the new file + * @mode: the permissions on the new inode + * + * @ghs[0] is an initialized holder for the directory + * @ghs[1] is the holder for the inode lock + * + * If the return value is not NULL, the glocks on both the directory and the new + * file are held. A transaction has been started and an inplace reservation + * is held, as well. + * + * Returns: An inode + */ + +struct inode *gfs2_createi(struct gfs2_holder *ghs, const struct qstr *name, + unsigned int mode, dev_t dev) +{ + struct inode *inode = NULL; + struct gfs2_inode *dip = ghs->gh_gl->gl_object; + struct inode *dir = &dip->i_inode; + struct gfs2_sbd *sdp = GFS2_SB(&dip->i_inode); + struct gfs2_inum_host inum = { .no_addr = 0, .no_formal_ino = 0 }; + int error; + u64 generation; + struct buffer_head *bh = NULL; + + if (!name->len || name->len > GFS2_FNAMESIZE) + return ERR_PTR(-ENAMETOOLONG); + + gfs2_holder_reinit(LM_ST_EXCLUSIVE, 0, ghs); + error = gfs2_glock_nq(ghs); + if (error) + goto fail; + + error = create_ok(dip, name, mode); + if (error) + goto fail_gunlock; + + error = alloc_dinode(dip, &inum.no_addr, &generation); + if (error) + goto fail_gunlock; + inum.no_formal_ino = generation; + + error = gfs2_glock_nq_num(sdp, inum.no_addr, &gfs2_inode_glops, + LM_ST_EXCLUSIVE, GL_SKIP, ghs + 1); + if (error) + goto fail_gunlock; + + error = make_dinode(dip, ghs[1].gh_gl, mode, &inum, &generation, dev, &bh); + if (error) + goto fail_gunlock2; + + inode = gfs2_inode_lookup(dir->i_sb, IF2DT(mode), inum.no_addr, + inum.no_formal_ino, 0); + if (IS_ERR(inode)) + goto fail_gunlock2; + + error = gfs2_inode_refresh(GFS2_I(inode)); + if (error) + goto fail_gunlock2; + + error = gfs2_acl_create(dip, inode); + if (error) + goto fail_gunlock2; + + error = gfs2_security_init(dip, GFS2_I(inode), name); + if (error) + goto fail_gunlock2; + + error = link_dinode(dip, name, GFS2_I(inode)); + if (error) + goto fail_gunlock2; + + if (bh) + brelse(bh); + return inode; + +fail_gunlock2: + gfs2_glock_dq_uninit(ghs + 1); + if (inode && !IS_ERR(inode)) + iput(inode); +fail_gunlock: + gfs2_glock_dq(ghs); +fail: + if (bh) + brelse(bh); + return ERR_PTR(error); +} +/** * gfs2_create - Create a file * @dir: The directory in which to create the file * @dentry: The dentry of the new file @@ -1000,6 +1669,48 @@ int gfs2_permission(struct inode *inode, int mask, unsigned int flags) return error; } +static int __gfs2_setattr_simple(struct gfs2_inode *ip, struct iattr *attr) +{ + struct inode *inode = &ip->i_inode; + struct buffer_head *dibh; + int error; + + error = gfs2_meta_inode_buffer(ip, &dibh); + if (error) + return error; + + setattr_copy(inode, attr); + mark_inode_dirty(inode); + gfs2_trans_add_bh(ip->i_gl, dibh, 1); + gfs2_dinode_out(ip, dibh->b_data); + brelse(dibh); + return 0; +} + +/** + * gfs2_setattr_simple - + * @ip: + * @attr: + * + * Returns: errno + */ + +int gfs2_setattr_simple(struct gfs2_inode *ip, struct iattr *attr) +{ + int error; + + if (current->journal_info) + return __gfs2_setattr_simple(ip, attr); + + error = gfs2_trans_begin(GFS2_SB(&ip->i_inode), RES_DINODE, 0); + if (error) + return error; + + error = __gfs2_setattr_simple(ip, attr); + gfs2_trans_end(GFS2_SB(&ip->i_inode)); + return error; +} + static int setattr_chown(struct inode *inode, struct iattr *attr) { struct gfs2_inode *ip = GFS2_I(inode); -- cgit v0.10.2 From 9eed04cd99b0a497cf0da22658808a7f5b10d734 Mon Sep 17 00:00:00 2001 From: Steven Whitehouse Date: Mon, 9 May 2011 14:11:40 +0100 Subject: GFS2: Move final part of inode.c into super.c Now inode.c is empty. Signed-off-by: Steven Whitehouse diff --git a/fs/gfs2/inode.c b/fs/gfs2/inode.c index b95ee5d..9076fbe 100644 --- a/fs/gfs2/inode.c +++ b/fs/gfs2/inode.c @@ -36,39 +36,3 @@ #include "util.h" -void gfs2_dinode_out(const struct gfs2_inode *ip, void *buf) -{ - struct gfs2_dinode *str = buf; - - str->di_header.mh_magic = cpu_to_be32(GFS2_MAGIC); - str->di_header.mh_type = cpu_to_be32(GFS2_METATYPE_DI); - str->di_header.mh_format = cpu_to_be32(GFS2_FORMAT_DI); - str->di_num.no_addr = cpu_to_be64(ip->i_no_addr); - str->di_num.no_formal_ino = cpu_to_be64(ip->i_no_formal_ino); - str->di_mode = cpu_to_be32(ip->i_inode.i_mode); - str->di_uid = cpu_to_be32(ip->i_inode.i_uid); - str->di_gid = cpu_to_be32(ip->i_inode.i_gid); - str->di_nlink = cpu_to_be32(ip->i_inode.i_nlink); - str->di_size = cpu_to_be64(i_size_read(&ip->i_inode)); - str->di_blocks = cpu_to_be64(gfs2_get_inode_blocks(&ip->i_inode)); - str->di_atime = cpu_to_be64(ip->i_inode.i_atime.tv_sec); - str->di_mtime = cpu_to_be64(ip->i_inode.i_mtime.tv_sec); - str->di_ctime = cpu_to_be64(ip->i_inode.i_ctime.tv_sec); - - str->di_goal_meta = cpu_to_be64(ip->i_goal); - str->di_goal_data = cpu_to_be64(ip->i_goal); - str->di_generation = cpu_to_be64(ip->i_generation); - - str->di_flags = cpu_to_be32(ip->i_diskflags); - str->di_height = cpu_to_be16(ip->i_height); - str->di_payload_format = cpu_to_be32(S_ISDIR(ip->i_inode.i_mode) && - !(ip->i_diskflags & GFS2_DIF_EXHASH) ? - GFS2_FORMAT_DE : 0); - str->di_depth = cpu_to_be16(ip->i_depth); - str->di_entries = cpu_to_be32(ip->i_entries); - - str->di_eattr = cpu_to_be64(ip->i_eattr); - str->di_atime_nsec = cpu_to_be32(ip->i_inode.i_atime.tv_nsec); - str->di_mtime_nsec = cpu_to_be32(ip->i_inode.i_mtime.tv_nsec); - str->di_ctime_nsec = cpu_to_be32(ip->i_inode.i_ctime.tv_nsec); -} diff --git a/fs/gfs2/super.c b/fs/gfs2/super.c index 3061ac6..ed540e7 100644 --- a/fs/gfs2/super.c +++ b/fs/gfs2/super.c @@ -701,6 +701,42 @@ void gfs2_unfreeze_fs(struct gfs2_sbd *sdp) mutex_unlock(&sdp->sd_freeze_lock); } +void gfs2_dinode_out(const struct gfs2_inode *ip, void *buf) +{ + struct gfs2_dinode *str = buf; + + str->di_header.mh_magic = cpu_to_be32(GFS2_MAGIC); + str->di_header.mh_type = cpu_to_be32(GFS2_METATYPE_DI); + str->di_header.mh_format = cpu_to_be32(GFS2_FORMAT_DI); + str->di_num.no_addr = cpu_to_be64(ip->i_no_addr); + str->di_num.no_formal_ino = cpu_to_be64(ip->i_no_formal_ino); + str->di_mode = cpu_to_be32(ip->i_inode.i_mode); + str->di_uid = cpu_to_be32(ip->i_inode.i_uid); + str->di_gid = cpu_to_be32(ip->i_inode.i_gid); + str->di_nlink = cpu_to_be32(ip->i_inode.i_nlink); + str->di_size = cpu_to_be64(i_size_read(&ip->i_inode)); + str->di_blocks = cpu_to_be64(gfs2_get_inode_blocks(&ip->i_inode)); + str->di_atime = cpu_to_be64(ip->i_inode.i_atime.tv_sec); + str->di_mtime = cpu_to_be64(ip->i_inode.i_mtime.tv_sec); + str->di_ctime = cpu_to_be64(ip->i_inode.i_ctime.tv_sec); + + str->di_goal_meta = cpu_to_be64(ip->i_goal); + str->di_goal_data = cpu_to_be64(ip->i_goal); + str->di_generation = cpu_to_be64(ip->i_generation); + + str->di_flags = cpu_to_be32(ip->i_diskflags); + str->di_height = cpu_to_be16(ip->i_height); + str->di_payload_format = cpu_to_be32(S_ISDIR(ip->i_inode.i_mode) && + !(ip->i_diskflags & GFS2_DIF_EXHASH) ? + GFS2_FORMAT_DE : 0); + str->di_depth = cpu_to_be16(ip->i_depth); + str->di_entries = cpu_to_be32(ip->i_entries); + + str->di_eattr = cpu_to_be64(ip->i_eattr); + str->di_atime_nsec = cpu_to_be32(ip->i_inode.i_atime.tv_nsec); + str->di_mtime_nsec = cpu_to_be32(ip->i_inode.i_mtime.tv_nsec); + str->di_ctime_nsec = cpu_to_be32(ip->i_inode.i_ctime.tv_nsec); +} /** * gfs2_write_inode - Make sure the inode is stable on the disk -- cgit v0.10.2 From 637b424bf8747e50bab6648ab919632d6efd6c28 Mon Sep 17 00:00:00 2001 From: Mikulas Patocka Date: Sun, 8 May 2011 20:42:44 +0200 Subject: HPFS: Make HPFS compile on preempt and SMP Make HPFS compile on preempt and SMP Signed-off-by: Mikulas Patocka Signed-off-by: Linus Torvalds diff --git a/fs/hpfs/Kconfig b/fs/hpfs/Kconfig index 0c39dc3..56bd15c 100644 --- a/fs/hpfs/Kconfig +++ b/fs/hpfs/Kconfig @@ -1,7 +1,6 @@ config HPFS_FS tristate "OS/2 HPFS file system support" depends on BLOCK - depends on BROKEN || !PREEMPT help OS/2 is IBM's operating system for PC's, the same as Warp, and HPFS is the file system used for organizing files on OS/2 hard disk diff --git a/fs/hpfs/super.c b/fs/hpfs/super.c index c89b408..501ea86 100644 --- a/fs/hpfs/super.c +++ b/fs/hpfs/super.c @@ -479,11 +479,6 @@ static int hpfs_fill_super(struct super_block *s, void *options, int silent) int o; - if (num_possible_cpus() > 1) { - printk(KERN_ERR "HPFS is not SMP safe\n"); - return -EINVAL; - } - save_mount_options(s, options); sbi = kzalloc(sizeof(*sbi), GFP_KERNEL); -- cgit v0.10.2 From 7dd29d8d865efdb00c0542a5d2c87af8c52ea6c7 Mon Sep 17 00:00:00 2001 From: Mikulas Patocka Date: Sun, 8 May 2011 20:42:54 +0200 Subject: HPFS: Introduce a global mutex and lock it on every callback from VFS. Introduce a global mutex and lock it on every callback from VFS. Performance doesn't matter, reviewing the whole code for locking correctness would be too complicated, so simply lock it all. Signed-off-by: Mikulas Patocka Signed-off-by: Linus Torvalds diff --git a/fs/hpfs/buffer.c b/fs/hpfs/buffer.c index 793cb9d..7cef5d5 100644 --- a/fs/hpfs/buffer.c +++ b/fs/hpfs/buffer.c @@ -32,6 +32,8 @@ void *hpfs_map_sector(struct super_block *s, unsigned secno, struct buffer_head { struct buffer_head *bh; + hpfs_lock_assert(s); + cond_resched(); *bhp = bh = sb_bread(s, secno); @@ -50,6 +52,8 @@ void *hpfs_get_sector(struct super_block *s, unsigned secno, struct buffer_head struct buffer_head *bh; /*return hpfs_map_sector(s, secno, bhp, 0);*/ + hpfs_lock_assert(s); + cond_resched(); if ((*bhp = bh = sb_getblk(s, secno)) != NULL) { @@ -70,6 +74,8 @@ void *hpfs_map_4sectors(struct super_block *s, unsigned secno, struct quad_buffe struct buffer_head *bh; char *data; + hpfs_lock_assert(s); + cond_resched(); if (secno & 3) { @@ -125,6 +131,8 @@ void *hpfs_get_4sectors(struct super_block *s, unsigned secno, { cond_resched(); + hpfs_lock_assert(s); + if (secno & 3) { printk("HPFS: hpfs_get_4sectors: unaligned read\n"); return NULL; diff --git a/fs/hpfs/file.c b/fs/hpfs/file.c index 9b9eb69..09a642f 100644 --- a/fs/hpfs/file.c +++ b/fs/hpfs/file.c @@ -48,38 +48,46 @@ static secno hpfs_bmap(struct inode *inode, unsigned file_secno) static void hpfs_truncate(struct inode *i) { if (IS_IMMUTABLE(i)) return /*-EPERM*/; - hpfs_lock(i->i_sb); + hpfs_lock_assert(i->i_sb); + hpfs_i(i)->i_n_secs = 0; i->i_blocks = 1 + ((i->i_size + 511) >> 9); hpfs_i(i)->mmu_private = i->i_size; hpfs_truncate_btree(i->i_sb, i->i_ino, 1, ((i->i_size + 511) >> 9)); hpfs_write_inode(i); hpfs_i(i)->i_n_secs = 0; - hpfs_unlock(i->i_sb); } static int hpfs_get_block(struct inode *inode, sector_t iblock, struct buffer_head *bh_result, int create) { + int r; secno s; + hpfs_lock(inode->i_sb); s = hpfs_bmap(inode, iblock); if (s) { map_bh(bh_result, inode->i_sb, s); - return 0; + goto ret_0; } - if (!create) return 0; + if (!create) goto ret_0; if (iblock<<9 != hpfs_i(inode)->mmu_private) { BUG(); - return -EIO; + r = -EIO; + goto ret_r; } if ((s = hpfs_add_sector_to_btree(inode->i_sb, inode->i_ino, 1, inode->i_blocks - 1)) == -1) { hpfs_truncate_btree(inode->i_sb, inode->i_ino, 1, inode->i_blocks - 1); - return -ENOSPC; + r = -ENOSPC; + goto ret_r; } inode->i_blocks++; hpfs_i(inode)->mmu_private += 512; set_buffer_new(bh_result); map_bh(bh_result, inode->i_sb, s); - return 0; + ret_0: + r = 0; + ret_r: + hpfs_unlock(inode->i_sb); + return r; } static int hpfs_writepage(struct page *page, struct writeback_control *wbc) @@ -130,8 +138,11 @@ static ssize_t hpfs_file_write(struct file *file, const char __user *buf, ssize_t retval; retval = do_sync_write(file, buf, count, ppos); - if (retval > 0) + if (retval > 0) { + hpfs_lock(file->f_path.dentry->d_sb); hpfs_i(file->f_path.dentry->d_inode)->i_dirty = 1; + hpfs_unlock(file->f_path.dentry->d_sb); + } return retval; } diff --git a/fs/hpfs/hpfs_fn.h b/fs/hpfs/hpfs_fn.h index c15adbc..89a4714 100644 --- a/fs/hpfs/hpfs_fn.h +++ b/fs/hpfs/hpfs_fn.h @@ -63,6 +63,7 @@ struct hpfs_inode_info { }; struct hpfs_sb_info { + struct mutex hpfs_mutex; /* global hpfs lock */ ino_t sb_root; /* inode number of root dir */ unsigned sb_fs_size; /* file system size, sectors */ unsigned sb_bitmaps; /* sector number of bitmap list */ @@ -346,21 +347,26 @@ static inline time32_t gmt_to_local(struct super_block *s, time_t t) /* * Locking: * - * hpfs_lock() is a leftover from the big kernel lock. - * Right now, these functions are empty and only left - * for documentation purposes. The file system no longer - * works on SMP systems, so the lock is not needed - * any more. + * hpfs_lock() locks the whole filesystem. It must be taken + * on any method called by the VFS. * - * If someone is interested in making it work again, this - * would be the place to start by adding a per-superblock - * mutex and fixing all the bugs and performance issues - * caused by that. + * We don't do any per-file locking anymore, it is hard to + * review and HPFS is not performance-sensitive anyway. */ static inline void hpfs_lock(struct super_block *s) { + struct hpfs_sb_info *sbi = hpfs_sb(s); + mutex_lock(&sbi->hpfs_mutex); } static inline void hpfs_unlock(struct super_block *s) { + struct hpfs_sb_info *sbi = hpfs_sb(s); + mutex_unlock(&sbi->hpfs_mutex); +} + +static inline void hpfs_lock_assert(struct super_block *s) +{ + struct hpfs_sb_info *sbi = hpfs_sb(s); + WARN_ON(!mutex_is_locked(&sbi->hpfs_mutex)); } diff --git a/fs/hpfs/super.c b/fs/hpfs/super.c index 501ea86..41232c2 100644 --- a/fs/hpfs/super.c +++ b/fs/hpfs/super.c @@ -102,9 +102,12 @@ static void hpfs_put_super(struct super_block *s) { struct hpfs_sb_info *sbi = hpfs_sb(s); + hpfs_lock(s); + unmark_dirty(s); + hpfs_unlock(s); + kfree(sbi->sb_cp_table); kfree(sbi->sb_bmp_dir); - unmark_dirty(s); s->s_fs_info = NULL; kfree(sbi); } @@ -490,6 +493,9 @@ static int hpfs_fill_super(struct super_block *s, void *options, int silent) sbi->sb_bmp_dir = NULL; sbi->sb_cp_table = NULL; + mutex_init(&sbi->hpfs_mutex); + hpfs_lock(s); + mutex_init(&sbi->hpfs_creation_de); uid = current_uid(); @@ -669,6 +675,7 @@ static int hpfs_fill_super(struct super_block *s, void *options, int silent) root->i_blocks = 5; hpfs_brelse4(&qbh); } + hpfs_unlock(s); return 0; bail4: brelse(bh2); @@ -676,6 +683,7 @@ bail3: brelse(bh1); bail2: brelse(bh0); bail1: bail0: + hpfs_unlock(s); kfree(sbi->sb_bmp_dir); kfree(sbi->sb_cp_table); s->s_fs_info = NULL; -- cgit v0.10.2 From 7d23ce36e3f52f9b83ac8da49296b73339c8b5b8 Mon Sep 17 00:00:00 2001 From: Mikulas Patocka Date: Sun, 8 May 2011 20:43:06 +0200 Subject: HPFS: Remove remaining locks Remove remaining locks Because of a new global per-fs lock, no other locks are needed Signed-off-by: Mikulas Patocka Signed-off-by: Linus Torvalds diff --git a/fs/hpfs/alloc.c b/fs/hpfs/alloc.c index 5503e2c..995472d 100644 --- a/fs/hpfs/alloc.c +++ b/fs/hpfs/alloc.c @@ -8,8 +8,6 @@ #include "hpfs_fn.h" -static int hpfs_alloc_if_possible_nolock(struct super_block *s, secno sec); - /* * Check if a sector is allocated in bitmap * This is really slow. Turned on only if chk==2 @@ -75,7 +73,6 @@ static secno alloc_in_bmp(struct super_block *s, secno near, unsigned n, unsigne hpfs_error(s, "Bad allocation size: %d", n); return 0; } - lock_super(s); if (bs != ~0x3fff) { if (!(bmp = hpfs_map_bitmap(s, near >> 14, &qbh, "aib"))) goto uls; } else { @@ -143,7 +140,6 @@ static secno alloc_in_bmp(struct super_block *s, secno near, unsigned n, unsigne b: hpfs_brelse4(&qbh); uls: - unlock_super(s); return ret; } @@ -155,7 +151,7 @@ static secno alloc_in_bmp(struct super_block *s, secno near, unsigned n, unsigne * sectors */ -secno hpfs_alloc_sector(struct super_block *s, secno near, unsigned n, int forward, int lock) +secno hpfs_alloc_sector(struct super_block *s, secno near, unsigned n, int forward) { secno sec; int i; @@ -167,7 +163,6 @@ secno hpfs_alloc_sector(struct super_block *s, secno near, unsigned n, int forwa forward = -forward; f_p = 1; } - if (lock) hpfs_lock_creation(s); n_bmps = (sbi->sb_fs_size + 0x4000 - 1) >> 14; if (near && near < sbi->sb_fs_size) { if ((sec = alloc_in_bmp(s, near, n, f_p ? forward : forward/4))) goto ret; @@ -214,18 +209,17 @@ secno hpfs_alloc_sector(struct super_block *s, secno near, unsigned n, int forwa ret: if (sec && f_p) { for (i = 0; i < forward; i++) { - if (!hpfs_alloc_if_possible_nolock(s, sec + i + 1)) { + if (!hpfs_alloc_if_possible(s, sec + i + 1)) { hpfs_error(s, "Prealloc doesn't work! Wanted %d, allocated at %08x, can't allocate %d", forward, sec, i); sec = 0; break; } } } - if (lock) hpfs_unlock_creation(s); return sec; } -static secno alloc_in_dirband(struct super_block *s, secno near, int lock) +static secno alloc_in_dirband(struct super_block *s, secno near) { unsigned nr = near; secno sec; @@ -236,43 +230,29 @@ static secno alloc_in_dirband(struct super_block *s, secno near, int lock) nr = sbi->sb_dirband_start + sbi->sb_dirband_size - 4; nr -= sbi->sb_dirband_start; nr >>= 2; - if (lock) hpfs_lock_creation(s); sec = alloc_in_bmp(s, (~0x3fff) | nr, 1, 0); - if (lock) hpfs_unlock_creation(s); if (!sec) return 0; return ((sec & 0x3fff) << 2) + sbi->sb_dirband_start; } /* Alloc sector if it's free */ -static int hpfs_alloc_if_possible_nolock(struct super_block *s, secno sec) +int hpfs_alloc_if_possible(struct super_block *s, secno sec) { struct quad_buffer_head qbh; unsigned *bmp; - lock_super(s); if (!(bmp = hpfs_map_bitmap(s, sec >> 14, &qbh, "aip"))) goto end; if (bmp[(sec & 0x3fff) >> 5] & (1 << (sec & 0x1f))) { bmp[(sec & 0x3fff) >> 5] &= ~(1 << (sec & 0x1f)); hpfs_mark_4buffers_dirty(&qbh); hpfs_brelse4(&qbh); - unlock_super(s); return 1; } hpfs_brelse4(&qbh); end: - unlock_super(s); return 0; } -int hpfs_alloc_if_possible(struct super_block *s, secno sec) -{ - int r; - hpfs_lock_creation(s); - r = hpfs_alloc_if_possible_nolock(s, sec); - hpfs_unlock_creation(s); - return r; -} - /* Free sectors in bitmaps */ void hpfs_free_sectors(struct super_block *s, secno sec, unsigned n) @@ -286,26 +266,22 @@ void hpfs_free_sectors(struct super_block *s, secno sec, unsigned n) hpfs_error(s, "Trying to free reserved sector %08x", sec); return; } - lock_super(s); sbi->sb_max_fwd_alloc += n > 0xffff ? 0xffff : n; if (sbi->sb_max_fwd_alloc > 0xffffff) sbi->sb_max_fwd_alloc = 0xffffff; new_map: if (!(bmp = hpfs_map_bitmap(s, sec >> 14, &qbh, "free"))) { - unlock_super(s); return; } new_tst: if ((bmp[(sec & 0x3fff) >> 5] >> (sec & 0x1f) & 1)) { hpfs_error(s, "sector %08x not allocated", sec); hpfs_brelse4(&qbh); - unlock_super(s); return; } bmp[(sec & 0x3fff) >> 5] |= 1 << (sec & 0x1f); if (!--n) { hpfs_mark_4buffers_dirty(&qbh); hpfs_brelse4(&qbh); - unlock_super(s); return; } if (!(++sec & 0x3fff)) { @@ -381,29 +357,25 @@ void hpfs_free_dnode(struct super_block *s, dnode_secno dno) struct quad_buffer_head qbh; unsigned *bmp; unsigned ssec = (dno - hpfs_sb(s)->sb_dirband_start) / 4; - lock_super(s); if (!(bmp = hpfs_map_dnode_bitmap(s, &qbh))) { - unlock_super(s); return; } bmp[ssec >> 5] |= 1 << (ssec & 0x1f); hpfs_mark_4buffers_dirty(&qbh); hpfs_brelse4(&qbh); - unlock_super(s); } } struct dnode *hpfs_alloc_dnode(struct super_block *s, secno near, - dnode_secno *dno, struct quad_buffer_head *qbh, - int lock) + dnode_secno *dno, struct quad_buffer_head *qbh) { struct dnode *d; if (hpfs_count_one_bitmap(s, hpfs_sb(s)->sb_dmap) > FREE_DNODES_ADD) { - if (!(*dno = alloc_in_dirband(s, near, lock))) - if (!(*dno = hpfs_alloc_sector(s, near, 4, 0, lock))) return NULL; + if (!(*dno = alloc_in_dirband(s, near))) + if (!(*dno = hpfs_alloc_sector(s, near, 4, 0))) return NULL; } else { - if (!(*dno = hpfs_alloc_sector(s, near, 4, 0, lock))) - if (!(*dno = alloc_in_dirband(s, near, lock))) return NULL; + if (!(*dno = hpfs_alloc_sector(s, near, 4, 0))) + if (!(*dno = alloc_in_dirband(s, near))) return NULL; } if (!(d = hpfs_get_4sectors(s, *dno, qbh))) { hpfs_free_dnode(s, *dno); @@ -424,7 +396,7 @@ struct fnode *hpfs_alloc_fnode(struct super_block *s, secno near, fnode_secno *f struct buffer_head **bh) { struct fnode *f; - if (!(*fno = hpfs_alloc_sector(s, near, 1, FNODE_ALLOC_FWD, 1))) return NULL; + if (!(*fno = hpfs_alloc_sector(s, near, 1, FNODE_ALLOC_FWD))) return NULL; if (!(f = hpfs_get_sector(s, *fno, bh))) { hpfs_free_sectors(s, *fno, 1); return NULL; @@ -441,7 +413,7 @@ struct anode *hpfs_alloc_anode(struct super_block *s, secno near, anode_secno *a struct buffer_head **bh) { struct anode *a; - if (!(*ano = hpfs_alloc_sector(s, near, 1, ANODE_ALLOC_FWD, 1))) return NULL; + if (!(*ano = hpfs_alloc_sector(s, near, 1, ANODE_ALLOC_FWD))) return NULL; if (!(a = hpfs_get_sector(s, *ano, bh))) { hpfs_free_sectors(s, *ano, 1); return NULL; diff --git a/fs/hpfs/anode.c b/fs/hpfs/anode.c index 6a2f04b..f2a0384 100644 --- a/fs/hpfs/anode.c +++ b/fs/hpfs/anode.c @@ -115,7 +115,7 @@ secno hpfs_add_sector_to_btree(struct super_block *s, secno node, int fnod, unsi } se = !fnod ? node : (node + 16384) & ~16383; } - if (!(se = hpfs_alloc_sector(s, se, 1, fsecno*ALLOC_M>ALLOC_FWD_MAX ? ALLOC_FWD_MAX : fsecno*ALLOC_MALLOC_FWD_MAX ? ALLOC_FWD_MAX : fsecno*ALLOC_M #include "hpfs_fn.h" -void hpfs_lock_creation(struct super_block *s) -{ -#ifdef DEBUG_LOCKS - printk("lock creation\n"); -#endif - mutex_lock(&hpfs_sb(s)->hpfs_creation_de); -} - -void hpfs_unlock_creation(struct super_block *s) -{ -#ifdef DEBUG_LOCKS - printk("unlock creation\n"); -#endif - mutex_unlock(&hpfs_sb(s)->hpfs_creation_de); -} - /* Map a sector into a buffer and return pointers to it and to the buffer. */ void *hpfs_map_sector(struct super_block *s, unsigned secno, struct buffer_head **bhp, diff --git a/fs/hpfs/dnode.c b/fs/hpfs/dnode.c index 9b2ffad..07711c3 100644 --- a/fs/hpfs/dnode.c +++ b/fs/hpfs/dnode.c @@ -145,9 +145,10 @@ static void set_last_pointer(struct super_block *s, struct dnode *d, dnode_secno } } if (ptr) { - if ((d->first_free += 4) > 2048) { - hpfs_error(s,"set_last_pointer: too long dnode %08x", d->self); - d->first_free -= 4; + d->first_free = cpu_to_le32(le32_to_cpu(d->first_free) + 4); + if (le32_to_cpu(d->first_free) > 2048) { + hpfs_error(s, "set_last_pointer: too long dnode %08x", d->self); + d->first_free = cpu_to_le32(le32_to_cpu(d->first_free) - 4); return; } de->length = 36; @@ -184,7 +185,7 @@ struct hpfs_dirent *hpfs_add_de(struct super_block *s, struct dnode *d, de->not_8x3 = hpfs_is_name_long(name, namelen); de->namelen = namelen; memcpy(de->name, name, namelen); - d->first_free += d_size; + d->first_free = cpu_to_le32(le32_to_cpu(d->first_free) + d_size); return de; } @@ -197,8 +198,8 @@ static void hpfs_delete_de(struct super_block *s, struct dnode *d, hpfs_error(s, "attempt to delete last dirent in dnode %08x", d->self); return; } - d->first_free -= de->length; - memmove(de, de_next_de(de), d->first_free + (char *)d - (char *)de); + d->first_free = cpu_to_le32(le32_to_cpu(d->first_free) - de->length); + memmove(de, de_next_de(de), le32_to_cpu(d->first_free) + (char *)d - (char *)de); } static void fix_up_ptrs(struct super_block *s, struct dnode *d) @@ -262,7 +263,7 @@ static int hpfs_add_to_dnode(struct inode *i, dnode_secno dno, kfree(nname); return 1; } - if (d->first_free + de_size(namelen, down_ptr) <= 2048) { + if (le32_to_cpu(d->first_free) + de_size(namelen, down_ptr) <= 2048) { loff_t t; copy_de(de=hpfs_add_de(i->i_sb, d, name, namelen, down_ptr), new_de); t = get_pos(d, de); @@ -286,11 +287,11 @@ static int hpfs_add_to_dnode(struct inode *i, dnode_secno dno, kfree(nname); return 1; } - memcpy(nd, d, d->first_free); + memcpy(nd, d, le32_to_cpu(d->first_free)); copy_de(de = hpfs_add_de(i->i_sb, nd, name, namelen, down_ptr), new_de); for_all_poss(i, hpfs_pos_ins, get_pos(nd, de), 1); h = ((char *)dnode_last_de(nd) - (char *)nd) / 2 + 10; - if (!(ad = hpfs_alloc_dnode(i->i_sb, d->up, &adno, &qbh1, 0))) { + if (!(ad = hpfs_alloc_dnode(i->i_sb, d->up, &adno, &qbh1))) { hpfs_error(i->i_sb, "unable to alloc dnode - dnode tree will be corrupted"); hpfs_brelse4(&qbh); kfree(nd); @@ -313,9 +314,9 @@ static int hpfs_add_to_dnode(struct inode *i, dnode_secno dno, down_ptr = adno; set_last_pointer(i->i_sb, ad, de->down ? de_down_pointer(de) : 0); de = de_next_de(de); - memmove((char *)nd + 20, de, nd->first_free + (char *)nd - (char *)de); - nd->first_free -= (char *)de - (char *)nd - 20; - memcpy(d, nd, nd->first_free); + memmove((char *)nd + 20, de, le32_to_cpu(nd->first_free) + (char *)nd - (char *)de); + nd->first_free = cpu_to_le32(le32_to_cpu(nd->first_free) - (char *)de - (char *)nd - 20); + memcpy(d, nd, le32_to_cpu(nd->first_free)); for_all_poss(i, hpfs_pos_del, (loff_t)dno << 4, pos); fix_up_ptrs(i->i_sb, ad); if (!d->root_dnode) { @@ -326,7 +327,7 @@ static int hpfs_add_to_dnode(struct inode *i, dnode_secno dno, hpfs_brelse4(&qbh1); goto go_up; } - if (!(rd = hpfs_alloc_dnode(i->i_sb, d->up, &rdno, &qbh2, 0))) { + if (!(rd = hpfs_alloc_dnode(i->i_sb, d->up, &rdno, &qbh2))) { hpfs_error(i->i_sb, "unable to alloc dnode - dnode tree will be corrupted"); hpfs_brelse4(&qbh); hpfs_brelse4(&qbh1); @@ -373,7 +374,7 @@ static int hpfs_add_to_dnode(struct inode *i, dnode_secno dno, int hpfs_add_dirent(struct inode *i, const unsigned char *name, unsigned namelen, - struct hpfs_dirent *new_de, int cdepth) + struct hpfs_dirent *new_de) { struct hpfs_inode_info *hpfs_inode = hpfs_i(i); struct dnode *d; @@ -403,7 +404,6 @@ int hpfs_add_dirent(struct inode *i, } } hpfs_brelse4(&qbh); - if (!cdepth) hpfs_lock_creation(i->i_sb); if (hpfs_check_free_dnodes(i->i_sb, FREE_DNODES_ADD)) { c = 1; goto ret; @@ -411,7 +411,6 @@ int hpfs_add_dirent(struct inode *i, i->i_version++; c = hpfs_add_to_dnode(i, dno, name, namelen, new_de, 0); ret: - if (!cdepth) hpfs_unlock_creation(i->i_sb); return c; } @@ -474,7 +473,7 @@ static secno move_to_top(struct inode *i, dnode_secno from, dnode_secno to) hpfs_brelse4(&qbh); return 0; } - dnode->first_free -= 4; + dnode->first_free = cpu_to_le32(le32_to_cpu(dnode->first_free) - 4); de->length -= 4; de->down = 0; hpfs_mark_4buffers_dirty(&qbh); @@ -517,8 +516,8 @@ static void delete_empty_dnode(struct inode *i, dnode_secno dno) try_it_again: if (hpfs_stop_cycles(i->i_sb, dno, &c1, &c2, "delete_empty_dnode")) return; if (!(dnode = hpfs_map_dnode(i->i_sb, dno, &qbh))) return; - if (dnode->first_free > 56) goto end; - if (dnode->first_free == 52 || dnode->first_free == 56) { + if (le32_to_cpu(dnode->first_free) > 56) goto end; + if (le32_to_cpu(dnode->first_free) == 52 || le32_to_cpu(dnode->first_free) == 56) { struct hpfs_dirent *de_end; int root = dnode->root_dnode; up = dnode->up; @@ -571,9 +570,9 @@ static void delete_empty_dnode(struct inode *i, dnode_secno dno) if (!down) { de->down = 0; de->length -= 4; - dnode->first_free -= 4; + dnode->first_free = cpu_to_le32(le32_to_cpu(dnode->first_free) - 4); memmove(de_next_de(de), (char *)de_next_de(de) + 4, - (char *)dnode + dnode->first_free - (char *)de_next_de(de)); + (char *)dnode + le32_to_cpu(dnode->first_free) - (char *)de_next_de(de)); } else { struct dnode *d1; struct quad_buffer_head qbh1; @@ -585,7 +584,7 @@ static void delete_empty_dnode(struct inode *i, dnode_secno dno) } } } else { - hpfs_error(i->i_sb, "delete_empty_dnode: dnode %08x, first_free == %03x", dno, dnode->first_free); + hpfs_error(i->i_sb, "delete_empty_dnode: dnode %08x, first_free == %03x", dno, le32_to_cpu(dnode->first_free)); goto end; } @@ -635,7 +634,7 @@ static void delete_empty_dnode(struct inode *i, dnode_secno dno) struct hpfs_dirent *del = dnode_last_de(d1); dlp = del->down ? de_down_pointer(del) : 0; if (!dlp && down) { - if (d1->first_free > 2044) { + if (le32_to_cpu(d1->first_free) > 2044) { if (hpfs_sb(i->i_sb)->sb_chk >= 2) { printk("HPFS: warning: unbalanced dnode tree, see hpfs.txt 4 more info\n"); printk("HPFS: warning: terminating balancing operation\n"); @@ -649,12 +648,12 @@ static void delete_empty_dnode(struct inode *i, dnode_secno dno) } del->length += 4; del->down = 1; - d1->first_free += 4; + d1->first_free = cpu_to_le32(le32_to_cpu(d1->first_free) + 4); } if (dlp && !down) { del->length -= 4; del->down = 0; - d1->first_free -= 4; + d1->first_free = cpu_to_le32(le32_to_cpu(d1->first_free) - 4); } else if (down) *(dnode_secno *) ((void *) del + del->length - 4) = down; } else goto endm; @@ -670,7 +669,7 @@ static void delete_empty_dnode(struct inode *i, dnode_secno dno) if (!de_prev->down) { de_prev->length += 4; de_prev->down = 1; - dnode->first_free += 4; + dnode->first_free = cpu_to_le32(le32_to_cpu(dnode->first_free) + 4); } *(dnode_secno *) ((void *) de_prev + de_prev->length - 4) = ndown; hpfs_mark_4buffers_dirty(&qbh); @@ -701,7 +700,6 @@ int hpfs_remove_dirent(struct inode *i, dnode_secno dno, struct hpfs_dirent *de, { struct dnode *dnode = qbh->data; dnode_secno down = 0; - int lock = 0; loff_t t; if (de->first || de->last) { hpfs_error(i->i_sb, "hpfs_remove_dirent: attempt to delete first or last dirent in dnode %08x", dno); @@ -710,11 +708,8 @@ int hpfs_remove_dirent(struct inode *i, dnode_secno dno, struct hpfs_dirent *de, } if (de->down) down = de_down_pointer(de); if (depth && (de->down || (de == dnode_first_de(dnode) && de_next_de(de)->last))) { - lock = 1; - hpfs_lock_creation(i->i_sb); if (hpfs_check_free_dnodes(i->i_sb, FREE_DNODES_DEL)) { hpfs_brelse4(qbh); - hpfs_unlock_creation(i->i_sb); return 2; } } @@ -727,11 +722,9 @@ int hpfs_remove_dirent(struct inode *i, dnode_secno dno, struct hpfs_dirent *de, dnode_secno a = move_to_top(i, down, dno); for_all_poss(i, hpfs_pos_subst, 5, t); if (a) delete_empty_dnode(i, a); - if (lock) hpfs_unlock_creation(i->i_sb); return !a; } delete_empty_dnode(i, dno); - if (lock) hpfs_unlock_creation(i->i_sb); return 0; } diff --git a/fs/hpfs/ea.c b/fs/hpfs/ea.c index 45e53d9..1ac05bb 100644 --- a/fs/hpfs/ea.c +++ b/fs/hpfs/ea.c @@ -266,7 +266,7 @@ void hpfs_set_ea(struct inode *inode, struct fnode *fnode, const char *key, secno n; struct buffer_head *bh; char *data; - if (!(n = hpfs_alloc_sector(s, fno, 1, 0, 1))) return; + if (!(n = hpfs_alloc_sector(s, fno, 1, 0))) return; if (!(data = hpfs_get_sector(s, n, &bh))) { hpfs_free_sectors(s, n, 1); return; @@ -284,7 +284,7 @@ void hpfs_set_ea(struct inode *inode, struct fnode *fnode, const char *key, if (pos >= 30000) goto bail; while (((pos + 511) >> 9) > len) { if (!len) { - if (!(fnode->ea_secno = hpfs_alloc_sector(s, fno, 1, 0, 1))) + if (!(fnode->ea_secno = hpfs_alloc_sector(s, fno, 1, 0))) goto bail; fnode->ea_anode = 0; len++; @@ -312,7 +312,7 @@ void hpfs_set_ea(struct inode *inode, struct fnode *fnode, const char *key, fnode->ea_secno = a_s;*/ secno new_sec; int i; - if (!(new_sec = hpfs_alloc_sector(s, fno, 1, 1 - ((pos + 511) >> 9), 1))) + if (!(new_sec = hpfs_alloc_sector(s, fno, 1, 1 - ((pos + 511) >> 9)))) goto bail; for (i = 0; i < len; i++) { struct buffer_head *bh1, *bh2; diff --git a/fs/hpfs/hpfs_fn.h b/fs/hpfs/hpfs_fn.h index 89a4714..860d09f 100644 --- a/fs/hpfs/hpfs_fn.h +++ b/fs/hpfs/hpfs_fn.h @@ -56,8 +56,6 @@ struct hpfs_inode_info { unsigned i_ea_uid : 1; /* file's uid is stored in ea */ unsigned i_ea_gid : 1; /* file's gid is stored in ea */ unsigned i_dirty : 1; - struct mutex i_mutex; - struct mutex i_parent_mutex; loff_t **i_rddir_off; struct inode vfs_inode; }; @@ -88,8 +86,6 @@ struct hpfs_sb_info { unsigned *sb_bmp_dir; /* main bitmap directory */ unsigned sb_c_bitmap; /* current bitmap */ unsigned sb_max_fwd_alloc; /* max forwad allocation */ - struct mutex hpfs_creation_de; /* when creating dirents, nobody else - can alloc blocks */ /*unsigned sb_mounting : 1;*/ int sb_timeshift; }; @@ -201,12 +197,12 @@ static inline unsigned tstbits(unsigned *bmp, unsigned b, unsigned n) /* alloc.c */ int hpfs_chk_sectors(struct super_block *, secno, int, char *); -secno hpfs_alloc_sector(struct super_block *, secno, unsigned, int, int); +secno hpfs_alloc_sector(struct super_block *, secno, unsigned, int); int hpfs_alloc_if_possible(struct super_block *, secno); void hpfs_free_sectors(struct super_block *, secno, unsigned); int hpfs_check_free_dnodes(struct super_block *, int); void hpfs_free_dnode(struct super_block *, secno); -struct dnode *hpfs_alloc_dnode(struct super_block *, secno, dnode_secno *, struct quad_buffer_head *, int); +struct dnode *hpfs_alloc_dnode(struct super_block *, secno, dnode_secno *, struct quad_buffer_head *); struct fnode *hpfs_alloc_fnode(struct super_block *, secno, fnode_secno *, struct buffer_head **); struct anode *hpfs_alloc_anode(struct super_block *, secno, anode_secno *, struct buffer_head **); @@ -223,8 +219,6 @@ void hpfs_remove_fnode(struct super_block *, fnode_secno fno); /* buffer.c */ -void hpfs_lock_creation(struct super_block *); -void hpfs_unlock_creation(struct super_block *); void *hpfs_map_sector(struct super_block *, unsigned, struct buffer_head **, int); void *hpfs_get_sector(struct super_block *, unsigned, struct buffer_head **); void *hpfs_map_4sectors(struct super_block *, unsigned, struct quad_buffer_head *, int); @@ -248,7 +242,7 @@ void hpfs_del_pos(struct inode *, loff_t *); struct hpfs_dirent *hpfs_add_de(struct super_block *, struct dnode *, const unsigned char *, unsigned, secno); int hpfs_add_dirent(struct inode *, const unsigned char *, unsigned, - struct hpfs_dirent *, int); + struct hpfs_dirent *); int hpfs_remove_dirent(struct inode *, dnode_secno, struct hpfs_dirent *, struct quad_buffer_head *, int); void hpfs_count_dnodes(struct super_block *, dnode_secno, int *, int *, int *); dnode_secno hpfs_de_as_down_as_possible(struct super_block *, dnode_secno dno); diff --git a/fs/hpfs/inode.c b/fs/hpfs/inode.c index 87f1f78..29cf050 100644 --- a/fs/hpfs/inode.c +++ b/fs/hpfs/inode.c @@ -187,9 +187,7 @@ void hpfs_write_inode(struct inode *i) kfree(hpfs_inode->i_rddir_off); hpfs_inode->i_rddir_off = NULL; } - mutex_lock(&hpfs_inode->i_parent_mutex); if (!i->i_nlink) { - mutex_unlock(&hpfs_inode->i_parent_mutex); return; } parent = iget_locked(i->i_sb, hpfs_inode->i_parent_dir); @@ -200,14 +198,11 @@ void hpfs_write_inode(struct inode *i) hpfs_read_inode(parent); unlock_new_inode(parent); } - mutex_lock(&hpfs_inode->i_mutex); hpfs_write_inode_nolock(i); - mutex_unlock(&hpfs_inode->i_mutex); iput(parent); } else { mark_inode_dirty(i); } - mutex_unlock(&hpfs_inode->i_parent_mutex); } void hpfs_write_inode_nolock(struct inode *i) diff --git a/fs/hpfs/namei.c b/fs/hpfs/namei.c index d5f8c8a..8c9f915 100644 --- a/fs/hpfs/namei.c +++ b/fs/hpfs/namei.c @@ -29,7 +29,7 @@ static int hpfs_mkdir(struct inode *dir, struct dentry *dentry, int mode) fnode = hpfs_alloc_fnode(dir->i_sb, hpfs_i(dir)->i_dno, &fno, &bh); if (!fnode) goto bail; - dnode = hpfs_alloc_dnode(dir->i_sb, fno, &dno, &qbh0, 1); + dnode = hpfs_alloc_dnode(dir->i_sb, fno, &dno, &qbh0); if (!dnode) goto bail1; memset(&dee, 0, sizeof dee); @@ -60,8 +60,7 @@ static int hpfs_mkdir(struct inode *dir, struct dentry *dentry, int mode) if (dee.read_only) result->i_mode &= ~0222; - mutex_lock(&hpfs_i(dir)->i_mutex); - r = hpfs_add_dirent(dir, name, len, &dee, 0); + r = hpfs_add_dirent(dir, name, len, &dee); if (r == 1) goto bail3; if (r == -1) { @@ -101,11 +100,9 @@ static int hpfs_mkdir(struct inode *dir, struct dentry *dentry, int mode) hpfs_write_inode_nolock(result); } d_instantiate(dentry, result); - mutex_unlock(&hpfs_i(dir)->i_mutex); hpfs_unlock(dir->i_sb); return 0; bail3: - mutex_unlock(&hpfs_i(dir)->i_mutex); iput(result); bail2: hpfs_brelse4(&qbh0); @@ -168,8 +165,7 @@ static int hpfs_create(struct inode *dir, struct dentry *dentry, int mode, struc result->i_data.a_ops = &hpfs_aops; hpfs_i(result)->mmu_private = 0; - mutex_lock(&hpfs_i(dir)->i_mutex); - r = hpfs_add_dirent(dir, name, len, &dee, 0); + r = hpfs_add_dirent(dir, name, len, &dee); if (r == 1) goto bail2; if (r == -1) { @@ -193,12 +189,10 @@ static int hpfs_create(struct inode *dir, struct dentry *dentry, int mode, struc hpfs_write_inode_nolock(result); } d_instantiate(dentry, result); - mutex_unlock(&hpfs_i(dir)->i_mutex); hpfs_unlock(dir->i_sb); return 0; bail2: - mutex_unlock(&hpfs_i(dir)->i_mutex); iput(result); bail1: brelse(bh); @@ -254,8 +248,7 @@ static int hpfs_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t result->i_blocks = 1; init_special_inode(result, mode, rdev); - mutex_lock(&hpfs_i(dir)->i_mutex); - r = hpfs_add_dirent(dir, name, len, &dee, 0); + r = hpfs_add_dirent(dir, name, len, &dee); if (r == 1) goto bail2; if (r == -1) { @@ -271,12 +264,10 @@ static int hpfs_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t hpfs_write_inode_nolock(result); d_instantiate(dentry, result); - mutex_unlock(&hpfs_i(dir)->i_mutex); brelse(bh); hpfs_unlock(dir->i_sb); return 0; bail2: - mutex_unlock(&hpfs_i(dir)->i_mutex); iput(result); bail1: brelse(bh); @@ -333,8 +324,7 @@ static int hpfs_symlink(struct inode *dir, struct dentry *dentry, const char *sy result->i_op = &page_symlink_inode_operations; result->i_data.a_ops = &hpfs_symlink_aops; - mutex_lock(&hpfs_i(dir)->i_mutex); - r = hpfs_add_dirent(dir, name, len, &dee, 0); + r = hpfs_add_dirent(dir, name, len, &dee); if (r == 1) goto bail2; if (r == -1) { @@ -352,11 +342,9 @@ static int hpfs_symlink(struct inode *dir, struct dentry *dentry, const char *sy hpfs_write_inode_nolock(result); d_instantiate(dentry, result); - mutex_unlock(&hpfs_i(dir)->i_mutex); hpfs_unlock(dir->i_sb); return 0; bail2: - mutex_unlock(&hpfs_i(dir)->i_mutex); iput(result); bail1: brelse(bh); @@ -382,8 +370,6 @@ static int hpfs_unlink(struct inode *dir, struct dentry *dentry) hpfs_lock(dir->i_sb); hpfs_adjust_length(name, &len); again: - mutex_lock(&hpfs_i(inode)->i_parent_mutex); - mutex_lock(&hpfs_i(dir)->i_mutex); err = -ENOENT; de = map_dirent(dir, hpfs_i(dir)->i_dno, name, len, &dno, &qbh); if (!de) @@ -410,8 +396,6 @@ again: if (rep++) break; - mutex_unlock(&hpfs_i(dir)->i_mutex); - mutex_unlock(&hpfs_i(inode)->i_parent_mutex); dentry_unhash(dentry); if (!d_unhashed(dentry)) { dput(dentry); @@ -445,8 +429,6 @@ again: out1: hpfs_brelse4(&qbh); out: - mutex_unlock(&hpfs_i(dir)->i_mutex); - mutex_unlock(&hpfs_i(inode)->i_parent_mutex); hpfs_unlock(dir->i_sb); return err; } @@ -466,8 +448,6 @@ static int hpfs_rmdir(struct inode *dir, struct dentry *dentry) hpfs_adjust_length(name, &len); hpfs_lock(dir->i_sb); - mutex_lock(&hpfs_i(inode)->i_parent_mutex); - mutex_lock(&hpfs_i(dir)->i_mutex); err = -ENOENT; de = map_dirent(dir, hpfs_i(dir)->i_dno, name, len, &dno, &qbh); if (!de) @@ -505,8 +485,6 @@ static int hpfs_rmdir(struct inode *dir, struct dentry *dentry) out1: hpfs_brelse4(&qbh); out: - mutex_unlock(&hpfs_i(dir)->i_mutex); - mutex_unlock(&hpfs_i(inode)->i_parent_mutex); hpfs_unlock(dir->i_sb); return err; } @@ -568,12 +546,6 @@ static int hpfs_rename(struct inode *old_dir, struct dentry *old_dentry, hpfs_lock(i->i_sb); /* order doesn't matter, due to VFS exclusion */ - mutex_lock(&hpfs_i(i)->i_parent_mutex); - if (new_inode) - mutex_lock(&hpfs_i(new_inode)->i_parent_mutex); - mutex_lock(&hpfs_i(old_dir)->i_mutex); - if (new_dir != old_dir) - mutex_lock(&hpfs_i(new_dir)->i_mutex); /* Erm? Moving over the empty non-busy directory is perfectly legal */ if (new_inode && S_ISDIR(new_inode->i_mode)) { @@ -610,9 +582,7 @@ static int hpfs_rename(struct inode *old_dir, struct dentry *old_dentry, if (new_dir == old_dir) hpfs_brelse4(&qbh); - hpfs_lock_creation(i->i_sb); - if ((r = hpfs_add_dirent(new_dir, new_name, new_len, &de, 1))) { - hpfs_unlock_creation(i->i_sb); + if ((r = hpfs_add_dirent(new_dir, new_name, new_len, &de))) { if (r == -1) hpfs_error(new_dir->i_sb, "hpfs_rename: dirent already exists!"); err = r == 1 ? -ENOSPC : -EFSERROR; if (new_dir != old_dir) hpfs_brelse4(&qbh); @@ -621,20 +591,17 @@ static int hpfs_rename(struct inode *old_dir, struct dentry *old_dentry, if (new_dir == old_dir) if (!(dep = map_dirent(old_dir, hpfs_i(old_dir)->i_dno, old_name, old_len, &dno, &qbh))) { - hpfs_unlock_creation(i->i_sb); hpfs_error(i->i_sb, "lookup succeeded but map dirent failed at #2"); err = -ENOENT; goto end1; } if ((r = hpfs_remove_dirent(old_dir, dno, dep, &qbh, 0))) { - hpfs_unlock_creation(i->i_sb); hpfs_error(i->i_sb, "hpfs_rename: could not remove dirent"); err = r == 2 ? -ENOSPC : -EFSERROR; goto end1; } - hpfs_unlock_creation(i->i_sb); - + end: hpfs_i(i)->i_parent_dir = new_dir->i_ino; if (S_ISDIR(i->i_mode)) { @@ -652,12 +619,6 @@ static int hpfs_rename(struct inode *old_dir, struct dentry *old_dentry, hpfs_i(i)->i_conv = hpfs_sb(i->i_sb)->sb_conv; hpfs_decide_conv(i, new_name, new_len); end1: - if (old_dir != new_dir) - mutex_unlock(&hpfs_i(new_dir)->i_mutex); - mutex_unlock(&hpfs_i(old_dir)->i_mutex); - mutex_unlock(&hpfs_i(i)->i_parent_mutex); - if (new_inode) - mutex_unlock(&hpfs_i(new_inode)->i_parent_mutex); hpfs_unlock(i->i_sb); return err; } diff --git a/fs/hpfs/super.c b/fs/hpfs/super.c index 41232c2..6493377 100644 --- a/fs/hpfs/super.c +++ b/fs/hpfs/super.c @@ -191,8 +191,6 @@ static void init_once(void *foo) { struct hpfs_inode_info *ei = (struct hpfs_inode_info *) foo; - mutex_init(&ei->i_mutex); - mutex_init(&ei->i_parent_mutex); inode_init_once(&ei->vfs_inode); } @@ -496,8 +494,6 @@ static int hpfs_fill_super(struct super_block *s, void *options, int silent) mutex_init(&sbi->hpfs_mutex); hpfs_lock(s); - mutex_init(&sbi->hpfs_creation_de); - uid = current_uid(); gid = current_gid(); umask = current_umask(); -- cgit v0.10.2 From 0fe105aa29bed0994991462b58ef61646db0e459 Mon Sep 17 00:00:00 2001 From: Mikulas Patocka Date: Sun, 8 May 2011 20:43:19 +0200 Subject: HPFS: Remove CR/LF conversion option Remove CR/LF conversion option It is unused anyway. It was used on 2.2 kernels or so. Signed-off-by: Mikulas Patocka Signed-off-by: Linus Torvalds diff --git a/fs/hpfs/dir.c b/fs/hpfs/dir.c index b3d7c0d..208f3d7 100644 --- a/fs/hpfs/dir.c +++ b/fs/hpfs/dir.c @@ -250,8 +250,6 @@ struct dentry *hpfs_lookup(struct inode *dir, struct dentry *dentry, struct name hpfs_result = hpfs_i(result); if (!de->directory) hpfs_result->i_parent_dir = dir->i_ino; - hpfs_decide_conv(result, name, len); - if (de->has_acl || de->has_xtd_perm) if (!(dir->i_sb->s_flags & MS_RDONLY)) { hpfs_error(result->i_sb, "ACLs or XPERM found. This is probably HPFS386. This driver doesn't support it now. Send me some info on these structures"); goto bail1; diff --git a/fs/hpfs/hpfs_fn.h b/fs/hpfs/hpfs_fn.h index 860d09f..d101086 100644 --- a/fs/hpfs/hpfs_fn.h +++ b/fs/hpfs/hpfs_fn.h @@ -51,7 +51,6 @@ struct hpfs_inode_info { unsigned i_disk_sec; /* (files) minimalist cache of alloc info */ unsigned i_n_secs; /* (files) minimalist cache of alloc info */ unsigned i_ea_size; /* size of extended attributes */ - unsigned i_conv : 2; /* (files) crlf->newline hackery */ unsigned i_ea_mode : 1; /* file's permission is stored in ea */ unsigned i_ea_uid : 1; /* file's uid is stored in ea */ unsigned i_ea_gid : 1; /* file's gid is stored in ea */ @@ -73,7 +72,6 @@ struct hpfs_sb_info { uid_t sb_uid; /* uid from mount options */ gid_t sb_gid; /* gid from mount options */ umode_t sb_mode; /* mode from mount options */ - unsigned sb_conv : 2; /* crlf->newline hackery */ unsigned sb_eas : 2; /* eas: 0-ignore, 1-ro, 2-rw */ unsigned sb_err : 2; /* on errs: 0-cont, 1-ro, 2-panic */ unsigned sb_chk : 2; /* checks: 0-no, 1-normal, 2-strict */ @@ -90,14 +88,6 @@ struct hpfs_sb_info { int sb_timeshift; }; -/* - * conv= options - */ - -#define CONV_BINARY 0 /* no conversion */ -#define CONV_TEXT 1 /* crlf->newline */ -#define CONV_AUTO 2 /* decide based on file contents */ - /* Four 512-byte buffers and the 2k block obtained by concatenating them */ struct quad_buffer_head { @@ -298,7 +288,6 @@ int hpfs_compare_names(struct super_block *, const unsigned char *, unsigned, const unsigned char *, unsigned, int); int hpfs_is_name_long(const unsigned char *, unsigned); void hpfs_adjust_length(const unsigned char *, unsigned *); -void hpfs_decide_conv(struct inode *, const unsigned char *, unsigned); /* namei.c */ diff --git a/fs/hpfs/inode.c b/fs/hpfs/inode.c index 29cf050..3b8eeb1 100644 --- a/fs/hpfs/inode.c +++ b/fs/hpfs/inode.c @@ -17,7 +17,6 @@ void hpfs_init_inode(struct inode *i) i->i_uid = hpfs_sb(sb)->sb_uid; i->i_gid = hpfs_sb(sb)->sb_gid; i->i_mode = hpfs_sb(sb)->sb_mode; - hpfs_inode->i_conv = hpfs_sb(sb)->sb_conv; i->i_size = -1; i->i_blocks = -1; diff --git a/fs/hpfs/name.c b/fs/hpfs/name.c index f24736d..9acdf33 100644 --- a/fs/hpfs/name.c +++ b/fs/hpfs/name.c @@ -8,39 +8,6 @@ #include "hpfs_fn.h" -static const char *text_postfix[]={ -".ASM", ".BAS", ".BAT", ".C", ".CC", ".CFG", ".CMD", ".CON", ".CPP", ".DEF", -".DOC", ".DPR", ".ERX", ".H", ".HPP", ".HTM", ".HTML", ".JAVA", ".LOG", ".PAS", -".RC", ".TEX", ".TXT", ".Y", ""}; - -static const char *text_prefix[]={ -"AUTOEXEC.", "CHANGES", "COPYING", "CONFIG.", "CREDITS", "FAQ", "FILE_ID.DIZ", -"MAKEFILE", "READ.ME", "README", "TERMCAP", ""}; - -void hpfs_decide_conv(struct inode *inode, const unsigned char *name, unsigned len) -{ - struct hpfs_inode_info *hpfs_inode = hpfs_i(inode); - int i; - if (hpfs_inode->i_conv != CONV_AUTO) return; - for (i = 0; *text_postfix[i]; i++) { - int l = strlen(text_postfix[i]); - if (l <= len) - if (!hpfs_compare_names(inode->i_sb, text_postfix[i], l, name + len - l, l, 0)) - goto text; - } - for (i = 0; *text_prefix[i]; i++) { - int l = strlen(text_prefix[i]); - if (l <= len) - if (!hpfs_compare_names(inode->i_sb, text_prefix[i], l, name, l, 0)) - goto text; - } - hpfs_inode->i_conv = CONV_BINARY; - return; - text: - hpfs_inode->i_conv = CONV_TEXT; - return; -} - static inline int not_allowed_char(unsigned char c) { return c<' ' || c=='"' || c=='*' || c=='/' || c==':' || c=='<' || diff --git a/fs/hpfs/namei.c b/fs/hpfs/namei.c index 8c9f915..9c66f0e 100644 --- a/fs/hpfs/namei.c +++ b/fs/hpfs/namei.c @@ -151,7 +151,6 @@ static int hpfs_create(struct inode *dir, struct dentry *dentry, int mode, struc result->i_op = &hpfs_file_iops; result->i_fop = &hpfs_file_ops; result->i_nlink = 1; - hpfs_decide_conv(result, name, len); hpfs_i(result)->i_parent_dir = dir->i_ino; result->i_ctime.tv_sec = result->i_mtime.tv_sec = result->i_atime.tv_sec = local_to_gmt(dir->i_sb, dee.creation_date); result->i_ctime.tv_nsec = 0; @@ -616,8 +615,6 @@ static int hpfs_rename(struct inode *old_dir, struct dentry *old_dentry, mark_buffer_dirty(bh); brelse(bh); } - hpfs_i(i)->i_conv = hpfs_sb(i->i_sb)->sb_conv; - hpfs_decide_conv(i, new_name, new_len); end1: hpfs_unlock(i->i_sb); return err; diff --git a/fs/hpfs/super.c b/fs/hpfs/super.c index 6493377..4858ff8 100644 --- a/fs/hpfs/super.c +++ b/fs/hpfs/super.c @@ -219,7 +219,6 @@ static void destroy_inodecache(void) enum { Opt_help, Opt_uid, Opt_gid, Opt_umask, Opt_case_lower, Opt_case_asis, - Opt_conv_binary, Opt_conv_text, Opt_conv_auto, Opt_check_none, Opt_check_normal, Opt_check_strict, Opt_err_cont, Opt_err_ro, Opt_err_panic, Opt_eas_no, Opt_eas_ro, Opt_eas_rw, @@ -234,9 +233,6 @@ static const match_table_t tokens = { {Opt_umask, "umask=%o"}, {Opt_case_lower, "case=lower"}, {Opt_case_asis, "case=asis"}, - {Opt_conv_binary, "conv=binary"}, - {Opt_conv_text, "conv=text"}, - {Opt_conv_auto, "conv=auto"}, {Opt_check_none, "check=none"}, {Opt_check_normal, "check=normal"}, {Opt_check_strict, "check=strict"}, @@ -254,7 +250,7 @@ static const match_table_t tokens = { }; static int parse_opts(char *opts, uid_t *uid, gid_t *gid, umode_t *umask, - int *lowercase, int *conv, int *eas, int *chk, int *errs, + int *lowercase, int *eas, int *chk, int *errs, int *chkdsk, int *timeshift) { char *p; @@ -296,15 +292,6 @@ static int parse_opts(char *opts, uid_t *uid, gid_t *gid, umode_t *umask, case Opt_case_asis: *lowercase = 0; break; - case Opt_conv_binary: - *conv = CONV_BINARY; - break; - case Opt_conv_text: - *conv = CONV_TEXT; - break; - case Opt_conv_auto: - *conv = CONV_AUTO; - break; case Opt_check_none: *chk = 0; break; @@ -371,9 +358,6 @@ HPFS filesystem options:\n\ umask=xxx set mode of files that don't have mode specified in eas\n\ case=lower lowercase all files\n\ case=asis do not lowercase files (default)\n\ - conv=binary do not convert CR/LF -> LF (default)\n\ - conv=auto convert only files with known text extensions\n\ - conv=text convert all files\n\ check=none no fs checks - kernel may crash on corrupted filesystem\n\ check=normal do some checks - it should not crash (default)\n\ check=strict do extra time-consuming checks, used for debugging\n\ @@ -395,7 +379,7 @@ static int hpfs_remount_fs(struct super_block *s, int *flags, char *data) uid_t uid; gid_t gid; umode_t umask; - int lowercase, conv, eas, chk, errs, chkdsk, timeshift; + int lowercase, eas, chk, errs, chkdsk, timeshift; int o; struct hpfs_sb_info *sbi = hpfs_sb(s); char *new_opts = kstrdup(data, GFP_KERNEL); @@ -406,11 +390,11 @@ static int hpfs_remount_fs(struct super_block *s, int *flags, char *data) lock_super(s); uid = sbi->sb_uid; gid = sbi->sb_gid; umask = 0777 & ~sbi->sb_mode; - lowercase = sbi->sb_lowercase; conv = sbi->sb_conv; + lowercase = sbi->sb_lowercase; eas = sbi->sb_eas; chk = sbi->sb_chk; chkdsk = sbi->sb_chkdsk; errs = sbi->sb_err; timeshift = sbi->sb_timeshift; - if (!(o = parse_opts(data, &uid, &gid, &umask, &lowercase, &conv, + if (!(o = parse_opts(data, &uid, &gid, &umask, &lowercase, &eas, &chk, &errs, &chkdsk, ×hift))) { printk("HPFS: bad mount options.\n"); goto out_err; @@ -428,7 +412,7 @@ static int hpfs_remount_fs(struct super_block *s, int *flags, char *data) sbi->sb_uid = uid; sbi->sb_gid = gid; sbi->sb_mode = 0777 & ~umask; - sbi->sb_lowercase = lowercase; sbi->sb_conv = conv; + sbi->sb_lowercase = lowercase; sbi->sb_eas = eas; sbi->sb_chk = chk; sbi->sb_chkdsk = chkdsk; sbi->sb_err = errs; sbi->sb_timeshift = timeshift; @@ -472,7 +456,7 @@ static int hpfs_fill_super(struct super_block *s, void *options, int silent) uid_t uid; gid_t gid; umode_t umask; - int lowercase, conv, eas, chk, errs, chkdsk, timeshift; + int lowercase, eas, chk, errs, chkdsk, timeshift; dnode_secno root_dno; struct hpfs_dirent *de = NULL; @@ -498,14 +482,13 @@ static int hpfs_fill_super(struct super_block *s, void *options, int silent) gid = current_gid(); umask = current_umask(); lowercase = 0; - conv = CONV_BINARY; eas = 2; chk = 1; errs = 1; chkdsk = 1; timeshift = 0; - if (!(o = parse_opts(options, &uid, &gid, &umask, &lowercase, &conv, + if (!(o = parse_opts(options, &uid, &gid, &umask, &lowercase, &eas, &chk, &errs, &chkdsk, ×hift))) { printk("HPFS: bad mount options.\n"); goto bail0; @@ -558,7 +541,6 @@ static int hpfs_fill_super(struct super_block *s, void *options, int silent) sbi->sb_n_free = -1; sbi->sb_n_free_dnodes = -1; sbi->sb_lowercase = lowercase; - sbi->sb_conv = conv; sbi->sb_eas = eas; sbi->sb_chk = chk; sbi->sb_chkdsk = chkdsk; -- cgit v0.10.2 From e5d6a7dd5e0b29eee4359e817e0bee728d7c5530 Mon Sep 17 00:00:00 2001 From: Mikulas Patocka Date: Sun, 8 May 2011 20:43:27 +0200 Subject: HPFS: Remove mark_inode_dirty Remove mark_inode_dirty HPFS doesn't use kernel's dirty inode indicator anyway because writing an inode requires directory's mutex. Signed-off-by: Mikulas Patocka Signed-off-by: Linus Torvalds diff --git a/fs/hpfs/inode.c b/fs/hpfs/inode.c index 3b8eeb1..d093ce7 100644 --- a/fs/hpfs/inode.c +++ b/fs/hpfs/inode.c @@ -199,8 +199,6 @@ void hpfs_write_inode(struct inode *i) } hpfs_write_inode_nolock(i); iput(parent); - } else { - mark_inode_dirty(i); } } @@ -278,7 +276,6 @@ int hpfs_setattr(struct dentry *dentry, struct iattr *attr) } setattr_copy(inode, attr); - mark_inode_dirty(inode); hpfs_write_inode(inode); -- cgit v0.10.2 From d878597c2c498b63abe3e68d343459944bc358f9 Mon Sep 17 00:00:00 2001 From: Mikulas Patocka Date: Sun, 8 May 2011 20:43:34 +0200 Subject: HPFS: Use types with defined width Use types with defined width Signed-off-by: Mikulas Patocka Signed-off-by: Linus Torvalds diff --git a/fs/hpfs/hpfs.h b/fs/hpfs/hpfs.h index 0e84c73..8cd5130 100644 --- a/fs/hpfs/hpfs.h +++ b/fs/hpfs/hpfs.h @@ -21,7 +21,7 @@ /* Notation */ -typedef unsigned secno; /* sector number, partition relative */ +typedef u32 secno; /* sector number, partition relative */ typedef secno dnode_secno; /* sector number of a dnode */ typedef secno fnode_secno; /* sector number of an fnode */ @@ -38,28 +38,28 @@ typedef u32 time32_t; /* 32-bit time_t type */ struct hpfs_boot_block { - unsigned char jmp[3]; - unsigned char oem_id[8]; - unsigned char bytes_per_sector[2]; /* 512 */ - unsigned char sectors_per_cluster; - unsigned char n_reserved_sectors[2]; - unsigned char n_fats; - unsigned char n_rootdir_entries[2]; - unsigned char n_sectors_s[2]; - unsigned char media_byte; - unsigned short sectors_per_fat; - unsigned short sectors_per_track; - unsigned short heads_per_cyl; - unsigned int n_hidden_sectors; - unsigned int n_sectors_l; /* size of partition */ - unsigned char drive_number; - unsigned char mbz; - unsigned char sig_28h; /* 28h */ - unsigned char vol_serno[4]; - unsigned char vol_label[11]; - unsigned char sig_hpfs[8]; /* "HPFS " */ - unsigned char pad[448]; - unsigned short magic; /* aa55 */ + u8 jmp[3]; + u8 oem_id[8]; + u8 bytes_per_sector[2]; /* 512 */ + u8 sectors_per_cluster; + u8 n_reserved_sectors[2]; + u8 n_fats; + u8 n_rootdir_entries[2]; + u8 n_sectors_s[2]; + u8 media_byte; + u16 sectors_per_fat; + u16 sectors_per_track; + u16 heads_per_cyl; + u32 n_hidden_sectors; + u32 n_sectors_l; /* size of partition */ + u8 drive_number; + u8 mbz; + u8 sig_28h; /* 28h */ + u8 vol_serno[4]; + u8 vol_label[11]; + u8 sig_hpfs[8]; /* "HPFS " */ + u8 pad[448]; + u16 magic; /* aa55 */ }; @@ -71,31 +71,30 @@ struct hpfs_boot_block struct hpfs_super_block { - unsigned magic; /* f995 e849 */ - unsigned magic1; /* fa53 e9c5, more magic? */ - /*unsigned huh202;*/ /* ?? 202 = N. of B. in 1.00390625 S.*/ - char version; /* version of a filesystem usually 2 */ - char funcversion; /* functional version - oldest version + u32 magic; /* f995 e849 */ + u32 magic1; /* fa53 e9c5, more magic? */ + u8 version; /* version of a filesystem usually 2 */ + u8 funcversion; /* functional version - oldest version of filesystem that can understand this disk */ - unsigned short int zero; /* 0 */ + u16 zero; /* 0 */ fnode_secno root; /* fnode of root directory */ secno n_sectors; /* size of filesystem */ - unsigned n_badblocks; /* number of bad blocks */ + u32 n_badblocks; /* number of bad blocks */ secno bitmaps; /* pointers to free space bit maps */ - unsigned zero1; /* 0 */ + u32 zero1; /* 0 */ secno badblocks; /* bad block list */ - unsigned zero3; /* 0 */ + u32 zero3; /* 0 */ time32_t last_chkdsk; /* date last checked, 0 if never */ - /*unsigned zero4;*/ /* 0 */ - time32_t last_optimize; /* date last optimized, 0 if never */ + /*u32 zero4;*/ /* 0 */ + time32_t last_optimize; /* date last optimized, 0 if never */ secno n_dir_band; /* number of sectors in dir band */ secno dir_band_start; /* first sector in dir band */ secno dir_band_end; /* last sector in dir band */ secno dir_band_bitmap; /* free space map, 1 dnode per bit */ - char volume_name[32]; /* not used */ + u8 volume_name[32]; /* not used */ secno user_id_table; /* 8 preallocated sectors - user id */ - unsigned zero6[103]; /* 0 */ + u32 zero6[103]; /* 0 */ }; @@ -107,11 +106,10 @@ struct hpfs_super_block struct hpfs_spare_block { - unsigned magic; /* f991 1849 */ - unsigned magic1; /* fa52 29c5, more magic? */ + u32 magic; /* f991 1849 */ + u32 magic1; /* fa52 29c5, more magic? */ unsigned dirty: 1; /* 0 clean, 1 "improperly stopped" */ - /*unsigned flag1234: 4;*/ /* unknown flags */ unsigned sparedir_used: 1; /* spare dirblks used */ unsigned hotfixes_used: 1; /* hotfixes used */ unsigned bad_sector: 1; /* bad sector, corrupted disk (???) */ @@ -126,25 +124,24 @@ struct hpfs_spare_block unsigned dce_acls_active: 1; unsigned dasd_limits_dirty: 1; unsigned flag67: 2; - unsigned char mm_contlgulty; - unsigned char unused; + u8 mm_contlgulty; + u8 unused; secno hotfix_map; /* info about remapped bad sectors */ - unsigned n_spares_used; /* number of hotfixes */ - unsigned n_spares; /* number of spares in hotfix map */ - unsigned n_dnode_spares_free; /* spare dnodes unused */ - unsigned n_dnode_spares; /* length of spare_dnodes[] list, + u32 n_spares_used; /* number of hotfixes */ + u32 n_spares; /* number of spares in hotfix map */ + u32 n_dnode_spares_free; /* spare dnodes unused */ + u32 n_dnode_spares; /* length of spare_dnodes[] list, follows in this block*/ secno code_page_dir; /* code page directory block */ - unsigned n_code_pages; /* number of code pages */ - /*unsigned large_numbers[2];*/ /* ?? */ - unsigned super_crc; /* on HPFS386 and LAN Server this is + u32 n_code_pages; /* number of code pages */ + u32 super_crc; /* on HPFS386 and LAN Server this is checksum of superblock, on normal OS/2 unused */ - unsigned spare_crc; /* on HPFS386 checksum of spareblock */ - unsigned zero1[15]; /* unused */ + u32 spare_crc; /* on HPFS386 checksum of spareblock */ + u32 zero1[15]; /* unused */ dnode_secno spare_dnodes[100]; /* emergency free dnode list */ - unsigned zero2[1]; /* room for more? */ + u32 zero2[1]; /* room for more? */ }; /* The bad block list is 4 sectors long. The first word must be zero, @@ -179,18 +176,18 @@ struct hpfs_spare_block struct code_page_directory { - unsigned magic; /* 4945 21f7 */ - unsigned n_code_pages; /* number of pointers following */ - unsigned zero1[2]; + u32 magic; /* 4945 21f7 */ + u32 n_code_pages; /* number of pointers following */ + u32 zero1[2]; struct { - unsigned short ix; /* index */ - unsigned short code_page_number; /* code page number */ - unsigned bounds; /* matches corresponding word + u16 ix; /* index */ + u16 code_page_number; /* code page number */ + u32 bounds; /* matches corresponding word in data block */ secno code_page_data; /* sector number of a code_page_data containing c.p. array */ - unsigned short index; /* index in c.p. array in that sector*/ - unsigned short unknown; /* some unknown value; usually 0; + u16 index; /* index in c.p. array in that sector*/ + u16 unknown; /* some unknown value; usually 0; 2 in Japanese version */ } array[31]; /* unknown length */ }; @@ -201,21 +198,21 @@ struct code_page_directory struct code_page_data { - unsigned magic; /* 8945 21f7 */ - unsigned n_used; /* # elements used in c_p_data[] */ - unsigned bounds[3]; /* looks a bit like + u32 magic; /* 8945 21f7 */ + u32 n_used; /* # elements used in c_p_data[] */ + u32 bounds[3]; /* looks a bit like (beg1,end1), (beg2,end2) one byte each */ - unsigned short offs[3]; /* offsets from start of sector + u16 offs[3]; /* offsets from start of sector to start of c_p_data[ix] */ struct { - unsigned short ix; /* index */ - unsigned short code_page_number; /* code page number */ - unsigned short unknown; /* the same as in cp directory */ - unsigned char map[128]; /* upcase table for chars 80..ff */ - unsigned short zero2; + u16 ix; /* index */ + u16 code_page_number; /* code page number */ + u16 unknown; /* the same as in cp directory */ + u8 map[128]; /* upcase table for chars 80..ff */ + u16 zero2; } code_page[3]; - unsigned char incognita[78]; + u8 incognita[78]; }; @@ -255,8 +252,8 @@ struct code_page_data #define DNODE_MAGIC 0x77e40aae struct dnode { - unsigned magic; /* 77e4 0aae */ - unsigned first_free; /* offset from start of dnode to + u32 magic; /* 77e4 0aae */ + u32 first_free; /* offset from start of dnode to first free dir entry */ unsigned root_dnode:1; /* Is it root dnode? */ unsigned increment_me:31; /* some kind of activity counter? @@ -265,11 +262,11 @@ struct dnode { secno up; /* (root dnode) directory's fnode (nonroot) parent dnode */ dnode_secno self; /* pointer to this dnode */ - unsigned char dirent[2028]; /* one or more dirents */ + u8 dirent[2028]; /* one or more dirents */ }; struct hpfs_dirent { - unsigned short length; /* offset to next dirent */ + u16 length; /* offset to next dirent */ unsigned first: 1; /* set on phony ^A^A (".") entry */ unsigned has_acl: 1; unsigned down: 1; /* down pointer present (after name) */ @@ -290,15 +287,15 @@ struct hpfs_dirent { unsigned flag15: 1; fnode_secno fnode; /* fnode giving allocation info */ time32_t write_date; /* mtime */ - unsigned file_size; /* file length, bytes */ + u32 file_size; /* file length, bytes */ time32_t read_date; /* atime */ time32_t creation_date; /* ctime */ - unsigned ea_size; /* total EA length, bytes */ + u32 ea_size; /* total EA length, bytes */ unsigned char no_of_acls : 3; /* number of ACL's */ unsigned char reserver : 5; - unsigned char ix; /* code page index (of filename), see + u8 ix; /* code page index (of filename), see struct code_page_data */ - unsigned char namelen, name[1]; /* file name */ + u8 namelen, name[1]; /* file name */ /* dnode_secno down; btree down pointer, if present, follows name on next word boundary, or maybe it precedes next dirent, which is on a word boundary. */ @@ -318,14 +315,14 @@ struct hpfs_dirent { struct bplus_leaf_node { - unsigned file_secno; /* first file sector in extent */ - unsigned length; /* length, sectors */ + u32 file_secno; /* first file sector in extent */ + u32 length; /* length, sectors */ secno disk_secno; /* first corresponding disk sector */ }; struct bplus_internal_node { - unsigned file_secno; /* subtree maps sectors < this */ + u32 file_secno; /* subtree maps sectors < this */ anode_secno down; /* pointer to subtree */ }; @@ -346,10 +343,10 @@ struct bplus_header unsigned binary_search: 1; /* suggest binary search (unused) */ unsigned internal: 1; /* 1 -> (internal) tree of anodes 0 -> (leaf) list of extents */ - unsigned char fill[3]; - unsigned char n_free_nodes; /* free nodes in following array */ - unsigned char n_used_nodes; /* used nodes in following array */ - unsigned short first_free; /* offset from start of header to + u8 fill[3]; + u8 n_free_nodes; /* free nodes in following array */ + u8 n_used_nodes; /* used nodes in following array */ + u16 first_free; /* offset from start of header to first free node in array */ union { struct bplus_internal_node internal[0]; /* (internal) 2-word entries giving @@ -369,19 +366,18 @@ struct bplus_header struct fnode { - unsigned magic; /* f7e4 0aae */ - unsigned zero1[2]; /* read history */ - unsigned char len, name[15]; /* true length, truncated name */ + u32 magic; /* f7e4 0aae */ + u32 zero1[2]; /* read history */ + u8 len, name[15]; /* true length, truncated name */ fnode_secno up; /* pointer to file's directory fnode */ - /*unsigned zero2[3];*/ secno acl_size_l; secno acl_secno; - unsigned short acl_size_s; - char acl_anode; - char zero2; /* history bit count */ - unsigned ea_size_l; /* length of disk-resident ea's */ + u16 acl_size_s; + u8 acl_anode; + u8 zero2; /* history bit count */ + u32 ea_size_l; /* length of disk-resident ea's */ secno ea_secno; /* first sector of disk-resident ea's*/ - unsigned short ea_size_s; /* length of fnode-resident ea's */ + u16 ea_size_s; /* length of fnode-resident ea's */ unsigned flag0: 1; unsigned ea_anode: 1; /* 1 -> ea_secno is an anode */ @@ -407,17 +403,16 @@ struct fnode struct bplus_internal_node internal[12]; } u; - unsigned file_size; /* file length, bytes */ - unsigned n_needea; /* number of EA's with NEEDEA set */ - char user_id[16]; /* unused */ - unsigned short ea_offs; /* offset from start of fnode + u32 file_size; /* file length, bytes */ + u32 n_needea; /* number of EA's with NEEDEA set */ + u8 user_id[16]; /* unused */ + u16 ea_offs; /* offset from start of fnode to first fnode-resident ea */ - char dasd_limit_treshhold; - char dasd_limit_delta; - unsigned dasd_limit; - unsigned dasd_usage; - /*unsigned zero5[2];*/ - unsigned char ea[316]; /* zero or more EA's, packed together + u8 dasd_limit_treshhold; + u8 dasd_limit_delta; + u32 dasd_limit; + u32 dasd_usage; + u8 ea[316]; /* zero or more EA's, packed together with no alignment padding. (Do not use this name, get here via fnode + ea_offs. I think.) */ @@ -430,7 +425,7 @@ struct fnode struct anode { - unsigned magic; /* 37e4 0aae */ + u32 magic; /* 37e4 0aae */ anode_secno self; /* pointer to this anode */ secno up; /* parent anode or fnode */ @@ -440,7 +435,7 @@ struct anode struct bplus_internal_node internal[60]; } u; - unsigned fill[3]; /* unused */ + u32 fill[3]; /* unused */ }; @@ -471,15 +466,15 @@ struct extended_attribute unsigned flag5: 1; unsigned flag6: 1; unsigned needea: 1; /* required ea */ - unsigned char namelen; /* length of name, bytes */ - unsigned short valuelen; /* length of value, bytes */ - unsigned char name[0]; + u8 namelen; /* length of name, bytes */ + u16 valuelen; /* length of value, bytes */ + u8 name[0]; /* - unsigned char name[namelen]; ascii attrib name - unsigned char nul; terminating '\0', not counted - unsigned char value[valuelen]; value, arbitrary + u8 name[namelen]; ascii attrib name + u8 nul; terminating '\0', not counted + u8 value[valuelen]; value, arbitrary if this.indirect, valuelen is 8 and the value is - unsigned length; real length of value, bytes + u32 length; real length of value, bytes secno secno; sector address where it starts if this.anode, the above sector number is the root of an anode tree which points to the value. -- cgit v0.10.2 From f73976818adeaa46515a238b21e865850b011a87 Mon Sep 17 00:00:00 2001 From: Mikulas Patocka Date: Sun, 8 May 2011 20:43:41 +0200 Subject: HPFS: When marking or clearing the dirty bit, sync the filesystem When marking or clearing the dirty bit, sync the filesystem Signed-off-by: Mikulas Patocka Signed-off-by: Linus Torvalds diff --git a/fs/hpfs/super.c b/fs/hpfs/super.c index 4858ff8..07e8d0c 100644 --- a/fs/hpfs/super.c +++ b/fs/hpfs/super.c @@ -27,6 +27,7 @@ static void mark_dirty(struct super_block *s) sb->dirty = 1; sb->old_wrote = 0; mark_buffer_dirty(bh); + sync_dirty_buffer(bh); brelse(bh); } } @@ -40,10 +41,12 @@ static void unmark_dirty(struct super_block *s) struct buffer_head *bh; struct hpfs_spare_block *sb; if (s->s_flags & MS_RDONLY) return; + sync_blockdev(s->s_bdev); if ((sb = hpfs_map_sector(s, 17, &bh, 0))) { sb->dirty = hpfs_sb(s)->sb_chkdsk > 1 - hpfs_sb(s)->sb_was_error; sb->old_wrote = hpfs_sb(s)->sb_chkdsk >= 2 && !hpfs_sb(s)->sb_was_error; mark_buffer_dirty(bh); + sync_dirty_buffer(bh); brelse(bh); } } -- cgit v0.10.2 From 48f10e8ce7461b393186c4c7c6d6f6634082159c Mon Sep 17 00:00:00 2001 From: Mikulas Patocka Date: Sun, 8 May 2011 20:44:00 +0200 Subject: HPFS: Restrict uid and gid to 16-bit values Restrict uid and gid to 16-bit values. HPFS stores only 2 bytes in the EAs. Signed-off-by: Mikulas Patocka Signed-off-by: Linus Torvalds diff --git a/fs/hpfs/inode.c b/fs/hpfs/inode.c index d093ce7..bc61bb4 100644 --- a/fs/hpfs/inode.c +++ b/fs/hpfs/inode.c @@ -261,6 +261,10 @@ int hpfs_setattr(struct dentry *dentry, struct iattr *attr) hpfs_lock(inode->i_sb); if (inode->i_ino == hpfs_sb(inode->i_sb)->sb_root) goto out_unlock; + if ((attr->ia_valid & ATTR_UID) && attr->ia_uid >= 0x10000) + goto out_unlock; + if ((attr->ia_valid & ATTR_GID) && attr->ia_gid >= 0x10000) + goto out_unlock; if ((attr->ia_valid & ATTR_SIZE) && attr->ia_size > inode->i_size) goto out_unlock; -- cgit v0.10.2 From dab4c82a6e7ee2c60e63737eaa2ec283f9784df6 Mon Sep 17 00:00:00 2001 From: Mikulas Patocka Date: Sun, 8 May 2011 20:44:08 +0200 Subject: HPFS: Fix a bug that filesystem was not marked dirty when remounting it Fix a bug that filesystem was not marked dirty when remounting it Signed-off-by: Mikulas Patocka Signed-off-by: Linus Torvalds diff --git a/fs/hpfs/super.c b/fs/hpfs/super.c index 07e8d0c..4a7d026 100644 --- a/fs/hpfs/super.c +++ b/fs/hpfs/super.c @@ -18,9 +18,9 @@ /* Mark the filesystem dirty, so that chkdsk checks it when os/2 booted */ -static void mark_dirty(struct super_block *s) +static void mark_dirty(struct super_block *s, int remount) { - if (hpfs_sb(s)->sb_chkdsk && !(s->s_flags & MS_RDONLY)) { + if (hpfs_sb(s)->sb_chkdsk && (remount || !(s->s_flags & MS_RDONLY))) { struct buffer_head *bh; struct hpfs_spare_block *sb; if ((sb = hpfs_map_sector(s, 17, &bh, 0))) { @@ -66,13 +66,13 @@ void hpfs_error(struct super_block *s, const char *fmt, ...) if (!hpfs_sb(s)->sb_was_error) { if (hpfs_sb(s)->sb_err == 2) { printk("; crashing the system because you wanted it\n"); - mark_dirty(s); + mark_dirty(s, 0); panic("HPFS panic"); } else if (hpfs_sb(s)->sb_err == 1) { if (s->s_flags & MS_RDONLY) printk("; already mounted read-only\n"); else { printk("; remounting read-only\n"); - mark_dirty(s); + mark_dirty(s, 0); s->s_flags |= MS_RDONLY; } } else if (s->s_flags & MS_RDONLY) printk("; going on - but anything won't be destroyed because it's read-only\n"); @@ -419,7 +419,7 @@ static int hpfs_remount_fs(struct super_block *s, int *flags, char *data) sbi->sb_eas = eas; sbi->sb_chk = chk; sbi->sb_chkdsk = chkdsk; sbi->sb_err = errs; sbi->sb_timeshift = timeshift; - if (!(*flags & MS_RDONLY)) mark_dirty(s); + if (!(*flags & MS_RDONLY)) mark_dirty(s, 1); replace_mount_options(s, new_opts); @@ -576,7 +576,7 @@ static int hpfs_fill_super(struct super_block *s, void *options, int silent) if (spareblock->hotfixes_used || spareblock->n_spares_used) { if (errs >= 2) { printk("HPFS: Hotfixes not supported here, try chkdsk\n"); - mark_dirty(s); + mark_dirty(s, 0); goto bail4; } hpfs_error(s, "hotfixes not supported here, try chkdsk"); @@ -586,7 +586,7 @@ static int hpfs_fill_super(struct super_block *s, void *options, int silent) if (spareblock->n_dnode_spares != spareblock->n_dnode_spares_free) { if (errs >= 2) { printk("HPFS: Spare dnodes used, try chkdsk\n"); - mark_dirty(s); + mark_dirty(s, 0); goto bail4; } hpfs_error(s, "warning: spare dnodes used, try chkdsk"); @@ -605,7 +605,7 @@ static int hpfs_fill_super(struct super_block *s, void *options, int silent) if (hpfs_chk_sectors(s, superblock->dir_band_start, superblock->n_dir_band, "dir_band") || hpfs_chk_sectors(s, superblock->dir_band_bitmap, 4, "dir_band_bitmap") || hpfs_chk_sectors(s, superblock->bitmaps, 4, "bitmaps")) { - mark_dirty(s); + mark_dirty(s, 0); goto bail4; } sbi->sb_dirband_size = a; -- cgit v0.10.2 From bc8728ee56bca62df269b2dd159bc60838ac8e80 Mon Sep 17 00:00:00 2001 From: Mikulas Patocka Date: Sun, 8 May 2011 20:44:19 +0200 Subject: HPFS: Implement fsync for hpfs Implement fsync for hpfs. Signed-off-by: Mikulas Patocka Signed-off-by: Linus Torvalds diff --git a/fs/hpfs/file.c b/fs/hpfs/file.c index 09a642f..89c500e 100644 --- a/fs/hpfs/file.c +++ b/fs/hpfs/file.c @@ -20,8 +20,8 @@ static int hpfs_file_release(struct inode *inode, struct file *file) int hpfs_file_fsync(struct file *file, int datasync) { - /*return file_fsync(file, datasync);*/ - return 0; /* Don't fsync :-) */ + struct inode *inode = file->f_mapping->host; + return sync_blockdev(inode->i_sb->s_bdev); } /* -- cgit v0.10.2 From 0b69760be6968c528869d4aec95ecf64dbf3e8bd Mon Sep 17 00:00:00 2001 From: Mikulas Patocka Date: Sun, 8 May 2011 20:44:26 +0200 Subject: HPFS: Fix endianity. Make hpfs work on big-endian machines Fix endianity. Make hpfs work on big-endian machines. Signed-off-by: Mikulas Patocka Signed-off-by: Linus Torvalds diff --git a/fs/hpfs/alloc.c b/fs/hpfs/alloc.c index 995472d..7a5eb2c 100644 --- a/fs/hpfs/alloc.c +++ b/fs/hpfs/alloc.c @@ -16,9 +16,9 @@ static int chk_if_allocated(struct super_block *s, secno sec, char *msg) { struct quad_buffer_head qbh; - unsigned *bmp; + u32 *bmp; if (!(bmp = hpfs_map_bitmap(s, sec >> 14, &qbh, "chk"))) goto fail; - if ((bmp[(sec & 0x3fff) >> 5] >> (sec & 0x1f)) & 1) { + if ((cpu_to_le32(bmp[(sec & 0x3fff) >> 5]) >> (sec & 0x1f)) & 1) { hpfs_error(s, "sector '%s' - %08x not allocated in bitmap", msg, sec); goto fail1; } @@ -26,7 +26,7 @@ static int chk_if_allocated(struct super_block *s, secno sec, char *msg) if (sec >= hpfs_sb(s)->sb_dirband_start && sec < hpfs_sb(s)->sb_dirband_start + hpfs_sb(s)->sb_dirband_size) { unsigned ssec = (sec - hpfs_sb(s)->sb_dirband_start) / 4; if (!(bmp = hpfs_map_dnode_bitmap(s, &qbh))) goto fail; - if ((bmp[ssec >> 5] >> (ssec & 0x1f)) & 1) { + if ((le32_to_cpu(bmp[ssec >> 5]) >> (ssec & 0x1f)) & 1) { hpfs_error(s, "sector '%s' - %08x not allocated in directory bitmap", msg, sec); goto fail1; } @@ -82,10 +82,6 @@ static secno alloc_in_bmp(struct super_block *s, secno near, unsigned n, unsigne ret = bs + nr; goto rt; } - /*if (!tstbits(bmp, nr + n, n + forward)) { - ret = bs + nr + n; - goto rt; - }*/ q = nr + n; b = 0; while ((a = tstbits(bmp, q, n + forward)) != 0) { q += a; @@ -102,14 +98,14 @@ static secno alloc_in_bmp(struct super_block *s, secno near, unsigned n, unsigne goto rt; } nr >>= 5; - /*for (i = nr + 1; i != nr; i++, i &= 0x1ff) {*/ + /*for (i = nr + 1; i != nr; i++, i &= 0x1ff) */ i = nr; do { - if (!bmp[i]) goto cont; - if (n + forward >= 0x3f && bmp[i] != -1) goto cont; + if (!le32_to_cpu(bmp[i])) goto cont; + if (n + forward >= 0x3f && le32_to_cpu(bmp[i]) != 0xffffffff) goto cont; q = i<<5; if (i > 0) { - unsigned k = bmp[i-1]; + unsigned k = le32_to_cpu(bmp[i-1]); while (k & 0x80000000) { q--; k <<= 1; } @@ -129,12 +125,12 @@ static secno alloc_in_bmp(struct super_block *s, secno near, unsigned n, unsigne } while (i != nr); rt: if (ret) { - if (hpfs_sb(s)->sb_chk && ((ret >> 14) != (bs >> 14) || (bmp[(ret & 0x3fff) >> 5] | ~(((1 << n) - 1) << (ret & 0x1f))) != 0xffffffff)) { + if (hpfs_sb(s)->sb_chk && ((ret >> 14) != (bs >> 14) || (le32_to_cpu(bmp[(ret & 0x3fff) >> 5]) | ~(((1 << n) - 1) << (ret & 0x1f))) != 0xffffffff)) { hpfs_error(s, "Allocation doesn't work! Wanted %d, allocated at %08x", n, ret); ret = 0; goto b; } - bmp[(ret & 0x3fff) >> 5] &= ~(((1 << n) - 1) << (ret & 0x1f)); + bmp[(ret & 0x3fff) >> 5] &= cpu_to_le32(~(((1 << n) - 1) << (ret & 0x1f))); hpfs_mark_4buffers_dirty(&qbh); } b: @@ -240,10 +236,10 @@ static secno alloc_in_dirband(struct super_block *s, secno near) int hpfs_alloc_if_possible(struct super_block *s, secno sec) { struct quad_buffer_head qbh; - unsigned *bmp; + u32 *bmp; if (!(bmp = hpfs_map_bitmap(s, sec >> 14, &qbh, "aip"))) goto end; - if (bmp[(sec & 0x3fff) >> 5] & (1 << (sec & 0x1f))) { - bmp[(sec & 0x3fff) >> 5] &= ~(1 << (sec & 0x1f)); + if (le32_to_cpu(bmp[(sec & 0x3fff) >> 5]) & (1 << (sec & 0x1f))) { + bmp[(sec & 0x3fff) >> 5] &= cpu_to_le32(~(1 << (sec & 0x1f))); hpfs_mark_4buffers_dirty(&qbh); hpfs_brelse4(&qbh); return 1; @@ -258,7 +254,7 @@ int hpfs_alloc_if_possible(struct super_block *s, secno sec) void hpfs_free_sectors(struct super_block *s, secno sec, unsigned n) { struct quad_buffer_head qbh; - unsigned *bmp; + u32 *bmp; struct hpfs_sb_info *sbi = hpfs_sb(s); /*printk("2 - ");*/ if (!n) return; @@ -273,12 +269,12 @@ void hpfs_free_sectors(struct super_block *s, secno sec, unsigned n) return; } new_tst: - if ((bmp[(sec & 0x3fff) >> 5] >> (sec & 0x1f) & 1)) { + if ((le32_to_cpu(bmp[(sec & 0x3fff) >> 5]) >> (sec & 0x1f) & 1)) { hpfs_error(s, "sector %08x not allocated", sec); hpfs_brelse4(&qbh); return; } - bmp[(sec & 0x3fff) >> 5] |= 1 << (sec & 0x1f); + bmp[(sec & 0x3fff) >> 5] |= cpu_to_le32(1 << (sec & 0x1f)); if (!--n) { hpfs_mark_4buffers_dirty(&qbh); hpfs_brelse4(&qbh); @@ -303,13 +299,13 @@ int hpfs_check_free_dnodes(struct super_block *s, int n) int n_bmps = (hpfs_sb(s)->sb_fs_size + 0x4000 - 1) >> 14; int b = hpfs_sb(s)->sb_c_bitmap & 0x0fffffff; int i, j; - unsigned *bmp; + u32 *bmp; struct quad_buffer_head qbh; if ((bmp = hpfs_map_dnode_bitmap(s, &qbh))) { for (j = 0; j < 512; j++) { unsigned k; - if (!bmp[j]) continue; - for (k = bmp[j]; k; k >>= 1) if (k & 1) if (!--n) { + if (!le32_to_cpu(bmp[j])) continue; + for (k = le32_to_cpu(bmp[j]); k; k >>= 1) if (k & 1) if (!--n) { hpfs_brelse4(&qbh); return 0; } @@ -328,10 +324,10 @@ int hpfs_check_free_dnodes(struct super_block *s, int n) chk_bmp: if (bmp) { for (j = 0; j < 512; j++) { - unsigned k; - if (!bmp[j]) continue; + u32 k; + if (!le32_to_cpu(bmp[j])) continue; for (k = 0xf; k; k <<= 4) - if ((bmp[j] & k) == k) { + if ((le32_to_cpu(bmp[j]) & k) == k) { if (!--n) { hpfs_brelse4(&qbh); return 0; @@ -355,12 +351,12 @@ void hpfs_free_dnode(struct super_block *s, dnode_secno dno) hpfs_free_sectors(s, dno, 4); } else { struct quad_buffer_head qbh; - unsigned *bmp; + u32 *bmp; unsigned ssec = (dno - hpfs_sb(s)->sb_dirband_start) / 4; if (!(bmp = hpfs_map_dnode_bitmap(s, &qbh))) { return; } - bmp[ssec >> 5] |= 1 << (ssec & 0x1f); + bmp[ssec >> 5] |= cpu_to_le32(1 << (ssec & 0x1f)); hpfs_mark_4buffers_dirty(&qbh); hpfs_brelse4(&qbh); } @@ -382,13 +378,13 @@ struct dnode *hpfs_alloc_dnode(struct super_block *s, secno near, return NULL; } memset(d, 0, 2048); - d->magic = DNODE_MAGIC; - d->first_free = 52; + d->magic = cpu_to_le32(DNODE_MAGIC); + d->first_free = cpu_to_le32(52); d->dirent[0] = 32; d->dirent[2] = 8; d->dirent[30] = 1; d->dirent[31] = 255; - d->self = *dno; + d->self = cpu_to_le32(*dno); return d; } @@ -402,10 +398,10 @@ struct fnode *hpfs_alloc_fnode(struct super_block *s, secno near, fnode_secno *f return NULL; } memset(f, 0, 512); - f->magic = FNODE_MAGIC; - f->ea_offs = 0xc4; + f->magic = cpu_to_le32(FNODE_MAGIC); + f->ea_offs = cpu_to_le16(0xc4); f->btree.n_free_nodes = 8; - f->btree.first_free = 8; + f->btree.first_free = cpu_to_le16(8); return f; } @@ -419,10 +415,10 @@ struct anode *hpfs_alloc_anode(struct super_block *s, secno near, anode_secno *a return NULL; } memset(a, 0, 512); - a->magic = ANODE_MAGIC; - a->self = *ano; + a->magic = cpu_to_le32(ANODE_MAGIC); + a->self = cpu_to_le32(*ano); a->btree.n_free_nodes = 40; a->btree.n_used_nodes = 0; - a->btree.first_free = 8; + a->btree.first_free = cpu_to_le16(8); return a; } diff --git a/fs/hpfs/anode.c b/fs/hpfs/anode.c index f2a0384..08b503e 100644 --- a/fs/hpfs/anode.c +++ b/fs/hpfs/anode.c @@ -22,8 +22,8 @@ secno hpfs_bplus_lookup(struct super_block *s, struct inode *inode, if (hpfs_sb(s)->sb_chk) if (hpfs_stop_cycles(s, a, &c1, &c2, "hpfs_bplus_lookup")) return -1; if (btree->internal) { for (i = 0; i < btree->n_used_nodes; i++) - if (btree->u.internal[i].file_secno > sec) { - a = btree->u.internal[i].down; + if (le32_to_cpu(btree->u.internal[i].file_secno) > sec) { + a = le32_to_cpu(btree->u.internal[i].down); brelse(bh); if (!(anode = hpfs_map_anode(s, a, &bh))) return -1; btree = &anode->btree; @@ -34,18 +34,18 @@ secno hpfs_bplus_lookup(struct super_block *s, struct inode *inode, return -1; } for (i = 0; i < btree->n_used_nodes; i++) - if (btree->u.external[i].file_secno <= sec && - btree->u.external[i].file_secno + btree->u.external[i].length > sec) { - a = btree->u.external[i].disk_secno + sec - btree->u.external[i].file_secno; + if (le32_to_cpu(btree->u.external[i].file_secno) <= sec && + le32_to_cpu(btree->u.external[i].file_secno) + le32_to_cpu(btree->u.external[i].length) > sec) { + a = le32_to_cpu(btree->u.external[i].disk_secno) + sec - le32_to_cpu(btree->u.external[i].file_secno); if (hpfs_sb(s)->sb_chk) if (hpfs_chk_sectors(s, a, 1, "data")) { brelse(bh); return -1; } if (inode) { struct hpfs_inode_info *hpfs_inode = hpfs_i(inode); - hpfs_inode->i_file_sec = btree->u.external[i].file_secno; - hpfs_inode->i_disk_sec = btree->u.external[i].disk_secno; - hpfs_inode->i_n_secs = btree->u.external[i].length; + hpfs_inode->i_file_sec = le32_to_cpu(btree->u.external[i].file_secno); + hpfs_inode->i_disk_sec = le32_to_cpu(btree->u.external[i].disk_secno); + hpfs_inode->i_n_secs = le32_to_cpu(btree->u.external[i].length); } brelse(bh); return a; @@ -83,8 +83,8 @@ secno hpfs_add_sector_to_btree(struct super_block *s, secno node, int fnod, unsi return -1; } if (btree->internal) { - a = btree->u.internal[n].down; - btree->u.internal[n].file_secno = -1; + a = le32_to_cpu(btree->u.internal[n].down); + btree->u.internal[n].file_secno = cpu_to_le32(-1); mark_buffer_dirty(bh); brelse(bh); if (hpfs_sb(s)->sb_chk) @@ -94,15 +94,15 @@ secno hpfs_add_sector_to_btree(struct super_block *s, secno node, int fnod, unsi goto go_down; } if (n >= 0) { - if (btree->u.external[n].file_secno + btree->u.external[n].length != fsecno) { + if (le32_to_cpu(btree->u.external[n].file_secno) + le32_to_cpu(btree->u.external[n].length) != fsecno) { hpfs_error(s, "allocated size %08x, trying to add sector %08x, %cnode %08x", - btree->u.external[n].file_secno + btree->u.external[n].length, fsecno, + le32_to_cpu(btree->u.external[n].file_secno) + le32_to_cpu(btree->u.external[n].length), fsecno, fnod?'f':'a', node); brelse(bh); return -1; } - if (hpfs_alloc_if_possible(s, se = btree->u.external[n].disk_secno + btree->u.external[n].length)) { - btree->u.external[n].length++; + if (hpfs_alloc_if_possible(s, se = le32_to_cpu(btree->u.external[n].disk_secno) + le32_to_cpu(btree->u.external[n].length))) { + btree->u.external[n].length = cpu_to_le32(le32_to_cpu(btree->u.external[n].length) + 1); mark_buffer_dirty(bh); brelse(bh); return se; @@ -119,16 +119,16 @@ secno hpfs_add_sector_to_btree(struct super_block *s, secno node, int fnod, unsi brelse(bh); return -1; } - fs = n < 0 ? 0 : btree->u.external[n].file_secno + btree->u.external[n].length; + fs = n < 0 ? 0 : le32_to_cpu(btree->u.external[n].file_secno) + le32_to_cpu(btree->u.external[n].length); if (!btree->n_free_nodes) { - up = a != node ? anode->up : -1; + up = a != node ? le32_to_cpu(anode->up) : -1; if (!(anode = hpfs_alloc_anode(s, a, &na, &bh1))) { brelse(bh); hpfs_free_sectors(s, se, 1); return -1; } if (a == node && fnod) { - anode->up = node; + anode->up = cpu_to_le32(node); anode->btree.fnode_parent = 1; anode->btree.n_used_nodes = btree->n_used_nodes; anode->btree.first_free = btree->first_free; @@ -137,9 +137,9 @@ secno hpfs_add_sector_to_btree(struct super_block *s, secno node, int fnod, unsi btree->internal = 1; btree->n_free_nodes = 11; btree->n_used_nodes = 1; - btree->first_free = (char *)&(btree->u.internal[1]) - (char *)btree; - btree->u.internal[0].file_secno = -1; - btree->u.internal[0].down = na; + btree->first_free = cpu_to_le16((char *)&(btree->u.internal[1]) - (char *)btree); + btree->u.internal[0].file_secno = cpu_to_le32(-1); + btree->u.internal[0].down = cpu_to_le32(na); mark_buffer_dirty(bh); } else if (!(ranode = hpfs_alloc_anode(s, /*a*/0, &ra, &bh2))) { brelse(bh); @@ -153,15 +153,15 @@ secno hpfs_add_sector_to_btree(struct super_block *s, secno node, int fnod, unsi btree = &anode->btree; } btree->n_free_nodes--; n = btree->n_used_nodes++; - btree->first_free += 12; - btree->u.external[n].disk_secno = se; - btree->u.external[n].file_secno = fs; - btree->u.external[n].length = 1; + btree->first_free = cpu_to_le16(le16_to_cpu(btree->first_free) + 12); + btree->u.external[n].disk_secno = cpu_to_le32(se); + btree->u.external[n].file_secno = cpu_to_le32(fs); + btree->u.external[n].length = cpu_to_le32(1); mark_buffer_dirty(bh); brelse(bh); if ((a == node && fnod) || na == -1) return se; c2 = 0; - while (up != -1) { + while (up != (anode_secno)-1) { struct anode *new_anode; if (hpfs_sb(s)->sb_chk) if (hpfs_stop_cycles(s, up, &c1, &c2, "hpfs_add_sector_to_btree #2")) return -1; @@ -174,47 +174,47 @@ secno hpfs_add_sector_to_btree(struct super_block *s, secno node, int fnod, unsi } if (btree->n_free_nodes) { btree->n_free_nodes--; n = btree->n_used_nodes++; - btree->first_free += 8; - btree->u.internal[n].file_secno = -1; - btree->u.internal[n].down = na; - btree->u.internal[n-1].file_secno = fs; + btree->first_free = cpu_to_le16(le16_to_cpu(btree->first_free) + 8); + btree->u.internal[n].file_secno = cpu_to_le32(-1); + btree->u.internal[n].down = cpu_to_le32(na); + btree->u.internal[n-1].file_secno = cpu_to_le32(fs); mark_buffer_dirty(bh); brelse(bh); brelse(bh2); hpfs_free_sectors(s, ra, 1); if ((anode = hpfs_map_anode(s, na, &bh))) { - anode->up = up; + anode->up = cpu_to_le32(up); anode->btree.fnode_parent = up == node && fnod; mark_buffer_dirty(bh); brelse(bh); } return se; } - up = up != node ? anode->up : -1; - btree->u.internal[btree->n_used_nodes - 1].file_secno = /*fs*/-1; + up = up != node ? le32_to_cpu(anode->up) : -1; + btree->u.internal[btree->n_used_nodes - 1].file_secno = cpu_to_le32(/*fs*/-1); mark_buffer_dirty(bh); brelse(bh); a = na; if ((new_anode = hpfs_alloc_anode(s, a, &na, &bh))) { anode = new_anode; - /*anode->up = up != -1 ? up : ra;*/ + /*anode->up = cpu_to_le32(up != -1 ? up : ra);*/ anode->btree.internal = 1; anode->btree.n_used_nodes = 1; anode->btree.n_free_nodes = 59; - anode->btree.first_free = 16; - anode->btree.u.internal[0].down = a; - anode->btree.u.internal[0].file_secno = -1; + anode->btree.first_free = cpu_to_le16(16); + anode->btree.u.internal[0].down = cpu_to_le32(a); + anode->btree.u.internal[0].file_secno = cpu_to_le32(-1); mark_buffer_dirty(bh); brelse(bh); if ((anode = hpfs_map_anode(s, a, &bh))) { - anode->up = na; + anode->up = cpu_to_le32(na); mark_buffer_dirty(bh); brelse(bh); } } else na = a; } if ((anode = hpfs_map_anode(s, na, &bh))) { - anode->up = node; + anode->up = cpu_to_le32(node); if (fnod) anode->btree.fnode_parent = 1; mark_buffer_dirty(bh); brelse(bh); @@ -232,14 +232,14 @@ secno hpfs_add_sector_to_btree(struct super_block *s, secno node, int fnod, unsi } btree = &fnode->btree; } - ranode->up = node; - memcpy(&ranode->btree, btree, btree->first_free); + ranode->up = cpu_to_le32(node); + memcpy(&ranode->btree, btree, le16_to_cpu(btree->first_free)); if (fnod) ranode->btree.fnode_parent = 1; ranode->btree.n_free_nodes = (ranode->btree.internal ? 60 : 40) - ranode->btree.n_used_nodes; if (ranode->btree.internal) for (n = 0; n < ranode->btree.n_used_nodes; n++) { struct anode *unode; - if ((unode = hpfs_map_anode(s, ranode->u.internal[n].down, &bh1))) { - unode->up = ra; + if ((unode = hpfs_map_anode(s, le32_to_cpu(ranode->u.internal[n].down), &bh1))) { + unode->up = cpu_to_le32(ra); unode->btree.fnode_parent = 0; mark_buffer_dirty(bh1); brelse(bh1); @@ -248,11 +248,11 @@ secno hpfs_add_sector_to_btree(struct super_block *s, secno node, int fnod, unsi btree->internal = 1; btree->n_free_nodes = fnod ? 10 : 58; btree->n_used_nodes = 2; - btree->first_free = (char *)&btree->u.internal[2] - (char *)btree; - btree->u.internal[0].file_secno = fs; - btree->u.internal[0].down = ra; - btree->u.internal[1].file_secno = -1; - btree->u.internal[1].down = na; + btree->first_free = cpu_to_le16((char *)&btree->u.internal[2] - (char *)btree); + btree->u.internal[0].file_secno = cpu_to_le32(fs); + btree->u.internal[0].down = cpu_to_le32(ra); + btree->u.internal[1].file_secno = cpu_to_le32(-1); + btree->u.internal[1].down = cpu_to_le32(na); mark_buffer_dirty(bh); brelse(bh); mark_buffer_dirty(bh2); @@ -279,7 +279,7 @@ void hpfs_remove_btree(struct super_block *s, struct bplus_header *btree) go_down: d2 = 0; while (btree1->internal) { - ano = btree1->u.internal[pos].down; + ano = le32_to_cpu(btree1->u.internal[pos].down); if (level) brelse(bh); if (hpfs_sb(s)->sb_chk) if (hpfs_stop_cycles(s, ano, &d1, &d2, "hpfs_remove_btree #1")) @@ -290,7 +290,7 @@ void hpfs_remove_btree(struct super_block *s, struct bplus_header *btree) pos = 0; } for (i = 0; i < btree1->n_used_nodes; i++) - hpfs_free_sectors(s, btree1->u.external[i].disk_secno, btree1->u.external[i].length); + hpfs_free_sectors(s, le32_to_cpu(btree1->u.external[i].disk_secno), le32_to_cpu(btree1->u.external[i].length)); go_up: if (!level) return; brelse(bh); @@ -298,13 +298,13 @@ void hpfs_remove_btree(struct super_block *s, struct bplus_header *btree) if (hpfs_stop_cycles(s, ano, &c1, &c2, "hpfs_remove_btree #2")) return; hpfs_free_sectors(s, ano, 1); oano = ano; - ano = anode->up; + ano = le32_to_cpu(anode->up); if (--level) { if (!(anode = hpfs_map_anode(s, ano, &bh))) return; btree1 = &anode->btree; } else btree1 = btree; for (i = 0; i < btree1->n_used_nodes; i++) { - if (btree1->u.internal[i].down == oano) { + if (le32_to_cpu(btree1->u.internal[i].down) == oano) { if ((pos = i + 1) < btree1->n_used_nodes) goto go_down; else @@ -411,7 +411,7 @@ void hpfs_truncate_btree(struct super_block *s, secno f, int fno, unsigned secs) if (fno) { btree->n_free_nodes = 8; btree->n_used_nodes = 0; - btree->first_free = 8; + btree->first_free = cpu_to_le16(8); btree->internal = 0; mark_buffer_dirty(bh); } else hpfs_free_sectors(s, f, 1); @@ -421,22 +421,22 @@ void hpfs_truncate_btree(struct super_block *s, secno f, int fno, unsigned secs) while (btree->internal) { nodes = btree->n_used_nodes + btree->n_free_nodes; for (i = 0; i < btree->n_used_nodes; i++) - if (btree->u.internal[i].file_secno >= secs) goto f; + if (le32_to_cpu(btree->u.internal[i].file_secno) >= secs) goto f; brelse(bh); hpfs_error(s, "internal btree %08x doesn't end with -1", node); return; f: for (j = i + 1; j < btree->n_used_nodes; j++) - hpfs_ea_remove(s, btree->u.internal[j].down, 1, 0); + hpfs_ea_remove(s, le32_to_cpu(btree->u.internal[j].down), 1, 0); btree->n_used_nodes = i + 1; btree->n_free_nodes = nodes - btree->n_used_nodes; - btree->first_free = 8 + 8 * btree->n_used_nodes; + btree->first_free = cpu_to_le16(8 + 8 * btree->n_used_nodes); mark_buffer_dirty(bh); - if (btree->u.internal[i].file_secno == secs) { + if (btree->u.internal[i].file_secno == cpu_to_le32(secs)) { brelse(bh); return; } - node = btree->u.internal[i].down; + node = le32_to_cpu(btree->u.internal[i].down); brelse(bh); if (hpfs_sb(s)->sb_chk) if (hpfs_stop_cycles(s, node, &c1, &c2, "hpfs_truncate_btree")) @@ -446,25 +446,25 @@ void hpfs_truncate_btree(struct super_block *s, secno f, int fno, unsigned secs) } nodes = btree->n_used_nodes + btree->n_free_nodes; for (i = 0; i < btree->n_used_nodes; i++) - if (btree->u.external[i].file_secno + btree->u.external[i].length >= secs) goto ff; + if (le32_to_cpu(btree->u.external[i].file_secno) + le32_to_cpu(btree->u.external[i].length) >= secs) goto ff; brelse(bh); return; ff: - if (secs <= btree->u.external[i].file_secno) { + if (secs <= le32_to_cpu(btree->u.external[i].file_secno)) { hpfs_error(s, "there is an allocation error in file %08x, sector %08x", f, secs); if (i) i--; } - else if (btree->u.external[i].file_secno + btree->u.external[i].length > secs) { - hpfs_free_sectors(s, btree->u.external[i].disk_secno + secs - - btree->u.external[i].file_secno, btree->u.external[i].length - - secs + btree->u.external[i].file_secno); /* I hope gcc optimizes this :-) */ - btree->u.external[i].length = secs - btree->u.external[i].file_secno; + else if (le32_to_cpu(btree->u.external[i].file_secno) + le32_to_cpu(btree->u.external[i].length) > secs) { + hpfs_free_sectors(s, le32_to_cpu(btree->u.external[i].disk_secno) + secs - + le32_to_cpu(btree->u.external[i].file_secno), le32_to_cpu(btree->u.external[i].length) + - secs + le32_to_cpu(btree->u.external[i].file_secno)); /* I hope gcc optimizes this :-) */ + btree->u.external[i].length = cpu_to_le32(secs - le32_to_cpu(btree->u.external[i].file_secno)); } for (j = i + 1; j < btree->n_used_nodes; j++) - hpfs_free_sectors(s, btree->u.external[j].disk_secno, btree->u.external[j].length); + hpfs_free_sectors(s, le32_to_cpu(btree->u.external[j].disk_secno), le32_to_cpu(btree->u.external[j].length)); btree->n_used_nodes = i + 1; btree->n_free_nodes = nodes - btree->n_used_nodes; - btree->first_free = 8 + 12 * btree->n_used_nodes; + btree->first_free = cpu_to_le16(8 + 12 * btree->n_used_nodes); mark_buffer_dirty(bh); brelse(bh); } @@ -480,12 +480,12 @@ void hpfs_remove_fnode(struct super_block *s, fnode_secno fno) struct extended_attribute *ea_end; if (!(fnode = hpfs_map_fnode(s, fno, &bh))) return; if (!fnode->dirflag) hpfs_remove_btree(s, &fnode->btree); - else hpfs_remove_dtree(s, fnode->u.external[0].disk_secno); + else hpfs_remove_dtree(s, le32_to_cpu(fnode->u.external[0].disk_secno)); ea_end = fnode_end_ea(fnode); for (ea = fnode_ea(fnode); ea < ea_end; ea = next_ea(ea)) if (ea->indirect) hpfs_ea_remove(s, ea_sec(ea), ea->anode, ea_len(ea)); - hpfs_ea_ext_remove(s, fnode->ea_secno, fnode->ea_anode, fnode->ea_size_l); + hpfs_ea_ext_remove(s, le32_to_cpu(fnode->ea_secno), fnode->ea_anode, le32_to_cpu(fnode->ea_size_l)); brelse(bh); hpfs_free_sectors(s, fno, 1); } diff --git a/fs/hpfs/dir.c b/fs/hpfs/dir.c index 208f3d7..f46ae02 100644 --- a/fs/hpfs/dir.c +++ b/fs/hpfs/dir.c @@ -88,9 +88,9 @@ static int hpfs_readdir(struct file *filp, void *dirent, filldir_t filldir) hpfs_error(inode->i_sb, "not a directory, fnode %08lx", (unsigned long)inode->i_ino); } - if (hpfs_inode->i_dno != fno->u.external[0].disk_secno) { + if (hpfs_inode->i_dno != le32_to_cpu(fno->u.external[0].disk_secno)) { e = 1; - hpfs_error(inode->i_sb, "corrupted inode: i_dno == %08x, fnode -> dnode == %08x", hpfs_inode->i_dno, fno->u.external[0].disk_secno); + hpfs_error(inode->i_sb, "corrupted inode: i_dno == %08x, fnode -> dnode == %08x", hpfs_inode->i_dno, le32_to_cpu(fno->u.external[0].disk_secno)); } brelse(bh); if (e) { @@ -156,7 +156,7 @@ static int hpfs_readdir(struct file *filp, void *dirent, filldir_t filldir) goto again; } tempname = hpfs_translate_name(inode->i_sb, de->name, de->namelen, lc, de->not_8x3); - if (filldir(dirent, tempname, de->namelen, old_pos, de->fnode, DT_UNKNOWN) < 0) { + if (filldir(dirent, tempname, de->namelen, old_pos, le32_to_cpu(de->fnode), DT_UNKNOWN) < 0) { filp->f_pos = old_pos; if (tempname != de->name) kfree(tempname); hpfs_brelse4(&qbh); @@ -221,7 +221,7 @@ struct dentry *hpfs_lookup(struct inode *dir, struct dentry *dentry, struct name * Get inode number, what we're after. */ - ino = de->fnode; + ino = le32_to_cpu(de->fnode); /* * Go find or make an inode. @@ -236,7 +236,7 @@ struct dentry *hpfs_lookup(struct inode *dir, struct dentry *dentry, struct name hpfs_init_inode(result); if (de->directory) hpfs_read_inode(result); - else if (de->ea_size && hpfs_sb(dir->i_sb)->sb_eas) + else if (le32_to_cpu(de->ea_size) && hpfs_sb(dir->i_sb)->sb_eas) hpfs_read_inode(result); else { result->i_mode |= S_IFREG; @@ -261,19 +261,19 @@ struct dentry *hpfs_lookup(struct inode *dir, struct dentry *dentry, struct name */ if (!result->i_ctime.tv_sec) { - if (!(result->i_ctime.tv_sec = local_to_gmt(dir->i_sb, de->creation_date))) + if (!(result->i_ctime.tv_sec = local_to_gmt(dir->i_sb, le32_to_cpu(de->creation_date)))) result->i_ctime.tv_sec = 1; result->i_ctime.tv_nsec = 0; - result->i_mtime.tv_sec = local_to_gmt(dir->i_sb, de->write_date); + result->i_mtime.tv_sec = local_to_gmt(dir->i_sb, le32_to_cpu(de->write_date)); result->i_mtime.tv_nsec = 0; - result->i_atime.tv_sec = local_to_gmt(dir->i_sb, de->read_date); + result->i_atime.tv_sec = local_to_gmt(dir->i_sb, le32_to_cpu(de->read_date)); result->i_atime.tv_nsec = 0; - hpfs_result->i_ea_size = de->ea_size; + hpfs_result->i_ea_size = le32_to_cpu(de->ea_size); if (!hpfs_result->i_ea_mode && de->read_only) result->i_mode &= ~0222; if (!de->directory) { if (result->i_size == -1) { - result->i_size = de->file_size; + result->i_size = le32_to_cpu(de->file_size); result->i_data.a_ops = &hpfs_aops; hpfs_i(result)->mmu_private = result->i_size; /* diff --git a/fs/hpfs/dnode.c b/fs/hpfs/dnode.c index 07711c3..1e0e2ac 100644 --- a/fs/hpfs/dnode.c +++ b/fs/hpfs/dnode.c @@ -14,11 +14,11 @@ static loff_t get_pos(struct dnode *d, struct hpfs_dirent *fde) struct hpfs_dirent *de_end = dnode_end_de(d); int i = 1; for (de = dnode_first_de(d); de < de_end; de = de_next_de(de)) { - if (de == fde) return ((loff_t) d->self << 4) | (loff_t)i; + if (de == fde) return ((loff_t) le32_to_cpu(d->self) << 4) | (loff_t)i; i++; } printk("HPFS: get_pos: not_found\n"); - return ((loff_t)d->self << 4) | (loff_t)1; + return ((loff_t)le32_to_cpu(d->self) << 4) | (loff_t)1; } void hpfs_add_pos(struct inode *inode, loff_t *pos) @@ -130,30 +130,30 @@ static void set_last_pointer(struct super_block *s, struct dnode *d, dnode_secno { struct hpfs_dirent *de; if (!(de = dnode_last_de(d))) { - hpfs_error(s, "set_last_pointer: empty dnode %08x", d->self); + hpfs_error(s, "set_last_pointer: empty dnode %08x", le32_to_cpu(d->self)); return; } if (hpfs_sb(s)->sb_chk) { if (de->down) { hpfs_error(s, "set_last_pointer: dnode %08x has already last pointer %08x", - d->self, de_down_pointer(de)); + le32_to_cpu(d->self), de_down_pointer(de)); return; } - if (de->length != 32) { - hpfs_error(s, "set_last_pointer: bad last dirent in dnode %08x", d->self); + if (le16_to_cpu(de->length) != 32) { + hpfs_error(s, "set_last_pointer: bad last dirent in dnode %08x", le32_to_cpu(d->self)); return; } } if (ptr) { d->first_free = cpu_to_le32(le32_to_cpu(d->first_free) + 4); if (le32_to_cpu(d->first_free) > 2048) { - hpfs_error(s, "set_last_pointer: too long dnode %08x", d->self); + hpfs_error(s, "set_last_pointer: too long dnode %08x", le32_to_cpu(d->self)); d->first_free = cpu_to_le32(le32_to_cpu(d->first_free) - 4); return; } - de->length = 36; + de->length = cpu_to_le16(36); de->down = 1; - *(dnode_secno *)((char *)de + 32) = ptr; + *(dnode_secno *)((char *)de + 32) = cpu_to_le32(ptr); } } @@ -169,7 +169,7 @@ struct hpfs_dirent *hpfs_add_de(struct super_block *s, struct dnode *d, for (de = dnode_first_de(d); de < de_end; de = de_next_de(de)) { int c = hpfs_compare_names(s, name, namelen, de->name, de->namelen, de->last); if (!c) { - hpfs_error(s, "name (%c,%d) already exists in dnode %08x", *name, namelen, d->self); + hpfs_error(s, "name (%c,%d) already exists in dnode %08x", *name, namelen, le32_to_cpu(d->self)); return NULL; } if (c < 0) break; @@ -177,11 +177,10 @@ struct hpfs_dirent *hpfs_add_de(struct super_block *s, struct dnode *d, memmove((char *)de + d_size, de, (char *)de_end - (char *)de); memset(de, 0, d_size); if (down_ptr) { - *(int *)((char *)de + d_size - 4) = down_ptr; + *(dnode_secno *)((char *)de + d_size - 4) = cpu_to_le32(down_ptr); de->down = 1; } - de->length = d_size; - if (down_ptr) de->down = 1; + de->length = cpu_to_le16(d_size); de->not_8x3 = hpfs_is_name_long(name, namelen); de->namelen = namelen; memcpy(de->name, name, namelen); @@ -195,10 +194,10 @@ static void hpfs_delete_de(struct super_block *s, struct dnode *d, struct hpfs_dirent *de) { if (de->last) { - hpfs_error(s, "attempt to delete last dirent in dnode %08x", d->self); + hpfs_error(s, "attempt to delete last dirent in dnode %08x", le32_to_cpu(d->self)); return; } - d->first_free = cpu_to_le32(le32_to_cpu(d->first_free) - de->length); + d->first_free = cpu_to_le32(le32_to_cpu(d->first_free) - le16_to_cpu(de->length)); memmove(de, de_next_de(de), le32_to_cpu(d->first_free) + (char *)d - (char *)de); } @@ -206,14 +205,14 @@ static void fix_up_ptrs(struct super_block *s, struct dnode *d) { struct hpfs_dirent *de; struct hpfs_dirent *de_end = dnode_end_de(d); - dnode_secno dno = d->self; + dnode_secno dno = le32_to_cpu(d->self); for (de = dnode_first_de(d); de < de_end; de = de_next_de(de)) if (de->down) { struct quad_buffer_head qbh; struct dnode *dd; if ((dd = hpfs_map_dnode(s, de_down_pointer(de), &qbh))) { - if (dd->up != dno || dd->root_dnode) { - dd->up = dno; + if (le32_to_cpu(dd->up) != dno || dd->root_dnode) { + dd->up = cpu_to_le32(dno); dd->root_dnode = 0; hpfs_mark_4buffers_dirty(&qbh); } @@ -291,7 +290,7 @@ static int hpfs_add_to_dnode(struct inode *i, dnode_secno dno, copy_de(de = hpfs_add_de(i->i_sb, nd, name, namelen, down_ptr), new_de); for_all_poss(i, hpfs_pos_ins, get_pos(nd, de), 1); h = ((char *)dnode_last_de(nd) - (char *)nd) / 2 + 10; - if (!(ad = hpfs_alloc_dnode(i->i_sb, d->up, &adno, &qbh1))) { + if (!(ad = hpfs_alloc_dnode(i->i_sb, le32_to_cpu(d->up), &adno, &qbh1))) { hpfs_error(i->i_sb, "unable to alloc dnode - dnode tree will be corrupted"); hpfs_brelse4(&qbh); kfree(nd); @@ -315,19 +314,20 @@ static int hpfs_add_to_dnode(struct inode *i, dnode_secno dno, set_last_pointer(i->i_sb, ad, de->down ? de_down_pointer(de) : 0); de = de_next_de(de); memmove((char *)nd + 20, de, le32_to_cpu(nd->first_free) + (char *)nd - (char *)de); - nd->first_free = cpu_to_le32(le32_to_cpu(nd->first_free) - (char *)de - (char *)nd - 20); + nd->first_free = cpu_to_le32(le32_to_cpu(nd->first_free) - ((char *)de - (char *)nd - 20)); memcpy(d, nd, le32_to_cpu(nd->first_free)); for_all_poss(i, hpfs_pos_del, (loff_t)dno << 4, pos); fix_up_ptrs(i->i_sb, ad); if (!d->root_dnode) { - dno = ad->up = d->up; + ad->up = d->up; + dno = le32_to_cpu(ad->up); hpfs_mark_4buffers_dirty(&qbh); hpfs_brelse4(&qbh); hpfs_mark_4buffers_dirty(&qbh1); hpfs_brelse4(&qbh1); goto go_up; } - if (!(rd = hpfs_alloc_dnode(i->i_sb, d->up, &rdno, &qbh2))) { + if (!(rd = hpfs_alloc_dnode(i->i_sb, le32_to_cpu(d->up), &rdno, &qbh2))) { hpfs_error(i->i_sb, "unable to alloc dnode - dnode tree will be corrupted"); hpfs_brelse4(&qbh); hpfs_brelse4(&qbh1); @@ -339,7 +339,7 @@ static int hpfs_add_to_dnode(struct inode *i, dnode_secno dno, i->i_blocks += 4; rd->root_dnode = 1; rd->up = d->up; - if (!(fnode = hpfs_map_fnode(i->i_sb, d->up, &bh))) { + if (!(fnode = hpfs_map_fnode(i->i_sb, le32_to_cpu(d->up), &bh))) { hpfs_free_dnode(i->i_sb, rdno); hpfs_brelse4(&qbh); hpfs_brelse4(&qbh1); @@ -348,10 +348,11 @@ static int hpfs_add_to_dnode(struct inode *i, dnode_secno dno, kfree(nname); return 1; } - fnode->u.external[0].disk_secno = rdno; + fnode->u.external[0].disk_secno = cpu_to_le32(rdno); mark_buffer_dirty(bh); brelse(bh); - d->up = ad->up = hpfs_i(i)->i_dno = rdno; + hpfs_i(i)->i_dno = rdno; + d->up = ad->up = cpu_to_le32(rdno); d->root_dnode = ad->root_dnode = 0; hpfs_mark_4buffers_dirty(&qbh); hpfs_brelse4(&qbh); @@ -436,9 +437,9 @@ static secno move_to_top(struct inode *i, dnode_secno from, dnode_secno to) return 0; if (!(dnode = hpfs_map_dnode(i->i_sb, dno, &qbh))) return 0; if (hpfs_sb(i->i_sb)->sb_chk) { - if (dnode->up != chk_up) { + if (le32_to_cpu(dnode->up) != chk_up) { hpfs_error(i->i_sb, "move_to_top: up pointer from %08x should be %08x, is %08x", - dno, chk_up, dnode->up); + dno, chk_up, le32_to_cpu(dnode->up)); hpfs_brelse4(&qbh); return 0; } @@ -454,7 +455,7 @@ static secno move_to_top(struct inode *i, dnode_secno from, dnode_secno to) hpfs_brelse4(&qbh); } while (!(de = dnode_pre_last_de(dnode))) { - dnode_secno up = dnode->up; + dnode_secno up = le32_to_cpu(dnode->up); hpfs_brelse4(&qbh); hpfs_free_dnode(i->i_sb, dno); i->i_size -= 2048; @@ -474,7 +475,7 @@ static secno move_to_top(struct inode *i, dnode_secno from, dnode_secno to) return 0; } dnode->first_free = cpu_to_le32(le32_to_cpu(dnode->first_free) - 4); - de->length -= 4; + de->length = cpu_to_le16(le16_to_cpu(de->length) - 4); de->down = 0; hpfs_mark_4buffers_dirty(&qbh); dno = up; @@ -482,12 +483,12 @@ static secno move_to_top(struct inode *i, dnode_secno from, dnode_secno to) t = get_pos(dnode, de); for_all_poss(i, hpfs_pos_subst, t, 4); for_all_poss(i, hpfs_pos_subst, t + 1, 5); - if (!(nde = kmalloc(de->length, GFP_NOFS))) { + if (!(nde = kmalloc(le16_to_cpu(de->length), GFP_NOFS))) { hpfs_error(i->i_sb, "out of memory for dirent - directory will be corrupted"); hpfs_brelse4(&qbh); return 0; } - memcpy(nde, de, de->length); + memcpy(nde, de, le16_to_cpu(de->length)); ddno = de->down ? de_down_pointer(de) : 0; hpfs_delete_de(i->i_sb, dnode, de); set_last_pointer(i->i_sb, dnode, ddno); @@ -520,7 +521,7 @@ static void delete_empty_dnode(struct inode *i, dnode_secno dno) if (le32_to_cpu(dnode->first_free) == 52 || le32_to_cpu(dnode->first_free) == 56) { struct hpfs_dirent *de_end; int root = dnode->root_dnode; - up = dnode->up; + up = le32_to_cpu(dnode->up); de = dnode_first_de(dnode); down = de->down ? de_down_pointer(de) : 0; if (hpfs_sb(i->i_sb)->sb_chk) if (root && !down) { @@ -544,13 +545,13 @@ static void delete_empty_dnode(struct inode *i, dnode_secno dno) return; } if ((d1 = hpfs_map_dnode(i->i_sb, down, &qbh1))) { - d1->up = up; + d1->up = cpu_to_le32(up); d1->root_dnode = 1; hpfs_mark_4buffers_dirty(&qbh1); hpfs_brelse4(&qbh1); } if ((fnode = hpfs_map_fnode(i->i_sb, up, &bh))) { - fnode->u.external[0].disk_secno = down; + fnode->u.external[0].disk_secno = cpu_to_le32(down); mark_buffer_dirty(bh); brelse(bh); } @@ -569,16 +570,16 @@ static void delete_empty_dnode(struct inode *i, dnode_secno dno) for_all_poss(i, hpfs_pos_subst, ((loff_t)dno << 4) | 1, ((loff_t)up << 4) | p); if (!down) { de->down = 0; - de->length -= 4; + de->length = cpu_to_le16(le16_to_cpu(de->length) - 4); dnode->first_free = cpu_to_le32(le32_to_cpu(dnode->first_free) - 4); memmove(de_next_de(de), (char *)de_next_de(de) + 4, (char *)dnode + le32_to_cpu(dnode->first_free) - (char *)de_next_de(de)); } else { struct dnode *d1; struct quad_buffer_head qbh1; - *(dnode_secno *) ((void *) de + de->length - 4) = down; + *(dnode_secno *) ((void *) de + le16_to_cpu(de->length) - 4) = down; if ((d1 = hpfs_map_dnode(i->i_sb, down, &qbh1))) { - d1->up = up; + d1->up = cpu_to_le32(up); hpfs_mark_4buffers_dirty(&qbh1); hpfs_brelse4(&qbh1); } @@ -595,18 +596,18 @@ static void delete_empty_dnode(struct inode *i, dnode_secno dno) struct quad_buffer_head qbh1; if (!de_next->down) goto endm; ndown = de_down_pointer(de_next); - if (!(de_cp = kmalloc(de->length, GFP_NOFS))) { + if (!(de_cp = kmalloc(le16_to_cpu(de->length), GFP_NOFS))) { printk("HPFS: out of memory for dtree balancing\n"); goto endm; } - memcpy(de_cp, de, de->length); + memcpy(de_cp, de, le16_to_cpu(de->length)); hpfs_delete_de(i->i_sb, dnode, de); hpfs_mark_4buffers_dirty(&qbh); hpfs_brelse4(&qbh); for_all_poss(i, hpfs_pos_subst, ((loff_t)up << 4) | p, 4); for_all_poss(i, hpfs_pos_del, ((loff_t)up << 4) | p, 1); if (de_cp->down) if ((d1 = hpfs_map_dnode(i->i_sb, de_down_pointer(de_cp), &qbh1))) { - d1->up = ndown; + d1->up = cpu_to_le32(ndown); hpfs_mark_4buffers_dirty(&qbh1); hpfs_brelse4(&qbh1); } @@ -646,38 +647,38 @@ static void delete_empty_dnode(struct inode *i, dnode_secno dno) printk("HPFS: warning: unbalanced dnode tree, see hpfs.txt 4 more info\n"); printk("HPFS: warning: goin'on\n"); } - del->length += 4; + del->length = cpu_to_le16(le16_to_cpu(del->length) + 4); del->down = 1; d1->first_free = cpu_to_le32(le32_to_cpu(d1->first_free) + 4); } if (dlp && !down) { - del->length -= 4; + del->length = cpu_to_le16(le16_to_cpu(del->length) - 4); del->down = 0; d1->first_free = cpu_to_le32(le32_to_cpu(d1->first_free) - 4); } else if (down) - *(dnode_secno *) ((void *) del + del->length - 4) = down; + *(dnode_secno *) ((void *) del + le16_to_cpu(del->length) - 4) = cpu_to_le32(down); } else goto endm; - if (!(de_cp = kmalloc(de_prev->length, GFP_NOFS))) { + if (!(de_cp = kmalloc(le16_to_cpu(de_prev->length), GFP_NOFS))) { printk("HPFS: out of memory for dtree balancing\n"); hpfs_brelse4(&qbh1); goto endm; } hpfs_mark_4buffers_dirty(&qbh1); hpfs_brelse4(&qbh1); - memcpy(de_cp, de_prev, de_prev->length); + memcpy(de_cp, de_prev, le16_to_cpu(de_prev->length)); hpfs_delete_de(i->i_sb, dnode, de_prev); if (!de_prev->down) { - de_prev->length += 4; + de_prev->length = cpu_to_le16(le16_to_cpu(de_prev->length) + 4); de_prev->down = 1; dnode->first_free = cpu_to_le32(le32_to_cpu(dnode->first_free) + 4); } - *(dnode_secno *) ((void *) de_prev + de_prev->length - 4) = ndown; + *(dnode_secno *) ((void *) de_prev + le16_to_cpu(de_prev->length) - 4) = cpu_to_le32(ndown); hpfs_mark_4buffers_dirty(&qbh); hpfs_brelse4(&qbh); for_all_poss(i, hpfs_pos_subst, ((loff_t)up << 4) | (p - 1), 4); for_all_poss(i, hpfs_pos_subst, ((loff_t)up << 4) | p, ((loff_t)up << 4) | (p - 1)); if (down) if ((d1 = hpfs_map_dnode(i->i_sb, de_down_pointer(de), &qbh1))) { - d1->up = ndown; + d1->up = cpu_to_le32(ndown); hpfs_mark_4buffers_dirty(&qbh1); hpfs_brelse4(&qbh1); } @@ -744,8 +745,8 @@ void hpfs_count_dnodes(struct super_block *s, dnode_secno dno, int *n_dnodes, ptr = 0; go_up: if (!(dnode = hpfs_map_dnode(s, dno, &qbh))) return; - if (hpfs_sb(s)->sb_chk) if (odno && odno != -1 && dnode->up != odno) - hpfs_error(s, "hpfs_count_dnodes: bad up pointer; dnode %08x, down %08x points to %08x", odno, dno, dnode->up); + if (hpfs_sb(s)->sb_chk) if (odno && odno != -1 && le32_to_cpu(dnode->up) != odno) + hpfs_error(s, "hpfs_count_dnodes: bad up pointer; dnode %08x, down %08x points to %08x", odno, dno, le32_to_cpu(dnode->up)); de = dnode_first_de(dnode); if (ptr) while(1) { if (de->down) if (de_down_pointer(de) == ptr) goto process_de; @@ -769,7 +770,7 @@ void hpfs_count_dnodes(struct super_block *s, dnode_secno dno, int *n_dnodes, if (!de->first && !de->last && n_items) (*n_items)++; if ((de = de_next_de(de)) < dnode_end_de(dnode)) goto next_de; ptr = dno; - dno = dnode->up; + dno = le32_to_cpu(dnode->up); if (dnode->root_dnode) { hpfs_brelse4(&qbh); return; @@ -817,8 +818,8 @@ dnode_secno hpfs_de_as_down_as_possible(struct super_block *s, dnode_secno dno) return d; if (!(de = map_nth_dirent(s, d, 1, &qbh, NULL))) return dno; if (hpfs_sb(s)->sb_chk) - if (up && ((struct dnode *)qbh.data)->up != up) - hpfs_error(s, "hpfs_de_as_down_as_possible: bad up pointer; dnode %08x, down %08x points to %08x", up, d, ((struct dnode *)qbh.data)->up); + if (up && le32_to_cpu(((struct dnode *)qbh.data)->up) != up) + hpfs_error(s, "hpfs_de_as_down_as_possible: bad up pointer; dnode %08x, down %08x points to %08x", up, d, le32_to_cpu(((struct dnode *)qbh.data)->up)); if (!de->down) { hpfs_brelse4(&qbh); return d; @@ -867,7 +868,7 @@ struct hpfs_dirent *map_pos_dirent(struct inode *inode, loff_t *posp, /* Going up */ if (dnode->root_dnode) goto bail; - if (!(up_dnode = hpfs_map_dnode(inode->i_sb, dnode->up, &qbh0))) + if (!(up_dnode = hpfs_map_dnode(inode->i_sb, le32_to_cpu(dnode->up), &qbh0))) goto bail; end_up_de = dnode_end_de(up_dnode); @@ -875,16 +876,16 @@ struct hpfs_dirent *map_pos_dirent(struct inode *inode, loff_t *posp, for (up_de = dnode_first_de(up_dnode); up_de < end_up_de; up_de = de_next_de(up_de)) { if (!(++c & 077)) hpfs_error(inode->i_sb, - "map_pos_dirent: pos crossed dnode boundary; dnode = %08x", dnode->up); + "map_pos_dirent: pos crossed dnode boundary; dnode = %08x", le32_to_cpu(dnode->up)); if (up_de->down && de_down_pointer(up_de) == dno) { - *posp = ((loff_t) dnode->up << 4) + c; + *posp = ((loff_t) le32_to_cpu(dnode->up) << 4) + c; hpfs_brelse4(&qbh0); return de; } } hpfs_error(inode->i_sb, "map_pos_dirent: pointer to dnode %08x not found in parent dnode %08x", - dno, dnode->up); + dno, le32_to_cpu(dnode->up)); hpfs_brelse4(&qbh0); bail: @@ -1010,17 +1011,17 @@ struct hpfs_dirent *map_fnode_dirent(struct super_block *s, fnode_secno fno, /*name2[15] = 0xff;*/ name1len = 15; name2len = 256; } - if (!(upf = hpfs_map_fnode(s, f->up, &bh))) { + if (!(upf = hpfs_map_fnode(s, le32_to_cpu(f->up), &bh))) { kfree(name2); return NULL; } if (!upf->dirflag) { brelse(bh); - hpfs_error(s, "fnode %08x has non-directory parent %08x", fno, f->up); + hpfs_error(s, "fnode %08x has non-directory parent %08x", fno, le32_to_cpu(f->up)); kfree(name2); return NULL; } - dno = upf->u.external[0].disk_secno; + dno = le32_to_cpu(upf->u.external[0].disk_secno); brelse(bh); go_down: downd = 0; @@ -1042,7 +1043,7 @@ struct hpfs_dirent *map_fnode_dirent(struct super_block *s, fnode_secno fno, return NULL; } next_de: - if (de->fnode == fno) { + if (le32_to_cpu(de->fnode) == fno) { kfree(name2); return de; } @@ -1058,7 +1059,7 @@ struct hpfs_dirent *map_fnode_dirent(struct super_block *s, fnode_secno fno, goto go_down; } f: - if (de->fnode == fno) { + if (le32_to_cpu(de->fnode) == fno) { kfree(name2); return de; } @@ -1067,7 +1068,7 @@ struct hpfs_dirent *map_fnode_dirent(struct super_block *s, fnode_secno fno, if ((de = de_next_de(de)) < de_end) goto next_de; if (d->root_dnode) goto not_found; downd = dno; - dno = d->up; + dno = le32_to_cpu(d->up); hpfs_brelse4(qbh); if (hpfs_sb(s)->sb_chk) if (hpfs_stop_cycles(s, downd, &d1, &d2, "map_fnode_dirent #2")) { diff --git a/fs/hpfs/ea.c b/fs/hpfs/ea.c index 1ac05bb..1bbc37d 100644 --- a/fs/hpfs/ea.c +++ b/fs/hpfs/ea.c @@ -24,7 +24,7 @@ void hpfs_ea_ext_remove(struct super_block *s, secno a, int ano, unsigned len) } if (hpfs_ea_read(s, a, ano, pos, 4, ex)) return; if (ea->indirect) { - if (ea->valuelen != 8) { + if (le16_to_cpu(ea->valuelen) != 8) { hpfs_error(s, "ea->indirect set while ea->valuelen!=8, %s %08x, pos %08x", ano ? "anode" : "sectors", a, pos); return; @@ -33,7 +33,7 @@ void hpfs_ea_ext_remove(struct super_block *s, secno a, int ano, unsigned len) return; hpfs_ea_remove(s, ea_sec(ea), ea->anode, ea_len(ea)); } - pos += ea->namelen + ea->valuelen + 5; + pos += ea->namelen + le16_to_cpu(ea->valuelen) + 5; } if (!ano) hpfs_free_sectors(s, a, (len+511) >> 9); else { @@ -82,14 +82,14 @@ int hpfs_read_ea(struct super_block *s, struct fnode *fnode, char *key, if (!strcmp(ea->name, key)) { if (ea->indirect) goto indirect; - if (ea->valuelen >= size) + if (le16_to_cpu(ea->valuelen) >= size) return -EINVAL; - memcpy(buf, ea_data(ea), ea->valuelen); - buf[ea->valuelen] = 0; + memcpy(buf, ea_data(ea), le16_to_cpu(ea->valuelen)); + buf[le16_to_cpu(ea->valuelen)] = 0; return 0; } - a = fnode->ea_secno; - len = fnode->ea_size_l; + a = le32_to_cpu(fnode->ea_secno); + len = le32_to_cpu(fnode->ea_size_l); ano = fnode->ea_anode; pos = 0; while (pos < len) { @@ -106,14 +106,14 @@ int hpfs_read_ea(struct super_block *s, struct fnode *fnode, char *key, if (!strcmp(ea->name, key)) { if (ea->indirect) goto indirect; - if (ea->valuelen >= size) + if (le16_to_cpu(ea->valuelen) >= size) return -EINVAL; - if (hpfs_ea_read(s, a, ano, pos + 4 + ea->namelen + 1, ea->valuelen, buf)) + if (hpfs_ea_read(s, a, ano, pos + 4 + ea->namelen + 1, le16_to_cpu(ea->valuelen), buf)) return -EIO; - buf[ea->valuelen] = 0; + buf[le16_to_cpu(ea->valuelen)] = 0; return 0; } - pos += ea->namelen + ea->valuelen + 5; + pos += ea->namelen + le16_to_cpu(ea->valuelen) + 5; } return -ENOENT; indirect: @@ -138,16 +138,16 @@ char *hpfs_get_ea(struct super_block *s, struct fnode *fnode, char *key, int *si if (!strcmp(ea->name, key)) { if (ea->indirect) return get_indirect_ea(s, ea->anode, ea_sec(ea), *size = ea_len(ea)); - if (!(ret = kmalloc((*size = ea->valuelen) + 1, GFP_NOFS))) { + if (!(ret = kmalloc((*size = le16_to_cpu(ea->valuelen)) + 1, GFP_NOFS))) { printk("HPFS: out of memory for EA\n"); return NULL; } - memcpy(ret, ea_data(ea), ea->valuelen); - ret[ea->valuelen] = 0; + memcpy(ret, ea_data(ea), le16_to_cpu(ea->valuelen)); + ret[le16_to_cpu(ea->valuelen)] = 0; return ret; } - a = fnode->ea_secno; - len = fnode->ea_size_l; + a = le32_to_cpu(fnode->ea_secno); + len = le32_to_cpu(fnode->ea_size_l); ano = fnode->ea_anode; pos = 0; while (pos < len) { @@ -164,18 +164,18 @@ char *hpfs_get_ea(struct super_block *s, struct fnode *fnode, char *key, int *si if (!strcmp(ea->name, key)) { if (ea->indirect) return get_indirect_ea(s, ea->anode, ea_sec(ea), *size = ea_len(ea)); - if (!(ret = kmalloc((*size = ea->valuelen) + 1, GFP_NOFS))) { + if (!(ret = kmalloc((*size = le16_to_cpu(ea->valuelen)) + 1, GFP_NOFS))) { printk("HPFS: out of memory for EA\n"); return NULL; } - if (hpfs_ea_read(s, a, ano, pos + 4 + ea->namelen + 1, ea->valuelen, ret)) { + if (hpfs_ea_read(s, a, ano, pos + 4 + ea->namelen + 1, le16_to_cpu(ea->valuelen), ret)) { kfree(ret); return NULL; } - ret[ea->valuelen] = 0; + ret[le16_to_cpu(ea->valuelen)] = 0; return ret; } - pos += ea->namelen + ea->valuelen + 5; + pos += ea->namelen + le16_to_cpu(ea->valuelen) + 5; } return NULL; } @@ -202,13 +202,13 @@ void hpfs_set_ea(struct inode *inode, struct fnode *fnode, const char *key, if (ea->indirect) { if (ea_len(ea) == size) set_indirect_ea(s, ea->anode, ea_sec(ea), data, size); - } else if (ea->valuelen == size) { + } else if (le16_to_cpu(ea->valuelen) == size) { memcpy(ea_data(ea), data, size); } return; } - a = fnode->ea_secno; - len = fnode->ea_size_l; + a = le32_to_cpu(fnode->ea_secno); + len = le32_to_cpu(fnode->ea_size_l); ano = fnode->ea_anode; pos = 0; while (pos < len) { @@ -228,41 +228,41 @@ void hpfs_set_ea(struct inode *inode, struct fnode *fnode, const char *key, set_indirect_ea(s, ea->anode, ea_sec(ea), data, size); } else { - if (ea->valuelen == size) + if (le16_to_cpu(ea->valuelen) == size) hpfs_ea_write(s, a, ano, pos + 4 + ea->namelen + 1, size, data); } return; } - pos += ea->namelen + ea->valuelen + 5; + pos += ea->namelen + le16_to_cpu(ea->valuelen) + 5; } - if (!fnode->ea_offs) { - /*if (fnode->ea_size_s) { + if (!le16_to_cpu(fnode->ea_offs)) { + /*if (le16_to_cpu(fnode->ea_size_s)) { hpfs_error(s, "fnode %08x: ea_size_s == %03x, ea_offs == 0", - inode->i_ino, fnode->ea_size_s); + inode->i_ino, le16_to_cpu(fnode->ea_size_s)); return; }*/ - fnode->ea_offs = 0xc4; + fnode->ea_offs = cpu_to_le16(0xc4); } - if (fnode->ea_offs < 0xc4 || fnode->ea_offs + fnode->acl_size_s + fnode->ea_size_s > 0x200) { + if (le16_to_cpu(fnode->ea_offs) < 0xc4 || le16_to_cpu(fnode->ea_offs) + le16_to_cpu(fnode->acl_size_s) + le16_to_cpu(fnode->ea_size_s) > 0x200) { hpfs_error(s, "fnode %08lx: ea_offs == %03x, ea_size_s == %03x", (unsigned long)inode->i_ino, - fnode->ea_offs, fnode->ea_size_s); + le32_to_cpu(fnode->ea_offs), le16_to_cpu(fnode->ea_size_s)); return; } - if ((fnode->ea_size_s || !fnode->ea_size_l) && - fnode->ea_offs + fnode->acl_size_s + fnode->ea_size_s + strlen(key) + size + 5 <= 0x200) { + if ((le16_to_cpu(fnode->ea_size_s) || !le32_to_cpu(fnode->ea_size_l)) && + le16_to_cpu(fnode->ea_offs) + le16_to_cpu(fnode->acl_size_s) + le16_to_cpu(fnode->ea_size_s) + strlen(key) + size + 5 <= 0x200) { ea = fnode_end_ea(fnode); *(char *)ea = 0; ea->namelen = strlen(key); - ea->valuelen = size; + ea->valuelen = cpu_to_le16(size); strcpy(ea->name, key); memcpy(ea_data(ea), data, size); - fnode->ea_size_s += strlen(key) + size + 5; + fnode->ea_size_s = cpu_to_le16(le16_to_cpu(fnode->ea_size_s) + strlen(key) + size + 5); goto ret; } /* Most the code here is 99.9993422% unused. I hope there are no bugs. But what .. HPFS.IFS has also bugs in ea management. */ - if (fnode->ea_size_s && !fnode->ea_size_l) { + if (le16_to_cpu(fnode->ea_size_s) && !le32_to_cpu(fnode->ea_size_l)) { secno n; struct buffer_head *bh; char *data; @@ -271,25 +271,26 @@ void hpfs_set_ea(struct inode *inode, struct fnode *fnode, const char *key, hpfs_free_sectors(s, n, 1); return; } - memcpy(data, fnode_ea(fnode), fnode->ea_size_s); - fnode->ea_size_l = fnode->ea_size_s; - fnode->ea_size_s = 0; - fnode->ea_secno = n; - fnode->ea_anode = 0; + memcpy(data, fnode_ea(fnode), le16_to_cpu(fnode->ea_size_s)); + fnode->ea_size_l = cpu_to_le32(le16_to_cpu(fnode->ea_size_s)); + fnode->ea_size_s = cpu_to_le16(0); + fnode->ea_secno = cpu_to_le32(n); + fnode->ea_anode = cpu_to_le32(0); mark_buffer_dirty(bh); brelse(bh); } - pos = fnode->ea_size_l + 5 + strlen(key) + size; - len = (fnode->ea_size_l + 511) >> 9; + pos = le32_to_cpu(fnode->ea_size_l) + 5 + strlen(key) + size; + len = (le32_to_cpu(fnode->ea_size_l) + 511) >> 9; if (pos >= 30000) goto bail; while (((pos + 511) >> 9) > len) { if (!len) { - if (!(fnode->ea_secno = hpfs_alloc_sector(s, fno, 1, 0))) - goto bail; + secno q = hpfs_alloc_sector(s, fno, 1, 0); + if (!q) goto bail; + fnode->ea_secno = cpu_to_le32(q); fnode->ea_anode = 0; len++; } else if (!fnode->ea_anode) { - if (hpfs_alloc_if_possible(s, fnode->ea_secno + len)) { + if (hpfs_alloc_if_possible(s, le32_to_cpu(fnode->ea_secno) + len)) { len++; } else { /* Aargh... don't know how to create ea anodes :-( */ @@ -298,18 +299,18 @@ void hpfs_set_ea(struct inode *inode, struct fnode *fnode, const char *key, anode_secno a_s; if (!(anode = hpfs_alloc_anode(s, fno, &a_s, &bh))) goto bail; - anode->up = fno; + anode->up = cpu_to_le32(fno); anode->btree.fnode_parent = 1; anode->btree.n_free_nodes--; anode->btree.n_used_nodes++; - anode->btree.first_free += 12; - anode->u.external[0].disk_secno = fnode->ea_secno; - anode->u.external[0].file_secno = 0; - anode->u.external[0].length = len; + anode->btree.first_free = cpu_to_le16(le16_to_cpu(anode->btree.first_free) + 12); + anode->u.external[0].disk_secno = cpu_to_le32(le32_to_cpu(fnode->ea_secno)); + anode->u.external[0].file_secno = cpu_to_le32(0); + anode->u.external[0].length = cpu_to_le32(len); mark_buffer_dirty(bh); brelse(bh); fnode->ea_anode = 1; - fnode->ea_secno = a_s;*/ + fnode->ea_secno = cpu_to_le32(a_s);*/ secno new_sec; int i; if (!(new_sec = hpfs_alloc_sector(s, fno, 1, 1 - ((pos + 511) >> 9)))) @@ -317,7 +318,7 @@ void hpfs_set_ea(struct inode *inode, struct fnode *fnode, const char *key, for (i = 0; i < len; i++) { struct buffer_head *bh1, *bh2; void *b1, *b2; - if (!(b1 = hpfs_map_sector(s, fnode->ea_secno + i, &bh1, len - i - 1))) { + if (!(b1 = hpfs_map_sector(s, le32_to_cpu(fnode->ea_secno) + i, &bh1, len - i - 1))) { hpfs_free_sectors(s, new_sec, (pos + 511) >> 9); goto bail; } @@ -331,13 +332,13 @@ void hpfs_set_ea(struct inode *inode, struct fnode *fnode, const char *key, mark_buffer_dirty(bh2); brelse(bh2); } - hpfs_free_sectors(s, fnode->ea_secno, len); - fnode->ea_secno = new_sec; + hpfs_free_sectors(s, le32_to_cpu(fnode->ea_secno), len); + fnode->ea_secno = cpu_to_le32(new_sec); len = (pos + 511) >> 9; } } if (fnode->ea_anode) { - if (hpfs_add_sector_to_btree(s, fnode->ea_secno, + if (hpfs_add_sector_to_btree(s, le32_to_cpu(fnode->ea_secno), 0, len) != -1) { len++; } else { @@ -349,17 +350,17 @@ void hpfs_set_ea(struct inode *inode, struct fnode *fnode, const char *key, h[1] = strlen(key); h[2] = size & 0xff; h[3] = size >> 8; - if (hpfs_ea_write(s, fnode->ea_secno, fnode->ea_anode, fnode->ea_size_l, 4, h)) goto bail; - if (hpfs_ea_write(s, fnode->ea_secno, fnode->ea_anode, fnode->ea_size_l + 4, h[1] + 1, key)) goto bail; - if (hpfs_ea_write(s, fnode->ea_secno, fnode->ea_anode, fnode->ea_size_l + 5 + h[1], size, data)) goto bail; - fnode->ea_size_l = pos; + if (hpfs_ea_write(s, le32_to_cpu(fnode->ea_secno), fnode->ea_anode, le32_to_cpu(fnode->ea_size_l), 4, h)) goto bail; + if (hpfs_ea_write(s, le32_to_cpu(fnode->ea_secno), fnode->ea_anode, le32_to_cpu(fnode->ea_size_l) + 4, h[1] + 1, key)) goto bail; + if (hpfs_ea_write(s, le32_to_cpu(fnode->ea_secno), fnode->ea_anode, le32_to_cpu(fnode->ea_size_l) + 5 + h[1], size, data)) goto bail; + fnode->ea_size_l = cpu_to_le32(pos); ret: hpfs_i(inode)->i_ea_size += 5 + strlen(key) + size; return; bail: - if (fnode->ea_secno) - if (fnode->ea_anode) hpfs_truncate_btree(s, fnode->ea_secno, 1, (fnode->ea_size_l + 511) >> 9); - else hpfs_free_sectors(s, fnode->ea_secno + ((fnode->ea_size_l + 511) >> 9), len - ((fnode->ea_size_l + 511) >> 9)); - else fnode->ea_secno = fnode->ea_size_l = 0; + if (le32_to_cpu(fnode->ea_secno)) + if (fnode->ea_anode) hpfs_truncate_btree(s, le32_to_cpu(fnode->ea_secno), 1, (le32_to_cpu(fnode->ea_size_l) + 511) >> 9); + else hpfs_free_sectors(s, le32_to_cpu(fnode->ea_secno) + ((le32_to_cpu(fnode->ea_size_l) + 511) >> 9), len - ((le32_to_cpu(fnode->ea_size_l) + 511) >> 9)); + else fnode->ea_secno = fnode->ea_size_l = cpu_to_le32(0); } diff --git a/fs/hpfs/hpfs.h b/fs/hpfs/hpfs.h index 8cd5130..91a6223 100644 --- a/fs/hpfs/hpfs.h +++ b/fs/hpfs/hpfs.h @@ -19,6 +19,10 @@ For definitive information on HPFS, ask somebody else -- this is guesswork. There are certain to be many mistakes. */ +#if !defined(__LITTLE_ENDIAN) && !defined(__BIG_ENDIAN) +#error unknown endian +#endif + /* Notation */ typedef u32 secno; /* sector number, partition relative */ @@ -86,7 +90,6 @@ struct hpfs_super_block secno badblocks; /* bad block list */ u32 zero3; /* 0 */ time32_t last_chkdsk; /* date last checked, 0 if never */ - /*u32 zero4;*/ /* 0 */ time32_t last_optimize; /* date last optimized, 0 if never */ secno n_dir_band; /* number of sectors in dir band */ secno dir_band_start; /* first sector in dir band */ @@ -109,21 +112,44 @@ struct hpfs_spare_block u32 magic; /* f991 1849 */ u32 magic1; /* fa52 29c5, more magic? */ - unsigned dirty: 1; /* 0 clean, 1 "improperly stopped" */ - unsigned sparedir_used: 1; /* spare dirblks used */ - unsigned hotfixes_used: 1; /* hotfixes used */ - unsigned bad_sector: 1; /* bad sector, corrupted disk (???) */ - unsigned bad_bitmap: 1; /* bad bitmap */ - unsigned fast: 1; /* partition was fast formatted */ - unsigned old_wrote: 1; /* old version wrote to partion */ - unsigned old_wrote_1: 1; /* old version wrote to partion (?) */ - unsigned install_dasd_limits: 1; /* HPFS386 flags */ - unsigned resynch_dasd_limits: 1; - unsigned dasd_limits_operational: 1; - unsigned multimedia_active: 1; - unsigned dce_acls_active: 1; - unsigned dasd_limits_dirty: 1; - unsigned flag67: 2; +#ifdef __LITTLE_ENDIAN + u8 dirty: 1; /* 0 clean, 1 "improperly stopped" */ + u8 sparedir_used: 1; /* spare dirblks used */ + u8 hotfixes_used: 1; /* hotfixes used */ + u8 bad_sector: 1; /* bad sector, corrupted disk (???) */ + u8 bad_bitmap: 1; /* bad bitmap */ + u8 fast: 1; /* partition was fast formatted */ + u8 old_wrote: 1; /* old version wrote to partion */ + u8 old_wrote_1: 1; /* old version wrote to partion (?) */ +#else + u8 old_wrote_1: 1; /* old version wrote to partion (?) */ + u8 old_wrote: 1; /* old version wrote to partion */ + u8 fast: 1; /* partition was fast formatted */ + u8 bad_bitmap: 1; /* bad bitmap */ + u8 bad_sector: 1; /* bad sector, corrupted disk (???) */ + u8 hotfixes_used: 1; /* hotfixes used */ + u8 sparedir_used: 1; /* spare dirblks used */ + u8 dirty: 1; /* 0 clean, 1 "improperly stopped" */ +#endif + +#ifdef __LITTLE_ENDIAN + u8 install_dasd_limits: 1; /* HPFS386 flags */ + u8 resynch_dasd_limits: 1; + u8 dasd_limits_operational: 1; + u8 multimedia_active: 1; + u8 dce_acls_active: 1; + u8 dasd_limits_dirty: 1; + u8 flag67: 2; +#else + u8 flag67: 2; + u8 dasd_limits_dirty: 1; + u8 dce_acls_active: 1; + u8 multimedia_active: 1; + u8 dasd_limits_operational: 1; + u8 resynch_dasd_limits: 1; + u8 install_dasd_limits: 1; /* HPFS386 flags */ +#endif + u8 mm_contlgulty; u8 unused; @@ -255,10 +281,18 @@ struct dnode { u32 magic; /* 77e4 0aae */ u32 first_free; /* offset from start of dnode to first free dir entry */ - unsigned root_dnode:1; /* Is it root dnode? */ - unsigned increment_me:31; /* some kind of activity counter? - Neither HPFS.IFS nor CHKDSK cares +#ifdef __LITTLE_ENDIAN + u8 root_dnode: 1; /* Is it root dnode? */ + u8 increment_me: 7; /* some kind of activity counter? */ + /* Neither HPFS.IFS nor CHKDSK cares if you change this word */ +#else + u8 increment_me: 7; /* some kind of activity counter? */ + /* Neither HPFS.IFS nor CHKDSK cares + if you change this word */ + u8 root_dnode: 1; /* Is it root dnode? */ +#endif + u8 increment_me2[3]; secno up; /* (root dnode) directory's fnode (nonroot) parent dnode */ dnode_secno self; /* pointer to this dnode */ @@ -266,33 +300,59 @@ struct dnode { }; struct hpfs_dirent { - u16 length; /* offset to next dirent */ - unsigned first: 1; /* set on phony ^A^A (".") entry */ - unsigned has_acl: 1; - unsigned down: 1; /* down pointer present (after name) */ - unsigned last: 1; /* set on phony \377 entry */ - unsigned has_ea: 1; /* entry has EA */ - unsigned has_xtd_perm: 1; /* has extended perm list (???) */ - unsigned has_explicit_acl: 1; - unsigned has_needea: 1; /* ?? some EA has NEEDEA set + u16 length; /* offset to next dirent */ + +#ifdef __LITTLE_ENDIAN + u8 first: 1; /* set on phony ^A^A (".") entry */ + u8 has_acl: 1; + u8 down: 1; /* down pointer present (after name) */ + u8 last: 1; /* set on phony \377 entry */ + u8 has_ea: 1; /* entry has EA */ + u8 has_xtd_perm: 1; /* has extended perm list (???) */ + u8 has_explicit_acl: 1; + u8 has_needea: 1; /* ?? some EA has NEEDEA set + I have no idea why this is + interesting in a dir entry */ +#else + u8 has_needea: 1; /* ?? some EA has NEEDEA set I have no idea why this is interesting in a dir entry */ - unsigned read_only: 1; /* dos attrib */ - unsigned hidden: 1; /* dos attrib */ - unsigned system: 1; /* dos attrib */ - unsigned flag11: 1; /* would be volume label dos attrib */ - unsigned directory: 1; /* dos attrib */ - unsigned archive: 1; /* dos attrib */ - unsigned not_8x3: 1; /* name is not 8.3 */ - unsigned flag15: 1; + u8 has_explicit_acl: 1; + u8 has_xtd_perm: 1; /* has extended perm list (???) */ + u8 has_ea: 1; /* entry has EA */ + u8 last: 1; /* set on phony \377 entry */ + u8 down: 1; /* down pointer present (after name) */ + u8 has_acl: 1; + u8 first: 1; /* set on phony ^A^A (".") entry */ +#endif + +#ifdef __LITTLE_ENDIAN + u8 read_only: 1; /* dos attrib */ + u8 hidden: 1; /* dos attrib */ + u8 system: 1; /* dos attrib */ + u8 flag11: 1; /* would be volume label dos attrib */ + u8 directory: 1; /* dos attrib */ + u8 archive: 1; /* dos attrib */ + u8 not_8x3: 1; /* name is not 8.3 */ + u8 flag15: 1; +#else + u8 flag15: 1; + u8 not_8x3: 1; /* name is not 8.3 */ + u8 archive: 1; /* dos attrib */ + u8 directory: 1; /* dos attrib */ + u8 flag11: 1; /* would be volume label dos attrib */ + u8 system: 1; /* dos attrib */ + u8 hidden: 1; /* dos attrib */ + u8 read_only: 1; /* dos attrib */ +#endif + fnode_secno fnode; /* fnode giving allocation info */ time32_t write_date; /* mtime */ u32 file_size; /* file length, bytes */ time32_t read_date; /* atime */ time32_t creation_date; /* ctime */ u32 ea_size; /* total EA length, bytes */ - unsigned char no_of_acls : 3; /* number of ACL's */ - unsigned char reserver : 5; + u8 no_of_acls; /* number of ACL's (low 3 bits) */ u8 ix; /* code page index (of filename), see struct code_page_data */ u8 namelen, name[1]; /* file name */ @@ -328,21 +388,33 @@ struct bplus_internal_node struct bplus_header { - unsigned hbff: 1; /* high bit of first free entry offset */ - unsigned flag1: 1; - unsigned flag2: 1; - unsigned flag3: 1; - unsigned flag4: 1; - unsigned fnode_parent: 1; /* ? we're pointed to by an fnode, +#ifdef __LITTLE_ENDIAN + u8 hbff: 1; /* high bit of first free entry offset */ + u8 flag1234: 4; + u8 fnode_parent: 1; /* ? we're pointed to by an fnode, the data btree or some ea or the main ea bootage pointer ea_secno */ /* also can get set in fnodes, which may be a chkdsk glitch or may mean this bit is irrelevant in fnodes, or this interpretation is all wet */ - unsigned binary_search: 1; /* suggest binary search (unused) */ - unsigned internal: 1; /* 1 -> (internal) tree of anodes + u8 binary_search: 1; /* suggest binary search (unused) */ + u8 internal: 1; /* 1 -> (internal) tree of anodes 0 -> (leaf) list of extents */ +#else + u8 internal: 1; /* 1 -> (internal) tree of anodes + 0 -> (leaf) list of extents */ + u8 binary_search: 1; /* suggest binary search (unused) */ + u8 fnode_parent: 1; /* ? we're pointed to by an fnode, + the data btree or some ea or the + main ea bootage pointer ea_secno */ + /* also can get set in fnodes, which + may be a chkdsk glitch or may mean + this bit is irrelevant in fnodes, + or this interpretation is all wet */ + u8 flag1234: 4; + u8 hbff: 1; /* high bit of first free entry offset */ +#endif u8 fill[3]; u8 n_free_nodes; /* free nodes in following array */ u8 n_used_nodes; /* used nodes in following array */ @@ -379,23 +451,25 @@ struct fnode secno ea_secno; /* first sector of disk-resident ea's*/ u16 ea_size_s; /* length of fnode-resident ea's */ - unsigned flag0: 1; - unsigned ea_anode: 1; /* 1 -> ea_secno is an anode */ - unsigned flag2: 1; - unsigned flag3: 1; - unsigned flag4: 1; - unsigned flag5: 1; - unsigned flag6: 1; - unsigned flag7: 1; - unsigned dirflag: 1; /* 1 -> directory. first & only extent +#ifdef __LITTLE_ENDIAN + u8 flag0: 1; + u8 ea_anode: 1; /* 1 -> ea_secno is an anode */ + u8 flag234567: 6; +#else + u8 flag234567: 6; + u8 ea_anode: 1; /* 1 -> ea_secno is an anode */ + u8 flag0: 1; +#endif + +#ifdef __LITTLE_ENDIAN + u8 dirflag: 1; /* 1 -> directory. first & only extent + points to dnode. */ + u8 flag9012345: 7; +#else + u8 flag9012345: 7; + u8 dirflag: 1; /* 1 -> directory. first & only extent points to dnode. */ - unsigned flag9: 1; - unsigned flag10: 1; - unsigned flag11: 1; - unsigned flag12: 1; - unsigned flag13: 1; - unsigned flag14: 1; - unsigned flag15: 1; +#endif struct bplus_header btree; /* b+ tree, 8 extents or 12 subtrees */ union { @@ -456,16 +530,21 @@ struct anode struct extended_attribute { - unsigned indirect: 1; /* 1 -> value gives sector number +#ifdef __LITTLE_ENDIAN + u8 indirect: 1; /* 1 -> value gives sector number where real value starts */ - unsigned anode: 1; /* 1 -> sector is an anode + u8 anode: 1; /* 1 -> sector is an anode that points to fragmented value */ - unsigned flag2: 1; - unsigned flag3: 1; - unsigned flag4: 1; - unsigned flag5: 1; - unsigned flag6: 1; - unsigned needea: 1; /* required ea */ + u8 flag23456: 5; + u8 needea: 1; /* required ea */ +#else + u8 needea: 1; /* required ea */ + u8 flag23456: 5; + u8 anode: 1; /* 1 -> sector is an anode + that points to fragmented value */ + u8 indirect: 1; /* 1 -> value gives sector number + where real value starts */ +#endif u8 namelen; /* length of name, bytes */ u16 valuelen; /* length of value, bytes */ u8 name[0]; diff --git a/fs/hpfs/hpfs_fn.h b/fs/hpfs/hpfs_fn.h index d101086..f993773 100644 --- a/fs/hpfs/hpfs_fn.h +++ b/fs/hpfs/hpfs_fn.h @@ -84,7 +84,6 @@ struct hpfs_sb_info { unsigned *sb_bmp_dir; /* main bitmap directory */ unsigned sb_c_bitmap; /* current bitmap */ unsigned sb_max_fwd_alloc; /* max forwad allocation */ - /*unsigned sb_mounting : 1;*/ int sb_timeshift; }; @@ -100,7 +99,7 @@ struct quad_buffer_head { static inline dnode_secno de_down_pointer (struct hpfs_dirent *de) { CHKCOND(de->down,("HPFS: de_down_pointer: !de->down\n")); - return *(dnode_secno *) ((void *) de + de->length - 4); + return le32_to_cpu(*(dnode_secno *) ((void *) de + le16_to_cpu(de->length) - 4)); } /* The first dir entry in a dnode */ @@ -114,41 +113,41 @@ static inline struct hpfs_dirent *dnode_first_de (struct dnode *dnode) static inline struct hpfs_dirent *dnode_end_de (struct dnode *dnode) { - CHKCOND(dnode->first_free>=0x14 && dnode->first_free<=0xa00,("HPFS: dnode_end_de: dnode->first_free = %d\n",(int)dnode->first_free)); - return (void *) dnode + dnode->first_free; + CHKCOND(le32_to_cpu(dnode->first_free)>=0x14 && le32_to_cpu(dnode->first_free)<=0xa00,("HPFS: dnode_end_de: dnode->first_free = %x\n",(unsigned)le32_to_cpu(dnode->first_free))); + return (void *) dnode + le32_to_cpu(dnode->first_free); } /* The dir entry after dir entry de */ static inline struct hpfs_dirent *de_next_de (struct hpfs_dirent *de) { - CHKCOND(de->length>=0x20 && de->length<0x800,("HPFS: de_next_de: de->length = %d\n",(int)de->length)); - return (void *) de + de->length; + CHKCOND(le16_to_cpu(de->length)>=0x20 && le16_to_cpu(de->length)<0x800,("HPFS: de_next_de: de->length = %x\n",(unsigned)le16_to_cpu(de->length))); + return (void *) de + le16_to_cpu(de->length); } static inline struct extended_attribute *fnode_ea(struct fnode *fnode) { - return (struct extended_attribute *)((char *)fnode + fnode->ea_offs + fnode->acl_size_s); + return (struct extended_attribute *)((char *)fnode + le16_to_cpu(fnode->ea_offs) + le16_to_cpu(fnode->acl_size_s)); } static inline struct extended_attribute *fnode_end_ea(struct fnode *fnode) { - return (struct extended_attribute *)((char *)fnode + fnode->ea_offs + fnode->acl_size_s + fnode->ea_size_s); + return (struct extended_attribute *)((char *)fnode + le16_to_cpu(fnode->ea_offs) + le16_to_cpu(fnode->acl_size_s) + le16_to_cpu(fnode->ea_size_s)); } static inline struct extended_attribute *next_ea(struct extended_attribute *ea) { - return (struct extended_attribute *)((char *)ea + 5 + ea->namelen + ea->valuelen); + return (struct extended_attribute *)((char *)ea + 5 + ea->namelen + le16_to_cpu(ea->valuelen)); } static inline secno ea_sec(struct extended_attribute *ea) { - return *(secno *)((char *)ea + 9 + ea->namelen); + return le32_to_cpu(*((secno *)((char *)ea + 9 + ea->namelen))); } static inline secno ea_len(struct extended_attribute *ea) { - return *(secno *)((char *)ea + 5 + ea->namelen); + return le32_to_cpu(*((secno *)((char *)ea + 5 + ea->namelen))); } static inline char *ea_data(struct extended_attribute *ea) @@ -173,13 +172,13 @@ static inline void copy_de(struct hpfs_dirent *dst, struct hpfs_dirent *src) dst->not_8x3 = n; } -static inline unsigned tstbits(unsigned *bmp, unsigned b, unsigned n) +static inline unsigned tstbits(u32 *bmp, unsigned b, unsigned n) { int i; if ((b >= 0x4000) || (b + n - 1 >= 0x4000)) return n; - if (!((bmp[(b & 0x3fff) >> 5] >> (b & 0x1f)) & 1)) return 1; + if (!((le32_to_cpu(bmp[(b & 0x3fff) >> 5]) >> (b & 0x1f)) & 1)) return 1; for (i = 1; i < n; i++) - if (/*b+i < 0x4000 &&*/ !((bmp[((b+i) & 0x3fff) >> 5] >> ((b+i) & 0x1f)) & 1)) + if (!((le32_to_cpu(bmp[((b+i) & 0x3fff) >> 5]) >> ((b+i) & 0x1f)) & 1)) return i + 1; return 0; } diff --git a/fs/hpfs/inode.c b/fs/hpfs/inode.c index bc61bb4..338cd83 100644 --- a/fs/hpfs/inode.c +++ b/fs/hpfs/inode.c @@ -115,8 +115,8 @@ void hpfs_read_inode(struct inode *i) i->i_mode |= S_IFDIR; i->i_op = &hpfs_dir_iops; i->i_fop = &hpfs_dir_ops; - hpfs_inode->i_parent_dir = fnode->up; - hpfs_inode->i_dno = fnode->u.external[0].disk_secno; + hpfs_inode->i_parent_dir = le32_to_cpu(fnode->up); + hpfs_inode->i_dno = le32_to_cpu(fnode->u.external[0].disk_secno); if (hpfs_sb(sb)->sb_chk >= 2) { struct buffer_head *bh0; if (hpfs_map_fnode(sb, hpfs_inode->i_parent_dir, &bh0)) brelse(bh0); @@ -132,7 +132,7 @@ void hpfs_read_inode(struct inode *i) i->i_op = &hpfs_file_iops; i->i_fop = &hpfs_file_ops; i->i_nlink = 1; - i->i_size = fnode->file_size; + i->i_size = le32_to_cpu(fnode->file_size); i->i_blocks = ((i->i_size + 511) >> 9) + 1; i->i_data.a_ops = &hpfs_aops; hpfs_i(i)->mmu_private = i->i_size; @@ -143,7 +143,7 @@ void hpfs_read_inode(struct inode *i) static void hpfs_write_inode_ea(struct inode *i, struct fnode *fnode) { struct hpfs_inode_info *hpfs_inode = hpfs_i(i); - /*if (fnode->acl_size_l || fnode->acl_size_s) { + /*if (le32_to_cpu(fnode->acl_size_l) || le16_to_cpu(fnode->acl_size_s)) { Some unknown structures like ACL may be in fnode, we'd better not overwrite them hpfs_error(i->i_sb, "fnode %08x has some unknown HPFS386 stuctures", i->i_ino); @@ -218,30 +218,30 @@ void hpfs_write_inode_nolock(struct inode *i) } } else de = NULL; if (S_ISREG(i->i_mode)) { - fnode->file_size = i->i_size; - if (de) de->file_size = i->i_size; + fnode->file_size = cpu_to_le32(i->i_size); + if (de) de->file_size = cpu_to_le32(i->i_size); } else if (S_ISDIR(i->i_mode)) { - fnode->file_size = 0; - if (de) de->file_size = 0; + fnode->file_size = cpu_to_le32(0); + if (de) de->file_size = cpu_to_le32(0); } hpfs_write_inode_ea(i, fnode); if (de) { - de->write_date = gmt_to_local(i->i_sb, i->i_mtime.tv_sec); - de->read_date = gmt_to_local(i->i_sb, i->i_atime.tv_sec); - de->creation_date = gmt_to_local(i->i_sb, i->i_ctime.tv_sec); + de->write_date = cpu_to_le32(gmt_to_local(i->i_sb, i->i_mtime.tv_sec)); + de->read_date = cpu_to_le32(gmt_to_local(i->i_sb, i->i_atime.tv_sec)); + de->creation_date = cpu_to_le32(gmt_to_local(i->i_sb, i->i_ctime.tv_sec)); de->read_only = !(i->i_mode & 0222); - de->ea_size = hpfs_inode->i_ea_size; + de->ea_size = cpu_to_le32(hpfs_inode->i_ea_size); hpfs_mark_4buffers_dirty(&qbh); hpfs_brelse4(&qbh); } if (S_ISDIR(i->i_mode)) { if ((de = map_dirent(i, hpfs_inode->i_dno, "\001\001", 2, NULL, &qbh))) { - de->write_date = gmt_to_local(i->i_sb, i->i_mtime.tv_sec); - de->read_date = gmt_to_local(i->i_sb, i->i_atime.tv_sec); - de->creation_date = gmt_to_local(i->i_sb, i->i_ctime.tv_sec); + de->write_date = cpu_to_le32(gmt_to_local(i->i_sb, i->i_mtime.tv_sec)); + de->read_date = cpu_to_le32(gmt_to_local(i->i_sb, i->i_atime.tv_sec)); + de->creation_date = cpu_to_le32(gmt_to_local(i->i_sb, i->i_ctime.tv_sec)); de->read_only = !(i->i_mode & 0222); - de->ea_size = /*hpfs_inode->i_ea_size*/0; - de->file_size = 0; + de->ea_size = cpu_to_le32(/*hpfs_inode->i_ea_size*/0); + de->file_size = cpu_to_le32(0); hpfs_mark_4buffers_dirty(&qbh); hpfs_brelse4(&qbh); } else diff --git a/fs/hpfs/map.c b/fs/hpfs/map.c index 840d033..a790821 100644 --- a/fs/hpfs/map.c +++ b/fs/hpfs/map.c @@ -21,7 +21,7 @@ unsigned int *hpfs_map_bitmap(struct super_block *s, unsigned bmp_block, hpfs_error(s, "hpfs_map_bitmap called with bad parameter: %08x at %s", bmp_block, id); return NULL; } - sec = hpfs_sb(s)->sb_bmp_dir[bmp_block]; + sec = le32_to_cpu(hpfs_sb(s)->sb_bmp_dir[bmp_block]); if (!sec || sec > hpfs_sb(s)->sb_fs_size-4) { hpfs_error(s, "invalid bitmap block pointer %08x -> %08x at %s", bmp_block, sec, id); return NULL; @@ -46,18 +46,18 @@ unsigned char *hpfs_load_code_page(struct super_block *s, secno cps) struct code_page_data *cpd; struct code_page_directory *cp = hpfs_map_sector(s, cps, &bh, 0); if (!cp) return NULL; - if (cp->magic != CP_DIR_MAGIC) { - printk("HPFS: Code page directory magic doesn't match (magic = %08x)\n", cp->magic); + if (le32_to_cpu(cp->magic) != CP_DIR_MAGIC) { + printk("HPFS: Code page directory magic doesn't match (magic = %08x)\n", le32_to_cpu(cp->magic)); brelse(bh); return NULL; } - if (!cp->n_code_pages) { + if (!le32_to_cpu(cp->n_code_pages)) { printk("HPFS: n_code_pages == 0\n"); brelse(bh); return NULL; } - cpds = cp->array[0].code_page_data; - cpi = cp->array[0].index; + cpds = le32_to_cpu(cp->array[0].code_page_data); + cpi = le16_to_cpu(cp->array[0].index); brelse(bh); if (cpi >= 3) { @@ -66,12 +66,12 @@ unsigned char *hpfs_load_code_page(struct super_block *s, secno cps) } if (!(cpd = hpfs_map_sector(s, cpds, &bh, 0))) return NULL; - if ((unsigned)cpd->offs[cpi] > 0x178) { + if (le16_to_cpu(cpd->offs[cpi]) > 0x178) { printk("HPFS: Code page index out of sector\n"); brelse(bh); return NULL; } - ptr = (unsigned char *)cpd + cpd->offs[cpi] + 6; + ptr = (unsigned char *)cpd + le16_to_cpu(cpd->offs[cpi]) + 6; if (!(cp_table = kmalloc(256, GFP_KERNEL))) { printk("HPFS: out of memory for code page table\n"); brelse(bh); @@ -125,7 +125,7 @@ struct fnode *hpfs_map_fnode(struct super_block *s, ino_t ino, struct buffer_hea if (hpfs_sb(s)->sb_chk) { struct extended_attribute *ea; struct extended_attribute *ea_end; - if (fnode->magic != FNODE_MAGIC) { + if (le32_to_cpu(fnode->magic) != FNODE_MAGIC) { hpfs_error(s, "bad magic on fnode %08lx", (unsigned long)ino); goto bail; @@ -138,7 +138,7 @@ struct fnode *hpfs_map_fnode(struct super_block *s, ino_t ino, struct buffer_hea (unsigned long)ino); goto bail; } - if (fnode->btree.first_free != + if (le16_to_cpu(fnode->btree.first_free) != 8 + fnode->btree.n_used_nodes * (fnode->btree.internal ? 8 : 12)) { hpfs_error(s, "bad first_free pointer in fnode %08lx", @@ -146,12 +146,12 @@ struct fnode *hpfs_map_fnode(struct super_block *s, ino_t ino, struct buffer_hea goto bail; } } - if (fnode->ea_size_s && ((signed int)fnode->ea_offs < 0xc4 || - (signed int)fnode->ea_offs + fnode->acl_size_s + fnode->ea_size_s > 0x200)) { + if (le16_to_cpu(fnode->ea_size_s) && (le16_to_cpu(fnode->ea_offs) < 0xc4 || + le16_to_cpu(fnode->ea_offs) + le16_to_cpu(fnode->acl_size_s) + le16_to_cpu(fnode->ea_size_s) > 0x200)) { hpfs_error(s, "bad EA info in fnode %08lx: ea_offs == %04x ea_size_s == %04x", (unsigned long)ino, - fnode->ea_offs, fnode->ea_size_s); + le16_to_cpu(fnode->ea_offs), le16_to_cpu(fnode->ea_size_s)); goto bail; } ea = fnode_ea(fnode); @@ -178,16 +178,20 @@ struct anode *hpfs_map_anode(struct super_block *s, anode_secno ano, struct buff if (hpfs_sb(s)->sb_chk) if (hpfs_chk_sectors(s, ano, 1, "anode")) return NULL; if ((anode = hpfs_map_sector(s, ano, bhp, ANODE_RD_AHEAD))) if (hpfs_sb(s)->sb_chk) { - if (anode->magic != ANODE_MAGIC || anode->self != ano) { + if (le32_to_cpu(anode->magic) != ANODE_MAGIC) { hpfs_error(s, "bad magic on anode %08x", ano); goto bail; } + if (le32_to_cpu(anode->self) != ano) { + hpfs_error(s, "self pointer invalid on anode %08x", ano); + goto bail; + } if ((unsigned)anode->btree.n_used_nodes + (unsigned)anode->btree.n_free_nodes != (anode->btree.internal ? 60 : 40)) { hpfs_error(s, "bad number of nodes in anode %08x", ano); goto bail; } - if (anode->btree.first_free != + if (le16_to_cpu(anode->btree.first_free) != 8 + anode->btree.n_used_nodes * (anode->btree.internal ? 8 : 12)) { hpfs_error(s, "bad first_free pointer in anode %08x", ano); goto bail; @@ -219,26 +223,26 @@ struct dnode *hpfs_map_dnode(struct super_block *s, unsigned secno, unsigned p, pp = 0; unsigned char *d = (unsigned char *)dnode; int b = 0; - if (dnode->magic != DNODE_MAGIC) { + if (le32_to_cpu(dnode->magic) != DNODE_MAGIC) { hpfs_error(s, "bad magic on dnode %08x", secno); goto bail; } - if (dnode->self != secno) - hpfs_error(s, "bad self pointer on dnode %08x self = %08x", secno, dnode->self); + if (le32_to_cpu(dnode->self) != secno) + hpfs_error(s, "bad self pointer on dnode %08x self = %08x", secno, le32_to_cpu(dnode->self)); /* Check dirents - bad dirents would cause infinite loops or shooting to memory */ - if (dnode->first_free > 2048/* || dnode->first_free < 84*/) { - hpfs_error(s, "dnode %08x has first_free == %08x", secno, dnode->first_free); + if (le32_to_cpu(dnode->first_free) > 2048) { + hpfs_error(s, "dnode %08x has first_free == %08x", secno, le32_to_cpu(dnode->first_free)); goto bail; } - for (p = 20; p < dnode->first_free; p += d[p] + (d[p+1] << 8)) { + for (p = 20; p < le32_to_cpu(dnode->first_free); p += d[p] + (d[p+1] << 8)) { struct hpfs_dirent *de = (struct hpfs_dirent *)((char *)dnode + p); - if (de->length > 292 || (de->length < 32) || (de->length & 3) || p + de->length > 2048) { + if (le16_to_cpu(de->length) > 292 || (le16_to_cpu(de->length) < 32) || (le16_to_cpu(de->length) & 3) || p + le16_to_cpu(de->length) > 2048) { hpfs_error(s, "bad dirent size in dnode %08x, dirent %03x, last %03x", secno, p, pp); goto bail; } - if (((31 + de->namelen + de->down*4 + 3) & ~3) != de->length) { - if (((31 + de->namelen + de->down*4 + 3) & ~3) < de->length && s->s_flags & MS_RDONLY) goto ok; + if (((31 + de->namelen + de->down*4 + 3) & ~3) != le16_to_cpu(de->length)) { + if (((31 + de->namelen + de->down*4 + 3) & ~3) < le16_to_cpu(de->length) && s->s_flags & MS_RDONLY) goto ok; hpfs_error(s, "namelen does not match dirent size in dnode %08x, dirent %03x, last %03x", secno, p, pp); goto bail; } @@ -251,7 +255,7 @@ struct dnode *hpfs_map_dnode(struct super_block *s, unsigned secno, pp = p; } - if (p != dnode->first_free) { + if (p != le32_to_cpu(dnode->first_free)) { hpfs_error(s, "size on last dirent does not match first_free; dnode %08x", secno); goto bail; } @@ -277,7 +281,7 @@ dnode_secno hpfs_fnode_dno(struct super_block *s, ino_t ino) if (!fnode) return 0; - dno = fnode->u.external[0].disk_secno; + dno = le32_to_cpu(fnode->u.external[0].disk_secno); brelse(bh); return dno; } diff --git a/fs/hpfs/namei.c b/fs/hpfs/namei.c index 9c66f0e..5a8de6a 100644 --- a/fs/hpfs/namei.c +++ b/fs/hpfs/namei.c @@ -37,8 +37,8 @@ static int hpfs_mkdir(struct inode *dir, struct dentry *dentry, int mode) if (!(mode & 0222)) dee.read_only = 1; /*dee.archive = 0;*/ dee.hidden = name[0] == '.'; - dee.fnode = fno; - dee.creation_date = dee.write_date = dee.read_date = gmt_to_local(dir->i_sb, get_seconds()); + dee.fnode = cpu_to_le32(fno); + dee.creation_date = dee.write_date = dee.read_date = cpu_to_le32(gmt_to_local(dir->i_sb, get_seconds())); result = new_inode(dir->i_sb); if (!result) goto bail2; @@ -46,7 +46,7 @@ static int hpfs_mkdir(struct inode *dir, struct dentry *dentry, int mode) result->i_ino = fno; hpfs_i(result)->i_parent_dir = dir->i_ino; hpfs_i(result)->i_dno = dno; - result->i_ctime.tv_sec = result->i_mtime.tv_sec = result->i_atime.tv_sec = local_to_gmt(dir->i_sb, dee.creation_date); + result->i_ctime.tv_sec = result->i_mtime.tv_sec = result->i_atime.tv_sec = local_to_gmt(dir->i_sb, le32_to_cpu(dee.creation_date)); result->i_ctime.tv_nsec = 0; result->i_mtime.tv_nsec = 0; result->i_atime.tv_nsec = 0; @@ -69,21 +69,21 @@ static int hpfs_mkdir(struct inode *dir, struct dentry *dentry, int mode) } fnode->len = len; memcpy(fnode->name, name, len > 15 ? 15 : len); - fnode->up = dir->i_ino; + fnode->up = cpu_to_le32(dir->i_ino); fnode->dirflag = 1; fnode->btree.n_free_nodes = 7; fnode->btree.n_used_nodes = 1; - fnode->btree.first_free = 0x14; - fnode->u.external[0].disk_secno = dno; - fnode->u.external[0].file_secno = -1; + fnode->btree.first_free = cpu_to_le16(0x14); + fnode->u.external[0].disk_secno = cpu_to_le32(dno); + fnode->u.external[0].file_secno = cpu_to_le32(-1); dnode->root_dnode = 1; - dnode->up = fno; + dnode->up = cpu_to_le32(fno); de = hpfs_add_de(dir->i_sb, dnode, "\001\001", 2, 0); - de->creation_date = de->write_date = de->read_date = gmt_to_local(dir->i_sb, get_seconds()); + de->creation_date = de->write_date = de->read_date = cpu_to_le32(gmt_to_local(dir->i_sb, get_seconds())); if (!(mode & 0222)) de->read_only = 1; de->first = de->directory = 1; /*de->hidden = de->system = 0;*/ - de->fnode = fno; + de->fnode = cpu_to_le32(fno); mark_buffer_dirty(bh); brelse(bh); hpfs_mark_4buffers_dirty(&qbh0); @@ -137,8 +137,8 @@ static int hpfs_create(struct inode *dir, struct dentry *dentry, int mode, struc if (!(mode & 0222)) dee.read_only = 1; dee.archive = 1; dee.hidden = name[0] == '.'; - dee.fnode = fno; - dee.creation_date = dee.write_date = dee.read_date = gmt_to_local(dir->i_sb, get_seconds()); + dee.fnode = cpu_to_le32(fno); + dee.creation_date = dee.write_date = dee.read_date = cpu_to_le32(gmt_to_local(dir->i_sb, get_seconds())); result = new_inode(dir->i_sb); if (!result) @@ -152,7 +152,7 @@ static int hpfs_create(struct inode *dir, struct dentry *dentry, int mode, struc result->i_fop = &hpfs_file_ops; result->i_nlink = 1; hpfs_i(result)->i_parent_dir = dir->i_ino; - result->i_ctime.tv_sec = result->i_mtime.tv_sec = result->i_atime.tv_sec = local_to_gmt(dir->i_sb, dee.creation_date); + result->i_ctime.tv_sec = result->i_mtime.tv_sec = result->i_atime.tv_sec = local_to_gmt(dir->i_sb, le32_to_cpu(dee.creation_date)); result->i_ctime.tv_nsec = 0; result->i_mtime.tv_nsec = 0; result->i_atime.tv_nsec = 0; @@ -173,7 +173,7 @@ static int hpfs_create(struct inode *dir, struct dentry *dentry, int mode, struc } fnode->len = len; memcpy(fnode->name, name, len > 15 ? 15 : len); - fnode->up = dir->i_ino; + fnode->up = cpu_to_le32(dir->i_ino); mark_buffer_dirty(bh); brelse(bh); @@ -225,8 +225,8 @@ static int hpfs_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t if (!(mode & 0222)) dee.read_only = 1; dee.archive = 1; dee.hidden = name[0] == '.'; - dee.fnode = fno; - dee.creation_date = dee.write_date = dee.read_date = gmt_to_local(dir->i_sb, get_seconds()); + dee.fnode = cpu_to_le32(fno); + dee.creation_date = dee.write_date = dee.read_date = cpu_to_le32(gmt_to_local(dir->i_sb, get_seconds())); result = new_inode(dir->i_sb); if (!result) @@ -235,7 +235,7 @@ static int hpfs_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t hpfs_init_inode(result); result->i_ino = fno; hpfs_i(result)->i_parent_dir = dir->i_ino; - result->i_ctime.tv_sec = result->i_mtime.tv_sec = result->i_atime.tv_sec = local_to_gmt(dir->i_sb, dee.creation_date); + result->i_ctime.tv_sec = result->i_mtime.tv_sec = result->i_atime.tv_sec = local_to_gmt(dir->i_sb, le32_to_cpu(dee.creation_date)); result->i_ctime.tv_nsec = 0; result->i_mtime.tv_nsec = 0; result->i_atime.tv_nsec = 0; @@ -256,7 +256,7 @@ static int hpfs_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t } fnode->len = len; memcpy(fnode->name, name, len > 15 ? 15 : len); - fnode->up = dir->i_ino; + fnode->up = cpu_to_le32(dir->i_ino); mark_buffer_dirty(bh); insert_inode_hash(result); @@ -300,8 +300,8 @@ static int hpfs_symlink(struct inode *dir, struct dentry *dentry, const char *sy memset(&dee, 0, sizeof dee); dee.archive = 1; dee.hidden = name[0] == '.'; - dee.fnode = fno; - dee.creation_date = dee.write_date = dee.read_date = gmt_to_local(dir->i_sb, get_seconds()); + dee.fnode = cpu_to_le32(fno); + dee.creation_date = dee.write_date = dee.read_date = cpu_to_le32(gmt_to_local(dir->i_sb, get_seconds())); result = new_inode(dir->i_sb); if (!result) @@ -309,7 +309,7 @@ static int hpfs_symlink(struct inode *dir, struct dentry *dentry, const char *sy result->i_ino = fno; hpfs_init_inode(result); hpfs_i(result)->i_parent_dir = dir->i_ino; - result->i_ctime.tv_sec = result->i_mtime.tv_sec = result->i_atime.tv_sec = local_to_gmt(dir->i_sb, dee.creation_date); + result->i_ctime.tv_sec = result->i_mtime.tv_sec = result->i_atime.tv_sec = local_to_gmt(dir->i_sb, le32_to_cpu(dee.creation_date)); result->i_ctime.tv_nsec = 0; result->i_mtime.tv_nsec = 0; result->i_atime.tv_nsec = 0; @@ -332,7 +332,7 @@ static int hpfs_symlink(struct inode *dir, struct dentry *dentry, const char *sy } fnode->len = len; memcpy(fnode->name, name, len > 15 ? 15 : len); - fnode->up = dir->i_ino; + fnode->up = cpu_to_le32(dir->i_ino); hpfs_set_ea(result, fnode, "SYMLINK", symlink, strlen(symlink)); mark_buffer_dirty(bh); brelse(bh); @@ -382,7 +382,7 @@ again: if (de->directory) goto out1; - fno = de->fnode; + fno = le32_to_cpu(de->fnode); r = hpfs_remove_dirent(dir, dno, de, &qbh, 1); switch (r) { case 1: @@ -465,7 +465,7 @@ static int hpfs_rmdir(struct inode *dir, struct dentry *dentry) if (n_items) goto out1; - fno = de->fnode; + fno = le32_to_cpu(de->fnode); r = hpfs_remove_dirent(dir, dno, de, &qbh, 1); switch (r) { case 1: @@ -608,7 +608,7 @@ static int hpfs_rename(struct inode *old_dir, struct dentry *old_dentry, drop_nlink(old_dir); } if ((fnode = hpfs_map_fnode(i->i_sb, i->i_ino, &bh))) { - fnode->up = new_dir->i_ino; + fnode->up = cpu_to_le32(new_dir->i_ino); fnode->len = new_len; memcpy(fnode->name, new_name, new_len>15?15:new_len); if (new_len < 15) memset(&fnode->name[new_len], 0, 15 - new_len); diff --git a/fs/hpfs/super.c b/fs/hpfs/super.c index 4a7d026..98580a3 100644 --- a/fs/hpfs/super.c +++ b/fs/hpfs/super.c @@ -135,7 +135,7 @@ static unsigned count_bitmaps(struct super_block *s) n_bands = (hpfs_sb(s)->sb_fs_size + 0x3fff) >> 14; count = 0; for (n = 0; n < n_bands; n++) - count += hpfs_count_one_bitmap(s, hpfs_sb(s)->sb_bmp_dir[n]); + count += hpfs_count_one_bitmap(s, le32_to_cpu(hpfs_sb(s)->sb_bmp_dir[n])); return count; } @@ -509,9 +509,9 @@ static int hpfs_fill_super(struct super_block *s, void *options, int silent) if (!(spareblock = hpfs_map_sector(s, 17, &bh2, 0))) goto bail3; /* Check magics */ - if (/*bootblock->magic != BB_MAGIC - ||*/ superblock->magic != SB_MAGIC - || spareblock->magic != SP_MAGIC) { + if (/*le16_to_cpu(bootblock->magic) != BB_MAGIC + ||*/ le32_to_cpu(superblock->magic) != SB_MAGIC + || le32_to_cpu(spareblock->magic) != SP_MAGIC) { if (!silent) printk("HPFS: Bad magic ... probably not HPFS\n"); goto bail4; } @@ -532,12 +532,12 @@ static int hpfs_fill_super(struct super_block *s, void *options, int silent) s->s_op = &hpfs_sops; s->s_d_op = &hpfs_dentry_operations; - sbi->sb_root = superblock->root; - sbi->sb_fs_size = superblock->n_sectors; - sbi->sb_bitmaps = superblock->bitmaps; - sbi->sb_dirband_start = superblock->dir_band_start; - sbi->sb_dirband_size = superblock->n_dir_band; - sbi->sb_dmap = superblock->dir_band_bitmap; + sbi->sb_root = le32_to_cpu(superblock->root); + sbi->sb_fs_size = le32_to_cpu(superblock->n_sectors); + sbi->sb_bitmaps = le32_to_cpu(superblock->bitmaps); + sbi->sb_dirband_start = le32_to_cpu(superblock->dir_band_start); + sbi->sb_dirband_size = le32_to_cpu(superblock->n_dir_band); + sbi->sb_dmap = le32_to_cpu(superblock->dir_band_bitmap); sbi->sb_uid = uid; sbi->sb_gid = gid; sbi->sb_mode = 0777 & ~umask; @@ -555,7 +555,7 @@ static int hpfs_fill_super(struct super_block *s, void *options, int silent) sbi->sb_max_fwd_alloc = 0xffffff; /* Load bitmap directory */ - if (!(sbi->sb_bmp_dir = hpfs_load_bitmap_directory(s, superblock->bitmaps))) + if (!(sbi->sb_bmp_dir = hpfs_load_bitmap_directory(s, le32_to_cpu(superblock->bitmaps)))) goto bail4; /* Check for general fs errors*/ @@ -573,7 +573,7 @@ static int hpfs_fill_super(struct super_block *s, void *options, int silent) mark_buffer_dirty(bh2); } - if (spareblock->hotfixes_used || spareblock->n_spares_used) { + if (le32_to_cpu(spareblock->hotfixes_used) || le32_to_cpu(spareblock->n_spares_used)) { if (errs >= 2) { printk("HPFS: Hotfixes not supported here, try chkdsk\n"); mark_dirty(s, 0); @@ -583,7 +583,7 @@ static int hpfs_fill_super(struct super_block *s, void *options, int silent) if (errs == 0) printk("HPFS: Proceeding, but your filesystem will be probably corrupted by this driver...\n"); else printk("HPFS: This driver may read bad files or crash when operating on disk with hotfixes.\n"); } - if (spareblock->n_dnode_spares != spareblock->n_dnode_spares_free) { + if (le32_to_cpu(spareblock->n_dnode_spares) != le32_to_cpu(spareblock->n_dnode_spares_free)) { if (errs >= 2) { printk("HPFS: Spare dnodes used, try chkdsk\n"); mark_dirty(s, 0); @@ -594,17 +594,17 @@ static int hpfs_fill_super(struct super_block *s, void *options, int silent) } if (chk) { unsigned a; - if (superblock->dir_band_end - superblock->dir_band_start + 1 != superblock->n_dir_band || - superblock->dir_band_end < superblock->dir_band_start || superblock->n_dir_band > 0x4000) { + if (le32_to_cpu(superblock->dir_band_end) - le32_to_cpu(superblock->dir_band_start) + 1 != le32_to_cpu(superblock->n_dir_band) || + le32_to_cpu(superblock->dir_band_end) < le32_to_cpu(superblock->dir_band_start) || le32_to_cpu(superblock->n_dir_band) > 0x4000) { hpfs_error(s, "dir band size mismatch: dir_band_start==%08x, dir_band_end==%08x, n_dir_band==%08x", - superblock->dir_band_start, superblock->dir_band_end, superblock->n_dir_band); + le32_to_cpu(superblock->dir_band_start), le32_to_cpu(superblock->dir_band_end), le32_to_cpu(superblock->n_dir_band)); goto bail4; } a = sbi->sb_dirband_size; sbi->sb_dirband_size = 0; - if (hpfs_chk_sectors(s, superblock->dir_band_start, superblock->n_dir_band, "dir_band") || - hpfs_chk_sectors(s, superblock->dir_band_bitmap, 4, "dir_band_bitmap") || - hpfs_chk_sectors(s, superblock->bitmaps, 4, "bitmaps")) { + if (hpfs_chk_sectors(s, le32_to_cpu(superblock->dir_band_start), le32_to_cpu(superblock->n_dir_band), "dir_band") || + hpfs_chk_sectors(s, le32_to_cpu(superblock->dir_band_bitmap), 4, "dir_band_bitmap") || + hpfs_chk_sectors(s, le32_to_cpu(superblock->bitmaps), 4, "bitmaps")) { mark_dirty(s, 0); goto bail4; } @@ -612,8 +612,8 @@ static int hpfs_fill_super(struct super_block *s, void *options, int silent) } else printk("HPFS: You really don't want any checks? You are crazy...\n"); /* Load code page table */ - if (spareblock->n_code_pages) - if (!(sbi->sb_cp_table = hpfs_load_code_page(s, spareblock->code_page_dir))) + if (le32_to_cpu(spareblock->n_code_pages)) + if (!(sbi->sb_cp_table = hpfs_load_code_page(s, le32_to_cpu(spareblock->code_page_dir)))) printk("HPFS: Warning: code page support is disabled\n"); brelse(bh2); @@ -642,13 +642,13 @@ static int hpfs_fill_super(struct super_block *s, void *options, int silent) if (!de) hpfs_error(s, "unable to find root dir"); else { - root->i_atime.tv_sec = local_to_gmt(s, de->read_date); + root->i_atime.tv_sec = local_to_gmt(s, le32_to_cpu(de->read_date)); root->i_atime.tv_nsec = 0; - root->i_mtime.tv_sec = local_to_gmt(s, de->write_date); + root->i_mtime.tv_sec = local_to_gmt(s, le32_to_cpu(de->write_date)); root->i_mtime.tv_nsec = 0; - root->i_ctime.tv_sec = local_to_gmt(s, de->creation_date); + root->i_ctime.tv_sec = local_to_gmt(s, le32_to_cpu(de->creation_date)); root->i_ctime.tv_nsec = 0; - hpfs_i(root)->i_ea_size = de->ea_size; + hpfs_i(root)->i_ea_size = le16_to_cpu(de->ea_size); hpfs_i(root)->i_parent_dir = root->i_ino; if (root->i_size == -1) root->i_size = 2048; -- cgit v0.10.2 From d0969d1949cc67a0f100f30ad69ec7ec1eca70d2 Mon Sep 17 00:00:00 2001 From: Mikulas Patocka Date: Sun, 8 May 2011 20:44:32 +0200 Subject: HPFS: Fix some unaligned accesses Fix some unaligned accesses Signed-off-by: Mikulas Patocka Signed-off-by: Linus Torvalds diff --git a/fs/hpfs/ea.c b/fs/hpfs/ea.c index 1bbc37d..7f1d90c 100644 --- a/fs/hpfs/ea.c +++ b/fs/hpfs/ea.c @@ -24,7 +24,7 @@ void hpfs_ea_ext_remove(struct super_block *s, secno a, int ano, unsigned len) } if (hpfs_ea_read(s, a, ano, pos, 4, ex)) return; if (ea->indirect) { - if (le16_to_cpu(ea->valuelen) != 8) { + if (ea_valuelen(ea) != 8) { hpfs_error(s, "ea->indirect set while ea->valuelen!=8, %s %08x, pos %08x", ano ? "anode" : "sectors", a, pos); return; @@ -33,7 +33,7 @@ void hpfs_ea_ext_remove(struct super_block *s, secno a, int ano, unsigned len) return; hpfs_ea_remove(s, ea_sec(ea), ea->anode, ea_len(ea)); } - pos += ea->namelen + le16_to_cpu(ea->valuelen) + 5; + pos += ea->namelen + ea_valuelen(ea) + 5; } if (!ano) hpfs_free_sectors(s, a, (len+511) >> 9); else { @@ -82,10 +82,10 @@ int hpfs_read_ea(struct super_block *s, struct fnode *fnode, char *key, if (!strcmp(ea->name, key)) { if (ea->indirect) goto indirect; - if (le16_to_cpu(ea->valuelen) >= size) + if (ea_valuelen(ea) >= size) return -EINVAL; - memcpy(buf, ea_data(ea), le16_to_cpu(ea->valuelen)); - buf[le16_to_cpu(ea->valuelen)] = 0; + memcpy(buf, ea_data(ea), ea_valuelen(ea)); + buf[ea_valuelen(ea)] = 0; return 0; } a = le32_to_cpu(fnode->ea_secno); @@ -106,14 +106,14 @@ int hpfs_read_ea(struct super_block *s, struct fnode *fnode, char *key, if (!strcmp(ea->name, key)) { if (ea->indirect) goto indirect; - if (le16_to_cpu(ea->valuelen) >= size) + if (ea_valuelen(ea) >= size) return -EINVAL; - if (hpfs_ea_read(s, a, ano, pos + 4 + ea->namelen + 1, le16_to_cpu(ea->valuelen), buf)) + if (hpfs_ea_read(s, a, ano, pos + 4 + ea->namelen + 1, ea_valuelen(ea), buf)) return -EIO; - buf[le16_to_cpu(ea->valuelen)] = 0; + buf[ea_valuelen(ea)] = 0; return 0; } - pos += ea->namelen + le16_to_cpu(ea->valuelen) + 5; + pos += ea->namelen + ea_valuelen(ea) + 5; } return -ENOENT; indirect: @@ -138,12 +138,12 @@ char *hpfs_get_ea(struct super_block *s, struct fnode *fnode, char *key, int *si if (!strcmp(ea->name, key)) { if (ea->indirect) return get_indirect_ea(s, ea->anode, ea_sec(ea), *size = ea_len(ea)); - if (!(ret = kmalloc((*size = le16_to_cpu(ea->valuelen)) + 1, GFP_NOFS))) { + if (!(ret = kmalloc((*size = ea_valuelen(ea)) + 1, GFP_NOFS))) { printk("HPFS: out of memory for EA\n"); return NULL; } - memcpy(ret, ea_data(ea), le16_to_cpu(ea->valuelen)); - ret[le16_to_cpu(ea->valuelen)] = 0; + memcpy(ret, ea_data(ea), ea_valuelen(ea)); + ret[ea_valuelen(ea)] = 0; return ret; } a = le32_to_cpu(fnode->ea_secno); @@ -164,18 +164,18 @@ char *hpfs_get_ea(struct super_block *s, struct fnode *fnode, char *key, int *si if (!strcmp(ea->name, key)) { if (ea->indirect) return get_indirect_ea(s, ea->anode, ea_sec(ea), *size = ea_len(ea)); - if (!(ret = kmalloc((*size = le16_to_cpu(ea->valuelen)) + 1, GFP_NOFS))) { + if (!(ret = kmalloc((*size = ea_valuelen(ea)) + 1, GFP_NOFS))) { printk("HPFS: out of memory for EA\n"); return NULL; } - if (hpfs_ea_read(s, a, ano, pos + 4 + ea->namelen + 1, le16_to_cpu(ea->valuelen), ret)) { + if (hpfs_ea_read(s, a, ano, pos + 4 + ea->namelen + 1, ea_valuelen(ea), ret)) { kfree(ret); return NULL; } - ret[le16_to_cpu(ea->valuelen)] = 0; + ret[ea_valuelen(ea)] = 0; return ret; } - pos += ea->namelen + le16_to_cpu(ea->valuelen) + 5; + pos += ea->namelen + ea_valuelen(ea) + 5; } return NULL; } @@ -202,7 +202,7 @@ void hpfs_set_ea(struct inode *inode, struct fnode *fnode, const char *key, if (ea->indirect) { if (ea_len(ea) == size) set_indirect_ea(s, ea->anode, ea_sec(ea), data, size); - } else if (le16_to_cpu(ea->valuelen) == size) { + } else if (ea_valuelen(ea) == size) { memcpy(ea_data(ea), data, size); } return; @@ -228,12 +228,12 @@ void hpfs_set_ea(struct inode *inode, struct fnode *fnode, const char *key, set_indirect_ea(s, ea->anode, ea_sec(ea), data, size); } else { - if (le16_to_cpu(ea->valuelen) == size) + if (ea_valuelen(ea) == size) hpfs_ea_write(s, a, ano, pos + 4 + ea->namelen + 1, size, data); } return; } - pos += ea->namelen + le16_to_cpu(ea->valuelen) + 5; + pos += ea->namelen + ea_valuelen(ea) + 5; } if (!le16_to_cpu(fnode->ea_offs)) { /*if (le16_to_cpu(fnode->ea_size_s)) { @@ -254,7 +254,8 @@ void hpfs_set_ea(struct inode *inode, struct fnode *fnode, const char *key, ea = fnode_end_ea(fnode); *(char *)ea = 0; ea->namelen = strlen(key); - ea->valuelen = cpu_to_le16(size); + ea->valuelen_lo = size; + ea->valuelen_hi = size >> 8; strcpy(ea->name, key); memcpy(ea_data(ea), data, size); fnode->ea_size_s = cpu_to_le16(le16_to_cpu(fnode->ea_size_s) + strlen(key) + size + 5); diff --git a/fs/hpfs/hpfs.h b/fs/hpfs/hpfs.h index 91a6223..8b0650a 100644 --- a/fs/hpfs/hpfs.h +++ b/fs/hpfs/hpfs.h @@ -546,7 +546,8 @@ struct extended_attribute where real value starts */ #endif u8 namelen; /* length of name, bytes */ - u16 valuelen; /* length of value, bytes */ + u8 valuelen_lo; /* length of value, bytes */ + u8 valuelen_hi; /* length of value, bytes */ u8 name[0]; /* u8 name[namelen]; ascii attrib name diff --git a/fs/hpfs/hpfs_fn.h b/fs/hpfs/hpfs_fn.h index f993773..dd552f8 100644 --- a/fs/hpfs/hpfs_fn.h +++ b/fs/hpfs/hpfs_fn.h @@ -13,6 +13,7 @@ #include #include #include +#include #include "hpfs.h" @@ -135,19 +136,24 @@ static inline struct extended_attribute *fnode_end_ea(struct fnode *fnode) return (struct extended_attribute *)((char *)fnode + le16_to_cpu(fnode->ea_offs) + le16_to_cpu(fnode->acl_size_s) + le16_to_cpu(fnode->ea_size_s)); } +static unsigned ea_valuelen(struct extended_attribute *ea) +{ + return ea->valuelen_lo + 256 * ea->valuelen_hi; +} + static inline struct extended_attribute *next_ea(struct extended_attribute *ea) { - return (struct extended_attribute *)((char *)ea + 5 + ea->namelen + le16_to_cpu(ea->valuelen)); + return (struct extended_attribute *)((char *)ea + 5 + ea->namelen + ea_valuelen(ea)); } static inline secno ea_sec(struct extended_attribute *ea) { - return le32_to_cpu(*((secno *)((char *)ea + 9 + ea->namelen))); + return le32_to_cpu(get_unaligned((secno *)((char *)ea + 9 + ea->namelen))); } static inline secno ea_len(struct extended_attribute *ea) { - return le32_to_cpu(*((secno *)((char *)ea + 5 + ea->namelen))); + return le32_to_cpu(get_unaligned((secno *)((char *)ea + 5 + ea->namelen))); } static inline char *ea_data(struct extended_attribute *ea) -- cgit v0.10.2 From c3514817445a5a5e6c0d0c8152f5f161a98001db Mon Sep 17 00:00:00 2001 From: Mikulas Patocka Date: Sun, 8 May 2011 20:44:38 +0200 Subject: HPFS: Move declaration up, so that there are no out-of-scope pointers Move declaration up, so that there are no out-of-scope pointers Reported-by: Jesper Juhl Signed-off-by: Mikulas Patocka Signed-off-by: Linus Torvalds diff --git a/fs/hpfs/ea.c b/fs/hpfs/ea.c index 7f1d90c..d8b84d1 100644 --- a/fs/hpfs/ea.c +++ b/fs/hpfs/ea.c @@ -76,6 +76,7 @@ int hpfs_read_ea(struct super_block *s, struct fnode *fnode, char *key, unsigned pos; int ano, len; secno a; + char ex[4 + 255 + 1 + 8]; struct extended_attribute *ea; struct extended_attribute *ea_end = fnode_end_ea(fnode); for (ea = fnode_ea(fnode); ea < ea_end; ea = next_ea(ea)) @@ -93,7 +94,6 @@ int hpfs_read_ea(struct super_block *s, struct fnode *fnode, char *key, ano = fnode->ea_anode; pos = 0; while (pos < len) { - char ex[4 + 255 + 1 + 8]; ea = (struct extended_attribute *)ex; if (pos + 4 > len) { hpfs_error(s, "EAs don't end correctly, %s %08x, len %08x", -- cgit v0.10.2 From 88f4e9e870c01452e57a6943c04c8d62f6a0a7a6 Mon Sep 17 00:00:00 2001 From: Mikulas Patocka Date: Sun, 8 May 2011 20:44:46 +0200 Subject: HPFS: Remove unused variable Remove unused variable Signed-off-by: Mikulas Patocka Signed-off-by: Linus Torvalds diff --git a/fs/hpfs/namei.c b/fs/hpfs/namei.c index 5a8de6a..1f05839 100644 --- a/fs/hpfs/namei.c +++ b/fs/hpfs/namei.c @@ -361,7 +361,6 @@ static int hpfs_unlink(struct inode *dir, struct dentry *dentry) struct hpfs_dirent *de; struct inode *inode = dentry->d_inode; dnode_secno dno; - fnode_secno fno; int r; int rep = 0; int err; @@ -382,7 +381,6 @@ again: if (de->directory) goto out1; - fno = le32_to_cpu(de->fnode); r = hpfs_remove_dirent(dir, dno, de, &qbh, 1); switch (r) { case 1: @@ -440,7 +438,6 @@ static int hpfs_rmdir(struct inode *dir, struct dentry *dentry) struct hpfs_dirent *de; struct inode *inode = dentry->d_inode; dnode_secno dno; - fnode_secno fno; int n_items = 0; int err; int r; @@ -465,7 +462,6 @@ static int hpfs_rmdir(struct inode *dir, struct dentry *dentry) if (n_items) goto out1; - fno = le32_to_cpu(de->fnode); r = hpfs_remove_dirent(dir, dno, de, &qbh, 1); switch (r) { case 1: -- cgit v0.10.2 From 49183b2818de6899383bb82bc032f9344d6791ff Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Tue, 19 Apr 2011 21:14:14 +0100 Subject: drm/i915: Only enable the plane after setting the fb base (pre-ILK) When enabling the plane, it is helpful to have already pointed that plane to valid memory or else we may incur the wrath of a PGTBL_ER. This code preserved the behaviour from the bad old days for unknown reasons... Found by assert_fb_bound_for_plane(). References: https://bugs.freedesktop.org/show_bug.cgi?id=36246 Signed-off-by: Chris Wilson Cc: Daniel Vetter Cc: Jesse Barnes Signed-off-by: Keith Packard diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index aab06cf..967451e 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -5154,8 +5154,6 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc, I915_WRITE(DSPCNTR(plane), dspcntr); POSTING_READ(DSPCNTR(plane)); - if (!HAS_PCH_SPLIT(dev)) - intel_enable_plane(dev_priv, plane, pipe); ret = intel_pipe_set_base(crtc, x, y, old_fb); -- cgit v0.10.2 From 39adb7a542db08998b4ae88f1698c4300dc39b55 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Fri, 22 Apr 2011 22:17:21 +0100 Subject: drm/i915: fix intel_crtc_clock_get pipe reads after "cleanup cleanup" Despite the fixes in 548f245ba6a31 (drm/i915: fix per-pipe reads after "cleanup"), we missed one neighbouring read that was mistakenly replaced with the reg value in 9db4a9c (drm/i915: cleanup per-pipe reg usage). This was preventing us from correctly determining the mode the BIOS left the panel in for machines that neither have an OpRegion nor access to the VBT, (e.g. the EeePC 700). Signed-off-by: Chris Wilson Cc: Jesse Barnes Cc: stable@kernel.org Reviewed-by: Jesse Barnes Signed-off-by: Keith Packard diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 967451e..373c2a0 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -5603,9 +5603,9 @@ static int intel_crtc_clock_get(struct drm_device *dev, struct drm_crtc *crtc) intel_clock_t clock; if ((dpll & DISPLAY_RATE_SELECT_FPA1) == 0) - fp = FP0(pipe); + fp = I915_READ(FP0(pipe)); else - fp = FP1(pipe); + fp = I915_READ(FP1(pipe)); clock.m1 = (fp & FP_M1_DIV_MASK) >> FP_M1_DIV_SHIFT; if (IS_PINEVIEW(dev)) { -- cgit v0.10.2 From 2fb4e61d9471867677c97bf11dba8f1e9dfa7f7c Mon Sep 17 00:00:00 2001 From: Alex Williamson Date: Thu, 21 Apr 2011 16:08:14 -0600 Subject: drm/i915/lvds: Only act on lid notify when the device is on If we're using vga switcheroo, the device may be turned off and poking it can return random state. This provokes an OOPS fixed separately by 8ff887c847 (drm/i915/dp: Be paranoid in case we disable a DP before it is attached). Trying to use and respond to events on a device that has been turned off by the user is in principle a silly thing to do. Signed-off-by: Alex Williamson Signed-off-by: Chris Wilson Cc: stable@kernel.org Signed-off-by: Keith Packard diff --git a/drivers/gpu/drm/i915/intel_lvds.c b/drivers/gpu/drm/i915/intel_lvds.c index a562bd2..67cb076 100644 --- a/drivers/gpu/drm/i915/intel_lvds.c +++ b/drivers/gpu/drm/i915/intel_lvds.c @@ -539,6 +539,9 @@ static int intel_lid_notify(struct notifier_block *nb, unsigned long val, struct drm_device *dev = dev_priv->dev; struct drm_connector *connector = dev_priv->int_lvds_connector; + if (dev->switch_power_state != DRM_SWITCH_POWER_ON) + return NOTIFY_OK; + /* * check and update the status of LVDS connector after receiving * the LID nofication event. -- cgit v0.10.2 From 226bd3411471af42f7edbdfaf73f2d54ebb62a66 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Sun, 8 May 2011 23:17:57 +0000 Subject: net: use batched device unregister in veth and macvlan MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit veth devices dont use the batched device unregisters yet. Since veth are a pair of devices, it makes sense to use a batch of two unregisters, this roughly divides dismantle time by two. Fix this by changing dellink() callers to always provide a non NULL head. (Idea from MichaÅ‚ MirosÅ‚aw) This patch also handles macvlan case : We now dismantle all macvlans on top of a lower dev at once. Reported-by: Alex Bligh Signed-off-by: Eric Dumazet Cc: MichaÅ‚ MirosÅ‚aw Cc: Jesse Gross Cc: Paul E. McKenney Cc: Ben Greear Signed-off-by: David S. Miller diff --git a/drivers/net/macvlan.c b/drivers/net/macvlan.c index 3ad5425..d7c0bc62 100644 --- a/drivers/net/macvlan.c +++ b/drivers/net/macvlan.c @@ -785,6 +785,7 @@ static int macvlan_device_event(struct notifier_block *unused, struct net_device *dev = ptr; struct macvlan_dev *vlan, *next; struct macvlan_port *port; + LIST_HEAD(list_kill); if (!macvlan_port_exists(dev)) return NOTIFY_DONE; @@ -810,7 +811,9 @@ static int macvlan_device_event(struct notifier_block *unused, break; list_for_each_entry_safe(vlan, next, &port->vlans, list) - vlan->dev->rtnl_link_ops->dellink(vlan->dev, NULL); + vlan->dev->rtnl_link_ops->dellink(vlan->dev, &list_kill); + unregister_netdevice_many(&list_kill); + list_del(&list_kill); break; case NETDEV_PRE_TYPE_CHANGE: /* Forbid underlaying device to change its type. */ diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c index 5a160f4..d2ba259 100644 --- a/net/core/rtnetlink.c +++ b/net/core/rtnetlink.c @@ -1501,6 +1501,7 @@ static int rtnl_dellink(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg) char ifname[IFNAMSIZ]; struct nlattr *tb[IFLA_MAX+1]; int err; + LIST_HEAD(list_kill); err = nlmsg_parse(nlh, sizeof(*ifm), tb, IFLA_MAX, ifla_policy); if (err < 0) @@ -1524,7 +1525,9 @@ static int rtnl_dellink(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg) if (!ops) return -EOPNOTSUPP; - ops->dellink(dev, NULL); + ops->dellink(dev, &list_kill); + unregister_netdevice_many(&list_kill); + list_del(&list_kill); return 0; } -- cgit v0.10.2 From da37e368763f708d2ae5a81e61ec59372b831cf5 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Mon, 9 May 2011 03:35:55 +0000 Subject: garp: remove one synchronize_rcu() call Speedup vlan dismantling in CONFIG_VLAN_8021Q_GVRP=y cases, by using a call_rcu() to free the memory instead of waiting with expensive synchronize_rcu() [ while RTNL is held ] Signed-off-by: Eric Dumazet Cc: Ben Greear Cc: Patrick McHardy Cc: Paul E. McKenney Signed-off-by: David S. Miller diff --git a/include/net/garp.h b/include/net/garp.h index f4c2959..8cabbf08 100644 --- a/include/net/garp.h +++ b/include/net/garp.h @@ -108,6 +108,7 @@ struct garp_applicant { struct garp_port { struct garp_applicant __rcu *applicants[GARP_APPLICATION_MAX + 1]; + struct rcu_head rcu; }; extern int garp_register_application(struct garp_application *app); diff --git a/net/802/garp.c b/net/802/garp.c index c1df2da..5dbe896 100644 --- a/net/802/garp.c +++ b/net/802/garp.c @@ -544,6 +544,11 @@ static int garp_init_port(struct net_device *dev) return 0; } +static void garp_kfree_rcu(struct rcu_head *head) +{ + kfree(container_of(head, struct garp_port, rcu)); +} + static void garp_release_port(struct net_device *dev) { struct garp_port *port = rtnl_dereference(dev->garp_port); @@ -554,8 +559,7 @@ static void garp_release_port(struct net_device *dev) return; } rcu_assign_pointer(dev->garp_port, NULL); - synchronize_rcu(); - kfree(port); + call_rcu(&port->rcu, garp_kfree_rcu); } int garp_init_applicant(struct net_device *dev, struct garp_application *appl) -- cgit v0.10.2 From 48752e1b1802231ef2a076f34d861918b7d571c3 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Mon, 9 May 2011 04:40:44 +0000 Subject: vlan: remove one synchronize_net() call MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit At VLAN dismantle phase, unregister_vlan_dev() makes one synchronize_net() call after vlan_group_set_device(grp, vlan_id, NULL). This call can be safely removed because we are calling unregister_netdevice_queue() to queue device for deletion, and this process needs at least one rcu grace period to complete. Signed-off-by: Eric Dumazet Cc: Ben Greear Cc: Patrick McHardy Cc: Paul E. McKenney Cc: Jesse Gross Cc: MichaÅ‚ MirosÅ‚aw Acked-by: Jesse Gross Signed-off-by: David S. Miller diff --git a/include/linux/if_vlan.h b/include/linux/if_vlan.h index 546d9d3..290bd8a 100644 --- a/include/linux/if_vlan.h +++ b/include/linux/if_vlan.h @@ -86,7 +86,6 @@ struct vlan_group { * the vlan is attached to. */ unsigned int nr_vlans; - int killall; struct hlist_node hlist; /* linked list */ struct net_device **vlan_devices_arrays[VLAN_GROUP_ARRAY_SPLIT_PARTS]; struct rcu_head rcu; diff --git a/net/8021q/vlan.c b/net/8021q/vlan.c index 969e700..718d635d 100644 --- a/net/8021q/vlan.c +++ b/net/8021q/vlan.c @@ -120,9 +120,10 @@ void unregister_vlan_dev(struct net_device *dev, struct list_head *head) grp->nr_vlans--; vlan_group_set_device(grp, vlan_id, NULL); - if (!grp->killall) - synchronize_net(); - + /* Because unregister_netdevice_queue() makes sure at least one rcu + * grace period is respected before device freeing, + * we dont need to call synchronize_net() here. + */ unregister_netdevice_queue(dev, head); /* If the group is now empty, kill off the group. */ @@ -478,9 +479,6 @@ static int vlan_device_event(struct notifier_block *unused, unsigned long event, if (dev->reg_state != NETREG_UNREGISTERING) break; - /* Delete all VLANs for this dev. */ - grp->killall = 1; - for (i = 0; i < VLAN_N_VID; i++) { vlandev = vlan_group_get_device(grp, i); if (!vlandev) -- cgit v0.10.2 From dcbe14b91a920657ff3a9ba0efb7c5b5562f956a Mon Sep 17 00:00:00 2001 From: Kleber Sacilotto de Souza Date: Wed, 4 May 2011 13:05:11 +0000 Subject: ehea: fix wrongly reported speed and port Currently EHEA reports to ethtool as supporting 10M, 100M, 1G and 10G and connected to FIBRE independent of the hardware configuration. However, when connected to FIBRE the only supported speed is 10G full-duplex, and the other speeds and modes are only supported when connected to twisted pair. Signed-off-by: Kleber Sacilotto de Souza Acked-by: Breno Leitao Signed-off-by: David S. Miller diff --git a/drivers/net/ehea/ehea_ethtool.c b/drivers/net/ehea/ehea_ethtool.c index 3e2e734..f3bbdce 100644 --- a/drivers/net/ehea/ehea_ethtool.c +++ b/drivers/net/ehea/ehea_ethtool.c @@ -55,15 +55,20 @@ static int ehea_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) cmd->duplex = -1; } - cmd->supported = (SUPPORTED_10000baseT_Full | SUPPORTED_1000baseT_Full - | SUPPORTED_100baseT_Full | SUPPORTED_100baseT_Half - | SUPPORTED_10baseT_Full | SUPPORTED_10baseT_Half - | SUPPORTED_Autoneg | SUPPORTED_FIBRE); - - cmd->advertising = (ADVERTISED_10000baseT_Full | ADVERTISED_Autoneg - | ADVERTISED_FIBRE); + if (cmd->speed == SPEED_10000) { + cmd->supported = (SUPPORTED_10000baseT_Full | SUPPORTED_FIBRE); + cmd->advertising = (ADVERTISED_10000baseT_Full | ADVERTISED_FIBRE); + cmd->port = PORT_FIBRE; + } else { + cmd->supported = (SUPPORTED_1000baseT_Full | SUPPORTED_100baseT_Full + | SUPPORTED_100baseT_Half | SUPPORTED_10baseT_Full + | SUPPORTED_10baseT_Half | SUPPORTED_Autoneg + | SUPPORTED_TP); + cmd->advertising = (ADVERTISED_1000baseT_Full | ADVERTISED_Autoneg + | ADVERTISED_TP); + cmd->port = PORT_TP; + } - cmd->port = PORT_FIBRE; cmd->autoneg = port->autoneg == 1 ? AUTONEG_ENABLE : AUTONEG_DISABLE; return 0; -- cgit v0.10.2 From 6709d9521df05c105343473ab8b147e2ef1e13d8 Mon Sep 17 00:00:00 2001 From: Somnath Kotur Date: Wed, 4 May 2011 22:40:46 +0000 Subject: be2net: Fixed bugs related to PVID. Fixed bug to make sure 'pvid' retrieval will work on big endian hosts. Fixed incorrect comparison between the Rx Completion's 16-bit VLAN TCI and the PVID. Now comparing only the relevant 12 bits corresponding to the VID. Renamed 'vid' field under Rx Completion to 'vlan_tag' to reflect accurate description. Signed-off-by: Somnath Kotur Signed-off-by: David S. Miller diff --git a/drivers/net/benet/be.h b/drivers/net/benet/be.h index 66823ed..2353eca 100644 --- a/drivers/net/benet/be.h +++ b/drivers/net/benet/be.h @@ -213,7 +213,7 @@ struct be_rx_stats { struct be_rx_compl_info { u32 rss_hash; - u16 vid; + u16 vlan_tag; u16 pkt_size; u16 rxq_idx; u16 mac_id; diff --git a/drivers/net/benet/be_cmds.c b/drivers/net/benet/be_cmds.c index 1e2d825..9dc9394 100644 --- a/drivers/net/benet/be_cmds.c +++ b/drivers/net/benet/be_cmds.c @@ -132,7 +132,7 @@ static void be_async_grp5_pvid_state_process(struct be_adapter *adapter, struct be_async_event_grp5_pvid_state *evt) { if (evt->enabled) - adapter->pvid = evt->tag; + adapter->pvid = le16_to_cpu(evt->tag); else adapter->pvid = 0; } diff --git a/drivers/net/benet/be_main.c b/drivers/net/benet/be_main.c index 02a0443..9187fb4 100644 --- a/drivers/net/benet/be_main.c +++ b/drivers/net/benet/be_main.c @@ -1018,7 +1018,8 @@ static void be_rx_compl_process(struct be_adapter *adapter, kfree_skb(skb); return; } - vlan_hwaccel_receive_skb(skb, adapter->vlan_grp, rxcp->vid); + vlan_hwaccel_receive_skb(skb, adapter->vlan_grp, + rxcp->vlan_tag); } else { netif_receive_skb(skb); } @@ -1076,7 +1077,8 @@ static void be_rx_compl_process_gro(struct be_adapter *adapter, if (likely(!rxcp->vlanf)) napi_gro_frags(&eq_obj->napi); else - vlan_gro_frags(&eq_obj->napi, adapter->vlan_grp, rxcp->vid); + vlan_gro_frags(&eq_obj->napi, adapter->vlan_grp, + rxcp->vlan_tag); } static void be_parse_rx_compl_v1(struct be_adapter *adapter, @@ -1102,7 +1104,8 @@ static void be_parse_rx_compl_v1(struct be_adapter *adapter, rxcp->pkt_type = AMAP_GET_BITS(struct amap_eth_rx_compl_v1, cast_enc, compl); rxcp->vtm = AMAP_GET_BITS(struct amap_eth_rx_compl_v1, vtm, compl); - rxcp->vid = AMAP_GET_BITS(struct amap_eth_rx_compl_v1, vlan_tag, compl); + rxcp->vlan_tag = AMAP_GET_BITS(struct amap_eth_rx_compl_v1, vlan_tag, + compl); } static void be_parse_rx_compl_v0(struct be_adapter *adapter, @@ -1128,7 +1131,8 @@ static void be_parse_rx_compl_v0(struct be_adapter *adapter, rxcp->pkt_type = AMAP_GET_BITS(struct amap_eth_rx_compl_v0, cast_enc, compl); rxcp->vtm = AMAP_GET_BITS(struct amap_eth_rx_compl_v0, vtm, compl); - rxcp->vid = AMAP_GET_BITS(struct amap_eth_rx_compl_v0, vlan_tag, compl); + rxcp->vlan_tag = AMAP_GET_BITS(struct amap_eth_rx_compl_v0, vlan_tag, + compl); } static struct be_rx_compl_info *be_rx_compl_get(struct be_rx_obj *rxo) @@ -1155,9 +1159,11 @@ static struct be_rx_compl_info *be_rx_compl_get(struct be_rx_obj *rxo) rxcp->vlanf = 0; if (!lancer_chip(adapter)) - rxcp->vid = swab16(rxcp->vid); + rxcp->vlan_tag = swab16(rxcp->vlan_tag); - if ((adapter->pvid == rxcp->vid) && !adapter->vlan_tag[rxcp->vid]) + if (((adapter->pvid & VLAN_VID_MASK) == + (rxcp->vlan_tag & VLAN_VID_MASK)) && + !adapter->vlan_tag[rxcp->vlan_tag]) rxcp->vlanf = 0; /* As the compl has been parsed, reset it; we wont touch it again */ -- cgit v0.10.2 From 057bef938896e6266ae24ec4266d24792d27c29a Mon Sep 17 00:00:00 2001 From: Matvejchikov Ilya Date: Fri, 6 May 2011 06:23:09 +0000 Subject: NET: slip, fix ldisc->open retval TTY layer expects 0 if the ldisc->open operation succeeded. Signed-off-by : Matvejchikov Ilya Acked-by: Oliver Hartkopp Acked-by: Alan Cox Signed-off-by: David S. Miller diff --git a/drivers/net/slip.c b/drivers/net/slip.c index 86cbb9e..8ec1a9a 100644 --- a/drivers/net/slip.c +++ b/drivers/net/slip.c @@ -853,7 +853,9 @@ static int slip_open(struct tty_struct *tty) /* Done. We have linked the TTY line to a channel. */ rtnl_unlock(); tty->receive_room = 65536; /* We don't flow control */ - return sl->dev->base_addr; + + /* TTY layer expects 0 on success */ + return 0; err_free_bufs: sl_free_bufs(sl); -- cgit v0.10.2 From ce3dad0f74e6b240f0b1dedbd8ea268a3f298d82 Mon Sep 17 00:00:00 2001 From: Toshiharu Okada Date: Fri, 6 May 2011 02:53:51 +0000 Subject: PCH_GbE : Fixed the issue of collision detection The collision detection setting was invalid. When collision occurred, because data was not resent, there was an issue to which a transmitting throughput falls. This patch enables the collision detection. Signed-off-by: Toshiharu Okada Signed-off-by: David S. Miller diff --git a/drivers/net/pch_gbe/pch_gbe_main.c b/drivers/net/pch_gbe/pch_gbe_main.c index 2ef2f9c..4ebd1d4 100644 --- a/drivers/net/pch_gbe/pch_gbe_main.c +++ b/drivers/net/pch_gbe/pch_gbe_main.c @@ -43,8 +43,7 @@ const char pch_driver_version[] = DRV_VERSION; #define PCH_GBE_MAC_RGMII_CTRL_SETTING ( \ PCH_GBE_CHIP_TYPE_INTERNAL | \ - PCH_GBE_RGMII_MODE_RGMII | \ - PCH_GBE_CRS_SEL \ + PCH_GBE_RGMII_MODE_RGMII \ ) /* Ethertype field values */ -- cgit v0.10.2 From 5d05a04d283061b586e8dc819cfa6f4b8cfd5948 Mon Sep 17 00:00:00 2001 From: Toshiharu Okada Date: Fri, 6 May 2011 02:53:56 +0000 Subject: PCH_GbE : Fixed the issue of checksum judgment The checksum judgment was mistaken. Judgment result 0:Correct 1:Wrong This patch fixes the issue. Signed-off-by: Toshiharu Okada Signed-off-by: David S. Miller diff --git a/drivers/net/pch_gbe/pch_gbe_main.c b/drivers/net/pch_gbe/pch_gbe_main.c index 4ebd1d4..9f6c402 100644 --- a/drivers/net/pch_gbe/pch_gbe_main.c +++ b/drivers/net/pch_gbe/pch_gbe_main.c @@ -1493,12 +1493,11 @@ pch_gbe_clean_rx(struct pch_gbe_adapter *adapter, /* Write meta date of skb */ skb_put(skb, length); skb->protocol = eth_type_trans(skb, netdev); - if ((tcp_ip_status & PCH_GBE_RXD_ACC_STAT_TCPIPOK) == - PCH_GBE_RXD_ACC_STAT_TCPIPOK) { - skb->ip_summed = CHECKSUM_UNNECESSARY; - } else { + if (tcp_ip_status & PCH_GBE_RXD_ACC_STAT_TCPIPOK) skb->ip_summed = CHECKSUM_NONE; - } + else + skb->ip_summed = CHECKSUM_UNNECESSARY; + napi_gro_receive(&adapter->napi, skb); (*work_done)++; pr_debug("Receive skb->ip_summed: %d length: %d\n", -- cgit v0.10.2 From cecb5fd7c277c1bba161980bb41792a60b56df4a Mon Sep 17 00:00:00 2001 From: Francois Romieu Date: Fri, 1 Apr 2011 10:21:07 +0200 Subject: r8169: style cleanups. Signed-off-by: Francois Romieu Cc: Realtek linux nic maintainers diff --git a/drivers/net/r8169.c b/drivers/net/r8169.c index a8976a7..c51515f 100644 --- a/drivers/net/r8169.c +++ b/drivers/net/r8169.c @@ -345,7 +345,7 @@ enum rtl8168_registers { #define OCPAR_GPHY_READ_CMD 0x0000f060 RDSAR1 = 0xd0, /* 8168c only. Undocumented on 8168dp */ MISC = 0xf0, /* 8168e only. */ - txpla_rst = (1 << 29) +#define TXPLA_RST (1 << 29) }; enum rtl_register_content { @@ -423,7 +423,7 @@ enum rtl_register_content { BWF = (1 << 6), /* Accept Broadcast wakeup frame */ MWF = (1 << 5), /* Accept Multicast wakeup frame */ UWF = (1 << 4), /* Accept Unicast wakeup frame */ - spi_en = (1 << 3), + Spi_en = (1 << 3), LanWake = (1 << 1), /* LanWake enable/disable */ PMEStatus = (1 << 0), /* PME status can be reset by PCI RST# */ @@ -594,10 +594,10 @@ struct rtl8169_counters { struct rtl8169_private { void __iomem *mmio_addr; /* memory map physical address */ - struct pci_dev *pci_dev; /* Index of PCI device */ + struct pci_dev *pci_dev; struct net_device *dev; struct napi_struct napi; - spinlock_t lock; /* spin lock flag */ + spinlock_t lock; u32 msg_enable; u16 txd_version; u16 mac_version; @@ -730,17 +730,19 @@ static void rtl8168_oob_notify(struct rtl8169_private *tp, u8 cmd) #define OOB_CMD_DRIVER_START 0x05 #define OOB_CMD_DRIVER_STOP 0x06 +static u16 rtl8168_get_ocp_reg(struct rtl8169_private *tp) +{ + return (tp->mac_version == RTL_GIGA_MAC_VER_31) ? 0xb8 : 0x10; +} + static void rtl8168_driver_start(struct rtl8169_private *tp) { + u16 reg; int i; - u32 reg; rtl8168_oob_notify(tp, OOB_CMD_DRIVER_START); - if (tp->mac_version == RTL_GIGA_MAC_VER_31) - reg = 0xb8; - else - reg = 0x10; + reg = rtl8168_get_ocp_reg(tp); for (i = 0; i < 10; i++) { msleep(10); @@ -751,15 +753,12 @@ static void rtl8168_driver_start(struct rtl8169_private *tp) static void rtl8168_driver_stop(struct rtl8169_private *tp) { + u16 reg; int i; - u32 reg; rtl8168_oob_notify(tp, OOB_CMD_DRIVER_STOP); - if (tp->mac_version == RTL_GIGA_MAC_VER_31) - reg = 0xb8; - else - reg = 0x10; + reg = rtl8168_get_ocp_reg(tp); for (i = 0; i < 10; i++) { msleep(10); @@ -770,17 +769,9 @@ static void rtl8168_driver_stop(struct rtl8169_private *tp) static int r8168dp_check_dash(struct rtl8169_private *tp) { - u32 reg; - - if (tp->mac_version == RTL_GIGA_MAC_VER_31) - reg = 0xb8; - else - reg = 0x10; + u16 reg = rtl8168_get_ocp_reg(tp); - if (ocp_read(tp, 0xF, reg) & 0x00008000) - return 1; - else - return 0; + return (ocp_read(tp, 0x0f, reg) & 0x00008000) ? 1 : 0; } static void r8169_mdio_write(void __iomem *ioaddr, int reg_addr, int value) @@ -1080,9 +1071,8 @@ static void rtl8169_xmii_reset_enable(struct rtl8169_private *tp) } static void __rtl8169_check_link_status(struct net_device *dev, - struct rtl8169_private *tp, - void __iomem *ioaddr, - bool pm) + struct rtl8169_private *tp, + void __iomem *ioaddr, bool pm) { unsigned long flags; @@ -1268,16 +1258,16 @@ static int rtl8169_set_speed_xmii(struct net_device *dev, giga_ctrl &= ~(ADVERTISE_1000FULL | ADVERTISE_1000HALF); /* The 8100e/8101e/8102e do Fast Ethernet only. */ - if ((tp->mac_version != RTL_GIGA_MAC_VER_07) && - (tp->mac_version != RTL_GIGA_MAC_VER_08) && - (tp->mac_version != RTL_GIGA_MAC_VER_09) && - (tp->mac_version != RTL_GIGA_MAC_VER_10) && - (tp->mac_version != RTL_GIGA_MAC_VER_13) && - (tp->mac_version != RTL_GIGA_MAC_VER_14) && - (tp->mac_version != RTL_GIGA_MAC_VER_15) && - (tp->mac_version != RTL_GIGA_MAC_VER_16) && - (tp->mac_version != RTL_GIGA_MAC_VER_29) && - (tp->mac_version != RTL_GIGA_MAC_VER_30)) { + if (tp->mac_version != RTL_GIGA_MAC_VER_07 && + tp->mac_version != RTL_GIGA_MAC_VER_08 && + tp->mac_version != RTL_GIGA_MAC_VER_09 && + tp->mac_version != RTL_GIGA_MAC_VER_10 && + tp->mac_version != RTL_GIGA_MAC_VER_13 && + tp->mac_version != RTL_GIGA_MAC_VER_14 && + tp->mac_version != RTL_GIGA_MAC_VER_15 && + tp->mac_version != RTL_GIGA_MAC_VER_16 && + tp->mac_version != RTL_GIGA_MAC_VER_29 && + tp->mac_version != RTL_GIGA_MAC_VER_30) { if (adv & ADVERTISED_1000baseT_Half) giga_ctrl |= ADVERTISE_1000HALF; if (adv & ADVERTISED_1000baseT_Full) @@ -1311,8 +1301,8 @@ static int rtl8169_set_speed_xmii(struct net_device *dev, rtl_writephy(tp, MII_BMCR, bmcr); - if ((tp->mac_version == RTL_GIGA_MAC_VER_02) || - (tp->mac_version == RTL_GIGA_MAC_VER_03)) { + if (tp->mac_version == RTL_GIGA_MAC_VER_02 || + tp->mac_version == RTL_GIGA_MAC_VER_03) { if ((speed == SPEED_100) && (autoneg != AUTONEG_ENABLE)) { rtl_writephy(tp, 0x17, 0x2138); rtl_writephy(tp, 0x0e, 0x0260); @@ -1348,8 +1338,7 @@ static int rtl8169_set_settings(struct net_device *dev, struct ethtool_cmd *cmd) int ret; spin_lock_irqsave(&tp->lock, flags); - ret = rtl8169_set_speed(dev, - cmd->autoneg, ethtool_cmd_speed(cmd), + ret = rtl8169_set_speed(dev, cmd->autoneg, ethtool_cmd_speed(cmd), cmd->duplex, cmd->advertising); spin_unlock_irqrestore(&tp->lock, flags); @@ -1507,11 +1496,11 @@ static void rtl8169_update_counters(struct net_device *dev) { struct rtl8169_private *tp = netdev_priv(dev); void __iomem *ioaddr = tp->mmio_addr; + struct device *d = &tp->pci_dev->dev; struct rtl8169_counters *counters; dma_addr_t paddr; u32 cmd; int wait = 1000; - struct device *d = &tp->pci_dev->dev; /* * Some chips are unable to dump tally counters when the receiver @@ -1531,7 +1520,6 @@ static void rtl8169_update_counters(struct net_device *dev) while (wait--) { if ((RTL_R32(CounterAddrLow) & CounterDump) == 0) { - /* copy updated counters */ memcpy(&tp->counters, counters, sizeof(*counters)); break; } @@ -1751,14 +1739,14 @@ rtl_phy_write_fw(struct rtl8169_private *tp, const struct firmware *fw) case PHY_BJMPN: if (regno > index) { netif_err(tp, probe, tp->dev, - "Out of range of firmware\n"); + "Out of range of firmware\n"); return; } break; case PHY_READCOUNT_EQ_SKIP: if (index + 2 >= fw_size) { netif_err(tp, probe, tp->dev, - "Out of range of firmware\n"); + "Out of range of firmware\n"); return; } break; @@ -1767,7 +1755,7 @@ rtl_phy_write_fw(struct rtl8169_private *tp, const struct firmware *fw) case PHY_SKIPN: if (index + 1 + regno >= fw_size) { netif_err(tp, probe, tp->dev, - "Out of range of firmware\n"); + "Out of range of firmware\n"); return; } break; @@ -1823,10 +1811,7 @@ rtl_phy_write_fw(struct rtl8169_private *tp, const struct firmware *fw) index++; break; case PHY_READCOUNT_EQ_SKIP: - if (count == data) - index += 2; - else - index += 1; + index += (count == data) ? 2 : 1; break; case PHY_COMP_EQ_SKIPN: if (predata == data) @@ -2237,7 +2222,7 @@ static void rtl8168d_1_hw_phy_config(struct rtl8169_private *tp) /* * Tx Error Issue - * enhance line driver power + * Enhance line driver power */ { 0x1f, 0x0002 }, { 0x06, 0x5561 }, @@ -2349,7 +2334,7 @@ static void rtl8168d_2_hw_phy_config(struct rtl8169_private *tp) /* * Tx Error Issue - * enhance line driver power + * Enhance line driver power */ { 0x1f, 0x0002 }, { 0x06, 0x5561 }, @@ -2548,7 +2533,7 @@ static void rtl8168e_hw_phy_config(struct rtl8169_private *tp) /* For impedance matching */ rtl_writephy(tp, 0x1f, 0x0002); rtl_w1w0_phy(tp, 0x08, 0x8000, 0x7f00); - rtl_writephy(tp, 0x1F, 0x0000); + rtl_writephy(tp, 0x1f, 0x0000); /* PHY auto speed down */ rtl_writephy(tp, 0x1f, 0x0007); @@ -2692,6 +2677,9 @@ static void rtl_hw_phy_config(struct net_device *dev) case RTL_GIGA_MAC_VER_30: rtl8105e_hw_phy_config(tp); break; + case RTL_GIGA_MAC_VER_31: + /* None. */ + break; case RTL_GIGA_MAC_VER_32: case RTL_GIGA_MAC_VER_33: rtl8168e_hw_phy_config(tp); @@ -2828,11 +2816,11 @@ static void rtl8169_init_phy(struct net_device *dev, struct rtl8169_private *tp) rtl8169_phy_reset(dev, tp); rtl8169_set_speed(dev, AUTONEG_ENABLE, SPEED_1000, DUPLEX_FULL, - ADVERTISED_10baseT_Half | ADVERTISED_10baseT_Full | - ADVERTISED_100baseT_Half | ADVERTISED_100baseT_Full | - (tp->mii.supports_gmii ? - ADVERTISED_1000baseT_Half | - ADVERTISED_1000baseT_Full : 0)); + ADVERTISED_10baseT_Half | ADVERTISED_10baseT_Full | + ADVERTISED_100baseT_Half | ADVERTISED_100baseT_Full | + (tp->mii.supports_gmii ? + ADVERTISED_1000baseT_Half | + ADVERTISED_1000baseT_Full : 0)); if (RTL_R8(PHYstatus) & TBI_Enable) netif_info(tp, link, dev, "TBI auto-negotiating\n"); @@ -2885,7 +2873,8 @@ static int rtl8169_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) return netif_running(dev) ? tp->do_ioctl(tp, data, cmd) : -ENODEV; } -static int rtl_xmii_ioctl(struct rtl8169_private *tp, struct mii_ioctl_data *data, int cmd) +static int rtl_xmii_ioctl(struct rtl8169_private *tp, + struct mii_ioctl_data *data, int cmd) { switch (cmd) { case SIOCGMIIPHY: @@ -3107,15 +3096,15 @@ static void r8168_pll_power_down(struct rtl8169_private *tp) { void __iomem *ioaddr = tp->mmio_addr; - if (((tp->mac_version == RTL_GIGA_MAC_VER_27) || - (tp->mac_version == RTL_GIGA_MAC_VER_28) || - (tp->mac_version == RTL_GIGA_MAC_VER_31)) && + if ((tp->mac_version == RTL_GIGA_MAC_VER_27 || + tp->mac_version == RTL_GIGA_MAC_VER_28 || + tp->mac_version == RTL_GIGA_MAC_VER_31) && r8168dp_check_dash(tp)) { return; } - if (((tp->mac_version == RTL_GIGA_MAC_VER_23) || - (tp->mac_version == RTL_GIGA_MAC_VER_24)) && + if ((tp->mac_version == RTL_GIGA_MAC_VER_23 || + tp->mac_version == RTL_GIGA_MAC_VER_24) && (RTL_R16(CPlusCmd) & ASF)) { return; } @@ -3152,9 +3141,9 @@ static void r8168_pll_power_up(struct rtl8169_private *tp) { void __iomem *ioaddr = tp->mmio_addr; - if (((tp->mac_version == RTL_GIGA_MAC_VER_27) || - (tp->mac_version == RTL_GIGA_MAC_VER_28) || - (tp->mac_version == RTL_GIGA_MAC_VER_31)) && + if ((tp->mac_version == RTL_GIGA_MAC_VER_27 || + tp->mac_version == RTL_GIGA_MAC_VER_28 || + tp->mac_version == RTL_GIGA_MAC_VER_31) && r8168dp_check_dash(tp)) { return; } @@ -3469,9 +3458,9 @@ rtl8169_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) rtl_chip_info[chipset].name, dev->base_addr, dev->dev_addr, (u32)(RTL_R32(TxConfig) & 0x9cf0f8ff), dev->irq); - if ((tp->mac_version == RTL_GIGA_MAC_VER_27) || - (tp->mac_version == RTL_GIGA_MAC_VER_28) || - (tp->mac_version == RTL_GIGA_MAC_VER_31)) { + if (tp->mac_version == RTL_GIGA_MAC_VER_27 || + tp->mac_version == RTL_GIGA_MAC_VER_28 || + tp->mac_version == RTL_GIGA_MAC_VER_31) { rtl8168_driver_start(tp); } @@ -3503,9 +3492,9 @@ static void __devexit rtl8169_remove_one(struct pci_dev *pdev) struct net_device *dev = pci_get_drvdata(pdev); struct rtl8169_private *tp = netdev_priv(dev); - if ((tp->mac_version == RTL_GIGA_MAC_VER_27) || - (tp->mac_version == RTL_GIGA_MAC_VER_28) || - (tp->mac_version == RTL_GIGA_MAC_VER_31)) { + if (tp->mac_version == RTL_GIGA_MAC_VER_27 || + tp->mac_version == RTL_GIGA_MAC_VER_28 || + tp->mac_version == RTL_GIGA_MAC_VER_31) { rtl8168_driver_stop(tp); } @@ -3753,26 +3742,26 @@ static void rtl_hw_start_8169(struct net_device *dev) } RTL_W8(Cfg9346, Cfg9346_Unlock); - if ((tp->mac_version == RTL_GIGA_MAC_VER_01) || - (tp->mac_version == RTL_GIGA_MAC_VER_02) || - (tp->mac_version == RTL_GIGA_MAC_VER_03) || - (tp->mac_version == RTL_GIGA_MAC_VER_04)) + if (tp->mac_version == RTL_GIGA_MAC_VER_01 || + tp->mac_version == RTL_GIGA_MAC_VER_02 || + tp->mac_version == RTL_GIGA_MAC_VER_03 || + tp->mac_version == RTL_GIGA_MAC_VER_04) RTL_W8(ChipCmd, CmdTxEnb | CmdRxEnb); RTL_W8(EarlyTxThres, NoEarlyTx); rtl_set_rx_max_size(ioaddr, rx_buf_sz); - if ((tp->mac_version == RTL_GIGA_MAC_VER_01) || - (tp->mac_version == RTL_GIGA_MAC_VER_02) || - (tp->mac_version == RTL_GIGA_MAC_VER_03) || - (tp->mac_version == RTL_GIGA_MAC_VER_04)) + if (tp->mac_version == RTL_GIGA_MAC_VER_01 || + tp->mac_version == RTL_GIGA_MAC_VER_02 || + tp->mac_version == RTL_GIGA_MAC_VER_03 || + tp->mac_version == RTL_GIGA_MAC_VER_04) rtl_set_rx_tx_config_registers(tp); tp->cp_cmd |= rtl_rw_cpluscmd(ioaddr) | PCIMulRW; - if ((tp->mac_version == RTL_GIGA_MAC_VER_02) || - (tp->mac_version == RTL_GIGA_MAC_VER_03)) { + if (tp->mac_version == RTL_GIGA_MAC_VER_02 || + tp->mac_version == RTL_GIGA_MAC_VER_03) { dprintk("Set MAC Reg C+CR Offset 0xE0. " "Bit-3 and bit-14 MUST be 1\n"); tp->cp_cmd |= (1 << 14); @@ -3790,10 +3779,10 @@ static void rtl_hw_start_8169(struct net_device *dev) rtl_set_rx_tx_desc_registers(tp, ioaddr); - if ((tp->mac_version != RTL_GIGA_MAC_VER_01) && - (tp->mac_version != RTL_GIGA_MAC_VER_02) && - (tp->mac_version != RTL_GIGA_MAC_VER_03) && - (tp->mac_version != RTL_GIGA_MAC_VER_04)) { + if (tp->mac_version != RTL_GIGA_MAC_VER_01 && + tp->mac_version != RTL_GIGA_MAC_VER_02 && + tp->mac_version != RTL_GIGA_MAC_VER_03 && + tp->mac_version != RTL_GIGA_MAC_VER_04) { RTL_W8(ChipCmd, CmdTxEnb | CmdRxEnb); rtl_set_rx_tx_config_registers(tp); } @@ -4103,10 +4092,10 @@ static void rtl_hw_start_8168e(void __iomem *ioaddr, struct pci_dev *pdev) rtl_disable_clock_request(pdev); /* Reset tx FIFO pointer */ - RTL_W32(MISC, RTL_R32(MISC) | txpla_rst); - RTL_W32(MISC, RTL_R32(MISC) & ~txpla_rst); + RTL_W32(MISC, RTL_R32(MISC) | TXPLA_RST); + RTL_W32(MISC, RTL_R32(MISC) & ~TXPLA_RST); - RTL_W8(Config5, RTL_R8(Config5) & ~spi_en); + RTL_W8(Config5, RTL_R8(Config5) & ~Spi_en); } static void rtl_hw_start_8168(struct net_device *dev) @@ -4190,6 +4179,7 @@ static void rtl_hw_start_8168(struct net_device *dev) case RTL_GIGA_MAC_VER_28: rtl_hw_start_8168d_4(ioaddr, pdev); break; + case RTL_GIGA_MAC_VER_31: rtl_hw_start_8168dp(ioaddr, pdev); break; @@ -4286,10 +4276,10 @@ static void rtl_hw_start_8105e_1(void __iomem *ioaddr, struct pci_dev *pdev) { 0x0a, 0, 0x0020 } }; - /* Force LAN exit from ASPM if Rx/Tx are not idel */ + /* Force LAN exit from ASPM if Rx/Tx are not idle */ RTL_W32(FuncEvent, RTL_R32(FuncEvent) | 0x002800); - /* disable Early Tally Counter */ + /* Disable Early Tally Counter */ RTL_W32(FuncEvent, RTL_R32(FuncEvent) & ~0x010000); RTL_W8(MCU, RTL_R8(MCU) | EN_NDP | EN_OOB_RESET); @@ -4310,8 +4300,8 @@ static void rtl_hw_start_8101(struct net_device *dev) void __iomem *ioaddr = tp->mmio_addr; struct pci_dev *pdev = tp->pci_dev; - if ((tp->mac_version == RTL_GIGA_MAC_VER_13) || - (tp->mac_version == RTL_GIGA_MAC_VER_16)) { + if (tp->mac_version == RTL_GIGA_MAC_VER_13 || + tp->mac_version == RTL_GIGA_MAC_VER_16) { int cap = tp->pcie_cap; if (cap) { @@ -4677,7 +4667,7 @@ static int rtl8169_xmit_frags(struct rtl8169_private *tp, struct sk_buff *skb, goto err_out; } - /* anti gcc 2.95.3 bugware (sic) */ + /* Anti gcc 2.95.3 bugware (sic) */ status = opts[0] | len | (RingEnd * !((entry + 1) % NUM_TX_DESC)); @@ -4773,7 +4763,7 @@ static netdev_tx_t rtl8169_start_xmit(struct sk_buff *skb, wmb(); - /* anti gcc 2.95.3 bugware (sic) */ + /* Anti gcc 2.95.3 bugware (sic) */ status = opts[0] | len | (RingEnd * !((entry + 1) % NUM_TX_DESC)); txd->opts1 = cpu_to_le32(status); @@ -4781,7 +4771,7 @@ static netdev_tx_t rtl8169_start_xmit(struct sk_buff *skb, wmb(); - RTL_W8(TxPoll, NPQ); /* set polling bit */ + RTL_W8(TxPoll, NPQ); if (TX_BUFFS_AVAIL(tp) < MAX_SKB_FRAGS) { netif_stop_queue(dev); @@ -5207,7 +5197,7 @@ static int rtl8169_close(struct net_device *dev) pm_runtime_get_sync(&pdev->dev); - /* update counters before going down */ + /* Update counters before going down */ rtl8169_update_counters(dev); rtl8169_down(dev); @@ -5400,15 +5390,15 @@ static int rtl8169_runtime_idle(struct device *device) } static const struct dev_pm_ops rtl8169_pm_ops = { - .suspend = rtl8169_suspend, - .resume = rtl8169_resume, - .freeze = rtl8169_suspend, - .thaw = rtl8169_resume, - .poweroff = rtl8169_suspend, - .restore = rtl8169_resume, - .runtime_suspend = rtl8169_runtime_suspend, - .runtime_resume = rtl8169_runtime_resume, - .runtime_idle = rtl8169_runtime_idle, + .suspend = rtl8169_suspend, + .resume = rtl8169_resume, + .freeze = rtl8169_suspend, + .thaw = rtl8169_resume, + .poweroff = rtl8169_suspend, + .restore = rtl8169_resume, + .runtime_suspend = rtl8169_runtime_suspend, + .runtime_resume = rtl8169_runtime_resume, + .runtime_idle = rtl8169_runtime_idle, }; #define RTL8169_PM_OPS (&rtl8169_pm_ops) @@ -5427,7 +5417,7 @@ static void rtl_shutdown(struct pci_dev *pdev) rtl8169_net_suspend(dev); - /* restore original MAC address */ + /* Restore original MAC address */ rtl_rar_set(tp, dev->perm_addr); spin_lock_irq(&tp->lock); -- cgit v0.10.2 From 6f43adc88f49cb8164fbd665e968de4de380dc35 Mon Sep 17 00:00:00 2001 From: Francois Romieu Date: Fri, 29 Apr 2011 15:05:51 +0200 Subject: r8169: remove some code duplication. Signed-off-by: Francois Romieu Cc: Realtek linux nic maintainers diff --git a/drivers/net/r8169.c b/drivers/net/r8169.c index c51515f..976bb31 100644 --- a/drivers/net/r8169.c +++ b/drivers/net/r8169.c @@ -3224,6 +3224,22 @@ static void __devinit rtl_init_pll_power_ops(struct rtl8169_private *tp) } } +static void rtl_hw_reset(struct rtl8169_private *tp) +{ + void __iomem *ioaddr = tp->mmio_addr; + int i; + + /* Soft reset the chip. */ + RTL_W8(ChipCmd, CmdReset); + + /* Check that the chip has finished the reset. */ + for (i = 0; i < 100; i++) { + if ((RTL_R8(ChipCmd) & CmdReset) == 0) + break; + msleep_interruptible(1); + } +} + static int __devinit rtl8169_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) { @@ -3323,6 +3339,7 @@ rtl8169_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) rc = -EIO; goto err_out_free_res_3; } + tp->mmio_addr = ioaddr; tp->pcie_cap = pci_find_capability(pdev, PCI_CAP_ID_EXP); if (!tp->pcie_cap) @@ -3330,15 +3347,7 @@ rtl8169_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) RTL_W16(IntrMask, 0x0000); - /* Soft reset the chip. */ - RTL_W8(ChipCmd, CmdReset); - - /* Check that the chip has finished the reset. */ - for (i = 0; i < 100; i++) { - if ((RTL_R8(ChipCmd) & CmdReset) == 0) - break; - msleep_interruptible(1); - } + rtl_hw_reset(tp); RTL_W16(IntrStatus, 0xffff); @@ -3409,8 +3418,6 @@ rtl8169_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) spin_lock_init(&tp->lock); - tp->mmio_addr = ioaddr; - /* Get MAC address */ for (i = 0; i < MAC_ADDR_LEN; i++) dev->dev_addr[i] = RTL_R8(MAC0 + i); @@ -3658,25 +3665,14 @@ static void rtl_set_rx_tx_config_registers(struct rtl8169_private *tp) static void rtl_hw_start(struct net_device *dev) { struct rtl8169_private *tp = netdev_priv(dev); - void __iomem *ioaddr = tp->mmio_addr; - unsigned int i; - /* Soft reset the chip. */ - RTL_W8(ChipCmd, CmdReset); - - /* Check that the chip has finished the reset. */ - for (i = 0; i < 100; i++) { - if ((RTL_R8(ChipCmd) & CmdReset) == 0) - break; - msleep_interruptible(1); - } + rtl_hw_reset(tp); tp->hw_start(dev); netif_start_queue(dev); } - static void rtl_set_rx_tx_desc_registers(struct rtl8169_private *tp, void __iomem *ioaddr) { -- cgit v0.10.2 From 826e6cbdadfa51495c7189641df2514cc48e23da Mon Sep 17 00:00:00 2001 From: Francois Romieu Date: Fri, 11 Mar 2011 20:30:24 +0100 Subject: r8169: rtl8169_set_speed_xmii cleanup. Shorten chipset version test. No functional change. Careful readers will notice that the 'supports_gmii' flag is deduced from the device PCI id. Though less specific than the chipset related RTL_GIGA_MAC_VER_XY, it is good enough to detect a GMII deprieved 810x. Some features push for a device specific configuration (improved jumbo frame support for instance). 'supports_gmii' will follow this path if / when the device PCI id test stops working. Signed-off-by: Francois Romieu Cc: Realtek linux nic maintainers diff --git a/drivers/net/r8169.c b/drivers/net/r8169.c index 976bb31..182c794 100644 --- a/drivers/net/r8169.c +++ b/drivers/net/r8169.c @@ -1258,16 +1258,7 @@ static int rtl8169_set_speed_xmii(struct net_device *dev, giga_ctrl &= ~(ADVERTISE_1000FULL | ADVERTISE_1000HALF); /* The 8100e/8101e/8102e do Fast Ethernet only. */ - if (tp->mac_version != RTL_GIGA_MAC_VER_07 && - tp->mac_version != RTL_GIGA_MAC_VER_08 && - tp->mac_version != RTL_GIGA_MAC_VER_09 && - tp->mac_version != RTL_GIGA_MAC_VER_10 && - tp->mac_version != RTL_GIGA_MAC_VER_13 && - tp->mac_version != RTL_GIGA_MAC_VER_14 && - tp->mac_version != RTL_GIGA_MAC_VER_15 && - tp->mac_version != RTL_GIGA_MAC_VER_16 && - tp->mac_version != RTL_GIGA_MAC_VER_29 && - tp->mac_version != RTL_GIGA_MAC_VER_30) { + if (tp->mii.supports_gmii) { if (adv & ADVERTISED_1000baseT_Half) giga_ctrl |= ADVERTISE_1000HALF; if (adv & ADVERTISED_1000baseT_Full) -- cgit v0.10.2 From 4876cc1e49efac03827a51a2422cfbbb7f6335de Mon Sep 17 00:00:00 2001 From: Francois Romieu Date: Fri, 11 Mar 2011 21:07:11 +0100 Subject: r8169: link speed selection timer rework. The implementation was a bit krusty. The 10s rtl8169_phy_timer timer has been (was ?) required with older 8169 for adequate phy operation when full gigabit is advertised in autonegotiated mode. The timer does nothing if the link is up. Otherwise it keeps resetting the phy until things improve. - the device private data field phy_1000_ctrl_reg was used to schedule the timer. Avoid it and save a few bytes. - rtl8169_set_settings pending timer is disabled before changing the link settings as rtl8169_phy_timer is not always needed (see the removed test in rtl8169_phy_timer). - rtl8169_set_speed the requested link parameters may not match the chipset : bail out early on failure. - rtl8169_open Calling rtl8169_request_timer is redundant with -> rtl8169_open -> rtl8169_init_phy -> rtl8169_set_speed -> mod_timer The latter always enables the phy timer whereas the former did not for RTL_GIGA_MAC_VER_01. It should not make things worse but only time will tell if reality agrees. - rtl8169_request_timer : unused yet. Removed. - rtl8169_delete_timer : useless. Bloat. Removed. Side effect : the timer may kick in if the TBI is enabled. I do not know if the TBI has ever been used in real life. Signed-off-by: Francois Romieu Cc: Realtek linux nic maintainers diff --git a/drivers/net/r8169.c b/drivers/net/r8169.c index 182c794..b3cf1d2 100644 --- a/drivers/net/r8169.c +++ b/drivers/net/r8169.c @@ -616,7 +616,6 @@ struct rtl8169_private { u16 intr_event; u16 napi_event; u16 intr_mask; - int phy_1000_ctrl_reg; struct mdio_ops { void (*write)(void __iomem *, int, int); @@ -1288,8 +1287,6 @@ static int rtl8169_set_speed_xmii(struct net_device *dev, bmcr |= BMCR_FULLDPLX; } - tp->phy_1000_ctrl_reg = giga_ctrl; - rtl_writephy(tp, MII_BMCR, bmcr); if (tp->mac_version == RTL_GIGA_MAC_VER_02 || @@ -1315,10 +1312,14 @@ static int rtl8169_set_speed(struct net_device *dev, int ret; ret = tp->set_speed(dev, autoneg, speed, duplex, advertising); + if (ret < 0) + goto out; - if (netif_running(dev) && (tp->phy_1000_ctrl_reg & ADVERTISE_1000FULL)) + if (netif_running(dev) && (autoneg == AUTONEG_ENABLE) && + (advertising & ADVERTISED_1000baseT_Full)) { mod_timer(&tp->timer, jiffies + RTL8169_PHY_TIMEOUT); - + } +out: return ret; } @@ -1328,6 +1329,8 @@ static int rtl8169_set_settings(struct net_device *dev, struct ethtool_cmd *cmd) unsigned long flags; int ret; + del_timer_sync(&tp->timer); + spin_lock_irqsave(&tp->lock, flags); ret = rtl8169_set_speed(dev, cmd->autoneg, ethtool_cmd_speed(cmd), cmd->duplex, cmd->advertising); @@ -2691,9 +2694,6 @@ static void rtl8169_phy_timer(unsigned long __opaque) assert(tp->mac_version > RTL_GIGA_MAC_VER_01); - if (!(tp->phy_1000_ctrl_reg & ADVERTISE_1000FULL)) - return; - spin_lock_irq(&tp->lock); if (tp->phy_reset_pending(tp)) { @@ -2718,28 +2718,6 @@ out_unlock: spin_unlock_irq(&tp->lock); } -static inline void rtl8169_delete_timer(struct net_device *dev) -{ - struct rtl8169_private *tp = netdev_priv(dev); - struct timer_list *timer = &tp->timer; - - if (tp->mac_version <= RTL_GIGA_MAC_VER_01) - return; - - del_timer_sync(timer); -} - -static inline void rtl8169_request_timer(struct net_device *dev) -{ - struct rtl8169_private *tp = netdev_priv(dev); - struct timer_list *timer = &tp->timer; - - if (tp->mac_version <= RTL_GIGA_MAC_VER_01) - return; - - mod_timer(timer, jiffies + RTL8169_PHY_TIMEOUT); -} - #ifdef CONFIG_NET_POLL_CONTROLLER /* * Polling 'interrupt' - used by things like netconsole to send skbs @@ -3396,8 +3374,6 @@ rtl8169_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) tp->phy_reset_pending = rtl8169_tbi_reset_pending; tp->link_ok = rtl8169_tbi_link_ok; tp->do_ioctl = rtl_tbi_ioctl; - - tp->phy_1000_ctrl_reg = ADVERTISE_1000FULL; /* Implied by TBI */ } else { tp->set_speed = rtl8169_set_speed_xmii; tp->get_settings = rtl8169_gset_xmii; @@ -3593,8 +3569,6 @@ static int rtl8169_open(struct net_device *dev) rtl_hw_start(dev); - rtl8169_request_timer(dev); - tp->saved_wolopts = 0; pm_runtime_put_noidle(&pdev->dev); @@ -5147,7 +5121,7 @@ static void rtl8169_down(struct net_device *dev) struct rtl8169_private *tp = netdev_priv(dev); void __iomem *ioaddr = tp->mmio_addr; - rtl8169_delete_timer(dev); + del_timer_sync(&tp->timer); netif_stop_queue(dev); -- cgit v0.10.2 From 56de414c0c7333f1e1adedc23057e131ce84233e Mon Sep 17 00:00:00 2001 From: Francois Romieu Date: Tue, 15 Mar 2011 17:29:31 +0100 Subject: r8169: remove non-NAPI context invocation of rtl8169_rx_interrupt. Invocation of rtl8169_rx_interrupt from rtl8169_reset_task was originally intended to retrieve as much packets as possible from the rx ring when a reset was needed. Nowadays rtl8169_reset_task is only scheduled, with some delay a. from the tx timeout watchdog b. when resuming c. from rtl8169_rx_interrupt itself It's dubious that the loss of outdated packets will matter much for a) and b). c) does not need to call itself again. Signed-off-by: Francois Romieu Cc: Realtek linux nic maintainers diff --git a/drivers/net/r8169.c b/drivers/net/r8169.c index b3cf1d2..81906bc 100644 --- a/drivers/net/r8169.c +++ b/drivers/net/r8169.c @@ -4564,6 +4564,7 @@ static void rtl8169_reset_task(struct work_struct *work) struct rtl8169_private *tp = container_of(work, struct rtl8169_private, task.work); struct net_device *dev = tp->dev; + int i; rtnl_lock(); @@ -4572,19 +4573,15 @@ static void rtl8169_reset_task(struct work_struct *work) rtl8169_wait_for_quiescence(dev); - rtl8169_rx_interrupt(dev, tp, tp->mmio_addr, ~(u32)0); + for (i = 0; i < NUM_RX_DESC; i++) + rtl8169_mark_to_asic(tp->RxDescArray + i, rx_buf_sz); + rtl8169_tx_clear(tp); - if (tp->dirty_rx == tp->cur_rx) { - rtl8169_init_ring_indexes(tp); - rtl_hw_start(dev); - netif_wake_queue(dev); - rtl8169_check_link_status(dev, tp, tp->mmio_addr); - } else { - if (net_ratelimit()) - netif_emerg(tp, intr, dev, "Rx buffers shortage\n"); - rtl8169_schedule_work(dev, rtl8169_reset_task); - } + rtl8169_init_ring_indexes(tp); + rtl_hw_start(dev); + netif_wake_queue(dev); + rtl8169_check_link_status(dev, tp, tp->mmio_addr); out_unlock: rtnl_unlock(); @@ -4889,20 +4886,12 @@ static struct sk_buff *rtl8169_try_rx_copy(void *data, return skb; } -/* - * Warning : rtl8169_rx_interrupt() might be called : - * 1) from NAPI (softirq) context - * (polling = 1 : we should call netif_receive_skb()) - * 2) from process context (rtl8169_reset_task()) - * (polling = 0 : we must call netif_rx() instead) - */ static int rtl8169_rx_interrupt(struct net_device *dev, struct rtl8169_private *tp, void __iomem *ioaddr, u32 budget) { unsigned int cur_rx, rx_left; unsigned int count; - int polling = (budget != ~(u32)0) ? 1 : 0; cur_rx = tp->cur_rx; rx_left = NUM_RX_DESC + tp->dirty_rx - cur_rx; @@ -4962,10 +4951,7 @@ static int rtl8169_rx_interrupt(struct net_device *dev, rtl8169_rx_vlan_tag(desc, skb); - if (likely(polling)) - napi_gro_receive(&tp->napi, skb); - else - netif_rx(skb); + napi_gro_receive(&tp->napi, skb); dev->stats.rx_bytes += pkt_size; dev->stats.rx_packets++; -- cgit v0.10.2 From 31bd204f97e3796c5cfcfc582a93a10e45b99946 Mon Sep 17 00:00:00 2001 From: Francois Romieu Date: Tue, 26 Apr 2011 18:58:59 +0200 Subject: r8169: provide some firmware information via ethtool. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit There is no real firmware version yet but the manpage of ethtool is rather terse about the driver information. Former output: $ ethtool -i eth1 driver: r8169 version: 2.3LK-NAPI firmware-version: bus-info: 0000:01:00.0 $ ethtool -i eth0 driver: r8169 version: 2.3LK-NAPI firmware-version: bus-info: 0000:03:00.0 Current output: $ ethtool -i eth1 driver: r8169 version: 2.3LK-NAPI firmware-version: N/A bus-info: 0000:01:00.0 $ ethtool -i eth0 driver: r8169 version: 2.3LK-NAPI firmware-version: rtl_nic/rtl8168d-1.fw bus-info: 0000:03:00.0 Signed-off-by: Francois Romieu Fixed-by Ciprian Docan Cc: Realtek linux nic maintainers Cc: Fejes József Cc: Borislav Petkov diff --git a/drivers/net/r8169.c b/drivers/net/r8169.c index 81906bc..83e5202 100644 --- a/drivers/net/r8169.c +++ b/drivers/net/r8169.c @@ -1188,6 +1188,19 @@ static int rtl8169_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol) return 0; } +static const char *rtl_lookup_firmware_name(struct rtl8169_private *tp) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(rtl_firmware_infos); i++) { + const struct rtl_firmware_info *info = rtl_firmware_infos + i; + + if (info->mac_version == tp->mac_version) + return info->fw_name; + } + return NULL; +} + static void rtl8169_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info) { @@ -1196,6 +1209,8 @@ static void rtl8169_get_drvinfo(struct net_device *dev, strcpy(info->driver, MODULENAME); strcpy(info->version, RTL8169_VERSION); strcpy(info->bus_info, pci_name(tp->pci_dev)); + strncpy(info->fw_version, IS_ERR_OR_NULL(tp->fw) ? "N/A" : + rtl_lookup_firmware_name(tp), sizeof(info->fw_version) - 1); } static int rtl8169_get_regs_len(struct net_device *dev) @@ -3491,33 +3506,23 @@ static void __devexit rtl8169_remove_one(struct pci_dev *pdev) static void rtl_request_firmware(struct rtl8169_private *tp) { - int i; - /* Return early if the firmware is already loaded / cached. */ - if (!IS_ERR(tp->fw)) - goto out; - - for (i = 0; i < ARRAY_SIZE(rtl_firmware_infos); i++) { - const struct rtl_firmware_info *info = rtl_firmware_infos + i; + if (IS_ERR(tp->fw)) { + const char *name; - if (info->mac_version == tp->mac_version) { - const char *name = info->fw_name; + name = rtl_lookup_firmware_name(tp); + if (name) { int rc; rc = request_firmware(&tp->fw, name, &tp->pci_dev->dev); - if (rc < 0) { - netif_warn(tp, ifup, tp->dev, "unable to load " - "firmware patch %s (%d)\n", name, rc); - goto out_disable_request_firmware; - } - goto out; + if (rc >= 0) + return; + + netif_warn(tp, ifup, tp->dev, "unable to load " + "firmware patch %s (%d)\n", name, rc); } + tp->fw = NULL; } - -out_disable_request_firmware: - tp->fw = NULL; -out: - return; } static int rtl8169_open(struct net_device *dev) -- cgit v0.10.2 From 85bffe6ca2e2d7e9510c115aa4f11c3d4209051f Mon Sep 17 00:00:00 2001 From: Francois Romieu Date: Wed, 27 Apr 2011 08:22:39 +0200 Subject: r8169: merge firmware information into the chipset description data. - RTL_GIGA_MAC_NONE is a fake index so put it at the end of the enumeration and shift everybody. - RTL_GIGA_MAC_VER_17 / RTL_GIGA_MAC_VER_16 ordering fixed. Though not wrong it was confusing enough to wonder if things were right. Renaming rtl_chip_info was not strictly necessary. It allows to check the patch for the correct use of the indexes though. Signed-off-by: Francois Romieu Cc: Realtek linux nic maintainers diff --git a/drivers/net/r8169.c b/drivers/net/r8169.c index 83e5202..4f1d45b 100644 --- a/drivers/net/r8169.c +++ b/drivers/net/r8169.c @@ -98,40 +98,40 @@ static const int multicast_filter_limit = 32; #define RTL_R32(reg) readl (ioaddr + (reg)) enum mac_version { - RTL_GIGA_MAC_NONE = 0x00, - RTL_GIGA_MAC_VER_01 = 0x01, // 8169 - RTL_GIGA_MAC_VER_02 = 0x02, // 8169S - RTL_GIGA_MAC_VER_03 = 0x03, // 8110S - RTL_GIGA_MAC_VER_04 = 0x04, // 8169SB - RTL_GIGA_MAC_VER_05 = 0x05, // 8110SCd - RTL_GIGA_MAC_VER_06 = 0x06, // 8110SCe - RTL_GIGA_MAC_VER_07 = 0x07, // 8102e - RTL_GIGA_MAC_VER_08 = 0x08, // 8102e - RTL_GIGA_MAC_VER_09 = 0x09, // 8102e - RTL_GIGA_MAC_VER_10 = 0x0a, // 8101e - RTL_GIGA_MAC_VER_11 = 0x0b, // 8168Bb - RTL_GIGA_MAC_VER_12 = 0x0c, // 8168Be - RTL_GIGA_MAC_VER_13 = 0x0d, // 8101Eb - RTL_GIGA_MAC_VER_14 = 0x0e, // 8101 ? - RTL_GIGA_MAC_VER_15 = 0x0f, // 8101 ? - RTL_GIGA_MAC_VER_16 = 0x11, // 8101Ec - RTL_GIGA_MAC_VER_17 = 0x10, // 8168Bf - RTL_GIGA_MAC_VER_18 = 0x12, // 8168CP - RTL_GIGA_MAC_VER_19 = 0x13, // 8168C - RTL_GIGA_MAC_VER_20 = 0x14, // 8168C - RTL_GIGA_MAC_VER_21 = 0x15, // 8168C - RTL_GIGA_MAC_VER_22 = 0x16, // 8168C - RTL_GIGA_MAC_VER_23 = 0x17, // 8168CP - RTL_GIGA_MAC_VER_24 = 0x18, // 8168CP - RTL_GIGA_MAC_VER_25 = 0x19, // 8168D - RTL_GIGA_MAC_VER_26 = 0x1a, // 8168D - RTL_GIGA_MAC_VER_27 = 0x1b, // 8168DP - RTL_GIGA_MAC_VER_28 = 0x1c, // 8168DP - RTL_GIGA_MAC_VER_29 = 0x1d, // 8105E - RTL_GIGA_MAC_VER_30 = 0x1e, // 8105E - RTL_GIGA_MAC_VER_31 = 0x1f, // 8168DP - RTL_GIGA_MAC_VER_32 = 0x20, // 8168E - RTL_GIGA_MAC_VER_33 = 0x21, // 8168E + RTL_GIGA_MAC_VER_01 = 0, + RTL_GIGA_MAC_VER_02, + RTL_GIGA_MAC_VER_03, + RTL_GIGA_MAC_VER_04, + RTL_GIGA_MAC_VER_05, + RTL_GIGA_MAC_VER_06, + RTL_GIGA_MAC_VER_07, + RTL_GIGA_MAC_VER_08, + RTL_GIGA_MAC_VER_09, + RTL_GIGA_MAC_VER_10, + RTL_GIGA_MAC_VER_11, + RTL_GIGA_MAC_VER_12, + RTL_GIGA_MAC_VER_13, + RTL_GIGA_MAC_VER_14, + RTL_GIGA_MAC_VER_15, + RTL_GIGA_MAC_VER_16, + RTL_GIGA_MAC_VER_17, + RTL_GIGA_MAC_VER_18, + RTL_GIGA_MAC_VER_19, + RTL_GIGA_MAC_VER_20, + RTL_GIGA_MAC_VER_21, + RTL_GIGA_MAC_VER_22, + RTL_GIGA_MAC_VER_23, + RTL_GIGA_MAC_VER_24, + RTL_GIGA_MAC_VER_25, + RTL_GIGA_MAC_VER_26, + RTL_GIGA_MAC_VER_27, + RTL_GIGA_MAC_VER_28, + RTL_GIGA_MAC_VER_29, + RTL_GIGA_MAC_VER_30, + RTL_GIGA_MAC_VER_31, + RTL_GIGA_MAC_VER_32, + RTL_GIGA_MAC_VER_33, + RTL_GIGA_MAC_NONE = 0xff, }; enum rtl_tx_desc_version { @@ -139,61 +139,84 @@ enum rtl_tx_desc_version { RTL_TD_1 = 1, }; -#define _R(NAME,MAC,TD) \ - { .name = NAME, .mac_version = MAC, .txd_version = TD } +#define _R(NAME,TD,FW) \ + { .name = NAME, .txd_version = TD, .fw_name = FW } static const struct { const char *name; - u8 mac_version; enum rtl_tx_desc_version txd_version; -} rtl_chip_info[] = { - _R("RTL8169", RTL_GIGA_MAC_VER_01, RTL_TD_0), // 8169 - _R("RTL8169s", RTL_GIGA_MAC_VER_02, RTL_TD_0), // 8169S - _R("RTL8110s", RTL_GIGA_MAC_VER_03, RTL_TD_0), // 8110S - _R("RTL8169sb/8110sb", RTL_GIGA_MAC_VER_04, RTL_TD_0), // 8169SB - _R("RTL8169sc/8110sc", RTL_GIGA_MAC_VER_05, RTL_TD_0), // 8110SCd - _R("RTL8169sc/8110sc", RTL_GIGA_MAC_VER_06, RTL_TD_0), // 8110SCe - _R("RTL8102e", RTL_GIGA_MAC_VER_07, RTL_TD_1), // PCI-E - _R("RTL8102e", RTL_GIGA_MAC_VER_08, RTL_TD_1), // PCI-E - _R("RTL8102e", RTL_GIGA_MAC_VER_09, RTL_TD_1), // PCI-E - _R("RTL8101e", RTL_GIGA_MAC_VER_10, RTL_TD_0), // PCI-E - _R("RTL8168b/8111b", RTL_GIGA_MAC_VER_11, RTL_TD_0), // PCI-E - _R("RTL8168b/8111b", RTL_GIGA_MAC_VER_12, RTL_TD_0), // PCI-E - _R("RTL8101e", RTL_GIGA_MAC_VER_13, RTL_TD_0), // PCI-E 8139 - _R("RTL8100e", RTL_GIGA_MAC_VER_14, RTL_TD_0), // PCI-E 8139 - _R("RTL8100e", RTL_GIGA_MAC_VER_15, RTL_TD_0), // PCI-E 8139 - _R("RTL8168b/8111b", RTL_GIGA_MAC_VER_17, RTL_TD_0), // PCI-E - _R("RTL8101e", RTL_GIGA_MAC_VER_16, RTL_TD_0), // PCI-E - _R("RTL8168cp/8111cp", RTL_GIGA_MAC_VER_18, RTL_TD_1), // PCI-E - _R("RTL8168c/8111c", RTL_GIGA_MAC_VER_19, RTL_TD_1), // PCI-E - _R("RTL8168c/8111c", RTL_GIGA_MAC_VER_20, RTL_TD_1), // PCI-E - _R("RTL8168c/8111c", RTL_GIGA_MAC_VER_21, RTL_TD_1), // PCI-E - _R("RTL8168c/8111c", RTL_GIGA_MAC_VER_22, RTL_TD_1), // PCI-E - _R("RTL8168cp/8111cp", RTL_GIGA_MAC_VER_23, RTL_TD_1), // PCI-E - _R("RTL8168cp/8111cp", RTL_GIGA_MAC_VER_24, RTL_TD_1), // PCI-E - _R("RTL8168d/8111d", RTL_GIGA_MAC_VER_25, RTL_TD_1), // PCI-E - _R("RTL8168d/8111d", RTL_GIGA_MAC_VER_26, RTL_TD_1), // PCI-E - _R("RTL8168dp/8111dp", RTL_GIGA_MAC_VER_27, RTL_TD_1), // PCI-E - _R("RTL8168dp/8111dp", RTL_GIGA_MAC_VER_28, RTL_TD_1), // PCI-E - _R("RTL8105e", RTL_GIGA_MAC_VER_29, RTL_TD_1), // PCI-E - _R("RTL8105e", RTL_GIGA_MAC_VER_30, RTL_TD_1), // PCI-E - _R("RTL8168dp/8111dp", RTL_GIGA_MAC_VER_31, RTL_TD_1), // PCI-E - _R("RTL8168e/8111e", RTL_GIGA_MAC_VER_32, RTL_TD_1), // PCI-E - _R("RTL8168e/8111e", RTL_GIGA_MAC_VER_33, RTL_TD_1) // PCI-E -}; -#undef _R - -static const struct rtl_firmware_info { - int mac_version; const char *fw_name; -} rtl_firmware_infos[] = { - { .mac_version = RTL_GIGA_MAC_VER_25, .fw_name = FIRMWARE_8168D_1 }, - { .mac_version = RTL_GIGA_MAC_VER_26, .fw_name = FIRMWARE_8168D_2 }, - { .mac_version = RTL_GIGA_MAC_VER_29, .fw_name = FIRMWARE_8105E_1 }, - { .mac_version = RTL_GIGA_MAC_VER_30, .fw_name = FIRMWARE_8105E_1 }, - { .mac_version = RTL_GIGA_MAC_VER_32, .fw_name = FIRMWARE_8168E_1 }, - { .mac_version = RTL_GIGA_MAC_VER_33, .fw_name = FIRMWARE_8168E_2 } +} rtl_chip_infos[] = { + /* PCI devices. */ + [RTL_GIGA_MAC_VER_01] = + _R("RTL8169", RTL_TD_0, NULL), + [RTL_GIGA_MAC_VER_02] = + _R("RTL8169s", RTL_TD_0, NULL), + [RTL_GIGA_MAC_VER_03] = + _R("RTL8110s", RTL_TD_0, NULL), + [RTL_GIGA_MAC_VER_04] = + _R("RTL8169sb/8110sb", RTL_TD_0, NULL), + [RTL_GIGA_MAC_VER_05] = + _R("RTL8169sc/8110sc", RTL_TD_0, NULL), + [RTL_GIGA_MAC_VER_06] = + _R("RTL8169sc/8110sc", RTL_TD_0, NULL), + /* PCI-E devices. */ + [RTL_GIGA_MAC_VER_07] = + _R("RTL8102e", RTL_TD_1, NULL), + [RTL_GIGA_MAC_VER_08] = + _R("RTL8102e", RTL_TD_1, NULL), + [RTL_GIGA_MAC_VER_09] = + _R("RTL8102e", RTL_TD_1, NULL), + [RTL_GIGA_MAC_VER_10] = + _R("RTL8101e", RTL_TD_0, NULL), + [RTL_GIGA_MAC_VER_11] = + _R("RTL8168b/8111b", RTL_TD_0, NULL), + [RTL_GIGA_MAC_VER_12] = + _R("RTL8168b/8111b", RTL_TD_0, NULL), + [RTL_GIGA_MAC_VER_13] = + _R("RTL8101e", RTL_TD_0, NULL), + [RTL_GIGA_MAC_VER_14] = + _R("RTL8100e", RTL_TD_0, NULL), + [RTL_GIGA_MAC_VER_15] = + _R("RTL8100e", RTL_TD_0, NULL), + [RTL_GIGA_MAC_VER_16] = + _R("RTL8101e", RTL_TD_0, NULL), + [RTL_GIGA_MAC_VER_17] = + _R("RTL8168b/8111b", RTL_TD_0, NULL), + [RTL_GIGA_MAC_VER_18] = + _R("RTL8168cp/8111cp", RTL_TD_1, NULL), + [RTL_GIGA_MAC_VER_19] = + _R("RTL8168c/8111c", RTL_TD_1, NULL), + [RTL_GIGA_MAC_VER_20] = + _R("RTL8168c/8111c", RTL_TD_1, NULL), + [RTL_GIGA_MAC_VER_21] = + _R("RTL8168c/8111c", RTL_TD_1, NULL), + [RTL_GIGA_MAC_VER_22] = + _R("RTL8168c/8111c", RTL_TD_1, NULL), + [RTL_GIGA_MAC_VER_23] = + _R("RTL8168cp/8111cp", RTL_TD_1, NULL), + [RTL_GIGA_MAC_VER_24] = + _R("RTL8168cp/8111cp", RTL_TD_1, NULL), + [RTL_GIGA_MAC_VER_25] = + _R("RTL8168d/8111d", RTL_TD_1, FIRMWARE_8168D_1), + [RTL_GIGA_MAC_VER_26] = + _R("RTL8168d/8111d", RTL_TD_1, FIRMWARE_8168D_2), + [RTL_GIGA_MAC_VER_27] = + _R("RTL8168dp/8111dp", RTL_TD_1, NULL), + [RTL_GIGA_MAC_VER_28] = + _R("RTL8168dp/8111dp", RTL_TD_1, NULL), + [RTL_GIGA_MAC_VER_29] = + _R("RTL8105e", RTL_TD_1, FIRMWARE_8105E_1), + [RTL_GIGA_MAC_VER_30] = + _R("RTL8105e", RTL_TD_1, FIRMWARE_8105E_1), + [RTL_GIGA_MAC_VER_31] = + _R("RTL8168dp/8111dp", RTL_TD_1, NULL), + [RTL_GIGA_MAC_VER_32] = + _R("RTL8168e/8111e", RTL_TD_1, FIRMWARE_8168E_1), + [RTL_GIGA_MAC_VER_33] = + _R("RTL8168e/8111e", RTL_TD_1, FIRMWARE_8168E_2) }; +#undef _R enum cfg_version { RTL_CFG_0 = 0x00, @@ -1190,15 +1213,7 @@ static int rtl8169_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol) static const char *rtl_lookup_firmware_name(struct rtl8169_private *tp) { - int i; - - for (i = 0; i < ARRAY_SIZE(rtl_firmware_infos); i++) { - const struct rtl_firmware_info *info = rtl_firmware_infos + i; - - if (info->mac_version == tp->mac_version) - return info->fw_name; - } - return NULL; + return rtl_chip_infos[tp->mac_version].fw_name; } static void rtl8169_get_drvinfo(struct net_device *dev, @@ -3359,17 +3374,8 @@ rtl8169_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) rtl8169_print_mac_version(tp); - for (i = 0; i < ARRAY_SIZE(rtl_chip_info); i++) { - if (tp->mac_version == rtl_chip_info[i].mac_version) - break; - } - if (i == ARRAY_SIZE(rtl_chip_info)) { - dev_err(&pdev->dev, - "driver bug, MAC version not found in rtl_chip_info\n"); - goto err_out_msi_4; - } - chipset = i; - tp->txd_version = rtl_chip_info[chipset].txd_version; + chipset = tp->mac_version; + tp->txd_version = rtl_chip_infos[chipset].txd_version; RTL_W8(Cfg9346, Cfg9346_Unlock); RTL_W8(Config1, RTL_R8(Config1) | PMEnable); @@ -3444,7 +3450,7 @@ rtl8169_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) pci_set_drvdata(pdev, dev); netif_info(tp, probe, dev, "%s at 0x%lx, %pM, XID %08x IRQ %d\n", - rtl_chip_info[chipset].name, dev->base_addr, dev->dev_addr, + rtl_chip_infos[chipset].name, dev->base_addr, dev->dev_addr, (u32)(RTL_R32(TxConfig) & 0x9cf0f8ff), dev->irq); if (tp->mac_version == RTL_GIGA_MAC_VER_27 || -- cgit v0.10.2 From 5d320a205de277774962782a4b1923e4f8cdf781 Mon Sep 17 00:00:00 2001 From: Francois Romieu Date: Sun, 8 May 2011 17:47:36 +0200 Subject: r8169: avoid late chip identifier initialisation. Unknown 8168 chips did not have any PLL power method set as they did not inherit a default family soon enough. Fix it. Signed-off-by: Francois Romieu Cc: Realtek linux nic maintainers diff --git a/drivers/net/r8169.c b/drivers/net/r8169.c index 4f1d45b..04f4e60 100644 --- a/drivers/net/r8169.c +++ b/drivers/net/r8169.c @@ -1606,8 +1606,9 @@ static const struct ethtool_ops rtl8169_ethtool_ops = { }; static void rtl8169_get_mac_version(struct rtl8169_private *tp, - void __iomem *ioaddr) + struct net_device *dev, u8 default_version) { + void __iomem *ioaddr = tp->mmio_addr; /* * The driver currently handles the 8168Bf and the 8168Be identically * but they can be identified more specifically through the test below @@ -1694,6 +1695,12 @@ static void rtl8169_get_mac_version(struct rtl8169_private *tp, while ((reg & p->mask) != p->val) p++; tp->mac_version = p->mac_version; + + if (tp->mac_version == RTL_GIGA_MAC_NONE) { + netif_notice(tp, probe, dev, + "unknown MAC, using family default\n"); + tp->mac_version = default_version; + } } static void rtl8169_print_mac_version(struct rtl8169_private *tp) @@ -3353,7 +3360,7 @@ rtl8169_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) pci_set_master(pdev); /* Identify chip attached to board */ - rtl8169_get_mac_version(tp, ioaddr); + rtl8169_get_mac_version(tp, dev, cfg->default_ver); /* * Pretend we are using VLANs; This bypasses a nasty bug where @@ -3365,13 +3372,6 @@ rtl8169_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) rtl_init_mdio_ops(tp); rtl_init_pll_power_ops(tp); - /* Use appropriate default if unknown */ - if (tp->mac_version == RTL_GIGA_MAC_NONE) { - netif_notice(tp, probe, dev, - "unknown MAC, using family default\n"); - tp->mac_version = cfg->default_ver; - } - rtl8169_print_mac_version(tp); chipset = tp->mac_version; -- cgit v0.10.2 From 0693e88e6ccf615d9674548d8b924cdd9a1c976c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Miros=C5=82aw?= Date: Sat, 7 May 2011 01:48:02 +0000 Subject: net: bonding: factor out rlock(bond->lock) in xmit path MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Pull read_lock(&bond->lock) and BOND_IS_OK() to bond_start_xmit() from mode-dependent xmit functions. netif_running() is always true in hard_start_xmit. Signed-off-by: MichaÅ‚ MirosÅ‚aw Signed-off-by: David S. Miller diff --git a/drivers/net/bonding/bond_3ad.c b/drivers/net/bonding/bond_3ad.c index d4160f8..c7537abc 100644 --- a/drivers/net/bonding/bond_3ad.c +++ b/drivers/net/bonding/bond_3ad.c @@ -2403,14 +2403,6 @@ int bond_3ad_xmit_xor(struct sk_buff *skb, struct net_device *dev) struct ad_info ad_info; int res = 1; - /* make sure that the slaves list will - * not change during tx - */ - read_lock(&bond->lock); - - if (!BOND_IS_OK(bond)) - goto out; - if (bond_3ad_get_active_agg_info(bond, &ad_info)) { pr_debug("%s: Error: bond_3ad_get_active_agg_info failed\n", dev->name); @@ -2464,7 +2456,7 @@ out: /* no suitable interface, frame not sent */ dev_kfree_skb(skb); } - read_unlock(&bond->lock); + return NETDEV_TX_OK; } diff --git a/drivers/net/bonding/bond_alb.c b/drivers/net/bonding/bond_alb.c index 3b7b040..8f2d2e7 100644 --- a/drivers/net/bonding/bond_alb.c +++ b/drivers/net/bonding/bond_alb.c @@ -1225,16 +1225,10 @@ int bond_alb_xmit(struct sk_buff *skb, struct net_device *bond_dev) skb_reset_mac_header(skb); eth_data = eth_hdr(skb); - /* make sure that the curr_active_slave and the slaves list do - * not change during tx + /* make sure that the curr_active_slave do not change during tx */ - read_lock(&bond->lock); read_lock(&bond->curr_slave_lock); - if (!BOND_IS_OK(bond)) { - goto out; - } - switch (ntohs(skb->protocol)) { case ETH_P_IP: { const struct iphdr *iph = ip_hdr(skb); @@ -1334,13 +1328,12 @@ int bond_alb_xmit(struct sk_buff *skb, struct net_device *bond_dev) } } -out: if (res) { /* no suitable interface, frame not sent */ dev_kfree_skb(skb); } read_unlock(&bond->curr_slave_lock); - read_unlock(&bond->lock); + return NETDEV_TX_OK; } diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index 9a5feaf..6312db1 100644 --- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c @@ -4004,10 +4004,6 @@ static int bond_xmit_roundrobin(struct sk_buff *skb, struct net_device *bond_dev int i, slave_no, res = 1; struct iphdr *iph = ip_hdr(skb); - read_lock(&bond->lock); - - if (!BOND_IS_OK(bond)) - goto out; /* * Start with the curr_active_slave that joined the bond as the * default for sending IGMP traffic. For failover purposes one @@ -4054,7 +4050,7 @@ out: /* no suitable interface, frame not sent */ dev_kfree_skb(skb); } - read_unlock(&bond->lock); + return NETDEV_TX_OK; } @@ -4068,24 +4064,18 @@ static int bond_xmit_activebackup(struct sk_buff *skb, struct net_device *bond_d struct bonding *bond = netdev_priv(bond_dev); int res = 1; - read_lock(&bond->lock); read_lock(&bond->curr_slave_lock); - if (!BOND_IS_OK(bond)) - goto out; + if (bond->curr_active_slave) + res = bond_dev_queue_xmit(bond, skb, + bond->curr_active_slave->dev); - if (!bond->curr_active_slave) - goto out; - - res = bond_dev_queue_xmit(bond, skb, bond->curr_active_slave->dev); - -out: if (res) /* no suitable interface, frame not sent */ dev_kfree_skb(skb); read_unlock(&bond->curr_slave_lock); - read_unlock(&bond->lock); + return NETDEV_TX_OK; } @@ -4102,11 +4092,6 @@ static int bond_xmit_xor(struct sk_buff *skb, struct net_device *bond_dev) int i; int res = 1; - read_lock(&bond->lock); - - if (!BOND_IS_OK(bond)) - goto out; - slave_no = bond->xmit_hash_policy(skb, bond->slave_cnt); bond_for_each_slave(bond, slave, i) { @@ -4126,12 +4111,11 @@ static int bond_xmit_xor(struct sk_buff *skb, struct net_device *bond_dev) } } -out: if (res) { /* no suitable interface, frame not sent */ dev_kfree_skb(skb); } - read_unlock(&bond->lock); + return NETDEV_TX_OK; } @@ -4146,11 +4130,6 @@ static int bond_xmit_broadcast(struct sk_buff *skb, struct net_device *bond_dev) int i; int res = 1; - read_lock(&bond->lock); - - if (!BOND_IS_OK(bond)) - goto out; - read_lock(&bond->curr_slave_lock); start_at = bond->curr_active_slave; read_unlock(&bond->curr_slave_lock); @@ -4189,7 +4168,6 @@ out: dev_kfree_skb(skb); /* frame sent to all suitable interfaces */ - read_unlock(&bond->lock); return NETDEV_TX_OK; } @@ -4221,10 +4199,8 @@ static inline int bond_slave_override(struct bonding *bond, struct slave *slave = NULL; struct slave *check_slave; - read_lock(&bond->lock); - - if (!BOND_IS_OK(bond) || !skb->queue_mapping) - goto out; + if (!skb->queue_mapping) + return 1; /* Find out if any slaves have the same mapping as this skb. */ bond_for_each_slave(bond, check_slave, i) { @@ -4240,8 +4216,6 @@ static inline int bond_slave_override(struct bonding *bond, res = bond_dev_queue_xmit(bond, skb, slave->dev); } -out: - read_unlock(&bond->lock); return res; } @@ -4263,17 +4237,10 @@ static u16 bond_select_queue(struct net_device *dev, struct sk_buff *skb) return txq; } -static netdev_tx_t bond_start_xmit(struct sk_buff *skb, struct net_device *dev) +static netdev_tx_t __bond_start_xmit(struct sk_buff *skb, struct net_device *dev) { struct bonding *bond = netdev_priv(dev); - /* - * If we risk deadlock from transmitting this in the - * netpoll path, tell netpoll to queue the frame for later tx - */ - if (is_netpoll_tx_blocked(dev)) - return NETDEV_TX_BUSY; - if (TX_QUEUE_OVERRIDE(bond->params.mode)) { if (!bond_slave_override(bond, skb)) return NETDEV_TX_OK; @@ -4303,6 +4270,29 @@ static netdev_tx_t bond_start_xmit(struct sk_buff *skb, struct net_device *dev) } } +static netdev_tx_t bond_start_xmit(struct sk_buff *skb, struct net_device *dev) +{ + struct bonding *bond = netdev_priv(dev); + netdev_tx_t ret = NETDEV_TX_OK; + + /* + * If we risk deadlock from transmitting this in the + * netpoll path, tell netpoll to queue the frame for later tx + */ + if (is_netpoll_tx_blocked(dev)) + return NETDEV_TX_BUSY; + + read_lock(&bond->lock); + + if (bond->slave_cnt) + ret = __bond_start_xmit(skb, dev); + else + dev_kfree_skb(skb); + + read_unlock(&bond->lock); + + return ret; +} /* * set bond mode specific net device operations -- cgit v0.10.2 From 99f823f98fb981b55c663a3783c3d2293958ece4 Mon Sep 17 00:00:00 2001 From: Alexey Dobriyan Date: Sat, 7 May 2011 20:33:13 +0000 Subject: netconsole: switch to kstrto*() functions Signed-off-by: Alexey Dobriyan Signed-off-by: David S. Miller diff --git a/drivers/net/netconsole.c b/drivers/net/netconsole.c index eb41e44..62fdbaa 100644 --- a/drivers/net/netconsole.c +++ b/drivers/net/netconsole.c @@ -242,34 +242,6 @@ static struct netconsole_target *to_target(struct config_item *item) } /* - * Wrapper over simple_strtol (base 10) with sanity and range checking. - * We return (signed) long only because we may want to return errors. - * Do not use this to convert numbers that are allowed to be negative. - */ -static long strtol10_check_range(const char *cp, long min, long max) -{ - long ret; - char *p = (char *) cp; - - WARN_ON(min < 0); - WARN_ON(max < min); - - ret = simple_strtol(p, &p, 10); - - if (*p && (*p != '\n')) { - printk(KERN_ERR "netconsole: invalid input\n"); - return -EINVAL; - } - if ((ret < min) || (ret > max)) { - printk(KERN_ERR "netconsole: input %ld must be between " - "%ld and %ld\n", ret, min, max); - return -EINVAL; - } - - return ret; -} - -/* * Attribute operations for netconsole_target. */ @@ -327,12 +299,14 @@ static ssize_t store_enabled(struct netconsole_target *nt, const char *buf, size_t count) { + int enabled; int err; - long enabled; - enabled = strtol10_check_range(buf, 0, 1); - if (enabled < 0) - return enabled; + err = kstrtoint(buf, 10, &enabled); + if (err < 0) + return err; + if (enabled < 0 || enabled > 1) + return -EINVAL; if (enabled) { /* 1 */ @@ -384,8 +358,7 @@ static ssize_t store_local_port(struct netconsole_target *nt, const char *buf, size_t count) { - long local_port; -#define __U16_MAX ((__u16) ~0U) + int rv; if (nt->enabled) { printk(KERN_ERR "netconsole: target (%s) is enabled, " @@ -394,12 +367,9 @@ static ssize_t store_local_port(struct netconsole_target *nt, return -EINVAL; } - local_port = strtol10_check_range(buf, 0, __U16_MAX); - if (local_port < 0) - return local_port; - - nt->np.local_port = local_port; - + rv = kstrtou16(buf, 10, &nt->np.local_port); + if (rv < 0) + return rv; return strnlen(buf, count); } @@ -407,8 +377,7 @@ static ssize_t store_remote_port(struct netconsole_target *nt, const char *buf, size_t count) { - long remote_port; -#define __U16_MAX ((__u16) ~0U) + int rv; if (nt->enabled) { printk(KERN_ERR "netconsole: target (%s) is enabled, " @@ -417,12 +386,9 @@ static ssize_t store_remote_port(struct netconsole_target *nt, return -EINVAL; } - remote_port = strtol10_check_range(buf, 0, __U16_MAX); - if (remote_port < 0) - return remote_port; - - nt->np.remote_port = remote_port; - + rv = kstrtou16(buf, 10, &nt->np.remote_port); + if (rv < 0) + return rv; return strnlen(buf, count); } -- cgit v0.10.2 From 4940fc889e1e63667a15243028ddcd84d471cd8e Mon Sep 17 00:00:00 2001 From: Alexey Dobriyan Date: Sat, 7 May 2011 23:00:07 +0000 Subject: net: add mac_pton() for parsing MAC address mac_pton() parses MAC address in form XX:XX:XX:XX:XX:XX and only in that form. mac_pton() doesn't dirty result until it's sure string representation is valid. mac_pton() doesn't care about characters _after_ last octet, it's up to caller to deal with it. mac_pton() diverges from 0/-E return value convention. Target usage: if (!mac_pton(str, whatever->mac)) return -EINVAL; /* ->mac being u8 [ETH_ALEN] is filled at this point. */ /* optionally check str[3 * ETH_ALEN - 1] for termination */ Use mac_pton() in pktgen and netconsole for start. Signed-off-by: Alexey Dobriyan Signed-off-by: David S. Miller diff --git a/drivers/net/netconsole.c b/drivers/net/netconsole.c index 62fdbaa..a83e101 100644 --- a/drivers/net/netconsole.c +++ b/drivers/net/netconsole.c @@ -429,8 +429,6 @@ static ssize_t store_remote_mac(struct netconsole_target *nt, size_t count) { u8 remote_mac[ETH_ALEN]; - char *p = (char *) buf; - int i; if (nt->enabled) { printk(KERN_ERR "netconsole: target (%s) is enabled, " @@ -439,23 +437,13 @@ static ssize_t store_remote_mac(struct netconsole_target *nt, return -EINVAL; } - for (i = 0; i < ETH_ALEN - 1; i++) { - remote_mac[i] = simple_strtoul(p, &p, 16); - if (*p != ':') - goto invalid; - p++; - } - remote_mac[ETH_ALEN - 1] = simple_strtoul(p, &p, 16); - if (*p && (*p != '\n')) - goto invalid; - + if (!mac_pton(buf, remote_mac)) + return -EINVAL; + if (buf[3 * ETH_ALEN - 1] && buf[3 * ETH_ALEN - 1] != '\n') + return -EINVAL; memcpy(nt->np.remote_mac, remote_mac, ETH_ALEN); return strnlen(buf, count); - -invalid: - printk(KERN_ERR "netconsole: invalid input\n"); - return -EINVAL; } /* diff --git a/include/linux/if_ether.h b/include/linux/if_ether.h index be69043..0f1325d 100644 --- a/include/linux/if_ether.h +++ b/include/linux/if_ether.h @@ -136,6 +136,7 @@ int eth_header_parse(const struct sk_buff *skb, unsigned char *haddr); extern struct ctl_table ether_table[]; #endif +int mac_pton(const char *s, u8 *mac); extern ssize_t sysfs_format_mac(char *buf, const unsigned char *addr, int len); #endif diff --git a/net/core/netpoll.c b/net/core/netpoll.c index 46d9c3a..2d7d6d4 100644 --- a/net/core/netpoll.c +++ b/net/core/netpoll.c @@ -698,32 +698,8 @@ int netpoll_parse_options(struct netpoll *np, char *opt) if (*cur != 0) { /* MAC address */ - if ((delim = strchr(cur, ':')) == NULL) + if (!mac_pton(cur, np->remote_mac)) goto parse_failed; - *delim = 0; - np->remote_mac[0] = simple_strtol(cur, NULL, 16); - cur = delim + 1; - if ((delim = strchr(cur, ':')) == NULL) - goto parse_failed; - *delim = 0; - np->remote_mac[1] = simple_strtol(cur, NULL, 16); - cur = delim + 1; - if ((delim = strchr(cur, ':')) == NULL) - goto parse_failed; - *delim = 0; - np->remote_mac[2] = simple_strtol(cur, NULL, 16); - cur = delim + 1; - if ((delim = strchr(cur, ':')) == NULL) - goto parse_failed; - *delim = 0; - np->remote_mac[3] = simple_strtol(cur, NULL, 16); - cur = delim + 1; - if ((delim = strchr(cur, ':')) == NULL) - goto parse_failed; - *delim = 0; - np->remote_mac[4] = simple_strtol(cur, NULL, 16); - cur = delim + 1; - np->remote_mac[5] = simple_strtol(cur, NULL, 16); } netpoll_print_options(np); diff --git a/net/core/pktgen.c b/net/core/pktgen.c index d41d88b..379270f 100644 --- a/net/core/pktgen.c +++ b/net/core/pktgen.c @@ -1420,11 +1420,6 @@ static ssize_t pktgen_if_write(struct file *file, return count; } if (!strcmp(name, "dst_mac")) { - char *v = valstr; - unsigned char old_dmac[ETH_ALEN]; - unsigned char *m = pkt_dev->dst_mac; - memcpy(old_dmac, pkt_dev->dst_mac, ETH_ALEN); - len = strn_len(&user_buffer[i], sizeof(valstr) - 1); if (len < 0) return len; @@ -1432,35 +1427,16 @@ static ssize_t pktgen_if_write(struct file *file, memset(valstr, 0, sizeof(valstr)); if (copy_from_user(valstr, &user_buffer[i], len)) return -EFAULT; - i += len; - - for (*m = 0; *v && m < pkt_dev->dst_mac + 6; v++) { - int value; - - value = hex_to_bin(*v); - if (value >= 0) - *m = *m * 16 + value; - - if (*v == ':') { - m++; - *m = 0; - } - } + if (!mac_pton(valstr, pkt_dev->dst_mac)) + return -EINVAL; /* Set up Dest MAC */ - if (compare_ether_addr(old_dmac, pkt_dev->dst_mac)) - memcpy(&(pkt_dev->hh[0]), pkt_dev->dst_mac, ETH_ALEN); + memcpy(&pkt_dev->hh[0], pkt_dev->dst_mac, ETH_ALEN); - sprintf(pg_result, "OK: dstmac"); + sprintf(pg_result, "OK: dstmac %pM", pkt_dev->dst_mac); return count; } if (!strcmp(name, "src_mac")) { - char *v = valstr; - unsigned char old_smac[ETH_ALEN]; - unsigned char *m = pkt_dev->src_mac; - - memcpy(old_smac, pkt_dev->src_mac, ETH_ALEN); - len = strn_len(&user_buffer[i], sizeof(valstr) - 1); if (len < 0) return len; @@ -1468,26 +1444,13 @@ static ssize_t pktgen_if_write(struct file *file, memset(valstr, 0, sizeof(valstr)); if (copy_from_user(valstr, &user_buffer[i], len)) return -EFAULT; - i += len; - - for (*m = 0; *v && m < pkt_dev->src_mac + 6; v++) { - int value; - - value = hex_to_bin(*v); - if (value >= 0) - *m = *m * 16 + value; - - if (*v == ':') { - m++; - *m = 0; - } - } + if (!mac_pton(valstr, pkt_dev->src_mac)) + return -EINVAL; /* Set up Src MAC */ - if (compare_ether_addr(old_smac, pkt_dev->src_mac)) - memcpy(&(pkt_dev->hh[6]), pkt_dev->src_mac, ETH_ALEN); + memcpy(&pkt_dev->hh[6], pkt_dev->src_mac, ETH_ALEN); - sprintf(pg_result, "OK: srcmac"); + sprintf(pg_result, "OK: srcmac %pM", pkt_dev->src_mac); return count; } diff --git a/net/core/utils.c b/net/core/utils.c index 5fea0ab..2012bc7 100644 --- a/net/core/utils.c +++ b/net/core/utils.c @@ -296,3 +296,27 @@ void inet_proto_csum_replace4(__sum16 *sum, struct sk_buff *skb, csum_unfold(*sum))); } EXPORT_SYMBOL(inet_proto_csum_replace4); + +int mac_pton(const char *s, u8 *mac) +{ + int i; + + /* XX:XX:XX:XX:XX:XX */ + if (strlen(s) < 3 * ETH_ALEN - 1) + return 0; + + /* Don't dirty result unless string is valid MAC. */ + for (i = 0; i < ETH_ALEN; i++) { + if (!strchr("0123456789abcdefABCDEF", s[i * 3])) + return 0; + if (!strchr("0123456789abcdefABCDEF", s[i * 3 + 1])) + return 0; + if (i != ETH_ALEN - 1 && s[i * 3 + 2] != ':') + return 0; + } + for (i = 0; i < ETH_ALEN; i++) { + mac[i] = (hex_to_bin(s[i * 3]) << 4) | hex_to_bin(s[i * 3 + 1]); + } + return 1; +} +EXPORT_SYMBOL(mac_pton); -- cgit v0.10.2 From 2b5e8ef35bc89eee944c0627edacbb1fea5a1b84 Mon Sep 17 00:00:00 2001 From: Matthew Garrett Date: Thu, 5 May 2011 15:19:42 -0400 Subject: x86, efi: Remove virtual-mode SetVirtualAddressMap call The spec says that SetVirtualAddressMap doesn't work once you're in virtual mode, so there's no point in having infrastructure for calling it from there. Signed-off-by: Matthew Garrett Link: http://lkml.kernel.org/r/1304623186-18261-1-git-send-email-mjg@redhat.com Signed-off-by: H. Peter Anvin diff --git a/arch/x86/platform/efi/efi.c b/arch/x86/platform/efi/efi.c index 0fe27d7..f2e4fe9 100644 --- a/arch/x86/platform/efi/efi.c +++ b/arch/x86/platform/efi/efi.c @@ -145,17 +145,6 @@ static void virt_efi_reset_system(int reset_type, data_size, data); } -static efi_status_t virt_efi_set_virtual_address_map( - unsigned long memory_map_size, - unsigned long descriptor_size, - u32 descriptor_version, - efi_memory_desc_t *virtual_map) -{ - return efi_call_virt4(set_virtual_address_map, - memory_map_size, descriptor_size, - descriptor_version, virtual_map); -} - static efi_status_t __init phys_efi_set_virtual_address_map( unsigned long memory_map_size, unsigned long descriptor_size, @@ -572,7 +561,7 @@ void __init efi_enter_virtual_mode(void) efi.set_variable = virt_efi_set_variable; efi.get_next_high_mono_count = virt_efi_get_next_high_mono_count; efi.reset_system = virt_efi_reset_system; - efi.set_virtual_address_map = virt_efi_set_virtual_address_map; + efi.set_virtual_address_map = NULL; if (__supported_pte_mask & _PAGE_NX) runtime_code_page_mkexec(); early_iounmap(memmap.map, memmap.nr_map * memmap.desc_size); -- cgit v0.10.2 From 9cd2b07c197e3ff594fc04f5fb3d86efbeab6ad8 Mon Sep 17 00:00:00 2001 From: Matthew Garrett Date: Thu, 5 May 2011 15:19:43 -0400 Subject: x86, efi: Consolidate EFI nx control The core EFI code and 64-bit EFI code currently have independent implementations of code for setting memory regions as executable or not. Let's consolidate them. Signed-off-by: Matthew Garrett Link: http://lkml.kernel.org/r/1304623186-18261-2-git-send-email-mjg@redhat.com Signed-off-by: H. Peter Anvin diff --git a/arch/x86/include/asm/efi.h b/arch/x86/include/asm/efi.h index 8e4a165..7093e4a 100644 --- a/arch/x86/include/asm/efi.h +++ b/arch/x86/include/asm/efi.h @@ -90,6 +90,7 @@ extern void __iomem *efi_ioremap(unsigned long addr, unsigned long size, #endif /* CONFIG_X86_32 */ extern int add_efi_memmap; +extern void efi_set_executable(efi_memory_desc_t *md, bool executable); extern void efi_memblock_x86_reserve_range(void); extern void efi_call_phys_prelog(void); extern void efi_call_phys_epilog(void); diff --git a/arch/x86/platform/efi/efi.c b/arch/x86/platform/efi/efi.c index f2e4fe9..7daae27 100644 --- a/arch/x86/platform/efi/efi.c +++ b/arch/x86/platform/efi/efi.c @@ -457,11 +457,25 @@ void __init efi_init(void) #endif } +void __init efi_set_executable(efi_memory_desc_t *md, bool executable) +{ + u64 addr, npages; + + addr = md->virt_addr; + npages = md->num_pages; + + memrange_efi_to_native(&addr, &npages); + + if (executable) + set_memory_x(addr, npages); + else + set_memory_nx(addr, npages); +} + static void __init runtime_code_page_mkexec(void) { efi_memory_desc_t *md; void *p; - u64 addr, npages; /* Make EFI runtime service code area executable */ for (p = memmap.map; p < memmap.map_end; p += memmap.desc_size) { @@ -470,10 +484,7 @@ static void __init runtime_code_page_mkexec(void) if (md->type != EFI_RUNTIME_SERVICES_CODE) continue; - addr = md->virt_addr; - npages = md->num_pages; - memrange_efi_to_native(&addr, &npages); - set_memory_x(addr, npages); + efi_set_executable(md, true); } } diff --git a/arch/x86/platform/efi/efi_64.c b/arch/x86/platform/efi/efi_64.c index ac0621a..94d6b39 100644 --- a/arch/x86/platform/efi/efi_64.c +++ b/arch/x86/platform/efi/efi_64.c @@ -41,22 +41,7 @@ static pgd_t save_pgd __initdata; static unsigned long efi_flags __initdata; -static void __init early_mapping_set_exec(unsigned long start, - unsigned long end, - int executable) -{ - unsigned long num_pages; - - start &= PMD_MASK; - end = (end + PMD_SIZE - 1) & PMD_MASK; - num_pages = (end - start) >> PAGE_SHIFT; - if (executable) - set_memory_x((unsigned long)__va(start), num_pages); - else - set_memory_nx((unsigned long)__va(start), num_pages); -} - -static void __init early_runtime_code_mapping_set_exec(int executable) +static void __init early_code_mapping_set_exec(int executable) { efi_memory_desc_t *md; void *p; @@ -67,11 +52,8 @@ static void __init early_runtime_code_mapping_set_exec(int executable) /* Make EFI runtime service code area executable */ for (p = memmap.map; p < memmap.map_end; p += memmap.desc_size) { md = p; - if (md->type == EFI_RUNTIME_SERVICES_CODE) { - unsigned long end; - end = md->phys_addr + (md->num_pages << EFI_PAGE_SHIFT); - early_mapping_set_exec(md->phys_addr, end, executable); - } + if (md->type == EFI_RUNTIME_SERVICES_CODE) + efi_set_executable(md, executable); } } @@ -79,7 +61,7 @@ void __init efi_call_phys_prelog(void) { unsigned long vaddress; - early_runtime_code_mapping_set_exec(1); + early_code_mapping_set_exec(1); local_irq_save(efi_flags); vaddress = (unsigned long)__va(0x0UL); save_pgd = *pgd_offset_k(0x0UL); @@ -95,7 +77,7 @@ void __init efi_call_phys_epilog(void) set_pgd(pgd_offset_k(0x0UL), save_pgd); __flush_tlb_all(); local_irq_restore(efi_flags); - early_runtime_code_mapping_set_exec(0); + early_code_mapping_set_exec(0); } void __iomem *__init efi_ioremap(unsigned long phys_addr, unsigned long size, -- cgit v0.10.2 From 202f9d0a41809e3424af5f61489b48b622824aed Mon Sep 17 00:00:00 2001 From: Matthew Garrett Date: Thu, 5 May 2011 15:19:44 -0400 Subject: x86, efi: Merge contiguous memory regions of the same type and attribute Some firmware implementations assume that physically contiguous regions will be contiguous in virtual address space. This assumption is, obviously, entirely unjustifiable. Said firmware implementations lack the good grace to handle their failings in a measured and reasonable manner, instead tending to shit all over address space and oopsing the kernel. In an ideal universe these firmware implementations would simultaneously catch fire and cease to be a problem, but since some of them are present in attractively thin and shiny metal devices vanity wins out and some poor developer spends an extended period of time surrounded by a growing array of empty bottles until the underlying reason becomes apparent. Said developer presents this patch, which simply merges adjacent regions if they happen to be contiguous and have the same EFI memory type and caching attributes. Signed-off-by: Matthew Garrett Link: http://lkml.kernel.org/r/1304623186-18261-3-git-send-email-mjg@redhat.com Signed-off-by: H. Peter Anvin diff --git a/arch/x86/platform/efi/efi.c b/arch/x86/platform/efi/efi.c index 7daae27..a46a73e 100644 --- a/arch/x86/platform/efi/efi.c +++ b/arch/x86/platform/efi/efi.c @@ -498,13 +498,41 @@ static void __init runtime_code_page_mkexec(void) */ void __init efi_enter_virtual_mode(void) { - efi_memory_desc_t *md; + efi_memory_desc_t *md, *prev_md = NULL; efi_status_t status; unsigned long size; u64 end, systab, addr, npages, end_pfn; void *p, *va; efi.systab = NULL; + + /* Merge contiguous regions of the same type and attribute */ + for (p = memmap.map; p < memmap.map_end; p += memmap.desc_size) { + u64 prev_size; + md = p; + + if (!prev_md) { + prev_md = md; + continue; + } + + if (prev_md->type != md->type || + prev_md->attribute != md->attribute) { + prev_md = md; + continue; + } + + prev_size = prev_md->num_pages << EFI_PAGE_SHIFT; + + if (md->phys_addr == (prev_md->phys_addr + prev_size)) { + prev_md->num_pages += md->num_pages; + md->type = EFI_RESERVED_TYPE; + md->attribute = 0; + continue; + } + prev_md = md; + } + for (p = memmap.map; p < memmap.map_end; p += memmap.desc_size) { md = p; if (!(md->attribute & EFI_MEMORY_RUNTIME)) -- cgit v0.10.2 From 7cb00b72876ea2451eb79d468da0e8fb9134aa8a Mon Sep 17 00:00:00 2001 From: Matthew Garrett Date: Thu, 5 May 2011 15:19:45 -0400 Subject: x86, efi: Pass a minimal map to SetVirtualAddressMap() Experimentation with various EFI implementations has shown that functions outside runtime services will still update their pointers if SetVirtualAddressMap() is called with memory descriptors outside the runtime area. This is obviously insane, and therefore is unsurprising. Evidence from instrumenting another EFI implementation suggests that it only passes the set of descriptors covering runtime regions, so let's avoid any problems by doing the same. Runtime descriptors are copied to a separate memory map, and only that map is passed back to the firmware. Signed-off-by: Matthew Garrett Link: http://lkml.kernel.org/r/1304623186-18261-4-git-send-email-mjg@redhat.com Signed-off-by: H. Peter Anvin diff --git a/arch/x86/platform/efi/efi.c b/arch/x86/platform/efi/efi.c index a46a73e..b30aa26 100644 --- a/arch/x86/platform/efi/efi.c +++ b/arch/x86/platform/efi/efi.c @@ -502,7 +502,8 @@ void __init efi_enter_virtual_mode(void) efi_status_t status; unsigned long size; u64 end, systab, addr, npages, end_pfn; - void *p, *va; + void *p, *va, *new_memmap = NULL; + int count = 0; efi.systab = NULL; @@ -569,15 +570,21 @@ void __init efi_enter_virtual_mode(void) systab += md->virt_addr - md->phys_addr; efi.systab = (efi_system_table_t *) (unsigned long) systab; } + new_memmap = krealloc(new_memmap, + (count + 1) * memmap.desc_size, + GFP_KERNEL); + memcpy(new_memmap + (count * memmap.desc_size), md, + memmap.desc_size); + count++; } BUG_ON(!efi.systab); status = phys_efi_set_virtual_address_map( - memmap.desc_size * memmap.nr_map, + memmap.desc_size * count, memmap.desc_size, memmap.desc_version, - memmap.phys_map); + (efi_memory_desc_t *)__pa(new_memmap)); if (status != EFI_SUCCESS) { printk(KERN_ALERT "Unable to switch EFI into virtual mode " @@ -605,6 +612,7 @@ void __init efi_enter_virtual_mode(void) runtime_code_page_mkexec(); early_iounmap(memmap.map, memmap.nr_map * memmap.desc_size); memmap.map = NULL; + kfree(new_memmap); } /* -- cgit v0.10.2 From 935a638241b0658b9749edd060f972575f9d4a78 Mon Sep 17 00:00:00 2001 From: Matthew Garrett Date: Thu, 5 May 2011 15:19:46 -0400 Subject: x86, efi: Ensure that the entirity of a region is mapped It's possible for init_memory_mapping() to fail to map the entire region if it crosses a boundary, so ensure that we complete the mapping. Signed-off-by: Matthew Garrett Link: http://lkml.kernel.org/r/1304623186-18261-5-git-send-email-mjg@redhat.com Signed-off-by: H. Peter Anvin diff --git a/arch/x86/platform/efi/efi_64.c b/arch/x86/platform/efi/efi_64.c index 94d6b39..2649426 100644 --- a/arch/x86/platform/efi/efi_64.c +++ b/arch/x86/platform/efi/efi_64.c @@ -89,8 +89,10 @@ void __iomem *__init efi_ioremap(unsigned long phys_addr, unsigned long size, return ioremap(phys_addr, size); last_map_pfn = init_memory_mapping(phys_addr, phys_addr + size); - if ((last_map_pfn << PAGE_SHIFT) < phys_addr + size) - return NULL; + if ((last_map_pfn << PAGE_SHIFT) < phys_addr + size) { + unsigned long top = last_map_pfn << PAGE_SHIFT; + efi_ioremap(top, size - (top - phys_addr), type); + } return (void __iomem *)__va(phys_addr); } -- cgit v0.10.2 From b0e6baf5619a6fa3eaf43b55fdb4daa362c3c916 Mon Sep 17 00:00:00 2001 From: Tomoya Date: Mon, 9 May 2011 01:19:37 +0000 Subject: pch_gbe: support ML7223 IOH Support new device OKI SEMICONDUCTOR ML7223 IOH(Input/Output Hub). The ML7223 IOH is for MP(Media Phone) use. The ML7223 is companion chip for Intel Atom E6xx series. The ML7223 is completely compatible for Intel EG20T PCH. Signed-off-by: Tomoya MORINAGA Signed-off-by: David S. Miller diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index dc280bc..6c884ef 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -2536,7 +2536,7 @@ config S6GMAC source "drivers/net/stmmac/Kconfig" config PCH_GBE - tristate "PCH Gigabit Ethernet" + tristate "Intel EG20T PCH / OKI SEMICONDUCTOR ML7223 IOH GbE" depends on PCI select MII ---help--- @@ -2548,6 +2548,12 @@ config PCH_GBE to Gigabit Ethernet. This driver enables Gigabit Ethernet function. + This driver also can be used for OKI SEMICONDUCTOR IOH(Input/ + Output Hub), ML7223. + ML7223 IOH is for MP(Media Phone) use. + ML7223 is companion chip for Intel Atom E6xx series. + ML7223 is completely compatible for Intel EG20T PCH. + endif # NETDEV_1000 # diff --git a/drivers/net/pch_gbe/pch_gbe_main.c b/drivers/net/pch_gbe/pch_gbe_main.c index 9f6c402..56d049a 100644 --- a/drivers/net/pch_gbe/pch_gbe_main.c +++ b/drivers/net/pch_gbe/pch_gbe_main.c @@ -34,6 +34,10 @@ const char pch_driver_version[] = DRV_VERSION; #define PCH_GBE_COPYBREAK_DEFAULT 256 #define PCH_GBE_PCI_BAR 1 +/* Macros for ML7223 */ +#define PCI_VENDOR_ID_ROHM 0x10db +#define PCI_DEVICE_ID_ROHM_ML7223_GBE 0x8013 + #define PCH_GBE_TX_WEIGHT 64 #define PCH_GBE_RX_WEIGHT 64 #define PCH_GBE_RX_BUFFER_WRITE 16 @@ -2418,6 +2422,13 @@ static DEFINE_PCI_DEVICE_TABLE(pch_gbe_pcidev_id) = { .class = (PCI_CLASS_NETWORK_ETHERNET << 8), .class_mask = (0xFFFF00) }, + {.vendor = PCI_VENDOR_ID_ROHM, + .device = PCI_DEVICE_ID_ROHM_ML7223_GBE, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + .class = (PCI_CLASS_NETWORK_ETHERNET << 8), + .class_mask = (0xFFFF00) + }, /* required last entry */ {0} }; -- cgit v0.10.2 From 54668b84bd2ee808e6b43ed9bd7aa3338fa95857 Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Mon, 9 May 2011 09:45:20 +0000 Subject: tulip: xircom_cb: Convert #ifdef DEBUG blocks and enter/leave uses Change the blocks that are guarded by #if DEBUG to be #if defined DEBUG && DEBUG > 1 so that pr_debug can be used later. Remove enter/leave macros and uses. Signed-off-by: Joe Perches Signed-off-by: David S. Miller diff --git a/drivers/net/tulip/xircom_cb.c b/drivers/net/tulip/xircom_cb.c index 5a73752..d0d0cbe 100644 --- a/drivers/net/tulip/xircom_cb.c +++ b/drivers/net/tulip/xircom_cb.c @@ -37,15 +37,6 @@ #include #endif -#ifdef DEBUG -#define enter(x) printk("Enter: %s, %s line %i\n",x,__FILE__,__LINE__) -#define leave(x) printk("Leave: %s, %s line %i\n",x,__FILE__,__LINE__) -#else -#define enter(x) do {} while (0) -#define leave(x) do {} while (0) -#endif - - MODULE_DESCRIPTION("Xircom Cardbus ethernet driver"); MODULE_AUTHOR("Arjan van de Ven "); MODULE_LICENSE("GPL"); @@ -161,7 +152,7 @@ static struct pci_driver xircom_ops = { }; -#ifdef DEBUG +#if defined DEBUG && DEBUG > 1 static void print_binary(unsigned int number) { int i,i2; @@ -176,7 +167,7 @@ static void print_binary(unsigned int number) if ((i&3)==0) buffer[i2++]=' '; } - printk("%s\n",buffer); + pr_debug("%s\n",buffer); } #endif @@ -205,7 +196,6 @@ static int __devinit xircom_probe(struct pci_dev *pdev, const struct pci_device_ struct xircom_private *private; unsigned long flags; unsigned short tmp16; - enter("xircom_probe"); /* First do the PCI initialisation */ @@ -285,7 +275,6 @@ static int __devinit xircom_probe(struct pci_dev *pdev, const struct pci_device_ trigger_receive(private); - leave("xircom_probe"); return 0; reg_fail: @@ -310,7 +299,6 @@ static void __devexit xircom_remove(struct pci_dev *pdev) struct net_device *dev = pci_get_drvdata(pdev); struct xircom_private *card = netdev_priv(dev); - enter("xircom_remove"); pci_free_consistent(pdev,8192,card->rx_buffer,card->rx_dma_handle); pci_free_consistent(pdev,8192,card->tx_buffer,card->tx_dma_handle); @@ -318,7 +306,6 @@ static void __devexit xircom_remove(struct pci_dev *pdev) unregister_netdev(dev); free_netdev(dev); pci_set_drvdata(pdev, NULL); - leave("xircom_remove"); } static irqreturn_t xircom_interrupt(int irq, void *dev_instance) @@ -328,17 +315,15 @@ static irqreturn_t xircom_interrupt(int irq, void *dev_instance) unsigned int status; int i; - enter("xircom_interrupt\n"); - spin_lock(&card->lock); status = inl(card->io_port+CSR5); -#ifdef DEBUG +#if defined DEBUG && DEBUG > 1 print_binary(status); - printk("tx status 0x%08x 0x%08x\n", - card->tx_buffer[0], card->tx_buffer[4]); - printk("rx status 0x%08x 0x%08x\n", - card->rx_buffer[0], card->rx_buffer[4]); + pr_debug("tx status 0x%08x 0x%08x\n", + card->tx_buffer[0], card->tx_buffer[4]); + pr_debug("rx status 0x%08x 0x%08x\n", + card->rx_buffer[0], card->rx_buffer[4]); #endif /* Handle shared irq and hotplug */ if (status == 0 || status == 0xffffffff) { @@ -369,9 +354,7 @@ static irqreturn_t xircom_interrupt(int irq, void *dev_instance) for (i=0;ilock); - leave("xircom_interrupt"); return IRQ_HANDLED; } @@ -382,7 +365,6 @@ static netdev_tx_t xircom_start_xmit(struct sk_buff *skb, unsigned long flags; int nextdescriptor; int desc; - enter("xircom_start_xmit"); card = netdev_priv(dev); spin_lock_irqsave(&card->lock,flags); @@ -424,13 +406,10 @@ static netdev_tx_t xircom_start_xmit(struct sk_buff *skb, netif_stop_queue(dev); } card->transmit_used = nextdescriptor; - leave("xircom-start_xmit - sent"); spin_unlock_irqrestore(&card->lock,flags); return NETDEV_TX_OK; } - - /* Uh oh... no free descriptor... drop the packet */ netif_stop_queue(dev); spin_unlock_irqrestore(&card->lock,flags); @@ -446,18 +425,16 @@ static int xircom_open(struct net_device *dev) { struct xircom_private *xp = netdev_priv(dev); int retval; - enter("xircom_open"); + pr_info("xircom cardbus adaptor found, registering as %s, using irq %i\n", dev->name, dev->irq); retval = request_irq(dev->irq, xircom_interrupt, IRQF_SHARED, dev->name, dev); - if (retval) { - leave("xircom_open - No IRQ"); + if (retval) return retval; - } xircom_up(xp); xp->open = 1; - leave("xircom_open"); + return 0; } @@ -466,7 +443,6 @@ static int xircom_close(struct net_device *dev) struct xircom_private *card; unsigned long flags; - enter("xircom_close"); card = netdev_priv(dev); netif_stop_queue(dev); /* we don't want new packets */ @@ -486,8 +462,6 @@ static int xircom_close(struct net_device *dev) card->open = 0; free_irq(dev->irq,dev); - leave("xircom_close"); - return 0; } @@ -507,8 +481,6 @@ static void initialize_card(struct xircom_private *card) { unsigned int val; unsigned long flags; - enter("initialize_card"); - spin_lock_irqsave(&card->lock, flags); @@ -534,8 +506,6 @@ static void initialize_card(struct xircom_private *card) deactivate_transmitter(card); spin_unlock_irqrestore(&card->lock, flags); - - leave("initialize_card"); } /* @@ -547,12 +517,9 @@ ignored; I chose zero. static void trigger_transmit(struct xircom_private *card) { unsigned int val; - enter("trigger_transmit"); val = 0; outl(val, card->io_port + CSR1); - - leave("trigger_transmit"); } /* @@ -565,12 +532,9 @@ ignored; I chose zero. static void trigger_receive(struct xircom_private *card) { unsigned int val; - enter("trigger_receive"); val = 0; outl(val, card->io_port + CSR2); - - leave("trigger_receive"); } /* @@ -581,8 +545,6 @@ static void setup_descriptors(struct xircom_private *card) { u32 address; int i; - enter("setup_descriptors"); - BUG_ON(card->rx_buffer == NULL); BUG_ON(card->tx_buffer == NULL); @@ -636,8 +598,6 @@ static void setup_descriptors(struct xircom_private *card) /* wite the transmit descriptor ring to the card */ address = card->tx_dma_handle; outl(address, card->io_port + CSR4); /* xmit descr list address */ - - leave("setup_descriptors"); } /* @@ -647,13 +607,10 @@ valid by setting the address in the card to 0x00. static void remove_descriptors(struct xircom_private *card) { unsigned int val; - enter("remove_descriptors"); val = 0; outl(val, card->io_port + CSR3); /* Receive descriptor address */ outl(val, card->io_port + CSR4); /* Send descriptor address */ - - leave("remove_descriptors"); } /* @@ -665,21 +622,17 @@ This function also clears the status-bit. static int link_status_changed(struct xircom_private *card) { unsigned int val; - enter("link_status_changed"); val = inl(card->io_port + CSR5); /* Status register */ - if ((val & (1 << 27)) == 0) { /* no change */ - leave("link_status_changed - nochange"); + if ((val & (1 << 27)) == 0) /* no change */ return 0; - } /* clear the event by writing a 1 to the bit in the status register. */ val = (1 << 27); outl(val, card->io_port + CSR5); - leave("link_status_changed - changed"); return 1; } @@ -691,16 +644,12 @@ in a non-stopped state. static int transmit_active(struct xircom_private *card) { unsigned int val; - enter("transmit_active"); val = inl(card->io_port + CSR5); /* Status register */ - if ((val & (7 << 20)) == 0) { /* transmitter disabled */ - leave("transmit_active - inactive"); + if ((val & (7 << 20)) == 0) /* transmitter disabled */ return 0; - } - leave("transmit_active - active"); return 1; } @@ -711,17 +660,12 @@ in a non-stopped state. static int receive_active(struct xircom_private *card) { unsigned int val; - enter("receive_active"); - val = inl(card->io_port + CSR5); /* Status register */ - if ((val & (7 << 17)) == 0) { /* receiver disabled */ - leave("receive_active - inactive"); + if ((val & (7 << 17)) == 0) /* receiver disabled */ return 0; - } - leave("receive_active - active"); return 1; } @@ -739,8 +683,6 @@ static void activate_receiver(struct xircom_private *card) { unsigned int val; int counter; - enter("activate_receiver"); - val = inl(card->io_port + CSR6); /* Operation mode */ @@ -780,8 +722,6 @@ static void activate_receiver(struct xircom_private *card) if (counter <= 0) pr_err("Receiver failed to re-activate\n"); } - - leave("activate_receiver"); } /* @@ -795,7 +735,6 @@ static void deactivate_receiver(struct xircom_private *card) { unsigned int val; int counter; - enter("deactivate_receiver"); val = inl(card->io_port + CSR6); /* Operation mode */ val = val & ~2; /* disable the receiver */ @@ -811,9 +750,6 @@ static void deactivate_receiver(struct xircom_private *card) if (counter <= 0) pr_err("Receiver failed to deactivate\n"); } - - - leave("deactivate_receiver"); } @@ -831,8 +767,6 @@ static void activate_transmitter(struct xircom_private *card) { unsigned int val; int counter; - enter("activate_transmitter"); - val = inl(card->io_port + CSR6); /* Operation mode */ @@ -871,8 +805,6 @@ static void activate_transmitter(struct xircom_private *card) if (counter <= 0) pr_err("Transmitter failed to re-activate\n"); } - - leave("activate_transmitter"); } /* @@ -886,7 +818,6 @@ static void deactivate_transmitter(struct xircom_private *card) { unsigned int val; int counter; - enter("deactivate_transmitter"); val = inl(card->io_port + CSR6); /* Operation mode */ val = val & ~2; /* disable the transmitter */ @@ -902,9 +833,6 @@ static void deactivate_transmitter(struct xircom_private *card) if (counter <= 0) pr_err("Transmitter failed to deactivate\n"); } - - - leave("deactivate_transmitter"); } @@ -916,13 +844,10 @@ must be called with the lock held and interrupts disabled. static void enable_transmit_interrupt(struct xircom_private *card) { unsigned int val; - enter("enable_transmit_interrupt"); val = inl(card->io_port + CSR7); /* Interrupt enable register */ val |= 1; /* enable the transmit interrupt */ outl(val, card->io_port + CSR7); - - leave("enable_transmit_interrupt"); } @@ -934,13 +859,10 @@ must be called with the lock held and interrupts disabled. static void enable_receive_interrupt(struct xircom_private *card) { unsigned int val; - enter("enable_receive_interrupt"); val = inl(card->io_port + CSR7); /* Interrupt enable register */ val = val | (1 << 6); /* enable the receive interrupt */ outl(val, card->io_port + CSR7); - - leave("enable_receive_interrupt"); } /* @@ -951,13 +873,10 @@ must be called with the lock held and interrupts disabled. static void enable_link_interrupt(struct xircom_private *card) { unsigned int val; - enter("enable_link_interrupt"); val = inl(card->io_port + CSR7); /* Interrupt enable register */ val = val | (1 << 27); /* enable the link status chage interrupt */ outl(val, card->io_port + CSR7); - - leave("enable_link_interrupt"); } @@ -970,12 +889,9 @@ must be called with the lock held and interrupts disabled. static void disable_all_interrupts(struct xircom_private *card) { unsigned int val; - enter("enable_all_interrupts"); val = 0; /* disable all interrupts */ outl(val, card->io_port + CSR7); - - leave("disable_all_interrupts"); } /* @@ -986,7 +902,6 @@ must be called with the lock held and interrupts disabled. static void enable_common_interrupts(struct xircom_private *card) { unsigned int val; - enter("enable_link_interrupt"); val = inl(card->io_port + CSR7); /* Interrupt enable register */ val |= (1<<16); /* Normal Interrupt Summary */ @@ -998,8 +913,6 @@ static void enable_common_interrupts(struct xircom_private *card) val |= (1<<2); /* Transmit Buffer Unavailable */ val |= (1<<1); /* Transmit Process Stopped */ outl(val, card->io_port + CSR7); - - leave("enable_link_interrupt"); } /* @@ -1010,13 +923,11 @@ must be called with the lock held and interrupts disabled. static int enable_promisc(struct xircom_private *card) { unsigned int val; - enter("enable_promisc"); val = inl(card->io_port + CSR6); val = val | (1 << 6); outl(val, card->io_port + CSR6); - leave("enable_promisc"); return 1; } @@ -1031,7 +942,6 @@ Must be called in locked state with interrupts disabled static int link_status(struct xircom_private *card) { unsigned int val; - enter("link_status"); val = inb(card->io_port + CSR12); @@ -1042,7 +952,6 @@ static int link_status(struct xircom_private *card) /* If we get here -> no link at all */ - leave("link_status"); return 0; } @@ -1061,8 +970,6 @@ static void read_mac_address(struct xircom_private *card) unsigned long flags; int i; - enter("read_mac_address"); - spin_lock_irqsave(&card->lock, flags); outl(1 << 12, card->io_port + CSR9); /* enable boot rom access */ @@ -1090,7 +997,6 @@ static void read_mac_address(struct xircom_private *card) } spin_unlock_irqrestore(&card->lock, flags); pr_debug(" %pM\n", card->dev->dev_addr); - leave("read_mac_address"); } @@ -1103,8 +1009,6 @@ static void transceiver_voodoo(struct xircom_private *card) { unsigned long flags; - enter("transceiver_voodoo"); - /* disable all powermanagement */ pci_write_config_dword(card->pdev, PCI_POWERMGMT, 0x0000); @@ -1122,7 +1026,6 @@ static void transceiver_voodoo(struct xircom_private *card) spin_unlock_irqrestore(&card->lock, flags); netif_start_queue(card->dev); - leave("transceiver_voodoo"); } @@ -1131,8 +1034,6 @@ static void xircom_up(struct xircom_private *card) unsigned long flags; int i; - enter("xircom_up"); - /* disable all powermanagement */ pci_write_config_dword(card->pdev, PCI_POWERMGMT, 0x0000); @@ -1156,7 +1057,6 @@ static void xircom_up(struct xircom_private *card) trigger_receive(card); trigger_transmit(card); netif_start_queue(card->dev); - leave("xircom_up"); } /* Bufferoffset is in BYTES */ @@ -1164,7 +1064,6 @@ static void investigate_read_descriptor(struct net_device *dev,struct xircom_pri { int status; - enter("investigate_read_descriptor"); status = le32_to_cpu(card->rx_buffer[4*descnr]); if ((status > 0)) { /* packet received */ @@ -1197,9 +1096,6 @@ static void investigate_read_descriptor(struct net_device *dev,struct xircom_pri card->rx_buffer[4*descnr] = cpu_to_le32(0x80000000); trigger_receive(card); } - - leave("investigate_read_descriptor"); - } @@ -1208,8 +1104,6 @@ static void investigate_write_descriptor(struct net_device *dev, struct xircom_p { int status; - enter("investigate_write_descriptor"); - status = le32_to_cpu(card->tx_buffer[4*descnr]); #if 0 if (status & 0x8000) { /* Major error */ @@ -1232,8 +1126,6 @@ static void investigate_write_descriptor(struct net_device *dev, struct xircom_p dev->stats.tx_packets++; } - leave("investigate_write_descriptor"); - } -- cgit v0.10.2 From 163ef0b5922b14751e93218bdf2c9fe8f74b9c9d Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Mon, 9 May 2011 09:45:21 +0000 Subject: tulip: Convert printks to netdev_ Use the current more descriptive logging styles. Add pr_fmt and remove PFX where appropriate. Use netif_, netdev_ Indent a few blocks in xircom_cb where appropriate. Signed-off-by: Joe Perches Signed-off-by: David S. Miller diff --git a/drivers/net/tulip/de2104x.c b/drivers/net/tulip/de2104x.c index 46d5a1b..62883a0 100644 --- a/drivers/net/tulip/de2104x.c +++ b/drivers/net/tulip/de2104x.c @@ -27,6 +27,8 @@ */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #define DRV_NAME "de2104x" #define DRV_VERSION "0.7" #define DRV_RELDATE "Mar 17, 2004" @@ -73,8 +75,6 @@ static int rx_copybreak = 100; module_param (rx_copybreak, int, 0); MODULE_PARM_DESC (rx_copybreak, "de2104x Breakpoint at which Rx packets are copied"); -#define PFX DRV_NAME ": " - #define DE_DEF_MSG_ENABLE (NETIF_MSG_DRV | \ NETIF_MSG_PROBE | \ NETIF_MSG_LINK | \ @@ -377,18 +377,16 @@ static u16 t21041_csr15[] = { 0x0008, 0x0006, 0x000E, 0x0008, 0x0008, }; static void de_rx_err_acct (struct de_private *de, unsigned rx_tail, u32 status, u32 len) { - if (netif_msg_rx_err (de)) - printk (KERN_DEBUG - "%s: rx err, slot %d status 0x%x len %d\n", - de->dev->name, rx_tail, status, len); + netif_printk(de, rx_err, KERN_DEBUG, de->dev, + "rx err, slot %d status 0x%x len %d\n", + rx_tail, status, len); if ((status & 0x38000300) != 0x0300) { /* Ingore earlier buffers. */ if ((status & 0xffff) != 0x7fff) { - if (netif_msg_rx_err(de)) - dev_warn(&de->dev->dev, - "Oversized Ethernet frame spanned multiple buffers, status %08x!\n", - status); + netif_warn(de, rx_err, de->dev, + "Oversized Ethernet frame spanned multiple buffers, status %08x!\n", + status); de->net_stats.rx_length_errors++; } } else if (status & RxError) { @@ -491,7 +489,7 @@ rx_next: } if (!rx_work) - dev_warn(&de->dev->dev, "rx work limit reached\n"); + netdev_warn(de->dev, "rx work limit reached\n"); de->rx_tail = rx_tail; } @@ -534,9 +532,9 @@ static irqreturn_t de_interrupt (int irq, void *dev_instance) pci_read_config_word(de->pdev, PCI_STATUS, &pci_status); pci_write_config_word(de->pdev, PCI_STATUS, pci_status); - dev_err(&de->dev->dev, - "PCI bus error, status=%08x, PCI status=%04x\n", - status, pci_status); + netdev_err(de->dev, + "PCI bus error, status=%08x, PCI status=%04x\n", + status, pci_status); } return IRQ_HANDLED; @@ -873,7 +871,7 @@ static void de_stop_rxtx (struct de_private *de) udelay(100); } - dev_warn(&de->dev->dev, "timeout expired stopping DMA\n"); + netdev_warn(de->dev, "timeout expired, stopping DMA\n"); } static inline void de_start_rxtx (struct de_private *de) @@ -907,9 +905,8 @@ static void de_link_up(struct de_private *de) { if (!netif_carrier_ok(de->dev)) { netif_carrier_on(de->dev); - if (netif_msg_link(de)) - dev_info(&de->dev->dev, "link up, media %s\n", - media_name[de->media_type]); + netif_info(de, link, de->dev, "link up, media %s\n", + media_name[de->media_type]); } } @@ -917,8 +914,7 @@ static void de_link_down(struct de_private *de) { if (netif_carrier_ok(de->dev)) { netif_carrier_off(de->dev); - if (netif_msg_link(de)) - dev_info(&de->dev->dev, "link down\n"); + netif_info(de, link, de->dev, "link down\n"); } } @@ -928,8 +924,7 @@ static void de_set_media (struct de_private *de) u32 macmode = dr32(MacMode); if (de_is_running(de)) - dev_warn(&de->dev->dev, - "chip is running while changing media!\n"); + netdev_warn(de->dev, "chip is running while changing media!\n"); if (de->de21040) dw32(CSR11, FULL_DUPLEX_MAGIC); @@ -948,18 +943,13 @@ static void de_set_media (struct de_private *de) else macmode &= ~FullDuplex; - if (netif_msg_link(de)) - dev_info(&de->dev->dev, "set link %s\n", media_name[media]); - if (netif_msg_hw(de)) { - dev_info(&de->dev->dev, "mode 0x%x, sia 0x%x,0x%x,0x%x,0x%x\n", - dr32(MacMode), dr32(SIAStatus), - dr32(CSR13), dr32(CSR14), dr32(CSR15)); - - dev_info(&de->dev->dev, - "set mode 0x%x, set sia 0x%x,0x%x,0x%x\n", - macmode, de->media[media].csr13, - de->media[media].csr14, de->media[media].csr15); - } + netif_info(de, link, de->dev, "set link %s\n", media_name[media]); + netif_info(de, hw, de->dev, "mode 0x%x, sia 0x%x,0x%x,0x%x,0x%x\n", + dr32(MacMode), dr32(SIAStatus), + dr32(CSR13), dr32(CSR14), dr32(CSR15)); + netif_info(de, hw, de->dev, "set mode 0x%x, set sia 0x%x,0x%x,0x%x\n", + macmode, de->media[media].csr13, + de->media[media].csr14, de->media[media].csr15); if (macmode != dr32(MacMode)) dw32(MacMode, macmode); } @@ -996,9 +986,8 @@ static void de21040_media_timer (unsigned long data) if (!netif_carrier_ok(dev)) de_link_up(de); else - if (netif_msg_timer(de)) - dev_info(&dev->dev, "%s link ok, status %x\n", - media_name[de->media_type], status); + netif_info(de, timer, dev, "%s link ok, status %x\n", + media_name[de->media_type], status); return; } @@ -1025,9 +1014,8 @@ no_link_yet: de->media_timer.expires = jiffies + DE_TIMER_NO_LINK; add_timer(&de->media_timer); - if (netif_msg_timer(de)) - dev_info(&dev->dev, "no link, trying media %s, status %x\n", - media_name[de->media_type], status); + netif_info(de, timer, dev, "no link, trying media %s, status %x\n", + media_name[de->media_type], status); } static unsigned int de_ok_to_advertise (struct de_private *de, u32 new_media) @@ -1085,11 +1073,10 @@ static void de21041_media_timer (unsigned long data) if (!netif_carrier_ok(dev)) de_link_up(de); else - if (netif_msg_timer(de)) - dev_info(&dev->dev, - "%s link ok, mode %x status %x\n", - media_name[de->media_type], - dr32(MacMode), status); + netif_info(de, timer, dev, + "%s link ok, mode %x status %x\n", + media_name[de->media_type], + dr32(MacMode), status); return; } @@ -1163,9 +1150,8 @@ no_link_yet: de->media_timer.expires = jiffies + DE_TIMER_NO_LINK; add_timer(&de->media_timer); - if (netif_msg_timer(de)) - dev_info(&dev->dev, "no link, trying media %s, status %x\n", - media_name[de->media_type], status); + netif_info(de, timer, dev, "no link, trying media %s, status %x\n", + media_name[de->media_type], status); } static void de_media_interrupt (struct de_private *de, u32 status) @@ -1401,14 +1387,13 @@ static int de_open (struct net_device *dev) struct de_private *de = netdev_priv(dev); int rc; - if (netif_msg_ifup(de)) - printk(KERN_DEBUG "%s: enabling interface\n", dev->name); + netif_printk(de, ifup, KERN_DEBUG, dev, "enabling interface\n"); de->rx_buf_sz = (dev->mtu <= 1500 ? PKT_BUF_SZ : dev->mtu + 32); rc = de_alloc_rings(de); if (rc) { - dev_err(&dev->dev, "ring allocation failure, err=%d\n", rc); + netdev_err(dev, "ring allocation failure, err=%d\n", rc); return rc; } @@ -1416,14 +1401,14 @@ static int de_open (struct net_device *dev) rc = request_irq(dev->irq, de_interrupt, IRQF_SHARED, dev->name, dev); if (rc) { - dev_err(&dev->dev, "IRQ %d request failure, err=%d\n", - dev->irq, rc); + netdev_err(dev, "IRQ %d request failure, err=%d\n", + dev->irq, rc); goto err_out_free; } rc = de_init_hw(de); if (rc) { - dev_err(&dev->dev, "h/w init failure, err=%d\n", rc); + netdev_err(dev, "h/w init failure, err=%d\n", rc); goto err_out_free_irq; } @@ -1444,8 +1429,7 @@ static int de_close (struct net_device *dev) struct de_private *de = netdev_priv(dev); unsigned long flags; - if (netif_msg_ifdown(de)) - printk(KERN_DEBUG "%s: disabling interface\n", dev->name); + netif_printk(de, ifdown, KERN_DEBUG, dev, "disabling interface\n"); del_timer_sync(&de->media_timer); @@ -1466,9 +1450,10 @@ static void de_tx_timeout (struct net_device *dev) { struct de_private *de = netdev_priv(dev); - printk(KERN_DEBUG "%s: NIC status %08x mode %08x sia %08x desc %u/%u/%u\n", - dev->name, dr32(MacStatus), dr32(MacMode), dr32(SIAStatus), - de->rx_tail, de->tx_head, de->tx_tail); + netdev_printk(KERN_DEBUG, dev, + "NIC status %08x mode %08x sia %08x desc %u/%u/%u\n", + dr32(MacStatus), dr32(MacMode), dr32(SIAStatus), + de->rx_tail, de->tx_head, de->tx_tail); del_timer_sync(&de->media_timer); @@ -1693,9 +1678,8 @@ static int de_nway_reset(struct net_device *dev) status = dr32(SIAStatus); dw32(SIAStatus, (status & ~NWayState) | NWayRestart); - if (netif_msg_link(de)) - dev_info(&de->dev->dev, "link nway restart, status %x,%x\n", - status, dr32(SIAStatus)); + netif_info(de, link, dev, "link nway restart, status %x,%x\n", + status, dr32(SIAStatus)); return 0; } @@ -1740,7 +1724,8 @@ static void __devinit de21040_get_mac_address (struct de_private *de) de->dev->dev_addr[i] = value; udelay(1); if (boguscnt <= 0) - pr_warning(PFX "timeout reading 21040 MAC address byte %u\n", i); + pr_warn("timeout reading 21040 MAC address byte %u\n", + i); } } @@ -1926,8 +1911,10 @@ static void __devinit de21041_get_srom_info (struct de_private *de) de->media[idx].csr14, de->media[idx].csr15); - } else if (netif_msg_probe(de)) - pr_cont("\n"); + } else { + if (netif_msg_probe(de)) + pr_cont("\n"); + } if (bufp > ((void *)&ee_data[DE_EEPROM_SIZE - 3])) break; @@ -2038,7 +2025,7 @@ static int __devinit de_init_one (struct pci_dev *pdev, /* check for invalid IRQ value */ if (pdev->irq < 2) { rc = -EIO; - pr_err(PFX "invalid irq (%d) for pci dev %s\n", + pr_err("invalid irq (%d) for pci dev %s\n", pdev->irq, pci_name(pdev)); goto err_out_res; } @@ -2049,12 +2036,12 @@ static int __devinit de_init_one (struct pci_dev *pdev, pciaddr = pci_resource_start(pdev, 1); if (!pciaddr) { rc = -EIO; - pr_err(PFX "no MMIO resource for pci dev %s\n", pci_name(pdev)); + pr_err("no MMIO resource for pci dev %s\n", pci_name(pdev)); goto err_out_res; } if (pci_resource_len(pdev, 1) < DE_REGS_SIZE) { rc = -EIO; - pr_err(PFX "MMIO resource (%llx) too small on pci dev %s\n", + pr_err("MMIO resource (%llx) too small on pci dev %s\n", (unsigned long long)pci_resource_len(pdev, 1), pci_name(pdev)); goto err_out_res; @@ -2064,7 +2051,7 @@ static int __devinit de_init_one (struct pci_dev *pdev, regs = ioremap_nocache(pciaddr, DE_REGS_SIZE); if (!regs) { rc = -EIO; - pr_err(PFX "Cannot map PCI MMIO (%llx@%lx) on pci dev %s\n", + pr_err("Cannot map PCI MMIO (%llx@%lx) on pci dev %s\n", (unsigned long long)pci_resource_len(pdev, 1), pciaddr, pci_name(pdev)); goto err_out_res; @@ -2077,7 +2064,7 @@ static int __devinit de_init_one (struct pci_dev *pdev, /* make sure hardware is not running */ rc = de_reset_mac(de); if (rc) { - pr_err(PFX "Cannot reset MAC, pci dev %s\n", pci_name(pdev)); + pr_err("Cannot reset MAC, pci dev %s\n", pci_name(pdev)); goto err_out_iomap; } @@ -2097,11 +2084,11 @@ static int __devinit de_init_one (struct pci_dev *pdev, goto err_out_iomap; /* print info about board and interface just registered */ - dev_info(&dev->dev, "%s at 0x%lx, %pM, IRQ %d\n", - de->de21040 ? "21040" : "21041", - dev->base_addr, - dev->dev_addr, - dev->irq); + netdev_info(dev, "%s at 0x%lx, %pM, IRQ %d\n", + de->de21040 ? "21040" : "21041", + dev->base_addr, + dev->dev_addr, + dev->irq); pci_set_drvdata(pdev, dev); @@ -2189,7 +2176,7 @@ static int de_resume (struct pci_dev *pdev) if (!netif_running(dev)) goto out_attach; if ((retval = pci_enable_device(pdev))) { - dev_err(&dev->dev, "pci_enable_device failed in resume\n"); + netdev_err(dev, "pci_enable_device failed in resume\n"); goto out; } pci_set_master(pdev); diff --git a/drivers/net/tulip/dmfe.c b/drivers/net/tulip/dmfe.c index fb07f48..96e8541 100644 --- a/drivers/net/tulip/dmfe.c +++ b/drivers/net/tulip/dmfe.c @@ -406,7 +406,7 @@ static int __devinit dmfe_init_one (struct pci_dev *pdev, SET_NETDEV_DEV(dev, &pdev->dev); if (pci_set_dma_mask(pdev, DMA_BIT_MASK(32))) { - pr_warning("32-bit PCI DMA not available\n"); + pr_warn("32-bit PCI DMA not available\n"); err = -ENODEV; goto err_out_free; } diff --git a/drivers/net/tulip/eeprom.c b/drivers/net/tulip/eeprom.c index 296486b..fa5eee9 100644 --- a/drivers/net/tulip/eeprom.c +++ b/drivers/net/tulip/eeprom.c @@ -222,8 +222,8 @@ subsequent_board: /* there is no phy information, don't even try to build mtable */ if (count == 0) { if (tulip_debug > 0) - pr_warning("%s: no phy info, aborting mtable build\n", - dev->name); + pr_warn("%s: no phy info, aborting mtable build\n", + dev->name); return; } diff --git a/drivers/net/tulip/tulip_core.c b/drivers/net/tulip/tulip_core.c index 5c01e26..f46898a 100644 --- a/drivers/net/tulip/tulip_core.c +++ b/drivers/net/tulip/tulip_core.c @@ -12,6 +12,7 @@ Please submit bugs to http://bugzilla.kernel.org/ . */ +#define pr_fmt(fmt) "tulip: " fmt #define DRV_NAME "tulip" #ifdef CONFIG_TULIP_NAPI @@ -119,8 +120,6 @@ module_param(csr0, int, 0); module_param_array(options, int, NULL, 0); module_param_array(full_duplex, int, NULL, 0); -#define PFX DRV_NAME ": " - #ifdef TULIP_DEBUG int tulip_debug = TULIP_DEBUG; #else @@ -1340,13 +1339,13 @@ static int __devinit tulip_init_one (struct pci_dev *pdev, */ if (pdev->subsystem_vendor == PCI_VENDOR_ID_LMC) { - pr_err(PFX "skipping LMC card\n"); + pr_err("skipping LMC card\n"); return -ENODEV; } else if (pdev->subsystem_vendor == PCI_VENDOR_ID_SBE && (pdev->subsystem_device == PCI_SUBDEVICE_ID_SBE_T3E3 || pdev->subsystem_device == PCI_SUBDEVICE_ID_SBE_2T3E3_P0 || pdev->subsystem_device == PCI_SUBDEVICE_ID_SBE_2T3E3_P1)) { - pr_err(PFX "skipping SBE T3E3 port\n"); + pr_err("skipping SBE T3E3 port\n"); return -ENODEV; } @@ -1362,13 +1361,13 @@ static int __devinit tulip_init_one (struct pci_dev *pdev, if (pdev->vendor == 0x1282 && pdev->device == 0x9100 && pdev->revision < 0x30) { - pr_info(PFX "skipping early DM9100 with Crc bug (use dmfe)\n"); + pr_info("skipping early DM9100 with Crc bug (use dmfe)\n"); return -ENODEV; } dp = pci_device_to_OF_node(pdev); if (!(dp && of_get_property(dp, "local-mac-address", NULL))) { - pr_info(PFX "skipping DM910x expansion card (use dmfe)\n"); + pr_info("skipping DM910x expansion card (use dmfe)\n"); return -ENODEV; } } @@ -1415,16 +1414,14 @@ static int __devinit tulip_init_one (struct pci_dev *pdev, i = pci_enable_device(pdev); if (i) { - pr_err(PFX "Cannot enable tulip board #%d, aborting\n", - board_idx); + pr_err("Cannot enable tulip board #%d, aborting\n", board_idx); return i; } /* The chip will fail to enter a low-power state later unless * first explicitly commanded into D0 */ if (pci_set_power_state(pdev, PCI_D0)) { - printk (KERN_NOTICE PFX - "Failed to set power state to D0\n"); + pr_notice("Failed to set power state to D0\n"); } irq = pdev->irq; @@ -1432,13 +1429,13 @@ static int __devinit tulip_init_one (struct pci_dev *pdev, /* alloc_etherdev ensures aligned and zeroed private structures */ dev = alloc_etherdev (sizeof (*tp)); if (!dev) { - pr_err(PFX "ether device alloc failed, aborting\n"); + pr_err("ether device alloc failed, aborting\n"); return -ENOMEM; } SET_NETDEV_DEV(dev, &pdev->dev); if (pci_resource_len (pdev, 0) < tulip_tbl[chip_idx].io_size) { - pr_err(PFX "%s: I/O region (0x%llx@0x%llx) too small, aborting\n", + pr_err("%s: I/O region (0x%llx@0x%llx) too small, aborting\n", pci_name(pdev), (unsigned long long)pci_resource_len (pdev, 0), (unsigned long long)pci_resource_start (pdev, 0)); @@ -1905,12 +1902,12 @@ static int tulip_resume(struct pci_dev *pdev) return 0; if ((retval = pci_enable_device(pdev))) { - pr_err(PFX "pci_enable_device failed in resume\n"); + pr_err("pci_enable_device failed in resume\n"); return retval; } if ((retval = request_irq(dev->irq, tulip_interrupt, IRQF_SHARED, dev->name, dev))) { - pr_err(PFX "request_irq failed in resume\n"); + pr_err("request_irq failed in resume\n"); return retval; } diff --git a/drivers/net/tulip/uli526x.c b/drivers/net/tulip/uli526x.c index a4375c4..92c00ee 100644 --- a/drivers/net/tulip/uli526x.c +++ b/drivers/net/tulip/uli526x.c @@ -292,7 +292,7 @@ static int __devinit uli526x_init_one (struct pci_dev *pdev, SET_NETDEV_DEV(dev, &pdev->dev); if (pci_set_dma_mask(pdev, DMA_BIT_MASK(32))) { - pr_warning("32-bit PCI DMA not available\n"); + pr_warn("32-bit PCI DMA not available\n"); err = -ENODEV; goto err_out_free; } @@ -390,9 +390,9 @@ static int __devinit uli526x_init_one (struct pci_dev *pdev, if (err) goto err_out_res; - dev_info(&dev->dev, "ULi M%04lx at pci%s, %pM, irq %d\n", - ent->driver_data >> 16, pci_name(pdev), - dev->dev_addr, dev->irq); + netdev_info(dev, "ULi M%04lx at pci%s, %pM, irq %d\n", + ent->driver_data >> 16, pci_name(pdev), + dev->dev_addr, dev->irq); pci_set_master(pdev); @@ -524,7 +524,7 @@ static void uli526x_init(struct net_device *dev) } } if(phy_tmp == 32) - pr_warning("Can not find the phy address!!!"); + pr_warn("Can not find the phy address!!!\n"); /* Parser SROM and media mode */ db->media_mode = uli526x_media_mode; @@ -590,7 +590,7 @@ static netdev_tx_t uli526x_start_xmit(struct sk_buff *skb, /* Too large packet check */ if (skb->len > MAX_PACKET_SIZE) { - pr_err("big packet = %d\n", (u16)skb->len); + netdev_err(dev, "big packet = %d\n", (u16)skb->len); dev_kfree_skb(skb); return NETDEV_TX_OK; } @@ -600,7 +600,7 @@ static netdev_tx_t uli526x_start_xmit(struct sk_buff *skb, /* No Tx resource check, it never happen nromally */ if (db->tx_packet_cnt >= TX_FREE_DESC_CNT) { spin_unlock_irqrestore(&db->lock, flags); - pr_err("No Tx resource %ld\n", db->tx_packet_cnt); + netdev_err(dev, "No Tx resource %ld\n", db->tx_packet_cnt); return NETDEV_TX_BUSY; } @@ -1024,7 +1024,6 @@ static void uli526x_timer(unsigned long data) struct net_device *dev = (struct net_device *) data; struct uli526x_board_info *db = netdev_priv(dev); unsigned long flags; - u8 TmpSpeed=10; //ULI526X_DBUG(0, "uli526x_timer()", 0); spin_lock_irqsave(&db->lock, flags); @@ -1070,7 +1069,7 @@ static void uli526x_timer(unsigned long data) /* Link Failed */ ULI526X_DBUG(0, "Link Failed", tmp_cr12); netif_carrier_off(dev); - pr_info("%s NIC Link is Down\n",dev->name); + netdev_info(dev, "NIC Link is Down\n"); db->link_failed = 1; /* For Force 10/100M Half/Full mode: Enable Auto-Nego mode */ @@ -1096,18 +1095,13 @@ static void uli526x_timer(unsigned long data) if(db->link_failed==0) { - if(db->op_mode==ULI526X_100MHF || db->op_mode==ULI526X_100MFD) - { - TmpSpeed = 100; - } - if(db->op_mode==ULI526X_10MFD || db->op_mode==ULI526X_100MFD) - { - pr_info("%s NIC Link is Up %d Mbps Full duplex\n",dev->name,TmpSpeed); - } - else - { - pr_info("%s NIC Link is Up %d Mbps Half duplex\n",dev->name,TmpSpeed); - } + netdev_info(dev, "NIC Link is Up %d Mbps %s duplex\n", + (db->op_mode == ULI526X_100MHF || + db->op_mode == ULI526X_100MFD) + ? 100 : 10, + (db->op_mode == ULI526X_10MFD || + db->op_mode == ULI526X_100MFD) + ? "Full" : "Half"); netif_carrier_on(dev); } /* SHOW_MEDIA_TYPE(db->op_mode); */ @@ -1116,7 +1110,7 @@ static void uli526x_timer(unsigned long data) { if(db->init==1) { - pr_info("%s NIC Link is Down\n",dev->name); + netdev_info(dev, "NIC Link is Down\n"); netif_carrier_off(dev); } } @@ -1242,7 +1236,7 @@ static int uli526x_resume(struct pci_dev *pdev) err = pci_set_power_state(pdev, PCI_D0); if (err) { - dev_warn(&dev->dev, "Could not put device into D0\n"); + netdev_warn(dev, "Could not put device into D0\n"); return err; } @@ -1443,7 +1437,7 @@ static void send_filter_frame(struct net_device *dev, int mc_cnt) update_cr6(db->cr6_data, dev->base_addr); dev->trans_start = jiffies; } else - pr_err("No Tx resource - Send_filter_frame!\n"); + netdev_err(dev, "No Tx resource - Send_filter_frame!\n"); } diff --git a/drivers/net/tulip/winbond-840.c b/drivers/net/tulip/winbond-840.c index f0b2310..939c96e 100644 --- a/drivers/net/tulip/winbond-840.c +++ b/drivers/net/tulip/winbond-840.c @@ -44,6 +44,8 @@ * Wake-On-LAN */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #define DRV_NAME "winbond-840" #define DRV_VERSION "1.01-e" #define DRV_RELDATE "Sep-11-2006" @@ -375,8 +377,8 @@ static int __devinit w840_probe1 (struct pci_dev *pdev, irq = pdev->irq; if (pci_set_dma_mask(pdev, DMA_BIT_MASK(32))) { - pr_warning("Winbond-840: Device %s disabled due to DMA limitations\n", - pci_name(pdev)); + pr_warn("Device %s disabled due to DMA limitations\n", + pci_name(pdev)); return -EIO; } dev = alloc_etherdev(sizeof(*np)); diff --git a/drivers/net/tulip/xircom_cb.c b/drivers/net/tulip/xircom_cb.c index d0d0cbe..7e82872 100644 --- a/drivers/net/tulip/xircom_cb.c +++ b/drivers/net/tulip/xircom_cb.c @@ -262,8 +262,8 @@ static int __devinit xircom_probe(struct pci_dev *pdev, const struct pci_device_ goto reg_fail; } - dev_info(&dev->dev, "Xircom cardbus revision %i at irq %i\n", - pdev->revision, pdev->irq); + netdev_info(dev, "Xircom cardbus revision %i at irq %i\n", + pdev->revision, pdev->irq); /* start the transmitter to get a heartbeat */ /* TODO: send 2 dummy packets here */ transceiver_voodoo(private); @@ -335,7 +335,7 @@ static irqreturn_t xircom_interrupt(int irq, void *dev_instance) int newlink; printk(KERN_DEBUG "xircom_cb: Link status has changed\n"); newlink = link_status(card); - dev_info(&dev->dev, "Link is %i mbit\n", newlink); + netdev_info(dev, "Link is %d mbit\n", newlink); if (newlink) netif_carrier_on(dev); else @@ -426,8 +426,8 @@ static int xircom_open(struct net_device *dev) struct xircom_private *xp = netdev_priv(dev); int retval; - pr_info("xircom cardbus adaptor found, registering as %s, using irq %i\n", - dev->name, dev->irq); + netdev_info(dev, "xircom cardbus adaptor found, using irq %i\n", + dev->irq); retval = request_irq(dev->irq, xircom_interrupt, IRQF_SHARED, dev->name, dev); if (retval) return retval; @@ -703,7 +703,7 @@ static void activate_receiver(struct xircom_private *card) udelay(50); counter--; if (counter <= 0) - pr_err("Receiver failed to deactivate\n"); + netdev_err(card->dev, "Receiver failed to deactivate\n"); } /* enable the receiver */ @@ -720,7 +720,8 @@ static void activate_receiver(struct xircom_private *card) udelay(50); counter--; if (counter <= 0) - pr_err("Receiver failed to re-activate\n"); + netdev_err(card->dev, + "Receiver failed to re-activate\n"); } } @@ -748,7 +749,7 @@ static void deactivate_receiver(struct xircom_private *card) udelay(50); counter--; if (counter <= 0) - pr_err("Receiver failed to deactivate\n"); + netdev_err(card->dev, "Receiver failed to deactivate\n"); } } @@ -786,7 +787,8 @@ static void activate_transmitter(struct xircom_private *card) udelay(50); counter--; if (counter <= 0) - pr_err("Transmitter failed to deactivate\n"); + netdev_err(card->dev, + "Transmitter failed to deactivate\n"); } /* enable the transmitter */ @@ -803,7 +805,8 @@ static void activate_transmitter(struct xircom_private *card) udelay(50); counter--; if (counter <= 0) - pr_err("Transmitter failed to re-activate\n"); + netdev_err(card->dev, + "Transmitter failed to re-activate\n"); } } @@ -831,7 +834,8 @@ static void deactivate_transmitter(struct xircom_private *card) udelay(50); counter--; if (counter <= 0) - pr_err("Transmitter failed to deactivate\n"); + netdev_err(card->dev, + "Transmitter failed to deactivate\n"); } } @@ -1060,75 +1064,81 @@ static void xircom_up(struct xircom_private *card) } /* Bufferoffset is in BYTES */ -static void investigate_read_descriptor(struct net_device *dev,struct xircom_private *card, int descnr, unsigned int bufferoffset) +static void +investigate_read_descriptor(struct net_device *dev, struct xircom_private *card, + int descnr, unsigned int bufferoffset) { - int status; + int status; - status = le32_to_cpu(card->rx_buffer[4*descnr]); + status = le32_to_cpu(card->rx_buffer[4*descnr]); - if ((status > 0)) { /* packet received */ + if (status > 0) { /* packet received */ - /* TODO: discard error packets */ + /* TODO: discard error packets */ - short pkt_len = ((status >> 16) & 0x7ff) - 4; /* minus 4, we don't want the CRC */ - struct sk_buff *skb; + short pkt_len = ((status >> 16) & 0x7ff) - 4; + /* minus 4, we don't want the CRC */ + struct sk_buff *skb; - if (pkt_len > 1518) { - pr_err("Packet length %i is bogus\n", pkt_len); - pkt_len = 1518; - } + if (pkt_len > 1518) { + netdev_err(dev, "Packet length %i is bogus\n", pkt_len); + pkt_len = 1518; + } - skb = dev_alloc_skb(pkt_len + 2); - if (skb == NULL) { - dev->stats.rx_dropped++; - goto out; - } - skb_reserve(skb, 2); - skb_copy_to_linear_data(skb, (unsigned char*)&card->rx_buffer[bufferoffset / 4], pkt_len); - skb_put(skb, pkt_len); - skb->protocol = eth_type_trans(skb, dev); - netif_rx(skb); - dev->stats.rx_packets++; - dev->stats.rx_bytes += pkt_len; - - out: - /* give the buffer back to the card */ - card->rx_buffer[4*descnr] = cpu_to_le32(0x80000000); - trigger_receive(card); + skb = dev_alloc_skb(pkt_len + 2); + if (skb == NULL) { + dev->stats.rx_dropped++; + goto out; } + skb_reserve(skb, 2); + skb_copy_to_linear_data(skb, + &card->rx_buffer[bufferoffset / 4], + pkt_len); + skb_put(skb, pkt_len); + skb->protocol = eth_type_trans(skb, dev); + netif_rx(skb); + dev->stats.rx_packets++; + dev->stats.rx_bytes += pkt_len; + +out: + /* give the buffer back to the card */ + card->rx_buffer[4*descnr] = cpu_to_le32(0x80000000); + trigger_receive(card); + } } /* Bufferoffset is in BYTES */ -static void investigate_write_descriptor(struct net_device *dev, struct xircom_private *card, int descnr, unsigned int bufferoffset) +static void +investigate_write_descriptor(struct net_device *dev, + struct xircom_private *card, + int descnr, unsigned int bufferoffset) { - int status; + int status; - status = le32_to_cpu(card->tx_buffer[4*descnr]); + status = le32_to_cpu(card->tx_buffer[4*descnr]); #if 0 - if (status & 0x8000) { /* Major error */ - pr_err("Major transmit error status %x\n", status); - card->tx_buffer[4*descnr] = 0; - netif_wake_queue (dev); - } + if (status & 0x8000) { /* Major error */ + pr_err("Major transmit error status %x\n", status); + card->tx_buffer[4*descnr] = 0; + netif_wake_queue (dev); + } #endif - if (status > 0) { /* bit 31 is 0 when done */ - if (card->tx_skb[descnr]!=NULL) { - dev->stats.tx_bytes += card->tx_skb[descnr]->len; - dev_kfree_skb_irq(card->tx_skb[descnr]); - } - card->tx_skb[descnr] = NULL; - /* Bit 8 in the status field is 1 if there was a collision */ - if (status&(1<<8)) - dev->stats.collisions++; - card->tx_buffer[4*descnr] = 0; /* descriptor is free again */ - netif_wake_queue (dev); - dev->stats.tx_packets++; + if (status > 0) { /* bit 31 is 0 when done */ + if (card->tx_skb[descnr]!=NULL) { + dev->stats.tx_bytes += card->tx_skb[descnr]->len; + dev_kfree_skb_irq(card->tx_skb[descnr]); } - + card->tx_skb[descnr] = NULL; + /* Bit 8 in the status field is 1 if there was a collision */ + if (status & (1 << 8)) + dev->stats.collisions++; + card->tx_buffer[4*descnr] = 0; /* descriptor is free again */ + netif_wake_queue (dev); + dev->stats.tx_packets++; + } } - static int __init xircom_init(void) { return pci_register_driver(&xircom_ops); -- cgit v0.10.2 From 726b65ad444dd142e34d0087fcbba03d16b34ca6 Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Mon, 9 May 2011 09:45:22 +0000 Subject: tulip: Convert uses of KERN_DEBUG Convert logging messages to more current styles. Added -DDEBUG to Makefile to maintain current message logging. This could be converted to a specific CONFIG_TULIP_DEBUG option. Signed-off-by: Joe Perches Signed-off-by: David S. Miller diff --git a/drivers/net/tulip/21142.c b/drivers/net/tulip/21142.c index 007d8e7..092c3fa 100644 --- a/drivers/net/tulip/21142.c +++ b/drivers/net/tulip/21142.c @@ -122,8 +122,8 @@ void t21142_start_nway(struct net_device *dev) tp->nway = tp->mediasense = 1; tp->nwayset = tp->lpar = 0; if (tulip_debug > 1) - printk(KERN_DEBUG "%s: Restarting 21143 autonegotiation, csr14=%08x\n", - dev->name, csr14); + netdev_dbg(dev, "Restarting 21143 autonegotiation, csr14=%08x\n", + csr14); iowrite32(0x0001, ioaddr + CSR13); udelay(100); iowrite32(csr14, ioaddr + CSR14); @@ -206,14 +206,14 @@ void t21142_lnk_change(struct net_device *dev, int csr5) #if 0 /* Restart shouldn't be needed. */ iowrite32(tp->csr6 | RxOn, ioaddr + CSR6); if (tulip_debug > 2) - printk(KERN_DEBUG "%s: Restarting Tx and Rx, CSR5 is %08x\n", - dev->name, ioread32(ioaddr + CSR5)); + netdev_dbg(dev, " Restarting Tx and Rx, CSR5 is %08x\n", + ioread32(ioaddr + CSR5)); #endif tulip_start_rxtx(tp); if (tulip_debug > 2) - printk(KERN_DEBUG "%s: Setting CSR6 %08x/%x CSR12 %08x\n", - dev->name, tp->csr6, ioread32(ioaddr + CSR6), - ioread32(ioaddr + CSR12)); + netdev_dbg(dev, " Setting CSR6 %08x/%x CSR12 %08x\n", + tp->csr6, ioread32(ioaddr + CSR6), + ioread32(ioaddr + CSR12)); } else if ((tp->nwayset && (csr5 & 0x08000000) && (dev->if_port == 3 || dev->if_port == 5) && (csr12 & 2) == 2) || diff --git a/drivers/net/tulip/Makefile b/drivers/net/tulip/Makefile index 200cbf7..5e8be38 100644 --- a/drivers/net/tulip/Makefile +++ b/drivers/net/tulip/Makefile @@ -2,6 +2,8 @@ # Makefile for the Linux "Tulip" family network device drivers. # +ccflags-$(CONFIG_NET_TULIP) := -DDEBUG + obj-$(CONFIG_PCMCIA_XIRCOM) += xircom_cb.o obj-$(CONFIG_DM9102) += dmfe.o obj-$(CONFIG_WINBOND_840) += winbond-840.o diff --git a/drivers/net/tulip/de2104x.c b/drivers/net/tulip/de2104x.c index 62883a0..e925c1e 100644 --- a/drivers/net/tulip/de2104x.c +++ b/drivers/net/tulip/de2104x.c @@ -377,9 +377,9 @@ static u16 t21041_csr15[] = { 0x0008, 0x0006, 0x000E, 0x0008, 0x0008, }; static void de_rx_err_acct (struct de_private *de, unsigned rx_tail, u32 status, u32 len) { - netif_printk(de, rx_err, KERN_DEBUG, de->dev, - "rx err, slot %d status 0x%x len %d\n", - rx_tail, status, len); + netif_dbg(de, rx_err, de->dev, + "rx err, slot %d status 0x%x len %d\n", + rx_tail, status, len); if ((status & 0x38000300) != 0x0300) { /* Ingore earlier buffers. */ @@ -433,10 +433,9 @@ static void de_rx (struct de_private *de) copying_skb = (len <= rx_copybreak); - if (unlikely(netif_msg_rx_status(de))) - printk(KERN_DEBUG "%s: rx slot %d status 0x%x len %d copying? %d\n", - de->dev->name, rx_tail, status, len, - copying_skb); + netif_dbg(de, rx_status, de->dev, + "rx slot %d status 0x%x len %d copying? %d\n", + rx_tail, status, len, copying_skb); buflen = copying_skb ? (len + RX_OFFSET) : de->rx_buf_sz; copy_skb = dev_alloc_skb (buflen); @@ -504,10 +503,9 @@ static irqreturn_t de_interrupt (int irq, void *dev_instance) if ((!(status & (IntrOK|IntrErr))) || (status == 0xFFFF)) return IRQ_NONE; - if (netif_msg_intr(de)) - printk(KERN_DEBUG "%s: intr, status %08x mode %08x desc %u/%u/%u\n", - dev->name, status, dr32(MacMode), - de->rx_tail, de->tx_head, de->tx_tail); + netif_dbg(de, intr, dev, "intr, status %08x mode %08x desc %u/%u/%u\n", + status, dr32(MacMode), + de->rx_tail, de->tx_head, de->tx_tail); dw32(MacStatus, status); @@ -570,9 +568,9 @@ static void de_tx (struct de_private *de) if (status & LastFrag) { if (status & TxError) { - if (netif_msg_tx_err(de)) - printk(KERN_DEBUG "%s: tx err, status 0x%x\n", - de->dev->name, status); + netif_dbg(de, tx_err, de->dev, + "tx err, status 0x%x\n", + status); de->net_stats.tx_errors++; if (status & TxOWC) de->net_stats.tx_window_errors++; @@ -585,9 +583,8 @@ static void de_tx (struct de_private *de) } else { de->net_stats.tx_packets++; de->net_stats.tx_bytes += skb->len; - if (netif_msg_tx_done(de)) - printk(KERN_DEBUG "%s: tx done, slot %d\n", - de->dev->name, tx_tail); + netif_dbg(de, tx_done, de->dev, + "tx done, slot %d\n", tx_tail); } dev_kfree_skb_irq(skb); } @@ -644,9 +641,8 @@ static netdev_tx_t de_start_xmit (struct sk_buff *skb, wmb(); de->tx_head = NEXT_TX(entry); - if (netif_msg_tx_queued(de)) - printk(KERN_DEBUG "%s: tx queued, slot %d, skblen %d\n", - dev->name, entry, skb->len); + netif_dbg(de, tx_queued, dev, "tx queued, slot %d, skblen %d\n", + entry, skb->len); if (tx_free == 0) netif_stop_queue(dev); @@ -1387,7 +1383,7 @@ static int de_open (struct net_device *dev) struct de_private *de = netdev_priv(dev); int rc; - netif_printk(de, ifup, KERN_DEBUG, dev, "enabling interface\n"); + netif_dbg(de, ifup, dev, "enabling interface\n"); de->rx_buf_sz = (dev->mtu <= 1500 ? PKT_BUF_SZ : dev->mtu + 32); @@ -1429,7 +1425,7 @@ static int de_close (struct net_device *dev) struct de_private *de = netdev_priv(dev); unsigned long flags; - netif_printk(de, ifdown, KERN_DEBUG, dev, "disabling interface\n"); + netif_dbg(de, ifdown, dev, "disabling interface\n"); del_timer_sync(&de->media_timer); @@ -1450,10 +1446,9 @@ static void de_tx_timeout (struct net_device *dev) { struct de_private *de = netdev_priv(dev); - netdev_printk(KERN_DEBUG, dev, - "NIC status %08x mode %08x sia %08x desc %u/%u/%u\n", - dr32(MacStatus), dr32(MacMode), dr32(SIAStatus), - de->rx_tail, de->tx_head, de->tx_tail); + netdev_dbg(dev, "NIC status %08x mode %08x sia %08x desc %u/%u/%u\n", + dr32(MacStatus), dr32(MacMode), dr32(SIAStatus), + de->rx_tail, de->tx_head, de->tx_tail); del_timer_sync(&de->media_timer); diff --git a/drivers/net/tulip/interrupt.c b/drivers/net/tulip/interrupt.c index 0013642..5350d75 100644 --- a/drivers/net/tulip/interrupt.c +++ b/drivers/net/tulip/interrupt.c @@ -125,12 +125,12 @@ int tulip_poll(struct napi_struct *napi, int budget) #endif if (tulip_debug > 4) - printk(KERN_DEBUG " In tulip_rx(), entry %d %08x\n", - entry, tp->rx_ring[entry].status); + netdev_dbg(dev, " In tulip_rx(), entry %d %08x\n", + entry, tp->rx_ring[entry].status); do { if (ioread32(tp->base_addr + CSR5) == 0xffffffff) { - printk(KERN_DEBUG " In tulip_poll(), hardware disappeared\n"); + netdev_dbg(dev, " In tulip_poll(), hardware disappeared\n"); break; } /* Acknowledge current RX interrupt sources. */ @@ -145,9 +145,9 @@ int tulip_poll(struct napi_struct *napi, int budget) if (tp->dirty_rx + RX_RING_SIZE == tp->cur_rx) break; - if (tulip_debug > 5) - printk(KERN_DEBUG "%s: In tulip_rx(), entry %d %08x\n", - dev->name, entry, status); + if (tulip_debug > 5) + netdev_dbg(dev, "In tulip_rx(), entry %d %08x\n", + entry, status); if (++work_done >= budget) goto not_done; @@ -184,9 +184,9 @@ int tulip_poll(struct napi_struct *napi, int budget) } } else { /* There was a fatal error. */ - if (tulip_debug > 2) - printk(KERN_DEBUG "%s: Receive error, Rx status %08x\n", - dev->name, status); + if (tulip_debug > 2) + netdev_dbg(dev, "Receive error, Rx status %08x\n", + status); dev->stats.rx_errors++; /* end of a packet.*/ if (pkt_len > 1518 || (status & RxDescRunt)) @@ -367,16 +367,16 @@ static int tulip_rx(struct net_device *dev) int received = 0; if (tulip_debug > 4) - printk(KERN_DEBUG " In tulip_rx(), entry %d %08x\n", - entry, tp->rx_ring[entry].status); + netdev_dbg(dev, "In tulip_rx(), entry %d %08x\n", + entry, tp->rx_ring[entry].status); /* If we own the next entry, it is a new packet. Send it up. */ while ( ! (tp->rx_ring[entry].status & cpu_to_le32(DescOwned))) { s32 status = le32_to_cpu(tp->rx_ring[entry].status); short pkt_len; if (tulip_debug > 5) - printk(KERN_DEBUG "%s: In tulip_rx(), entry %d %08x\n", - dev->name, entry, status); + netdev_dbg(dev, "In tulip_rx(), entry %d %08x\n", + entry, status); if (--rx_work_limit < 0) break; @@ -404,16 +404,16 @@ static int tulip_rx(struct net_device *dev) /* Ingore earlier buffers. */ if ((status & 0xffff) != 0x7fff) { if (tulip_debug > 1) - dev_warn(&dev->dev, - "Oversized Ethernet frame spanned multiple buffers, status %08x!\n", - status); + netdev_warn(dev, + "Oversized Ethernet frame spanned multiple buffers, status %08x!\n", + status); dev->stats.rx_length_errors++; } } else { /* There was a fatal error. */ if (tulip_debug > 2) - printk(KERN_DEBUG "%s: Receive error, Rx status %08x\n", - dev->name, status); + netdev_dbg(dev, "Receive error, Rx status %08x\n", + status); dev->stats.rx_errors++; /* end of a packet.*/ if (pkt_len > 1518 || (status & RxDescRunt)) @@ -573,8 +573,8 @@ irqreturn_t tulip_interrupt(int irq, void *dev_instance) #endif /* CONFIG_TULIP_NAPI */ if (tulip_debug > 4) - printk(KERN_DEBUG "%s: interrupt csr5=%#8.8x new csr5=%#8.8x\n", - dev->name, csr5, ioread32(ioaddr + CSR5)); + netdev_dbg(dev, "interrupt csr5=%#8.8x new csr5=%#8.8x\n", + csr5, ioread32(ioaddr + CSR5)); if (csr5 & (TxNoBuf | TxDied | TxIntr | TimerInt)) { @@ -605,8 +605,8 @@ irqreturn_t tulip_interrupt(int irq, void *dev_instance) /* There was an major error, log it. */ #ifndef final_version if (tulip_debug > 1) - printk(KERN_DEBUG "%s: Transmit error, Tx status %08x\n", - dev->name, status); + netdev_dbg(dev, "Transmit error, Tx status %08x\n", + status); #endif dev->stats.tx_errors++; if (status & 0x4104) @@ -804,8 +804,8 @@ irqreturn_t tulip_interrupt(int irq, void *dev_instance) } if (tulip_debug > 4) - printk(KERN_DEBUG "%s: exiting interrupt, csr5=%#04x\n", - dev->name, ioread32(ioaddr + CSR5)); + netdev_dbg(dev, "exiting interrupt, csr5=%#04x\n", + ioread32(ioaddr + CSR5)); return IRQ_HANDLED; } diff --git a/drivers/net/tulip/media.c b/drivers/net/tulip/media.c index a0c770e..4bd1392 100644 --- a/drivers/net/tulip/media.c +++ b/drivers/net/tulip/media.c @@ -182,8 +182,8 @@ void tulip_select_media(struct net_device *dev, int startup) switch (mleaf->type) { case 0: /* 21140 non-MII xcvr. */ if (tulip_debug > 1) - printk(KERN_DEBUG "%s: Using a 21140 non-MII transceiver with control setting %02x\n", - dev->name, p[1]); + netdev_dbg(dev, "Using a 21140 non-MII transceiver with control setting %02x\n", + p[1]); dev->if_port = p[0]; if (startup) iowrite32(mtable->csr12dir | 0x100, ioaddr + CSR12); @@ -204,15 +204,14 @@ void tulip_select_media(struct net_device *dev, int startup) struct medialeaf *rleaf = &mtable->mleaf[mtable->has_reset]; unsigned char *rst = rleaf->leafdata; if (tulip_debug > 1) - printk(KERN_DEBUG "%s: Resetting the transceiver\n", - dev->name); + netdev_dbg(dev, "Resetting the transceiver\n"); for (i = 0; i < rst[0]; i++) iowrite32(get_u16(rst + 1 + (i<<1)) << 16, ioaddr + CSR15); } if (tulip_debug > 1) - printk(KERN_DEBUG "%s: 21143 non-MII %s transceiver control %04x/%04x\n", - dev->name, medianame[dev->if_port], - setup[0], setup[1]); + netdev_dbg(dev, "21143 non-MII %s transceiver control %04x/%04x\n", + medianame[dev->if_port], + setup[0], setup[1]); if (p[0] & 0x40) { /* SIA (CSR13-15) setup values are provided. */ csr13val = setup[0]; csr14val = setup[1]; @@ -239,8 +238,8 @@ void tulip_select_media(struct net_device *dev, int startup) if (startup) iowrite32(csr13val, ioaddr + CSR13); } if (tulip_debug > 1) - printk(KERN_DEBUG "%s: Setting CSR15 to %08x/%08x\n", - dev->name, csr15dir, csr15val); + netdev_dbg(dev, "Setting CSR15 to %08x/%08x\n", + csr15dir, csr15val); if (mleaf->type == 4) new_csr6 = 0x82020000 | ((setup[2] & 0x71) << 18); else @@ -316,9 +315,9 @@ void tulip_select_media(struct net_device *dev, int startup) if (tp->mii_advertise == 0) tp->mii_advertise = tp->advertising[phy_num]; if (tulip_debug > 1) - printk(KERN_DEBUG "%s: Advertising %04x on MII %d\n", - dev->name, tp->mii_advertise, - tp->phys[phy_num]); + netdev_dbg(dev, " Advertising %04x on MII %d\n", + tp->mii_advertise, + tp->phys[phy_num]); tulip_mdio_write(dev, tp->phys[phy_num], 4, tp->mii_advertise); } break; @@ -335,8 +334,7 @@ void tulip_select_media(struct net_device *dev, int startup) struct medialeaf *rleaf = &mtable->mleaf[mtable->has_reset]; unsigned char *rst = rleaf->leafdata; if (tulip_debug > 1) - printk(KERN_DEBUG "%s: Resetting the transceiver\n", - dev->name); + netdev_dbg(dev, "Resetting the transceiver\n"); for (i = 0; i < rst[0]; i++) iowrite32(get_u16(rst + 1 + (i<<1)) << 16, ioaddr + CSR15); } @@ -344,20 +342,21 @@ void tulip_select_media(struct net_device *dev, int startup) break; } default: - printk(KERN_DEBUG "%s: Invalid media table selection %d\n", - dev->name, mleaf->type); + netdev_dbg(dev, " Invalid media table selection %d\n", + mleaf->type); new_csr6 = 0x020E0000; } if (tulip_debug > 1) - printk(KERN_DEBUG "%s: Using media type %s, CSR12 is %02x\n", - dev->name, medianame[dev->if_port], + netdev_dbg(dev, "Using media type %s, CSR12 is %02x\n", + medianame[dev->if_port], ioread32(ioaddr + CSR12) & 0xff); } else if (tp->chip_id == LC82C168) { if (startup && ! tp->medialock) dev->if_port = tp->mii_cnt ? 11 : 0; if (tulip_debug > 1) - printk(KERN_DEBUG "%s: PNIC PHY status is %3.3x, media %s\n", - dev->name, ioread32(ioaddr + 0xB8), medianame[dev->if_port]); + netdev_dbg(dev, "PNIC PHY status is %3.3x, media %s\n", + ioread32(ioaddr + 0xB8), + medianame[dev->if_port]); if (tp->mii_cnt) { new_csr6 = 0x810C0000; iowrite32(0x0001, ioaddr + CSR15); @@ -388,9 +387,9 @@ void tulip_select_media(struct net_device *dev, int startup) } else new_csr6 = 0x03860000; if (tulip_debug > 1) - printk(KERN_DEBUG "%s: No media description table, assuming %s transceiver, CSR12 %02x\n", - dev->name, medianame[dev->if_port], - ioread32(ioaddr + CSR12)); + netdev_dbg(dev, "No media description table, assuming %s transceiver, CSR12 %02x\n", + medianame[dev->if_port], + ioread32(ioaddr + CSR12)); } tp->csr6 = new_csr6 | (tp->csr6 & 0xfdff) | (tp->full_duplex ? 0x0200 : 0); @@ -504,8 +503,8 @@ void __devinit tulip_find_mii (struct net_device *dev, int board_idx) /* Fixup for DLink with miswired PHY. */ if (mii_advert != to_advert) { - printk(KERN_DEBUG "tulip%d: Advertising %04x on PHY %d, previously advertising %04x\n", - board_idx, to_advert, phy, mii_advert); + pr_debug("tulip%d: Advertising %04x on PHY %d, previously advertising %04x\n", + board_idx, to_advert, phy, mii_advert); tulip_mdio_write (dev, phy, 4, to_advert); } diff --git a/drivers/net/tulip/pnic.c b/drivers/net/tulip/pnic.c index a63e64b..aa4d9da 100644 --- a/drivers/net/tulip/pnic.c +++ b/drivers/net/tulip/pnic.c @@ -40,8 +40,8 @@ void pnic_do_nway(struct net_device *dev) new_csr6 |= 0x00000200; } if (tulip_debug > 1) - printk(KERN_DEBUG "%s: PNIC autonegotiated status %08x, %s\n", - dev->name, phy_reg, medianame[dev->if_port]); + netdev_dbg(dev, "PNIC autonegotiated status %08x, %s\n", + phy_reg, medianame[dev->if_port]); if (tp->csr6 != new_csr6) { tp->csr6 = new_csr6; /* Restart Tx */ @@ -58,8 +58,8 @@ void pnic_lnk_change(struct net_device *dev, int csr5) int phy_reg = ioread32(ioaddr + 0xB8); if (tulip_debug > 1) - printk(KERN_DEBUG "%s: PNIC link changed state %08x, CSR5 %08x\n", - dev->name, phy_reg, csr5); + netdev_dbg(dev, "PNIC link changed state %08x, CSR5 %08x\n", + phy_reg, csr5); if (ioread32(ioaddr + CSR5) & TPLnkFail) { iowrite32((ioread32(ioaddr + CSR7) & ~TPLnkFail) | TPLnkPass, ioaddr + CSR7); /* If we use an external MII, then we mustn't use the @@ -114,8 +114,8 @@ void pnic_timer(unsigned long data) int csr5 = ioread32(ioaddr + CSR5); if (tulip_debug > 1) - printk(KERN_DEBUG "%s: PNIC timer PHY status %08x, %s CSR5 %08x\n", - dev->name, phy_reg, medianame[dev->if_port], csr5); + netdev_dbg(dev, "PNIC timer PHY status %08x, %s CSR5 %08x\n", + phy_reg, medianame[dev->if_port], csr5); if (phy_reg & 0x04000000) { /* Remote link fault */ iowrite32(0x0201F078, ioaddr + 0xB8); next_tick = 1*HZ; @@ -125,11 +125,11 @@ void pnic_timer(unsigned long data) next_tick = 60*HZ; } else if (csr5 & TPLnkFail) { /* 100baseTx link beat */ if (tulip_debug > 1) - printk(KERN_DEBUG "%s: %s link beat failed, CSR12 %04x, CSR5 %08x, PHY %03x\n", - dev->name, medianame[dev->if_port], - csr12, - ioread32(ioaddr + CSR5), - ioread32(ioaddr + 0xB8)); + netdev_dbg(dev, "%s link beat failed, CSR12 %04x, CSR5 %08x, PHY %03x\n", + medianame[dev->if_port], + csr12, + ioread32(ioaddr + CSR5), + ioread32(ioaddr + 0xB8)); next_tick = 3*HZ; if (tp->medialock) { } else if (tp->nwayset && (dev->if_port & 1)) { diff --git a/drivers/net/tulip/pnic2.c b/drivers/net/tulip/pnic2.c index 4690c8e..93358ee 100644 --- a/drivers/net/tulip/pnic2.c +++ b/drivers/net/tulip/pnic2.c @@ -125,8 +125,8 @@ void pnic2_start_nway(struct net_device *dev) csr14 |= 0x00001184; if (tulip_debug > 1) - printk(KERN_DEBUG "%s: Restarting PNIC2 autonegotiation, csr14=%08x\n", - dev->name, csr14); + netdev_dbg(dev, "Restarting PNIC2 autonegotiation, csr14=%08x\n", + csr14); /* tell pnic2_lnk_change we are doing an nway negotiation */ dev->if_port = 0; @@ -137,8 +137,7 @@ void pnic2_start_nway(struct net_device *dev) tp->csr6 = ioread32(ioaddr + CSR6); if (tulip_debug > 1) - printk(KERN_DEBUG "%s: On Entry to Nway, csr6=%08x\n", - dev->name, tp->csr6); + netdev_dbg(dev, "On Entry to Nway, csr6=%08x\n", tp->csr6); /* mask off any bits not to touch * comment at top of file explains mask value @@ -271,9 +270,10 @@ void pnic2_lnk_change(struct net_device *dev, int csr5) iowrite32(1, ioaddr + CSR13); if (tulip_debug > 2) - printk(KERN_DEBUG "%s: Setting CSR6 %08x/%x CSR12 %08x\n", - dev->name, tp->csr6, - ioread32(ioaddr + CSR6), ioread32(ioaddr + CSR12)); + netdev_dbg(dev, "Setting CSR6 %08x/%x CSR12 %08x\n", + tp->csr6, + ioread32(ioaddr + CSR6), + ioread32(ioaddr + CSR12)); /* now the following actually writes out the * new csr6 values @@ -324,7 +324,7 @@ void pnic2_lnk_change(struct net_device *dev, int csr5) /* Link blew? Maybe restart NWay. */ if (tulip_debug > 2) - printk(KERN_DEBUG "%s: Ugh! Link blew?\n", dev->name); + netdev_dbg(dev, "Ugh! Link blew?\n"); del_timer_sync(&tp->timer); pnic2_start_nway(dev); diff --git a/drivers/net/tulip/timer.c b/drivers/net/tulip/timer.c index 36c2725..2017faf 100644 --- a/drivers/net/tulip/timer.c +++ b/drivers/net/tulip/timer.c @@ -28,11 +28,11 @@ void tulip_media_task(struct work_struct *work) unsigned long flags; if (tulip_debug > 2) { - printk(KERN_DEBUG "%s: Media selection tick, %s, status %08x mode %08x SIA %08x %08x %08x %08x\n", - dev->name, medianame[dev->if_port], - ioread32(ioaddr + CSR5), ioread32(ioaddr + CSR6), - csr12, ioread32(ioaddr + CSR13), - ioread32(ioaddr + CSR14), ioread32(ioaddr + CSR15)); + netdev_dbg(dev, "Media selection tick, %s, status %08x mode %08x SIA %08x %08x %08x %08x\n", + medianame[dev->if_port], + ioread32(ioaddr + CSR5), ioread32(ioaddr + CSR6), + csr12, ioread32(ioaddr + CSR13), + ioread32(ioaddr + CSR14), ioread32(ioaddr + CSR15)); } switch (tp->chip_id) { case DC21140: @@ -48,9 +48,9 @@ void tulip_media_task(struct work_struct *work) Assume this a generic MII or SYM transceiver. */ next_tick = 60*HZ; if (tulip_debug > 2) - printk(KERN_DEBUG "%s: network media monitor CSR6 %08x CSR12 0x%02x\n", - dev->name, - ioread32(ioaddr + CSR6), csr12 & 0xff); + netdev_dbg(dev, "network media monitor CSR6 %08x CSR12 0x%02x\n", + ioread32(ioaddr + CSR6), + csr12 & 0xff); break; } mleaf = &tp->mtable->mleaf[tp->cur_index]; @@ -62,8 +62,8 @@ void tulip_media_task(struct work_struct *work) s8 bitnum = p[offset]; if (p[offset+1] & 0x80) { if (tulip_debug > 1) - printk(KERN_DEBUG "%s: Transceiver monitor tick CSR12=%#02x, no media sense\n", - dev->name, csr12); + netdev_dbg(dev, "Transceiver monitor tick CSR12=%#02x, no media sense\n", + csr12); if (mleaf->type == 4) { if (mleaf->media == 3 && (csr12 & 0x02)) goto select_next_media; @@ -71,17 +71,16 @@ void tulip_media_task(struct work_struct *work) break; } if (tulip_debug > 2) - printk(KERN_DEBUG "%s: Transceiver monitor tick: CSR12=%#02x bit %d is %d, expecting %d\n", - dev->name, csr12, (bitnum >> 1) & 7, - (csr12 & (1 << ((bitnum >> 1) & 7))) != 0, - (bitnum >= 0)); + netdev_dbg(dev, "Transceiver monitor tick: CSR12=%#02x bit %d is %d, expecting %d\n", + csr12, (bitnum >> 1) & 7, + (csr12 & (1 << ((bitnum >> 1) & 7))) != 0, + (bitnum >= 0)); /* Check that the specified bit has the proper value. */ if ((bitnum < 0) != ((csr12 & (1 << ((bitnum >> 1) & 7))) != 0)) { if (tulip_debug > 2) - printk(KERN_DEBUG "%s: Link beat detected for %s\n", - dev->name, - medianame[mleaf->media & MEDIA_MASK]); + netdev_dbg(dev, "Link beat detected for %s\n", + medianame[mleaf->media & MEDIA_MASK]); if ((p[2] & 0x61) == 0x01) /* Bogus Znyx board. */ goto actually_mii; netif_carrier_on(dev); @@ -99,10 +98,9 @@ void tulip_media_task(struct work_struct *work) if (tulip_media_cap[dev->if_port] & MediaIsFD) goto select_next_media; /* Skip FD entries. */ if (tulip_debug > 1) - printk(KERN_DEBUG "%s: No link beat on media %s, trying transceiver type %s\n", - dev->name, - medianame[mleaf->media & MEDIA_MASK], - medianame[tp->mtable->mleaf[tp->cur_index].media]); + netdev_dbg(dev, "No link beat on media %s, trying transceiver type %s\n", + medianame[mleaf->media & MEDIA_MASK], + medianame[tp->mtable->mleaf[tp->cur_index].media]); tulip_select_media(dev, 0); /* Restart the transmit process. */ tulip_restart_rxtx(tp); @@ -166,10 +164,9 @@ void comet_timer(unsigned long data) int next_tick = 60*HZ; if (tulip_debug > 1) - printk(KERN_DEBUG "%s: Comet link status %04x partner capability %04x\n", - dev->name, - tulip_mdio_read(dev, tp->phys[0], 1), - tulip_mdio_read(dev, tp->phys[0], 5)); + netdev_dbg(dev, "Comet link status %04x partner capability %04x\n", + tulip_mdio_read(dev, tp->phys[0], 1), + tulip_mdio_read(dev, tp->phys[0], 5)); /* mod_timer synchronizes us with potential add_timer calls * from interrupts. */ diff --git a/drivers/net/tulip/tulip.h b/drivers/net/tulip/tulip.h index ed66a16..9db5289 100644 --- a/drivers/net/tulip/tulip.h +++ b/drivers/net/tulip/tulip.h @@ -547,11 +547,9 @@ static inline void tulip_stop_rxtx(struct tulip_private *tp) udelay(10); if (!i) - printk(KERN_DEBUG "%s: tulip_stop_rxtx() failed" - " (CSR5 0x%x CSR6 0x%x)\n", - pci_name(tp->pdev), - ioread32(ioaddr + CSR5), - ioread32(ioaddr + CSR6)); + netdev_dbg(tp->dev, "tulip_stop_rxtx() failed (CSR5 0x%x CSR6 0x%x)\n", + ioread32(ioaddr + CSR5), + ioread32(ioaddr + CSR6)); } } diff --git a/drivers/net/tulip/tulip_core.c b/drivers/net/tulip/tulip_core.c index f46898a..ebc8058 100644 --- a/drivers/net/tulip/tulip_core.c +++ b/drivers/net/tulip/tulip_core.c @@ -330,8 +330,7 @@ static void tulip_up(struct net_device *dev) udelay(100); if (tulip_debug > 1) - printk(KERN_DEBUG "%s: tulip_up(), irq==%d\n", - dev->name, dev->irq); + netdev_dbg(dev, "tulip_up(), irq==%d\n", dev->irq); iowrite32(tp->rx_ring_dma, ioaddr + CSR3); iowrite32(tp->tx_ring_dma, ioaddr + CSR4); @@ -498,10 +497,10 @@ media_picked: iowrite32(0, ioaddr + CSR2); /* Rx poll demand */ if (tulip_debug > 2) { - printk(KERN_DEBUG "%s: Done tulip_up(), CSR0 %08x, CSR5 %08x CSR6 %08x\n", - dev->name, ioread32(ioaddr + CSR0), - ioread32(ioaddr + CSR5), - ioread32(ioaddr + CSR6)); + netdev_dbg(dev, "Done tulip_up(), CSR0 %08x, CSR5 %08x CSR6 %08x\n", + ioread32(ioaddr + CSR0), + ioread32(ioaddr + CSR5), + ioread32(ioaddr + CSR6)); } /* Set the timer to switch to check for link beat and perhaps switch @@ -842,8 +841,7 @@ static int tulip_close (struct net_device *dev) tulip_down (dev); if (tulip_debug > 1) - dev_printk(KERN_DEBUG, &dev->dev, - "Shutting down ethercard, status was %02x\n", + netdev_dbg(dev, "Shutting down ethercard, status was %02x\n", ioread32 (ioaddr + CSR5)); free_irq (dev->irq, dev); @@ -1206,7 +1204,7 @@ static void __devinit tulip_mwi_config (struct pci_dev *pdev, u32 csr0; if (tulip_debug > 3) - printk(KERN_DEBUG "%s: tulip_mwi_config()\n", pci_name(pdev)); + netdev_dbg(dev, "tulip_mwi_config()\n"); tp->csr0 = csr0 = 0; @@ -1268,8 +1266,8 @@ static void __devinit tulip_mwi_config (struct pci_dev *pdev, out: tp->csr0 = csr0; if (tulip_debug > 2) - printk(KERN_DEBUG "%s: MWI config cacheline=%d, csr0=%08x\n", - pci_name(pdev), cache, csr0); + netdev_dbg(dev, "MWI config cacheline=%d, csr0=%08x\n", + cache, csr0); } #endif diff --git a/drivers/net/tulip/winbond-840.c b/drivers/net/tulip/winbond-840.c index 939c96e..64e3f01 100644 --- a/drivers/net/tulip/winbond-840.c +++ b/drivers/net/tulip/winbond-840.c @@ -645,8 +645,7 @@ static int netdev_open(struct net_device *dev) goto out_err; if (debug > 1) - printk(KERN_DEBUG "%s: w89c840_open() irq %d\n", - dev->name, dev->irq); + netdev_dbg(dev, "w89c840_open() irq %d\n", dev->irq); if((i=alloc_ringdesc(dev))) goto out_err; @@ -658,7 +657,7 @@ static int netdev_open(struct net_device *dev) netif_start_queue(dev); if (debug > 2) - printk(KERN_DEBUG "%s: Done netdev_open()\n", dev->name); + netdev_dbg(dev, "Done netdev_open()\n"); /* Set the timer to check for link beat. */ init_timer(&np->timer); @@ -787,9 +786,9 @@ static void netdev_timer(unsigned long data) void __iomem *ioaddr = np->base_addr; if (debug > 2) - printk(KERN_DEBUG "%s: Media selection timer tick, status %08x config %08x\n", - dev->name, ioread32(ioaddr + IntrStatus), - ioread32(ioaddr + NetworkConfig)); + netdev_dbg(dev, "Media selection timer tick, status %08x config %08x\n", + ioread32(ioaddr + IntrStatus), + ioread32(ioaddr + NetworkConfig)); spin_lock_irq(&np->lock); update_csr6(dev, update_link(dev)); spin_unlock_irq(&np->lock); @@ -1056,8 +1055,8 @@ static netdev_tx_t start_tx(struct sk_buff *skb, struct net_device *dev) spin_unlock_irq(&np->lock); if (debug > 4) { - printk(KERN_DEBUG "%s: Transmit frame #%d queued in slot %d\n", - dev->name, np->cur_tx, entry); + netdev_dbg(dev, "Transmit frame #%d queued in slot %d\n", + np->cur_tx, entry); } return NETDEV_TX_OK; } @@ -1074,8 +1073,8 @@ static void netdev_tx_done(struct net_device *dev) if (tx_status & 0x8000) { /* There was an error, log it. */ #ifndef final_version if (debug > 1) - printk(KERN_DEBUG "%s: Transmit error, Tx status %08x\n", - dev->name, tx_status); + netdev_dbg(dev, "Transmit error, Tx status %08x\n", + tx_status); #endif np->stats.tx_errors++; if (tx_status & 0x0104) np->stats.tx_aborted_errors++; @@ -1087,8 +1086,8 @@ static void netdev_tx_done(struct net_device *dev) } else { #ifndef final_version if (debug > 3) - printk(KERN_DEBUG "%s: Transmit slot %d ok, Tx status %08x\n", - dev->name, entry, tx_status); + netdev_dbg(dev, "Transmit slot %d ok, Tx status %08x\n", + entry, tx_status); #endif np->stats.tx_bytes += np->tx_skbuff[entry]->len; np->stats.collisions += (tx_status >> 3) & 15; @@ -1131,8 +1130,7 @@ static irqreturn_t intr_handler(int irq, void *dev_instance) iowrite32(intr_status & 0x001ffff, ioaddr + IntrStatus); if (debug > 4) - printk(KERN_DEBUG "%s: Interrupt, status %04x\n", - dev->name, intr_status); + netdev_dbg(dev, "Interrupt, status %04x\n", intr_status); if ((intr_status & (NormalIntr|AbnormalIntr)) == 0) break; @@ -1173,8 +1171,8 @@ static irqreturn_t intr_handler(int irq, void *dev_instance) } while (1); if (debug > 3) - printk(KERN_DEBUG "%s: exiting interrupt, status=%#4.4x\n", - dev->name, ioread32(ioaddr + IntrStatus)); + netdev_dbg(dev, "exiting interrupt, status=%#4.4x\n", + ioread32(ioaddr + IntrStatus)); return IRQ_RETVAL(handled); } @@ -1187,8 +1185,8 @@ static int netdev_rx(struct net_device *dev) int work_limit = np->dirty_rx + RX_RING_SIZE - np->cur_rx; if (debug > 4) { - printk(KERN_DEBUG " In netdev_rx(), entry %d status %04x\n", - entry, np->rx_ring[entry].status); + netdev_dbg(dev, " In netdev_rx(), entry %d status %04x\n", + entry, np->rx_ring[entry].status); } /* If EOP is set on the next entry, it's a new packet. Send it up. */ @@ -1197,8 +1195,8 @@ static int netdev_rx(struct net_device *dev) s32 status = desc->status; if (debug > 4) - printk(KERN_DEBUG " netdev_rx() status was %08x\n", - status); + netdev_dbg(dev, " netdev_rx() status was %08x\n", + status); if (status < 0) break; if ((status & 0x38008300) != 0x0300) { @@ -1213,8 +1211,8 @@ static int netdev_rx(struct net_device *dev) } else if (status & 0x8000) { /* There was a fatal error. */ if (debug > 2) - printk(KERN_DEBUG "%s: Receive error, Rx status %08x\n", - dev->name, status); + netdev_dbg(dev, "Receive error, Rx status %08x\n", + status); np->stats.rx_errors++; /* end of a packet.*/ if (status & 0x0890) np->stats.rx_length_errors++; if (status & 0x004C) np->stats.rx_frame_errors++; @@ -1227,8 +1225,8 @@ static int netdev_rx(struct net_device *dev) #ifndef final_version if (debug > 4) - printk(KERN_DEBUG " netdev_rx() normal Rx pkt length %d status %x\n", - pkt_len, status); + netdev_dbg(dev, " netdev_rx() normal Rx pkt length %d status %x\n", + pkt_len, status); #endif /* Check if the packet is long enough to accept without copying to a minimally-sized skbuff. */ @@ -1253,10 +1251,10 @@ static int netdev_rx(struct net_device *dev) #ifndef final_version /* Remove after testing. */ /* You will want this info for the initial debug. */ if (debug > 5) - printk(KERN_DEBUG " Rx data %pM %pM %02x%02x %pI4\n", - &skb->data[0], &skb->data[6], - skb->data[12], skb->data[13], - &skb->data[14]); + netdev_dbg(dev, " Rx data %pM %pM %02x%02x %pI4\n", + &skb->data[0], &skb->data[6], + skb->data[12], skb->data[13], + &skb->data[14]); #endif skb->protocol = eth_type_trans(skb, dev); netif_rx(skb); @@ -1294,8 +1292,7 @@ static void netdev_error(struct net_device *dev, int intr_status) void __iomem *ioaddr = np->base_addr; if (debug > 2) - printk(KERN_DEBUG "%s: Abnormal event, %08x\n", - dev->name, intr_status); + netdev_dbg(dev, "Abnormal event, %08x\n", intr_status); if (intr_status == 0xffffffff) return; spin_lock(&np->lock); @@ -1315,8 +1312,7 @@ static void netdev_error(struct net_device *dev, int intr_status) new = 127; /* load full packet before starting */ new = (np->csr6 & ~(0x7F << 14)) | (new<<14); #endif - printk(KERN_DEBUG "%s: Tx underflow, new csr6 %08x\n", - dev->name, new); + netdev_dbg(dev, "Tx underflow, new csr6 %08x\n", new); update_csr6(dev, new); } if (intr_status & RxDied) { /* Missed a Rx frame. */ @@ -1489,13 +1485,12 @@ static int netdev_close(struct net_device *dev) netif_stop_queue(dev); if (debug > 1) { - printk(KERN_DEBUG "%s: Shutting down ethercard, status was %08x Config %08x\n", - dev->name, ioread32(ioaddr + IntrStatus), - ioread32(ioaddr + NetworkConfig)); - printk(KERN_DEBUG "%s: Queue pointers were Tx %d / %d, Rx %d / %d\n", - dev->name, - np->cur_tx, np->dirty_tx, - np->cur_rx, np->dirty_rx); + netdev_dbg(dev, "Shutting down ethercard, status was %08x Config %08x\n", + ioread32(ioaddr + IntrStatus), + ioread32(ioaddr + NetworkConfig)); + netdev_dbg(dev, "Queue pointers were Tx %d / %d, Rx %d / %d\n", + np->cur_tx, np->dirty_tx, + np->cur_rx, np->dirty_rx); } /* Stop the chip's Tx and Rx processes. */ diff --git a/drivers/net/tulip/xircom_cb.c b/drivers/net/tulip/xircom_cb.c index 7e82872..988b8eb 100644 --- a/drivers/net/tulip/xircom_cb.c +++ b/drivers/net/tulip/xircom_cb.c @@ -333,7 +333,7 @@ static irqreturn_t xircom_interrupt(int irq, void *dev_instance) if (link_status_changed(card)) { int newlink; - printk(KERN_DEBUG "xircom_cb: Link status has changed\n"); + netdev_dbg(dev, "Link status has changed\n"); newlink = link_status(card); netdev_info(dev, "Link is %d mbit\n", newlink); if (newlink) -- cgit v0.10.2 From 1c3319fb69c29376fe23c1aa0cd7cb6df91c7883 Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Mon, 9 May 2011 09:45:23 +0000 Subject: tulip: Use pr_ where appropriate Use the current logging styles. Signed-off-by: Joe Perches Signed-off-by: David S. Miller diff --git a/drivers/net/tulip/de2104x.c b/drivers/net/tulip/de2104x.c index e925c1e..e2f6923 100644 --- a/drivers/net/tulip/de2104x.c +++ b/drivers/net/tulip/de2104x.c @@ -53,7 +53,7 @@ /* These identify the driver base version and may not be removed. */ static char version[] = -KERN_INFO DRV_NAME " PCI Ethernet driver v" DRV_VERSION " (" DRV_RELDATE ")\n"; +"PCI Ethernet driver v" DRV_VERSION " (" DRV_RELDATE ")"; MODULE_AUTHOR("Jeff Garzik "); MODULE_DESCRIPTION("Intel/Digital 21040/1 series PCI Ethernet driver"); @@ -1978,7 +1978,7 @@ static int __devinit de_init_one (struct pci_dev *pdev, #ifndef MODULE if (board_idx == 0) - printk("%s", version); + pr_info("%s\n", version); #endif /* allocate a new ethernet device structure, and fill in defaults */ @@ -2200,7 +2200,7 @@ static struct pci_driver de_driver = { static int __init de_init (void) { #ifdef MODULE - printk("%s", version); + pr_info("%s\n", version); #endif return pci_register_driver(&de_driver); } diff --git a/drivers/net/tulip/dmfe.c b/drivers/net/tulip/dmfe.c index 96e8541..4685127 100644 --- a/drivers/net/tulip/dmfe.c +++ b/drivers/net/tulip/dmfe.c @@ -295,8 +295,7 @@ enum dmfe_CR6_bits { /* Global variable declaration ----------------------------- */ static int __devinitdata printed_version; static const char version[] __devinitconst = - KERN_INFO DRV_NAME ": Davicom DM9xxx net driver, version " - DRV_VERSION " (" DRV_RELDATE ")\n"; + "Davicom DM9xxx net driver, version " DRV_VERSION " (" DRV_RELDATE ")"; static int dmfe_debug; static unsigned char dmfe_media_mode = DMFE_AUTO; @@ -381,7 +380,7 @@ static int __devinit dmfe_init_one (struct pci_dev *pdev, DMFE_DBUG(0, "dmfe_init_one()", 0); if (!printed_version++) - printk(version); + pr_info("%s\n", version); /* * SPARC on-board DM910x chips should be handled by the main @@ -2203,7 +2202,7 @@ static int __init dmfe_init_module(void) { int rc; - printk(version); + pr_info("%s\n", version); printed_version = 1; DMFE_DBUG(0, "init_module() ", debug); diff --git a/drivers/net/tulip/tulip_core.c b/drivers/net/tulip/tulip_core.c index ebc8058..82f8764 100644 --- a/drivers/net/tulip/tulip_core.c +++ b/drivers/net/tulip/tulip_core.c @@ -1478,7 +1478,8 @@ static int __devinit tulip_init_one (struct pci_dev *pdev, if (sig == 0x09811317) { tp->flags |= COMET_PM; tp->wolinfo.supported = WAKE_PHY | WAKE_MAGIC; - printk(KERN_INFO "tulip_init_one: Enabled WOL support for AN983B\n"); + pr_info("%s: Enabled WOL support for AN983B\n", + __func__); } } tp->pdev = pdev; @@ -1874,7 +1875,7 @@ save_state: tulip_set_wolopts(pdev, tp->wolinfo.wolopts); rc = pci_enable_wake(pdev, pstate, tp->wolinfo.wolopts); if (rc) - printk("tulip: pci_enable_wake failed (%d)\n", rc); + pr_err("pci_enable_wake failed (%d)\n", rc); } pci_set_power_state(pdev, pstate); diff --git a/drivers/net/tulip/uli526x.c b/drivers/net/tulip/uli526x.c index 92c00ee..9e63f40 100644 --- a/drivers/net/tulip/uli526x.c +++ b/drivers/net/tulip/uli526x.c @@ -209,8 +209,7 @@ enum uli526x_CR6_bits { /* Global variable declaration ----------------------------- */ static int __devinitdata printed_version; static const char version[] __devinitconst = - KERN_INFO DRV_NAME ": ULi M5261/M5263 net driver, version " - DRV_VERSION " (" DRV_RELDATE ")\n"; + "ULi M5261/M5263 net driver, version " DRV_VERSION " (" DRV_RELDATE ")"; static int uli526x_debug; static unsigned char uli526x_media_mode = ULI526X_AUTO; @@ -283,7 +282,7 @@ static int __devinit uli526x_init_one (struct pci_dev *pdev, ULI526X_DBUG(0, "uli526x_init_one()", 0); if (!printed_version++) - printk(version); + pr_info("%s\n", version); /* Init network device */ dev = alloc_etherdev(sizeof(*db)); @@ -667,15 +666,6 @@ static int uli526x_stop(struct net_device *dev) /* free allocated rx buffer */ uli526x_free_rxbuffer(db); -#if 0 - /* show statistic counter */ - printk(DRV_NAME ": FU:%lx EC:%lx LC:%lx NC:%lx LOC:%lx TXJT:%lx RESET:%lx RCR8:%lx FAL:%lx TT:%lx\n", - db->tx_fifo_underrun, db->tx_excessive_collision, - db->tx_late_collision, db->tx_no_carrier, db->tx_loss_carrier, - db->tx_jabber_timeout, db->reset_count, db->reset_cr8, - db->reset_fatal, db->reset_TXtimeout); -#endif - return 0; } @@ -755,7 +745,6 @@ static void uli526x_free_tx_pkt(struct net_device *dev, txptr = db->tx_remove_ptr; while(db->tx_packet_cnt) { tdes0 = le32_to_cpu(txptr->tdes0); - /* printk(DRV_NAME ": tdes0=%x\n", tdes0); */ if (tdes0 & 0x80000000) break; @@ -765,7 +754,6 @@ static void uli526x_free_tx_pkt(struct net_device *dev, /* Transmit statistic counter */ if ( tdes0 != 0x7fffffff ) { - /* printk(DRV_NAME ": tdes0=%x\n", tdes0); */ dev->stats.collisions += (tdes0 >> 3) & 0xf; dev->stats.tx_bytes += le32_to_cpu(txptr->tdes1) & 0x7ff; if (tdes0 & TDES0_ERR_MASK) { @@ -838,7 +826,6 @@ static void uli526x_rx_packet(struct net_device *dev, struct uli526x_board_info /* error summary bit check */ if (rdes0 & 0x8000) { /* This is a error packet */ - //printk(DRV_NAME ": rdes0: %lx\n", rdes0); dev->stats.rx_errors++; if (rdes0 & 1) dev->stats.rx_fifo_errors++; @@ -1046,8 +1033,7 @@ static void uli526x_timer(unsigned long data) if ( time_after(jiffies, dev_trans_start(dev) + ULI526X_TX_TIMEOUT) ) { db->reset_TXtimeout++; db->wait_reset = 1; - printk( "%s: Tx timeout - resetting\n", - dev->name); + netdev_err(dev, " Tx timeout - resetting\n"); } } @@ -1534,7 +1520,6 @@ static u8 uli526x_sense_speed(struct uli526x_board_info * db) else phy_mode = 0x1000; - /* printk(DRV_NAME ": Phy_mode %x ",phy_mode); */ switch (phy_mode) { case 0x1000: db->op_mode = ULI526X_10MHF; break; case 0x2000: db->op_mode = ULI526X_10MFD; break; @@ -1823,7 +1808,7 @@ MODULE_PARM_DESC(mode, "ULi M5261/M5263: Bit 0: 10/100Mbps, bit 2: duplex, bit 8 static int __init uli526x_init_module(void) { - printk(version); + pr_info("%s\n", version); printed_version = 1; ULI526X_DBUG(0, "init_module() ", debug); diff --git a/drivers/net/tulip/winbond-840.c b/drivers/net/tulip/winbond-840.c index 64e3f01..862eadf 100644 --- a/drivers/net/tulip/winbond-840.c +++ b/drivers/net/tulip/winbond-840.c @@ -141,7 +141,7 @@ static int full_duplex[MAX_UNITS] = {-1, -1, -1, -1, -1, -1, -1, -1}; /* These identify the driver base version and may not be removed. */ static const char version[] __initconst = - KERN_INFO DRV_NAME ".c:v" DRV_VERSION " (2.4 port) " + "v" DRV_VERSION " (2.4 port) " DRV_RELDATE " Donald Becker \n" " http://www.scyld.com/network/drivers.html\n"; -- cgit v0.10.2 From a09a79f66874c905af35d5bb5e5f2fdc7b6b894d Mon Sep 17 00:00:00 2001 From: Mikulas Patocka Date: Mon, 9 May 2011 13:01:09 +0200 Subject: Don't lock guardpage if the stack is growing up Linux kernel excludes guard page when performing mlock on a VMA with down-growing stack. However, some architectures have up-growing stack and locking the guard page should be excluded in this case too. This patch fixes lvm2 on PA-RISC (and possibly other architectures with up-growing stack). lvm2 calculates number of used pages when locking and when unlocking and reports an internal error if the numbers mismatch. [ Patch changed fairly extensively to also fix /proc//maps for the grows-up case, and to move things around a bit to clean it all up and share the infrstructure with the /proc bits. Tested on ia64 that has both grow-up and grow-down segments - Linus ] Signed-off-by: Mikulas Patocka Tested-by: Tony Luck Cc: stable@kernel.org Signed-off-by: Linus Torvalds diff --git a/fs/proc/task_mmu.c b/fs/proc/task_mmu.c index 2e7addf..318d865 100644 --- a/fs/proc/task_mmu.c +++ b/fs/proc/task_mmu.c @@ -214,7 +214,7 @@ static void show_map_vma(struct seq_file *m, struct vm_area_struct *vma) int flags = vma->vm_flags; unsigned long ino = 0; unsigned long long pgoff = 0; - unsigned long start; + unsigned long start, end; dev_t dev = 0; int len; @@ -227,13 +227,15 @@ static void show_map_vma(struct seq_file *m, struct vm_area_struct *vma) /* We don't show the stack guard page in /proc/maps */ start = vma->vm_start; - if (vma->vm_flags & VM_GROWSDOWN) - if (!vma_stack_continue(vma->vm_prev, vma->vm_start)) - start += PAGE_SIZE; + if (stack_guard_page_start(vma, start)) + start += PAGE_SIZE; + end = vma->vm_end; + if (stack_guard_page_end(vma, end)) + end -= PAGE_SIZE; seq_printf(m, "%08lx-%08lx %c%c%c%c %08llx %02x:%02x %lu %n", start, - vma->vm_end, + end, flags & VM_READ ? 'r' : '-', flags & VM_WRITE ? 'w' : '-', flags & VM_EXEC ? 'x' : '-', diff --git a/include/linux/mm.h b/include/linux/mm.h index 2348db2..6507dde 100644 --- a/include/linux/mm.h +++ b/include/linux/mm.h @@ -1011,11 +1011,33 @@ int set_page_dirty_lock(struct page *page); int clear_page_dirty_for_io(struct page *page); /* Is the vma a continuation of the stack vma above it? */ -static inline int vma_stack_continue(struct vm_area_struct *vma, unsigned long addr) +static inline int vma_growsdown(struct vm_area_struct *vma, unsigned long addr) { return vma && (vma->vm_end == addr) && (vma->vm_flags & VM_GROWSDOWN); } +static inline int stack_guard_page_start(struct vm_area_struct *vma, + unsigned long addr) +{ + return (vma->vm_flags & VM_GROWSDOWN) && + (vma->vm_start == addr) && + !vma_growsdown(vma->vm_prev, addr); +} + +/* Is the vma a continuation of the stack vma below it? */ +static inline int vma_growsup(struct vm_area_struct *vma, unsigned long addr) +{ + return vma && (vma->vm_start == addr) && (vma->vm_flags & VM_GROWSUP); +} + +static inline int stack_guard_page_end(struct vm_area_struct *vma, + unsigned long addr) +{ + return (vma->vm_flags & VM_GROWSUP) && + (vma->vm_end == addr) && + !vma_growsup(vma->vm_next, addr); +} + extern unsigned long move_page_tables(struct vm_area_struct *vma, unsigned long old_addr, struct vm_area_struct *new_vma, unsigned long new_addr, unsigned long len); diff --git a/mm/memory.c b/mm/memory.c index 27f4253..61e66f0 100644 --- a/mm/memory.c +++ b/mm/memory.c @@ -1412,9 +1412,8 @@ no_page_table: static inline int stack_guard_page(struct vm_area_struct *vma, unsigned long addr) { - return (vma->vm_flags & VM_GROWSDOWN) && - (vma->vm_start == addr) && - !vma_stack_continue(vma->vm_prev, addr); + return stack_guard_page_start(vma, addr) || + stack_guard_page_end(vma, addr+PAGE_SIZE); } /** @@ -1551,12 +1550,6 @@ int __get_user_pages(struct task_struct *tsk, struct mm_struct *mm, continue; } - /* - * For mlock, just skip the stack guard page. - */ - if ((gup_flags & FOLL_MLOCK) && stack_guard_page(vma, start)) - goto next_page; - do { struct page *page; unsigned int foll_flags = gup_flags; @@ -1573,6 +1566,11 @@ int __get_user_pages(struct task_struct *tsk, struct mm_struct *mm, int ret; unsigned int fault_flags = 0; + /* For mlock, just skip the stack guard page. */ + if (foll_flags & FOLL_MLOCK) { + if (stack_guard_page(vma, start)) + goto next_page; + } if (foll_flags & FOLL_WRITE) fault_flags |= FAULT_FLAG_WRITE; if (nonblocking) -- cgit v0.10.2 From 228d62dd3f74734b9801c789b5addc57fdfc208f Mon Sep 17 00:00:00 2001 From: Dave Chinner Date: Fri, 6 May 2011 02:54:04 +0000 Subject: xfs: ensure reclaim cursor is reset correctly at end of AG On a 32 bit highmem PowerPC machine, the XFS inode cache was growing without bound and exhausting low memory causing the OOM killer to be triggered. After some effort, the problem was reproduced on a 32 bit x86 highmem machine. The problem is that the per-ag inode reclaim index cursor was not getting reset to the start of the AG if the radix tree tag lookup found no more reclaimable inodes. Hence every further reclaim attempt started at the same index beyond where any reclaimable inodes lay, and no further background reclaim ever occurred from the AG. Without background inode reclaim the VM driven cache shrinker simply cannot keep up with cache growth, and OOM is the result. While the change that exposed the problem was the conversion of the inode reclaim to use work queues for background reclaim, it was not the cause of the bug. The bug was introduced when the cursor code was added, just waiting for some weird configuration to strike.... Signed-off-by: Dave Chinner Tested-By: Christian Kujau Reviewed-by: Christoph Hellwig Reviewed-by: Alex Elder (cherry picked from commit b223221956675ce8a7b436d198ced974bb388571) diff --git a/fs/xfs/linux-2.6/xfs_sync.c b/fs/xfs/linux-2.6/xfs_sync.c index e4f9c1b..3e898a4 100644 --- a/fs/xfs/linux-2.6/xfs_sync.c +++ b/fs/xfs/linux-2.6/xfs_sync.c @@ -926,6 +926,7 @@ restart: XFS_LOOKUP_BATCH, XFS_ICI_RECLAIM_TAG); if (!nr_found) { + done = 1; rcu_read_unlock(); break; } -- cgit v0.10.2 From 9e7004e741de0b2daabbbadafbaf11ff1a94e00c Mon Sep 17 00:00:00 2001 From: Dave Chinner Date: Fri, 6 May 2011 02:54:05 +0000 Subject: xfs: exit AIL push work correctly when AIL is empty The recent conversion of the xfsaild functionality to a work queue introduced a hard-to-hit log space grant hang. The main cause is a regression where a work exit path fails to clear the PUSHING state and recheck the target correctly. Make both exit paths do the same PUSHING bit clearing and target checking when the "no more work to be done" condition is hit. Signed-off-by: Dave Chinner Reviewed-by: Christoph Hellwig Reviewed-by: Alex Elder (cherry picked from commit ea35a20021f8497390d05b93271b4d675516c654) diff --git a/fs/xfs/xfs_trans_ail.c b/fs/xfs/xfs_trans_ail.c index acdb92f..226c58b 100644 --- a/fs/xfs/xfs_trans_ail.c +++ b/fs/xfs/xfs_trans_ail.c @@ -346,18 +346,20 @@ xfs_ail_delete( */ STATIC void xfs_ail_worker( - struct work_struct *work) + struct work_struct *work) { - struct xfs_ail *ailp = container_of(to_delayed_work(work), + struct xfs_ail *ailp = container_of(to_delayed_work(work), struct xfs_ail, xa_work); - long tout; - xfs_lsn_t target = ailp->xa_target; - xfs_lsn_t lsn; - xfs_log_item_t *lip; - int flush_log, count, stuck; - xfs_mount_t *mp = ailp->xa_mount; + xfs_mount_t *mp = ailp->xa_mount; struct xfs_ail_cursor *cur = &ailp->xa_cursors; - int push_xfsbufd = 0; + xfs_log_item_t *lip; + xfs_lsn_t lsn; + xfs_lsn_t target = ailp->xa_target; + long tout = 10; + int flush_log = 0; + int stuck = 0; + int count = 0; + int push_xfsbufd = 0; spin_lock(&ailp->xa_lock); xfs_trans_ail_cursor_init(ailp, cur); @@ -368,8 +370,7 @@ xfs_ail_worker( */ xfs_trans_ail_cursor_done(ailp, cur); spin_unlock(&ailp->xa_lock); - ailp->xa_last_pushed_lsn = 0; - return; + goto out_done; } XFS_STATS_INC(xs_push_ail); @@ -386,7 +387,6 @@ xfs_ail_worker( * lots of contention on the AIL lists. */ lsn = lip->li_lsn; - flush_log = stuck = count = 0; while ((XFS_LSN_CMP(lip->li_lsn, target) < 0)) { int lock_result; /* @@ -480,7 +480,7 @@ xfs_ail_worker( } /* assume we have more work to do in a short while */ - tout = 10; +out_done: if (!count) { /* We're past our target or empty, so idle */ ailp->xa_last_pushed_lsn = 0; -- cgit v0.10.2 From 50e86686dfb287d720af8b0f977202d205c04215 Mon Sep 17 00:00:00 2001 From: Dave Chinner Date: Fri, 6 May 2011 02:54:06 +0000 Subject: xfs: always push the AIL to the target The recent conversion of the xfsaild functionality to a work queue introduced a hard-to-hit log space grant hang. One of the problems discovered is a target mismatch between the item pushing loop and the target itself. The push trigger checks for the target increasing (i.e. new target > current) while the push loop only pushes items that have a LSN < current. As a result, we can get the situation where the push target is X, the items at the tail of the AIL have LSN X and they don't get pushed. The push work then completes thinking it is done, and cannot be restarted until the push target increases to >= X + 1. If the push target then never increases (because the tail is not moving), then we never run the push work again and we stall. Fix it by making sure log items with a LSN that matches the target exactly are pushed during the loop. Signed-off-by: Dave Chinner Reviewed-by: Christoph Hellwig Reviewed-by: Alex Elder (cherry picked from commit cb64026b6e8af50db598ec7c3f59d504259b00bb) diff --git a/fs/xfs/xfs_trans_ail.c b/fs/xfs/xfs_trans_ail.c index 226c58b..9f427c2 100644 --- a/fs/xfs/xfs_trans_ail.c +++ b/fs/xfs/xfs_trans_ail.c @@ -387,7 +387,7 @@ xfs_ail_worker( * lots of contention on the AIL lists. */ lsn = lip->li_lsn; - while ((XFS_LSN_CMP(lip->li_lsn, target) < 0)) { + while ((XFS_LSN_CMP(lip->li_lsn, target) <= 0)) { int lock_result; /* * If we can lock the item without sleeping, unlock the AIL -- cgit v0.10.2 From fe0da767311933d1c1907cb8d326beea7a3cbd9c Mon Sep 17 00:00:00 2001 From: Dave Chinner Date: Fri, 6 May 2011 02:54:07 +0000 Subject: xfs: make AIL target updates and compares 32bit safe. The recent conversion of the xfsaild functionality to a work queue introduced a hard-to-hit log space grant hang. One of the problems noticed was that updates of the push target are not 32 bit safe as the target is a 64 bit value. We cannot copy a 64 bit LSN without the possibility of corrupting the result when racing with another updating thread. We have function to do this update safely without needing to care about 32/64 bit issues - xfs_trans_ail_copy_lsn() - so use that when updating the AIL push target. Also move the reading of the target in the push work inside the AIL lock, and use XFS_LSN_CMP() for the unlocked comparison during work termination to close read holes as well. Signed-off-by: Dave Chinner Reviewed-by: Christoph Hellwig Reviewed-by: Alex Elder (cherry picked from commit fd5670f22fce247754243cf2ed41941e5762d990) diff --git a/fs/xfs/xfs_trans_ail.c b/fs/xfs/xfs_trans_ail.c index 9f427c2..d7eebbf 100644 --- a/fs/xfs/xfs_trans_ail.c +++ b/fs/xfs/xfs_trans_ail.c @@ -354,7 +354,7 @@ xfs_ail_worker( struct xfs_ail_cursor *cur = &ailp->xa_cursors; xfs_log_item_t *lip; xfs_lsn_t lsn; - xfs_lsn_t target = ailp->xa_target; + xfs_lsn_t target; long tout = 10; int flush_log = 0; int stuck = 0; @@ -362,6 +362,7 @@ xfs_ail_worker( int push_xfsbufd = 0; spin_lock(&ailp->xa_lock); + target = ailp->xa_target; xfs_trans_ail_cursor_init(ailp, cur); lip = xfs_trans_ail_cursor_first(ailp, cur, ailp->xa_last_pushed_lsn); if (!lip || XFS_FORCED_SHUTDOWN(mp)) { @@ -491,7 +492,7 @@ out_done: * work to do. Wait a bit longer before starting that work. */ smp_rmb(); - if (ailp->xa_target == target) { + if (XFS_LSN_CMP(ailp->xa_target, target) == 0) { clear_bit(XFS_AIL_PUSHING_BIT, &ailp->xa_flags); return; } @@ -553,7 +554,7 @@ xfs_ail_push( * the XFS_AIL_PUSHING_BIT. */ smp_wmb(); - ailp->xa_target = threshold_lsn; + xfs_trans_ail_copy_lsn(ailp, &ailp->xa_target, &threshold_lsn); if (!test_and_set_bit(XFS_AIL_PUSHING_BIT, &ailp->xa_flags)) queue_delayed_work(xfs_syncd_wq, &ailp->xa_work, 0); } -- cgit v0.10.2 From 7ac956576d0ce8f97450a39c2f304db8eea01647 Mon Sep 17 00:00:00 2001 From: Dave Chinner Date: Fri, 6 May 2011 02:54:08 +0000 Subject: xfs: fix race condition in AIL push trigger The recent conversion of the xfsaild functionality to a work queue introduced a hard-to-hit log space grant hang. One is caused by a race condition in determining whether there is a psh in progress or not. The XFS_AIL_PUSHING_BIT is used to determine whether a push is currently in progress. When the AIL push work completes, it checked whether the target changed and cleared the PUSHING bit to allow a new push to be requeued. The race condition is as follows: Thread 1 push work smp_wmb() smp_rmb() check ailp->xa_target unchanged update ailp->xa_target test/set PUSHING bit does not queue clear PUSHING bit does not requeue Now that the push target is updated, new attempts to push the AIL will not trigger as the push target will be the same, and hence despite trying to push the AIL we won't ever wake it again. The fix is to ensure that the AIL push work clears the PUSHING bit before it checks if the target is unchanged. As a result, both push triggers operate on the same test/set bit criteria, so even if we race in the push work and miss the target update, the thread requesting the push will still set the PUSHING bit and queue the push work to occur. For safety sake, the same queue check is done if the push work detects the target change, though only one of the two will will queue new work due to the use of test_and_set_bit() checks. Signed-off-by: Dave Chinner Reviewed-by: Christoph Hellwig Reviewed-by: Alex Elder (cherry picked from commit e4d3c4a43b595d5124ae824d300626e6489ae857) diff --git a/fs/xfs/xfs_trans_ail.c b/fs/xfs/xfs_trans_ail.c index d7eebbf..5fc2380 100644 --- a/fs/xfs/xfs_trans_ail.c +++ b/fs/xfs/xfs_trans_ail.c @@ -487,15 +487,19 @@ out_done: ailp->xa_last_pushed_lsn = 0; /* - * Check for an updated push target before clearing the - * XFS_AIL_PUSHING_BIT. If the target changed, we've got more - * work to do. Wait a bit longer before starting that work. + * We clear the XFS_AIL_PUSHING_BIT first before checking + * whether the target has changed. If the target has changed, + * this pushes the requeue race directly onto the result of the + * atomic test/set bit, so we are guaranteed that either the + * the pusher that changed the target or ourselves will requeue + * the work (but not both). */ + clear_bit(XFS_AIL_PUSHING_BIT, &ailp->xa_flags); smp_rmb(); - if (XFS_LSN_CMP(ailp->xa_target, target) == 0) { - clear_bit(XFS_AIL_PUSHING_BIT, &ailp->xa_flags); + if (XFS_LSN_CMP(ailp->xa_target, target) == 0 || + test_and_set_bit(XFS_AIL_PUSHING_BIT, &ailp->xa_flags)) return; - } + tout = 50; } else if (XFS_LSN_CMP(lsn, target) >= 0) { /* -- cgit v0.10.2 From 42c36f63ac1366ab0ecc2d5717821362c259f517 Mon Sep 17 00:00:00 2001 From: Hugh Dickins Date: Mon, 9 May 2011 17:44:42 -0700 Subject: vm: fix vm_pgoff wrap in upward expansion Commit a626ca6a6564 ("vm: fix vm_pgoff wrap in stack expansion") fixed the case of an expanding mapping causing vm_pgoff wrapping when you had downward stack expansion. But there was another case where IA64 and PA-RISC expand mappings: upward expansion. This fixes that case too. Signed-off-by: Hugh Dickins Cc: stable@kernel.org Signed-off-by: Linus Torvalds diff --git a/mm/mmap.c b/mm/mmap.c index e27e0cf..772140c 100644 --- a/mm/mmap.c +++ b/mm/mmap.c @@ -1767,10 +1767,13 @@ int expand_upwards(struct vm_area_struct *vma, unsigned long address) size = address - vma->vm_start; grow = (address - vma->vm_end) >> PAGE_SHIFT; - error = acct_stack_growth(vma, size, grow); - if (!error) { - vma->vm_end = address; - perf_event_mmap(vma); + error = -ENOMEM; + if (vma->vm_pgoff + (size >> PAGE_SHIFT) >= vma->vm_pgoff) { + error = acct_stack_growth(vma, size, grow); + if (!error) { + vma->vm_end = address; + perf_event_mmap(vma); + } } } vma_unlock_anon_vma(vma); -- cgit v0.10.2 From 693d92a1bbc9e42681c42ed190bd42b636ca876f Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Mon, 9 May 2011 19:33:54 -0700 Subject: Linux 2.6.39-rc7 diff --git a/Makefile b/Makefile index 28820f7..41ea6fb 100644 --- a/Makefile +++ b/Makefile @@ -1,7 +1,7 @@ VERSION = 2 PATCHLEVEL = 6 SUBLEVEL = 39 -EXTRAVERSION = -rc6 +EXTRAVERSION = -rc7 NAME = Flesh-Eating Bats with Fangs # *DOCUMENTATION* -- cgit v0.10.2 From 3cd7967825a2b3926dc96ae566d986c4420919f7 Mon Sep 17 00:00:00 2001 From: "M. Mohan Kumar" Date: Fri, 15 Apr 2011 13:59:33 +0530 Subject: net/9p: Handle get_user_pages_fast return properly Use proper data type to handle get_user_pages_fast error condition. Also do not treat EFAULT error as fatal. Signed-off-by: M. Mohan Kumar Signed-off-by: Venkateswararao Jujjuri Signed-off-by: Eric Van Hensbergen diff --git a/net/9p/client.c b/net/9p/client.c index 7736774..a9aa2dd 100644 --- a/net/9p/client.c +++ b/net/9p/client.c @@ -614,7 +614,7 @@ p9_client_rpc(struct p9_client *c, int8_t type, const char *fmt, ...) err = c->trans_mod->request(c, req); if (err < 0) { - if (err != -ERESTARTSYS) + if (err != -ERESTARTSYS && err != -EFAULT) c->status = Disconnected; goto reterr; } diff --git a/net/9p/trans_common.c b/net/9p/trans_common.c index e883172..9a70ebd 100644 --- a/net/9p/trans_common.c +++ b/net/9p/trans_common.c @@ -63,7 +63,7 @@ p9_payload_gup(struct p9_req_t *req, size_t *pdata_off, int *pdata_len, int nr_pages, u8 rw) { uint32_t first_page_bytes = 0; - uint32_t pdata_mapped_pages; + int32_t pdata_mapped_pages; struct trans_rpage_info *rpinfo; *pdata_off = (__force size_t)req->tc->pubuf & (PAGE_SIZE-1); @@ -75,14 +75,9 @@ p9_payload_gup(struct p9_req_t *req, size_t *pdata_off, int *pdata_len, rpinfo = req->tc->private; pdata_mapped_pages = get_user_pages_fast((unsigned long)req->tc->pubuf, nr_pages, rw, &rpinfo->rp_data[0]); + if (pdata_mapped_pages <= 0) + return pdata_mapped_pages; - if (pdata_mapped_pages < 0) { - printk(KERN_ERR "get_user_pages_fast failed:%d udata:%p" - "nr_pages:%d\n", pdata_mapped_pages, - req->tc->pubuf, nr_pages); - pdata_mapped_pages = 0; - return -EIO; - } rpinfo->rp_nr_pages = pdata_mapped_pages; if (*pdata_off) { *pdata_len = first_page_bytes; -- cgit v0.10.2 From 43b752daae9445a3b2b075a236840d801fce1593 Mon Sep 17 00:00:00 2001 From: "Hefty, Sean" Date: Mon, 9 May 2011 22:06:10 -0700 Subject: RDMA/cma: Fix handling of IPv6 addressing in cma_use_port cma_use_port() assumes that the sockaddr is an IPv4 address. Since IPv6 addressing is supported (and also to support other address families) make the code more generic in its address handling. Signed-off-by: Sean Hefty Signed-off-by: Roland Dreier diff --git a/drivers/infiniband/core/cma.c b/drivers/infiniband/core/cma.c index 5ed9d25..eff5e46 100644 --- a/drivers/infiniband/core/cma.c +++ b/drivers/infiniband/core/cma.c @@ -712,6 +712,21 @@ static inline int cma_any_addr(struct sockaddr *addr) return cma_zero_addr(addr) || cma_loopback_addr(addr); } +static int cma_addr_cmp(struct sockaddr *src, struct sockaddr *dst) +{ + if (src->sa_family != dst->sa_family) + return -1; + + switch (src->sa_family) { + case AF_INET: + return ((struct sockaddr_in *) src)->sin_addr.s_addr != + ((struct sockaddr_in *) dst)->sin_addr.s_addr; + default: + return ipv6_addr_cmp(&((struct sockaddr_in6 *) src)->sin6_addr, + &((struct sockaddr_in6 *) dst)->sin6_addr); + } +} + static inline __be16 cma_port(struct sockaddr *addr) { if (addr->sa_family == AF_INET) @@ -2168,13 +2183,13 @@ retry: static int cma_use_port(struct idr *ps, struct rdma_id_private *id_priv) { struct rdma_id_private *cur_id; - struct sockaddr_in *sin, *cur_sin; + struct sockaddr *addr, *cur_addr; struct rdma_bind_list *bind_list; struct hlist_node *node; unsigned short snum; - sin = (struct sockaddr_in *) &id_priv->id.route.addr.src_addr; - snum = ntohs(sin->sin_port); + addr = (struct sockaddr *) &id_priv->id.route.addr.src_addr; + snum = ntohs(cma_port(addr)); if (snum < PROT_SOCK && !capable(CAP_NET_BIND_SERVICE)) return -EACCES; @@ -2186,15 +2201,15 @@ static int cma_use_port(struct idr *ps, struct rdma_id_private *id_priv) * We don't support binding to any address if anyone is bound to * a specific address on the same port. */ - if (cma_any_addr((struct sockaddr *) &id_priv->id.route.addr.src_addr)) + if (cma_any_addr(addr)) return -EADDRNOTAVAIL; hlist_for_each_entry(cur_id, node, &bind_list->owners, node) { - if (cma_any_addr((struct sockaddr *) &cur_id->id.route.addr.src_addr)) + cur_addr = (struct sockaddr *) &cur_id->id.route.addr.src_addr; + if (cma_any_addr(cur_addr)) return -EADDRNOTAVAIL; - cur_sin = (struct sockaddr_in *) &cur_id->id.route.addr.src_addr; - if (sin->sin_addr.s_addr == cur_sin->sin_addr.s_addr) + if (!cma_addr_cmp(addr, cur_addr)) return -EADDRINUSE; } -- cgit v0.10.2 From a9bb79128aa659f97b774b97c9bb1bdc74444595 Mon Sep 17 00:00:00 2001 From: "Hefty, Sean" Date: Mon, 9 May 2011 22:06:10 -0700 Subject: RDMA/cma: Add an ID_REUSEADDR option Lustre requires that clients bind to a privileged port number before connecting to a remote server. On larger clusters (typically more than about 1000 nodes), the number of privileged ports is exhausted, resulting in lustre being unusable. To handle this, we add support for reusable addresses to the rdma_cm. This mimics the behavior of the socket option SO_REUSEADDR. A user may set an rdma_cm_id to reuse an address before calling rdma_bind_addr() (explicitly or implicitly). If set, other rdma_cm_id's may be bound to the same address, provided that they all have reuse enabled, and there are no active listens. If rdma_listen() is called on an rdma_cm_id that has reuse enabled, it will only succeed if there are no other id's bound to that same address. The reuse option is exported to user space. The behavior of the kernel reuse implementation was verified against that given by sockets. This patch is derived from a path by Ira Weiny Signed-off-by: Sean Hefty Signed-off-by: Roland Dreier diff --git a/drivers/infiniband/core/cma.c b/drivers/infiniband/core/cma.c index eff5e46..99dde87 100644 --- a/drivers/infiniband/core/cma.c +++ b/drivers/infiniband/core/cma.c @@ -148,6 +148,7 @@ struct rdma_id_private { u32 qp_num; u8 srq; u8 tos; + u8 reuseaddr; }; struct cma_multicast { @@ -1579,50 +1580,6 @@ static void cma_listen_on_all(struct rdma_id_private *id_priv) mutex_unlock(&lock); } -int rdma_listen(struct rdma_cm_id *id, int backlog) -{ - struct rdma_id_private *id_priv; - int ret; - - id_priv = container_of(id, struct rdma_id_private, id); - if (id_priv->state == CMA_IDLE) { - ((struct sockaddr *) &id->route.addr.src_addr)->sa_family = AF_INET; - ret = rdma_bind_addr(id, (struct sockaddr *) &id->route.addr.src_addr); - if (ret) - return ret; - } - - if (!cma_comp_exch(id_priv, CMA_ADDR_BOUND, CMA_LISTEN)) - return -EINVAL; - - id_priv->backlog = backlog; - if (id->device) { - switch (rdma_node_get_transport(id->device->node_type)) { - case RDMA_TRANSPORT_IB: - ret = cma_ib_listen(id_priv); - if (ret) - goto err; - break; - case RDMA_TRANSPORT_IWARP: - ret = cma_iw_listen(id_priv, backlog); - if (ret) - goto err; - break; - default: - ret = -ENOSYS; - goto err; - } - } else - cma_listen_on_all(id_priv); - - return 0; -err: - id_priv->backlog = 0; - cma_comp_exch(id_priv, CMA_LISTEN, CMA_ADDR_BOUND); - return ret; -} -EXPORT_SYMBOL(rdma_listen); - void rdma_set_service_type(struct rdma_cm_id *id, int tos) { struct rdma_id_private *id_priv; @@ -2105,6 +2062,25 @@ err: } EXPORT_SYMBOL(rdma_resolve_addr); +int rdma_set_reuseaddr(struct rdma_cm_id *id, int reuse) +{ + struct rdma_id_private *id_priv; + unsigned long flags; + int ret; + + id_priv = container_of(id, struct rdma_id_private, id); + spin_lock_irqsave(&id_priv->lock, flags); + if (id_priv->state == CMA_IDLE) { + id_priv->reuseaddr = reuse; + ret = 0; + } else { + ret = -EINVAL; + } + spin_unlock_irqrestore(&id_priv->lock, flags); + return ret; +} +EXPORT_SYMBOL(rdma_set_reuseaddr); + static void cma_bind_port(struct rdma_bind_list *bind_list, struct rdma_id_private *id_priv) { @@ -2180,43 +2156,73 @@ retry: return -EADDRNOTAVAIL; } -static int cma_use_port(struct idr *ps, struct rdma_id_private *id_priv) +/* + * Check that the requested port is available. This is called when trying to + * bind to a specific port, or when trying to listen on a bound port. In + * the latter case, the provided id_priv may already be on the bind_list, but + * we still need to check that it's okay to start listening. + */ +static int cma_check_port(struct rdma_bind_list *bind_list, + struct rdma_id_private *id_priv, uint8_t reuseaddr) { struct rdma_id_private *cur_id; struct sockaddr *addr, *cur_addr; - struct rdma_bind_list *bind_list; struct hlist_node *node; - unsigned short snum; addr = (struct sockaddr *) &id_priv->id.route.addr.src_addr; - snum = ntohs(cma_port(addr)); - if (snum < PROT_SOCK && !capable(CAP_NET_BIND_SERVICE)) - return -EACCES; - - bind_list = idr_find(ps, snum); - if (!bind_list) - return cma_alloc_port(ps, id_priv, snum); - - /* - * We don't support binding to any address if anyone is bound to - * a specific address on the same port. - */ - if (cma_any_addr(addr)) + if (cma_any_addr(addr) && !reuseaddr) return -EADDRNOTAVAIL; hlist_for_each_entry(cur_id, node, &bind_list->owners, node) { - cur_addr = (struct sockaddr *) &cur_id->id.route.addr.src_addr; - if (cma_any_addr(cur_addr)) - return -EADDRNOTAVAIL; + if (id_priv == cur_id) + continue; - if (!cma_addr_cmp(addr, cur_addr)) - return -EADDRINUSE; - } + if ((cur_id->state == CMA_LISTEN) || + !reuseaddr || !cur_id->reuseaddr) { + cur_addr = (struct sockaddr *) &cur_id->id.route.addr.src_addr; + if (cma_any_addr(cur_addr)) + return -EADDRNOTAVAIL; - cma_bind_port(bind_list, id_priv); + if (!cma_addr_cmp(addr, cur_addr)) + return -EADDRINUSE; + } + } return 0; } +static int cma_use_port(struct idr *ps, struct rdma_id_private *id_priv) +{ + struct rdma_bind_list *bind_list; + unsigned short snum; + int ret; + + snum = ntohs(cma_port((struct sockaddr *) &id_priv->id.route.addr.src_addr)); + if (snum < PROT_SOCK && !capable(CAP_NET_BIND_SERVICE)) + return -EACCES; + + bind_list = idr_find(ps, snum); + if (!bind_list) { + ret = cma_alloc_port(ps, id_priv, snum); + } else { + ret = cma_check_port(bind_list, id_priv, id_priv->reuseaddr); + if (!ret) + cma_bind_port(bind_list, id_priv); + } + return ret; +} + +static int cma_bind_listen(struct rdma_id_private *id_priv) +{ + struct rdma_bind_list *bind_list = id_priv->bind_list; + int ret = 0; + + mutex_lock(&lock); + if (bind_list->owners.first->next) + ret = cma_check_port(bind_list, id_priv, 0); + mutex_unlock(&lock); + return ret; +} + static int cma_get_port(struct rdma_id_private *id_priv) { struct idr *ps; @@ -2268,6 +2274,56 @@ static int cma_check_linklocal(struct rdma_dev_addr *dev_addr, return 0; } +int rdma_listen(struct rdma_cm_id *id, int backlog) +{ + struct rdma_id_private *id_priv; + int ret; + + id_priv = container_of(id, struct rdma_id_private, id); + if (id_priv->state == CMA_IDLE) { + ((struct sockaddr *) &id->route.addr.src_addr)->sa_family = AF_INET; + ret = rdma_bind_addr(id, (struct sockaddr *) &id->route.addr.src_addr); + if (ret) + return ret; + } + + if (!cma_comp_exch(id_priv, CMA_ADDR_BOUND, CMA_LISTEN)) + return -EINVAL; + + if (id_priv->reuseaddr) { + ret = cma_bind_listen(id_priv); + if (ret) + goto err; + } + + id_priv->backlog = backlog; + if (id->device) { + switch (rdma_node_get_transport(id->device->node_type)) { + case RDMA_TRANSPORT_IB: + ret = cma_ib_listen(id_priv); + if (ret) + goto err; + break; + case RDMA_TRANSPORT_IWARP: + ret = cma_iw_listen(id_priv, backlog); + if (ret) + goto err; + break; + default: + ret = -ENOSYS; + goto err; + } + } else + cma_listen_on_all(id_priv); + + return 0; +err: + id_priv->backlog = 0; + cma_comp_exch(id_priv, CMA_LISTEN, CMA_ADDR_BOUND); + return ret; +} +EXPORT_SYMBOL(rdma_listen); + int rdma_bind_addr(struct rdma_cm_id *id, struct sockaddr *addr) { struct rdma_id_private *id_priv; diff --git a/drivers/infiniband/core/ucma.c b/drivers/infiniband/core/ucma.c index ec1e9da..b3fa798 100644 --- a/drivers/infiniband/core/ucma.c +++ b/drivers/infiniband/core/ucma.c @@ -883,6 +883,13 @@ static int ucma_set_option_id(struct ucma_context *ctx, int optname, } rdma_set_service_type(ctx->cm_id, *((u8 *) optval)); break; + case RDMA_OPTION_ID_REUSEADDR: + if (optlen != sizeof(int)) { + ret = -EINVAL; + break; + } + ret = rdma_set_reuseaddr(ctx->cm_id, *((int *) optval) ? 1 : 0); + break; default: ret = -ENOSYS; } diff --git a/include/rdma/rdma_cm.h b/include/rdma/rdma_cm.h index 4fae903..169f7a5 100644 --- a/include/rdma/rdma_cm.h +++ b/include/rdma/rdma_cm.h @@ -329,4 +329,14 @@ void rdma_leave_multicast(struct rdma_cm_id *id, struct sockaddr *addr); */ void rdma_set_service_type(struct rdma_cm_id *id, int tos); +/** + * rdma_set_reuseaddr - Allow the reuse of local addresses when binding + * the rdma_cm_id. + * @id: Communication identifier to configure. + * @reuse: Value indicating if the bound address is reusable. + * + * Reuse must be set before an address is bound to the id. + */ +int rdma_set_reuseaddr(struct rdma_cm_id *id, int reuse); + #endif /* RDMA_CM_H */ diff --git a/include/rdma/rdma_user_cm.h b/include/rdma/rdma_user_cm.h index 1d16502..fc82c18 100644 --- a/include/rdma/rdma_user_cm.h +++ b/include/rdma/rdma_user_cm.h @@ -221,8 +221,9 @@ enum { /* Option details */ enum { - RDMA_OPTION_ID_TOS = 0, - RDMA_OPTION_IB_PATH = 1 + RDMA_OPTION_ID_TOS = 0, + RDMA_OPTION_ID_REUSEADDR = 1, + RDMA_OPTION_IB_PATH = 1 }; struct rdma_ucm_set_option { -- cgit v0.10.2 From 30c95c2d495c1c8d4d6a97bb9f4e4eacb91ba1d2 Mon Sep 17 00:00:00 2001 From: Steve Wise Date: Mon, 9 May 2011 22:06:22 -0700 Subject: RDMA/cxgb4: Don't change QP state outside EP lock Concurrent ingress CLOSE and ULP ABORT operations causes a crash due to a race condition where the close path releases the EP lock and then tries to move the QP state to CLOSED. This must be done inside the EP lock to avoid the race. Signed-off-by: Steve Wise Signed-off-by: Roland Dreier diff --git a/drivers/infiniband/hw/cxgb4/cm.c b/drivers/infiniband/hw/cxgb4/cm.c index 9d8dcfa..d235810 100644 --- a/drivers/infiniband/hw/cxgb4/cm.c +++ b/drivers/infiniband/hw/cxgb4/cm.c @@ -1466,7 +1466,7 @@ static int peer_close(struct c4iw_dev *dev, struct sk_buff *skb) struct c4iw_qp_attributes attrs; int disconnect = 1; int release = 0; - int closing = 0; + int abort = 0; struct tid_info *t = dev->rdev.lldi.tids; unsigned int tid = GET_TID(hdr); @@ -1507,8 +1507,11 @@ static int peer_close(struct c4iw_dev *dev, struct sk_buff *skb) case FPDU_MODE: start_ep_timer(ep); __state_set(&ep->com, CLOSING); - closing = 1; + attrs.next_state = C4IW_QP_STATE_CLOSING; + abort = c4iw_modify_qp(ep->com.qp->rhp, ep->com.qp, + C4IW_QP_ATTR_NEXT_STATE, &attrs, 1); peer_close_upcall(ep); + disconnect = 1; break; case ABORTING: disconnect = 0; @@ -1536,11 +1539,6 @@ static int peer_close(struct c4iw_dev *dev, struct sk_buff *skb) BUG_ON(1); } mutex_unlock(&ep->com.mutex); - if (closing) { - attrs.next_state = C4IW_QP_STATE_CLOSING; - c4iw_modify_qp(ep->com.qp->rhp, ep->com.qp, - C4IW_QP_ATTR_NEXT_STATE, &attrs, 1); - } if (disconnect) c4iw_ep_disconnect(ep, 0, GFP_KERNEL); if (release) @@ -1710,14 +1708,14 @@ static int terminate(struct c4iw_dev *dev, struct sk_buff *skb) ep = lookup_tid(t, tid); BUG_ON(!ep); - if (ep->com.qp) { + if (ep && ep->com.qp) { printk(KERN_WARNING MOD "TERM received tid %u qpid %u\n", tid, ep->com.qp->wq.sq.qid); attrs.next_state = C4IW_QP_STATE_TERMINATE; c4iw_modify_qp(ep->com.qp->rhp, ep->com.qp, C4IW_QP_ATTR_NEXT_STATE, &attrs, 1); } else - printk(KERN_WARNING MOD "TERM received tid %u no qp\n", tid); + printk(KERN_WARNING MOD "TERM received tid %u no ep/qp\n", tid); return 0; } diff --git a/drivers/infiniband/hw/cxgb4/iw_cxgb4.h b/drivers/infiniband/hw/cxgb4/iw_cxgb4.h index 9f6166f..8e16eb2 100644 --- a/drivers/infiniband/hw/cxgb4/iw_cxgb4.h +++ b/drivers/infiniband/hw/cxgb4/iw_cxgb4.h @@ -161,8 +161,8 @@ static inline int c4iw_wait_for_reply(struct c4iw_rdev *rdev, } } while (!wr_waitp->done); if (wr_waitp->ret) - printk(KERN_WARNING MOD "%s: FW reply %d tid %u qpid %u\n", - pci_name(rdev->lldi.pdev), wr_waitp->ret, hwtid, qpid); + PDBG("%s: FW reply %d tid %u qpid %u\n", + pci_name(rdev->lldi.pdev), wr_waitp->ret, hwtid, qpid); return wr_waitp->ret; } diff --git a/drivers/infiniband/hw/cxgb4/qp.c b/drivers/infiniband/hw/cxgb4/qp.c index 70a5a3c..a1824a5 100644 --- a/drivers/infiniband/hw/cxgb4/qp.c +++ b/drivers/infiniband/hw/cxgb4/qp.c @@ -1210,7 +1210,6 @@ int c4iw_modify_qp(struct c4iw_dev *rhp, struct c4iw_qp *qhp, if (ret) { if (internal) c4iw_get_ep(&qhp->ep->com); - disconnect = abort = 1; goto err; } break; -- cgit v0.10.2 From bbe9a0a2bc07cf30c5b89b51154f2c87200a5dfd Mon Sep 17 00:00:00 2001 From: Steve Wise Date: Mon, 9 May 2011 22:06:22 -0700 Subject: RDMA/cxgb4: Initialization errors can cause crash c4iw_uld_add() must return ERR_PTR() values instead of NULL on failure. Signed-off-by: Steve Wise Signed-off-by: Roland Dreier diff --git a/drivers/infiniband/hw/cxgb4/device.c b/drivers/infiniband/hw/cxgb4/device.c index e29172c..8e70953 100644 --- a/drivers/infiniband/hw/cxgb4/device.c +++ b/drivers/infiniband/hw/cxgb4/device.c @@ -392,7 +392,7 @@ static struct c4iw_dev *c4iw_alloc(const struct cxgb4_lld_info *infop) devp = (struct c4iw_dev *)ib_alloc_device(sizeof(*devp)); if (!devp) { printk(KERN_ERR MOD "Cannot allocate ib device\n"); - return NULL; + return ERR_PTR(-ENOMEM); } devp->rdev.lldi = *infop; @@ -414,7 +414,7 @@ static struct c4iw_dev *c4iw_alloc(const struct cxgb4_lld_info *infop) mutex_unlock(&dev_mutex); printk(KERN_ERR MOD "Unable to open CXIO rdev err %d\n", ret); ib_dealloc_device(&devp->ibdev); - return NULL; + return ERR_PTR(ret); } idr_init(&devp->cqidr); @@ -444,7 +444,7 @@ static void *c4iw_uld_add(const struct cxgb4_lld_info *infop) DRV_VERSION); dev = c4iw_alloc(infop); - if (!dev) + if (IS_ERR(dev)) goto out; PDBG("%s found device %s nchan %u nrxq %u ntxq %u nports %u\n", -- cgit v0.10.2 From 85d215b0f316bee0a6936bd1a5f21abf03333eaa Mon Sep 17 00:00:00 2001 From: Roel Kluin Date: Mon, 9 May 2011 22:06:22 -0700 Subject: RDMA/cxgb4: Fix missing parentheses Parens are missing: '|' has a higher presedence than '?'. Signed-off-by: Roel Kluin Acked-by: Steve Wise Signed-off-by: Roland Dreier diff --git a/drivers/infiniband/hw/cxgb4/qp.c b/drivers/infiniband/hw/cxgb4/qp.c index a1824a5..3b773b0 100644 --- a/drivers/infiniband/hw/cxgb4/qp.c +++ b/drivers/infiniband/hw/cxgb4/qp.c @@ -214,7 +214,7 @@ static int create_qp(struct c4iw_rdev *rdev, struct t4_wq *wq, V_FW_RI_RES_WR_HOSTFCMODE(0) | /* no host cidx updates */ V_FW_RI_RES_WR_CPRIO(0) | /* don't keep in chip cache */ V_FW_RI_RES_WR_PCIECHN(0) | /* set by uP at ri_init time */ - t4_sq_onchip(&wq->sq) ? F_FW_RI_RES_WR_ONCHIP : 0 | + (t4_sq_onchip(&wq->sq) ? F_FW_RI_RES_WR_ONCHIP : 0) | V_FW_RI_RES_WR_IQID(scq->cqid)); res->u.sqrq.dcaen_to_eqsize = cpu_to_be32( V_FW_RI_RES_WR_DCAEN(0) | -- cgit v0.10.2 From d9594d990a528d4c444777d0f360bb50c6114825 Mon Sep 17 00:00:00 2001 From: Steve Wise Date: Mon, 9 May 2011 22:06:22 -0700 Subject: RDMA/cxgb4: Reset wait condition atomically The driver was never really waiting for RDMA_WR/FINI completions because the condition variable used to determine if the completion happened was never reset, and this condition variable is reused for both connection setup and teardown. This causes various driver crashes under heavy loads due to releasing resources too early. The fix is to use atomic bits to correctly reset the condition immediately after the completion is detected. Signed-off-by: Steve Wise Signed-off-by: Roland Dreier diff --git a/drivers/infiniband/hw/cxgb4/cm.c b/drivers/infiniband/hw/cxgb4/cm.c index d235810..d7ee70f 100644 --- a/drivers/infiniband/hw/cxgb4/cm.c +++ b/drivers/infiniband/hw/cxgb4/cm.c @@ -1198,9 +1198,7 @@ static int pass_open_rpl(struct c4iw_dev *dev, struct sk_buff *skb) } PDBG("%s ep %p status %d error %d\n", __func__, ep, rpl->status, status2errno(rpl->status)); - ep->com.wr_wait.ret = status2errno(rpl->status); - ep->com.wr_wait.done = 1; - wake_up(&ep->com.wr_wait.wait); + c4iw_wake_up(&ep->com.wr_wait, status2errno(rpl->status)); return 0; } @@ -1234,9 +1232,7 @@ static int close_listsrv_rpl(struct c4iw_dev *dev, struct sk_buff *skb) struct c4iw_listen_ep *ep = lookup_stid(t, stid); PDBG("%s ep %p\n", __func__, ep); - ep->com.wr_wait.ret = status2errno(rpl->status); - ep->com.wr_wait.done = 1; - wake_up(&ep->com.wr_wait.wait); + c4iw_wake_up(&ep->com.wr_wait, status2errno(rpl->status)); return 0; } @@ -1492,17 +1488,13 @@ static int peer_close(struct c4iw_dev *dev, struct sk_buff *skb) * in rdma connection migration (see c4iw_accept_cr()). */ __state_set(&ep->com, CLOSING); - ep->com.wr_wait.done = 1; - ep->com.wr_wait.ret = -ECONNRESET; PDBG("waking up ep %p tid %u\n", ep, ep->hwtid); - wake_up(&ep->com.wr_wait.wait); + c4iw_wake_up(&ep->com.wr_wait, -ECONNRESET); break; case MPA_REP_SENT: __state_set(&ep->com, CLOSING); - ep->com.wr_wait.done = 1; - ep->com.wr_wait.ret = -ECONNRESET; PDBG("waking up ep %p tid %u\n", ep, ep->hwtid); - wake_up(&ep->com.wr_wait.wait); + c4iw_wake_up(&ep->com.wr_wait, -ECONNRESET); break; case FPDU_MODE: start_ep_timer(ep); @@ -1579,9 +1571,7 @@ static int peer_abort(struct c4iw_dev *dev, struct sk_buff *skb) /* * Wake up any threads in rdma_init() or rdma_fini(). */ - ep->com.wr_wait.done = 1; - ep->com.wr_wait.ret = -ECONNRESET; - wake_up(&ep->com.wr_wait.wait); + c4iw_wake_up(&ep->com.wr_wait, -ECONNRESET); mutex_lock(&ep->com.mutex); switch (ep->com.state) { @@ -2294,14 +2284,8 @@ static int fw6_msg(struct c4iw_dev *dev, struct sk_buff *skb) ret = (int)((be64_to_cpu(rpl->data[0]) >> 8) & 0xff); wr_waitp = (struct c4iw_wr_wait *)(__force unsigned long) rpl->data[1]; PDBG("%s wr_waitp %p ret %u\n", __func__, wr_waitp, ret); - if (wr_waitp) { - if (ret) - wr_waitp->ret = -ret; - else - wr_waitp->ret = 0; - wr_waitp->done = 1; - wake_up(&wr_waitp->wait); - } + if (wr_waitp) + c4iw_wake_up(wr_waitp, ret ? -ret : 0); kfree_skb(skb); break; case 2: diff --git a/drivers/infiniband/hw/cxgb4/iw_cxgb4.h b/drivers/infiniband/hw/cxgb4/iw_cxgb4.h index 8e16eb2..3dcfe82 100644 --- a/drivers/infiniband/hw/cxgb4/iw_cxgb4.h +++ b/drivers/infiniband/hw/cxgb4/iw_cxgb4.h @@ -131,42 +131,54 @@ static inline int c4iw_num_stags(struct c4iw_rdev *rdev) #define C4IW_WR_TO (10*HZ) +enum { + REPLY_READY = 0, +}; + struct c4iw_wr_wait { wait_queue_head_t wait; - int done; + unsigned long status; int ret; }; static inline void c4iw_init_wr_wait(struct c4iw_wr_wait *wr_waitp) { wr_waitp->ret = 0; - wr_waitp->done = 0; + wr_waitp->status = 0; init_waitqueue_head(&wr_waitp->wait); } +static inline void c4iw_wake_up(struct c4iw_wr_wait *wr_waitp, int ret) +{ + wr_waitp->ret = ret; + set_bit(REPLY_READY, &wr_waitp->status); + wake_up(&wr_waitp->wait); +} + static inline int c4iw_wait_for_reply(struct c4iw_rdev *rdev, struct c4iw_wr_wait *wr_waitp, u32 hwtid, u32 qpid, const char *func) { unsigned to = C4IW_WR_TO; - do { + int ret; - wait_event_timeout(wr_waitp->wait, wr_waitp->done, to); - if (!wr_waitp->done) { + do { + ret = wait_event_timeout(wr_waitp->wait, + test_and_clear_bit(REPLY_READY, &wr_waitp->status), to); + if (!ret) { printk(KERN_ERR MOD "%s - Device %s not responding - " "tid %u qpid %u\n", func, pci_name(rdev->lldi.pdev), hwtid, qpid); to = to << 2; } - } while (!wr_waitp->done); + } while (!ret); if (wr_waitp->ret) PDBG("%s: FW reply %d tid %u qpid %u\n", pci_name(rdev->lldi.pdev), wr_waitp->ret, hwtid, qpid); return wr_waitp->ret; } - struct c4iw_dev { struct ib_device ibdev; struct c4iw_rdev rdev; -- cgit v0.10.2 From 2f25e9a540951ebd533b9b98d2259deb44b0b476 Mon Sep 17 00:00:00 2001 From: Steve Wise Date: Mon, 9 May 2011 22:06:23 -0700 Subject: RDMA/cxgb4: EEH errors can hang the driver A few more EEH fixes: c4iw_wait_for_reply(): detect fatal EEH condition on timeout and return an error. The iw_cxgb4 driver was only calling ib_deregister_device() on an EEH event followed by a ib_register_device() when the device was reinitialized. However, the RDMA core doesn't allow multiple iterations of register/deregister by the provider. See drivers/infiniband/core/sysfs.c: ib_device_unregister_sysfs() where the kobject ref is held until the device is deallocated in ib_deallocate_device(). Calling deregister adds this kobj reference, and then a subsequent register call will generate a WARN_ON() from the kobject subsystem because the kobject is being initialized but is already initialized with the ref held. So the provider must deregister and dealloc when resetting for an EEH event, then alloc/register to re-initialize. To do this, we cannot use the device ptr as our ULD handle since it will change with each reallocation. This commit adds a ULD context struct which is used as the ULD handle, and then contains the device pointer and other state needed. Signed-off-by: Steve Wise Signed-off-by: Roland Dreier diff --git a/drivers/infiniband/hw/cxgb4/device.c b/drivers/infiniband/hw/cxgb4/device.c index 8e70953..40a13cc 100644 --- a/drivers/infiniband/hw/cxgb4/device.c +++ b/drivers/infiniband/hw/cxgb4/device.c @@ -44,7 +44,7 @@ MODULE_DESCRIPTION("Chelsio T4 RDMA Driver"); MODULE_LICENSE("Dual BSD/GPL"); MODULE_VERSION(DRV_VERSION); -static LIST_HEAD(dev_list); +static LIST_HEAD(uld_ctx_list); static DEFINE_MUTEX(dev_mutex); static struct dentry *c4iw_debugfs_root; @@ -370,18 +370,23 @@ static void c4iw_rdev_close(struct c4iw_rdev *rdev) c4iw_destroy_resource(&rdev->resource); } -static void c4iw_remove(struct c4iw_dev *dev) +struct uld_ctx { + struct list_head entry; + struct cxgb4_lld_info lldi; + struct c4iw_dev *dev; +}; + +static void c4iw_remove(struct uld_ctx *ctx) { - PDBG("%s c4iw_dev %p\n", __func__, dev); - list_del(&dev->entry); - if (dev->registered) - c4iw_unregister_device(dev); - c4iw_rdev_close(&dev->rdev); - idr_destroy(&dev->cqidr); - idr_destroy(&dev->qpidr); - idr_destroy(&dev->mmidr); - iounmap(dev->rdev.oc_mw_kva); - ib_dealloc_device(&dev->ibdev); + PDBG("%s c4iw_dev %p\n", __func__, ctx->dev); + c4iw_unregister_device(ctx->dev); + c4iw_rdev_close(&ctx->dev->rdev); + idr_destroy(&ctx->dev->cqidr); + idr_destroy(&ctx->dev->qpidr); + idr_destroy(&ctx->dev->mmidr); + iounmap(ctx->dev->rdev.oc_mw_kva); + ib_dealloc_device(&ctx->dev->ibdev); + ctx->dev = NULL; } static struct c4iw_dev *c4iw_alloc(const struct cxgb4_lld_info *infop) @@ -402,13 +407,11 @@ static struct c4iw_dev *c4iw_alloc(const struct cxgb4_lld_info *infop) devp->rdev.oc_mw_kva = ioremap_wc(devp->rdev.oc_mw_pa, devp->rdev.lldi.vr->ocq.size); - printk(KERN_INFO MOD "ocq memory: " + PDBG(KERN_INFO MOD "ocq memory: " "hw_start 0x%x size %u mw_pa 0x%lx mw_kva %p\n", devp->rdev.lldi.vr->ocq.start, devp->rdev.lldi.vr->ocq.size, devp->rdev.oc_mw_pa, devp->rdev.oc_mw_kva); - mutex_lock(&dev_mutex); - ret = c4iw_rdev_open(&devp->rdev); if (ret) { mutex_unlock(&dev_mutex); @@ -421,8 +424,6 @@ static struct c4iw_dev *c4iw_alloc(const struct cxgb4_lld_info *infop) idr_init(&devp->qpidr); idr_init(&devp->mmidr); spin_lock_init(&devp->lock); - list_add_tail(&devp->entry, &dev_list); - mutex_unlock(&dev_mutex); if (c4iw_debugfs_root) { devp->debugfs_root = debugfs_create_dir( @@ -435,7 +436,7 @@ static struct c4iw_dev *c4iw_alloc(const struct cxgb4_lld_info *infop) static void *c4iw_uld_add(const struct cxgb4_lld_info *infop) { - struct c4iw_dev *dev; + struct uld_ctx *ctx; static int vers_printed; int i; @@ -443,25 +444,33 @@ static void *c4iw_uld_add(const struct cxgb4_lld_info *infop) printk(KERN_INFO MOD "Chelsio T4 RDMA Driver - version %s\n", DRV_VERSION); - dev = c4iw_alloc(infop); - if (IS_ERR(dev)) + ctx = kzalloc(sizeof *ctx, GFP_KERNEL); + if (!ctx) { + ctx = ERR_PTR(-ENOMEM); goto out; + } + ctx->lldi = *infop; PDBG("%s found device %s nchan %u nrxq %u ntxq %u nports %u\n", - __func__, pci_name(dev->rdev.lldi.pdev), - dev->rdev.lldi.nchan, dev->rdev.lldi.nrxq, - dev->rdev.lldi.ntxq, dev->rdev.lldi.nports); + __func__, pci_name(ctx->lldi.pdev), + ctx->lldi.nchan, ctx->lldi.nrxq, + ctx->lldi.ntxq, ctx->lldi.nports); + + mutex_lock(&dev_mutex); + list_add_tail(&ctx->entry, &uld_ctx_list); + mutex_unlock(&dev_mutex); - for (i = 0; i < dev->rdev.lldi.nrxq; i++) - PDBG("rxqid[%u] %u\n", i, dev->rdev.lldi.rxq_ids[i]); + for (i = 0; i < ctx->lldi.nrxq; i++) + PDBG("rxqid[%u] %u\n", i, ctx->lldi.rxq_ids[i]); out: - return dev; + return ctx; } static int c4iw_uld_rx_handler(void *handle, const __be64 *rsp, const struct pkt_gl *gl) { - struct c4iw_dev *dev = handle; + struct uld_ctx *ctx = handle; + struct c4iw_dev *dev = ctx->dev; struct sk_buff *skb; const struct cpl_act_establish *rpl; unsigned int opcode; @@ -503,47 +512,49 @@ nomem: static int c4iw_uld_state_change(void *handle, enum cxgb4_state new_state) { - struct c4iw_dev *dev = handle; + struct uld_ctx *ctx = handle; PDBG("%s new_state %u\n", __func__, new_state); switch (new_state) { case CXGB4_STATE_UP: - printk(KERN_INFO MOD "%s: Up\n", pci_name(dev->rdev.lldi.pdev)); - if (!dev->registered) { - int ret; - ret = c4iw_register_device(dev); - if (ret) + printk(KERN_INFO MOD "%s: Up\n", pci_name(ctx->lldi.pdev)); + if (!ctx->dev) { + int ret = 0; + + ctx->dev = c4iw_alloc(&ctx->lldi); + if (!IS_ERR(ctx->dev)) + ret = c4iw_register_device(ctx->dev); + if (IS_ERR(ctx->dev) || ret) printk(KERN_ERR MOD "%s: RDMA registration failed: %d\n", - pci_name(dev->rdev.lldi.pdev), ret); + pci_name(ctx->lldi.pdev), ret); } break; case CXGB4_STATE_DOWN: printk(KERN_INFO MOD "%s: Down\n", - pci_name(dev->rdev.lldi.pdev)); - if (dev->registered) - c4iw_unregister_device(dev); + pci_name(ctx->lldi.pdev)); + if (ctx->dev) + c4iw_remove(ctx); break; case CXGB4_STATE_START_RECOVERY: printk(KERN_INFO MOD "%s: Fatal Error\n", - pci_name(dev->rdev.lldi.pdev)); - dev->rdev.flags |= T4_FATAL_ERROR; - if (dev->registered) { + pci_name(ctx->lldi.pdev)); + if (ctx->dev) { struct ib_event event; + ctx->dev->rdev.flags |= T4_FATAL_ERROR; memset(&event, 0, sizeof event); event.event = IB_EVENT_DEVICE_FATAL; - event.device = &dev->ibdev; + event.device = &ctx->dev->ibdev; ib_dispatch_event(&event); - c4iw_unregister_device(dev); + c4iw_remove(ctx); } break; case CXGB4_STATE_DETACH: printk(KERN_INFO MOD "%s: Detach\n", - pci_name(dev->rdev.lldi.pdev)); - mutex_lock(&dev_mutex); - c4iw_remove(dev); - mutex_unlock(&dev_mutex); + pci_name(ctx->lldi.pdev)); + if (ctx->dev) + c4iw_remove(ctx); break; } return 0; @@ -576,11 +587,13 @@ static int __init c4iw_init_module(void) static void __exit c4iw_exit_module(void) { - struct c4iw_dev *dev, *tmp; + struct uld_ctx *ctx, *tmp; mutex_lock(&dev_mutex); - list_for_each_entry_safe(dev, tmp, &dev_list, entry) { - c4iw_remove(dev); + list_for_each_entry_safe(ctx, tmp, &uld_ctx_list, entry) { + if (ctx->dev) + c4iw_remove(ctx); + kfree(ctx); } mutex_unlock(&dev_mutex); cxgb4_unregister_uld(CXGB4_ULD_RDMA); diff --git a/drivers/infiniband/hw/cxgb4/iw_cxgb4.h b/drivers/infiniband/hw/cxgb4/iw_cxgb4.h index 3dcfe82..35d2a5d 100644 --- a/drivers/infiniband/hw/cxgb4/iw_cxgb4.h +++ b/drivers/infiniband/hw/cxgb4/iw_cxgb4.h @@ -170,6 +170,10 @@ static inline int c4iw_wait_for_reply(struct c4iw_rdev *rdev, printk(KERN_ERR MOD "%s - Device %s not responding - " "tid %u qpid %u\n", func, pci_name(rdev->lldi.pdev), hwtid, qpid); + if (c4iw_fatal_error(rdev)) { + wr_waitp->ret = -EIO; + break; + } to = to << 2; } } while (!ret); @@ -187,9 +191,7 @@ struct c4iw_dev { struct idr qpidr; struct idr mmidr; spinlock_t lock; - struct list_head entry; struct dentry *debugfs_root; - u8 registered; }; static inline struct c4iw_dev *to_c4iw_dev(struct ib_device *ibdev) diff --git a/drivers/infiniband/hw/cxgb4/provider.c b/drivers/infiniband/hw/cxgb4/provider.c index f66dd8b..5b9e422 100644 --- a/drivers/infiniband/hw/cxgb4/provider.c +++ b/drivers/infiniband/hw/cxgb4/provider.c @@ -516,7 +516,6 @@ int c4iw_register_device(struct c4iw_dev *dev) if (ret) goto bail2; } - dev->registered = 1; return 0; bail2: ib_unregister_device(&dev->ibdev); @@ -535,6 +534,5 @@ void c4iw_unregister_device(struct c4iw_dev *dev) c4iw_class_attributes[i]); ib_unregister_device(&dev->ibdev); kfree(dev->ibdev.iwcm); - dev->registered = 0; return; } -- cgit v0.10.2 From 9f5754e34bf964a41e821b2e0b358bc7c314ca4e Mon Sep 17 00:00:00 2001 From: Mitko Haralanov Date: Mon, 9 May 2011 22:07:31 -0700 Subject: IB/qib: Prevent driver hang with unprogrammed boards The time limit test now correctly checks against current jiffies to avoid the hang. Signed-off-by: Mitko Haralanov Signed-off-by: Mike Marciniszyn Signed-off-by: Roland Dreier diff --git a/drivers/infiniband/hw/qib/qib_iba7322.c b/drivers/infiniband/hw/qib/qib_iba7322.c index 6bab3ea..9f53e68 100644 --- a/drivers/infiniband/hw/qib/qib_iba7322.c +++ b/drivers/infiniband/hw/qib/qib_iba7322.c @@ -7534,7 +7534,8 @@ static int serdes_7322_init_new(struct qib_pportdata *ppd) ibsd_wr_allchans(ppd, 4, (1 << 10), BMASK(10, 10)); tstart = get_jiffies_64(); while (chan_done && - !time_after64(tstart, tstart + msecs_to_jiffies(500))) { + !time_after64(get_jiffies_64(), + tstart + msecs_to_jiffies(500))) { msleep(20); for (chan = 0; chan < SERDES_CHANS; ++chan) { rxcaldone = ahb_mod(ppd->dd, IBSD(ppd->hw_pidx), -- cgit v0.10.2 From ec03d6777a9e2b76917ef6d3fc8a01e174bcb9b1 Mon Sep 17 00:00:00 2001 From: Sergei Shtylyov Date: Mon, 9 May 2011 22:07:31 -0700 Subject: IB/ipath: Use pci_dev->revision, again Commit 44c10138fd4b ("PCI: Change all drivers to use pci_device->revision") already converted this driver to using the revision field of struct pci_dev but commit bb9171448deb ("IB/ipath: Misc changes to prepare for IB7220 introduction") later reverted that change for some strange reason. Restore the change. Signed-off-by: Sergei Shtylyov Acked-by: Mike Marciniszyn Signed-off-by: Roland Dreier diff --git a/drivers/infiniband/hw/ipath/ipath_driver.c b/drivers/infiniband/hw/ipath/ipath_driver.c index 58c0e41..be24ac7 100644 --- a/drivers/infiniband/hw/ipath/ipath_driver.c +++ b/drivers/infiniband/hw/ipath/ipath_driver.c @@ -398,7 +398,6 @@ static int __devinit ipath_init_one(struct pci_dev *pdev, struct ipath_devdata *dd; unsigned long long addr; u32 bar0 = 0, bar1 = 0; - u8 rev; dd = ipath_alloc_devdata(pdev); if (IS_ERR(dd)) { @@ -540,13 +539,7 @@ static int __devinit ipath_init_one(struct pci_dev *pdev, goto bail_regions; } - ret = pci_read_config_byte(pdev, PCI_REVISION_ID, &rev); - if (ret) { - ipath_dev_err(dd, "Failed to read PCI revision ID unit " - "%u: err %d\n", dd->ipath_unit, -ret); - goto bail_regions; /* shouldn't ever happen */ - } - dd->ipath_pcirev = rev; + dd->ipath_pcirev = pdev->revision; #if defined(__powerpc__) /* There isn't a generic way to specify writethrough mappings */ -- cgit v0.10.2 From d0c49bf391b2e230a8f3ae4486da7df440f1216d Mon Sep 17 00:00:00 2001 From: Roland Dreier Date: Mon, 9 May 2011 22:23:57 -0700 Subject: RDMA/iwcm: Get rid of enum iw_cm_event_status The IW_CM_EVENT_STATUS_xxx values were used in only a couple of places; cma.c uses -Exxx values instead, and so do the amso1100, cxgb3 and cxgb4 drivers -- only nes was using the enum values (with the mild consequence that all nes connection failures were treated as generic errors rather than reported as timeouts or rejections). We can fix this confusion by getting rid of enum iw_cm_event_status and using a plain int for struct iw_cm_event.status, and converting nes to use -Exxx as the other iWARP drivers do. This also gets rid of the warning drivers/infiniband/core/cma.c: In function 'cma_iw_handler': drivers/infiniband/core/cma.c:1333:3: warning: case value '4294967185' not in enumerated type 'enum iw_cm_event_status' drivers/infiniband/core/cma.c:1336:3: warning: case value '4294967186' not in enumerated type 'enum iw_cm_event_status' drivers/infiniband/core/cma.c:1332:3: warning: case value '4294967192' not in enumerated type 'enum iw_cm_event_status' Signed-off-by: Roland Dreier Reviewed-by: Steve Wise Reviewed-by: Sean Hefty Reviewed-by: Faisal Latif diff --git a/drivers/infiniband/core/iwcm.c b/drivers/infiniband/core/iwcm.c index 2a1e9ae..a9c0423 100644 --- a/drivers/infiniband/core/iwcm.c +++ b/drivers/infiniband/core/iwcm.c @@ -725,7 +725,7 @@ static int cm_conn_rep_handler(struct iwcm_id_private *cm_id_priv, */ clear_bit(IWCM_F_CONNECT_WAIT, &cm_id_priv->flags); BUG_ON(cm_id_priv->state != IW_CM_STATE_CONN_SENT); - if (iw_event->status == IW_CM_EVENT_STATUS_ACCEPTED) { + if (iw_event->status == 0) { cm_id_priv->id.local_addr = iw_event->local_addr; cm_id_priv->id.remote_addr = iw_event->remote_addr; cm_id_priv->state = IW_CM_STATE_ESTABLISHED; diff --git a/drivers/infiniband/hw/nes/nes_cm.c b/drivers/infiniband/hw/nes/nes_cm.c index 33c7eed..e74cdf9 100644 --- a/drivers/infiniband/hw/nes/nes_cm.c +++ b/drivers/infiniband/hw/nes/nes_cm.c @@ -2563,7 +2563,7 @@ static int nes_cm_disconn_true(struct nes_qp *nesqp) u16 last_ae; u8 original_hw_tcp_state; u8 original_ibqp_state; - enum iw_cm_event_status disconn_status = IW_CM_EVENT_STATUS_OK; + int disconn_status = 0; int issue_disconn = 0; int issue_close = 0; int issue_flush = 0; @@ -2605,7 +2605,7 @@ static int nes_cm_disconn_true(struct nes_qp *nesqp) (last_ae == NES_AEQE_AEID_LLP_CONNECTION_RESET))) { issue_disconn = 1; if (last_ae == NES_AEQE_AEID_LLP_CONNECTION_RESET) - disconn_status = IW_CM_EVENT_STATUS_RESET; + disconn_status = -ECONNRESET; } if (((original_hw_tcp_state == NES_AEQE_TCP_STATE_CLOSED) || @@ -2666,7 +2666,7 @@ static int nes_cm_disconn_true(struct nes_qp *nesqp) cm_id->provider_data = nesqp; /* Send up the close complete event */ cm_event.event = IW_CM_EVENT_CLOSE; - cm_event.status = IW_CM_EVENT_STATUS_OK; + cm_event.status = 0; cm_event.provider_data = cm_id->provider_data; cm_event.local_addr = cm_id->local_addr; cm_event.remote_addr = cm_id->remote_addr; @@ -2966,7 +2966,7 @@ int nes_accept(struct iw_cm_id *cm_id, struct iw_cm_conn_param *conn_param) nes_add_ref(&nesqp->ibqp); cm_event.event = IW_CM_EVENT_ESTABLISHED; - cm_event.status = IW_CM_EVENT_STATUS_ACCEPTED; + cm_event.status = 0; cm_event.provider_data = (void *)nesqp; cm_event.local_addr = cm_id->local_addr; cm_event.remote_addr = cm_id->remote_addr; @@ -3377,7 +3377,7 @@ static void cm_event_connected(struct nes_cm_event *event) /* notify OF layer we successfully created the requested connection */ cm_event.event = IW_CM_EVENT_CONNECT_REPLY; - cm_event.status = IW_CM_EVENT_STATUS_ACCEPTED; + cm_event.status = 0; cm_event.provider_data = cm_id->provider_data; cm_event.local_addr.sin_family = AF_INET; cm_event.local_addr.sin_port = cm_id->local_addr.sin_port; @@ -3484,7 +3484,7 @@ static void cm_event_reset(struct nes_cm_event *event) nesqp->cm_id = NULL; /* cm_id->provider_data = NULL; */ cm_event.event = IW_CM_EVENT_DISCONNECT; - cm_event.status = IW_CM_EVENT_STATUS_RESET; + cm_event.status = -ECONNRESET; cm_event.provider_data = cm_id->provider_data; cm_event.local_addr = cm_id->local_addr; cm_event.remote_addr = cm_id->remote_addr; @@ -3495,7 +3495,7 @@ static void cm_event_reset(struct nes_cm_event *event) ret = cm_id->event_handler(cm_id, &cm_event); atomic_inc(&cm_closes); cm_event.event = IW_CM_EVENT_CLOSE; - cm_event.status = IW_CM_EVENT_STATUS_OK; + cm_event.status = 0; cm_event.provider_data = cm_id->provider_data; cm_event.local_addr = cm_id->local_addr; cm_event.remote_addr = cm_id->remote_addr; @@ -3534,7 +3534,7 @@ static void cm_event_mpa_req(struct nes_cm_event *event) cm_node, cm_id, jiffies); cm_event.event = IW_CM_EVENT_CONNECT_REQUEST; - cm_event.status = IW_CM_EVENT_STATUS_OK; + cm_event.status = 0; cm_event.provider_data = (void *)cm_node; cm_event.local_addr.sin_family = AF_INET; diff --git a/drivers/infiniband/hw/nes/nes_verbs.c b/drivers/infiniband/hw/nes/nes_verbs.c index 26d8018..95ca93c 100644 --- a/drivers/infiniband/hw/nes/nes_verbs.c +++ b/drivers/infiniband/hw/nes/nes_verbs.c @@ -1484,7 +1484,7 @@ static int nes_destroy_qp(struct ib_qp *ibqp) (nesqp->ibqp_state == IB_QPS_RTR)) && (nesqp->cm_id)) { cm_id = nesqp->cm_id; cm_event.event = IW_CM_EVENT_CONNECT_REPLY; - cm_event.status = IW_CM_EVENT_STATUS_TIMEOUT; + cm_event.status = -ETIMEDOUT; cm_event.local_addr = cm_id->local_addr; cm_event.remote_addr = cm_id->remote_addr; cm_event.private_data = NULL; diff --git a/include/rdma/iw_cm.h b/include/rdma/iw_cm.h index cbb822e..2d0191c 100644 --- a/include/rdma/iw_cm.h +++ b/include/rdma/iw_cm.h @@ -46,18 +46,9 @@ enum iw_cm_event_type { IW_CM_EVENT_CLOSE /* close complete */ }; -enum iw_cm_event_status { - IW_CM_EVENT_STATUS_OK = 0, /* request successful */ - IW_CM_EVENT_STATUS_ACCEPTED = 0, /* connect request accepted */ - IW_CM_EVENT_STATUS_REJECTED, /* connect request rejected */ - IW_CM_EVENT_STATUS_TIMEOUT, /* the operation timed out */ - IW_CM_EVENT_STATUS_RESET, /* reset from remote peer */ - IW_CM_EVENT_STATUS_EINVAL, /* asynchronous failure for bad parm */ -}; - struct iw_cm_event { enum iw_cm_event_type event; - enum iw_cm_event_status status; + int status; struct sockaddr_in local_addr; struct sockaddr_in remote_addr; void *private_data; -- cgit v0.10.2 From 1d44e8288a0557c28c447d7e511f50d06ff93a34 Mon Sep 17 00:00:00 2001 From: Jack Steiner Date: Mon, 9 May 2011 11:35:19 -0500 Subject: x86, UV: Fix NMI handler for UV platforms This fixes problems seen on UV systems handling NMIs from the node controller. I isolated the "dazed..." messages that I saw earlier to a bug in the BMC on our platform. It was sending NMIs w/o properly setting a register that indicated the source of NMI. So rather than _assuming_ any unhandled NMI came from the UV system maintenance console (SMC), add a check to verify that the SMC actually sent the NMI. Signed-off-by: Jack Steiner Cc: gorcunov@gmail.com Cc: dzickus@redhat.com Signed-off-by: Ingo Molnar diff --git a/arch/x86/include/asm/uv/uv_hub.h b/arch/x86/include/asm/uv/uv_hub.h index a501741..4298002 100644 --- a/arch/x86/include/asm/uv/uv_hub.h +++ b/arch/x86/include/asm/uv/uv_hub.h @@ -398,6 +398,8 @@ struct uv_blade_info { unsigned short nr_online_cpus; unsigned short pnode; short memory_nid; + spinlock_t nmi_lock; + unsigned long nmi_count; }; extern struct uv_blade_info *uv_blade_info; extern short *uv_node_to_blade; diff --git a/arch/x86/include/asm/uv/uv_mmrs.h b/arch/x86/include/asm/uv/uv_mmrs.h index 20cafea..f5bb64a 100644 --- a/arch/x86/include/asm/uv/uv_mmrs.h +++ b/arch/x86/include/asm/uv/uv_mmrs.h @@ -5,7 +5,7 @@ * * SGI UV MMR definitions * - * Copyright (C) 2007-2010 Silicon Graphics, Inc. All rights reserved. + * Copyright (C) 2007-2011 Silicon Graphics, Inc. All rights reserved. */ #ifndef _ASM_X86_UV_UV_MMRS_H @@ -1099,5 +1099,19 @@ union uvh_rtc1_int_config_u { } s; }; +/* ========================================================================= */ +/* UVH_SCRATCH5 */ +/* ========================================================================= */ +#define UVH_SCRATCH5 0x2d0200UL +#define UVH_SCRATCH5_32 0x00778 + +#define UVH_SCRATCH5_SCRATCH5_SHFT 0 +#define UVH_SCRATCH5_SCRATCH5_MASK 0xffffffffffffffffUL +union uvh_scratch5_u { + unsigned long v; + struct uvh_scratch5_s { + unsigned long scratch5 : 64; /* RW, W1CS */ + } s; +}; #endif /* __ASM_UV_MMRS_X86_H__ */ diff --git a/arch/x86/kernel/apic/x2apic_uv_x.c b/arch/x86/kernel/apic/x2apic_uv_x.c index 33b10a0..7acd2d2 100644 --- a/arch/x86/kernel/apic/x2apic_uv_x.c +++ b/arch/x86/kernel/apic/x2apic_uv_x.c @@ -37,6 +37,13 @@ #include #include #include +#include + +/* BMC sets a bit this MMR non-zero before sending an NMI */ +#define UVH_NMI_MMR UVH_SCRATCH5 +#define UVH_NMI_MMR_CLEAR (UVH_NMI_MMR + 8) +#define UV_NMI_PENDING_MASK (1UL << 63) +DEFINE_PER_CPU(unsigned long, cpu_last_nmi_count); DEFINE_PER_CPU(int, x2apic_extra_bits); @@ -642,18 +649,46 @@ void __cpuinit uv_cpu_init(void) */ int uv_handle_nmi(struct notifier_block *self, unsigned long reason, void *data) { + unsigned long real_uv_nmi; + int bid; + if (reason != DIE_NMIUNKNOWN) return NOTIFY_OK; if (in_crash_kexec) /* do nothing if entering the crash kernel */ return NOTIFY_OK; + /* - * Use a lock so only one cpu prints at a time - * to prevent intermixed output. + * Each blade has an MMR that indicates when an NMI has been sent + * to cpus on the blade. If an NMI is detected, atomically + * clear the MMR and update a per-blade NMI count used to + * cause each cpu on the blade to notice a new NMI. + */ + bid = uv_numa_blade_id(); + real_uv_nmi = (uv_read_local_mmr(UVH_NMI_MMR) & UV_NMI_PENDING_MASK); + + if (unlikely(real_uv_nmi)) { + spin_lock(&uv_blade_info[bid].nmi_lock); + real_uv_nmi = (uv_read_local_mmr(UVH_NMI_MMR) & UV_NMI_PENDING_MASK); + if (real_uv_nmi) { + uv_blade_info[bid].nmi_count++; + uv_write_local_mmr(UVH_NMI_MMR_CLEAR, UV_NMI_PENDING_MASK); + } + spin_unlock(&uv_blade_info[bid].nmi_lock); + } + + if (likely(__get_cpu_var(cpu_last_nmi_count) == uv_blade_info[bid].nmi_count)) + return NOTIFY_DONE; + + __get_cpu_var(cpu_last_nmi_count) = uv_blade_info[bid].nmi_count; + + /* + * Use a lock so only one cpu prints at a time. + * This prevents intermixed output. */ spin_lock(&uv_nmi_lock); - pr_info("NMI stack dump cpu %u:\n", smp_processor_id()); + pr_info("UV NMI stack dump cpu %u:\n", smp_processor_id()); dump_stack(); spin_unlock(&uv_nmi_lock); @@ -661,7 +696,8 @@ int uv_handle_nmi(struct notifier_block *self, unsigned long reason, void *data) } static struct notifier_block uv_dump_stack_nmi_nb = { - .notifier_call = uv_handle_nmi + .notifier_call = uv_handle_nmi, + .priority = NMI_LOCAL_LOW_PRIOR - 1, }; void uv_register_nmi_notifier(void) @@ -720,8 +756,9 @@ void __init uv_system_init(void) printk(KERN_DEBUG "UV: Found %d blades\n", uv_num_possible_blades()); bytes = sizeof(struct uv_blade_info) * uv_num_possible_blades(); - uv_blade_info = kmalloc(bytes, GFP_KERNEL); + uv_blade_info = kzalloc(bytes, GFP_KERNEL); BUG_ON(!uv_blade_info); + for (blade = 0; blade < uv_num_possible_blades(); blade++) uv_blade_info[blade].memory_nid = -1; @@ -747,6 +784,7 @@ void __init uv_system_init(void) uv_blade_info[blade].pnode = pnode; uv_blade_info[blade].nr_possible_cpus = 0; uv_blade_info[blade].nr_online_cpus = 0; + spin_lock_init(&uv_blade_info[blade].nmi_lock); max_pnode = max(pnode, max_pnode); blade++; } -- cgit v0.10.2 From 315c34dae0069d0c67abd714bb846cd466289c7f Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Thu, 21 Apr 2011 10:55:07 +0200 Subject: netfilter: ctnetlink: fix timestamp support for new conntracks This patch fixes the missing initialization of the start time if the timestamp support is enabled. libnetfilter_conntrack/utils# conntrack -E & libnetfilter_conntrack/utils# ./conntrack_create tcp 6 109 ESTABLISHED src=1.1.1.1 dst=2.2.2.2 sport=1025 dport=21 packets=0 bytes=0 [UNREPLIED] src=2.2.2.2 dst=1.1.1.1 sport=21 dport=1025 packets=0 bytes=0 mark=0 delta-time=1303296401 use=2 Signed-off-by: Pablo Neira Ayuso Signed-off-by: Patrick McHardy diff --git a/net/netfilter/nf_conntrack_netlink.c b/net/netfilter/nf_conntrack_netlink.c index 30bf8a1..482e90c 100644 --- a/net/netfilter/nf_conntrack_netlink.c +++ b/net/netfilter/nf_conntrack_netlink.c @@ -1334,6 +1334,7 @@ ctnetlink_create_conntrack(struct net *net, u16 zone, struct nf_conn *ct; int err = -EINVAL; struct nf_conntrack_helper *helper; + struct nf_conn_tstamp *tstamp; ct = nf_conntrack_alloc(net, zone, otuple, rtuple, GFP_ATOMIC); if (IS_ERR(ct)) @@ -1451,6 +1452,9 @@ ctnetlink_create_conntrack(struct net *net, u16 zone, __set_bit(IPS_EXPECTED_BIT, &ct->status); ct->master = master_ct; } + tstamp = nf_conn_tstamp_find(ct); + if (tstamp) + tstamp->start = ktime_to_ns(ktime_get_real()); add_timer(&ct->timeout); nf_conntrack_hash_insert(ct); -- cgit v0.10.2 From 5a6351eecf8c87afed9c883bb6341d09406d74ba Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Thu, 21 Apr 2011 10:57:21 +0200 Subject: netfilter: fix ebtables compat support commit 255d0dc34068a976 (netfilter: x_table: speedup compat operations) made ebtables not working anymore. 1) xt_compat_calc_jump() is not an exact match lookup 2) compat_table_info() has a typo in xt_compat_init_offsets() call 3) compat_do_replace() misses a xt_compat_init_offsets() call Reported-by: dann frazier Signed-off-by: Eric Dumazet Signed-off-by: Patrick McHardy diff --git a/net/bridge/netfilter/ebtables.c b/net/bridge/netfilter/ebtables.c index 893669c..9707079 100644 --- a/net/bridge/netfilter/ebtables.c +++ b/net/bridge/netfilter/ebtables.c @@ -1766,7 +1766,7 @@ static int compat_table_info(const struct ebt_table_info *info, newinfo->entries_size = size; - xt_compat_init_offsets(AF_INET, info->nentries); + xt_compat_init_offsets(NFPROTO_BRIDGE, info->nentries); return EBT_ENTRY_ITERATE(entries, size, compat_calc_entry, info, entries, newinfo); } @@ -2240,6 +2240,7 @@ static int compat_do_replace(struct net *net, void __user *user, xt_compat_lock(NFPROTO_BRIDGE); + xt_compat_init_offsets(NFPROTO_BRIDGE, tmp.nentries); ret = compat_copy_entries(entries_tmp, tmp.entries_size, &state); if (ret < 0) goto out_unlock; diff --git a/net/netfilter/x_tables.c b/net/netfilter/x_tables.c index a9adf4c..8a025a5 100644 --- a/net/netfilter/x_tables.c +++ b/net/netfilter/x_tables.c @@ -455,6 +455,7 @@ void xt_compat_flush_offsets(u_int8_t af) vfree(xt[af].compat_tab); xt[af].compat_tab = NULL; xt[af].number = 0; + xt[af].cur = 0; } } EXPORT_SYMBOL_GPL(xt_compat_flush_offsets); @@ -473,8 +474,7 @@ int xt_compat_calc_jump(u_int8_t af, unsigned int offset) else return mid ? tmp[mid - 1].delta : 0; } - WARN_ON_ONCE(1); - return 0; + return left ? tmp[left - 1].delta : 0; } EXPORT_SYMBOL_GPL(xt_compat_calc_jump); -- cgit v0.10.2 From 103a9778e07bcc0cd34b5c35a87281454eec719e Mon Sep 17 00:00:00 2001 From: Florian Westphal Date: Thu, 21 Apr 2011 10:58:25 +0200 Subject: netfilter: ebtables: only call xt_compat_add_offset once per rule The optimizations in commit 255d0dc34068a976 (netfilter: x_table: speedup compat operations) assume that xt_compat_add_offset is called once per rule. ebtables however called it for each match/target found in a rule. The match/watcher/target parser already returns the needed delta, so it is sufficient to move the xt_compat_add_offset call to a more reasonable location. While at it, also get rid of the unused COMPAT iterator macros. Signed-off-by: Florian Westphal Signed-off-by: Patrick McHardy diff --git a/net/bridge/netfilter/ebtables.c b/net/bridge/netfilter/ebtables.c index 9707079..1a92b36 100644 --- a/net/bridge/netfilter/ebtables.c +++ b/net/bridge/netfilter/ebtables.c @@ -1882,7 +1882,7 @@ static int compat_mtw_from_user(struct compat_ebt_entry_mwt *mwt, struct xt_match *match; struct xt_target *wt; void *dst = NULL; - int off, pad = 0, ret = 0; + int off, pad = 0; unsigned int size_kern, entry_offset, match_size = mwt->match_size; strlcpy(name, mwt->u.name, sizeof(name)); @@ -1935,13 +1935,6 @@ static int compat_mtw_from_user(struct compat_ebt_entry_mwt *mwt, break; } - if (!dst) { - ret = xt_compat_add_offset(NFPROTO_BRIDGE, entry_offset, - off + ebt_compat_entry_padsize()); - if (ret < 0) - return ret; - } - state->buf_kern_offset += match_size + off; state->buf_user_offset += match_size; pad = XT_ALIGN(size_kern) - size_kern; @@ -2016,50 +2009,6 @@ static int ebt_size_mwt(struct compat_ebt_entry_mwt *match32, return growth; } -#define EBT_COMPAT_WATCHER_ITERATE(e, fn, args...) \ -({ \ - unsigned int __i; \ - int __ret = 0; \ - struct compat_ebt_entry_mwt *__watcher; \ - \ - for (__i = e->watchers_offset; \ - __i < (e)->target_offset; \ - __i += __watcher->watcher_size + \ - sizeof(struct compat_ebt_entry_mwt)) { \ - __watcher = (void *)(e) + __i; \ - __ret = fn(__watcher , ## args); \ - if (__ret != 0) \ - break; \ - } \ - if (__ret == 0) { \ - if (__i != (e)->target_offset) \ - __ret = -EINVAL; \ - } \ - __ret; \ -}) - -#define EBT_COMPAT_MATCH_ITERATE(e, fn, args...) \ -({ \ - unsigned int __i; \ - int __ret = 0; \ - struct compat_ebt_entry_mwt *__match; \ - \ - for (__i = sizeof(struct ebt_entry); \ - __i < (e)->watchers_offset; \ - __i += __match->match_size + \ - sizeof(struct compat_ebt_entry_mwt)) { \ - __match = (void *)(e) + __i; \ - __ret = fn(__match , ## args); \ - if (__ret != 0) \ - break; \ - } \ - if (__ret == 0) { \ - if (__i != (e)->watchers_offset) \ - __ret = -EINVAL; \ - } \ - __ret; \ -}) - /* called for all ebt_entry structures. */ static int size_entry_mwt(struct ebt_entry *entry, const unsigned char *base, unsigned int *total, @@ -2132,6 +2081,14 @@ static int size_entry_mwt(struct ebt_entry *entry, const unsigned char *base, } } + if (state->buf_kern_start == NULL) { + unsigned int offset = buf_start - (char *) base; + + ret = xt_compat_add_offset(NFPROTO_BRIDGE, offset, new_offset); + if (ret < 0) + return ret; + } + startoff = state->buf_user_offset - startoff; BUG_ON(*total < startoff); -- cgit v0.10.2 From 1ae132b0347907ac95b8bc9dba37934f59d2a508 Mon Sep 17 00:00:00 2001 From: Hans Schillstrom Date: Tue, 3 May 2011 22:09:30 +0200 Subject: IPVS: Change of socket usage to enable name space exit. If the sync daemons run in a name space while it crashes or get killed, there is no way to stop them except for a reboot. When all patches are there, ip_vs_core will handle register_pernet_(), i.e. ip_vs_sync_init() and ip_vs_sync_cleanup() will be removed. Kernel threads should not increment the use count of a socket. By calling sk_change_net() after creating a socket this is avoided. sock_release cant be used intead sk_release_kernel() should be used. Thanks Eric W Biederman for your advices. Signed-off-by: Hans Schillstrom [horms@verge.net.au: minor edit to changelog] Signed-off-by: Simon Horman diff --git a/net/netfilter/ipvs/ip_vs_core.c b/net/netfilter/ipvs/ip_vs_core.c index 07accf6..a0791dc 100644 --- a/net/netfilter/ipvs/ip_vs_core.c +++ b/net/netfilter/ipvs/ip_vs_core.c @@ -1896,7 +1896,7 @@ static int __net_init __ip_vs_init(struct net *net) static void __net_exit __ip_vs_cleanup(struct net *net) { - IP_VS_DBG(10, "ipvs netns %d released\n", net_ipvs(net)->gen); + IP_VS_DBG(2, "ipvs netns %d released\n", net_ipvs(net)->gen); } static struct pernet_operations ipvs_core_ops = { diff --git a/net/netfilter/ipvs/ip_vs_sync.c b/net/netfilter/ipvs/ip_vs_sync.c index 3e7961e..0cce953 100644 --- a/net/netfilter/ipvs/ip_vs_sync.c +++ b/net/netfilter/ipvs/ip_vs_sync.c @@ -1303,13 +1303,18 @@ static struct socket *make_send_sock(struct net *net) struct socket *sock; int result; - /* First create a socket */ - result = __sock_create(net, PF_INET, SOCK_DGRAM, IPPROTO_UDP, &sock, 1); + /* First create a socket move it to right name space later */ + result = sock_create_kern(PF_INET, SOCK_DGRAM, IPPROTO_UDP, &sock); if (result < 0) { pr_err("Error during creation of socket; terminating\n"); return ERR_PTR(result); } - + /* + * Kernel sockets that are a part of a namespace, should not + * hold a reference to a namespace in order to allow to stop it. + * After sk_change_net should be released using sk_release_kernel. + */ + sk_change_net(sock->sk, net); result = set_mcast_if(sock->sk, ipvs->master_mcast_ifn); if (result < 0) { pr_err("Error setting outbound mcast interface\n"); @@ -1334,8 +1339,8 @@ static struct socket *make_send_sock(struct net *net) return sock; - error: - sock_release(sock); +error: + sk_release_kernel(sock->sk); return ERR_PTR(result); } @@ -1350,12 +1355,17 @@ static struct socket *make_receive_sock(struct net *net) int result; /* First create a socket */ - result = __sock_create(net, PF_INET, SOCK_DGRAM, IPPROTO_UDP, &sock, 1); + result = sock_create_kern(PF_INET, SOCK_DGRAM, IPPROTO_UDP, &sock); if (result < 0) { pr_err("Error during creation of socket; terminating\n"); return ERR_PTR(result); } - + /* + * Kernel sockets that are a part of a namespace, should not + * hold a reference to a namespace in order to allow to stop it. + * After sk_change_net should be released using sk_release_kernel. + */ + sk_change_net(sock->sk, net); /* it is equivalent to the REUSEADDR option in user-space */ sock->sk->sk_reuse = 1; @@ -1377,8 +1387,8 @@ static struct socket *make_receive_sock(struct net *net) return sock; - error: - sock_release(sock); +error: + sk_release_kernel(sock->sk); return ERR_PTR(result); } @@ -1473,7 +1483,7 @@ static int sync_thread_master(void *data) ip_vs_sync_buff_release(sb); /* release the sending multicast socket */ - sock_release(tinfo->sock); + sk_release_kernel(tinfo->sock->sk); kfree(tinfo); return 0; @@ -1513,7 +1523,7 @@ static int sync_thread_backup(void *data) } /* release the sending multicast socket */ - sock_release(tinfo->sock); + sk_release_kernel(tinfo->sock->sk); kfree(tinfo->buf); kfree(tinfo); @@ -1601,7 +1611,7 @@ outtinfo: outbuf: kfree(buf); outsocket: - sock_release(sock); + sk_release_kernel(sock->sk); out: return result; } @@ -1610,6 +1620,7 @@ out: int stop_sync_thread(struct net *net, int state) { struct netns_ipvs *ipvs = net_ipvs(net); + int retc = -EINVAL; IP_VS_DBG(7, "%s(): pid %d\n", __func__, task_pid_nr(current)); @@ -1629,7 +1640,7 @@ int stop_sync_thread(struct net *net, int state) spin_lock_bh(&ipvs->sync_lock); ipvs->sync_state &= ~IP_VS_STATE_MASTER; spin_unlock_bh(&ipvs->sync_lock); - kthread_stop(ipvs->master_thread); + retc = kthread_stop(ipvs->master_thread); ipvs->master_thread = NULL; } else if (state == IP_VS_STATE_BACKUP) { if (!ipvs->backup_thread) @@ -1639,16 +1650,14 @@ int stop_sync_thread(struct net *net, int state) task_pid_nr(ipvs->backup_thread)); ipvs->sync_state &= ~IP_VS_STATE_BACKUP; - kthread_stop(ipvs->backup_thread); + retc = kthread_stop(ipvs->backup_thread); ipvs->backup_thread = NULL; - } else { - return -EINVAL; } /* decrease the module use count */ ip_vs_use_count_dec(); - return 0; + return retc; } /* @@ -1670,8 +1679,15 @@ static int __net_init __ip_vs_sync_init(struct net *net) static void __ip_vs_sync_cleanup(struct net *net) { - stop_sync_thread(net, IP_VS_STATE_MASTER); - stop_sync_thread(net, IP_VS_STATE_BACKUP); + int retc; + + retc = stop_sync_thread(net, IP_VS_STATE_MASTER); + if (retc && retc != -ESRCH) + pr_err("Failed to stop Master Daemon\n"); + + retc = stop_sync_thread(net, IP_VS_STATE_BACKUP); + if (retc && retc != -ESRCH) + pr_err("Failed to stop Backup Daemon\n"); } static struct pernet_operations ipvs_sync_ops = { @@ -1682,10 +1698,10 @@ static struct pernet_operations ipvs_sync_ops = { int __init ip_vs_sync_init(void) { - return register_pernet_subsys(&ipvs_sync_ops); + return register_pernet_device(&ipvs_sync_ops); } void ip_vs_sync_cleanup(void) { - unregister_pernet_subsys(&ipvs_sync_ops); + unregister_pernet_device(&ipvs_sync_ops); } -- cgit v0.10.2 From 7a4f0761fce32ff4918a7c23b08db564ad33092d Mon Sep 17 00:00:00 2001 From: Hans Schillstrom Date: Tue, 3 May 2011 22:09:31 +0200 Subject: IPVS: init and cleanup restructuring DESCRIPTION This patch tries to restore the initial init and cleanup sequences that was before namspace patch. Netns also requires action when net devices unregister which has never been implemented. I.e this patch also covers when a device moves into a network namespace, and has to be released. IMPLEMENTATION The number of calls to register_pernet_device have been reduced to one for the ip_vs.ko Schedulers still have their own calls. This patch adds a function __ip_vs_service_cleanup() and an enable flag for the netfilter hooks. The nf hooks will be enabled when the first service is loaded and never disabled again, except when a namespace exit starts. Signed-off-by: Hans Schillstrom Acked-by: Julian Anastasov [horms@verge.net.au: minor edit to changelog] Signed-off-by: Simon Horman diff --git a/include/net/ip_vs.h b/include/net/ip_vs.h index d516f00..86aefed 100644 --- a/include/net/ip_vs.h +++ b/include/net/ip_vs.h @@ -791,6 +791,7 @@ struct ip_vs_app { /* IPVS in network namespace */ struct netns_ipvs { int gen; /* Generation */ + int enable; /* enable like nf_hooks do */ /* * Hash table: for real service lookups */ @@ -1089,6 +1090,22 @@ ip_vs_control_add(struct ip_vs_conn *cp, struct ip_vs_conn *ctl_cp) atomic_inc(&ctl_cp->n_control); } +/* + * IPVS netns init & cleanup functions + */ +extern int __ip_vs_estimator_init(struct net *net); +extern int __ip_vs_control_init(struct net *net); +extern int __ip_vs_protocol_init(struct net *net); +extern int __ip_vs_app_init(struct net *net); +extern int __ip_vs_conn_init(struct net *net); +extern int __ip_vs_sync_init(struct net *net); +extern void __ip_vs_conn_cleanup(struct net *net); +extern void __ip_vs_app_cleanup(struct net *net); +extern void __ip_vs_protocol_cleanup(struct net *net); +extern void __ip_vs_control_cleanup(struct net *net); +extern void __ip_vs_estimator_cleanup(struct net *net); +extern void __ip_vs_sync_cleanup(struct net *net); +extern void __ip_vs_service_cleanup(struct net *net); /* * IPVS application functions diff --git a/net/netfilter/ipvs/ip_vs_app.c b/net/netfilter/ipvs/ip_vs_app.c index 2dc6de1..51f3af7 100644 --- a/net/netfilter/ipvs/ip_vs_app.c +++ b/net/netfilter/ipvs/ip_vs_app.c @@ -576,7 +576,7 @@ static const struct file_operations ip_vs_app_fops = { }; #endif -static int __net_init __ip_vs_app_init(struct net *net) +int __net_init __ip_vs_app_init(struct net *net) { struct netns_ipvs *ipvs = net_ipvs(net); @@ -585,26 +585,17 @@ static int __net_init __ip_vs_app_init(struct net *net) return 0; } -static void __net_exit __ip_vs_app_cleanup(struct net *net) +void __net_exit __ip_vs_app_cleanup(struct net *net) { proc_net_remove(net, "ip_vs_app"); } -static struct pernet_operations ip_vs_app_ops = { - .init = __ip_vs_app_init, - .exit = __ip_vs_app_cleanup, -}; - int __init ip_vs_app_init(void) { - int rv; - - rv = register_pernet_subsys(&ip_vs_app_ops); - return rv; + return 0; } void ip_vs_app_cleanup(void) { - unregister_pernet_subsys(&ip_vs_app_ops); } diff --git a/net/netfilter/ipvs/ip_vs_conn.c b/net/netfilter/ipvs/ip_vs_conn.c index c97bd45..d3fd91b 100644 --- a/net/netfilter/ipvs/ip_vs_conn.c +++ b/net/netfilter/ipvs/ip_vs_conn.c @@ -1258,22 +1258,17 @@ int __net_init __ip_vs_conn_init(struct net *net) return 0; } -static void __net_exit __ip_vs_conn_cleanup(struct net *net) +void __net_exit __ip_vs_conn_cleanup(struct net *net) { /* flush all the connection entries first */ ip_vs_conn_flush(net); proc_net_remove(net, "ip_vs_conn"); proc_net_remove(net, "ip_vs_conn_sync"); } -static struct pernet_operations ipvs_conn_ops = { - .init = __ip_vs_conn_init, - .exit = __ip_vs_conn_cleanup, -}; int __init ip_vs_conn_init(void) { int idx; - int retc; /* Compute size and mask */ ip_vs_conn_tab_size = 1 << ip_vs_conn_tab_bits; @@ -1309,17 +1304,14 @@ int __init ip_vs_conn_init(void) rwlock_init(&__ip_vs_conntbl_lock_array[idx].l); } - retc = register_pernet_subsys(&ipvs_conn_ops); - /* calculate the random value for connection hash */ get_random_bytes(&ip_vs_conn_rnd, sizeof(ip_vs_conn_rnd)); - return retc; + return 0; } void ip_vs_conn_cleanup(void) { - unregister_pernet_subsys(&ipvs_conn_ops); /* Release the empty cache */ kmem_cache_destroy(ip_vs_conn_cachep); vfree(ip_vs_conn_tab); diff --git a/net/netfilter/ipvs/ip_vs_core.c b/net/netfilter/ipvs/ip_vs_core.c index a0791dc..a74dae6 100644 --- a/net/netfilter/ipvs/ip_vs_core.c +++ b/net/netfilter/ipvs/ip_vs_core.c @@ -1113,6 +1113,9 @@ ip_vs_out(unsigned int hooknum, struct sk_buff *skb, int af) return NF_ACCEPT; net = skb_net(skb); + if (!net_ipvs(net)->enable) + return NF_ACCEPT; + ip_vs_fill_iphdr(af, skb_network_header(skb), &iph); #ifdef CONFIG_IP_VS_IPV6 if (af == AF_INET6) { @@ -1343,6 +1346,7 @@ ip_vs_in_icmp(struct sk_buff *skb, int *related, unsigned int hooknum) return NF_ACCEPT; /* The packet looks wrong, ignore */ net = skb_net(skb); + pd = ip_vs_proto_data_get(net, cih->protocol); if (!pd) return NF_ACCEPT; @@ -1529,6 +1533,11 @@ ip_vs_in(unsigned int hooknum, struct sk_buff *skb, int af) IP_VS_DBG_ADDR(af, &iph.daddr), hooknum); return NF_ACCEPT; } + /* ipvs enabled in this netns ? */ + net = skb_net(skb); + if (!net_ipvs(net)->enable) + return NF_ACCEPT; + ip_vs_fill_iphdr(af, skb_network_header(skb), &iph); /* Bad... Do not break raw sockets */ @@ -1562,7 +1571,6 @@ ip_vs_in(unsigned int hooknum, struct sk_buff *skb, int af) ip_vs_fill_iphdr(af, skb_network_header(skb), &iph); } - net = skb_net(skb); /* Protocol supported? */ pd = ip_vs_proto_data_get(net, iph.protocol); if (unlikely(!pd)) @@ -1588,7 +1596,6 @@ ip_vs_in(unsigned int hooknum, struct sk_buff *skb, int af) } IP_VS_DBG_PKT(11, af, pp, skb, 0, "Incoming packet"); - net = skb_net(skb); ipvs = net_ipvs(net); /* Check the server status */ if (cp->dest && !(cp->dest->flags & IP_VS_DEST_F_AVAILABLE)) { @@ -1743,10 +1750,16 @@ ip_vs_forward_icmp(unsigned int hooknum, struct sk_buff *skb, int (*okfn)(struct sk_buff *)) { int r; + struct net *net; if (ip_hdr(skb)->protocol != IPPROTO_ICMP) return NF_ACCEPT; + /* ipvs enabled in this netns ? */ + net = skb_net(skb); + if (!net_ipvs(net)->enable) + return NF_ACCEPT; + return ip_vs_in_icmp(skb, &r, hooknum); } @@ -1757,10 +1770,16 @@ ip_vs_forward_icmp_v6(unsigned int hooknum, struct sk_buff *skb, int (*okfn)(struct sk_buff *)) { int r; + struct net *net; if (ipv6_hdr(skb)->nexthdr != IPPROTO_ICMPV6) return NF_ACCEPT; + /* ipvs enabled in this netns ? */ + net = skb_net(skb); + if (!net_ipvs(net)->enable) + return NF_ACCEPT; + return ip_vs_in_icmp_v6(skb, &r, hooknum); } #endif @@ -1884,21 +1903,72 @@ static int __net_init __ip_vs_init(struct net *net) pr_err("%s(): no memory.\n", __func__); return -ENOMEM; } + /* Hold the beast until a service is registerd */ + ipvs->enable = 0; ipvs->net = net; /* Counters used for creating unique names */ ipvs->gen = atomic_read(&ipvs_netns_cnt); atomic_inc(&ipvs_netns_cnt); net->ipvs = ipvs; + + if (__ip_vs_estimator_init(net) < 0) + goto estimator_fail; + + if (__ip_vs_control_init(net) < 0) + goto control_fail; + + if (__ip_vs_protocol_init(net) < 0) + goto protocol_fail; + + if (__ip_vs_app_init(net) < 0) + goto app_fail; + + if (__ip_vs_conn_init(net) < 0) + goto conn_fail; + + if (__ip_vs_sync_init(net) < 0) + goto sync_fail; + printk(KERN_INFO "IPVS: Creating netns size=%zu id=%d\n", sizeof(struct netns_ipvs), ipvs->gen); return 0; +/* + * Error handling + */ + +sync_fail: + __ip_vs_conn_cleanup(net); +conn_fail: + __ip_vs_app_cleanup(net); +app_fail: + __ip_vs_protocol_cleanup(net); +protocol_fail: + __ip_vs_control_cleanup(net); +control_fail: + __ip_vs_estimator_cleanup(net); +estimator_fail: + return -ENOMEM; } static void __net_exit __ip_vs_cleanup(struct net *net) { + __ip_vs_service_cleanup(net); /* ip_vs_flush() with locks */ + __ip_vs_conn_cleanup(net); + __ip_vs_app_cleanup(net); + __ip_vs_protocol_cleanup(net); + __ip_vs_control_cleanup(net); + __ip_vs_estimator_cleanup(net); IP_VS_DBG(2, "ipvs netns %d released\n", net_ipvs(net)->gen); } +static void __net_exit __ip_vs_dev_cleanup(struct net *net) +{ + EnterFunction(2); + net_ipvs(net)->enable = 0; /* Disable packet reception */ + __ip_vs_sync_cleanup(net); + LeaveFunction(2); +} + static struct pernet_operations ipvs_core_ops = { .init = __ip_vs_init, .exit = __ip_vs_cleanup, @@ -1906,6 +1976,10 @@ static struct pernet_operations ipvs_core_ops = { .size = sizeof(struct netns_ipvs), }; +static struct pernet_operations ipvs_core_dev_ops = { + .exit = __ip_vs_dev_cleanup, +}; + /* * Initialize IP Virtual Server */ @@ -1913,10 +1987,6 @@ static int __init ip_vs_init(void) { int ret; - ret = register_pernet_subsys(&ipvs_core_ops); /* Alloc ip_vs struct */ - if (ret < 0) - return ret; - ip_vs_estimator_init(); ret = ip_vs_control_init(); if (ret < 0) { @@ -1944,15 +2014,28 @@ static int __init ip_vs_init(void) goto cleanup_conn; } + ret = register_pernet_subsys(&ipvs_core_ops); /* Alloc ip_vs struct */ + if (ret < 0) + goto cleanup_sync; + + ret = register_pernet_device(&ipvs_core_dev_ops); + if (ret < 0) + goto cleanup_sub; + ret = nf_register_hooks(ip_vs_ops, ARRAY_SIZE(ip_vs_ops)); if (ret < 0) { pr_err("can't register hooks.\n"); - goto cleanup_sync; + goto cleanup_dev; } pr_info("ipvs loaded.\n"); + return ret; +cleanup_dev: + unregister_pernet_device(&ipvs_core_dev_ops); +cleanup_sub: + unregister_pernet_subsys(&ipvs_core_ops); cleanup_sync: ip_vs_sync_cleanup(); cleanup_conn: @@ -1964,20 +2047,20 @@ cleanup_sync: ip_vs_control_cleanup(); cleanup_estimator: ip_vs_estimator_cleanup(); - unregister_pernet_subsys(&ipvs_core_ops); /* free ip_vs struct */ return ret; } static void __exit ip_vs_cleanup(void) { nf_unregister_hooks(ip_vs_ops, ARRAY_SIZE(ip_vs_ops)); + unregister_pernet_device(&ipvs_core_dev_ops); + unregister_pernet_subsys(&ipvs_core_ops); /* free ip_vs struct */ ip_vs_sync_cleanup(); ip_vs_conn_cleanup(); ip_vs_app_cleanup(); ip_vs_protocol_cleanup(); ip_vs_control_cleanup(); ip_vs_estimator_cleanup(); - unregister_pernet_subsys(&ipvs_core_ops); /* free ip_vs struct */ pr_info("ipvs unloaded.\n"); } diff --git a/net/netfilter/ipvs/ip_vs_ctl.c b/net/netfilter/ipvs/ip_vs_ctl.c index ae47090..ea72281 100644 --- a/net/netfilter/ipvs/ip_vs_ctl.c +++ b/net/netfilter/ipvs/ip_vs_ctl.c @@ -69,6 +69,11 @@ int ip_vs_get_debug_level(void) } #endif + +/* Protos */ +static void __ip_vs_del_service(struct ip_vs_service *svc); + + #ifdef CONFIG_IP_VS_IPV6 /* Taken from rt6_fill_node() in net/ipv6/route.c, is there a better way? */ static int __ip_vs_addr_is_local_v6(struct net *net, @@ -1214,6 +1219,8 @@ ip_vs_add_service(struct net *net, struct ip_vs_service_user_kern *u, write_unlock_bh(&__ip_vs_svc_lock); *svc_p = svc; + /* Now there is a service - full throttle */ + ipvs->enable = 1; return 0; @@ -1472,6 +1479,84 @@ static int ip_vs_flush(struct net *net) return 0; } +/* + * Delete service by {netns} in the service table. + * Called by __ip_vs_cleanup() + */ +void __ip_vs_service_cleanup(struct net *net) +{ + EnterFunction(2); + /* Check for "full" addressed entries */ + mutex_lock(&__ip_vs_mutex); + ip_vs_flush(net); + mutex_unlock(&__ip_vs_mutex); + LeaveFunction(2); +} +/* + * Release dst hold by dst_cache + */ +static inline void +__ip_vs_dev_reset(struct ip_vs_dest *dest, struct net_device *dev) +{ + spin_lock_bh(&dest->dst_lock); + if (dest->dst_cache && dest->dst_cache->dev == dev) { + IP_VS_DBG_BUF(3, "Reset dev:%s dest %s:%u ,dest->refcnt=%d\n", + dev->name, + IP_VS_DBG_ADDR(dest->af, &dest->addr), + ntohs(dest->port), + atomic_read(&dest->refcnt)); + ip_vs_dst_reset(dest); + } + spin_unlock_bh(&dest->dst_lock); + +} +/* + * Netdev event receiver + * Currently only NETDEV_UNREGISTER is handled, i.e. if we hold a reference to + * a device that is "unregister" it must be released. + */ +static int ip_vs_dst_event(struct notifier_block *this, unsigned long event, + void *ptr) +{ + struct net_device *dev = ptr; + struct net *net = dev_net(dev); + struct ip_vs_service *svc; + struct ip_vs_dest *dest; + unsigned int idx; + + if (event != NETDEV_UNREGISTER) + return NOTIFY_DONE; + IP_VS_DBG(3, "%s() dev=%s\n", __func__, dev->name); + EnterFunction(2); + mutex_lock(&__ip_vs_mutex); + for (idx = 0; idx < IP_VS_SVC_TAB_SIZE; idx++) { + list_for_each_entry(svc, &ip_vs_svc_table[idx], s_list) { + if (net_eq(svc->net, net)) { + list_for_each_entry(dest, &svc->destinations, + n_list) { + __ip_vs_dev_reset(dest, dev); + } + } + } + + list_for_each_entry(svc, &ip_vs_svc_fwm_table[idx], f_list) { + if (net_eq(svc->net, net)) { + list_for_each_entry(dest, &svc->destinations, + n_list) { + __ip_vs_dev_reset(dest, dev); + } + } + + } + } + + list_for_each_entry(dest, &net_ipvs(net)->dest_trash, n_list) { + __ip_vs_dev_reset(dest, dev); + } + mutex_unlock(&__ip_vs_mutex); + LeaveFunction(2); + return NOTIFY_DONE; +} /* * Zero counters in a service or all services @@ -3588,6 +3673,10 @@ void __net_init __ip_vs_control_cleanup_sysctl(struct net *net) { } #endif +static struct notifier_block ip_vs_dst_notifier = { + .notifier_call = ip_vs_dst_event, +}; + int __net_init __ip_vs_control_init(struct net *net) { int idx; @@ -3626,7 +3715,7 @@ err: return -ENOMEM; } -static void __net_exit __ip_vs_control_cleanup(struct net *net) +void __net_exit __ip_vs_control_cleanup(struct net *net) { struct netns_ipvs *ipvs = net_ipvs(net); @@ -3639,11 +3728,6 @@ static void __net_exit __ip_vs_control_cleanup(struct net *net) free_percpu(ipvs->tot_stats.cpustats); } -static struct pernet_operations ipvs_control_ops = { - .init = __ip_vs_control_init, - .exit = __ip_vs_control_cleanup, -}; - int __init ip_vs_control_init(void) { int idx; @@ -3657,33 +3741,32 @@ int __init ip_vs_control_init(void) INIT_LIST_HEAD(&ip_vs_svc_fwm_table[idx]); } - ret = register_pernet_subsys(&ipvs_control_ops); - if (ret) { - pr_err("cannot register namespace.\n"); - goto err; - } - smp_wmb(); /* Do we really need it now ? */ ret = nf_register_sockopt(&ip_vs_sockopts); if (ret) { pr_err("cannot register sockopt.\n"); - goto err_net; + goto err_sock; } ret = ip_vs_genl_register(); if (ret) { pr_err("cannot register Generic Netlink interface.\n"); - nf_unregister_sockopt(&ip_vs_sockopts); - goto err_net; + goto err_genl; } + ret = register_netdevice_notifier(&ip_vs_dst_notifier); + if (ret < 0) + goto err_notf; + LeaveFunction(2); return 0; -err_net: - unregister_pernet_subsys(&ipvs_control_ops); -err: +err_notf: + ip_vs_genl_unregister(); +err_genl: + nf_unregister_sockopt(&ip_vs_sockopts); +err_sock: return ret; } @@ -3691,7 +3774,6 @@ err: void ip_vs_control_cleanup(void) { EnterFunction(2); - unregister_pernet_subsys(&ipvs_control_ops); ip_vs_genl_unregister(); nf_unregister_sockopt(&ip_vs_sockopts); LeaveFunction(2); diff --git a/net/netfilter/ipvs/ip_vs_est.c b/net/netfilter/ipvs/ip_vs_est.c index 8c8766c..508cce9 100644 --- a/net/netfilter/ipvs/ip_vs_est.c +++ b/net/netfilter/ipvs/ip_vs_est.c @@ -192,7 +192,7 @@ void ip_vs_read_estimator(struct ip_vs_stats_user *dst, dst->outbps = (e->outbps + 0xF) >> 5; } -static int __net_init __ip_vs_estimator_init(struct net *net) +int __net_init __ip_vs_estimator_init(struct net *net) { struct netns_ipvs *ipvs = net_ipvs(net); @@ -203,24 +203,16 @@ static int __net_init __ip_vs_estimator_init(struct net *net) return 0; } -static void __net_exit __ip_vs_estimator_exit(struct net *net) +void __net_exit __ip_vs_estimator_cleanup(struct net *net) { del_timer_sync(&net_ipvs(net)->est_timer); } -static struct pernet_operations ip_vs_app_ops = { - .init = __ip_vs_estimator_init, - .exit = __ip_vs_estimator_exit, -}; int __init ip_vs_estimator_init(void) { - int rv; - - rv = register_pernet_subsys(&ip_vs_app_ops); - return rv; + return 0; } void ip_vs_estimator_cleanup(void) { - unregister_pernet_subsys(&ip_vs_app_ops); } diff --git a/net/netfilter/ipvs/ip_vs_proto.c b/net/netfilter/ipvs/ip_vs_proto.c index 17484a4..eb86028 100644 --- a/net/netfilter/ipvs/ip_vs_proto.c +++ b/net/netfilter/ipvs/ip_vs_proto.c @@ -316,7 +316,7 @@ ip_vs_tcpudp_debug_packet(int af, struct ip_vs_protocol *pp, /* * per network name-space init */ -static int __net_init __ip_vs_protocol_init(struct net *net) +int __net_init __ip_vs_protocol_init(struct net *net) { #ifdef CONFIG_IP_VS_PROTO_TCP register_ip_vs_proto_netns(net, &ip_vs_protocol_tcp); @@ -336,7 +336,7 @@ static int __net_init __ip_vs_protocol_init(struct net *net) return 0; } -static void __net_exit __ip_vs_protocol_cleanup(struct net *net) +void __net_exit __ip_vs_protocol_cleanup(struct net *net) { struct netns_ipvs *ipvs = net_ipvs(net); struct ip_vs_proto_data *pd; @@ -349,11 +349,6 @@ static void __net_exit __ip_vs_protocol_cleanup(struct net *net) } } -static struct pernet_operations ipvs_proto_ops = { - .init = __ip_vs_protocol_init, - .exit = __ip_vs_protocol_cleanup, -}; - int __init ip_vs_protocol_init(void) { char protocols[64]; @@ -382,7 +377,6 @@ int __init ip_vs_protocol_init(void) REGISTER_PROTOCOL(&ip_vs_protocol_esp); #endif pr_info("Registered protocols (%s)\n", &protocols[2]); - return register_pernet_subsys(&ipvs_proto_ops); return 0; } @@ -393,7 +387,6 @@ void ip_vs_protocol_cleanup(void) struct ip_vs_protocol *pp; int i; - unregister_pernet_subsys(&ipvs_proto_ops); /* unregister all the ipvs protocols */ for (i = 0; i < IP_VS_PROTO_TAB_SIZE; i++) { while ((pp = ip_vs_proto_table[i]) != NULL) diff --git a/net/netfilter/ipvs/ip_vs_sync.c b/net/netfilter/ipvs/ip_vs_sync.c index 0cce953..e292e5b 100644 --- a/net/netfilter/ipvs/ip_vs_sync.c +++ b/net/netfilter/ipvs/ip_vs_sync.c @@ -1663,7 +1663,7 @@ int stop_sync_thread(struct net *net, int state) /* * Initialize data struct for each netns */ -static int __net_init __ip_vs_sync_init(struct net *net) +int __net_init __ip_vs_sync_init(struct net *net) { struct netns_ipvs *ipvs = net_ipvs(net); @@ -1677,7 +1677,7 @@ static int __net_init __ip_vs_sync_init(struct net *net) return 0; } -static void __ip_vs_sync_cleanup(struct net *net) +void __ip_vs_sync_cleanup(struct net *net) { int retc; @@ -1690,18 +1690,11 @@ static void __ip_vs_sync_cleanup(struct net *net) pr_err("Failed to stop Backup Daemon\n"); } -static struct pernet_operations ipvs_sync_ops = { - .init = __ip_vs_sync_init, - .exit = __ip_vs_sync_cleanup, -}; - - int __init ip_vs_sync_init(void) { - return register_pernet_device(&ipvs_sync_ops); + return 0; } void ip_vs_sync_cleanup(void) { - unregister_pernet_device(&ipvs_sync_ops); } -- cgit v0.10.2 From 4319cc0cf5bb894b7368008cdf6dd20eb8868018 Mon Sep 17 00:00:00 2001 From: Fernando Luis Vazquez Cao Date: Tue, 10 May 2011 09:55:44 +0200 Subject: netfilter: IPv6: initialize TOS field in REJECT target module The IPv6 header is not zeroed out in alloc_skb so we must initialize it properly unless we want to see IPv6 packets with random TOS fields floating around. The current implementation resets the flow label but this could be changed if deemed necessary. We stumbled upon this issue when trying to apply a mangle rule to the RST packet generated by the REJECT target module. Signed-off-by: Fernando Luis Vazquez Cao Signed-off-by: Pablo Neira Ayuso diff --git a/net/ipv6/netfilter/ip6t_REJECT.c b/net/ipv6/netfilter/ip6t_REJECT.c index 28e7448..a5a4c5d 100644 --- a/net/ipv6/netfilter/ip6t_REJECT.c +++ b/net/ipv6/netfilter/ip6t_REJECT.c @@ -45,6 +45,8 @@ static void send_reset(struct net *net, struct sk_buff *oldskb) int tcphoff, needs_ack; const struct ipv6hdr *oip6h = ipv6_hdr(oldskb); struct ipv6hdr *ip6h; +#define DEFAULT_TOS_VALUE 0x0U + const __u8 tclass = DEFAULT_TOS_VALUE; struct dst_entry *dst = NULL; u8 proto; struct flowi6 fl6; @@ -124,7 +126,7 @@ static void send_reset(struct net *net, struct sk_buff *oldskb) skb_put(nskb, sizeof(struct ipv6hdr)); skb_reset_network_header(nskb); ip6h = ipv6_hdr(nskb); - ip6h->version = 6; + *(__be32 *)ip6h = htonl(0x60000000 | (tclass << 20)); ip6h->hop_limit = ip6_dst_hoplimit(dst); ip6h->nexthdr = IPPROTO_TCP; ipv6_addr_copy(&ip6h->saddr, &oip6h->daddr); -- cgit v0.10.2 From 1ed2f73d90fb49bcf5704aee7e9084adb882bfc5 Mon Sep 17 00:00:00 2001 From: Fernando Luis Vazquez Cao Date: Tue, 10 May 2011 10:00:21 +0200 Subject: netfilter: IPv6: fix DSCP mangle code The mask indicates the bits one wants to zero out, so it needs to be inverted before applying to the original TOS field. Signed-off-by: Fernando Luis Vazquez Cao Signed-off-by: Pablo Neira Ayuso diff --git a/net/netfilter/xt_DSCP.c b/net/netfilter/xt_DSCP.c index 0a22919..ae82716 100644 --- a/net/netfilter/xt_DSCP.c +++ b/net/netfilter/xt_DSCP.c @@ -99,7 +99,7 @@ tos_tg6(struct sk_buff *skb, const struct xt_action_param *par) u_int8_t orig, nv; orig = ipv6_get_dsfield(iph); - nv = (orig & info->tos_mask) ^ info->tos_value; + nv = (orig & ~info->tos_mask) ^ info->tos_value; if (orig != nv) { if (!skb_make_writable(skb, sizeof(struct iphdr))) -- cgit v0.10.2 From e969687595c27e02e02be0c9363261826123ba77 Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Fri, 5 Nov 2010 16:12:35 -0700 Subject: arch/x86/kernel/pci-iommu_table.c: Convert sprintf_symbol to %pS Coalesce format as well. Signed-off-by: Joe Perches Signed-off-by: Joerg Roedel diff --git a/arch/x86/kernel/pci-iommu_table.c b/arch/x86/kernel/pci-iommu_table.c index 55d745e..35ccf75 100644 --- a/arch/x86/kernel/pci-iommu_table.c +++ b/arch/x86/kernel/pci-iommu_table.c @@ -50,20 +50,14 @@ void __init check_iommu_entries(struct iommu_table_entry *start, struct iommu_table_entry *finish) { struct iommu_table_entry *p, *q, *x; - char sym_p[KSYM_SYMBOL_LEN]; - char sym_q[KSYM_SYMBOL_LEN]; /* Simple cyclic dependency checker. */ for (p = start; p < finish; p++) { q = find_dependents_of(start, finish, p); x = find_dependents_of(start, finish, q); if (p == x) { - sprint_symbol(sym_p, (unsigned long)p->detect); - sprint_symbol(sym_q, (unsigned long)q->detect); - - printk(KERN_ERR "CYCLIC DEPENDENCY FOUND! %s depends" \ - " on %s and vice-versa. BREAKING IT.\n", - sym_p, sym_q); + printk(KERN_ERR "CYCLIC DEPENDENCY FOUND! %pS depends on %pS and vice-versa. BREAKING IT.\n", + p->detect, q->detect); /* Heavy handed way..*/ x->depend = 0; } @@ -72,12 +66,8 @@ void __init check_iommu_entries(struct iommu_table_entry *start, for (p = start; p < finish; p++) { q = find_dependents_of(p, finish, p); if (q && q > p) { - sprint_symbol(sym_p, (unsigned long)p->detect); - sprint_symbol(sym_q, (unsigned long)q->detect); - - printk(KERN_ERR "EXECUTION ORDER INVALID! %s "\ - "should be called before %s!\n", - sym_p, sym_q); + printk(KERN_ERR "EXECUTION ORDER INVALID! %pS should be called before %pS!\n", + p->detect, q->detect); } } } -- cgit v0.10.2 From 72fe00f01f9a3240a1073be27aeaf4fc476cc662 Mon Sep 17 00:00:00 2001 From: Joerg Roedel Date: Tue, 10 May 2011 10:50:42 +0200 Subject: x86/amd-iommu: Use threaded interupt handler Move the interupt handling for the iommu into the interupt thread to reduce latencies and prepare interupt handling for pri handling. Signed-off-by: Joerg Roedel diff --git a/arch/x86/include/asm/amd_iommu_proto.h b/arch/x86/include/asm/amd_iommu_proto.h index a4ae6c3..55d95eb 100644 --- a/arch/x86/include/asm/amd_iommu_proto.h +++ b/arch/x86/include/asm/amd_iommu_proto.h @@ -23,6 +23,7 @@ extern int amd_iommu_init_dma_ops(void); extern int amd_iommu_init_passthrough(void); +extern irqreturn_t amd_iommu_int_thread(int irq, void *data); extern irqreturn_t amd_iommu_int_handler(int irq, void *data); extern void amd_iommu_apply_erratum_63(u16 devid); extern void amd_iommu_reset_cmd_buffer(struct amd_iommu *iommu); diff --git a/arch/x86/kernel/amd_iommu.c b/arch/x86/kernel/amd_iommu.c index dc5ddda..873e7e1 100644 --- a/arch/x86/kernel/amd_iommu.c +++ b/arch/x86/kernel/amd_iommu.c @@ -366,7 +366,7 @@ static void iommu_poll_events(struct amd_iommu *iommu) spin_unlock_irqrestore(&iommu->lock, flags); } -irqreturn_t amd_iommu_int_handler(int irq, void *data) +irqreturn_t amd_iommu_int_thread(int irq, void *data) { struct amd_iommu *iommu; @@ -376,6 +376,11 @@ irqreturn_t amd_iommu_int_handler(int irq, void *data) return IRQ_HANDLED; } +irqreturn_t amd_iommu_int_handler(int irq, void *data) +{ + return IRQ_WAKE_THREAD; +} + /**************************************************************************** * * IOMMU command queuing functions diff --git a/arch/x86/kernel/amd_iommu_init.c b/arch/x86/kernel/amd_iommu_init.c index 28b0781..9179c21 100644 --- a/arch/x86/kernel/amd_iommu_init.c +++ b/arch/x86/kernel/amd_iommu_init.c @@ -1034,10 +1034,11 @@ static int iommu_setup_msi(struct amd_iommu *iommu) if (pci_enable_msi(iommu->dev)) return 1; - r = request_irq(iommu->dev->irq, amd_iommu_int_handler, - IRQF_SAMPLE_RANDOM, - "AMD-Vi", - NULL); + r = request_threaded_irq(iommu->dev->irq, + amd_iommu_int_handler, + amd_iommu_int_thread, + 0, "AMD-Vi", + iommu->dev); if (r) { pci_disable_msi(iommu->dev); -- cgit v0.10.2 From 61bf35b9a3eab961ee1249467d9b2ac11d3c34c1 Mon Sep 17 00:00:00 2001 From: Stephen Warren Date: Mon, 9 May 2011 16:32:03 -0600 Subject: ASoC: WM8903: Fix Digital Capture Volume range Increase the range of the Digital Capture Volume control to be 120 steps. Each step is 0.75dB, and the range starts at -72dB, giving a max setting of 18dB, which matches the latest datasheet, to the precision of the step size. Signed-off-by: Stephen Warren Acked-by: Liam Girdwood Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/wm8903.c b/sound/soc/codecs/wm8903.c index f52b623..824d1c8 100644 --- a/sound/soc/codecs/wm8903.c +++ b/sound/soc/codecs/wm8903.c @@ -692,7 +692,7 @@ SOC_ENUM("DRC Smoothing Threshold", drc_smoothing), SOC_SINGLE_TLV("DRC Startup Volume", WM8903_DRC_0, 6, 18, 0, drc_tlv_startup), SOC_DOUBLE_R_TLV("Digital Capture Volume", WM8903_ADC_DIGITAL_VOLUME_LEFT, - WM8903_ADC_DIGITAL_VOLUME_RIGHT, 1, 96, 0, digital_tlv), + WM8903_ADC_DIGITAL_VOLUME_RIGHT, 1, 120, 0, digital_tlv), SOC_ENUM("ADC Companding Mode", adc_companding), SOC_SINGLE("ADC Companding Switch", WM8903_AUDIO_INTERFACE_0, 3, 1, 0), -- cgit v0.10.2 From 93bbce1ad0cd788190dd7d6c17d289f771fe3d0d Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Tue, 10 May 2011 12:13:36 +0200 Subject: netfilter: revert a2361c8735e07322023aedc36e4938b35af31eb0 This patch reverts a2361c8735e07322023aedc36e4938b35af31eb0: "[PATCH] netfilter: xt_conntrack: warn about use in raw table" Florian Wesphal says: "... when the packet was sent from the local machine the skb already has ->nfct attached, and -m conntrack seems to do the right thing." Acked-by: Jan Engelhardt Reported-by: Florian Wesphal Signed-off-by: Pablo Neira Ayuso diff --git a/net/netfilter/xt_conntrack.c b/net/netfilter/xt_conntrack.c index 481a86f..61805d7 100644 --- a/net/netfilter/xt_conntrack.c +++ b/net/netfilter/xt_conntrack.c @@ -272,11 +272,6 @@ static int conntrack_mt_check(const struct xt_mtchk_param *par) { int ret; - if (strcmp(par->table, "raw") == 0) { - pr_info("state is undetermined at the time of raw table\n"); - return -EINVAL; - } - ret = nf_ct_l3proto_try_module_get(par->family); if (ret < 0) pr_info("cannot load conntrack support for proto=%u\n", -- cgit v0.10.2 From 64ea5402581485237d3b6e3a0cf2b364ad8bd580 Mon Sep 17 00:00:00 2001 From: Steven Whitehouse Date: Tue, 10 May 2011 13:09:53 +0100 Subject: GFS2: Inode.c is empty now, remove it Signed-off-by: Steven Whitehouse diff --git a/fs/gfs2/Makefile b/fs/gfs2/Makefile index f3d23ef..d22edbb 100644 --- a/fs/gfs2/Makefile +++ b/fs/gfs2/Makefile @@ -1,7 +1,7 @@ ccflags-y := -I$(src) obj-$(CONFIG_GFS2_FS) += gfs2.o gfs2-y := acl.o bmap.o dir.o xattr.o glock.o \ - glops.o inode.o log.o lops.o main.o meta_io.o \ + glops.o log.o lops.o main.o meta_io.o \ aops.o dentry.o export.o file.o \ ops_fstype.o ops_inode.o quota.o \ recovery.o rgrp.o super.o sys.o trans.o util.o diff --git a/fs/gfs2/inode.c b/fs/gfs2/inode.c deleted file mode 100644 index 9076fbe..0000000 --- a/fs/gfs2/inode.c +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved. - * Copyright (C) 2004-2008 Red Hat, Inc. All rights reserved. - * - * This copyrighted material is made available to anyone wishing to use, - * modify, copy, or redistribute it subject to the terms and conditions - * of the GNU General Public License version 2. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "gfs2.h" -#include "incore.h" -#include "acl.h" -#include "bmap.h" -#include "dir.h" -#include "xattr.h" -#include "glock.h" -#include "glops.h" -#include "inode.h" -#include "log.h" -#include "meta_io.h" -#include "quota.h" -#include "rgrp.h" -#include "trans.h" -#include "util.h" - - -- cgit v0.10.2 From 2ab9cd1c63b519e37b21b504376822be983badba Mon Sep 17 00:00:00 2001 From: Steven Whitehouse Date: Tue, 10 May 2011 13:12:49 +0100 Subject: GFS2: Rename ops_inode.c to inode.c This is the final part of the ops_inode.c/inode.c reordering. We are left with a single file called inode.c which now contains all the inode operations, as expected. Signed-off-by: Steven Whitehouse diff --git a/fs/gfs2/Makefile b/fs/gfs2/Makefile index d22edbb..8612820 100644 --- a/fs/gfs2/Makefile +++ b/fs/gfs2/Makefile @@ -3,7 +3,7 @@ obj-$(CONFIG_GFS2_FS) += gfs2.o gfs2-y := acl.o bmap.o dir.o xattr.o glock.o \ glops.o log.o lops.o main.o meta_io.o \ aops.o dentry.o export.o file.o \ - ops_fstype.o ops_inode.o quota.o \ + ops_fstype.o inode.o quota.o \ recovery.o rgrp.o super.o sys.o trans.o util.o gfs2-$(CONFIG_GFS2_FS_LOCKING_DLM) += lock_dlm.o diff --git a/fs/gfs2/inode.c b/fs/gfs2/inode.c new file mode 100644 index 0000000..a783a7a --- /dev/null +++ b/fs/gfs2/inode.c @@ -0,0 +1,1990 @@ +/* + * Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved. + * Copyright (C) 2004-2006 Red Hat, Inc. All rights reserved. + * + * This copyrighted material is made available to anyone wishing to use, + * modify, copy, or redistribute it subject to the terms and conditions + * of the GNU General Public License version 2. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "gfs2.h" +#include "incore.h" +#include "acl.h" +#include "bmap.h" +#include "dir.h" +#include "xattr.h" +#include "glock.h" +#include "inode.h" +#include "meta_io.h" +#include "quota.h" +#include "rgrp.h" +#include "trans.h" +#include "util.h" +#include "super.h" +#include "glops.h" + +struct gfs2_skip_data { + u64 no_addr; + int skipped; + int non_block; +}; + +static int iget_test(struct inode *inode, void *opaque) +{ + struct gfs2_inode *ip = GFS2_I(inode); + struct gfs2_skip_data *data = opaque; + + if (ip->i_no_addr == data->no_addr) { + if (data->non_block && + inode->i_state & (I_FREEING|I_CLEAR|I_WILL_FREE)) { + data->skipped = 1; + return 0; + } + return 1; + } + return 0; +} + +static int iget_set(struct inode *inode, void *opaque) +{ + struct gfs2_inode *ip = GFS2_I(inode); + struct gfs2_skip_data *data = opaque; + + if (data->skipped) + return -ENOENT; + inode->i_ino = (unsigned long)(data->no_addr); + ip->i_no_addr = data->no_addr; + return 0; +} + +struct inode *gfs2_ilookup(struct super_block *sb, u64 no_addr, int non_block) +{ + unsigned long hash = (unsigned long)no_addr; + struct gfs2_skip_data data; + + data.no_addr = no_addr; + data.skipped = 0; + data.non_block = non_block; + return ilookup5(sb, hash, iget_test, &data); +} + +static struct inode *gfs2_iget(struct super_block *sb, u64 no_addr, + int non_block) +{ + struct gfs2_skip_data data; + unsigned long hash = (unsigned long)no_addr; + + data.no_addr = no_addr; + data.skipped = 0; + data.non_block = non_block; + return iget5_locked(sb, hash, iget_test, iget_set, &data); +} + +/** + * gfs2_set_iop - Sets inode operations + * @inode: The inode with correct i_mode filled in + * + * GFS2 lookup code fills in vfs inode contents based on info obtained + * from directory entry inside gfs2_inode_lookup(). + */ + +static void gfs2_set_iop(struct inode *inode) +{ + struct gfs2_sbd *sdp = GFS2_SB(inode); + umode_t mode = inode->i_mode; + + if (S_ISREG(mode)) { + inode->i_op = &gfs2_file_iops; + if (gfs2_localflocks(sdp)) + inode->i_fop = &gfs2_file_fops_nolock; + else + inode->i_fop = &gfs2_file_fops; + } else if (S_ISDIR(mode)) { + inode->i_op = &gfs2_dir_iops; + if (gfs2_localflocks(sdp)) + inode->i_fop = &gfs2_dir_fops_nolock; + else + inode->i_fop = &gfs2_dir_fops; + } else if (S_ISLNK(mode)) { + inode->i_op = &gfs2_symlink_iops; + } else { + inode->i_op = &gfs2_file_iops; + init_special_inode(inode, inode->i_mode, inode->i_rdev); + } +} + +/** + * gfs2_inode_lookup - Lookup an inode + * @sb: The super block + * @no_addr: The inode number + * @type: The type of the inode + * non_block: Can we block on inodes that are being freed? + * + * Returns: A VFS inode, or an error + */ + +struct inode *gfs2_inode_lookup(struct super_block *sb, unsigned int type, + u64 no_addr, u64 no_formal_ino, int non_block) +{ + struct inode *inode; + struct gfs2_inode *ip; + struct gfs2_glock *io_gl = NULL; + int error; + + inode = gfs2_iget(sb, no_addr, non_block); + ip = GFS2_I(inode); + + if (!inode) + return ERR_PTR(-ENOBUFS); + + if (inode->i_state & I_NEW) { + struct gfs2_sbd *sdp = GFS2_SB(inode); + ip->i_no_formal_ino = no_formal_ino; + + error = gfs2_glock_get(sdp, no_addr, &gfs2_inode_glops, CREATE, &ip->i_gl); + if (unlikely(error)) + goto fail; + ip->i_gl->gl_object = ip; + + error = gfs2_glock_get(sdp, no_addr, &gfs2_iopen_glops, CREATE, &io_gl); + if (unlikely(error)) + goto fail_put; + + set_bit(GIF_INVALID, &ip->i_flags); + error = gfs2_glock_nq_init(io_gl, LM_ST_SHARED, GL_EXACT, &ip->i_iopen_gh); + if (unlikely(error)) + goto fail_iopen; + + ip->i_iopen_gh.gh_gl->gl_object = ip; + gfs2_glock_put(io_gl); + io_gl = NULL; + + if (type == DT_UNKNOWN) { + /* Inode glock must be locked already */ + error = gfs2_inode_refresh(GFS2_I(inode)); + if (error) + goto fail_refresh; + } else { + inode->i_mode = DT2IF(type); + } + + gfs2_set_iop(inode); + unlock_new_inode(inode); + } + + return inode; + +fail_refresh: + ip->i_iopen_gh.gh_gl->gl_object = NULL; + gfs2_glock_dq_uninit(&ip->i_iopen_gh); +fail_iopen: + if (io_gl) + gfs2_glock_put(io_gl); +fail_put: + ip->i_gl->gl_object = NULL; + gfs2_glock_put(ip->i_gl); +fail: + iget_failed(inode); + return ERR_PTR(error); +} + +struct inode *gfs2_lookup_by_inum(struct gfs2_sbd *sdp, u64 no_addr, + u64 *no_formal_ino, unsigned int blktype) +{ + struct super_block *sb = sdp->sd_vfs; + struct gfs2_holder i_gh; + struct inode *inode = NULL; + int error; + + /* Must not read in block until block type is verified */ + error = gfs2_glock_nq_num(sdp, no_addr, &gfs2_inode_glops, + LM_ST_EXCLUSIVE, GL_SKIP, &i_gh); + if (error) + return ERR_PTR(error); + + error = gfs2_check_blk_type(sdp, no_addr, blktype); + if (error) + goto fail; + + inode = gfs2_inode_lookup(sb, DT_UNKNOWN, no_addr, 0, 1); + if (IS_ERR(inode)) + goto fail; + + /* Two extra checks for NFS only */ + if (no_formal_ino) { + error = -ESTALE; + if (GFS2_I(inode)->i_no_formal_ino != *no_formal_ino) + goto fail_iput; + + error = -EIO; + if (GFS2_I(inode)->i_diskflags & GFS2_DIF_SYSTEM) + goto fail_iput; + + error = 0; + } + +fail: + gfs2_glock_dq_uninit(&i_gh); + return error ? ERR_PTR(error) : inode; +fail_iput: + iput(inode); + goto fail; +} + + +struct inode *gfs2_lookup_simple(struct inode *dip, const char *name) +{ + struct qstr qstr; + struct inode *inode; + gfs2_str2qstr(&qstr, name); + inode = gfs2_lookupi(dip, &qstr, 1); + /* gfs2_lookupi has inconsistent callers: vfs + * related routines expect NULL for no entry found, + * gfs2_lookup_simple callers expect ENOENT + * and do not check for NULL. + */ + if (inode == NULL) + return ERR_PTR(-ENOENT); + else + return inode; +} + + +/** + * gfs2_lookupi - Look up a filename in a directory and return its inode + * @d_gh: An initialized holder for the directory glock + * @name: The name of the inode to look for + * @is_root: If 1, ignore the caller's permissions + * @i_gh: An uninitialized holder for the new inode glock + * + * This can be called via the VFS filldir function when NFS is doing + * a readdirplus and the inode which its intending to stat isn't + * already in cache. In this case we must not take the directory glock + * again, since the readdir call will have already taken that lock. + * + * Returns: errno + */ + +struct inode *gfs2_lookupi(struct inode *dir, const struct qstr *name, + int is_root) +{ + struct super_block *sb = dir->i_sb; + struct gfs2_inode *dip = GFS2_I(dir); + struct gfs2_holder d_gh; + int error = 0; + struct inode *inode = NULL; + int unlock = 0; + + if (!name->len || name->len > GFS2_FNAMESIZE) + return ERR_PTR(-ENAMETOOLONG); + + if ((name->len == 1 && memcmp(name->name, ".", 1) == 0) || + (name->len == 2 && memcmp(name->name, "..", 2) == 0 && + dir == sb->s_root->d_inode)) { + igrab(dir); + return dir; + } + + if (gfs2_glock_is_locked_by_me(dip->i_gl) == NULL) { + error = gfs2_glock_nq_init(dip->i_gl, LM_ST_SHARED, 0, &d_gh); + if (error) + return ERR_PTR(error); + unlock = 1; + } + + if (!is_root) { + error = gfs2_permission(dir, MAY_EXEC, 0); + if (error) + goto out; + } + + inode = gfs2_dir_search(dir, name); + if (IS_ERR(inode)) + error = PTR_ERR(inode); +out: + if (unlock) + gfs2_glock_dq_uninit(&d_gh); + if (error == -ENOENT) + return NULL; + return inode ? inode : ERR_PTR(error); +} + +/** + * create_ok - OK to create a new on-disk inode here? + * @dip: Directory in which dinode is to be created + * @name: Name of new dinode + * @mode: + * + * Returns: errno + */ + +static int create_ok(struct gfs2_inode *dip, const struct qstr *name, + unsigned int mode) +{ + int error; + + error = gfs2_permission(&dip->i_inode, MAY_WRITE | MAY_EXEC, 0); + if (error) + return error; + + /* Don't create entries in an unlinked directory */ + if (!dip->i_inode.i_nlink) + return -ENOENT; + + error = gfs2_dir_check(&dip->i_inode, name, NULL); + switch (error) { + case -ENOENT: + error = 0; + break; + case 0: + return -EEXIST; + default: + return error; + } + + if (dip->i_entries == (u32)-1) + return -EFBIG; + if (S_ISDIR(mode) && dip->i_inode.i_nlink == (u32)-1) + return -EMLINK; + + return 0; +} + +static void munge_mode_uid_gid(struct gfs2_inode *dip, unsigned int *mode, + unsigned int *uid, unsigned int *gid) +{ + if (GFS2_SB(&dip->i_inode)->sd_args.ar_suiddir && + (dip->i_inode.i_mode & S_ISUID) && dip->i_inode.i_uid) { + if (S_ISDIR(*mode)) + *mode |= S_ISUID; + else if (dip->i_inode.i_uid != current_fsuid()) + *mode &= ~07111; + *uid = dip->i_inode.i_uid; + } else + *uid = current_fsuid(); + + if (dip->i_inode.i_mode & S_ISGID) { + if (S_ISDIR(*mode)) + *mode |= S_ISGID; + *gid = dip->i_inode.i_gid; + } else + *gid = current_fsgid(); +} + +static int alloc_dinode(struct gfs2_inode *dip, u64 *no_addr, u64 *generation) +{ + struct gfs2_sbd *sdp = GFS2_SB(&dip->i_inode); + int error; + + if (gfs2_alloc_get(dip) == NULL) + return -ENOMEM; + + dip->i_alloc->al_requested = RES_DINODE; + error = gfs2_inplace_reserve(dip); + if (error) + goto out; + + error = gfs2_trans_begin(sdp, RES_RG_BIT + RES_STATFS, 0); + if (error) + goto out_ipreserv; + + error = gfs2_alloc_di(dip, no_addr, generation); + + gfs2_trans_end(sdp); + +out_ipreserv: + gfs2_inplace_release(dip); +out: + gfs2_alloc_put(dip); + return error; +} + +/** + * init_dinode - Fill in a new dinode structure + * @dip: the directory this inode is being created in + * @gl: The glock covering the new inode + * @inum: the inode number + * @mode: the file permissions + * @uid: + * @gid: + * + */ + +static void init_dinode(struct gfs2_inode *dip, struct gfs2_glock *gl, + const struct gfs2_inum_host *inum, unsigned int mode, + unsigned int uid, unsigned int gid, + const u64 *generation, dev_t dev, struct buffer_head **bhp) +{ + struct gfs2_sbd *sdp = GFS2_SB(&dip->i_inode); + struct gfs2_dinode *di; + struct buffer_head *dibh; + struct timespec tv = CURRENT_TIME; + + dibh = gfs2_meta_new(gl, inum->no_addr); + gfs2_trans_add_bh(gl, dibh, 1); + gfs2_metatype_set(dibh, GFS2_METATYPE_DI, GFS2_FORMAT_DI); + gfs2_buffer_clear_tail(dibh, sizeof(struct gfs2_dinode)); + di = (struct gfs2_dinode *)dibh->b_data; + + di->di_num.no_formal_ino = cpu_to_be64(inum->no_formal_ino); + di->di_num.no_addr = cpu_to_be64(inum->no_addr); + di->di_mode = cpu_to_be32(mode); + di->di_uid = cpu_to_be32(uid); + di->di_gid = cpu_to_be32(gid); + di->di_nlink = 0; + di->di_size = 0; + di->di_blocks = cpu_to_be64(1); + di->di_atime = di->di_mtime = di->di_ctime = cpu_to_be64(tv.tv_sec); + di->di_major = cpu_to_be32(MAJOR(dev)); + di->di_minor = cpu_to_be32(MINOR(dev)); + di->di_goal_meta = di->di_goal_data = cpu_to_be64(inum->no_addr); + di->di_generation = cpu_to_be64(*generation); + di->di_flags = 0; + + if (S_ISREG(mode)) { + if ((dip->i_diskflags & GFS2_DIF_INHERIT_JDATA) || + gfs2_tune_get(sdp, gt_new_files_jdata)) + di->di_flags |= cpu_to_be32(GFS2_DIF_JDATA); + } else if (S_ISDIR(mode)) { + di->di_flags |= cpu_to_be32(dip->i_diskflags & + GFS2_DIF_INHERIT_JDATA); + } + + di->__pad1 = 0; + di->di_payload_format = cpu_to_be32(S_ISDIR(mode) ? GFS2_FORMAT_DE : 0); + di->di_height = 0; + di->__pad2 = 0; + di->__pad3 = 0; + di->di_depth = 0; + di->di_entries = 0; + memset(&di->__pad4, 0, sizeof(di->__pad4)); + di->di_eattr = 0; + di->di_atime_nsec = cpu_to_be32(tv.tv_nsec); + di->di_mtime_nsec = cpu_to_be32(tv.tv_nsec); + di->di_ctime_nsec = cpu_to_be32(tv.tv_nsec); + memset(&di->di_reserved, 0, sizeof(di->di_reserved)); + + set_buffer_uptodate(dibh); + + *bhp = dibh; +} + +static int make_dinode(struct gfs2_inode *dip, struct gfs2_glock *gl, + unsigned int mode, const struct gfs2_inum_host *inum, + const u64 *generation, dev_t dev, struct buffer_head **bhp) +{ + struct gfs2_sbd *sdp = GFS2_SB(&dip->i_inode); + unsigned int uid, gid; + int error; + + munge_mode_uid_gid(dip, &mode, &uid, &gid); + if (!gfs2_alloc_get(dip)) + return -ENOMEM; + + error = gfs2_quota_lock(dip, uid, gid); + if (error) + goto out; + + error = gfs2_quota_check(dip, uid, gid); + if (error) + goto out_quota; + + error = gfs2_trans_begin(sdp, RES_DINODE + RES_QUOTA, 0); + if (error) + goto out_quota; + + init_dinode(dip, gl, inum, mode, uid, gid, generation, dev, bhp); + gfs2_quota_change(dip, +1, uid, gid); + gfs2_trans_end(sdp); + +out_quota: + gfs2_quota_unlock(dip); +out: + gfs2_alloc_put(dip); + return error; +} + +static int link_dinode(struct gfs2_inode *dip, const struct qstr *name, + struct gfs2_inode *ip) +{ + struct gfs2_sbd *sdp = GFS2_SB(&dip->i_inode); + struct gfs2_alloc *al; + int alloc_required; + struct buffer_head *dibh; + int error; + + al = gfs2_alloc_get(dip); + if (!al) + return -ENOMEM; + + error = gfs2_quota_lock(dip, NO_QUOTA_CHANGE, NO_QUOTA_CHANGE); + if (error) + goto fail; + + error = alloc_required = gfs2_diradd_alloc_required(&dip->i_inode, name); + if (alloc_required < 0) + goto fail_quota_locks; + if (alloc_required) { + error = gfs2_quota_check(dip, dip->i_inode.i_uid, dip->i_inode.i_gid); + if (error) + goto fail_quota_locks; + + al->al_requested = sdp->sd_max_dirres; + + error = gfs2_inplace_reserve(dip); + if (error) + goto fail_quota_locks; + + error = gfs2_trans_begin(sdp, sdp->sd_max_dirres + + al->al_rgd->rd_length + + 2 * RES_DINODE + + RES_STATFS + RES_QUOTA, 0); + if (error) + goto fail_ipreserv; + } else { + error = gfs2_trans_begin(sdp, RES_LEAF + 2 * RES_DINODE, 0); + if (error) + goto fail_quota_locks; + } + + error = gfs2_dir_add(&dip->i_inode, name, ip); + if (error) + goto fail_end_trans; + + error = gfs2_meta_inode_buffer(ip, &dibh); + if (error) + goto fail_end_trans; + ip->i_inode.i_nlink = 1; + gfs2_trans_add_bh(ip->i_gl, dibh, 1); + gfs2_dinode_out(ip, dibh->b_data); + brelse(dibh); + return 0; + +fail_end_trans: + gfs2_trans_end(sdp); + +fail_ipreserv: + if (dip->i_alloc->al_rgd) + gfs2_inplace_release(dip); + +fail_quota_locks: + gfs2_quota_unlock(dip); + +fail: + gfs2_alloc_put(dip); + return error; +} + +static int gfs2_security_init(struct gfs2_inode *dip, struct gfs2_inode *ip, + const struct qstr *qstr) +{ + int err; + size_t len; + void *value; + char *name; + + err = security_inode_init_security(&ip->i_inode, &dip->i_inode, qstr, + &name, &value, &len); + + if (err) { + if (err == -EOPNOTSUPP) + return 0; + return err; + } + + err = __gfs2_xattr_set(&ip->i_inode, name, value, len, 0, + GFS2_EATYPE_SECURITY); + kfree(value); + kfree(name); + + return err; +} + +/** + * gfs2_createi - Create a new inode + * @ghs: An array of two holders + * @name: The name of the new file + * @mode: the permissions on the new inode + * + * @ghs[0] is an initialized holder for the directory + * @ghs[1] is the holder for the inode lock + * + * If the return value is not NULL, the glocks on both the directory and the new + * file are held. A transaction has been started and an inplace reservation + * is held, as well. + * + * Returns: An inode + */ + +struct inode *gfs2_createi(struct gfs2_holder *ghs, const struct qstr *name, + unsigned int mode, dev_t dev) +{ + struct inode *inode = NULL; + struct gfs2_inode *dip = ghs->gh_gl->gl_object; + struct inode *dir = &dip->i_inode; + struct gfs2_sbd *sdp = GFS2_SB(&dip->i_inode); + struct gfs2_inum_host inum = { .no_addr = 0, .no_formal_ino = 0 }; + int error; + u64 generation; + struct buffer_head *bh = NULL; + + if (!name->len || name->len > GFS2_FNAMESIZE) + return ERR_PTR(-ENAMETOOLONG); + + gfs2_holder_reinit(LM_ST_EXCLUSIVE, 0, ghs); + error = gfs2_glock_nq(ghs); + if (error) + goto fail; + + error = create_ok(dip, name, mode); + if (error) + goto fail_gunlock; + + error = alloc_dinode(dip, &inum.no_addr, &generation); + if (error) + goto fail_gunlock; + inum.no_formal_ino = generation; + + error = gfs2_glock_nq_num(sdp, inum.no_addr, &gfs2_inode_glops, + LM_ST_EXCLUSIVE, GL_SKIP, ghs + 1); + if (error) + goto fail_gunlock; + + error = make_dinode(dip, ghs[1].gh_gl, mode, &inum, &generation, dev, &bh); + if (error) + goto fail_gunlock2; + + inode = gfs2_inode_lookup(dir->i_sb, IF2DT(mode), inum.no_addr, + inum.no_formal_ino, 0); + if (IS_ERR(inode)) + goto fail_gunlock2; + + error = gfs2_inode_refresh(GFS2_I(inode)); + if (error) + goto fail_gunlock2; + + error = gfs2_acl_create(dip, inode); + if (error) + goto fail_gunlock2; + + error = gfs2_security_init(dip, GFS2_I(inode), name); + if (error) + goto fail_gunlock2; + + error = link_dinode(dip, name, GFS2_I(inode)); + if (error) + goto fail_gunlock2; + + if (bh) + brelse(bh); + return inode; + +fail_gunlock2: + gfs2_glock_dq_uninit(ghs + 1); + if (inode && !IS_ERR(inode)) + iput(inode); +fail_gunlock: + gfs2_glock_dq(ghs); +fail: + if (bh) + brelse(bh); + return ERR_PTR(error); +} +/** + * gfs2_create - Create a file + * @dir: The directory in which to create the file + * @dentry: The dentry of the new file + * @mode: The mode of the new file + * + * Returns: errno + */ + +static int gfs2_create(struct inode *dir, struct dentry *dentry, + int mode, struct nameidata *nd) +{ + struct gfs2_inode *dip = GFS2_I(dir); + struct gfs2_sbd *sdp = GFS2_SB(dir); + struct gfs2_holder ghs[2]; + struct inode *inode; + + gfs2_holder_init(dip->i_gl, 0, 0, ghs); + + for (;;) { + inode = gfs2_createi(ghs, &dentry->d_name, S_IFREG | mode, 0); + if (!IS_ERR(inode)) { + gfs2_trans_end(sdp); + if (dip->i_alloc->al_rgd) + gfs2_inplace_release(dip); + gfs2_quota_unlock(dip); + gfs2_alloc_put(dip); + gfs2_glock_dq_uninit_m(2, ghs); + mark_inode_dirty(inode); + break; + } else if (PTR_ERR(inode) != -EEXIST || + (nd && nd->flags & LOOKUP_EXCL)) { + gfs2_holder_uninit(ghs); + return PTR_ERR(inode); + } + + inode = gfs2_lookupi(dir, &dentry->d_name, 0); + if (inode) { + if (!IS_ERR(inode)) { + gfs2_holder_uninit(ghs); + break; + } else { + gfs2_holder_uninit(ghs); + return PTR_ERR(inode); + } + } + } + + d_instantiate(dentry, inode); + + return 0; +} + +/** + * gfs2_lookup - Look up a filename in a directory and return its inode + * @dir: The directory inode + * @dentry: The dentry of the new inode + * @nd: passed from Linux VFS, ignored by us + * + * Called by the VFS layer. Lock dir and call gfs2_lookupi() + * + * Returns: errno + */ + +static struct dentry *gfs2_lookup(struct inode *dir, struct dentry *dentry, + struct nameidata *nd) +{ + struct inode *inode = NULL; + + inode = gfs2_lookupi(dir, &dentry->d_name, 0); + if (inode && IS_ERR(inode)) + return ERR_CAST(inode); + + if (inode) { + struct gfs2_glock *gl = GFS2_I(inode)->i_gl; + struct gfs2_holder gh; + int error; + error = gfs2_glock_nq_init(gl, LM_ST_SHARED, LM_FLAG_ANY, &gh); + if (error) { + iput(inode); + return ERR_PTR(error); + } + gfs2_glock_dq_uninit(&gh); + return d_splice_alias(inode, dentry); + } + d_add(dentry, inode); + + return NULL; +} + +/** + * gfs2_link - Link to a file + * @old_dentry: The inode to link + * @dir: Add link to this directory + * @dentry: The name of the link + * + * Link the inode in "old_dentry" into the directory "dir" with the + * name in "dentry". + * + * Returns: errno + */ + +static int gfs2_link(struct dentry *old_dentry, struct inode *dir, + struct dentry *dentry) +{ + struct gfs2_inode *dip = GFS2_I(dir); + struct gfs2_sbd *sdp = GFS2_SB(dir); + struct inode *inode = old_dentry->d_inode; + struct gfs2_inode *ip = GFS2_I(inode); + struct gfs2_holder ghs[2]; + struct buffer_head *dibh; + int alloc_required; + int error; + + if (S_ISDIR(inode->i_mode)) + return -EPERM; + + gfs2_holder_init(dip->i_gl, LM_ST_EXCLUSIVE, 0, ghs); + gfs2_holder_init(ip->i_gl, LM_ST_EXCLUSIVE, 0, ghs + 1); + + error = gfs2_glock_nq(ghs); /* parent */ + if (error) + goto out_parent; + + error = gfs2_glock_nq(ghs + 1); /* child */ + if (error) + goto out_child; + + error = -ENOENT; + if (inode->i_nlink == 0) + goto out_gunlock; + + error = gfs2_permission(dir, MAY_WRITE | MAY_EXEC, 0); + if (error) + goto out_gunlock; + + error = gfs2_dir_check(dir, &dentry->d_name, NULL); + switch (error) { + case -ENOENT: + break; + case 0: + error = -EEXIST; + default: + goto out_gunlock; + } + + error = -EINVAL; + if (!dip->i_inode.i_nlink) + goto out_gunlock; + error = -EFBIG; + if (dip->i_entries == (u32)-1) + goto out_gunlock; + error = -EPERM; + if (IS_IMMUTABLE(inode) || IS_APPEND(inode)) + goto out_gunlock; + error = -EINVAL; + if (!ip->i_inode.i_nlink) + goto out_gunlock; + error = -EMLINK; + if (ip->i_inode.i_nlink == (u32)-1) + goto out_gunlock; + + alloc_required = error = gfs2_diradd_alloc_required(dir, &dentry->d_name); + if (error < 0) + goto out_gunlock; + error = 0; + + if (alloc_required) { + struct gfs2_alloc *al = gfs2_alloc_get(dip); + if (!al) { + error = -ENOMEM; + goto out_gunlock; + } + + error = gfs2_quota_lock_check(dip); + if (error) + goto out_alloc; + + al->al_requested = sdp->sd_max_dirres; + + error = gfs2_inplace_reserve(dip); + if (error) + goto out_gunlock_q; + + error = gfs2_trans_begin(sdp, sdp->sd_max_dirres + + gfs2_rg_blocks(al) + + 2 * RES_DINODE + RES_STATFS + + RES_QUOTA, 0); + if (error) + goto out_ipres; + } else { + error = gfs2_trans_begin(sdp, 2 * RES_DINODE + RES_LEAF, 0); + if (error) + goto out_ipres; + } + + error = gfs2_meta_inode_buffer(ip, &dibh); + if (error) + goto out_end_trans; + + error = gfs2_dir_add(dir, &dentry->d_name, ip); + if (error) + goto out_brelse; + + gfs2_trans_add_bh(ip->i_gl, dibh, 1); + inc_nlink(&ip->i_inode); + ip->i_inode.i_ctime = CURRENT_TIME; + gfs2_dinode_out(ip, dibh->b_data); + mark_inode_dirty(&ip->i_inode); + +out_brelse: + brelse(dibh); +out_end_trans: + gfs2_trans_end(sdp); +out_ipres: + if (alloc_required) + gfs2_inplace_release(dip); +out_gunlock_q: + if (alloc_required) + gfs2_quota_unlock(dip); +out_alloc: + if (alloc_required) + gfs2_alloc_put(dip); +out_gunlock: + gfs2_glock_dq(ghs + 1); +out_child: + gfs2_glock_dq(ghs); +out_parent: + gfs2_holder_uninit(ghs); + gfs2_holder_uninit(ghs + 1); + if (!error) { + ihold(inode); + d_instantiate(dentry, inode); + mark_inode_dirty(inode); + } + return error; +} + +/* + * gfs2_unlink_ok - check to see that a inode is still in a directory + * @dip: the directory + * @name: the name of the file + * @ip: the inode + * + * Assumes that the lock on (at least) @dip is held. + * + * Returns: 0 if the parent/child relationship is correct, errno if it isn't + */ + +static int gfs2_unlink_ok(struct gfs2_inode *dip, const struct qstr *name, + const struct gfs2_inode *ip) +{ + int error; + + if (IS_IMMUTABLE(&ip->i_inode) || IS_APPEND(&ip->i_inode)) + return -EPERM; + + if ((dip->i_inode.i_mode & S_ISVTX) && + dip->i_inode.i_uid != current_fsuid() && + ip->i_inode.i_uid != current_fsuid() && !capable(CAP_FOWNER)) + return -EPERM; + + if (IS_APPEND(&dip->i_inode)) + return -EPERM; + + error = gfs2_permission(&dip->i_inode, MAY_WRITE | MAY_EXEC, 0); + if (error) + return error; + + error = gfs2_dir_check(&dip->i_inode, name, ip); + if (error) + return error; + + return 0; +} + +/** + * gfs2_unlink_inode - Removes an inode from its parent dir and unlinks it + * @dip: The parent directory + * @name: The name of the entry in the parent directory + * @bh: The inode buffer for the inode to be removed + * @inode: The inode to be removed + * + * Called with all the locks and in a transaction. This will only be + * called for a directory after it has been checked to ensure it is empty. + * + * Returns: 0 on success, or an error + */ + +static int gfs2_unlink_inode(struct gfs2_inode *dip, + const struct dentry *dentry, + struct buffer_head *bh) +{ + struct inode *inode = dentry->d_inode; + struct gfs2_inode *ip = GFS2_I(inode); + int error; + + error = gfs2_dir_del(dip, dentry); + if (error) + return error; + + ip->i_entries = 0; + inode->i_ctime = CURRENT_TIME; + if (S_ISDIR(inode->i_mode)) + clear_nlink(inode); + else + drop_nlink(inode); + gfs2_trans_add_bh(ip->i_gl, bh, 1); + gfs2_dinode_out(ip, bh->b_data); + mark_inode_dirty(inode); + if (inode->i_nlink == 0) + gfs2_unlink_di(inode); + return 0; +} + + +/** + * gfs2_unlink - Unlink an inode (this does rmdir as well) + * @dir: The inode of the directory containing the inode to unlink + * @dentry: The file itself + * + * This routine uses the type of the inode as a flag to figure out + * whether this is an unlink or an rmdir. + * + * Returns: errno + */ + +static int gfs2_unlink(struct inode *dir, struct dentry *dentry) +{ + struct gfs2_inode *dip = GFS2_I(dir); + struct gfs2_sbd *sdp = GFS2_SB(dir); + struct inode *inode = dentry->d_inode; + struct gfs2_inode *ip = GFS2_I(inode); + struct buffer_head *bh; + struct gfs2_holder ghs[3]; + struct gfs2_rgrpd *rgd; + struct gfs2_holder ri_gh; + int error; + + error = gfs2_rindex_hold(sdp, &ri_gh); + if (error) + return error; + + gfs2_holder_init(dip->i_gl, LM_ST_EXCLUSIVE, 0, ghs); + gfs2_holder_init(ip->i_gl, LM_ST_EXCLUSIVE, 0, ghs + 1); + + rgd = gfs2_blk2rgrpd(sdp, ip->i_no_addr); + gfs2_holder_init(rgd->rd_gl, LM_ST_EXCLUSIVE, 0, ghs + 2); + + + error = gfs2_glock_nq(ghs); /* parent */ + if (error) + goto out_parent; + + error = gfs2_glock_nq(ghs + 1); /* child */ + if (error) + goto out_child; + + error = -ENOENT; + if (inode->i_nlink == 0) + goto out_rgrp; + + if (S_ISDIR(inode->i_mode)) { + error = -ENOTEMPTY; + if (ip->i_entries > 2 || inode->i_nlink > 2) + goto out_rgrp; + } + + error = gfs2_glock_nq(ghs + 2); /* rgrp */ + if (error) + goto out_rgrp; + + error = gfs2_unlink_ok(dip, &dentry->d_name, ip); + if (error) + goto out_gunlock; + + error = gfs2_trans_begin(sdp, 2*RES_DINODE + 3*RES_LEAF + RES_RG_BIT, 0); + if (error) + goto out_gunlock; + + error = gfs2_meta_inode_buffer(ip, &bh); + if (error) + goto out_end_trans; + + error = gfs2_unlink_inode(dip, dentry, bh); + brelse(bh); + +out_end_trans: + gfs2_trans_end(sdp); +out_gunlock: + gfs2_glock_dq(ghs + 2); +out_rgrp: + gfs2_holder_uninit(ghs + 2); + gfs2_glock_dq(ghs + 1); +out_child: + gfs2_holder_uninit(ghs + 1); + gfs2_glock_dq(ghs); +out_parent: + gfs2_holder_uninit(ghs); + gfs2_glock_dq_uninit(&ri_gh); + return error; +} + +/** + * gfs2_symlink - Create a symlink + * @dir: The directory to create the symlink in + * @dentry: The dentry to put the symlink in + * @symname: The thing which the link points to + * + * Returns: errno + */ + +static int gfs2_symlink(struct inode *dir, struct dentry *dentry, + const char *symname) +{ + struct gfs2_inode *dip = GFS2_I(dir), *ip; + struct gfs2_sbd *sdp = GFS2_SB(dir); + struct gfs2_holder ghs[2]; + struct inode *inode; + struct buffer_head *dibh; + int size; + int error; + + /* Must be stuffed with a null terminator for gfs2_follow_link() */ + size = strlen(symname); + if (size > sdp->sd_sb.sb_bsize - sizeof(struct gfs2_dinode) - 1) + return -ENAMETOOLONG; + + gfs2_holder_init(dip->i_gl, 0, 0, ghs); + + inode = gfs2_createi(ghs, &dentry->d_name, S_IFLNK | S_IRWXUGO, 0); + if (IS_ERR(inode)) { + gfs2_holder_uninit(ghs); + return PTR_ERR(inode); + } + + ip = ghs[1].gh_gl->gl_object; + + i_size_write(inode, size); + + error = gfs2_meta_inode_buffer(ip, &dibh); + + if (!gfs2_assert_withdraw(sdp, !error)) { + gfs2_dinode_out(ip, dibh->b_data); + memcpy(dibh->b_data + sizeof(struct gfs2_dinode), symname, + size); + brelse(dibh); + } + + gfs2_trans_end(sdp); + if (dip->i_alloc->al_rgd) + gfs2_inplace_release(dip); + gfs2_quota_unlock(dip); + gfs2_alloc_put(dip); + + gfs2_glock_dq_uninit_m(2, ghs); + + d_instantiate(dentry, inode); + mark_inode_dirty(inode); + + return 0; +} + +/** + * gfs2_mkdir - Make a directory + * @dir: The parent directory of the new one + * @dentry: The dentry of the new directory + * @mode: The mode of the new directory + * + * Returns: errno + */ + +static int gfs2_mkdir(struct inode *dir, struct dentry *dentry, int mode) +{ + struct gfs2_inode *dip = GFS2_I(dir), *ip; + struct gfs2_sbd *sdp = GFS2_SB(dir); + struct gfs2_holder ghs[2]; + struct inode *inode; + struct buffer_head *dibh; + int error; + + gfs2_holder_init(dip->i_gl, 0, 0, ghs); + + inode = gfs2_createi(ghs, &dentry->d_name, S_IFDIR | mode, 0); + if (IS_ERR(inode)) { + gfs2_holder_uninit(ghs); + return PTR_ERR(inode); + } + + ip = ghs[1].gh_gl->gl_object; + + ip->i_inode.i_nlink = 2; + i_size_write(inode, sdp->sd_sb.sb_bsize - sizeof(struct gfs2_dinode)); + ip->i_diskflags |= GFS2_DIF_JDATA; + ip->i_entries = 2; + + error = gfs2_meta_inode_buffer(ip, &dibh); + + if (!gfs2_assert_withdraw(sdp, !error)) { + struct gfs2_dinode *di = (struct gfs2_dinode *)dibh->b_data; + struct gfs2_dirent *dent = (struct gfs2_dirent *)(di+1); + + gfs2_trans_add_bh(ip->i_gl, dibh, 1); + gfs2_qstr2dirent(&gfs2_qdot, GFS2_DIRENT_SIZE(gfs2_qdot.len), dent); + dent->de_inum = di->di_num; /* already GFS2 endian */ + dent->de_type = cpu_to_be16(DT_DIR); + di->di_entries = cpu_to_be32(1); + + dent = (struct gfs2_dirent *)((char*)dent + GFS2_DIRENT_SIZE(1)); + gfs2_qstr2dirent(&gfs2_qdotdot, dibh->b_size - GFS2_DIRENT_SIZE(1) - sizeof(struct gfs2_dinode), dent); + + gfs2_inum_out(dip, dent); + dent->de_type = cpu_to_be16(DT_DIR); + + gfs2_dinode_out(ip, di); + + brelse(dibh); + } + + gfs2_trans_end(sdp); + if (dip->i_alloc->al_rgd) + gfs2_inplace_release(dip); + gfs2_quota_unlock(dip); + gfs2_alloc_put(dip); + + gfs2_glock_dq_uninit_m(2, ghs); + + d_instantiate(dentry, inode); + mark_inode_dirty(inode); + + return 0; +} + +/** + * gfs2_mknod - Make a special file + * @dir: The directory in which the special file will reside + * @dentry: The dentry of the special file + * @mode: The mode of the special file + * @rdev: The device specification of the special file + * + */ + +static int gfs2_mknod(struct inode *dir, struct dentry *dentry, int mode, + dev_t dev) +{ + struct gfs2_inode *dip = GFS2_I(dir); + struct gfs2_sbd *sdp = GFS2_SB(dir); + struct gfs2_holder ghs[2]; + struct inode *inode; + + gfs2_holder_init(dip->i_gl, 0, 0, ghs); + + inode = gfs2_createi(ghs, &dentry->d_name, mode, dev); + if (IS_ERR(inode)) { + gfs2_holder_uninit(ghs); + return PTR_ERR(inode); + } + + gfs2_trans_end(sdp); + if (dip->i_alloc->al_rgd) + gfs2_inplace_release(dip); + gfs2_quota_unlock(dip); + gfs2_alloc_put(dip); + + gfs2_glock_dq_uninit_m(2, ghs); + + d_instantiate(dentry, inode); + mark_inode_dirty(inode); + + return 0; +} + +/* + * gfs2_ok_to_move - check if it's ok to move a directory to another directory + * @this: move this + * @to: to here + * + * Follow @to back to the root and make sure we don't encounter @this + * Assumes we already hold the rename lock. + * + * Returns: errno + */ + +static int gfs2_ok_to_move(struct gfs2_inode *this, struct gfs2_inode *to) +{ + struct inode *dir = &to->i_inode; + struct super_block *sb = dir->i_sb; + struct inode *tmp; + int error = 0; + + igrab(dir); + + for (;;) { + if (dir == &this->i_inode) { + error = -EINVAL; + break; + } + if (dir == sb->s_root->d_inode) { + error = 0; + break; + } + + tmp = gfs2_lookupi(dir, &gfs2_qdotdot, 1); + if (IS_ERR(tmp)) { + error = PTR_ERR(tmp); + break; + } + + iput(dir); + dir = tmp; + } + + iput(dir); + + return error; +} + +/** + * gfs2_rename - Rename a file + * @odir: Parent directory of old file name + * @odentry: The old dentry of the file + * @ndir: Parent directory of new file name + * @ndentry: The new dentry of the file + * + * Returns: errno + */ + +static int gfs2_rename(struct inode *odir, struct dentry *odentry, + struct inode *ndir, struct dentry *ndentry) +{ + struct gfs2_inode *odip = GFS2_I(odir); + struct gfs2_inode *ndip = GFS2_I(ndir); + struct gfs2_inode *ip = GFS2_I(odentry->d_inode); + struct gfs2_inode *nip = NULL; + struct gfs2_sbd *sdp = GFS2_SB(odir); + struct gfs2_holder ghs[5], r_gh = { .gh_gl = NULL, }, ri_gh; + struct gfs2_rgrpd *nrgd; + unsigned int num_gh; + int dir_rename = 0; + int alloc_required = 0; + unsigned int x; + int error; + + if (ndentry->d_inode) { + nip = GFS2_I(ndentry->d_inode); + if (ip == nip) + return 0; + } + + error = gfs2_rindex_hold(sdp, &ri_gh); + if (error) + return error; + + if (odip != ndip) { + error = gfs2_glock_nq_init(sdp->sd_rename_gl, LM_ST_EXCLUSIVE, + 0, &r_gh); + if (error) + goto out; + + if (S_ISDIR(ip->i_inode.i_mode)) { + dir_rename = 1; + /* don't move a dirctory into it's subdir */ + error = gfs2_ok_to_move(ip, ndip); + if (error) + goto out_gunlock_r; + } + } + + num_gh = 1; + gfs2_holder_init(odip->i_gl, LM_ST_EXCLUSIVE, 0, ghs); + if (odip != ndip) { + gfs2_holder_init(ndip->i_gl, LM_ST_EXCLUSIVE, 0, ghs + num_gh); + num_gh++; + } + gfs2_holder_init(ip->i_gl, LM_ST_EXCLUSIVE, 0, ghs + num_gh); + num_gh++; + + if (nip) { + gfs2_holder_init(nip->i_gl, LM_ST_EXCLUSIVE, 0, ghs + num_gh); + num_gh++; + /* grab the resource lock for unlink flag twiddling + * this is the case of the target file already existing + * so we unlink before doing the rename + */ + nrgd = gfs2_blk2rgrpd(sdp, nip->i_no_addr); + if (nrgd) + gfs2_holder_init(nrgd->rd_gl, LM_ST_EXCLUSIVE, 0, ghs + num_gh++); + } + + for (x = 0; x < num_gh; x++) { + error = gfs2_glock_nq(ghs + x); + if (error) + goto out_gunlock; + } + + error = -ENOENT; + if (ip->i_inode.i_nlink == 0) + goto out_gunlock; + + /* Check out the old directory */ + + error = gfs2_unlink_ok(odip, &odentry->d_name, ip); + if (error) + goto out_gunlock; + + /* Check out the new directory */ + + if (nip) { + error = gfs2_unlink_ok(ndip, &ndentry->d_name, nip); + if (error) + goto out_gunlock; + + if (nip->i_inode.i_nlink == 0) { + error = -EAGAIN; + goto out_gunlock; + } + + if (S_ISDIR(nip->i_inode.i_mode)) { + if (nip->i_entries < 2) { + gfs2_consist_inode(nip); + error = -EIO; + goto out_gunlock; + } + if (nip->i_entries > 2) { + error = -ENOTEMPTY; + goto out_gunlock; + } + } + } else { + error = gfs2_permission(ndir, MAY_WRITE | MAY_EXEC, 0); + if (error) + goto out_gunlock; + + error = gfs2_dir_check(ndir, &ndentry->d_name, NULL); + switch (error) { + case -ENOENT: + error = 0; + break; + case 0: + error = -EEXIST; + default: + goto out_gunlock; + }; + + if (odip != ndip) { + if (!ndip->i_inode.i_nlink) { + error = -ENOENT; + goto out_gunlock; + } + if (ndip->i_entries == (u32)-1) { + error = -EFBIG; + goto out_gunlock; + } + if (S_ISDIR(ip->i_inode.i_mode) && + ndip->i_inode.i_nlink == (u32)-1) { + error = -EMLINK; + goto out_gunlock; + } + } + } + + /* Check out the dir to be renamed */ + + if (dir_rename) { + error = gfs2_permission(odentry->d_inode, MAY_WRITE, 0); + if (error) + goto out_gunlock; + } + + if (nip == NULL) + alloc_required = gfs2_diradd_alloc_required(ndir, &ndentry->d_name); + error = alloc_required; + if (error < 0) + goto out_gunlock; + error = 0; + + if (alloc_required) { + struct gfs2_alloc *al = gfs2_alloc_get(ndip); + if (!al) { + error = -ENOMEM; + goto out_gunlock; + } + + error = gfs2_quota_lock_check(ndip); + if (error) + goto out_alloc; + + al->al_requested = sdp->sd_max_dirres; + + error = gfs2_inplace_reserve_ri(ndip); + if (error) + goto out_gunlock_q; + + error = gfs2_trans_begin(sdp, sdp->sd_max_dirres + + gfs2_rg_blocks(al) + + 4 * RES_DINODE + 4 * RES_LEAF + + RES_STATFS + RES_QUOTA + 4, 0); + if (error) + goto out_ipreserv; + } else { + error = gfs2_trans_begin(sdp, 4 * RES_DINODE + + 5 * RES_LEAF + 4, 0); + if (error) + goto out_gunlock; + } + + /* Remove the target file, if it exists */ + + if (nip) { + struct buffer_head *bh; + error = gfs2_meta_inode_buffer(nip, &bh); + if (error) + goto out_end_trans; + error = gfs2_unlink_inode(ndip, ndentry, bh); + brelse(bh); + } + + if (dir_rename) { + error = gfs2_dir_mvino(ip, &gfs2_qdotdot, ndip, DT_DIR); + if (error) + goto out_end_trans; + } else { + struct buffer_head *dibh; + error = gfs2_meta_inode_buffer(ip, &dibh); + if (error) + goto out_end_trans; + ip->i_inode.i_ctime = CURRENT_TIME; + gfs2_trans_add_bh(ip->i_gl, dibh, 1); + gfs2_dinode_out(ip, dibh->b_data); + brelse(dibh); + } + + error = gfs2_dir_del(odip, odentry); + if (error) + goto out_end_trans; + + error = gfs2_dir_add(ndir, &ndentry->d_name, ip); + if (error) + goto out_end_trans; + +out_end_trans: + gfs2_trans_end(sdp); +out_ipreserv: + if (alloc_required) + gfs2_inplace_release(ndip); +out_gunlock_q: + if (alloc_required) + gfs2_quota_unlock(ndip); +out_alloc: + if (alloc_required) + gfs2_alloc_put(ndip); +out_gunlock: + while (x--) { + gfs2_glock_dq(ghs + x); + gfs2_holder_uninit(ghs + x); + } +out_gunlock_r: + if (r_gh.gh_gl) + gfs2_glock_dq_uninit(&r_gh); +out: + gfs2_glock_dq_uninit(&ri_gh); + return error; +} + +/** + * gfs2_follow_link - Follow a symbolic link + * @dentry: The dentry of the link + * @nd: Data that we pass to vfs_follow_link() + * + * This can handle symlinks of any size. + * + * Returns: 0 on success or error code + */ + +static void *gfs2_follow_link(struct dentry *dentry, struct nameidata *nd) +{ + struct gfs2_inode *ip = GFS2_I(dentry->d_inode); + struct gfs2_holder i_gh; + struct buffer_head *dibh; + unsigned int x, size; + char *buf; + int error; + + gfs2_holder_init(ip->i_gl, LM_ST_SHARED, 0, &i_gh); + error = gfs2_glock_nq(&i_gh); + if (error) { + gfs2_holder_uninit(&i_gh); + nd_set_link(nd, ERR_PTR(error)); + return NULL; + } + + size = (unsigned int)i_size_read(&ip->i_inode); + if (size == 0) { + gfs2_consist_inode(ip); + buf = ERR_PTR(-EIO); + goto out; + } + + error = gfs2_meta_inode_buffer(ip, &dibh); + if (error) { + buf = ERR_PTR(error); + goto out; + } + + x = size + 1; + buf = kmalloc(x, GFP_NOFS); + if (!buf) + buf = ERR_PTR(-ENOMEM); + else + memcpy(buf, dibh->b_data + sizeof(struct gfs2_dinode), x); + brelse(dibh); +out: + gfs2_glock_dq_uninit(&i_gh); + nd_set_link(nd, buf); + return NULL; +} + +static void gfs2_put_link(struct dentry *dentry, struct nameidata *nd, void *p) +{ + char *s = nd_get_link(nd); + if (!IS_ERR(s)) + kfree(s); +} + +/** + * gfs2_permission - + * @inode: The inode + * @mask: The mask to be tested + * @flags: Indicates whether this is an RCU path walk or not + * + * This may be called from the VFS directly, or from within GFS2 with the + * inode locked, so we look to see if the glock is already locked and only + * lock the glock if its not already been done. + * + * Returns: errno + */ + +int gfs2_permission(struct inode *inode, int mask, unsigned int flags) +{ + struct gfs2_inode *ip; + struct gfs2_holder i_gh; + int error; + int unlock = 0; + + + ip = GFS2_I(inode); + if (gfs2_glock_is_locked_by_me(ip->i_gl) == NULL) { + if (flags & IPERM_FLAG_RCU) + return -ECHILD; + error = gfs2_glock_nq_init(ip->i_gl, LM_ST_SHARED, LM_FLAG_ANY, &i_gh); + if (error) + return error; + unlock = 1; + } + + if ((mask & MAY_WRITE) && IS_IMMUTABLE(inode)) + error = -EACCES; + else + error = generic_permission(inode, mask, flags, gfs2_check_acl); + if (unlock) + gfs2_glock_dq_uninit(&i_gh); + + return error; +} + +static int __gfs2_setattr_simple(struct gfs2_inode *ip, struct iattr *attr) +{ + struct inode *inode = &ip->i_inode; + struct buffer_head *dibh; + int error; + + error = gfs2_meta_inode_buffer(ip, &dibh); + if (error) + return error; + + setattr_copy(inode, attr); + mark_inode_dirty(inode); + gfs2_trans_add_bh(ip->i_gl, dibh, 1); + gfs2_dinode_out(ip, dibh->b_data); + brelse(dibh); + return 0; +} + +/** + * gfs2_setattr_simple - + * @ip: + * @attr: + * + * Returns: errno + */ + +int gfs2_setattr_simple(struct gfs2_inode *ip, struct iattr *attr) +{ + int error; + + if (current->journal_info) + return __gfs2_setattr_simple(ip, attr); + + error = gfs2_trans_begin(GFS2_SB(&ip->i_inode), RES_DINODE, 0); + if (error) + return error; + + error = __gfs2_setattr_simple(ip, attr); + gfs2_trans_end(GFS2_SB(&ip->i_inode)); + return error; +} + +static int setattr_chown(struct inode *inode, struct iattr *attr) +{ + struct gfs2_inode *ip = GFS2_I(inode); + struct gfs2_sbd *sdp = GFS2_SB(inode); + u32 ouid, ogid, nuid, ngid; + int error; + + ouid = inode->i_uid; + ogid = inode->i_gid; + nuid = attr->ia_uid; + ngid = attr->ia_gid; + + if (!(attr->ia_valid & ATTR_UID) || ouid == nuid) + ouid = nuid = NO_QUOTA_CHANGE; + if (!(attr->ia_valid & ATTR_GID) || ogid == ngid) + ogid = ngid = NO_QUOTA_CHANGE; + + if (!gfs2_alloc_get(ip)) + return -ENOMEM; + + error = gfs2_quota_lock(ip, nuid, ngid); + if (error) + goto out_alloc; + + if (ouid != NO_QUOTA_CHANGE || ogid != NO_QUOTA_CHANGE) { + error = gfs2_quota_check(ip, nuid, ngid); + if (error) + goto out_gunlock_q; + } + + error = gfs2_trans_begin(sdp, RES_DINODE + 2 * RES_QUOTA, 0); + if (error) + goto out_gunlock_q; + + error = gfs2_setattr_simple(ip, attr); + if (error) + goto out_end_trans; + + if (ouid != NO_QUOTA_CHANGE || ogid != NO_QUOTA_CHANGE) { + u64 blocks = gfs2_get_inode_blocks(&ip->i_inode); + gfs2_quota_change(ip, -blocks, ouid, ogid); + gfs2_quota_change(ip, blocks, nuid, ngid); + } + +out_end_trans: + gfs2_trans_end(sdp); +out_gunlock_q: + gfs2_quota_unlock(ip); +out_alloc: + gfs2_alloc_put(ip); + return error; +} + +/** + * gfs2_setattr - Change attributes on an inode + * @dentry: The dentry which is changing + * @attr: The structure describing the change + * + * The VFS layer wants to change one or more of an inodes attributes. Write + * that change out to disk. + * + * Returns: errno + */ + +static int gfs2_setattr(struct dentry *dentry, struct iattr *attr) +{ + struct inode *inode = dentry->d_inode; + struct gfs2_inode *ip = GFS2_I(inode); + struct gfs2_holder i_gh; + int error; + + error = gfs2_glock_nq_init(ip->i_gl, LM_ST_EXCLUSIVE, 0, &i_gh); + if (error) + return error; + + error = -EPERM; + if (IS_IMMUTABLE(inode) || IS_APPEND(inode)) + goto out; + + error = inode_change_ok(inode, attr); + if (error) + goto out; + + if (attr->ia_valid & ATTR_SIZE) + error = gfs2_setattr_size(inode, attr->ia_size); + else if (attr->ia_valid & (ATTR_UID | ATTR_GID)) + error = setattr_chown(inode, attr); + else if ((attr->ia_valid & ATTR_MODE) && IS_POSIXACL(inode)) + error = gfs2_acl_chmod(ip, attr); + else + error = gfs2_setattr_simple(ip, attr); + +out: + gfs2_glock_dq_uninit(&i_gh); + if (!error) + mark_inode_dirty(inode); + return error; +} + +/** + * gfs2_getattr - Read out an inode's attributes + * @mnt: The vfsmount the inode is being accessed from + * @dentry: The dentry to stat + * @stat: The inode's stats + * + * This may be called from the VFS directly, or from within GFS2 with the + * inode locked, so we look to see if the glock is already locked and only + * lock the glock if its not already been done. Note that its the NFS + * readdirplus operation which causes this to be called (from filldir) + * with the glock already held. + * + * Returns: errno + */ + +static int gfs2_getattr(struct vfsmount *mnt, struct dentry *dentry, + struct kstat *stat) +{ + struct inode *inode = dentry->d_inode; + struct gfs2_inode *ip = GFS2_I(inode); + struct gfs2_holder gh; + int error; + int unlock = 0; + + if (gfs2_glock_is_locked_by_me(ip->i_gl) == NULL) { + error = gfs2_glock_nq_init(ip->i_gl, LM_ST_SHARED, LM_FLAG_ANY, &gh); + if (error) + return error; + unlock = 1; + } + + generic_fillattr(inode, stat); + if (unlock) + gfs2_glock_dq_uninit(&gh); + + return 0; +} + +static int gfs2_setxattr(struct dentry *dentry, const char *name, + const void *data, size_t size, int flags) +{ + struct inode *inode = dentry->d_inode; + struct gfs2_inode *ip = GFS2_I(inode); + struct gfs2_holder gh; + int ret; + + gfs2_holder_init(ip->i_gl, LM_ST_EXCLUSIVE, 0, &gh); + ret = gfs2_glock_nq(&gh); + if (ret == 0) { + ret = generic_setxattr(dentry, name, data, size, flags); + gfs2_glock_dq(&gh); + } + gfs2_holder_uninit(&gh); + return ret; +} + +static ssize_t gfs2_getxattr(struct dentry *dentry, const char *name, + void *data, size_t size) +{ + struct inode *inode = dentry->d_inode; + struct gfs2_inode *ip = GFS2_I(inode); + struct gfs2_holder gh; + int ret; + + gfs2_holder_init(ip->i_gl, LM_ST_SHARED, LM_FLAG_ANY, &gh); + ret = gfs2_glock_nq(&gh); + if (ret == 0) { + ret = generic_getxattr(dentry, name, data, size); + gfs2_glock_dq(&gh); + } + gfs2_holder_uninit(&gh); + return ret; +} + +static int gfs2_removexattr(struct dentry *dentry, const char *name) +{ + struct inode *inode = dentry->d_inode; + struct gfs2_inode *ip = GFS2_I(inode); + struct gfs2_holder gh; + int ret; + + gfs2_holder_init(ip->i_gl, LM_ST_EXCLUSIVE, 0, &gh); + ret = gfs2_glock_nq(&gh); + if (ret == 0) { + ret = generic_removexattr(dentry, name); + gfs2_glock_dq(&gh); + } + gfs2_holder_uninit(&gh); + return ret; +} + +static int gfs2_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo, + u64 start, u64 len) +{ + struct gfs2_inode *ip = GFS2_I(inode); + struct gfs2_holder gh; + int ret; + + ret = fiemap_check_flags(fieinfo, FIEMAP_FLAG_SYNC); + if (ret) + return ret; + + mutex_lock(&inode->i_mutex); + + ret = gfs2_glock_nq_init(ip->i_gl, LM_ST_SHARED, 0, &gh); + if (ret) + goto out; + + if (gfs2_is_stuffed(ip)) { + u64 phys = ip->i_no_addr << inode->i_blkbits; + u64 size = i_size_read(inode); + u32 flags = FIEMAP_EXTENT_LAST|FIEMAP_EXTENT_NOT_ALIGNED| + FIEMAP_EXTENT_DATA_INLINE; + phys += sizeof(struct gfs2_dinode); + phys += start; + if (start + len > size) + len = size - start; + if (start < size) + ret = fiemap_fill_next_extent(fieinfo, start, phys, + len, flags); + if (ret == 1) + ret = 0; + } else { + ret = __generic_block_fiemap(inode, fieinfo, start, len, + gfs2_block_map); + } + + gfs2_glock_dq_uninit(&gh); +out: + mutex_unlock(&inode->i_mutex); + return ret; +} + +const struct inode_operations gfs2_file_iops = { + .permission = gfs2_permission, + .setattr = gfs2_setattr, + .getattr = gfs2_getattr, + .setxattr = gfs2_setxattr, + .getxattr = gfs2_getxattr, + .listxattr = gfs2_listxattr, + .removexattr = gfs2_removexattr, + .fiemap = gfs2_fiemap, +}; + +const struct inode_operations gfs2_dir_iops = { + .create = gfs2_create, + .lookup = gfs2_lookup, + .link = gfs2_link, + .unlink = gfs2_unlink, + .symlink = gfs2_symlink, + .mkdir = gfs2_mkdir, + .rmdir = gfs2_unlink, + .mknod = gfs2_mknod, + .rename = gfs2_rename, + .permission = gfs2_permission, + .setattr = gfs2_setattr, + .getattr = gfs2_getattr, + .setxattr = gfs2_setxattr, + .getxattr = gfs2_getxattr, + .listxattr = gfs2_listxattr, + .removexattr = gfs2_removexattr, + .fiemap = gfs2_fiemap, +}; + +const struct inode_operations gfs2_symlink_iops = { + .readlink = generic_readlink, + .follow_link = gfs2_follow_link, + .put_link = gfs2_put_link, + .permission = gfs2_permission, + .setattr = gfs2_setattr, + .getattr = gfs2_getattr, + .setxattr = gfs2_setxattr, + .getxattr = gfs2_getxattr, + .listxattr = gfs2_listxattr, + .removexattr = gfs2_removexattr, + .fiemap = gfs2_fiemap, +}; + diff --git a/fs/gfs2/ops_inode.c b/fs/gfs2/ops_inode.c deleted file mode 100644 index a783a7a..0000000 --- a/fs/gfs2/ops_inode.c +++ /dev/null @@ -1,1990 +0,0 @@ -/* - * Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved. - * Copyright (C) 2004-2006 Red Hat, Inc. All rights reserved. - * - * This copyrighted material is made available to anyone wishing to use, - * modify, copy, or redistribute it subject to the terms and conditions - * of the GNU General Public License version 2. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "gfs2.h" -#include "incore.h" -#include "acl.h" -#include "bmap.h" -#include "dir.h" -#include "xattr.h" -#include "glock.h" -#include "inode.h" -#include "meta_io.h" -#include "quota.h" -#include "rgrp.h" -#include "trans.h" -#include "util.h" -#include "super.h" -#include "glops.h" - -struct gfs2_skip_data { - u64 no_addr; - int skipped; - int non_block; -}; - -static int iget_test(struct inode *inode, void *opaque) -{ - struct gfs2_inode *ip = GFS2_I(inode); - struct gfs2_skip_data *data = opaque; - - if (ip->i_no_addr == data->no_addr) { - if (data->non_block && - inode->i_state & (I_FREEING|I_CLEAR|I_WILL_FREE)) { - data->skipped = 1; - return 0; - } - return 1; - } - return 0; -} - -static int iget_set(struct inode *inode, void *opaque) -{ - struct gfs2_inode *ip = GFS2_I(inode); - struct gfs2_skip_data *data = opaque; - - if (data->skipped) - return -ENOENT; - inode->i_ino = (unsigned long)(data->no_addr); - ip->i_no_addr = data->no_addr; - return 0; -} - -struct inode *gfs2_ilookup(struct super_block *sb, u64 no_addr, int non_block) -{ - unsigned long hash = (unsigned long)no_addr; - struct gfs2_skip_data data; - - data.no_addr = no_addr; - data.skipped = 0; - data.non_block = non_block; - return ilookup5(sb, hash, iget_test, &data); -} - -static struct inode *gfs2_iget(struct super_block *sb, u64 no_addr, - int non_block) -{ - struct gfs2_skip_data data; - unsigned long hash = (unsigned long)no_addr; - - data.no_addr = no_addr; - data.skipped = 0; - data.non_block = non_block; - return iget5_locked(sb, hash, iget_test, iget_set, &data); -} - -/** - * gfs2_set_iop - Sets inode operations - * @inode: The inode with correct i_mode filled in - * - * GFS2 lookup code fills in vfs inode contents based on info obtained - * from directory entry inside gfs2_inode_lookup(). - */ - -static void gfs2_set_iop(struct inode *inode) -{ - struct gfs2_sbd *sdp = GFS2_SB(inode); - umode_t mode = inode->i_mode; - - if (S_ISREG(mode)) { - inode->i_op = &gfs2_file_iops; - if (gfs2_localflocks(sdp)) - inode->i_fop = &gfs2_file_fops_nolock; - else - inode->i_fop = &gfs2_file_fops; - } else if (S_ISDIR(mode)) { - inode->i_op = &gfs2_dir_iops; - if (gfs2_localflocks(sdp)) - inode->i_fop = &gfs2_dir_fops_nolock; - else - inode->i_fop = &gfs2_dir_fops; - } else if (S_ISLNK(mode)) { - inode->i_op = &gfs2_symlink_iops; - } else { - inode->i_op = &gfs2_file_iops; - init_special_inode(inode, inode->i_mode, inode->i_rdev); - } -} - -/** - * gfs2_inode_lookup - Lookup an inode - * @sb: The super block - * @no_addr: The inode number - * @type: The type of the inode - * non_block: Can we block on inodes that are being freed? - * - * Returns: A VFS inode, or an error - */ - -struct inode *gfs2_inode_lookup(struct super_block *sb, unsigned int type, - u64 no_addr, u64 no_formal_ino, int non_block) -{ - struct inode *inode; - struct gfs2_inode *ip; - struct gfs2_glock *io_gl = NULL; - int error; - - inode = gfs2_iget(sb, no_addr, non_block); - ip = GFS2_I(inode); - - if (!inode) - return ERR_PTR(-ENOBUFS); - - if (inode->i_state & I_NEW) { - struct gfs2_sbd *sdp = GFS2_SB(inode); - ip->i_no_formal_ino = no_formal_ino; - - error = gfs2_glock_get(sdp, no_addr, &gfs2_inode_glops, CREATE, &ip->i_gl); - if (unlikely(error)) - goto fail; - ip->i_gl->gl_object = ip; - - error = gfs2_glock_get(sdp, no_addr, &gfs2_iopen_glops, CREATE, &io_gl); - if (unlikely(error)) - goto fail_put; - - set_bit(GIF_INVALID, &ip->i_flags); - error = gfs2_glock_nq_init(io_gl, LM_ST_SHARED, GL_EXACT, &ip->i_iopen_gh); - if (unlikely(error)) - goto fail_iopen; - - ip->i_iopen_gh.gh_gl->gl_object = ip; - gfs2_glock_put(io_gl); - io_gl = NULL; - - if (type == DT_UNKNOWN) { - /* Inode glock must be locked already */ - error = gfs2_inode_refresh(GFS2_I(inode)); - if (error) - goto fail_refresh; - } else { - inode->i_mode = DT2IF(type); - } - - gfs2_set_iop(inode); - unlock_new_inode(inode); - } - - return inode; - -fail_refresh: - ip->i_iopen_gh.gh_gl->gl_object = NULL; - gfs2_glock_dq_uninit(&ip->i_iopen_gh); -fail_iopen: - if (io_gl) - gfs2_glock_put(io_gl); -fail_put: - ip->i_gl->gl_object = NULL; - gfs2_glock_put(ip->i_gl); -fail: - iget_failed(inode); - return ERR_PTR(error); -} - -struct inode *gfs2_lookup_by_inum(struct gfs2_sbd *sdp, u64 no_addr, - u64 *no_formal_ino, unsigned int blktype) -{ - struct super_block *sb = sdp->sd_vfs; - struct gfs2_holder i_gh; - struct inode *inode = NULL; - int error; - - /* Must not read in block until block type is verified */ - error = gfs2_glock_nq_num(sdp, no_addr, &gfs2_inode_glops, - LM_ST_EXCLUSIVE, GL_SKIP, &i_gh); - if (error) - return ERR_PTR(error); - - error = gfs2_check_blk_type(sdp, no_addr, blktype); - if (error) - goto fail; - - inode = gfs2_inode_lookup(sb, DT_UNKNOWN, no_addr, 0, 1); - if (IS_ERR(inode)) - goto fail; - - /* Two extra checks for NFS only */ - if (no_formal_ino) { - error = -ESTALE; - if (GFS2_I(inode)->i_no_formal_ino != *no_formal_ino) - goto fail_iput; - - error = -EIO; - if (GFS2_I(inode)->i_diskflags & GFS2_DIF_SYSTEM) - goto fail_iput; - - error = 0; - } - -fail: - gfs2_glock_dq_uninit(&i_gh); - return error ? ERR_PTR(error) : inode; -fail_iput: - iput(inode); - goto fail; -} - - -struct inode *gfs2_lookup_simple(struct inode *dip, const char *name) -{ - struct qstr qstr; - struct inode *inode; - gfs2_str2qstr(&qstr, name); - inode = gfs2_lookupi(dip, &qstr, 1); - /* gfs2_lookupi has inconsistent callers: vfs - * related routines expect NULL for no entry found, - * gfs2_lookup_simple callers expect ENOENT - * and do not check for NULL. - */ - if (inode == NULL) - return ERR_PTR(-ENOENT); - else - return inode; -} - - -/** - * gfs2_lookupi - Look up a filename in a directory and return its inode - * @d_gh: An initialized holder for the directory glock - * @name: The name of the inode to look for - * @is_root: If 1, ignore the caller's permissions - * @i_gh: An uninitialized holder for the new inode glock - * - * This can be called via the VFS filldir function when NFS is doing - * a readdirplus and the inode which its intending to stat isn't - * already in cache. In this case we must not take the directory glock - * again, since the readdir call will have already taken that lock. - * - * Returns: errno - */ - -struct inode *gfs2_lookupi(struct inode *dir, const struct qstr *name, - int is_root) -{ - struct super_block *sb = dir->i_sb; - struct gfs2_inode *dip = GFS2_I(dir); - struct gfs2_holder d_gh; - int error = 0; - struct inode *inode = NULL; - int unlock = 0; - - if (!name->len || name->len > GFS2_FNAMESIZE) - return ERR_PTR(-ENAMETOOLONG); - - if ((name->len == 1 && memcmp(name->name, ".", 1) == 0) || - (name->len == 2 && memcmp(name->name, "..", 2) == 0 && - dir == sb->s_root->d_inode)) { - igrab(dir); - return dir; - } - - if (gfs2_glock_is_locked_by_me(dip->i_gl) == NULL) { - error = gfs2_glock_nq_init(dip->i_gl, LM_ST_SHARED, 0, &d_gh); - if (error) - return ERR_PTR(error); - unlock = 1; - } - - if (!is_root) { - error = gfs2_permission(dir, MAY_EXEC, 0); - if (error) - goto out; - } - - inode = gfs2_dir_search(dir, name); - if (IS_ERR(inode)) - error = PTR_ERR(inode); -out: - if (unlock) - gfs2_glock_dq_uninit(&d_gh); - if (error == -ENOENT) - return NULL; - return inode ? inode : ERR_PTR(error); -} - -/** - * create_ok - OK to create a new on-disk inode here? - * @dip: Directory in which dinode is to be created - * @name: Name of new dinode - * @mode: - * - * Returns: errno - */ - -static int create_ok(struct gfs2_inode *dip, const struct qstr *name, - unsigned int mode) -{ - int error; - - error = gfs2_permission(&dip->i_inode, MAY_WRITE | MAY_EXEC, 0); - if (error) - return error; - - /* Don't create entries in an unlinked directory */ - if (!dip->i_inode.i_nlink) - return -ENOENT; - - error = gfs2_dir_check(&dip->i_inode, name, NULL); - switch (error) { - case -ENOENT: - error = 0; - break; - case 0: - return -EEXIST; - default: - return error; - } - - if (dip->i_entries == (u32)-1) - return -EFBIG; - if (S_ISDIR(mode) && dip->i_inode.i_nlink == (u32)-1) - return -EMLINK; - - return 0; -} - -static void munge_mode_uid_gid(struct gfs2_inode *dip, unsigned int *mode, - unsigned int *uid, unsigned int *gid) -{ - if (GFS2_SB(&dip->i_inode)->sd_args.ar_suiddir && - (dip->i_inode.i_mode & S_ISUID) && dip->i_inode.i_uid) { - if (S_ISDIR(*mode)) - *mode |= S_ISUID; - else if (dip->i_inode.i_uid != current_fsuid()) - *mode &= ~07111; - *uid = dip->i_inode.i_uid; - } else - *uid = current_fsuid(); - - if (dip->i_inode.i_mode & S_ISGID) { - if (S_ISDIR(*mode)) - *mode |= S_ISGID; - *gid = dip->i_inode.i_gid; - } else - *gid = current_fsgid(); -} - -static int alloc_dinode(struct gfs2_inode *dip, u64 *no_addr, u64 *generation) -{ - struct gfs2_sbd *sdp = GFS2_SB(&dip->i_inode); - int error; - - if (gfs2_alloc_get(dip) == NULL) - return -ENOMEM; - - dip->i_alloc->al_requested = RES_DINODE; - error = gfs2_inplace_reserve(dip); - if (error) - goto out; - - error = gfs2_trans_begin(sdp, RES_RG_BIT + RES_STATFS, 0); - if (error) - goto out_ipreserv; - - error = gfs2_alloc_di(dip, no_addr, generation); - - gfs2_trans_end(sdp); - -out_ipreserv: - gfs2_inplace_release(dip); -out: - gfs2_alloc_put(dip); - return error; -} - -/** - * init_dinode - Fill in a new dinode structure - * @dip: the directory this inode is being created in - * @gl: The glock covering the new inode - * @inum: the inode number - * @mode: the file permissions - * @uid: - * @gid: - * - */ - -static void init_dinode(struct gfs2_inode *dip, struct gfs2_glock *gl, - const struct gfs2_inum_host *inum, unsigned int mode, - unsigned int uid, unsigned int gid, - const u64 *generation, dev_t dev, struct buffer_head **bhp) -{ - struct gfs2_sbd *sdp = GFS2_SB(&dip->i_inode); - struct gfs2_dinode *di; - struct buffer_head *dibh; - struct timespec tv = CURRENT_TIME; - - dibh = gfs2_meta_new(gl, inum->no_addr); - gfs2_trans_add_bh(gl, dibh, 1); - gfs2_metatype_set(dibh, GFS2_METATYPE_DI, GFS2_FORMAT_DI); - gfs2_buffer_clear_tail(dibh, sizeof(struct gfs2_dinode)); - di = (struct gfs2_dinode *)dibh->b_data; - - di->di_num.no_formal_ino = cpu_to_be64(inum->no_formal_ino); - di->di_num.no_addr = cpu_to_be64(inum->no_addr); - di->di_mode = cpu_to_be32(mode); - di->di_uid = cpu_to_be32(uid); - di->di_gid = cpu_to_be32(gid); - di->di_nlink = 0; - di->di_size = 0; - di->di_blocks = cpu_to_be64(1); - di->di_atime = di->di_mtime = di->di_ctime = cpu_to_be64(tv.tv_sec); - di->di_major = cpu_to_be32(MAJOR(dev)); - di->di_minor = cpu_to_be32(MINOR(dev)); - di->di_goal_meta = di->di_goal_data = cpu_to_be64(inum->no_addr); - di->di_generation = cpu_to_be64(*generation); - di->di_flags = 0; - - if (S_ISREG(mode)) { - if ((dip->i_diskflags & GFS2_DIF_INHERIT_JDATA) || - gfs2_tune_get(sdp, gt_new_files_jdata)) - di->di_flags |= cpu_to_be32(GFS2_DIF_JDATA); - } else if (S_ISDIR(mode)) { - di->di_flags |= cpu_to_be32(dip->i_diskflags & - GFS2_DIF_INHERIT_JDATA); - } - - di->__pad1 = 0; - di->di_payload_format = cpu_to_be32(S_ISDIR(mode) ? GFS2_FORMAT_DE : 0); - di->di_height = 0; - di->__pad2 = 0; - di->__pad3 = 0; - di->di_depth = 0; - di->di_entries = 0; - memset(&di->__pad4, 0, sizeof(di->__pad4)); - di->di_eattr = 0; - di->di_atime_nsec = cpu_to_be32(tv.tv_nsec); - di->di_mtime_nsec = cpu_to_be32(tv.tv_nsec); - di->di_ctime_nsec = cpu_to_be32(tv.tv_nsec); - memset(&di->di_reserved, 0, sizeof(di->di_reserved)); - - set_buffer_uptodate(dibh); - - *bhp = dibh; -} - -static int make_dinode(struct gfs2_inode *dip, struct gfs2_glock *gl, - unsigned int mode, const struct gfs2_inum_host *inum, - const u64 *generation, dev_t dev, struct buffer_head **bhp) -{ - struct gfs2_sbd *sdp = GFS2_SB(&dip->i_inode); - unsigned int uid, gid; - int error; - - munge_mode_uid_gid(dip, &mode, &uid, &gid); - if (!gfs2_alloc_get(dip)) - return -ENOMEM; - - error = gfs2_quota_lock(dip, uid, gid); - if (error) - goto out; - - error = gfs2_quota_check(dip, uid, gid); - if (error) - goto out_quota; - - error = gfs2_trans_begin(sdp, RES_DINODE + RES_QUOTA, 0); - if (error) - goto out_quota; - - init_dinode(dip, gl, inum, mode, uid, gid, generation, dev, bhp); - gfs2_quota_change(dip, +1, uid, gid); - gfs2_trans_end(sdp); - -out_quota: - gfs2_quota_unlock(dip); -out: - gfs2_alloc_put(dip); - return error; -} - -static int link_dinode(struct gfs2_inode *dip, const struct qstr *name, - struct gfs2_inode *ip) -{ - struct gfs2_sbd *sdp = GFS2_SB(&dip->i_inode); - struct gfs2_alloc *al; - int alloc_required; - struct buffer_head *dibh; - int error; - - al = gfs2_alloc_get(dip); - if (!al) - return -ENOMEM; - - error = gfs2_quota_lock(dip, NO_QUOTA_CHANGE, NO_QUOTA_CHANGE); - if (error) - goto fail; - - error = alloc_required = gfs2_diradd_alloc_required(&dip->i_inode, name); - if (alloc_required < 0) - goto fail_quota_locks; - if (alloc_required) { - error = gfs2_quota_check(dip, dip->i_inode.i_uid, dip->i_inode.i_gid); - if (error) - goto fail_quota_locks; - - al->al_requested = sdp->sd_max_dirres; - - error = gfs2_inplace_reserve(dip); - if (error) - goto fail_quota_locks; - - error = gfs2_trans_begin(sdp, sdp->sd_max_dirres + - al->al_rgd->rd_length + - 2 * RES_DINODE + - RES_STATFS + RES_QUOTA, 0); - if (error) - goto fail_ipreserv; - } else { - error = gfs2_trans_begin(sdp, RES_LEAF + 2 * RES_DINODE, 0); - if (error) - goto fail_quota_locks; - } - - error = gfs2_dir_add(&dip->i_inode, name, ip); - if (error) - goto fail_end_trans; - - error = gfs2_meta_inode_buffer(ip, &dibh); - if (error) - goto fail_end_trans; - ip->i_inode.i_nlink = 1; - gfs2_trans_add_bh(ip->i_gl, dibh, 1); - gfs2_dinode_out(ip, dibh->b_data); - brelse(dibh); - return 0; - -fail_end_trans: - gfs2_trans_end(sdp); - -fail_ipreserv: - if (dip->i_alloc->al_rgd) - gfs2_inplace_release(dip); - -fail_quota_locks: - gfs2_quota_unlock(dip); - -fail: - gfs2_alloc_put(dip); - return error; -} - -static int gfs2_security_init(struct gfs2_inode *dip, struct gfs2_inode *ip, - const struct qstr *qstr) -{ - int err; - size_t len; - void *value; - char *name; - - err = security_inode_init_security(&ip->i_inode, &dip->i_inode, qstr, - &name, &value, &len); - - if (err) { - if (err == -EOPNOTSUPP) - return 0; - return err; - } - - err = __gfs2_xattr_set(&ip->i_inode, name, value, len, 0, - GFS2_EATYPE_SECURITY); - kfree(value); - kfree(name); - - return err; -} - -/** - * gfs2_createi - Create a new inode - * @ghs: An array of two holders - * @name: The name of the new file - * @mode: the permissions on the new inode - * - * @ghs[0] is an initialized holder for the directory - * @ghs[1] is the holder for the inode lock - * - * If the return value is not NULL, the glocks on both the directory and the new - * file are held. A transaction has been started and an inplace reservation - * is held, as well. - * - * Returns: An inode - */ - -struct inode *gfs2_createi(struct gfs2_holder *ghs, const struct qstr *name, - unsigned int mode, dev_t dev) -{ - struct inode *inode = NULL; - struct gfs2_inode *dip = ghs->gh_gl->gl_object; - struct inode *dir = &dip->i_inode; - struct gfs2_sbd *sdp = GFS2_SB(&dip->i_inode); - struct gfs2_inum_host inum = { .no_addr = 0, .no_formal_ino = 0 }; - int error; - u64 generation; - struct buffer_head *bh = NULL; - - if (!name->len || name->len > GFS2_FNAMESIZE) - return ERR_PTR(-ENAMETOOLONG); - - gfs2_holder_reinit(LM_ST_EXCLUSIVE, 0, ghs); - error = gfs2_glock_nq(ghs); - if (error) - goto fail; - - error = create_ok(dip, name, mode); - if (error) - goto fail_gunlock; - - error = alloc_dinode(dip, &inum.no_addr, &generation); - if (error) - goto fail_gunlock; - inum.no_formal_ino = generation; - - error = gfs2_glock_nq_num(sdp, inum.no_addr, &gfs2_inode_glops, - LM_ST_EXCLUSIVE, GL_SKIP, ghs + 1); - if (error) - goto fail_gunlock; - - error = make_dinode(dip, ghs[1].gh_gl, mode, &inum, &generation, dev, &bh); - if (error) - goto fail_gunlock2; - - inode = gfs2_inode_lookup(dir->i_sb, IF2DT(mode), inum.no_addr, - inum.no_formal_ino, 0); - if (IS_ERR(inode)) - goto fail_gunlock2; - - error = gfs2_inode_refresh(GFS2_I(inode)); - if (error) - goto fail_gunlock2; - - error = gfs2_acl_create(dip, inode); - if (error) - goto fail_gunlock2; - - error = gfs2_security_init(dip, GFS2_I(inode), name); - if (error) - goto fail_gunlock2; - - error = link_dinode(dip, name, GFS2_I(inode)); - if (error) - goto fail_gunlock2; - - if (bh) - brelse(bh); - return inode; - -fail_gunlock2: - gfs2_glock_dq_uninit(ghs + 1); - if (inode && !IS_ERR(inode)) - iput(inode); -fail_gunlock: - gfs2_glock_dq(ghs); -fail: - if (bh) - brelse(bh); - return ERR_PTR(error); -} -/** - * gfs2_create - Create a file - * @dir: The directory in which to create the file - * @dentry: The dentry of the new file - * @mode: The mode of the new file - * - * Returns: errno - */ - -static int gfs2_create(struct inode *dir, struct dentry *dentry, - int mode, struct nameidata *nd) -{ - struct gfs2_inode *dip = GFS2_I(dir); - struct gfs2_sbd *sdp = GFS2_SB(dir); - struct gfs2_holder ghs[2]; - struct inode *inode; - - gfs2_holder_init(dip->i_gl, 0, 0, ghs); - - for (;;) { - inode = gfs2_createi(ghs, &dentry->d_name, S_IFREG | mode, 0); - if (!IS_ERR(inode)) { - gfs2_trans_end(sdp); - if (dip->i_alloc->al_rgd) - gfs2_inplace_release(dip); - gfs2_quota_unlock(dip); - gfs2_alloc_put(dip); - gfs2_glock_dq_uninit_m(2, ghs); - mark_inode_dirty(inode); - break; - } else if (PTR_ERR(inode) != -EEXIST || - (nd && nd->flags & LOOKUP_EXCL)) { - gfs2_holder_uninit(ghs); - return PTR_ERR(inode); - } - - inode = gfs2_lookupi(dir, &dentry->d_name, 0); - if (inode) { - if (!IS_ERR(inode)) { - gfs2_holder_uninit(ghs); - break; - } else { - gfs2_holder_uninit(ghs); - return PTR_ERR(inode); - } - } - } - - d_instantiate(dentry, inode); - - return 0; -} - -/** - * gfs2_lookup - Look up a filename in a directory and return its inode - * @dir: The directory inode - * @dentry: The dentry of the new inode - * @nd: passed from Linux VFS, ignored by us - * - * Called by the VFS layer. Lock dir and call gfs2_lookupi() - * - * Returns: errno - */ - -static struct dentry *gfs2_lookup(struct inode *dir, struct dentry *dentry, - struct nameidata *nd) -{ - struct inode *inode = NULL; - - inode = gfs2_lookupi(dir, &dentry->d_name, 0); - if (inode && IS_ERR(inode)) - return ERR_CAST(inode); - - if (inode) { - struct gfs2_glock *gl = GFS2_I(inode)->i_gl; - struct gfs2_holder gh; - int error; - error = gfs2_glock_nq_init(gl, LM_ST_SHARED, LM_FLAG_ANY, &gh); - if (error) { - iput(inode); - return ERR_PTR(error); - } - gfs2_glock_dq_uninit(&gh); - return d_splice_alias(inode, dentry); - } - d_add(dentry, inode); - - return NULL; -} - -/** - * gfs2_link - Link to a file - * @old_dentry: The inode to link - * @dir: Add link to this directory - * @dentry: The name of the link - * - * Link the inode in "old_dentry" into the directory "dir" with the - * name in "dentry". - * - * Returns: errno - */ - -static int gfs2_link(struct dentry *old_dentry, struct inode *dir, - struct dentry *dentry) -{ - struct gfs2_inode *dip = GFS2_I(dir); - struct gfs2_sbd *sdp = GFS2_SB(dir); - struct inode *inode = old_dentry->d_inode; - struct gfs2_inode *ip = GFS2_I(inode); - struct gfs2_holder ghs[2]; - struct buffer_head *dibh; - int alloc_required; - int error; - - if (S_ISDIR(inode->i_mode)) - return -EPERM; - - gfs2_holder_init(dip->i_gl, LM_ST_EXCLUSIVE, 0, ghs); - gfs2_holder_init(ip->i_gl, LM_ST_EXCLUSIVE, 0, ghs + 1); - - error = gfs2_glock_nq(ghs); /* parent */ - if (error) - goto out_parent; - - error = gfs2_glock_nq(ghs + 1); /* child */ - if (error) - goto out_child; - - error = -ENOENT; - if (inode->i_nlink == 0) - goto out_gunlock; - - error = gfs2_permission(dir, MAY_WRITE | MAY_EXEC, 0); - if (error) - goto out_gunlock; - - error = gfs2_dir_check(dir, &dentry->d_name, NULL); - switch (error) { - case -ENOENT: - break; - case 0: - error = -EEXIST; - default: - goto out_gunlock; - } - - error = -EINVAL; - if (!dip->i_inode.i_nlink) - goto out_gunlock; - error = -EFBIG; - if (dip->i_entries == (u32)-1) - goto out_gunlock; - error = -EPERM; - if (IS_IMMUTABLE(inode) || IS_APPEND(inode)) - goto out_gunlock; - error = -EINVAL; - if (!ip->i_inode.i_nlink) - goto out_gunlock; - error = -EMLINK; - if (ip->i_inode.i_nlink == (u32)-1) - goto out_gunlock; - - alloc_required = error = gfs2_diradd_alloc_required(dir, &dentry->d_name); - if (error < 0) - goto out_gunlock; - error = 0; - - if (alloc_required) { - struct gfs2_alloc *al = gfs2_alloc_get(dip); - if (!al) { - error = -ENOMEM; - goto out_gunlock; - } - - error = gfs2_quota_lock_check(dip); - if (error) - goto out_alloc; - - al->al_requested = sdp->sd_max_dirres; - - error = gfs2_inplace_reserve(dip); - if (error) - goto out_gunlock_q; - - error = gfs2_trans_begin(sdp, sdp->sd_max_dirres + - gfs2_rg_blocks(al) + - 2 * RES_DINODE + RES_STATFS + - RES_QUOTA, 0); - if (error) - goto out_ipres; - } else { - error = gfs2_trans_begin(sdp, 2 * RES_DINODE + RES_LEAF, 0); - if (error) - goto out_ipres; - } - - error = gfs2_meta_inode_buffer(ip, &dibh); - if (error) - goto out_end_trans; - - error = gfs2_dir_add(dir, &dentry->d_name, ip); - if (error) - goto out_brelse; - - gfs2_trans_add_bh(ip->i_gl, dibh, 1); - inc_nlink(&ip->i_inode); - ip->i_inode.i_ctime = CURRENT_TIME; - gfs2_dinode_out(ip, dibh->b_data); - mark_inode_dirty(&ip->i_inode); - -out_brelse: - brelse(dibh); -out_end_trans: - gfs2_trans_end(sdp); -out_ipres: - if (alloc_required) - gfs2_inplace_release(dip); -out_gunlock_q: - if (alloc_required) - gfs2_quota_unlock(dip); -out_alloc: - if (alloc_required) - gfs2_alloc_put(dip); -out_gunlock: - gfs2_glock_dq(ghs + 1); -out_child: - gfs2_glock_dq(ghs); -out_parent: - gfs2_holder_uninit(ghs); - gfs2_holder_uninit(ghs + 1); - if (!error) { - ihold(inode); - d_instantiate(dentry, inode); - mark_inode_dirty(inode); - } - return error; -} - -/* - * gfs2_unlink_ok - check to see that a inode is still in a directory - * @dip: the directory - * @name: the name of the file - * @ip: the inode - * - * Assumes that the lock on (at least) @dip is held. - * - * Returns: 0 if the parent/child relationship is correct, errno if it isn't - */ - -static int gfs2_unlink_ok(struct gfs2_inode *dip, const struct qstr *name, - const struct gfs2_inode *ip) -{ - int error; - - if (IS_IMMUTABLE(&ip->i_inode) || IS_APPEND(&ip->i_inode)) - return -EPERM; - - if ((dip->i_inode.i_mode & S_ISVTX) && - dip->i_inode.i_uid != current_fsuid() && - ip->i_inode.i_uid != current_fsuid() && !capable(CAP_FOWNER)) - return -EPERM; - - if (IS_APPEND(&dip->i_inode)) - return -EPERM; - - error = gfs2_permission(&dip->i_inode, MAY_WRITE | MAY_EXEC, 0); - if (error) - return error; - - error = gfs2_dir_check(&dip->i_inode, name, ip); - if (error) - return error; - - return 0; -} - -/** - * gfs2_unlink_inode - Removes an inode from its parent dir and unlinks it - * @dip: The parent directory - * @name: The name of the entry in the parent directory - * @bh: The inode buffer for the inode to be removed - * @inode: The inode to be removed - * - * Called with all the locks and in a transaction. This will only be - * called for a directory after it has been checked to ensure it is empty. - * - * Returns: 0 on success, or an error - */ - -static int gfs2_unlink_inode(struct gfs2_inode *dip, - const struct dentry *dentry, - struct buffer_head *bh) -{ - struct inode *inode = dentry->d_inode; - struct gfs2_inode *ip = GFS2_I(inode); - int error; - - error = gfs2_dir_del(dip, dentry); - if (error) - return error; - - ip->i_entries = 0; - inode->i_ctime = CURRENT_TIME; - if (S_ISDIR(inode->i_mode)) - clear_nlink(inode); - else - drop_nlink(inode); - gfs2_trans_add_bh(ip->i_gl, bh, 1); - gfs2_dinode_out(ip, bh->b_data); - mark_inode_dirty(inode); - if (inode->i_nlink == 0) - gfs2_unlink_di(inode); - return 0; -} - - -/** - * gfs2_unlink - Unlink an inode (this does rmdir as well) - * @dir: The inode of the directory containing the inode to unlink - * @dentry: The file itself - * - * This routine uses the type of the inode as a flag to figure out - * whether this is an unlink or an rmdir. - * - * Returns: errno - */ - -static int gfs2_unlink(struct inode *dir, struct dentry *dentry) -{ - struct gfs2_inode *dip = GFS2_I(dir); - struct gfs2_sbd *sdp = GFS2_SB(dir); - struct inode *inode = dentry->d_inode; - struct gfs2_inode *ip = GFS2_I(inode); - struct buffer_head *bh; - struct gfs2_holder ghs[3]; - struct gfs2_rgrpd *rgd; - struct gfs2_holder ri_gh; - int error; - - error = gfs2_rindex_hold(sdp, &ri_gh); - if (error) - return error; - - gfs2_holder_init(dip->i_gl, LM_ST_EXCLUSIVE, 0, ghs); - gfs2_holder_init(ip->i_gl, LM_ST_EXCLUSIVE, 0, ghs + 1); - - rgd = gfs2_blk2rgrpd(sdp, ip->i_no_addr); - gfs2_holder_init(rgd->rd_gl, LM_ST_EXCLUSIVE, 0, ghs + 2); - - - error = gfs2_glock_nq(ghs); /* parent */ - if (error) - goto out_parent; - - error = gfs2_glock_nq(ghs + 1); /* child */ - if (error) - goto out_child; - - error = -ENOENT; - if (inode->i_nlink == 0) - goto out_rgrp; - - if (S_ISDIR(inode->i_mode)) { - error = -ENOTEMPTY; - if (ip->i_entries > 2 || inode->i_nlink > 2) - goto out_rgrp; - } - - error = gfs2_glock_nq(ghs + 2); /* rgrp */ - if (error) - goto out_rgrp; - - error = gfs2_unlink_ok(dip, &dentry->d_name, ip); - if (error) - goto out_gunlock; - - error = gfs2_trans_begin(sdp, 2*RES_DINODE + 3*RES_LEAF + RES_RG_BIT, 0); - if (error) - goto out_gunlock; - - error = gfs2_meta_inode_buffer(ip, &bh); - if (error) - goto out_end_trans; - - error = gfs2_unlink_inode(dip, dentry, bh); - brelse(bh); - -out_end_trans: - gfs2_trans_end(sdp); -out_gunlock: - gfs2_glock_dq(ghs + 2); -out_rgrp: - gfs2_holder_uninit(ghs + 2); - gfs2_glock_dq(ghs + 1); -out_child: - gfs2_holder_uninit(ghs + 1); - gfs2_glock_dq(ghs); -out_parent: - gfs2_holder_uninit(ghs); - gfs2_glock_dq_uninit(&ri_gh); - return error; -} - -/** - * gfs2_symlink - Create a symlink - * @dir: The directory to create the symlink in - * @dentry: The dentry to put the symlink in - * @symname: The thing which the link points to - * - * Returns: errno - */ - -static int gfs2_symlink(struct inode *dir, struct dentry *dentry, - const char *symname) -{ - struct gfs2_inode *dip = GFS2_I(dir), *ip; - struct gfs2_sbd *sdp = GFS2_SB(dir); - struct gfs2_holder ghs[2]; - struct inode *inode; - struct buffer_head *dibh; - int size; - int error; - - /* Must be stuffed with a null terminator for gfs2_follow_link() */ - size = strlen(symname); - if (size > sdp->sd_sb.sb_bsize - sizeof(struct gfs2_dinode) - 1) - return -ENAMETOOLONG; - - gfs2_holder_init(dip->i_gl, 0, 0, ghs); - - inode = gfs2_createi(ghs, &dentry->d_name, S_IFLNK | S_IRWXUGO, 0); - if (IS_ERR(inode)) { - gfs2_holder_uninit(ghs); - return PTR_ERR(inode); - } - - ip = ghs[1].gh_gl->gl_object; - - i_size_write(inode, size); - - error = gfs2_meta_inode_buffer(ip, &dibh); - - if (!gfs2_assert_withdraw(sdp, !error)) { - gfs2_dinode_out(ip, dibh->b_data); - memcpy(dibh->b_data + sizeof(struct gfs2_dinode), symname, - size); - brelse(dibh); - } - - gfs2_trans_end(sdp); - if (dip->i_alloc->al_rgd) - gfs2_inplace_release(dip); - gfs2_quota_unlock(dip); - gfs2_alloc_put(dip); - - gfs2_glock_dq_uninit_m(2, ghs); - - d_instantiate(dentry, inode); - mark_inode_dirty(inode); - - return 0; -} - -/** - * gfs2_mkdir - Make a directory - * @dir: The parent directory of the new one - * @dentry: The dentry of the new directory - * @mode: The mode of the new directory - * - * Returns: errno - */ - -static int gfs2_mkdir(struct inode *dir, struct dentry *dentry, int mode) -{ - struct gfs2_inode *dip = GFS2_I(dir), *ip; - struct gfs2_sbd *sdp = GFS2_SB(dir); - struct gfs2_holder ghs[2]; - struct inode *inode; - struct buffer_head *dibh; - int error; - - gfs2_holder_init(dip->i_gl, 0, 0, ghs); - - inode = gfs2_createi(ghs, &dentry->d_name, S_IFDIR | mode, 0); - if (IS_ERR(inode)) { - gfs2_holder_uninit(ghs); - return PTR_ERR(inode); - } - - ip = ghs[1].gh_gl->gl_object; - - ip->i_inode.i_nlink = 2; - i_size_write(inode, sdp->sd_sb.sb_bsize - sizeof(struct gfs2_dinode)); - ip->i_diskflags |= GFS2_DIF_JDATA; - ip->i_entries = 2; - - error = gfs2_meta_inode_buffer(ip, &dibh); - - if (!gfs2_assert_withdraw(sdp, !error)) { - struct gfs2_dinode *di = (struct gfs2_dinode *)dibh->b_data; - struct gfs2_dirent *dent = (struct gfs2_dirent *)(di+1); - - gfs2_trans_add_bh(ip->i_gl, dibh, 1); - gfs2_qstr2dirent(&gfs2_qdot, GFS2_DIRENT_SIZE(gfs2_qdot.len), dent); - dent->de_inum = di->di_num; /* already GFS2 endian */ - dent->de_type = cpu_to_be16(DT_DIR); - di->di_entries = cpu_to_be32(1); - - dent = (struct gfs2_dirent *)((char*)dent + GFS2_DIRENT_SIZE(1)); - gfs2_qstr2dirent(&gfs2_qdotdot, dibh->b_size - GFS2_DIRENT_SIZE(1) - sizeof(struct gfs2_dinode), dent); - - gfs2_inum_out(dip, dent); - dent->de_type = cpu_to_be16(DT_DIR); - - gfs2_dinode_out(ip, di); - - brelse(dibh); - } - - gfs2_trans_end(sdp); - if (dip->i_alloc->al_rgd) - gfs2_inplace_release(dip); - gfs2_quota_unlock(dip); - gfs2_alloc_put(dip); - - gfs2_glock_dq_uninit_m(2, ghs); - - d_instantiate(dentry, inode); - mark_inode_dirty(inode); - - return 0; -} - -/** - * gfs2_mknod - Make a special file - * @dir: The directory in which the special file will reside - * @dentry: The dentry of the special file - * @mode: The mode of the special file - * @rdev: The device specification of the special file - * - */ - -static int gfs2_mknod(struct inode *dir, struct dentry *dentry, int mode, - dev_t dev) -{ - struct gfs2_inode *dip = GFS2_I(dir); - struct gfs2_sbd *sdp = GFS2_SB(dir); - struct gfs2_holder ghs[2]; - struct inode *inode; - - gfs2_holder_init(dip->i_gl, 0, 0, ghs); - - inode = gfs2_createi(ghs, &dentry->d_name, mode, dev); - if (IS_ERR(inode)) { - gfs2_holder_uninit(ghs); - return PTR_ERR(inode); - } - - gfs2_trans_end(sdp); - if (dip->i_alloc->al_rgd) - gfs2_inplace_release(dip); - gfs2_quota_unlock(dip); - gfs2_alloc_put(dip); - - gfs2_glock_dq_uninit_m(2, ghs); - - d_instantiate(dentry, inode); - mark_inode_dirty(inode); - - return 0; -} - -/* - * gfs2_ok_to_move - check if it's ok to move a directory to another directory - * @this: move this - * @to: to here - * - * Follow @to back to the root and make sure we don't encounter @this - * Assumes we already hold the rename lock. - * - * Returns: errno - */ - -static int gfs2_ok_to_move(struct gfs2_inode *this, struct gfs2_inode *to) -{ - struct inode *dir = &to->i_inode; - struct super_block *sb = dir->i_sb; - struct inode *tmp; - int error = 0; - - igrab(dir); - - for (;;) { - if (dir == &this->i_inode) { - error = -EINVAL; - break; - } - if (dir == sb->s_root->d_inode) { - error = 0; - break; - } - - tmp = gfs2_lookupi(dir, &gfs2_qdotdot, 1); - if (IS_ERR(tmp)) { - error = PTR_ERR(tmp); - break; - } - - iput(dir); - dir = tmp; - } - - iput(dir); - - return error; -} - -/** - * gfs2_rename - Rename a file - * @odir: Parent directory of old file name - * @odentry: The old dentry of the file - * @ndir: Parent directory of new file name - * @ndentry: The new dentry of the file - * - * Returns: errno - */ - -static int gfs2_rename(struct inode *odir, struct dentry *odentry, - struct inode *ndir, struct dentry *ndentry) -{ - struct gfs2_inode *odip = GFS2_I(odir); - struct gfs2_inode *ndip = GFS2_I(ndir); - struct gfs2_inode *ip = GFS2_I(odentry->d_inode); - struct gfs2_inode *nip = NULL; - struct gfs2_sbd *sdp = GFS2_SB(odir); - struct gfs2_holder ghs[5], r_gh = { .gh_gl = NULL, }, ri_gh; - struct gfs2_rgrpd *nrgd; - unsigned int num_gh; - int dir_rename = 0; - int alloc_required = 0; - unsigned int x; - int error; - - if (ndentry->d_inode) { - nip = GFS2_I(ndentry->d_inode); - if (ip == nip) - return 0; - } - - error = gfs2_rindex_hold(sdp, &ri_gh); - if (error) - return error; - - if (odip != ndip) { - error = gfs2_glock_nq_init(sdp->sd_rename_gl, LM_ST_EXCLUSIVE, - 0, &r_gh); - if (error) - goto out; - - if (S_ISDIR(ip->i_inode.i_mode)) { - dir_rename = 1; - /* don't move a dirctory into it's subdir */ - error = gfs2_ok_to_move(ip, ndip); - if (error) - goto out_gunlock_r; - } - } - - num_gh = 1; - gfs2_holder_init(odip->i_gl, LM_ST_EXCLUSIVE, 0, ghs); - if (odip != ndip) { - gfs2_holder_init(ndip->i_gl, LM_ST_EXCLUSIVE, 0, ghs + num_gh); - num_gh++; - } - gfs2_holder_init(ip->i_gl, LM_ST_EXCLUSIVE, 0, ghs + num_gh); - num_gh++; - - if (nip) { - gfs2_holder_init(nip->i_gl, LM_ST_EXCLUSIVE, 0, ghs + num_gh); - num_gh++; - /* grab the resource lock for unlink flag twiddling - * this is the case of the target file already existing - * so we unlink before doing the rename - */ - nrgd = gfs2_blk2rgrpd(sdp, nip->i_no_addr); - if (nrgd) - gfs2_holder_init(nrgd->rd_gl, LM_ST_EXCLUSIVE, 0, ghs + num_gh++); - } - - for (x = 0; x < num_gh; x++) { - error = gfs2_glock_nq(ghs + x); - if (error) - goto out_gunlock; - } - - error = -ENOENT; - if (ip->i_inode.i_nlink == 0) - goto out_gunlock; - - /* Check out the old directory */ - - error = gfs2_unlink_ok(odip, &odentry->d_name, ip); - if (error) - goto out_gunlock; - - /* Check out the new directory */ - - if (nip) { - error = gfs2_unlink_ok(ndip, &ndentry->d_name, nip); - if (error) - goto out_gunlock; - - if (nip->i_inode.i_nlink == 0) { - error = -EAGAIN; - goto out_gunlock; - } - - if (S_ISDIR(nip->i_inode.i_mode)) { - if (nip->i_entries < 2) { - gfs2_consist_inode(nip); - error = -EIO; - goto out_gunlock; - } - if (nip->i_entries > 2) { - error = -ENOTEMPTY; - goto out_gunlock; - } - } - } else { - error = gfs2_permission(ndir, MAY_WRITE | MAY_EXEC, 0); - if (error) - goto out_gunlock; - - error = gfs2_dir_check(ndir, &ndentry->d_name, NULL); - switch (error) { - case -ENOENT: - error = 0; - break; - case 0: - error = -EEXIST; - default: - goto out_gunlock; - }; - - if (odip != ndip) { - if (!ndip->i_inode.i_nlink) { - error = -ENOENT; - goto out_gunlock; - } - if (ndip->i_entries == (u32)-1) { - error = -EFBIG; - goto out_gunlock; - } - if (S_ISDIR(ip->i_inode.i_mode) && - ndip->i_inode.i_nlink == (u32)-1) { - error = -EMLINK; - goto out_gunlock; - } - } - } - - /* Check out the dir to be renamed */ - - if (dir_rename) { - error = gfs2_permission(odentry->d_inode, MAY_WRITE, 0); - if (error) - goto out_gunlock; - } - - if (nip == NULL) - alloc_required = gfs2_diradd_alloc_required(ndir, &ndentry->d_name); - error = alloc_required; - if (error < 0) - goto out_gunlock; - error = 0; - - if (alloc_required) { - struct gfs2_alloc *al = gfs2_alloc_get(ndip); - if (!al) { - error = -ENOMEM; - goto out_gunlock; - } - - error = gfs2_quota_lock_check(ndip); - if (error) - goto out_alloc; - - al->al_requested = sdp->sd_max_dirres; - - error = gfs2_inplace_reserve_ri(ndip); - if (error) - goto out_gunlock_q; - - error = gfs2_trans_begin(sdp, sdp->sd_max_dirres + - gfs2_rg_blocks(al) + - 4 * RES_DINODE + 4 * RES_LEAF + - RES_STATFS + RES_QUOTA + 4, 0); - if (error) - goto out_ipreserv; - } else { - error = gfs2_trans_begin(sdp, 4 * RES_DINODE + - 5 * RES_LEAF + 4, 0); - if (error) - goto out_gunlock; - } - - /* Remove the target file, if it exists */ - - if (nip) { - struct buffer_head *bh; - error = gfs2_meta_inode_buffer(nip, &bh); - if (error) - goto out_end_trans; - error = gfs2_unlink_inode(ndip, ndentry, bh); - brelse(bh); - } - - if (dir_rename) { - error = gfs2_dir_mvino(ip, &gfs2_qdotdot, ndip, DT_DIR); - if (error) - goto out_end_trans; - } else { - struct buffer_head *dibh; - error = gfs2_meta_inode_buffer(ip, &dibh); - if (error) - goto out_end_trans; - ip->i_inode.i_ctime = CURRENT_TIME; - gfs2_trans_add_bh(ip->i_gl, dibh, 1); - gfs2_dinode_out(ip, dibh->b_data); - brelse(dibh); - } - - error = gfs2_dir_del(odip, odentry); - if (error) - goto out_end_trans; - - error = gfs2_dir_add(ndir, &ndentry->d_name, ip); - if (error) - goto out_end_trans; - -out_end_trans: - gfs2_trans_end(sdp); -out_ipreserv: - if (alloc_required) - gfs2_inplace_release(ndip); -out_gunlock_q: - if (alloc_required) - gfs2_quota_unlock(ndip); -out_alloc: - if (alloc_required) - gfs2_alloc_put(ndip); -out_gunlock: - while (x--) { - gfs2_glock_dq(ghs + x); - gfs2_holder_uninit(ghs + x); - } -out_gunlock_r: - if (r_gh.gh_gl) - gfs2_glock_dq_uninit(&r_gh); -out: - gfs2_glock_dq_uninit(&ri_gh); - return error; -} - -/** - * gfs2_follow_link - Follow a symbolic link - * @dentry: The dentry of the link - * @nd: Data that we pass to vfs_follow_link() - * - * This can handle symlinks of any size. - * - * Returns: 0 on success or error code - */ - -static void *gfs2_follow_link(struct dentry *dentry, struct nameidata *nd) -{ - struct gfs2_inode *ip = GFS2_I(dentry->d_inode); - struct gfs2_holder i_gh; - struct buffer_head *dibh; - unsigned int x, size; - char *buf; - int error; - - gfs2_holder_init(ip->i_gl, LM_ST_SHARED, 0, &i_gh); - error = gfs2_glock_nq(&i_gh); - if (error) { - gfs2_holder_uninit(&i_gh); - nd_set_link(nd, ERR_PTR(error)); - return NULL; - } - - size = (unsigned int)i_size_read(&ip->i_inode); - if (size == 0) { - gfs2_consist_inode(ip); - buf = ERR_PTR(-EIO); - goto out; - } - - error = gfs2_meta_inode_buffer(ip, &dibh); - if (error) { - buf = ERR_PTR(error); - goto out; - } - - x = size + 1; - buf = kmalloc(x, GFP_NOFS); - if (!buf) - buf = ERR_PTR(-ENOMEM); - else - memcpy(buf, dibh->b_data + sizeof(struct gfs2_dinode), x); - brelse(dibh); -out: - gfs2_glock_dq_uninit(&i_gh); - nd_set_link(nd, buf); - return NULL; -} - -static void gfs2_put_link(struct dentry *dentry, struct nameidata *nd, void *p) -{ - char *s = nd_get_link(nd); - if (!IS_ERR(s)) - kfree(s); -} - -/** - * gfs2_permission - - * @inode: The inode - * @mask: The mask to be tested - * @flags: Indicates whether this is an RCU path walk or not - * - * This may be called from the VFS directly, or from within GFS2 with the - * inode locked, so we look to see if the glock is already locked and only - * lock the glock if its not already been done. - * - * Returns: errno - */ - -int gfs2_permission(struct inode *inode, int mask, unsigned int flags) -{ - struct gfs2_inode *ip; - struct gfs2_holder i_gh; - int error; - int unlock = 0; - - - ip = GFS2_I(inode); - if (gfs2_glock_is_locked_by_me(ip->i_gl) == NULL) { - if (flags & IPERM_FLAG_RCU) - return -ECHILD; - error = gfs2_glock_nq_init(ip->i_gl, LM_ST_SHARED, LM_FLAG_ANY, &i_gh); - if (error) - return error; - unlock = 1; - } - - if ((mask & MAY_WRITE) && IS_IMMUTABLE(inode)) - error = -EACCES; - else - error = generic_permission(inode, mask, flags, gfs2_check_acl); - if (unlock) - gfs2_glock_dq_uninit(&i_gh); - - return error; -} - -static int __gfs2_setattr_simple(struct gfs2_inode *ip, struct iattr *attr) -{ - struct inode *inode = &ip->i_inode; - struct buffer_head *dibh; - int error; - - error = gfs2_meta_inode_buffer(ip, &dibh); - if (error) - return error; - - setattr_copy(inode, attr); - mark_inode_dirty(inode); - gfs2_trans_add_bh(ip->i_gl, dibh, 1); - gfs2_dinode_out(ip, dibh->b_data); - brelse(dibh); - return 0; -} - -/** - * gfs2_setattr_simple - - * @ip: - * @attr: - * - * Returns: errno - */ - -int gfs2_setattr_simple(struct gfs2_inode *ip, struct iattr *attr) -{ - int error; - - if (current->journal_info) - return __gfs2_setattr_simple(ip, attr); - - error = gfs2_trans_begin(GFS2_SB(&ip->i_inode), RES_DINODE, 0); - if (error) - return error; - - error = __gfs2_setattr_simple(ip, attr); - gfs2_trans_end(GFS2_SB(&ip->i_inode)); - return error; -} - -static int setattr_chown(struct inode *inode, struct iattr *attr) -{ - struct gfs2_inode *ip = GFS2_I(inode); - struct gfs2_sbd *sdp = GFS2_SB(inode); - u32 ouid, ogid, nuid, ngid; - int error; - - ouid = inode->i_uid; - ogid = inode->i_gid; - nuid = attr->ia_uid; - ngid = attr->ia_gid; - - if (!(attr->ia_valid & ATTR_UID) || ouid == nuid) - ouid = nuid = NO_QUOTA_CHANGE; - if (!(attr->ia_valid & ATTR_GID) || ogid == ngid) - ogid = ngid = NO_QUOTA_CHANGE; - - if (!gfs2_alloc_get(ip)) - return -ENOMEM; - - error = gfs2_quota_lock(ip, nuid, ngid); - if (error) - goto out_alloc; - - if (ouid != NO_QUOTA_CHANGE || ogid != NO_QUOTA_CHANGE) { - error = gfs2_quota_check(ip, nuid, ngid); - if (error) - goto out_gunlock_q; - } - - error = gfs2_trans_begin(sdp, RES_DINODE + 2 * RES_QUOTA, 0); - if (error) - goto out_gunlock_q; - - error = gfs2_setattr_simple(ip, attr); - if (error) - goto out_end_trans; - - if (ouid != NO_QUOTA_CHANGE || ogid != NO_QUOTA_CHANGE) { - u64 blocks = gfs2_get_inode_blocks(&ip->i_inode); - gfs2_quota_change(ip, -blocks, ouid, ogid); - gfs2_quota_change(ip, blocks, nuid, ngid); - } - -out_end_trans: - gfs2_trans_end(sdp); -out_gunlock_q: - gfs2_quota_unlock(ip); -out_alloc: - gfs2_alloc_put(ip); - return error; -} - -/** - * gfs2_setattr - Change attributes on an inode - * @dentry: The dentry which is changing - * @attr: The structure describing the change - * - * The VFS layer wants to change one or more of an inodes attributes. Write - * that change out to disk. - * - * Returns: errno - */ - -static int gfs2_setattr(struct dentry *dentry, struct iattr *attr) -{ - struct inode *inode = dentry->d_inode; - struct gfs2_inode *ip = GFS2_I(inode); - struct gfs2_holder i_gh; - int error; - - error = gfs2_glock_nq_init(ip->i_gl, LM_ST_EXCLUSIVE, 0, &i_gh); - if (error) - return error; - - error = -EPERM; - if (IS_IMMUTABLE(inode) || IS_APPEND(inode)) - goto out; - - error = inode_change_ok(inode, attr); - if (error) - goto out; - - if (attr->ia_valid & ATTR_SIZE) - error = gfs2_setattr_size(inode, attr->ia_size); - else if (attr->ia_valid & (ATTR_UID | ATTR_GID)) - error = setattr_chown(inode, attr); - else if ((attr->ia_valid & ATTR_MODE) && IS_POSIXACL(inode)) - error = gfs2_acl_chmod(ip, attr); - else - error = gfs2_setattr_simple(ip, attr); - -out: - gfs2_glock_dq_uninit(&i_gh); - if (!error) - mark_inode_dirty(inode); - return error; -} - -/** - * gfs2_getattr - Read out an inode's attributes - * @mnt: The vfsmount the inode is being accessed from - * @dentry: The dentry to stat - * @stat: The inode's stats - * - * This may be called from the VFS directly, or from within GFS2 with the - * inode locked, so we look to see if the glock is already locked and only - * lock the glock if its not already been done. Note that its the NFS - * readdirplus operation which causes this to be called (from filldir) - * with the glock already held. - * - * Returns: errno - */ - -static int gfs2_getattr(struct vfsmount *mnt, struct dentry *dentry, - struct kstat *stat) -{ - struct inode *inode = dentry->d_inode; - struct gfs2_inode *ip = GFS2_I(inode); - struct gfs2_holder gh; - int error; - int unlock = 0; - - if (gfs2_glock_is_locked_by_me(ip->i_gl) == NULL) { - error = gfs2_glock_nq_init(ip->i_gl, LM_ST_SHARED, LM_FLAG_ANY, &gh); - if (error) - return error; - unlock = 1; - } - - generic_fillattr(inode, stat); - if (unlock) - gfs2_glock_dq_uninit(&gh); - - return 0; -} - -static int gfs2_setxattr(struct dentry *dentry, const char *name, - const void *data, size_t size, int flags) -{ - struct inode *inode = dentry->d_inode; - struct gfs2_inode *ip = GFS2_I(inode); - struct gfs2_holder gh; - int ret; - - gfs2_holder_init(ip->i_gl, LM_ST_EXCLUSIVE, 0, &gh); - ret = gfs2_glock_nq(&gh); - if (ret == 0) { - ret = generic_setxattr(dentry, name, data, size, flags); - gfs2_glock_dq(&gh); - } - gfs2_holder_uninit(&gh); - return ret; -} - -static ssize_t gfs2_getxattr(struct dentry *dentry, const char *name, - void *data, size_t size) -{ - struct inode *inode = dentry->d_inode; - struct gfs2_inode *ip = GFS2_I(inode); - struct gfs2_holder gh; - int ret; - - gfs2_holder_init(ip->i_gl, LM_ST_SHARED, LM_FLAG_ANY, &gh); - ret = gfs2_glock_nq(&gh); - if (ret == 0) { - ret = generic_getxattr(dentry, name, data, size); - gfs2_glock_dq(&gh); - } - gfs2_holder_uninit(&gh); - return ret; -} - -static int gfs2_removexattr(struct dentry *dentry, const char *name) -{ - struct inode *inode = dentry->d_inode; - struct gfs2_inode *ip = GFS2_I(inode); - struct gfs2_holder gh; - int ret; - - gfs2_holder_init(ip->i_gl, LM_ST_EXCLUSIVE, 0, &gh); - ret = gfs2_glock_nq(&gh); - if (ret == 0) { - ret = generic_removexattr(dentry, name); - gfs2_glock_dq(&gh); - } - gfs2_holder_uninit(&gh); - return ret; -} - -static int gfs2_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo, - u64 start, u64 len) -{ - struct gfs2_inode *ip = GFS2_I(inode); - struct gfs2_holder gh; - int ret; - - ret = fiemap_check_flags(fieinfo, FIEMAP_FLAG_SYNC); - if (ret) - return ret; - - mutex_lock(&inode->i_mutex); - - ret = gfs2_glock_nq_init(ip->i_gl, LM_ST_SHARED, 0, &gh); - if (ret) - goto out; - - if (gfs2_is_stuffed(ip)) { - u64 phys = ip->i_no_addr << inode->i_blkbits; - u64 size = i_size_read(inode); - u32 flags = FIEMAP_EXTENT_LAST|FIEMAP_EXTENT_NOT_ALIGNED| - FIEMAP_EXTENT_DATA_INLINE; - phys += sizeof(struct gfs2_dinode); - phys += start; - if (start + len > size) - len = size - start; - if (start < size) - ret = fiemap_fill_next_extent(fieinfo, start, phys, - len, flags); - if (ret == 1) - ret = 0; - } else { - ret = __generic_block_fiemap(inode, fieinfo, start, len, - gfs2_block_map); - } - - gfs2_glock_dq_uninit(&gh); -out: - mutex_unlock(&inode->i_mutex); - return ret; -} - -const struct inode_operations gfs2_file_iops = { - .permission = gfs2_permission, - .setattr = gfs2_setattr, - .getattr = gfs2_getattr, - .setxattr = gfs2_setxattr, - .getxattr = gfs2_getxattr, - .listxattr = gfs2_listxattr, - .removexattr = gfs2_removexattr, - .fiemap = gfs2_fiemap, -}; - -const struct inode_operations gfs2_dir_iops = { - .create = gfs2_create, - .lookup = gfs2_lookup, - .link = gfs2_link, - .unlink = gfs2_unlink, - .symlink = gfs2_symlink, - .mkdir = gfs2_mkdir, - .rmdir = gfs2_unlink, - .mknod = gfs2_mknod, - .rename = gfs2_rename, - .permission = gfs2_permission, - .setattr = gfs2_setattr, - .getattr = gfs2_getattr, - .setxattr = gfs2_setxattr, - .getxattr = gfs2_getxattr, - .listxattr = gfs2_listxattr, - .removexattr = gfs2_removexattr, - .fiemap = gfs2_fiemap, -}; - -const struct inode_operations gfs2_symlink_iops = { - .readlink = generic_readlink, - .follow_link = gfs2_follow_link, - .put_link = gfs2_put_link, - .permission = gfs2_permission, - .setattr = gfs2_setattr, - .getattr = gfs2_getattr, - .setxattr = gfs2_setxattr, - .getxattr = gfs2_getxattr, - .listxattr = gfs2_listxattr, - .removexattr = gfs2_removexattr, - .fiemap = gfs2_fiemap, -}; - -- cgit v0.10.2 From 349dbc3669d043e656f3ed48c7bfe073ca1c6326 Mon Sep 17 00:00:00 2001 From: Ryusuke Konishi Date: Tue, 10 May 2011 20:59:34 +0900 Subject: nilfs2: fix infinite loop in nilfs_palloc_freev function After having applied commit 9954e7af14868b8b ("nilfs2: add free entries count only if clear bit operation succeeded"), a free routine of nilfs came to fall into an infinite loop, outputting the same message endlessly: nilfs_palloc_freev: entry number 29497 already freed nilfs_palloc_freev: entry number 29497 already freed nilfs_palloc_freev: entry number 29497 already freed nilfs_palloc_freev: entry number 29497 already freed nilfs_palloc_freev: entry number 29497 already freed ... That patch broke the routine so that a loop counter is never updated in an abnormal state. This fixes the regression. Signed-off-by: Ryusuke Konishi diff --git a/fs/nilfs2/alloc.c b/fs/nilfs2/alloc.c index 0a0a66d..f768448 100644 --- a/fs/nilfs2/alloc.c +++ b/fs/nilfs2/alloc.c @@ -646,7 +646,7 @@ int nilfs_palloc_freev(struct inode *inode, __u64 *entry_nrs, size_t nitems) unsigned long group, group_offset; int i, j, n, ret; - for (i = 0; i < nitems; i += n) { + for (i = 0; i < nitems; i = j) { group = nilfs_palloc_group(inode, entry_nrs[i], &group_offset); ret = nilfs_palloc_get_desc_block(inode, group, 0, &desc_bh); if (ret < 0) -- cgit v0.10.2 From 32e471ef1057e812856739d26b4a87d929fb8aa1 Mon Sep 17 00:00:00 2001 From: Steven Whitehouse Date: Tue, 10 May 2011 15:01:59 +0100 Subject: GFS2: Use UUID field in generic superblock The VFS superblock structure now has a UUID field, so we can use that in preference to the UUID field in the GFS2 superblock now. Signed-off-by: Steven Whitehouse diff --git a/fs/gfs2/incore.h b/fs/gfs2/incore.h index 69a6382..0a064e9 100644 --- a/fs/gfs2/incore.h +++ b/fs/gfs2/incore.h @@ -488,7 +488,6 @@ struct gfs2_sb_host { char sb_lockproto[GFS2_LOCKNAME_LEN]; char sb_locktable[GFS2_LOCKNAME_LEN]; - u8 sb_uuid[16]; }; /* diff --git a/fs/gfs2/ops_fstype.c b/fs/gfs2/ops_fstype.c index d3c69eb..8ac9ae1 100644 --- a/fs/gfs2/ops_fstype.c +++ b/fs/gfs2/ops_fstype.c @@ -126,8 +126,10 @@ static struct gfs2_sbd *init_sbd(struct super_block *sb) * changed. */ -static int gfs2_check_sb(struct gfs2_sbd *sdp, struct gfs2_sb_host *sb, int silent) +static int gfs2_check_sb(struct gfs2_sbd *sdp, int silent) { + struct gfs2_sb_host *sb = &sdp->sd_sb; + if (sb->sb_magic != GFS2_MAGIC || sb->sb_type != GFS2_METATYPE_SB) { if (!silent) @@ -157,8 +159,10 @@ static void end_bio_io_page(struct bio *bio, int error) unlock_page(page); } -static void gfs2_sb_in(struct gfs2_sb_host *sb, const void *buf) +static void gfs2_sb_in(struct gfs2_sbd *sdp, const void *buf) { + struct gfs2_sb_host *sb = &sdp->sd_sb; + struct super_block *s = sdp->sd_vfs; const struct gfs2_sb *str = buf; sb->sb_magic = be32_to_cpu(str->sb_header.mh_magic); @@ -175,7 +179,7 @@ static void gfs2_sb_in(struct gfs2_sb_host *sb, const void *buf) memcpy(sb->sb_lockproto, str->sb_lockproto, GFS2_LOCKNAME_LEN); memcpy(sb->sb_locktable, str->sb_locktable, GFS2_LOCKNAME_LEN); - memcpy(sb->sb_uuid, str->sb_uuid, 16); + memcpy(s->s_uuid, str->sb_uuid, 16); } /** @@ -197,7 +201,7 @@ static void gfs2_sb_in(struct gfs2_sb_host *sb, const void *buf) * Returns: 0 on success or error */ -static int gfs2_read_super(struct gfs2_sbd *sdp, sector_t sector) +static int gfs2_read_super(struct gfs2_sbd *sdp, sector_t sector, int silent) { struct super_block *sb = sdp->sd_vfs; struct gfs2_sb *p; @@ -227,10 +231,10 @@ static int gfs2_read_super(struct gfs2_sbd *sdp, sector_t sector) return -EIO; } p = kmap(page); - gfs2_sb_in(&sdp->sd_sb, p); + gfs2_sb_in(sdp, p); kunmap(page); __free_page(page); - return 0; + return gfs2_check_sb(sdp, silent); } /** @@ -247,17 +251,13 @@ static int gfs2_read_sb(struct gfs2_sbd *sdp, int silent) unsigned int x; int error; - error = gfs2_read_super(sdp, GFS2_SB_ADDR >> sdp->sd_fsb2bb_shift); + error = gfs2_read_super(sdp, GFS2_SB_ADDR >> sdp->sd_fsb2bb_shift, silent); if (error) { if (!silent) fs_err(sdp, "can't read superblock\n"); return error; } - error = gfs2_check_sb(sdp, &sdp->sd_sb, silent); - if (error) - return error; - sdp->sd_fsb2bb_shift = sdp->sd_sb.sb_bsize_shift - GFS2_BASIC_BLOCK_SHIFT; sdp->sd_fsb2bb = 1 << sdp->sd_fsb2bb_shift; @@ -340,14 +340,10 @@ static int init_names(struct gfs2_sbd *sdp, int silent) /* Try to autodetect */ if (!proto[0] || !table[0]) { - error = gfs2_read_super(sdp, GFS2_SB_ADDR >> sdp->sd_fsb2bb_shift); + error = gfs2_read_super(sdp, GFS2_SB_ADDR >> sdp->sd_fsb2bb_shift, silent); if (error) return error; - error = gfs2_check_sb(sdp, &sdp->sd_sb, silent); - if (error) - goto out; - if (!proto[0]) proto = sdp->sd_sb.sb_lockproto; if (!table[0]) @@ -364,7 +360,6 @@ static int init_names(struct gfs2_sbd *sdp, int silent) while ((table = strchr(table, '/'))) *table = '_'; -out: return error; } @@ -1119,8 +1114,7 @@ static int fill_super(struct super_block *sb, struct gfs2_args *args, int silent if (sdp->sd_args.ar_statfs_quantum) { sdp->sd_tune.gt_statfs_slow = 0; sdp->sd_tune.gt_statfs_quantum = sdp->sd_args.ar_statfs_quantum; - } - else { + } else { sdp->sd_tune.gt_statfs_slow = 1; sdp->sd_tune.gt_statfs_quantum = 30; } diff --git a/fs/gfs2/sys.c b/fs/gfs2/sys.c index 748ccb5..e20eab3 100644 --- a/fs/gfs2/sys.c +++ b/fs/gfs2/sys.c @@ -81,7 +81,8 @@ static int gfs2_uuid_valid(const u8 *uuid) static ssize_t uuid_show(struct gfs2_sbd *sdp, char *buf) { - const u8 *uuid = sdp->sd_sb.sb_uuid; + struct super_block *s = sdp->sd_vfs; + const u8 *uuid = s->s_uuid; buf[0] = '\0'; if (!gfs2_uuid_valid(uuid)) return 0; @@ -616,7 +617,8 @@ static int gfs2_uevent(struct kset *kset, struct kobject *kobj, struct kobj_uevent_env *env) { struct gfs2_sbd *sdp = container_of(kobj, struct gfs2_sbd, sd_kobj); - const u8 *uuid = sdp->sd_sb.sb_uuid; + struct super_block *s = sdp->sd_vfs; + const u8 *uuid = s->s_uuid; add_uevent_var(env, "LOCKTABLE=%s", sdp->sd_table_name); add_uevent_var(env, "LOCKPROTO=%s", sdp->sd_proto_name); -- cgit v0.10.2 From 97fbdc1f77e9ce50ed0be543273d78f8de8675ac Mon Sep 17 00:00:00 2001 From: Michal Marek Date: Tue, 5 Apr 2011 16:59:16 +0200 Subject: tipc: Drop __TIME__ usage The kernel already prints its build timestamp during boot, no need to repeat it in random drivers and produce different object files each time. Signed-off-by: Michal Marek Cc: Jon Maloy Cc: netdev@vger.kernel.org Cc: tipc-discussion@lists.sourceforge.net Signed-off-by: Allan Stephens Signed-off-by: Paul Gortmaker diff --git a/net/tipc/core.c b/net/tipc/core.c index c9a73e7..943b6af 100644 --- a/net/tipc/core.c +++ b/net/tipc/core.c @@ -179,8 +179,7 @@ static int __init tipc_init(void) if (tipc_log_resize(CONFIG_TIPC_LOG) != 0) warn("Unable to create log buffer\n"); - info("Activated (version " TIPC_MOD_VER - " compiled " __DATE__ " " __TIME__ ")\n"); + info("Activated (version " TIPC_MOD_VER ")\n"); tipc_own_addr = 0; tipc_remote_management = 1; -- cgit v0.10.2 From 2b348a77981227c6b64fb9cf19f7c711a6806bc9 Mon Sep 17 00:00:00 2001 From: Lin Ming Date: Fri, 29 Apr 2011 08:41:57 +0000 Subject: perf probe: Fix the missed parameter initialization pubname_callback_param::found should be initialized to 0 in fastpath lookup, the structure is on the stack and uninitialized otherwise. Signed-off-by: Lin Ming Cc: Arnaldo Carvalho de Melo Link: http://lkml.kernel.org/r/1304066518-30420-2-git-send-email-ming.m.lin@intel.com Signed-off-by: Ingo Molnar diff --git a/tools/perf/util/probe-finder.c b/tools/perf/util/probe-finder.c index a7c7145..3b9d0b8 100644 --- a/tools/perf/util/probe-finder.c +++ b/tools/perf/util/probe-finder.c @@ -1538,6 +1538,7 @@ static int find_probes(int fd, struct probe_finder *pf) .file = pp->file, .cu_die = &pf->cu_die, .sp_die = &pf->sp_die, + .found = 0, }; struct dwarf_callback_param probe_param = { .data = pf, -- cgit v0.10.2 From fdb1bb157525907163e2a0c96fe8bb19fbe867a8 Mon Sep 17 00:00:00 2001 From: Heiko Carstens Date: Tue, 10 May 2011 17:13:37 +0200 Subject: [S390] sclp/memory hotplug: fix initial usecount of increments Fix initial usecount of attached and assigned storage increments so they can be set offline. Signed-off-by: Heiko Carstens Signed-off-by: Martin Schwidefsky diff --git a/drivers/s390/char/sclp_cmd.c b/drivers/s390/char/sclp_cmd.c index 4b60ede..be55fb2 100644 --- a/drivers/s390/char/sclp_cmd.c +++ b/drivers/s390/char/sclp_cmd.c @@ -518,6 +518,8 @@ static void __init insert_increment(u16 rn, int standby, int assigned) return; new_incr->rn = rn; new_incr->standby = standby; + if (!standby) + new_incr->usecount = 1; last_rn = 0; prev = &sclp_mem_list; list_for_each_entry(incr, &sclp_mem_list, list) { -- cgit v0.10.2 From aade6c0dfb46ff7ce7df0ed7a2ef15d2d3c47f05 Mon Sep 17 00:00:00 2001 From: Stefan Haberland Date: Tue, 10 May 2011 17:13:38 +0200 Subject: [S390] dasd: prevent IO error during reserve/release loop The termination of running CQR caused by reserve/release operations may lead to an IO error if reserve/release is done in a tight loop. Prevent this by increasing the retry counter after termination. Signed-off-by: Stefan Haberland Signed-off-by: Martin Schwidefsky diff --git a/drivers/s390/block/dasd.c b/drivers/s390/block/dasd.c index 475e603..86b6f1c 100644 --- a/drivers/s390/block/dasd.c +++ b/drivers/s390/block/dasd.c @@ -1742,11 +1742,20 @@ int dasd_sleep_on_interruptible(struct dasd_ccw_req *cqr) static inline int _dasd_term_running_cqr(struct dasd_device *device) { struct dasd_ccw_req *cqr; + int rc; if (list_empty(&device->ccw_queue)) return 0; cqr = list_entry(device->ccw_queue.next, struct dasd_ccw_req, devlist); - return device->discipline->term_IO(cqr); + rc = device->discipline->term_IO(cqr); + if (!rc) + /* + * CQR terminated because a more important request is pending. + * Undo decreasing of retry counter because this is + * not an error case. + */ + cqr->retries++; + return rc; } int dasd_sleep_on_immediatly(struct dasd_ccw_req *cqr) -- cgit v0.10.2 From 8eb4bd666ffdca7171cd8118138a91842012b028 Mon Sep 17 00:00:00 2001 From: Michael Holzheu Date: Tue, 10 May 2011 17:13:39 +0200 Subject: [S390] kernel: Initialize register 14 when starting new CPU When starting a new CPU we currently jump to start_secondary() without setting register 14 (the return address) correctly. Therefore on the stack frame for start_secondary an invalid return address is stored. This leads to wrong stack back traces in kernel dumps. Example: #00 [1f33fe48] cpu_idle at 10614a #01 [1f33fe90] start_secondary at 54fa88 #02 [1f33feb8] (null) at 0 <--- invalid To fix this start_secondary() is called now with basr/brasl that sets register 14 correctly. The output of the stack backtrace looks then like the following: #00 [1f33fe48] cpu_idle at 10614a #01 [1f33fe90] start_secondary at 54fa88 #02 [1f33feb8] restart_base at 54f41e <--- correct Signed-off-by: Michael Holzheu Signed-off-by: Martin Schwidefsky diff --git a/arch/s390/kernel/entry.S b/arch/s390/kernel/entry.S index 648f642..1b67fc6 100644 --- a/arch/s390/kernel/entry.S +++ b/arch/s390/kernel/entry.S @@ -836,7 +836,7 @@ restart_base: stosm __SF_EMPTY(%r15),0x04 # now we can turn dat on basr %r14,0 l %r14,restart_addr-.(%r14) - br %r14 # branch to start_secondary + basr %r14,%r14 # branch to start_secondary restart_addr: .long start_secondary .align 8 diff --git a/arch/s390/kernel/entry64.S b/arch/s390/kernel/entry64.S index 9d3603d..9fd8645 100644 --- a/arch/s390/kernel/entry64.S +++ b/arch/s390/kernel/entry64.S @@ -841,7 +841,7 @@ restart_base: mvc __LC_SYSTEM_TIMER(8),__TI_system_timer(%r1) xc __LC_STEAL_TIMER(8),__LC_STEAL_TIMER stosm __SF_EMPTY(%r15),0x04 # now we can turn dat on - jg start_secondary + brasl %r14,start_secondary .align 8 restart_vtime: .long 0x7fffffff,0xffffffff -- cgit v0.10.2 From 91d378088b104f8e31baba8c518f32a7a219d58c Mon Sep 17 00:00:00 2001 From: Christian Borntraeger Date: Tue, 10 May 2011 17:13:40 +0200 Subject: [S390] disassembler: handle b280/spp instruction arch/s390/kvm/sie64a.S uses the b280 instruction. Tell the builtin disassembler to handle that code. Signed-off-by: Christian Borntraeger Signed-off-by: Martin Schwidefsky diff --git a/arch/s390/kernel/dis.c b/arch/s390/kernel/dis.c index c83726c..3d4a78f 100644 --- a/arch/s390/kernel/dis.c +++ b/arch/s390/kernel/dis.c @@ -672,6 +672,7 @@ static struct insn opcode_b2[] = { { "rp", 0x77, INSTR_S_RD }, { "stcke", 0x78, INSTR_S_RD }, { "sacf", 0x79, INSTR_S_RD }, + { "spp", 0x80, INSTR_S_RD }, { "stsi", 0x7d, INSTR_S_RD }, { "srnm", 0x99, INSTR_S_RD }, { "stfpc", 0x9c, INSTR_S_RD }, -- cgit v0.10.2 From 83ace2701b81be549cca7af33c5b0499cb2602d6 Mon Sep 17 00:00:00 2001 From: Michael Holzheu Date: Tue, 10 May 2011 17:13:41 +0200 Subject: [S390] replace diag10() with diag10_range() function Currently the diag10() function can only release one page. For exploiters that have to call diag10 on a contiguous memory region this is suboptimal. This patch replaces the diag10() function with diag10_range() that is able to release multiple pages. In addition to that the new function now allows to release memory with addresses higher than 2047 MiB. This was due to a restriction of the diagnose implementation under z/VM prior to release 5.2. Signed-off-by: Michael Holzheu Signed-off-by: Martin Schwidefsky diff --git a/arch/s390/include/asm/diag.h b/arch/s390/include/asm/diag.h index 72b2e2f..7e91c58 100644 --- a/arch/s390/include/asm/diag.h +++ b/arch/s390/include/asm/diag.h @@ -9,9 +9,22 @@ #define _ASM_S390_DIAG_H /* - * Diagnose 10: Release pages + * Diagnose 10: Release page range */ -extern void diag10(unsigned long addr); +static inline void diag10_range(unsigned long start_pfn, unsigned long num_pfn) +{ + unsigned long start_addr, end_addr; + + start_addr = start_pfn << PAGE_SHIFT; + end_addr = (start_pfn + num_pfn - 1) << PAGE_SHIFT; + + asm volatile( + "0: diag %0,%1,0x10\n" + "1:\n" + EX_TABLE(0b, 1b) + EX_TABLE(1b, 1b) + : : "a" (start_addr), "a" (end_addr)); +} /* * Diagnose 14: Input spool file manipulation diff --git a/arch/s390/kernel/diag.c b/arch/s390/kernel/diag.c index c032d11..8237fc0 100644 --- a/arch/s390/kernel/diag.c +++ b/arch/s390/kernel/diag.c @@ -9,27 +9,6 @@ #include /* - * Diagnose 10: Release pages - */ -void diag10(unsigned long addr) -{ - if (addr >= 0x7ff00000) - return; - asm volatile( -#ifdef CONFIG_64BIT - " sam31\n" - " diag %0,%0,0x10\n" - "0: sam64\n" -#else - " diag %0,%0,0x10\n" - "0:\n" -#endif - EX_TABLE(0b, 0b) - : : "a" (addr)); -} -EXPORT_SYMBOL(diag10); - -/* * Diagnose 14: Input spool file manipulation */ int diag14(unsigned long rx, unsigned long ry1, unsigned long subcode) diff --git a/arch/s390/mm/cmm.c b/arch/s390/mm/cmm.c index c66ffd8..1f1dba9 100644 --- a/arch/s390/mm/cmm.c +++ b/arch/s390/mm/cmm.c @@ -91,7 +91,7 @@ static long cmm_alloc_pages(long nr, long *counter, } else free_page((unsigned long) npa); } - diag10(addr); + diag10_range(addr >> PAGE_SHIFT, 1); pa->pages[pa->index++] = addr; (*counter)++; spin_unlock(&cmm_lock); -- cgit v0.10.2 From 3d8dcb3c76bb2930798f61675c33cce8945ab988 Mon Sep 17 00:00:00 2001 From: Martin Schwidefsky Date: Tue, 10 May 2011 17:13:42 +0200 Subject: [S390] oprofile: fix min/max interval query checks oprofile_min_interval and oprofile_max_interval are unsigned, checking for negative values doesn't work. Change hwsampler_query_min_interval and hwsampler_query_max_interval to return an unsigned long and check for a zero value instead. Reported-by: Nicolas Kaiser Acked-by: Robert Richter Signed-off-by: Martin Schwidefsky diff --git a/arch/s390/oprofile/hwsampler.c b/arch/s390/oprofile/hwsampler.c index 4952872..33cbd37 100644 --- a/arch/s390/oprofile/hwsampler.c +++ b/arch/s390/oprofile/hwsampler.c @@ -1021,20 +1021,14 @@ deallocate_exit: return rc; } -long hwsampler_query_min_interval(void) +unsigned long hwsampler_query_min_interval(void) { - if (min_sampler_rate) - return min_sampler_rate; - else - return -EINVAL; + return min_sampler_rate; } -long hwsampler_query_max_interval(void) +unsigned long hwsampler_query_max_interval(void) { - if (max_sampler_rate) - return max_sampler_rate; - else - return -EINVAL; + return max_sampler_rate; } unsigned long hwsampler_get_sample_overflow_count(unsigned int cpu) diff --git a/arch/s390/oprofile/hwsampler.h b/arch/s390/oprofile/hwsampler.h index 8c72b59..1912f3b 100644 --- a/arch/s390/oprofile/hwsampler.h +++ b/arch/s390/oprofile/hwsampler.h @@ -102,8 +102,8 @@ int hwsampler_setup(void); int hwsampler_shutdown(void); int hwsampler_allocate(unsigned long sdbt, unsigned long sdb); int hwsampler_deallocate(void); -long hwsampler_query_min_interval(void); -long hwsampler_query_max_interval(void); +unsigned long hwsampler_query_min_interval(void); +unsigned long hwsampler_query_max_interval(void); int hwsampler_start_all(unsigned long interval); int hwsampler_stop_all(void); int hwsampler_deactivate(unsigned int cpu); diff --git a/arch/s390/oprofile/init.c b/arch/s390/oprofile/init.c index c63d7e5..5995e9b 100644 --- a/arch/s390/oprofile/init.c +++ b/arch/s390/oprofile/init.c @@ -145,15 +145,11 @@ static int oprofile_hwsampler_init(struct oprofile_operations *ops) * create hwsampler files only if hwsampler_setup() succeeds. */ oprofile_min_interval = hwsampler_query_min_interval(); - if (oprofile_min_interval < 0) { - oprofile_min_interval = 0; + if (oprofile_min_interval == 0) return -ENODEV; - } oprofile_max_interval = hwsampler_query_max_interval(); - if (oprofile_max_interval < 0) { - oprofile_max_interval = 0; + if (oprofile_max_interval == 0) return -ENODEV; - } if (oprofile_timer_init(ops)) return -ENODEV; -- cgit v0.10.2 From badb8bb983e9cf5b7a872e0a4f6ebeac2b1ce133 Mon Sep 17 00:00:00 2001 From: Martin Schwidefsky Date: Tue, 10 May 2011 17:13:43 +0200 Subject: [S390] fix alloc_pgste check in init_new_context Processes started with kernel_execve from a kernel thread will have current->mm==NULL. Reading current->mm->context.alloc_pgste will read a more or less random bit from lowcore in this case. If the bit turns out to be set the whole process tree started this way will allocate page table extensions although they have no need for it. Signed-off-by: Martin Schwidefsky diff --git a/arch/s390/include/asm/mmu_context.h b/arch/s390/include/asm/mmu_context.h index a6f0e7c..8c277ca 100644 --- a/arch/s390/include/asm/mmu_context.h +++ b/arch/s390/include/asm/mmu_context.h @@ -23,7 +23,7 @@ static inline int init_new_context(struct task_struct *tsk, #ifdef CONFIG_64BIT mm->context.asce_bits |= _ASCE_TYPE_REGION3; #endif - if (current->mm->context.alloc_pgste) { + if (current->mm && current->mm->context.alloc_pgste) { /* * alloc_pgste indicates, that any NEW context will be created * with extended page tables. The old context is unchanged. The -- cgit v0.10.2 From fffcda1183e93df84ad73ba7eb7782a5c354e2b3 Mon Sep 17 00:00:00 2001 From: Joerg Roedel Date: Tue, 10 May 2011 17:22:06 +0200 Subject: x86, gart: Rename pci-gart_64.c to amd_gart_64.c This file only contains code relevant for the northbridge gart in AMD processors. This patch renames the file to represent this fact in the filename. Signed-off-by: Joerg Roedel diff --git a/Documentation/x86/x86_64/boot-options.txt b/Documentation/x86/x86_64/boot-options.txt index 092e596..c54b4f5 100644 --- a/Documentation/x86/x86_64/boot-options.txt +++ b/Documentation/x86/x86_64/boot-options.txt @@ -206,7 +206,7 @@ IOMMU (input/output memory management unit) (e.g. because you have < 3 GB memory). Kernel boot message: "PCI-DMA: Disabling IOMMU" - 2. : AMD GART based hardware IOMMU. + 2. : AMD GART based hardware IOMMU. Kernel boot message: "PCI-DMA: using GART IOMMU" 3. : Software IOMMU implementation. Used diff --git a/arch/x86/kernel/Makefile b/arch/x86/kernel/Makefile index 7338ef2..97ebf82e 100644 --- a/arch/x86/kernel/Makefile +++ b/arch/x86/kernel/Makefile @@ -117,7 +117,7 @@ obj-$(CONFIG_OF) += devicetree.o ifeq ($(CONFIG_X86_64),y) obj-$(CONFIG_AUDIT) += audit_64.o - obj-$(CONFIG_GART_IOMMU) += pci-gart_64.o aperture_64.o + obj-$(CONFIG_GART_IOMMU) += amd_gart_64.o aperture_64.o obj-$(CONFIG_CALGARY_IOMMU) += pci-calgary_64.o tce_64.o obj-$(CONFIG_AMD_IOMMU) += amd_iommu_init.o amd_iommu.o diff --git a/arch/x86/kernel/amd_gart_64.c b/arch/x86/kernel/amd_gart_64.c new file mode 100644 index 0000000..b117efd --- /dev/null +++ b/arch/x86/kernel/amd_gart_64.c @@ -0,0 +1,898 @@ +/* + * Dynamic DMA mapping support for AMD Hammer. + * + * Use the integrated AGP GART in the Hammer northbridge as an IOMMU for PCI. + * This allows to use PCI devices that only support 32bit addresses on systems + * with more than 4GB. + * + * See Documentation/PCI/PCI-DMA-mapping.txt for the interface specification. + * + * Copyright 2002 Andi Kleen, SuSE Labs. + * Subject to the GNU General Public License v2 only. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static unsigned long iommu_bus_base; /* GART remapping area (physical) */ +static unsigned long iommu_size; /* size of remapping area bytes */ +static unsigned long iommu_pages; /* .. and in pages */ + +static u32 *iommu_gatt_base; /* Remapping table */ + +static dma_addr_t bad_dma_addr; + +/* + * If this is disabled the IOMMU will use an optimized flushing strategy + * of only flushing when an mapping is reused. With it true the GART is + * flushed for every mapping. Problem is that doing the lazy flush seems + * to trigger bugs with some popular PCI cards, in particular 3ware (but + * has been also also seen with Qlogic at least). + */ +static int iommu_fullflush = 1; + +/* Allocation bitmap for the remapping area: */ +static DEFINE_SPINLOCK(iommu_bitmap_lock); +/* Guarded by iommu_bitmap_lock: */ +static unsigned long *iommu_gart_bitmap; + +static u32 gart_unmapped_entry; + +#define GPTE_VALID 1 +#define GPTE_COHERENT 2 +#define GPTE_ENCODE(x) \ + (((x) & 0xfffff000) | (((x) >> 32) << 4) | GPTE_VALID | GPTE_COHERENT) +#define GPTE_DECODE(x) (((x) & 0xfffff000) | (((u64)(x) & 0xff0) << 28)) + +#define EMERGENCY_PAGES 32 /* = 128KB */ + +#ifdef CONFIG_AGP +#define AGPEXTERN extern +#else +#define AGPEXTERN +#endif + +/* GART can only remap to physical addresses < 1TB */ +#define GART_MAX_PHYS_ADDR (1ULL << 40) + +/* backdoor interface to AGP driver */ +AGPEXTERN int agp_memory_reserved; +AGPEXTERN __u32 *agp_gatt_table; + +static unsigned long next_bit; /* protected by iommu_bitmap_lock */ +static bool need_flush; /* global flush state. set for each gart wrap */ + +static unsigned long alloc_iommu(struct device *dev, int size, + unsigned long align_mask) +{ + unsigned long offset, flags; + unsigned long boundary_size; + unsigned long base_index; + + base_index = ALIGN(iommu_bus_base & dma_get_seg_boundary(dev), + PAGE_SIZE) >> PAGE_SHIFT; + boundary_size = ALIGN((u64)dma_get_seg_boundary(dev) + 1, + PAGE_SIZE) >> PAGE_SHIFT; + + spin_lock_irqsave(&iommu_bitmap_lock, flags); + offset = iommu_area_alloc(iommu_gart_bitmap, iommu_pages, next_bit, + size, base_index, boundary_size, align_mask); + if (offset == -1) { + need_flush = true; + offset = iommu_area_alloc(iommu_gart_bitmap, iommu_pages, 0, + size, base_index, boundary_size, + align_mask); + } + if (offset != -1) { + next_bit = offset+size; + if (next_bit >= iommu_pages) { + next_bit = 0; + need_flush = true; + } + } + if (iommu_fullflush) + need_flush = true; + spin_unlock_irqrestore(&iommu_bitmap_lock, flags); + + return offset; +} + +static void free_iommu(unsigned long offset, int size) +{ + unsigned long flags; + + spin_lock_irqsave(&iommu_bitmap_lock, flags); + bitmap_clear(iommu_gart_bitmap, offset, size); + if (offset >= next_bit) + next_bit = offset + size; + spin_unlock_irqrestore(&iommu_bitmap_lock, flags); +} + +/* + * Use global flush state to avoid races with multiple flushers. + */ +static void flush_gart(void) +{ + unsigned long flags; + + spin_lock_irqsave(&iommu_bitmap_lock, flags); + if (need_flush) { + amd_flush_garts(); + need_flush = false; + } + spin_unlock_irqrestore(&iommu_bitmap_lock, flags); +} + +#ifdef CONFIG_IOMMU_LEAK +/* Debugging aid for drivers that don't free their IOMMU tables */ +static int leak_trace; +static int iommu_leak_pages = 20; + +static void dump_leak(void) +{ + static int dump; + + if (dump) + return; + dump = 1; + + show_stack(NULL, NULL); + debug_dma_dump_mappings(NULL); +} +#endif + +static void iommu_full(struct device *dev, size_t size, int dir) +{ + /* + * Ran out of IOMMU space for this operation. This is very bad. + * Unfortunately the drivers cannot handle this operation properly. + * Return some non mapped prereserved space in the aperture and + * let the Northbridge deal with it. This will result in garbage + * in the IO operation. When the size exceeds the prereserved space + * memory corruption will occur or random memory will be DMAed + * out. Hopefully no network devices use single mappings that big. + */ + + dev_err(dev, "PCI-DMA: Out of IOMMU space for %lu bytes\n", size); + + if (size > PAGE_SIZE*EMERGENCY_PAGES) { + if (dir == PCI_DMA_FROMDEVICE || dir == PCI_DMA_BIDIRECTIONAL) + panic("PCI-DMA: Memory would be corrupted\n"); + if (dir == PCI_DMA_TODEVICE || dir == PCI_DMA_BIDIRECTIONAL) + panic(KERN_ERR + "PCI-DMA: Random memory would be DMAed\n"); + } +#ifdef CONFIG_IOMMU_LEAK + dump_leak(); +#endif +} + +static inline int +need_iommu(struct device *dev, unsigned long addr, size_t size) +{ + return force_iommu || !dma_capable(dev, addr, size); +} + +static inline int +nonforced_iommu(struct device *dev, unsigned long addr, size_t size) +{ + return !dma_capable(dev, addr, size); +} + +/* Map a single continuous physical area into the IOMMU. + * Caller needs to check if the iommu is needed and flush. + */ +static dma_addr_t dma_map_area(struct device *dev, dma_addr_t phys_mem, + size_t size, int dir, unsigned long align_mask) +{ + unsigned long npages = iommu_num_pages(phys_mem, size, PAGE_SIZE); + unsigned long iommu_page; + int i; + + if (unlikely(phys_mem + size > GART_MAX_PHYS_ADDR)) + return bad_dma_addr; + + iommu_page = alloc_iommu(dev, npages, align_mask); + if (iommu_page == -1) { + if (!nonforced_iommu(dev, phys_mem, size)) + return phys_mem; + if (panic_on_overflow) + panic("dma_map_area overflow %lu bytes\n", size); + iommu_full(dev, size, dir); + return bad_dma_addr; + } + + for (i = 0; i < npages; i++) { + iommu_gatt_base[iommu_page + i] = GPTE_ENCODE(phys_mem); + phys_mem += PAGE_SIZE; + } + return iommu_bus_base + iommu_page*PAGE_SIZE + (phys_mem & ~PAGE_MASK); +} + +/* Map a single area into the IOMMU */ +static dma_addr_t gart_map_page(struct device *dev, struct page *page, + unsigned long offset, size_t size, + enum dma_data_direction dir, + struct dma_attrs *attrs) +{ + unsigned long bus; + phys_addr_t paddr = page_to_phys(page) + offset; + + if (!dev) + dev = &x86_dma_fallback_dev; + + if (!need_iommu(dev, paddr, size)) + return paddr; + + bus = dma_map_area(dev, paddr, size, dir, 0); + flush_gart(); + + return bus; +} + +/* + * Free a DMA mapping. + */ +static void gart_unmap_page(struct device *dev, dma_addr_t dma_addr, + size_t size, enum dma_data_direction dir, + struct dma_attrs *attrs) +{ + unsigned long iommu_page; + int npages; + int i; + + if (dma_addr < iommu_bus_base + EMERGENCY_PAGES*PAGE_SIZE || + dma_addr >= iommu_bus_base + iommu_size) + return; + + iommu_page = (dma_addr - iommu_bus_base)>>PAGE_SHIFT; + npages = iommu_num_pages(dma_addr, size, PAGE_SIZE); + for (i = 0; i < npages; i++) { + iommu_gatt_base[iommu_page + i] = gart_unmapped_entry; + } + free_iommu(iommu_page, npages); +} + +/* + * Wrapper for pci_unmap_single working with scatterlists. + */ +static void gart_unmap_sg(struct device *dev, struct scatterlist *sg, int nents, + enum dma_data_direction dir, struct dma_attrs *attrs) +{ + struct scatterlist *s; + int i; + + for_each_sg(sg, s, nents, i) { + if (!s->dma_length || !s->length) + break; + gart_unmap_page(dev, s->dma_address, s->dma_length, dir, NULL); + } +} + +/* Fallback for dma_map_sg in case of overflow */ +static int dma_map_sg_nonforce(struct device *dev, struct scatterlist *sg, + int nents, int dir) +{ + struct scatterlist *s; + int i; + +#ifdef CONFIG_IOMMU_DEBUG + pr_debug("dma_map_sg overflow\n"); +#endif + + for_each_sg(sg, s, nents, i) { + unsigned long addr = sg_phys(s); + + if (nonforced_iommu(dev, addr, s->length)) { + addr = dma_map_area(dev, addr, s->length, dir, 0); + if (addr == bad_dma_addr) { + if (i > 0) + gart_unmap_sg(dev, sg, i, dir, NULL); + nents = 0; + sg[0].dma_length = 0; + break; + } + } + s->dma_address = addr; + s->dma_length = s->length; + } + flush_gart(); + + return nents; +} + +/* Map multiple scatterlist entries continuous into the first. */ +static int __dma_map_cont(struct device *dev, struct scatterlist *start, + int nelems, struct scatterlist *sout, + unsigned long pages) +{ + unsigned long iommu_start = alloc_iommu(dev, pages, 0); + unsigned long iommu_page = iommu_start; + struct scatterlist *s; + int i; + + if (iommu_start == -1) + return -1; + + for_each_sg(start, s, nelems, i) { + unsigned long pages, addr; + unsigned long phys_addr = s->dma_address; + + BUG_ON(s != start && s->offset); + if (s == start) { + sout->dma_address = iommu_bus_base; + sout->dma_address += iommu_page*PAGE_SIZE + s->offset; + sout->dma_length = s->length; + } else { + sout->dma_length += s->length; + } + + addr = phys_addr; + pages = iommu_num_pages(s->offset, s->length, PAGE_SIZE); + while (pages--) { + iommu_gatt_base[iommu_page] = GPTE_ENCODE(addr); + addr += PAGE_SIZE; + iommu_page++; + } + } + BUG_ON(iommu_page - iommu_start != pages); + + return 0; +} + +static inline int +dma_map_cont(struct device *dev, struct scatterlist *start, int nelems, + struct scatterlist *sout, unsigned long pages, int need) +{ + if (!need) { + BUG_ON(nelems != 1); + sout->dma_address = start->dma_address; + sout->dma_length = start->length; + return 0; + } + return __dma_map_cont(dev, start, nelems, sout, pages); +} + +/* + * DMA map all entries in a scatterlist. + * Merge chunks that have page aligned sizes into a continuous mapping. + */ +static int gart_map_sg(struct device *dev, struct scatterlist *sg, int nents, + enum dma_data_direction dir, struct dma_attrs *attrs) +{ + struct scatterlist *s, *ps, *start_sg, *sgmap; + int need = 0, nextneed, i, out, start; + unsigned long pages = 0; + unsigned int seg_size; + unsigned int max_seg_size; + + if (nents == 0) + return 0; + + if (!dev) + dev = &x86_dma_fallback_dev; + + out = 0; + start = 0; + start_sg = sg; + sgmap = sg; + seg_size = 0; + max_seg_size = dma_get_max_seg_size(dev); + ps = NULL; /* shut up gcc */ + + for_each_sg(sg, s, nents, i) { + dma_addr_t addr = sg_phys(s); + + s->dma_address = addr; + BUG_ON(s->length == 0); + + nextneed = need_iommu(dev, addr, s->length); + + /* Handle the previous not yet processed entries */ + if (i > start) { + /* + * Can only merge when the last chunk ends on a + * page boundary and the new one doesn't have an + * offset. + */ + if (!iommu_merge || !nextneed || !need || s->offset || + (s->length + seg_size > max_seg_size) || + (ps->offset + ps->length) % PAGE_SIZE) { + if (dma_map_cont(dev, start_sg, i - start, + sgmap, pages, need) < 0) + goto error; + out++; + + seg_size = 0; + sgmap = sg_next(sgmap); + pages = 0; + start = i; + start_sg = s; + } + } + + seg_size += s->length; + need = nextneed; + pages += iommu_num_pages(s->offset, s->length, PAGE_SIZE); + ps = s; + } + if (dma_map_cont(dev, start_sg, i - start, sgmap, pages, need) < 0) + goto error; + out++; + flush_gart(); + if (out < nents) { + sgmap = sg_next(sgmap); + sgmap->dma_length = 0; + } + return out; + +error: + flush_gart(); + gart_unmap_sg(dev, sg, out, dir, NULL); + + /* When it was forced or merged try again in a dumb way */ + if (force_iommu || iommu_merge) { + out = dma_map_sg_nonforce(dev, sg, nents, dir); + if (out > 0) + return out; + } + if (panic_on_overflow) + panic("dma_map_sg: overflow on %lu pages\n", pages); + + iommu_full(dev, pages << PAGE_SHIFT, dir); + for_each_sg(sg, s, nents, i) + s->dma_address = bad_dma_addr; + return 0; +} + +/* allocate and map a coherent mapping */ +static void * +gart_alloc_coherent(struct device *dev, size_t size, dma_addr_t *dma_addr, + gfp_t flag) +{ + dma_addr_t paddr; + unsigned long align_mask; + struct page *page; + + if (force_iommu && !(flag & GFP_DMA)) { + flag &= ~(__GFP_DMA | __GFP_HIGHMEM | __GFP_DMA32); + page = alloc_pages(flag | __GFP_ZERO, get_order(size)); + if (!page) + return NULL; + + align_mask = (1UL << get_order(size)) - 1; + paddr = dma_map_area(dev, page_to_phys(page), size, + DMA_BIDIRECTIONAL, align_mask); + + flush_gart(); + if (paddr != bad_dma_addr) { + *dma_addr = paddr; + return page_address(page); + } + __free_pages(page, get_order(size)); + } else + return dma_generic_alloc_coherent(dev, size, dma_addr, flag); + + return NULL; +} + +/* free a coherent mapping */ +static void +gart_free_coherent(struct device *dev, size_t size, void *vaddr, + dma_addr_t dma_addr) +{ + gart_unmap_page(dev, dma_addr, size, DMA_BIDIRECTIONAL, NULL); + free_pages((unsigned long)vaddr, get_order(size)); +} + +static int gart_mapping_error(struct device *dev, dma_addr_t dma_addr) +{ + return (dma_addr == bad_dma_addr); +} + +static int no_agp; + +static __init unsigned long check_iommu_size(unsigned long aper, u64 aper_size) +{ + unsigned long a; + + if (!iommu_size) { + iommu_size = aper_size; + if (!no_agp) + iommu_size /= 2; + } + + a = aper + iommu_size; + iommu_size -= round_up(a, PMD_PAGE_SIZE) - a; + + if (iommu_size < 64*1024*1024) { + pr_warning( + "PCI-DMA: Warning: Small IOMMU %luMB." + " Consider increasing the AGP aperture in BIOS\n", + iommu_size >> 20); + } + + return iommu_size; +} + +static __init unsigned read_aperture(struct pci_dev *dev, u32 *size) +{ + unsigned aper_size = 0, aper_base_32, aper_order; + u64 aper_base; + + pci_read_config_dword(dev, AMD64_GARTAPERTUREBASE, &aper_base_32); + pci_read_config_dword(dev, AMD64_GARTAPERTURECTL, &aper_order); + aper_order = (aper_order >> 1) & 7; + + aper_base = aper_base_32 & 0x7fff; + aper_base <<= 25; + + aper_size = (32 * 1024 * 1024) << aper_order; + if (aper_base + aper_size > 0x100000000UL || !aper_size) + aper_base = 0; + + *size = aper_size; + return aper_base; +} + +static void enable_gart_translations(void) +{ + int i; + + if (!amd_nb_has_feature(AMD_NB_GART)) + return; + + for (i = 0; i < amd_nb_num(); i++) { + struct pci_dev *dev = node_to_amd_nb(i)->misc; + + enable_gart_translation(dev, __pa(agp_gatt_table)); + } + + /* Flush the GART-TLB to remove stale entries */ + amd_flush_garts(); +} + +/* + * If fix_up_north_bridges is set, the north bridges have to be fixed up on + * resume in the same way as they are handled in gart_iommu_hole_init(). + */ +static bool fix_up_north_bridges; +static u32 aperture_order; +static u32 aperture_alloc; + +void set_up_gart_resume(u32 aper_order, u32 aper_alloc) +{ + fix_up_north_bridges = true; + aperture_order = aper_order; + aperture_alloc = aper_alloc; +} + +static void gart_fixup_northbridges(void) +{ + int i; + + if (!fix_up_north_bridges) + return; + + if (!amd_nb_has_feature(AMD_NB_GART)) + return; + + pr_info("PCI-DMA: Restoring GART aperture settings\n"); + + for (i = 0; i < amd_nb_num(); i++) { + struct pci_dev *dev = node_to_amd_nb(i)->misc; + + /* + * Don't enable translations just yet. That is the next + * step. Restore the pre-suspend aperture settings. + */ + gart_set_size_and_enable(dev, aperture_order); + pci_write_config_dword(dev, AMD64_GARTAPERTUREBASE, aperture_alloc >> 25); + } +} + +static void gart_resume(void) +{ + pr_info("PCI-DMA: Resuming GART IOMMU\n"); + + gart_fixup_northbridges(); + + enable_gart_translations(); +} + +static struct syscore_ops gart_syscore_ops = { + .resume = gart_resume, + +}; + +/* + * Private Northbridge GATT initialization in case we cannot use the + * AGP driver for some reason. + */ +static __init int init_amd_gatt(struct agp_kern_info *info) +{ + unsigned aper_size, gatt_size, new_aper_size; + unsigned aper_base, new_aper_base; + struct pci_dev *dev; + void *gatt; + int i; + + pr_info("PCI-DMA: Disabling AGP.\n"); + + aper_size = aper_base = info->aper_size = 0; + dev = NULL; + for (i = 0; i < amd_nb_num(); i++) { + dev = node_to_amd_nb(i)->misc; + new_aper_base = read_aperture(dev, &new_aper_size); + if (!new_aper_base) + goto nommu; + + if (!aper_base) { + aper_size = new_aper_size; + aper_base = new_aper_base; + } + if (aper_size != new_aper_size || aper_base != new_aper_base) + goto nommu; + } + if (!aper_base) + goto nommu; + + info->aper_base = aper_base; + info->aper_size = aper_size >> 20; + + gatt_size = (aper_size >> PAGE_SHIFT) * sizeof(u32); + gatt = (void *)__get_free_pages(GFP_KERNEL | __GFP_ZERO, + get_order(gatt_size)); + if (!gatt) + panic("Cannot allocate GATT table"); + if (set_memory_uc((unsigned long)gatt, gatt_size >> PAGE_SHIFT)) + panic("Could not set GART PTEs to uncacheable pages"); + + agp_gatt_table = gatt; + + register_syscore_ops(&gart_syscore_ops); + + flush_gart(); + + pr_info("PCI-DMA: aperture base @ %x size %u KB\n", + aper_base, aper_size>>10); + + return 0; + + nommu: + /* Should not happen anymore */ + pr_warning("PCI-DMA: More than 4GB of RAM and no IOMMU\n" + "falling back to iommu=soft.\n"); + return -1; +} + +static struct dma_map_ops gart_dma_ops = { + .map_sg = gart_map_sg, + .unmap_sg = gart_unmap_sg, + .map_page = gart_map_page, + .unmap_page = gart_unmap_page, + .alloc_coherent = gart_alloc_coherent, + .free_coherent = gart_free_coherent, + .mapping_error = gart_mapping_error, +}; + +static void gart_iommu_shutdown(void) +{ + struct pci_dev *dev; + int i; + + /* don't shutdown it if there is AGP installed */ + if (!no_agp) + return; + + if (!amd_nb_has_feature(AMD_NB_GART)) + return; + + for (i = 0; i < amd_nb_num(); i++) { + u32 ctl; + + dev = node_to_amd_nb(i)->misc; + pci_read_config_dword(dev, AMD64_GARTAPERTURECTL, &ctl); + + ctl &= ~GARTEN; + + pci_write_config_dword(dev, AMD64_GARTAPERTURECTL, ctl); + } +} + +int __init gart_iommu_init(void) +{ + struct agp_kern_info info; + unsigned long iommu_start; + unsigned long aper_base, aper_size; + unsigned long start_pfn, end_pfn; + unsigned long scratch; + long i; + + if (!amd_nb_has_feature(AMD_NB_GART)) + return 0; + +#ifndef CONFIG_AGP_AMD64 + no_agp = 1; +#else + /* Makefile puts PCI initialization via subsys_initcall first. */ + /* Add other AMD AGP bridge drivers here */ + no_agp = no_agp || + (agp_amd64_init() < 0) || + (agp_copy_info(agp_bridge, &info) < 0); +#endif + + if (no_iommu || + (!force_iommu && max_pfn <= MAX_DMA32_PFN) || + !gart_iommu_aperture || + (no_agp && init_amd_gatt(&info) < 0)) { + if (max_pfn > MAX_DMA32_PFN) { + pr_warning("More than 4GB of memory but GART IOMMU not available.\n"); + pr_warning("falling back to iommu=soft.\n"); + } + return 0; + } + + /* need to map that range */ + aper_size = info.aper_size << 20; + aper_base = info.aper_base; + end_pfn = (aper_base>>PAGE_SHIFT) + (aper_size>>PAGE_SHIFT); + + if (end_pfn > max_low_pfn_mapped) { + start_pfn = (aper_base>>PAGE_SHIFT); + init_memory_mapping(start_pfn<> PAGE_SHIFT; + + iommu_gart_bitmap = (void *) __get_free_pages(GFP_KERNEL | __GFP_ZERO, + get_order(iommu_pages/8)); + if (!iommu_gart_bitmap) + panic("Cannot allocate iommu bitmap\n"); + +#ifdef CONFIG_IOMMU_LEAK + if (leak_trace) { + int ret; + + ret = dma_debug_resize_entries(iommu_pages); + if (ret) + pr_debug("PCI-DMA: Cannot trace all the entries\n"); + } +#endif + + /* + * Out of IOMMU space handling. + * Reserve some invalid pages at the beginning of the GART. + */ + bitmap_set(iommu_gart_bitmap, 0, EMERGENCY_PAGES); + + pr_info("PCI-DMA: Reserving %luMB of IOMMU area in the AGP aperture\n", + iommu_size >> 20); + + agp_memory_reserved = iommu_size; + iommu_start = aper_size - iommu_size; + iommu_bus_base = info.aper_base + iommu_start; + bad_dma_addr = iommu_bus_base; + iommu_gatt_base = agp_gatt_table + (iommu_start>>PAGE_SHIFT); + + /* + * Unmap the IOMMU part of the GART. The alias of the page is + * always mapped with cache enabled and there is no full cache + * coherency across the GART remapping. The unmapping avoids + * automatic prefetches from the CPU allocating cache lines in + * there. All CPU accesses are done via the direct mapping to + * the backing memory. The GART address is only used by PCI + * devices. + */ + set_memory_np((unsigned long)__va(iommu_bus_base), + iommu_size >> PAGE_SHIFT); + /* + * Tricky. The GART table remaps the physical memory range, + * so the CPU wont notice potential aliases and if the memory + * is remapped to UC later on, we might surprise the PCI devices + * with a stray writeout of a cacheline. So play it sure and + * do an explicit, full-scale wbinvd() _after_ having marked all + * the pages as Not-Present: + */ + wbinvd(); + + /* + * Now all caches are flushed and we can safely enable + * GART hardware. Doing it early leaves the possibility + * of stale cache entries that can lead to GART PTE + * errors. + */ + enable_gart_translations(); + + /* + * Try to workaround a bug (thanks to BenH): + * Set unmapped entries to a scratch page instead of 0. + * Any prefetches that hit unmapped entries won't get an bus abort + * then. (P2P bridge may be prefetching on DMA reads). + */ + scratch = get_zeroed_page(GFP_KERNEL); + if (!scratch) + panic("Cannot allocate iommu scratch page"); + gart_unmapped_entry = GPTE_ENCODE(__pa(scratch)); + for (i = EMERGENCY_PAGES; i < iommu_pages; i++) + iommu_gatt_base[i] = gart_unmapped_entry; + + flush_gart(); + dma_ops = &gart_dma_ops; + x86_platform.iommu_shutdown = gart_iommu_shutdown; + swiotlb = 0; + + return 0; +} + +void __init gart_parse_options(char *p) +{ + int arg; + +#ifdef CONFIG_IOMMU_LEAK + if (!strncmp(p, "leak", 4)) { + leak_trace = 1; + p += 4; + if (*p == '=') + ++p; + if (isdigit(*p) && get_option(&p, &arg)) + iommu_leak_pages = arg; + } +#endif + if (isdigit(*p) && get_option(&p, &arg)) + iommu_size = arg; + if (!strncmp(p, "fullflush", 9)) + iommu_fullflush = 1; + if (!strncmp(p, "nofullflush", 11)) + iommu_fullflush = 0; + if (!strncmp(p, "noagp", 5)) + no_agp = 1; + if (!strncmp(p, "noaperture", 10)) + fix_aperture = 0; + /* duplicated from pci-dma.c */ + if (!strncmp(p, "force", 5)) + gart_iommu_aperture_allowed = 1; + if (!strncmp(p, "allowed", 7)) + gart_iommu_aperture_allowed = 1; + if (!strncmp(p, "memaper", 7)) { + fallback_aper_force = 1; + p += 7; + if (*p == '=') { + ++p; + if (get_option(&p, &arg)) + fallback_aper_order = arg; + } + } +} +IOMMU_INIT_POST(gart_iommu_hole_init); diff --git a/arch/x86/kernel/pci-gart_64.c b/arch/x86/kernel/pci-gart_64.c deleted file mode 100644 index b117efd..0000000 --- a/arch/x86/kernel/pci-gart_64.c +++ /dev/null @@ -1,898 +0,0 @@ -/* - * Dynamic DMA mapping support for AMD Hammer. - * - * Use the integrated AGP GART in the Hammer northbridge as an IOMMU for PCI. - * This allows to use PCI devices that only support 32bit addresses on systems - * with more than 4GB. - * - * See Documentation/PCI/PCI-DMA-mapping.txt for the interface specification. - * - * Copyright 2002 Andi Kleen, SuSE Labs. - * Subject to the GNU General Public License v2 only. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -static unsigned long iommu_bus_base; /* GART remapping area (physical) */ -static unsigned long iommu_size; /* size of remapping area bytes */ -static unsigned long iommu_pages; /* .. and in pages */ - -static u32 *iommu_gatt_base; /* Remapping table */ - -static dma_addr_t bad_dma_addr; - -/* - * If this is disabled the IOMMU will use an optimized flushing strategy - * of only flushing when an mapping is reused. With it true the GART is - * flushed for every mapping. Problem is that doing the lazy flush seems - * to trigger bugs with some popular PCI cards, in particular 3ware (but - * has been also also seen with Qlogic at least). - */ -static int iommu_fullflush = 1; - -/* Allocation bitmap for the remapping area: */ -static DEFINE_SPINLOCK(iommu_bitmap_lock); -/* Guarded by iommu_bitmap_lock: */ -static unsigned long *iommu_gart_bitmap; - -static u32 gart_unmapped_entry; - -#define GPTE_VALID 1 -#define GPTE_COHERENT 2 -#define GPTE_ENCODE(x) \ - (((x) & 0xfffff000) | (((x) >> 32) << 4) | GPTE_VALID | GPTE_COHERENT) -#define GPTE_DECODE(x) (((x) & 0xfffff000) | (((u64)(x) & 0xff0) << 28)) - -#define EMERGENCY_PAGES 32 /* = 128KB */ - -#ifdef CONFIG_AGP -#define AGPEXTERN extern -#else -#define AGPEXTERN -#endif - -/* GART can only remap to physical addresses < 1TB */ -#define GART_MAX_PHYS_ADDR (1ULL << 40) - -/* backdoor interface to AGP driver */ -AGPEXTERN int agp_memory_reserved; -AGPEXTERN __u32 *agp_gatt_table; - -static unsigned long next_bit; /* protected by iommu_bitmap_lock */ -static bool need_flush; /* global flush state. set for each gart wrap */ - -static unsigned long alloc_iommu(struct device *dev, int size, - unsigned long align_mask) -{ - unsigned long offset, flags; - unsigned long boundary_size; - unsigned long base_index; - - base_index = ALIGN(iommu_bus_base & dma_get_seg_boundary(dev), - PAGE_SIZE) >> PAGE_SHIFT; - boundary_size = ALIGN((u64)dma_get_seg_boundary(dev) + 1, - PAGE_SIZE) >> PAGE_SHIFT; - - spin_lock_irqsave(&iommu_bitmap_lock, flags); - offset = iommu_area_alloc(iommu_gart_bitmap, iommu_pages, next_bit, - size, base_index, boundary_size, align_mask); - if (offset == -1) { - need_flush = true; - offset = iommu_area_alloc(iommu_gart_bitmap, iommu_pages, 0, - size, base_index, boundary_size, - align_mask); - } - if (offset != -1) { - next_bit = offset+size; - if (next_bit >= iommu_pages) { - next_bit = 0; - need_flush = true; - } - } - if (iommu_fullflush) - need_flush = true; - spin_unlock_irqrestore(&iommu_bitmap_lock, flags); - - return offset; -} - -static void free_iommu(unsigned long offset, int size) -{ - unsigned long flags; - - spin_lock_irqsave(&iommu_bitmap_lock, flags); - bitmap_clear(iommu_gart_bitmap, offset, size); - if (offset >= next_bit) - next_bit = offset + size; - spin_unlock_irqrestore(&iommu_bitmap_lock, flags); -} - -/* - * Use global flush state to avoid races with multiple flushers. - */ -static void flush_gart(void) -{ - unsigned long flags; - - spin_lock_irqsave(&iommu_bitmap_lock, flags); - if (need_flush) { - amd_flush_garts(); - need_flush = false; - } - spin_unlock_irqrestore(&iommu_bitmap_lock, flags); -} - -#ifdef CONFIG_IOMMU_LEAK -/* Debugging aid for drivers that don't free their IOMMU tables */ -static int leak_trace; -static int iommu_leak_pages = 20; - -static void dump_leak(void) -{ - static int dump; - - if (dump) - return; - dump = 1; - - show_stack(NULL, NULL); - debug_dma_dump_mappings(NULL); -} -#endif - -static void iommu_full(struct device *dev, size_t size, int dir) -{ - /* - * Ran out of IOMMU space for this operation. This is very bad. - * Unfortunately the drivers cannot handle this operation properly. - * Return some non mapped prereserved space in the aperture and - * let the Northbridge deal with it. This will result in garbage - * in the IO operation. When the size exceeds the prereserved space - * memory corruption will occur or random memory will be DMAed - * out. Hopefully no network devices use single mappings that big. - */ - - dev_err(dev, "PCI-DMA: Out of IOMMU space for %lu bytes\n", size); - - if (size > PAGE_SIZE*EMERGENCY_PAGES) { - if (dir == PCI_DMA_FROMDEVICE || dir == PCI_DMA_BIDIRECTIONAL) - panic("PCI-DMA: Memory would be corrupted\n"); - if (dir == PCI_DMA_TODEVICE || dir == PCI_DMA_BIDIRECTIONAL) - panic(KERN_ERR - "PCI-DMA: Random memory would be DMAed\n"); - } -#ifdef CONFIG_IOMMU_LEAK - dump_leak(); -#endif -} - -static inline int -need_iommu(struct device *dev, unsigned long addr, size_t size) -{ - return force_iommu || !dma_capable(dev, addr, size); -} - -static inline int -nonforced_iommu(struct device *dev, unsigned long addr, size_t size) -{ - return !dma_capable(dev, addr, size); -} - -/* Map a single continuous physical area into the IOMMU. - * Caller needs to check if the iommu is needed and flush. - */ -static dma_addr_t dma_map_area(struct device *dev, dma_addr_t phys_mem, - size_t size, int dir, unsigned long align_mask) -{ - unsigned long npages = iommu_num_pages(phys_mem, size, PAGE_SIZE); - unsigned long iommu_page; - int i; - - if (unlikely(phys_mem + size > GART_MAX_PHYS_ADDR)) - return bad_dma_addr; - - iommu_page = alloc_iommu(dev, npages, align_mask); - if (iommu_page == -1) { - if (!nonforced_iommu(dev, phys_mem, size)) - return phys_mem; - if (panic_on_overflow) - panic("dma_map_area overflow %lu bytes\n", size); - iommu_full(dev, size, dir); - return bad_dma_addr; - } - - for (i = 0; i < npages; i++) { - iommu_gatt_base[iommu_page + i] = GPTE_ENCODE(phys_mem); - phys_mem += PAGE_SIZE; - } - return iommu_bus_base + iommu_page*PAGE_SIZE + (phys_mem & ~PAGE_MASK); -} - -/* Map a single area into the IOMMU */ -static dma_addr_t gart_map_page(struct device *dev, struct page *page, - unsigned long offset, size_t size, - enum dma_data_direction dir, - struct dma_attrs *attrs) -{ - unsigned long bus; - phys_addr_t paddr = page_to_phys(page) + offset; - - if (!dev) - dev = &x86_dma_fallback_dev; - - if (!need_iommu(dev, paddr, size)) - return paddr; - - bus = dma_map_area(dev, paddr, size, dir, 0); - flush_gart(); - - return bus; -} - -/* - * Free a DMA mapping. - */ -static void gart_unmap_page(struct device *dev, dma_addr_t dma_addr, - size_t size, enum dma_data_direction dir, - struct dma_attrs *attrs) -{ - unsigned long iommu_page; - int npages; - int i; - - if (dma_addr < iommu_bus_base + EMERGENCY_PAGES*PAGE_SIZE || - dma_addr >= iommu_bus_base + iommu_size) - return; - - iommu_page = (dma_addr - iommu_bus_base)>>PAGE_SHIFT; - npages = iommu_num_pages(dma_addr, size, PAGE_SIZE); - for (i = 0; i < npages; i++) { - iommu_gatt_base[iommu_page + i] = gart_unmapped_entry; - } - free_iommu(iommu_page, npages); -} - -/* - * Wrapper for pci_unmap_single working with scatterlists. - */ -static void gart_unmap_sg(struct device *dev, struct scatterlist *sg, int nents, - enum dma_data_direction dir, struct dma_attrs *attrs) -{ - struct scatterlist *s; - int i; - - for_each_sg(sg, s, nents, i) { - if (!s->dma_length || !s->length) - break; - gart_unmap_page(dev, s->dma_address, s->dma_length, dir, NULL); - } -} - -/* Fallback for dma_map_sg in case of overflow */ -static int dma_map_sg_nonforce(struct device *dev, struct scatterlist *sg, - int nents, int dir) -{ - struct scatterlist *s; - int i; - -#ifdef CONFIG_IOMMU_DEBUG - pr_debug("dma_map_sg overflow\n"); -#endif - - for_each_sg(sg, s, nents, i) { - unsigned long addr = sg_phys(s); - - if (nonforced_iommu(dev, addr, s->length)) { - addr = dma_map_area(dev, addr, s->length, dir, 0); - if (addr == bad_dma_addr) { - if (i > 0) - gart_unmap_sg(dev, sg, i, dir, NULL); - nents = 0; - sg[0].dma_length = 0; - break; - } - } - s->dma_address = addr; - s->dma_length = s->length; - } - flush_gart(); - - return nents; -} - -/* Map multiple scatterlist entries continuous into the first. */ -static int __dma_map_cont(struct device *dev, struct scatterlist *start, - int nelems, struct scatterlist *sout, - unsigned long pages) -{ - unsigned long iommu_start = alloc_iommu(dev, pages, 0); - unsigned long iommu_page = iommu_start; - struct scatterlist *s; - int i; - - if (iommu_start == -1) - return -1; - - for_each_sg(start, s, nelems, i) { - unsigned long pages, addr; - unsigned long phys_addr = s->dma_address; - - BUG_ON(s != start && s->offset); - if (s == start) { - sout->dma_address = iommu_bus_base; - sout->dma_address += iommu_page*PAGE_SIZE + s->offset; - sout->dma_length = s->length; - } else { - sout->dma_length += s->length; - } - - addr = phys_addr; - pages = iommu_num_pages(s->offset, s->length, PAGE_SIZE); - while (pages--) { - iommu_gatt_base[iommu_page] = GPTE_ENCODE(addr); - addr += PAGE_SIZE; - iommu_page++; - } - } - BUG_ON(iommu_page - iommu_start != pages); - - return 0; -} - -static inline int -dma_map_cont(struct device *dev, struct scatterlist *start, int nelems, - struct scatterlist *sout, unsigned long pages, int need) -{ - if (!need) { - BUG_ON(nelems != 1); - sout->dma_address = start->dma_address; - sout->dma_length = start->length; - return 0; - } - return __dma_map_cont(dev, start, nelems, sout, pages); -} - -/* - * DMA map all entries in a scatterlist. - * Merge chunks that have page aligned sizes into a continuous mapping. - */ -static int gart_map_sg(struct device *dev, struct scatterlist *sg, int nents, - enum dma_data_direction dir, struct dma_attrs *attrs) -{ - struct scatterlist *s, *ps, *start_sg, *sgmap; - int need = 0, nextneed, i, out, start; - unsigned long pages = 0; - unsigned int seg_size; - unsigned int max_seg_size; - - if (nents == 0) - return 0; - - if (!dev) - dev = &x86_dma_fallback_dev; - - out = 0; - start = 0; - start_sg = sg; - sgmap = sg; - seg_size = 0; - max_seg_size = dma_get_max_seg_size(dev); - ps = NULL; /* shut up gcc */ - - for_each_sg(sg, s, nents, i) { - dma_addr_t addr = sg_phys(s); - - s->dma_address = addr; - BUG_ON(s->length == 0); - - nextneed = need_iommu(dev, addr, s->length); - - /* Handle the previous not yet processed entries */ - if (i > start) { - /* - * Can only merge when the last chunk ends on a - * page boundary and the new one doesn't have an - * offset. - */ - if (!iommu_merge || !nextneed || !need || s->offset || - (s->length + seg_size > max_seg_size) || - (ps->offset + ps->length) % PAGE_SIZE) { - if (dma_map_cont(dev, start_sg, i - start, - sgmap, pages, need) < 0) - goto error; - out++; - - seg_size = 0; - sgmap = sg_next(sgmap); - pages = 0; - start = i; - start_sg = s; - } - } - - seg_size += s->length; - need = nextneed; - pages += iommu_num_pages(s->offset, s->length, PAGE_SIZE); - ps = s; - } - if (dma_map_cont(dev, start_sg, i - start, sgmap, pages, need) < 0) - goto error; - out++; - flush_gart(); - if (out < nents) { - sgmap = sg_next(sgmap); - sgmap->dma_length = 0; - } - return out; - -error: - flush_gart(); - gart_unmap_sg(dev, sg, out, dir, NULL); - - /* When it was forced or merged try again in a dumb way */ - if (force_iommu || iommu_merge) { - out = dma_map_sg_nonforce(dev, sg, nents, dir); - if (out > 0) - return out; - } - if (panic_on_overflow) - panic("dma_map_sg: overflow on %lu pages\n", pages); - - iommu_full(dev, pages << PAGE_SHIFT, dir); - for_each_sg(sg, s, nents, i) - s->dma_address = bad_dma_addr; - return 0; -} - -/* allocate and map a coherent mapping */ -static void * -gart_alloc_coherent(struct device *dev, size_t size, dma_addr_t *dma_addr, - gfp_t flag) -{ - dma_addr_t paddr; - unsigned long align_mask; - struct page *page; - - if (force_iommu && !(flag & GFP_DMA)) { - flag &= ~(__GFP_DMA | __GFP_HIGHMEM | __GFP_DMA32); - page = alloc_pages(flag | __GFP_ZERO, get_order(size)); - if (!page) - return NULL; - - align_mask = (1UL << get_order(size)) - 1; - paddr = dma_map_area(dev, page_to_phys(page), size, - DMA_BIDIRECTIONAL, align_mask); - - flush_gart(); - if (paddr != bad_dma_addr) { - *dma_addr = paddr; - return page_address(page); - } - __free_pages(page, get_order(size)); - } else - return dma_generic_alloc_coherent(dev, size, dma_addr, flag); - - return NULL; -} - -/* free a coherent mapping */ -static void -gart_free_coherent(struct device *dev, size_t size, void *vaddr, - dma_addr_t dma_addr) -{ - gart_unmap_page(dev, dma_addr, size, DMA_BIDIRECTIONAL, NULL); - free_pages((unsigned long)vaddr, get_order(size)); -} - -static int gart_mapping_error(struct device *dev, dma_addr_t dma_addr) -{ - return (dma_addr == bad_dma_addr); -} - -static int no_agp; - -static __init unsigned long check_iommu_size(unsigned long aper, u64 aper_size) -{ - unsigned long a; - - if (!iommu_size) { - iommu_size = aper_size; - if (!no_agp) - iommu_size /= 2; - } - - a = aper + iommu_size; - iommu_size -= round_up(a, PMD_PAGE_SIZE) - a; - - if (iommu_size < 64*1024*1024) { - pr_warning( - "PCI-DMA: Warning: Small IOMMU %luMB." - " Consider increasing the AGP aperture in BIOS\n", - iommu_size >> 20); - } - - return iommu_size; -} - -static __init unsigned read_aperture(struct pci_dev *dev, u32 *size) -{ - unsigned aper_size = 0, aper_base_32, aper_order; - u64 aper_base; - - pci_read_config_dword(dev, AMD64_GARTAPERTUREBASE, &aper_base_32); - pci_read_config_dword(dev, AMD64_GARTAPERTURECTL, &aper_order); - aper_order = (aper_order >> 1) & 7; - - aper_base = aper_base_32 & 0x7fff; - aper_base <<= 25; - - aper_size = (32 * 1024 * 1024) << aper_order; - if (aper_base + aper_size > 0x100000000UL || !aper_size) - aper_base = 0; - - *size = aper_size; - return aper_base; -} - -static void enable_gart_translations(void) -{ - int i; - - if (!amd_nb_has_feature(AMD_NB_GART)) - return; - - for (i = 0; i < amd_nb_num(); i++) { - struct pci_dev *dev = node_to_amd_nb(i)->misc; - - enable_gart_translation(dev, __pa(agp_gatt_table)); - } - - /* Flush the GART-TLB to remove stale entries */ - amd_flush_garts(); -} - -/* - * If fix_up_north_bridges is set, the north bridges have to be fixed up on - * resume in the same way as they are handled in gart_iommu_hole_init(). - */ -static bool fix_up_north_bridges; -static u32 aperture_order; -static u32 aperture_alloc; - -void set_up_gart_resume(u32 aper_order, u32 aper_alloc) -{ - fix_up_north_bridges = true; - aperture_order = aper_order; - aperture_alloc = aper_alloc; -} - -static void gart_fixup_northbridges(void) -{ - int i; - - if (!fix_up_north_bridges) - return; - - if (!amd_nb_has_feature(AMD_NB_GART)) - return; - - pr_info("PCI-DMA: Restoring GART aperture settings\n"); - - for (i = 0; i < amd_nb_num(); i++) { - struct pci_dev *dev = node_to_amd_nb(i)->misc; - - /* - * Don't enable translations just yet. That is the next - * step. Restore the pre-suspend aperture settings. - */ - gart_set_size_and_enable(dev, aperture_order); - pci_write_config_dword(dev, AMD64_GARTAPERTUREBASE, aperture_alloc >> 25); - } -} - -static void gart_resume(void) -{ - pr_info("PCI-DMA: Resuming GART IOMMU\n"); - - gart_fixup_northbridges(); - - enable_gart_translations(); -} - -static struct syscore_ops gart_syscore_ops = { - .resume = gart_resume, - -}; - -/* - * Private Northbridge GATT initialization in case we cannot use the - * AGP driver for some reason. - */ -static __init int init_amd_gatt(struct agp_kern_info *info) -{ - unsigned aper_size, gatt_size, new_aper_size; - unsigned aper_base, new_aper_base; - struct pci_dev *dev; - void *gatt; - int i; - - pr_info("PCI-DMA: Disabling AGP.\n"); - - aper_size = aper_base = info->aper_size = 0; - dev = NULL; - for (i = 0; i < amd_nb_num(); i++) { - dev = node_to_amd_nb(i)->misc; - new_aper_base = read_aperture(dev, &new_aper_size); - if (!new_aper_base) - goto nommu; - - if (!aper_base) { - aper_size = new_aper_size; - aper_base = new_aper_base; - } - if (aper_size != new_aper_size || aper_base != new_aper_base) - goto nommu; - } - if (!aper_base) - goto nommu; - - info->aper_base = aper_base; - info->aper_size = aper_size >> 20; - - gatt_size = (aper_size >> PAGE_SHIFT) * sizeof(u32); - gatt = (void *)__get_free_pages(GFP_KERNEL | __GFP_ZERO, - get_order(gatt_size)); - if (!gatt) - panic("Cannot allocate GATT table"); - if (set_memory_uc((unsigned long)gatt, gatt_size >> PAGE_SHIFT)) - panic("Could not set GART PTEs to uncacheable pages"); - - agp_gatt_table = gatt; - - register_syscore_ops(&gart_syscore_ops); - - flush_gart(); - - pr_info("PCI-DMA: aperture base @ %x size %u KB\n", - aper_base, aper_size>>10); - - return 0; - - nommu: - /* Should not happen anymore */ - pr_warning("PCI-DMA: More than 4GB of RAM and no IOMMU\n" - "falling back to iommu=soft.\n"); - return -1; -} - -static struct dma_map_ops gart_dma_ops = { - .map_sg = gart_map_sg, - .unmap_sg = gart_unmap_sg, - .map_page = gart_map_page, - .unmap_page = gart_unmap_page, - .alloc_coherent = gart_alloc_coherent, - .free_coherent = gart_free_coherent, - .mapping_error = gart_mapping_error, -}; - -static void gart_iommu_shutdown(void) -{ - struct pci_dev *dev; - int i; - - /* don't shutdown it if there is AGP installed */ - if (!no_agp) - return; - - if (!amd_nb_has_feature(AMD_NB_GART)) - return; - - for (i = 0; i < amd_nb_num(); i++) { - u32 ctl; - - dev = node_to_amd_nb(i)->misc; - pci_read_config_dword(dev, AMD64_GARTAPERTURECTL, &ctl); - - ctl &= ~GARTEN; - - pci_write_config_dword(dev, AMD64_GARTAPERTURECTL, ctl); - } -} - -int __init gart_iommu_init(void) -{ - struct agp_kern_info info; - unsigned long iommu_start; - unsigned long aper_base, aper_size; - unsigned long start_pfn, end_pfn; - unsigned long scratch; - long i; - - if (!amd_nb_has_feature(AMD_NB_GART)) - return 0; - -#ifndef CONFIG_AGP_AMD64 - no_agp = 1; -#else - /* Makefile puts PCI initialization via subsys_initcall first. */ - /* Add other AMD AGP bridge drivers here */ - no_agp = no_agp || - (agp_amd64_init() < 0) || - (agp_copy_info(agp_bridge, &info) < 0); -#endif - - if (no_iommu || - (!force_iommu && max_pfn <= MAX_DMA32_PFN) || - !gart_iommu_aperture || - (no_agp && init_amd_gatt(&info) < 0)) { - if (max_pfn > MAX_DMA32_PFN) { - pr_warning("More than 4GB of memory but GART IOMMU not available.\n"); - pr_warning("falling back to iommu=soft.\n"); - } - return 0; - } - - /* need to map that range */ - aper_size = info.aper_size << 20; - aper_base = info.aper_base; - end_pfn = (aper_base>>PAGE_SHIFT) + (aper_size>>PAGE_SHIFT); - - if (end_pfn > max_low_pfn_mapped) { - start_pfn = (aper_base>>PAGE_SHIFT); - init_memory_mapping(start_pfn<> PAGE_SHIFT; - - iommu_gart_bitmap = (void *) __get_free_pages(GFP_KERNEL | __GFP_ZERO, - get_order(iommu_pages/8)); - if (!iommu_gart_bitmap) - panic("Cannot allocate iommu bitmap\n"); - -#ifdef CONFIG_IOMMU_LEAK - if (leak_trace) { - int ret; - - ret = dma_debug_resize_entries(iommu_pages); - if (ret) - pr_debug("PCI-DMA: Cannot trace all the entries\n"); - } -#endif - - /* - * Out of IOMMU space handling. - * Reserve some invalid pages at the beginning of the GART. - */ - bitmap_set(iommu_gart_bitmap, 0, EMERGENCY_PAGES); - - pr_info("PCI-DMA: Reserving %luMB of IOMMU area in the AGP aperture\n", - iommu_size >> 20); - - agp_memory_reserved = iommu_size; - iommu_start = aper_size - iommu_size; - iommu_bus_base = info.aper_base + iommu_start; - bad_dma_addr = iommu_bus_base; - iommu_gatt_base = agp_gatt_table + (iommu_start>>PAGE_SHIFT); - - /* - * Unmap the IOMMU part of the GART. The alias of the page is - * always mapped with cache enabled and there is no full cache - * coherency across the GART remapping. The unmapping avoids - * automatic prefetches from the CPU allocating cache lines in - * there. All CPU accesses are done via the direct mapping to - * the backing memory. The GART address is only used by PCI - * devices. - */ - set_memory_np((unsigned long)__va(iommu_bus_base), - iommu_size >> PAGE_SHIFT); - /* - * Tricky. The GART table remaps the physical memory range, - * so the CPU wont notice potential aliases and if the memory - * is remapped to UC later on, we might surprise the PCI devices - * with a stray writeout of a cacheline. So play it sure and - * do an explicit, full-scale wbinvd() _after_ having marked all - * the pages as Not-Present: - */ - wbinvd(); - - /* - * Now all caches are flushed and we can safely enable - * GART hardware. Doing it early leaves the possibility - * of stale cache entries that can lead to GART PTE - * errors. - */ - enable_gart_translations(); - - /* - * Try to workaround a bug (thanks to BenH): - * Set unmapped entries to a scratch page instead of 0. - * Any prefetches that hit unmapped entries won't get an bus abort - * then. (P2P bridge may be prefetching on DMA reads). - */ - scratch = get_zeroed_page(GFP_KERNEL); - if (!scratch) - panic("Cannot allocate iommu scratch page"); - gart_unmapped_entry = GPTE_ENCODE(__pa(scratch)); - for (i = EMERGENCY_PAGES; i < iommu_pages; i++) - iommu_gatt_base[i] = gart_unmapped_entry; - - flush_gart(); - dma_ops = &gart_dma_ops; - x86_platform.iommu_shutdown = gart_iommu_shutdown; - swiotlb = 0; - - return 0; -} - -void __init gart_parse_options(char *p) -{ - int arg; - -#ifdef CONFIG_IOMMU_LEAK - if (!strncmp(p, "leak", 4)) { - leak_trace = 1; - p += 4; - if (*p == '=') - ++p; - if (isdigit(*p) && get_option(&p, &arg)) - iommu_leak_pages = arg; - } -#endif - if (isdigit(*p) && get_option(&p, &arg)) - iommu_size = arg; - if (!strncmp(p, "fullflush", 9)) - iommu_fullflush = 1; - if (!strncmp(p, "nofullflush", 11)) - iommu_fullflush = 0; - if (!strncmp(p, "noagp", 5)) - no_agp = 1; - if (!strncmp(p, "noaperture", 10)) - fix_aperture = 0; - /* duplicated from pci-dma.c */ - if (!strncmp(p, "force", 5)) - gart_iommu_aperture_allowed = 1; - if (!strncmp(p, "allowed", 7)) - gart_iommu_aperture_allowed = 1; - if (!strncmp(p, "memaper", 7)) { - fallback_aper_force = 1; - p += 7; - if (*p == '=') { - ++p; - if (get_option(&p, &arg)) - fallback_aper_order = arg; - } - } -} -IOMMU_INIT_POST(gart_iommu_hole_init); -- cgit v0.10.2 From d24339059d640f108c08ba99ef30e3bafa10f8e4 Mon Sep 17 00:00:00 2001 From: Miklos Szeredi Date: Tue, 10 May 2011 17:35:58 +0200 Subject: fuse: fix oops in revalidate when called with NULL nameidata Some cases (e.g. ecryptfs) can call ->dentry_revalidate with NULL nameidata. https://bugzilla.kernel.org/show_bug.cgi?id=34732 Tyler Hicks pointed out that this bug was introduced by commit e7c0a16786 "fuse: make fuse_dentry_revalidate() RCU aware" Reported-by: Witold Baryluk Signed-off-by: Miklos Szeredi diff --git a/fs/fuse/dir.c b/fs/fuse/dir.c index c6ba49b..b32eb29 100644 --- a/fs/fuse/dir.c +++ b/fs/fuse/dir.c @@ -174,7 +174,7 @@ static int fuse_dentry_revalidate(struct dentry *entry, struct nameidata *nd) if (!inode) return 0; - if (nd->flags & LOOKUP_RCU) + if (nd && (nd->flags & LOOKUP_RCU)) return -ECHILD; fc = get_fuse_conn(inode); -- cgit v0.10.2 From 7e186bdd0098b34c69fb8067c67340ae610ea499 Mon Sep 17 00:00:00 2001 From: Stefano Stabellini Date: Fri, 6 May 2011 12:27:50 +0100 Subject: xen: do not clear and mask evtchns in __xen_evtchn_do_upcall Change the irq handler of evtchns and pirqs that don't need EOI (pirqs that correspond to physical edge interrupts) to handle_edge_irq. Use handle_fasteoi_irq for pirqs that need eoi (they generally correspond to level triggered irqs), no risk in loosing interrupts because we have to EOI the irq anyway. This change has the following benefits: - it uses the very same handlers that Linux would use on native for the same irqs (handle_edge_irq for edge irqs and msis, and handle_fasteoi_irq for everything else); - it uses these handlers in the same way native code would use them: it let Linux mask\unmask and ack the irq when Linux want to mask\unmask and ack the irq; - it fixes a problem occurring when a driver calls disable_irq() in its handler: the old code was unconditionally unmasking the evtchn even if the irq is disabled when irq_eoi was called. See Documentation/DocBook/genericirq.tmpl for more informations. Signed-off-by: Stefano Stabellini [v1: Fixed space/tab issues] Signed-off-by: Konrad Rzeszutek Wilk diff --git a/drivers/xen/events.c b/drivers/xen/events.c index 33167b4..0ae1d4d 100644 --- a/drivers/xen/events.c +++ b/drivers/xen/events.c @@ -118,6 +118,8 @@ static DEFINE_PER_CPU(unsigned long [NR_EVENT_CHANNELS/BITS_PER_LONG], static struct irq_chip xen_dynamic_chip; static struct irq_chip xen_percpu_chip; static struct irq_chip xen_pirq_chip; +static void enable_dynirq(struct irq_data *data); +static void disable_dynirq(struct irq_data *data); /* Get info for IRQ */ static struct irq_info *info_for_irq(unsigned irq) @@ -473,16 +475,6 @@ static void xen_free_irq(unsigned irq) irq_free_desc(irq); } -static void pirq_unmask_notify(int irq) -{ - struct physdev_eoi eoi = { .irq = pirq_from_irq(irq) }; - - if (unlikely(pirq_needs_eoi(irq))) { - int rc = HYPERVISOR_physdev_op(PHYSDEVOP_eoi, &eoi); - WARN_ON(rc); - } -} - static void pirq_query_unmask(int irq) { struct physdev_irq_status_query irq_status; @@ -506,6 +498,29 @@ static bool probing_irq(int irq) return desc && desc->action == NULL; } +static void eoi_pirq(struct irq_data *data) +{ + int evtchn = evtchn_from_irq(data->irq); + struct physdev_eoi eoi = { .irq = pirq_from_irq(data->irq) }; + int rc = 0; + + irq_move_irq(data); + + if (VALID_EVTCHN(evtchn)) + clear_evtchn(evtchn); + + if (pirq_needs_eoi(data->irq)) { + rc = HYPERVISOR_physdev_op(PHYSDEVOP_eoi, &eoi); + WARN_ON(rc); + } +} + +static void mask_ack_pirq(struct irq_data *data) +{ + disable_dynirq(data); + eoi_pirq(data); +} + static unsigned int __startup_pirq(unsigned int irq) { struct evtchn_bind_pirq bind_pirq; @@ -539,7 +554,7 @@ static unsigned int __startup_pirq(unsigned int irq) out: unmask_evtchn(evtchn); - pirq_unmask_notify(irq); + eoi_pirq(irq_get_irq_data(irq)); return 0; } @@ -579,18 +594,7 @@ static void enable_pirq(struct irq_data *data) static void disable_pirq(struct irq_data *data) { -} - -static void ack_pirq(struct irq_data *data) -{ - int evtchn = evtchn_from_irq(data->irq); - - irq_move_irq(data); - - if (VALID_EVTCHN(evtchn)) { - mask_evtchn(evtchn); - clear_evtchn(evtchn); - } + disable_dynirq(data); } static int find_irq_by_gsi(unsigned gsi) @@ -639,9 +643,6 @@ int xen_bind_pirq_gsi_to_irq(unsigned gsi, if (irq < 0) goto out; - irq_set_chip_and_handler_name(irq, &xen_pirq_chip, handle_level_irq, - name); - irq_op.irq = irq; irq_op.vector = 0; @@ -658,6 +659,32 @@ int xen_bind_pirq_gsi_to_irq(unsigned gsi, xen_irq_info_pirq_init(irq, 0, pirq, gsi, irq_op.vector, shareable ? PIRQ_SHAREABLE : 0); + pirq_query_unmask(irq); + /* We try to use the handler with the appropriate semantic for the + * type of interrupt: if the interrupt doesn't need an eoi + * (pirq_needs_eoi returns false), we treat it like an edge + * triggered interrupt so we use handle_edge_irq. + * As a matter of fact this only happens when the corresponding + * physical interrupt is edge triggered or an msi. + * + * On the other hand if the interrupt needs an eoi (pirq_needs_eoi + * returns true) we treat it like a level triggered interrupt so we + * use handle_fasteoi_irq like the native code does for this kind of + * interrupts. + * Depending on the Xen version, pirq_needs_eoi might return true + * not only for level triggered interrupts but for edge triggered + * interrupts too. In any case Xen always honors the eoi mechanism, + * not injecting any more pirqs of the same kind if the first one + * hasn't received an eoi yet. Therefore using the fasteoi handler + * is the right choice either way. + */ + if (pirq_needs_eoi(irq)) + irq_set_chip_and_handler_name(irq, &xen_pirq_chip, + handle_fasteoi_irq, name); + else + irq_set_chip_and_handler_name(irq, &xen_pirq_chip, + handle_edge_irq, name); + out: spin_unlock(&irq_mapping_update_lock); @@ -690,8 +717,8 @@ int xen_bind_pirq_msi_to_irq(struct pci_dev *dev, struct msi_desc *msidesc, if (irq == -1) goto out; - irq_set_chip_and_handler_name(irq, &xen_pirq_chip, handle_level_irq, - name); + irq_set_chip_and_handler_name(irq, &xen_pirq_chip, handle_edge_irq, + name); xen_irq_info_pirq_init(irq, 0, pirq, 0, vector, 0); ret = irq_set_msi_desc(irq, msidesc); @@ -773,7 +800,7 @@ int bind_evtchn_to_irq(unsigned int evtchn) goto out; irq_set_chip_and_handler_name(irq, &xen_dynamic_chip, - handle_fasteoi_irq, "event"); + handle_edge_irq, "event"); xen_irq_info_evtchn_init(irq, evtchn); } @@ -1179,9 +1206,6 @@ static void __xen_evtchn_do_upcall(void) port = (word_idx * BITS_PER_LONG) + bit_idx; irq = evtchn_to_irq[port]; - mask_evtchn(port); - clear_evtchn(port); - if (irq != -1) { desc = irq_to_desc(irq); if (desc) @@ -1337,10 +1361,16 @@ static void ack_dynirq(struct irq_data *data) { int evtchn = evtchn_from_irq(data->irq); - irq_move_masked_irq(data); + irq_move_irq(data); if (VALID_EVTCHN(evtchn)) - unmask_evtchn(evtchn); + clear_evtchn(evtchn); +} + +static void mask_ack_dynirq(struct irq_data *data) +{ + disable_dynirq(data); + ack_dynirq(data); } static int retrigger_dynirq(struct irq_data *data) @@ -1535,7 +1565,9 @@ static struct irq_chip xen_dynamic_chip __read_mostly = { .irq_mask = disable_dynirq, .irq_unmask = enable_dynirq, - .irq_eoi = ack_dynirq, + .irq_ack = ack_dynirq, + .irq_mask_ack = mask_ack_dynirq, + .irq_set_affinity = set_affinity_irq, .irq_retrigger = retrigger_dynirq, }; @@ -1545,14 +1577,15 @@ static struct irq_chip xen_pirq_chip __read_mostly = { .irq_startup = startup_pirq, .irq_shutdown = shutdown_pirq, - .irq_enable = enable_pirq, - .irq_unmask = enable_pirq, - .irq_disable = disable_pirq, - .irq_mask = disable_pirq, - .irq_ack = ack_pirq, + .irq_mask = disable_dynirq, + .irq_unmask = enable_dynirq, + + .irq_ack = eoi_pirq, + .irq_eoi = eoi_pirq, + .irq_mask_ack = mask_ack_pirq, .irq_set_affinity = set_affinity_irq, -- cgit v0.10.2 From c54794d19e61472156e37263c074225574c80df1 Mon Sep 17 00:00:00 2001 From: David Daney Date: Tue, 28 Dec 2010 13:21:37 -0800 Subject: MIPS: Mask jump target in ftrace_dyn_arch_init_insns(). The current code is abusing the uasm interface by passing jump target addresses with high bits set. Mask the addresses to avoid annoying messages at boot time. Signed-off-by: David Daney Cc: Steven Rostedt Cc: Wu Zhangjin Patchwork: https://patchwork.linux-mips.org/patch/1922/ Signed-off-by: Ralf Baechle diff --git a/arch/mips/kernel/ftrace.c b/arch/mips/kernel/ftrace.c index 94ca2b0..feb8021 100644 --- a/arch/mips/kernel/ftrace.c +++ b/arch/mips/kernel/ftrace.c @@ -23,6 +23,7 @@ #define JAL 0x0c000000 /* jump & link: ip --> ra, jump to target */ #define ADDR_MASK 0x03ffffff /* op_code|addr : 31...26|25 ....0 */ +#define JUMP_RANGE_MASK ((1UL << 28) - 1) #define INSN_NOP 0x00000000 /* nop */ #define INSN_JAL(addr) \ @@ -44,12 +45,12 @@ static inline void ftrace_dyn_arch_init_insns(void) /* jal (ftrace_caller + 8), jump over the first two instruction */ buf = (u32 *)&insn_jal_ftrace_caller; - uasm_i_jal(&buf, (FTRACE_ADDR + 8)); + uasm_i_jal(&buf, (FTRACE_ADDR + 8) & JUMP_RANGE_MASK); #ifdef CONFIG_FUNCTION_GRAPH_TRACER /* j ftrace_graph_caller */ buf = (u32 *)&insn_j_ftrace_graph_caller; - uasm_i_j(&buf, (unsigned long)ftrace_graph_caller); + uasm_i_j(&buf, (unsigned long)ftrace_graph_caller & JUMP_RANGE_MASK); #endif } -- cgit v0.10.2 From 71271aab8cbdeb9612761db3230fe8dadb9a01c3 Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Tue, 29 Mar 2011 10:50:38 +0200 Subject: MIPS: c-r4k: Fix GCC 4.6.0 build error CC arch/mips/mm/c-r4k.o arch/mips/mm/c-r4k.c: In function 'probe_scache': arch/mips/mm/c-r4k.c:1078:6: error: variable 'tmp' set but not used [-Werror=unused-but-set-variable] cc1: all warnings being treated as errors Older GCC versions didn't warn about the unused variable tmp because it was getting initialized. Signed-off-by: Ralf Baechle diff --git a/arch/mips/mm/c-r4k.c b/arch/mips/mm/c-r4k.c index b4923a7..71bddf8 100644 --- a/arch/mips/mm/c-r4k.c +++ b/arch/mips/mm/c-r4k.c @@ -1075,7 +1075,6 @@ static int __cpuinit probe_scache(void) unsigned long flags, addr, begin, end, pow2; unsigned int config = read_c0_config(); struct cpuinfo_mips *c = ¤t_cpu_data; - int tmp; if (config & CONF_SC) return 0; @@ -1108,7 +1107,6 @@ static int __cpuinit probe_scache(void) /* Now search for the wrap around point. */ pow2 = (128 * 1024); - tmp = 0; for (addr = begin + (128 * 1024); addr < end; addr = begin + pow2) { cache_op(Index_Load_Tag_SD, addr); __asm__ __volatile__("nop; nop; nop; nop;"); /* hazard... */ -- cgit v0.10.2 From 4a9040f451c32cd62971ecda1cb5bc4aed444c78 Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Tue, 29 Mar 2011 10:54:54 +0200 Subject: MIPS: tlbex: Fix GCC 4.6.0 build error CC arch/mips/mm/tlbex.o arch/mips/mm/tlbex.c: In function 'build_r4000_tlb_refill_handler': arch/mips/mm/tlbex.c:1155:22: error: variable 'vmalloc_mode' set but not used [-Werror=unused-but-set-variable] arch/mips/mm/tlbex.c:1154:28: error: variable 'htlb_info' set but not used [-Werror=unused-but-set-variable] cc1: all warnings being treated as errors Signed-off-by: Ralf Baechle diff --git a/arch/mips/mm/tlbex.c b/arch/mips/mm/tlbex.c index 5ef294f..f5734c2 100644 --- a/arch/mips/mm/tlbex.c +++ b/arch/mips/mm/tlbex.c @@ -1151,8 +1151,8 @@ static void __cpuinit build_r4000_tlb_refill_handler(void) struct uasm_reloc *r = relocs; u32 *f; unsigned int final_len; - struct mips_huge_tlb_info htlb_info; - enum vmalloc64_mode vmalloc_mode; + struct mips_huge_tlb_info htlb_info __maybe_unused; + enum vmalloc64_mode vmalloc_mode __maybe_unused; memset(tlb_handler, 0, sizeof(tlb_handler)); memset(labels, 0, sizeof(labels)); -- cgit v0.10.2 From 6fd78fc1fa3ed1e70501c978c2d0bef94320252f Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Tue, 29 Mar 2011 11:00:44 +0200 Subject: MIPS: IP22: Fix GCC 4.6.0 build error CC arch/mips/sgi-ip22/ip22-time.o arch/mips/sgi-ip22/ip22-time.c: In function 'dosample': arch/mips/sgi-ip22/ip22-time.c:35:10: error: variable 'lsb' set but not used [-Werror=unused-but-set-variable] cc1: all warnings being treated as errors Signed-off-by: Ralf Baechle diff --git a/arch/mips/sgi-ip22/ip22-time.c b/arch/mips/sgi-ip22/ip22-time.c index 603fc91..1a94c98 100644 --- a/arch/mips/sgi-ip22/ip22-time.c +++ b/arch/mips/sgi-ip22/ip22-time.c @@ -32,7 +32,7 @@ static unsigned long dosample(void) { u32 ct0, ct1; - u8 msb, lsb; + u8 msb; /* Start the counter. */ sgint->tcword = (SGINT_TCWORD_CNT2 | SGINT_TCWORD_CALL | @@ -46,7 +46,7 @@ static unsigned long dosample(void) /* Latch and spin until top byte of counter2 is zero */ do { writeb(SGINT_TCWORD_CNT2 | SGINT_TCWORD_CLAT, &sgint->tcword); - lsb = readb(&sgint->tcnt2); + (void) readb(&sgint->tcnt2); msb = readb(&sgint->tcnt2); ct1 = read_c0_count(); } while (msb); -- cgit v0.10.2 From 3be1afc8f64742552325d9f03c2b96339e822f9e Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Tue, 29 Mar 2011 11:06:49 +0200 Subject: MIPS: IP22: Fix GCC 4.6.0 build error CC arch/mips/sgi-ip22/ip22-platform.o arch/mips/sgi-ip22/ip22-platform.c: In function 'sgiseeq_devinit': arch/mips/sgi-ip22/ip22-platform.c:135:15: error: variable 'tmp' set but not used [-Werror=unused-but-set-variable] cc1: all warnings being treated as errors While at it rename the variable to pbdma for readability; there is a local variable tmp of different type being used in two nested blocks. Signed-off-by: Ralf Baechle diff --git a/arch/mips/sgi-ip22/ip22-platform.c b/arch/mips/sgi-ip22/ip22-platform.c index deddbf0..698904d 100644 --- a/arch/mips/sgi-ip22/ip22-platform.c +++ b/arch/mips/sgi-ip22/ip22-platform.c @@ -132,7 +132,7 @@ static struct platform_device eth1_device = { */ static int __init sgiseeq_devinit(void) { - unsigned int tmp; + unsigned int pbdma __maybe_unused; int res, i; eth0_pd.hpc = hpc3c0; @@ -151,7 +151,7 @@ static int __init sgiseeq_devinit(void) /* Second HPC is missing? */ if (ip22_is_fullhouse() || - get_dbe(tmp, (unsigned int *)&hpc3c1->pbdma[1])) + get_dbe(pbdma, (unsigned int *)&hpc3c1->pbdma[1])) return 0; sgimc->giopar |= SGIMC_GIOPAR_MASTEREXP1 | SGIMC_GIOPAR_EXP164 | -- cgit v0.10.2 From af3a1f6f4813907e143f87030cde67a9971db533 Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Tue, 29 Mar 2011 11:43:19 +0200 Subject: MIPS: Malta: Fix GCC 4.6.0 build error CC arch/mips/mti-malta/malta-init.o arch/mips/mti-malta/malta-init.c: In function 'prom_init': arch/mips/mti-malta/malta-init.c:196:6: error: variable 'result' set but not used [-Werror=unused-but-set-variable] cc1: all warnings being treated as errors Signed-off-by: Ralf Baechle diff --git a/arch/mips/mti-malta/malta-init.c b/arch/mips/mti-malta/malta-init.c index 414f0c9..31180c3 100644 --- a/arch/mips/mti-malta/malta-init.c +++ b/arch/mips/mti-malta/malta-init.c @@ -193,8 +193,6 @@ extern struct plat_smp_ops msmtc_smp_ops; void __init prom_init(void) { - int result; - prom_argc = fw_arg0; _prom_argv = (int *) fw_arg1; _prom_envp = (int *) fw_arg2; @@ -360,20 +358,14 @@ void __init prom_init(void) #ifdef CONFIG_SERIAL_8250_CONSOLE console_config(); #endif - /* Early detection of CMP support */ - result = gcmp_probe(GCMP_BASE_ADDR, GCMP_ADDRSPACE_SZ); - #ifdef CONFIG_MIPS_CMP - if (result) + /* Early detection of CMP support */ + if (gcmp_probe(GCMP_BASE_ADDR, GCMP_ADDRSPACE_SZ)) register_smp_ops(&cmp_smp_ops); + else #endif #ifdef CONFIG_MIPS_MT_SMP -#ifdef CONFIG_MIPS_CMP - if (!result) register_smp_ops(&vsmp_smp_ops); -#else - register_smp_ops(&vsmp_smp_ops); -#endif #endif #ifdef CONFIG_MIPS_MT_SMTC register_smp_ops(&msmtc_smp_ops); -- cgit v0.10.2 From 6be63bbbdab66b9185dc6f67c8b1bacb6f37f946 Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Tue, 29 Mar 2011 11:48:22 +0200 Subject: MIPS: Malta: Fix GCC 4.6.0 build error CC arch/mips/mti-malta/malta-int.o arch/mips/mti-malta/malta-int.c: In function 'mips_pcibios_iack': arch/mips/mti-malta/malta-int.c:59:6: error: variable 'dummy' set but not used [-Werror=unused-but-set-variable] cc1: all warnings being treated as errors Signed-off-by: Ralf Baechle diff --git a/arch/mips/mti-malta/malta-int.c b/arch/mips/mti-malta/malta-int.c index 9027061..e85c977 100644 --- a/arch/mips/mti-malta/malta-int.c +++ b/arch/mips/mti-malta/malta-int.c @@ -56,7 +56,6 @@ static DEFINE_RAW_SPINLOCK(mips_irq_lock); static inline int mips_pcibios_iack(void) { int irq; - u32 dummy; /* * Determine highest priority pending interrupt by performing @@ -83,7 +82,7 @@ static inline int mips_pcibios_iack(void) BONITO_PCIMAP_CFG = 0x20000; /* Flush Bonito register block */ - dummy = BONITO_PCIMAP_CFG; + (void) BONITO_PCIMAP_CFG; iob(); /* sync */ irq = __raw_readl((u32 *)_pcictrl_bonito_pcicfg); -- cgit v0.10.2 From 11b9d0eca559d087f3d49282033f2865cceacedd Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Tue, 29 Mar 2011 11:57:11 +0200 Subject: MIPS: SNI: Fix GCC 4.6.0 build error CC arch/mips/sni/time.o arch/mips/sni/time.c: In function 'dosample': arch/mips/sni/time.c:98:19: error: variable 'lsb' set but not used [-Werror=unused-but-set-variable] cc1: all warnings being treated as errors Signed-off-by: Ralf Baechle diff --git a/arch/mips/sni/time.c b/arch/mips/sni/time.c index c76151b..0904d4d 100644 --- a/arch/mips/sni/time.c +++ b/arch/mips/sni/time.c @@ -95,7 +95,7 @@ static void __init sni_a20r_timer_setup(void) static __init unsigned long dosample(void) { u32 ct0, ct1; - volatile u8 msb, lsb; + volatile u8 msb; /* Start the counter. */ outb_p(0x34, 0x43); @@ -108,7 +108,7 @@ static __init unsigned long dosample(void) /* Latch and spin until top byte of counter0 is zero */ do { outb(0x00, 0x43); - lsb = inb(0x40); + (void) inb(0x40); msb = inb(0x40); ct1 = read_c0_count(); } while (msb); -- cgit v0.10.2 From 84d3b0dbac103fc1b3aff1e71cb723b5456a849c Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Tue, 29 Mar 2011 12:09:51 +0200 Subject: MIPS: Jazz: Fix GCC 4.6.0 build error CC arch/mips/jazz/jazzdma.o arch/mips/jazz/jazzdma.c: In function 'vdma_remap': arch/mips/jazz/jazzdma.c:214:20: error: variable 'npages' set but not used [-Werror=unused-but-set-variable] cc1: all warnings being treated as errors Signed-off-by: Ralf Baechle diff --git a/arch/mips/jazz/jazzdma.c b/arch/mips/jazz/jazzdma.c index 9ce9f64..2d8e447 100644 --- a/arch/mips/jazz/jazzdma.c +++ b/arch/mips/jazz/jazzdma.c @@ -211,7 +211,7 @@ EXPORT_SYMBOL(vdma_free); */ int vdma_remap(unsigned long laddr, unsigned long paddr, unsigned long size) { - int first, pages, npages; + int first, pages; if (laddr > 0xffffff) { if (vdma_debug) @@ -228,8 +228,7 @@ int vdma_remap(unsigned long laddr, unsigned long paddr, unsigned long size) return -EINVAL; /* invalid physical address */ } - npages = pages = - (((paddr & (VDMA_PAGESIZE - 1)) + size) >> 12) + 1; + pages = (((paddr & (VDMA_PAGESIZE - 1)) + size) >> 12) + 1; first = laddr >> 12; if (vdma_debug) printk("vdma_remap: first=%x, pages=%x\n", first, pages); -- cgit v0.10.2 From c87444af6fc853dd5571a830efff7e07c46a544e Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Tue, 29 Mar 2011 12:32:55 +0200 Subject: MIPS: Loongson: Fix GCC 2.6.0 build error. CC arch/mips/loongson/common/env.o arch/mips/loongson/common/env.c: In function 'prom_init_env': arch/mips/loongson/common/env.c:50:12: error: variable 'ret' set but not used [-Werror=unused-but-set-variable] arch/mips/loongson/common/env.c:51:12: error: variable 'ret' set but not used [-Werror=unused-but-set-variable] arch/mips/loongson/common/env.c:52:12: error: variable 'ret' set but not used [-Werror=unused-but-set-variable] arch/mips/loongson/common/env.c:53:12: error: variable 'ret' set but not used [-Werror=unused-but-set-variable] cc1: all warnings being treated as errors Signed-off-by: Ralf Baechle diff --git a/arch/mips/loongson/common/env.c b/arch/mips/loongson/common/env.c index 11b193f..d93830a 100644 --- a/arch/mips/loongson/common/env.c +++ b/arch/mips/loongson/common/env.c @@ -29,9 +29,10 @@ unsigned long memsize, highmemsize; #define parse_even_earlier(res, option, p) \ do { \ - int ret; \ + unsigned int tmp __maybe_unused; \ + \ if (strncmp(option, (char *)p, strlen(option)) == 0) \ - ret = strict_strtol((char *)p + strlen(option"="), 10, &res); \ + tmp = strict_strtol((char *)p + strlen(option"="), 10, &res); \ } while (0) void __init prom_init_env(void) -- cgit v0.10.2 From 088a42acc4f0e28fc6d8b823cafb03a00ff61aec Mon Sep 17 00:00:00 2001 From: Yoichi Yuasa Date: Tue, 29 Mar 2011 15:53:56 +0900 Subject: MIPS: MSP71xx: Fix typo in msp_per_irq_controller CC arch/mips/pmc-sierra/msp71xx/msp_irq_per.o arch/mips/pmc-sierra/msp71xx/msp_irq_per.c:101:2: error: expected identifier before '.' token make[2]: *** [arch/mips/pmc-sierra/msp71xx/msp_irq_per.o] Error 1 Signed-off-by: Yoichi Yuasa Patchwork: https://patchwork.linux-mips.org/patch/2246/ Cc: linux-mips Signed-off-by: Ralf Baechle diff --git a/arch/mips/pmc-sierra/msp71xx/msp_irq_per.c b/arch/mips/pmc-sierra/msp71xx/msp_irq_per.c index f9b9dcd..98fd009 100644 --- a/arch/mips/pmc-sierra/msp71xx/msp_irq_per.c +++ b/arch/mips/pmc-sierra/msp71xx/msp_irq_per.c @@ -97,7 +97,7 @@ static int msp_per_irq_set_affinity(struct irq_data *d, static struct irq_chip msp_per_irq_controller = { .name = "MSP_PER", - .irq_enable = unmask_per_irq. + .irq_enable = unmask_per_irq, .irq_disable = mask_per_irq, .irq_ack = msp_per_irq_ack, #ifdef CONFIG_SMP -- cgit v0.10.2 From 866d7f5622cf5830b085a4471e67d4ed9106cb2e Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Tue, 29 Mar 2011 16:09:25 +0200 Subject: MIPS: MSP: Fix build error Reported and original patch by Yoichi Yuasa . Signed-off-by: Ralf Baechle diff --git a/arch/mips/include/asm/cevt-r4k.h b/arch/mips/include/asm/cevt-r4k.h index fa4328f..65f9bdd 100644 --- a/arch/mips/include/asm/cevt-r4k.h +++ b/arch/mips/include/asm/cevt-r4k.h @@ -14,6 +14,9 @@ #ifndef __ASM_CEVT_R4K_H #define __ASM_CEVT_R4K_H +#include +#include + DECLARE_PER_CPU(struct clock_event_device, mips_clockevent_device); void mips_event_handler(struct clock_event_device *dev); -- cgit v0.10.2 From f8bec75acdadd3a6597fe0acb5c3161b71cc2ea0 Mon Sep 17 00:00:00 2001 From: Catalin Marinas Date: Tue, 29 Mar 2011 11:40:06 +0100 Subject: MIPS: Rename .data..mostly and properly handle it in linker script Signed-off-by: Ralf Baechle diff --git a/arch/mips/include/asm/cache.h b/arch/mips/include/asm/cache.h index 650ac9b..b4db69f 100644 --- a/arch/mips/include/asm/cache.h +++ b/arch/mips/include/asm/cache.h @@ -17,6 +17,6 @@ #define SMP_CACHE_SHIFT L1_CACHE_SHIFT #define SMP_CACHE_BYTES L1_CACHE_BYTES -#define __read_mostly __attribute__((__section__(".data.read_mostly"))) +#define __read_mostly __attribute__((__section__(".data..read_mostly"))) #endif /* _ASM_CACHE_H */ diff --git a/arch/mips/kernel/vmlinux.lds.S b/arch/mips/kernel/vmlinux.lds.S index 832afbb..e4b0b0b 100644 --- a/arch/mips/kernel/vmlinux.lds.S +++ b/arch/mips/kernel/vmlinux.lds.S @@ -74,6 +74,7 @@ SECTIONS INIT_TASK_DATA(PAGE_SIZE) NOSAVE_DATA CACHELINE_ALIGNED_DATA(1 << CONFIG_MIPS_L1_CACHE_SHIFT) + READ_MOSTLY_DATA(1 << CONFIG_MIPS_L1_CACHE_SHIFT) DATA_DATA CONSTRUCTORS } -- cgit v0.10.2 From e3fb3f27a7600982478e1ec415bf265c744d2ae4 Mon Sep 17 00:00:00 2001 From: David Daney Date: Thu, 17 Feb 2011 14:04:33 -0800 Subject: MIPS: Octeon: Cleanup Kconfig IRQ_CPU* symbols. Octeon doesn't use IRQ_CPU, so don't select it. IRQ_CPU_OCTEON is a completely unused symbol, remove it completely. Signed-off-by: David Daney To: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/2086/ Signed-off-by: Ralf Baechle diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig index 8e256cc..351c80f 100644 --- a/arch/mips/Kconfig +++ b/arch/mips/Kconfig @@ -997,9 +997,6 @@ config IRQ_GT641XX config IRQ_GIC bool -config IRQ_CPU_OCTEON - bool - config MIPS_BOARDS_GEN bool @@ -1359,8 +1356,6 @@ config CPU_SB1 config CPU_CAVIUM_OCTEON bool "Cavium Octeon processor" depends on SYS_HAS_CPU_CAVIUM_OCTEON - select IRQ_CPU - select IRQ_CPU_OCTEON select CPU_HAS_PREFETCH select CPU_SUPPORTS_64BIT_KERNEL select SYS_SUPPORTS_SMP -- cgit v0.10.2 From 23a271ecdf463e5b0198f78b0a0d5763598972b1 Mon Sep 17 00:00:00 2001 From: David Daney Date: Thu, 17 Feb 2011 18:23:32 -0800 Subject: MIPS: Octeon: Guard the Kconfig body with CPU_CAVIUM_OCTEON Instead of making each Octeon specific option depend on CPU_CAVIUM_OCTEON, gate the body of the entire file with CPU_CAVIUM_OCTEON. With this change, CAVIUM_OCTEON_SPECIFIC_OPTIONS becomes useless, so get rid of it as well. Signed-off-by: David Daney To: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/2091/ Signed-off-by: Ralf Baechle diff --git a/arch/mips/cavium-octeon/Kconfig b/arch/mips/cavium-octeon/Kconfig index caae228..cad555e 100644 --- a/arch/mips/cavium-octeon/Kconfig +++ b/arch/mips/cavium-octeon/Kconfig @@ -1,11 +1,7 @@ -config CAVIUM_OCTEON_SPECIFIC_OPTIONS - bool "Enable Octeon specific options" - depends on CPU_CAVIUM_OCTEON - default "y" +if CPU_CAVIUM_OCTEON config CAVIUM_CN63XXP1 bool "Enable CN63XXP1 errata worarounds" - depends on CAVIUM_OCTEON_SPECIFIC_OPTIONS default "n" help The CN63XXP1 chip requires build time workarounds to @@ -16,7 +12,6 @@ config CAVIUM_CN63XXP1 config CAVIUM_OCTEON_2ND_KERNEL bool "Build the kernel to be used as a 2nd kernel on the same chip" - depends on CAVIUM_OCTEON_SPECIFIC_OPTIONS default "n" help This option configures this kernel to be linked at a different @@ -26,7 +21,6 @@ config CAVIUM_OCTEON_2ND_KERNEL config CAVIUM_OCTEON_HW_FIX_UNALIGNED bool "Enable hardware fixups of unaligned loads and stores" - depends on CAVIUM_OCTEON_SPECIFIC_OPTIONS default "y" help Configure the Octeon hardware to automatically fix unaligned loads @@ -38,7 +32,6 @@ config CAVIUM_OCTEON_HW_FIX_UNALIGNED config CAVIUM_OCTEON_CVMSEG_SIZE int "Number of L1 cache lines reserved for CVMSEG memory" - depends on CAVIUM_OCTEON_SPECIFIC_OPTIONS range 0 54 default 1 help @@ -50,7 +43,6 @@ config CAVIUM_OCTEON_CVMSEG_SIZE config CAVIUM_OCTEON_LOCK_L2 bool "Lock often used kernel code in the L2" - depends on CAVIUM_OCTEON_SPECIFIC_OPTIONS default "y" help Enable locking parts of the kernel into the L2 cache. @@ -93,7 +85,6 @@ config CAVIUM_OCTEON_LOCK_L2_MEMCPY config ARCH_SPARSEMEM_ENABLE def_bool y select SPARSEMEM_STATIC - depends on CPU_CAVIUM_OCTEON config CAVIUM_OCTEON_HELPER def_bool y @@ -107,6 +98,8 @@ config NEED_SG_DMA_LENGTH config SWIOTLB def_bool y - depends on CPU_CAVIUM_OCTEON select IOMMU_HELPER select NEED_SG_DMA_LENGTH + + +endif # CPU_CAVIUM_OCTEON -- cgit v0.10.2 From 7da34c1dac0db934913d0e81d2fd548e4973a326 Mon Sep 17 00:00:00 2001 From: Jonas Gorski Date: Fri, 8 Apr 2011 14:32:15 +0200 Subject: MIPS: bcm63xx: Fix header_crc comment in bcm963xx_tag.h The CRC32 actually includes the tag_version. Signed-off-by: Jonas Gorski Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/2275/ Signed-off-by: Ralf Baechle diff --git a/arch/mips/include/asm/mach-bcm63xx/bcm963xx_tag.h b/arch/mips/include/asm/mach-bcm63xx/bcm963xx_tag.h index 32978d3..ed72e6a 100644 --- a/arch/mips/include/asm/mach-bcm63xx/bcm963xx_tag.h +++ b/arch/mips/include/asm/mach-bcm63xx/bcm963xx_tag.h @@ -88,7 +88,7 @@ struct bcm_tag { char kernel_crc[CRC_LEN]; /* 228-235: Unused at present */ char reserved1[8]; - /* 236-239: CRC32 of header excluding tagVersion */ + /* 236-239: CRC32 of header excluding last 20 bytes */ char header_crc[CRC_LEN]; /* 240-255: Unused at present */ char reserved2[16]; -- cgit v0.10.2 From a6ab5ca39404e04d46b1bae133cd059d84926a2d Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Mon, 11 Apr 2011 11:37:15 +0200 Subject: MIPS: IP27: Fix GCC 4.6.0 build error. CC arch/mips/sgi-ip27/ip27-hubio.o arch/mips/sgi-ip27/ip27-hubio.c: In function 'hub_pio_map': arch/mips/sgi-ip27/ip27-hubio.c:32:20: error: variable 'junk' set but not used [-Werror=unused-but-set-variable] cc1: all warnings being treated as errors Signed-off-by: Ralf Baechle diff --git a/arch/mips/sgi-ip27/ip27-klnuma.c b/arch/mips/sgi-ip27/ip27-klnuma.c index c3d30a8..1d1919a 100644 --- a/arch/mips/sgi-ip27/ip27-klnuma.c +++ b/arch/mips/sgi-ip27/ip27-klnuma.c @@ -54,11 +54,8 @@ void __init setup_replication_mask(void) static __init void set_ktext_source(nasid_t client_nasid, nasid_t server_nasid) { - cnodeid_t client_cnode; kern_vars_t *kvp; - client_cnode = NASID_TO_COMPACT_NODEID(client_nasid); - kvp = &hub_data(client_nasid)->kern_vars; KERN_VARS_ADDR(client_nasid) = (unsigned long)kvp; -- cgit v0.10.2 From e12f47ef1680d8bd6449a8e4e98165d2590617eb Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Mon, 11 Apr 2011 11:48:31 +0200 Subject: MIPS: IP27: Fix GCC 4.6.0 build error. CC arch/mips/sgi-ip27/ip27-hubio.o arch/mips/sgi-ip27/ip27-hubio.c: In function 'hub_pio_map': arch/mips/sgi-ip27/ip27-hubio.c:32:20: error: variable 'junk' set but not used [-Werror=unused-but-set-variable] cc1: all warnings being treated as errors Signed-off-by: Ralf Baechle diff --git a/arch/mips/sgi-ip27/ip27-hubio.c b/arch/mips/sgi-ip27/ip27-hubio.c index a1fa4ab..cd0d5b0 100644 --- a/arch/mips/sgi-ip27/ip27-hubio.c +++ b/arch/mips/sgi-ip27/ip27-hubio.c @@ -29,7 +29,6 @@ unsigned long hub_pio_map(cnodeid_t cnode, xwidgetnum_t widget, unsigned long xtalk_addr, size_t size) { nasid_t nasid = COMPACT_TO_NASID_NODEID(cnode); - volatile hubreg_t junk; unsigned i; /* use small-window mapping if possible */ @@ -64,7 +63,7 @@ unsigned long hub_pio_map(cnodeid_t cnode, xwidgetnum_t widget, * after we write it. */ IIO_ITTE_PUT(nasid, i, HUB_PIO_MAP_TO_MEM, widget, xtalk_addr); - junk = HUB_L(IIO_ITTE_GET(nasid, i)); + (void) HUB_L(IIO_ITTE_GET(nasid, i)); return NODE_BWIN_BASE(nasid, widget) + (xtalk_addr % BWIN_SIZE); } -- cgit v0.10.2 From 8bdd51429da5aec173ab6f0e431b13ee6782a888 Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Wed, 13 Apr 2011 20:50:46 +0200 Subject: MIPS: Document former use of timerfd(2) syscall number. Signed-off-by: Ralf Baechle diff --git a/arch/mips/kernel/scall32-o32.S b/arch/mips/kernel/scall32-o32.S index 7f5468b..7f1377e 100644 --- a/arch/mips/kernel/scall32-o32.S +++ b/arch/mips/kernel/scall32-o32.S @@ -565,7 +565,7 @@ einval: li v0, -ENOSYS sys sys_ioprio_get 2 /* 4315 */ sys sys_utimensat 4 sys sys_signalfd 3 - sys sys_ni_syscall 0 + sys sys_ni_syscall 0 /* was timerfd */ sys sys_eventfd 1 sys sys_fallocate 6 /* 4320 */ sys sys_timerfd_create 2 diff --git a/arch/mips/kernel/scall64-64.S b/arch/mips/kernel/scall64-64.S index a2e1fcb..7c0ef7f 100644 --- a/arch/mips/kernel/scall64-64.S +++ b/arch/mips/kernel/scall64-64.S @@ -404,7 +404,7 @@ sys_call_table: PTR sys_ioprio_get PTR sys_utimensat /* 5275 */ PTR sys_signalfd - PTR sys_ni_syscall + PTR sys_ni_syscall /* was timerfd */ PTR sys_eventfd PTR sys_fallocate PTR sys_timerfd_create /* 5280 */ diff --git a/arch/mips/kernel/scall64-n32.S b/arch/mips/kernel/scall64-n32.S index b2c7624..de6c556 100644 --- a/arch/mips/kernel/scall64-n32.S +++ b/arch/mips/kernel/scall64-n32.S @@ -403,7 +403,7 @@ EXPORT(sysn32_call_table) PTR sys_ioprio_get PTR compat_sys_utimensat PTR compat_sys_signalfd /* 6280 */ - PTR sys_ni_syscall + PTR sys_ni_syscall /* was timerfd */ PTR sys_eventfd PTR sys_fallocate PTR sys_timerfd_create diff --git a/arch/mips/kernel/scall64-o32.S b/arch/mips/kernel/scall64-o32.S index 049a9c8..b0541dd 100644 --- a/arch/mips/kernel/scall64-o32.S +++ b/arch/mips/kernel/scall64-o32.S @@ -522,7 +522,7 @@ sys_call_table: PTR sys_ioprio_get /* 4315 */ PTR compat_sys_utimensat PTR compat_sys_signalfd - PTR sys_ni_syscall + PTR sys_ni_syscall /* was timerfd */ PTR sys_eventfd PTR sys32_fallocate /* 4320 */ PTR sys_timerfd_create -- cgit v0.10.2 From 403fbdff96057ad312b672408ec676782a802b74 Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Wed, 13 Apr 2011 21:15:09 +0200 Subject: MIPS: Alchemy: Fix GCC 4.6.0 build error. CC arch/mips/alchemy/devboards/db1x00/board_setup.o arch/mips/alchemy/devboards/db1x00/board_setup.c: In function 'board_setup': arch/mips/alchemy/devboards/db1x00/board_setup.c:130:6: error: variable 'pin_func' set but not used [-Werror=unused-but-set-variable] Signed-off-by: Ralf Baechle diff --git a/arch/mips/alchemy/devboards/db1x00/board_setup.c b/arch/mips/alchemy/devboards/db1x00/board_setup.c index 05f120f..5c956fe 100644 --- a/arch/mips/alchemy/devboards/db1x00/board_setup.c +++ b/arch/mips/alchemy/devboards/db1x00/board_setup.c @@ -127,13 +127,10 @@ const char *get_system_type(void) void __init board_setup(void) { unsigned long bcsr1, bcsr2; - u32 pin_func; bcsr1 = DB1000_BCSR_PHYS_ADDR; bcsr2 = DB1000_BCSR_PHYS_ADDR + DB1000_BCSR_HEXLED_OFS; - pin_func = 0; - #ifdef CONFIG_MIPS_DB1000 printk(KERN_INFO "AMD Alchemy Au1000/Db1000 Board\n"); #endif @@ -164,12 +161,16 @@ void __init board_setup(void) /* Not valid for Au1550 */ #if defined(CONFIG_IRDA) && \ (defined(CONFIG_SOC_AU1000) || defined(CONFIG_SOC_AU1100)) - /* Set IRFIRSEL instead of GPIO15 */ - pin_func = au_readl(SYS_PINFUNC) | SYS_PF_IRF; - au_writel(pin_func, SYS_PINFUNC); - /* Power off until the driver is in use */ - bcsr_mod(BCSR_RESETS, BCSR_RESETS_IRDA_MODE_MASK, - BCSR_RESETS_IRDA_MODE_OFF); + { + u32 pin_func; + + /* Set IRFIRSEL instead of GPIO15 */ + pin_func = au_readl(SYS_PINFUNC) | SYS_PF_IRF; + au_writel(pin_func, SYS_PINFUNC); + /* Power off until the driver is in use */ + bcsr_mod(BCSR_RESETS, BCSR_RESETS_IRDA_MODE_MASK, + BCSR_RESETS_IRDA_MODE_OFF); + } #endif bcsr_write(BCSR_PCMCIA, 0); /* turn off PCMCIA power */ @@ -177,31 +178,35 @@ void __init board_setup(void) alchemy_gpio1_input_enable(); #ifdef CONFIG_MIPS_MIRAGE - /* GPIO[20] is output */ - alchemy_gpio_direction_output(20, 0); + { + u32 pin_func; - /* Set GPIO[210:208] instead of SSI_0 */ - pin_func = au_readl(SYS_PINFUNC) | SYS_PF_S0; + /* GPIO[20] is output */ + alchemy_gpio_direction_output(20, 0); - /* Set GPIO[215:211] for LEDs */ - pin_func |= 5 << 2; + /* Set GPIO[210:208] instead of SSI_0 */ + pin_func = au_readl(SYS_PINFUNC) | SYS_PF_S0; - /* Set GPIO[214:213] for more LEDs */ - pin_func |= 5 << 12; + /* Set GPIO[215:211] for LEDs */ + pin_func |= 5 << 2; - /* Set GPIO[207:200] instead of PCMCIA/LCD */ - pin_func |= SYS_PF_LCD | SYS_PF_PC; - au_writel(pin_func, SYS_PINFUNC); + /* Set GPIO[214:213] for more LEDs */ + pin_func |= 5 << 12; - /* - * Enable speaker amplifier. This should - * be part of the audio driver. - */ - alchemy_gpio_direction_output(209, 1); + /* Set GPIO[207:200] instead of PCMCIA/LCD */ + pin_func |= SYS_PF_LCD | SYS_PF_PC; + au_writel(pin_func, SYS_PINFUNC); - pm_power_off = mirage_power_off; - _machine_halt = mirage_power_off; - _machine_restart = (void(*)(char *))mips_softreset; + /* + * Enable speaker amplifier. This should + * be part of the audio driver. + */ + alchemy_gpio_direction_output(209, 1); + + pm_power_off = mirage_power_off; + _machine_halt = mirage_power_off; + _machine_restart = (void(*)(char *))mips_softreset; + } #endif #ifdef CONFIG_MIPS_BOSPORUS -- cgit v0.10.2 From 893d20fbae483913250a5d8bd9b4ce861a3adf2a Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Wed, 13 Apr 2011 21:49:54 +0200 Subject: MIPS: Fix calc_vmlinuz_load_addr build warnings. HOSTCC arch/mips/boot/compressed/calc_vmlinuz_load_addr arch/mips/boot/compressed/calc_vmlinuz_load_addr.c: In function 'main': arch/mips/boot/compressed/calc_vmlinuz_load_addr.c:35:2: warning: format '%llx' expects type 'long long unsigned int *', but argument 3 has type 'uint64_t *' arch/mips/boot/compressed/calc_vmlinuz_load_addr.c:54:2: warning: format '%llx' expects type 'long long unsigned int', but argument 2 has type 'uint64_t' Signed-off-by: Ralf Baechle diff --git a/arch/mips/boot/compressed/calc_vmlinuz_load_addr.c b/arch/mips/boot/compressed/calc_vmlinuz_load_addr.c index 88c9d963..9a62436 100644 --- a/arch/mips/boot/compressed/calc_vmlinuz_load_addr.c +++ b/arch/mips/boot/compressed/calc_vmlinuz_load_addr.c @@ -16,8 +16,8 @@ int main(int argc, char *argv[]) { + unsigned long long vmlinux_size, vmlinux_load_addr, vmlinuz_load_addr; struct stat sb; - uint64_t vmlinux_size, vmlinux_load_addr, vmlinuz_load_addr; if (argc != 3) { fprintf(stderr, "Usage: %s \n", -- cgit v0.10.2 From b20bff02b21ac7b725fd09590d5724d306552529 Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Wed, 13 Apr 2011 23:51:23 +0200 Subject: MIPS: Audit: Fix success success argument pass to audit_syscall_exit Signed-off-by: Ralf Baechle diff --git a/arch/mips/kernel/ptrace.c b/arch/mips/kernel/ptrace.c index d21c388..584e6b5 100644 --- a/arch/mips/kernel/ptrace.c +++ b/arch/mips/kernel/ptrace.c @@ -540,8 +540,8 @@ asmlinkage void do_syscall_trace(struct pt_regs *regs, int entryexit) secure_computing(regs->regs[2]); if (unlikely(current->audit_context) && entryexit) - audit_syscall_exit(AUDITSC_RESULT(regs->regs[2]), - regs->regs[2]); + audit_syscall_exit(AUDITSC_RESULT(regs->regs[7]), + -regs->regs[2]); if (!(current->ptrace & PT_PTRACED)) goto out; -- cgit v0.10.2 From f1b6a5054c5c5c1770863b781de9b721fc99c3e3 Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Mon, 18 Apr 2011 11:16:42 +0100 Subject: MIPS: JZ4740: Fix GCC 4.6.0 build error. CC arch/mips/jz4740/dma.o arch/mips/jz4740/dma.c: In function 'jz4740_dma_chan_irq': arch/mips/jz4740/dma.c:245:11: error: variable 'status' set but not used [-Werro r=unused-but-set-variable] Signed-off-by: Ralf Baechle diff --git a/arch/mips/jz4740/dma.c b/arch/mips/jz4740/dma.c index 5ebe75a..d7feb89 100644 --- a/arch/mips/jz4740/dma.c +++ b/arch/mips/jz4740/dma.c @@ -242,9 +242,7 @@ EXPORT_SYMBOL_GPL(jz4740_dma_get_residue); static void jz4740_dma_chan_irq(struct jz4740_dma_chan *dma) { - uint32_t status; - - status = jz4740_dma_read(JZ_REG_DMA_STATUS_CTRL(dma->id)); + (void) jz4740_dma_read(JZ_REG_DMA_STATUS_CTRL(dma->id)); jz4740_dma_write_mask(JZ_REG_DMA_STATUS_CTRL(dma->id), 0, JZ_DMA_STATUS_CTRL_ENABLE | JZ_DMA_STATUS_CTRL_TRANSFER_DONE); -- cgit v0.10.2 From aa7ce1c3038814801c5d7712f7403b15fea5d77d Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Mon, 18 Apr 2011 11:19:32 +0100 Subject: MIPS: JZ4740: Export symbols to the watchdog driver module MODPOST 356 modules ERROR: "jz4740_timer_disable_watchdog" [drivers/watchdog/jz4740_wdt.ko] undefine d! ERROR: "jz4740_timer_enable_watchdog" [drivers/watchdog/jz4740_wdt.ko] undefined ! make[1]: *** [__modpost] Error 1 Signed-off-by: Ralf Baechle diff --git a/arch/mips/jz4740/timer.c b/arch/mips/jz4740/timer.c index b2c0151..654d5c3 100644 --- a/arch/mips/jz4740/timer.c +++ b/arch/mips/jz4740/timer.c @@ -27,11 +27,13 @@ void jz4740_timer_enable_watchdog(void) { writel(BIT(16), jz4740_timer_base + JZ_REG_TIMER_STOP_CLEAR); } +EXPORT_SYMBOL_GPL(jz4740_timer_enable_watchdog); void jz4740_timer_disable_watchdog(void) { writel(BIT(16), jz4740_timer_base + JZ_REG_TIMER_STOP_SET); } +EXPORT_SYMBOL_GPL(jz4740_timer_disable_watchdog); void __init jz4740_timer_init(void) { -- cgit v0.10.2 From 1e2bbde4afd97b8d6a3f1f6c7bf3b6a9d226ba2e Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Thu, 31 Mar 2011 20:52:20 +0200 Subject: MIPS: JZ4740: Set one-shot feature flag for the clockevent The code for supporting one-shot mode for the clockevent is already there, only the feature flag was not set. Setting the one-shot flag allows the kernel to run in tickless mode. Signed-off-by: Lars-Peter Clausen Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/2261/ Signed-off-by: Ralf Baechle diff --git a/arch/mips/jz4740/time.c b/arch/mips/jz4740/time.c index fe01678..eaa853a 100644 --- a/arch/mips/jz4740/time.c +++ b/arch/mips/jz4740/time.c @@ -89,7 +89,7 @@ static int jz4740_clockevent_set_next(unsigned long evt, static struct clock_event_device jz4740_clockevent = { .name = "jz4740-timer", - .features = CLOCK_EVT_FEAT_PERIODIC, + .features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT, .set_next_event = jz4740_clockevent_set_next, .set_mode = jz4740_clockevent_set_mode, .rating = 200, -- cgit v0.10.2 From f850548ef88e5ff9e40bae9e1a7140bef0653e6b Mon Sep 17 00:00:00 2001 From: Wu Zhangjin Date: Sun, 24 Apr 2011 05:56:59 +0800 Subject: MIPS: Hibernation: Fixes for PAGE_SIZE >= 64kb PAGE_SIZE >= 64kb (1 << 16) is too big to be the immediate of the addiu/daddiu instruction, so, use addu/daddu instruction instead. The following compiling error is fixed: AS arch/mips/power/hibernate.o arch/mips/power/hibernate.S: Assembler messages: arch/mips/power/hibernate.S:38: Error: expression out of range make[2]: *** [arch/mips/power/hibernate.o] Error 1 make[1]: *** [arch/mips/power] Error 2 Reported-by: Roman Mamedov Signed-off-by: Wu Zhangjin To: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/2313/ Signed-off-by: Ralf Baechle diff --git a/arch/mips/power/hibernate.S b/arch/mips/power/hibernate.S index dbb5c7b..f8a751c 100644 --- a/arch/mips/power/hibernate.S +++ b/arch/mips/power/hibernate.S @@ -35,7 +35,7 @@ LEAF(swsusp_arch_resume) 0: PTR_L t1, PBE_ADDRESS(t0) /* source */ PTR_L t2, PBE_ORIG_ADDRESS(t0) /* destination */ - PTR_ADDIU t3, t1, PAGE_SIZE + PTR_ADDU t3, t1, PAGE_SIZE 1: REG_L t8, (t1) REG_S t8, (t2) -- cgit v0.10.2 From 310f1303390758ee7688e350e117a7b50ba5fa05 Mon Sep 17 00:00:00 2001 From: David Daney Date: Wed, 27 Apr 2011 16:39:28 -0700 Subject: MIPS: Invalidate old TLB mappings when updating huge page PTEs. Without this, stale Icache or TLB entries may be used. Signed-off-by: David Daney To: linux-mips@linux-mips.org https://patchwork.linux-mips.org/patch/2318/ Signed-off-by: Ralf Baechle diff --git a/arch/mips/include/asm/hugetlb.h b/arch/mips/include/asm/hugetlb.h index f5e85601..c565b7c 100644 --- a/arch/mips/include/asm/hugetlb.h +++ b/arch/mips/include/asm/hugetlb.h @@ -70,6 +70,7 @@ static inline pte_t huge_ptep_get_and_clear(struct mm_struct *mm, static inline void huge_ptep_clear_flush(struct vm_area_struct *vma, unsigned long addr, pte_t *ptep) { + flush_tlb_mm(vma->vm_mm); } static inline int huge_pte_none(pte_t pte) -- cgit v0.10.2 From 780914c3cf691a75a0b7fe89f4466eeff8058165 Mon Sep 17 00:00:00 2001 From: Manuel Lauss Date: Sat, 7 May 2011 13:55:19 +0200 Subject: MIPS: Alchemy: fix xxs1500 build error This fixes: alchemy/xxs1500/init.c: In function 'prom_init': alchemy/xxs1500/init.c:57:17: error: ignoring return value of 'kstrtoul', declared with attribute warn_unused_result Signed-off-by: Manuel Lauss Cc: Linux-MIPS Patchwork: https://patchwork.linux-mips.org/patch/2340/ Signed-off-by: Ralf Baechle diff --git a/arch/mips/alchemy/xxs1500/init.c b/arch/mips/alchemy/xxs1500/init.c index 15125c2..34a90a4 100644 --- a/arch/mips/alchemy/xxs1500/init.c +++ b/arch/mips/alchemy/xxs1500/init.c @@ -51,10 +51,9 @@ void __init prom_init(void) prom_init_cmdline(); memsize_str = prom_getenv("memsize"); - if (!memsize_str) + if (!memsize_str || strict_strtoul(memsize_str, 0, &memsize)) memsize = 0x04000000; - else - strict_strtoul(memsize_str, 0, &memsize); + add_memory_region(0, memsize, BOOT_MEM_RAM); } -- cgit v0.10.2 From 5db1c07ced19b2eec3a149a3c624d88e02e246ae Mon Sep 17 00:00:00 2001 From: Luciano Coelho Date: Tue, 3 May 2011 21:40:08 +0300 Subject: mac80211: don't start the dynamic ps timer if not associated When we are disconnecting, we set PS off, but this happens before we send the deauth/disassoc request. When the deauth/disassoc frames are sent, we trigger the dynamic ps timer, which then times out and turns PS back on. Thus, PS remains on after disconnecting, causing problems when associating again. This can be fixed by preventing the timer to start when we're not associated anymore. Signed-off-by: Luciano Coelho Signed-off-by: John W. Linville diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index ce4596e..bd1224f 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -237,6 +237,10 @@ ieee80211_tx_h_dynamic_ps(struct ieee80211_tx_data *tx) &local->dynamic_ps_disable_work); } + /* Don't restart the timer if we're not disassociated */ + if (!ifmgd->associated) + return TX_CONTINUE; + mod_timer(&local->dynamic_ps_timer, jiffies + msecs_to_jiffies(local->hw.conf.dynamic_ps_timeout)); -- cgit v0.10.2 From 99aa55b66e3553e6f7212ec1104e0fac06cc558e Mon Sep 17 00:00:00 2001 From: Mohammed Shafi Shajakhan Date: Fri, 6 May 2011 20:43:11 +0530 Subject: ath9k: Fix a warning due to a queued work during S3 state during suspend/S3 state drv_flush is called from mac80211 irrespective of interface count. In ath9k we queue a work in ath9k_flush which we expect to be cancelled in the drv_stop call back. during suspend process mac80211 calls drv_stop only when the interface count(local->count) is non-zero. unfortunately when the network manager is enabled, drv_flush is called while drv_stop is not called as local->count reaches '0'. So fix this by simply checking for the device presence in the drv_flush call back in the driver before queueing work or anything else. this patch fixes the following WARNING Call Trace: [] warn_slowpath_common+0x72/0xa0 [] ? ieee80211_can_queue_work+0x39/0x50 [mac80211] [] ? ieee80211_can_queue_work+0x39/0x50 [mac80211] [] warn_slowpath_fmt+0x2b/0x30 [] ieee80211_can_queue_work+0x39/0x50 [mac80211] [] ieee80211_queue_delayed_work+0x21/0x50 [mac80211] [] ath_tx_complete_poll_work+0xb2/0x100 [ath9k] [] run_workqueue+0x8e/0x150 [] ? ath_tx_complete_poll_work+0x0/0x100 [ath9k] [] worker_thread+0x84/0xe0 [] ? autoremove_wake_function+0x0/0x50 [] ? worker_thread+0x0/0xe0 [] kthread+0x74/0x80 [] ? kthread+0x0/0x80 [] kernel_thread_helper+0x7/0x10 ---[ end trace 2aff81010df9215b ]--- Signed-off-by: Rajkumar Manoharan Signed-off-by: Mohammed Shafi Shajakhan Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index 17d04ff..1482fa6 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -2141,6 +2141,8 @@ static void ath9k_set_coverage_class(struct ieee80211_hw *hw, u8 coverage_class) static void ath9k_flush(struct ieee80211_hw *hw, bool drop) { struct ath_softc *sc = hw->priv; + struct ath_hw *ah = sc->sc_ah; + struct ath_common *common = ath9k_hw_common(ah); int timeout = 200; /* ms */ int i, j; @@ -2149,6 +2151,12 @@ static void ath9k_flush(struct ieee80211_hw *hw, bool drop) cancel_delayed_work_sync(&sc->tx_complete_work); + if (sc->sc_flags & SC_OP_INVALID) { + ath_dbg(common, ATH_DBG_ANY, "Device not present\n"); + mutex_unlock(&sc->mutex); + return; + } + if (drop) timeout = 1; -- cgit v0.10.2 From eb85de3f84868ca85703a23617b4079ce79a801e Mon Sep 17 00:00:00 2001 From: Stanislaw Gruszka Date: Sat, 7 May 2011 17:46:21 +0200 Subject: iwlegacy: fix IBSS mode crashes We should not switch to non-IBSS channels when working in IBSS mode, otherwise there are microcode errors, and after some time system crashes. This bug is only observable when software scan is used in IBSS mode, so should be considered as regression after: commit 0263aa45293838b514b8af674a03faf040991a90 Author: Stanislaw Gruszka Date: Tue Mar 29 11:24:21 2011 +0200 iwl3945: disable hw scan by default However IBSS mode check, which this patch add again, was removed by commit b2f30e8bdd8ef5f3b5a7ef9146509585a15347d3 Author: Johannes Berg Date: Thu Jan 21 07:32:20 2010 -0800 iwlwifi: remove IBSS channel sanity check That commit claim that mac80211 will not use non-IBSS channel in IBSS mode, what definitely is not true. Bug probably should be fixed in mac80211, but that will require more work, so better to apply that patch temporally, and provide proper mac80211 fix latter. Resolves: https://bugzilla.kernel.org/show_bug.cgi?id=34452 Reported-and-tested-by: Mikko Rapeli Cc: stable@kernel.org # 2.6.38.5+ Signed-off-by: Stanislaw Gruszka Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwlegacy/iwl-core.c b/drivers/net/wireless/iwlegacy/iwl-core.c index 2b08efb..dcbb2ef 100644 --- a/drivers/net/wireless/iwlegacy/iwl-core.c +++ b/drivers/net/wireless/iwlegacy/iwl-core.c @@ -2155,6 +2155,13 @@ int iwl_legacy_mac_config(struct ieee80211_hw *hw, u32 changed) goto set_ch_out; } + if (priv->iw_mode == NL80211_IFTYPE_ADHOC && + !iwl_legacy_is_channel_ibss(ch_info)) { + IWL_DEBUG_MAC80211(priv, "leave - not IBSS channel\n"); + ret = -EINVAL; + goto set_ch_out; + } + spin_lock_irqsave(&priv->lock, flags); for_each_context(priv, ctx) { diff --git a/drivers/net/wireless/iwlegacy/iwl-dev.h b/drivers/net/wireless/iwlegacy/iwl-dev.h index 9ee849d..f43ac1e 100644 --- a/drivers/net/wireless/iwlegacy/iwl-dev.h +++ b/drivers/net/wireless/iwlegacy/iwl-dev.h @@ -1411,6 +1411,12 @@ iwl_legacy_is_channel_passive(const struct iwl_channel_info *ch) return (!(ch->flags & EEPROM_CHANNEL_ACTIVE)) ? 1 : 0; } +static inline int +iwl_legacy_is_channel_ibss(const struct iwl_channel_info *ch) +{ + return (ch->flags & EEPROM_CHANNEL_IBSS) ? 1 : 0; +} + static inline void __iwl_legacy_free_pages(struct iwl_priv *priv, struct page *page) { -- cgit v0.10.2 From 2ae1b8b35faba31a59b153cbad07f9c15de99740 Mon Sep 17 00:00:00 2001 From: Paul Fox Date: Mon, 9 May 2011 10:40:42 +0100 Subject: libertas: fix cmdpendingq locking We occasionally see list corruption using libertas. While we haven't been able to diagnose this precisely, we have spotted a possible cause: cmdpendingq is generally modified with driver_lock held. However, there are a couple of points where this is not the case. Fix up those operations to execute under the lock, it seems like the correct thing to do and will hopefully improve the situation. Signed-off-by: Paul Fox Signed-off-by: Daniel Drake Acked-by: Dan Williams Cc: stable@kernel.org Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/libertas/cmd.c b/drivers/net/wireless/libertas/cmd.c index 7e8a658..f3ac624 100644 --- a/drivers/net/wireless/libertas/cmd.c +++ b/drivers/net/wireless/libertas/cmd.c @@ -1339,8 +1339,8 @@ int lbs_execute_next_command(struct lbs_private *priv) cpu_to_le16(PS_MODE_ACTION_EXIT_PS)) { lbs_deb_host( "EXEC_NEXT_CMD: ignore ENTER_PS cmd\n"); - list_del(&cmdnode->list); spin_lock_irqsave(&priv->driver_lock, flags); + list_del(&cmdnode->list); lbs_complete_command(priv, cmdnode, 0); spin_unlock_irqrestore(&priv->driver_lock, flags); @@ -1352,8 +1352,8 @@ int lbs_execute_next_command(struct lbs_private *priv) (priv->psstate == PS_STATE_PRE_SLEEP)) { lbs_deb_host( "EXEC_NEXT_CMD: ignore EXIT_PS cmd in sleep\n"); - list_del(&cmdnode->list); spin_lock_irqsave(&priv->driver_lock, flags); + list_del(&cmdnode->list); lbs_complete_command(priv, cmdnode, 0); spin_unlock_irqrestore(&priv->driver_lock, flags); priv->needtowakeup = 1; @@ -1366,7 +1366,9 @@ int lbs_execute_next_command(struct lbs_private *priv) "EXEC_NEXT_CMD: sending EXIT_PS\n"); } } + spin_lock_irqsave(&priv->driver_lock, flags); list_del(&cmdnode->list); + spin_unlock_irqrestore(&priv->driver_lock, flags); lbs_deb_host("EXEC_NEXT_CMD: sending command 0x%04x\n", le16_to_cpu(cmd->command)); lbs_submit_command(priv, cmdnode); -- cgit v0.10.2 From 6572e91d5fa61bb3f879a00b96d763c566ced6cb Mon Sep 17 00:00:00 2001 From: Rajkumar Manoharan Date: Mon, 25 Apr 2011 15:56:16 +0530 Subject: wireless: Fix warnings due to -Wunused-but-set-variable These warnings are exposed by gcc 4.6. net/wireless/reg.c: In function 'freq_reg_info_regd': net/wireless/reg.c:675:38: warning: variable 'pr' set but not used [-Wunused-but-set-variable] net/wireless/lib80211_crypt_wep.c: In function 'lib80211_wep_build_iv': net/wireless/lib80211_crypt_wep.c:99:12: warning: variable 'len' set but not used [-Wunused-but-set-variable] Signed-off-by: Rajkumar Manoharan Signed-off-by: John W. Linville diff --git a/net/wireless/lib80211_crypt_wep.c b/net/wireless/lib80211_crypt_wep.c index e2e8887..2f265e0 100644 --- a/net/wireless/lib80211_crypt_wep.c +++ b/net/wireless/lib80211_crypt_wep.c @@ -96,13 +96,12 @@ static int lib80211_wep_build_iv(struct sk_buff *skb, int hdr_len, u8 *key, int keylen, void *priv) { struct lib80211_wep_data *wep = priv; - u32 klen, len; + u32 klen; u8 *pos; if (skb_headroom(skb) < 4 || skb->len < hdr_len) return -1; - len = skb->len - hdr_len; pos = skb_push(skb, 4); memmove(pos, pos + 4, hdr_len); pos += hdr_len; diff --git a/net/wireless/reg.c b/net/wireless/reg.c index 8982053..798cb4c 100644 --- a/net/wireless/reg.c +++ b/net/wireless/reg.c @@ -672,11 +672,9 @@ static int freq_reg_info_regd(struct wiphy *wiphy, for (i = 0; i < regd->n_reg_rules; i++) { const struct ieee80211_reg_rule *rr; const struct ieee80211_freq_range *fr = NULL; - const struct ieee80211_power_rule *pr = NULL; rr = ®d->reg_rules[i]; fr = &rr->freq_range; - pr = &rr->power_rule; /* * We only need to know if one frequency rule was -- cgit v0.10.2 From 3782cf4a04c272bdaa8476463b1d0208edbc505d Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Sat, 30 Apr 2011 08:38:16 -0700 Subject: iwlagn: led stay solid on when no traffic commit 5ed540aecc2aae92d5c97b9a9306a5bf88ad5574 change the led behavior for iwlwifi driver; the side effect cause led blink all the time. Modify the led blink table to fix this problem Signed-off-by: Wey-Yi Guy Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwlwifi/iwl-led.c b/drivers/net/wireless/iwlwifi/iwl-led.c index d798c2a..439187f 100644 --- a/drivers/net/wireless/iwlwifi/iwl-led.c +++ b/drivers/net/wireless/iwlwifi/iwl-led.c @@ -48,8 +48,21 @@ module_param(led_mode, int, S_IRUGO); MODULE_PARM_DESC(led_mode, "0=system default, " "1=On(RF On)/Off(RF Off), 2=blinking"); +/* Throughput OFF time(ms) ON time (ms) + * >300 25 25 + * >200 to 300 40 40 + * >100 to 200 55 55 + * >70 to 100 65 65 + * >50 to 70 75 75 + * >20 to 50 85 85 + * >10 to 20 95 95 + * >5 to 10 110 110 + * >1 to 5 130 130 + * >0 to 1 167 167 + * <=0 SOLID ON + */ static const struct ieee80211_tpt_blink iwl_blink[] = { - { .throughput = 0 * 1024 - 1, .blink_time = 334 }, + { .throughput = 0, .blink_time = 334 }, { .throughput = 1 * 1024 - 1, .blink_time = 260 }, { .throughput = 5 * 1024 - 1, .blink_time = 220 }, { .throughput = 10 * 1024 - 1, .blink_time = 190 }, @@ -125,6 +138,11 @@ static int iwl_led_cmd(struct iwl_priv *priv, if (priv->blink_on == on && priv->blink_off == off) return 0; + if (off == 0) { + /* led is SOLID_ON */ + on = IWL_LED_SOLID; + } + IWL_DEBUG_LED(priv, "Led blink time compensation=%u\n", priv->cfg->base_params->led_compensation); led_cmd.on = iwl_blink_compensation(priv, on, -- cgit v0.10.2 From 38bb3e9da62f6ebf1c6940d5482f0d6f431dac1c Mon Sep 17 00:00:00 2001 From: Larry Finger Date: Thu, 5 May 2011 18:48:47 -0500 Subject: mac80211: Fix build error when CONFIG_PM is not defined MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When mac80211 is built without CONFIG_PM being defined, the following errors are output: net/mac80211/main.c: In function ‘ieee80211_register_hw’: net/mac80211/main.c:700: error: ‘const struct ieee80211_ops’ has no member named ‘suspend’ net/mac80211/main.c:700: error: ‘const struct ieee80211_ops’ has no member named ‘resume’ make[2]: *** [net/mac80211/main.o] Error 1 make[1]: *** [net/mac80211] Error 2 make[1]: *** Waiting for unfinished jobs.... make: *** [net] Error 2 Signed-off-by: Larry Finger Signed-off-by: John W. Linville diff --git a/net/mac80211/main.c b/net/mac80211/main.c index cb326d3..ab1f464 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c @@ -696,8 +696,11 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) WLAN_CIPHER_SUITE_AES_CMAC }; - if ((hw->wiphy->wowlan.flags || hw->wiphy->wowlan.n_patterns) && - (!local->ops->suspend || !local->ops->resume)) + if ((hw->wiphy->wowlan.flags || hw->wiphy->wowlan.n_patterns) +#ifdef CONFIG_PM + && (!local->ops->suspend || !local->ops->resume) +#endif + ) return -EINVAL; if (hw->max_report_rates == 0) -- cgit v0.10.2 From deb751880af6f2dce6cdc232a7b023f2b58cd815 Mon Sep 17 00:00:00 2001 From: Rajkumar Manoharan Date: Fri, 6 May 2011 18:27:46 +0530 Subject: ath9k: avoid enabling interrupts while processing rx The assumsion is that while processing ath9k tasklet, interrupts were already disabled and it will be enabled at the completion of ath9k tasklet. But whenever TSFOOR is raised, the driver configures the beacon timers after having received a beacon frame from the AP which inturn enables the interrupts. Cc: stable@kernel.org Signed-off-by: Rajkumar Manoharan Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h index 1bffd15..f2f672b 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h @@ -564,6 +564,7 @@ struct ath_ant_comb { #define PS_WAIT_FOR_PSPOLL_DATA BIT(2) #define PS_WAIT_FOR_TX_ACK BIT(3) #define PS_BEACON_SYNC BIT(4) +#define PS_TSFOOR_SYNC BIT(5) struct ath_rate_table; diff --git a/drivers/net/wireless/ath/ath9k/beacon.c b/drivers/net/wireless/ath/ath9k/beacon.c index 22cd241..637dbc5 100644 --- a/drivers/net/wireless/ath/ath9k/beacon.c +++ b/drivers/net/wireless/ath/ath9k/beacon.c @@ -620,7 +620,13 @@ static void ath_beacon_config_sta(struct ath_softc *sc, ath9k_hw_disable_interrupts(ah); ath9k_hw_set_sta_beacon_timers(ah, &bs); ah->imask |= ATH9K_INT_BMISS; - ath9k_hw_set_interrupts(ah, ah->imask); + + /* + * If the beacon config is called beacause of TSFOOR, + * Interrupts will be enabled back at the end of ath9k_tasklet + */ + if (!(sc->ps_flags & PS_TSFOOR_SYNC)) + ath9k_hw_set_interrupts(ah, ah->imask); } static void ath_beacon_config_adhoc(struct ath_softc *sc, @@ -661,7 +667,12 @@ static void ath_beacon_config_adhoc(struct ath_softc *sc, ath9k_hw_disable_interrupts(ah); ath9k_beacon_init(sc, nexttbtt, intval); sc->beacon.bmisscnt = 0; - ath9k_hw_set_interrupts(ah, ah->imask); + /* + * If the beacon config is called beacause of TSFOOR, + * Interrupts will be enabled back at the end of ath9k_tasklet + */ + if (!(sc->ps_flags & PS_TSFOOR_SYNC)) + ath9k_hw_set_interrupts(ah, ah->imask); } static bool ath9k_allow_beacon_config(struct ath_softc *sc, diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index 3de115d..c171d11 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -718,7 +718,8 @@ void ath9k_tasklet(unsigned long data) */ ath_dbg(common, ATH_DBG_PS, "TSFOOR - Sync with next Beacon\n"); - sc->ps_flags |= PS_WAIT_FOR_BEACON | PS_BEACON_SYNC; + sc->ps_flags |= PS_WAIT_FOR_BEACON | PS_BEACON_SYNC | + PS_TSFOOR_SYNC; } if (ah->btcoex_hw.scheme == ATH_BTCOEX_CFG_3WIRE) diff --git a/drivers/net/wireless/ath/ath9k/recv.c b/drivers/net/wireless/ath/ath9k/recv.c index c5b7cbe..a485c04 100644 --- a/drivers/net/wireless/ath/ath9k/recv.c +++ b/drivers/net/wireless/ath/ath9k/recv.c @@ -572,6 +572,7 @@ static void ath_rx_ps_beacon(struct ath_softc *sc, struct sk_buff *skb) ath_dbg(common, ATH_DBG_PS, "Reconfigure Beacon timers based on timestamp from the AP\n"); ath_set_beacon(sc); + sc->ps_flags &= ~PS_TSFOOR_SYNC; } if (ath_beacon_dtim_pending_cab(skb)) { -- cgit v0.10.2 From 4105f8075051b62816830c95de1ec17ceb364d09 Mon Sep 17 00:00:00 2001 From: Rajkumar Manoharan Date: Fri, 6 May 2011 18:27:47 +0530 Subject: ath9k: process TSF out of range before RX Processing TSF out of range before RX helps to update beacon timers so early in the succeeding rx process. Signed-off-by: Rajkumar Manoharan Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index c171d11..11d9eca 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -689,6 +689,17 @@ void ath9k_tasklet(unsigned long data) !ath9k_hw_check_alive(ah)) ieee80211_queue_work(sc->hw, &sc->hw_check_work); + if ((status & ATH9K_INT_TSFOOR) && sc->ps_enabled) { + /* + * TSF sync does not look correct; remain awake to sync with + * the next Beacon. + */ + ath_dbg(common, ATH_DBG_PS, + "TSFOOR - Sync with next Beacon\n"); + sc->ps_flags |= PS_WAIT_FOR_BEACON | PS_BEACON_SYNC | + PS_TSFOOR_SYNC; + } + if (ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) rxmask = (ATH9K_INT_RXHP | ATH9K_INT_RXLP | ATH9K_INT_RXEOL | ATH9K_INT_RXORN); @@ -711,17 +722,6 @@ void ath9k_tasklet(unsigned long data) ath_tx_tasklet(sc); } - if ((status & ATH9K_INT_TSFOOR) && sc->ps_enabled) { - /* - * TSF sync does not look correct; remain awake to sync with - * the next Beacon. - */ - ath_dbg(common, ATH_DBG_PS, - "TSFOOR - Sync with next Beacon\n"); - sc->ps_flags |= PS_WAIT_FOR_BEACON | PS_BEACON_SYNC | - PS_TSFOOR_SYNC; - } - if (ah->btcoex_hw.scheme == ATH_BTCOEX_CFG_3WIRE) if (status & ATH9K_INT_GENTIMER) ath_gen_timer_isr(sc->sc_ah); -- cgit v0.10.2 From 054ec924944912413e4ee927b8cf02f476d08783 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 6 May 2011 11:11:20 -0700 Subject: iwlagn: fix iwl_is_any_associated The function iwl_is_any_associated() was intended to check both contexts, but due to an oversight it only checks the BSS context. This leads to a problem with scanning since the passive dwell time isn't restricted appropriately and a scan that includes passive channels will never finish if only the PAN context is associated since the default dwell time of 120ms won't fit into the normal 100 TU DTIM interval. Fix the function by using for_each_context() and also reorganise the other functions a bit to take advantage of each other making the code easier to read. Cc: stable@kernel.org Signed-off-by: Johannes Berg Signed-off-by: Wey-Yi Guy Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index 2fd752a..214e465 100644 --- a/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h @@ -1558,21 +1558,24 @@ iwl_rxon_ctx_from_vif(struct ieee80211_vif *vif) ctx < &priv->contexts[NUM_IWL_RXON_CTX]; ctx++) \ if (priv->valid_contexts & BIT(ctx->ctxid)) -static inline int iwl_is_associated(struct iwl_priv *priv, - enum iwl_rxon_context_id ctxid) +static inline int iwl_is_associated_ctx(struct iwl_rxon_context *ctx) { - return (priv->contexts[ctxid].active.filter_flags & - RXON_FILTER_ASSOC_MSK) ? 1 : 0; + return (ctx->active.filter_flags & RXON_FILTER_ASSOC_MSK) ? 1 : 0; } -static inline int iwl_is_any_associated(struct iwl_priv *priv) +static inline int iwl_is_associated(struct iwl_priv *priv, + enum iwl_rxon_context_id ctxid) { - return iwl_is_associated(priv, IWL_RXON_CTX_BSS); + return iwl_is_associated_ctx(&priv->contexts[ctxid]); } -static inline int iwl_is_associated_ctx(struct iwl_rxon_context *ctx) +static inline int iwl_is_any_associated(struct iwl_priv *priv) { - return (ctx->active.filter_flags & RXON_FILTER_ASSOC_MSK) ? 1 : 0; + struct iwl_rxon_context *ctx; + for_each_context(priv, ctx) + if (iwl_is_associated_ctx(ctx)) + return true; + return false; } static inline int is_channel_valid(const struct iwl_channel_info *ch_info) -- cgit v0.10.2 From c84aa5af996a306c8ce66aac2cc4d5f4a74e27ca Mon Sep 17 00:00:00 2001 From: Larry Finger Date: Fri, 6 May 2011 13:56:18 -0500 Subject: rtlwifi: Move 2 large arrays off stack In driver rtlwifi, efuse_read() places two relatively large arrays on the stack - a 1D u8 array of size 128, and a 2D array of u16 with 128 * 4 elements. With driver rtl8192de, the sizes will be 256 and 256 * 4 respectively. As that will make the 2D array be 2048 bytes, I have changed the code to use kmalloc to allocate the space. Signed-off-by: Larry Finger Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/rtlwifi/efuse.c b/drivers/net/wireless/rtlwifi/efuse.c index 510d42e..50de6f5 100644 --- a/drivers/net/wireless/rtlwifi/efuse.c +++ b/drivers/net/wireless/rtlwifi/efuse.c @@ -235,7 +235,7 @@ void read_efuse(struct ieee80211_hw *hw, u16 _offset, u16 _size_byte, u8 *pbuf) { struct rtl_priv *rtlpriv = rtl_priv(hw); struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw)); - u8 efuse_tbl[HWSET_MAX_SIZE]; + u8 *efuse_tbl; u8 rtemp8[1]; u16 efuse_addr = 0; u8 offset, wren; @@ -245,7 +245,7 @@ void read_efuse(struct ieee80211_hw *hw, u16 _offset, u16 _size_byte, u8 *pbuf) rtlpriv->cfg->maps[EFUSE_MAX_SECTION_MAP]; const u32 efuse_len = rtlpriv->cfg->maps[EFUSE_REAL_CONTENT_SIZE]; - u16 efuse_word[EFUSE_MAX_SECTION][EFUSE_MAX_WORD_UNIT]; + u16 **efuse_word; u16 efuse_utilized = 0; u8 efuse_usage; @@ -256,9 +256,24 @@ void read_efuse(struct ieee80211_hw *hw, u16 _offset, u16 _size_byte, u8 *pbuf) return; } + /* allocate memory for efuse_tbl and efuse_word */ + efuse_tbl = kmalloc(rtlpriv->cfg->maps[EFUSE_HWSET_MAX_SIZE] * + sizeof(u8), GFP_ATOMIC); + if (!efuse_tbl) + return; + efuse_word = kmalloc(EFUSE_MAX_WORD_UNIT * sizeof(u16 *), GFP_ATOMIC); + if (!efuse_word) + goto done; + for (i = 0; i < EFUSE_MAX_WORD_UNIT; i++) { + efuse_word[i] = kmalloc(efuse_max_section * sizeof(u16), + GFP_ATOMIC); + if (!efuse_word[i]) + goto done; + } + for (i = 0; i < efuse_max_section; i++) for (j = 0; j < EFUSE_MAX_WORD_UNIT; j++) - efuse_word[i][j] = 0xFFFF; + efuse_word[j][i] = 0xFFFF; read_efuse_byte(hw, efuse_addr, rtemp8); if (*rtemp8 != 0xFF) { @@ -285,7 +300,8 @@ void read_efuse(struct ieee80211_hw *hw, u16 _offset, u16 _size_byte, u8 *pbuf) read_efuse_byte(hw, efuse_addr, rtemp8); efuse_addr++; efuse_utilized++; - efuse_word[offset][i] = (*rtemp8 & 0xff); + efuse_word[i][offset] = + (*rtemp8 & 0xff); if (efuse_addr >= efuse_len) break; @@ -297,7 +313,7 @@ void read_efuse(struct ieee80211_hw *hw, u16 _offset, u16 _size_byte, u8 *pbuf) read_efuse_byte(hw, efuse_addr, rtemp8); efuse_addr++; efuse_utilized++; - efuse_word[offset][i] |= + efuse_word[i][offset] |= (((u16)*rtemp8 << 8) & 0xff00); if (efuse_addr >= efuse_len) @@ -320,9 +336,9 @@ void read_efuse(struct ieee80211_hw *hw, u16 _offset, u16 _size_byte, u8 *pbuf) for (i = 0; i < efuse_max_section; i++) { for (j = 0; j < EFUSE_MAX_WORD_UNIT; j++) { efuse_tbl[(i * 8) + (j * 2)] = - (efuse_word[i][j] & 0xff); + (efuse_word[j][i] & 0xff); efuse_tbl[(i * 8) + ((j * 2) + 1)] = - ((efuse_word[i][j] >> 8) & 0xff); + ((efuse_word[j][i] >> 8) & 0xff); } } @@ -336,6 +352,11 @@ void read_efuse(struct ieee80211_hw *hw, u16 _offset, u16 _size_byte, u8 *pbuf) (u8 *)&efuse_utilized); rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_EFUSE_USAGE, (u8 *)&efuse_usage); +done: + for (i = 0; i < EFUSE_MAX_WORD_UNIT; i++) + kfree(efuse_word[i]); + kfree(efuse_word); + kfree(efuse_tbl); } bool efuse_shadow_update_chk(struct ieee80211_hw *hw) -- cgit v0.10.2 From fc7707a469785fe786ddc66d723c150226ddc40e Mon Sep 17 00:00:00 2001 From: Chaoming Li Date: Fri, 6 May 2011 15:32:02 -0500 Subject: rtlwifi: rtl8192se: Remove need to disable ASPM When this driver was initially submitted, the system would crash unless ASPM was disabled. This problem has been fixed. This patch also adds a printk that outputs the name of the firmware file that is used. Signed-off-by: Chaoming_Li Signed-off-by: Larry Finger Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/rtlwifi/pci.c b/drivers/net/wireless/rtlwifi/pci.c index 3550c9f..a409528 100644 --- a/drivers/net/wireless/rtlwifi/pci.c +++ b/drivers/net/wireless/rtlwifi/pci.c @@ -1611,6 +1611,7 @@ static bool _rtl_pci_find_adapter(struct pci_dev *pdev, u16 irqline; u8 tmp; + pcipriv->ndis_adapter.pcibridge_vendor = PCI_BRIDGE_VENDOR_UNKNOWN; venderid = pdev->vendor; deviceid = pdev->device; pci_read_config_byte(pdev, 0x8, &revisionid); diff --git a/drivers/net/wireless/rtlwifi/rtl8192se/sw.c b/drivers/net/wireless/rtlwifi/rtl8192se/sw.c index 7cfd6a2c..1c6cb1d 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192se/sw.c +++ b/drivers/net/wireless/rtlwifi/rtl8192se/sw.c @@ -58,7 +58,7 @@ static void rtl92s_init_aspm_vars(struct ieee80211_hw *hw) * 4 - Always Enable ASPM without Clock Req. * set defult to RTL8192CE:3 RTL8192E:2 * */ - rtlpci->const_pci_aspm = 0; /* changed from 2 due to crashes */ + rtlpci->const_pci_aspm = 2; /*Setting for PCI-E device */ rtlpci->const_devicepci_aspm_setting = 0x03; @@ -183,6 +183,8 @@ static int rtl92s_init_sw_vars(struct ieee80211_hw *hw) return 1; } + printk(KERN_INFO "rtl8192se: Driver for Realtek RTL8192SE/RTL8191SE\n" + " Loading firmware %s\n", rtlpriv->cfg->fw_name); /* request fw */ err = request_firmware(&firmware, rtlpriv->cfg->fw_name, rtlpriv->io.dev); -- cgit v0.10.2 From 6490e334bc3af960965adfcef5acf6e5cbdd925c Mon Sep 17 00:00:00 2001 From: Christian Lamparter Date: Sat, 7 May 2011 11:13:37 +0200 Subject: carl9170: fix -Wunused-but-set-variable warnings MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit tx.c: In function ‘carl9170_tx_accounting_free’: tx.c:159:28: warning: variable ‘txinfo’ set but not used tx.c: In function ‘carl9170_tx_status_process_ampdu’: tx.c:383:27: warning: variable ‘ar_info’ set but not used tx.c: In function ‘__carl9170_tx_process_status’: tx.c:626:27: warning: variable ‘arinfo’ set but not used tx.c: In function ‘carl9170_tx_ampdu_queue’: tx.c:1324:15: warning: variable ‘max’ set but not used Signed-off-by: Christian Lamparter Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/carl9170/tx.c b/drivers/net/wireless/ath/carl9170/tx.c index bf2eff9..e94084f 100644 --- a/drivers/net/wireless/ath/carl9170/tx.c +++ b/drivers/net/wireless/ath/carl9170/tx.c @@ -156,10 +156,8 @@ out_rcu: static void carl9170_tx_accounting_free(struct ar9170 *ar, struct sk_buff *skb) { - struct ieee80211_tx_info *txinfo; int queue; - txinfo = IEEE80211_SKB_CB(skb); queue = skb_get_queue_mapping(skb); spin_lock_bh(&ar->tx_stats_lock); @@ -380,7 +378,6 @@ static void carl9170_tx_status_process_ampdu(struct ar9170 *ar, { struct _carl9170_tx_superframe *super = (void *) skb->data; struct ieee80211_hdr *hdr = (void *) super->frame_data; - struct carl9170_tx_info *ar_info; struct ieee80211_sta *sta; struct carl9170_sta_info *sta_info; struct carl9170_sta_tid *tid_info; @@ -391,8 +388,6 @@ static void carl9170_tx_status_process_ampdu(struct ar9170 *ar, (!(super->f.mac_control & cpu_to_le16(AR9170_TX_MAC_AGGR)))) return; - ar_info = (void *) txinfo->rate_driver_data; - rcu_read_lock(); sta = __carl9170_get_tx_sta(ar, skb); if (unlikely(!sta)) @@ -623,7 +618,6 @@ static void __carl9170_tx_process_status(struct ar9170 *ar, { struct sk_buff *skb; struct ieee80211_tx_info *txinfo; - struct carl9170_tx_info *arinfo; unsigned int r, t, q; bool success = true; @@ -639,7 +633,6 @@ static void __carl9170_tx_process_status(struct ar9170 *ar, } txinfo = IEEE80211_SKB_CB(skb); - arinfo = (void *) txinfo->rate_driver_data; if (!(info & CARL9170_TX_STATUS_SUCCESS)) success = false; @@ -1321,7 +1314,6 @@ static bool carl9170_tx_ampdu_queue(struct ar9170 *ar, struct carl9170_sta_info *sta_info; struct carl9170_sta_tid *agg; struct sk_buff *iter; - unsigned int max; u16 tid, seq, qseq, off; bool run = false; @@ -1331,7 +1323,6 @@ static bool carl9170_tx_ampdu_queue(struct ar9170 *ar, rcu_read_lock(); agg = rcu_dereference(sta_info->agg[tid]); - max = sta_info->ampdu_max_len; if (!agg) goto err_unlock_rcu; -- cgit v0.10.2 From 1816fcdcbbe9ff42ba1a9dac5198d18efb9d95e9 Mon Sep 17 00:00:00 2001 From: Christian Lamparter Date: Sat, 7 May 2011 11:16:08 +0200 Subject: p54pci: fix -Wunused-but-set-variable warnings MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit p54pci.c: In function ‘p54p_tx’: p54pci.c:334:6: warning: variable ‘device_idx’ set but not used Signed-off-by: Christian Lamparter Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/p54/p54pci.c b/drivers/net/wireless/p54/p54pci.c index 0494d7b..1b75317 100644 --- a/drivers/net/wireless/p54/p54pci.c +++ b/drivers/net/wireless/p54/p54pci.c @@ -331,10 +331,9 @@ static void p54p_tx(struct ieee80211_hw *dev, struct sk_buff *skb) struct p54p_ring_control *ring_control = priv->ring_control; struct p54p_desc *desc; dma_addr_t mapping; - u32 device_idx, idx, i; + u32 idx, i; spin_lock_irqsave(&priv->lock, flags); - device_idx = le32_to_cpu(ring_control->device_idx[1]); idx = le32_to_cpu(ring_control->host_idx[1]); i = idx % ARRAY_SIZE(ring_control->tx_data); -- cgit v0.10.2 From 9a24af1136e6d08c73010205caa282f46223aed5 Mon Sep 17 00:00:00 2001 From: Gertjan van Wingerde Date: Sat, 7 May 2011 17:27:46 +0200 Subject: rt2x00: Fix rmmod hang of rt2800pci txstatus_timer should only be deleted for USB devices, as it is only initialized for USB devices. Reported-by: Andreas Hartmann Signed-off-by: Gertjan van Wingerde Signed-off-by: Ivo van Doorn Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/rt2x00/rt2x00dev.c b/drivers/net/wireless/rt2x00/rt2x00dev.c index 2eb5196..c018d67 100644 --- a/drivers/net/wireless/rt2x00/rt2x00dev.c +++ b/drivers/net/wireless/rt2x00/rt2x00dev.c @@ -1159,9 +1159,9 @@ void rt2x00lib_remove_dev(struct rt2x00_dev *rt2x00dev) /* * Stop all work. */ - del_timer_sync(&rt2x00dev->txstatus_timer); cancel_work_sync(&rt2x00dev->intf_work); if (rt2x00_is_usb(rt2x00dev)) { + del_timer_sync(&rt2x00dev->txstatus_timer); cancel_work_sync(&rt2x00dev->rxdone_work); cancel_work_sync(&rt2x00dev->txdone_work); } -- cgit v0.10.2 From 25ea0dd9ffb7459f3b2948430f75d99b46ca1870 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= Date: Sun, 8 May 2011 20:30:32 +0200 Subject: b43: drop ssb-duplicated workaround for dangling cores MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Remove the code to detect inactive 802.11 cores, as that function is now done in ssb. Signed-off-by: RafaÅ‚ MiÅ‚ecki Tested-by: Larry Finger Acked-by: Larry Finger Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c index 675e288..70838e8 100644 --- a/drivers/net/wireless/b43/main.c +++ b/drivers/net/wireless/b43/main.c @@ -4836,25 +4836,8 @@ static void b43_one_core_detach(struct ssb_device *dev) static int b43_one_core_attach(struct ssb_device *dev, struct b43_wl *wl) { struct b43_wldev *wldev; - struct pci_dev *pdev; int err = -ENOMEM; - if (!list_empty(&wl->devlist)) { - /* We are not the first core on this chip. */ - pdev = (dev->bus->bustype == SSB_BUSTYPE_PCI) ? dev->bus->host_pci : NULL; - /* Only special chips support more than one wireless - * core, although some of the other chips have more than - * one wireless core as well. Check for this and - * bail out early. - */ - if (!pdev || - ((pdev->device != 0x4321) && - (pdev->device != 0x4313) && (pdev->device != 0x431A))) { - b43dbg(wl, "Ignoring unconnected 802.11 core\n"); - return -ENODEV; - } - } - wldev = kzalloc(sizeof(*wldev), GFP_KERNEL); if (!wldev) goto out; -- cgit v0.10.2 From 3ed3f49473985718ce51f84d990ed5b8b6472598 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= Date: Sun, 8 May 2011 20:30:33 +0200 Subject: b43legacy: drop ssb-duplicated workaround for dangling cores MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Remove the code to detect inactive 802.11 cores, as that function is now done in ssb. Signed-off-by: RafaÅ‚ MiÅ‚ecki Tested-by: Larry Finger Acked-by: Larry Finger Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/b43legacy/main.c b/drivers/net/wireless/b43legacy/main.c index 2162663..f6d5446 100644 --- a/drivers/net/wireless/b43legacy/main.c +++ b/drivers/net/wireless/b43legacy/main.c @@ -3696,26 +3696,8 @@ static int b43legacy_one_core_attach(struct ssb_device *dev, struct b43legacy_wl *wl) { struct b43legacy_wldev *wldev; - struct pci_dev *pdev; int err = -ENOMEM; - if (!list_empty(&wl->devlist)) { - /* We are not the first core on this chip. */ - pdev = (dev->bus->bustype == SSB_BUSTYPE_PCI) ? dev->bus->host_pci : NULL; - /* Only special chips support more than one wireless - * core, although some of the other chips have more than - * one wireless core as well. Check for this and - * bail out early. - */ - if (!pdev || - ((pdev->device != 0x4321) && - (pdev->device != 0x4313) && - (pdev->device != 0x431A))) { - b43legacydbg(wl, "Ignoring unconnected 802.11 core\n"); - return -ENODEV; - } - } - wldev = kzalloc(sizeof(*wldev), GFP_KERNEL); if (!wldev) goto out; -- cgit v0.10.2 From b53575ecf939a4f752de87eabf1adbcfa4478a6c Mon Sep 17 00:00:00 2001 From: Christoph Fritz Date: Sun, 8 May 2011 22:50:09 +0200 Subject: mwifiex: fix null derefs, mem leaks and trivia This patch: - adds kfree() where necessary - prevents potential null dereferences - makes use of kfree_skb() - replaces -1 for failed kzallocs with -ENOMEM Signed-off-by: Christoph Fritz Reviewed-by: Kiran Divekar Tested-by: Amitkumar Karwar Acked-by: Bing Zhao Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/mwifiex/11n_aggr.c b/drivers/net/wireless/mwifiex/11n_aggr.c index 12cf424..2b2cca5 100644 --- a/drivers/net/wireless/mwifiex/11n_aggr.c +++ b/drivers/net/wireless/mwifiex/11n_aggr.c @@ -318,7 +318,8 @@ mwifiex_11n_aggregate_pkt(struct mwifiex_private *priv, else skb_src = NULL; - pra_list->total_pkts_size -= skb_src->len; + if (skb_src) + pra_list->total_pkts_size -= skb_src->len; spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock, ra_list_flags); @@ -373,7 +374,8 @@ mwifiex_11n_aggregate_pkt(struct mwifiex_private *priv, (adapter->pps_uapsd_mode) && (adapter->tx_lock_flag)) { priv->adapter->tx_lock_flag = false; - ptx_pd->flags = 0; + if (ptx_pd) + ptx_pd->flags = 0; } skb_queue_tail(&pra_list->skb_head, skb_aggr); diff --git a/drivers/net/wireless/mwifiex/cfg80211.c b/drivers/net/wireless/mwifiex/cfg80211.c index 0c011637..19be887 100644 --- a/drivers/net/wireless/mwifiex/cfg80211.c +++ b/drivers/net/wireless/mwifiex/cfg80211.c @@ -1255,8 +1255,10 @@ int mwifiex_register_cfg80211(struct net_device *dev, u8 *mac, wdev->wiphy = wiphy_new(&mwifiex_cfg80211_ops, sizeof(struct mwifiex_private *)); - if (!wdev->wiphy) + if (!wdev->wiphy) { + kfree(wdev); return -ENOMEM; + } wdev->iftype = NL80211_IFTYPE_STATION; wdev->wiphy->max_scan_ssids = 10; wdev->wiphy->interface_modes = @@ -1296,6 +1298,7 @@ int mwifiex_register_cfg80211(struct net_device *dev, u8 *mac, dev_err(priv->adapter->dev, "%s: registering cfg80211 device\n", __func__); wiphy_free(wdev->wiphy); + kfree(wdev); return ret; } else { dev_dbg(priv->adapter->dev, diff --git a/drivers/net/wireless/mwifiex/cmdevt.c b/drivers/net/wireless/mwifiex/cmdevt.c index b75cc92..1c8b4f7 100644 --- a/drivers/net/wireless/mwifiex/cmdevt.c +++ b/drivers/net/wireless/mwifiex/cmdevt.c @@ -292,7 +292,7 @@ int mwifiex_alloc_cmd_buffer(struct mwifiex_adapter *adapter) if (!cmd_array) { dev_err(adapter->dev, "%s: failed to alloc cmd_array\n", __func__); - return -1; + return -ENOMEM; } adapter->cmd_pool = cmd_array; diff --git a/drivers/net/wireless/mwifiex/init.c b/drivers/net/wireless/mwifiex/init.c index 27ad72b..6a8fd99 100644 --- a/drivers/net/wireless/mwifiex/init.c +++ b/drivers/net/wireless/mwifiex/init.c @@ -41,7 +41,7 @@ static int mwifiex_add_bss_prio_tbl(struct mwifiex_private *priv) if (!bss_prio) { dev_err(adapter->dev, "%s: failed to alloc bss_prio\n", __func__); - return -1; + return -ENOMEM; } bss_prio->priv = priv; @@ -161,7 +161,7 @@ static int mwifiex_allocate_adapter(struct mwifiex_adapter *adapter) if (!temp_scan_table) { dev_err(adapter->dev, "%s: failed to alloc temp_scan_table\n", __func__); - return -1; + return -ENOMEM; } adapter->scan_table = temp_scan_table; diff --git a/drivers/net/wireless/mwifiex/main.c b/drivers/net/wireless/mwifiex/main.c index 38f912b..44957ca 100644 --- a/drivers/net/wireless/mwifiex/main.c +++ b/drivers/net/wireless/mwifiex/main.c @@ -69,7 +69,7 @@ static int mwifiex_register(void *card, struct mwifiex_if_ops *if_ops, adapter = kzalloc(sizeof(struct mwifiex_adapter), GFP_KERNEL); if (!adapter) - return -1; + return -ENOMEM; g_adapter = adapter; adapter->card = card; @@ -516,13 +516,13 @@ mwifiex_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) jiffies, priv->bss_index); if (priv->adapter->surprise_removed) { - kfree(skb); + kfree_skb(skb); priv->stats.tx_dropped++; return 0; } if (!skb->len || (skb->len > ETH_FRAME_LEN)) { dev_err(priv->adapter->dev, "Tx: bad skb len %d\n", skb->len); - kfree(skb); + kfree_skb(skb); priv->stats.tx_dropped++; return 0; } @@ -535,7 +535,7 @@ mwifiex_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) skb_realloc_headroom(skb, MWIFIEX_MIN_DATA_HEADER_LEN); if (unlikely(!new_skb)) { dev_err(priv->adapter->dev, "Tx: cannot alloca new_skb\n"); - kfree(skb); + kfree_skb(skb); priv->stats.tx_dropped++; return 0; } diff --git a/drivers/net/wireless/mwifiex/scan.c b/drivers/net/wireless/mwifiex/scan.c index 4968974..5c22860 100644 --- a/drivers/net/wireless/mwifiex/scan.c +++ b/drivers/net/wireless/mwifiex/scan.c @@ -2283,7 +2283,7 @@ int mwifiex_scan_networks(struct mwifiex_private *priv, GFP_KERNEL); if (!scan_cfg_out) { dev_err(adapter->dev, "failed to alloc scan_cfg_out\n"); - return -1; + return -ENOMEM; } buf_size = sizeof(struct mwifiex_chan_scan_param_set) * @@ -2292,7 +2292,7 @@ int mwifiex_scan_networks(struct mwifiex_private *priv, if (!scan_chan_list) { dev_err(adapter->dev, "failed to alloc scan_chan_list\n"); kfree(scan_cfg_out); - return -1; + return -ENOMEM; } keep_previous_scan = false; @@ -2491,7 +2491,7 @@ int mwifiex_ret_802_11_scan(struct mwifiex_private *priv, GFP_KERNEL); if (!bss_new_entry) { dev_err(adapter->dev, " failed to alloc bss_new_entry\n"); - return -1; + return -ENOMEM; } for (idx = 0; idx < scan_rsp->number_of_sets && bytes_left; idx++) { @@ -2881,7 +2881,7 @@ static int mwifiex_scan_specific_ssid(struct mwifiex_private *priv, scan_cfg = kzalloc(sizeof(struct mwifiex_user_scan_cfg), GFP_KERNEL); if (!scan_cfg) { dev_err(adapter->dev, "failed to alloc scan_cfg\n"); - return -1; + return -ENOMEM; } memcpy(scan_cfg->ssid_list[0].ssid, req_ssid->ssid, diff --git a/drivers/net/wireless/mwifiex/sdio.c b/drivers/net/wireless/mwifiex/sdio.c index 470dbaa..d425dbd 100644 --- a/drivers/net/wireless/mwifiex/sdio.c +++ b/drivers/net/wireless/mwifiex/sdio.c @@ -68,6 +68,7 @@ mwifiex_sdio_probe(struct sdio_func *func, const struct sdio_device_id *id) if (ret) { pr_err("%s: failed to enable function\n", __func__); + kfree(card); return -EIO; } @@ -676,7 +677,7 @@ static int mwifiex_prog_fw_w_helper(struct mwifiex_adapter *adapter, if (!fwbuf) { dev_err(adapter->dev, "unable to alloc buffer for firmware." " Terminating download\n"); - return -1; + return -ENOMEM; } /* Perform firmware data transfer */ @@ -1605,7 +1606,7 @@ static int mwifiex_init_sdio(struct mwifiex_adapter *adapter) card->mp_regs = kzalloc(MAX_MP_REGS, GFP_KERNEL); if (!card->mp_regs) { dev_err(adapter->dev, "failed to alloc mp_regs\n"); - return -1; + return -ENOMEM; } ret = mwifiex_alloc_sdio_mpa_buffers(adapter, diff --git a/drivers/net/wireless/mwifiex/sta_ioctl.c b/drivers/net/wireless/mwifiex/sta_ioctl.c index 4585c1b..75bca56 100644 --- a/drivers/net/wireless/mwifiex/sta_ioctl.c +++ b/drivers/net/wireless/mwifiex/sta_ioctl.c @@ -895,7 +895,7 @@ int mwifiex_set_tx_power(struct mwifiex_private *priv, if (!buf) { dev_err(priv->adapter->dev, "%s: failed to alloc cmd buffer\n", __func__); - return -1; + return -ENOMEM; } txp_cfg = (struct host_cmd_ds_txpwr_cfg *) buf; -- cgit v0.10.2 From 5ee9c6afcb72eb41c3607e424c3b969f8c56031b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= Date: Mon, 9 May 2011 00:21:18 +0200 Subject: b43: trivial: include ssb word in ssb specific functions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This can be helpful when we decide to add support for other buses. Signed-off-by: RafaÅ‚ MiÅ‚ecki Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c index 70838e8..f7582c0 100644 --- a/drivers/net/wireless/b43/main.c +++ b/drivers/net/wireless/b43/main.c @@ -4958,7 +4958,7 @@ out: return err; } -static int b43_probe(struct ssb_device *dev, const struct ssb_device_id *id) +static int b43_ssb_probe(struct ssb_device *dev, const struct ssb_device_id *id) { struct b43_wl *wl; int err; @@ -4996,7 +4996,7 @@ static int b43_probe(struct ssb_device *dev, const struct ssb_device_id *id) return err; } -static void b43_remove(struct ssb_device *dev) +static void b43_ssb_remove(struct ssb_device *dev) { struct b43_wl *wl = ssb_get_devtypedata(dev); struct b43_wldev *wldev = ssb_get_drvdata(dev); @@ -5039,8 +5039,8 @@ void b43_controller_restart(struct b43_wldev *dev, const char *reason) static struct ssb_driver b43_ssb_driver = { .name = KBUILD_MODNAME, .id_table = b43_ssb_tbl, - .probe = b43_probe, - .remove = b43_remove, + .probe = b43_ssb_probe, + .remove = b43_ssb_remove, }; static void b43_print_driverinfo(void) -- cgit v0.10.2 From 8c12c7b0efce09b87e67d05332bdcb86ea83f65a Mon Sep 17 00:00:00 2001 From: Mohammed Shafi Shajakhan Date: Mon, 9 May 2011 10:29:01 +0530 Subject: ath9k_hw: remove get_channel_noise function currently ath9k_hw_getchan_noise is not used anywhere Signed-off-by: Mohammed Shafi Shajakhan Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/calib.c b/drivers/net/wireless/ath/ath9k/calib.c index fe3c10e..558b228 100644 --- a/drivers/net/wireless/ath/ath9k/calib.c +++ b/drivers/net/wireless/ath/ath9k/calib.c @@ -409,14 +409,6 @@ void ath9k_init_nfcal_hist_buffer(struct ath_hw *ah, } } -s16 ath9k_hw_getchan_noise(struct ath_hw *ah, struct ath9k_channel *chan) -{ - if (!ah->curchan || !ah->curchan->noisefloor) - return ath9k_hw_get_default_nf(ah, chan); - - return ah->curchan->noisefloor; -} -EXPORT_SYMBOL(ath9k_hw_getchan_noise); void ath9k_hw_bstuck_nfcal(struct ath_hw *ah) { diff --git a/drivers/net/wireless/ath/ath9k/calib.h b/drivers/net/wireless/ath/ath9k/calib.h index b8973eb..4420780 100644 --- a/drivers/net/wireless/ath/ath9k/calib.h +++ b/drivers/net/wireless/ath/ath9k/calib.h @@ -106,7 +106,6 @@ bool ath9k_hw_getnf(struct ath_hw *ah, struct ath9k_channel *chan); void ath9k_init_nfcal_hist_buffer(struct ath_hw *ah, struct ath9k_channel *chan); void ath9k_hw_bstuck_nfcal(struct ath_hw *ah); -s16 ath9k_hw_getchan_noise(struct ath_hw *ah, struct ath9k_channel *chan); void ath9k_hw_reset_calibration(struct ath_hw *ah, struct ath9k_cal_list *currCal); -- cgit v0.10.2 From 73f743670d36ddd61247d709711227b0e2e1a497 Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Mon, 9 May 2011 12:51:57 -0700 Subject: rtlwifi: rtl8192cu: Fix memset/memcpy using sizeof(ptr) not sizeof(*ptr) Found via coccinelle script @@ type T; T* ptr; expression E1; @@ * memset(E1, 0, sizeof(ptr)); Signed-off-by: Joe Perches Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/rtlwifi/rtl8192cu/trx.c b/drivers/net/wireless/rtlwifi/rtl8192cu/trx.c index 79c98f6..3a92ba3 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192cu/trx.c +++ b/drivers/net/wireless/rtlwifi/rtl8192cu/trx.c @@ -372,7 +372,7 @@ static void _rtl_rx_process(struct ieee80211_hw *hw, struct sk_buff *skb) __le16 fc; struct ieee80211_hdr *hdr; - memset(rx_status, 0, sizeof(rx_status)); + memset(rx_status, 0, sizeof(*rx_status)); rxdesc = skb->data; skb_len = skb->len; drvinfo_len = (GET_RX_DESC_DRVINFO_SIZE(rxdesc) * RTL_RX_DRV_INFO_UNIT); @@ -434,7 +434,7 @@ static void _rtl_rx_process(struct ieee80211_hw *hw, struct sk_buff *skb) "0x%02X\n", fc, (u32)hdr->addr1[0], (u32)hdr->addr1[1], (u32)hdr->addr1[2], (u32)hdr->addr1[3], (u32)hdr->addr1[4], (u32)hdr->addr1[5])); - memcpy(IEEE80211_SKB_RXCB(skb), &rx_status, sizeof(rx_status)); + memcpy(IEEE80211_SKB_RXCB(skb), rx_status, sizeof(*rx_status)); ieee80211_rx_irqsafe(hw, skb); } -- cgit v0.10.2 From 165af96d56dce3bd0cd09567106f22215f80bb63 Mon Sep 17 00:00:00 2001 From: Rajkumar Manoharan Date: Mon, 9 May 2011 19:11:26 +0530 Subject: ath9k_hw: Corrected xpabiaslevel register settings for AR9340 Signed-off-by: Rajkumar Manoharan Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c b/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c index a9dd3a4..070dc8b 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c @@ -3442,17 +3442,15 @@ static void ar9003_hw_xpa_bias_level_apply(struct ath_hw *ah, bool is2ghz) { int bias = ar9003_hw_xpa_bias_level_get(ah, is2ghz); - if (AR_SREV_9485(ah)) + if (AR_SREV_9485(ah) || AR_SREV_9340(ah)) REG_RMW_FIELD(ah, AR_CH0_TOP2, AR_CH0_TOP2_XPABIASLVL, bias); else { REG_RMW_FIELD(ah, AR_CH0_TOP, AR_CH0_TOP_XPABIASLVL, bias); - if (!AR_SREV_9340(ah)) { - REG_RMW_FIELD(ah, AR_CH0_THERM, - AR_CH0_THERM_XPABIASLVL_MSB, - bias >> 2); - REG_RMW_FIELD(ah, AR_CH0_THERM, - AR_CH0_THERM_XPASHORT2GND, 1); - } + REG_RMW_FIELD(ah, AR_CH0_THERM, + AR_CH0_THERM_XPABIASLVL_MSB, + bias >> 2); + REG_RMW_FIELD(ah, AR_CH0_THERM, + AR_CH0_THERM_XPASHORT2GND, 1); } } -- cgit v0.10.2 From 94333f59cba08a1f6513ecd7e2fc5b85c1949a98 Mon Sep 17 00:00:00 2001 From: Rajkumar Manoharan Date: Mon, 9 May 2011 19:11:27 +0530 Subject: ath9k_hw: Change DCU backoff thresh for AR9340 By changing DCU backoff threshold for AR9340 to 1, helps to reduce rx overrurns seen while running bidirectional traffic. Signed-off-by: Rajkumar Manoharan Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/mac.c b/drivers/net/wireless/ath/ath9k/mac.c index 9cf7a7d..bd6d2b9 100644 --- a/drivers/net/wireless/ath/ath9k/mac.c +++ b/drivers/net/wireless/ath/ath9k/mac.c @@ -430,8 +430,13 @@ bool ath9k_hw_resettxqueue(struct ath_hw *ah, u32 q) SM(qi->tqi_shretry, AR_D_RETRY_LIMIT_FR_SH)); REG_WRITE(ah, AR_QMISC(q), AR_Q_MISC_DCU_EARLY_TERM_REQ); - REG_WRITE(ah, AR_DMISC(q), - AR_D_MISC_CW_BKOFF_EN | AR_D_MISC_FRAG_WAIT_EN | 0x2); + + if (AR_SREV_9340(ah)) + REG_WRITE(ah, AR_DMISC(q), + AR_D_MISC_CW_BKOFF_EN | AR_D_MISC_FRAG_WAIT_EN | 0x1); + else + REG_WRITE(ah, AR_DMISC(q), + AR_D_MISC_CW_BKOFF_EN | AR_D_MISC_FRAG_WAIT_EN | 0x2); if (qi->tqi_cbrPeriod) { REG_WRITE(ah, AR_QCBRCFG(q), -- cgit v0.10.2 From 2b892a98db269b96ed097d560aaaa371907d20f5 Mon Sep 17 00:00:00 2001 From: Rajkumar Manoharan Date: Mon, 9 May 2011 19:11:28 +0530 Subject: ath9k: Fix rssi update in ad-hoc mode The average beacon rssi which will be used by ani is not updated in adhoc mode. Signed-off-by: Rajkumar Manoharan Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/recv.c b/drivers/net/wireless/ath/ath9k/recv.c index a485c04..9fcd1e4 100644 --- a/drivers/net/wireless/ath/ath9k/recv.c +++ b/drivers/net/wireless/ath/ath9k/recv.c @@ -917,7 +917,8 @@ static void ath9k_process_rssi(struct ath_common *common, int last_rssi; __le16 fc; - if (ah->opmode != NL80211_IFTYPE_STATION) + if ((ah->opmode != NL80211_IFTYPE_STATION) && + (ah->opmode != NL80211_IFTYPE_ADHOC)) return; fc = hdr->frame_control; -- cgit v0.10.2 From 729da390034d04ff1b3a3f188dfb04a54f458e35 Mon Sep 17 00:00:00 2001 From: Rajkumar Manoharan Date: Mon, 9 May 2011 19:11:29 +0530 Subject: ath9k: Failed to set default beacon rssi in AP/IBSS mode This beacon rssi will be used to set noisefloor during ani reset. Signed-off-by: Rajkumar Manoharan Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index 11d9eca..c4d32c5 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -1409,6 +1409,7 @@ static void ath9k_calculate_summary_state(struct ieee80211_hw *hw, /* Set up ANI */ if ((iter_data.naps + iter_data.nadhocs) > 0) { + sc->sc_ah->stats.avgbrssi = ATH_RSSI_DUMMY_MARKER; sc->sc_flags |= SC_OP_ANI_RUN; ath_start_ani(common); } else { -- cgit v0.10.2 From 306fe9384f06d31219778cece2d3c646146e7bb6 Mon Sep 17 00:00:00 2001 From: Luciano Coelho Date: Mon, 9 May 2011 19:15:04 +0300 Subject: mac80211: don't drop frames where skb->len < 24 in ieee80211_scan_rx() This seems to be a leftover from the old days, when we didn't support any frames that didn't contain the full ieee802.11 header. This is not the case anymore. It does not cause problems now, because they are only dropped during scan. But when scheduled scans get merged, this would become a problem because we would drop all small frames while scheduled scan is running. To fix this, return RX_CONTINUE instead of RX_DROP_MONITOR. Cc: Johannes Berg Signed-off-by: Luciano Coelho Signed-off-by: John W. Linville diff --git a/net/mac80211/scan.c b/net/mac80211/scan.c index 489b6ad..8acce72 100644 --- a/net/mac80211/scan.c +++ b/net/mac80211/scan.c @@ -170,7 +170,7 @@ ieee80211_scan_rx(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb) return RX_CONTINUE; if (skb->len < 24) - return RX_DROP_MONITOR; + return RX_CONTINUE; presp = ieee80211_is_probe_resp(fc); if (presp) { -- cgit v0.10.2 From 8369ae33b705222aa05ab53c7d6b4458f4ed161b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= Date: Mon, 9 May 2011 18:56:46 +0200 Subject: bcma: add Broadcom specific AMBA bus driver MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Broadcom has released cards based on a new AMBA-based bus type. From a programming point of view, this new bus type differs from AMBA and does not use AMBA common registers. It also differs enough from SSB. We decided that a new bus driver is needed to keep the code clean. In its current form, the driver detects devices present on the bus and registers them in the system. It allows registering BCMA drivers for specified bus devices and provides them basic operations. The bus driver itself includes two important bus managing drivers: ChipCommon core driver and PCI(c) core driver. They are early used to allow correct initialization. Currently code is limited to supporting buses on PCI(e) devices, however the driver is designed to be used also on other hosts. The host abstraction layer is implemented and already used for PCI(e). Support for PCI(e) hosts is working and seems to be stable (access to 80211 core was tested successfully on a few devices). We can still optimize it by using some fixed windows, but this can be done later without affecting any external code. Windows are just ranges in MMIO used for accessing cores on the bus. Cc: Greg KH Cc: Michael Büsch Cc: Larry Finger Cc: George Kashperko Cc: Arend van Spriel Cc: linux-arm-kernel@lists.infradead.org Cc: Russell King Cc: Arnd Bergmann Cc: Andy Botting Cc: linuxdriverproject Cc: linux-kernel@vger.kernel.org Signed-off-by: RafaÅ‚ MiÅ‚ecki Signed-off-by: John W. Linville diff --git a/Documentation/ABI/testing/sysfs-bus-bcma b/Documentation/ABI/testing/sysfs-bus-bcma new file mode 100644 index 0000000..06b62ba --- /dev/null +++ b/Documentation/ABI/testing/sysfs-bus-bcma @@ -0,0 +1,31 @@ +What: /sys/bus/bcma/devices/.../manuf +Date: May 2011 +KernelVersion: 2.6.40 +Contact: RafaÅ‚ MiÅ‚ecki +Description: + Each BCMA core has it's manufacturer id. See + include/linux/bcma/bcma.h for possible values. + +What: /sys/bus/bcma/devices/.../id +Date: May 2011 +KernelVersion: 2.6.40 +Contact: RafaÅ‚ MiÅ‚ecki +Description: + There are a few types of BCMA cores, they can be identified by + id field. + +What: /sys/bus/bcma/devices/.../rev +Date: May 2011 +KernelVersion: 2.6.40 +Contact: RafaÅ‚ MiÅ‚ecki +Description: + BCMA cores of the same type can still slightly differ depending + on their revision. Use it for detailed programming. + +What: /sys/bus/bcma/devices/.../class +Date: May 2011 +KernelVersion: 2.6.40 +Contact: RafaÅ‚ MiÅ‚ecki +Description: + Each BCMA core is identified by few fields, including class it + belongs to. See include/linux/bcma/bcma.h for possible values. diff --git a/MAINTAINERS b/MAINTAINERS index 9f91049..df55858 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -5810,6 +5810,13 @@ S: Maintained F: drivers/ssb/ F: include/linux/ssb/ +BROADCOM SPECIFIC AMBA DRIVER (BCMA) +M: RafaÅ‚ MiÅ‚ecki +L: linux-wireless@vger.kernel.org +S: Maintained +F: drivers/bcma/ +F: include/linux/bcma/ + SONY VAIO CONTROL DEVICE DRIVER M: Mattia Dongili L: platform-driver-x86@vger.kernel.org diff --git a/drivers/Kconfig b/drivers/Kconfig index 177c7d1..aca7067 100644 --- a/drivers/Kconfig +++ b/drivers/Kconfig @@ -68,6 +68,8 @@ source "drivers/watchdog/Kconfig" source "drivers/ssb/Kconfig" +source "drivers/bcma/Kconfig" + source "drivers/mfd/Kconfig" source "drivers/regulator/Kconfig" diff --git a/drivers/Makefile b/drivers/Makefile index 3f135b6..a29527f 100644 --- a/drivers/Makefile +++ b/drivers/Makefile @@ -110,6 +110,7 @@ obj-$(CONFIG_HID) += hid/ obj-$(CONFIG_PPC_PS3) += ps3/ obj-$(CONFIG_OF) += of/ obj-$(CONFIG_SSB) += ssb/ +obj-$(CONFIG_BCMA) += bcma/ obj-$(CONFIG_VHOST_NET) += vhost/ obj-$(CONFIG_VLYNQ) += vlynq/ obj-$(CONFIG_STAGING) += staging/ diff --git a/drivers/bcma/Kconfig b/drivers/bcma/Kconfig new file mode 100644 index 0000000..353781b --- /dev/null +++ b/drivers/bcma/Kconfig @@ -0,0 +1,33 @@ +config BCMA_POSSIBLE + bool + depends on HAS_IOMEM && HAS_DMA + default y + +menu "Broadcom specific AMBA" + depends on BCMA_POSSIBLE + +config BCMA + tristate "BCMA support" + depends on BCMA_POSSIBLE + help + Bus driver for Broadcom specific Advanced Microcontroller Bus + Architecture. + +config BCMA_HOST_PCI_POSSIBLE + bool + depends on BCMA && PCI = y + default y + +config BCMA_HOST_PCI + bool "Support for BCMA on PCI-host bus" + depends on BCMA_HOST_PCI_POSSIBLE + +config BCMA_DEBUG + bool "BCMA debugging" + depends on BCMA + help + This turns on additional debugging messages. + + If unsure, say N + +endmenu diff --git a/drivers/bcma/Makefile b/drivers/bcma/Makefile new file mode 100644 index 0000000..0d56245 --- /dev/null +++ b/drivers/bcma/Makefile @@ -0,0 +1,7 @@ +bcma-y += main.o scan.o core.o +bcma-y += driver_chipcommon.o driver_chipcommon_pmu.o +bcma-y += driver_pci.o +bcma-$(CONFIG_BCMA_HOST_PCI) += host_pci.o +obj-$(CONFIG_BCMA) += bcma.o + +ccflags-$(CONFIG_BCMA_DEBUG) := -DDEBUG diff --git a/drivers/bcma/README b/drivers/bcma/README new file mode 100644 index 0000000..f7e7ce4 --- /dev/null +++ b/drivers/bcma/README @@ -0,0 +1,19 @@ +Broadcom introduced new bus as replacement for older SSB. It is based on AMBA, +however from programming point of view there is nothing AMBA specific we use. + +Standard AMBA drivers are platform specific, have hardcoded addresses and use +AMBA standard fields like CID and PID. + +In case of Broadcom's cards every device consists of: +1) Broadcom specific AMBA device. It is put on AMBA bus, but can not be treated + as standard AMBA device. Reading it's CID or PID can cause machine lockup. +2) AMBA standard devices called ports or wrappers. They have CIDs (AMBA_CID) + and PIDs (0x103BB369), but we do not use that info for anything. One of that + devices is used for managing Broadcom specific core. + +Addresses of AMBA devices are not hardcoded in driver and have to be read from +EPROM. + +In this situation we decided to introduce separated bus. It can contain up to +16 devices identified by Broadcom specific fields: manufacturer, id, revision +and class. diff --git a/drivers/bcma/TODO b/drivers/bcma/TODO new file mode 100644 index 0000000..da7aa99 --- /dev/null +++ b/drivers/bcma/TODO @@ -0,0 +1,3 @@ +- Interrupts +- Defines for PCI core driver +- Create kernel Documentation (use info from README) diff --git a/drivers/bcma/bcma_private.h b/drivers/bcma/bcma_private.h new file mode 100644 index 0000000..2f72e9c --- /dev/null +++ b/drivers/bcma/bcma_private.h @@ -0,0 +1,28 @@ +#ifndef LINUX_BCMA_PRIVATE_H_ +#define LINUX_BCMA_PRIVATE_H_ + +#ifndef pr_fmt +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt +#endif + +#include +#include + +#define BCMA_CORE_SIZE 0x1000 + +struct bcma_bus; + +/* main.c */ +extern int bcma_bus_register(struct bcma_bus *bus); +extern void bcma_bus_unregister(struct bcma_bus *bus); + +/* scan.c */ +int bcma_bus_scan(struct bcma_bus *bus); + +#ifdef CONFIG_BCMA_HOST_PCI +/* host_pci.c */ +extern int __init bcma_host_pci_init(void); +extern void __exit bcma_host_pci_exit(void); +#endif /* CONFIG_BCMA_HOST_PCI */ + +#endif diff --git a/drivers/bcma/core.c b/drivers/bcma/core.c new file mode 100644 index 0000000..ced379f --- /dev/null +++ b/drivers/bcma/core.c @@ -0,0 +1,51 @@ +/* + * Broadcom specific AMBA + * Core ops + * + * Licensed under the GNU/GPL. See COPYING for details. + */ + +#include "bcma_private.h" +#include + +bool bcma_core_is_enabled(struct bcma_device *core) +{ + if ((bcma_aread32(core, BCMA_IOCTL) & (BCMA_IOCTL_CLK | BCMA_IOCTL_FGC)) + != BCMA_IOCTL_CLK) + return false; + if (bcma_aread32(core, BCMA_RESET_CTL) & BCMA_RESET_CTL_RESET) + return false; + return true; +} +EXPORT_SYMBOL_GPL(bcma_core_is_enabled); + +static void bcma_core_disable(struct bcma_device *core, u32 flags) +{ + if (bcma_aread32(core, BCMA_RESET_CTL) & BCMA_RESET_CTL_RESET) + return; + + bcma_awrite32(core, BCMA_IOCTL, flags); + bcma_aread32(core, BCMA_IOCTL); + udelay(10); + + bcma_awrite32(core, BCMA_RESET_CTL, BCMA_RESET_CTL_RESET); + udelay(1); +} + +int bcma_core_enable(struct bcma_device *core, u32 flags) +{ + bcma_core_disable(core, flags); + + bcma_awrite32(core, BCMA_IOCTL, (BCMA_IOCTL_CLK | BCMA_IOCTL_FGC | flags)); + bcma_aread32(core, BCMA_IOCTL); + + bcma_awrite32(core, BCMA_RESET_CTL, 0); + udelay(1); + + bcma_awrite32(core, BCMA_IOCTL, (BCMA_IOCTL_CLK | flags)); + bcma_aread32(core, BCMA_IOCTL); + udelay(1); + + return 0; +} +EXPORT_SYMBOL_GPL(bcma_core_enable); diff --git a/drivers/bcma/driver_chipcommon.c b/drivers/bcma/driver_chipcommon.c new file mode 100644 index 0000000..caf5960 --- /dev/null +++ b/drivers/bcma/driver_chipcommon.c @@ -0,0 +1,87 @@ +/* + * Broadcom specific AMBA + * ChipCommon core driver + * + * Copyright 2005, Broadcom Corporation + * Copyright 2006, 2007, Michael Buesch + * + * Licensed under the GNU/GPL. See COPYING for details. + */ + +#include "bcma_private.h" +#include + +static inline u32 bcma_cc_write32_masked(struct bcma_drv_cc *cc, u16 offset, + u32 mask, u32 value) +{ + value &= mask; + value |= bcma_cc_read32(cc, offset) & ~mask; + bcma_cc_write32(cc, offset, value); + + return value; +} + +void bcma_core_chipcommon_init(struct bcma_drv_cc *cc) +{ + if (cc->core->id.rev >= 11) + cc->status = bcma_cc_read32(cc, BCMA_CC_CHIPSTAT); + cc->capabilities = bcma_cc_read32(cc, BCMA_CC_CAP); + if (cc->core->id.rev >= 35) + cc->capabilities_ext = bcma_cc_read32(cc, BCMA_CC_CAP_EXT); + + bcma_cc_write32(cc, 0x58, 0); + bcma_cc_write32(cc, 0x5C, 0); + + if (cc->capabilities & BCMA_CC_CAP_PMU) + bcma_pmu_init(cc); + if (cc->capabilities & BCMA_CC_CAP_PCTL) + pr_err("Power control not implemented!\n"); +} + +/* Set chip watchdog reset timer to fire in 'ticks' backplane cycles */ +void bcma_chipco_watchdog_timer_set(struct bcma_drv_cc *cc, u32 ticks) +{ + /* instant NMI */ + bcma_cc_write32(cc, BCMA_CC_WATCHDOG, ticks); +} + +void bcma_chipco_irq_mask(struct bcma_drv_cc *cc, u32 mask, u32 value) +{ + bcma_cc_write32_masked(cc, BCMA_CC_IRQMASK, mask, value); +} + +u32 bcma_chipco_irq_status(struct bcma_drv_cc *cc, u32 mask) +{ + return bcma_cc_read32(cc, BCMA_CC_IRQSTAT) & mask; +} + +u32 bcma_chipco_gpio_in(struct bcma_drv_cc *cc, u32 mask) +{ + return bcma_cc_read32(cc, BCMA_CC_GPIOIN) & mask; +} + +u32 bcma_chipco_gpio_out(struct bcma_drv_cc *cc, u32 mask, u32 value) +{ + return bcma_cc_write32_masked(cc, BCMA_CC_GPIOOUT, mask, value); +} + +u32 bcma_chipco_gpio_outen(struct bcma_drv_cc *cc, u32 mask, u32 value) +{ + return bcma_cc_write32_masked(cc, BCMA_CC_GPIOOUTEN, mask, value); +} + +u32 bcma_chipco_gpio_control(struct bcma_drv_cc *cc, u32 mask, u32 value) +{ + return bcma_cc_write32_masked(cc, BCMA_CC_GPIOCTL, mask, value); +} +EXPORT_SYMBOL_GPL(bcma_chipco_gpio_control); + +u32 bcma_chipco_gpio_intmask(struct bcma_drv_cc *cc, u32 mask, u32 value) +{ + return bcma_cc_write32_masked(cc, BCMA_CC_GPIOIRQ, mask, value); +} + +u32 bcma_chipco_gpio_polarity(struct bcma_drv_cc *cc, u32 mask, u32 value) +{ + return bcma_cc_write32_masked(cc, BCMA_CC_GPIOPOL, mask, value); +} diff --git a/drivers/bcma/driver_chipcommon_pmu.c b/drivers/bcma/driver_chipcommon_pmu.c new file mode 100644 index 0000000..f44177a --- /dev/null +++ b/drivers/bcma/driver_chipcommon_pmu.c @@ -0,0 +1,134 @@ +/* + * Broadcom specific AMBA + * ChipCommon Power Management Unit driver + * + * Copyright 2009, Michael Buesch + * Copyright 2007, Broadcom Corporation + * + * Licensed under the GNU/GPL. See COPYING for details. + */ + +#include "bcma_private.h" +#include + +static void bcma_chipco_chipctl_maskset(struct bcma_drv_cc *cc, + u32 offset, u32 mask, u32 set) +{ + u32 value; + + bcma_cc_read32(cc, BCMA_CC_CHIPCTL_ADDR); + bcma_cc_write32(cc, BCMA_CC_CHIPCTL_ADDR, offset); + bcma_cc_read32(cc, BCMA_CC_CHIPCTL_ADDR); + value = bcma_cc_read32(cc, BCMA_CC_CHIPCTL_DATA); + value &= mask; + value |= set; + bcma_cc_write32(cc, BCMA_CC_CHIPCTL_DATA, value); + bcma_cc_read32(cc, BCMA_CC_CHIPCTL_DATA); +} + +static void bcma_pmu_pll_init(struct bcma_drv_cc *cc) +{ + struct bcma_bus *bus = cc->core->bus; + + switch (bus->chipinfo.id) { + case 0x4313: + case 0x4331: + case 43224: + case 43225: + break; + default: + pr_err("PLL init unknown for device 0x%04X\n", + bus->chipinfo.id); + } +} + +static void bcma_pmu_resources_init(struct bcma_drv_cc *cc) +{ + struct bcma_bus *bus = cc->core->bus; + u32 min_msk = 0, max_msk = 0; + + switch (bus->chipinfo.id) { + case 0x4313: + min_msk = 0x200D; + max_msk = 0xFFFF; + break; + case 43224: + break; + default: + pr_err("PMU resource config unknown for device 0x%04X\n", + bus->chipinfo.id); + } + + /* Set the resource masks. */ + if (min_msk) + bcma_cc_write32(cc, BCMA_CC_PMU_MINRES_MSK, min_msk); + if (max_msk) + bcma_cc_write32(cc, BCMA_CC_PMU_MAXRES_MSK, max_msk); +} + +void bcma_pmu_swreg_init(struct bcma_drv_cc *cc) +{ + struct bcma_bus *bus = cc->core->bus; + + switch (bus->chipinfo.id) { + case 0x4313: + case 0x4331: + case 43224: + break; + default: + pr_err("PMU switch/regulators init unknown for device " + "0x%04X\n", bus->chipinfo.id); + } +} + +void bcma_pmu_workarounds(struct bcma_drv_cc *cc) +{ + struct bcma_bus *bus = cc->core->bus; + + switch (bus->chipinfo.id) { + case 0x4313: + bcma_chipco_chipctl_maskset(cc, 0, ~0, 0x7); + break; + case 0x4331: + pr_err("Enabling Ext PA lines not implemented\n"); + break; + case 43224: + if (bus->chipinfo.rev == 0) { + pr_err("Workarounds for 43224 rev 0 not fully " + "implemented\n"); + bcma_chipco_chipctl_maskset(cc, 0, ~0, 0xF0); + } else { + bcma_chipco_chipctl_maskset(cc, 0, ~0, 0xF0); + } + break; + default: + pr_err("Workarounds unknown for device 0x%04X\n", + bus->chipinfo.id); + } +} + +void bcma_pmu_init(struct bcma_drv_cc *cc) +{ + u32 pmucap; + + pmucap = bcma_cc_read32(cc, BCMA_CC_PMU_CAP); + cc->pmu.rev = (pmucap & BCMA_CC_PMU_CAP_REVISION); + + pr_debug("Found rev %u PMU (capabilities 0x%08X)\n", cc->pmu.rev, + pmucap); + + if (cc->pmu.rev == 1) + bcma_cc_mask32(cc, BCMA_CC_PMU_CTL, + ~BCMA_CC_PMU_CTL_NOILPONW); + else + bcma_cc_set32(cc, BCMA_CC_PMU_CTL, + BCMA_CC_PMU_CTL_NOILPONW); + + if (cc->core->id.id == 0x4329 && cc->core->id.rev == 2) + pr_err("Fix for 4329b0 bad LPOM state not implemented!\n"); + + bcma_pmu_pll_init(cc); + bcma_pmu_resources_init(cc); + bcma_pmu_swreg_init(cc); + bcma_pmu_workarounds(cc); +} diff --git a/drivers/bcma/driver_pci.c b/drivers/bcma/driver_pci.c new file mode 100644 index 0000000..b98b835 --- /dev/null +++ b/drivers/bcma/driver_pci.c @@ -0,0 +1,163 @@ +/* + * Broadcom specific AMBA + * PCI Core + * + * Copyright 2005, Broadcom Corporation + * Copyright 2006, 2007, Michael Buesch + * + * Licensed under the GNU/GPL. See COPYING for details. + */ + +#include "bcma_private.h" +#include + +/************************************************** + * R/W ops. + **************************************************/ + +static u32 bcma_pcie_read(struct bcma_drv_pci *pc, u32 address) +{ + pcicore_write32(pc, 0x130, address); + pcicore_read32(pc, 0x130); + return pcicore_read32(pc, 0x134); +} + +#if 0 +static void bcma_pcie_write(struct bcma_drv_pci *pc, u32 address, u32 data) +{ + pcicore_write32(pc, 0x130, address); + pcicore_read32(pc, 0x130); + pcicore_write32(pc, 0x134, data); +} +#endif + +static void bcma_pcie_mdio_set_phy(struct bcma_drv_pci *pc, u8 phy) +{ + const u16 mdio_control = 0x128; + const u16 mdio_data = 0x12C; + u32 v; + int i; + + v = (1 << 30); /* Start of Transaction */ + v |= (1 << 28); /* Write Transaction */ + v |= (1 << 17); /* Turnaround */ + v |= (0x1F << 18); + v |= (phy << 4); + pcicore_write32(pc, mdio_data, v); + + udelay(10); + for (i = 0; i < 200; i++) { + v = pcicore_read32(pc, mdio_control); + if (v & 0x100 /* Trans complete */) + break; + msleep(1); + } +} + +static u16 bcma_pcie_mdio_read(struct bcma_drv_pci *pc, u8 device, u8 address) +{ + const u16 mdio_control = 0x128; + const u16 mdio_data = 0x12C; + int max_retries = 10; + u16 ret = 0; + u32 v; + int i; + + v = 0x80; /* Enable Preamble Sequence */ + v |= 0x2; /* MDIO Clock Divisor */ + pcicore_write32(pc, mdio_control, v); + + if (pc->core->id.rev >= 10) { + max_retries = 200; + bcma_pcie_mdio_set_phy(pc, device); + } + + v = (1 << 30); /* Start of Transaction */ + v |= (1 << 29); /* Read Transaction */ + v |= (1 << 17); /* Turnaround */ + if (pc->core->id.rev < 10) + v |= (u32)device << 22; + v |= (u32)address << 18; + pcicore_write32(pc, mdio_data, v); + /* Wait for the device to complete the transaction */ + udelay(10); + for (i = 0; i < 200; i++) { + v = pcicore_read32(pc, mdio_control); + if (v & 0x100 /* Trans complete */) { + udelay(10); + ret = pcicore_read32(pc, mdio_data); + break; + } + msleep(1); + } + pcicore_write32(pc, mdio_control, 0); + return ret; +} + +static void bcma_pcie_mdio_write(struct bcma_drv_pci *pc, u8 device, + u8 address, u16 data) +{ + const u16 mdio_control = 0x128; + const u16 mdio_data = 0x12C; + int max_retries = 10; + u32 v; + int i; + + v = 0x80; /* Enable Preamble Sequence */ + v |= 0x2; /* MDIO Clock Divisor */ + pcicore_write32(pc, mdio_control, v); + + if (pc->core->id.rev >= 10) { + max_retries = 200; + bcma_pcie_mdio_set_phy(pc, device); + } + + v = (1 << 30); /* Start of Transaction */ + v |= (1 << 28); /* Write Transaction */ + v |= (1 << 17); /* Turnaround */ + if (pc->core->id.rev < 10) + v |= (u32)device << 22; + v |= (u32)address << 18; + v |= data; + pcicore_write32(pc, mdio_data, v); + /* Wait for the device to complete the transaction */ + udelay(10); + for (i = 0; i < max_retries; i++) { + v = pcicore_read32(pc, mdio_control); + if (v & 0x100 /* Trans complete */) + break; + msleep(1); + } + pcicore_write32(pc, mdio_control, 0); +} + +/************************************************** + * Workarounds. + **************************************************/ + +static u8 bcma_pcicore_polarity_workaround(struct bcma_drv_pci *pc) +{ + return (bcma_pcie_read(pc, 0x204) & 0x10) ? 0xC0 : 0x80; +} + +static void bcma_pcicore_serdes_workaround(struct bcma_drv_pci *pc) +{ + const u8 serdes_pll_device = 0x1D; + const u8 serdes_rx_device = 0x1F; + u16 tmp; + + bcma_pcie_mdio_write(pc, serdes_rx_device, 1 /* Control */, + bcma_pcicore_polarity_workaround(pc)); + tmp = bcma_pcie_mdio_read(pc, serdes_pll_device, 1 /* Control */); + if (tmp & 0x4000) + bcma_pcie_mdio_write(pc, serdes_pll_device, 1, tmp & ~0x4000); +} + +/************************************************** + * Init. + **************************************************/ + +void bcma_core_pci_init(struct bcma_drv_pci *pc) +{ + bcma_pcicore_serdes_workaround(pc); +} diff --git a/drivers/bcma/host_pci.c b/drivers/bcma/host_pci.c new file mode 100644 index 0000000..99dd36e --- /dev/null +++ b/drivers/bcma/host_pci.c @@ -0,0 +1,196 @@ +/* + * Broadcom specific AMBA + * PCI Host + * + * Licensed under the GNU/GPL. See COPYING for details. + */ + +#include "bcma_private.h" +#include +#include + +static void bcma_host_pci_switch_core(struct bcma_device *core) +{ + pci_write_config_dword(core->bus->host_pci, BCMA_PCI_BAR0_WIN, + core->addr); + pci_write_config_dword(core->bus->host_pci, BCMA_PCI_BAR0_WIN2, + core->wrap); + core->bus->mapped_core = core; + pr_debug("Switched to core: 0x%X\n", core->id.id); +} + +static u8 bcma_host_pci_read8(struct bcma_device *core, u16 offset) +{ + if (core->bus->mapped_core != core) + bcma_host_pci_switch_core(core); + return ioread8(core->bus->mmio + offset); +} + +static u16 bcma_host_pci_read16(struct bcma_device *core, u16 offset) +{ + if (core->bus->mapped_core != core) + bcma_host_pci_switch_core(core); + return ioread16(core->bus->mmio + offset); +} + +static u32 bcma_host_pci_read32(struct bcma_device *core, u16 offset) +{ + if (core->bus->mapped_core != core) + bcma_host_pci_switch_core(core); + return ioread32(core->bus->mmio + offset); +} + +static void bcma_host_pci_write8(struct bcma_device *core, u16 offset, + u8 value) +{ + if (core->bus->mapped_core != core) + bcma_host_pci_switch_core(core); + iowrite8(value, core->bus->mmio + offset); +} + +static void bcma_host_pci_write16(struct bcma_device *core, u16 offset, + u16 value) +{ + if (core->bus->mapped_core != core) + bcma_host_pci_switch_core(core); + iowrite16(value, core->bus->mmio + offset); +} + +static void bcma_host_pci_write32(struct bcma_device *core, u16 offset, + u32 value) +{ + if (core->bus->mapped_core != core) + bcma_host_pci_switch_core(core); + iowrite32(value, core->bus->mmio + offset); +} + +static u32 bcma_host_pci_aread32(struct bcma_device *core, u16 offset) +{ + if (core->bus->mapped_core != core) + bcma_host_pci_switch_core(core); + return ioread32(core->bus->mmio + (1 * BCMA_CORE_SIZE) + offset); +} + +static void bcma_host_pci_awrite32(struct bcma_device *core, u16 offset, + u32 value) +{ + if (core->bus->mapped_core != core) + bcma_host_pci_switch_core(core); + iowrite32(value, core->bus->mmio + (1 * BCMA_CORE_SIZE) + offset); +} + +const struct bcma_host_ops bcma_host_pci_ops = { + .read8 = bcma_host_pci_read8, + .read16 = bcma_host_pci_read16, + .read32 = bcma_host_pci_read32, + .write8 = bcma_host_pci_write8, + .write16 = bcma_host_pci_write16, + .write32 = bcma_host_pci_write32, + .aread32 = bcma_host_pci_aread32, + .awrite32 = bcma_host_pci_awrite32, +}; + +static int bcma_host_pci_probe(struct pci_dev *dev, + const struct pci_device_id *id) +{ + struct bcma_bus *bus; + int err = -ENOMEM; + const char *name; + u32 val; + + /* Alloc */ + bus = kzalloc(sizeof(*bus), GFP_KERNEL); + if (!bus) + goto out; + + /* Basic PCI configuration */ + err = pci_enable_device(dev); + if (err) + goto err_kfree_bus; + + name = dev_name(&dev->dev); + if (dev->driver && dev->driver->name) + name = dev->driver->name; + err = pci_request_regions(dev, name); + if (err) + goto err_pci_disable; + pci_set_master(dev); + + /* Disable the RETRY_TIMEOUT register (0x41) to keep + * PCI Tx retries from interfering with C3 CPU state */ + pci_read_config_dword(dev, 0x40, &val); + if ((val & 0x0000ff00) != 0) + pci_write_config_dword(dev, 0x40, val & 0xffff00ff); + + /* SSB needed additional powering up, do we have any AMBA PCI cards? */ + if (!pci_is_pcie(dev)) + pr_err("PCI card detected, report problems.\n"); + + /* Map MMIO */ + err = -ENOMEM; + bus->mmio = pci_iomap(dev, 0, ~0UL); + if (!bus->mmio) + goto err_pci_release_regions; + + /* Host specific */ + bus->host_pci = dev; + bus->hosttype = BCMA_HOSTTYPE_PCI; + bus->ops = &bcma_host_pci_ops; + + /* Register */ + err = bcma_bus_register(bus); + if (err) + goto err_pci_unmap_mmio; + + pci_set_drvdata(dev, bus); + +out: + return err; + +err_pci_unmap_mmio: + pci_iounmap(dev, bus->mmio); +err_pci_release_regions: + pci_release_regions(dev); +err_pci_disable: + pci_disable_device(dev); +err_kfree_bus: + kfree(bus); + return err; +} + +static void bcma_host_pci_remove(struct pci_dev *dev) +{ + struct bcma_bus *bus = pci_get_drvdata(dev); + + bcma_bus_unregister(bus); + pci_iounmap(dev, bus->mmio); + pci_release_regions(dev); + pci_disable_device(dev); + kfree(bus); + pci_set_drvdata(dev, NULL); +} + +static DEFINE_PCI_DEVICE_TABLE(bcma_pci_bridge_tbl) = { + { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4331) }, + { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4353) }, + { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4727) }, + { 0, }, +}; +MODULE_DEVICE_TABLE(pci, bcma_pci_bridge_tbl); + +static struct pci_driver bcma_pci_bridge_driver = { + .name = "bcma-pci-bridge", + .id_table = bcma_pci_bridge_tbl, + .probe = bcma_host_pci_probe, + .remove = bcma_host_pci_remove, +}; + +int __init bcma_host_pci_init(void) +{ + return pci_register_driver(&bcma_pci_bridge_driver); +} + +void __exit bcma_host_pci_exit(void) +{ + pci_unregister_driver(&bcma_pci_bridge_driver); +} diff --git a/drivers/bcma/main.c b/drivers/bcma/main.c new file mode 100644 index 0000000..be52344 --- /dev/null +++ b/drivers/bcma/main.c @@ -0,0 +1,247 @@ +/* + * Broadcom specific AMBA + * Bus subsystem + * + * Licensed under the GNU/GPL. See COPYING for details. + */ + +#include "bcma_private.h" +#include + +MODULE_DESCRIPTION("Broadcom's specific AMBA driver"); +MODULE_LICENSE("GPL"); + +static int bcma_bus_match(struct device *dev, struct device_driver *drv); +static int bcma_device_probe(struct device *dev); +static int bcma_device_remove(struct device *dev); + +static ssize_t manuf_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct bcma_device *core = container_of(dev, struct bcma_device, dev); + return sprintf(buf, "0x%03X\n", core->id.manuf); +} +static ssize_t id_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct bcma_device *core = container_of(dev, struct bcma_device, dev); + return sprintf(buf, "0x%03X\n", core->id.id); +} +static ssize_t rev_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct bcma_device *core = container_of(dev, struct bcma_device, dev); + return sprintf(buf, "0x%02X\n", core->id.rev); +} +static ssize_t class_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct bcma_device *core = container_of(dev, struct bcma_device, dev); + return sprintf(buf, "0x%X\n", core->id.class); +} +static struct device_attribute bcma_device_attrs[] = { + __ATTR_RO(manuf), + __ATTR_RO(id), + __ATTR_RO(rev), + __ATTR_RO(class), + __ATTR_NULL, +}; + +static struct bus_type bcma_bus_type = { + .name = "bcma", + .match = bcma_bus_match, + .probe = bcma_device_probe, + .remove = bcma_device_remove, + .dev_attrs = bcma_device_attrs, +}; + +static struct bcma_device *bcma_find_core(struct bcma_bus *bus, u16 coreid) +{ + struct bcma_device *core; + + list_for_each_entry(core, &bus->cores, list) { + if (core->id.id == coreid) + return core; + } + return NULL; +} + +static void bcma_release_core_dev(struct device *dev) +{ + struct bcma_device *core = container_of(dev, struct bcma_device, dev); + kfree(core); +} + +static int bcma_register_cores(struct bcma_bus *bus) +{ + struct bcma_device *core; + int err, dev_id = 0; + + list_for_each_entry(core, &bus->cores, list) { + /* We support that cores ourself */ + switch (core->id.id) { + case BCMA_CORE_CHIPCOMMON: + case BCMA_CORE_PCI: + case BCMA_CORE_PCIE: + continue; + } + + core->dev.release = bcma_release_core_dev; + core->dev.bus = &bcma_bus_type; + dev_set_name(&core->dev, "bcma%d:%d", 0/*bus->num*/, dev_id); + + switch (bus->hosttype) { + case BCMA_HOSTTYPE_PCI: + core->dev.parent = &bus->host_pci->dev; + break; + case BCMA_HOSTTYPE_NONE: + case BCMA_HOSTTYPE_SDIO: + break; + } + + err = device_register(&core->dev); + if (err) { + pr_err("Could not register dev for core 0x%03X\n", + core->id.id); + continue; + } + core->dev_registered = true; + dev_id++; + } + + return 0; +} + +static void bcma_unregister_cores(struct bcma_bus *bus) +{ + struct bcma_device *core; + + list_for_each_entry(core, &bus->cores, list) { + if (core->dev_registered) + device_unregister(&core->dev); + } +} + +int bcma_bus_register(struct bcma_bus *bus) +{ + int err; + struct bcma_device *core; + + /* Scan for devices (cores) */ + err = bcma_bus_scan(bus); + if (err) { + pr_err("Failed to scan: %d\n", err); + return -1; + } + + /* Init CC core */ + core = bcma_find_core(bus, BCMA_CORE_CHIPCOMMON); + if (core) { + bus->drv_cc.core = core; + bcma_core_chipcommon_init(&bus->drv_cc); + } + + /* Init PCIE core */ + core = bcma_find_core(bus, BCMA_CORE_PCIE); + if (core) { + bus->drv_pci.core = core; + bcma_core_pci_init(&bus->drv_pci); + } + + /* Register found cores */ + bcma_register_cores(bus); + + pr_info("Bus registered\n"); + + return 0; +} +EXPORT_SYMBOL_GPL(bcma_bus_register); + +void bcma_bus_unregister(struct bcma_bus *bus) +{ + bcma_unregister_cores(bus); +} +EXPORT_SYMBOL_GPL(bcma_bus_unregister); + +int __bcma_driver_register(struct bcma_driver *drv, struct module *owner) +{ + drv->drv.name = drv->name; + drv->drv.bus = &bcma_bus_type; + drv->drv.owner = owner; + + return driver_register(&drv->drv); +} +EXPORT_SYMBOL_GPL(__bcma_driver_register); + +void bcma_driver_unregister(struct bcma_driver *drv) +{ + driver_unregister(&drv->drv); +} +EXPORT_SYMBOL_GPL(bcma_driver_unregister); + +static int bcma_bus_match(struct device *dev, struct device_driver *drv) +{ + struct bcma_device *core = container_of(dev, struct bcma_device, dev); + struct bcma_driver *adrv = container_of(drv, struct bcma_driver, drv); + const struct bcma_device_id *cid = &core->id; + const struct bcma_device_id *did; + + for (did = adrv->id_table; did->manuf || did->id || did->rev; did++) { + if ((did->manuf == cid->manuf || did->manuf == BCMA_ANY_MANUF) && + (did->id == cid->id || did->id == BCMA_ANY_ID) && + (did->rev == cid->rev || did->rev == BCMA_ANY_REV) && + (did->class == cid->class || did->class == BCMA_ANY_CLASS)) + return 1; + } + return 0; +} + +static int bcma_device_probe(struct device *dev) +{ + struct bcma_device *core = container_of(dev, struct bcma_device, dev); + struct bcma_driver *adrv = container_of(dev->driver, struct bcma_driver, + drv); + int err = 0; + + if (adrv->probe) + err = adrv->probe(core); + + return err; +} + +static int bcma_device_remove(struct device *dev) +{ + struct bcma_device *core = container_of(dev, struct bcma_device, dev); + struct bcma_driver *adrv = container_of(dev->driver, struct bcma_driver, + drv); + + if (adrv->remove) + adrv->remove(core); + + return 0; +} + +static int __init bcma_modinit(void) +{ + int err; + + err = bus_register(&bcma_bus_type); + if (err) + return err; + +#ifdef CONFIG_BCMA_HOST_PCI + err = bcma_host_pci_init(); + if (err) { + pr_err("PCI host initialization failed\n"); + err = 0; + } +#endif + + return err; +} +fs_initcall(bcma_modinit); + +static void __exit bcma_modexit(void) +{ +#ifdef CONFIG_BCMA_HOST_PCI + bcma_host_pci_exit(); +#endif + bus_unregister(&bcma_bus_type); +} +module_exit(bcma_modexit) diff --git a/drivers/bcma/scan.c b/drivers/bcma/scan.c new file mode 100644 index 0000000..40d7dcc --- /dev/null +++ b/drivers/bcma/scan.c @@ -0,0 +1,360 @@ +/* + * Broadcom specific AMBA + * Bus scanning + * + * Licensed under the GNU/GPL. See COPYING for details. + */ + +#include "scan.h" +#include "bcma_private.h" + +#include +#include +#include +#include +#include +#include + +struct bcma_device_id_name { + u16 id; + const char *name; +}; +struct bcma_device_id_name bcma_device_names[] = { + { BCMA_CORE_OOB_ROUTER, "OOB Router" }, + { BCMA_CORE_INVALID, "Invalid" }, + { BCMA_CORE_CHIPCOMMON, "ChipCommon" }, + { BCMA_CORE_ILINE20, "ILine 20" }, + { BCMA_CORE_SRAM, "SRAM" }, + { BCMA_CORE_SDRAM, "SDRAM" }, + { BCMA_CORE_PCI, "PCI" }, + { BCMA_CORE_MIPS, "MIPS" }, + { BCMA_CORE_ETHERNET, "Fast Ethernet" }, + { BCMA_CORE_V90, "V90" }, + { BCMA_CORE_USB11_HOSTDEV, "USB 1.1 Hostdev" }, + { BCMA_CORE_ADSL, "ADSL" }, + { BCMA_CORE_ILINE100, "ILine 100" }, + { BCMA_CORE_IPSEC, "IPSEC" }, + { BCMA_CORE_UTOPIA, "UTOPIA" }, + { BCMA_CORE_PCMCIA, "PCMCIA" }, + { BCMA_CORE_INTERNAL_MEM, "Internal Memory" }, + { BCMA_CORE_MEMC_SDRAM, "MEMC SDRAM" }, + { BCMA_CORE_OFDM, "OFDM" }, + { BCMA_CORE_EXTIF, "EXTIF" }, + { BCMA_CORE_80211, "IEEE 802.11" }, + { BCMA_CORE_PHY_A, "PHY A" }, + { BCMA_CORE_PHY_B, "PHY B" }, + { BCMA_CORE_PHY_G, "PHY G" }, + { BCMA_CORE_MIPS_3302, "MIPS 3302" }, + { BCMA_CORE_USB11_HOST, "USB 1.1 Host" }, + { BCMA_CORE_USB11_DEV, "USB 1.1 Device" }, + { BCMA_CORE_USB20_HOST, "USB 2.0 Host" }, + { BCMA_CORE_USB20_DEV, "USB 2.0 Device" }, + { BCMA_CORE_SDIO_HOST, "SDIO Host" }, + { BCMA_CORE_ROBOSWITCH, "Roboswitch" }, + { BCMA_CORE_PARA_ATA, "PATA" }, + { BCMA_CORE_SATA_XORDMA, "SATA XOR-DMA" }, + { BCMA_CORE_ETHERNET_GBIT, "GBit Ethernet" }, + { BCMA_CORE_PCIE, "PCIe" }, + { BCMA_CORE_PHY_N, "PHY N" }, + { BCMA_CORE_SRAM_CTL, "SRAM Controller" }, + { BCMA_CORE_MINI_MACPHY, "Mini MACPHY" }, + { BCMA_CORE_ARM_1176, "ARM 1176" }, + { BCMA_CORE_ARM_7TDMI, "ARM 7TDMI" }, + { BCMA_CORE_PHY_LP, "PHY LP" }, + { BCMA_CORE_PMU, "PMU" }, + { BCMA_CORE_PHY_SSN, "PHY SSN" }, + { BCMA_CORE_SDIO_DEV, "SDIO Device" }, + { BCMA_CORE_ARM_CM3, "ARM CM3" }, + { BCMA_CORE_PHY_HT, "PHY HT" }, + { BCMA_CORE_MIPS_74K, "MIPS 74K" }, + { BCMA_CORE_MAC_GBIT, "GBit MAC" }, + { BCMA_CORE_DDR12_MEM_CTL, "DDR1/DDR2 Memory Controller" }, + { BCMA_CORE_PCIE_RC, "PCIe Root Complex" }, + { BCMA_CORE_OCP_OCP_BRIDGE, "OCP to OCP Bridge" }, + { BCMA_CORE_SHARED_COMMON, "Common Shared" }, + { BCMA_CORE_OCP_AHB_BRIDGE, "OCP to AHB Bridge" }, + { BCMA_CORE_SPI_HOST, "SPI Host" }, + { BCMA_CORE_I2S, "I2S" }, + { BCMA_CORE_SDR_DDR1_MEM_CTL, "SDR/DDR1 Memory Controller" }, + { BCMA_CORE_SHIM, "SHIM" }, + { BCMA_CORE_DEFAULT, "Default" }, +}; +const char *bcma_device_name(struct bcma_device_id *id) +{ + int i; + + if (id->manuf == BCMA_MANUF_BCM) { + for (i = 0; i < ARRAY_SIZE(bcma_device_names); i++) { + if (bcma_device_names[i].id == id->id) + return bcma_device_names[i].name; + } + } + return "UNKNOWN"; +} + +static u32 bcma_scan_read32(struct bcma_bus *bus, u8 current_coreidx, + u16 offset) +{ + return readl(bus->mmio + offset); +} + +static void bcma_scan_switch_core(struct bcma_bus *bus, u32 addr) +{ + if (bus->hosttype == BCMA_HOSTTYPE_PCI) + pci_write_config_dword(bus->host_pci, BCMA_PCI_BAR0_WIN, + addr); +} + +static u32 bcma_erom_get_ent(struct bcma_bus *bus, u32 **eromptr) +{ + u32 ent = readl(*eromptr); + (*eromptr)++; + return ent; +} + +static void bcma_erom_push_ent(u32 **eromptr) +{ + (*eromptr)--; +} + +static s32 bcma_erom_get_ci(struct bcma_bus *bus, u32 **eromptr) +{ + u32 ent = bcma_erom_get_ent(bus, eromptr); + if (!(ent & SCAN_ER_VALID)) + return -ENOENT; + if ((ent & SCAN_ER_TAG) != SCAN_ER_TAG_CI) + return -ENOENT; + return ent; +} + +static bool bcma_erom_is_end(struct bcma_bus *bus, u32 **eromptr) +{ + u32 ent = bcma_erom_get_ent(bus, eromptr); + bcma_erom_push_ent(eromptr); + return (ent == (SCAN_ER_TAG_END | SCAN_ER_VALID)); +} + +static bool bcma_erom_is_bridge(struct bcma_bus *bus, u32 **eromptr) +{ + u32 ent = bcma_erom_get_ent(bus, eromptr); + bcma_erom_push_ent(eromptr); + return (((ent & SCAN_ER_VALID)) && + ((ent & SCAN_ER_TAGX) == SCAN_ER_TAG_ADDR) && + ((ent & SCAN_ADDR_TYPE) == SCAN_ADDR_TYPE_BRIDGE)); +} + +static void bcma_erom_skip_component(struct bcma_bus *bus, u32 **eromptr) +{ + u32 ent; + while (1) { + ent = bcma_erom_get_ent(bus, eromptr); + if ((ent & SCAN_ER_VALID) && + ((ent & SCAN_ER_TAG) == SCAN_ER_TAG_CI)) + break; + if (ent == (SCAN_ER_TAG_END | SCAN_ER_VALID)) + break; + } + bcma_erom_push_ent(eromptr); +} + +static s32 bcma_erom_get_mst_port(struct bcma_bus *bus, u32 **eromptr) +{ + u32 ent = bcma_erom_get_ent(bus, eromptr); + if (!(ent & SCAN_ER_VALID)) + return -ENOENT; + if ((ent & SCAN_ER_TAG) != SCAN_ER_TAG_MP) + return -ENOENT; + return ent; +} + +static s32 bcma_erom_get_addr_desc(struct bcma_bus *bus, u32 **eromptr, + u32 type, u8 port) +{ + u32 addrl, addrh, sizel, sizeh = 0; + u32 size; + + u32 ent = bcma_erom_get_ent(bus, eromptr); + if ((!(ent & SCAN_ER_VALID)) || + ((ent & SCAN_ER_TAGX) != SCAN_ER_TAG_ADDR) || + ((ent & SCAN_ADDR_TYPE) != type) || + (((ent & SCAN_ADDR_PORT) >> SCAN_ADDR_PORT_SHIFT) != port)) { + bcma_erom_push_ent(eromptr); + return -EINVAL; + } + + addrl = ent & SCAN_ADDR_ADDR; + if (ent & SCAN_ADDR_AG32) + addrh = bcma_erom_get_ent(bus, eromptr); + else + addrh = 0; + + if ((ent & SCAN_ADDR_SZ) == SCAN_ADDR_SZ_SZD) { + size = bcma_erom_get_ent(bus, eromptr); + sizel = size & SCAN_SIZE_SZ; + if (size & SCAN_SIZE_SG32) + sizeh = bcma_erom_get_ent(bus, eromptr); + } else + sizel = SCAN_ADDR_SZ_BASE << + ((ent & SCAN_ADDR_SZ) >> SCAN_ADDR_SZ_SHIFT); + + return addrl; +} + +int bcma_bus_scan(struct bcma_bus *bus) +{ + u32 erombase; + u32 __iomem *eromptr, *eromend; + + s32 cia, cib; + u8 ports[2], wrappers[2]; + + s32 tmp; + u8 i, j; + + int err; + + INIT_LIST_HEAD(&bus->cores); + bus->nr_cores = 0; + + bcma_scan_switch_core(bus, BCMA_ADDR_BASE); + + tmp = bcma_scan_read32(bus, 0, BCMA_CC_ID); + bus->chipinfo.id = (tmp & BCMA_CC_ID_ID) >> BCMA_CC_ID_ID_SHIFT; + bus->chipinfo.rev = (tmp & BCMA_CC_ID_REV) >> BCMA_CC_ID_REV_SHIFT; + bus->chipinfo.pkg = (tmp & BCMA_CC_ID_PKG) >> BCMA_CC_ID_PKG_SHIFT; + + erombase = bcma_scan_read32(bus, 0, BCMA_CC_EROM); + eromptr = bus->mmio; + eromend = eromptr + BCMA_CORE_SIZE / sizeof(u32); + + bcma_scan_switch_core(bus, erombase); + + while (eromptr < eromend) { + struct bcma_device *core = kzalloc(sizeof(*core), GFP_KERNEL); + if (!core) + return -ENOMEM; + INIT_LIST_HEAD(&core->list); + core->bus = bus; + + /* get CIs */ + cia = bcma_erom_get_ci(bus, &eromptr); + if (cia < 0) { + bcma_erom_push_ent(&eromptr); + if (bcma_erom_is_end(bus, &eromptr)) + break; + err= -EILSEQ; + goto out; + } + cib = bcma_erom_get_ci(bus, &eromptr); + if (cib < 0) { + err= -EILSEQ; + goto out; + } + + /* parse CIs */ + core->id.class = (cia & SCAN_CIA_CLASS) >> SCAN_CIA_CLASS_SHIFT; + core->id.id = (cia & SCAN_CIA_ID) >> SCAN_CIA_ID_SHIFT; + core->id.manuf = (cia & SCAN_CIA_MANUF) >> SCAN_CIA_MANUF_SHIFT; + ports[0] = (cib & SCAN_CIB_NMP) >> SCAN_CIB_NMP_SHIFT; + ports[1] = (cib & SCAN_CIB_NSP) >> SCAN_CIB_NSP_SHIFT; + wrappers[0] = (cib & SCAN_CIB_NMW) >> SCAN_CIB_NMW_SHIFT; + wrappers[1] = (cib & SCAN_CIB_NSW) >> SCAN_CIB_NSW_SHIFT; + core->id.rev = (cib & SCAN_CIB_REV) >> SCAN_CIB_REV_SHIFT; + + if (((core->id.manuf == BCMA_MANUF_ARM) && + (core->id.id == 0xFFF)) || + (ports[1] == 0)) { + bcma_erom_skip_component(bus, &eromptr); + continue; + } + + /* check if component is a core at all */ + if (wrappers[0] + wrappers[1] == 0) { + /* we could save addrl of the router + if (cid == BCMA_CORE_OOB_ROUTER) + */ + bcma_erom_skip_component(bus, &eromptr); + continue; + } + + if (bcma_erom_is_bridge(bus, &eromptr)) { + bcma_erom_skip_component(bus, &eromptr); + continue; + } + + /* get & parse master ports */ + for (i = 0; i < ports[0]; i++) { + u32 mst_port_d = bcma_erom_get_mst_port(bus, &eromptr); + if (mst_port_d < 0) { + err= -EILSEQ; + goto out; + } + } + + /* get & parse slave ports */ + for (i = 0; i < ports[1]; i++) { + for (j = 0; ; j++) { + tmp = bcma_erom_get_addr_desc(bus, &eromptr, + SCAN_ADDR_TYPE_SLAVE, i); + if (tmp < 0) { + /* no more entries for port _i_ */ + /* pr_debug("erom: slave port %d " + * "has %d descriptors\n", i, j); */ + break; + } else { + if (i == 0 && j == 0) + core->addr = tmp; + } + } + } + + /* get & parse master wrappers */ + for (i = 0; i < wrappers[0]; i++) { + for (j = 0; ; j++) { + tmp = bcma_erom_get_addr_desc(bus, &eromptr, + SCAN_ADDR_TYPE_MWRAP, i); + if (tmp < 0) { + /* no more entries for port _i_ */ + /* pr_debug("erom: master wrapper %d " + * "has %d descriptors\n", i, j); */ + break; + } else { + if (i == 0 && j == 0) + core->wrap = tmp; + } + } + } + + /* get & parse slave wrappers */ + for (i = 0; i < wrappers[1]; i++) { + u8 hack = (ports[1] == 1) ? 0 : 1; + for (j = 0; ; j++) { + tmp = bcma_erom_get_addr_desc(bus, &eromptr, + SCAN_ADDR_TYPE_SWRAP, i + hack); + if (tmp < 0) { + /* no more entries for port _i_ */ + /* pr_debug("erom: master wrapper %d " + * has %d descriptors\n", i, j); */ + break; + } else { + if (wrappers[0] == 0 && !i && !j) + core->wrap = tmp; + } + } + } + + pr_info("Core %d found: %s " + "(manuf 0x%03X, id 0x%03X, rev 0x%02X, class 0x%X)\n", + bus->nr_cores, bcma_device_name(&core->id), + core->id.manuf, core->id.id, core->id.rev, + core->id.class); + + core->core_index = bus->nr_cores++; + list_add(&core->list, &bus->cores); + continue; +out: + return err; + } + + return 0; +} diff --git a/drivers/bcma/scan.h b/drivers/bcma/scan.h new file mode 100644 index 0000000..113e6a6 --- /dev/null +++ b/drivers/bcma/scan.h @@ -0,0 +1,56 @@ +#ifndef BCMA_SCAN_H_ +#define BCMA_SCAN_H_ + +#define BCMA_ADDR_BASE 0x18000000 +#define BCMA_WRAP_BASE 0x18100000 + +#define SCAN_ER_VALID 0x00000001 +#define SCAN_ER_TAGX 0x00000006 /* we have to ignore 0x8 bit when checking tag for SCAN_ER_TAG_ADDR */ +#define SCAN_ER_TAG 0x0000000E +#define SCAN_ER_TAG_CI 0x00000000 +#define SCAN_ER_TAG_MP 0x00000002 +#define SCAN_ER_TAG_ADDR 0x00000004 +#define SCAN_ER_TAG_END 0x0000000E +#define SCAN_ER_BAD 0xFFFFFFFF + +#define SCAN_CIA_CLASS 0x000000F0 +#define SCAN_CIA_CLASS_SHIFT 4 +#define SCAN_CIA_ID 0x000FFF00 +#define SCAN_CIA_ID_SHIFT 8 +#define SCAN_CIA_MANUF 0xFFF00000 +#define SCAN_CIA_MANUF_SHIFT 20 + +#define SCAN_CIB_NMP 0x000001F0 +#define SCAN_CIB_NMP_SHIFT 4 +#define SCAN_CIB_NSP 0x00003E00 +#define SCAN_CIB_NSP_SHIFT 9 +#define SCAN_CIB_NMW 0x0007C000 +#define SCAN_CIB_NMW_SHIFT 14 +#define SCAN_CIB_NSW 0x00F80000 +#define SCAN_CIB_NSW_SHIFT 17 +#define SCAN_CIB_REV 0xFF000000 +#define SCAN_CIB_REV_SHIFT 24 + +#define SCAN_ADDR_AG32 0x00000008 +#define SCAN_ADDR_SZ 0x00000030 +#define SCAN_ADDR_SZ_SHIFT 4 +#define SCAN_ADDR_SZ_4K 0x00000000 +#define SCAN_ADDR_SZ_8K 0x00000010 +#define SCAN_ADDR_SZ_16K 0x00000020 +#define SCAN_ADDR_SZ_SZD 0x00000030 +#define SCAN_ADDR_TYPE 0x000000C0 +#define SCAN_ADDR_TYPE_SLAVE 0x00000000 +#define SCAN_ADDR_TYPE_BRIDGE 0x00000040 +#define SCAN_ADDR_TYPE_SWRAP 0x00000080 +#define SCAN_ADDR_TYPE_MWRAP 0x000000C0 +#define SCAN_ADDR_PORT 0x00000F00 +#define SCAN_ADDR_PORT_SHIFT 8 +#define SCAN_ADDR_ADDR 0xFFFFF000 + +#define SCAN_ADDR_SZ_BASE 0x00001000 /* 4KB */ + +#define SCAN_SIZE_SZ_ALIGN 0x00000FFF +#define SCAN_SIZE_SZ 0xFFFFF000 +#define SCAN_SIZE_SG32 0x00000008 + +#endif /* BCMA_SCAN_H_ */ diff --git a/include/linux/bcma/bcma.h b/include/linux/bcma/bcma.h new file mode 100644 index 0000000..08763e4 --- /dev/null +++ b/include/linux/bcma/bcma.h @@ -0,0 +1,224 @@ +#ifndef LINUX_BCMA_H_ +#define LINUX_BCMA_H_ + +#include +#include + +#include +#include + +#include "bcma_regs.h" + +struct bcma_device; +struct bcma_bus; + +enum bcma_hosttype { + BCMA_HOSTTYPE_NONE, + BCMA_HOSTTYPE_PCI, + BCMA_HOSTTYPE_SDIO, +}; + +struct bcma_chipinfo { + u16 id; + u8 rev; + u8 pkg; +}; + +struct bcma_host_ops { + u8 (*read8)(struct bcma_device *core, u16 offset); + u16 (*read16)(struct bcma_device *core, u16 offset); + u32 (*read32)(struct bcma_device *core, u16 offset); + void (*write8)(struct bcma_device *core, u16 offset, u8 value); + void (*write16)(struct bcma_device *core, u16 offset, u16 value); + void (*write32)(struct bcma_device *core, u16 offset, u32 value); + /* Agent ops */ + u32 (*aread32)(struct bcma_device *core, u16 offset); + void (*awrite32)(struct bcma_device *core, u16 offset, u32 value); +}; + +/* Core manufacturers */ +#define BCMA_MANUF_ARM 0x43B +#define BCMA_MANUF_MIPS 0x4A7 +#define BCMA_MANUF_BCM 0x4BF + +/* Core class values. */ +#define BCMA_CL_SIM 0x0 +#define BCMA_CL_EROM 0x1 +#define BCMA_CL_CORESIGHT 0x9 +#define BCMA_CL_VERIF 0xB +#define BCMA_CL_OPTIMO 0xD +#define BCMA_CL_GEN 0xE +#define BCMA_CL_PRIMECELL 0xF + +/* Core-ID values. */ +#define BCMA_CORE_OOB_ROUTER 0x367 /* Out of band */ +#define BCMA_CORE_INVALID 0x700 +#define BCMA_CORE_CHIPCOMMON 0x800 +#define BCMA_CORE_ILINE20 0x801 +#define BCMA_CORE_SRAM 0x802 +#define BCMA_CORE_SDRAM 0x803 +#define BCMA_CORE_PCI 0x804 +#define BCMA_CORE_MIPS 0x805 +#define BCMA_CORE_ETHERNET 0x806 +#define BCMA_CORE_V90 0x807 +#define BCMA_CORE_USB11_HOSTDEV 0x808 +#define BCMA_CORE_ADSL 0x809 +#define BCMA_CORE_ILINE100 0x80A +#define BCMA_CORE_IPSEC 0x80B +#define BCMA_CORE_UTOPIA 0x80C +#define BCMA_CORE_PCMCIA 0x80D +#define BCMA_CORE_INTERNAL_MEM 0x80E +#define BCMA_CORE_MEMC_SDRAM 0x80F +#define BCMA_CORE_OFDM 0x810 +#define BCMA_CORE_EXTIF 0x811 +#define BCMA_CORE_80211 0x812 +#define BCMA_CORE_PHY_A 0x813 +#define BCMA_CORE_PHY_B 0x814 +#define BCMA_CORE_PHY_G 0x815 +#define BCMA_CORE_MIPS_3302 0x816 +#define BCMA_CORE_USB11_HOST 0x817 +#define BCMA_CORE_USB11_DEV 0x818 +#define BCMA_CORE_USB20_HOST 0x819 +#define BCMA_CORE_USB20_DEV 0x81A +#define BCMA_CORE_SDIO_HOST 0x81B +#define BCMA_CORE_ROBOSWITCH 0x81C +#define BCMA_CORE_PARA_ATA 0x81D +#define BCMA_CORE_SATA_XORDMA 0x81E +#define BCMA_CORE_ETHERNET_GBIT 0x81F +#define BCMA_CORE_PCIE 0x820 +#define BCMA_CORE_PHY_N 0x821 +#define BCMA_CORE_SRAM_CTL 0x822 +#define BCMA_CORE_MINI_MACPHY 0x823 +#define BCMA_CORE_ARM_1176 0x824 +#define BCMA_CORE_ARM_7TDMI 0x825 +#define BCMA_CORE_PHY_LP 0x826 +#define BCMA_CORE_PMU 0x827 +#define BCMA_CORE_PHY_SSN 0x828 +#define BCMA_CORE_SDIO_DEV 0x829 +#define BCMA_CORE_ARM_CM3 0x82A +#define BCMA_CORE_PHY_HT 0x82B +#define BCMA_CORE_MIPS_74K 0x82C +#define BCMA_CORE_MAC_GBIT 0x82D +#define BCMA_CORE_DDR12_MEM_CTL 0x82E +#define BCMA_CORE_PCIE_RC 0x82F /* PCIe Root Complex */ +#define BCMA_CORE_OCP_OCP_BRIDGE 0x830 +#define BCMA_CORE_SHARED_COMMON 0x831 +#define BCMA_CORE_OCP_AHB_BRIDGE 0x832 +#define BCMA_CORE_SPI_HOST 0x833 +#define BCMA_CORE_I2S 0x834 +#define BCMA_CORE_SDR_DDR1_MEM_CTL 0x835 /* SDR/DDR1 memory controller core */ +#define BCMA_CORE_SHIM 0x837 /* SHIM component in ubus/6362 */ +#define BCMA_CORE_DEFAULT 0xFFF + +#define BCMA_MAX_NR_CORES 16 + +struct bcma_device { + struct bcma_bus *bus; + struct bcma_device_id id; + + struct device dev; + bool dev_registered; + + u8 core_index; + + u32 addr; + u32 wrap; + + void *drvdata; + struct list_head list; +}; + +static inline void *bcma_get_drvdata(struct bcma_device *core) +{ + return core->drvdata; +} +static inline void bcma_set_drvdata(struct bcma_device *core, void *drvdata) +{ + core->drvdata = drvdata; +} + +struct bcma_driver { + const char *name; + const struct bcma_device_id *id_table; + + int (*probe)(struct bcma_device *dev); + void (*remove)(struct bcma_device *dev); + int (*suspend)(struct bcma_device *dev, pm_message_t state); + int (*resume)(struct bcma_device *dev); + void (*shutdown)(struct bcma_device *dev); + + struct device_driver drv; +}; +extern +int __bcma_driver_register(struct bcma_driver *drv, struct module *owner); +static inline int bcma_driver_register(struct bcma_driver *drv) +{ + return __bcma_driver_register(drv, THIS_MODULE); +} +extern void bcma_driver_unregister(struct bcma_driver *drv); + +struct bcma_bus { + /* The MMIO area. */ + void __iomem *mmio; + + const struct bcma_host_ops *ops; + + enum bcma_hosttype hosttype; + union { + /* Pointer to the PCI bus (only for BCMA_HOSTTYPE_PCI) */ + struct pci_dev *host_pci; + /* Pointer to the SDIO device (only for BCMA_HOSTTYPE_SDIO) */ + struct sdio_func *host_sdio; + }; + + struct bcma_chipinfo chipinfo; + + struct bcma_device *mapped_core; + struct list_head cores; + u8 nr_cores; + + struct bcma_drv_cc drv_cc; + struct bcma_drv_pci drv_pci; +}; + +extern inline u32 bcma_read8(struct bcma_device *core, u16 offset) +{ + return core->bus->ops->read8(core, offset); +} +extern inline u32 bcma_read16(struct bcma_device *core, u16 offset) +{ + return core->bus->ops->read16(core, offset); +} +extern inline u32 bcma_read32(struct bcma_device *core, u16 offset) +{ + return core->bus->ops->read32(core, offset); +} +extern inline +void bcma_write8(struct bcma_device *core, u16 offset, u32 value) +{ + core->bus->ops->write8(core, offset, value); +} +extern inline +void bcma_write16(struct bcma_device *core, u16 offset, u32 value) +{ + core->bus->ops->write16(core, offset, value); +} +extern inline +void bcma_write32(struct bcma_device *core, u16 offset, u32 value) +{ + core->bus->ops->write32(core, offset, value); +} +extern inline u32 bcma_aread32(struct bcma_device *core, u16 offset) +{ + return core->bus->ops->aread32(core, offset); +} +extern inline +void bcma_awrite32(struct bcma_device *core, u16 offset, u32 value) +{ + core->bus->ops->awrite32(core, offset, value); +} + +extern bool bcma_core_is_enabled(struct bcma_device *core); +extern int bcma_core_enable(struct bcma_device *core, u32 flags); + +#endif /* LINUX_BCMA_H_ */ diff --git a/include/linux/bcma/bcma_driver_chipcommon.h b/include/linux/bcma/bcma_driver_chipcommon.h new file mode 100644 index 0000000..4f8fd6a --- /dev/null +++ b/include/linux/bcma/bcma_driver_chipcommon.h @@ -0,0 +1,297 @@ +#ifndef LINUX_BCMA_DRIVER_CC_H_ +#define LINUX_BCMA_DRIVER_CC_H_ + +/** ChipCommon core registers. **/ +#define BCMA_CC_ID 0x0000 +#define BCMA_CC_ID_ID 0x0000FFFF +#define BCMA_CC_ID_ID_SHIFT 0 +#define BCMA_CC_ID_REV 0x000F0000 +#define BCMA_CC_ID_REV_SHIFT 16 +#define BCMA_CC_ID_PKG 0x00F00000 +#define BCMA_CC_ID_PKG_SHIFT 20 +#define BCMA_CC_ID_NRCORES 0x0F000000 +#define BCMA_CC_ID_NRCORES_SHIFT 24 +#define BCMA_CC_ID_TYPE 0xF0000000 +#define BCMA_CC_ID_TYPE_SHIFT 28 +#define BCMA_CC_CAP 0x0004 /* Capabilities */ +#define BCMA_CC_CAP_NRUART 0x00000003 /* # of UARTs */ +#define BCMA_CC_CAP_MIPSEB 0x00000004 /* MIPS in BigEndian Mode */ +#define BCMA_CC_CAP_UARTCLK 0x00000018 /* UART clock select */ +#define BCMA_CC_CAP_UARTCLK_INT 0x00000008 /* UARTs are driven by internal divided clock */ +#define BCMA_CC_CAP_UARTGPIO 0x00000020 /* UARTs on GPIO 15-12 */ +#define BCMA_CC_CAP_EXTBUS 0x000000C0 /* External buses present */ +#define BCMA_CC_CAP_FLASHT 0x00000700 /* Flash Type */ +#define BCMA_CC_FLASHT_NONE 0x00000000 /* No flash */ +#define BCMA_CC_FLASHT_STSER 0x00000100 /* ST serial flash */ +#define BCMA_CC_FLASHT_ATSER 0x00000200 /* Atmel serial flash */ +#define BCMA_CC_FLASHT_PARA 0x00000700 /* Parallel flash */ +#define BCMA_CC_CAP_PLLT 0x00038000 /* PLL Type */ +#define BCMA_PLLTYPE_NONE 0x00000000 +#define BCMA_PLLTYPE_1 0x00010000 /* 48Mhz base, 3 dividers */ +#define BCMA_PLLTYPE_2 0x00020000 /* 48Mhz, 4 dividers */ +#define BCMA_PLLTYPE_3 0x00030000 /* 25Mhz, 2 dividers */ +#define BCMA_PLLTYPE_4 0x00008000 /* 48Mhz, 4 dividers */ +#define BCMA_PLLTYPE_5 0x00018000 /* 25Mhz, 4 dividers */ +#define BCMA_PLLTYPE_6 0x00028000 /* 100/200 or 120/240 only */ +#define BCMA_PLLTYPE_7 0x00038000 /* 25Mhz, 4 dividers */ +#define BCMA_CC_CAP_PCTL 0x00040000 /* Power Control */ +#define BCMA_CC_CAP_OTPS 0x00380000 /* OTP size */ +#define BCMA_CC_CAP_OTPS_SHIFT 19 +#define BCMA_CC_CAP_OTPS_BASE 5 +#define BCMA_CC_CAP_JTAGM 0x00400000 /* JTAG master present */ +#define BCMA_CC_CAP_BROM 0x00800000 /* Internal boot ROM active */ +#define BCMA_CC_CAP_64BIT 0x08000000 /* 64-bit Backplane */ +#define BCMA_CC_CAP_PMU 0x10000000 /* PMU available (rev >= 20) */ +#define BCMA_CC_CAP_ECI 0x20000000 /* ECI available (rev >= 20) */ +#define BCMA_CC_CAP_SPROM 0x40000000 /* SPROM present */ +#define BCMA_CC_CORECTL 0x0008 +#define BCMA_CC_CORECTL_UARTCLK0 0x00000001 /* Drive UART with internal clock */ +#define BCMA_CC_CORECTL_SE 0x00000002 /* sync clk out enable (corerev >= 3) */ +#define BCMA_CC_CORECTL_UARTCLKEN 0x00000008 /* UART clock enable (rev >= 21) */ +#define BCMA_CC_BIST 0x000C +#define BCMA_CC_OTPS 0x0010 /* OTP status */ +#define BCMA_CC_OTPS_PROGFAIL 0x80000000 +#define BCMA_CC_OTPS_PROTECT 0x00000007 +#define BCMA_CC_OTPS_HW_PROTECT 0x00000001 +#define BCMA_CC_OTPS_SW_PROTECT 0x00000002 +#define BCMA_CC_OTPS_CID_PROTECT 0x00000004 +#define BCMA_CC_OTPC 0x0014 /* OTP control */ +#define BCMA_CC_OTPC_RECWAIT 0xFF000000 +#define BCMA_CC_OTPC_PROGWAIT 0x00FFFF00 +#define BCMA_CC_OTPC_PRW_SHIFT 8 +#define BCMA_CC_OTPC_MAXFAIL 0x00000038 +#define BCMA_CC_OTPC_VSEL 0x00000006 +#define BCMA_CC_OTPC_SELVL 0x00000001 +#define BCMA_CC_OTPP 0x0018 /* OTP prog */ +#define BCMA_CC_OTPP_COL 0x000000FF +#define BCMA_CC_OTPP_ROW 0x0000FF00 +#define BCMA_CC_OTPP_ROW_SHIFT 8 +#define BCMA_CC_OTPP_READERR 0x10000000 +#define BCMA_CC_OTPP_VALUE 0x20000000 +#define BCMA_CC_OTPP_READ 0x40000000 +#define BCMA_CC_OTPP_START 0x80000000 +#define BCMA_CC_OTPP_BUSY 0x80000000 +#define BCMA_CC_IRQSTAT 0x0020 +#define BCMA_CC_IRQMASK 0x0024 +#define BCMA_CC_IRQ_GPIO 0x00000001 /* gpio intr */ +#define BCMA_CC_IRQ_EXT 0x00000002 /* ro: ext intr pin (corerev >= 3) */ +#define BCMA_CC_IRQ_WDRESET 0x80000000 /* watchdog reset occurred */ +#define BCMA_CC_CHIPCTL 0x0028 /* Rev >= 11 only */ +#define BCMA_CC_CHIPSTAT 0x002C /* Rev >= 11 only */ +#define BCMA_CC_JCMD 0x0030 /* Rev >= 10 only */ +#define BCMA_CC_JCMD_START 0x80000000 +#define BCMA_CC_JCMD_BUSY 0x80000000 +#define BCMA_CC_JCMD_PAUSE 0x40000000 +#define BCMA_CC_JCMD0_ACC_MASK 0x0000F000 +#define BCMA_CC_JCMD0_ACC_IRDR 0x00000000 +#define BCMA_CC_JCMD0_ACC_DR 0x00001000 +#define BCMA_CC_JCMD0_ACC_IR 0x00002000 +#define BCMA_CC_JCMD0_ACC_RESET 0x00003000 +#define BCMA_CC_JCMD0_ACC_IRPDR 0x00004000 +#define BCMA_CC_JCMD0_ACC_PDR 0x00005000 +#define BCMA_CC_JCMD0_IRW_MASK 0x00000F00 +#define BCMA_CC_JCMD_ACC_MASK 0x000F0000 /* Changes for corerev 11 */ +#define BCMA_CC_JCMD_ACC_IRDR 0x00000000 +#define BCMA_CC_JCMD_ACC_DR 0x00010000 +#define BCMA_CC_JCMD_ACC_IR 0x00020000 +#define BCMA_CC_JCMD_ACC_RESET 0x00030000 +#define BCMA_CC_JCMD_ACC_IRPDR 0x00040000 +#define BCMA_CC_JCMD_ACC_PDR 0x00050000 +#define BCMA_CC_JCMD_IRW_MASK 0x00001F00 +#define BCMA_CC_JCMD_IRW_SHIFT 8 +#define BCMA_CC_JCMD_DRW_MASK 0x0000003F +#define BCMA_CC_JIR 0x0034 /* Rev >= 10 only */ +#define BCMA_CC_JDR 0x0038 /* Rev >= 10 only */ +#define BCMA_CC_JCTL 0x003C /* Rev >= 10 only */ +#define BCMA_CC_JCTL_FORCE_CLK 4 /* Force clock */ +#define BCMA_CC_JCTL_EXT_EN 2 /* Enable external targets */ +#define BCMA_CC_JCTL_EN 1 /* Enable Jtag master */ +#define BCMA_CC_FLASHCTL 0x0040 +#define BCMA_CC_FLASHCTL_START 0x80000000 +#define BCMA_CC_FLASHCTL_BUSY BCMA_CC_FLASHCTL_START +#define BCMA_CC_FLASHADDR 0x0044 +#define BCMA_CC_FLASHDATA 0x0048 +#define BCMA_CC_BCAST_ADDR 0x0050 +#define BCMA_CC_BCAST_DATA 0x0054 +#define BCMA_CC_GPIOIN 0x0060 +#define BCMA_CC_GPIOOUT 0x0064 +#define BCMA_CC_GPIOOUTEN 0x0068 +#define BCMA_CC_GPIOCTL 0x006C +#define BCMA_CC_GPIOPOL 0x0070 +#define BCMA_CC_GPIOIRQ 0x0074 +#define BCMA_CC_WATCHDOG 0x0080 +#define BCMA_CC_GPIOTIMER 0x0088 /* LED powersave (corerev >= 16) */ +#define BCMA_CC_GPIOTIMER_ONTIME_SHIFT 16 +#define BCMA_CC_GPIOTOUTM 0x008C /* LED powersave (corerev >= 16) */ +#define BCMA_CC_CLOCK_N 0x0090 +#define BCMA_CC_CLOCK_SB 0x0094 +#define BCMA_CC_CLOCK_PCI 0x0098 +#define BCMA_CC_CLOCK_M2 0x009C +#define BCMA_CC_CLOCK_MIPS 0x00A0 +#define BCMA_CC_CLKDIV 0x00A4 /* Rev >= 3 only */ +#define BCMA_CC_CLKDIV_SFLASH 0x0F000000 +#define BCMA_CC_CLKDIV_SFLASH_SHIFT 24 +#define BCMA_CC_CLKDIV_OTP 0x000F0000 +#define BCMA_CC_CLKDIV_OTP_SHIFT 16 +#define BCMA_CC_CLKDIV_JTAG 0x00000F00 +#define BCMA_CC_CLKDIV_JTAG_SHIFT 8 +#define BCMA_CC_CLKDIV_UART 0x000000FF +#define BCMA_CC_CAP_EXT 0x00AC /* Capabilities */ +#define BCMA_CC_PLLONDELAY 0x00B0 /* Rev >= 4 only */ +#define BCMA_CC_FREFSELDELAY 0x00B4 /* Rev >= 4 only */ +#define BCMA_CC_SLOWCLKCTL 0x00B8 /* 6 <= Rev <= 9 only */ +#define BCMA_CC_SLOWCLKCTL_SRC 0x00000007 /* slow clock source mask */ +#define BCMA_CC_SLOWCLKCTL_SRC_LPO 0x00000000 /* source of slow clock is LPO */ +#define BCMA_CC_SLOWCLKCTL_SRC_XTAL 0x00000001 /* source of slow clock is crystal */ +#define BCMA_CC_SLOECLKCTL_SRC_PCI 0x00000002 /* source of slow clock is PCI */ +#define BCMA_CC_SLOWCLKCTL_LPOFREQ 0x00000200 /* LPOFreqSel, 1: 160Khz, 0: 32KHz */ +#define BCMA_CC_SLOWCLKCTL_LPOPD 0x00000400 /* LPOPowerDown, 1: LPO is disabled, 0: LPO is enabled */ +#define BCMA_CC_SLOWCLKCTL_FSLOW 0x00000800 /* ForceSlowClk, 1: sb/cores running on slow clock, 0: power logic control */ +#define BCMA_CC_SLOWCLKCTL_IPLL 0x00001000 /* IgnorePllOffReq, 1/0: power logic ignores/honors PLL clock disable requests from core */ +#define BCMA_CC_SLOWCLKCTL_ENXTAL 0x00002000 /* XtalControlEn, 1/0: power logic does/doesn't disable crystal when appropriate */ +#define BCMA_CC_SLOWCLKCTL_XTALPU 0x00004000 /* XtalPU (RO), 1/0: crystal running/disabled */ +#define BCMA_CC_SLOWCLKCTL_CLKDIV 0xFFFF0000 /* ClockDivider (SlowClk = 1/(4+divisor)) */ +#define BCMA_CC_SLOWCLKCTL_CLKDIV_SHIFT 16 +#define BCMA_CC_SYSCLKCTL 0x00C0 /* Rev >= 3 only */ +#define BCMA_CC_SYSCLKCTL_IDLPEN 0x00000001 /* ILPen: Enable Idle Low Power */ +#define BCMA_CC_SYSCLKCTL_ALPEN 0x00000002 /* ALPen: Enable Active Low Power */ +#define BCMA_CC_SYSCLKCTL_PLLEN 0x00000004 /* ForcePLLOn */ +#define BCMA_CC_SYSCLKCTL_FORCEALP 0x00000008 /* Force ALP (or HT if ALPen is not set */ +#define BCMA_CC_SYSCLKCTL_FORCEHT 0x00000010 /* Force HT */ +#define BCMA_CC_SYSCLKCTL_CLKDIV 0xFFFF0000 /* ClkDiv (ILP = 1/(4+divisor)) */ +#define BCMA_CC_SYSCLKCTL_CLKDIV_SHIFT 16 +#define BCMA_CC_CLKSTSTR 0x00C4 /* Rev >= 3 only */ +#define BCMA_CC_EROM 0x00FC +#define BCMA_CC_PCMCIA_CFG 0x0100 +#define BCMA_CC_PCMCIA_MEMWAIT 0x0104 +#define BCMA_CC_PCMCIA_ATTRWAIT 0x0108 +#define BCMA_CC_PCMCIA_IOWAIT 0x010C +#define BCMA_CC_IDE_CFG 0x0110 +#define BCMA_CC_IDE_MEMWAIT 0x0114 +#define BCMA_CC_IDE_ATTRWAIT 0x0118 +#define BCMA_CC_IDE_IOWAIT 0x011C +#define BCMA_CC_PROG_CFG 0x0120 +#define BCMA_CC_PROG_WAITCNT 0x0124 +#define BCMA_CC_FLASH_CFG 0x0128 +#define BCMA_CC_FLASH_WAITCNT 0x012C +#define BCMA_CC_CLKCTLST 0x01E0 /* Clock control and status (rev >= 20) */ +#define BCMA_CC_CLKCTLST_FORCEALP 0x00000001 /* Force ALP request */ +#define BCMA_CC_CLKCTLST_FORCEHT 0x00000002 /* Force HT request */ +#define BCMA_CC_CLKCTLST_FORCEILP 0x00000004 /* Force ILP request */ +#define BCMA_CC_CLKCTLST_HAVEALPREQ 0x00000008 /* ALP available request */ +#define BCMA_CC_CLKCTLST_HAVEHTREQ 0x00000010 /* HT available request */ +#define BCMA_CC_CLKCTLST_HWCROFF 0x00000020 /* Force HW clock request off */ +#define BCMA_CC_CLKCTLST_HAVEHT 0x00010000 /* HT available */ +#define BCMA_CC_CLKCTLST_HAVEALP 0x00020000 /* APL available */ +#define BCMA_CC_HW_WORKAROUND 0x01E4 /* Hardware workaround (rev >= 20) */ +#define BCMA_CC_UART0_DATA 0x0300 +#define BCMA_CC_UART0_IMR 0x0304 +#define BCMA_CC_UART0_FCR 0x0308 +#define BCMA_CC_UART0_LCR 0x030C +#define BCMA_CC_UART0_MCR 0x0310 +#define BCMA_CC_UART0_LSR 0x0314 +#define BCMA_CC_UART0_MSR 0x0318 +#define BCMA_CC_UART0_SCRATCH 0x031C +#define BCMA_CC_UART1_DATA 0x0400 +#define BCMA_CC_UART1_IMR 0x0404 +#define BCMA_CC_UART1_FCR 0x0408 +#define BCMA_CC_UART1_LCR 0x040C +#define BCMA_CC_UART1_MCR 0x0410 +#define BCMA_CC_UART1_LSR 0x0414 +#define BCMA_CC_UART1_MSR 0x0418 +#define BCMA_CC_UART1_SCRATCH 0x041C +/* PMU registers (rev >= 20) */ +#define BCMA_CC_PMU_CTL 0x0600 /* PMU control */ +#define BCMA_CC_PMU_CTL_ILP_DIV 0xFFFF0000 /* ILP div mask */ +#define BCMA_CC_PMU_CTL_ILP_DIV_SHIFT 16 +#define BCMA_CC_PMU_CTL_NOILPONW 0x00000200 /* No ILP on wait */ +#define BCMA_CC_PMU_CTL_HTREQEN 0x00000100 /* HT req enable */ +#define BCMA_CC_PMU_CTL_ALPREQEN 0x00000080 /* ALP req enable */ +#define BCMA_CC_PMU_CTL_XTALFREQ 0x0000007C /* Crystal freq */ +#define BCMA_CC_PMU_CTL_XTALFREQ_SHIFT 2 +#define BCMA_CC_PMU_CTL_ILPDIVEN 0x00000002 /* ILP div enable */ +#define BCMA_CC_PMU_CTL_LPOSEL 0x00000001 /* LPO sel */ +#define BCMA_CC_PMU_CAP 0x0604 /* PMU capabilities */ +#define BCMA_CC_PMU_CAP_REVISION 0x000000FF /* Revision mask */ +#define BCMA_CC_PMU_STAT 0x0608 /* PMU status */ +#define BCMA_CC_PMU_STAT_INTPEND 0x00000040 /* Interrupt pending */ +#define BCMA_CC_PMU_STAT_SBCLKST 0x00000030 /* Backplane clock status? */ +#define BCMA_CC_PMU_STAT_HAVEALP 0x00000008 /* ALP available */ +#define BCMA_CC_PMU_STAT_HAVEHT 0x00000004 /* HT available */ +#define BCMA_CC_PMU_STAT_RESINIT 0x00000003 /* Res init */ +#define BCMA_CC_PMU_RES_STAT 0x060C /* PMU res status */ +#define BCMA_CC_PMU_RES_PEND 0x0610 /* PMU res pending */ +#define BCMA_CC_PMU_TIMER 0x0614 /* PMU timer */ +#define BCMA_CC_PMU_MINRES_MSK 0x0618 /* PMU min res mask */ +#define BCMA_CC_PMU_MAXRES_MSK 0x061C /* PMU max res mask */ +#define BCMA_CC_PMU_RES_TABSEL 0x0620 /* PMU res table sel */ +#define BCMA_CC_PMU_RES_DEPMSK 0x0624 /* PMU res dep mask */ +#define BCMA_CC_PMU_RES_UPDNTM 0x0628 /* PMU res updown timer */ +#define BCMA_CC_PMU_RES_TIMER 0x062C /* PMU res timer */ +#define BCMA_CC_PMU_CLKSTRETCH 0x0630 /* PMU clockstretch */ +#define BCMA_CC_PMU_WATCHDOG 0x0634 /* PMU watchdog */ +#define BCMA_CC_PMU_RES_REQTS 0x0640 /* PMU res req timer sel */ +#define BCMA_CC_PMU_RES_REQT 0x0644 /* PMU res req timer */ +#define BCMA_CC_PMU_RES_REQM 0x0648 /* PMU res req mask */ +#define BCMA_CC_CHIPCTL_ADDR 0x0650 +#define BCMA_CC_CHIPCTL_DATA 0x0654 +#define BCMA_CC_REGCTL_ADDR 0x0658 +#define BCMA_CC_REGCTL_DATA 0x065C +#define BCMA_CC_PLLCTL_ADDR 0x0660 +#define BCMA_CC_PLLCTL_DATA 0x0664 + +/* Data for the PMU, if available. + * Check availability with ((struct bcma_chipcommon)->capabilities & BCMA_CC_CAP_PMU) + */ +struct bcma_chipcommon_pmu { + u8 rev; /* PMU revision */ + u32 crystalfreq; /* The active crystal frequency (in kHz) */ +}; + +struct bcma_drv_cc { + struct bcma_device *core; + u32 status; + u32 capabilities; + u32 capabilities_ext; + /* Fast Powerup Delay constant */ + u16 fast_pwrup_delay; + struct bcma_chipcommon_pmu pmu; +}; + +/* Register access */ +#define bcma_cc_read32(cc, offset) \ + bcma_read32((cc)->core, offset) +#define bcma_cc_write32(cc, offset, val) \ + bcma_write32((cc)->core, offset, val) + +#define bcma_cc_mask32(cc, offset, mask) \ + bcma_cc_write32(cc, offset, bcma_cc_read32(cc, offset) & (mask)) +#define bcma_cc_set32(cc, offset, set) \ + bcma_cc_write32(cc, offset, bcma_cc_read32(cc, offset) | (set)) +#define bcma_cc_maskset32(cc, offset, mask, set) \ + bcma_cc_write32(cc, offset, (bcma_cc_read32(cc, offset) & (mask)) | (set)) + +extern void bcma_core_chipcommon_init(struct bcma_drv_cc *cc); + +extern void bcma_chipco_suspend(struct bcma_drv_cc *cc); +extern void bcma_chipco_resume(struct bcma_drv_cc *cc); + +extern void bcma_chipco_watchdog_timer_set(struct bcma_drv_cc *cc, + u32 ticks); + +void bcma_chipco_irq_mask(struct bcma_drv_cc *cc, u32 mask, u32 value); + +u32 bcma_chipco_irq_status(struct bcma_drv_cc *cc, u32 mask); + +/* Chipcommon GPIO pin access. */ +u32 bcma_chipco_gpio_in(struct bcma_drv_cc *cc, u32 mask); +u32 bcma_chipco_gpio_out(struct bcma_drv_cc *cc, u32 mask, u32 value); +u32 bcma_chipco_gpio_outen(struct bcma_drv_cc *cc, u32 mask, u32 value); +u32 bcma_chipco_gpio_control(struct bcma_drv_cc *cc, u32 mask, u32 value); +u32 bcma_chipco_gpio_intmask(struct bcma_drv_cc *cc, u32 mask, u32 value); +u32 bcma_chipco_gpio_polarity(struct bcma_drv_cc *cc, u32 mask, u32 value); + +/* PMU support */ +extern void bcma_pmu_init(struct bcma_drv_cc *cc); + +#endif /* LINUX_BCMA_DRIVER_CC_H_ */ diff --git a/include/linux/bcma/bcma_driver_pci.h b/include/linux/bcma/bcma_driver_pci.h new file mode 100644 index 0000000..b7e191c --- /dev/null +++ b/include/linux/bcma/bcma_driver_pci.h @@ -0,0 +1,89 @@ +#ifndef LINUX_BCMA_DRIVER_PCI_H_ +#define LINUX_BCMA_DRIVER_PCI_H_ + +#include + +struct pci_dev; + +/** PCI core registers. **/ +#define BCMA_CORE_PCI_CTL 0x0000 /* PCI Control */ +#define BCMA_CORE_PCI_CTL_RST_OE 0x00000001 /* PCI_RESET Output Enable */ +#define BCMA_CORE_PCI_CTL_RST 0x00000002 /* PCI_RESET driven out to pin */ +#define BCMA_CORE_PCI_CTL_CLK_OE 0x00000004 /* Clock gate Output Enable */ +#define BCMA_CORE_PCI_CTL_CLK 0x00000008 /* Gate for clock driven out to pin */ +#define BCMA_CORE_PCI_ARBCTL 0x0010 /* PCI Arbiter Control */ +#define BCMA_CORE_PCI_ARBCTL_INTERN 0x00000001 /* Use internal arbiter */ +#define BCMA_CORE_PCI_ARBCTL_EXTERN 0x00000002 /* Use external arbiter */ +#define BCMA_CORE_PCI_ARBCTL_PARKID 0x00000006 /* Mask, selects which agent is parked on an idle bus */ +#define BCMA_CORE_PCI_ARBCTL_PARKID_LAST 0x00000000 /* Last requestor */ +#define BCMA_CORE_PCI_ARBCTL_PARKID_4710 0x00000002 /* 4710 */ +#define BCMA_CORE_PCI_ARBCTL_PARKID_EXT0 0x00000004 /* External requestor 0 */ +#define BCMA_CORE_PCI_ARBCTL_PARKID_EXT1 0x00000006 /* External requestor 1 */ +#define BCMA_CORE_PCI_ISTAT 0x0020 /* Interrupt status */ +#define BCMA_CORE_PCI_ISTAT_INTA 0x00000001 /* PCI INTA# */ +#define BCMA_CORE_PCI_ISTAT_INTB 0x00000002 /* PCI INTB# */ +#define BCMA_CORE_PCI_ISTAT_SERR 0x00000004 /* PCI SERR# (write to clear) */ +#define BCMA_CORE_PCI_ISTAT_PERR 0x00000008 /* PCI PERR# (write to clear) */ +#define BCMA_CORE_PCI_ISTAT_PME 0x00000010 /* PCI PME# */ +#define BCMA_CORE_PCI_IMASK 0x0024 /* Interrupt mask */ +#define BCMA_CORE_PCI_IMASK_INTA 0x00000001 /* PCI INTA# */ +#define BCMA_CORE_PCI_IMASK_INTB 0x00000002 /* PCI INTB# */ +#define BCMA_CORE_PCI_IMASK_SERR 0x00000004 /* PCI SERR# */ +#define BCMA_CORE_PCI_IMASK_PERR 0x00000008 /* PCI PERR# */ +#define BCMA_CORE_PCI_IMASK_PME 0x00000010 /* PCI PME# */ +#define BCMA_CORE_PCI_MBOX 0x0028 /* Backplane to PCI Mailbox */ +#define BCMA_CORE_PCI_MBOX_F0_0 0x00000100 /* PCI function 0, INT 0 */ +#define BCMA_CORE_PCI_MBOX_F0_1 0x00000200 /* PCI function 0, INT 1 */ +#define BCMA_CORE_PCI_MBOX_F1_0 0x00000400 /* PCI function 1, INT 0 */ +#define BCMA_CORE_PCI_MBOX_F1_1 0x00000800 /* PCI function 1, INT 1 */ +#define BCMA_CORE_PCI_MBOX_F2_0 0x00001000 /* PCI function 2, INT 0 */ +#define BCMA_CORE_PCI_MBOX_F2_1 0x00002000 /* PCI function 2, INT 1 */ +#define BCMA_CORE_PCI_MBOX_F3_0 0x00004000 /* PCI function 3, INT 0 */ +#define BCMA_CORE_PCI_MBOX_F3_1 0x00008000 /* PCI function 3, INT 1 */ +#define BCMA_CORE_PCI_BCAST_ADDR 0x0050 /* Backplane Broadcast Address */ +#define BCMA_CORE_PCI_BCAST_ADDR_MASK 0x000000FF +#define BCMA_CORE_PCI_BCAST_DATA 0x0054 /* Backplane Broadcast Data */ +#define BCMA_CORE_PCI_GPIO_IN 0x0060 /* rev >= 2 only */ +#define BCMA_CORE_PCI_GPIO_OUT 0x0064 /* rev >= 2 only */ +#define BCMA_CORE_PCI_GPIO_ENABLE 0x0068 /* rev >= 2 only */ +#define BCMA_CORE_PCI_GPIO_CTL 0x006C /* rev >= 2 only */ +#define BCMA_CORE_PCI_SBTOPCI0 0x0100 /* Backplane to PCI translation 0 (sbtopci0) */ +#define BCMA_CORE_PCI_SBTOPCI0_MASK 0xFC000000 +#define BCMA_CORE_PCI_SBTOPCI1 0x0104 /* Backplane to PCI translation 1 (sbtopci1) */ +#define BCMA_CORE_PCI_SBTOPCI1_MASK 0xFC000000 +#define BCMA_CORE_PCI_SBTOPCI2 0x0108 /* Backplane to PCI translation 2 (sbtopci2) */ +#define BCMA_CORE_PCI_SBTOPCI2_MASK 0xC0000000 +#define BCMA_CORE_PCI_PCICFG0 0x0400 /* PCI config space 0 (rev >= 8) */ +#define BCMA_CORE_PCI_PCICFG1 0x0500 /* PCI config space 1 (rev >= 8) */ +#define BCMA_CORE_PCI_PCICFG2 0x0600 /* PCI config space 2 (rev >= 8) */ +#define BCMA_CORE_PCI_PCICFG3 0x0700 /* PCI config space 3 (rev >= 8) */ +#define BCMA_CORE_PCI_SPROM(wordoffset) (0x0800 + ((wordoffset) * 2)) /* SPROM shadow area (72 bytes) */ + +/* SBtoPCIx */ +#define BCMA_CORE_PCI_SBTOPCI_MEM 0x00000000 +#define BCMA_CORE_PCI_SBTOPCI_IO 0x00000001 +#define BCMA_CORE_PCI_SBTOPCI_CFG0 0x00000002 +#define BCMA_CORE_PCI_SBTOPCI_CFG1 0x00000003 +#define BCMA_CORE_PCI_SBTOPCI_PREF 0x00000004 /* Prefetch enable */ +#define BCMA_CORE_PCI_SBTOPCI_BURST 0x00000008 /* Burst enable */ +#define BCMA_CORE_PCI_SBTOPCI_MRM 0x00000020 /* Memory Read Multiple */ +#define BCMA_CORE_PCI_SBTOPCI_RC 0x00000030 /* Read Command mask (rev >= 11) */ +#define BCMA_CORE_PCI_SBTOPCI_RC_READ 0x00000000 /* Memory read */ +#define BCMA_CORE_PCI_SBTOPCI_RC_READL 0x00000010 /* Memory read line */ +#define BCMA_CORE_PCI_SBTOPCI_RC_READM 0x00000020 /* Memory read multiple */ + +/* PCIcore specific boardflags */ +#define BCMA_CORE_PCI_BFL_NOPCI 0x00000400 /* Board leaves PCI floating */ + +struct bcma_drv_pci { + struct bcma_device *core; + u8 setup_done:1; +}; + +/* Register access */ +#define pcicore_read32(pc, offset) bcma_read32((pc)->core, offset) +#define pcicore_write32(pc, offset, val) bcma_write32((pc)->core, offset, val) + +extern void bcma_core_pci_init(struct bcma_drv_pci *pc); + +#endif /* LINUX_BCMA_DRIVER_PCI_H_ */ diff --git a/include/linux/bcma/bcma_regs.h b/include/linux/bcma/bcma_regs.h new file mode 100644 index 0000000..f82d88a --- /dev/null +++ b/include/linux/bcma/bcma_regs.h @@ -0,0 +1,34 @@ +#ifndef LINUX_BCMA_REGS_H_ +#define LINUX_BCMA_REGS_H_ + +/* Agent registers (common for every core) */ +#define BCMA_IOCTL 0x0408 +#define BCMA_IOCTL_CLK 0x0001 +#define BCMA_IOCTL_FGC 0x0002 +#define BCMA_IOCTL_CORE_BITS 0x3FFC +#define BCMA_IOCTL_PME_EN 0x4000 +#define BCMA_IOCTL_BIST_EN 0x8000 +#define BCMA_RESET_CTL 0x0800 +#define BCMA_RESET_CTL_RESET 0x0001 + +/* BCMA PCI config space registers. */ +#define BCMA_PCI_PMCSR 0x44 +#define BCMA_PCI_PE 0x100 +#define BCMA_PCI_BAR0_WIN 0x80 /* Backplane address space 0 */ +#define BCMA_PCI_BAR1_WIN 0x84 /* Backplane address space 1 */ +#define BCMA_PCI_SPROMCTL 0x88 /* SPROM control */ +#define BCMA_PCI_SPROMCTL_WE 0x10 /* SPROM write enable */ +#define BCMA_PCI_BAR1_CONTROL 0x8c /* Address space 1 burst control */ +#define BCMA_PCI_IRQS 0x90 /* PCI interrupts */ +#define BCMA_PCI_IRQMASK 0x94 /* PCI IRQ control and mask (pcirev >= 6 only) */ +#define BCMA_PCI_BACKPLANE_IRQS 0x98 /* Backplane Interrupts */ +#define BCMA_PCI_BAR0_WIN2 0xAC +#define BCMA_PCI_GPIO_IN 0xB0 /* GPIO Input (pcirev >= 3 only) */ +#define BCMA_PCI_GPIO_OUT 0xB4 /* GPIO Output (pcirev >= 3 only) */ +#define BCMA_PCI_GPIO_OUT_ENABLE 0xB8 /* GPIO Output Enable/Disable (pcirev >= 3 only) */ +#define BCMA_PCI_GPIO_SCS 0x10 /* PCI config space bit 4 for 4306c0 slow clock source */ +#define BCMA_PCI_GPIO_HWRAD 0x20 /* PCI config space GPIO 13 for hw radio disable */ +#define BCMA_PCI_GPIO_XTAL 0x40 /* PCI config space GPIO 14 for Xtal powerup */ +#define BCMA_PCI_GPIO_PLL 0x80 /* PCI config space GPIO 15 for PLL powerdown */ + +#endif /* LINUX_BCMA_REGS_H_ */ diff --git a/include/linux/mod_devicetable.h b/include/linux/mod_devicetable.h index 48c007d..ae28e93 100644 --- a/include/linux/mod_devicetable.h +++ b/include/linux/mod_devicetable.h @@ -382,6 +382,23 @@ struct ssb_device_id { #define SSB_ANY_ID 0xFFFF #define SSB_ANY_REV 0xFF +/* Broadcom's specific AMBA core, see drivers/bcma/ */ +struct bcma_device_id { + __u16 manuf; + __u16 id; + __u8 rev; + __u8 class; +}; +#define BCMA_CORE(_manuf, _id, _rev, _class) \ + { .manuf = _manuf, .id = _id, .rev = _rev, .class = _class, } +#define BCMA_CORETABLE_END \ + { 0, }, + +#define BCMA_ANY_MANUF 0xFFFF +#define BCMA_ANY_ID 0xFFFF +#define BCMA_ANY_REV 0xFF +#define BCMA_ANY_CLASS 0xFF + struct virtio_device_id { __u32 device; __u32 vendor; diff --git a/scripts/mod/file2alias.c b/scripts/mod/file2alias.c index 88f3f07..e26e2fb 100644 --- a/scripts/mod/file2alias.c +++ b/scripts/mod/file2alias.c @@ -702,6 +702,24 @@ static int do_ssb_entry(const char *filename, return 1; } +/* Looks like: bcma:mNidNrevNclN. */ +static int do_bcma_entry(const char *filename, + struct bcma_device_id *id, char *alias) +{ + id->manuf = TO_NATIVE(id->manuf); + id->id = TO_NATIVE(id->id); + id->rev = TO_NATIVE(id->rev); + id->class = TO_NATIVE(id->class); + + strcpy(alias, "bcma:"); + ADD(alias, "m", id->manuf != BCMA_ANY_MANUF, id->manuf); + ADD(alias, "id", id->id != BCMA_ANY_ID, id->id); + ADD(alias, "rev", id->rev != BCMA_ANY_REV, id->rev); + ADD(alias, "cl", id->class != BCMA_ANY_CLASS, id->class); + add_wildcard(alias); + return 1; +} + /* Looks like: virtio:dNvN */ static int do_virtio_entry(const char *filename, struct virtio_device_id *id, char *alias) @@ -968,6 +986,10 @@ void handle_moddevtable(struct module *mod, struct elf_info *info, do_table(symval, sym->st_size, sizeof(struct ssb_device_id), "ssb", do_ssb_entry, mod); + else if (sym_is(symname, "__mod_bcma_device_table")) + do_table(symval, sym->st_size, + sizeof(struct bcma_device_id), "bcma", + do_bcma_entry, mod); else if (sym_is(symname, "__mod_virtio_device_table")) do_table(symval, sym->st_size, sizeof(struct virtio_device_id), "virtio", -- cgit v0.10.2 From 7cc5eb629cefa9a40295ff5ee4b1ec41ad855e8d Mon Sep 17 00:00:00 2001 From: Amitkumar Karwar Date: Mon, 9 May 2011 19:00:18 -0700 Subject: mwifiex: remove unnecessary struct mwifiex_opt_sleep_confirm_buffer The structure definition is struct mwifiex_opt_sleep_confirm_buffer { u8 hdr[4]; struct mwifiex_opt_sleep_confirm ps_cfm_sleep; } __packed; For sleep_confirm command we already reserve 4 bytes (using skb_reserve()) for an interface header. It will be filled later by interface specific code. We don't need "hdr[4]" element in above structure. So we can use "struct mwifiex_opt_sleep_confirm" directly instead of "struct mwifiex_opt_sleep_confirm_buffer". Signed-off-by: Amitkumar Karwar Signed-off-by: Yogesh Ashok Powar Signed-off-by: Bing Zhao Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/mwifiex/cmdevt.c b/drivers/net/wireless/mwifiex/cmdevt.c index 1c8b4f7..5c75399 100644 --- a/drivers/net/wireless/mwifiex/cmdevt.c +++ b/drivers/net/wireless/mwifiex/cmdevt.c @@ -223,24 +223,23 @@ static int mwifiex_dnld_cmd_to_fw(struct mwifiex_private *priv, static int mwifiex_dnld_sleep_confirm_cmd(struct mwifiex_adapter *adapter) { int ret; - u16 cmd_len; struct mwifiex_private *priv; - struct mwifiex_opt_sleep_confirm_buffer *sleep_cfm_buf = - (struct mwifiex_opt_sleep_confirm_buffer *) + struct mwifiex_opt_sleep_confirm *sleep_cfm_buf = + (struct mwifiex_opt_sleep_confirm *) adapter->sleep_cfm->data; - cmd_len = sizeof(struct mwifiex_opt_sleep_confirm); priv = mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_ANY); - sleep_cfm_buf->ps_cfm_sleep.seq_num = + sleep_cfm_buf->seq_num = cpu_to_le16((HostCmd_SET_SEQ_NO_BSS_INFO (adapter->seq_num, priv->bss_num, priv->bss_type))); adapter->seq_num++; + skb_push(adapter->sleep_cfm, INTF_HEADER_LEN); ret = adapter->if_ops.host_to_card(adapter, MWIFIEX_TYPE_CMD, adapter->sleep_cfm->data, - adapter->sleep_cfm->len + - INTF_HEADER_LEN, NULL); + adapter->sleep_cfm->len, NULL); + skb_pull(adapter->sleep_cfm, INTF_HEADER_LEN); if (ret == -1) { dev_err(adapter->dev, "SLEEP_CFM: failed\n"); @@ -249,14 +248,14 @@ static int mwifiex_dnld_sleep_confirm_cmd(struct mwifiex_adapter *adapter) } if (GET_BSS_ROLE(mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_ANY)) == MWIFIEX_BSS_ROLE_STA) { - if (!sleep_cfm_buf->ps_cfm_sleep.resp_ctrl) + if (!sleep_cfm_buf->resp_ctrl) /* Response is not needed for sleep confirm command */ adapter->ps_state = PS_STATE_SLEEP; else adapter->ps_state = PS_STATE_SLEEP_CFM; - if (!sleep_cfm_buf->ps_cfm_sleep.resp_ctrl + if (!sleep_cfm_buf->resp_ctrl && (adapter->is_hs_configured && !adapter->sleep_period.period)) { adapter->pm_wakeup_card_req = true; diff --git a/drivers/net/wireless/mwifiex/fw.h b/drivers/net/wireless/mwifiex/fw.h index 6d1c454..c6b2681 100644 --- a/drivers/net/wireless/mwifiex/fw.h +++ b/drivers/net/wireless/mwifiex/fw.h @@ -1198,9 +1198,4 @@ struct mwifiex_opt_sleep_confirm { __le16 action; __le16 resp_ctrl; } __packed; - -struct mwifiex_opt_sleep_confirm_buffer { - u8 hdr[4]; - struct mwifiex_opt_sleep_confirm ps_cfm_sleep; -} __packed; #endif /* !_MWIFIEX_FW_H_ */ diff --git a/drivers/net/wireless/mwifiex/init.c b/drivers/net/wireless/mwifiex/init.c index 6a8fd99..3f1559e 100644 --- a/drivers/net/wireless/mwifiex/init.c +++ b/drivers/net/wireless/mwifiex/init.c @@ -175,7 +175,7 @@ static int mwifiex_allocate_adapter(struct mwifiex_adapter *adapter) } adapter->sleep_cfm = - dev_alloc_skb(sizeof(struct mwifiex_opt_sleep_confirm_buffer) + dev_alloc_skb(sizeof(struct mwifiex_opt_sleep_confirm) + INTF_HEADER_LEN); if (!adapter->sleep_cfm) { @@ -197,10 +197,10 @@ static int mwifiex_allocate_adapter(struct mwifiex_adapter *adapter) */ static void mwifiex_init_adapter(struct mwifiex_adapter *adapter) { - struct mwifiex_opt_sleep_confirm_buffer *sleep_cfm_buf = NULL; + struct mwifiex_opt_sleep_confirm *sleep_cfm_buf = NULL; - skb_put(adapter->sleep_cfm, sizeof(sleep_cfm_buf->ps_cfm_sleep)); - sleep_cfm_buf = (struct mwifiex_opt_sleep_confirm_buffer *) + skb_put(adapter->sleep_cfm, sizeof(struct mwifiex_opt_sleep_confirm)); + sleep_cfm_buf = (struct mwifiex_opt_sleep_confirm *) (adapter->sleep_cfm->data); adapter->cmd_sent = false; @@ -268,16 +268,14 @@ static void mwifiex_init_adapter(struct mwifiex_adapter *adapter) mwifiex_wmm_init(adapter); if (adapter->sleep_cfm) { - memset(&sleep_cfm_buf->ps_cfm_sleep, 0, - adapter->sleep_cfm->len); - sleep_cfm_buf->ps_cfm_sleep.command = - cpu_to_le16(HostCmd_CMD_802_11_PS_MODE_ENH); - sleep_cfm_buf->ps_cfm_sleep.size = - cpu_to_le16(adapter->sleep_cfm->len); - sleep_cfm_buf->ps_cfm_sleep.result = 0; - sleep_cfm_buf->ps_cfm_sleep.action = cpu_to_le16(SLEEP_CONFIRM); - sleep_cfm_buf->ps_cfm_sleep.resp_ctrl = - cpu_to_le16(RESP_NEEDED); + memset(sleep_cfm_buf, 0, adapter->sleep_cfm->len); + sleep_cfm_buf->command = + cpu_to_le16(HostCmd_CMD_802_11_PS_MODE_ENH); + sleep_cfm_buf->size = + cpu_to_le16(adapter->sleep_cfm->len); + sleep_cfm_buf->result = 0; + sleep_cfm_buf->action = cpu_to_le16(SLEEP_CONFIRM); + sleep_cfm_buf->resp_ctrl = cpu_to_le16(RESP_NEEDED); } memset(&adapter->sleep_params, 0, sizeof(adapter->sleep_params)); memset(&adapter->sleep_period, 0, sizeof(adapter->sleep_period)); -- cgit v0.10.2 From cc4c4353f0ebde05992bf360f16ec92260811393 Mon Sep 17 00:00:00 2001 From: Allan Stephens Date: Fri, 8 Apr 2011 10:50:52 -0400 Subject: tipc: Update comments in message header include file Removes comments in TIPC's message header include file that are outdated and/or unnecessary. Also introduces short comments (or supplements existing ones) to better describe several set of existing symbolic constants. Signed-off-by: Allan Stephens Signed-off-by: Paul Gortmaker diff --git a/net/tipc/msg.h b/net/tipc/msg.h index de02339..d098317 100644 --- a/net/tipc/msg.h +++ b/net/tipc/msg.h @@ -39,41 +39,24 @@ #include "bearer.h" +/* + * Constants and routines used to read and write TIPC payload message headers + * + * Note: Some items are also used with TIPC internal message headers + */ + #define TIPC_VERSION 2 /* - * TIPC user data message header format, version 2: - * - * - * 1 0 9 8 7 6 5 4|3 2 1 0 9 8 7 6|5 4 3 2 1 0 9 8|7 6 5 4 3 2 1 0 - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * w0:|vers | user |hdr sz |n|d|s|-| message size | - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * w1:|mstyp| error |rer cnt|lsc|opt p| broadcast ack no | - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * w2:| link level ack no | broadcast/link level seq no | - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * w3:| previous node | - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * w4:| originating port | - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * w5:| destination port | - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * w6:| originating node | - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * w7:| destination node | - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * w8:| name type / transport sequence number | - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * w9:| name instance/multicast lower bound | - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * wA:| multicast upper bound | - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * / / - * \ options \ - * / / - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * + * Payload message users are defined in TIPC's public API: + * - TIPC_LOW_IMPORTANCE + * - TIPC_MEDIUM_IMPORTANCE + * - TIPC_HIGH_IMPORTANCE + * - TIPC_CRITICAL_IMPORTANCE + */ + +/* + * Payload message types */ #define TIPC_CONN_MSG 0 @@ -81,6 +64,9 @@ #define TIPC_NAMED_MSG 2 #define TIPC_DIRECT_MSG 3 +/* + * Message header sizes + */ #define SHORT_H_SIZE 24 /* Connected, in-cluster messages */ #define DIR_MSG_H_SIZE 32 /* Directly addressed messages */ @@ -473,40 +459,11 @@ static inline struct tipc_msg *msg_get_wrapped(struct tipc_msg *m) /* - TIPC internal message header format, version 2 - - 1 0 9 8 7 6 5 4|3 2 1 0 9 8 7 6|5 4 3 2 1 0 9 8|7 6 5 4 3 2 1 0 - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - w0:|vers |msg usr|hdr sz |n|resrv| packet size | - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - w1:|m typ| sequence gap | broadcast ack no | - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - w2:| link level ack no/bc_gap_from | seq no / bcast_gap_to | - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - w3:| previous node | - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - w4:| next sent broadcast/fragm no | next sent pkt/ fragm msg no | - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - w5:| session no |rsv=0|r|berid|link prio|netpl|p| - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - w6:| originating node | - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - w7:| destination node | - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - w8:| transport sequence number | - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - w9:| msg count / bcast tag | link tolerance | - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - \ \ - / User Specific Data / - \ \ - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - - NB: CONN_MANAGER use data message format. LINK_CONFIG has own format. -*/ + * Constants and routines used to read and write TIPC internal message headers + */ /* - * Internal users + * Internal message users */ #define BCAST_PROTOCOL 5 @@ -520,7 +477,7 @@ static inline struct tipc_msg *msg_get_wrapped(struct tipc_msg *m) #define LINK_CONFIG 13 /* - * Connection management protocol messages + * Connection management protocol message types */ #define CONN_PROBE 0 @@ -528,7 +485,7 @@ static inline struct tipc_msg *msg_get_wrapped(struct tipc_msg *m) #define CONN_ACK 2 /* - * Name distributor messages + * Name distributor message types */ #define PUBLICATION 0 -- cgit v0.10.2 From 19f53d2cef97506364638c647a3aa11291819896 Mon Sep 17 00:00:00 2001 From: Allan Stephens Date: Fri, 8 Apr 2011 10:59:04 -0400 Subject: tipc: Eliminate unused routing message definitions Gets rid of unused constants defining the types used in routing messages. These messages no longer exist in TIPC now that multicluster and multizone support has been eliminated. Signed-off-by: Allan Stephens Signed-off-by: Paul Gortmaker diff --git a/net/tipc/msg.h b/net/tipc/msg.h index d098317..c5593ac 100644 --- a/net/tipc/msg.h +++ b/net/tipc/msg.h @@ -741,15 +741,6 @@ static inline void msg_set_link_tolerance(struct tipc_msg *m, u32 n) #define ORIGINAL_MSG 1 /* - * Routing table message types - */ -#define EXT_ROUTING_TABLE 0 -#define LOCAL_ROUTING_TABLE 1 /* obsoleted */ -#define SLAVE_ROUTING_TABLE 2 -#define ROUTE_ADDITION 3 -#define ROUTE_REMOVAL 4 - -/* * Config protocol message types */ -- cgit v0.10.2 From 92138d1f254d58b818e7c3b91a1967cf57d374b5 Mon Sep 17 00:00:00 2001 From: Allan Stephens Date: Fri, 8 Apr 2011 11:04:15 -0400 Subject: tipc: Cosmetic consolidation of internal message type definitions Half of the #define entries in msg.h were down at the bottom of the header, instead of up at the top before any of the static inlines etc. Relocate them up to the top, to be consistent with the other normal linux header file layout conventions. Signed-off-by: Allan Stephens Signed-off-by: Paul Gortmaker diff --git a/net/tipc/msg.h b/net/tipc/msg.h index c5593ac..005b318 100644 --- a/net/tipc/msg.h +++ b/net/tipc/msg.h @@ -491,6 +491,35 @@ static inline struct tipc_msg *msg_get_wrapped(struct tipc_msg *m) #define PUBLICATION 0 #define WITHDRAWAL 1 +/* + * Segmentation message types + */ + +#define FIRST_FRAGMENT 0 +#define FRAGMENT 1 +#define LAST_FRAGMENT 2 + +/* + * Link management protocol message types + */ + +#define STATE_MSG 0 +#define RESET_MSG 1 +#define ACTIVATE_MSG 2 + +/* + * Changeover tunnel message types + */ +#define DUPLICATE_MSG 0 +#define ORIGINAL_MSG 1 + +/* + * Config protocol message types + */ + +#define DSC_REQ_MSG 0 +#define DSC_RESP_MSG 1 + /* * Word 1 @@ -718,35 +747,6 @@ static inline void msg_set_link_tolerance(struct tipc_msg *m, u32 n) msg_set_bits(m, 9, 0, 0xffff, n); } -/* - * Segmentation message types - */ - -#define FIRST_FRAGMENT 0 -#define FRAGMENT 1 -#define LAST_FRAGMENT 2 - -/* - * Link management protocol message types - */ - -#define STATE_MSG 0 -#define RESET_MSG 1 -#define ACTIVATE_MSG 2 - -/* - * Changeover tunnel message types - */ -#define DUPLICATE_MSG 0 -#define ORIGINAL_MSG 1 - -/* - * Config protocol message types - */ - -#define DSC_REQ_MSG 0 -#define DSC_RESP_MSG 1 - u32 tipc_msg_tot_importance(struct tipc_msg *m); void tipc_msg_init(struct tipc_msg *m, u32 user, u32 type, u32 hsize, u32 destnode); -- cgit v0.10.2 From 7775bcc722ed9993e83401fee9c14008843b83c7 Mon Sep 17 00:00:00 2001 From: Allan Stephens Date: Tue, 12 Apr 2011 14:59:03 -0400 Subject: tipc: Remove code to emulate loss of broadcast messages Eliminates optional code used to test TIPC's ability to recover from lost broadcast messages. This code duplicates functionality already provided by the network stack's QoS option "network emulator". Signed-off-by: Allan Stephens Signed-off-by: Paul Gortmaker diff --git a/net/tipc/bcast.c b/net/tipc/bcast.c index 7dc1dc7..08e3216 100644 --- a/net/tipc/bcast.c +++ b/net/tipc/bcast.c @@ -44,13 +44,6 @@ #define BCLINK_WIN_DEFAULT 20 /* bcast link window size (default) */ -/* - * Loss rate for incoming broadcast frames; used to test retransmission code. - * Set to N to cause every N'th frame to be discarded; 0 => don't discard any. - */ - -#define TIPC_BCAST_LOSS_RATE 0 - /** * struct bcbearer_pair - a pair of bearers used by broadcast link * @primary: pointer to primary bearer @@ -434,9 +427,6 @@ int tipc_bclink_send_msg(struct sk_buff *buf) void tipc_bclink_recv_pkt(struct sk_buff *buf) { -#if (TIPC_BCAST_LOSS_RATE) - static int rx_count; -#endif struct tipc_msg *msg = buf_msg(buf); struct tipc_node *node = tipc_node_find(msg_prevnode(msg)); u32 next_in; @@ -470,14 +460,6 @@ void tipc_bclink_recv_pkt(struct sk_buff *buf) return; } -#if (TIPC_BCAST_LOSS_RATE) - if (++rx_count == TIPC_BCAST_LOSS_RATE) { - rx_count = 0; - buf_discard(buf); - return; - } -#endif - tipc_node_lock(node); receive: deferred = node->bclink.deferred_head; -- cgit v0.10.2 From 670c54083aa6e0eeefda1c4b307a91679b577664 Mon Sep 17 00:00:00 2001 From: Allan Stephens Date: Sun, 17 Apr 2011 10:29:16 -0400 Subject: tipc: Don't initialize link selector field in fragmented messages Eliminates code that sets the link selector field in the header of fragmented messages, since this information is never referenced. (The unnecessary initialization was harmless as it was over-written by the fragmented message identifier value before the fragments were transmitted.) Signed-off-by: Allan Stephens Signed-off-by: Paul Gortmaker diff --git a/net/tipc/link.c b/net/tipc/link.c index ebf338f..95249ba 100644 --- a/net/tipc/link.c +++ b/net/tipc/link.c @@ -1169,7 +1169,6 @@ again: tipc_msg_init(&fragm_hdr, MSG_FRAGMENTER, FIRST_FRAGMENT, INT_H_SIZE, msg_destnode(hdr)); - msg_set_link_selector(&fragm_hdr, sender->ref); msg_set_size(&fragm_hdr, max_pkt); msg_set_fragm_no(&fragm_hdr, 1); @@ -2427,7 +2426,6 @@ static int link_send_long_buf(struct link *l_ptr, struct sk_buff *buf) tipc_msg_init(&fragm_hdr, MSG_FRAGMENTER, FIRST_FRAGMENT, INT_H_SIZE, destaddr); - msg_set_link_selector(&fragm_hdr, msg_link_selector(inmsg)); msg_set_long_msgno(&fragm_hdr, mod(l_ptr->long_msg_seq_no++)); msg_set_fragm_no(&fragm_hdr, fragm_no); l_ptr->stats.sent_fragmented++; -- cgit v0.10.2 From e0f085964cac97a3a9e47741365ef6a03e500873 Mon Sep 17 00:00:00 2001 From: Allan Stephens Date: Sun, 17 Apr 2011 11:44:24 -0400 Subject: tipc: Avoid pointless masking of fragmented message identifier Eliminates code that restricts a link's counter of its fragmented messages to a 16-bit value, since the counter value is automatically restricted to this range when it is written into the message header. Signed-off-by: Allan Stephens Signed-off-by: Paul Gortmaker diff --git a/net/tipc/link.c b/net/tipc/link.c index 95249ba..ad356df 100644 --- a/net/tipc/link.c +++ b/net/tipc/link.c @@ -1276,7 +1276,7 @@ reject: /* Append whole chain to send queue: */ buf = buf_chain; - l_ptr->long_msg_seq_no = mod(l_ptr->long_msg_seq_no + 1); + l_ptr->long_msg_seq_no++; if (!l_ptr->next_out) l_ptr->next_out = buf_chain; l_ptr->stats.sent_fragmented++; @@ -2426,7 +2426,7 @@ static int link_send_long_buf(struct link *l_ptr, struct sk_buff *buf) tipc_msg_init(&fragm_hdr, MSG_FRAGMENTER, FIRST_FRAGMENT, INT_H_SIZE, destaddr); - msg_set_long_msgno(&fragm_hdr, mod(l_ptr->long_msg_seq_no++)); + msg_set_long_msgno(&fragm_hdr, l_ptr->long_msg_seq_no++); msg_set_fragm_no(&fragm_hdr, fragm_no); l_ptr->stats.sent_fragmented++; -- cgit v0.10.2 From 77561557447d3be586e701815e261c93c11ded00 Mon Sep 17 00:00:00 2001 From: Allan Stephens Date: Sun, 17 Apr 2011 13:06:23 -0400 Subject: tipc: Fix issues with fragmentation of an existing message buffer Modifies the routine that fragments an existing message buffer to use similar logic to that used when generating fragments from an iovec. The routine now creates a complete chain of fragments and adds them to the link transmit queue as a unit, so that the link sends all fragments or none; this prevents the incomplete transmission of a fragmented message that might otherwise result because of link congestion or memory exhaustion. This change also ensures that the counter recording the number of fragmented messages sent by the link is now incremented only if the message is actually sent. Signed-off-by: Allan Stephens Signed-off-by: Paul Gortmaker diff --git a/net/tipc/link.c b/net/tipc/link.c index ad356df..02b083e 100644 --- a/net/tipc/link.c +++ b/net/tipc/link.c @@ -2406,6 +2406,8 @@ void tipc_link_recv_bundle(struct sk_buff *buf) */ static int link_send_long_buf(struct link *l_ptr, struct sk_buff *buf) { + struct sk_buff *buf_chain = NULL; + struct sk_buff *buf_chain_tail = (struct sk_buff *)&buf_chain; struct tipc_msg *inmsg = buf_msg(buf); struct tipc_msg fragm_hdr; u32 insize = msg_size(inmsg); @@ -2414,7 +2416,7 @@ static int link_send_long_buf(struct link *l_ptr, struct sk_buff *buf) u32 rest = insize; u32 pack_sz = l_ptr->max_pkt; u32 fragm_sz = pack_sz - INT_H_SIZE; - u32 fragm_no = 1; + u32 fragm_no = 0; u32 destaddr; if (msg_short(inmsg)) @@ -2426,9 +2428,6 @@ static int link_send_long_buf(struct link *l_ptr, struct sk_buff *buf) tipc_msg_init(&fragm_hdr, MSG_FRAGMENTER, FIRST_FRAGMENT, INT_H_SIZE, destaddr); - msg_set_long_msgno(&fragm_hdr, l_ptr->long_msg_seq_no++); - msg_set_fragm_no(&fragm_hdr, fragm_no); - l_ptr->stats.sent_fragmented++; /* Chop up message: */ @@ -2441,27 +2440,37 @@ static int link_send_long_buf(struct link *l_ptr, struct sk_buff *buf) } fragm = tipc_buf_acquire(fragm_sz + INT_H_SIZE); if (fragm == NULL) { - warn("Link unable to fragment message\n"); - dsz = -ENOMEM; - goto exit; + buf_discard(buf); + while (buf_chain) { + buf = buf_chain; + buf_chain = buf_chain->next; + buf_discard(buf); + } + return -ENOMEM; } msg_set_size(&fragm_hdr, fragm_sz + INT_H_SIZE); + fragm_no++; + msg_set_fragm_no(&fragm_hdr, fragm_no); skb_copy_to_linear_data(fragm, &fragm_hdr, INT_H_SIZE); skb_copy_to_linear_data_offset(fragm, INT_H_SIZE, crs, fragm_sz); - /* Send queued messages first, if any: */ + buf_chain_tail->next = fragm; + buf_chain_tail = fragm; - l_ptr->stats.sent_fragments++; - tipc_link_send_buf(l_ptr, fragm); - if (!tipc_link_is_up(l_ptr)) - return dsz; - msg_set_fragm_no(&fragm_hdr, ++fragm_no); rest -= fragm_sz; crs += fragm_sz; msg_set_type(&fragm_hdr, FRAGMENT); } -exit: buf_discard(buf); + + /* Append chain of fragments to send queue & send them */ + + l_ptr->long_msg_seq_no++; + link_add_chain_to_outqueue(l_ptr, buf_chain, l_ptr->long_msg_seq_no); + l_ptr->stats.sent_fragments += fragm_no; + l_ptr->stats.sent_fragmented++; + tipc_link_push_queue(l_ptr); + return dsz; } -- cgit v0.10.2 From 53b94364a7c96d3b2276cb2bbbecfb269bc9f0fc Mon Sep 17 00:00:00 2001 From: Allan Stephens Date: Sun, 17 Apr 2011 16:02:11 -0400 Subject: tipc: Set name lookup scope field properly in all data messages Ensures that all outgoing data messages have the "name lookup scope" field of their header set correctly; that is, named multicast messages now specify cluster-wide name lookup, while messages not using TIPC naming zero out the lookup field. (Previously, the lookup scope specified for these types of messages was inherited from the last message sent by the sending port.) Signed-off-by: Allan Stephens Signed-off-by: Paul Gortmaker diff --git a/net/tipc/port.c b/net/tipc/port.c index 6ff78f9..c2229c4 100644 --- a/net/tipc/port.c +++ b/net/tipc/port.c @@ -91,6 +91,7 @@ int tipc_multicast(u32 ref, struct tipc_name_seq const *seq, hdr = &oport->phdr; msg_set_type(hdr, TIPC_MCAST_MSG); + msg_set_lookup_scope(hdr, TIPC_CLUSTER_SCOPE); msg_set_nametype(hdr, seq->type); msg_set_namelower(hdr, seq->lower); msg_set_nameupper(hdr, seq->upper); @@ -1065,6 +1066,7 @@ int tipc_connect2port(u32 ref, struct tipc_portid const *peer) msg_set_orignode(msg, tipc_own_addr); msg_set_origport(msg, p_ptr->ref); msg_set_type(msg, TIPC_CONN_MSG); + msg_set_lookup_scope(msg, 0); msg_set_hdr_sz(msg, SHORT_H_SIZE); p_ptr->probing_interval = PROBING_INTERVAL; @@ -1276,6 +1278,7 @@ int tipc_send2port(u32 ref, struct tipc_portid const *dest, msg = &p_ptr->phdr; msg_set_type(msg, TIPC_DIRECT_MSG); + msg_set_lookup_scope(msg, 0); msg_set_orignode(msg, tipc_own_addr); msg_set_origport(msg, ref); msg_set_destnode(msg, dest->node); -- cgit v0.10.2 From 7462b9e9f69aa6c5e2fded65d3b03df4ed08ff45 Mon Sep 17 00:00:00 2001 From: Allan Stephens Date: Mon, 18 Apr 2011 10:08:22 -0400 Subject: tipc: Fix problem with bundled multicast message Set the destination node and destination port fields of an outgoing multicast message header to zero; this is necessary to ensure that the receiving node can route the message properly if it was packed into a bundle due to link congestion. (Previously, there was a chance that the receiving node would send the unbundled message to a random node & port, rather than processing the message itself.) Signed-off-by: Allan Stephens Signed-off-by: Paul Gortmaker diff --git a/net/tipc/port.c b/net/tipc/port.c index c2229c4..ac64037 100644 --- a/net/tipc/port.c +++ b/net/tipc/port.c @@ -92,6 +92,8 @@ int tipc_multicast(u32 ref, struct tipc_name_seq const *seq, hdr = &oport->phdr; msg_set_type(hdr, TIPC_MCAST_MSG); msg_set_lookup_scope(hdr, TIPC_CLUSTER_SCOPE); + msg_set_destport(hdr, 0); + msg_set_destnode(hdr, 0); msg_set_nametype(hdr, seq->type); msg_set_namelower(hdr, seq->lower); msg_set_nameupper(hdr, seq->upper); -- cgit v0.10.2 From 7f47f5c751c93f2ca9e7f0ef6c0915162ac9e076 Mon Sep 17 00:00:00 2001 From: Allan Stephens Date: Mon, 18 Apr 2011 10:14:26 -0400 Subject: tipc: Update destination node field on incoming multicast messages Sets the destination node field of an incoming multicast message to the receiving node's network address before handing off the message to each receiving port. This ensures that, in the event the destination port returns the message to the sender, the sender can identify which node the destination port belonged to. Signed-off-by: Allan Stephens Signed-off-by: Paul Gortmaker diff --git a/net/tipc/port.c b/net/tipc/port.c index ac64037..9f2ff12 100644 --- a/net/tipc/port.c +++ b/net/tipc/port.c @@ -164,6 +164,7 @@ void tipc_port_recv_mcast(struct sk_buff *buf, struct port_list *dp) /* Deliver a copy of message to each destination port */ if (dp->count != 0) { + msg_set_destnode(msg, tipc_own_addr); if (dp->count == 1) { msg_set_destport(msg, dp->ports[0]); tipc_port_recv_msg(buf); -- cgit v0.10.2 From bebc55aeffa72d8198e5c54cab9973a30e92f854 Mon Sep 17 00:00:00 2001 From: Allan Stephens Date: Tue, 19 Apr 2011 10:17:58 -0400 Subject: tipc: Fix sk_buff leaks when link congestion is detected Modifies a TIPC send routine that did not discard the outgoing sk_buff if it was not transmitted because of link congestion; this eliminates the potential for buffer leakage in the many callers who did not clean up the unsent buffer. (The two routines that previously did discard the unsent buffer have been updated to eliminate their now-redundant clean up.) Signed-off-by: Allan Stephens Signed-off-by: Paul Gortmaker diff --git a/net/tipc/bcast.c b/net/tipc/bcast.c index 08e3216..fa68d1e 100644 --- a/net/tipc/bcast.c +++ b/net/tipc/bcast.c @@ -407,9 +407,7 @@ int tipc_bclink_send_msg(struct sk_buff *buf) spin_lock_bh(&bc_lock); res = tipc_link_send_buf(bcl, buf); - if (unlikely(res == -ELINKCONG)) - buf_discard(buf); - else + if (likely(res > 0)) bclink_set_last_sent(); bcl->stats.queue_sz_counts++; diff --git a/net/tipc/link.c b/net/tipc/link.c index 02b083e..2a9f44a 100644 --- a/net/tipc/link.c +++ b/net/tipc/link.c @@ -864,8 +864,9 @@ int tipc_link_send_buf(struct link *l_ptr, struct sk_buff *buf) if (unlikely(queue_size >= queue_limit)) { if (imp <= TIPC_CRITICAL_IMPORTANCE) { - return link_schedule_port(l_ptr, msg_origport(msg), - size); + link_schedule_port(l_ptr, msg_origport(msg), size); + buf_discard(buf); + return -ELINKCONG; } buf_discard(buf); if (imp > CONN_MANAGER) { @@ -1069,8 +1070,6 @@ again: if (likely(buf)) { res = link_send_buf_fast(l_ptr, buf, &sender->max_pkt); - if (unlikely(res < 0)) - buf_discard(buf); exit: tipc_node_unlock(node); read_unlock_bh(&tipc_net_lock); -- cgit v0.10.2 From 1f3de471adf5c2a584480a6010808d7a17063897 Mon Sep 17 00:00:00 2001 From: Paul Gortmaker Date: Tue, 19 Apr 2011 13:11:23 -0400 Subject: tipc: make zone/cluster mask constants a define This allows them to be available for easy re-use in other places and avoids trivial mistakes caused by "count the f's and 0's". Signed-off-by: Paul Gortmaker diff --git a/net/tipc/addr.h b/net/tipc/addr.h index 8971aba..e4f35af 100644 --- a/net/tipc/addr.h +++ b/net/tipc/addr.h @@ -37,14 +37,17 @@ #ifndef _TIPC_ADDR_H #define _TIPC_ADDR_H +#define TIPC_ZONE_MASK 0xff000000u +#define TIPC_CLUSTER_MASK 0xfffff000u + static inline u32 tipc_zone_mask(u32 addr) { - return addr & 0xff000000u; + return addr & TIPC_ZONE_MASK; } static inline u32 tipc_cluster_mask(u32 addr) { - return addr & 0xfffff000u; + return addr & TIPC_CLUSTER_MASK; } static inline int in_own_cluster(u32 addr) -- cgit v0.10.2 From 66e019a6af827a254641e83e96ee36b0f4adc5e3 Mon Sep 17 00:00:00 2001 From: Allan Stephens Date: Wed, 20 Apr 2011 16:24:07 -0500 Subject: tipc: Strengthen checks for neighboring node discovery Enhances existing checks on the discovery domain associated with a TIPC bearer. A bearer can no longer be configured to accept links from itself only (which would be pointless), or to nodes outside its own cluster (since multi-cluster support has now been removed from TIPC). Also, the neighbor discovery routine now validates link setup requests against the configured discovery domain for the bearer, rather than simply ensuring the requesting node belongs to the node's own cluster. Signed-off-by: Allan Stephens Signed-off-by: Paul Gortmaker diff --git a/net/tipc/bearer.c b/net/tipc/bearer.c index 411719f..f7c29af 100644 --- a/net/tipc/bearer.c +++ b/net/tipc/bearer.c @@ -493,8 +493,15 @@ int tipc_enable_bearer(const char *name, u32 disc_domain, u32 priority) warn("Bearer <%s> rejected, illegal name\n", name); return -EINVAL; } - if (!tipc_addr_domain_valid(disc_domain) || - !tipc_in_scope(disc_domain, tipc_own_addr)) { + if (tipc_addr_domain_valid(disc_domain) && + (disc_domain != tipc_own_addr)) { + if (tipc_in_scope(disc_domain, tipc_own_addr)) { + disc_domain = tipc_own_addr & TIPC_CLUSTER_MASK; + res = 0; /* accept any node in own cluster */ + } else if (in_own_cluster(disc_domain)) + res = 0; /* accept specified node in own cluster */ + } + if (res) { warn("Bearer <%s> rejected, illegal discovery domain\n", name); return -EINVAL; } diff --git a/net/tipc/discover.c b/net/tipc/discover.c index 491eff5..d2163bd 100644 --- a/net/tipc/discover.c +++ b/net/tipc/discover.c @@ -52,6 +52,7 @@ * struct link_req - information about an ongoing link setup request * @bearer: bearer issuing requests * @dest: destination address for request messages + * @domain: network domain to which links can be established * @buf: request message to be (repeatedly) sent * @timer: timer governing period between requests * @timer_intv: current interval between requests (in ms) @@ -59,6 +60,7 @@ struct link_req { struct tipc_bearer *bearer; struct tipc_media_addr dest; + u32 domain; struct sk_buff *buf; struct timer_list timer; unsigned int timer_intv; @@ -147,7 +149,7 @@ void tipc_disc_recv_msg(struct sk_buff *buf, struct tipc_bearer *b_ptr) } if (!tipc_in_scope(dest, tipc_own_addr)) return; - if (!in_own_cluster(orig)) + if (!tipc_in_scope(b_ptr->link_req->domain, orig)) return; /* Locate structure corresponding to requesting node */ @@ -287,7 +289,7 @@ static void disc_timeout(struct link_req *req) * tipc_disc_init_link_req - start sending periodic link setup requests * @b_ptr: ptr to bearer issuing requests * @dest: destination address for request messages - * @dest_domain: network domain of node(s) which should respond to message + * @dest_domain: network domain to which links can be established * * Returns pointer to link request structure, or NULL if unable to create. */ @@ -310,6 +312,7 @@ struct link_req *tipc_disc_init_link_req(struct tipc_bearer *b_ptr, memcpy(&req->dest, dest, sizeof(*dest)); req->bearer = b_ptr; + req->domain = dest_domain; req->timer_intv = TIPC_LINK_REQ_INIT; k_init_timer(&req->timer, (Handler)disc_timeout, (unsigned long)req); k_start_timer(&req->timer, req->timer_intv); -- cgit v0.10.2 From c29c3f70c9eb6f18090da5af9dbe9dcb4adece8c Mon Sep 17 00:00:00 2001 From: Allan Stephens Date: Tue, 20 Apr 2010 17:58:24 -0400 Subject: tipc: Abort excessive send requests as early as possible Adds checks to TIPC's socket send routines to promptly detect and abort attempts to send more than 66,000 bytes in a single TIPC message or more than 2**31-1 bytes in a single TIPC byte stream request. In addition, this ensures that the number of iovecs in a send request does not exceed the limits of a standard integer variable. Signed-off-by: Allan Stephens Signed-off-by: Paul Gortmaker diff --git a/include/linux/tipc.h b/include/linux/tipc.h index a5b994a..f2d9009 100644 --- a/include/linux/tipc.h +++ b/include/linux/tipc.h @@ -101,7 +101,7 @@ static inline unsigned int tipc_node(__u32 addr) * Limiting values for messages */ -#define TIPC_MAX_USER_MSG_SIZE 66000 +#define TIPC_MAX_USER_MSG_SIZE 66000U /* * Message importance levels diff --git a/net/tipc/socket.c b/net/tipc/socket.c index 29d94d5..e1c7917 100644 --- a/net/tipc/socket.c +++ b/net/tipc/socket.c @@ -535,6 +535,9 @@ static int send_msg(struct kiocb *iocb, struct socket *sock, if (unlikely((m->msg_namelen < sizeof(*dest)) || (dest->family != AF_TIPC))) return -EINVAL; + if ((total_len > TIPC_MAX_USER_MSG_SIZE) || + (m->msg_iovlen > (unsigned)INT_MAX)) + return -EMSGSIZE; if (iocb) lock_sock(sk); @@ -640,6 +643,10 @@ static int send_packet(struct kiocb *iocb, struct socket *sock, if (unlikely(dest)) return send_msg(iocb, sock, m, total_len); + if ((total_len > TIPC_MAX_USER_MSG_SIZE) || + (m->msg_iovlen > (unsigned)INT_MAX)) + return -EMSGSIZE; + if (iocb) lock_sock(sk); @@ -723,6 +730,12 @@ static int send_stream(struct kiocb *iocb, struct socket *sock, goto exit; } + if ((total_len > (unsigned)INT_MAX) || + (m->msg_iovlen > (unsigned)INT_MAX)) { + res = -EMSGSIZE; + goto exit; + } + /* * Send each iovec entry using one or more messages * -- cgit v0.10.2 From 2689690469c9fd76f9db0afcdf2523f48cce4006 Mon Sep 17 00:00:00 2001 From: Allan Stephens Date: Thu, 21 Apr 2011 10:42:07 -0500 Subject: tipc: Avoid recomputation of outgoing message length Rework TIPC's message sending routines to take advantage of the total amount of data value passed to it by the kernel socket infrastructure. This change eliminates the need for TIPC to compute the size of outgoing messages itself, as well as the check for an oversize message in tipc_msg_build(). In addition, this change warrants an explanation: - res = send_packet(NULL, sock, &my_msg, 0); + res = send_packet(NULL, sock, &my_msg, bytes_to_send); Previously, the final argument to send_packet() was ignored (since the amount of data being sent was recalculated by a lower-level routine) and we could just pass in a dummy value (0). Now that the recalculation is being eliminated, the argument value being passed to send_packet() is significant and we have to supply the actual amount of data we want to send. Signed-off-by: Allan Stephens Signed-off-by: Paul Gortmaker diff --git a/net/tipc/link.c b/net/tipc/link.c index 2a9f44a..4bab139 100644 --- a/net/tipc/link.c +++ b/net/tipc/link.c @@ -92,7 +92,8 @@ static int link_recv_changeover_msg(struct link **l_ptr, struct sk_buff **buf); static void link_set_supervision_props(struct link *l_ptr, u32 tolerance); static int link_send_sections_long(struct tipc_port *sender, struct iovec const *msg_sect, - u32 num_sect, u32 destnode); + u32 num_sect, unsigned int total_len, + u32 destnode); static void link_check_defragm_bufs(struct link *l_ptr); static void link_state_event(struct link *l_ptr, u32 event); static void link_reset_statistics(struct link *l_ptr); @@ -1043,6 +1044,7 @@ int tipc_send_buf_fast(struct sk_buff *buf, u32 destnode) int tipc_link_send_sections_fast(struct tipc_port *sender, struct iovec const *msg_sect, const u32 num_sect, + unsigned int total_len, u32 destaddr) { struct tipc_msg *hdr = &sender->phdr; @@ -1058,8 +1060,8 @@ again: * (Must not hold any locks while building message.) */ - res = tipc_msg_build(hdr, msg_sect, num_sect, sender->max_pkt, - !sender->user_port, &buf); + res = tipc_msg_build(hdr, msg_sect, num_sect, total_len, + sender->max_pkt, !sender->user_port, &buf); read_lock_bh(&tipc_net_lock); node = tipc_node_find(destaddr); @@ -1104,7 +1106,8 @@ exit: goto again; return link_send_sections_long(sender, msg_sect, - num_sect, destaddr); + num_sect, total_len, + destaddr); } tipc_node_unlock(node); } @@ -1116,7 +1119,7 @@ exit: return tipc_reject_msg(buf, TIPC_ERR_NO_NODE); if (res >= 0) return tipc_port_reject_sections(sender, hdr, msg_sect, num_sect, - TIPC_ERR_NO_NODE); + total_len, TIPC_ERR_NO_NODE); return res; } @@ -1137,12 +1140,13 @@ exit: static int link_send_sections_long(struct tipc_port *sender, struct iovec const *msg_sect, u32 num_sect, + unsigned int total_len, u32 destaddr) { struct link *l_ptr; struct tipc_node *node; struct tipc_msg *hdr = &sender->phdr; - u32 dsz = msg_data_sz(hdr); + u32 dsz = total_len; u32 max_pkt, fragm_sz, rest; struct tipc_msg fragm_hdr; struct sk_buff *buf, *buf_chain, *prev; @@ -1269,7 +1273,7 @@ reject: buf_discard(buf_chain); } return tipc_port_reject_sections(sender, hdr, msg_sect, num_sect, - TIPC_ERR_NO_NODE); + total_len, TIPC_ERR_NO_NODE); } /* Append whole chain to send queue: */ diff --git a/net/tipc/link.h b/net/tipc/link.h index e6a30db..74fbeca 100644 --- a/net/tipc/link.h +++ b/net/tipc/link.h @@ -228,6 +228,7 @@ u32 tipc_link_get_max_pkt(u32 dest, u32 selector); int tipc_link_send_sections_fast(struct tipc_port *sender, struct iovec const *msg_sect, const u32 num_sect, + unsigned int total_len, u32 destnode); void tipc_link_recv_bundle(struct sk_buff *buf); int tipc_link_recv_fragment(struct sk_buff **pending, diff --git a/net/tipc/msg.c b/net/tipc/msg.c index 6d92d17..03e57bf 100644 --- a/net/tipc/msg.c +++ b/net/tipc/msg.c @@ -68,20 +68,6 @@ void tipc_msg_init(struct tipc_msg *m, u32 user, u32 type, } /** - * tipc_msg_calc_data_size - determine total data size for message - */ - -int tipc_msg_calc_data_size(struct iovec const *msg_sect, u32 num_sect) -{ - int dsz = 0; - int i; - - for (i = 0; i < num_sect; i++) - dsz += msg_sect[i].iov_len; - return dsz; -} - -/** * tipc_msg_build - create message using specified header and data * * Note: Caller must not hold any locks in case copy_from_user() is interrupted! @@ -89,18 +75,13 @@ int tipc_msg_calc_data_size(struct iovec const *msg_sect, u32 num_sect) * Returns message data size or errno */ -int tipc_msg_build(struct tipc_msg *hdr, - struct iovec const *msg_sect, u32 num_sect, +int tipc_msg_build(struct tipc_msg *hdr, struct iovec const *msg_sect, + u32 num_sect, unsigned int total_len, int max_size, int usrmem, struct sk_buff **buf) { int dsz, sz, hsz, pos, res, cnt; - dsz = tipc_msg_calc_data_size(msg_sect, num_sect); - if (unlikely(dsz > TIPC_MAX_USER_MSG_SIZE)) { - *buf = NULL; - return -EINVAL; - } - + dsz = total_len; pos = hsz = msg_hdr_sz(hdr); sz = hsz + dsz; msg_set_size(hdr, sz); diff --git a/net/tipc/msg.h b/net/tipc/msg.h index 005b318..8452454 100644 --- a/net/tipc/msg.h +++ b/net/tipc/msg.h @@ -750,9 +750,8 @@ static inline void msg_set_link_tolerance(struct tipc_msg *m, u32 n) u32 tipc_msg_tot_importance(struct tipc_msg *m); void tipc_msg_init(struct tipc_msg *m, u32 user, u32 type, u32 hsize, u32 destnode); -int tipc_msg_calc_data_size(struct iovec const *msg_sect, u32 num_sect); -int tipc_msg_build(struct tipc_msg *hdr, - struct iovec const *msg_sect, u32 num_sect, +int tipc_msg_build(struct tipc_msg *hdr, struct iovec const *msg_sect, + u32 num_sect, unsigned int total_len, int max_size, int usrmem, struct sk_buff **buf); static inline void msg_set_media_addr(struct tipc_msg *m, struct tipc_media_addr *a) diff --git a/net/tipc/port.c b/net/tipc/port.c index 9f2ff12..c68dc95 100644 --- a/net/tipc/port.c +++ b/net/tipc/port.c @@ -74,7 +74,8 @@ static u32 port_peerport(struct tipc_port *p_ptr) */ int tipc_multicast(u32 ref, struct tipc_name_seq const *seq, - u32 num_sect, struct iovec const *msg_sect) + u32 num_sect, struct iovec const *msg_sect, + unsigned int total_len) { struct tipc_msg *hdr; struct sk_buff *buf; @@ -98,7 +99,7 @@ int tipc_multicast(u32 ref, struct tipc_name_seq const *seq, msg_set_namelower(hdr, seq->lower); msg_set_nameupper(hdr, seq->upper); msg_set_hdr_sz(hdr, MCAST_H_SIZE); - res = tipc_msg_build(hdr, msg_sect, num_sect, MAX_MSG_SIZE, + res = tipc_msg_build(hdr, msg_sect, num_sect, total_len, MAX_MSG_SIZE, !oport->user_port, &buf); if (unlikely(!buf)) return res; @@ -418,12 +419,12 @@ int tipc_reject_msg(struct sk_buff *buf, u32 err) int tipc_port_reject_sections(struct tipc_port *p_ptr, struct tipc_msg *hdr, struct iovec const *msg_sect, u32 num_sect, - int err) + unsigned int total_len, int err) { struct sk_buff *buf; int res; - res = tipc_msg_build(hdr, msg_sect, num_sect, MAX_MSG_SIZE, + res = tipc_msg_build(hdr, msg_sect, num_sect, total_len, MAX_MSG_SIZE, !p_ptr->user_port, &buf); if (!buf) return res; @@ -1163,12 +1164,13 @@ int tipc_shutdown(u32 ref) */ static int tipc_port_recv_sections(struct tipc_port *sender, unsigned int num_sect, - struct iovec const *msg_sect) + struct iovec const *msg_sect, + unsigned int total_len) { struct sk_buff *buf; int res; - res = tipc_msg_build(&sender->phdr, msg_sect, num_sect, + res = tipc_msg_build(&sender->phdr, msg_sect, num_sect, total_len, MAX_MSG_SIZE, !sender->user_port, &buf); if (likely(buf)) tipc_port_recv_msg(buf); @@ -1179,7 +1181,8 @@ static int tipc_port_recv_sections(struct tipc_port *sender, unsigned int num_se * tipc_send - send message sections on connection */ -int tipc_send(u32 ref, unsigned int num_sect, struct iovec const *msg_sect) +int tipc_send(u32 ref, unsigned int num_sect, struct iovec const *msg_sect, + unsigned int total_len) { struct tipc_port *p_ptr; u32 destnode; @@ -1194,9 +1197,10 @@ int tipc_send(u32 ref, unsigned int num_sect, struct iovec const *msg_sect) destnode = port_peernode(p_ptr); if (likely(destnode != tipc_own_addr)) res = tipc_link_send_sections_fast(p_ptr, msg_sect, num_sect, - destnode); + total_len, destnode); else - res = tipc_port_recv_sections(p_ptr, num_sect, msg_sect); + res = tipc_port_recv_sections(p_ptr, num_sect, msg_sect, + total_len); if (likely(res != -ELINKCONG)) { p_ptr->congested = 0; @@ -1207,8 +1211,7 @@ int tipc_send(u32 ref, unsigned int num_sect, struct iovec const *msg_sect) } if (port_unreliable(p_ptr)) { p_ptr->congested = 0; - /* Just calculate msg length and return */ - return tipc_msg_calc_data_size(msg_sect, num_sect); + return total_len; } return -ELINKCONG; } @@ -1218,7 +1221,8 @@ int tipc_send(u32 ref, unsigned int num_sect, struct iovec const *msg_sect) */ int tipc_send2name(u32 ref, struct tipc_name const *name, unsigned int domain, - unsigned int num_sect, struct iovec const *msg_sect) + unsigned int num_sect, struct iovec const *msg_sect, + unsigned int total_len) { struct tipc_port *p_ptr; struct tipc_msg *msg; @@ -1245,23 +1249,23 @@ int tipc_send2name(u32 ref, struct tipc_name const *name, unsigned int domain, if (likely(destport)) { if (likely(destnode == tipc_own_addr)) res = tipc_port_recv_sections(p_ptr, num_sect, - msg_sect); + msg_sect, total_len); else res = tipc_link_send_sections_fast(p_ptr, msg_sect, - num_sect, destnode); + num_sect, total_len, + destnode); if (likely(res != -ELINKCONG)) { if (res > 0) p_ptr->sent++; return res; } if (port_unreliable(p_ptr)) { - /* Just calculate msg length and return */ - return tipc_msg_calc_data_size(msg_sect, num_sect); + return total_len; } return -ELINKCONG; } return tipc_port_reject_sections(p_ptr, msg, msg_sect, num_sect, - TIPC_ERR_NO_NAME); + total_len, TIPC_ERR_NO_NAME); } /** @@ -1269,7 +1273,8 @@ int tipc_send2name(u32 ref, struct tipc_name const *name, unsigned int domain, */ int tipc_send2port(u32 ref, struct tipc_portid const *dest, - unsigned int num_sect, struct iovec const *msg_sect) + unsigned int num_sect, struct iovec const *msg_sect, + unsigned int total_len) { struct tipc_port *p_ptr; struct tipc_msg *msg; @@ -1289,18 +1294,18 @@ int tipc_send2port(u32 ref, struct tipc_portid const *dest, msg_set_hdr_sz(msg, DIR_MSG_H_SIZE); if (dest->node == tipc_own_addr) - res = tipc_port_recv_sections(p_ptr, num_sect, msg_sect); + res = tipc_port_recv_sections(p_ptr, num_sect, msg_sect, + total_len); else res = tipc_link_send_sections_fast(p_ptr, msg_sect, num_sect, - dest->node); + total_len, dest->node); if (likely(res != -ELINKCONG)) { if (res > 0) p_ptr->sent++; return res; } if (port_unreliable(p_ptr)) { - /* Just calculate msg length and return */ - return tipc_msg_calc_data_size(msg_sect, num_sect); + return total_len; } return -ELINKCONG; } diff --git a/net/tipc/port.h b/net/tipc/port.h index 87b9424..b9aa341 100644 --- a/net/tipc/port.h +++ b/net/tipc/port.h @@ -205,23 +205,27 @@ int tipc_disconnect_port(struct tipc_port *tp_ptr); /* * TIPC messaging routines */ -int tipc_send(u32 portref, unsigned int num_sect, struct iovec const *msg_sect); +int tipc_send(u32 portref, unsigned int num_sect, struct iovec const *msg_sect, + unsigned int total_len); int tipc_send2name(u32 portref, struct tipc_name const *name, u32 domain, - unsigned int num_sect, struct iovec const *msg_sect); + unsigned int num_sect, struct iovec const *msg_sect, + unsigned int total_len); int tipc_send2port(u32 portref, struct tipc_portid const *dest, - unsigned int num_sect, struct iovec const *msg_sect); + unsigned int num_sect, struct iovec const *msg_sect, + unsigned int total_len); int tipc_send_buf2port(u32 portref, struct tipc_portid const *dest, struct sk_buff *buf, unsigned int dsz); int tipc_multicast(u32 portref, struct tipc_name_seq const *seq, - unsigned int section_count, struct iovec const *msg); + unsigned int section_count, struct iovec const *msg, + unsigned int total_len); int tipc_port_reject_sections(struct tipc_port *p_ptr, struct tipc_msg *hdr, struct iovec const *msg_sect, u32 num_sect, - int err); + unsigned int total_len, int err); struct sk_buff *tipc_port_get_ports(void); void tipc_port_recv_proto_msg(struct sk_buff *buf); void tipc_port_recv_mcast(struct sk_buff *buf, struct port_list *dp); diff --git a/net/tipc/socket.c b/net/tipc/socket.c index e1c7917..3388373 100644 --- a/net/tipc/socket.c +++ b/net/tipc/socket.c @@ -576,12 +576,14 @@ static int send_msg(struct kiocb *iocb, struct socket *sock, &dest->addr.name.name, dest->addr.name.domain, m->msg_iovlen, - m->msg_iov); + m->msg_iov, + total_len); } else if (dest->addrtype == TIPC_ADDR_ID) { res = tipc_send2port(tport->ref, &dest->addr.id, m->msg_iovlen, - m->msg_iov); + m->msg_iov, + total_len); } else if (dest->addrtype == TIPC_ADDR_MCAST) { if (needs_conn) { res = -EOPNOTSUPP; @@ -593,7 +595,8 @@ static int send_msg(struct kiocb *iocb, struct socket *sock, res = tipc_multicast(tport->ref, &dest->addr.nameseq, m->msg_iovlen, - m->msg_iov); + m->msg_iov, + total_len); } if (likely(res != -ELINKCONG)) { if (needs_conn && (res >= 0)) @@ -659,7 +662,8 @@ static int send_packet(struct kiocb *iocb, struct socket *sock, break; } - res = tipc_send(tport->ref, m->msg_iovlen, m->msg_iov); + res = tipc_send(tport->ref, m->msg_iovlen, m->msg_iov, + total_len); if (likely(res != -ELINKCONG)) break; if (m->msg_flags & MSG_DONTWAIT) { @@ -766,7 +770,7 @@ static int send_stream(struct kiocb *iocb, struct socket *sock, bytes_to_send = curr_left; my_iov.iov_base = curr_start; my_iov.iov_len = bytes_to_send; - res = send_packet(NULL, sock, &my_msg, 0); + res = send_packet(NULL, sock, &my_msg, bytes_to_send); if (res < 0) { if (bytes_sent) res = bytes_sent; diff --git a/net/tipc/subscr.c b/net/tipc/subscr.c index aae9eae..6cf7268 100644 --- a/net/tipc/subscr.c +++ b/net/tipc/subscr.c @@ -109,7 +109,7 @@ static void subscr_send_event(struct subscription *sub, sub->evt.found_upper = htohl(found_upper, sub->swap); sub->evt.port.ref = htohl(port_ref, sub->swap); sub->evt.port.node = htohl(node, sub->swap); - tipc_send(sub->server_ref, 1, &msg_sect); + tipc_send(sub->server_ref, 1, &msg_sect, msg_sect.iov_len); } /** @@ -521,7 +521,7 @@ static void subscr_named_msg_event(void *usr_handle, /* Send an ACK- to complete connection handshaking */ - tipc_send(server_port_ref, 0, NULL); + tipc_send(server_port_ref, 0, NULL, 0); /* Handle optional subscription request */ -- cgit v0.10.2 From dc63d91eb1cf74233c68b0058dcd477f5d019d02 Mon Sep 17 00:00:00 2001 From: Allan Stephens Date: Thu, 21 Apr 2011 11:50:42 -0400 Subject: tipc: Introduce routine to enqueue a chain of messages on link tx queue Create a helper routine to enqueue a chain of sk_buffs to a link's transmit queue. It improves readability and the new function is anticipated to be used more than just once in the future as well. Signed-off-by: Allan Stephens Signed-off-by: Paul Gortmaker diff --git a/net/tipc/link.c b/net/tipc/link.c index 4bab139..5ed4b4f 100644 --- a/net/tipc/link.c +++ b/net/tipc/link.c @@ -843,6 +843,25 @@ static void link_add_to_outqueue(struct link *l_ptr, l_ptr->stats.max_queue_sz = l_ptr->out_queue_size; } +static void link_add_chain_to_outqueue(struct link *l_ptr, + struct sk_buff *buf_chain, + u32 long_msgno) +{ + struct sk_buff *buf; + struct tipc_msg *msg; + + if (!l_ptr->next_out) + l_ptr->next_out = buf_chain; + while (buf_chain) { + buf = buf_chain; + buf_chain = buf_chain->next; + + msg = buf_msg(buf); + msg_set_long_msgno(msg, long_msgno); + link_add_to_outqueue(l_ptr, buf, msg); + } +} + /* * tipc_link_send_buf() is the 'full path' for messages, called from * inside TIPC when the 'fast path' in tipc_send_buf @@ -1276,25 +1295,12 @@ reject: total_len, TIPC_ERR_NO_NODE); } - /* Append whole chain to send queue: */ + /* Append chain of fragments to send queue & send them */ - buf = buf_chain; l_ptr->long_msg_seq_no++; - if (!l_ptr->next_out) - l_ptr->next_out = buf_chain; + link_add_chain_to_outqueue(l_ptr, buf_chain, l_ptr->long_msg_seq_no); + l_ptr->stats.sent_fragments += fragm_no; l_ptr->stats.sent_fragmented++; - while (buf) { - struct sk_buff *next = buf->next; - struct tipc_msg *msg = buf_msg(buf); - - l_ptr->stats.sent_fragments++; - msg_set_long_msgno(msg, l_ptr->long_msg_seq_no); - link_add_to_outqueue(l_ptr, buf, msg); - buf = next; - } - - /* Send it, if possible: */ - tipc_link_push_queue(l_ptr); tipc_node_unlock(node); return dsz; -- cgit v0.10.2 From 3a777ff8b14456e15991c9fcc225943453dc3a75 Mon Sep 17 00:00:00 2001 From: Allan Stephens Date: Thu, 21 Apr 2011 13:58:26 -0500 Subject: tipc: Enhance handling of discovery object creation failures Modifies bearer creation and deletion code to improve handling of scenarios when a neighbor discovery object cannot be created. The creation routine now aborts the creation of a bearer if its discovery object cannot be created, and deletes the newly created bearer, rather than failing quietly and leaving an unusable bearer hanging around. Since the exit via the goto label really isn't a definitive failure in all cases, relabel it appropriately. Signed-off-by: Allan Stephens Signed-off-by: Paul Gortmaker diff --git a/net/tipc/bearer.c b/net/tipc/bearer.c index f7c29af..5fcd1c1 100644 --- a/net/tipc/bearer.c +++ b/net/tipc/bearer.c @@ -46,6 +46,8 @@ static u32 media_count; struct tipc_bearer tipc_bearers[MAX_BEARERS]; +static void bearer_disable(struct tipc_bearer *b_ptr); + /** * media_name_valid - validate media name * @@ -518,7 +520,7 @@ int tipc_enable_bearer(const char *name, u32 disc_domain, u32 priority) if (!m_ptr) { warn("Bearer <%s> rejected, media <%s> not registered\n", name, b_name.media_name); - goto failed; + goto exit; } if (priority == TIPC_MEDIA_LINK_PRI) @@ -534,14 +536,14 @@ restart: } if (!strcmp(name, tipc_bearers[i].name)) { warn("Bearer <%s> rejected, already enabled\n", name); - goto failed; + goto exit; } if ((tipc_bearers[i].priority == priority) && (++with_this_prio > 2)) { if (priority-- == 0) { warn("Bearer <%s> rejected, duplicate priority\n", name); - goto failed; + goto exit; } warn("Bearer <%s> priority adjustment required %u->%u\n", name, priority + 1, priority); @@ -551,7 +553,7 @@ restart: if (bearer_id >= MAX_BEARERS) { warn("Bearer <%s> rejected, bearer limit reached (%u)\n", name, MAX_BEARERS); - goto failed; + goto exit; } b_ptr = &tipc_bearers[bearer_id]; @@ -559,7 +561,7 @@ restart: res = m_ptr->enable_bearer(b_ptr); if (res) { warn("Bearer <%s> rejected, enable failure (%d)\n", name, -res); - goto failed; + goto exit; } b_ptr->identity = bearer_id; @@ -569,14 +571,18 @@ restart: b_ptr->priority = priority; INIT_LIST_HEAD(&b_ptr->cong_links); INIT_LIST_HEAD(&b_ptr->links); - b_ptr->link_req = tipc_disc_init_link_req(b_ptr, &m_ptr->bcast_addr, - disc_domain); spin_lock_init(&b_ptr->lock); - write_unlock_bh(&tipc_net_lock); + + res = tipc_disc_create(b_ptr, &m_ptr->bcast_addr, disc_domain); + if (res) { + bearer_disable(b_ptr); + warn("Bearer <%s> rejected, discovery object creation failed\n", + name); + goto exit; + } info("Enabled bearer <%s>, discovery domain %s, priority %u\n", name, tipc_addr_string_fill(addr_string, disc_domain), priority); - return 0; -failed: +exit: write_unlock_bh(&tipc_net_lock); return res; } @@ -627,14 +633,14 @@ static void bearer_disable(struct tipc_bearer *b_ptr) struct link *temp_l_ptr; info("Disabling bearer <%s>\n", b_ptr->name); - tipc_disc_stop_link_req(b_ptr->link_req); spin_lock_bh(&b_ptr->lock); - b_ptr->link_req = NULL; b_ptr->blocked = 1; b_ptr->media->disable_bearer(b_ptr); list_for_each_entry_safe(l_ptr, temp_l_ptr, &b_ptr->links, link_list) { tipc_link_delete(l_ptr); } + if (b_ptr->link_req) + tipc_disc_delete(b_ptr->link_req); spin_unlock_bh(&b_ptr->lock); memset(b_ptr, 0, sizeof(struct tipc_bearer)); } diff --git a/net/tipc/discover.c b/net/tipc/discover.c index d2163bd..6acf32a 100644 --- a/net/tipc/discover.c +++ b/net/tipc/discover.c @@ -216,22 +216,6 @@ void tipc_disc_recv_msg(struct sk_buff *buf, struct tipc_bearer *b_ptr) } /** - * tipc_disc_stop_link_req - stop sending periodic link setup requests - * @req: ptr to link request structure - */ - -void tipc_disc_stop_link_req(struct link_req *req) -{ - if (!req) - return; - - k_cancel_timer(&req->timer); - k_term_timer(&req->timer); - buf_discard(req->buf); - kfree(req); -} - -/** * tipc_disc_update_link_req - update frequency of periodic link setup requests * @req: ptr to link request structure */ @@ -286,28 +270,27 @@ static void disc_timeout(struct link_req *req) } /** - * tipc_disc_init_link_req - start sending periodic link setup requests + * tipc_disc_create - create object to send periodic link setup requests * @b_ptr: ptr to bearer issuing requests * @dest: destination address for request messages * @dest_domain: network domain to which links can be established * - * Returns pointer to link request structure, or NULL if unable to create. + * Returns 0 if successful, otherwise -errno. */ -struct link_req *tipc_disc_init_link_req(struct tipc_bearer *b_ptr, - const struct tipc_media_addr *dest, - u32 dest_domain) +int tipc_disc_create(struct tipc_bearer *b_ptr, + struct tipc_media_addr *dest, u32 dest_domain) { struct link_req *req; req = kmalloc(sizeof(*req), GFP_ATOMIC); if (!req) - return NULL; + return -ENOMEM; req->buf = tipc_disc_init_msg(DSC_REQ_MSG, dest_domain, b_ptr); if (!req->buf) { kfree(req); - return NULL; + return -ENOMSG; } memcpy(&req->dest, dest, sizeof(*dest)); @@ -316,6 +299,20 @@ struct link_req *tipc_disc_init_link_req(struct tipc_bearer *b_ptr, req->timer_intv = TIPC_LINK_REQ_INIT; k_init_timer(&req->timer, (Handler)disc_timeout, (unsigned long)req); k_start_timer(&req->timer, req->timer_intv); - return req; + b_ptr->link_req = req; + return 0; +} + +/** + * tipc_disc_delete - destroy object sending periodic link setup requests + * @req: ptr to link request structure + */ + +void tipc_disc_delete(struct link_req *req) +{ + k_cancel_timer(&req->timer); + k_term_timer(&req->timer); + buf_discard(req->buf); + kfree(req); } diff --git a/net/tipc/discover.h b/net/tipc/discover.h index e48a167..d6e44e3 100644 --- a/net/tipc/discover.h +++ b/net/tipc/discover.h @@ -39,12 +39,10 @@ struct link_req; -struct link_req *tipc_disc_init_link_req(struct tipc_bearer *b_ptr, - const struct tipc_media_addr *dest, - u32 dest_domain); +int tipc_disc_create(struct tipc_bearer *b_ptr, struct tipc_media_addr *dest, + u32 dest_domain); +void tipc_disc_delete(struct link_req *req); void tipc_disc_update_link_req(struct link_req *req); -void tipc_disc_stop_link_req(struct link_req *req); - void tipc_disc_recv_msg(struct sk_buff *buf, struct tipc_bearer *b_ptr); #endif -- cgit v0.10.2 From 691a62075922b43b2b03def87ebcfdfbf0cd2ed8 Mon Sep 17 00:00:00 2001 From: Allan Stephens Date: Thu, 21 Apr 2011 16:28:02 -0500 Subject: tipc: Enhance sending of discovery object link request messages Augments TIPC's discovery object to send its initial neighbor discovery request message as soon as the associated bearer is created, rather than waiting for its first periodic timeout to occur, thereby speeding up the discovery process. Also adds a check to suppress the initial request or subsequent requests if the bearer is blocked at the time the request is scheduled for transmission. Signed-off-by: Allan Stephens Signed-off-by: Paul Gortmaker diff --git a/net/tipc/discover.c b/net/tipc/discover.c index 6acf32a..dba4767 100644 --- a/net/tipc/discover.c +++ b/net/tipc/discover.c @@ -241,6 +241,17 @@ void tipc_disc_update_link_req(struct link_req *req) } /** + * disc_send_msg - send link setup request message + * @req: ptr to link request structure + */ + +static void disc_send_msg(struct link_req *req) +{ + if (!req->bearer->blocked) + tipc_bearer_send(req->bearer, req->buf, &req->dest); +} + +/** * disc_timeout - send a periodic link setup request * @req: ptr to link request structure * @@ -251,7 +262,7 @@ static void disc_timeout(struct link_req *req) { spin_lock_bh(&req->bearer->lock); - req->bearer->media->send_msg(req->buf, req->bearer, &req->dest); + disc_send_msg(req); if ((req->timer_intv == TIPC_LINK_REQ_SLOW) || (req->timer_intv == TIPC_LINK_REQ_FAST)) { @@ -300,6 +311,7 @@ int tipc_disc_create(struct tipc_bearer *b_ptr, k_init_timer(&req->timer, (Handler)disc_timeout, (unsigned long)req); k_start_timer(&req->timer, req->timer_intv); b_ptr->link_req = req; + disc_send_msg(req); return 0; } -- cgit v0.10.2 From 1209966cd5d2ec7f89ad2ed58a6a342aa8ea8712 Mon Sep 17 00:00:00 2001 From: Allan Stephens Date: Thu, 21 Apr 2011 19:05:25 -0500 Subject: tipc: Add monitoring of number of nodes discovered by bearer Augments TIPC's discovery object to track the number of neighboring nodes having an active link to the associated bearer. This means tipc_disc_update_link_req() becomes either one of: tipc_disc_add_dest() or: tipc_disc_remove_dest() depending on the code flow direction of things. Signed-off-by: Allan Stephens Signed-off-by: Paul Gortmaker diff --git a/net/tipc/bearer.c b/net/tipc/bearer.c index 5fcd1c1..85209ea 100644 --- a/net/tipc/bearer.c +++ b/net/tipc/bearer.c @@ -344,15 +344,15 @@ struct sk_buff *tipc_bearer_get_names(void) void tipc_bearer_add_dest(struct tipc_bearer *b_ptr, u32 dest) { tipc_nmap_add(&b_ptr->nodes, dest); - tipc_disc_update_link_req(b_ptr->link_req); tipc_bcbearer_sort(); + tipc_disc_add_dest(b_ptr->link_req); } void tipc_bearer_remove_dest(struct tipc_bearer *b_ptr, u32 dest) { tipc_nmap_remove(&b_ptr->nodes, dest); - tipc_disc_update_link_req(b_ptr->link_req); tipc_bcbearer_sort(); + tipc_disc_remove_dest(b_ptr->link_req); } /* diff --git a/net/tipc/discover.c b/net/tipc/discover.c index dba4767..3cb232d 100644 --- a/net/tipc/discover.c +++ b/net/tipc/discover.c @@ -53,6 +53,7 @@ * @bearer: bearer issuing requests * @dest: destination address for request messages * @domain: network domain to which links can be established + * @num_nodes: number of nodes currently discovered (i.e. with an active link) * @buf: request message to be (repeatedly) sent * @timer: timer governing period between requests * @timer_intv: current interval between requests (in ms) @@ -61,6 +62,7 @@ struct link_req { struct tipc_bearer *bearer; struct tipc_media_addr dest; u32 domain; + int num_nodes; struct sk_buff *buf; struct timer_list timer; unsigned int timer_intv; @@ -216,15 +218,12 @@ void tipc_disc_recv_msg(struct sk_buff *buf, struct tipc_bearer *b_ptr) } /** - * tipc_disc_update_link_req - update frequency of periodic link setup requests + * disc_update - update frequency of periodic link setup requests * @req: ptr to link request structure */ -void tipc_disc_update_link_req(struct link_req *req) +static void disc_update(struct link_req *req) { - if (!req) - return; - if (req->timer_intv == TIPC_LINK_REQ_SLOW) { if (!req->bearer->nodes.count) { req->timer_intv = TIPC_LINK_REQ_FAST; @@ -241,6 +240,28 @@ void tipc_disc_update_link_req(struct link_req *req) } /** + * tipc_disc_add_dest - increment set of discovered nodes + * @req: ptr to link request structure + */ + +void tipc_disc_add_dest(struct link_req *req) +{ + req->num_nodes++; + disc_update(req); +} + +/** + * tipc_disc_remove_dest - decrement set of discovered nodes + * @req: ptr to link request structure + */ + +void tipc_disc_remove_dest(struct link_req *req) +{ + req->num_nodes--; + disc_update(req); +} + +/** * disc_send_msg - send link setup request message * @req: ptr to link request structure */ @@ -307,6 +328,7 @@ int tipc_disc_create(struct tipc_bearer *b_ptr, memcpy(&req->dest, dest, sizeof(*dest)); req->bearer = b_ptr; req->domain = dest_domain; + req->num_nodes = 0; req->timer_intv = TIPC_LINK_REQ_INIT; k_init_timer(&req->timer, (Handler)disc_timeout, (unsigned long)req); k_start_timer(&req->timer, req->timer_intv); diff --git a/net/tipc/discover.h b/net/tipc/discover.h index d6e44e3..a3af595 100644 --- a/net/tipc/discover.h +++ b/net/tipc/discover.h @@ -42,7 +42,8 @@ struct link_req; int tipc_disc_create(struct tipc_bearer *b_ptr, struct tipc_media_addr *dest, u32 dest_domain); void tipc_disc_delete(struct link_req *req); -void tipc_disc_update_link_req(struct link_req *req); +void tipc_disc_add_dest(struct link_req *req); +void tipc_disc_remove_dest(struct link_req *req); void tipc_disc_recv_msg(struct sk_buff *buf, struct tipc_bearer *b_ptr); #endif -- cgit v0.10.2 From 972a77fbf1bbea6f54b5986b05041a17b607695b Mon Sep 17 00:00:00 2001 From: Allan Stephens Date: Thu, 21 Apr 2011 20:34:03 -0500 Subject: tipc: Revise timings used when sending link request messages Revises the algorithm governing the sending of link request messages to take into account the number of nodes each bearer is currently in contact with, and to ensure more rapid rediscovery of neighboring nodes if a bearer fails and then recovers. The discovery object now sends requests at least once a second if it is not in contact with any other nodes, and at least once a minute if it has at least one neighbor; if contact with the only neighbor is lost, the object immediately reverts to its initial rapid-fire search timing to accelerate the rediscovery process. In addition, the discovery object now stops issuing link request messages if it is in contact with the only neighboring node it is configured to communicate with, since further searching is unnecessary. Signed-off-by: Allan Stephens Signed-off-by: Paul Gortmaker diff --git a/net/tipc/discover.c b/net/tipc/discover.c index 3cb232d..0987933 100644 --- a/net/tipc/discover.c +++ b/net/tipc/discover.c @@ -39,13 +39,9 @@ #include "discover.h" #define TIPC_LINK_REQ_INIT 125 /* min delay during bearer start up */ -#define TIPC_LINK_REQ_FAST 2000 /* normal delay if bearer has no links */ -#define TIPC_LINK_REQ_SLOW 600000 /* normal delay if bearer has links */ - -/* - * TODO: Most of the inter-cluster setup stuff should be - * rewritten, and be made conformant with specification. - */ +#define TIPC_LINK_REQ_FAST 1000 /* max delay if bearer has no links */ +#define TIPC_LINK_REQ_SLOW 60000 /* max delay if bearer has links */ +#define TIPC_LINK_REQ_INACTIVE 0xffffffff /* indicates no timer in use */ /** @@ -220,22 +216,19 @@ void tipc_disc_recv_msg(struct sk_buff *buf, struct tipc_bearer *b_ptr) /** * disc_update - update frequency of periodic link setup requests * @req: ptr to link request structure + * + * Reinitiates discovery process if discovery object has no associated nodes + * and is either not currently searching or is searching at a slow rate */ static void disc_update(struct link_req *req) { - if (req->timer_intv == TIPC_LINK_REQ_SLOW) { - if (!req->bearer->nodes.count) { - req->timer_intv = TIPC_LINK_REQ_FAST; + if (!req->num_nodes) { + if ((req->timer_intv == TIPC_LINK_REQ_INACTIVE) || + (req->timer_intv > TIPC_LINK_REQ_FAST)) { + req->timer_intv = TIPC_LINK_REQ_INIT; k_start_timer(&req->timer, req->timer_intv); } - } else if (req->timer_intv == TIPC_LINK_REQ_FAST) { - if (req->bearer->nodes.count) { - req->timer_intv = TIPC_LINK_REQ_SLOW; - k_start_timer(&req->timer, req->timer_intv); - } - } else { - /* leave timer "as is" if haven't yet reached a "normal" rate */ } } @@ -247,7 +240,6 @@ static void disc_update(struct link_req *req) void tipc_disc_add_dest(struct link_req *req) { req->num_nodes++; - disc_update(req); } /** @@ -281,23 +273,37 @@ static void disc_send_msg(struct link_req *req) static void disc_timeout(struct link_req *req) { + int max_delay; + spin_lock_bh(&req->bearer->lock); - disc_send_msg(req); + /* Stop searching if only desired node has been found */ - if ((req->timer_intv == TIPC_LINK_REQ_SLOW) || - (req->timer_intv == TIPC_LINK_REQ_FAST)) { - /* leave timer interval "as is" if already at a "normal" rate */ - } else { - req->timer_intv *= 2; - if (req->timer_intv > TIPC_LINK_REQ_FAST) - req->timer_intv = TIPC_LINK_REQ_FAST; - if ((req->timer_intv == TIPC_LINK_REQ_FAST) && - (req->bearer->nodes.count)) - req->timer_intv = TIPC_LINK_REQ_SLOW; + if (tipc_node(req->domain) && req->num_nodes) { + req->timer_intv = TIPC_LINK_REQ_INACTIVE; + goto exit; } - k_start_timer(&req->timer, req->timer_intv); + /* + * Send discovery message, then update discovery timer + * + * Keep doubling time between requests until limit is reached; + * hold at fast polling rate if don't have any associated nodes, + * otherwise hold at slow polling rate + */ + + disc_send_msg(req); + + req->timer_intv *= 2; + if (req->num_nodes) + max_delay = TIPC_LINK_REQ_SLOW; + else + max_delay = TIPC_LINK_REQ_FAST; + if (req->timer_intv > max_delay) + req->timer_intv = max_delay; + + k_start_timer(&req->timer, req->timer_intv); +exit: spin_unlock_bh(&req->bearer->lock); } -- cgit v0.10.2 From 0a5ebb8000c5362be368df9d197943deb06b6916 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Mon, 9 May 2011 13:22:43 -0700 Subject: ipv4: Pass explicit daddr arg to ip_send_reply(). This eliminates an access to rt->rt_src. Signed-off-by: David S. Miller diff --git a/include/net/ip.h b/include/net/ip.h index 0b30d3a..66dd491 100644 --- a/include/net/ip.h +++ b/include/net/ip.h @@ -174,8 +174,8 @@ static inline __u8 ip_reply_arg_flowi_flags(const struct ip_reply_arg *arg) return (arg->flags & IP_REPLY_ARG_NOSRCCHECK) ? FLOWI_FLAG_ANYSRC : 0; } -void ip_send_reply(struct sock *sk, struct sk_buff *skb, struct ip_reply_arg *arg, - unsigned int len); +void ip_send_reply(struct sock *sk, struct sk_buff *skb, __be32 daddr, + struct ip_reply_arg *arg, unsigned int len); struct ipv4_config { int log_martians; diff --git a/net/ipv4/ip_output.c b/net/ipv4/ip_output.c index cd89d22..70778d4 100644 --- a/net/ipv4/ip_output.c +++ b/net/ipv4/ip_output.c @@ -1459,20 +1459,19 @@ static int ip_reply_glue_bits(void *dptr, char *to, int offset, * Should run single threaded per socket because it uses the sock * structure to pass arguments. */ -void ip_send_reply(struct sock *sk, struct sk_buff *skb, struct ip_reply_arg *arg, - unsigned int len) +void ip_send_reply(struct sock *sk, struct sk_buff *skb, __be32 daddr, + struct ip_reply_arg *arg, unsigned int len) { struct inet_sock *inet = inet_sk(sk); struct ip_options_data replyopts; struct ipcm_cookie ipc; struct flowi4 fl4; - __be32 daddr; struct rtable *rt = skb_rtable(skb); if (ip_options_echo(&replyopts.opt.opt, skb)) return; - daddr = ipc.addr = rt->rt_src; + ipc.addr = daddr; ipc.opt = NULL; ipc.tx_flags = 0; diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c index 2b65503..f67fb34 100644 --- a/net/ipv4/tcp_ipv4.c +++ b/net/ipv4/tcp_ipv4.c @@ -651,7 +651,7 @@ static void tcp_v4_send_reset(struct sock *sk, struct sk_buff *skb) arg.flags = (sk && inet_sk(sk)->transparent) ? IP_REPLY_ARG_NOSRCCHECK : 0; net = dev_net(skb_dst(skb)->dev); - ip_send_reply(net->ipv4.tcp_sock, skb, + ip_send_reply(net->ipv4.tcp_sock, skb, ip_hdr(skb)->saddr, &arg, arg.iov[0].iov_len); TCP_INC_STATS_BH(net, TCP_MIB_OUTSEGS); @@ -726,7 +726,7 @@ static void tcp_v4_send_ack(struct sk_buff *skb, u32 seq, u32 ack, if (oif) arg.bound_dev_if = oif; - ip_send_reply(net->ipv4.tcp_sock, skb, + ip_send_reply(net->ipv4.tcp_sock, skb, ip_hdr(skb)->saddr, &arg, arg.iov[0].iov_len); TCP_INC_STATS_BH(net, TCP_MIB_OUTSEGS); -- cgit v0.10.2 From 9f6abb5f175bdb9ecfd390000a631bf0abf2fedb Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Mon, 9 May 2011 13:28:22 -0700 Subject: ipv4: icmp: Eliminate remaining uses of rt->rt_src On input packets, rt->rt_src always equals ip_hdr(skb)->saddr Anything that mangles or otherwise changes the IP header must relookup the route found at skb_rtable(). Therefore this invariant must always hold true. Signed-off-by: David S. Miller diff --git a/net/ipv4/icmp.c b/net/ipv4/icmp.c index 853a670..3314394 100644 --- a/net/ipv4/icmp.c +++ b/net/ipv4/icmp.c @@ -345,7 +345,7 @@ static void icmp_reply(struct icmp_bxm *icmp_param, struct sk_buff *skb) icmp_param->data.icmph.checksum = 0; inet->tos = ip_hdr(skb)->tos; - daddr = ipc.addr = rt->rt_src; + daddr = ipc.addr = ip_hdr(skb)->saddr; ipc.opt = NULL; ipc.tx_flags = 0; if (icmp_param->replyopts.opt.opt.optlen) { @@ -930,12 +930,12 @@ static void icmp_address_reply(struct sk_buff *skb) BUG_ON(mp == NULL); for (ifa = in_dev->ifa_list; ifa; ifa = ifa->ifa_next) { if (*mp == ifa->ifa_mask && - inet_ifa_match(rt->rt_src, ifa)) + inet_ifa_match(ip_hdr(skb)->saddr, ifa)) break; } if (!ifa && net_ratelimit()) { printk(KERN_INFO "Wrong address mask %pI4 from %s/%pI4\n", - mp, dev->name, &rt->rt_src); + mp, dev->name, &ip_hdr(skb)->saddr); } } } -- cgit v0.10.2 From 79ab053145ae10edf8f0809d1c788b853c7f6ef1 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Mon, 9 May 2011 13:31:04 -0700 Subject: ipv4: udp: Eliminate remaining uses of rt->rt_src We already track and pass around the correct flow key, so simply use it in udp_send_skb(). Signed-off-by: David S. Miller diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c index 66341a3..599374f 100644 --- a/net/ipv4/udp.c +++ b/net/ipv4/udp.c @@ -706,12 +706,11 @@ static void udp4_hwcsum(struct sk_buff *skb, __be32 src, __be32 dst) } } -static int udp_send_skb(struct sk_buff *skb, __be32 daddr, __be32 dport) +static int udp_send_skb(struct sk_buff *skb, struct flowi4 *fl4) { struct sock *sk = skb->sk; struct inet_sock *inet = inet_sk(sk); struct udphdr *uh; - struct rtable *rt = (struct rtable *)skb_dst(skb); int err = 0; int is_udplite = IS_UDPLITE(sk); int offset = skb_transport_offset(skb); @@ -723,7 +722,7 @@ static int udp_send_skb(struct sk_buff *skb, __be32 daddr, __be32 dport) */ uh = udp_hdr(skb); uh->source = inet->inet_sport; - uh->dest = dport; + uh->dest = fl4->fl4_dport; uh->len = htons(len); uh->check = 0; @@ -737,14 +736,14 @@ static int udp_send_skb(struct sk_buff *skb, __be32 daddr, __be32 dport) } else if (skb->ip_summed == CHECKSUM_PARTIAL) { /* UDP hardware csum */ - udp4_hwcsum(skb, rt->rt_src, daddr); + udp4_hwcsum(skb, fl4->saddr, fl4->daddr); goto send; } else csum = udp_csum(skb); /* add protocol-dependent pseudo-header */ - uh->check = csum_tcpudp_magic(rt->rt_src, daddr, len, + uh->check = csum_tcpudp_magic(fl4->saddr, fl4->daddr, len, sk->sk_protocol, csum); if (uh->check == 0) uh->check = CSUM_MANGLED_0; @@ -778,7 +777,7 @@ static int udp_push_pending_frames(struct sock *sk) if (!skb) goto out; - err = udp_send_skb(skb, fl4->daddr, fl4->fl4_dport); + err = udp_send_skb(skb, fl4); out: up->len = 0; @@ -963,7 +962,7 @@ back_from_confirm: msg->msg_flags); err = PTR_ERR(skb); if (skb && !IS_ERR(skb)) - err = udp_send_skb(skb, daddr, dport); + err = udp_send_skb(skb, fl4); goto out; } -- cgit v0.10.2 From 902ebd3e0de618b6d39004edac00b2cc36362065 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Mon, 9 May 2011 14:49:13 -0700 Subject: sctp: Remove rt->rt_src usage in sctp_v4_get_saddr() Flow key is available, so fetch it from there. Signed-off-by: David S. Miller diff --git a/net/sctp/protocol.c b/net/sctp/protocol.c index 4f270ac..4de77cb 100644 --- a/net/sctp/protocol.c +++ b/net/sctp/protocol.c @@ -566,7 +566,7 @@ static void sctp_v4_get_saddr(struct sctp_sock *sk, if (rt) { saddr->v4.sin_family = AF_INET; - saddr->v4.sin_addr.s_addr = rt->rt_src; + saddr->v4.sin_addr.s_addr = fl->u.ip4.saddr; } } -- cgit v0.10.2 From 5fc3590c81bd233c25fbe127cdcf7a8e26e12378 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Mon, 9 May 2011 14:52:02 -0700 Subject: infiniband: Remove rt->rt_src usage in addr4_resolve() Use an explicit flow key and fetch it from there. Signed-off-by: David S. Miller diff --git a/drivers/infiniband/core/addr.c b/drivers/infiniband/core/addr.c index 4ffc224..8e21d45 100644 --- a/drivers/infiniband/core/addr.c +++ b/drivers/infiniband/core/addr.c @@ -185,15 +185,20 @@ static int addr4_resolve(struct sockaddr_in *src_in, __be32 dst_ip = dst_in->sin_addr.s_addr; struct rtable *rt; struct neighbour *neigh; + struct flowi4 fl4; int ret; - rt = ip_route_output(&init_net, dst_ip, src_ip, 0, addr->bound_dev_if); + memset(&fl4, 0, sizeof(fl4)); + fl4.daddr = dst_ip; + fl4.saddr = src_ip; + fl4.flowi4_oif = addr->bound_dev_if; + rt = ip_route_output_key(&init_net, &fl4); if (IS_ERR(rt)) { ret = PTR_ERR(rt); goto out; } src_in->sin_family = AF_INET; - src_in->sin_addr.s_addr = rt->rt_src; + src_in->sin_addr.s_addr = fl4.saddr; if (rt->dst.dev->flags & IFF_LOOPBACK) { ret = rdma_translate_ip((struct sockaddr *) dst_in, addr); -- cgit v0.10.2 From 8f01cb0827c84bd9c4866b849415b3aa6f0428df Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Mon, 9 May 2011 15:13:28 -0700 Subject: ipv4: xfrm: Eliminate ->rt_src reference in policy code. Rearrange xfrm4_dst_lookup() so that it works by calling a helper function __xfrm_dst_lookup() that takes an explicit flow key storage area as an argument. Use this new helper in xfrm4_get_saddr() so we can fetch the selected source address from the flow instead of from rt->rt_src Signed-off-by: David S. Miller diff --git a/net/ipv4/xfrm4_policy.c b/net/ipv4/xfrm4_policy.c index 7ff973b..981e43e 100644 --- a/net/ipv4/xfrm4_policy.c +++ b/net/ipv4/xfrm4_policy.c @@ -18,38 +18,46 @@ static struct xfrm_policy_afinfo xfrm4_policy_afinfo; -static struct dst_entry *xfrm4_dst_lookup(struct net *net, int tos, - const xfrm_address_t *saddr, - const xfrm_address_t *daddr) +static struct dst_entry *__xfrm4_dst_lookup(struct net *net, struct flowi4 *fl4, + int tos, + const xfrm_address_t *saddr, + const xfrm_address_t *daddr) { - struct flowi4 fl4 = { - .daddr = daddr->a4, - .flowi4_tos = tos, - }; struct rtable *rt; + memset(fl4, 0, sizeof(*fl4)); + fl4->daddr = daddr->a4; + fl4->flowi4_tos = tos; if (saddr) - fl4.saddr = saddr->a4; + fl4->saddr = saddr->a4; - rt = __ip_route_output_key(net, &fl4); + rt = __ip_route_output_key(net, fl4); if (!IS_ERR(rt)) return &rt->dst; return ERR_CAST(rt); } +static struct dst_entry *xfrm4_dst_lookup(struct net *net, int tos, + const xfrm_address_t *saddr, + const xfrm_address_t *daddr) +{ + struct flowi4 fl4; + + return __xfrm4_dst_lookup(net, &fl4, tos, saddr, daddr); +} + static int xfrm4_get_saddr(struct net *net, xfrm_address_t *saddr, xfrm_address_t *daddr) { struct dst_entry *dst; - struct rtable *rt; + struct flowi4 fl4; - dst = xfrm4_dst_lookup(net, 0, NULL, daddr); + dst = __xfrm4_dst_lookup(net, &fl4, 0, NULL, daddr); if (IS_ERR(dst)) return -EHOSTUNREACH; - rt = (struct rtable *)dst; - saddr->a4 = rt->rt_src; + saddr->a4 = fl4.saddr; dst_release(dst); return 0; } -- cgit v0.10.2 From f30e6d3e419bfb5540fa82ba7eca01d578556e6b Mon Sep 17 00:00:00 2001 From: Stefan Richter Date: Fri, 22 Apr 2011 15:13:54 +0200 Subject: firewire: octlet AT payloads can be stack-allocated We do not need slab allocations anymore in order to satisfy streaming DMA mapping constraints, thanks to commit da28947e7e36 "firewire: ohci: avoid separate DMA mapping for small AT payloads". (Besides, the slab-allocated buffers that firewire-core, firewire-sbp2, and firedtv used to provide for 8-byte write and lock requests were still not fully portable since they crossed cacheline boundaries or shared a cacheline with unrelated CPU-accessed data. snd-firewire-lib got this aspect right by using an extra kmalloc/ kfree just for the 8-byte transaction buffer.) This change replaces kmalloc'ed lock transaction scratch buffers in firewire-core, firedtv, and snd-firewire-lib by local stack allocations. Perhaps the most notable result of the change is simpler locking because there is no need to serialize usages of preallocated per-device buffers anymore. Also, allocations and deallocations are simpler. Signed-off-by: Stefan Richter Acked-by: Clemens Ladisch diff --git a/drivers/firewire/core-card.c b/drivers/firewire/core-card.c index 3c44fbc..e119f1e 100644 --- a/drivers/firewire/core-card.c +++ b/drivers/firewire/core-card.c @@ -258,8 +258,7 @@ static void allocate_broadcast_channel(struct fw_card *card, int generation) if (!card->broadcast_channel_allocated) { fw_iso_resource_manage(card, generation, 1ULL << 31, - &channel, &bandwidth, true, - card->bm_transaction_data); + &channel, &bandwidth, true); if (channel != 31) { fw_notify("failed to allocate broadcast channel\n"); return; @@ -294,6 +293,7 @@ static void bm_work(struct work_struct *work) bool root_device_is_cmc; bool irm_is_1394_1995_only; bool keep_this_irm; + __be32 transaction_data[2]; spin_lock_irq(&card->lock); @@ -355,21 +355,21 @@ static void bm_work(struct work_struct *work) goto pick_me; } - card->bm_transaction_data[0] = cpu_to_be32(0x3f); - card->bm_transaction_data[1] = cpu_to_be32(local_id); + transaction_data[0] = cpu_to_be32(0x3f); + transaction_data[1] = cpu_to_be32(local_id); spin_unlock_irq(&card->lock); rcode = fw_run_transaction(card, TCODE_LOCK_COMPARE_SWAP, irm_id, generation, SCODE_100, CSR_REGISTER_BASE + CSR_BUS_MANAGER_ID, - card->bm_transaction_data, 8); + transaction_data, 8); if (rcode == RCODE_GENERATION) /* Another bus reset, BM work has been rescheduled. */ goto out; - bm_id = be32_to_cpu(card->bm_transaction_data[0]); + bm_id = be32_to_cpu(transaction_data[0]); spin_lock_irq(&card->lock); if (rcode == RCODE_COMPLETE && generation == card->generation) @@ -490,11 +490,11 @@ static void bm_work(struct work_struct *work) /* * Make sure that the cycle master sends cycle start packets. */ - card->bm_transaction_data[0] = cpu_to_be32(CSR_STATE_BIT_CMSTR); + transaction_data[0] = cpu_to_be32(CSR_STATE_BIT_CMSTR); rcode = fw_run_transaction(card, TCODE_WRITE_QUADLET_REQUEST, root_id, generation, SCODE_100, CSR_REGISTER_BASE + CSR_STATE_SET, - card->bm_transaction_data, 4); + transaction_data, 4); if (rcode == RCODE_GENERATION) goto out; } diff --git a/drivers/firewire/core-cdev.c b/drivers/firewire/core-cdev.c index 62ac111..2a3f1c4 100644 --- a/drivers/firewire/core-cdev.c +++ b/drivers/firewire/core-cdev.c @@ -141,7 +141,6 @@ struct iso_resource { int generation; u64 channels; s32 bandwidth; - __be32 transaction_data[2]; struct iso_resource_event *e_alloc, *e_dealloc; }; @@ -1229,8 +1228,7 @@ static void iso_resource_work(struct work_struct *work) r->channels, &channel, &bandwidth, todo == ISO_RES_ALLOC || todo == ISO_RES_REALLOC || - todo == ISO_RES_ALLOC_ONCE, - r->transaction_data); + todo == ISO_RES_ALLOC_ONCE); /* * Is this generation outdated already? As long as this resource sticks * in the idr, it will be scheduled again for a newer generation or at diff --git a/drivers/firewire/core-iso.c b/drivers/firewire/core-iso.c index 481056d..f872ede 100644 --- a/drivers/firewire/core-iso.c +++ b/drivers/firewire/core-iso.c @@ -196,9 +196,10 @@ EXPORT_SYMBOL(fw_iso_context_stop); */ static int manage_bandwidth(struct fw_card *card, int irm_id, int generation, - int bandwidth, bool allocate, __be32 data[2]) + int bandwidth, bool allocate) { int try, new, old = allocate ? BANDWIDTH_AVAILABLE_INITIAL : 0; + __be32 data[2]; /* * On a 1394a IRM with low contention, try < 1 is enough. @@ -233,9 +234,10 @@ static int manage_bandwidth(struct fw_card *card, int irm_id, int generation, } static int manage_channel(struct fw_card *card, int irm_id, int generation, - u32 channels_mask, u64 offset, bool allocate, __be32 data[2]) + u32 channels_mask, u64 offset, bool allocate) { __be32 bit, all, old; + __be32 data[2]; int channel, ret = -EIO, retry = 5; old = all = allocate ? cpu_to_be32(~0) : 0; @@ -284,7 +286,7 @@ static int manage_channel(struct fw_card *card, int irm_id, int generation, } static void deallocate_channel(struct fw_card *card, int irm_id, - int generation, int channel, __be32 buffer[2]) + int generation, int channel) { u32 mask; u64 offset; @@ -293,7 +295,7 @@ static void deallocate_channel(struct fw_card *card, int irm_id, offset = channel < 32 ? CSR_REGISTER_BASE + CSR_CHANNELS_AVAILABLE_HI : CSR_REGISTER_BASE + CSR_CHANNELS_AVAILABLE_LO; - manage_channel(card, irm_id, generation, mask, offset, false, buffer); + manage_channel(card, irm_id, generation, mask, offset, false); } /** @@ -322,7 +324,7 @@ static void deallocate_channel(struct fw_card *card, int irm_id, */ void fw_iso_resource_manage(struct fw_card *card, int generation, u64 channels_mask, int *channel, int *bandwidth, - bool allocate, __be32 buffer[2]) + bool allocate) { u32 channels_hi = channels_mask; /* channels 31...0 */ u32 channels_lo = channels_mask >> 32; /* channels 63...32 */ @@ -335,11 +337,11 @@ void fw_iso_resource_manage(struct fw_card *card, int generation, if (channels_hi) c = manage_channel(card, irm_id, generation, channels_hi, CSR_REGISTER_BASE + CSR_CHANNELS_AVAILABLE_HI, - allocate, buffer); + allocate); if (channels_lo && c < 0) { c = manage_channel(card, irm_id, generation, channels_lo, CSR_REGISTER_BASE + CSR_CHANNELS_AVAILABLE_LO, - allocate, buffer); + allocate); if (c >= 0) c += 32; } @@ -351,14 +353,13 @@ void fw_iso_resource_manage(struct fw_card *card, int generation, if (*bandwidth == 0) return; - ret = manage_bandwidth(card, irm_id, generation, *bandwidth, - allocate, buffer); + ret = manage_bandwidth(card, irm_id, generation, *bandwidth, allocate); if (ret < 0) *bandwidth = 0; if (allocate && ret < 0) { if (c >= 0) - deallocate_channel(card, irm_id, generation, c, buffer); + deallocate_channel(card, irm_id, generation, c); *channel = ret; } } diff --git a/drivers/firewire/core-transaction.c b/drivers/firewire/core-transaction.c index d00f8ce..77275fd 100644 --- a/drivers/firewire/core-transaction.c +++ b/drivers/firewire/core-transaction.c @@ -326,8 +326,8 @@ static int allocate_tlabel(struct fw_card *card) * It will contain tag, channel, and sy data instead of a node ID then. * * The payload buffer at @data is going to be DMA-mapped except in case of - * quadlet-sized payload or of local (loopback) requests. Hence make sure that - * the buffer complies with the restrictions for DMA-mapped memory. The + * @length <= 8 or of local (loopback) requests. Hence make sure that the + * buffer complies with the restrictions of the streaming DMA mapping API. * @payload must not be freed before the @callback is called. * * In case of request types without payload, @data is NULL and @length is 0. @@ -411,7 +411,8 @@ static void transaction_callback(struct fw_card *card, int rcode, * * Returns the RCODE. See fw_send_request() for parameter documentation. * Unlike fw_send_request(), @data points to the payload of the request or/and - * to the payload of the response. + * to the payload of the response. DMA mapping restrictions apply to outbound + * request payloads of >= 8 bytes but not to inbound response payloads. */ int fw_run_transaction(struct fw_card *card, int tcode, int destination_id, int generation, int speed, unsigned long long offset, diff --git a/drivers/media/dvb/firewire/firedtv-avc.c b/drivers/media/dvb/firewire/firedtv-avc.c index fc5ccd8..21c52e3 100644 --- a/drivers/media/dvb/firewire/firedtv-avc.c +++ b/drivers/media/dvb/firewire/firedtv-avc.c @@ -1320,14 +1320,10 @@ static int cmp_read(struct firedtv *fdtv, u64 addr, __be32 *data) { int ret; - mutex_lock(&fdtv->avc_mutex); - ret = fdtv_read(fdtv, addr, data); if (ret < 0) dev_err(fdtv->device, "CMP: read I/O error\n"); - mutex_unlock(&fdtv->avc_mutex); - return ret; } @@ -1335,18 +1331,9 @@ static int cmp_lock(struct firedtv *fdtv, u64 addr, __be32 data[]) { int ret; - mutex_lock(&fdtv->avc_mutex); - - /* data[] is stack-allocated and should not be DMA-mapped. */ - memcpy(fdtv->avc_data, data, 8); - - ret = fdtv_lock(fdtv, addr, fdtv->avc_data); + ret = fdtv_lock(fdtv, addr, data); if (ret < 0) dev_err(fdtv->device, "CMP: lock I/O error\n"); - else - memcpy(data, fdtv->avc_data, 8); - - mutex_unlock(&fdtv->avc_mutex); return ret; } diff --git a/include/linux/firewire.h b/include/linux/firewire.h index c64f368..de90e1f 100644 --- a/include/linux/firewire.h +++ b/include/linux/firewire.h @@ -125,7 +125,6 @@ struct fw_card { struct delayed_work bm_work; /* bus manager job */ int bm_retries; int bm_generation; - __be32 bm_transaction_data[2]; int bm_node_id; bool bm_abdicate; @@ -447,6 +446,6 @@ int fw_iso_context_stop(struct fw_iso_context *ctx); void fw_iso_context_destroy(struct fw_iso_context *ctx); void fw_iso_resource_manage(struct fw_card *card, int generation, u64 channels_mask, int *channel, int *bandwidth, - bool allocate, __be32 buffer[2]); + bool allocate); #endif /* _LINUX_FIREWIRE_H */ diff --git a/sound/firewire/cmp.c b/sound/firewire/cmp.c index 4a37f3a..14cacbc 100644 --- a/sound/firewire/cmp.c +++ b/sound/firewire/cmp.c @@ -49,10 +49,9 @@ static int pcr_modify(struct cmp_connection *c, enum bus_reset_handling bus_reset_handling) { struct fw_device *device = fw_parent_device(c->resources.unit); - __be32 *buffer = c->resources.buffer; int generation = c->resources.generation; int rcode, errors = 0; - __be32 old_arg; + __be32 old_arg, buffer[2]; int err; buffer[0] = c->last_pcr_value; diff --git a/sound/firewire/iso-resources.c b/sound/firewire/iso-resources.c index 775dbd5..bb9c0c1 100644 --- a/sound/firewire/iso-resources.c +++ b/sound/firewire/iso-resources.c @@ -11,7 +11,6 @@ #include #include #include -#include #include #include "iso-resources.h" @@ -25,10 +24,6 @@ */ int fw_iso_resources_init(struct fw_iso_resources *r, struct fw_unit *unit) { - r->buffer = kmalloc(2 * 4, GFP_KERNEL); - if (!r->buffer) - return -ENOMEM; - r->channels_mask = ~0uLL; r->unit = fw_unit_get(unit); mutex_init(&r->mutex); @@ -44,7 +39,6 @@ int fw_iso_resources_init(struct fw_iso_resources *r, struct fw_unit *unit) void fw_iso_resources_destroy(struct fw_iso_resources *r) { WARN_ON(r->allocated); - kfree(r->buffer); mutex_destroy(&r->mutex); fw_unit_put(r->unit); } @@ -131,7 +125,7 @@ retry_after_bus_reset: bandwidth = r->bandwidth + r->bandwidth_overhead; fw_iso_resource_manage(card, r->generation, r->channels_mask, - &channel, &bandwidth, true, r->buffer); + &channel, &bandwidth, true); if (channel == -EAGAIN) { mutex_unlock(&r->mutex); goto retry_after_bus_reset; @@ -184,7 +178,7 @@ int fw_iso_resources_update(struct fw_iso_resources *r) bandwidth = r->bandwidth + r->bandwidth_overhead; fw_iso_resource_manage(card, r->generation, 1uLL << r->channel, - &channel, &bandwidth, true, r->buffer); + &channel, &bandwidth, true); /* * When another bus reset happens, pretend that the allocation * succeeded; we will try again for the new generation later. @@ -220,7 +214,7 @@ void fw_iso_resources_free(struct fw_iso_resources *r) if (r->allocated) { bandwidth = r->bandwidth + r->bandwidth_overhead; fw_iso_resource_manage(card, r->generation, 1uLL << r->channel, - &channel, &bandwidth, false, r->buffer); + &channel, &bandwidth, false); if (channel < 0) dev_err(&r->unit->device, "isochronous resource deallocation failed\n"); diff --git a/sound/firewire/iso-resources.h b/sound/firewire/iso-resources.h index 3f0730e4..5a9af7c 100644 --- a/sound/firewire/iso-resources.h +++ b/sound/firewire/iso-resources.h @@ -24,7 +24,6 @@ struct fw_iso_resources { unsigned int bandwidth_overhead; int generation; /* in which allocation is valid */ bool allocated; - __be32 *buffer; }; int fw_iso_resources_init(struct fw_iso_resources *r, -- cgit v0.10.2 From 13882a82ee1646336c3996c93b4a560a55d2a419 Mon Sep 17 00:00:00 2001 From: Clemens Ladisch Date: Mon, 2 May 2011 09:33:56 +0200 Subject: firewire: optimize iso queueing by setting wake only after the last packet When queueing iso packets, the run time is dominated by the two MMIO accesses that set the DMA context's wake bit. Because most drivers submit packets in batches, we can save much time by removing all but the last wakeup. The internal kernel API is changed to require a call to fw_iso_context_queue_flush() after a batch of queued packets. The user space API does not change, so one call to FW_CDEV_IOC_QUEUE_ISO must specify multiple packets to take advantage of this optimization. In my measurements, this patch reduces the time needed to queue fifty skip packets from userspace to one sixth on a 2.5 GHz CPU, or to one third at 800 MHz. Signed-off-by: Clemens Ladisch Signed-off-by: Stefan Richter diff --git a/drivers/firewire/core-card.c b/drivers/firewire/core-card.c index e119f1e..f05fc7b 100644 --- a/drivers/firewire/core-card.c +++ b/drivers/firewire/core-card.c @@ -630,6 +630,10 @@ static int dummy_queue_iso(struct fw_iso_context *ctx, struct fw_iso_packet *p, return -ENODEV; } +static void dummy_flush_queue_iso(struct fw_iso_context *ctx) +{ +} + static const struct fw_card_driver dummy_driver_template = { .read_phy_reg = dummy_read_phy_reg, .update_phy_reg = dummy_update_phy_reg, @@ -641,6 +645,7 @@ static const struct fw_card_driver dummy_driver_template = { .start_iso = dummy_start_iso, .set_iso_channels = dummy_set_iso_channels, .queue_iso = dummy_queue_iso, + .flush_queue_iso = dummy_flush_queue_iso, }; void fw_card_release(struct kref *kref) diff --git a/drivers/firewire/core-cdev.c b/drivers/firewire/core-cdev.c index 2a3f1c4..64768c2 100644 --- a/drivers/firewire/core-cdev.c +++ b/drivers/firewire/core-cdev.c @@ -1107,6 +1107,7 @@ static int ioctl_queue_iso(struct client *client, union ioctl_arg *arg) payload += u.packet.payload_length; count++; } + fw_iso_context_queue_flush(ctx); a->size -= uptr_to_u64(p) - a->packets; a->packets = uptr_to_u64(p); diff --git a/drivers/firewire/core-iso.c b/drivers/firewire/core-iso.c index f872ede..57c3973 100644 --- a/drivers/firewire/core-iso.c +++ b/drivers/firewire/core-iso.c @@ -185,6 +185,12 @@ int fw_iso_context_queue(struct fw_iso_context *ctx, } EXPORT_SYMBOL(fw_iso_context_queue); +void fw_iso_context_queue_flush(struct fw_iso_context *ctx) +{ + ctx->card->driver->flush_queue_iso(ctx); +} +EXPORT_SYMBOL(fw_iso_context_queue_flush); + int fw_iso_context_stop(struct fw_iso_context *ctx) { return ctx->card->driver->stop_iso(ctx); diff --git a/drivers/firewire/core.h b/drivers/firewire/core.h index 25e729c..0fe4e4e 100644 --- a/drivers/firewire/core.h +++ b/drivers/firewire/core.h @@ -97,6 +97,8 @@ struct fw_card_driver { struct fw_iso_buffer *buffer, unsigned long payload); + void (*flush_queue_iso)(struct fw_iso_context *ctx); + int (*stop_iso)(struct fw_iso_context *ctx); }; diff --git a/drivers/firewire/net.c b/drivers/firewire/net.c index 3f04dd3..b9762d0 100644 --- a/drivers/firewire/net.c +++ b/drivers/firewire/net.c @@ -881,7 +881,9 @@ static void fwnet_receive_broadcast(struct fw_iso_context *context, spin_unlock_irqrestore(&dev->lock, flags); - if (retval < 0) + if (retval >= 0) + fw_iso_context_queue_flush(dev->broadcast_rcv_context); + else fw_error("requeue failed\n"); } diff --git a/drivers/firewire/ohci.c b/drivers/firewire/ohci.c index f9f5570..438e6c8 100644 --- a/drivers/firewire/ohci.c +++ b/drivers/firewire/ohci.c @@ -1192,9 +1192,6 @@ static void context_append(struct context *ctx, wmb(); /* finish init of new descriptors before branch_address update */ ctx->prev->branch_address = cpu_to_le32(d_bus | z); ctx->prev = find_branch_descriptor(d, z); - - reg_write(ctx->ohci, CONTROL_SET(ctx->regs), CONTEXT_WAKE); - flush_writes(ctx->ohci); } static void context_stop(struct context *ctx) @@ -1348,8 +1345,12 @@ static int at_context_queue_packet(struct context *ctx, context_append(ctx, d, z, 4 - z); - if (!ctx->running) + if (ctx->running) { + reg_write(ohci, CONTROL_SET(ctx->regs), CONTEXT_WAKE); + flush_writes(ohci); + } else { context_run(ctx, 0); + } return 0; } @@ -3121,6 +3122,15 @@ static int ohci_queue_iso(struct fw_iso_context *base, return ret; } +static void ohci_flush_queue_iso(struct fw_iso_context *base) +{ + struct context *ctx = + &container_of(base, struct iso_context, base)->context; + + reg_write(ctx->ohci, CONTROL_SET(ctx->regs), CONTEXT_WAKE); + flush_writes(ctx->ohci); +} + static const struct fw_card_driver ohci_driver = { .enable = ohci_enable, .read_phy_reg = ohci_read_phy_reg, @@ -3137,6 +3147,7 @@ static const struct fw_card_driver ohci_driver = { .free_iso_context = ohci_free_iso_context, .set_iso_channels = ohci_set_iso_channels, .queue_iso = ohci_queue_iso, + .flush_queue_iso = ohci_flush_queue_iso, .start_iso = ohci_start_iso, .stop_iso = ohci_stop_iso, }; diff --git a/drivers/media/dvb/firewire/firedtv-fw.c b/drivers/media/dvb/firewire/firedtv-fw.c index 8022b74..864b627 100644 --- a/drivers/media/dvb/firewire/firedtv-fw.c +++ b/drivers/media/dvb/firewire/firedtv-fw.c @@ -125,6 +125,7 @@ static void handle_iso(struct fw_iso_context *context, u32 cycle, i = (i + 1) & (N_PACKETS - 1); } + fw_iso_context_queue_flush(ctx->context); ctx->current_packet = i; } diff --git a/include/linux/firewire.h b/include/linux/firewire.h index de90e1f..c0fb405 100644 --- a/include/linux/firewire.h +++ b/include/linux/firewire.h @@ -440,6 +440,7 @@ int fw_iso_context_queue(struct fw_iso_context *ctx, struct fw_iso_packet *packet, struct fw_iso_buffer *buffer, unsigned long payload); +void fw_iso_context_queue_flush(struct fw_iso_context *ctx); int fw_iso_context_start(struct fw_iso_context *ctx, int cycle, int sync, int tags); int fw_iso_context_stop(struct fw_iso_context *ctx); diff --git a/sound/firewire/amdtp.c b/sound/firewire/amdtp.c index b18140f..87657dd 100644 --- a/sound/firewire/amdtp.c +++ b/sound/firewire/amdtp.c @@ -396,6 +396,7 @@ static void out_packet_callback(struct fw_iso_context *context, u32 cycle, for (i = 0; i < packets; ++i) queue_out_packet(s, ++cycle); + fw_iso_context_queue_flush(s->context); } static int queue_initial_skip_packets(struct amdtp_out_stream *s) -- cgit v0.10.2 From 6ea9e7bbfc389a12d52646449a201fe933ccd663 Mon Sep 17 00:00:00 2001 From: Stefan Richter Date: Wed, 13 Oct 2010 13:39:46 +0200 Subject: firewire: core: use non-reentrant workqueue with rescuer firewire-core manages the following types of work items: fw_card.br_work: - resets the bus on a card and possibly sends a PHY packet before that - does not sleep for long or not at all - is scheduled via fw_schedule_bus_reset() by - firewire-ohci's pci_probe method - firewire-ohci's set_config_rom method, called by kernelspace protocol drivers and userspace drivers which add/remove Configuration ROM descriptors - userspace drivers which use the bus reset ioctl - itself if the last reset happened less than 2 seconds ago fw_card.bm_work: - performs bus management duties - usually does not (but may in corner cases) sleep for long - is scheduled via fw_schedule_bm_work() by - firewire-ohci's self-ID-complete IRQ handler tasklet - firewire-core's fw_device.work instances whenever the root node device was (successfully or unsuccessfully) discovered, refreshed, or rediscovered - itself in case of resource allocation failures or in order to obey the 125ms bus manager arbitration interval fw_device.work: - performs node probe, update, shutdown, revival, removal; including kernel driver probe, update, shutdown and bus reset notification to userspace drivers - usually sleeps moderately long, in corner cases very long - is scheduled by - firewire-ohci's self-ID-complete IRQ handler tasklet via the core's fw_node_event - firewire-ohci's pci_remove method via core's fw_destroy_nodes/ fw_node_event - itself during retries, e.g. while a node is powering up iso_resource.work: - accesses registers at the Isochronous Resource Manager node - usually does not (but may in corner cases) sleep for long - is scheduled via schedule_iso_resource() by - the owning userspace driver at addition and removal of the resource - firewire-core's fw_device.work instances after bus reset - itself in case of resource allocation if necessary to obey the 1000ms reallocation period after bus reset fw_card.br_work instances should not, and instances of the others must not, be executed in parallel by multiple CPUs -- but were not protected against that. Hence allocate a non-reentrant workqueue for them. fw_device.work may be used in the memory reclaim path in case of SBP-2 device updates. Hence we need a workqueue with rescuer and cannot use system_nrt_wq. Signed-off-by: Stefan Richter Reviewed-by: Tejun Heo diff --git a/drivers/firewire/core-card.c b/drivers/firewire/core-card.c index f05fc7b..bb8c4d2 100644 --- a/drivers/firewire/core-card.c +++ b/drivers/firewire/core-card.c @@ -228,8 +228,8 @@ void fw_schedule_bus_reset(struct fw_card *card, bool delayed, bool short_reset) /* Use an arbitrary short delay to combine multiple reset requests. */ fw_card_get(card); - if (!schedule_delayed_work(&card->br_work, - delayed ? DIV_ROUND_UP(HZ, 100) : 0)) + if (!queue_delayed_work(fw_wq, &card->br_work, + delayed ? DIV_ROUND_UP(HZ, 100) : 0)) fw_card_put(card); } EXPORT_SYMBOL(fw_schedule_bus_reset); @@ -241,7 +241,7 @@ static void br_work(struct work_struct *work) /* Delay for 2s after last reset per IEEE 1394 clause 8.2.1. */ if (card->reset_jiffies != 0 && time_before64(get_jiffies_64(), card->reset_jiffies + 2 * HZ)) { - if (!schedule_delayed_work(&card->br_work, 2 * HZ)) + if (!queue_delayed_work(fw_wq, &card->br_work, 2 * HZ)) fw_card_put(card); return; } diff --git a/drivers/firewire/core-cdev.c b/drivers/firewire/core-cdev.c index 64768c2..aa1131d 100644 --- a/drivers/firewire/core-cdev.c +++ b/drivers/firewire/core-cdev.c @@ -149,7 +149,7 @@ static void release_iso_resource(struct client *, struct client_resource *); static void schedule_iso_resource(struct iso_resource *r, unsigned long delay) { client_get(r->client); - if (!schedule_delayed_work(&r->work, delay)) + if (!queue_delayed_work(fw_wq, &r->work, delay)) client_put(r->client); } diff --git a/drivers/firewire/core-device.c b/drivers/firewire/core-device.c index 9a26243..ef900d9 100644 --- a/drivers/firewire/core-device.c +++ b/drivers/firewire/core-device.c @@ -725,6 +725,14 @@ struct fw_device *fw_device_get_by_devt(dev_t devt) return device; } +struct workqueue_struct *fw_wq; + +static void fw_schedule_device_work(struct fw_device *device, + unsigned long delay) +{ + queue_delayed_work(fw_wq, &device->work, delay); +} + /* * These defines control the retry behavior for reading the config * rom. It shouldn't be necessary to tweak these; if the device @@ -750,7 +758,7 @@ static void fw_device_shutdown(struct work_struct *work) if (time_before64(get_jiffies_64(), device->card->reset_jiffies + SHUTDOWN_DELAY) && !list_empty(&device->card->link)) { - schedule_delayed_work(&device->work, SHUTDOWN_DELAY); + fw_schedule_device_work(device, SHUTDOWN_DELAY); return; } @@ -862,7 +870,7 @@ static int lookup_existing_device(struct device *dev, void *data) fw_notify("rediscovered device %s\n", dev_name(dev)); PREPARE_DELAYED_WORK(&old->work, fw_device_update); - schedule_delayed_work(&old->work, 0); + fw_schedule_device_work(old, 0); if (current_node == card->root_node) fw_schedule_bm_work(card, 0); @@ -953,7 +961,7 @@ static void fw_device_init(struct work_struct *work) if (device->config_rom_retries < MAX_RETRIES && atomic_read(&device->state) == FW_DEVICE_INITIALIZING) { device->config_rom_retries++; - schedule_delayed_work(&device->work, RETRY_DELAY); + fw_schedule_device_work(device, RETRY_DELAY); } else { if (device->node->link_on) fw_notify("giving up on config rom for node id %x\n", @@ -1019,7 +1027,7 @@ static void fw_device_init(struct work_struct *work) FW_DEVICE_INITIALIZING, FW_DEVICE_RUNNING) == FW_DEVICE_GONE) { PREPARE_DELAYED_WORK(&device->work, fw_device_shutdown); - schedule_delayed_work(&device->work, SHUTDOWN_DELAY); + fw_schedule_device_work(device, SHUTDOWN_DELAY); } else { if (device->config_rom_retries) fw_notify("created device %s: GUID %08x%08x, S%d00, " @@ -1098,7 +1106,7 @@ static void fw_device_refresh(struct work_struct *work) if (device->config_rom_retries < MAX_RETRIES / 2 && atomic_read(&device->state) == FW_DEVICE_INITIALIZING) { device->config_rom_retries++; - schedule_delayed_work(&device->work, RETRY_DELAY / 2); + fw_schedule_device_work(device, RETRY_DELAY / 2); return; } @@ -1131,7 +1139,7 @@ static void fw_device_refresh(struct work_struct *work) if (device->config_rom_retries < MAX_RETRIES && atomic_read(&device->state) == FW_DEVICE_INITIALIZING) { device->config_rom_retries++; - schedule_delayed_work(&device->work, RETRY_DELAY); + fw_schedule_device_work(device, RETRY_DELAY); return; } @@ -1158,7 +1166,7 @@ static void fw_device_refresh(struct work_struct *work) gone: atomic_set(&device->state, FW_DEVICE_GONE); PREPARE_DELAYED_WORK(&device->work, fw_device_shutdown); - schedule_delayed_work(&device->work, SHUTDOWN_DELAY); + fw_schedule_device_work(device, SHUTDOWN_DELAY); out: if (node_id == card->root_node->node_id) fw_schedule_bm_work(card, 0); @@ -1214,7 +1222,7 @@ void fw_node_event(struct fw_card *card, struct fw_node *node, int event) * first config rom scan half a second after bus reset. */ INIT_DELAYED_WORK(&device->work, fw_device_init); - schedule_delayed_work(&device->work, INITIAL_DELAY); + fw_schedule_device_work(device, INITIAL_DELAY); break; case FW_NODE_INITIATED_RESET: @@ -1230,7 +1238,7 @@ void fw_node_event(struct fw_card *card, struct fw_node *node, int event) FW_DEVICE_RUNNING, FW_DEVICE_INITIALIZING) == FW_DEVICE_RUNNING) { PREPARE_DELAYED_WORK(&device->work, fw_device_refresh); - schedule_delayed_work(&device->work, + fw_schedule_device_work(device, device->is_local ? 0 : INITIAL_DELAY); } break; @@ -1245,7 +1253,7 @@ void fw_node_event(struct fw_card *card, struct fw_node *node, int event) device->generation = card->generation; if (atomic_read(&device->state) == FW_DEVICE_RUNNING) { PREPARE_DELAYED_WORK(&device->work, fw_device_update); - schedule_delayed_work(&device->work, 0); + fw_schedule_device_work(device, 0); } break; @@ -1270,7 +1278,7 @@ void fw_node_event(struct fw_card *card, struct fw_node *node, int event) if (atomic_xchg(&device->state, FW_DEVICE_GONE) == FW_DEVICE_RUNNING) { PREPARE_DELAYED_WORK(&device->work, fw_device_shutdown); - schedule_delayed_work(&device->work, + fw_schedule_device_work(device, list_empty(&card->link) ? 0 : SHUTDOWN_DELAY); } break; diff --git a/drivers/firewire/core-transaction.c b/drivers/firewire/core-transaction.c index 77275fd..d4c28a2 100644 --- a/drivers/firewire/core-transaction.c +++ b/drivers/firewire/core-transaction.c @@ -36,6 +36,7 @@ #include #include #include +#include #include @@ -1213,13 +1214,21 @@ static int __init fw_core_init(void) { int ret; + fw_wq = alloc_workqueue(KBUILD_MODNAME, + WQ_NON_REENTRANT | WQ_MEM_RECLAIM, 0); + if (!fw_wq) + return -ENOMEM; + ret = bus_register(&fw_bus_type); - if (ret < 0) + if (ret < 0) { + destroy_workqueue(fw_wq); return ret; + } fw_cdev_major = register_chrdev(0, "firewire", &fw_device_ops); if (fw_cdev_major < 0) { bus_unregister(&fw_bus_type); + destroy_workqueue(fw_wq); return fw_cdev_major; } @@ -1235,6 +1244,7 @@ static void __exit fw_core_cleanup(void) { unregister_chrdev(fw_cdev_major, "firewire"); bus_unregister(&fw_bus_type); + destroy_workqueue(fw_wq); idr_destroy(&fw_device_idr); } diff --git a/drivers/firewire/core.h b/drivers/firewire/core.h index 0fe4e4e..00ea773 100644 --- a/drivers/firewire/core.h +++ b/drivers/firewire/core.h @@ -140,6 +140,8 @@ void fw_cdev_handle_phy_packet(struct fw_card *card, struct fw_packet *p); extern struct rw_semaphore fw_device_rwsem; extern struct idr fw_device_idr; extern int fw_cdev_major; +struct workqueue_struct; +extern struct workqueue_struct *fw_wq; struct fw_device *fw_device_get_by_devt(dev_t devt); int fw_device_set_broadcast_channel(struct device *dev, void *gen); -- cgit v0.10.2 From b75ca5ea8e439893121ad80406a3c04c4b7612ab Mon Sep 17 00:00:00 2001 From: Stefan Richter Date: Fri, 22 Apr 2011 12:21:44 +0200 Subject: firewire: sbp2: omit Scsi_Host lock from queuecommand firewire-sbp2 already takes care for internal serialization where required (ORB list accesses), and it does not use cmd->serial_number internally. Hence it is safe to not grab the shost lock around queuecommand. While we are at housekeeping, drop a redundant struct member: sbp2_command_orb.done is set once in a hot path and dereferenced once in a hot path. We can as well dereference sbp2_command_orb.cmd->scsi_done instead. Signed-off-by: Stefan Richter diff --git a/drivers/firewire/sbp2.c b/drivers/firewire/sbp2.c index 77ed589..cc002e9 100644 --- a/drivers/firewire/sbp2.c +++ b/drivers/firewire/sbp2.c @@ -125,9 +125,6 @@ MODULE_PARM_DESC(workarounds, "Work around device bugs (default = 0" ", override internal blacklist = " __stringify(SBP2_WORKAROUND_OVERRIDE) ", or a combination)"); -/* I don't know why the SCSI stack doesn't define something like this... */ -typedef void (*scsi_done_fn_t)(struct scsi_cmnd *); - static const char sbp2_driver_name[] = "sbp2"; /* @@ -314,7 +311,6 @@ struct sbp2_command_orb { u8 command_block[SBP2_MAX_CDB_SIZE]; } request; struct scsi_cmnd *cmd; - scsi_done_fn_t done; struct sbp2_logical_unit *lu; struct sbp2_pointer page_table[SG_ALL] __attribute__((aligned(8))); @@ -1398,7 +1394,7 @@ static void complete_command_orb(struct sbp2_orb *base_orb, sbp2_unmap_scatterlist(device->card->device, orb); orb->cmd->result = result; - orb->done(orb->cmd); + orb->cmd->scsi_done(orb->cmd); } static int sbp2_map_scatterlist(struct sbp2_command_orb *orb, @@ -1463,7 +1459,8 @@ static int sbp2_map_scatterlist(struct sbp2_command_orb *orb, /* SCSI stack integration */ -static int sbp2_scsi_queuecommand_lck(struct scsi_cmnd *cmd, scsi_done_fn_t done) +static int sbp2_scsi_queuecommand(struct Scsi_Host *shost, + struct scsi_cmnd *cmd) { struct sbp2_logical_unit *lu = cmd->device->hostdata; struct fw_device *device = target_device(lu->tgt); @@ -1477,7 +1474,7 @@ static int sbp2_scsi_queuecommand_lck(struct scsi_cmnd *cmd, scsi_done_fn_t done if (cmd->sc_data_direction == DMA_BIDIRECTIONAL) { fw_error("Can't handle DMA_BIDIRECTIONAL, rejecting command\n"); cmd->result = DID_ERROR << 16; - done(cmd); + cmd->scsi_done(cmd); return 0; } @@ -1490,11 +1487,8 @@ static int sbp2_scsi_queuecommand_lck(struct scsi_cmnd *cmd, scsi_done_fn_t done /* Initialize rcode to something not RCODE_COMPLETE. */ orb->base.rcode = -1; kref_init(&orb->base.kref); - - orb->lu = lu; - orb->done = done; - orb->cmd = cmd; - + orb->lu = lu; + orb->cmd = cmd; orb->request.next.high = cpu_to_be32(SBP2_ORB_NULL); orb->request.misc = cpu_to_be32( COMMAND_ORB_MAX_PAYLOAD(lu->tgt->max_payload) | @@ -1529,8 +1523,6 @@ static int sbp2_scsi_queuecommand_lck(struct scsi_cmnd *cmd, scsi_done_fn_t done return retval; } -static DEF_SCSI_QCMD(sbp2_scsi_queuecommand) - static int sbp2_scsi_slave_alloc(struct scsi_device *sdev) { struct sbp2_logical_unit *lu = sdev->hostdata; -- cgit v0.10.2 From 81bf52d8622f05cfe89893fd5c1101efd85f855b Mon Sep 17 00:00:00 2001 From: Stefan Richter Date: Sun, 1 May 2011 21:06:42 +0200 Subject: firewire: sbp2: octlet AT payloads can be stack-allocated We do not need slab allocations for ORB pointer write transactions anymore in order to satisfy streaming DMA mapping constraints, thanks to commit da28947e7e36 "firewire: ohci: avoid separate DMA mapping for small AT payloads". (Besides, the slab-allocated buffers that firewire-sbp2 used to provide for 8-byte write requests were still not fully portable since they shared a cacheline with unrelated CPU-accessed data.) Signed-off-by: Stefan Richter diff --git a/drivers/firewire/sbp2.c b/drivers/firewire/sbp2.c index cc002e9..2aafc61 100644 --- a/drivers/firewire/sbp2.c +++ b/drivers/firewire/sbp2.c @@ -258,7 +258,6 @@ struct sbp2_orb { struct kref kref; dma_addr_t request_bus; int rcode; - struct sbp2_pointer pointer; void (*callback)(struct sbp2_orb * orb, struct sbp2_status * status); struct list_head link; }; @@ -490,10 +489,11 @@ static void sbp2_send_orb(struct sbp2_orb *orb, struct sbp2_logical_unit *lu, int node_id, int generation, u64 offset) { struct fw_device *device = target_device(lu->tgt); + struct sbp2_pointer orb_pointer; unsigned long flags; - orb->pointer.high = 0; - orb->pointer.low = cpu_to_be32(orb->request_bus); + orb_pointer.high = 0; + orb_pointer.low = cpu_to_be32(orb->request_bus); spin_lock_irqsave(&device->card->lock, flags); list_add_tail(&orb->link, &lu->orb_list); @@ -504,7 +504,7 @@ static void sbp2_send_orb(struct sbp2_orb *orb, struct sbp2_logical_unit *lu, fw_send_request(device->card, &orb->t, TCODE_WRITE_BLOCK_REQUEST, node_id, generation, device->max_speed, offset, - &orb->pointer, 8, complete_transaction, orb); + &orb_pointer, 8, complete_transaction, orb); } static int sbp2_cancel_orbs(struct sbp2_logical_unit *lu) -- cgit v0.10.2 From 105e53f863c04e1d9e5bb34bf753c9fdbce6a60c Mon Sep 17 00:00:00 2001 From: Stefan Richter Date: Sun, 1 May 2011 20:50:31 +0200 Subject: firewire: sbp2: parallelize login, reconnect, logout The struct sbp2_logical_unit.work items can all be executed in parallel but are not reentrant. Furthermore, reconnect or re-login work must be executed in a WQ_MEM_RECLAIM workqueue. Hence replace the old single-threaded firewire-sbp2 workqueue by a concurrency-managed but non-reentrant workqueue with rescuer. firewire-core already maintains one, hence use this one. In earlier versions of this change, I observed occasional failures of parallel INQUIRY to an Initio INIC-2430 FireWire 800 to dual IDE bridge. More testing indicates that parallel INQUIRY is not actually a problem, but too quick successions of logout and login + INQUIRY, e.g. a quick sequence of cable plugout and plugin, can result in failed INQUIRY. This does not seem to be something that should or could be addressed by serialization. Another dual-LU device to which I currently have access to, an OXUF924DSB FireWire 800 to dual SATA bridge with firmware from MacPower, has been successfully tested with this too. This change is beneficial to environments with two or more FireWire storage devices, especially if they are located on the same bus. Management tasks that should be performed as soon and as quickly as possible, especially reconnect, are no longer held up by tasks on other devices that may take a long time, especially login with INQUIRY and sd or sr driver probe. Signed-off-by: Stefan Richter diff --git a/drivers/firewire/core-card.c b/drivers/firewire/core-card.c index bb8c4d2..29d2423 100644 --- a/drivers/firewire/core-card.c +++ b/drivers/firewire/core-card.c @@ -228,7 +228,7 @@ void fw_schedule_bus_reset(struct fw_card *card, bool delayed, bool short_reset) /* Use an arbitrary short delay to combine multiple reset requests. */ fw_card_get(card); - if (!queue_delayed_work(fw_wq, &card->br_work, + if (!queue_delayed_work(fw_workqueue, &card->br_work, delayed ? DIV_ROUND_UP(HZ, 100) : 0)) fw_card_put(card); } @@ -241,7 +241,7 @@ static void br_work(struct work_struct *work) /* Delay for 2s after last reset per IEEE 1394 clause 8.2.1. */ if (card->reset_jiffies != 0 && time_before64(get_jiffies_64(), card->reset_jiffies + 2 * HZ)) { - if (!queue_delayed_work(fw_wq, &card->br_work, 2 * HZ)) + if (!queue_delayed_work(fw_workqueue, &card->br_work, 2 * HZ)) fw_card_put(card); return; } diff --git a/drivers/firewire/core-cdev.c b/drivers/firewire/core-cdev.c index aa1131d..b1c1177 100644 --- a/drivers/firewire/core-cdev.c +++ b/drivers/firewire/core-cdev.c @@ -149,7 +149,7 @@ static void release_iso_resource(struct client *, struct client_resource *); static void schedule_iso_resource(struct iso_resource *r, unsigned long delay) { client_get(r->client); - if (!queue_delayed_work(fw_wq, &r->work, delay)) + if (!queue_delayed_work(fw_workqueue, &r->work, delay)) client_put(r->client); } diff --git a/drivers/firewire/core-device.c b/drivers/firewire/core-device.c index ef900d9..95a4714 100644 --- a/drivers/firewire/core-device.c +++ b/drivers/firewire/core-device.c @@ -725,12 +725,13 @@ struct fw_device *fw_device_get_by_devt(dev_t devt) return device; } -struct workqueue_struct *fw_wq; +struct workqueue_struct *fw_workqueue; +EXPORT_SYMBOL(fw_workqueue); static void fw_schedule_device_work(struct fw_device *device, unsigned long delay) { - queue_delayed_work(fw_wq, &device->work, delay); + queue_delayed_work(fw_workqueue, &device->work, delay); } /* diff --git a/drivers/firewire/core-transaction.c b/drivers/firewire/core-transaction.c index d4c28a2..334b82a 100644 --- a/drivers/firewire/core-transaction.c +++ b/drivers/firewire/core-transaction.c @@ -1214,21 +1214,21 @@ static int __init fw_core_init(void) { int ret; - fw_wq = alloc_workqueue(KBUILD_MODNAME, - WQ_NON_REENTRANT | WQ_MEM_RECLAIM, 0); - if (!fw_wq) + fw_workqueue = alloc_workqueue("firewire", + WQ_NON_REENTRANT | WQ_MEM_RECLAIM, 0); + if (!fw_workqueue) return -ENOMEM; ret = bus_register(&fw_bus_type); if (ret < 0) { - destroy_workqueue(fw_wq); + destroy_workqueue(fw_workqueue); return ret; } fw_cdev_major = register_chrdev(0, "firewire", &fw_device_ops); if (fw_cdev_major < 0) { bus_unregister(&fw_bus_type); - destroy_workqueue(fw_wq); + destroy_workqueue(fw_workqueue); return fw_cdev_major; } @@ -1244,7 +1244,7 @@ static void __exit fw_core_cleanup(void) { unregister_chrdev(fw_cdev_major, "firewire"); bus_unregister(&fw_bus_type); - destroy_workqueue(fw_wq); + destroy_workqueue(fw_workqueue); idr_destroy(&fw_device_idr); } diff --git a/drivers/firewire/core.h b/drivers/firewire/core.h index 00ea773..0fe4e4e 100644 --- a/drivers/firewire/core.h +++ b/drivers/firewire/core.h @@ -140,8 +140,6 @@ void fw_cdev_handle_phy_packet(struct fw_card *card, struct fw_packet *p); extern struct rw_semaphore fw_device_rwsem; extern struct idr fw_device_idr; extern int fw_cdev_major; -struct workqueue_struct; -extern struct workqueue_struct *fw_wq; struct fw_device *fw_device_get_by_devt(dev_t devt); int fw_device_set_broadcast_channel(struct device *dev, void *gen); diff --git a/drivers/firewire/sbp2.c b/drivers/firewire/sbp2.c index 2aafc61..41841a3 100644 --- a/drivers/firewire/sbp2.c +++ b/drivers/firewire/sbp2.c @@ -826,8 +826,6 @@ static void sbp2_target_put(struct sbp2_target *tgt) kref_put(&tgt->kref, sbp2_release_target); } -static struct workqueue_struct *sbp2_wq; - /* * Always get the target's kref when scheduling work on one its units. * Each workqueue job is responsible to call sbp2_target_put() upon return. @@ -835,7 +833,7 @@ static struct workqueue_struct *sbp2_wq; static void sbp2_queue_work(struct sbp2_logical_unit *lu, unsigned long delay) { sbp2_target_get(lu->tgt); - if (!queue_delayed_work(sbp2_wq, &lu->work, delay)) + if (!queue_delayed_work(fw_workqueue, &lu->work, delay)) sbp2_target_put(lu->tgt); } @@ -1645,17 +1643,12 @@ MODULE_ALIAS("sbp2"); static int __init sbp2_init(void) { - sbp2_wq = create_singlethread_workqueue(KBUILD_MODNAME); - if (!sbp2_wq) - return -ENOMEM; - return driver_register(&sbp2_driver.driver); } static void __exit sbp2_cleanup(void) { driver_unregister(&sbp2_driver.driver); - destroy_workqueue(sbp2_wq); } module_init(sbp2_init); diff --git a/include/linux/firewire.h b/include/linux/firewire.h index c0fb405..5e6f427 100644 --- a/include/linux/firewire.h +++ b/include/linux/firewire.h @@ -449,4 +449,6 @@ void fw_iso_resource_manage(struct fw_card *card, int generation, u64 channels_mask, int *channel, int *bandwidth, bool allocate); +extern struct workqueue_struct *fw_workqueue; + #endif /* _LINUX_FIREWIRE_H */ -- cgit v0.10.2 From 1f8e1cdac616e510eeb2dc2a9226bf597bc6cfd6 Mon Sep 17 00:00:00 2001 From: "Robert P. J. Day" Date: Sat, 7 May 2011 17:18:20 -0400 Subject: SYSFS: Fix erroneous comments for sysfs_update_group(). Fix what is clearly a simple copy-and-paste error in commenting the sysfs_update_group() routine. Signed-off-by: Robert P. J. Day Signed-off-by: Greg Kroah-Hartman diff --git a/fs/sysfs/group.c b/fs/sysfs/group.c index c8769dc2..194414f 100644 --- a/fs/sysfs/group.c +++ b/fs/sysfs/group.c @@ -101,9 +101,9 @@ int sysfs_create_group(struct kobject *kobj, } /** - * sysfs_update_group - given a directory kobject, create an attribute group - * @kobj: The kobject to create the group on - * @grp: The attribute group to create + * sysfs_update_group - given a directory kobject, update an attribute group + * @kobj: The kobject to update the group on + * @grp: The attribute group to update * * This function updates an attribute group. Unlike * sysfs_create_group(), it will explicitly not warn or error if any -- cgit v0.10.2 From 1fc19aff84edf97753c58cf4b858c6c4fdb246fa Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Mon, 9 May 2011 20:55:03 -0700 Subject: net: fix two lockdep splats Commit e67f88dd12f6 (net: dont hold rtnl mutex during netlink dump callbacks) switched rtnl protection to RCU, but we forgot to adjust two rcu_dereference() lockdep annotations : inet_get_link_af_size() or inet_fill_link_af() might be called with rcu_read_lock or rtnl held, so use rcu_dereference_rtnl() instead of rtnl_dereference() Reported-by: Valdis Kletnieks Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller diff --git a/net/ipv4/devinet.c b/net/ipv4/devinet.c index cd9ca08..0d4a184 100644 --- a/net/ipv4/devinet.c +++ b/net/ipv4/devinet.c @@ -1369,7 +1369,7 @@ errout: static size_t inet_get_link_af_size(const struct net_device *dev) { - struct in_device *in_dev = __in_dev_get_rtnl(dev); + struct in_device *in_dev = rcu_dereference_rtnl(dev->ip_ptr); if (!in_dev) return 0; @@ -1379,7 +1379,7 @@ static size_t inet_get_link_af_size(const struct net_device *dev) static int inet_fill_link_af(struct sk_buff *skb, const struct net_device *dev) { - struct in_device *in_dev = __in_dev_get_rtnl(dev); + struct in_device *in_dev = rcu_dereference_rtnl(dev->ip_ptr); struct nlattr *nla; int i; -- cgit v0.10.2 From 55aee10dec477254241e4f72968f92e0543b33ad Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Tue, 10 May 2011 12:22:54 -0700 Subject: vlan: fix GVRP at dismantle time MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ip link add link eth2 eth2.103 type vlan id 103 gvrp on loose_binding on ip link set eth2.103 up rmmod tg3 # driver providing eth2 BUG: unable to handle kernel NULL pointer dereference at (null) IP: [] garp_request_leave+0x3e/0xc0 [garp] PGD 11d251067 PUD 11b9e0067 PMD 0 Oops: 0000 [#1] SMP last sysfs file: /sys/devices/virtual/net/eth2.104/ifindex CPU 0 Modules linked in: tg3(-) 8021q garp nfsd lockd auth_rpcgss sunrpc libphy sg [last unloaded: x_tables] Pid: 11494, comm: rmmod Tainted: G W 2.6.39-rc6-00261-gfd71257-dirty #580 HP ProLiant BL460c G6 RIP: 0010:[] [] garp_request_leave+0x3e/0xc0 [garp] RSP: 0018:ffff88007a19bae8 EFLAGS: 00010286 RAX: 0000000000000000 RBX: ffff88011b5e2000 RCX: 0000000000000002 RDX: 0000000000000000 RSI: 0000000000000175 RDI: ffffffffa0030d5b RBP: ffff88007a19bb18 R08: 0000000000000001 R09: ffff88011bd64a00 R10: ffff88011d34ec00 R11: 0000000000000000 R12: 0000000000000002 R13: ffff88007a19bc48 R14: ffff88007a19bb88 R15: 0000000000000001 FS: 0000000000000000(0000) GS:ffff88011fc00000(0063) knlGS:00000000f77d76c0 CS: 0010 DS: 002b ES: 002b CR0: 000000008005003b CR2: 0000000000000000 CR3: 000000011a675000 CR4: 00000000000006f0 DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000 DR3: 0000000000000000 DR6: 00000000ffff0ff0 DR7: 0000000000000400 Process rmmod (pid: 11494, threadinfo ffff88007a19a000, task ffff8800798595c0) Stack: ffff88007a19bb36 ffff88011c84b800 ffff88011b5e2000 ffff88007a19bc48 ffff88007a19bb88 0000000000000006 ffff88007a19bb38 ffffffffa003a5f6 ffff88007a19bb38 670088007a19bba8 ffff88007a19bb58 ffffffffa00397e7 Call Trace: [] vlan_gvrp_request_leave+0x46/0x50 [8021q] [] vlan_dev_stop+0xb7/0xc0 [8021q] [] __dev_close_many+0x87/0xe0 [] dev_close_many+0x87/0x110 [] rollback_registered_many+0xa0/0x240 [] unregister_netdevice_many+0x19/0x60 [] vlan_device_event+0x53b/0x550 [8021q] [] ? ip6mr_device_event+0xa8/0xd0 [] notifier_call_chain+0x53/0x80 [] __raw_notifier_call_chain+0x9/0x10 [] raw_notifier_call_chain+0x11/0x20 [] call_netdevice_notifiers+0x32/0x60 [] rollback_registered_many+0x10f/0x240 [] rollback_registered+0x2f/0x40 [] unregister_netdevice_queue+0x58/0x90 [] unregister_netdev+0x1b/0x30 [] tg3_remove_one+0x6f/0x10b [tg3] We should call vlan_gvrp_request_leave() from unregister_vlan_dev(), not from vlan_dev_stop(), because vlan_gvrp_uninit_applicant() is called right after unregister_netdevice_queue(). In batch mode, unregister_netdevice_queue() doesn’t immediately call vlan_dev_stop(). Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller diff --git a/net/8021q/vlan.c b/net/8021q/vlan.c index 7850412..0eb1a88 100644 --- a/net/8021q/vlan.c +++ b/net/8021q/vlan.c @@ -124,6 +124,9 @@ void unregister_vlan_dev(struct net_device *dev, struct list_head *head) grp->nr_vlans--; + if (vlan->flags & VLAN_FLAG_GVRP) + vlan_gvrp_request_leave(dev); + vlan_group_set_device(grp, vlan_id, NULL); if (!grp->killall) synchronize_net(); diff --git a/net/8021q/vlan_dev.c b/net/8021q/vlan_dev.c index e34ea9e..b2ff6c8 100644 --- a/net/8021q/vlan_dev.c +++ b/net/8021q/vlan_dev.c @@ -487,9 +487,6 @@ static int vlan_dev_stop(struct net_device *dev) struct vlan_dev_info *vlan = vlan_dev_info(dev); struct net_device *real_dev = vlan->real_dev; - if (vlan->flags & VLAN_FLAG_GVRP) - vlan_gvrp_request_leave(dev); - dev_mc_unsync(real_dev, dev); dev_uc_unsync(real_dev, dev); if (dev->flags & IFF_ALLMULTI) -- cgit v0.10.2 From e14a599335427f81bbb0008963e59aa9c6449dce Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Tue, 10 May 2011 12:26:06 -0700 Subject: net: dev_close() should check IFF_UP Commit 443457242beb (factorize sync-rcu call in unregister_netdevice_many) mistakenly removed one test from dev_close() Following actions trigger a BUG : modprobe bonding modprobe dummy ifconfig bond0 up ifenslave bond0 dummy0 rmmod dummy dev_close() must not close a non IFF_UP device. With help from Frank Blaschka and Einar EL Lueck Reported-by: Frank Blaschka Reported-by: Einar EL Lueck Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller diff --git a/net/core/dev.c b/net/core/dev.c index 856b6ee..9200944 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -1284,11 +1284,13 @@ static int dev_close_many(struct list_head *head) */ int dev_close(struct net_device *dev) { - LIST_HEAD(single); + if (dev->flags & IFF_UP) { + LIST_HEAD(single); - list_add(&dev->unreg_list, &single); - dev_close_many(&single); - list_del(&single); + list_add(&dev->unreg_list, &single); + dev_close_many(&single); + list_del(&single); + } return 0; } EXPORT_SYMBOL(dev_close); -- cgit v0.10.2 From 43a4dea4c9d44baae38ddc14b9b6d86fde4c8b88 Mon Sep 17 00:00:00 2001 From: Steffen Klassert Date: Mon, 9 May 2011 19:36:38 +0000 Subject: xfrm: Assign the inner mode output function to the dst entry As it is, we assign the outer modes output function to the dst entry when we create the xfrm bundle. This leads to two problems on interfamily scenarios. We might insert ipv4 packets into ip6_fragment when called from xfrm6_output. The system crashes if we try to fragment an ipv4 packet with ip6_fragment. This issue was introduced with git commit ad0081e4 (ipv6: Fragment locally generated tunnel-mode IPSec6 packets as needed). The second issue is, that we might insert ipv4 packets in netfilter6 and vice versa on interfamily scenarios. With this patch we assign the inner mode output function to the dst entry when we create the xfrm bundle. So xfrm4_output/xfrm6_output from the inner mode is used and the right fragmentation and netfilter functions are called. We switch then to outer mode with the output_finish functions. Signed-off-by: Steffen Klassert Signed-off-by: David S. Miller diff --git a/include/net/xfrm.h b/include/net/xfrm.h index 6ae4bc5..20afeaa 100644 --- a/include/net/xfrm.h +++ b/include/net/xfrm.h @@ -324,6 +324,7 @@ struct xfrm_state_afinfo { int (*tmpl_sort)(struct xfrm_tmpl **dst, struct xfrm_tmpl **src, int n); int (*state_sort)(struct xfrm_state **dst, struct xfrm_state **src, int n); int (*output)(struct sk_buff *skb); + int (*output_finish)(struct sk_buff *skb); int (*extract_input)(struct xfrm_state *x, struct sk_buff *skb); int (*extract_output)(struct xfrm_state *x, @@ -1454,6 +1455,7 @@ static inline int xfrm4_rcv_spi(struct sk_buff *skb, int nexthdr, __be32 spi) extern int xfrm4_extract_output(struct xfrm_state *x, struct sk_buff *skb); extern int xfrm4_prepare_output(struct xfrm_state *x, struct sk_buff *skb); extern int xfrm4_output(struct sk_buff *skb); +extern int xfrm4_output_finish(struct sk_buff *skb); extern int xfrm4_tunnel_register(struct xfrm_tunnel *handler, unsigned short family); extern int xfrm4_tunnel_deregister(struct xfrm_tunnel *handler, unsigned short family); extern int xfrm6_extract_header(struct sk_buff *skb); @@ -1470,6 +1472,7 @@ extern __be32 xfrm6_tunnel_spi_lookup(struct net *net, xfrm_address_t *saddr); extern int xfrm6_extract_output(struct xfrm_state *x, struct sk_buff *skb); extern int xfrm6_prepare_output(struct xfrm_state *x, struct sk_buff *skb); extern int xfrm6_output(struct sk_buff *skb); +extern int xfrm6_output_finish(struct sk_buff *skb); extern int xfrm6_find_1stfragopt(struct xfrm_state *x, struct sk_buff *skb, u8 **prevhdr); diff --git a/net/ipv4/xfrm4_output.c b/net/ipv4/xfrm4_output.c index 571aa96..2d51840 100644 --- a/net/ipv4/xfrm4_output.c +++ b/net/ipv4/xfrm4_output.c @@ -69,7 +69,7 @@ int xfrm4_prepare_output(struct xfrm_state *x, struct sk_buff *skb) } EXPORT_SYMBOL(xfrm4_prepare_output); -static int xfrm4_output_finish(struct sk_buff *skb) +int xfrm4_output_finish(struct sk_buff *skb) { #ifdef CONFIG_NETFILTER if (!skb_dst(skb)->xfrm) { @@ -86,7 +86,11 @@ static int xfrm4_output_finish(struct sk_buff *skb) int xfrm4_output(struct sk_buff *skb) { + struct dst_entry *dst = skb_dst(skb); + struct xfrm_state *x = dst->xfrm; + return NF_HOOK_COND(NFPROTO_IPV4, NF_INET_POST_ROUTING, skb, - NULL, skb_dst(skb)->dev, xfrm4_output_finish, + NULL, dst->dev, + x->outer_mode->afinfo->output_finish, !(IPCB(skb)->flags & IPSKB_REROUTED)); } diff --git a/net/ipv4/xfrm4_state.c b/net/ipv4/xfrm4_state.c index 1717c64..805d63e 100644 --- a/net/ipv4/xfrm4_state.c +++ b/net/ipv4/xfrm4_state.c @@ -78,6 +78,7 @@ static struct xfrm_state_afinfo xfrm4_state_afinfo = { .init_tempsel = __xfrm4_init_tempsel, .init_temprop = xfrm4_init_temprop, .output = xfrm4_output, + .output_finish = xfrm4_output_finish, .extract_input = xfrm4_extract_input, .extract_output = xfrm4_extract_output, .transport_finish = xfrm4_transport_finish, diff --git a/net/ipv6/xfrm6_output.c b/net/ipv6/xfrm6_output.c index 8e688b3..49a91c5f 100644 --- a/net/ipv6/xfrm6_output.c +++ b/net/ipv6/xfrm6_output.c @@ -79,7 +79,7 @@ int xfrm6_prepare_output(struct xfrm_state *x, struct sk_buff *skb) } EXPORT_SYMBOL(xfrm6_prepare_output); -static int xfrm6_output_finish(struct sk_buff *skb) +int xfrm6_output_finish(struct sk_buff *skb) { #ifdef CONFIG_NETFILTER IP6CB(skb)->flags |= IP6SKB_XFRM_TRANSFORMED; @@ -97,9 +97,9 @@ static int __xfrm6_output(struct sk_buff *skb) if ((x && x->props.mode == XFRM_MODE_TUNNEL) && ((skb->len > ip6_skb_dst_mtu(skb) && !skb_is_gso(skb)) || dst_allfrag(skb_dst(skb)))) { - return ip6_fragment(skb, xfrm6_output_finish); + return ip6_fragment(skb, x->outer_mode->afinfo->output_finish); } - return xfrm6_output_finish(skb); + return x->outer_mode->afinfo->output_finish(skb); } int xfrm6_output(struct sk_buff *skb) diff --git a/net/ipv6/xfrm6_state.c b/net/ipv6/xfrm6_state.c index afe941e..248f0b2 100644 --- a/net/ipv6/xfrm6_state.c +++ b/net/ipv6/xfrm6_state.c @@ -178,6 +178,7 @@ static struct xfrm_state_afinfo xfrm6_state_afinfo = { .tmpl_sort = __xfrm6_tmpl_sort, .state_sort = __xfrm6_state_sort, .output = xfrm6_output, + .output_finish = xfrm6_output_finish, .extract_input = xfrm6_extract_input, .extract_output = xfrm6_extract_output, .transport_finish = xfrm6_transport_finish, diff --git a/net/xfrm/xfrm_policy.c b/net/xfrm/xfrm_policy.c index 15792d8..b4d745e 100644 --- a/net/xfrm/xfrm_policy.c +++ b/net/xfrm/xfrm_policy.c @@ -1406,6 +1406,7 @@ static struct dst_entry *xfrm_bundle_create(struct xfrm_policy *policy, struct net *net = xp_net(policy); unsigned long now = jiffies; struct net_device *dev; + struct xfrm_mode *inner_mode; struct dst_entry *dst_prev = NULL; struct dst_entry *dst0 = NULL; int i = 0; @@ -1436,6 +1437,17 @@ static struct dst_entry *xfrm_bundle_create(struct xfrm_policy *policy, goto put_states; } + if (xfrm[i]->sel.family == AF_UNSPEC) { + inner_mode = xfrm_ip2inner_mode(xfrm[i], + xfrm_af2proto(family)); + if (!inner_mode) { + err = -EAFNOSUPPORT; + dst_release(dst); + goto put_states; + } + } else + inner_mode = xfrm[i]->inner_mode; + if (!dst_prev) dst0 = dst1; else { @@ -1464,7 +1476,7 @@ static struct dst_entry *xfrm_bundle_create(struct xfrm_policy *policy, dst1->lastuse = now; dst1->input = dst_discard; - dst1->output = xfrm[i]->outer_mode->afinfo->output; + dst1->output = inner_mode->afinfo->output; dst1->next = dst_prev; dst_prev = dst1; -- cgit v0.10.2 From 6fa5ddcc675b937f94d05628e8997c07a80c6cb9 Mon Sep 17 00:00:00 2001 From: Steffen Klassert Date: Mon, 9 May 2011 19:43:05 +0000 Subject: xfrm: Don't allow esn with disabled anti replay detection Unlike the standard case, disabled anti replay detection needs some nontrivial extra treatment on ESN. RFC 4303 states: Note: If a receiver chooses to not enable anti-replay for an SA, then the receiver SHOULD NOT negotiate ESN in an SA management protocol. Use of ESN creates a need for the receiver to manage the anti-replay window (in order to determine the correct value for the high-order bits of the ESN, which are employed in the ICV computation), which is generally contrary to the notion of disabling anti-replay for an SA. So return an error if an ESN state with disabled anti replay detection is inserted for now and add the extra treatment later if we need it. Signed-off-by: Steffen Klassert Signed-off-by: David S. Miller diff --git a/net/xfrm/xfrm_replay.c b/net/xfrm/xfrm_replay.c index e8a7814..47f1b86 100644 --- a/net/xfrm/xfrm_replay.c +++ b/net/xfrm/xfrm_replay.c @@ -535,6 +535,9 @@ int xfrm_init_replay(struct xfrm_state *x) replay_esn->bmp_len * sizeof(__u32) * 8) return -EINVAL; + if ((x->props.flags & XFRM_STATE_ESN) && replay_esn->replay_window == 0) + return -EINVAL; + if ((x->props.flags & XFRM_STATE_ESN) && x->replay_esn) x->repl = &xfrm_replay_esn; else -- cgit v0.10.2 From aae1e743fee2b5523fb31ee050295f062cb26a31 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Mon, 9 May 2011 07:43:20 +0000 Subject: net/usb: mark LG VL600 LTE modem ethernet interface as WWAN Like other mobile broadband device ethernet interfaces, mark the LG VL600 with the 'wwan' devtype so userspace knows it needs additional configuration via the AT port before the interface can be used. Signed-off-by: Dan Williams Signed-off-by: David S. Miller diff --git a/drivers/net/usb/cdc_ether.c b/drivers/net/usb/cdc_ether.c index a301479..c924ea2 100644 --- a/drivers/net/usb/cdc_ether.c +++ b/drivers/net/usb/cdc_ether.c @@ -567,7 +567,7 @@ static const struct usb_device_id products [] = { { USB_DEVICE_AND_INTERFACE_INFO(0x1004, 0x61aa, USB_CLASS_COMM, USB_CDC_SUBCLASS_ETHERNET, USB_CDC_PROTO_NONE), - .driver_info = 0, + .driver_info = (unsigned long)&wwan_info, }, /* -- cgit v0.10.2 From 0d4420a90b51abdea71585f571bad6d789ff8eb7 Mon Sep 17 00:00:00 2001 From: Oliver Hartkopp Date: Tue, 10 May 2011 13:12:30 -0700 Subject: slcan: fix ldisc->open retval TTY layer expects 0 if the ldisc->open operation succeeded. Reported-by: Matvejchikov Ilya Signed-off-by: Oliver Hartkopp Signed-off-by: David S. Miller diff --git a/drivers/net/can/slcan.c b/drivers/net/can/slcan.c index b423965..1b49df6 100644 --- a/drivers/net/can/slcan.c +++ b/drivers/net/can/slcan.c @@ -583,7 +583,9 @@ static int slcan_open(struct tty_struct *tty) /* Done. We have linked the TTY line to a channel. */ rtnl_unlock(); tty->receive_room = 65536; /* We don't flow control */ - return sl->dev->base_addr; + + /* TTY layer expects 0 on success */ + return 0; err_free_chan: sl->tty = NULL; -- cgit v0.10.2 From 21a43e397e7f66d3be44e09b54045f1a67838cc0 Mon Sep 17 00:00:00 2001 From: David Rientjes Date: Tue, 10 May 2011 17:08:54 -0700 Subject: slub: Revert "[PARISC] slub: fix panic with DISCONTIGMEM" This reverts commit 4a5fa3590f09, which did not allow SLUB to be used on architectures that use DISCONTIGMEM without compiling NUMA support without CONFIG_BROKEN also set. The slub panic that it was intended to prevent is addressed by d9b41e0b54fd ("[PARISC] set memory ranges in N_NORMAL_MEMORY when onlined") on parisc so there is no further slub issues with such a configuration. The reverts allows SLUB now to be used on such architectures since there haven't been any reports of additional errors. Cc: James Bottomley Signed-off-by: David Rientjes Signed-off-by: Linus Torvalds diff --git a/init/Kconfig b/init/Kconfig index d886b1e..7a71e0a 100644 --- a/init/Kconfig +++ b/init/Kconfig @@ -1226,7 +1226,6 @@ config SLAB per cpu and per node queues. config SLUB - depends on BROKEN || NUMA || !DISCONTIGMEM bool "SLUB (Unqueued Allocator)" help SLUB is a slab allocator that minimizes cache line usage -- cgit v0.10.2 From 285e042dcd9fe9a9b7fbfdc215e4d076791ded8e Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Mon, 9 May 2011 14:54:33 +1000 Subject: drm/radeon: fix cayman struct accessors. We are accessing totally the wrong struct in this case, and putting uninitialised values into the GPU, which it doesn't like unsurprisingly. Signed-off-by: Dave Airlie diff --git a/drivers/gpu/drm/radeon/ni.c b/drivers/gpu/drm/radeon/ni.c index 7aade20..e9e45ea 100644 --- a/drivers/gpu/drm/radeon/ni.c +++ b/drivers/gpu/drm/radeon/ni.c @@ -871,7 +871,7 @@ static void cayman_gpu_init(struct radeon_device *rdev) smx_dc_ctl0 = RREG32(SMX_DC_CTL0); smx_dc_ctl0 &= ~NUMBER_OF_SETS(0x1ff); - smx_dc_ctl0 |= NUMBER_OF_SETS(rdev->config.evergreen.sx_num_of_sets); + smx_dc_ctl0 |= NUMBER_OF_SETS(rdev->config.cayman.sx_num_of_sets); WREG32(SMX_DC_CTL0, smx_dc_ctl0); WREG32(SPI_CONFIG_CNTL_1, VTX_DONE_DELAY(4) | CRC_SIMD_ID_WADDR_DISABLE); @@ -887,20 +887,20 @@ static void cayman_gpu_init(struct radeon_device *rdev) WREG32(TA_CNTL_AUX, DISABLE_CUBE_ANISO); - WREG32(SX_EXPORT_BUFFER_SIZES, (COLOR_BUFFER_SIZE((rdev->config.evergreen.sx_max_export_size / 4) - 1) | - POSITION_BUFFER_SIZE((rdev->config.evergreen.sx_max_export_pos_size / 4) - 1) | - SMX_BUFFER_SIZE((rdev->config.evergreen.sx_max_export_smx_size / 4) - 1))); + WREG32(SX_EXPORT_BUFFER_SIZES, (COLOR_BUFFER_SIZE((rdev->config.cayman.sx_max_export_size / 4) - 1) | + POSITION_BUFFER_SIZE((rdev->config.cayman.sx_max_export_pos_size / 4) - 1) | + SMX_BUFFER_SIZE((rdev->config.cayman.sx_max_export_smx_size / 4) - 1))); - WREG32(PA_SC_FIFO_SIZE, (SC_PRIM_FIFO_SIZE(rdev->config.evergreen.sc_prim_fifo_size) | - SC_HIZ_TILE_FIFO_SIZE(rdev->config.evergreen.sc_hiz_tile_fifo_size) | - SC_EARLYZ_TILE_FIFO_SIZE(rdev->config.evergreen.sc_earlyz_tile_fifo_size))); + WREG32(PA_SC_FIFO_SIZE, (SC_PRIM_FIFO_SIZE(rdev->config.cayman.sc_prim_fifo_size) | + SC_HIZ_TILE_FIFO_SIZE(rdev->config.cayman.sc_hiz_tile_fifo_size) | + SC_EARLYZ_TILE_FIFO_SIZE(rdev->config.cayman.sc_earlyz_tile_fifo_size))); WREG32(VGT_NUM_INSTANCES, 1); WREG32(CP_PERFMON_CNTL, 0); - WREG32(SQ_MS_FIFO_SIZES, (CACHE_FIFO_SIZE(16 * rdev->config.evergreen.sq_num_cf_insts) | + WREG32(SQ_MS_FIFO_SIZES, (CACHE_FIFO_SIZE(16 * rdev->config.cayman.sq_num_cf_insts) | FETCH_FIFO_HIWATER(0x4) | DONE_FIFO_HIWATER(0xe0) | ALU_UPDATE_FIFO_HIWATER(0x8))); -- cgit v0.10.2 From 1f03128251b77bfc68d1578a4f11316eb3806238 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Tue, 10 May 2011 02:14:52 +0000 Subject: drm/radeon/kms: fix cayman acceleration The TCC disable setup was incorrect. This prevents the GPU from hanging when draw commands are issued. Signed-off-by: Alex Deucher Signed-off-by: Dave Airlie diff --git a/drivers/gpu/drm/radeon/ni.c b/drivers/gpu/drm/radeon/ni.c index e9e45ea..3d8a763 100644 --- a/drivers/gpu/drm/radeon/ni.c +++ b/drivers/gpu/drm/radeon/ni.c @@ -674,7 +674,7 @@ static void cayman_gpu_init(struct radeon_device *rdev) cc_rb_backend_disable = RREG32(CC_RB_BACKEND_DISABLE); cc_gc_shader_pipe_config = RREG32(CC_GC_SHADER_PIPE_CONFIG); - cgts_tcc_disable = RREG32(CGTS_TCC_DISABLE); + cgts_tcc_disable = 0xff000000; gc_user_rb_backend_disable = RREG32(GC_USER_RB_BACKEND_DISABLE); gc_user_shader_pipe_config = RREG32(GC_USER_SHADER_PIPE_CONFIG); cgts_user_tcc_disable = RREG32(CGTS_USER_TCC_DISABLE); -- cgit v0.10.2 From 03a80665341bbb9a57064c2ddeca13b554d56893 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Mon, 9 May 2011 02:24:04 +0000 Subject: drm/radeon/nouveau: fix build regression on alpha due to Xen changes. The Xen changes were using DMA_ERROR_CODE which isn't defined on a few platforms, however we reverted the Xen patch that caused use to try and use this code path earlier in 2.6.39 cycle, so for now lets just force the code to never take this path and allow it to build again on alpha. The proper long term answer is probably to store if the dma_addr has been assigned to alongside the dma_addr in the higher level code, though I think Thomas wanted to rewrite most of this anyways properly. Acked-by: Konrad Rzeszutek Wilk Signed-off-by: Dave Airlie diff --git a/drivers/gpu/drm/nouveau/nouveau_sgdma.c b/drivers/gpu/drm/nouveau/nouveau_sgdma.c index 4bce801..c77111e 100644 --- a/drivers/gpu/drm/nouveau/nouveau_sgdma.c +++ b/drivers/gpu/drm/nouveau/nouveau_sgdma.c @@ -42,7 +42,8 @@ nouveau_sgdma_populate(struct ttm_backend *be, unsigned long num_pages, nvbe->nr_pages = 0; while (num_pages--) { - if (dma_addrs[nvbe->nr_pages] != DMA_ERROR_CODE) { + /* this code path isn't called and is incorrect anyways */ + if (0) { /*dma_addrs[nvbe->nr_pages] != DMA_ERROR_CODE)*/ nvbe->pages[nvbe->nr_pages] = dma_addrs[nvbe->nr_pages]; nvbe->ttm_alloced[nvbe->nr_pages] = true; diff --git a/drivers/gpu/drm/radeon/radeon_gart.c b/drivers/gpu/drm/radeon/radeon_gart.c index 8a955bb..a533f52 100644 --- a/drivers/gpu/drm/radeon/radeon_gart.c +++ b/drivers/gpu/drm/radeon/radeon_gart.c @@ -181,9 +181,9 @@ int radeon_gart_bind(struct radeon_device *rdev, unsigned offset, p = t / (PAGE_SIZE / RADEON_GPU_PAGE_SIZE); for (i = 0; i < pages; i++, p++) { - /* On TTM path, we only use the DMA API if TTM_PAGE_FLAG_DMA32 - * is requested. */ - if (dma_addr[i] != DMA_ERROR_CODE) { + /* we reverted the patch using dma_addr in TTM for now but this + * code stops building on alpha so just comment it out for now */ + if (0) { /*dma_addr[i] != DMA_ERROR_CODE) */ rdev->gart.ttm_alloced[p] = true; rdev->gart.pages_addr[p] = dma_addr[i]; } else { -- cgit v0.10.2 From 042e9e73561aa406b872f3e310bdc9477c379cb3 Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Thu, 5 May 2011 15:28:57 +0200 Subject: crypto: mv_cesa - use ablkcipher_request_cast instead of the manual container_of Signed-off-by: Phil Sutter Signed-off-by: Herbert Xu diff --git a/drivers/crypto/mv_cesa.c b/drivers/crypto/mv_cesa.c index c99305a..c443246 100644 --- a/drivers/crypto/mv_cesa.c +++ b/drivers/crypto/mv_cesa.c @@ -603,9 +603,7 @@ static int queue_manag(void *data) if (async_req->tfm->__crt_alg->cra_type != &crypto_ahash_type) { struct ablkcipher_request *req = - container_of(async_req, - struct ablkcipher_request, - base); + ablkcipher_request_cast(async_req); mv_start_new_crypt_req(req); } else { struct ahash_request *req = -- cgit v0.10.2 From 99db3eacac81e50225d8a3571e32d692428f6920 Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Thu, 5 May 2011 15:28:58 +0200 Subject: crypto: mv_cesa - the descriptor pointer register needs to be set just once Signed-off-by: Phil Sutter Signed-off-by: Herbert Xu diff --git a/drivers/crypto/mv_cesa.c b/drivers/crypto/mv_cesa.c index c443246..889c098 100644 --- a/drivers/crypto/mv_cesa.c +++ b/drivers/crypto/mv_cesa.c @@ -275,7 +275,6 @@ static void mv_process_current_q(int first_block) memcpy(cpg->sram + SRAM_CONFIG, &op, sizeof(struct sec_accel_config)); - writel(SRAM_CONFIG, cpg->reg + SEC_ACCEL_DESC_P0); /* GO */ writel(SEC_CMD_EN_SEC_ACCL0, cpg->reg + SEC_ACCEL_CMD); @@ -349,7 +348,6 @@ static void mv_process_hash_current(int first_block) memcpy(cpg->sram + SRAM_CONFIG, &op, sizeof(struct sec_accel_config)); - writel(SRAM_CONFIG, cpg->reg + SEC_ACCEL_DESC_P0); /* GO */ writel(SEC_CMD_EN_SEC_ACCL0, cpg->reg + SEC_ACCEL_CMD); @@ -1063,6 +1061,7 @@ static int mv_probe(struct platform_device *pdev) writel(SEC_INT_ACCEL0_DONE, cpg->reg + SEC_ACCEL_INT_MASK); writel(SEC_CFG_STOP_DIG_ERR, cpg->reg + SEC_ACCEL_CFG); + writel(SRAM_CONFIG, cpg->reg + SEC_ACCEL_DESC_P0); ret = crypto_register_alg(&mv_aes_alg_ecb); if (ret) -- cgit v0.10.2 From 811e6ed62347f1042ab1c560e5e2ebc8892f7f8f Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Thu, 5 May 2011 15:28:59 +0200 Subject: crypto: mv_cesa - drop this call to mv_hash_final from mv_hash_finup The code in mv_hash_final is actually a superset of mv_hash_finup's body. Since the driver works fine without, drop it. Signed-off-by: Phil Sutter Signed-off-by: Herbert Xu diff --git a/drivers/crypto/mv_cesa.c b/drivers/crypto/mv_cesa.c index 889c098..4aac294 100644 --- a/drivers/crypto/mv_cesa.c +++ b/drivers/crypto/mv_cesa.c @@ -728,9 +728,6 @@ static int mv_hash_final(struct ahash_request *req) static int mv_hash_finup(struct ahash_request *req) { - if (!req->nbytes) - return mv_hash_final(req); - mv_update_hash_req_ctx(ahash_request_ctx(req), 1, req->nbytes); return mv_handle_req(&req->base); } -- cgit v0.10.2 From 2a025f5dfcfaf7348fff6bda3ea007144f7eb47c Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Thu, 5 May 2011 15:29:00 +0200 Subject: crypto: mv_cesa - print a warning when registration of AES algos fail Signed-off-by: Phil Sutter Signed-off-by: Herbert Xu diff --git a/drivers/crypto/mv_cesa.c b/drivers/crypto/mv_cesa.c index 4aac294..c018cd0 100644 --- a/drivers/crypto/mv_cesa.c +++ b/drivers/crypto/mv_cesa.c @@ -1061,12 +1061,18 @@ static int mv_probe(struct platform_device *pdev) writel(SRAM_CONFIG, cpg->reg + SEC_ACCEL_DESC_P0); ret = crypto_register_alg(&mv_aes_alg_ecb); - if (ret) + if (ret) { + printk(KERN_WARNING MV_CESA + "Could not register aes-ecb driver\n"); goto err_irq; + } ret = crypto_register_alg(&mv_aes_alg_cbc); - if (ret) + if (ret) { + printk(KERN_WARNING MV_CESA + "Could not register aes-cbc driver\n"); goto err_unreg_ecb; + } ret = crypto_register_ahash(&mv_sha1_alg); if (ret == 0) -- cgit v0.10.2 From 7a1c6bcf269203485d716d8e3bec6671dabb5067 Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Thu, 5 May 2011 15:29:01 +0200 Subject: crypto: mv_cesa - no need to save digest state after the last chunk Signed-off-by: Phil Sutter Signed-off-by: Herbert Xu diff --git a/drivers/crypto/mv_cesa.c b/drivers/crypto/mv_cesa.c index c018cd0..fb3f1e3 100644 --- a/drivers/crypto/mv_cesa.c +++ b/drivers/crypto/mv_cesa.c @@ -407,12 +407,6 @@ static void mv_hash_algo_completion(void) copy_src_to_buf(&cpg->p, ctx->buffer, ctx->extra_bytes); sg_miter_stop(&cpg->p.src_sg_it); - ctx->state[0] = readl(cpg->reg + DIGEST_INITIAL_VAL_A); - ctx->state[1] = readl(cpg->reg + DIGEST_INITIAL_VAL_B); - ctx->state[2] = readl(cpg->reg + DIGEST_INITIAL_VAL_C); - ctx->state[3] = readl(cpg->reg + DIGEST_INITIAL_VAL_D); - ctx->state[4] = readl(cpg->reg + DIGEST_INITIAL_VAL_E); - if (likely(ctx->last_chunk)) { if (likely(ctx->count <= MAX_HW_HASH_SIZE)) { memcpy(req->result, cpg->sram + SRAM_DIGEST_BUF, @@ -420,6 +414,12 @@ static void mv_hash_algo_completion(void) (req))); } else mv_hash_final_fallback(req); + } else { + ctx->state[0] = readl(cpg->reg + DIGEST_INITIAL_VAL_A); + ctx->state[1] = readl(cpg->reg + DIGEST_INITIAL_VAL_B); + ctx->state[2] = readl(cpg->reg + DIGEST_INITIAL_VAL_C); + ctx->state[3] = readl(cpg->reg + DIGEST_INITIAL_VAL_D); + ctx->state[4] = readl(cpg->reg + DIGEST_INITIAL_VAL_E); } } -- cgit v0.10.2 From 6677a776cf3dc4950a790946f88d26dafc4baf7b Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Thu, 5 May 2011 15:29:02 +0200 Subject: crypto: mv_cesa - refactor copy_src_to_buf() The main goal was to have it not do anything when a zero len parameter was being passed (which could lead to a null pointer dereference, as in this case p->src_sg is null, either). Using the min() macro, the lower part of the loop gets simpler, too. Signed-off-by: Phil Sutter Signed-off-by: Herbert Xu diff --git a/drivers/crypto/mv_cesa.c b/drivers/crypto/mv_cesa.c index fb3f1e3..de09303 100644 --- a/drivers/crypto/mv_cesa.c +++ b/drivers/crypto/mv_cesa.c @@ -187,9 +187,9 @@ static void copy_src_to_buf(struct req_progress *p, char *dbuf, int len) { int ret; void *sbuf; - int copied = 0; + int copy_len; - while (1) { + while (len) { if (!p->sg_src_left) { ret = sg_miter_next(&p->src_sg_it); BUG_ON(!ret); @@ -199,19 +199,14 @@ static void copy_src_to_buf(struct req_progress *p, char *dbuf, int len) sbuf = p->src_sg_it.addr + p->src_start; - if (p->sg_src_left <= len - copied) { - memcpy(dbuf + copied, sbuf, p->sg_src_left); - copied += p->sg_src_left; - p->sg_src_left = 0; - if (copied >= len) - break; - } else { - int copy_len = len - copied; - memcpy(dbuf + copied, sbuf, copy_len); - p->src_start += copy_len; - p->sg_src_left -= copy_len; - break; - } + copy_len = min(p->sg_src_left, len); + memcpy(dbuf, sbuf, copy_len); + + p->src_start += copy_len; + p->sg_src_left -= copy_len; + + len -= copy_len; + dbuf += copy_len; } } -- cgit v0.10.2 From cc8d35057ce7ae2f88cc65be0f839316c4641332 Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Thu, 5 May 2011 15:29:03 +0200 Subject: crypto: mv_cesa - fill inner/outer IV fields only in HMAC case Signed-off-by: Phil Sutter Signed-off-by: Herbert Xu diff --git a/drivers/crypto/mv_cesa.c b/drivers/crypto/mv_cesa.c index de09303..c1925c2 100644 --- a/drivers/crypto/mv_cesa.c +++ b/drivers/crypto/mv_cesa.c @@ -296,6 +296,7 @@ static void mv_crypto_algo_completion(void) static void mv_process_hash_current(int first_block) { struct ahash_request *req = ahash_request_cast(cpg->cur_req); + const struct mv_tfm_hash_ctx *tfm_ctx = crypto_tfm_ctx(req->base.tfm); struct mv_req_hash_ctx *req_ctx = ahash_request_ctx(req); struct req_progress *p = &cpg->p; struct sec_accel_config op = { 0 }; @@ -308,6 +309,8 @@ static void mv_process_hash_current(int first_block) break; case COP_HMAC_SHA1: op.config = CFG_OP_MAC_ONLY | CFG_MACM_HMAC_SHA1; + memcpy(cpg->sram + SRAM_HMAC_IV_IN, + tfm_ctx->ivs, sizeof(tfm_ctx->ivs)); break; } @@ -510,7 +513,6 @@ static void mv_start_new_hash_req(struct ahash_request *req) { struct req_progress *p = &cpg->p; struct mv_req_hash_ctx *ctx = ahash_request_ctx(req); - const struct mv_tfm_hash_ctx *tfm_ctx = crypto_tfm_ctx(req->base.tfm); int num_sgs, hw_bytes, old_extra_bytes, rc; cpg->cur_req = &req->base; memset(p, 0, sizeof(struct req_progress)); @@ -523,8 +525,6 @@ static void mv_start_new_hash_req(struct ahash_request *req) p->crypt_len = ctx->extra_bytes; } - memcpy(cpg->sram + SRAM_HMAC_IV_IN, tfm_ctx->ivs, sizeof(tfm_ctx->ivs)); - if (unlikely(!ctx->first_hash)) { writel(ctx->state[0], cpg->reg + DIGEST_INITIAL_VAL_A); writel(ctx->state[1], cpg->reg + DIGEST_INITIAL_VAL_B); -- cgit v0.10.2 From 8652348754a1f538daa1eab248e5c9c4c3600204 Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Thu, 5 May 2011 15:29:04 +0200 Subject: crypto: mv_cesa - move digest state initialisation to a better place On one hand, the digest state registers need to be set only when actually using the crypto engine. On the other hand, there is a check for ctx->first_hash in mv_process_hash_current() already, so use that. Signed-off-by: Phil Sutter Signed-off-by: Herbert Xu diff --git a/drivers/crypto/mv_cesa.c b/drivers/crypto/mv_cesa.c index c1925c2..a2d9e39 100644 --- a/drivers/crypto/mv_cesa.c +++ b/drivers/crypto/mv_cesa.c @@ -342,6 +342,12 @@ static void mv_process_hash_current(int first_block) op.config |= CFG_LAST_FRAG; else op.config |= CFG_MID_FRAG; + + writel(req_ctx->state[0], cpg->reg + DIGEST_INITIAL_VAL_A); + writel(req_ctx->state[1], cpg->reg + DIGEST_INITIAL_VAL_B); + writel(req_ctx->state[2], cpg->reg + DIGEST_INITIAL_VAL_C); + writel(req_ctx->state[3], cpg->reg + DIGEST_INITIAL_VAL_D); + writel(req_ctx->state[4], cpg->reg + DIGEST_INITIAL_VAL_E); } memcpy(cpg->sram + SRAM_CONFIG, &op, sizeof(struct sec_accel_config)); @@ -525,14 +531,6 @@ static void mv_start_new_hash_req(struct ahash_request *req) p->crypt_len = ctx->extra_bytes; } - if (unlikely(!ctx->first_hash)) { - writel(ctx->state[0], cpg->reg + DIGEST_INITIAL_VAL_A); - writel(ctx->state[1], cpg->reg + DIGEST_INITIAL_VAL_B); - writel(ctx->state[2], cpg->reg + DIGEST_INITIAL_VAL_C); - writel(ctx->state[3], cpg->reg + DIGEST_INITIAL_VAL_D); - writel(ctx->state[4], cpg->reg + DIGEST_INITIAL_VAL_E); - } - ctx->extra_bytes = hw_bytes % SHA1_BLOCK_SIZE; if (ctx->extra_bytes != 0 && (!ctx->last_chunk || ctx->count > MAX_HW_HASH_SIZE)) -- cgit v0.10.2 From 7759995c75ae0cbd4c861582908449f6b6208e7a Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Thu, 5 May 2011 15:29:05 +0200 Subject: crypto: mv_cesa - copy remaining bytes to SRAM only when needed Signed-off-by: Phil Sutter Signed-off-by: Herbert Xu diff --git a/drivers/crypto/mv_cesa.c b/drivers/crypto/mv_cesa.c index a2d9e39..d704ed0 100644 --- a/drivers/crypto/mv_cesa.c +++ b/drivers/crypto/mv_cesa.c @@ -525,12 +525,6 @@ static void mv_start_new_hash_req(struct ahash_request *req) hw_bytes = req->nbytes + ctx->extra_bytes; old_extra_bytes = ctx->extra_bytes; - if (unlikely(ctx->extra_bytes)) { - memcpy(cpg->sram + SRAM_DATA_IN_START, ctx->buffer, - ctx->extra_bytes); - p->crypt_len = ctx->extra_bytes; - } - ctx->extra_bytes = hw_bytes % SHA1_BLOCK_SIZE; if (ctx->extra_bytes != 0 && (!ctx->last_chunk || ctx->count > MAX_HW_HASH_SIZE)) @@ -546,6 +540,12 @@ static void mv_start_new_hash_req(struct ahash_request *req) p->complete = mv_hash_algo_completion; p->process = mv_process_hash_current; + if (unlikely(old_extra_bytes)) { + memcpy(cpg->sram + SRAM_DATA_IN_START, ctx->buffer, + old_extra_bytes); + p->crypt_len = old_extra_bytes; + } + mv_process_hash_current(1); } else { copy_src_to_buf(p, ctx->buffer + old_extra_bytes, -- cgit v0.10.2 From 6ef84509f3d439ed2d43ea40080643efec37f54f Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Thu, 5 May 2011 15:29:06 +0200 Subject: crypto: mv_cesa - make count_sgs() null-pointer proof This also makes the dummy scatterlist in mv_hash_final() needless, so drop it. XXX: should this routine be made pulicly available? There are probably other users with their own implementations. Signed-off-by: Phil Sutter Signed-off-by: Herbert Xu diff --git a/drivers/crypto/mv_cesa.c b/drivers/crypto/mv_cesa.c index d704ed0..3cf303e 100644 --- a/drivers/crypto/mv_cesa.c +++ b/drivers/crypto/mv_cesa.c @@ -133,7 +133,6 @@ struct mv_req_hash_ctx { int extra_bytes; /* unprocessed bytes in buffer */ enum hash_op op; int count_add; - struct scatterlist dummysg; }; static void compute_aes_dec_key(struct mv_ctx *ctx) @@ -482,7 +481,7 @@ static int count_sgs(struct scatterlist *sl, unsigned int total_bytes) int i = 0; size_t cur_len; - while (1) { + while (sl) { cur_len = sl[i].length; ++i; if (total_bytes > cur_len) @@ -711,10 +710,7 @@ static int mv_hash_update(struct ahash_request *req) static int mv_hash_final(struct ahash_request *req) { struct mv_req_hash_ctx *ctx = ahash_request_ctx(req); - /* dummy buffer of 4 bytes */ - sg_init_one(&ctx->dummysg, ctx->buffer, 4); - /* I think I'm allowed to do that... */ - ahash_request_set_crypt(req, &ctx->dummysg, req->result, 0); + mv_update_hash_req_ctx(ctx, 1, 0); return mv_handle_req(&req->base); } -- cgit v0.10.2 From 8aa4d96fe3e4cda9a6469b22b3f017ed30996b10 Mon Sep 17 00:00:00 2001 From: Daniel Drake Date: Tue, 10 May 2011 22:34:11 +0100 Subject: viafb: Automatic OLPC XO-1.5 configuration Currently, a long set of viafb options are needed to get the XO-1.5 laptop to output video (there is only 1 configuration that works, that can't really be autodetected). This patch automatically detects and configures viafb for the XO-1.5 laptop, meaning all that is required for working display is that viafb is loaded. Signed-off-by: Daniel Drake Signed-off-by: Florian Tobias Schandinat diff --git a/drivers/video/via/viafbdev.c b/drivers/video/via/viafbdev.c index eace9a4..3114a87 100644 --- a/drivers/video/via/viafbdev.c +++ b/drivers/video/via/viafbdev.c @@ -24,6 +24,7 @@ #include #include #include +#include #define _MASTER_FILE #include "global.h" @@ -1011,8 +1012,13 @@ static int __init parse_active_dev(void) /* Note: The previous of active_dev is primary device, and the following is secondary device. */ if (!viafb_active_dev) { - viafb_CRT_ON = STATE_ON; - viafb_SAMM_ON = STATE_OFF; + if (machine_is_olpc()) { /* LCD only */ + viafb_LCD_ON = STATE_ON; + viafb_SAMM_ON = STATE_OFF; + } else { + viafb_CRT_ON = STATE_ON; + viafb_SAMM_ON = STATE_OFF; + } } else if (!strcmp(viafb_active_dev, "CRT+DVI")) { /* CRT+DVI */ viafb_CRT_ON = STATE_ON; @@ -1665,8 +1671,13 @@ static int parse_mode(const char *str, u32 *xres, u32 *yres) char *ptr; if (!str) { - *xres = 640; - *yres = 480; + if (machine_is_olpc()) { + *xres = 1200; + *yres = 900; + } else { + *xres = 640; + *yres = 480; + } return 0; } @@ -1922,11 +1933,16 @@ void __devexit via_fb_pci_remove(struct pci_dev *pdev) } #ifndef MODULE -static int __init viafb_setup(char *options) +static int __init viafb_setup(void) { char *this_opt; + char *options; + DEBUG_MSG(KERN_INFO "viafb_setup!\n"); + if (fb_get_options("viafb", &options)) + return -ENODEV; + if (!options || !*options) return 0; @@ -2000,11 +2016,16 @@ static int __init viafb_setup(char *options) int __init viafb_init(void) { u32 dummy_x, dummy_y; + int r; + + if (machine_is_olpc()) + /* Apply XO-1.5-specific configuration. */ + viafb_lcd_panel_id = 23; + #ifndef MODULE - char *option = NULL; - if (fb_get_options("viafb", &option)) - return -ENODEV; - viafb_setup(option); + r = viafb_setup(); + if (r < 0) + return r; #endif if (parse_mode(viafb_mode, &dummy_x, &dummy_y) || !viafb_get_mode(dummy_x, dummy_y) -- cgit v0.10.2 From 557f447f21621de9c5447c8702c33b53279822ce Mon Sep 17 00:00:00 2001 From: Juergen Kilb Date: Thu, 14 Apr 2011 09:31:43 +0200 Subject: mfd: Fixed gpio polarity of omap-usb gpio USB-phy reset With commit 19403165 a main part of ehci-omap.c moved to drivers/mfd/omap-usb-host.c created by commit 17cdd29d. Due to this reorganisation the polarity used to reset the external USB phy changed and USB host doesn't recognize any devices. Signed-off-by: Juergen Kilb Acked-by: Felipe Balbi Tested-by: Steve Sakoman Signed-off-by: Samuel Ortiz diff --git a/drivers/mfd/omap-usb-host.c b/drivers/mfd/omap-usb-host.c index 2e16511..3ab9ffa 100644 --- a/drivers/mfd/omap-usb-host.c +++ b/drivers/mfd/omap-usb-host.c @@ -717,14 +717,14 @@ static int usbhs_enable(struct device *dev) gpio_request(pdata->ehci_data->reset_gpio_port[0], "USB1 PHY reset"); gpio_direction_output - (pdata->ehci_data->reset_gpio_port[0], 1); + (pdata->ehci_data->reset_gpio_port[0], 0); } if (gpio_is_valid(pdata->ehci_data->reset_gpio_port[1])) { gpio_request(pdata->ehci_data->reset_gpio_port[1], "USB2 PHY reset"); gpio_direction_output - (pdata->ehci_data->reset_gpio_port[1], 1); + (pdata->ehci_data->reset_gpio_port[1], 0); } /* Hold the PHY in RESET for enough time till DIR is high */ @@ -904,11 +904,11 @@ static int usbhs_enable(struct device *dev) if (gpio_is_valid(pdata->ehci_data->reset_gpio_port[0])) gpio_set_value - (pdata->ehci_data->reset_gpio_port[0], 0); + (pdata->ehci_data->reset_gpio_port[0], 1); if (gpio_is_valid(pdata->ehci_data->reset_gpio_port[1])) gpio_set_value - (pdata->ehci_data->reset_gpio_port[1], 0); + (pdata->ehci_data->reset_gpio_port[1], 1); } end_count: -- cgit v0.10.2 From a09aee8b636a3b2b7b10ad57d60d91e9272e771d Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Thu, 14 Apr 2011 22:43:47 +0800 Subject: mfd: Fix asic3 build error Fix below compile error: CC drivers/mfd/asic3.o drivers/mfd/asic3.c: In function 'asic3_irq_demux': drivers/mfd/asic3.c:147: error: 'irq_data' undeclared (first use in this function) drivers/mfd/asic3.c:147: error: (Each undeclared identifier is reported only once drivers/mfd/asic3.c:147: error: for each function it appears in.) Signed-off-by: Axel Lin Signed-off-by: Samuel Ortiz diff --git a/drivers/mfd/asic3.c b/drivers/mfd/asic3.c index d4a851c..0b4d5b2 100644 --- a/drivers/mfd/asic3.c +++ b/drivers/mfd/asic3.c @@ -144,7 +144,7 @@ static void asic3_irq_demux(unsigned int irq, struct irq_desc *desc) int iter, i; unsigned long flags; - data->chip->irq_ack(irq_data); + data->chip->irq_ack(data); for (iter = 0 ; iter < MAX_ASIC_ISR_LOOPS; iter++) { u32 status; -- cgit v0.10.2 From c62dd365e248222903e6e3e3a8f5d8587e7e3345 Mon Sep 17 00:00:00 2001 From: Lesly A M Date: Thu, 14 Apr 2011 17:57:49 +0530 Subject: mfd: Fix for the TWL4030 PM sleep/wakeup sequence Only configure sleep script when the flag is TWL4030_SLEEP_SCRIPT. Adding the missing brackets for fixing the issue. Signed-off-by: Lesly A M Cc: Nishanth Menon Cc: David Derrick Signed-off-by: Samuel Ortiz diff --git a/drivers/mfd/twl4030-power.c b/drivers/mfd/twl4030-power.c index 16422de0..2c0d4d1 100644 --- a/drivers/mfd/twl4030-power.c +++ b/drivers/mfd/twl4030-power.c @@ -447,12 +447,13 @@ static int __init load_twl4030_script(struct twl4030_script *tscript, if (err) goto out; } - if (tscript->flags & TWL4030_SLEEP_SCRIPT) + if (tscript->flags & TWL4030_SLEEP_SCRIPT) { if (order) pr_warning("TWL4030: Bad order of scripts (sleep "\ "script before wakeup) Leads to boot"\ "failure on some boards\n"); err = twl4030_config_sleep_sequence(address); + } out: return err; } -- cgit v0.10.2 From 9bbeacf52f66d165739a4bbe9c018d17493a74b5 Mon Sep 17 00:00:00 2001 From: Jiri Olsa Date: Wed, 11 May 2011 13:06:13 +0200 Subject: kprobes, x86: Disable irqs during optimized callback Disable irqs during optimized callback, so we dont miss any in-irq kprobes. The following commands: # cd /debug/tracing/ # echo "p mutex_unlock" >> kprobe_events # echo "p _raw_spin_lock" >> kprobe_events # echo "p smp_apic_timer_interrupt" >> ./kprobe_events # echo 1 > events/enable Cause the optimized kprobes to be missed. None is missed with the fix applied. Signed-off-by: Jiri Olsa Acked-by: Masami Hiramatsu Link: http://lkml.kernel.org/r/20110511110613.GB2390@jolsa.brq.redhat.com Signed-off-by: Ingo Molnar diff --git a/arch/x86/kernel/kprobes.c b/arch/x86/kernel/kprobes.c index c969fd9..f1a6244d 100644 --- a/arch/x86/kernel/kprobes.c +++ b/arch/x86/kernel/kprobes.c @@ -1183,12 +1183,13 @@ static void __kprobes optimized_callback(struct optimized_kprobe *op, struct pt_regs *regs) { struct kprobe_ctlblk *kcb = get_kprobe_ctlblk(); + unsigned long flags; /* This is possible if op is under delayed unoptimizing */ if (kprobe_disabled(&op->kp)) return; - preempt_disable(); + local_irq_save(flags); if (kprobe_running()) { kprobes_inc_nmissed_count(&op->kp); } else { @@ -1207,7 +1208,7 @@ static void __kprobes optimized_callback(struct optimized_kprobe *op, opt_pre_handler(&op->kp, regs); __this_cpu_write(current_kprobe, NULL); } - preempt_enable_no_resched(); + local_irq_restore(flags); } static int __kprobes copy_optimized_instructions(u8 *dest, u8 *src) -- cgit v0.10.2 From 9fcce61c0eddbe21f42cb47bd5a366a6eb7956ce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= Date: Sun, 8 May 2011 20:30:31 +0200 Subject: ssb: update list of devices supporting multiple 80211 cores MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Some of the BCM43xx chips contain cores that are attached to the SSB, but are inactive as they do not connect to the external environment. These must not be registered. Several of these types are handled in driver ssb; however, the specific case of an inactive 802.11 cores is now treated in b43 and b43legacy. Although the current setup works, this minor change will place all such workarounds in ssb, and simplify the code in drivers b43 and b43legacy. Signed-off-by: RafaÅ‚ MiÅ‚ecki Tested-by: Larry Finger Acked-by: Larry Finger Signed-off-by: John W. Linville diff --git a/drivers/ssb/scan.c b/drivers/ssb/scan.c index 7dca719..45e5bab 100644 --- a/drivers/ssb/scan.c +++ b/drivers/ssb/scan.c @@ -258,7 +258,10 @@ static int we_support_multiple_80211_cores(struct ssb_bus *bus) #ifdef CONFIG_SSB_PCIHOST if (bus->bustype == SSB_BUSTYPE_PCI) { if (bus->host_pci->vendor == PCI_VENDOR_ID_BROADCOM && - bus->host_pci->device == 0x4324) + ((bus->host_pci->device == 0x4313) || + (bus->host_pci->device == 0x431A) || + (bus->host_pci->device == 0x4321) || + (bus->host_pci->device == 0x4324))) return 1; } #endif /* CONFIG_SSB_PCIHOST */ -- cgit v0.10.2 From 0e4e06ae5e895864b4a4bca7eec2e3015fddca98 Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Mon, 2 May 2011 16:49:14 -0700 Subject: libertas: Convert lbs_pr_ to pr_ Use the standard pr_ functions eases grep a bit. Added a few missing terminating newlines to messages. Coalesced long formats. Signed-off-by: Joe Perches Acked-by: Dan Williams Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/libertas/cfg.c b/drivers/net/wireless/libertas/cfg.c index f582dfd..73c5f54 100644 --- a/drivers/net/wireless/libertas/cfg.c +++ b/drivers/net/wireless/libertas/cfg.c @@ -6,6 +6,8 @@ * */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include #include #include @@ -1322,8 +1324,7 @@ static int lbs_cfg_connect(struct wiphy *wiphy, struct net_device *dev, sme->ssid, sme->ssid_len, WLAN_CAPABILITY_ESS, WLAN_CAPABILITY_ESS); if (!bss) { - lbs_pr_err("assoc: bss %pM not in scan results\n", - sme->bssid); + pr_err("assoc: bss %pM not in scan results\n", sme->bssid); ret = -ENOENT; goto done; } @@ -1380,8 +1381,8 @@ static int lbs_cfg_connect(struct wiphy *wiphy, struct net_device *dev, lbs_enable_rsn(priv, sme->crypto.cipher_group != 0); break; default: - lbs_pr_err("unsupported cipher group 0x%x\n", - sme->crypto.cipher_group); + pr_err("unsupported cipher group 0x%x\n", + sme->crypto.cipher_group); ret = -ENOTSUPP; goto done; } @@ -1499,7 +1500,7 @@ static int lbs_cfg_add_key(struct wiphy *wiphy, struct net_device *netdev, params->key, params->key_len); break; default: - lbs_pr_err("unhandled cipher 0x%x\n", params->cipher); + pr_err("unhandled cipher 0x%x\n", params->cipher); ret = -ENOTSUPP; break; } @@ -2127,13 +2128,13 @@ int lbs_cfg_register(struct lbs_private *priv) ret = wiphy_register(wdev->wiphy); if (ret < 0) - lbs_pr_err("cannot register wiphy device\n"); + pr_err("cannot register wiphy device\n"); priv->wiphy_registered = true; ret = register_netdev(priv->dev); if (ret) - lbs_pr_err("cannot register network device\n"); + pr_err("cannot register network device\n"); INIT_DELAYED_WORK(&priv->scan_work, lbs_scan_worker); diff --git a/drivers/net/wireless/libertas/cmd.c b/drivers/net/wireless/libertas/cmd.c index 6a96fc9..af8ef90 100644 --- a/drivers/net/wireless/libertas/cmd.c +++ b/drivers/net/wireless/libertas/cmd.c @@ -3,6 +3,8 @@ * It prepares command and sends it to firmware when it is ready. */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include #include #include @@ -110,7 +112,7 @@ int lbs_update_hw_spec(struct lbs_private *priv) * CF card firmware 5.0.16p0: cap 0x00000303 * USB dongle firmware 5.110.17p2: cap 0x00000303 */ - lbs_pr_info("%pM, fw %u.%u.%up%u, cap 0x%08x\n", + pr_info("%pM, fw %u.%u.%up%u, cap 0x%08x\n", cmd.permanentaddr, priv->fwrelease >> 24 & 0xff, priv->fwrelease >> 16 & 0xff, @@ -141,7 +143,7 @@ int lbs_update_hw_spec(struct lbs_private *priv) /* if it's unidentified region code, use the default (USA) */ if (i >= MRVDRV_MAX_REGION_CODE) { priv->regioncode = 0x10; - lbs_pr_info("unidentified region code; using the default (USA)\n"); + pr_info("unidentified region code; using the default (USA)\n"); } if (priv->current_addr[0] == 0xff) @@ -211,7 +213,7 @@ int lbs_host_sleep_cfg(struct lbs_private *priv, uint32_t criteria, (uint8_t *)&cmd_config.wol_conf, sizeof(struct wol_config)); } else { - lbs_pr_info("HOST_SLEEP_CFG failed %d\n", ret); + pr_info("HOST_SLEEP_CFG failed %d\n", ret); } return ret; @@ -314,7 +316,7 @@ static int lbs_wait_for_ds_awake(struct lbs_private *priv) if (priv->is_deep_sleep) { if (!wait_event_interruptible_timeout(priv->ds_awake_q, !priv->is_deep_sleep, (10 * HZ))) { - lbs_pr_err("ds_awake_q: timer expired\n"); + pr_err("ds_awake_q: timer expired\n"); ret = -1; } } @@ -339,7 +341,7 @@ int lbs_set_deep_sleep(struct lbs_private *priv, int deep_sleep) netif_carrier_off(priv->dev); } } else { - lbs_pr_err("deep sleep: already enabled\n"); + pr_err("deep sleep: already enabled\n"); } } else { if (priv->is_deep_sleep) { @@ -349,8 +351,7 @@ int lbs_set_deep_sleep(struct lbs_private *priv, int deep_sleep) if (!ret) { ret = lbs_wait_for_ds_awake(priv); if (ret) - lbs_pr_err("deep sleep: wakeup" - "failed\n"); + pr_err("deep sleep: wakeup failed\n"); } } } @@ -384,8 +385,8 @@ int lbs_set_host_sleep(struct lbs_private *priv, int host_sleep) ret = lbs_host_sleep_cfg(priv, priv->wol_criteria, (struct wol_config *)NULL); if (ret) { - lbs_pr_info("Host sleep configuration failed: " - "%d\n", ret); + pr_info("Host sleep configuration failed: %d\n", + ret); return ret; } if (priv->psstate == PS_STATE_FULL_POWER) { @@ -395,19 +396,19 @@ int lbs_set_host_sleep(struct lbs_private *priv, int host_sleep) sizeof(cmd), lbs_ret_host_sleep_activate, 0); if (ret) - lbs_pr_info("HOST_SLEEP_ACTIVATE " - "failed: %d\n", ret); + pr_info("HOST_SLEEP_ACTIVATE failed: %d\n", + ret); } if (!wait_event_interruptible_timeout( priv->host_sleep_q, priv->is_host_sleep_activated, (10 * HZ))) { - lbs_pr_err("host_sleep_q: timer expired\n"); + pr_err("host_sleep_q: timer expired\n"); ret = -1; } } else { - lbs_pr_err("host sleep: already enabled\n"); + pr_err("host sleep: already enabled\n"); } } else { if (priv->is_host_sleep_activated) @@ -1007,7 +1008,7 @@ static void lbs_submit_command(struct lbs_private *priv, ret = priv->hw_host_to_card(priv, MVMS_CMD, (u8 *) cmd, cmdsize); if (ret) { - lbs_pr_info("DNLD_CMD: hw_host_to_card failed: %d\n", ret); + pr_info("DNLD_CMD: hw_host_to_card failed: %d\n", ret); /* Let the timer kick in and retry, and potentially reset the whole thing if the condition persists */ timeo = HZ/4; @@ -1276,7 +1277,7 @@ int lbs_execute_next_command(struct lbs_private *priv) spin_lock_irqsave(&priv->driver_lock, flags); if (priv->cur_cmd) { - lbs_pr_alert( "EXEC_NEXT_CMD: already processing command!\n"); + pr_alert( "EXEC_NEXT_CMD: already processing command!\n"); spin_unlock_irqrestore(&priv->driver_lock, flags); ret = -1; goto done; @@ -1438,7 +1439,7 @@ static void lbs_send_confirmsleep(struct lbs_private *priv) ret = priv->hw_host_to_card(priv, MVMS_CMD, (u8 *) &confirm_sleep, sizeof(confirm_sleep)); if (ret) { - lbs_pr_alert("confirm_sleep failed\n"); + pr_alert("confirm_sleep failed\n"); goto out; } @@ -1664,8 +1665,7 @@ int __lbs_cmd(struct lbs_private *priv, uint16_t command, spin_lock_irqsave(&priv->driver_lock, flags); ret = cmdnode->result; if (ret) - lbs_pr_info("PREP_CMD: command 0x%04x failed: %d\n", - command, ret); + pr_info("PREP_CMD: command 0x%04x failed: %d\n", command, ret); __lbs_cleanup_and_insert_cmd(priv, cmdnode); spin_unlock_irqrestore(&priv->driver_lock, flags); diff --git a/drivers/net/wireless/libertas/cmdresp.c b/drivers/net/wireless/libertas/cmdresp.c index 03e5289..45291a4 100644 --- a/drivers/net/wireless/libertas/cmdresp.c +++ b/drivers/net/wireless/libertas/cmdresp.c @@ -2,6 +2,9 @@ * This file contains the handling of command * responses as well as events generated by firmware. */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include #include #include @@ -85,15 +88,17 @@ int lbs_process_command_response(struct lbs_private *priv, u8 *data, u32 len) lbs_deb_hex(LBS_DEB_CMD, "CMD_RESP", (void *) resp, len); if (resp->seqnum != priv->cur_cmd->cmdbuf->seqnum) { - lbs_pr_info("Received CMD_RESP with invalid sequence %d (expected %d)\n", - le16_to_cpu(resp->seqnum), le16_to_cpu(priv->cur_cmd->cmdbuf->seqnum)); + pr_info("Received CMD_RESP with invalid sequence %d (expected %d)\n", + le16_to_cpu(resp->seqnum), + le16_to_cpu(priv->cur_cmd->cmdbuf->seqnum)); spin_unlock_irqrestore(&priv->driver_lock, flags); ret = -1; goto done; } if (respcmd != CMD_RET(curcmd) && respcmd != CMD_RET_802_11_ASSOCIATE && curcmd != CMD_802_11_ASSOCIATE) { - lbs_pr_info("Invalid CMD_RESP %x to command %x!\n", respcmd, curcmd); + pr_info("Invalid CMD_RESP %x to command %x!\n", + respcmd, curcmd); spin_unlock_irqrestore(&priv->driver_lock, flags); ret = -1; goto done; @@ -102,8 +107,8 @@ int lbs_process_command_response(struct lbs_private *priv, u8 *data, u32 len) if (resp->result == cpu_to_le16(0x0004)) { /* 0x0004 means -EAGAIN. Drop the response, let it time out and be resubmitted */ - lbs_pr_info("Firmware returns DEFER to command %x. Will let it time out...\n", - le16_to_cpu(resp->command)); + pr_info("Firmware returns DEFER to command %x. Will let it time out...\n", + le16_to_cpu(resp->command)); spin_unlock_irqrestore(&priv->driver_lock, flags); ret = -1; goto done; @@ -314,28 +319,28 @@ int lbs_process_event(struct lbs_private *priv, u32 event) lbs_deb_cmd("EVENT: ADHOC beacon lost\n"); break; case MACREG_INT_CODE_RSSI_LOW: - lbs_pr_alert("EVENT: rssi low\n"); + pr_alert("EVENT: rssi low\n"); break; case MACREG_INT_CODE_SNR_LOW: - lbs_pr_alert("EVENT: snr low\n"); + pr_alert("EVENT: snr low\n"); break; case MACREG_INT_CODE_MAX_FAIL: - lbs_pr_alert("EVENT: max fail\n"); + pr_alert("EVENT: max fail\n"); break; case MACREG_INT_CODE_RSSI_HIGH: - lbs_pr_alert("EVENT: rssi high\n"); + pr_alert("EVENT: rssi high\n"); break; case MACREG_INT_CODE_SNR_HIGH: - lbs_pr_alert("EVENT: snr high\n"); + pr_alert("EVENT: snr high\n"); break; case MACREG_INT_CODE_MESH_AUTO_STARTED: /* Ignore spurious autostart events */ - lbs_pr_info("EVENT: MESH_AUTO_STARTED (ignoring)\n"); + pr_info("EVENT: MESH_AUTO_STARTED (ignoring)\n"); break; default: - lbs_pr_alert("EVENT: unknown event id %d\n", event); + pr_alert("EVENT: unknown event id %d\n", event); break; } diff --git a/drivers/net/wireless/libertas/debugfs.c b/drivers/net/wireless/libertas/debugfs.c index 851fe7b..0bd79c5 100644 --- a/drivers/net/wireless/libertas/debugfs.c +++ b/drivers/net/wireless/libertas/debugfs.c @@ -1,3 +1,5 @@ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include #include #include @@ -151,13 +153,13 @@ static ssize_t lbs_host_sleep_write(struct file *file, ret = lbs_set_host_sleep(priv, 0); else if (host_sleep == 1) { if (priv->wol_criteria == EHS_REMOVE_WAKEUP) { - lbs_pr_info("wake parameters not configured"); + pr_info("wake parameters not configured\n"); ret = -EINVAL; goto out_unlock; } ret = lbs_set_host_sleep(priv, 1); } else { - lbs_pr_err("invalid option\n"); + pr_err("invalid option\n"); ret = -EINVAL; } diff --git a/drivers/net/wireless/libertas/defs.h b/drivers/net/wireless/libertas/defs.h index 92b5b1f..ab966f0 100644 --- a/drivers/net/wireless/libertas/defs.h +++ b/drivers/net/wireless/libertas/defs.h @@ -89,13 +89,6 @@ do { if ((lbs_debug & (grp)) == (grp)) \ #define lbs_deb_spi(fmt, args...) LBS_DEB_LL(LBS_DEB_SPI, " spi", fmt, ##args) #define lbs_deb_cfg80211(fmt, args...) LBS_DEB_LL(LBS_DEB_CFG80211, " cfg80211", fmt, ##args) -#define lbs_pr_info(format, args...) \ - printk(KERN_INFO DRV_NAME": " format, ## args) -#define lbs_pr_err(format, args...) \ - printk(KERN_ERR DRV_NAME": " format, ## args) -#define lbs_pr_alert(format, args...) \ - printk(KERN_ALERT DRV_NAME": " format, ## args) - #ifdef DEBUG static inline void lbs_deb_hex(unsigned int grp, const char *prompt, u8 *buf, int len) { diff --git a/drivers/net/wireless/libertas/if_cs.c b/drivers/net/wireless/libertas/if_cs.c index 4dfd48f..f2d1011 100644 --- a/drivers/net/wireless/libertas/if_cs.c +++ b/drivers/net/wireless/libertas/if_cs.c @@ -21,6 +21,8 @@ */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include #include #include @@ -362,7 +364,7 @@ static int if_cs_send_cmd(struct lbs_private *priv, u8 *buf, u16 nb) if (status & IF_CS_BIT_COMMAND) break; if (++loops > 100) { - lbs_pr_err("card not ready for commands\n"); + pr_err("card not ready for commands\n"); goto done; } mdelay(1); @@ -432,14 +434,14 @@ static int if_cs_receive_cmdres(struct lbs_private *priv, u8 *data, u32 *len) /* is hardware ready? */ status = if_cs_read16(priv->card, IF_CS_CARD_STATUS); if ((status & IF_CS_BIT_RESP) == 0) { - lbs_pr_err("no cmd response in card\n"); + pr_err("no cmd response in card\n"); *len = 0; goto out; } *len = if_cs_read16(priv->card, IF_CS_RESP_LEN); if ((*len == 0) || (*len > LBS_CMD_BUFFER_SIZE)) { - lbs_pr_err("card cmd buffer has invalid # of bytes (%d)\n", *len); + pr_err("card cmd buffer has invalid # of bytes (%d)\n", *len); goto out; } @@ -473,7 +475,7 @@ static struct sk_buff *if_cs_receive_data(struct lbs_private *priv) len = if_cs_read16(priv->card, IF_CS_READ_LEN); if (len == 0 || len > MRVDRV_ETH_RX_PACKET_BUFFER_SIZE) { - lbs_pr_err("card data buffer has invalid # of bytes (%d)\n", len); + pr_err("card data buffer has invalid # of bytes (%d)\n", len); priv->dev->stats.rx_dropped++; goto dat_err; } @@ -653,8 +655,8 @@ static int if_cs_prog_helper(struct if_cs_card *card, const struct firmware *fw) ret = if_cs_poll_while_fw_download(card, IF_CS_CARD_STATUS, IF_CS_BIT_COMMAND); if (ret < 0) { - lbs_pr_err("can't download helper at 0x%x, ret %d\n", - sent, ret); + pr_err("can't download helper at 0x%x, ret %d\n", + sent, ret); goto done; } @@ -684,7 +686,7 @@ static int if_cs_prog_real(struct if_cs_card *card, const struct firmware *fw) ret = if_cs_poll_while_fw_download(card, IF_CS_SQ_READ_LOW, IF_CS_SQ_HELPER_OK); if (ret < 0) { - lbs_pr_err("helper firmware doesn't answer\n"); + pr_err("helper firmware doesn't answer\n"); goto done; } @@ -692,13 +694,13 @@ static int if_cs_prog_real(struct if_cs_card *card, const struct firmware *fw) len = if_cs_read16(card, IF_CS_SQ_READ_LOW); if (len & 1) { retry++; - lbs_pr_info("odd, need to retry this firmware block\n"); + pr_info("odd, need to retry this firmware block\n"); } else { retry = 0; } if (retry > 20) { - lbs_pr_err("could not download firmware\n"); + pr_err("could not download firmware\n"); ret = -ENODEV; goto done; } @@ -718,14 +720,14 @@ static int if_cs_prog_real(struct if_cs_card *card, const struct firmware *fw) ret = if_cs_poll_while_fw_download(card, IF_CS_CARD_STATUS, IF_CS_BIT_COMMAND); if (ret < 0) { - lbs_pr_err("can't download firmware at 0x%x\n", sent); + pr_err("can't download firmware at 0x%x\n", sent); goto done; } } ret = if_cs_poll_while_fw_download(card, IF_CS_SCRATCH, 0x5a); if (ret < 0) - lbs_pr_err("firmware download failed\n"); + pr_err("firmware download failed\n"); done: lbs_deb_leave_args(LBS_DEB_CS, "ret %d", ret); @@ -759,7 +761,7 @@ static int if_cs_host_to_card(struct lbs_private *priv, ret = if_cs_send_cmd(priv, buf, nb); break; default: - lbs_pr_err("%s: unsupported type %d\n", __func__, type); + pr_err("%s: unsupported type %d\n", __func__, type); } lbs_deb_leave_args(LBS_DEB_CS, "ret %d", ret); @@ -788,7 +790,7 @@ static int if_cs_ioprobe(struct pcmcia_device *p_dev, void *priv_data) p_dev->resource[0]->flags |= IO_DATA_PATH_WIDTH_AUTO; if (p_dev->resource[1]->end) { - lbs_pr_err("wrong CIS (check number of IO windows)\n"); + pr_err("wrong CIS (check number of IO windows)\n"); return -ENODEV; } @@ -809,7 +811,7 @@ static int if_cs_probe(struct pcmcia_device *p_dev) card = kzalloc(sizeof(struct if_cs_card), GFP_KERNEL); if (!card) { - lbs_pr_err("error in kzalloc\n"); + pr_err("error in kzalloc\n"); goto out; } card->p_dev = p_dev; @@ -818,7 +820,7 @@ static int if_cs_probe(struct pcmcia_device *p_dev) p_dev->config_flags |= CONF_ENABLE_IRQ | CONF_AUTO_SET_IO; if (pcmcia_loop_config(p_dev, if_cs_ioprobe, NULL)) { - lbs_pr_err("error in pcmcia_loop_config\n"); + pr_err("error in pcmcia_loop_config\n"); goto out1; } @@ -834,14 +836,14 @@ static int if_cs_probe(struct pcmcia_device *p_dev) card->iobase = ioport_map(p_dev->resource[0]->start, resource_size(p_dev->resource[0])); if (!card->iobase) { - lbs_pr_err("error in ioport_map\n"); + pr_err("error in ioport_map\n"); ret = -EIO; goto out1; } ret = pcmcia_enable_device(p_dev); if (ret) { - lbs_pr_err("error in pcmcia_enable_device\n"); + pr_err("error in pcmcia_enable_device\n"); goto out2; } @@ -856,8 +858,8 @@ static int if_cs_probe(struct pcmcia_device *p_dev) card->model = get_model(p_dev->manf_id, p_dev->card_id); if (card->model == MODEL_UNKNOWN) { - lbs_pr_err("unsupported manf_id 0x%04x / card_id 0x%04x\n", - p_dev->manf_id, p_dev->card_id); + pr_err("unsupported manf_id 0x%04x / card_id 0x%04x\n", + p_dev->manf_id, p_dev->card_id); goto out2; } @@ -866,20 +868,20 @@ static int if_cs_probe(struct pcmcia_device *p_dev) if (card->model == MODEL_8305) { card->align_regs = 1; if (prod_id < IF_CS_CF8305_B1_REV) { - lbs_pr_err("8305 rev B0 and older are not supported\n"); + pr_err("8305 rev B0 and older are not supported\n"); ret = -ENODEV; goto out2; } } if ((card->model == MODEL_8381) && prod_id < IF_CS_CF8381_B3_REV) { - lbs_pr_err("8381 rev B2 and older are not supported\n"); + pr_err("8381 rev B2 and older are not supported\n"); ret = -ENODEV; goto out2; } if ((card->model == MODEL_8385) && prod_id < IF_CS_CF8385_B1_REV) { - lbs_pr_err("8385 rev B0 and older are not supported\n"); + pr_err("8385 rev B0 and older are not supported\n"); ret = -ENODEV; goto out2; } @@ -887,7 +889,7 @@ static int if_cs_probe(struct pcmcia_device *p_dev) ret = lbs_get_firmware(&p_dev->dev, NULL, NULL, card->model, &fw_table[0], &helper, &mainfw); if (ret) { - lbs_pr_err("failed to find firmware (%d)\n", ret); + pr_err("failed to find firmware (%d)\n", ret); goto out2; } @@ -918,7 +920,7 @@ static int if_cs_probe(struct pcmcia_device *p_dev) ret = request_irq(p_dev->irq, if_cs_interrupt, IRQF_SHARED, DRV_NAME, card); if (ret) { - lbs_pr_err("error in request_irq\n"); + pr_err("error in request_irq\n"); goto out3; } @@ -931,7 +933,7 @@ static int if_cs_probe(struct pcmcia_device *p_dev) /* And finally bring the card up */ if (lbs_start_card(priv) != 0) { - lbs_pr_err("could not activate card\n"); + pr_err("could not activate card\n"); goto out3; } diff --git a/drivers/net/wireless/libertas/if_sdio.c b/drivers/net/wireless/libertas/if_sdio.c index b4de0ca..ab86779 100644 --- a/drivers/net/wireless/libertas/if_sdio.c +++ b/drivers/net/wireless/libertas/if_sdio.c @@ -26,6 +26,8 @@ * if_sdio_card_to_host() to pad the data. */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include #include #include @@ -409,7 +411,7 @@ static int if_sdio_card_to_host(struct if_sdio_card *card) out: if (ret) - lbs_pr_err("problem fetching packet from firmware\n"); + pr_err("problem fetching packet from firmware\n"); lbs_deb_leave_args(LBS_DEB_SDIO, "ret %d", ret); @@ -446,7 +448,7 @@ static void if_sdio_host_to_card_worker(struct work_struct *work) } if (ret) - lbs_pr_err("error %d sending packet to firmware\n", ret); + pr_err("error %d sending packet to firmware\n", ret); sdio_release_host(card->func); @@ -555,7 +557,7 @@ release: out: if (ret) - lbs_pr_err("failed to load helper firmware\n"); + pr_err("failed to load helper firmware\n"); lbs_deb_leave_args(LBS_DEB_SDIO, "ret %d", ret); return ret; @@ -669,7 +671,7 @@ release: out: if (ret) - lbs_pr_err("failed to load firmware\n"); + pr_err("failed to load firmware\n"); lbs_deb_leave_args(LBS_DEB_SDIO, "ret %d", ret); return ret; @@ -723,7 +725,7 @@ static int if_sdio_prog_firmware(struct if_sdio_card *card) ret = lbs_get_firmware(&card->func->dev, lbs_helper_name, lbs_fw_name, card->model, &fw_table[0], &helper, &mainfw); if (ret) { - lbs_pr_err("failed to find firmware (%d)\n", ret); + pr_err("failed to find firmware (%d)\n", ret); goto out; } @@ -849,7 +851,7 @@ static int if_sdio_enter_deep_sleep(struct lbs_private *priv) ret = __lbs_cmd(priv, CMD_802_11_DEEP_SLEEP, &cmd, sizeof(cmd), lbs_cmd_copyback, (unsigned long) &cmd); if (ret) - lbs_pr_err("DEEP_SLEEP cmd failed\n"); + pr_err("DEEP_SLEEP cmd failed\n"); mdelay(200); return ret; @@ -865,7 +867,7 @@ static int if_sdio_exit_deep_sleep(struct lbs_private *priv) sdio_writeb(card->func, HOST_POWER_UP, CONFIGURATION_REG, &ret); if (ret) - lbs_pr_err("sdio_writeb failed!\n"); + pr_err("sdio_writeb failed!\n"); sdio_release_host(card->func); lbs_deb_leave_args(LBS_DEB_SDIO, "ret %d", ret); @@ -882,7 +884,7 @@ static int if_sdio_reset_deep_sleep_wakeup(struct lbs_private *priv) sdio_writeb(card->func, 0, CONFIGURATION_REG, &ret); if (ret) - lbs_pr_err("sdio_writeb failed!\n"); + pr_err("sdio_writeb failed!\n"); sdio_release_host(card->func); lbs_deb_leave_args(LBS_DEB_SDIO, "ret %d", ret); @@ -961,7 +963,7 @@ static int if_sdio_probe(struct sdio_func *func, } if (i == func->card->num_info) { - lbs_pr_err("unable to identify card model\n"); + pr_err("unable to identify card model\n"); return -ENODEV; } @@ -995,7 +997,7 @@ static int if_sdio_probe(struct sdio_func *func, break; } if (i == ARRAY_SIZE(fw_table)) { - lbs_pr_err("unknown card model 0x%x\n", card->model); + pr_err("unknown card model 0x%x\n", card->model); ret = -ENODEV; goto free; } @@ -1101,7 +1103,7 @@ static int if_sdio_probe(struct sdio_func *func, lbs_deb_sdio("send function INIT command\n"); if (__lbs_cmd(priv, CMD_FUNC_INIT, &cmd, sizeof(cmd), lbs_cmd_copyback, (unsigned long) &cmd)) - lbs_pr_alert("CMD_FUNC_INIT cmd failed\n"); + pr_alert("CMD_FUNC_INIT cmd failed\n"); } ret = lbs_start_card(priv); @@ -1163,7 +1165,7 @@ static void if_sdio_remove(struct sdio_func *func) if (__lbs_cmd(card->priv, CMD_FUNC_SHUTDOWN, &cmd, sizeof(cmd), lbs_cmd_copyback, (unsigned long) &cmd)) - lbs_pr_alert("CMD_FUNC_SHUTDOWN cmd failed\n"); + pr_alert("CMD_FUNC_SHUTDOWN cmd failed\n"); } @@ -1202,21 +1204,19 @@ static int if_sdio_suspend(struct device *dev) mmc_pm_flag_t flags = sdio_get_host_pm_caps(func); - lbs_pr_info("%s: suspend: PM flags = 0x%x\n", - sdio_func_id(func), flags); + pr_info("%s: suspend: PM flags = 0x%x\n", sdio_func_id(func), flags); /* If we aren't being asked to wake on anything, we should bail out * and let the SD stack power down the card. */ if (card->priv->wol_criteria == EHS_REMOVE_WAKEUP) { - lbs_pr_info("Suspend without wake params -- " - "powering down card."); + pr_info("Suspend without wake params -- powering down card\n"); return -ENOSYS; } if (!(flags & MMC_PM_KEEP_POWER)) { - lbs_pr_err("%s: cannot remain alive while host is suspended\n", - sdio_func_id(func)); + pr_err("%s: cannot remain alive while host is suspended\n", + sdio_func_id(func)); return -ENOSYS; } @@ -1237,7 +1237,7 @@ static int if_sdio_resume(struct device *dev) struct if_sdio_card *card = sdio_get_drvdata(func); int ret; - lbs_pr_info("%s: resume: we're back\n", sdio_func_id(func)); + pr_info("%s: resume: we're back\n", sdio_func_id(func)); ret = lbs_resume(card->priv); diff --git a/drivers/net/wireless/libertas/if_spi.c b/drivers/net/wireless/libertas/if_spi.c index 67de5b3..4d19b57 100644 --- a/drivers/net/wireless/libertas/if_spi.c +++ b/drivers/net/wireless/libertas/if_spi.c @@ -17,6 +17,8 @@ * (at your option) any later version. */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include #include #include @@ -305,8 +307,7 @@ static int spu_wait_for_u16(struct if_spi_card *card, u16 reg, } udelay(100); if (time_after(jiffies, timeout)) { - lbs_pr_err("%s: timeout with val=%02x, " - "target_mask=%02x, target=%02x\n", + pr_err("%s: timeout with val=%02x, target_mask=%02x, target=%02x\n", __func__, val, target_mask, target); return -ETIMEDOUT; } @@ -405,7 +406,7 @@ static int spu_set_bus_mode(struct if_spi_card *card, u16 mode) if (err) return err; if ((rval & 0xF) != mode) { - lbs_pr_err("Can't read bus mode register.\n"); + pr_err("Can't read bus mode register\n"); return -EIO; } return 0; @@ -534,7 +535,7 @@ static int if_spi_prog_helper_firmware(struct if_spi_card *card, out: if (err) - lbs_pr_err("failed to load helper firmware (err=%d)\n", err); + pr_err("failed to load helper firmware (err=%d)\n", err); lbs_deb_leave_args(LBS_DEB_SPI, "err %d", err); return err; } @@ -557,7 +558,7 @@ static int if_spi_prog_main_firmware_check_len(struct if_spi_card *card, IF_SPI_HIST_CMD_DOWNLOAD_RDY, IF_SPI_HIST_CMD_DOWNLOAD_RDY); if (err) { - lbs_pr_err("timed out waiting for host_int_status\n"); + pr_err("timed out waiting for host_int_status\n"); return err; } @@ -567,9 +568,8 @@ static int if_spi_prog_main_firmware_check_len(struct if_spi_card *card, return err; if (len > IF_SPI_CMD_BUF_SIZE) { - lbs_pr_err("firmware load device requested a larger " - "tranfer than we are prepared to " - "handle. (len = %d)\n", len); + pr_err("firmware load device requested a larger transfer than we are prepared to handle (len = %d)\n", + len); return -EIO; } if (len & 0x1) { @@ -598,8 +598,8 @@ static int if_spi_prog_main_firmware(struct if_spi_card *card, err = spu_wait_for_u16(card, IF_SPI_SCRATCH_1_REG, 0, 0); if (err) { - lbs_pr_err("%s: timed out waiting for initial " - "scratch reg = 0\n", __func__); + pr_err("%s: timed out waiting for initial scratch reg = 0\n", + __func__); goto out; } @@ -617,15 +617,13 @@ static int if_spi_prog_main_firmware(struct if_spi_card *card, * If there are no more bytes left, we would normally * expect to have terminated with len = 0 */ - lbs_pr_err("Firmware load wants more bytes " - "than we have to offer.\n"); + pr_err("Firmware load wants more bytes than we have to offer.\n"); break; } if (crc_err) { /* Previous transfer failed. */ if (++num_crc_errs > MAX_MAIN_FW_LOAD_CRC_ERR) { - lbs_pr_err("Too many CRC errors encountered " - "in firmware load.\n"); + pr_err("Too many CRC errors encountered in firmware load.\n"); err = -EIO; goto out; } @@ -654,21 +652,20 @@ static int if_spi_prog_main_firmware(struct if_spi_card *card, prev_len = len; } if (bytes > prev_len) { - lbs_pr_err("firmware load wants fewer bytes than " - "we have to offer.\n"); + pr_err("firmware load wants fewer bytes than we have to offer\n"); } /* Confirm firmware download */ err = spu_wait_for_u32(card, IF_SPI_SCRATCH_4_REG, SUCCESSFUL_FW_DOWNLOAD_MAGIC); if (err) { - lbs_pr_err("failed to confirm the firmware download\n"); + pr_err("failed to confirm the firmware download\n"); goto out; } out: if (err) - lbs_pr_err("failed to load firmware (err=%d)\n", err); + pr_err("failed to load firmware (err=%d)\n", err); lbs_deb_leave_args(LBS_DEB_SPI, "err %d", err); return err; } @@ -709,14 +706,12 @@ static int if_spi_c2h_cmd(struct if_spi_card *card) if (err) goto out; if (!len) { - lbs_pr_err("%s: error: card has no data for host\n", - __func__); + pr_err("%s: error: card has no data for host\n", __func__); err = -EINVAL; goto out; } else if (len > IF_SPI_CMD_BUF_SIZE) { - lbs_pr_err("%s: error: response packet too large: " - "%d bytes, but maximum is %d\n", - __func__, len, IF_SPI_CMD_BUF_SIZE); + pr_err("%s: error: response packet too large: %d bytes, but maximum is %d\n", + __func__, len, IF_SPI_CMD_BUF_SIZE); err = -EINVAL; goto out; } @@ -737,7 +732,7 @@ static int if_spi_c2h_cmd(struct if_spi_card *card) out: if (err) - lbs_pr_err("%s: err=%d\n", __func__, err); + pr_err("%s: err=%d\n", __func__, err); lbs_deb_leave(LBS_DEB_SPI); return err; } @@ -757,14 +752,12 @@ static int if_spi_c2h_data(struct if_spi_card *card) if (err) goto out; if (!len) { - lbs_pr_err("%s: error: card has no data for host\n", - __func__); + pr_err("%s: error: card has no data for host\n", __func__); err = -EINVAL; goto out; } else if (len > MRVDRV_ETH_RX_PACKET_BUFFER_SIZE) { - lbs_pr_err("%s: error: card has %d bytes of data, but " - "our maximum skb size is %zu\n", - __func__, len, MRVDRV_ETH_RX_PACKET_BUFFER_SIZE); + pr_err("%s: error: card has %d bytes of data, but our maximum skb size is %zu\n", + __func__, len, MRVDRV_ETH_RX_PACKET_BUFFER_SIZE); err = -EINVAL; goto out; } @@ -795,7 +788,7 @@ free_skb: dev_kfree_skb(skb); out: if (err) - lbs_pr_err("%s: err=%d\n", __func__, err); + pr_err("%s: err=%d\n", __func__, err); lbs_deb_leave(LBS_DEB_SPI); return err; } @@ -817,7 +810,7 @@ static void if_spi_h2c(struct if_spi_card *card, port_reg = IF_SPI_CMD_RDWRPORT_REG; break; default: - lbs_pr_err("can't transfer buffer of type %d\n", type); + pr_err("can't transfer buffer of type %d\n", type); err = -EINVAL; goto out; } @@ -831,7 +824,7 @@ out: kfree(packet); if (err) - lbs_pr_err("%s: error %d\n", __func__, err); + pr_err("%s: error %d\n", __func__, err); } /* Inform the host about a card event */ @@ -855,7 +848,7 @@ static void if_spi_e2h(struct if_spi_card *card) lbs_queue_event(priv, cause & 0xff); out: if (err) - lbs_pr_err("%s: error %d\n", __func__, err); + pr_err("%s: error %d\n", __func__, err); } static void if_spi_host_to_card_worker(struct work_struct *work) @@ -877,7 +870,7 @@ static void if_spi_host_to_card_worker(struct work_struct *work) err = spu_read_u16(card, IF_SPI_HOST_INT_STATUS_REG, &hiStatus); if (err) { - lbs_pr_err("I/O error\n"); + pr_err("I/O error\n"); goto err; } @@ -940,7 +933,7 @@ static void if_spi_host_to_card_worker(struct work_struct *work) err: if (err) - lbs_pr_err("%s: got error %d\n", __func__, err); + pr_err("%s: got error %d\n", __func__, err); lbs_deb_leave(LBS_DEB_SPI); } @@ -963,7 +956,7 @@ static int if_spi_host_to_card(struct lbs_private *priv, lbs_deb_enter_args(LBS_DEB_SPI, "type %d, bytes %d", type, nb); if (nb == 0) { - lbs_pr_err("%s: invalid size requested: %d\n", __func__, nb); + pr_err("%s: invalid size requested: %d\n", __func__, nb); err = -EINVAL; goto out; } @@ -991,7 +984,7 @@ static int if_spi_host_to_card(struct lbs_private *priv, spin_unlock_irqrestore(&card->buffer_lock, flags); break; default: - lbs_pr_err("can't transfer buffer of type %d", type); + pr_err("can't transfer buffer of type %d\n", type); err = -EINVAL; break; } @@ -1052,8 +1045,7 @@ static int if_spi_init_card(struct if_spi_card *card) break; } if (i == ARRAY_SIZE(fw_table)) { - lbs_pr_err("Unsupported chip_id: 0x%02x\n", - card->card_id); + pr_err("Unsupported chip_id: 0x%02x\n", card->card_id); err = -ENODEV; goto out; } @@ -1062,7 +1054,7 @@ static int if_spi_init_card(struct if_spi_card *card) card->card_id, &fw_table[0], &helper, &mainfw); if (err) { - lbs_pr_err("failed to find firmware (%d)\n", err); + pr_err("failed to find firmware (%d)\n", err); goto out; } @@ -1187,7 +1179,7 @@ static int __devinit if_spi_probe(struct spi_device *spi) err = request_irq(spi->irq, if_spi_host_interrupt, IRQF_TRIGGER_FALLING, "libertas_spi", card); if (err) { - lbs_pr_err("can't get host irq line-- request_irq failed\n"); + pr_err("can't get host irq line-- request_irq failed\n"); goto terminate_workqueue; } diff --git a/drivers/net/wireless/libertas/if_usb.c b/drivers/net/wireless/libertas/if_usb.c index e1e2128f..b68e162 100644 --- a/drivers/net/wireless/libertas/if_usb.c +++ b/drivers/net/wireless/libertas/if_usb.c @@ -1,6 +1,9 @@ /* * This file contains functions used in USB interface module. */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include #include #include @@ -153,7 +156,7 @@ static void if_usb_write_bulk_callback(struct urb *urb) lbs_host_to_card_done(priv); } else { /* print the failure status number for debug */ - lbs_pr_info("URB in failure status: %d\n", urb->status); + pr_info("URB in failure status: %d\n", urb->status); } } @@ -203,7 +206,7 @@ static void if_usb_setup_firmware(struct lbs_private *priv) wake_method.hdr.size = cpu_to_le16(sizeof(wake_method)); wake_method.action = cpu_to_le16(CMD_ACT_GET); if (lbs_cmd_with_response(priv, CMD_802_11_FW_WAKE_METHOD, &wake_method)) { - lbs_pr_info("Firmware does not seem to support PS mode\n"); + pr_info("Firmware does not seem to support PS mode\n"); priv->fwcapinfo &= ~FW_CAPINFO_PS; } else { if (le16_to_cpu(wake_method.method) == CMD_WAKE_METHOD_COMMAND_INT) { @@ -212,7 +215,7 @@ static void if_usb_setup_firmware(struct lbs_private *priv) /* The versions which boot up this way don't seem to work even if we set it to the command interrupt */ priv->fwcapinfo &= ~FW_CAPINFO_PS; - lbs_pr_info("Firmware doesn't wake via command interrupt; disabling PS mode\n"); + pr_info("Firmware doesn't wake via command interrupt; disabling PS mode\n"); } } } @@ -224,7 +227,7 @@ static void if_usb_fw_timeo(unsigned long priv) if (cardp->fwdnldover) { lbs_deb_usb("Download complete, no event. Assuming success\n"); } else { - lbs_pr_err("Download timed out\n"); + pr_err("Download timed out\n"); cardp->surprise_removed = 1; } wake_up(&cardp->fw_wq); @@ -258,7 +261,7 @@ static int if_usb_probe(struct usb_interface *intf, cardp = kzalloc(sizeof(struct if_usb_card), GFP_KERNEL); if (!cardp) { - lbs_pr_err("Out of memory allocating private data.\n"); + pr_err("Out of memory allocating private data\n"); goto error; } @@ -348,10 +351,10 @@ static int if_usb_probe(struct usb_interface *intf, usb_set_intfdata(intf, cardp); if (device_create_file(&priv->dev->dev, &dev_attr_lbs_flash_fw)) - lbs_pr_err("cannot register lbs_flash_fw attribute\n"); + pr_err("cannot register lbs_flash_fw attribute\n"); if (device_create_file(&priv->dev->dev, &dev_attr_lbs_flash_boot2)) - lbs_pr_err("cannot register lbs_flash_boot2 attribute\n"); + pr_err("cannot register lbs_flash_boot2 attribute\n"); /* * EHS_REMOVE_WAKEUP is not supported on all versions of the firmware. @@ -536,7 +539,7 @@ static int __if_usb_submit_rx_urb(struct if_usb_card *cardp, int ret = -1; if (!(skb = dev_alloc_skb(MRVDRV_ETH_RX_PACKET_BUFFER_SIZE))) { - lbs_pr_err("No free skb\n"); + pr_err("No free skb\n"); goto rx_ret; } @@ -595,7 +598,7 @@ static void if_usb_receive_fwload(struct urb *urb) if (tmp[0] == cpu_to_le32(CMD_TYPE_INDICATION) && tmp[1] == cpu_to_le32(MACREG_INT_CODE_FIRMWARE_READY)) { - lbs_pr_info("Firmware ready event received\n"); + pr_info("Firmware ready event received\n"); wake_up(&cardp->fw_wq); } else { lbs_deb_usb("Waiting for confirmation; got %x %x\n", @@ -622,20 +625,20 @@ static void if_usb_receive_fwload(struct urb *urb) bootcmdresp.magic == cpu_to_le32(CMD_TYPE_DATA) || bootcmdresp.magic == cpu_to_le32(CMD_TYPE_INDICATION)) { if (!cardp->bootcmdresp) - lbs_pr_info("Firmware already seems alive; resetting\n"); + pr_info("Firmware already seems alive; resetting\n"); cardp->bootcmdresp = -1; } else { - lbs_pr_info("boot cmd response wrong magic number (0x%x)\n", + pr_info("boot cmd response wrong magic number (0x%x)\n", le32_to_cpu(bootcmdresp.magic)); } } else if ((bootcmdresp.cmd != BOOT_CMD_FW_BY_USB) && (bootcmdresp.cmd != BOOT_CMD_UPDATE_FW) && (bootcmdresp.cmd != BOOT_CMD_UPDATE_BOOT2)) { - lbs_pr_info("boot cmd response cmd_tag error (%d)\n", - bootcmdresp.cmd); + pr_info("boot cmd response cmd_tag error (%d)\n", + bootcmdresp.cmd); } else if (bootcmdresp.result != BOOT_CMD_RESP_OK) { - lbs_pr_info("boot cmd response result error (%d)\n", - bootcmdresp.result); + pr_info("boot cmd response result error (%d)\n", + bootcmdresp.result); } else { cardp->bootcmdresp = 1; lbs_deb_usbd(&cardp->udev->dev, @@ -901,7 +904,7 @@ static int check_fwfile_format(const uint8_t *data, uint32_t totlen) } while (!exit); if (ret) - lbs_pr_err("firmware file format check FAIL\n"); + pr_err("firmware file format check FAIL\n"); else lbs_deb_fw("firmware file format check PASS\n"); @@ -998,7 +1001,7 @@ static int __if_usb_prog_firmware(struct if_usb_card *cardp, ret = get_fw(cardp, fwname); if (ret) { - lbs_pr_err("failed to find firmware (%d)\n", ret); + pr_err("failed to find firmware (%d)\n", ret); goto done; } @@ -1073,13 +1076,13 @@ restart: usb_kill_urb(cardp->rx_urb); if (!cardp->fwdnldover) { - lbs_pr_info("failed to load fw, resetting device!\n"); + pr_info("failed to load fw, resetting device!\n"); if (--reset_count >= 0) { if_usb_reset_device(cardp); goto restart; } - lbs_pr_info("FW download failure, time = %d ms\n", i * 100); + pr_info("FW download failure, time = %d ms\n", i * 100); ret = -EIO; goto release_fw; } diff --git a/drivers/net/wireless/libertas/main.c b/drivers/net/wireless/libertas/main.c index ae02e6b..1144afd 100644 --- a/drivers/net/wireless/libertas/main.c +++ b/drivers/net/wireless/libertas/main.c @@ -4,6 +4,8 @@ * thread etc.. */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include #include #include @@ -442,7 +444,7 @@ static int lbs_thread(void *data) if (priv->cmd_timed_out && priv->cur_cmd) { struct cmd_ctrl_node *cmdnode = priv->cur_cmd; - lbs_pr_info("Timeout submitting command 0x%04x\n", + pr_info("Timeout submitting command 0x%04x\n", le16_to_cpu(cmdnode->cmdbuf->command)); lbs_complete_command(priv, cmdnode, -ETIMEDOUT); if (priv->reset_card) @@ -470,8 +472,7 @@ static int lbs_thread(void *data) * after firmware fixes it */ priv->psstate = PS_STATE_AWAKE; - lbs_pr_alert("ignore PS_SleepConfirm in " - "non-connected state\n"); + pr_alert("ignore PS_SleepConfirm in non-connected state\n"); } } @@ -565,7 +566,7 @@ int lbs_suspend(struct lbs_private *priv) if (priv->is_deep_sleep) { ret = lbs_set_deep_sleep(priv, 0); if (ret) { - lbs_pr_err("deep sleep cancellation failed: %d\n", ret); + pr_err("deep sleep cancellation failed: %d\n", ret); return ret; } priv->deep_sleep_required = 1; @@ -598,7 +599,7 @@ int lbs_resume(struct lbs_private *priv) priv->deep_sleep_required = 0; ret = lbs_set_deep_sleep(priv, 1); if (ret) - lbs_pr_err("deep sleep activation failed: %d\n", ret); + pr_err("deep sleep activation failed: %d\n", ret); } if (priv->setup_fw_on_resume) @@ -626,7 +627,7 @@ static void lbs_cmd_timeout_handler(unsigned long data) if (!priv->cur_cmd) goto out; - lbs_pr_info("command 0x%04x timed out\n", + pr_info("command 0x%04x timed out\n", le16_to_cpu(priv->cur_cmd->cmdbuf->command)); priv->cmd_timed_out = 1; @@ -732,7 +733,7 @@ static int lbs_init_adapter(struct lbs_private *priv) /* Allocate the command buffers */ if (lbs_allocate_cmd_buffer(priv)) { - lbs_pr_err("Out of memory allocating command buffers\n"); + pr_err("Out of memory allocating command buffers\n"); ret = -ENOMEM; goto out; } @@ -742,7 +743,7 @@ static int lbs_init_adapter(struct lbs_private *priv) /* Create the event FIFO */ ret = kfifo_alloc(&priv->event_fifo, sizeof(u32) * 16, GFP_KERNEL); if (ret) { - lbs_pr_err("Out of memory allocating event FIFO buffer\n"); + pr_err("Out of memory allocating event FIFO buffer\n"); goto out; } @@ -793,7 +794,7 @@ struct lbs_private *lbs_add_card(void *card, struct device *dmdev) /* Allocate an Ethernet device and register it */ wdev = lbs_cfg_alloc(dmdev); if (IS_ERR(wdev)) { - lbs_pr_err("cfg80211 init failed\n"); + pr_err("cfg80211 init failed\n"); goto done; } @@ -802,7 +803,7 @@ struct lbs_private *lbs_add_card(void *card, struct device *dmdev) priv->wdev = wdev; if (lbs_init_adapter(priv)) { - lbs_pr_err("failed to initialize adapter structure.\n"); + pr_err("failed to initialize adapter structure\n"); goto err_wdev; } @@ -934,7 +935,7 @@ int lbs_start_card(struct lbs_private *priv) goto done; if (lbs_cfg_register(priv)) { - lbs_pr_err("cannot register device\n"); + pr_err("cannot register device\n"); goto done; } @@ -944,7 +945,7 @@ int lbs_start_card(struct lbs_private *priv) lbs_debugfs_init_one(priv, dev); - lbs_pr_info("%s: Marvell WLAN 802.11 adapter\n", dev->name); + pr_info("%s: Marvell WLAN 802.11 adapter\n", dev->name); ret = 0; @@ -1071,16 +1072,14 @@ int lbs_get_firmware(struct device *dev, const char *user_helper, if (user_helper) { ret = request_firmware(helper, user_helper, dev); if (ret) { - lbs_pr_err("couldn't find helper firmware %s", - user_helper); + pr_err("couldn't find helper firmware %s", user_helper); goto fail; } } if (user_mainfw) { ret = request_firmware(mainfw, user_mainfw, dev); if (ret) { - lbs_pr_err("couldn't find main firmware %s", - user_mainfw); + pr_err("couldn't find main firmware %s", user_mainfw); goto fail; } } diff --git a/drivers/net/wireless/libertas/mesh.c b/drivers/net/wireless/libertas/mesh.c index a0804d1..054ac07 100644 --- a/drivers/net/wireless/libertas/mesh.c +++ b/drivers/net/wireless/libertas/mesh.c @@ -1,3 +1,5 @@ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include #include #include @@ -267,7 +269,7 @@ int lbs_init_mesh(struct lbs_private *priv) lbs_add_mesh(priv); if (device_create_file(&dev->dev, &dev_attr_lbs_mesh)) - lbs_pr_err("cannot register lbs_mesh attribute\n"); + pr_err("cannot register lbs_mesh attribute\n"); ret = 1; } @@ -395,7 +397,7 @@ int lbs_add_mesh(struct lbs_private *priv) /* Register virtual mesh interface */ ret = register_netdev(mesh_dev); if (ret) { - lbs_pr_err("cannot register mshX virtual interface\n"); + pr_err("cannot register mshX virtual interface\n"); goto err_free; } @@ -973,7 +975,7 @@ static ssize_t mesh_id_get(struct device *dev, struct device_attribute *attr, return ret; if (defs.meshie.val.mesh_id_len > IEEE80211_MAX_SSID_LEN) { - lbs_pr_err("inconsistent mesh ID length"); + pr_err("inconsistent mesh ID length\n"); defs.meshie.val.mesh_id_len = IEEE80211_MAX_SSID_LEN; } diff --git a/drivers/net/wireless/libertas/rx.c b/drivers/net/wireless/libertas/rx.c index a3f4b55..24a12da 100644 --- a/drivers/net/wireless/libertas/rx.c +++ b/drivers/net/wireless/libertas/rx.c @@ -1,6 +1,9 @@ /* * This file contains the handling of RX in wlan driver. */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include #include #include @@ -191,7 +194,7 @@ static u8 convert_mv_rate_to_radiotap(u8 rate) case 12: /* 54 Mbps */ return 108; } - lbs_pr_alert("Invalid Marvell WLAN rate %i\n", rate); + pr_alert("Invalid Marvell WLAN rate %i\n", rate); return 0; } @@ -248,7 +251,7 @@ static int process_rxed_802_11_packet(struct lbs_private *priv, /* add space for the new radio header */ if ((skb_headroom(skb) < sizeof(struct rx_radiotap_hdr)) && pskb_expand_head(skb, sizeof(struct rx_radiotap_hdr), 0, GFP_ATOMIC)) { - lbs_pr_alert("%s: couldn't pskb_expand_head\n", __func__); + pr_alert("%s: couldn't pskb_expand_head\n", __func__); ret = -ENOMEM; kfree_skb(skb); goto done; -- cgit v0.10.2 From f3a57fd148a4afd3c38f558c5b44972cb29ea8ba Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Mon, 2 May 2011 16:49:15 -0700 Subject: libertas: Use netdev_ or dev_ where possible Using the more descriptive logging styles gives a bit more information about the device being operated on. Makes the object trivially smaller too. $ size drivers/net/wireless/libertas/built-in.o.* 187730 2973 38488 229191 37f47 drivers/net/wireless/libertas/built-in.o.new 188195 2973 38488 229656 38118 drivers/net/wireless/libertas/built-in.o.old Signed-off-by: Joe Perches Acked-by: Dan Williams Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/libertas/cfg.c b/drivers/net/wireless/libertas/cfg.c index 73c5f54..a2e8849 100644 --- a/drivers/net/wireless/libertas/cfg.c +++ b/drivers/net/wireless/libertas/cfg.c @@ -1324,7 +1324,8 @@ static int lbs_cfg_connect(struct wiphy *wiphy, struct net_device *dev, sme->ssid, sme->ssid_len, WLAN_CAPABILITY_ESS, WLAN_CAPABILITY_ESS); if (!bss) { - pr_err("assoc: bss %pM not in scan results\n", sme->bssid); + wiphy_err(wiphy, "assoc: bss %pM not in scan results\n", + sme->bssid); ret = -ENOENT; goto done; } @@ -1381,8 +1382,8 @@ static int lbs_cfg_connect(struct wiphy *wiphy, struct net_device *dev, lbs_enable_rsn(priv, sme->crypto.cipher_group != 0); break; default: - pr_err("unsupported cipher group 0x%x\n", - sme->crypto.cipher_group); + wiphy_err(wiphy, "unsupported cipher group 0x%x\n", + sme->crypto.cipher_group); ret = -ENOTSUPP; goto done; } @@ -1500,7 +1501,7 @@ static int lbs_cfg_add_key(struct wiphy *wiphy, struct net_device *netdev, params->key, params->key_len); break; default: - pr_err("unhandled cipher 0x%x\n", params->cipher); + wiphy_err(wiphy, "unhandled cipher 0x%x\n", params->cipher); ret = -ENOTSUPP; break; } diff --git a/drivers/net/wireless/libertas/cmd.c b/drivers/net/wireless/libertas/cmd.c index af8ef90..6d59b4c 100644 --- a/drivers/net/wireless/libertas/cmd.c +++ b/drivers/net/wireless/libertas/cmd.c @@ -3,8 +3,6 @@ * It prepares command and sends it to firmware when it is ready. */ -#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt - #include #include #include @@ -112,7 +110,7 @@ int lbs_update_hw_spec(struct lbs_private *priv) * CF card firmware 5.0.16p0: cap 0x00000303 * USB dongle firmware 5.110.17p2: cap 0x00000303 */ - pr_info("%pM, fw %u.%u.%up%u, cap 0x%08x\n", + netdev_info(priv->dev, "%pM, fw %u.%u.%up%u, cap 0x%08x\n", cmd.permanentaddr, priv->fwrelease >> 24 & 0xff, priv->fwrelease >> 16 & 0xff, @@ -143,7 +141,8 @@ int lbs_update_hw_spec(struct lbs_private *priv) /* if it's unidentified region code, use the default (USA) */ if (i >= MRVDRV_MAX_REGION_CODE) { priv->regioncode = 0x10; - pr_info("unidentified region code; using the default (USA)\n"); + netdev_info(priv->dev, + "unidentified region code; using the default (USA)\n"); } if (priv->current_addr[0] == 0xff) @@ -213,7 +212,7 @@ int lbs_host_sleep_cfg(struct lbs_private *priv, uint32_t criteria, (uint8_t *)&cmd_config.wol_conf, sizeof(struct wol_config)); } else { - pr_info("HOST_SLEEP_CFG failed %d\n", ret); + netdev_info(priv->dev, "HOST_SLEEP_CFG failed %d\n", ret); } return ret; @@ -316,7 +315,7 @@ static int lbs_wait_for_ds_awake(struct lbs_private *priv) if (priv->is_deep_sleep) { if (!wait_event_interruptible_timeout(priv->ds_awake_q, !priv->is_deep_sleep, (10 * HZ))) { - pr_err("ds_awake_q: timer expired\n"); + netdev_err(priv->dev, "ds_awake_q: timer expired\n"); ret = -1; } } @@ -341,7 +340,7 @@ int lbs_set_deep_sleep(struct lbs_private *priv, int deep_sleep) netif_carrier_off(priv->dev); } } else { - pr_err("deep sleep: already enabled\n"); + netdev_err(priv->dev, "deep sleep: already enabled\n"); } } else { if (priv->is_deep_sleep) { @@ -351,7 +350,8 @@ int lbs_set_deep_sleep(struct lbs_private *priv, int deep_sleep) if (!ret) { ret = lbs_wait_for_ds_awake(priv); if (ret) - pr_err("deep sleep: wakeup failed\n"); + netdev_err(priv->dev, + "deep sleep: wakeup failed\n"); } } } @@ -385,8 +385,9 @@ int lbs_set_host_sleep(struct lbs_private *priv, int host_sleep) ret = lbs_host_sleep_cfg(priv, priv->wol_criteria, (struct wol_config *)NULL); if (ret) { - pr_info("Host sleep configuration failed: %d\n", - ret); + netdev_info(priv->dev, + "Host sleep configuration failed: %d\n", + ret); return ret; } if (priv->psstate == PS_STATE_FULL_POWER) { @@ -396,19 +397,21 @@ int lbs_set_host_sleep(struct lbs_private *priv, int host_sleep) sizeof(cmd), lbs_ret_host_sleep_activate, 0); if (ret) - pr_info("HOST_SLEEP_ACTIVATE failed: %d\n", - ret); + netdev_info(priv->dev, + "HOST_SLEEP_ACTIVATE failed: %d\n", + ret); } if (!wait_event_interruptible_timeout( priv->host_sleep_q, priv->is_host_sleep_activated, (10 * HZ))) { - pr_err("host_sleep_q: timer expired\n"); + netdev_err(priv->dev, + "host_sleep_q: timer expired\n"); ret = -1; } } else { - pr_err("host sleep: already enabled\n"); + netdev_err(priv->dev, "host sleep: already enabled\n"); } } else { if (priv->is_host_sleep_activated) @@ -1008,7 +1011,8 @@ static void lbs_submit_command(struct lbs_private *priv, ret = priv->hw_host_to_card(priv, MVMS_CMD, (u8 *) cmd, cmdsize); if (ret) { - pr_info("DNLD_CMD: hw_host_to_card failed: %d\n", ret); + netdev_info(priv->dev, "DNLD_CMD: hw_host_to_card failed: %d\n", + ret); /* Let the timer kick in and retry, and potentially reset the whole thing if the condition persists */ timeo = HZ/4; @@ -1277,7 +1281,8 @@ int lbs_execute_next_command(struct lbs_private *priv) spin_lock_irqsave(&priv->driver_lock, flags); if (priv->cur_cmd) { - pr_alert( "EXEC_NEXT_CMD: already processing command!\n"); + netdev_alert(priv->dev, + "EXEC_NEXT_CMD: already processing command!\n"); spin_unlock_irqrestore(&priv->driver_lock, flags); ret = -1; goto done; @@ -1439,7 +1444,7 @@ static void lbs_send_confirmsleep(struct lbs_private *priv) ret = priv->hw_host_to_card(priv, MVMS_CMD, (u8 *) &confirm_sleep, sizeof(confirm_sleep)); if (ret) { - pr_alert("confirm_sleep failed\n"); + netdev_alert(priv->dev, "confirm_sleep failed\n"); goto out; } @@ -1665,7 +1670,8 @@ int __lbs_cmd(struct lbs_private *priv, uint16_t command, spin_lock_irqsave(&priv->driver_lock, flags); ret = cmdnode->result; if (ret) - pr_info("PREP_CMD: command 0x%04x failed: %d\n", command, ret); + netdev_info(priv->dev, "PREP_CMD: command 0x%04x failed: %d\n", + command, ret); __lbs_cleanup_and_insert_cmd(priv, cmdnode); spin_unlock_irqrestore(&priv->driver_lock, flags); diff --git a/drivers/net/wireless/libertas/cmdresp.c b/drivers/net/wireless/libertas/cmdresp.c index 45291a4..207fc36 100644 --- a/drivers/net/wireless/libertas/cmdresp.c +++ b/drivers/net/wireless/libertas/cmdresp.c @@ -3,8 +3,6 @@ * responses as well as events generated by firmware. */ -#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt - #include #include #include @@ -88,17 +86,18 @@ int lbs_process_command_response(struct lbs_private *priv, u8 *data, u32 len) lbs_deb_hex(LBS_DEB_CMD, "CMD_RESP", (void *) resp, len); if (resp->seqnum != priv->cur_cmd->cmdbuf->seqnum) { - pr_info("Received CMD_RESP with invalid sequence %d (expected %d)\n", - le16_to_cpu(resp->seqnum), - le16_to_cpu(priv->cur_cmd->cmdbuf->seqnum)); + netdev_info(priv->dev, + "Received CMD_RESP with invalid sequence %d (expected %d)\n", + le16_to_cpu(resp->seqnum), + le16_to_cpu(priv->cur_cmd->cmdbuf->seqnum)); spin_unlock_irqrestore(&priv->driver_lock, flags); ret = -1; goto done; } if (respcmd != CMD_RET(curcmd) && respcmd != CMD_RET_802_11_ASSOCIATE && curcmd != CMD_802_11_ASSOCIATE) { - pr_info("Invalid CMD_RESP %x to command %x!\n", - respcmd, curcmd); + netdev_info(priv->dev, "Invalid CMD_RESP %x to command %x!\n", + respcmd, curcmd); spin_unlock_irqrestore(&priv->driver_lock, flags); ret = -1; goto done; @@ -107,8 +106,9 @@ int lbs_process_command_response(struct lbs_private *priv, u8 *data, u32 len) if (resp->result == cpu_to_le16(0x0004)) { /* 0x0004 means -EAGAIN. Drop the response, let it time out and be resubmitted */ - pr_info("Firmware returns DEFER to command %x. Will let it time out...\n", - le16_to_cpu(resp->command)); + netdev_info(priv->dev, + "Firmware returns DEFER to command %x. Will let it time out...\n", + le16_to_cpu(resp->command)); spin_unlock_irqrestore(&priv->driver_lock, flags); ret = -1; goto done; @@ -319,28 +319,28 @@ int lbs_process_event(struct lbs_private *priv, u32 event) lbs_deb_cmd("EVENT: ADHOC beacon lost\n"); break; case MACREG_INT_CODE_RSSI_LOW: - pr_alert("EVENT: rssi low\n"); + netdev_alert(priv->dev, "EVENT: rssi low\n"); break; case MACREG_INT_CODE_SNR_LOW: - pr_alert("EVENT: snr low\n"); + netdev_alert(priv->dev, "EVENT: snr low\n"); break; case MACREG_INT_CODE_MAX_FAIL: - pr_alert("EVENT: max fail\n"); + netdev_alert(priv->dev, "EVENT: max fail\n"); break; case MACREG_INT_CODE_RSSI_HIGH: - pr_alert("EVENT: rssi high\n"); + netdev_alert(priv->dev, "EVENT: rssi high\n"); break; case MACREG_INT_CODE_SNR_HIGH: - pr_alert("EVENT: snr high\n"); + netdev_alert(priv->dev, "EVENT: snr high\n"); break; case MACREG_INT_CODE_MESH_AUTO_STARTED: /* Ignore spurious autostart events */ - pr_info("EVENT: MESH_AUTO_STARTED (ignoring)\n"); + netdev_info(priv->dev, "EVENT: MESH_AUTO_STARTED (ignoring)\n"); break; default: - pr_alert("EVENT: unknown event id %d\n", event); + netdev_alert(priv->dev, "EVENT: unknown event id %d\n", event); break; } diff --git a/drivers/net/wireless/libertas/debugfs.c b/drivers/net/wireless/libertas/debugfs.c index 0bd79c5..23250f6 100644 --- a/drivers/net/wireless/libertas/debugfs.c +++ b/drivers/net/wireless/libertas/debugfs.c @@ -1,5 +1,3 @@ -#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt - #include #include #include @@ -153,13 +151,14 @@ static ssize_t lbs_host_sleep_write(struct file *file, ret = lbs_set_host_sleep(priv, 0); else if (host_sleep == 1) { if (priv->wol_criteria == EHS_REMOVE_WAKEUP) { - pr_info("wake parameters not configured\n"); + netdev_info(priv->dev, + "wake parameters not configured\n"); ret = -EINVAL; goto out_unlock; } ret = lbs_set_host_sleep(priv, 1); } else { - pr_err("invalid option\n"); + netdev_err(priv->dev, "invalid option\n"); ret = -EINVAL; } diff --git a/drivers/net/wireless/libertas/if_cs.c b/drivers/net/wireless/libertas/if_cs.c index f2d1011..63ed579 100644 --- a/drivers/net/wireless/libertas/if_cs.c +++ b/drivers/net/wireless/libertas/if_cs.c @@ -364,7 +364,7 @@ static int if_cs_send_cmd(struct lbs_private *priv, u8 *buf, u16 nb) if (status & IF_CS_BIT_COMMAND) break; if (++loops > 100) { - pr_err("card not ready for commands\n"); + netdev_err(priv->dev, "card not ready for commands\n"); goto done; } mdelay(1); @@ -434,14 +434,16 @@ static int if_cs_receive_cmdres(struct lbs_private *priv, u8 *data, u32 *len) /* is hardware ready? */ status = if_cs_read16(priv->card, IF_CS_CARD_STATUS); if ((status & IF_CS_BIT_RESP) == 0) { - pr_err("no cmd response in card\n"); + netdev_err(priv->dev, "no cmd response in card\n"); *len = 0; goto out; } *len = if_cs_read16(priv->card, IF_CS_RESP_LEN); if ((*len == 0) || (*len > LBS_CMD_BUFFER_SIZE)) { - pr_err("card cmd buffer has invalid # of bytes (%d)\n", *len); + netdev_err(priv->dev, + "card cmd buffer has invalid # of bytes (%d)\n", + *len); goto out; } @@ -475,7 +477,9 @@ static struct sk_buff *if_cs_receive_data(struct lbs_private *priv) len = if_cs_read16(priv->card, IF_CS_READ_LEN); if (len == 0 || len > MRVDRV_ETH_RX_PACKET_BUFFER_SIZE) { - pr_err("card data buffer has invalid # of bytes (%d)\n", len); + netdev_err(priv->dev, + "card data buffer has invalid # of bytes (%d)\n", + len); priv->dev->stats.rx_dropped++; goto dat_err; } @@ -761,7 +765,8 @@ static int if_cs_host_to_card(struct lbs_private *priv, ret = if_cs_send_cmd(priv, buf, nb); break; default: - pr_err("%s: unsupported type %d\n", __func__, type); + netdev_err(priv->dev, "%s: unsupported type %d\n", + __func__, type); } lbs_deb_leave_args(LBS_DEB_CS, "ret %d", ret); diff --git a/drivers/net/wireless/libertas/if_sdio.c b/drivers/net/wireless/libertas/if_sdio.c index ab86779..a7b5cb0 100644 --- a/drivers/net/wireless/libertas/if_sdio.c +++ b/drivers/net/wireless/libertas/if_sdio.c @@ -851,7 +851,7 @@ static int if_sdio_enter_deep_sleep(struct lbs_private *priv) ret = __lbs_cmd(priv, CMD_802_11_DEEP_SLEEP, &cmd, sizeof(cmd), lbs_cmd_copyback, (unsigned long) &cmd); if (ret) - pr_err("DEEP_SLEEP cmd failed\n"); + netdev_err(priv->dev, "DEEP_SLEEP cmd failed\n"); mdelay(200); return ret; @@ -867,7 +867,7 @@ static int if_sdio_exit_deep_sleep(struct lbs_private *priv) sdio_writeb(card->func, HOST_POWER_UP, CONFIGURATION_REG, &ret); if (ret) - pr_err("sdio_writeb failed!\n"); + netdev_err(priv->dev, "sdio_writeb failed!\n"); sdio_release_host(card->func); lbs_deb_leave_args(LBS_DEB_SDIO, "ret %d", ret); @@ -884,7 +884,7 @@ static int if_sdio_reset_deep_sleep_wakeup(struct lbs_private *priv) sdio_writeb(card->func, 0, CONFIGURATION_REG, &ret); if (ret) - pr_err("sdio_writeb failed!\n"); + netdev_err(priv->dev, "sdio_writeb failed!\n"); sdio_release_host(card->func); lbs_deb_leave_args(LBS_DEB_SDIO, "ret %d", ret); @@ -1103,7 +1103,7 @@ static int if_sdio_probe(struct sdio_func *func, lbs_deb_sdio("send function INIT command\n"); if (__lbs_cmd(priv, CMD_FUNC_INIT, &cmd, sizeof(cmd), lbs_cmd_copyback, (unsigned long) &cmd)) - pr_alert("CMD_FUNC_INIT cmd failed\n"); + netdev_alert(priv->dev, "CMD_FUNC_INIT cmd failed\n"); } ret = lbs_start_card(priv); @@ -1204,19 +1204,20 @@ static int if_sdio_suspend(struct device *dev) mmc_pm_flag_t flags = sdio_get_host_pm_caps(func); - pr_info("%s: suspend: PM flags = 0x%x\n", sdio_func_id(func), flags); + dev_info(dev, "%s: suspend: PM flags = 0x%x\n", + sdio_func_id(func), flags); /* If we aren't being asked to wake on anything, we should bail out * and let the SD stack power down the card. */ if (card->priv->wol_criteria == EHS_REMOVE_WAKEUP) { - pr_info("Suspend without wake params -- powering down card\n"); + dev_info(dev, "Suspend without wake params -- powering down card\n"); return -ENOSYS; } if (!(flags & MMC_PM_KEEP_POWER)) { - pr_err("%s: cannot remain alive while host is suspended\n", - sdio_func_id(func)); + dev_err(dev, "%s: cannot remain alive while host is suspended\n", + sdio_func_id(func)); return -ENOSYS; } @@ -1237,7 +1238,7 @@ static int if_sdio_resume(struct device *dev) struct if_sdio_card *card = sdio_get_drvdata(func); int ret; - pr_info("%s: resume: we're back\n", sdio_func_id(func)); + dev_info(dev, "%s: resume: we're back\n", sdio_func_id(func)); ret = lbs_resume(card->priv); diff --git a/drivers/net/wireless/libertas/if_spi.c b/drivers/net/wireless/libertas/if_spi.c index 4d19b57..463352c 100644 --- a/drivers/net/wireless/libertas/if_spi.c +++ b/drivers/net/wireless/libertas/if_spi.c @@ -585,6 +585,7 @@ static int if_spi_prog_main_firmware_check_len(struct if_spi_card *card, static int if_spi_prog_main_firmware(struct if_spi_card *card, const struct firmware *firmware) { + struct lbs_private *priv = card->priv; int len, prev_len; int bytes, crc_err = 0, err = 0; const u8 *fw; @@ -598,8 +599,9 @@ static int if_spi_prog_main_firmware(struct if_spi_card *card, err = spu_wait_for_u16(card, IF_SPI_SCRATCH_1_REG, 0, 0); if (err) { - pr_err("%s: timed out waiting for initial scratch reg = 0\n", - __func__); + netdev_err(priv->dev, + "%s: timed out waiting for initial scratch reg = 0\n", + __func__); goto out; } @@ -617,7 +619,8 @@ static int if_spi_prog_main_firmware(struct if_spi_card *card, * If there are no more bytes left, we would normally * expect to have terminated with len = 0 */ - pr_err("Firmware load wants more bytes than we have to offer.\n"); + netdev_err(priv->dev, + "Firmware load wants more bytes than we have to offer.\n"); break; } if (crc_err) { @@ -706,12 +709,14 @@ static int if_spi_c2h_cmd(struct if_spi_card *card) if (err) goto out; if (!len) { - pr_err("%s: error: card has no data for host\n", __func__); + netdev_err(priv->dev, "%s: error: card has no data for host\n", + __func__); err = -EINVAL; goto out; } else if (len > IF_SPI_CMD_BUF_SIZE) { - pr_err("%s: error: response packet too large: %d bytes, but maximum is %d\n", - __func__, len, IF_SPI_CMD_BUF_SIZE); + netdev_err(priv->dev, + "%s: error: response packet too large: %d bytes, but maximum is %d\n", + __func__, len, IF_SPI_CMD_BUF_SIZE); err = -EINVAL; goto out; } @@ -732,7 +737,7 @@ static int if_spi_c2h_cmd(struct if_spi_card *card) out: if (err) - pr_err("%s: err=%d\n", __func__, err); + netdev_err(priv->dev, "%s: err=%d\n", __func__, err); lbs_deb_leave(LBS_DEB_SPI); return err; } @@ -740,6 +745,7 @@ out: /* Move data from the card to the host */ static int if_spi_c2h_data(struct if_spi_card *card) { + struct lbs_private *priv = card->priv; struct sk_buff *skb; char *data; u16 len; @@ -752,12 +758,14 @@ static int if_spi_c2h_data(struct if_spi_card *card) if (err) goto out; if (!len) { - pr_err("%s: error: card has no data for host\n", __func__); + netdev_err(priv->dev, "%s: error: card has no data for host\n", + __func__); err = -EINVAL; goto out; } else if (len > MRVDRV_ETH_RX_PACKET_BUFFER_SIZE) { - pr_err("%s: error: card has %d bytes of data, but our maximum skb size is %zu\n", - __func__, len, MRVDRV_ETH_RX_PACKET_BUFFER_SIZE); + netdev_err(priv->dev, + "%s: error: card has %d bytes of data, but our maximum skb size is %zu\n", + __func__, len, MRVDRV_ETH_RX_PACKET_BUFFER_SIZE); err = -EINVAL; goto out; } @@ -788,7 +796,7 @@ free_skb: dev_kfree_skb(skb); out: if (err) - pr_err("%s: err=%d\n", __func__, err); + netdev_err(priv->dev, "%s: err=%d\n", __func__, err); lbs_deb_leave(LBS_DEB_SPI); return err; } @@ -797,6 +805,7 @@ out: static void if_spi_h2c(struct if_spi_card *card, struct if_spi_packet *packet, int type) { + struct lbs_private *priv = card->priv; int err = 0; u16 int_type, port_reg; @@ -810,7 +819,8 @@ static void if_spi_h2c(struct if_spi_card *card, port_reg = IF_SPI_CMD_RDWRPORT_REG; break; default: - pr_err("can't transfer buffer of type %d\n", type); + netdev_err(priv->dev, "can't transfer buffer of type %d\n", + type); err = -EINVAL; goto out; } @@ -824,7 +834,7 @@ out: kfree(packet); if (err) - pr_err("%s: error %d\n", __func__, err); + netdev_err(priv->dev, "%s: error %d\n", __func__, err); } /* Inform the host about a card event */ @@ -848,7 +858,7 @@ static void if_spi_e2h(struct if_spi_card *card) lbs_queue_event(priv, cause & 0xff); out: if (err) - pr_err("%s: error %d\n", __func__, err); + netdev_err(priv->dev, "%s: error %d\n", __func__, err); } static void if_spi_host_to_card_worker(struct work_struct *work) @@ -858,8 +868,10 @@ static void if_spi_host_to_card_worker(struct work_struct *work) u16 hiStatus; unsigned long flags; struct if_spi_packet *packet; + struct lbs_private *priv; card = container_of(work, struct if_spi_card, packet_work); + priv = card->priv; lbs_deb_enter(LBS_DEB_SPI); @@ -870,7 +882,7 @@ static void if_spi_host_to_card_worker(struct work_struct *work) err = spu_read_u16(card, IF_SPI_HOST_INT_STATUS_REG, &hiStatus); if (err) { - pr_err("I/O error\n"); + netdev_err(priv->dev, "I/O error\n"); goto err; } @@ -933,7 +945,7 @@ static void if_spi_host_to_card_worker(struct work_struct *work) err: if (err) - pr_err("%s: got error %d\n", __func__, err); + netdev_err(priv->dev, "%s: got error %d\n", __func__, err); lbs_deb_leave(LBS_DEB_SPI); } @@ -956,7 +968,8 @@ static int if_spi_host_to_card(struct lbs_private *priv, lbs_deb_enter_args(LBS_DEB_SPI, "type %d, bytes %d", type, nb); if (nb == 0) { - pr_err("%s: invalid size requested: %d\n", __func__, nb); + netdev_err(priv->dev, "%s: invalid size requested: %d\n", + __func__, nb); err = -EINVAL; goto out; } @@ -984,7 +997,8 @@ static int if_spi_host_to_card(struct lbs_private *priv, spin_unlock_irqrestore(&card->buffer_lock, flags); break; default: - pr_err("can't transfer buffer of type %d\n", type); + netdev_err(priv->dev, "can't transfer buffer of type %d\n", + type); err = -EINVAL; break; } @@ -1017,6 +1031,7 @@ static irqreturn_t if_spi_host_interrupt(int irq, void *dev_id) static int if_spi_init_card(struct if_spi_card *card) { + struct lbs_private *priv = card->priv; struct spi_device *spi = card->spi; int err, i; u32 scratch; @@ -1045,7 +1060,8 @@ static int if_spi_init_card(struct if_spi_card *card) break; } if (i == ARRAY_SIZE(fw_table)) { - pr_err("Unsupported chip_id: 0x%02x\n", card->card_id); + netdev_err(priv->dev, "Unsupported chip_id: 0x%02x\n", + card->card_id); err = -ENODEV; goto out; } @@ -1054,7 +1070,8 @@ static int if_spi_init_card(struct if_spi_card *card) card->card_id, &fw_table[0], &helper, &mainfw); if (err) { - pr_err("failed to find firmware (%d)\n", err); + netdev_err(priv->dev, "failed to find firmware (%d)\n", + err); goto out; } diff --git a/drivers/net/wireless/libertas/if_usb.c b/drivers/net/wireless/libertas/if_usb.c index b68e162..b5acc39 100644 --- a/drivers/net/wireless/libertas/if_usb.c +++ b/drivers/net/wireless/libertas/if_usb.c @@ -206,7 +206,7 @@ static void if_usb_setup_firmware(struct lbs_private *priv) wake_method.hdr.size = cpu_to_le16(sizeof(wake_method)); wake_method.action = cpu_to_le16(CMD_ACT_GET); if (lbs_cmd_with_response(priv, CMD_802_11_FW_WAKE_METHOD, &wake_method)) { - pr_info("Firmware does not seem to support PS mode\n"); + netdev_info(priv->dev, "Firmware does not seem to support PS mode\n"); priv->fwcapinfo &= ~FW_CAPINFO_PS; } else { if (le16_to_cpu(wake_method.method) == CMD_WAKE_METHOD_COMMAND_INT) { @@ -215,7 +215,8 @@ static void if_usb_setup_firmware(struct lbs_private *priv) /* The versions which boot up this way don't seem to work even if we set it to the command interrupt */ priv->fwcapinfo &= ~FW_CAPINFO_PS; - pr_info("Firmware doesn't wake via command interrupt; disabling PS mode\n"); + netdev_info(priv->dev, + "Firmware doesn't wake via command interrupt; disabling PS mode\n"); } } } @@ -351,10 +352,12 @@ static int if_usb_probe(struct usb_interface *intf, usb_set_intfdata(intf, cardp); if (device_create_file(&priv->dev->dev, &dev_attr_lbs_flash_fw)) - pr_err("cannot register lbs_flash_fw attribute\n"); + netdev_err(priv->dev, + "cannot register lbs_flash_fw attribute\n"); if (device_create_file(&priv->dev->dev, &dev_attr_lbs_flash_boot2)) - pr_err("cannot register lbs_flash_boot2 attribute\n"); + netdev_err(priv->dev, + "cannot register lbs_flash_boot2 attribute\n"); /* * EHS_REMOVE_WAKEUP is not supported on all versions of the firmware. diff --git a/drivers/net/wireless/libertas/main.c b/drivers/net/wireless/libertas/main.c index 1144afd..84d05a7 100644 --- a/drivers/net/wireless/libertas/main.c +++ b/drivers/net/wireless/libertas/main.c @@ -444,8 +444,8 @@ static int lbs_thread(void *data) if (priv->cmd_timed_out && priv->cur_cmd) { struct cmd_ctrl_node *cmdnode = priv->cur_cmd; - pr_info("Timeout submitting command 0x%04x\n", - le16_to_cpu(cmdnode->cmdbuf->command)); + netdev_info(dev, "Timeout submitting command 0x%04x\n", + le16_to_cpu(cmdnode->cmdbuf->command)); lbs_complete_command(priv, cmdnode, -ETIMEDOUT); if (priv->reset_card) priv->reset_card(priv); @@ -472,7 +472,8 @@ static int lbs_thread(void *data) * after firmware fixes it */ priv->psstate = PS_STATE_AWAKE; - pr_alert("ignore PS_SleepConfirm in non-connected state\n"); + netdev_alert(dev, + "ignore PS_SleepConfirm in non-connected state\n"); } } @@ -566,7 +567,8 @@ int lbs_suspend(struct lbs_private *priv) if (priv->is_deep_sleep) { ret = lbs_set_deep_sleep(priv, 0); if (ret) { - pr_err("deep sleep cancellation failed: %d\n", ret); + netdev_err(priv->dev, + "deep sleep cancellation failed: %d\n", ret); return ret; } priv->deep_sleep_required = 1; @@ -599,7 +601,8 @@ int lbs_resume(struct lbs_private *priv) priv->deep_sleep_required = 0; ret = lbs_set_deep_sleep(priv, 1); if (ret) - pr_err("deep sleep activation failed: %d\n", ret); + netdev_err(priv->dev, + "deep sleep activation failed: %d\n", ret); } if (priv->setup_fw_on_resume) @@ -627,8 +630,8 @@ static void lbs_cmd_timeout_handler(unsigned long data) if (!priv->cur_cmd) goto out; - pr_info("command 0x%04x timed out\n", - le16_to_cpu(priv->cur_cmd->cmdbuf->command)); + netdev_info(priv->dev, "command 0x%04x timed out\n", + le16_to_cpu(priv->cur_cmd->cmdbuf->command)); priv->cmd_timed_out = 1; wake_up_interruptible(&priv->waitq); @@ -945,7 +948,7 @@ int lbs_start_card(struct lbs_private *priv) lbs_debugfs_init_one(priv, dev); - pr_info("%s: Marvell WLAN 802.11 adapter\n", dev->name); + netdev_info(dev, "Marvell WLAN 802.11 adapter\n"); ret = 0; @@ -1072,14 +1075,16 @@ int lbs_get_firmware(struct device *dev, const char *user_helper, if (user_helper) { ret = request_firmware(helper, user_helper, dev); if (ret) { - pr_err("couldn't find helper firmware %s", user_helper); + dev_err(dev, "couldn't find helper firmware %s\n", + user_helper); goto fail; } } if (user_mainfw) { ret = request_firmware(mainfw, user_mainfw, dev); if (ret) { - pr_err("couldn't find main firmware %s", user_mainfw); + dev_err(dev, "couldn't find main firmware %s\n", + user_mainfw); goto fail; } } diff --git a/drivers/net/wireless/libertas/mesh.c b/drivers/net/wireless/libertas/mesh.c index 054ac07..24cf066 100644 --- a/drivers/net/wireless/libertas/mesh.c +++ b/drivers/net/wireless/libertas/mesh.c @@ -269,7 +269,7 @@ int lbs_init_mesh(struct lbs_private *priv) lbs_add_mesh(priv); if (device_create_file(&dev->dev, &dev_attr_lbs_mesh)) - pr_err("cannot register lbs_mesh attribute\n"); + netdev_err(dev, "cannot register lbs_mesh attribute\n"); ret = 1; } @@ -975,7 +975,7 @@ static ssize_t mesh_id_get(struct device *dev, struct device_attribute *attr, return ret; if (defs.meshie.val.mesh_id_len > IEEE80211_MAX_SSID_LEN) { - pr_err("inconsistent mesh ID length\n"); + dev_err(dev, "inconsistent mesh ID length\n"); defs.meshie.val.mesh_id_len = IEEE80211_MAX_SSID_LEN; } diff --git a/drivers/net/wireless/libertas/rx.c b/drivers/net/wireless/libertas/rx.c index 24a12da..fdb0448 100644 --- a/drivers/net/wireless/libertas/rx.c +++ b/drivers/net/wireless/libertas/rx.c @@ -251,7 +251,7 @@ static int process_rxed_802_11_packet(struct lbs_private *priv, /* add space for the new radio header */ if ((skb_headroom(skb) < sizeof(struct rx_radiotap_hdr)) && pskb_expand_head(skb, sizeof(struct rx_radiotap_hdr), 0, GFP_ATOMIC)) { - pr_alert("%s: couldn't pskb_expand_head\n", __func__); + netdev_alert(dev, "%s: couldn't pskb_expand_head\n", __func__); ret = -ENOMEM; kfree_skb(skb); goto done; -- cgit v0.10.2 From 7d8e18a69d9ebb8bf51748842929f8cc1ad61d49 Mon Sep 17 00:00:00 2001 From: Henry C Chang Date: Wed, 11 May 2011 10:29:52 +0000 Subject: ceph: print debug message before put mds session The mds session, s, could be freed during ceph_put_mds_session. Move dout before ceph_put_mds_session. Signed-off-by: Henry C Chang Signed-off-by: Sage Weil diff --git a/fs/ceph/mds_client.c b/fs/ceph/mds_client.c index f60b07b..d0fae4c 100644 --- a/fs/ceph/mds_client.c +++ b/fs/ceph/mds_client.c @@ -3304,8 +3304,8 @@ static void con_put(struct ceph_connection *con) { struct ceph_mds_session *s = con->private; + dout("mdsc con_put %p (%d)\n", s, atomic_read(&s->s_ref) - 1); ceph_put_mds_session(s); - dout("mdsc con_put %p (%d)\n", s, atomic_read(&s->s_ref)); } /* -- cgit v0.10.2 From a26a185d27b49e1656b335ef8ad1a32f7a0e7d7f Mon Sep 17 00:00:00 2001 From: Henry C Chang Date: Wed, 11 May 2011 10:29:53 +0000 Subject: ceph: fix list_add in ceph_put_snap_realm Signed-off-by: Henry C Chang Signed-off-by: Sage Weil diff --git a/fs/ceph/snap.c b/fs/ceph/snap.c index e86ec11..24067d6 100644 --- a/fs/ceph/snap.c +++ b/fs/ceph/snap.c @@ -206,7 +206,7 @@ void ceph_put_snap_realm(struct ceph_mds_client *mdsc, up_write(&mdsc->snap_rwsem); } else { spin_lock(&mdsc->snap_empty_lock); - list_add(&mdsc->snap_empty, &realm->empty_item); + list_add(&realm->empty_item, &mdsc->snap_empty); spin_unlock(&mdsc->snap_empty_lock); } } -- cgit v0.10.2 From d3d0720d4a7a46e93e055e5b0f1a8bd612743ed6 Mon Sep 17 00:00:00 2001 From: Henry C Chang Date: Wed, 11 May 2011 10:29:54 +0000 Subject: ceph: do not use i_wrbuffer_ref as refcount for Fb cap We increments i_wrbuffer_ref when taking the Fb cap. This breaks the dirty page accounting and causes looping in __ceph_do_pending_vmtruncate, and ceph client hangs. This bug can be reproduced occasionally by running blogbench. Add a new field i_wb_ref to inode and dedicate it to Fb reference counting. Signed-off-by: Henry C Chang Signed-off-by: Sage Weil diff --git a/fs/ceph/caps.c b/fs/ceph/caps.c index 9fa0866..2a5404c 100644 --- a/fs/ceph/caps.c +++ b/fs/ceph/caps.c @@ -819,7 +819,7 @@ int __ceph_caps_used(struct ceph_inode_info *ci) used |= CEPH_CAP_FILE_CACHE; if (ci->i_wr_ref) used |= CEPH_CAP_FILE_WR; - if (ci->i_wrbuffer_ref) + if (ci->i_wb_ref || ci->i_wrbuffer_ref) used |= CEPH_CAP_FILE_BUFFER; return used; } @@ -1990,11 +1990,11 @@ static void __take_cap_refs(struct ceph_inode_info *ci, int got) if (got & CEPH_CAP_FILE_WR) ci->i_wr_ref++; if (got & CEPH_CAP_FILE_BUFFER) { - if (ci->i_wrbuffer_ref == 0) + if (ci->i_wb_ref == 0) ihold(&ci->vfs_inode); - ci->i_wrbuffer_ref++; - dout("__take_cap_refs %p wrbuffer %d -> %d (?)\n", - &ci->vfs_inode, ci->i_wrbuffer_ref-1, ci->i_wrbuffer_ref); + ci->i_wb_ref++; + dout("__take_cap_refs %p wb %d -> %d (?)\n", + &ci->vfs_inode, ci->i_wb_ref-1, ci->i_wb_ref); } } @@ -2169,12 +2169,12 @@ void ceph_put_cap_refs(struct ceph_inode_info *ci, int had) if (--ci->i_rdcache_ref == 0) last++; if (had & CEPH_CAP_FILE_BUFFER) { - if (--ci->i_wrbuffer_ref == 0) { + if (--ci->i_wb_ref == 0) { last++; put++; } - dout("put_cap_refs %p wrbuffer %d -> %d (?)\n", - inode, ci->i_wrbuffer_ref+1, ci->i_wrbuffer_ref); + dout("put_cap_refs %p wb %d -> %d (?)\n", + inode, ci->i_wb_ref+1, ci->i_wb_ref); } if (had & CEPH_CAP_FILE_WR) if (--ci->i_wr_ref == 0) { diff --git a/fs/ceph/inode.c b/fs/ceph/inode.c index 03d6daf..70b6a48 100644 --- a/fs/ceph/inode.c +++ b/fs/ceph/inode.c @@ -355,6 +355,7 @@ struct inode *ceph_alloc_inode(struct super_block *sb) ci->i_rd_ref = 0; ci->i_rdcache_ref = 0; ci->i_wr_ref = 0; + ci->i_wb_ref = 0; ci->i_wrbuffer_ref = 0; ci->i_wrbuffer_ref_head = 0; ci->i_shared_gen = 0; diff --git a/fs/ceph/super.h b/fs/ceph/super.h index b1f1b8b..f5cabef 100644 --- a/fs/ceph/super.h +++ b/fs/ceph/super.h @@ -293,7 +293,7 @@ struct ceph_inode_info { /* held references to caps */ int i_pin_ref; - int i_rd_ref, i_rdcache_ref, i_wr_ref; + int i_rd_ref, i_rdcache_ref, i_wr_ref, i_wb_ref; int i_wrbuffer_ref, i_wrbuffer_ref_head; u32 i_shared_gen; /* increment each time we get FILE_SHARED */ u32 i_rdcache_gen; /* incremented each time we get FILE_CACHE. */ -- cgit v0.10.2 From c56b2ddd5ff4352cdb0df07eefba8068d043382e Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Tue, 10 May 2011 16:56:46 +0200 Subject: omap: iommu: Return IRQ_HANDLED in fault handler when no fault occured Commit d594f1f31afe13edd8c02f3854a65cc58cfb3b74 (omap: IOMMU: add support to callback during fault handling) broke interrupt line sharing between the OMAP3 ISP and its IOMMU. Because of this, every interrupt generated by the OMAP3 ISP is handled by the IOMMU driver instead of being passed to the OMAP3 ISP driver. Signed-off-by: Laurent Pinchart Acked-by: Hiroshi DOYU Signed-off-by: Tony Lindgren diff --git a/arch/arm/plat-omap/iommu.c b/arch/arm/plat-omap/iommu.c index 8a51fd5..34fc31e 100644 --- a/arch/arm/plat-omap/iommu.c +++ b/arch/arm/plat-omap/iommu.c @@ -793,6 +793,8 @@ static irqreturn_t iommu_fault_handler(int irq, void *data) clk_enable(obj->clk); errs = iommu_report_fault(obj, &da); clk_disable(obj->clk); + if (errs == 0) + return IRQ_HANDLED; /* Fault callback or TLB/PTE Dynamic loading */ if (obj->isr && !obj->isr(obj, da, errs, obj->isr_priv)) -- cgit v0.10.2 From 2a7bccccdb9604a717c2128a931f022267d35629 Mon Sep 17 00:00:00 2001 From: Andy Ross Date: Mon, 9 May 2011 16:11:16 -0700 Subject: Bluetooth: Device ids for ath3k on Pegatron Lucid tablets New ath3k device IDs used on the Pegatron Lucid (ExoPC and WeTab) units. Signed-off-by: Andy Ross Signed-off-by: Gustavo F. Padovan diff --git a/drivers/bluetooth/ath3k.c b/drivers/bluetooth/ath3k.c index 695d441..6bacef3 100644 --- a/drivers/bluetooth/ath3k.c +++ b/drivers/bluetooth/ath3k.c @@ -62,6 +62,7 @@ static struct usb_device_id ath3k_table[] = { /* Atheros AR3011 with sflash firmware*/ { USB_DEVICE(0x0CF3, 0x3002) }, + { USB_DEVICE(0x13d3, 0x3304) }, /* Atheros AR9285 Malbec with sflash firmware */ { USB_DEVICE(0x03F0, 0x311D) }, diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c index 762a510..c2de895 100644 --- a/drivers/bluetooth/btusb.c +++ b/drivers/bluetooth/btusb.c @@ -104,6 +104,7 @@ static struct usb_device_id blacklist_table[] = { /* Atheros 3011 with sflash firmware */ { USB_DEVICE(0x0cf3, 0x3002), .driver_info = BTUSB_IGNORE }, + { USB_DEVICE(0x13d3, 0x3304), .driver_info = BTUSB_IGNORE }, /* Atheros AR9285 Malbec with sflash firmware */ { USB_DEVICE(0x03f0, 0x311d), .driver_info = BTUSB_IGNORE }, -- cgit v0.10.2 From b3b1b061583ba4909b59a2f736825d86495fe956 Mon Sep 17 00:00:00 2001 From: Waldemar Rymarkiewicz Date: Fri, 6 May 2011 09:42:31 +0200 Subject: Bluetooth: Double check sec req for pre 2.1 device In case of pre v2.1 devices authentication request will return success immediately if the link key already exists without any authentication process. That means, it's not possible to re-authenticate the link if you already have combination key and for instance want to re-authenticate to get the high security (use 16 digit pin). Therefore, it's necessary to check security requirements on auth complete event to prevent not enough secure connection. Signed-off-by: Waldemar Rymarkiewicz Signed-off-by: Gustavo F. Padovan diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index 14cc324..6c994c0 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -422,6 +422,7 @@ void hci_conn_check_pending(struct hci_dev *hdev); struct hci_conn *hci_connect(struct hci_dev *hdev, int type, bdaddr_t *dst, __u8 sec_level, __u8 auth_type); int hci_conn_check_link_mode(struct hci_conn *conn); +int hci_conn_check_secure(struct hci_conn *conn, __u8 sec_level); int hci_conn_security(struct hci_conn *conn, __u8 sec_level, __u8 auth_type); int hci_conn_change_link_key(struct hci_conn *conn); int hci_conn_switch_role(struct hci_conn *conn, __u8 role); diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c index 7f5ad8a..3163330 100644 --- a/net/bluetooth/hci_conn.c +++ b/net/bluetooth/hci_conn.c @@ -623,6 +623,23 @@ encrypt: } EXPORT_SYMBOL(hci_conn_security); +/* Check secure link requirement */ +int hci_conn_check_secure(struct hci_conn *conn, __u8 sec_level) +{ + BT_DBG("conn %p", conn); + + if (sec_level != BT_SECURITY_HIGH) + return 1; /* Accept if non-secure is required */ + + if (conn->key_type == HCI_LK_AUTH_COMBINATION || + (conn->key_type == HCI_LK_COMBINATION && + conn->pin_length == 16)) + return 1; + + return 0; /* Reject not secure link */ +} +EXPORT_SYMBOL(hci_conn_check_secure); + /* Change link key */ int hci_conn_change_link_key(struct hci_conn *conn) { diff --git a/net/bluetooth/rfcomm/core.c b/net/bluetooth/rfcomm/core.c index 121a5c1..5759bb7 100644 --- a/net/bluetooth/rfcomm/core.c +++ b/net/bluetooth/rfcomm/core.c @@ -2096,7 +2096,7 @@ static void rfcomm_security_cfm(struct hci_conn *conn, u8 status, u8 encrypt) if (!test_and_clear_bit(RFCOMM_AUTH_PENDING, &d->flags)) continue; - if (!status) + if (!status && hci_conn_check_secure(conn, d->sec_level)) set_bit(RFCOMM_AUTH_ACCEPT, &d->flags); else set_bit(RFCOMM_AUTH_REJECT, &d->flags); -- cgit v0.10.2 From a8a4ae3a899a6c0b4771cc57884800d8b76a6996 Mon Sep 17 00:00:00 2001 From: Andy Adamson Date: Tue, 3 May 2011 13:43:03 -0400 Subject: NFSv41: Resend on NFS4ERR_RETRY_UNCACHED_REP Free the slot and resend the RPC with new session . For nfs4_async_handle_error, return -EAGAIN and set the task->tk_status to 0 to restart the async rpc in the rpc_restart_call_prepare state which resets the slot. For nfs4_handle_exception, retrying a call that uses nfs4_call_sync will reset the slot via nfs41_call_sync_prepare. For open/close/lock/locku/delegreturn/layoutcommit/unlink/rename/write cachethis is true, so these operations will not trigger an NFS4ERR_RETRY_UNCACHED_REP. Signed-off-by: Andy Adamson Signed-off-by: Trond Myklebust diff --git a/fs/nfs/nfs4filelayout.c b/fs/nfs/nfs4filelayout.c index 6f8192f..7841ea6 100644 --- a/fs/nfs/nfs4filelayout.c +++ b/fs/nfs/nfs4filelayout.c @@ -117,6 +117,8 @@ static int filelayout_async_handle_error(struct rpc_task *task, case -EKEYEXPIRED: rpc_delay(task, FILELAYOUT_POLL_RETRY_MAX); break; + case -NFS4ERR_RETRY_UNCACHED_REP: + break; default: dprintk("%s DS error. Retry through MDS %d\n", __func__, task->tk_status); diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index 69c0f3c..cf1b339 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c @@ -300,6 +300,7 @@ static int nfs4_handle_exception(struct nfs_server *server, int errorcode, struc ret = nfs4_delay(server->client, &exception->timeout); if (ret != 0) break; + case -NFS4ERR_RETRY_UNCACHED_REP: case -NFS4ERR_OLD_STATEID: exception->retry = 1; break; @@ -3695,6 +3696,7 @@ nfs4_async_handle_error(struct rpc_task *task, const struct nfs_server *server, rpc_delay(task, NFS4_POLL_RETRY_MAX); task->tk_status = 0; return -EAGAIN; + case -NFS4ERR_RETRY_UNCACHED_REP: case -NFS4ERR_OLD_STATEID: task->tk_status = 0; return -EAGAIN; @@ -4844,6 +4846,8 @@ static void nfs4_get_lease_time_done(struct rpc_task *task, void *calldata) dprintk("%s Retry: tk_status %d\n", __func__, task->tk_status); rpc_delay(task, NFS4_POLL_RETRY_MIN); task->tk_status = 0; + /* fall through */ + case -NFS4ERR_RETRY_UNCACHED_REP: nfs_restart_rpc(task, data->clp); return; } @@ -5479,6 +5483,8 @@ static int nfs41_reclaim_complete_handle_errors(struct rpc_task *task, struct nf break; case -NFS4ERR_DELAY: rpc_delay(task, NFS4_POLL_RETRY_MAX); + /* fall through */ + case -NFS4ERR_RETRY_UNCACHED_REP: return -EAGAIN; default: nfs4_schedule_lease_recovery(clp); -- cgit v0.10.2 From 2887fe45522843149ccf72e01f43813be4fb36c5 Mon Sep 17 00:00:00 2001 From: Andy Adamson Date: Wed, 11 May 2011 01:19:58 -0400 Subject: NFSv4.1: remove pnfs_layout_hdr from pnfs_destroy_all_layouts tmp_list Prevents an infinite loop as list was never emptied. Signed-off-by: Andy Adamson Signed-off-by: Trond Myklebust diff --git a/fs/nfs/pnfs.c b/fs/nfs/pnfs.c index ff681ab..65455f5 100644 --- a/fs/nfs/pnfs.c +++ b/fs/nfs/pnfs.c @@ -383,6 +383,7 @@ pnfs_destroy_all_layouts(struct nfs_client *clp) plh_layouts); dprintk("%s freeing layout for inode %lu\n", __func__, lo->plh_inode->i_ino); + list_del_init(&lo->plh_layouts); pnfs_destroy_layout(NFS_I(lo->plh_inode)); } } -- cgit v0.10.2 From b130e5cec958bae3867cf6ab09a9b24ba8fada01 Mon Sep 17 00:00:00 2001 From: Javier Cardona Date: Tue, 3 May 2011 16:57:07 -0700 Subject: nl80211: Introduce NL80211_MESH_SETUP_USERSPACE_AMPE Introduce a new configuration option to support AMPE from userspace. Prior to this series we only supported authentication in userspace: an authentication daemon would authenticate peer candidates in userspace and hand them over to the kernel. From that point the mesh stack would take over and establish a peer link (Mesh Peering Management). These patches introduce support for Authenticated Mesh Peering Exchange in userspace. The userspace daemon implements the AMPE protocol and on successfull completion create mesh peers and install encryption keys. Signed-off-by: Javier Cardona Signed-off-by: John W. Linville diff --git a/include/linux/nl80211.h b/include/linux/nl80211.h index a75dea9..c53b916 100644 --- a/include/linux/nl80211.h +++ b/include/linux/nl80211.h @@ -1769,6 +1769,15 @@ enum nl80211_meshconf_params { * @NL80211_MESH_SETUP_USERSPACE_AUTH: Enable this option if an authentication * daemon will be authenticating mesh candidates. * + * @NL80211_MESH_SETUP_USERSPACE_AMPE: Enable this option if an authentication + * daemon will be securing peer link frames. AMPE is a secured version of Mesh + * Peering Management (MPM) and is implemented with the assistance of a + * userspace daemon. When this flag is set, the kernel will send peer + * management frames to a userspace daemon that will implement AMPE + * functionality (security capabilities selection, key confirmation, and key + * management). When the flag is unset (default), the kernel can autonomously + * complete (unsecured) mesh peering without the need of a userspace daemon. + * * @NL80211_MESH_SETUP_ATTR_MAX: highest possible mesh setup attribute number * @__NL80211_MESH_SETUP_ATTR_AFTER_LAST: Internal use */ @@ -1778,6 +1787,7 @@ enum nl80211_mesh_setup_params { NL80211_MESH_SETUP_ENABLE_VENDOR_METRIC, NL80211_MESH_SETUP_IE, NL80211_MESH_SETUP_USERSPACE_AUTH, + NL80211_MESH_SETUP_USERSPACE_AMPE, /* keep last */ __NL80211_MESH_SETUP_ATTR_AFTER_LAST, diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index 0920daf..10c17d6 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -695,7 +695,8 @@ struct mesh_config { * @path_metric: which metric to use * @ie: vendor information elements (optional) * @ie_len: length of vendor information elements - * @is_secure: or not + * @is_authenticated: this mesh requires authentication + * @is_secure: this mesh uses security * * These parameters are fixed when the mesh is created. */ @@ -706,6 +707,7 @@ struct mesh_setup { u8 path_metric; const u8 *ie; u8 ie_len; + bool is_authenticated; bool is_secure; }; diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index 1ebc133..18c2555 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -1064,7 +1064,11 @@ static int copy_mesh_setup(struct ieee80211_if_mesh *ifmsh, memcpy(ifmsh->mesh_id, setup->mesh_id, ifmsh->mesh_id_len); ifmsh->mesh_pp_id = setup->path_sel_proto; ifmsh->mesh_pm_id = setup->path_metric; - ifmsh->is_secure = setup->is_secure; + ifmsh->security = IEEE80211_MESH_SEC_NONE; + if (setup->is_authenticated) + ifmsh->security |= IEEE80211_MESH_SEC_AUTHED; + if (setup->is_secure) + ifmsh->security |= IEEE80211_MESH_SEC_SECURED; return 0; } diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index e89bc27..7f4d0dc 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -490,7 +490,11 @@ struct ieee80211_if_mesh { bool accepting_plinks; const u8 *ie; u8 ie_len; - bool is_secure; + enum { + IEEE80211_MESH_SEC_NONE = 0x0, + IEEE80211_MESH_SEC_AUTHED = 0x1, + IEEE80211_MESH_SEC_SECURED = 0x2, + } security; }; #ifdef CONFIG_MAC80211_MESH diff --git a/net/mac80211/mesh.c b/net/mac80211/mesh.c index c1299e2..2a59eb3 100644 --- a/net/mac80211/mesh.c +++ b/net/mac80211/mesh.c @@ -574,7 +574,7 @@ static void ieee80211_mesh_rx_bcn_presp(struct ieee80211_sub_if_data *sdata, &elems); /* ignore beacons from secure mesh peers if our security is off */ - if (elems.rsn_len && !sdata->u.mesh.is_secure) + if (elems.rsn_len && sdata->u.mesh.security == IEEE80211_MESH_SEC_NONE) return; if (elems.ds_params && elems.ds_params_len == 1) diff --git a/net/mac80211/mesh_plink.c b/net/mac80211/mesh_plink.c index 84e5b05..87abf8d 100644 --- a/net/mac80211/mesh_plink.c +++ b/net/mac80211/mesh_plink.c @@ -251,7 +251,7 @@ void mesh_neighbour_update(u8 *hw_addr, u32 rates, rcu_read_unlock(); /* Userspace handles peer allocation when security is enabled * */ - if (sdata->u.mesh.is_secure) + if (sdata->u.mesh.security & IEEE80211_MESH_SEC_AUTHED) cfg80211_notify_new_peer_candidate(sdata->dev, hw_addr, elems->ie_start, elems->total_len, GFP_KERNEL); @@ -460,7 +460,8 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m mpl_dbg("Mesh plink: missing necessary peer link ie\n"); return; } - if (elems.rsn_len && !sdata->u.mesh.is_secure) { + if (elems.rsn_len && + sdata->u.mesh.security == IEEE80211_MESH_SEC_NONE) { mpl_dbg("Mesh plink: can't establish link with secure peer\n"); return; } diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 0a199a1..64efc2d 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -2871,6 +2871,7 @@ static const struct nla_policy [NL80211_MESH_SETUP_USERSPACE_AUTH] = { .type = NLA_FLAG }, [NL80211_MESH_SETUP_IE] = { .type = NLA_BINARY, .len = IEEE80211_MAX_DATA_LEN }, + [NL80211_MESH_SETUP_USERSPACE_AMPE] = { .type = NLA_FLAG }, }; static int nl80211_parse_mesh_config(struct genl_info *info, @@ -2980,7 +2981,8 @@ static int nl80211_parse_mesh_setup(struct genl_info *info, setup->ie = nla_data(ieattr); setup->ie_len = nla_len(ieattr); } - setup->is_secure = nla_get_flag(tb[NL80211_MESH_SETUP_USERSPACE_AUTH]); + setup->is_authenticated = nla_get_flag(tb[NL80211_MESH_SETUP_USERSPACE_AUTH]); + setup->is_secure = nla_get_flag(tb[NL80211_MESH_SETUP_USERSPACE_AMPE]); return 0; } -- cgit v0.10.2 From 0778a6a3e56cabdc322755f97ad23ee67efad0f0 Mon Sep 17 00:00:00 2001 From: Javier Cardona Date: Tue, 3 May 2011 16:57:08 -0700 Subject: mac80211: Let userspace send action frames over mesh interfaces Signed-off-by: Javier Cardona Signed-off-by: John W. Linville diff --git a/net/wireless/mlme.c b/net/wireless/mlme.c index 16881fe..493b939 100644 --- a/net/wireless/mlme.c +++ b/net/wireless/mlme.c @@ -963,6 +963,16 @@ int cfg80211_mlme_mgmt_tx(struct cfg80211_registered_device *rdev, if (memcmp(mgmt->bssid, dev->dev_addr, ETH_ALEN)) err = -EINVAL; break; + case NL80211_IFTYPE_MESH_POINT: + if (memcmp(mgmt->sa, mgmt->bssid, ETH_ALEN)) { + err = -EINVAL; + break; + } + /* + * check for mesh DA must be done by driver as + * cfg80211 doesn't track the stations + */ + break; default: err = -EOPNOTSUPP; break; -- cgit v0.10.2 From d3aaec8ab76c2d604c2ba7332e1338674607597b Mon Sep 17 00:00:00 2001 From: Javier Cardona Date: Tue, 3 May 2011 16:57:09 -0700 Subject: mac80211: Drop MESH_PLINK category and use new ANA-approved MESH_ACTION Note: This breaks compatibility with previous mesh protocol instances. Signed-off-by: Javier Cardona Signed-off-by: John W. Linville diff --git a/include/linux/ieee80211.h b/include/linux/ieee80211.h index 79690b7..ee1c96a 100644 --- a/include/linux/ieee80211.h +++ b/include/linux/ieee80211.h @@ -1261,9 +1261,8 @@ enum ieee80211_category { WLAN_CATEGORY_MULTIHOP_ACTION = 14, WLAN_CATEGORY_SELF_PROTECTED = 15, WLAN_CATEGORY_WMM = 17, - /* TODO: remove MESH_PLINK and MESH_PATH_SEL after */ - /* mesh is updated to current 802.11s draft */ - WLAN_CATEGORY_MESH_PLINK = 30, + /* TODO: remove MESH_PATH_SEL after mesh is updated + * to current 802.11s draft */ WLAN_CATEGORY_MESH_PATH_SEL = 32, WLAN_CATEGORY_VENDOR_SPECIFIC_PROTECTED = 126, WLAN_CATEGORY_VENDOR_SPECIFIC = 127, diff --git a/net/mac80211/mesh.c b/net/mac80211/mesh.c index 2a59eb3..75378e8 100644 --- a/net/mac80211/mesh.c +++ b/net/mac80211/mesh.c @@ -600,7 +600,7 @@ static void ieee80211_mesh_rx_mgmt_action(struct ieee80211_sub_if_data *sdata, struct ieee80211_rx_status *rx_status) { switch (mgmt->u.action.category) { - case WLAN_CATEGORY_MESH_PLINK: + case WLAN_CATEGORY_MESH_ACTION: mesh_rx_plink_frame(sdata, mgmt, len, rx_status); break; case WLAN_CATEGORY_MESH_PATH_SEL: diff --git a/net/mac80211/mesh_plink.c b/net/mac80211/mesh_plink.c index 87abf8d..0120e9e 100644 --- a/net/mac80211/mesh_plink.c +++ b/net/mac80211/mesh_plink.c @@ -182,7 +182,7 @@ static int mesh_plink_frame_tx(struct ieee80211_sub_if_data *sdata, memcpy(mgmt->da, da, ETH_ALEN); memcpy(mgmt->sa, sdata->vif.addr, ETH_ALEN); /* BSSID is left zeroed, wildcard value */ - mgmt->u.action.category = WLAN_CATEGORY_MESH_PLINK; + mgmt->u.action.category = WLAN_CATEGORY_MESH_ACTION; mgmt->u.action.u.plink_action.action_code = action; if (action == PLINK_CLOSE) diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index 81241e1..634f3d9 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -495,8 +495,11 @@ ieee80211_rx_mesh_check(struct ieee80211_rx_data *rx) return RX_DROP_MONITOR; if (ieee80211_is_action(hdr->frame_control)) { + u8 category; mgmt = (struct ieee80211_mgmt *)hdr; - if (mgmt->u.action.category != WLAN_CATEGORY_MESH_PLINK) + category = mgmt->u.action.category; + if (category != WLAN_CATEGORY_MESH_ACTION && + category != WLAN_CATEGORY_SELF_PROTECTED) return RX_DROP_MONITOR; return RX_CONTINUE; } @@ -2205,7 +2208,7 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx) goto handled; } break; - case WLAN_CATEGORY_MESH_PLINK: + case WLAN_CATEGORY_MESH_ACTION: if (!ieee80211_vif_is_mesh(&sdata->vif)) break; goto queue; -- cgit v0.10.2 From 915b5c50f8f45e78ea96d93f1e49edb20c9470bd Mon Sep 17 00:00:00 2001 From: Javier Cardona Date: Tue, 3 May 2011 16:57:10 -0700 Subject: open80211s: Stop using zero for address 3 in mesh plink mgmt frames Previous versions of 11s draft used the all zeroes address. Current draft uses the same address as address 2. Also, use the ANA-approved action category code for peer establishment frames. Note: This breaks compatibility with previous mesh protocol instances. Signed-off-by: Javier Cardona Signed-off-by: John W. Linville diff --git a/net/mac80211/mesh_plink.c b/net/mac80211/mesh_plink.c index 0120e9e..2c37bee 100644 --- a/net/mac80211/mesh_plink.c +++ b/net/mac80211/mesh_plink.c @@ -43,7 +43,7 @@ #define dot11MeshMaxPeerLinks(s) (s->u.mesh.mshcfg.dot11MeshMaxPeerLinks) enum plink_frame_type { - PLINK_OPEN = 0, + PLINK_OPEN = 1, PLINK_CONFIRM, PLINK_CLOSE }; @@ -181,7 +181,7 @@ static int mesh_plink_frame_tx(struct ieee80211_sub_if_data *sdata, IEEE80211_STYPE_ACTION); memcpy(mgmt->da, da, ETH_ALEN); memcpy(mgmt->sa, sdata->vif.addr, ETH_ALEN); - /* BSSID is left zeroed, wildcard value */ + memcpy(mgmt->bssid, sdata->vif.addr, ETH_ALEN); mgmt->u.action.category = WLAN_CATEGORY_MESH_ACTION; mgmt->u.action.u.plink_action.action_code = action; -- cgit v0.10.2 From 0a35d36d6f019bde6c98812456798275b02e5aee Mon Sep 17 00:00:00 2001 From: Javier Cardona Date: Wed, 4 May 2011 10:24:56 -0700 Subject: cfg80211: Use capability info to detect mesh beacons. Mesh beacons no longer use all-zeroes BSSID. Beacon frames for MBSS, infrastructure BSS, or IBSS are differentiated by the Capability Information field in the Beacon frame. A mesh STA sets the ESS and IBSS subfields to 0 in transmitted Beacon or Probe Response management frames. Signed-off-by: Javier Cardona Signed-off-by: John W. Linville diff --git a/include/linux/ieee80211.h b/include/linux/ieee80211.h index ee1c96a..d527fb7 100644 --- a/include/linux/ieee80211.h +++ b/include/linux/ieee80211.h @@ -1002,6 +1002,11 @@ struct ieee80211_ht_info { #define WLAN_CAPABILITY_ESS (1<<0) #define WLAN_CAPABILITY_IBSS (1<<1) + +/* A mesh STA sets the ESS and IBSS capability bits to zero */ +#define WLAN_CAPABILITY_IS_MBSS(cap) \ + (!((cap) & (WLAN_CAPABILITY_ESS | WLAN_CAPABILITY_IBSS))) + #define WLAN_CAPABILITY_CF_POLLABLE (1<<2) #define WLAN_CAPABILITY_CF_POLL_REQUEST (1<<3) #define WLAN_CAPABILITY_PRIVACY (1<<4) diff --git a/net/wireless/scan.c b/net/wireless/scan.c index fbf6f33..62e542a 100644 --- a/net/wireless/scan.c +++ b/net/wireless/scan.c @@ -210,7 +210,7 @@ static bool is_mesh(struct cfg80211_bss *a, { const u8 *ie; - if (!is_zero_ether_addr(a->bssid)) + if (!WLAN_CAPABILITY_IS_MBSS(a->capability)) return false; ie = cfg80211_find_ie(WLAN_EID_MESH_ID, @@ -248,11 +248,7 @@ static int cmp_bss(struct cfg80211_bss *a, if (a->channel != b->channel) return b->channel->center_freq - a->channel->center_freq; - r = memcmp(a->bssid, b->bssid, ETH_ALEN); - if (r) - return r; - - if (is_zero_ether_addr(a->bssid)) { + if (WLAN_CAPABILITY_IS_MBSS(a->capability | b->capability)) { r = cmp_ies(WLAN_EID_MESH_ID, a->information_elements, a->len_information_elements, @@ -267,6 +263,10 @@ static int cmp_bss(struct cfg80211_bss *a, b->len_information_elements); } + r = memcmp(a->bssid, b->bssid, ETH_ALEN); + if (r) + return r; + return cmp_ies(WLAN_EID_SSID, a->information_elements, a->len_information_elements, @@ -407,7 +407,7 @@ cfg80211_bss_update(struct cfg80211_registered_device *dev, res->ts = jiffies; - if (is_zero_ether_addr(res->pub.bssid)) { + if (WLAN_CAPABILITY_IS_MBSS(res->pub.capability)) { /* must be mesh, verify */ meshid = cfg80211_find_ie(WLAN_EID_MESH_ID, res->pub.information_elements, -- cgit v0.10.2 From 9c3990aaec0ad9f686ef6480f6861f2df89b2a7a Mon Sep 17 00:00:00 2001 From: Javier Cardona Date: Tue, 3 May 2011 16:57:11 -0700 Subject: nl80211: Let userspace drive the peer link management states. Signed-off-by: Javier Cardona Signed-off-by: John W. Linville diff --git a/include/linux/nl80211.h b/include/linux/nl80211.h index c53b916..de96783 100644 --- a/include/linux/nl80211.h +++ b/include/linux/nl80211.h @@ -913,6 +913,9 @@ enum nl80211_commands { * @NL80211_ATTR_SUPPORT_MESH_AUTH: Currently, this means the underlying driver * allows auth frames in a mesh to be passed to userspace for processing via * the @NL80211_MESH_SETUP_USERSPACE_AUTH flag. + * @NL80211_ATTR_STA_PLINK_STATE: The state of a mesh peer link. Used when + * userspace is driving the peer link management state machine. + * @NL80211_MESH_SETUP_USERSPACE_AMPE must be enabled. * * @NL80211_ATTR_WOWLAN_SUPPORTED: indicates, as part of the wiphy capabilities, * the supported WoWLAN triggers @@ -1109,6 +1112,7 @@ enum nl80211_attrs { NL80211_ATTR_WIPHY_ANTENNA_AVAIL_RX, NL80211_ATTR_SUPPORT_MESH_AUTH, + NL80211_ATTR_STA_PLINK_STATE, NL80211_ATTR_WOWLAN_TRIGGERS, NL80211_ATTR_WOWLAN_TRIGGERS_SUPPORTED, diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index 10c17d6..4b0d035 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -372,6 +372,33 @@ enum plink_actions { }; /** + * enum plink_states - state of a mesh peer link finite state machine + * + * @PLINK_LISTEN: initial state, considered the implicit state of non + * existant mesh peer links + * @PLINK_OPN_SNT: mesh plink open frame has been sent to this mesh + * peer @PLINK_OPN_RCVD: mesh plink open frame has been received from + * this mesh peer + * @PLINK_CNF_RCVD: mesh plink confirm frame has been received from + * this mesh peer + * @PLINK_ESTAB: mesh peer link is established + * @PLINK_HOLDING: mesh peer link is being closed or cancelled + * @PLINK_BLOCKED: all frames transmitted from this mesh plink are + * discarded + * @PLINK_INVALID: reserved + */ +enum plink_state { + PLINK_LISTEN, + PLINK_OPN_SNT, + PLINK_OPN_RCVD, + PLINK_CNF_RCVD, + PLINK_ESTAB, + PLINK_HOLDING, + PLINK_BLOCKED, + PLINK_INVALID, +}; + +/** * struct station_parameters - station parameters * * Used to change and create a new station. @@ -387,6 +414,7 @@ enum plink_actions { * @listen_interval: listen interval or -1 for no change * @aid: AID or zero for no change * @plink_action: plink action to take + * @plink_state: set the peer link state for a station * @ht_capa: HT capabilities of station */ struct station_parameters { @@ -397,6 +425,7 @@ struct station_parameters { u16 aid; u8 supported_rates_len; u8 plink_action; + u8 plink_state; struct ieee80211_ht_cap *ht_capa; }; diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index 18c2555..51f7757 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -734,15 +734,27 @@ static void sta_apply_parameters(struct ieee80211_local *local, params->ht_capa, &sta->sta.ht_cap); - if (ieee80211_vif_is_mesh(&sdata->vif) && params->plink_action) { - switch (params->plink_action) { - case PLINK_ACTION_OPEN: - mesh_plink_open(sta); - break; - case PLINK_ACTION_BLOCK: - mesh_plink_block(sta); - break; - } + if (ieee80211_vif_is_mesh(&sdata->vif)) { + if (sdata->u.mesh.security & IEEE80211_MESH_SEC_SECURED) + switch (params->plink_state) { + case PLINK_LISTEN: + case PLINK_ESTAB: + case PLINK_BLOCKED: + sta->plink_state = params->plink_state; + break; + default: + /* nothing */ + break; + } + else + switch (params->plink_action) { + case PLINK_ACTION_OPEN: + mesh_plink_open(sta); + break; + case PLINK_ACTION_BLOCK: + mesh_plink_block(sta); + break; + } } } diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h index af1a7f8..f00b4dc 100644 --- a/net/mac80211/sta_info.h +++ b/net/mac80211/sta_info.h @@ -174,29 +174,6 @@ struct sta_ampdu_mlme { /** - * enum plink_state - state of a mesh peer link finite state machine - * - * @PLINK_LISTEN: initial state, considered the implicit state of non existant - * mesh peer links - * @PLINK_OPN_SNT: mesh plink open frame has been sent to this mesh peer - * @PLINK_OPN_RCVD: mesh plink open frame has been received from this mesh peer - * @PLINK_CNF_RCVD: mesh plink confirm frame has been received from this mesh - * peer - * @PLINK_ESTAB: mesh peer link is established - * @PLINK_HOLDING: mesh peer link is being closed or cancelled - * @PLINK_BLOCKED: all frames transmitted from this mesh plink are discarded - */ -enum plink_state { - PLINK_LISTEN, - PLINK_OPN_SNT, - PLINK_OPN_RCVD, - PLINK_CNF_RCVD, - PLINK_ESTAB, - PLINK_HOLDING, - PLINK_BLOCKED -}; - -/** * struct sta_info - STA information * * This structure collects information about a station that diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 64efc2d..f698c1d 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -174,6 +174,7 @@ static const struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] = { [NL80211_ATTR_OFFCHANNEL_TX_OK] = { .type = NLA_FLAG }, [NL80211_ATTR_KEY_DEFAULT_TYPES] = { .type = NLA_NESTED }, [NL80211_ATTR_WOWLAN_TRIGGERS] = { .type = NLA_NESTED }, + [NL80211_ATTR_STA_PLINK_STATE] = { .type = NLA_U8 }, }; /* policy for the key attributes */ @@ -2247,6 +2248,7 @@ static int nl80211_set_station(struct sk_buff *skb, struct genl_info *info) memset(¶ms, 0, sizeof(params)); params.listen_interval = -1; + params.plink_state = PLINK_INVALID; if (info->attrs[NL80211_ATTR_STA_AID]) return -EINVAL; @@ -2278,6 +2280,10 @@ static int nl80211_set_station(struct sk_buff *skb, struct genl_info *info) params.plink_action = nla_get_u8(info->attrs[NL80211_ATTR_STA_PLINK_ACTION]); + if (info->attrs[NL80211_ATTR_STA_PLINK_STATE]) + params.plink_state = + nla_get_u8(info->attrs[NL80211_ATTR_STA_PLINK_STATE]); + err = get_vlan(info, rdev, ¶ms.vlan); if (err) goto out; -- cgit v0.10.2 From ff973af74aa6932ca4758266bccec68e8135ddf7 Mon Sep 17 00:00:00 2001 From: Thomas Pedersen Date: Tue, 3 May 2011 16:57:12 -0700 Subject: nl80211: allow installing keys for a meshif Signed-off-by: Thomas Pedersen Signed-off-by: Javier Cardona Signed-off-by: John W. Linville diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index 51f7757..c416cce 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -136,7 +136,10 @@ static int ieee80211_add_key(struct wiphy *wiphy, struct net_device *dev, mutex_lock(&sdata->local->sta_mtx); if (mac_addr) { - sta = sta_info_get_bss(sdata, mac_addr); + if (ieee80211_vif_is_mesh(&sdata->vif)) + sta = sta_info_get(sdata, mac_addr); + else + sta = sta_info_get_bss(sdata, mac_addr); if (!sta) { ieee80211_key_free(sdata->local, key); err = -ENOENT; diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index f698c1d..b454f89 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -545,6 +545,7 @@ static int nl80211_key_allowed(struct wireless_dev *wdev) case NL80211_IFTYPE_AP: case NL80211_IFTYPE_AP_VLAN: case NL80211_IFTYPE_P2P_GO: + case NL80211_IFTYPE_MESH_POINT: break; case NL80211_IFTYPE_ADHOC: if (!wdev->current_bss) -- cgit v0.10.2 From 8429828ec96b66b6861e9fabebec007e9e132370 Mon Sep 17 00:00:00 2001 From: Thomas Pedersen Date: Tue, 3 May 2011 16:57:13 -0700 Subject: nl80211: allow setting MFP flag for a meshif Signed-off-by: Thomas Pedersen Signed-off-by: Javier Cardona Signed-off-by: John W. Linville diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index b454f89..fc3c95d 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -2328,6 +2328,7 @@ static int nl80211_set_station(struct sk_buff *skb, struct genl_info *info) err = -EINVAL; if (params.sta_flags_mask & ~(BIT(NL80211_STA_FLAG_AUTHENTICATED) | + BIT(NL80211_STA_FLAG_MFP) | BIT(NL80211_STA_FLAG_AUTHORIZED))) err = -EINVAL; break; -- cgit v0.10.2 From 8f9cb77d6d213c153b0571f494df0c24456aaf47 Mon Sep 17 00:00:00 2001 From: Thomas Pedersen Date: Tue, 3 May 2011 16:57:14 -0700 Subject: mac80211: Self-protected management frames are not robust They may contain encrypted information elements (as AMPE frames do) but they are not encrypted. Signed-off-by: Thomas Pedersen Signed-off-by: Javier Cardona Signed-off-by: John W. Linville diff --git a/include/linux/ieee80211.h b/include/linux/ieee80211.h index d527fb7..b2eee58 100644 --- a/include/linux/ieee80211.h +++ b/include/linux/ieee80211.h @@ -1520,6 +1520,7 @@ static inline bool ieee80211_is_robust_mgmt_frame(struct ieee80211_hdr *hdr) category = ((u8 *) hdr) + 24; return *category != WLAN_CATEGORY_PUBLIC && *category != WLAN_CATEGORY_HT && + *category != WLAN_CATEGORY_SELF_PROTECTED && *category != WLAN_CATEGORY_VENDOR_SPECIFIC; } -- cgit v0.10.2 From 9ca99eeca0cfe839c481f3350988e9ed94188567 Mon Sep 17 00:00:00 2001 From: Javier Cardona Date: Tue, 3 May 2011 16:57:15 -0700 Subject: mac80211: Check size of a new mesh path table for changes since allocation. Not sure if I'm chasing a ghost here, seems like the mesh_path->size_order needs to be inside an RCU-read section to prevent that value from changing between table allocation and copying. We have observed crashes that might be caused by this. Signed-off-by: Javier Cardona Signed-off-by: John W. Linville diff --git a/net/mac80211/mesh_pathtbl.c b/net/mac80211/mesh_pathtbl.c index 7776ae5..c1a2bf2 100644 --- a/net/mac80211/mesh_pathtbl.c +++ b/net/mac80211/mesh_pathtbl.c @@ -76,7 +76,6 @@ static int mesh_table_grow(struct mesh_table *oldtbl, < oldtbl->mean_chain_len * (oldtbl->hash_mask + 1)) return -EAGAIN; - newtbl->free_node = oldtbl->free_node; newtbl->mean_chain_len = oldtbl->mean_chain_len; newtbl->copy_node = oldtbl->copy_node; @@ -329,7 +328,8 @@ void mesh_mpath_table_grow(void) { struct mesh_table *oldtbl, *newtbl; - newtbl = mesh_table_alloc(mesh_paths->size_order + 1); + rcu_read_lock(); + newtbl = mesh_table_alloc(rcu_dereference(mesh_paths)->size_order + 1); if (!newtbl) return; write_lock(&pathtbl_resize_lock); @@ -339,6 +339,7 @@ void mesh_mpath_table_grow(void) write_unlock(&pathtbl_resize_lock); return; } + rcu_read_unlock(); rcu_assign_pointer(mesh_paths, newtbl); write_unlock(&pathtbl_resize_lock); @@ -350,7 +351,8 @@ void mesh_mpp_table_grow(void) { struct mesh_table *oldtbl, *newtbl; - newtbl = mesh_table_alloc(mpp_paths->size_order + 1); + rcu_read_lock(); + newtbl = mesh_table_alloc(rcu_dereference(mpp_paths)->size_order + 1); if (!newtbl) return; write_lock(&pathtbl_resize_lock); @@ -360,6 +362,7 @@ void mesh_mpp_table_grow(void) write_unlock(&pathtbl_resize_lock); return; } + rcu_read_unlock(); rcu_assign_pointer(mpp_paths, newtbl); write_unlock(&pathtbl_resize_lock); -- cgit v0.10.2 From 9b84b80891e5e25ae21c855bb135b05274125a29 Mon Sep 17 00:00:00 2001 From: Javier Cardona Date: Tue, 3 May 2011 16:57:16 -0700 Subject: mac80211: Fix locking bug on mesh path table access The mesh and mpp path tables are accessed from softirq and workqueue context so non-irq locking cannot be used. Or at least that's what PROVE_RCU seems to tell us here: [ 431.240946] ================================= [ 431.241061] [ INFO: inconsistent lock state ] [ 431.241061] 2.6.39-rc3-wl+ #354 [ 431.241061] --------------------------------- [ 431.241061] inconsistent {IN-SOFTIRQ-W} -> {SOFTIRQ-ON-W} usage. [ 431.241061] kworker/u:1/1423 [HC0[0]:SC0[0]:HE1:SE1] takes: [ 431.241061] (&(&newtbl->hashwlock[i])->rlock){+.?...}, at: [] mesh_path_add+0x167/0x257 Signed-off-by: Javier Cardona Signed-off-by: John W. Linville diff --git a/net/mac80211/mesh_pathtbl.c b/net/mac80211/mesh_pathtbl.c index c1a2bf2..c7cb3cc 100644 --- a/net/mac80211/mesh_pathtbl.c +++ b/net/mac80211/mesh_pathtbl.c @@ -55,12 +55,12 @@ void mesh_table_free(struct mesh_table *tbl, bool free_leafs) mesh_hash = tbl->hash_buckets; for (i = 0; i <= tbl->hash_mask; i++) { - spin_lock(&tbl->hashwlock[i]); + spin_lock_bh(&tbl->hashwlock[i]); hlist_for_each_safe(p, q, &mesh_hash[i]) { tbl->free_node(p, free_leafs); atomic_dec(&tbl->entries); } - spin_unlock(&tbl->hashwlock[i]); + spin_unlock_bh(&tbl->hashwlock[i]); } __mesh_table_free(tbl); } @@ -274,7 +274,7 @@ int mesh_path_add(u8 *dst, struct ieee80211_sub_if_data *sdata) if (!new_node) goto err_node_alloc; - read_lock(&pathtbl_resize_lock); + read_lock_bh(&pathtbl_resize_lock); memcpy(new_mpath->dst, dst, ETH_ALEN); new_mpath->sdata = sdata; new_mpath->flags = 0; @@ -289,7 +289,7 @@ int mesh_path_add(u8 *dst, struct ieee80211_sub_if_data *sdata) hash_idx = mesh_table_hash(dst, sdata, mesh_paths); bucket = &mesh_paths->hash_buckets[hash_idx]; - spin_lock(&mesh_paths->hashwlock[hash_idx]); + spin_lock_bh(&mesh_paths->hashwlock[hash_idx]); err = -EEXIST; hlist_for_each_entry(node, n, bucket, list) { @@ -305,8 +305,8 @@ int mesh_path_add(u8 *dst, struct ieee80211_sub_if_data *sdata) mesh_paths_generation++; - spin_unlock(&mesh_paths->hashwlock[hash_idx]); - read_unlock(&pathtbl_resize_lock); + spin_unlock_bh(&mesh_paths->hashwlock[hash_idx]); + read_unlock_bh(&pathtbl_resize_lock); if (grow) { set_bit(MESH_WORK_GROW_MPATH_TABLE, &ifmsh->wrkq_flags); ieee80211_queue_work(&local->hw, &sdata->work); @@ -314,8 +314,8 @@ int mesh_path_add(u8 *dst, struct ieee80211_sub_if_data *sdata) return 0; err_exists: - spin_unlock(&mesh_paths->hashwlock[hash_idx]); - read_unlock(&pathtbl_resize_lock); + spin_unlock_bh(&mesh_paths->hashwlock[hash_idx]); + read_unlock_bh(&pathtbl_resize_lock); kfree(new_node); err_node_alloc: kfree(new_mpath); @@ -332,16 +332,17 @@ void mesh_mpath_table_grow(void) newtbl = mesh_table_alloc(rcu_dereference(mesh_paths)->size_order + 1); if (!newtbl) return; - write_lock(&pathtbl_resize_lock); + write_lock_bh(&pathtbl_resize_lock); oldtbl = mesh_paths; if (mesh_table_grow(mesh_paths, newtbl) < 0) { + rcu_read_unlock(); __mesh_table_free(newtbl); - write_unlock(&pathtbl_resize_lock); + write_unlock_bh(&pathtbl_resize_lock); return; } rcu_read_unlock(); rcu_assign_pointer(mesh_paths, newtbl); - write_unlock(&pathtbl_resize_lock); + write_unlock_bh(&pathtbl_resize_lock); synchronize_rcu(); mesh_table_free(oldtbl, false); @@ -355,16 +356,17 @@ void mesh_mpp_table_grow(void) newtbl = mesh_table_alloc(rcu_dereference(mpp_paths)->size_order + 1); if (!newtbl) return; - write_lock(&pathtbl_resize_lock); + write_lock_bh(&pathtbl_resize_lock); oldtbl = mpp_paths; if (mesh_table_grow(mpp_paths, newtbl) < 0) { + rcu_read_unlock(); __mesh_table_free(newtbl); - write_unlock(&pathtbl_resize_lock); + write_unlock_bh(&pathtbl_resize_lock); return; } rcu_read_unlock(); rcu_assign_pointer(mpp_paths, newtbl); - write_unlock(&pathtbl_resize_lock); + write_unlock_bh(&pathtbl_resize_lock); synchronize_rcu(); mesh_table_free(oldtbl, false); @@ -398,7 +400,7 @@ int mpp_path_add(u8 *dst, u8 *mpp, struct ieee80211_sub_if_data *sdata) if (!new_node) goto err_node_alloc; - read_lock(&pathtbl_resize_lock); + read_lock_bh(&pathtbl_resize_lock); memcpy(new_mpath->dst, dst, ETH_ALEN); memcpy(new_mpath->mpp, mpp, ETH_ALEN); new_mpath->sdata = sdata; @@ -411,7 +413,7 @@ int mpp_path_add(u8 *dst, u8 *mpp, struct ieee80211_sub_if_data *sdata) hash_idx = mesh_table_hash(dst, sdata, mpp_paths); bucket = &mpp_paths->hash_buckets[hash_idx]; - spin_lock(&mpp_paths->hashwlock[hash_idx]); + spin_lock_bh(&mpp_paths->hashwlock[hash_idx]); err = -EEXIST; hlist_for_each_entry(node, n, bucket, list) { @@ -425,8 +427,8 @@ int mpp_path_add(u8 *dst, u8 *mpp, struct ieee80211_sub_if_data *sdata) mpp_paths->mean_chain_len * (mpp_paths->hash_mask + 1)) grow = 1; - spin_unlock(&mpp_paths->hashwlock[hash_idx]); - read_unlock(&pathtbl_resize_lock); + spin_unlock_bh(&mpp_paths->hashwlock[hash_idx]); + read_unlock_bh(&pathtbl_resize_lock); if (grow) { set_bit(MESH_WORK_GROW_MPP_TABLE, &ifmsh->wrkq_flags); ieee80211_queue_work(&local->hw, &sdata->work); @@ -434,8 +436,8 @@ int mpp_path_add(u8 *dst, u8 *mpp, struct ieee80211_sub_if_data *sdata) return 0; err_exists: - spin_unlock(&mpp_paths->hashwlock[hash_idx]); - read_unlock(&pathtbl_resize_lock); + spin_unlock_bh(&mpp_paths->hashwlock[hash_idx]); + read_unlock_bh(&pathtbl_resize_lock); kfree(new_node); err_node_alloc: kfree(new_mpath); @@ -548,11 +550,11 @@ int mesh_path_del(u8 *addr, struct ieee80211_sub_if_data *sdata) int hash_idx; int err = 0; - read_lock(&pathtbl_resize_lock); + read_lock_bh(&pathtbl_resize_lock); hash_idx = mesh_table_hash(addr, sdata, mesh_paths); bucket = &mesh_paths->hash_buckets[hash_idx]; - spin_lock(&mesh_paths->hashwlock[hash_idx]); + spin_lock_bh(&mesh_paths->hashwlock[hash_idx]); hlist_for_each_entry(node, n, bucket, list) { mpath = node->mpath; if (mpath->sdata == sdata && @@ -570,8 +572,8 @@ int mesh_path_del(u8 *addr, struct ieee80211_sub_if_data *sdata) err = -ENXIO; enddel: mesh_paths_generation++; - spin_unlock(&mesh_paths->hashwlock[hash_idx]); - read_unlock(&pathtbl_resize_lock); + spin_unlock_bh(&mesh_paths->hashwlock[hash_idx]); + read_unlock_bh(&pathtbl_resize_lock); return err; } @@ -723,7 +725,7 @@ void mesh_path_expire(struct ieee80211_sub_if_data *sdata) struct hlist_node *p; int i; - read_lock(&pathtbl_resize_lock); + read_lock_bh(&pathtbl_resize_lock); for_each_mesh_entry(mesh_paths, p, node, i) { if (node->mpath->sdata != sdata) continue; @@ -738,7 +740,7 @@ void mesh_path_expire(struct ieee80211_sub_if_data *sdata) } else spin_unlock_bh(&mpath->state_lock); } - read_unlock(&pathtbl_resize_lock); + read_unlock_bh(&pathtbl_resize_lock); } void mesh_pathtbl_unregister(void) -- cgit v0.10.2 From 28104cae63708d1790cd71db8a45af50d5ea5a92 Mon Sep 17 00:00:00 2001 From: Javier Cardona Date: Tue, 3 May 2011 16:57:17 -0700 Subject: mac80211: Move call to mpp_path_lookup inside RCU-read section PROVE_RCU caught that one: [ 431.214070] =================================================== [ 431.215341] [ INFO: suspicious rcu_dereference_check() usage. ] [ 431.215674] --------------------------------------------------- [ 431.216043] net/mac80211/mesh_pathtbl.c:184 invoked rcu_dereference_check() without protection! Signed-off-by: Javier Cardona Signed-off-by: John W. Linville diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index e1a39ed..c9f1211 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -1751,6 +1751,7 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb, ret = NETDEV_TX_OK; goto fail; } + rcu_read_lock(); if (!is_multicast_ether_addr(skb->data)) mppath = mpp_path_lookup(skb->data, sdata); @@ -1765,13 +1766,13 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb, !(mppath && compare_ether_addr(mppath->mpp, skb->data))) { hdrlen = ieee80211_fill_mesh_addresses(&hdr, &fc, skb->data, skb->data + ETH_ALEN); + rcu_read_unlock(); meshhdrlen = ieee80211_new_mesh_header(&mesh_hdr, sdata, NULL, NULL); } else { int is_mesh_mcast = 1; const u8 *mesh_da; - rcu_read_lock(); if (is_multicast_ether_addr(skb->data)) /* DA TA mSA AE:SA */ mesh_da = skb->data; -- cgit v0.10.2 From 1833d81a1229adeab98f275b47624d66462561e5 Mon Sep 17 00:00:00 2001 From: Javier Cardona Date: Tue, 3 May 2011 16:57:18 -0700 Subject: mac80211: allow setting supported rates on mesh peers This is necessary for userspace managed stations. Signed-off-by: Javier Cardona Signed-off-by: John W. Linville diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index fc3c95d..95dd583 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -2324,8 +2324,6 @@ static int nl80211_set_station(struct sk_buff *skb, struct genl_info *info) err = -EINVAL; if (params.listen_interval >= 0) err = -EINVAL; - if (params.supported_rates) - err = -EINVAL; if (params.sta_flags_mask & ~(BIT(NL80211_STA_FLAG_AUTHENTICATED) | BIT(NL80211_STA_FLAG_MFP) | -- cgit v0.10.2 From fd5999cf11c8322568034bbf0d5594be94542a57 Mon Sep 17 00:00:00 2001 From: Javier Cardona Date: Tue, 3 May 2011 16:57:19 -0700 Subject: ath9k: fix beaconing for mesh interfaces Mesh beaconing on ath9k was broken by this commit: commit 4801416c76a3a355076d6d371c00270dfe332e1c Author: Ben Greear Date: Sat Jan 15 19:13:48 2011 +0000 This patch assigns the right opmode when the device is used in mesh mode. Reported-by: Fabrice Deyber fabricedeyber@agilemesh.com Signed-off-by: Javier Cardona Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index c4d32c5..9dd72d8 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -1385,7 +1385,9 @@ static void ath9k_calculate_summary_state(struct ieee80211_hw *hw, ath9k_hw_set_tsfadjust(ah, 0); sc->sc_flags &= ~SC_OP_TSF_RESET; - if (iter_data.nwds + iter_data.nmeshes) + if (iter_data.nmeshes) + ah->opmode = NL80211_IFTYPE_MESH_POINT; + else if (iter_data.nwds) ah->opmode = NL80211_IFTYPE_AP; else if (iter_data.nadhocs) ah->opmode = NL80211_IFTYPE_ADHOC; -- cgit v0.10.2 From 9b76b1e4d383868ba9c2a5fa2c2716bbc2384342 Mon Sep 17 00:00:00 2001 From: Fabrice Deyber Date: Fri, 6 May 2011 15:11:51 -0700 Subject: mac80211: Only process mesh PREPs with equal seq number if metric is better. This fixes routing loops in PREP propagation and is in accordance with Draft 11, Section: 11C.9.8.4. Signed-off-by: Fabrice Deyber Signed-off-by: Javier Cardona Signed-off-by: John W. Linville diff --git a/net/mac80211/mesh_hwmp.c b/net/mac80211/mesh_hwmp.c index e57f2e7..849fecd 100644 --- a/net/mac80211/mesh_hwmp.c +++ b/net/mac80211/mesh_hwmp.c @@ -391,7 +391,6 @@ static u32 hwmp_route_info_get(struct ieee80211_sub_if_data *sdata, (mpath->flags & MESH_PATH_SN_VALID)) { if (SN_GT(mpath->sn, orig_sn) || (mpath->sn == orig_sn && - action == MPATH_PREQ && new_metric >= mpath->metric)) { process = false; fresh_info = false; -- cgit v0.10.2 From d381f221199c58d2bf25a7024e786fc58562487c Mon Sep 17 00:00:00 2001 From: Ben Greear Date: Fri, 6 May 2011 15:24:34 -0700 Subject: ath5k: Fix lockup due to un-init spinlock. This was introduced in 2.6.39-rc1 it seems. Signed-off-by: Ben Greear Tested-by: Sedat Dilek Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath5k/base.c b/drivers/net/wireless/ath/ath5k/base.c index 7583841..aaa0cd7 100644 --- a/drivers/net/wireless/ath/ath5k/base.c +++ b/drivers/net/wireless/ath/ath5k/base.c @@ -2394,7 +2394,7 @@ ath5k_init_softc(struct ath5k_softc *sc, const struct ath_bus_ops *bus_ops) spin_lock_init(&sc->rxbuflock); spin_lock_init(&sc->txbuflock); spin_lock_init(&sc->block); - + spin_lock_init(&sc->irqlock); /* Setup interrupt handler */ ret = request_irq(sc->irq, ath5k_intr, IRQF_SHARED, "ath", sc); -- cgit v0.10.2 From 92ddc111c4bc7216673bce7c49a2d54bedb1593c Mon Sep 17 00:00:00 2001 From: Luciano Coelho Date: Mon, 9 May 2011 14:40:06 +0300 Subject: mac80211: add a couple of trace event classes to reduce duplicated code The functions drv_add_interface() and drv_remove_interface() print out the same values in the traces. Combine the traces of these two functions into one event class to remove some duplicate code. Also add a new class for functions drv_set_frag_threshold() and drv_set_rts_threshold(). Cc: Johannes Berg Signed-off-by: Luciano Coelho Signed-off-by: John W. Linville diff --git a/net/mac80211/driver-trace.h b/net/mac80211/driver-trace.h index 11e1ea5..dd9779d 100644 --- a/net/mac80211/driver-trace.h +++ b/net/mac80211/driver-trace.h @@ -55,6 +55,49 @@ DECLARE_EVENT_CLASS(local_only_evt, TP_printk(LOCAL_PR_FMT, LOCAL_PR_ARG) ); +DECLARE_EVENT_CLASS(local_sdata_addr_evt, + TP_PROTO(struct ieee80211_local *local, + struct ieee80211_sub_if_data *sdata), + TP_ARGS(local, sdata), + + TP_STRUCT__entry( + LOCAL_ENTRY + VIF_ENTRY + __array(char, addr, 6) + ), + + TP_fast_assign( + LOCAL_ASSIGN; + VIF_ASSIGN; + memcpy(__entry->addr, sdata->vif.addr, 6); + ), + + TP_printk( + LOCAL_PR_FMT VIF_PR_FMT " addr:%pM", + LOCAL_PR_ARG, VIF_PR_ARG, __entry->addr + ) +); + +DECLARE_EVENT_CLASS(local_u32_evt, + TP_PROTO(struct ieee80211_local *local, u32 value), + TP_ARGS(local, value), + + TP_STRUCT__entry( + LOCAL_ENTRY + __field(u32, value) + ), + + TP_fast_assign( + LOCAL_ASSIGN; + __entry->value = value; + ), + + TP_printk( + LOCAL_PR_FMT " value:%d", + LOCAL_PR_ARG, __entry->value + ) +); + DEFINE_EVENT(local_only_evt, drv_return_void, TP_PROTO(struct ieee80211_local *local), TP_ARGS(local) @@ -123,28 +166,10 @@ DEFINE_EVENT(local_only_evt, drv_stop, TP_ARGS(local) ); -TRACE_EVENT(drv_add_interface, +DEFINE_EVENT(local_sdata_addr_evt, drv_add_interface, TP_PROTO(struct ieee80211_local *local, struct ieee80211_sub_if_data *sdata), - - TP_ARGS(local, sdata), - - TP_STRUCT__entry( - LOCAL_ENTRY - VIF_ENTRY - __array(char, addr, 6) - ), - - TP_fast_assign( - LOCAL_ASSIGN; - VIF_ASSIGN; - memcpy(__entry->addr, sdata->vif.addr, 6); - ), - - TP_printk( - LOCAL_PR_FMT VIF_PR_FMT " addr:%pM", - LOCAL_PR_ARG, VIF_PR_ARG, __entry->addr - ) + TP_ARGS(local, sdata) ); TRACE_EVENT(drv_change_interface, @@ -175,27 +200,10 @@ TRACE_EVENT(drv_change_interface, ) ); -TRACE_EVENT(drv_remove_interface, - TP_PROTO(struct ieee80211_local *local, struct ieee80211_sub_if_data *sdata), - - TP_ARGS(local, sdata), - - TP_STRUCT__entry( - LOCAL_ENTRY - VIF_ENTRY - __array(char, addr, 6) - ), - - TP_fast_assign( - LOCAL_ASSIGN; - VIF_ASSIGN; - memcpy(__entry->addr, sdata->vif.addr, 6); - ), - - TP_printk( - LOCAL_PR_FMT VIF_PR_FMT " addr:%pM", - LOCAL_PR_ARG, VIF_PR_ARG, __entry->addr - ) +DEFINE_EVENT(local_sdata_addr_evt, drv_remove_interface, + TP_PROTO(struct ieee80211_local *local, + struct ieee80211_sub_if_data *sdata), + TP_ARGS(local, sdata) ); TRACE_EVENT(drv_config, @@ -514,46 +522,14 @@ TRACE_EVENT(drv_get_tkip_seq, ) ); -TRACE_EVENT(drv_set_frag_threshold, +DEFINE_EVENT(local_u32_evt, drv_set_frag_threshold, TP_PROTO(struct ieee80211_local *local, u32 value), - - TP_ARGS(local, value), - - TP_STRUCT__entry( - LOCAL_ENTRY - __field(u32, value) - ), - - TP_fast_assign( - LOCAL_ASSIGN; - __entry->value = value; - ), - - TP_printk( - LOCAL_PR_FMT " value:%d", - LOCAL_PR_ARG, __entry->value - ) + TP_ARGS(local, value) ); -TRACE_EVENT(drv_set_rts_threshold, +DEFINE_EVENT(local_u32_evt, drv_set_rts_threshold, TP_PROTO(struct ieee80211_local *local, u32 value), - - TP_ARGS(local, value), - - TP_STRUCT__entry( - LOCAL_ENTRY - __field(u32, value) - ), - - TP_fast_assign( - LOCAL_ASSIGN; - __entry->value = value; - ), - - TP_printk( - LOCAL_PR_FMT " value:%d", - LOCAL_PR_ARG, __entry->value - ) + TP_ARGS(local, value) ); TRACE_EVENT(drv_set_coverage_class, -- cgit v0.10.2 From a7ffab33203ae0c755b33a80756fe734f732dbb0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= Date: Tue, 10 May 2011 15:53:16 +0200 Subject: b43legacy: trivial: use TMSLOW def instead of magic value 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 diff --git a/drivers/net/wireless/b43legacy/main.c b/drivers/net/wireless/b43legacy/main.c index f6d5446..1ab8861 100644 --- a/drivers/net/wireless/b43legacy/main.c +++ b/drivers/net/wireless/b43legacy/main.c @@ -2234,7 +2234,7 @@ static int b43legacy_chip_init(struct b43legacy_wldev *dev) b43legacy_write32(dev, B43legacy_MMIO_DMA5_IRQ_MASK, 0x0000DC00); value32 = ssb_read32(dev->dev, SSB_TMSLOW); - value32 |= 0x00100000; + value32 |= B43legacy_TMSLOW_MACPHYCLKEN; ssb_write32(dev->dev, SSB_TMSLOW, value32); b43legacy_write16(dev, B43legacy_MMIO_POWERUP_DELAY, -- cgit v0.10.2 From 858a16529cb4c6434d863740283e0dfeb93cd599 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= Date: Tue, 10 May 2011 16:05:33 +0200 Subject: b43: move MAC PHY clock controling function MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This is not N-PHY specific function, we partially duplicate code. Signed-off-by: RafaÅ‚ MiÅ‚ecki Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c index f7582c0..1e6a2ad 100644 --- a/drivers/net/wireless/b43/main.c +++ b/drivers/net/wireless/b43/main.c @@ -2685,6 +2685,17 @@ out: dev->mac_suspended++; } +/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/MacPhyClkSet */ +void b43_mac_phy_clock_set(struct b43_wldev *dev, bool on) +{ + u32 tmslow = ssb_read32(dev->dev, SSB_TMSLOW); + if (on) + tmslow |= B43_TMSLOW_MACPHYCLKEN; + else + tmslow &= ~B43_TMSLOW_MACPHYCLKEN; + ssb_write32(dev->dev, SSB_TMSLOW, tmslow); +} + static void b43_adjust_opmode(struct b43_wldev *dev) { struct b43_wl *wl = dev->wl; @@ -2841,7 +2852,7 @@ static int b43_chip_init(struct b43_wldev *dev) { struct b43_phy *phy = &dev->phy; int err; - u32 value32, macctl; + u32 macctl; u16 value16; /* Initialize the MAC control */ @@ -2919,9 +2930,7 @@ static int b43_chip_init(struct b43_wldev *dev) b43_write32(dev, B43_MMIO_DMA4_IRQ_MASK, 0x0000DC00); b43_write32(dev, B43_MMIO_DMA5_IRQ_MASK, 0x0000DC00); - value32 = ssb_read32(dev->dev, SSB_TMSLOW); - value32 |= 0x00100000; - ssb_write32(dev->dev, SSB_TMSLOW, value32); + b43_mac_phy_clock_set(dev, true); b43_write16(dev, B43_MMIO_POWERUP_DELAY, dev->dev->bus->chipco.fast_pwrup_delay); diff --git a/drivers/net/wireless/b43/main.h b/drivers/net/wireless/b43/main.h index 40db036..a0d327f 100644 --- a/drivers/net/wireless/b43/main.h +++ b/drivers/net/wireless/b43/main.h @@ -133,6 +133,7 @@ void b43_power_saving_ctl_bits(struct b43_wldev *dev, unsigned int ps_flags); void b43_mac_suspend(struct b43_wldev *dev); void b43_mac_enable(struct b43_wldev *dev); +void b43_mac_phy_clock_set(struct b43_wldev *dev, bool on); struct b43_request_fw_context; diff --git a/drivers/net/wireless/b43/phy_n.c b/drivers/net/wireless/b43/phy_n.c index 6755063..b075a3f 100644 --- a/drivers/net/wireless/b43/phy_n.c +++ b/drivers/net/wireless/b43/phy_n.c @@ -3540,17 +3540,6 @@ static int b43_nphy_cal_rx_iq(struct b43_wldev *dev, return b43_nphy_rev2_cal_rx_iq(dev, target, type, debug); } -/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/MacPhyClkSet */ -static void b43_nphy_mac_phy_clock_set(struct b43_wldev *dev, bool on) -{ - u32 tmslow = ssb_read32(dev->dev, SSB_TMSLOW); - if (on) - tmslow |= B43_TMSLOW_MACPHYCLKEN; - else - tmslow &= ~B43_TMSLOW_MACPHYCLKEN; - ssb_write32(dev->dev, SSB_TMSLOW, tmslow); -} - /* http://bcm-v4.sipsolutions.net/802.11/PHY/N/RxCoreSetState */ static void b43_nphy_set_rx_core_state(struct b43_wldev *dev, u8 mask) { @@ -3691,7 +3680,7 @@ int b43_phy_initn(struct b43_wldev *dev) b43_phy_write(dev, B43_NPHY_BBCFG, tmp & ~B43_NPHY_BBCFG_RSTCCA); b43_nphy_bmac_clock_fgc(dev, 0); - b43_nphy_mac_phy_clock_set(dev, true); + b43_mac_phy_clock_set(dev, true); b43_nphy_pa_override(dev, false); b43_nphy_force_rf_sequence(dev, B43_RFSEQ_RX2TX); -- cgit v0.10.2 From f59a59fea3be78c2bda23cb7f55225b33c502c3c Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Tue, 10 May 2011 20:52:22 +0200 Subject: ath9k: fix a regression in PS frame filter handling Only leave filtering enabled for AP or VLAN interfaces, clear the destination mask for all other interfaces. Signed-off-by: Felix Fietkau Reported-by: Ben Greear Tested-by: Ben Greear Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index 9dd72d8..3381609 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -1782,6 +1782,11 @@ static int ath9k_sta_add(struct ieee80211_hw *hw, struct ieee80211_key_conf ps_key = { }; ath_node_attach(sc, sta); + + if (vif->type != NL80211_IFTYPE_AP && + vif->type != NL80211_IFTYPE_AP_VLAN) + return 0; + an->ps_key = ath_key_config(common, vif, sta, &ps_key); return 0; diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c index 947d5b3..41469d7 100644 --- a/drivers/net/wireless/ath/ath9k/xmit.c +++ b/drivers/net/wireless/ath/ath9k/xmit.c @@ -1845,6 +1845,7 @@ int ath_tx_start(struct ieee80211_hw *hw, struct sk_buff *skb, struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); struct ieee80211_sta *sta = info->control.sta; + struct ieee80211_vif *vif = info->control.vif; struct ath_softc *sc = hw->priv; struct ath_txq *txq = txctl->txq; struct ath_buf *bf; @@ -1882,6 +1883,11 @@ int ath_tx_start(struct ieee80211_hw *hw, struct sk_buff *skb, memmove(skb->data, skb->data + padsize, padpos); } + if ((vif && vif->type != NL80211_IFTYPE_AP && + vif->type != NL80211_IFTYPE_AP_VLAN) || + !ieee80211_is_data(hdr->frame_control)) + info->flags |= IEEE80211_TX_CTL_CLEAR_PS_FILT; + setup_frame_info(hw, skb, frmlen); /* -- cgit v0.10.2 From 1073e4ee595265086a592a056d903bf4fcc8885a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= Date: Wed, 11 May 2011 02:08:09 +0200 Subject: bcma: add missing GPIO defines, use PULL register only when available MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Similar patch was commited to ssb. Signed-off-by: RafaÅ‚ MiÅ‚ecki Signed-off-by: John W. Linville diff --git a/drivers/bcma/driver_chipcommon.c b/drivers/bcma/driver_chipcommon.c index caf5960..6061022 100644 --- a/drivers/bcma/driver_chipcommon.c +++ b/drivers/bcma/driver_chipcommon.c @@ -29,8 +29,10 @@ void bcma_core_chipcommon_init(struct bcma_drv_cc *cc) if (cc->core->id.rev >= 35) cc->capabilities_ext = bcma_cc_read32(cc, BCMA_CC_CAP_EXT); - bcma_cc_write32(cc, 0x58, 0); - bcma_cc_write32(cc, 0x5C, 0); + if (cc->core->id.rev >= 20) { + bcma_cc_write32(cc, BCMA_CC_GPIOPULLUP, 0); + bcma_cc_write32(cc, BCMA_CC_GPIOPULLDOWN, 0); + } if (cc->capabilities & BCMA_CC_CAP_PMU) bcma_pmu_init(cc); diff --git a/include/linux/bcma/bcma_driver_chipcommon.h b/include/linux/bcma/bcma_driver_chipcommon.h index 4f8fd6a..083c3b6 100644 --- a/include/linux/bcma/bcma_driver_chipcommon.h +++ b/include/linux/bcma/bcma_driver_chipcommon.h @@ -113,6 +113,8 @@ #define BCMA_CC_FLASHDATA 0x0048 #define BCMA_CC_BCAST_ADDR 0x0050 #define BCMA_CC_BCAST_DATA 0x0054 +#define BCMA_CC_GPIOPULLUP 0x0058 /* Rev >= 20 only */ +#define BCMA_CC_GPIOPULLDOWN 0x005C /* Rev >= 20 only */ #define BCMA_CC_GPIOIN 0x0060 #define BCMA_CC_GPIOOUT 0x0064 #define BCMA_CC_GPIOOUTEN 0x0068 @@ -121,6 +123,9 @@ #define BCMA_CC_GPIOIRQ 0x0074 #define BCMA_CC_WATCHDOG 0x0080 #define BCMA_CC_GPIOTIMER 0x0088 /* LED powersave (corerev >= 16) */ +#define BCMA_CC_GPIOTIMER_OFFTIME 0x0000FFFF +#define BCMA_CC_GPIOTIMER_OFFTIME_SHIFT 0 +#define BCMA_CC_GPIOTIMER_ONTIME 0xFFFF0000 #define BCMA_CC_GPIOTIMER_ONTIME_SHIFT 16 #define BCMA_CC_GPIOTOUTM 0x008C /* LED powersave (corerev >= 16) */ #define BCMA_CC_CLOCK_N 0x0090 -- cgit v0.10.2 From 8576f815d5c8beb8b10f96abe31831b90af3d352 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= Date: Wed, 11 May 2011 02:10:58 +0200 Subject: ssb: move ssb_commit_settings and export it MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Commiting settings is possible on devices without PCI core (but with CC core). Export it for usage in drivers supporting other cores. Signed-off-by: RafaÅ‚ MiÅ‚ecki Signed-off-by: John W. Linville diff --git a/drivers/ssb/driver_pcicore.c b/drivers/ssb/driver_pcicore.c index 8fde122..82feb34 100644 --- a/drivers/ssb/driver_pcicore.c +++ b/drivers/ssb/driver_pcicore.c @@ -21,8 +21,6 @@ static u16 ssb_pcie_mdio_read(struct ssb_pcicore *pc, u8 device, u8 address); static void ssb_pcie_mdio_write(struct ssb_pcicore *pc, u8 device, u8 address, u16 data); -static void ssb_commit_settings(struct ssb_bus *bus); - static inline u32 pcicore_read32(struct ssb_pcicore *pc, u16 offset) { @@ -659,30 +657,6 @@ static void ssb_pcie_mdio_write(struct ssb_pcicore *pc, u8 device, pcicore_write32(pc, mdio_control, 0); } -static void ssb_broadcast_value(struct ssb_device *dev, - u32 address, u32 data) -{ - /* This is used for both, PCI and ChipCommon core, so be careful. */ - BUILD_BUG_ON(SSB_PCICORE_BCAST_ADDR != SSB_CHIPCO_BCAST_ADDR); - BUILD_BUG_ON(SSB_PCICORE_BCAST_DATA != SSB_CHIPCO_BCAST_DATA); - - ssb_write32(dev, SSB_PCICORE_BCAST_ADDR, address); - ssb_read32(dev, SSB_PCICORE_BCAST_ADDR); /* flush */ - ssb_write32(dev, SSB_PCICORE_BCAST_DATA, data); - ssb_read32(dev, SSB_PCICORE_BCAST_DATA); /* flush */ -} - -static void ssb_commit_settings(struct ssb_bus *bus) -{ - struct ssb_device *dev; - - dev = bus->chipco.dev ? bus->chipco.dev : bus->pcicore.dev; - if (WARN_ON(!dev)) - return; - /* This forces an update of the cached registers. */ - ssb_broadcast_value(dev, 0xFD8, 0); -} - int ssb_pcicore_dev_irqvecs_enable(struct ssb_pcicore *pc, struct ssb_device *dev) { diff --git a/drivers/ssb/main.c b/drivers/ssb/main.c index ad3da93..ee2937c 100644 --- a/drivers/ssb/main.c +++ b/drivers/ssb/main.c @@ -1329,6 +1329,31 @@ error: } EXPORT_SYMBOL(ssb_bus_powerup); +static void ssb_broadcast_value(struct ssb_device *dev, + u32 address, u32 data) +{ + /* This is used for both, PCI and ChipCommon core, so be careful. */ + BUILD_BUG_ON(SSB_PCICORE_BCAST_ADDR != SSB_CHIPCO_BCAST_ADDR); + BUILD_BUG_ON(SSB_PCICORE_BCAST_DATA != SSB_CHIPCO_BCAST_DATA); + + ssb_write32(dev, SSB_PCICORE_BCAST_ADDR, address); + ssb_read32(dev, SSB_PCICORE_BCAST_ADDR); /* flush */ + ssb_write32(dev, SSB_PCICORE_BCAST_DATA, data); + ssb_read32(dev, SSB_PCICORE_BCAST_DATA); /* flush */ +} + +void ssb_commit_settings(struct ssb_bus *bus) +{ + struct ssb_device *dev; + + dev = bus->chipco.dev ? bus->chipco.dev : bus->pcicore.dev; + if (WARN_ON(!dev)) + return; + /* This forces an update of the cached registers. */ + ssb_broadcast_value(dev, 0xFD8, 0); +} +EXPORT_SYMBOL(ssb_commit_settings); + u32 ssb_admatch_base(u32 adm) { u32 base = 0; diff --git a/include/linux/ssb/ssb.h b/include/linux/ssb/ssb.h index 7e99b34..f017b89 100644 --- a/include/linux/ssb/ssb.h +++ b/include/linux/ssb/ssb.h @@ -518,6 +518,7 @@ extern int ssb_bus_may_powerdown(struct ssb_bus *bus); * Otherwise static always-on powercontrol will be used. */ extern int ssb_bus_powerup(struct ssb_bus *bus, bool dynamic_pctl); +extern void ssb_commit_settings(struct ssb_bus *bus); /* Various helper functions */ extern u32 ssb_admatch_base(u32 adm); -- cgit v0.10.2 From 0fd82eafe3aa70937905b7e19e256409ae48477e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= Date: Wed, 11 May 2011 02:10:59 +0200 Subject: b43: implement timeouts workaround MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Documented in: <4DCA7E40.9070709@lwfinger.net> Signed-off-by: RafaÅ‚ MiÅ‚ecki Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c index 1e6a2ad..a96e05a 100644 --- a/drivers/net/wireless/b43/main.c +++ b/drivers/net/wireless/b43/main.c @@ -4221,7 +4221,18 @@ static void b43_bluetooth_coext_disable(struct b43_wldev *dev) static void b43_imcfglo_timeouts_workaround(struct b43_wldev *dev) { - /* TODO: implement 80211 core workaround here */ + struct ssb_bus *bus = dev->dev->bus; + u32 tmp; + + if ((bus->chip_id == 0x4311 && bus->chip_rev == 2) || + (bus->chip_id == 0x4312)) { + tmp = ssb_read32(dev->dev, SSB_IMCFGLO); + tmp &= ~SSB_IMCFGLO_REQTO; + tmp &= ~SSB_IMCFGLO_SERTO; + tmp |= 0x3; + ssb_write32(dev->dev, SSB_IMCFGLO, tmp); + ssb_commit_settings(bus); + } } static void b43_set_synth_pu_delay(struct b43_wldev *dev, bool idle) -- cgit v0.10.2 From c4859fbcfc12d5cfe8c30a33ad37d192a3093a7b Mon Sep 17 00:00:00 2001 From: Amitkumar Karwar Date: Tue, 10 May 2011 20:47:35 -0700 Subject: mwifiex: remove redundant local structures Avoid use of local structure in the function if the structure is already allocated by the caller and the structure pointer is passed. Signed-off-by: Amitkumar Karwar Signed-off-by: Bing Zhao Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/mwifiex/sta_ioctl.c b/drivers/net/wireless/mwifiex/sta_ioctl.c index 75bca56..d05907d 100644 --- a/drivers/net/wireless/mwifiex/sta_ioctl.c +++ b/drivers/net/wireless/mwifiex/sta_ioctl.c @@ -1250,11 +1250,9 @@ mwifiex_drv_get_driver_version(struct mwifiex_adapter *adapter, char *version, int mwifiex_get_signal_info(struct mwifiex_private *priv, struct mwifiex_ds_get_signal *signal) { - struct mwifiex_ds_get_signal info; int status; - memset(&info, 0, sizeof(struct mwifiex_ds_get_signal)); - info.selector = ALL_RSSI_INFO_MASK; + signal->selector = ALL_RSSI_INFO_MASK; /* Signal info can be obtained only if connected */ if (!priv->media_connected) { @@ -1267,13 +1265,10 @@ int mwifiex_get_signal_info(struct mwifiex_private *priv, HostCmd_ACT_GEN_GET, 0, signal); if (!status) { - if (signal) - memcpy(signal, &info, - sizeof(struct mwifiex_ds_get_signal)); - if (info.selector & BCN_RSSI_AVG_MASK) - priv->w_stats.qual.level = info.bcn_rssi_avg; - if (info.selector & BCN_NF_AVG_MASK) - priv->w_stats.qual.noise = info.bcn_nf_avg; + if (signal->selector & BCN_RSSI_AVG_MASK) + priv->w_stats.qual.level = signal->bcn_rssi_avg; + if (signal->selector & BCN_NF_AVG_MASK) + priv->w_stats.qual.noise = signal->bcn_nf_avg; } return status; @@ -1333,19 +1328,14 @@ mwifiex_get_stats_info(struct mwifiex_private *priv, struct mwifiex_ds_get_stats *log) { int ret; - struct mwifiex_ds_get_stats get_log; - memset(&get_log, 0, sizeof(struct mwifiex_ds_get_stats)); ret = mwifiex_send_cmd_sync(priv, HostCmd_CMD_802_11_GET_LOG, - HostCmd_ACT_GEN_GET, 0, &get_log); + HostCmd_ACT_GEN_GET, 0, log); if (!ret) { - if (log) - memcpy(log, &get_log, sizeof(struct - mwifiex_ds_get_stats)); - priv->w_stats.discard.fragment = get_log.fcs_error; - priv->w_stats.discard.retries = get_log.retry; - priv->w_stats.discard.misc = get_log.ack_failure; + priv->w_stats.discard.fragment = log->fcs_error; + priv->w_stats.discard.retries = log->retry; + priv->w_stats.discard.misc = log->ack_failure; } return ret; -- cgit v0.10.2 From a8c485652ad4217800015aab25f1b70b96adb1a9 Mon Sep 17 00:00:00 2001 From: Bing Zhao Date: Tue, 10 May 2011 20:47:36 -0700 Subject: mwifiex: cleanup ioctl.h Some structures and macros in ioctl.h are redundant or no longer used. Signed-off-by: Bing Zhao Signed-off-by: Yogesh Ashok Powar Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/mwifiex/cfg80211.c b/drivers/net/wireless/mwifiex/cfg80211.c index 19be887..660831c 100644 --- a/drivers/net/wireless/mwifiex/cfg80211.c +++ b/drivers/net/wireless/mwifiex/cfg80211.c @@ -761,7 +761,6 @@ static int mwifiex_cfg80211_inform_ibss_bss(struct mwifiex_private *priv) static int mwifiex_inform_bss_from_scan_result(struct mwifiex_private *priv, struct mwifiex_802_11_ssid *ssid) { - struct mwifiex_scan_resp scan_resp; struct mwifiex_bssdescriptor *scan_table; int i, j; struct ieee80211_channel *chan; @@ -771,10 +770,6 @@ static int mwifiex_inform_bss_from_scan_result(struct mwifiex_private *priv, int beacon_size; u8 element_id, element_len; - memset(&scan_resp, 0, sizeof(scan_resp)); - scan_resp.scan_table = (u8 *) priv->adapter->scan_table; - scan_resp.num_in_scan_table = priv->adapter->num_in_scan_table; - #define MAX_IE_BUF 2048 ie_buf = kzalloc(MAX_IE_BUF, GFP_KERNEL); if (!ie_buf) { @@ -783,8 +778,8 @@ static int mwifiex_inform_bss_from_scan_result(struct mwifiex_private *priv, return -ENOMEM; } - scan_table = (struct mwifiex_bssdescriptor *) scan_resp.scan_table; - for (i = 0; i < scan_resp.num_in_scan_table; i++) { + scan_table = priv->adapter->scan_table; + for (i = 0; i < priv->adapter->num_in_scan_table; i++) { if (ssid) { /* Inform specific BSS only */ if (memcmp(ssid->ssid, scan_table[i].ssid.ssid, diff --git a/drivers/net/wireless/mwifiex/fw.h b/drivers/net/wireless/mwifiex/fw.h index c6b2681..afdd145 100644 --- a/drivers/net/wireless/mwifiex/fw.h +++ b/drivers/net/wireless/mwifiex/fw.h @@ -816,14 +816,7 @@ struct host_cmd_ds_txpwr_cfg { struct mwifiex_scan_cmd_config { /* - * BSS Type to be sent in the firmware command - * - * Field can be used to restrict the types of networks returned in the - * scan. Valid settings are: - * - * - MWIFIEX_SCAN_MODE_BSS (infrastructure) - * - MWIFIEX_SCAN_MODE_IBSS (adhoc) - * - MWIFIEX_SCAN_MODE_ANY (unrestricted, adhoc and infrastructure) + * BSS mode to be sent in the firmware command */ u8 bss_mode; @@ -866,13 +859,6 @@ struct mwifiex_user_scan_cfg { u8 keep_previous_scan; /* * BSS mode to be sent in the firmware command - * - * Field can be used to restrict the types of networks returned in the - * scan. Valid settings are: - * - * - MWIFIEX_SCAN_MODE_BSS (infrastructure) - * - MWIFIEX_SCAN_MODE_IBSS (adhoc) - * - MWIFIEX_SCAN_MODE_ANY (unrestricted, adhoc and infrastructure) */ u8 bss_mode; /* Configure the number of probe requests for active chan scans */ diff --git a/drivers/net/wireless/mwifiex/ioctl.h b/drivers/net/wireless/mwifiex/ioctl.h index 5488e11..7c1c5ee 100644 --- a/drivers/net/wireless/mwifiex/ioctl.h +++ b/drivers/net/wireless/mwifiex/ioctl.h @@ -23,49 +23,16 @@ #include enum { - MWIFIEX_SCAN_MODE_UNCHANGED = 0, - MWIFIEX_SCAN_MODE_BSS, - MWIFIEX_SCAN_MODE_IBSS, - MWIFIEX_SCAN_MODE_ANY -}; - -enum { MWIFIEX_SCAN_TYPE_UNCHANGED = 0, MWIFIEX_SCAN_TYPE_ACTIVE, MWIFIEX_SCAN_TYPE_PASSIVE }; -struct mwifiex_get_scan_table_fixed { - u8 bssid[ETH_ALEN]; - u8 channel; - u8 rssi; - long long network_tsf; -}; - -struct mwifiex_scan_time_params { - u32 specific_scan_time; - u32 active_scan_time; - u32 passive_scan_time; -}; - struct mwifiex_user_scan { u32 scan_cfg_len; u8 scan_cfg_buf[1]; }; -struct mwifiex_scan_req { - u32 scan_mode; - u32 scan_type; - struct mwifiex_802_11_ssid scan_ssid; - struct mwifiex_scan_time_params scan_time; - struct mwifiex_user_scan user_scan; -}; - -struct mwifiex_scan_resp { - u32 num_in_scan_table; - u8 *scan_table; -}; - #define MWIFIEX_PROMISC_MODE 1 #define MWIFIEX_MULTICAST_MODE 2 #define MWIFIEX_ALL_MULTI_MODE 4 @@ -77,18 +44,11 @@ struct mwifiex_multicast_list { u8 mac_list[MWIFIEX_MAX_MULTICAST_LIST_SIZE][ETH_ALEN]; }; -#define MWIFIEX_MAX_CHANNEL_NUM 128 - struct mwifiex_chan_freq { u32 channel; u32 freq; }; -struct mwifiex_chan_list { - u32 num_of_chan; - struct mwifiex_chan_freq cf[MWIFIEX_MAX_CHANNEL_NUM]; -}; - struct mwifiex_ssid_bssid { struct mwifiex_802_11_ssid ssid; u8 bssid[ETH_ALEN]; @@ -136,18 +96,8 @@ struct mwifiex_ds_get_stats { u32 wep_icv_error[4]; }; -#define BCN_RSSI_LAST_MASK 0x00000001 #define BCN_RSSI_AVG_MASK 0x00000002 -#define DATA_RSSI_LAST_MASK 0x00000004 -#define DATA_RSSI_AVG_MASK 0x00000008 -#define BCN_SNR_LAST_MASK 0x00000010 -#define BCN_SNR_AVG_MASK 0x00000020 -#define DATA_SNR_LAST_MASK 0x00000040 -#define DATA_SNR_AVG_MASK 0x00000080 -#define BCN_NF_LAST_MASK 0x00000100 #define BCN_NF_AVG_MASK 0x00000200 -#define DATA_NF_LAST_MASK 0x00000400 -#define DATA_NF_AVG_MASK 0x00000800 #define ALL_RSSI_INFO_MASK 0x00000fff struct mwifiex_ds_get_signal { @@ -174,11 +124,6 @@ struct mwifiex_ds_get_signal { s16 data_nf_avg; }; -struct mwifiex_fw_info { - u32 fw_ver; - u8 mac_addr[ETH_ALEN]; -}; - #define MWIFIEX_MAX_VER_STR_LEN 128 struct mwifiex_ver_ext { @@ -286,11 +231,6 @@ struct mwifiex_rate_cfg { u32 rate; }; -struct mwifiex_data_rate { - u32 tx_data_rate; - u32 rx_data_rate; -}; - struct mwifiex_power_cfg { u32 is_power_auto; u32 power_level; @@ -309,21 +249,14 @@ struct mwifiex_ds_hs_cfg { }; #define DEEP_SLEEP_ON 1 -#define DEEP_SLEEP_OFF 0 - #define DEEP_SLEEP_IDLE_TIME 100 +#define PS_MODE_AUTO 1 struct mwifiex_ds_auto_ds { u16 auto_ds; u16 idle_time; }; -#define PS_MODE_UNCHANGED 0 -#define PS_MODE_AUTO 1 -#define PS_MODE_POLL 2 -#define PS_MODE_NULL 3 - - struct mwifiex_ds_pm_cfg { union { u32 ps_mode; @@ -333,18 +266,6 @@ struct mwifiex_ds_pm_cfg { } param; }; -struct mwifiex_ioctl_wmm_queue_status_ac { - u8 wmm_acm; - u8 flow_required; - u8 flow_created; - u8 disabled; -}; - -struct mwifiex_ds_wmm_queue_status { - struct mwifiex_ioctl_wmm_queue_status_ac - ac_status[IEEE80211_MAX_QUEUES]; -}; - struct mwifiex_ds_11n_tx_cfg { u16 tx_htcap; u16 tx_htinfo; -- cgit v0.10.2 From 87186475a402391a1ca7d42a675c9b35a18dc348 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Tue, 10 May 2011 21:09:53 +0200 Subject: PM: Fix warning in pm_restrict_gfp_mask() during SNAPSHOT_S2RAM ioctl A warning is printed by pm_restrict_gfp_mask() while the SNAPSHOT_S2RAM ioctl is being executed after creating a hibernation image, because pm_restrict_gfp_mask() has been called once already before the image creation and suspend_devices_and_enter() calls it once again. This happens after commit 452aa6999e6703ffbddd7f6ea124d3 (mm/pm: force GFP_NOIO during suspend/hibernation and resume). To avoid this issue, move pm_restrict_gfp_mask() and pm_restore_gfp_mask() from suspend_devices_and_enter() to its caller in kernel/power/suspend.c. Reported-by: Alexandre Felipe Muller de Souza Signed-off-by: Rafael J. Wysocki Cc: stable@kernel.org diff --git a/kernel/power/suspend.c b/kernel/power/suspend.c index 8935369..6275970 100644 --- a/kernel/power/suspend.c +++ b/kernel/power/suspend.c @@ -216,7 +216,6 @@ int suspend_devices_and_enter(suspend_state_t state) goto Close; } suspend_console(); - pm_restrict_gfp_mask(); suspend_test_start(); error = dpm_suspend_start(PMSG_SUSPEND); if (error) { @@ -233,7 +232,6 @@ int suspend_devices_and_enter(suspend_state_t state) suspend_test_start(); dpm_resume_end(PMSG_RESUME); suspend_test_finish("resume devices"); - pm_restore_gfp_mask(); resume_console(); Close: if (suspend_ops->end) @@ -294,7 +292,9 @@ int enter_state(suspend_state_t state) goto Finish; pr_debug("PM: Entering %s sleep\n", pm_states[state]); + pm_restrict_gfp_mask(); error = suspend_devices_and_enter(state); + pm_restore_gfp_mask(); Finish: pr_debug("PM: Finishing wakeup.\n"); -- cgit v0.10.2 From 9744997a8a2280e67984d4bffd87221d24f3b6b1 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Tue, 10 May 2011 21:10:01 +0200 Subject: PM / Hibernate: Make snapshot_release() restore GFP mask If the process using the hibernate user space interface closes /dev/snapshot after creating a hibernation image without thawing tasks, snapshot_release() should call pm_restore_gfp_mask() to restore the GFP mask used before the creation of the image. Make that happen. Tested-by: Alexandre Felipe Muller de Souza Signed-off-by: Rafael J. Wysocki Cc: stable@kernel.org diff --git a/kernel/power/user.c b/kernel/power/user.c index c36c3b9..6522be9 100644 --- a/kernel/power/user.c +++ b/kernel/power/user.c @@ -135,8 +135,10 @@ static int snapshot_release(struct inode *inode, struct file *filp) free_basic_memory_bitmaps(); data = filp->private_data; free_all_swap_pages(data->swap); - if (data->frozen) + if (data->frozen) { + pm_restore_gfp_mask(); thaw_processes(); + } pm_notifier_call_chain(data->mode == O_RDONLY ? PM_POST_HIBERNATION : PM_POST_RESTORE); atomic_inc(&snapshot_device_available); -- cgit v0.10.2 From 36cb7035ea0c11ef2c7fa2bbe0cd181b23569b29 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Tue, 10 May 2011 21:10:13 +0200 Subject: PM / Hibernate: Fix ioctl SNAPSHOT_S2RAM The SNAPSHOT_S2RAM ioctl used for implementing the feature allowing one to suspend to RAM after creating a hibernation image is currently broken, because it doesn't clear the "ready" flag in the struct snapshot_data object handled by it. As a result, the SNAPSHOT_UNFREEZE doesn't work correctly after SNAPSHOT_S2RAM has returned and the user space hibernate task cannot thaw the other processes as appropriate. Make SNAPSHOT_S2RAM clear data->ready to fix this problem. Tested-by: Alexandre Felipe Muller de Souza Signed-off-by: Rafael J. Wysocki Cc: stable@kernel.org diff --git a/kernel/power/user.c b/kernel/power/user.c index 6522be9..7d02d33 100644 --- a/kernel/power/user.c +++ b/kernel/power/user.c @@ -381,6 +381,7 @@ static long snapshot_ioctl(struct file *filp, unsigned int cmd, * PM_HIBERNATION_PREPARE */ error = suspend_devices_and_enter(PM_SUSPEND_MEM); + data->ready = 0; break; case SNAPSHOT_PLATFORM_SUPPORT: -- cgit v0.10.2 From 6bdbdbf4a151a3a1333818cd17a7d7795e936041 Mon Sep 17 00:00:00 2001 From: Sascha Silbe Date: Wed, 11 May 2011 14:52:34 +0200 Subject: libertas: Add libertas_disablemesh module parameter to disable mesh interface This allows individual users and deployments to disable mesh support at runtime, i.e. without having to build and maintain a custom kernel. Based on a patch by Paul Fox . Signed-off-by: Sascha Silbe Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/libertas/main.c b/drivers/net/wireless/libertas/main.c index 84d05a7..8c40949 100644 --- a/drivers/net/wireless/libertas/main.c +++ b/drivers/net/wireless/libertas/main.c @@ -36,6 +36,10 @@ unsigned int lbs_debug; EXPORT_SYMBOL_GPL(lbs_debug); module_param_named(libertas_debug, lbs_debug, int, 0644); +unsigned int lbs_disablemesh; +EXPORT_SYMBOL_GPL(lbs_disablemesh); +module_param_named(libertas_disablemesh, lbs_disablemesh, int, 0644); + /* * This global structure is used to send the confirm_sleep command as @@ -944,7 +948,10 @@ int lbs_start_card(struct lbs_private *priv) lbs_update_channel(priv); - lbs_init_mesh(priv); + if (!lbs_disablemesh) + lbs_init_mesh(priv); + else + pr_info("%s: mesh disabled\n", dev->name); lbs_debugfs_init_one(priv, dev); -- cgit v0.10.2 From 807f8a8c300435d5483e8d78df9dcdbc27333166 Mon Sep 17 00:00:00 2001 From: Luciano Coelho Date: Wed, 11 May 2011 17:09:35 +0300 Subject: cfg80211/nl80211: add support for scheduled scans Implement new functionality for scheduled scan offload. With this feature we can scan automatically at certain intervals. The idea is that the hardware can perform scan automatically and filter on desired results without waking up the host unnecessarily. Add NL80211_CMD_START_SCHED_SCAN and NL80211_CMD_STOP_SCHED_SCAN commands to the nl80211 interface. When results are available they are reported by NL80211_CMD_SCHED_SCAN_RESULTS events. The userspace is informed when the scheduled scan has stopped with a NL80211_CMD_SCHED_SCAN_STOPPED event, which can be triggered either by the driver or by a call to NL80211_CMD_STOP_SCHED_SCAN. Signed-off-by: Luciano Coelho Signed-off-by: John W. Linville diff --git a/include/linux/nl80211.h b/include/linux/nl80211.h index de96783..f8b5595 100644 --- a/include/linux/nl80211.h +++ b/include/linux/nl80211.h @@ -203,6 +203,26 @@ * @NL80211_CMD_SCAN_ABORTED: scan was aborted, for unspecified reasons, * partial scan results may be available * + * @NL80211_CMD_START_SCHED_SCAN: start a scheduled scan. Like with normal + * scans, if SSIDs (%NL80211_ATTR_SCAN_SSIDS) are passed, they are used + * in the probe requests. For broadcast, a broadcast SSID must be + * passed (ie. an empty string). If no SSID is passed, no probe + * requests are sent and a passive scan is performed. + * %NL80211_ATTR_SCAN_FREQUENCIES, if passed, define which channels + * should be scanned; if not passed, all channels allowed for the + * current regulatory domain are used. Extra IEs can also be passed + * from the userspace by using the %NL80211_ATTR_IE attribute. + * @NL80211_CMD_STOP_SCHED_SCAN: stop a scheduled scan + * @NL80211_CMD_SCHED_SCAN_RESULTS: indicates that there are scheduled scan + * results available. + * @NL80211_CMD_SCHED_SCAN_STOPPED: indicates that the scheduled scan has + * stopped. The driver may issue this event at any time during a + * scheduled scan. One reason for stopping the scan is if the hardware + * does not support starting an association or a normal scan while running + * a scheduled scan. This event is also sent when the + * %NL80211_CMD_STOP_SCHED_SCAN command is received or when the interface + * is brought down while a scheduled scan was running. + * * @NL80211_CMD_GET_SURVEY: get survey resuls, e.g. channel occupation * or noise level * @NL80211_CMD_NEW_SURVEY_RESULTS: survey data notification (as a reply to @@ -545,6 +565,11 @@ enum nl80211_commands { NL80211_CMD_GET_WOWLAN, NL80211_CMD_SET_WOWLAN, + NL80211_CMD_START_SCHED_SCAN, + NL80211_CMD_STOP_SCHED_SCAN, + NL80211_CMD_SCHED_SCAN_RESULTS, + NL80211_CMD_SCHED_SCAN_STOPPED, + /* add new commands above here */ /* used to define NL80211_CMD_MAX below */ diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index 4b0d035..e214c85 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -824,6 +824,33 @@ struct cfg80211_scan_request { }; /** + * struct cfg80211_sched_scan_request - scheduled scan request description + * + * @ssids: SSIDs to scan for (passed in the probe_reqs in active scans) + * @n_ssids: number of SSIDs + * @n_channels: total number of channels to scan + * @ie: optional information element(s) to add into Probe Request or %NULL + * @ie_len: length of ie in octets + * @wiphy: the wiphy this was for + * @dev: the interface + * @channels: channels to scan + */ +struct cfg80211_sched_scan_request { + struct cfg80211_ssid *ssids; + int n_ssids; + u32 n_channels; + const u8 *ie; + size_t ie_len; + + /* internal */ + struct wiphy *wiphy; + struct net_device *dev; + + /* keep last */ + struct ieee80211_channel *channels[0]; +}; + +/** * enum cfg80211_signal_type - signal type * * @CFG80211_SIGNAL_TYPE_NONE: no signal strength information available @@ -1292,6 +1319,10 @@ struct cfg80211_wowlan { * @set_power_mgmt: Configure WLAN power management. A timeout value of -1 * allows the driver to adjust the dynamic ps timeout value. * @set_cqm_rssi_config: Configure connection quality monitor RSSI threshold. + * @sched_scan_start: Tell the driver to start a scheduled scan. + * @sched_scan_stop: Tell the driver to stop an ongoing scheduled + * scan. The driver_initiated flag specifies whether the driver + * itself has informed that the scan has stopped. * * @mgmt_frame_register: Notify driver that a management frame type was * registered. Note that this callback may not sleep, and cannot run @@ -1478,6 +1509,12 @@ struct cfg80211_ops { int (*set_ringparam)(struct wiphy *wiphy, u32 tx, u32 rx); void (*get_ringparam)(struct wiphy *wiphy, u32 *tx, u32 *tx_max, u32 *rx, u32 *rx_max); + + int (*sched_scan_start)(struct wiphy *wiphy, + struct net_device *dev, + struct cfg80211_sched_scan_request *request); + int (*sched_scan_stop)(struct wiphy *wiphy, struct net_device *dev, + bool driver_initiated); }; /* @@ -1522,6 +1559,7 @@ struct cfg80211_ops { * @WIPHY_FLAG_IBSS_RSN: The device supports IBSS RSN. * @WIPHY_FLAG_MESH_AUTH: The device supports mesh authentication by routing * auth frames to userspace. See @NL80211_MESH_SETUP_USERSPACE_AUTH. + * @WIPHY_FLAG_SCHED_SCAN: The device supports scheduled scans. */ enum wiphy_flags { WIPHY_FLAG_CUSTOM_REGULATORY = BIT(0), @@ -1534,6 +1572,7 @@ enum wiphy_flags { WIPHY_FLAG_CONTROL_PORT_PROTOCOL = BIT(7), WIPHY_FLAG_IBSS_RSN = BIT(8), WIPHY_FLAG_MESH_AUTH = BIT(10), + WIPHY_FLAG_SUPPORTS_SCHED_SCAN = BIT(11), }; struct mac_address { @@ -2355,6 +2394,24 @@ int cfg80211_wext_siwpmksa(struct net_device *dev, void cfg80211_scan_done(struct cfg80211_scan_request *request, bool aborted); /** + * cfg80211_sched_scan_results - notify that new scan results are available + * + * @wiphy: the wiphy which got scheduled scan results + */ +void cfg80211_sched_scan_results(struct wiphy *wiphy); + +/** + * cfg80211_sched_scan_stopped - notify that the scheduled scan has stopped + * + * @wiphy: the wiphy on which the scheduled scan stopped + * + * The driver can call this function to inform cfg80211 that the + * scheduled scan had to be stopped, for whatever reason. The driver + * is then called back via the sched_scan_stop operation when done. + */ +void cfg80211_sched_scan_stopped(struct wiphy *wiphy); + +/** * cfg80211_inform_bss_frame - inform cfg80211 of a received BSS frame * * @wiphy: the wiphy reporting the BSS diff --git a/net/wireless/core.c b/net/wireless/core.c index bea0d80..f924a49 100644 --- a/net/wireless/core.c +++ b/net/wireless/core.c @@ -370,7 +370,8 @@ struct wiphy *wiphy_new(const struct cfg80211_ops *ops, int sizeof_priv) spin_lock_init(&rdev->bss_lock); INIT_LIST_HEAD(&rdev->bss_list); INIT_WORK(&rdev->scan_done_wk, __cfg80211_scan_done); - + INIT_WORK(&rdev->sched_scan_results_wk, __cfg80211_sched_scan_results); + INIT_WORK(&rdev->sched_scan_stopped_wk, __cfg80211_sched_scan_stopped); #ifdef CONFIG_CFG80211_WEXT rdev->wiphy.wext = &cfg80211_wext_handler; #endif @@ -672,6 +673,11 @@ static void wdev_cleanup_work(struct work_struct *work) ___cfg80211_scan_done(rdev, true); } + if (WARN_ON(rdev->sched_scan_req && + rdev->sched_scan_req->dev == wdev->netdev)) { + __cfg80211_stop_sched_scan(rdev, false); + } + cfg80211_unlock_rdev(rdev); mutex_lock(&rdev->devlist_mtx); @@ -759,6 +765,10 @@ static int cfg80211_netdev_notifier_call(struct notifier_block * nb, break; case NL80211_IFTYPE_P2P_CLIENT: case NL80211_IFTYPE_STATION: + cfg80211_lock_rdev(rdev); + __cfg80211_stop_sched_scan(rdev, false); + cfg80211_unlock_rdev(rdev); + wdev_lock(wdev); #ifdef CONFIG_CFG80211_WEXT kfree(wdev->wext.ie); diff --git a/net/wireless/core.h b/net/wireless/core.h index 7a18c10..e3f7b1d 100644 --- a/net/wireless/core.h +++ b/net/wireless/core.h @@ -60,8 +60,11 @@ struct cfg80211_registered_device { struct rb_root bss_tree; u32 bss_generation; struct cfg80211_scan_request *scan_req; /* protected by RTNL */ + struct cfg80211_sched_scan_request *sched_scan_req; unsigned long suspend_at; struct work_struct scan_done_wk; + struct work_struct sched_scan_results_wk; + struct work_struct sched_scan_stopped_wk; #ifdef CONFIG_NL80211_TESTMODE struct genl_info *testmode_info; @@ -411,6 +414,10 @@ void cfg80211_sme_rx_auth(struct net_device *dev, const u8 *buf, size_t len); void cfg80211_sme_disassoc(struct net_device *dev, int idx); void __cfg80211_scan_done(struct work_struct *wk); void ___cfg80211_scan_done(struct cfg80211_registered_device *rdev, bool leak); +void __cfg80211_sched_scan_results(struct work_struct *wk); +int __cfg80211_stop_sched_scan(struct cfg80211_registered_device *rdev, + bool driver_initiated); +void __cfg80211_sched_scan_stopped(struct work_struct *wk); void cfg80211_upload_connect_keys(struct wireless_dev *wdev); int cfg80211_change_iface(struct cfg80211_registered_device *rdev, struct net_device *dev, enum nl80211_iftype ntype, diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 95dd583..4fac370 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -761,6 +761,8 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags, } CMD(set_channel, SET_CHANNEL); CMD(set_wds_peer, SET_WDS_PEER); + if (dev->wiphy.flags & WIPHY_FLAG_SUPPORTS_SCHED_SCAN) + CMD(sched_scan_start, START_SCHED_SCAN); #undef CMD @@ -3357,6 +3359,179 @@ static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info) return err; } +static int nl80211_start_sched_scan(struct sk_buff *skb, + struct genl_info *info) +{ + struct cfg80211_sched_scan_request *request; + struct cfg80211_registered_device *rdev = info->user_ptr[0]; + struct net_device *dev = info->user_ptr[1]; + struct cfg80211_ssid *ssid; + struct ieee80211_channel *channel; + struct nlattr *attr; + struct wiphy *wiphy; + int err, tmp, n_ssids = 0, n_channels, i; + enum ieee80211_band band; + size_t ie_len; + + if (!(rdev->wiphy.flags & WIPHY_FLAG_SUPPORTS_SCHED_SCAN) || + !rdev->ops->sched_scan_start) + return -EOPNOTSUPP; + + if (!is_valid_ie_attr(info->attrs[NL80211_ATTR_IE])) + return -EINVAL; + + if (rdev->sched_scan_req) + return -EINPROGRESS; + + wiphy = &rdev->wiphy; + + if (info->attrs[NL80211_ATTR_SCAN_FREQUENCIES]) { + n_channels = validate_scan_freqs( + info->attrs[NL80211_ATTR_SCAN_FREQUENCIES]); + if (!n_channels) + return -EINVAL; + } else { + n_channels = 0; + + for (band = 0; band < IEEE80211_NUM_BANDS; band++) + if (wiphy->bands[band]) + n_channels += wiphy->bands[band]->n_channels; + } + + if (info->attrs[NL80211_ATTR_SCAN_SSIDS]) + nla_for_each_nested(attr, info->attrs[NL80211_ATTR_SCAN_SSIDS], + tmp) + n_ssids++; + + if (n_ssids > wiphy->max_scan_ssids) + return -EINVAL; + + if (info->attrs[NL80211_ATTR_IE]) + ie_len = nla_len(info->attrs[NL80211_ATTR_IE]); + else + ie_len = 0; + + if (ie_len > wiphy->max_scan_ie_len) + return -EINVAL; + + request = kzalloc(sizeof(*request) + + sizeof(*ssid) * n_ssids + + sizeof(channel) * n_channels + + ie_len, GFP_KERNEL); + if (!request) + return -ENOMEM; + + if (n_ssids) + request->ssids = (void *)&request->channels[n_channels]; + request->n_ssids = n_ssids; + if (ie_len) { + if (request->ssids) + request->ie = (void *)(request->ssids + n_ssids); + else + request->ie = (void *)(request->channels + n_channels); + } + + i = 0; + if (info->attrs[NL80211_ATTR_SCAN_FREQUENCIES]) { + /* user specified, bail out if channel not found */ + nla_for_each_nested(attr, + info->attrs[NL80211_ATTR_SCAN_FREQUENCIES], + tmp) { + struct ieee80211_channel *chan; + + chan = ieee80211_get_channel(wiphy, nla_get_u32(attr)); + + if (!chan) { + err = -EINVAL; + goto out_free; + } + + /* ignore disabled channels */ + if (chan->flags & IEEE80211_CHAN_DISABLED) + continue; + + request->channels[i] = chan; + i++; + } + } else { + /* all channels */ + for (band = 0; band < IEEE80211_NUM_BANDS; band++) { + int j; + if (!wiphy->bands[band]) + continue; + for (j = 0; j < wiphy->bands[band]->n_channels; j++) { + struct ieee80211_channel *chan; + + chan = &wiphy->bands[band]->channels[j]; + + if (chan->flags & IEEE80211_CHAN_DISABLED) + continue; + + request->channels[i] = chan; + i++; + } + } + } + + if (!i) { + err = -EINVAL; + goto out_free; + } + + request->n_channels = i; + + i = 0; + if (info->attrs[NL80211_ATTR_SCAN_SSIDS]) { + nla_for_each_nested(attr, info->attrs[NL80211_ATTR_SCAN_SSIDS], + tmp) { + if (request->ssids[i].ssid_len > + IEEE80211_MAX_SSID_LEN) { + err = -EINVAL; + goto out_free; + } + memcpy(request->ssids[i].ssid, nla_data(attr), + nla_len(attr)); + request->ssids[i].ssid_len = nla_len(attr); + i++; + } + } + + if (info->attrs[NL80211_ATTR_IE]) { + request->ie_len = nla_len(info->attrs[NL80211_ATTR_IE]); + memcpy((void *)request->ie, + nla_data(info->attrs[NL80211_ATTR_IE]), + request->ie_len); + } + + request->dev = dev; + request->wiphy = &rdev->wiphy; + + err = rdev->ops->sched_scan_start(&rdev->wiphy, dev, request); + if (!err) { + rdev->sched_scan_req = request; + nl80211_send_sched_scan(rdev, dev, + NL80211_CMD_START_SCHED_SCAN); + goto out; + } + +out_free: + kfree(request); +out: + return err; +} + +static int nl80211_stop_sched_scan(struct sk_buff *skb, + struct genl_info *info) +{ + struct cfg80211_registered_device *rdev = info->user_ptr[0]; + + if (!(rdev->wiphy.flags & WIPHY_FLAG_SUPPORTS_SCHED_SCAN) || + !rdev->ops->sched_scan_stop) + return -EOPNOTSUPP; + + return __cfg80211_stop_sched_scan(rdev, false); +} + static int nl80211_send_bss(struct sk_buff *msg, u32 pid, u32 seq, int flags, struct cfg80211_registered_device *rdev, struct wireless_dev *wdev, @@ -5327,6 +5502,22 @@ static struct genl_ops nl80211_ops[] = { .dumpit = nl80211_dump_scan, }, { + .cmd = NL80211_CMD_START_SCHED_SCAN, + .doit = nl80211_start_sched_scan, + .policy = nl80211_policy, + .flags = GENL_ADMIN_PERM, + .internal_flags = NL80211_FLAG_NEED_NETDEV_UP | + NL80211_FLAG_NEED_RTNL, + }, + { + .cmd = NL80211_CMD_STOP_SCHED_SCAN, + .doit = nl80211_stop_sched_scan, + .policy = nl80211_policy, + .flags = GENL_ADMIN_PERM, + .internal_flags = NL80211_FLAG_NEED_NETDEV_UP | + NL80211_FLAG_NEED_RTNL, + }, + { .cmd = NL80211_CMD_AUTHENTICATE, .doit = nl80211_authenticate, .policy = nl80211_policy, @@ -5652,6 +5843,28 @@ static int nl80211_send_scan_msg(struct sk_buff *msg, return -EMSGSIZE; } +static int +nl80211_send_sched_scan_msg(struct sk_buff *msg, + struct cfg80211_registered_device *rdev, + struct net_device *netdev, + u32 pid, u32 seq, int flags, u32 cmd) +{ + void *hdr; + + hdr = nl80211hdr_put(msg, pid, seq, flags, cmd); + if (!hdr) + return -1; + + NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx); + NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex); + + return genlmsg_end(msg, hdr); + + nla_put_failure: + genlmsg_cancel(msg, hdr); + return -EMSGSIZE; +} + void nl80211_send_scan_start(struct cfg80211_registered_device *rdev, struct net_device *netdev) { @@ -5709,6 +5922,43 @@ void nl80211_send_scan_aborted(struct cfg80211_registered_device *rdev, nl80211_scan_mcgrp.id, GFP_KERNEL); } +void nl80211_send_sched_scan_results(struct cfg80211_registered_device *rdev, + struct net_device *netdev) +{ + struct sk_buff *msg; + + msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); + if (!msg) + return; + + if (nl80211_send_sched_scan_msg(msg, rdev, netdev, 0, 0, 0, + NL80211_CMD_SCHED_SCAN_RESULTS) < 0) { + nlmsg_free(msg); + return; + } + + genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0, + nl80211_scan_mcgrp.id, GFP_KERNEL); +} + +void nl80211_send_sched_scan(struct cfg80211_registered_device *rdev, + struct net_device *netdev, u32 cmd) +{ + struct sk_buff *msg; + + msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL); + if (!msg) + return; + + if (nl80211_send_sched_scan_msg(msg, rdev, netdev, 0, 0, 0, cmd) < 0) { + nlmsg_free(msg); + return; + } + + genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0, + nl80211_scan_mcgrp.id, GFP_KERNEL); +} + /* * This can happen on global regulatory changes or device specific settings * based on custom world regulatory domains. diff --git a/net/wireless/nl80211.h b/net/wireless/nl80211.h index f2af695..2f1bfb8 100644 --- a/net/wireless/nl80211.h +++ b/net/wireless/nl80211.h @@ -12,6 +12,10 @@ void nl80211_send_scan_done(struct cfg80211_registered_device *rdev, struct net_device *netdev); void nl80211_send_scan_aborted(struct cfg80211_registered_device *rdev, struct net_device *netdev); +void nl80211_send_sched_scan(struct cfg80211_registered_device *rdev, + struct net_device *netdev, u32 cmd); +void nl80211_send_sched_scan_results(struct cfg80211_registered_device *rdev, + struct net_device *netdev); void nl80211_send_reg_change_event(struct regulatory_request *request); void nl80211_send_rx_auth(struct cfg80211_registered_device *rdev, struct net_device *netdev, diff --git a/net/wireless/scan.c b/net/wireless/scan.c index 62e542a..65dfae3 100644 --- a/net/wireless/scan.c +++ b/net/wireless/scan.c @@ -93,6 +93,76 @@ void cfg80211_scan_done(struct cfg80211_scan_request *request, bool aborted) } EXPORT_SYMBOL(cfg80211_scan_done); +void __cfg80211_sched_scan_results(struct work_struct *wk) +{ + struct cfg80211_registered_device *rdev; + + rdev = container_of(wk, struct cfg80211_registered_device, + sched_scan_results_wk); + + cfg80211_lock_rdev(rdev); + + /* we don't have sched_scan_req anymore if the scan is stopping */ + if (rdev->sched_scan_req) + nl80211_send_sched_scan_results(rdev, + rdev->sched_scan_req->dev); + + cfg80211_unlock_rdev(rdev); +} + +void cfg80211_sched_scan_results(struct wiphy *wiphy) +{ + /* ignore if we're not scanning */ + if (wiphy_to_dev(wiphy)->sched_scan_req) + queue_work(cfg80211_wq, + &wiphy_to_dev(wiphy)->sched_scan_results_wk); +} +EXPORT_SYMBOL(cfg80211_sched_scan_results); + +void __cfg80211_sched_scan_stopped(struct work_struct *wk) +{ + struct cfg80211_registered_device *rdev; + + rdev = container_of(wk, struct cfg80211_registered_device, + sched_scan_stopped_wk); + + cfg80211_lock_rdev(rdev); + __cfg80211_stop_sched_scan(rdev, true); + cfg80211_unlock_rdev(rdev); +} + +void cfg80211_sched_scan_stopped(struct wiphy *wiphy) +{ + queue_work(cfg80211_wq, &wiphy_to_dev(wiphy)->sched_scan_stopped_wk); +} +EXPORT_SYMBOL(cfg80211_sched_scan_stopped); + +int __cfg80211_stop_sched_scan(struct cfg80211_registered_device *rdev, + bool driver_initiated) +{ + int err; + struct net_device *dev; + + ASSERT_RDEV_LOCK(rdev); + + if (!rdev->sched_scan_req) + return 0; + + dev = rdev->sched_scan_req->dev; + + err = rdev->ops->sched_scan_stop(&rdev->wiphy, dev, + driver_initiated); + if (err) + return err; + + nl80211_send_sched_scan(rdev, dev, NL80211_CMD_SCHED_SCAN_STOPPED); + + kfree(rdev->sched_scan_req); + rdev->sched_scan_req = NULL; + + return err; +} + static void bss_release(struct kref *ref) { struct cfg80211_internal_bss *bss; -- cgit v0.10.2 From 79f460ca49d8d5700756ab7071c951311c7f29cc Mon Sep 17 00:00:00 2001 From: Luciano Coelho Date: Wed, 11 May 2011 17:09:36 +0300 Subject: mac80211: add support for HW scheduled scan Implement support for HW scheduled scan. The mac80211 code doesn't perform scheduled scans itself, but calls the driver to start and stop scheduled scans. This patch also creates a trace event class to be used by drv_hw_scan and the new drv_sched_scan_start and drv_sched_stop functions, in order to avoid duplicate code. Signed-off-by: Luciano Coelho Signed-off-by: John W. Linville diff --git a/include/net/mac80211.h b/include/net/mac80211.h index 9e55427..62a1c22 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -537,6 +537,21 @@ struct ieee80211_tx_info { }; }; +/** + * ieee80211_sched_scan_ies - scheduled scan IEs + * + * This structure is used to pass the appropriate IEs to be used in scheduled + * scans for all bands. It contains both the IEs passed from the userspace + * and the ones generated by mac80211. + * + * @ie: array with the IEs for each supported band + * @len: array with the total length of the IEs for each band + */ +struct ieee80211_sched_scan_ies { + u8 *ie[IEEE80211_NUM_BANDS]; + size_t len[IEEE80211_NUM_BANDS]; +}; + static inline struct ieee80211_tx_info *IEEE80211_SKB_CB(struct sk_buff *skb) { return (struct ieee80211_tx_info *)skb->cb; @@ -1693,6 +1708,13 @@ enum ieee80211_ampdu_mlme_action { * any error unless this callback returned a negative error code. * The callback can sleep. * + * @sched_scan_start: Ask the hardware to start scanning repeatedly at + * specific intervals. The driver must call the + * ieee80211_sched_scan_results() function whenever it finds results. + * This process will continue until sched_scan_stop is called. + * + * @sched_scan_stop: Tell the hardware to stop an ongoing scheduled scan. + * * @sw_scan_start: Notifier function that is called just before a software scan * is started. Can be NULL, if the driver doesn't need this notification. * The callback can sleep. @@ -1877,6 +1899,12 @@ struct ieee80211_ops { u32 iv32, u16 *phase1key); int (*hw_scan)(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct cfg80211_scan_request *req); + int (*sched_scan_start)(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct cfg80211_sched_scan_request *req, + struct ieee80211_sched_scan_ies *ies); + void (*sched_scan_stop)(struct ieee80211_hw *hw, + struct ieee80211_vif *vif); void (*sw_scan_start)(struct ieee80211_hw *hw); void (*sw_scan_complete)(struct ieee80211_hw *hw); int (*get_stats)(struct ieee80211_hw *hw, @@ -2594,6 +2622,28 @@ void ieee80211_wake_queues(struct ieee80211_hw *hw); void ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted); /** + * ieee80211_sched_scan_results - got results from scheduled scan + * + * When a scheduled scan is running, this function needs to be called by the + * driver whenever there are new scan results available. + * + * @hw: the hardware that is performing scheduled scans + */ +void ieee80211_sched_scan_results(struct ieee80211_hw *hw); + +/** + * ieee80211_sched_scan_stopped - inform that the scheduled scan has stopped + * + * When a scheduled scan is running, this function can be called by + * the driver if it needs to stop the scan to perform another task. + * Usual scenarios are drivers that cannot continue the scheduled scan + * while associating, for instance. + * + * @hw: the hardware that is performing scheduled scans + */ +void ieee80211_sched_scan_stopped(struct ieee80211_hw *hw); + +/** * ieee80211_iterate_active_interfaces - iterate active interfaces * * This function iterates over the interfaces associated with a given diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index c416cce..a2ff474 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -1362,6 +1362,31 @@ static int ieee80211_scan(struct wiphy *wiphy, return ieee80211_request_scan(sdata, req); } +static int +ieee80211_sched_scan_start(struct wiphy *wiphy, + struct net_device *dev, + struct cfg80211_sched_scan_request *req) +{ + struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); + + if (!sdata->local->ops->sched_scan_start) + return -EOPNOTSUPP; + + return ieee80211_request_sched_scan_start(sdata, req); +} + +static int +ieee80211_sched_scan_stop(struct wiphy *wiphy, struct net_device *dev, + bool driver_initiated) +{ + struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); + + if (!sdata->local->ops->sched_scan_stop) + return -EOPNOTSUPP; + + return ieee80211_request_sched_scan_stop(sdata, driver_initiated); +} + static int ieee80211_auth(struct wiphy *wiphy, struct net_device *dev, struct cfg80211_auth_request *req) { @@ -2103,6 +2128,8 @@ struct cfg80211_ops mac80211_config_ops = { .suspend = ieee80211_suspend, .resume = ieee80211_resume, .scan = ieee80211_scan, + .sched_scan_start = ieee80211_sched_scan_start, + .sched_scan_stop = ieee80211_sched_scan_stop, .auth = ieee80211_auth, .assoc = ieee80211_assoc, .deauth = ieee80211_deauth, diff --git a/net/mac80211/driver-ops.h b/net/mac80211/driver-ops.h index aa16bd8..eebf7a6 100644 --- a/net/mac80211/driver-ops.h +++ b/net/mac80211/driver-ops.h @@ -212,12 +212,39 @@ static inline int drv_hw_scan(struct ieee80211_local *local, might_sleep(); - trace_drv_hw_scan(local, sdata, req); + trace_drv_hw_scan(local, sdata); ret = local->ops->hw_scan(&local->hw, &sdata->vif, req); trace_drv_return_int(local, ret); return ret; } +static inline int +drv_sched_scan_start(struct ieee80211_local *local, + struct ieee80211_sub_if_data *sdata, + struct cfg80211_sched_scan_request *req, + struct ieee80211_sched_scan_ies *ies) +{ + int ret; + + might_sleep(); + + trace_drv_sched_scan_start(local, sdata); + ret = local->ops->sched_scan_start(&local->hw, &sdata->vif, + req, ies); + trace_drv_return_int(local, ret); + return ret; +} + +static inline void drv_sched_scan_stop(struct ieee80211_local *local, + struct ieee80211_sub_if_data *sdata) +{ + might_sleep(); + + trace_drv_sched_scan_stop(local, sdata); + local->ops->sched_scan_stop(&local->hw, &sdata->vif); + trace_drv_return_void(local); +} + static inline void drv_sw_scan_start(struct ieee80211_local *local) { might_sleep(); diff --git a/net/mac80211/driver-trace.h b/net/mac80211/driver-trace.h index dd9779d..ed9edcb 100644 --- a/net/mac80211/driver-trace.h +++ b/net/mac80211/driver-trace.h @@ -98,6 +98,27 @@ DECLARE_EVENT_CLASS(local_u32_evt, ) ); +DECLARE_EVENT_CLASS(local_sdata_evt, + TP_PROTO(struct ieee80211_local *local, + struct ieee80211_sub_if_data *sdata), + TP_ARGS(local, sdata), + + TP_STRUCT__entry( + LOCAL_ENTRY + VIF_ENTRY + ), + + TP_fast_assign( + LOCAL_ASSIGN; + VIF_ASSIGN; + ), + + TP_printk( + LOCAL_PR_FMT VIF_PR_FMT, + LOCAL_PR_ARG, VIF_PR_ARG + ) +); + DEFINE_EVENT(local_only_evt, drv_return_void, TP_PROTO(struct ieee80211_local *local), TP_ARGS(local) @@ -433,27 +454,22 @@ TRACE_EVENT(drv_update_tkip_key, ) ); -TRACE_EVENT(drv_hw_scan, +DEFINE_EVENT(local_sdata_evt, drv_hw_scan, TP_PROTO(struct ieee80211_local *local, - struct ieee80211_sub_if_data *sdata, - struct cfg80211_scan_request *req), - - TP_ARGS(local, sdata, req), - - TP_STRUCT__entry( - LOCAL_ENTRY - VIF_ENTRY - ), + struct ieee80211_sub_if_data *sdata), + TP_ARGS(local, sdata) +); - TP_fast_assign( - LOCAL_ASSIGN; - VIF_ASSIGN; - ), +DEFINE_EVENT(local_sdata_evt, drv_sched_scan_start, + TP_PROTO(struct ieee80211_local *local, + struct ieee80211_sub_if_data *sdata), + TP_ARGS(local, sdata) +); - TP_printk( - LOCAL_PR_FMT VIF_PR_FMT, - LOCAL_PR_ARG,VIF_PR_ARG - ) +DEFINE_EVENT(local_sdata_evt, drv_sched_scan_stop, + TP_PROTO(struct ieee80211_local *local, + struct ieee80211_sub_if_data *sdata), + TP_ARGS(local, sdata) ); DEFINE_EVENT(local_only_evt, drv_sw_scan_start, @@ -1180,6 +1196,42 @@ TRACE_EVENT(api_scan_completed, ) ); +TRACE_EVENT(api_sched_scan_results, + TP_PROTO(struct ieee80211_local *local), + + TP_ARGS(local), + + TP_STRUCT__entry( + LOCAL_ENTRY + ), + + TP_fast_assign( + LOCAL_ASSIGN; + ), + + TP_printk( + LOCAL_PR_FMT, LOCAL_PR_ARG + ) +); + +TRACE_EVENT(api_sched_scan_stopped, + TP_PROTO(struct ieee80211_local *local), + + TP_ARGS(local), + + TP_STRUCT__entry( + LOCAL_ENTRY + ), + + TP_fast_assign( + LOCAL_ASSIGN; + ), + + TP_printk( + LOCAL_PR_FMT, LOCAL_PR_ARG + ) +); + TRACE_EVENT(api_sta_block_awake, TP_PROTO(struct ieee80211_local *local, struct ieee80211_sta *sta, bool block), diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 7f4d0dc..6f55a78 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -847,6 +847,9 @@ struct ieee80211_local { int scan_channel_idx; int scan_ies_len; + bool sched_scanning; + struct ieee80211_sched_scan_ies sched_scan_ies; + unsigned long leave_oper_channel_time; enum mac80211_scan_state next_scan_state; struct delayed_work scan_work; @@ -1154,6 +1157,12 @@ ieee80211_rx_bss_get(struct ieee80211_local *local, u8 *bssid, int freq, void ieee80211_rx_bss_put(struct ieee80211_local *local, struct ieee80211_bss *bss); +/* scheduled scan handling */ +int ieee80211_request_sched_scan_start(struct ieee80211_sub_if_data *sdata, + struct cfg80211_sched_scan_request *req); +int ieee80211_request_sched_scan_stop(struct ieee80211_sub_if_data *sdata, + bool driver_initiated); + /* off-channel helpers */ bool ieee80211_cfg_on_oper_channel(struct ieee80211_local *local); void ieee80211_offchannel_enable_all_ps(struct ieee80211_local *local, diff --git a/net/mac80211/main.c b/net/mac80211/main.c index ab1f464..30e6a68 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c @@ -358,7 +358,8 @@ static void ieee80211_restart_work(struct work_struct *work) flush_workqueue(local->workqueue); mutex_lock(&local->mtx); - WARN(test_bit(SCAN_HW_SCANNING, &local->scanning), + WARN(test_bit(SCAN_HW_SCANNING, &local->scanning) || + local->sched_scanning, "%s called with hardware scan in progress\n", __func__); mutex_unlock(&local->mtx); @@ -833,6 +834,9 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) if (!local->ops->remain_on_channel) local->hw.wiphy->max_remain_on_channel_duration = 5000; + if (local->ops->sched_scan_start) + local->hw.wiphy->flags |= WIPHY_FLAG_SUPPORTS_SCHED_SCAN; + result = wiphy_register(local->hw.wiphy); if (result < 0) goto fail_wiphy_register; diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index 634f3d9..1b9413f 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -404,11 +404,13 @@ ieee80211_rx_h_passive_scan(struct ieee80211_rx_data *rx) struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(rx->skb); struct sk_buff *skb = rx->skb; - if (likely(!(status->rx_flags & IEEE80211_RX_IN_SCAN))) + if (likely(!(status->rx_flags & IEEE80211_RX_IN_SCAN) && + !local->sched_scanning)) return RX_CONTINUE; if (test_bit(SCAN_HW_SCANNING, &local->scanning) || - test_bit(SCAN_SW_SCANNING, &local->scanning)) + test_bit(SCAN_SW_SCANNING, &local->scanning) || + local->sched_scanning) return ieee80211_scan_rx(rx->sdata, skb); /* scanning finished during invoking of handlers */ diff --git a/net/mac80211/scan.c b/net/mac80211/scan.c index 8acce72..ea44a8e 100644 --- a/net/mac80211/scan.c +++ b/net/mac80211/scan.c @@ -15,6 +15,7 @@ #include #include #include +#include #include #include #include @@ -850,3 +851,101 @@ void ieee80211_scan_cancel(struct ieee80211_local *local) } mutex_unlock(&local->mtx); } + +int ieee80211_request_sched_scan_start(struct ieee80211_sub_if_data *sdata, + struct cfg80211_sched_scan_request *req) +{ + struct ieee80211_local *local = sdata->local; + int ret, i; + + mutex_lock(&sdata->local->mtx); + + if (local->sched_scanning) { + ret = -EBUSY; + goto out; + } + + if (!local->ops->sched_scan_start) { + ret = -ENOTSUPP; + goto out; + } + + for (i = 0; i < IEEE80211_NUM_BANDS; i++) { + local->sched_scan_ies.ie[i] = kzalloc(2 + + IEEE80211_MAX_SSID_LEN + + local->scan_ies_len, + GFP_KERNEL); + if (!local->sched_scan_ies.ie[i]) { + ret = -ENOMEM; + goto out_free; + } + + local->sched_scan_ies.len[i] = + ieee80211_build_preq_ies(local, + local->sched_scan_ies.ie[i], + req->ie, req->ie_len, i, + (u32) -1, 0); + } + + ret = drv_sched_scan_start(local, sdata, req, + &local->sched_scan_ies); + if (ret == 0) { + local->sched_scanning = true; + goto out; + } + +out_free: + while (i > 0) + kfree(local->sched_scan_ies.ie[--i]); +out: + mutex_unlock(&sdata->local->mtx); + return ret; +} + +int ieee80211_request_sched_scan_stop(struct ieee80211_sub_if_data *sdata, + bool driver_initiated) +{ + struct ieee80211_local *local = sdata->local; + int ret = 0, i; + + mutex_lock(&sdata->local->mtx); + + if (!local->ops->sched_scan_stop) { + ret = -ENOTSUPP; + goto out; + } + + if (local->sched_scanning) { + for (i = 0; i < IEEE80211_NUM_BANDS; i++) + kfree(local->sched_scan_ies.ie[i]); + + if (!driver_initiated) + drv_sched_scan_stop(local, sdata); + local->sched_scanning = false; + } + +out: + mutex_unlock(&sdata->local->mtx); + + return ret; +} + +void ieee80211_sched_scan_results(struct ieee80211_hw *hw) +{ + struct ieee80211_local *local = hw_to_local(hw); + + trace_api_sched_scan_results(local); + + cfg80211_sched_scan_results(hw->wiphy); +} +EXPORT_SYMBOL(ieee80211_sched_scan_results); + +void ieee80211_sched_scan_stopped(struct ieee80211_hw *hw) +{ + struct ieee80211_local *local = hw_to_local(hw); + + trace_api_sched_scan_stopped(local); + + cfg80211_sched_scan_stopped(hw->wiphy); +} +EXPORT_SYMBOL(ieee80211_sched_scan_stopped); -- cgit v0.10.2 From bbe6ad6dcb1eb26bd12ec85320f402721c3383ae Mon Sep 17 00:00:00 2001 From: Luciano Coelho Date: Wed, 11 May 2011 17:09:37 +0300 Subject: cfg80211/nl80211: add interval attribute for scheduled scans Introduce NL80211_ATTR_SCHED_SCAN_INTERVAL as a required attribute for NL80211_CMD_START_SCHED_SCAN. This value informs the driver at which intervals the scheduled scan cycles should be executed. Signed-off-by: Luciano Coelho Signed-off-by: John W. Linville diff --git a/include/linux/nl80211.h b/include/linux/nl80211.h index f8b5595..281a2bb 100644 --- a/include/linux/nl80211.h +++ b/include/linux/nl80211.h @@ -203,15 +203,17 @@ * @NL80211_CMD_SCAN_ABORTED: scan was aborted, for unspecified reasons, * partial scan results may be available * - * @NL80211_CMD_START_SCHED_SCAN: start a scheduled scan. Like with normal - * scans, if SSIDs (%NL80211_ATTR_SCAN_SSIDS) are passed, they are used - * in the probe requests. For broadcast, a broadcast SSID must be - * passed (ie. an empty string). If no SSID is passed, no probe - * requests are sent and a passive scan is performed. - * %NL80211_ATTR_SCAN_FREQUENCIES, if passed, define which channels - * should be scanned; if not passed, all channels allowed for the - * current regulatory domain are used. Extra IEs can also be passed - * from the userspace by using the %NL80211_ATTR_IE attribute. + * @NL80211_CMD_START_SCHED_SCAN: start a scheduled scan at certain + * intervals, as specified by %NL80211_ATTR_SCHED_SCAN_INTERVAL. + * Like with normal scans, if SSIDs (%NL80211_ATTR_SCAN_SSIDS) + * are passed, they are used in the probe requests. For + * broadcast, a broadcast SSID must be passed (ie. an empty + * string). If no SSID is passed, no probe requests are sent and + * a passive scan is performed. %NL80211_ATTR_SCAN_FREQUENCIES, + * if passed, define which channels should be scanned; if not + * passed, all channels allowed for the current regulatory domain + * are used. Extra IEs can also be passed from the userspace by + * using the %NL80211_ATTR_IE attribute. * @NL80211_CMD_STOP_SCHED_SCAN: stop a scheduled scan * @NL80211_CMD_SCHED_SCAN_RESULTS: indicates that there are scheduled scan * results available. @@ -948,6 +950,9 @@ enum nl80211_commands { * indicate which WoW triggers should be enabled. This is also * used by %NL80211_CMD_GET_WOWLAN to get the currently enabled WoWLAN * triggers. + + * @NL80211_ATTR_SCHED_SCAN_INTERVAL: Interval between scheduled scan + * cycles, in msecs. * * @NL80211_ATTR_MAX: highest attribute number currently defined * @__NL80211_ATTR_AFTER_LAST: internal use @@ -1142,6 +1147,8 @@ enum nl80211_attrs { NL80211_ATTR_WOWLAN_TRIGGERS, NL80211_ATTR_WOWLAN_TRIGGERS_SUPPORTED, + NL80211_ATTR_SCHED_SCAN_INTERVAL, + /* add attributes here, update the policy in nl80211.c */ __NL80211_ATTR_AFTER_LAST, diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index e214c85..1f1e221 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -829,6 +829,7 @@ struct cfg80211_scan_request { * @ssids: SSIDs to scan for (passed in the probe_reqs in active scans) * @n_ssids: number of SSIDs * @n_channels: total number of channels to scan + * @interval: interval between each scheduled scan cycle * @ie: optional information element(s) to add into Probe Request or %NULL * @ie_len: length of ie in octets * @wiphy: the wiphy this was for @@ -839,6 +840,7 @@ struct cfg80211_sched_scan_request { struct cfg80211_ssid *ssids; int n_ssids; u32 n_channels; + u32 interval; const u8 *ie; size_t ie_len; diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 4fac370..b5b050b 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -175,6 +175,7 @@ static const struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] = { [NL80211_ATTR_KEY_DEFAULT_TYPES] = { .type = NLA_NESTED }, [NL80211_ATTR_WOWLAN_TRIGGERS] = { .type = NLA_NESTED }, [NL80211_ATTR_STA_PLINK_STATE] = { .type = NLA_U8 }, + [NL80211_ATTR_SCHED_SCAN_INTERVAL] = { .type = NLA_U32 }, }; /* policy for the key attributes */ @@ -3370,6 +3371,7 @@ static int nl80211_start_sched_scan(struct sk_buff *skb, struct nlattr *attr; struct wiphy *wiphy; int err, tmp, n_ssids = 0, n_channels, i; + u32 interval; enum ieee80211_band band; size_t ie_len; @@ -3383,6 +3385,13 @@ static int nl80211_start_sched_scan(struct sk_buff *skb, if (rdev->sched_scan_req) return -EINPROGRESS; + if (!info->attrs[NL80211_ATTR_SCHED_SCAN_INTERVAL]) + return -EINVAL; + + interval = nla_get_u32(info->attrs[NL80211_ATTR_SCHED_SCAN_INTERVAL]); + if (interval == 0) + return -EINVAL; + wiphy = &rdev->wiphy; if (info->attrs[NL80211_ATTR_SCAN_FREQUENCIES]) { @@ -3505,6 +3514,7 @@ static int nl80211_start_sched_scan(struct sk_buff *skb, request->dev = dev; request->wiphy = &rdev->wiphy; + request->interval = interval; err = rdev->ops->sched_scan_start(&rdev->wiphy, dev, request); if (!err) { -- cgit v0.10.2 From f25f4f522a9d2e18595da9df0bf1b6f282040e08 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Tue, 26 Apr 2011 19:14:35 +0200 Subject: PM / AVR32: Use struct syscore_ops instead of sysdevs for PM Convert some AVR32 architecture's code to using struct syscore_ops objects for power management instead of sysdev classes and sysdevs. This simplifies the code and reduces the kernel's memory footprint. It also is necessary for removing sysdevs from the kernel entirely in the future. Signed-off-by: Rafael J. Wysocki Acked-by: Greg Kroah-Hartman Acked-by: Hans-Christian Egtvedt diff --git a/arch/avr32/mach-at32ap/intc.c b/arch/avr32/mach-at32ap/intc.c index 21ce35f..3e36461 100644 --- a/arch/avr32/mach-at32ap/intc.c +++ b/arch/avr32/mach-at32ap/intc.c @@ -12,7 +12,7 @@ #include #include #include -#include +#include #include @@ -21,7 +21,6 @@ struct intc { void __iomem *regs; struct irq_chip chip; - struct sys_device sysdev; #ifdef CONFIG_PM unsigned long suspend_ipr; unsigned long saved_ipr[64]; @@ -146,9 +145,8 @@ void intc_set_suspend_handler(unsigned long offset) intc0.suspend_ipr = offset; } -static int intc_suspend(struct sys_device *sdev, pm_message_t state) +static int intc_suspend(void) { - struct intc *intc = container_of(sdev, struct intc, sysdev); int i; if (unlikely(!irqs_disabled())) { @@ -156,28 +154,25 @@ static int intc_suspend(struct sys_device *sdev, pm_message_t state) return -EINVAL; } - if (unlikely(!intc->suspend_ipr)) { + if (unlikely(!intc0.suspend_ipr)) { pr_err("intc_suspend: suspend_ipr not initialized\n"); return -EINVAL; } for (i = 0; i < 64; i++) { - intc->saved_ipr[i] = intc_readl(intc, INTPR0 + 4 * i); - intc_writel(intc, INTPR0 + 4 * i, intc->suspend_ipr); + intc0.saved_ipr[i] = intc_readl(&intc0, INTPR0 + 4 * i); + intc_writel(&intc0, INTPR0 + 4 * i, intc0.suspend_ipr); } return 0; } -static int intc_resume(struct sys_device *sdev) +static int intc_resume(void) { - struct intc *intc = container_of(sdev, struct intc, sysdev); int i; - WARN_ON(!irqs_disabled()); - for (i = 0; i < 64; i++) - intc_writel(intc, INTPR0 + 4 * i, intc->saved_ipr[i]); + intc_writel(&intc0, INTPR0 + 4 * i, intc0.saved_ipr[i]); return 0; } @@ -186,27 +181,18 @@ static int intc_resume(struct sys_device *sdev) #define intc_resume NULL #endif -static struct sysdev_class intc_class = { - .name = "intc", +static struct syscore_ops intc_syscore_ops = { .suspend = intc_suspend, .resume = intc_resume, }; -static int __init intc_init_sysdev(void) +static int __init intc_init_syscore(void) { - int ret; - - ret = sysdev_class_register(&intc_class); - if (ret) - return ret; + register_syscore_ops(&intc_syscore_ops); - intc0.sysdev.id = 0; - intc0.sysdev.cls = &intc_class; - ret = sysdev_register(&intc0.sysdev); - - return ret; + return 0; } -device_initcall(intc_init_sysdev); +device_initcall(intc_init_syscore); unsigned long intc_get_pending(unsigned int group) { -- cgit v0.10.2 From f98bf4aa39ecce96020631cba910be094c87ac3c Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Tue, 26 Apr 2011 19:14:47 +0200 Subject: PM / UNICORE32: Use struct syscore_ops instead of sysdevs for PM Make some UNICORE32 architecture's code use struct syscore_ops objects for power management instead of sysdev classes and sysdevs. This simplifies the code and reduces the kernel's memory footprint. It also is necessary for removing sysdevs from the kernel entirely in the future. Signed-off-by: Rafael J. Wysocki Acked-by: Greg Kroah-Hartman Acked-by: Guan Xuetao diff --git a/arch/unicore32/kernel/irq.c b/arch/unicore32/kernel/irq.c index 2aa30a3..d4efa7d 100644 --- a/arch/unicore32/kernel/irq.c +++ b/arch/unicore32/kernel/irq.c @@ -23,7 +23,7 @@ #include #include #include -#include +#include #include #include @@ -237,7 +237,7 @@ static struct puv3_irq_state { unsigned int iccr; } puv3_irq_state; -static int puv3_irq_suspend(struct sys_device *dev, pm_message_t state) +static int puv3_irq_suspend(void) { struct puv3_irq_state *st = &puv3_irq_state; @@ -265,7 +265,7 @@ static int puv3_irq_suspend(struct sys_device *dev, pm_message_t state) return 0; } -static int puv3_irq_resume(struct sys_device *dev) +static void puv3_irq_resume(void) { struct puv3_irq_state *st = &puv3_irq_state; @@ -278,27 +278,20 @@ static int puv3_irq_resume(struct sys_device *dev) writel(st->icmr, INTC_ICMR); } - return 0; } -static struct sysdev_class puv3_irq_sysclass = { - .name = "pkunity-irq", +static struct syscore_ops puv3_irq_syscore_ops = { .suspend = puv3_irq_suspend, .resume = puv3_irq_resume, }; -static struct sys_device puv3_irq_device = { - .id = 0, - .cls = &puv3_irq_sysclass, -}; - -static int __init puv3_irq_init_devicefs(void) +static int __init puv3_irq_init_syscore(void) { - sysdev_class_register(&puv3_irq_sysclass); - return sysdev_register(&puv3_irq_device); + register_syscore_ops(&puv3_irq_syscore_ops); + return 0; } -device_initcall(puv3_irq_init_devicefs); +device_initcall(puv3_irq_init_syscore); void __init init_IRQ(void) { -- cgit v0.10.2 From f5a592f7d74e38c5007876c731e6bf5580072e63 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Tue, 26 Apr 2011 19:14:57 +0200 Subject: PM / PowerPC: Use struct syscore_ops instead of sysdevs for PM Make some PowerPC architecture's code use struct syscore_ops objects for power management instead of sysdev classes and sysdevs. This simplifies the code and reduces the kernel's memory footprint. It also is necessary for removing sysdevs from the kernel entirely in the future. Signed-off-by: Rafael J. Wysocki Acked-by: Greg Kroah-Hartman diff --git a/arch/powerpc/include/asm/mpic.h b/arch/powerpc/include/asm/mpic.h index 7005ee0..49baddc 100644 --- a/arch/powerpc/include/asm/mpic.h +++ b/arch/powerpc/include/asm/mpic.h @@ -3,7 +3,6 @@ #ifdef __KERNEL__ #include -#include #include #include @@ -320,8 +319,6 @@ struct mpic /* link */ struct mpic *next; - struct sys_device sysdev; - #ifdef CONFIG_PM struct mpic_irq_save *save_data; #endif diff --git a/arch/powerpc/platforms/cell/spu_base.c b/arch/powerpc/platforms/cell/spu_base.c index acfacce..3675da7 100644 --- a/arch/powerpc/platforms/cell/spu_base.c +++ b/arch/powerpc/platforms/cell/spu_base.c @@ -32,6 +32,7 @@ #include #include #include +#include #include #include #include @@ -521,18 +522,8 @@ void spu_init_channels(struct spu *spu) } EXPORT_SYMBOL_GPL(spu_init_channels); -static int spu_shutdown(struct sys_device *sysdev) -{ - struct spu *spu = container_of(sysdev, struct spu, sysdev); - - spu_free_irqs(spu); - spu_destroy_spu(spu); - return 0; -} - static struct sysdev_class spu_sysdev_class = { .name = "spu", - .shutdown = spu_shutdown, }; int spu_add_sysdev_attr(struct sysdev_attribute *attr) @@ -797,6 +788,22 @@ static inline void crash_register_spus(struct list_head *list) } #endif +static void spu_shutdown(void) +{ + struct spu *spu; + + mutex_lock(&spu_full_list_mutex); + list_for_each_entry(spu, &spu_full_list, full_list) { + spu_free_irqs(spu); + spu_destroy_spu(spu); + } + mutex_unlock(&spu_full_list_mutex); +} + +static struct syscore_ops spu_syscore_ops = { + .shutdown = spu_shutdown, +}; + static int __init init_spu_base(void) { int i, ret = 0; @@ -830,6 +837,7 @@ static int __init init_spu_base(void) crash_register_spus(&spu_full_list); mutex_unlock(&spu_full_list_mutex); spu_add_sysdev_attr(&attr_stat); + register_syscore_ops(&spu_syscore_ops); spu_init_affinity(); diff --git a/arch/powerpc/platforms/powermac/pic.c b/arch/powerpc/platforms/powermac/pic.c index 023f240..7c18a16 100644 --- a/arch/powerpc/platforms/powermac/pic.c +++ b/arch/powerpc/platforms/powermac/pic.c @@ -21,7 +21,7 @@ #include #include #include -#include +#include #include #include #include @@ -677,7 +677,7 @@ not_found: return viaint; } -static int pmacpic_suspend(struct sys_device *sysdev, pm_message_t state) +static int pmacpic_suspend(void) { int viaint = pmacpic_find_viaint(); @@ -698,7 +698,7 @@ static int pmacpic_suspend(struct sys_device *sysdev, pm_message_t state) return 0; } -static int pmacpic_resume(struct sys_device *sysdev) +static void pmacpic_resume(void) { int i; @@ -709,39 +709,19 @@ static int pmacpic_resume(struct sys_device *sysdev) for (i = 0; i < max_real_irqs; ++i) if (test_bit(i, sleep_save_mask)) pmac_unmask_irq(irq_get_irq_data(i)); - - return 0; } -#endif /* CONFIG_PM && CONFIG_PPC32 */ - -static struct sysdev_class pmacpic_sysclass = { - .name = "pmac_pic", +static struct syscore_ops pmacpic_syscore_ops = { + .suspend = pmacpic_suspend, + .resume = pmacpic_resume, }; -static struct sys_device device_pmacpic = { - .id = 0, - .cls = &pmacpic_sysclass, -}; - -static struct sysdev_driver driver_pmacpic = { -#if defined(CONFIG_PM) && defined(CONFIG_PPC32) - .suspend = &pmacpic_suspend, - .resume = &pmacpic_resume, -#endif /* CONFIG_PM && CONFIG_PPC32 */ -}; - -static int __init init_pmacpic_sysfs(void) +static int __init init_pmacpic_syscore(void) { -#ifdef CONFIG_PPC32 - if (max_irqs == 0) - return -ENODEV; -#endif - printk(KERN_DEBUG "Registering pmac pic with sysfs...\n"); - sysdev_class_register(&pmacpic_sysclass); - sysdev_register(&device_pmacpic); - sysdev_driver_register(&pmacpic_sysclass, &driver_pmacpic); + register_syscore_ops(&pmacpic_syscore_ops); return 0; } -machine_subsys_initcall(powermac, init_pmacpic_sysfs); +machine_subsys_initcall(powermac, init_pmacpic_syscore); + +#endif /* CONFIG_PM && CONFIG_PPC32 */ diff --git a/arch/powerpc/sysdev/ipic.c b/arch/powerpc/sysdev/ipic.c index fa438be..596554a 100644 --- a/arch/powerpc/sysdev/ipic.c +++ b/arch/powerpc/sysdev/ipic.c @@ -18,7 +18,7 @@ #include #include #include -#include +#include #include #include #include @@ -902,7 +902,7 @@ static struct { u32 sercr; } ipic_saved_state; -static int ipic_suspend(struct sys_device *sdev, pm_message_t state) +static int ipic_suspend(void) { struct ipic *ipic = primary_ipic; @@ -933,7 +933,7 @@ static int ipic_suspend(struct sys_device *sdev, pm_message_t state) return 0; } -static int ipic_resume(struct sys_device *sdev) +static void ipic_resume(void) { struct ipic *ipic = primary_ipic; @@ -949,44 +949,26 @@ static int ipic_resume(struct sys_device *sdev) ipic_write(ipic->regs, IPIC_SECNR, ipic_saved_state.secnr); ipic_write(ipic->regs, IPIC_SERMR, ipic_saved_state.sermr); ipic_write(ipic->regs, IPIC_SERCR, ipic_saved_state.sercr); - - return 0; } #else #define ipic_suspend NULL #define ipic_resume NULL #endif -static struct sysdev_class ipic_sysclass = { - .name = "ipic", +static struct syscore_ops ipic_syscore_ops = { .suspend = ipic_suspend, .resume = ipic_resume, }; -static struct sys_device device_ipic = { - .id = 0, - .cls = &ipic_sysclass, -}; - -static int __init init_ipic_sysfs(void) +static int __init init_ipic_syscore(void) { - int rc; - if (!primary_ipic || !primary_ipic->regs) return -ENODEV; - printk(KERN_DEBUG "Registering ipic with sysfs...\n"); - rc = sysdev_class_register(&ipic_sysclass); - if (rc) { - printk(KERN_ERR "Failed registering ipic sys class\n"); - return -ENODEV; - } - rc = sysdev_register(&device_ipic); - if (rc) { - printk(KERN_ERR "Failed registering ipic sys device\n"); - return -ENODEV; - } + printk(KERN_DEBUG "Registering ipic system core operations\n"); + register_syscore_ops(&ipic_syscore_ops); + return 0; } -subsys_initcall(init_ipic_sysfs); +subsys_initcall(init_ipic_syscore); diff --git a/arch/powerpc/sysdev/mpic.c b/arch/powerpc/sysdev/mpic.c index f91c065..7e5dc8f 100644 --- a/arch/powerpc/sysdev/mpic.c +++ b/arch/powerpc/sysdev/mpic.c @@ -27,6 +27,7 @@ #include #include #include +#include #include #include @@ -1702,9 +1703,8 @@ void mpic_reset_core(int cpu) #endif /* CONFIG_SMP */ #ifdef CONFIG_PM -static int mpic_suspend(struct sys_device *dev, pm_message_t state) +static void mpic_suspend_one(struct mpic *mpic) { - struct mpic *mpic = container_of(dev, struct mpic, sysdev); int i; for (i = 0; i < mpic->num_sources; i++) { @@ -1713,13 +1713,22 @@ static int mpic_suspend(struct sys_device *dev, pm_message_t state) mpic->save_data[i].dest = mpic_irq_read(i, MPIC_INFO(IRQ_DESTINATION)); } +} + +static int mpic_suspend(void) +{ + struct mpic *mpic = mpics; + + while (mpic) { + mpic_suspend_one(mpic); + mpic = mpic->next; + } return 0; } -static int mpic_resume(struct sys_device *dev) +static void mpic_resume_one(struct mpic *mpic) { - struct mpic *mpic = container_of(dev, struct mpic, sysdev); int i; for (i = 0; i < mpic->num_sources; i++) { @@ -1746,33 +1755,28 @@ static int mpic_resume(struct sys_device *dev) } #endif } /* end for loop */ +} - return 0; +static void mpic_resume(void) +{ + struct mpic *mpic = mpics; + + while (mpic) { + mpic_resume_one(mpic); + mpic = mpic->next; + } } -#endif -static struct sysdev_class mpic_sysclass = { -#ifdef CONFIG_PM +static struct syscore_ops mpic_syscore_ops = { .resume = mpic_resume, .suspend = mpic_suspend, -#endif - .name = "mpic", }; static int mpic_init_sys(void) { - struct mpic *mpic = mpics; - int error, id = 0; - - error = sysdev_class_register(&mpic_sysclass); - - while (mpic && !error) { - mpic->sysdev.cls = &mpic_sysclass; - mpic->sysdev.id = id++; - error = sysdev_register(&mpic->sysdev); - mpic = mpic->next; - } - return error; + register_syscore_ops(&mpic_syscore_ops); + return 0; } device_initcall(mpic_init_sys); +#endif -- cgit v0.10.2 From 2e711c04dbbf7a7732a3f7073b1fc285d12b369d Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Tue, 26 Apr 2011 19:15:07 +0200 Subject: PM: Remove sysdev suspend, resume and shutdown operations Since suspend, resume and shutdown operations in struct sysdev_class and struct sysdev_driver are not used any more, remove them. Also drop sysdev_suspend(), sysdev_resume() and sysdev_shutdown() used for executing those operations and modify all of their users accordingly. This reduces kernel code size quite a bit and reduces its complexity. Signed-off-by: Rafael J. Wysocki Acked-by: Greg Kroah-Hartman diff --git a/arch/sh/Kconfig b/arch/sh/Kconfig index 4b89da2..bc439de 100644 --- a/arch/sh/Kconfig +++ b/arch/sh/Kconfig @@ -24,7 +24,6 @@ config SUPERH select RTC_LIB select GENERIC_ATOMIC64 select GENERIC_IRQ_SHOW - select ARCH_NO_SYSDEV_OPS help The SuperH is a RISC processor targeted for use in embedded systems and consumer electronics; it was also used in the Sega Dreamcast diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig index cc6c53a..140e254 100644 --- a/arch/x86/Kconfig +++ b/arch/x86/Kconfig @@ -71,7 +71,6 @@ config X86 select GENERIC_IRQ_SHOW select IRQ_FORCED_THREADING select USE_GENERIC_SMP_HELPERS if SMP - select ARCH_NO_SYSDEV_OPS config INSTRUCTION_DECODER def_bool (KPROBES || PERF_EVENTS) diff --git a/arch/x86/kernel/apm_32.c b/arch/x86/kernel/apm_32.c index adee12e..3bfa022 100644 --- a/arch/x86/kernel/apm_32.c +++ b/arch/x86/kernel/apm_32.c @@ -1238,7 +1238,6 @@ static int suspend(int vetoable) dpm_suspend_noirq(PMSG_SUSPEND); local_irq_disable(); - sysdev_suspend(PMSG_SUSPEND); syscore_suspend(); local_irq_enable(); @@ -1258,7 +1257,6 @@ static int suspend(int vetoable) err = (err == APM_SUCCESS) ? 0 : -EIO; syscore_resume(); - sysdev_resume(); local_irq_enable(); dpm_resume_noirq(PMSG_RESUME); @@ -1282,7 +1280,6 @@ static void standby(void) dpm_suspend_noirq(PMSG_SUSPEND); local_irq_disable(); - sysdev_suspend(PMSG_SUSPEND); syscore_suspend(); local_irq_enable(); @@ -1292,7 +1289,6 @@ static void standby(void) local_irq_disable(); syscore_resume(); - sysdev_resume(); local_irq_enable(); dpm_resume_noirq(PMSG_RESUME); diff --git a/drivers/base/Kconfig b/drivers/base/Kconfig index e9e5238..d57e8d0 100644 --- a/drivers/base/Kconfig +++ b/drivers/base/Kconfig @@ -168,11 +168,4 @@ config SYS_HYPERVISOR bool default n -config ARCH_NO_SYSDEV_OPS - bool - ---help--- - To be selected by architectures that don't use sysdev class or - sysdev driver power management (suspend/resume) and shutdown - operations. - endmenu diff --git a/drivers/base/base.h b/drivers/base/base.h index 19f49e4..a34dca0 100644 --- a/drivers/base/base.h +++ b/drivers/base/base.h @@ -111,8 +111,6 @@ static inline int driver_match_device(struct device_driver *drv, return drv->bus->match ? drv->bus->match(dev, drv) : 1; } -extern void sysdev_shutdown(void); - extern char *make_class_name(const char *name, struct kobject *kobj); extern int devres_release_all(struct device *dev); diff --git a/drivers/base/sys.c b/drivers/base/sys.c index acde9b5..9dff77b 100644 --- a/drivers/base/sys.c +++ b/drivers/base/sys.c @@ -328,203 +328,8 @@ void sysdev_unregister(struct sys_device *sysdev) kobject_put(&sysdev->kobj); } - -#ifndef CONFIG_ARCH_NO_SYSDEV_OPS -/** - * sysdev_shutdown - Shut down all system devices. - * - * Loop over each class of system devices, and the devices in each - * of those classes. For each device, we call the shutdown method for - * each driver registered for the device - the auxiliaries, - * and the class driver. - * - * Note: The list is iterated in reverse order, so that we shut down - * child devices before we shut down their parents. The list ordering - * is guaranteed by virtue of the fact that child devices are registered - * after their parents. - */ -void sysdev_shutdown(void) -{ - struct sysdev_class *cls; - - pr_debug("Shutting Down System Devices\n"); - - mutex_lock(&sysdev_drivers_lock); - list_for_each_entry_reverse(cls, &system_kset->list, kset.kobj.entry) { - struct sys_device *sysdev; - - pr_debug("Shutting down type '%s':\n", - kobject_name(&cls->kset.kobj)); - - list_for_each_entry(sysdev, &cls->kset.list, kobj.entry) { - struct sysdev_driver *drv; - pr_debug(" %s\n", kobject_name(&sysdev->kobj)); - - /* Call auxiliary drivers first */ - list_for_each_entry(drv, &cls->drivers, entry) { - if (drv->shutdown) - drv->shutdown(sysdev); - } - - /* Now call the generic one */ - if (cls->shutdown) - cls->shutdown(sysdev); - } - } - mutex_unlock(&sysdev_drivers_lock); -} - -static void __sysdev_resume(struct sys_device *dev) -{ - struct sysdev_class *cls = dev->cls; - struct sysdev_driver *drv; - - /* First, call the class-specific one */ - if (cls->resume) - cls->resume(dev); - WARN_ONCE(!irqs_disabled(), - "Interrupts enabled after %pF\n", cls->resume); - - /* Call auxiliary drivers next. */ - list_for_each_entry(drv, &cls->drivers, entry) { - if (drv->resume) - drv->resume(dev); - WARN_ONCE(!irqs_disabled(), - "Interrupts enabled after %pF\n", drv->resume); - } -} - -/** - * sysdev_suspend - Suspend all system devices. - * @state: Power state to enter. - * - * We perform an almost identical operation as sysdev_shutdown() - * above, though calling ->suspend() instead. Interrupts are disabled - * when this called. Devices are responsible for both saving state and - * quiescing or powering down the device. - * - * This is only called by the device PM core, so we let them handle - * all synchronization. - */ -int sysdev_suspend(pm_message_t state) -{ - struct sysdev_class *cls; - struct sys_device *sysdev, *err_dev; - struct sysdev_driver *drv, *err_drv; - int ret; - - pr_debug("Checking wake-up interrupts\n"); - - /* Return error code if there are any wake-up interrupts pending */ - ret = check_wakeup_irqs(); - if (ret) - return ret; - - WARN_ONCE(!irqs_disabled(), - "Interrupts enabled while suspending system devices\n"); - - pr_debug("Suspending System Devices\n"); - - list_for_each_entry_reverse(cls, &system_kset->list, kset.kobj.entry) { - pr_debug("Suspending type '%s':\n", - kobject_name(&cls->kset.kobj)); - - list_for_each_entry(sysdev, &cls->kset.list, kobj.entry) { - pr_debug(" %s\n", kobject_name(&sysdev->kobj)); - - /* Call auxiliary drivers first */ - list_for_each_entry(drv, &cls->drivers, entry) { - if (drv->suspend) { - ret = drv->suspend(sysdev, state); - if (ret) - goto aux_driver; - } - WARN_ONCE(!irqs_disabled(), - "Interrupts enabled after %pF\n", - drv->suspend); - } - - /* Now call the generic one */ - if (cls->suspend) { - ret = cls->suspend(sysdev, state); - if (ret) - goto cls_driver; - WARN_ONCE(!irqs_disabled(), - "Interrupts enabled after %pF\n", - cls->suspend); - } - } - } - return 0; - /* resume current sysdev */ -cls_driver: - drv = NULL; - printk(KERN_ERR "Class suspend failed for %s: %d\n", - kobject_name(&sysdev->kobj), ret); - -aux_driver: - if (drv) - printk(KERN_ERR "Class driver suspend failed for %s: %d\n", - kobject_name(&sysdev->kobj), ret); - list_for_each_entry(err_drv, &cls->drivers, entry) { - if (err_drv == drv) - break; - if (err_drv->resume) - err_drv->resume(sysdev); - } - - /* resume other sysdevs in current class */ - list_for_each_entry(err_dev, &cls->kset.list, kobj.entry) { - if (err_dev == sysdev) - break; - pr_debug(" %s\n", kobject_name(&err_dev->kobj)); - __sysdev_resume(err_dev); - } - - /* resume other classes */ - list_for_each_entry_continue(cls, &system_kset->list, kset.kobj.entry) { - list_for_each_entry(err_dev, &cls->kset.list, kobj.entry) { - pr_debug(" %s\n", kobject_name(&err_dev->kobj)); - __sysdev_resume(err_dev); - } - } - return ret; -} -EXPORT_SYMBOL_GPL(sysdev_suspend); - -/** - * sysdev_resume - Bring system devices back to life. - * - * Similar to sysdev_suspend(), but we iterate the list forwards - * to guarantee that parent devices are resumed before their children. - * - * Note: Interrupts are disabled when called. - */ -int sysdev_resume(void) -{ - struct sysdev_class *cls; - - WARN_ONCE(!irqs_disabled(), - "Interrupts enabled while resuming system devices\n"); - - pr_debug("Resuming System Devices\n"); - - list_for_each_entry(cls, &system_kset->list, kset.kobj.entry) { - struct sys_device *sysdev; - - pr_debug("Resuming type '%s':\n", - kobject_name(&cls->kset.kobj)); - - list_for_each_entry(sysdev, &cls->kset.list, kobj.entry) { - pr_debug(" %s\n", kobject_name(&sysdev->kobj)); - - __sysdev_resume(sysdev); - } - } - return 0; -} -EXPORT_SYMBOL_GPL(sysdev_resume); -#endif /* CONFIG_ARCH_NO_SYSDEV_OPS */ +EXPORT_SYMBOL_GPL(sysdev_register); +EXPORT_SYMBOL_GPL(sysdev_unregister); int __init system_bus_init(void) { @@ -534,9 +339,6 @@ int __init system_bus_init(void) return 0; } -EXPORT_SYMBOL_GPL(sysdev_register); -EXPORT_SYMBOL_GPL(sysdev_unregister); - #define to_ext_attr(x) container_of(x, struct sysdev_ext_attribute, attr) ssize_t sysdev_store_ulong(struct sys_device *sysdev, diff --git a/drivers/xen/manage.c b/drivers/xen/manage.c index a2eee57..0b5366b 100644 --- a/drivers/xen/manage.c +++ b/drivers/xen/manage.c @@ -70,12 +70,7 @@ static int xen_suspend(void *data) BUG_ON(!irqs_disabled()); - err = sysdev_suspend(PMSG_FREEZE); - if (!err) { - err = syscore_suspend(); - if (err) - sysdev_resume(); - } + err = syscore_suspend(); if (err) { printk(KERN_ERR "xen_suspend: system core suspend failed: %d\n", err); @@ -102,7 +97,6 @@ static int xen_suspend(void *data) } syscore_resume(); - sysdev_resume(); return 0; } diff --git a/include/linux/device.h b/include/linux/device.h index ab8dfc0..ea9db9b 100644 --- a/include/linux/device.h +++ b/include/linux/device.h @@ -633,13 +633,6 @@ static inline int devtmpfs_mount(const char *mountpoint) { return 0; } /* drivers/base/power/shutdown.c */ extern void device_shutdown(void); -#ifndef CONFIG_ARCH_NO_SYSDEV_OPS -/* drivers/base/sys.c */ -extern void sysdev_shutdown(void); -#else -static inline void sysdev_shutdown(void) { } -#endif - /* debugging and troubleshooting/diagnostic helpers. */ extern const char *dev_driver_string(const struct device *dev); diff --git a/include/linux/pm.h b/include/linux/pm.h index 512e091..3c053e2 100644 --- a/include/linux/pm.h +++ b/include/linux/pm.h @@ -529,14 +529,6 @@ struct dev_power_domain { */ #ifdef CONFIG_PM_SLEEP -#ifndef CONFIG_ARCH_NO_SYSDEV_OPS -extern int sysdev_suspend(pm_message_t state); -extern int sysdev_resume(void); -#else -static inline int sysdev_suspend(pm_message_t state) { return 0; } -static inline int sysdev_resume(void) { return 0; } -#endif - extern void device_pm_lock(void); extern void dpm_resume_noirq(pm_message_t state); extern void dpm_resume_end(pm_message_t state); diff --git a/include/linux/sysdev.h b/include/linux/sysdev.h index dfb078d..d35e783 100644 --- a/include/linux/sysdev.h +++ b/include/linux/sysdev.h @@ -34,12 +34,6 @@ struct sysdev_class { struct list_head drivers; struct sysdev_class_attribute **attrs; struct kset kset; -#ifndef CONFIG_ARCH_NO_SYSDEV_OPS - /* Default operations for these types of devices */ - int (*shutdown)(struct sys_device *); - int (*suspend)(struct sys_device *, pm_message_t state); - int (*resume)(struct sys_device *); -#endif }; struct sysdev_class_attribute { @@ -77,11 +71,6 @@ struct sysdev_driver { struct list_head entry; int (*add)(struct sys_device *); int (*remove)(struct sys_device *); -#ifndef CONFIG_ARCH_NO_SYSDEV_OPS - int (*shutdown)(struct sys_device *); - int (*suspend)(struct sys_device *, pm_message_t state); - int (*resume)(struct sys_device *); -#endif }; diff --git a/kernel/kexec.c b/kernel/kexec.c index 87b77de..8d814cb 100644 --- a/kernel/kexec.c +++ b/kernel/kexec.c @@ -1531,13 +1531,7 @@ int kernel_kexec(void) if (error) goto Enable_cpus; local_irq_disable(); - /* Suspend system devices */ - error = sysdev_suspend(PMSG_FREEZE); - if (!error) { - error = syscore_suspend(); - if (error) - sysdev_resume(); - } + error = syscore_suspend(); if (error) goto Enable_irqs; } else @@ -1553,7 +1547,6 @@ int kernel_kexec(void) #ifdef CONFIG_KEXEC_JUMP if (kexec_image->preserve_context) { syscore_resume(); - sysdev_resume(); Enable_irqs: local_irq_enable(); Enable_cpus: diff --git a/kernel/power/hibernate.c b/kernel/power/hibernate.c index 50aae66..554d3b0 100644 --- a/kernel/power/hibernate.c +++ b/kernel/power/hibernate.c @@ -272,12 +272,7 @@ static int create_image(int platform_mode) local_irq_disable(); - error = sysdev_suspend(PMSG_FREEZE); - if (!error) { - error = syscore_suspend(); - if (error) - sysdev_resume(); - } + error = syscore_suspend(); if (error) { printk(KERN_ERR "PM: Some system devices failed to power down, " "aborting hibernation\n"); @@ -302,7 +297,6 @@ static int create_image(int platform_mode) Power_up: syscore_resume(); - sysdev_resume(); /* NOTE: dpm_resume_noirq() is just a resume() for devices * that suspended with irqs off ... no overall powerup. */ @@ -409,12 +403,7 @@ static int resume_target_kernel(bool platform_mode) local_irq_disable(); - error = sysdev_suspend(PMSG_QUIESCE); - if (!error) { - error = syscore_suspend(); - if (error) - sysdev_resume(); - } + error = syscore_suspend(); if (error) goto Enable_irqs; @@ -442,7 +431,6 @@ static int resume_target_kernel(bool platform_mode) touch_softlockup_watchdog(); syscore_resume(); - sysdev_resume(); Enable_irqs: local_irq_enable(); @@ -528,7 +516,6 @@ int hibernation_platform_enter(void) goto Platform_finish; local_irq_disable(); - sysdev_suspend(PMSG_HIBERNATE); syscore_suspend(); if (pm_wakeup_pending()) { error = -EAGAIN; @@ -541,7 +528,6 @@ int hibernation_platform_enter(void) Power_up: syscore_resume(); - sysdev_resume(); local_irq_enable(); enable_nonboot_cpus(); diff --git a/kernel/power/suspend.c b/kernel/power/suspend.c index 8935369..732d77a 100644 --- a/kernel/power/suspend.c +++ b/kernel/power/suspend.c @@ -163,19 +163,13 @@ static int suspend_enter(suspend_state_t state) arch_suspend_disable_irqs(); BUG_ON(!irqs_disabled()); - error = sysdev_suspend(PMSG_SUSPEND); - if (!error) { - error = syscore_suspend(); - if (error) - sysdev_resume(); - } + error = syscore_suspend(); if (!error) { if (!(suspend_test(TEST_CORE) || pm_wakeup_pending())) { error = suspend_ops->enter(state); events_check_enabled = false; } syscore_resume(); - sysdev_resume(); } arch_suspend_enable_irqs(); diff --git a/kernel/sys.c b/kernel/sys.c index af468ed..f0c1038 100644 --- a/kernel/sys.c +++ b/kernel/sys.c @@ -315,7 +315,6 @@ void kernel_restart_prepare(char *cmd) blocking_notifier_call_chain(&reboot_notifier_list, SYS_RESTART, cmd); system_state = SYSTEM_RESTART; device_shutdown(); - sysdev_shutdown(); syscore_shutdown(); } @@ -354,7 +353,6 @@ static void kernel_shutdown_prepare(enum system_states state) void kernel_halt(void) { kernel_shutdown_prepare(SYSTEM_HALT); - sysdev_shutdown(); syscore_shutdown(); printk(KERN_EMERG "System halted.\n"); kmsg_dump(KMSG_DUMP_HALT); @@ -374,7 +372,6 @@ void kernel_power_off(void) if (pm_power_off_prepare) pm_power_off_prepare(); disable_nonboot_cpus(); - sysdev_shutdown(); syscore_shutdown(); printk(KERN_EMERG "Power down.\n"); kmsg_dump(KMSG_DUMP_POWEROFF); -- cgit v0.10.2 From 83bc71b4102d2a288edaf9ee398b330b88a88086 Mon Sep 17 00:00:00 2001 From: Vinicius Costa Gomes Date: Fri, 6 May 2011 18:41:43 -0300 Subject: Bluetooth: Add support for sending connection events for LE links We need to be able for receive events notifying that the connection was established, the connection attempt failed or that disconnection happened. Signed-off-by: Vinicius Costa Gomes Signed-off-by: Gustavo F. Padovan diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index d5aa97e..f13ddbf 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -1440,7 +1440,7 @@ static inline void hci_disconn_complete_evt(struct hci_dev *hdev, struct sk_buff conn->state = BT_CLOSED; - if (conn->type == ACL_LINK) + if (conn->type == ACL_LINK || conn->type == LE_LINK) mgmt_disconnected(hdev->id, &conn->dst); hci_proto_disconn_cfm(conn, ev->reason); @@ -2659,12 +2659,15 @@ static inline void hci_le_conn_complete_evt(struct hci_dev *hdev, struct sk_buff } if (ev->status) { + mgmt_connect_failed(hdev->id, &ev->bdaddr, ev->status); hci_proto_connect_cfm(conn, ev->status); conn->state = BT_CLOSED; hci_conn_del(conn); goto unlock; } + mgmt_connected(hdev->id, &ev->bdaddr); + conn->handle = __le16_to_cpu(ev->handle); conn->state = BT_CONNECTED; -- cgit v0.10.2 From 365227e5fdf3d117e096416d9d3cc148959a829e Mon Sep 17 00:00:00 2001 From: Vinicius Costa Gomes Date: Fri, 6 May 2011 18:41:44 -0300 Subject: Bluetooth: Add support for disconnecting LE links via mgmt If we can't find a ACL link between the devices, we search the connection list one second time looking for LE links. Signed-off-by: Vinicius Costa Gomes Signed-off-by: Gustavo F. Padovan diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 2481d25..dae382c 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -1033,6 +1033,9 @@ static int disconnect(struct sock *sk, u16 index, unsigned char *data, u16 len) } conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->bdaddr); + if (!conn) + conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &cp->bdaddr); + if (!conn) { err = cmd_status(sk, index, MGMT_OP_DISCONNECT, ENOTCONN); goto failed; -- cgit v0.10.2 From 5409d2cd841cf2c76396470e566500f6505f8d2a Mon Sep 17 00:00:00 2001 From: Anton Blanchard Date: Wed, 11 May 2011 17:25:14 +1000 Subject: memory hotplug: Speed up add/remove when blocks are larger than PAGES_PER_SECTION On ppc64 the minimum memory section for hotplug is 16MB but most recent machines have a memory block size of 256MB. This means memory_block_change_state does 16 separate calls to memory_section_action. This also means we call the notifiers 16 times and the hook in the ehea network driver is quite costly. To offline one 256MB region takes: # time echo offline > /sys/devices/system/memory/memory32/state 7.9s This patch removes the loop and calls online_pages or remove_memory once for the entire region and in doing so makes the logic simpler since we don't have to back out if things fail part way through. The same test to offline one region now takes: # time echo online > /sys/devices/system/memory/memory32/state 0.67s Over 11 times faster. Signed-off-by: Anton Blanchard Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/base/memory.c b/drivers/base/memory.c index 3e9aa3d..c4c443d 100644 --- a/drivers/base/memory.c +++ b/drivers/base/memory.c @@ -229,10 +229,11 @@ int memory_isolate_notify(unsigned long val, void *v) * OK to have direct references to sparsemem variables in here. */ static int -memory_section_action(unsigned long phys_index, unsigned long action) +memory_block_action(unsigned long phys_index, unsigned long action) { int i; unsigned long start_pfn, start_paddr; + unsigned long nr_pages = PAGES_PER_SECTION * sections_per_block; struct page *first_page; int ret; @@ -244,7 +245,7 @@ memory_section_action(unsigned long phys_index, unsigned long action) * that way. */ if (action == MEM_ONLINE) { - for (i = 0; i < PAGES_PER_SECTION; i++) { + for (i = 0; i < nr_pages; i++) { if (PageReserved(first_page+i)) continue; @@ -258,12 +259,12 @@ memory_section_action(unsigned long phys_index, unsigned long action) switch (action) { case MEM_ONLINE: start_pfn = page_to_pfn(first_page); - ret = online_pages(start_pfn, PAGES_PER_SECTION); + ret = online_pages(start_pfn, nr_pages); break; case MEM_OFFLINE: start_paddr = page_to_pfn(first_page) << PAGE_SHIFT; ret = remove_memory(start_paddr, - PAGES_PER_SECTION << PAGE_SHIFT); + nr_pages << PAGE_SHIFT); break; default: WARN(1, KERN_WARNING "%s(%ld, %ld) unknown action: " @@ -289,20 +290,11 @@ static int memory_block_change_state(struct memory_block *mem, if (to_state == MEM_OFFLINE) mem->state = MEM_GOING_OFFLINE; - for (i = 0; i < sections_per_block; i++) { - ret = memory_section_action(mem->start_section_nr + i, - to_state); - if (ret) - break; - } - - if (ret) { - for (i = 0; i < sections_per_block; i++) - memory_section_action(mem->start_section_nr + i, - from_state_req); + ret = memory_block_action(mem->start_section_nr, to_state); + if (ret) mem->state = from_state_req; - } else + else mem->state = to_state; out: -- cgit v0.10.2 From 009dd872d753f854cf13c8334e0055092f539b38 Mon Sep 17 00:00:00 2001 From: Padmanabh Ratnakar Date: Tue, 10 May 2011 05:12:17 +0000 Subject: be2net: Handle error completion in Lancer In Lancer if a frame is DMAed partially due to lack of RX buffers, an error completion is sent with packet size as zero and num_recvd indicating number of used buffers. These buffers need to be freed and packet dropped. Signed-off-by: Padmanabh Ratnakar Signed-off-by: David S. Miller diff --git a/drivers/net/benet/be_main.c b/drivers/net/benet/be_main.c index 3fb4a1f..3202f67 100644 --- a/drivers/net/benet/be_main.c +++ b/drivers/net/benet/be_main.c @@ -1757,12 +1757,15 @@ static int be_poll_rx(struct napi_struct *napi, int budget) break; /* Ignore flush completions */ - if (rxcp->num_rcvd) { + if (rxcp->num_rcvd && rxcp->pkt_size) { if (do_gro(rxcp)) be_rx_compl_process_gro(adapter, rxo, rxcp); else be_rx_compl_process(adapter, rxo, rxcp); + } else if (rxcp->pkt_size == 0) { + be_rx_compl_discard(adapter, rxo, rxcp); } + be_rx_stats_update(rxo, rxcp); } -- cgit v0.10.2 From 6bd011d54254d6f2a5314ab0ed38e66772e6b9f7 Mon Sep 17 00:00:00 2001 From: Padmanabh Ratnakar Date: Tue, 10 May 2011 05:12:37 +0000 Subject: be2net: Disable coalesce water mark mode of CQ for Lancer Disable coalesce water mark mode of CQ for Lancer Signed-off-by: Padmanabh Ratnakar Signed-off-by: David S. Miller diff --git a/drivers/net/benet/be_cmds.c b/drivers/net/benet/be_cmds.c index 5fedc27..391dee2 100644 --- a/drivers/net/benet/be_cmds.c +++ b/drivers/net/benet/be_cmds.c @@ -729,8 +729,6 @@ int be_cmd_cq_create(struct be_adapter *adapter, if (lancer_chip(adapter)) { req->hdr.version = 2; req->page_size = 1; /* 1 for 4K */ - AMAP_SET_BITS(struct amap_cq_context_lancer, coalescwm, ctxt, - coalesce_wm); AMAP_SET_BITS(struct amap_cq_context_lancer, nodelay, ctxt, no_delay); AMAP_SET_BITS(struct amap_cq_context_lancer, count, ctxt, -- cgit v0.10.2 From 18a91e6002207c8212e0960854f88ab924ea22f9 Mon Sep 17 00:00:00 2001 From: Padmanabh Ratnakar Date: Tue, 10 May 2011 05:13:01 +0000 Subject: be2net: In case of UE, do not dump registers for Lancer In case of UE, do not dump registers for Lancer as they are not supported. Signed-off-by: Padmanabh Ratnakar Signed-off-by: David S. Miller diff --git a/drivers/net/benet/be_cmds.c b/drivers/net/benet/be_cmds.c index 391dee2..bdd6c54 100644 --- a/drivers/net/benet/be_cmds.c +++ b/drivers/net/benet/be_cmds.c @@ -293,7 +293,8 @@ static int be_mbox_db_ready_wait(struct be_adapter *adapter, void __iomem *db) if (msecs > 4000) { dev_err(&adapter->pdev->dev, "mbox poll timed out\n"); - be_detect_dump_ue(adapter); + if (!lancer_chip(adapter)) + be_detect_dump_ue(adapter); return -1; } -- cgit v0.10.2 From ecd0bf0f7b280bac3ac7419ed3aac84cd92878e9 Mon Sep 17 00:00:00 2001 From: Padmanabh Ratnakar Date: Tue, 10 May 2011 05:13:26 +0000 Subject: be2net: Use NTWK_RX_FILTER command for promiscous mode Use OPCODE_COMMON_NTWK_RX_FILTER command for promiscous mode as OPCODE_ETH_PROMISCUOUS command is getting deprecated. Signed-off-by: Padmanabh Ratnakar Signed-off-by: David S. Miller diff --git a/drivers/net/benet/be_cmds.c b/drivers/net/benet/be_cmds.c index bdd6c54..0dbb4cb 100644 --- a/drivers/net/benet/be_cmds.c +++ b/drivers/net/benet/be_cmds.c @@ -1404,12 +1404,24 @@ err: /* Uses MCC for this command as it may be called in BH context * Uses synchronous mcc */ -int be_cmd_promiscuous_config(struct be_adapter *adapter, u8 port_num, bool en) +int be_cmd_promiscuous_config(struct be_adapter *adapter, bool en) { struct be_mcc_wrb *wrb; - struct be_cmd_req_promiscuous_config *req; + struct be_cmd_req_rx_filter *req; + struct be_dma_mem promiscous_cmd; + struct be_sge *sge; int status; + memset(&promiscous_cmd, 0, sizeof(struct be_dma_mem)); + promiscous_cmd.size = sizeof(struct be_cmd_req_rx_filter); + promiscous_cmd.va = pci_alloc_consistent(adapter->pdev, + promiscous_cmd.size, &promiscous_cmd.dma); + if (!promiscous_cmd.va) { + dev_err(&adapter->pdev->dev, + "Memory allocation failure\n"); + return -ENOMEM; + } + spin_lock_bh(&adapter->mcc_lock); wrb = wrb_from_mccq(adapter); @@ -1417,26 +1429,30 @@ int be_cmd_promiscuous_config(struct be_adapter *adapter, u8 port_num, bool en) status = -EBUSY; goto err; } - req = embedded_payload(wrb); - be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0, OPCODE_ETH_PROMISCUOUS); + req = promiscous_cmd.va; + sge = nonembedded_sgl(wrb); - be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_ETH, - OPCODE_ETH_PROMISCUOUS, sizeof(*req)); - - /* In FW versions X.102.149/X.101.487 and later, - * the port setting associated only with the - * issuing pci function will take effect - */ - if (port_num) - req->port1_promiscuous = en; - else - req->port0_promiscuous = en; + be_wrb_hdr_prepare(wrb, sizeof(*req), false, 1, + OPCODE_COMMON_NTWK_RX_FILTER); + be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON, + OPCODE_COMMON_NTWK_RX_FILTER, sizeof(*req)); + + req->if_id = cpu_to_le32(adapter->if_handle); + req->if_flags_mask = cpu_to_le32(BE_IF_FLAGS_PROMISCUOUS); + if (en) + req->if_flags = cpu_to_le32(BE_IF_FLAGS_PROMISCUOUS); + + sge->pa_hi = cpu_to_le32(upper_32_bits(promiscous_cmd.dma)); + sge->pa_lo = cpu_to_le32(promiscous_cmd.dma & 0xFFFFFFFF); + sge->len = cpu_to_le32(promiscous_cmd.size); status = be_mcc_notify_wait(adapter); err: spin_unlock_bh(&adapter->mcc_lock); + pci_free_consistent(adapter->pdev, promiscous_cmd.size, + promiscous_cmd.va, promiscous_cmd.dma); return status; } diff --git a/drivers/net/benet/be_cmds.h b/drivers/net/benet/be_cmds.h index af4bbff..78256b6 100644 --- a/drivers/net/benet/be_cmds.h +++ b/drivers/net/benet/be_cmds.h @@ -714,13 +714,6 @@ struct be_cmd_req_vlan_config { u16 normal_vlan[64]; } __packed; -struct be_cmd_req_promiscuous_config { - struct be_cmd_req_hdr hdr; - u8 port0_promiscuous; - u8 port1_promiscuous; - u16 rsvd0; -} __packed; - /******************** Multicast MAC Config *******************/ #define BE_MAX_MC 64 /* set mcast promisc if > 64 */ struct macaddr { @@ -741,6 +734,20 @@ hw_stats_from_cmd(struct be_cmd_resp_get_stats *cmd) return &cmd->hw_stats; } + +/******************* RX FILTER ******************************/ +struct be_cmd_req_rx_filter { + struct be_cmd_req_hdr hdr; + u32 global_flags_mask; + u32 global_flags; + u32 if_flags_mask; + u32 if_flags; + u32 if_id; + u32 multicast_num; + struct macaddr mac[BE_MAX_MC]; +}; + + /******************** Link Status Query *******************/ struct be_cmd_req_link_status { struct be_cmd_req_hdr hdr; @@ -1122,8 +1129,7 @@ extern int be_cmd_modify_eqd(struct be_adapter *adapter, u32 eq_id, u32 eqd); extern int be_cmd_vlan_config(struct be_adapter *adapter, u32 if_id, u16 *vtag_array, u32 num, bool untagged, bool promiscuous); -extern int be_cmd_promiscuous_config(struct be_adapter *adapter, - u8 port_num, bool en); +extern int be_cmd_promiscuous_config(struct be_adapter *adapter, bool en); extern int be_cmd_multicast_set(struct be_adapter *adapter, u32 if_id, struct net_device *netdev, struct be_dma_mem *mem); extern int be_cmd_set_flow_control(struct be_adapter *adapter, diff --git a/drivers/net/benet/be_main.c b/drivers/net/benet/be_main.c index 3202f67..babe53a 100644 --- a/drivers/net/benet/be_main.c +++ b/drivers/net/benet/be_main.c @@ -698,7 +698,7 @@ static void be_set_multicast_list(struct net_device *netdev) struct be_adapter *adapter = netdev_priv(netdev); if (netdev->flags & IFF_PROMISC) { - be_cmd_promiscuous_config(adapter, adapter->port_num, 1); + be_cmd_promiscuous_config(adapter, true); adapter->promiscuous = true; goto done; } @@ -706,7 +706,7 @@ static void be_set_multicast_list(struct net_device *netdev) /* BE was previously in promiscuous mode; disable it */ if (adapter->promiscuous) { adapter->promiscuous = false; - be_cmd_promiscuous_config(adapter, adapter->port_num, 0); + be_cmd_promiscuous_config(adapter, false); } /* Enable multicast promisc if num configured exceeds what we support */ -- cgit v0.10.2 From 4d586b823acc46c55c889ae1798de236c9d403da Mon Sep 17 00:00:00 2001 From: Padmanabh Ratnakar Date: Tue, 10 May 2011 05:13:57 +0000 Subject: be2net: Fix to prevent flooding of TX queue Start/stop TX queue is controlled by TX queue "used" counter. It is incremented while WRBs are posted to TX queue and decremented when TX completions are received. This counter was getting decremented before HW is informed about processing of TX completions. As used counter is decremented, transmit function posts new WRBs and creates completion queue full scenario in HW. Signed-off-by: Padmanabh Ratnakar Signed-off-by: David S. Miller diff --git a/drivers/net/benet/be_main.c b/drivers/net/benet/be_main.c index babe53a..243172b 100644 --- a/drivers/net/benet/be_main.c +++ b/drivers/net/benet/be_main.c @@ -1275,7 +1275,7 @@ static struct be_eth_tx_compl *be_tx_compl_get(struct be_queue_info *tx_cq) return txcp; } -static void be_tx_compl_process(struct be_adapter *adapter, u16 last_index) +static u16 be_tx_compl_process(struct be_adapter *adapter, u16 last_index) { struct be_queue_info *txq = &adapter->tx_obj.q; struct be_eth_wrb *wrb; @@ -1302,9 +1302,8 @@ static void be_tx_compl_process(struct be_adapter *adapter, u16 last_index) queue_tail_inc(txq); } while (cur_index != last_index); - atomic_sub(num_wrbs, &txq->used); - kfree_skb(sent_skb); + return num_wrbs; } static inline struct be_eq_entry *event_get(struct be_eq_obj *eq_obj) @@ -1387,7 +1386,7 @@ static void be_tx_compl_clean(struct be_adapter *adapter) struct be_queue_info *tx_cq = &adapter->tx_obj.cq; struct be_queue_info *txq = &adapter->tx_obj.q; struct be_eth_tx_compl *txcp; - u16 end_idx, cmpl = 0, timeo = 0; + u16 end_idx, cmpl = 0, timeo = 0, num_wrbs = 0; struct sk_buff **sent_skbs = adapter->tx_obj.sent_skb_list; struct sk_buff *sent_skb; bool dummy_wrb; @@ -1397,12 +1396,14 @@ static void be_tx_compl_clean(struct be_adapter *adapter) while ((txcp = be_tx_compl_get(tx_cq))) { end_idx = AMAP_GET_BITS(struct amap_eth_tx_compl, wrb_index, txcp); - be_tx_compl_process(adapter, end_idx); + num_wrbs += be_tx_compl_process(adapter, end_idx); cmpl++; } if (cmpl) { be_cq_notify(adapter, tx_cq->id, false, cmpl); + atomic_sub(num_wrbs, &txq->used); cmpl = 0; + num_wrbs = 0; } if (atomic_read(&txq->used) == 0 || ++timeo > 200) @@ -1422,7 +1423,8 @@ static void be_tx_compl_clean(struct be_adapter *adapter) index_adv(&end_idx, wrb_cnt_for_skb(adapter, sent_skb, &dummy_wrb) - 1, txq->len); - be_tx_compl_process(adapter, end_idx); + num_wrbs = be_tx_compl_process(adapter, end_idx); + atomic_sub(num_wrbs, &txq->used); } } @@ -1796,12 +1798,12 @@ static int be_poll_tx_mcc(struct napi_struct *napi, int budget) struct be_queue_info *tx_cq = &adapter->tx_obj.cq; struct be_eth_tx_compl *txcp; int tx_compl = 0, mcc_compl, status = 0; - u16 end_idx; + u16 end_idx, num_wrbs = 0; while ((txcp = be_tx_compl_get(tx_cq))) { end_idx = AMAP_GET_BITS(struct amap_eth_tx_compl, wrb_index, txcp); - be_tx_compl_process(adapter, end_idx); + num_wrbs += be_tx_compl_process(adapter, end_idx); tx_compl++; } @@ -1817,6 +1819,8 @@ static int be_poll_tx_mcc(struct napi_struct *napi, int budget) if (tx_compl) { be_cq_notify(adapter, adapter->tx_obj.cq.id, true, tx_compl); + atomic_sub(num_wrbs, &txq->used); + /* As Tx wrbs have been freed up, wake up netdev queue if * it was stopped due to lack of tx wrbs. */ -- cgit v0.10.2 From 52cd4e5c620af9e21b5298bf01844b98573505a7 Mon Sep 17 00:00:00 2001 From: Ben Dooks Date: Wed, 11 May 2011 15:13:28 -0700 Subject: drivers/rtc/rtc-s3c.c: fixup wake support for rtc The driver is not balancing set_irq and disable_irq_wake() calls, so ensure that it keeps track of whether the wake is enabled. The fixes the following error on S3C6410 devices: WARNING: at kernel/irq/manage.c:382 set_irq_wake+0x84/0xec() Unbalanced IRQ 92 wake disable Signed-off-by: Ben Dooks Signed-off-by: Mark Brown Cc: Alessandro Zummo Cc: Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/drivers/rtc/rtc-s3c.c b/drivers/rtc/rtc-s3c.c index b3466c4..16512ec 100644 --- a/drivers/rtc/rtc-s3c.c +++ b/drivers/rtc/rtc-s3c.c @@ -46,6 +46,7 @@ static struct clk *rtc_clk; static void __iomem *s3c_rtc_base; static int s3c_rtc_alarmno = NO_IRQ; static int s3c_rtc_tickno = NO_IRQ; +static bool wake_en; static enum s3c_cpu_type s3c_rtc_cpu_type; static DEFINE_SPINLOCK(s3c_rtc_pie_lock); @@ -562,8 +563,12 @@ static int s3c_rtc_suspend(struct platform_device *pdev, pm_message_t state) } s3c_rtc_enable(pdev, 0); - if (device_may_wakeup(&pdev->dev)) - enable_irq_wake(s3c_rtc_alarmno); + if (device_may_wakeup(&pdev->dev) && !wake_en) { + if (enable_irq_wake(s3c_rtc_alarmno) == 0) + wake_en = true; + else + dev_err(&pdev->dev, "enable_irq_wake failed\n"); + } return 0; } @@ -579,8 +584,10 @@ static int s3c_rtc_resume(struct platform_device *pdev) writew(tmp | ticnt_en_save, s3c_rtc_base + S3C2410_RTCCON); } - if (device_may_wakeup(&pdev->dev)) + if (device_may_wakeup(&pdev->dev) && wake_en) { disable_irq_wake(s3c_rtc_alarmno); + wake_en = false; + } return 0; } -- cgit v0.10.2 From bad49d9c89d8755a1289d68e6d0127a6ee79e119 Mon Sep 17 00:00:00 2001 From: Minchan Kim Date: Wed, 11 May 2011 15:13:30 -0700 Subject: mm: check PageUnevictable in lru_deactivate_fn() The lru_deactivate_fn should not move page which in on unevictable lru into inactive list. Otherwise, we can meet BUG when we use isolate_lru_pages as __isolate_lru_page could return -EINVAL. Reported-by: Ying Han Tested-by: Ying Han Signed-off-by: Minchan Kim Reviewed-by: KOSAKI Motohiro Reviewed-by: Rik van Riel Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/mm/swap.c b/mm/swap.c index a448db3..5602f1a 100644 --- a/mm/swap.c +++ b/mm/swap.c @@ -396,6 +396,9 @@ static void lru_deactivate_fn(struct page *page, void *arg) if (!PageLRU(page)) return; + if (PageUnevictable(page)) + return; + /* Some processes are using the page */ if (page_mapped(page)) return; -- cgit v0.10.2 From 8f389a99b652aab5b42297280bd94d95933ad12f Mon Sep 17 00:00:00 2001 From: Yinghai Lu Date: Wed, 11 May 2011 15:13:32 -0700 Subject: mm: use alloc_bootmem_node_nopanic() on really needed path Stefan found nobootmem does not work on his system that has only 8M of RAM. This causes an early panic: BIOS-provided physical RAM map: BIOS-88: 0000000000000000 - 000000000009f000 (usable) BIOS-88: 0000000000100000 - 0000000000840000 (usable) bootconsole [earlyser0] enabled Notice: NX (Execute Disable) protection missing in CPU or disabled in BIOS! DMI not present or invalid. last_pfn = 0x840 max_arch_pfn = 0x100000 init_memory_mapping: 0000000000000000-0000000000840000 8MB LOWMEM available. mapped low ram: 0 - 00840000 low ram: 0 - 00840000 Zone PFN ranges: DMA 0x00000001 -> 0x00001000 Normal empty Movable zone start PFN for each node early_node_map[2] active PFN ranges 0: 0x00000001 -> 0x0000009f 0: 0x00000100 -> 0x00000840 BUG: Int 6: CR2 (null) EDI c034663c ESI (null) EBP c0329f38 ESP c0329ef4 EBX c0346380 EDX 00000006 ECX ffffffff EAX fffffff4 err (null) EIP c0353191 CS c0320060 flg 00010082 Stack: (null) c030c533 000007cd (null) c030c533 00000001 (null) (null) 00000003 0000083f 00000018 00000002 00000002 c0329f6c c03534d6 (null) (null) 00000100 00000840 (null) c0329f64 00000001 00001000 (null) Pid: 0, comm: swapper Not tainted 2.6.36 #5 Call Trace: [] ? 0xc02e3707 [] 0xc035e6e5 [] ? 0xc0353191 [] 0xc03534d6 [] 0xc034f1cd [] 0xc034a824 [] ? 0xc03513cb [] 0xc0349432 [] 0xc0349066 It turns out that we should ignore the low limit of 16M. Use alloc_bootmem_node_nopanic() in this case. [akpm@linux-foundation.org: less mess] Signed-off-by: Yinghai LU Reported-by: Stefan Hellermann Tested-by: Stefan Hellermann Cc: Ingo Molnar Cc: "H. Peter Anvin" Cc: Thomas Gleixner Cc: [2.6.34+] Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/include/linux/bootmem.h b/include/linux/bootmem.h index b8613e8..01eca17 100644 --- a/include/linux/bootmem.h +++ b/include/linux/bootmem.h @@ -111,6 +111,8 @@ extern void *__alloc_bootmem_low_node(pg_data_t *pgdat, __alloc_bootmem_nopanic(x, PAGE_SIZE, __pa(MAX_DMA_ADDRESS)) #define alloc_bootmem_node(pgdat, x) \ __alloc_bootmem_node(pgdat, x, SMP_CACHE_BYTES, __pa(MAX_DMA_ADDRESS)) +#define alloc_bootmem_node_nopanic(pgdat, x) \ + __alloc_bootmem_node_nopanic(pgdat, x, SMP_CACHE_BYTES, __pa(MAX_DMA_ADDRESS)) #define alloc_bootmem_pages_node(pgdat, x) \ __alloc_bootmem_node(pgdat, x, PAGE_SIZE, __pa(MAX_DMA_ADDRESS)) #define alloc_bootmem_pages_node_nopanic(pgdat, x) \ diff --git a/mm/page_alloc.c b/mm/page_alloc.c index 9f8a97b..454191a 100644 --- a/mm/page_alloc.c +++ b/mm/page_alloc.c @@ -3564,7 +3564,7 @@ int zone_wait_table_init(struct zone *zone, unsigned long zone_size_pages) if (!slab_is_available()) { zone->wait_table = (wait_queue_head_t *) - alloc_bootmem_node(pgdat, alloc_size); + alloc_bootmem_node_nopanic(pgdat, alloc_size); } else { /* * This case means that a zone whose size was 0 gets new memory @@ -4141,7 +4141,8 @@ static void __init setup_usemap(struct pglist_data *pgdat, unsigned long usemapsize = usemap_size(zonesize); zone->pageblock_flags = NULL; if (usemapsize) - zone->pageblock_flags = alloc_bootmem_node(pgdat, usemapsize); + zone->pageblock_flags = alloc_bootmem_node_nopanic(pgdat, + usemapsize); } #else static inline void setup_usemap(struct pglist_data *pgdat, @@ -4307,7 +4308,7 @@ static void __init_refok alloc_node_mem_map(struct pglist_data *pgdat) size = (end - start) * sizeof(struct page); map = alloc_remap(pgdat->node_id, size); if (!map) - map = alloc_bootmem_node(pgdat, size); + map = alloc_bootmem_node_nopanic(pgdat, size); pgdat->node_mem_map = map + (pgdat->node_start_pfn - start); } #ifndef CONFIG_NEED_MULTIPLE_NODES -- cgit v0.10.2 From 71a6d0af5b031d27029fda64fbab9b9d953d2b33 Mon Sep 17 00:00:00 2001 From: Harry Wei Date: Wed, 11 May 2011 15:13:33 -0700 Subject: MAINTAINERS: fix sorting Take alphabetical orders for MAINTAINERS file. Signed-off-by: Harry Wei Cc: Joe Perches Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/MAINTAINERS b/MAINTAINERS index 16a5c5f..69f19f1 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -2813,38 +2813,19 @@ F: Documentation/gpio.txt F: drivers/gpio/ F: include/linux/gpio* +GRE DEMULTIPLEXER DRIVER +M: Dmitry Kozlov +L: netdev@vger.kernel.org +S: Maintained +F: net/ipv4/gre.c +F: include/net/gre.h + GRETH 10/100/1G Ethernet MAC device driver M: Kristoffer Glembo L: netdev@vger.kernel.org S: Maintained F: drivers/net/greth* -HARD DRIVE ACTIVE PROTECTION SYSTEM (HDAPS) DRIVER -M: Frank Seidel -L: platform-driver-x86@vger.kernel.org -W: http://www.kernel.org/pub/linux/kernel/people/fseidel/hdaps/ -S: Maintained -F: drivers/platform/x86/hdaps.c - -HWPOISON MEMORY FAILURE HANDLING -M: Andi Kleen -L: linux-mm@kvack.org -T: git git://git.kernel.org/pub/scm/linux/kernel/git/ak/linux-mce-2.6.git hwpoison -S: Maintained -F: mm/memory-failure.c -F: mm/hwpoison-inject.c - -HYPERVISOR VIRTUAL CONSOLE DRIVER -L: linuxppc-dev@lists.ozlabs.org -S: Odd Fixes -F: drivers/tty/hvc/ - -iSCSI BOOT FIRMWARE TABLE (iBFT) DRIVER -M: Peter Jones -M: Konrad Rzeszutek Wilk -S: Maintained -F: drivers/firmware/iscsi_ibft* - GSPCA FINEPIX SUBDRIVER M: Frank Zago L: linux-media@vger.kernel.org @@ -2895,6 +2876,26 @@ T: git git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-2.6.git S: Maintained F: drivers/media/video/gspca/ +HARD DRIVE ACTIVE PROTECTION SYSTEM (HDAPS) DRIVER +M: Frank Seidel +L: platform-driver-x86@vger.kernel.org +W: http://www.kernel.org/pub/linux/kernel/people/fseidel/hdaps/ +S: Maintained +F: drivers/platform/x86/hdaps.c + +HWPOISON MEMORY FAILURE HANDLING +M: Andi Kleen +L: linux-mm@kvack.org +T: git git://git.kernel.org/pub/scm/linux/kernel/git/ak/linux-mce-2.6.git hwpoison +S: Maintained +F: mm/memory-failure.c +F: mm/hwpoison-inject.c + +HYPERVISOR VIRTUAL CONSOLE DRIVER +L: linuxppc-dev@lists.ozlabs.org +S: Odd Fixes +F: drivers/tty/hvc/ + HARDWARE MONITORING M: Jean Delvare M: Guenter Roeck @@ -3478,6 +3479,12 @@ F: Documentation/isapnp.txt F: drivers/pnp/isapnp/ F: include/linux/isapnp.h +iSCSI BOOT FIRMWARE TABLE (iBFT) DRIVER +M: Peter Jones +M: Konrad Rzeszutek Wilk +S: Maintained +F: drivers/firmware/iscsi_ibft* + ISCSI M: Mike Christie L: open-iscsi@googlegroups.com @@ -4989,6 +4996,13 @@ F: Documentation/pps/ F: drivers/pps/ F: include/linux/pps*.h +PPTP DRIVER +M: Dmitry Kozlov +L: netdev@vger.kernel.org +S: Maintained +F: drivers/net/pptp.c +W: http://sourceforge.net/projects/accel-pptp + PREEMPTIBLE KERNEL M: Robert Love L: kpreempt-tech@lists.sourceforge.net @@ -7024,20 +7038,6 @@ M: "Maciej W. Rozycki" S: Maintained F: drivers/tty/serial/zs.* -GRE DEMULTIPLEXER DRIVER -M: Dmitry Kozlov -L: netdev@vger.kernel.org -S: Maintained -F: net/ipv4/gre.c -F: include/net/gre.h - -PPTP DRIVER -M: Dmitry Kozlov -L: netdev@vger.kernel.org -S: Maintained -F: drivers/net/pptp.c -W: http://sourceforge.net/projects/accel-pptp - THE REST M: Linus Torvalds L: linux-kernel@vger.kernel.org -- cgit v0.10.2 From ee85c2e1454603ebb9f8d87223ac79dcdc87fa32 Mon Sep 17 00:00:00 2001 From: Andi Kleen Date: Wed, 11 May 2011 15:13:34 -0700 Subject: mm: add alloc_pages_exact_nid() Add a alloc_pages_exact_nid() that allocates on a specific node. The naming is quite broken, but fixing that would need a larger renaming action. [akpm@linux-foundation.org: coding-style fixes] [akpm@linux-foundation.org: tweak comment] Signed-off-by: Andi Kleen Cc: Michal Hocko Cc: Balbir Singh Cc: KOSAKI Motohiro Cc: Dave Hansen Cc: David Rientjes Acked-by: Johannes Weiner Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/include/linux/gfp.h b/include/linux/gfp.h index bfb8f93..56d8fc8 100644 --- a/include/linux/gfp.h +++ b/include/linux/gfp.h @@ -353,6 +353,8 @@ extern unsigned long get_zeroed_page(gfp_t gfp_mask); void *alloc_pages_exact(size_t size, gfp_t gfp_mask); void free_pages_exact(void *virt, size_t size); +/* This is different from alloc_pages_exact_node !!! */ +void *alloc_pages_exact_nid(int nid, size_t size, gfp_t gfp_mask); #define __get_free_page(gfp_mask) \ __get_free_pages((gfp_mask), 0) diff --git a/mm/page_alloc.c b/mm/page_alloc.c index 454191a..570d944 100644 --- a/mm/page_alloc.c +++ b/mm/page_alloc.c @@ -2317,6 +2317,21 @@ void free_pages(unsigned long addr, unsigned int order) EXPORT_SYMBOL(free_pages); +static void *make_alloc_exact(unsigned long addr, unsigned order, size_t size) +{ + if (addr) { + unsigned long alloc_end = addr + (PAGE_SIZE << order); + unsigned long used = addr + PAGE_ALIGN(size); + + split_page(virt_to_page((void *)addr), order); + while (used < alloc_end) { + free_page(used); + used += PAGE_SIZE; + } + } + return (void *)addr; +} + /** * alloc_pages_exact - allocate an exact number physically-contiguous pages. * @size: the number of bytes to allocate @@ -2336,22 +2351,32 @@ void *alloc_pages_exact(size_t size, gfp_t gfp_mask) unsigned long addr; addr = __get_free_pages(gfp_mask, order); - if (addr) { - unsigned long alloc_end = addr + (PAGE_SIZE << order); - unsigned long used = addr + PAGE_ALIGN(size); - - split_page(virt_to_page((void *)addr), order); - while (used < alloc_end) { - free_page(used); - used += PAGE_SIZE; - } - } - - return (void *)addr; + return make_alloc_exact(addr, order, size); } EXPORT_SYMBOL(alloc_pages_exact); /** + * alloc_pages_exact_nid - allocate an exact number of physically-contiguous + * pages on a node. + * @size: the number of bytes to allocate + * @gfp_mask: GFP flags for the allocation + * + * Like alloc_pages_exact(), but try to allocate on node nid first before falling + * back. + * Note this is not alloc_pages_exact_node() which allocates on a specific node, + * but is not exact. + */ +void *alloc_pages_exact_nid(int nid, size_t size, gfp_t gfp_mask) +{ + unsigned order = get_order(size); + struct page *p = alloc_pages_node(nid, gfp_mask, order); + if (!p) + return NULL; + return make_alloc_exact((unsigned long)page_address(p), order, size); +} +EXPORT_SYMBOL(alloc_pages_exact_nid); + +/** * free_pages_exact - release memory allocated via alloc_pages_exact() * @virt: the value returned by alloc_pages_exact. * @size: size of allocation, same value as passed to alloc_pages_exact(). -- cgit v0.10.2 From 21a3c9646873ae0919415d635b671d6a58758ede Mon Sep 17 00:00:00 2001 From: Andi Kleen Date: Wed, 11 May 2011 15:13:35 -0700 Subject: memcg: allocate memory cgroup structures in local nodes Commit dde79e005a769 ("page_cgroup: reduce allocation overhead for page_cgroup array for CONFIG_SPARSEMEM") added a regression that the memory cgroup data structures all end up in node 0 because the first attempt at allocating them would not pass in a node hint. Since the initialization runs on CPU #0 it would all end up node 0. This is a problem on large memory systems, where node 0 would lose a lot of memory. Change the alloc_pages_exact() to alloc_pages_exact_nid(). This will still fall back to other nodes if not enough memory is available. [ RED-PEN: right now it would fall back first before trying vmalloc_node. Probably not the best strategy ... But I left it like that for now. ] Signed-off-by: Andi Kleen Reported-by: Doug Nelson Cc: David Rientjes Reviewed-by: Michal Hocko Cc: Dave Hansen Acked-by: Balbir Singh Acked-by: Johannes Weiner Reviewed-by: KOSAKI Motohiro Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/mm/page_cgroup.c b/mm/page_cgroup.c index 9905501..2daadc3 100644 --- a/mm/page_cgroup.c +++ b/mm/page_cgroup.c @@ -134,7 +134,7 @@ static void *__init_refok alloc_page_cgroup(size_t size, int nid) { void *addr = NULL; - addr = alloc_pages_exact(size, GFP_KERNEL | __GFP_NOWARN); + addr = alloc_pages_exact_nid(nid, size, GFP_KERNEL | __GFP_NOWARN); if (addr) return addr; -- cgit v0.10.2 From b1dea800ac39599301d4bb8dcf2b1d29c2558211 Mon Sep 17 00:00:00 2001 From: Hugh Dickins Date: Wed, 11 May 2011 15:13:36 -0700 Subject: tmpfs: fix race between umount and writepage Konstanin Khlebnikov reports that a dangerous race between umount and shmem_writepage can be reproduced by this script: for i in {1..300} ; do mkdir $i while true ; do mount -t tmpfs none $i dd if=/dev/zero of=$i/test bs=1M count=$(($RANDOM % 100)) umount $i done & done on a 6xCPU node with 8Gb RAM: kernel very unstable after this accident. =) Kernel log: VFS: Busy inodes after unmount of tmpfs. Self-destruct in 5 seconds. Have a nice day... WARNING: at lib/list_debug.c:53 __list_del_entry+0x8d/0x98() list_del corruption. prev->next should be ffff880222fdaac8, but was (null) Pid: 11222, comm: mount.tmpfs Not tainted 2.6.39-rc2+ #4 Call Trace: warn_slowpath_common+0x80/0x98 warn_slowpath_fmt+0x41/0x43 __list_del_entry+0x8d/0x98 evict+0x50/0x113 iput+0x138/0x141 ... BUG: unable to handle kernel paging request at ffffffffffffffff IP: shmem_free_blocks+0x18/0x4c Pid: 10422, comm: dd Tainted: G W 2.6.39-rc2+ #4 Call Trace: shmem_recalc_inode+0x61/0x66 shmem_writepage+0xba/0x1dc pageout+0x13c/0x24c shrink_page_list+0x28e/0x4be shrink_inactive_list+0x21f/0x382 ... shmem_writepage() calls igrab() on the inode for the page which came from page reclaim, to add it later into shmem_swaplist for swapoff operation. This igrab() can race with super-block deactivating process: shrink_inactive_list() deactivate_super() pageout() tmpfs_fs_type->kill_sb() shmem_writepage() kill_litter_super() generic_shutdown_super() evict_inodes() igrab() atomic_read(&inode->i_count) skip-inode iput() if (!list_empty(&sb->s_inodes)) printk("VFS: Busy inodes after... This igrap-iput pair was added in commit 1b1b32f2c6f6 "tmpfs: fix shmem_swaplist races" based on incorrect assumptions: igrab() protects the inode from concurrent eviction by deletion, but it does nothing to protect it from concurrent unmounting, which goes ahead despite the raised i_count. So this use of igrab() was wrong all along, but the race made much worse in 2.6.37 when commit 63997e98a3be "split invalidate_inodes()" replaced two attempts at invalidate_inodes() by a single evict_inodes(). Konstantin posted a plausible patch, raising sb->s_active too: I'm unsure whether it was correct or not; but burnt once by igrab(), I am sure that we don't want to rely more deeply upon externals here. Fix it by adding the inode to shmem_swaplist earlier, while the page lock on page in page cache still secures the inode against eviction, without artifically raising i_count. It was originally added later because shmem_unuse_inode() is liable to remove an inode from the list while it's unswapped; but we can guard against that by taking spinlock before dropping mutex. Reported-by: Konstantin Khlebnikov Signed-off-by: Hugh Dickins Tested-by: Konstantin Khlebnikov Cc: Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/mm/shmem.c b/mm/shmem.c index 8fa27e4..262d711 100644 --- a/mm/shmem.c +++ b/mm/shmem.c @@ -1039,6 +1039,7 @@ static int shmem_writepage(struct page *page, struct writeback_control *wbc) struct address_space *mapping; unsigned long index; struct inode *inode; + bool unlock_mutex = false; BUG_ON(!PageLocked(page)); mapping = page->mapping; @@ -1064,7 +1065,26 @@ static int shmem_writepage(struct page *page, struct writeback_control *wbc) else swap.val = 0; + /* + * Add inode to shmem_unuse()'s list of swapped-out inodes, + * if it's not already there. Do it now because we cannot take + * mutex while holding spinlock, and must do so before the page + * is moved to swap cache, when its pagelock no longer protects + * the inode from eviction. But don't unlock the mutex until + * we've taken the spinlock, because shmem_unuse_inode() will + * prune a !swapped inode from the swaplist under both locks. + */ + if (swap.val && list_empty(&info->swaplist)) { + mutex_lock(&shmem_swaplist_mutex); + /* move instead of add in case we're racing */ + list_move_tail(&info->swaplist, &shmem_swaplist); + unlock_mutex = true; + } + spin_lock(&info->lock); + if (unlock_mutex) + mutex_unlock(&shmem_swaplist_mutex); + if (index >= info->next_index) { BUG_ON(!(info->flags & SHMEM_TRUNCATE)); goto unlock; @@ -1084,21 +1104,10 @@ static int shmem_writepage(struct page *page, struct writeback_control *wbc) delete_from_page_cache(page); shmem_swp_set(info, entry, swap.val); shmem_swp_unmap(entry); - if (list_empty(&info->swaplist)) - inode = igrab(inode); - else - inode = NULL; spin_unlock(&info->lock); swap_shmem_alloc(swap); BUG_ON(page_mapped(page)); swap_writepage(page, wbc); - if (inode) { - mutex_lock(&shmem_swaplist_mutex); - /* move instead of add in case we're racing */ - list_move_tail(&info->swaplist, &shmem_swaplist); - mutex_unlock(&shmem_swaplist_mutex); - iput(inode); - } return 0; } -- cgit v0.10.2 From 778dd893ae785c5fd505dac30b5fc40aae188bf1 Mon Sep 17 00:00:00 2001 From: Hugh Dickins Date: Wed, 11 May 2011 15:13:37 -0700 Subject: tmpfs: fix race between umount and swapoff The use of igrab() in swapoff's shmem_unuse_inode() is just as vulnerable to umount as that in shmem_writepage(). Fix this instance by extending the protection of shmem_swaplist_mutex right across shmem_unuse_inode(): while it's on the list, the inode cannot be evicted (and the filesystem cannot be unmounted) without shmem_evict_inode() taking that mutex to remove it from the list. But since shmem_writepage() might take that mutex, we should avoid making memory allocations or memcg charges while holding it: prepare them at the outer level in shmem_unuse(). When mem_cgroup_cache_charge() was originally placed, we didn't know until that point that the page from swap was actually a shmem page; but nowadays it's noted in the swap_map, so we're safe to charge upfront. For the radix_tree, do as is done in shmem_getpage(): preload upfront, but don't pin to the cpu; so we make a habit of refreshing the node pool, but might dip into GFP_NOWAIT reserves on occasion if subsequently preempted. With the allocation and charge moved out from shmem_unuse_inode(), we can also hold index map and info->lock over from finding the entry. Signed-off-by: Hugh Dickins Cc: Konstantin Khlebnikov Cc: Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/mm/shmem.c b/mm/shmem.c index 262d711..dc17551 100644 --- a/mm/shmem.c +++ b/mm/shmem.c @@ -852,7 +852,7 @@ static inline int shmem_find_swp(swp_entry_t entry, swp_entry_t *dir, swp_entry_ static int shmem_unuse_inode(struct shmem_inode_info *info, swp_entry_t entry, struct page *page) { - struct inode *inode; + struct address_space *mapping; unsigned long idx; unsigned long size; unsigned long limit; @@ -875,8 +875,10 @@ static int shmem_unuse_inode(struct shmem_inode_info *info, swp_entry_t entry, s if (size > SHMEM_NR_DIRECT) size = SHMEM_NR_DIRECT; offset = shmem_find_swp(entry, ptr, ptr+size); - if (offset >= 0) + if (offset >= 0) { + shmem_swp_balance_unmap(); goto found; + } if (!info->i_indirect) goto lost2; @@ -914,11 +916,11 @@ static int shmem_unuse_inode(struct shmem_inode_info *info, swp_entry_t entry, s if (size > ENTRIES_PER_PAGE) size = ENTRIES_PER_PAGE; offset = shmem_find_swp(entry, ptr, ptr+size); - shmem_swp_unmap(ptr); if (offset >= 0) { shmem_dir_unmap(dir); goto found; } + shmem_swp_unmap(ptr); } } lost1: @@ -928,8 +930,7 @@ lost2: return 0; found: idx += offset; - inode = igrab(&info->vfs_inode); - spin_unlock(&info->lock); + ptr += offset; /* * Move _head_ to start search for next from here. @@ -940,37 +941,18 @@ found: */ if (shmem_swaplist.next != &info->swaplist) list_move_tail(&shmem_swaplist, &info->swaplist); - mutex_unlock(&shmem_swaplist_mutex); - error = 1; - if (!inode) - goto out; /* - * Charge page using GFP_KERNEL while we can wait. - * Charged back to the user(not to caller) when swap account is used. - * add_to_page_cache() will be called with GFP_NOWAIT. + * We rely on shmem_swaplist_mutex, not only to protect the swaplist, + * but also to hold up shmem_evict_inode(): so inode cannot be freed + * beneath us (pagelock doesn't help until the page is in pagecache). */ - error = mem_cgroup_cache_charge(page, current->mm, GFP_KERNEL); - if (error) - goto out; - error = radix_tree_preload(GFP_KERNEL); - if (error) { - mem_cgroup_uncharge_cache_page(page); - goto out; - } - error = 1; - - spin_lock(&info->lock); - ptr = shmem_swp_entry(info, idx, NULL); - if (ptr && ptr->val == entry.val) { - error = add_to_page_cache_locked(page, inode->i_mapping, - idx, GFP_NOWAIT); - /* does mem_cgroup_uncharge_cache_page on error */ - } else /* we must compensate for our precharge above */ - mem_cgroup_uncharge_cache_page(page); + mapping = info->vfs_inode.i_mapping; + error = add_to_page_cache_locked(page, mapping, idx, GFP_NOWAIT); + /* which does mem_cgroup_uncharge_cache_page on error */ if (error == -EEXIST) { - struct page *filepage = find_get_page(inode->i_mapping, idx); + struct page *filepage = find_get_page(mapping, idx); error = 1; if (filepage) { /* @@ -990,14 +972,8 @@ found: swap_free(entry); error = 1; /* not an error, but entry was found */ } - if (ptr) - shmem_swp_unmap(ptr); + shmem_swp_unmap(ptr); spin_unlock(&info->lock); - radix_tree_preload_end(); -out: - unlock_page(page); - page_cache_release(page); - iput(inode); /* allows for NULL */ return error; } @@ -1009,6 +985,26 @@ int shmem_unuse(swp_entry_t entry, struct page *page) struct list_head *p, *next; struct shmem_inode_info *info; int found = 0; + int error; + + /* + * Charge page using GFP_KERNEL while we can wait, before taking + * the shmem_swaplist_mutex which might hold up shmem_writepage(). + * Charged back to the user (not to caller) when swap account is used. + * add_to_page_cache() will be called with GFP_NOWAIT. + */ + error = mem_cgroup_cache_charge(page, current->mm, GFP_KERNEL); + if (error) + goto out; + /* + * Try to preload while we can wait, to not make a habit of + * draining atomic reserves; but don't latch on to this cpu, + * it's okay if sometimes we get rescheduled after this. + */ + error = radix_tree_preload(GFP_KERNEL); + if (error) + goto uncharge; + radix_tree_preload_end(); mutex_lock(&shmem_swaplist_mutex); list_for_each_safe(p, next, &shmem_swaplist) { @@ -1016,17 +1012,19 @@ int shmem_unuse(swp_entry_t entry, struct page *page) found = shmem_unuse_inode(info, entry, page); cond_resched(); if (found) - goto out; + break; } mutex_unlock(&shmem_swaplist_mutex); - /* - * Can some race bring us here? We've been holding page lock, - * so I think not; but would rather try again later than BUG() - */ + +uncharge: + if (!found) + mem_cgroup_uncharge_cache_page(page); + if (found < 0) + error = found; +out: unlock_page(page); page_cache_release(page); -out: - return (found < 0) ? found : 0; + return error; } /* -- cgit v0.10.2 From 59a16ead572330deb38e5848151d30ed1af754bc Mon Sep 17 00:00:00 2001 From: Hugh Dickins Date: Wed, 11 May 2011 15:13:38 -0700 Subject: tmpfs: fix spurious ENOSPC when racing with unswap Testing the shmem_swaplist replacements for igrab() revealed another bug: writes to /dev/loop0 on a tmpfs file which fills its filesystem were sometimes failing with "Buffer I/O error"s. These came from ENOSPC failures of shmem_getpage(), when racing with swapoff: the same could happen when racing with another shmem_getpage(), pulling the page in from swap in between our find_lock_page() and our taking the info->lock (though not in the single-threaded loop case). This is unacceptable, and surprising that I've not noticed it before: it dates back many years, but (presumably) was made a lot easier to reproduce in 2.6.36, which sited a page preallocation in the race window. Fix it by rechecking the page cache before settling on an ENOSPC error. Signed-off-by: Hugh Dickins Cc: Konstantin Khlebnikov Cc: Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/mm/shmem.c b/mm/shmem.c index dc17551..9e755c1 100644 --- a/mm/shmem.c +++ b/mm/shmem.c @@ -1407,20 +1407,14 @@ repeat: if (sbinfo->max_blocks) { if (percpu_counter_compare(&sbinfo->used_blocks, sbinfo->max_blocks) >= 0 || - shmem_acct_block(info->flags)) { - spin_unlock(&info->lock); - error = -ENOSPC; - goto failed; - } + shmem_acct_block(info->flags)) + goto nospace; percpu_counter_inc(&sbinfo->used_blocks); spin_lock(&inode->i_lock); inode->i_blocks += BLOCKS_PER_PAGE; spin_unlock(&inode->i_lock); - } else if (shmem_acct_block(info->flags)) { - spin_unlock(&info->lock); - error = -ENOSPC; - goto failed; - } + } else if (shmem_acct_block(info->flags)) + goto nospace; if (!filepage) { int ret; @@ -1500,6 +1494,24 @@ done: error = 0; goto out; +nospace: + /* + * Perhaps the page was brought in from swap between find_lock_page + * and taking info->lock? We allow for that at add_to_page_cache_lru, + * but must also avoid reporting a spurious ENOSPC while working on a + * full tmpfs. (When filepage has been passed in to shmem_getpage, it + * is already in page cache, which prevents this race from occurring.) + */ + if (!filepage) { + struct page *page = find_get_page(mapping, idx); + if (page) { + spin_unlock(&info->lock); + page_cache_release(page); + goto repeat; + } + } + spin_unlock(&info->lock); + error = -ENOSPC; failed: if (*pagep != filepage) { unlock_page(filepage); -- cgit v0.10.2 From 1d929b7a84438ad9012c5826f5617d79a3efcef1 Mon Sep 17 00:00:00 2001 From: Mel Gorman Date: Wed, 11 May 2011 15:13:39 -0700 Subject: mm: tracing: add missing GFP flags to tracing include/linux/gfp.h and include/trace/events/gfpflags.h are out of sync. When tracing is enabled, certain flags are not recognised and the text output is less useful as a result. Add the missing flags. Signed-off-by: Mel Gorman Cc: Andrea Arcangeli Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/include/trace/events/gfpflags.h b/include/trace/events/gfpflags.h index e3615c0..9fe3a36 100644 --- a/include/trace/events/gfpflags.h +++ b/include/trace/events/gfpflags.h @@ -10,6 +10,7 @@ */ #define show_gfp_flags(flags) \ (flags) ? __print_flags(flags, "|", \ + {(unsigned long)GFP_TRANSHUGE, "GFP_TRANSHUGE"}, \ {(unsigned long)GFP_HIGHUSER_MOVABLE, "GFP_HIGHUSER_MOVABLE"}, \ {(unsigned long)GFP_HIGHUSER, "GFP_HIGHUSER"}, \ {(unsigned long)GFP_USER, "GFP_USER"}, \ @@ -32,6 +33,9 @@ {(unsigned long)__GFP_HARDWALL, "GFP_HARDWALL"}, \ {(unsigned long)__GFP_THISNODE, "GFP_THISNODE"}, \ {(unsigned long)__GFP_RECLAIMABLE, "GFP_RECLAIMABLE"}, \ - {(unsigned long)__GFP_MOVABLE, "GFP_MOVABLE"} \ + {(unsigned long)__GFP_MOVABLE, "GFP_MOVABLE"}, \ + {(unsigned long)__GFP_NOTRACK, "GFP_NOTRACK"}, \ + {(unsigned long)__GFP_NO_KSWAPD, "GFP_NO_KSWAPD"}, \ + {(unsigned long)__GFP_OTHER_NODE, "GFP_OTHER_NODE"} \ ) : "GFP_NOWAIT" -- cgit v0.10.2 From ce8453776d68982cfe93bcb28191af8ccad01f45 Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Wed, 11 May 2011 18:58:16 -0700 Subject: Revert "Bluetooth: fix shutdown on SCO sockets" This reverts commit f21ca5fff6e548833fa5ee8867239a8378623150. Quoth Gustavo F. Padovan: "Commit f21ca5fff6e548833fa5ee8867239a8378623150 can cause a NULL dereference if we call shutdown in a bluetooth SCO socket and doesn't wait the shutdown completion to call close(). Please revert it. I may have a fix for it soon, but we don't have time anymore, so revert is the way to go. ;)" Requested-by: Gustavo F. Padovan Signed-off-by: Linus Torvalds diff --git a/net/bluetooth/sco.c b/net/bluetooth/sco.c index 94954c7..42fdffd 100644 --- a/net/bluetooth/sco.c +++ b/net/bluetooth/sco.c @@ -369,15 +369,6 @@ static void __sco_sock_close(struct sock *sk) case BT_CONNECTED: case BT_CONFIG: - if (sco_pi(sk)->conn) { - sk->sk_state = BT_DISCONN; - sco_sock_set_timer(sk, SCO_DISCONN_TIMEOUT); - hci_conn_put(sco_pi(sk)->conn->hcon); - sco_pi(sk)->conn = NULL; - } else - sco_chan_del(sk, ECONNRESET); - break; - case BT_CONNECT: case BT_DISCONN: sco_chan_del(sk, ECONNRESET); -- cgit v0.10.2 From a75b9df9d3bfc3cd1083974c045ae31ce5f3434f Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Wed, 11 May 2011 18:00:51 -0400 Subject: NFSv4.1: Ensure that layoutget uses the correct gfp modes Currently, writebacks may end up recursing back into the filesystem due to GFP_KERNEL direct reclaims in the pnfs subsystem. Signed-off-by: Trond Myklebust diff --git a/fs/nfs/nfs4filelayout.c b/fs/nfs/nfs4filelayout.c index 7841ea6..be79dc9 100644 --- a/fs/nfs/nfs4filelayout.c +++ b/fs/nfs/nfs4filelayout.c @@ -418,7 +418,8 @@ static int filelayout_check_layout(struct pnfs_layout_hdr *lo, struct nfs4_filelayout_segment *fl, struct nfs4_layoutget_res *lgr, - struct nfs4_deviceid *id) + struct nfs4_deviceid *id, + gfp_t gfp_flags) { struct nfs4_file_layout_dsaddr *dsaddr; int status = -EINVAL; @@ -441,7 +442,7 @@ filelayout_check_layout(struct pnfs_layout_hdr *lo, /* find and reference the deviceid */ dsaddr = nfs4_fl_find_get_deviceid(id); if (dsaddr == NULL) { - dsaddr = get_device_info(lo->plh_inode, id); + dsaddr = get_device_info(lo->plh_inode, id, gfp_flags); if (dsaddr == NULL) goto out; } @@ -502,7 +503,8 @@ static int filelayout_decode_layout(struct pnfs_layout_hdr *flo, struct nfs4_filelayout_segment *fl, struct nfs4_layoutget_res *lgr, - struct nfs4_deviceid *id) + struct nfs4_deviceid *id, + gfp_t gfp_flags) { struct xdr_stream stream; struct xdr_buf buf = { @@ -518,7 +520,7 @@ filelayout_decode_layout(struct pnfs_layout_hdr *flo, dprintk("%s: set_layout_map Begin\n", __func__); - scratch = alloc_page(GFP_KERNEL); + scratch = alloc_page(gfp_flags); if (!scratch) return -ENOMEM; @@ -556,13 +558,13 @@ filelayout_decode_layout(struct pnfs_layout_hdr *flo, goto out_err; fl->fh_array = kzalloc(fl->num_fh * sizeof(struct nfs_fh *), - GFP_KERNEL); + gfp_flags); if (!fl->fh_array) goto out_err; for (i = 0; i < fl->num_fh; i++) { /* Do we want to use a mempool here? */ - fl->fh_array[i] = kmalloc(sizeof(struct nfs_fh), GFP_KERNEL); + fl->fh_array[i] = kmalloc(sizeof(struct nfs_fh), gfp_flags); if (!fl->fh_array[i]) goto out_err_free; @@ -607,19 +609,20 @@ filelayout_free_lseg(struct pnfs_layout_segment *lseg) static struct pnfs_layout_segment * filelayout_alloc_lseg(struct pnfs_layout_hdr *layoutid, - struct nfs4_layoutget_res *lgr) + struct nfs4_layoutget_res *lgr, + gfp_t gfp_flags) { struct nfs4_filelayout_segment *fl; int rc; struct nfs4_deviceid id; dprintk("--> %s\n", __func__); - fl = kzalloc(sizeof(*fl), GFP_KERNEL); + fl = kzalloc(sizeof(*fl), gfp_flags); if (!fl) return NULL; - rc = filelayout_decode_layout(layoutid, fl, lgr, &id); - if (rc != 0 || filelayout_check_layout(layoutid, fl, lgr, &id)) { + rc = filelayout_decode_layout(layoutid, fl, lgr, &id, gfp_flags); + if (rc != 0 || filelayout_check_layout(layoutid, fl, lgr, &id, gfp_flags)) { _filelayout_free_lseg(fl); return NULL; } @@ -635,7 +638,7 @@ filelayout_alloc_lseg(struct pnfs_layout_hdr *layoutid, int size = (fl->stripe_type == STRIPE_SPARSE) ? fl->dsaddr->ds_num : fl->dsaddr->stripe_count; - fl->commit_buckets = kcalloc(size, sizeof(struct list_head), GFP_KERNEL); + fl->commit_buckets = kcalloc(size, sizeof(struct list_head), gfp_flags); if (!fl->commit_buckets) { filelayout_free_lseg(&fl->generic_hdr); return NULL; diff --git a/fs/nfs/nfs4filelayout.h b/fs/nfs/nfs4filelayout.h index 7c44579..2b461d7 100644 --- a/fs/nfs/nfs4filelayout.h +++ b/fs/nfs/nfs4filelayout.h @@ -104,6 +104,6 @@ extern struct nfs4_file_layout_dsaddr * nfs4_fl_find_get_deviceid(struct nfs4_deviceid *dev_id); extern void nfs4_fl_put_deviceid(struct nfs4_file_layout_dsaddr *dsaddr); struct nfs4_file_layout_dsaddr * -get_device_info(struct inode *inode, struct nfs4_deviceid *dev_id); +get_device_info(struct inode *inode, struct nfs4_deviceid *dev_id, gfp_t gfp_flags); #endif /* FS_NFS_NFS4FILELAYOUT_H */ diff --git a/fs/nfs/nfs4filelayoutdev.c b/fs/nfs/nfs4filelayoutdev.c index de5350f..db07c7a 100644 --- a/fs/nfs/nfs4filelayoutdev.c +++ b/fs/nfs/nfs4filelayoutdev.c @@ -225,11 +225,11 @@ nfs4_fl_free_deviceid(struct nfs4_file_layout_dsaddr *dsaddr) } static struct nfs4_pnfs_ds * -nfs4_pnfs_ds_add(struct inode *inode, u32 ip_addr, u32 port) +nfs4_pnfs_ds_add(struct inode *inode, u32 ip_addr, u32 port, gfp_t gfp_flags) { struct nfs4_pnfs_ds *tmp_ds, *ds; - ds = kzalloc(sizeof(*tmp_ds), GFP_KERNEL); + ds = kzalloc(sizeof(*tmp_ds), gfp_flags); if (!ds) goto out; @@ -261,7 +261,7 @@ out: * Currently only support ipv4, and one multi-path address. */ static struct nfs4_pnfs_ds * -decode_and_add_ds(struct xdr_stream *streamp, struct inode *inode) +decode_and_add_ds(struct xdr_stream *streamp, struct inode *inode, gfp_t gfp_flags) { struct nfs4_pnfs_ds *ds = NULL; char *buf; @@ -303,7 +303,7 @@ decode_and_add_ds(struct xdr_stream *streamp, struct inode *inode) rlen); goto out_err; } - buf = kmalloc(rlen + 1, GFP_KERNEL); + buf = kmalloc(rlen + 1, gfp_flags); if (!buf) { dprintk("%s: Not enough memory\n", __func__); goto out_err; @@ -333,7 +333,7 @@ decode_and_add_ds(struct xdr_stream *streamp, struct inode *inode) sscanf(pstr, "-%d-%d", &tmp[0], &tmp[1]); port = htons((tmp[0] << 8) | (tmp[1])); - ds = nfs4_pnfs_ds_add(inode, ip_addr, port); + ds = nfs4_pnfs_ds_add(inode, ip_addr, port, gfp_flags); dprintk("%s: Decoded address and port %s\n", __func__, buf); out_free: kfree(buf); @@ -343,7 +343,7 @@ out_err: /* Decode opaque device data and return the result */ static struct nfs4_file_layout_dsaddr* -decode_device(struct inode *ino, struct pnfs_device *pdev) +decode_device(struct inode *ino, struct pnfs_device *pdev, gfp_t gfp_flags) { int i; u32 cnt, num; @@ -362,7 +362,7 @@ decode_device(struct inode *ino, struct pnfs_device *pdev) struct page *scratch; /* set up xdr stream */ - scratch = alloc_page(GFP_KERNEL); + scratch = alloc_page(gfp_flags); if (!scratch) goto out_err; @@ -384,7 +384,7 @@ decode_device(struct inode *ino, struct pnfs_device *pdev) } /* read stripe indices */ - stripe_indices = kcalloc(cnt, sizeof(u8), GFP_KERNEL); + stripe_indices = kcalloc(cnt, sizeof(u8), gfp_flags); if (!stripe_indices) goto out_err_free_scratch; @@ -423,7 +423,7 @@ decode_device(struct inode *ino, struct pnfs_device *pdev) dsaddr = kzalloc(sizeof(*dsaddr) + (sizeof(struct nfs4_pnfs_ds *) * (num - 1)), - GFP_KERNEL); + gfp_flags); if (!dsaddr) goto out_err_free_stripe_indices; @@ -452,7 +452,7 @@ decode_device(struct inode *ino, struct pnfs_device *pdev) for (j = 0; j < mp_count; j++) { if (j == 0) { dsaddr->ds_list[i] = decode_and_add_ds(&stream, - ino); + ino, gfp_flags); if (dsaddr->ds_list[i] == NULL) goto out_err_free_deviceid; } else { @@ -503,12 +503,12 @@ out_err: * available devices. */ static struct nfs4_file_layout_dsaddr * -decode_and_add_device(struct inode *inode, struct pnfs_device *dev) +decode_and_add_device(struct inode *inode, struct pnfs_device *dev, gfp_t gfp_flags) { struct nfs4_file_layout_dsaddr *d, *new; long hash; - new = decode_device(inode, dev); + new = decode_device(inode, dev, gfp_flags); if (!new) { printk(KERN_WARNING "%s: Could not decode or add device\n", __func__); @@ -537,7 +537,7 @@ decode_and_add_device(struct inode *inode, struct pnfs_device *dev) * of available devices, and return it. */ struct nfs4_file_layout_dsaddr * -get_device_info(struct inode *inode, struct nfs4_deviceid *dev_id) +get_device_info(struct inode *inode, struct nfs4_deviceid *dev_id, gfp_t gfp_flags) { struct pnfs_device *pdev = NULL; u32 max_resp_sz; @@ -556,17 +556,17 @@ get_device_info(struct inode *inode, struct nfs4_deviceid *dev_id) dprintk("%s inode %p max_resp_sz %u max_pages %d\n", __func__, inode, max_resp_sz, max_pages); - pdev = kzalloc(sizeof(struct pnfs_device), GFP_KERNEL); + pdev = kzalloc(sizeof(struct pnfs_device), gfp_flags); if (pdev == NULL) return NULL; - pages = kzalloc(max_pages * sizeof(struct page *), GFP_KERNEL); + pages = kzalloc(max_pages * sizeof(struct page *), gfp_flags); if (pages == NULL) { kfree(pdev); return NULL; } for (i = 0; i < max_pages; i++) { - pages[i] = alloc_page(GFP_KERNEL); + pages[i] = alloc_page(gfp_flags); if (!pages[i]) goto out_free; } @@ -587,7 +587,7 @@ get_device_info(struct inode *inode, struct nfs4_deviceid *dev_id) * Found new device, need to decode it and then add it to the * list of known devices for this mountpoint. */ - dsaddr = decode_and_add_device(inode, pdev); + dsaddr = decode_and_add_device(inode, pdev, gfp_flags); out_free: for (i = 0; i < max_pages; i++) __free_page(pages[i]); diff --git a/fs/nfs/pnfs.c b/fs/nfs/pnfs.c index 65455f5..f57f528 100644 --- a/fs/nfs/pnfs.c +++ b/fs/nfs/pnfs.c @@ -467,7 +467,8 @@ pnfs_choose_layoutget_stateid(nfs4_stateid *dst, struct pnfs_layout_hdr *lo, static struct pnfs_layout_segment * send_layoutget(struct pnfs_layout_hdr *lo, struct nfs_open_context *ctx, - u32 iomode) + u32 iomode, + gfp_t gfp_flags) { struct inode *ino = lo->plh_inode; struct nfs_server *server = NFS_SERVER(ino); @@ -480,7 +481,7 @@ send_layoutget(struct pnfs_layout_hdr *lo, dprintk("--> %s\n", __func__); BUG_ON(ctx == NULL); - lgp = kzalloc(sizeof(*lgp), GFP_KERNEL); + lgp = kzalloc(sizeof(*lgp), gfp_flags); if (lgp == NULL) return NULL; @@ -488,12 +489,12 @@ send_layoutget(struct pnfs_layout_hdr *lo, max_resp_sz = server->nfs_client->cl_session->fc_attrs.max_resp_sz; max_pages = max_resp_sz >> PAGE_SHIFT; - pages = kzalloc(max_pages * sizeof(struct page *), GFP_KERNEL); + pages = kzalloc(max_pages * sizeof(struct page *), gfp_flags); if (!pages) goto out_err_free; for (i = 0; i < max_pages; i++) { - pages[i] = alloc_page(GFP_KERNEL); + pages[i] = alloc_page(gfp_flags); if (!pages[i]) goto out_err_free; } @@ -509,6 +510,7 @@ send_layoutget(struct pnfs_layout_hdr *lo, lgp->args.layout.pages = pages; lgp->args.layout.pglen = max_pages * PAGE_SIZE; lgp->lsegpp = &lseg; + lgp->gfp_flags = gfp_flags; /* Synchronously retrieve layout information from server and * store in lseg. @@ -666,11 +668,11 @@ pnfs_insert_layout(struct pnfs_layout_hdr *lo, } static struct pnfs_layout_hdr * -alloc_init_layout_hdr(struct inode *ino) +alloc_init_layout_hdr(struct inode *ino, gfp_t gfp_flags) { struct pnfs_layout_hdr *lo; - lo = kzalloc(sizeof(struct pnfs_layout_hdr), GFP_KERNEL); + lo = kzalloc(sizeof(struct pnfs_layout_hdr), gfp_flags); if (!lo) return NULL; atomic_set(&lo->plh_refcount, 1); @@ -682,7 +684,7 @@ alloc_init_layout_hdr(struct inode *ino) } static struct pnfs_layout_hdr * -pnfs_find_alloc_layout(struct inode *ino) +pnfs_find_alloc_layout(struct inode *ino, gfp_t gfp_flags) { struct nfs_inode *nfsi = NFS_I(ino); struct pnfs_layout_hdr *new = NULL; @@ -697,7 +699,7 @@ pnfs_find_alloc_layout(struct inode *ino) return nfsi->layout; } spin_unlock(&ino->i_lock); - new = alloc_init_layout_hdr(ino); + new = alloc_init_layout_hdr(ino, gfp_flags); spin_lock(&ino->i_lock); if (likely(nfsi->layout == NULL)) /* Won the race? */ @@ -757,7 +759,8 @@ pnfs_find_lseg(struct pnfs_layout_hdr *lo, u32 iomode) struct pnfs_layout_segment * pnfs_update_layout(struct inode *ino, struct nfs_open_context *ctx, - enum pnfs_iomode iomode) + enum pnfs_iomode iomode, + gfp_t gfp_flags) { struct nfs_inode *nfsi = NFS_I(ino); struct nfs_client *clp = NFS_SERVER(ino)->nfs_client; @@ -768,7 +771,7 @@ pnfs_update_layout(struct inode *ino, if (!pnfs_enabled_sb(NFS_SERVER(ino))) return NULL; spin_lock(&ino->i_lock); - lo = pnfs_find_alloc_layout(ino); + lo = pnfs_find_alloc_layout(ino, gfp_flags); if (lo == NULL) { dprintk("%s ERROR: can't get pnfs_layout_hdr\n", __func__); goto out_unlock; @@ -808,7 +811,7 @@ pnfs_update_layout(struct inode *ino, spin_unlock(&clp->cl_lock); } - lseg = send_layoutget(lo, ctx, iomode); + lseg = send_layoutget(lo, ctx, iomode, gfp_flags); if (!lseg && first) { spin_lock(&clp->cl_lock); list_del_init(&lo->plh_layouts); @@ -847,7 +850,7 @@ pnfs_layout_process(struct nfs4_layoutget *lgp) goto out; } /* Inject layout blob into I/O device driver */ - lseg = NFS_SERVER(ino)->pnfs_curr_ld->alloc_lseg(lo, res); + lseg = NFS_SERVER(ino)->pnfs_curr_ld->alloc_lseg(lo, res, lgp->gfp_flags); if (!lseg || IS_ERR(lseg)) { if (!lseg) status = -ENOMEM; @@ -900,7 +903,8 @@ static int pnfs_read_pg_test(struct nfs_pageio_descriptor *pgio, /* This is first coelesce call for a series of nfs_pages */ pgio->pg_lseg = pnfs_update_layout(pgio->pg_inode, prev->wb_context, - IOMODE_READ); + IOMODE_READ, + GFP_KERNEL); } return NFS_SERVER(pgio->pg_inode)->pnfs_curr_ld->pg_test(pgio, prev, req); } @@ -922,7 +926,8 @@ static int pnfs_write_pg_test(struct nfs_pageio_descriptor *pgio, /* This is first coelesce call for a series of nfs_pages */ pgio->pg_lseg = pnfs_update_layout(pgio->pg_inode, prev->wb_context, - IOMODE_RW); + IOMODE_RW, + GFP_NOFS); } return NFS_SERVER(pgio->pg_inode)->pnfs_curr_ld->pg_test(pgio, prev, req); } diff --git a/fs/nfs/pnfs.h b/fs/nfs/pnfs.h index bc48272..0c015ba 100644 --- a/fs/nfs/pnfs.h +++ b/fs/nfs/pnfs.h @@ -70,7 +70,7 @@ struct pnfs_layoutdriver_type { const u32 id; const char *name; struct module *owner; - struct pnfs_layout_segment * (*alloc_lseg) (struct pnfs_layout_hdr *layoutid, struct nfs4_layoutget_res *lgr); + struct pnfs_layout_segment * (*alloc_lseg) (struct pnfs_layout_hdr *layoutid, struct nfs4_layoutget_res *lgr, gfp_t gfp_flags); void (*free_lseg) (struct pnfs_layout_segment *lseg); /* test for nfs page cache coalescing */ @@ -126,7 +126,7 @@ void get_layout_hdr(struct pnfs_layout_hdr *lo); void put_lseg(struct pnfs_layout_segment *lseg); struct pnfs_layout_segment * pnfs_update_layout(struct inode *ino, struct nfs_open_context *ctx, - enum pnfs_iomode access_type); + enum pnfs_iomode access_type, gfp_t gfp_flags); void set_pnfs_layoutdriver(struct nfs_server *, u32 id); void unset_pnfs_layoutdriver(struct nfs_server *); enum pnfs_try_status pnfs_try_to_write_data(struct nfs_write_data *, @@ -245,7 +245,7 @@ static inline void put_lseg(struct pnfs_layout_segment *lseg) static inline struct pnfs_layout_segment * pnfs_update_layout(struct inode *ino, struct nfs_open_context *ctx, - enum pnfs_iomode access_type) + enum pnfs_iomode access_type, gfp_t gfp_flags) { return NULL; } diff --git a/fs/nfs/read.c b/fs/nfs/read.c index 7cded2b..2bcf0dc 100644 --- a/fs/nfs/read.c +++ b/fs/nfs/read.c @@ -288,7 +288,7 @@ static int nfs_pagein_multi(struct nfs_pageio_descriptor *desc) atomic_set(&req->wb_complete, requests); BUG_ON(desc->pg_lseg != NULL); - lseg = pnfs_update_layout(desc->pg_inode, req->wb_context, IOMODE_READ); + lseg = pnfs_update_layout(desc->pg_inode, req->wb_context, IOMODE_READ, GFP_KERNEL); ClearPageError(page); offset = 0; nbytes = desc->pg_count; @@ -351,7 +351,7 @@ static int nfs_pagein_one(struct nfs_pageio_descriptor *desc) } req = nfs_list_entry(data->pages.next); if ((!lseg) && list_is_singular(&data->pages)) - lseg = pnfs_update_layout(desc->pg_inode, req->wb_context, IOMODE_READ); + lseg = pnfs_update_layout(desc->pg_inode, req->wb_context, IOMODE_READ, GFP_KERNEL); ret = nfs_read_rpcsetup(req, data, &nfs_read_full_ops, desc->pg_count, 0, lseg); diff --git a/fs/nfs/write.c b/fs/nfs/write.c index 3bd5d7e..49c715b 100644 --- a/fs/nfs/write.c +++ b/fs/nfs/write.c @@ -939,7 +939,7 @@ static int nfs_flush_multi(struct nfs_pageio_descriptor *desc) atomic_set(&req->wb_complete, requests); BUG_ON(desc->pg_lseg); - lseg = pnfs_update_layout(desc->pg_inode, req->wb_context, IOMODE_RW); + lseg = pnfs_update_layout(desc->pg_inode, req->wb_context, IOMODE_RW, GFP_NOFS); ClearPageError(page); offset = 0; nbytes = desc->pg_count; @@ -1013,7 +1013,7 @@ static int nfs_flush_one(struct nfs_pageio_descriptor *desc) } req = nfs_list_entry(data->pages.next); if ((!lseg) && list_is_singular(&data->pages)) - lseg = pnfs_update_layout(desc->pg_inode, req->wb_context, IOMODE_RW); + lseg = pnfs_update_layout(desc->pg_inode, req->wb_context, IOMODE_RW, GFP_NOFS); if ((desc->pg_ioflags & FLUSH_COND_STABLE) && (desc->pg_moreio || NFS_I(desc->pg_inode)->ncommit)) diff --git a/include/linux/nfs_xdr.h b/include/linux/nfs_xdr.h index 890dce2..7e371f7 100644 --- a/include/linux/nfs_xdr.h +++ b/include/linux/nfs_xdr.h @@ -233,6 +233,7 @@ struct nfs4_layoutget { struct nfs4_layoutget_args args; struct nfs4_layoutget_res res; struct pnfs_layout_segment **lsegpp; + gfp_t gfp_flags; }; struct nfs4_getdeviceinfo_args { -- cgit v0.10.2 From 21ccc7936dac5ca9b3e2838bbc112a60f34e18b3 Mon Sep 17 00:00:00 2001 From: Anton Blanchard Date: Tue, 10 May 2011 16:17:10 +0000 Subject: ehea: Fix memory hotplug oops The ehea driver oopses during memory hotplug if the ports are not up. A simple testcase: # ifconfig ethX down # echo offline > /sys/devices/system/memory/memory32/state Oops: Kernel access of bad area, sig: 11 [#1] last sysfs file: /sys/devices/system/memory/memory32/state REGS: c000000709393110 TRAP: 0300 Not tainted (2.6.39-rc2-01385-g7ef73bc-dirty) DAR: 0000000000000000, DSISR: 40000000 ... NIP [c000000000067c98] .__wake_up_common+0x48/0xf0 LR [c00000000006d034] .__wake_up+0x54/0x90 Call Trace: [c00000000006d034] .__wake_up+0x54/0x90 [d000000006bb6270] .ehea_rereg_mrs+0x140/0x730 [ehea] [d000000006bb69c4] .ehea_mem_notifier+0x164/0x170 [ehea] [c0000000006fc8a8] .notifier_call_chain+0x78/0xf0 [c0000000000b3d70] .__blocking_notifier_call_chain+0x70/0xb0 [c000000000458d78] .memory_notify+0x28/0x40 [c0000000001871d8] .remove_memory+0x208/0x6d0 [c000000000458264] .memory_section_action+0x94/0x140 [c0000000004583ec] .memory_block_change_state+0xdc/0x1d0 [c0000000004585cc] .store_mem_state+0xec/0x160 [c00000000044768c] .sysdev_store+0x3c/0x50 [c00000000020b48c] .sysfs_write_file+0xec/0x1f0 [c00000000018f86c] .vfs_write+0xec/0x1e0 [c00000000018fa88] .SyS_write+0x58/0xd0 To fix this, initialise the waitqueues during port probe instead of port open. Signed-off-by: Anton Blanchard Cc: stable@kernel.org Acked-by: Breno Leitao Signed-off-by: David S. Miller diff --git a/drivers/net/ehea/ehea_main.c b/drivers/net/ehea/ehea_main.c index 53c0f04..cf79cf7 100644 --- a/drivers/net/ehea/ehea_main.c +++ b/drivers/net/ehea/ehea_main.c @@ -2688,9 +2688,6 @@ static int ehea_open(struct net_device *dev) netif_start_queue(dev); } - init_waitqueue_head(&port->swqe_avail_wq); - init_waitqueue_head(&port->restart_wq); - mutex_unlock(&port->port_lock); return ret; @@ -3276,6 +3273,9 @@ struct ehea_port *ehea_setup_single_port(struct ehea_adapter *adapter, INIT_WORK(&port->reset_task, ehea_reset_port); + init_waitqueue_head(&port->swqe_avail_wq); + init_waitqueue_head(&port->restart_wq); + ret = register_netdev(dev); if (ret) { pr_err("register_netdev failed. ret=%d\n", ret); -- cgit v0.10.2 From b1054282d752c5a026e2c0450616ebf37fc0413e Mon Sep 17 00:00:00 2001 From: Tkhai Kirill Date: Tue, 10 May 2011 02:31:41 +0000 Subject: sparc32: Fixed unaligned memory copying in function __csum_partial_copy_sparc_generic When we are in the label cc_dword_align, registers %o0 and %o1 have the same last 2 bits, but it's not guaranteed one of them is zero. So we can get unaligned memory access in label ccte. Example of parameters which lead to this: %o0=0x7ff183e9, %o1=0x8e709e7d, %g1=3 With the parameters I had a memory corruption, when the additional 5 bytes were rewritten. This patch corrects the error. One comment to the patch. We don't care about the third bit in %o1, because cc_end_cruft stores word or less. Signed-off-by: Tkhai Kirill Signed-off-by: David S. Miller diff --git a/arch/sparc/lib/checksum_32.S b/arch/sparc/lib/checksum_32.S index 3632cb3..0084c33 100644 --- a/arch/sparc/lib/checksum_32.S +++ b/arch/sparc/lib/checksum_32.S @@ -289,10 +289,16 @@ cc_end_cruft: /* Also, handle the alignment code out of band. */ cc_dword_align: - cmp %g1, 6 - bl,a ccte + cmp %g1, 16 + bge 1f + srl %g1, 1, %o3 +2: cmp %o3, 0 + be,a ccte andcc %g1, 0xf, %o3 - andcc %o0, 0x1, %g0 + andcc %o3, %o0, %g0 ! Check %o0 only (%o1 has the same last 2 bits) + be,a 2b + srl %o3, 1, %o3 +1: andcc %o0, 0x1, %g0 bne ccslow andcc %o0, 0x2, %g0 be 1f -- cgit v0.10.2 From 55183d06cd1bd939ceccdad628b0aae12c86b803 Mon Sep 17 00:00:00 2001 From: "Gustavo F. Padovan" Date: Wed, 11 May 2011 19:26:06 -0300 Subject: Bluetooth: Remove leftover debug messages They were added by me while testing and I forgot to remove. Signed-off-by: Gustavo F. Padovan diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index d0769a8..a5ab4a2 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -2095,7 +2095,7 @@ static inline int l2cap_connect_req(struct l2cap_conn *conn, struct l2cap_cmd_hd u16 dcid = 0, scid = __le16_to_cpu(req->scid); __le16 psm = req->psm; - BT_ERR("psm 0x%2.2x scid 0x%4.4x", psm, scid); + BT_DBG("psm 0x%2.2x scid 0x%4.4x", psm, scid); /* Check if we have socket listening on psm */ pchan = l2cap_global_chan_by_psm(BT_LISTEN, psm, conn->src); @@ -2104,8 +2104,6 @@ static inline int l2cap_connect_req(struct l2cap_conn *conn, struct l2cap_cmd_hd goto sendresp; } - BT_ERR("%p 0x%2.2x", pchan, pchan->psm); - parent = pchan->sk; bh_lock_sock(parent); -- cgit v0.10.2 From 3e51e3edfd81bfd9853ad7de91167e4ce33d0fe7 Mon Sep 17 00:00:00 2001 From: Samir Bellabes Date: Wed, 11 May 2011 18:18:05 +0200 Subject: sched: Remove unused parameters from sched_fork() and wake_up_new_task() sched_fork() and wake_up_new_task() are defined with a parameter 'unsigned long clone_flags', which is unused. This patch removes the parameters. Signed-off-by: Samir Bellabes Acked-by: Peter Zijlstra Link: http://lkml.kernel.org/r/1305130685-1047-1-git-send-email-sam@synack.fr Signed-off-by: Ingo Molnar diff --git a/include/linux/sched.h b/include/linux/sched.h index 6b4280b..12211e1 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h @@ -2051,14 +2051,13 @@ extern void xtime_update(unsigned long ticks); extern int wake_up_state(struct task_struct *tsk, unsigned int state); extern int wake_up_process(struct task_struct *tsk); -extern void wake_up_new_task(struct task_struct *tsk, - unsigned long clone_flags); +extern void wake_up_new_task(struct task_struct *tsk); #ifdef CONFIG_SMP extern void kick_process(struct task_struct *tsk); #else static inline void kick_process(struct task_struct *tsk) { } #endif -extern void sched_fork(struct task_struct *p, int clone_flags); +extern void sched_fork(struct task_struct *p); extern void sched_dead(struct task_struct *p); extern void proc_caches_init(void); diff --git a/kernel/fork.c b/kernel/fork.c index aca6287..2b44d82 100644 --- a/kernel/fork.c +++ b/kernel/fork.c @@ -1152,7 +1152,7 @@ static struct task_struct *copy_process(unsigned long clone_flags, #endif /* Perform scheduler related setup. Assign this task to a CPU. */ - sched_fork(p, clone_flags); + sched_fork(p); retval = perf_event_init_task(p); if (retval) @@ -1463,7 +1463,7 @@ long do_fork(unsigned long clone_flags, */ p->flags &= ~PF_STARTING; - wake_up_new_task(p, clone_flags); + wake_up_new_task(p); tracehook_report_clone_complete(trace, regs, clone_flags, nr, p); diff --git a/kernel/sched.c b/kernel/sched.c index da93381..f9778c0 100644 --- a/kernel/sched.c +++ b/kernel/sched.c @@ -2741,7 +2741,7 @@ static void __sched_fork(struct task_struct *p) /* * fork()/clone()-time setup: */ -void sched_fork(struct task_struct *p, int clone_flags) +void sched_fork(struct task_struct *p) { unsigned long flags; int cpu = get_cpu(); @@ -2823,7 +2823,7 @@ void sched_fork(struct task_struct *p, int clone_flags) * that must be done for every newly created context, then puts the task * on the runqueue and wakes it. */ -void wake_up_new_task(struct task_struct *p, unsigned long clone_flags) +void wake_up_new_task(struct task_struct *p) { unsigned long flags; struct rq *rq; -- cgit v0.10.2 From 9af386c8dc5a9dce56f36b484647ad6401758c85 Mon Sep 17 00:00:00 2001 From: Will Deacon Date: Thu, 28 Apr 2011 18:44:31 +0100 Subject: ARM: 6890/1: memmap: only free allocated memmap entries when using SPARSEMEM The SPARSEMEM code allocates memmap entries only for sections which are present (i.e. those which contain some valid memory). The membank checks in free_unused_memmap do not take this into account and can incorrectly attempt to free memory which is not allocated, resulting in a BUG() in the bootmem code. However, if memory is configured as follows: |<----section---->|<----hole---->|<----section---->| +--------+--------+--------------+--------+--------+ | bank 0 | unused | | bank 1 | unused | +--------+--------+--------------+--------+--------+ where a bank only occupies part of a section, the memmap allocated for the remainder of the section *can* be freed. This patch modifies the checks in free_unused_memmap so that only valid memmap entries are considered for removal. Acked-by: Catalin Marinas Signed-off-by: Will Deacon Signed-off-by: Russell King diff --git a/arch/arm/mm/init.c b/arch/arm/mm/init.c index e5f6fc4..e591513 100644 --- a/arch/arm/mm/init.c +++ b/arch/arm/mm/init.c @@ -392,7 +392,7 @@ free_memmap(unsigned long start_pfn, unsigned long end_pfn) * Convert start_pfn/end_pfn to a struct page pointer. */ start_pg = pfn_to_page(start_pfn - 1) + 1; - end_pg = pfn_to_page(end_pfn); + end_pg = pfn_to_page(end_pfn - 1) + 1; /* * Convert to physical addresses, and @@ -426,6 +426,14 @@ static void __init free_unused_memmap(struct meminfo *mi) bank_start = bank_pfn_start(bank); +#ifdef CONFIG_SPARSEMEM + /* + * Take care not to free memmap entries that don't exist + * due to SPARSEMEM sections which aren't present. + */ + bank_start = min(bank_start, + ALIGN(prev_bank_end, PAGES_PER_SECTION)); +#endif /* * If we had a previous bank, and there is a space * between the current bank and the previous, free it. @@ -440,6 +448,12 @@ static void __init free_unused_memmap(struct meminfo *mi) */ prev_bank_end = ALIGN(bank_pfn_end(bank), MAX_ORDER_NR_PAGES); } + +#ifdef CONFIG_SPARSEMEM + if (!IS_ALIGNED(prev_bank_end, PAGES_PER_SECTION)) + free_memmap(prev_bank_end, + ALIGN(prev_bank_end, PAGES_PER_SECTION)); +#endif } static void __init free_highpages(void) -- cgit v0.10.2 From 2af68df02fe5ccd644f4312ba2401996f52faab3 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Tue, 3 May 2011 18:32:55 +0100 Subject: ARM: 6892/1: handle ptrace requests to change PC during interrupted system calls GDB's interrupt.exp test cases currenly fail on ARM. The problem is how do_signal handled restarting interrupted system calls: The entry.S assembler code determines that we come from a system call; and that information is passed as "syscall" parameter to do_signal. That routine then calls get_signal_to_deliver [*] and if a signal is to be delivered, calls into handle_signal. If a system call is to be restarted either after the signal handler returns, or if no handler is to be called in the first place, the PC is updated after the get_signal_to_deliver call, either in handle_signal (if we have a handler) or at the end of do_signal (otherwise). Now the problem is that during [*], the call to get_signal_to_deliver, a ptrace intercept may happen. During this intercept, the debugger may change registers, including the PC. This is done by GDB if it wants to execute an "inferior call", i.e. the execution of some code in the debugged program triggered by GDB. To this purpose, GDB will save all registers, allocate a stack frame, set up PC and arguments as appropriate for the call, and point the link register to a dummy breakpoint instruction. Once the process is restarted, it will execute the call and then trap back to the debugger, at which point GDB will restore all registers and continue original execution. This generally works fine. However, now consider what happens when GDB attempts to do exactly that while the process was interrupted during execution of a to-be- restarted system call: do_signal is called with the syscall flag set; it calls get_signal_to_deliver, at which point the debugger takes over and changes the PC to point to a completely different place. Now get_signal_to_deliver returns without a signal to deliver; but now do_signal decides it should be restarting a system call, and decrements the PC by 2 or 4 -- so it now points to 2 or 4 bytes before the function GDB wants to call -- which leads to a subsequent crash. To fix this problem, two things need to be supported: - do_signal must be able to recognize that get_signal_to_deliver changed the PC to a different location, and skip the restart-syscall sequence - once the debugger has restored all registers at the end of the inferior call sequence, do_signal must recognize that *now* it needs to restart the pending system call, even though it was now entered from a breakpoint instead of an actual svc instruction This set of issues is solved on other platforms, usually by one of two mechanisms: - The status information "do_signal is handling a system call that may need restarting" is itself carried in some register that can be accessed via ptrace. This is e.g. on Intel the "orig_eax" register; on Sparc the kernel defines a magic extra bit in the flags register for this purpose. This allows GDB to manage that state: reset it when doing an inferior call, and restore it after the call is finished. - On s390, do_signal transparently handles this problem without requiring GDB interaction, by performing system call restarting in the following way: first, adjust the PC as necessary for restarting the call. Then, call get_signal_to_deliver; and finally just continue execution at the PC. This way, if GDB does not change the PC, everything is as before. If GDB *does* change the PC, execution will simply continue there -- and once GDB restores the PC it saved at that point, it will automatically point to the *restarted* system call. (There is the minor twist how to handle system calls that do *not* need restarting -- do_signal will undo the PC change in this case, after get_signal_to_deliver has returned, and only if ptrace did not change the PC during that call.) Because there does not appear to be any obvious register to carry the syscall-restart information on ARM, we'd either have to introduce a new artificial ptrace register just for that purpose, or else handle the issue transparently like on s390. The patch below implements the second option; using this patch makes the interrupt.exp test cases pass on ARM, with no regression in the GDB test suite otherwise. Cc: patches@linaro.org Signed-off-by: Ulrich Weigand Signed-off-by: Arnd Bergmann Signed-off-by: Russell King diff --git a/arch/arm/kernel/signal.c b/arch/arm/kernel/signal.c index cb83983..0340224 100644 --- a/arch/arm/kernel/signal.c +++ b/arch/arm/kernel/signal.c @@ -597,19 +597,13 @@ setup_rt_frame(int usig, struct k_sigaction *ka, siginfo_t *info, return err; } -static inline void setup_syscall_restart(struct pt_regs *regs) -{ - regs->ARM_r0 = regs->ARM_ORIG_r0; - regs->ARM_pc -= thumb_mode(regs) ? 2 : 4; -} - /* * OK, we're invoking a handler */ static int handle_signal(unsigned long sig, struct k_sigaction *ka, siginfo_t *info, sigset_t *oldset, - struct pt_regs * regs, int syscall) + struct pt_regs * regs) { struct thread_info *thread = current_thread_info(); struct task_struct *tsk = current; @@ -617,26 +611,6 @@ handle_signal(unsigned long sig, struct k_sigaction *ka, int ret; /* - * If we were from a system call, check for system call restarting... - */ - if (syscall) { - switch (regs->ARM_r0) { - case -ERESTART_RESTARTBLOCK: - case -ERESTARTNOHAND: - regs->ARM_r0 = -EINTR; - break; - case -ERESTARTSYS: - if (!(ka->sa.sa_flags & SA_RESTART)) { - regs->ARM_r0 = -EINTR; - break; - } - /* fallthrough */ - case -ERESTARTNOINTR: - setup_syscall_restart(regs); - } - } - - /* * translate the signal */ if (usig < 32 && thread->exec_domain && thread->exec_domain->signal_invmap) @@ -685,6 +659,7 @@ handle_signal(unsigned long sig, struct k_sigaction *ka, */ static void do_signal(struct pt_regs *regs, int syscall) { + unsigned int retval = 0, continue_addr = 0, restart_addr = 0; struct k_sigaction ka; siginfo_t info; int signr; @@ -698,18 +673,61 @@ static void do_signal(struct pt_regs *regs, int syscall) if (!user_mode(regs)) return; + /* + * If we were from a system call, check for system call restarting... + */ + if (syscall) { + continue_addr = regs->ARM_pc; + restart_addr = continue_addr - (thumb_mode(regs) ? 2 : 4); + retval = regs->ARM_r0; + + /* + * Prepare for system call restart. We do this here so that a + * debugger will see the already changed PSW. + */ + switch (retval) { + case -ERESTARTNOHAND: + case -ERESTARTSYS: + case -ERESTARTNOINTR: + regs->ARM_r0 = regs->ARM_ORIG_r0; + regs->ARM_pc = restart_addr; + break; + case -ERESTART_RESTARTBLOCK: + regs->ARM_r0 = -EINTR; + break; + } + } + if (try_to_freeze()) goto no_signal; + /* + * Get the signal to deliver. When running under ptrace, at this + * point the debugger may change all our registers ... + */ signr = get_signal_to_deliver(&info, &ka, regs, NULL); if (signr > 0) { sigset_t *oldset; + /* + * Depending on the signal settings we may need to revert the + * decision to restart the system call. But skip this if a + * debugger has chosen to restart at a different PC. + */ + if (regs->ARM_pc == restart_addr) { + if (retval == -ERESTARTNOHAND + || (retval == -ERESTARTSYS + && !(ka.sa.sa_flags & SA_RESTART))) { + regs->ARM_r0 = -EINTR; + regs->ARM_pc = continue_addr; + } + } + if (test_thread_flag(TIF_RESTORE_SIGMASK)) oldset = ¤t->saved_sigmask; else oldset = ¤t->blocked; - if (handle_signal(signr, &ka, &info, oldset, regs, syscall) == 0) { + if (handle_signal(signr, &ka, &info, oldset, regs) == 0) { /* * A signal was successfully delivered; the saved * sigmask will have been stored in the signal frame, @@ -723,11 +741,14 @@ static void do_signal(struct pt_regs *regs, int syscall) } no_signal: - /* - * No signal to deliver to the process - restart the syscall. - */ if (syscall) { - if (regs->ARM_r0 == -ERESTART_RESTARTBLOCK) { + /* + * Handle restarting a different system call. As above, + * if a debugger has chosen to restart at a different PC, + * ignore the restart. + */ + if (retval == -ERESTART_RESTARTBLOCK + && regs->ARM_pc == continue_addr) { if (thumb_mode(regs)) { regs->ARM_r7 = __NR_restart_syscall - __NR_SYSCALL_BASE; regs->ARM_pc -= 2; @@ -750,11 +771,6 @@ static void do_signal(struct pt_regs *regs, int syscall) #endif } } - if (regs->ARM_r0 == -ERESTARTNOHAND || - regs->ARM_r0 == -ERESTARTSYS || - regs->ARM_r0 == -ERESTARTNOINTR) { - setup_syscall_restart(regs); - } /* If there's no signal to deliver, we just put the saved sigmask * back. -- cgit v0.10.2 From a904f5f9eb7a55baacb2f4c1423cac8a8eb78a3a Mon Sep 17 00:00:00 2001 From: Catalin Marinas Date: Wed, 6 Apr 2011 16:18:47 +0100 Subject: ARM: 6870/1: The mandatory barrier rmb() must be a dsb() in for device accesses Since mandatory barriers may be used (explicitly or implicitly via readl etc.) to ensure the ordering between Device and Normal memory accesses, a DMB is not enough. This patch converts it to a DSB. Cc: Colin Cross Signed-off-by: Catalin Marinas Signed-off-by: Russell King diff --git a/arch/arm/include/asm/system.h b/arch/arm/include/asm/system.h index 885be09..832888d 100644 --- a/arch/arm/include/asm/system.h +++ b/arch/arm/include/asm/system.h @@ -159,7 +159,7 @@ extern unsigned int user_debug; #include #elif defined(CONFIG_ARM_DMA_MEM_BUFFERABLE) || defined(CONFIG_SMP) #define mb() do { dsb(); outer_sync(); } while (0) -#define rmb() dmb() +#define rmb() dsb() #define wmb() mb() #else #include diff --git a/arch/arm/mach-realview/include/mach/barriers.h b/arch/arm/mach-realview/include/mach/barriers.h index 0c5d749..9a73219 100644 --- a/arch/arm/mach-realview/include/mach/barriers.h +++ b/arch/arm/mach-realview/include/mach/barriers.h @@ -4,5 +4,5 @@ * operation to deadlock the system. */ #define mb() dsb() -#define rmb() dmb() +#define rmb() dsb() #define wmb() mb() diff --git a/arch/arm/mach-tegra/include/mach/barriers.h b/arch/arm/mach-tegra/include/mach/barriers.h index cc11517..425b42e 100644 --- a/arch/arm/mach-tegra/include/mach/barriers.h +++ b/arch/arm/mach-tegra/include/mach/barriers.h @@ -23,7 +23,7 @@ #include -#define rmb() dmb() +#define rmb() dsb() #define wmb() do { dsb(); outer_sync(); } while (0) #define mb() wmb() -- cgit v0.10.2 From 5db1256a5131d3b133946fa02ac9770a784e6eb2 Mon Sep 17 00:00:00 2001 From: Milton Miller Date: Thu, 12 May 2011 04:13:54 -0500 Subject: seqlock: Don't smp_rmb in seqlock reader spin loop Move the smp_rmb after cpu_relax loop in read_seqlock and add ACCESS_ONCE to make sure the test and return are consistent. A multi-threaded core in the lab didn't like the update from 2.6.35 to 2.6.36, to the point it would hang during boot when multiple threads were active. Bisection showed af5ab277ded04bd9bc6b048c5a2f0e7d70ef0867 (clockevents: Remove the per cpu tick skew) as the culprit and it is supported with stack traces showing xtime_lock waits including tick_do_update_jiffies64 and/or update_vsyscall. Experimentation showed the combination of cpu_relax and smp_rmb was significantly slowing the progress of other threads sharing the core, and this patch is effective in avoiding the hang. A theory is the rmb is affecting the whole core while the cpu_relax is causing a resource rebalance flush, together they cause an interfernce cadance that is unbroken when the seqlock reader has interrupts disabled. At first I was confused why the refactor in 3c22cd5709e8143444a6d08682a87f4c57902df3 (kernel: optimise seqlock) didn't affect this patch application, but after some study that affected seqcount not seqlock. The new seqcount was not factored back into the seqlock. I defer that the future. While the removal of the timer interrupt offset created contention for the xtime lock while a cpu does the additonal work to update the system clock, the seqlock implementation with the tight rmb spin loop goes back much further, and is just waiting for the right trigger. Cc: Signed-off-by: Milton Miller Cc: Cc: Linus Torvalds Cc: Andi Kleen Cc: Nick Piggin Cc: Benjamin Herrenschmidt Cc: Anton Blanchard Cc: Paul McKenney Acked-by: Eric Dumazet Link: http://lkml.kernel.org/r/%3Cseqlock-rmb%40mdm.bga.com%3E Signed-off-by: Thomas Gleixner diff --git a/include/linux/seqlock.h b/include/linux/seqlock.h index e98cd2e..06d6964 100644 --- a/include/linux/seqlock.h +++ b/include/linux/seqlock.h @@ -88,12 +88,12 @@ static __always_inline unsigned read_seqbegin(const seqlock_t *sl) unsigned ret; repeat: - ret = sl->sequence; - smp_rmb(); + ret = ACCESS_ONCE(sl->sequence); if (unlikely(ret & 1)) { cpu_relax(); goto repeat; } + smp_rmb(); return ret; } -- cgit v0.10.2 From 449a66fd1fa75d36dca917704827c40c8f416bca Mon Sep 17 00:00:00 2001 From: Richard Weinberger Date: Thu, 12 May 2011 15:11:12 +0200 Subject: x86: Remove warning and warning_symbol from struct stacktrace_ops Both warning and warning_symbol are nowhere used. Let's get rid of them. Signed-off-by: Richard Weinberger Cc: Oleg Nesterov Cc: Andrew Morton Cc: Huang Ying Cc: Soeren Sandmann Pedersen Cc: Namhyung Kim Cc: x86 Cc: H. Peter Anvin Cc: Thomas Gleixner Cc: Robert Richter Cc: Paul Mundt Link: http://lkml.kernel.org/r/1305205872-10321-2-git-send-email-richard@nod.at Signed-off-by: Frederic Weisbecker diff --git a/arch/x86/include/asm/stacktrace.h b/arch/x86/include/asm/stacktrace.h index d7e89c8..70bbe39 100644 --- a/arch/x86/include/asm/stacktrace.h +++ b/arch/x86/include/asm/stacktrace.h @@ -37,9 +37,6 @@ print_context_stack_bp(struct thread_info *tinfo, /* Generic stack tracer with callbacks */ struct stacktrace_ops { - void (*warning)(void *data, char *msg); - /* msg must contain %s for the symbol */ - void (*warning_symbol)(void *data, char *msg, unsigned long symbol); void (*address)(void *data, unsigned long address, int reliable); /* On negative return stop dumping */ int (*stack)(void *data, char *name); diff --git a/arch/x86/kernel/cpu/perf_event.c b/arch/x86/kernel/cpu/perf_event.c index 0de6b2b..3a0338b 100644 --- a/arch/x86/kernel/cpu/perf_event.c +++ b/arch/x86/kernel/cpu/perf_event.c @@ -1773,17 +1773,6 @@ static struct pmu pmu = { * callchain support */ -static void -backtrace_warning_symbol(void *data, char *msg, unsigned long symbol) -{ - /* Ignore warnings */ -} - -static void backtrace_warning(void *data, char *msg) -{ - /* Ignore warnings */ -} - static int backtrace_stack(void *data, char *name) { return 0; @@ -1797,8 +1786,6 @@ static void backtrace_address(void *data, unsigned long addr, int reliable) } static const struct stacktrace_ops backtrace_ops = { - .warning = backtrace_warning, - .warning_symbol = backtrace_warning_symbol, .stack = backtrace_stack, .address = backtrace_address, .walk_stack = print_context_stack_bp, diff --git a/arch/x86/kernel/dumpstack.c b/arch/x86/kernel/dumpstack.c index e2a3f06..f478ff6 100644 --- a/arch/x86/kernel/dumpstack.c +++ b/arch/x86/kernel/dumpstack.c @@ -135,20 +135,6 @@ print_context_stack_bp(struct thread_info *tinfo, } EXPORT_SYMBOL_GPL(print_context_stack_bp); - -static void -print_trace_warning_symbol(void *data, char *msg, unsigned long symbol) -{ - printk(data); - print_symbol(msg, symbol); - printk("\n"); -} - -static void print_trace_warning(void *data, char *msg) -{ - printk("%s%s\n", (char *)data, msg); -} - static int print_trace_stack(void *data, char *name) { printk("%s <%s> ", (char *)data, name); @@ -166,8 +152,6 @@ static void print_trace_address(void *data, unsigned long addr, int reliable) } static const struct stacktrace_ops print_trace_ops = { - .warning = print_trace_warning, - .warning_symbol = print_trace_warning_symbol, .stack = print_trace_stack, .address = print_trace_address, .walk_stack = print_context_stack, diff --git a/arch/x86/kernel/stacktrace.c b/arch/x86/kernel/stacktrace.c index 6515733..55d9bc0 100644 --- a/arch/x86/kernel/stacktrace.c +++ b/arch/x86/kernel/stacktrace.c @@ -9,15 +9,6 @@ #include #include -static void save_stack_warning(void *data, char *msg) -{ -} - -static void -save_stack_warning_symbol(void *data, char *msg, unsigned long symbol) -{ -} - static int save_stack_stack(void *data, char *name) { return 0; @@ -53,16 +44,12 @@ save_stack_address_nosched(void *data, unsigned long addr, int reliable) } static const struct stacktrace_ops save_stack_ops = { - .warning = save_stack_warning, - .warning_symbol = save_stack_warning_symbol, .stack = save_stack_stack, .address = save_stack_address, .walk_stack = print_context_stack, }; static const struct stacktrace_ops save_stack_ops_nosched = { - .warning = save_stack_warning, - .warning_symbol = save_stack_warning_symbol, .stack = save_stack_stack, .address = save_stack_address_nosched, .walk_stack = print_context_stack, diff --git a/arch/x86/oprofile/backtrace.c b/arch/x86/oprofile/backtrace.c index 2d49d4e..a5b64ab 100644 --- a/arch/x86/oprofile/backtrace.c +++ b/arch/x86/oprofile/backtrace.c @@ -16,17 +16,6 @@ #include #include -static void backtrace_warning_symbol(void *data, char *msg, - unsigned long symbol) -{ - /* Ignore warnings */ -} - -static void backtrace_warning(void *data, char *msg) -{ - /* Ignore warnings */ -} - static int backtrace_stack(void *data, char *name) { /* Yes, we want all stacks */ @@ -42,8 +31,6 @@ static void backtrace_address(void *data, unsigned long addr, int reliable) } static struct stacktrace_ops backtrace_ops = { - .warning = backtrace_warning, - .warning_symbol = backtrace_warning_symbol, .stack = backtrace_stack, .address = backtrace_address, .walk_stack = print_context_stack, -- cgit v0.10.2 From 4daf50f20256e0022c87c1609226e971a70c82fd Mon Sep 17 00:00:00 2001 From: Yogesh Ashok Powar Date: Thu, 12 May 2011 09:32:17 -0400 Subject: mac80211: Fix mesh-related build breakage... MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit net/mac80211/cfg.c: In function ‘sta_apply_parameters’: net/mac80211/cfg.c:746: error: ‘struct sta_info’ has no member named ‘plink_state’ make[1]: *** [net/mac80211/cfg.o] Error 1 make: *** [net/mac80211/mac80211.ko] Error 2 Signed-off-by: John W. Linville diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index a2ff474..ed3400c 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -738,6 +738,7 @@ static void sta_apply_parameters(struct ieee80211_local *local, &sta->sta.ht_cap); if (ieee80211_vif_is_mesh(&sdata->vif)) { +#ifdef CONFIG_MAC80211_MESH if (sdata->u.mesh.security & IEEE80211_MESH_SEC_SECURED) switch (params->plink_state) { case PLINK_LISTEN: @@ -758,6 +759,7 @@ static void sta_apply_parameters(struct ieee80211_local *local, mesh_plink_block(sta); break; } +#endif } } -- cgit v0.10.2 From 747df2258b1b9a2e25929ef496262c339c380009 Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Wed, 11 May 2011 17:41:18 +0100 Subject: sfc: Always map MCDI shared memory as uncacheable We enabled write-combining for memory-mapped registers in commit 65f0b417dee94f779ce9b77102b7d73c93723b39, but inhibited it for the MCDI shared memory where this is not supported. However, write-combining mappings also allow read-reordering, which may also be a problem. I found that when an SFC9000-family controller is connected to an Intel 3000 chipset, and write-combining is enabled, the controller stops responding to PCIe read requests during driver initialisation while the driver is polling for completion of an MCDI command. This results in an NMI and system hang. Adding read memory barriers between all reads to the shared memory area appears to reduce but not eliminate the probability of this. We have not yet established whether this is a bug in our BIU or in the PCIe bridge. For now, work around by mapping the shared memory area separately. Signed-off-by: Ben Hutchings diff --git a/drivers/net/sfc/mcdi.c b/drivers/net/sfc/mcdi.c index d984790..3dd45ed 100644 --- a/drivers/net/sfc/mcdi.c +++ b/drivers/net/sfc/mcdi.c @@ -50,6 +50,20 @@ static inline struct efx_mcdi_iface *efx_mcdi(struct efx_nic *efx) return &nic_data->mcdi; } +static inline void +efx_mcdi_readd(struct efx_nic *efx, efx_dword_t *value, unsigned reg) +{ + struct siena_nic_data *nic_data = efx->nic_data; + value->u32[0] = (__force __le32)__raw_readl(nic_data->mcdi_smem + reg); +} + +static inline void +efx_mcdi_writed(struct efx_nic *efx, const efx_dword_t *value, unsigned reg) +{ + struct siena_nic_data *nic_data = efx->nic_data; + __raw_writel((__force u32)value->u32[0], nic_data->mcdi_smem + reg); +} + void efx_mcdi_init(struct efx_nic *efx) { struct efx_mcdi_iface *mcdi; @@ -70,8 +84,8 @@ static void efx_mcdi_copyin(struct efx_nic *efx, unsigned cmd, const u8 *inbuf, size_t inlen) { struct efx_mcdi_iface *mcdi = efx_mcdi(efx); - unsigned pdu = FR_CZ_MC_TREG_SMEM + MCDI_PDU(efx); - unsigned doorbell = FR_CZ_MC_TREG_SMEM + MCDI_DOORBELL(efx); + unsigned pdu = MCDI_PDU(efx); + unsigned doorbell = MCDI_DOORBELL(efx); unsigned int i; efx_dword_t hdr; u32 xflags, seqno; @@ -92,30 +106,28 @@ static void efx_mcdi_copyin(struct efx_nic *efx, unsigned cmd, MCDI_HEADER_SEQ, seqno, MCDI_HEADER_XFLAGS, xflags); - efx_writed(efx, &hdr, pdu); + efx_mcdi_writed(efx, &hdr, pdu); - for (i = 0; i < inlen; i += 4) { - _efx_writed(efx, *((__le32 *)(inbuf + i)), pdu + 4 + i); - /* use wmb() within loop to inhibit write combining */ - wmb(); - } + for (i = 0; i < inlen; i += 4) + efx_mcdi_writed(efx, (const efx_dword_t *)(inbuf + i), + pdu + 4 + i); /* ring the doorbell with a distinctive value */ - _efx_writed(efx, (__force __le32) 0x45789abc, doorbell); - wmb(); + EFX_POPULATE_DWORD_1(hdr, EFX_DWORD_0, 0x45789abc); + efx_mcdi_writed(efx, &hdr, doorbell); } static void efx_mcdi_copyout(struct efx_nic *efx, u8 *outbuf, size_t outlen) { struct efx_mcdi_iface *mcdi = efx_mcdi(efx); - unsigned int pdu = FR_CZ_MC_TREG_SMEM + MCDI_PDU(efx); + unsigned int pdu = MCDI_PDU(efx); int i; BUG_ON(atomic_read(&mcdi->state) == MCDI_STATE_QUIESCENT); BUG_ON(outlen & 3 || outlen >= 0x100); for (i = 0; i < outlen; i += 4) - *((__le32 *)(outbuf + i)) = _efx_readd(efx, pdu + 4 + i); + efx_mcdi_readd(efx, (efx_dword_t *)(outbuf + i), pdu + 4 + i); } static int efx_mcdi_poll(struct efx_nic *efx) @@ -123,7 +135,7 @@ static int efx_mcdi_poll(struct efx_nic *efx) struct efx_mcdi_iface *mcdi = efx_mcdi(efx); unsigned int time, finish; unsigned int respseq, respcmd, error; - unsigned int pdu = FR_CZ_MC_TREG_SMEM + MCDI_PDU(efx); + unsigned int pdu = MCDI_PDU(efx); unsigned int rc, spins; efx_dword_t reg; @@ -149,8 +161,7 @@ static int efx_mcdi_poll(struct efx_nic *efx) time = get_seconds(); - rmb(); - efx_readd(efx, ®, pdu); + efx_mcdi_readd(efx, ®, pdu); /* All 1's indicates that shared memory is in reset (and is * not a valid header). Wait for it to come out reset before @@ -177,7 +188,7 @@ static int efx_mcdi_poll(struct efx_nic *efx) respseq, mcdi->seqno); rc = EIO; } else if (error) { - efx_readd(efx, ®, pdu + 4); + efx_mcdi_readd(efx, ®, pdu + 4); switch (EFX_DWORD_FIELD(reg, EFX_DWORD_0)) { #define TRANSLATE_ERROR(name) \ case MC_CMD_ERR_ ## name: \ @@ -211,21 +222,21 @@ out: /* Test and clear MC-rebooted flag for this port/function */ int efx_mcdi_poll_reboot(struct efx_nic *efx) { - unsigned int addr = FR_CZ_MC_TREG_SMEM + MCDI_REBOOT_FLAG(efx); + unsigned int addr = MCDI_REBOOT_FLAG(efx); efx_dword_t reg; uint32_t value; if (efx_nic_rev(efx) < EFX_REV_SIENA_A0) return false; - efx_readd(efx, ®, addr); + efx_mcdi_readd(efx, ®, addr); value = EFX_DWORD_FIELD(reg, EFX_DWORD_0); if (value == 0) return 0; EFX_ZERO_DWORD(reg); - efx_writed(efx, ®, addr); + efx_mcdi_writed(efx, ®, addr); if (value == MC_STATUS_DWORD_ASSERT) return -EINTR; diff --git a/drivers/net/sfc/nic.h b/drivers/net/sfc/nic.h index a42db6e..d91701a 100644 --- a/drivers/net/sfc/nic.h +++ b/drivers/net/sfc/nic.h @@ -143,10 +143,12 @@ static inline struct falcon_board *falcon_board(struct efx_nic *efx) /** * struct siena_nic_data - Siena NIC state * @mcdi: Management-Controller-to-Driver Interface + * @mcdi_smem: MCDI shared memory mapping. The mapping is always uncacheable. * @wol_filter_id: Wake-on-LAN packet filter id */ struct siena_nic_data { struct efx_mcdi_iface mcdi; + void __iomem *mcdi_smem; int wol_filter_id; }; diff --git a/drivers/net/sfc/siena.c b/drivers/net/sfc/siena.c index e4dd898..837869b 100644 --- a/drivers/net/sfc/siena.c +++ b/drivers/net/sfc/siena.c @@ -220,12 +220,26 @@ static int siena_probe_nic(struct efx_nic *efx) efx_reado(efx, ®, FR_AZ_CS_DEBUG); efx->net_dev->dev_id = EFX_OWORD_FIELD(reg, FRF_CZ_CS_PORT_NUM) - 1; + /* Initialise MCDI */ + nic_data->mcdi_smem = ioremap_nocache(efx->membase_phys + + FR_CZ_MC_TREG_SMEM, + FR_CZ_MC_TREG_SMEM_STEP * + FR_CZ_MC_TREG_SMEM_ROWS); + if (!nic_data->mcdi_smem) { + netif_err(efx, probe, efx->net_dev, + "could not map MCDI at %llx+%x\n", + (unsigned long long)efx->membase_phys + + FR_CZ_MC_TREG_SMEM, + FR_CZ_MC_TREG_SMEM_STEP * FR_CZ_MC_TREG_SMEM_ROWS); + rc = -ENOMEM; + goto fail1; + } efx_mcdi_init(efx); /* Recover from a failed assertion before probing */ rc = efx_mcdi_handle_assertion(efx); if (rc) - goto fail1; + goto fail2; /* Let the BMC know that the driver is now in charge of link and * filter settings. We must do this before we reset the NIC */ @@ -280,6 +294,7 @@ fail4: fail3: efx_mcdi_drv_attach(efx, false, NULL); fail2: + iounmap(nic_data->mcdi_smem); fail1: kfree(efx->nic_data); return rc; @@ -359,6 +374,8 @@ static int siena_init_nic(struct efx_nic *efx) static void siena_remove_nic(struct efx_nic *efx) { + struct siena_nic_data *nic_data = efx->nic_data; + efx_nic_free_buffer(efx, &efx->irq_status); siena_reset_hw(efx, RESET_TYPE_ALL); @@ -368,7 +385,8 @@ static void siena_remove_nic(struct efx_nic *efx) efx_mcdi_drv_attach(efx, false, NULL); /* Tear down the private nic state */ - kfree(efx->nic_data); + iounmap(nic_data->mcdi_smem); + kfree(nic_data); efx->nic_data = NULL; } @@ -606,8 +624,7 @@ struct efx_nic_type siena_a0_nic_type = { .default_mac_ops = &efx_mcdi_mac_operations, .revision = EFX_REV_SIENA_A0, - .mem_map_size = (FR_CZ_MC_TREG_SMEM + - FR_CZ_MC_TREG_SMEM_STEP * FR_CZ_MC_TREG_SMEM_ROWS), + .mem_map_size = FR_CZ_MC_TREG_SMEM, /* MC_TREG_SMEM mapped separately */ .txd_ptr_tbl_base = FR_BZ_TX_DESC_PTR_TBL, .rxd_ptr_tbl_base = FR_BZ_RX_DESC_PTR_TBL, .buf_tbl_base = FR_BZ_BUF_FULL_TBL, -- cgit v0.10.2 From 698b368275c3fa98261159253cfc79653f9dffc6 Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Wed, 11 May 2011 14:49:36 -0700 Subject: fbcon: add lifetime refcount to opened frame buffers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This just adds the refcount and the new registration lock logic. It does not (for example) actually change the read/write/ioctl routines to actually use the frame buffer that was opened: those function still end up alway susing whatever the current frame buffer is at the time of the call. Without this, if something holds the frame buffer open over a framebuffer switch, the close() operation after the switch will access a fb_info that has been free'd by the unregistering of the old frame buffer. (The read/write/ioctl operations will normally not cause problems, because they will - illogically - pick up the new fbcon instead. But a switch that happens just as one of those is going on might see problems too, the window is just much smaller: one individual op rather than the whole open-close sequence.) This use-after-free is apparently fairly easily triggered by the Ubuntu 11.04 boot sequence. Acked-by: Tim Gardner Tested-by: Daniel J Blueman Tested-by: Anca Emanuel Cc: Bruno Prémont Cc: Alan Cox Cc: Paul Mundt Cc: Dave Airlie Cc: Andy Whitcroft Signed-off-by: Linus Torvalds diff --git a/drivers/video/fbmem.c b/drivers/video/fbmem.c index e0c2284..eec14d2 100644 --- a/drivers/video/fbmem.c +++ b/drivers/video/fbmem.c @@ -42,9 +42,34 @@ #define FBPIXMAPSIZE (1024 * 8) +static DEFINE_MUTEX(registration_lock); struct fb_info *registered_fb[FB_MAX] __read_mostly; int num_registered_fb __read_mostly; +static struct fb_info *get_fb_info(unsigned int idx) +{ + struct fb_info *fb_info; + + if (idx >= FB_MAX) + return ERR_PTR(-ENODEV); + + mutex_lock(®istration_lock); + fb_info = registered_fb[idx]; + if (fb_info) + atomic_inc(&fb_info->count); + mutex_unlock(®istration_lock); + + return fb_info; +} + +static void put_fb_info(struct fb_info *fb_info) +{ + if (!atomic_dec_and_test(&fb_info->count)) + return; + if (fb_info->fbops->fb_destroy) + fb_info->fbops->fb_destroy(fb_info); +} + int lock_fb_info(struct fb_info *info) { mutex_lock(&info->lock); @@ -647,6 +672,7 @@ int fb_show_logo(struct fb_info *info, int rotate) { return 0; } static void *fb_seq_start(struct seq_file *m, loff_t *pos) { + mutex_lock(®istration_lock); return (*pos < FB_MAX) ? pos : NULL; } @@ -658,6 +684,7 @@ static void *fb_seq_next(struct seq_file *m, void *v, loff_t *pos) static void fb_seq_stop(struct seq_file *m, void *v) { + mutex_unlock(®istration_lock); } static int fb_seq_show(struct seq_file *m, void *v) @@ -1361,14 +1388,16 @@ __releases(&info->lock) struct fb_info *info; int res = 0; - if (fbidx >= FB_MAX) - return -ENODEV; - info = registered_fb[fbidx]; - if (!info) + info = get_fb_info(fbidx); + if (!info) { request_module("fb%d", fbidx); - info = registered_fb[fbidx]; - if (!info) - return -ENODEV; + info = get_fb_info(fbidx); + if (!info) + return -ENODEV; + } + if (IS_ERR(info)) + return PTR_ERR(info); + mutex_lock(&info->lock); if (!try_module_get(info->fbops->owner)) { res = -ENODEV; @@ -1386,6 +1415,8 @@ __releases(&info->lock) #endif out: mutex_unlock(&info->lock); + if (res) + put_fb_info(info); return res; } @@ -1401,6 +1432,7 @@ __releases(&info->lock) info->fbops->fb_release(info,1); module_put(info->fbops->owner); mutex_unlock(&info->lock); + put_fb_info(info); return 0; } @@ -1542,11 +1574,13 @@ register_framebuffer(struct fb_info *fb_info) remove_conflicting_framebuffers(fb_info->apertures, fb_info->fix.id, fb_is_primary_device(fb_info)); + mutex_lock(®istration_lock); num_registered_fb++; for (i = 0 ; i < FB_MAX; i++) if (!registered_fb[i]) break; fb_info->node = i; + atomic_set(&fb_info->count, 1); mutex_init(&fb_info->lock); mutex_init(&fb_info->mm_lock); @@ -1583,6 +1617,7 @@ register_framebuffer(struct fb_info *fb_info) fb_var_to_videomode(&mode, &fb_info->var); fb_add_videomode(&mode, &fb_info->modelist); registered_fb[i] = fb_info; + mutex_unlock(®istration_lock); event.info = fb_info; if (!lock_fb_info(fb_info)) @@ -1616,6 +1651,7 @@ unregister_framebuffer(struct fb_info *fb_info) struct fb_event event; int i, ret = 0; + mutex_lock(®istration_lock); i = fb_info->node; if (!registered_fb[i]) { ret = -EINVAL; @@ -1638,7 +1674,7 @@ unregister_framebuffer(struct fb_info *fb_info) (fb_info->pixmap.flags & FB_PIXMAP_DEFAULT)) kfree(fb_info->pixmap.addr); fb_destroy_modelist(&fb_info->modelist); - registered_fb[i]=NULL; + registered_fb[i] = NULL; num_registered_fb--; fb_cleanup_device(fb_info); device_destroy(fb_class, MKDEV(FB_MAJOR, i)); @@ -1646,9 +1682,9 @@ unregister_framebuffer(struct fb_info *fb_info) fb_notifier_call_chain(FB_EVENT_FB_UNREGISTERED, &event); /* this may free fb info */ - if (fb_info->fbops->fb_destroy) - fb_info->fbops->fb_destroy(fb_info); + put_fb_info(fb_info); done: + mutex_unlock(®istration_lock); return ret; } diff --git a/include/linux/fb.h b/include/linux/fb.h index df728c1..6a82748 100644 --- a/include/linux/fb.h +++ b/include/linux/fb.h @@ -832,6 +832,7 @@ struct fb_tile_ops { #define FBINFO_CAN_FORCE_OUTPUT 0x200000 struct fb_info { + atomic_t count; int node; int flags; struct mutex lock; /* Lock for open/release/ioctl funcs */ -- cgit v0.10.2 From c47747fde931c02455683bd00ea43eaa62f35b0e Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Wed, 11 May 2011 14:58:34 -0700 Subject: fbmem: make read/write/ioctl use the frame buffer at open time MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit read/write/ioctl on a fbcon file descriptor has traditionally used the fbcon not when it was opened, but as it was at the time of the call. That makes no sense, but the lack of sense is much more obvious now that we properly ref-count the usage - it means that the ref-counting doesn't actually protect operations we do on the frame buffer. This changes it to look at the fb_info that we got at open time, but in order to avoid using a frame buffer long after it has been unregistered, we do verify that it is still current, and return -ENODEV if not. Acked-by: Tim Gardner Tested-by: Daniel J Blueman Tested-by: Anca Emanuel Cc: Bruno Prémont Cc: Alan Cox Cc: Paul Mundt Cc: Dave Airlie Cc: Andy Whitcroft Signed-off-by: Linus Torvalds diff --git a/drivers/video/fbmem.c b/drivers/video/fbmem.c index eec14d2..ea16e65 100644 --- a/drivers/video/fbmem.c +++ b/drivers/video/fbmem.c @@ -717,13 +717,30 @@ static const struct file_operations fb_proc_fops = { .release = seq_release, }; -static ssize_t -fb_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) +/* + * We hold a reference to the fb_info in file->private_data, + * but if the current registered fb has changed, we don't + * actually want to use it. + * + * So look up the fb_info using the inode minor number, + * and just verify it against the reference we have. + */ +static struct fb_info *file_fb_info(struct file *file) { - unsigned long p = *ppos; struct inode *inode = file->f_path.dentry->d_inode; int fbidx = iminor(inode); struct fb_info *info = registered_fb[fbidx]; + + if (info != file->private_data) + info = NULL; + return info; +} + +static ssize_t +fb_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) +{ + unsigned long p = *ppos; + struct fb_info *info = file_fb_info(file); u8 *buffer, *dst; u8 __iomem *src; int c, cnt = 0, err = 0; @@ -788,9 +805,7 @@ static ssize_t fb_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos) { unsigned long p = *ppos; - struct inode *inode = file->f_path.dentry->d_inode; - int fbidx = iminor(inode); - struct fb_info *info = registered_fb[fbidx]; + struct fb_info *info = file_fb_info(file); u8 *buffer, *src; u8 __iomem *dst; int c, cnt = 0, err = 0; @@ -1168,10 +1183,10 @@ static long do_fb_ioctl(struct fb_info *info, unsigned int cmd, static long fb_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { - struct inode *inode = file->f_path.dentry->d_inode; - int fbidx = iminor(inode); - struct fb_info *info = registered_fb[fbidx]; + struct fb_info *info = file_fb_info(file); + if (!info) + return -ENODEV; return do_fb_ioctl(info, cmd, arg); } @@ -1292,12 +1307,13 @@ static int fb_get_fscreeninfo(struct fb_info *info, unsigned int cmd, static long fb_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { - struct inode *inode = file->f_path.dentry->d_inode; - int fbidx = iminor(inode); - struct fb_info *info = registered_fb[fbidx]; - struct fb_ops *fb = info->fbops; + struct fb_info *info = file_fb_info(file); + struct fb_ops *fb; long ret = -ENOIOCTLCMD; + if (!info) + return -ENODEV; + fb = info->fbops; switch(cmd) { case FBIOGET_VSCREENINFO: case FBIOPUT_VSCREENINFO: @@ -1330,16 +1346,18 @@ static long fb_compat_ioctl(struct file *file, unsigned int cmd, static int fb_mmap(struct file *file, struct vm_area_struct * vma) { - int fbidx = iminor(file->f_path.dentry->d_inode); - struct fb_info *info = registered_fb[fbidx]; - struct fb_ops *fb = info->fbops; + struct fb_info *info = file_fb_info(file); + struct fb_ops *fb; unsigned long off; unsigned long start; u32 len; + if (!info) + return -ENODEV; if (vma->vm_pgoff > (~0UL >> PAGE_SHIFT)) return -EINVAL; off = vma->vm_pgoff << PAGE_SHIFT; + fb = info->fbops; if (!fb) return -ENODEV; mutex_lock(&info->mm_lock); -- cgit v0.10.2 From 1c65335714e99864a438b0d757c8736d3c6e7d79 Mon Sep 17 00:00:00 2001 From: Sergei Shtylyov Date: Mon, 9 May 2011 22:07:31 -0700 Subject: IB/qib: Use pci_dev->revision The driver reads PCI revision ID from the PCI configuration register while it's already stored by PCI subsystem in the revision field of struct pci_dev. Signed-off-by: Sergei Shtylyov Acked-by: Mike Marciniszyn Signed-off-by: Roland Dreier diff --git a/drivers/infiniband/hw/qib/qib_pcie.c b/drivers/infiniband/hw/qib/qib_pcie.c index 48b6674..891cc2f 100644 --- a/drivers/infiniband/hw/qib/qib_pcie.c +++ b/drivers/infiniband/hw/qib/qib_pcie.c @@ -526,11 +526,8 @@ static int qib_tune_pcie_coalesce(struct qib_devdata *dd) */ devid = parent->device; if (devid >= 0x25e2 && devid <= 0x25fa) { - u8 rev; - /* 5000 P/V/X/Z */ - pci_read_config_byte(parent, PCI_REVISION_ID, &rev); - if (rev <= 0xb2) + if (parent->revision <= 0xb2) bits = 1U << 10; else bits = 7U << 10; -- cgit v0.10.2 From 92bdaef7b2c5d3cb8abc902faa1f7670a183dcdc Mon Sep 17 00:00:00 2001 From: Konrad Rzeszutek Wilk Date: Thu, 5 May 2011 13:50:43 -0400 Subject: Revert "xen/mmu: Add workaround "x86-64, mm: Put early page table high"" This reverts commit a38647837a411f7df79623128421eef2118b5884. It does not work with certain AMD machines. last_pfn = 0x100000 max_arch_pfn = 0x400000000 initial memory mapped : 0 - 02c3a000 Base memory trampoline at [ffff88000009b000] 9b000 size 20480 init_memory_mapping: 0000000000000000-0000000100000000 0000000000 - 0100000000 page 4k kernel direct mapping tables up to 100000000 @ ff7fb000-100000000 init_memory_mapping: 0000000100000000-00000001e0800000 0100000000 - 01e0800000 page 4k kernel direct mapping tables up to 1e0800000 @ 1df0f3000-1e0000000 xen: setting RW the range fffdc000 - 100000000 RAMDISK: 0203b000 - 02c3a000 No NUMA configuration found Faking a node at 0000000000000000-00000001e0800000 NUMA: Using 63 for the hash shift. Initmem setup node 0 0000000000000000-00000001e0800000 NODE_DATA [00000001dfffb000 - 00000001dfffffff] BUG: unable to handle kernel NULL pointer dereference at (null) IP: [] setup_node_bootmem+0x18a/0x1ea PGD 0 Oops: 0003 [#1] SMP last sysfs file: CPU 0 Modules linked in: Pid: 0, comm: swapper Not tainted 2.6.39-0-virtual #6~smb1 RIP: e030:[] [] setup_node_bootmem+0x18a/0x1ea RSP: e02b:ffffffff81c01e38 EFLAGS: 00010046 RAX: 0000000000000000 RBX: 00000001e0800000 RCX: 0000000000001040 RDX: 0000000000004100 RSI: 0000000000000000 RDI: ffff8801dfffb000 RBP: ffffffff81c01e58 R08: 0000000000000020 R09: 0000000000000000 R10: 0000000000000000 R11: 0000000000000001 R12: 0000000000000000 R13: 0000000000000000 R14: 0000000000000000 R15: 0000000000bfe400 FS: 0000000000000000(0000) GS:ffffffff81cca000(0000) knlGS:0000000000000000 CS: e033 DS: 0000 ES: 0000 CR0: 0000000080050033 CR2: 0000000000000000 CR3: 0000000001c03000 CR4: 0000000000000660 DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000 DR3: 0000000000000000 DR6: 00000000ffff0ff0 DR7: 0000000000000400 Process swapper (pid: 0, threadinfo ffffffff81c00000, task ffffffff81c0b020) Stack: 0000000000000040 0000000000000001 0000000000000000 ffffffffffffffff ffffffff81c01e88 ffffffff81cf6c25 0000000000000000 0000000000000000 ffffffff81cf687f 0000000000000000 ffffffff81c01ea8 ffffffff81cf6e45 Call Trace: [] numa_register_memblks.constprop.3+0x150/0x181 [] ? numa_add_memblk+0x7c/0x7c [] numa_init.part.2+0x1c/0x7c [] ? numa_add_memblk+0x7c/0x7c [] numa_init+0x6c/0x70 [] initmem_init+0x39/0x3b [] setup_arch+0x64e/0x769 [] ? printk+0x51/0x53 [] start_kernel+0xd4/0x3f3 [] x86_64_start_reservations+0x132/0x136 [] xen_start_kernel+0x588/0x58f Code: 41 00 00 48 8b 3c c5 a0 24 cc 81 31 c0 40 f6 c7 01 74 05 aa 66 ba ff 40 40 f6 c7 02 74 05 66 ab 83 ea 02 89 d1 c1 e9 02 f6 c2 02 ab 74 02 66 ab 80 e2 01 74 01 aa 49 63 c4 48 c1 eb 0c 44 89 RIP [] setup_node_bootmem+0x18a/0x1ea RSP CR2: 0000000000000000 ---[ end trace a7919e7f17c0a725 ]--- Kernel panic - not syncing: Attempted to kill the idle task! Pid: 0, comm: swapper Tainted: G D 2.6.39-0-virtual #6~smb1 Reported-by: Stefan Bader Signed-off-by: Konrad Rzeszutek Wilk diff --git a/arch/x86/xen/mmu.c b/arch/x86/xen/mmu.c index 55c965b..cf4ef61 100644 --- a/arch/x86/xen/mmu.c +++ b/arch/x86/xen/mmu.c @@ -1463,119 +1463,6 @@ static int xen_pgd_alloc(struct mm_struct *mm) return ret; } -#ifdef CONFIG_X86_64 -static __initdata u64 __last_pgt_set_rw = 0; -static __initdata u64 __pgt_buf_start = 0; -static __initdata u64 __pgt_buf_end = 0; -static __initdata u64 __pgt_buf_top = 0; -/* - * As a consequence of the commit: - * - * commit 4b239f458c229de044d6905c2b0f9fe16ed9e01e - * Author: Yinghai Lu - * Date: Fri Dec 17 16:58:28 2010 -0800 - * - * x86-64, mm: Put early page table high - * - * at some point init_memory_mapping is going to reach the pagetable pages - * area and map those pages too (mapping them as normal memory that falls - * in the range of addresses passed to init_memory_mapping as argument). - * Some of those pages are already pagetable pages (they are in the range - * pgt_buf_start-pgt_buf_end) therefore they are going to be mapped RO and - * everything is fine. - * Some of these pages are not pagetable pages yet (they fall in the range - * pgt_buf_end-pgt_buf_top; for example the page at pgt_buf_end) so they - * are going to be mapped RW. When these pages become pagetable pages and - * are hooked into the pagetable, xen will find that the guest has already - * a RW mapping of them somewhere and fail the operation. - * The reason Xen requires pagetables to be RO is that the hypervisor needs - * to verify that the pagetables are valid before using them. The validation - * operations are called "pinning". - * - * In order to fix the issue we mark all the pages in the entire range - * pgt_buf_start-pgt_buf_top as RO, however when the pagetable allocation - * is completed only the range pgt_buf_start-pgt_buf_end is reserved by - * init_memory_mapping. Hence the kernel is going to crash as soon as one - * of the pages in the range pgt_buf_end-pgt_buf_top is reused (b/c those - * ranges are RO). - * - * For this reason, 'mark_rw_past_pgt' is introduced which is called _after_ - * the init_memory_mapping has completed (in a perfect world we would - * call this function from init_memory_mapping, but lets ignore that). - * - * Because we are called _after_ init_memory_mapping the pgt_buf_[start, - * end,top] have all changed to new values (b/c init_memory_mapping - * is called and setting up another new page-table). Hence, the first time - * we enter this function, we save away the pgt_buf_start value and update - * the pgt_buf_[end,top]. - * - * When we detect that the "old" pgt_buf_start through pgt_buf_end - * PFNs have been reserved (so memblock_x86_reserve_range has been called), - * we immediately set out to RW the "old" pgt_buf_end through pgt_buf_top. - * - * And then we update those "old" pgt_buf_[end|top] with the new ones - * so that we can redo this on the next pagetable. - */ -static __init void mark_rw_past_pgt(void) { - - if (pgt_buf_end > pgt_buf_start) { - u64 addr, size; - - /* Save it away. */ - if (!__pgt_buf_start) { - __pgt_buf_start = pgt_buf_start; - __pgt_buf_end = pgt_buf_end; - __pgt_buf_top = pgt_buf_top; - return; - } - /* If we get the range that starts at __pgt_buf_end that means - * the range is reserved, and that in 'init_memory_mapping' - * the 'memblock_x86_reserve_range' has been called with the - * outdated __pgt_buf_start, __pgt_buf_end (the "new" - * pgt_buf_[start|end|top] refer now to a new pagetable. - * Note: we are called _after_ the pgt_buf_[..] have been - * updated.*/ - - addr = memblock_x86_find_in_range_size(PFN_PHYS(__pgt_buf_start), - &size, PAGE_SIZE); - - /* Still not reserved, meaning 'memblock_x86_reserve_range' - * hasn't been called yet. Update the _end and _top.*/ - if (addr == PFN_PHYS(__pgt_buf_start)) { - __pgt_buf_end = pgt_buf_end; - __pgt_buf_top = pgt_buf_top; - return; - } - - /* OK, the area is reserved, meaning it is time for us to - * set RW for the old end->top PFNs. */ - - /* ..unless we had already done this. */ - if (__pgt_buf_end == __last_pgt_set_rw) - return; - - addr = PFN_PHYS(__pgt_buf_end); - - /* set as RW the rest */ - printk(KERN_DEBUG "xen: setting RW the range %llx - %llx\n", - PFN_PHYS(__pgt_buf_end), PFN_PHYS(__pgt_buf_top)); - - while (addr < PFN_PHYS(__pgt_buf_top)) { - make_lowmem_page_readwrite(__va(addr)); - addr += PAGE_SIZE; - } - /* And update everything so that we are ready for the next - * pagetable (the one created for regions past 4GB) */ - __last_pgt_set_rw = __pgt_buf_end; - __pgt_buf_start = pgt_buf_start; - __pgt_buf_end = pgt_buf_end; - __pgt_buf_top = pgt_buf_top; - } - return; -} -#else -static __init void mark_rw_past_pgt(void) { } -#endif static void xen_pgd_free(struct mm_struct *mm, pgd_t *pgd) { #ifdef CONFIG_X86_64 @@ -1602,14 +1489,6 @@ static __init pte_t mask_rw_pte(pte_t *ptep, pte_t pte) unsigned long pfn = pte_pfn(pte); /* - * A bit of optimization. We do not need to call the workaround - * when xen_set_pte_init is called with a PTE with 0 as PFN. - * That is b/c the pagetable at that point are just being populated - * with empty values and we can save some cycles by not calling - * the 'memblock' code.*/ - if (pfn) - mark_rw_past_pgt(); - /* * If the new pfn is within the range of the newly allocated * kernel pagetable, and it isn't being mapped into an * early_ioremap fixmap slot as a freshly allocated page, make sure @@ -2118,8 +1997,6 @@ __init void xen_ident_map_ISA(void) static __init void xen_post_allocator_init(void) { - mark_rw_past_pgt(); - #ifdef CONFIG_XEN_DEBUG pv_mmu_ops.make_pte = PV_CALLEE_SAVE(xen_make_pte_debug); #endif -- cgit v0.10.2 From 279b706bf800b5967037f492dbe4fc5081ad5d0f Mon Sep 17 00:00:00 2001 From: Stefano Stabellini Date: Thu, 14 Apr 2011 15:49:41 +0100 Subject: x86,xen: introduce x86_init.mapping.pagetable_reserve Introduce a new x86_init hook called pagetable_reserve that at the end of init_memory_mapping is used to reserve a range of memory addresses for the kernel pagetable pages we used and free the other ones. On native it just calls memblock_x86_reserve_range while on xen it also takes care of setting the spare memory previously allocated for kernel pagetable pages from RO to RW, so that it can be used for other purposes. A detailed explanation of the reason why this hook is needed follows. As a consequence of the commit: commit 4b239f458c229de044d6905c2b0f9fe16ed9e01e Author: Yinghai Lu Date: Fri Dec 17 16:58:28 2010 -0800 x86-64, mm: Put early page table high at some point init_memory_mapping is going to reach the pagetable pages area and map those pages too (mapping them as normal memory that falls in the range of addresses passed to init_memory_mapping as argument). Some of those pages are already pagetable pages (they are in the range pgt_buf_start-pgt_buf_end) therefore they are going to be mapped RO and everything is fine. Some of these pages are not pagetable pages yet (they fall in the range pgt_buf_end-pgt_buf_top; for example the page at pgt_buf_end) so they are going to be mapped RW. When these pages become pagetable pages and are hooked into the pagetable, xen will find that the guest has already a RW mapping of them somewhere and fail the operation. The reason Xen requires pagetables to be RO is that the hypervisor needs to verify that the pagetables are valid before using them. The validation operations are called "pinning" (more details in arch/x86/xen/mmu.c). In order to fix the issue we mark all the pages in the entire range pgt_buf_start-pgt_buf_top as RO, however when the pagetable allocation is completed only the range pgt_buf_start-pgt_buf_end is reserved by init_memory_mapping. Hence the kernel is going to crash as soon as one of the pages in the range pgt_buf_end-pgt_buf_top is reused (b/c those ranges are RO). For this reason we need a hook to reserve the kernel pagetable pages we used and free the other ones so that they can be reused for other purposes. On native it just means calling memblock_x86_reserve_range, on Xen it also means marking RW the pagetable pages that we allocated before but that haven't been used before. Another way to fix this is without using the hook is by adding a 'if (xen_pv_domain)' in the 'init_memory_mapping' code and calling the Xen counterpart, but that is just nasty. Signed-off-by: Stefano Stabellini Acked-by: Yinghai Lu Acked-by: H. Peter Anvin Cc: Ingo Molnar Signed-off-by: Konrad Rzeszutek Wilk diff --git a/arch/x86/include/asm/pgtable_types.h b/arch/x86/include/asm/pgtable_types.h index 7db7723..d56187c 100644 --- a/arch/x86/include/asm/pgtable_types.h +++ b/arch/x86/include/asm/pgtable_types.h @@ -299,6 +299,7 @@ int phys_mem_access_prot_allowed(struct file *file, unsigned long pfn, /* Install a pte for a particular vaddr in kernel space. */ void set_pte_vaddr(unsigned long vaddr, pte_t pte); +extern void native_pagetable_reserve(u64 start, u64 end); #ifdef CONFIG_X86_32 extern void native_pagetable_setup_start(pgd_t *base); extern void native_pagetable_setup_done(pgd_t *base); diff --git a/arch/x86/include/asm/x86_init.h b/arch/x86/include/asm/x86_init.h index 643ebf2..d3d8590 100644 --- a/arch/x86/include/asm/x86_init.h +++ b/arch/x86/include/asm/x86_init.h @@ -68,6 +68,17 @@ struct x86_init_oem { }; /** + * struct x86_init_mapping - platform specific initial kernel pagetable setup + * @pagetable_reserve: reserve a range of addresses for kernel pagetable usage + * + * For more details on the purpose of this hook, look in + * init_memory_mapping and the commit that added it. + */ +struct x86_init_mapping { + void (*pagetable_reserve)(u64 start, u64 end); +}; + +/** * struct x86_init_paging - platform specific paging functions * @pagetable_setup_start: platform specific pre paging_init() call * @pagetable_setup_done: platform specific post paging_init() call @@ -123,6 +134,7 @@ struct x86_init_ops { struct x86_init_mpparse mpparse; struct x86_init_irqs irqs; struct x86_init_oem oem; + struct x86_init_mapping mapping; struct x86_init_paging paging; struct x86_init_timers timers; struct x86_init_iommu iommu; diff --git a/arch/x86/kernel/x86_init.c b/arch/x86/kernel/x86_init.c index c11514e9..75ef4b1 100644 --- a/arch/x86/kernel/x86_init.c +++ b/arch/x86/kernel/x86_init.c @@ -61,6 +61,10 @@ struct x86_init_ops x86_init __initdata = { .banner = default_banner, }, + .mapping = { + .pagetable_reserve = native_pagetable_reserve, + }, + .paging = { .pagetable_setup_start = native_pagetable_setup_start, .pagetable_setup_done = native_pagetable_setup_done, diff --git a/arch/x86/mm/init.c b/arch/x86/mm/init.c index 286d289..722a4c3 100644 --- a/arch/x86/mm/init.c +++ b/arch/x86/mm/init.c @@ -81,6 +81,11 @@ static void __init find_early_table_space(unsigned long end, int use_pse, end, pgt_buf_start << PAGE_SHIFT, pgt_buf_top << PAGE_SHIFT); } +void native_pagetable_reserve(u64 start, u64 end) +{ + memblock_x86_reserve_range(start, end, "PGTABLE"); +} + struct map_range { unsigned long start; unsigned long end; @@ -272,9 +277,24 @@ unsigned long __init_refok init_memory_mapping(unsigned long start, __flush_tlb_all(); + /* + * Reserve the kernel pagetable pages we used (pgt_buf_start - + * pgt_buf_end) and free the other ones (pgt_buf_end - pgt_buf_top) + * so that they can be reused for other purposes. + * + * On native it just means calling memblock_x86_reserve_range, on Xen it + * also means marking RW the pagetable pages that we allocated before + * but that haven't been used. + * + * In fact on xen we mark RO the whole range pgt_buf_start - + * pgt_buf_top, because we have to make sure that when + * init_memory_mapping reaches the pagetable pages area, it maps + * RO all the pagetable pages, including the ones that are beyond + * pgt_buf_end at that time. + */ if (!after_bootmem && pgt_buf_end > pgt_buf_start) - memblock_x86_reserve_range(pgt_buf_start << PAGE_SHIFT, - pgt_buf_end << PAGE_SHIFT, "PGTABLE"); + x86_init.mapping.pagetable_reserve(PFN_PHYS(pgt_buf_start), + PFN_PHYS(pgt_buf_end)); if (!after_bootmem) early_memtest(start, end); diff --git a/arch/x86/xen/mmu.c b/arch/x86/xen/mmu.c index cf4ef61..0684f3c 100644 --- a/arch/x86/xen/mmu.c +++ b/arch/x86/xen/mmu.c @@ -1275,6 +1275,20 @@ static __init void xen_pagetable_setup_start(pgd_t *base) { } +static __init void xen_mapping_pagetable_reserve(u64 start, u64 end) +{ + /* reserve the range used */ + native_pagetable_reserve(start, end); + + /* set as RW the rest */ + printk(KERN_DEBUG "xen: setting RW the range %llx - %llx\n", end, + PFN_PHYS(pgt_buf_top)); + while (end < PFN_PHYS(pgt_buf_top)) { + make_lowmem_page_readwrite(__va(end)); + end += PAGE_SIZE; + } +} + static void xen_post_allocator_init(void); static __init void xen_pagetable_setup_done(pgd_t *base) @@ -2105,6 +2119,7 @@ static const struct pv_mmu_ops xen_mmu_ops __initdata = { void __init xen_init_mmu_ops(void) { + x86_init.mapping.pagetable_reserve = xen_mapping_pagetable_reserve; x86_init.paging.pagetable_setup_start = xen_pagetable_setup_start; x86_init.paging.pagetable_setup_done = xen_pagetable_setup_done; pv_mmu_ops = xen_mmu_ops; -- cgit v0.10.2 From 53f8023febf9b3e18d8fb0d99c55010e473ce53d Mon Sep 17 00:00:00 2001 From: Sedat Dilek Date: Sun, 17 Apr 2011 16:17:34 +0200 Subject: x86/mm: Fix section mismatch derived from native_pagetable_reserve() With CONFIG_DEBUG_SECTION_MISMATCH=y I see these warnings in next-20110415: LD vmlinux.o MODPOST vmlinux.o WARNING: vmlinux.o(.text+0x1ba48): Section mismatch in reference from the function native_pagetable_reserve() to the function .init.text:memblock_x86_reserve_range() The function native_pagetable_reserve() references the function __init memblock_x86_reserve_range(). This is often because native_pagetable_reserve lacks a __init annotation or the annotation of memblock_x86_reserve_range is wrong. This patch fixes the issue. Thanks to pipacs from PaX project for help on IRC. Acked-by: "H. Peter Anvin" Signed-off-by: Sedat Dilek Signed-off-by: Konrad Rzeszutek Wilk diff --git a/arch/x86/mm/init.c b/arch/x86/mm/init.c index 722a4c3..37b8b0f 100644 --- a/arch/x86/mm/init.c +++ b/arch/x86/mm/init.c @@ -81,7 +81,7 @@ static void __init find_early_table_space(unsigned long end, int use_pse, end, pgt_buf_start << PAGE_SHIFT, pgt_buf_top << PAGE_SHIFT); } -void native_pagetable_reserve(u64 start, u64 end) +void __init native_pagetable_reserve(u64 start, u64 end) { memblock_x86_reserve_range(start, end, "PGTABLE"); } -- cgit v0.10.2 From 56d1893d94bc06d0b1aa3a53f924ed02f9e207bf Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 9 May 2011 18:41:15 +0200 Subject: cfg80211: restrict AP beacon intervals Multiple virtual AP interfaces can currently try to use different beacon intervals, but that just leads to problems since it won't actually be done that way by drivers. Return an error in this case to make sure it won't be done wrong. Also, ignore attempts to change the DTIM period or beacon interval during the lifetime of the BSS. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index 1f1e221..a46adb7 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -1908,6 +1908,8 @@ struct cfg80211_cached_keys; * @mgmt_registrations_lock: lock for the list * @mtx: mutex used to lock data in this struct * @cleanup_work: work struct used for cleanup that can't be done directly + * @beacon_interval: beacon interval used on this device for transmitting + * beacons, 0 when not valid */ struct wireless_dev { struct wiphy *wiphy; @@ -1948,6 +1950,8 @@ struct wireless_dev { bool ps; int ps_timeout; + int beacon_interval; + #ifdef CONFIG_CFG80211_WEXT /* wext data */ struct { diff --git a/net/wireless/core.c b/net/wireless/core.c index f924a49..e2ab65d 100644 --- a/net/wireless/core.c +++ b/net/wireless/core.c @@ -787,6 +787,7 @@ static int cfg80211_netdev_notifier_call(struct notifier_block * nb, default: break; } + wdev->beacon_interval = 0; break; case NETDEV_DOWN: dev_hold(dev); diff --git a/net/wireless/core.h b/net/wireless/core.h index e3f7b1d..fd9135f 100644 --- a/net/wireless/core.h +++ b/net/wireless/core.h @@ -433,6 +433,9 @@ int cfg80211_set_freq(struct cfg80211_registered_device *rdev, u16 cfg80211_calculate_bitrate(struct rate_info *rate); +int cfg80211_validate_beacon_int(struct cfg80211_registered_device *rdev, + u32 beacon_int); + #ifdef CONFIG_CFG80211_DEVELOPER_WARNINGS #define CFG80211_DEV_WARN_ON(cond) WARN_ON(cond) #else diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index b5b050b..9ef8e28 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -1876,8 +1876,9 @@ static int nl80211_addset_beacon(struct sk_buff *skb, struct genl_info *info) struct beacon_parameters *info); struct cfg80211_registered_device *rdev = info->user_ptr[0]; struct net_device *dev = info->user_ptr[1]; + struct wireless_dev *wdev = dev->ieee80211_ptr; struct beacon_parameters params; - int haveinfo = 0; + int haveinfo = 0, err; if (!is_valid_ie_attr(info->attrs[NL80211_ATTR_BEACON_TAIL])) return -EINVAL; @@ -1886,6 +1887,8 @@ static int nl80211_addset_beacon(struct sk_buff *skb, struct genl_info *info) dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO) return -EOPNOTSUPP; + memset(¶ms, 0, sizeof(params)); + switch (info->genlhdr->cmd) { case NL80211_CMD_NEW_BEACON: /* these are required for NEW_BEACON */ @@ -1894,6 +1897,15 @@ static int nl80211_addset_beacon(struct sk_buff *skb, struct genl_info *info) !info->attrs[NL80211_ATTR_BEACON_HEAD]) return -EINVAL; + params.interval = + nla_get_u32(info->attrs[NL80211_ATTR_BEACON_INTERVAL]); + params.dtim_period = + nla_get_u32(info->attrs[NL80211_ATTR_DTIM_PERIOD]); + + err = cfg80211_validate_beacon_int(rdev, params.interval); + if (err) + return err; + call = rdev->ops->add_beacon; break; case NL80211_CMD_SET_BEACON: @@ -1907,20 +1919,6 @@ static int nl80211_addset_beacon(struct sk_buff *skb, struct genl_info *info) if (!call) return -EOPNOTSUPP; - memset(¶ms, 0, sizeof(params)); - - if (info->attrs[NL80211_ATTR_BEACON_INTERVAL]) { - params.interval = - nla_get_u32(info->attrs[NL80211_ATTR_BEACON_INTERVAL]); - haveinfo = 1; - } - - if (info->attrs[NL80211_ATTR_DTIM_PERIOD]) { - params.dtim_period = - nla_get_u32(info->attrs[NL80211_ATTR_DTIM_PERIOD]); - haveinfo = 1; - } - if (info->attrs[NL80211_ATTR_BEACON_HEAD]) { params.head = nla_data(info->attrs[NL80211_ATTR_BEACON_HEAD]); params.head_len = @@ -1938,13 +1936,18 @@ static int nl80211_addset_beacon(struct sk_buff *skb, struct genl_info *info) if (!haveinfo) return -EINVAL; - return call(&rdev->wiphy, dev, ¶ms); + err = call(&rdev->wiphy, dev, ¶ms); + if (!err && params.interval) + wdev->beacon_interval = params.interval; + return err; } static int nl80211_del_beacon(struct sk_buff *skb, struct genl_info *info) { struct cfg80211_registered_device *rdev = info->user_ptr[0]; struct net_device *dev = info->user_ptr[1]; + struct wireless_dev *wdev = dev->ieee80211_ptr; + int err; if (!rdev->ops->del_beacon) return -EOPNOTSUPP; @@ -1953,7 +1956,10 @@ static int nl80211_del_beacon(struct sk_buff *skb, struct genl_info *info) dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO) return -EOPNOTSUPP; - return rdev->ops->del_beacon(&rdev->wiphy, dev); + err = rdev->ops->del_beacon(&rdev->wiphy, dev); + if (!err) + wdev->beacon_interval = 0; + return err; } static const struct nla_policy sta_flags_policy[NL80211_STA_FLAG_MAX + 1] = { diff --git a/net/wireless/util.c b/net/wireless/util.c index 6a750bc..414c9f6 100644 --- a/net/wireless/util.c +++ b/net/wireless/util.c @@ -896,3 +896,28 @@ u16 cfg80211_calculate_bitrate(struct rate_info *rate) /* do NOT round down here */ return (bitrate + 50000) / 100000; } + +int cfg80211_validate_beacon_int(struct cfg80211_registered_device *rdev, + u32 beacon_int) +{ + struct wireless_dev *wdev; + int res = 0; + + if (!beacon_int) + return -EINVAL; + + mutex_lock(&rdev->devlist_mtx); + + list_for_each_entry(wdev, &rdev->netdev_list, list) { + if (!wdev->beacon_interval) + continue; + if (wdev->beacon_interval != beacon_int) { + res = -EINVAL; + break; + } + } + + mutex_unlock(&rdev->devlist_mtx); + + return res; +} -- cgit v0.10.2 From 8fddddff0ad4ccc2787464207eba9ed3063e69cd Mon Sep 17 00:00:00 2001 From: Daniel Halperin Date: Tue, 10 May 2011 19:00:45 -0700 Subject: mac80211: fix contention time computation in minstrel, minstrel_ht When transmitting a frame, the transmitter waits a random number of slots between 0 and cw. Thus, the contention time is (cw / 2) * t_slot which we can represent instead as (cw * t_slot) >> 1. Also fix a few other accounting bugs around contention time, and add comments. Signed-off-by: Daniel Halperin Signed-off-by: John W. Linville diff --git a/net/mac80211/rc80211_minstrel.c b/net/mac80211/rc80211_minstrel.c index 778c604..8adac67 100644 --- a/net/mac80211/rc80211_minstrel.c +++ b/net/mac80211/rc80211_minstrel.c @@ -417,8 +417,8 @@ minstrel_rate_init(void *priv, struct ieee80211_supported_band *sband, tx_time_single = mr->ack_time + mr->perfect_tx_time; /* contention window */ - tx_time_single += t_slot + min(cw, mp->cw_max); - cw = (cw << 1) | 1; + tx_time_single += (t_slot * cw) >> 1; + cw = min((cw << 1) | 1, mp->cw_max); tx_time += tx_time_single; tx_time_cts += tx_time_single + mi->sp_ack_dur; diff --git a/net/mac80211/rc80211_minstrel_ht.c b/net/mac80211/rc80211_minstrel_ht.c index dbdebeda..3d09c58 100644 --- a/net/mac80211/rc80211_minstrel_ht.c +++ b/net/mac80211/rc80211_minstrel_ht.c @@ -464,6 +464,7 @@ minstrel_calc_retransmit(struct minstrel_priv *mp, struct minstrel_ht_sta *mi, const struct mcs_group *group; unsigned int tx_time, tx_time_rtscts, tx_time_data; unsigned int cw = mp->cw_min; + unsigned int ctime = 0; unsigned int t_slot = 9; /* FIXME */ unsigned int ampdu_len = MINSTREL_TRUNC(mi->avg_ampdu_len); @@ -480,13 +481,27 @@ minstrel_calc_retransmit(struct minstrel_priv *mp, struct minstrel_ht_sta *mi, group = &minstrel_mcs_groups[index / MCS_GROUP_RATES]; tx_time_data = group->duration[index % MCS_GROUP_RATES] * ampdu_len; - tx_time = 2 * (t_slot + mi->overhead + tx_time_data); - tx_time_rtscts = 2 * (t_slot + mi->overhead_rtscts + tx_time_data); + + /* Contention time for first 2 tries */ + ctime = (t_slot * cw) >> 1; + cw = min((cw << 1) | 1, mp->cw_max); + ctime += (t_slot * cw) >> 1; + cw = min((cw << 1) | 1, mp->cw_max); + + /* Total TX time for data and Contention after first 2 tries */ + tx_time = ctime + 2 * (mi->overhead + tx_time_data); + tx_time_rtscts = ctime + 2 * (mi->overhead_rtscts + tx_time_data); + + /* See how many more tries we can fit inside segment size */ do { - cw = (cw << 1) | 1; - cw = min(cw, mp->cw_max); - tx_time += cw + t_slot + mi->overhead; - tx_time_rtscts += cw + t_slot + mi->overhead_rtscts; + /* Contention time for this try */ + ctime = (t_slot * cw) >> 1; + cw = min((cw << 1) | 1, mp->cw_max); + + /* Total TX time after this try */ + tx_time += ctime + mi->overhead + tx_time_data; + tx_time_rtscts += ctime + mi->overhead_rtscts + tx_time_data; + if (tx_time_rtscts < mp->segment_size) mr->retry_count_rtscts++; } while ((tx_time < mp->segment_size) && -- cgit v0.10.2 From 9ba7f4f5eba5f4b44c7796bbad29f8ec3a7d5864 Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Wed, 11 May 2011 14:57:26 -0700 Subject: ath9k_hw: fix dual band assumption for XB113 The XB113 cards are single band, 5 GHz-only, but the default settings were configured to assume it was dual band. Users of these cards then would see 2.4 GHz channels but you would never get any scan results from these channels given that the radio is not present. Cc: stable@kernel.org Cc: Fiona Cain Cc: Ray Li Cc: Kathy Giori Cc: Aeolus Yang Cc: Dan Friedman Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c b/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c index 070dc8b..0647cc5 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c @@ -652,7 +652,7 @@ static const struct ar9300_eeprom ar9300_x113 = { .regDmn = { LE16(0), LE16(0x1f) }, .txrxMask = 0x77, /* 4 bits tx and 4 bits rx */ .opCapFlags = { - .opFlags = AR5416_OPFLAGS_11G | AR5416_OPFLAGS_11A, + .opFlags = AR5416_OPFLAGS_11A, .eepMisc = 0, }, .rfSilent = 0, -- cgit v0.10.2 From f1a9c1e694f84938e6526590d23e88a791a8069f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= Date: Thu, 12 May 2011 00:01:47 +0200 Subject: bcma: pci: trivial: correct amount of maximum retries 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 diff --git a/drivers/bcma/driver_pci.c b/drivers/bcma/driver_pci.c index b98b835..e757e4e 100644 --- a/drivers/bcma/driver_pci.c +++ b/drivers/bcma/driver_pci.c @@ -81,7 +81,7 @@ static u16 bcma_pcie_mdio_read(struct bcma_drv_pci *pc, u8 device, u8 address) pcicore_write32(pc, mdio_data, v); /* Wait for the device to complete the transaction */ udelay(10); - for (i = 0; i < 200; i++) { + for (i = 0; i < max_retries; i++) { v = pcicore_read32(pc, mdio_control); if (v & 0x100 /* Trans complete */) { udelay(10); -- cgit v0.10.2 From 406a39ec00992090cda034625e176504eb7a71f9 Mon Sep 17 00:00:00 2001 From: Amitkumar Karwar Date: Wed, 11 May 2011 19:47:11 -0700 Subject: mwifiex: remove mwifiex_recv_complete function The function - increments dropped rx_packet count if status code passed to it is "-1". - frees SKB buffer. But currently the function is being called with "0" status code. This patch replaces above function by dev_kfree_skb_any() call. Signed-off-by: Amitkumar Karwar Signed-off-by: Bing Zhao Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/mwifiex/cmdevt.c b/drivers/net/wireless/mwifiex/cmdevt.c index 5c75399..cd89fed 100644 --- a/drivers/net/wireless/mwifiex/cmdevt.c +++ b/drivers/net/wireless/mwifiex/cmdevt.c @@ -91,7 +91,7 @@ mwifiex_clean_cmd_node(struct mwifiex_adapter *adapter, cmd_node->wait_q_enabled = false; if (cmd_node->resp_skb) { - mwifiex_recv_complete(adapter, cmd_node->resp_skb, 0); + dev_kfree_skb_any(cmd_node->resp_skb); cmd_node->resp_skb = NULL; } } @@ -339,7 +339,7 @@ int mwifiex_free_cmd_buffer(struct mwifiex_adapter *adapter) } if (!cmd_array[i].resp_skb) continue; - mwifiex_recv_complete(adapter, cmd_array[i].resp_skb, 0); + dev_kfree_skb_any(cmd_array[i].resp_skb); } /* Release struct cmd_ctrl_node */ if (adapter->cmd_pool) { @@ -402,7 +402,7 @@ int mwifiex_process_event(struct mwifiex_adapter *adapter) adapter->event_cause = 0; adapter->event_skb = NULL; - mwifiex_recv_complete(adapter, skb, 0); + dev_kfree_skb_any(skb); return ret; } diff --git a/drivers/net/wireless/mwifiex/main.h b/drivers/net/wireless/mwifiex/main.h index b4bb5ec..672701d 100644 --- a/drivers/net/wireless/mwifiex/main.h +++ b/drivers/net/wireless/mwifiex/main.h @@ -692,10 +692,6 @@ int mwifiex_shutdown_fw_complete(struct mwifiex_adapter *adapter); int mwifiex_dnld_fw(struct mwifiex_adapter *, struct mwifiex_fw_image *); -int mwifiex_recv_complete(struct mwifiex_adapter *, - struct sk_buff *skb, - int status); - int mwifiex_recv_packet(struct mwifiex_adapter *, struct sk_buff *skb); int mwifiex_process_event(struct mwifiex_adapter *adapter); diff --git a/drivers/net/wireless/mwifiex/util.c b/drivers/net/wireless/mwifiex/util.c index a8d53aa7..d412915 100644 --- a/drivers/net/wireless/mwifiex/util.c +++ b/drivers/net/wireless/mwifiex/util.c @@ -177,31 +177,6 @@ int mwifiex_recv_packet(struct mwifiex_adapter *adapter, struct sk_buff *skb) } /* - * Receive packet completion callback handler. - * - * This function updates the statistics and frees the buffer SKB. - */ -int mwifiex_recv_complete(struct mwifiex_adapter *adapter, - struct sk_buff *skb, int status) -{ - struct mwifiex_private *priv; - struct mwifiex_rxinfo *rx_info; - - if (!skb) - return 0; - - rx_info = MWIFIEX_SKB_RXCB(skb); - priv = mwifiex_bss_index_to_priv(adapter, rx_info->bss_index); - - if (priv && (status == -1)) - priv->stats.rx_dropped++; - - dev_kfree_skb_any(skb); - - return 0; -} - -/* * IOCTL completion callback handler. * * This function is called when a pending IOCTL is completed. -- cgit v0.10.2 From be0e6aa5a0c487a2a0880dda8bc70f7f1860fc39 Mon Sep 17 00:00:00 2001 From: Senthil Balasubramanian Date: Thu, 12 May 2011 16:24:28 +0530 Subject: ath9k_hw: Fix STA connection issues with AR9380 (XB113). XB113 (AR9380) 3x3 SB 5G only cards were failing to connect to APs due to incorrect xpabiaslevel configuration. fix it. Cc: stable@kernel.org Cc: Ray Li Cc: Kathy Giori Cc: Aeolus Yang Cc: compat@orbit-lab.org Signed-off-by: Senthil Balasubramanian Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c b/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c index 0647cc5..6dfb69a 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c @@ -922,7 +922,7 @@ static const struct ar9300_eeprom ar9300_x113 = { .db_stage2 = {3, 3, 3}, /* 3 chain */ .db_stage3 = {3, 3, 3}, /* doesn't exist for 2G */ .db_stage4 = {3, 3, 3}, /* don't exist for 2G */ - .xpaBiasLvl = 0, + .xpaBiasLvl = 0xf, .txFrameToDataStart = 0x0e, .txFrameToPaOn = 0x0e, .txClip = 3, /* 4 bits tx_clip, 4 bits dac_scale_cck */ -- cgit v0.10.2 From dea4096bc41a9642039840ced91e585d04883a16 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 12 May 2011 15:03:32 +0200 Subject: mac80211: remove pointless mesh path timer RCU code The code here to RCU-dereference a pointer that's on the stack is totally pointless, RCU isn't magic (like say Java's weak references are), so the code can't work like whoever wrote it thought it might. Remove it so readers don't get confused. Note that it seems that a bug is there anyway: I don't see any code that cancels the timer when a mesh path struct is destroyed. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville diff --git a/net/mac80211/mesh_hwmp.c b/net/mac80211/mesh_hwmp.c index 849fecd..2aec7c4 100644 --- a/net/mac80211/mesh_hwmp.c +++ b/net/mac80211/mesh_hwmp.c @@ -966,20 +966,11 @@ endlookup: void mesh_path_timer(unsigned long data) { - struct ieee80211_sub_if_data *sdata; - struct mesh_path *mpath; - - rcu_read_lock(); - mpath = (struct mesh_path *) data; - mpath = rcu_dereference(mpath); - if (!mpath) - goto endmpathtimer; - sdata = mpath->sdata; + struct mesh_path *mpath = (void *) data; + struct ieee80211_sub_if_data *sdata = mpath->sdata; - if (sdata->local->quiescing) { - rcu_read_unlock(); + if (sdata->local->quiescing) return; - } spin_lock_bh(&mpath->state_lock); if (mpath->flags & MESH_PATH_RESOLVED || @@ -996,8 +987,6 @@ void mesh_path_timer(unsigned long data) } spin_unlock_bh(&mpath->state_lock); -endmpathtimer: - rcu_read_unlock(); } void -- cgit v0.10.2 From 5c0c36412b2dc6b1e243c7e9115306fe286583b7 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 12 May 2011 14:31:49 +0200 Subject: mac80211: make key locking clearer The code in ieee80211_del_key() doesn't acquire the key_mtx properly when it dereferences the keys. It turns out that isn't actually necessary since the key_mtx itself seems to be redundant since all key manipulations are done under the RTNL, but as long as we have the key_mtx we should use it the right way too. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index ed3400c..9469036 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -160,13 +160,14 @@ static int ieee80211_add_key(struct wiphy *wiphy, struct net_device *dev, static int ieee80211_del_key(struct wiphy *wiphy, struct net_device *dev, u8 key_idx, bool pairwise, const u8 *mac_addr) { - struct ieee80211_sub_if_data *sdata; + struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); + struct ieee80211_local *local = sdata->local; struct sta_info *sta; + struct ieee80211_key *key = NULL; int ret; - sdata = IEEE80211_DEV_TO_SUB_IF(dev); - - mutex_lock(&sdata->local->sta_mtx); + mutex_lock(&local->sta_mtx); + mutex_lock(&local->key_mtx); if (mac_addr) { ret = -ENOENT; @@ -175,33 +176,24 @@ static int ieee80211_del_key(struct wiphy *wiphy, struct net_device *dev, if (!sta) goto out_unlock; - if (pairwise) { - if (sta->ptk) { - ieee80211_key_free(sdata->local, sta->ptk); - ret = 0; - } - } else { - if (sta->gtk[key_idx]) { - ieee80211_key_free(sdata->local, - sta->gtk[key_idx]); - ret = 0; - } - } - - goto out_unlock; - } + if (pairwise) + key = sta->ptk; + else + key = sta->gtk[key_idx]; + } else + key = sdata->keys[key_idx]; - if (!sdata->keys[key_idx]) { + if (!key) { ret = -ENOENT; goto out_unlock; } - ieee80211_key_free(sdata->local, sdata->keys[key_idx]); - WARN_ON(sdata->keys[key_idx]); + __ieee80211_key_free(key); ret = 0; out_unlock: - mutex_unlock(&sdata->local->sta_mtx); + mutex_unlock(&local->key_mtx); + mutex_unlock(&local->sta_mtx); return ret; } diff --git a/net/mac80211/key.c b/net/mac80211/key.c index b510721..958832dd 100644 --- a/net/mac80211/key.c +++ b/net/mac80211/key.c @@ -471,8 +471,11 @@ int ieee80211_key_link(struct ieee80211_key *key, return ret; } -static void __ieee80211_key_free(struct ieee80211_key *key) +void __ieee80211_key_free(struct ieee80211_key *key) { + if (!key) + return; + /* * Replace key with nothingness if it was ever used. */ @@ -486,9 +489,6 @@ static void __ieee80211_key_free(struct ieee80211_key *key) void ieee80211_key_free(struct ieee80211_local *local, struct ieee80211_key *key) { - if (!key) - return; - mutex_lock(&local->key_mtx); __ieee80211_key_free(key); mutex_unlock(&local->key_mtx); diff --git a/net/mac80211/key.h b/net/mac80211/key.h index 4ddbe27..e5432ef 100644 --- a/net/mac80211/key.h +++ b/net/mac80211/key.h @@ -135,6 +135,7 @@ struct ieee80211_key *ieee80211_key_alloc(u32 cipher, int idx, size_t key_len, int __must_check ieee80211_key_link(struct ieee80211_key *key, struct ieee80211_sub_if_data *sdata, struct sta_info *sta); +void __ieee80211_key_free(struct ieee80211_key *key); void ieee80211_key_free(struct ieee80211_local *local, struct ieee80211_key *key); void ieee80211_set_default_key(struct ieee80211_sub_if_data *sdata, int idx, -- cgit v0.10.2 From 8cb231530f03961b55aa4e84e6ead5590bcde04d Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 12 May 2011 15:07:15 +0200 Subject: mac80211: fix another key non-race The code here is only not racy because all the places that assign the pointers it uses are holding the sta_mtx as well as the key_mtx and so can't race against this because this code holds the sta_mtx. But that's not intuitive, so fix it to hold the key_mtx. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c index f05244d..cba8309 100644 --- a/net/mac80211/sta_info.c +++ b/net/mac80211/sta_info.c @@ -652,10 +652,12 @@ static int __must_check __sta_info_destroy(struct sta_info *sta) if (ret) return ret; + mutex_lock(&local->key_mtx); for (i = 0; i < NUM_DEFAULT_KEYS; i++) - ieee80211_key_free(local, sta->gtk[i]); + __ieee80211_key_free(sta->gtk[i]); if (sta->ptk) - ieee80211_key_free(local, sta->ptk); + __ieee80211_key_free(sta->ptk); + mutex_unlock(&local->key_mtx); sta->dead = true; -- cgit v0.10.2 From a3836e02ba4c50db958d32d710b226f2408623dc Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 12 May 2011 15:11:37 +0200 Subject: mac80211: fix a few RCU issues A few configuration functions correctly do rcu_read_lock() but don't correctly reference some pointers protected by RCU. Fix that. Cc: stable@kernel.org Signed-off-by: Johannes Berg Signed-off-by: John W. Linville diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index 9469036..303f33f 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -223,11 +223,11 @@ static int ieee80211_get_key(struct wiphy *wiphy, struct net_device *dev, goto out; if (pairwise) - key = sta->ptk; + key = rcu_dereference(sta->ptk); else if (key_idx < NUM_DEFAULT_KEYS) - key = sta->gtk[key_idx]; + key = rcu_dereference(sta->gtk[key_idx]); } else - key = sdata->keys[key_idx]; + key = rcu_dereference(sdata->keys[key_idx]); if (!key) goto out; @@ -952,8 +952,10 @@ static int ieee80211_change_mpath(struct wiphy *wiphy, static void mpath_set_pinfo(struct mesh_path *mpath, u8 *next_hop, struct mpath_info *pinfo) { - if (mpath->next_hop) - memcpy(next_hop, mpath->next_hop->sta.addr, ETH_ALEN); + struct sta_info *next_hop_sta = rcu_dereference(mpath->next_hop); + + if (next_hop_sta) + memcpy(next_hop, next_hop_sta->sta.addr, ETH_ALEN); else memset(next_hop, 0, ETH_ALEN); -- cgit v0.10.2 From 85a9994a0a6cba1a6cc6af4bd3ebd85f778be0fe Mon Sep 17 00:00:00 2001 From: Luciano Coelho Date: Thu, 12 May 2011 16:28:29 +0300 Subject: cfg80211/mac80211: avoid bounce back mac->cfg->mac on sched_scan_stopped When sched_scan_stopped was called by the driver, mac80211 calls cfg80211, which in turn was calling mac80211 back with a flag "driver_initiated". This flag was used so that mac80211 would do the necessary cleanup but would not call the driver. This was enough to prevent the bounce back between the driver and mac80211, but not between mac80211 and cfg80211. To fix this, we now do the cleanup in mac80211 before calling cfg80211. To help with locking issues, the workqueue was moved from cfg80211 to mac80211. Reported-by: Johannes Berg Signed-off-by: Luciano Coelho Signed-off-by: John W. Linville diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index a46adb7..e1f1b41 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -1515,8 +1515,7 @@ struct cfg80211_ops { int (*sched_scan_start)(struct wiphy *wiphy, struct net_device *dev, struct cfg80211_sched_scan_request *request); - int (*sched_scan_stop)(struct wiphy *wiphy, struct net_device *dev, - bool driver_initiated); + int (*sched_scan_stop)(struct wiphy *wiphy, struct net_device *dev); }; /* diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index 303f33f..2d1c1a5 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -1372,15 +1372,14 @@ ieee80211_sched_scan_start(struct wiphy *wiphy, } static int -ieee80211_sched_scan_stop(struct wiphy *wiphy, struct net_device *dev, - bool driver_initiated) +ieee80211_sched_scan_stop(struct wiphy *wiphy, struct net_device *dev) { struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); if (!sdata->local->ops->sched_scan_stop) return -EOPNOTSUPP; - return ieee80211_request_sched_scan_stop(sdata, driver_initiated); + return ieee80211_request_sched_scan_stop(sdata); } static int ieee80211_auth(struct wiphy *wiphy, struct net_device *dev, diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 6f55a78..82f90ff 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -849,6 +849,7 @@ struct ieee80211_local { bool sched_scanning; struct ieee80211_sched_scan_ies sched_scan_ies; + struct work_struct sched_scan_stopped_work; unsigned long leave_oper_channel_time; enum mac80211_scan_state next_scan_state; @@ -1160,8 +1161,8 @@ void ieee80211_rx_bss_put(struct ieee80211_local *local, /* scheduled scan handling */ int ieee80211_request_sched_scan_start(struct ieee80211_sub_if_data *sdata, struct cfg80211_sched_scan_request *req); -int ieee80211_request_sched_scan_stop(struct ieee80211_sub_if_data *sdata, - bool driver_initiated); +int ieee80211_request_sched_scan_stop(struct ieee80211_sub_if_data *sdata); +void ieee80211_sched_scan_stopped_work(struct work_struct *work); /* off-channel helpers */ bool ieee80211_cfg_on_oper_channel(struct ieee80211_local *local); diff --git a/net/mac80211/main.c b/net/mac80211/main.c index 30e6a68..7f89011 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c @@ -652,6 +652,9 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len, setup_timer(&local->dynamic_ps_timer, ieee80211_dynamic_ps_timer, (unsigned long) local); + INIT_WORK(&local->sched_scan_stopped_work, + ieee80211_sched_scan_stopped_work); + sta_info_init(local); for (i = 0; i < IEEE80211_MAX_QUEUES; i++) { diff --git a/net/mac80211/scan.c b/net/mac80211/scan.c index ea44a8e..d20046b 100644 --- a/net/mac80211/scan.c +++ b/net/mac80211/scan.c @@ -902,8 +902,7 @@ out: return ret; } -int ieee80211_request_sched_scan_stop(struct ieee80211_sub_if_data *sdata, - bool driver_initiated) +int ieee80211_request_sched_scan_stop(struct ieee80211_sub_if_data *sdata) { struct ieee80211_local *local = sdata->local; int ret = 0, i; @@ -919,11 +918,9 @@ int ieee80211_request_sched_scan_stop(struct ieee80211_sub_if_data *sdata, for (i = 0; i < IEEE80211_NUM_BANDS; i++) kfree(local->sched_scan_ies.ie[i]); - if (!driver_initiated) - drv_sched_scan_stop(local, sdata); + drv_sched_scan_stop(local, sdata); local->sched_scanning = false; } - out: mutex_unlock(&sdata->local->mtx); @@ -940,12 +937,36 @@ void ieee80211_sched_scan_results(struct ieee80211_hw *hw) } EXPORT_SYMBOL(ieee80211_sched_scan_results); +void ieee80211_sched_scan_stopped_work(struct work_struct *work) +{ + struct ieee80211_local *local = + container_of(work, struct ieee80211_local, + sched_scan_stopped_work); + int i; + + mutex_lock(&local->mtx); + + if (!local->sched_scanning) { + mutex_unlock(&local->mtx); + return; + } + + for (i = 0; i < IEEE80211_NUM_BANDS; i++) + kfree(local->sched_scan_ies.ie[i]); + + local->sched_scanning = false; + + mutex_unlock(&local->mtx); + + cfg80211_sched_scan_stopped(local->hw.wiphy); +} + void ieee80211_sched_scan_stopped(struct ieee80211_hw *hw) { struct ieee80211_local *local = hw_to_local(hw); trace_api_sched_scan_stopped(local); - cfg80211_sched_scan_stopped(hw->wiphy); + ieee80211_queue_work(&local->hw, &local->sched_scan_stopped_work); } EXPORT_SYMBOL(ieee80211_sched_scan_stopped); diff --git a/net/wireless/core.c b/net/wireless/core.c index e2ab65d..18b002f 100644 --- a/net/wireless/core.c +++ b/net/wireless/core.c @@ -371,7 +371,6 @@ struct wiphy *wiphy_new(const struct cfg80211_ops *ops, int sizeof_priv) INIT_LIST_HEAD(&rdev->bss_list); INIT_WORK(&rdev->scan_done_wk, __cfg80211_scan_done); INIT_WORK(&rdev->sched_scan_results_wk, __cfg80211_sched_scan_results); - INIT_WORK(&rdev->sched_scan_stopped_wk, __cfg80211_sched_scan_stopped); #ifdef CONFIG_CFG80211_WEXT rdev->wiphy.wext = &cfg80211_wext_handler; #endif diff --git a/net/wireless/core.h b/net/wireless/core.h index fd9135f..d4b8f4c 100644 --- a/net/wireless/core.h +++ b/net/wireless/core.h @@ -64,7 +64,6 @@ struct cfg80211_registered_device { unsigned long suspend_at; struct work_struct scan_done_wk; struct work_struct sched_scan_results_wk; - struct work_struct sched_scan_stopped_wk; #ifdef CONFIG_NL80211_TESTMODE struct genl_info *testmode_info; @@ -417,7 +416,6 @@ void ___cfg80211_scan_done(struct cfg80211_registered_device *rdev, bool leak); void __cfg80211_sched_scan_results(struct work_struct *wk); int __cfg80211_stop_sched_scan(struct cfg80211_registered_device *rdev, bool driver_initiated); -void __cfg80211_sched_scan_stopped(struct work_struct *wk); void cfg80211_upload_connect_keys(struct wireless_dev *wdev); int cfg80211_change_iface(struct cfg80211_registered_device *rdev, struct net_device *dev, enum nl80211_iftype ntype, diff --git a/net/wireless/scan.c b/net/wireless/scan.c index 65dfae3..73a441d 100644 --- a/net/wireless/scan.c +++ b/net/wireless/scan.c @@ -119,22 +119,14 @@ void cfg80211_sched_scan_results(struct wiphy *wiphy) } EXPORT_SYMBOL(cfg80211_sched_scan_results); -void __cfg80211_sched_scan_stopped(struct work_struct *wk) +void cfg80211_sched_scan_stopped(struct wiphy *wiphy) { - struct cfg80211_registered_device *rdev; - - rdev = container_of(wk, struct cfg80211_registered_device, - sched_scan_stopped_wk); + struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); cfg80211_lock_rdev(rdev); __cfg80211_stop_sched_scan(rdev, true); cfg80211_unlock_rdev(rdev); } - -void cfg80211_sched_scan_stopped(struct wiphy *wiphy) -{ - queue_work(cfg80211_wq, &wiphy_to_dev(wiphy)->sched_scan_stopped_wk); -} EXPORT_SYMBOL(cfg80211_sched_scan_stopped); int __cfg80211_stop_sched_scan(struct cfg80211_registered_device *rdev, @@ -150,10 +142,11 @@ int __cfg80211_stop_sched_scan(struct cfg80211_registered_device *rdev, dev = rdev->sched_scan_req->dev; - err = rdev->ops->sched_scan_stop(&rdev->wiphy, dev, - driver_initiated); - if (err) - return err; + if (!driver_initiated) { + err = rdev->ops->sched_scan_stop(&rdev->wiphy, dev); + if (err) + return err; + } nl80211_send_sched_scan(rdev, dev, NL80211_CMD_SCHED_SCAN_STOPPED); -- cgit v0.10.2 From 6b86bd62a505a4a9739474f00f8088395b7a80ba Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 12 May 2011 13:38:50 +0200 Subject: mac80211: mesh: move some code to make it static There's no need to have table functions in one file and all users in another, move the functions to the right file and make them static. Also move a static variable to the beginning of the file to make it easier to find. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville diff --git a/net/mac80211/mesh.c b/net/mac80211/mesh.c index 75378e8..29e9980 100644 --- a/net/mac80211/mesh.c +++ b/net/mac80211/mesh.c @@ -287,49 +287,6 @@ void mesh_mgmt_ies_add(struct sk_buff *skb, struct ieee80211_sub_if_data *sdata) } } -u32 mesh_table_hash(u8 *addr, struct ieee80211_sub_if_data *sdata, struct mesh_table *tbl) -{ - /* Use last four bytes of hw addr and interface index as hash index */ - return jhash_2words(*(u32 *)(addr+2), sdata->dev->ifindex, tbl->hash_rnd) - & tbl->hash_mask; -} - -struct mesh_table *mesh_table_alloc(int size_order) -{ - int i; - struct mesh_table *newtbl; - - newtbl = kmalloc(sizeof(struct mesh_table), GFP_KERNEL); - if (!newtbl) - return NULL; - - newtbl->hash_buckets = kzalloc(sizeof(struct hlist_head) * - (1 << size_order), GFP_KERNEL); - - if (!newtbl->hash_buckets) { - kfree(newtbl); - return NULL; - } - - newtbl->hashwlock = kmalloc(sizeof(spinlock_t) * - (1 << size_order), GFP_KERNEL); - if (!newtbl->hashwlock) { - kfree(newtbl->hash_buckets); - kfree(newtbl); - return NULL; - } - - newtbl->size_order = size_order; - newtbl->hash_mask = (1 << size_order) - 1; - atomic_set(&newtbl->entries, 0); - get_random_bytes(&newtbl->hash_rnd, - sizeof(newtbl->hash_rnd)); - for (i = 0; i <= newtbl->hash_mask; i++) - spin_lock_init(&newtbl->hashwlock[i]); - - return newtbl; -} - static void ieee80211_mesh_path_timer(unsigned long data) { diff --git a/net/mac80211/mesh.h b/net/mac80211/mesh.h index 10acf1c..5c0c2038 100644 --- a/net/mac80211/mesh.h +++ b/net/mac80211/mesh.h @@ -240,12 +240,8 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, /* Private interfaces */ /* Mesh tables */ -struct mesh_table *mesh_table_alloc(int size_order); -void mesh_table_free(struct mesh_table *tbl, bool free_leafs); void mesh_mpath_table_grow(void); void mesh_mpp_table_grow(void); -u32 mesh_table_hash(u8 *addr, struct ieee80211_sub_if_data *sdata, - struct mesh_table *tbl); /* Mesh paths */ int mesh_path_error_tx(u8 ttl, u8 *target, __le32 target_sn, __le16 target_rcode, const u8 *ra, struct ieee80211_sub_if_data *sdata); diff --git a/net/mac80211/mesh_pathtbl.c b/net/mac80211/mesh_pathtbl.c index c7cb3cc..0aa96cd 100644 --- a/net/mac80211/mesh_pathtbl.c +++ b/net/mac80211/mesh_pathtbl.c @@ -40,6 +40,50 @@ static struct mesh_table *mesh_paths; static struct mesh_table *mpp_paths; /* Store paths for MPP&MAP */ int mesh_paths_generation; + +/* This lock will have the grow table function as writer and add / delete nodes + * as readers. When reading the table (i.e. doing lookups) we are well protected + * by RCU + */ +static DEFINE_RWLOCK(pathtbl_resize_lock); + + +static struct mesh_table *mesh_table_alloc(int size_order) +{ + int i; + struct mesh_table *newtbl; + + newtbl = kmalloc(sizeof(struct mesh_table), GFP_KERNEL); + if (!newtbl) + return NULL; + + newtbl->hash_buckets = kzalloc(sizeof(struct hlist_head) * + (1 << size_order), GFP_KERNEL); + + if (!newtbl->hash_buckets) { + kfree(newtbl); + return NULL; + } + + newtbl->hashwlock = kmalloc(sizeof(spinlock_t) * + (1 << size_order), GFP_KERNEL); + if (!newtbl->hashwlock) { + kfree(newtbl->hash_buckets); + kfree(newtbl); + return NULL; + } + + newtbl->size_order = size_order; + newtbl->hash_mask = (1 << size_order) - 1; + atomic_set(&newtbl->entries, 0); + get_random_bytes(&newtbl->hash_rnd, + sizeof(newtbl->hash_rnd)); + for (i = 0; i <= newtbl->hash_mask; i++) + spin_lock_init(&newtbl->hashwlock[i]); + + return newtbl; +} + static void __mesh_table_free(struct mesh_table *tbl) { kfree(tbl->hash_buckets); @@ -47,7 +91,7 @@ static void __mesh_table_free(struct mesh_table *tbl) kfree(tbl); } -void mesh_table_free(struct mesh_table *tbl, bool free_leafs) +static void mesh_table_free(struct mesh_table *tbl, bool free_leafs) { struct hlist_head *mesh_hash; struct hlist_node *p, *q; @@ -66,7 +110,7 @@ void mesh_table_free(struct mesh_table *tbl, bool free_leafs) } static int mesh_table_grow(struct mesh_table *oldtbl, - struct mesh_table *newtbl) + struct mesh_table *newtbl) { struct hlist_head *oldhash; struct hlist_node *p, *q; @@ -97,12 +141,14 @@ errcopy: return -ENOMEM; } +static u32 mesh_table_hash(u8 *addr, struct ieee80211_sub_if_data *sdata, + struct mesh_table *tbl) +{ + /* Use last four bytes of hw addr and interface index as hash index */ + return jhash_2words(*(u32 *)(addr+2), sdata->dev->ifindex, tbl->hash_rnd) + & tbl->hash_mask; +} -/* This lock will have the grow table function as writer and add / delete nodes - * as readers. When reading the table (i.e. doing lookups) we are well protected - * by RCU - */ -static DEFINE_RWLOCK(pathtbl_resize_lock); /** * -- cgit v0.10.2 From 7899891c7d161752f29abcc9bc0a9c6c3a3af26c Mon Sep 17 00:00:00 2001 From: "Tian, Kevin" Date: Thu, 12 May 2011 10:56:08 +0800 Subject: xen mmu: fix a race window causing leave_mm BUG() There's a race window in xen_drop_mm_ref, where remote cpu may exit dirty bitmap between the check on this cpu and the point where remote cpu handles drop request. So in drop_other_mm_ref we need check whether TLB state is still lazy before calling into leave_mm. This bug is rarely observed in earlier kernel, but exaggerated by the commit 831d52bc153971b70e64eccfbed2b232394f22f8 ("x86, mm: avoid possible bogus tlb entries by clearing prev mm_cpumask after switching mm") which clears bitmap after changing the TLB state. the call trace is as below: --------------------------------- kernel BUG at arch/x86/mm/tlb.c:61! invalid opcode: 0000 [#1] SMP last sysfs file: /sys/devices/system/xen_memory/xen_memory0/info/current_kb CPU 1 Modules linked in: 8021q garp xen_netback xen_blkback blktap blkback_pagemap nbd bridge stp llc autofs4 ipmi_devintf ipmi_si ipmi_msghandler lockd sunrpc bonding ipv6 xenfs dm_multipath video output sbs sbshc parport_pc lp parport ses enclosure snd_seq_dummy snd_seq_oss snd_seq_midi_event snd_seq snd_seq_device serio_raw bnx2 snd_pcm_oss snd_mixer_oss snd_pcm snd_timer iTCO_wdt snd soundcore snd_page_alloc i2c_i801 iTCO_vendor_support i2c_core pcs pkr pata_acpi ata_generic ata_piix shpchp mptsas mptscsih mptbase [last unloaded: freq_table] Pid: 25581, comm: khelper Not tainted 2.6.32.36fixxen #1 Tecal RH2285 RIP: e030:[] [] leave_mm+0x15/0x46 RSP: e02b:ffff88002805be48 EFLAGS: 00010046 RAX: 0000000000000000 RBX: 0000000000000001 RCX: ffff88015f8e2da0 RDX: ffff88002805be78 RSI: 0000000000000000 RDI: 0000000000000001 RBP: ffff88002805be48 R08: ffff88009d662000 R09: dead000000200200 R10: dead000000100100 R11: ffffffff814472b2 R12: ffff88009bfc1880 R13: ffff880028063020 R14: 00000000000004f6 R15: 0000000000000000 FS: 00007f62362d66e0(0000) GS:ffff880028058000(0000) knlGS:0000000000000000 CS: e033 DS: 0000 ES: 0000 CR0: 000000008005003b CR2: 0000003aabc11909 CR3: 000000009b8ca000 CR4: 0000000000002660 DR0: 0000000000000000 DR1: 0000000000000000 DR2: 00000000000000 00 DR3: 0000000000000000 DR6: 00000000ffff0ff0 DR7: 0000000000000400 Process khelper (pid: 25581, threadinfo ffff88007691e000, task ffff88009b92db40) Stack: ffff88002805be68 ffffffff8100e4ae 0000000000000001 ffff88009d733b88 <0> ffff88002805be98 ffffffff81087224 ffff88002805be78 ffff88002805be78 <0> ffff88015f808360 00000000000004f6 ffff88002805bea8 ffffffff81010108 Call Trace: [] drop_other_mm_ref+0x2a/0x53 [] generic_smp_call_function_single_interrupt+0xd8/0xfc [] xen_call_function_single_interrupt+0x13/0x28 [] handle_IRQ_event+0x66/0x120 [] handle_percpu_irq+0x41/0x6e [] __xen_evtchn_do_upcall+0x1ab/0x27d [] xen_evtchn_do_upcall+0x33/0x46 [] xen_do_hyper visor_callback+0x1e/0x30 [] ? _spin_unlock_irqrestore+0x15/0x17 [] ? xen_restore_fl_direct_end+0x0/0x1 [] ? flush_old_exec+0x3ac/0x500 [] ? load_elf_binary+0x0/0x17ef [] ? load_elf_binary+0x0/0x17ef [] ? load_elf_binary+0x398/0x17ef [] ? need_resched+0x23/0x2d [] ? process_measurement+0xc0/0xd7 [] ? load_elf_binary+0x0/0x17ef [] ? search_binary_handler+0xc8/0x255 [] ? do_execve+0x1c3/0x29e [] ? sys_execve+0x43/0x5d [] ? __call_usermodehelper+0x0/0x6f [] ? kernel_execve+0x68/0xd0 [] ? __call_usermodehelper+0x0/0x6f [] ? xen_restore_fl_direct_end+0x0/0x1 [] ? ____call_usermodehelper+0x113/0x11e [] ? child_rip+0xa/0x20 [] ? __call_usermodehelper+0x0/0x6f [] ? int_ret_from_sys_call+0x7/0x1b [] ? retint_restore_args+0x5/0x6 [] ? child_rip+0x0/0x20 Code: 41 5e 41 5f c9 c3 55 48 89 e5 0f 1f 44 00 00 e8 17 ff ff ff c9 c3 55 48 89 e5 0f 1f 44 00 00 65 8b 04 25 c8 55 01 00 ff c8 75 04 <0f> 0b eb fe 65 48 8b 34 25 c0 55 01 00 48 81 c6 b8 02 00 00 e8 RIP [] leave_mm+0x15/0x46 RSP ---[ end trace ce9cee6832a9c503 ]--- Tested-by: Maoxiaoyun Signed-off-by: Kevin Tian [v1: Fleshed out the git description a bit] Signed-off-by: Konrad Rzeszutek Wilk diff --git a/arch/x86/xen/mmu.c b/arch/x86/xen/mmu.c index 5e92b61..4fd7387 100644 --- a/arch/x86/xen/mmu.c +++ b/arch/x86/xen/mmu.c @@ -1140,7 +1140,7 @@ static void drop_other_mm_ref(void *info) active_mm = percpu_read(cpu_tlbstate.active_mm); - if (active_mm == mm) + if (active_mm == mm && percpu_read(cpu_tlbstate.state) != TLBSTATE_OK) leave_mm(smp_processor_id()); /* If this cpu still has a stale cr3 reference, then make sure -- cgit v0.10.2 From 15bfc094517db2ddf38ca7ed47f3a1c0ad24f7c4 Mon Sep 17 00:00:00 2001 From: Konrad Rzeszutek Wilk Date: Tue, 12 Apr 2011 07:57:15 -0400 Subject: xen/setup: Ignore E820_UNUSABLE when setting 1-1 mappings. When we parse the raw E820, the Xen hypervisor can set "E820_RAM" to "E820_UNUSABLE" if the mem=X argument is used. As such we should _not_ consider the E820_UNUSABLE as an 1-1 identity mapping, but instead use the same case as for E820_RAM. Signed-off-by: Konrad Rzeszutek Wilk diff --git a/arch/x86/xen/setup.c b/arch/x86/xen/setup.c index 90bac0a..fba4a6c 100644 --- a/arch/x86/xen/setup.c +++ b/arch/x86/xen/setup.c @@ -166,7 +166,7 @@ static unsigned long __init xen_set_identity(const struct e820entry *list, if (last > end) continue; - if (entry->type == E820_RAM) { + if ((entry->type == E820_RAM) || (entry->type == E820_UNUSABLE)) { if (start > start_pci) identity += set_phys_range_identity( PFN_UP(start_pci), PFN_DOWN(start)); -- cgit v0.10.2 From 0f16d0dfcdb5aab97d9e368f008b070b5b3ec6d3 Mon Sep 17 00:00:00 2001 From: Daniel Kiper Date: Wed, 11 May 2011 22:34:38 +0200 Subject: xen/setup: Fix for incorrect xen_extra_mem_start initialization under 32-bit git commit 24bdb0b62cc82120924762ae6bc85afc8c3f2b26 (xen: do not create the extra e820 region at an addr lower than 4G) does not take into account that ifdef CONFIG_X86_32 instead of e820_end_of_low_ram_pfn() find_low_pfn_range() is called (both calls are from arch/x86/kernel/setup.c). find_low_pfn_range() behaves correctly and does not require change in xen_extra_mem_start initialization. Additionally, if xen_extra_mem_start is initialized in the same way as ifdef CONFIG_X86_64 then memory hotplug support for Xen balloon driver (under development) is broken. Signed-off-by: Daniel Kiper Signed-off-by: Konrad Rzeszutek Wilk diff --git a/arch/x86/xen/setup.c b/arch/x86/xen/setup.c index fba4a6c..ca6297b 100644 --- a/arch/x86/xen/setup.c +++ b/arch/x86/xen/setup.c @@ -227,7 +227,11 @@ char * __init xen_memory_setup(void) memcpy(map_raw, map, sizeof(map)); e820.nr_map = 0; +#ifdef CONFIG_X86_32 + xen_extra_mem_start = mem_end; +#else xen_extra_mem_start = max((1ULL << 32), mem_end); +#endif for (i = 0; i < memmap.nr_entries; i++) { unsigned long long end; -- cgit v0.10.2 From 8c5950881c3b5e6e350e4b0438a8ccc513d90df9 Mon Sep 17 00:00:00 2001 From: Konrad Rzeszutek Wilk Date: Fri, 1 Apr 2011 15:18:48 -0400 Subject: xen/p2m: Create entries in the P2M_MFN trees's to track 1-1 mappings .. when applicable. We need to track in the p2m_mfn and p2m_mfn_p the MFNs and pointers, respectivly, for the P2M entries that are allocated for the identity mappings. Without this, a PV domain with an E820 that triggers the 1-1 mapping to kick in, won't be able to be restored as the P2M won't have the identity mappings. Signed-off-by: Konrad Rzeszutek Wilk diff --git a/arch/x86/xen/p2m.c b/arch/x86/xen/p2m.c index 141eb0d..a01e653 100644 --- a/arch/x86/xen/p2m.c +++ b/arch/x86/xen/p2m.c @@ -522,11 +522,20 @@ static bool __init __early_alloc_p2m(unsigned long pfn) /* Boundary cross-over for the edges: */ if (idx) { unsigned long *p2m = extend_brk(PAGE_SIZE, PAGE_SIZE); + unsigned long *mid_mfn_p; p2m_init(p2m); p2m_top[topidx][mididx] = p2m; + /* For save/restore we need to MFN of the P2M saved */ + + mid_mfn_p = p2m_top_mfn_p[topidx]; + WARN(mid_mfn_p[mididx] != virt_to_mfn(p2m_missing), + "P2M_TOP_P[%d][%d] != MFN of p2m_missing!\n", + topidx, mididx); + mid_mfn_p[mididx] = virt_to_mfn(p2m); + } return idx != 0; } @@ -549,12 +558,29 @@ unsigned long __init set_phys_range_identity(unsigned long pfn_s, pfn += P2M_MID_PER_PAGE * P2M_PER_PAGE) { unsigned topidx = p2m_top_index(pfn); - if (p2m_top[topidx] == p2m_mid_missing) { - unsigned long **mid = extend_brk(PAGE_SIZE, PAGE_SIZE); + unsigned long *mid_mfn_p; + unsigned long **mid; + + mid = p2m_top[topidx]; + mid_mfn_p = p2m_top_mfn_p[topidx]; + if (mid == p2m_mid_missing) { + mid = extend_brk(PAGE_SIZE, PAGE_SIZE); p2m_mid_init(mid); p2m_top[topidx] = mid; + + BUG_ON(mid_mfn_p != p2m_mid_missing_mfn); + } + /* And the save/restore P2M tables.. */ + if (mid_mfn_p == p2m_mid_missing_mfn) { + mid_mfn_p = extend_brk(PAGE_SIZE, PAGE_SIZE); + p2m_mid_mfn_init(mid_mfn_p); + + p2m_top_mfn_p[topidx] = mid_mfn_p; + p2m_top_mfn[topidx] = virt_to_mfn(mid_mfn_p); + /* Note: we don't set mid_mfn_p[midix] here, + * look in __early_alloc_p2m */ } } -- cgit v0.10.2 From 982b2035d9d7033f63db187bac55e9d8998b0266 Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Thu, 12 May 2011 12:19:43 -0700 Subject: Revert "drm/i915: Only enable the plane after setting the fb base (pre-ILK)" This reverts commit 49183b2818de6899383bb82bc032f9344d6791ff. Quoth Franz Melchior: "This patch introduces a bug on my infamous "Acer Travelmate 5735Z-452G32Mnss": when KMS takes over, the frame buffer contents get completely garbled up on screen, with colored stripes and unreadable text (photo on request). Only when X11 is started, the screen gets restored again. Closing and re-opening the lid partly cures the mess, too: it makes the font readable, though horizontally stretched." Acked-by: Keith Packard Cc: Chris Wilson Cc: Daniel Vetter Cc: Jesse Barnes Signed-off-by: Linus Torvalds diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 373c2a0..2166ee0 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -5154,6 +5154,8 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc, I915_WRITE(DSPCNTR(plane), dspcntr); POSTING_READ(DSPCNTR(plane)); + if (!HAS_PCH_SPLIT(dev)) + intel_enable_plane(dev_priv, plane, pipe); ret = intel_pipe_set_base(crtc, x, y, old_fb); -- cgit v0.10.2 From 93826c092c385549c04af184fbebd43f36995c69 Mon Sep 17 00:00:00 2001 From: Eric Paris Date: Thu, 7 Apr 2011 14:46:59 -0400 Subject: SELinux: delete debugging printks from filename_trans rule processing The filename_trans rule processing has some printk(KERN_ERR ) messages which were intended as debug aids in creating the code but weren't removed before it was submitted. Remove them. Reported-by: Paul Bolle Signed-off-by: Eric Paris diff --git a/security/selinux/ss/policydb.c b/security/selinux/ss/policydb.c index e6e7ce0..7102457 100644 --- a/security/selinux/ss/policydb.c +++ b/security/selinux/ss/policydb.c @@ -1819,8 +1819,6 @@ static int filename_trans_read(struct policydb *p, void *fp) goto out; nel = le32_to_cpu(buf[0]); - printk(KERN_ERR "%s: nel=%d\n", __func__, nel); - last = p->filename_trans; while (last && last->next) last = last->next; @@ -1857,8 +1855,6 @@ static int filename_trans_read(struct policydb *p, void *fp) goto out; name[len] = 0; - printk(KERN_ERR "%s: ft=%p ft->name=%p ft->name=%s\n", __func__, ft, ft->name, ft->name); - rc = next_entry(buf, fp, sizeof(u32) * 4); if (rc) goto out; -- cgit v0.10.2 From a236c71766a5f69edf189e2eaeb0aa587c8c5684 Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Thu, 12 May 2011 12:45:31 -0700 Subject: drivers/base/memory.c: fix warning due to "memory hotplug: Speed up add/remove when blocks are larger than PAGES_PER_SECTION" drivers/base/memory.c: In function 'memory_block_change_state': drivers/base/memory.c:281: warning: unused variable 'i' less beer, more testing Cc: Anton Blanchard Signed-off-by: Andrew Morton Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/base/memory.c b/drivers/base/memory.c index c4c443d..0a134a4 100644 --- a/drivers/base/memory.c +++ b/drivers/base/memory.c @@ -278,7 +278,7 @@ memory_block_action(unsigned long phys_index, unsigned long action) static int memory_block_change_state(struct memory_block *mem, unsigned long to_state, unsigned long from_state_req) { - int i, ret = 0; + int ret = 0; mutex_lock(&mem->state_mutex); -- cgit v0.10.2 From cf7e032fc87d59c475df26c4d40bf45d401b2adb Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Thu, 12 May 2011 09:11:38 +0000 Subject: zorro8390: Fix regression caused during net_device_ops conversion Changeset b6114794a1c394534659f4a17420e48cf23aa922 ("zorro8390: convert to net_device_ops") broke zorro8390 by adding 8390.o to the link. That meant that lib8390.c was included twice, once in zorro8390.c and once in 8390.c, subject to different macros. This patch reverts that by avoiding the wrappers in 8390.c. Fix based on commits 217cbfa856dc1cbc2890781626c4032d9e3ec59f ("mac8390: fix regression caused during net_device_ops conversion") and 4e0168fa4842e27795a75b205a510f25b62181d9 ("mac8390: fix build with NET_POLL_CONTROLLER"). Reported-by: Christian T. Steigies Suggested-by: Finn Thain Signed-off-by: Geert Uytterhoeven Tested-by: Christian T. Steigies Cc: stable@kernel.org Signed-off-by: David S. Miller diff --git a/drivers/net/Makefile b/drivers/net/Makefile index 01b604a..c64675f 100644 --- a/drivers/net/Makefile +++ b/drivers/net/Makefile @@ -219,7 +219,7 @@ obj-$(CONFIG_SC92031) += sc92031.o obj-$(CONFIG_LP486E) += lp486e.o obj-$(CONFIG_ETH16I) += eth16i.o -obj-$(CONFIG_ZORRO8390) += zorro8390.o 8390.o +obj-$(CONFIG_ZORRO8390) += zorro8390.o obj-$(CONFIG_HPLANCE) += hplance.o 7990.o obj-$(CONFIG_MVME147_NET) += mvme147.o 7990.o obj-$(CONFIG_EQUALIZER) += eql.o diff --git a/drivers/net/zorro8390.c b/drivers/net/zorro8390.c index b78a38d..8c7c522 100644 --- a/drivers/net/zorro8390.c +++ b/drivers/net/zorro8390.c @@ -126,7 +126,7 @@ static int __devinit zorro8390_init_one(struct zorro_dev *z, board = z->resource.start; ioaddr = board+cards[i].offset; - dev = alloc_ei_netdev(); + dev = ____alloc_ei_netdev(0); if (!dev) return -ENOMEM; if (!request_mem_region(ioaddr, NE_IO_EXTENT*2, DRV_NAME)) { @@ -146,15 +146,15 @@ static int __devinit zorro8390_init_one(struct zorro_dev *z, static const struct net_device_ops zorro8390_netdev_ops = { .ndo_open = zorro8390_open, .ndo_stop = zorro8390_close, - .ndo_start_xmit = ei_start_xmit, - .ndo_tx_timeout = ei_tx_timeout, - .ndo_get_stats = ei_get_stats, - .ndo_set_multicast_list = ei_set_multicast_list, + .ndo_start_xmit = __ei_start_xmit, + .ndo_tx_timeout = __ei_tx_timeout, + .ndo_get_stats = __ei_get_stats, + .ndo_set_multicast_list = __ei_set_multicast_list, .ndo_validate_addr = eth_validate_addr, .ndo_set_mac_address = eth_mac_addr, .ndo_change_mtu = eth_change_mtu, #ifdef CONFIG_NET_POLL_CONTROLLER - .ndo_poll_controller = ei_poll, + .ndo_poll_controller = __ei_poll, #endif }; -- cgit v0.10.2 From 0b25e0157dfa236a0629c16c8ad6f222f633f682 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Thu, 12 May 2011 09:11:39 +0000 Subject: hydra: Fix regression caused during net_device_ops conversion Changeset 5618f0d1193d6b051da9b59b0e32ad24397f06a4 ("hydra: convert to net_device_ops") broke hydra by adding 8390.o to the link. That meant that lib8390.c was included twice, once in hydra.c and once in 8390.c, subject to different macros. This patch reverts that by avoiding the wrappers in 8390.c. Fix based on commits 217cbfa856dc1cbc2890781626c4032d9e3ec59f ("mac8390: fix regression caused during net_device_ops conversion") and 4e0168fa4842e27795a75b205a510f25b62181d9 ("mac8390: fix build with NET_POLL_CONTROLLER"). Signed-off-by: Geert Uytterhoeven Cc: stable@kernel.org Signed-off-by: David S. Miller diff --git a/drivers/net/Makefile b/drivers/net/Makefile index c64675f..4d2f094 100644 --- a/drivers/net/Makefile +++ b/drivers/net/Makefile @@ -231,7 +231,7 @@ obj-$(CONFIG_SGI_IOC3_ETH) += ioc3-eth.o obj-$(CONFIG_DECLANCE) += declance.o obj-$(CONFIG_ATARILANCE) += atarilance.o obj-$(CONFIG_A2065) += a2065.o -obj-$(CONFIG_HYDRA) += hydra.o 8390.o +obj-$(CONFIG_HYDRA) += hydra.o obj-$(CONFIG_ARIADNE) += ariadne.o obj-$(CONFIG_CS89x0) += cs89x0.o obj-$(CONFIG_MACSONIC) += macsonic.o diff --git a/drivers/net/hydra.c b/drivers/net/hydra.c index c5ef62c..1cd481c 100644 --- a/drivers/net/hydra.c +++ b/drivers/net/hydra.c @@ -98,15 +98,15 @@ static const struct net_device_ops hydra_netdev_ops = { .ndo_open = hydra_open, .ndo_stop = hydra_close, - .ndo_start_xmit = ei_start_xmit, - .ndo_tx_timeout = ei_tx_timeout, - .ndo_get_stats = ei_get_stats, - .ndo_set_multicast_list = ei_set_multicast_list, + .ndo_start_xmit = __ei_start_xmit, + .ndo_tx_timeout = __ei_tx_timeout, + .ndo_get_stats = __ei_get_stats, + .ndo_set_multicast_list = __ei_set_multicast_list, .ndo_validate_addr = eth_validate_addr, - .ndo_set_mac_address = eth_mac_addr, + .ndo_set_mac_address = eth_mac_addr, .ndo_change_mtu = eth_change_mtu, #ifdef CONFIG_NET_POLL_CONTROLLER - .ndo_poll_controller = ei_poll, + .ndo_poll_controller = __ei_poll, #endif }; @@ -125,7 +125,7 @@ static int __devinit hydra_init(struct zorro_dev *z) 0x10, 0x12, 0x14, 0x16, 0x18, 0x1a, 0x1c, 0x1e, }; - dev = alloc_ei_netdev(); + dev = ____alloc_ei_netdev(0); if (!dev) return -ENOMEM; -- cgit v0.10.2 From 2592a7354092afd304a8c067319b15ab1e441e35 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Thu, 12 May 2011 09:11:40 +0000 Subject: ne-h8300: Fix regression caused during net_device_ops conversion Changeset dcd39c90290297f6e6ed8a04bb20da7ac2b043c5 ("ne-h8300: convert to net_device_ops") broke ne-h8300 by adding 8390.o to the link. That meant that lib8390.c was included twice, once in ne-h8300.c and once in 8390.c, subject to different macros. This patch reverts that by avoiding the wrappers in 8390.c. Fix based on commits 217cbfa856dc1cbc2890781626c4032d9e3ec59f ("mac8390: fix regression caused during net_device_ops conversion") and 4e0168fa4842e27795a75b205a510f25b62181d9 ("mac8390: fix build with NET_POLL_CONTROLLER"). Signed-off-by: Geert Uytterhoeven Cc: stable@kernel.org Signed-off-by: David S. Miller diff --git a/drivers/net/Makefile b/drivers/net/Makefile index 4d2f094..e5a7375 100644 --- a/drivers/net/Makefile +++ b/drivers/net/Makefile @@ -144,7 +144,7 @@ obj-$(CONFIG_NE3210) += ne3210.o 8390.o obj-$(CONFIG_SB1250_MAC) += sb1250-mac.o obj-$(CONFIG_B44) += b44.o obj-$(CONFIG_FORCEDETH) += forcedeth.o -obj-$(CONFIG_NE_H8300) += ne-h8300.o 8390.o +obj-$(CONFIG_NE_H8300) += ne-h8300.o obj-$(CONFIG_AX88796) += ax88796.o obj-$(CONFIG_BCM63XX_ENET) += bcm63xx_enet.o obj-$(CONFIG_FTMAC100) += ftmac100.o diff --git a/drivers/net/ne-h8300.c b/drivers/net/ne-h8300.c index 30be8c6..7298a34 100644 --- a/drivers/net/ne-h8300.c +++ b/drivers/net/ne-h8300.c @@ -167,7 +167,7 @@ static void cleanup_card(struct net_device *dev) #ifndef MODULE struct net_device * __init ne_probe(int unit) { - struct net_device *dev = alloc_ei_netdev(); + struct net_device *dev = ____alloc_ei_netdev(0); int err; if (!dev) @@ -197,15 +197,15 @@ static const struct net_device_ops ne_netdev_ops = { .ndo_open = ne_open, .ndo_stop = ne_close, - .ndo_start_xmit = ei_start_xmit, - .ndo_tx_timeout = ei_tx_timeout, - .ndo_get_stats = ei_get_stats, - .ndo_set_multicast_list = ei_set_multicast_list, + .ndo_start_xmit = __ei_start_xmit, + .ndo_tx_timeout = __ei_tx_timeout, + .ndo_get_stats = __ei_get_stats, + .ndo_set_multicast_list = __ei_set_multicast_list, .ndo_validate_addr = eth_validate_addr, - .ndo_set_mac_address = eth_mac_addr, + .ndo_set_mac_address = eth_mac_addr, .ndo_change_mtu = eth_change_mtu, #ifdef CONFIG_NET_POLL_CONTROLLER - .ndo_poll_controller = ei_poll, + .ndo_poll_controller = __ei_poll, #endif }; @@ -637,7 +637,7 @@ int init_module(void) int err; for (this_dev = 0; this_dev < MAX_NE_CARDS; this_dev++) { - struct net_device *dev = alloc_ei_netdev(); + struct net_device *dev = ____alloc_ei_netdev(0); if (!dev) break; if (io[this_dev]) { -- cgit v0.10.2 From 889cb360b4f48c1334311093161f06f7b4bd77d2 Mon Sep 17 00:00:00 2001 From: Eliad Peller Date: Sun, 1 May 2011 09:56:45 +0300 Subject: wl12xx: simplify wl1271_ssid_set() Simplify wl1271_ssid_set by re-using cfg80211_find_ie instead of reimplementing it. Additionally, add a length check to prevent a potential buffer overflow. Signed-off-by: Eliad Peller Signed-off-by: Luciano Coelho diff --git a/drivers/net/wireless/wl12xx/main.c b/drivers/net/wireless/wl12xx/main.c index 6dab6f0..f82e736 100644 --- a/drivers/net/wireless/wl12xx/main.c +++ b/drivers/net/wireless/wl12xx/main.c @@ -2376,20 +2376,24 @@ out: static int wl1271_ssid_set(struct wl1271 *wl, struct sk_buff *skb, int offset) { - u8 *ptr = skb->data + offset; + u8 ssid_len; + const u8 *ptr = cfg80211_find_ie(WLAN_EID_SSID, skb->data + offset, + skb->len - offset); - /* find the location of the ssid in the beacon */ - while (ptr < skb->data + skb->len) { - if (ptr[0] == WLAN_EID_SSID) { - wl->ssid_len = ptr[1]; - memcpy(wl->ssid, ptr+2, wl->ssid_len); - return 0; - } - ptr += (ptr[1] + 2); + if (!ptr) { + wl1271_error("No SSID in IEs!"); + return -ENOENT; } - wl1271_error("No SSID in IEs!\n"); - return -ENOENT; + ssid_len = ptr[1]; + if (ssid_len > IEEE80211_MAX_SSID_LEN) { + wl1271_error("SSID is too long!"); + return -EINVAL; + } + + wl->ssid_len = ssid_len; + memcpy(wl->ssid, ptr+2, ssid_len); + return 0; } static int wl1271_bss_erp_info_changed(struct wl1271 *wl, -- cgit v0.10.2 From bc76b94051983b94c8ba04fbfbc59651b9925fa7 Mon Sep 17 00:00:00 2001 From: Shahar Levi Date: Wed, 11 May 2011 11:14:22 +0300 Subject: wl12xx: Don't filter beacons that include changed HT IEs This patch adds a beacon filter rule to pass up the beacons that contain changed HT information elements. These beacons need to be passed to mac80211 so that it can act on such changes. [Reworded commit log -- Luca.] Signed-off-by: Shahar Levi Signed-off-by: Luciano Coelho diff --git a/drivers/net/wireless/wl12xx/main.c b/drivers/net/wireless/wl12xx/main.c index f82e736..fa6b996 100644 --- a/drivers/net/wireless/wl12xx/main.c +++ b/drivers/net/wireless/wl12xx/main.c @@ -257,12 +257,16 @@ static struct conf_drv_settings default_conf = { .wake_up_event = CONF_WAKE_UP_EVENT_DTIM, .listen_interval = 1, .bcn_filt_mode = CONF_BCN_FILT_MODE_ENABLED, - .bcn_filt_ie_count = 1, + .bcn_filt_ie_count = 2, .bcn_filt_ie = { [0] = { .ie = WLAN_EID_CHANNEL_SWITCH, .rule = CONF_BCN_RULE_PASS_ON_APPEARANCE, - } + }, + [1] = { + .ie = WLAN_EID_HT_INFORMATION, + .rule = CONF_BCN_RULE_PASS_ON_CHANGE, + }, }, .synch_fail_thold = 10, .bss_lose_timeout = 100, -- cgit v0.10.2 From fcd23b6305e98f5ad3ddd7ff3f5081c75fcd4367 Mon Sep 17 00:00:00 2001 From: Shahar Levi Date: Wed, 11 May 2011 12:12:56 +0300 Subject: wl12xx: add IEEE80211_HW_SPECTRUM_MGMT bit to the hw flags Set the spectrum management bit in the hw flags so that mac80211 will set the WLAN_CAPABILITY_SPECTRUM_MGMT bit in association requests (which in practice means that we support 802.11h spectrum management). [Reworded the commit log -- Luca.] Signed-off-by: Shahar Levi Signed-off-by: Luciano Coelho diff --git a/drivers/net/wireless/wl12xx/main.c b/drivers/net/wireless/wl12xx/main.c index fa6b996..acfbbfd 100644 --- a/drivers/net/wireless/wl12xx/main.c +++ b/drivers/net/wireless/wl12xx/main.c @@ -3634,6 +3634,7 @@ int wl1271_init_ieee80211(struct wl1271 *wl) IEEE80211_HW_CONNECTION_MONITOR | IEEE80211_HW_SUPPORTS_CQM_RSSI | IEEE80211_HW_REPORTS_TX_ACK_STATUS | + IEEE80211_HW_SPECTRUM_MGMT | IEEE80211_HW_AP_LINK_PS; wl->hw->wiphy->cipher_suites = cipher_suites; -- cgit v0.10.2 From 3a9d60e5bd72f9533b05d39278fec50b181dbdd2 Mon Sep 17 00:00:00 2001 From: Luciano Coelho Date: Tue, 10 May 2011 14:06:31 +0300 Subject: wl12xx: add configuration values for scheduled scan Add the structures and values for driver-configured scheduled scan parameters. Signed-off-by: Luciano Coelho diff --git a/drivers/net/wireless/wl12xx/conf.h b/drivers/net/wireless/wl12xx/conf.h index 1f94736..ba558fc 100644 --- a/drivers/net/wireless/wl12xx/conf.h +++ b/drivers/net/wireless/wl12xx/conf.h @@ -1147,6 +1147,26 @@ struct conf_scan_settings { }; +struct conf_sched_scan_settings { + /* minimum time to wait on the channel for active scans (in TUs) */ + u16 min_dwell_time_active; + + /* maximum time to wait on the channel for active scans (in TUs) */ + u16 max_dwell_time_active; + + /* time to wait on the channel for passive scans (in TUs) */ + u32 dwell_time_passive; + + /* number of probe requests to send on each channel in active scans */ + u8 num_probe_reqs; + + /* RSSI threshold to be used for filtering */ + s8 rssi_threshold; + + /* SNR threshold to be used for filtering */ + s8 snr_threshold; +}; + /* these are number of channels on the band divided by two, rounded up */ #define CONF_TX_PWR_COMPENSATION_LEN_2 7 #define CONF_TX_PWR_COMPENSATION_LEN_5 18 @@ -1234,6 +1254,7 @@ struct conf_drv_settings { struct conf_pm_config_settings pm_config; struct conf_roam_trigger_settings roam_trigger; struct conf_scan_settings scan; + struct conf_sched_scan_settings sched_scan; struct conf_rf_settings rf; struct conf_ht_setting ht; struct conf_memory_settings mem_wl127x; diff --git a/drivers/net/wireless/wl12xx/main.c b/drivers/net/wireless/wl12xx/main.c index acfbbfd..88d2e90 100644 --- a/drivers/net/wireless/wl12xx/main.c +++ b/drivers/net/wireless/wl12xx/main.c @@ -306,6 +306,15 @@ static struct conf_drv_settings default_conf = { .max_dwell_time_passive = 100000, .num_probe_reqs = 2, }, + .sched_scan = { + /* sched_scan requires dwell times in TU instead of TU/1000 */ + .min_dwell_time_active = 8, + .max_dwell_time_active = 30, + .dwell_time_passive = 100, + .num_probe_reqs = 2, + .rssi_threshold = -90, + .snr_threshold = 0, + }, .rf = { .tx_per_channel_power_compensation_2 = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -- cgit v0.10.2 From 6394c01b61f8ab66a6af1a24ff05f2429130afcd Mon Sep 17 00:00:00 2001 From: Luciano Coelho Date: Tue, 10 May 2011 14:28:27 +0300 Subject: wl12xx: listen to scheduled scan events Subscribe and listen to PERIODIC_SCAN_REPORT_EVENT_ID and PERIODIC_SCAN_COMPLETE_EVENT_ID in preparation for the scheduled scan implementation. Signed-off-by: Luciano Coelho diff --git a/drivers/net/wireless/wl12xx/boot.c b/drivers/net/wireless/wl12xx/boot.c index 2b0cf85..b07f8b7 100644 --- a/drivers/net/wireless/wl12xx/boot.c +++ b/drivers/net/wireless/wl12xx/boot.c @@ -478,7 +478,9 @@ static int wl1271_boot_run_firmware(struct wl1271 *wl) DISCONNECT_EVENT_COMPLETE_ID | RSSI_SNR_TRIGGER_0_EVENT_ID | PSPOLL_DELIVERY_FAILURE_EVENT_ID | - SOFT_GEMINI_SENSE_EVENT_ID; + SOFT_GEMINI_SENSE_EVENT_ID | + PERIODIC_SCAN_REPORT_EVENT_ID | + PERIODIC_SCAN_COMPLETE_EVENT_ID; if (wl->bss_type == BSS_TYPE_AP_BSS) wl->event_mask |= STA_REMOVE_COMPLETE_EVENT_ID; diff --git a/drivers/net/wireless/wl12xx/event.c b/drivers/net/wireless/wl12xx/event.c index ae69330..dc110e8 100644 --- a/drivers/net/wireless/wl12xx/event.c +++ b/drivers/net/wireless/wl12xx/event.c @@ -188,6 +188,16 @@ static int wl1271_event_process(struct wl1271 *wl, struct event_mailbox *mbox) wl1271_scan_stm(wl); } + if (vector & PERIODIC_SCAN_REPORT_EVENT_ID) { + wl1271_debug(DEBUG_EVENT, "PERIODIC_SCAN_REPORT_EVENT " + "(status 0x%0x)", mbox->scheduled_scan_status); + } + + if (vector & PERIODIC_SCAN_COMPLETE_EVENT_ID) { + wl1271_debug(DEBUG_EVENT, "PERIODIC_SCAN_COMPLETE_EVENT " + "(status 0x%0x)", mbox->scheduled_scan_status); + } + /* disable dynamic PS when requested by the firmware */ if (vector & SOFT_GEMINI_SENSE_EVENT_ID && wl->bss_type == BSS_TYPE_STA_BSS) { -- cgit v0.10.2 From 95feadca6dca909ae0f6e65665b782c7ca9d5122 Mon Sep 17 00:00:00 2001 From: Luciano Coelho Date: Tue, 10 May 2011 14:38:59 +0300 Subject: wl12xx: add scheduled scan structures and commands Add firmware command structures, definitions and code to to configure, start and stop scheduled scans. Signed-off-by: Luciano Coelho diff --git a/drivers/net/wireless/wl12xx/scan.c b/drivers/net/wireless/wl12xx/scan.c index 5d0544c..d78044f 100644 --- a/drivers/net/wireless/wl12xx/scan.c +++ b/drivers/net/wireless/wl12xx/scan.c @@ -320,3 +320,236 @@ int wl1271_scan(struct wl1271 *wl, const u8 *ssid, size_t ssid_len, return 0; } + +static int +wl1271_scan_get_sched_scan_channels(struct wl1271 *wl, + struct cfg80211_sched_scan_request *req, + struct conn_scan_ch_params *channels, + u32 band, bool radar, bool passive, + int start) +{ + struct conf_sched_scan_settings *c = &wl->conf.sched_scan; + int i, j; + u32 flags; + + for (i = 0, j = start; + i < req->n_channels && j < MAX_CHANNELS_ALL_BANDS; + i++) { + flags = req->channels[i]->flags; + + if (!(flags & IEEE80211_CHAN_DISABLED) && + ((flags & IEEE80211_CHAN_PASSIVE_SCAN) == passive) && + ((flags & IEEE80211_CHAN_RADAR) == radar) && + (req->channels[i]->band == band)) { + wl1271_debug(DEBUG_SCAN, "band %d, center_freq %d ", + req->channels[i]->band, + req->channels[i]->center_freq); + wl1271_debug(DEBUG_SCAN, "hw_value %d, flags %X", + req->channels[i]->hw_value, + req->channels[i]->flags); + wl1271_debug(DEBUG_SCAN, "max_power %d", + req->channels[i]->max_power); + + if (flags & IEEE80211_CHAN_PASSIVE_SCAN) { + channels[j].passive_duration = + cpu_to_le16(c->dwell_time_passive); + } else { + channels[j].min_duration = + cpu_to_le16(c->min_dwell_time_active); + channels[j].max_duration = + cpu_to_le16(c->max_dwell_time_active); + } + channels[j].tx_power_att = req->channels[j]->max_power; + channels[j].channel = req->channels[i]->hw_value; + + j++; + } + } + + return j - start; +} + +static int +wl1271_scan_sched_scan_channels(struct wl1271 *wl, + struct cfg80211_sched_scan_request *req, + struct wl1271_cmd_sched_scan_config *cfg) +{ + int idx = 0; + + cfg->passive[0] = + wl1271_scan_get_sched_scan_channels(wl, req, cfg->channels, + IEEE80211_BAND_2GHZ, + false, true, idx); + idx += cfg->passive[0]; + + cfg->active[0] = + wl1271_scan_get_sched_scan_channels(wl, req, cfg->channels, + IEEE80211_BAND_2GHZ, + false, false, idx); + idx += cfg->active[0]; + + cfg->passive[1] = + wl1271_scan_get_sched_scan_channels(wl, req, cfg->channels, + IEEE80211_BAND_5GHZ, + false, true, idx); + idx += cfg->passive[1]; + + cfg->active[1] = + wl1271_scan_get_sched_scan_channels(wl, req, cfg->channels, + IEEE80211_BAND_5GHZ, + false, false, 14); + idx += cfg->active[1]; + + cfg->dfs = + wl1271_scan_get_sched_scan_channels(wl, req, cfg->channels, + IEEE80211_BAND_5GHZ, + true, false, idx); + idx += cfg->dfs; + + wl1271_debug(DEBUG_SCAN, " 2.4GHz: active %d passive %d", + cfg->active[0], cfg->passive[0]); + wl1271_debug(DEBUG_SCAN, " 5GHz: active %d passive %d", + cfg->active[1], cfg->passive[1]); + + return idx; +} + +int wl1271_scan_sched_scan_config(struct wl1271 *wl, + struct cfg80211_sched_scan_request *req, + struct ieee80211_sched_scan_ies *ies) +{ + struct wl1271_cmd_sched_scan_config *cfg = NULL; + struct conf_sched_scan_settings *c = &wl->conf.sched_scan; + int i, total_channels, ret; + + wl1271_debug(DEBUG_CMD, "cmd sched_scan scan config"); + + cfg = kzalloc(sizeof(*cfg), GFP_KERNEL); + if (!cfg) + return -ENOMEM; + + cfg->rssi_threshold = c->rssi_threshold; + cfg->snr_threshold = c->snr_threshold; + cfg->n_probe_reqs = c->num_probe_reqs; + /* cycles set to 0 it means infinite (until manually stopped) */ + cfg->cycles = 0; + /* report APs when at least 1 is found */ + cfg->report_after = 1; + /* don't stop scanning automatically when something is found */ + cfg->terminate = 0; + cfg->tag = WL1271_SCAN_DEFAULT_TAG; + /* don't filter on BSS type */ + cfg->bss_type = SCAN_BSS_TYPE_ANY; + /* currently NL80211 supports only a single interval */ + for (i = 0; i < SCAN_MAX_CYCLE_INTERVALS; i++) + cfg->intervals[i] = cpu_to_le32(req->interval); + + if (req->ssids[0].ssid_len && req->ssids[0].ssid) { + cfg->filter_type = SCAN_SSID_FILTER_SPECIFIC; + cfg->ssid_len = req->ssids[0].ssid_len; + memcpy(cfg->ssid, req->ssids[0].ssid, + req->ssids[0].ssid_len); + } else { + cfg->filter_type = SCAN_SSID_FILTER_ANY; + cfg->ssid_len = 0; + } + + total_channels = wl1271_scan_sched_scan_channels(wl, req, cfg); + if (total_channels == 0) { + wl1271_error("scan channel list is empty"); + ret = -EINVAL; + goto out; + } + + if (cfg->active[0]) { + ret = wl1271_cmd_build_probe_req(wl, req->ssids[0].ssid, + req->ssids[0].ssid_len, + ies->ie[IEEE80211_BAND_2GHZ], + ies->len[IEEE80211_BAND_2GHZ], + IEEE80211_BAND_2GHZ); + if (ret < 0) { + wl1271_error("2.4GHz PROBE request template failed"); + goto out; + } + } + + if (cfg->active[1]) { + ret = wl1271_cmd_build_probe_req(wl, req->ssids[0].ssid, + req->ssids[0].ssid_len, + ies->ie[IEEE80211_BAND_5GHZ], + ies->len[IEEE80211_BAND_5GHZ], + IEEE80211_BAND_5GHZ); + if (ret < 0) { + wl1271_error("5GHz PROBE request template failed"); + goto out; + } + } + + wl1271_dump(DEBUG_SCAN, "SCAN_CFG: ", cfg, sizeof(*cfg)); + + ret = wl1271_cmd_send(wl, CMD_CONNECTION_SCAN_CFG, cfg, + sizeof(*cfg), 0); + if (ret < 0) { + wl1271_error("SCAN configuration failed"); + goto out; + } +out: + kfree(cfg); + return ret; +} + +int wl1271_scan_sched_scan_start(struct wl1271 *wl) +{ + struct wl1271_cmd_sched_scan_start *start; + int ret = 0; + + wl1271_debug(DEBUG_CMD, "cmd periodic scan start"); + + start = kzalloc(sizeof(*start), GFP_KERNEL); + if (!start) + return -ENOMEM; + + start->tag = WL1271_SCAN_DEFAULT_TAG; + + ret = wl1271_cmd_send(wl, CMD_START_PERIODIC_SCAN, start, + sizeof(*start), 0); + if (ret < 0) { + wl1271_error("failed to send scan start command"); + goto out_free; + } + +out_free: + kfree(start); + return ret; +} + +void wl1271_scan_sched_scan_results(struct wl1271 *wl) +{ + wl1271_debug(DEBUG_SCAN, "got periodic scan results"); + + ieee80211_sched_scan_results(wl->hw); +} + +void wl1271_scan_sched_scan_stop(struct wl1271 *wl) +{ + struct wl1271_cmd_sched_scan_stop *stop; + int ret = 0; + + wl1271_debug(DEBUG_CMD, "cmd periodic scan stop"); + + /* FIXME: what to do if alloc'ing to stop fails? */ + stop = kzalloc(sizeof(*stop), GFP_KERNEL); + if (!stop) { + wl1271_error("failed to alloc memory to send sched scan stop"); + return; + } + + stop->tag = WL1271_SCAN_DEFAULT_TAG; + + ret = wl1271_cmd_send(wl, CMD_STOP_PERIODIC_SCAN, stop, + sizeof(*stop), 0); + if (ret < 0) + wl1271_error("failed to send sched scan stop command"); + + kfree(stop); +} diff --git a/drivers/net/wireless/wl12xx/scan.h b/drivers/net/wireless/wl12xx/scan.h index 421a750..c833195 100644 --- a/drivers/net/wireless/wl12xx/scan.h +++ b/drivers/net/wireless/wl12xx/scan.h @@ -33,6 +33,12 @@ int wl1271_scan_build_probe_req(struct wl1271 *wl, const u8 *ie, size_t ie_len, u8 band); void wl1271_scan_stm(struct wl1271 *wl); void wl1271_scan_complete_work(struct work_struct *work); +int wl1271_scan_sched_scan_config(struct wl1271 *wl, + struct cfg80211_sched_scan_request *req, + struct ieee80211_sched_scan_ies *ies); +int wl1271_scan_sched_scan_start(struct wl1271 *wl); +void wl1271_scan_sched_scan_stop(struct wl1271 *wl); +void wl1271_scan_sched_scan_results(struct wl1271 *wl); #define WL1271_SCAN_MAX_CHANNELS 24 #define WL1271_SCAN_DEFAULT_TAG 1 @@ -106,4 +112,112 @@ struct wl1271_cmd_trigger_scan_to { __le32 timeout; } __packed; +#define MAX_CHANNELS_ALL_BANDS 41 +#define SCAN_MAX_CYCLE_INTERVALS 16 +#define SCAN_MAX_BANDS 3 + +enum { + SCAN_CHANNEL_TYPE_2GHZ_PASSIVE, + SCAN_CHANNEL_TYPE_2GHZ_ACTIVE, + SCAN_CHANNEL_TYPE_5GHZ_PASSIVE, + SCAN_CHANNEL_TYPE_5GHZ_ACTIVE, + SCAN_CHANNEL_TYPE_5GHZ_DFS, +}; + +enum { + SCAN_SSID_FILTER_ANY = 0, + SCAN_SSID_FILTER_SPECIFIC = 1, + SCAN_SSID_FILTER_LIST = 2, + SCAN_SSID_FILTER_DISABLED = 3 +}; + +enum { + SCAN_BSS_TYPE_INDEPENDENT, + SCAN_BSS_TYPE_INFRASTRUCTURE, + SCAN_BSS_TYPE_ANY, +}; + +struct conn_scan_ch_params { + __le16 min_duration; + __le16 max_duration; + __le16 passive_duration; + + u8 channel; + u8 tx_power_att; + + /* bit 0: DFS channel; bit 1: DFS enabled */ + u8 flags; + + u8 padding[3]; +} __packed; + +struct wl1271_cmd_sched_scan_config { + struct wl1271_cmd_header header; + + __le32 intervals[SCAN_MAX_CYCLE_INTERVALS]; + + s8 rssi_threshold; /* for filtering (in dBm) */ + s8 snr_threshold; /* for filtering (in dB) */ + + u8 cycles; /* maximum number of scan cycles */ + u8 report_after; /* report when this number of results are received */ + u8 terminate; /* stop scanning after reporting */ + + u8 tag; + u8 bss_type; /* for filtering */ + u8 filter_type; + + u8 ssid_len; /* For SCAN_SSID_FILTER_SPECIFIC */ + u8 ssid[IW_ESSID_MAX_SIZE]; + + u8 n_probe_reqs; /* Number of probes requests per channel */ + + u8 passive[SCAN_MAX_BANDS]; + u8 active[SCAN_MAX_BANDS]; + + u8 dfs; + + u8 padding[3]; + + struct conn_scan_ch_params channels[MAX_CHANNELS_ALL_BANDS]; +} __packed; + + +#define SCHED_SCAN_MAX_SSIDS 8 + +enum { + SCAN_SSID_TYPE_PUBLIC = 0, + SCAN_SSID_TYPE_HIDDEN = 1, +}; + +struct wl1271_ssid { + u8 type; + u8 len; + u8 ssid[IW_ESSID_MAX_SIZE]; + /* u8 padding[2]; */ +} __packed; + +struct wl1271_cmd_sched_scan_ssid_list { + struct wl1271_cmd_header header; + + u8 n_ssids; + struct wl1271_ssid ssids[SCHED_SCAN_MAX_SSIDS]; + u8 padding[3]; +} __packed; + +struct wl1271_cmd_sched_scan_start { + struct wl1271_cmd_header header; + + u8 tag; + u8 padding[3]; +} __packed; + +struct wl1271_cmd_sched_scan_stop { + struct wl1271_cmd_header header; + + u8 tag; + u8 padding[3]; +} __packed; + + #endif /* __WL1271_SCAN_H__ */ -- cgit v0.10.2 From 33c2c06cd2d766387cf919d0afd432cc5796c369 Mon Sep 17 00:00:00 2001 From: Luciano Coelho Date: Tue, 10 May 2011 14:46:02 +0300 Subject: wl12xx: implement scheduled scan driver operations and reporting This patch adds the mac80211 operations for scheduled scan and the scheduled scan results reporting. Signed-off-by: Luciano Coelho diff --git a/drivers/net/wireless/wl12xx/event.c b/drivers/net/wireless/wl12xx/event.c index dc110e8..1e4bd6a 100644 --- a/drivers/net/wireless/wl12xx/event.c +++ b/drivers/net/wireless/wl12xx/event.c @@ -191,11 +191,17 @@ static int wl1271_event_process(struct wl1271 *wl, struct event_mailbox *mbox) if (vector & PERIODIC_SCAN_REPORT_EVENT_ID) { wl1271_debug(DEBUG_EVENT, "PERIODIC_SCAN_REPORT_EVENT " "(status 0x%0x)", mbox->scheduled_scan_status); + + wl1271_scan_sched_scan_results(wl); } if (vector & PERIODIC_SCAN_COMPLETE_EVENT_ID) { wl1271_debug(DEBUG_EVENT, "PERIODIC_SCAN_COMPLETE_EVENT " "(status 0x%0x)", mbox->scheduled_scan_status); + if (wl->sched_scanning) { + wl1271_scan_sched_scan_stop(wl); + ieee80211_sched_scan_stopped(wl->hw); + } } /* disable dynamic PS when requested by the firmware */ diff --git a/drivers/net/wireless/wl12xx/main.c b/drivers/net/wireless/wl12xx/main.c index 88d2e90..a14a035 100644 --- a/drivers/net/wireless/wl12xx/main.c +++ b/drivers/net/wireless/wl12xx/main.c @@ -988,6 +988,11 @@ static void wl1271_recovery_work(struct work_struct *work) /* Prevent spurious TX during FW restart */ ieee80211_stop_queues(wl->hw); + if (wl->sched_scanning) { + ieee80211_sched_scan_stopped(wl->hw); + wl->sched_scanning = false; + } + /* reboot the chipset */ __wl1271_op_remove_interface(wl, false); ieee80211_restart_hw(wl->hw); @@ -1576,6 +1581,7 @@ static void __wl1271_op_remove_interface(struct wl1271 *wl, memset(wl->ap_hlid_map, 0, sizeof(wl->ap_hlid_map)); wl->ap_fw_ps_map = 0; wl->ap_ps_map = 0; + wl->sched_scanning = false; /* * this is performed after the cancel_work calls and the associated @@ -1778,6 +1784,13 @@ static int wl1271_sta_handle_idle(struct wl1271 *wl, bool idle) wl->session_counter++; if (wl->session_counter >= SESSION_COUNTER_MAX) wl->session_counter = 0; + + /* The current firmware only supports sched_scan in idle */ + if (wl->sched_scanning) { + wl1271_scan_sched_scan_stop(wl); + ieee80211_sched_scan_stopped(wl->hw); + } + ret = wl1271_dummy_join(wl); if (ret < 0) goto out; @@ -2330,6 +2343,60 @@ out: return ret; } +static int wl1271_op_sched_scan_start(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct cfg80211_sched_scan_request *req, + struct ieee80211_sched_scan_ies *ies) +{ + struct wl1271 *wl = hw->priv; + int ret; + + wl1271_debug(DEBUG_MAC80211, "wl1271_op_sched_scan_start"); + + mutex_lock(&wl->mutex); + + ret = wl1271_ps_elp_wakeup(wl); + if (ret < 0) + goto out; + + ret = wl1271_scan_sched_scan_config(wl, req, ies); + if (ret < 0) + goto out_sleep; + + ret = wl1271_scan_sched_scan_start(wl); + if (ret < 0) + goto out_sleep; + + wl->sched_scanning = true; + +out_sleep: + wl1271_ps_elp_sleep(wl); +out: + mutex_unlock(&wl->mutex); + return ret; +} + +static void wl1271_op_sched_scan_stop(struct ieee80211_hw *hw, + struct ieee80211_vif *vif) +{ + struct wl1271 *wl = hw->priv; + int ret; + + wl1271_debug(DEBUG_MAC80211, "wl1271_op_sched_scan_stop"); + + mutex_lock(&wl->mutex); + + ret = wl1271_ps_elp_wakeup(wl); + if (ret < 0) + goto out; + + wl1271_scan_sched_scan_stop(wl); + + wl1271_ps_elp_sleep(wl); +out: + mutex_unlock(&wl->mutex); +} + static int wl1271_op_set_frag_threshold(struct ieee80211_hw *hw, u32 value) { struct wl1271 *wl = hw->priv; @@ -3445,6 +3512,8 @@ static const struct ieee80211_ops wl1271_ops = { .tx = wl1271_op_tx, .set_key = wl1271_op_set_key, .hw_scan = wl1271_op_hw_scan, + .sched_scan_start = wl1271_op_sched_scan_start, + .sched_scan_stop = wl1271_op_sched_scan_stop, .bss_info_changed = wl1271_op_bss_info_changed, .set_frag_threshold = wl1271_op_set_frag_threshold, .set_rts_threshold = wl1271_op_set_rts_threshold, @@ -3765,6 +3834,7 @@ struct ieee80211_hw *wl1271_alloc_hw(void) wl->ap_fw_ps_map = 0; wl->quirks = 0; wl->platform_quirks = 0; + wl->sched_scanning = false; memset(wl->tx_frames_map, 0, sizeof(wl->tx_frames_map)); for (i = 0; i < ACX_TX_DESCRIPTORS; i++) diff --git a/drivers/net/wireless/wl12xx/scan.c b/drivers/net/wireless/wl12xx/scan.c index d78044f..668ff46 100644 --- a/drivers/net/wireless/wl12xx/scan.c +++ b/drivers/net/wireless/wl12xx/scan.c @@ -548,8 +548,12 @@ void wl1271_scan_sched_scan_stop(struct wl1271 *wl) ret = wl1271_cmd_send(wl, CMD_STOP_PERIODIC_SCAN, stop, sizeof(*stop), 0); - if (ret < 0) + if (ret < 0) { wl1271_error("failed to send sched scan stop command"); + goto out_free; + } + wl->sched_scanning = false; +out_free: kfree(stop); } diff --git a/drivers/net/wireless/wl12xx/wl12xx.h b/drivers/net/wireless/wl12xx/wl12xx.h index b760143..10f0767 100644 --- a/drivers/net/wireless/wl12xx/wl12xx.h +++ b/drivers/net/wireless/wl12xx/wl12xx.h @@ -480,6 +480,8 @@ struct wl1271 { struct wl1271_scan scan; struct delayed_work scan_complete_work; + bool sched_scanning; + /* probe-req template for the current AP */ struct sk_buff *probereq; -- cgit v0.10.2 From d3eff81de6048d8af8f95f52f0f06625980f2efb Mon Sep 17 00:00:00 2001 From: Luciano Coelho Date: Tue, 10 May 2011 14:47:45 +0300 Subject: wl12xx: export scheduled scan state in debugfs Add the sched_scanning value to the driver_status debugfs entry. Signed-off-by: Luciano Coelho diff --git a/drivers/net/wireless/wl12xx/debugfs.c b/drivers/net/wireless/wl12xx/debugfs.c index b2f692b..f1f8df9 100644 --- a/drivers/net/wireless/wl12xx/debugfs.c +++ b/drivers/net/wireless/wl12xx/debugfs.c @@ -377,6 +377,7 @@ static ssize_t driver_state_read(struct file *file, char __user *user_buf, DRIVER_STATE_PRINT_HEX(platform_quirks); DRIVER_STATE_PRINT_HEX(chip.id); DRIVER_STATE_PRINT_STR(chip.fw_ver_str); + DRIVER_STATE_PRINT_INT(sched_scanning); #undef DRIVER_STATE_PRINT_INT #undef DRIVER_STATE_PRINT_LONG -- cgit v0.10.2 From 683c002447c12742f5151691083f68524f33b13a Mon Sep 17 00:00:00 2001 From: Luciano Coelho Date: Thu, 12 May 2011 17:07:55 +0300 Subject: wl12xx: prevent sched_scan when not idle or not in station mode The current firmware only supports scheduled scan in station mode and when idle. To prevent the firmware from crashing, return -EOPNOTSUPP when sched_scan start is called in an invalid state. Signed-off-by: Luciano Coelho diff --git a/drivers/net/wireless/wl12xx/scan.c b/drivers/net/wireless/wl12xx/scan.c index 668ff46..f37e5a3 100644 --- a/drivers/net/wireless/wl12xx/scan.c +++ b/drivers/net/wireless/wl12xx/scan.c @@ -505,6 +505,12 @@ int wl1271_scan_sched_scan_start(struct wl1271 *wl) wl1271_debug(DEBUG_CMD, "cmd periodic scan start"); + if (wl->bss_type != BSS_TYPE_STA_BSS) + return -EOPNOTSUPP; + + if (!test_bit(WL1271_FLAG_IDLE, &wl->flags)) + return -EBUSY; + start = kzalloc(sizeof(*start), GFP_KERNEL); if (!start) return -ENOMEM; -- cgit v0.10.2 From fe44870bcdf614e4abb35657c68081cda35ba741 Mon Sep 17 00:00:00 2001 From: Luciano Coelho Date: Thu, 12 May 2011 16:50:41 +0300 Subject: wl12xx: remove unused flag WL1271_FLAG_IDLE_REQUESTED This flag is not used anymore, remove it from the list. Signed-off-by: Luciano Coelho diff --git a/drivers/net/wireless/wl12xx/wl12xx.h b/drivers/net/wireless/wl12xx/wl12xx.h index 10f0767..ab0c2f1 100644 --- a/drivers/net/wireless/wl12xx/wl12xx.h +++ b/drivers/net/wireless/wl12xx/wl12xx.h @@ -351,7 +351,6 @@ enum wl12xx_flags { WL1271_FLAG_PSM_REQUESTED, WL1271_FLAG_IRQ_RUNNING, WL1271_FLAG_IDLE, - WL1271_FLAG_IDLE_REQUESTED, WL1271_FLAG_PSPOLL_FAILURE, WL1271_FLAG_STA_STATE_SENT, WL1271_FLAG_FW_TX_BUSY, -- cgit v0.10.2 From bdf516748ed73f6219f5e4065a8fe2f333520687 Mon Sep 17 00:00:00 2001 From: Ian Campbell Date: Mon, 4 Apr 2011 13:39:53 +0100 Subject: xen: tidy up whitespace in drivers/xen/Makefile Various merges over time have led to rather a mish-mash of indentation. Signed-off-by: Ian Campbell Cc: Jeremy Fitzhardinge Cc: xen-devel@lists.xensource.com Signed-off-by: Konrad Rzeszutek Wilk diff --git a/drivers/xen/Makefile b/drivers/xen/Makefile index f420f1f..4781f80 100644 --- a/drivers/xen/Makefile +++ b/drivers/xen/Makefile @@ -4,21 +4,21 @@ obj-y += xenbus/ nostackp := $(call cc-option, -fno-stack-protector) CFLAGS_features.o := $(nostackp) -obj-$(CONFIG_BLOCK) += biomerge.o -obj-$(CONFIG_HOTPLUG_CPU) += cpu_hotplug.o -obj-$(CONFIG_XEN_XENCOMM) += xencomm.o -obj-$(CONFIG_XEN_BALLOON) += xen-balloon.o -obj-$(CONFIG_XEN_DEV_EVTCHN) += xen-evtchn.o -obj-$(CONFIG_XEN_GNTDEV) += xen-gntdev.o +obj-$(CONFIG_BLOCK) += biomerge.o +obj-$(CONFIG_HOTPLUG_CPU) += cpu_hotplug.o +obj-$(CONFIG_XEN_XENCOMM) += xencomm.o +obj-$(CONFIG_XEN_BALLOON) += xen-balloon.o +obj-$(CONFIG_XEN_DEV_EVTCHN) += xen-evtchn.o +obj-$(CONFIG_XEN_GNTDEV) += xen-gntdev.o obj-$(CONFIG_XEN_GRANT_DEV_ALLOC) += xen-gntalloc.o -obj-$(CONFIG_XENFS) += xenfs/ +obj-$(CONFIG_XENFS) += xenfs/ obj-$(CONFIG_XEN_SYS_HYPERVISOR) += sys-hypervisor.o -obj-$(CONFIG_XEN_PLATFORM_PCI) += xen-platform-pci.o -obj-$(CONFIG_SWIOTLB_XEN) += swiotlb-xen.o -obj-$(CONFIG_XEN_DOM0) += pci.o +obj-$(CONFIG_XEN_PLATFORM_PCI) += xen-platform-pci.o +obj-$(CONFIG_SWIOTLB_XEN) += swiotlb-xen.o +obj-$(CONFIG_XEN_DOM0) += pci.o -xen-evtchn-y := evtchn.o +xen-evtchn-y := evtchn.o xen-gntdev-y := gntdev.o xen-gntalloc-y := gntalloc.o -xen-platform-pci-y := platform-pci.o +xen-platform-pci-y := platform-pci.o -- cgit v0.10.2 From 251511a18dcfe1868e3edfdc490777dcfaa1f851 Mon Sep 17 00:00:00 2001 From: Daniel Kiper Date: Wed, 4 May 2011 20:16:07 +0200 Subject: arch/x86/xen/irq: Cleanup code/data sections definitions Cleanup code/data sections definitions accordingly to include/linux/init.h. Signed-off-by: Daniel Kiper Signed-off-by: Konrad Rzeszutek Wilk diff --git a/arch/x86/xen/irq.c b/arch/x86/xen/irq.c index 6a6fe89..8bbb465 100644 --- a/arch/x86/xen/irq.c +++ b/arch/x86/xen/irq.c @@ -113,7 +113,7 @@ static void xen_halt(void) xen_safe_halt(); } -static const struct pv_irq_ops xen_irq_ops __initdata = { +static const struct pv_irq_ops xen_irq_ops __initconst = { .save_fl = PV_CALLEE_SAVE(xen_save_fl), .restore_fl = PV_CALLEE_SAVE(xen_restore_fl), .irq_disable = PV_CALLEE_SAVE(xen_irq_disable), -- cgit v0.10.2 From ad3062a0f438a5f436dae267f795c0a9686f11d2 Mon Sep 17 00:00:00 2001 From: Daniel Kiper Date: Wed, 4 May 2011 20:15:18 +0200 Subject: arch/x86/xen/enlighten: Cleanup code/data sections definitions Cleanup code/data sections definitions accordingly to include/linux/init.h. Signed-off-by: Daniel Kiper Signed-off-by: Konrad Rzeszutek Wilk diff --git a/arch/x86/xen/enlighten.c b/arch/x86/xen/enlighten.c index e3c6a06..dd7b88f 100644 --- a/arch/x86/xen/enlighten.c +++ b/arch/x86/xen/enlighten.c @@ -235,7 +235,7 @@ static void xen_cpuid(unsigned int *ax, unsigned int *bx, *dx &= maskedx; } -static __init void xen_init_cpuid_mask(void) +static void __init xen_init_cpuid_mask(void) { unsigned int ax, bx, cx, dx; unsigned int xsave_mask; @@ -400,7 +400,7 @@ static void xen_load_gdt(const struct desc_ptr *dtr) /* * load_gdt for early boot, when the gdt is only mapped once */ -static __init void xen_load_gdt_boot(const struct desc_ptr *dtr) +static void __init xen_load_gdt_boot(const struct desc_ptr *dtr) { unsigned long va = dtr->address; unsigned int size = dtr->size + 1; @@ -662,7 +662,7 @@ static void xen_write_gdt_entry(struct desc_struct *dt, int entry, * Version of write_gdt_entry for use at early boot-time needed to * update an entry as simply as possible. */ -static __init void xen_write_gdt_entry_boot(struct desc_struct *dt, int entry, +static void __init xen_write_gdt_entry_boot(struct desc_struct *dt, int entry, const void *desc, int type) { switch (type) { @@ -933,18 +933,18 @@ static unsigned xen_patch(u8 type, u16 clobbers, void *insnbuf, return ret; } -static const struct pv_info xen_info __initdata = { +static const struct pv_info xen_info __initconst = { .paravirt_enabled = 1, .shared_kernel_pmd = 0, .name = "Xen", }; -static const struct pv_init_ops xen_init_ops __initdata = { +static const struct pv_init_ops xen_init_ops __initconst = { .patch = xen_patch, }; -static const struct pv_cpu_ops xen_cpu_ops __initdata = { +static const struct pv_cpu_ops xen_cpu_ops __initconst = { .cpuid = xen_cpuid, .set_debugreg = xen_set_debugreg, @@ -1004,7 +1004,7 @@ static const struct pv_cpu_ops xen_cpu_ops __initdata = { .end_context_switch = xen_end_context_switch, }; -static const struct pv_apic_ops xen_apic_ops __initdata = { +static const struct pv_apic_ops xen_apic_ops __initconst = { #ifdef CONFIG_X86_LOCAL_APIC .startup_ipi_hook = paravirt_nop, #endif @@ -1055,7 +1055,7 @@ int xen_panic_handler_init(void) return 0; } -static const struct machine_ops __initdata xen_machine_ops = { +static const struct machine_ops xen_machine_ops __initconst = { .restart = xen_restart, .halt = xen_machine_halt, .power_off = xen_machine_halt, @@ -1332,7 +1332,7 @@ static int __cpuinit xen_hvm_cpu_notify(struct notifier_block *self, return NOTIFY_OK; } -static struct notifier_block __cpuinitdata xen_hvm_cpu_notifier = { +static struct notifier_block xen_hvm_cpu_notifier __cpuinitdata = { .notifier_call = xen_hvm_cpu_notify, }; @@ -1381,7 +1381,7 @@ bool xen_hvm_need_lapic(void) } EXPORT_SYMBOL_GPL(xen_hvm_need_lapic); -const __refconst struct hypervisor_x86 x86_hyper_xen_hvm = { +const struct hypervisor_x86 x86_hyper_xen_hvm __refconst = { .name = "Xen HVM", .detect = xen_hvm_platform, .init_platform = xen_hvm_guest_init, -- cgit v0.10.2 From ae15a3b4d1374b733016ce4b4148b2ba42bbeb0f Mon Sep 17 00:00:00 2001 From: Daniel Kiper Date: Wed, 4 May 2011 20:17:21 +0200 Subject: arch/x86/xen/setup: Cleanup code/data sections definitions Cleanup code/data sections definitions accordingly to include/linux/init.h. Signed-off-by: Daniel Kiper Signed-off-by: Konrad Rzeszutek Wilk diff --git a/arch/x86/xen/setup.c b/arch/x86/xen/setup.c index 90bac0a..d3663df 100644 --- a/arch/x86/xen/setup.c +++ b/arch/x86/xen/setup.c @@ -50,7 +50,7 @@ phys_addr_t xen_extra_mem_start, xen_extra_mem_size; */ #define EXTRA_MEM_RATIO (10) -static __init void xen_add_extra_mem(unsigned long pages) +static void __init xen_add_extra_mem(unsigned long pages) { unsigned long pfn; @@ -336,7 +336,7 @@ static void __init fiddle_vdso(void) #endif } -static __cpuinit int register_callback(unsigned type, const void *func) +static int __cpuinit register_callback(unsigned type, const void *func) { struct callback_register callback = { .type = type, -- cgit v0.10.2 From 1769192a3c50778e03352a3d95faec830d47ba55 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Wed, 11 May 2011 18:22:36 +0000 Subject: l2tp: fix potential rcu race While trying to remove useless synchronize_rcu() calls, I found l2tp is indeed incorrectly using two of such calls, but also bumps tunnel refcount after list insertion. tunnel refcount must be incremented before being made publically visible by rcu readers. This fix can be applied to 2.6.35+ and might need a backport for older kernels, since things were shuffled in commit fd558d186df2c (l2tp: Split pppol2tp patch into separate l2tp and ppp parts) Signed-off-by: Eric Dumazet CC: Paul E. McKenney CC: James Chapman Reviewed-by: Paul E. McKenney Signed-off-by: David S. Miller diff --git a/net/l2tp/l2tp_core.c b/net/l2tp/l2tp_core.c index 9be095e..ed8a233 100644 --- a/net/l2tp/l2tp_core.c +++ b/net/l2tp/l2tp_core.c @@ -1435,16 +1435,15 @@ int l2tp_tunnel_create(struct net *net, int fd, int version, u32 tunnel_id, u32 /* Add tunnel to our list */ INIT_LIST_HEAD(&tunnel->list); - spin_lock_bh(&pn->l2tp_tunnel_list_lock); - list_add_rcu(&tunnel->list, &pn->l2tp_tunnel_list); - spin_unlock_bh(&pn->l2tp_tunnel_list_lock); - synchronize_rcu(); atomic_inc(&l2tp_tunnel_count); /* Bump the reference count. The tunnel context is deleted - * only when this drops to zero. + * only when this drops to zero. Must be done before list insertion */ l2tp_tunnel_inc_refcount(tunnel); + spin_lock_bh(&pn->l2tp_tunnel_list_lock); + list_add_rcu(&tunnel->list, &pn->l2tp_tunnel_list); + spin_unlock_bh(&pn->l2tp_tunnel_list_lock); err = 0; err: @@ -1636,7 +1635,6 @@ struct l2tp_session *l2tp_session_create(int priv_size, struct l2tp_tunnel *tunn hlist_add_head_rcu(&session->global_hlist, l2tp_session_id_hash_2(pn, session_id)); spin_unlock_bh(&pn->l2tp_session_hlist_lock); - synchronize_rcu(); } /* Ignore management session in session count value */ -- cgit v0.10.2 From 517aa0bcda9b092a4c3fab7bf93f0cebe372ece0 Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Thu, 12 May 2011 11:27:20 +0000 Subject: sctp: sctp_sendmsg: Don't initialize default_sinfo This variable only needs initialization when cmsgs.info is NULL. Use memset to ensure padding is also zeroed so kernel doesn't leak any data. Signed-off-by: Joe Perches Signed-off-by: David S. Miller diff --git a/net/sctp/socket.c b/net/sctp/socket.c index 33d9ee6..d4b8db1 100644 --- a/net/sctp/socket.c +++ b/net/sctp/socket.c @@ -1496,7 +1496,7 @@ SCTP_STATIC int sctp_sendmsg(struct kiocb *iocb, struct sock *sk, struct sctp_chunk *chunk; union sctp_addr to; struct sockaddr *msg_name = NULL; - struct sctp_sndrcvinfo default_sinfo = { 0 }; + struct sctp_sndrcvinfo default_sinfo; struct sctp_sndrcvinfo *sinfo; struct sctp_initmsg *sinit; sctp_assoc_t associd = 0; @@ -1760,6 +1760,7 @@ SCTP_STATIC int sctp_sendmsg(struct kiocb *iocb, struct sock *sk, /* If the user didn't specify SNDRCVINFO, make up one with * some defaults. */ + memset(&default_sinfo, 0, sizeof(default_sinfo)); default_sinfo.sinfo_stream = asoc->default_stream; default_sinfo.sinfo_flags = asoc->default_flags; default_sinfo.sinfo_ppid = asoc->default_ppid; -- cgit v0.10.2 From afd7614c00e364f8f1327e73ad291b02f6d4d1a6 Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Thu, 12 May 2011 09:19:10 +0000 Subject: sctp: sctp_sendmsg: Don't test known non-null sinfo It's already known non-null above. Signed-off-by: Joe Perches Signed-off-by: David S. Miller diff --git a/net/sctp/socket.c b/net/sctp/socket.c index d4b8db1..6766913 100644 --- a/net/sctp/socket.c +++ b/net/sctp/socket.c @@ -1791,12 +1791,10 @@ SCTP_STATIC int sctp_sendmsg(struct kiocb *iocb, struct sock *sk, goto out_free; } - if (sinfo) { - /* Check for invalid stream. */ - if (sinfo->sinfo_stream >= asoc->c.sinit_num_ostreams) { - err = -EINVAL; - goto out_free; - } + /* Check for invalid stream. */ + if (sinfo->sinfo_stream >= asoc->c.sinit_num_ostreams) { + err = -EINVAL; + goto out_free; } timeo = sock_sndtimeo(sk, msg->msg_flags & MSG_DONTWAIT); -- cgit v0.10.2 From e154b639bbe53dc91d1873cd37d162bb2fe87aab Mon Sep 17 00:00:00 2001 From: Shreyas Bhatewara Date: Tue, 10 May 2011 06:13:56 +0000 Subject: vmxnet3: Use single tx queue when CONFIG_PCI_MSI not defined Resending this patch with few changes. Avoid multiple queues when MSI or MSI-X not available Limit number of Tx queues to 1 if MSI/MSI-X support is not configured in the kernel. This will make number of tx and rx queues equal when MSI/X is not configured thus providing better performance. Signed-off-by: Bhavesh Davda Signed-off-by: Shreyas N Bhatewara Signed-off-by: David S. Miller diff --git a/drivers/net/vmxnet3/vmxnet3_drv.c b/drivers/net/vmxnet3/vmxnet3_drv.c index c0da230..fa6e2ac 100644 --- a/drivers/net/vmxnet3/vmxnet3_drv.c +++ b/drivers/net/vmxnet3/vmxnet3_drv.c @@ -2884,6 +2884,9 @@ vmxnet3_probe_device(struct pci_dev *pdev, int num_tx_queues; int num_rx_queues; + if (!pci_msi_enabled()) + enable_mq = 0; + #ifdef VMXNET3_RSS if (enable_mq) num_rx_queues = min(VMXNET3_DEVICE_MAX_RX_QUEUES, diff --git a/drivers/net/vmxnet3/vmxnet3_int.h b/drivers/net/vmxnet3/vmxnet3_int.h index 8ba7b5f..f50d36f 100644 --- a/drivers/net/vmxnet3/vmxnet3_int.h +++ b/drivers/net/vmxnet3/vmxnet3_int.h @@ -68,10 +68,10 @@ /* * Version numbers */ -#define VMXNET3_DRIVER_VERSION_STRING "1.0.25.0-k" +#define VMXNET3_DRIVER_VERSION_STRING "1.1.9.0-k" /* a 32-bit int, each byte encode a verion number in VMXNET3_DRIVER_VERSION */ -#define VMXNET3_DRIVER_VERSION_NUM 0x01001900 +#define VMXNET3_DRIVER_VERSION_NUM 0x01010900 #if defined(CONFIG_PCI_MSI) /* RSS only makes sense if MSI-X is supported. */ -- cgit v0.10.2 From 77ed23f8d995a01cd8101d84351b567bf5177a30 Mon Sep 17 00:00:00 2001 From: Cliff Wickman Date: Tue, 10 May 2011 08:26:43 -0500 Subject: x86: Fix UV BAU for non-consecutive nasids This is a fix for the SGI Altix-UV Broadcast Assist Unit code, which is used for TLB flushing. Certain hardware configurations (that customers are ordering) cause nasids (numa address space id's) to be non-consecutive. Specifically, once you have more than 4 blades in a IRU (Individual Rack Unit - or 1/2 rack) but less than the maximum of 16, the nasid numbering becomes non-consecutive. This currently results in a 'catastrophic error' (CATERR) detected by the firmware during OS boot. The BAU is generating an 'INTD' request that is targeting a non-existent nasid value. Such configurations may also occur when a blade is configured off because of hardware errors. (There is one UV hub per blade.) This patch is required to support such configurations. The problem with the tlb_uv.c code is that is using the consecutive hub numbers as indices to the BAU distribution bit map. These are simply the ordinal position of the hub or blade within its partition. It should be using physical node numbers (pnodes), which correspond to the physical nasid values. Use of the hub number only works as long as the nasids in the partition are consecutive and increase with a stride of 1. This patch changes the index to be the pnode number, thus allowing nasids to be non-consecutive. It also provides a table in local memory for each cpu to translate target cpu number to target pnode and nasid. And it improves naming to properly reflect 'node' and 'uvhub' versus 'nasid'. Signed-off-by: Cliff Wickman Cc: Link: http://lkml.kernel.org/r/E1QJmxX-0002Mz-Fk@eag09.americas.sgi.com Signed-off-by: Ingo Molnar diff --git a/arch/x86/include/asm/uv/uv_bau.h b/arch/x86/include/asm/uv/uv_bau.h index 3e094af..130f1ee 100644 --- a/arch/x86/include/asm/uv/uv_bau.h +++ b/arch/x86/include/asm/uv/uv_bau.h @@ -94,6 +94,8 @@ /* after this # consecutive successes, bump up the throttle if it was lowered */ #define COMPLETE_THRESHOLD 5 +#define UV_LB_SUBNODEID 0x10 + /* * number of entries in the destination side payload queue */ @@ -124,7 +126,7 @@ * The distribution specification (32 bytes) is interpreted as a 256-bit * distribution vector. Adjacent bits correspond to consecutive even numbered * nodeIDs. The result of adding the index of a given bit to the 15-bit - * 'base_dest_nodeid' field of the header corresponds to the + * 'base_dest_nasid' field of the header corresponds to the * destination nodeID associated with that specified bit. */ struct bau_target_uvhubmask { @@ -176,7 +178,7 @@ struct bau_msg_payload { struct bau_msg_header { unsigned int dest_subnodeid:6; /* must be 0x10, for the LB */ /* bits 5:0 */ - unsigned int base_dest_nodeid:15; /* nasid of the */ + unsigned int base_dest_nasid:15; /* nasid of the */ /* bits 20:6 */ /* first bit in uvhub map */ unsigned int command:8; /* message type */ /* bits 28:21 */ @@ -378,6 +380,10 @@ struct ptc_stats { unsigned long d_rcanceled; /* number of messages canceled by resets */ }; +struct hub_and_pnode { + short uvhub; + short pnode; +}; /* * one per-cpu; to locate the software tables */ @@ -399,10 +405,12 @@ struct bau_control { int baudisabled; int set_bau_off; short cpu; + short osnode; short uvhub_cpu; short uvhub; short cpus_in_socket; short cpus_in_uvhub; + short partition_base_pnode; unsigned short message_number; unsigned short uvhub_quiesce; short socket_acknowledge_count[DEST_Q_SIZE]; @@ -422,15 +430,16 @@ struct bau_control { int congested_period; cycles_t period_time; long period_requests; + struct hub_and_pnode *target_hub_and_pnode; }; static inline int bau_uvhub_isset(int uvhub, struct bau_target_uvhubmask *dstp) { return constant_test_bit(uvhub, &dstp->bits[0]); } -static inline void bau_uvhub_set(int uvhub, struct bau_target_uvhubmask *dstp) +static inline void bau_uvhub_set(int pnode, struct bau_target_uvhubmask *dstp) { - __set_bit(uvhub, &dstp->bits[0]); + __set_bit(pnode, &dstp->bits[0]); } static inline void bau_uvhubs_clear(struct bau_target_uvhubmask *dstp, int nbits) diff --git a/arch/x86/platform/uv/tlb_uv.c b/arch/x86/platform/uv/tlb_uv.c index 7cb6424..c58e0ea 100644 --- a/arch/x86/platform/uv/tlb_uv.c +++ b/arch/x86/platform/uv/tlb_uv.c @@ -699,16 +699,17 @@ const struct cpumask *uv_flush_tlb_others(const struct cpumask *cpumask, struct mm_struct *mm, unsigned long va, unsigned int cpu) { - int tcpu; - int uvhub; int locals = 0; int remotes = 0; int hubs = 0; + int tcpu; + int tpnode; struct bau_desc *bau_desc; struct cpumask *flush_mask; struct ptc_stats *stat; struct bau_control *bcp; struct bau_control *tbcp; + struct hub_and_pnode *hpp; /* kernel was booted 'nobau' */ if (nobau) @@ -750,11 +751,18 @@ const struct cpumask *uv_flush_tlb_others(const struct cpumask *cpumask, bau_desc += UV_ITEMS_PER_DESCRIPTOR * bcp->uvhub_cpu; bau_uvhubs_clear(&bau_desc->distribution, UV_DISTRIBUTION_SIZE); - /* cpu statistics */ for_each_cpu(tcpu, flush_mask) { - uvhub = uv_cpu_to_blade_id(tcpu); - bau_uvhub_set(uvhub, &bau_desc->distribution); - if (uvhub == bcp->uvhub) + /* + * The distribution vector is a bit map of pnodes, relative + * to the partition base pnode (and the partition base nasid + * in the header). + * Translate cpu to pnode and hub using an array stored + * in local memory. + */ + hpp = &bcp->socket_master->target_hub_and_pnode[tcpu]; + tpnode = hpp->pnode - bcp->partition_base_pnode; + bau_uvhub_set(tpnode, &bau_desc->distribution); + if (hpp->uvhub == bcp->uvhub) locals++; else remotes++; @@ -855,7 +863,7 @@ void uv_bau_message_interrupt(struct pt_regs *regs) * an interrupt, but causes an error message to be returned to * the sender. */ -static void uv_enable_timeouts(void) +static void __init uv_enable_timeouts(void) { int uvhub; int nuvhubs; @@ -1326,10 +1334,10 @@ static int __init uv_ptc_init(void) } /* - * initialize the sending side's sending buffers + * Initialize the sending side's sending buffers. */ static void -uv_activation_descriptor_init(int node, int pnode) +uv_activation_descriptor_init(int node, int pnode, int base_pnode) { int i; int cpu; @@ -1352,11 +1360,11 @@ uv_activation_descriptor_init(int node, int pnode) n = pa >> uv_nshift; m = pa & uv_mmask; + /* the 14-bit pnode */ uv_write_global_mmr64(pnode, UVH_LB_BAU_SB_DESCRIPTOR_BASE, (n << UV_DESC_BASE_PNODE_SHIFT | m)); - /* - * initializing all 8 (UV_ITEMS_PER_DESCRIPTOR) descriptors for each + * Initializing all 8 (UV_ITEMS_PER_DESCRIPTOR) descriptors for each * cpu even though we only use the first one; one descriptor can * describe a broadcast to 256 uv hubs. */ @@ -1365,12 +1373,13 @@ uv_activation_descriptor_init(int node, int pnode) memset(bd2, 0, sizeof(struct bau_desc)); bd2->header.sw_ack_flag = 1; /* - * base_dest_nodeid is the nasid of the first uvhub - * in the partition. The bit map will indicate uvhub numbers, - * which are 0-N in a partition. Pnodes are unique system-wide. + * The base_dest_nasid set in the message header is the nasid + * of the first uvhub in the partition. The bit map will + * indicate destination pnode numbers relative to that base. + * They may not be consecutive if nasid striding is being used. */ - bd2->header.base_dest_nodeid = UV_PNODE_TO_NASID(uv_partition_base_pnode); - bd2->header.dest_subnodeid = 0x10; /* the LB */ + bd2->header.base_dest_nasid = UV_PNODE_TO_NASID(base_pnode); + bd2->header.dest_subnodeid = UV_LB_SUBNODEID; bd2->header.command = UV_NET_ENDPOINT_INTD; bd2->header.int_both = 1; /* @@ -1442,7 +1451,7 @@ uv_payload_queue_init(int node, int pnode) /* * Initialization of each UV hub's structures */ -static void __init uv_init_uvhub(int uvhub, int vector) +static void __init uv_init_uvhub(int uvhub, int vector, int base_pnode) { int node; int pnode; @@ -1450,11 +1459,11 @@ static void __init uv_init_uvhub(int uvhub, int vector) node = uvhub_to_first_node(uvhub); pnode = uv_blade_to_pnode(uvhub); - uv_activation_descriptor_init(node, pnode); + uv_activation_descriptor_init(node, pnode, base_pnode); uv_payload_queue_init(node, pnode); /* - * the below initialization can't be in firmware because the - * messaging IRQ will be determined by the OS + * The below initialization can't be in firmware because the + * messaging IRQ will be determined by the OS. */ apicid = uvhub_to_first_apicid(uvhub) | uv_apicid_hibits; uv_write_global_mmr64(pnode, UVH_BAU_DATA_CONFIG, @@ -1491,10 +1500,11 @@ calculate_destination_timeout(void) /* * initialize the bau_control structure for each cpu */ -static int __init uv_init_per_cpu(int nuvhubs) +static int __init uv_init_per_cpu(int nuvhubs, int base_part_pnode) { int i; int cpu; + int tcpu; int pnode; int uvhub; int have_hmaster; @@ -1528,6 +1538,15 @@ static int __init uv_init_per_cpu(int nuvhubs) bcp = &per_cpu(bau_control, cpu); memset(bcp, 0, sizeof(struct bau_control)); pnode = uv_cpu_hub_info(cpu)->pnode; + if ((pnode - base_part_pnode) >= UV_DISTRIBUTION_SIZE) { + printk(KERN_EMERG + "cpu %d pnode %d-%d beyond %d; BAU disabled\n", + cpu, pnode, base_part_pnode, + UV_DISTRIBUTION_SIZE); + return 1; + } + bcp->osnode = cpu_to_node(cpu); + bcp->partition_base_pnode = uv_partition_base_pnode; uvhub = uv_cpu_hub_info(cpu)->numa_blade_id; *(uvhub_mask + (uvhub/8)) |= (1 << (uvhub%8)); bdp = &uvhub_descs[uvhub]; @@ -1536,7 +1555,7 @@ static int __init uv_init_per_cpu(int nuvhubs) bdp->pnode = pnode; /* kludge: 'assuming' one node per socket, and assuming that disabling a socket just leaves a gap in node numbers */ - socket = (cpu_to_node(cpu) & 1); + socket = bcp->osnode & 1; bdp->socket_mask |= (1 << socket); sdp = &bdp->socket[socket]; sdp->cpu_number[sdp->num_cpus] = cpu; @@ -1585,6 +1604,20 @@ static int __init uv_init_per_cpu(int nuvhubs) nextsocket: socket++; socket_mask = (socket_mask >> 1); + /* each socket gets a local array of pnodes/hubs */ + bcp = smaster; + bcp->target_hub_and_pnode = kmalloc_node( + sizeof(struct hub_and_pnode) * + num_possible_cpus(), GFP_KERNEL, bcp->osnode); + memset(bcp->target_hub_and_pnode, 0, + sizeof(struct hub_and_pnode) * + num_possible_cpus()); + for_each_present_cpu(tcpu) { + bcp->target_hub_and_pnode[tcpu].pnode = + uv_cpu_hub_info(tcpu)->pnode; + bcp->target_hub_and_pnode[tcpu].uvhub = + uv_cpu_hub_info(tcpu)->numa_blade_id; + } } } kfree(uvhub_descs); @@ -1637,21 +1670,22 @@ static int __init uv_bau_init(void) spin_lock_init(&disable_lock); congested_cycles = microsec_2_cycles(congested_response_us); - if (uv_init_per_cpu(nuvhubs)) { - nobau = 1; - return 0; - } - uv_partition_base_pnode = 0x7fffffff; - for (uvhub = 0; uvhub < nuvhubs; uvhub++) + for (uvhub = 0; uvhub < nuvhubs; uvhub++) { if (uv_blade_nr_possible_cpus(uvhub) && (uv_blade_to_pnode(uvhub) < uv_partition_base_pnode)) uv_partition_base_pnode = uv_blade_to_pnode(uvhub); + } + + if (uv_init_per_cpu(nuvhubs, uv_partition_base_pnode)) { + nobau = 1; + return 0; + } vector = UV_BAU_MESSAGE; for_each_possible_blade(uvhub) if (uv_blade_nr_possible_cpus(uvhub)) - uv_init_uvhub(uvhub, vector); + uv_init_uvhub(uvhub, vector, uv_partition_base_pnode); uv_enable_timeouts(); alloc_intr_gate(vector, uv_bau_message_intr1); -- cgit v0.10.2 From f607a158004d75c9005423ce1ba70dc6ec3dd9c2 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Thu, 12 May 2011 17:46:56 -0400 Subject: garp: remove last synchronize_rcu() call When removing last vlan from a device, garp_uninit_applicant() calls synchronize_rcu() to make sure no user can still manipulate struct garp_applicant before we free it. Use call_rcu() instead, as a step to further net_device dismantle optimizations. Add the temporary garp_cleanup_module() function to make sure no pending call_rcu() are left at module unload time [ this will be removed when kfree_rcu() is available ] Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller diff --git a/include/net/garp.h b/include/net/garp.h index 8cabbf08..834d8ad 100644 --- a/include/net/garp.h +++ b/include/net/garp.h @@ -104,6 +104,7 @@ struct garp_applicant { struct sk_buff_head queue; struct sk_buff *pdu; struct rb_root gid; + struct rcu_head rcu; }; struct garp_port { diff --git a/net/802/garp.c b/net/802/garp.c index 5dbe896..f8300a8 100644 --- a/net/802/garp.c +++ b/net/802/garp.c @@ -603,6 +603,11 @@ err1: } EXPORT_SYMBOL_GPL(garp_init_applicant); +static void garp_app_kfree_rcu(struct rcu_head *head) +{ + kfree(container_of(head, struct garp_applicant, rcu)); +} + void garp_uninit_applicant(struct net_device *dev, struct garp_application *appl) { struct garp_port *port = rtnl_dereference(dev->garp_port); @@ -611,7 +616,6 @@ void garp_uninit_applicant(struct net_device *dev, struct garp_application *appl ASSERT_RTNL(); rcu_assign_pointer(port->applicants[appl->type], NULL); - synchronize_rcu(); /* Delete timer and generate a final TRANSMIT_PDU event to flush out * all pending messages before the applicant is gone. */ @@ -621,7 +625,7 @@ void garp_uninit_applicant(struct net_device *dev, struct garp_application *appl garp_queue_xmit(app); dev_mc_del(dev, appl->proto.group_address); - kfree(app); + call_rcu(&app->rcu, garp_app_kfree_rcu); garp_release_port(dev); } EXPORT_SYMBOL_GPL(garp_uninit_applicant); @@ -639,3 +643,9 @@ void garp_unregister_application(struct garp_application *appl) stp_proto_unregister(&appl->proto); } EXPORT_SYMBOL_GPL(garp_unregister_application); + +static void __exit garp_cleanup_module(void) +{ + rcu_barrier(); /* Wait for completion of call_rcu()'s */ +} +module_exit(garp_cleanup_module); -- cgit v0.10.2 From 864b5418ebc16893cfd27ff3cda254eff0f56d6f Mon Sep 17 00:00:00 2001 From: Franco Fichtner Date: Thu, 12 May 2011 06:42:04 +0000 Subject: ethtool: bring back missing comma in netdev features strings MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The issue was introduced in commit eed2a12f1ed9aabf. Signed-off-by: Franco Fichtner Acked-by: MichaÅ‚ MirosÅ‚aw Acked-by: Ben Hutchings Signed-off-by: David S. Miller diff --git a/net/core/ethtool.c b/net/core/ethtool.c index b6f4058..b8c2b10f 100644 --- a/net/core/ethtool.c +++ b/net/core/ethtool.c @@ -361,7 +361,7 @@ static const char netdev_features_strings[ETHTOOL_DEV_FEATURE_WORDS * 32][ETH_GS /* NETIF_F_NTUPLE */ "rx-ntuple-filter", /* NETIF_F_RXHASH */ "rx-hashing", /* NETIF_F_RXCSUM */ "rx-checksum", - /* NETIF_F_NOCACHE_COPY */ "tx-nocache-copy" + /* NETIF_F_NOCACHE_COPY */ "tx-nocache-copy", /* NETIF_F_LOOPBACK */ "loopback", }; -- cgit v0.10.2 From f0a619ccfb8a2ec8ff083a02299cfd076c362b27 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Miros=C5=82aw?= Date: Fri, 6 May 2011 07:56:29 +0000 Subject: net: Fix vlan_features propagation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fix VLAN features propagation for devices which change vlan_features. For this to work, driver needs to make sure netdev_features_changed() gets called after the change (it is e.g. after ndo_set_features()). Side effect is that a user might request features that will never be enabled on a VLAN device. Signed-off-by: MichaÅ‚ MirosÅ‚aw Signed-off-by: David S. Miller diff --git a/net/8021q/vlan_dev.c b/net/8021q/vlan_dev.c index 58f8010..f247f5b 100644 --- a/net/8021q/vlan_dev.c +++ b/net/8021q/vlan_dev.c @@ -528,7 +528,7 @@ static int vlan_dev_init(struct net_device *dev) (1<<__LINK_STATE_DORMANT))) | (1<<__LINK_STATE_PRESENT); - dev->hw_features = real_dev->vlan_features & NETIF_F_ALL_TX_OFFLOADS; + dev->hw_features = NETIF_F_ALL_TX_OFFLOADS; dev->features |= real_dev->vlan_features | NETIF_F_LLTX; dev->gso_max_size = real_dev->gso_max_size; @@ -587,9 +587,11 @@ static u32 vlan_dev_fix_features(struct net_device *dev, u32 features) { struct net_device *real_dev = vlan_dev_info(dev)->real_dev; - features &= (real_dev->features | NETIF_F_LLTX); + features &= real_dev->features; + features &= real_dev->vlan_features; if (dev_ethtool_get_rx_csum(real_dev)) features |= NETIF_F_RXCSUM; + features |= NETIF_F_LLTX; return features; } -- cgit v0.10.2 From 7f267051bd7a280265b1b5ead58e9c6e4e1ac3a4 Mon Sep 17 00:00:00 2001 From: Yi Zou Date: Mon, 9 May 2011 11:53:27 +0000 Subject: net: group FCoE related feature flags MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit MichaÅ‚ MirosÅ‚aw's patch (http://patchwork.ozlabs.org/patch/94421/) fixes the issue (http://patchwork.ozlabs.org/patch/94188/) about not populating FCoE related flags correctly on vlan devices. However, only NETIF_F_FCOE_CRC is part of the NETIF_F_ALL_TX_OFFLOADS right now, where weed NETIF_F_FCOE_MTU and NETIF_F_FSO as well. Therefore, add NETIF_F_ALL_FCOE to indicate feature flags used by FCoE TX offloads. These include NETIF_F_FCOE_CRC, NETIF_F_FCOE_MTU, and NETIF_F_FSO and add them to be part of NETIF_F_ALL_TX_OFFLOADS. This would eventually make sure all FCoE needed flags are populated properly to vlan devices. Signed-off-by: Yi Zou Signed-off-by: David S. Miller diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index e7244ed..00d650c 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -1097,10 +1097,14 @@ struct net_device { #define NETIF_F_ALL_TSO (NETIF_F_TSO | NETIF_F_TSO6 | NETIF_F_TSO_ECN) +#define NETIF_F_ALL_FCOE (NETIF_F_FCOE_CRC | NETIF_F_FCOE_MTU | \ + NETIF_F_FSO) + #define NETIF_F_ALL_TX_OFFLOADS (NETIF_F_ALL_CSUM | NETIF_F_SG | \ NETIF_F_FRAGLIST | NETIF_F_ALL_TSO | \ NETIF_F_HIGHDMA | \ - NETIF_F_SCTP_CSUM | NETIF_F_FCOE_CRC) + NETIF_F_SCTP_CSUM | \ + NETIF_F_ALL_FCOE) /* * If one device supports one of these features, then enable them -- cgit v0.10.2 From cbfd1526f6076ece92b4e2dcc0a2f1e89041b3bd Mon Sep 17 00:00:00 2001 From: Amit Virdi Date: Thu, 12 May 2011 01:04:40 +0000 Subject: net/irda/ircomm_tty.c: Use flip buffers to deliver data use tty_insert_flip_string and tty_flip_buffer_push to deliver incoming data packets from the IrDA device instead of delivering the packets directly to the line discipline. Following later approach resulted in warning "Sleeping function called from invalid context". Signed-off-by: Amit Virdi Acked-by: Alan Cox Signed-off-by: David S. Miller diff --git a/net/irda/ircomm/ircomm_tty.c b/net/irda/ircomm/ircomm_tty.c index a39cca8..b3cc8b3 100644 --- a/net/irda/ircomm/ircomm_tty.c +++ b/net/irda/ircomm/ircomm_tty.c @@ -38,6 +38,7 @@ #include #include #include +#include #include #include /* for MODULE_ALIAS_CHARDEV_MAJOR */ @@ -1132,7 +1133,6 @@ static int ircomm_tty_data_indication(void *instance, void *sap, struct sk_buff *skb) { struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) instance; - struct tty_ldisc *ld; IRDA_DEBUG(2, "%s()\n", __func__ ); @@ -1161,15 +1161,11 @@ static int ircomm_tty_data_indication(void *instance, void *sap, } /* - * Just give it over to the line discipline. There is no need to - * involve the flip buffers, since we are not running in an interrupt - * handler + * Use flip buffer functions since the code may be called from interrupt + * context */ - - ld = tty_ldisc_ref(self->tty); - if (ld) - ld->ops->receive_buf(self->tty, skb->data, NULL, skb->len); - tty_ldisc_deref(ld); + tty_insert_flip_string(self->tty, skb->data, skb->len); + tty_flip_buffer_push(self->tty); /* No need to kfree_skb - see ircomm_ttp_data_indication() */ -- cgit v0.10.2 From 06c03c02ea528af0cbce50ce45ddd6a361864550 Mon Sep 17 00:00:00 2001 From: Mahesh Bandewar Date: Sun, 8 May 2011 06:51:48 +0000 Subject: tg3: Allow ethtool to enable/disable loopback. This patch adds tg3_set_features() to handle loopback mode. Currently the capability is added for the devices which support internal MAC loopback mode. So when enabled, it enables internal-MAC loopback. Signed-off-by: Mahesh Bandewar Signed-off-by: David S. Miller diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index ec19530..d5a1f9e 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -3373,8 +3373,8 @@ relink: tg3_phy_copper_begin(tp); tg3_readphy(tp, MII_BMSR, &bmsr); - if (!tg3_readphy(tp, MII_BMSR, &bmsr) && - (bmsr & BMSR_LSTATUS)) + if ((!tg3_readphy(tp, MII_BMSR, &bmsr) && (bmsr & BMSR_LSTATUS)) || + (tp->mac_mode & MAC_MODE_PORT_INT_LPBACK)) current_link_up = 1; } @@ -6309,6 +6309,42 @@ dma_error: return NETDEV_TX_OK; } +static void tg3_set_loopback(struct net_device *dev, u32 features) +{ + struct tg3 *tp = netdev_priv(dev); + + if (features & NETIF_F_LOOPBACK) { + if (tp->mac_mode & MAC_MODE_PORT_INT_LPBACK) + return; + + /* + * Clear MAC_MODE_HALF_DUPLEX or you won't get packets back in + * loopback mode if Half-Duplex mode was negotiated earlier. + */ + tp->mac_mode &= ~MAC_MODE_HALF_DUPLEX; + + /* Enable internal MAC loopback mode */ + tp->mac_mode |= MAC_MODE_PORT_INT_LPBACK; + spin_lock_bh(&tp->lock); + tw32(MAC_MODE, tp->mac_mode); + netif_carrier_on(tp->dev); + spin_unlock_bh(&tp->lock); + netdev_info(dev, "Internal MAC loopback mode enabled.\n"); + } else { + if (!(tp->mac_mode & MAC_MODE_PORT_INT_LPBACK)) + return; + + /* Disable internal MAC loopback mode */ + tp->mac_mode &= ~MAC_MODE_PORT_INT_LPBACK; + spin_lock_bh(&tp->lock); + tw32(MAC_MODE, tp->mac_mode); + /* Force link status check */ + tg3_setup_phy(tp, 1); + spin_unlock_bh(&tp->lock); + netdev_info(dev, "Internal MAC loopback mode disabled.\n"); + } +} + static u32 tg3_fix_features(struct net_device *dev, u32 features) { struct tg3 *tp = netdev_priv(dev); @@ -6319,6 +6355,16 @@ static u32 tg3_fix_features(struct net_device *dev, u32 features) return features; } +static int tg3_set_features(struct net_device *dev, u32 features) +{ + u32 changed = dev->features ^ features; + + if ((changed & NETIF_F_LOOPBACK) && netif_running(dev)) + tg3_set_loopback(dev, features); + + return 0; +} + static inline void tg3_set_mtu(struct net_device *dev, struct tg3 *tp, int new_mtu) { @@ -9485,6 +9531,13 @@ static int tg3_open(struct net_device *dev) netif_tx_start_all_queues(dev); + /* + * Reset loopback feature if it was turned on while the device was down + * make sure that it's installed properly now. + */ + if (dev->features & NETIF_F_LOOPBACK) + tg3_set_loopback(dev, dev->features); + return 0; err_out3: @@ -15033,6 +15086,7 @@ static const struct net_device_ops tg3_netdev_ops = { .ndo_tx_timeout = tg3_tx_timeout, .ndo_change_mtu = tg3_change_mtu, .ndo_fix_features = tg3_fix_features, + .ndo_set_features = tg3_set_features, #ifdef CONFIG_NET_POLL_CONTROLLER .ndo_poll_controller = tg3_poll_controller, #endif @@ -15049,6 +15103,7 @@ static const struct net_device_ops tg3_netdev_ops_dma_bug = { .ndo_do_ioctl = tg3_ioctl, .ndo_tx_timeout = tg3_tx_timeout, .ndo_change_mtu = tg3_change_mtu, + .ndo_set_features = tg3_set_features, #ifdef CONFIG_NET_POLL_CONTROLLER .ndo_poll_controller = tg3_poll_controller, #endif @@ -15246,6 +15301,16 @@ static int __devinit tg3_init_one(struct pci_dev *pdev, dev->features |= hw_features; dev->vlan_features |= hw_features; + /* + * Add loopback capability only for a subset of devices that support + * MAC-LOOPBACK. Eventually this need to be enhanced to allow INT-PHY + * loopback for the remaining devices. + */ + if (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5780 && + !tg3_flag(tp, CPMU_PRESENT)) + /* Add the loopback capability */ + dev->hw_features |= NETIF_F_LOOPBACK; + if (tp->pci_chip_rev_id == CHIPREV_ID_5705_A1 && !tg3_flag(tp, TSO_CAPABLE) && !(tr32(TG3PCI_PCISTATE) & PCISTATE_BUS_SPEED_HIGH)) { -- cgit v0.10.2 From 1b0bcbcf62884959fa7214eb16c44cff445691c6 Mon Sep 17 00:00:00 2001 From: Pedro Scarapicchia Junior Date: Mon, 9 May 2011 14:10:49 +0000 Subject: net/9p/protocol.c: Fix a memory leak When p9pdu_readf() is called with "s" attribute, it allocates a pointer that will store a string. In p9dirent_read(), this pointer is not being released, leading to out of memory errors. This patch releases this pointer after string is copyed to dirent->d_name. Signed-off-by: Pedro Scarapicchia Junior Signed-off-by: Eric Van Hensbergen diff --git a/net/9p/protocol.c b/net/9p/protocol.c index b58a501..a873277 100644 --- a/net/9p/protocol.c +++ b/net/9p/protocol.c @@ -674,6 +674,7 @@ int p9dirent_read(char *buf, int len, struct p9_dirent *dirent, } strcpy(dirent->d_name, nameptr); + kfree(nameptr); out: return fake_pdu.offset; -- cgit v0.10.2 From 411f05f123cbd7f8aa1edcae86970755a6e2a9d9 Mon Sep 17 00:00:00 2001 From: Ingo Molnar Date: Thu, 12 May 2011 23:00:28 +0200 Subject: vsprintf: Turn kptr_restrict off by default kptr_restrict has been triggering bugs in apps such as perf, and it also makes the system less useful by default, so turn it off by default. This is how we generally handle security features that remove functionality, such as firewall code or SELinux - they have to be configured and activated from user-space. Distributions can turn kptr_restrict on again via this line in /etc/sysctrl.conf: kernel.kptr_restrict = 1 ( Also mark the variable __read_mostly while at it, as it's typically modified only once per bootup, or not at all. ) Signed-off-by: Ingo Molnar Acked-by: David S. Miller Signed-off-by: Linus Torvalds diff --git a/lib/vsprintf.c b/lib/vsprintf.c index bc0ac6b..dfd6019 100644 --- a/lib/vsprintf.c +++ b/lib/vsprintf.c @@ -797,7 +797,7 @@ char *uuid_string(char *buf, char *end, const u8 *addr, return string(buf, end, uuid, spec); } -int kptr_restrict = 1; +int kptr_restrict __read_mostly; /* * Show a '%p' thing. A kernel extension is that the '%p' is followed -- cgit v0.10.2 From e58b34425bfcb08c6bc8c520b82c37ffcec87072 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Thu, 12 May 2011 18:22:34 -0400 Subject: ipvs: Use IP_VS_RT_MODE_* instead of magic constants. [ Add some cases I missed, from Julian Anastasov ] Signed-off-by: David S. Miller diff --git a/net/netfilter/ipvs/ip_vs_xmit.c b/net/netfilter/ipvs/ip_vs_xmit.c index 6132b21..5d393c5 100644 --- a/net/netfilter/ipvs/ip_vs_xmit.c +++ b/net/netfilter/ipvs/ip_vs_xmit.c @@ -229,8 +229,6 @@ out_err: /* * Get route to destination or remote server - * rt_mode: flags, &1=Allow local dest, &2=Allow non-local dest, - * &4=Allow redirect from remote daddr to local */ static struct rt6_info * __ip_vs_get_out_rt_v6(struct sk_buff *skb, struct ip_vs_dest *dest, @@ -274,13 +272,14 @@ __ip_vs_get_out_rt_v6(struct sk_buff *skb, struct ip_vs_dest *dest, } local = __ip_vs_is_local_route6(rt); - if (!((local ? 1 : 2) & rt_mode)) { + if (!((local ? IP_VS_RT_MODE_LOCAL : IP_VS_RT_MODE_NON_LOCAL) & + rt_mode)) { IP_VS_DBG_RL("Stopping traffic to %s address, dest: %pI6\n", local ? "local":"non-local", daddr); dst_release(&rt->dst); return NULL; } - if (local && !(rt_mode & 4) && + if (local && !(rt_mode & IP_VS_RT_MODE_RDR) && !((ort = (struct rt6_info *) skb_dst(skb)) && __ip_vs_is_local_route6(ort))) { IP_VS_DBG_RL("Redirect from non-local address %pI6 to local " @@ -440,7 +439,8 @@ ip_vs_bypass_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp, EnterFunction(10); - if (!(rt = __ip_vs_get_out_rt_v6(skb, NULL, &iph->daddr, NULL, 0, 2))) + if (!(rt = __ip_vs_get_out_rt_v6(skb, NULL, &iph->daddr, NULL, 0, + IP_VS_RT_MODE_NON_LOCAL))) goto tx_error_icmp; /* MTU checking */ @@ -632,7 +632,9 @@ ip_vs_nat_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp, } if (!(rt = __ip_vs_get_out_rt_v6(skb, cp->dest, &cp->daddr.in6, NULL, - 0, 1|2|4))) + 0, (IP_VS_RT_MODE_LOCAL | + IP_VS_RT_MODE_NON_LOCAL | + IP_VS_RT_MODE_RDR)))) goto tx_error_icmp; local = __ip_vs_is_local_route6(rt); /* @@ -875,7 +877,8 @@ ip_vs_tunnel_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp, EnterFunction(10); if (!(rt = __ip_vs_get_out_rt_v6(skb, cp->dest, &cp->daddr.in6, - &saddr, 1, 1|2))) + &saddr, 1, (IP_VS_RT_MODE_LOCAL | + IP_VS_RT_MODE_NON_LOCAL)))) goto tx_error_icmp; if (__ip_vs_is_local_route6(rt)) { dst_release(&rt->dst); @@ -1050,7 +1053,8 @@ ip_vs_dr_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp, EnterFunction(10); if (!(rt = __ip_vs_get_out_rt_v6(skb, cp->dest, &cp->daddr.in6, NULL, - 0, 1|2))) + 0, (IP_VS_RT_MODE_LOCAL | + IP_VS_RT_MODE_NON_LOCAL)))) goto tx_error_icmp; if (__ip_vs_is_local_route6(rt)) { dst_release(&rt->dst); @@ -1254,7 +1258,9 @@ ip_vs_icmp_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp, */ if (!(rt = __ip_vs_get_out_rt_v6(skb, cp->dest, &cp->daddr.in6, NULL, - 0, 1|2|4))) + 0, (IP_VS_RT_MODE_LOCAL | + IP_VS_RT_MODE_NON_LOCAL | + IP_VS_RT_MODE_RDR)))) goto tx_error_icmp; local = __ip_vs_is_local_route6(rt); -- cgit v0.10.2 From 44e3125ccd521585e73e6dd228b283ab26993c68 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Mon, 9 May 2011 14:38:06 -0700 Subject: ipvs: Eliminate rt->rt_dst usage in __ip_vs_get_out_rt(). We can simply track what destination address is used based upon which code block is taken at the top of the function. Signed-off-by: David S. Miller diff --git a/net/netfilter/ipvs/ip_vs_xmit.c b/net/netfilter/ipvs/ip_vs_xmit.c index 5d393c5..3f3e0f4 100644 --- a/net/netfilter/ipvs/ip_vs_xmit.c +++ b/net/netfilter/ipvs/ip_vs_xmit.c @@ -110,6 +110,7 @@ __ip_vs_get_out_rt(struct sk_buff *skb, struct ip_vs_dest *dest, &dest->addr.ip, atomic_read(&rt->dst.__refcnt), rtos); } + daddr = dest->addr.ip; spin_unlock(&dest->dst_lock); } else { rt = ip_route_output(net, daddr, 0, rtos, 0); @@ -125,7 +126,7 @@ __ip_vs_get_out_rt(struct sk_buff *skb, struct ip_vs_dest *dest, rt_mode)) { IP_VS_DBG_RL("Stopping traffic to %s address, dest: %pI4\n", (rt->rt_flags & RTCF_LOCAL) ? - "local":"non-local", &rt->rt_dst); + "local":"non-local", &daddr); ip_rt_put(rt); return NULL; } @@ -133,14 +134,14 @@ __ip_vs_get_out_rt(struct sk_buff *skb, struct ip_vs_dest *dest, !((ort = skb_rtable(skb)) && ort->rt_flags & RTCF_LOCAL)) { IP_VS_DBG_RL("Redirect from non-local address %pI4 to local " "requires NAT method, dest: %pI4\n", - &ip_hdr(skb)->daddr, &rt->rt_dst); + &ip_hdr(skb)->daddr, &daddr); ip_rt_put(rt); return NULL; } if (unlikely(!local && ipv4_is_loopback(ip_hdr(skb)->saddr))) { IP_VS_DBG_RL("Stopping traffic from loopback address %pI4 " "to non-local address, dest: %pI4\n", - &ip_hdr(skb)->saddr, &rt->rt_dst); + &ip_hdr(skb)->saddr, &daddr); ip_rt_put(rt); return NULL; } -- cgit v0.10.2 From c92f5ca2e5120796c56455e0a4b7cc0dfd6ceb49 Mon Sep 17 00:00:00 2001 From: Julian Anastasov Date: Tue, 10 May 2011 12:46:05 +0000 Subject: ipvs: Remove all remaining references to rt->rt_{src,dst} Remove all remaining references to rt->rt_{src,dst} by using dest->dst_saddr to cache saddr (used for TUN mode). For ICMP in FORWARD hook just restrict the rt_mode for NAT to disable LOCALNODE. All other modes do not allow IP_VS_RT_MODE_RDR, so we should be safe with the ICMP forwarding. Using cp->daddr as replacement for rt_dst is safe for all modes except BYPASS, even when cp->dest is NULL because it is cp->daddr that is used to assign cp->dest for sync-ed connections. Signed-off-by: Julian Anastasov Signed-off-by: David S. Miller diff --git a/include/net/ip_vs.h b/include/net/ip_vs.h index 9d1f510..4fff432 100644 --- a/include/net/ip_vs.h +++ b/include/net/ip_vs.h @@ -665,9 +665,7 @@ struct ip_vs_dest { struct dst_entry *dst_cache; /* destination cache entry */ u32 dst_rtos; /* RT_TOS(tos) for dst */ u32 dst_cookie; -#ifdef CONFIG_IP_VS_IPV6 - struct in6_addr dst_saddr; -#endif + union nf_inet_addr dst_saddr; /* for virtual service */ struct ip_vs_service *svc; /* service it belongs to */ @@ -1253,7 +1251,8 @@ extern int ip_vs_tunnel_xmit extern int ip_vs_dr_xmit (struct sk_buff *skb, struct ip_vs_conn *cp, struct ip_vs_protocol *pp); extern int ip_vs_icmp_xmit -(struct sk_buff *skb, struct ip_vs_conn *cp, struct ip_vs_protocol *pp, int offset); +(struct sk_buff *skb, struct ip_vs_conn *cp, struct ip_vs_protocol *pp, + int offset, unsigned int hooknum); extern void ip_vs_dst_reset(struct ip_vs_dest *dest); #ifdef CONFIG_IP_VS_IPV6 @@ -1267,7 +1266,7 @@ extern int ip_vs_dr_xmit_v6 (struct sk_buff *skb, struct ip_vs_conn *cp, struct ip_vs_protocol *pp); extern int ip_vs_icmp_xmit_v6 (struct sk_buff *skb, struct ip_vs_conn *cp, struct ip_vs_protocol *pp, - int offset); + int offset, unsigned int hooknum); #endif #ifdef CONFIG_SYSCTL diff --git a/net/netfilter/ipvs/ip_vs_core.c b/net/netfilter/ipvs/ip_vs_core.c index a74dae6..bfa808f 100644 --- a/net/netfilter/ipvs/ip_vs_core.c +++ b/net/netfilter/ipvs/ip_vs_core.c @@ -1382,15 +1382,7 @@ ip_vs_in_icmp(struct sk_buff *skb, int *related, unsigned int hooknum) ip_vs_in_stats(cp, skb); if (IPPROTO_TCP == cih->protocol || IPPROTO_UDP == cih->protocol) offset += 2 * sizeof(__u16); - verdict = ip_vs_icmp_xmit(skb, cp, pp, offset); - /* LOCALNODE from FORWARD hook is not supported */ - if (verdict == NF_ACCEPT && hooknum == NF_INET_FORWARD && - skb_rtable(skb)->rt_flags & RTCF_LOCAL) { - IP_VS_DBG(1, "%s(): " - "local delivery to %pI4 but in FORWARD\n", - __func__, &skb_rtable(skb)->rt_dst); - verdict = NF_DROP; - } + verdict = ip_vs_icmp_xmit(skb, cp, pp, offset, hooknum); out: __ip_vs_conn_put(cp); @@ -1412,7 +1404,6 @@ ip_vs_in_icmp_v6(struct sk_buff *skb, int *related, unsigned int hooknum) struct ip_vs_protocol *pp; struct ip_vs_proto_data *pd; unsigned int offset, verdict; - struct rt6_info *rt; *related = 1; @@ -1474,23 +1465,12 @@ ip_vs_in_icmp_v6(struct sk_buff *skb, int *related, unsigned int hooknum) if (!cp) return NF_ACCEPT; - verdict = NF_DROP; - /* do the statistics and put it back */ ip_vs_in_stats(cp, skb); if (IPPROTO_TCP == cih->nexthdr || IPPROTO_UDP == cih->nexthdr || IPPROTO_SCTP == cih->nexthdr) offset += 2 * sizeof(__u16); - verdict = ip_vs_icmp_xmit_v6(skb, cp, pp, offset); - /* LOCALNODE from FORWARD hook is not supported */ - if (verdict == NF_ACCEPT && hooknum == NF_INET_FORWARD && - (rt = (struct rt6_info *) skb_dst(skb)) && - rt->rt6i_dev && rt->rt6i_dev->flags & IFF_LOOPBACK) { - IP_VS_DBG(1, "%s(): " - "local delivery to %pI6 but in FORWARD\n", - __func__, &rt->rt6i_dst); - verdict = NF_DROP; - } + verdict = ip_vs_icmp_xmit_v6(skb, cp, pp, offset, hooknum); __ip_vs_conn_put(cp); diff --git a/net/netfilter/ipvs/ip_vs_xmit.c b/net/netfilter/ipvs/ip_vs_xmit.c index 3f3e0f4..ee319a4 100644 --- a/net/netfilter/ipvs/ip_vs_xmit.c +++ b/net/netfilter/ipvs/ip_vs_xmit.c @@ -87,7 +87,7 @@ __ip_vs_dst_check(struct ip_vs_dest *dest, u32 rtos) /* Get route to destination or remote server */ static struct rtable * __ip_vs_get_out_rt(struct sk_buff *skb, struct ip_vs_dest *dest, - __be32 daddr, u32 rtos, int rt_mode) + __be32 daddr, u32 rtos, int rt_mode, __be32 *ret_saddr) { struct net *net = dev_net(skb_dst(skb)->dev); struct rtable *rt; /* Route to the other host */ @@ -98,7 +98,12 @@ __ip_vs_get_out_rt(struct sk_buff *skb, struct ip_vs_dest *dest, spin_lock(&dest->dst_lock); if (!(rt = (struct rtable *) __ip_vs_dst_check(dest, rtos))) { - rt = ip_route_output(net, dest->addr.ip, 0, rtos, 0); + struct flowi4 fl4; + + memset(&fl4, 0, sizeof(fl4)); + fl4.daddr = dest->addr.ip; + fl4.flowi4_tos = rtos; + rt = ip_route_output_key(net, &fl4); if (IS_ERR(rt)) { spin_unlock(&dest->dst_lock); IP_VS_DBG_RL("ip_route_output error, dest: %pI4\n", @@ -106,19 +111,30 @@ __ip_vs_get_out_rt(struct sk_buff *skb, struct ip_vs_dest *dest, return NULL; } __ip_vs_dst_set(dest, rtos, dst_clone(&rt->dst), 0); - IP_VS_DBG(10, "new dst %pI4, refcnt=%d, rtos=%X\n", - &dest->addr.ip, + dest->dst_saddr.ip = fl4.saddr; + IP_VS_DBG(10, "new dst %pI4, src %pI4, refcnt=%d, " + "rtos=%X\n", + &dest->addr.ip, &dest->dst_saddr.ip, atomic_read(&rt->dst.__refcnt), rtos); } daddr = dest->addr.ip; + if (ret_saddr) + *ret_saddr = dest->dst_saddr.ip; spin_unlock(&dest->dst_lock); } else { - rt = ip_route_output(net, daddr, 0, rtos, 0); + struct flowi4 fl4; + + memset(&fl4, 0, sizeof(fl4)); + fl4.daddr = daddr; + fl4.flowi4_tos = rtos; + rt = ip_route_output_key(net, &fl4); if (IS_ERR(rt)) { IP_VS_DBG_RL("ip_route_output error, dest: %pI4\n", &daddr); return NULL; } + if (ret_saddr) + *ret_saddr = fl4.saddr; } local = rt->rt_flags & RTCF_LOCAL; @@ -249,7 +265,7 @@ __ip_vs_get_out_rt_v6(struct sk_buff *skb, struct ip_vs_dest *dest, u32 cookie; dst = __ip_vs_route_output_v6(net, &dest->addr.in6, - &dest->dst_saddr, + &dest->dst_saddr.in6, do_xfrm); if (!dst) { spin_unlock(&dest->dst_lock); @@ -259,11 +275,11 @@ __ip_vs_get_out_rt_v6(struct sk_buff *skb, struct ip_vs_dest *dest, cookie = rt->rt6i_node ? rt->rt6i_node->fn_sernum : 0; __ip_vs_dst_set(dest, 0, dst_clone(&rt->dst), cookie); IP_VS_DBG(10, "new dst %pI6, src %pI6, refcnt=%d\n", - &dest->addr.in6, &dest->dst_saddr, + &dest->addr.in6, &dest->dst_saddr.in6, atomic_read(&rt->dst.__refcnt)); } if (ret_saddr) - ipv6_addr_copy(ret_saddr, &dest->dst_saddr); + ipv6_addr_copy(ret_saddr, &dest->dst_saddr.in6); spin_unlock(&dest->dst_lock); } else { dst = __ip_vs_route_output_v6(net, daddr, ret_saddr, do_xfrm); @@ -386,7 +402,7 @@ ip_vs_bypass_xmit(struct sk_buff *skb, struct ip_vs_conn *cp, EnterFunction(10); if (!(rt = __ip_vs_get_out_rt(skb, NULL, iph->daddr, RT_TOS(iph->tos), - IP_VS_RT_MODE_NON_LOCAL))) + IP_VS_RT_MODE_NON_LOCAL, NULL))) goto tx_error_icmp; /* MTU checking */ @@ -518,7 +534,7 @@ ip_vs_nat_xmit(struct sk_buff *skb, struct ip_vs_conn *cp, RT_TOS(iph->tos), IP_VS_RT_MODE_LOCAL | IP_VS_RT_MODE_NON_LOCAL | - IP_VS_RT_MODE_RDR))) + IP_VS_RT_MODE_RDR, NULL))) goto tx_error_icmp; local = rt->rt_flags & RTCF_LOCAL; /* @@ -540,7 +556,7 @@ ip_vs_nat_xmit(struct sk_buff *skb, struct ip_vs_conn *cp, #endif /* From world but DNAT to loopback address? */ - if (local && ipv4_is_loopback(rt->rt_dst) && + if (local && ipv4_is_loopback(cp->daddr.ip) && rt_is_input_route(skb_rtable(skb))) { IP_VS_DBG_RL_PKT(1, AF_INET, pp, skb, 0, "ip_vs_nat_xmit(): " "stopping DNAT to loopback address"); @@ -751,6 +767,7 @@ ip_vs_tunnel_xmit(struct sk_buff *skb, struct ip_vs_conn *cp, struct ip_vs_protocol *pp) { struct rtable *rt; /* Route to the other host */ + __be32 saddr; /* Source for tunnel */ struct net_device *tdev; /* Device to other host */ struct iphdr *old_iph = ip_hdr(skb); u8 tos = old_iph->tos; @@ -764,7 +781,8 @@ ip_vs_tunnel_xmit(struct sk_buff *skb, struct ip_vs_conn *cp, if (!(rt = __ip_vs_get_out_rt(skb, cp->dest, cp->daddr.ip, RT_TOS(tos), IP_VS_RT_MODE_LOCAL | - IP_VS_RT_MODE_NON_LOCAL))) + IP_VS_RT_MODE_NON_LOCAL, + &saddr))) goto tx_error_icmp; if (rt->rt_flags & RTCF_LOCAL) { ip_rt_put(rt); @@ -832,8 +850,8 @@ ip_vs_tunnel_xmit(struct sk_buff *skb, struct ip_vs_conn *cp, iph->frag_off = df; iph->protocol = IPPROTO_IPIP; iph->tos = tos; - iph->daddr = rt->rt_dst; - iph->saddr = rt->rt_src; + iph->daddr = cp->daddr.ip; + iph->saddr = saddr; iph->ttl = old_iph->ttl; ip_select_ident(iph, &rt->dst, NULL); @@ -996,7 +1014,7 @@ ip_vs_dr_xmit(struct sk_buff *skb, struct ip_vs_conn *cp, if (!(rt = __ip_vs_get_out_rt(skb, cp->dest, cp->daddr.ip, RT_TOS(iph->tos), IP_VS_RT_MODE_LOCAL | - IP_VS_RT_MODE_NON_LOCAL))) + IP_VS_RT_MODE_NON_LOCAL, NULL))) goto tx_error_icmp; if (rt->rt_flags & RTCF_LOCAL) { ip_rt_put(rt); @@ -1114,12 +1132,13 @@ tx_error: */ int ip_vs_icmp_xmit(struct sk_buff *skb, struct ip_vs_conn *cp, - struct ip_vs_protocol *pp, int offset) + struct ip_vs_protocol *pp, int offset, unsigned int hooknum) { struct rtable *rt; /* Route to the other host */ int mtu; int rc; int local; + int rt_mode; EnterFunction(10); @@ -1140,11 +1159,13 @@ ip_vs_icmp_xmit(struct sk_buff *skb, struct ip_vs_conn *cp, * mangle and send the packet here (only for VS/NAT) */ + /* LOCALNODE from FORWARD hook is not supported */ + rt_mode = (hooknum != NF_INET_FORWARD) ? + IP_VS_RT_MODE_LOCAL | IP_VS_RT_MODE_NON_LOCAL | + IP_VS_RT_MODE_RDR : IP_VS_RT_MODE_NON_LOCAL; if (!(rt = __ip_vs_get_out_rt(skb, cp->dest, cp->daddr.ip, RT_TOS(ip_hdr(skb)->tos), - IP_VS_RT_MODE_LOCAL | - IP_VS_RT_MODE_NON_LOCAL | - IP_VS_RT_MODE_RDR))) + rt_mode, NULL))) goto tx_error_icmp; local = rt->rt_flags & RTCF_LOCAL; @@ -1167,7 +1188,7 @@ ip_vs_icmp_xmit(struct sk_buff *skb, struct ip_vs_conn *cp, #endif /* From world but DNAT to loopback address? */ - if (local && ipv4_is_loopback(rt->rt_dst) && + if (local && ipv4_is_loopback(cp->daddr.ip) && rt_is_input_route(skb_rtable(skb))) { IP_VS_DBG(1, "%s(): " "stopping DNAT to loopback %pI4\n", @@ -1232,12 +1253,13 @@ ip_vs_icmp_xmit(struct sk_buff *skb, struct ip_vs_conn *cp, #ifdef CONFIG_IP_VS_IPV6 int ip_vs_icmp_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp, - struct ip_vs_protocol *pp, int offset) + struct ip_vs_protocol *pp, int offset, unsigned int hooknum) { struct rt6_info *rt; /* Route to the other host */ int mtu; int rc; int local; + int rt_mode; EnterFunction(10); @@ -1258,10 +1280,12 @@ ip_vs_icmp_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp, * mangle and send the packet here (only for VS/NAT) */ + /* LOCALNODE from FORWARD hook is not supported */ + rt_mode = (hooknum != NF_INET_FORWARD) ? + IP_VS_RT_MODE_LOCAL | IP_VS_RT_MODE_NON_LOCAL | + IP_VS_RT_MODE_RDR : IP_VS_RT_MODE_NON_LOCAL; if (!(rt = __ip_vs_get_out_rt_v6(skb, cp->dest, &cp->daddr.in6, NULL, - 0, (IP_VS_RT_MODE_LOCAL | - IP_VS_RT_MODE_NON_LOCAL | - IP_VS_RT_MODE_RDR)))) + 0, rt_mode))) goto tx_error_icmp; local = __ip_vs_is_local_route6(rt); -- cgit v0.10.2 From 6c60408e33aba6d1d7241bc9be3b8d1b39509291 Mon Sep 17 00:00:00 2001 From: Alexey Orishko Date: Fri, 6 May 2011 03:01:30 +0000 Subject: CDC NCM: Add mising short packet in cdc_ncm driver Changes: - while making NTB, driver shall check if device dwNtbOutMaxSize is higher than host value and shall add a short packet if this is the case - previous temporary patch for this issue is replaced by this one Signed-off-by: Alexey Orishko Signed-off-by: David S. Miller diff --git a/drivers/net/usb/cdc_ncm.c b/drivers/net/usb/cdc_ncm.c index 1033ef6..4ab557d 100644 --- a/drivers/net/usb/cdc_ncm.c +++ b/drivers/net/usb/cdc_ncm.c @@ -54,13 +54,13 @@ #include #include -#define DRIVER_VERSION "23-Apr-2011" +#define DRIVER_VERSION "06-May-2011" /* CDC NCM subclass 3.2.1 */ #define USB_CDC_NCM_NDP16_LENGTH_MIN 0x10 /* Maximum NTB length */ -#define CDC_NCM_NTB_MAX_SIZE_TX (16384 + 4) /* bytes, must be short terminated */ +#define CDC_NCM_NTB_MAX_SIZE_TX 16384 /* bytes */ #define CDC_NCM_NTB_MAX_SIZE_RX 16384 /* bytes */ /* Minimum value for MaxDatagramSize, ch. 6.2.9 */ @@ -722,7 +722,7 @@ cdc_ncm_fill_tx_frame(struct cdc_ncm_ctx *ctx, struct sk_buff *skb) } else { /* reset variables */ - skb_out = alloc_skb(ctx->tx_max, GFP_ATOMIC); + skb_out = alloc_skb((ctx->tx_max + 1), GFP_ATOMIC); if (skb_out == NULL) { if (skb != NULL) { dev_kfree_skb_any(skb); @@ -861,8 +861,11 @@ cdc_ncm_fill_tx_frame(struct cdc_ncm_ctx *ctx, struct sk_buff *skb) /* store last offset */ last_offset = offset; - if ((last_offset < ctx->tx_max) && ((last_offset % - le16_to_cpu(ctx->out_ep->desc.wMaxPacketSize)) == 0)) { + if (((last_offset < ctx->tx_max) && ((last_offset % + le16_to_cpu(ctx->out_ep->desc.wMaxPacketSize)) == 0)) || + (((last_offset == ctx->tx_max) && ((ctx->tx_max % + le16_to_cpu(ctx->out_ep->desc.wMaxPacketSize)) == 0)) && + (ctx->tx_max < le32_to_cpu(ctx->ncm_parm.dwNtbOutMaxSize)))) { /* force short packet */ *(((u8 *)skb_out->data) + last_offset) = 0; last_offset++; -- cgit v0.10.2 From afe12cc86b0ba545a01ad8716539ab07ab6e9e89 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Miros=C5=82aw?= Date: Sat, 7 May 2011 03:22:17 +0000 Subject: net: introduce netdev_change_features() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It will be needed by bonding and other drivers changing vlan_features after ndo_init callback. As a bonus, this includes kernel-doc for netdev_update_features(). Signed-off-by: MichaÅ‚ MirosÅ‚aw Signed-off-by: David S. Miller diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index 00d650c..1d9696a 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -2565,6 +2565,7 @@ u32 netdev_increment_features(u32 all, u32 one, u32 mask); u32 netdev_fix_features(struct net_device *dev, u32 features); int __netdev_update_features(struct net_device *dev); void netdev_update_features(struct net_device *dev); +void netdev_change_features(struct net_device *dev); void netif_stacked_transfer_operstate(const struct net_device *rootdev, struct net_device *dev); diff --git a/net/core/dev.c b/net/core/dev.c index 75898a3..ea23353 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -5289,6 +5289,14 @@ int __netdev_update_features(struct net_device *dev) return 1; } +/** + * netdev_update_features - recalculate device features + * @dev: the device to check + * + * Recalculate dev->features set and send notifications if it + * has changed. Should be called after driver or hardware dependent + * conditions might have changed that influence the features. + */ void netdev_update_features(struct net_device *dev) { if (__netdev_update_features(dev)) @@ -5297,6 +5305,23 @@ void netdev_update_features(struct net_device *dev) EXPORT_SYMBOL(netdev_update_features); /** + * netdev_change_features - recalculate device features + * @dev: the device to check + * + * Recalculate dev->features set and send notifications even + * if they have not changed. Should be called instead of + * netdev_update_features() if also dev->vlan_features might + * have changed to allow the changes to be propagated to stacked + * VLAN devices. + */ +void netdev_change_features(struct net_device *dev) +{ + __netdev_update_features(dev); + netdev_features_change(dev); +} +EXPORT_SYMBOL(netdev_change_features); + +/** * netif_stacked_transfer_operstate - transfer operstate * @rootdev: the root or lower level device to transfer state from * @dev: the device to transfer operstate to -- cgit v0.10.2 From b2a103e6d0afa432dff66b36473c5a55b6b0376c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Miros=C5=82aw?= Date: Sat, 7 May 2011 03:22:17 +0000 Subject: bonding: convert to ndo_fix_features MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This should also fix updating of vlan_features and propagating changes to VLAN devices on the bond. Side effect: it allows user to force-disable some offloads on the bond interface. Note: NETIF_F_VLAN_CHALLENGED is managed by bond_fix_features() now. Signed-off-by: MichaÅ‚ MirosÅ‚aw Signed-off-by: David S. Miller diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index 6312db1..088fd84 100644 --- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c @@ -344,32 +344,6 @@ out: } /** - * bond_has_challenged_slaves - * @bond: the bond we're working on - * - * Searches the slave list. Returns 1 if a vlan challenged slave - * was found, 0 otherwise. - * - * Assumes bond->lock is held. - */ -static int bond_has_challenged_slaves(struct bonding *bond) -{ - struct slave *slave; - int i; - - bond_for_each_slave(bond, slave, i) { - if (slave->dev->features & NETIF_F_VLAN_CHALLENGED) { - pr_debug("found VLAN challenged slave - %s\n", - slave->dev->name); - return 1; - } - } - - pr_debug("no VLAN challenged slaves found\n"); - return 0; -} - -/** * bond_next_vlan - safely skip to the next item in the vlans list. * @bond: the bond we're working on * @curr: item we're advancing from @@ -1406,52 +1380,68 @@ static int bond_sethwaddr(struct net_device *bond_dev, return 0; } -#define BOND_VLAN_FEATURES \ - (NETIF_F_VLAN_CHALLENGED | NETIF_F_HW_VLAN_RX | NETIF_F_HW_VLAN_TX | \ - NETIF_F_HW_VLAN_FILTER) - -/* - * Compute the common dev->feature set available to all slaves. Some - * feature bits are managed elsewhere, so preserve those feature bits - * on the master device. - */ -static int bond_compute_features(struct bonding *bond) +static u32 bond_fix_features(struct net_device *dev, u32 features) { struct slave *slave; - struct net_device *bond_dev = bond->dev; - u32 features = bond_dev->features; - u32 vlan_features = 0; - unsigned short max_hard_header_len = max((u16)ETH_HLEN, - bond_dev->hard_header_len); + struct bonding *bond = netdev_priv(dev); + u32 mask; int i; - features &= ~(NETIF_F_ALL_CSUM | BOND_VLAN_FEATURES); - features |= NETIF_F_GSO_MASK | NETIF_F_NO_CSUM | NETIF_F_NOCACHE_COPY; + read_lock(&bond->lock); - if (!bond->first_slave) - goto done; + if (!bond->first_slave) { + /* Disable adding VLANs to empty bond. But why? --mq */ + features |= NETIF_F_VLAN_CHALLENGED; + goto out; + } + mask = features; features &= ~NETIF_F_ONE_FOR_ALL; + features |= NETIF_F_ALL_FOR_ALL; - vlan_features = bond->first_slave->dev->vlan_features; bond_for_each_slave(bond, slave, i) { features = netdev_increment_features(features, slave->dev->features, - NETIF_F_ONE_FOR_ALL); + mask); + } + +out: + read_unlock(&bond->lock); + return features; +} + +#define BOND_VLAN_FEATURES (NETIF_F_ALL_TX_OFFLOADS | \ + NETIF_F_SOFT_FEATURES | \ + NETIF_F_LRO) + +static void bond_compute_features(struct bonding *bond) +{ + struct slave *slave; + struct net_device *bond_dev = bond->dev; + u32 vlan_features = BOND_VLAN_FEATURES; + unsigned short max_hard_header_len = ETH_HLEN; + int i; + + read_lock(&bond->lock); + + if (!bond->first_slave) + goto done; + + bond_for_each_slave(bond, slave, i) { vlan_features = netdev_increment_features(vlan_features, - slave->dev->vlan_features, - NETIF_F_ONE_FOR_ALL); + slave->dev->vlan_features, BOND_VLAN_FEATURES); + if (slave->dev->hard_header_len > max_hard_header_len) max_hard_header_len = slave->dev->hard_header_len; } done: - features |= (bond_dev->features & BOND_VLAN_FEATURES); - bond_dev->features = netdev_fix_features(bond_dev, features); - bond_dev->vlan_features = netdev_fix_features(bond_dev, vlan_features); + bond_dev->vlan_features = vlan_features; bond_dev->hard_header_len = max_hard_header_len; - return 0; + read_unlock(&bond->lock); + + netdev_change_features(bond_dev); } static void bond_setup_by_slave(struct net_device *bond_dev, @@ -1544,7 +1534,6 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev) struct netdev_hw_addr *ha; struct sockaddr addr; int link_reporting; - int old_features = bond_dev->features; int res = 0; if (!bond->params.use_carrier && slave_dev->ethtool_ops == NULL && @@ -1577,16 +1566,9 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev) pr_warning("%s: Warning: enslaved VLAN challenged slave %s. Adding VLANs will be blocked as long as %s is part of bond %s\n", bond_dev->name, slave_dev->name, slave_dev->name, bond_dev->name); - bond_dev->features |= NETIF_F_VLAN_CHALLENGED; } } else { pr_debug("%s: ! NETIF_F_VLAN_CHALLENGED\n", slave_dev->name); - if (bond->slave_cnt == 0) { - /* First slave, and it is not VLAN challenged, - * so remove the block of adding VLANs over the bond. - */ - bond_dev->features &= ~NETIF_F_VLAN_CHALLENGED; - } } /* @@ -1775,10 +1757,10 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev) new_slave->delay = 0; new_slave->link_failure_count = 0; - bond_compute_features(bond); - write_unlock_bh(&bond->lock); + bond_compute_features(bond); + read_lock(&bond->lock); new_slave->last_arp_rx = jiffies; @@ -1958,7 +1940,7 @@ err_free: kfree(new_slave); err_undo_flags: - bond_dev->features = old_features; + bond_compute_features(bond); return res; } @@ -1979,6 +1961,7 @@ int bond_release(struct net_device *bond_dev, struct net_device *slave_dev) struct bonding *bond = netdev_priv(bond_dev); struct slave *slave, *oldcurrent; struct sockaddr addr; + u32 old_features = bond_dev->features; /* slave is not a slave or master is not master of this slave */ if (!(slave_dev->flags & IFF_SLAVE) || @@ -2039,8 +2022,6 @@ int bond_release(struct net_device *bond_dev, struct net_device *slave_dev) /* release the slave from its bond */ bond_detach_slave(bond, slave); - bond_compute_features(bond); - if (bond->primary_slave == slave) bond->primary_slave = NULL; @@ -2084,24 +2065,23 @@ int bond_release(struct net_device *bond_dev, struct net_device *slave_dev) */ memset(bond_dev->dev_addr, 0, bond_dev->addr_len); - if (!bond->vlgrp) { - bond_dev->features |= NETIF_F_VLAN_CHALLENGED; - } else { + if (bond->vlgrp) { pr_warning("%s: Warning: clearing HW address of %s while it still has VLANs.\n", bond_dev->name, bond_dev->name); pr_warning("%s: When re-adding slaves, make sure the bond's HW address matches its VLANs'.\n", bond_dev->name); } - } else if ((bond_dev->features & NETIF_F_VLAN_CHALLENGED) && - !bond_has_challenged_slaves(bond)) { - pr_info("%s: last VLAN challenged slave %s left bond %s. VLAN blocking is removed\n", - bond_dev->name, slave_dev->name, bond_dev->name); - bond_dev->features &= ~NETIF_F_VLAN_CHALLENGED; } write_unlock_bh(&bond->lock); unblock_netpoll_tx(); + bond_compute_features(bond); + if (!(bond_dev->features & NETIF_F_VLAN_CHALLENGED) && + (old_features & NETIF_F_VLAN_CHALLENGED)) + pr_info("%s: last VLAN challenged slave %s left bond %s. VLAN blocking is removed\n", + bond_dev->name, slave_dev->name, bond_dev->name); + /* must do this from outside any spinlocks */ bond_destroy_slave_symlinks(bond_dev, slave_dev); @@ -2219,8 +2199,6 @@ static int bond_release_all(struct net_device *bond_dev) bond_alb_deinit_slave(bond, slave); } - bond_compute_features(bond); - bond_destroy_slave_symlinks(bond_dev, slave_dev); bond_del_vlans_from_slave(bond, slave_dev); @@ -2269,9 +2247,7 @@ static int bond_release_all(struct net_device *bond_dev) */ memset(bond_dev->dev_addr, 0, bond_dev->addr_len); - if (!bond->vlgrp) { - bond_dev->features |= NETIF_F_VLAN_CHALLENGED; - } else { + if (bond->vlgrp) { pr_warning("%s: Warning: clearing HW address of %s while it still has VLANs.\n", bond_dev->name, bond_dev->name); pr_warning("%s: When re-adding slaves, make sure the bond's HW address matches its VLANs'.\n", @@ -2282,6 +2258,9 @@ static int bond_release_all(struct net_device *bond_dev) out: write_unlock_bh(&bond->lock); + + bond_compute_features(bond); + return 0; } @@ -4337,11 +4316,6 @@ static void bond_ethtool_get_drvinfo(struct net_device *bond_dev, static const struct ethtool_ops bond_ethtool_ops = { .get_drvinfo = bond_ethtool_get_drvinfo, .get_link = ethtool_op_get_link, - .get_tx_csum = ethtool_op_get_tx_csum, - .get_sg = ethtool_op_get_sg, - .get_tso = ethtool_op_get_tso, - .get_ufo = ethtool_op_get_ufo, - .get_flags = ethtool_op_get_flags, }; static const struct net_device_ops bond_netdev_ops = { @@ -4367,6 +4341,7 @@ static const struct net_device_ops bond_netdev_ops = { #endif .ndo_add_slave = bond_enslave, .ndo_del_slave = bond_release, + .ndo_fix_features = bond_fix_features, }; static void bond_destructor(struct net_device *bond_dev) @@ -4422,14 +4397,14 @@ static void bond_setup(struct net_device *bond_dev) * when there are slaves that are not hw accel * capable */ - bond_dev->features |= (NETIF_F_HW_VLAN_TX | - NETIF_F_HW_VLAN_RX | - NETIF_F_HW_VLAN_FILTER); - /* By default, we enable GRO on bonding devices. - * Actual support requires lowlevel drivers are GRO ready. - */ - bond_dev->features |= NETIF_F_GRO; + bond_dev->hw_features = BOND_VLAN_FEATURES | + NETIF_F_HW_VLAN_TX | + NETIF_F_HW_VLAN_RX | + NETIF_F_HW_VLAN_FILTER; + + bond_dev->hw_features &= ~(NETIF_F_ALL_CSUM & ~NETIF_F_NO_CSUM); + bond_dev->features |= bond_dev->hw_features; } static void bond_work_cancel_all(struct bonding *bond) -- cgit v0.10.2 From ca06707022d6ba4744198a8ebbe4994786b0c613 Mon Sep 17 00:00:00 2001 From: "Steinar H. Gunderson" Date: Fri, 6 May 2011 23:44:46 +0000 Subject: ipv6: restore correct ECN handling on TCP xmit Since commit e9df2e8fd8fbc9 (Use appropriate sock tclass setting for routing lookup) we lost ability to properly add ECN codemarks to ipv6 TCP frames. It seems like TCP_ECN_send() calls INET_ECN_xmit(), which only sets the ECN bit in the IPv4 ToS field (inet_sk(sk)->tos), but after the patch, what's checked is inet6_sk(sk)->tclass, which is a completely different field. Close bug https://bugzilla.kernel.org/show_bug.cgi?id=34322 [Eric Dumazet] : added the INET_ECN_dontxmit() fix and replace macros by inline functions for clarity. Signed-off-by: Steinar H. Gunderson Signed-off-by: Eric Dumazet Cc: YOSHIFUJI Hideaki Cc: Andrew Morton Signed-off-by: David S. Miller diff --git a/include/net/inet_ecn.h b/include/net/inet_ecn.h index 88bdd01..2fa8d13 100644 --- a/include/net/inet_ecn.h +++ b/include/net/inet_ecn.h @@ -38,9 +38,19 @@ static inline __u8 INET_ECN_encapsulate(__u8 outer, __u8 inner) return outer; } -#define INET_ECN_xmit(sk) do { inet_sk(sk)->tos |= INET_ECN_ECT_0; } while (0) -#define INET_ECN_dontxmit(sk) \ - do { inet_sk(sk)->tos &= ~INET_ECN_MASK; } while (0) +static inline void INET_ECN_xmit(struct sock *sk) +{ + inet_sk(sk)->tos |= INET_ECN_ECT_0; + if (inet6_sk(sk) != NULL) + inet6_sk(sk)->tclass |= INET_ECN_ECT_0; +} + +static inline void INET_ECN_dontxmit(struct sock *sk) +{ + inet_sk(sk)->tos &= ~INET_ECN_MASK; + if (inet6_sk(sk) != NULL) + inet6_sk(sk)->tclass &= ~INET_ECN_MASK; +} #define IP6_ECN_flow_init(label) do { \ (label) &= ~htonl(INET_ECN_MASK << 20); \ -- cgit v0.10.2 From 9ddabb055d73c63037878bb9346e52c7f2e07e96 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Fri, 29 Apr 2011 15:30:02 +0200 Subject: i2c: pnx: Fix crash due to wrong init of timer->data alg_data is already a pointer which must be passed directly. Reported-by: Dieter Ripp Signed-off-by: Wolfram Sang Cc: Russell King Cc: Ben Dooks Signed-off-by: Ben Dooks diff --git a/drivers/i2c/busses/i2c-pnx.c b/drivers/i2c/busses/i2c-pnx.c index a97e3fe..04be9f8 100644 --- a/drivers/i2c/busses/i2c-pnx.c +++ b/drivers/i2c/busses/i2c-pnx.c @@ -65,7 +65,7 @@ static inline void i2c_pnx_arm_timer(struct i2c_pnx_algo_data *alg_data) jiffies, expires); timer->expires = jiffies + expires; - timer->data = (unsigned long)&alg_data; + timer->data = (unsigned long)alg_data; add_timer(timer); } -- cgit v0.10.2 From 10949550bd1e50cc91c0f5085f7080a44b0871fe Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Thu, 12 May 2011 19:26:57 -0400 Subject: ipv4: Kill spurious opt->srr check in ip_options_rcv_srr(). All call sites conditionalize the call to ip_options_rcv_srr() with a check of opt->srr, so no need to check it again there. Signed-off-by: David S. Miller diff --git a/net/ipv4/ip_options.c b/net/ipv4/ip_options.c index 01fc409..e82c304 100644 --- a/net/ipv4/ip_options.c +++ b/net/ipv4/ip_options.c @@ -601,7 +601,7 @@ int ip_options_rcv_srr(struct sk_buff *skb) unsigned long orefdst; int err; - if (!opt->srr || !rt) + if (!rt) return 0; if (skb->pkt_type != PACKET_HOST) -- cgit v0.10.2 From c30883bdff0b3544900a5c4aba18b8985436878f Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Thu, 12 May 2011 19:30:58 -0400 Subject: ipv4: Simplify iph->daddr overwrite in ip_options_rcv_srr(). We already copy the 4-byte nexthop from the options block into local variable "nexthop" for the route lookup. Re-use that variable instead of memcpy()'ing again when assigning to iph->daddr after the route lookup succeeds. Signed-off-by: David S. Miller diff --git a/net/ipv4/ip_options.c b/net/ipv4/ip_options.c index e82c304..c5c2619 100644 --- a/net/ipv4/ip_options.c +++ b/net/ipv4/ip_options.c @@ -635,7 +635,7 @@ int ip_options_rcv_srr(struct sk_buff *skb) if (rt2->rt_type != RTN_LOCAL) break; /* Superfast 8) loopback forward */ - memcpy(&iph->daddr, &optptr[srrptr-1], 4); + iph->daddr = nexthop; opt->is_changed = 1; } if (srrptr <= srrspace) { -- cgit v0.10.2 From def57687e9579b7a797681990dff763c411f5347 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Thu, 12 May 2011 19:34:30 -0400 Subject: ipv4: Elide use of rt->rt_dst in ip_forward() No matter what kind of header mangling occurs due to IP options processing, rt->rt_dst will always equal iph->daddr in the packet. So we can safely use iph->daddr instead of rt->rt_dst here. Signed-off-by: David S. Miller diff --git a/net/ipv4/ip_forward.c b/net/ipv4/ip_forward.c index 99461f0..fcbc0c8 100644 --- a/net/ipv4/ip_forward.c +++ b/net/ipv4/ip_forward.c @@ -84,7 +84,7 @@ int ip_forward(struct sk_buff *skb) rt = skb_rtable(skb); - if (opt->is_strictroute && rt->rt_dst != rt->rt_gateway) + if (opt->is_strictroute && iph->daddr != rt->rt_gateway) goto sr_failed; if (unlikely(skb->len > dst_mtu(&rt->dst) && !skb_is_gso(skb) && -- cgit v0.10.2 From 72a8f97bf2dfe1b0f02ba8dbaed7d6b76657aae3 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Thu, 12 May 2011 23:03:46 -0400 Subject: ipv4: Fix 'iph' use before set. I swear none of my compilers warned about this, yet it is so obvious. > net/ipv4/ip_forward.c: In function 'ip_forward': > net/ipv4/ip_forward.c:87: warning: 'iph' may be used uninitialized in this function Reported-by: Stephen Rothwell Signed-off-by: David S. Miller diff --git a/net/ipv4/ip_forward.c b/net/ipv4/ip_forward.c index fcbc0c8..3b34d1c 100644 --- a/net/ipv4/ip_forward.c +++ b/net/ipv4/ip_forward.c @@ -84,7 +84,7 @@ int ip_forward(struct sk_buff *skb) rt = skb_rtable(skb); - if (opt->is_strictroute && iph->daddr != rt->rt_gateway) + if (opt->is_strictroute && ip_hdr(skb)->daddr != rt->rt_gateway) goto sr_failed; if (unlikely(skb->len > dst_mtu(&rt->dst) && !skb_is_gso(skb) && -- cgit v0.10.2 From 11f770027b5c0de16544f3ec82b5c6f9f8d5a644 Mon Sep 17 00:00:00 2001 From: Sage Weil Date: Thu, 12 May 2011 16:13:54 -0700 Subject: rbd: fix leak of ops struct The ops vector must be freed by the rbd_do_request caller. Signed-off-by: Sage Weil diff --git a/drivers/block/rbd.c b/drivers/block/rbd.c index 3e90471..2146cab 100644 --- a/drivers/block/rbd.c +++ b/drivers/block/rbd.c @@ -996,6 +996,8 @@ static int rbd_do_op(struct request *rq, ops, num_reply, rbd_req_cb, 0, NULL); + + rbd_destroy_ops(ops); done: kfree(seg_name); return ret; @@ -1063,7 +1065,9 @@ static int rbd_req_sync_notify_ack(struct rbd_device *dev, { struct ceph_osd_req_op *ops; struct page **pages = NULL; - int ret = rbd_create_rw_ops(&ops, 1, CEPH_OSD_OP_NOTIFY_ACK, 0); + int ret; + + ret = rbd_create_rw_ops(&ops, 1, CEPH_OSD_OP_NOTIFY_ACK, 0); if (ret < 0) return ret; -- cgit v0.10.2 From d9282fca8a763be574a2fc20b2edcc6e132cbf90 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Wed, 11 May 2011 03:15:24 -0400 Subject: drm/radeon/kms: fix tiling reg on fusion The location of MC_ARB_RAMCFG changed on fusion. I've diffed all the other regs in evergreend.h and this is the only other reg that changed. Signed-off-by: Alex Deucher Signed-off-by: Dave Airlie diff --git a/drivers/gpu/drm/radeon/evergreen.c b/drivers/gpu/drm/radeon/evergreen.c index c20eac3..9073e3b 100644 --- a/drivers/gpu/drm/radeon/evergreen.c +++ b/drivers/gpu/drm/radeon/evergreen.c @@ -1780,7 +1780,10 @@ static void evergreen_gpu_init(struct radeon_device *rdev) mc_shared_chmap = RREG32(MC_SHARED_CHMAP); - mc_arb_ramcfg = RREG32(MC_ARB_RAMCFG); + if (rdev->flags & RADEON_IS_IGP) + mc_arb_ramcfg = RREG32(FUS_MC_ARB_RAMCFG); + else + mc_arb_ramcfg = RREG32(MC_ARB_RAMCFG); switch (rdev->config.evergreen.max_tile_pipes) { case 1: diff --git a/drivers/gpu/drm/radeon/evergreend.h b/drivers/gpu/drm/radeon/evergreend.h index 9453384..fc40e0c 100644 --- a/drivers/gpu/drm/radeon/evergreend.h +++ b/drivers/gpu/drm/radeon/evergreend.h @@ -200,6 +200,7 @@ #define BURSTLENGTH_SHIFT 9 #define BURSTLENGTH_MASK 0x00000200 #define CHANSIZE_OVERRIDE (1 << 11) +#define FUS_MC_ARB_RAMCFG 0x2768 #define MC_VM_AGP_TOP 0x2028 #define MC_VM_AGP_BOT 0x202C #define MC_VM_AGP_BASE 0x2030 -- cgit v0.10.2 From 05fa7ea7d23980de0014417a0e0af2048a0f9fc1 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Wed, 11 May 2011 14:02:07 -0400 Subject: drm/radeon/kms: fix extended lvds info parsing On rev <= 1.1 tables, the offset is absolute, on newer tables, it's relative. Fixes: https://bugzilla.redhat.com/show_bug.cgi?id=700326 Signed-off-by: Alex Deucher Reviewed-by: Jerome Glisse Cc: stable@kernel.org Signed-off-by: Dave Airlie diff --git a/drivers/gpu/drm/radeon/radeon_atombios.c b/drivers/gpu/drm/radeon/radeon_atombios.c index dd881d0..90dfb2b 100644 --- a/drivers/gpu/drm/radeon/radeon_atombios.c +++ b/drivers/gpu/drm/radeon/radeon_atombios.c @@ -1574,9 +1574,17 @@ struct radeon_encoder_atom_dig *radeon_atombios_get_lvds_info(struct ATOM_FAKE_EDID_PATCH_RECORD *fake_edid_record; ATOM_PANEL_RESOLUTION_PATCH_RECORD *panel_res_record; bool bad_record = false; - u8 *record = (u8 *)(mode_info->atom_context->bios + - data_offset + - le16_to_cpu(lvds_info->info.usModePatchTableOffset)); + u8 *record; + + if ((frev == 1) && (crev < 2)) + /* absolute */ + record = (u8 *)(mode_info->atom_context->bios + + le16_to_cpu(lvds_info->info.usModePatchTableOffset)); + else + /* relative */ + record = (u8 *)(mode_info->atom_context->bios + + data_offset + + le16_to_cpu(lvds_info->info.usModePatchTableOffset)); while (*record != ATOM_RECORD_END_TYPE) { switch (*record) { case LCD_MODE_PATCH_RECORD_MODE_TYPE: -- cgit v0.10.2 From 3a8ab79eae4500e6ac618a92a90cee63d6e804a8 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Thu, 12 May 2011 21:15:15 -0400 Subject: drm/radeon/kms: add some evergreen/ni safe regs need to programmed from the userspace drivers. Signed-off-by: Alex Deucher Signed-off-by: Dave Airlie diff --git a/drivers/gpu/drm/radeon/reg_srcs/cayman b/drivers/gpu/drm/radeon/reg_srcs/cayman index 6334f8a..0aa8e85 100644 --- a/drivers/gpu/drm/radeon/reg_srcs/cayman +++ b/drivers/gpu/drm/radeon/reg_srcs/cayman @@ -33,6 +33,7 @@ cayman 0x9400 0x00008E48 SQ_EX_ALLOC_TABLE_SLOTS 0x00009100 SPI_CONFIG_CNTL 0x0000913C SPI_CONFIG_CNTL_1 +0x00009508 TA_CNTL_AUX 0x00009830 DB_DEBUG 0x00009834 DB_DEBUG2 0x00009838 DB_DEBUG3 diff --git a/drivers/gpu/drm/radeon/reg_srcs/evergreen b/drivers/gpu/drm/radeon/reg_srcs/evergreen index 7e16371..0e28cae 100644 --- a/drivers/gpu/drm/radeon/reg_srcs/evergreen +++ b/drivers/gpu/drm/radeon/reg_srcs/evergreen @@ -46,6 +46,7 @@ evergreen 0x9400 0x00008E48 SQ_EX_ALLOC_TABLE_SLOTS 0x00009100 SPI_CONFIG_CNTL 0x0000913C SPI_CONFIG_CNTL_1 +0x00009508 TA_CNTL_AUX 0x00009700 VC_CNTL 0x00009714 VC_ENHANCE 0x00009830 DB_DEBUG -- cgit v0.10.2 From e2d0a13bba051d7a9618b0952d91fac68175a71a Mon Sep 17 00:00:00 2001 From: Steven Whitehouse Date: Fri, 13 May 2011 09:55:55 +0100 Subject: GFS2: Clean up mkdir This moves the initialisation of the directory into the inode creation functions to avoid having to duplicate the lookup of the inode's buffer. Signed-off-by: Steven Whitehouse diff --git a/fs/gfs2/inode.c b/fs/gfs2/inode.c index a783a7a..4aee9dd 100644 --- a/fs/gfs2/inode.c +++ b/fs/gfs2/inode.c @@ -413,6 +413,22 @@ out: return error; } +static void gfs2_init_dir(struct buffer_head *dibh, const struct gfs2_inode *parent) +{ + struct gfs2_dinode *di = (struct gfs2_dinode *)dibh->b_data; + struct gfs2_dirent *dent = (struct gfs2_dirent *)(di+1); + + gfs2_qstr2dirent(&gfs2_qdot, GFS2_DIRENT_SIZE(gfs2_qdot.len), dent); + dent->de_inum = di->di_num; /* already GFS2 endian */ + dent->de_type = cpu_to_be16(DT_DIR); + + dent = (struct gfs2_dirent *)((char*)dent + GFS2_DIRENT_SIZE(1)); + gfs2_qstr2dirent(&gfs2_qdotdot, dibh->b_size - GFS2_DIRENT_SIZE(1) - sizeof(struct gfs2_dinode), dent); + gfs2_inum_out(parent, dent); + dent->de_type = cpu_to_be16(DT_DIR); + +} + /** * init_dinode - Fill in a new dinode structure * @dip: the directory this inode is being created in @@ -454,16 +470,6 @@ static void init_dinode(struct gfs2_inode *dip, struct gfs2_glock *gl, di->di_goal_meta = di->di_goal_data = cpu_to_be64(inum->no_addr); di->di_generation = cpu_to_be64(*generation); di->di_flags = 0; - - if (S_ISREG(mode)) { - if ((dip->i_diskflags & GFS2_DIF_INHERIT_JDATA) || - gfs2_tune_get(sdp, gt_new_files_jdata)) - di->di_flags |= cpu_to_be32(GFS2_DIF_JDATA); - } else if (S_ISDIR(mode)) { - di->di_flags |= cpu_to_be32(dip->i_diskflags & - GFS2_DIF_INHERIT_JDATA); - } - di->__pad1 = 0; di->di_payload_format = cpu_to_be32(S_ISDIR(mode) ? GFS2_FORMAT_DE : 0); di->di_height = 0; @@ -478,6 +484,19 @@ static void init_dinode(struct gfs2_inode *dip, struct gfs2_glock *gl, di->di_ctime_nsec = cpu_to_be32(tv.tv_nsec); memset(&di->di_reserved, 0, sizeof(di->di_reserved)); + if (S_ISREG(mode)) { + if ((dip->i_diskflags & GFS2_DIF_INHERIT_JDATA) || + gfs2_tune_get(sdp, gt_new_files_jdata)) + di->di_flags |= cpu_to_be32(GFS2_DIF_JDATA); + } else if (S_ISDIR(mode)) { + di->di_flags |= cpu_to_be32(dip->i_diskflags & + GFS2_DIF_INHERIT_JDATA); + di->di_flags |= cpu_to_be32(GFS2_DIF_JDATA); + di->di_size = cpu_to_be64(sdp->sd_sb.sb_bsize - sizeof(struct gfs2_dinode)); + di->di_entries = cpu_to_be32(2); + gfs2_init_dir(dibh, dip); + } + set_buffer_uptodate(dibh); *bhp = dibh; @@ -568,7 +587,9 @@ static int link_dinode(struct gfs2_inode *dip, const struct qstr *name, error = gfs2_meta_inode_buffer(ip, &dibh); if (error) goto fail_end_trans; - ip->i_inode.i_nlink = 1; + inc_nlink(&ip->i_inode); + if (S_ISDIR(ip->i_inode.i_mode)) + inc_nlink(&ip->i_inode); gfs2_trans_add_bh(ip->i_gl, dibh, 1); gfs2_dinode_out(ip, dibh->b_data); brelse(dibh); @@ -1178,12 +1199,10 @@ static int gfs2_symlink(struct inode *dir, struct dentry *dentry, static int gfs2_mkdir(struct inode *dir, struct dentry *dentry, int mode) { - struct gfs2_inode *dip = GFS2_I(dir), *ip; + struct gfs2_inode *dip = GFS2_I(dir); struct gfs2_sbd *sdp = GFS2_SB(dir); struct gfs2_holder ghs[2]; struct inode *inode; - struct buffer_head *dibh; - int error; gfs2_holder_init(dip->i_gl, 0, 0, ghs); @@ -1193,36 +1212,6 @@ static int gfs2_mkdir(struct inode *dir, struct dentry *dentry, int mode) return PTR_ERR(inode); } - ip = ghs[1].gh_gl->gl_object; - - ip->i_inode.i_nlink = 2; - i_size_write(inode, sdp->sd_sb.sb_bsize - sizeof(struct gfs2_dinode)); - ip->i_diskflags |= GFS2_DIF_JDATA; - ip->i_entries = 2; - - error = gfs2_meta_inode_buffer(ip, &dibh); - - if (!gfs2_assert_withdraw(sdp, !error)) { - struct gfs2_dinode *di = (struct gfs2_dinode *)dibh->b_data; - struct gfs2_dirent *dent = (struct gfs2_dirent *)(di+1); - - gfs2_trans_add_bh(ip->i_gl, dibh, 1); - gfs2_qstr2dirent(&gfs2_qdot, GFS2_DIRENT_SIZE(gfs2_qdot.len), dent); - dent->de_inum = di->di_num; /* already GFS2 endian */ - dent->de_type = cpu_to_be16(DT_DIR); - di->di_entries = cpu_to_be32(1); - - dent = (struct gfs2_dirent *)((char*)dent + GFS2_DIRENT_SIZE(1)); - gfs2_qstr2dirent(&gfs2_qdotdot, dibh->b_size - GFS2_DIRENT_SIZE(1) - sizeof(struct gfs2_dinode), dent); - - gfs2_inum_out(dip, dent); - dent->de_type = cpu_to_be16(DT_DIR); - - gfs2_dinode_out(ip, di); - - brelse(dibh); - } - gfs2_trans_end(sdp); if (dip->i_alloc->al_rgd) gfs2_inplace_release(dip); -- cgit v0.10.2 From 160b4026dc3e75c0693d0123eca805e88cd200b6 Mon Sep 17 00:00:00 2001 From: Steven Whitehouse Date: Fri, 13 May 2011 10:34:59 +0100 Subject: GFS2: Clean up symlink creation This moves the symlink specific parts of inode creation into the function where we initialise the rest of the dinode. As a result we have one less place where we need to look up the inode's buffer. Signed-off-by: Steven Whitehouse diff --git a/fs/gfs2/inode.c b/fs/gfs2/inode.c index 4aee9dd..c2a3d9c 100644 --- a/fs/gfs2/inode.c +++ b/fs/gfs2/inode.c @@ -443,7 +443,8 @@ static void gfs2_init_dir(struct buffer_head *dibh, const struct gfs2_inode *par static void init_dinode(struct gfs2_inode *dip, struct gfs2_glock *gl, const struct gfs2_inum_host *inum, unsigned int mode, unsigned int uid, unsigned int gid, - const u64 *generation, dev_t dev, struct buffer_head **bhp) + const u64 *generation, dev_t dev, const char *symname, + unsigned size, struct buffer_head **bhp) { struct gfs2_sbd *sdp = GFS2_SB(&dip->i_inode); struct gfs2_dinode *di; @@ -462,7 +463,7 @@ static void init_dinode(struct gfs2_inode *dip, struct gfs2_glock *gl, di->di_uid = cpu_to_be32(uid); di->di_gid = cpu_to_be32(gid); di->di_nlink = 0; - di->di_size = 0; + di->di_size = cpu_to_be64(size); di->di_blocks = cpu_to_be64(1); di->di_atime = di->di_mtime = di->di_ctime = cpu_to_be64(tv.tv_sec); di->di_major = cpu_to_be32(MAJOR(dev)); @@ -483,18 +484,24 @@ static void init_dinode(struct gfs2_inode *dip, struct gfs2_glock *gl, di->di_mtime_nsec = cpu_to_be32(tv.tv_nsec); di->di_ctime_nsec = cpu_to_be32(tv.tv_nsec); memset(&di->di_reserved, 0, sizeof(di->di_reserved)); - - if (S_ISREG(mode)) { + + switch(mode & S_IFMT) { + case S_IFREG: if ((dip->i_diskflags & GFS2_DIF_INHERIT_JDATA) || gfs2_tune_get(sdp, gt_new_files_jdata)) di->di_flags |= cpu_to_be32(GFS2_DIF_JDATA); - } else if (S_ISDIR(mode)) { + break; + case S_IFDIR: di->di_flags |= cpu_to_be32(dip->i_diskflags & GFS2_DIF_INHERIT_JDATA); di->di_flags |= cpu_to_be32(GFS2_DIF_JDATA); di->di_size = cpu_to_be64(sdp->sd_sb.sb_bsize - sizeof(struct gfs2_dinode)); di->di_entries = cpu_to_be32(2); gfs2_init_dir(dibh, dip); + break; + case S_IFLNK: + memcpy(dibh->b_data + sizeof(struct gfs2_dinode), symname, size); + break; } set_buffer_uptodate(dibh); @@ -504,7 +511,8 @@ static void init_dinode(struct gfs2_inode *dip, struct gfs2_glock *gl, static int make_dinode(struct gfs2_inode *dip, struct gfs2_glock *gl, unsigned int mode, const struct gfs2_inum_host *inum, - const u64 *generation, dev_t dev, struct buffer_head **bhp) + const u64 *generation, dev_t dev, const char *symname, + unsigned int size, struct buffer_head **bhp) { struct gfs2_sbd *sdp = GFS2_SB(&dip->i_inode); unsigned int uid, gid; @@ -526,7 +534,7 @@ static int make_dinode(struct gfs2_inode *dip, struct gfs2_glock *gl, if (error) goto out_quota; - init_dinode(dip, gl, inum, mode, uid, gid, generation, dev, bhp); + init_dinode(dip, gl, inum, mode, uid, gid, generation, dev, symname, size, bhp); gfs2_quota_change(dip, +1, uid, gid); gfs2_trans_end(sdp); @@ -651,8 +659,10 @@ static int gfs2_security_init(struct gfs2_inode *dip, struct gfs2_inode *ip, * Returns: An inode */ -struct inode *gfs2_createi(struct gfs2_holder *ghs, const struct qstr *name, - unsigned int mode, dev_t dev) +static struct inode *gfs2_createi(struct gfs2_holder *ghs, + const struct qstr *name, unsigned int mode, + dev_t dev, const char *symname, + unsigned int size) { struct inode *inode = NULL; struct gfs2_inode *dip = ghs->gh_gl->gl_object; @@ -685,7 +695,7 @@ struct inode *gfs2_createi(struct gfs2_holder *ghs, const struct qstr *name, if (error) goto fail_gunlock; - error = make_dinode(dip, ghs[1].gh_gl, mode, &inum, &generation, dev, &bh); + error = make_dinode(dip, ghs[1].gh_gl, mode, &inum, &generation, dev, symname, size, &bh); if (error) goto fail_gunlock2; @@ -745,7 +755,7 @@ static int gfs2_create(struct inode *dir, struct dentry *dentry, gfs2_holder_init(dip->i_gl, 0, 0, ghs); for (;;) { - inode = gfs2_createi(ghs, &dentry->d_name, S_IFREG | mode, 0); + inode = gfs2_createi(ghs, &dentry->d_name, S_IFREG | mode, 0, NULL, 0); if (!IS_ERR(inode)) { gfs2_trans_end(sdp); if (dip->i_alloc->al_rgd) @@ -1140,40 +1150,24 @@ out_parent: static int gfs2_symlink(struct inode *dir, struct dentry *dentry, const char *symname) { - struct gfs2_inode *dip = GFS2_I(dir), *ip; + struct gfs2_inode *dip = GFS2_I(dir); struct gfs2_sbd *sdp = GFS2_SB(dir); struct gfs2_holder ghs[2]; struct inode *inode; - struct buffer_head *dibh; - int size; - int error; + unsigned int size; - /* Must be stuffed with a null terminator for gfs2_follow_link() */ size = strlen(symname); if (size > sdp->sd_sb.sb_bsize - sizeof(struct gfs2_dinode) - 1) return -ENAMETOOLONG; gfs2_holder_init(dip->i_gl, 0, 0, ghs); - inode = gfs2_createi(ghs, &dentry->d_name, S_IFLNK | S_IRWXUGO, 0); + inode = gfs2_createi(ghs, &dentry->d_name, S_IFLNK | S_IRWXUGO, 0, symname, size); if (IS_ERR(inode)) { gfs2_holder_uninit(ghs); return PTR_ERR(inode); } - ip = ghs[1].gh_gl->gl_object; - - i_size_write(inode, size); - - error = gfs2_meta_inode_buffer(ip, &dibh); - - if (!gfs2_assert_withdraw(sdp, !error)) { - gfs2_dinode_out(ip, dibh->b_data); - memcpy(dibh->b_data + sizeof(struct gfs2_dinode), symname, - size); - brelse(dibh); - } - gfs2_trans_end(sdp); if (dip->i_alloc->al_rgd) gfs2_inplace_release(dip); @@ -1206,7 +1200,7 @@ static int gfs2_mkdir(struct inode *dir, struct dentry *dentry, int mode) gfs2_holder_init(dip->i_gl, 0, 0, ghs); - inode = gfs2_createi(ghs, &dentry->d_name, S_IFDIR | mode, 0); + inode = gfs2_createi(ghs, &dentry->d_name, S_IFDIR | mode, 0, NULL, 0); if (IS_ERR(inode)) { gfs2_holder_uninit(ghs); return PTR_ERR(inode); @@ -1245,7 +1239,7 @@ static int gfs2_mknod(struct inode *dir, struct dentry *dentry, int mode, gfs2_holder_init(dip->i_gl, 0, 0, ghs); - inode = gfs2_createi(ghs, &dentry->d_name, mode, dev); + inode = gfs2_createi(ghs, &dentry->d_name, mode, dev, NULL, 0); if (IS_ERR(inode)) { gfs2_holder_uninit(ghs); return PTR_ERR(inode); @@ -1572,7 +1566,7 @@ static void *gfs2_follow_link(struct dentry *dentry, struct nameidata *nd) struct gfs2_inode *ip = GFS2_I(dentry->d_inode); struct gfs2_holder i_gh; struct buffer_head *dibh; - unsigned int x, size; + unsigned int size; char *buf; int error; @@ -1597,12 +1591,11 @@ static void *gfs2_follow_link(struct dentry *dentry, struct nameidata *nd) goto out; } - x = size + 1; - buf = kmalloc(x, GFP_NOFS); + buf = kzalloc(size + 1, GFP_NOFS); if (!buf) buf = ERR_PTR(-ENOMEM); else - memcpy(buf, dibh->b_data + sizeof(struct gfs2_dinode), x); + memcpy(buf, dibh->b_data + sizeof(struct gfs2_dinode), size); brelse(dibh); out: gfs2_glock_dq_uninit(&i_gh); diff --git a/fs/gfs2/inode.h b/fs/gfs2/inode.h index 7ed60aa..3160607 100644 --- a/fs/gfs2/inode.h +++ b/fs/gfs2/inode.h @@ -108,9 +108,6 @@ extern int gfs2_inode_refresh(struct gfs2_inode *ip); extern struct inode *gfs2_lookupi(struct inode *dir, const struct qstr *name, int is_root); -extern struct inode *gfs2_createi(struct gfs2_holder *ghs, - const struct qstr *name, - unsigned int mode, dev_t dev); extern int gfs2_permission(struct inode *inode, int mask, unsigned int flags); extern int gfs2_setattr_simple(struct gfs2_inode *ip, struct iattr *attr); extern struct inode *gfs2_lookup_simple(struct inode *dip, const char *name); -- cgit v0.10.2 From f2741d9898269e565c220ec295a8f5c3756c7585 Mon Sep 17 00:00:00 2001 From: Steven Whitehouse Date: Fri, 13 May 2011 12:11:17 +0100 Subject: GFS2: Move all locking inside the inode creation function Now that there are no longer any exceptions to the normal inode creation code path, we can move the parts of the locking code which were duplicated in mkdir/mknod/create/symlink into the inode create function. Signed-off-by: Steven Whitehouse diff --git a/fs/gfs2/inode.c b/fs/gfs2/inode.c index c2a3d9c..03e0c52 100644 --- a/fs/gfs2/inode.c +++ b/fs/gfs2/inode.c @@ -1,6 +1,6 @@ /* * Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved. - * Copyright (C) 2004-2006 Red Hat, Inc. All rights reserved. + * Copyright (C) 2004-2011 Red Hat, Inc. All rights reserved. * * This copyrighted material is made available to anyone wishing to use, * modify, copy, or redistribute it subject to the terms and conditions @@ -413,7 +413,8 @@ out: return error; } -static void gfs2_init_dir(struct buffer_head *dibh, const struct gfs2_inode *parent) +static void gfs2_init_dir(struct buffer_head *dibh, + const struct gfs2_inode *parent) { struct gfs2_dinode *di = (struct gfs2_dinode *)dibh->b_data; struct gfs2_dirent *dent = (struct gfs2_dirent *)(di+1); @@ -431,12 +432,17 @@ static void gfs2_init_dir(struct buffer_head *dibh, const struct gfs2_inode *par /** * init_dinode - Fill in a new dinode structure - * @dip: the directory this inode is being created in + * @dip: The directory this inode is being created in * @gl: The glock covering the new inode - * @inum: the inode number - * @mode: the file permissions - * @uid: - * @gid: + * @inum: The inode number + * @mode: The file permissions + * @uid: The uid of the new inode + * @gid: The gid of the new inode + * @generation: The generation number of the new inode + * @dev: The device number (if a device node) + * @symname: The symlink destination (if a symlink) + * @size: The inode size (ignored for directories) + * @bhp: The buffer head (returned to caller) * */ @@ -644,29 +650,25 @@ static int gfs2_security_init(struct gfs2_inode *dip, struct gfs2_inode *ip, } /** - * gfs2_createi - Create a new inode - * @ghs: An array of two holders - * @name: The name of the new file - * @mode: the permissions on the new inode + * gfs2_create_inode - Create a new inode + * @dir: The parent directory + * @dentry: The new dentry + * @mode: The permissions on the new inode + * @dev: For device nodes, this is the device number + * @symname: For symlinks, this is the link destination + * @size: The initial size of the inode (ignored for directories) * - * @ghs[0] is an initialized holder for the directory - * @ghs[1] is the holder for the inode lock - * - * If the return value is not NULL, the glocks on both the directory and the new - * file are held. A transaction has been started and an inplace reservation - * is held, as well. - * - * Returns: An inode + * Returns: 0 on success, or error code */ -static struct inode *gfs2_createi(struct gfs2_holder *ghs, - const struct qstr *name, unsigned int mode, - dev_t dev, const char *symname, - unsigned int size) +static int gfs2_create_inode(struct inode *dir, struct dentry *dentry, + unsigned int mode, dev_t dev, const char *symname, + unsigned int size) { + const struct qstr *name = &dentry->d_name; + struct gfs2_holder ghs[2]; struct inode *inode = NULL; - struct gfs2_inode *dip = ghs->gh_gl->gl_object; - struct inode *dir = &dip->i_inode; + struct gfs2_inode *dip = GFS2_I(dir); struct gfs2_sbd *sdp = GFS2_SB(&dip->i_inode); struct gfs2_inum_host inum = { .no_addr = 0, .no_formal_ino = 0 }; int error; @@ -674,10 +676,9 @@ static struct inode *gfs2_createi(struct gfs2_holder *ghs, struct buffer_head *bh = NULL; if (!name->len || name->len > GFS2_FNAMESIZE) - return ERR_PTR(-ENAMETOOLONG); + return -ENAMETOOLONG; - gfs2_holder_reinit(LM_ST_EXCLUSIVE, 0, ghs); - error = gfs2_glock_nq(ghs); + error = gfs2_glock_nq_init(dip->i_gl, LM_ST_EXCLUSIVE, 0, ghs); if (error) goto fail; @@ -722,19 +723,29 @@ static struct inode *gfs2_createi(struct gfs2_holder *ghs, if (bh) brelse(bh); - return inode; + + gfs2_trans_end(sdp); + if (dip->i_alloc->al_rgd) + gfs2_inplace_release(dip); + gfs2_quota_unlock(dip); + gfs2_alloc_put(dip); + gfs2_glock_dq_uninit_m(2, ghs); + mark_inode_dirty(inode); + d_instantiate(dentry, inode); + return 0; fail_gunlock2: gfs2_glock_dq_uninit(ghs + 1); if (inode && !IS_ERR(inode)) iput(inode); fail_gunlock: - gfs2_glock_dq(ghs); + gfs2_glock_dq_uninit(ghs); fail: if (bh) brelse(bh); - return ERR_PTR(error); + return error; } + /** * gfs2_create - Create a file * @dir: The directory in which to create the file @@ -747,44 +758,23 @@ fail: static int gfs2_create(struct inode *dir, struct dentry *dentry, int mode, struct nameidata *nd) { - struct gfs2_inode *dip = GFS2_I(dir); - struct gfs2_sbd *sdp = GFS2_SB(dir); - struct gfs2_holder ghs[2]; struct inode *inode; - - gfs2_holder_init(dip->i_gl, 0, 0, ghs); + int ret; for (;;) { - inode = gfs2_createi(ghs, &dentry->d_name, S_IFREG | mode, 0, NULL, 0); - if (!IS_ERR(inode)) { - gfs2_trans_end(sdp); - if (dip->i_alloc->al_rgd) - gfs2_inplace_release(dip); - gfs2_quota_unlock(dip); - gfs2_alloc_put(dip); - gfs2_glock_dq_uninit_m(2, ghs); - mark_inode_dirty(inode); - break; - } else if (PTR_ERR(inode) != -EEXIST || - (nd && nd->flags & LOOKUP_EXCL)) { - gfs2_holder_uninit(ghs); - return PTR_ERR(inode); - } + ret = gfs2_create_inode(dir, dentry, S_IFREG | mode, 0, NULL, 0); + if (ret != -EEXIST || (nd && (nd->flags & LOOKUP_EXCL))) + return ret; inode = gfs2_lookupi(dir, &dentry->d_name, 0); if (inode) { - if (!IS_ERR(inode)) { - gfs2_holder_uninit(ghs); + if (!IS_ERR(inode)) break; - } else { - gfs2_holder_uninit(ghs); - return PTR_ERR(inode); - } + return PTR_ERR(inode); } } d_instantiate(dentry, inode); - return 0; } @@ -1150,36 +1140,14 @@ out_parent: static int gfs2_symlink(struct inode *dir, struct dentry *dentry, const char *symname) { - struct gfs2_inode *dip = GFS2_I(dir); struct gfs2_sbd *sdp = GFS2_SB(dir); - struct gfs2_holder ghs[2]; - struct inode *inode; unsigned int size; size = strlen(symname); if (size > sdp->sd_sb.sb_bsize - sizeof(struct gfs2_dinode) - 1) return -ENAMETOOLONG; - gfs2_holder_init(dip->i_gl, 0, 0, ghs); - - inode = gfs2_createi(ghs, &dentry->d_name, S_IFLNK | S_IRWXUGO, 0, symname, size); - if (IS_ERR(inode)) { - gfs2_holder_uninit(ghs); - return PTR_ERR(inode); - } - - gfs2_trans_end(sdp); - if (dip->i_alloc->al_rgd) - gfs2_inplace_release(dip); - gfs2_quota_unlock(dip); - gfs2_alloc_put(dip); - - gfs2_glock_dq_uninit_m(2, ghs); - - d_instantiate(dentry, inode); - mark_inode_dirty(inode); - - return 0; + return gfs2_create_inode(dir, dentry, S_IFLNK | S_IRWXUGO, 0, symname, size); } /** @@ -1193,31 +1161,7 @@ static int gfs2_symlink(struct inode *dir, struct dentry *dentry, static int gfs2_mkdir(struct inode *dir, struct dentry *dentry, int mode) { - struct gfs2_inode *dip = GFS2_I(dir); - struct gfs2_sbd *sdp = GFS2_SB(dir); - struct gfs2_holder ghs[2]; - struct inode *inode; - - gfs2_holder_init(dip->i_gl, 0, 0, ghs); - - inode = gfs2_createi(ghs, &dentry->d_name, S_IFDIR | mode, 0, NULL, 0); - if (IS_ERR(inode)) { - gfs2_holder_uninit(ghs); - return PTR_ERR(inode); - } - - gfs2_trans_end(sdp); - if (dip->i_alloc->al_rgd) - gfs2_inplace_release(dip); - gfs2_quota_unlock(dip); - gfs2_alloc_put(dip); - - gfs2_glock_dq_uninit_m(2, ghs); - - d_instantiate(dentry, inode); - mark_inode_dirty(inode); - - return 0; + return gfs2_create_inode(dir, dentry, S_IFDIR | mode, 0, NULL, 0); } /** @@ -1225,38 +1169,14 @@ static int gfs2_mkdir(struct inode *dir, struct dentry *dentry, int mode) * @dir: The directory in which the special file will reside * @dentry: The dentry of the special file * @mode: The mode of the special file - * @rdev: The device specification of the special file + * @dev: The device specification of the special file * */ static int gfs2_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t dev) { - struct gfs2_inode *dip = GFS2_I(dir); - struct gfs2_sbd *sdp = GFS2_SB(dir); - struct gfs2_holder ghs[2]; - struct inode *inode; - - gfs2_holder_init(dip->i_gl, 0, 0, ghs); - - inode = gfs2_createi(ghs, &dentry->d_name, mode, dev, NULL, 0); - if (IS_ERR(inode)) { - gfs2_holder_uninit(ghs); - return PTR_ERR(inode); - } - - gfs2_trans_end(sdp); - if (dip->i_alloc->al_rgd) - gfs2_inplace_release(dip); - gfs2_quota_unlock(dip); - gfs2_alloc_put(dip); - - gfs2_glock_dq_uninit_m(2, ghs); - - d_instantiate(dentry, inode); - mark_inode_dirty(inode); - - return 0; + return gfs2_create_inode(dir, dentry, mode, dev, NULL, 0); } /* -- cgit v0.10.2 From 2c0f24636c80aa09990c507c0cede39add4b4724 Mon Sep 17 00:00:00 2001 From: Eliad Peller Date: Fri, 13 May 2011 11:57:08 +0300 Subject: wl12xx_sdio: set interrupt as wake_up interrupt set the sdio interrupt as wake_up interrupt, so we will be able to wake up the suspended system (Wake-On-Wireless) Signed-off-by: Eliad Peller Signed-off-by: Luciano Coelho diff --git a/drivers/net/wireless/wl12xx/sdio.c b/drivers/net/wireless/wl12xx/sdio.c index bcd4ad7..1298461 100644 --- a/drivers/net/wireless/wl12xx/sdio.c +++ b/drivers/net/wireless/wl12xx/sdio.c @@ -267,6 +267,8 @@ static int __devinit wl1271_probe(struct sdio_func *func, goto out_free; } + enable_irq_wake(wl->irq); + disable_irq(wl->irq); ret = wl1271_init_ieee80211(wl); @@ -303,6 +305,7 @@ static void __devexit wl1271_remove(struct sdio_func *func) pm_runtime_get_noresume(&func->dev); wl1271_unregister_hw(wl); + disable_irq_wake(wl->irq); free_irq(wl->irq, wl); wl1271_free_hw(wl); } -- cgit v0.10.2 From 402e48616078c1e56f55a69d314b77f1d750d6ad Mon Sep 17 00:00:00 2001 From: Eliad Peller Date: Fri, 13 May 2011 11:57:09 +0300 Subject: wl12xx: declare suspend/resume callbacks (for wowlan) Additionally, add wow_enabled field to wl, to indicate whether wowlan was configured. Signed-off-by: Eliad Peller Signed-off-by: Luciano Coelho diff --git a/drivers/net/wireless/wl12xx/main.c b/drivers/net/wireless/wl12xx/main.c index a14a035..4b421d8 100644 --- a/drivers/net/wireless/wl12xx/main.c +++ b/drivers/net/wireless/wl12xx/main.c @@ -1350,6 +1350,23 @@ static struct notifier_block wl1271_dev_notifier = { .notifier_call = wl1271_dev_notify, }; +static int wl1271_op_suspend(struct ieee80211_hw *hw, + struct cfg80211_wowlan *wow) +{ + struct wl1271 *wl = hw->priv; + wl1271_debug(DEBUG_MAC80211, "mac80211 suspend wow=%d", !!wow); + wl->wow_enabled = !!wow; + return 0; +} + +static int wl1271_op_resume(struct ieee80211_hw *hw) +{ + struct wl1271 *wl = hw->priv; + wl1271_debug(DEBUG_MAC80211, "mac80211 resume wow=%d", + wl->wow_enabled); + return 0; +} + static int wl1271_op_start(struct ieee80211_hw *hw) { wl1271_debug(DEBUG_MAC80211, "mac80211 start"); @@ -3506,6 +3523,8 @@ static const struct ieee80211_ops wl1271_ops = { .stop = wl1271_op_stop, .add_interface = wl1271_op_add_interface, .remove_interface = wl1271_op_remove_interface, + .suspend = wl1271_op_suspend, + .resume = wl1271_op_resume, .config = wl1271_op_config, .prepare_multicast = wl1271_op_prepare_multicast, .configure_filter = wl1271_op_configure_filter, diff --git a/drivers/net/wireless/wl12xx/wl12xx.h b/drivers/net/wireless/wl12xx/wl12xx.h index ab0c2f1..9629e90 100644 --- a/drivers/net/wireless/wl12xx/wl12xx.h +++ b/drivers/net/wireless/wl12xx/wl12xx.h @@ -565,6 +565,12 @@ struct wl1271 { int tcxo_clock; /* + * wowlan trigger was configured during suspend. + * (currently, only "ANY" trigger is supported) + */ + bool wow_enabled; + + /* * AP-mode - links indexed by HLID. The global and broadcast links * are always active. */ -- cgit v0.10.2 From 039bdb1494d1d514987ce596a4898494021c7af2 Mon Sep 17 00:00:00 2001 From: Eliad Peller Date: Fri, 13 May 2011 11:57:10 +0300 Subject: wl12xx_sdio: set MMC_PM_KEEP_POWER flag on suspend if a wow trigger was configured, set the MMC_PM_KEEP_POWER flag on suspend, so our power will be kept while the system is suspended. We needed to set this flag on each suspend attempt (when we want to keep power) Signed-off-by: Eliad Peller Signed-off-by: Luciano Coelho diff --git a/drivers/net/wireless/wl12xx/sdio.c b/drivers/net/wireless/wl12xx/sdio.c index 1298461..5b03fd5 100644 --- a/drivers/net/wireless/wl12xx/sdio.c +++ b/drivers/net/wireless/wl12xx/sdio.c @@ -314,7 +314,34 @@ static int wl1271_suspend(struct device *dev) { /* Tell MMC/SDIO core it's OK to power down the card * (if it isn't already), but not to remove it completely */ - return 0; + struct sdio_func *func = dev_to_sdio_func(dev); + struct wl1271 *wl = sdio_get_drvdata(func); + mmc_pm_flag_t sdio_flags; + int ret = 0; + + wl1271_debug(DEBUG_MAC80211, "wl1271 suspend. wow_enabled: %d", + wl->wow_enabled); + + /* check whether sdio should keep power */ + if (wl->wow_enabled) { + sdio_flags = sdio_get_host_pm_caps(func); + + if (!(sdio_flags & MMC_PM_KEEP_POWER)) { + wl1271_error("can't keep power while host " + "is suspended"); + ret = -EINVAL; + goto out; + } + + /* keep power while host suspended */ + ret = sdio_set_host_pm_flags(func, MMC_PM_KEEP_POWER); + if (ret) { + wl1271_error("error while trying to keep power"); + goto out; + } + } +out: + return ret; } static int wl1271_resume(struct device *dev) -- cgit v0.10.2 From f44e58681aec420b132a54823d8911293a644d4e Mon Sep 17 00:00:00 2001 From: Eliad Peller Date: Fri, 13 May 2011 11:57:11 +0300 Subject: wl12xx: prevent scheduling while suspending (WoW enabled) When WoW is enabled, the interface will stay up and the chip will be powered on, so we have to flush/cancel any remaining work, and prevent the irq handler from scheduling a new work until the system is resumed. Add 2 new flags: * WL1271_FLAG_SUSPENDED - the system is (about to be) suspended. * WL1271_FLAG_PENDING_WORK - there is a pending irq work which should be scheduled when the system is being resumed. In order to wake-up the system while getting an irq, we initialize the device as wakeup device, and calling pm_wakeup_event() upon getting the interrupt (while the system is about to be suspended) Signed-off-by: Eliad Peller Signed-off-by: Luciano Coelho diff --git a/drivers/net/wireless/wl12xx/main.c b/drivers/net/wireless/wl12xx/main.c index 4b421d8..8f9e615 100644 --- a/drivers/net/wireless/wl12xx/main.c +++ b/drivers/net/wireless/wl12xx/main.c @@ -1356,6 +1356,28 @@ static int wl1271_op_suspend(struct ieee80211_hw *hw, struct wl1271 *wl = hw->priv; wl1271_debug(DEBUG_MAC80211, "mac80211 suspend wow=%d", !!wow); wl->wow_enabled = !!wow; + if (wl->wow_enabled) { + /* flush any remaining work */ + wl1271_debug(DEBUG_MAC80211, "flushing remaining works"); + flush_delayed_work(&wl->scan_complete_work); + + /* + * disable and re-enable interrupts in order to flush + * the threaded_irq + */ + wl1271_disable_interrupts(wl); + + /* + * set suspended flag to avoid triggering a new threaded_irq + * work. no need for spinlock as interrupts are disabled. + */ + set_bit(WL1271_FLAG_SUSPENDED, &wl->flags); + + wl1271_enable_interrupts(wl); + flush_work(&wl->tx_work); + flush_delayed_work(&wl->pspoll_work); + flush_delayed_work(&wl->elp_work); + } return 0; } @@ -1364,6 +1386,30 @@ static int wl1271_op_resume(struct ieee80211_hw *hw) struct wl1271 *wl = hw->priv; wl1271_debug(DEBUG_MAC80211, "mac80211 resume wow=%d", wl->wow_enabled); + + /* + * re-enable irq_work enqueuing, and call irq_work directly if + * there is a pending work. + */ + if (wl->wow_enabled) { + struct wl1271 *wl = hw->priv; + unsigned long flags; + bool run_irq_work = false; + + spin_lock_irqsave(&wl->wl_lock, flags); + clear_bit(WL1271_FLAG_SUSPENDED, &wl->flags); + if (test_and_clear_bit(WL1271_FLAG_PENDING_WORK, &wl->flags)) + run_irq_work = true; + spin_unlock_irqrestore(&wl->wl_lock, flags); + + if (run_irq_work) { + wl1271_debug(DEBUG_MAC80211, + "run postponed irq_work directly"); + wl1271_irq(0, wl); + wl1271_enable_interrupts(wl); + } + } + return 0; } diff --git a/drivers/net/wireless/wl12xx/sdio.c b/drivers/net/wireless/wl12xx/sdio.c index 5b03fd5..41183db 100644 --- a/drivers/net/wireless/wl12xx/sdio.c +++ b/drivers/net/wireless/wl12xx/sdio.c @@ -82,6 +82,16 @@ static irqreturn_t wl1271_hardirq(int irq, void *cookie) complete(wl->elp_compl); wl->elp_compl = NULL; } + + if (test_bit(WL1271_FLAG_SUSPENDED, &wl->flags)) { + /* don't enqueue a work right now. mark it as pending */ + set_bit(WL1271_FLAG_PENDING_WORK, &wl->flags); + wl1271_debug(DEBUG_IRQ, "should not enqueue work"); + disable_irq_nosync(wl->irq); + pm_wakeup_event(wl1271_sdio_wl_to_dev(wl), 0); + spin_unlock_irqrestore(&wl->wl_lock, flags); + return IRQ_HANDLED; + } spin_unlock_irqrestore(&wl->wl_lock, flags); return IRQ_WAKE_THREAD; @@ -268,6 +278,7 @@ static int __devinit wl1271_probe(struct sdio_func *func, } enable_irq_wake(wl->irq); + device_init_wakeup(wl1271_sdio_wl_to_dev(wl), 1); disable_irq(wl->irq); @@ -305,6 +316,7 @@ static void __devexit wl1271_remove(struct sdio_func *func) pm_runtime_get_noresume(&func->dev); wl1271_unregister_hw(wl); + device_init_wakeup(wl1271_sdio_wl_to_dev(wl), 0); disable_irq_wake(wl->irq); free_irq(wl->irq, wl); wl1271_free_hw(wl); @@ -339,6 +351,9 @@ static int wl1271_suspend(struct device *dev) wl1271_error("error while trying to keep power"); goto out; } + + /* release host */ + sdio_release_host(func); } out: return ret; @@ -346,6 +361,15 @@ out: static int wl1271_resume(struct device *dev) { + struct sdio_func *func = dev_to_sdio_func(dev); + struct wl1271 *wl = sdio_get_drvdata(func); + + wl1271_debug(DEBUG_MAC80211, "wl1271 resume"); + if (wl->wow_enabled) { + /* claim back host */ + sdio_claim_host(func); + } + return 0; } diff --git a/drivers/net/wireless/wl12xx/wl12xx.h b/drivers/net/wireless/wl12xx/wl12xx.h index 9629e90..2218b9c 100644 --- a/drivers/net/wireless/wl12xx/wl12xx.h +++ b/drivers/net/wireless/wl12xx/wl12xx.h @@ -357,6 +357,8 @@ enum wl12xx_flags { WL1271_FLAG_AP_STARTED, WL1271_FLAG_IF_INITIALIZED, WL1271_FLAG_DUMMY_PACKET_PENDING, + WL1271_FLAG_SUSPENDED, + WL1271_FLAG_PENDING_WORK, }; struct wl1271_link { -- cgit v0.10.2 From f795ea8b2f047409c59e891d6e5e86a925048bf4 Mon Sep 17 00:00:00 2001 From: Eliad Peller Date: Fri, 13 May 2011 11:57:12 +0300 Subject: wl12xx_sdio: declare support for NL80211_WOW_TRIGGER_ANYTHING trigger Since wowlan requires the ability to stay awake while the host is suspended, declare support for NL80211_WOW_TRIGGER_ANYTHING if the MMC_PM_KEEP_POWER capability is being supported. Signed-off-by: Eliad Peller Signed-off-by: Luciano Coelho diff --git a/drivers/net/wireless/wl12xx/sdio.c b/drivers/net/wireless/wl12xx/sdio.c index 41183db..92d29a8 100644 --- a/drivers/net/wireless/wl12xx/sdio.c +++ b/drivers/net/wireless/wl12xx/sdio.c @@ -231,6 +231,7 @@ static int __devinit wl1271_probe(struct sdio_func *func, const struct wl12xx_platform_data *wlan_data; struct wl1271 *wl; unsigned long irqflags; + mmc_pm_flag_t mmcflags; int ret; /* We are only able to handle the wlan function */ @@ -282,6 +283,13 @@ static int __devinit wl1271_probe(struct sdio_func *func, disable_irq(wl->irq); + /* if sdio can keep power while host is suspended, enable wow */ + mmcflags = sdio_get_host_pm_caps(func); + wl1271_debug(DEBUG_SDIO, "sdio PM caps = 0x%x", mmcflags); + + if (mmcflags & MMC_PM_KEEP_POWER) + hw->wiphy->wowlan.flags = WIPHY_WOWLAN_ANY; + ret = wl1271_init_ieee80211(wl); if (ret) goto out_irq; -- cgit v0.10.2 From 9439064cd9fce8a4db716a748dbf581eb234f9c7 Mon Sep 17 00:00:00 2001 From: Eliad Peller Date: Fri, 13 May 2011 11:57:13 +0300 Subject: wl12xx: enter/exit psm on wowlan suspend/resume When operating as station, enter psm before suspending the device into wowlan state. Add a new completion event to signal when psm was entered successfully. Signed-off-by: Eliad Peller Signed-off-by: Luciano Coelho diff --git a/drivers/net/wireless/wl12xx/event.c b/drivers/net/wireless/wl12xx/event.c index 1e4bd6a..c3c554c 100644 --- a/drivers/net/wireless/wl12xx/event.c +++ b/drivers/net/wireless/wl12xx/event.c @@ -135,6 +135,13 @@ static int wl1271_event_ps_report(struct wl1271 *wl, /* enable beacon early termination */ ret = wl1271_acx_bet_enable(wl, true); + if (ret < 0) + break; + + if (wl->ps_compl) { + complete(wl->ps_compl); + wl->ps_compl = NULL; + } break; default: break; diff --git a/drivers/net/wireless/wl12xx/main.c b/drivers/net/wireless/wl12xx/main.c index 8f9e615..610be03 100644 --- a/drivers/net/wireless/wl12xx/main.c +++ b/drivers/net/wireless/wl12xx/main.c @@ -1350,6 +1350,79 @@ static struct notifier_block wl1271_dev_notifier = { .notifier_call = wl1271_dev_notify, }; +static int wl1271_configure_suspend(struct wl1271 *wl) +{ + int ret; + + if (wl->bss_type != BSS_TYPE_STA_BSS) + return 0; + + mutex_lock(&wl->mutex); + + ret = wl1271_ps_elp_wakeup(wl); + if (ret < 0) + goto out_unlock; + + /* enter psm if needed*/ + if (!test_bit(WL1271_FLAG_PSM, &wl->flags)) { + DECLARE_COMPLETION_ONSTACK(compl); + + wl->ps_compl = &compl; + ret = wl1271_ps_set_mode(wl, STATION_POWER_SAVE_MODE, + wl->basic_rate, true); + if (ret < 0) + goto out_sleep; + + /* we must unlock here so we will be able to get events */ + wl1271_ps_elp_sleep(wl); + mutex_unlock(&wl->mutex); + + ret = wait_for_completion_timeout( + &compl, msecs_to_jiffies(WL1271_PS_COMPLETE_TIMEOUT)); + if (ret <= 0) { + wl1271_warning("couldn't enter ps mode!"); + ret = -EBUSY; + goto out; + } + + /* take mutex again, and wakeup */ + mutex_lock(&wl->mutex); + + ret = wl1271_ps_elp_wakeup(wl); + if (ret < 0) + goto out_unlock; + } +out_sleep: + wl1271_ps_elp_sleep(wl); +out_unlock: + mutex_unlock(&wl->mutex); +out: + return ret; + +} + +static void wl1271_configure_resume(struct wl1271 *wl) +{ + int ret; + + if (wl->bss_type != BSS_TYPE_STA_BSS) + return; + + mutex_lock(&wl->mutex); + ret = wl1271_ps_elp_wakeup(wl); + if (ret < 0) + goto out; + + /* exit psm if it wasn't configured */ + if (!test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags)) + wl1271_ps_set_mode(wl, STATION_ACTIVE_MODE, + wl->basic_rate, true); + + wl1271_ps_elp_sleep(wl); +out: + mutex_unlock(&wl->mutex); +} + static int wl1271_op_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wow) { @@ -1357,6 +1430,12 @@ static int wl1271_op_suspend(struct ieee80211_hw *hw, wl1271_debug(DEBUG_MAC80211, "mac80211 suspend wow=%d", !!wow); wl->wow_enabled = !!wow; if (wl->wow_enabled) { + int ret; + ret = wl1271_configure_suspend(wl); + if (ret < 0) { + wl1271_warning("couldn't prepare device to suspend"); + return ret; + } /* flush any remaining work */ wl1271_debug(DEBUG_MAC80211, "flushing remaining works"); flush_delayed_work(&wl->scan_complete_work); @@ -1408,6 +1487,8 @@ static int wl1271_op_resume(struct ieee80211_hw *hw) wl1271_irq(0, wl); wl1271_enable_interrupts(wl); } + + wl1271_configure_resume(wl); } return 0; diff --git a/drivers/net/wireless/wl12xx/ps.h b/drivers/net/wireless/wl12xx/ps.h index c41bd0a..25eb9bc 100644 --- a/drivers/net/wireless/wl12xx/ps.h +++ b/drivers/net/wireless/wl12xx/ps.h @@ -35,4 +35,6 @@ void wl1271_elp_work(struct work_struct *work); void wl1271_ps_link_start(struct wl1271 *wl, u8 hlid, bool clean_queues); void wl1271_ps_link_end(struct wl1271 *wl, u8 hlid); +#define WL1271_PS_COMPLETE_TIMEOUT 500 + #endif /* __WL1271_PS_H__ */ diff --git a/drivers/net/wireless/wl12xx/wl12xx.h b/drivers/net/wireless/wl12xx/wl12xx.h index 2218b9c..fbe8f46 100644 --- a/drivers/net/wireless/wl12xx/wl12xx.h +++ b/drivers/net/wireless/wl12xx/wl12xx.h @@ -513,6 +513,7 @@ struct wl1271 { unsigned int rx_filter; struct completion *elp_compl; + struct completion *ps_compl; struct delayed_work elp_work; struct delayed_work pspoll_work; -- cgit v0.10.2 From 5fd2a84ab3c8b87176e25db1d98c5cc34043a669 Mon Sep 17 00:00:00 2001 From: "Avinash H.M" Date: Mon, 9 May 2011 12:29:40 +0000 Subject: OMAP3: set the core dpll clk rate in its set_rate function The debug l3_ick/rate is not displaying the actual rate of the clock in hardware. This is because, the core dpll set_rate function doesn't update the clk.rate. After fixing, the l3_ick/rate is displaying proper values. Signed-off-by: Shweta Gulati Signed-off-by: Avinash.H.M Cc: Rajendra Nayak Cc: Paul Wamsley Acked-by: Paul Walmsley Signed-off-by: Tony Lindgren diff --git a/arch/arm/mach-omap2/clkt34xx_dpll3m2.c b/arch/arm/mach-omap2/clkt34xx_dpll3m2.c index b2b1e37..d6e34dd 100644 --- a/arch/arm/mach-omap2/clkt34xx_dpll3m2.c +++ b/arch/arm/mach-omap2/clkt34xx_dpll3m2.c @@ -115,6 +115,7 @@ int omap3_core_dpll_m2_set_rate(struct clk *clk, unsigned long rate) sdrc_cs0->rfr_ctrl, sdrc_cs0->actim_ctrla, sdrc_cs0->actim_ctrlb, sdrc_cs0->mr, 0, 0, 0, 0); + clk->rate = rate; return 0; } -- cgit v0.10.2 From d9a5ac9ef306eb5cc874f285185a15c303c50009 Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Fri, 13 May 2011 15:52:09 +0200 Subject: x86, mce, AMD: Fix leaving freed data in a list b may be added to a list, but is not removed before being freed in the case of an error. This is done in the corresponding deallocation function, so the code here has been changed to follow that. The sematic match that finds this problem is as follows: (http://coccinelle.lip6.fr/) // @@ expression E,E1,E2; identifier l; @@ *list_add(&E->l,E1); ... when != E1 when != list_del(&E->l) when != list_del_init(&E->l) when != E = E2 *kfree(E);// Signed-off-by: Julia Lawall Cc: Borislav Petkov Cc: Robert Richter Cc: Yinghai Lu Cc: Andreas Herrmann Cc: Link: http://lkml.kernel.org/r/1305294731-12127-1-git-send-email-julia@diku.dk Signed-off-by: Ingo Molnar diff --git a/arch/x86/kernel/cpu/mcheck/mce_amd.c b/arch/x86/kernel/cpu/mcheck/mce_amd.c index 167f97b..bb0adad 100644 --- a/arch/x86/kernel/cpu/mcheck/mce_amd.c +++ b/arch/x86/kernel/cpu/mcheck/mce_amd.c @@ -509,6 +509,7 @@ recurse: out_free: if (b) { kobject_put(&b->kobj); + list_del(&b->miscj); kfree(b); } return err; -- cgit v0.10.2 From 19e274630c9e23a84d5940af83cf5db35103f968 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Thu, 12 May 2011 10:47:23 +0200 Subject: job control: reorganize wait_task_stopped() wait_task_stopped() tested task_stopped_code() without acquiring siglock and, if stop condition existed, called wait_task_stopped() and directly returned the result. This patch moves the initial task_stopped_code() testing into wait_task_stopped() and make wait_consider_task() fall through to wait_task_continue() on 0 return. This is for the following two reasons. * Because the initial task_stopped_code() test is done without acquiring siglock, it may race against SIGCONT generation. The stopped condition might have been replaced by continued state by the time wait_task_stopped() acquired siglock. This may lead to unexpected failure of WNOHANG waits. This reorganization addresses this single race case but there are other cases - TASK_RUNNING -> TASK_STOPPED transition and EXIT_* transitions. * Scheduled ptrace updates require changes to the initial test which would fit better inside wait_task_stopped(). Signed-off-by: Tejun Heo Reviewed-by: Oleg Nesterov Signed-off-by: Oleg Nesterov diff --git a/kernel/exit.c b/kernel/exit.c index 5cbc83e..3383793 100644 --- a/kernel/exit.c +++ b/kernel/exit.c @@ -1377,11 +1377,23 @@ static int *task_stopped_code(struct task_struct *p, bool ptrace) return NULL; } -/* - * Handle sys_wait4 work for one task in state TASK_STOPPED. We hold - * read_lock(&tasklist_lock) on entry. If we return zero, we still hold - * the lock and this task is uninteresting. If we return nonzero, we have - * released the lock and the system call should return. +/** + * wait_task_stopped - Wait for %TASK_STOPPED or %TASK_TRACED + * @wo: wait options + * @ptrace: is the wait for ptrace + * @p: task to wait for + * + * Handle sys_wait4() work for %p in state %TASK_STOPPED or %TASK_TRACED. + * + * CONTEXT: + * read_lock(&tasklist_lock), which is released if return value is + * non-zero. Also, grabs and releases @p->sighand->siglock. + * + * RETURNS: + * 0 if wait condition didn't exist and search for other wait conditions + * should continue. Non-zero return, -errno on failure and @p's pid on + * success, implies that tasklist_lock is released and wait condition + * search should terminate. */ static int wait_task_stopped(struct wait_opts *wo, int ptrace, struct task_struct *p) @@ -1397,6 +1409,9 @@ static int wait_task_stopped(struct wait_opts *wo, if (!ptrace && !(wo->wo_flags & WUNTRACED)) return 0; + if (!task_stopped_code(p, ptrace)) + return 0; + exit_code = 0; spin_lock_irq(&p->sighand->siglock); @@ -1607,8 +1622,9 @@ static int wait_consider_task(struct wait_opts *wo, int ptrace, * Wait for stopped. Depending on @ptrace, different stopped state * is used and the two don't interact with each other. */ - if (task_stopped_code(p, ptrace)) - return wait_task_stopped(wo, ptrace, p); + ret = wait_task_stopped(wo, ptrace, p); + if (ret) + return ret; /* * Wait for continued. There's only one continued state and the -- cgit v0.10.2 From bdc220da3209d50b8c295490dec94845c88670a2 Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Mon, 9 May 2011 17:42:46 +0000 Subject: netdevice.h: Align struct net_device members Save a bit of space. Signed-off-by: Joe Perches Signed-off-by: David S. Miller diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index 1d9696a..a134d80 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -1020,9 +1020,6 @@ struct net_device { * part of the usual set specified in Space.c. */ - unsigned char if_port; /* Selectable AUI, TP,..*/ - unsigned char dma; /* DMA channel */ - unsigned long state; struct list_head dev_list; @@ -1146,13 +1143,16 @@ struct net_device { const struct header_ops *header_ops; unsigned int flags; /* interface flags (a la BSD) */ + unsigned int priv_flags; /* Like 'flags' but invisible to userspace. */ unsigned short gflags; - unsigned int priv_flags; /* Like 'flags' but invisible to userspace. */ unsigned short padded; /* How much padding added by alloc_netdev() */ unsigned char operstate; /* RFC2863 operstate */ unsigned char link_mode; /* mapping policy to operstate */ + unsigned char if_port; /* Selectable AUI, TP,..*/ + unsigned char dma; /* DMA channel */ + unsigned int mtu; /* interface MTU value */ unsigned short type; /* interface hardware type */ unsigned short hard_header_len; /* hardware hdr length */ -- cgit v0.10.2 From 5d44670facd3205212f8fe89eb422e3b5f309612 Mon Sep 17 00:00:00 2001 From: Marcus Meissner Date: Thu, 5 May 2011 10:44:11 -0700 Subject: ocfs2: Initialize data_ac (might be used uninitialized) CLANG found that there is a path that has data_ac uninitialized, this place 2917 /* This gets us the dx_root */ 2918 ret = ocfs2_reserve_new_metadata_blocks(osb, 1, &meta_ac); 2919 if (ret) { 3 Taking true branch 2920 mlog_errno(ret); 2921 goto out; 4 Control jumps to line 3168 2922 } Goes to the out: label without data_ac being initialized. Ciao, Marcus Signed-Off-By: Marcus Meissner Signed-off-by: Mark Fasheh Signed-off-by: Joel Becker diff --git a/fs/ocfs2/dir.c b/fs/ocfs2/dir.c index 9fe5b8fd..8582e3f 100644 --- a/fs/ocfs2/dir.c +++ b/fs/ocfs2/dir.c @@ -2868,7 +2868,7 @@ static int ocfs2_expand_inline_dir(struct inode *dir, struct buffer_head *di_bh, bytes = blocks_wanted << sb->s_blocksize_bits; struct ocfs2_super *osb = OCFS2_SB(dir->i_sb); struct ocfs2_inode_info *oi = OCFS2_I(dir); - struct ocfs2_alloc_context *data_ac; + struct ocfs2_alloc_context *data_ac = NULL; struct ocfs2_alloc_context *meta_ac = NULL; struct buffer_head *dirdata_bh = NULL; struct buffer_head *dx_root_bh = NULL; -- cgit v0.10.2 From 9a790ba1ec02bbae0933e7ebd576c0bc329e9796 Mon Sep 17 00:00:00 2001 From: Tristan Ye Date: Thu, 12 May 2011 20:47:07 +0800 Subject: ocfs2: skip existing hole when removing the last extent_rec in punching-hole codes. In the case of removing a partial extent record which covers a hole, current punching-hole logic will try to remove more than the length of whole extent record, which leads to the failure of following assert(fs/ocfs2/alloc.c): 5507 BUG_ON(cpos < le32_to_cpu(rec->e_cpos) || trunc_range > rec_range); This patch tries to skip existing hole at the last attempt of removing a partial extent record, what's more, it also adds some necessary comments for better understanding of punching-hole codes. Signed-off-by: Tristan Ye Signed-off-by: Joel Becker diff --git a/fs/ocfs2/file.c b/fs/ocfs2/file.c index 41565ae..89659d6 100644 --- a/fs/ocfs2/file.c +++ b/fs/ocfs2/file.c @@ -1607,6 +1607,9 @@ static void ocfs2_calc_trunc_pos(struct inode *inode, range = le32_to_cpu(rec->e_cpos) + ocfs2_rec_clusters(el, rec); if (le32_to_cpu(rec->e_cpos) >= trunc_start) { + /* + * remove an entire extent record. + */ *trunc_cpos = le32_to_cpu(rec->e_cpos); /* * Skip holes if any. @@ -1617,7 +1620,16 @@ static void ocfs2_calc_trunc_pos(struct inode *inode, *blkno = le64_to_cpu(rec->e_blkno); *trunc_end = le32_to_cpu(rec->e_cpos); } else if (range > trunc_start) { + /* + * remove a partial extent record, which means we're + * removing the last extent record. + */ *trunc_cpos = trunc_start; + /* + * skip hole if any. + */ + if (range < *trunc_end) + *trunc_end = range; *trunc_len = *trunc_end - trunc_start; coff = trunc_start - le32_to_cpu(rec->e_cpos); *blkno = le64_to_cpu(rec->e_blkno) + -- cgit v0.10.2 From 4da6dc293604f55d156148b8f60b94053e3195fc Mon Sep 17 00:00:00 2001 From: Sunil Mushran Date: Wed, 4 May 2011 10:27:10 -0700 Subject: ocfs2/dlm: Use negotiated o2dlm protocol version Patch fixes a bug in the o2dlm protocol negotiation in that it is using the builtin version rather than the negotiated version during the domain join. This causes join errors when a node having kernel >= 2.6.37 joins a cluster with nodes having kernels < 2.6.37. This only affects the o2cb cluster stack. Signed-off-by: Sunil Mushran Reported-by: Jacek Stepniewski Acked-by: Mark Fasheh Signed-off-by: Joel Becker diff --git a/fs/ocfs2/dlm/dlmdomain.c b/fs/ocfs2/dlm/dlmdomain.c index 7540a49..3b179d6 100644 --- a/fs/ocfs2/dlm/dlmdomain.c +++ b/fs/ocfs2/dlm/dlmdomain.c @@ -1614,7 +1614,8 @@ static int dlm_try_to_join_domain(struct dlm_ctxt *dlm) spin_unlock(&dlm->spinlock); /* Support for global heartbeat and node info was added in 1.1 */ - if (dlm_protocol.pv_major > 1 || dlm_protocol.pv_minor > 0) { + if (dlm->dlm_locking_proto.pv_major > 1 || + dlm->dlm_locking_proto.pv_minor > 0) { status = dlm_send_nodeinfo(dlm, ctxt->yes_resp_map); if (status) { mlog_errno(status); -- cgit v0.10.2 From 76d9fc2954d057b19bf5d7b854df2b621b00fdec Mon Sep 17 00:00:00 2001 From: Sunil Mushran Date: Wed, 4 May 2011 10:28:00 -0700 Subject: ocfs2/cluster: Increase the live threshold for global heartbeat We have seen isolated cases (very few, I might add) of o2hb not detecting all live nodes on startup. One plausible reasoning for it is that other node had a hb io delay at the same time. The live threshold set at 2 (as low as it can be) could be increased to ameliorate the situation. But increasing the threshold directly affects mount time. Currently it takes around 5 secs to mount a volume in o2cb cluster with local heartbeat. Increasing the threshold will make mounts even slower. As the issue itself is rare, we have left things as they are for the local heartbeat mode. However we can improve the situation for global heartbeat mode as in that mode, we start the heartbeat much before the mount. This patch doubles the live threshold for the start of the first region in global heartbeat mode. Addresses internal Oracle bug#10635585. Signed-off-by: Sunil Mushran Acked-by: Mark Fasheh Signed-off-by: Joel Becker diff --git a/fs/ocfs2/cluster/heartbeat.c b/fs/ocfs2/cluster/heartbeat.c index 6437202..1d28505 100644 --- a/fs/ocfs2/cluster/heartbeat.c +++ b/fs/ocfs2/cluster/heartbeat.c @@ -1690,6 +1690,7 @@ static ssize_t o2hb_region_dev_write(struct o2hb_region *reg, struct file *filp = NULL; struct inode *inode = NULL; ssize_t ret = -EINVAL; + int live_threshold; if (reg->hr_bdev) goto out; @@ -1766,8 +1767,18 @@ static ssize_t o2hb_region_dev_write(struct o2hb_region *reg, * A node is considered live after it has beat LIVE_THRESHOLD * times. We're not steady until we've given them a chance * _after_ our first read. + * The default threshold is bare minimum so as to limit the delay + * during mounts. For global heartbeat, the threshold doubled for the + * first region. */ - atomic_set(®->hr_steady_iterations, O2HB_LIVE_THRESHOLD + 1); + live_threshold = O2HB_LIVE_THRESHOLD; + if (o2hb_global_heartbeat_active()) { + spin_lock(&o2hb_live_lock); + if (o2hb_pop_count(&o2hb_region_bitmap, O2NM_MAX_REGIONS) == 1) + live_threshold <<= 1; + spin_unlock(&o2hb_live_lock); + } + atomic_set(®->hr_steady_iterations, live_threshold + 1); hb_task = kthread_run(o2hb_thread, reg, "o2hb-%s", reg->hr_item.ci_name); -- cgit v0.10.2 From 33c12a5436464f8d4f56d68e5e79e24a3a1f11aa Mon Sep 17 00:00:00 2001 From: Sunil Mushran Date: Wed, 4 May 2011 10:28:01 -0700 Subject: ocfs2/cluster: Heartbeat mismatch message improved If o2hb finds unexpected values in the heartbeat slot, it prints a message "ERROR: Device "dm-6": another node is heartbeating in our slot!" This message could be misleading. This patch adds two more messages to help users better diagnose the problem. Signed-off-by: Sunil Mushran Acked-by: Mark Fasheh Signed-off-by: Joel Becker diff --git a/fs/ocfs2/cluster/heartbeat.c b/fs/ocfs2/cluster/heartbeat.c index 1d28505..9a3e6bb 100644 --- a/fs/ocfs2/cluster/heartbeat.c +++ b/fs/ocfs2/cluster/heartbeat.c @@ -539,25 +539,41 @@ static int o2hb_verify_crc(struct o2hb_region *reg, /* We want to make sure that nobody is heartbeating on top of us -- * this will help detect an invalid configuration. */ -static int o2hb_check_last_timestamp(struct o2hb_region *reg) +static void o2hb_check_last_timestamp(struct o2hb_region *reg) { - int node_num, ret; struct o2hb_disk_slot *slot; struct o2hb_disk_heartbeat_block *hb_block; + char *errstr; - node_num = o2nm_this_node(); - - ret = 1; - slot = ®->hr_slots[node_num]; + slot = ®->hr_slots[o2nm_this_node()]; /* Don't check on our 1st timestamp */ - if (slot->ds_last_time) { - hb_block = slot->ds_raw_block; + if (!slot->ds_last_time) + return; - if (le64_to_cpu(hb_block->hb_seq) != slot->ds_last_time) - ret = 0; - } + hb_block = slot->ds_raw_block; + if (le64_to_cpu(hb_block->hb_seq) == slot->ds_last_time && + le64_to_cpu(hb_block->hb_generation) == slot->ds_last_generation && + hb_block->hb_node == slot->ds_node_num) + return; - return ret; +#define ERRSTR1 "Another node is heartbeating on device" +#define ERRSTR2 "Heartbeat generation mismatch on device" +#define ERRSTR3 "Heartbeat sequence mismatch on device" + + if (hb_block->hb_node != slot->ds_node_num) + errstr = ERRSTR1; + else if (le64_to_cpu(hb_block->hb_generation) != + slot->ds_last_generation) + errstr = ERRSTR2; + else + errstr = ERRSTR3; + + mlog(ML_ERROR, "%s (%s): expected(%u:0x%llx, 0x%llx), " + "ondisk(%u:0x%llx, 0x%llx)\n", errstr, reg->hr_dev_name, + slot->ds_node_num, (unsigned long long)slot->ds_last_generation, + (unsigned long long)slot->ds_last_time, hb_block->hb_node, + (unsigned long long)le64_to_cpu(hb_block->hb_generation), + (unsigned long long)le64_to_cpu(hb_block->hb_seq)); } static inline void o2hb_prepare_block(struct o2hb_region *reg, @@ -983,9 +999,7 @@ static int o2hb_do_disk_heartbeat(struct o2hb_region *reg) /* With an up to date view of the slots, we can check that no * other node has been improperly configured to heartbeat in * our slot. */ - if (!o2hb_check_last_timestamp(reg)) - mlog(ML_ERROR, "Device \"%s\": another node is heartbeating " - "in our slot!\n", reg->hr_dev_name); + o2hb_check_last_timestamp(reg); /* fill in the proper info for our next heartbeat */ o2hb_prepare_block(reg, reg->hr_generation); @@ -999,8 +1013,8 @@ static int o2hb_do_disk_heartbeat(struct o2hb_region *reg) } i = -1; - while((i = find_next_bit(configured_nodes, O2NM_MAX_NODES, i + 1)) < O2NM_MAX_NODES) { - + while((i = find_next_bit(configured_nodes, + O2NM_MAX_NODES, i + 1)) < O2NM_MAX_NODES) { change |= o2hb_check_slot(reg, ®->hr_slots[i]); } -- cgit v0.10.2 From 10b3dd76117a327557b8cb898b41c18afd08dc86 Mon Sep 17 00:00:00 2001 From: Sunil Mushran Date: Wed, 4 May 2011 10:28:02 -0700 Subject: ocfs2: Skip mount recovery for hard-ro mounts Patch skips mount recovery for hard-ro mounts which otherwise leads to an oops. Signed-off-by: Sunil Mushran Acked-by: Mark Fasheh Signed-off-by: Joel Becker diff --git a/fs/ocfs2/journal.c b/fs/ocfs2/journal.c index b141a44..295d564 100644 --- a/fs/ocfs2/journal.c +++ b/fs/ocfs2/journal.c @@ -1260,6 +1260,9 @@ void ocfs2_complete_mount_recovery(struct ocfs2_super *osb) { struct ocfs2_journal *journal = osb->journal; + if (ocfs2_is_hard_readonly(osb)) + return; + /* No need to queue up our truncate_log as regular cleanup will catch * that */ ocfs2_queue_recovery_completion(journal, osb->slot_num, -- cgit v0.10.2 From df016c665b10ae80d8db67ec8103b50c5c234e5c Mon Sep 17 00:00:00 2001 From: Sunil Mushran Date: Wed, 4 May 2011 10:28:07 -0700 Subject: ocfs2/dlm: Target node death during resource migration leads to thread spin During resource migration, if the target node were to die, the thread doing the migration spins until the target node is not removed from the domain map. This patch slows the spin by making the thread wait for the recovery to kick in. Signed-off-by: Sunil Mushran Signed-off-by: Joel Becker diff --git a/fs/ocfs2/dlm/dlmmaster.c b/fs/ocfs2/dlm/dlmmaster.c index fede57e..84d1663 100644 --- a/fs/ocfs2/dlm/dlmmaster.c +++ b/fs/ocfs2/dlm/dlmmaster.c @@ -2574,6 +2574,9 @@ fail: res->state &= ~DLM_LOCK_RES_MIGRATING; wake = 1; spin_unlock(&res->spinlock); + if (dlm_is_host_down(ret)) + dlm_wait_for_node_death(dlm, target, + DLM_NODE_DEATH_WAIT_MAX); goto leave; } -- cgit v0.10.2 From 29dd54b72ba8c5ad0dd6dd33584449b5953f700b Mon Sep 17 00:00:00 2001 From: Anirban Chakraborty Date: Thu, 12 May 2011 12:48:32 +0000 Subject: ethtool: Added support for FW dump Added code to take FW dump via ethtool. Dump level can be controlled via setting the dump flag. A get function is provided to query the current setting of the dump flag. Dump data is obtained from the driver via a separate get function. Changes from v3: Fixed buffer length issue in ethtool_get_dump_data function. Updated kernel doc for ethtool_dump struct and get_dump_flag function. Changes from v2: Provided separate commands for get flag and data. Check for minimum of the two buffer length obtained via ethtool and driver and use that for dump buffer Pass up the driver return error codes up to the caller. Added kernel doc comments. Signed-off-by: Anirban Chakraborty Reviewed-by: Ben Hutchings Signed-off-by: David S. Miller diff --git a/include/linux/ethtool.h b/include/linux/ethtool.h index bd0b50b..c6a850a 100644 --- a/include/linux/ethtool.h +++ b/include/linux/ethtool.h @@ -601,6 +601,26 @@ struct ethtool_flash { char data[ETHTOOL_FLASH_MAX_FILENAME]; }; +/** + * struct ethtool_dump - used for retrieving, setting device dump + * @cmd: Command number - %ETHTOOL_GET_DUMP_FLAG, %ETHTOOL_GET_DUMP_DATA, or + * %ETHTOOL_SET_DUMP + * @version: FW version of the dump, filled in by driver + * @flag: driver dependent flag for dump setting, filled in by driver during + * get and filled in by ethtool for set operation + * @len: length of dump data, used as the length of the user buffer on entry to + * %ETHTOOL_GET_DUMP_DATA and this is returned as dump length by driver + * for %ETHTOOL_GET_DUMP_FLAG command + * @data: data collected for get dump data operation + */ +struct ethtool_dump { + __u32 cmd; + __u32 version; + __u32 flag; + __u32 len; + __u8 data[0]; +}; + /* for returning and changing feature sets */ /** @@ -853,6 +873,10 @@ bool ethtool_invalid_flags(struct net_device *dev, u32 data, u32 supported); * @get_channels: Get number of channels. * @set_channels: Set number of channels. Returns a negative error code or * zero. + * @get_dump_flag: Get dump flag indicating current dump length, version, + * and flag of the device. + * @get_dump_data: Get dump data. + * @set_dump: Set dump specific flags to the device. * * All operations are optional (i.e. the function pointer may be set * to %NULL) and callers must take this into account. Callers must @@ -927,6 +951,10 @@ struct ethtool_ops { const struct ethtool_rxfh_indir *); void (*get_channels)(struct net_device *, struct ethtool_channels *); int (*set_channels)(struct net_device *, struct ethtool_channels *); + int (*get_dump_flag)(struct net_device *, struct ethtool_dump *); + int (*get_dump_data)(struct net_device *, + struct ethtool_dump *, void *); + int (*set_dump)(struct net_device *, struct ethtool_dump *); }; #endif /* __KERNEL__ */ @@ -998,6 +1026,9 @@ struct ethtool_ops { #define ETHTOOL_SFEATURES 0x0000003b /* Change device offload settings */ #define ETHTOOL_GCHANNELS 0x0000003c /* Get no of channels */ #define ETHTOOL_SCHANNELS 0x0000003d /* Set no of channels */ +#define ETHTOOL_SET_DUMP 0x0000003e /* Set dump settings */ +#define ETHTOOL_GET_DUMP_FLAG 0x0000003f /* Get dump settings */ +#define ETHTOOL_GET_DUMP_DATA 0x00000040 /* Get dump data */ /* compatibility with older code */ #define SPARC_ETH_GSET ETHTOOL_GSET diff --git a/net/core/ethtool.c b/net/core/ethtool.c index b8c2b10f..b8c2bcf 100644 --- a/net/core/ethtool.c +++ b/net/core/ethtool.c @@ -1823,6 +1823,87 @@ static noinline_for_stack int ethtool_flash_device(struct net_device *dev, return dev->ethtool_ops->flash_device(dev, &efl); } +static int ethtool_set_dump(struct net_device *dev, + void __user *useraddr) +{ + struct ethtool_dump dump; + + if (!dev->ethtool_ops->set_dump) + return -EOPNOTSUPP; + + if (copy_from_user(&dump, useraddr, sizeof(dump))) + return -EFAULT; + + return dev->ethtool_ops->set_dump(dev, &dump); +} + +static int ethtool_get_dump_flag(struct net_device *dev, + void __user *useraddr) +{ + int ret; + struct ethtool_dump dump; + const struct ethtool_ops *ops = dev->ethtool_ops; + + if (!dev->ethtool_ops->get_dump_flag) + return -EOPNOTSUPP; + + if (copy_from_user(&dump, useraddr, sizeof(dump))) + return -EFAULT; + + ret = ops->get_dump_flag(dev, &dump); + if (ret) + return ret; + + if (copy_to_user(useraddr, &dump, sizeof(dump))) + return -EFAULT; + return 0; +} + +static int ethtool_get_dump_data(struct net_device *dev, + void __user *useraddr) +{ + int ret; + __u32 len; + struct ethtool_dump dump, tmp; + const struct ethtool_ops *ops = dev->ethtool_ops; + void *data = NULL; + + if (!dev->ethtool_ops->get_dump_data || + !dev->ethtool_ops->get_dump_flag) + return -EOPNOTSUPP; + + if (copy_from_user(&dump, useraddr, sizeof(dump))) + return -EFAULT; + + memset(&tmp, 0, sizeof(tmp)); + tmp.cmd = ETHTOOL_GET_DUMP_FLAG; + ret = ops->get_dump_flag(dev, &tmp); + if (ret) + return ret; + + len = (tmp.len > dump.len) ? dump.len : tmp.len; + if (!len) + return -EFAULT; + + data = vzalloc(tmp.len); + if (!data) + return -ENOMEM; + ret = ops->get_dump_data(dev, &dump, data); + if (ret) + goto out; + + if (copy_to_user(useraddr, &dump, sizeof(dump))) { + ret = -EFAULT; + goto out; + } + useraddr += offsetof(struct ethtool_dump, data); + if (copy_to_user(useraddr, data, len)) + ret = -EFAULT; +out: + vfree(data); + return ret; +} + /* The main entry point in this file. Called from net/core/dev.c */ int dev_ethtool(struct net *net, struct ifreq *ifr) @@ -2039,6 +2120,15 @@ int dev_ethtool(struct net *net, struct ifreq *ifr) case ETHTOOL_SCHANNELS: rc = ethtool_set_channels(dev, useraddr); break; + case ETHTOOL_SET_DUMP: + rc = ethtool_set_dump(dev, useraddr); + break; + case ETHTOOL_GET_DUMP_FLAG: + rc = ethtool_get_dump_flag(dev, useraddr); + break; + case ETHTOOL_GET_DUMP_DATA: + rc = ethtool_get_dump_data(dev, useraddr); + break; default: rc = -EOPNOTSUPP; } -- cgit v0.10.2 From 6ed35eea3b96977d76d61b5862a3209044cb4b1f Mon Sep 17 00:00:00 2001 From: Sathya Perla Date: Thu, 12 May 2011 19:32:15 +0000 Subject: be2net: handle signal reception while waiting for POST If waiting on POST returns prematurely (due to a signal), abort polling and return an error. Signed-off-by: Sathya Perla Signed-off-by: David S. Miller diff --git a/drivers/net/benet/be_cmds.c b/drivers/net/benet/be_cmds.c index 0dbb4cb..d558b90 100644 --- a/drivers/net/benet/be_cmds.c +++ b/drivers/net/benet/be_cmds.c @@ -376,23 +376,25 @@ int be_cmd_POST(struct be_adapter *adapter) { u16 stage; int status, timeout = 0; + struct device *dev = &adapter->pdev->dev; do { status = be_POST_stage_get(adapter, &stage); if (status) { - dev_err(&adapter->pdev->dev, "POST error; stage=0x%x\n", - stage); + dev_err(dev, "POST error; stage=0x%x\n", stage); return -1; } else if (stage != POST_STAGE_ARMFW_RDY) { - set_current_state(TASK_INTERRUPTIBLE); - schedule_timeout(2 * HZ); + if (msleep_interruptible(2000)) { + dev_err(dev, "Waiting for POST aborted\n"); + return -EINTR; + } timeout += 2; } else { return 0; } } while (timeout < 40); - dev_err(&adapter->pdev->dev, "POST timeout; stage=0x%x\n", stage); + dev_err(dev, "POST timeout; stage=0x%x\n", stage); return -1; } -- cgit v0.10.2 From 1dbf53a28262aa89ecbe653e8a9127c0baef9bc4 Mon Sep 17 00:00:00 2001 From: Sathya Perla Date: Thu, 12 May 2011 19:32:16 +0000 Subject: be2net: fix mbox polling for signal reception Sending mbox cmds require multiple steps of writing to the DB register and polling for an ack. Gettting interrupted in the middle by a signal breaks the mbox protocol. Use msleep() to not get interrupted. Signed-off-by: Sathya Perla Signed-off-by: David S. Miller diff --git a/drivers/net/benet/be_cmds.c b/drivers/net/benet/be_cmds.c index d558b90..f2c9099 100644 --- a/drivers/net/benet/be_cmds.c +++ b/drivers/net/benet/be_cmds.c @@ -298,8 +298,7 @@ static int be_mbox_db_ready_wait(struct be_adapter *adapter, void __iomem *db) return -1; } - set_current_state(TASK_INTERRUPTIBLE); - schedule_timeout(msecs_to_jiffies(1)); + msleep(1); msecs++; } while (true); -- cgit v0.10.2 From 18f2f616be88736f5daf31d9d40e027abbd607ed Mon Sep 17 00:00:00 2001 From: Anirban Chakraborty Date: Thu, 12 May 2011 12:48:33 +0000 Subject: qlcnic: FW dump support Added code to take FW dump. o Driver queries FW at the init time and gets the dump template o It takes FW dump as per the dump template o Level of FW dump (and its size) is configured via dump flag Signed-off-by: Sritej Velaga Signed-off-by: Anirban Chakraborty Signed-off-by: David S. Miller diff --git a/drivers/net/qlcnic/qlcnic.h b/drivers/net/qlcnic/qlcnic.h index f729363..689adea 100644 --- a/drivers/net/qlcnic/qlcnic.h +++ b/drivers/net/qlcnic/qlcnic.h @@ -411,6 +411,29 @@ struct qlcnic_nic_intr_coalesce { u32 timer_out; }; +struct qlcnic_dump_template_hdr { + __le32 type; + __le32 offset; + __le32 size; + __le32 cap_mask; + __le32 num_entries; + __le32 version; + __le32 timestamp; + __le32 checksum; + __le32 drv_cap_mask; + __le32 sys_info[3]; + __le32 saved_state[16]; + __le32 cap_sizes[8]; + __le32 rsvd[0]; +}; + +struct qlcnic_fw_dump { + u8 clr; /* flag to indicate if dump is cleared */ + u32 size; /* total size of the dump */ + void *data; /* dump data area */ + struct qlcnic_dump_template_hdr *tmpl_hdr; +}; + /* * One hardware_context{} per adapter * contains interrupt info as well shared hardware info. @@ -431,6 +454,7 @@ struct qlcnic_hardware_context { u16 board_type; struct qlcnic_nic_intr_coalesce coal; + struct qlcnic_fw_dump fw_dump; }; struct qlcnic_adapter_stats { @@ -574,6 +598,8 @@ struct qlcnic_recv_context { #define QLCNIC_CDRP_CMD_GET_ESWITCH_PORT_CONFIG 0x00000029 #define QLCNIC_CDRP_CMD_GET_ESWITCH_STATS 0x0000002a #define QLCNIC_CDRP_CMD_CONFIG_PORT 0x0000002E +#define QLCNIC_CDRP_CMD_TEMP_SIZE 0x0000002f +#define QLCNIC_CDRP_CMD_GET_TEMP_HDR 0x00000030 #define QLCNIC_RCODE_SUCCESS 0 #define QLCNIC_RCODE_NOT_SUPPORTED 9 @@ -1157,6 +1183,152 @@ struct qlcnic_esw_statistics { struct __qlcnic_esw_statistics tx; }; +struct qlcnic_common_entry_hdr { + __le32 type; + __le32 offset; + __le32 cap_size; + u8 mask; + u8 rsvd[2]; + u8 flags; +} __packed; + +struct __crb { + __le32 addr; + u8 stride; + u8 rsvd1[3]; + __le32 data_size; + __le32 no_ops; + __le32 rsvd2[4]; +} __packed; + +struct __ctrl { + __le32 addr; + u8 stride; + u8 index_a; + __le16 timeout; + __le32 data_size; + __le32 no_ops; + u8 opcode; + u8 index_v; + u8 shl_val; + u8 shr_val; + __le32 val1; + __le32 val2; + __le32 val3; +} __packed; + +struct __cache { + __le32 addr; + u8 stride; + u8 rsvd; + __le16 init_tag_val; + __le32 size; + __le32 no_ops; + __le32 ctrl_addr; + __le32 ctrl_val; + __le32 read_addr; + u8 read_addr_stride; + u8 read_addr_num; + u8 rsvd1[2]; +} __packed; + +struct __ocm { + u8 rsvd[8]; + __le32 size; + __le32 no_ops; + u8 rsvd1[8]; + __le32 read_addr; + __le32 read_addr_stride; +} __packed; + +struct __mem { + u8 rsvd[24]; + __le32 addr; + __le32 size; +} __packed; + +struct __mux { + __le32 addr; + u8 rsvd[4]; + __le32 size; + __le32 no_ops; + __le32 val; + __le32 val_stride; + __le32 read_addr; + u8 rsvd2[4]; +} __packed; + +struct __queue { + __le32 sel_addr; + __le16 stride; + u8 rsvd[2]; + __le32 size; + __le32 no_ops; + u8 rsvd2[8]; + __le32 read_addr; + u8 read_addr_stride; + u8 read_addr_cnt; + u8 rsvd3[2]; +} __packed; + +struct qlcnic_dump_entry { + struct qlcnic_common_entry_hdr hdr; + union { + struct __crb crb; + struct __cache cache; + struct __ocm ocm; + struct __mem mem; + struct __mux mux; + struct __queue que; + struct __ctrl ctrl; + } region; +} __packed; + +enum op_codes { + QLCNIC_DUMP_NOP = 0, + QLCNIC_DUMP_READ_CRB = 1, + QLCNIC_DUMP_READ_MUX = 2, + QLCNIC_DUMP_QUEUE = 3, + QLCNIC_DUMP_BRD_CONFIG = 4, + QLCNIC_DUMP_READ_OCM = 6, + QLCNIC_DUMP_PEG_REG = 7, + QLCNIC_DUMP_L1_DTAG = 8, + QLCNIC_DUMP_L1_ITAG = 9, + QLCNIC_DUMP_L1_DATA = 11, + QLCNIC_DUMP_L1_INST = 12, + QLCNIC_DUMP_L2_DTAG = 21, + QLCNIC_DUMP_L2_ITAG = 22, + QLCNIC_DUMP_L2_DATA = 23, + QLCNIC_DUMP_L2_INST = 24, + QLCNIC_DUMP_READ_ROM = 71, + QLCNIC_DUMP_READ_MEM = 72, + QLCNIC_DUMP_READ_CTRL = 98, + QLCNIC_DUMP_TLHDR = 99, + QLCNIC_DUMP_RDEND = 255 +}; + +#define QLCNIC_DUMP_WCRB BIT_0 +#define QLCNIC_DUMP_RWCRB BIT_1 +#define QLCNIC_DUMP_ANDCRB BIT_2 +#define QLCNIC_DUMP_ORCRB BIT_3 +#define QLCNIC_DUMP_POLLCRB BIT_4 +#define QLCNIC_DUMP_RD_SAVE BIT_5 +#define QLCNIC_DUMP_WRT_SAVED BIT_6 +#define QLCNIC_DUMP_MOD_SAVE_ST BIT_7 +#define QLCNIC_DUMP_SKIP BIT_7 + +#define QLCNIC_DUMP_MASK_MIN 3 +#define QLCNIC_DUMP_MASK_DEF 0x0f +#define QLCNIC_DUMP_MASK_MAX 0xff +#define QLCNIC_FORCE_FW_DUMP_KEY 0xdeadfeed + +struct qlcnic_dump_operations { + enum op_codes opcode; + u32 (*handler)(struct qlcnic_adapter *, + struct qlcnic_dump_entry *, u32 *); +}; + +int qlcnic_fw_cmd_get_minidump_temp(struct qlcnic_adapter *adapter); int qlcnic_fw_cmd_set_port(struct qlcnic_adapter *adapter, u32 config); u32 qlcnic_hw_read_wx_2M(struct qlcnic_adapter *adapter, ulong off); @@ -1203,6 +1375,7 @@ int qlcnic_wol_supported(struct qlcnic_adapter *adapter); int qlcnic_config_led(struct qlcnic_adapter *adapter, u32 state, u32 rate); void qlcnic_prune_lb_filters(struct qlcnic_adapter *adapter); void qlcnic_delete_lb_filters(struct qlcnic_adapter *adapter); +int qlcnic_dump_fw(struct qlcnic_adapter *); /* Functions from qlcnic_init.c */ int qlcnic_load_firmware(struct qlcnic_adapter *adapter); @@ -1213,7 +1386,7 @@ int qlcnic_pinit_from_rom(struct qlcnic_adapter *adapter); int qlcnic_setup_idc_param(struct qlcnic_adapter *adapter); int qlcnic_check_flash_fw_ver(struct qlcnic_adapter *adapter); -int qlcnic_rom_fast_read(struct qlcnic_adapter *adapter, int addr, int *valp); +int qlcnic_rom_fast_read(struct qlcnic_adapter *adapter, u32 addr, u32 *valp); int qlcnic_rom_fast_read_words(struct qlcnic_adapter *adapter, int addr, u8 *bytes, size_t size); int qlcnic_alloc_sw_resources(struct qlcnic_adapter *adapter); @@ -1265,6 +1438,7 @@ int qlcnic_diag_alloc_res(struct net_device *netdev, int test); netdev_tx_t qlcnic_xmit_frame(struct sk_buff *skb, struct net_device *netdev); int qlcnic_validate_max_rss(struct net_device *netdev, u8 max_hw, u8 val); int qlcnic_set_max_rss(struct qlcnic_adapter *adapter, u8 data); +void qlcnic_dev_request_reset(struct qlcnic_adapter *); /* Management functions */ int qlcnic_get_mac_address(struct qlcnic_adapter *, u8*); diff --git a/drivers/net/qlcnic/qlcnic_ctx.c b/drivers/net/qlcnic/qlcnic_ctx.c index 3a99886..bab041a 100644 --- a/drivers/net/qlcnic/qlcnic_ctx.c +++ b/drivers/net/qlcnic/qlcnic_ctx.c @@ -64,6 +64,97 @@ qlcnic_issue_cmd(struct qlcnic_adapter *adapter, return rcode; } +static uint32_t qlcnic_temp_checksum(uint32_t *temp_buffer, u16 temp_size) +{ + uint64_t sum = 0; + int count = temp_size / sizeof(uint32_t); + while (count-- > 0) + sum += *temp_buffer++; + while (sum >> 32) + sum = (sum & 0xFFFFFFFF) + (sum >> 32); + return ~sum; +} + +int qlcnic_fw_cmd_get_minidump_temp(struct qlcnic_adapter *adapter) +{ + int err, i; + u16 temp_size; + void *tmp_addr; + u32 version, csum, *template, *tmp_buf; + struct qlcnic_hardware_context *ahw; + struct qlcnic_dump_template_hdr *tmpl_hdr, *tmp_tmpl; + dma_addr_t tmp_addr_t = 0; + + ahw = adapter->ahw; + err = qlcnic_issue_cmd(adapter, + adapter->ahw->pci_func, + adapter->fw_hal_version, + 0, + 0, + 0, + QLCNIC_CDRP_CMD_TEMP_SIZE); + if (err != QLCNIC_RCODE_SUCCESS) { + err = QLCRD32(adapter, QLCNIC_ARG1_CRB_OFFSET); + dev_err(&adapter->pdev->dev, + "Failed to get template size %d\n", err); + err = -EIO; + return err; + } + version = QLCRD32(adapter, QLCNIC_ARG3_CRB_OFFSET); + temp_size = QLCRD32(adapter, QLCNIC_ARG2_CRB_OFFSET); + if (!temp_size) + return -EIO; + + tmp_addr = dma_alloc_coherent(&adapter->pdev->dev, temp_size, + &tmp_addr_t, GFP_KERNEL); + if (!tmp_addr) { + dev_err(&adapter->pdev->dev, + "Can't get memory for FW dump template\n"); + return -ENOMEM; + } + err = qlcnic_issue_cmd(adapter, + adapter->ahw->pci_func, + adapter->fw_hal_version, + LSD(tmp_addr_t), + MSD(tmp_addr_t), + temp_size, + QLCNIC_CDRP_CMD_GET_TEMP_HDR); + + if (err != QLCNIC_RCODE_SUCCESS) { + dev_err(&adapter->pdev->dev, + "Failed to get mini dump template header %d\n", err); + err = -EIO; + goto error; + } + tmp_tmpl = (struct qlcnic_dump_template_hdr *) tmp_addr; + csum = qlcnic_temp_checksum((uint32_t *) tmp_addr, temp_size); + if (csum) { + dev_err(&adapter->pdev->dev, + "Template header checksum validation failed\n"); + err = -EIO; + goto error; + } + ahw->fw_dump.tmpl_hdr = vzalloc(temp_size); + if (!ahw->fw_dump.tmpl_hdr) { + err = -EIO; + goto error; + } + tmp_buf = (u32 *) tmp_addr; + template = (u32 *) ahw->fw_dump.tmpl_hdr; + for (i = 0; i < temp_size/sizeof(u32); i++) + *template++ = __le32_to_cpu(*tmp_buf++); + + tmpl_hdr = ahw->fw_dump.tmpl_hdr; + if (tmpl_hdr->cap_mask > QLCNIC_DUMP_MASK_DEF && + tmpl_hdr->cap_mask <= QLCNIC_DUMP_MASK_MAX) + tmpl_hdr->drv_cap_mask = tmpl_hdr->cap_mask; + else + tmpl_hdr->drv_cap_mask = QLCNIC_DUMP_MASK_DEF; +error: + dma_free_coherent(&adapter->pdev->dev, temp_size, tmp_addr, tmp_addr_t); + return err; +} + int qlcnic_fw_cmd_set_mtu(struct qlcnic_adapter *adapter, int mtu) { diff --git a/drivers/net/qlcnic/qlcnic_hdr.h b/drivers/net/qlcnic/qlcnic_hdr.h index 726ef55..d14506f 100644 --- a/drivers/net/qlcnic/qlcnic_hdr.h +++ b/drivers/net/qlcnic/qlcnic_hdr.h @@ -492,10 +492,10 @@ enum { #define TEST_AGT_CTRL (0x00) -#define TA_CTL_START 1 -#define TA_CTL_ENABLE 2 -#define TA_CTL_WRITE 4 -#define TA_CTL_BUSY 8 +#define TA_CTL_START BIT_0 +#define TA_CTL_ENABLE BIT_1 +#define TA_CTL_WRITE BIT_2 +#define TA_CTL_BUSY BIT_3 /* * Register offsets for MN @@ -765,6 +765,38 @@ struct qlcnic_legacy_intr_set { #define QLCNIC_MAX_PCI_FUNC 8 #define QLCNIC_MAX_VLAN_FILTERS 64 +/* FW dump defines */ +#define MIU_TEST_CTR 0x41000090 +#define MIU_TEST_ADDR_LO 0x41000094 +#define MIU_TEST_ADDR_HI 0x41000098 +#define FLASH_ROM_WINDOW 0x42110030 +#define FLASH_ROM_DATA 0x42150000 + +static const u32 MIU_TEST_READ_DATA[] = { + 0x410000A8, 0x410000AC, 0x410000B8, 0x410000BC, }; + +#define QLCNIC_FW_DUMP_REG1 0x00130060 +#define QLCNIC_FW_DUMP_REG2 0x001e0000 +#define QLCNIC_FLASH_SEM2_LK 0x0013C010 +#define QLCNIC_FLASH_SEM2_ULK 0x0013C014 +#define QLCNIC_FLASH_LOCK_ID 0x001B2100 + +#define QLCNIC_RD_DUMP_REG(addr, bar0, data) do { \ + writel((addr & 0xFFFF0000), (void *) (bar0 + \ + QLCNIC_FW_DUMP_REG1)); \ + readl((void *) (bar0 + QLCNIC_FW_DUMP_REG1)); \ + *data = readl((void *) (bar0 + QLCNIC_FW_DUMP_REG2 + \ + LSW(addr))); \ +} while (0) + +#define QLCNIC_WR_DUMP_REG(addr, bar0, data) do { \ + writel((addr & 0xFFFF0000), (void *) (bar0 + \ + QLCNIC_FW_DUMP_REG1)); \ + readl((void *) (bar0 + QLCNIC_FW_DUMP_REG1)); \ + writel(data, (void *) (bar0 + QLCNIC_FW_DUMP_REG2 + LSW(addr)));\ + readl((void *) (bar0 + QLCNIC_FW_DUMP_REG2 + LSW(addr))); \ +} while (0) + /* PCI function operational mode */ enum { QLCNIC_MGMT_FUNC = 0, diff --git a/drivers/net/qlcnic/qlcnic_hw.c b/drivers/net/qlcnic/qlcnic_hw.c index cbb27f2..e965661 100644 --- a/drivers/net/qlcnic/qlcnic_hw.c +++ b/drivers/net/qlcnic/qlcnic_hw.c @@ -9,6 +9,7 @@ #include #include +#include #define MASK(n) ((1ULL<<(n))-1) #define OCM_WIN_P3P(addr) (addr & 0xffc0000) @@ -1261,3 +1262,461 @@ int qlcnic_config_led(struct qlcnic_adapter *adapter, u32 state, u32 rate) return rv; } + +/* FW dump related functions */ +static u32 +qlcnic_dump_crb(struct qlcnic_adapter *adapter, struct qlcnic_dump_entry *entry, + u32 *buffer) +{ + int i; + u32 addr, data; + struct __crb *crb = &entry->region.crb; + void __iomem *base = adapter->ahw->pci_base0; + + addr = crb->addr; + + for (i = 0; i < crb->no_ops; i++) { + QLCNIC_RD_DUMP_REG(addr, base, &data); + *buffer++ = cpu_to_le32(addr); + *buffer++ = cpu_to_le32(data); + addr += crb->stride; + } + return crb->no_ops * 2 * sizeof(u32); +} + +static u32 +qlcnic_dump_ctrl(struct qlcnic_adapter *adapter, + struct qlcnic_dump_entry *entry, u32 *buffer) +{ + int i, k, timeout = 0; + void __iomem *base = adapter->ahw->pci_base0; + u32 addr, data; + u8 opcode, no_ops; + struct __ctrl *ctr = &entry->region.ctrl; + struct qlcnic_dump_template_hdr *t_hdr = adapter->ahw->fw_dump.tmpl_hdr; + + addr = ctr->addr; + no_ops = ctr->no_ops; + + for (i = 0; i < no_ops; i++) { + k = 0; + opcode = 0; + for (k = 0; k < 8; k++) { + if (!(ctr->opcode & (1 << k))) + continue; + switch (1 << k) { + case QLCNIC_DUMP_WCRB: + QLCNIC_WR_DUMP_REG(addr, base, ctr->val1); + break; + case QLCNIC_DUMP_RWCRB: + QLCNIC_RD_DUMP_REG(addr, base, &data); + QLCNIC_WR_DUMP_REG(addr, base, data); + break; + case QLCNIC_DUMP_ANDCRB: + QLCNIC_RD_DUMP_REG(addr, base, &data); + QLCNIC_WR_DUMP_REG(addr, base, + (data & ctr->val2)); + break; + case QLCNIC_DUMP_ORCRB: + QLCNIC_RD_DUMP_REG(addr, base, &data); + QLCNIC_WR_DUMP_REG(addr, base, + (data | ctr->val3)); + break; + case QLCNIC_DUMP_POLLCRB: + while (timeout <= ctr->timeout) { + QLCNIC_RD_DUMP_REG(addr, base, &data); + if ((data & ctr->val2) == ctr->val1) + break; + msleep(1); + timeout++; + } + if (timeout > ctr->timeout) { + dev_info(&adapter->pdev->dev, + "Timed out, aborting poll CRB\n"); + return -EINVAL; + } + break; + case QLCNIC_DUMP_RD_SAVE: + if (ctr->index_a) + addr = t_hdr->saved_state[ctr->index_a]; + QLCNIC_RD_DUMP_REG(addr, base, &data); + t_hdr->saved_state[ctr->index_v] = data; + break; + case QLCNIC_DUMP_WRT_SAVED: + if (ctr->index_v) + data = t_hdr->saved_state[ctr->index_v]; + else + data = ctr->val1; + if (ctr->index_a) + addr = t_hdr->saved_state[ctr->index_a]; + QLCNIC_WR_DUMP_REG(addr, base, data); + break; + case QLCNIC_DUMP_MOD_SAVE_ST: + data = t_hdr->saved_state[ctr->index_v]; + data <<= ctr->shl_val; + data >>= ctr->shr_val; + if (ctr->val2) + data &= ctr->val2; + data |= ctr->val3; + data += ctr->val1; + t_hdr->saved_state[ctr->index_v] = data; + break; + default: + dev_info(&adapter->pdev->dev, + "Unknown opcode\n"); + break; + } + } + addr += ctr->stride; + } + return 0; +} + +static u32 +qlcnic_dump_mux(struct qlcnic_adapter *adapter, struct qlcnic_dump_entry *entry, + u32 *buffer) +{ + int loop; + u32 val, data = 0; + struct __mux *mux = &entry->region.mux; + void __iomem *base = adapter->ahw->pci_base0; + + val = mux->val; + for (loop = 0; loop < mux->no_ops; loop++) { + QLCNIC_WR_DUMP_REG(mux->addr, base, val); + QLCNIC_RD_DUMP_REG(mux->read_addr, base, &data); + *buffer++ = cpu_to_le32(val); + *buffer++ = cpu_to_le32(data); + val += mux->val_stride; + } + return 2 * mux->no_ops * sizeof(u32); +} + +static u32 +qlcnic_dump_que(struct qlcnic_adapter *adapter, struct qlcnic_dump_entry *entry, + u32 *buffer) +{ + int i, loop; + u32 cnt, addr, data, que_id = 0; + void __iomem *base = adapter->ahw->pci_base0; + struct __queue *que = &entry->region.que; + + addr = que->read_addr; + cnt = que->read_addr_cnt; + + for (loop = 0; loop < que->no_ops; loop++) { + QLCNIC_WR_DUMP_REG(que->sel_addr, base, que_id); + for (i = 0; i < cnt; i++) { + QLCNIC_RD_DUMP_REG(addr, base, &data); + *buffer++ = cpu_to_le32(data); + addr += que->read_addr_stride; + } + que_id += que->stride; + } + return que->no_ops * cnt * sizeof(u32); +} + +static u32 +qlcnic_dump_ocm(struct qlcnic_adapter *adapter, struct qlcnic_dump_entry *entry, + u32 *buffer) +{ + int i; + u32 data; + void __iomem *addr; + struct __ocm *ocm = &entry->region.ocm; + + addr = adapter->ahw->pci_base0 + ocm->read_addr; + for (i = 0; i < ocm->no_ops; i++) { + data = readl(addr); + *buffer++ = cpu_to_le32(data); + addr += ocm->read_addr_stride; + } + return ocm->no_ops * sizeof(u32); +} + +static u32 +qlcnic_read_rom(struct qlcnic_adapter *adapter, struct qlcnic_dump_entry *entry, + u32 *buffer) +{ + int i, count = 0; + u32 fl_addr, size, val, lck_val, addr; + struct __mem *rom = &entry->region.mem; + void __iomem *base = adapter->ahw->pci_base0; + + fl_addr = rom->addr; + size = rom->size/4; +lock_try: + lck_val = readl(base + QLCNIC_FLASH_SEM2_LK); + if (!lck_val && count < MAX_CTL_CHECK) { + msleep(10); + count++; + goto lock_try; + } + writel(adapter->ahw->pci_func, (base + QLCNIC_FLASH_LOCK_ID)); + for (i = 0; i < size; i++) { + addr = fl_addr & 0xFFFF0000; + QLCNIC_WR_DUMP_REG(FLASH_ROM_WINDOW, base, addr); + addr = LSW(fl_addr) + FLASH_ROM_DATA; + QLCNIC_RD_DUMP_REG(addr, base, &val); + fl_addr += 4; + *buffer++ = cpu_to_le32(val); + } + readl(base + QLCNIC_FLASH_SEM2_ULK); + return rom->size; +} + +static u32 +qlcnic_dump_l1_cache(struct qlcnic_adapter *adapter, + struct qlcnic_dump_entry *entry, u32 *buffer) +{ + int i; + u32 cnt, val, data, addr; + void __iomem *base = adapter->ahw->pci_base0; + struct __cache *l1 = &entry->region.cache; + + val = l1->init_tag_val; + + for (i = 0; i < l1->no_ops; i++) { + QLCNIC_WR_DUMP_REG(l1->addr, base, val); + QLCNIC_WR_DUMP_REG(l1->ctrl_addr, base, LSW(l1->ctrl_val)); + addr = l1->read_addr; + cnt = l1->read_addr_num; + while (cnt) { + QLCNIC_RD_DUMP_REG(addr, base, &data); + *buffer++ = cpu_to_le32(data); + addr += l1->read_addr_stride; + cnt--; + } + val += l1->stride; + } + return l1->no_ops * l1->read_addr_num * sizeof(u32); +} + +static u32 +qlcnic_dump_l2_cache(struct qlcnic_adapter *adapter, + struct qlcnic_dump_entry *entry, u32 *buffer) +{ + int i; + u32 cnt, val, data, addr; + u8 poll_mask, poll_to, time_out = 0; + void __iomem *base = adapter->ahw->pci_base0; + struct __cache *l2 = &entry->region.cache; + + val = l2->init_tag_val; + poll_mask = LSB(MSW(l2->ctrl_val)); + poll_to = MSB(MSW(l2->ctrl_val)); + + for (i = 0; i < l2->no_ops; i++) { + QLCNIC_WR_DUMP_REG(l2->addr, base, val); + do { + QLCNIC_WR_DUMP_REG(l2->ctrl_addr, base, + LSW(l2->ctrl_val)); + QLCNIC_RD_DUMP_REG(l2->ctrl_addr, base, &data); + if (!(data & poll_mask)) + break; + msleep(1); + time_out++; + } while (time_out <= poll_to); + if (time_out > poll_to) + return -EINVAL; + + addr = l2->read_addr; + cnt = l2->read_addr_num; + while (cnt) { + QLCNIC_RD_DUMP_REG(addr, base, &data); + *buffer++ = cpu_to_le32(data); + addr += l2->read_addr_stride; + cnt--; + } + val += l2->stride; + } + return l2->no_ops * l2->read_addr_num * sizeof(u32); +} + +static u32 +qlcnic_read_memory(struct qlcnic_adapter *adapter, + struct qlcnic_dump_entry *entry, u32 *buffer) +{ + u32 addr, data, test, ret = 0; + int i, reg_read; + struct __mem *mem = &entry->region.mem; + void __iomem *base = adapter->ahw->pci_base0; + + reg_read = mem->size; + addr = mem->addr; + /* check for data size of multiple of 16 and 16 byte alignment */ + if ((addr & 0xf) || (reg_read%16)) { + dev_info(&adapter->pdev->dev, + "Unaligned memory addr:0x%x size:0x%x\n", + addr, reg_read); + return -EINVAL; + } + + mutex_lock(&adapter->ahw->mem_lock); + + while (reg_read != 0) { + QLCNIC_WR_DUMP_REG(MIU_TEST_ADDR_LO, base, addr); + QLCNIC_WR_DUMP_REG(MIU_TEST_ADDR_HI, base, 0); + QLCNIC_WR_DUMP_REG(MIU_TEST_CTR, base, + TA_CTL_ENABLE | TA_CTL_START); + + for (i = 0; i < MAX_CTL_CHECK; i++) { + QLCNIC_RD_DUMP_REG(MIU_TEST_CTR, base, &test); + if (!(test & TA_CTL_BUSY)) + break; + } + if (i == MAX_CTL_CHECK) { + if (printk_ratelimit()) { + dev_err(&adapter->pdev->dev, + "failed to read through agent\n"); + ret = -EINVAL; + goto out; + } + } + for (i = 0; i < 4; i++) { + QLCNIC_RD_DUMP_REG(MIU_TEST_READ_DATA[i], base, &data); + *buffer++ = cpu_to_le32(data); + } + addr += 16; + reg_read -= 16; + ret += 16; + } +out: + mutex_unlock(&adapter->ahw->mem_lock); + return mem->size; +} + +static u32 +qlcnic_dump_nop(struct qlcnic_adapter *adapter, + struct qlcnic_dump_entry *entry, u32 *buffer) +{ + entry->hdr.flags |= QLCNIC_DUMP_SKIP; + return 0; +} + +struct qlcnic_dump_operations fw_dump_ops[] = { + { QLCNIC_DUMP_NOP, qlcnic_dump_nop }, + { QLCNIC_DUMP_READ_CRB, qlcnic_dump_crb }, + { QLCNIC_DUMP_READ_MUX, qlcnic_dump_mux }, + { QLCNIC_DUMP_QUEUE, qlcnic_dump_que }, + { QLCNIC_DUMP_BRD_CONFIG, qlcnic_read_rom }, + { QLCNIC_DUMP_READ_OCM, qlcnic_dump_ocm }, + { QLCNIC_DUMP_PEG_REG, qlcnic_dump_ctrl }, + { QLCNIC_DUMP_L1_DTAG, qlcnic_dump_l1_cache }, + { QLCNIC_DUMP_L1_ITAG, qlcnic_dump_l1_cache }, + { QLCNIC_DUMP_L1_DATA, qlcnic_dump_l1_cache }, + { QLCNIC_DUMP_L1_INST, qlcnic_dump_l1_cache }, + { QLCNIC_DUMP_L2_DTAG, qlcnic_dump_l2_cache }, + { QLCNIC_DUMP_L2_ITAG, qlcnic_dump_l2_cache }, + { QLCNIC_DUMP_L2_DATA, qlcnic_dump_l2_cache }, + { QLCNIC_DUMP_L2_INST, qlcnic_dump_l2_cache }, + { QLCNIC_DUMP_READ_ROM, qlcnic_read_rom }, + { QLCNIC_DUMP_READ_MEM, qlcnic_read_memory }, + { QLCNIC_DUMP_READ_CTRL, qlcnic_dump_ctrl }, + { QLCNIC_DUMP_TLHDR, qlcnic_dump_nop }, + { QLCNIC_DUMP_RDEND, qlcnic_dump_nop }, +}; + +/* Walk the template and collect dump for each entry in the dump template */ +static int +qlcnic_valid_dump_entry(struct device *dev, struct qlcnic_dump_entry *entry, + u32 size) +{ + int ret = 1; + if (size != entry->hdr.cap_size) { + dev_info(dev, + "Invalidate dump, Type:%d\tMask:%d\tSize:%dCap_size:%d\n", + entry->hdr.type, entry->hdr.mask, size, entry->hdr.cap_size); + dev_info(dev, "Aborting further dump capture\n"); + ret = 0; + } + return ret; +} + +int qlcnic_dump_fw(struct qlcnic_adapter *adapter) +{ + u32 *buffer; + char mesg[64]; + char *msg[] = {mesg, NULL}; + int i, k, ops_cnt, ops_index, dump_size = 0; + u32 entry_offset, dump, no_entries, buf_offset = 0; + struct qlcnic_dump_entry *entry; + struct qlcnic_fw_dump *fw_dump = &adapter->ahw->fw_dump; + struct qlcnic_dump_template_hdr *tmpl_hdr = fw_dump->tmpl_hdr; + + if (fw_dump->clr) { + dev_info(&adapter->pdev->dev, + "Previous dump not cleared, not capturing dump\n"); + return -EIO; + } + /* Calculate the size for dump data area only */ + for (i = 2, k = 1; (i & QLCNIC_DUMP_MASK_MAX); i <<= 1, k++) + if (i & tmpl_hdr->drv_cap_mask) + dump_size += tmpl_hdr->cap_sizes[k]; + if (!dump_size) + return -EIO; + + fw_dump->data = vzalloc(dump_size); + if (!fw_dump->data) { + dev_info(&adapter->pdev->dev, + "Unable to allocate (%d KB) for fw dump\n", + dump_size/1024); + return -ENOMEM; + } + buffer = fw_dump->data; + fw_dump->size = dump_size; + no_entries = tmpl_hdr->num_entries; + ops_cnt = ARRAY_SIZE(fw_dump_ops); + entry_offset = tmpl_hdr->offset; + tmpl_hdr->sys_info[0] = QLCNIC_DRIVER_VERSION; + tmpl_hdr->sys_info[1] = adapter->fw_version; + + for (i = 0; i < no_entries; i++) { + entry = (struct qlcnic_dump_entry *) ((void *) tmpl_hdr + + entry_offset); + if (!(entry->hdr.mask & tmpl_hdr->drv_cap_mask)) { + entry->hdr.flags |= QLCNIC_DUMP_SKIP; + entry_offset += entry->hdr.offset; + continue; + } + /* Find the handler for this entry */ + ops_index = 0; + while (ops_index < ops_cnt) { + if (entry->hdr.type == fw_dump_ops[ops_index].opcode) + break; + ops_index++; + } + if (ops_index == ops_cnt) { + dev_info(&adapter->pdev->dev, + "Invalid entry type %d, exiting dump\n", + entry->hdr.type); + goto error; + } + /* Collect dump for this entry */ + dump = fw_dump_ops[ops_index].handler(adapter, entry, buffer); + if (dump && !qlcnic_valid_dump_entry(&adapter->pdev->dev, entry, + dump)) + entry->hdr.flags |= QLCNIC_DUMP_SKIP; + buf_offset += entry->hdr.cap_size; + entry_offset += entry->hdr.offset; + buffer = fw_dump->data + buf_offset; + } + if (dump_size != buf_offset) { + dev_info(&adapter->pdev->dev, + "Captured(%d) and expected size(%d) do not match\n", + buf_offset, dump_size); + goto error; + } else { + fw_dump->clr = 1; + snprintf(mesg, sizeof(mesg), "FW dump for device: %d\n", + adapter->pdev->devfn); + dev_info(&adapter->pdev->dev, "Dump data, %d bytes captured\n", + fw_dump->size); + /* Send a udev event to notify availability of FW dump */ + kobject_uevent_env(&adapter->pdev->dev.kobj, KOBJ_CHANGE, msg); + return 0; + } +error: + vfree(fw_dump->data); + return -EINVAL; +} diff --git a/drivers/net/qlcnic/qlcnic_init.c b/drivers/net/qlcnic/qlcnic_init.c index d0f338b..5b8bbcf 100644 --- a/drivers/net/qlcnic/qlcnic_init.c +++ b/drivers/net/qlcnic/qlcnic_init.c @@ -345,7 +345,7 @@ static int qlcnic_wait_rom_done(struct qlcnic_adapter *adapter) } static int do_rom_fast_read(struct qlcnic_adapter *adapter, - int addr, int *valp) + u32 addr, u32 *valp) { QLCWR32(adapter, QLCNIC_ROMUSB_ROM_ADDRESS, addr); QLCWR32(adapter, QLCNIC_ROMUSB_ROM_DUMMY_BYTE_CNT, 0); @@ -398,7 +398,7 @@ qlcnic_rom_fast_read_words(struct qlcnic_adapter *adapter, int addr, return ret; } -int qlcnic_rom_fast_read(struct qlcnic_adapter *adapter, int addr, int *valp) +int qlcnic_rom_fast_read(struct qlcnic_adapter *adapter, u32 addr, u32 *valp) { int ret; diff --git a/drivers/net/qlcnic/qlcnic_main.c b/drivers/net/qlcnic/qlcnic_main.c index d6cc4d4..3ab7d2c 100644 --- a/drivers/net/qlcnic/qlcnic_main.c +++ b/drivers/net/qlcnic/qlcnic_main.c @@ -1343,6 +1343,10 @@ static void qlcnic_free_adapter_resources(struct qlcnic_adapter *adapter) kfree(adapter->recv_ctx); adapter->recv_ctx = NULL; + if (adapter->ahw->fw_dump.tmpl_hdr) { + vfree(adapter->ahw->fw_dump.tmpl_hdr); + adapter->ahw->fw_dump.tmpl_hdr = NULL; + } kfree(adapter->ahw); adapter->ahw = NULL; } @@ -1586,6 +1590,10 @@ qlcnic_probe(struct pci_dev *pdev, const struct pci_device_id *ent) /* This will be reset for mezz cards */ adapter->portnum = adapter->ahw->pci_func; + /* Get FW dump template and store it */ + if (adapter->op_mode != QLCNIC_NON_PRIV_FUNC) + qlcnic_fw_cmd_get_minidump_temp(adapter); + err = qlcnic_get_board_info(adapter); if (err) { dev_err(&pdev->dev, "Error getting board config info.\n"); @@ -2825,6 +2833,8 @@ skip_ack_check: set_bit(__QLCNIC_START_FW, &adapter->state); QLCDB(adapter, DRV, "Restarting fw\n"); qlcnic_idc_debug_info(adapter, 0); + QLCDB(adapter, DRV, "Take FW dump\n"); + qlcnic_dump_fw(adapter); } qlcnic_api_unlock(adapter); @@ -2923,7 +2933,7 @@ qlcnic_set_npar_non_operational(struct qlcnic_adapter *adapter) } /*Transit to RESET state from READY state only */ -static void +void qlcnic_dev_request_reset(struct qlcnic_adapter *adapter) { u32 state; @@ -3515,7 +3525,6 @@ qlcnic_sysfs_write_mem(struct file *filp, struct kobject *kobj, return size; } - static struct bin_attribute bin_attr_crb = { .attr = {.name = "crb", .mode = (S_IRUGO | S_IWUSR)}, .size = 0, -- cgit v0.10.2 From b3c687317ff5d65017ee431de9ccf80ec1552e3e Mon Sep 17 00:00:00 2001 From: Anirban Chakraborty Date: Thu, 12 May 2011 12:48:34 +0000 Subject: qlcnic: Take FW dump via ethtool Driver checks if the previous dump has been cleared before taking the dump. It doesn't take the dump if it is not cleared. Changes from v2: Added lock to protect dump data structures from being mangled while dumping or setting them via ethtool. Signed-off-by: Anirban Chakraborty Signed-off-by: David S. Miller diff --git a/drivers/net/qlcnic/qlcnic_ethtool.c b/drivers/net/qlcnic/qlcnic_ethtool.c index c541461..9efc690 100644 --- a/drivers/net/qlcnic/qlcnic_ethtool.c +++ b/drivers/net/qlcnic/qlcnic_ethtool.c @@ -965,6 +965,84 @@ static void qlcnic_set_msglevel(struct net_device *netdev, u32 msglvl) adapter->msg_enable = msglvl; } +static int +qlcnic_get_dump_flag(struct net_device *netdev, struct ethtool_dump *dump) +{ + struct qlcnic_adapter *adapter = netdev_priv(netdev); + struct qlcnic_fw_dump *fw_dump = &adapter->ahw->fw_dump; + + dump->len = fw_dump->tmpl_hdr->size + fw_dump->size; + dump->flag = fw_dump->tmpl_hdr->drv_cap_mask; + dump->version = adapter->fw_version; + return 0; +} + +static int +qlcnic_get_dump_data(struct net_device *netdev, struct ethtool_dump *dump, + void *buffer) +{ + int i, copy_sz; + u32 *hdr_ptr, *data; + struct qlcnic_adapter *adapter = netdev_priv(netdev); + struct qlcnic_fw_dump *fw_dump = &adapter->ahw->fw_dump; + + if (qlcnic_api_lock(adapter)) + return -EIO; + if (!fw_dump->clr) { + netdev_info(netdev, "Dump not available\n"); + qlcnic_api_unlock(adapter); + return -EINVAL; + } + /* Copy template header first */ + copy_sz = fw_dump->tmpl_hdr->size; + hdr_ptr = (u32 *) fw_dump->tmpl_hdr; + data = (u32 *) buffer; + for (i = 0; i < copy_sz/sizeof(u32); i++) + *data++ = cpu_to_le32(*hdr_ptr++); + + /* Copy captured dump data */ + memcpy(buffer + copy_sz, fw_dump->data, fw_dump->size); + dump->len = copy_sz + fw_dump->size; + dump->flag = fw_dump->tmpl_hdr->drv_cap_mask; + + /* Free dump area once data has been captured */ + vfree(fw_dump->data); + fw_dump->data = NULL; + fw_dump->clr = 0; + qlcnic_api_unlock(adapter); + + return 0; +} + +static int +qlcnic_set_dump(struct net_device *netdev, struct ethtool_dump *val) +{ + int ret = 0; + struct qlcnic_adapter *adapter = netdev_priv(netdev); + struct qlcnic_fw_dump *fw_dump = &adapter->ahw->fw_dump; + + if (val->flag == QLCNIC_FORCE_FW_DUMP_KEY) { + netdev_info(netdev, "Forcing a FW dump\n"); + qlcnic_dev_request_reset(adapter); + } else { + if (val->flag > QLCNIC_DUMP_MASK_MAX || + val->flag < QLCNIC_DUMP_MASK_MIN) { + netdev_info(netdev, + "Invalid dump level: 0x%x\n", val->flag); + ret = -EINVAL; + goto out; + } + if (qlcnic_api_lock(adapter)) + return -EIO; + fw_dump->tmpl_hdr->drv_cap_mask = val->flag & 0xff; + qlcnic_api_unlock(adapter); + netdev_info(netdev, "Driver mask changed to: 0x%x\n", + fw_dump->tmpl_hdr->drv_cap_mask); + } +out: + return ret; +} + const struct ethtool_ops qlcnic_ethtool_ops = { .get_settings = qlcnic_get_settings, .set_settings = qlcnic_set_settings, @@ -991,4 +1069,7 @@ const struct ethtool_ops qlcnic_ethtool_ops = { .set_phys_id = qlcnic_set_led, .set_msglevel = qlcnic_set_msglevel, .get_msglevel = qlcnic_get_msglevel, + .get_dump_flag = qlcnic_get_dump_flag, + .get_dump_data = qlcnic_get_dump_data, + .set_dump = qlcnic_set_dump, }; -- cgit v0.10.2 From 32f5469b5ed27b6403a91b6ca9bc64d144ae3a5d Mon Sep 17 00:00:00 2001 From: Anirban Chakraborty Date: Thu, 12 May 2011 12:48:35 +0000 Subject: qlcnic: Bumped up version number to 5.0.18 Update driver version number Signed-off-by: Anirban Chakraborty Signed-off-by: David S. Miller diff --git a/drivers/net/qlcnic/qlcnic.h b/drivers/net/qlcnic/qlcnic.h index 689adea..480ef5c 100644 --- a/drivers/net/qlcnic/qlcnic.h +++ b/drivers/net/qlcnic/qlcnic.h @@ -36,8 +36,8 @@ #define _QLCNIC_LINUX_MAJOR 5 #define _QLCNIC_LINUX_MINOR 0 -#define _QLCNIC_LINUX_SUBVERSION 17 -#define QLCNIC_LINUX_VERSIONID "5.0.17" +#define _QLCNIC_LINUX_SUBVERSION 18 +#define QLCNIC_LINUX_VERSIONID "5.0.18" #define QLCNIC_DRV_IDC_VER 0x01 #define QLCNIC_DRIVER_VERSION ((_QLCNIC_LINUX_MAJOR << 16) |\ (_QLCNIC_LINUX_MINOR << 8) | (_QLCNIC_LINUX_SUBVERSION)) -- cgit v0.10.2 From 47a150edc2ae734c0f4bf50aa19499e23b9a46f8 Mon Sep 17 00:00:00 2001 From: "Serge E. Hallyn" Date: Fri, 13 May 2011 04:27:54 +0100 Subject: Cache user_ns in struct cred If !CONFIG_USERNS, have current_user_ns() defined to (&init_user_ns). Get rid of _current_user_ns. This requires nsown_capable() to be defined in capability.c rather than as static inline in capability.h, so do that. Request_key needs init_user_ns defined at current_user_ns if !CONFIG_USERNS, so forward-declare that in cred.h if !CONFIG_USERNS at current_user_ns() define. Compile-tested with and without CONFIG_USERNS. Signed-off-by: Serge E. Hallyn [ This makes a huge performance difference for acl_permission_check(), up to 30%. And that is one of the hottest kernel functions for loads that are pathname-lookup heavy. ] Signed-off-by: Linus Torvalds diff --git a/include/linux/capability.h b/include/linux/capability.h index 16ee8b4..d4675af 100644 --- a/include/linux/capability.h +++ b/include/linux/capability.h @@ -546,18 +546,7 @@ extern bool has_capability_noaudit(struct task_struct *t, int cap); extern bool capable(int cap); extern bool ns_capable(struct user_namespace *ns, int cap); extern bool task_ns_capable(struct task_struct *t, int cap); - -/** - * nsown_capable - Check superior capability to one's own user_ns - * @cap: The capability in question - * - * Return true if the current task has the given superior capability - * targeted at its own user namespace. - */ -static inline bool nsown_capable(int cap) -{ - return ns_capable(current_user_ns(), cap); -} +extern bool nsown_capable(int cap); /* audit system wants to get cap info from files as well */ extern int get_vfs_caps_from_disk(const struct dentry *dentry, struct cpu_vfs_cap_data *cpu_caps); diff --git a/include/linux/cred.h b/include/linux/cred.h index 9aeeb0b..be16b61 100644 --- a/include/linux/cred.h +++ b/include/linux/cred.h @@ -146,6 +146,7 @@ struct cred { void *security; /* subjective LSM security */ #endif struct user_struct *user; /* real user ID subscription */ + struct user_namespace *user_ns; /* cached user->user_ns */ struct group_info *group_info; /* supplementary groups for euid/fsgid */ struct rcu_head rcu; /* RCU deletion hook */ }; @@ -354,10 +355,15 @@ static inline void put_cred(const struct cred *_cred) #define current_fsgid() (current_cred_xxx(fsgid)) #define current_cap() (current_cred_xxx(cap_effective)) #define current_user() (current_cred_xxx(user)) -#define _current_user_ns() (current_cred_xxx(user)->user_ns) #define current_security() (current_cred_xxx(security)) -extern struct user_namespace *current_user_ns(void); +#ifdef CONFIG_USER_NS +#define current_user_ns() (current_cred_xxx(user_ns)) +#else +extern struct user_namespace init_user_ns; +#define current_user_ns() (&init_user_ns) +#endif + #define current_uid_gid(_uid, _gid) \ do { \ diff --git a/kernel/capability.c b/kernel/capability.c index bf0c734..32a80e0 100644 --- a/kernel/capability.c +++ b/kernel/capability.c @@ -399,3 +399,15 @@ bool task_ns_capable(struct task_struct *t, int cap) return ns_capable(task_cred_xxx(t, user)->user_ns, cap); } EXPORT_SYMBOL(task_ns_capable); + +/** + * nsown_capable - Check superior capability to one's own user_ns + * @cap: The capability in question + * + * Return true if the current task has the given superior capability + * targeted at its own user namespace. + */ +bool nsown_capable(int cap) +{ + return ns_capable(current_user_ns(), cap); +} diff --git a/kernel/cred.c b/kernel/cred.c index 5557b55..8093c16 100644 --- a/kernel/cred.c +++ b/kernel/cred.c @@ -54,6 +54,7 @@ struct cred init_cred = { .cap_effective = CAP_INIT_EFF_SET, .cap_bset = CAP_INIT_BSET, .user = INIT_USER, + .user_ns = &init_user_ns, .group_info = &init_groups, #ifdef CONFIG_KEYS .tgcred = &init_tgcred, @@ -410,6 +411,11 @@ int copy_creds(struct task_struct *p, unsigned long clone_flags) goto error_put; } + /* cache user_ns in cred. Doesn't need a refcount because it will + * stay pinned by cred->user + */ + new->user_ns = new->user->user_ns; + #ifdef CONFIG_KEYS /* new threads get their own thread keyrings if their parent already * had one */ @@ -741,12 +747,6 @@ int set_create_files_as(struct cred *new, struct inode *inode) } EXPORT_SYMBOL(set_create_files_as); -struct user_namespace *current_user_ns(void) -{ - return _current_user_ns(); -} -EXPORT_SYMBOL(current_user_ns); - #ifdef CONFIG_DEBUG_CREDENTIALS bool creds_are_invalid(const struct cred *cred) -- cgit v0.10.2 From 26cf46be954a2dd391d32eeaf7d07c3a953dcc5a Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Fri, 13 May 2011 11:51:01 -0700 Subject: vfs: micro-optimize acl_permission_check() It's a hot function, and we're better off not mixing types in the mask calculations. The compiler just ends up mixing 16-bit and 32-bit operations, for no good reason. So do everything in 'unsigned int' rather than mixing 'unsigned int' masking with a 'umode_t' (16-bit) mode variable. This, together with the parent commit (47a150edc2ae: "Cache user_ns in struct cred") makes acl_permission_check() much nicer. Signed-off-by: Linus Torvalds diff --git a/fs/namei.c b/fs/namei.c index 54fc993..e3c4f11 100644 --- a/fs/namei.c +++ b/fs/namei.c @@ -179,7 +179,7 @@ EXPORT_SYMBOL(putname); static int acl_permission_check(struct inode *inode, int mask, unsigned int flags, int (*check_acl)(struct inode *inode, int mask, unsigned int flags)) { - umode_t mode = inode->i_mode; + unsigned int mode = inode->i_mode; mask &= MAY_READ | MAY_WRITE | MAY_EXEC; -- cgit v0.10.2 From c5e631a8d4e305a68465b7334efe9875be8b7033 Mon Sep 17 00:00:00 2001 From: Frank Blaschka Date: Thu, 12 May 2011 18:45:01 +0000 Subject: qeth: convert to hw_features part 2 Set rx csum default to hw checksumming again. Remove sysfs interface for rx csum (checksumming) and TSO (large_send). With the new hw_features it does not work to keep the old sysfs interface in parallel. Convert options.checksum_type to new hw_features. Signed-off-by: Frank Blaschka Signed-off-by: David S. Miller diff --git a/drivers/s390/net/qeth_core.h b/drivers/s390/net/qeth_core.h index 8d6146a..a2e6755 100644 --- a/drivers/s390/net/qeth_core.h +++ b/drivers/s390/net/qeth_core.h @@ -639,7 +639,6 @@ struct qeth_card_options { struct qeth_ipa_info adp; /*Adapter parameters*/ struct qeth_routing_info route6; struct qeth_ipa_info ipa6; - enum qeth_checksum_types checksum_type; int broadcast_mode; int macaddr_mode; int fake_broadcast; diff --git a/drivers/s390/net/qeth_core_main.c b/drivers/s390/net/qeth_core_main.c index 85cc531..4dffdbe 100644 --- a/drivers/s390/net/qeth_core_main.c +++ b/drivers/s390/net/qeth_core_main.c @@ -1039,7 +1039,6 @@ static void qeth_set_intial_options(struct qeth_card *card) { card->options.route4.type = NO_ROUTER; card->options.route6.type = NO_ROUTER; - card->options.checksum_type = QETH_CHECKSUM_DEFAULT; card->options.broadcast_mode = QETH_TR_BROADCAST_ALLRINGS; card->options.macaddr_mode = QETH_TR_MACADDR_NONCANONICAL; card->options.fake_broadcast = 0; diff --git a/drivers/s390/net/qeth_core_mpc.h b/drivers/s390/net/qeth_core_mpc.h index 07d5888..d8988dc 100644 --- a/drivers/s390/net/qeth_core_mpc.h +++ b/drivers/s390/net/qeth_core_mpc.h @@ -80,14 +80,6 @@ enum qeth_tr_broadcast_modes { QETH_TR_BROADCAST_LOCAL = 1, }; -/* these values match CHECKSUM_* in include/linux/skbuff.h */ -enum qeth_checksum_types { - SW_CHECKSUMMING = 0, /* TODO: set to bit flag used in IPA Command */ - HW_CHECKSUMMING = 1, - NO_CHECKSUMMING = 2, -}; -#define QETH_CHECKSUM_DEFAULT SW_CHECKSUMMING - /* * Routing stuff */ diff --git a/drivers/s390/net/qeth_l2_main.c b/drivers/s390/net/qeth_l2_main.c index 6fbaacb..8ba4c7e 100644 --- a/drivers/s390/net/qeth_l2_main.c +++ b/drivers/s390/net/qeth_l2_main.c @@ -420,10 +420,7 @@ static int qeth_l2_process_inbound_buffer(struct qeth_card *card, case QETH_HEADER_TYPE_LAYER2: skb->pkt_type = PACKET_HOST; skb->protocol = eth_type_trans(skb, skb->dev); - if (card->options.checksum_type == NO_CHECKSUMMING) - skb->ip_summed = CHECKSUM_UNNECESSARY; - else - skb->ip_summed = CHECKSUM_NONE; + skb->ip_summed = CHECKSUM_NONE; if (skb->protocol == htons(ETH_P_802_2)) *((__u32 *)skb->cb) = ++card->seqno.pkt_seqno; len = skb->len; diff --git a/drivers/s390/net/qeth_l3.h b/drivers/s390/net/qeth_l3.h index e705b27..14a43ae 100644 --- a/drivers/s390/net/qeth_l3.h +++ b/drivers/s390/net/qeth_l3.h @@ -62,8 +62,6 @@ void qeth_l3_del_vipa(struct qeth_card *, enum qeth_prot_versions, const u8 *); int qeth_l3_add_rxip(struct qeth_card *, enum qeth_prot_versions, const u8 *); void qeth_l3_del_rxip(struct qeth_card *card, enum qeth_prot_versions, const u8 *); -int qeth_l3_set_large_send(struct qeth_card *, enum qeth_large_send_types); -int qeth_l3_set_rx_csum(struct qeth_card *, enum qeth_checksum_types); int qeth_l3_is_addr_covered_by_ipato(struct qeth_card *, struct qeth_ipaddr *); #endif /* __QETH_L3_H__ */ diff --git a/drivers/s390/net/qeth_l3_main.c b/drivers/s390/net/qeth_l3_main.c index 1496661..18484b5 100644 --- a/drivers/s390/net/qeth_l3_main.c +++ b/drivers/s390/net/qeth_l3_main.c @@ -1445,34 +1445,30 @@ static int qeth_l3_send_checksum_command(struct qeth_card *card) return 0; } -int qeth_l3_set_rx_csum(struct qeth_card *card, - enum qeth_checksum_types csum_type) +int qeth_l3_set_rx_csum(struct qeth_card *card, int on) { int rc = 0; - if (card->options.checksum_type == HW_CHECKSUMMING) { - if ((csum_type != HW_CHECKSUMMING) && - (card->state != CARD_STATE_DOWN)) { - rc = qeth_l3_send_simple_setassparms(card, - IPA_INBOUND_CHECKSUM, IPA_CMD_ASS_STOP, 0); + if (on) { + if (card->state != CARD_STATE_DOWN) { + if (!qeth_is_supported(card, + IPA_INBOUND_CHECKSUM)) + return -EPERM; + rc = qeth_l3_send_checksum_command(card); if (rc) return -EIO; } card->dev->features |= NETIF_F_RXCSUM; } else { - if (csum_type == HW_CHECKSUMMING) { - if (card->state != CARD_STATE_DOWN) { - if (!qeth_is_supported(card, - IPA_INBOUND_CHECKSUM)) - return -EPERM; - rc = qeth_l3_send_checksum_command(card); - if (rc) - return -EIO; - } + if (card->state != CARD_STATE_DOWN) { + rc = qeth_l3_send_simple_setassparms(card, + IPA_INBOUND_CHECKSUM, IPA_CMD_ASS_STOP, 0); + if (rc) + return -EIO; } card->dev->features &= ~NETIF_F_RXCSUM; } - card->options.checksum_type = csum_type; + return rc; } @@ -1482,32 +1478,34 @@ static int qeth_l3_start_ipa_checksum(struct qeth_card *card) QETH_CARD_TEXT(card, 3, "strtcsum"); - if (card->options.checksum_type == NO_CHECKSUMMING) { - dev_info(&card->gdev->dev, - "Using no checksumming on %s.\n", - QETH_CARD_IFNAME(card)); - return 0; - } - if (card->options.checksum_type == SW_CHECKSUMMING) { - dev_info(&card->gdev->dev, - "Using SW checksumming on %s.\n", - QETH_CARD_IFNAME(card)); - return 0; - } - if (!qeth_is_supported(card, IPA_INBOUND_CHECKSUM)) { - dev_info(&card->gdev->dev, + if (card->dev->features & NETIF_F_RXCSUM) { + /* hw may have changed during offline or recovery */ + if (!qeth_is_supported(card, IPA_INBOUND_CHECKSUM)) { + dev_info(&card->gdev->dev, "Inbound HW Checksumming not " "supported on %s,\ncontinuing " "using Inbound SW Checksumming\n", QETH_CARD_IFNAME(card)); - card->options.checksum_type = SW_CHECKSUMMING; - return 0; - } - rc = qeth_l3_send_checksum_command(card); - if (!rc) - dev_info(&card->gdev->dev, + goto update_feature; + } + + rc = qeth_l3_send_checksum_command(card); + if (!rc) + dev_info(&card->gdev->dev, "HW Checksumming (inbound) enabled\n"); + else + goto update_feature; + } else + dev_info(&card->gdev->dev, + "Using SW checksumming on %s.\n", + QETH_CARD_IFNAME(card)); + return 0; +update_feature: + rtnl_lock(); + card->dev->features &= ~NETIF_F_RXCSUM; + netdev_update_features(card->dev); + rtnl_unlock(); return rc; } @@ -2037,14 +2035,7 @@ static inline int qeth_l3_rebuild_skb(struct qeth_card *card, is_vlan = 1; } - switch (card->options.checksum_type) { - case SW_CHECKSUMMING: - skb->ip_summed = CHECKSUM_NONE; - break; - case NO_CHECKSUMMING: - skb->ip_summed = CHECKSUM_UNNECESSARY; - break; - case HW_CHECKSUMMING: + if (card->dev->features & NETIF_F_RXCSUM) { if ((hdr->hdr.l3.ext_flags & (QETH_HDR_EXT_CSUM_HDR_REQ | QETH_HDR_EXT_CSUM_TRANSP_REQ)) == @@ -2053,7 +2044,8 @@ static inline int qeth_l3_rebuild_skb(struct qeth_card *card, skb->ip_summed = CHECKSUM_UNNECESSARY; else skb->ip_summed = CHECKSUM_NONE; - } + } else + skb->ip_summed = CHECKSUM_NONE; return is_vlan; } @@ -3235,20 +3227,19 @@ static u32 qeth_l3_fix_features(struct net_device *dev, u32 features) static int qeth_l3_set_features(struct net_device *dev, u32 features) { - enum qeth_checksum_types csum_type; struct qeth_card *card = dev->ml_priv; u32 changed = dev->features ^ features; + int on; if (!(changed & NETIF_F_RXCSUM)) return 0; if (features & NETIF_F_RXCSUM) - csum_type = HW_CHECKSUMMING; + on = 1; else - csum_type = SW_CHECKSUMMING; + on = 0; - dev->features = features ^ NETIF_F_RXCSUM; - return qeth_l3_set_rx_csum(card, csum_type); + return qeth_l3_set_rx_csum(card, on); } static const struct ethtool_ops qeth_l3_ethtool_ops = { @@ -3342,6 +3333,12 @@ static int qeth_l3_setup_netdev(struct qeth_card *card) if (!(card->info.unique_id & UNIQUE_ID_NOT_BY_CARD)) card->dev->dev_id = card->info.unique_id & 0xffff; + if (!card->info.guestlan) { + card->dev->hw_features = NETIF_F_SG | + NETIF_F_RXCSUM | NETIF_F_IP_CSUM | + NETIF_F_TSO; + card->dev->features = NETIF_F_RXCSUM; + } } } else if (card->info.type == QETH_CARD_TYPE_IQD) { card->dev = alloc_netdev(0, "hsi%d", ether_setup); @@ -3357,8 +3354,6 @@ static int qeth_l3_setup_netdev(struct qeth_card *card) card->dev->watchdog_timeo = QETH_TX_TIMEOUT; card->dev->mtu = card->info.initial_mtu; SET_ETHTOOL_OPS(card->dev, &qeth_l3_ethtool_ops); - card->dev->hw_features = NETIF_F_SG | NETIF_F_RXCSUM | - NETIF_F_IP_CSUM | NETIF_F_TSO; card->dev->features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX | NETIF_F_HW_VLAN_FILTER; @@ -3382,9 +3377,6 @@ static int qeth_l3_probe_device(struct ccwgroup_device *gdev) card->discipline.output_handler = (qdio_handler_t *) qeth_qdio_output_handler; card->discipline.recover = qeth_l3_recover; - if ((card->info.type == QETH_CARD_TYPE_OSD) || - (card->info.type == QETH_CARD_TYPE_OSX)) - card->options.checksum_type = HW_CHECKSUMMING; return 0; } diff --git a/drivers/s390/net/qeth_l3_sys.c b/drivers/s390/net/qeth_l3_sys.c index bf9f003..cd99210 100644 --- a/drivers/s390/net/qeth_l3_sys.c +++ b/drivers/s390/net/qeth_l3_sys.c @@ -15,16 +15,6 @@ #define QETH_DEVICE_ATTR(_id, _name, _mode, _show, _store) \ struct device_attribute dev_attr_##_id = __ATTR(_name, _mode, _show, _store) -static const char *qeth_l3_get_checksum_str(struct qeth_card *card) -{ - if (card->options.checksum_type == SW_CHECKSUMMING) - return "sw"; - else if (card->options.checksum_type == HW_CHECKSUMMING) - return "hw"; - else - return "no"; -} - static ssize_t qeth_l3_dev_route_show(struct qeth_card *card, struct qeth_routing_info *route, char *buf) { @@ -295,51 +285,6 @@ out: static DEVICE_ATTR(canonical_macaddr, 0644, qeth_l3_dev_canonical_macaddr_show, qeth_l3_dev_canonical_macaddr_store); -static ssize_t qeth_l3_dev_checksum_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct qeth_card *card = dev_get_drvdata(dev); - - if (!card) - return -EINVAL; - - return sprintf(buf, "%s checksumming\n", - qeth_l3_get_checksum_str(card)); -} - -static ssize_t qeth_l3_dev_checksum_store(struct device *dev, - struct device_attribute *attr, const char *buf, size_t count) -{ - struct qeth_card *card = dev_get_drvdata(dev); - enum qeth_checksum_types csum_type; - char *tmp; - int rc = 0; - - if (!card) - return -EINVAL; - - mutex_lock(&card->conf_mutex); - tmp = strsep((char **) &buf, "\n"); - if (!strcmp(tmp, "sw_checksumming")) - csum_type = SW_CHECKSUMMING; - else if (!strcmp(tmp, "hw_checksumming")) - csum_type = HW_CHECKSUMMING; - else if (!strcmp(tmp, "no_checksumming")) - csum_type = NO_CHECKSUMMING; - else { - rc = -EINVAL; - goto out; - } - - rc = qeth_l3_set_rx_csum(card, csum_type); -out: - mutex_unlock(&card->conf_mutex); - return rc ? rc : count; -} - -static DEVICE_ATTR(checksumming, 0644, qeth_l3_dev_checksum_show, - qeth_l3_dev_checksum_store); - static ssize_t qeth_l3_dev_sniffer_show(struct device *dev, struct device_attribute *attr, char *buf) { @@ -402,64 +347,13 @@ out: static DEVICE_ATTR(sniffer, 0644, qeth_l3_dev_sniffer_show, qeth_l3_dev_sniffer_store); -static ssize_t qeth_l3_dev_large_send_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct qeth_card *card = dev_get_drvdata(dev); - - if (!card) - return -EINVAL; - - if (!(card->dev->features & NETIF_F_TSO)) - return sprintf(buf, "%s\n", "no"); - else - return sprintf(buf, "%s\n", "TSO"); -} - -static ssize_t qeth_l3_dev_large_send_store(struct device *dev, - struct device_attribute *attr, const char *buf, size_t count) -{ - struct qeth_card *card; - char *tmp; - int enable; - - if (!card) - return -EINVAL; - tmp = strsep((char **) &buf, "\n"); - if (!strcmp(tmp, "no")) - enable = 0; - else if (!strcmp(tmp, "TSO")) - enable = 1; - else - return -EINVAL; - - rtnl_lock(); - - card = dev_get_drvdata(dev); - - if (enable) - card->dev->wanted_features |= NETIF_F_TSO; - else - card->dev->wanted_features &= ~NETIF_F_TSO; - netdev_update_features(card->dev); - - rtnl_unlock(); - - return count; -} - -static DEVICE_ATTR(large_send, 0644, qeth_l3_dev_large_send_show, - qeth_l3_dev_large_send_store); - static struct attribute *qeth_l3_device_attrs[] = { &dev_attr_route4.attr, &dev_attr_route6.attr, &dev_attr_fake_broadcast.attr, &dev_attr_broadcast_mode.attr, &dev_attr_canonical_macaddr.attr, - &dev_attr_checksumming.attr, &dev_attr_sniffer.attr, - &dev_attr_large_send.attr, NULL, }; -- cgit v0.10.2 From 1da74b1c10062eff5f67accb3bcb27fa329a55d6 Mon Sep 17 00:00:00 2001 From: Frank Blaschka Date: Thu, 12 May 2011 18:45:02 +0000 Subject: qeth: add OSA concurrent hardware trap This patch improves FFDC (first failure data capture) by requesting a hardware trace in case the device driver, the hardware or a user detects an error. Signed-off-by: Frank Blaschka Signed-off-by: David S. Miller diff --git a/drivers/s390/net/qeth_core.h b/drivers/s390/net/qeth_core.h index a2e6755..55c6aa1 100644 --- a/drivers/s390/net/qeth_core.h +++ b/drivers/s390/net/qeth_core.h @@ -631,6 +631,8 @@ struct qeth_card_info { __u32 csum_mask; __u32 tx_csum_mask; enum qeth_ipa_promisc_modes promisc_mode; + __u32 diagass_support; + __u32 hwtrap; }; struct qeth_card_options { @@ -752,6 +754,14 @@ struct qeth_card_list_struct { rwlock_t rwlock; }; +struct qeth_trap_id { + __u16 lparnr; + char vmname[8]; + __u8 chpid; + __u8 ssid; + __u16 devno; +} __packed; + /*some helper functions*/ #define QETH_CARD_IFNAME(card) (((card)->dev)? (card)->dev->name : "") @@ -786,6 +796,12 @@ static inline void qeth_put_buffer_pool_entry(struct qeth_card *card, list_add_tail(&entry->list, &card->qdio.in_buf_pool.entry_list); } +static inline int qeth_is_diagass_supported(struct qeth_card *card, + enum qeth_diags_cmds cmd) +{ + return card->info.diagass_support & (__u32)cmd; +} + extern struct ccwgroup_driver qeth_l2_ccwgroup_driver; extern struct ccwgroup_driver qeth_l3_ccwgroup_driver; const char *qeth_get_cardname_short(struct qeth_card *); @@ -871,6 +887,8 @@ void qeth_dbf_longtext(debug_info_t *id, int level, char *text, ...); int qeth_core_ethtool_get_settings(struct net_device *, struct ethtool_cmd *); int qeth_set_access_ctrl_online(struct qeth_card *card); int qeth_hdr_chk_and_bounce(struct sk_buff *, int); +int qeth_hw_trap(struct qeth_card *, enum qeth_diags_trap_action); +int qeth_query_ipassists(struct qeth_card *, enum qeth_prot_versions prot); /* exports for OSN */ int qeth_osn_assist(struct net_device *, void *, int); diff --git a/drivers/s390/net/qeth_core_main.c b/drivers/s390/net/qeth_core_main.c index 4dffdbe..92e37f7 100644 --- a/drivers/s390/net/qeth_core_main.c +++ b/drivers/s390/net/qeth_core_main.c @@ -24,6 +24,7 @@ #include #include +#include #include "qeth_core.h" @@ -349,6 +350,8 @@ static struct qeth_ipa_cmd *qeth_check_ipa_data(struct qeth_card *card, card->info.chpid); netif_carrier_on(card->dev); card->lan_online = 1; + if (card->info.hwtrap) + card->info.hwtrap = 2; qeth_schedule_recovery(card); return NULL; case IPA_CMD_MODCCID: @@ -2573,6 +2576,142 @@ int qeth_query_setadapterparms(struct qeth_card *card) } EXPORT_SYMBOL_GPL(qeth_query_setadapterparms); +static int qeth_query_ipassists_cb(struct qeth_card *card, + struct qeth_reply *reply, unsigned long data) +{ + struct qeth_ipa_cmd *cmd; + + QETH_DBF_TEXT(SETUP, 2, "qipasscb"); + + cmd = (struct qeth_ipa_cmd *) data; + if (cmd->hdr.prot_version == QETH_PROT_IPV4) { + card->options.ipa4.supported_funcs = cmd->hdr.ipa_supported; + card->options.ipa4.enabled_funcs = cmd->hdr.ipa_enabled; + } else { + card->options.ipa6.supported_funcs = cmd->hdr.ipa_supported; + card->options.ipa6.enabled_funcs = cmd->hdr.ipa_enabled; + } + QETH_DBF_TEXT(SETUP, 2, "suppenbl"); + QETH_DBF_TEXT_(SETUP, 2, "%x", cmd->hdr.ipa_supported); + QETH_DBF_TEXT_(SETUP, 2, "%x", cmd->hdr.ipa_enabled); + return 0; +} + +int qeth_query_ipassists(struct qeth_card *card, enum qeth_prot_versions prot) +{ + int rc; + struct qeth_cmd_buffer *iob; + + QETH_DBF_TEXT_(SETUP, 2, "qipassi%i", prot); + iob = qeth_get_ipacmd_buffer(card, IPA_CMD_QIPASSIST, prot); + rc = qeth_send_ipa_cmd(card, iob, qeth_query_ipassists_cb, NULL); + return rc; +} +EXPORT_SYMBOL_GPL(qeth_query_ipassists); + +static int qeth_query_setdiagass_cb(struct qeth_card *card, + struct qeth_reply *reply, unsigned long data) +{ + struct qeth_ipa_cmd *cmd; + __u16 rc; + + cmd = (struct qeth_ipa_cmd *)data; + rc = cmd->hdr.return_code; + if (rc) + QETH_CARD_TEXT_(card, 2, "diagq:%x", rc); + else + card->info.diagass_support = cmd->data.diagass.ext; + return 0; +} + +static int qeth_query_setdiagass(struct qeth_card *card) +{ + struct qeth_cmd_buffer *iob; + struct qeth_ipa_cmd *cmd; + + QETH_DBF_TEXT(SETUP, 2, "qdiagass"); + iob = qeth_get_ipacmd_buffer(card, IPA_CMD_SET_DIAG_ASS, 0); + cmd = (struct qeth_ipa_cmd *)(iob->data+IPA_PDU_HEADER_SIZE); + cmd->data.diagass.subcmd_len = 16; + cmd->data.diagass.subcmd = QETH_DIAGS_CMD_QUERY; + return qeth_send_ipa_cmd(card, iob, qeth_query_setdiagass_cb, NULL); +} + +static void qeth_get_trap_id(struct qeth_card *card, struct qeth_trap_id *tid) +{ + unsigned long info = get_zeroed_page(GFP_KERNEL); + struct sysinfo_2_2_2 *info222 = (struct sysinfo_2_2_2 *)info; + struct sysinfo_3_2_2 *info322 = (struct sysinfo_3_2_2 *)info; + struct ccw_dev_id ccwid; + int level, rc; + + tid->chpid = card->info.chpid; + ccw_device_get_id(CARD_RDEV(card), &ccwid); + tid->ssid = ccwid.ssid; + tid->devno = ccwid.devno; + if (!info) + return; + + rc = stsi(NULL, 0, 0, 0); + if (rc == -ENOSYS) + level = rc; + else + level = (((unsigned int) rc) >> 28); + + if ((level >= 2) && (stsi(info222, 2, 2, 2) != -ENOSYS)) + tid->lparnr = info222->lpar_number; + + if ((level >= 3) && (stsi(info322, 3, 2, 2) != -ENOSYS)) { + EBCASC(info322->vm[0].name, sizeof(info322->vm[0].name)); + memcpy(tid->vmname, info322->vm[0].name, sizeof(tid->vmname)); + } + free_page(info); + return; +} + +static int qeth_hw_trap_cb(struct qeth_card *card, + struct qeth_reply *reply, unsigned long data) +{ + struct qeth_ipa_cmd *cmd; + __u16 rc; + + cmd = (struct qeth_ipa_cmd *)data; + rc = cmd->hdr.return_code; + if (rc) + QETH_CARD_TEXT_(card, 2, "trapc:%x", rc); + return 0; +} + +int qeth_hw_trap(struct qeth_card *card, enum qeth_diags_trap_action action) +{ + struct qeth_cmd_buffer *iob; + struct qeth_ipa_cmd *cmd; + + QETH_DBF_TEXT(SETUP, 2, "diagtrap"); + iob = qeth_get_ipacmd_buffer(card, IPA_CMD_SET_DIAG_ASS, 0); + cmd = (struct qeth_ipa_cmd *)(iob->data+IPA_PDU_HEADER_SIZE); + cmd->data.diagass.subcmd_len = 80; + cmd->data.diagass.subcmd = QETH_DIAGS_CMD_TRAP; + cmd->data.diagass.type = 1; + cmd->data.diagass.action = action; + switch (action) { + case QETH_DIAGS_TRAP_ARM: + cmd->data.diagass.options = 0x0003; + cmd->data.diagass.ext = 0x00010000 + + sizeof(struct qeth_trap_id); + qeth_get_trap_id(card, + (struct qeth_trap_id *)cmd->data.diagass.cdata); + break; + case QETH_DIAGS_TRAP_DISARM: + cmd->data.diagass.options = 0x0001; + break; + case QETH_DIAGS_TRAP_CAPTURE: + break; + } + return qeth_send_ipa_cmd(card, iob, qeth_hw_trap_cb, NULL); +} +EXPORT_SYMBOL_GPL(qeth_hw_trap); + int qeth_check_qdio_errors(struct qeth_card *card, struct qdio_buffer *buf, unsigned int qdio_error, const char *dbftext) { @@ -3983,6 +4122,15 @@ retriable: QETH_DBF_TEXT_(SETUP, 2, "5err%d", rc); goto out; } + + card->options.ipa4.supported_funcs = 0; + card->options.adp.supported_funcs = 0; + card->info.diagass_support = 0; + qeth_query_ipassists(card, QETH_PROT_IPV4); + if (qeth_is_supported(card, IPA_SETADAPTERPARMS)) + qeth_query_setadapterparms(card); + if (qeth_adp_supported(card, IPA_SETADP_SET_DIAG_ASSIST)) + qeth_query_setdiagass(card); return 0; out: dev_warn(&card->gdev->dev, "The qeth device driver failed to recover " diff --git a/drivers/s390/net/qeth_core_mpc.h b/drivers/s390/net/qeth_core_mpc.h index d8988dc..e5a9d1c 100644 --- a/drivers/s390/net/qeth_core_mpc.h +++ b/drivers/s390/net/qeth_core_mpc.h @@ -448,6 +448,12 @@ enum qeth_diags_trace_cmds { QETH_DIAGS_CMD_TRACE_QUERY = 0x0010, }; +enum qeth_diags_trap_action { + QETH_DIAGS_TRAP_ARM = 0x01, + QETH_DIAGS_TRAP_DISARM = 0x02, + QETH_DIAGS_TRAP_CAPTURE = 0x04, +}; + struct qeth_ipacmd_diagass { __u32 host_tod2; __u32:32; @@ -457,7 +463,8 @@ struct qeth_ipacmd_diagass { __u8 type; __u8 action; __u16 options; - __u32:32; + __u32 ext; + __u8 cdata[64]; } __attribute__ ((packed)); /* Header for each IPA command */ diff --git a/drivers/s390/net/qeth_core_sys.c b/drivers/s390/net/qeth_core_sys.c index b5e967c..0a8e86c 100644 --- a/drivers/s390/net/qeth_core_sys.c +++ b/drivers/s390/net/qeth_core_sys.c @@ -530,6 +530,66 @@ out: static DEVICE_ATTR(isolation, 0644, qeth_dev_isolation_show, qeth_dev_isolation_store); +static ssize_t qeth_hw_trap_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct qeth_card *card = dev_get_drvdata(dev); + + if (!card) + return -EINVAL; + if (card->info.hwtrap) + return snprintf(buf, 5, "arm\n"); + else + return snprintf(buf, 8, "disarm\n"); +} + +static ssize_t qeth_hw_trap_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + struct qeth_card *card = dev_get_drvdata(dev); + int rc = 0; + char *tmp, *curtoken; + int state = 0; + curtoken = (char *)buf; + + if (!card) + return -EINVAL; + + mutex_lock(&card->conf_mutex); + if (card->state == CARD_STATE_SOFTSETUP || card->state == CARD_STATE_UP) + state = 1; + tmp = strsep(&curtoken, "\n"); + + if (!strcmp(tmp, "arm") && !card->info.hwtrap) { + if (state) { + if (qeth_is_diagass_supported(card, + QETH_DIAGS_CMD_TRAP)) { + rc = qeth_hw_trap(card, QETH_DIAGS_TRAP_ARM); + if (!rc) + card->info.hwtrap = 1; + } else + rc = -EINVAL; + } else + card->info.hwtrap = 1; + } else if (!strcmp(tmp, "disarm") && card->info.hwtrap) { + if (state) { + rc = qeth_hw_trap(card, QETH_DIAGS_TRAP_DISARM); + if (!rc) + card->info.hwtrap = 0; + } else + card->info.hwtrap = 0; + } else if (!strcmp(tmp, "trap") && state && card->info.hwtrap) + rc = qeth_hw_trap(card, QETH_DIAGS_TRAP_CAPTURE); + else + rc = -EINVAL; + + mutex_unlock(&card->conf_mutex); + return rc ? rc : count; +} + +static DEVICE_ATTR(hw_trap, 0644, qeth_hw_trap_show, + qeth_hw_trap_store); + static ssize_t qeth_dev_blkt_show(char *buf, struct qeth_card *card, int value) { @@ -653,6 +713,7 @@ static struct attribute *qeth_device_attrs[] = { &dev_attr_performance_stats.attr, &dev_attr_layer2.attr, &dev_attr_isolation.attr, + &dev_attr_hw_trap.attr, NULL, }; diff --git a/drivers/s390/net/qeth_l2_main.c b/drivers/s390/net/qeth_l2_main.c index 8ba4c7e..b70b47f 100644 --- a/drivers/s390/net/qeth_l2_main.c +++ b/drivers/s390/net/qeth_l2_main.c @@ -876,6 +876,7 @@ static int qeth_l2_probe_device(struct ccwgroup_device *gdev) INIT_LIST_HEAD(&card->vid_list); INIT_LIST_HEAD(&card->mc_list); card->options.layer2 = 1; + card->info.hwtrap = 0; card->discipline.start_poll = qeth_qdio_start_poll; card->discipline.input_handler = (qdio_handler_t *) qeth_qdio_input_handler; @@ -994,6 +995,13 @@ static int __qeth_l2_set_online(struct ccwgroup_device *gdev, int recovery_mode) if (card->info.type != QETH_CARD_TYPE_OSN) qeth_l2_send_setmac(card, &card->dev->dev_addr[0]); + if (qeth_is_diagass_supported(card, QETH_DIAGS_CMD_TRAP)) { + if (card->info.hwtrap && + qeth_hw_trap(card, QETH_DIAGS_TRAP_ARM)) + card->info.hwtrap = 0; + } else + card->info.hwtrap = 0; + card->state = CARD_STATE_HARDSETUP; memset(&card->rx, 0, sizeof(struct qeth_rx)); qeth_print_status_message(card); @@ -1092,6 +1100,10 @@ static int __qeth_l2_set_offline(struct ccwgroup_device *cgdev, if (card->dev && netif_carrier_ok(card->dev)) netif_carrier_off(card->dev); recover_flag = card->state; + if ((!recovery_mode && card->info.hwtrap) || card->info.hwtrap == 2) { + qeth_hw_trap(card, QETH_DIAGS_TRAP_DISARM); + card->info.hwtrap = 1; + } qeth_l2_stop_card(card, recovery_mode); rc = ccw_device_set_offline(CARD_DDEV(card)); rc2 = ccw_device_set_offline(CARD_WDEV(card)); @@ -1157,6 +1169,8 @@ static void __exit qeth_l2_exit(void) static void qeth_l2_shutdown(struct ccwgroup_device *gdev) { struct qeth_card *card = dev_get_drvdata(&gdev->dev); + if ((gdev->state == CCWGROUP_ONLINE) && card->info.hwtrap) + qeth_hw_trap(card, QETH_DIAGS_TRAP_DISARM); qeth_qdio_clear_card(card, 0); qeth_clear_qdio_buffers(card); } @@ -1172,6 +1186,8 @@ static int qeth_l2_pm_suspend(struct ccwgroup_device *gdev) if (gdev->state == CCWGROUP_OFFLINE) return 0; if (card->state == CARD_STATE_UP) { + if (card->info.hwtrap) + qeth_hw_trap(card, QETH_DIAGS_TRAP_DISARM); __qeth_l2_set_offline(card->gdev, 1); } else __qeth_l2_set_offline(card->gdev, 0); diff --git a/drivers/s390/net/qeth_l3_main.c b/drivers/s390/net/qeth_l3_main.c index 18484b5..bbe7e1c 100644 --- a/drivers/s390/net/qeth_l3_main.c +++ b/drivers/s390/net/qeth_l3_main.c @@ -1277,39 +1277,6 @@ static int qeth_l3_start_ipa_multicast(struct qeth_card *card) return rc; } -static int qeth_l3_query_ipassists_cb(struct qeth_card *card, - struct qeth_reply *reply, unsigned long data) -{ - struct qeth_ipa_cmd *cmd; - - QETH_DBF_TEXT(SETUP, 2, "qipasscb"); - - cmd = (struct qeth_ipa_cmd *) data; - if (cmd->hdr.prot_version == QETH_PROT_IPV4) { - card->options.ipa4.supported_funcs = cmd->hdr.ipa_supported; - card->options.ipa4.enabled_funcs = cmd->hdr.ipa_enabled; - } else { - card->options.ipa6.supported_funcs = cmd->hdr.ipa_supported; - card->options.ipa6.enabled_funcs = cmd->hdr.ipa_enabled; - } - QETH_DBF_TEXT(SETUP, 2, "suppenbl"); - QETH_DBF_TEXT_(SETUP, 2, "%x", cmd->hdr.ipa_supported); - QETH_DBF_TEXT_(SETUP, 2, "%x", cmd->hdr.ipa_enabled); - return 0; -} - -static int qeth_l3_query_ipassists(struct qeth_card *card, - enum qeth_prot_versions prot) -{ - int rc; - struct qeth_cmd_buffer *iob; - - QETH_DBF_TEXT_(SETUP, 2, "qipassi%i", prot); - iob = qeth_get_ipacmd_buffer(card, IPA_CMD_QIPASSIST, prot); - rc = qeth_send_ipa_cmd(card, iob, qeth_l3_query_ipassists_cb, NULL); - return rc; -} - #ifdef CONFIG_QETH_IPV6 static int qeth_l3_softsetup_ipv6(struct qeth_card *card) { @@ -1320,7 +1287,7 @@ static int qeth_l3_softsetup_ipv6(struct qeth_card *card) if (card->info.type == QETH_CARD_TYPE_IQD) goto out; - rc = qeth_l3_query_ipassists(card, QETH_PROT_IPV6); + rc = qeth_query_ipassists(card, QETH_PROT_IPV6); if (rc) { dev_err(&card->gdev->dev, "Activating IPv6 support for %s failed\n", @@ -3371,6 +3338,7 @@ static int qeth_l3_probe_device(struct ccwgroup_device *gdev) qeth_l3_create_device_attributes(&gdev->dev); card->options.layer2 = 0; + card->info.hwtrap = 0; card->discipline.start_poll = qeth_qdio_start_poll; card->discipline.input_handler = (qdio_handler_t *) qeth_qdio_input_handler; @@ -3422,13 +3390,18 @@ static int __qeth_l3_set_online(struct ccwgroup_device *gdev, int recovery_mode) goto out_remove; } - qeth_l3_query_ipassists(card, QETH_PROT_IPV4); - if (!card->dev && qeth_l3_setup_netdev(card)) { rc = -ENODEV; goto out_remove; } + if (qeth_is_diagass_supported(card, QETH_DIAGS_CMD_TRAP)) { + if (card->info.hwtrap && + qeth_hw_trap(card, QETH_DIAGS_TRAP_ARM)) + card->info.hwtrap = 0; + } else + card->info.hwtrap = 0; + card->state = CARD_STATE_HARDSETUP; memset(&card->rx, 0, sizeof(struct qeth_rx)); qeth_print_status_message(card); @@ -3530,6 +3503,10 @@ static int __qeth_l3_set_offline(struct ccwgroup_device *cgdev, if (card->dev && netif_carrier_ok(card->dev)) netif_carrier_off(card->dev); recover_flag = card->state; + if ((!recovery_mode && card->info.hwtrap) || card->info.hwtrap == 2) { + qeth_hw_trap(card, QETH_DIAGS_TRAP_DISARM); + card->info.hwtrap = 1; + } qeth_l3_stop_card(card, recovery_mode); rc = ccw_device_set_offline(CARD_DDEV(card)); rc2 = ccw_device_set_offline(CARD_WDEV(card)); @@ -3585,6 +3562,8 @@ static int qeth_l3_recover(void *ptr) static void qeth_l3_shutdown(struct ccwgroup_device *gdev) { struct qeth_card *card = dev_get_drvdata(&gdev->dev); + if ((gdev->state == CCWGROUP_ONLINE) && card->info.hwtrap) + qeth_hw_trap(card, QETH_DIAGS_TRAP_DISARM); qeth_qdio_clear_card(card, 0); qeth_clear_qdio_buffers(card); } @@ -3600,6 +3579,8 @@ static int qeth_l3_pm_suspend(struct ccwgroup_device *gdev) if (gdev->state == CCWGROUP_OFFLINE) return 0; if (card->state == CARD_STATE_UP) { + if (card->info.hwtrap) + qeth_hw_trap(card, QETH_DIAGS_TRAP_DISARM); __qeth_l3_set_offline(card->gdev, 1); } else __qeth_l3_set_offline(card->gdev, 0); -- cgit v0.10.2 From 3e70b3b8141c1a09e3a8809d94a0157756cb8f60 Mon Sep 17 00:00:00 2001 From: Sebastian Ott Date: Thu, 12 May 2011 18:45:03 +0000 Subject: qeth: add owner to ccw driver Fill in the owner of qeth's ccw device driver. Signed-off-by: Sebastian Ott Signed-off-by: Frank Blaschka Signed-off-by: David S. Miller diff --git a/drivers/s390/net/qeth_core_main.c b/drivers/s390/net/qeth_core_main.c index 92e37f7..503678a 100644 --- a/drivers/s390/net/qeth_core_main.c +++ b/drivers/s390/net/qeth_core_main.c @@ -4041,6 +4041,7 @@ MODULE_DEVICE_TABLE(ccw, qeth_ids); static struct ccw_driver qeth_ccw_driver = { .driver = { + .owner = THIS_MODULE, .name = "qeth", }, .ids = qeth_ids, -- cgit v0.10.2 From 38ed18ff5ed170a68f334c2362735c1268cec81b Mon Sep 17 00:00:00 2001 From: Heiko Carstens Date: Thu, 12 May 2011 18:45:04 +0000 Subject: claw: remove unused return code handling Remove unused return code handling. The claw driver is mostly dead, so just make sure it keeps compiling without warnings. Signed-off-by: Heiko Carstens Signed-off-by: Frank Blaschka Signed-off-by: David S. Miller diff --git a/drivers/s390/net/claw.c b/drivers/s390/net/claw.c index da8aa75..f1fa248 100644 --- a/drivers/s390/net/claw.c +++ b/drivers/s390/net/claw.c @@ -845,12 +845,10 @@ claw_irq_tasklet ( unsigned long data ) { struct chbk * p_ch; struct net_device *dev; - struct claw_privbk * privptr; p_ch = (struct chbk *) data; dev = (struct net_device *)p_ch->ndev; CLAW_DBF_TEXT(4, trace, "IRQtask"); - privptr = (struct claw_privbk *)dev->ml_priv; unpack_read(dev); clear_bit(CLAW_BH_ACTIVE, (void *)&p_ch->flag_a); CLAW_DBF_TEXT(4, trace, "TskletXt"); @@ -1026,7 +1024,6 @@ claw_write_next ( struct chbk * p_ch ) struct net_device *dev; struct claw_privbk *privptr=NULL; struct sk_buff *pk_skb; - int rc; CLAW_DBF_TEXT(4, trace, "claw_wrt"); if (p_ch->claw_state == CLAW_STOP) @@ -1038,7 +1035,7 @@ claw_write_next ( struct chbk * p_ch ) !skb_queue_empty(&p_ch->collect_queue)) { pk_skb = claw_pack_skb(privptr); while (pk_skb != NULL) { - rc = claw_hw_tx( pk_skb, dev,1); + claw_hw_tx(pk_skb, dev, 1); if (privptr->write_free_count > 0) { pk_skb = claw_pack_skb(privptr); } else @@ -1322,15 +1319,12 @@ claw_hw_tx(struct sk_buff *skb, struct net_device *dev, long linkid) unsigned char *pDataAddress; struct endccw *pEnd; struct ccw1 tempCCW; - struct chbk *p_ch; struct claw_env *p_env; - int lock; struct clawph *pk_head; struct chbk *ch; CLAW_DBF_TEXT(4, trace, "hw_tx"); privptr = (struct claw_privbk *)(dev->ml_priv); - p_ch = (struct chbk *)&privptr->channel[WRITE_CHANNEL]; p_env =privptr->p_env; claw_free_wrt_buf(dev); /* Clean up free chain if posible */ /* scan the write queue to free any completed write packets */ @@ -1511,12 +1505,6 @@ claw_hw_tx(struct sk_buff *skb, struct net_device *dev, long linkid) } /* endif (p_first_ccw!=NULL) */ dev_kfree_skb_any(skb); - if (linkid==0) { - lock=LOCK_NO; - } - else { - lock=LOCK_YES; - } claw_strt_out_IO(dev ); /* if write free count is zero , set NOBUFFER */ if (privptr->write_free_count==0) { @@ -2821,15 +2809,11 @@ claw_free_wrt_buf( struct net_device *dev ) { struct claw_privbk *privptr = (struct claw_privbk *)dev->ml_priv; - struct ccwbk*p_first_ccw; - struct ccwbk*p_last_ccw; struct ccwbk*p_this_ccw; struct ccwbk*p_next_ccw; CLAW_DBF_TEXT(4, trace, "freewrtb"); /* scan the write queue to free any completed write packets */ - p_first_ccw=NULL; - p_last_ccw=NULL; p_this_ccw=privptr->p_write_active_first; while ( (p_this_ccw!=NULL) && (p_this_ccw->header.flag!=CLAW_PENDING)) { @@ -3072,7 +3056,7 @@ claw_shutdown_device(struct ccwgroup_device *cgdev) { struct claw_privbk *priv; struct net_device *ndev; - int ret; + int ret = 0; CLAW_DBF_TEXT_(2, setup, "%s", dev_name(&cgdev->dev)); priv = dev_get_drvdata(&cgdev->dev); @@ -3095,7 +3079,7 @@ claw_shutdown_device(struct ccwgroup_device *cgdev) } ccw_device_set_offline(cgdev->cdev[1]); ccw_device_set_offline(cgdev->cdev[0]); - return 0; + return ret; } static void -- cgit v0.10.2 From 424f73b3ecc41367336ce75cc489c1e373c421fc Mon Sep 17 00:00:00 2001 From: Heiko Carstens Date: Thu, 12 May 2011 18:45:05 +0000 Subject: lcs: get rid of compile warning -Wunused-but-set-variable generates a compile warning for lcs' tasklet function. Invoked functions contain already error handling; thus additional return code checking is not needed here. Signed-off-by: Heiko Carstens Signed-off-by: Frank Blaschka Signed-off-by: David S. Miller diff --git a/drivers/s390/net/lcs.c b/drivers/s390/net/lcs.c index 49d1cfc..c3b8064 100644 --- a/drivers/s390/net/lcs.c +++ b/drivers/s390/net/lcs.c @@ -1483,7 +1483,6 @@ lcs_tasklet(unsigned long data) struct lcs_channel *channel; struct lcs_buffer *iob; int buf_idx; - int rc; channel = (struct lcs_channel *) data; LCS_DBF_TEXT_(5, trace, "tlet%s", dev_name(&channel->ccwdev->dev)); @@ -1500,14 +1499,11 @@ lcs_tasklet(unsigned long data) channel->buf_idx = buf_idx; if (channel->state == LCS_CH_STATE_STOPPED) - // FIXME: what if rc != 0 ?? - rc = lcs_start_channel(channel); + lcs_start_channel(channel); spin_lock_irqsave(get_ccwdev_lock(channel->ccwdev), flags); if (channel->state == LCS_CH_STATE_SUSPENDED && - channel->iob[channel->io_idx].state == LCS_BUF_STATE_READY) { - // FIXME: what if rc != 0 ?? - rc = __lcs_resume_channel(channel); - } + channel->iob[channel->io_idx].state == LCS_BUF_STATE_READY) + __lcs_resume_channel(channel); spin_unlock_irqrestore(get_ccwdev_lock(channel->ccwdev), flags); /* Something happened on the channel. Wake up waiters. */ -- cgit v0.10.2 From ff2aed7da18781bb32ce675e4621475e4baae08f Mon Sep 17 00:00:00 2001 From: Ursula Braun Date: Thu, 12 May 2011 18:45:06 +0000 Subject: ctcm: get rid of compile warning -Wunused-but-set-variable generates compile warnings. The affected variables are removed. Signed-off-by: Ursula Braun Signed-off-by: Frank Blaschka Signed-off-by: David S. Miller diff --git a/drivers/s390/net/ctcm_main.c b/drivers/s390/net/ctcm_main.c index c189296..426787e 100644 --- a/drivers/s390/net/ctcm_main.c +++ b/drivers/s390/net/ctcm_main.c @@ -672,7 +672,6 @@ static int ctcmpc_transmit_skb(struct channel *ch, struct sk_buff *skb) int ccw_idx; unsigned long hi; unsigned long saveflags = 0; /* avoids compiler warning */ - __u16 block_len; CTCM_PR_DEBUG("Enter %s: %s, cp=%i ch=0x%p id=%s state=%s\n", __func__, dev->name, smp_processor_id(), ch, @@ -719,7 +718,6 @@ static int ctcmpc_transmit_skb(struct channel *ch, struct sk_buff *skb) */ atomic_inc(&skb->users); - block_len = skb->len + TH_HEADER_LENGTH + PDU_HEADER_LENGTH; /* * IDAL support in CTCM is broken, so we have to * care about skb's above 2G ourselves. diff --git a/drivers/s390/net/ctcm_mpc.c b/drivers/s390/net/ctcm_mpc.c index b64881f..da4c747 100644 --- a/drivers/s390/net/ctcm_mpc.c +++ b/drivers/s390/net/ctcm_mpc.c @@ -653,7 +653,6 @@ static void ctcmpc_send_sweep_resp(struct channel *rch) struct net_device *dev = rch->netdev; struct ctcm_priv *priv = dev->ml_priv; struct mpc_group *grp = priv->mpcg; - int rc = 0; struct th_sweep *header; struct sk_buff *sweep_skb; struct channel *ch = priv->channel[CTCM_WRITE]; @@ -665,16 +664,14 @@ static void ctcmpc_send_sweep_resp(struct channel *rch) CTCM_DBF_TEXT_(MPC_ERROR, CTC_DBF_ERROR, "%s(%s): sweep_skb allocation ERROR\n", CTCM_FUNTAIL, rch->id); - rc = -ENOMEM; - goto done; + goto done; } header = kmalloc(sizeof(struct th_sweep), gfp_type()); if (!header) { dev_kfree_skb_any(sweep_skb); - rc = -ENOMEM; - goto done; + goto done; } header->th.th_seg = 0x00 ; @@ -1370,8 +1367,7 @@ static void mpc_action_go_inop(fsm_instance *fi, int event, void *arg) struct net_device *dev = arg; struct ctcm_priv *priv; struct mpc_group *grp; - int rc = 0; - struct channel *wch, *rch; + struct channel *wch; BUG_ON(dev == NULL); CTCM_PR_DEBUG("Enter %s: %s\n", __func__, dev->name); @@ -1396,7 +1392,6 @@ static void mpc_action_go_inop(fsm_instance *fi, int event, void *arg) fsm_deltimer(&priv->restart_timer); wch = priv->channel[CTCM_WRITE]; - rch = priv->channel[CTCM_READ]; switch (grp->saved_state) { case MPCG_STATE_RESET: @@ -1435,7 +1430,7 @@ static void mpc_action_go_inop(fsm_instance *fi, int event, void *arg) if (grp->send_qllc_disc == 1) { grp->send_qllc_disc = 0; - rc = mpc_send_qllc_discontact(dev); + mpc_send_qllc_discontact(dev); } /* DO NOT issue DEV_EVENT_STOP directly out of this code */ -- cgit v0.10.2 From 5db79c0679e542a156de54e97be8901aeaa7638a Mon Sep 17 00:00:00 2001 From: Ursula Braun Date: Thu, 12 May 2011 18:45:07 +0000 Subject: iucv: get rid of compile warning -Wunused-but-set-variable generates a compile warning. The affected variable is removed. Signed-off-by: Ursula Braun Signed-off-by: Frank Blaschka Signed-off-by: David S. Miller diff --git a/net/iucv/iucv.c b/net/iucv/iucv.c index 8f156bd..6c1483f 100644 --- a/net/iucv/iucv.c +++ b/net/iucv/iucv.c @@ -828,14 +828,14 @@ EXPORT_SYMBOL(iucv_unregister); static int iucv_reboot_event(struct notifier_block *this, unsigned long event, void *ptr) { - int i, rc; + int i; get_online_cpus(); on_each_cpu(iucv_block_cpu, NULL, 1); preempt_disable(); for (i = 0; i < iucv_max_pathid; i++) { if (iucv_path_table[i]) - rc = iucv_sever_pathid(i, NULL); + iucv_sever_pathid(i, NULL); } preempt_enable(); put_online_cpus(); -- cgit v0.10.2 From 9f6298a6ca38e251aa72a6035a8a36a52cf94536 Mon Sep 17 00:00:00 2001 From: Ursula Braun Date: Thu, 12 May 2011 18:45:08 +0000 Subject: af_iucv: get rid of compile warning -Wunused-but-set-variable generates compile warnings. The affected variables are removed. Signed-off-by: Ursula Braun Signed-off-by: Frank Blaschka Signed-off-by: David S. Miller diff --git a/net/iucv/af_iucv.c b/net/iucv/af_iucv.c index 986b2a5..e2013e4 100644 --- a/net/iucv/af_iucv.c +++ b/net/iucv/af_iucv.c @@ -190,7 +190,6 @@ static int afiucv_pm_freeze(struct device *dev) */ static int afiucv_pm_restore_thaw(struct device *dev) { - struct iucv_sock *iucv; struct sock *sk; struct hlist_node *node; @@ -199,7 +198,6 @@ static int afiucv_pm_restore_thaw(struct device *dev) #endif read_lock(&iucv_sk_list.lock); sk_for_each(sk, node, &iucv_sk_list.head) { - iucv = iucv_sk(sk); switch (sk->sk_state) { case IUCV_CONNECTED: sk->sk_err = EPIPE; @@ -381,7 +379,6 @@ static void iucv_sock_close(struct sock *sk) { unsigned char user_data[16]; struct iucv_sock *iucv = iucv_sk(sk); - int err; unsigned long timeo; iucv_sock_clear_timer(sk); @@ -394,8 +391,6 @@ static void iucv_sock_close(struct sock *sk) case IUCV_CONNECTED: case IUCV_DISCONN: - err = 0; - sk->sk_state = IUCV_CLOSING; sk->sk_state_change(sk); @@ -404,7 +399,7 @@ static void iucv_sock_close(struct sock *sk) timeo = sk->sk_lingertime; else timeo = IUCV_DISCONN_TIMEOUT; - err = iucv_sock_wait(sk, + iucv_sock_wait(sk, iucv_sock_in_state(sk, IUCV_CLOSED, 0), timeo); } @@ -417,7 +412,7 @@ static void iucv_sock_close(struct sock *sk) low_nmcpy(user_data, iucv->src_name); high_nmcpy(user_data, iucv->dst_name); ASCEBC(user_data, sizeof(user_data)); - err = iucv_path_sever(iucv->path, user_data); + iucv_path_sever(iucv->path, user_data); iucv_path_free(iucv->path); iucv->path = NULL; } -- cgit v0.10.2 From f20190302e3e697a166cc28ebef43058749dedda Mon Sep 17 00:00:00 2001 From: KOSAKI Motohiro Date: Thu, 12 May 2011 18:45:09 +0000 Subject: convert old cpumask API into new one Adapt new API. Signed-off-by: KOSAKI Motohiro Signed-off-by: Frank Blaschka Signed-off-by: David S. Miller diff --git a/net/iucv/iucv.c b/net/iucv/iucv.c index 6c1483f..a15c015 100644 --- a/net/iucv/iucv.c +++ b/net/iucv/iucv.c @@ -128,8 +128,8 @@ struct iucv_irq_list { }; static struct iucv_irq_data *iucv_irq_data[NR_CPUS]; -static cpumask_t iucv_buffer_cpumask = CPU_MASK_NONE; -static cpumask_t iucv_irq_cpumask = CPU_MASK_NONE; +static cpumask_t iucv_buffer_cpumask = { CPU_BITS_NONE }; +static cpumask_t iucv_irq_cpumask = { CPU_BITS_NONE }; /* * Queue of interrupt buffers lock for delivery via the tasklet @@ -406,7 +406,7 @@ static void iucv_allow_cpu(void *data) parm->set_mask.ipmask = 0xf8; iucv_call_b2f0(IUCV_SETCONTROLMASK, parm); /* Set indication that iucv interrupts are allowed for this cpu. */ - cpu_set(cpu, iucv_irq_cpumask); + cpumask_set_cpu(cpu, &iucv_irq_cpumask); } /** @@ -426,7 +426,7 @@ static void iucv_block_cpu(void *data) iucv_call_b2f0(IUCV_SETMASK, parm); /* Clear indication that iucv interrupts are allowed for this cpu. */ - cpu_clear(cpu, iucv_irq_cpumask); + cpumask_clear_cpu(cpu, &iucv_irq_cpumask); } /** @@ -451,7 +451,7 @@ static void iucv_block_cpu_almost(void *data) iucv_call_b2f0(IUCV_SETCONTROLMASK, parm); /* Clear indication that iucv interrupts are allowed for this cpu. */ - cpu_clear(cpu, iucv_irq_cpumask); + cpumask_clear_cpu(cpu, &iucv_irq_cpumask); } /** @@ -466,7 +466,7 @@ static void iucv_declare_cpu(void *data) union iucv_param *parm; int rc; - if (cpu_isset(cpu, iucv_buffer_cpumask)) + if (cpumask_test_cpu(cpu, &iucv_buffer_cpumask)) return; /* Declare interrupt buffer. */ @@ -499,9 +499,9 @@ static void iucv_declare_cpu(void *data) } /* Set indication that an iucv buffer exists for this cpu. */ - cpu_set(cpu, iucv_buffer_cpumask); + cpumask_set_cpu(cpu, &iucv_buffer_cpumask); - if (iucv_nonsmp_handler == 0 || cpus_empty(iucv_irq_cpumask)) + if (iucv_nonsmp_handler == 0 || cpumask_empty(&iucv_irq_cpumask)) /* Enable iucv interrupts on this cpu. */ iucv_allow_cpu(NULL); else @@ -520,7 +520,7 @@ static void iucv_retrieve_cpu(void *data) int cpu = smp_processor_id(); union iucv_param *parm; - if (!cpu_isset(cpu, iucv_buffer_cpumask)) + if (!cpumask_test_cpu(cpu, &iucv_buffer_cpumask)) return; /* Block iucv interrupts. */ @@ -531,7 +531,7 @@ static void iucv_retrieve_cpu(void *data) iucv_call_b2f0(IUCV_RETRIEVE_BUFFER, parm); /* Clear indication that an iucv buffer exists for this cpu. */ - cpu_clear(cpu, iucv_buffer_cpumask); + cpumask_clear_cpu(cpu, &iucv_buffer_cpumask); } /** @@ -546,8 +546,8 @@ static void iucv_setmask_mp(void) get_online_cpus(); for_each_online_cpu(cpu) /* Enable all cpus with a declared buffer. */ - if (cpu_isset(cpu, iucv_buffer_cpumask) && - !cpu_isset(cpu, iucv_irq_cpumask)) + if (cpumask_test_cpu(cpu, &iucv_buffer_cpumask) && + !cpumask_test_cpu(cpu, &iucv_irq_cpumask)) smp_call_function_single(cpu, iucv_allow_cpu, NULL, 1); put_online_cpus(); @@ -564,9 +564,9 @@ static void iucv_setmask_up(void) int cpu; /* Disable all cpu but the first in cpu_irq_cpumask. */ - cpumask = iucv_irq_cpumask; - cpu_clear(first_cpu(iucv_irq_cpumask), cpumask); - for_each_cpu_mask_nr(cpu, cpumask) + cpumask_copy(&cpumask, &iucv_irq_cpumask); + cpumask_clear_cpu(cpumask_first(&iucv_irq_cpumask), &cpumask); + for_each_cpu(cpu, &cpumask) smp_call_function_single(cpu, iucv_block_cpu, NULL, 1); } @@ -593,7 +593,7 @@ static int iucv_enable(void) rc = -EIO; for_each_online_cpu(cpu) smp_call_function_single(cpu, iucv_declare_cpu, NULL, 1); - if (cpus_empty(iucv_buffer_cpumask)) + if (cpumask_empty(&iucv_buffer_cpumask)) /* No cpu could declare an iucv buffer. */ goto out; put_online_cpus(); @@ -675,15 +675,16 @@ static int __cpuinit iucv_cpu_notify(struct notifier_block *self, case CPU_DOWN_PREPARE_FROZEN: if (!iucv_path_table) break; - cpumask = iucv_buffer_cpumask; - cpu_clear(cpu, cpumask); - if (cpus_empty(cpumask)) + cpumask_copy(&cpumask, &iucv_buffer_cpumask); + cpumask_clear_cpu(cpu, &cpumask); + if (cpumask_empty(&cpumask)) /* Can't offline last IUCV enabled cpu. */ return notifier_from_errno(-EINVAL); smp_call_function_single(cpu, iucv_retrieve_cpu, NULL, 1); - if (cpus_empty(iucv_irq_cpumask)) - smp_call_function_single(first_cpu(iucv_buffer_cpumask), - iucv_allow_cpu, NULL, 1); + if (cpumask_empty(&iucv_irq_cpumask)) + smp_call_function_single( + cpumask_first(&iucv_buffer_cpumask), + iucv_allow_cpu, NULL, 1); break; } return NOTIFY_OK; @@ -866,7 +867,7 @@ int iucv_path_accept(struct iucv_path *path, struct iucv_handler *handler, int rc; local_bh_disable(); - if (cpus_empty(iucv_buffer_cpumask)) { + if (cpumask_empty(&iucv_buffer_cpumask)) { rc = -EIO; goto out; } @@ -915,7 +916,7 @@ int iucv_path_connect(struct iucv_path *path, struct iucv_handler *handler, spin_lock_bh(&iucv_table_lock); iucv_cleanup_queue(); - if (cpus_empty(iucv_buffer_cpumask)) { + if (cpumask_empty(&iucv_buffer_cpumask)) { rc = -EIO; goto out; } @@ -975,7 +976,7 @@ int iucv_path_quiesce(struct iucv_path *path, u8 userdata[16]) int rc; local_bh_disable(); - if (cpus_empty(iucv_buffer_cpumask)) { + if (cpumask_empty(&iucv_buffer_cpumask)) { rc = -EIO; goto out; } @@ -1007,7 +1008,7 @@ int iucv_path_resume(struct iucv_path *path, u8 userdata[16]) int rc; local_bh_disable(); - if (cpus_empty(iucv_buffer_cpumask)) { + if (cpumask_empty(&iucv_buffer_cpumask)) { rc = -EIO; goto out; } @@ -1036,7 +1037,7 @@ int iucv_path_sever(struct iucv_path *path, u8 userdata[16]) int rc; preempt_disable(); - if (cpus_empty(iucv_buffer_cpumask)) { + if (cpumask_empty(&iucv_buffer_cpumask)) { rc = -EIO; goto out; } @@ -1070,7 +1071,7 @@ int iucv_message_purge(struct iucv_path *path, struct iucv_message *msg, int rc; local_bh_disable(); - if (cpus_empty(iucv_buffer_cpumask)) { + if (cpumask_empty(&iucv_buffer_cpumask)) { rc = -EIO; goto out; } @@ -1162,7 +1163,7 @@ int __iucv_message_receive(struct iucv_path *path, struct iucv_message *msg, if (msg->flags & IUCV_IPRMDATA) return iucv_message_receive_iprmdata(path, msg, flags, buffer, size, residual); - if (cpus_empty(iucv_buffer_cpumask)) { + if (cpumask_empty(&iucv_buffer_cpumask)) { rc = -EIO; goto out; } @@ -1235,7 +1236,7 @@ int iucv_message_reject(struct iucv_path *path, struct iucv_message *msg) int rc; local_bh_disable(); - if (cpus_empty(iucv_buffer_cpumask)) { + if (cpumask_empty(&iucv_buffer_cpumask)) { rc = -EIO; goto out; } @@ -1274,7 +1275,7 @@ int iucv_message_reply(struct iucv_path *path, struct iucv_message *msg, int rc; local_bh_disable(); - if (cpus_empty(iucv_buffer_cpumask)) { + if (cpumask_empty(&iucv_buffer_cpumask)) { rc = -EIO; goto out; } @@ -1324,7 +1325,7 @@ int __iucv_message_send(struct iucv_path *path, struct iucv_message *msg, union iucv_param *parm; int rc; - if (cpus_empty(iucv_buffer_cpumask)) { + if (cpumask_empty(&iucv_buffer_cpumask)) { rc = -EIO; goto out; } @@ -1411,7 +1412,7 @@ int iucv_message_send2way(struct iucv_path *path, struct iucv_message *msg, int rc; local_bh_disable(); - if (cpus_empty(iucv_buffer_cpumask)) { + if (cpumask_empty(&iucv_buffer_cpumask)) { rc = -EIO; goto out; } @@ -1888,7 +1889,7 @@ static int iucv_pm_freeze(struct device *dev) printk(KERN_WARNING "iucv_pm_freeze\n"); #endif if (iucv_pm_state != IUCV_PM_FREEZING) { - for_each_cpu_mask_nr(cpu, iucv_irq_cpumask) + for_each_cpu(cpu, &iucv_irq_cpumask) smp_call_function_single(cpu, iucv_block_cpu_almost, NULL, 1); cancel_work_sync(&iucv_work); @@ -1928,7 +1929,7 @@ static int iucv_pm_thaw(struct device *dev) if (rc) goto out; } - if (cpus_empty(iucv_irq_cpumask)) { + if (cpumask_empty(&iucv_irq_cpumask)) { if (iucv_nonsmp_handler) /* enable interrupts on one cpu */ iucv_allow_cpu(NULL); @@ -1961,7 +1962,7 @@ static int iucv_pm_restore(struct device *dev) pr_warning("Suspending Linux did not completely close all IUCV " "connections\n"); iucv_pm_state = IUCV_PM_RESTORING; - if (cpus_empty(iucv_irq_cpumask)) { + if (cpumask_empty(&iucv_irq_cpumask)) { rc = iucv_query_maxconn(); rc = iucv_enable(); if (rc) -- cgit v0.10.2 From 1159024d4c0aafecaa0c6635c55153b4b39cc1c8 Mon Sep 17 00:00:00 2001 From: "John W. Linville" Date: Fri, 13 May 2011 09:23:47 -0400 Subject: ssb: fix pcicore build breakage drivers/ssb/main.c:1336: error: 'SSB_PCICORE_BCAST_ADDR' undeclared (first use in this function) drivers/ssb/main.c:1337: error: 'SSB_PCICORE_BCAST_DATA' undeclared (first use in this function) drivers/ssb/main.c:1349: error: 'struct ssb_pcicore' has no member named 'dev' Reported-by: Randy Dunlap Signed-off-by: John W. Linville diff --git a/drivers/ssb/main.c b/drivers/ssb/main.c index ee2937c..f8a13f8 100644 --- a/drivers/ssb/main.c +++ b/drivers/ssb/main.c @@ -1332,21 +1332,27 @@ EXPORT_SYMBOL(ssb_bus_powerup); static void ssb_broadcast_value(struct ssb_device *dev, u32 address, u32 data) { +#ifdef CONFIG_SSB_DRIVER_PCICORE /* This is used for both, PCI and ChipCommon core, so be careful. */ BUILD_BUG_ON(SSB_PCICORE_BCAST_ADDR != SSB_CHIPCO_BCAST_ADDR); BUILD_BUG_ON(SSB_PCICORE_BCAST_DATA != SSB_CHIPCO_BCAST_DATA); +#endif - ssb_write32(dev, SSB_PCICORE_BCAST_ADDR, address); - ssb_read32(dev, SSB_PCICORE_BCAST_ADDR); /* flush */ - ssb_write32(dev, SSB_PCICORE_BCAST_DATA, data); - ssb_read32(dev, SSB_PCICORE_BCAST_DATA); /* flush */ + ssb_write32(dev, SSB_CHIPCO_BCAST_ADDR, address); + ssb_read32(dev, SSB_CHIPCO_BCAST_ADDR); /* flush */ + ssb_write32(dev, SSB_CHIPCO_BCAST_DATA, data); + ssb_read32(dev, SSB_CHIPCO_BCAST_DATA); /* flush */ } void ssb_commit_settings(struct ssb_bus *bus) { struct ssb_device *dev; +#ifdef CONFIG_SSB_DRIVER_PCICORE dev = bus->chipco.dev ? bus->chipco.dev : bus->pcicore.dev; +#else + dev = bus->chipco.dev; +#endif if (WARN_ON(!dev)) return; /* This forces an update of the cached registers. */ -- cgit v0.10.2 From a10e14667635dde504ed9e7ee851494c2cf2ae8e Mon Sep 17 00:00:00 2001 From: Vitalii Demianets Date: Thu, 12 May 2011 23:04:29 +0000 Subject: bonding,llc: Fix structure sizeof incompatibility for some PDUs With some combinations of arch/compiler (e.g. arm-linux-gcc) the sizeof operator on structure returns value greater than expected. In cases when the structure is used for mapping PDU fields it may lead to unexpected results (such as holes and alignment problems in skb data). __packed prevents this undesired behavior. Signed-off-by: Vitalii Demianets Signed-off-by: David S. Miller diff --git a/drivers/net/bonding/bond_3ad.h b/drivers/net/bonding/bond_3ad.h index b28baff..01b8a6a 100644 --- a/drivers/net/bonding/bond_3ad.h +++ b/drivers/net/bonding/bond_3ad.h @@ -39,7 +39,7 @@ typedef struct mac_addr { u8 mac_addr_value[ETH_ALEN]; -} mac_addr_t; +} __packed mac_addr_t; enum { BOND_AD_STABLE = 0, @@ -134,12 +134,12 @@ typedef struct lacpdu { u8 tlv_type_terminator; // = terminator u8 terminator_length; // = 0 u8 reserved_50[50]; // = 0 -} lacpdu_t; +} __packed lacpdu_t; typedef struct lacpdu_header { struct ethhdr hdr; struct lacpdu lacpdu; -} lacpdu_header_t; +} __packed lacpdu_header_t; // Marker Protocol Data Unit(PDU) structure(43.5.3.2 in the 802.3ad standard) typedef struct bond_marker { @@ -155,12 +155,12 @@ typedef struct bond_marker { u8 tlv_type_terminator; // = 0x00 u8 terminator_length; // = 0x00 u8 reserved_90[90]; // = 0 -} bond_marker_t; +} __packed bond_marker_t; typedef struct bond_marker_header { struct ethhdr hdr; struct bond_marker marker; -} bond_marker_header_t; +} __packed bond_marker_header_t; #pragma pack() diff --git a/include/net/llc_pdu.h b/include/net/llc_pdu.h index 75b8e29..f57e7d4 100644 --- a/include/net/llc_pdu.h +++ b/include/net/llc_pdu.h @@ -199,7 +199,7 @@ struct llc_pdu_sn { u8 ssap; u8 ctrl_1; u8 ctrl_2; -}; +} __packed; static inline struct llc_pdu_sn *llc_pdu_sn_hdr(struct sk_buff *skb) { @@ -211,7 +211,7 @@ struct llc_pdu_un { u8 dsap; u8 ssap; u8 ctrl_1; -}; +} __packed; static inline struct llc_pdu_un *llc_pdu_un_hdr(struct sk_buff *skb) { @@ -359,7 +359,7 @@ struct llc_xid_info { u8 fmt_id; /* always 0x81 for LLC */ u8 type; /* different if NULL/non-NULL LSAP */ u8 rw; /* sender receive window */ -}; +} __packed; /** * llc_pdu_init_as_xid_cmd - sets bytes 3, 4 & 5 of LLC header as XID @@ -415,7 +415,7 @@ struct llc_frmr_info { u8 curr_ssv; /* current send state variable val */ u8 curr_rsv; /* current receive state variable */ u8 ind_bits; /* indicator bits set with macro */ -}; +} __packed; extern void llc_pdu_set_cmd_rsp(struct sk_buff *skb, u8 type); extern void llc_pdu_set_pf_bit(struct sk_buff *skb, u8 bit_value); -- cgit v0.10.2 From 087fbc9962e10a65fb0b542ecfc116ebf6cf1735 Mon Sep 17 00:00:00 2001 From: Andy Lutomirski Date: Fri, 13 May 2011 12:14:54 -0400 Subject: drm/i915: Revert i915.semaphore=1 default from i915 merge My Q67 / i7-2600 box has rev09 Sandy Bridge graphics. It hangs instantly when GNOME loads and it hangs so hard the reset button doesn't work. Setting i915.semaphore=0 fixes it. Semaphores were disabled in a1656b9090f7 ("drm/i915: Disable GPU semaphores by default") in 2.6.38 but were then re-enabled (by mistake?) by the merge 47ae63e0c2e5 ("Merge branch 'drm-intel-fixes' into drm-intel-next"). (It's worth noting that the offending change is i915_drv.c, which was not marked as a conflict - although a 'git show --cc' on the merge does show that neither parent had it set to 1) Signed-off-by: Andy Lutomirski Signed-off-by: Linus Torvalds diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index c34a8dd..32d1b3e 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c @@ -49,7 +49,7 @@ module_param_named(panel_ignore_lid, i915_panel_ignore_lid, int, 0600); unsigned int i915_powersave = 1; module_param_named(powersave, i915_powersave, int, 0600); -unsigned int i915_semaphores = 1; +unsigned int i915_semaphores = 0; module_param_named(semaphores, i915_semaphores, int, 0600); unsigned int i915_enable_rc6 = 0; -- cgit v0.10.2 From cb68552858c64db302771469b1202ea09e696329 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Fri, 13 May 2011 16:03:24 -0400 Subject: bridge: fix forwarding of IPv6 The commit 6b1e960fdbd75dcd9bcc3ba5ff8898ff1ad30b6e bridge: Reset IPCB when entering IP stack on NF_FORWARD broke forwarding of IPV6 packets in bridge because it would call bp_parse_ip_options with an IPV6 packet. Reported-by: Noah Meyerhans Signed-off-by: Stephen Hemminger Reviewed-by: Eric Dumazet Signed-off-by: David S. Miller diff --git a/net/bridge/br_netfilter.c b/net/bridge/br_netfilter.c index f3bc322..74ef4d4 100644 --- a/net/bridge/br_netfilter.c +++ b/net/bridge/br_netfilter.c @@ -737,7 +737,7 @@ static unsigned int br_nf_forward_ip(unsigned int hook, struct sk_buff *skb, nf_bridge->mask |= BRNF_PKT_TYPE; } - if (br_parse_ip_options(skb)) + if (pf == PF_INET && br_parse_ip_options(skb)) return NF_DROP; /* The physdev module checks on this */ -- cgit v0.10.2 From c319b4d76b9e583a5d88d6bf190e079c4e43213d Mon Sep 17 00:00:00 2001 From: Vasiliy Kulikov Date: Fri, 13 May 2011 10:01:00 +0000 Subject: net: ipv4: add IPPROTO_ICMP socket kind This patch adds IPPROTO_ICMP socket kind. It makes it possible to send ICMP_ECHO messages and receive the corresponding ICMP_ECHOREPLY messages without any special privileges. In other words, the patch makes it possible to implement setuid-less and CAP_NET_RAW-less /bin/ping. In order not to increase the kernel's attack surface, the new functionality is disabled by default, but is enabled at bootup by supporting Linux distributions, optionally with restriction to a group or a group range (see below). Similar functionality is implemented in Mac OS X: http://www.manpagez.com/man/4/icmp/ A new ping socket is created with socket(PF_INET, SOCK_DGRAM, PROT_ICMP) Message identifiers (octets 4-5 of ICMP header) are interpreted as local ports. Addresses are stored in struct sockaddr_in. No port numbers are reserved for privileged processes, port 0 is reserved for API ("let the kernel pick a free number"). There is no notion of remote ports, remote port numbers provided by the user (e.g. in connect()) are ignored. Data sent and received include ICMP headers. This is deliberate to: 1) Avoid the need to transport headers values like sequence numbers by other means. 2) Make it easier to port existing programs using raw sockets. ICMP headers given to send() are checked and sanitized. The type must be ICMP_ECHO and the code must be zero (future extensions might relax this, see below). The id is set to the number (local port) of the socket, the checksum is always recomputed. ICMP reply packets received from the network are demultiplexed according to their id's, and are returned by recv() without any modifications. IP header information and ICMP errors of those packets may be obtained via ancillary data (IP_RECVTTL, IP_RETOPTS, and IP_RECVERR). ICMP source quenches and redirects are reported as fake errors via the error queue (IP_RECVERR); the next hop address for redirects is saved to ee_info (in network order). socket(2) is restricted to the group range specified in "/proc/sys/net/ipv4/ping_group_range". It is "1 0" by default, meaning that nobody (not even root) may create ping sockets. Setting it to "100 100" would grant permissions to the single group (to either make /sbin/ping g+s and owned by this group or to grant permissions to the "netadmins" group), "0 4294967295" would enable it for the world, "100 4294967295" would enable it for the users, but not daemons. The existing code might be (in the unlikely case anyone needs it) extended rather easily to handle other similar pairs of ICMP messages (Timestamp/Reply, Information Request/Reply, Address Mask Request/Reply etc.). Userspace ping util & patch for it: http://openwall.info/wiki/people/segoon/ping For Openwall GNU/*/Linux it was the last step on the road to the setuid-less distro. A revision of this patch (for RHEL5/OpenVZ kernels) is in use in Owl-current, such as in the 2011/03/12 LiveCD ISOs: http://mirrors.kernel.org/openwall/Owl/current/iso/ Initially this functionality was written by Pavel Kankovsky for Linux 2.4.32, but unfortunately it was never made public. All ping options (-b, -p, -Q, -R, -s, -t, -T, -M, -I), are tested with the patch. PATCH v3: - switched to flowi4. - minor changes to be consistent with raw sockets code. PATCH v2: - changed ping_debug() to pr_debug(). - removed CONFIG_IP_PING. - removed ping_seq_fops.owner field (unused for procfs). - switched to proc_net_fops_create(). - switched to %pK in seq_printf(). PATCH v1: - fixed checksumming bug. - CAP_NET_RAW may not create icmp sockets anymore. RFC v2: - minor cleanups. - introduced sysctl'able group range to restrict socket(2). Signed-off-by: Vasiliy Kulikov Signed-off-by: David S. Miller diff --git a/include/net/netns/ipv4.h b/include/net/netns/ipv4.h index 542195d..d786b4f 100644 --- a/include/net/netns/ipv4.h +++ b/include/net/netns/ipv4.h @@ -54,6 +54,8 @@ struct netns_ipv4 { int sysctl_rt_cache_rebuild_count; int current_rt_cache_rebuild_count; + unsigned int sysctl_ping_group_range[2]; + atomic_t rt_genid; atomic_t dev_addr_genid; diff --git a/include/net/ping.h b/include/net/ping.h new file mode 100644 index 0000000..23062c3 --- /dev/null +++ b/include/net/ping.h @@ -0,0 +1,57 @@ +/* + * INET An implementation of the TCP/IP protocol suite for the LINUX + * operating system. INET is implemented using the BSD Socket + * interface as the means of communication with the user level. + * + * Definitions for the "ping" module. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ +#ifndef _PING_H +#define _PING_H + +#include + +/* PING_HTABLE_SIZE must be power of 2 */ +#define PING_HTABLE_SIZE 64 +#define PING_HTABLE_MASK (PING_HTABLE_SIZE-1) + +#define ping_portaddr_for_each_entry(__sk, node, list) \ + hlist_nulls_for_each_entry(__sk, node, list, sk_nulls_node) + +/* + * gid_t is either uint or ushort. We want to pass it to + * proc_dointvec_minmax(), so it must not be larger than MAX_INT + */ +#define GID_T_MAX (((gid_t)~0U) >> 1) + +struct ping_table { + struct hlist_nulls_head hash[PING_HTABLE_SIZE]; + rwlock_t lock; +}; + +struct ping_iter_state { + struct seq_net_private p; + int bucket; +}; + +extern struct proto ping_prot; + + +extern void ping_rcv(struct sk_buff *); +extern void ping_err(struct sk_buff *, u32 info); + +extern void inet_get_ping_group_range_net(struct net *net, unsigned int *low, unsigned int *high); + +#ifdef CONFIG_PROC_FS +extern int __init ping_proc_init(void); +extern void ping_proc_exit(void); +#endif + +void __init ping_init(void); + + +#endif /* _PING_H */ diff --git a/net/ipv4/Makefile b/net/ipv4/Makefile index 0dc772d..f2dc69c 100644 --- a/net/ipv4/Makefile +++ b/net/ipv4/Makefile @@ -11,7 +11,7 @@ obj-y := route.o inetpeer.o protocol.o \ datagram.o raw.o udp.o udplite.o \ arp.o icmp.o devinet.o af_inet.o igmp.o \ fib_frontend.o fib_semantics.o fib_trie.o \ - inet_fragment.o + inet_fragment.o ping.o obj-$(CONFIG_SYSCTL) += sysctl_net_ipv4.o obj-$(CONFIG_PROC_FS) += proc.o diff --git a/net/ipv4/af_inet.c b/net/ipv4/af_inet.c index 851aa05..cc14631 100644 --- a/net/ipv4/af_inet.c +++ b/net/ipv4/af_inet.c @@ -105,6 +105,7 @@ #include #include #include +#include #include #include #include @@ -1008,6 +1009,14 @@ static struct inet_protosw inetsw_array[] = .flags = INET_PROTOSW_PERMANENT, }, + { + .type = SOCK_DGRAM, + .protocol = IPPROTO_ICMP, + .prot = &ping_prot, + .ops = &inet_dgram_ops, + .no_check = UDP_CSUM_DEFAULT, + .flags = INET_PROTOSW_REUSE, + }, { .type = SOCK_RAW, @@ -1527,6 +1536,7 @@ static const struct net_protocol udp_protocol = { static const struct net_protocol icmp_protocol = { .handler = icmp_rcv, + .err_handler = ping_err, .no_policy = 1, .netns_ok = 1, }; @@ -1642,6 +1652,10 @@ static int __init inet_init(void) if (rc) goto out_unregister_udp_proto; + rc = proto_register(&ping_prot, 1); + if (rc) + goto out_unregister_raw_proto; + /* * Tell SOCKET that we are alive... */ @@ -1697,6 +1711,8 @@ static int __init inet_init(void) /* Add UDP-Lite (RFC 3828) */ udplite4_register(); + ping_init(); + /* * Set the ICMP layer up */ @@ -1727,6 +1743,8 @@ static int __init inet_init(void) rc = 0; out: return rc; +out_unregister_raw_proto: + proto_unregister(&raw_prot); out_unregister_udp_proto: proto_unregister(&udp_prot); out_unregister_tcp_proto: @@ -1751,11 +1769,15 @@ static int __init ipv4_proc_init(void) goto out_tcp; if (udp4_proc_init()) goto out_udp; + if (ping_proc_init()) + goto out_ping; if (ip_misc_proc_init()) goto out_misc; out: return rc; out_misc: + ping_proc_exit(); +out_ping: udp4_proc_exit(); out_udp: tcp4_proc_exit(); diff --git a/net/ipv4/icmp.c b/net/ipv4/icmp.c index 3314394..3f47585 100644 --- a/net/ipv4/icmp.c +++ b/net/ipv4/icmp.c @@ -83,6 +83,7 @@ #include #include #include +#include #include #include #include @@ -781,6 +782,15 @@ static void icmp_redirect(struct sk_buff *skb) iph->saddr, skb->dev); break; } + + /* Ping wants to see redirects. + * Let's pretend they are errors of sorts... */ + if (iph->protocol == IPPROTO_ICMP && + iph->ihl >= 5 && + pskb_may_pull(skb, (iph->ihl<<2)+8)) { + ping_err(skb, icmp_hdr(skb)->un.gateway); + } + out: return; out_err: @@ -1041,7 +1051,7 @@ error: */ static const struct icmp_control icmp_pointers[NR_ICMP_TYPES + 1] = { [ICMP_ECHOREPLY] = { - .handler = icmp_discard, + .handler = ping_rcv, }, [1] = { .handler = icmp_discard, diff --git a/net/ipv4/ping.c b/net/ipv4/ping.c new file mode 100644 index 0000000..a77e2d7 --- /dev/null +++ b/net/ipv4/ping.c @@ -0,0 +1,937 @@ +/* + * INET An implementation of the TCP/IP protocol suite for the LINUX + * operating system. INET is implemented using the BSD Socket + * interface as the means of communication with the user level. + * + * "Ping" sockets + * + * 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. + * + * Based on ipv4/udp.c code. + * + * Authors: Vasiliy Kulikov / Openwall (for Linux 2.6), + * Pavel Kankovsky (for Linux 2.4.32) + * + * Pavel gave all rights to bugs to Vasiliy, + * none of the bugs are Pavel's now. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +struct ping_table ping_table __read_mostly; + +u16 ping_port_rover; + +static inline int ping_hashfn(struct net *net, unsigned num, unsigned mask) +{ + int res = (num + net_hash_mix(net)) & mask; + pr_debug("hash(%d) = %d\n", num, res); + return res; +} + +static inline struct hlist_nulls_head *ping_hashslot(struct ping_table *table, + struct net *net, unsigned num) +{ + return &table->hash[ping_hashfn(net, num, PING_HTABLE_MASK)]; +} + +static int ping_v4_get_port(struct sock *sk, unsigned short ident) +{ + struct hlist_nulls_node *node; + struct hlist_nulls_head *hlist; + struct inet_sock *isk, *isk2; + struct sock *sk2 = NULL; + + isk = inet_sk(sk); + write_lock_bh(&ping_table.lock); + if (ident == 0) { + u32 i; + u16 result = ping_port_rover + 1; + + for (i = 0; i < (1L << 16); i++, result++) { + if (!result) + result++; /* avoid zero */ + hlist = ping_hashslot(&ping_table, sock_net(sk), + result); + ping_portaddr_for_each_entry(sk2, node, hlist) { + isk2 = inet_sk(sk2); + + if (isk2->inet_num == result) + goto next_port; + } + + /* found */ + ping_port_rover = ident = result; + break; +next_port: + ; + } + if (i >= (1L << 16)) + goto fail; + } else { + hlist = ping_hashslot(&ping_table, sock_net(sk), ident); + ping_portaddr_for_each_entry(sk2, node, hlist) { + isk2 = inet_sk(sk2); + + if ((isk2->inet_num == ident) && + (sk2 != sk) && + (!sk2->sk_reuse || !sk->sk_reuse)) + goto fail; + } + } + + pr_debug("found port/ident = %d\n", ident); + isk->inet_num = ident; + if (sk_unhashed(sk)) { + pr_debug("was not hashed\n"); + sock_hold(sk); + hlist_nulls_add_head(&sk->sk_nulls_node, hlist); + sock_prot_inuse_add(sock_net(sk), sk->sk_prot, 1); + } + write_unlock_bh(&ping_table.lock); + return 0; + +fail: + write_unlock_bh(&ping_table.lock); + return 1; +} + +static void ping_v4_hash(struct sock *sk) +{ + pr_debug("ping_v4_hash(sk->port=%u)\n", inet_sk(sk)->inet_num); + BUG(); /* "Please do not press this button again." */ +} + +static void ping_v4_unhash(struct sock *sk) +{ + struct inet_sock *isk = inet_sk(sk); + pr_debug("ping_v4_unhash(isk=%p,isk->num=%u)\n", isk, isk->inet_num); + if (sk_hashed(sk)) { + struct hlist_nulls_head *hslot; + + hslot = ping_hashslot(&ping_table, sock_net(sk), isk->inet_num); + write_lock_bh(&ping_table.lock); + hlist_nulls_del(&sk->sk_nulls_node); + sock_put(sk); + isk->inet_num = isk->inet_sport = 0; + sock_prot_inuse_add(sock_net(sk), sk->sk_prot, -1); + write_unlock_bh(&ping_table.lock); + } +} + +struct sock *ping_v4_lookup(struct net *net, u32 saddr, u32 daddr, + u16 ident, int dif) +{ + struct hlist_nulls_head *hslot = ping_hashslot(&ping_table, net, ident); + struct sock *sk = NULL; + struct inet_sock *isk; + struct hlist_nulls_node *hnode; + + pr_debug("try to find: num = %d, daddr = %ld, dif = %d\n", + (int)ident, (unsigned long)daddr, dif); + read_lock_bh(&ping_table.lock); + + ping_portaddr_for_each_entry(sk, hnode, hslot) { + isk = inet_sk(sk); + + pr_debug("found: %p: num = %d, daddr = %ld, dif = %d\n", sk, + (int)isk->inet_num, (unsigned long)isk->inet_rcv_saddr, + sk->sk_bound_dev_if); + + pr_debug("iterate\n"); + if (isk->inet_num != ident) + continue; + if (isk->inet_rcv_saddr && isk->inet_rcv_saddr != daddr) + continue; + if (sk->sk_bound_dev_if && sk->sk_bound_dev_if != dif) + continue; + + sock_hold(sk); + goto exit; + } + + sk = NULL; +exit: + read_unlock_bh(&ping_table.lock); + + return sk; +} + +static int ping_init_sock(struct sock *sk) +{ + struct net *net = sock_net(sk); + gid_t group = current_egid(); + gid_t range[2]; + struct group_info *group_info = get_current_groups(); + int i, j, count = group_info->ngroups; + + inet_get_ping_group_range_net(net, range, range+1); + if (range[0] <= group && group <= range[1]) + return 0; + + for (i = 0; i < group_info->nblocks; i++) { + int cp_count = min_t(int, NGROUPS_PER_BLOCK, count); + + for (j = 0; j < cp_count; j++) { + group = group_info->blocks[i][j]; + if (range[0] <= group && group <= range[1]) + return 0; + } + + count -= cp_count; + } + + return -EACCES; +} + +static void ping_close(struct sock *sk, long timeout) +{ + pr_debug("ping_close(sk=%p,sk->num=%u)\n", + inet_sk(sk), inet_sk(sk)->inet_num); + pr_debug("isk->refcnt = %d\n", sk->sk_refcnt.counter); + + sk_common_release(sk); +} + +/* + * We need our own bind because there are no privileged id's == local ports. + * Moreover, we don't allow binding to multi- and broadcast addresses. + */ + +static int ping_bind(struct sock *sk, struct sockaddr *uaddr, int addr_len) +{ + struct sockaddr_in *addr = (struct sockaddr_in *)uaddr; + struct inet_sock *isk = inet_sk(sk); + unsigned short snum; + int chk_addr_ret; + int err; + + if (addr_len < sizeof(struct sockaddr_in)) + return -EINVAL; + + pr_debug("ping_v4_bind(sk=%p,sa_addr=%08x,sa_port=%d)\n", + sk, addr->sin_addr.s_addr, ntohs(addr->sin_port)); + + chk_addr_ret = inet_addr_type(sock_net(sk), addr->sin_addr.s_addr); + if (addr->sin_addr.s_addr == INADDR_ANY) + chk_addr_ret = RTN_LOCAL; + + if ((sysctl_ip_nonlocal_bind == 0 && + isk->freebind == 0 && isk->transparent == 0 && + chk_addr_ret != RTN_LOCAL) || + chk_addr_ret == RTN_MULTICAST || + chk_addr_ret == RTN_BROADCAST) + return -EADDRNOTAVAIL; + + lock_sock(sk); + + err = -EINVAL; + if (isk->inet_num != 0) + goto out; + + err = -EADDRINUSE; + isk->inet_rcv_saddr = isk->inet_saddr = addr->sin_addr.s_addr; + snum = ntohs(addr->sin_port); + if (ping_v4_get_port(sk, snum) != 0) { + isk->inet_saddr = isk->inet_rcv_saddr = 0; + goto out; + } + + pr_debug("after bind(): num = %d, daddr = %ld, dif = %d\n", + (int)isk->inet_num, + (unsigned long) isk->inet_rcv_saddr, + (int)sk->sk_bound_dev_if); + + err = 0; + if (isk->inet_rcv_saddr) + sk->sk_userlocks |= SOCK_BINDADDR_LOCK; + if (snum) + sk->sk_userlocks |= SOCK_BINDPORT_LOCK; + isk->inet_sport = htons(isk->inet_num); + isk->inet_daddr = 0; + isk->inet_dport = 0; + sk_dst_reset(sk); +out: + release_sock(sk); + pr_debug("ping_v4_bind -> %d\n", err); + return err; +} + +/* + * Is this a supported type of ICMP message? + */ + +static inline int ping_supported(int type, int code) +{ + if (type == ICMP_ECHO && code == 0) + return 1; + return 0; +} + +/* + * This routine is called by the ICMP module when it gets some + * sort of error condition. + */ + +static int ping_queue_rcv_skb(struct sock *sk, struct sk_buff *skb); + +void ping_err(struct sk_buff *skb, u32 info) +{ + struct iphdr *iph = (struct iphdr *)skb->data; + struct icmphdr *icmph = (struct icmphdr *)(skb->data+(iph->ihl<<2)); + struct inet_sock *inet_sock; + int type = icmph->type; + int code = icmph->code; + struct net *net = dev_net(skb->dev); + struct sock *sk; + int harderr; + int err; + + /* We assume the packet has already been checked by icmp_unreach */ + + if (!ping_supported(icmph->type, icmph->code)) + return; + + pr_debug("ping_err(type=%04x,code=%04x,id=%04x,seq=%04x)\n", type, + code, ntohs(icmph->un.echo.id), ntohs(icmph->un.echo.sequence)); + + sk = ping_v4_lookup(net, iph->daddr, iph->saddr, + ntohs(icmph->un.echo.id), skb->dev->ifindex); + if (sk == NULL) { + ICMP_INC_STATS_BH(net, ICMP_MIB_INERRORS); + pr_debug("no socket, dropping\n"); + return; /* No socket for error */ + } + pr_debug("err on socket %p\n", sk); + + err = 0; + harderr = 0; + inet_sock = inet_sk(sk); + + switch (type) { + default: + case ICMP_TIME_EXCEEDED: + err = EHOSTUNREACH; + break; + case ICMP_SOURCE_QUENCH: + /* This is not a real error but ping wants to see it. + * Report it with some fake errno. */ + err = EREMOTEIO; + break; + case ICMP_PARAMETERPROB: + err = EPROTO; + harderr = 1; + break; + case ICMP_DEST_UNREACH: + if (code == ICMP_FRAG_NEEDED) { /* Path MTU discovery */ + if (inet_sock->pmtudisc != IP_PMTUDISC_DONT) { + err = EMSGSIZE; + harderr = 1; + break; + } + goto out; + } + err = EHOSTUNREACH; + if (code <= NR_ICMP_UNREACH) { + harderr = icmp_err_convert[code].fatal; + err = icmp_err_convert[code].errno; + } + break; + case ICMP_REDIRECT: + /* See ICMP_SOURCE_QUENCH */ + err = EREMOTEIO; + break; + } + + /* + * RFC1122: OK. Passes ICMP errors back to application, as per + * 4.1.3.3. + */ + if (!inet_sock->recverr) { + if (!harderr || sk->sk_state != TCP_ESTABLISHED) + goto out; + } else { + ip_icmp_error(sk, skb, err, 0 /* no remote port */, + info, (u8 *)icmph); + } + sk->sk_err = err; + sk->sk_error_report(sk); +out: + sock_put(sk); +} + +/* + * Copy and checksum an ICMP Echo packet from user space into a buffer. + */ + +struct pingfakehdr { + struct icmphdr icmph; + struct iovec *iov; + u32 wcheck; +}; + +static int ping_getfrag(void *from, char * to, + int offset, int fraglen, int odd, struct sk_buff *skb) +{ + struct pingfakehdr *pfh = (struct pingfakehdr *)from; + + if (offset == 0) { + if (fraglen < sizeof(struct icmphdr)) + BUG(); + if (csum_partial_copy_fromiovecend(to + sizeof(struct icmphdr), + pfh->iov, 0, fraglen - sizeof(struct icmphdr), + &pfh->wcheck)) + return -EFAULT; + + return 0; + } + if (offset < sizeof(struct icmphdr)) + BUG(); + if (csum_partial_copy_fromiovecend + (to, pfh->iov, offset - sizeof(struct icmphdr), + fraglen, &pfh->wcheck)) + return -EFAULT; + return 0; +} + +static int ping_push_pending_frames(struct sock *sk, struct pingfakehdr *pfh, struct flowi4 *fl4) +{ + struct sk_buff *skb = skb_peek(&sk->sk_write_queue); + + pfh->wcheck = csum_partial((char *)&pfh->icmph, + sizeof(struct icmphdr), pfh->wcheck); + pfh->icmph.checksum = csum_fold(pfh->wcheck); + memcpy(icmp_hdr(skb), &pfh->icmph, sizeof(struct icmphdr)); + skb->ip_summed = CHECKSUM_NONE; + return ip_push_pending_frames(sk, fl4); +} + +int ping_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, + size_t len) +{ + struct net *net = sock_net(sk); + struct flowi4 fl4; + struct inet_sock *inet = inet_sk(sk); + struct ipcm_cookie ipc; + struct icmphdr user_icmph; + struct pingfakehdr pfh; + struct rtable *rt = NULL; + struct ip_options_data opt_copy; + int free = 0; + u32 saddr, daddr, faddr; + u8 tos; + int err; + + pr_debug("ping_sendmsg(sk=%p,sk->num=%u)\n", inet, inet->inet_num); + + + if (len > 0xFFFF) + return -EMSGSIZE; + + /* + * Check the flags. + */ + + /* Mirror BSD error message compatibility */ + if (msg->msg_flags & MSG_OOB) + return -EOPNOTSUPP; + + /* + * Fetch the ICMP header provided by the userland. + * iovec is modified! + */ + + if (memcpy_fromiovec((u8 *)&user_icmph, msg->msg_iov, + sizeof(struct icmphdr))) + return -EFAULT; + if (!ping_supported(user_icmph.type, user_icmph.code)) + return -EINVAL; + + /* + * Get and verify the address. + */ + + if (msg->msg_name) { + struct sockaddr_in *usin = (struct sockaddr_in *)msg->msg_name; + if (msg->msg_namelen < sizeof(*usin)) + return -EINVAL; + if (usin->sin_family != AF_INET) + return -EINVAL; + daddr = usin->sin_addr.s_addr; + /* no remote port */ + } else { + if (sk->sk_state != TCP_ESTABLISHED) + return -EDESTADDRREQ; + daddr = inet->inet_daddr; + /* no remote port */ + } + + ipc.addr = inet->inet_saddr; + ipc.opt = NULL; + ipc.oif = sk->sk_bound_dev_if; + ipc.tx_flags = 0; + err = sock_tx_timestamp(sk, &ipc.tx_flags); + if (err) + return err; + + if (msg->msg_controllen) { + err = ip_cmsg_send(sock_net(sk), msg, &ipc); + if (err) + return err; + if (ipc.opt) + free = 1; + } + if (!ipc.opt) { + struct ip_options_rcu *inet_opt; + + rcu_read_lock(); + inet_opt = rcu_dereference(inet->inet_opt); + if (inet_opt) { + memcpy(&opt_copy, inet_opt, + sizeof(*inet_opt) + inet_opt->opt.optlen); + ipc.opt = &opt_copy.opt; + } + rcu_read_unlock(); + } + + saddr = ipc.addr; + ipc.addr = faddr = daddr; + + if (ipc.opt && ipc.opt->opt.srr) { + if (!daddr) + return -EINVAL; + faddr = ipc.opt->opt.faddr; + } + tos = RT_TOS(inet->tos); + if (sock_flag(sk, SOCK_LOCALROUTE) || + (msg->msg_flags & MSG_DONTROUTE) || + (ipc.opt && ipc.opt->opt.is_strictroute)) { + tos |= RTO_ONLINK; + } + + if (ipv4_is_multicast(daddr)) { + if (!ipc.oif) + ipc.oif = inet->mc_index; + if (!saddr) + saddr = inet->mc_addr; + } + + flowi4_init_output(&fl4, ipc.oif, sk->sk_mark, tos, + RT_SCOPE_UNIVERSE, sk->sk_protocol, + inet_sk_flowi_flags(sk), faddr, saddr, 0, 0); + + security_sk_classify_flow(sk, flowi4_to_flowi(&fl4)); + rt = ip_route_output_flow(net, &fl4, sk); + if (IS_ERR(rt)) { + err = PTR_ERR(rt); + rt = NULL; + if (err == -ENETUNREACH) + IP_INC_STATS_BH(net, IPSTATS_MIB_OUTNOROUTES); + goto out; + } + + err = -EACCES; + if ((rt->rt_flags & RTCF_BROADCAST) && + !sock_flag(sk, SOCK_BROADCAST)) + goto out; + + if (msg->msg_flags & MSG_CONFIRM) + goto do_confirm; +back_from_confirm: + + if (!ipc.addr) + ipc.addr = fl4.daddr; + + lock_sock(sk); + + pfh.icmph.type = user_icmph.type; /* already checked */ + pfh.icmph.code = user_icmph.code; /* ditto */ + pfh.icmph.checksum = 0; + pfh.icmph.un.echo.id = inet->inet_sport; + pfh.icmph.un.echo.sequence = user_icmph.un.echo.sequence; + pfh.iov = msg->msg_iov; + pfh.wcheck = 0; + + err = ip_append_data(sk, &fl4, ping_getfrag, &pfh, len, + 0, &ipc, &rt, msg->msg_flags); + if (err) + ip_flush_pending_frames(sk); + else + err = ping_push_pending_frames(sk, &pfh, &fl4); + release_sock(sk); + +out: + ip_rt_put(rt); + if (free) + kfree(ipc.opt); + if (!err) { + icmp_out_count(sock_net(sk), user_icmph.type); + return len; + } + return err; + +do_confirm: + dst_confirm(&rt->dst); + if (!(msg->msg_flags & MSG_PROBE) || len) + goto back_from_confirm; + err = 0; + goto out; +} + +/* + * IOCTL requests applicable to the UDP^H^H^HICMP protocol + */ + +int ping_ioctl(struct sock *sk, int cmd, unsigned long arg) +{ + pr_debug("ping_ioctl(sk=%p,sk->num=%u,cmd=%d,arg=%lu)\n", + inet_sk(sk), inet_sk(sk)->inet_num, cmd, arg); + switch (cmd) { + case SIOCOUTQ: + case SIOCINQ: + return udp_ioctl(sk, cmd, arg); + default: + return -ENOIOCTLCMD; + } +} + +int ping_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, + size_t len, int noblock, int flags, int *addr_len) +{ + struct inet_sock *isk = inet_sk(sk); + struct sockaddr_in *sin = (struct sockaddr_in *)msg->msg_name; + struct sk_buff *skb; + int copied, err; + + pr_debug("ping_recvmsg(sk=%p,sk->num=%u)\n", isk, isk->inet_num); + + if (flags & MSG_OOB) + goto out; + + if (addr_len) + *addr_len = sizeof(*sin); + + if (flags & MSG_ERRQUEUE) + return ip_recv_error(sk, msg, len); + + skb = skb_recv_datagram(sk, flags, noblock, &err); + if (!skb) + goto out; + + copied = skb->len; + if (copied > len) { + msg->msg_flags |= MSG_TRUNC; + copied = len; + } + + /* Don't bother checking the checksum */ + err = skb_copy_datagram_iovec(skb, 0, msg->msg_iov, copied); + if (err) + goto done; + + sock_recv_timestamp(msg, sk, skb); + + /* Copy the address. */ + if (sin) { + sin->sin_family = AF_INET; + sin->sin_port = 0 /* skb->h.uh->source */; + sin->sin_addr.s_addr = ip_hdr(skb)->saddr; + memset(sin->sin_zero, 0, sizeof(sin->sin_zero)); + } + if (isk->cmsg_flags) + ip_cmsg_recv(msg, skb); + err = copied; + +done: + skb_free_datagram(sk, skb); +out: + pr_debug("ping_recvmsg -> %d\n", err); + return err; +} + +static int ping_queue_rcv_skb(struct sock *sk, struct sk_buff *skb) +{ + pr_debug("ping_queue_rcv_skb(sk=%p,sk->num=%d,skb=%p)\n", + inet_sk(sk), inet_sk(sk)->inet_num, skb); + if (sock_queue_rcv_skb(sk, skb) < 0) { + ICMP_INC_STATS_BH(sock_net(sk), ICMP_MIB_INERRORS); + kfree_skb(skb); + pr_debug("ping_queue_rcv_skb -> failed\n"); + return -1; + } + return 0; +} + + +/* + * All we need to do is get the socket. + */ + +void ping_rcv(struct sk_buff *skb) +{ + struct sock *sk; + struct net *net = dev_net(skb->dev); + struct iphdr *iph = ip_hdr(skb); + struct icmphdr *icmph = icmp_hdr(skb); + u32 saddr = iph->saddr; + u32 daddr = iph->daddr; + + /* We assume the packet has already been checked by icmp_rcv */ + + pr_debug("ping_rcv(skb=%p,id=%04x,seq=%04x)\n", + skb, ntohs(icmph->un.echo.id), ntohs(icmph->un.echo.sequence)); + + /* Push ICMP header back */ + skb_push(skb, skb->data - (u8 *)icmph); + + sk = ping_v4_lookup(net, saddr, daddr, ntohs(icmph->un.echo.id), + skb->dev->ifindex); + if (sk != NULL) { + pr_debug("rcv on socket %p\n", sk); + ping_queue_rcv_skb(sk, skb_get(skb)); + sock_put(sk); + return; + } + pr_debug("no socket, dropping\n"); + + /* We're called from icmp_rcv(). kfree_skb() is done there. */ +} + +struct proto ping_prot = { + .name = "PING", + .owner = THIS_MODULE, + .init = ping_init_sock, + .close = ping_close, + .connect = ip4_datagram_connect, + .disconnect = udp_disconnect, + .ioctl = ping_ioctl, + .setsockopt = ip_setsockopt, + .getsockopt = ip_getsockopt, + .sendmsg = ping_sendmsg, + .recvmsg = ping_recvmsg, + .bind = ping_bind, + .backlog_rcv = ping_queue_rcv_skb, + .hash = ping_v4_hash, + .unhash = ping_v4_unhash, + .get_port = ping_v4_get_port, + .obj_size = sizeof(struct inet_sock), +}; +EXPORT_SYMBOL(ping_prot); + +#ifdef CONFIG_PROC_FS + +static struct sock *ping_get_first(struct seq_file *seq, int start) +{ + struct sock *sk; + struct ping_iter_state *state = seq->private; + struct net *net = seq_file_net(seq); + + for (state->bucket = start; state->bucket < PING_HTABLE_SIZE; + ++state->bucket) { + struct hlist_nulls_node *node; + struct hlist_nulls_head *hslot = &ping_table.hash[state->bucket]; + + if (hlist_nulls_empty(hslot)) + continue; + + sk_nulls_for_each(sk, node, hslot) { + if (net_eq(sock_net(sk), net)) + goto found; + } + } + sk = NULL; +found: + return sk; +} + +static struct sock *ping_get_next(struct seq_file *seq, struct sock *sk) +{ + struct ping_iter_state *state = seq->private; + struct net *net = seq_file_net(seq); + + do { + sk = sk_nulls_next(sk); + } while (sk && (!net_eq(sock_net(sk), net))); + + if (!sk) + return ping_get_first(seq, state->bucket + 1); + return sk; +} + +static struct sock *ping_get_idx(struct seq_file *seq, loff_t pos) +{ + struct sock *sk = ping_get_first(seq, 0); + + if (sk) + while (pos && (sk = ping_get_next(seq, sk)) != NULL) + --pos; + return pos ? NULL : sk; +} + +static void *ping_seq_start(struct seq_file *seq, loff_t *pos) +{ + struct ping_iter_state *state = seq->private; + state->bucket = 0; + + read_lock_bh(&ping_table.lock); + + return *pos ? ping_get_idx(seq, *pos-1) : SEQ_START_TOKEN; +} + +static void *ping_seq_next(struct seq_file *seq, void *v, loff_t *pos) +{ + struct sock *sk; + + if (v == SEQ_START_TOKEN) + sk = ping_get_idx(seq, 0); + else + sk = ping_get_next(seq, v); + + ++*pos; + return sk; +} + +static void ping_seq_stop(struct seq_file *seq, void *v) +{ + read_unlock_bh(&ping_table.lock); +} + +static void ping_format_sock(struct sock *sp, struct seq_file *f, + int bucket, int *len) +{ + struct inet_sock *inet = inet_sk(sp); + __be32 dest = inet->inet_daddr; + __be32 src = inet->inet_rcv_saddr; + __u16 destp = ntohs(inet->inet_dport); + __u16 srcp = ntohs(inet->inet_sport); + + seq_printf(f, "%5d: %08X:%04X %08X:%04X" + " %02X %08X:%08X %02X:%08lX %08X %5d %8d %lu %d %pK %d%n", + bucket, src, srcp, dest, destp, sp->sk_state, + sk_wmem_alloc_get(sp), + sk_rmem_alloc_get(sp), + 0, 0L, 0, sock_i_uid(sp), 0, sock_i_ino(sp), + atomic_read(&sp->sk_refcnt), sp, + atomic_read(&sp->sk_drops), len); +} + +static int ping_seq_show(struct seq_file *seq, void *v) +{ + if (v == SEQ_START_TOKEN) + seq_printf(seq, "%-127s\n", + " sl local_address rem_address st tx_queue " + "rx_queue tr tm->when retrnsmt uid timeout " + "inode ref pointer drops"); + else { + struct ping_iter_state *state = seq->private; + int len; + + ping_format_sock(v, seq, state->bucket, &len); + seq_printf(seq, "%*s\n", 127 - len, ""); + } + return 0; +} + +static const struct seq_operations ping_seq_ops = { + .show = ping_seq_show, + .start = ping_seq_start, + .next = ping_seq_next, + .stop = ping_seq_stop, +}; + +static int ping_seq_open(struct inode *inode, struct file *file) +{ + return seq_open_net(inode, file, &ping_seq_ops, + sizeof(struct ping_iter_state)); +} + +static const struct file_operations ping_seq_fops = { + .open = ping_seq_open, + .read = seq_read, + .llseek = seq_lseek, + .release = seq_release_net, +}; + +static int ping_proc_register(struct net *net) +{ + struct proc_dir_entry *p; + int rc = 0; + + p = proc_net_fops_create(net, "icmp", S_IRUGO, &ping_seq_fops); + if (!p) + rc = -ENOMEM; + return rc; +} + +static void ping_proc_unregister(struct net *net) +{ + proc_net_remove(net, "icmp"); +} + + +static int __net_init ping_proc_init_net(struct net *net) +{ + return ping_proc_register(net); +} + +static void __net_exit ping_proc_exit_net(struct net *net) +{ + ping_proc_unregister(net); +} + +static struct pernet_operations ping_net_ops = { + .init = ping_proc_init_net, + .exit = ping_proc_exit_net, +}; + +int __init ping_proc_init(void) +{ + return register_pernet_subsys(&ping_net_ops); +} + +void ping_proc_exit(void) +{ + unregister_pernet_subsys(&ping_net_ops); +} + +#endif + +void __init ping_init(void) +{ + int i; + + for (i = 0; i < PING_HTABLE_SIZE; i++) + INIT_HLIST_NULLS_HEAD(&ping_table.hash[i], i); + rwlock_init(&ping_table.lock); +} diff --git a/net/ipv4/sysctl_net_ipv4.c b/net/ipv4/sysctl_net_ipv4.c index 321e6e8..28e8273 100644 --- a/net/ipv4/sysctl_net_ipv4.c +++ b/net/ipv4/sysctl_net_ipv4.c @@ -13,6 +13,7 @@ #include #include #include +#include #include #include #include @@ -21,6 +22,7 @@ #include #include #include +#include static int zero; static int tcp_retr1_max = 255; @@ -30,6 +32,8 @@ static int tcp_adv_win_scale_min = -31; static int tcp_adv_win_scale_max = 31; static int ip_ttl_min = 1; static int ip_ttl_max = 255; +static int ip_ping_group_range_min[] = { 0, 0 }; +static int ip_ping_group_range_max[] = { GID_T_MAX, GID_T_MAX }; /* Update system visible IP port range */ static void set_local_port_range(int range[2]) @@ -68,6 +72,65 @@ static int ipv4_local_port_range(ctl_table *table, int write, return ret; } + +void inet_get_ping_group_range_net(struct net *net, gid_t *low, gid_t *high) +{ + gid_t *data = net->ipv4.sysctl_ping_group_range; + unsigned seq; + do { + seq = read_seqbegin(&sysctl_local_ports.lock); + + *low = data[0]; + *high = data[1]; + } while (read_seqretry(&sysctl_local_ports.lock, seq)); +} + +void inet_get_ping_group_range_table(struct ctl_table *table, gid_t *low, gid_t *high) +{ + gid_t *data = table->data; + unsigned seq; + do { + seq = read_seqbegin(&sysctl_local_ports.lock); + + *low = data[0]; + *high = data[1]; + } while (read_seqretry(&sysctl_local_ports.lock, seq)); +} + +/* Update system visible IP port range */ +static void set_ping_group_range(struct ctl_table *table, int range[2]) +{ + gid_t *data = table->data; + write_seqlock(&sysctl_local_ports.lock); + data[0] = range[0]; + data[1] = range[1]; + write_sequnlock(&sysctl_local_ports.lock); +} + +/* Validate changes from /proc interface. */ +static int ipv4_ping_group_range(ctl_table *table, int write, + void __user *buffer, + size_t *lenp, loff_t *ppos) +{ + int ret; + gid_t range[2]; + ctl_table tmp = { + .data = &range, + .maxlen = sizeof(range), + .mode = table->mode, + .extra1 = &ip_ping_group_range_min, + .extra2 = &ip_ping_group_range_max, + }; + + inet_get_ping_group_range_table(table, range, range + 1); + ret = proc_dointvec_minmax(&tmp, write, buffer, lenp, ppos); + + if (write && ret == 0) + set_ping_group_range(table, range); + + return ret; +} + static int proc_tcp_congestion_control(ctl_table *ctl, int write, void __user *buffer, size_t *lenp, loff_t *ppos) { @@ -677,6 +740,13 @@ static struct ctl_table ipv4_net_table[] = { .mode = 0644, .proc_handler = proc_dointvec }, + { + .procname = "ping_group_range", + .data = &init_net.ipv4.sysctl_ping_group_range, + .maxlen = sizeof(init_net.ipv4.sysctl_ping_group_range), + .mode = 0644, + .proc_handler = ipv4_ping_group_range, + }, { } }; @@ -711,8 +781,18 @@ static __net_init int ipv4_sysctl_init_net(struct net *net) &net->ipv4.sysctl_icmp_ratemask; table[6].data = &net->ipv4.sysctl_rt_cache_rebuild_count; + table[7].data = + &net->ipv4.sysctl_ping_group_range; + } + /* + * Sane defaults - nobody may create ping sockets. + * Boot scripts should set this to distro-specific group. + */ + net->ipv4.sysctl_ping_group_range[0] = 1; + net->ipv4.sysctl_ping_group_range[1] = 0; + net->ipv4.sysctl_rt_cache_rebuild_count = 4; net->ipv4.ipv4_hdr = register_net_sysctl_table(net, -- cgit v0.10.2 From 5310cbce900094dce5df4a671b411e15319a75d4 Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Fri, 13 May 2011 04:15:39 +0000 Subject: drivers/isdn/hisax: Drop unused list The file st5481_init.c locally defines and initializes the adapter_list variable, but does not use it for anything. Removing the list makes it possible to remove the list field from the st5481_adapter data structure. In the function probe_st5481, it also makes it possible to free the locally allocated adapter value on an error exit. Signed-off-by: Julia Lawall Signed-off-by: David S. Miller diff --git a/drivers/isdn/hisax/st5481.h b/drivers/isdn/hisax/st5481.h index 64f78a8..b9054cb 100644 --- a/drivers/isdn/hisax/st5481.h +++ b/drivers/isdn/hisax/st5481.h @@ -377,7 +377,6 @@ struct st5481_bcs { }; struct st5481_adapter { - struct list_head list; int number_of_leds; struct usb_device *usb_dev; struct hisax_d_if hisax_d_if; diff --git a/drivers/isdn/hisax/st5481_init.c b/drivers/isdn/hisax/st5481_init.c index 1375123..9f7fd18 100644 --- a/drivers/isdn/hisax/st5481_init.c +++ b/drivers/isdn/hisax/st5481_init.c @@ -46,8 +46,6 @@ module_param(debug, int, 0); #endif int st5481_debug; -static LIST_HEAD(adapter_list); - /* ====================================================================== * registration/deregistration with the USB layer */ @@ -86,7 +84,6 @@ static int probe_st5481(struct usb_interface *intf, adapter->bcs[i].b_if.ifc.priv = &adapter->bcs[i]; adapter->bcs[i].b_if.ifc.l2l1 = st5481_b_l2l1; } - list_add(&adapter->list, &adapter_list); retval = st5481_setup_usb(adapter); if (retval < 0) @@ -125,6 +122,7 @@ static int probe_st5481(struct usb_interface *intf, err_usb: st5481_release_usb(adapter); err: + kfree(adapter); return -EIO; } @@ -142,8 +140,6 @@ static void disconnect_st5481(struct usb_interface *intf) if (!adapter) return; - list_del(&adapter->list); - st5481_stop(adapter); st5481_release_b(&adapter->bcs[1]); st5481_release_b(&adapter->bcs[0]); -- cgit v0.10.2 From 1334cb60826377de8f75adb9902c25302222f4fe Mon Sep 17 00:00:00 2001 From: David Decotigny Date: Thu, 12 May 2011 20:28:04 +0000 Subject: stmmac: don't go through ethtool to start auto-negotiation The driver used to call phy's ethtool configuration routine to start auto-negotiation. This change has it call directly phy's routine to start auto-negotiation. The initial version was hiding phy_start_aneg() return value, this patch returns it (<0 upon error). Tested: module compiles, tested on STM HDK7108 STB. Signed-off-by: David Decotigny Signed-off-by: Giuseppe Cavallaro Signed-off-by: David S. Miller diff --git a/drivers/net/stmmac/stmmac_ethtool.c b/drivers/net/stmmac/stmmac_ethtool.c index 6f5aaeb..9c05cf0 100644 --- a/drivers/net/stmmac/stmmac_ethtool.c +++ b/drivers/net/stmmac/stmmac_ethtool.c @@ -236,17 +236,8 @@ stmmac_set_pauseparam(struct net_device *netdev, priv->flow_ctrl = new_pause; if (phy->autoneg) { - if (netif_running(netdev)) { - struct ethtool_cmd cmd = { .cmd = ETHTOOL_SSET }; - /* auto-negotiation automatically restarted */ - cmd.supported = phy->supported; - cmd.advertising = phy->advertising; - cmd.autoneg = phy->autoneg; - ethtool_cmd_speed_set(&cmd, phy->speed); - cmd.duplex = phy->duplex; - cmd.phy_address = phy->addr; - ret = phy_ethtool_sset(phy, &cmd); - } + if (netif_running(netdev)) + ret = phy_start_aneg(phy); } else priv->hw->mac->flow_ctrl(priv->ioaddr, phy->duplex, priv->flow_ctrl, priv->pause); -- cgit v0.10.2 From 64c7f304b81a9a92dc7046c97a10427a5997dc07 Mon Sep 17 00:00:00 2001 From: Giuseppe CAVALLARO Date: Thu, 12 May 2011 20:28:05 +0000 Subject: stmmac: fix autoneg in set_pauseparam This patch fixes a bug in the set_pauseparam function that didn't well manage the ANE field and returned broken values when use ethtool -A|-a. Signed-off-by: Giuseppe Cavallaro Signed-off-by: David S. Miller diff --git a/drivers/net/stmmac/stmmac_ethtool.c b/drivers/net/stmmac/stmmac_ethtool.c index 9c05cf0..ae5213a 100644 --- a/drivers/net/stmmac/stmmac_ethtool.c +++ b/drivers/net/stmmac/stmmac_ethtool.c @@ -234,6 +234,7 @@ stmmac_set_pauseparam(struct net_device *netdev, new_pause |= FLOW_TX; priv->flow_ctrl = new_pause; + phy->autoneg = pause->autoneg; if (phy->autoneg) { if (netif_running(netdev)) -- cgit v0.10.2 From 0696c3a8acd3b7c3186dd231d65d97e05a75189f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Peter=20Pan=28=E6=BD=98=E5=8D=AB=E5=B9=B3=29?= Date: Thu, 12 May 2011 15:46:56 +0000 Subject: net:set valid name before calling ndo_init() In commit 1c5cae815d19 (net: call dev_alloc_name from register_netdevice), a bug of bonding was involved, see example 1 and 2. In register_netdevice(), the name of net_device is not valid until dev_get_valid_name() is called. But dev->netdev_ops->ndo_init(that is bond_init) is called before dev_get_valid_name(), and it uses the invalid name of net_device. I think register_netdevice() should make sure that the name of net_device is valid before calling ndo_init(). example 1: modprobe bonding ls /proc/net/bonding/bond%d ps -eLf root 3398 2 3398 0 1 21:34 ? 00:00:00 [bond%d] example 2: modprobe bonding max_bonds=3 [ 170.100292] bonding: Ethernet Channel Bonding Driver: v3.7.1 (April 27, 2011) [ 170.101090] bonding: Warning: either miimon or arp_interval and arp_ip_target module parameters must be specified, otherwise bonding will not detect link failures! see bonding.txt for details. [ 170.102469] ------------[ cut here ]------------ [ 170.103150] WARNING: at /home/pwp/net-next-2.6/fs/proc/generic.c:586 proc_register+0x126/0x157() [ 170.104075] Hardware name: VirtualBox [ 170.105065] proc_dir_entry 'bonding/bond%d' already registered [ 170.105613] Modules linked in: bonding(+) sunrpc ipv6 uinput microcode ppdev parport_pc parport joydev e1000 pcspkr i2c_piix4 i2c_core [last unloaded: bonding] [ 170.108397] Pid: 3457, comm: modprobe Not tainted 2.6.39-rc2+ #14 [ 170.108935] Call Trace: [ 170.109382] [] warn_slowpath_common+0x6a/0x7f [ 170.109911] [] ? proc_register+0x126/0x157 [ 170.110329] [] warn_slowpath_fmt+0x2b/0x2f [ 170.110846] [] proc_register+0x126/0x157 [ 170.111870] [] proc_create_data+0x82/0x98 [ 170.112335] [] bond_create_proc_entry+0x3f/0x73 [bonding] [ 170.112905] [] bond_init+0x77/0xa5 [bonding] [ 170.113319] [] register_netdevice+0x8c/0x1d3 [ 170.113848] [] bond_create+0x6c/0x90 [bonding] [ 170.114322] [] bonding_init+0x763/0x7b1 [bonding] [ 170.114879] [] do_one_initcall+0x76/0x122 [ 170.115317] [] ? 0xf94f3fff [ 170.115799] [] sys_init_module+0x1286/0x140d [ 170.116879] [] sysenter_do_call+0x12/0x28 [ 170.117404] ---[ end trace 64e4fac3ae5fff1a ]--- [ 170.117924] bond%d: Warning: failed to register to debugfs [ 170.128728] ------------[ cut here ]------------ [ 170.129360] WARNING: at /home/pwp/net-next-2.6/fs/proc/generic.c:586 proc_register+0x126/0x157() [ 170.130323] Hardware name: VirtualBox [ 170.130797] proc_dir_entry 'bonding/bond%d' already registered [ 170.131315] Modules linked in: bonding(+) sunrpc ipv6 uinput microcode ppdev parport_pc parport joydev e1000 pcspkr i2c_piix4 i2c_core [last unloaded: bonding] [ 170.133731] Pid: 3457, comm: modprobe Tainted: G W 2.6.39-rc2+ #14 [ 170.134308] Call Trace: [ 170.134743] [] warn_slowpath_common+0x6a/0x7f [ 170.135305] [] ? proc_register+0x126/0x157 [ 170.135820] [] warn_slowpath_fmt+0x2b/0x2f [ 170.137168] [] proc_register+0x126/0x157 [ 170.137700] [] proc_create_data+0x82/0x98 [ 170.138174] [] bond_create_proc_entry+0x3f/0x73 [bonding] [ 170.138745] [] bond_init+0x77/0xa5 [bonding] [ 170.139278] [] register_netdevice+0x8c/0x1d3 [ 170.139828] [] bond_create+0x6c/0x90 [bonding] [ 170.140361] [] bonding_init+0x763/0x7b1 [bonding] [ 170.140927] [] do_one_initcall+0x76/0x122 [ 170.141494] [] ? 0xf94f3fff [ 170.141975] [] sys_init_module+0x1286/0x140d [ 170.142463] [] sysenter_do_call+0x12/0x28 [ 170.142974] ---[ end trace 64e4fac3ae5fff1b ]--- [ 170.144949] bond%d: Warning: failed to register to debugfs Signed-off-by: Weiping Pan Reviewed-by: Jiri Pirko Signed-off-by: David S. Miller diff --git a/net/core/dev.c b/net/core/dev.c index ea23353..3ed09f8 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -5437,6 +5437,10 @@ int register_netdevice(struct net_device *dev) dev->iflink = -1; + ret = dev_get_valid_name(dev, dev->name); + if (ret < 0) + goto out; + /* Init, if this function is available */ if (dev->netdev_ops->ndo_init) { ret = dev->netdev_ops->ndo_init(dev); @@ -5447,10 +5451,6 @@ int register_netdevice(struct net_device *dev) } } - ret = dev_get_valid_name(dev, dev->name); - if (ret < 0) - goto err_uninit; - dev->ifindex = dev_new_index(net); if (dev->iflink == -1) dev->iflink = dev->ifindex; -- cgit v0.10.2 From 48e20467227fe540e6bbf3d98df98c2c0fca10f3 Mon Sep 17 00:00:00 2001 From: Alexey Dobriyan Date: Fri, 13 May 2011 16:50:49 -0400 Subject: olympic: convert to seq_file ->read_proc interface is going away, switch to seq_file. Signed-off-by: Alexey Dobriyan Signed-off-by: David S. Miller diff --git a/drivers/net/tokenring/olympic.c b/drivers/net/tokenring/olympic.c index 2684003..e3855ae 100644 --- a/drivers/net/tokenring/olympic.c +++ b/drivers/net/tokenring/olympic.c @@ -86,6 +86,7 @@ #include #include #include +#include #include #include #include @@ -193,7 +194,7 @@ static void olympic_arb_cmd(struct net_device *dev); static int olympic_change_mtu(struct net_device *dev, int mtu); static void olympic_srb_bh(struct net_device *dev) ; static void olympic_asb_bh(struct net_device *dev) ; -static int olympic_proc_info(char *buffer, char **start, off_t offset, int length, int *eof, void *data) ; +static const struct file_operations olympic_proc_ops; static const struct net_device_ops olympic_netdev_ops = { .ndo_open = olympic_open, @@ -272,7 +273,7 @@ static int __devinit olympic_probe(struct pci_dev *pdev, const struct pci_device char proc_name[20] ; strcpy(proc_name,"olympic_") ; strcat(proc_name,dev->name) ; - create_proc_read_entry(proc_name,0,init_net.proc_net,olympic_proc_info,(void *)dev) ; + proc_create_data(proc_name, 0, init_net.proc_net, &olympic_proc_ops, dev); printk("Olympic: Network Monitor information: /proc/%s\n",proc_name); } return 0 ; @@ -1615,29 +1616,25 @@ static int olympic_change_mtu(struct net_device *dev, int mtu) return 0 ; } -static int olympic_proc_info(char *buffer, char **start, off_t offset, int length, int *eof, void *data) +static int olympic_proc_show(struct seq_file *m, void *v) { - struct net_device *dev = (struct net_device *)data ; + struct net_device *dev = m->private; struct olympic_private *olympic_priv=netdev_priv(dev); u8 __iomem *oat = (olympic_priv->olympic_lap + olympic_priv->olympic_addr_table_addr) ; u8 __iomem *opt = (olympic_priv->olympic_lap + olympic_priv->olympic_parms_addr) ; - int size = 0 ; - int len=0; - off_t begin=0; - off_t pos=0; u8 addr[6]; u8 addr2[6]; int i; - size = sprintf(buffer, + seq_printf(m, "IBM Pit/Pit-Phy/Olympic Chipset Token Ring Adapter %s\n",dev->name); - size += sprintf(buffer+size, "\n%6s: Adapter Address : Node Address : Functional Addr\n", + seq_printf(m, "\n%6s: Adapter Address : Node Address : Functional Addr\n", dev->name); for (i = 0 ; i < 6 ; i++) addr[i] = readb(oat+offsetof(struct olympic_adapter_addr_table,node_addr) + i); - size += sprintf(buffer+size, "%6s: %pM : %pM : %02x:%02x:%02x:%02x\n", + seq_printf(m, "%6s: %pM : %pM : %02x:%02x:%02x:%02x\n", dev->name, dev->dev_addr, addr, readb(oat+offsetof(struct olympic_adapter_addr_table,func_addr)), @@ -1645,9 +1642,9 @@ static int olympic_proc_info(char *buffer, char **start, off_t offset, int lengt readb(oat+offsetof(struct olympic_adapter_addr_table,func_addr)+2), readb(oat+offsetof(struct olympic_adapter_addr_table,func_addr)+3)); - size += sprintf(buffer+size, "\n%6s: Token Ring Parameters Table:\n", dev->name); + seq_printf(m, "\n%6s: Token Ring Parameters Table:\n", dev->name); - size += sprintf(buffer+size, "%6s: Physical Addr : Up Node Address : Poll Address : AccPri : Auth Src : Att Code :\n", + seq_printf(m, "%6s: Physical Addr : Up Node Address : Poll Address : AccPri : Auth Src : Att Code :\n", dev->name) ; for (i = 0 ; i < 6 ; i++) @@ -1655,7 +1652,7 @@ static int olympic_proc_info(char *buffer, char **start, off_t offset, int lengt for (i = 0 ; i < 6 ; i++) addr2[i] = readb(opt+offsetof(struct olympic_parameters_table, poll_addr) + i); - size += sprintf(buffer+size, "%6s: %02x:%02x:%02x:%02x : %pM : %pM : %04x : %04x : %04x :\n", + seq_printf(m, "%6s: %02x:%02x:%02x:%02x : %pM : %pM : %04x : %04x : %04x :\n", dev->name, readb(opt+offsetof(struct olympic_parameters_table, phys_addr)), readb(opt+offsetof(struct olympic_parameters_table, phys_addr)+1), @@ -1666,12 +1663,12 @@ static int olympic_proc_info(char *buffer, char **start, off_t offset, int lengt swab16(readw(opt+offsetof(struct olympic_parameters_table, auth_source_class))), swab16(readw(opt+offsetof(struct olympic_parameters_table, att_code)))); - size += sprintf(buffer+size, "%6s: Source Address : Bcn T : Maj. V : Lan St : Lcl Rg : Mon Err : Frame Correl : \n", + seq_printf(m, "%6s: Source Address : Bcn T : Maj. V : Lan St : Lcl Rg : Mon Err : Frame Correl : \n", dev->name) ; for (i = 0 ; i < 6 ; i++) addr[i] = readb(opt+offsetof(struct olympic_parameters_table, source_addr) + i); - size += sprintf(buffer+size, "%6s: %pM : %04x : %04x : %04x : %04x : %04x : %04x : \n", + seq_printf(m, "%6s: %pM : %04x : %04x : %04x : %04x : %04x : %04x : \n", dev->name, addr, swab16(readw(opt+offsetof(struct olympic_parameters_table, beacon_type))), swab16(readw(opt+offsetof(struct olympic_parameters_table, major_vector))), @@ -1680,12 +1677,12 @@ static int olympic_proc_info(char *buffer, char **start, off_t offset, int lengt swab16(readw(opt+offsetof(struct olympic_parameters_table, mon_error))), swab16(readw(opt+offsetof(struct olympic_parameters_table, frame_correl)))); - size += sprintf(buffer+size, "%6s: Beacon Details : Tx : Rx : NAUN Node Address : NAUN Node Phys : \n", + seq_printf(m, "%6s: Beacon Details : Tx : Rx : NAUN Node Address : NAUN Node Phys : \n", dev->name) ; for (i = 0 ; i < 6 ; i++) addr[i] = readb(opt+offsetof(struct olympic_parameters_table, beacon_naun) + i); - size += sprintf(buffer+size, "%6s: : %02x : %02x : %pM : %02x:%02x:%02x:%02x : \n", + seq_printf(m, "%6s: : %02x : %02x : %pM : %02x:%02x:%02x:%02x : \n", dev->name, swab16(readw(opt+offsetof(struct olympic_parameters_table, beacon_transmit))), swab16(readw(opt+offsetof(struct olympic_parameters_table, beacon_receive))), @@ -1695,19 +1692,21 @@ static int olympic_proc_info(char *buffer, char **start, off_t offset, int lengt readb(opt+offsetof(struct olympic_parameters_table, beacon_phys)+2), readb(opt+offsetof(struct olympic_parameters_table, beacon_phys)+3)); - len=size; - pos=begin+size; - if (poslength) - len=length; /* Ending slop */ - return len; + return 0; } +static int olympic_proc_open(struct inode *inode, struct file *file) +{ + return single_open(file, olympic_proc_show, PDE(inode)->data); +} + +static const struct file_operations olympic_proc_ops = { + .open = olympic_proc_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + static void __devexit olympic_remove_one(struct pci_dev *pdev) { struct net_device *dev = pci_get_drvdata(pdev) ; -- cgit v0.10.2 From 1fec70932d867416ffe620dd17005f168cc84eb5 Mon Sep 17 00:00:00 2001 From: Yehuda Sadeh Date: Fri, 13 May 2011 13:52:56 -0700 Subject: rbd: fix split bio handling The rbd driver currently splits bios when they span an object boundary. However, the blk_end_request expects the completions to roll up the results in block device order, and the split rbd/ceph ops can complete in any order. This patch adds a struct rbd_req_coll to track completion of split requests and ensures that the results are passed back up to the block layer in order. This fixes errors where the file system gets completion of a read operation that spans an object boundary before the data has actually arrived. The bug is easily reproduced with iozone with a working set larger than available RAM. Reported-by: Fyodor Ustinov Signed-off-by: Yehuda Sadeh Signed-off-by: Sage Weil diff --git a/drivers/block/rbd.c b/drivers/block/rbd.c index 2146cab..9712fad 100644 --- a/drivers/block/rbd.c +++ b/drivers/block/rbd.c @@ -92,6 +92,8 @@ struct rbd_client { struct list_head node; }; +struct rbd_req_coll; + /* * a single io request */ @@ -100,6 +102,24 @@ struct rbd_request { struct bio *bio; /* cloned bio */ struct page **pages; /* list of used pages */ u64 len; + int coll_index; + struct rbd_req_coll *coll; +}; + +struct rbd_req_status { + int done; + int rc; + u64 bytes; +}; + +/* + * a collection of requests + */ +struct rbd_req_coll { + int total; + int num_done; + struct kref kref; + struct rbd_req_status status[0]; }; struct rbd_snap { @@ -416,6 +436,17 @@ static void rbd_put_client(struct rbd_device *rbd_dev) rbd_dev->client = NULL; } +/* + * Destroy requests collection + */ +static void rbd_coll_release(struct kref *kref) +{ + struct rbd_req_coll *coll = + container_of(kref, struct rbd_req_coll, kref); + + dout("rbd_coll_release %p\n", coll); + kfree(coll); +} /* * Create a new header structure, translate header format from the on-disk @@ -590,6 +621,14 @@ static u64 rbd_get_segment(struct rbd_image_header *header, return len; } +static int rbd_get_num_segments(struct rbd_image_header *header, + u64 ofs, u64 len) +{ + u64 start_seg = ofs >> header->obj_order; + u64 end_seg = (ofs + len - 1) >> header->obj_order; + return end_seg - start_seg + 1; +} + /* * bio helpers */ @@ -735,6 +774,50 @@ static void rbd_destroy_ops(struct ceph_osd_req_op *ops) kfree(ops); } +static void rbd_coll_end_req_index(struct request *rq, + struct rbd_req_coll *coll, + int index, + int ret, u64 len) +{ + struct request_queue *q; + int min, max, i; + + dout("rbd_coll_end_req_index %p index %d ret %d len %lld\n", + coll, index, ret, len); + + if (!rq) + return; + + if (!coll) { + blk_end_request(rq, ret, len); + return; + } + + q = rq->q; + + spin_lock_irq(q->queue_lock); + coll->status[index].done = 1; + coll->status[index].rc = ret; + coll->status[index].bytes = len; + max = min = coll->num_done; + while (max < coll->total && coll->status[max].done) + max++; + + for (i = min; istatus[i].rc, + coll->status[i].bytes); + coll->num_done++; + kref_put(&coll->kref, rbd_coll_release); + } + spin_unlock_irq(q->queue_lock); +} + +static void rbd_coll_end_req(struct rbd_request *req, + int ret, u64 len) +{ + rbd_coll_end_req_index(req->rq, req->coll, req->coll_index, ret, len); +} + /* * Send ceph osd request */ @@ -749,6 +832,8 @@ static int rbd_do_request(struct request *rq, int flags, struct ceph_osd_req_op *ops, int num_reply, + struct rbd_req_coll *coll, + int coll_index, void (*rbd_cb)(struct ceph_osd_request *req, struct ceph_msg *msg), struct ceph_osd_request **linger_req, @@ -763,12 +848,20 @@ static int rbd_do_request(struct request *rq, struct ceph_osd_request_head *reqhead; struct rbd_image_header *header = &dev->header; - ret = -ENOMEM; req_data = kzalloc(sizeof(*req_data), GFP_NOIO); - if (!req_data) - goto done; + if (!req_data) { + if (coll) + rbd_coll_end_req_index(rq, coll, coll_index, + -ENOMEM, len); + return -ENOMEM; + } + + if (coll) { + req_data->coll = coll; + req_data->coll_index = coll_index; + } - dout("rbd_do_request len=%lld ofs=%lld\n", len, ofs); + dout("rbd_do_request obj=%s ofs=%lld len=%lld\n", obj, len, ofs); down_read(&header->snap_rwsem); @@ -828,7 +921,8 @@ static int rbd_do_request(struct request *rq, ret = ceph_osdc_wait_request(&dev->client->osdc, req); if (ver) *ver = le64_to_cpu(req->r_reassert_version.version); - dout("reassert_ver=%lld\n", le64_to_cpu(req->r_reassert_version.version)); + dout("reassert_ver=%lld\n", + le64_to_cpu(req->r_reassert_version.version)); ceph_osdc_put_request(req); } return ret; @@ -837,10 +931,8 @@ done_err: bio_chain_put(req_data->bio); ceph_osdc_put_request(req); done_pages: + rbd_coll_end_req(req_data, ret, len); kfree(req_data); -done: - if (rq) - blk_end_request(rq, ret, len); return ret; } @@ -874,7 +966,7 @@ static void rbd_req_cb(struct ceph_osd_request *req, struct ceph_msg *msg) bytes = req_data->len; } - blk_end_request(req_data->rq, rc, bytes); + rbd_coll_end_req(req_data, rc, bytes); if (req_data->bio) bio_chain_put(req_data->bio); @@ -934,6 +1026,7 @@ static int rbd_req_sync_op(struct rbd_device *dev, flags, ops, 2, + NULL, 0, NULL, linger_req, ver); if (ret < 0) @@ -959,7 +1052,9 @@ static int rbd_do_op(struct request *rq, u64 snapid, int opcode, int flags, int num_reply, u64 ofs, u64 len, - struct bio *bio) + struct bio *bio, + struct rbd_req_coll *coll, + int coll_index) { char *seg_name; u64 seg_ofs; @@ -995,6 +1090,7 @@ static int rbd_do_op(struct request *rq, flags, ops, num_reply, + coll, coll_index, rbd_req_cb, 0, NULL); rbd_destroy_ops(ops); @@ -1010,13 +1106,15 @@ static int rbd_req_write(struct request *rq, struct rbd_device *rbd_dev, struct ceph_snap_context *snapc, u64 ofs, u64 len, - struct bio *bio) + struct bio *bio, + struct rbd_req_coll *coll, + int coll_index) { return rbd_do_op(rq, rbd_dev, snapc, CEPH_NOSNAP, CEPH_OSD_OP_WRITE, CEPH_OSD_FLAG_WRITE | CEPH_OSD_FLAG_ONDISK, 2, - ofs, len, bio); + ofs, len, bio, coll, coll_index); } /* @@ -1026,14 +1124,16 @@ static int rbd_req_read(struct request *rq, struct rbd_device *rbd_dev, u64 snapid, u64 ofs, u64 len, - struct bio *bio) + struct bio *bio, + struct rbd_req_coll *coll, + int coll_index) { return rbd_do_op(rq, rbd_dev, NULL, (snapid ? snapid : CEPH_NOSNAP), CEPH_OSD_OP_READ, CEPH_OSD_FLAG_READ, 2, - ofs, len, bio); + ofs, len, bio, coll, coll_index); } /* @@ -1081,6 +1181,7 @@ static int rbd_req_sync_notify_ack(struct rbd_device *dev, CEPH_OSD_FLAG_READ, ops, 1, + NULL, 0, rbd_simple_req_cb, 0, NULL); rbd_destroy_ops(ops); @@ -1278,6 +1379,20 @@ static int rbd_req_sync_exec(struct rbd_device *dev, return ret; } +static struct rbd_req_coll *rbd_alloc_coll(int num_reqs) +{ + struct rbd_req_coll *coll = + kzalloc(sizeof(struct rbd_req_coll) + + sizeof(struct rbd_req_status) * num_reqs, + GFP_ATOMIC); + + if (!coll) + return NULL; + coll->total = num_reqs; + kref_init(&coll->kref); + return coll; +} + /* * block device queue callback */ @@ -1295,6 +1410,8 @@ static void rbd_rq_fn(struct request_queue *q) bool do_write; int size, op_size = 0; u64 ofs; + int num_segs, cur_seg = 0; + struct rbd_req_coll *coll; /* peek at request from block layer */ if (!rq) @@ -1325,6 +1442,14 @@ static void rbd_rq_fn(struct request_queue *q) do_write ? "write" : "read", size, blk_rq_pos(rq) * 512ULL); + num_segs = rbd_get_num_segments(&rbd_dev->header, ofs, size); + coll = rbd_alloc_coll(num_segs); + if (!coll) { + spin_lock_irq(q->queue_lock); + __blk_end_request_all(rq, -ENOMEM); + goto next; + } + do { /* a bio clone to be passed down to OSD req */ dout("rq->bio->bi_vcnt=%d\n", rq->bio->bi_vcnt); @@ -1332,35 +1457,41 @@ static void rbd_rq_fn(struct request_queue *q) rbd_dev->header.block_name, ofs, size, NULL, NULL); + kref_get(&coll->kref); bio = bio_chain_clone(&rq_bio, &next_bio, &bp, op_size, GFP_ATOMIC); if (!bio) { - spin_lock_irq(q->queue_lock); - __blk_end_request_all(rq, -ENOMEM); - goto next; + rbd_coll_end_req_index(rq, coll, cur_seg, + -ENOMEM, op_size); + goto next_seg; } + /* init OSD command: write or read */ if (do_write) rbd_req_write(rq, rbd_dev, rbd_dev->header.snapc, ofs, - op_size, bio); + op_size, bio, + coll, cur_seg); else rbd_req_read(rq, rbd_dev, cur_snap_id(rbd_dev), ofs, - op_size, bio); + op_size, bio, + coll, cur_seg); +next_seg: size -= op_size; ofs += op_size; + cur_seg++; rq_bio = next_bio; } while (size > 0); + kref_put(&coll->kref, rbd_coll_release); if (bp) bio_pair_release(bp); - spin_lock_irq(q->queue_lock); next: rq = blk_fetch_request(q); -- cgit v0.10.2 From 0374d9ceb02eb12fcd65be9dd5df9c911ef93424 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Fri, 13 May 2011 17:15:50 -0400 Subject: ipv4: Kill spurious write to iph->daddr in ip_forward_options(). This code block executes when opt->srr_is_hit is set. It will be set only by ip_options_rcv_srr(). ip_options_rcv_srr() walks until it hits a matching nexthop in the SRR option addresses, and when it matches one 1) looks up the route for that nexthop and 2) on route lookup success it writes that nexthop value into iph->daddr. ip_forward_options() runs later, and again walks the SRR option addresses looking for the option matching the destination of the route stored in skb_rtable(). This route will be the same exact one looked up for the nexthop by ip_options_rcv_srr(). Therefore "rt->rt_dst == iph->daddr" must be true. All it really needs to do is record the route's source address in the matching SRR option adddress. It need not write iph->daddr again, since that has already been done by ip_options_rcv_srr() as detailed above. Signed-off-by: David S. Miller diff --git a/net/ipv4/ip_options.c b/net/ipv4/ip_options.c index c5c2619..c6474cd 100644 --- a/net/ipv4/ip_options.c +++ b/net/ipv4/ip_options.c @@ -573,7 +573,6 @@ void ip_forward_options(struct sk_buff *skb) if (srrptr + 3 <= srrspace) { opt->is_changed = 1; ip_rt_get_source(&optptr[srrptr-1], rt); - ip_hdr(skb)->daddr = rt->rt_dst; optptr[2] = srrptr+4; } else if (net_ratelimit()) printk(KERN_CRIT "ip_forward(): Argh! Destination lost!\n"); -- cgit v0.10.2 From 22f728f8f311659b068e73ed92833c205651a47f Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Fri, 13 May 2011 17:21:27 -0400 Subject: ipv4: Always call ip_options_build() after rest of IP header is filled in. This will allow ip_options_build() to reliably look at the values of iph->{daddr,saddr} Signed-off-by: David S. Miller diff --git a/net/ipv4/ip_output.c b/net/ipv4/ip_output.c index 70778d4..98af369 100644 --- a/net/ipv4/ip_output.c +++ b/net/ipv4/ip_output.c @@ -1327,10 +1327,6 @@ struct sk_buff *__ip_make_skb(struct sock *sk, iph = (struct iphdr *)skb->data; iph->version = 4; iph->ihl = 5; - if (opt) { - iph->ihl += opt->optlen>>2; - ip_options_build(skb, opt, cork->addr, rt, 0); - } iph->tos = inet->tos; iph->frag_off = df; ip_select_ident(iph, &rt->dst, sk); @@ -1339,6 +1335,11 @@ struct sk_buff *__ip_make_skb(struct sock *sk, iph->saddr = fl4->saddr; iph->daddr = fl4->daddr; + if (opt) { + iph->ihl += opt->optlen>>2; + ip_options_build(skb, opt, cork->addr, rt, 0); + } + skb->priority = sk->sk_priority; skb->mark = sk->sk_mark; /* -- cgit v0.10.2 From 8e36360ae876995e92d3a7538dda70548e64e685 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Fri, 13 May 2011 17:29:41 -0400 Subject: ipv4: Remove route key identity dependencies in ip_rt_get_source(). Pass in the sk_buff so that we can fetch the necessary keys from the packet header when working with input routes. Signed-off-by: David S. Miller diff --git a/include/net/route.h b/include/net/route.h index 9f8070b..ba0e084 100644 --- a/include/net/route.h +++ b/include/net/route.h @@ -189,7 +189,7 @@ extern unsigned inet_addr_type(struct net *net, __be32 addr); extern unsigned inet_dev_addr_type(struct net *net, const struct net_device *dev, __be32 addr); extern void ip_rt_multicast_event(struct in_device *); extern int ip_rt_ioctl(struct net *, unsigned int cmd, void __user *arg); -extern void ip_rt_get_source(u8 *src, struct rtable *rt); +extern void ip_rt_get_source(u8 *src, struct sk_buff *skb, struct rtable *rt); extern int ip_rt_dump(struct sk_buff *skb, struct netlink_callback *cb); struct in_ifaddr; diff --git a/net/ipv4/ip_options.c b/net/ipv4/ip_options.c index c6474cd..89268ba 100644 --- a/net/ipv4/ip_options.c +++ b/net/ipv4/ip_options.c @@ -37,7 +37,7 @@ */ void ip_options_build(struct sk_buff *skb, struct ip_options *opt, - __be32 daddr, struct rtable *rt, int is_frag) + __be32 daddr, struct rtable *rt, int is_frag) { unsigned char *iph = skb_network_header(skb); @@ -50,9 +50,9 @@ void ip_options_build(struct sk_buff *skb, struct ip_options *opt, if (!is_frag) { if (opt->rr_needaddr) - ip_rt_get_source(iph+opt->rr+iph[opt->rr+2]-5, rt); + ip_rt_get_source(iph+opt->rr+iph[opt->rr+2]-5, skb, rt); if (opt->ts_needaddr) - ip_rt_get_source(iph+opt->ts+iph[opt->ts+2]-9, rt); + ip_rt_get_source(iph+opt->ts+iph[opt->ts+2]-9, skb, rt); if (opt->ts_needtime) { struct timespec tv; __be32 midtime; @@ -553,7 +553,7 @@ void ip_forward_options(struct sk_buff *skb) if (opt->rr_needaddr) { optptr = (unsigned char *)raw + opt->rr; - ip_rt_get_source(&optptr[optptr[2]-5], rt); + ip_rt_get_source(&optptr[optptr[2]-5], skb, rt); opt->is_changed = 1; } if (opt->srr_is_hit) { @@ -572,13 +572,13 @@ void ip_forward_options(struct sk_buff *skb) } if (srrptr + 3 <= srrspace) { opt->is_changed = 1; - ip_rt_get_source(&optptr[srrptr-1], rt); + ip_rt_get_source(&optptr[srrptr-1], skb, rt); optptr[2] = srrptr+4; } else if (net_ratelimit()) printk(KERN_CRIT "ip_forward(): Argh! Destination lost!\n"); if (opt->ts_needaddr) { optptr = raw + opt->ts; - ip_rt_get_source(&optptr[optptr[2]-9], rt); + ip_rt_get_source(&optptr[optptr[2]-9], skb, rt); opt->is_changed = 1; } } diff --git a/net/ipv4/route.c b/net/ipv4/route.c index 6a83840..ad141d8 100644 --- a/net/ipv4/route.c +++ b/net/ipv4/route.c @@ -1699,22 +1699,26 @@ static int ip_rt_bug(struct sk_buff *skb) in IP options! */ -void ip_rt_get_source(u8 *addr, struct rtable *rt) +void ip_rt_get_source(u8 *addr, struct sk_buff *skb, struct rtable *rt) { __be32 src; - struct fib_result res; if (rt_is_output_route(rt)) src = rt->rt_src; else { - struct flowi4 fl4 = { - .daddr = rt->rt_key_dst, - .saddr = rt->rt_key_src, - .flowi4_tos = rt->rt_key_tos, - .flowi4_oif = rt->rt_oif, - .flowi4_iif = rt->rt_iif, - .flowi4_mark = rt->rt_mark, - }; + struct fib_result res; + struct flowi4 fl4; + struct iphdr *iph; + + iph = ip_hdr(skb); + + memset(&fl4, 0, sizeof(fl4)); + fl4.daddr = iph->daddr; + fl4.saddr = iph->saddr; + fl4.flowi4_tos = iph->tos; + fl4.flowi4_oif = rt->dst.dev->ifindex; + fl4.flowi4_iif = skb->dev->ifindex; + fl4.flowi4_mark = skb->mark; rcu_read_lock(); if (fib_lookup(dev_net(rt->dst.dev), &fl4, &res) == 0) -- cgit v0.10.2 From 7be799a70ba3dd90a59e8d2c72bbe06020005b3f Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Fri, 13 May 2011 17:31:02 -0400 Subject: ipv4: Remove rt->rt_dst reference from ip_forward_options(). At this point iph->daddr equals what rt->rt_dst would hold. Signed-off-by: David S. Miller diff --git a/net/ipv4/ip_options.c b/net/ipv4/ip_options.c index 89268ba..c3118e1 100644 --- a/net/ipv4/ip_options.c +++ b/net/ipv4/ip_options.c @@ -567,7 +567,7 @@ void ip_forward_options(struct sk_buff *skb) ) { if (srrptr + 3 > srrspace) break; - if (memcmp(&rt->rt_dst, &optptr[srrptr-1], 4) == 0) + if (memcmp(&ip_hdr(skb)->daddr, &optptr[srrptr-1], 4) == 0) break; } if (srrptr + 3 <= srrspace) { -- cgit v0.10.2 From 82a3242e11d9e63c8195be46c954efaefee35e22 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Thu, 12 May 2011 16:01:02 -0700 Subject: sysfs: remove "last sysfs file:" line from the oops messages On some arches (x86, sh, arm, unicore, powerpc) the oops message would print out the last sysfs file accessed. This was very useful in finding a number of sysfs and driver core bugs in the 2.5 and early 2.6 development days, but it has been a number of years since this file has actually helped in debugging anything that couldn't also be trivially determined from the stack traceback. So it's time to delete the line. This is good as we need all the space we can get for oops messages at times on consoles. Acked-by: Phil Carmody Acked-by: Ingo Molnar Cc: Andrew Morton Cc: Thomas Gleixner Signed-off-by: Greg Kroah-Hartman diff --git a/arch/arm/kernel/traps.c b/arch/arm/kernel/traps.c index 3b54ad1..d52eec2 100644 --- a/arch/arm/kernel/traps.c +++ b/arch/arm/kernel/traps.c @@ -234,7 +234,6 @@ static int __die(const char *str, int err, struct thread_info *thread, struct pt printk(KERN_EMERG "Internal error: %s: %x [#%d]" S_PREEMPT S_SMP "\n", str, err, ++die_counter); - sysfs_printk_last_file(); /* trap and error numbers are mostly meaningless on ARM */ ret = notify_die(DIE_OOPS, str, regs, err, tsk->thread.trap_no, SIGSEGV); diff --git a/arch/powerpc/kernel/traps.c b/arch/powerpc/kernel/traps.c index 5ddb801..d782cd7 100644 --- a/arch/powerpc/kernel/traps.c +++ b/arch/powerpc/kernel/traps.c @@ -143,7 +143,6 @@ int die(const char *str, struct pt_regs *regs, long err) #endif printk("%s\n", ppc_md.name ? ppc_md.name : ""); - sysfs_printk_last_file(); if (notify_die(DIE_OOPS, str, regs, err, 255, SIGSEGV) == NOTIFY_STOP) return 1; diff --git a/arch/sh/kernel/traps_32.c b/arch/sh/kernel/traps_32.c index 3484c2f..b51a171 100644 --- a/arch/sh/kernel/traps_32.c +++ b/arch/sh/kernel/traps_32.c @@ -87,7 +87,6 @@ void die(const char * str, struct pt_regs * regs, long err) bust_spinlocks(1); printk("%s: %04lx [#%d]\n", str, err & 0xffff, ++die_counter); - sysfs_printk_last_file(); print_modules(); show_regs(regs); diff --git a/arch/unicore32/kernel/traps.c b/arch/unicore32/kernel/traps.c index 254e36f..b9a2646 100644 --- a/arch/unicore32/kernel/traps.c +++ b/arch/unicore32/kernel/traps.c @@ -192,7 +192,6 @@ static int __die(const char *str, int err, struct thread_info *thread, printk(KERN_EMERG "Internal error: %s: %x [#%d]\n", str, err, ++die_counter); - sysfs_printk_last_file(); /* trap and error numbers are mostly meaningless on UniCore */ ret = notify_die(DIE_OOPS, str, regs, err, tsk->thread.trap_no, \ diff --git a/arch/x86/kernel/dumpstack.c b/arch/x86/kernel/dumpstack.c index e2a3f06..f72e719 100644 --- a/arch/x86/kernel/dumpstack.c +++ b/arch/x86/kernel/dumpstack.c @@ -279,7 +279,6 @@ int __kprobes __die(const char *str, struct pt_regs *regs, long err) printk("DEBUG_PAGEALLOC"); #endif printk("\n"); - sysfs_printk_last_file(); if (notify_die(DIE_OOPS, str, regs, err, current->thread.trap_no, SIGSEGV) == NOTIFY_STOP) return 1; diff --git a/fs/sysfs/file.c b/fs/sysfs/file.c index da3fefe..1ad8c93 100644 --- a/fs/sysfs/file.c +++ b/fs/sysfs/file.c @@ -24,13 +24,6 @@ #include "sysfs.h" -/* used in crash dumps to help with debugging */ -static char last_sysfs_file[PATH_MAX]; -void sysfs_printk_last_file(void) -{ - printk(KERN_EMERG "last sysfs file: %s\n", last_sysfs_file); -} - /* * There's one sysfs_buffer for each open file and one * sysfs_open_dirent for each sysfs_dirent with one or more open @@ -337,11 +330,6 @@ static int sysfs_open_file(struct inode *inode, struct file *file) struct sysfs_buffer *buffer; const struct sysfs_ops *ops; int error = -EACCES; - char *p; - - p = d_path(&file->f_path, last_sysfs_file, sizeof(last_sysfs_file)); - if (!IS_ERR(p)) - memmove(last_sysfs_file, p, strlen(p) + 1); /* need attr_sd for attr and ops, its parent for kobj */ if (!sysfs_get_active(attr_sd)) diff --git a/include/linux/sysfs.h b/include/linux/sysfs.h index 30b8815..c3acda6 100644 --- a/include/linux/sysfs.h +++ b/include/linux/sysfs.h @@ -176,7 +176,6 @@ struct sysfs_dirent *sysfs_get_dirent(struct sysfs_dirent *parent_sd, const unsigned char *name); struct sysfs_dirent *sysfs_get(struct sysfs_dirent *sd); void sysfs_put(struct sysfs_dirent *sd); -void sysfs_printk_last_file(void); /* Called to clear a ns tag when it is no longer valid */ void sysfs_exit_ns(enum kobj_ns_type type, const void *tag); @@ -348,10 +347,6 @@ static inline int __must_check sysfs_init(void) return 0; } -static inline void sysfs_printk_last_file(void) -{ -} - #endif /* CONFIG_SYSFS */ #endif /* _SYSFS_H_ */ -- cgit v0.10.2 From c42d2237143fcf35cff642cefe2bcf7786aae312 Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Thu, 12 May 2011 16:50:07 -0700 Subject: debugfs: Silence DEBUG_STRICT_USER_COPY_CHECKS=y warning Enabling DEBUG_STRICT_USER_COPY_CHECKS causes the following warning: In file included from arch/x86/include/asm/uaccess.h:573, from include/linux/uaccess.h:5, from include/linux/highmem.h:7, from include/linux/pagemap.h:10, from fs/debugfs/file.c:18: In function 'copy_from_user', inlined from 'write_file_bool' at fs/debugfs/file.c:435: arch/x86/include/asm/uaccess_64.h:65: warning: call to 'copy_from_user_overflow' declared with attribute warning: copy_from_user() buffer size is not provably correct presumably due to buf_size being signed causing GCC to fail to see that buf_size can't become negative. Signed-off-by: Stephen Boyd Signed-off-by: Greg Kroah-Hartman diff --git a/fs/debugfs/file.c b/fs/debugfs/file.c index 568304d..90f7657 100644 --- a/fs/debugfs/file.c +++ b/fs/debugfs/file.c @@ -428,7 +428,7 @@ static ssize_t write_file_bool(struct file *file, const char __user *user_buf, size_t count, loff_t *ppos) { char buf[32]; - int buf_size; + size_t buf_size; bool bv; u32 *val = file->private_data; -- cgit v0.10.2 From f550806a7fbca06b487238442546aceb7ecbb0c9 Mon Sep 17 00:00:00 2001 From: John Stultz Date: Tue, 15 Feb 2011 22:34:49 -0800 Subject: alpha: convert to clocksource_register_hz Converts alpha to use clocksource_register_hz. Signed-off-by: John Stultz CC: Richard Henderson CC: Ivan Kokshaysky CC: Thomas Gleixner Signed-off-by: Matt Turner diff --git a/arch/alpha/kernel/time.c b/arch/alpha/kernel/time.c index 918e8e0..818e74e 100644 --- a/arch/alpha/kernel/time.c +++ b/arch/alpha/kernel/time.c @@ -375,8 +375,7 @@ static struct clocksource clocksource_rpcc = { static inline void register_rpcc_clocksource(long cycle_freq) { - clocksource_calc_mult_shift(&clocksource_rpcc, cycle_freq, 4); - clocksource_register(&clocksource_rpcc); + clocksource_register_hz(&clocksource_rpcc, cycle_freq); } #else /* !CONFIG_SMP */ static inline void register_rpcc_clocksource(long cycle_freq) -- cgit v0.10.2 From 90b57f35164aa715dcc7d939a88780a23231f84e Mon Sep 17 00:00:00 2001 From: Michael Cree Date: Wed, 4 May 2011 08:14:50 +0000 Subject: alpha: Wire up syscalls new to 2.6.39 Wire up the syscalls: name_to_handle_at open_by_handle_at clock_adjtime syncfs and adjust some whitespace in the neighbourhood to align commments. Signed-off-by: Michael Cree Signed-off-by: Matt Turner diff --git a/arch/alpha/include/asm/unistd.h b/arch/alpha/include/asm/unistd.h index 058937b..b183416 100644 --- a/arch/alpha/include/asm/unistd.h +++ b/arch/alpha/include/asm/unistd.h @@ -452,10 +452,14 @@ #define __NR_fanotify_init 494 #define __NR_fanotify_mark 495 #define __NR_prlimit64 496 +#define __NR_name_to_handle_at 497 +#define __NR_open_by_handle_at 498 +#define __NR_clock_adjtime 499 +#define __NR_syncfs 500 #ifdef __KERNEL__ -#define NR_SYSCALLS 497 +#define NR_SYSCALLS 501 #define __ARCH_WANT_IPC_PARSE_VERSION #define __ARCH_WANT_OLD_READDIR diff --git a/arch/alpha/kernel/systbls.S b/arch/alpha/kernel/systbls.S index a6a1de9..15f999d 100644 --- a/arch/alpha/kernel/systbls.S +++ b/arch/alpha/kernel/systbls.S @@ -498,23 +498,27 @@ sys_call_table: .quad sys_ni_syscall /* sys_timerfd */ .quad sys_eventfd .quad sys_recvmmsg - .quad sys_fallocate /* 480 */ + .quad sys_fallocate /* 480 */ .quad sys_timerfd_create .quad sys_timerfd_settime .quad sys_timerfd_gettime .quad sys_signalfd4 - .quad sys_eventfd2 /* 485 */ + .quad sys_eventfd2 /* 485 */ .quad sys_epoll_create1 .quad sys_dup3 .quad sys_pipe2 .quad sys_inotify_init1 - .quad sys_preadv /* 490 */ + .quad sys_preadv /* 490 */ .quad sys_pwritev .quad sys_rt_tgsigqueueinfo .quad sys_perf_event_open .quad sys_fanotify_init - .quad sys_fanotify_mark /* 495 */ + .quad sys_fanotify_mark /* 495 */ .quad sys_prlimit64 + .quad sys_name_to_handle_at + .quad sys_open_by_handle_at + .quad sys_clock_adjtime + .quad sys_syncfs /* 500 */ .size sys_call_table, . - sys_call_table .type sys_call_table, @object -- cgit v0.10.2 From 47a8467cc0907e2fd3e6f4d02465dfb64494133e Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Sat, 14 May 2011 02:35:25 +0100 Subject: sfc: Fix return value from efx_ethtool_set_rx_ntuple() ethtool_ops::set_rx_ntuple is supposed to return 0 on success, but it currently returns the filter ID when it inserts or modifies a filter. Signed-off-by: Ben Hutchings diff --git a/drivers/net/sfc/ethtool.c b/drivers/net/sfc/ethtool.c index 8c5e005..348437a 100644 --- a/drivers/net/sfc/ethtool.c +++ b/drivers/net/sfc/ethtool.c @@ -955,8 +955,9 @@ static int efx_ethtool_set_rx_ntuple(struct net_device *net_dev, if (ntuple->fs.action == ETHTOOL_RXNTUPLE_ACTION_CLEAR) return efx_filter_remove_filter(efx, &filter); - else - return efx_filter_insert_filter(efx, &filter, true); + + rc = efx_filter_insert_filter(efx, &filter, true); + return rc < 0 ? rc : 0; } static int efx_ethtool_get_rxfh_indir(struct net_device *net_dev, -- cgit v0.10.2 From 89c0b8e2520e12d69dafc663dfbd39f8180438ea Mon Sep 17 00:00:00 2001 From: Russell King Date: Sun, 8 May 2011 18:47:58 +0100 Subject: clocksource: add common i8253 PIT clocksource This is based upon both arch/arm/mach-footbridge/isa-timer.c and arch/x86/kernel/i8253.c. Acked-by: John Stultz Acked-by: Thomas Gleixner Cc: "H. Peter Anvin" Cc: Ingo Molnar Cc: Ralf Baechle Signed-off-by: Russell King diff --git a/drivers/Kconfig b/drivers/Kconfig index 177c7d1..557a469 100644 --- a/drivers/Kconfig +++ b/drivers/Kconfig @@ -119,4 +119,7 @@ source "drivers/platform/Kconfig" source "drivers/clk/Kconfig" source "drivers/hwspinlock/Kconfig" + +source "drivers/clocksource/Kconfig" + endmenu diff --git a/drivers/clocksource/Kconfig b/drivers/clocksource/Kconfig new file mode 100644 index 0000000..110aeeb --- /dev/null +++ b/drivers/clocksource/Kconfig @@ -0,0 +1,2 @@ +config CLKSRC_I8253 + bool diff --git a/drivers/clocksource/Makefile b/drivers/clocksource/Makefile index be61ece..cfb6383 100644 --- a/drivers/clocksource/Makefile +++ b/drivers/clocksource/Makefile @@ -6,3 +6,4 @@ obj-$(CONFIG_CS5535_CLOCK_EVENT_SRC) += cs5535-clockevt.o obj-$(CONFIG_SH_TIMER_CMT) += sh_cmt.o obj-$(CONFIG_SH_TIMER_MTU2) += sh_mtu2.o obj-$(CONFIG_SH_TIMER_TMU) += sh_tmu.o +obj-$(CONFIG_CLKSRC_I8253) += i8253.o diff --git a/drivers/clocksource/i8253.c b/drivers/clocksource/i8253.c new file mode 100644 index 0000000..225c176 --- /dev/null +++ b/drivers/clocksource/i8253.c @@ -0,0 +1,88 @@ +/* + * i8253 PIT clocksource + */ +#include +#include +#include +#include +#include + +#include + +/* + * Since the PIT overflows every tick, its not very useful + * to just read by itself. So use jiffies to emulate a free + * running counter: + */ +static cycle_t i8253_read(struct clocksource *cs) +{ + static int old_count; + static u32 old_jifs; + unsigned long flags; + int count; + u32 jifs; + + raw_spin_lock_irqsave(&i8253_lock, flags); + /* + * Although our caller may have the read side of xtime_lock, + * this is now a seqlock, and we are cheating in this routine + * by having side effects on state that we cannot undo if + * there is a collision on the seqlock and our caller has to + * retry. (Namely, old_jifs and old_count.) So we must treat + * jiffies as volatile despite the lock. We read jiffies + * before latching the timer count to guarantee that although + * the jiffies value might be older than the count (that is, + * the counter may underflow between the last point where + * jiffies was incremented and the point where we latch the + * count), it cannot be newer. + */ + jifs = jiffies; + outb_pit(0x00, PIT_MODE); /* latch the count ASAP */ + count = inb_pit(PIT_CH0); /* read the latched count */ + count |= inb_pit(PIT_CH0) << 8; + + /* VIA686a test code... reset the latch if count > max + 1 */ + if (count > LATCH) { + outb_pit(0x34, PIT_MODE); + outb_pit(PIT_LATCH & 0xff, PIT_CH0); + outb_pit(PIT_LATCH >> 8, PIT_CH0); + count = PIT_LATCH - 1; + } + + /* + * It's possible for count to appear to go the wrong way for a + * couple of reasons: + * + * 1. The timer counter underflows, but we haven't handled the + * resulting interrupt and incremented jiffies yet. + * 2. Hardware problem with the timer, not giving us continuous time, + * the counter does small "jumps" upwards on some Pentium systems, + * (see c't 95/10 page 335 for Neptun bug.) + * + * Previous attempts to handle these cases intelligently were + * buggy, so we just do the simple thing now. + */ + if (count > old_count && jifs == old_jifs) + count = old_count; + + old_count = count; + old_jifs = jifs; + + raw_spin_unlock_irqrestore(&i8253_lock, flags); + + count = (PIT_LATCH - 1) - count; + + return (cycle_t)(jifs * PIT_LATCH) + count; +} + +static struct clocksource i8253_cs = { + .name = "pit", + .rating = 110, + .read = i8253_read, + .mask = CLOCKSOURCE_MASK(32), +}; + +int __init clocksource_i8253_init(void) +{ + return clocksource_register_hz(&i8253_cs, PIT_TICK_RATE); +} -- cgit v0.10.2 From 8c414ff3f4dcdde228c6a668385218290d73a265 Mon Sep 17 00:00:00 2001 From: Russell King Date: Sun, 8 May 2011 18:50:20 +0100 Subject: clocksource: convert footbridge to generic i8253 clocksource Convert the footbridge isa-timer code to use generic i8253 clocksource. Acked-by: John Stultz Acked-by: Thomas Gleixner Signed-off-by: Russell King diff --git a/arch/arm/include/asm/i8253.h b/arch/arm/include/asm/i8253.h new file mode 100644 index 0000000..70656b6 --- /dev/null +++ b/arch/arm/include/asm/i8253.h @@ -0,0 +1,15 @@ +#ifndef __ASMARM_I8253_H +#define __ASMARM_I8253_H + +/* i8253A PIT registers */ +#define PIT_MODE 0x43 +#define PIT_CH0 0x40 + +#define PIT_LATCH ((PIT_TICK_RATE + HZ / 2) / HZ) + +extern raw_spinlock_t i8253_lock; + +#define outb_pit outb_p +#define inb_pit inb_p + +#endif diff --git a/arch/arm/mach-footbridge/Kconfig b/arch/arm/mach-footbridge/Kconfig index bdd2579..46adca0 100644 --- a/arch/arm/mach-footbridge/Kconfig +++ b/arch/arm/mach-footbridge/Kconfig @@ -4,6 +4,7 @@ menu "Footbridge Implementations" config ARCH_CATS bool "CATS" + select CLKSRC_I8253 select FOOTBRIDGE_HOST select ISA select ISA_DMA @@ -59,6 +60,7 @@ config ARCH_EBSA285_HOST config ARCH_NETWINDER bool "NetWinder" + select CLKSRC_I8253 select FOOTBRIDGE_HOST select ISA select ISA_DMA diff --git a/arch/arm/mach-footbridge/isa-timer.c b/arch/arm/mach-footbridge/isa-timer.c index 441c6ce..7020f1a 100644 --- a/arch/arm/mach-footbridge/isa-timer.c +++ b/arch/arm/mach-footbridge/isa-timer.c @@ -10,53 +10,16 @@ #include #include #include +#include #include #include - +#include #include #include "common.h" -#define PIT_MODE 0x43 -#define PIT_CH0 0x40 - -#define PIT_LATCH ((PIT_TICK_RATE + HZ / 2) / HZ) - -static cycle_t pit_read(struct clocksource *cs) -{ - unsigned long flags; - static int old_count; - static u32 old_jifs; - int count; - u32 jifs; - - raw_local_irq_save(flags); - - jifs = jiffies; - outb_p(0x00, PIT_MODE); /* latch the count */ - count = inb_p(PIT_CH0); /* read the latched count */ - count |= inb_p(PIT_CH0) << 8; - - if (count > old_count && jifs == old_jifs) - count = old_count; - - old_count = count; - old_jifs = jifs; - - raw_local_irq_restore(flags); - - count = (PIT_LATCH - 1) - count; - - return (cycle_t)(jifs * PIT_LATCH) + count; -} - -static struct clocksource pit_cs = { - .name = "pit", - .rating = 110, - .read = pit_read, - .mask = CLOCKSOURCE_MASK(32), -}; +DEFINE_RAW_SPINLOCK(i8253_lock); static void pit_set_mode(enum clock_event_mode mode, struct clock_event_device *evt) @@ -121,7 +84,7 @@ static void __init isa_timer_init(void) pit_ce.max_delta_ns = clockevent_delta2ns(0x7fff, &pit_ce); pit_ce.min_delta_ns = clockevent_delta2ns(0x000f, &pit_ce); - clocksource_register_hz(&pit_cs, PIT_TICK_RATE); + clocksource_i8253_init(); setup_irq(pit_ce.irq, &pit_timer_irq); clockevents_register_device(&pit_ce); diff --git a/include/linux/clocksource.h b/include/linux/clocksource.h index c37b21a..f13469b 100644 --- a/include/linux/clocksource.h +++ b/include/linux/clocksource.h @@ -341,4 +341,6 @@ static inline void update_vsyscall_tz(void) extern void timekeeping_notify(struct clocksource *clock); +extern int clocksource_i8253_init(void); + #endif /* _LINUX_CLOCKSOURCE_H */ -- cgit v0.10.2 From 82491451dd25a3abe8496ddbd04ddb3f77d285c2 Mon Sep 17 00:00:00 2001 From: Russell King Date: Sun, 8 May 2011 18:55:19 +0100 Subject: clocksource: convert x86 to generic i8253 clocksource Convert x86 i8253 clocksource code to use generic i8253 clocksource. Acked-by: John Stultz Acked-by: Thomas Gleixner Cc: "H. Peter Anvin" Cc: Ingo Molnar Signed-off-by: Russell King diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig index cc6c53a..01115d5 100644 --- a/arch/x86/Kconfig +++ b/arch/x86/Kconfig @@ -8,6 +8,7 @@ config 64BIT config X86_32 def_bool !64BIT + select CLKSRC_I8253 config X86_64 def_bool 64BIT diff --git a/arch/x86/include/asm/i8253.h b/arch/x86/include/asm/i8253.h index fc1f579..65aaa91 100644 --- a/arch/x86/include/asm/i8253.h +++ b/arch/x86/include/asm/i8253.h @@ -6,6 +6,8 @@ #define PIT_CH0 0x40 #define PIT_CH2 0x42 +#define PIT_LATCH LATCH + extern raw_spinlock_t i8253_lock; extern struct clock_event_device *global_clock_event; diff --git a/arch/x86/kernel/i8253.c b/arch/x86/kernel/i8253.c index 2dfd315..b904dfb 100644 --- a/arch/x86/kernel/i8253.c +++ b/arch/x86/kernel/i8253.c @@ -117,81 +117,6 @@ void __init setup_pit_timer(void) } #ifndef CONFIG_X86_64 -/* - * Since the PIT overflows every tick, its not very useful - * to just read by itself. So use jiffies to emulate a free - * running counter: - */ -static cycle_t pit_read(struct clocksource *cs) -{ - static int old_count; - static u32 old_jifs; - unsigned long flags; - int count; - u32 jifs; - - raw_spin_lock_irqsave(&i8253_lock, flags); - /* - * Although our caller may have the read side of xtime_lock, - * this is now a seqlock, and we are cheating in this routine - * by having side effects on state that we cannot undo if - * there is a collision on the seqlock and our caller has to - * retry. (Namely, old_jifs and old_count.) So we must treat - * jiffies as volatile despite the lock. We read jiffies - * before latching the timer count to guarantee that although - * the jiffies value might be older than the count (that is, - * the counter may underflow between the last point where - * jiffies was incremented and the point where we latch the - * count), it cannot be newer. - */ - jifs = jiffies; - outb_pit(0x00, PIT_MODE); /* latch the count ASAP */ - count = inb_pit(PIT_CH0); /* read the latched count */ - count |= inb_pit(PIT_CH0) << 8; - - /* VIA686a test code... reset the latch if count > max + 1 */ - if (count > LATCH) { - outb_pit(0x34, PIT_MODE); - outb_pit(LATCH & 0xff, PIT_CH0); - outb_pit(LATCH >> 8, PIT_CH0); - count = LATCH - 1; - } - - /* - * It's possible for count to appear to go the wrong way for a - * couple of reasons: - * - * 1. The timer counter underflows, but we haven't handled the - * resulting interrupt and incremented jiffies yet. - * 2. Hardware problem with the timer, not giving us continuous time, - * the counter does small "jumps" upwards on some Pentium systems, - * (see c't 95/10 page 335 for Neptun bug.) - * - * Previous attempts to handle these cases intelligently were - * buggy, so we just do the simple thing now. - */ - if (count > old_count && jifs == old_jifs) - count = old_count; - - old_count = count; - old_jifs = jifs; - - raw_spin_unlock_irqrestore(&i8253_lock, flags); - - count = (LATCH - 1) - count; - - return (cycle_t)(jifs * LATCH) + count; -} - -static struct clocksource pit_cs = { - .name = "pit", - .rating = 110, - .read = pit_read, - .mask = CLOCKSOURCE_MASK(32), - .mult = 0, - .shift = 20, -}; - static int __init init_pit_clocksource(void) { /* @@ -205,9 +130,7 @@ static int __init init_pit_clocksource(void) pit_ce.mode != CLOCK_EVT_MODE_PERIODIC) return 0; - pit_cs.mult = clocksource_hz2mult(CLOCK_TICK_RATE, pit_cs.shift); - - return clocksource_register(&pit_cs); + return clocksource_i8253_init(); } arch_initcall(init_pit_clocksource); -- cgit v0.10.2 From 798778b8653f64b7b2162ac70eca10367cff6ce8 Mon Sep 17 00:00:00 2001 From: Russell King Date: Sun, 8 May 2011 19:03:03 +0100 Subject: clocksource: convert mips to generic i8253 clocksource Convert MIPS i8253 clocksource code to use generic i8253 clocksource. Acked-by: John Stultz Acked-by: Thomas Gleixner Cc: Ralf Baechle Signed-off-by: Russell King diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig index 8e256cc..f7f6419 100644 --- a/arch/mips/Kconfig +++ b/arch/mips/Kconfig @@ -2339,6 +2339,7 @@ config MMU config I8253 bool + select CLKSRC_I8253 select MIPS_EXTERNAL_TIMER config ZONE_DMA32 diff --git a/arch/mips/include/asm/i8253.h b/arch/mips/include/asm/i8253.h index 48bb823..9ad0113 100644 --- a/arch/mips/include/asm/i8253.h +++ b/arch/mips/include/asm/i8253.h @@ -12,8 +12,13 @@ #define PIT_CH0 0x40 #define PIT_CH2 0x42 +#define PIT_LATCH LATCH + extern raw_spinlock_t i8253_lock; extern void setup_pit_timer(void); +#define inb_pit inb_p +#define outb_pit outb_p + #endif /* __ASM_I8253_H */ diff --git a/arch/mips/kernel/i8253.c b/arch/mips/kernel/i8253.c index 2392a7a2..391221b 100644 --- a/arch/mips/kernel/i8253.c +++ b/arch/mips/kernel/i8253.c @@ -125,87 +125,11 @@ void __init setup_pit_timer(void) setup_irq(0, &irq0); } -/* - * Since the PIT overflows every tick, its not very useful - * to just read by itself. So use jiffies to emulate a free - * running counter: - */ -static cycle_t pit_read(struct clocksource *cs) -{ - unsigned long flags; - int count; - u32 jifs; - static int old_count; - static u32 old_jifs; - - raw_spin_lock_irqsave(&i8253_lock, flags); - /* - * Although our caller may have the read side of xtime_lock, - * this is now a seqlock, and we are cheating in this routine - * by having side effects on state that we cannot undo if - * there is a collision on the seqlock and our caller has to - * retry. (Namely, old_jifs and old_count.) So we must treat - * jiffies as volatile despite the lock. We read jiffies - * before latching the timer count to guarantee that although - * the jiffies value might be older than the count (that is, - * the counter may underflow between the last point where - * jiffies was incremented and the point where we latch the - * count), it cannot be newer. - */ - jifs = jiffies; - outb_p(0x00, PIT_MODE); /* latch the count ASAP */ - count = inb_p(PIT_CH0); /* read the latched count */ - count |= inb_p(PIT_CH0) << 8; - - /* VIA686a test code... reset the latch if count > max + 1 */ - if (count > LATCH) { - outb_p(0x34, PIT_MODE); - outb_p(LATCH & 0xff, PIT_CH0); - outb(LATCH >> 8, PIT_CH0); - count = LATCH - 1; - } - - /* - * It's possible for count to appear to go the wrong way for a - * couple of reasons: - * - * 1. The timer counter underflows, but we haven't handled the - * resulting interrupt and incremented jiffies yet. - * 2. Hardware problem with the timer, not giving us continuous time, - * the counter does small "jumps" upwards on some Pentium systems, - * (see c't 95/10 page 335 for Neptun bug.) - * - * Previous attempts to handle these cases intelligently were - * buggy, so we just do the simple thing now. - */ - if (count > old_count && jifs == old_jifs) { - count = old_count; - } - old_count = count; - old_jifs = jifs; - - raw_spin_unlock_irqrestore(&i8253_lock, flags); - - count = (LATCH - 1) - count; - - return (cycle_t)(jifs * LATCH) + count; -} - -static struct clocksource clocksource_pit = { - .name = "pit", - .rating = 110, - .read = pit_read, - .mask = CLOCKSOURCE_MASK(32), - .mult = 0, - .shift = 20, -}; - static int __init init_pit_clocksource(void) { if (num_possible_cpus() > 1) /* PIT does not scale! */ return 0; - clocksource_pit.mult = clocksource_hz2mult(CLOCK_TICK_RATE, 20); - return clocksource_register(&clocksource_pit); + return clocksource_i8253_init(); } arch_initcall(init_pit_clocksource); -- cgit v0.10.2 From 712f3147aee0fbbbbed2da20b21b272c5505125e Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Fri, 13 May 2011 16:16:41 -0700 Subject: fbmem: fix remove_conflicting_framebuffers races MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When a register_framebuffer() call results in us removing old conflicting framebuffers, the new registration_lock doesn't protect that situation. And we can't just add the same locking to the function, because these functions call each other: register_framebuffer() calls remove_conflicting_framebuffers, which in turn calls unregister_framebuffer for any conflicting entry. In order to fix it, this just creates wrapper functions around all three functions and makes the versions that actually do the work be called "do_xxx()", leaving just the wrapper that gets the lock and calls the worker function. So the rule becomes simply that "do_xxxx()" has to be called with the lock held, and now do_register_framebuffer() can just call do_remove_conflicting_framebuffers(), and that in turn can call _do_unregister_framebuffer(), and there is no deadlock, and we can hold the registration lock over the whole sequence, fixing the races. It also makes error cases simpler, and fixes one situation where we would return from unregister_framebuffer() without releasing the lock, pointed out by Bruno Prémont. Tested-by: Bruno Prémont Tested-by: Anca Emanuel Signed-off-by: Linus Torvalds diff --git a/drivers/video/fbmem.c b/drivers/video/fbmem.c index ea16e65..46ee5e5 100644 --- a/drivers/video/fbmem.c +++ b/drivers/video/fbmem.c @@ -1537,8 +1537,10 @@ static bool fb_do_apertures_overlap(struct apertures_struct *gena, return false; } +static int do_unregister_framebuffer(struct fb_info *fb_info); + #define VGA_FB_PHYS 0xA0000 -void remove_conflicting_framebuffers(struct apertures_struct *a, +static void do_remove_conflicting_framebuffers(struct apertures_struct *a, const char *name, bool primary) { int i; @@ -1560,24 +1562,12 @@ void remove_conflicting_framebuffers(struct apertures_struct *a, printk(KERN_INFO "fb: conflicting fb hw usage " "%s vs %s - removing generic driver\n", name, registered_fb[i]->fix.id); - unregister_framebuffer(registered_fb[i]); + do_unregister_framebuffer(registered_fb[i]); } } } -EXPORT_SYMBOL(remove_conflicting_framebuffers); - -/** - * register_framebuffer - registers a frame buffer device - * @fb_info: frame buffer info structure - * - * Registers a frame buffer device @fb_info. - * - * Returns negative errno on error, or zero for success. - * - */ -int -register_framebuffer(struct fb_info *fb_info) +static int do_register_framebuffer(struct fb_info *fb_info) { int i; struct fb_event event; @@ -1589,10 +1579,9 @@ register_framebuffer(struct fb_info *fb_info) if (fb_check_foreignness(fb_info)) return -ENOSYS; - remove_conflicting_framebuffers(fb_info->apertures, fb_info->fix.id, + do_remove_conflicting_framebuffers(fb_info->apertures, fb_info->fix.id, fb_is_primary_device(fb_info)); - mutex_lock(®istration_lock); num_registered_fb++; for (i = 0 ; i < FB_MAX; i++) if (!registered_fb[i]) @@ -1635,7 +1624,6 @@ register_framebuffer(struct fb_info *fb_info) fb_var_to_videomode(&mode, &fb_info->var); fb_add_videomode(&mode, &fb_info->modelist); registered_fb[i] = fb_info; - mutex_unlock(®istration_lock); event.info = fb_info; if (!lock_fb_info(fb_info)) @@ -1645,37 +1633,14 @@ register_framebuffer(struct fb_info *fb_info) return 0; } - -/** - * unregister_framebuffer - releases a frame buffer device - * @fb_info: frame buffer info structure - * - * Unregisters a frame buffer device @fb_info. - * - * Returns negative errno on error, or zero for success. - * - * This function will also notify the framebuffer console - * to release the driver. - * - * This is meant to be called within a driver's module_exit() - * function. If this is called outside module_exit(), ensure - * that the driver implements fb_open() and fb_release() to - * check that no processes are using the device. - */ - -int -unregister_framebuffer(struct fb_info *fb_info) +static int do_unregister_framebuffer(struct fb_info *fb_info) { struct fb_event event; int i, ret = 0; - mutex_lock(®istration_lock); i = fb_info->node; - if (!registered_fb[i]) { - ret = -EINVAL; - goto done; - } - + if (!registered_fb[i]) + return -EINVAL; if (!lock_fb_info(fb_info)) return -ENODEV; @@ -1683,10 +1648,8 @@ unregister_framebuffer(struct fb_info *fb_info) ret = fb_notifier_call_chain(FB_EVENT_FB_UNBIND, &event); unlock_fb_info(fb_info); - if (ret) { - ret = -EINVAL; - goto done; - } + if (ret) + return -EINVAL; if (fb_info->pixmap.addr && (fb_info->pixmap.flags & FB_PIXMAP_DEFAULT)) @@ -1701,8 +1664,64 @@ unregister_framebuffer(struct fb_info *fb_info) /* this may free fb info */ put_fb_info(fb_info); -done: + return 0; +} + +void remove_conflicting_framebuffers(struct apertures_struct *a, + const char *name, bool primary) +{ + mutex_lock(®istration_lock); + do_remove_conflicting_framebuffers(a, name, primary); mutex_unlock(®istration_lock); +} +EXPORT_SYMBOL(remove_conflicting_framebuffers); + +/** + * register_framebuffer - registers a frame buffer device + * @fb_info: frame buffer info structure + * + * Registers a frame buffer device @fb_info. + * + * Returns negative errno on error, or zero for success. + * + */ +int +register_framebuffer(struct fb_info *fb_info) +{ + int ret; + + mutex_lock(®istration_lock); + ret = do_register_framebuffer(fb_info); + mutex_unlock(®istration_lock); + + return ret; +} + +/** + * unregister_framebuffer - releases a frame buffer device + * @fb_info: frame buffer info structure + * + * Unregisters a frame buffer device @fb_info. + * + * Returns negative errno on error, or zero for success. + * + * This function will also notify the framebuffer console + * to release the driver. + * + * This is meant to be called within a driver's module_exit() + * function. If this is called outside module_exit(), ensure + * that the driver implements fb_open() and fb_release() to + * check that no processes are using the device. + */ +int +unregister_framebuffer(struct fb_info *fb_info) +{ + int ret; + + mutex_lock(®istration_lock); + ret = do_unregister_framebuffer(fb_info); + mutex_unlock(®istration_lock); + return ret; } -- cgit v0.10.2 From c590cece75728a85ea06801df3ebad2d7ad8612c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bruno=20Pr=C3=A9mont?= Date: Sat, 14 May 2011 12:24:15 +0200 Subject: Further fbcon sanity checking MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This moves the if (num_registered_fb == FB_MAX) return -ENXIO; check _AFTER_ the call to do_remove_conflicting_framebuffers() as this would (now in a safe way) allow a native driver to replace the conflicting one even if all slots in registered_fb[] are taken. This also prevents unregistering a framebuffer that is no longer registered (vga16f will unregister at module unload time even if the frame buffer had been unregistered earlier due to being found conflicting). Signed-off-by: Bruno Prémont Signed-off-by: Linus Torvalds diff --git a/drivers/video/fbmem.c b/drivers/video/fbmem.c index 46ee5e5..5aac00e 100644 --- a/drivers/video/fbmem.c +++ b/drivers/video/fbmem.c @@ -1573,15 +1573,15 @@ static int do_register_framebuffer(struct fb_info *fb_info) struct fb_event event; struct fb_videomode mode; - if (num_registered_fb == FB_MAX) - return -ENXIO; - if (fb_check_foreignness(fb_info)) return -ENOSYS; do_remove_conflicting_framebuffers(fb_info->apertures, fb_info->fix.id, fb_is_primary_device(fb_info)); + if (num_registered_fb == FB_MAX) + return -ENXIO; + num_registered_fb++; for (i = 0 ; i < FB_MAX; i++) if (!registered_fb[i]) @@ -1639,7 +1639,7 @@ static int do_unregister_framebuffer(struct fb_info *fb_info) int i, ret = 0; i = fb_info->node; - if (!registered_fb[i]) + if (i < 0 || i >= FB_MAX || registered_fb[i] != fb_info) return -EINVAL; if (!lock_fb_info(fb_info)) -- cgit v0.10.2 From 22fe9446e82f1fe4b59900db4599061384efb0ad Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Sat, 14 May 2011 12:28:04 +0200 Subject: Revert "libata: ahci_start_engine compliant to AHCI spec" This reverts commit 270dac35c26433d06a89150c51e75ca0181ca7e4. The commits causes command timeouts on AC plug/unplug. It isn't yet clear why. As the commit was for a single rather obscure controller, revert the change for now. The problem was reported and bisected by Gu Rui in bug#34692. https://bugzilla.kernel.org/show_bug.cgi?id=34692 Also, reported by Rafael and Michael in the following thread. http://thread.gmane.org/gmane.linux.kernel/1138771 Signed-off-by: Tejun Heo Reported-by: Gu Rui Reported-by: Rafael J. Wysocki Reported-by: Michael Leun Cc: Jian Peng Cc: Jeff Garzik Signed-off-by: Linus Torvalds diff --git a/drivers/ata/libahci.c b/drivers/ata/libahci.c index ff9d832..d38c40f 100644 --- a/drivers/ata/libahci.c +++ b/drivers/ata/libahci.c @@ -561,27 +561,6 @@ void ahci_start_engine(struct ata_port *ap) { void __iomem *port_mmio = ahci_port_base(ap); u32 tmp; - u8 status; - - status = readl(port_mmio + PORT_TFDATA) & 0xFF; - - /* - * At end of section 10.1 of AHCI spec (rev 1.3), it states - * Software shall not set PxCMD.ST to 1 until it is determined - * that a functoinal device is present on the port as determined by - * PxTFD.STS.BSY=0, PxTFD.STS.DRQ=0 and PxSSTS.DET=3h - * - * Even though most AHCI host controllers work without this check, - * specific controller will fail under this condition - */ - if (status & (ATA_BUSY | ATA_DRQ)) - return; - else { - ahci_scr_read(&ap->link, SCR_STATUS, &tmp); - - if ((tmp & 0xf) != 0x3) - return; - } /* start DMA */ tmp = readl(port_mmio + PORT_CMD); -- cgit v0.10.2 From 5f6f12ccf3aa42cfc0c5bde9228df0c843dd63f7 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Mon, 9 May 2011 16:04:11 +0200 Subject: libata: fix oops when LPM is used with PMP ae01b2493c (libata: Implement ATA_FLAG_NO_DIPM and apply it to mcp65) added ATA_FLAG_NO_DIPM and made ata_eh_set_lpm() check the flag. However, @ap is NULL if @link points to a PMP link and thus the unconditional @ap->flags dereference leads to the following oops. BUG: unable to handle kernel NULL pointer dereference at 0000000000000018 IP: [] ata_eh_recover+0x9a1/0x1510 ... Pid: 295, comm: scsi_eh_4 Tainted: P 2.6.38.5-core2 #1 System76, Inc. Serval Professional/Serval Professional RIP: 0010:[] [] ata_eh_recover+0x9a1/0x1510 RSP: 0018:ffff880132defbf0 EFLAGS: 00010246 RAX: 0000000000000000 RBX: ffff880132f40000 RCX: 0000000000000000 RDX: ffff88013377c000 RSI: ffff880132f40000 RDI: 0000000000000000 RBP: ffff880132defce0 R08: ffff88013377dc58 R09: ffff880132defd98 R10: 0000000000000000 R11: 00000000ffffffff R12: 0000000000000000 R13: 0000000000000000 R14: ffff88013377c000 R15: 0000000000000000 FS: 0000000000000000(0000) GS:ffff8800bf700000(0000) knlGS:0000000000000000 CS: 0010 DS: 0000 ES: 0000 CR0: 000000008005003b CR2: 0000000000000018 CR3: 0000000001a03000 CR4: 00000000000406e0 DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000 DR3: 0000000000000000 DR6: 00000000ffff0ff0 DR7: 0000000000000400 Process scsi_eh_4 (pid: 295, threadinfo ffff880132dee000, task ffff880133b416c0) Stack: 0000000000000000 ffff880132defcc0 0000000000000000 ffff880132f42738 ffffffff813ee8f0 ffffffff813eefe0 ffff880132defd98 ffff88013377f190 ffffffffa00b3e30 ffffffff813ef030 0000000032defc60 ffff880100000000 Call Trace: [] sata_pmp_error_handler+0x607/0xc30 [] ahci_error_handler+0x1f/0x70 [libahci] [] ata_scsi_error+0x5be/0x900 [] scsi_error_handler+0x124/0x650 [] kthread+0x96/0xa0 [] kernel_thread_helper+0x4/0x10 Code: 8b 95 70 ff ff ff b8 00 00 00 00 48 3b 9a 10 2e 00 00 48 0f 44 c2 48 89 85 70 ff ff ff 48 8b 8d 70 ff ff ff f6 83 69 02 00 00 01 <48> 8b 41 18 0f 85 48 01 00 00 48 85 c9 74 12 48 8b 51 08 48 83 RIP [] ata_eh_recover+0x9a1/0x1510 RSP CR2: 0000000000000018 Fix it by testing @link->ap->flags instead. stable: ATA_FLAG_NO_DIPM was added during 2.6.39 cycle but was backported to 2.6.37 and 38. This is a fix for that and thus also applicable to 2.6.37 and 38. Signed-off-by: Tejun Heo Reported-by: "Nathan A. Mourey II" LKML-Reference: <1304555277.2059.2.camel@localhost.localdomain> Cc: Connor H Cc: stable@kernel.org Signed-off-by: Jeff Garzik diff --git a/drivers/ata/libata-eh.c b/drivers/ata/libata-eh.c index f26f2fe..dad9fd6 100644 --- a/drivers/ata/libata-eh.c +++ b/drivers/ata/libata-eh.c @@ -3316,7 +3316,7 @@ static int ata_eh_set_lpm(struct ata_link *link, enum ata_lpm_policy policy, struct ata_eh_context *ehc = &link->eh_context; struct ata_device *dev, *link_dev = NULL, *lpm_dev = NULL; enum ata_lpm_policy old_policy = link->lpm_policy; - bool no_dipm = ap->flags & ATA_FLAG_NO_DIPM; + bool no_dipm = link->ap->flags & ATA_FLAG_NO_DIPM; unsigned int hints = ATA_LPM_EMPTY | ATA_LPM_HIPM; unsigned int err_mask; int rc; -- cgit v0.10.2 From 9281b16caac1276817b77033c5b8a1f5ca30102c Mon Sep 17 00:00:00 2001 From: James Bottomley Date: Sun, 24 Apr 2011 14:30:14 -0500 Subject: pata_cm64x: fix boot crash on parisc The old IDE cmd64x checks the status of the CNTRL register to see if the ports are enabled before probing them. pata_cmd64x doesn't do this, which causes a HPMC on parisc when it tries to poke at the secondary port because apparently the BAR isn't wired up (and a non-responding piece of memory causes a HPMC). Fix this by porting the CNTRL register port detection logic from IDE cmd64x. In addition, following converns from Alan Cox, add a check to see if a mobility electronics bridge is the immediate parent and forgo the check if it is (prevents problems on hotplug controllers). Signed-off-by: James Bottomley Signed-off-by: Jeff Garzik diff --git a/drivers/ata/pata_cmd64x.c b/drivers/ata/pata_cmd64x.c index 905ff76..7bafc16 100644 --- a/drivers/ata/pata_cmd64x.c +++ b/drivers/ata/pata_cmd64x.c @@ -41,6 +41,9 @@ enum { CFR = 0x50, CFR_INTR_CH0 = 0x04, + CNTRL = 0x51, + CNTRL_CH0 = 0x04, + CNTRL_CH1 = 0x08, CMDTIM = 0x52, ARTTIM0 = 0x53, DRWTIM0 = 0x54, @@ -328,9 +331,19 @@ static int cmd64x_init_one(struct pci_dev *pdev, const struct pci_device_id *id) .port_ops = &cmd648_port_ops } }; - const struct ata_port_info *ppi[] = { &cmd_info[id->driver_data], NULL }; - u8 mrdmode; + const struct ata_port_info *ppi[] = { + &cmd_info[id->driver_data], + &cmd_info[id->driver_data], + NULL + }; + u8 mrdmode, reg; int rc; + struct pci_dev *bridge = pdev->bus->self; + /* mobility split bridges don't report enabled ports correctly */ + int port_ok = !(bridge && bridge->vendor == + PCI_VENDOR_ID_MOBILITY_ELECTRONICS); + /* all (with exceptions below) apart from 643 have CNTRL_CH0 bit */ + int cntrl_ch0_ok = (id->driver_data != 0); rc = pcim_enable_device(pdev); if (rc) @@ -341,11 +354,18 @@ static int cmd64x_init_one(struct pci_dev *pdev, const struct pci_device_id *id) if (pdev->device == PCI_DEVICE_ID_CMD_646) { /* Does UDMA work ? */ - if (pdev->revision > 4) + if (pdev->revision > 4) { ppi[0] = &cmd_info[2]; + ppi[1] = &cmd_info[2]; + } /* Early rev with other problems ? */ - else if (pdev->revision == 1) + else if (pdev->revision == 1) { ppi[0] = &cmd_info[3]; + ppi[1] = &cmd_info[3]; + } + /* revs 1,2 have no CNTRL_CH0 */ + if (pdev->revision < 3) + cntrl_ch0_ok = 0; } pci_write_config_byte(pdev, PCI_LATENCY_TIMER, 64); @@ -354,6 +374,20 @@ static int cmd64x_init_one(struct pci_dev *pdev, const struct pci_device_id *id) mrdmode |= 0x02; /* Memory read line enable */ pci_write_config_byte(pdev, MRDMODE, mrdmode); + /* check for enabled ports */ + pci_read_config_byte(pdev, CNTRL, ®); + if (!port_ok) + dev_printk(KERN_NOTICE, &pdev->dev, "Mobility Bridge detected, ignoring CNTRL port enable/disable\n"); + if (port_ok && cntrl_ch0_ok && !(reg & CNTRL_CH0)) { + dev_printk(KERN_NOTICE, &pdev->dev, "Primary port is disabled\n"); + ppi[0] = &ata_dummy_port_info; + + } + if (port_ok && !(reg & CNTRL_CH1)) { + dev_printk(KERN_NOTICE, &pdev->dev, "Secondary port is disabled\n"); + ppi[1] = &ata_dummy_port_info; + } + /* Force PIO 0 here.. */ /* PPC specific fixup copied from old driver */ diff --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h index 8abe8d7..8652a4f 100644 --- a/include/linux/pci_ids.h +++ b/include/linux/pci_ids.h @@ -608,6 +608,8 @@ #define PCI_DEVICE_ID_MATROX_G550 0x2527 #define PCI_DEVICE_ID_MATROX_VIA 0x4536 +#define PCI_VENDOR_ID_MOBILITY_ELECTRONICS 0x14f2 + #define PCI_VENDOR_ID_CT 0x102c #define PCI_DEVICE_ID_CT_69000 0x00c0 #define PCI_DEVICE_ID_CT_65545 0x00d8 -- cgit v0.10.2 From af649a1b56032a84b75825a94204a8f8f0120698 Mon Sep 17 00:00:00 2001 From: James Bottomley Date: Sun, 24 Apr 2011 14:31:33 -0500 Subject: libata-sff: prevent irq descriptions for dummy ports This is a cosmetic change to prevent libata-sff adding irq descriptions to dummy ports, since the information, while largely unused, is erroneous. Signed-off-by: James Bottomley Signed-off-by: Jeff Garzik diff --git a/drivers/ata/libata-sff.c b/drivers/ata/libata-sff.c index f8380ce..b1b926c 100644 --- a/drivers/ata/libata-sff.c +++ b/drivers/ata/libata-sff.c @@ -2447,13 +2447,18 @@ int ata_pci_sff_activate_host(struct ata_host *host, return -ENOMEM; if (!legacy_mode && pdev->irq) { + int i; + rc = devm_request_irq(dev, pdev->irq, irq_handler, IRQF_SHARED, drv_name, host); if (rc) goto out; - ata_port_desc(host->ports[0], "irq %d", pdev->irq); - ata_port_desc(host->ports[1], "irq %d", pdev->irq); + for (i = 0; i < 2; i++) { + if (ata_port_is_dummy(host->ports[i])) + continue; + ata_port_desc(host->ports[i], "irq %d", pdev->irq); + } } else if (legacy_mode) { if (!ata_port_is_dummy(host->ports[0])) { rc = devm_request_irq(dev, ATA_PRIMARY_IRQ(pdev), -- cgit v0.10.2 From 0144261fa677e9490eb112231de30c95af1679d2 Mon Sep 17 00:00:00 2001 From: Igor Plyatov Date: Thu, 12 May 2011 22:15:51 +0400 Subject: pata_at91: SMC settings calculation bugfixes, support for t6z and IORDY * New code correctly calculates SMC registers values, adjusts calculated to admissible ranges, enlarges cycles when required and converts values into SMC's format. * Support for TDF cycles (ATA t6z) and IORDY line added. * Eliminate need in the initial_timing structure. * Code cleanup. Signed-off-by: Igor Plyatov Signed-off-by: Jeff Garzik diff --git a/drivers/ata/pata_at91.c b/drivers/ata/pata_at91.c index a5fdbdc..960c725 100644 --- a/drivers/ata/pata_at91.c +++ b/drivers/ata/pata_at91.c @@ -3,6 +3,7 @@ * with CompactFlash interface in True IDE mode * * Copyright (C) 2009 Matyukevich Sergey + * 2011 Igor Plyatov * * Based on: * * generic platform driver by Paul Mundt: drivers/ata/pata_platform.c @@ -31,38 +32,150 @@ #include #include +#define DRV_NAME "pata_at91" +#define DRV_VERSION "0.3" -#define DRV_NAME "pata_at91" -#define DRV_VERSION "0.2" - -#define CF_IDE_OFFSET 0x00c00000 -#define CF_ALT_IDE_OFFSET 0x00e00000 -#define CF_IDE_RES_SIZE 0x08 -#define NCS_RD_PULSE_LIMIT 0x3f /* maximal value for pulse bitfields */ +#define CF_IDE_OFFSET 0x00c00000 +#define CF_ALT_IDE_OFFSET 0x00e00000 +#define CF_IDE_RES_SIZE 0x08 +#define CS_PULSE_MAXIMUM 319 +#define ER_SMC_CALC 1 +#define ER_SMC_RECALC 2 struct at91_ide_info { unsigned long mode; unsigned int cs; - struct clk *mck; - void __iomem *ide_addr; void __iomem *alt_addr; }; -static const struct ata_timing initial_timing = { - .mode = XFER_PIO_0, - .setup = 70, - .act8b = 290, - .rec8b = 240, - .cyc8b = 600, - .active = 165, - .recover = 150, - .dmack_hold = 0, - .cycle = 600, - .udma = 0 +/** + * struct smc_range - range of valid values for SMC register. + */ +struct smc_range { + int min; + int max; }; +/** + * adjust_smc_value - adjust value for one of SMC registers. + * @value: adjusted value + * @range: array of SMC ranges with valid values + * @size: SMC ranges array size + * + * This returns the difference between input and output value or negative + * in case of invalid input value. + * If negative returned, then output value = maximal possible from ranges. + */ +static int adjust_smc_value(int *value, struct smc_range *range, int size) +{ + int maximum = (range + size - 1)->max; + int remainder; + + do { + if (*value < range->min) { + remainder = range->min - *value; + *value = range->min; /* nearest valid value */ + return remainder; + } else if ((range->min <= *value) && (*value <= range->max)) + return 0; + + range++; + } while (--size); + *value = maximum; + + return -1; /* invalid value */ +} + +/** + * calc_smc_vals - calculate SMC register values + * @dev: ATA device + * @setup: SMC_SETUP register value + * @pulse: SMC_PULSE register value + * @cycle: SMC_CYCLE register value + * + * This returns negative in case of invalid values for SMC registers: + * -ER_SMC_RECALC - recalculation required for SMC values, + * -ER_SMC_CALC - calculation failed (invalid input values). + * + * SMC use special coding scheme, see "Coding and Range of Timing + * Parameters" table from AT91SAM9 datasheets. + * + * SMC_SETUP = 128*setup[5] + setup[4:0] + * SMC_PULSE = 256*pulse[6] + pulse[5:0] + * SMC_CYCLE = 256*cycle[8:7] + cycle[6:0] + */ +static int calc_smc_vals(struct device *dev, + int *setup, int *pulse, int *cycle, int *cs_pulse) +{ + int ret_val; + int err = 0; + struct smc_range range_setup[] = { /* SMC_SETUP valid values */ + {.min = 0, .max = 31}, /* first range */ + {.min = 128, .max = 159} /* second range */ + }; + struct smc_range range_pulse[] = { /* SMC_PULSE valid values */ + {.min = 0, .max = 63}, /* first range */ + {.min = 256, .max = 319} /* second range */ + }; + struct smc_range range_cycle[] = { /* SMC_CYCLE valid values */ + {.min = 0, .max = 127}, /* first range */ + {.min = 256, .max = 383}, /* second range */ + {.min = 512, .max = 639}, /* third range */ + {.min = 768, .max = 895} /* fourth range */ + }; + + ret_val = adjust_smc_value(setup, range_setup, ARRAY_SIZE(range_setup)); + if (ret_val < 0) + dev_warn(dev, "maximal SMC Setup value\n"); + else + *cycle += ret_val; + + ret_val = adjust_smc_value(pulse, range_pulse, ARRAY_SIZE(range_pulse)); + if (ret_val < 0) + dev_warn(dev, "maximal SMC Pulse value\n"); + else + *cycle += ret_val; + + ret_val = adjust_smc_value(cycle, range_cycle, ARRAY_SIZE(range_cycle)); + if (ret_val < 0) + dev_warn(dev, "maximal SMC Cycle value\n"); + + *cs_pulse = *cycle; + if (*cs_pulse > CS_PULSE_MAXIMUM) { + dev_err(dev, "unable to calculate valid SMC settings\n"); + return -ER_SMC_CALC; + } + + ret_val = adjust_smc_value(cs_pulse, range_pulse, + ARRAY_SIZE(range_pulse)); + if (ret_val < 0) { + dev_warn(dev, "maximal SMC CS Pulse value\n"); + } else if (ret_val != 0) { + *cycle = *cs_pulse; + dev_warn(dev, "SMC Cycle extended\n"); + err = -ER_SMC_RECALC; + } + + return err; +} + +/** + * to_smc_format - convert values into SMC format + * @setup: SETUP value of SMC Setup Register + * @pulse: PULSE value of SMC Pulse Register + * @cycle: CYCLE value of SMC Cycle Register + * @cs_pulse: NCS_PULSE value of SMC Pulse Register + */ +static void to_smc_format(int *setup, int *pulse, int *cycle, int *cs_pulse) +{ + *setup = (*setup & 0x1f) | ((*setup & 0x80) >> 2); + *pulse = (*pulse & 0x3f) | ((*pulse & 0x100) >> 2); + *cycle = (*cycle & 0x7f) | ((*cycle & 0x300) >> 1); + *cs_pulse = (*cs_pulse & 0x3f) | ((*cs_pulse & 0x100) >> 2); +} + static unsigned long calc_mck_cycles(unsigned long ns, unsigned long mck_hz) { unsigned long mul; @@ -80,85 +193,77 @@ static unsigned long calc_mck_cycles(unsigned long ns, unsigned long mck_hz) return (ns * mul + 65536) >> 16; /* rounding */ } -static void set_smc_mode(struct at91_ide_info *info) -{ - at91_sys_write(AT91_SMC_MODE(info->cs), info->mode); - return; -} - -static void set_smc_timing(struct device *dev, +/** + * set_smc_timing - SMC timings setup. + * @dev: device + * @info: AT91 IDE info + * @ata: ATA timings + * + * Its assumed that write timings are same as read timings, + * cs_setup = 0 and cs_pulse = cycle. + */ +static void set_smc_timing(struct device *dev, struct ata_device *adev, struct at91_ide_info *info, const struct ata_timing *ata) { - unsigned long read_cycle, write_cycle, active, recover; - unsigned long nrd_setup, nrd_pulse, nrd_recover; - unsigned long nwe_setup, nwe_pulse; - - unsigned long ncs_write_setup, ncs_write_pulse; - unsigned long ncs_read_setup, ncs_read_pulse; - - unsigned long mck_hz; - - read_cycle = ata->cyc8b; - nrd_setup = ata->setup; - nrd_pulse = ata->act8b; - nrd_recover = ata->rec8b; - + int ret = 0; + int use_iordy; + unsigned int t6z; /* data tristate time in ns */ + unsigned int cycle; /* SMC Cycle width in MCK ticks */ + unsigned int setup; /* SMC Setup width in MCK ticks */ + unsigned int pulse; /* CFIOR and CFIOW pulse width in MCK ticks */ + unsigned int cs_setup = 0;/* CS4 or CS5 setup width in MCK ticks */ + unsigned int cs_pulse; /* CS4 or CS5 pulse width in MCK ticks*/ + unsigned int tdf_cycles; /* SMC TDF MCK ticks */ + unsigned long mck_hz; /* MCK frequency in Hz */ + + t6z = (ata->mode < XFER_PIO_5) ? 30 : 20; mck_hz = clk_get_rate(info->mck); - - read_cycle = calc_mck_cycles(read_cycle, mck_hz); - nrd_setup = calc_mck_cycles(nrd_setup, mck_hz); - nrd_pulse = calc_mck_cycles(nrd_pulse, mck_hz); - nrd_recover = calc_mck_cycles(nrd_recover, mck_hz); - - active = nrd_setup + nrd_pulse; - recover = read_cycle - active; - - /* Need at least two cycles recovery */ - if (recover < 2) - read_cycle = active + 2; - - /* (CS0, CS1, DIR, OE) <= (CFCE1, CFCE2, CFRNW, NCSX) timings */ - ncs_read_setup = 1; - ncs_read_pulse = read_cycle - 2; - if (ncs_read_pulse > NCS_RD_PULSE_LIMIT) { - ncs_read_pulse = NCS_RD_PULSE_LIMIT; - dev_warn(dev, "ncs_read_pulse limited to maximal value %lu\n", - ncs_read_pulse); + cycle = calc_mck_cycles(ata->cyc8b, mck_hz); + setup = calc_mck_cycles(ata->setup, mck_hz); + pulse = calc_mck_cycles(ata->act8b, mck_hz); + tdf_cycles = calc_mck_cycles(t6z, mck_hz); + + do { + ret = calc_smc_vals(dev, &setup, &pulse, &cycle, &cs_pulse); + } while (ret == -ER_SMC_RECALC); + + if (ret == -ER_SMC_CALC) + dev_err(dev, "Interface may not operate correctly\n"); + + dev_dbg(dev, "SMC Setup=%u, Pulse=%u, Cycle=%u, CS Pulse=%u\n", + setup, pulse, cycle, cs_pulse); + to_smc_format(&setup, &pulse, &cycle, &cs_pulse); + /* disable or enable waiting for IORDY signal */ + use_iordy = ata_pio_need_iordy(adev); + if (use_iordy) + info->mode |= AT91_SMC_EXNWMODE_READY; + + if (tdf_cycles > 15) { + tdf_cycles = 15; + dev_warn(dev, "maximal SMC TDF Cycles value\n"); } - /* Write timings same as read timings */ - write_cycle = read_cycle; - nwe_setup = nrd_setup; - nwe_pulse = nrd_pulse; - ncs_write_setup = ncs_read_setup; - ncs_write_pulse = ncs_read_pulse; - - dev_dbg(dev, "ATA timings: nrd_setup = %lu nrd_pulse = %lu nrd_cycle = %lu\n", - nrd_setup, nrd_pulse, read_cycle); - dev_dbg(dev, "ATA timings: nwe_setup = %lu nwe_pulse = %lu nwe_cycle = %lu\n", - nwe_setup, nwe_pulse, write_cycle); - dev_dbg(dev, "ATA timings: ncs_read_setup = %lu ncs_read_pulse = %lu\n", - ncs_read_setup, ncs_read_pulse); - dev_dbg(dev, "ATA timings: ncs_write_setup = %lu ncs_write_pulse = %lu\n", - ncs_write_setup, ncs_write_pulse); + dev_dbg(dev, "Use IORDY=%u, TDF Cycles=%u\n", use_iordy, tdf_cycles); + info->mode |= AT91_SMC_TDF_(tdf_cycles); + /* write SMC Setup Register */ at91_sys_write(AT91_SMC_SETUP(info->cs), - AT91_SMC_NWESETUP_(nwe_setup) | - AT91_SMC_NRDSETUP_(nrd_setup) | - AT91_SMC_NCS_WRSETUP_(ncs_write_setup) | - AT91_SMC_NCS_RDSETUP_(ncs_read_setup)); - + AT91_SMC_NWESETUP_(setup) | + AT91_SMC_NRDSETUP_(setup) | + AT91_SMC_NCS_WRSETUP_(cs_setup) | + AT91_SMC_NCS_RDSETUP_(cs_setup)); + /* write SMC Pulse Register */ at91_sys_write(AT91_SMC_PULSE(info->cs), - AT91_SMC_NWEPULSE_(nwe_pulse) | - AT91_SMC_NRDPULSE_(nrd_pulse) | - AT91_SMC_NCS_WRPULSE_(ncs_write_pulse) | - AT91_SMC_NCS_RDPULSE_(ncs_read_pulse)); - + AT91_SMC_NWEPULSE_(pulse) | + AT91_SMC_NRDPULSE_(pulse) | + AT91_SMC_NCS_WRPULSE_(cs_pulse) | + AT91_SMC_NCS_RDPULSE_(cs_pulse)); + /* write SMC Cycle Register */ at91_sys_write(AT91_SMC_CYCLE(info->cs), - AT91_SMC_NWECYCLE_(write_cycle) | - AT91_SMC_NRDCYCLE_(read_cycle)); - - return; + AT91_SMC_NWECYCLE_(cycle) | + AT91_SMC_NRDCYCLE_(cycle)); + /* write SMC Mode Register*/ + at91_sys_write(AT91_SMC_MODE(info->cs), info->mode); } static void pata_at91_set_piomode(struct ata_port *ap, struct ata_device *adev) @@ -172,15 +277,9 @@ static void pata_at91_set_piomode(struct ata_port *ap, struct ata_device *adev) if (ret) { dev_warn(ap->dev, "Failed to compute ATA timing %d, " "set PIO_0 timing\n", ret); - set_smc_timing(ap->dev, info, &initial_timing); - } else { - set_smc_timing(ap->dev, info, &timing); + timing = *ata_timing_find_mode(XFER_PIO_0); } - - /* Setup SMC mode */ - set_smc_mode(info); - - return; + set_smc_timing(ap->dev, adev, info, &timing); } static unsigned int pata_at91_data_xfer_noirq(struct ata_device *dev, @@ -346,7 +445,7 @@ static int __devexit pata_at91_remove(struct platform_device *pdev) static struct platform_driver pata_at91_driver = { .probe = pata_at91_probe, .remove = __devexit_p(pata_at91_remove), - .driver = { + .driver = { .name = DRV_NAME, .owner = THIS_MODULE, }, -- cgit v0.10.2 From 05bf86b4ccfd0f197da61c67bd372111d15a6620 Mon Sep 17 00:00:00 2001 From: Hugh Dickins Date: Sat, 14 May 2011 12:06:42 -0700 Subject: tmpfs: fix race between swapoff and writepage Shame on me! Commit b1dea800ac39 "tmpfs: fix race between umount and writepage" fixed the advertized race, but introduced another: as even its comment makes clear, we cannot safely rely on a peek at list_empty() while holding no lock - until info->swapped is set, shmem_unuse_inode() may delete any formerly-swapped inode from the shmem_swaplist, which in this case would leave a swap area impossible to swapoff. Although I don't relish taking the mutex every time, I don't care much for the alternatives either; and at least the peek at list_empty() in shmem_evict_inode() (a hotter path since most inodes would never have been swapped) remains safe, because we already truncated the whole file. Signed-off-by: Hugh Dickins Cc: stable@kernel.org Signed-off-by: Linus Torvalds diff --git a/mm/shmem.c b/mm/shmem.c index 9e755c1..dfc7069 100644 --- a/mm/shmem.c +++ b/mm/shmem.c @@ -1037,7 +1037,6 @@ static int shmem_writepage(struct page *page, struct writeback_control *wbc) struct address_space *mapping; unsigned long index; struct inode *inode; - bool unlock_mutex = false; BUG_ON(!PageLocked(page)); mapping = page->mapping; @@ -1072,15 +1071,14 @@ static int shmem_writepage(struct page *page, struct writeback_control *wbc) * we've taken the spinlock, because shmem_unuse_inode() will * prune a !swapped inode from the swaplist under both locks. */ - if (swap.val && list_empty(&info->swaplist)) { + if (swap.val) { mutex_lock(&shmem_swaplist_mutex); - /* move instead of add in case we're racing */ - list_move_tail(&info->swaplist, &shmem_swaplist); - unlock_mutex = true; + if (list_empty(&info->swaplist)) + list_add_tail(&info->swaplist, &shmem_swaplist); } spin_lock(&info->lock); - if (unlock_mutex) + if (swap.val) mutex_unlock(&shmem_swaplist_mutex); if (index >= info->next_index) { -- cgit v0.10.2 From f5de93914983bf04b92a786d1d205286fc53b49b Mon Sep 17 00:00:00 2001 From: Daniel J Blueman Date: Tue, 3 May 2011 16:44:13 +0000 Subject: Prevent oopsing in posix_acl_valid() If posix_acl_from_xattr() returns an error code, a negative address is dereferenced causing an oops; fix by checking for error code first. Signed-off-by: Daniel J Blueman Reviewed-by: Josef Bacik Signed-off-by: Chris Mason diff --git a/fs/btrfs/acl.c b/fs/btrfs/acl.c index a892bc2..827be9a 100644 --- a/fs/btrfs/acl.c +++ b/fs/btrfs/acl.c @@ -178,12 +178,13 @@ static int btrfs_xattr_acl_set(struct dentry *dentry, const char *name, if (value) { acl = posix_acl_from_xattr(value, size); + if (IS_ERR(acl)) + return PTR_ERR(acl); + if (acl) { ret = posix_acl_valid(acl); if (ret) goto out; - } else if (IS_ERR(acl)) { - return PTR_ERR(acl); } } -- cgit v0.10.2 From 1aba86d67f340a8001d67183ec32e8a62e3ec658 Mon Sep 17 00:00:00 2001 From: liubo Date: Fri, 8 Apr 2011 08:44:37 +0000 Subject: Btrfs: fix easily get into ENOSPC in mixed case When a btrfs disk is created by mixed data & metadata option, it will have no pure data or pure metadata space info. In btrfs's for-linus branch, commit 78b1ea13838039cd88afdd62519b40b344d6c920 (Btrfs: fix OOPS of empty filesystem after balance) initializes space infos at the very beginning. The problem is this initialization does not take the mixed case into account, which will cause btrfs will easily get into ENOSPC in mixed case. Signed-off-by: Liu Bo Signed-off-by: Chris Mason diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c index cd52f7f..9ee6bd5 100644 --- a/fs/btrfs/extent-tree.c +++ b/fs/btrfs/extent-tree.c @@ -8856,23 +8856,38 @@ out: int btrfs_init_space_info(struct btrfs_fs_info *fs_info) { struct btrfs_space_info *space_info; + struct btrfs_super_block *disk_super; + u64 features; + u64 flags; + int mixed = 0; int ret; - ret = update_space_info(fs_info, BTRFS_BLOCK_GROUP_SYSTEM, 0, 0, - &space_info); - if (ret) - return ret; + disk_super = &fs_info->super_copy; + if (!btrfs_super_root(disk_super)) + return 1; - ret = update_space_info(fs_info, BTRFS_BLOCK_GROUP_METADATA, 0, 0, - &space_info); - if (ret) - return ret; + features = btrfs_super_incompat_flags(disk_super); + if (features & BTRFS_FEATURE_INCOMPAT_MIXED_GROUPS) + mixed = 1; - ret = update_space_info(fs_info, BTRFS_BLOCK_GROUP_DATA, 0, 0, - &space_info); + flags = BTRFS_BLOCK_GROUP_SYSTEM; + ret = update_space_info(fs_info, flags, 0, 0, &space_info); if (ret) - return ret; + goto out; + if (mixed) { + flags = BTRFS_BLOCK_GROUP_METADATA | BTRFS_BLOCK_GROUP_DATA; + ret = update_space_info(fs_info, flags, 0, 0, &space_info); + } else { + flags = BTRFS_BLOCK_GROUP_METADATA; + ret = update_space_info(fs_info, flags, 0, 0, &space_info); + if (ret) + goto out; + + flags = BTRFS_BLOCK_GROUP_DATA; + ret = update_space_info(fs_info, flags, 0, 0, &space_info); + } +out: return ret; } -- cgit v0.10.2 From e1e8fb6a1ff3f9487e03a4cbf85b81d1316068ce Mon Sep 17 00:00:00 2001 From: Li Zefan Date: Fri, 15 Apr 2011 03:02:49 +0000 Subject: fs: remove FS_COW_FL FS_COW_FL and FS_NOCOW_FL were newly introduced to control per file COW in btrfs, but FS_NOCOW_FL is sufficient. The fact is we don't have corresponding BTRFS_INODE_COW flag. COW is default, and FS_NOCOW_FL can be used to switch off COW for a single file. If we mount btrfs with nodatacow, a newly created file will be set with the FS_NOCOW_FL flag. So to turn on COW for it, we can just clear the FS_NOCOW_FL flag. Signed-off-by: Li Zefan Signed-off-by: Chris Mason diff --git a/fs/btrfs/ioctl.c b/fs/btrfs/ioctl.c index f580a3a..3240dd9 100644 --- a/fs/btrfs/ioctl.c +++ b/fs/btrfs/ioctl.c @@ -144,16 +144,13 @@ static int check_flags(unsigned int flags) if (flags & ~(FS_IMMUTABLE_FL | FS_APPEND_FL | \ FS_NOATIME_FL | FS_NODUMP_FL | \ FS_SYNC_FL | FS_DIRSYNC_FL | \ - FS_NOCOMP_FL | FS_COMPR_FL | \ - FS_NOCOW_FL | FS_COW_FL)) + FS_NOCOMP_FL | FS_COMPR_FL | + FS_NOCOW_FL)) return -EOPNOTSUPP; if ((flags & FS_NOCOMP_FL) && (flags & FS_COMPR_FL)) return -EINVAL; - if ((flags & FS_NOCOW_FL) && (flags & FS_COW_FL)) - return -EINVAL; - return 0; } @@ -218,6 +215,10 @@ static int btrfs_ioctl_setflags(struct file *file, void __user *arg) ip->flags |= BTRFS_INODE_DIRSYNC; else ip->flags &= ~BTRFS_INODE_DIRSYNC; + if (flags & FS_NOCOW_FL) + ip->flags |= BTRFS_INODE_NODATACOW; + else + ip->flags &= ~BTRFS_INODE_NODATACOW; /* * The COMPRESS flag can only be changed by users, while the NOCOMPRESS @@ -231,10 +232,6 @@ static int btrfs_ioctl_setflags(struct file *file, void __user *arg) ip->flags |= BTRFS_INODE_COMPRESS; ip->flags &= ~BTRFS_INODE_NOCOMPRESS; } - if (flags & FS_NOCOW_FL) - ip->flags |= BTRFS_INODE_NODATACOW; - else if (flags & FS_COW_FL) - ip->flags &= ~BTRFS_INODE_NODATACOW; trans = btrfs_join_transaction(root, 1); BUG_ON(IS_ERR(trans)); diff --git a/include/linux/fs.h b/include/linux/fs.h index de9dd81..56a4141 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -365,7 +365,6 @@ struct inodes_stat_t { #define FS_EXTENT_FL 0x00080000 /* Extents */ #define FS_DIRECTIO_FL 0x00100000 /* Use direct i/o */ #define FS_NOCOW_FL 0x00800000 /* Do not cow file */ -#define FS_COW_FL 0x02000000 /* Cow file */ #define FS_RESERVED_FL 0x80000000 /* reserved for ext2 lib */ #define FS_FL_USER_VISIBLE 0x0003DFFF /* User visible flags */ -- cgit v0.10.2 From d0092bdda819914b8725da76a8c33eb06eb0bd21 Mon Sep 17 00:00:00 2001 From: Li Zefan Date: Fri, 15 Apr 2011 03:03:06 +0000 Subject: Btrfs: fix FS_IOC_GETFLAGS ioctl As we've added per file compression/cow support. Signed-off-by: Li Zefan Signed-off-by: Chris Mason diff --git a/fs/btrfs/ioctl.c b/fs/btrfs/ioctl.c index 3240dd9..aeabf6b 100644 --- a/fs/btrfs/ioctl.c +++ b/fs/btrfs/ioctl.c @@ -81,6 +81,13 @@ static unsigned int btrfs_flags_to_ioctl(unsigned int flags) iflags |= FS_NOATIME_FL; if (flags & BTRFS_INODE_DIRSYNC) iflags |= FS_DIRSYNC_FL; + if (flags & BTRFS_INODE_NODATACOW) + iflags |= FS_NOCOW_FL; + + if ((flags & BTRFS_INODE_COMPRESS) && !(flags & BTRFS_INODE_NOCOMPRESS)) + iflags |= FS_COMPR_FL; + else if (flags & BTRFS_INODE_NOCOMPRESS) + iflags |= FS_NOCOMP_FL; return iflags; } -- cgit v0.10.2 From ebcb904dfe31644857422e3bb62e50f76fe86255 Mon Sep 17 00:00:00 2001 From: Li Zefan Date: Fri, 15 Apr 2011 03:03:17 +0000 Subject: Btrfs: fix FS_IOC_SETFLAGS ioctl Steps to reproduce the bug: - Call FS_IOC_SETLFAGS ioctl with flags=FS_COMPR_FL - Call FS_IOC_SETFLAGS ioctl with flags=0 - Call FS_IOC_GETFLAGS ioctl, and you'll see FS_COMPR_FL is still set! Signed-off-by: Li Zefan Signed-off-by: Chris Mason diff --git a/fs/btrfs/ioctl.c b/fs/btrfs/ioctl.c index aeabf6b..3e7031d 100644 --- a/fs/btrfs/ioctl.c +++ b/fs/btrfs/ioctl.c @@ -238,6 +238,8 @@ static int btrfs_ioctl_setflags(struct file *file, void __user *arg) } else if (flags & FS_COMPR_FL) { ip->flags |= BTRFS_INODE_COMPRESS; ip->flags &= ~BTRFS_INODE_NOCOMPRESS; + } else { + ip->flags &= ~(BTRFS_INODE_COMPRESS | BTRFS_INODE_NOCOMPRESS); } trans = btrfs_join_transaction(root, 1); -- cgit v0.10.2 From 6d5808d4ae1b0851c3b732d9ec2860d5f7804294 Mon Sep 17 00:00:00 2001 From: Sven Eckelmann Date: Wed, 11 May 2011 20:59:06 +0200 Subject: batman-adv: Add missing hardif_free_ref in forw_packet_free add_bcast_packet_to_list increases the refcount for if_incoming but the reference count is never decreased. The reference count must be increased for all kinds of forwarded packets which have the primary interface stored and forw_packet_free must decrease them. Also purge_outstanding_packets has to invoke forw_packet_free when a work item was really cancelled. This regression was introduced in 32ae9b221e788413ce68feaae2ca39e406211a0a. Reported-by: Antonio Quartulli Signed-off-by: Sven Eckelmann diff --git a/net/batman-adv/aggregation.c b/net/batman-adv/aggregation.c index 9b94590..a8c3203 100644 --- a/net/batman-adv/aggregation.c +++ b/net/batman-adv/aggregation.c @@ -23,6 +23,7 @@ #include "aggregation.h" #include "send.h" #include "routing.h" +#include "hard-interface.h" /* calculate the size of the tt information for a given packet */ static int tt_len(struct batman_packet *batman_packet) @@ -105,12 +106,15 @@ static void new_aggregated_packet(unsigned char *packet_buff, int packet_len, struct forw_packet *forw_packet_aggr; unsigned char *skb_buff; + if (!atomic_inc_not_zero(&if_incoming->refcount)) + return; + /* own packet should always be scheduled */ if (!own_packet) { if (!atomic_dec_not_zero(&bat_priv->batman_queue_left)) { bat_dbg(DBG_BATMAN, bat_priv, "batman packet queue full\n"); - return; + goto out; } } @@ -118,7 +122,7 @@ static void new_aggregated_packet(unsigned char *packet_buff, int packet_len, if (!forw_packet_aggr) { if (!own_packet) atomic_inc(&bat_priv->batman_queue_left); - return; + goto out; } if ((atomic_read(&bat_priv->aggregated_ogms)) && @@ -133,7 +137,7 @@ static void new_aggregated_packet(unsigned char *packet_buff, int packet_len, if (!own_packet) atomic_inc(&bat_priv->batman_queue_left); kfree(forw_packet_aggr); - return; + goto out; } skb_reserve(forw_packet_aggr->skb, sizeof(struct ethhdr)); @@ -164,6 +168,10 @@ static void new_aggregated_packet(unsigned char *packet_buff, int packet_len, queue_delayed_work(bat_event_workqueue, &forw_packet_aggr->delayed_work, send_time - jiffies); + + return; +out: + hardif_free_ref(if_incoming); } /* aggregate a new packet into the existing aggregation */ diff --git a/net/batman-adv/send.c b/net/batman-adv/send.c index f30d0c6..76daa46 100644 --- a/net/batman-adv/send.c +++ b/net/batman-adv/send.c @@ -377,6 +377,8 @@ static void forw_packet_free(struct forw_packet *forw_packet) { if (forw_packet->skb) kfree_skb(forw_packet->skb); + if (forw_packet->if_incoming) + hardif_free_ref(forw_packet->if_incoming); kfree(forw_packet); } @@ -539,6 +541,7 @@ void purge_outstanding_packets(struct bat_priv *bat_priv, { struct forw_packet *forw_packet; struct hlist_node *tmp_node, *safe_tmp_node; + bool pending; if (hard_iface) bat_dbg(DBG_BATMAN, bat_priv, @@ -567,8 +570,13 @@ void purge_outstanding_packets(struct bat_priv *bat_priv, * send_outstanding_bcast_packet() will lock the list to * delete the item from the list */ - cancel_delayed_work_sync(&forw_packet->delayed_work); + pending = cancel_delayed_work_sync(&forw_packet->delayed_work); spin_lock_bh(&bat_priv->forw_bcast_list_lock); + + if (pending) { + hlist_del(&forw_packet->list); + forw_packet_free(forw_packet); + } } spin_unlock_bh(&bat_priv->forw_bcast_list_lock); @@ -591,8 +599,13 @@ void purge_outstanding_packets(struct bat_priv *bat_priv, * send_outstanding_bat_packet() will lock the list to * delete the item from the list */ - cancel_delayed_work_sync(&forw_packet->delayed_work); + pending = cancel_delayed_work_sync(&forw_packet->delayed_work); spin_lock_bh(&bat_priv->forw_bat_list_lock); + + if (pending) { + hlist_del(&forw_packet->list); + forw_packet_free(forw_packet); + } } spin_unlock_bh(&bat_priv->forw_bat_list_lock); } -- cgit v0.10.2 From ca06c6eb9a31ae782e74596231fb23df4fc5e46d Mon Sep 17 00:00:00 2001 From: Marek Lindner Date: Sat, 14 May 2011 20:01:22 +0200 Subject: batman-adv: reset broadcast flood protection on error The broadcast flood protection should be reset to its original value if the primary interface could not be retrieved. Signed-off-by: Marek Lindner Signed-off-by: Sven Eckelmann diff --git a/net/batman-adv/send.c b/net/batman-adv/send.c index 76daa46..3377927 100644 --- a/net/batman-adv/send.c +++ b/net/batman-adv/send.c @@ -421,7 +421,7 @@ int add_bcast_packet_to_list(struct bat_priv *bat_priv, struct sk_buff *skb) primary_if = primary_if_get_selected(bat_priv); if (!primary_if) - goto out; + goto out_and_inc; forw_packet = kmalloc(sizeof(struct forw_packet), GFP_ATOMIC); -- cgit v0.10.2 From d64a6f4dca0b45495dd5be8116b618d9cc004eea Mon Sep 17 00:00:00 2001 From: Bruce Allan Date: Fri, 13 May 2011 07:19:58 +0000 Subject: e1000e: minor comment cleanups Signed-off-by: Bruce Allan Tested-by: Aaron Brown Signed-off-by: Jeff Kirsher diff --git a/drivers/net/e1000e/lib.c b/drivers/net/e1000e/lib.c index 6432dda..dd8ab05 100644 --- a/drivers/net/e1000e/lib.c +++ b/drivers/net/e1000e/lib.c @@ -144,7 +144,7 @@ void e1000_write_vfta_generic(struct e1000_hw *hw, u32 offset, u32 value) * @hw: pointer to the HW structure * @rar_count: receive address registers * - * Setups the receive address registers by setting the base receive address + * Setup the receive address registers by setting the base receive address * register to the devices MAC address and clearing all the other receive * address registers to 0. **/ @@ -1181,7 +1181,7 @@ s32 e1000e_config_fc_after_link_up(struct e1000_hw *hw) * of pause frames. In this case, we had to advertise * FULL flow control because we could not advertise Rx * ONLY. Hence, we must now check to see if we need to - * turn OFF the TRANSMISSION of PAUSE frames. + * turn OFF the TRANSMISSION of PAUSE frames. */ if (hw->fc.requested_mode == e1000_fc_full) { hw->fc.current_mode = e1000_fc_full; -- cgit v0.10.2 From 46ec20ff7d6f9f011e06d58e4e87153ed8c893ed Mon Sep 17 00:00:00 2001 From: Greg Rose Date: Fri, 13 May 2011 01:33:42 +0000 Subject: ixgbevf: Add macvlan support in the set rx mode op Implement setup of unicast address list in the VF driver's set_rx_mode netdev op. Unicast addresses are sent to the PF via a mailbox message and the PF will check if it has room in the RAR table and if so set the filter for the VF. Signed-off-by: Greg Rose Tested-by: Sibai Li Signed-off-by: Jeff Kirsher diff --git a/drivers/net/ixgbevf/ixgbevf_main.c b/drivers/net/ixgbevf/ixgbevf_main.c index 05fa7c8..d7ab202 100644 --- a/drivers/net/ixgbevf/ixgbevf_main.c +++ b/drivers/net/ixgbevf/ixgbevf_main.c @@ -1460,6 +1460,34 @@ static void ixgbevf_restore_vlan(struct ixgbevf_adapter *adapter) } } +static int ixgbevf_write_uc_addr_list(struct net_device *netdev) +{ + struct ixgbevf_adapter *adapter = netdev_priv(netdev); + struct ixgbe_hw *hw = &adapter->hw; + int count = 0; + + if ((netdev_uc_count(netdev)) > 10) { + printk(KERN_ERR "Too many unicast filters - No Space\n"); + return -ENOSPC; + } + + if (!netdev_uc_empty(netdev)) { + struct netdev_hw_addr *ha; + netdev_for_each_uc_addr(ha, netdev) { + hw->mac.ops.set_uc_addr(hw, ++count, ha->addr); + udelay(200); + } + } else { + /* + * If the list is empty then send message to PF driver to + * clear all macvlans on this VF. + */ + hw->mac.ops.set_uc_addr(hw, 0, NULL); + } + + return count; +} + /** * ixgbevf_set_rx_mode - Multicast set * @netdev: network interface device structure @@ -1476,6 +1504,8 @@ static void ixgbevf_set_rx_mode(struct net_device *netdev) /* reprogram multicast list */ if (hw->mac.ops.update_mc_addr_list) hw->mac.ops.update_mc_addr_list(hw, netdev); + + ixgbevf_write_uc_addr_list(netdev); } static void ixgbevf_napi_enable_all(struct ixgbevf_adapter *adapter) diff --git a/drivers/net/ixgbevf/mbx.h b/drivers/net/ixgbevf/mbx.h index b2b5bf5..ea393eb 100644 --- a/drivers/net/ixgbevf/mbx.h +++ b/drivers/net/ixgbevf/mbx.h @@ -81,6 +81,7 @@ #define IXGBE_VF_SET_MULTICAST 0x03 /* VF requests PF to set MC addr */ #define IXGBE_VF_SET_VLAN 0x04 /* VF requests PF to set VLAN */ #define IXGBE_VF_SET_LPE 0x05 /* VF requests PF to set VMOLR.LPE */ +#define IXGBE_VF_SET_MACVLAN 0x06 /* VF requests PF for unicast filter */ /* length of permanent address message returned from PF */ #define IXGBE_VF_PERMADDR_MSG_LEN 4 diff --git a/drivers/net/ixgbevf/vf.c b/drivers/net/ixgbevf/vf.c index eecd3bf..aa3682e 100644 --- a/drivers/net/ixgbevf/vf.c +++ b/drivers/net/ixgbevf/vf.c @@ -216,6 +216,39 @@ static s32 ixgbevf_get_mac_addr_vf(struct ixgbe_hw *hw, u8 *mac_addr) return 0; } +static s32 ixgbevf_set_uc_addr_vf(struct ixgbe_hw *hw, u32 index, u8 *addr) +{ + struct ixgbe_mbx_info *mbx = &hw->mbx; + u32 msgbuf[3]; + u8 *msg_addr = (u8 *)(&msgbuf[1]); + s32 ret_val; + + memset(msgbuf, 0, sizeof(msgbuf)); + /* + * If index is one then this is the start of a new list and needs + * indication to the PF so it can do it's own list management. + * If it is zero then that tells the PF to just clear all of + * this VF's macvlans and there is no new list. + */ + msgbuf[0] |= index << IXGBE_VT_MSGINFO_SHIFT; + msgbuf[0] |= IXGBE_VF_SET_MACVLAN; + if (addr) + memcpy(msg_addr, addr, 6); + ret_val = mbx->ops.write_posted(hw, msgbuf, 3); + + if (!ret_val) + ret_val = mbx->ops.read_posted(hw, msgbuf, 3); + + msgbuf[0] &= ~IXGBE_VT_MSGTYPE_CTS; + + if (!ret_val) + if (msgbuf[0] == + (IXGBE_VF_SET_MACVLAN | IXGBE_VT_MSGTYPE_NACK)) + ret_val = -ENOMEM; + + return ret_val; +} + /** * ixgbevf_set_rar_vf - set device MAC address * @hw: pointer to hardware structure @@ -378,6 +411,7 @@ static struct ixgbe_mac_operations ixgbevf_mac_ops = { .check_link = ixgbevf_check_mac_link_vf, .set_rar = ixgbevf_set_rar_vf, .update_mc_addr_list = ixgbevf_update_mc_addr_list_vf, + .set_uc_addr = ixgbevf_set_uc_addr_vf, .set_vfta = ixgbevf_set_vfta_vf, }; diff --git a/drivers/net/ixgbevf/vf.h b/drivers/net/ixgbevf/vf.h index 23eb114..10306b4 100644 --- a/drivers/net/ixgbevf/vf.h +++ b/drivers/net/ixgbevf/vf.h @@ -62,6 +62,7 @@ struct ixgbe_mac_operations { /* RAR, Multicast, VLAN */ s32 (*set_rar)(struct ixgbe_hw *, u32, u8 *, u32); + s32 (*set_uc_addr)(struct ixgbe_hw *, u32, u8 *); s32 (*init_rx_addrs)(struct ixgbe_hw *); s32 (*update_mc_addr_list)(struct ixgbe_hw *, struct net_device *); s32 (*enable_mc)(struct ixgbe_hw *); -- cgit v0.10.2 From a1cbb15c13971bd5d41626e9e5ced9f9de132c47 Mon Sep 17 00:00:00 2001 From: Greg Rose Date: Fri, 13 May 2011 01:33:48 +0000 Subject: ixgbe: Add macvlan support for VF Add infrastructure in the PF driver to support macvlan in the VF driver. Signed-off-by: Greg Rose Tested-by: Sibai Li Signed-off-by: Jeff Kirsher diff --git a/drivers/net/ixgbe/ixgbe.h b/drivers/net/ixgbe/ixgbe.h index 37ff531..91c1540 100644 --- a/drivers/net/ixgbe/ixgbe.h +++ b/drivers/net/ixgbe/ixgbe.h @@ -106,6 +106,7 @@ #define IXGBE_MAX_VF_FUNCTIONS 64 #define IXGBE_MAX_VFTA_ENTRIES 128 #define MAX_EMULATION_MAC_ADDRS 16 +#define IXGBE_MAX_PF_MACVLANS 15 #define VMDQ_P(p) ((p) + adapter->num_vfs) struct vf_data_storage { @@ -121,6 +122,15 @@ struct vf_data_storage { u16 tx_rate; }; +struct vf_macvlans { + struct list_head l; + int vf; + int rar_entry; + bool free; + bool is_macvlan; + u8 vf_macvlan[ETH_ALEN]; +}; + /* wrapper around a pointer to a socket buffer, * so a DMA handle can be stored along with the buffer */ struct ixgbe_tx_buffer { @@ -471,6 +481,9 @@ struct ixgbe_adapter { unsigned int num_vfs; struct vf_data_storage *vfinfo; int vf_rate_link_speed; + struct vf_macvlans vf_mvs; + struct vf_macvlans *mv_list; + bool antispoofing_enabled; }; enum ixbge_state_t { diff --git a/drivers/net/ixgbe/ixgbe_main.c b/drivers/net/ixgbe/ixgbe_main.c index a3e384b..f8196e0 100644 --- a/drivers/net/ixgbe/ixgbe_main.c +++ b/drivers/net/ixgbe/ixgbe_main.c @@ -3188,7 +3188,9 @@ static void ixgbe_configure_virtualization(struct ixgbe_adapter *adapter) /* enable Tx loopback for VF/PF communication */ IXGBE_WRITE_REG(hw, IXGBE_PFDTXGSWC, IXGBE_PFDTXGSWC_VT_LBEN); /* Enable MAC Anti-Spoofing */ - hw->mac.ops.set_mac_anti_spoofing(hw, (adapter->num_vfs != 0), + hw->mac.ops.set_mac_anti_spoofing(hw, + (adapter->antispoofing_enabled = + (adapter->num_vfs != 0)), adapter->num_vfs); } @@ -3497,7 +3499,7 @@ static int ixgbe_write_uc_addr_list(struct net_device *netdev) struct ixgbe_adapter *adapter = netdev_priv(netdev); struct ixgbe_hw *hw = &adapter->hw; unsigned int vfn = adapter->num_vfs; - unsigned int rar_entries = hw->mac.num_rar_entries - (vfn + 1); + unsigned int rar_entries = IXGBE_MAX_PF_MACVLANS; int count = 0; /* return ENOMEM indicating insufficient memory for addresses */ @@ -7107,6 +7109,8 @@ static void __devinit ixgbe_probe_vf(struct ixgbe_adapter *adapter, #ifdef CONFIG_PCI_IOV struct ixgbe_hw *hw = &adapter->hw; int err; + int num_vf_macvlans, i; + struct vf_macvlans *mv_list; if (hw->mac.type == ixgbe_mac_82598EB || !max_vfs) return; @@ -7123,6 +7127,26 @@ static void __devinit ixgbe_probe_vf(struct ixgbe_adapter *adapter, e_err(probe, "Failed to enable PCI sriov: %d\n", err); goto err_novfs; } + + num_vf_macvlans = hw->mac.num_rar_entries - + (IXGBE_MAX_PF_MACVLANS + 1 + adapter->num_vfs); + + adapter->mv_list = mv_list = kcalloc(num_vf_macvlans, + sizeof(struct vf_macvlans), + GFP_KERNEL); + if (mv_list) { + /* Initialize list of VF macvlans */ + INIT_LIST_HEAD(&adapter->vf_mvs.l); + for (i = 0; i < num_vf_macvlans; i++) { + mv_list->vf = -1; + mv_list->free = true; + mv_list->rar_entry = hw->mac.num_rar_entries - + (i + adapter->num_vfs + 1); + list_add(&mv_list->l, &adapter->vf_mvs.l); + mv_list++; + } + } + /* If call to enable VFs succeeded then allocate memory * for per VF control structures. */ diff --git a/drivers/net/ixgbe/ixgbe_mbx.h b/drivers/net/ixgbe/ixgbe_mbx.h index f53dc5b..b239bda 100644 --- a/drivers/net/ixgbe/ixgbe_mbx.h +++ b/drivers/net/ixgbe/ixgbe_mbx.h @@ -67,6 +67,7 @@ #define IXGBE_VF_SET_MULTICAST 0x03 /* VF requests PF to set MC addr */ #define IXGBE_VF_SET_VLAN 0x04 /* VF requests PF to set VLAN */ #define IXGBE_VF_SET_LPE 0x05 /* VF requests PF to set VMOLR.LPE */ +#define IXGBE_VF_SET_MACVLAN 0x06 /* VF requests PF for unicast filter */ /* length of permanent address message returned from PF */ #define IXGBE_VF_PERMADDR_MSG_LEN 4 diff --git a/drivers/net/ixgbe/ixgbe_sriov.c b/drivers/net/ixgbe/ixgbe_sriov.c index 4765027..9f97246 100644 --- a/drivers/net/ixgbe/ixgbe_sriov.c +++ b/drivers/net/ixgbe/ixgbe_sriov.c @@ -82,6 +82,21 @@ static int ixgbe_set_vf_multicasts(struct ixgbe_adapter *adapter, return 0; } +static void ixgbe_restore_vf_macvlans(struct ixgbe_adapter *adapter) +{ + struct ixgbe_hw *hw = &adapter->hw; + struct list_head *pos; + struct vf_macvlans *entry; + + list_for_each(pos, &adapter->vf_mvs.l) { + entry = list_entry(pos, struct vf_macvlans, l); + if (entry->free == false) + hw->mac.ops.set_rar(hw, entry->rar_entry, + entry->vf_macvlan, + entry->vf, IXGBE_RAH_AV); + } +} + void ixgbe_restore_vf_multicasts(struct ixgbe_adapter *adapter) { struct ixgbe_hw *hw = &adapter->hw; @@ -102,6 +117,9 @@ void ixgbe_restore_vf_multicasts(struct ixgbe_adapter *adapter) IXGBE_WRITE_REG(hw, IXGBE_MTA(vector_reg), mta_reg); } } + + /* Restore any VF macvlans */ + ixgbe_restore_vf_macvlans(adapter); } static int ixgbe_set_vf_vlan(struct ixgbe_adapter *adapter, int add, int vid, @@ -200,6 +218,61 @@ static int ixgbe_set_vf_mac(struct ixgbe_adapter *adapter, return 0; } +static int ixgbe_set_vf_macvlan(struct ixgbe_adapter *adapter, + int vf, int index, unsigned char *mac_addr) +{ + struct ixgbe_hw *hw = &adapter->hw; + struct list_head *pos; + struct vf_macvlans *entry; + + if (index <= 1) { + list_for_each(pos, &adapter->vf_mvs.l) { + entry = list_entry(pos, struct vf_macvlans, l); + if (entry->vf == vf) { + entry->vf = -1; + entry->free = true; + entry->is_macvlan = false; + hw->mac.ops.clear_rar(hw, entry->rar_entry); + } + } + } + + /* + * If index was zero then we were asked to clear the uc list + * for the VF. We're done. + */ + if (!index) + return 0; + + entry = NULL; + + list_for_each(pos, &adapter->vf_mvs.l) { + entry = list_entry(pos, struct vf_macvlans, l); + if (entry->free) + break; + } + + /* + * If we traversed the entire list and didn't find a free entry + * then we're out of space on the RAR table. Also entry may + * be NULL because the original memory allocation for the list + * failed, which is not fatal but does mean we can't support + * VF requests for MACVLAN because we couldn't allocate + * memory for the list management required. + */ + if (!entry || !entry->free) + return -ENOSPC; + + entry->free = false; + entry->is_macvlan = true; + entry->vf = vf; + memcpy(entry->vf_macvlan, mac_addr, ETH_ALEN); + + hw->mac.ops.set_rar(hw, entry->rar_entry, mac_addr, vf, IXGBE_RAH_AV); + + return 0; +} + int ixgbe_vf_configuration(struct pci_dev *pdev, unsigned int event_mask) { unsigned char vf_mac_addr[6]; @@ -256,7 +329,7 @@ static int ixgbe_rcv_msg_from_vf(struct ixgbe_adapter *adapter, u32 vf) s32 retval; int entries; u16 *hash_list; - int add, vid; + int add, vid, index; u8 *new_mac; retval = ixgbe_read_mbx(hw, msgbuf, mbx_size, vf); @@ -345,6 +418,24 @@ static int ixgbe_rcv_msg_from_vf(struct ixgbe_adapter *adapter, u32 vf) retval = ixgbe_set_vf_vlan(adapter, add, vid, vf); } break; + case IXGBE_VF_SET_MACVLAN: + index = (msgbuf[0] & IXGBE_VT_MSGINFO_MASK) >> + IXGBE_VT_MSGINFO_SHIFT; + /* + * If the VF is allowed to set MAC filters then turn off + * anti-spoofing to avoid false positives. An index + * greater than 0 will indicate the VF is setting a + * macvlan MAC filter. + */ + if (index > 0 && adapter->antispoofing_enabled) { + hw->mac.ops.set_mac_anti_spoofing(hw, false, + adapter->num_vfs); + hw->mac.ops.set_vlan_anti_spoofing(hw, false, vf); + adapter->antispoofing_enabled = false; + } + retval = ixgbe_set_vf_macvlan(adapter, vf, index, + (unsigned char *)(&msgbuf[1])); + break; default: e_err(drv, "Unhandled Msg %8.8x\n", msgbuf[0]); retval = IXGBE_ERR_MBX; @@ -452,7 +543,8 @@ int ixgbe_ndo_set_vf_vlan(struct net_device *netdev, int vf, u16 vlan, u8 qos) goto out; ixgbe_set_vmvir(adapter, vlan | (qos << VLAN_PRIO_SHIFT), vf); ixgbe_set_vmolr(hw, vf, false); - hw->mac.ops.set_vlan_anti_spoofing(hw, true, vf); + if (adapter->antispoofing_enabled) + hw->mac.ops.set_vlan_anti_spoofing(hw, true, vf); adapter->vfinfo[vf].pf_vlan = vlan; adapter->vfinfo[vf].pf_qos = qos; dev_info(&adapter->pdev->dev, -- cgit v0.10.2 From 51275d37a85bc82bda7e5b179ee520e85e66e782 Mon Sep 17 00:00:00 2001 From: Emil Tantilov Date: Fri, 8 Apr 2011 01:23:59 +0000 Subject: ixgbe: force unlock on timeout The semaphore can be in locked state upon driver load, particularly on 82598 if a machine is rebooted due to panic and the semaphore was acquired just prior to the panic. This patch unlocks the semaphore if it times out. Signed-off-by: Emil Tantilov Signed-off-by: Jeff Kirsher diff --git a/drivers/net/ixgbe/ixgbe_common.c b/drivers/net/ixgbe/ixgbe_common.c index c4730cd..b894b42 100644 --- a/drivers/net/ixgbe/ixgbe_common.c +++ b/drivers/net/ixgbe/ixgbe_common.c @@ -1189,6 +1189,28 @@ static s32 ixgbe_get_eeprom_semaphore(struct ixgbe_hw *hw) udelay(50); } + if (i == timeout) { + hw_dbg(hw, "Driver can't access the Eeprom - SMBI Semaphore " + "not granted.\n"); + /* + * this release is particularly important because our attempts + * above to get the semaphore may have succeeded, and if there + * was a timeout, we should unconditionally clear the semaphore + * bits to free the driver to make progress + */ + ixgbe_release_eeprom_semaphore(hw); + + udelay(50); + /* + * one last try + * If the SMBI bit is 0 when we read it, then the bit will be + * set and we have the semaphore + */ + swsm = IXGBE_READ_REG(hw, IXGBE_SWSM); + if (!(swsm & IXGBE_SWSM_SMBI)) + status = 0; + } + /* Now get the semaphore between SW/FW through the SWESMBI bit */ if (status == 0) { for (i = 0; i < timeout; i++) { -- cgit v0.10.2 From e606bfe74de63d6c3778c145ee0673d96ab257c9 Mon Sep 17 00:00:00 2001 From: Alexander Duyck Date: Fri, 22 Apr 2011 04:07:43 +0000 Subject: ixgbe: move flags and state into the same cacheline This change moves flags and state into the same cacheline. The reason for this change is because both are frequently read around the same time and infrequently written. By combining them into the same cacheline this should help to reduce memory utilization. Signed-off-by: Alexander Duyck Tested-by: Evan Swanson Signed-off-by: Jeff Kirsher diff --git a/drivers/net/ixgbe/ixgbe.h b/drivers/net/ixgbe/ixgbe.h index 91c1540..ec948ff 100644 --- a/drivers/net/ixgbe/ixgbe.h +++ b/drivers/net/ixgbe/ixgbe.h @@ -341,10 +341,48 @@ struct ixgbe_q_vector { /* board specific private data structure */ struct ixgbe_adapter { - struct timer_list watchdog_timer; + unsigned long state; + + /* Some features need tri-state capability, + * thus the additional *_CAPABLE flags. + */ + u32 flags; +#define IXGBE_FLAG_RX_CSUM_ENABLED (u32)(1) +#define IXGBE_FLAG_MSI_CAPABLE (u32)(1 << 1) +#define IXGBE_FLAG_MSI_ENABLED (u32)(1 << 2) +#define IXGBE_FLAG_MSIX_CAPABLE (u32)(1 << 3) +#define IXGBE_FLAG_MSIX_ENABLED (u32)(1 << 4) +#define IXGBE_FLAG_RX_1BUF_CAPABLE (u32)(1 << 6) +#define IXGBE_FLAG_RX_PS_CAPABLE (u32)(1 << 7) +#define IXGBE_FLAG_RX_PS_ENABLED (u32)(1 << 8) +#define IXGBE_FLAG_IN_NETPOLL (u32)(1 << 9) +#define IXGBE_FLAG_DCA_ENABLED (u32)(1 << 10) +#define IXGBE_FLAG_DCA_CAPABLE (u32)(1 << 11) +#define IXGBE_FLAG_IMIR_ENABLED (u32)(1 << 12) +#define IXGBE_FLAG_MQ_CAPABLE (u32)(1 << 13) +#define IXGBE_FLAG_DCB_ENABLED (u32)(1 << 14) +#define IXGBE_FLAG_RSS_ENABLED (u32)(1 << 16) +#define IXGBE_FLAG_RSS_CAPABLE (u32)(1 << 17) +#define IXGBE_FLAG_VMDQ_CAPABLE (u32)(1 << 18) +#define IXGBE_FLAG_VMDQ_ENABLED (u32)(1 << 19) +#define IXGBE_FLAG_FAN_FAIL_CAPABLE (u32)(1 << 20) +#define IXGBE_FLAG_NEED_LINK_UPDATE (u32)(1 << 22) +#define IXGBE_FLAG_IN_SFP_LINK_TASK (u32)(1 << 23) +#define IXGBE_FLAG_IN_SFP_MOD_TASK (u32)(1 << 24) +#define IXGBE_FLAG_FDIR_HASH_CAPABLE (u32)(1 << 25) +#define IXGBE_FLAG_FDIR_PERFECT_CAPABLE (u32)(1 << 26) +#define IXGBE_FLAG_FCOE_CAPABLE (u32)(1 << 27) +#define IXGBE_FLAG_FCOE_ENABLED (u32)(1 << 28) +#define IXGBE_FLAG_SRIOV_CAPABLE (u32)(1 << 29) +#define IXGBE_FLAG_SRIOV_ENABLED (u32)(1 << 30) + + u32 flags2; +#define IXGBE_FLAG2_RSC_CAPABLE (u32)(1) +#define IXGBE_FLAG2_RSC_ENABLED (u32)(1 << 1) +#define IXGBE_FLAG2_TEMP_SENSOR_CAPABLE (u32)(1 << 2) + unsigned long active_vlans[BITS_TO_LONGS(VLAN_N_VID)]; u16 bd_number; - struct work_struct reset_task; struct ixgbe_q_vector *q_vector[MAX_MSIX_Q_VECTORS]; /* DCB parameters */ @@ -387,43 +425,6 @@ struct ixgbe_adapter { u32 alloc_rx_page_failed; u32 alloc_rx_buff_failed; - /* Some features need tri-state capability, - * thus the additional *_CAPABLE flags. - */ - u32 flags; -#define IXGBE_FLAG_RX_CSUM_ENABLED (u32)(1) -#define IXGBE_FLAG_MSI_CAPABLE (u32)(1 << 1) -#define IXGBE_FLAG_MSI_ENABLED (u32)(1 << 2) -#define IXGBE_FLAG_MSIX_CAPABLE (u32)(1 << 3) -#define IXGBE_FLAG_MSIX_ENABLED (u32)(1 << 4) -#define IXGBE_FLAG_RX_1BUF_CAPABLE (u32)(1 << 6) -#define IXGBE_FLAG_RX_PS_CAPABLE (u32)(1 << 7) -#define IXGBE_FLAG_RX_PS_ENABLED (u32)(1 << 8) -#define IXGBE_FLAG_IN_NETPOLL (u32)(1 << 9) -#define IXGBE_FLAG_DCA_ENABLED (u32)(1 << 10) -#define IXGBE_FLAG_DCA_CAPABLE (u32)(1 << 11) -#define IXGBE_FLAG_IMIR_ENABLED (u32)(1 << 12) -#define IXGBE_FLAG_MQ_CAPABLE (u32)(1 << 13) -#define IXGBE_FLAG_DCB_ENABLED (u32)(1 << 14) -#define IXGBE_FLAG_RSS_ENABLED (u32)(1 << 16) -#define IXGBE_FLAG_RSS_CAPABLE (u32)(1 << 17) -#define IXGBE_FLAG_VMDQ_CAPABLE (u32)(1 << 18) -#define IXGBE_FLAG_VMDQ_ENABLED (u32)(1 << 19) -#define IXGBE_FLAG_FAN_FAIL_CAPABLE (u32)(1 << 20) -#define IXGBE_FLAG_NEED_LINK_UPDATE (u32)(1 << 22) -#define IXGBE_FLAG_IN_SFP_LINK_TASK (u32)(1 << 23) -#define IXGBE_FLAG_IN_SFP_MOD_TASK (u32)(1 << 24) -#define IXGBE_FLAG_FDIR_HASH_CAPABLE (u32)(1 << 25) -#define IXGBE_FLAG_FDIR_PERFECT_CAPABLE (u32)(1 << 26) -#define IXGBE_FLAG_FCOE_CAPABLE (u32)(1 << 27) -#define IXGBE_FLAG_FCOE_ENABLED (u32)(1 << 28) -#define IXGBE_FLAG_SRIOV_CAPABLE (u32)(1 << 29) -#define IXGBE_FLAG_SRIOV_ENABLED (u32)(1 << 30) - - u32 flags2; -#define IXGBE_FLAG2_RSC_CAPABLE (u32)(1) -#define IXGBE_FLAG2_RSC_ENABLED (u32)(1 << 1) -#define IXGBE_FLAG2_TEMP_SENSOR_CAPABLE (u32)(1 << 2) /* default to trying for four seconds */ #define IXGBE_TRY_LINK_TIMEOUT (4 * HZ) @@ -444,7 +445,6 @@ struct ixgbe_adapter { u32 rx_eitr_param; u32 tx_eitr_param; - unsigned long state; u64 tx_busy; unsigned int tx_ring_count; unsigned int rx_ring_count; @@ -453,15 +453,18 @@ struct ixgbe_adapter { bool link_up; unsigned long link_check_timeout; + struct work_struct reset_task; struct work_struct watchdog_task; struct work_struct sfp_task; - struct timer_list sfp_timer; struct work_struct multispeed_fiber_task; struct work_struct sfp_config_module_task; + struct work_struct fdir_reinit_task; + struct work_struct check_overtemp_task; + struct timer_list watchdog_timer; + struct timer_list sfp_timer; u32 fdir_pballoc; u32 atr_sample_rate; spinlock_t fdir_perfect_lock; - struct work_struct fdir_reinit_task; #ifdef IXGBE_FCOE struct ixgbe_fcoe fcoe; #endif /* IXGBE_FCOE */ @@ -472,7 +475,6 @@ struct ixgbe_adapter { int node; u32 led_reg; - struct work_struct check_overtemp_task; u32 interrupt_event; char lsc_int_name[IFNAMSIZ + 9]; -- cgit v0.10.2 From 7086400d87a06588c13270949db9134afc9553ba Mon Sep 17 00:00:00 2001 From: Alexander Duyck Date: Wed, 27 Apr 2011 09:13:56 +0000 Subject: ixgbe: Combine SFP and multi-speed fiber task into single service task This change is meant to address several race conditions with multi-speed fiber SFP+ modules in 82599 adapters. Specifically issues have been seen in which both the SFP configuration and the multi-speed fiber configuration are running simultaneously which will result in the device getting into an erroneous link down state. Signed-off-by: Alexander Duyck Tested-by: Evan Swanson Signed-off-by: Jeff Kirsher diff --git a/drivers/net/ixgbe/ixgbe.h b/drivers/net/ixgbe/ixgbe.h index ec948ff..cbb04ba 100644 --- a/drivers/net/ixgbe/ixgbe.h +++ b/drivers/net/ixgbe/ixgbe.h @@ -367,19 +367,20 @@ struct ixgbe_adapter { #define IXGBE_FLAG_VMDQ_ENABLED (u32)(1 << 19) #define IXGBE_FLAG_FAN_FAIL_CAPABLE (u32)(1 << 20) #define IXGBE_FLAG_NEED_LINK_UPDATE (u32)(1 << 22) -#define IXGBE_FLAG_IN_SFP_LINK_TASK (u32)(1 << 23) -#define IXGBE_FLAG_IN_SFP_MOD_TASK (u32)(1 << 24) -#define IXGBE_FLAG_FDIR_HASH_CAPABLE (u32)(1 << 25) -#define IXGBE_FLAG_FDIR_PERFECT_CAPABLE (u32)(1 << 26) -#define IXGBE_FLAG_FCOE_CAPABLE (u32)(1 << 27) -#define IXGBE_FLAG_FCOE_ENABLED (u32)(1 << 28) -#define IXGBE_FLAG_SRIOV_CAPABLE (u32)(1 << 29) -#define IXGBE_FLAG_SRIOV_ENABLED (u32)(1 << 30) +#define IXGBE_FLAG_NEED_LINK_CONFIG (u32)(1 << 23) +#define IXGBE_FLAG_FDIR_HASH_CAPABLE (u32)(1 << 24) +#define IXGBE_FLAG_FDIR_PERFECT_CAPABLE (u32)(1 << 25) +#define IXGBE_FLAG_FCOE_CAPABLE (u32)(1 << 26) +#define IXGBE_FLAG_FCOE_ENABLED (u32)(1 << 27) +#define IXGBE_FLAG_SRIOV_CAPABLE (u32)(1 << 28) +#define IXGBE_FLAG_SRIOV_ENABLED (u32)(1 << 29) u32 flags2; #define IXGBE_FLAG2_RSC_CAPABLE (u32)(1) #define IXGBE_FLAG2_RSC_ENABLED (u32)(1 << 1) #define IXGBE_FLAG2_TEMP_SENSOR_CAPABLE (u32)(1 << 2) +#define IXGBE_FLAG2_SEARCH_FOR_SFP (u32)(1 << 4) +#define IXGBE_FLAG2_SFP_NEEDS_RESET (u32)(1 << 5) unsigned long active_vlans[BITS_TO_LONGS(VLAN_N_VID)]; u16 bd_number; @@ -455,13 +456,11 @@ struct ixgbe_adapter { struct work_struct reset_task; struct work_struct watchdog_task; - struct work_struct sfp_task; - struct work_struct multispeed_fiber_task; - struct work_struct sfp_config_module_task; struct work_struct fdir_reinit_task; struct work_struct check_overtemp_task; + struct work_struct service_task; struct timer_list watchdog_timer; - struct timer_list sfp_timer; + struct timer_list service_timer; u32 fdir_pballoc; u32 atr_sample_rate; spinlock_t fdir_perfect_lock; @@ -492,7 +491,8 @@ enum ixbge_state_t { __IXGBE_TESTING, __IXGBE_RESETTING, __IXGBE_DOWN, - __IXGBE_SFP_MODULE_NOT_FOUND + __IXGBE_SERVICE_SCHED, + __IXGBE_IN_SFP_INIT, }; struct ixgbe_rsc_cb { diff --git a/drivers/net/ixgbe/ixgbe_main.c b/drivers/net/ixgbe/ixgbe_main.c index f8196e0..a5d4226 100644 --- a/drivers/net/ixgbe/ixgbe_main.c +++ b/drivers/net/ixgbe/ixgbe_main.c @@ -191,6 +191,22 @@ static inline void ixgbe_disable_sriov(struct ixgbe_adapter *adapter) adapter->flags &= ~IXGBE_FLAG_SRIOV_ENABLED; } +static void ixgbe_service_event_schedule(struct ixgbe_adapter *adapter) +{ + if (!test_bit(__IXGBE_DOWN, &adapter->state) && + !test_and_set_bit(__IXGBE_SERVICE_SCHED, &adapter->state)) + schedule_work(&adapter->service_task); +} + +static void ixgbe_service_event_complete(struct ixgbe_adapter *adapter) +{ + BUG_ON(!test_bit(__IXGBE_SERVICE_SCHED, &adapter->state)); + + /* flush memory to make sure state is correct before next watchog */ + smp_mb__before_clear_bit(); + clear_bit(__IXGBE_SERVICE_SCHED, &adapter->state); +} + struct ixgbe_reg_info { u32 ofs; char *name; @@ -1858,15 +1874,19 @@ static void ixgbe_check_sfp_event(struct ixgbe_adapter *adapter, u32 eicr) if (eicr & IXGBE_EICR_GPI_SDP2) { /* Clear the interrupt */ IXGBE_WRITE_REG(hw, IXGBE_EICR, IXGBE_EICR_GPI_SDP2); - if (!test_bit(__IXGBE_DOWN, &adapter->state)) - schedule_work(&adapter->sfp_config_module_task); + if (!test_bit(__IXGBE_DOWN, &adapter->state)) { + adapter->flags2 |= IXGBE_FLAG2_SFP_NEEDS_RESET; + ixgbe_service_event_schedule(adapter); + } } if (eicr & IXGBE_EICR_GPI_SDP1) { /* Clear the interrupt */ IXGBE_WRITE_REG(hw, IXGBE_EICR, IXGBE_EICR_GPI_SDP1); - if (!test_bit(__IXGBE_DOWN, &adapter->state)) - schedule_work(&adapter->multispeed_fiber_task); + if (!test_bit(__IXGBE_DOWN, &adapter->state)) { + adapter->flags |= IXGBE_FLAG_NEED_LINK_CONFIG; + ixgbe_service_event_schedule(adapter); + } } } @@ -1937,8 +1957,10 @@ static irqreturn_t ixgbe_msix_lsc(int irq, void *data) ixgbe_check_fan_failure(adapter, eicr); + /* re-enable the original interrupt state, no lsc, no queues */ if (!test_bit(__IXGBE_DOWN, &adapter->state)) - IXGBE_WRITE_REG(hw, IXGBE_EIMS, IXGBE_EIMS_OTHER); + IXGBE_WRITE_REG(hw, IXGBE_EIMS, eicr & + ~(IXGBE_EIMS_LSC | IXGBE_EIMS_RTX_QUEUE)); return IRQ_HANDLED; } @@ -3772,31 +3794,16 @@ static inline bool ixgbe_is_sfp(struct ixgbe_hw *hw) **/ static void ixgbe_sfp_link_config(struct ixgbe_adapter *adapter) { - struct ixgbe_hw *hw = &adapter->hw; + /* + * We are assuming the worst case scenerio here, and that + * is that an SFP was inserted/removed after the reset + * but before SFP detection was enabled. As such the best + * solution is to just start searching as soon as we start + */ + if (adapter->hw.mac.type == ixgbe_mac_82598EB) + adapter->flags2 |= IXGBE_FLAG2_SEARCH_FOR_SFP; - if (hw->phy.multispeed_fiber) { - /* - * In multispeed fiber setups, the device may not have - * had a physical connection when the driver loaded. - * If that's the case, the initial link configuration - * couldn't get the MAC into 10G or 1G mode, so we'll - * never have a link status change interrupt fire. - * We need to try and force an autonegotiation - * session, then bring up link. - */ - if (hw->mac.ops.setup_sfp) - hw->mac.ops.setup_sfp(hw); - if (!(adapter->flags & IXGBE_FLAG_IN_SFP_LINK_TASK)) - schedule_work(&adapter->multispeed_fiber_task); - } else { - /* - * Direct Attach Cu and non-multispeed fiber modules - * still need to be configured properly prior to - * attempting link. - */ - if (!(adapter->flags & IXGBE_FLAG_IN_SFP_MOD_TASK)) - schedule_work(&adapter->sfp_config_module_task); - } + adapter->flags2 |= IXGBE_FLAG2_SFP_NEEDS_RESET; } /** @@ -3926,17 +3933,6 @@ static int ixgbe_up_complete(struct ixgbe_adapter *adapter) e_crit(drv, "Fan has stopped, replace the adapter\n"); } - /* - * For hot-pluggable SFP+ devices, a new SFP+ module may have - * arrived before interrupts were enabled but after probe. Such - * devices wouldn't have their type identified yet. We need to - * kick off the SFP+ module setup first, then try to bring up link. - * If we're not hot-pluggable SFP+, we just need to configure link - * and bring it up. - */ - if (hw->phy.type == ixgbe_phy_none) - schedule_work(&adapter->sfp_config_module_task); - /* enable transmits */ netif_tx_start_all_queues(adapter->netdev); @@ -3945,6 +3941,7 @@ static int ixgbe_up_complete(struct ixgbe_adapter *adapter) adapter->flags |= IXGBE_FLAG_NEED_LINK_UPDATE; adapter->link_check_timeout = jiffies; mod_timer(&adapter->watchdog_timer, jiffies); + mod_timer(&adapter->service_timer, jiffies); /* Set PF Reset Done bit so PF/VF Mail Ops can work */ ctrl_ext = IXGBE_READ_REG(hw, IXGBE_CTRL_EXT); @@ -3957,6 +3954,9 @@ static int ixgbe_up_complete(struct ixgbe_adapter *adapter) void ixgbe_reinit_locked(struct ixgbe_adapter *adapter) { WARN_ON(in_interrupt()); + /* put off any impending NetWatchDogTimeout */ + adapter->netdev->trans_start = jiffies; + while (test_and_set_bit(__IXGBE_RESETTING, &adapter->state)) usleep_range(1000, 2000); ixgbe_down(adapter); @@ -3985,10 +3985,20 @@ void ixgbe_reset(struct ixgbe_adapter *adapter) struct ixgbe_hw *hw = &adapter->hw; int err; + /* lock SFP init bit to prevent race conditions with the watchdog */ + while (test_and_set_bit(__IXGBE_IN_SFP_INIT, &adapter->state)) + usleep_range(1000, 2000); + + /* clear all SFP and link config related flags while holding SFP_INIT */ + adapter->flags2 &= ~(IXGBE_FLAG2_SEARCH_FOR_SFP | + IXGBE_FLAG2_SFP_NEEDS_RESET); + adapter->flags &= ~IXGBE_FLAG_NEED_LINK_CONFIG; + err = hw->mac.ops.init_hw(hw); switch (err) { case 0: case IXGBE_ERR_SFP_NOT_PRESENT: + case IXGBE_ERR_SFP_NOT_SUPPORTED: break; case IXGBE_ERR_MASTER_REQUESTS_PENDING: e_dev_err("master disable timed out\n"); @@ -4006,6 +4016,8 @@ void ixgbe_reset(struct ixgbe_adapter *adapter) e_dev_err("Hardware Error: %d\n", err); } + clear_bit(__IXGBE_IN_SFP_INIT, &adapter->state); + /* reprogram the RAR[0] in case user changed it. */ hw->mac.ops.set_rar(hw, 0, hw->mac.addr, adapter->num_vfs, IXGBE_RAH_AV); @@ -4167,11 +4179,9 @@ void ixgbe_down(struct ixgbe_adapter *adapter) netif_tx_stop_all_queues(netdev); - clear_bit(__IXGBE_SFP_MODULE_NOT_FOUND, &adapter->state); - del_timer_sync(&adapter->sfp_timer); del_timer_sync(&adapter->watchdog_timer); cancel_work_sync(&adapter->watchdog_task); - + /* call carrier off first to avoid false dev_watchdog timeouts */ netif_carrier_off(netdev); netif_tx_disable(netdev); @@ -4179,6 +4189,10 @@ void ixgbe_down(struct ixgbe_adapter *adapter) ixgbe_napi_disable_all(adapter); + adapter->flags &= ~IXGBE_FLAG_NEED_LINK_UPDATE; + + del_timer_sync(&adapter->service_timer); + /* Cleanup the affinity_hint CPU mask memory and callback */ for (i = 0; i < num_q_vectors; i++) { struct ixgbe_q_vector *q_vector = adapter->q_vector[i]; @@ -5148,57 +5162,6 @@ void ixgbe_clear_interrupt_scheme(struct ixgbe_adapter *adapter) } /** - * ixgbe_sfp_timer - worker thread to find a missing module - * @data: pointer to our adapter struct - **/ -static void ixgbe_sfp_timer(unsigned long data) -{ - struct ixgbe_adapter *adapter = (struct ixgbe_adapter *)data; - - /* - * Do the sfp_timer outside of interrupt context due to the - * delays that sfp+ detection requires - */ - schedule_work(&adapter->sfp_task); -} - -/** - * ixgbe_sfp_task - worker thread to find a missing module - * @work: pointer to work_struct containing our data - **/ -static void ixgbe_sfp_task(struct work_struct *work) -{ - struct ixgbe_adapter *adapter = container_of(work, - struct ixgbe_adapter, - sfp_task); - struct ixgbe_hw *hw = &adapter->hw; - - if ((hw->phy.type == ixgbe_phy_nl) && - (hw->phy.sfp_type == ixgbe_sfp_type_not_present)) { - s32 ret = hw->phy.ops.identify_sfp(hw); - if (ret == IXGBE_ERR_SFP_NOT_PRESENT) - goto reschedule; - ret = hw->phy.ops.reset(hw); - if (ret == IXGBE_ERR_SFP_NOT_SUPPORTED) { - e_dev_err("failed to initialize because an unsupported " - "SFP+ module type was detected.\n"); - e_dev_err("Reload the driver after installing a " - "supported module.\n"); - unregister_netdev(adapter->netdev); - } else { - e_info(probe, "detected SFP+: %d\n", hw->phy.sfp_type); - } - /* don't need this routine any more */ - clear_bit(__IXGBE_SFP_MODULE_NOT_FOUND, &adapter->state); - } - return; -reschedule: - if (test_bit(__IXGBE_SFP_MODULE_NOT_FOUND, &adapter->state)) - mod_timer(&adapter->sfp_timer, - round_jiffies(jiffies + (2 * HZ))); -} - -/** * ixgbe_sw_init - Initialize general software structures (struct ixgbe_adapter) * @adapter: board private structure to initialize * @@ -6042,65 +6005,6 @@ watchdog_short_circuit: } /** - * ixgbe_multispeed_fiber_task - worker thread to configure multispeed fiber - * @work: pointer to work_struct containing our data - **/ -static void ixgbe_multispeed_fiber_task(struct work_struct *work) -{ - struct ixgbe_adapter *adapter = container_of(work, - struct ixgbe_adapter, - multispeed_fiber_task); - struct ixgbe_hw *hw = &adapter->hw; - u32 autoneg; - bool negotiation; - - adapter->flags |= IXGBE_FLAG_IN_SFP_LINK_TASK; - autoneg = hw->phy.autoneg_advertised; - if ((!autoneg) && (hw->mac.ops.get_link_capabilities)) - hw->mac.ops.get_link_capabilities(hw, &autoneg, &negotiation); - hw->mac.autotry_restart = false; - if (hw->mac.ops.setup_link) - hw->mac.ops.setup_link(hw, autoneg, negotiation, true); - adapter->flags |= IXGBE_FLAG_NEED_LINK_UPDATE; - adapter->flags &= ~IXGBE_FLAG_IN_SFP_LINK_TASK; -} - -/** - * ixgbe_sfp_config_module_task - worker thread to configure a new SFP+ module - * @work: pointer to work_struct containing our data - **/ -static void ixgbe_sfp_config_module_task(struct work_struct *work) -{ - struct ixgbe_adapter *adapter = container_of(work, - struct ixgbe_adapter, - sfp_config_module_task); - struct ixgbe_hw *hw = &adapter->hw; - u32 err; - - adapter->flags |= IXGBE_FLAG_IN_SFP_MOD_TASK; - - /* Time for electrical oscillations to settle down */ - msleep(100); - err = hw->phy.ops.identify_sfp(hw); - - if (err == IXGBE_ERR_SFP_NOT_SUPPORTED) { - e_dev_err("failed to initialize because an unsupported SFP+ " - "module type was detected.\n"); - e_dev_err("Reload the driver after installing a supported " - "module.\n"); - unregister_netdev(adapter->netdev); - return; - } - if (hw->mac.ops.setup_sfp) - hw->mac.ops.setup_sfp(hw); - - if (!(adapter->flags & IXGBE_FLAG_IN_SFP_LINK_TASK)) - /* This will also work for DA Twinax connections */ - schedule_work(&adapter->multispeed_fiber_task); - adapter->flags &= ~IXGBE_FLAG_IN_SFP_MOD_TASK; -} - -/** * ixgbe_fdir_reinit_task - worker thread to reinit FDIR filter table * @work: pointer to work_struct containing our data **/ @@ -6273,6 +6177,141 @@ static void ixgbe_watchdog_task(struct work_struct *work) mutex_unlock(&ixgbe_watchdog_lock); } +/** + * ixgbe_sfp_detection_subtask - poll for SFP+ cable + * @adapter - the ixgbe adapter structure + **/ +static void ixgbe_sfp_detection_subtask(struct ixgbe_adapter *adapter) +{ + struct ixgbe_hw *hw = &adapter->hw; + s32 err; + + /* not searching for SFP so there is nothing to do here */ + if (!(adapter->flags2 & IXGBE_FLAG2_SEARCH_FOR_SFP) && + !(adapter->flags2 & IXGBE_FLAG2_SFP_NEEDS_RESET)) + return; + + /* someone else is in init, wait until next service event */ + if (test_and_set_bit(__IXGBE_IN_SFP_INIT, &adapter->state)) + return; + + err = hw->phy.ops.identify_sfp(hw); + if (err == IXGBE_ERR_SFP_NOT_SUPPORTED) + goto sfp_out; + + if (err == IXGBE_ERR_SFP_NOT_PRESENT) { + /* If no cable is present, then we need to reset + * the next time we find a good cable. */ + adapter->flags2 |= IXGBE_FLAG2_SFP_NEEDS_RESET; + } + + /* exit on error */ + if (err) + goto sfp_out; + + /* exit if reset not needed */ + if (!(adapter->flags2 & IXGBE_FLAG2_SFP_NEEDS_RESET)) + goto sfp_out; + + adapter->flags2 &= ~IXGBE_FLAG2_SFP_NEEDS_RESET; + + /* + * A module may be identified correctly, but the EEPROM may not have + * support for that module. setup_sfp() will fail in that case, so + * we should not allow that module to load. + */ + if (hw->mac.type == ixgbe_mac_82598EB) + err = hw->phy.ops.reset(hw); + else + err = hw->mac.ops.setup_sfp(hw); + + if (err == IXGBE_ERR_SFP_NOT_SUPPORTED) + goto sfp_out; + + adapter->flags |= IXGBE_FLAG_NEED_LINK_CONFIG; + e_info(probe, "detected SFP+: %d\n", hw->phy.sfp_type); + +sfp_out: + clear_bit(__IXGBE_IN_SFP_INIT, &adapter->state); + + if ((err == IXGBE_ERR_SFP_NOT_SUPPORTED) && + (adapter->netdev->reg_state == NETREG_REGISTERED)) { + e_dev_err("failed to initialize because an unsupported " + "SFP+ module type was detected.\n"); + e_dev_err("Reload the driver after installing a " + "supported module.\n"); + unregister_netdev(adapter->netdev); + } +} + +/** + * ixgbe_sfp_link_config_subtask - set up link SFP after module install + * @adapter - the ixgbe adapter structure + **/ +static void ixgbe_sfp_link_config_subtask(struct ixgbe_adapter *adapter) +{ + struct ixgbe_hw *hw = &adapter->hw; + u32 autoneg; + bool negotiation; + + if (!(adapter->flags & IXGBE_FLAG_NEED_LINK_CONFIG)) + return; + + /* someone else is in init, wait until next service event */ + if (test_and_set_bit(__IXGBE_IN_SFP_INIT, &adapter->state)) + return; + + adapter->flags &= ~IXGBE_FLAG_NEED_LINK_CONFIG; + + autoneg = hw->phy.autoneg_advertised; + if ((!autoneg) && (hw->mac.ops.get_link_capabilities)) + hw->mac.ops.get_link_capabilities(hw, &autoneg, &negotiation); + hw->mac.autotry_restart = false; + if (hw->mac.ops.setup_link) + hw->mac.ops.setup_link(hw, autoneg, negotiation, true); + + adapter->flags |= IXGBE_FLAG_NEED_LINK_UPDATE; + adapter->link_check_timeout = jiffies; + clear_bit(__IXGBE_IN_SFP_INIT, &adapter->state); +} + +/** + * ixgbe_service_timer - Timer Call-back + * @data: pointer to adapter cast into an unsigned long + **/ +static void ixgbe_service_timer(unsigned long data) +{ + struct ixgbe_adapter *adapter = (struct ixgbe_adapter *)data; + unsigned long next_event_offset; + + /* poll faster when waiting for link */ + if (adapter->flags & IXGBE_FLAG_NEED_LINK_UPDATE) + next_event_offset = HZ / 10; + else + next_event_offset = HZ * 2; + + /* Reset the timer */ + mod_timer(&adapter->service_timer, next_event_offset + jiffies); + + ixgbe_service_event_schedule(adapter); +} + +/** + * ixgbe_service_task - manages and runs subtasks + * @work: pointer to work_struct containing our data + **/ +static void ixgbe_service_task(struct work_struct *work) +{ + struct ixgbe_adapter *adapter = container_of(work, + struct ixgbe_adapter, + service_task); + + ixgbe_sfp_detection_subtask(adapter); + ixgbe_sfp_link_config_subtask(adapter); + + ixgbe_service_event_complete(adapter); +} + static int ixgbe_tso(struct ixgbe_adapter *adapter, struct ixgbe_ring *tx_ring, struct sk_buff *skb, u32 tx_flags, u8 *hdr_len, __be16 protocol) @@ -7317,22 +7356,6 @@ static int __devinit ixgbe_probe(struct pci_dev *pdev, hw->phy.mdio.mdio_read = ixgbe_mdio_read; hw->phy.mdio.mdio_write = ixgbe_mdio_write; - /* set up this timer and work struct before calling get_invariants - * which might start the timer - */ - init_timer(&adapter->sfp_timer); - adapter->sfp_timer.function = ixgbe_sfp_timer; - adapter->sfp_timer.data = (unsigned long) adapter; - - INIT_WORK(&adapter->sfp_task, ixgbe_sfp_task); - - /* multispeed fiber has its own tasklet, called from GPI SDP1 context */ - INIT_WORK(&adapter->multispeed_fiber_task, ixgbe_multispeed_fiber_task); - - /* a new SFP+ module arrival, called from GPI SDP2 context */ - INIT_WORK(&adapter->sfp_config_module_task, - ixgbe_sfp_config_module_task); - ii->get_invariants(hw); /* setup the private structure */ @@ -7366,17 +7389,9 @@ static int __devinit ixgbe_probe(struct pci_dev *pdev, hw->phy.reset_if_overtemp = false; if (err == IXGBE_ERR_SFP_NOT_PRESENT && hw->mac.type == ixgbe_mac_82598EB) { - /* - * Start a kernel thread to watch for a module to arrive. - * Only do this for 82598, since 82599 will generate - * interrupts on module arrival. - */ - set_bit(__IXGBE_SFP_MODULE_NOT_FOUND, &adapter->state); - mod_timer(&adapter->sfp_timer, - round_jiffies(jiffies + (2 * HZ))); err = 0; } else if (err == IXGBE_ERR_SFP_NOT_SUPPORTED) { - e_dev_err("failed to initialize because an unsupported SFP+ " + e_dev_err("failed to load because an unsupported SFP+ " "module type was detected.\n"); e_dev_err("Reload the driver after installing a supported " "module.\n"); @@ -7468,6 +7483,8 @@ static int __devinit ixgbe_probe(struct pci_dev *pdev, (hw->mac.type == ixgbe_mac_82599EB)))) hw->mac.ops.disable_tx_laser(hw); + setup_timer(&adapter->service_timer, &ixgbe_service_timer, + (unsigned long) adapter); init_timer(&adapter->watchdog_timer); adapter->watchdog_timer.function = ixgbe_watchdog; adapter->watchdog_timer.data = (unsigned long)adapter; @@ -7475,6 +7492,9 @@ static int __devinit ixgbe_probe(struct pci_dev *pdev, INIT_WORK(&adapter->reset_task, ixgbe_reset_task); INIT_WORK(&adapter->watchdog_task, ixgbe_watchdog_task); + INIT_WORK(&adapter->service_task, ixgbe_service_task); + clear_bit(__IXGBE_SERVICE_SCHED, &adapter->state); + err = ixgbe_init_interrupt_scheme(adapter); if (err) goto err_sw_init; @@ -7593,11 +7613,7 @@ err_sw_init: err_eeprom: if (adapter->flags & IXGBE_FLAG_SRIOV_ENABLED) ixgbe_disable_sriov(adapter); - clear_bit(__IXGBE_SFP_MODULE_NOT_FOUND, &adapter->state); - del_timer_sync(&adapter->sfp_timer); - cancel_work_sync(&adapter->sfp_task); - cancel_work_sync(&adapter->multispeed_fiber_task); - cancel_work_sync(&adapter->sfp_config_module_task); + adapter->flags2 &= ~IXGBE_FLAG2_SEARCH_FOR_SFP; iounmap(hw->hw_addr); err_ioremap: free_netdev(netdev); @@ -7625,19 +7641,15 @@ static void __devexit ixgbe_remove(struct pci_dev *pdev) struct net_device *netdev = adapter->netdev; set_bit(__IXGBE_DOWN, &adapter->state); + cancel_work_sync(&adapter->service_task); /* * The timers may be rescheduled, so explicitly disable them * from being rescheduled. */ - clear_bit(__IXGBE_SFP_MODULE_NOT_FOUND, &adapter->state); del_timer_sync(&adapter->watchdog_timer); - del_timer_sync(&adapter->sfp_timer); cancel_work_sync(&adapter->watchdog_task); - cancel_work_sync(&adapter->sfp_task); - cancel_work_sync(&adapter->multispeed_fiber_task); - cancel_work_sync(&adapter->sfp_config_module_task); if (adapter->flags & IXGBE_FLAG_FDIR_HASH_CAPABLE || adapter->flags & IXGBE_FLAG_FDIR_PERFECT_CAPABLE) cancel_work_sync(&adapter->fdir_reinit_task); -- cgit v0.10.2 From 93c52dd0033be3cb91376916b8461fcb94ef0c22 Mon Sep 17 00:00:00 2001 From: Alexander Duyck Date: Fri, 22 Apr 2011 04:07:54 +0000 Subject: ixgbe: Merge watchdog functionality into service task This patch is meant to merge the functionality of the ixgbe watchdog task into the service task. By doing this all link state functionality will be controlled by a single task. As a result the reliability of the interface will be improved as the likelihood of any race conditions is further reduced. Signed-off-by: Alexander Duyck Signed-off-by: Jeff Kirsher diff --git a/drivers/net/ixgbe/ixgbe.h b/drivers/net/ixgbe/ixgbe.h index cbb04ba..193c6c4 100644 --- a/drivers/net/ixgbe/ixgbe.h +++ b/drivers/net/ixgbe/ixgbe.h @@ -455,11 +455,9 @@ struct ixgbe_adapter { unsigned long link_check_timeout; struct work_struct reset_task; - struct work_struct watchdog_task; struct work_struct fdir_reinit_task; struct work_struct check_overtemp_task; struct work_struct service_task; - struct timer_list watchdog_timer; struct timer_list service_timer; u32 fdir_pballoc; u32 atr_sample_rate; diff --git a/drivers/net/ixgbe/ixgbe_main.c b/drivers/net/ixgbe/ixgbe_main.c index a5d4226..d1e52b5 100644 --- a/drivers/net/ixgbe/ixgbe_main.c +++ b/drivers/net/ixgbe/ixgbe_main.c @@ -1900,7 +1900,7 @@ static void ixgbe_check_lsc(struct ixgbe_adapter *adapter) if (!test_bit(__IXGBE_DOWN, &adapter->state)) { IXGBE_WRITE_REG(hw, IXGBE_EIMC, IXGBE_EIMC_LSC); IXGBE_WRITE_FLUSH(hw); - schedule_work(&adapter->watchdog_task); + ixgbe_service_event_schedule(adapter); } } @@ -3940,7 +3940,6 @@ static int ixgbe_up_complete(struct ixgbe_adapter *adapter) * link up interrupt but shouldn't be a problem */ adapter->flags |= IXGBE_FLAG_NEED_LINK_UPDATE; adapter->link_check_timeout = jiffies; - mod_timer(&adapter->watchdog_timer, jiffies); mod_timer(&adapter->service_timer, jiffies); /* Set PF Reset Done bit so PF/VF Mail Ops can work */ @@ -4179,8 +4178,6 @@ void ixgbe_down(struct ixgbe_adapter *adapter) netif_tx_stop_all_queues(netdev); - del_timer_sync(&adapter->watchdog_timer); - cancel_work_sync(&adapter->watchdog_task); /* call carrier off first to avoid false dev_watchdog timeouts */ netif_carrier_off(netdev); netif_tx_disable(netdev); @@ -5957,23 +5954,54 @@ void ixgbe_update_stats(struct ixgbe_adapter *adapter) } /** - * ixgbe_watchdog - Timer Call-back - * @data: pointer to adapter cast into an unsigned long + * ixgbe_fdir_reinit_task - worker thread to reinit FDIR filter table + * @work: pointer to work_struct containing our data **/ -static void ixgbe_watchdog(unsigned long data) +static void ixgbe_fdir_reinit_task(struct work_struct *work) +{ + struct ixgbe_adapter *adapter = container_of(work, + struct ixgbe_adapter, + fdir_reinit_task); + struct ixgbe_hw *hw = &adapter->hw; + int i; + + if (ixgbe_reinit_fdir_tables_82599(hw) == 0) { + for (i = 0; i < adapter->num_tx_queues; i++) + set_bit(__IXGBE_TX_FDIR_INIT_DONE, + &(adapter->tx_ring[i]->state)); + } else { + e_err(probe, "failed to finish FDIR re-initialization, " + "ignored adding FDIR ATR filters\n"); + } + /* Done FDIR Re-initialization, enable transmits */ + netif_tx_start_all_queues(adapter->netdev); +} + +/** + * ixgbe_check_hang_subtask - check for hung queues and dropped interrupts + * @adapter - pointer to the device adapter structure + * + * This function serves two purposes. First it strobes the interrupt lines + * in order to make certain interrupts are occuring. Secondly it sets the + * bits needed to check for TX hangs. As a result we should immediately + * determine if a hang has occured. + */ +static void ixgbe_check_hang_subtask(struct ixgbe_adapter *adapter) { - struct ixgbe_adapter *adapter = (struct ixgbe_adapter *)data; struct ixgbe_hw *hw = &adapter->hw; u64 eics = 0; int i; - /* - * Do the watchdog outside of interrupt context due to the lovely - * delays that some of the newer hardware requires - */ + /* If we're down or resetting, just bail */ + if (test_bit(__IXGBE_DOWN, &adapter->state) || + test_bit(__IXGBE_RESETTING, &adapter->state)) + return; - if (test_bit(__IXGBE_DOWN, &adapter->state)) - goto watchdog_short_circuit; + /* Force detection of hung controller */ + if (netif_carrier_ok(adapter->netdev)) { + for (i = 0; i < adapter->num_tx_queues; i++) + set_check_for_tx_hang(adapter->tx_ring[i]); + } if (!(adapter->flags & IXGBE_FLAG_MSIX_ENABLED)) { /* @@ -5983,179 +6011,157 @@ static void ixgbe_watchdog(unsigned long data) */ IXGBE_WRITE_REG(hw, IXGBE_EICS, (IXGBE_EICS_TCP_TIMER | IXGBE_EICS_OTHER)); - goto watchdog_reschedule; - } - - /* get one bit for every active tx/rx interrupt vector */ - for (i = 0; i < adapter->num_msix_vectors - NON_Q_VECTORS; i++) { - struct ixgbe_q_vector *qv = adapter->q_vector[i]; - if (qv->rxr_count || qv->txr_count) - eics |= ((u64)1 << i); + } else { + /* get one bit for every active tx/rx interrupt vector */ + for (i = 0; i < adapter->num_msix_vectors - NON_Q_VECTORS; i++) { + struct ixgbe_q_vector *qv = adapter->q_vector[i]; + if (qv->rxr_count || qv->txr_count) + eics |= ((u64)1 << i); + } } - /* Cause software interrupt to ensure rx rings are cleaned */ + /* Cause software interrupt to ensure rings are cleaned */ ixgbe_irq_rearm_queues(adapter, eics); -watchdog_reschedule: - /* Reset the timer */ - mod_timer(&adapter->watchdog_timer, round_jiffies(jiffies + 2 * HZ)); - -watchdog_short_circuit: - schedule_work(&adapter->watchdog_task); } /** - * ixgbe_fdir_reinit_task - worker thread to reinit FDIR filter table - * @work: pointer to work_struct containing our data + * ixgbe_watchdog_update_link - update the link status + * @adapter - pointer to the device adapter structure + * @link_speed - pointer to a u32 to store the link_speed **/ -static void ixgbe_fdir_reinit_task(struct work_struct *work) +static void ixgbe_watchdog_update_link(struct ixgbe_adapter *adapter) { - struct ixgbe_adapter *adapter = container_of(work, - struct ixgbe_adapter, - fdir_reinit_task); struct ixgbe_hw *hw = &adapter->hw; + u32 link_speed = adapter->link_speed; + bool link_up = adapter->link_up; int i; - if (ixgbe_reinit_fdir_tables_82599(hw) == 0) { - for (i = 0; i < adapter->num_tx_queues; i++) - set_bit(__IXGBE_TX_FDIR_INIT_DONE, - &(adapter->tx_ring[i]->state)); + if (!(adapter->flags & IXGBE_FLAG_NEED_LINK_UPDATE)) + return; + + if (hw->mac.ops.check_link) { + hw->mac.ops.check_link(hw, &link_speed, &link_up, false); } else { - e_err(probe, "failed to finish FDIR re-initialization, " - "ignored adding FDIR ATR filters\n"); + /* always assume link is up, if no check link function */ + link_speed = IXGBE_LINK_SPEED_10GB_FULL; + link_up = true; } - /* Done FDIR Re-initialization, enable transmits */ - netif_tx_start_all_queues(adapter->netdev); + if (link_up) { + if (adapter->flags & IXGBE_FLAG_DCB_ENABLED) { + for (i = 0; i < MAX_TRAFFIC_CLASS; i++) + hw->mac.ops.fc_enable(hw, i); + } else { + hw->mac.ops.fc_enable(hw, 0); + } + } + + if (link_up || + time_after(jiffies, (adapter->link_check_timeout + + IXGBE_TRY_LINK_TIMEOUT))) { + adapter->flags &= ~IXGBE_FLAG_NEED_LINK_UPDATE; + IXGBE_WRITE_REG(hw, IXGBE_EIMS, IXGBE_EIMC_LSC); + IXGBE_WRITE_FLUSH(hw); + } + + adapter->link_up = link_up; + adapter->link_speed = link_speed; } -static void ixgbe_spoof_check(struct ixgbe_adapter *adapter) +/** + * ixgbe_watchdog_link_is_up - update netif_carrier status and + * print link up message + * @adapter - pointer to the device adapter structure + **/ +static void ixgbe_watchdog_link_is_up(struct ixgbe_adapter *adapter) { - u32 ssvpc; + struct net_device *netdev = adapter->netdev; + struct ixgbe_hw *hw = &adapter->hw; + u32 link_speed = adapter->link_speed; + bool flow_rx, flow_tx; - /* Do not perform spoof check for 82598 */ - if (adapter->hw.mac.type == ixgbe_mac_82598EB) + /* only continue if link was previously down */ + if (netif_carrier_ok(netdev)) return; - ssvpc = IXGBE_READ_REG(&adapter->hw, IXGBE_SSVPC); + adapter->flags2 &= ~IXGBE_FLAG2_SEARCH_FOR_SFP; - /* - * ssvpc register is cleared on read, if zero then no - * spoofed packets in the last interval. - */ - if (!ssvpc) - return; + switch (hw->mac.type) { + case ixgbe_mac_82598EB: { + u32 frctl = IXGBE_READ_REG(hw, IXGBE_FCTRL); + u32 rmcs = IXGBE_READ_REG(hw, IXGBE_RMCS); + flow_rx = !!(frctl & IXGBE_FCTRL_RFCE); + flow_tx = !!(rmcs & IXGBE_RMCS_TFCE_802_3X); + } + break; + case ixgbe_mac_X540: + case ixgbe_mac_82599EB: { + u32 mflcn = IXGBE_READ_REG(hw, IXGBE_MFLCN); + u32 fccfg = IXGBE_READ_REG(hw, IXGBE_FCCFG); + flow_rx = !!(mflcn & IXGBE_MFLCN_RFCE); + flow_tx = !!(fccfg & IXGBE_FCCFG_TFCE_802_3X); + } + break; + default: + flow_tx = false; + flow_rx = false; + break; + } + e_info(drv, "NIC Link is Up %s, Flow Control: %s\n", + (link_speed == IXGBE_LINK_SPEED_10GB_FULL ? + "10 Gbps" : + (link_speed == IXGBE_LINK_SPEED_1GB_FULL ? + "1 Gbps" : + (link_speed == IXGBE_LINK_SPEED_100_FULL ? + "100 Mbps" : + "unknown speed"))), + ((flow_rx && flow_tx) ? "RX/TX" : + (flow_rx ? "RX" : + (flow_tx ? "TX" : "None")))); - e_warn(drv, "%d Spoofed packets detected\n", ssvpc); + netif_carrier_on(netdev); +#ifdef HAVE_IPLINK_VF_CONFIG + ixgbe_check_vf_rate_limit(adapter); +#endif /* HAVE_IPLINK_VF_CONFIG */ } -static DEFINE_MUTEX(ixgbe_watchdog_lock); - /** - * ixgbe_watchdog_task - worker thread to bring link up - * @work: pointer to work_struct containing our data + * ixgbe_watchdog_link_is_down - update netif_carrier status and + * print link down message + * @adapter - pointer to the adapter structure **/ -static void ixgbe_watchdog_task(struct work_struct *work) +static void ixgbe_watchdog_link_is_down(struct ixgbe_adapter* adapter) { - struct ixgbe_adapter *adapter = container_of(work, - struct ixgbe_adapter, - watchdog_task); struct net_device *netdev = adapter->netdev; struct ixgbe_hw *hw = &adapter->hw; - u32 link_speed; - bool link_up; - int i; - struct ixgbe_ring *tx_ring; - int some_tx_pending = 0; - - mutex_lock(&ixgbe_watchdog_lock); - link_up = adapter->link_up; - link_speed = adapter->link_speed; + adapter->link_up = false; + adapter->link_speed = 0; - if (adapter->flags & IXGBE_FLAG_NEED_LINK_UPDATE) { - hw->mac.ops.check_link(hw, &link_speed, &link_up, false); - if (link_up) { -#ifdef CONFIG_DCB - if (adapter->flags & IXGBE_FLAG_DCB_ENABLED) { - for (i = 0; i < MAX_TRAFFIC_CLASS; i++) - hw->mac.ops.fc_enable(hw, i); - } else { - hw->mac.ops.fc_enable(hw, 0); - } -#else - hw->mac.ops.fc_enable(hw, 0); -#endif - } + /* only continue if link was up previously */ + if (!netif_carrier_ok(netdev)) + return; - if (link_up || - time_after(jiffies, (adapter->link_check_timeout + - IXGBE_TRY_LINK_TIMEOUT))) { - adapter->flags &= ~IXGBE_FLAG_NEED_LINK_UPDATE; - IXGBE_WRITE_REG(hw, IXGBE_EIMS, IXGBE_EIMC_LSC); - } - adapter->link_up = link_up; - adapter->link_speed = link_speed; - } + /* poll for SFP+ cable when link is down */ + if (ixgbe_is_sfp(hw) && hw->mac.type == ixgbe_mac_82598EB) + adapter->flags2 |= IXGBE_FLAG2_SEARCH_FOR_SFP; - if (link_up) { - if (!netif_carrier_ok(netdev)) { - bool flow_rx, flow_tx; - - switch (hw->mac.type) { - case ixgbe_mac_82598EB: { - u32 frctl = IXGBE_READ_REG(hw, IXGBE_FCTRL); - u32 rmcs = IXGBE_READ_REG(hw, IXGBE_RMCS); - flow_rx = !!(frctl & IXGBE_FCTRL_RFCE); - flow_tx = !!(rmcs & IXGBE_RMCS_TFCE_802_3X); - } - break; - case ixgbe_mac_82599EB: - case ixgbe_mac_X540: { - u32 mflcn = IXGBE_READ_REG(hw, IXGBE_MFLCN); - u32 fccfg = IXGBE_READ_REG(hw, IXGBE_FCCFG); - flow_rx = !!(mflcn & IXGBE_MFLCN_RFCE); - flow_tx = !!(fccfg & IXGBE_FCCFG_TFCE_802_3X); - } - break; - default: - flow_tx = false; - flow_rx = false; - break; - } + e_info(drv, "NIC Link is Down\n"); + netif_carrier_off(netdev); +} - e_info(drv, "NIC Link is Up %s, Flow Control: %s\n", - (link_speed == IXGBE_LINK_SPEED_10GB_FULL ? - "10 Gbps" : - (link_speed == IXGBE_LINK_SPEED_1GB_FULL ? - "1 Gbps" : - (link_speed == IXGBE_LINK_SPEED_100_FULL ? - "100 Mbps" : - "unknown speed"))), - ((flow_rx && flow_tx) ? "RX/TX" : - (flow_rx ? "RX" : - (flow_tx ? "TX" : "None")))); - - netif_carrier_on(netdev); - ixgbe_check_vf_rate_limit(adapter); - } else { - /* Force detection of hung controller */ - for (i = 0; i < adapter->num_tx_queues; i++) { - tx_ring = adapter->tx_ring[i]; - set_check_for_tx_hang(tx_ring); - } - } - } else { - adapter->link_up = false; - adapter->link_speed = 0; - if (netif_carrier_ok(netdev)) { - e_info(drv, "NIC Link is Down\n"); - netif_carrier_off(netdev); - } - } +/** + * ixgbe_watchdog_flush_tx - flush queues on link down + * @adapter - pointer to the device adapter structure + **/ +static void ixgbe_watchdog_flush_tx(struct ixgbe_adapter *adapter) +{ + int i; + int some_tx_pending = 0; - if (!netif_carrier_ok(netdev)) { + if (!netif_carrier_ok(adapter->netdev)) { for (i = 0; i < adapter->num_tx_queues; i++) { - tx_ring = adapter->tx_ring[i]; + struct ixgbe_ring *tx_ring = adapter->tx_ring[i]; if (tx_ring->next_to_use != tx_ring->next_to_clean) { some_tx_pending = 1; break; @@ -6168,13 +6174,52 @@ static void ixgbe_watchdog_task(struct work_struct *work) * to get done, so reset controller to flush Tx. * (Do the reset outside of interrupt context). */ - schedule_work(&adapter->reset_task); + schedule_work(&adapter->reset_task); } } +} + +static void ixgbe_spoof_check(struct ixgbe_adapter *adapter) +{ + u32 ssvpc; + + /* Do not perform spoof check for 82598 */ + if (adapter->hw.mac.type == ixgbe_mac_82598EB) + return; + + ssvpc = IXGBE_READ_REG(&adapter->hw, IXGBE_SSVPC); + + /* + * ssvpc register is cleared on read, if zero then no + * spoofed packets in the last interval. + */ + if (!ssvpc) + return; + + e_warn(drv, "%d Spoofed packets detected\n", ssvpc); +} + +/** + * ixgbe_watchdog_subtask - check and bring link up + * @adapter - pointer to the device adapter structure + **/ +static void ixgbe_watchdog_subtask(struct ixgbe_adapter *adapter) +{ + /* if interface is down do nothing */ + if (test_bit(__IXGBE_DOWN, &adapter->state)) + return; + + ixgbe_watchdog_update_link(adapter); + + if (adapter->link_up) + ixgbe_watchdog_link_is_up(adapter); + else + ixgbe_watchdog_link_is_down(adapter); ixgbe_spoof_check(adapter); ixgbe_update_stats(adapter); - mutex_unlock(&ixgbe_watchdog_lock); + + ixgbe_watchdog_flush_tx(adapter); } /** @@ -6308,6 +6353,8 @@ static void ixgbe_service_task(struct work_struct *work) ixgbe_sfp_detection_subtask(adapter); ixgbe_sfp_link_config_subtask(adapter); + ixgbe_watchdog_subtask(adapter); + ixgbe_check_hang_subtask(adapter); ixgbe_service_event_complete(adapter); } @@ -7485,12 +7532,8 @@ static int __devinit ixgbe_probe(struct pci_dev *pdev, setup_timer(&adapter->service_timer, &ixgbe_service_timer, (unsigned long) adapter); - init_timer(&adapter->watchdog_timer); - adapter->watchdog_timer.function = ixgbe_watchdog; - adapter->watchdog_timer.data = (unsigned long)adapter; INIT_WORK(&adapter->reset_task, ixgbe_reset_task); - INIT_WORK(&adapter->watchdog_task, ixgbe_watchdog_task); INIT_WORK(&adapter->service_task, ixgbe_service_task); clear_bit(__IXGBE_SERVICE_SCHED, &adapter->state); @@ -7643,13 +7686,6 @@ static void __devexit ixgbe_remove(struct pci_dev *pdev) set_bit(__IXGBE_DOWN, &adapter->state); cancel_work_sync(&adapter->service_task); - /* - * The timers may be rescheduled, so explicitly disable them - * from being rescheduled. - */ - del_timer_sync(&adapter->watchdog_timer); - - cancel_work_sync(&adapter->watchdog_task); if (adapter->flags & IXGBE_FLAG_FDIR_HASH_CAPABLE || adapter->flags & IXGBE_FLAG_FDIR_PERFECT_CAPABLE) cancel_work_sync(&adapter->fdir_reinit_task); -- cgit v0.10.2 From c83c6cbdbff360e5323748720dfb2b000c0ae491 Mon Sep 17 00:00:00 2001 From: Alexander Duyck Date: Wed, 27 Apr 2011 09:21:16 +0000 Subject: ixgbe: merge reset task into service task This change is meant to further help to reduce possible configuration collisions between the various tasklets. This change combines the device reset with the service task. As a result it is now not possible to be updating the link on the device while also resetting the part. Signed-off-by: Alexander Duyck Tested-by: Evan Swanson Signed-off-by: Jeff Kirsher diff --git a/drivers/net/ixgbe/ixgbe.h b/drivers/net/ixgbe/ixgbe.h index 193c6c4..760b850 100644 --- a/drivers/net/ixgbe/ixgbe.h +++ b/drivers/net/ixgbe/ixgbe.h @@ -381,6 +381,7 @@ struct ixgbe_adapter { #define IXGBE_FLAG2_TEMP_SENSOR_CAPABLE (u32)(1 << 2) #define IXGBE_FLAG2_SEARCH_FOR_SFP (u32)(1 << 4) #define IXGBE_FLAG2_SFP_NEEDS_RESET (u32)(1 << 5) +#define IXGBE_FLAG2_RESET_REQUESTED (u32)(1 << 6) unsigned long active_vlans[BITS_TO_LONGS(VLAN_N_VID)]; u16 bd_number; @@ -454,7 +455,6 @@ struct ixgbe_adapter { bool link_up; unsigned long link_check_timeout; - struct work_struct reset_task; struct work_struct fdir_reinit_task; struct work_struct check_overtemp_task; struct work_struct service_task; diff --git a/drivers/net/ixgbe/ixgbe_main.c b/drivers/net/ixgbe/ixgbe_main.c index d1e52b5..dbb20e5 100644 --- a/drivers/net/ixgbe/ixgbe_main.c +++ b/drivers/net/ixgbe/ixgbe_main.c @@ -833,7 +833,19 @@ static inline bool ixgbe_check_tx_hang(struct ixgbe_ring *tx_ring) #define DESC_NEEDED (TXD_USE_COUNT(IXGBE_MAX_DATA_PER_TXD) /* skb->data */ + \ MAX_SKB_FRAGS * TXD_USE_COUNT(PAGE_SIZE) + 1) /* for context */ -static void ixgbe_tx_timeout(struct net_device *netdev); +/** + * ixgbe_tx_timeout_reset - initiate reset due to Tx timeout + * @adapter: driver private struct + **/ +static void ixgbe_tx_timeout_reset(struct ixgbe_adapter *adapter) +{ + + /* Do the reset outside of interrupt context */ + if (!test_bit(__IXGBE_DOWN, &adapter->state)) { + adapter->flags2 |= IXGBE_FLAG2_RESET_REQUESTED; + ixgbe_service_event_schedule(adapter); + } +} /** * ixgbe_clean_tx_irq - Reclaim resources after transmit completes @@ -915,7 +927,7 @@ static bool ixgbe_clean_tx_irq(struct ixgbe_q_vector *q_vector, adapter->tx_timeout_count + 1, tx_ring->queue_index); /* schedule immediate reset if we believe we hung */ - ixgbe_tx_timeout(adapter->netdev); + ixgbe_tx_timeout_reset(adapter); /* the adapter is about to reset, no point in enabling stuff */ return true; @@ -4186,6 +4198,7 @@ void ixgbe_down(struct ixgbe_adapter *adapter) ixgbe_napi_disable_all(adapter); + adapter->flags2 &= ~IXGBE_FLAG2_RESET_REQUESTED; adapter->flags &= ~IXGBE_FLAG_NEED_LINK_UPDATE; del_timer_sync(&adapter->service_timer); @@ -4288,25 +4301,8 @@ static void ixgbe_tx_timeout(struct net_device *netdev) { struct ixgbe_adapter *adapter = netdev_priv(netdev); - adapter->tx_timeout_count++; - /* Do the reset outside of interrupt context */ - schedule_work(&adapter->reset_task); -} - -static void ixgbe_reset_task(struct work_struct *work) -{ - struct ixgbe_adapter *adapter; - adapter = container_of(work, struct ixgbe_adapter, reset_task); - - /* If we're already down or resetting, just bail */ - if (test_bit(__IXGBE_DOWN, &adapter->state) || - test_bit(__IXGBE_RESETTING, &adapter->state)) - return; - - ixgbe_dump(adapter); - netdev_err(adapter->netdev, "Reset adapter\n"); - ixgbe_reinit_locked(adapter); + ixgbe_tx_timeout_reset(adapter); } /** @@ -6174,7 +6170,7 @@ static void ixgbe_watchdog_flush_tx(struct ixgbe_adapter *adapter) * to get done, so reset controller to flush Tx. * (Do the reset outside of interrupt context). */ - schedule_work(&adapter->reset_task); + adapter->flags2 |= IXGBE_FLAG2_RESET_REQUESTED; } } } @@ -6341,6 +6337,25 @@ static void ixgbe_service_timer(unsigned long data) ixgbe_service_event_schedule(adapter); } +static void ixgbe_reset_subtask(struct ixgbe_adapter *adapter) +{ + if (!(adapter->flags2 & IXGBE_FLAG2_RESET_REQUESTED)) + return; + + adapter->flags2 &= ~IXGBE_FLAG2_RESET_REQUESTED; + + /* If we're already down or resetting, just bail */ + if (test_bit(__IXGBE_DOWN, &adapter->state) || + test_bit(__IXGBE_RESETTING, &adapter->state)) + return; + + ixgbe_dump(adapter); + netdev_err(adapter->netdev, "Reset adapter\n"); + adapter->tx_timeout_count++; + + ixgbe_reinit_locked(adapter); +} + /** * ixgbe_service_task - manages and runs subtasks * @work: pointer to work_struct containing our data @@ -6351,6 +6366,7 @@ static void ixgbe_service_task(struct work_struct *work) struct ixgbe_adapter, service_task); + ixgbe_reset_subtask(adapter); ixgbe_sfp_detection_subtask(adapter); ixgbe_sfp_link_config_subtask(adapter); ixgbe_watchdog_subtask(adapter); @@ -7533,8 +7549,6 @@ static int __devinit ixgbe_probe(struct pci_dev *pdev, setup_timer(&adapter->service_timer, &ixgbe_service_timer, (unsigned long) adapter); - INIT_WORK(&adapter->reset_task, ixgbe_reset_task); - INIT_WORK(&adapter->service_task, ixgbe_service_task); clear_bit(__IXGBE_SERVICE_SCHED, &adapter->state); -- cgit v0.10.2 From d034acf1851c15c3da56d31e7eb4151e40ed0119 Mon Sep 17 00:00:00 2001 From: Alexander Duyck Date: Wed, 27 Apr 2011 09:25:34 +0000 Subject: ixgbe: Merge ATR reinit into the service task This change merges the ATR table reinitialization into the service task. This is yet another opportunity to avoid any race conditions as we don't want to be attempting to reinitialize the table during a possible reset. In addition this change adds a counter for table reinitialization so that it can be tracked as part of the regular statistics. Signed-off-by: Alexander Duyck Tested-by: Evan Swanson Signed-off-by: Jeff Kirsher diff --git a/drivers/net/ixgbe/ixgbe.h b/drivers/net/ixgbe/ixgbe.h index 760b850..a180cde 100644 --- a/drivers/net/ixgbe/ixgbe.h +++ b/drivers/net/ixgbe/ixgbe.h @@ -382,6 +382,7 @@ struct ixgbe_adapter { #define IXGBE_FLAG2_SEARCH_FOR_SFP (u32)(1 << 4) #define IXGBE_FLAG2_SFP_NEEDS_RESET (u32)(1 << 5) #define IXGBE_FLAG2_RESET_REQUESTED (u32)(1 << 6) +#define IXGBE_FLAG2_FDIR_REQUIRES_REINIT (u32)(1 << 7) unsigned long active_vlans[BITS_TO_LONGS(VLAN_N_VID)]; u16 bd_number; @@ -455,12 +456,12 @@ struct ixgbe_adapter { bool link_up; unsigned long link_check_timeout; - struct work_struct fdir_reinit_task; struct work_struct check_overtemp_task; struct work_struct service_task; struct timer_list service_timer; u32 fdir_pballoc; u32 atr_sample_rate; + unsigned long fdir_overflow; /* number of times ATR was backed off */ spinlock_t fdir_perfect_lock; #ifdef IXGBE_FCOE struct ixgbe_fcoe fcoe; diff --git a/drivers/net/ixgbe/ixgbe_ethtool.c b/drivers/net/ixgbe/ixgbe_ethtool.c index 1fdd075..cb1555b 100644 --- a/drivers/net/ixgbe/ixgbe_ethtool.c +++ b/drivers/net/ixgbe/ixgbe_ethtool.c @@ -84,6 +84,7 @@ static struct ixgbe_stats ixgbe_gstrings_stats[] = { {"hw_rsc_flushed", IXGBE_STAT(rsc_total_flush)}, {"fdir_match", IXGBE_STAT(stats.fdirmatch)}, {"fdir_miss", IXGBE_STAT(stats.fdirmiss)}, + {"fdir_overflow", IXGBE_STAT(fdir_overflow)}, {"rx_fifo_errors", IXGBE_NETDEV_STAT(rx_fifo_errors)}, {"rx_missed_errors", IXGBE_NETDEV_STAT(rx_missed_errors)}, {"tx_aborted_errors", IXGBE_NETDEV_STAT(tx_aborted_errors)}, diff --git a/drivers/net/ixgbe/ixgbe_main.c b/drivers/net/ixgbe/ixgbe_main.c index dbb20e5..7edd360 100644 --- a/drivers/net/ixgbe/ixgbe_main.c +++ b/drivers/net/ixgbe/ixgbe_main.c @@ -1950,16 +1950,20 @@ static irqreturn_t ixgbe_msix_lsc(int irq, void *data) case ixgbe_mac_X540: /* Handle Flow Director Full threshold interrupt */ if (eicr & IXGBE_EICR_FLOW_DIR) { + int reinit_count = 0; int i; - IXGBE_WRITE_REG(hw, IXGBE_EICR, IXGBE_EICR_FLOW_DIR); - /* Disable transmits before FDIR Re-initialization */ - netif_tx_stop_all_queues(netdev); for (i = 0; i < adapter->num_tx_queues; i++) { - struct ixgbe_ring *tx_ring = - adapter->tx_ring[i]; + struct ixgbe_ring *ring = adapter->tx_ring[i]; if (test_and_clear_bit(__IXGBE_TX_FDIR_INIT_DONE, - &tx_ring->state)) - schedule_work(&adapter->fdir_reinit_task); + &ring->state)) + reinit_count++; + } + if (reinit_count) { + /* no more flow director interrupts until after init */ + IXGBE_WRITE_REG(hw, IXGBE_EIMC, IXGBE_EIMC_FLOW_DIR); + eicr &= ~IXGBE_EICR_FLOW_DIR; + adapter->flags2 |= IXGBE_FLAG2_FDIR_REQUIRES_REINIT; + ixgbe_service_event_schedule(adapter); } } break; @@ -4198,7 +4202,8 @@ void ixgbe_down(struct ixgbe_adapter *adapter) ixgbe_napi_disable_all(adapter); - adapter->flags2 &= ~IXGBE_FLAG2_RESET_REQUESTED; + adapter->flags2 &= ~(IXGBE_FLAG2_FDIR_REQUIRES_REINIT | + IXGBE_FLAG2_RESET_REQUESTED); adapter->flags &= ~IXGBE_FLAG_NEED_LINK_UPDATE; del_timer_sync(&adapter->service_timer); @@ -4212,13 +4217,6 @@ void ixgbe_down(struct ixgbe_adapter *adapter) free_cpumask_var(q_vector->affinity_mask); } - if (adapter->flags & IXGBE_FLAG_FDIR_HASH_CAPABLE || - adapter->flags & IXGBE_FLAG_FDIR_PERFECT_CAPABLE) - cancel_work_sync(&adapter->fdir_reinit_task); - - if (adapter->flags2 & IXGBE_FLAG2_TEMP_SENSOR_CAPABLE) - cancel_work_sync(&adapter->check_overtemp_task); - /* disable transmits in the hardware now that interrupts are off */ for (i = 0; i < adapter->num_tx_queues; i++) { u8 reg_idx = adapter->tx_ring[i]->reg_idx; @@ -5950,27 +5948,39 @@ void ixgbe_update_stats(struct ixgbe_adapter *adapter) } /** - * ixgbe_fdir_reinit_task - worker thread to reinit FDIR filter table - * @work: pointer to work_struct containing our data + * ixgbe_fdir_reinit_subtask - worker thread to reinit FDIR filter table + * @adapter - pointer to the device adapter structure **/ -static void ixgbe_fdir_reinit_task(struct work_struct *work) +static void ixgbe_fdir_reinit_subtask(struct ixgbe_adapter *adapter) { - struct ixgbe_adapter *adapter = container_of(work, - struct ixgbe_adapter, - fdir_reinit_task); struct ixgbe_hw *hw = &adapter->hw; int i; + if (!(adapter->flags2 & IXGBE_FLAG2_FDIR_REQUIRES_REINIT)) + return; + + adapter->flags2 &= ~IXGBE_FLAG2_FDIR_REQUIRES_REINIT; + + /* if interface is down do nothing */ + if (test_bit(__IXGBE_DOWN, &adapter->state)) + return; + + /* do nothing if we are not using signature filters */ + if (!(adapter->flags & IXGBE_FLAG_FDIR_HASH_CAPABLE)) + return; + + adapter->fdir_overflow++; + if (ixgbe_reinit_fdir_tables_82599(hw) == 0) { for (i = 0; i < adapter->num_tx_queues; i++) set_bit(__IXGBE_TX_FDIR_INIT_DONE, &(adapter->tx_ring[i]->state)); + /* re-enable flow director interrupts */ + IXGBE_WRITE_REG(hw, IXGBE_EIMS, IXGBE_EIMS_FLOW_DIR); } else { e_err(probe, "failed to finish FDIR re-initialization, " "ignored adding FDIR ATR filters\n"); } - /* Done FDIR Re-initialization, enable transmits */ - netif_tx_start_all_queues(adapter->netdev); } /** @@ -6370,6 +6380,7 @@ static void ixgbe_service_task(struct work_struct *work) ixgbe_sfp_detection_subtask(adapter); ixgbe_sfp_link_config_subtask(adapter); ixgbe_watchdog_subtask(adapter); + ixgbe_fdir_reinit_subtask(adapter); ixgbe_check_hang_subtask(adapter); ixgbe_service_event_complete(adapter); @@ -7637,10 +7648,6 @@ static int __devinit ixgbe_probe(struct pci_dev *pdev, /* carrier off reporting is important to ethtool even BEFORE open */ netif_carrier_off(netdev); - if (adapter->flags & IXGBE_FLAG_FDIR_HASH_CAPABLE || - adapter->flags & IXGBE_FLAG_FDIR_PERFECT_CAPABLE) - INIT_WORK(&adapter->fdir_reinit_task, ixgbe_fdir_reinit_task); - if (adapter->flags2 & IXGBE_FLAG2_TEMP_SENSOR_CAPABLE) INIT_WORK(&adapter->check_overtemp_task, ixgbe_check_overtemp_task); @@ -7700,12 +7707,8 @@ static void __devexit ixgbe_remove(struct pci_dev *pdev) set_bit(__IXGBE_DOWN, &adapter->state); cancel_work_sync(&adapter->service_task); - if (adapter->flags & IXGBE_FLAG_FDIR_HASH_CAPABLE || - adapter->flags & IXGBE_FLAG_FDIR_PERFECT_CAPABLE) - cancel_work_sync(&adapter->fdir_reinit_task); if (adapter->flags2 & IXGBE_FLAG2_TEMP_SENSOR_CAPABLE) cancel_work_sync(&adapter->check_overtemp_task); - #ifdef CONFIG_IXGBE_DCA if (adapter->flags & IXGBE_FLAG_DCA_ENABLED) { adapter->flags &= ~IXGBE_FLAG_DCA_ENABLED; -- cgit v0.10.2 From f0f9778d043481f3cded693849e3b88b01fbc69b Mon Sep 17 00:00:00 2001 From: Alexander Duyck Date: Fri, 22 Apr 2011 04:08:09 +0000 Subject: ixgbe: Merge over-temp task into service task This change merges the over-temp task into the service task. As a result all tasklets are finally combined into once single tasklet for easier management. Signed-off-by: Alexander Duyck Signed-off-by: Jeff Kirsher diff --git a/drivers/net/ixgbe/ixgbe.h b/drivers/net/ixgbe/ixgbe.h index a180cde..e467b20 100644 --- a/drivers/net/ixgbe/ixgbe.h +++ b/drivers/net/ixgbe/ixgbe.h @@ -379,6 +379,7 @@ struct ixgbe_adapter { #define IXGBE_FLAG2_RSC_CAPABLE (u32)(1) #define IXGBE_FLAG2_RSC_ENABLED (u32)(1 << 1) #define IXGBE_FLAG2_TEMP_SENSOR_CAPABLE (u32)(1 << 2) +#define IXGBE_FLAG2_TEMP_SENSOR_EVENT (u32)(1 << 3) #define IXGBE_FLAG2_SEARCH_FOR_SFP (u32)(1 << 4) #define IXGBE_FLAG2_SFP_NEEDS_RESET (u32)(1 << 5) #define IXGBE_FLAG2_RESET_REQUESTED (u32)(1 << 6) @@ -456,7 +457,6 @@ struct ixgbe_adapter { bool link_up; unsigned long link_check_timeout; - struct work_struct check_overtemp_task; struct work_struct service_task; struct timer_list service_timer; u32 fdir_pballoc; diff --git a/drivers/net/ixgbe/ixgbe_main.c b/drivers/net/ixgbe/ixgbe_main.c index 7edd360..dad56e1 100644 --- a/drivers/net/ixgbe/ixgbe_main.c +++ b/drivers/net/ixgbe/ixgbe_main.c @@ -1825,35 +1825,51 @@ static void ixgbe_set_itr_msix(struct ixgbe_q_vector *q_vector) } /** - * ixgbe_check_overtemp_task - worker thread to check over tempurature - * @work: pointer to work_struct containing our data + * ixgbe_check_overtemp_subtask - check for over tempurature + * @adapter: pointer to adapter **/ -static void ixgbe_check_overtemp_task(struct work_struct *work) +static void ixgbe_check_overtemp_subtask(struct ixgbe_adapter *adapter) { - struct ixgbe_adapter *adapter = container_of(work, - struct ixgbe_adapter, - check_overtemp_task); struct ixgbe_hw *hw = &adapter->hw; u32 eicr = adapter->interrupt_event; - if (!(adapter->flags2 & IXGBE_FLAG2_TEMP_SENSOR_CAPABLE)) + if (test_bit(__IXGBE_DOWN, &adapter->state)) return; + if (!(adapter->flags2 & IXGBE_FLAG2_TEMP_SENSOR_CAPABLE) && + !(adapter->flags2 & IXGBE_FLAG2_TEMP_SENSOR_EVENT)) + return; + + adapter->flags2 &= ~IXGBE_FLAG2_TEMP_SENSOR_EVENT; + switch (hw->device_id) { - case IXGBE_DEV_ID_82599_T3_LOM: { - u32 autoneg; - bool link_up = false; + case IXGBE_DEV_ID_82599_T3_LOM: + /* + * Since the warning interrupt is for both ports + * we don't have to check if: + * - This interrupt wasn't for our port. + * - We may have missed the interrupt so always have to + * check if we got a LSC + */ + if (!(eicr & IXGBE_EICR_GPI_SDP0) && + !(eicr & IXGBE_EICR_LSC)) + return; + + if (!(eicr & IXGBE_EICR_LSC) && hw->mac.ops.check_link) { + u32 autoneg; + bool link_up = false; - if (hw->mac.ops.check_link) hw->mac.ops.check_link(hw, &autoneg, &link_up, false); - if (((eicr & IXGBE_EICR_GPI_SDP0) && (!link_up)) || - (eicr & IXGBE_EICR_LSC)) - /* Check if this is due to overtemp */ - if (hw->phy.ops.check_overtemp(hw) == IXGBE_ERR_OVERTEMP) - break; - return; - } + if (link_up) + return; + } + + /* Check if this is not due to overtemp */ + if (hw->phy.ops.check_overtemp(hw) != IXGBE_ERR_OVERTEMP) + return; + + break; default: if (!(eicr & IXGBE_EICR_GPI_SDP0)) return; @@ -1863,8 +1879,8 @@ static void ixgbe_check_overtemp_task(struct work_struct *work) "Network adapter has been stopped because it has over heated. " "Restart the computer. If the problem persists, " "power off the system and replace the adapter\n"); - /* write to clear the interrupt */ - IXGBE_WRITE_REG(hw, IXGBE_EICR, IXGBE_EICR_GPI_SDP0); + + adapter->interrupt_event = 0; } static void ixgbe_check_fan_failure(struct ixgbe_adapter *adapter, u32 eicr) @@ -1940,13 +1956,6 @@ static irqreturn_t ixgbe_msix_lsc(int irq, void *data) switch (hw->mac.type) { case ixgbe_mac_82599EB: - ixgbe_check_sfp_event(adapter, eicr); - if ((adapter->flags2 & IXGBE_FLAG2_TEMP_SENSOR_CAPABLE) && - ((eicr & IXGBE_EICR_GPI_SDP0) || (eicr & IXGBE_EICR_LSC))) { - adapter->interrupt_event = eicr; - schedule_work(&adapter->check_overtemp_task); - } - /* now fallthrough to handle Flow Director */ case ixgbe_mac_X540: /* Handle Flow Director Full threshold interrupt */ if (eicr & IXGBE_EICR_FLOW_DIR) { @@ -1966,6 +1975,15 @@ static irqreturn_t ixgbe_msix_lsc(int irq, void *data) ixgbe_service_event_schedule(adapter); } } + ixgbe_check_sfp_event(adapter, eicr); + if ((adapter->flags2 & IXGBE_FLAG2_TEMP_SENSOR_CAPABLE) && + ((eicr & IXGBE_EICR_GPI_SDP0) || (eicr & IXGBE_EICR_LSC))) { + if (!test_bit(__IXGBE_DOWN, &adapter->state)) { + adapter->interrupt_event = eicr; + adapter->flags2 |= IXGBE_FLAG2_TEMP_SENSOR_EVENT; + ixgbe_service_event_schedule(adapter); + } + } break; default: break; @@ -2561,8 +2579,11 @@ static irqreturn_t ixgbe_intr(int irq, void *data) ixgbe_check_sfp_event(adapter, eicr); if ((adapter->flags2 & IXGBE_FLAG2_TEMP_SENSOR_CAPABLE) && ((eicr & IXGBE_EICR_GPI_SDP0) || (eicr & IXGBE_EICR_LSC))) { - adapter->interrupt_event = eicr; - schedule_work(&adapter->check_overtemp_task); + if (!test_bit(__IXGBE_DOWN, &adapter->state)) { + adapter->interrupt_event = eicr; + adapter->flags2 |= IXGBE_FLAG2_TEMP_SENSOR_EVENT; + ixgbe_service_event_schedule(adapter); + } } break; default: @@ -5974,7 +5995,7 @@ static void ixgbe_fdir_reinit_subtask(struct ixgbe_adapter *adapter) if (ixgbe_reinit_fdir_tables_82599(hw) == 0) { for (i = 0; i < adapter->num_tx_queues; i++) set_bit(__IXGBE_TX_FDIR_INIT_DONE, - &(adapter->tx_ring[i]->state)); + &(adapter->tx_ring[i]->state)); /* re-enable flow director interrupts */ IXGBE_WRITE_REG(hw, IXGBE_EIMS, IXGBE_EIMS_FLOW_DIR); } else { @@ -6379,6 +6400,7 @@ static void ixgbe_service_task(struct work_struct *work) ixgbe_reset_subtask(adapter); ixgbe_sfp_detection_subtask(adapter); ixgbe_sfp_link_config_subtask(adapter); + ixgbe_check_overtemp_subtask(adapter); ixgbe_watchdog_subtask(adapter); ixgbe_fdir_reinit_subtask(adapter); ixgbe_check_hang_subtask(adapter); @@ -7648,9 +7670,6 @@ static int __devinit ixgbe_probe(struct pci_dev *pdev, /* carrier off reporting is important to ethtool even BEFORE open */ netif_carrier_off(netdev); - if (adapter->flags2 & IXGBE_FLAG2_TEMP_SENSOR_CAPABLE) - INIT_WORK(&adapter->check_overtemp_task, - ixgbe_check_overtemp_task); #ifdef CONFIG_IXGBE_DCA if (dca_add_requester(&pdev->dev) == 0) { adapter->flags |= IXGBE_FLAG_DCA_ENABLED; @@ -7707,8 +7726,6 @@ static void __devexit ixgbe_remove(struct pci_dev *pdev) set_bit(__IXGBE_DOWN, &adapter->state); cancel_work_sync(&adapter->service_task); - if (adapter->flags2 & IXGBE_FLAG2_TEMP_SENSOR_CAPABLE) - cancel_work_sync(&adapter->check_overtemp_task); #ifdef CONFIG_IXGBE_DCA if (adapter->flags & IXGBE_FLAG_DCA_ENABLED) { adapter->flags &= ~IXGBE_FLAG_DCA_ENABLED; -- cgit v0.10.2 From 34cecbbfad5a01050604d5b12fd7d7fb02597dbe Mon Sep 17 00:00:00 2001 From: Alexander Duyck Date: Fri, 22 Apr 2011 04:08:14 +0000 Subject: ixgbe: cleanup some minor issues in ixgbe_down() This patch cleans up two minor issues in ixgbe_down. Specifically it addresses the fact that the VFs should not be pinged until after interrupts are disabled otherwise they might still get a response. It also drops the use of the txdctl temporary variable since the only bit we should be writing to the TXDCTL registers during a shutdown is the flush bit. Signed-off-by: Alexander Duyck Signed-off-by: Jeff Kirsher diff --git a/drivers/net/ixgbe/ixgbe_main.c b/drivers/net/ixgbe/ixgbe_main.c index dad56e1..4be2af2 100644 --- a/drivers/net/ixgbe/ixgbe_main.c +++ b/drivers/net/ixgbe/ixgbe_main.c @@ -4182,26 +4182,12 @@ void ixgbe_down(struct ixgbe_adapter *adapter) struct net_device *netdev = adapter->netdev; struct ixgbe_hw *hw = &adapter->hw; u32 rxctrl; - u32 txdctl; int i; int num_q_vectors = adapter->num_msix_vectors - NON_Q_VECTORS; /* signal that we are down to the interrupt handler */ set_bit(__IXGBE_DOWN, &adapter->state); - /* disable receive for all VFs and wait one second */ - if (adapter->num_vfs) { - /* ping all the active vfs to let them know we are going down */ - ixgbe_ping_all_vfs(adapter); - - /* Disable all VFTE/VFRE TX/RX */ - ixgbe_disable_tx_rx(adapter); - - /* Mark all the VFs as inactive */ - for (i = 0 ; i < adapter->num_vfs; i++) - adapter->vfinfo[i].clear_to_send = 0; - } - /* disable receives */ rxctrl = IXGBE_READ_REG(hw, IXGBE_RXCTRL); IXGBE_WRITE_REG(hw, IXGBE_RXCTRL, rxctrl & ~IXGBE_RXCTRL_RXEN); @@ -4229,6 +4215,19 @@ void ixgbe_down(struct ixgbe_adapter *adapter) del_timer_sync(&adapter->service_timer); + /* disable receive for all VFs and wait one second */ + if (adapter->num_vfs) { + /* ping all the active vfs to let them know we are going down */ + ixgbe_ping_all_vfs(adapter); + + /* Disable all VFTE/VFRE TX/RX */ + ixgbe_disable_tx_rx(adapter); + + /* Mark all the VFs as inactive */ + for (i = 0 ; i < adapter->num_vfs; i++) + adapter->vfinfo[i].clear_to_send = 0; + } + /* Cleanup the affinity_hint CPU mask memory and callback */ for (i = 0; i < num_q_vectors; i++) { struct ixgbe_q_vector *q_vector = adapter->q_vector[i]; @@ -4241,11 +4240,10 @@ void ixgbe_down(struct ixgbe_adapter *adapter) /* disable transmits in the hardware now that interrupts are off */ for (i = 0; i < adapter->num_tx_queues; i++) { u8 reg_idx = adapter->tx_ring[i]->reg_idx; - txdctl = IXGBE_READ_REG(hw, IXGBE_TXDCTL(reg_idx)); - IXGBE_WRITE_REG(hw, IXGBE_TXDCTL(reg_idx), - (txdctl & ~IXGBE_TXDCTL_ENABLE)); + IXGBE_WRITE_REG(hw, IXGBE_TXDCTL(reg_idx), IXGBE_TXDCTL_SWFLSH); } - /* Disable the Tx DMA engine on 82599 */ + + /* Disable the Tx DMA engine on 82599 and X540 */ switch (hw->mac.type) { case ixgbe_mac_82599EB: case ixgbe_mac_X540: -- cgit v0.10.2 From c050999e2c00b189a21df3ee9ad8d27c85ce9c34 Mon Sep 17 00:00:00 2001 From: Emil Tantilov Date: Sat, 7 May 2011 06:49:18 +0000 Subject: ixgbe: fix sparse warning error: bad constant expression Signed-off-by: Emil Tantilov Tested-by: Evan Swanson Signed-off-by: Jeff Kirsher diff --git a/drivers/net/ixgbe/ixgbe_sriov.c b/drivers/net/ixgbe/ixgbe_sriov.c index 9f97246..ac99b04 100644 --- a/drivers/net/ixgbe/ixgbe_sriov.c +++ b/drivers/net/ixgbe/ixgbe_sriov.c @@ -324,7 +324,7 @@ static inline void ixgbe_vf_reset_msg(struct ixgbe_adapter *adapter, u32 vf) static int ixgbe_rcv_msg_from_vf(struct ixgbe_adapter *adapter, u32 vf) { u32 mbx_size = IXGBE_VFMAILBOX_SIZE; - u32 msgbuf[mbx_size]; + u32 msgbuf[IXGBE_VFMAILBOX_SIZE]; struct ixgbe_hw *hw = &adapter->hw; s32 retval; int entries; -- cgit v0.10.2 From 4f6290cf610a7a48b39603ff7822746463453e01 Mon Sep 17 00:00:00 2001 From: Don Skidmore Date: Sat, 14 May 2011 06:36:35 +0000 Subject: ixgbe: Add support for new 82599 adapter This patch adds support for a new adapter in the 82599 family. Included in that support is a new media_type ixgbe_media_type_fiber_lco. Signed-of-by: Don Skidmore Signed-off-by: Jeff Kirsher diff --git a/drivers/net/ixgbe/ixgbe_82599.c b/drivers/net/ixgbe/ixgbe_82599.c index dba5ca6..8ee66124 100644 --- a/drivers/net/ixgbe/ixgbe_82599.c +++ b/drivers/net/ixgbe/ixgbe_82599.c @@ -368,6 +368,9 @@ static enum ixgbe_media_type ixgbe_get_media_type_82599(struct ixgbe_hw *hw) case IXGBE_DEV_ID_82599_T3_LOM: media_type = ixgbe_media_type_copper; break; + case IXGBE_DEV_ID_82599_LS: + media_type = ixgbe_media_type_fiber_lco; + break; default: media_type = ixgbe_media_type_unknown; break; diff --git a/drivers/net/ixgbe/ixgbe_main.c b/drivers/net/ixgbe/ixgbe_main.c index 4be2af2..2dce3d0 100644 --- a/drivers/net/ixgbe/ixgbe_main.c +++ b/drivers/net/ixgbe/ixgbe_main.c @@ -126,6 +126,8 @@ static DEFINE_PCI_DEVICE_TABLE(ixgbe_pci_tbl) = { board_X540 }, {PCI_VDEVICE(INTEL, IXGBE_DEV_ID_82599_SFP_SF2), board_82599 }, + {PCI_VDEVICE(INTEL, IXGBE_DEV_ID_82599_LS), + board_82599 }, /* required last entry */ {0, } diff --git a/drivers/net/ixgbe/ixgbe_type.h b/drivers/net/ixgbe/ixgbe_type.h index 70e6870..fa43f25 100644 --- a/drivers/net/ixgbe/ixgbe_type.h +++ b/drivers/net/ixgbe/ixgbe_type.h @@ -62,6 +62,7 @@ #define IXGBE_DEV_ID_82599_XAUI_LOM 0x10FC #define IXGBE_DEV_ID_82599_COMBO_BACKPLANE 0x10F8 #define IXGBE_SUBDEV_ID_82599_KX4_KR_MEZZ 0x000C +#define IXGBE_DEV_ID_82599_LS 0x154F #define IXGBE_DEV_ID_X540T 0x1528 /* General Registers */ @@ -2395,6 +2396,7 @@ enum ixgbe_sfp_type { enum ixgbe_media_type { ixgbe_media_type_unknown = 0, ixgbe_media_type_fiber, + ixgbe_media_type_fiber_lco, ixgbe_media_type_copper, ixgbe_media_type_backplane, ixgbe_media_type_cx4, -- cgit v0.10.2 From 1b1cb1f78a5e9d54c13e176020c3e8ded5d081ce Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Fri, 13 May 2011 22:59:19 +0000 Subject: net: ping: small changes ping_table is not __read_mostly, since it contains one rwlock, and is static to ping.c ping_port_rover & ping_v4_lookup are static Signed-off-by: Eric Dumazet Acked-by: Vasiliy Kulikov Signed-off-by: David S. Miller diff --git a/net/ipv4/ping.c b/net/ipv4/ping.c index a77e2d7..7041d09 100644 --- a/net/ipv4/ping.c +++ b/net/ipv4/ping.c @@ -49,9 +49,9 @@ #include -struct ping_table ping_table __read_mostly; +static struct ping_table ping_table; -u16 ping_port_rover; +static u16 ping_port_rover; static inline int ping_hashfn(struct net *net, unsigned num, unsigned mask) { @@ -150,8 +150,8 @@ static void ping_v4_unhash(struct sock *sk) } } -struct sock *ping_v4_lookup(struct net *net, u32 saddr, u32 daddr, - u16 ident, int dif) +static struct sock *ping_v4_lookup(struct net *net, u32 saddr, u32 daddr, + u16 ident, int dif) { struct hlist_nulls_head *hslot = ping_hashslot(&ping_table, net, ident); struct sock *sk = NULL; -- cgit v0.10.2 From b90194181988063266f3da0b7bf3e57268c627c8 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Mon, 25 Apr 2011 16:25:20 -0300 Subject: perf tools: Honour the cpu list parameter when also monitoring a thread list The perf_evlist__create_maps was discarding the --cpu parameter when a --pid or --tid was specified, fix that. Cc: Frederic Weisbecker Cc: Ingo Molnar Cc: Mike Galbraith Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Stephane Eranian Cc: Tom Zanussi Link: http://lkml.kernel.org/r/20110426204401.GB1746@ghostprotocols.net Signed-off-by: Arnaldo Carvalho de Melo diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c index 45da8d1..1884a7c 100644 --- a/tools/perf/util/evlist.c +++ b/tools/perf/util/evlist.c @@ -348,7 +348,7 @@ int perf_evlist__create_maps(struct perf_evlist *evlist, pid_t target_pid, if (evlist->threads == NULL) return -1; - if (target_tid != -1) + if (cpu_list == NULL && target_tid != -1) evlist->cpus = cpu_map__dummy_new(); else evlist->cpus = cpu_map__new(cpu_list); -- cgit v0.10.2 From aece948f5ddd70d70df2f35855c706ef9a4f62e2 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Sun, 15 May 2011 09:39:00 -0300 Subject: perf evlist: Fix per thread mmap setup The PERF_EVENT_IOC_SET_OUTPUT ioctl was returning -EINVAL when using --pid when monitoring multithreaded apps, as we can only share a ring buffer for events on the same thread if not doing per cpu. Fix it by using per thread ring buffers. Tested with: [root@felicio ~]# tuna -t 26131 -CP | nl 1 thread ctxt_switches 2 pid SCHED_ rtpri affinity voluntary nonvoluntary cmd 3 26131 OTHER 0 0,1 10814276 2397830 chromium-browse 4 642 OTHER 0 0,1 14688 0 chromium-browse 5 26148 OTHER 0 0,1 713602 115479 chromium-browse 6 26149 OTHER 0 0,1 801958 2262 chromium-browse 7 26150 OTHER 0 0,1 1271128 248 chromium-browse 8 26151 OTHER 0 0,1 3 0 chromium-browse 9 27049 OTHER 0 0,1 36796 9 chromium-browse 10 618 OTHER 0 0,1 14711 0 chromium-browse 11 661 OTHER 0 0,1 14593 0 chromium-browse 12 29048 OTHER 0 0,1 28125 0 chromium-browse 13 26143 OTHER 0 0,1 2202789 781 chromium-browse [root@felicio ~]# So 11 threads under pid 26131, then: [root@felicio ~]# perf record -F 50000 --pid 26131 [root@felicio ~]# grep perf_event /proc/`pidof perf`/maps | nl 1 7fa4a2538000-7fa4a25b9000 rwxs 00000000 00:09 4064 anon_inode:[perf_event] 2 7fa4a25b9000-7fa4a263a000 rwxs 00000000 00:09 4064 anon_inode:[perf_event] 3 7fa4a263a000-7fa4a26bb000 rwxs 00000000 00:09 4064 anon_inode:[perf_event] 4 7fa4a26bb000-7fa4a273c000 rwxs 00000000 00:09 4064 anon_inode:[perf_event] 5 7fa4a273c000-7fa4a27bd000 rwxs 00000000 00:09 4064 anon_inode:[perf_event] 6 7fa4a27bd000-7fa4a283e000 rwxs 00000000 00:09 4064 anon_inode:[perf_event] 7 7fa4a283e000-7fa4a28bf000 rwxs 00000000 00:09 4064 anon_inode:[perf_event] 8 7fa4a28bf000-7fa4a2940000 rwxs 00000000 00:09 4064 anon_inode:[perf_event] 9 7fa4a2940000-7fa4a29c1000 rwxs 00000000 00:09 4064 anon_inode:[perf_event] 10 7fa4a29c1000-7fa4a2a42000 rwxs 00000000 00:09 4064 anon_inode:[perf_event] 11 7fa4a2a42000-7fa4a2ac3000 rwxs 00000000 00:09 4064 anon_inode:[perf_event] [root@felicio ~]# 11 mmaps, one per thread since we didn't specify any CPU list, so we need one mmap per thread and: [root@felicio ~]# perf record -F 50000 --pid 26131 ^M ^C[ perf record: Woken up 79 times to write data ] [ perf record: Captured and wrote 20.614 MB perf.data (~900639 samples) ] [root@felicio ~]# perf report -D | grep PERF_RECORD_SAMPLE | cut -d/ -f2 | cut -d: -f1 | sort -n | uniq -c | sort -nr | nl 1 371310 26131 2 96516 26148 3 95694 26149 4 95203 26150 5 7291 26143 6 87 27049 7 76 661 8 60 29048 9 47 618 10 43 642 [root@felicio ~]# Ok, one of the threads, 26151 was quiescent, so no samples there, but all the others are there. Then, if I specify one CPU: [root@felicio ~]# perf record -F 50000 --pid 26131 --cpu 1 ^C[ perf record: Woken up 1 times to write data ] [ perf record: Captured and wrote 0.680 MB perf.data (~29730 samples) ] [root@felicio ~]# perf report -D | grep PERF_RECORD_SAMPLE | cut -d/ -f2 | cut -d: -f1 | sort -n | uniq -c | sort -nr | nl 1 8444 26131 2 2584 26149 3 2518 26148 4 2324 26150 5 123 26143 6 9 661 7 9 29048 [root@felicio ~]# This machine has two cores, so fewer threads appeared on the radar, and: [root@felicio ~]# grep perf_event /proc/`pidof perf`/maps | nl 1 7f484b922000-7f484b9a3000 rwxs 00000000 00:09 4064 anon_inode:[perf_event] [root@felicio ~]# Just one mmap, as now we can use just one per-cpu buffer instead of the per-thread needed in the previous case. For global profiling: [root@felicio ~]# perf record -F 50000 -a ^C[ perf record: Woken up 26 times to write data ] [ perf record: Captured and wrote 7.128 MB perf.data (~311412 samples) ] [root@felicio ~]# grep perf_event /proc/`pidof perf`/maps | nl 1 7fb49b435000-7fb49b4b6000 rwxs 00000000 00:09 4064 anon_inode:[perf_event] 2 7fb49b4b6000-7fb49b537000 rwxs 00000000 00:09 4064 anon_inode:[perf_event] [root@felicio ~]# It uses per-cpu buffers. For just one thread: [root@felicio ~]# perf record -F 50000 --tid 26148 ^C[ perf record: Woken up 2 times to write data ] [ perf record: Captured and wrote 0.330 MB perf.data (~14426 samples) ] [root@felicio ~]# perf report -D | grep PERF_RECORD_SAMPLE | cut -d/ -f2 | cut -d: -f1 | sort -n | uniq -c | sort -nr | nl 1 9969 26148 [root@felicio ~]# [root@felicio ~]# grep perf_event /proc/`pidof perf`/maps | nl 1 7f286a51b000-7f286a59c000 rwxs 00000000 00:09 4064 anon_inode:[perf_event] [root@felicio ~]# Tested-by: David Ahern Tested-by: Lin Ming Cc: Frederic Weisbecker Cc: Ingo Molnar Cc: Mike Galbraith Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Stephane Eranian Cc: Tom Zanussi Link: http://lkml.kernel.org/r/20110426204401.GB1746@ghostprotocols.net Signed-off-by: Arnaldo Carvalho de Melo diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c index 4165382..0974f95 100644 --- a/tools/perf/builtin-record.c +++ b/tools/perf/builtin-record.c @@ -427,7 +427,7 @@ static void mmap_read_all(void) { int i; - for (i = 0; i < evsel_list->cpus->nr; i++) { + for (i = 0; i < evsel_list->nr_mmaps; i++) { if (evsel_list->mmap[i].base) mmap_read(&evsel_list->mmap[i]); } diff --git a/tools/perf/builtin-test.c b/tools/perf/builtin-test.c index 11e3c84..2f9a337 100644 --- a/tools/perf/builtin-test.c +++ b/tools/perf/builtin-test.c @@ -549,7 +549,7 @@ static int test__basic_mmap(void) ++foo; } - while ((event = perf_evlist__read_on_cpu(evlist, 0)) != NULL) { + while ((event = perf_evlist__mmap_read(evlist, 0)) != NULL) { struct perf_sample sample; if (event->header.type != PERF_RECORD_SAMPLE) { diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c index 7e3d6e3..ebfc7cf 100644 --- a/tools/perf/builtin-top.c +++ b/tools/perf/builtin-top.c @@ -801,12 +801,12 @@ static void perf_event__process_sample(const union perf_event *event, } } -static void perf_session__mmap_read_cpu(struct perf_session *self, int cpu) +static void perf_session__mmap_read_idx(struct perf_session *self, int idx) { struct perf_sample sample; union perf_event *event; - while ((event = perf_evlist__read_on_cpu(top.evlist, cpu)) != NULL) { + while ((event = perf_evlist__mmap_read(top.evlist, idx)) != NULL) { perf_session__parse_sample(self, event, &sample); if (event->header.type == PERF_RECORD_SAMPLE) @@ -820,8 +820,8 @@ static void perf_session__mmap_read(struct perf_session *self) { int i; - for (i = 0; i < top.evlist->cpus->nr; i++) - perf_session__mmap_read_cpu(self, i); + for (i = 0; i < top.evlist->nr_mmaps; i++) + perf_session__mmap_read_idx(self, i); } static void start_counters(struct perf_evlist *evlist) diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c index 1884a7c..23eb22b 100644 --- a/tools/perf/util/evlist.c +++ b/tools/perf/util/evlist.c @@ -166,11 +166,11 @@ struct perf_evsel *perf_evlist__id2evsel(struct perf_evlist *evlist, u64 id) return NULL; } -union perf_event *perf_evlist__read_on_cpu(struct perf_evlist *evlist, int cpu) +union perf_event *perf_evlist__mmap_read(struct perf_evlist *evlist, int idx) { /* XXX Move this to perf.c, making it generally available */ unsigned int page_size = sysconf(_SC_PAGE_SIZE); - struct perf_mmap *md = &evlist->mmap[cpu]; + struct perf_mmap *md = &evlist->mmap[idx]; unsigned int head = perf_mmap__read_head(md); unsigned int old = md->prev; unsigned char *data = md->base + page_size; @@ -235,31 +235,37 @@ union perf_event *perf_evlist__read_on_cpu(struct perf_evlist *evlist, int cpu) void perf_evlist__munmap(struct perf_evlist *evlist) { - int cpu; + int i; - for (cpu = 0; cpu < evlist->cpus->nr; cpu++) { - if (evlist->mmap[cpu].base != NULL) { - munmap(evlist->mmap[cpu].base, evlist->mmap_len); - evlist->mmap[cpu].base = NULL; + for (i = 0; i < evlist->nr_mmaps; i++) { + if (evlist->mmap[i].base != NULL) { + munmap(evlist->mmap[i].base, evlist->mmap_len); + evlist->mmap[i].base = NULL; } } + + free(evlist->mmap); + evlist->mmap = NULL; } int perf_evlist__alloc_mmap(struct perf_evlist *evlist) { - evlist->mmap = zalloc(evlist->cpus->nr * sizeof(struct perf_mmap)); + evlist->nr_mmaps = evlist->cpus->nr; + if (evlist->cpus->map[0] == -1) + evlist->nr_mmaps = evlist->threads->nr; + evlist->mmap = zalloc(evlist->nr_mmaps * sizeof(struct perf_mmap)); return evlist->mmap != NULL ? 0 : -ENOMEM; } static int __perf_evlist__mmap(struct perf_evlist *evlist, struct perf_evsel *evsel, - int cpu, int prot, int mask, int fd) + int idx, int prot, int mask, int fd) { - evlist->mmap[cpu].prev = 0; - evlist->mmap[cpu].mask = mask; - evlist->mmap[cpu].base = mmap(NULL, evlist->mmap_len, prot, + evlist->mmap[idx].prev = 0; + evlist->mmap[idx].mask = mask; + evlist->mmap[idx].base = mmap(NULL, evlist->mmap_len, prot, MAP_SHARED, fd, 0); - if (evlist->mmap[cpu].base == MAP_FAILED) { - if (evlist->cpus->map[cpu] == -1 && evsel->attr.inherit) + if (evlist->mmap[idx].base == MAP_FAILED) { + if (evlist->cpus->map[idx] == -1 && evsel->attr.inherit) ui__warning("Inherit is not allowed on per-task " "events using mmap.\n"); return -1; @@ -269,6 +275,86 @@ static int __perf_evlist__mmap(struct perf_evlist *evlist, struct perf_evsel *ev return 0; } +static int perf_evlist__mmap_per_cpu(struct perf_evlist *evlist, int prot, int mask) +{ + struct perf_evsel *evsel; + int cpu, thread; + + for (cpu = 0; cpu < evlist->cpus->nr; cpu++) { + int output = -1; + + for (thread = 0; thread < evlist->threads->nr; thread++) { + list_for_each_entry(evsel, &evlist->entries, node) { + int fd = FD(evsel, cpu, thread); + + if (output == -1) { + output = fd; + if (__perf_evlist__mmap(evlist, evsel, cpu, + prot, mask, output) < 0) + goto out_unmap; + } else { + if (ioctl(fd, PERF_EVENT_IOC_SET_OUTPUT, output) != 0) + goto out_unmap; + } + + if ((evsel->attr.read_format & PERF_FORMAT_ID) && + perf_evlist__id_add_fd(evlist, evsel, cpu, thread, fd) < 0) + goto out_unmap; + } + } + } + + return 0; + +out_unmap: + for (cpu = 0; cpu < evlist->cpus->nr; cpu++) { + if (evlist->mmap[cpu].base != NULL) { + munmap(evlist->mmap[cpu].base, evlist->mmap_len); + evlist->mmap[cpu].base = NULL; + } + } + return -1; +} + +static int perf_evlist__mmap_per_thread(struct perf_evlist *evlist, int prot, int mask) +{ + struct perf_evsel *evsel; + int thread; + + for (thread = 0; thread < evlist->threads->nr; thread++) { + int output = -1; + + list_for_each_entry(evsel, &evlist->entries, node) { + int fd = FD(evsel, 0, thread); + + if (output == -1) { + output = fd; + if (__perf_evlist__mmap(evlist, evsel, thread, + prot, mask, output) < 0) + goto out_unmap; + } else { + if (ioctl(fd, PERF_EVENT_IOC_SET_OUTPUT, output) != 0) + goto out_unmap; + } + + if ((evsel->attr.read_format & PERF_FORMAT_ID) && + perf_evlist__id_add_fd(evlist, evsel, 0, thread, fd) < 0) + goto out_unmap; + } + } + + return 0; + +out_unmap: + for (thread = 0; thread < evlist->threads->nr; thread++) { + if (evlist->mmap[thread].base != NULL) { + munmap(evlist->mmap[thread].base, evlist->mmap_len); + evlist->mmap[thread].base = NULL; + } + } + return -1; +} + /** perf_evlist__mmap - Create per cpu maps to receive events * * @evlist - list of events @@ -287,11 +373,11 @@ static int __perf_evlist__mmap(struct perf_evlist *evlist, struct perf_evsel *ev int perf_evlist__mmap(struct perf_evlist *evlist, int pages, bool overwrite) { unsigned int page_size = sysconf(_SC_PAGE_SIZE); - int mask = pages * page_size - 1, cpu; - struct perf_evsel *first_evsel, *evsel; + int mask = pages * page_size - 1; + struct perf_evsel *evsel; const struct cpu_map *cpus = evlist->cpus; const struct thread_map *threads = evlist->threads; - int thread, prot = PROT_READ | (overwrite ? 0 : PROT_WRITE); + int prot = PROT_READ | (overwrite ? 0 : PROT_WRITE); if (evlist->mmap == NULL && perf_evlist__alloc_mmap(evlist) < 0) return -ENOMEM; @@ -301,43 +387,18 @@ int perf_evlist__mmap(struct perf_evlist *evlist, int pages, bool overwrite) evlist->overwrite = overwrite; evlist->mmap_len = (pages + 1) * page_size; - first_evsel = list_entry(evlist->entries.next, struct perf_evsel, node); list_for_each_entry(evsel, &evlist->entries, node) { if ((evsel->attr.read_format & PERF_FORMAT_ID) && evsel->sample_id == NULL && perf_evsel__alloc_id(evsel, cpus->nr, threads->nr) < 0) return -ENOMEM; - - for (cpu = 0; cpu < cpus->nr; cpu++) { - for (thread = 0; thread < threads->nr; thread++) { - int fd = FD(evsel, cpu, thread); - - if (evsel->idx || thread) { - if (ioctl(fd, PERF_EVENT_IOC_SET_OUTPUT, - FD(first_evsel, cpu, 0)) != 0) - goto out_unmap; - } else if (__perf_evlist__mmap(evlist, evsel, cpu, - prot, mask, fd) < 0) - goto out_unmap; - - if ((evsel->attr.read_format & PERF_FORMAT_ID) && - perf_evlist__id_add_fd(evlist, evsel, cpu, thread, fd) < 0) - goto out_unmap; - } - } } - return 0; + if (evlist->cpus->map[0] == -1) + return perf_evlist__mmap_per_thread(evlist, prot, mask); -out_unmap: - for (cpu = 0; cpu < cpus->nr; cpu++) { - if (evlist->mmap[cpu].base != NULL) { - munmap(evlist->mmap[cpu].base, evlist->mmap_len); - evlist->mmap[cpu].base = NULL; - } - } - return -1; + return perf_evlist__mmap_per_cpu(evlist, prot, mask); } int perf_evlist__create_maps(struct perf_evlist *evlist, pid_t target_pid, diff --git a/tools/perf/util/evlist.h b/tools/perf/util/evlist.h index 8b1cb7a..7109d7a 100644 --- a/tools/perf/util/evlist.h +++ b/tools/perf/util/evlist.h @@ -17,6 +17,7 @@ struct perf_evlist { struct hlist_head heads[PERF_EVLIST__HLIST_SIZE]; int nr_entries; int nr_fds; + int nr_mmaps; int mmap_len; bool overwrite; union perf_event event_copy; @@ -46,7 +47,7 @@ void perf_evlist__add_pollfd(struct perf_evlist *evlist, int fd); struct perf_evsel *perf_evlist__id2evsel(struct perf_evlist *evlist, u64 id); -union perf_event *perf_evlist__read_on_cpu(struct perf_evlist *self, int cpu); +union perf_event *perf_evlist__mmap_read(struct perf_evlist *self, int idx); int perf_evlist__alloc_mmap(struct perf_evlist *evlist); int perf_evlist__mmap(struct perf_evlist *evlist, int pages, bool overwrite); diff --git a/tools/perf/util/python.c b/tools/perf/util/python.c index f5e3845..99c7226 100644 --- a/tools/perf/util/python.c +++ b/tools/perf/util/python.c @@ -680,7 +680,7 @@ static PyObject *pyrf_evlist__read_on_cpu(struct pyrf_evlist *pevlist, &cpu, &sample_id_all)) return NULL; - event = perf_evlist__read_on_cpu(evlist, cpu); + event = perf_evlist__mmap_read(evlist, cpu); if (event != NULL) { struct perf_evsel *first; PyObject *pyevent = pyrf_event__new(event); -- cgit v0.10.2 From d8083deb4f1aa0977980dfb834fcc336ef38318f Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Fri, 13 May 2011 16:03:24 -0400 Subject: bridge: fix forwarding of IPv6 The commit 6b1e960fdbd75dcd9bcc3ba5ff8898ff1ad30b6e bridge: Reset IPCB when entering IP stack on NF_FORWARD broke forwarding of IPV6 packets in bridge because it would call bp_parse_ip_options with an IPV6 packet. Reported-by: Noah Meyerhans Signed-off-by: Stephen Hemminger Reviewed-by: Eric Dumazet Signed-off-by: David S. Miller Signed-off-by: Pablo Neira Ayuso diff --git a/net/bridge/br_netfilter.c b/net/bridge/br_netfilter.c index f3bc322..74ef4d4 100644 --- a/net/bridge/br_netfilter.c +++ b/net/bridge/br_netfilter.c @@ -737,7 +737,7 @@ static unsigned int br_nf_forward_ip(unsigned int hook, struct sk_buff *skb, nf_bridge->mask |= BRNF_PKT_TYPE; } - if (br_parse_ip_options(skb)) + if (pf == PF_INET && br_parse_ip_options(skb)) return NF_DROP; /* The physdev module checks on this */ -- cgit v0.10.2 From 0f08190fe8af3cdb6ba19690eb0fa253ecef4bde Mon Sep 17 00:00:00 2001 From: Hans Schillstrom Date: Sun, 15 May 2011 17:20:29 +0200 Subject: IPVS: fix netns if reading ip_vs_* procfs entries Without this patch every access to ip_vs in procfs will increase the netns count i.e. an unbalanced get_net()/put_net(). (ipvsadm commands also use procfs.) The result is you can't exit a netns if reading ip_vs_* procfs entries. Signed-off-by: Hans Schillstrom Signed-off-by: Pablo Neira Ayuso diff --git a/net/netfilter/ipvs/ip_vs_app.c b/net/netfilter/ipvs/ip_vs_app.c index 51f3af7..059af31 100644 --- a/net/netfilter/ipvs/ip_vs_app.c +++ b/net/netfilter/ipvs/ip_vs_app.c @@ -572,7 +572,7 @@ static const struct file_operations ip_vs_app_fops = { .open = ip_vs_app_open, .read = seq_read, .llseek = seq_lseek, - .release = seq_release, + .release = seq_release_net, }; #endif diff --git a/net/netfilter/ipvs/ip_vs_conn.c b/net/netfilter/ipvs/ip_vs_conn.c index d3fd91b..bf28ac2 100644 --- a/net/netfilter/ipvs/ip_vs_conn.c +++ b/net/netfilter/ipvs/ip_vs_conn.c @@ -1046,7 +1046,7 @@ static const struct file_operations ip_vs_conn_fops = { .open = ip_vs_conn_open, .read = seq_read, .llseek = seq_lseek, - .release = seq_release, + .release = seq_release_net, }; static const char *ip_vs_origin_name(unsigned flags) @@ -1114,7 +1114,7 @@ static const struct file_operations ip_vs_conn_sync_fops = { .open = ip_vs_conn_sync_open, .read = seq_read, .llseek = seq_lseek, - .release = seq_release, + .release = seq_release_net, }; #endif diff --git a/net/netfilter/ipvs/ip_vs_ctl.c b/net/netfilter/ipvs/ip_vs_ctl.c index ea72281..37890f2 100644 --- a/net/netfilter/ipvs/ip_vs_ctl.c +++ b/net/netfilter/ipvs/ip_vs_ctl.c @@ -2066,7 +2066,7 @@ static const struct file_operations ip_vs_info_fops = { .open = ip_vs_info_open, .read = seq_read, .llseek = seq_lseek, - .release = seq_release_private, + .release = seq_release_net, }; #endif @@ -2109,7 +2109,7 @@ static const struct file_operations ip_vs_stats_fops = { .open = ip_vs_stats_seq_open, .read = seq_read, .llseek = seq_lseek, - .release = single_release, + .release = single_release_net, }; static int ip_vs_stats_percpu_show(struct seq_file *seq, void *v) @@ -2178,7 +2178,7 @@ static const struct file_operations ip_vs_stats_percpu_fops = { .open = ip_vs_stats_percpu_seq_open, .read = seq_read, .llseek = seq_lseek, - .release = single_release, + .release = single_release_net, }; #endif -- cgit v0.10.2 From 0b1e9738deb30f4c35c0add43a52dcd0608b227e Mon Sep 17 00:00:00 2001 From: "sjur.brandeland@stericsson.com" Date: Fri, 13 May 2011 02:43:59 +0000 Subject: caif: Use rcu_read_lock in CAIF mux layer. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Replace spin_lock with rcu_read_lock when accessing lists to layers and cache. While packets are in flight rcu_read_lock should not be held, instead ref-counters are used in combination with RCU. Signed-off-by: Sjur Brændeland Signed-off-by: David S. Miller diff --git a/include/net/caif/cffrml.h b/include/net/caif/cffrml.h index 3f14d2e..4f126d7 100644 --- a/include/net/caif/cffrml.h +++ b/include/net/caif/cffrml.h @@ -12,5 +12,7 @@ struct cffrml; struct cflayer *cffrml_create(u16 phyid, bool DoFCS); void cffrml_set_uplayer(struct cflayer *this, struct cflayer *up); void cffrml_set_dnlayer(struct cflayer *this, struct cflayer *dn); +void cffrml_put(struct cflayer *layr); +void cffrml_hold(struct cflayer *layr); #endif /* CFFRML_H_ */ diff --git a/net/caif/cffrml.c b/net/caif/cffrml.c index 2423fed..f4b8892 100644 --- a/net/caif/cffrml.c +++ b/net/caif/cffrml.c @@ -145,3 +145,11 @@ static void cffrml_ctrlcmd(struct cflayer *layr, enum caif_ctrlcmd ctrl, if (layr->up->ctrlcmd) layr->up->ctrlcmd(layr->up, ctrl, layr->id); } + +void cffrml_put(struct cflayer *layr) +{ +} + +void cffrml_hold(struct cflayer *layr) +{ +} diff --git a/net/caif/cfmuxl.c b/net/caif/cfmuxl.c index fc24974..2a56df7 100644 --- a/net/caif/cfmuxl.c +++ b/net/caif/cfmuxl.c @@ -9,6 +9,7 @@ #include #include #include +#include #include #include #include @@ -64,31 +65,31 @@ struct cflayer *cfmuxl_create(void) int cfmuxl_set_uplayer(struct cflayer *layr, struct cflayer *up, u8 linkid) { struct cfmuxl *muxl = container_obj(layr); - spin_lock(&muxl->receive_lock); - cfsrvl_get(up); - list_add(&up->node, &muxl->srvl_list); - spin_unlock(&muxl->receive_lock); + + spin_lock_bh(&muxl->receive_lock); + list_add_rcu(&up->node, &muxl->srvl_list); + spin_unlock_bh(&muxl->receive_lock); return 0; } int cfmuxl_set_dnlayer(struct cflayer *layr, struct cflayer *dn, u8 phyid) { struct cfmuxl *muxl = (struct cfmuxl *) layr; - spin_lock(&muxl->transmit_lock); - list_add(&dn->node, &muxl->frml_list); - spin_unlock(&muxl->transmit_lock); + + spin_lock_bh(&muxl->transmit_lock); + list_add_rcu(&dn->node, &muxl->frml_list); + spin_unlock_bh(&muxl->transmit_lock); return 0; } static struct cflayer *get_from_id(struct list_head *list, u16 id) { - struct list_head *node; - struct cflayer *layer; - list_for_each(node, list) { - layer = list_entry(node, struct cflayer, node); - if (layer->id == id) - return layer; + struct cflayer *lyr; + list_for_each_entry_rcu(lyr, list, node) { + if (lyr->id == id) + return lyr; } + return NULL; } @@ -96,41 +97,45 @@ struct cflayer *cfmuxl_remove_dnlayer(struct cflayer *layr, u8 phyid) { struct cfmuxl *muxl = container_obj(layr); struct cflayer *dn; - spin_lock(&muxl->transmit_lock); - memset(muxl->dn_cache, 0, sizeof(muxl->dn_cache)); + int idx = phyid % DN_CACHE_SIZE; + + spin_lock_bh(&muxl->transmit_lock); + rcu_assign_pointer(muxl->dn_cache[idx], NULL); dn = get_from_id(&muxl->frml_list, phyid); - if (dn == NULL) { - spin_unlock(&muxl->transmit_lock); - return NULL; - } - list_del(&dn->node); + if (dn == NULL) + goto out; + + list_del_rcu(&dn->node); caif_assert(dn != NULL); - spin_unlock(&muxl->transmit_lock); +out: + spin_unlock_bh(&muxl->transmit_lock); return dn; } -/* Invariant: lock is taken */ static struct cflayer *get_up(struct cfmuxl *muxl, u16 id) { struct cflayer *up; int idx = id % UP_CACHE_SIZE; - up = muxl->up_cache[idx]; + up = rcu_dereference(muxl->up_cache[idx]); if (up == NULL || up->id != id) { + spin_lock_bh(&muxl->receive_lock); up = get_from_id(&muxl->srvl_list, id); - muxl->up_cache[idx] = up; + rcu_assign_pointer(muxl->up_cache[idx], up); + spin_unlock_bh(&muxl->receive_lock); } return up; } -/* Invariant: lock is taken */ static struct cflayer *get_dn(struct cfmuxl *muxl, struct dev_info *dev_info) { struct cflayer *dn; int idx = dev_info->id % DN_CACHE_SIZE; - dn = muxl->dn_cache[idx]; + dn = rcu_dereference(muxl->dn_cache[idx]); if (dn == NULL || dn->id != dev_info->id) { + spin_lock_bh(&muxl->transmit_lock); dn = get_from_id(&muxl->frml_list, dev_info->id); - muxl->dn_cache[idx] = dn; + rcu_assign_pointer(muxl->dn_cache[idx], dn); + spin_unlock_bh(&muxl->transmit_lock); } return dn; } @@ -139,15 +144,17 @@ struct cflayer *cfmuxl_remove_uplayer(struct cflayer *layr, u8 id) { struct cflayer *up; struct cfmuxl *muxl = container_obj(layr); - spin_lock(&muxl->receive_lock); - up = get_up(muxl, id); + int idx = id % UP_CACHE_SIZE; + + spin_lock_bh(&muxl->receive_lock); + up = get_from_id(&muxl->srvl_list, id); if (up == NULL) goto out; - memset(muxl->up_cache, 0, sizeof(muxl->up_cache)); - list_del(&up->node); - cfsrvl_put(up); + + rcu_assign_pointer(muxl->up_cache[idx], NULL); + list_del_rcu(&up->node); out: - spin_unlock(&muxl->receive_lock); + spin_unlock_bh(&muxl->receive_lock); return up; } @@ -162,22 +169,28 @@ static int cfmuxl_receive(struct cflayer *layr, struct cfpkt *pkt) cfpkt_destroy(pkt); return -EPROTO; } - - spin_lock(&muxl->receive_lock); + rcu_read_lock(); up = get_up(muxl, id); - spin_unlock(&muxl->receive_lock); + if (up == NULL) { - pr_info("Received data on unknown link ID = %d (0x%x) up == NULL", - id, id); + pr_debug("Received data on unknown link ID = %d (0x%x)" + " up == NULL", id, id); cfpkt_destroy(pkt); /* * Don't return ERROR, since modem misbehaves and sends out * flow on before linksetup response. */ + + rcu_read_unlock(); return /* CFGLU_EPROT; */ 0; } + + /* We can't hold rcu_lock during receive, so take a ref count instead */ cfsrvl_get(up); + rcu_read_unlock(); + ret = up->receive(up, pkt); + cfsrvl_put(up); return ret; } @@ -185,31 +198,49 @@ static int cfmuxl_receive(struct cflayer *layr, struct cfpkt *pkt) static int cfmuxl_transmit(struct cflayer *layr, struct cfpkt *pkt) { struct cfmuxl *muxl = container_obj(layr); + int err; u8 linkid; struct cflayer *dn; struct caif_payload_info *info = cfpkt_info(pkt); BUG_ON(!info); + + rcu_read_lock(); + dn = get_dn(muxl, info->dev_info); if (dn == NULL) { - pr_warn("Send data on unknown phy ID = %d (0x%x)\n", + pr_debug("Send data on unknown phy ID = %d (0x%x)\n", info->dev_info->id, info->dev_info->id); + rcu_read_unlock(); + cfpkt_destroy(pkt); return -ENOTCONN; } + info->hdr_len += 1; linkid = info->channel_id; cfpkt_add_head(pkt, &linkid, 1); - return dn->transmit(dn, pkt); + + /* We can't hold rcu_lock during receive, so take a ref count instead */ + cffrml_hold(dn); + + rcu_read_unlock(); + + err = dn->transmit(dn, pkt); + + cffrml_put(dn); + return err; } static void cfmuxl_ctrlcmd(struct cflayer *layr, enum caif_ctrlcmd ctrl, int phyid) { struct cfmuxl *muxl = container_obj(layr); - struct list_head *node, *next; struct cflayer *layer; - list_for_each_safe(node, next, &muxl->srvl_list) { - layer = list_entry(node, struct cflayer, node); - if (cfsrvl_phyid_match(layer, phyid)) + + rcu_read_lock(); + list_for_each_entry_rcu(layer, &muxl->srvl_list, node) { + if (cfsrvl_phyid_match(layer, phyid) && layer->ctrlcmd) + /* NOTE: ctrlcmd is not allowed to block */ layer->ctrlcmd(layer, ctrl, phyid); } + rcu_read_unlock(); } -- cgit v0.10.2 From bd30ce4bc0b7dc859c1d1cba7ad87e08642418b0 Mon Sep 17 00:00:00 2001 From: "sjur.brandeland@stericsson.com" Date: Fri, 13 May 2011 02:44:00 +0000 Subject: caif: Use RCU instead of spin-lock in caif_dev.c MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit RCU read_lock and refcount is used to protect in-flight packets. Use RCU and counters to manage freeing lower part of the CAIF stack if CAIF-link layer is removed. Old solution based on delaying removal of device is removed. When CAIF link layer goes down the use of CAIF link layer is disabled (by calling caif_set_phy_state()), but removal and freeing of the lower part of the CAIF stack is done when Link layer is unregistered. Signed-off-by: Sjur Brændeland Signed-off-by: David S. Miller diff --git a/include/net/caif/cfcnfg.h b/include/net/caif/cfcnfg.h index f33d363..e0a1eb5 100644 --- a/include/net/caif/cfcnfg.h +++ b/include/net/caif/cfcnfg.h @@ -145,4 +145,14 @@ struct dev_info *cfcnfg_get_phyid(struct cfcnfg *cnfg, * @ifi: ifindex obtained from socket.c bindtodevice. */ int cfcnfg_get_id_from_ifi(struct cfcnfg *cnfg, int ifi); + +/** + * cfcnfg_set_phy_state() - Set the state of the physical interface device. + * @cnfg: Configuration object + * @phy_layer: Physical Layer representation + * @up: State of device + */ +int cfcnfg_set_phy_state(struct cfcnfg *cnfg, struct cflayer *phy_layer, + bool up); + #endif /* CFCNFG_H_ */ diff --git a/net/caif/caif_dev.c b/net/caif/caif_dev.c index 75e00d5..6d1d86b 100644 --- a/net/caif/caif_dev.c +++ b/net/caif/caif_dev.c @@ -12,14 +12,11 @@ #define pr_fmt(fmt) KBUILD_MODNAME ":%s(): " fmt, __func__ #include -#include #include #include #include #include -#include -#include -#include +#include #include #include #include @@ -30,23 +27,19 @@ #include MODULE_LICENSE("GPL"); -#define TIMEOUT (HZ*5) /* Used for local tracking of the CAIF net devices */ struct caif_device_entry { struct cflayer layer; struct list_head list; - atomic_t in_use; - atomic_t state; - u16 phyid; struct net_device *netdev; - wait_queue_head_t event; + int __percpu *pcpu_refcnt; }; struct caif_device_entry_list { struct list_head list; /* Protects simulanous deletes in list */ - spinlock_t lock; + struct mutex lock; }; struct caif_net { @@ -65,19 +58,39 @@ static struct caif_device_entry_list *caif_device_list(struct net *net) return &caifn->caifdevs; } +static void caifd_put(struct caif_device_entry *e) +{ + irqsafe_cpu_dec(*e->pcpu_refcnt); +} + +static void caifd_hold(struct caif_device_entry *e) +{ + irqsafe_cpu_inc(*e->pcpu_refcnt); +} + +static int caifd_refcnt_read(struct caif_device_entry *e) +{ + int i, refcnt = 0; + for_each_possible_cpu(i) + refcnt += *per_cpu_ptr(e->pcpu_refcnt, i); + return refcnt; +} + /* Allocate new CAIF device. */ static struct caif_device_entry *caif_device_alloc(struct net_device *dev) { struct caif_device_entry_list *caifdevs; struct caif_device_entry *caifd; + caifdevs = caif_device_list(dev_net(dev)); BUG_ON(!caifdevs); + caifd = kzalloc(sizeof(*caifd), GFP_ATOMIC); if (!caifd) return NULL; + caifd->pcpu_refcnt = alloc_percpu(int); caifd->netdev = dev; - list_add(&caifd->list, &caifdevs->list); - init_waitqueue_head(&caifd->event); + dev_hold(dev); return caifd; } @@ -87,35 +100,13 @@ static struct caif_device_entry *caif_get(struct net_device *dev) caif_device_list(dev_net(dev)); struct caif_device_entry *caifd; BUG_ON(!caifdevs); - list_for_each_entry(caifd, &caifdevs->list, list) { + list_for_each_entry_rcu(caifd, &caifdevs->list, list) { if (caifd->netdev == dev) return caifd; } return NULL; } -static void caif_device_destroy(struct net_device *dev) -{ - struct caif_device_entry_list *caifdevs = - caif_device_list(dev_net(dev)); - struct caif_device_entry *caifd; - ASSERT_RTNL(); - if (dev->type != ARPHRD_CAIF) - return; - - spin_lock_bh(&caifdevs->lock); - caifd = caif_get(dev); - if (caifd == NULL) { - spin_unlock_bh(&caifdevs->lock); - return; - } - - list_del(&caifd->list); - spin_unlock_bh(&caifdevs->lock); - - kfree(caifd); -} - static int transmit(struct cflayer *layer, struct cfpkt *pkt) { struct caif_device_entry *caifd = @@ -130,23 +121,8 @@ static int transmit(struct cflayer *layer, struct cfpkt *pkt) return 0; } -static int modemcmd(struct cflayer *layr, enum caif_modemcmd ctrl) -{ - struct caif_device_entry *caifd; - caifd = container_of(layr, struct caif_device_entry, layer); - if (ctrl == _CAIF_MODEMCMD_PHYIF_USEFULL) { - atomic_set(&caifd->in_use, 1); - wake_up_interruptible(&caifd->event); - - } else if (ctrl == _CAIF_MODEMCMD_PHYIF_USELESS) { - atomic_set(&caifd->in_use, 0); - wake_up_interruptible(&caifd->event); - } - return 0; -} - /* - * Stuff received packets to associated sockets. + * Stuff received packets into the CAIF stack. * On error, returns non-zero and releases the skb. */ static int receive(struct sk_buff *skb, struct net_device *dev, @@ -154,14 +130,27 @@ static int receive(struct sk_buff *skb, struct net_device *dev, { struct cfpkt *pkt; struct caif_device_entry *caifd; + pkt = cfpkt_fromnative(CAIF_DIR_IN, skb); + + rcu_read_lock(); caifd = caif_get(dev); - if (!caifd || !caifd->layer.up || !caifd->layer.up->receive) - return NET_RX_DROP; - if (caifd->layer.up->receive(caifd->layer.up, pkt)) + if (!caifd || !caifd->layer.up || !caifd->layer.up->receive || + !netif_oper_up(caifd->netdev)) { + rcu_read_unlock(); + kfree_skb(skb); return NET_RX_DROP; + } + + /* Hold reference to netdevice while using CAIF stack */ + caifd_hold(caifd); + rcu_read_unlock(); + caifd->layer.up->receive(caifd->layer.up, pkt); + + /* Release reference to stack upwards */ + caifd_put(caifd); return 0; } @@ -172,15 +161,25 @@ static struct packet_type caif_packet_type __read_mostly = { static void dev_flowctrl(struct net_device *dev, int on) { - struct caif_device_entry *caifd = caif_get(dev); - if (!caifd || !caifd->layer.up || !caifd->layer.up->ctrlcmd) + struct caif_device_entry *caifd; + + rcu_read_lock(); + + caifd = caif_get(dev); + if (!caifd || !caifd->layer.up || !caifd->layer.up->ctrlcmd) { + rcu_read_unlock(); return; + } + + caifd_hold(caifd); + rcu_read_unlock(); caifd->layer.up->ctrlcmd(caifd->layer.up, on ? _CAIF_CTRLCMD_PHYIF_FLOW_ON_IND : _CAIF_CTRLCMD_PHYIF_FLOW_OFF_IND, caifd->layer.id); + caifd_put(caifd); } /* notify Caif of device events */ @@ -192,34 +191,22 @@ static int caif_device_notify(struct notifier_block *me, unsigned long what, struct caif_dev_common *caifdev; enum cfcnfg_phy_preference pref; enum cfcnfg_phy_type phy_type; + struct caif_device_entry_list *caifdevs = + caif_device_list(dev_net(dev)); if (dev->type != ARPHRD_CAIF) return 0; switch (what) { case NETDEV_REGISTER: - netdev_info(dev, "register\n"); caifd = caif_device_alloc(dev); - if (caifd == NULL) - break; + if (!caifd) + return 0; + caifdev = netdev_priv(dev); caifdev->flowctrl = dev_flowctrl; - atomic_set(&caifd->state, what); - break; - case NETDEV_UP: - netdev_info(dev, "up\n"); - caifd = caif_get(dev); - if (caifd == NULL) - break; - caifdev = netdev_priv(dev); - if (atomic_read(&caifd->state) == NETDEV_UP) { - netdev_info(dev, "already up\n"); - break; - } - atomic_set(&caifd->state, what); caifd->layer.transmit = transmit; - caifd->layer.modemcmd = modemcmd; if (caifdev->use_frag) phy_type = CFPHYTYPE_FRAG; @@ -237,62 +224,95 @@ static int caif_device_notify(struct notifier_block *me, unsigned long what, pref = CFPHYPREF_HIGH_BW; break; } - dev_hold(dev); + strncpy(caifd->layer.name, dev->name, + sizeof(caifd->layer.name) - 1); + caifd->layer.name[sizeof(caifd->layer.name) - 1] = 0; + + mutex_lock(&caifdevs->lock); + list_add_rcu(&caifd->list, &caifdevs->list); + cfcnfg_add_phy_layer(cfg, phy_type, dev, &caifd->layer, - &caifd->phyid, + 0, pref, caifdev->use_fcs, caifdev->use_stx); - strncpy(caifd->layer.name, dev->name, - sizeof(caifd->layer.name) - 1); - caifd->layer.name[sizeof(caifd->layer.name) - 1] = 0; + mutex_unlock(&caifdevs->lock); break; - case NETDEV_GOING_DOWN: + case NETDEV_UP: + rcu_read_lock(); + caifd = caif_get(dev); - if (caifd == NULL) + if (caifd == NULL) { + rcu_read_unlock(); break; - netdev_info(dev, "going down\n"); + } - if (atomic_read(&caifd->state) == NETDEV_GOING_DOWN || - atomic_read(&caifd->state) == NETDEV_DOWN) - break; + cfcnfg_set_phy_state(cfg, &caifd->layer, true); + rcu_read_unlock(); - atomic_set(&caifd->state, what); - if (!caifd || !caifd->layer.up || !caifd->layer.up->ctrlcmd) - return -EINVAL; - caifd->layer.up->ctrlcmd(caifd->layer.up, - _CAIF_CTRLCMD_PHYIF_DOWN_IND, - caifd->layer.id); - might_sleep(); - wait_event_interruptible_timeout(caifd->event, - atomic_read(&caifd->in_use) == 0, - TIMEOUT); break; case NETDEV_DOWN: + rcu_read_lock(); + caifd = caif_get(dev); - if (caifd == NULL) - break; - netdev_info(dev, "down\n"); - if (atomic_read(&caifd->in_use)) - netdev_warn(dev, - "Unregistering an active CAIF device\n"); - cfcnfg_del_phy_layer(cfg, &caifd->layer); - dev_put(dev); - atomic_set(&caifd->state, what); + if (!caifd || !caifd->layer.up || !caifd->layer.up->ctrlcmd) { + rcu_read_unlock(); + return -EINVAL; + } + + cfcnfg_set_phy_state(cfg, &caifd->layer, false); + caifd_hold(caifd); + rcu_read_unlock(); + + caifd->layer.up->ctrlcmd(caifd->layer.up, + _CAIF_CTRLCMD_PHYIF_DOWN_IND, + caifd->layer.id); + caifd_put(caifd); break; case NETDEV_UNREGISTER: + mutex_lock(&caifdevs->lock); + caifd = caif_get(dev); - if (caifd == NULL) + if (caifd == NULL) { + mutex_unlock(&caifdevs->lock); break; - netdev_info(dev, "unregister\n"); - atomic_set(&caifd->state, what); - caif_device_destroy(dev); + } + list_del_rcu(&caifd->list); + + /* + * NETDEV_UNREGISTER is called repeatedly until all reference + * counts for the net-device are released. If references to + * caifd is taken, simply ignore NETDEV_UNREGISTER and wait for + * the next call to NETDEV_UNREGISTER. + * + * If any packets are in flight down the CAIF Stack, + * cfcnfg_del_phy_layer will return nonzero. + * If no packets are in flight, the CAIF Stack associated + * with the net-device un-registering is freed. + */ + + if (caifd_refcnt_read(caifd) != 0 || + cfcnfg_del_phy_layer(cfg, &caifd->layer) != 0) { + + pr_info("Wait for device inuse\n"); + /* Enrole device if CAIF Stack is still in use */ + list_add_rcu(&caifd->list, &caifdevs->list); + mutex_unlock(&caifdevs->lock); + break; + } + + synchronize_rcu(); + dev_put(caifd->netdev); + free_percpu(caifd->pcpu_refcnt); + kfree(caifd); + + mutex_unlock(&caifdevs->lock); break; } return 0; @@ -304,8 +324,8 @@ static struct notifier_block caif_device_notifier = { }; int caif_connect_client(struct caif_connect_request *conn_req, - struct cflayer *client_layer, int *ifindex, - int *headroom, int *tailroom) + struct cflayer *client_layer, int *ifindex, + int *headroom, int *tailroom) { struct cfctrl_link_param param; int ret; @@ -315,8 +335,8 @@ int caif_connect_client(struct caif_connect_request *conn_req, return ret; /* Hook up the adaptation layer. */ return cfcnfg_add_adaptation_layer(cfg, ¶m, - client_layer, ifindex, - headroom, tailroom); + client_layer, ifindex, + headroom, tailroom); } EXPORT_SYMBOL(caif_connect_client); @@ -331,20 +351,40 @@ static int caif_init_net(struct net *net) { struct caif_net *caifn = net_generic(net, caif_net_id); INIT_LIST_HEAD(&caifn->caifdevs.list); - spin_lock_init(&caifn->caifdevs.lock); + mutex_init(&caifn->caifdevs.lock); return 0; } static void caif_exit_net(struct net *net) { - struct net_device *dev; + struct caif_device_entry *caifd, *tmp; + struct caif_device_entry_list *caifdevs = + caif_device_list(net); + rtnl_lock(); - for_each_netdev(net, dev) { - if (dev->type != ARPHRD_CAIF) - continue; - dev_close(dev); - caif_device_destroy(dev); + mutex_lock(&caifdevs->lock); + + list_for_each_entry_safe(caifd, tmp, &caifdevs->list, list) { + int i = 0; + list_del_rcu(&caifd->list); + cfcnfg_set_phy_state(cfg, &caifd->layer, false); + + while (i < 10 && + (caifd_refcnt_read(caifd) != 0 || + cfcnfg_del_phy_layer(cfg, &caifd->layer) != 0)) { + + pr_info("Wait for device inuse\n"); + msleep(250); + i++; + } + synchronize_rcu(); + dev_put(caifd->netdev); + free_percpu(caifd->pcpu_refcnt); + kfree(caifd); } + + + mutex_unlock(&caifdevs->lock); rtnl_unlock(); } @@ -359,6 +399,7 @@ static struct pernet_operations caif_net_ops = { static int __init caif_device_init(void) { int result; + cfg = cfcnfg_create(); if (!cfg) { pr_warn("can't create cfcnfg\n"); -- cgit v0.10.2 From f36214408470ecf6a052e76b72d05b2328b60fcf Mon Sep 17 00:00:00 2001 From: "sjur.brandeland@stericsson.com" Date: Fri, 13 May 2011 02:44:01 +0000 Subject: caif: Use RCU and lists in cfcnfg.c for managing caif link layers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit RCU lists are used for handling the link layers instead of array. When generating CAIF phy-id, ifindex is used as base. Legal range is 1-6. Introduced set_phy_state() for managing CAIF Link layer state. Signed-off-by: Sjur Brændeland Signed-off-by: David S. Miller diff --git a/net/caif/cfcnfg.c b/net/caif/cfcnfg.c index 25c0b19..7892cc0 100644 --- a/net/caif/cfcnfg.c +++ b/net/caif/cfcnfg.c @@ -10,6 +10,7 @@ #include #include #include +#include #include #include #include @@ -18,11 +19,7 @@ #include #include #include - -#include -#include - -#define MAX_PHY_LAYERS 7 +#include #define container_obj(layr) container_of(layr, struct cfcnfg, layer) @@ -30,6 +27,9 @@ * to manage physical interfaces */ struct cfcnfg_phyinfo { + struct list_head node; + bool up; + /* Pointer to the layer below the MUX (framing layer) */ struct cflayer *frm_layer; /* Pointer to the lowest actual physical layer */ @@ -39,9 +39,6 @@ struct cfcnfg_phyinfo { /* Preference of the physical in interface */ enum cfcnfg_phy_preference pref; - /* Reference count, number of channels using the device */ - int phy_ref_count; - /* Information about the physical device */ struct dev_info dev_info; @@ -59,8 +56,8 @@ struct cfcnfg { struct cflayer layer; struct cflayer *ctrl; struct cflayer *mux; - u8 last_phyid; - struct cfcnfg_phyinfo phy_layers[MAX_PHY_LAYERS]; + struct list_head phys; + struct mutex lock; }; static void cfcnfg_linkup_rsp(struct cflayer *layer, u8 channel_id, @@ -76,6 +73,9 @@ struct cfcnfg *cfcnfg_create(void) { struct cfcnfg *this; struct cfctrl_rsp *resp; + + might_sleep(); + /* Initiate this layer */ this = kzalloc(sizeof(struct cfcnfg), GFP_ATOMIC); if (!this) { @@ -99,15 +99,19 @@ struct cfcnfg *cfcnfg_create(void) resp->radioset_rsp = cfctrl_resp_func; resp->linksetup_rsp = cfcnfg_linkup_rsp; resp->reject_rsp = cfcnfg_reject_rsp; - - this->last_phyid = 1; + INIT_LIST_HEAD(&this->phys); cfmuxl_set_uplayer(this->mux, this->ctrl, 0); layer_set_dn(this->ctrl, this->mux); layer_set_up(this->ctrl, this); + mutex_init(&this->lock); + return this; out_of_mem: pr_warn("Out of memory\n"); + + synchronize_rcu(); + kfree(this->mux); kfree(this->ctrl); kfree(this); @@ -117,7 +121,10 @@ EXPORT_SYMBOL(cfcnfg_create); void cfcnfg_remove(struct cfcnfg *cfg) { + might_sleep(); if (cfg) { + synchronize_rcu(); + kfree(cfg->mux); kfree(cfg->ctrl); kfree(cfg); @@ -128,6 +135,17 @@ static void cfctrl_resp_func(void) { } +static struct cfcnfg_phyinfo *cfcnfg_get_phyinfo_rcu(struct cfcnfg *cnfg, + u8 phyid) +{ + struct cfcnfg_phyinfo *phy; + + list_for_each_entry_rcu(phy, &cnfg->phys, node) + if (phy->id == phyid) + return phy; + return NULL; +} + static void cfctrl_enum_resp(void) { } @@ -135,106 +153,65 @@ static void cfctrl_enum_resp(void) struct dev_info *cfcnfg_get_phyid(struct cfcnfg *cnfg, enum cfcnfg_phy_preference phy_pref) { - u16 i; - /* Try to match with specified preference */ - for (i = 1; i < MAX_PHY_LAYERS; i++) { - if (cnfg->phy_layers[i].id == i && - cnfg->phy_layers[i].pref == phy_pref && - cnfg->phy_layers[i].frm_layer != NULL) { - caif_assert(cnfg->phy_layers != NULL); - caif_assert(cnfg->phy_layers[i].id == i); - return &cnfg->phy_layers[i].dev_info; - } - } - /* Otherwise just return something */ - for (i = 1; i < MAX_PHY_LAYERS; i++) { - if (cnfg->phy_layers[i].id == i) { - caif_assert(cnfg->phy_layers != NULL); - caif_assert(cnfg->phy_layers[i].id == i); - return &cnfg->phy_layers[i].dev_info; - } + struct cfcnfg_phyinfo *phy; + + list_for_each_entry_rcu(phy, &cnfg->phys, node) { + if (phy->up && phy->pref == phy_pref && + phy->frm_layer != NULL) + + return &phy->dev_info; } - return NULL; -} + /* Otherwise just return something */ + list_for_each_entry_rcu(phy, &cnfg->phys, node) + if (phy->up) + return &phy->dev_info; -static struct cfcnfg_phyinfo *cfcnfg_get_phyinfo(struct cfcnfg *cnfg, - u8 phyid) -{ - int i; - /* Try to match with specified preference */ - for (i = 0; i < MAX_PHY_LAYERS; i++) - if (cnfg->phy_layers[i].frm_layer != NULL && - cnfg->phy_layers[i].id == phyid) - return &cnfg->phy_layers[i]; return NULL; } - int cfcnfg_get_id_from_ifi(struct cfcnfg *cnfg, int ifi) { - int i; - for (i = 0; i < MAX_PHY_LAYERS; i++) - if (cnfg->phy_layers[i].frm_layer != NULL && - cnfg->phy_layers[i].ifindex == ifi) - return i; + struct cfcnfg_phyinfo *phy; + + list_for_each_entry_rcu(phy, &cnfg->phys, node) + if (phy->ifindex == ifi && phy->up) + return phy->id; return -ENODEV; } -int cfcnfg_disconn_adapt_layer(struct cfcnfg *cnfg, struct cflayer *adap_layer) +int cfcnfg_disconn_adapt_layer(struct cfcnfg *cfg, struct cflayer *adap_layer) { u8 channel_id = 0; int ret = 0; struct cflayer *servl = NULL; - struct cfcnfg_phyinfo *phyinfo = NULL; - u8 phyid = 0; caif_assert(adap_layer != NULL); + channel_id = adap_layer->id; if (adap_layer->dn == NULL || channel_id == 0) { pr_err("adap_layer->dn == NULL or adap_layer->id is 0\n"); ret = -ENOTCONN; goto end; } - servl = cfmuxl_remove_uplayer(cnfg->mux, channel_id); + + servl = cfmuxl_remove_uplayer(cfg->mux, channel_id); if (servl == NULL) { - pr_err("PROTOCOL ERROR - Error removing service_layer Channel_Id(%d)", - channel_id); + pr_err("PROTOCOL ERROR - " + "Error removing service_layer Channel_Id(%d)", + channel_id); ret = -EINVAL; goto end; } - layer_set_up(servl, NULL); - ret = cfctrl_linkdown_req(cnfg->ctrl, channel_id, adap_layer); - if (ret) - goto end; - caif_assert(channel_id == servl->id); - if (adap_layer->dn != NULL) { - phyid = cfsrvl_getphyid(adap_layer->dn); - - phyinfo = cfcnfg_get_phyinfo(cnfg, phyid); - if (phyinfo == NULL) { - pr_warn("No interface to send disconnect to\n"); - ret = -ENODEV; - goto end; - } - if (phyinfo->id != phyid || - phyinfo->phy_layer->id != phyid || - phyinfo->frm_layer->id != phyid) { - pr_err("Inconsistency in phy registration\n"); - ret = -EINVAL; - goto end; - } - } - if (phyinfo != NULL && --phyinfo->phy_ref_count == 0 && - phyinfo->phy_layer != NULL && - phyinfo->phy_layer->modemcmd != NULL) { - phyinfo->phy_layer->modemcmd(phyinfo->phy_layer, - _CAIF_MODEMCMD_PHYIF_USELESS); - } + + ret = cfctrl_linkdown_req(cfg->ctrl, channel_id, adap_layer); + end: - cfsrvl_put(servl); - cfctrl_cancel_req(cnfg->ctrl, adap_layer); + cfctrl_cancel_req(cfg->ctrl, adap_layer); + + /* Do RCU sync before initiating cleanup */ + synchronize_rcu(); if (adap_layer->ctrlcmd != NULL) adap_layer->ctrlcmd(adap_layer, CAIF_CTRLCMD_DEINIT_RSP, 0); return ret; @@ -269,39 +246,56 @@ int cfcnfg_add_adaptation_layer(struct cfcnfg *cnfg, int *proto_tail) { struct cflayer *frml; + struct cfcnfg_phyinfo *phy; + int err; + + rcu_read_lock(); + phy = cfcnfg_get_phyinfo_rcu(cnfg, param->phyid); + if (!phy) { + err = -ENODEV; + goto unlock; + } + err = -EINVAL; + if (adap_layer == NULL) { pr_err("adap_layer is zero\n"); - return -EINVAL; + goto unlock; } if (adap_layer->receive == NULL) { pr_err("adap_layer->receive is NULL\n"); - return -EINVAL; + goto unlock; } if (adap_layer->ctrlcmd == NULL) { pr_err("adap_layer->ctrlcmd == NULL\n"); - return -EINVAL; + goto unlock; } - frml = cnfg->phy_layers[param->phyid].frm_layer; + + err = -ENODEV; + frml = phy->frm_layer; if (frml == NULL) { pr_err("Specified PHY type does not exist!\n"); - return -ENODEV; + goto unlock; } - caif_assert(param->phyid == cnfg->phy_layers[param->phyid].id); - caif_assert(cnfg->phy_layers[param->phyid].frm_layer->id == + caif_assert(param->phyid == phy->id); + caif_assert(phy->frm_layer->id == param->phyid); - caif_assert(cnfg->phy_layers[param->phyid].phy_layer->id == + caif_assert(phy->phy_layer->id == param->phyid); - *ifindex = cnfg->phy_layers[param->phyid].ifindex; + *ifindex = phy->ifindex; + *proto_tail = 2; *proto_head = - protohead[param->linktype]+ - (cnfg->phy_layers[param->phyid].use_stx ? 1 : 0); + protohead[param->linktype] + (phy->use_stx ? 1 : 0); - *proto_tail = 2; + rcu_read_unlock(); /* FIXME: ENUMERATE INITIALLY WHEN ACTIVATING PHYSICAL INTERFACE */ cfctrl_enum_req(cnfg->ctrl, param->phyid); return cfctrl_linkup_request(cnfg->ctrl, param, adap_layer); + +unlock: + rcu_read_unlock(); + return err; } EXPORT_SYMBOL(cfcnfg_add_adaptation_layer); @@ -315,32 +309,37 @@ static void cfcnfg_reject_rsp(struct cflayer *layer, u8 channel_id, static void cfcnfg_linkup_rsp(struct cflayer *layer, u8 channel_id, enum cfctrl_srv serv, - u8 phyid, struct cflayer *adapt_layer) + u8 phyid, struct cflayer *adapt_layer) { struct cfcnfg *cnfg = container_obj(layer); struct cflayer *servicel = NULL; struct cfcnfg_phyinfo *phyinfo; struct net_device *netdev; + rcu_read_lock(); + if (adapt_layer == NULL) { - pr_debug("link setup response but no client exist, send linkdown back\n"); + pr_debug("link setup response but no client exist," + "send linkdown back\n"); cfctrl_linkdown_req(cnfg->ctrl, channel_id, NULL); - return; + goto unlock; } caif_assert(cnfg != NULL); caif_assert(phyid != 0); - phyinfo = &cnfg->phy_layers[phyid]; + + phyinfo = cfcnfg_get_phyinfo_rcu(cnfg, phyid); + if (phyinfo == NULL) { + pr_err("ERROR: Link Layer Device dissapeared" + "while connecting\n"); + goto unlock; + } + + caif_assert(phyinfo != NULL); caif_assert(phyinfo->id == phyid); caif_assert(phyinfo->phy_layer != NULL); caif_assert(phyinfo->phy_layer->id == phyid); - phyinfo->phy_ref_count++; - if (phyinfo->phy_ref_count == 1 && - phyinfo->phy_layer->modemcmd != NULL) { - phyinfo->phy_layer->modemcmd(phyinfo->phy_layer, - _CAIF_MODEMCMD_PHYIF_USEFULL); - } adapt_layer->id = channel_id; switch (serv) { @@ -348,7 +347,8 @@ cfcnfg_linkup_rsp(struct cflayer *layer, u8 channel_id, enum cfctrl_srv serv, servicel = cfvei_create(channel_id, &phyinfo->dev_info); break; case CFCTRL_SRV_DATAGRAM: - servicel = cfdgml_create(channel_id, &phyinfo->dev_info); + servicel = cfdgml_create(channel_id, + &phyinfo->dev_info); break; case CFCTRL_SRV_RFM: netdev = phyinfo->dev_info.dev; @@ -365,94 +365,93 @@ cfcnfg_linkup_rsp(struct cflayer *layer, u8 channel_id, enum cfctrl_srv serv, servicel = cfdbgl_create(channel_id, &phyinfo->dev_info); break; default: - pr_err("Protocol error. Link setup response - unknown channel type\n"); - return; + pr_err("Protocol error. Link setup response " + "- unknown channel type\n"); + goto unlock; } if (!servicel) { pr_warn("Out of memory\n"); - return; + goto unlock; } layer_set_dn(servicel, cnfg->mux); cfmuxl_set_uplayer(cnfg->mux, servicel, channel_id); layer_set_up(servicel, adapt_layer); layer_set_dn(adapt_layer, servicel); - cfsrvl_get(servicel); + + rcu_read_unlock(); + servicel->ctrlcmd(servicel, CAIF_CTRLCMD_INIT_RSP, 0); + return; +unlock: + rcu_read_unlock(); } void cfcnfg_add_phy_layer(struct cfcnfg *cnfg, enum cfcnfg_phy_type phy_type, struct net_device *dev, struct cflayer *phy_layer, - u16 *phyid, enum cfcnfg_phy_preference pref, + u16 *phy_id, enum cfcnfg_phy_preference pref, bool fcs, bool stx) { struct cflayer *frml; struct cflayer *phy_driver = NULL; + struct cfcnfg_phyinfo *phyinfo; int i; + u8 phyid; + mutex_lock(&cnfg->lock); - if (cnfg->phy_layers[cnfg->last_phyid].frm_layer == NULL) { - *phyid = cnfg->last_phyid; - - /* range: * 1..(MAX_PHY_LAYERS-1) */ - cnfg->last_phyid = - (cnfg->last_phyid % (MAX_PHY_LAYERS - 1)) + 1; - } else { - *phyid = 0; - for (i = 1; i < MAX_PHY_LAYERS; i++) { - if (cnfg->phy_layers[i].frm_layer == NULL) { - *phyid = i; - break; - } - } - } - if (*phyid == 0) { - pr_err("No Available PHY ID\n"); - return; + /* CAIF protocol allow maximum 6 link-layers */ + for (i = 0; i < 7; i++) { + phyid = (dev->ifindex + i) & 0x7; + if (phyid == 0) + continue; + if (cfcnfg_get_phyinfo_rcu(cnfg, phyid) == NULL) + goto got_phyid; } + pr_warn("Too many CAIF Link Layers (max 6)\n"); + goto out; + +got_phyid: + phyinfo = kzalloc(sizeof(struct cfcnfg_phyinfo), GFP_ATOMIC); switch (phy_type) { case CFPHYTYPE_FRAG: phy_driver = - cfserl_create(CFPHYTYPE_FRAG, *phyid, stx); + cfserl_create(CFPHYTYPE_FRAG, phyid, stx); if (!phy_driver) { pr_warn("Out of memory\n"); - return; + goto out; } - break; case CFPHYTYPE_CAIF: phy_driver = NULL; break; default: - pr_err("%d\n", phy_type); - return; - break; + goto out; } - - phy_layer->id = *phyid; - cnfg->phy_layers[*phyid].pref = pref; - cnfg->phy_layers[*phyid].id = *phyid; - cnfg->phy_layers[*phyid].dev_info.id = *phyid; - cnfg->phy_layers[*phyid].dev_info.dev = dev; - cnfg->phy_layers[*phyid].phy_layer = phy_layer; - cnfg->phy_layers[*phyid].phy_ref_count = 0; - cnfg->phy_layers[*phyid].ifindex = dev->ifindex; - cnfg->phy_layers[*phyid].use_stx = stx; - cnfg->phy_layers[*phyid].use_fcs = fcs; + phy_layer->id = phyid; + phyinfo->pref = pref; + phyinfo->id = phyid; + phyinfo->dev_info.id = phyid; + phyinfo->dev_info.dev = dev; + phyinfo->phy_layer = phy_layer; + phyinfo->ifindex = dev->ifindex; + phyinfo->use_stx = stx; + phyinfo->use_fcs = fcs; phy_layer->type = phy_type; - frml = cffrml_create(*phyid, fcs); + frml = cffrml_create(phyid, fcs); + if (!frml) { pr_warn("Out of memory\n"); - return; + kfree(phyinfo); + goto out; } - cnfg->phy_layers[*phyid].frm_layer = frml; - cfmuxl_set_dnlayer(cnfg->mux, frml, *phyid); + phyinfo->frm_layer = frml; layer_set_up(frml, cnfg->mux); if (phy_driver != NULL) { - phy_driver->id = *phyid; + phy_driver->id = phyid; layer_set_dn(frml, phy_driver); layer_set_up(phy_driver, frml); layer_set_dn(phy_driver, phy_layer); @@ -461,33 +460,87 @@ cfcnfg_add_phy_layer(struct cfcnfg *cnfg, enum cfcnfg_phy_type phy_type, layer_set_dn(frml, phy_layer); layer_set_up(phy_layer, frml); } + + list_add_rcu(&phyinfo->node, &cnfg->phys); +out: + mutex_unlock(&cnfg->lock); } EXPORT_SYMBOL(cfcnfg_add_phy_layer); +int cfcnfg_set_phy_state(struct cfcnfg *cnfg, struct cflayer *phy_layer, + bool up) +{ + struct cfcnfg_phyinfo *phyinfo; + + rcu_read_lock(); + phyinfo = cfcnfg_get_phyinfo_rcu(cnfg, phy_layer->id); + if (phyinfo == NULL) { + rcu_read_unlock(); + return -ENODEV; + } + + if (phyinfo->up == up) { + rcu_read_unlock(); + return 0; + } + phyinfo->up = up; + + if (up) { + cffrml_hold(phyinfo->frm_layer); + cfmuxl_set_dnlayer(cnfg->mux, phyinfo->frm_layer, + phy_layer->id); + } else { + cfmuxl_remove_dnlayer(cnfg->mux, phy_layer->id); + cffrml_put(phyinfo->frm_layer); + } + + rcu_read_unlock(); + return 0; +} +EXPORT_SYMBOL(cfcnfg_set_phy_state); + int cfcnfg_del_phy_layer(struct cfcnfg *cnfg, struct cflayer *phy_layer) { struct cflayer *frml, *frml_dn; u16 phyid; + struct cfcnfg_phyinfo *phyinfo; + + might_sleep(); + + mutex_lock(&cnfg->lock); + phyid = phy_layer->id; - caif_assert(phyid == cnfg->phy_layers[phyid].id); - caif_assert(phy_layer == cnfg->phy_layers[phyid].phy_layer); + phyinfo = cfcnfg_get_phyinfo_rcu(cnfg, phyid); + + if (phyinfo == NULL) + return 0; + caif_assert(phyid == phyinfo->id); + caif_assert(phy_layer == phyinfo->phy_layer); caif_assert(phy_layer->id == phyid); - caif_assert(cnfg->phy_layers[phyid].frm_layer->id == phyid); + caif_assert(phyinfo->frm_layer->id == phyid); + + list_del_rcu(&phyinfo->node); + synchronize_rcu(); - memset(&cnfg->phy_layers[phy_layer->id], 0, - sizeof(struct cfcnfg_phyinfo)); - frml = cfmuxl_remove_dnlayer(cnfg->mux, phy_layer->id); + frml = phyinfo->frm_layer; frml_dn = frml->dn; cffrml_set_uplayer(frml, NULL); cffrml_set_dnlayer(frml, NULL); - kfree(frml); - if (phy_layer != frml_dn) { layer_set_up(frml_dn, NULL); layer_set_dn(frml_dn, NULL); - kfree(frml_dn); } layer_set_up(phy_layer, NULL); + + + + if (phyinfo->phy_layer != frml_dn) + kfree(frml_dn); + + kfree(frml); + kfree(phyinfo); + mutex_unlock(&cnfg->lock); + return 0; } EXPORT_SYMBOL(cfcnfg_del_phy_layer); -- cgit v0.10.2 From cb3cb423a0f3c627639535e5d87977ae662d779f Mon Sep 17 00:00:00 2001 From: "sjur.brandeland@stericsson.com" Date: Fri, 13 May 2011 02:44:02 +0000 Subject: caif: Add ref-count to framing layer MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Introduce Per-cpu reference for lower part of CAIF Stack. Before freeing payload is disabled, synchronize_rcu() is called, and then ref-count verified to be zero. Signed-off-by: Sjur Brændeland Signed-off-by: David S. Miller diff --git a/include/net/caif/cffrml.h b/include/net/caif/cffrml.h index 4f126d7..afac1a4 100644 --- a/include/net/caif/cffrml.h +++ b/include/net/caif/cffrml.h @@ -7,12 +7,15 @@ #ifndef CFFRML_H_ #define CFFRML_H_ #include +#include struct cffrml; -struct cflayer *cffrml_create(u16 phyid, bool DoFCS); +struct cflayer *cffrml_create(u16 phyid, bool use_fcs); +void cffrml_free(struct cflayer *layr); void cffrml_set_uplayer(struct cflayer *this, struct cflayer *up); void cffrml_set_dnlayer(struct cflayer *this, struct cflayer *dn); void cffrml_put(struct cflayer *layr); void cffrml_hold(struct cflayer *layr); +int cffrml_refcnt_read(struct cflayer *layr); #endif /* CFFRML_H_ */ diff --git a/net/caif/cfcnfg.c b/net/caif/cfcnfg.c index 7892cc0..3f4f31f 100644 --- a/net/caif/cfcnfg.c +++ b/net/caif/cfcnfg.c @@ -519,6 +519,13 @@ int cfcnfg_del_phy_layer(struct cfcnfg *cnfg, struct cflayer *phy_layer) caif_assert(phy_layer->id == phyid); caif_assert(phyinfo->frm_layer->id == phyid); + /* Fail if reference count is not zero */ + if (cffrml_refcnt_read(phyinfo->frm_layer) != 0) { + pr_info("Wait for device inuse\n"); + mutex_unlock(&cnfg->lock); + return -EAGAIN; + } + list_del_rcu(&phyinfo->node); synchronize_rcu(); @@ -537,7 +544,7 @@ int cfcnfg_del_phy_layer(struct cfcnfg *cnfg, struct cflayer *phy_layer) if (phyinfo->phy_layer != frml_dn) kfree(frml_dn); - kfree(frml); + cffrml_free(frml); kfree(phyinfo); mutex_unlock(&cnfg->lock); diff --git a/net/caif/cffrml.c b/net/caif/cffrml.c index f4b8892..4f4f756 100644 --- a/net/caif/cffrml.c +++ b/net/caif/cffrml.c @@ -12,6 +12,7 @@ #include #include #include +#include #include #include #include @@ -21,6 +22,7 @@ struct cffrml { struct cflayer layer; bool dofcs; /* !< FCS active */ + int __percpu *pcpu_refcnt; }; static int cffrml_receive(struct cflayer *layr, struct cfpkt *pkt); @@ -31,12 +33,19 @@ static void cffrml_ctrlcmd(struct cflayer *layr, enum caif_ctrlcmd ctrl, static u32 cffrml_rcv_error; static u32 cffrml_rcv_checsum_error; struct cflayer *cffrml_create(u16 phyid, bool use_fcs) + { struct cffrml *this = kmalloc(sizeof(struct cffrml), GFP_ATOMIC); if (!this) { pr_warn("Out of memory\n"); return NULL; } + this->pcpu_refcnt = alloc_percpu(int); + if (this->pcpu_refcnt == NULL) { + kfree(this); + return NULL; + } + caif_assert(offsetof(struct cffrml, layer) == 0); memset(this, 0, sizeof(struct cflayer)); @@ -49,6 +58,13 @@ struct cflayer *cffrml_create(u16 phyid, bool use_fcs) return (struct cflayer *) this; } +void cffrml_free(struct cflayer *layer) +{ + struct cffrml *this = container_obj(layer); + free_percpu(this->pcpu_refcnt); + kfree(layer); +} + void cffrml_set_uplayer(struct cflayer *this, struct cflayer *up) { this->up = up; @@ -148,8 +164,23 @@ static void cffrml_ctrlcmd(struct cflayer *layr, enum caif_ctrlcmd ctrl, void cffrml_put(struct cflayer *layr) { + struct cffrml *this = container_obj(layr); + if (layr != NULL && this->pcpu_refcnt != NULL) + irqsafe_cpu_dec(*this->pcpu_refcnt); } void cffrml_hold(struct cflayer *layr) { + struct cffrml *this = container_obj(layr); + if (layr != NULL && this->pcpu_refcnt != NULL) + irqsafe_cpu_inc(*this->pcpu_refcnt); +} + +int cffrml_refcnt_read(struct cflayer *layr) +{ + int i, refcnt = 0; + struct cffrml *this = container_obj(layr); + for_each_possible_cpu(i) + refcnt += *per_cpu_ptr(this->pcpu_refcnt, i); + return refcnt; } -- cgit v0.10.2 From 43e3692101086add8719c3b8b50b05c9ac5b14e1 Mon Sep 17 00:00:00 2001 From: "sjur.brandeland@stericsson.com" Date: Fri, 13 May 2011 02:44:03 +0000 Subject: caif: Move refcount from service layer to sock and dev. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Instead of having reference counts in caif service layers, we hook into existing refcount handling in socket layer and netdevice. Signed-off-by: Sjur Brændeland Signed-off-by: David S. Miller diff --git a/include/net/caif/cfsrvl.h b/include/net/caif/cfsrvl.h index 6c8279c..0f59052 100644 --- a/include/net/caif/cfsrvl.h +++ b/include/net/caif/cfsrvl.h @@ -10,6 +10,7 @@ #include #include #include +#include struct cfsrvl { struct cflayer layer; @@ -17,9 +18,11 @@ struct cfsrvl { bool phy_flow_on; bool modem_flow_on; bool supports_flowctrl; - void (*release)(struct kref *); + void (*release)(struct cflayer *layer); struct dev_info dev_info; - struct kref ref; + void (*hold)(struct cflayer *lyr); + void (*put)(struct cflayer *lyr); + struct rcu_head rcu; }; struct cflayer *cfvei_create(u8 linkid, struct dev_info *dev_info); @@ -29,6 +32,10 @@ struct cflayer *cfvidl_create(u8 linkid, struct dev_info *dev_info); struct cflayer *cfrfml_create(u8 linkid, struct dev_info *dev_info, int mtu_size); struct cflayer *cfdbgl_create(u8 linkid, struct dev_info *dev_info); + +void cfsrvl_ctrlcmd(struct cflayer *layr, enum caif_ctrlcmd ctrl, + int phyid); + bool cfsrvl_phyid_match(struct cflayer *layer, int phyid); void cfsrvl_init(struct cfsrvl *service, @@ -40,23 +47,19 @@ u8 cfsrvl_getphyid(struct cflayer *layer); static inline void cfsrvl_get(struct cflayer *layr) { - struct cfsrvl *s; - if (layr == NULL) + struct cfsrvl *s = container_of(layr, struct cfsrvl, layer); + if (layr == NULL || layr->up == NULL || s->hold == NULL) return; - s = container_of(layr, struct cfsrvl, layer); - kref_get(&s->ref); + + s->hold(layr->up); } static inline void cfsrvl_put(struct cflayer *layr) { - struct cfsrvl *s; - if (layr == NULL) + struct cfsrvl *s = container_of(layr, struct cfsrvl, layer); + if (layr == NULL || layr->up == NULL || s->hold == NULL) return; - s = container_of(layr, struct cfsrvl, layer); - WARN_ON(!s->release); - if (s->release) - kref_put(&s->ref, s->release); + s->put(layr->up); } - #endif /* CFSRVL_H_ */ diff --git a/net/caif/cfrfml.c b/net/caif/cfrfml.c index e2fb5fa..0deabb4 100644 --- a/net/caif/cfrfml.c +++ b/net/caif/cfrfml.c @@ -31,9 +31,9 @@ struct cfrfml { spinlock_t sync; }; -static void cfrfml_release(struct kref *kref) +static void cfrfml_release(struct cflayer *layer) { - struct cfsrvl *srvl = container_of(kref, struct cfsrvl, ref); + struct cfsrvl *srvl = container_of(layer, struct cfsrvl, layer); struct cfrfml *rfml = container_obj(&srvl->layer); if (rfml->incomplete_frm) diff --git a/net/caif/cfsrvl.c b/net/caif/cfsrvl.c index 24ba392..535a1e7 100644 --- a/net/caif/cfsrvl.c +++ b/net/caif/cfsrvl.c @@ -10,6 +10,7 @@ #include #include #include +#include #include #include #include @@ -27,8 +28,8 @@ static void cfservl_ctrlcmd(struct cflayer *layr, enum caif_ctrlcmd ctrl, { struct cfsrvl *service = container_obj(layr); - caif_assert(layr->up != NULL); - caif_assert(layr->up->ctrlcmd != NULL); + if (layr->up == NULL || layr->up->ctrlcmd == NULL) + return; switch (ctrl) { case CAIF_CTRLCMD_INIT_RSP: @@ -151,9 +152,9 @@ static int cfservl_modemcmd(struct cflayer *layr, enum caif_modemcmd ctrl) return -EINVAL; } -static void cfsrvl_release(struct kref *kref) +static void cfsrvl_release(struct cflayer *layer) { - struct cfsrvl *service = container_of(kref, struct cfsrvl, ref); + struct cfsrvl *service = container_of(layer, struct cfsrvl, layer); kfree(service); } @@ -173,10 +174,8 @@ void cfsrvl_init(struct cfsrvl *service, service->dev_info = *dev_info; service->supports_flowctrl = supports_flowctrl; service->release = cfsrvl_release; - kref_init(&service->ref); } - bool cfsrvl_ready(struct cfsrvl *service, int *err) { if (service->open && service->modem_flow_on && service->phy_flow_on) @@ -189,6 +188,7 @@ bool cfsrvl_ready(struct cfsrvl *service, int *err) *err = -EAGAIN; return false; } + u8 cfsrvl_getphyid(struct cflayer *layer) { struct cfsrvl *servl = container_obj(layer); @@ -200,3 +200,26 @@ bool cfsrvl_phyid_match(struct cflayer *layer, int phyid) struct cfsrvl *servl = container_obj(layer); return servl->dev_info.id == phyid; } + +void caif_free_client(struct cflayer *adap_layer) +{ + struct cfsrvl *servl; + if (adap_layer == NULL || adap_layer->dn == NULL) + return; + servl = container_obj(adap_layer->dn); + servl->release(&servl->layer); +} +EXPORT_SYMBOL(caif_free_client); + +void caif_client_register_refcnt(struct cflayer *adapt_layer, + void (*hold)(struct cflayer *lyr), + void (*put)(struct cflayer *lyr)) +{ + struct cfsrvl *service; + service = container_of(adapt_layer->dn, struct cfsrvl, layer); + + WARN_ON(adapt_layer == NULL || adapt_layer->dn == NULL); + service->hold = hold; + service->put = put; +} +EXPORT_SYMBOL(caif_client_register_refcnt); -- cgit v0.10.2 From b3ccfbe4098a5542177d0f34e8979f32e7d606e1 Mon Sep 17 00:00:00 2001 From: "sjur.brandeland@stericsson.com" Date: Fri, 13 May 2011 02:44:04 +0000 Subject: caif: Protected in-flight packets using dev or sock refcont. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit CAIF Socket Layer and ip-interface registers reference counters in CAIF service layer. The functions sock_hold, sock_put and dev_hold, dev_put are used by CAIF Stack to protect from freeing memory while packets are in-flight. Signed-off-by: Sjur Brændeland Signed-off-by: David S. Miller diff --git a/include/net/caif/caif_dev.h b/include/net/caif/caif_dev.h index 7e3f7a6..6638435 100644 --- a/include/net/caif/caif_dev.h +++ b/include/net/caif/caif_dev.h @@ -74,6 +74,23 @@ int caif_connect_client(struct caif_connect_request *conn_req, int caif_disconnect_client(struct cflayer *client_layer); /** + * caif_client_register_refcnt - register ref-count functions provided by client. + * + * @adapt_layer: Client layer using CAIF Stack. + * @hold: Function provided by client layer increasing ref-count + * @put: Function provided by client layer decreasing ref-count + * + * Client of the CAIF Stack must register functions for reference counting. + * These functions are called by the CAIF Stack for every upstream packet, + * and must therefore be implemented efficiently. + * + * Client should call caif_free_client when reference count degrease to zero. + */ + +void caif_client_register_refcnt(struct cflayer *adapt_layer, + void (*hold)(struct cflayer *lyr), + void (*put)(struct cflayer *lyr)); +/** * caif_connect_req_to_link_param - Translate configuration parameters * from socket format to internal format. * @cnfg: Pointer to configuration handler @@ -83,8 +100,20 @@ int caif_disconnect_client(struct cflayer *client_layer); * setting up channels. * */ + int caif_connect_req_to_link_param(struct cfcnfg *cnfg, struct caif_connect_request *con_req, struct cfctrl_link_param *setup_param); +/** + * caif_free_client - Free memory used to manage the client in the CAIF Stack. + * + * @client_layer: Client layer to be removed. + * + * This function must be called from client layer in order to free memory. + * Caller must guarantee that no packets are in flight upstream when calling + * this function. + */ +void caif_free_client(struct cflayer *adap_layer); + #endif /* CAIF_DEV_H_ */ diff --git a/net/caif/caif_socket.c b/net/caif/caif_socket.c index 2021242..01f612d 100644 --- a/net/caif/caif_socket.c +++ b/net/caif/caif_socket.c @@ -209,6 +209,18 @@ static int caif_sktrecv_cb(struct cflayer *layr, struct cfpkt *pkt) return 0; } +static void cfsk_hold(struct cflayer *layr) +{ + struct caifsock *cf_sk = container_of(layr, struct caifsock, layer); + sock_hold(&cf_sk->sk); +} + +static void cfsk_put(struct cflayer *layr) +{ + struct caifsock *cf_sk = container_of(layr, struct caifsock, layer); + sock_put(&cf_sk->sk); +} + /* Packet Control Callback function called from CAIF */ static void caif_ctrl_cb(struct cflayer *layr, enum caif_ctrlcmd flow, @@ -232,6 +244,8 @@ static void caif_ctrl_cb(struct cflayer *layr, case CAIF_CTRLCMD_INIT_RSP: /* We're now connected */ + caif_client_register_refcnt(&cf_sk->layer, + cfsk_hold, cfsk_put); dbfs_atomic_inc(&cnt.num_connect_resp); cf_sk->sk.sk_state = CAIF_CONNECTED; set_tx_flow_on(cf_sk); @@ -242,7 +256,6 @@ static void caif_ctrl_cb(struct cflayer *layr, /* We're now disconnected */ cf_sk->sk.sk_state = CAIF_DISCONNECTED; cf_sk->sk.sk_state_change(&cf_sk->sk); - cfcnfg_release_adap_layer(&cf_sk->layer); break; case CAIF_CTRLCMD_INIT_FAIL_RSP: @@ -837,8 +850,10 @@ static int caif_connect(struct socket *sock, struct sockaddr *uaddr, dbfs_atomic_inc(&cnt.num_connect_req); cf_sk->layer.receive = caif_sktrecv_cb; + err = caif_connect_client(&cf_sk->conn_req, &cf_sk->layer, &ifindex, &headroom, &tailroom); + if (err < 0) { cf_sk->sk.sk_socket->state = SS_UNCONNECTED; cf_sk->sk.sk_state = CAIF_DISCONNECTED; @@ -940,7 +955,6 @@ static int caif_release(struct socket *sock) wake_up_interruptible_poll(sk_sleep(sk), POLLERR|POLLHUP); sock_orphan(sk); - cf_sk->layer.dn = NULL; sk_stream_kill_queues(&cf_sk->sk); release_sock(sk); sock_put(sk); @@ -1036,6 +1050,7 @@ static void caif_sock_destructor(struct sock *sk) } sk_stream_kill_queues(&cf_sk->sk); dbfs_atomic_dec(&cnt.caif_nr_socks); + caif_free_client(&cf_sk->layer); } static int caif_create(struct net *net, struct socket *sock, int protocol, diff --git a/net/caif/chnl_net.c b/net/caif/chnl_net.c index 6008d6d..9ef8f16 100644 --- a/net/caif/chnl_net.c +++ b/net/caif/chnl_net.c @@ -153,6 +153,18 @@ static void close_work(struct work_struct *work) } static DECLARE_WORK(close_worker, close_work); +static void chnl_hold(struct cflayer *lyr) +{ + struct chnl_net *priv = container_of(lyr, struct chnl_net, chnl); + dev_hold(priv->netdev); +} + +static void chnl_put(struct cflayer *lyr) +{ + struct chnl_net *priv = container_of(lyr, struct chnl_net, chnl); + dev_put(priv->netdev); +} + static void chnl_flowctrl_cb(struct cflayer *layr, enum caif_ctrlcmd flow, int phyid) { @@ -190,6 +202,7 @@ static void chnl_flowctrl_cb(struct cflayer *layr, enum caif_ctrlcmd flow, netif_wake_queue(priv->netdev); break; case CAIF_CTRLCMD_INIT_RSP: + caif_client_register_refcnt(&priv->chnl, chnl_hold, chnl_put); priv->state = CAIF_CONNECTED; priv->flowenabled = true; netif_wake_queue(priv->netdev); @@ -373,11 +386,18 @@ static const struct net_device_ops netdev_ops = { .ndo_start_xmit = chnl_net_start_xmit, }; +static void chnl_net_destructor(struct net_device *dev) +{ + struct chnl_net *priv = netdev_priv(dev); + caif_free_client(&priv->chnl); + free_netdev(dev); +} + static void ipcaif_net_setup(struct net_device *dev) { struct chnl_net *priv; dev->netdev_ops = &netdev_ops; - dev->destructor = free_netdev; + dev->destructor = chnl_net_destructor; dev->flags |= IFF_NOARP; dev->flags |= IFF_POINTOPOINT; dev->mtu = GPRS_PDP_MTU; @@ -391,7 +411,7 @@ static void ipcaif_net_setup(struct net_device *dev) priv->conn_req.link_selector = CAIF_LINK_HIGH_BANDW; priv->conn_req.priority = CAIF_PRIO_LOW; /* Insert illegal value */ - priv->conn_req.sockaddr.u.dgm.connection_id = -1; + priv->conn_req.sockaddr.u.dgm.connection_id = 0; priv->flowenabled = false; init_waitqueue_head(&priv->netmgmt_wq); @@ -453,6 +473,10 @@ static int ipcaif_newlink(struct net *src_net, struct net_device *dev, pr_warn("device rtml registration failed\n"); else list_add(&caifdev->list_field, &chnl_net_list); + + /* Take ifindex as connection-id if null */ + if (caifdev->conn_req.sockaddr.u.dgm.connection_id == 0) + caifdev->conn_req.sockaddr.u.dgm.connection_id = dev->ifindex; return ret; } -- cgit v0.10.2 From bee925db9a77a5736596dcf6f91d0879f5ee915b Mon Sep 17 00:00:00 2001 From: "sjur.brandeland@stericsson.com" Date: Fri, 13 May 2011 02:44:05 +0000 Subject: caif: prepare support for namespaces MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use struct net to reference CAIF configuration object instead of static variables. Refactor functions caif_connect_client, caif_disconnect_client and squach files cfcnfg.c and caif_config_utils. Signed-off-by: Sjur Brændeland Signed-off-by: David S. Miller diff --git a/include/net/caif/caif_dev.h b/include/net/caif/caif_dev.h index 6638435..c011281 100644 --- a/include/net/caif/caif_dev.h +++ b/include/net/caif/caif_dev.h @@ -11,6 +11,7 @@ #include #include #include +#include /** * struct caif_param - CAIF parameters. @@ -62,16 +63,18 @@ struct caif_connect_request { * E.g. CAIF Socket will call this function for each socket it connects * and have one client_layer instance for each socket. */ -int caif_connect_client(struct caif_connect_request *conn_req, +int caif_connect_client(struct net *net, + struct caif_connect_request *conn_req, struct cflayer *client_layer, int *ifindex, int *headroom, int *tailroom); /** * caif_disconnect_client - Disconnects a client from the CAIF stack. * - * @client_layer: Client layer to be removed. + * @client_layer: Client layer to be disconnected. */ -int caif_disconnect_client(struct cflayer *client_layer); +int caif_disconnect_client(struct net *net, struct cflayer *client_layer); + /** * caif_client_register_refcnt - register ref-count functions provided by client. @@ -91,21 +94,6 @@ void caif_client_register_refcnt(struct cflayer *adapt_layer, void (*hold)(struct cflayer *lyr), void (*put)(struct cflayer *lyr)); /** - * caif_connect_req_to_link_param - Translate configuration parameters - * from socket format to internal format. - * @cnfg: Pointer to configuration handler - * @con_req: Configuration parameters supplied in function - * caif_connect_client - * @channel_setup_param: Parameters supplied to the CAIF Core stack for - * setting up channels. - * - */ - -int caif_connect_req_to_link_param(struct cfcnfg *cnfg, - struct caif_connect_request *con_req, - struct cfctrl_link_param *setup_param); - -/** * caif_free_client - Free memory used to manage the client in the CAIF Stack. * * @client_layer: Client layer to be removed. diff --git a/include/net/caif/cfcnfg.h b/include/net/caif/cfcnfg.h index e0a1eb5..3e93a4a 100644 --- a/include/net/caif/cfcnfg.h +++ b/include/net/caif/cfcnfg.h @@ -46,6 +46,12 @@ enum cfcnfg_phy_preference { }; /** + * cfcnfg_create() - Get the CAIF configuration object given network. + * @net: Network for the CAIF configuration object. + */ +struct cfcnfg *get_cfcnfg(struct net *net); + +/** * cfcnfg_create() - Create the CAIF configuration object. */ struct cfcnfg *cfcnfg_create(void); @@ -65,17 +71,15 @@ void cfcnfg_remove(struct cfcnfg *cfg); * @dev: Pointer to link layer device * @phy_layer: Specify the physical layer. The transmit function * MUST be set in the structure. - * @phyid: The assigned physical ID for this layer, used in - * cfcnfg_add_adapt_layer to specify PHY for the link. * @pref: The phy (link layer) preference. * @fcs: Specify if checksum is used in CAIF Framing Layer. - * @stx: Specify if Start Of Frame extension is used. + * @stx: Specify if Start Of Frame eXtention is used. */ void cfcnfg_add_phy_layer(struct cfcnfg *cnfg, enum cfcnfg_phy_type phy_type, struct net_device *dev, struct cflayer *phy_layer, - u16 *phyid, enum cfcnfg_phy_preference pref, + enum cfcnfg_phy_preference pref, bool fcs, bool stx); /** @@ -88,65 +92,6 @@ cfcnfg_add_phy_layer(struct cfcnfg *cnfg, enum cfcnfg_phy_type phy_type, int cfcnfg_del_phy_layer(struct cfcnfg *cnfg, struct cflayer *phy_layer); /** - * cfcnfg_disconn_adapt_layer - Disconnects an adaptation layer. - * - * @cnfg: Pointer to a CAIF configuration object, created by - * cfcnfg_create(). - * @adap_layer: Adaptation layer to be removed. - */ -int cfcnfg_disconn_adapt_layer(struct cfcnfg *cnfg, - struct cflayer *adap_layer); - -/** - * cfcnfg_release_adap_layer - Used by client to release the adaptation layer. - * - * @adap_layer: Adaptation layer. - */ -void cfcnfg_release_adap_layer(struct cflayer *adap_layer); - -/** - * cfcnfg_add_adaptation_layer - Add an adaptation layer to the CAIF stack. - * - * The adaptation Layer is where the interface to application or higher-level - * driver functionality is implemented. - * - * @cnfg: Pointer to a CAIF configuration object, created by - * cfcnfg_create(). - * @param: Link setup parameters. - * @adap_layer: Specify the adaptation layer; the receive and - * flow-control functions MUST be set in the structure. - * @ifindex: Link layer interface index used for this connection. - * @proto_head: Protocol head-space needed by CAIF protocol, - * excluding link layer. - * @proto_tail: Protocol tail-space needed by CAIF protocol, - * excluding link layer. - */ -int cfcnfg_add_adaptation_layer(struct cfcnfg *cnfg, - struct cfctrl_link_param *param, - struct cflayer *adap_layer, - int *ifindex, - int *proto_head, - int *proto_tail); - -/** - * cfcnfg_get_phyid() - Get physical ID, given type. - * Returns one of the physical interfaces matching the given type. - * Zero if no match is found. - * @cnfg: Configuration object - * @phy_pref: Caif Link Layer preference - */ -struct dev_info *cfcnfg_get_phyid(struct cfcnfg *cnfg, - enum cfcnfg_phy_preference phy_pref); - -/** - * cfcnfg_get_id_from_ifi() - Get the Physical Identifier of ifindex, - * it matches caif physical id with the kernel interface id. - * @cnfg: Configuration object - * @ifi: ifindex obtained from socket.c bindtodevice. - */ -int cfcnfg_get_id_from_ifi(struct cfcnfg *cnfg, int ifi); - -/** * cfcnfg_set_phy_state() - Set the state of the physical interface device. * @cnfg: Configuration object * @phy_layer: Physical Layer representation diff --git a/net/caif/Makefile b/net/caif/Makefile index 9d38e40..ebcd4e7 100644 --- a/net/caif/Makefile +++ b/net/caif/Makefile @@ -5,7 +5,7 @@ caif-y := caif_dev.o \ cffrml.o cfveil.o cfdbgl.o\ cfserl.o cfdgml.o \ cfrfml.o cfvidl.o cfutill.o \ - cfsrvl.o cfpkt_skbuff.o caif_config_util.o + cfsrvl.o cfpkt_skbuff.o obj-$(CONFIG_CAIF) += caif.o obj-$(CONFIG_CAIF_NETDEV) += chnl_net.o diff --git a/net/caif/caif_config_util.c b/net/caif/caif_config_util.c deleted file mode 100644 index 9b63e4e..0000000 --- a/net/caif/caif_config_util.c +++ /dev/null @@ -1,99 +0,0 @@ -/* - * Copyright (C) ST-Ericsson AB 2010 - * Author: Sjur Brendeland sjur.brandeland@stericsson.com - * License terms: GNU General Public License (GPL) version 2 - */ - -#include -#include -#include -#include -#include - -int caif_connect_req_to_link_param(struct cfcnfg *cnfg, - struct caif_connect_request *s, - struct cfctrl_link_param *l) -{ - struct dev_info *dev_info; - enum cfcnfg_phy_preference pref; - int res; - - memset(l, 0, sizeof(*l)); - /* In caif protocol low value is high priority */ - l->priority = CAIF_PRIO_MAX - s->priority + 1; - - if (s->ifindex != 0){ - res = cfcnfg_get_id_from_ifi(cnfg, s->ifindex); - if (res < 0) - return res; - l->phyid = res; - } - else { - switch (s->link_selector) { - case CAIF_LINK_HIGH_BANDW: - pref = CFPHYPREF_HIGH_BW; - break; - case CAIF_LINK_LOW_LATENCY: - pref = CFPHYPREF_LOW_LAT; - break; - default: - return -EINVAL; - } - dev_info = cfcnfg_get_phyid(cnfg, pref); - if (dev_info == NULL) - return -ENODEV; - l->phyid = dev_info->id; - } - switch (s->protocol) { - case CAIFPROTO_AT: - l->linktype = CFCTRL_SRV_VEI; - if (s->sockaddr.u.at.type == CAIF_ATTYPE_PLAIN) - l->chtype = 0x02; - else - l->chtype = s->sockaddr.u.at.type; - l->endpoint = 0x00; - break; - case CAIFPROTO_DATAGRAM: - l->linktype = CFCTRL_SRV_DATAGRAM; - l->chtype = 0x00; - l->u.datagram.connid = s->sockaddr.u.dgm.connection_id; - break; - case CAIFPROTO_DATAGRAM_LOOP: - l->linktype = CFCTRL_SRV_DATAGRAM; - l->chtype = 0x03; - l->endpoint = 0x00; - l->u.datagram.connid = s->sockaddr.u.dgm.connection_id; - break; - case CAIFPROTO_RFM: - l->linktype = CFCTRL_SRV_RFM; - l->u.datagram.connid = s->sockaddr.u.rfm.connection_id; - strncpy(l->u.rfm.volume, s->sockaddr.u.rfm.volume, - sizeof(l->u.rfm.volume)-1); - l->u.rfm.volume[sizeof(l->u.rfm.volume)-1] = 0; - break; - case CAIFPROTO_UTIL: - l->linktype = CFCTRL_SRV_UTIL; - l->endpoint = 0x00; - l->chtype = 0x00; - strncpy(l->u.utility.name, s->sockaddr.u.util.service, - sizeof(l->u.utility.name)-1); - l->u.utility.name[sizeof(l->u.utility.name)-1] = 0; - caif_assert(sizeof(l->u.utility.name) > 10); - l->u.utility.paramlen = s->param.size; - if (l->u.utility.paramlen > sizeof(l->u.utility.params)) - l->u.utility.paramlen = sizeof(l->u.utility.params); - - memcpy(l->u.utility.params, s->param.data, - l->u.utility.paramlen); - - break; - case CAIFPROTO_DEBUG: - l->linktype = CFCTRL_SRV_DBG; - l->endpoint = s->sockaddr.u.dbg.service; - l->chtype = s->sockaddr.u.dbg.type; - break; - default: - return -EINVAL; - } - return 0; -} diff --git a/net/caif/caif_dev.c b/net/caif/caif_dev.c index 6d1d86b..0e651cf 100644 --- a/net/caif/caif_dev.c +++ b/net/caif/caif_dev.c @@ -21,7 +21,6 @@ #include #include #include -#include #include #include #include @@ -43,11 +42,21 @@ struct caif_device_entry_list { }; struct caif_net { + struct cfcnfg *cfg; struct caif_device_entry_list caifdevs; }; static int caif_net_id; -static struct cfcnfg *cfg; + +struct cfcnfg *get_cfcnfg(struct net *net) +{ + struct caif_net *caifn; + BUG_ON(!net); + caifn = net_generic(net, caif_net_id); + BUG_ON(!caifn); + return caifn->cfg; +} +EXPORT_SYMBOL(get_cfcnfg); static struct caif_device_entry_list *caif_device_list(struct net *net) { @@ -191,12 +200,17 @@ static int caif_device_notify(struct notifier_block *me, unsigned long what, struct caif_dev_common *caifdev; enum cfcnfg_phy_preference pref; enum cfcnfg_phy_type phy_type; + struct cfcnfg *cfg; struct caif_device_entry_list *caifdevs = caif_device_list(dev_net(dev)); if (dev->type != ARPHRD_CAIF) return 0; + cfg = get_cfcnfg(dev_net(dev)); + if (cfg == NULL) + return 0; + switch (what) { case NETDEV_REGISTER: caifd = caif_device_alloc(dev); @@ -235,7 +249,6 @@ static int caif_device_notify(struct notifier_block *me, unsigned long what, phy_type, dev, &caifd->layer, - 0, pref, caifdev->use_fcs, caifdev->use_stx); @@ -323,35 +336,20 @@ static struct notifier_block caif_device_notifier = { .priority = 0, }; -int caif_connect_client(struct caif_connect_request *conn_req, - struct cflayer *client_layer, int *ifindex, - int *headroom, int *tailroom) -{ - struct cfctrl_link_param param; - int ret; - - ret = caif_connect_req_to_link_param(cfg, conn_req, ¶m); - if (ret) - return ret; - /* Hook up the adaptation layer. */ - return cfcnfg_add_adaptation_layer(cfg, ¶m, - client_layer, ifindex, - headroom, tailroom); -} -EXPORT_SYMBOL(caif_connect_client); - -int caif_disconnect_client(struct cflayer *adap_layer) -{ - return cfcnfg_disconn_adapt_layer(cfg, adap_layer); -} -EXPORT_SYMBOL(caif_disconnect_client); - /* Per-namespace Caif devices handling */ static int caif_init_net(struct net *net) { struct caif_net *caifn = net_generic(net, caif_net_id); + BUG_ON(!caifn); INIT_LIST_HEAD(&caifn->caifdevs.list); mutex_init(&caifn->caifdevs.lock); + + caifn->cfg = cfcnfg_create(); + if (!caifn->cfg) { + pr_warn("can't create cfcnfg\n"); + return -ENOMEM; + } + return 0; } @@ -360,10 +358,17 @@ static void caif_exit_net(struct net *net) struct caif_device_entry *caifd, *tmp; struct caif_device_entry_list *caifdevs = caif_device_list(net); + struct cfcnfg *cfg; rtnl_lock(); mutex_lock(&caifdevs->lock); + cfg = get_cfcnfg(net); + if (cfg == NULL) { + mutex_unlock(&caifdevs->lock); + return; + } + list_for_each_entry_safe(caifd, tmp, &caifdevs->list, list) { int i = 0; list_del_rcu(&caifd->list); @@ -382,7 +387,7 @@ static void caif_exit_net(struct net *net) free_percpu(caifd->pcpu_refcnt); kfree(caifd); } - + cfcnfg_remove(cfg); mutex_unlock(&caifdevs->lock); rtnl_unlock(); @@ -400,32 +405,22 @@ static int __init caif_device_init(void) { int result; - cfg = cfcnfg_create(); - if (!cfg) { - pr_warn("can't create cfcnfg\n"); - goto err_cfcnfg_create_failed; - } result = register_pernet_device(&caif_net_ops); - if (result) { - kfree(cfg); - cfg = NULL; + if (result) return result; - } - dev_add_pack(&caif_packet_type); + register_netdevice_notifier(&caif_device_notifier); + dev_add_pack(&caif_packet_type); return result; -err_cfcnfg_create_failed: - return -ENODEV; } static void __exit caif_device_exit(void) { - dev_remove_pack(&caif_packet_type); unregister_pernet_device(&caif_net_ops); unregister_netdevice_notifier(&caif_device_notifier); - cfcnfg_remove(cfg); + dev_remove_pack(&caif_packet_type); } module_init(caif_device_init); diff --git a/net/caif/caif_socket.c b/net/caif/caif_socket.c index 01f612d..653db75 100644 --- a/net/caif/caif_socket.c +++ b/net/caif/caif_socket.c @@ -810,7 +810,7 @@ static int caif_connect(struct socket *sock, struct sockaddr *uaddr, sk->sk_state == CAIF_DISCONNECTED); if (sk->sk_shutdown & SHUTDOWN_MASK) { /* Allow re-connect after SHUTDOWN_IND */ - caif_disconnect_client(&cf_sk->layer); + caif_disconnect_client(sock_net(sk), &cf_sk->layer); break; } /* No reconnect on a seqpacket socket */ @@ -851,7 +851,7 @@ static int caif_connect(struct socket *sock, struct sockaddr *uaddr, dbfs_atomic_inc(&cnt.num_connect_req); cf_sk->layer.receive = caif_sktrecv_cb; - err = caif_connect_client(&cf_sk->conn_req, + err = caif_connect_client(sock_net(sk), &cf_sk->conn_req, &cf_sk->layer, &ifindex, &headroom, &tailroom); if (err < 0) { @@ -949,7 +949,7 @@ static int caif_release(struct socket *sock) if (cf_sk->sk.sk_socket->state == SS_CONNECTED || cf_sk->sk.sk_socket->state == SS_CONNECTING) - res = caif_disconnect_client(&cf_sk->layer); + res = caif_disconnect_client(sock_net(sk), &cf_sk->layer); cf_sk->sk.sk_socket->state = SS_DISCONNECTING; wake_up_interruptible_poll(sk_sleep(sk), POLLERR|POLLHUP); diff --git a/net/caif/cfcnfg.c b/net/caif/cfcnfg.c index 3f4f31f..e857d89 100644 --- a/net/caif/cfcnfg.c +++ b/net/caif/cfcnfg.c @@ -150,7 +150,7 @@ static void cfctrl_enum_resp(void) { } -struct dev_info *cfcnfg_get_phyid(struct cfcnfg *cnfg, +static struct dev_info *cfcnfg_get_phyid(struct cfcnfg *cnfg, enum cfcnfg_phy_preference phy_pref) { /* Try to match with specified preference */ @@ -171,7 +171,7 @@ struct dev_info *cfcnfg_get_phyid(struct cfcnfg *cnfg, return NULL; } -int cfcnfg_get_id_from_ifi(struct cfcnfg *cnfg, int ifi) +static int cfcnfg_get_id_from_ifi(struct cfcnfg *cnfg, int ifi) { struct cfcnfg_phyinfo *phy; @@ -181,11 +181,12 @@ int cfcnfg_get_id_from_ifi(struct cfcnfg *cnfg, int ifi) return -ENODEV; } -int cfcnfg_disconn_adapt_layer(struct cfcnfg *cfg, struct cflayer *adap_layer) +int caif_disconnect_client(struct net *net, struct cflayer *adap_layer) { u8 channel_id = 0; int ret = 0; struct cflayer *servl = NULL; + struct cfcnfg *cfg = get_cfcnfg(net); caif_assert(adap_layer != NULL); @@ -217,14 +218,7 @@ end: return ret; } -EXPORT_SYMBOL(cfcnfg_disconn_adapt_layer); - -void cfcnfg_release_adap_layer(struct cflayer *adap_layer) -{ - if (adap_layer->dn) - cfsrvl_put(adap_layer->dn); -} -EXPORT_SYMBOL(cfcnfg_release_adap_layer); +EXPORT_SYMBOL(caif_disconnect_client); static void cfcnfg_linkdestroy_rsp(struct cflayer *layer, u8 channel_id) { @@ -238,19 +232,109 @@ static const int protohead[CFCTRL_SRV_MASK] = { [CFCTRL_SRV_DBG] = 3, }; -int cfcnfg_add_adaptation_layer(struct cfcnfg *cnfg, - struct cfctrl_link_param *param, - struct cflayer *adap_layer, - int *ifindex, + +static int caif_connect_req_to_link_param(struct cfcnfg *cnfg, + struct caif_connect_request *s, + struct cfctrl_link_param *l) +{ + struct dev_info *dev_info; + enum cfcnfg_phy_preference pref; + int res; + + memset(l, 0, sizeof(*l)); + /* In caif protocol low value is high priority */ + l->priority = CAIF_PRIO_MAX - s->priority + 1; + + if (s->ifindex != 0) { + res = cfcnfg_get_id_from_ifi(cnfg, s->ifindex); + if (res < 0) + return res; + l->phyid = res; + } else { + switch (s->link_selector) { + case CAIF_LINK_HIGH_BANDW: + pref = CFPHYPREF_HIGH_BW; + break; + case CAIF_LINK_LOW_LATENCY: + pref = CFPHYPREF_LOW_LAT; + break; + default: + return -EINVAL; + } + dev_info = cfcnfg_get_phyid(cnfg, pref); + if (dev_info == NULL) + return -ENODEV; + l->phyid = dev_info->id; + } + switch (s->protocol) { + case CAIFPROTO_AT: + l->linktype = CFCTRL_SRV_VEI; + l->endpoint = (s->sockaddr.u.at.type >> 2) & 0x3; + l->chtype = s->sockaddr.u.at.type & 0x3; + break; + case CAIFPROTO_DATAGRAM: + l->linktype = CFCTRL_SRV_DATAGRAM; + l->chtype = 0x00; + l->u.datagram.connid = s->sockaddr.u.dgm.connection_id; + break; + case CAIFPROTO_DATAGRAM_LOOP: + l->linktype = CFCTRL_SRV_DATAGRAM; + l->chtype = 0x03; + l->endpoint = 0x00; + l->u.datagram.connid = s->sockaddr.u.dgm.connection_id; + break; + case CAIFPROTO_RFM: + l->linktype = CFCTRL_SRV_RFM; + l->u.datagram.connid = s->sockaddr.u.rfm.connection_id; + strncpy(l->u.rfm.volume, s->sockaddr.u.rfm.volume, + sizeof(l->u.rfm.volume)-1); + l->u.rfm.volume[sizeof(l->u.rfm.volume)-1] = 0; + break; + case CAIFPROTO_UTIL: + l->linktype = CFCTRL_SRV_UTIL; + l->endpoint = 0x00; + l->chtype = 0x00; + strncpy(l->u.utility.name, s->sockaddr.u.util.service, + sizeof(l->u.utility.name)-1); + l->u.utility.name[sizeof(l->u.utility.name)-1] = 0; + caif_assert(sizeof(l->u.utility.name) > 10); + l->u.utility.paramlen = s->param.size; + if (l->u.utility.paramlen > sizeof(l->u.utility.params)) + l->u.utility.paramlen = sizeof(l->u.utility.params); + + memcpy(l->u.utility.params, s->param.data, + l->u.utility.paramlen); + + break; + case CAIFPROTO_DEBUG: + l->linktype = CFCTRL_SRV_DBG; + l->endpoint = s->sockaddr.u.dbg.service; + l->chtype = s->sockaddr.u.dbg.type; + break; + default: + return -EINVAL; + } + return 0; +} + +int caif_connect_client(struct net *net, struct caif_connect_request *conn_req, + struct cflayer *adap_layer, int *ifindex, int *proto_head, int *proto_tail) { struct cflayer *frml; struct cfcnfg_phyinfo *phy; int err; + struct cfctrl_link_param param; + struct cfcnfg *cfg = get_cfcnfg(net); + caif_assert(cfg != NULL); rcu_read_lock(); - phy = cfcnfg_get_phyinfo_rcu(cnfg, param->phyid); + err = caif_connect_req_to_link_param(cfg, conn_req, ¶m); + if (err) + goto unlock; + + phy = cfcnfg_get_phyinfo_rcu(cfg, param.phyid); if (!phy) { err = -ENODEV; goto unlock; @@ -276,28 +360,29 @@ int cfcnfg_add_adaptation_layer(struct cfcnfg *cnfg, pr_err("Specified PHY type does not exist!\n"); goto unlock; } - caif_assert(param->phyid == phy->id); + caif_assert(param.phyid == phy->id); caif_assert(phy->frm_layer->id == - param->phyid); + param.phyid); caif_assert(phy->phy_layer->id == - param->phyid); + param.phyid); *ifindex = phy->ifindex; *proto_tail = 2; *proto_head = - protohead[param->linktype] + (phy->use_stx ? 1 : 0); + + protohead[param.linktype] + (phy->use_stx ? 1 : 0); rcu_read_unlock(); /* FIXME: ENUMERATE INITIALLY WHEN ACTIVATING PHYSICAL INTERFACE */ - cfctrl_enum_req(cnfg->ctrl, param->phyid); - return cfctrl_linkup_request(cnfg->ctrl, param, adap_layer); + cfctrl_enum_req(cfg->ctrl, param.phyid); + return cfctrl_linkup_request(cfg->ctrl, ¶m, adap_layer); unlock: rcu_read_unlock(); return err; } -EXPORT_SYMBOL(cfcnfg_add_adaptation_layer); +EXPORT_SYMBOL(caif_connect_client); static void cfcnfg_reject_rsp(struct cflayer *layer, u8 channel_id, struct cflayer *adapt_layer) @@ -389,7 +474,7 @@ unlock: void cfcnfg_add_phy_layer(struct cfcnfg *cnfg, enum cfcnfg_phy_type phy_type, struct net_device *dev, struct cflayer *phy_layer, - u16 *phy_id, enum cfcnfg_phy_preference pref, + enum cfcnfg_phy_preference pref, bool fcs, bool stx) { struct cflayer *frml; @@ -512,23 +597,26 @@ int cfcnfg_del_phy_layer(struct cfcnfg *cnfg, struct cflayer *phy_layer) phyid = phy_layer->id; phyinfo = cfcnfg_get_phyinfo_rcu(cnfg, phyid); - if (phyinfo == NULL) + if (phyinfo == NULL) { + mutex_unlock(&cnfg->lock); return 0; + } caif_assert(phyid == phyinfo->id); caif_assert(phy_layer == phyinfo->phy_layer); caif_assert(phy_layer->id == phyid); caif_assert(phyinfo->frm_layer->id == phyid); + list_del_rcu(&phyinfo->node); + synchronize_rcu(); + /* Fail if reference count is not zero */ if (cffrml_refcnt_read(phyinfo->frm_layer) != 0) { pr_info("Wait for device inuse\n"); + list_add_rcu(&phyinfo->node, &cnfg->phys); mutex_unlock(&cnfg->lock); return -EAGAIN; } - list_del_rcu(&phyinfo->node); - synchronize_rcu(); - frml = phyinfo->frm_layer; frml_dn = frml->dn; cffrml_set_uplayer(frml, NULL); @@ -539,8 +627,6 @@ int cfcnfg_del_phy_layer(struct cfcnfg *cnfg, struct cflayer *phy_layer) } layer_set_up(phy_layer, NULL); - - if (phyinfo->phy_layer != frml_dn) kfree(frml_dn); diff --git a/net/caif/chnl_net.c b/net/caif/chnl_net.c index 9ef8f16..1a3398a 100644 --- a/net/caif/chnl_net.c +++ b/net/caif/chnl_net.c @@ -20,7 +20,6 @@ #include #include #include -#include #include #include @@ -270,8 +269,9 @@ static int chnl_net_open(struct net_device *dev) if (priv->state != CAIF_CONNECTING) { priv->state = CAIF_CONNECTING; - result = caif_connect_client(&priv->conn_req, &priv->chnl, - &llifindex, &headroom, &tailroom); + result = caif_connect_client(dev_net(dev), &priv->conn_req, + &priv->chnl, &llifindex, + &headroom, &tailroom); if (result != 0) { pr_debug("err: " "Unable to register and open device," @@ -327,7 +327,7 @@ static int chnl_net_open(struct net_device *dev) if (result == 0) { pr_debug("connect timeout\n"); - caif_disconnect_client(&priv->chnl); + caif_disconnect_client(dev_net(dev), &priv->chnl); priv->state = CAIF_DISCONNECTED; pr_debug("state disconnected\n"); result = -ETIMEDOUT; @@ -343,7 +343,7 @@ static int chnl_net_open(struct net_device *dev) return 0; error: - caif_disconnect_client(&priv->chnl); + caif_disconnect_client(dev_net(dev), &priv->chnl); priv->state = CAIF_DISCONNECTED; pr_debug("state disconnected\n"); return result; @@ -357,7 +357,7 @@ static int chnl_net_stop(struct net_device *dev) ASSERT_RTNL(); priv = netdev_priv(dev); priv->state = CAIF_DISCONNECTED; - caif_disconnect_client(&priv->chnl); + caif_disconnect_client(dev_net(dev), &priv->chnl); return 0; } -- cgit v0.10.2 From c85c2951d4da1236e32f1858db418221e624aba5 Mon Sep 17 00:00:00 2001 From: "sjur.brandeland@stericsson.com" Date: Fri, 13 May 2011 02:44:06 +0000 Subject: caif: Handle dev_queue_xmit errors. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Do proper handling of dev_queue_xmit errors in order to avoid double free of skb and leaks in error conditions. In cfctrl pending requests are removed when CAIF Link layer goes down. Signed-off-by: Sjur Brændeland Signed-off-by: David S. Miller diff --git a/include/net/caif/cfctrl.h b/include/net/caif/cfctrl.h index d84416f..9e5425b 100644 --- a/include/net/caif/cfctrl.h +++ b/include/net/caif/cfctrl.h @@ -124,6 +124,7 @@ int cfctrl_linkdown_req(struct cflayer *cfctrl, u8 linkid, struct cflayer *cfctrl_create(void); struct cfctrl_rsp *cfctrl_get_respfuncs(struct cflayer *layer); -void cfctrl_cancel_req(struct cflayer *layr, struct cflayer *adap_layer); +int cfctrl_cancel_req(struct cflayer *layr, struct cflayer *adap_layer); +void cfctrl_remove(struct cflayer *layr); #endif /* CFCTRL_H_ */ diff --git a/net/caif/caif_dev.c b/net/caif/caif_dev.c index 0e651cf..366ca0f 100644 --- a/net/caif/caif_dev.c +++ b/net/caif/caif_dev.c @@ -118,6 +118,7 @@ static struct caif_device_entry *caif_get(struct net_device *dev) static int transmit(struct cflayer *layer, struct cfpkt *pkt) { + int err; struct caif_device_entry *caifd = container_of(layer, struct caif_device_entry, layer); struct sk_buff *skb; @@ -125,9 +126,11 @@ static int transmit(struct cflayer *layer, struct cfpkt *pkt) skb = cfpkt_tonative(pkt); skb->dev = caifd->netdev; - dev_queue_xmit(skb); + err = dev_queue_xmit(skb); + if (err > 0) + err = -EIO; - return 0; + return err; } /* diff --git a/net/caif/caif_socket.c b/net/caif/caif_socket.c index 653db75..7baae11 100644 --- a/net/caif/caif_socket.c +++ b/net/caif/caif_socket.c @@ -604,7 +604,9 @@ static int caif_seqpkt_sendmsg(struct kiocb *kiocb, struct socket *sock, goto err; ret = transmit_skb(skb, cf_sk, noblock, timeo); if (ret < 0) - goto err; + /* skb is already freed */ + return ret; + return len; err: kfree_skb(skb); @@ -933,9 +935,9 @@ static int caif_release(struct socket *sock) * caif_queue_rcv_skb checks SOCK_DEAD holding the queue lock, * this ensures no packets when sock is dead. */ - spin_lock(&sk->sk_receive_queue.lock); + spin_lock_bh(&sk->sk_receive_queue.lock); sock_set_flag(sk, SOCK_DEAD); - spin_unlock(&sk->sk_receive_queue.lock); + spin_unlock_bh(&sk->sk_receive_queue.lock); sock->sk = NULL; dbfs_atomic_inc(&cnt.num_disconnect); diff --git a/net/caif/cfcnfg.c b/net/caif/cfcnfg.c index e857d89..4230099 100644 --- a/net/caif/cfcnfg.c +++ b/net/caif/cfcnfg.c @@ -126,7 +126,7 @@ void cfcnfg_remove(struct cfcnfg *cfg) synchronize_rcu(); kfree(cfg->mux); - kfree(cfg->ctrl); + cfctrl_remove(cfg->ctrl); kfree(cfg); } } diff --git a/net/caif/cfctrl.c b/net/caif/cfctrl.c index 397a2c0..0c00a60 100644 --- a/net/caif/cfctrl.c +++ b/net/caif/cfctrl.c @@ -17,7 +17,6 @@ #define UTILITY_NAME_LENGTH 16 #define CFPKT_CTRL_PKT_LEN 20 - #ifdef CAIF_NO_LOOP static int handle_loop(struct cfctrl *ctrl, int cmd, struct cfpkt *pkt){ @@ -51,13 +50,29 @@ struct cflayer *cfctrl_create(void) this->serv.layer.receive = cfctrl_recv; sprintf(this->serv.layer.name, "ctrl"); this->serv.layer.ctrlcmd = cfctrl_ctrlcmd; +#ifndef CAIF_NO_LOOP spin_lock_init(&this->loop_linkid_lock); + this->loop_linkid = 1; +#endif spin_lock_init(&this->info_list_lock); INIT_LIST_HEAD(&this->list); - this->loop_linkid = 1; return &this->serv.layer; } +void cfctrl_remove(struct cflayer *layer) +{ + struct cfctrl_request_info *p, *tmp; + struct cfctrl *ctrl = container_obj(layer); + + spin_lock_bh(&ctrl->info_list_lock); + list_for_each_entry_safe(p, tmp, &ctrl->list, list) { + list_del(&p->list); + kfree(p); + } + spin_unlock_bh(&ctrl->info_list_lock); + kfree(layer); +} + static bool param_eq(const struct cfctrl_link_param *p1, const struct cfctrl_link_param *p2) { @@ -116,11 +131,11 @@ static bool cfctrl_req_eq(const struct cfctrl_request_info *r1, static void cfctrl_insert_req(struct cfctrl *ctrl, struct cfctrl_request_info *req) { - spin_lock(&ctrl->info_list_lock); + spin_lock_bh(&ctrl->info_list_lock); atomic_inc(&ctrl->req_seq_no); req->sequence_no = atomic_read(&ctrl->req_seq_no); list_add_tail(&req->list, &ctrl->list); - spin_unlock(&ctrl->info_list_lock); + spin_unlock_bh(&ctrl->info_list_lock); } /* Compare and remove request */ @@ -129,7 +144,6 @@ static struct cfctrl_request_info *cfctrl_remove_req(struct cfctrl *ctrl, { struct cfctrl_request_info *p, *tmp, *first; - spin_lock(&ctrl->info_list_lock); first = list_first_entry(&ctrl->list, struct cfctrl_request_info, list); list_for_each_entry_safe(p, tmp, &ctrl->list, list) { @@ -145,7 +159,6 @@ static struct cfctrl_request_info *cfctrl_remove_req(struct cfctrl *ctrl, } p = NULL; out: - spin_unlock(&ctrl->info_list_lock); return p; } @@ -179,10 +192,6 @@ void cfctrl_enum_req(struct cflayer *layer, u8 physlinkid) cfpkt_addbdy(pkt, physlinkid); ret = cfctrl->serv.layer.dn->transmit(cfctrl->serv.layer.dn, pkt); - if (ret < 0) { - pr_err("Could not transmit enum message\n"); - cfpkt_destroy(pkt); - } } int cfctrl_linkup_request(struct cflayer *layer, @@ -196,14 +205,23 @@ int cfctrl_linkup_request(struct cflayer *layer, struct cfctrl_request_info *req; int ret; char utility_name[16]; - struct cfpkt *pkt = cfpkt_create(CFPKT_CTRL_PKT_LEN); + struct cfpkt *pkt; + + if (cfctrl_cancel_req(layer, user_layer) > 0) { + /* Slight Paranoia, check if already connecting */ + pr_err("Duplicate connect request for same client\n"); + WARN_ON(1); + return -EALREADY; + } + + pkt = cfpkt_create(CFPKT_CTRL_PKT_LEN); if (!pkt) { pr_warn("Out of memory\n"); return -ENOMEM; } cfpkt_addbdy(pkt, CFCTRL_CMD_LINK_SETUP); - cfpkt_addbdy(pkt, (param->chtype << 4) + param->linktype); - cfpkt_addbdy(pkt, (param->priority << 3) + param->phyid); + cfpkt_addbdy(pkt, (param->chtype << 4) | param->linktype); + cfpkt_addbdy(pkt, (param->priority << 3) | param->phyid); cfpkt_addbdy(pkt, param->endpoint & 0x03); switch (param->linktype) { @@ -266,9 +284,13 @@ int cfctrl_linkup_request(struct cflayer *layer, ret = cfctrl->serv.layer.dn->transmit(cfctrl->serv.layer.dn, pkt); if (ret < 0) { - pr_err("Could not transmit linksetup request\n"); - cfpkt_destroy(pkt); - return -ENODEV; + int count; + + count = cfctrl_cancel_req(&cfctrl->serv.layer, + user_layer); + if (count != 1) + pr_err("Could not remove request (%d)", count); + return -ENODEV; } return 0; } @@ -288,28 +310,29 @@ int cfctrl_linkdown_req(struct cflayer *layer, u8 channelid, init_info(cfpkt_info(pkt), cfctrl); ret = cfctrl->serv.layer.dn->transmit(cfctrl->serv.layer.dn, pkt); - if (ret < 0) { - pr_err("Could not transmit link-down request\n"); - cfpkt_destroy(pkt); - } +#ifndef CAIF_NO_LOOP + cfctrl->loop_linkused[channelid] = 0; +#endif return ret; } -void cfctrl_cancel_req(struct cflayer *layr, struct cflayer *adap_layer) +int cfctrl_cancel_req(struct cflayer *layr, struct cflayer *adap_layer) { struct cfctrl_request_info *p, *tmp; struct cfctrl *ctrl = container_obj(layr); - spin_lock(&ctrl->info_list_lock); + int found = 0; + spin_lock_bh(&ctrl->info_list_lock); list_for_each_entry_safe(p, tmp, &ctrl->list, list) { if (p->client_layer == adap_layer) { - pr_debug("cancel req :%d\n", p->sequence_no); list_del(&p->list); kfree(p); + found++; } } - spin_unlock(&ctrl->info_list_lock); + spin_unlock_bh(&ctrl->info_list_lock); + return found; } static int cfctrl_recv(struct cflayer *layer, struct cfpkt *pkt) @@ -461,6 +484,7 @@ static int cfctrl_recv(struct cflayer *layer, struct cfpkt *pkt) rsp.cmd = cmd; rsp.param = linkparam; + spin_lock_bh(&cfctrl->info_list_lock); req = cfctrl_remove_req(cfctrl, &rsp); if (CFCTRL_ERR_BIT == (CFCTRL_ERR_BIT & cmdrsp) || @@ -480,6 +504,8 @@ static int cfctrl_recv(struct cflayer *layer, struct cfpkt *pkt) if (req != NULL) kfree(req); + + spin_unlock_bh(&cfctrl->info_list_lock); } break; case CFCTRL_CMD_LINK_DESTROY: @@ -523,12 +549,29 @@ static void cfctrl_ctrlcmd(struct cflayer *layr, enum caif_ctrlcmd ctrl, switch (ctrl) { case _CAIF_CTRLCMD_PHYIF_FLOW_OFF_IND: case CAIF_CTRLCMD_FLOW_OFF_IND: - spin_lock(&this->info_list_lock); + spin_lock_bh(&this->info_list_lock); if (!list_empty(&this->list)) { pr_debug("Received flow off in control layer\n"); } - spin_unlock(&this->info_list_lock); + spin_unlock_bh(&this->info_list_lock); break; + case _CAIF_CTRLCMD_PHYIF_DOWN_IND: { + struct cfctrl_request_info *p, *tmp; + + /* Find all connect request and report failure */ + spin_lock_bh(&this->info_list_lock); + list_for_each_entry_safe(p, tmp, &this->list, list) { + if (p->param.phyid == phyid) { + list_del(&p->list); + p->client_layer->ctrlcmd(p->client_layer, + CAIF_CTRLCMD_INIT_FAIL_RSP, + phyid); + kfree(p); + } + } + spin_unlock_bh(&this->info_list_lock); + break; + } default: break; } @@ -538,27 +581,33 @@ static void cfctrl_ctrlcmd(struct cflayer *layr, enum caif_ctrlcmd ctrl, static int handle_loop(struct cfctrl *ctrl, int cmd, struct cfpkt *pkt) { static int last_linkid; + static int dec; u8 linkid, linktype, tmp; switch (cmd) { case CFCTRL_CMD_LINK_SETUP: - spin_lock(&ctrl->loop_linkid_lock); - for (linkid = last_linkid + 1; linkid < 255; linkid++) - if (!ctrl->loop_linkused[linkid]) - goto found; + spin_lock_bh(&ctrl->loop_linkid_lock); + if (!dec) { + for (linkid = last_linkid + 1; linkid < 255; linkid++) + if (!ctrl->loop_linkused[linkid]) + goto found; + } + dec = 1; for (linkid = last_linkid - 1; linkid > 0; linkid--) if (!ctrl->loop_linkused[linkid]) goto found; - spin_unlock(&ctrl->loop_linkid_lock); - pr_err("Out of link-ids\n"); - return -EINVAL; + spin_unlock_bh(&ctrl->loop_linkid_lock); + found: + if (linkid < 10) + dec = 0; + if (!ctrl->loop_linkused[linkid]) ctrl->loop_linkused[linkid] = 1; last_linkid = linkid; cfpkt_add_trail(pkt, &linkid, 1); - spin_unlock(&ctrl->loop_linkid_lock); + spin_unlock_bh(&ctrl->loop_linkid_lock); cfpkt_peek_head(pkt, &linktype, 1); if (linktype == CFCTRL_SRV_UTIL) { tmp = 0x01; @@ -568,10 +617,10 @@ found: break; case CFCTRL_CMD_LINK_DESTROY: - spin_lock(&ctrl->loop_linkid_lock); + spin_lock_bh(&ctrl->loop_linkid_lock); cfpkt_peek_head(pkt, &linkid, 1); ctrl->loop_linkused[linkid] = 0; - spin_unlock(&ctrl->loop_linkid_lock); + spin_unlock_bh(&ctrl->loop_linkid_lock); break; default: break; diff --git a/net/caif/cffrml.c b/net/caif/cffrml.c index 4f4f756..04204b2 100644 --- a/net/caif/cffrml.c +++ b/net/caif/cffrml.c @@ -33,7 +33,6 @@ static void cffrml_ctrlcmd(struct cflayer *layr, enum caif_ctrlcmd ctrl, static u32 cffrml_rcv_error; static u32 cffrml_rcv_checsum_error; struct cflayer *cffrml_create(u16 phyid, bool use_fcs) - { struct cffrml *this = kmalloc(sizeof(struct cffrml), GFP_ATOMIC); if (!this) { @@ -128,6 +127,13 @@ static int cffrml_receive(struct cflayer *layr, struct cfpkt *pkt) cfpkt_destroy(pkt); return -EPROTO; } + + if (layr->up == NULL) { + pr_err("Layr up is missing!\n"); + cfpkt_destroy(pkt); + return -EINVAL; + } + return layr->up->receive(layr->up, pkt); } @@ -150,15 +156,22 @@ static int cffrml_transmit(struct cflayer *layr, struct cfpkt *pkt) cfpkt_info(pkt)->hdr_len += 2; if (cfpkt_erroneous(pkt)) { pr_err("Packet is erroneous!\n"); + cfpkt_destroy(pkt); return -EPROTO; } + + if (layr->dn == NULL) { + cfpkt_destroy(pkt); + return -ENODEV; + + } return layr->dn->transmit(layr->dn, pkt); } static void cffrml_ctrlcmd(struct cflayer *layr, enum caif_ctrlcmd ctrl, int phyid) { - if (layr->up->ctrlcmd) + if (layr->up && layr->up->ctrlcmd) layr->up->ctrlcmd(layr->up, ctrl, layr->id); } diff --git a/net/caif/cfveil.c b/net/caif/cfveil.c index 1a588cd..3ec83fb 100644 --- a/net/caif/cfveil.c +++ b/net/caif/cfveil.c @@ -82,13 +82,14 @@ static int cfvei_transmit(struct cflayer *layr, struct cfpkt *pkt) int ret; struct cfsrvl *service = container_obj(layr); if (!cfsrvl_ready(service, &ret)) - return ret; + goto err; caif_assert(layr->dn != NULL); caif_assert(layr->dn->transmit != NULL); if (cfpkt_add_head(pkt, &tmp, 1) < 0) { pr_err("Packet is erroneous!\n"); - return -EPROTO; + ret = -EPROTO; + goto err; } /* Add info-> for MUX-layer to route the packet out. */ @@ -97,4 +98,7 @@ static int cfvei_transmit(struct cflayer *layr, struct cfpkt *pkt) info->hdr_len = 1; info->dev_info = &service->dev_info; return layr->dn->transmit(layr->dn, pkt); +err: + cfpkt_destroy(pkt); + return ret; } -- cgit v0.10.2 From 33b2f5598b4ee68021364a7b795c09ad66bc0aa8 Mon Sep 17 00:00:00 2001 From: "sjur.brandeland@stericsson.com" Date: Fri, 13 May 2011 02:44:07 +0000 Subject: caif: Bugfix debugfs directory name must be unique. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Race condition caused debugfs_create_dir() to fail due to duplicate name. Use atomic counter to create unique directory name. net_ratelimit() is introduced to limit debug printouts. Signed-off-by: Sjur Brændeland Signed-off-by: David S. Miller diff --git a/net/caif/caif_socket.c b/net/caif/caif_socket.c index 7baae11..5cf9c73 100644 --- a/net/caif/caif_socket.c +++ b/net/caif/caif_socket.c @@ -48,6 +48,7 @@ static struct dentry *debugfsdir; #ifdef CONFIG_DEBUG_FS struct debug_fs_counter { atomic_t caif_nr_socks; + atomic_t caif_sock_create; atomic_t num_connect_req; atomic_t num_connect_resp; atomic_t num_connect_fail_resp; @@ -59,11 +60,11 @@ struct debug_fs_counter { atomic_t num_rx_flow_on; }; static struct debug_fs_counter cnt; -#define dbfs_atomic_inc(v) atomic_inc(v) -#define dbfs_atomic_dec(v) atomic_dec(v) +#define dbfs_atomic_inc(v) atomic_inc_return(v) +#define dbfs_atomic_dec(v) atomic_dec_return(v) #else -#define dbfs_atomic_inc(v) -#define dbfs_atomic_dec(v) +#define dbfs_atomic_inc(v) 0 +#define dbfs_atomic_dec(v) 0 #endif struct caifsock { @@ -155,9 +156,10 @@ static int caif_queue_rcv_skb(struct sock *sk, struct sk_buff *skb) if (atomic_read(&sk->sk_rmem_alloc) + skb->truesize >= (unsigned)sk->sk_rcvbuf && rx_flow_is_on(cf_sk)) { - pr_debug("sending flow OFF (queue len = %d %d)\n", - atomic_read(&cf_sk->sk.sk_rmem_alloc), - sk_rcvbuf_lowwater(cf_sk)); + if (net_ratelimit()) + pr_debug("sending flow OFF (queue len = %d %d)\n", + atomic_read(&cf_sk->sk.sk_rmem_alloc), + sk_rcvbuf_lowwater(cf_sk)); set_rx_flow_off(cf_sk); dbfs_atomic_inc(&cnt.num_rx_flow_off); caif_flow_ctrl(sk, CAIF_MODEMCMD_FLOW_OFF_REQ); @@ -168,7 +170,8 @@ static int caif_queue_rcv_skb(struct sock *sk, struct sk_buff *skb) return err; if (!sk_rmem_schedule(sk, skb->truesize) && rx_flow_is_on(cf_sk)) { set_rx_flow_off(cf_sk); - pr_debug("sending flow OFF due to rmem_schedule\n"); + if (net_ratelimit()) + pr_debug("sending flow OFF due to rmem_schedule\n"); dbfs_atomic_inc(&cnt.num_rx_flow_off); caif_flow_ctrl(sk, CAIF_MODEMCMD_FLOW_OFF_REQ); } @@ -838,7 +841,7 @@ static int caif_connect(struct socket *sock, struct sockaddr *uaddr, sock->state = SS_CONNECTING; sk->sk_state = CAIF_CONNECTING; - /* Check priority value coming from socket */ + /* Check priority value comming from socket */ /* if priority value is out of range it will be ajusted */ if (cf_sk->sk.sk_priority > CAIF_PRIO_MAX) cf_sk->conn_req.priority = CAIF_PRIO_MAX; @@ -942,6 +945,7 @@ static int caif_release(struct socket *sock) dbfs_atomic_inc(&cnt.num_disconnect); + WARN_ON(IS_ERR(cf_sk->debugfs_socket_dir)); if (cf_sk->debugfs_socket_dir != NULL) debugfs_remove_recursive(cf_sk->debugfs_socket_dir); @@ -1047,7 +1051,7 @@ static void caif_sock_destructor(struct sock *sk) caif_assert(sk_unhashed(sk)); caif_assert(!sk->sk_socket); if (!sock_flag(sk, SOCK_DEAD)) { - pr_info("Attempt to release alive CAIF socket: %p\n", sk); + pr_debug("Attempt to release alive CAIF socket: %p\n", sk); return; } sk_stream_kill_queues(&cf_sk->sk); @@ -1058,6 +1062,7 @@ static void caif_sock_destructor(struct sock *sk) static int caif_create(struct net *net, struct socket *sock, int protocol, int kern) { + int num; struct sock *sk = NULL; struct caifsock *cf_sk = NULL; static struct proto prot = {.name = "PF_CAIF", @@ -1120,14 +1125,16 @@ static int caif_create(struct net *net, struct socket *sock, int protocol, cf_sk->conn_req.protocol = protocol; /* Increase the number of sockets created. */ dbfs_atomic_inc(&cnt.caif_nr_socks); + num = dbfs_atomic_inc(&cnt.caif_sock_create); #ifdef CONFIG_DEBUG_FS if (!IS_ERR(debugfsdir)) { + /* Fill in some information concerning the misc socket. */ - snprintf(cf_sk->name, sizeof(cf_sk->name), "cfsk%d", - atomic_read(&cnt.caif_nr_socks)); + snprintf(cf_sk->name, sizeof(cf_sk->name), "cfsk%d", num); cf_sk->debugfs_socket_dir = debugfs_create_dir(cf_sk->name, debugfsdir); + debugfs_create_u32("sk_state", S_IRUSR | S_IWUSR, cf_sk->debugfs_socket_dir, (u32 *) &cf_sk->sk.sk_state); @@ -1171,6 +1178,9 @@ static int __init caif_sktinit_module(void) debugfs_create_u32("num_sockets", S_IRUSR | S_IWUSR, debugfsdir, (u32 *) &cnt.caif_nr_socks); + debugfs_create_u32("num_create", S_IRUSR | S_IWUSR, + debugfsdir, + (u32 *) &cnt.caif_sock_create); debugfs_create_u32("num_connect_req", S_IRUSR | S_IWUSR, debugfsdir, (u32 *) &cnt.num_connect_req); -- cgit v0.10.2 From 3f874adc4ae80828b79e8aac6891c108c1f6be6d Mon Sep 17 00:00:00 2001 From: "sjur.brandeland@stericsson.com" Date: Fri, 13 May 2011 02:44:08 +0000 Subject: caif: remove unesesarry exports MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Sjur Brændeland Signed-off-by: David S. Miller diff --git a/include/net/caif/cfpkt.h b/include/net/caif/cfpkt.h index 8b550f8..6bd200a 100644 --- a/include/net/caif/cfpkt.h +++ b/include/net/caif/cfpkt.h @@ -195,5 +195,4 @@ void *cfpkt_tonative(struct cfpkt *pkt); * @return Packet information */ struct caif_payload_info *cfpkt_info(struct cfpkt *pkt); -/*! @} */ #endif /* CFPKT_H_ */ diff --git a/net/caif/caif_socket.c b/net/caif/caif_socket.c index 5cf9c73..b840395 100644 --- a/net/caif/caif_socket.c +++ b/net/caif/caif_socket.c @@ -205,7 +205,7 @@ static int caif_sktrecv_cb(struct cflayer *layr, struct cfpkt *pkt) skb = cfpkt_tonative(pkt); if (unlikely(cf_sk->sk.sk_state != CAIF_CONNECTED)) { - cfpkt_destroy(pkt); + kfree_skb(skb); return 0; } caif_queue_rcv_skb(&cf_sk->sk, skb); @@ -537,7 +537,7 @@ static int transmit_skb(struct sk_buff *skb, struct caifsock *cf_sk, struct cfpkt *pkt; pkt = cfpkt_fromnative(CAIF_DIR_OUT, skb); - memset(cfpkt_info(pkt), 0, sizeof(struct caif_payload_info)); + memset(skb->cb, 0, sizeof(struct caif_payload_info)); if (cf_sk->layer.dn == NULL) return -EINVAL; diff --git a/net/caif/cfcnfg.c b/net/caif/cfcnfg.c index 4230099..351c2ca 100644 --- a/net/caif/cfcnfg.c +++ b/net/caif/cfcnfg.c @@ -117,7 +117,6 @@ out_of_mem: kfree(this); return NULL; } -EXPORT_SYMBOL(cfcnfg_create); void cfcnfg_remove(struct cfcnfg *cfg) { diff --git a/net/caif/cfpkt_skbuff.c b/net/caif/cfpkt_skbuff.c index 20c6cb3..75d4bfa 100644 --- a/net/caif/cfpkt_skbuff.c +++ b/net/caif/cfpkt_skbuff.c @@ -97,21 +97,20 @@ inline struct cfpkt *cfpkt_create(u16 len) { return cfpkt_create_pfx(len + PKT_POSTFIX, PKT_PREFIX); } -EXPORT_SYMBOL(cfpkt_create); void cfpkt_destroy(struct cfpkt *pkt) { struct sk_buff *skb = pkt_to_skb(pkt); kfree_skb(skb); } -EXPORT_SYMBOL(cfpkt_destroy); + inline bool cfpkt_more(struct cfpkt *pkt) { struct sk_buff *skb = pkt_to_skb(pkt); return skb->len > 0; } -EXPORT_SYMBOL(cfpkt_more); + int cfpkt_peek_head(struct cfpkt *pkt, void *data, u16 len) { @@ -123,7 +122,6 @@ int cfpkt_peek_head(struct cfpkt *pkt, void *data, u16 len) return !cfpkt_extr_head(pkt, data, len) && !cfpkt_add_head(pkt, data, len); } -EXPORT_SYMBOL(cfpkt_peek_head); int cfpkt_extr_head(struct cfpkt *pkt, void *data, u16 len) { @@ -148,7 +146,6 @@ int cfpkt_extr_head(struct cfpkt *pkt, void *data, u16 len) memcpy(data, from, len); return 0; } -EXPORT_SYMBOL(cfpkt_extr_head); int cfpkt_extr_trail(struct cfpkt *pkt, void *dta, u16 len) { @@ -171,13 +168,13 @@ int cfpkt_extr_trail(struct cfpkt *pkt, void *dta, u16 len) memcpy(data, from, len); return 0; } -EXPORT_SYMBOL(cfpkt_extr_trail); + int cfpkt_pad_trail(struct cfpkt *pkt, u16 len) { return cfpkt_add_body(pkt, NULL, len); } -EXPORT_SYMBOL(cfpkt_pad_trail); + int cfpkt_add_body(struct cfpkt *pkt, const void *data, u16 len) { @@ -226,13 +223,11 @@ int cfpkt_add_body(struct cfpkt *pkt, const void *data, u16 len) memcpy(to, data, len); return 0; } -EXPORT_SYMBOL(cfpkt_add_body); inline int cfpkt_addbdy(struct cfpkt *pkt, u8 data) { return cfpkt_add_body(pkt, &data, 1); } -EXPORT_SYMBOL(cfpkt_addbdy); int cfpkt_add_head(struct cfpkt *pkt, const void *data2, u16 len) { @@ -259,20 +254,20 @@ int cfpkt_add_head(struct cfpkt *pkt, const void *data2, u16 len) memcpy(to, data, len); return 0; } -EXPORT_SYMBOL(cfpkt_add_head); + inline int cfpkt_add_trail(struct cfpkt *pkt, const void *data, u16 len) { return cfpkt_add_body(pkt, data, len); } -EXPORT_SYMBOL(cfpkt_add_trail); + inline u16 cfpkt_getlen(struct cfpkt *pkt) { struct sk_buff *skb = pkt_to_skb(pkt); return skb->len; } -EXPORT_SYMBOL(cfpkt_getlen); + inline u16 cfpkt_iterate(struct cfpkt *pkt, u16 (*iter_func)(u16, void *, u16), @@ -290,7 +285,7 @@ inline u16 cfpkt_iterate(struct cfpkt *pkt, } return iter_func(data, pkt->skb.data, cfpkt_getlen(pkt)); } -EXPORT_SYMBOL(cfpkt_iterate); + int cfpkt_setlen(struct cfpkt *pkt, u16 len) { @@ -315,7 +310,6 @@ int cfpkt_setlen(struct cfpkt *pkt, u16 len) return cfpkt_getlen(pkt); } -EXPORT_SYMBOL(cfpkt_setlen); struct cfpkt *cfpkt_append(struct cfpkt *dstpkt, struct cfpkt *addpkt, @@ -357,7 +351,6 @@ struct cfpkt *cfpkt_append(struct cfpkt *dstpkt, dst->len += addlen; return skb_to_pkt(dst); } -EXPORT_SYMBOL(cfpkt_append); struct cfpkt *cfpkt_split(struct cfpkt *pkt, u16 pos) { @@ -395,17 +388,13 @@ struct cfpkt *cfpkt_split(struct cfpkt *pkt, u16 pos) skb2->len += len2nd; return skb_to_pkt(skb2); } -EXPORT_SYMBOL(cfpkt_split); bool cfpkt_erroneous(struct cfpkt *pkt) { return cfpkt_priv(pkt)->erronous; } -EXPORT_SYMBOL(cfpkt_erroneous); - struct caif_payload_info *cfpkt_info(struct cfpkt *pkt) { return (struct caif_payload_info *)&pkt_to_skb(pkt)->cb; } -EXPORT_SYMBOL(cfpkt_info); diff --git a/net/caif/chnl_net.c b/net/caif/chnl_net.c index 1a3398a..649ebac 100644 --- a/net/caif/chnl_net.c +++ b/net/caif/chnl_net.c @@ -83,10 +83,11 @@ static int chnl_recv_cb(struct cflayer *layr, struct cfpkt *pkt) if (!priv) return -EINVAL; + skb = (struct sk_buff *) cfpkt_tonative(pkt); + /* Get length of CAIF packet. */ - pktlen = cfpkt_getlen(pkt); + pktlen = skb->len; - skb = (struct sk_buff *) cfpkt_tonative(pkt); /* Pass some minimum information and * send the packet to the net stack. */ -- cgit v0.10.2 From 534ea99b063de7c30262a8e22f0ab44dd7d11a71 Mon Sep 17 00:00:00 2001 From: Shan Wei Date: Fri, 13 May 2011 21:08:47 +0000 Subject: net: drivers: kill two unused macro definitions Signed-off-by: Shan Wei Reviewed-by: Jiri Pirko Signed-off-by: David S. Miller diff --git a/drivers/net/bonding/bonding.h b/drivers/net/bonding/bonding.h index d08362e..ea1d005 100644 --- a/drivers/net/bonding/bonding.h +++ b/drivers/net/bonding/bonding.h @@ -39,16 +39,6 @@ netif_carrier_ok(dev)) /* - * Checks whether bond is ready for transmit. - * - * Caller must hold bond->lock - */ -#define BOND_IS_OK(bond) \ - (((bond)->dev->flags & IFF_UP) && \ - netif_running((bond)->dev) && \ - ((bond)->slave_cnt > 0)) - -/* * Checks whether slave is ready for transmit. */ #define SLAVE_IS_OK(slave) \ diff --git a/drivers/net/veth.c b/drivers/net/veth.c index 3b0151a..8461576 100644 --- a/drivers/net/veth.c +++ b/drivers/net/veth.c @@ -22,7 +22,6 @@ #define MIN_MTU 68 /* Min L3 MTU */ #define MAX_MTU 65535 /* Max L3 MTU (arbitrary) */ -#define MTU_PAD (ETH_HLEN + 4) /* Max difference between L2 and L3 size MTU */ struct veth_net_stats { unsigned long rx_packets; -- cgit v0.10.2 From a67b8887ced9d54cab7759bdb19deafed37481eb Mon Sep 17 00:00:00 2001 From: Florian Mickler Date: Sun, 15 May 2011 16:32:50 +0200 Subject: vga_switcheroo: don't toggle-switch devices If the requested device is already active, ignore the request. This restores the original behaviour of the interface. The change was probably an unintended side effect of commit 66b37c6777c4 vga_switcheroo: split switching into two stages which did not take into account to duplicate the !active check in the split-off stage2. Fix this by factoring that check out of stage1 into the debugfs_write routine. References: https://bugzilla.kernel.org/show_bug.cgi?id=34252 Reported-by: Igor Murzov Tested-by: Igor Murzov Signed-off-by: Florian Mickler Signed-off-by: Dave Airlie diff --git a/drivers/gpu/vga/vga_switcheroo.c b/drivers/gpu/vga/vga_switcheroo.c index e01cacb..498b284 100644 --- a/drivers/gpu/vga/vga_switcheroo.c +++ b/drivers/gpu/vga/vga_switcheroo.c @@ -219,9 +219,6 @@ static int vga_switchto_stage1(struct vga_switcheroo_client *new_client) int i; struct vga_switcheroo_client *active = NULL; - if (new_client->active == true) - return 0; - for (i = 0; i < VGA_SWITCHEROO_MAX_CLIENTS; i++) { if (vgasr_priv.clients[i].active == true) { active = &vgasr_priv.clients[i]; @@ -372,6 +369,9 @@ vga_switcheroo_debugfs_write(struct file *filp, const char __user *ubuf, goto out; } + if (client->active == true) + goto out; + /* okay we want a switch - test if devices are willing to switch */ can_switch = true; for (i = 0; i < VGA_SWITCHEROO_MAX_CLIENTS; i++) { -- cgit v0.10.2 From 8eea1be174a1ea4b86323167bbadc8a6abdca613 Mon Sep 17 00:00:00 2001 From: Andy Lutomirski Date: Fri, 13 May 2011 12:14:54 -0400 Subject: drm/i915: Revert i915.semaphore=1 default from 47ae63e0 My Q67 / i7-2600 box has rev09 Sandy Bridge graphics. It hangs instantly when GNOME loads and it hangs so hard the reset button doesn't work. Setting i915.semaphore=0 fixes it. Semaphores were disabled in a1656b9090f7008d2941c314f5a64724bea2ae37 in 2.6.38 and were re-enabled by commit 47ae63e0c2e5fdb582d471dc906eb29be94c732f Merge: c59a333 467cffb Author: Chris Wilson Date: Mon Mar 7 12:32:44 2011 +0000 Merge branch 'drm-intel-fixes' into drm-intel-next Apply the trivial conflicting regression fixes, but keep GPU semaphores enabled. Conflicts: drivers/gpu/drm/i915/i915_drv.h drivers/gpu/drm/i915/i915_gem_execbuffer.c (It's worth noting that the offending change is i915_drv.c, which is not a conflict.) Signed-off-by: Andy Lutomirski Acked-by: Keith Packard Signed-off-by: Dave Airlie diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index c34a8dd..32d1b3e 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c @@ -49,7 +49,7 @@ module_param_named(panel_ignore_lid, i915_panel_ignore_lid, int, 0600); unsigned int i915_powersave = 1; module_param_named(powersave, i915_powersave, int, 0600); -unsigned int i915_semaphores = 1; +unsigned int i915_semaphores = 0; module_param_named(semaphores, i915_semaphores, int, 0600); unsigned int i915_enable_rc6 = 0; -- cgit v0.10.2 From 752d2635ebb12b6122ba05775f7d1ccfef14b275 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Fri, 22 Apr 2011 11:03:57 +0100 Subject: drm: Take lock around probes for drm_fb_helper_hotplug_event We need to hold the dev->mode_config.mutex whilst detecting the output status. But we also need to drop it for the call into drm_fb_helper_single_fb_probe(), which indirectly acquires the lock when attaching the fbcon. Failure to do so exposes a race with normal output probing. Detected by adding some warnings that the mutex is held to the backend detect routines: [ 17.772456] WARNING: at drivers/gpu/drm/i915/intel_crt.c:471 intel_crt_detect+0x3e/0x373 [i915]() [ 17.772458] Hardware name: Latitude E6400 [ 17.772460] Modules linked in: .... [ 17.772582] Pid: 11, comm: kworker/0:1 Tainted: G W 2.6.38.4-custom.2 #8 [ 17.772584] Call Trace: [ 17.772591] [] ? warn_slowpath_common+0x78/0x8c [ 17.772603] [] ? intel_crt_detect+0x3e/0x373 [i915] [ 17.772612] [] ? drm_helper_probe_single_connector_modes+0xbf/0x2af [drm_kms_helper] [ 17.772619] [] ? drm_fb_helper_probe_connector_modes+0x39/0x4d [drm_kms_helper] [ 17.772625] [] ? drm_fb_helper_hotplug_event+0xa5/0xc3 [drm_kms_helper] [ 17.772633] [] ? output_poll_execute+0x146/0x17c [drm_kms_helper] [ 17.772638] [] ? cfq_init_queue+0x247/0x345 [ 17.772644] [] ? output_poll_execute+0x0/0x17c [drm_kms_helper] [ 17.772648] [] ? process_one_work+0x193/0x28e [ 17.772652] [] ? worker_thread+0xef/0x172 [ 17.772655] [] ? worker_thread+0x0/0x172 [ 17.772658] [] ? worker_thread+0x0/0x172 [ 17.772663] [] ? kthread+0x7a/0x82 [ 17.772668] [] ? kernel_thread_helper+0x4/0x10 [ 17.772671] [] ? kthread+0x0/0x82 [ 17.772674] [] ? kernel_thread_helper+0x0/0x10 Reported-by: Frederik Himpe References: https://bugs.freedesktop.org/show_bug.cgi?id=36394 Signed-off-by: Chris Wilson Signed-off-by: Dave Airlie diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c index 11d7a72..140b952 100644 --- a/drivers/gpu/drm/drm_fb_helper.c +++ b/drivers/gpu/drm/drm_fb_helper.c @@ -1516,17 +1516,33 @@ bool drm_fb_helper_initial_config(struct drm_fb_helper *fb_helper, int bpp_sel) } EXPORT_SYMBOL(drm_fb_helper_initial_config); -bool drm_fb_helper_hotplug_event(struct drm_fb_helper *fb_helper) +/** + * drm_fb_helper_hotplug_event - respond to a hotplug notification by + * probing all the outputs attached to the fb. + * @fb_helper: the drm_fb_helper + * + * LOCKING: + * Called at runtime, must take mode config lock. + * + * Scan the connectors attached to the fb_helper and try to put together a + * setup after *notification of a change in output configuration. + * + * RETURNS: + * 0 on success and a non-zero error code otherwise. + */ +int drm_fb_helper_hotplug_event(struct drm_fb_helper *fb_helper) { + struct drm_device *dev = fb_helper->dev; int count = 0; u32 max_width, max_height, bpp_sel; bool bound = false, crtcs_bound = false; struct drm_crtc *crtc; if (!fb_helper->fb) - return false; + return 0; - list_for_each_entry(crtc, &fb_helper->dev->mode_config.crtc_list, head) { + mutex_lock(&dev->mode_config.mutex); + list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { if (crtc->fb) crtcs_bound = true; if (crtc->fb == fb_helper->fb) @@ -1535,7 +1551,8 @@ bool drm_fb_helper_hotplug_event(struct drm_fb_helper *fb_helper) if (!bound && crtcs_bound) { fb_helper->delayed_hotplug = true; - return false; + mutex_unlock(&dev->mode_config.mutex); + return 0; } DRM_DEBUG_KMS("\n"); @@ -1546,6 +1563,7 @@ bool drm_fb_helper_hotplug_event(struct drm_fb_helper *fb_helper) count = drm_fb_helper_probe_connector_modes(fb_helper, max_width, max_height); drm_setup_crtcs(fb_helper); + mutex_unlock(&dev->mode_config.mutex); return drm_fb_helper_single_fb_probe(fb_helper, bpp_sel); } diff --git a/include/drm/drm_fb_helper.h b/include/drm/drm_fb_helper.h index ade09d7..c99c3d3 100644 --- a/include/drm/drm_fb_helper.h +++ b/include/drm/drm_fb_helper.h @@ -127,7 +127,7 @@ void drm_fb_helper_fill_fix(struct fb_info *info, uint32_t pitch, int drm_fb_helper_setcmap(struct fb_cmap *cmap, struct fb_info *info); -bool drm_fb_helper_hotplug_event(struct drm_fb_helper *fb_helper); +int drm_fb_helper_hotplug_event(struct drm_fb_helper *fb_helper); bool drm_fb_helper_initial_config(struct drm_fb_helper *fb_helper, int bpp_sel); int drm_fb_helper_single_add_all_connectors(struct drm_fb_helper *fb_helper); int drm_fb_helper_debug_enter(struct fb_info *info); -- cgit v0.10.2 From b23b64516500df6b70fcafb820970f18538252cf Mon Sep 17 00:00:00 2001 From: Andy Lutomirski Date: Mon, 16 May 2011 15:12:47 +1000 Subject: crypto: aesni-intel - Merge with fpu.ko Loading fpu without aesni-intel does nothing. Loading aesni-intel without fpu causes modes like xts to fail. (Unloading aesni-intel will restore those modes.) One solution would be to make aesni-intel depend on fpu, but it seems cleaner to just combine the modules. This is probably responsible for bugs like: https://bugzilla.redhat.com/show_bug.cgi?id=589390 Signed-off-by: Andy Lutomirski Signed-off-by: Herbert Xu diff --git a/arch/x86/crypto/Makefile b/arch/x86/crypto/Makefile index 1a58ad8..c04f1b7 100644 --- a/arch/x86/crypto/Makefile +++ b/arch/x86/crypto/Makefile @@ -2,8 +2,6 @@ # Arch-specific CryptoAPI modules. # -obj-$(CONFIG_CRYPTO_FPU) += fpu.o - obj-$(CONFIG_CRYPTO_AES_586) += aes-i586.o obj-$(CONFIG_CRYPTO_TWOFISH_586) += twofish-i586.o obj-$(CONFIG_CRYPTO_SALSA20_586) += salsa20-i586.o @@ -24,6 +22,6 @@ aes-x86_64-y := aes-x86_64-asm_64.o aes_glue.o twofish-x86_64-y := twofish-x86_64-asm_64.o twofish_glue.o salsa20-x86_64-y := salsa20-x86_64-asm_64.o salsa20_glue.o -aesni-intel-y := aesni-intel_asm.o aesni-intel_glue.o +aesni-intel-y := aesni-intel_asm.o aesni-intel_glue.o fpu.o ghash-clmulni-intel-y := ghash-clmulni-intel_asm.o ghash-clmulni-intel_glue.o diff --git a/arch/x86/crypto/aesni-intel_glue.c b/arch/x86/crypto/aesni-intel_glue.c index 2577613..cbc60ef 100644 --- a/arch/x86/crypto/aesni-intel_glue.c +++ b/arch/x86/crypto/aesni-intel_glue.c @@ -140,6 +140,9 @@ asmlinkage void aesni_gcm_dec(void *ctx, u8 *out, u8 *hash_subkey, const u8 *aad, unsigned long aad_len, u8 *auth_tag, unsigned long auth_tag_len); +int crypto_fpu_init(void); +void crypto_fpu_exit(void); + static inline struct aesni_rfc4106_gcm_ctx *aesni_rfc4106_gcm_ctx_get(struct crypto_aead *tfm) { @@ -1257,6 +1260,8 @@ static int __init aesni_init(void) return -ENODEV; } + if ((err = crypto_fpu_init())) + goto fpu_err; if ((err = crypto_register_alg(&aesni_alg))) goto aes_err; if ((err = crypto_register_alg(&__aesni_alg))) @@ -1334,6 +1339,7 @@ blk_ecb_err: __aes_err: crypto_unregister_alg(&aesni_alg); aes_err: +fpu_err: return err; } @@ -1363,6 +1369,8 @@ static void __exit aesni_exit(void) crypto_unregister_alg(&blk_ecb_alg); crypto_unregister_alg(&__aesni_alg); crypto_unregister_alg(&aesni_alg); + + crypto_fpu_exit(); } module_init(aesni_init); diff --git a/arch/x86/crypto/fpu.c b/arch/x86/crypto/fpu.c index 1a8f864..98d7a18 100644 --- a/arch/x86/crypto/fpu.c +++ b/arch/x86/crypto/fpu.c @@ -150,18 +150,12 @@ static struct crypto_template crypto_fpu_tmpl = { .module = THIS_MODULE, }; -static int __init crypto_fpu_module_init(void) +int __init crypto_fpu_init(void) { return crypto_register_template(&crypto_fpu_tmpl); } -static void __exit crypto_fpu_module_exit(void) +void __exit crypto_fpu_exit(void) { crypto_unregister_template(&crypto_fpu_tmpl); } - -module_init(crypto_fpu_module_init); -module_exit(crypto_fpu_module_exit); - -MODULE_LICENSE("GPL"); -MODULE_DESCRIPTION("FPU block cipher wrapper"); diff --git a/crypto/Kconfig b/crypto/Kconfig index 4b7cb0e..87b22ca 100644 --- a/crypto/Kconfig +++ b/crypto/Kconfig @@ -264,11 +264,6 @@ config CRYPTO_XTS key size 256, 384 or 512 bits. This implementation currently can't handle a sectorsize which is not a multiple of 16 bytes. -config CRYPTO_FPU - tristate - select CRYPTO_BLKCIPHER - select CRYPTO_MANAGER - comment "Hash modes" config CRYPTO_HMAC @@ -543,7 +538,6 @@ config CRYPTO_AES_NI_INTEL select CRYPTO_AES_586 if !64BIT select CRYPTO_CRYPTD select CRYPTO_ALGAPI - select CRYPTO_FPU help Use Intel AES-NI instructions for AES algorithm. -- cgit v0.10.2 From ec514c487c3d4b652943da7b0afbc094eee08cfa Mon Sep 17 00:00:00 2001 From: Cheng Xu Date: Sat, 14 May 2011 14:20:02 +0800 Subject: sched: Fix rt_rq runtime leakage bug This patch is to fix the real-time scheduler bug reported at: https://lkml.org/lkml/2011/4/26/13 That is, when running multiple real-time threads on every logical CPUs and then turning off one CPU, the kernel will bug at function __disable_runtime(). Function __disable_runtime() bugs and reports leakage of rt_rq runtime. The root cause is __disable_runtime() assumes it iterates through all the existing rt_rq's while walking rq->leaf_rt_rq_list, which actually contains only runnable rt_rq's. This problem also applies to __enable_runtime() and print_rt_stats(). The patch is based on above analysis, appears to fix the problem, but is only lightly tested. Reported-by: Paul E. McKenney Tested-by: Paul E. McKenney Signed-off-by: Cheng Xu Signed-off-by: Peter Zijlstra Link: http://lkml.kernel.org/r/4DCE1F12.6040609@linux.vnet.ibm.com Signed-off-by: Ingo Molnar diff --git a/kernel/sched_rt.c b/kernel/sched_rt.c index e7cebdc..f8fcf82 100644 --- a/kernel/sched_rt.c +++ b/kernel/sched_rt.c @@ -183,6 +183,14 @@ static inline u64 sched_rt_period(struct rt_rq *rt_rq) return ktime_to_ns(rt_rq->tg->rt_bandwidth.rt_period); } +typedef struct task_group *rt_rq_iter_t; + +#define for_each_rt_rq(rt_rq, iter, rq) \ + for (iter = list_entry_rcu(task_groups.next, typeof(*iter), list); \ + (&iter->list != &task_groups) && \ + (rt_rq = iter->rt_rq[cpu_of(rq)]); \ + iter = list_entry_rcu(iter->list.next, typeof(*iter), list)) + static inline void list_add_leaf_rt_rq(struct rt_rq *rt_rq) { list_add_rcu(&rt_rq->leaf_rt_rq_list, @@ -288,6 +296,11 @@ static inline u64 sched_rt_period(struct rt_rq *rt_rq) return ktime_to_ns(def_rt_bandwidth.rt_period); } +typedef struct rt_rq *rt_rq_iter_t; + +#define for_each_rt_rq(rt_rq, iter, rq) \ + for ((void) iter, rt_rq = &rq->rt; rt_rq; rt_rq = NULL) + static inline void list_add_leaf_rt_rq(struct rt_rq *rt_rq) { } @@ -402,12 +415,13 @@ next: static void __disable_runtime(struct rq *rq) { struct root_domain *rd = rq->rd; + rt_rq_iter_t iter; struct rt_rq *rt_rq; if (unlikely(!scheduler_running)) return; - for_each_leaf_rt_rq(rt_rq, rq) { + for_each_rt_rq(rt_rq, iter, rq) { struct rt_bandwidth *rt_b = sched_rt_bandwidth(rt_rq); s64 want; int i; @@ -487,6 +501,7 @@ static void disable_runtime(struct rq *rq) static void __enable_runtime(struct rq *rq) { + rt_rq_iter_t iter; struct rt_rq *rt_rq; if (unlikely(!scheduler_running)) @@ -495,7 +510,7 @@ static void __enable_runtime(struct rq *rq) /* * Reset each runqueue's bandwidth settings */ - for_each_leaf_rt_rq(rt_rq, rq) { + for_each_rt_rq(rt_rq, iter, rq) { struct rt_bandwidth *rt_b = sched_rt_bandwidth(rt_rq); raw_spin_lock(&rt_b->rt_runtime_lock); @@ -1796,10 +1811,11 @@ extern void print_rt_rq(struct seq_file *m, int cpu, struct rt_rq *rt_rq); static void print_rt_stats(struct seq_file *m, int cpu) { + rt_rq_iter_t iter; struct rt_rq *rt_rq; rcu_read_lock(); - for_each_leaf_rt_rq(rt_rq, cpu_rq(cpu)) + for_each_rt_rq(rt_rq, iter, cpu_rq(cpu)) print_rt_rq(m, cpu, rt_rq); rcu_read_unlock(); } -- cgit v0.10.2 From 61eadef6a9bde9ea62fda724a9cb501ce9bc925a Mon Sep 17 00:00:00 2001 From: Mike Galbraith Date: Fri, 29 Apr 2011 08:36:50 +0200 Subject: sched, rt: Update rq clock when unthrottling of an otherwise idle CPU If an RT task is awakened while it's rt_rq is throttled, the time between wakeup/enqueue and unthrottle/selection may be accounted as rt_time if the CPU is idle. Set rq->skip_clock_update negative upon throttle release to tell put_prev_task() that we need a clock update. Reported-by: Thomas Giesel Signed-off-by: Mike Galbraith Signed-off-by: Peter Zijlstra Link: http://lkml.kernel.org/r/1304059010.7472.1.camel@marge.simson.net Signed-off-by: Ingo Molnar diff --git a/kernel/sched.c b/kernel/sched.c index f9778c0..b8b9a7d 100644 --- a/kernel/sched.c +++ b/kernel/sched.c @@ -466,7 +466,7 @@ struct rq { u64 nohz_stamp; unsigned char nohz_balance_kick; #endif - unsigned int skip_clock_update; + int skip_clock_update; /* capture load from *all* tasks on this cpu: */ struct load_weight load; @@ -652,7 +652,7 @@ static void update_rq_clock(struct rq *rq) { s64 delta; - if (rq->skip_clock_update) + if (rq->skip_clock_update > 0) return; delta = sched_clock_cpu(cpu_of(rq)) - rq->clock; @@ -4127,7 +4127,7 @@ static inline void schedule_debug(struct task_struct *prev) static void put_prev_task(struct rq *rq, struct task_struct *prev) { - if (prev->on_rq) + if (prev->on_rq || rq->skip_clock_update < 0) update_rq_clock(rq); prev->sched_class->put_prev_task(rq, prev); } diff --git a/kernel/sched_rt.c b/kernel/sched_rt.c index 19ecb31..0943ed7 100644 --- a/kernel/sched_rt.c +++ b/kernel/sched_rt.c @@ -562,6 +562,13 @@ static int do_sched_rt_period_timer(struct rt_bandwidth *rt_b, int overrun) if (rt_rq->rt_throttled && rt_rq->rt_time < runtime) { rt_rq->rt_throttled = 0; enqueue = 1; + + /* + * Force a clock update if the CPU was idle, + * lest wakeup -> unthrottle time accumulate. + */ + if (rt_rq->rt_nr_running && rq->curr == rq->idle) + rq->skip_clock_update = -1; } if (rt_rq->rt_time || rt_rq->rt_nr_running) idle = 0; -- cgit v0.10.2 From db44fc017d5989302713ab4e7f9e922b648f4b59 Mon Sep 17 00:00:00 2001 From: Yong Zhang Date: Mon, 9 May 2011 22:07:05 +0800 Subject: sched: Avoid going ahead if ->cpus_allowed is not changed If cpumask_equal(&p->cpus_allowed, new_mask) is true, seems there is no reason to prevent set_cpus_allowed_ptr() return directly. Signed-off-by: Yong Zhang Acked-by: Hillf Danton Signed-off-by: Peter Zijlstra Link: http://lkml.kernel.org/r/20110509140705.GA2219@zhy Signed-off-by: Ingo Molnar diff --git a/kernel/sched.c b/kernel/sched.c index b8b9a7d..70bec4f 100644 --- a/kernel/sched.c +++ b/kernel/sched.c @@ -5946,13 +5946,15 @@ int set_cpus_allowed_ptr(struct task_struct *p, const struct cpumask *new_mask) rq = task_rq_lock(p, &flags); + if (cpumask_equal(&p->cpus_allowed, new_mask)) + goto out; + if (!cpumask_intersects(new_mask, cpu_active_mask)) { ret = -EINVAL; goto out; } - if (unlikely((p->flags & PF_THREAD_BOUND) && p != current && - !cpumask_equal(&p->cpus_allowed, new_mask))) { + if (unlikely((p->flags & PF_THREAD_BOUND) && p != current)) { ret = -EINVAL; goto out; } -- cgit v0.10.2 From db670dac49b5423b39b5e523d28fe32045d71b10 Mon Sep 17 00:00:00 2001 From: Stephan Baerwolf Date: Wed, 11 May 2011 18:03:29 +0200 Subject: sched: Fix and optimise calculation of the weight-inverse If the inverse loadweight should be zero, function "calc_delta_mine" calculates the inverse of "lw->weight" (in 32bit integer ops). This calculation is actually a little bit impure (because it is inverting something around "lw-weight"+1), especially when "lw->weight" becomes smaller. The correct inverse would be 1/lw->weight multiplied by "WMULT_CONST" for fixcomma-scaling it into integers. (So WMULT_CONST/lw->weight ...) The old, impure algorithm took two divisions for inverting lw->weight, the new, more exact one only takes one and an additional unlikely-if. Signed-off-by: Stephan Baerwolf Signed-off-by: Peter Zijlstra Cc: Linus Torvalds Link: http://lkml.kernel.org/n/tip-0pz0wnyalr4tk4ln11xwumdx@git.kernel.org [ This could explain some aritmetical issues for small shares but nothing concrete has been reported yet so we are not confident enough to queue this up in sched/urgent and for -stable backport. But if anyone finds this commit and sees it to fix some badness then we can certainly change our mind! ] Signed-off-by: Ingo Molnar diff --git a/kernel/sched.c b/kernel/sched.c index 70bec4f..c62acf4 100644 --- a/kernel/sched.c +++ b/kernel/sched.c @@ -1330,15 +1330,15 @@ calc_delta_mine(unsigned long delta_exec, unsigned long weight, { u64 tmp; + tmp = (u64)delta_exec * weight; + if (!lw->inv_weight) { if (BITS_PER_LONG > 32 && unlikely(lw->weight >= WMULT_CONST)) lw->inv_weight = 1; else - lw->inv_weight = 1 + (WMULT_CONST-lw->weight/2) - / (lw->weight+1); + lw->inv_weight = WMULT_CONST / lw->weight; } - tmp = (u64)delta_exec * weight; /* * Check whether we'd overflow the 64-bit multiplication: */ -- cgit v0.10.2 From e503f9e4b092e2349a9477a333543de8f3c7f5d9 Mon Sep 17 00:00:00 2001 From: Youquan Song Date: Fri, 22 Apr 2011 00:22:43 +0800 Subject: x86, apic: Fix spurious error interrupts triggering on all non-boot APs This patch fixes a bug reported by a customer, who found that many unreasonable error interrupts reported on all non-boot CPUs (APs) during the system boot stage. According to Chapter 10 of Intel Software Developer Manual Volume 3A, Local APIC may signal an illegal vector error when an LVT entry is set as an illegal vector value (0~15) under FIXED delivery mode (bits 8-11 is 0), regardless of whether the mask bit is set or an interrupt actually happen. These errors are seen as error interrupts. The initial value of thermal LVT entries on all APs always reads 0x10000 because APs are woken up by BSP issuing INIT-SIPI-SIPI sequence to them and LVT registers are reset to 0s except for the mask bits which are set to 1s when APs receive INIT IPI. When the BIOS takes over the thermal throttling interrupt, the LVT thermal deliver mode should be SMI and it is required from the kernel to keep AP's LVT thermal monitoring register programmed as such as well. This issue happens when BIOS does not take over thermal throttling interrupt, AP's LVT thermal monitor register will be restored to 0x10000 which means vector 0 and fixed deliver mode, so all APs will signal illegal vector error interrupts. This patch check if interrupt delivery mode is not fixed mode before restoring AP's LVT thermal monitor register. Signed-off-by: Youquan Song Acked-by: Suresh Siddha Acked-by: Yong Wang Cc: hpa@linux.intel.com Cc: joe@perches.com Cc: jbaron@redhat.com Cc: trenn@suse.de Cc: kent.liu@intel.com Cc: chaohong.guo@intel.com Cc: # As far back as possible Link: http://lkml.kernel.org/r/1303402963-17738-1-git-send-email-youquan.song@intel.com Signed-off-by: Ingo Molnar diff --git a/arch/x86/include/asm/apicdef.h b/arch/x86/include/asm/apicdef.h index d87988b..34595d5 100644 --- a/arch/x86/include/asm/apicdef.h +++ b/arch/x86/include/asm/apicdef.h @@ -78,6 +78,7 @@ #define APIC_DEST_LOGICAL 0x00800 #define APIC_DEST_PHYSICAL 0x00000 #define APIC_DM_FIXED 0x00000 +#define APIC_DM_FIXED_MASK 0x00700 #define APIC_DM_LOWEST 0x00100 #define APIC_DM_SMI 0x00200 #define APIC_DM_REMRD 0x00300 diff --git a/arch/x86/kernel/cpu/mcheck/therm_throt.c b/arch/x86/kernel/cpu/mcheck/therm_throt.c index 6f8c5e9..0f03446 100644 --- a/arch/x86/kernel/cpu/mcheck/therm_throt.c +++ b/arch/x86/kernel/cpu/mcheck/therm_throt.c @@ -446,18 +446,20 @@ void intel_init_thermal(struct cpuinfo_x86 *c) */ rdmsr(MSR_IA32_MISC_ENABLE, l, h); + h = lvtthmr_init; /* * The initial value of thermal LVT entries on all APs always reads * 0x10000 because APs are woken up by BSP issuing INIT-SIPI-SIPI * sequence to them and LVT registers are reset to 0s except for * the mask bits which are set to 1s when APs receive INIT IPI. - * Always restore the value that BIOS has programmed on AP based on - * BSP's info we saved since BIOS is always setting the same value - * for all threads/cores + * If BIOS takes over the thermal interrupt and sets its interrupt + * delivery mode to SMI (not fixed), it restores the value that the + * BIOS has programmed on AP based on BSP's info we saved since BIOS + * is always setting the same value for all threads/cores. */ - apic_write(APIC_LVTTHMR, lvtthmr_init); + if ((h & APIC_DM_FIXED_MASK) != APIC_DM_FIXED) + apic_write(APIC_LVTTHMR, lvtthmr_init); - h = lvtthmr_init; if ((l & MSR_IA32_MISC_ENABLE_TM1) && (h & APIC_DM_SMI)) { printk(KERN_DEBUG -- cgit v0.10.2 From 274ea0e2a4cdf18110e5931b8ecbfef6353e5293 Mon Sep 17 00:00:00 2001 From: Patrick McHardy Date: Mon, 16 May 2011 14:42:26 +0200 Subject: netfilter: nf_ct_sip: validate Content-Length in TCP SIP messages Verify that the message length of a single SIP message, which is calculated based on the Content-Length field contained in the SIP message, does not exceed the packet boundaries. Signed-off-by: Patrick McHardy diff --git a/net/netfilter/nf_conntrack_sip.c b/net/netfilter/nf_conntrack_sip.c index bcf47eb..1f81abd 100644 --- a/net/netfilter/nf_conntrack_sip.c +++ b/net/netfilter/nf_conntrack_sip.c @@ -1461,6 +1461,8 @@ static int sip_help_tcp(struct sk_buff *skb, unsigned int protoff, end += strlen("\r\n\r\n") + clen; msglen = origlen = end - dptr; + if (msglen > datalen) + return NF_DROP; ret = process_sip_msg(skb, ct, dataoff, &dptr, &msglen); if (ret != NF_ACCEPT) -- cgit v0.10.2 From e6e4d9ed11fb1fab8b3256a3dc14d71b5e984ac4 Mon Sep 17 00:00:00 2001 From: Patrick McHardy Date: Mon, 16 May 2011 14:45:39 +0200 Subject: netfilter: nf_ct_sip: fix SDP parsing in TCP SIP messages for some Cisco phones Some Cisco phones do not place the Content-Length field at the end of the SIP message. This is valid, due to a misunderstanding of the specification the parser expects the SDP body to start directly after the Content-Length field. Fix the parser to scan for \r\n\r\n to locate the beginning of the SDP body. Reported-by: Teresa Kang Signed-off-by: Patrick McHardy diff --git a/net/netfilter/nf_conntrack_sip.c b/net/netfilter/nf_conntrack_sip.c index 1f81abd..c05c0dc 100644 --- a/net/netfilter/nf_conntrack_sip.c +++ b/net/netfilter/nf_conntrack_sip.c @@ -1419,6 +1419,7 @@ static int sip_help_tcp(struct sk_buff *skb, unsigned int protoff, const char *dptr, *end; s16 diff, tdiff = 0; int ret = NF_ACCEPT; + bool term; typeof(nf_nat_sip_seq_adjust_hook) nf_nat_sip_seq_adjust; if (ctinfo != IP_CT_ESTABLISHED && @@ -1453,10 +1454,15 @@ static int sip_help_tcp(struct sk_buff *skb, unsigned int protoff, if (dptr + matchoff == end) break; - if (end + strlen("\r\n\r\n") > dptr + datalen) - break; - if (end[0] != '\r' || end[1] != '\n' || - end[2] != '\r' || end[3] != '\n') + term = false; + for (; end + strlen("\r\n\r\n") <= dptr + datalen; end++) { + if (end[0] == '\r' && end[1] == '\n' && + end[2] == '\r' && end[3] == '\n') { + term = true; + break; + } + } + if (!term) break; end += strlen("\r\n\r\n") + clen; -- cgit v0.10.2 From 70087dc38cc77ca8f46059564c00338777734762 Mon Sep 17 00:00:00 2001 From: Vivek Goyal Date: Mon, 16 May 2011 15:24:08 +0200 Subject: blk-throttle: Use task_subsys_state() to determine a task's blkio_cgroup Currentlly we first map the task to cgroup and then cgroup to blkio_cgroup. There is a more direct way to get to blkio_cgroup from task using task_subsys_state(). Use that. The real reason for the fix is that it also avoids a race in generic cgroup code. During remount/umount rebind_subsystems() is called and it can do following with and rcu protection. cgrp->subsys[i] = NULL; That means if somebody got hold of cgroup under rcu and then it tried to do cgroup->subsys[] to get to blkio_cgroup, it would get NULL which is wrong. I was running into this race condition with ltp running on a upstream derived kernel and that lead to crash. So ideally we should also fix cgroup generic code to wait for rcu grace period before setting pointer to NULL. Li Zefan is not very keen on introducing synchronize_wait() as he thinks it will slow down moun/remount/umount operations. So for the time being atleast fix the kernel crash by taking a more direct route to blkio_cgroup. One tester had reported a crash while running LTP on a derived kernel and with this fix crash is no more seen while the test has been running for over 6 days. Signed-off-by: Vivek Goyal Reviewed-by: Li Zefan Signed-off-by: Jens Axboe diff --git a/block/blk-cgroup.c b/block/blk-cgroup.c index f0605ab..471fdcc 100644 --- a/block/blk-cgroup.c +++ b/block/blk-cgroup.c @@ -114,6 +114,13 @@ struct blkio_cgroup *cgroup_to_blkio_cgroup(struct cgroup *cgroup) } EXPORT_SYMBOL_GPL(cgroup_to_blkio_cgroup); +struct blkio_cgroup *task_blkio_cgroup(struct task_struct *tsk) +{ + return container_of(task_subsys_state(tsk, blkio_subsys_id), + struct blkio_cgroup, css); +} +EXPORT_SYMBOL_GPL(task_blkio_cgroup); + static inline void blkio_update_group_weight(struct blkio_group *blkg, unsigned int weight) { diff --git a/block/blk-cgroup.h b/block/blk-cgroup.h index 10919fa..c774930 100644 --- a/block/blk-cgroup.h +++ b/block/blk-cgroup.h @@ -291,6 +291,7 @@ static inline void blkiocg_set_start_empty_time(struct blkio_group *blkg) {} #if defined(CONFIG_BLK_CGROUP) || defined(CONFIG_BLK_CGROUP_MODULE) extern struct blkio_cgroup blkio_root_cgroup; extern struct blkio_cgroup *cgroup_to_blkio_cgroup(struct cgroup *cgroup); +extern struct blkio_cgroup *task_blkio_cgroup(struct task_struct *tsk); extern void blkiocg_add_blkio_group(struct blkio_cgroup *blkcg, struct blkio_group *blkg, void *key, dev_t dev, enum blkio_policy_id plid); @@ -314,6 +315,8 @@ void blkiocg_update_io_remove_stats(struct blkio_group *blkg, struct cgroup; static inline struct blkio_cgroup * cgroup_to_blkio_cgroup(struct cgroup *cgroup) { return NULL; } +static inline struct blkio_cgroup * +task_blkio_cgroup(struct task_struct *tsk) { return NULL; } static inline void blkiocg_add_blkio_group(struct blkio_cgroup *blkcg, struct blkio_group *blkg, void *key, dev_t dev, diff --git a/block/blk-throttle.c b/block/blk-throttle.c index 0475a22..252a81a 100644 --- a/block/blk-throttle.c +++ b/block/blk-throttle.c @@ -160,9 +160,8 @@ static void throtl_put_tg(struct throtl_grp *tg) } static struct throtl_grp * throtl_find_alloc_tg(struct throtl_data *td, - struct cgroup *cgroup) + struct blkio_cgroup *blkcg) { - struct blkio_cgroup *blkcg = cgroup_to_blkio_cgroup(cgroup); struct throtl_grp *tg = NULL; void *key = td; struct backing_dev_info *bdi = &td->queue->backing_dev_info; @@ -229,12 +228,12 @@ done: static struct throtl_grp * throtl_get_tg(struct throtl_data *td) { - struct cgroup *cgroup; struct throtl_grp *tg = NULL; + struct blkio_cgroup *blkcg; rcu_read_lock(); - cgroup = task_cgroup(current, blkio_subsys_id); - tg = throtl_find_alloc_tg(td, cgroup); + blkcg = task_blkio_cgroup(current); + tg = throtl_find_alloc_tg(td, blkcg); if (!tg) tg = &td->root_tg; rcu_read_unlock(); diff --git a/block/cfq-iosched.c b/block/cfq-iosched.c index 5b52011..ab7a9e6 100644 --- a/block/cfq-iosched.c +++ b/block/cfq-iosched.c @@ -1014,10 +1014,9 @@ void cfq_update_blkio_group_weight(void *key, struct blkio_group *blkg, cfqg->needs_update = true; } -static struct cfq_group * -cfq_find_alloc_cfqg(struct cfq_data *cfqd, struct cgroup *cgroup, int create) +static struct cfq_group * cfq_find_alloc_cfqg(struct cfq_data *cfqd, + struct blkio_cgroup *blkcg, int create) { - struct blkio_cgroup *blkcg = cgroup_to_blkio_cgroup(cgroup); struct cfq_group *cfqg = NULL; void *key = cfqd; int i, j; @@ -1079,12 +1078,12 @@ done: */ static struct cfq_group *cfq_get_cfqg(struct cfq_data *cfqd, int create) { - struct cgroup *cgroup; + struct blkio_cgroup *blkcg; struct cfq_group *cfqg = NULL; rcu_read_lock(); - cgroup = task_cgroup(current, blkio_subsys_id); - cfqg = cfq_find_alloc_cfqg(cfqd, cgroup, create); + blkcg = task_blkio_cgroup(current); + cfqg = cfq_find_alloc_cfqg(cfqd, blkcg, create); if (!cfqg && create) cfqg = &cfqd->root_group; rcu_read_unlock(); -- cgit v0.10.2 From 86f315bbb2374f1f077500ad131dd9b71856e697 Mon Sep 17 00:00:00 2001 From: Chris Ball Date: Mon, 16 May 2011 11:32:26 -0400 Subject: Revert "mmc: fix a race between card-detect rescan and clock-gate work instances" This reverts commit 26fc8775b51484d8c0a671198639c6d5ae60533e, which has been reported to cause boot/resume-time crashes for some users: https://bbs.archlinux.org/viewtopic.php?id=118751. Signed-off-by: Chris Ball Cc: diff --git a/drivers/mmc/core/host.c b/drivers/mmc/core/host.c index 2b200c1..461e6a1 100644 --- a/drivers/mmc/core/host.c +++ b/drivers/mmc/core/host.c @@ -94,7 +94,7 @@ static void mmc_host_clk_gate_delayed(struct mmc_host *host) spin_unlock_irqrestore(&host->clk_lock, flags); return; } - mmc_claim_host(host); + mutex_lock(&host->clk_gate_mutex); spin_lock_irqsave(&host->clk_lock, flags); if (!host->clk_requests) { spin_unlock_irqrestore(&host->clk_lock, flags); @@ -104,7 +104,7 @@ static void mmc_host_clk_gate_delayed(struct mmc_host *host) pr_debug("%s: gated MCI clock\n", mmc_hostname(host)); } spin_unlock_irqrestore(&host->clk_lock, flags); - mmc_release_host(host); + mutex_unlock(&host->clk_gate_mutex); } /* @@ -130,7 +130,7 @@ void mmc_host_clk_ungate(struct mmc_host *host) { unsigned long flags; - mmc_claim_host(host); + mutex_lock(&host->clk_gate_mutex); spin_lock_irqsave(&host->clk_lock, flags); if (host->clk_gated) { spin_unlock_irqrestore(&host->clk_lock, flags); @@ -140,7 +140,7 @@ void mmc_host_clk_ungate(struct mmc_host *host) } host->clk_requests++; spin_unlock_irqrestore(&host->clk_lock, flags); - mmc_release_host(host); + mutex_unlock(&host->clk_gate_mutex); } /** @@ -215,6 +215,7 @@ static inline void mmc_host_clk_init(struct mmc_host *host) host->clk_gated = false; INIT_WORK(&host->clk_gate_work, mmc_host_clk_gate_work); spin_lock_init(&host->clk_lock); + mutex_init(&host->clk_gate_mutex); } /** diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h index eb792cb..bcb793e 100644 --- a/include/linux/mmc/host.h +++ b/include/linux/mmc/host.h @@ -183,6 +183,7 @@ struct mmc_host { struct work_struct clk_gate_work; /* delayed clock gate */ unsigned int clk_old; /* old clock value cache */ spinlock_t clk_lock; /* lock for clk fields */ + struct mutex clk_gate_mutex; /* mutex for clock gating */ #endif /* host specific block data */ -- cgit v0.10.2 From 1a8218e96271790a07dd7065a2ef173e0f67e328 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Sun, 15 May 2011 21:26:31 +0000 Subject: net: ping: dont call udp_ioctl() udp_ioctl() really handles UDP and UDPLite protocols. 1) It can increment UDP_MIB_INERRORS in case first_packet_length() finds a frame with bad checksum. 2) It has a dependency on sizeof(struct udphdr), not applicable to ICMP/PING If ping sockets need to handle SIOCINQ/SIOCOUTQ ioctl, this should be done differently. Signed-off-by: Eric Dumazet CC: Vasiliy Kulikov Acked-by: Vasiliy Kulikov Signed-off-by: David S. Miller diff --git a/net/ipv4/ping.c b/net/ipv4/ping.c index 7041d09..41836ab 100644 --- a/net/ipv4/ping.c +++ b/net/ipv4/ping.c @@ -22,7 +22,6 @@ #include #include -#include #include #include #include @@ -609,23 +608,6 @@ do_confirm: goto out; } -/* - * IOCTL requests applicable to the UDP^H^H^HICMP protocol - */ - -int ping_ioctl(struct sock *sk, int cmd, unsigned long arg) -{ - pr_debug("ping_ioctl(sk=%p,sk->num=%u,cmd=%d,arg=%lu)\n", - inet_sk(sk), inet_sk(sk)->inet_num, cmd, arg); - switch (cmd) { - case SIOCOUTQ: - case SIOCINQ: - return udp_ioctl(sk, cmd, arg); - default: - return -ENOIOCTLCMD; - } -} - int ping_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, size_t len, int noblock, int flags, int *addr_len) { @@ -735,7 +717,6 @@ struct proto ping_prot = { .close = ping_close, .connect = ip4_datagram_connect, .disconnect = udp_disconnect, - .ioctl = ping_ioctl, .setsockopt = ip_setsockopt, .getsockopt = ip_getsockopt, .sendmsg = ping_sendmsg, -- cgit v0.10.2 From 602a5322a7a1b6b005cb50d423939bb7a8782838 Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Mon, 16 May 2011 17:32:39 +0100 Subject: sfc: Fix TX queue numbering when separate_tx_channels=1 This option appears to have been broken by commit 8313aca38b3937947fffebca6e34bac8e24300c8 ('sfc: Allocate each channel separately, along with its RX and TX queues'). Signed-off-by: Ben Hutchings diff --git a/drivers/net/sfc/efx.c b/drivers/net/sfc/efx.c index 38a55e9..796c47e 100644 --- a/drivers/net/sfc/efx.c +++ b/drivers/net/sfc/efx.c @@ -1319,8 +1319,20 @@ static void efx_remove_interrupts(struct efx_nic *efx) static void efx_set_channels(struct efx_nic *efx) { + struct efx_channel *channel; + struct efx_tx_queue *tx_queue; + efx->tx_channel_offset = separate_tx_channels ? efx->n_channels - efx->n_tx_channels : 0; + + /* We need to adjust the TX queue numbers if we have separate + * RX-only and TX-only channels. + */ + efx_for_each_channel(channel, efx) { + efx_for_each_channel_tx_queue(tx_queue, channel) + tx_queue->queue -= (efx->tx_channel_offset * + EFX_TXQ_TYPES); + } } static int efx_probe_nic(struct efx_nic *efx) -- cgit v0.10.2 From 7c1bfd685bcdc822ab1d7411ea05c82bd2a7b260 Mon Sep 17 00:00:00 2001 From: Konrad Rzeszutek Wilk Date: Mon, 16 May 2011 13:47:30 -0400 Subject: xen/pci: Fix compiler error when CONFIG_XEN_PRIVILEGED_GUEST is not set. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit If we have CONFIG_XEN and the other parameters to build an Linux kernel that is non-privileged, the xen_[find|register|unregister]_ device_domain_owner functions should not be compiled. They should use the nops defined in arch/x86/include/asm/xen/pci.h instead. This fixes: arch/x86/pci/xen.c:496: error: redefinition of ‘xen_find_device_domain_owner’ arch/x86/include/asm/xen/pci.h:25: note: previous definition of ‘xen_find_device_domain_owner’ was here arch/x86/pci/xen.c:510: error: redefinition of ‘xen_register_device_domain_owner’ arch/x86/include/asm/xen/pci.h:29: note: previous definition of ‘xen_register_device_domain_owner’ was here arch/x86/pci/xen.c:532: error: redefinition of ‘xen_unregister_device_domain_owner’ arch/x86/include/asm/xen/pci.h:34: note: previous definition of ‘xen_unregister_device_domain_owner’ was here Signed-off-by: Konrad Rzeszutek Wilk Reported-by: Randy Dunlap diff --git a/arch/x86/pci/xen.c b/arch/x86/pci/xen.c index 393981f..8214724 100644 --- a/arch/x86/pci/xen.c +++ b/arch/x86/pci/xen.c @@ -473,6 +473,7 @@ void __init xen_setup_pirqs(void) } #endif +#ifdef CONFIG_XEN_DOM0 struct xen_device_domain_owner { domid_t domain; struct pci_dev *dev; @@ -545,3 +546,4 @@ int xen_unregister_device_domain_owner(struct pci_dev *dev) return 0; } EXPORT_SYMBOL_GPL(xen_unregister_device_domain_owner); +#endif -- cgit v0.10.2 From c5be24ff62d238a3fdd5d15461b420cd72e78a14 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Fri, 13 May 2011 18:01:21 -0400 Subject: ipv4: Trivial rt->rt_src conversions in net/ipv4/route.c At these points we have a fully filled in value via the IP header the form of ip_hdr(skb)->saddr Signed-off-by: David S. Miller diff --git a/net/ipv4/route.c b/net/ipv4/route.c index ad141d8..cb93c32 100644 --- a/net/ipv4/route.c +++ b/net/ipv4/route.c @@ -1435,7 +1435,7 @@ void ip_rt_send_redirect(struct sk_buff *skb) peer->rate_tokens == ip_rt_redirect_number && net_ratelimit()) printk(KERN_WARNING "host %pI4/if%d ignores redirects for %pI4 to %pI4.\n", - &rt->rt_src, rt->rt_iif, + &ip_hdr(skb)->saddr, rt->rt_iif, &rt->rt_dst, &rt->rt_gateway); #endif } @@ -1704,7 +1704,7 @@ void ip_rt_get_source(u8 *addr, struct sk_buff *skb, struct rtable *rt) __be32 src; if (rt_is_output_route(rt)) - src = rt->rt_src; + src = ip_hdr(skb)->saddr; else { struct fib_result res; struct flowi4 fl4; -- cgit v0.10.2 From 538dd2e3976a7c572ee927d6bbebe01bf4d6f128 Mon Sep 17 00:00:00 2001 From: Mahesh Bandewar Date: Fri, 13 May 2011 15:08:49 +0000 Subject: bnx2x: Allow ethtool to enable/disable loopback. This patch updates the bnx2x_set_features() to handle loopback mode. When enabled; it sets internal-MAC loopback. Signed-off-by: Mahesh Bandewar Signed-off-by: David S. Miller diff --git a/drivers/net/bnx2x/bnx2x_cmn.c b/drivers/net/bnx2x/bnx2x_cmn.c index 6ee6601..ca2bbc0 100644 --- a/drivers/net/bnx2x/bnx2x_cmn.c +++ b/drivers/net/bnx2x/bnx2x_cmn.c @@ -2840,15 +2840,31 @@ int bnx2x_set_features(struct net_device *dev, u32 features) { struct bnx2x *bp = netdev_priv(dev); u32 flags = bp->flags; + bool bnx2x_reload = false; if (features & NETIF_F_LRO) flags |= TPA_ENABLE_FLAG; else flags &= ~TPA_ENABLE_FLAG; + if (features & NETIF_F_LOOPBACK) { + if (bp->link_params.loopback_mode != LOOPBACK_BMAC) { + bp->link_params.loopback_mode = LOOPBACK_BMAC; + bnx2x_reload = true; + } + } else { + if (bp->link_params.loopback_mode != LOOPBACK_NONE) { + bp->link_params.loopback_mode = LOOPBACK_NONE; + bnx2x_reload = true; + } + } + if (flags ^ bp->flags) { bp->flags = flags; + bnx2x_reload = true; + } + if (bnx2x_reload) { if (bp->recovery_state == BNX2X_RECOVERY_DONE) return bnx2x_reload_if_running(dev); /* else: bnx2x_nic_load() will be called at end of recovery */ diff --git a/drivers/net/bnx2x/bnx2x_main.c b/drivers/net/bnx2x/bnx2x_main.c index 2762edf..f45c0ca 100644 --- a/drivers/net/bnx2x/bnx2x_main.c +++ b/drivers/net/bnx2x/bnx2x_main.c @@ -9273,6 +9273,9 @@ static int __devinit bnx2x_init_dev(struct pci_dev *pdev, if (bp->flags & USING_DAC_FLAG) dev->features |= NETIF_F_HIGHDMA; + /* Add Loopback capability to the device */ + dev->hw_features |= NETIF_F_LOOPBACK; + #ifdef BCM_DCBNL dev->dcbnl_ops = &bnx2x_dcbnl_ops; #endif -- cgit v0.10.2 From 8d38d74b648513dd8ed8bd2b67d899208ef4e09e Mon Sep 17 00:00:00 2001 From: Chen Gong Date: Mon, 16 May 2011 10:58:57 -0700 Subject: pstore: fix one type of return value in pstore the return type of function _read_ in pstore is size_t, but in the callback function of _read_, the logic doesn't consider it too much, which means if negative value (assuming error here) is returned, it will be converted to positive because of type casting. ssize_t is enough for this function. Signed-off-by: Chen Gong Signed-off-by: Tony Luck diff --git a/drivers/acpi/apei/erst.c b/drivers/acpi/apei/erst.c index d6cb0ff..d5a89d0 100644 --- a/drivers/acpi/apei/erst.c +++ b/drivers/acpi/apei/erst.c @@ -929,7 +929,7 @@ static int erst_check_table(struct acpi_table_erst *erst_tab) return 0; } -static size_t erst_reader(u64 *id, enum pstore_type_id *type, +static ssize_t erst_reader(u64 *id, enum pstore_type_id *type, struct timespec *time); static u64 erst_writer(enum pstore_type_id type, size_t size); @@ -957,7 +957,7 @@ struct cper_pstore_record { char data[]; } __packed; -static size_t erst_reader(u64 *id, enum pstore_type_id *type, +static ssize_t erst_reader(u64 *id, enum pstore_type_id *type, struct timespec *time) { int rc; diff --git a/fs/pstore/platform.c b/fs/pstore/platform.c index f835a25..912403c 100644 --- a/fs/pstore/platform.c +++ b/fs/pstore/platform.c @@ -152,7 +152,7 @@ EXPORT_SYMBOL_GPL(pstore_register); void pstore_get_records(void) { struct pstore_info *psi = psinfo; - size_t size; + ssize_t size; u64 id; enum pstore_type_id type; struct timespec time; @@ -163,7 +163,7 @@ void pstore_get_records(void) mutex_lock(&psinfo->buf_mutex); while ((size = psi->read(&id, &type, &time)) > 0) { - if (pstore_mkfile(type, psi->name, id, psi->buf, size, + if (pstore_mkfile(type, psi->name, id, psi->buf, (size_t)size, time, psi->erase)) failed++; } diff --git a/include/linux/pstore.h b/include/linux/pstore.h index 4197773..14ce2f5 100644 --- a/include/linux/pstore.h +++ b/include/linux/pstore.h @@ -35,7 +35,7 @@ struct pstore_info { struct mutex buf_mutex; /* serialize access to 'buf' */ char *buf; size_t bufsize; - size_t (*read)(u64 *id, enum pstore_type_id *type, + ssize_t (*read)(u64 *id, enum pstore_type_id *type, struct timespec *time); u64 (*write)(enum pstore_type_id type, size_t size); int (*erase)(u64 id); -- cgit v0.10.2 From 06cf91b4b4aafa50ee0a94c81d2c6922a18af242 Mon Sep 17 00:00:00 2001 From: Chen Gong Date: Mon, 16 May 2011 11:00:27 -0700 Subject: pstore: fix pstore filesystem mount/remount issue Currently after mount/remount operation on pstore filesystem, the content on pstore will be lost. It is because current ERST implementation doesn't support multi-user usage, which moves internal pointer to the end after accessing it. Adding multi-user support for pstore usage. Signed-off-by: Chen Gong Signed-off-by: Tony Luck diff --git a/drivers/acpi/apei/erst.c b/drivers/acpi/apei/erst.c index d5a89d0..ddb68c4 100644 --- a/drivers/acpi/apei/erst.c +++ b/drivers/acpi/apei/erst.c @@ -929,6 +929,8 @@ static int erst_check_table(struct acpi_table_erst *erst_tab) return 0; } +static int erst_open_pstore(struct pstore_info *psi); +static int erst_close_pstore(struct pstore_info *psi); static ssize_t erst_reader(u64 *id, enum pstore_type_id *type, struct timespec *time); static u64 erst_writer(enum pstore_type_id type, size_t size); @@ -936,6 +938,8 @@ static u64 erst_writer(enum pstore_type_id type, size_t size); static struct pstore_info erst_info = { .owner = THIS_MODULE, .name = "erst", + .open = erst_open_pstore, + .close = erst_close_pstore, .read = erst_reader, .write = erst_writer, .erase = erst_clear @@ -957,12 +961,32 @@ struct cper_pstore_record { char data[]; } __packed; +static int reader_pos; + +static int erst_open_pstore(struct pstore_info *psi) +{ + int rc; + + if (erst_disable) + return -ENODEV; + + rc = erst_get_record_id_begin(&reader_pos); + + return rc; +} + +static int erst_close_pstore(struct pstore_info *psi) +{ + erst_get_record_id_end(); + + return 0; +} + static ssize_t erst_reader(u64 *id, enum pstore_type_id *type, struct timespec *time) { int rc; - ssize_t len; - unsigned long flags; + ssize_t len = 0; u64 record_id; struct cper_pstore_record *rcd = (struct cper_pstore_record *) (erst_info.buf - sizeof(*rcd)); @@ -970,24 +994,21 @@ static ssize_t erst_reader(u64 *id, enum pstore_type_id *type, if (erst_disable) return -ENODEV; - raw_spin_lock_irqsave(&erst_lock, flags); skip: - rc = __erst_get_next_record_id(&record_id); - if (rc) { - raw_spin_unlock_irqrestore(&erst_lock, flags); - return rc; - } + rc = erst_get_record_id_next(&reader_pos, &record_id); + if (rc) + goto out; + /* no more record */ if (record_id == APEI_ERST_INVALID_RECORD_ID) { - raw_spin_unlock_irqrestore(&erst_lock, flags); - return 0; + rc = -1; + goto out; } - len = __erst_read(record_id, &rcd->hdr, sizeof(*rcd) + + len = erst_read(record_id, &rcd->hdr, sizeof(*rcd) + erst_erange.size); if (uuid_le_cmp(rcd->hdr.creator_id, CPER_CREATOR_PSTORE) != 0) goto skip; - raw_spin_unlock_irqrestore(&erst_lock, flags); *id = record_id; if (uuid_le_cmp(rcd->sec_hdr.section_type, @@ -1005,7 +1026,8 @@ skip: time->tv_sec = 0; time->tv_nsec = 0; - return len - sizeof(*rcd); +out: + return (rc < 0) ? rc : (len - sizeof(*rcd)); } static u64 erst_writer(enum pstore_type_id type, size_t size) diff --git a/fs/pstore/platform.c b/fs/pstore/platform.c index 912403c..f2c3ff2 100644 --- a/fs/pstore/platform.c +++ b/fs/pstore/platform.c @@ -156,17 +156,23 @@ void pstore_get_records(void) u64 id; enum pstore_type_id type; struct timespec time; - int failed = 0; + int failed = 0, rc; if (!psi) return; mutex_lock(&psinfo->buf_mutex); + rc = psi->open(psi); + if (rc) + goto out; + while ((size = psi->read(&id, &type, &time)) > 0) { if (pstore_mkfile(type, psi->name, id, psi->buf, (size_t)size, time, psi->erase)) failed++; } + psi->close(psi); +out: mutex_unlock(&psinfo->buf_mutex); if (failed) diff --git a/include/linux/pstore.h b/include/linux/pstore.h index 14ce2f5..2455ef2 100644 --- a/include/linux/pstore.h +++ b/include/linux/pstore.h @@ -35,6 +35,8 @@ struct pstore_info { struct mutex buf_mutex; /* serialize access to 'buf' */ char *buf; size_t bufsize; + int (*open)(struct pstore_info *psi); + int (*close)(struct pstore_info *psi); ssize_t (*read)(u64 *id, enum pstore_type_id *type, struct timespec *time); u64 (*write)(enum pstore_type_id type, size_t size); -- cgit v0.10.2 From f5ec25deb2471bd49e907ab2f9ef6f860eb7cf95 Mon Sep 17 00:00:00 2001 From: Chen Gong Date: Mon, 16 May 2011 11:01:39 -0700 Subject: pstore: fix potential logic issue in pstore read interface 1) in the calling of erst_read, the parameter of buffer size maybe overflows and cause crash 2) the return value of erst_read should be checked more strictly Signed-off-by: Chen Gong Signed-off-by: Tony Luck diff --git a/drivers/acpi/apei/erst.c b/drivers/acpi/apei/erst.c index ddb68c4..e6cef8e 100644 --- a/drivers/acpi/apei/erst.c +++ b/drivers/acpi/apei/erst.c @@ -1006,7 +1006,14 @@ skip: } len = erst_read(record_id, &rcd->hdr, sizeof(*rcd) + - erst_erange.size); + erst_info.bufsize); + /* The record may be cleared by others, try read next record */ + if (len == -ENOENT) + goto skip; + else if (len < 0) { + rc = -1; + goto out; + } if (uuid_le_cmp(rcd->hdr.creator_id, CPER_CREATOR_PSTORE) != 0) goto skip; -- cgit v0.10.2 From 8220ba3e2e671492b777159d8dac721f95f4a0ec Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Thu, 12 May 2011 16:50:04 -0700 Subject: iwlegacy: Silence DEBUG_STRICT_USER_COPY_CHECKS=y warning Enabling DEBUG_STRICT_USER_COPY_CHECKS causes the following warning: In file included from arch/x86/include/asm/uaccess.h:573, from include/net/checksum.h:25, from include/linux/skbuff.h:28, from drivers/net/wireless/iwlegacy/iwl-4965-rs.c:28: In function 'copy_from_user', inlined from 'iwl4965_rs_sta_dbgfs_scale_table_write' at drivers/net/wireless/iwlegacy/iwl-4965-rs.c:2616: arch/x86/include/asm/uaccess_64.h:65: warning: call to 'copy_from_user_overflow' declared with attribute warning: copy_from_user() buffer size is not provably correct presumably due to buf_size being signed causing GCC to fail to see that buf_size can't become negative. Cc: Johannes Berg Signed-off-by: Stephen Boyd Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwlegacy/iwl-4965-rs.c b/drivers/net/wireless/iwlegacy/iwl-4965-rs.c index 8950939..24d1499 100644 --- a/drivers/net/wireless/iwlegacy/iwl-4965-rs.c +++ b/drivers/net/wireless/iwlegacy/iwl-4965-rs.c @@ -2604,7 +2604,7 @@ static ssize_t iwl4965_rs_sta_dbgfs_scale_table_write(struct file *file, struct iwl_lq_sta *lq_sta = file->private_data; struct iwl_priv *priv; char buf[64]; - int buf_size; + size_t buf_size; u32 parsed_rate; struct iwl_station_priv *sta_priv = container_of(lq_sta, struct iwl_station_priv, lq_sta); -- cgit v0.10.2 From 805d7d23ef9806e47b550ad80270c4cea4ffc984 Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Thu, 12 May 2011 16:50:05 -0700 Subject: iwlwifi: Silence DEBUG_STRICT_USER_COPY_CHECKS=y warning Enabling DEBUG_STRICT_USER_COPY_CHECKS causes the following warning: In file included from arch/x86/include/asm/uaccess.h:573, from include/net/checksum.h:25, from include/linux/skbuff.h:28, from drivers/net/wireless/iwlwifi/iwl-agn-rs.c:28: In function 'copy_from_user', inlined from 'rs_sta_dbgfs_scale_table_write' at drivers/net/wireless/iwlwifi/iwl-agn-rs.c:3099: arch/x86/include/asm/uaccess_64.h:65: warning: call to 'copy_from_user_overflow' declared with attribute warning: copy_from_user() buffer size is not provably correct presumably due to buf_size being signed causing GCC to fail to see that buf_size can't become negative. Signed-off-by: Stephen Boyd Signed-off-by: Wey-Yi Guy Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c index dbe6295..91f2655 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c @@ -3086,7 +3086,7 @@ static ssize_t rs_sta_dbgfs_scale_table_write(struct file *file, struct iwl_lq_sta *lq_sta = file->private_data; struct iwl_priv *priv; char buf[64]; - int buf_size; + size_t buf_size; u32 parsed_rate; struct iwl_station_priv *sta_priv = container_of(lq_sta, struct iwl_station_priv, lq_sta); -- cgit v0.10.2 From 7527a782e187d1214a5b3dc2897ce441033bb4ef Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 13 May 2011 10:58:57 +0200 Subject: cfg80211: advertise possible interface combinations Add the ability to advertise interface combinations in nl80211. This allows the driver to indicate what the combinations are that it supports. "Combinations" of just a single interface are implicit, as previously. Note that cfg80211 will enforce that the restrictions are met, but not for all drivers yet (once all drivers are updated, we can remove the flag and enforce for all). When no combinations are actually supported, an empty list will be exported so that userspace can know if the kernel exported this info or not (although it isn't clear to me what tools using the info should do if the kernel didn't export it). Since some interface types are purely virtual/software and don't fit the restrictions, those are exposed in a new list of pure SW types, not subject to restrictions. This mainly exists to handle AP-VLAN and monitor interfaces in mac80211. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville diff --git a/include/linux/nl80211.h b/include/linux/nl80211.h index 281a2bb..0ea497c 100644 --- a/include/linux/nl80211.h +++ b/include/linux/nl80211.h @@ -77,6 +77,39 @@ */ /** + * DOC: Virtual interface / concurrency capabilities + * + * Some devices are able to operate with virtual MACs, they can have + * more than one virtual interface. The capability handling for this + * is a bit complex though, as there may be a number of restrictions + * on the types of concurrency that are supported. + * + * To start with, each device supports the interface types listed in + * the %NL80211_ATTR_SUPPORTED_IFTYPES attribute, but by listing the + * types there no concurrency is implied. + * + * Once concurrency is desired, more attributes must be observed: + * To start with, since some interface types are purely managed in + * software, like the AP-VLAN type in mac80211 for example, there's + * an additional list of these, they can be added at any time and + * are only restricted by some semantic restrictions (e.g. AP-VLAN + * cannot be added without a corresponding AP interface). This list + * is exported in the %NL80211_ATTR_SOFTWARE_IFTYPES attribute. + * + * Further, the list of supported combinations is exported. This is + * in the %NL80211_ATTR_INTERFACE_COMBINATIONS attribute. Basically, + * it exports a list of "groups", and at any point in time the + * interfaces that are currently active must fall into any one of + * the advertised groups. Within each group, there are restrictions + * on the number of interfaces of different types that are supported + * and also the number of different channels, along with potentially + * some other restrictions. See &enum nl80211_if_combination_attrs. + * + * All together, these attributes define the concurrency of virtual + * interfaces that a given device supports. + */ + +/** * enum nl80211_commands - supported nl80211 commands * * @NL80211_CMD_UNSPEC: unspecified command to catch errors @@ -954,6 +987,14 @@ enum nl80211_commands { * @NL80211_ATTR_SCHED_SCAN_INTERVAL: Interval between scheduled scan * cycles, in msecs. * + * @NL80211_ATTR_INTERFACE_COMBINATIONS: Nested attribute listing the supported + * interface combinations. In each nested item, it contains attributes + * defined in &enum nl80211_if_combination_attrs. + * @NL80211_ATTR_SOFTWARE_IFTYPES: Nested attribute (just like + * %NL80211_ATTR_SUPPORTED_IFTYPES) containing the interface types that + * are managed in software: interfaces of these types aren't subject to + * any restrictions in their number or combinations. + * * @NL80211_ATTR_MAX: highest attribute number currently defined * @__NL80211_ATTR_AFTER_LAST: internal use */ @@ -1149,6 +1190,9 @@ enum nl80211_attrs { NL80211_ATTR_SCHED_SCAN_INTERVAL, + NL80211_ATTR_INTERFACE_COMBINATIONS, + NL80211_ATTR_SOFTWARE_IFTYPES, + /* add attributes here, update the policy in nl80211.c */ __NL80211_ATTR_AFTER_LAST, @@ -1201,7 +1245,9 @@ enum nl80211_attrs { * @NL80211_IFTYPE_ADHOC: independent BSS member * @NL80211_IFTYPE_STATION: managed BSS member * @NL80211_IFTYPE_AP: access point - * @NL80211_IFTYPE_AP_VLAN: VLAN interface for access points + * @NL80211_IFTYPE_AP_VLAN: VLAN interface for access points; VLAN interfaces + * are a bit special in that they must always be tied to a pre-existing + * AP type interface. * @NL80211_IFTYPE_WDS: wireless distribution interface * @NL80211_IFTYPE_MONITOR: monitor interface receiving all frames * @NL80211_IFTYPE_MESH_POINT: mesh point @@ -2206,4 +2252,78 @@ enum nl80211_wowlan_triggers { MAX_NL80211_WOWLAN_TRIG = NUM_NL80211_WOWLAN_TRIG - 1 }; +/** + * enum nl80211_iface_limit_attrs - limit attributes + * @NL80211_IFACE_LIMIT_UNSPEC: (reserved) + * @NL80211_IFACE_LIMIT_MAX: maximum number of interfaces that + * can be chosen from this set of interface types (u32) + * @NL80211_IFACE_LIMIT_TYPES: nested attribute containing a + * flag attribute for each interface type in this set + * @NUM_NL80211_IFACE_LIMIT: number of attributes + * @MAX_NL80211_IFACE_LIMIT: highest attribute number + */ +enum nl80211_iface_limit_attrs { + NL80211_IFACE_LIMIT_UNSPEC, + NL80211_IFACE_LIMIT_MAX, + NL80211_IFACE_LIMIT_TYPES, + + /* keep last */ + NUM_NL80211_IFACE_LIMIT, + MAX_NL80211_IFACE_LIMIT = NUM_NL80211_IFACE_LIMIT - 1 +}; + +/** + * enum nl80211_if_combination_attrs -- interface combination attributes + * + * @NL80211_IFACE_COMB_UNSPEC: (reserved) + * @NL80211_IFACE_COMB_LIMITS: Nested attributes containing the limits + * for given interface types, see &enum nl80211_iface_limit_attrs. + * @NL80211_IFACE_COMB_MAXNUM: u32 attribute giving the total number of + * interfaces that can be created in this group. This number doesn't + * apply to interfaces purely managed in software, which are listed + * in a separate attribute %NL80211_ATTR_INTERFACES_SOFTWARE. + * @NL80211_IFACE_COMB_STA_AP_BI_MATCH: flag attribute specifying that + * beacon intervals within this group must be all the same even for + * infrastructure and AP/GO combinations, i.e. the GO(s) must adopt + * the infrastructure network's beacon interval. + * @NL80211_IFACE_COMB_NUM_CHANNELS: u32 attribute specifying how many + * different channels may be used within this group. + * @NUM_NL80211_IFACE_COMB: number of attributes + * @MAX_NL80211_IFACE_COMB: highest attribute number + * + * Examples: + * limits = [ #{STA} <= 1, #{AP} <= 1 ], matching BI, channels = 1, max = 2 + * => allows an AP and a STA that must match BIs + * + * numbers = [ #{AP, P2P-GO} <= 8 ], channels = 1, max = 8 + * => allows 8 of AP/GO + * + * numbers = [ #{STA} <= 2 ], channels = 2, max = 2 + * => allows two STAs on different channels + * + * numbers = [ #{STA} <= 1, #{P2P-client,P2P-GO} <= 3 ], max = 4 + * => allows a STA plus three P2P interfaces + * + * The list of these four possiblities could completely be contained + * within the %NL80211_ATTR_INTERFACE_COMBINATIONS attribute to indicate + * that any of these groups must match. + * + * "Combinations" of just a single interface will not be listed here, + * a single interface of any valid interface type is assumed to always + * be possible by itself. This means that implicitly, for each valid + * interface type, the following group always exists: + * numbers = [ #{} <= 1 ], channels = 1, max = 1 + */ +enum nl80211_if_combination_attrs { + NL80211_IFACE_COMB_UNSPEC, + NL80211_IFACE_COMB_LIMITS, + NL80211_IFACE_COMB_MAXNUM, + NL80211_IFACE_COMB_STA_AP_BI_MATCH, + NL80211_IFACE_COMB_NUM_CHANNELS, + + /* keep last */ + NUM_NL80211_IFACE_COMB, + MAX_NL80211_IFACE_COMB = NUM_NL80211_IFACE_COMB - 1 +}; + #endif /* __LINUX_NL80211_H */ diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index e1f1b41..04afcfb 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -1547,6 +1547,10 @@ struct cfg80211_ops { * hints read the documenation for regulatory_hint_found_beacon() * @WIPHY_FLAG_NETNS_OK: if not set, do not allow changing the netns of this * wiphy at all + * @WIPHY_FLAG_ENFORCE_COMBINATIONS: Set this flag to enforce interface + * combinations for this device. This flag is used for backward + * compatibility only until all drivers advertise combinations and + * they will always be enforced. * @WIPHY_FLAG_PS_ON_BY_DEFAULT: if set to true, powersave will be enabled * by default -- this flag will be set depending on the kernel's default * on wiphy_new(), but can be changed by the driver if it has a good @@ -1574,6 +1578,81 @@ enum wiphy_flags { WIPHY_FLAG_IBSS_RSN = BIT(8), WIPHY_FLAG_MESH_AUTH = BIT(10), WIPHY_FLAG_SUPPORTS_SCHED_SCAN = BIT(11), + WIPHY_FLAG_ENFORCE_COMBINATIONS = BIT(12), +}; + +/** + * struct ieee80211_iface_limit - limit on certain interface types + * @max: maximum number of interfaces of these types + * @types: interface types (bits) + */ +struct ieee80211_iface_limit { + u16 max; + u16 types; +}; + +/** + * struct ieee80211_iface_combination - possible interface combination + * @limits: limits for the given interface types + * @n_limits: number of limitations + * @num_different_channels: can use up to this many different channels + * @max_interfaces: maximum number of interfaces in total allowed in this + * group + * @beacon_int_infra_match: In this combination, the beacon intervals + * between infrastructure and AP types must match. This is required + * only in special cases. + * + * These examples can be expressed as follows: + * + * Allow #STA <= 1, #AP <= 1, matching BI, channels = 1, 2 total: + * + * struct ieee80211_iface_limit limits1[] = { + * { .max = 1, .types = BIT(NL80211_IFTYPE_STATION), }, + * { .max = 1, .types = BIT(NL80211_IFTYPE_AP}, }, + * }; + * struct ieee80211_iface_combination combination1 = { + * .limits = limits1, + * .n_limits = ARRAY_SIZE(limits1), + * .max_interfaces = 2, + * .beacon_int_infra_match = true, + * }; + * + * + * Allow #{AP, P2P-GO} <= 8, channels = 1, 8 total: + * + * struct ieee80211_iface_limit limits2[] = { + * { .max = 8, .types = BIT(NL80211_IFTYPE_AP) | + * BIT(NL80211_IFTYPE_P2P_GO), }, + * }; + * struct ieee80211_iface_combination combination2 = { + * .limits = limits2, + * .n_limits = ARRAY_SIZE(limits2), + * .max_interfaces = 8, + * .num_different_channels = 1, + * }; + * + * + * Allow #STA <= 1, #{P2P-client,P2P-GO} <= 3 on two channels, 4 total. + * This allows for an infrastructure connection and three P2P connections. + * + * struct ieee80211_iface_limit limits3[] = { + * { .max = 1, .types = BIT(NL80211_IFTYPE_STATION), }, + * { .max = 3, .types = BIT(NL80211_IFTYPE_P2P_GO) | + * BIT(NL80211_IFTYPE_P2P_CLIENT), }, + * }; + * struct ieee80211_iface_combination combination3 = { + * .limits = limits3, + * .n_limits = ARRAY_SIZE(limits3), + * .max_interfaces = 4, + * .num_different_channels = 2, + * }; + */ +struct ieee80211_iface_combination { + const struct ieee80211_iface_limit *limits; + u32 num_different_channels; + u16 max_interfaces; + u8 n_limits; + bool beacon_int_infra_match; }; struct mac_address { @@ -1653,6 +1732,11 @@ struct wiphy_wowlan_support { * @priv: driver private data (sized according to wiphy_new() parameter) * @interface_modes: bitmask of interfaces types valid for this wiphy, * must be set by driver + * @iface_combinations: Valid interface combinations array, should not + * list single interface types. + * @n_iface_combinations: number of entries in @iface_combinations array. + * @software_iftypes: bitmask of software interface types, these are not + * subject to any restrictions since they are purely managed in SW. * @flags: wiphy flags, see &enum wiphy_flags * @bss_priv_size: each BSS struct has private data allocated with it, * this variable determines its size @@ -1697,6 +1781,10 @@ struct wiphy { const struct ieee80211_txrx_stypes *mgmt_stypes; + const struct ieee80211_iface_combination *iface_combinations; + int n_iface_combinations; + u16 software_iftypes; + u16 n_addresses; /* Supported interface modes, OR together BIT(NL80211_IFTYPE_...) */ diff --git a/net/mac80211/main.c b/net/mac80211/main.c index 7f89011..79a2281 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c @@ -685,7 +685,7 @@ EXPORT_SYMBOL(ieee80211_alloc_hw); int ieee80211_register_hw(struct ieee80211_hw *hw) { struct ieee80211_local *local = hw_to_local(hw); - int result; + int result, i; enum ieee80211_band band; int channels, max_bitrates; bool supp_ht; @@ -743,11 +743,19 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) return -ENOMEM; /* if low-level driver supports AP, we also support VLAN */ - if (local->hw.wiphy->interface_modes & BIT(NL80211_IFTYPE_AP)) - local->hw.wiphy->interface_modes |= BIT(NL80211_IFTYPE_AP_VLAN); + if (local->hw.wiphy->interface_modes & BIT(NL80211_IFTYPE_AP)) { + hw->wiphy->interface_modes |= BIT(NL80211_IFTYPE_AP_VLAN); + hw->wiphy->software_iftypes |= BIT(NL80211_IFTYPE_AP_VLAN); + } /* mac80211 always supports monitor */ - local->hw.wiphy->interface_modes |= BIT(NL80211_IFTYPE_MONITOR); + hw->wiphy->interface_modes |= BIT(NL80211_IFTYPE_MONITOR); + hw->wiphy->software_iftypes |= BIT(NL80211_IFTYPE_MONITOR); + + /* mac80211 doesn't support more than 1 channel */ + for (i = 0; i < hw->wiphy->n_iface_combinations; i++) + if (hw->wiphy->iface_combinations[i].num_different_channels > 1) + return -EINVAL; #ifndef CONFIG_MAC80211_MESH /* mesh depends on Kconfig, but drivers should set it if they want */ diff --git a/net/wireless/core.c b/net/wireless/core.c index 18b002f..c22ef34 100644 --- a/net/wireless/core.c +++ b/net/wireless/core.c @@ -416,6 +416,67 @@ struct wiphy *wiphy_new(const struct cfg80211_ops *ops, int sizeof_priv) } EXPORT_SYMBOL(wiphy_new); +static int wiphy_verify_combinations(struct wiphy *wiphy) +{ + const struct ieee80211_iface_combination *c; + int i, j; + + /* If we have combinations enforce them */ + if (wiphy->n_iface_combinations) + wiphy->flags |= WIPHY_FLAG_ENFORCE_COMBINATIONS; + + for (i = 0; i < wiphy->n_iface_combinations; i++) { + u32 cnt = 0; + u16 all_iftypes = 0; + + c = &wiphy->iface_combinations[i]; + + /* Combinations with just one interface aren't real */ + if (WARN_ON(c->max_interfaces < 2)) + return -EINVAL; + + /* Need at least one channel */ + if (WARN_ON(!c->num_different_channels)) + return -EINVAL; + + if (WARN_ON(!c->n_limits)) + return -EINVAL; + + for (j = 0; j < c->n_limits; j++) { + u16 types = c->limits[j].types; + + /* + * interface types shouldn't overlap, this is + * used in cfg80211_can_change_interface() + */ + if (WARN_ON(types & all_iftypes)) + return -EINVAL; + all_iftypes |= types; + + if (WARN_ON(!c->limits[j].max)) + return -EINVAL; + + /* Shouldn't list software iftypes in combinations! */ + if (WARN_ON(wiphy->software_iftypes & types)) + return -EINVAL; + + cnt += c->limits[j].max; + /* + * Don't advertise an unsupported type + * in a combination. + */ + if (WARN_ON((wiphy->interface_modes & types) != types)) + return -EINVAL; + } + + /* You can't even choose that many! */ + if (WARN_ON(cnt < c->max_interfaces)) + return -EINVAL; + } + + return 0; +} + int wiphy_register(struct wiphy *wiphy) { struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); @@ -444,6 +505,10 @@ int wiphy_register(struct wiphy *wiphy) if (WARN_ON(ifmodes != wiphy->interface_modes)) wiphy->interface_modes = ifmodes; + res = wiphy_verify_combinations(wiphy); + if (res) + return res; + /* sanity check supported bands/channels */ for (band = 0; band < IEEE80211_NUM_BANDS; band++) { sband = wiphy->bands[band]; @@ -698,6 +763,7 @@ static int cfg80211_netdev_notifier_call(struct notifier_block * nb, struct net_device *dev = ndev; struct wireless_dev *wdev = dev->ieee80211_ptr; struct cfg80211_registered_device *rdev; + int ret; if (!wdev) return NOTIFY_DONE; @@ -893,6 +959,9 @@ static int cfg80211_netdev_notifier_call(struct notifier_block * nb, return notifier_from_errno(-EOPNOTSUPP); if (rfkill_blocked(rdev->rfkill)) return notifier_from_errno(-ERFKILL); + ret = cfg80211_can_add_interface(rdev, wdev->iftype); + if (ret) + return notifier_from_errno(ret); break; } diff --git a/net/wireless/core.h b/net/wireless/core.h index d4b8f4c..bf0fb40 100644 --- a/net/wireless/core.h +++ b/net/wireless/core.h @@ -422,6 +422,17 @@ int cfg80211_change_iface(struct cfg80211_registered_device *rdev, u32 *flags, struct vif_params *params); void cfg80211_process_rdev_events(struct cfg80211_registered_device *rdev); +int cfg80211_can_change_interface(struct cfg80211_registered_device *rdev, + struct wireless_dev *wdev, + enum nl80211_iftype iftype); + +static inline int +cfg80211_can_add_interface(struct cfg80211_registered_device *rdev, + enum nl80211_iftype iftype) +{ + return cfg80211_can_change_interface(rdev, NULL, iftype); +} + struct ieee80211_channel * rdev_freq_to_chan(struct cfg80211_registered_device *rdev, int freq, enum nl80211_channel_type channel_type); diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 9ef8e28..beac296 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -564,6 +564,88 @@ static int nl80211_key_allowed(struct wireless_dev *wdev) return 0; } +static int nl80211_put_iftypes(struct sk_buff *msg, u32 attr, u16 ifmodes) +{ + struct nlattr *nl_modes = nla_nest_start(msg, attr); + int i; + + if (!nl_modes) + goto nla_put_failure; + + i = 0; + while (ifmodes) { + if (ifmodes & 1) + NLA_PUT_FLAG(msg, i); + ifmodes >>= 1; + i++; + } + + nla_nest_end(msg, nl_modes); + return 0; + +nla_put_failure: + return -ENOBUFS; +} + +static int nl80211_put_iface_combinations(struct wiphy *wiphy, + struct sk_buff *msg) +{ + struct nlattr *nl_combis; + int i, j; + + nl_combis = nla_nest_start(msg, + NL80211_ATTR_INTERFACE_COMBINATIONS); + if (!nl_combis) + goto nla_put_failure; + + for (i = 0; i < wiphy->n_iface_combinations; i++) { + const struct ieee80211_iface_combination *c; + struct nlattr *nl_combi, *nl_limits; + + c = &wiphy->iface_combinations[i]; + + nl_combi = nla_nest_start(msg, i + 1); + if (!nl_combi) + goto nla_put_failure; + + nl_limits = nla_nest_start(msg, NL80211_IFACE_COMB_LIMITS); + if (!nl_limits) + goto nla_put_failure; + + for (j = 0; j < c->n_limits; j++) { + struct nlattr *nl_limit; + + nl_limit = nla_nest_start(msg, j + 1); + if (!nl_limit) + goto nla_put_failure; + NLA_PUT_U32(msg, NL80211_IFACE_LIMIT_MAX, + c->limits[j].max); + if (nl80211_put_iftypes(msg, NL80211_IFACE_LIMIT_TYPES, + c->limits[j].types)) + goto nla_put_failure; + nla_nest_end(msg, nl_limit); + } + + nla_nest_end(msg, nl_limits); + + if (c->beacon_int_infra_match) + NLA_PUT_FLAG(msg, + NL80211_IFACE_COMB_STA_AP_BI_MATCH); + NLA_PUT_U32(msg, NL80211_IFACE_COMB_NUM_CHANNELS, + c->num_different_channels); + NLA_PUT_U32(msg, NL80211_IFACE_COMB_MAXNUM, + c->max_interfaces); + + nla_nest_end(msg, nl_combi); + } + + nla_nest_end(msg, nl_combis); + + return 0; +nla_put_failure: + return -ENOBUFS; +} + static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags, struct cfg80211_registered_device *dev) { @@ -571,13 +653,11 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags, struct nlattr *nl_bands, *nl_band; struct nlattr *nl_freqs, *nl_freq; struct nlattr *nl_rates, *nl_rate; - struct nlattr *nl_modes; struct nlattr *nl_cmds; enum ieee80211_band band; struct ieee80211_channel *chan; struct ieee80211_rate *rate; int i; - u16 ifmodes = dev->wiphy.interface_modes; const struct ieee80211_txrx_stypes *mgmt_stypes = dev->wiphy.mgmt_stypes; @@ -637,20 +717,10 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags, } } - nl_modes = nla_nest_start(msg, NL80211_ATTR_SUPPORTED_IFTYPES); - if (!nl_modes) + if (nl80211_put_iftypes(msg, NL80211_ATTR_SUPPORTED_IFTYPES, + dev->wiphy.interface_modes)) goto nla_put_failure; - i = 0; - while (ifmodes) { - if (ifmodes & 1) - NLA_PUT_FLAG(msg, i); - ifmodes >>= 1; - i++; - } - - nla_nest_end(msg, nl_modes); - nl_bands = nla_nest_start(msg, NL80211_ATTR_WIPHY_BANDS); if (!nl_bands) goto nla_put_failure; @@ -865,6 +935,13 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags, nla_nest_end(msg, nl_wowlan); } + if (nl80211_put_iftypes(msg, NL80211_ATTR_SOFTWARE_IFTYPES, + dev->wiphy.software_iftypes)) + goto nla_put_failure; + + if (nl80211_put_iface_combinations(&dev->wiphy, msg)) + goto nla_put_failure; + return genlmsg_end(msg, hdr); nla_put_failure: diff --git a/net/wireless/util.c b/net/wireless/util.c index 414c9f6..95e4e25 100644 --- a/net/wireless/util.c +++ b/net/wireless/util.c @@ -803,6 +803,11 @@ int cfg80211_change_iface(struct cfg80211_registered_device *rdev, return -EBUSY; if (ntype != otype) { + err = cfg80211_can_change_interface(rdev, dev->ieee80211_ptr, + ntype); + if (err) + return err; + dev->ieee80211_ptr->use_4addr = false; dev->ieee80211_ptr->mesh_id_up_len = 0; @@ -921,3 +926,78 @@ int cfg80211_validate_beacon_int(struct cfg80211_registered_device *rdev, return res; } + +int cfg80211_can_change_interface(struct cfg80211_registered_device *rdev, + struct wireless_dev *wdev, + enum nl80211_iftype iftype) +{ + struct wireless_dev *wdev_iter; + int num[NUM_NL80211_IFTYPES]; + int total = 1; + int i, j; + + ASSERT_RTNL(); + + /* Always allow software iftypes */ + if (rdev->wiphy.software_iftypes & BIT(iftype)) + return 0; + + /* + * Drivers will gradually all set this flag, until all + * have it we only enforce for those that set it. + */ + if (!(rdev->wiphy.flags & WIPHY_FLAG_ENFORCE_COMBINATIONS)) + return 0; + + memset(num, 0, sizeof(num)); + + num[iftype] = 1; + + mutex_lock(&rdev->devlist_mtx); + list_for_each_entry(wdev_iter, &rdev->netdev_list, list) { + if (wdev_iter == wdev) + continue; + if (!netif_running(wdev_iter->netdev)) + continue; + + if (rdev->wiphy.software_iftypes & BIT(wdev_iter->iftype)) + continue; + + num[wdev_iter->iftype]++; + total++; + } + mutex_unlock(&rdev->devlist_mtx); + + for (i = 0; i < rdev->wiphy.n_iface_combinations; i++) { + const struct ieee80211_iface_combination *c; + struct ieee80211_iface_limit *limits; + + c = &rdev->wiphy.iface_combinations[i]; + + limits = kmemdup(c->limits, sizeof(limits[0]) * c->n_limits, + GFP_KERNEL); + if (!limits) + return -ENOMEM; + if (total > c->max_interfaces) + goto cont; + + for (iftype = 0; iftype < NUM_NL80211_IFTYPES; iftype++) { + if (rdev->wiphy.software_iftypes & BIT(iftype)) + continue; + for (j = 0; j < c->n_limits; j++) { + if (!(limits[j].types & iftype)) + continue; + if (limits[j].max < num[iftype]) + goto cont; + limits[j].max -= num[iftype]; + } + } + /* yay, it fits */ + kfree(limits); + return 0; + cont: + kfree(limits); + } + + return -EBUSY; +} -- cgit v0.10.2 From ec034b208dc8aa5dc73ec46c3f27e34c5efbf113 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 13 May 2011 13:35:40 +0200 Subject: mac80211: fix TX a-MPDU locking During my quest to make mac80211 not have any RCU warnings from sparse, I came across the a-MPDU code again and it wasn't quite clear why it isn't racy. So instead of assigning the tid_tx array with just the spinlock held in ieee80211_start_tx_ba_session use a separate temporary array protected only by the spinlock and protect all assignments to the "live" array by both the spinlock and the mutex so that other code is easily verified to be correct. Due to pointer assignment atomicity I don't think this is a real issue, but I'm not sure, especially on Alpha the current code might be problematic. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville diff --git a/net/mac80211/agg-tx.c b/net/mac80211/agg-tx.c index 63d852c..f614ee6 100644 --- a/net/mac80211/agg-tx.c +++ b/net/mac80211/agg-tx.c @@ -136,6 +136,14 @@ void ieee80211_send_bar(struct ieee80211_sub_if_data *sdata, u8 *ra, u16 tid, u1 ieee80211_tx_skb(sdata, skb); } +void ieee80211_assign_tid_tx(struct sta_info *sta, int tid, + struct tid_ampdu_tx *tid_tx) +{ + lockdep_assert_held(&sta->ampdu_mlme.mtx); + lockdep_assert_held(&sta->lock); + rcu_assign_pointer(sta->ampdu_mlme.tid_tx[tid], tid_tx); +} + static void kfree_tid_tx(struct rcu_head *rcu_head) { struct tid_ampdu_tx *tid_tx = @@ -161,7 +169,7 @@ int ___ieee80211_stop_tx_ba_session(struct sta_info *sta, u16 tid, if (test_bit(HT_AGG_STATE_WANT_START, &tid_tx->state)) { /* not even started yet! */ - rcu_assign_pointer(sta->ampdu_mlme.tid_tx[tid], NULL); + ieee80211_assign_tid_tx(sta, tid, NULL); spin_unlock_bh(&sta->lock); call_rcu(&tid_tx->rcu_head, kfree_tid_tx); return 0; @@ -318,7 +326,7 @@ void ieee80211_tx_ba_session_handle_start(struct sta_info *sta, int tid) " tid %d\n", tid); #endif spin_lock_bh(&sta->lock); - rcu_assign_pointer(sta->ampdu_mlme.tid_tx[tid], NULL); + ieee80211_assign_tid_tx(sta, tid, NULL); spin_unlock_bh(&sta->lock); ieee80211_wake_queue_agg(local, tid); @@ -398,7 +406,7 @@ int ieee80211_start_tx_ba_session(struct ieee80211_sta *pubsta, u16 tid, tid_tx = sta->ampdu_mlme.tid_tx[tid]; /* check if the TID is not in aggregation flow already */ - if (tid_tx) { + if (tid_tx || sta->ampdu_mlme.tid_start_tx[tid]) { #ifdef CONFIG_MAC80211_HT_DEBUG printk(KERN_DEBUG "BA request denied - session is not " "idle on tid %u\n", tid); @@ -433,8 +441,11 @@ int ieee80211_start_tx_ba_session(struct ieee80211_sta *pubsta, u16 tid, sta->ampdu_mlme.dialog_token_allocator++; tid_tx->dialog_token = sta->ampdu_mlme.dialog_token_allocator; - /* finally, assign it to the array */ - rcu_assign_pointer(sta->ampdu_mlme.tid_tx[tid], tid_tx); + /* + * Finally, assign it to the start array; the work item will + * collect it and move it to the normal array. + */ + sta->ampdu_mlme.tid_start_tx[tid] = tid_tx; ieee80211_queue_work(&local->hw, &sta->ampdu_mlme.work); @@ -697,7 +708,7 @@ void ieee80211_stop_tx_ba_cb(struct ieee80211_vif *vif, u8 *ra, u8 tid) ieee80211_agg_splice_packets(local, tid_tx, tid); /* future packets must not find the tid_tx struct any more */ - rcu_assign_pointer(sta->ampdu_mlme.tid_tx[tid], NULL); + ieee80211_assign_tid_tx(sta, tid, NULL); ieee80211_agg_splice_finish(local, tid); diff --git a/net/mac80211/ht.c b/net/mac80211/ht.c index b9e4b9b..9f5842a 100644 --- a/net/mac80211/ht.c +++ b/net/mac80211/ht.c @@ -140,14 +140,29 @@ void ieee80211_ba_session_work(struct work_struct *work) sta, tid, WLAN_BACK_RECIPIENT, WLAN_REASON_QSTA_TIMEOUT, true); - tid_tx = sta->ampdu_mlme.tid_tx[tid]; - if (!tid_tx) - continue; + tid_tx = sta->ampdu_mlme.tid_start_tx[tid]; + if (tid_tx) { + /* + * Assign it over to the normal tid_tx array + * where it "goes live". + */ + spin_lock_bh(&sta->lock); + + sta->ampdu_mlme.tid_start_tx[tid] = NULL; + /* could there be a race? */ + if (sta->ampdu_mlme.tid_tx[tid]) + kfree(tid_tx); + else + ieee80211_assign_tid_tx(sta, tid, tid_tx); + spin_unlock_bh(&sta->lock); - if (test_bit(HT_AGG_STATE_WANT_START, &tid_tx->state)) ieee80211_tx_ba_session_handle_start(sta, tid); - else if (test_and_clear_bit(HT_AGG_STATE_WANT_STOP, - &tid_tx->state)) + continue; + } + + tid_tx = sta->ampdu_mlme.tid_tx[tid]; + if (tid_tx && test_and_clear_bit(HT_AGG_STATE_WANT_STOP, + &tid_tx->state)) ___ieee80211_stop_tx_ba_session(sta, tid, WLAN_BACK_INITIATOR, true); diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h index f00b4dc..55c5185 100644 --- a/net/mac80211/sta_info.h +++ b/net/mac80211/sta_info.h @@ -152,6 +152,7 @@ struct tid_ampdu_rx { * * @tid_rx: aggregation info for Rx per TID -- RCU protected * @tid_tx: aggregation info for Tx per TID + * @tid_start_tx: sessions where start was requested * @addba_req_num: number of times addBA request has been sent. * @dialog_token_allocator: dialog token enumerator for each new session; * @work: work struct for starting/stopping aggregation @@ -168,6 +169,7 @@ struct sta_ampdu_mlme { /* tx */ struct work_struct work; struct tid_ampdu_tx *tid_tx[STA_TID_NUM]; + struct tid_ampdu_tx *tid_start_tx[STA_TID_NUM]; u8 addba_req_num[STA_TID_NUM]; u8 dialog_token_allocator; }; @@ -398,6 +400,8 @@ static inline u32 get_sta_flags(struct sta_info *sta) return ret; } +void ieee80211_assign_tid_tx(struct sta_info *sta, int tid, + struct tid_ampdu_tx *tid_tx); #define STA_HASH_SIZE 256 -- cgit v0.10.2 From 40b275b69ee660274b77fb612b0db31fd282fc3f Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 13 May 2011 14:15:49 +0200 Subject: mac80211: sparse RCU annotations This adds sparse RCU annotations to most of mac80211, only the mesh code remains to be done. Due the the previous patches, the annotations are pretty simple. The only thing that this actually changes is removing the RCU usage of key->sta in debugfs since this pointer isn't actually an RCU-managed pointer (it only has a single assignment done before the key even goes live). As that is otherwise harmless, I decided to make it part of this patch. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville diff --git a/net/mac80211/agg-rx.c b/net/mac80211/agg-rx.c index 0c9d0c0..9c0d76c 100644 --- a/net/mac80211/agg-rx.c +++ b/net/mac80211/agg-rx.c @@ -63,7 +63,8 @@ void ___ieee80211_stop_rx_ba_session(struct sta_info *sta, u16 tid, lockdep_assert_held(&sta->ampdu_mlme.mtx); - tid_rx = sta->ampdu_mlme.tid_rx[tid]; + tid_rx = rcu_dereference_protected(sta->ampdu_mlme.tid_rx[tid], + lockdep_is_held(&sta->ampdu_mlme.mtx)); if (!tid_rx) return; diff --git a/net/mac80211/agg-tx.c b/net/mac80211/agg-tx.c index f614ee6..cd5125f 100644 --- a/net/mac80211/agg-tx.c +++ b/net/mac80211/agg-tx.c @@ -157,16 +157,19 @@ int ___ieee80211_stop_tx_ba_session(struct sta_info *sta, u16 tid, bool tx) { struct ieee80211_local *local = sta->local; - struct tid_ampdu_tx *tid_tx = sta->ampdu_mlme.tid_tx[tid]; + struct tid_ampdu_tx *tid_tx; int ret; lockdep_assert_held(&sta->ampdu_mlme.mtx); - if (!tid_tx) - return -ENOENT; - spin_lock_bh(&sta->lock); + tid_tx = rcu_dereference_protected_tid_tx(sta, tid); + if (!tid_tx) { + spin_unlock_bh(&sta->lock); + return -ENOENT; + } + if (test_bit(HT_AGG_STATE_WANT_START, &tid_tx->state)) { /* not even started yet! */ ieee80211_assign_tid_tx(sta, tid, NULL); @@ -291,13 +294,13 @@ ieee80211_wake_queue_agg(struct ieee80211_local *local, int tid) void ieee80211_tx_ba_session_handle_start(struct sta_info *sta, int tid) { - struct tid_ampdu_tx *tid_tx = sta->ampdu_mlme.tid_tx[tid]; + struct tid_ampdu_tx *tid_tx; struct ieee80211_local *local = sta->local; struct ieee80211_sub_if_data *sdata = sta->sdata; u16 start_seq_num; int ret; - lockdep_assert_held(&sta->ampdu_mlme.mtx); + tid_tx = rcu_dereference_protected_tid_tx(sta, tid); /* * While we're asking the driver about the aggregation, @@ -404,7 +407,7 @@ int ieee80211_start_tx_ba_session(struct ieee80211_sta *pubsta, u16 tid, goto err_unlock_sta; } - tid_tx = sta->ampdu_mlme.tid_tx[tid]; + tid_tx = rcu_dereference_protected_tid_tx(sta, tid); /* check if the TID is not in aggregation flow already */ if (tid_tx || sta->ampdu_mlme.tid_start_tx[tid]) { #ifdef CONFIG_MAC80211_HT_DEBUG @@ -491,16 +494,19 @@ ieee80211_agg_splice_finish(struct ieee80211_local *local, u16 tid) static void ieee80211_agg_tx_operational(struct ieee80211_local *local, struct sta_info *sta, u16 tid) { + struct tid_ampdu_tx *tid_tx; + lockdep_assert_held(&sta->ampdu_mlme.mtx); + tid_tx = rcu_dereference_protected_tid_tx(sta, tid); + #ifdef CONFIG_MAC80211_HT_DEBUG printk(KERN_DEBUG "Aggregation is on for tid %d\n", tid); #endif drv_ampdu_action(local, sta->sdata, IEEE80211_AMPDU_TX_OPERATIONAL, - &sta->sta, tid, NULL, - sta->ampdu_mlme.tid_tx[tid]->buf_size); + &sta->sta, tid, NULL, tid_tx->buf_size); /* * synchronize with TX path, while splicing the TX path @@ -508,13 +514,13 @@ static void ieee80211_agg_tx_operational(struct ieee80211_local *local, */ spin_lock_bh(&sta->lock); - ieee80211_agg_splice_packets(local, sta->ampdu_mlme.tid_tx[tid], tid); + ieee80211_agg_splice_packets(local, tid_tx, tid); /* * Now mark as operational. This will be visible * in the TX path, and lets it go lock-free in * the common case. */ - set_bit(HT_AGG_STATE_OPERATIONAL, &sta->ampdu_mlme.tid_tx[tid]->state); + set_bit(HT_AGG_STATE_OPERATIONAL, &tid_tx->state); ieee80211_agg_splice_finish(local, tid); spin_unlock_bh(&sta->lock); @@ -548,7 +554,7 @@ void ieee80211_start_tx_ba_cb(struct ieee80211_vif *vif, u8 *ra, u16 tid) } mutex_lock(&sta->ampdu_mlme.mtx); - tid_tx = sta->ampdu_mlme.tid_tx[tid]; + tid_tx = rcu_dereference_protected_tid_tx(sta, tid); if (WARN_ON(!tid_tx)) { #ifdef CONFIG_MAC80211_HT_DEBUG @@ -626,7 +632,7 @@ int ieee80211_stop_tx_ba_session(struct ieee80211_sta *pubsta, u16 tid) return -EINVAL; spin_lock_bh(&sta->lock); - tid_tx = sta->ampdu_mlme.tid_tx[tid]; + tid_tx = rcu_dereference_protected_tid_tx(sta, tid); if (!tid_tx) { ret = -ENOENT; @@ -682,7 +688,7 @@ void ieee80211_stop_tx_ba_cb(struct ieee80211_vif *vif, u8 *ra, u8 tid) mutex_lock(&sta->ampdu_mlme.mtx); spin_lock_bh(&sta->lock); - tid_tx = sta->ampdu_mlme.tid_tx[tid]; + tid_tx = rcu_dereference_protected_tid_tx(sta, tid); if (!tid_tx || !test_bit(HT_AGG_STATE_STOPPING, &tid_tx->state)) { #ifdef CONFIG_MAC80211_HT_DEBUG @@ -763,7 +769,7 @@ void ieee80211_process_addba_resp(struct ieee80211_local *local, mutex_lock(&sta->ampdu_mlme.mtx); - tid_tx = sta->ampdu_mlme.tid_tx[tid]; + tid_tx = rcu_dereference_protected_tid_tx(sta, tid); if (!tid_tx) goto out; diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index 2d1c1a5..6ecd586 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -177,11 +177,11 @@ static int ieee80211_del_key(struct wiphy *wiphy, struct net_device *dev, goto out_unlock; if (pairwise) - key = sta->ptk; + key = key_mtx_dereference(local, sta->ptk); else - key = sta->gtk[key_idx]; + key = key_mtx_dereference(local, sta->gtk[key_idx]); } else - key = sdata->keys[key_idx]; + key = key_mtx_dereference(local, sdata->keys[key_idx]); if (!key) { ret = -ENOENT; @@ -463,7 +463,7 @@ static int ieee80211_config_beacon(struct ieee80211_sub_if_data *sdata, int size; int err = -EINVAL; - old = sdata->u.ap.beacon; + old = rtnl_dereference(sdata->u.ap.beacon); /* head must not be zero-length */ if (params->head && !params->head_len) @@ -558,8 +558,7 @@ static int ieee80211_add_beacon(struct wiphy *wiphy, struct net_device *dev, sdata = IEEE80211_DEV_TO_SUB_IF(dev); - old = sdata->u.ap.beacon; - + old = rtnl_dereference(sdata->u.ap.beacon); if (old) return -EALREADY; @@ -574,8 +573,7 @@ static int ieee80211_set_beacon(struct wiphy *wiphy, struct net_device *dev, sdata = IEEE80211_DEV_TO_SUB_IF(dev); - old = sdata->u.ap.beacon; - + old = rtnl_dereference(sdata->u.ap.beacon); if (!old) return -ENOENT; @@ -589,8 +587,7 @@ static int ieee80211_del_beacon(struct wiphy *wiphy, struct net_device *dev) sdata = IEEE80211_DEV_TO_SUB_IF(dev); - old = sdata->u.ap.beacon; - + old = rtnl_dereference(sdata->u.ap.beacon); if (!old) return -ENOENT; diff --git a/net/mac80211/debugfs_key.c b/net/mac80211/debugfs_key.c index f7ef347..33c58b8 100644 --- a/net/mac80211/debugfs_key.c +++ b/net/mac80211/debugfs_key.c @@ -241,16 +241,12 @@ void ieee80211_debugfs_key_add(struct ieee80211_key *key) if (!key->debugfs.dir) return; - rcu_read_lock(); - sta = rcu_dereference(key->sta); - if (sta) + sta = key->sta; + if (sta) { sprintf(buf, "../../stations/%pM", sta->sta.addr); - rcu_read_unlock(); - - /* using sta as a boolean is fine outside RCU lock */ - if (sta) key->debugfs.stalink = debugfs_create_symlink("station", key->debugfs.dir, buf); + } DEBUGFS_ADD(keylen); DEBUGFS_ADD(flags); @@ -286,7 +282,8 @@ void ieee80211_debugfs_key_update_default(struct ieee80211_sub_if_data *sdata) lockdep_assert_held(&sdata->local->key_mtx); if (sdata->default_unicast_key) { - key = sdata->default_unicast_key; + key = key_mtx_dereference(sdata->local, + sdata->default_unicast_key); sprintf(buf, "../keys/%d", key->debugfs.cnt); sdata->debugfs.default_unicast_key = debugfs_create_symlink("default_unicast_key", @@ -297,7 +294,8 @@ void ieee80211_debugfs_key_update_default(struct ieee80211_sub_if_data *sdata) } if (sdata->default_multicast_key) { - key = sdata->default_multicast_key; + key = key_mtx_dereference(sdata->local, + sdata->default_multicast_key); sprintf(buf, "../keys/%d", key->debugfs.cnt); sdata->debugfs.default_multicast_key = debugfs_create_symlink("default_multicast_key", @@ -316,9 +314,8 @@ void ieee80211_debugfs_key_add_mgmt_default(struct ieee80211_sub_if_data *sdata) if (!sdata->debugfs.dir) return; - /* this is running under the key lock */ - - key = sdata->default_mgmt_key; + key = key_mtx_dereference(sdata->local, + sdata->default_mgmt_key); if (key) { sprintf(buf, "../keys/%d", key->debugfs.cnt); sdata->debugfs.default_mgmt_key = diff --git a/net/mac80211/ht.c b/net/mac80211/ht.c index 9f5842a..591add2 100644 --- a/net/mac80211/ht.c +++ b/net/mac80211/ht.c @@ -160,7 +160,7 @@ void ieee80211_ba_session_work(struct work_struct *work) continue; } - tid_tx = sta->ampdu_mlme.tid_tx[tid]; + tid_tx = rcu_dereference_protected_tid_tx(sta, tid); if (tid_tx && test_and_clear_bit(HT_AGG_STATE_WANT_STOP, &tid_tx->state)) ___ieee80211_stop_tx_ba_session(sta, tid, diff --git a/net/mac80211/ibss.c b/net/mac80211/ibss.c index b81860c..421eaa6 100644 --- a/net/mac80211/ibss.c +++ b/net/mac80211/ibss.c @@ -662,12 +662,16 @@ static void ieee80211_rx_mgmt_probe_req(struct ieee80211_sub_if_data *sdata, int tx_last_beacon, len = req->len; struct sk_buff *skb; struct ieee80211_mgmt *resp; + struct sk_buff *presp; u8 *pos, *end; lockdep_assert_held(&ifibss->mtx); + presp = rcu_dereference_protected(ifibss->presp, + lockdep_is_held(&ifibss->mtx)); + if (ifibss->state != IEEE80211_IBSS_MLME_JOINED || - len < 24 + 2 || !ifibss->presp) + len < 24 + 2 || !presp) return; tx_last_beacon = drv_tx_last_beacon(local); @@ -705,7 +709,7 @@ static void ieee80211_rx_mgmt_probe_req(struct ieee80211_sub_if_data *sdata, } /* Reply with ProbeResp */ - skb = skb_copy(ifibss->presp, GFP_KERNEL); + skb = skb_copy(presp, GFP_KERNEL); if (!skb) return; @@ -985,7 +989,8 @@ int ieee80211_ibss_leave(struct ieee80211_sub_if_data *sdata) /* remove beacon */ kfree(sdata->u.ibss.ie); - skb = sdata->u.ibss.presp; + skb = rcu_dereference_protected(sdata->u.ibss.presp, + lockdep_is_held(&sdata->u.ibss.mtx)); rcu_assign_pointer(sdata->u.ibss.presp, NULL); sdata->vif.bss_conf.ibss_joined = false; ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON_ENABLED | diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 82f90ff..ed75588 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -214,7 +214,7 @@ struct beacon_data { }; struct ieee80211_if_ap { - struct beacon_data *beacon; + struct beacon_data __rcu *beacon; struct list_head vlans; @@ -237,7 +237,7 @@ struct ieee80211_if_vlan { struct list_head list; /* used for all tx if the VLAN is configured to 4-addr mode */ - struct sta_info *sta; + struct sta_info __rcu *sta; }; struct mesh_stats { @@ -442,7 +442,8 @@ struct ieee80211_if_ibss { unsigned long ibss_join_req; /* probe response/beacon for IBSS */ - struct sk_buff *presp, *skb; + struct sk_buff __rcu *presp; + struct sk_buff *skb; enum { IEEE80211_IBSS_MLME_SEARCH, @@ -567,9 +568,10 @@ struct ieee80211_sub_if_data { struct ieee80211_fragment_entry fragments[IEEE80211_FRAGMENT_MAX]; unsigned int fragment_next; - struct ieee80211_key *keys[NUM_DEFAULT_KEYS + NUM_DEFAULT_MGMT_KEYS]; - struct ieee80211_key *default_unicast_key, *default_multicast_key; - struct ieee80211_key *default_mgmt_key; + struct ieee80211_key __rcu *keys[NUM_DEFAULT_KEYS + NUM_DEFAULT_MGMT_KEYS]; + struct ieee80211_key __rcu *default_unicast_key; + struct ieee80211_key __rcu *default_multicast_key; + struct ieee80211_key __rcu *default_mgmt_key; u16 sequence_number; __be16 control_port_protocol; @@ -805,7 +807,7 @@ struct ieee80211_local { spinlock_t sta_lock; unsigned long num_sta; struct list_head sta_list, sta_pending_list; - struct sta_info *sta_hash[STA_HASH_SIZE]; + struct sta_info __rcu *sta_hash[STA_HASH_SIZE]; struct timer_list sta_cleanup; struct work_struct sta_finish_work; int sta_generation; diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c index 4054399..0d00ac9 100644 --- a/net/mac80211/iface.c +++ b/net/mac80211/iface.c @@ -449,7 +449,8 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata, /* APs need special treatment */ if (sdata->vif.type == NL80211_IFTYPE_AP) { struct ieee80211_sub_if_data *vlan, *tmpsdata; - struct beacon_data *old_beacon = sdata->u.ap.beacon; + struct beacon_data *old_beacon = + rtnl_dereference(sdata->u.ap.beacon); /* sdata_running will return false, so this will disable */ ieee80211_bss_info_change_notify(sdata, diff --git a/net/mac80211/key.c b/net/mac80211/key.c index 958832dd..31afd712 100644 --- a/net/mac80211/key.c +++ b/net/mac80211/key.c @@ -195,7 +195,7 @@ static void __ieee80211_set_default_key(struct ieee80211_sub_if_data *sdata, assert_key_lock(sdata->local); if (idx >= 0 && idx < NUM_DEFAULT_KEYS) - key = sdata->keys[idx]; + key = key_mtx_dereference(sdata->local, sdata->keys[idx]); if (uni) rcu_assign_pointer(sdata->default_unicast_key, key); @@ -222,7 +222,7 @@ __ieee80211_set_default_mgmt_key(struct ieee80211_sub_if_data *sdata, int idx) if (idx >= NUM_DEFAULT_KEYS && idx < NUM_DEFAULT_KEYS + NUM_DEFAULT_MGMT_KEYS) - key = sdata->keys[idx]; + key = key_mtx_dereference(sdata->local, sdata->keys[idx]); rcu_assign_pointer(sdata->default_mgmt_key, key); @@ -266,9 +266,15 @@ static void __ieee80211_key_replace(struct ieee80211_sub_if_data *sdata, else idx = new->conf.keyidx; - defunikey = old && sdata->default_unicast_key == old; - defmultikey = old && sdata->default_multicast_key == old; - defmgmtkey = old && sdata->default_mgmt_key == old; + defunikey = old && + old == key_mtx_dereference(sdata->local, + sdata->default_unicast_key); + defmultikey = old && + old == key_mtx_dereference(sdata->local, + sdata->default_multicast_key); + defmgmtkey = old && + old == key_mtx_dereference(sdata->local, + sdata->default_mgmt_key); if (defunikey && !new) __ieee80211_set_default_key(sdata, -1, true, false); @@ -451,11 +457,11 @@ int ieee80211_key_link(struct ieee80211_key *key, mutex_lock(&sdata->local->key_mtx); if (sta && pairwise) - old_key = sta->ptk; + old_key = key_mtx_dereference(sdata->local, sta->ptk); else if (sta) - old_key = sta->gtk[idx]; + old_key = key_mtx_dereference(sdata->local, sta->gtk[idx]); else - old_key = sdata->keys[idx]; + old_key = key_mtx_dereference(sdata->local, sdata->keys[idx]); __ieee80211_key_replace(sdata, sta, pairwise, old_key, key); __ieee80211_key_destroy(old_key); diff --git a/net/mac80211/key.h b/net/mac80211/key.h index e5432ef..d801d53 100644 --- a/net/mac80211/key.h +++ b/net/mac80211/key.h @@ -146,4 +146,7 @@ void ieee80211_free_keys(struct ieee80211_sub_if_data *sdata); void ieee80211_enable_keys(struct ieee80211_sub_if_data *sdata); void ieee80211_disable_keys(struct ieee80211_sub_if_data *sdata); +#define key_mtx_dereference(local, ref) \ + rcu_dereference_protected(ref, lockdep_is_held(&((local)->key_mtx))) + #endif /* IEEE80211_KEY_H */ diff --git a/net/mac80211/main.c b/net/mac80211/main.c index 79a2281..0d7b08d 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c @@ -871,8 +871,10 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) * and we need some headroom for passing the frame to monitor * interfaces, but never both at the same time. */ +#ifndef __CHECKER__ BUILD_BUG_ON(IEEE80211_TX_STATUS_HEADROOM != sizeof(struct ieee80211_tx_status_rtap_hdr)); +#endif local->tx_headroom = max_t(unsigned int , local->hw.extra_tx_headroom, sizeof(struct ieee80211_tx_status_rtap_hdr)); diff --git a/net/mac80211/mesh.h b/net/mac80211/mesh.h index 5c0c2038..e7c5fdd 100644 --- a/net/mac80211/mesh.h +++ b/net/mac80211/mesh.h @@ -92,7 +92,7 @@ struct mesh_path { u8 dst[ETH_ALEN]; u8 mpp[ETH_ALEN]; /* used for MPP or MAP */ struct ieee80211_sub_if_data *sdata; - struct sta_info *next_hop; + struct sta_info __rcu *next_hop; struct timer_list timer; struct sk_buff_head frame_queue; struct rcu_head rcu; diff --git a/net/mac80211/mesh_hwmp.c b/net/mac80211/mesh_hwmp.c index 2aec7c4..2b18053 100644 --- a/net/mac80211/mesh_hwmp.c +++ b/net/mac80211/mesh_hwmp.c @@ -560,6 +560,14 @@ static void hwmp_preq_frame_process(struct ieee80211_sub_if_data *sdata, } +static inline struct sta_info * +next_hop_deref_protected(struct mesh_path *mpath) +{ + return rcu_dereference_protected(mpath->next_hop, + lockdep_is_held(&mpath->state_lock)); +} + + static void hwmp_prep_frame_process(struct ieee80211_sub_if_data *sdata, struct ieee80211_mgmt *mgmt, u8 *prep_elem, u32 metric) @@ -599,7 +607,7 @@ static void hwmp_prep_frame_process(struct ieee80211_sub_if_data *sdata, spin_unlock_bh(&mpath->state_lock); goto fail; } - memcpy(next_hop, mpath->next_hop->sta.addr, ETH_ALEN); + memcpy(next_hop, next_hop_deref_protected(mpath)->sta.addr, ETH_ALEN); spin_unlock_bh(&mpath->state_lock); --ttl; flags = PREP_IE_FLAGS(prep_elem); @@ -651,7 +659,8 @@ static void hwmp_perr_frame_process(struct ieee80211_sub_if_data *sdata, if (mpath) { spin_lock_bh(&mpath->state_lock); if (mpath->flags & MESH_PATH_ACTIVE && - memcmp(ta, mpath->next_hop->sta.addr, ETH_ALEN) == 0 && + memcmp(ta, next_hop_deref_protected(mpath)->sta.addr, + ETH_ALEN) == 0 && (!(mpath->flags & MESH_PATH_SN_VALID) || SN_GT(target_sn, mpath->sn))) { mpath->flags &= ~MESH_PATH_ACTIVE; @@ -913,6 +922,7 @@ int mesh_nexthop_lookup(struct sk_buff *skb, { struct sk_buff *skb_to_free = NULL; struct mesh_path *mpath; + struct sta_info *next_hop; struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; u8 *target_addr = hdr->addr3; int err = 0; @@ -940,7 +950,11 @@ int mesh_nexthop_lookup(struct sk_buff *skb, mesh_queue_preq(mpath, PREQ_Q_F_START | PREQ_Q_F_REFRESH); } - memcpy(hdr->addr1, mpath->next_hop->sta.addr, ETH_ALEN); + next_hop = rcu_dereference(mpath->next_hop); + if (next_hop) + memcpy(hdr->addr1, next_hop->sta.addr, ETH_ALEN); + else + err = -ENOENT; } else { struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); if (!(mpath->flags & MESH_PATH_RESOLVING)) { diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c index cba8309..82ab6b4 100644 --- a/net/mac80211/sta_info.c +++ b/net/mac80211/sta_info.c @@ -67,7 +67,8 @@ static int sta_info_hash_del(struct ieee80211_local *local, { struct sta_info *s; - s = local->sta_hash[STA_HASH(sta->sta.addr)]; + s = rcu_dereference_protected(local->sta_hash[STA_HASH(sta->sta.addr)], + lockdep_is_held(&local->sta_lock)); if (!s) return -ENOENT; if (s == sta) { @@ -76,9 +77,11 @@ static int sta_info_hash_del(struct ieee80211_local *local, return 0; } - while (s->hnext && s->hnext != sta) - s = s->hnext; - if (s->hnext) { + while (rcu_access_pointer(s->hnext) && + rcu_access_pointer(s->hnext) != sta) + s = rcu_dereference_protected(s->hnext, + lockdep_is_held(&local->sta_lock)); + if (rcu_access_pointer(s->hnext)) { rcu_assign_pointer(s->hnext, sta->hnext); return 0; } @@ -654,9 +657,9 @@ static int __must_check __sta_info_destroy(struct sta_info *sta) mutex_lock(&local->key_mtx); for (i = 0; i < NUM_DEFAULT_KEYS; i++) - __ieee80211_key_free(sta->gtk[i]); + __ieee80211_key_free(key_mtx_dereference(local, sta->gtk[i])); if (sta->ptk) - __ieee80211_key_free(sta->ptk); + __ieee80211_key_free(key_mtx_dereference(local, sta->ptk)); mutex_unlock(&local->key_mtx); sta->dead = true; diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h index 55c5185..d6b5660 100644 --- a/net/mac80211/sta_info.h +++ b/net/mac80211/sta_info.h @@ -164,11 +164,11 @@ struct tid_ampdu_rx { struct sta_ampdu_mlme { struct mutex mtx; /* rx */ - struct tid_ampdu_rx *tid_rx[STA_TID_NUM]; + struct tid_ampdu_rx __rcu *tid_rx[STA_TID_NUM]; unsigned long tid_rx_timer_expired[BITS_TO_LONGS(STA_TID_NUM)]; /* tx */ struct work_struct work; - struct tid_ampdu_tx *tid_tx[STA_TID_NUM]; + struct tid_ampdu_tx __rcu *tid_tx[STA_TID_NUM]; struct tid_ampdu_tx *tid_start_tx[STA_TID_NUM]; u8 addba_req_num[STA_TID_NUM]; u8 dialog_token_allocator; @@ -243,11 +243,11 @@ struct sta_ampdu_mlme { struct sta_info { /* General information, mostly static */ struct list_head list; - struct sta_info *hnext; + struct sta_info __rcu *hnext; struct ieee80211_local *local; struct ieee80211_sub_if_data *sdata; - struct ieee80211_key *gtk[NUM_DEFAULT_KEYS + NUM_DEFAULT_MGMT_KEYS]; - struct ieee80211_key *ptk; + struct ieee80211_key __rcu *gtk[NUM_DEFAULT_KEYS + NUM_DEFAULT_MGMT_KEYS]; + struct ieee80211_key __rcu *ptk; struct rate_control_ref *rate_ctrl; void *rate_ctrl_priv; spinlock_t lock; @@ -403,6 +403,13 @@ static inline u32 get_sta_flags(struct sta_info *sta) void ieee80211_assign_tid_tx(struct sta_info *sta, int tid, struct tid_ampdu_tx *tid_tx); +static inline struct tid_ampdu_tx * +rcu_dereference_protected_tid_tx(struct sta_info *sta, int tid) +{ + return rcu_dereference_protected(sta->ampdu_mlme.tid_tx[tid], + lockdep_is_held(&sta->lock) || + lockdep_is_held(&sta->ampdu_mlme.mtx)); +} #define STA_HASH_SIZE 256 #define STA_HASH(sta) (sta[5]) diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index c9f1211..6eeaaa2 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -1147,7 +1147,7 @@ static bool ieee80211_tx_prep_agg(struct ieee80211_tx_data *tx, * packet pass through because splicing the frames * back is already done. */ - tid_tx = tx->sta->ampdu_mlme.tid_tx[tid]; + tid_tx = rcu_dereference_protected_tid_tx(tx->sta, tid); if (!tid_tx) { /* do nothing, let packet pass through */ -- cgit v0.10.2 From bd2281b85d929af0bd192f05135f70dd05f4fd85 Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Fri, 13 May 2011 15:52:10 +0200 Subject: net/rfkill/core.c: Avoid leaving freed data in a list The list_for_each_entry loop can fail, in which case the list element is not removed from the list rfkill_fds. Since this list is not accessed by the loop, the addition of &data->list into the list is just moved after the loop. The sematic match that finds this problem is as follows: (http://coccinelle.lip6.fr/) // @@ expression E,E1,E2; identifier l; @@ *list_add(&E->l,E1); ... when != E1 when != list_del(&E->l) when != list_del_init(&E->l) when != E = E2 *kfree(E);// Signed-off-by: Julia Lawall Signed-off-by: John W. Linville diff --git a/net/rfkill/core.c b/net/rfkill/core.c index 0198191..be90640 100644 --- a/net/rfkill/core.c +++ b/net/rfkill/core.c @@ -1024,7 +1024,6 @@ static int rfkill_fop_open(struct inode *inode, struct file *file) * start getting events from elsewhere but hold mtx to get * startup events added first */ - list_add(&data->list, &rfkill_fds); list_for_each_entry(rfkill, &rfkill_list, node) { ev = kzalloc(sizeof(*ev), GFP_KERNEL); @@ -1033,6 +1032,7 @@ static int rfkill_fop_open(struct inode *inode, struct file *file) rfkill_fill_event(&ev->ev, rfkill, RFKILL_OP_ADD); list_add_tail(&ev->list, &data->events); } + list_add(&data->list, &rfkill_fds); mutex_unlock(&data->mtx); mutex_unlock(&rfkill_global_mutex); -- cgit v0.10.2 From 69de3721750ea4fae504be9e67f140cafe1c7a89 Mon Sep 17 00:00:00 2001 From: Mohammed Shafi Shajakhan Date: Fri, 13 May 2011 20:29:04 +0530 Subject: ath9k_hw: make antenna diversity modules chip specific this is necessary to support Antenna diversity and combining in new chip sets such as AR9485, previously Antenna diversity support is available only in AR9285 Cc: Gabriel Tseng Cc: Senthilkumar Balasubramanian Signed-off-by: Mohammed Shafi Shajakhan Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/ar9002_phy.c b/drivers/net/wireless/ath/ath9k/ar9002_phy.c index 7d68d61..b4a0c1d 100644 --- a/drivers/net/wireless/ath/ath9k/ar9002_phy.c +++ b/drivers/net/wireless/ath/ath9k/ar9002_phy.c @@ -517,23 +517,7 @@ static void ar9002_hw_set_nf_limits(struct ath_hw *ah) } } -void ar9002_hw_attach_phy_ops(struct ath_hw *ah) -{ - struct ath_hw_private_ops *priv_ops = ath9k_hw_private_ops(ah); - - priv_ops->set_rf_regs = NULL; - priv_ops->rf_alloc_ext_banks = NULL; - priv_ops->rf_free_ext_banks = NULL; - priv_ops->rf_set_freq = ar9002_hw_set_channel; - priv_ops->spur_mitigate_freq = ar9002_hw_spur_mitigate; - priv_ops->olc_init = ar9002_olc_init; - priv_ops->compute_pll_control = ar9002_hw_compute_pll_control; - priv_ops->do_getnf = ar9002_hw_do_getnf; - - ar9002_hw_set_nf_limits(ah); -} - -void ath9k_hw_antdiv_comb_conf_get(struct ath_hw *ah, +static void ar9002_hw_antdiv_comb_conf_get(struct ath_hw *ah, struct ath_hw_antcomb_conf *antconf) { u32 regval; @@ -546,9 +530,8 @@ void ath9k_hw_antdiv_comb_conf_get(struct ath_hw *ah, antconf->fast_div_bias = (regval & AR_PHY_9285_FAST_DIV_BIAS) >> AR_PHY_9285_FAST_DIV_BIAS_S; } -EXPORT_SYMBOL(ath9k_hw_antdiv_comb_conf_get); -void ath9k_hw_antdiv_comb_conf_set(struct ath_hw *ah, +static void ar9002_hw_antdiv_comb_conf_set(struct ath_hw *ah, struct ath_hw_antcomb_conf *antconf) { u32 regval; @@ -566,4 +549,23 @@ void ath9k_hw_antdiv_comb_conf_set(struct ath_hw *ah, REG_WRITE(ah, AR_PHY_MULTICHAIN_GAIN_CTL, regval); } -EXPORT_SYMBOL(ath9k_hw_antdiv_comb_conf_set); + +void ar9002_hw_attach_phy_ops(struct ath_hw *ah) +{ + struct ath_hw_private_ops *priv_ops = ath9k_hw_private_ops(ah); + struct ath_hw_ops *ops = ath9k_hw_ops(ah); + + priv_ops->set_rf_regs = NULL; + priv_ops->rf_alloc_ext_banks = NULL; + priv_ops->rf_free_ext_banks = NULL; + priv_ops->rf_set_freq = ar9002_hw_set_channel; + priv_ops->spur_mitigate_freq = ar9002_hw_spur_mitigate; + priv_ops->olc_init = ar9002_olc_init; + priv_ops->compute_pll_control = ar9002_hw_compute_pll_control; + priv_ops->do_getnf = ar9002_hw_do_getnf; + + ops->antdiv_comb_conf_get = ar9002_hw_antdiv_comb_conf_get; + ops->antdiv_comb_conf_set = ar9002_hw_antdiv_comb_conf_set; + + ar9002_hw_set_nf_limits(ah); +} diff --git a/drivers/net/wireless/ath/ath9k/hw-ops.h b/drivers/net/wireless/ath/ath9k/hw-ops.h index 99f8334..8b8f044 100644 --- a/drivers/net/wireless/ath/ath9k/hw-ops.h +++ b/drivers/net/wireless/ath/ath9k/hw-ops.h @@ -121,6 +121,18 @@ static inline void ath9k_hw_set_clrdmask(struct ath_hw *ah, void *ds, bool val) ath9k_hw_ops(ah)->set_clrdmask(ah, ds, val); } +static inline void ath9k_hw_antdiv_comb_conf_get(struct ath_hw *ah, + struct ath_hw_antcomb_conf *antconf) +{ + ath9k_hw_ops(ah)->antdiv_comb_conf_get(ah, antconf); +} + +static inline void ath9k_hw_antdiv_comb_conf_set(struct ath_hw *ah, + struct ath_hw_antcomb_conf *antconf) +{ + ath9k_hw_ops(ah)->antdiv_comb_conf_set(ah, antconf); +} + /* Private hardware call ops */ /* PHY ops */ diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h index b2248bb..67cca10 100644 --- a/drivers/net/wireless/ath/ath9k/hw.h +++ b/drivers/net/wireless/ath/ath9k/hw.h @@ -629,6 +629,11 @@ struct ath_hw_ops { void (*set11n_aggr_last)(struct ath_hw *ah, void *ds); void (*clr11n_aggr)(struct ath_hw *ah, void *ds); void (*set_clrdmask)(struct ath_hw *ah, void *ds, bool val); + void (*antdiv_comb_conf_get)(struct ath_hw *ah, + struct ath_hw_antcomb_conf *antconf); + void (*antdiv_comb_conf_set)(struct ath_hw *ah, + struct ath_hw_antcomb_conf *antconf); + }; struct ath_nf_limits { @@ -904,10 +909,6 @@ void ath9k_hw_cfg_output(struct ath_hw *ah, u32 gpio, void ath9k_hw_set_gpio(struct ath_hw *ah, u32 gpio, u32 val); u32 ath9k_hw_getdefantenna(struct ath_hw *ah); void ath9k_hw_setantenna(struct ath_hw *ah, u32 antenna); -void ath9k_hw_antdiv_comb_conf_get(struct ath_hw *ah, - struct ath_hw_antcomb_conf *antconf); -void ath9k_hw_antdiv_comb_conf_set(struct ath_hw *ah, - struct ath_hw_antcomb_conf *antconf); /* General Operation */ bool ath9k_hw_wait(struct ath_hw *ah, u32 reg, u32 mask, u32 val, u32 timeout); -- cgit v0.10.2 From 21d2c63a2866a47030803de3db9b4e8759806095 Mon Sep 17 00:00:00 2001 From: Mohammed Shafi Shajakhan Date: Fri, 13 May 2011 20:29:31 +0530 Subject: ath9k_hw: enable Antenna diversity for AR9485 read antenna diversity and combining information from the EEPROM. Enable antenna diversity/combining feature only when both LNA diversity and fast diversity are supported Cc: Gabriel Tseng Cc: Senthilkumar Balasubramanian Tested-by: Mohammed Shafi Shajakhan Signed-off-by: Mohammed Shafi Shajakhan Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index 58f3d42..b75b5dc 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c @@ -2022,6 +2022,22 @@ int ath9k_hw_fill_cap_info(struct ath_hw *ah) } + if (AR_SREV_9485(ah)) { + ant_div_ctl1 = ah->eep_ops->get_eeprom(ah, EEP_ANT_DIV_CTL1); + /* + * enable the diversity-combining algorithm only when + * both enable_lna_div and enable_fast_div are set + * Table for Diversity + * ant_div_alt_lnaconf bit 0-1 + * ant_div_main_lnaconf bit 2-3 + * ant_div_alt_gaintb bit 4 + * ant_div_main_gaintb bit 5 + * enable_ant_div_lnadiv bit 6 + * enable_ant_fast_div bit 7 + */ + if ((ant_div_ctl1 >> 0x6) == 0x3) + pCap->hw_caps |= ATH9K_HW_CAP_ANT_DIV_COMB; + } if (AR_SREV_9485_10(ah)) { pCap->pcie_lcr_extsync_en = true; -- cgit v0.10.2 From c6ba9feb4fa33f31f26ac1a2b0a337d79426b822 Mon Sep 17 00:00:00 2001 From: Mohammed Shafi Shajakhan Date: Fri, 13 May 2011 20:29:53 +0530 Subject: ath9k_hw: define registers/macros to support Antenna diversity define few registers and macros to configure/enable Antenna diversity parameters in AR9485 Cc: Gabriel Tseng Cc: Senthilkumar Balasubramanian Signed-off-by: Mohammed Shafi Shajakhan Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/ar9003_phy.h b/drivers/net/wireless/ath/ath9k/ar9003_phy.h index 2a0d5cb..c7505b4 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_phy.h +++ b/drivers/net/wireless/ath/ath9k/ar9003_phy.h @@ -261,12 +261,34 @@ #define AR_PHY_EXT_CCA0 (AR_AGC_BASE + 0x20) #define AR_PHY_RESTART (AR_AGC_BASE + 0x24) +/* + * Antenna Diversity settings + */ #define AR_PHY_MC_GAIN_CTRL (AR_AGC_BASE + 0x28) #define AR_ANT_DIV_CTRL_ALL 0x7e000000 #define AR_ANT_DIV_CTRL_ALL_S 25 #define AR_ANT_DIV_ENABLE 0x1000000 #define AR_ANT_DIV_ENABLE_S 24 + +#define AR_PHY_9485_ANT_FAST_DIV_BIAS 0x00007e00 +#define AR_PHY_9485_ANT_FAST_DIV_BIAS_S 9 +#define AR_PHY_9485_ANT_DIV_LNADIV 0x01000000 +#define AR_PHY_9485_ANT_DIV_LNADIV_S 24 +#define AR_PHY_9485_ANT_DIV_ALT_LNACONF 0x06000000 +#define AR_PHY_9485_ANT_DIV_ALT_LNACONF_S 25 +#define AR_PHY_9485_ANT_DIV_MAIN_LNACONF 0x18000000 +#define AR_PHY_9485_ANT_DIV_MAIN_LNACONF_S 27 +#define AR_PHY_9485_ANT_DIV_ALT_GAINTB 0x20000000 +#define AR_PHY_9485_ANT_DIV_ALT_GAINTB_S 29 +#define AR_PHY_9485_ANT_DIV_MAIN_GAINTB 0x40000000 +#define AR_PHY_9485_ANT_DIV_MAIN_GAINTB_S 30 + +#define AR_PHY_9485_ANT_DIV_LNA1_MINUS_LNA2 0x0 +#define AR_PHY_9485_ANT_DIV_LNA2 0x1 +#define AR_PHY_9485_ANT_DIV_LNA1 0x2 +#define AR_PHY_9485_ANT_DIV_LNA1_PLUS_LNA2 0x3 + #define AR_PHY_EXTCHN_PWRTHR1 (AR_AGC_BASE + 0x2c) #define AR_PHY_EXT_CHN_WIN (AR_AGC_BASE + 0x30) #define AR_PHY_20_40_DET_THR (AR_AGC_BASE + 0x34) diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h index 67cca10..80f512d 100644 --- a/drivers/net/wireless/ath/ath9k/hw.h +++ b/drivers/net/wireless/ath/ath9k/hw.h @@ -479,6 +479,9 @@ struct ath_hw_antcomb_conf { u8 main_lna_conf; u8 alt_lna_conf; u8 fast_div_bias; + u8 main_gaintb; + u8 alt_gaintb; + int lna1_lna2_delta; }; /** -- cgit v0.10.2 From 842ca780af06d166c87725b68f4fe359c3da7bc0 Mon Sep 17 00:00:00 2001 From: Mohammed Shafi Shajakhan Date: Fri, 13 May 2011 20:30:27 +0530 Subject: ath9k_hw: config diversity based on eeprom contents * enable LNA-diversity, fast-diversity for AR9485 based on the value read from EEPROM content * if antenna diversity/combining is supported, set LNA1 for the main antenna and LNA2 for the alternate antenna based on the new diversity algorithm Cc: Gabriel Tseng Cc: Senthilkumar Balasubramanian Cc: Luis Rodriguez Signed-off-by: Mohammed Shafi Shajakhan Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c b/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c index 6dfb69a..c7ad056 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c @@ -3498,6 +3498,8 @@ static u16 ar9003_hw_ant_ctrl_chain_get(struct ath_hw *ah, static void ar9003_hw_ant_ctrl_apply(struct ath_hw *ah, bool is2ghz) { int chain; + u32 regval; + u32 ant_div_ctl1; static const u32 switch_chain_reg[AR9300_MAX_CHAINS] = { AR_PHY_SWITCH_CHAIN_0, AR_PHY_SWITCH_CHAIN_1, @@ -3523,13 +3525,49 @@ static void ar9003_hw_ant_ctrl_apply(struct ath_hw *ah, bool is2ghz) if (AR_SREV_9485(ah)) { value = ath9k_hw_ar9300_get_eeprom(ah, EEP_ANT_DIV_CTL1); - REG_RMW_FIELD(ah, AR_PHY_MC_GAIN_CTRL, AR_ANT_DIV_CTRL_ALL, - value); - REG_RMW_FIELD(ah, AR_PHY_MC_GAIN_CTRL, AR_ANT_DIV_ENABLE, - value >> 6); - REG_RMW_FIELD(ah, AR_PHY_CCK_DETECT, AR_FAST_DIV_ENABLE, - value >> 7); + /* + * main_lnaconf, alt_lnaconf, main_tb, alt_tb + * are the fields present + */ + regval = REG_READ(ah, AR_PHY_MC_GAIN_CTRL); + regval &= (~AR_ANT_DIV_CTRL_ALL); + regval |= (value & 0x3f) << AR_ANT_DIV_CTRL_ALL_S; + /* enable_lnadiv */ + regval &= (~AR_PHY_9485_ANT_DIV_LNADIV); + regval |= ((value >> 6) & 0x1) << + AR_PHY_9485_ANT_DIV_LNADIV_S; + REG_WRITE(ah, AR_PHY_MC_GAIN_CTRL, regval); + + /*enable fast_div */ + regval = REG_READ(ah, AR_PHY_CCK_DETECT); + regval &= (~AR_FAST_DIV_ENABLE); + regval |= ((value >> 7) & 0x1) << + AR_FAST_DIV_ENABLE_S; + REG_WRITE(ah, AR_PHY_CCK_DETECT, regval); + ant_div_ctl1 = + ah->eep_ops->get_eeprom(ah, EEP_ANT_DIV_CTL1); + /* check whether antenna diversity is enabled */ + if ((ant_div_ctl1 >> 0x6) == 0x3) { + regval = REG_READ(ah, AR_PHY_MC_GAIN_CTRL); + /* + * clear bits 25-30 main_lnaconf, alt_lnaconf, + * main_tb, alt_tb + */ + regval &= (~(AR_PHY_9485_ANT_DIV_MAIN_LNACONF | + AR_PHY_9485_ANT_DIV_ALT_LNACONF | + AR_PHY_9485_ANT_DIV_ALT_GAINTB | + AR_PHY_9485_ANT_DIV_MAIN_GAINTB)); + /* by default use LNA1 for the main antenna */ + regval |= (AR_PHY_9485_ANT_DIV_LNA1 << + AR_PHY_9485_ANT_DIV_MAIN_LNACONF_S); + regval |= (AR_PHY_9485_ANT_DIV_LNA2 << + AR_PHY_9485_ANT_DIV_ALT_LNACONF_S); + REG_WRITE(ah, AR_PHY_MC_GAIN_CTRL, regval); + } + + } + } static void ar9003_hw_drive_strength_apply(struct ath_hw *ah) -- cgit v0.10.2 From 6bcbc062c23ac769cb775f3d2cf209db9d1a96fe Mon Sep 17 00:00:00 2001 From: Mohammed Shafi Shajakhan Date: Fri, 13 May 2011 20:30:41 +0530 Subject: ath9k_hw: define modules to get/set Antenna diversity paramaters these are the two important modules that will be called by the antenna diversity algorithm module in the rx. this will continuosly configure the hardware based on the current diversity status obtained from the algorithm Cc: Gabriel Tseng Cc: Senthilkumar Balasubramanian Signed-off-by: Mohammed Shafi Shajakhan Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/ar9003_phy.c b/drivers/net/wireless/ath/ath9k/ar9003_phy.c index c83be2d..d2a5d27 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_phy.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_phy.c @@ -1184,9 +1184,50 @@ static void ar9003_hw_set_radar_conf(struct ath_hw *ah) conf->radar_inband = 8; } +static void ar9003_hw_antdiv_comb_conf_get(struct ath_hw *ah, + struct ath_hw_antcomb_conf *antconf) +{ + u32 regval; + + regval = REG_READ(ah, AR_PHY_MC_GAIN_CTRL); + antconf->main_lna_conf = (regval & AR_PHY_9485_ANT_DIV_MAIN_LNACONF) >> + AR_PHY_9485_ANT_DIV_MAIN_LNACONF_S; + antconf->alt_lna_conf = (regval & AR_PHY_9485_ANT_DIV_ALT_LNACONF) >> + AR_PHY_9485_ANT_DIV_ALT_LNACONF_S; + antconf->fast_div_bias = (regval & AR_PHY_9485_ANT_FAST_DIV_BIAS) >> + AR_PHY_9485_ANT_FAST_DIV_BIAS_S; +} + +static void ar9003_hw_antdiv_comb_conf_set(struct ath_hw *ah, + struct ath_hw_antcomb_conf *antconf) +{ + u32 regval; + + regval = REG_READ(ah, AR_PHY_MC_GAIN_CTRL); + regval &= ~(AR_PHY_9485_ANT_DIV_MAIN_LNACONF | + AR_PHY_9485_ANT_DIV_ALT_LNACONF | + AR_PHY_9485_ANT_FAST_DIV_BIAS | + AR_PHY_9485_ANT_DIV_MAIN_GAINTB | + AR_PHY_9485_ANT_DIV_ALT_GAINTB); + regval |= ((antconf->main_lna_conf << + AR_PHY_9485_ANT_DIV_MAIN_LNACONF_S) + & AR_PHY_9485_ANT_DIV_MAIN_LNACONF); + regval |= ((antconf->alt_lna_conf << AR_PHY_9485_ANT_DIV_ALT_LNACONF_S) + & AR_PHY_9485_ANT_DIV_ALT_LNACONF); + regval |= ((antconf->fast_div_bias << AR_PHY_9485_ANT_FAST_DIV_BIAS_S) + & AR_PHY_9485_ANT_FAST_DIV_BIAS); + regval |= ((antconf->main_gaintb << AR_PHY_9485_ANT_DIV_MAIN_GAINTB_S) + & AR_PHY_9485_ANT_DIV_MAIN_GAINTB); + regval |= ((antconf->alt_gaintb << AR_PHY_9485_ANT_DIV_ALT_GAINTB_S) + & AR_PHY_9485_ANT_DIV_ALT_GAINTB); + + REG_WRITE(ah, AR_PHY_MC_GAIN_CTRL, regval); +} + void ar9003_hw_attach_phy_ops(struct ath_hw *ah) { struct ath_hw_private_ops *priv_ops = ath9k_hw_private_ops(ah); + struct ath_hw_ops *ops = ath9k_hw_ops(ah); static const u32 ar9300_cca_regs[6] = { AR_PHY_CCA_0, AR_PHY_CCA_1, @@ -1213,6 +1254,9 @@ void ar9003_hw_attach_phy_ops(struct ath_hw *ah) priv_ops->ani_cache_ini_regs = ar9003_hw_ani_cache_ini_regs; priv_ops->set_radar_params = ar9003_hw_set_radar_params; + ops->antdiv_comb_conf_get = ar9003_hw_antdiv_comb_conf_get; + ops->antdiv_comb_conf_set = ar9003_hw_antdiv_comb_conf_set; + ar9003_hw_set_nf_limits(ah); ar9003_hw_set_radar_conf(ah); memcpy(ah->nf_regs, ar9300_cca_regs, sizeof(ah->nf_regs)); -- cgit v0.10.2 From 8afbcc8bfb549a522298fa4a31ee5155c2b5f7a0 Mon Sep 17 00:00:00 2001 From: Mohammed Shafi Shajakhan Date: Fri, 13 May 2011 20:30:56 +0530 Subject: ath9k_hw: define antenna diversity group AR9285 belongs to diversity group 0 and AR9485 belongs to diversity group 2. Based on the diversity group we configure certain antenna diversity paramaters such as lna1_lna2_delta and fast diversity bias values. For AR9485 we have some gain table parameter which selects the gain table 0/1 for main and alternate antenna Cc: Gabriel Tseng Cc: Senthilkumar Balasubramanian Signed-off-by: Mohammed Shafi Shajakhan Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/ar9002_phy.c b/drivers/net/wireless/ath/ath9k/ar9002_phy.c index b4a0c1d..a57e963 100644 --- a/drivers/net/wireless/ath/ath9k/ar9002_phy.c +++ b/drivers/net/wireless/ath/ath9k/ar9002_phy.c @@ -529,6 +529,8 @@ static void ar9002_hw_antdiv_comb_conf_get(struct ath_hw *ah, AR_PHY_9285_ANT_DIV_ALT_LNACONF_S; antconf->fast_div_bias = (regval & AR_PHY_9285_FAST_DIV_BIAS) >> AR_PHY_9285_FAST_DIV_BIAS_S; + antconf->lna1_lna2_delta = -3; + antconf->div_group = 0; } static void ar9002_hw_antdiv_comb_conf_set(struct ath_hw *ah, diff --git a/drivers/net/wireless/ath/ath9k/ar9003_phy.c b/drivers/net/wireless/ath/ath9k/ar9003_phy.c index d2a5d27..25f3c2f 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_phy.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_phy.c @@ -1196,6 +1196,8 @@ static void ar9003_hw_antdiv_comb_conf_get(struct ath_hw *ah, AR_PHY_9485_ANT_DIV_ALT_LNACONF_S; antconf->fast_div_bias = (regval & AR_PHY_9485_ANT_FAST_DIV_BIAS) >> AR_PHY_9485_ANT_FAST_DIV_BIAS_S; + antconf->lna1_lna2_delta = -9; + antconf->div_group = 2; } static void ar9003_hw_antdiv_comb_conf_set(struct ath_hw *ah, diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h index f2f672b..03b37d7 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h @@ -483,7 +483,6 @@ static inline void ath_deinit_leds(struct ath_softc *sc) #define ATH_ANT_DIV_COMB_ALT_ANT_RATIO 30 #define ATH_ANT_DIV_COMB_ALT_ANT_RATIO2 20 -#define ATH_ANT_DIV_COMB_LNA1_LNA2_DELTA -3 #define ATH_ANT_DIV_COMB_LNA1_LNA2_SWITCH_DELTA -1 #define ATH_ANT_DIV_COMB_LNA1_DELTA_HI -4 #define ATH_ANT_DIV_COMB_LNA1_DELTA_MID -2 diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h index 80f512d..7af2773 100644 --- a/drivers/net/wireless/ath/ath9k/hw.h +++ b/drivers/net/wireless/ath/ath9k/hw.h @@ -482,6 +482,7 @@ struct ath_hw_antcomb_conf { u8 main_gaintb; u8 alt_gaintb; int lna1_lna2_delta; + u8 div_group; }; /** diff --git a/drivers/net/wireless/ath/ath9k/recv.c b/drivers/net/wireless/ath/ath9k/recv.c index 9fcd1e4..85e0532 100644 --- a/drivers/net/wireless/ath/ath9k/recv.c +++ b/drivers/net/wireless/ath/ath9k/recv.c @@ -1442,7 +1442,7 @@ static void ath_ant_comb_scan(struct ath_softc *sc, struct ath_rx_status *rs) } if ((alt_rssi_avg < (main_rssi_avg + - ATH_ANT_DIV_COMB_LNA1_LNA2_DELTA))) + div_ant_conf.lna1_lna2_delta))) goto div_comb_done; } -- cgit v0.10.2 From b85c5734f00886ee0f33ef4d0038ed9a278eefce Mon Sep 17 00:00:00 2001 From: Mohammed Shafi Shajakhan Date: Fri, 13 May 2011 20:31:09 +0530 Subject: ath9k: Implement an API to swap main/ALT LNA's for the diversity group 2(AR9485) we swap the LNA's of main/ALT antenna based on alternate antenna's rssi average in comparision with main antenna's rssi, while for AR9285(antenna diversity group 0)we still follow the older method of looking at the packet count in alternate antenna Cc: Gabriel Tseng Cc: Senthilkumar Balasubramanian Signed-off-by: Mohammed Shafi Shajakhan Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/recv.c b/drivers/net/wireless/ath/ath9k/recv.c index 85e0532..47e0fc1 100644 --- a/drivers/net/wireless/ath/ath9k/recv.c +++ b/drivers/net/wireless/ath/ath9k/recv.c @@ -28,6 +28,33 @@ static inline bool ath_is_alt_ant_ratio_better(int alt_ratio, int maxdelta, (alt_rssi_avg > main_rssi_avg + mindelta)) && (pkt_count > 50); } +static inline bool ath_ant_div_comb_alt_check(u8 div_group, int alt_ratio, + int curr_main_set, int curr_alt_set, + int alt_rssi_avg, int main_rssi_avg) +{ + bool result = false; + switch (div_group) { + case 0: + if (alt_ratio > ATH_ANT_DIV_COMB_ALT_ANT_RATIO) + result = true; + break; + case 1: + if ((((curr_main_set == ATH_ANT_DIV_COMB_LNA2) && + (curr_alt_set == ATH_ANT_DIV_COMB_LNA1) && + (alt_rssi_avg >= (main_rssi_avg - 5))) || + ((curr_main_set == ATH_ANT_DIV_COMB_LNA1) && + (curr_alt_set == ATH_ANT_DIV_COMB_LNA2) && + (alt_rssi_avg >= (main_rssi_avg - 2)))) && + (alt_rssi_avg >= 4)) + result = true; + else + result = false; + break; + } + + return result; +} + static inline bool ath9k_check_auto_sleep(struct ath_softc *sc) { return sc->ps_enabled && @@ -1413,7 +1440,9 @@ static void ath_ant_comb_scan(struct ath_softc *sc, struct ath_rx_status *rs) } if (!antcomb->scan) { - if (alt_ratio > ATH_ANT_DIV_COMB_ALT_ANT_RATIO) { + if (ath_ant_div_comb_alt_check(div_ant_conf.div_group, + alt_ratio, curr_main_set, curr_alt_set, + alt_rssi_avg, main_rssi_avg)) { if (curr_alt_set == ATH_ANT_DIV_COMB_LNA2) { /* Switch main and alt LNA */ div_ant_conf.main_lna_conf = -- cgit v0.10.2 From 3e9a212a9e21266115bad2982016950fb2bf29c2 Mon Sep 17 00:00:00 2001 From: Mohammed Shafi Shajakhan Date: Fri, 13 May 2011 20:31:23 +0530 Subject: ath9k: configure fast_div_bias based on diversity group configure fast diversity bias based on the antenna diversity group and based on main/alt LNA configurations. also configure main antenna and alternate antenna to gain-table 0 for diversity group 2(AR9485) Cc: Gabriel Tseng Cc: Senthilkumar Balasubramanian Signed-off-by: Mohammed Shafi Shajakhan Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/recv.c b/drivers/net/wireless/ath/ath9k/recv.c index 47e0fc1..2fecfcb 100644 --- a/drivers/net/wireless/ath/ath9k/recv.c +++ b/drivers/net/wireless/ath/ath9k/recv.c @@ -1317,49 +1317,138 @@ static void ath_select_ant_div_from_quick_scan(struct ath_ant_comb *antcomb, } } -static void ath_ant_div_conf_fast_divbias(struct ath_hw_antcomb_conf *ant_conf) +static void ath_ant_div_conf_fast_divbias(struct ath_hw_antcomb_conf *ant_conf, + struct ath_ant_comb *antcomb, int alt_ratio) { - /* Adjust the fast_div_bias based on main and alt lna conf */ - switch ((ant_conf->main_lna_conf << 4) | ant_conf->alt_lna_conf) { - case (0x01): /* A-B LNA2 */ - ant_conf->fast_div_bias = 0x3b; - break; - case (0x02): /* A-B LNA1 */ - ant_conf->fast_div_bias = 0x3d; - break; - case (0x03): /* A-B A+B */ - ant_conf->fast_div_bias = 0x1; - break; - case (0x10): /* LNA2 A-B */ - ant_conf->fast_div_bias = 0x7; - break; - case (0x12): /* LNA2 LNA1 */ - ant_conf->fast_div_bias = 0x2; - break; - case (0x13): /* LNA2 A+B */ - ant_conf->fast_div_bias = 0x7; - break; - case (0x20): /* LNA1 A-B */ - ant_conf->fast_div_bias = 0x6; - break; - case (0x21): /* LNA1 LNA2 */ - ant_conf->fast_div_bias = 0x0; - break; - case (0x23): /* LNA1 A+B */ - ant_conf->fast_div_bias = 0x6; - break; - case (0x30): /* A+B A-B */ - ant_conf->fast_div_bias = 0x1; - break; - case (0x31): /* A+B LNA2 */ - ant_conf->fast_div_bias = 0x3b; - break; - case (0x32): /* A+B LNA1 */ - ant_conf->fast_div_bias = 0x3d; - break; - default: - break; + if (ant_conf->div_group == 0) { + /* Adjust the fast_div_bias based on main and alt lna conf */ + switch ((ant_conf->main_lna_conf << 4) | + ant_conf->alt_lna_conf) { + case (0x01): /* A-B LNA2 */ + ant_conf->fast_div_bias = 0x3b; + break; + case (0x02): /* A-B LNA1 */ + ant_conf->fast_div_bias = 0x3d; + break; + case (0x03): /* A-B A+B */ + ant_conf->fast_div_bias = 0x1; + break; + case (0x10): /* LNA2 A-B */ + ant_conf->fast_div_bias = 0x7; + break; + case (0x12): /* LNA2 LNA1 */ + ant_conf->fast_div_bias = 0x2; + break; + case (0x13): /* LNA2 A+B */ + ant_conf->fast_div_bias = 0x7; + break; + case (0x20): /* LNA1 A-B */ + ant_conf->fast_div_bias = 0x6; + break; + case (0x21): /* LNA1 LNA2 */ + ant_conf->fast_div_bias = 0x0; + break; + case (0x23): /* LNA1 A+B */ + ant_conf->fast_div_bias = 0x6; + break; + case (0x30): /* A+B A-B */ + ant_conf->fast_div_bias = 0x1; + break; + case (0x31): /* A+B LNA2 */ + ant_conf->fast_div_bias = 0x3b; + break; + case (0x32): /* A+B LNA1 */ + ant_conf->fast_div_bias = 0x3d; + break; + default: + break; + } + } else if (ant_conf->div_group == 2) { + /* Adjust the fast_div_bias based on main and alt_lna_conf */ + switch ((ant_conf->main_lna_conf << 4) | + ant_conf->alt_lna_conf) { + case (0x01): /* A-B LNA2 */ + ant_conf->fast_div_bias = 0x1; + ant_conf->main_gaintb = 0; + ant_conf->alt_gaintb = 0; + break; + case (0x02): /* A-B LNA1 */ + ant_conf->fast_div_bias = 0x1; + ant_conf->main_gaintb = 0; + ant_conf->alt_gaintb = 0; + break; + case (0x03): /* A-B A+B */ + ant_conf->fast_div_bias = 0x1; + ant_conf->main_gaintb = 0; + ant_conf->alt_gaintb = 0; + break; + case (0x10): /* LNA2 A-B */ + if (!(antcomb->scan) && + (alt_ratio > ATH_ANT_DIV_COMB_ALT_ANT_RATIO)) + ant_conf->fast_div_bias = 0x1; + else + ant_conf->fast_div_bias = 0x2; + ant_conf->main_gaintb = 0; + ant_conf->alt_gaintb = 0; + break; + case (0x12): /* LNA2 LNA1 */ + ant_conf->fast_div_bias = 0x1; + ant_conf->main_gaintb = 0; + ant_conf->alt_gaintb = 0; + break; + case (0x13): /* LNA2 A+B */ + if (!(antcomb->scan) && + (alt_ratio > ATH_ANT_DIV_COMB_ALT_ANT_RATIO)) + ant_conf->fast_div_bias = 0x1; + else + ant_conf->fast_div_bias = 0x2; + ant_conf->main_gaintb = 0; + ant_conf->alt_gaintb = 0; + break; + case (0x20): /* LNA1 A-B */ + if (!(antcomb->scan) && + (alt_ratio > ATH_ANT_DIV_COMB_ALT_ANT_RATIO)) + ant_conf->fast_div_bias = 0x1; + else + ant_conf->fast_div_bias = 0x2; + ant_conf->main_gaintb = 0; + ant_conf->alt_gaintb = 0; + break; + case (0x21): /* LNA1 LNA2 */ + ant_conf->fast_div_bias = 0x1; + ant_conf->main_gaintb = 0; + ant_conf->alt_gaintb = 0; + break; + case (0x23): /* LNA1 A+B */ + if (!(antcomb->scan) && + (alt_ratio > ATH_ANT_DIV_COMB_ALT_ANT_RATIO)) + ant_conf->fast_div_bias = 0x1; + else + ant_conf->fast_div_bias = 0x2; + ant_conf->main_gaintb = 0; + ant_conf->alt_gaintb = 0; + break; + case (0x30): /* A+B A-B */ + ant_conf->fast_div_bias = 0x1; + ant_conf->main_gaintb = 0; + ant_conf->alt_gaintb = 0; + break; + case (0x31): /* A+B LNA2 */ + ant_conf->fast_div_bias = 0x1; + ant_conf->main_gaintb = 0; + ant_conf->alt_gaintb = 0; + break; + case (0x32): /* A+B LNA1 */ + ant_conf->fast_div_bias = 0x1; + ant_conf->main_gaintb = 0; + ant_conf->alt_gaintb = 0; + break; + default: + break; + } + } + } /* Antenna diversity and combining */ @@ -1585,8 +1674,7 @@ static void ath_ant_comb_scan(struct ath_softc *sc, struct ath_rx_status *rs) antcomb->quick_scan_cnt++; div_comb_done: - ath_ant_div_conf_fast_divbias(&div_ant_conf); - + ath_ant_div_conf_fast_divbias(&div_ant_conf, antcomb, alt_ratio); ath9k_hw_antdiv_comb_conf_set(sc->sc_ah, &div_ant_conf); antcomb->scan_start_time = jiffies; -- cgit v0.10.2 From 21e8ee6d207f6d384689571101436eb9070c22ca Mon Sep 17 00:00:00 2001 From: Mohammed Shafi Shajakhan Date: Fri, 13 May 2011 20:31:40 +0530 Subject: ath9k: make sure main_rssi is positive some times the rssi control descriptor for the main antenna may be negative like that of alternate antenna, hence before incrementing packet counts/rssi of main/alternate antenna make sure both main_rssi and alt_rssi are positive only. this avoids wrong selection of antenna due to diversity Cc: Gabriel Tseng Cc: Senthilkumar Balasubramanian Signed-off-by: Mohammed Shafi Shajakhan Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/recv.c b/drivers/net/wireless/ath/ath9k/recv.c index 2fecfcb..4f52e04 100644 --- a/drivers/net/wireless/ath/ath9k/recv.c +++ b/drivers/net/wireless/ath/ath9k/recv.c @@ -1468,8 +1468,8 @@ static void ath_ant_comb_scan(struct ath_softc *sc, struct ath_rx_status *rs) main_ant_conf = (rs->rs_rssi_ctl2 >> ATH_ANT_RX_MAIN_SHIFT) & ATH_ANT_RX_MASK; - /* Record packet only when alt_rssi is positive */ - if (alt_rssi > 0) { + /* Record packet only when both main_rssi and alt_rssi is positive */ + if (main_rssi > 0 && alt_rssi > 0) { antcomb->total_pkt_count++; antcomb->main_total_rssi += main_rssi; antcomb->alt_total_rssi += alt_rssi; -- cgit v0.10.2 From 108697c44b8e50bea3505c6bf9667da4627cb2d5 Mon Sep 17 00:00:00 2001 From: Mohammed Shafi Shajakhan Date: Fri, 13 May 2011 20:59:42 +0530 Subject: ath9k: make npending frames check as bool we are not doing anything by tracking the number of pending frames. bail out when we first find a pending frame in any one of the 10 queues. Signed-off-by: Mohammed Shafi Shajakhan Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index 3381609..45303bdb 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -2276,7 +2276,7 @@ static void ath9k_flush(struct ieee80211_hw *hw, bool drop) timeout = 1; for (j = 0; j < timeout; j++) { - int npend = 0; + bool npend = false; if (j) usleep_range(1000, 2000); @@ -2285,7 +2285,10 @@ static void ath9k_flush(struct ieee80211_hw *hw, bool drop) if (!ATH_TXQ_SETUP(sc, i)) continue; - npend += ath9k_has_pending_frames(sc, &sc->tx.txq[i]); + npend = ath9k_has_pending_frames(sc, &sc->tx.txq[i]); + + if (npend) + break; } if (!npend) -- cgit v0.10.2 From 57cf8043a64b56a10b9f194572548a3dfb62e596 Mon Sep 17 00:00:00 2001 From: Javier Cardona Date: Fri, 13 May 2011 10:45:43 -0700 Subject: nl80211: Move peer link state definition to nl80211 These definitions need to be exposed now that we can set the peer link states via NL80211_ATTR_STA_PLINK_STATE. They were already being (opaquely) reported by NL80211_STA_INFO_PLINK_STATE. Signed-off-by: Javier Cardona Signed-off-by: John W. Linville diff --git a/include/linux/nl80211.h b/include/linux/nl80211.h index 0ea497c..fc3a948 100644 --- a/include/linux/nl80211.h +++ b/include/linux/nl80211.h @@ -973,9 +973,10 @@ enum nl80211_commands { * @NL80211_ATTR_SUPPORT_MESH_AUTH: Currently, this means the underlying driver * allows auth frames in a mesh to be passed to userspace for processing via * the @NL80211_MESH_SETUP_USERSPACE_AUTH flag. - * @NL80211_ATTR_STA_PLINK_STATE: The state of a mesh peer link. Used when - * userspace is driving the peer link management state machine. - * @NL80211_MESH_SETUP_USERSPACE_AMPE must be enabled. + * @NL80211_ATTR_STA_PLINK_STATE: The state of a mesh peer link as + * defined in &enum nl80211_plink_state. Used when userspace is + * driving the peer link management state machine. + * @NL80211_MESH_SETUP_USERSPACE_AMPE must be enabled. * * @NL80211_ATTR_WOWLAN_SUPPORTED: indicates, as part of the wiphy capabilities, * the supported WoWLAN triggers @@ -1396,6 +1397,7 @@ enum nl80211_sta_bss_param { * @NL80211_STA_INFO_LLID: the station's mesh LLID * @NL80211_STA_INFO_PLID: the station's mesh PLID * @NL80211_STA_INFO_PLINK_STATE: peer link state for the station + * (see %enum nl80211_plink_state) * @NL80211_STA_INFO_RX_BITRATE: last unicast data frame rx rate, nested * attribute, like NL80211_STA_INFO_TX_BITRATE. * @NL80211_STA_INFO_BSS_PARAM: current station's view of BSS, nested attribute @@ -2326,4 +2328,37 @@ enum nl80211_if_combination_attrs { MAX_NL80211_IFACE_COMB = NUM_NL80211_IFACE_COMB - 1 }; + +/** + * enum nl80211_plink_state - state of a mesh peer link finite state machine + * + * @NL80211_PLINK_LISTEN: initial state, considered the implicit + * state of non existant mesh peer links + * @NL80211_PLINK_OPN_SNT: mesh plink open frame has been sent to + * this mesh peer + * @NL80211_PLINK_OPN_RCVD: mesh plink open frame has been received + * from this mesh peer + * @NL80211_PLINK_CNF_RCVD: mesh plink confirm frame has been + * received from this mesh peer + * @NL80211_PLINK_ESTAB: mesh peer link is established + * @NL80211_PLINK_HOLDING: mesh peer link is being closed or cancelled + * @NL80211_PLINK_BLOCKED: all frames transmitted from this mesh + * plink are discarded + * @NUM_NL80211_PLINK_STATES: number of peer link states + * @MAX_NL80211_PLINK_STATES: highest numerical value of plink states + */ +enum nl80211_plink_state { + NL80211_PLINK_LISTEN, + NL80211_PLINK_OPN_SNT, + NL80211_PLINK_OPN_RCVD, + NL80211_PLINK_CNF_RCVD, + NL80211_PLINK_ESTAB, + NL80211_PLINK_HOLDING, + NL80211_PLINK_BLOCKED, + + /* keep last */ + NUM_NL80211_PLINK_STATES, + MAX_NL80211_PLINK_STATES = NUM_NL80211_PLINK_STATES - 1 +}; + #endif /* __LINUX_NL80211_H */ diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index 04afcfb..0a2d795 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -372,33 +372,6 @@ enum plink_actions { }; /** - * enum plink_states - state of a mesh peer link finite state machine - * - * @PLINK_LISTEN: initial state, considered the implicit state of non - * existant mesh peer links - * @PLINK_OPN_SNT: mesh plink open frame has been sent to this mesh - * peer @PLINK_OPN_RCVD: mesh plink open frame has been received from - * this mesh peer - * @PLINK_CNF_RCVD: mesh plink confirm frame has been received from - * this mesh peer - * @PLINK_ESTAB: mesh peer link is established - * @PLINK_HOLDING: mesh peer link is being closed or cancelled - * @PLINK_BLOCKED: all frames transmitted from this mesh plink are - * discarded - * @PLINK_INVALID: reserved - */ -enum plink_state { - PLINK_LISTEN, - PLINK_OPN_SNT, - PLINK_OPN_RCVD, - PLINK_CNF_RCVD, - PLINK_ESTAB, - PLINK_HOLDING, - PLINK_BLOCKED, - PLINK_INVALID, -}; - -/** * struct station_parameters - station parameters * * Used to change and create a new station. diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index 6ecd586..be70c70 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -730,9 +730,9 @@ static void sta_apply_parameters(struct ieee80211_local *local, #ifdef CONFIG_MAC80211_MESH if (sdata->u.mesh.security & IEEE80211_MESH_SEC_SECURED) switch (params->plink_state) { - case PLINK_LISTEN: - case PLINK_ESTAB: - case PLINK_BLOCKED: + case NL80211_PLINK_LISTEN: + case NL80211_PLINK_ESTAB: + case NL80211_PLINK_BLOCKED: sta->plink_state = params->plink_state; break; default: diff --git a/net/mac80211/mesh_plink.c b/net/mac80211/mesh_plink.c index 2c37bee..f4adc09 100644 --- a/net/mac80211/mesh_plink.c +++ b/net/mac80211/mesh_plink.c @@ -83,7 +83,7 @@ void mesh_plink_dec_estab_count(struct ieee80211_sub_if_data *sdata) */ static inline void mesh_plink_fsm_restart(struct sta_info *sta) { - sta->plink_state = PLINK_LISTEN; + sta->plink_state = NL80211_PLINK_LISTEN; sta->llid = sta->plid = sta->reason = 0; sta->plink_retries = 0; } @@ -126,11 +126,11 @@ static bool __mesh_plink_deactivate(struct sta_info *sta) struct ieee80211_sub_if_data *sdata = sta->sdata; bool deactivated = false; - if (sta->plink_state == PLINK_ESTAB) { + if (sta->plink_state == NL80211_PLINK_ESTAB) { mesh_plink_dec_estab_count(sdata); deactivated = true; } - sta->plink_state = PLINK_BLOCKED; + sta->plink_state = NL80211_PLINK_BLOCKED; mesh_path_flush_by_nexthop(sta); return deactivated; @@ -268,7 +268,7 @@ void mesh_neighbour_update(u8 *hw_addr, u32 rates, sta->last_rx = jiffies; sta->sta.supp_rates[local->hw.conf.channel->band] = rates; if (mesh_peer_accepts_plinks(elems) && - sta->plink_state == PLINK_LISTEN && + sta->plink_state == NL80211_PLINK_LISTEN && sdata->u.mesh.accepting_plinks && sdata->u.mesh.mshcfg.auto_open_plinks) mesh_plink_open(sta); @@ -308,8 +308,8 @@ static void mesh_plink_timer(unsigned long data) sdata = sta->sdata; switch (sta->plink_state) { - case PLINK_OPN_RCVD: - case PLINK_OPN_SNT: + case NL80211_PLINK_OPN_RCVD: + case NL80211_PLINK_OPN_SNT: /* retry timer */ if (sta->plink_retries < dot11MeshMaxRetries(sdata)) { u32 rand; @@ -328,17 +328,17 @@ static void mesh_plink_timer(unsigned long data) } reason = cpu_to_le16(MESH_MAX_RETRIES); /* fall through on else */ - case PLINK_CNF_RCVD: + case NL80211_PLINK_CNF_RCVD: /* confirm timer */ if (!reason) reason = cpu_to_le16(MESH_CONFIRM_TIMEOUT); - sta->plink_state = PLINK_HOLDING; + sta->plink_state = NL80211_PLINK_HOLDING; mod_plink_timer(sta, dot11MeshHoldingTimeout(sdata)); spin_unlock_bh(&sta->lock); mesh_plink_frame_tx(sdata, PLINK_CLOSE, sta->sta.addr, llid, plid, reason); break; - case PLINK_HOLDING: + case NL80211_PLINK_HOLDING: /* holding timer */ del_timer(&sta->plink_timer); mesh_plink_fsm_restart(sta); @@ -386,11 +386,11 @@ int mesh_plink_open(struct sta_info *sta) spin_lock_bh(&sta->lock); get_random_bytes(&llid, 2); sta->llid = llid; - if (sta->plink_state != PLINK_LISTEN) { + if (sta->plink_state != NL80211_PLINK_LISTEN) { spin_unlock_bh(&sta->lock); return -EBUSY; } - sta->plink_state = PLINK_OPN_SNT; + sta->plink_state = NL80211_PLINK_OPN_SNT; mesh_plink_timer_set(sta, dot11MeshRetryTimeout(sdata)); spin_unlock_bh(&sta->lock); mpl_dbg("Mesh plink: starting establishment with %pM\n", @@ -407,7 +407,7 @@ void mesh_plink_block(struct sta_info *sta) spin_lock_bh(&sta->lock); deactivated = __mesh_plink_deactivate(sta); - sta->plink_state = PLINK_BLOCKED; + sta->plink_state = NL80211_PLINK_BLOCKED; spin_unlock_bh(&sta->lock); if (deactivated) @@ -430,13 +430,13 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m __le16 plid, llid, reason; #ifdef CONFIG_MAC80211_VERBOSE_MPL_DEBUG static const char *mplstates[] = { - [PLINK_LISTEN] = "LISTEN", - [PLINK_OPN_SNT] = "OPN-SNT", - [PLINK_OPN_RCVD] = "OPN-RCVD", - [PLINK_CNF_RCVD] = "CNF_RCVD", - [PLINK_ESTAB] = "ESTAB", - [PLINK_HOLDING] = "HOLDING", - [PLINK_BLOCKED] = "BLOCKED" + [NL80211_PLINK_LISTEN] = "LISTEN", + [NL80211_PLINK_OPN_SNT] = "OPN-SNT", + [NL80211_PLINK_OPN_RCVD] = "OPN-RCVD", + [NL80211_PLINK_CNF_RCVD] = "CNF_RCVD", + [NL80211_PLINK_ESTAB] = "ESTAB", + [NL80211_PLINK_HOLDING] = "HOLDING", + [NL80211_PLINK_BLOCKED] = "BLOCKED" }; #endif @@ -502,7 +502,7 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m return; } - if (sta && sta->plink_state == PLINK_BLOCKED) { + if (sta && sta->plink_state == NL80211_PLINK_BLOCKED) { rcu_read_unlock(); return; } @@ -572,7 +572,7 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m event = CNF_ACPT; break; case PLINK_CLOSE: - if (sta->plink_state == PLINK_ESTAB) + if (sta->plink_state == NL80211_PLINK_ESTAB) /* Do not check for llid or plid. This does not * follow the standard but since multiple plinks * per sta are not supported, it is necessary in @@ -607,14 +607,14 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m reason = 0; switch (sta->plink_state) { /* spin_unlock as soon as state is updated at each case */ - case PLINK_LISTEN: + case NL80211_PLINK_LISTEN: switch (event) { case CLS_ACPT: mesh_plink_fsm_restart(sta); spin_unlock_bh(&sta->lock); break; case OPN_ACPT: - sta->plink_state = PLINK_OPN_RCVD; + sta->plink_state = NL80211_PLINK_OPN_RCVD; sta->plid = plid; get_random_bytes(&llid, 2); sta->llid = llid; @@ -631,7 +631,7 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m } break; - case PLINK_OPN_SNT: + case NL80211_PLINK_OPN_SNT: switch (event) { case OPN_RJCT: case CNF_RJCT: @@ -640,7 +640,7 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m if (!reason) reason = cpu_to_le16(MESH_CLOSE_RCVD); sta->reason = reason; - sta->plink_state = PLINK_HOLDING; + sta->plink_state = NL80211_PLINK_HOLDING; if (!mod_plink_timer(sta, dot11MeshHoldingTimeout(sdata))) sta->ignore_plink_timer = true; @@ -652,7 +652,7 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m break; case OPN_ACPT: /* retry timer is left untouched */ - sta->plink_state = PLINK_OPN_RCVD; + sta->plink_state = NL80211_PLINK_OPN_RCVD; sta->plid = plid; llid = sta->llid; spin_unlock_bh(&sta->lock); @@ -660,7 +660,7 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m plid, 0); break; case CNF_ACPT: - sta->plink_state = PLINK_CNF_RCVD; + sta->plink_state = NL80211_PLINK_CNF_RCVD; if (!mod_plink_timer(sta, dot11MeshConfirmTimeout(sdata))) sta->ignore_plink_timer = true; @@ -673,7 +673,7 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m } break; - case PLINK_OPN_RCVD: + case NL80211_PLINK_OPN_RCVD: switch (event) { case OPN_RJCT: case CNF_RJCT: @@ -682,7 +682,7 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m if (!reason) reason = cpu_to_le16(MESH_CLOSE_RCVD); sta->reason = reason; - sta->plink_state = PLINK_HOLDING; + sta->plink_state = NL80211_PLINK_HOLDING; if (!mod_plink_timer(sta, dot11MeshHoldingTimeout(sdata))) sta->ignore_plink_timer = true; @@ -700,7 +700,7 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m break; case CNF_ACPT: del_timer(&sta->plink_timer); - sta->plink_state = PLINK_ESTAB; + sta->plink_state = NL80211_PLINK_ESTAB; spin_unlock_bh(&sta->lock); mesh_plink_inc_estab_count(sdata); ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON); @@ -713,7 +713,7 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m } break; - case PLINK_CNF_RCVD: + case NL80211_PLINK_CNF_RCVD: switch (event) { case OPN_RJCT: case CNF_RJCT: @@ -722,7 +722,7 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m if (!reason) reason = cpu_to_le16(MESH_CLOSE_RCVD); sta->reason = reason; - sta->plink_state = PLINK_HOLDING; + sta->plink_state = NL80211_PLINK_HOLDING; if (!mod_plink_timer(sta, dot11MeshHoldingTimeout(sdata))) sta->ignore_plink_timer = true; @@ -734,7 +734,7 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m break; case OPN_ACPT: del_timer(&sta->plink_timer); - sta->plink_state = PLINK_ESTAB; + sta->plink_state = NL80211_PLINK_ESTAB; spin_unlock_bh(&sta->lock); mesh_plink_inc_estab_count(sdata); ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON); @@ -749,13 +749,13 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m } break; - case PLINK_ESTAB: + case NL80211_PLINK_ESTAB: switch (event) { case CLS_ACPT: reason = cpu_to_le16(MESH_CLOSE_RCVD); sta->reason = reason; deactivated = __mesh_plink_deactivate(sta); - sta->plink_state = PLINK_HOLDING; + sta->plink_state = NL80211_PLINK_HOLDING; llid = sta->llid; mod_plink_timer(sta, dot11MeshHoldingTimeout(sdata)); spin_unlock_bh(&sta->lock); @@ -775,7 +775,7 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m break; } break; - case PLINK_HOLDING: + case NL80211_PLINK_HOLDING: switch (event) { case CLS_ACPT: if (del_timer(&sta->plink_timer)) diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index 1b9413f..3a9515c 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -490,7 +490,7 @@ ieee80211_rx_mesh_check(struct ieee80211_rx_data *rx) * establisment frame, beacon or probe, drop the frame. */ - if (!rx->sta || sta_plink_state(rx->sta) != PLINK_ESTAB) { + if (!rx->sta || sta_plink_state(rx->sta) != NL80211_PLINK_ESTAB) { struct ieee80211_mgmt *mgmt; if (!ieee80211_is_mgmt(hdr->frame_control)) diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c index 82ab6b4..4a15f96 100644 --- a/net/mac80211/sta_info.c +++ b/net/mac80211/sta_info.c @@ -277,7 +277,7 @@ struct sta_info *sta_info_alloc(struct ieee80211_sub_if_data *sdata, #endif /* CONFIG_MAC80211_VERBOSE_DEBUG */ #ifdef CONFIG_MAC80211_MESH - sta->plink_state = PLINK_LISTEN; + sta->plink_state = NL80211_PLINK_LISTEN; init_timer(&sta->plink_timer); #endif diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h index d6b5660..c6ae871 100644 --- a/net/mac80211/sta_info.h +++ b/net/mac80211/sta_info.h @@ -318,7 +318,7 @@ struct sta_info { u8 plink_retries; bool ignore_plink_timer; bool plink_timer_was_running; - enum plink_state plink_state; + enum nl80211_plink_state plink_state; u32 plink_timeout; struct timer_list plink_timer; #endif @@ -336,12 +336,12 @@ struct sta_info { struct ieee80211_sta sta; }; -static inline enum plink_state sta_plink_state(struct sta_info *sta) +static inline enum nl80211_plink_state sta_plink_state(struct sta_info *sta) { #ifdef CONFIG_MAC80211_MESH return sta->plink_state; #endif - return PLINK_LISTEN; + return NL80211_PLINK_LISTEN; } static inline void set_sta_flags(struct sta_info *sta, const u32 flags) diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index beac296..2222ce08 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -2335,7 +2335,7 @@ static int nl80211_set_station(struct sk_buff *skb, struct genl_info *info) memset(¶ms, 0, sizeof(params)); params.listen_interval = -1; - params.plink_state = PLINK_INVALID; + params.plink_state = -1; if (info->attrs[NL80211_ATTR_STA_AID]) return -EINVAL; -- cgit v0.10.2 From 8b3becadc82de3b87a5c196239db3fef6caa9c82 Mon Sep 17 00:00:00 2001 From: Yogesh Ashok Powar Date: Fri, 13 May 2011 11:22:31 -0700 Subject: cfg80211: make stripping of 802.11 header optional from AMSDU Currently the devices that have already stripped IEEE 802.11 header from the AMSDU SKB can not use ieee80211_amsdu_to_8023s routine. This patch enhances ieee80211_amsdu_to_8023s() API by changing mandatory removing of IEEE 802.11 header from AMSDU to optional. Signed-off-by: Yogesh Ashok Powar Signed-off-by: Bing Zhao Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwmc3200wifi/rx.c b/drivers/net/wireless/iwmc3200wifi/rx.c index 9a57cf6..5665a1a 100644 --- a/drivers/net/wireless/iwmc3200wifi/rx.c +++ b/drivers/net/wireless/iwmc3200wifi/rx.c @@ -1576,7 +1576,8 @@ static void iwm_rx_process_amsdu(struct iwm_priv *iwm, struct sk_buff *skb) IWM_HEXDUMP(iwm, DBG, RX, "A-MSDU: ", skb->data, skb->len); __skb_queue_head_init(&list); - ieee80211_amsdu_to_8023s(skb, &list, ndev->dev_addr, wdev->iftype, 0); + ieee80211_amsdu_to_8023s(skb, &list, ndev->dev_addr, wdev->iftype, 0, + true); while ((frame = __skb_dequeue(&list))) { ndev->stats.rx_packets++; diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index 0a2d795..bfd6557 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -2237,10 +2237,12 @@ int ieee80211_data_from_8023(struct sk_buff *skb, const u8 *addr, * @addr: The device MAC address. * @iftype: The device interface type. * @extra_headroom: The hardware extra headroom for SKBs in the @list. + * @has_80211_header: Set it true if SKB is with IEEE 802.11 header. */ void ieee80211_amsdu_to_8023s(struct sk_buff *skb, struct sk_buff_head *list, const u8 *addr, enum nl80211_iftype iftype, - const unsigned int extra_headroom); + const unsigned int extra_headroom, + bool has_80211_header); /** * cfg80211_classify8021d - determine the 802.1p/1d tag for a data frame diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index 3a9515c..78c72a4 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -1783,7 +1783,7 @@ ieee80211_rx_h_amsdu(struct ieee80211_rx_data *rx) ieee80211_amsdu_to_8023s(skb, &frame_list, dev->dev_addr, rx->sdata->vif.type, - rx->local->hw.extra_tx_headroom); + rx->local->hw.extra_tx_headroom, true); while (!skb_queue_empty(&frame_list)) { rx->skb = __skb_dequeue(&frame_list); diff --git a/net/wireless/util.c b/net/wireless/util.c index 95e4e25..f0536d4 100644 --- a/net/wireless/util.c +++ b/net/wireless/util.c @@ -544,7 +544,8 @@ EXPORT_SYMBOL(ieee80211_data_from_8023); void ieee80211_amsdu_to_8023s(struct sk_buff *skb, struct sk_buff_head *list, const u8 *addr, enum nl80211_iftype iftype, - const unsigned int extra_headroom) + const unsigned int extra_headroom, + bool has_80211_header) { struct sk_buff *frame = NULL; u16 ethertype; @@ -553,14 +554,18 @@ void ieee80211_amsdu_to_8023s(struct sk_buff *skb, struct sk_buff_head *list, int remaining, err; u8 dst[ETH_ALEN], src[ETH_ALEN]; - err = ieee80211_data_to_8023(skb, addr, iftype); - if (err) - goto out; + if (has_80211_header) { + err = ieee80211_data_to_8023(skb, addr, iftype); + if (err) + goto out; - /* skip the wrapping header */ - eth = (struct ethhdr *) skb_pull(skb, sizeof(struct ethhdr)); - if (!eth) - goto out; + /* skip the wrapping header */ + eth = (struct ethhdr *) skb_pull(skb, sizeof(struct ethhdr)); + if (!eth) + goto out; + } else { + eth = (struct ethhdr *) skb->data; + } while (skb != frame) { u8 padding; -- cgit v0.10.2 From 3b8ab88acaceb505aa06ef3bbf3a73b92470ae78 Mon Sep 17 00:00:00 2001 From: Yogesh Ashok Powar Date: Fri, 13 May 2011 11:22:32 -0700 Subject: mwifiex: use ieee80211_amsdu_to_8023s routine mwifiex was using its own implementation of converting 802.11n AMSDU to 802.3s. This patch removes mwifiex specific implementation and uses existing ieee80211_amsdu_to_8023s routine. Signed-off-by: Yogesh Ashok Powar Signed-off-by: Bing Zhao Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/mwifiex/11n_aggr.c b/drivers/net/wireless/mwifiex/11n_aggr.c index 2b2cca5..d3d5e08 100644 --- a/drivers/net/wireless/mwifiex/11n_aggr.c +++ b/drivers/net/wireless/mwifiex/11n_aggr.c @@ -136,131 +136,6 @@ mwifiex_11n_form_amsdu_txpd(struct mwifiex_private *priv, } /* - * Counts the number of subframes in an aggregate packet. - * - * This function parses an aggregate packet buffer, looking for - * subframes and counting the number of such subframe found. The - * function automatically skips the DA/SA fields at the beginning - * of each subframe and padding at the end. - */ -static int -mwifiex_11n_get_num_aggr_pkts(u8 *data, int total_pkt_len) -{ - int pkt_count = 0, pkt_len, pad; - - while (total_pkt_len > 0) { - /* Length will be in network format, change it to host */ - pkt_len = ntohs((*(__be16 *)(data + 2 * ETH_ALEN))); - pad = (((pkt_len + sizeof(struct ethhdr)) & 3)) ? - (4 - ((pkt_len + sizeof(struct ethhdr)) & 3)) : 0; - data += pkt_len + pad + sizeof(struct ethhdr); - total_pkt_len -= pkt_len + pad + sizeof(struct ethhdr); - ++pkt_count; - } - - return pkt_count; -} - -/* - * De-aggregate received packets. - * - * This function parses the received aggregate buffer, extracts each subframe, - * strips off the SNAP header from them and sends the data portion for further - * processing. - * - * Each subframe body is copied onto a separate buffer, which are freed by - * upper layer after processing. The function also performs sanity tests on - * the received buffer. - */ -int mwifiex_11n_deaggregate_pkt(struct mwifiex_private *priv, - struct sk_buff *skb) -{ - u16 pkt_len; - int total_pkt_len; - u8 *data; - int pad; - struct mwifiex_rxinfo *rx_info = MWIFIEX_SKB_RXCB(skb); - struct rxpd *local_rx_pd = (struct rxpd *) skb->data; - struct sk_buff *skb_daggr; - struct mwifiex_rxinfo *rx_info_daggr; - int ret = -1; - struct rx_packet_hdr *rx_pkt_hdr; - struct mwifiex_adapter *adapter = priv->adapter; - u8 rfc1042_eth_hdr[ETH_ALEN] = { 0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00}; - - data = (u8 *) (local_rx_pd + local_rx_pd->rx_pkt_offset); - total_pkt_len = local_rx_pd->rx_pkt_length; - - /* Sanity test */ - if (total_pkt_len > MWIFIEX_RX_DATA_BUF_SIZE) { - dev_err(adapter->dev, "total pkt len greater than buffer" - " size %d\n", total_pkt_len); - return -1; - } - - rx_info->use_count = mwifiex_11n_get_num_aggr_pkts(data, total_pkt_len); - - while (total_pkt_len > 0) { - rx_pkt_hdr = (struct rx_packet_hdr *) data; - /* Length will be in network format, change it to host */ - pkt_len = ntohs((*(__be16 *) (data + 2 * ETH_ALEN))); - if (pkt_len > total_pkt_len) { - dev_err(adapter->dev, "pkt_len %d > total_pkt_len %d\n", - total_pkt_len, pkt_len); - break; - } - - pad = (((pkt_len + sizeof(struct ethhdr)) & 3)) ? - (4 - ((pkt_len + sizeof(struct ethhdr)) & 3)) : 0; - - total_pkt_len -= pkt_len + pad + sizeof(struct ethhdr); - - if (memcmp(&rx_pkt_hdr->rfc1042_hdr, - rfc1042_eth_hdr, sizeof(rfc1042_eth_hdr)) == 0) { - memmove(data + LLC_SNAP_LEN, data, 2 * ETH_ALEN); - data += LLC_SNAP_LEN; - pkt_len += sizeof(struct ethhdr) - LLC_SNAP_LEN; - } else { - *(u16 *) (data + 2 * ETH_ALEN) = (u16) 0; - pkt_len += sizeof(struct ethhdr); - } - - skb_daggr = dev_alloc_skb(pkt_len); - if (!skb_daggr) { - dev_err(adapter->dev, "%s: failed to alloc skb_daggr\n", - __func__); - return -1; - } - rx_info_daggr = MWIFIEX_SKB_RXCB(skb_daggr); - - rx_info_daggr->bss_index = rx_info->bss_index; - skb_daggr->tstamp = skb->tstamp; - rx_info_daggr->parent = skb; - skb_daggr->priority = skb->priority; - skb_put(skb_daggr, pkt_len); - memcpy(skb_daggr->data, data, pkt_len); - - ret = mwifiex_recv_packet(adapter, skb_daggr); - - switch (ret) { - case -EINPROGRESS: - break; - case -1: - dev_err(adapter->dev, "deaggr: host_to_card failed\n"); - case 0: - mwifiex_recv_packet_complete(adapter, skb_daggr, ret); - break; - default: - break; - } - - data += pkt_len + pad; - } - - return ret; -} - -/* * Create aggregated packet. * * This function creates an aggregated MSDU packet, by combining buffers diff --git a/drivers/net/wireless/mwifiex/sta_rx.c b/drivers/net/wireless/mwifiex/sta_rx.c index e047f0d..1fdddec 100644 --- a/drivers/net/wireless/mwifiex/sta_rx.c +++ b/drivers/net/wireless/mwifiex/sta_rx.c @@ -141,10 +141,28 @@ int mwifiex_process_sta_rx_packet(struct mwifiex_adapter *adapter, dev_kfree_skb_any(skb); return ret; } + if (local_rx_pd->rx_pkt_type == PKT_TYPE_AMSDU) { - mwifiex_11n_deaggregate_pkt(priv, skb); - return ret; + struct sk_buff_head list; + struct sk_buff *rx_skb; + + __skb_queue_head_init(&list); + + skb_pull(skb, local_rx_pd->rx_pkt_offset); + skb_trim(skb, local_rx_pd->rx_pkt_length); + + ieee80211_amsdu_to_8023s(skb, &list, priv->curr_addr, + priv->wdev->iftype, 0, false); + + while (!skb_queue_empty(&list)) { + rx_skb = __skb_dequeue(&list); + ret = mwifiex_recv_packet(adapter, rx_skb); + if (ret == -1) + dev_err(adapter->dev, "Rx of A-MSDU failed"); + } + return 0; } + /* * If the packet is not an unicast packet then send the packet * directly to os. Don't pass thru rx reordering -- cgit v0.10.2 From 89a88ab84b946a90839fb66ca3583a2504c11292 Mon Sep 17 00:00:00 2001 From: Ajit Khaparde Date: Mon, 16 May 2011 07:36:18 +0000 Subject: be2net: Support for version 1 of stats for BE3 Added support to get version 1 of the stats for BE3. Use old stats command for BE2. Signed-off-by: Ajit Khaparde Signed-off-by: Selvin Xavier Signed-off-by: Padmanabh Ratnakar Signed-off-by: David S. Miller diff --git a/drivers/net/benet/be.h b/drivers/net/benet/be.h index 41bbc32..0da0384 100644 --- a/drivers/net/benet/be.h +++ b/drivers/net/benet/be.h @@ -244,6 +244,43 @@ struct be_rx_obj { struct be_drv_stats { u8 be_on_die_temperature; + u32 be_tx_events; + u32 eth_red_drops; + u32 rx_drops_no_pbuf; + u32 rx_drops_no_txpb; + u32 rx_drops_no_erx_descr; + u32 rx_drops_no_tpre_descr; + u32 rx_drops_too_many_frags; + u32 rx_drops_invalid_ring; + u32 forwarded_packets; + u32 rx_drops_mtu; + u32 rx_crc_errors; + u32 rx_alignment_symbol_errors; + u32 rx_pause_frames; + u32 rx_priority_pause_frames; + u32 rx_control_frames; + u32 rx_in_range_errors; + u32 rx_out_range_errors; + u32 rx_frame_too_long; + u32 rx_address_match_errors; + u32 rx_dropped_too_small; + u32 rx_dropped_too_short; + u32 rx_dropped_header_too_small; + u32 rx_dropped_tcp_length; + u32 rx_dropped_runt; + u32 rx_ip_checksum_errs; + u32 rx_tcp_checksum_errs; + u32 rx_udp_checksum_errs; + u32 rx_switched_unicast_packets; + u32 rx_switched_multicast_packets; + u32 rx_switched_broadcast_packets; + u32 tx_pauseframes; + u32 tx_priority_pauseframes; + u32 tx_controlframes; + u32 rxpp_fifo_overflow_drop; + u32 rx_input_fifo_overflow_drop; + u32 pmem_fifo_overflow_drop; + u32 jabber_events; }; struct be_vf_cfg { @@ -483,5 +520,6 @@ extern void be_cq_notify(struct be_adapter *adapter, u16 qid, bool arm, u16 num_popped); extern void be_link_status_update(struct be_adapter *adapter, bool link_up); extern void netdev_stats_update(struct be_adapter *adapter); +extern void be_parse_stats(struct be_adapter *adapter); extern int be_load_fw(struct be_adapter *adapter, u8 *func); #endif /* BE_H */ diff --git a/drivers/net/benet/be_cmds.c b/drivers/net/benet/be_cmds.c index f2c9099..08e0938 100644 --- a/drivers/net/benet/be_cmds.c +++ b/drivers/net/benet/be_cmds.c @@ -80,10 +80,20 @@ static int be_mcc_compl_process(struct be_adapter *adapter, if (compl_status == MCC_STATUS_SUCCESS) { if ((compl->tag0 == OPCODE_ETH_GET_STATISTICS) && (compl->tag1 == CMD_SUBSYSTEM_ETH)) { - struct be_cmd_resp_get_stats *resp = - adapter->stats_cmd.va; - be_dws_le_to_cpu(&resp->hw_stats, - sizeof(resp->hw_stats)); + if (adapter->generation == BE_GEN3) { + struct be_cmd_resp_get_stats_v1 *resp = + adapter->stats_cmd.va; + + be_dws_le_to_cpu(&resp->hw_stats, + sizeof(resp->hw_stats)); + } else { + struct be_cmd_resp_get_stats_v0 *resp = + adapter->stats_cmd.va; + + be_dws_le_to_cpu(&resp->hw_stats, + sizeof(resp->hw_stats)); + } + be_parse_stats(adapter); netdev_stats_update(adapter); adapter->stats_cmd_sent = false; } @@ -1075,7 +1085,7 @@ int be_cmd_if_destroy(struct be_adapter *adapter, u32 interface_id, u32 domain) int be_cmd_get_stats(struct be_adapter *adapter, struct be_dma_mem *nonemb_cmd) { struct be_mcc_wrb *wrb; - struct be_cmd_req_get_stats *req; + struct be_cmd_req_hdr *hdr; struct be_sge *sge; int status = 0; @@ -1089,14 +1099,18 @@ int be_cmd_get_stats(struct be_adapter *adapter, struct be_dma_mem *nonemb_cmd) status = -EBUSY; goto err; } - req = nonemb_cmd->va; + hdr = nonemb_cmd->va; sge = nonembedded_sgl(wrb); - be_wrb_hdr_prepare(wrb, sizeof(*req), false, 1, + be_wrb_hdr_prepare(wrb, nonemb_cmd->size, false, 1, OPCODE_ETH_GET_STATISTICS); - be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_ETH, - OPCODE_ETH_GET_STATISTICS, sizeof(*req)); + be_cmd_hdr_prepare(hdr, CMD_SUBSYSTEM_ETH, + OPCODE_ETH_GET_STATISTICS, nonemb_cmd->size); + + if (adapter->generation == BE_GEN3) + hdr->version = 1; + wrb->tag1 = CMD_SUBSYSTEM_ETH; sge->pa_hi = cpu_to_le32(upper_32_bits(nonemb_cmd->dma)); sge->pa_lo = cpu_to_le32(nonemb_cmd->dma & 0xFFFFFFFF); diff --git a/drivers/net/benet/be_cmds.h b/drivers/net/benet/be_cmds.h index 78256b6..bcf816d 100644 --- a/drivers/net/benet/be_cmds.h +++ b/drivers/net/benet/be_cmds.h @@ -568,7 +568,7 @@ struct be_cmd_req_if_destroy { }; /*************** HW Stats Get **********************************/ -struct be_port_rxf_stats { +struct be_port_rxf_stats_v0 { u32 rx_bytes_lsd; /* dword 0*/ u32 rx_bytes_msd; /* dword 1*/ u32 rx_total_frames; /* dword 2*/ @@ -637,8 +637,8 @@ struct be_port_rxf_stats { u32 rx_input_fifo_overflow; /* dword 65*/ }; -struct be_rxf_stats { - struct be_port_rxf_stats port[2]; +struct be_rxf_stats_v0 { + struct be_port_rxf_stats_v0 port[2]; u32 rx_drops_no_pbuf; /* dword 132*/ u32 rx_drops_no_txpb; /* dword 133*/ u32 rx_drops_no_erx_descr; /* dword 134*/ @@ -661,34 +661,31 @@ struct be_rxf_stats { u32 rsvd1[6]; }; -struct be_erx_stats { +struct be_erx_stats_v0 { u32 rx_drops_no_fragments[44]; /* dwordS 0 to 43*/ - u32 debug_wdma_sent_hold; /* dword 44*/ - u32 debug_wdma_pbfree_sent_hold; /* dword 45*/ - u32 debug_wdma_zerobyte_pbfree_sent_hold; /* dword 46*/ - u32 debug_pmem_pbuf_dealloc; /* dword 47*/ + u32 rsvd[4]; }; struct be_pmem_stats { u32 eth_red_drops; - u32 rsvd[4]; + u32 rsvd[5]; }; -struct be_hw_stats { - struct be_rxf_stats rxf; +struct be_hw_stats_v0 { + struct be_rxf_stats_v0 rxf; u32 rsvd[48]; - struct be_erx_stats erx; + struct be_erx_stats_v0 erx; struct be_pmem_stats pmem; }; -struct be_cmd_req_get_stats { +struct be_cmd_req_get_stats_v0 { struct be_cmd_req_hdr hdr; - u8 rsvd[sizeof(struct be_hw_stats)]; + u8 rsvd[sizeof(struct be_hw_stats_v0)]; }; -struct be_cmd_resp_get_stats { +struct be_cmd_resp_get_stats_v0 { struct be_cmd_resp_hdr hdr; - struct be_hw_stats hw_stats; + struct be_hw_stats_v0 hw_stats; }; struct be_cmd_req_get_cntl_addnl_attribs { @@ -728,13 +725,6 @@ struct be_cmd_req_mcast_mac_config { struct macaddr mac[BE_MAX_MC]; } __packed; -static inline struct be_hw_stats * -hw_stats_from_cmd(struct be_cmd_resp_get_stats *cmd) -{ - return &cmd->hw_stats; -} - - /******************* RX FILTER ******************************/ struct be_cmd_req_rx_filter { struct be_cmd_req_hdr hdr; @@ -1087,6 +1077,151 @@ struct be_cmd_resp_set_func_cap { u8 rsvd[212]; }; +/*************** HW Stats Get v1 **********************************/ +#define BE_TXP_SW_SZ 48 +struct be_port_rxf_stats_v1 { + u32 rsvd0[12]; + u32 rx_crc_errors; + u32 rx_alignment_symbol_errors; + u32 rx_pause_frames; + u32 rx_priority_pause_frames; + u32 rx_control_frames; + u32 rx_in_range_errors; + u32 rx_out_range_errors; + u32 rx_frame_too_long; + u32 rx_address_match_errors; + u32 rx_dropped_too_small; + u32 rx_dropped_too_short; + u32 rx_dropped_header_too_small; + u32 rx_dropped_tcp_length; + u32 rx_dropped_runt; + u32 rsvd1[10]; + u32 rx_ip_checksum_errs; + u32 rx_tcp_checksum_errs; + u32 rx_udp_checksum_errs; + u32 rsvd2[7]; + u32 rx_switched_unicast_packets; + u32 rx_switched_multicast_packets; + u32 rx_switched_broadcast_packets; + u32 rsvd3[3]; + u32 tx_pauseframes; + u32 tx_priority_pauseframes; + u32 tx_controlframes; + u32 rsvd4[10]; + u32 rxpp_fifo_overflow_drop; + u32 rx_input_fifo_overflow_drop; + u32 pmem_fifo_overflow_drop; + u32 jabber_events; + u32 rsvd5[3]; +}; + + +struct be_rxf_stats_v1 { + struct be_port_rxf_stats_v1 port[4]; + u32 rsvd0[2]; + u32 rx_drops_no_pbuf; + u32 rx_drops_no_txpb; + u32 rx_drops_no_erx_descr; + u32 rx_drops_no_tpre_descr; + u32 rsvd1[6]; + u32 rx_drops_too_many_frags; + u32 rx_drops_invalid_ring; + u32 forwarded_packets; + u32 rx_drops_mtu; + u32 rsvd2[14]; +}; + +struct be_erx_stats_v1 { + u32 rx_drops_no_fragments[68]; /* dwordS 0 to 67*/ + u32 rsvd[4]; +}; + +struct be_hw_stats_v1 { + struct be_rxf_stats_v1 rxf; + u32 rsvd0[BE_TXP_SW_SZ]; + struct be_erx_stats_v1 erx; + struct be_pmem_stats pmem; + u32 rsvd1[3]; +}; + +struct be_cmd_req_get_stats_v1 { + struct be_cmd_req_hdr hdr; + u8 rsvd[sizeof(struct be_hw_stats_v1)]; +}; + +struct be_cmd_resp_get_stats_v1 { + struct be_cmd_resp_hdr hdr; + struct be_hw_stats_v1 hw_stats; +}; + +static inline void * +hw_stats_from_cmd(struct be_adapter *adapter) +{ + if (adapter->generation == BE_GEN3) { + struct be_cmd_resp_get_stats_v1 *cmd = adapter->stats_cmd.va; + + return &cmd->hw_stats; + } else { + struct be_cmd_resp_get_stats_v0 *cmd = adapter->stats_cmd.va; + + return &cmd->hw_stats; + } +} + +static inline void *be_port_rxf_stats_from_cmd(struct be_adapter *adapter) +{ + if (adapter->generation == BE_GEN3) { + struct be_hw_stats_v1 *hw_stats = hw_stats_from_cmd(adapter); + struct be_rxf_stats_v1 *rxf_stats = &hw_stats->rxf; + + return &rxf_stats->port[adapter->port_num]; + } else { + struct be_hw_stats_v0 *hw_stats = hw_stats_from_cmd(adapter); + struct be_rxf_stats_v0 *rxf_stats = &hw_stats->rxf; + + return &rxf_stats->port[adapter->port_num]; + } +} + +static inline void *be_rxf_stats_from_cmd(struct be_adapter *adapter) +{ + if (adapter->generation == BE_GEN3) { + struct be_hw_stats_v1 *hw_stats = hw_stats_from_cmd(adapter); + + return &hw_stats->rxf; + } else { + struct be_hw_stats_v0 *hw_stats = hw_stats_from_cmd(adapter); + + return &hw_stats->rxf; + } +} + +static inline void *be_erx_stats_from_cmd(struct be_adapter *adapter) +{ + if (adapter->generation == BE_GEN3) { + struct be_hw_stats_v1 *hw_stats = hw_stats_from_cmd(adapter); + + return &hw_stats->erx; + } else { + struct be_hw_stats_v0 *hw_stats = hw_stats_from_cmd(adapter); + + return &hw_stats->erx; + } +} + +static inline void *be_pmem_stats_from_cmd(struct be_adapter *adapter) +{ + if (adapter->generation == BE_GEN3) { + struct be_hw_stats_v1 *hw_stats = hw_stats_from_cmd(adapter); + + return &hw_stats->pmem; + } else { + struct be_hw_stats_v0 *hw_stats = hw_stats_from_cmd(adapter); + + return &hw_stats->pmem; + } +} + extern int be_pci_fnum_get(struct be_adapter *adapter); extern int be_cmd_POST(struct be_adapter *adapter); extern int be_cmd_mac_addr_query(struct be_adapter *adapter, u8 *mac_addr, diff --git a/drivers/net/benet/be_ethtool.c b/drivers/net/benet/be_ethtool.c index 8e770e8..facfe3c 100644 --- a/drivers/net/benet/be_ethtool.c +++ b/drivers/net/benet/be_ethtool.c @@ -26,8 +26,8 @@ struct be_ethtool_stat { int offset; }; -enum {NETSTAT, PORTSTAT, MISCSTAT, DRVSTAT_TX, DRVSTAT_RX, ERXSTAT, - PMEMSTAT, DRVSTAT}; +enum {NETSTAT, DRVSTAT_TX, DRVSTAT_RX, ERXSTAT, + DRVSTAT}; #define FIELDINFO(_struct, field) FIELD_SIZEOF(_struct, field), \ offsetof(_struct, field) #define NETSTAT_INFO(field) #field, NETSTAT,\ @@ -37,15 +37,8 @@ enum {NETSTAT, PORTSTAT, MISCSTAT, DRVSTAT_TX, DRVSTAT_RX, ERXSTAT, FIELDINFO(struct be_tx_stats, field) #define DRVSTAT_RX_INFO(field) #field, DRVSTAT_RX,\ FIELDINFO(struct be_rx_stats, field) -#define MISCSTAT_INFO(field) #field, MISCSTAT,\ - FIELDINFO(struct be_rxf_stats, field) -#define PORTSTAT_INFO(field) #field, PORTSTAT,\ - FIELDINFO(struct be_port_rxf_stats, \ - field) -#define ERXSTAT_INFO(field) #field, ERXSTAT,\ - FIELDINFO(struct be_erx_stats, field) -#define PMEMSTAT_INFO(field) #field, PMEMSTAT,\ - FIELDINFO(struct be_pmem_stats, field) +#define ERXSTAT_INFO(field) #field, ERXSTAT,\ + FIELDINFO(struct be_erx_stats_v1, field) #define DRVSTAT_INFO(field) #field, DRVSTAT,\ FIELDINFO(struct be_drv_stats, \ field) @@ -65,50 +58,41 @@ static const struct be_ethtool_stat et_stats[] = { {DRVSTAT_TX_INFO(be_tx_stops)}, {DRVSTAT_TX_INFO(be_tx_events)}, {DRVSTAT_TX_INFO(be_tx_compl)}, - {PORTSTAT_INFO(rx_unicast_frames)}, - {PORTSTAT_INFO(rx_multicast_frames)}, - {PORTSTAT_INFO(rx_broadcast_frames)}, - {PORTSTAT_INFO(rx_crc_errors)}, - {PORTSTAT_INFO(rx_alignment_symbol_errors)}, - {PORTSTAT_INFO(rx_pause_frames)}, - {PORTSTAT_INFO(rx_control_frames)}, - {PORTSTAT_INFO(rx_in_range_errors)}, - {PORTSTAT_INFO(rx_out_range_errors)}, - {PORTSTAT_INFO(rx_frame_too_long)}, - {PORTSTAT_INFO(rx_address_match_errors)}, - {PORTSTAT_INFO(rx_vlan_mismatch)}, - {PORTSTAT_INFO(rx_dropped_too_small)}, - {PORTSTAT_INFO(rx_dropped_too_short)}, - {PORTSTAT_INFO(rx_dropped_header_too_small)}, - {PORTSTAT_INFO(rx_dropped_tcp_length)}, - {PORTSTAT_INFO(rx_dropped_runt)}, - {PORTSTAT_INFO(rx_fifo_overflow)}, - {PORTSTAT_INFO(rx_input_fifo_overflow)}, - {PORTSTAT_INFO(rx_ip_checksum_errs)}, - {PORTSTAT_INFO(rx_tcp_checksum_errs)}, - {PORTSTAT_INFO(rx_udp_checksum_errs)}, - {PORTSTAT_INFO(rx_non_rss_packets)}, - {PORTSTAT_INFO(rx_ipv4_packets)}, - {PORTSTAT_INFO(rx_ipv6_packets)}, - {PORTSTAT_INFO(rx_switched_unicast_packets)}, - {PORTSTAT_INFO(rx_switched_multicast_packets)}, - {PORTSTAT_INFO(rx_switched_broadcast_packets)}, - {PORTSTAT_INFO(tx_unicastframes)}, - {PORTSTAT_INFO(tx_multicastframes)}, - {PORTSTAT_INFO(tx_broadcastframes)}, - {PORTSTAT_INFO(tx_pauseframes)}, - {PORTSTAT_INFO(tx_controlframes)}, - {MISCSTAT_INFO(rx_drops_no_pbuf)}, - {MISCSTAT_INFO(rx_drops_no_txpb)}, - {MISCSTAT_INFO(rx_drops_no_erx_descr)}, - {MISCSTAT_INFO(rx_drops_no_tpre_descr)}, - {MISCSTAT_INFO(rx_drops_too_many_frags)}, - {MISCSTAT_INFO(rx_drops_invalid_ring)}, - {MISCSTAT_INFO(forwarded_packets)}, - {MISCSTAT_INFO(rx_drops_mtu)}, - {MISCSTAT_INFO(port0_jabber_events)}, - {MISCSTAT_INFO(port1_jabber_events)}, - {PMEMSTAT_INFO(eth_red_drops)}, + {DRVSTAT_INFO(rx_crc_errors)}, + {DRVSTAT_INFO(rx_alignment_symbol_errors)}, + {DRVSTAT_INFO(rx_pause_frames)}, + {DRVSTAT_INFO(rx_control_frames)}, + {DRVSTAT_INFO(rx_in_range_errors)}, + {DRVSTAT_INFO(rx_out_range_errors)}, + {DRVSTAT_INFO(rx_frame_too_long)}, + {DRVSTAT_INFO(rx_address_match_errors)}, + {DRVSTAT_INFO(rx_dropped_too_small)}, + {DRVSTAT_INFO(rx_dropped_too_short)}, + {DRVSTAT_INFO(rx_dropped_header_too_small)}, + {DRVSTAT_INFO(rx_dropped_tcp_length)}, + {DRVSTAT_INFO(rx_dropped_runt)}, + {DRVSTAT_INFO(rxpp_fifo_overflow_drop)}, + {DRVSTAT_INFO(rx_input_fifo_overflow_drop)}, + {DRVSTAT_INFO(rx_ip_checksum_errs)}, + {DRVSTAT_INFO(rx_tcp_checksum_errs)}, + {DRVSTAT_INFO(rx_udp_checksum_errs)}, + {DRVSTAT_INFO(rx_switched_unicast_packets)}, + {DRVSTAT_INFO(rx_switched_multicast_packets)}, + {DRVSTAT_INFO(rx_switched_broadcast_packets)}, + {DRVSTAT_INFO(tx_pauseframes)}, + {DRVSTAT_INFO(tx_controlframes)}, + {DRVSTAT_INFO(rx_priority_pause_frames)}, + {DRVSTAT_INFO(pmem_fifo_overflow_drop)}, + {DRVSTAT_INFO(jabber_events)}, + {DRVSTAT_INFO(rx_drops_no_pbuf)}, + {DRVSTAT_INFO(rx_drops_no_txpb)}, + {DRVSTAT_INFO(rx_drops_no_erx_descr)}, + {DRVSTAT_INFO(rx_drops_no_tpre_descr)}, + {DRVSTAT_INFO(rx_drops_too_many_frags)}, + {DRVSTAT_INFO(rx_drops_invalid_ring)}, + {DRVSTAT_INFO(forwarded_packets)}, + {DRVSTAT_INFO(rx_drops_mtu)}, + {DRVSTAT_INFO(eth_red_drops)}, {DRVSTAT_INFO(be_on_die_temperature)} }; #define ETHTOOL_STATS_NUM ARRAY_SIZE(et_stats) @@ -268,8 +252,6 @@ be_get_ethtool_stats(struct net_device *netdev, struct ethtool_stats *stats, uint64_t *data) { struct be_adapter *adapter = netdev_priv(netdev); - struct be_hw_stats *hw_stats = hw_stats_from_cmd(adapter->stats_cmd.va); - struct be_erx_stats *erx_stats = &hw_stats->erx; struct be_rx_obj *rxo; void *p = NULL; int i, j; @@ -282,15 +264,6 @@ be_get_ethtool_stats(struct net_device *netdev, case DRVSTAT_TX: p = &adapter->tx_stats; break; - case PORTSTAT: - p = &hw_stats->rxf.port[adapter->port_num]; - break; - case MISCSTAT: - p = &hw_stats->rxf; - break; - case PMEMSTAT: - p = &hw_stats->pmem; - break; case DRVSTAT: p = &adapter->drv_stats; break; @@ -308,7 +281,8 @@ be_get_ethtool_stats(struct net_device *netdev, p = (u8 *)&rxo->stats + et_rx_stats[i].offset; break; case ERXSTAT: - p = (u32 *)erx_stats + rxo->q.id; + p = (u32 *)be_erx_stats_from_cmd(adapter) + + rxo->q.id; break; } data[ETHTOOL_STATS_NUM + j * ETHTOOL_RXSTATS_NUM + i] = diff --git a/drivers/net/benet/be_main.c b/drivers/net/benet/be_main.c index 243172b..cff2cca 100644 --- a/drivers/net/benet/be_main.c +++ b/drivers/net/benet/be_main.c @@ -245,14 +245,126 @@ netdev_addr: return status; } +static void populate_be2_stats(struct be_adapter *adapter) +{ + + struct be_drv_stats *drvs = &adapter->drv_stats; + struct be_pmem_stats *pmem_sts = be_pmem_stats_from_cmd(adapter); + struct be_port_rxf_stats_v0 *port_stats = + be_port_rxf_stats_from_cmd(adapter); + struct be_rxf_stats_v0 *rxf_stats = + be_rxf_stats_from_cmd(adapter); + + drvs->rx_pause_frames = port_stats->rx_pause_frames; + drvs->rx_crc_errors = port_stats->rx_crc_errors; + drvs->rx_control_frames = port_stats->rx_control_frames; + drvs->rx_in_range_errors = port_stats->rx_in_range_errors; + drvs->rx_frame_too_long = port_stats->rx_frame_too_long; + drvs->rx_dropped_runt = port_stats->rx_dropped_runt; + drvs->rx_ip_checksum_errs = port_stats->rx_ip_checksum_errs; + drvs->rx_tcp_checksum_errs = port_stats->rx_tcp_checksum_errs; + drvs->rx_udp_checksum_errs = port_stats->rx_udp_checksum_errs; + drvs->rxpp_fifo_overflow_drop = port_stats->rx_fifo_overflow; + drvs->rx_dropped_tcp_length = port_stats->rx_dropped_tcp_length; + drvs->rx_dropped_too_small = port_stats->rx_dropped_too_small; + drvs->rx_dropped_too_short = port_stats->rx_dropped_too_short; + drvs->rx_out_range_errors = port_stats->rx_out_range_errors; + drvs->rx_input_fifo_overflow_drop = + port_stats->rx_input_fifo_overflow; + drvs->rx_dropped_header_too_small = + port_stats->rx_dropped_header_too_small; + drvs->rx_address_match_errors = + port_stats->rx_address_match_errors; + drvs->rx_alignment_symbol_errors = + port_stats->rx_alignment_symbol_errors; + + drvs->tx_pauseframes = port_stats->tx_pauseframes; + drvs->tx_controlframes = port_stats->tx_controlframes; + + if (adapter->port_num) + drvs->jabber_events = + rxf_stats->port1_jabber_events; + else + drvs->jabber_events = + rxf_stats->port0_jabber_events; + drvs->rx_drops_no_pbuf = rxf_stats->rx_drops_no_pbuf; + drvs->rx_drops_no_txpb = rxf_stats->rx_drops_no_txpb; + drvs->rx_drops_no_erx_descr = rxf_stats->rx_drops_no_erx_descr; + drvs->rx_drops_invalid_ring = rxf_stats->rx_drops_invalid_ring; + drvs->forwarded_packets = rxf_stats->forwarded_packets; + drvs->rx_drops_mtu = rxf_stats->rx_drops_mtu; + drvs->rx_drops_no_tpre_descr = + rxf_stats->rx_drops_no_tpre_descr; + drvs->rx_drops_too_many_frags = + rxf_stats->rx_drops_too_many_frags; + adapter->drv_stats.eth_red_drops = pmem_sts->eth_red_drops; +} + +static void populate_be3_stats(struct be_adapter *adapter) +{ + struct be_drv_stats *drvs = &adapter->drv_stats; + struct be_pmem_stats *pmem_sts = be_pmem_stats_from_cmd(adapter); + + struct be_rxf_stats_v1 *rxf_stats = + be_rxf_stats_from_cmd(adapter); + struct be_port_rxf_stats_v1 *port_stats = + be_port_rxf_stats_from_cmd(adapter); + + drvs->rx_priority_pause_frames = 0; + drvs->pmem_fifo_overflow_drop = 0; + drvs->rx_pause_frames = port_stats->rx_pause_frames; + drvs->rx_crc_errors = port_stats->rx_crc_errors; + drvs->rx_control_frames = port_stats->rx_control_frames; + drvs->rx_in_range_errors = port_stats->rx_in_range_errors; + drvs->rx_frame_too_long = port_stats->rx_frame_too_long; + drvs->rx_dropped_runt = port_stats->rx_dropped_runt; + drvs->rx_ip_checksum_errs = port_stats->rx_ip_checksum_errs; + drvs->rx_tcp_checksum_errs = port_stats->rx_tcp_checksum_errs; + drvs->rx_udp_checksum_errs = port_stats->rx_udp_checksum_errs; + drvs->rx_dropped_tcp_length = port_stats->rx_dropped_tcp_length; + drvs->rx_dropped_too_small = port_stats->rx_dropped_too_small; + drvs->rx_dropped_too_short = port_stats->rx_dropped_too_short; + drvs->rx_out_range_errors = port_stats->rx_out_range_errors; + drvs->rx_dropped_header_too_small = + port_stats->rx_dropped_header_too_small; + drvs->rx_input_fifo_overflow_drop = + port_stats->rx_input_fifo_overflow_drop; + drvs->rx_address_match_errors = + port_stats->rx_address_match_errors; + drvs->rx_alignment_symbol_errors = + port_stats->rx_alignment_symbol_errors; + drvs->rxpp_fifo_overflow_drop = + port_stats->rxpp_fifo_overflow_drop; + drvs->tx_pauseframes = port_stats->tx_pauseframes; + drvs->tx_controlframes = port_stats->tx_controlframes; + drvs->jabber_events = port_stats->jabber_events; + drvs->rx_drops_no_pbuf = rxf_stats->rx_drops_no_pbuf; + drvs->rx_drops_no_txpb = rxf_stats->rx_drops_no_txpb; + drvs->rx_drops_no_erx_descr = rxf_stats->rx_drops_no_erx_descr; + drvs->rx_drops_invalid_ring = rxf_stats->rx_drops_invalid_ring; + drvs->forwarded_packets = rxf_stats->forwarded_packets; + drvs->rx_drops_mtu = rxf_stats->rx_drops_mtu; + drvs->rx_drops_no_tpre_descr = + rxf_stats->rx_drops_no_tpre_descr; + drvs->rx_drops_too_many_frags = + rxf_stats->rx_drops_too_many_frags; + adapter->drv_stats.eth_red_drops = pmem_sts->eth_red_drops; +} + + + +void be_parse_stats(struct be_adapter *adapter) +{ + if (adapter->generation == BE_GEN3) + populate_be3_stats(adapter); + else + populate_be2_stats(adapter); +} + void netdev_stats_update(struct be_adapter *adapter) { - struct be_hw_stats *hw_stats = hw_stats_from_cmd(adapter->stats_cmd.va); - struct be_rxf_stats *rxf_stats = &hw_stats->rxf; - struct be_port_rxf_stats *port_stats = - &rxf_stats->port[adapter->port_num]; + struct be_drv_stats *drvs = &adapter->drv_stats; struct net_device_stats *dev_stats = &adapter->netdev->stats; - struct be_erx_stats *erx_stats = &hw_stats->erx; struct be_rx_obj *rxo; int i; @@ -262,43 +374,52 @@ void netdev_stats_update(struct be_adapter *adapter) dev_stats->rx_bytes += rx_stats(rxo)->rx_bytes; dev_stats->multicast += rx_stats(rxo)->rx_mcast_pkts; /* no space in linux buffers: best possible approximation */ - dev_stats->rx_dropped += - erx_stats->rx_drops_no_fragments[rxo->q.id]; + if (adapter->generation == BE_GEN3) { + struct be_erx_stats_v1 *erx_stats = + be_erx_stats_from_cmd(adapter); + dev_stats->rx_dropped += + erx_stats->rx_drops_no_fragments[rxo->q.id]; + } else { + struct be_erx_stats_v0 *erx_stats = + be_erx_stats_from_cmd(adapter); + dev_stats->rx_dropped += + erx_stats->rx_drops_no_fragments[rxo->q.id]; + } } dev_stats->tx_packets = tx_stats(adapter)->be_tx_pkts; dev_stats->tx_bytes = tx_stats(adapter)->be_tx_bytes; /* bad pkts received */ - dev_stats->rx_errors = port_stats->rx_crc_errors + - port_stats->rx_alignment_symbol_errors + - port_stats->rx_in_range_errors + - port_stats->rx_out_range_errors + - port_stats->rx_frame_too_long + - port_stats->rx_dropped_too_small + - port_stats->rx_dropped_too_short + - port_stats->rx_dropped_header_too_small + - port_stats->rx_dropped_tcp_length + - port_stats->rx_dropped_runt + - port_stats->rx_tcp_checksum_errs + - port_stats->rx_ip_checksum_errs + - port_stats->rx_udp_checksum_errs; + dev_stats->rx_errors = drvs->rx_crc_errors + + drvs->rx_alignment_symbol_errors + + drvs->rx_in_range_errors + + drvs->rx_out_range_errors + + drvs->rx_frame_too_long + + drvs->rx_dropped_too_small + + drvs->rx_dropped_too_short + + drvs->rx_dropped_header_too_small + + drvs->rx_dropped_tcp_length + + drvs->rx_dropped_runt + + drvs->rx_tcp_checksum_errs + + drvs->rx_ip_checksum_errs + + drvs->rx_udp_checksum_errs; /* detailed rx errors */ - dev_stats->rx_length_errors = port_stats->rx_in_range_errors + - port_stats->rx_out_range_errors + - port_stats->rx_frame_too_long; + dev_stats->rx_length_errors = drvs->rx_in_range_errors + + drvs->rx_out_range_errors + + drvs->rx_frame_too_long; - dev_stats->rx_crc_errors = port_stats->rx_crc_errors; + dev_stats->rx_crc_errors = drvs->rx_crc_errors; /* frame alignment errors */ - dev_stats->rx_frame_errors = port_stats->rx_alignment_symbol_errors; + dev_stats->rx_frame_errors = drvs->rx_alignment_symbol_errors; /* receiver fifo overrun */ /* drops_no_pbuf is no per i/f, it's per BE card */ - dev_stats->rx_fifo_errors = port_stats->rx_fifo_overflow + - port_stats->rx_input_fifo_overflow + - rxf_stats->rx_drops_no_pbuf; + dev_stats->rx_fifo_errors = drvs->rxpp_fifo_overflow_drop + + drvs->rx_input_fifo_overflow_drop + + drvs->rx_drops_no_pbuf; } void be_link_status_update(struct be_adapter *adapter, bool link_up) @@ -2823,7 +2944,10 @@ static int be_stats_init(struct be_adapter *adapter) { struct be_dma_mem *cmd = &adapter->stats_cmd; - cmd->size = sizeof(struct be_cmd_req_get_stats); + if (adapter->generation == BE_GEN2) + cmd->size = sizeof(struct be_cmd_req_get_stats_v0); + else + cmd->size = sizeof(struct be_cmd_req_get_stats_v1); cmd->va = dma_alloc_coherent(&adapter->pdev->dev, cmd->size, &cmd->dma, GFP_KERNEL); if (cmd->va == NULL) -- cgit v0.10.2 From 005d569600b404cae0b356e3c4085290ecc17775 Mon Sep 17 00:00:00 2001 From: Selvin Xavier Date: Mon, 16 May 2011 07:36:35 +0000 Subject: be2net: Stats for Lancer Added Lancer stats implementation. Signed-off-by: Selvin Xavier Signed-off-by: Padmanabh Ratnakar Signed-off-by: David S. Miller diff --git a/drivers/net/benet/be.h b/drivers/net/benet/be.h index 0da0384..0b73dcf 100644 --- a/drivers/net/benet/be.h +++ b/drivers/net/benet/be.h @@ -244,43 +244,43 @@ struct be_rx_obj { struct be_drv_stats { u8 be_on_die_temperature; - u32 be_tx_events; - u32 eth_red_drops; - u32 rx_drops_no_pbuf; - u32 rx_drops_no_txpb; - u32 rx_drops_no_erx_descr; - u32 rx_drops_no_tpre_descr; - u32 rx_drops_too_many_frags; - u32 rx_drops_invalid_ring; - u32 forwarded_packets; - u32 rx_drops_mtu; - u32 rx_crc_errors; - u32 rx_alignment_symbol_errors; - u32 rx_pause_frames; - u32 rx_priority_pause_frames; - u32 rx_control_frames; - u32 rx_in_range_errors; - u32 rx_out_range_errors; - u32 rx_frame_too_long; - u32 rx_address_match_errors; - u32 rx_dropped_too_small; - u32 rx_dropped_too_short; - u32 rx_dropped_header_too_small; - u32 rx_dropped_tcp_length; - u32 rx_dropped_runt; - u32 rx_ip_checksum_errs; - u32 rx_tcp_checksum_errs; - u32 rx_udp_checksum_errs; - u32 rx_switched_unicast_packets; - u32 rx_switched_multicast_packets; - u32 rx_switched_broadcast_packets; - u32 tx_pauseframes; - u32 tx_priority_pauseframes; - u32 tx_controlframes; - u32 rxpp_fifo_overflow_drop; - u32 rx_input_fifo_overflow_drop; - u32 pmem_fifo_overflow_drop; - u32 jabber_events; + u64 be_tx_events; + u64 eth_red_drops; + u64 rx_drops_no_pbuf; + u64 rx_drops_no_txpb; + u64 rx_drops_no_erx_descr; + u64 rx_drops_no_tpre_descr; + u64 rx_drops_too_many_frags; + u64 rx_drops_invalid_ring; + u64 forwarded_packets; + u64 rx_drops_mtu; + u64 rx_crc_errors; + u64 rx_alignment_symbol_errors; + u64 rx_pause_frames; + u64 rx_priority_pause_frames; + u64 rx_control_frames; + u64 rx_in_range_errors; + u64 rx_out_range_errors; + u64 rx_frame_too_long; + u64 rx_address_match_errors; + u64 rx_dropped_too_small; + u64 rx_dropped_too_short; + u64 rx_dropped_header_too_small; + u64 rx_dropped_tcp_length; + u64 rx_dropped_runt; + u64 rx_ip_checksum_errs; + u64 rx_tcp_checksum_errs; + u64 rx_udp_checksum_errs; + u64 rx_switched_unicast_packets; + u64 rx_switched_multicast_packets; + u64 rx_switched_broadcast_packets; + u64 tx_pauseframes; + u64 tx_priority_pauseframes; + u64 tx_controlframes; + u64 rxpp_fifo_overflow_drop; + u64 rx_input_fifo_overflow_drop; + u64 pmem_fifo_overflow_drop; + u64 jabber_events; }; struct be_vf_cfg { diff --git a/drivers/net/benet/be_cmds.c b/drivers/net/benet/be_cmds.c index 08e0938..aaef0c7 100644 --- a/drivers/net/benet/be_cmds.c +++ b/drivers/net/benet/be_cmds.c @@ -78,14 +78,22 @@ static int be_mcc_compl_process(struct be_adapter *adapter, } if (compl_status == MCC_STATUS_SUCCESS) { - if ((compl->tag0 == OPCODE_ETH_GET_STATISTICS) && + if (((compl->tag0 == OPCODE_ETH_GET_STATISTICS) || + (compl->tag0 == OPCODE_ETH_GET_PPORT_STATS)) && (compl->tag1 == CMD_SUBSYSTEM_ETH)) { if (adapter->generation == BE_GEN3) { - struct be_cmd_resp_get_stats_v1 *resp = + if (lancer_chip(adapter)) { + struct lancer_cmd_resp_pport_stats + *resp = adapter->stats_cmd.va; + be_dws_le_to_cpu(&resp->pport_stats, + sizeof(resp->pport_stats)); + } else { + struct be_cmd_resp_get_stats_v1 *resp = adapter->stats_cmd.va; be_dws_le_to_cpu(&resp->hw_stats, sizeof(resp->hw_stats)); + } } else { struct be_cmd_resp_get_stats_v0 *resp = adapter->stats_cmd.va; @@ -1124,6 +1132,49 @@ err: return status; } +/* Lancer Stats */ +int lancer_cmd_get_pport_stats(struct be_adapter *adapter, + struct be_dma_mem *nonemb_cmd) +{ + + struct be_mcc_wrb *wrb; + struct lancer_cmd_req_pport_stats *req; + struct be_sge *sge; + int status = 0; + + spin_lock_bh(&adapter->mcc_lock); + + wrb = wrb_from_mccq(adapter); + if (!wrb) { + status = -EBUSY; + goto err; + } + req = nonemb_cmd->va; + sge = nonembedded_sgl(wrb); + + be_wrb_hdr_prepare(wrb, nonemb_cmd->size, false, 1, + OPCODE_ETH_GET_PPORT_STATS); + + be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_ETH, + OPCODE_ETH_GET_PPORT_STATS, nonemb_cmd->size); + + + req->cmd_params.params.pport_num = cpu_to_le16(adapter->port_num); + req->cmd_params.params.reset_stats = 0; + + wrb->tag1 = CMD_SUBSYSTEM_ETH; + sge->pa_hi = cpu_to_le32(upper_32_bits(nonemb_cmd->dma)); + sge->pa_lo = cpu_to_le32(nonemb_cmd->dma & 0xFFFFFFFF); + sge->len = cpu_to_le32(nonemb_cmd->size); + + be_mcc_notify(adapter); + adapter->stats_cmd_sent = true; + +err: + spin_unlock_bh(&adapter->mcc_lock); + return status; +} + /* Uses synchronous mcc */ int be_cmd_link_status_query(struct be_adapter *adapter, bool *link_up, u8 *mac_speed, u16 *link_speed, u32 dom) diff --git a/drivers/net/benet/be_cmds.h b/drivers/net/benet/be_cmds.h index bcf816d..9cff226 100644 --- a/drivers/net/benet/be_cmds.h +++ b/drivers/net/benet/be_cmds.h @@ -203,6 +203,7 @@ struct be_mcc_mailbox { #define OPCODE_ETH_TX_DESTROY 9 #define OPCODE_ETH_RX_DESTROY 10 #define OPCODE_ETH_ACPI_WOL_MAGIC_CONFIG 12 +#define OPCODE_ETH_GET_PPORT_STATS 18 #define OPCODE_LOWLEVEL_HOST_DDR_DMA 17 #define OPCODE_LOWLEVEL_LOOPBACK_TEST 18 @@ -688,6 +689,200 @@ struct be_cmd_resp_get_stats_v0 { struct be_hw_stats_v0 hw_stats; }; +#define make_64bit_val(hi_32, lo_32) (((u64)hi_32<<32) | lo_32) +struct lancer_cmd_pport_stats { + u32 tx_packets_lo; + u32 tx_packets_hi; + u32 tx_unicast_packets_lo; + u32 tx_unicast_packets_hi; + u32 tx_multicast_packets_lo; + u32 tx_multicast_packets_hi; + u32 tx_broadcast_packets_lo; + u32 tx_broadcast_packets_hi; + u32 tx_bytes_lo; + u32 tx_bytes_hi; + u32 tx_unicast_bytes_lo; + u32 tx_unicast_bytes_hi; + u32 tx_multicast_bytes_lo; + u32 tx_multicast_bytes_hi; + u32 tx_broadcast_bytes_lo; + u32 tx_broadcast_bytes_hi; + u32 tx_discards_lo; + u32 tx_discards_hi; + u32 tx_errors_lo; + u32 tx_errors_hi; + u32 tx_pause_frames_lo; + u32 tx_pause_frames_hi; + u32 tx_pause_on_frames_lo; + u32 tx_pause_on_frames_hi; + u32 tx_pause_off_frames_lo; + u32 tx_pause_off_frames_hi; + u32 tx_internal_mac_errors_lo; + u32 tx_internal_mac_errors_hi; + u32 tx_control_frames_lo; + u32 tx_control_frames_hi; + u32 tx_packets_64_bytes_lo; + u32 tx_packets_64_bytes_hi; + u32 tx_packets_65_to_127_bytes_lo; + u32 tx_packets_65_to_127_bytes_hi; + u32 tx_packets_128_to_255_bytes_lo; + u32 tx_packets_128_to_255_bytes_hi; + u32 tx_packets_256_to_511_bytes_lo; + u32 tx_packets_256_to_511_bytes_hi; + u32 tx_packets_512_to_1023_bytes_lo; + u32 tx_packets_512_to_1023_bytes_hi; + u32 tx_packets_1024_to_1518_bytes_lo; + u32 tx_packets_1024_to_1518_bytes_hi; + u32 tx_packets_1519_to_2047_bytes_lo; + u32 tx_packets_1519_to_2047_bytes_hi; + u32 tx_packets_2048_to_4095_bytes_lo; + u32 tx_packets_2048_to_4095_bytes_hi; + u32 tx_packets_4096_to_8191_bytes_lo; + u32 tx_packets_4096_to_8191_bytes_hi; + u32 tx_packets_8192_to_9216_bytes_lo; + u32 tx_packets_8192_to_9216_bytes_hi; + u32 tx_lso_packets_lo; + u32 tx_lso_packets_hi; + u32 rx_packets_lo; + u32 rx_packets_hi; + u32 rx_unicast_packets_lo; + u32 rx_unicast_packets_hi; + u32 rx_multicast_packets_lo; + u32 rx_multicast_packets_hi; + u32 rx_broadcast_packets_lo; + u32 rx_broadcast_packets_hi; + u32 rx_bytes_lo; + u32 rx_bytes_hi; + u32 rx_unicast_bytes_lo; + u32 rx_unicast_bytes_hi; + u32 rx_multicast_bytes_lo; + u32 rx_multicast_bytes_hi; + u32 rx_broadcast_bytes_lo; + u32 rx_broadcast_bytes_hi; + u32 rx_unknown_protos; + u32 rsvd_69; /* Word 69 is reserved */ + u32 rx_discards_lo; + u32 rx_discards_hi; + u32 rx_errors_lo; + u32 rx_errors_hi; + u32 rx_crc_errors_lo; + u32 rx_crc_errors_hi; + u32 rx_alignment_errors_lo; + u32 rx_alignment_errors_hi; + u32 rx_symbol_errors_lo; + u32 rx_symbol_errors_hi; + u32 rx_pause_frames_lo; + u32 rx_pause_frames_hi; + u32 rx_pause_on_frames_lo; + u32 rx_pause_on_frames_hi; + u32 rx_pause_off_frames_lo; + u32 rx_pause_off_frames_hi; + u32 rx_frames_too_long_lo; + u32 rx_frames_too_long_hi; + u32 rx_internal_mac_errors_lo; + u32 rx_internal_mac_errors_hi; + u32 rx_undersize_packets; + u32 rx_oversize_packets; + u32 rx_fragment_packets; + u32 rx_jabbers; + u32 rx_control_frames_lo; + u32 rx_control_frames_hi; + u32 rx_control_frames_unknown_opcode_lo; + u32 rx_control_frames_unknown_opcode_hi; + u32 rx_in_range_errors; + u32 rx_out_of_range_errors; + u32 rx_address_match_errors; + u32 rx_vlan_mismatch_errors; + u32 rx_dropped_too_small; + u32 rx_dropped_too_short; + u32 rx_dropped_header_too_small; + u32 rx_dropped_invalid_tcp_length; + u32 rx_dropped_runt; + u32 rx_ip_checksum_errors; + u32 rx_tcp_checksum_errors; + u32 rx_udp_checksum_errors; + u32 rx_non_rss_packets; + u32 rsvd_111; + u32 rx_ipv4_packets_lo; + u32 rx_ipv4_packets_hi; + u32 rx_ipv6_packets_lo; + u32 rx_ipv6_packets_hi; + u32 rx_ipv4_bytes_lo; + u32 rx_ipv4_bytes_hi; + u32 rx_ipv6_bytes_lo; + u32 rx_ipv6_bytes_hi; + u32 rx_nic_packets_lo; + u32 rx_nic_packets_hi; + u32 rx_tcp_packets_lo; + u32 rx_tcp_packets_hi; + u32 rx_iscsi_packets_lo; + u32 rx_iscsi_packets_hi; + u32 rx_management_packets_lo; + u32 rx_management_packets_hi; + u32 rx_switched_unicast_packets_lo; + u32 rx_switched_unicast_packets_hi; + u32 rx_switched_multicast_packets_lo; + u32 rx_switched_multicast_packets_hi; + u32 rx_switched_broadcast_packets_lo; + u32 rx_switched_broadcast_packets_hi; + u32 num_forwards_lo; + u32 num_forwards_hi; + u32 rx_fifo_overflow; + u32 rx_input_fifo_overflow; + u32 rx_drops_too_many_frags_lo; + u32 rx_drops_too_many_frags_hi; + u32 rx_drops_invalid_queue; + u32 rsvd_141; + u32 rx_drops_mtu_lo; + u32 rx_drops_mtu_hi; + u32 rx_packets_64_bytes_lo; + u32 rx_packets_64_bytes_hi; + u32 rx_packets_65_to_127_bytes_lo; + u32 rx_packets_65_to_127_bytes_hi; + u32 rx_packets_128_to_255_bytes_lo; + u32 rx_packets_128_to_255_bytes_hi; + u32 rx_packets_256_to_511_bytes_lo; + u32 rx_packets_256_to_511_bytes_hi; + u32 rx_packets_512_to_1023_bytes_lo; + u32 rx_packets_512_to_1023_bytes_hi; + u32 rx_packets_1024_to_1518_bytes_lo; + u32 rx_packets_1024_to_1518_bytes_hi; + u32 rx_packets_1519_to_2047_bytes_lo; + u32 rx_packets_1519_to_2047_bytes_hi; + u32 rx_packets_2048_to_4095_bytes_lo; + u32 rx_packets_2048_to_4095_bytes_hi; + u32 rx_packets_4096_to_8191_bytes_lo; + u32 rx_packets_4096_to_8191_bytes_hi; + u32 rx_packets_8192_to_9216_bytes_lo; + u32 rx_packets_8192_to_9216_bytes_hi; +}; + +struct pport_stats_params { + u16 pport_num; + u8 rsvd; + u8 reset_stats; +}; + +struct lancer_cmd_req_pport_stats { + struct be_cmd_req_hdr hdr; + union { + struct pport_stats_params params; + u8 rsvd[sizeof(struct lancer_cmd_pport_stats)]; + } cmd_params; +}; + +struct lancer_cmd_resp_pport_stats { + struct be_cmd_resp_hdr hdr; + struct lancer_cmd_pport_stats pport_stats; +}; + +static inline struct lancer_cmd_pport_stats* + pport_stats_from_cmd(struct be_adapter *adapter) +{ + struct lancer_cmd_resp_pport_stats *cmd = adapter->stats_cmd.va; + return &cmd->pport_stats; +} + struct be_cmd_req_get_cntl_addnl_attribs { struct be_cmd_req_hdr hdr; u8 rsvd[8]; @@ -1258,6 +1453,8 @@ extern int be_cmd_link_status_query(struct be_adapter *adapter, extern int be_cmd_reset(struct be_adapter *adapter); extern int be_cmd_get_stats(struct be_adapter *adapter, struct be_dma_mem *nonemb_cmd); +extern int lancer_cmd_get_pport_stats(struct be_adapter *adapter, + struct be_dma_mem *nonemb_cmd); extern int be_cmd_get_fw_ver(struct be_adapter *adapter, char *fw_ver); extern int be_cmd_modify_eqd(struct be_adapter *adapter, u32 eq_id, u32 eqd); diff --git a/drivers/net/benet/be_main.c b/drivers/net/benet/be_main.c index cff2cca..93be84c 100644 --- a/drivers/net/benet/be_main.c +++ b/drivers/net/benet/be_main.c @@ -351,14 +351,73 @@ static void populate_be3_stats(struct be_adapter *adapter) adapter->drv_stats.eth_red_drops = pmem_sts->eth_red_drops; } +static void populate_lancer_stats(struct be_adapter *adapter) +{ + struct be_drv_stats *drvs = &adapter->drv_stats; + struct lancer_cmd_pport_stats *pport_stats = pport_stats_from_cmd + (adapter); + drvs->rx_priority_pause_frames = 0; + drvs->pmem_fifo_overflow_drop = 0; + drvs->rx_pause_frames = + make_64bit_val(pport_stats->rx_pause_frames_lo, + pport_stats->rx_pause_frames_hi); + drvs->rx_crc_errors = make_64bit_val(pport_stats->rx_crc_errors_hi, + pport_stats->rx_crc_errors_lo); + drvs->rx_control_frames = + make_64bit_val(pport_stats->rx_control_frames_hi, + pport_stats->rx_control_frames_lo); + drvs->rx_in_range_errors = pport_stats->rx_in_range_errors; + drvs->rx_frame_too_long = + make_64bit_val(pport_stats->rx_internal_mac_errors_hi, + pport_stats->rx_frames_too_long_lo); + drvs->rx_dropped_runt = pport_stats->rx_dropped_runt; + drvs->rx_ip_checksum_errs = pport_stats->rx_ip_checksum_errors; + drvs->rx_tcp_checksum_errs = pport_stats->rx_tcp_checksum_errors; + drvs->rx_udp_checksum_errs = pport_stats->rx_udp_checksum_errors; + drvs->rx_dropped_tcp_length = + pport_stats->rx_dropped_invalid_tcp_length; + drvs->rx_dropped_too_small = pport_stats->rx_dropped_too_small; + drvs->rx_dropped_too_short = pport_stats->rx_dropped_too_short; + drvs->rx_out_range_errors = pport_stats->rx_out_of_range_errors; + drvs->rx_dropped_header_too_small = + pport_stats->rx_dropped_header_too_small; + drvs->rx_input_fifo_overflow_drop = pport_stats->rx_fifo_overflow; + drvs->rx_address_match_errors = pport_stats->rx_address_match_errors; + drvs->rx_alignment_symbol_errors = + make_64bit_val(pport_stats->rx_symbol_errors_hi, + pport_stats->rx_symbol_errors_lo); + drvs->rxpp_fifo_overflow_drop = pport_stats->rx_fifo_overflow; + drvs->tx_pauseframes = make_64bit_val(pport_stats->tx_pause_frames_hi, + pport_stats->tx_pause_frames_lo); + drvs->tx_controlframes = + make_64bit_val(pport_stats->tx_control_frames_hi, + pport_stats->tx_control_frames_lo); + drvs->jabber_events = pport_stats->rx_jabbers; + drvs->rx_drops_no_pbuf = 0; + drvs->rx_drops_no_txpb = 0; + drvs->rx_drops_no_erx_descr = 0; + drvs->rx_drops_invalid_ring = pport_stats->rx_drops_invalid_queue; + drvs->forwarded_packets = make_64bit_val(pport_stats->num_forwards_hi, + pport_stats->num_forwards_lo); + drvs->rx_drops_mtu = make_64bit_val(pport_stats->rx_drops_mtu_hi, + pport_stats->rx_drops_mtu_lo); + drvs->rx_drops_no_tpre_descr = 0; + drvs->rx_drops_too_many_frags = + make_64bit_val(pport_stats->rx_drops_too_many_frags_hi, + pport_stats->rx_drops_too_many_frags_lo); +} void be_parse_stats(struct be_adapter *adapter) { - if (adapter->generation == BE_GEN3) - populate_be3_stats(adapter); - else + if (adapter->generation == BE_GEN3) { + if (lancer_chip(adapter)) + populate_lancer_stats(adapter); + else + populate_be3_stats(adapter); + } else { populate_be2_stats(adapter); + } } void netdev_stats_update(struct be_adapter *adapter) @@ -375,10 +434,12 @@ void netdev_stats_update(struct be_adapter *adapter) dev_stats->multicast += rx_stats(rxo)->rx_mcast_pkts; /* no space in linux buffers: best possible approximation */ if (adapter->generation == BE_GEN3) { - struct be_erx_stats_v1 *erx_stats = + if (!(lancer_chip(adapter))) { + struct be_erx_stats_v1 *erx_stats = be_erx_stats_from_cmd(adapter); - dev_stats->rx_dropped += + dev_stats->rx_dropped += erx_stats->rx_drops_no_fragments[rxo->q.id]; + } } else { struct be_erx_stats_v0 *erx_stats = be_erx_stats_from_cmd(adapter); @@ -2022,9 +2083,13 @@ static void be_worker(struct work_struct *work) goto reschedule; } - if (!adapter->stats_cmd_sent) - be_cmd_get_stats(adapter, &adapter->stats_cmd); - + if (!adapter->stats_cmd_sent) { + if (lancer_chip(adapter)) + lancer_cmd_get_pport_stats(adapter, + &adapter->stats_cmd); + else + be_cmd_get_stats(adapter, &adapter->stats_cmd); + } be_tx_rate_update(adapter); for_all_rx_queues(adapter, rxo, i) { @@ -2944,10 +3009,14 @@ static int be_stats_init(struct be_adapter *adapter) { struct be_dma_mem *cmd = &adapter->stats_cmd; - if (adapter->generation == BE_GEN2) + if (adapter->generation == BE_GEN2) { cmd->size = sizeof(struct be_cmd_req_get_stats_v0); - else - cmd->size = sizeof(struct be_cmd_req_get_stats_v1); + } else { + if (lancer_chip(adapter)) + cmd->size = sizeof(struct lancer_cmd_req_pport_stats); + else + cmd->size = sizeof(struct be_cmd_req_get_stats_v1); + } cmd->va = dma_alloc_coherent(&adapter->pdev->dev, cmd->size, &cmd->dma, GFP_KERNEL); if (cmd->va == NULL) -- cgit v0.10.2 From 485bf569ba798b4702bc2efbfd3a355fe2c8db04 Mon Sep 17 00:00:00 2001 From: Shripad Nunjundarao Date: Mon, 16 May 2011 07:36:59 +0000 Subject: be2net: FW download for Lancer Added implementation of FW download feature for Lancer. Signed-off-by: Shripad Nunjundarao Signed-off-by: Sevin Xavier Signed-off-by: Padmanabh Ratnakar Signed-off-by: David S. Miller diff --git a/drivers/net/benet/be_cmds.c b/drivers/net/benet/be_cmds.c index aaef0c7..2463b1c 100644 --- a/drivers/net/benet/be_cmds.c +++ b/drivers/net/benet/be_cmds.c @@ -71,7 +71,8 @@ static int be_mcc_compl_process(struct be_adapter *adapter, compl_status = (compl->status >> CQE_STATUS_COMPL_SHIFT) & CQE_STATUS_COMPL_MASK; - if ((compl->tag0 == OPCODE_COMMON_WRITE_FLASHROM) && + if (((compl->tag0 == OPCODE_COMMON_WRITE_FLASHROM) || + (compl->tag0 == OPCODE_COMMON_WRITE_OBJECT)) && (compl->tag1 == CMD_SUBSYSTEM_COMMON)) { adapter->flash_status = compl_status; complete(&adapter->flash_compl); @@ -1801,6 +1802,81 @@ err: return status; } +int lancer_cmd_write_object(struct be_adapter *adapter, struct be_dma_mem *cmd, + u32 data_size, u32 data_offset, const char *obj_name, + u32 *data_written, u8 *addn_status) +{ + struct be_mcc_wrb *wrb; + struct lancer_cmd_req_write_object *req; + struct lancer_cmd_resp_write_object *resp; + void *ctxt = NULL; + int status; + + spin_lock_bh(&adapter->mcc_lock); + adapter->flash_status = 0; + + wrb = wrb_from_mccq(adapter); + if (!wrb) { + status = -EBUSY; + goto err_unlock; + } + + req = embedded_payload(wrb); + + be_wrb_hdr_prepare(wrb, sizeof(struct lancer_cmd_req_write_object), + true, 1, OPCODE_COMMON_WRITE_OBJECT); + wrb->tag1 = CMD_SUBSYSTEM_COMMON; + + be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON, + OPCODE_COMMON_WRITE_OBJECT, + sizeof(struct lancer_cmd_req_write_object)); + + ctxt = &req->context; + AMAP_SET_BITS(struct amap_lancer_write_obj_context, + write_length, ctxt, data_size); + + if (data_size == 0) + AMAP_SET_BITS(struct amap_lancer_write_obj_context, + eof, ctxt, 1); + else + AMAP_SET_BITS(struct amap_lancer_write_obj_context, + eof, ctxt, 0); + + be_dws_cpu_to_le(ctxt, sizeof(req->context)); + req->write_offset = cpu_to_le32(data_offset); + strcpy(req->object_name, obj_name); + req->descriptor_count = cpu_to_le32(1); + req->buf_len = cpu_to_le32(data_size); + req->addr_low = cpu_to_le32((cmd->dma + + sizeof(struct lancer_cmd_req_write_object)) + & 0xFFFFFFFF); + req->addr_high = cpu_to_le32(upper_32_bits(cmd->dma + + sizeof(struct lancer_cmd_req_write_object))); + + be_mcc_notify(adapter); + spin_unlock_bh(&adapter->mcc_lock); + + if (!wait_for_completion_timeout(&adapter->flash_compl, + msecs_to_jiffies(12000))) + status = -1; + else + status = adapter->flash_status; + + resp = embedded_payload(wrb); + if (!status) { + *data_written = le32_to_cpu(resp->actual_write_len); + } else { + *addn_status = resp->additional_status; + status = resp->status; + } + + return status; + +err_unlock: + spin_unlock_bh(&adapter->mcc_lock); + return status; +} + int be_cmd_write_flashrom(struct be_adapter *adapter, struct be_dma_mem *cmd, u32 flash_type, u32 flash_opcode, u32 buf_size) { diff --git a/drivers/net/benet/be_cmds.h b/drivers/net/benet/be_cmds.h index 9cff226..8148cc6 100644 --- a/drivers/net/benet/be_cmds.h +++ b/drivers/net/benet/be_cmds.h @@ -193,6 +193,7 @@ struct be_mcc_mailbox { #define OPCODE_COMMON_GET_PHY_DETAILS 102 #define OPCODE_COMMON_SET_DRIVER_FUNCTION_CAP 103 #define OPCODE_COMMON_GET_CNTL_ADDITIONAL_ATTRIBUTES 121 +#define OPCODE_COMMON_WRITE_OBJECT 172 #define OPCODE_ETH_RSS_CONFIG 1 #define OPCODE_ETH_ACPI_CONFIG 2 @@ -1131,6 +1132,36 @@ struct be_cmd_write_flashrom { struct flashrom_params params; }; +/**************** Lancer Firmware Flash ************/ +struct amap_lancer_write_obj_context { + u8 write_length[24]; + u8 reserved1[7]; + u8 eof; +} __packed; + +struct lancer_cmd_req_write_object { + struct be_cmd_req_hdr hdr; + u8 context[sizeof(struct amap_lancer_write_obj_context) / 8]; + u32 write_offset; + u8 object_name[104]; + u32 descriptor_count; + u32 buf_len; + u32 addr_low; + u32 addr_high; +}; + +struct lancer_cmd_resp_write_object { + u8 opcode; + u8 subsystem; + u8 rsvd1[2]; + u8 status; + u8 additional_status; + u8 rsvd2[2]; + u32 resp_len; + u32 actual_resp_len; + u32 actual_write_len; +}; + /************************ WOL *******************************/ struct be_cmd_req_acpi_wol_magic_config{ struct be_cmd_req_hdr hdr; @@ -1481,6 +1512,11 @@ extern int be_cmd_get_beacon_state(struct be_adapter *adapter, extern int be_cmd_write_flashrom(struct be_adapter *adapter, struct be_dma_mem *cmd, u32 flash_oper, u32 flash_opcode, u32 buf_size); +extern int lancer_cmd_write_object(struct be_adapter *adapter, + struct be_dma_mem *cmd, + u32 data_size, u32 data_offset, + const char *obj_name, + u32 *data_written, u8 *addn_status); int be_cmd_get_flash_crc(struct be_adapter *adapter, u8 *flashed_crc, int offset); extern int be_cmd_enable_magic_wol(struct be_adapter *adapter, u8 *mac, diff --git a/drivers/net/benet/be_main.c b/drivers/net/benet/be_main.c index 93be84c..7322a51 100644 --- a/drivers/net/benet/be_main.c +++ b/drivers/net/benet/be_main.c @@ -2712,7 +2712,6 @@ static int be_flash_data(struct be_adapter *adapter, "cmd to write to flash rom failed.\n"); return -1; } - yield(); } } return 0; @@ -2730,32 +2729,98 @@ static int get_ufigen_type(struct flash_file_hdr_g2 *fhdr) return 0; } -int be_load_fw(struct be_adapter *adapter, u8 *func) +static int lancer_fw_download(struct be_adapter *adapter, + const struct firmware *fw) { - char fw_file[ETHTOOL_FLASH_MAX_FILENAME]; - const struct firmware *fw; - struct flash_file_hdr_g2 *fhdr; - struct flash_file_hdr_g3 *fhdr3; - struct image_hdr *img_hdr_ptr = NULL; +#define LANCER_FW_DOWNLOAD_CHUNK (32 * 1024) +#define LANCER_FW_DOWNLOAD_LOCATION "/prg" struct be_dma_mem flash_cmd; - int status, i = 0, num_imgs = 0; - const u8 *p; + struct lancer_cmd_req_write_object *req; + const u8 *data_ptr = NULL; + u8 *dest_image_ptr = NULL; + size_t image_size = 0; + u32 chunk_size = 0; + u32 data_written = 0; + u32 offset = 0; + int status = 0; + u8 add_status = 0; - if (!netif_running(adapter->netdev)) { + if (!IS_ALIGNED(fw->size, sizeof(u32))) { dev_err(&adapter->pdev->dev, - "Firmware load not allowed (interface is down)\n"); - return -EPERM; + "FW Image not properly aligned. " + "Length must be 4 byte aligned.\n"); + status = -EINVAL; + goto lancer_fw_exit; } - strcpy(fw_file, func); + flash_cmd.size = sizeof(struct lancer_cmd_req_write_object) + + LANCER_FW_DOWNLOAD_CHUNK; + flash_cmd.va = dma_alloc_coherent(&adapter->pdev->dev, flash_cmd.size, + &flash_cmd.dma, GFP_KERNEL); + if (!flash_cmd.va) { + status = -ENOMEM; + dev_err(&adapter->pdev->dev, + "Memory allocation failure while flashing\n"); + goto lancer_fw_exit; + } - status = request_firmware(&fw, fw_file, &adapter->pdev->dev); - if (status) - goto fw_exit; + req = flash_cmd.va; + dest_image_ptr = flash_cmd.va + + sizeof(struct lancer_cmd_req_write_object); + image_size = fw->size; + data_ptr = fw->data; + + while (image_size) { + chunk_size = min_t(u32, image_size, LANCER_FW_DOWNLOAD_CHUNK); + + /* Copy the image chunk content. */ + memcpy(dest_image_ptr, data_ptr, chunk_size); + + status = lancer_cmd_write_object(adapter, &flash_cmd, + chunk_size, offset, LANCER_FW_DOWNLOAD_LOCATION, + &data_written, &add_status); + + if (status) + break; + + offset += data_written; + data_ptr += data_written; + image_size -= data_written; + } + + if (!status) { + /* Commit the FW written */ + status = lancer_cmd_write_object(adapter, &flash_cmd, + 0, offset, LANCER_FW_DOWNLOAD_LOCATION, + &data_written, &add_status); + } + + dma_free_coherent(&adapter->pdev->dev, flash_cmd.size, flash_cmd.va, + flash_cmd.dma); + if (status) { + dev_err(&adapter->pdev->dev, + "Firmware load error. " + "Status code: 0x%x Additional Status: 0x%x\n", + status, add_status); + goto lancer_fw_exit; + } + + dev_info(&adapter->pdev->dev, "Firmware flashed successfully\n"); +lancer_fw_exit: + return status; +} + +static int be_fw_download(struct be_adapter *adapter, const struct firmware* fw) +{ + struct flash_file_hdr_g2 *fhdr; + struct flash_file_hdr_g3 *fhdr3; + struct image_hdr *img_hdr_ptr = NULL; + struct be_dma_mem flash_cmd; + const u8 *p; + int status = 0, i = 0, num_imgs = 0; p = fw->data; fhdr = (struct flash_file_hdr_g2 *) p; - dev_info(&adapter->pdev->dev, "Flashing firmware file %s\n", fw_file); flash_cmd.size = sizeof(struct be_cmd_write_flashrom) + 32*1024; flash_cmd.va = dma_alloc_coherent(&adapter->pdev->dev, flash_cmd.size, @@ -2764,7 +2829,7 @@ int be_load_fw(struct be_adapter *adapter, u8 *func) status = -ENOMEM; dev_err(&adapter->pdev->dev, "Memory allocation failure while flashing\n"); - goto fw_exit; + goto be_fw_exit; } if ((adapter->generation == BE_GEN3) && @@ -2792,11 +2857,37 @@ int be_load_fw(struct be_adapter *adapter, u8 *func) flash_cmd.dma); if (status) { dev_err(&adapter->pdev->dev, "Firmware load error\n"); - goto fw_exit; + goto be_fw_exit; } dev_info(&adapter->pdev->dev, "Firmware flashed successfully\n"); +be_fw_exit: + return status; +} + +int be_load_fw(struct be_adapter *adapter, u8 *fw_file) +{ + const struct firmware *fw; + int status; + + if (!netif_running(adapter->netdev)) { + dev_err(&adapter->pdev->dev, + "Firmware load not allowed (interface is down)\n"); + return -1; + } + + status = request_firmware(&fw, fw_file, &adapter->pdev->dev); + if (status) + goto fw_exit; + + dev_info(&adapter->pdev->dev, "Flashing firmware file %s\n", fw_file); + + if (lancer_chip(adapter)) + status = lancer_fw_download(adapter, fw); + else + status = be_fw_download(adapter, fw); + fw_exit: release_firmware(fw); return status; -- cgit v0.10.2 From 600b776eb39a13a28b090ba9efceb0c69d4508aa Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Mon, 16 May 2011 20:15:36 +0200 Subject: OMAP1 / PM: Use generic clock manipulation routines for runtime PM Convert OMAP1 to using the new generic clock manipulation routines and a device power domain for runtime PM instead of overriding the platform bus type's runtime PM callbacks. This allows us to simplify OMAP1-specific code and to share some code with other platforms (shmobile in particular). Signed-off-by: Rafael J. Wysocki Acked-by: Kevin Hilman diff --git a/arch/arm/mach-omap1/pm_bus.c b/arch/arm/mach-omap1/pm_bus.c index 6588c22..fe31d93 100644 --- a/arch/arm/mach-omap1/pm_bus.c +++ b/arch/arm/mach-omap1/pm_bus.c @@ -24,75 +24,50 @@ #ifdef CONFIG_PM_RUNTIME static int omap1_pm_runtime_suspend(struct device *dev) { - struct clk *iclk, *fclk; - int ret = 0; + int ret; dev_dbg(dev, "%s\n", __func__); ret = pm_generic_runtime_suspend(dev); + if (ret) + return ret; - fclk = clk_get(dev, "fck"); - if (!IS_ERR(fclk)) { - clk_disable(fclk); - clk_put(fclk); - } - - iclk = clk_get(dev, "ick"); - if (!IS_ERR(iclk)) { - clk_disable(iclk); - clk_put(iclk); + ret = pm_runtime_clk_suspend(dev); + if (ret) { + pm_generic_runtime_resume(dev); + return ret; } return 0; -}; +} static int omap1_pm_runtime_resume(struct device *dev) { - struct clk *iclk, *fclk; - dev_dbg(dev, "%s\n", __func__); - iclk = clk_get(dev, "ick"); - if (!IS_ERR(iclk)) { - clk_enable(iclk); - clk_put(iclk); - } + pm_runtime_clk_resume(dev); + return pm_generic_runtime_resume(dev); +} - fclk = clk_get(dev, "fck"); - if (!IS_ERR(fclk)) { - clk_enable(fclk); - clk_put(fclk); - } +static struct dev_power_domain default_power_domain = { + .ops = { + .runtime_suspend = omap1_pm_runtime_suspend, + .runtime_resume = omap1_pm_runtime_resume, + USE_PLATFORM_PM_SLEEP_OPS + }, +}; - return pm_generic_runtime_resume(dev); +static struct pm_clk_notifier_block platform_bus_notifier = { + .pwr_domain = &default_power_domain, + .con_ids = { "ick", "fck", NULL, }, }; static int __init omap1_pm_runtime_init(void) { - const struct dev_pm_ops *pm; - struct dev_pm_ops *omap_pm; - if (!cpu_class_is_omap1()) return -ENODEV; - pm = platform_bus_get_pm_ops(); - if (!pm) { - pr_err("%s: unable to get dev_pm_ops from platform_bus\n", - __func__); - return -ENODEV; - } - - omap_pm = kmemdup(pm, sizeof(struct dev_pm_ops), GFP_KERNEL); - if (!omap_pm) { - pr_err("%s: unable to alloc memory for new dev_pm_ops\n", - __func__); - return -ENOMEM; - } - - omap_pm->runtime_suspend = omap1_pm_runtime_suspend; - omap_pm->runtime_resume = omap1_pm_runtime_resume; - - platform_bus_set_pm_ops(omap_pm); + pm_runtime_clk_add_notifier(&platform_bus_type, &platform_bus_notifier); return 0; } -- cgit v0.10.2 From 2064af917b3ba7589070064ca4ed12cecd99a63c Mon Sep 17 00:00:00 2001 From: Kevin Hilman Date: Fri, 29 Apr 2011 00:37:26 +0200 Subject: PM: Revert "driver core: platform_bus: allow runtime override of dev_pm_ops" The platform_bus_set_pm_ops() operation is deprecated in favor of the new device power domain infrastructre implemented in commit 7538e3db6e015e890825fbd9f8659952896ddd5b (PM: add support for device power domains) Signed-off-by: Kevin Hilman Signed-off-by: Rafael J. Wysocki diff --git a/drivers/base/platform.c b/drivers/base/platform.c index 079c18a..48425f1 100644 --- a/drivers/base/platform.c +++ b/drivers/base/platform.c @@ -916,41 +916,6 @@ struct bus_type platform_bus_type = { }; EXPORT_SYMBOL_GPL(platform_bus_type); -/** - * platform_bus_get_pm_ops() - return pointer to busses dev_pm_ops - * - * This function can be used by platform code to get the current - * set of dev_pm_ops functions used by the platform_bus_type. - */ -const struct dev_pm_ops * __init platform_bus_get_pm_ops(void) -{ - return platform_bus_type.pm; -} - -/** - * platform_bus_set_pm_ops() - update dev_pm_ops for the platform_bus_type - * - * @pm: pointer to new dev_pm_ops struct to be used for platform_bus_type - * - * Platform code can override the dev_pm_ops methods of - * platform_bus_type by using this function. It is expected that - * platform code will first do a platform_bus_get_pm_ops(), then - * kmemdup it, then customize selected methods and pass a pointer to - * the new struct dev_pm_ops to this function. - * - * Since platform-specific code is customizing methods for *all* - * devices (not just platform-specific devices) it is expected that - * any custom overrides of these functions will keep existing behavior - * and simply extend it. For example, any customization of the - * runtime PM methods should continue to call the pm_generic_* - * functions as the default ones do in addition to the - * platform-specific behavior. - */ -void __init platform_bus_set_pm_ops(const struct dev_pm_ops *pm) -{ - platform_bus_type.pm = pm; -} - int __init platform_bus_init(void) { int error; diff --git a/include/linux/platform_device.h b/include/linux/platform_device.h index e0093e0..ede1a80 100644 --- a/include/linux/platform_device.h +++ b/include/linux/platform_device.h @@ -150,9 +150,6 @@ extern struct platform_device *platform_create_bundle(struct platform_driver *dr struct resource *res, unsigned int n_res, const void *data, size_t size); -extern const struct dev_pm_ops * platform_bus_get_pm_ops(void); -extern void platform_bus_set_pm_ops(const struct dev_pm_ops *pm); - /* early platform driver interface */ struct early_platform_driver { const char *class_str; -- cgit v0.10.2 From 72874daa5e9064c4e8d689e6a04b1e96f687f872 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Tue, 3 May 2011 19:45:32 +0200 Subject: PM: Fix build issue in clock_ops.c for CONFIG_PM_RUNTIME unset Fix a build issue in drivers/base/power/clock_ops.c occuring when CONFIG_PM_RUNTIME is not set. Signed-off-by: Rafael J. Wysocki diff --git a/drivers/base/power/clock_ops.c b/drivers/base/power/clock_ops.c index d74abf3..c0dd09d 100644 --- a/drivers/base/power/clock_ops.c +++ b/drivers/base/power/clock_ops.c @@ -380,6 +380,7 @@ static int pm_runtime_clk_notify(struct notifier_block *nb, { struct pm_clk_notifier_block *clknb; struct device *dev = data; + char *con_id; dev_dbg(dev, "%s() %ld\n", __func__, action); -- cgit v0.10.2 From 50e7534427283afd997d58481778c07bea79eb63 Mon Sep 17 00:00:00 2001 From: Borislav Petkov Date: Mon, 16 May 2011 15:39:46 +0200 Subject: x86, AMD, cacheinfo: Fix fallout caused by max3 conversion 732eacc0542d0aa48797f675888b85d6065af837 converted code around the kernel using nested max() macros to use the new max3 macro but forgot to remove the old line in intel_cacheinfo.c. Fix it. Cc: Hagen Paul Pfeifer Cc: Frank Arnold Signed-off-by: Borislav Petkov Link: http://lkml.kernel.org/r/1305553188-21061-2-git-send-email-bp@amd64.org Signed-off-by: H. Peter Anvin diff --git a/arch/x86/kernel/cpu/intel_cacheinfo.c b/arch/x86/kernel/cpu/intel_cacheinfo.c index 1ce1af28..31590a0 100644 --- a/arch/x86/kernel/cpu/intel_cacheinfo.c +++ b/arch/x86/kernel/cpu/intel_cacheinfo.c @@ -327,7 +327,6 @@ static void __cpuinit amd_calc_l3_indices(struct amd_l3_cache *l3) l3->subcaches[2] = sc2 = !(val & BIT(8)) + !(val & BIT(9)); l3->subcaches[3] = sc3 = !(val & BIT(12)) + !(val & BIT(13)); - l3->indices = (max(max(max(sc0, sc1), sc2), sc3) << 10) - 1; l3->indices = (max(max3(sc0, sc1, sc2), sc3) << 10) - 1; } -- cgit v0.10.2 From 42be450565b0fc4607fae3e3a7da038d367a23ed Mon Sep 17 00:00:00 2001 From: Frank Arnold Date: Mon, 16 May 2011 15:39:47 +0200 Subject: x86, AMD, cacheinfo: Fix L3 cache index disable checks We provide two slots to disable cache indices, and have a check to prevent both slots to be used for the same index. If the user disables the same index on different subcaches, both slots will hold the same index, e.g. $ echo 2047 > /sys/devices/system/cpu/cpu0/cache/index3/cache_disable_0 $ cat /sys/devices/system/cpu/cpu0/cache/index3/cache_disable_0 2047 $ echo 1050623 > /sys/devices/system/cpu/cpu0/cache/index3/cache_disable_1 $ cat /sys/devices/system/cpu/cpu0/cache/index3/cache_disable_1 2047 due to the fact that the check was looking only at index bits [11:0] and was ignoring writes to bits outside that range. The more correct fix is to simply check whether the index is within the bounds of [0..l3->indices]. While at it, cleanup comments and drop now-unused local macros. Signed-off-by: Frank Arnold Link: http://lkml.kernel.org/r/1305553188-21061-3-git-send-email-bp@amd64.org Signed-off-by: Borislav Petkov Signed-off-by: H. Peter Anvin diff --git a/arch/x86/kernel/cpu/intel_cacheinfo.c b/arch/x86/kernel/cpu/intel_cacheinfo.c index 31590a0..c105c53 100644 --- a/arch/x86/kernel/cpu/intel_cacheinfo.c +++ b/arch/x86/kernel/cpu/intel_cacheinfo.c @@ -453,27 +453,16 @@ int amd_set_l3_disable_slot(struct amd_l3_cache *l3, int cpu, unsigned slot, { int ret = 0; -#define SUBCACHE_MASK (3UL << 20) -#define SUBCACHE_INDEX 0xfff - - /* - * check whether this slot is already used or - * the index is already disabled - */ + /* check if @slot is already used or the index is already disabled */ ret = amd_get_l3_disable_slot(l3, slot); if (ret >= 0) return -EINVAL; - /* - * check whether the other slot has disabled the - * same index already - */ - if (index == amd_get_l3_disable_slot(l3, !slot)) + if (index > l3->indices) return -EINVAL; - /* do not allow writes outside of allowed bits */ - if ((index & ~(SUBCACHE_MASK | SUBCACHE_INDEX)) || - ((index & SUBCACHE_INDEX) > l3->indices)) + /* check whether the other slot has disabled the same index already */ + if (index == amd_get_l3_disable_slot(l3, !slot)) return -EINVAL; amd_l3_disable_index(l3, cpu, slot, index); -- cgit v0.10.2 From eecaaba5b2e4ae762b4726fae2e3b22630e137ec Mon Sep 17 00:00:00 2001 From: Borislav Petkov Date: Mon, 16 May 2011 15:39:48 +0200 Subject: Documentation, ABI: Update L3 cache index disable text Change contact person to AMD kernel mailing list, update text and external references, drop "Users:" tag. Cc: Randy Dunlap Signed-off-by: Borislav Petkov Link: http://lkml.kernel.org/r/1305553188-21061-4-git-send-email-bp@amd64.org Acked-by: Greg Kroah-Hartman Signed-off-by: H. Peter Anvin diff --git a/Documentation/ABI/testing/sysfs-devices-system-cpu b/Documentation/ABI/testing/sysfs-devices-system-cpu index 7564e88..e7be75b 100644 --- a/Documentation/ABI/testing/sysfs-devices-system-cpu +++ b/Documentation/ABI/testing/sysfs-devices-system-cpu @@ -183,21 +183,21 @@ Description: Discover and change clock speed of CPUs to learn how to control the knobs. -What: /sys/devices/system/cpu/cpu*/cache/index*/cache_disable_X -Date: August 2008 +What: /sys/devices/system/cpu/cpu*/cache/index3/cache_disable_{0,1} +Date: August 2008 KernelVersion: 2.6.27 -Contact: mark.langsdorf@amd.com -Description: These files exist in every cpu's cache index directories. - There are currently 2 cache_disable_# files in each - directory. Reading from these files on a supported - processor will return that cache disable index value - for that processor and node. Writing to one of these - files will cause the specificed cache index to be disabled. - - Currently, only AMD Family 10h Processors support cache index - disable, and only for their L3 caches. See the BIOS and - Kernel Developer's Guide at - http://support.amd.com/us/Embedded_TechDocs/31116-Public-GH-BKDG_3-28_5-28-09.pdf - for formatting information and other details on the - cache index disable. -Users: joachim.deguara@amd.com +Contact: discuss@x86-64.org +Description: Disable L3 cache indices + + These files exist in every CPU's cache/index3 directory. Each + cache_disable_{0,1} file corresponds to one disable slot which + can be used to disable a cache index. Reading from these files + on a processor with this functionality will return the currently + disabled index for that node. There is one L3 structure per + node, or per internal node on MCM machines. Writing a valid + index to one of these files will cause the specificed cache + index to be disabled. + + All AMD processors with L3 caches provide this functionality. + For details, see BKDGs at + http://developer.amd.com/documentation/guides/Pages/default.aspx -- cgit v0.10.2 From dd5477ff3ba978892014ea5f988cb1bf04aa505e Mon Sep 17 00:00:00 2001 From: Steven Rostedt Date: Wed, 6 Apr 2011 13:21:17 -0400 Subject: ftrace/trivial: Clean up recordmcount.c to use Linux style comparisons The Linux ftrace subsystem style for comparing is: var == 1 var > 0 and not: 1 == var 0 < var It is considered that Linux developers are smart enough not to do the if (var = 1) mistake. Cc: John Reiser Link: http://lkml.kernel.org/r/20110421023737.290712238@goodmis.org Signed-off-by: Steven Rostedt diff --git a/scripts/recordmcount.c b/scripts/recordmcount.c index f9f6f52..37afe0e 100644 --- a/scripts/recordmcount.c +++ b/scripts/recordmcount.c @@ -78,7 +78,7 @@ static off_t ulseek(int const fd, off_t const offset, int const whence) { off_t const w = lseek(fd, offset, whence); - if ((off_t)-1 == w) { + if (w == (off_t)-1) { perror("lseek"); fail_file(); } @@ -111,7 +111,7 @@ static void * umalloc(size_t size) { void *const addr = malloc(size); - if (0 == addr) { + if (addr == 0) { fprintf(stderr, "malloc failed: %zu bytes\n", size); fail_file(); } @@ -136,7 +136,7 @@ static void *mmap_file(char const *fname) void *addr; fd_map = open(fname, O_RDWR); - if (0 > fd_map || 0 > fstat(fd_map, &sb)) { + if (fd_map < 0 || fstat(fd_map, &sb) < 0) { perror(fname); fail_file(); } @@ -147,7 +147,7 @@ static void *mmap_file(char const *fname) addr = mmap(0, sb.st_size, PROT_READ|PROT_WRITE, MAP_PRIVATE, fd_map, 0); mmap_failed = 0; - if (MAP_FAILED == addr) { + if (addr == MAP_FAILED) { mmap_failed = 1; addr = umalloc(sb.st_size); uread(fd_map, addr, sb.st_size); @@ -206,12 +206,12 @@ static uint32_t (*w2)(uint16_t); static int is_mcounted_section_name(char const *const txtname) { - return 0 == strcmp(".text", txtname) || - 0 == strcmp(".ref.text", txtname) || - 0 == strcmp(".sched.text", txtname) || - 0 == strcmp(".spinlock.text", txtname) || - 0 == strcmp(".irqentry.text", txtname) || - 0 == strcmp(".text.unlikely", txtname); + return strcmp(".text", txtname) == 0 || + strcmp(".ref.text", txtname) == 0 || + strcmp(".sched.text", txtname) == 0 || + strcmp(".spinlock.text", txtname) == 0 || + strcmp(".irqentry.text", txtname) == 0 || + strcmp(".text.unlikely", txtname) == 0; } /* 32 bit and 64 bit are very similar */ @@ -270,7 +270,7 @@ do_file(char const *const fname) fail_file(); } break; case ELFDATA2LSB: { - if (1 != *(unsigned char const *)&endian) { + if (*(unsigned char const *)&endian != 1) { /* main() is big endian, file.o is little endian. */ w = w4rev; w2 = w2rev; @@ -278,7 +278,7 @@ do_file(char const *const fname) } } break; case ELFDATA2MSB: { - if (0 != *(unsigned char const *)&endian) { + if (*(unsigned char const *)&endian != 0) { /* main() is little endian, file.o is big endian. */ w = w4rev; w2 = w2rev; @@ -286,9 +286,9 @@ do_file(char const *const fname) } } break; } /* end switch */ - if (0 != memcmp(ELFMAG, ehdr->e_ident, SELFMAG) - || ET_REL != w2(ehdr->e_type) - || EV_CURRENT != ehdr->e_ident[EI_VERSION]) { + if (memcmp(ELFMAG, ehdr->e_ident, SELFMAG) != 0 + || w2(ehdr->e_type) != ET_REL + || ehdr->e_ident[EI_VERSION] != EV_CURRENT) { fprintf(stderr, "unrecognized ET_REL file %s\n", fname); fail_file(); } @@ -321,15 +321,15 @@ do_file(char const *const fname) fail_file(); } break; case ELFCLASS32: { - if (sizeof(Elf32_Ehdr) != w2(ehdr->e_ehsize) - || sizeof(Elf32_Shdr) != w2(ehdr->e_shentsize)) { + if (w2(ehdr->e_ehsize) != sizeof(Elf32_Ehdr) + || w2(ehdr->e_shentsize) != sizeof(Elf32_Shdr)) { fprintf(stderr, "unrecognized ET_REL file: %s\n", fname); fail_file(); } - if (EM_S390 == w2(ehdr->e_machine)) + if (w2(ehdr->e_machine) == EM_S390) reltype = R_390_32; - if (EM_MIPS == w2(ehdr->e_machine)) { + if (w2(ehdr->e_machine) == EM_MIPS) { reltype = R_MIPS_32; is_fake_mcount32 = MIPS32_is_fake_mcount; } @@ -337,15 +337,15 @@ do_file(char const *const fname) } break; case ELFCLASS64: { Elf64_Ehdr *const ghdr = (Elf64_Ehdr *)ehdr; - if (sizeof(Elf64_Ehdr) != w2(ghdr->e_ehsize) - || sizeof(Elf64_Shdr) != w2(ghdr->e_shentsize)) { + if (w2(ghdr->e_ehsize) != sizeof(Elf64_Ehdr) + || w2(ghdr->e_shentsize) != sizeof(Elf64_Shdr)) { fprintf(stderr, "unrecognized ET_REL file: %s\n", fname); fail_file(); } - if (EM_S390 == w2(ghdr->e_machine)) + if (w2(ghdr->e_machine) == EM_S390) reltype = R_390_64; - if (EM_MIPS == w2(ghdr->e_machine)) { + if (w2(ghdr->e_machine) == EM_MIPS) { reltype = R_MIPS_64; Elf64_r_sym = MIPS64_r_sym; Elf64_r_info = MIPS64_r_info; @@ -371,7 +371,7 @@ main(int argc, char const *argv[]) } /* Process each file in turn, allowing deep failure. */ - for (--argc, ++argv; 0 < argc; --argc, ++argv) { + for (--argc, ++argv; argc > 0; --argc, ++argv) { int const sjval = setjmp(jmpenv); int len; diff --git a/scripts/recordmcount.h b/scripts/recordmcount.h index baf187b..ac7b330 100644 --- a/scripts/recordmcount.h +++ b/scripts/recordmcount.h @@ -275,12 +275,12 @@ static uint_t *sift_rel_mcount(uint_t *mlocp, Elf_Sym const *const symp = &sym0[Elf_r_sym(relp)]; char const *symname = &str0[w(symp->st_name)]; - char const *mcount = '_' == gpfx ? "_mcount" : "mcount"; + char const *mcount = gpfx == '_' ? "_mcount" : "mcount"; - if ('.' == symname[0]) + if (symname[0] == '.') ++symname; /* ppc64 hack */ - if (0 == strcmp(mcount, symname) || - (altmcount && 0 == strcmp(altmcount, symname))) + if (strcmp(mcount, symname) == 0 || + (altmcount && strcmp(altmcount, symname) == 0)) mcountsym = Elf_r_sym(relp); } @@ -290,7 +290,7 @@ static uint_t *sift_rel_mcount(uint_t *mlocp, mrelp->r_offset = _w(offbase + ((void *)mlocp - (void *)mloc0)); Elf_r_info(mrelp, recsym, reltype); - if (sizeof(Elf_Rela) == rel_entsize) { + if (rel_entsize == sizeof(Elf_Rela)) { ((Elf_Rela *)mrelp)->r_addend = addend; *mlocp++ = 0; } else @@ -354,12 +354,12 @@ __has_rel_mcount(Elf_Shdr const *const relhdr, /* is SHT_REL or SHT_RELA */ Elf_Shdr const *const txthdr = &shdr0[w(relhdr->sh_info)]; char const *const txtname = &shstrtab[w(txthdr->sh_name)]; - if (0 == strcmp("__mcount_loc", txtname)) { + if (strcmp("__mcount_loc", txtname) == 0) { fprintf(stderr, "warning: __mcount_loc already exists: %s\n", fname); succeed_file(); } - if (SHT_PROGBITS != w(txthdr->sh_type) || + if (w(txthdr->sh_type) != SHT_PROGBITS || !is_mcounted_section_name(txtname)) return NULL; return txtname; @@ -370,7 +370,7 @@ static char const *has_rel_mcount(Elf_Shdr const *const relhdr, char const *const shstrtab, char const *const fname) { - if (SHT_REL != w(relhdr->sh_type) && SHT_RELA != w(relhdr->sh_type)) + if (w(relhdr->sh_type) != SHT_REL && w(relhdr->sh_type) != SHT_RELA) return NULL; return __has_rel_mcount(relhdr, shdr0, shstrtab, fname); } -- cgit v0.10.2 From e90b0c8bf211958a296d60369fecd51b35864407 Mon Sep 17 00:00:00 2001 From: Steven Rostedt Date: Wed, 6 Apr 2011 13:32:24 -0400 Subject: ftrace/trivial: Clean up record mcount to use Linux switch style The Linux style for switch statements is: switch (var) { case x: [...] break; } Not: switch (var) { case x: { [...] } break; Cc: John Reiser Link: http://lkml.kernel.org/r/20110421023737.523968644@goodmis.org Signed-off-by: Steven Rostedt diff --git a/scripts/recordmcount.c b/scripts/recordmcount.c index 37afe0e..4ebd839 100644 --- a/scripts/recordmcount.c +++ b/scripts/recordmcount.c @@ -264,27 +264,27 @@ do_file(char const *const fname) w8 = w8nat; switch (ehdr->e_ident[EI_DATA]) { static unsigned int const endian = 1; - default: { + default: fprintf(stderr, "unrecognized ELF data encoding %d: %s\n", ehdr->e_ident[EI_DATA], fname); fail_file(); - } break; - case ELFDATA2LSB: { + break; + case ELFDATA2LSB: if (*(unsigned char const *)&endian != 1) { /* main() is big endian, file.o is little endian. */ w = w4rev; w2 = w2rev; w8 = w8rev; } - } break; - case ELFDATA2MSB: { + break; + case ELFDATA2MSB: if (*(unsigned char const *)&endian != 0) { /* main() is little endian, file.o is big endian. */ w = w4rev; w2 = w2rev; w8 = w8rev; } - } break; + break; } /* end switch */ if (memcmp(ELFMAG, ehdr->e_ident, SELFMAG) != 0 || w2(ehdr->e_type) != ET_REL @@ -295,11 +295,11 @@ do_file(char const *const fname) gpfx = 0; switch (w2(ehdr->e_machine)) { - default: { + default: fprintf(stderr, "unrecognized e_machine %d %s\n", w2(ehdr->e_machine), fname); fail_file(); - } break; + break; case EM_386: reltype = R_386_32; break; case EM_ARM: reltype = R_ARM_ABS32; altmcount = "__gnu_mcount_nc"; @@ -315,12 +315,12 @@ do_file(char const *const fname) } /* end switch */ switch (ehdr->e_ident[EI_CLASS]) { - default: { + default: fprintf(stderr, "unrecognized ELF class %d %s\n", ehdr->e_ident[EI_CLASS], fname); fail_file(); - } break; - case ELFCLASS32: { + break; + case ELFCLASS32: if (w2(ehdr->e_ehsize) != sizeof(Elf32_Ehdr) || w2(ehdr->e_shentsize) != sizeof(Elf32_Shdr)) { fprintf(stderr, @@ -334,7 +334,7 @@ do_file(char const *const fname) is_fake_mcount32 = MIPS32_is_fake_mcount; } do32(ehdr, fname, reltype); - } break; + break; case ELFCLASS64: { Elf64_Ehdr *const ghdr = (Elf64_Ehdr *)ehdr; if (w2(ghdr->e_ehsize) != sizeof(Elf64_Ehdr) @@ -352,7 +352,8 @@ do_file(char const *const fname) is_fake_mcount64 = MIPS64_is_fake_mcount; } do64(ghdr, fname, reltype); - } break; + break; + } } /* end switch */ cleanup(); @@ -386,23 +387,23 @@ main(int argc, char const *argv[]) continue; switch (sjval) { - default: { + default: fprintf(stderr, "internal error: %s\n", argv[0]); exit(1); - } break; - case SJ_SETJMP: { /* normal sequence */ + break; + case SJ_SETJMP: /* normal sequence */ /* Avoid problems if early cleanup() */ fd_map = -1; ehdr_curr = NULL; mmap_failed = 1; do_file(argv[0]); - } break; - case SJ_FAIL: { /* error in do_file or below */ + break; + case SJ_FAIL: /* error in do_file or below */ ++n_error; - } break; - case SJ_SUCCEED: { /* premature success */ + break; + case SJ_SUCCEED: /* premature success */ /* do nothing */ - } break; + break; } /* end switch */ } return !!n_error; -- cgit v0.10.2 From 9f087e7612115b7a201d4f3392a95ac7408948ab Mon Sep 17 00:00:00 2001 From: Steven Rostedt Date: Wed, 6 Apr 2011 14:10:22 -0400 Subject: ftrace: Add .kprobe.text section to whitelist for recordmcount.c The .kprobe.text section is safe to modify mcount to nop and tracing. Add it to the whitelist in recordmcount.c and recordmcount.pl. Cc: John Reiser Cc: Masami Hiramatsu Link: http://lkml.kernel.org/r/20110421023737.743350547@goodmis.org Signed-off-by: Steven Rostedt diff --git a/scripts/recordmcount.c b/scripts/recordmcount.c index 4ebd839..37c5965 100644 --- a/scripts/recordmcount.c +++ b/scripts/recordmcount.c @@ -211,6 +211,7 @@ is_mcounted_section_name(char const *const txtname) strcmp(".sched.text", txtname) == 0 || strcmp(".spinlock.text", txtname) == 0 || strcmp(".irqentry.text", txtname) == 0 || + strcmp(".kprobes.text", txtname) == 0 || strcmp(".text.unlikely", txtname) == 0; } diff --git a/scripts/recordmcount.pl b/scripts/recordmcount.pl index 4be0dee..a871cd4 100755 --- a/scripts/recordmcount.pl +++ b/scripts/recordmcount.pl @@ -134,6 +134,7 @@ my %text_sections = ( ".sched.text" => 1, ".spinlock.text" => 1, ".irqentry.text" => 1, + ".kprobes.text" => 1, ".text.unlikely" => 1, ); -- cgit v0.10.2 From 8abd5724a7f1631ab2276954156c629d4d17149a Mon Sep 17 00:00:00 2001 From: Steven Rostedt Date: Wed, 13 Apr 2011 13:31:08 -0400 Subject: ftrace/recordmcount: Modify only executable sections PROGBITS is not enough to determine if the section should be modified or not. Only process sections that are marked as executable. Cc: John Reiser Link: http://lkml.kernel.org/r/20110421023737.991485123@goodmis.org Signed-off-by: Steven Rostedt diff --git a/scripts/recordmcount.h b/scripts/recordmcount.h index ac7b330..7f8d5c4 100644 --- a/scripts/recordmcount.h +++ b/scripts/recordmcount.h @@ -360,6 +360,7 @@ __has_rel_mcount(Elf_Shdr const *const relhdr, /* is SHT_REL or SHT_RELA */ succeed_file(); } if (w(txthdr->sh_type) != SHT_PROGBITS || + !(w(txthdr->sh_flags) & SHF_EXECINSTR) || !is_mcounted_section_name(txtname)) return NULL; return txtname; -- cgit v0.10.2 From ffd618fa39284f8cc343894b566dd42ec6e74e77 Mon Sep 17 00:00:00 2001 From: Steven Rostedt Date: Fri, 8 Apr 2011 03:58:48 -0400 Subject: ftrace/recordmcount: Make ignored mcount calls into nops at compile time There are sections that are ignored by ftrace for the function tracing because the text is in a section that can be removed without notice. The mcount calls in these sections are ignored and ftrace never sees them. The downside of this is that the functions in these sections still call mcount. Although the mcount function is defined in assembly simply as a return, this added overhead is unnecessary. The solution is to convert these callers into nops at compile time. A better solution is to add 'notrace' to the section markers, but as new sections come up all the time, it would be nice that they are delt with when they are created. Later patches will deal with finding these sections and doing the proper solution. Thanks to H. Peter Anvin for giving me the right nops to use for x86. Cc: "H. Peter Anvin" Cc: John Reiser Link: http://lkml.kernel.org/r/20110421023738.237101176@goodmis.org Signed-off-by: Steven Rostedt diff --git a/scripts/recordmcount.c b/scripts/recordmcount.c index 37c5965..78054a4 100644 --- a/scripts/recordmcount.c +++ b/scripts/recordmcount.c @@ -118,6 +118,34 @@ umalloc(size_t size) return addr; } +static unsigned char ideal_nop5_x86_64[5] = { 0x0f, 0x1f, 0x44, 0x00, 0x00 }; +static unsigned char ideal_nop5_x86_32[5] = { 0x3e, 0x8d, 0x74, 0x26, 0x00 }; +static unsigned char *ideal_nop; + +static char rel_type_nop; + +static int (*make_nop)(void *map, size_t const offset); + +static int make_nop_x86(void *map, size_t const offset) +{ + uint32_t *ptr; + unsigned char *op; + + /* Confirm we have 0xe8 0x0 0x0 0x0 0x0 */ + ptr = map + offset; + if (*ptr != 0) + return -1; + + op = map + offset - 1; + if (*op != 0xe8) + return -1; + + /* convert to nop */ + ulseek(fd_map, offset - 1, SEEK_SET); + uwrite(fd_map, ideal_nop, 5); + return 0; +} + /* * Get the whole file as a programming convenience in order to avoid * malloc+lseek+read+free of many pieces. If successful, then mmap @@ -301,7 +329,11 @@ do_file(char const *const fname) w2(ehdr->e_machine), fname); fail_file(); break; - case EM_386: reltype = R_386_32; break; + case EM_386: + reltype = R_386_32; + make_nop = make_nop_x86; + ideal_nop = ideal_nop5_x86_32; + break; case EM_ARM: reltype = R_ARM_ABS32; altmcount = "__gnu_mcount_nc"; break; @@ -312,7 +344,11 @@ do_file(char const *const fname) case EM_S390: /* reltype: e_class */ gpfx = '_'; break; case EM_SH: reltype = R_SH_DIR32; break; case EM_SPARCV9: reltype = R_SPARC_64; gpfx = '_'; break; - case EM_X86_64: reltype = R_X86_64_64; break; + case EM_X86_64: + make_nop = make_nop_x86; + ideal_nop = ideal_nop5_x86_64; + reltype = R_X86_64_64; + break; } /* end switch */ switch (ehdr->e_ident[EI_CLASS]) { diff --git a/scripts/recordmcount.h b/scripts/recordmcount.h index 7f8d5c4..657dbed 100644 --- a/scripts/recordmcount.h +++ b/scripts/recordmcount.h @@ -23,6 +23,7 @@ #undef fn_is_fake_mcount #undef MIPS_is_fake_mcount #undef sift_rel_mcount +#undef nop_mcount #undef find_secsym_ndx #undef __has_rel_mcount #undef has_rel_mcount @@ -49,6 +50,7 @@ #ifdef RECORD_MCOUNT_64 # define append_func append64 # define sift_rel_mcount sift64_rel_mcount +# define nop_mcount nop_mcount_64 # define find_secsym_ndx find64_secsym_ndx # define __has_rel_mcount __has64_rel_mcount # define has_rel_mcount has64_rel_mcount @@ -77,6 +79,7 @@ #else # define append_func append32 # define sift_rel_mcount sift32_rel_mcount +# define nop_mcount nop_mcount_32 # define find_secsym_ndx find32_secsym_ndx # define __has_rel_mcount __has32_rel_mcount # define has_rel_mcount has32_rel_mcount @@ -304,6 +307,70 @@ static uint_t *sift_rel_mcount(uint_t *mlocp, return mlocp; } +/* + * Read the relocation table again, but this time its called on sections + * that are not going to be traced. The mcount calls here will be converted + * into nops. + */ +static void nop_mcount(Elf_Shdr const *const relhdr, + Elf_Ehdr const *const ehdr) +{ + Elf_Shdr *const shdr0 = (Elf_Shdr *)(_w(ehdr->e_shoff) + + (void *)ehdr); + unsigned const symsec_sh_link = w(relhdr->sh_link); + Elf_Shdr const *const symsec = &shdr0[symsec_sh_link]; + Elf_Sym const *const sym0 = (Elf_Sym const *)(_w(symsec->sh_offset) + + (void *)ehdr); + + Elf_Shdr const *const strsec = &shdr0[w(symsec->sh_link)]; + char const *const str0 = (char const *)(_w(strsec->sh_offset) + + (void *)ehdr); + + Elf_Rel const *const rel0 = (Elf_Rel const *)(_w(relhdr->sh_offset) + + (void *)ehdr); + unsigned rel_entsize = _w(relhdr->sh_entsize); + unsigned const nrel = _w(relhdr->sh_size) / rel_entsize; + Elf_Rel const *relp = rel0; + + Elf_Shdr const *const shdr = &shdr0[w(relhdr->sh_info)]; + + unsigned mcountsym = 0; + unsigned t; + + for (t = nrel; t; --t) { + int ret = -1; + + if (!mcountsym) { + Elf_Sym const *const symp = + &sym0[Elf_r_sym(relp)]; + char const *symname = &str0[w(symp->st_name)]; + char const *mcount = gpfx == '_' ? "_mcount" : "mcount"; + + if (symname[0] == '.') + ++symname; /* ppc64 hack */ + if (strcmp(mcount, symname) == 0 || + (altmcount && strcmp(altmcount, symname) == 0)) + mcountsym = Elf_r_sym(relp); + } + + if (mcountsym == Elf_r_sym(relp) && !is_fake_mcount(relp)) + ret = make_nop((void *)ehdr, shdr->sh_offset + relp->r_offset); + + /* + * If we successfully removed the mcount, mark the relocation + * as a nop (don't do anything with it). + */ + if (!ret) { + Elf_Rel rel; + rel = *(Elf_Rel *)relp; + Elf_r_info(&rel, Elf_r_sym(relp), rel_type_nop); + ulseek(fd_map, (void *)relp - (void *)ehdr, SEEK_SET); + uwrite(fd_map, &rel, sizeof(rel)); + } + relp = (Elf_Rel const *)(rel_entsize + (void *)relp); + } +} + /* * Find a symbol in the given section, to be used as the base for relocating @@ -360,8 +427,7 @@ __has_rel_mcount(Elf_Shdr const *const relhdr, /* is SHT_REL or SHT_RELA */ succeed_file(); } if (w(txthdr->sh_type) != SHT_PROGBITS || - !(w(txthdr->sh_flags) & SHF_EXECINSTR) || - !is_mcounted_section_name(txtname)) + !(w(txthdr->sh_flags) & SHF_EXECINSTR)) return NULL; return txtname; } @@ -384,9 +450,11 @@ static unsigned tot_relsize(Elf_Shdr const *const shdr0, { unsigned totrelsz = 0; Elf_Shdr const *shdrp = shdr0; + char const *txtname; for (; nhdr; --nhdr, ++shdrp) { - if (has_rel_mcount(shdrp, shdr0, shstrtab, fname)) + txtname = has_rel_mcount(shdrp, shdr0, shstrtab, fname); + if (txtname && is_mcounted_section_name(txtname)) totrelsz += _w(shdrp->sh_size); } return totrelsz; @@ -422,7 +490,7 @@ do_func(Elf_Ehdr *const ehdr, char const *const fname, unsigned const reltype) for (relhdr = shdr0, k = nhdr; k; --k, ++relhdr) { char const *const txtname = has_rel_mcount(relhdr, shdr0, shstrtab, fname); - if (txtname) { + if (txtname && is_mcounted_section_name(txtname)) { uint_t recval = 0; unsigned const recsym = find_secsym_ndx( w(relhdr->sh_info), txtname, &recval, @@ -433,6 +501,12 @@ do_func(Elf_Ehdr *const ehdr, char const *const fname, unsigned const reltype) mlocp = sift_rel_mcount(mlocp, (void *)mlocp - (void *)mloc0, &mrelp, relhdr, ehdr, recsym, recval, reltype); + } else if (make_nop && txtname) { + /* + * This section is ignored by ftrace, but still + * has mcount calls. Convert them to nops now. + */ + nop_mcount(relhdr, ehdr); } } if (mloc0 != mlocp) { -- cgit v0.10.2 From dfad3d598c4bbbaf137588e22bac1ce624529f7e Mon Sep 17 00:00:00 2001 From: Steven Rostedt Date: Tue, 12 Apr 2011 18:53:25 -0400 Subject: ftrace/recordmcount: Add warning logic to warn on mcount not recorded There's some sections that should not have mcount recorded and should not have modifications to the that code. But currently they waste some time by calling mcount anyway (which simply returns). As the real answer should be to either whitelist the section or have gcc ignore it fully. This change adds a option to recordmcount to warn when it finds a section that is ignored by ftrace but still contains mcount callers. This is not on by default as developers may not know if the section should be completely ignored or added to the whitelist. Cc: John Reiser Link: http://lkml.kernel.org/r/20110421023738.476989377@goodmis.org Signed-off-by: Steven Rostedt diff --git a/scripts/recordmcount.c b/scripts/recordmcount.c index 78054a4..0e18975 100644 --- a/scripts/recordmcount.c +++ b/scripts/recordmcount.c @@ -24,6 +24,7 @@ #include #include #include +#include #include #include #include @@ -39,6 +40,7 @@ static char gpfx; /* prefix for global symbol name (sometimes '_') */ static struct stat sb; /* Remember .st_size, etc. */ static jmp_buf jmpenv; /* setjmp/longjmp per-file error escape */ static const char *altmcount; /* alternate mcount symbol name */ +static int warn_on_notrace_sect; /* warn when section has mcount not being recorded */ /* setjmp() return values */ enum { @@ -397,19 +399,33 @@ do_file(char const *const fname) } int -main(int argc, char const *argv[]) +main(int argc, char *argv[]) { const char ftrace[] = "/ftrace.o"; int ftrace_size = sizeof(ftrace) - 1; int n_error = 0; /* gcc-4.3.0 false positive complaint */ + int c; + int i; - if (argc <= 1) { - fprintf(stderr, "usage: recordmcount file.o...\n"); + while ((c = getopt(argc, argv, "w")) >= 0) { + switch (c) { + case 'w': + warn_on_notrace_sect = 1; + break; + default: + fprintf(stderr, "usage: recordmcount [-w] file.o...\n"); + return 0; + } + } + + if ((argc - optind) < 1) { + fprintf(stderr, "usage: recordmcount [-w] file.o...\n"); return 0; } /* Process each file in turn, allowing deep failure. */ - for (--argc, ++argv; argc > 0; --argc, ++argv) { + for (i = optind; i < argc; i++) { + char *file = argv[i]; int const sjval = setjmp(jmpenv); int len; @@ -418,14 +434,14 @@ main(int argc, char const *argv[]) * function but does not call it. Since ftrace.o should * not be traced anyway, we just skip it. */ - len = strlen(argv[0]); + len = strlen(file); if (len >= ftrace_size && - strcmp(argv[0] + (len - ftrace_size), ftrace) == 0) + strcmp(file + (len - ftrace_size), ftrace) == 0) continue; switch (sjval) { default: - fprintf(stderr, "internal error: %s\n", argv[0]); + fprintf(stderr, "internal error: %s\n", file); exit(1); break; case SJ_SETJMP: /* normal sequence */ @@ -433,7 +449,7 @@ main(int argc, char const *argv[]) fd_map = -1; ehdr_curr = NULL; mmap_failed = 1; - do_file(argv[0]); + do_file(file); break; case SJ_FAIL: /* error in do_file or below */ ++n_error; diff --git a/scripts/recordmcount.h b/scripts/recordmcount.h index 657dbed..22033d5 100644 --- a/scripts/recordmcount.h +++ b/scripts/recordmcount.h @@ -313,7 +313,8 @@ static uint_t *sift_rel_mcount(uint_t *mlocp, * into nops. */ static void nop_mcount(Elf_Shdr const *const relhdr, - Elf_Ehdr const *const ehdr) + Elf_Ehdr const *const ehdr, + const char *const txtname) { Elf_Shdr *const shdr0 = (Elf_Shdr *)(_w(ehdr->e_shoff) + (void *)ehdr); @@ -336,6 +337,7 @@ static void nop_mcount(Elf_Shdr const *const relhdr, unsigned mcountsym = 0; unsigned t; + int once = 0; for (t = nrel; t; --t) { int ret = -1; @@ -353,8 +355,18 @@ static void nop_mcount(Elf_Shdr const *const relhdr, mcountsym = Elf_r_sym(relp); } - if (mcountsym == Elf_r_sym(relp) && !is_fake_mcount(relp)) - ret = make_nop((void *)ehdr, shdr->sh_offset + relp->r_offset); + if (mcountsym == Elf_r_sym(relp) && !is_fake_mcount(relp)) { + if (make_nop) + ret = make_nop((void *)ehdr, shdr->sh_offset + relp->r_offset); + if (warn_on_notrace_sect && !once) { + printf("Section %s has mcount callers being ignored\n", + txtname); + once = 1; + /* just warn? */ + if (!make_nop) + return; + } + } /* * If we successfully removed the mcount, mark the relocation @@ -501,12 +513,12 @@ do_func(Elf_Ehdr *const ehdr, char const *const fname, unsigned const reltype) mlocp = sift_rel_mcount(mlocp, (void *)mlocp - (void *)mloc0, &mrelp, relhdr, ehdr, recsym, recval, reltype); - } else if (make_nop && txtname) { + } else if (txtname && (warn_on_notrace_sect || make_nop)) { /* * This section is ignored by ftrace, but still * has mcount calls. Convert them to nops now. */ - nop_mcount(relhdr, ehdr); + nop_mcount(relhdr, ehdr, txtname); } } if (mloc0 != mlocp) { -- cgit v0.10.2 From 85356f802225fedeee8c3e65bdd93b263ace0a8b Mon Sep 17 00:00:00 2001 From: Steven Rostedt Date: Tue, 12 Apr 2011 18:59:10 -0400 Subject: kbuild/recordmcount: Add RECORDMCOUNT_WARN to warn about mcount callers When mcount is called in a section that ftrace will not modify it into a nop, we want to warn about this. But not warn about this always. Now if the user builds the kernel with the option RECORDMCOUNT_WARN=1 then the build will warn about mcount callers that are ignored and will just waste execution time. Acked-by: Michal Marek Cc: linux-kbuild@vger.kernel.org Link: http://lkml.kernel.org/r/20110421023738.714956282@goodmis.org Signed-off-by: Steven Rostedt diff --git a/Makefile b/Makefile index 41ea6fb..e7d01ada 100644 --- a/Makefile +++ b/Makefile @@ -1268,6 +1268,7 @@ help: @echo ' make C=1 [targets] Check all c source with $$CHECK (sparse by default)' @echo ' make C=2 [targets] Force check of all c source with $$CHECK' @echo ' make W=1 [targets] Enable extra gcc checks' + @echo ' make RECORDMCOUNT_WARN=1 [targets] Warn about ignored mcount sections' @echo '' @echo 'Execute "make" or "make all" to build all targets marked with [*] ' @echo 'For further info see the ./README file' diff --git a/scripts/Makefile.build b/scripts/Makefile.build index d5f925a..fdca952 100644 --- a/scripts/Makefile.build +++ b/scripts/Makefile.build @@ -244,13 +244,16 @@ endif ifdef CONFIG_FTRACE_MCOUNT_RECORD ifdef BUILD_C_RECORDMCOUNT +ifeq ("$(origin RECORDMCOUNT_WARN)", "command line") + RECORDMCOUNT_FLAGS = -w +endif # Due to recursion, we must skip empty.o. # The empty.o file is created in the make process in order to determine # the target endianness and word size. It is made before all other C # files, including recordmcount. sub_cmd_record_mcount = \ if [ $(@) != "scripts/mod/empty.o" ]; then \ - $(objtree)/scripts/recordmcount "$(@)"; \ + $(objtree)/scripts/recordmcount $(RECORDMCOUNT_FLAGS) "$(@)"; \ fi; else sub_cmd_record_mcount = set -e ; perl $(srctree)/scripts/recordmcount.pl "$(ARCH)" \ -- cgit v0.10.2 From f0201738b61b1adcf6b2c4719c5c415745014c1c Mon Sep 17 00:00:00 2001 From: Steven Rostedt Date: Tue, 12 Apr 2011 19:06:39 -0400 Subject: ftrace: Avoid recording mcount on .init sections directly The init and exit sections should not be traced and adding a call to mcount to them is a waste of text and instruction cache. Have the macro section attributes include notrace to ignore these functions for tracing from the build. Link: http://lkml.kernel.org/r/20110421023738.953028219@goodmis.org Signed-off-by: Steven Rostedt diff --git a/include/linux/init.h b/include/linux/init.h index 577671c..9146f39 100644 --- a/include/linux/init.h +++ b/include/linux/init.h @@ -79,29 +79,29 @@ #define __exitused __used #endif -#define __exit __section(.exit.text) __exitused __cold +#define __exit __section(.exit.text) __exitused __cold notrace /* Used for HOTPLUG */ -#define __devinit __section(.devinit.text) __cold +#define __devinit __section(.devinit.text) __cold notrace #define __devinitdata __section(.devinit.data) #define __devinitconst __section(.devinit.rodata) -#define __devexit __section(.devexit.text) __exitused __cold +#define __devexit __section(.devexit.text) __exitused __cold notrace #define __devexitdata __section(.devexit.data) #define __devexitconst __section(.devexit.rodata) /* Used for HOTPLUG_CPU */ -#define __cpuinit __section(.cpuinit.text) __cold +#define __cpuinit __section(.cpuinit.text) __cold notrace #define __cpuinitdata __section(.cpuinit.data) #define __cpuinitconst __section(.cpuinit.rodata) -#define __cpuexit __section(.cpuexit.text) __exitused __cold +#define __cpuexit __section(.cpuexit.text) __exitused __cold notrace #define __cpuexitdata __section(.cpuexit.data) #define __cpuexitconst __section(.cpuexit.rodata) /* Used for MEMORY_HOTPLUG */ -#define __meminit __section(.meminit.text) __cold +#define __meminit __section(.meminit.text) __cold notrace #define __meminitdata __section(.meminit.data) #define __meminitconst __section(.meminit.rodata) -#define __memexit __section(.memexit.text) __exitused __cold +#define __memexit __section(.memexit.text) __exitused __cold notrace #define __memexitdata __section(.memexit.data) #define __memexitconst __section(.memexit.rodata) -- cgit v0.10.2 From 2895cd2ab81dfb7bc22637bc110857db44a30b4a Mon Sep 17 00:00:00 2001 From: Steven Rostedt Date: Wed, 13 Apr 2011 16:43:29 -0400 Subject: ftrace/x86: Do not trace .discard.text section The section called .discard.text has tracing attached to it and is currently ignored by ftrace. But it does include a call to the mcount stub. Adding a notrace to the code keeps gcc from adding the useless mcount caller to it. Link: http://lkml.kernel.org/r/20110421023739.243651696@goodmis.org Signed-off-by: Steven Rostedt diff --git a/arch/x86/include/asm/setup.h b/arch/x86/include/asm/setup.h index db8aa19..647d8a0 100644 --- a/arch/x86/include/asm/setup.h +++ b/arch/x86/include/asm/setup.h @@ -88,7 +88,7 @@ void *extend_brk(size_t size, size_t align); * executable.) */ #define RESERVE_BRK(name,sz) \ - static void __section(.discard.text) __used \ + static void __section(.discard.text) __used notrace \ __brk_reservation_fn_##name##__(void) { \ asm volatile ( \ ".pushsection .brk_reservation,\"aw\",@nobits;" \ -- cgit v0.10.2 From 37762cb9977626343b3cd1aab9146313c94748c2 Mon Sep 17 00:00:00 2001 From: Steven Rostedt Date: Wed, 20 Apr 2011 20:47:34 -0400 Subject: ftrace/recordmcount: Remove duplicate code to find mcount symbol The code in sift_rel_mcount() and nop_mcount() to get the mcount symbol number is identical. Replace the two locations with a call to a function that does the work. Cc: John Reiser Link: http://lkml.kernel.org/r/20110421023739.488093407@goodmis.org Signed-off-by: Steven Rostedt diff --git a/scripts/recordmcount.h b/scripts/recordmcount.h index 22033d5..deb6a51 100644 --- a/scripts/recordmcount.h +++ b/scripts/recordmcount.h @@ -28,6 +28,7 @@ #undef __has_rel_mcount #undef has_rel_mcount #undef tot_relsize +#undef get_mcountsym #undef do_func #undef Elf_Addr #undef Elf_Ehdr @@ -56,6 +57,7 @@ # define has_rel_mcount has64_rel_mcount # define tot_relsize tot64_relsize # define do_func do64 +# define get_mcountsym get_mcountsym_64 # define is_fake_mcount is_fake_mcount64 # define fn_is_fake_mcount fn_is_fake_mcount64 # define MIPS_is_fake_mcount MIPS64_is_fake_mcount @@ -85,6 +87,7 @@ # define has_rel_mcount has32_rel_mcount # define tot_relsize tot32_relsize # define do_func do32 +# define get_mcountsym get_mcountsym_32 # define is_fake_mcount is_fake_mcount32 # define fn_is_fake_mcount fn_is_fake_mcount32 # define MIPS_is_fake_mcount MIPS32_is_fake_mcount @@ -237,6 +240,26 @@ static void append_func(Elf_Ehdr *const ehdr, uwrite(fd_map, ehdr, sizeof(*ehdr)); } +static unsigned get_mcountsym(Elf_Sym const *const sym0, + Elf_Rel const *relp, + char const *const str0) +{ + unsigned mcountsym = 0; + + Elf_Sym const *const symp = + &sym0[Elf_r_sym(relp)]; + char const *symname = &str0[w(symp->st_name)]; + char const *mcount = gpfx == '_' ? "_mcount" : "mcount"; + + if (symname[0] == '.') + ++symname; /* ppc64 hack */ + if (strcmp(mcount, symname) == 0 || + (altmcount && strcmp(altmcount, symname) == 0)) + mcountsym = Elf_r_sym(relp); + + return mcountsym; +} + /* * Look at the relocations in order to find the calls to mcount. * Accumulate the section offsets that are found, and their relocation info, @@ -274,18 +297,8 @@ static uint_t *sift_rel_mcount(uint_t *mlocp, unsigned t; for (t = nrel; t; --t) { - if (!mcountsym) { - Elf_Sym const *const symp = - &sym0[Elf_r_sym(relp)]; - char const *symname = &str0[w(symp->st_name)]; - char const *mcount = gpfx == '_' ? "_mcount" : "mcount"; - - if (symname[0] == '.') - ++symname; /* ppc64 hack */ - if (strcmp(mcount, symname) == 0 || - (altmcount && strcmp(altmcount, symname) == 0)) - mcountsym = Elf_r_sym(relp); - } + if (!mcountsym) + mcountsym = get_mcountsym(sym0, relp, str0); if (mcountsym == Elf_r_sym(relp) && !is_fake_mcount(relp)) { uint_t const addend = _w(_w(relp->r_offset) - recval); @@ -342,18 +355,8 @@ static void nop_mcount(Elf_Shdr const *const relhdr, for (t = nrel; t; --t) { int ret = -1; - if (!mcountsym) { - Elf_Sym const *const symp = - &sym0[Elf_r_sym(relp)]; - char const *symname = &str0[w(symp->st_name)]; - char const *mcount = gpfx == '_' ? "_mcount" : "mcount"; - - if (symname[0] == '.') - ++symname; /* ppc64 hack */ - if (strcmp(mcount, symname) == 0 || - (altmcount && strcmp(altmcount, symname) == 0)) - mcountsym = Elf_r_sym(relp); - } + if (!mcountsym) + mcountsym = get_mcountsym(sym0, relp, str0); if (mcountsym == Elf_r_sym(relp) && !is_fake_mcount(relp)) { if (make_nop) -- cgit v0.10.2 From 41b402a201a12efdff4acc990e023a89a409cd41 Mon Sep 17 00:00:00 2001 From: Steven Rostedt Date: Wed, 20 Apr 2011 21:13:06 -0400 Subject: ftrace/recordmcount: Add helper function get_sym_str_and_relp() The code to get the symbol, string, and relp pointers in the two functions sift_rel_mcount() and nop_mcount() are identical and also non-trivial. Moving this duplicate code into a single helper function makes the code easier to read and more maintainable. Cc: John Reiser Link: http://lkml.kernel.org/r/20110421023739.723658553@goodmis.org Signed-off-by: Steven Rostedt diff --git a/scripts/recordmcount.h b/scripts/recordmcount.h index deb6a51..3c00fab 100644 --- a/scripts/recordmcount.h +++ b/scripts/recordmcount.h @@ -29,6 +29,7 @@ #undef has_rel_mcount #undef tot_relsize #undef get_mcountsym +#undef get_sym_str_and_relp #undef do_func #undef Elf_Addr #undef Elf_Ehdr @@ -56,6 +57,7 @@ # define __has_rel_mcount __has64_rel_mcount # define has_rel_mcount has64_rel_mcount # define tot_relsize tot64_relsize +# define get_sym_str_and_relp get_sym_str_and_relp_64 # define do_func do64 # define get_mcountsym get_mcountsym_64 # define is_fake_mcount is_fake_mcount64 @@ -86,6 +88,7 @@ # define __has_rel_mcount __has32_rel_mcount # define has_rel_mcount has32_rel_mcount # define tot_relsize tot32_relsize +# define get_sym_str_and_relp get_sym_str_and_relp_32 # define do_func do32 # define get_mcountsym get_mcountsym_32 # define is_fake_mcount is_fake_mcount32 @@ -260,6 +263,29 @@ static unsigned get_mcountsym(Elf_Sym const *const sym0, return mcountsym; } +static void get_sym_str_and_relp(Elf_Shdr const *const relhdr, + Elf_Ehdr const *const ehdr, + Elf_Sym const **sym0, + char const **str0, + Elf_Rel const **relp) +{ + Elf_Shdr *const shdr0 = (Elf_Shdr *)(_w(ehdr->e_shoff) + + (void *)ehdr); + unsigned const symsec_sh_link = w(relhdr->sh_link); + Elf_Shdr const *const symsec = &shdr0[symsec_sh_link]; + Elf_Shdr const *const strsec = &shdr0[w(symsec->sh_link)]; + Elf_Rel const *const rel0 = (Elf_Rel const *)(_w(relhdr->sh_offset) + + (void *)ehdr); + + *sym0 = (Elf_Sym const *)(_w(symsec->sh_offset) + + (void *)ehdr); + + *str0 = (char const *)(_w(strsec->sh_offset) + + (void *)ehdr); + + *relp = rel0; +} + /* * Look at the relocations in order to find the calls to mcount. * Accumulate the section offsets that are found, and their relocation info, @@ -276,26 +302,16 @@ static uint_t *sift_rel_mcount(uint_t *mlocp, { uint_t *const mloc0 = mlocp; Elf_Rel *mrelp = *mrelpp; - Elf_Shdr *const shdr0 = (Elf_Shdr *)(_w(ehdr->e_shoff) - + (void *)ehdr); - unsigned const symsec_sh_link = w(relhdr->sh_link); - Elf_Shdr const *const symsec = &shdr0[symsec_sh_link]; - Elf_Sym const *const sym0 = (Elf_Sym const *)(_w(symsec->sh_offset) - + (void *)ehdr); - - Elf_Shdr const *const strsec = &shdr0[w(symsec->sh_link)]; - char const *const str0 = (char const *)(_w(strsec->sh_offset) - + (void *)ehdr); - - Elf_Rel const *const rel0 = (Elf_Rel const *)(_w(relhdr->sh_offset) - + (void *)ehdr); + Elf_Sym const *sym0; + char const *str0; + Elf_Rel const *relp; unsigned rel_entsize = _w(relhdr->sh_entsize); unsigned const nrel = _w(relhdr->sh_size) / rel_entsize; - Elf_Rel const *relp = rel0; - unsigned mcountsym = 0; unsigned t; + get_sym_str_and_relp(relhdr, ehdr, &sym0, &str0, &relp); + for (t = nrel; t; --t) { if (!mcountsym) mcountsym = get_mcountsym(sym0, relp, str0); @@ -331,27 +347,18 @@ static void nop_mcount(Elf_Shdr const *const relhdr, { Elf_Shdr *const shdr0 = (Elf_Shdr *)(_w(ehdr->e_shoff) + (void *)ehdr); - unsigned const symsec_sh_link = w(relhdr->sh_link); - Elf_Shdr const *const symsec = &shdr0[symsec_sh_link]; - Elf_Sym const *const sym0 = (Elf_Sym const *)(_w(symsec->sh_offset) - + (void *)ehdr); - - Elf_Shdr const *const strsec = &shdr0[w(symsec->sh_link)]; - char const *const str0 = (char const *)(_w(strsec->sh_offset) - + (void *)ehdr); - - Elf_Rel const *const rel0 = (Elf_Rel const *)(_w(relhdr->sh_offset) - + (void *)ehdr); + Elf_Sym const *sym0; + char const *str0; + Elf_Rel const *relp; + Elf_Shdr const *const shdr = &shdr0[w(relhdr->sh_info)]; unsigned rel_entsize = _w(relhdr->sh_entsize); unsigned const nrel = _w(relhdr->sh_size) / rel_entsize; - Elf_Rel const *relp = rel0; - - Elf_Shdr const *const shdr = &shdr0[w(relhdr->sh_info)]; - unsigned mcountsym = 0; unsigned t; int once = 0; + get_sym_str_and_relp(relhdr, ehdr, &sym0, &str0, &relp); + for (t = nrel; t; --t) { int ret = -1; -- cgit v0.10.2 From 5173cc057787560c127c6e9737f308c833dc4ff3 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Mon, 16 May 2011 08:37:37 +0000 Subject: ipv4: more compliant RFC 3168 support Commit 6623e3b24a5e (ipv4: IP defragmentation must be ECN aware) was an attempt to not lose "Congestion Experienced" (CE) indications when performing datagram defragmentation. Stefanos Harhalakis raised the point that RFC 3168 requirements were not completely met by this commit. In particular, we MUST detect invalid combinations and eventually drop illegal frames. Reported-by: Stefanos Harhalakis Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller diff --git a/net/ipv4/ip_fragment.c b/net/ipv4/ip_fragment.c index b1d282f..9e1458d 100644 --- a/net/ipv4/ip_fragment.c +++ b/net/ipv4/ip_fragment.c @@ -77,22 +77,42 @@ struct ipq { struct inet_peer *peer; }; -#define IPFRAG_ECN_CLEAR 0x01 /* one frag had INET_ECN_NOT_ECT */ -#define IPFRAG_ECN_SET_CE 0x04 /* one frag had INET_ECN_CE */ +/* RFC 3168 support : + * We want to check ECN values of all fragments, do detect invalid combinations. + * In ipq->ecn, we store the OR value of each ip4_frag_ecn() fragment value. + */ +enum { + IPFRAG_ECN_NOT_ECT = 0x01, /* one frag had ECN_NOT_ECT */ + IPFRAG_ECN_ECT_1 = 0x02, /* one frag had ECN_ECT_1 */ + IPFRAG_ECN_ECT_0 = 0x04, /* one frag had ECN_ECT_0 */ + IPFRAG_ECN_CE = 0x08, /* one frag had ECN_CE */ +}; static inline u8 ip4_frag_ecn(u8 tos) { - tos = (tos & INET_ECN_MASK) + 1; - /* - * After the last operation we have (in binary): - * INET_ECN_NOT_ECT => 001 - * INET_ECN_ECT_1 => 010 - * INET_ECN_ECT_0 => 011 - * INET_ECN_CE => 100 - */ - return (tos & 2) ? 0 : tos; + return 1 << (tos & INET_ECN_MASK); } +/* Given the OR values of all fragments, apply RFC 3168 5.3 requirements + * Value : 0xff if frame should be dropped. + * 0 or INET_ECN_CE value, to be ORed in to final iph->tos field + */ +static const u8 ip4_frag_ecn_table[16] = { + /* at least one fragment had CE, and others ECT_0 or ECT_1 */ + [IPFRAG_ECN_CE | IPFRAG_ECN_ECT_0] = INET_ECN_CE, + [IPFRAG_ECN_CE | IPFRAG_ECN_ECT_1] = INET_ECN_CE, + [IPFRAG_ECN_CE | IPFRAG_ECN_ECT_0 | IPFRAG_ECN_ECT_1] = INET_ECN_CE, + + /* invalid combinations : drop frame */ + [IPFRAG_ECN_NOT_ECT | IPFRAG_ECN_CE] = 0xff, + [IPFRAG_ECN_NOT_ECT | IPFRAG_ECN_ECT_0] = 0xff, + [IPFRAG_ECN_NOT_ECT | IPFRAG_ECN_ECT_1] = 0xff, + [IPFRAG_ECN_NOT_ECT | IPFRAG_ECN_ECT_0 | IPFRAG_ECN_ECT_1] = 0xff, + [IPFRAG_ECN_NOT_ECT | IPFRAG_ECN_CE | IPFRAG_ECN_ECT_0] = 0xff, + [IPFRAG_ECN_NOT_ECT | IPFRAG_ECN_CE | IPFRAG_ECN_ECT_1] = 0xff, + [IPFRAG_ECN_NOT_ECT | IPFRAG_ECN_CE | IPFRAG_ECN_ECT_0 | IPFRAG_ECN_ECT_1] = 0xff, +}; + static struct inet_frags ip4_frags; int ip_frag_nqueues(struct net *net) @@ -524,9 +544,15 @@ static int ip_frag_reasm(struct ipq *qp, struct sk_buff *prev, int len; int ihlen; int err; + u8 ecn; ipq_kill(qp); + ecn = ip4_frag_ecn_table[qp->ecn]; + if (unlikely(ecn == 0xff)) { + err = -EINVAL; + goto out_fail; + } /* Make the one we just received the head. */ if (prev) { head = prev->next; @@ -605,17 +631,7 @@ static int ip_frag_reasm(struct ipq *qp, struct sk_buff *prev, iph = ip_hdr(head); iph->frag_off = 0; iph->tot_len = htons(len); - /* RFC3168 5.3 Fragmentation support - * If one fragment had INET_ECN_NOT_ECT, - * reassembled frame also has INET_ECN_NOT_ECT - * Elif one fragment had INET_ECN_CE - * reassembled frame also has INET_ECN_CE - */ - if (qp->ecn & IPFRAG_ECN_CLEAR) - iph->tos &= ~INET_ECN_MASK; - else if (qp->ecn & IPFRAG_ECN_SET_CE) - iph->tos |= INET_ECN_CE; - + iph->tos |= ecn; IP_INC_STATS_BH(net, IPSTATS_MIB_REASMOKS); qp->q.fragments = NULL; qp->q.fragments_tail = NULL; -- cgit v0.10.2 From 07d8b595f367f4604e6027ad4cba33cbe3f55e10 Mon Sep 17 00:00:00 2001 From: Martin Schwidefsky Date: Tue, 10 May 2011 10:10:40 +0200 Subject: ftrace/recordmcount: mcount address adjustment Introduce mcount_adjust{,_32,_64} to the C implementation of recordmcount analog to $mcount_adjust in the perl script. The adjustment is added to the address of the relocations against the mcount symbol. If this adjustment is done by recordmcount at compile time the ftrace_call_adjust function can be turned into a nop. Cc: John Reiser Signed-off-by: Martin Schwidefsky Signed-off-by: Steven Rostedt diff --git a/scripts/recordmcount.h b/scripts/recordmcount.h index 3c00fab..4be6036 100644 --- a/scripts/recordmcount.h +++ b/scripts/recordmcount.h @@ -22,6 +22,7 @@ #undef is_fake_mcount #undef fn_is_fake_mcount #undef MIPS_is_fake_mcount +#undef mcount_adjust #undef sift_rel_mcount #undef nop_mcount #undef find_secsym_ndx @@ -63,6 +64,7 @@ # define is_fake_mcount is_fake_mcount64 # define fn_is_fake_mcount fn_is_fake_mcount64 # define MIPS_is_fake_mcount MIPS64_is_fake_mcount +# define mcount_adjust mcount_adjust_64 # define Elf_Addr Elf64_Addr # define Elf_Ehdr Elf64_Ehdr # define Elf_Shdr Elf64_Shdr @@ -94,6 +96,7 @@ # define is_fake_mcount is_fake_mcount32 # define fn_is_fake_mcount fn_is_fake_mcount32 # define MIPS_is_fake_mcount MIPS32_is_fake_mcount +# define mcount_adjust mcount_adjust_32 # define Elf_Addr Elf32_Addr # define Elf_Ehdr Elf32_Ehdr # define Elf_Shdr Elf32_Shdr @@ -132,6 +135,8 @@ static void fn_ELF_R_INFO(Elf_Rel *const rp, unsigned sym, unsigned type) } static void (*Elf_r_info)(Elf_Rel *const rp, unsigned sym, unsigned type) = fn_ELF_R_INFO; +static int mcount_adjust = 0; + /* * MIPS mcount long call has 2 _mcount symbols, only the position of the 1st * _mcount symbol is needed for dynamic function tracer, with it, to disable @@ -317,8 +322,8 @@ static uint_t *sift_rel_mcount(uint_t *mlocp, mcountsym = get_mcountsym(sym0, relp, str0); if (mcountsym == Elf_r_sym(relp) && !is_fake_mcount(relp)) { - uint_t const addend = _w(_w(relp->r_offset) - recval); - + uint_t const addend = + _w(_w(relp->r_offset) - recval + mcount_adjust); mrelp->r_offset = _w(offbase + ((void *)mlocp - (void *)mloc0)); Elf_r_info(mrelp, recsym, reltype); -- cgit v0.10.2 From 2142c131a3e290ae350f8a0b0d354c0585a96df1 Mon Sep 17 00:00:00 2001 From: KOSAKI Motohiro Date: Mon, 16 May 2011 11:53:49 -0700 Subject: net: convert to new cpumask API We plan to remove cpu_xx() old api later. Thus this patch convert it. This patch has no functional change. Signed-off-by: KOSAKI Motohiro Signed-off-by: David S. Miller diff --git a/net/core/net-sysfs.c b/net/core/net-sysfs.c index 381813e..1b12217 100644 --- a/net/core/net-sysfs.c +++ b/net/core/net-sysfs.c @@ -964,7 +964,7 @@ static ssize_t store_xps_map(struct netdev_queue *queue, } else pos = map_len = alloc_len = 0; - need_set = cpu_isset(cpu, *mask) && cpu_online(cpu); + need_set = cpumask_test_cpu(cpu, mask) && cpu_online(cpu); #ifdef CONFIG_NUMA if (need_set) { if (numa_node == -2) -- cgit v0.10.2 From 521ccb5c4aece609311bfa7157910a8f0c942af5 Mon Sep 17 00:00:00 2001 From: Martin Schwidefsky Date: Tue, 10 May 2011 10:10:41 +0200 Subject: ftrace/x86: mcount offset calculation Do the mcount offset adjustment in the recordmcount.pl/recordmcount.[ch] at compile time and not in ftrace_call_adjust at run time. Signed-off-by: Martin Schwidefsky Signed-off-by: Steven Rostedt diff --git a/arch/x86/include/asm/ftrace.h b/arch/x86/include/asm/ftrace.h index db24c22..268c783 100644 --- a/arch/x86/include/asm/ftrace.h +++ b/arch/x86/include/asm/ftrace.h @@ -38,11 +38,10 @@ extern void mcount(void); static inline unsigned long ftrace_call_adjust(unsigned long addr) { /* - * call mcount is "e8 <4 byte offset>" - * The addr points to the 4 byte offset and the caller of this - * function wants the pointer to e8. Simply subtract one. + * addr is the address of the mcount call instruction. + * recordmcount does the necessary offset calculation. */ - return addr - 1; + return addr; } #ifdef CONFIG_DYNAMIC_FTRACE diff --git a/scripts/recordmcount.c b/scripts/recordmcount.c index 0e18975..7648a5d 100644 --- a/scripts/recordmcount.c +++ b/scripts/recordmcount.c @@ -335,6 +335,7 @@ do_file(char const *const fname) reltype = R_386_32; make_nop = make_nop_x86; ideal_nop = ideal_nop5_x86_32; + mcount_adjust_32 = -1; break; case EM_ARM: reltype = R_ARM_ABS32; altmcount = "__gnu_mcount_nc"; @@ -350,6 +351,7 @@ do_file(char const *const fname) make_nop = make_nop_x86; ideal_nop = ideal_nop5_x86_64; reltype = R_X86_64_64; + mcount_adjust_64 = -1; break; } /* end switch */ diff --git a/scripts/recordmcount.pl b/scripts/recordmcount.pl index a871cd4..414e7f5 100755 --- a/scripts/recordmcount.pl +++ b/scripts/recordmcount.pl @@ -223,6 +223,7 @@ if ($arch eq "x86_64") { $mcount_regex = "^\\s*([0-9a-fA-F]+):.*\\smcount([+-]0x[0-9a-zA-Z]+)?\$"; $type = ".quad"; $alignment = 8; + $mcount_adjust = -1; # force flags for this arch $ld .= " -m elf_x86_64"; @@ -232,6 +233,7 @@ if ($arch eq "x86_64") { } elsif ($arch eq "i386") { $alignment = 4; + $mcount_adjust = -1; # force flags for this arch $ld .= " -m elf_i386"; -- cgit v0.10.2 From f29638868280534ed7e2fdd93b31557232597940 Mon Sep 17 00:00:00 2001 From: Martin Schwidefsky Date: Tue, 10 May 2011 10:10:43 +0200 Subject: ftrace/s390: mcount offset calculation Do the mcount offset adjustment in the recordmcount.pl/recordmcount.[ch] at compile time and not in ftrace_call_adjust at run time. Signed-off-by: Martin Schwidefsky Signed-off-by: Steven Rostedt diff --git a/arch/s390/include/asm/ftrace.h b/arch/s390/include/asm/ftrace.h index 3c29be4..b7931fa 100644 --- a/arch/s390/include/asm/ftrace.h +++ b/arch/s390/include/asm/ftrace.h @@ -11,15 +11,13 @@ struct dyn_arch_ftrace { }; #ifdef CONFIG_64BIT #define MCOUNT_INSN_SIZE 12 -#define MCOUNT_OFFSET 8 #else #define MCOUNT_INSN_SIZE 20 -#define MCOUNT_OFFSET 4 #endif static inline unsigned long ftrace_call_adjust(unsigned long addr) { - return addr - MCOUNT_OFFSET; + return addr; } #endif /* __ASSEMBLY__ */ diff --git a/scripts/recordmcount.c b/scripts/recordmcount.c index 7648a5d..ee52cb8 100644 --- a/scripts/recordmcount.c +++ b/scripts/recordmcount.c @@ -368,8 +368,10 @@ do_file(char const *const fname) "unrecognized ET_REL file: %s\n", fname); fail_file(); } - if (w2(ehdr->e_machine) == EM_S390) + if (w2(ehdr->e_machine) == EM_S390) { reltype = R_390_32; + mcount_adjust_32 = -4; + } if (w2(ehdr->e_machine) == EM_MIPS) { reltype = R_MIPS_32; is_fake_mcount32 = MIPS32_is_fake_mcount; @@ -384,8 +386,10 @@ do_file(char const *const fname) "unrecognized ET_REL file: %s\n", fname); fail_file(); } - if (w2(ghdr->e_machine) == EM_S390) + if (w2(ghdr->e_machine) == EM_S390) { reltype = R_390_64; + mcount_adjust_64 = -8; + } if (w2(ghdr->e_machine) == EM_MIPS) { reltype = R_MIPS_64; Elf64_r_sym = MIPS64_r_sym; diff --git a/scripts/recordmcount.pl b/scripts/recordmcount.pl index 414e7f5..858966a 100755 --- a/scripts/recordmcount.pl +++ b/scripts/recordmcount.pl @@ -243,12 +243,14 @@ if ($arch eq "x86_64") { } elsif ($arch eq "s390" && $bits == 32) { $mcount_regex = "^\\s*([0-9a-fA-F]+):\\s*R_390_32\\s+_mcount\$"; + $mcount_adjust = -4; $alignment = 4; $ld .= " -m elf_s390"; $cc .= " -m31"; } elsif ($arch eq "s390" && $bits == 64) { $mcount_regex = "^\\s*([0-9a-fA-F]+):\\s*R_390_(PC|PLT)32DBL\\s+_mcount\\+0x2\$"; + $mcount_adjust = -8; $alignment = 8; $type = ".quad"; $ld .= " -m elf64_s390"; -- cgit v0.10.2 From 867955f5682f7157fdafe8670804b9f8ea077bc7 Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Mon, 16 May 2011 06:13:49 +0000 Subject: sfc: Fix oops in register dump after mapping change Commit 747df2258b1b9a2e25929ef496262c339c380009 ('sfc: Always map MCDI shared memory as uncacheable') introduced a separate mapping for the MCDI shared memory (MC_TREG_SMEM). This means we can no longer easily include it in the register dump. Since it is not particularly useful in debugging, substitute a recognisable dummy value. Signed-off-by: Ben Hutchings Signed-off-by: David S. Miller diff --git a/drivers/net/sfc/nic.c b/drivers/net/sfc/nic.c index 10f1cb7..9b29a8d 100644 --- a/drivers/net/sfc/nic.c +++ b/drivers/net/sfc/nic.c @@ -1937,6 +1937,13 @@ void efx_nic_get_regs(struct efx_nic *efx, void *buf) size = min_t(size_t, table->step, 16); + if (table->offset >= efx->type->mem_map_size) { + /* No longer mapped; return dummy data */ + memcpy(buf, "\xde\xc0\xad\xde", 4); + buf += table->rows * size; + continue; + } + for (i = 0; i < table->rows; i++) { switch (table->step) { case 4: /* 32-bit register or SRAM */ -- cgit v0.10.2 From ebde6f8acba92abfc203585198a54f47e83e2cd0 Mon Sep 17 00:00:00 2001 From: Thomas Jarosch Date: Mon, 16 May 2011 06:28:15 +0000 Subject: vmxnet3: Fix inconsistent LRO state after initialization During initialization of vmxnet3, the state of LRO gets out of sync with netdev->features. This leads to very poor TCP performance in a IP forwarding setup and is hitting many VMware users. Simplified call sequence: 1. vmxnet3_declare_features() initializes "adapter->lro" to true. 2. The kernel automatically disables LRO if IP forwarding is enabled, so vmxnet3_set_flags() gets called. This also updates netdev->features. 3. Now vmxnet3_setup_driver_shared() is called. "adapter->lro" is still set to true and LRO gets enabled again, even though netdev->features shows it's disabled. Fix it by updating "adapter->lro", too. The private vmxnet3 adapter flags are scheduled for removal in net-next, see commit a0d2730c9571aeba793cb5d3009094ee1d8fda35 "net: vmxnet3: convert to hw_features". Patch applies to 2.6.37 / 2.6.38 and 2.6.39-rc6. Please CC: comments. Signed-off-by: Thomas Jarosch Acked-by: Stephen Hemminger Signed-off-by: David S. Miller diff --git a/drivers/net/vmxnet3/vmxnet3_ethtool.c b/drivers/net/vmxnet3/vmxnet3_ethtool.c index 51f2ef1..9764672 100644 --- a/drivers/net/vmxnet3/vmxnet3_ethtool.c +++ b/drivers/net/vmxnet3/vmxnet3_ethtool.c @@ -311,6 +311,9 @@ vmxnet3_set_flags(struct net_device *netdev, u32 data) /* toggle the LRO feature*/ netdev->features ^= NETIF_F_LRO; + /* Update private LRO flag */ + adapter->lro = lro_requested; + /* update harware LRO capability accordingly */ if (lro_requested) adapter->shared->devRead.misc.uptFeatures |= -- cgit v0.10.2 From 6f404e441d169afc90929ef5e451ec9779c1f11a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Miros=C5=82aw?= Date: Mon, 16 May 2011 15:14:21 -0400 Subject: net: Change netdev_fix_features messages loglevel MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Those reduced to DEBUG can possibly be triggered by unprivileged processes and are nothing exceptional. Illegal checksum combinations can only be caused by driver bug, so promote those messages to WARN. Since GSO without SG will now only cause DEBUG message from netdev_fix_features(), remove the workaround from register_netdevice(). Signed-off-by: MichaÅ‚ MirosÅ‚aw Signed-off-by: David S. Miller diff --git a/net/core/dev.c b/net/core/dev.c index 9200944..b624fe4 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -5186,27 +5186,27 @@ u32 netdev_fix_features(struct net_device *dev, u32 features) /* Fix illegal checksum combinations */ if ((features & NETIF_F_HW_CSUM) && (features & (NETIF_F_IP_CSUM|NETIF_F_IPV6_CSUM))) { - netdev_info(dev, "mixed HW and IP checksum settings.\n"); + netdev_warn(dev, "mixed HW and IP checksum settings.\n"); features &= ~(NETIF_F_IP_CSUM|NETIF_F_IPV6_CSUM); } if ((features & NETIF_F_NO_CSUM) && (features & (NETIF_F_HW_CSUM|NETIF_F_IP_CSUM|NETIF_F_IPV6_CSUM))) { - netdev_info(dev, "mixed no checksumming and other settings.\n"); + netdev_warn(dev, "mixed no checksumming and other settings.\n"); features &= ~(NETIF_F_IP_CSUM|NETIF_F_IPV6_CSUM|NETIF_F_HW_CSUM); } /* Fix illegal SG+CSUM combinations. */ if ((features & NETIF_F_SG) && !(features & NETIF_F_ALL_CSUM)) { - netdev_info(dev, - "Dropping NETIF_F_SG since no checksum feature.\n"); + netdev_dbg(dev, + "Dropping NETIF_F_SG since no checksum feature.\n"); features &= ~NETIF_F_SG; } /* TSO requires that SG is present as well. */ if ((features & NETIF_F_ALL_TSO) && !(features & NETIF_F_SG)) { - netdev_info(dev, "Dropping TSO features since no SG feature.\n"); + netdev_dbg(dev, "Dropping TSO features since no SG feature.\n"); features &= ~NETIF_F_ALL_TSO; } @@ -5216,7 +5216,7 @@ u32 netdev_fix_features(struct net_device *dev, u32 features) /* Software GSO depends on SG. */ if ((features & NETIF_F_GSO) && !(features & NETIF_F_SG)) { - netdev_info(dev, "Dropping NETIF_F_GSO since no SG feature.\n"); + netdev_dbg(dev, "Dropping NETIF_F_GSO since no SG feature.\n"); features &= ~NETIF_F_GSO; } @@ -5226,13 +5226,13 @@ u32 netdev_fix_features(struct net_device *dev, u32 features) if (!((features & NETIF_F_GEN_CSUM) || (features & (NETIF_F_IP_CSUM|NETIF_F_IPV6_CSUM)) == (NETIF_F_IP_CSUM|NETIF_F_IPV6_CSUM))) { - netdev_info(dev, + netdev_dbg(dev, "Dropping NETIF_F_UFO since no checksum offload features.\n"); features &= ~NETIF_F_UFO; } if (!(features & NETIF_F_SG)) { - netdev_info(dev, + netdev_dbg(dev, "Dropping NETIF_F_UFO since no NETIF_F_SG feature.\n"); features &= ~NETIF_F_UFO; } @@ -5414,12 +5414,6 @@ int register_netdevice(struct net_device *dev) dev->features |= NETIF_F_SOFT_FEATURES; dev->wanted_features = dev->features & dev->hw_features; - /* Avoid warning from netdev_fix_features() for GSO without SG */ - if (!(dev->wanted_features & NETIF_F_SG)) { - dev->wanted_features &= ~NETIF_F_GSO; - dev->features &= ~NETIF_F_GSO; - } - /* Enable GRO and NETIF_F_HIGHDMA for vlans by default, * vlan_dev_init() will do the dev->features check, so these features * are enabled only if supported by underlying device. -- cgit v0.10.2 From 865be7a81071a77014c83cd01536c989eed362b4 Mon Sep 17 00:00:00 2001 From: Ondrej Zary Date: Mon, 16 May 2011 21:38:08 +0200 Subject: x86, cpu: Fix detection of Celeron Covington stepping A1 and B0 Steppings A1 and B0 of Celeron Covington are currently misdetected as Pentium II (Dixon). Fix it by removing the stepping check. [ hpa: this fixes this specific bug... the CPUID documentation specifies that the L2 cache size can disambiguate additional CPUs; this patch does not fix that. ] Signed-off-by: Ondrej Zary Link: http://lkml.kernel.org/r/201105162138.15416.linux@rainbow-software.org Signed-off-by: H. Peter Anvin diff --git a/arch/x86/kernel/cpu/intel.c b/arch/x86/kernel/cpu/intel.c index df86bc8..32e86aa 100644 --- a/arch/x86/kernel/cpu/intel.c +++ b/arch/x86/kernel/cpu/intel.c @@ -400,12 +400,10 @@ static void __cpuinit init_intel(struct cpuinfo_x86 *c) switch (c->x86_model) { case 5: - if (c->x86_mask == 0) { - if (l2 == 0) - p = "Celeron (Covington)"; - else if (l2 == 256) - p = "Mobile Pentium II (Dixon)"; - } + if (l2 == 0) + p = "Celeron (Covington)"; + else if (l2 == 256) + p = "Mobile Pentium II (Dixon)"; break; case 6: -- cgit v0.10.2 From dc382fd5bcca7098a984705ed6ac880f539d068e Mon Sep 17 00:00:00 2001 From: David Rientjes Date: Mon, 16 May 2011 13:54:10 -0700 Subject: x86, mm: Allow ZONE_DMA to be configurable ZONE_DMA is unnecessary for a large number of machines that do not require less than 32-bit DMA addressing, e.g. ISA legacy DMA or PCI cards with a restricted DMA address mask. This patch allows users to disable ZONE_DMA for x86 if they know they will not be using such devices with their kernel. This prevents the VM from unnecessarily reserving a ratio of memory (defaulting to 1/256th of system capacity) with lowmem_reserve_ratio for such allocations when it will never be used. Signed-off-by: David Rientjes Link: http://lkml.kernel.org/r/alpine.DEB.2.00.1105161353560.4353@chino.kir.corp.google.com Signed-off-by: H. Peter Anvin diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig index 648fca4..0eb801a 100644 --- a/arch/x86/Kconfig +++ b/arch/x86/Kconfig @@ -112,7 +112,14 @@ config MMU def_bool y config ZONE_DMA - def_bool y + bool "DMA memory allocation support" if EXPERT + default y + help + DMA memory allocation support allows devices with less than 32-bit + addressing to allocate within the first 16MB of address space. + Disable if no such devices will be used. + + If unsure, say Y. config SBUS bool diff --git a/arch/x86/mm/init_32.c b/arch/x86/mm/init_32.c index 2cde0a34..29f7c6d9 100644 --- a/arch/x86/mm/init_32.c +++ b/arch/x86/mm/init_32.c @@ -678,8 +678,10 @@ static void __init zone_sizes_init(void) { unsigned long max_zone_pfns[MAX_NR_ZONES]; memset(max_zone_pfns, 0, sizeof(max_zone_pfns)); +#ifdef CONFIG_ZONE_DMA max_zone_pfns[ZONE_DMA] = virt_to_phys((char *)MAX_DMA_ADDRESS) >> PAGE_SHIFT; +#endif max_zone_pfns[ZONE_NORMAL] = max_low_pfn; #ifdef CONFIG_HIGHMEM max_zone_pfns[ZONE_HIGHMEM] = highend_pfn; diff --git a/arch/x86/mm/init_64.c b/arch/x86/mm/init_64.c index 0404bb3..d865c4a 100644 --- a/arch/x86/mm/init_64.c +++ b/arch/x86/mm/init_64.c @@ -616,7 +616,9 @@ void __init paging_init(void) unsigned long max_zone_pfns[MAX_NR_ZONES]; memset(max_zone_pfns, 0, sizeof(max_zone_pfns)); +#ifdef CONFIG_ZONE_DMA max_zone_pfns[ZONE_DMA] = MAX_DMA_PFN; +#endif max_zone_pfns[ZONE_DMA32] = MAX_DMA32_PFN; max_zone_pfns[ZONE_NORMAL] = max_pfn; -- cgit v0.10.2 From 07f4beb0b5bbfaf36a64aa00d59e670ec578a95a Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Mon, 16 May 2011 11:07:48 +0200 Subject: tick: Clear broadcast active bit when switching to oneshot The first cpu which switches from periodic to oneshot mode switches also the broadcast device into oneshot mode. The broadcast device serves as a backup for per cpu timers which stop in deeper C-states. To avoid starvation of the cpus which might be in idle and depend on broadcast mode it marks the other cpus as broadcast active and sets the brodcast expiry value of those cpus to the next tick. The oneshot mode broadcast bit for the other cpus is sticky and gets only cleared when those cpus exit idle. If a cpu was not idle while the bit got set in consequence the bit prevents that the broadcast device is armed on behalf of that cpu when it enters idle for the first time after it switched to oneshot mode. In most cases that goes unnoticed as one of the other cpus has usually a timer pending which keeps the broadcast device armed with a short timeout. Now if the only cpu which has a short timer active has the bit set then the broadcast device will not be armed on behalf of that cpu and will fire way after the expected timer expiry. In the case of Christians bug report it took ~145 seconds which is about half of the wrap around time of HPET (the limit for that device) due to the fact that all other cpus had no timers armed which expired before the 145 seconds timeframe. The solution is simply to clear the broadcast active bit unconditionally when a cpu switches to oneshot mode after the first cpu switched the broadcast device over. It's not idle at that point otherwise it would not be executing that code. [ I fundamentally hate that broadcast crap. Why the heck thought some folks that when going into deep idle it's a brilliant concept to switch off the last device which brings the cpu back from that state? ] Thanks to Christian for providing all the valuable debug information! Reported-and-tested-by: Christian Hoffmann Cc: John Stultz Link: http://lkml.kernel.org/r/%3Calpine.LFD.2.02.1105161105170.3078%40ionos%3E Cc: stable@kernel.org Signed-off-by: Thomas Gleixner diff --git a/kernel/time/tick-broadcast.c b/kernel/time/tick-broadcast.c index da800ff..723c763 100644 --- a/kernel/time/tick-broadcast.c +++ b/kernel/time/tick-broadcast.c @@ -522,10 +522,11 @@ static void tick_broadcast_init_next_event(struct cpumask *mask, */ void tick_broadcast_setup_oneshot(struct clock_event_device *bc) { + int cpu = smp_processor_id(); + /* Set it up only once ! */ if (bc->event_handler != tick_handle_oneshot_broadcast) { int was_periodic = bc->mode == CLOCK_EVT_MODE_PERIODIC; - int cpu = smp_processor_id(); bc->event_handler = tick_handle_oneshot_broadcast; clockevents_set_mode(bc, CLOCK_EVT_MODE_ONESHOT); @@ -551,6 +552,15 @@ void tick_broadcast_setup_oneshot(struct clock_event_device *bc) tick_broadcast_set_event(tick_next_period, 1); } else bc->next_event.tv64 = KTIME_MAX; + } else { + /* + * The first cpu which switches to oneshot mode sets + * the bit for all other cpus which are in the general + * (periodic) broadcast mask. So the bit is set and + * would prevent the first broadcast enter after this + * to program the bc device. + */ + tick_broadcast_clear_oneshot(cpu); } } -- cgit v0.10.2 From e4abce8538496ba90cb89909894ea42e00f96a7d Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Mon, 16 May 2011 18:51:24 +0100 Subject: sfc: Use netif_device_{detach,attach}() around reset and self-test We need to keep the TX queues stopped throughout a reset, without triggering the TX watchdog and regardless of the link state. The proper way to do this is to use netif_device_{detach,attach}() just as we do around suspend/resume, rather than the current bodge of faking link-down. Since we also need to do this during an offline self-test and we perform a reset during that, add these function calls outside of efx_reset_down() and efx_reset_up(). Signed-off-by: Ben Hutchings diff --git a/drivers/net/sfc/efx.c b/drivers/net/sfc/efx.c index 796c47e..05502b3 100644 --- a/drivers/net/sfc/efx.c +++ b/drivers/net/sfc/efx.c @@ -798,11 +798,6 @@ void efx_link_status_changed(struct efx_nic *efx) if (!netif_running(efx->net_dev)) return; - if (efx->port_inhibited) { - netif_carrier_off(efx->net_dev); - return; - } - if (link_state->up != netif_carrier_ok(efx->net_dev)) { efx->n_link_state_changes++; @@ -1450,7 +1445,7 @@ static void efx_start_all(struct efx_nic *efx) * restart the transmit interface early so the watchdog timer stops */ efx_start_port(efx); - if (efx_dev_registered(efx) && !efx->port_inhibited) + if (efx_dev_registered(efx) && netif_device_present(efx->net_dev)) netif_tx_wake_all_queues(efx->net_dev); efx_for_each_channel(channel, efx) @@ -2114,6 +2109,7 @@ int efx_reset(struct efx_nic *efx, enum reset_type method) netif_info(efx, drv, efx->net_dev, "resetting (%s)\n", RESET_TYPE(method)); + netif_device_detach(efx->net_dev); efx_reset_down(efx, method); rc = efx->type->reset(efx, method); @@ -2147,6 +2143,7 @@ out: efx->state = STATE_DISABLED; } else { netif_dbg(efx, drv, efx->net_dev, "reset complete\n"); + netif_device_attach(efx->net_dev); } return rc; } diff --git a/drivers/net/sfc/net_driver.h b/drivers/net/sfc/net_driver.h index 5718260..ce9697b 100644 --- a/drivers/net/sfc/net_driver.h +++ b/drivers/net/sfc/net_driver.h @@ -670,13 +670,12 @@ struct efx_filter_state; * @mtd_list: List of MTDs attached to the NIC * @nic_data: Hardware dependent state * @mac_lock: MAC access lock. Protects @port_enabled, @phy_mode, - * @port_inhibited, efx_monitor() and efx_reconfigure_port() + * efx_monitor() and efx_reconfigure_port() * @port_enabled: Port enabled indicator. * Serialises efx_stop_all(), efx_start_all(), efx_monitor() and * efx_mac_work() with kernel interfaces. Safe to read under any * one of the rtnl_lock, mac_lock, or netif_tx_lock, but all three must * be held to modify it. - * @port_inhibited: If set, the netif_carrier is always off. Hold the mac_lock * @port_initialized: Port initialized? * @net_dev: Operating system network device. Consider holding the rtnl lock * @stats_buffer: DMA buffer for statistics @@ -764,7 +763,6 @@ struct efx_nic { struct mutex mac_lock; struct work_struct mac_work; bool port_enabled; - bool port_inhibited; bool port_initialized; struct net_device *net_dev; diff --git a/drivers/net/sfc/selftest.c b/drivers/net/sfc/selftest.c index 50ad3bc..822f6c2 100644 --- a/drivers/net/sfc/selftest.c +++ b/drivers/net/sfc/selftest.c @@ -695,12 +695,12 @@ int efx_selftest(struct efx_nic *efx, struct efx_self_tests *tests, /* Offline (i.e. disruptive) testing * This checks MAC and PHY loopback on the specified port. */ - /* force the carrier state off so the kernel doesn't transmit during - * the loopback test, and the watchdog timeout doesn't fire. Also put - * falcon into loopback for the register test. + /* Detach the device so the kernel doesn't transmit during the + * loopback test and the watchdog timeout doesn't fire. */ + netif_device_detach(efx->net_dev); + mutex_lock(&efx->mac_lock); - efx->port_inhibited = true; if (efx->loopback_modes) { /* We need the 312 clock from the PHY to test the XMAC * registers, so move into XGMII loopback if available */ @@ -750,12 +750,11 @@ int efx_selftest(struct efx_nic *efx, struct efx_self_tests *tests, /* restore the PHY to the previous state */ mutex_lock(&efx->mac_lock); efx->phy_mode = phy_mode; - efx->port_inhibited = false; efx->loopback_mode = loopback_mode; __efx_reconfigure_port(efx); mutex_unlock(&efx->mac_lock); - netif_tx_wake_all_queues(efx->net_dev); + netif_device_attach(efx->net_dev); return rc_test; } diff --git a/drivers/net/sfc/tx.c b/drivers/net/sfc/tx.c index d2c85df..84eb99e 100644 --- a/drivers/net/sfc/tx.c +++ b/drivers/net/sfc/tx.c @@ -205,7 +205,9 @@ netdev_tx_t efx_enqueue_skb(struct efx_tx_queue *tx_queue, struct sk_buff *skb) goto unwind; } smp_mb(); - netif_tx_start_queue(tx_queue->core_txq); + if (likely(!efx->loopback_selftest)) + netif_tx_start_queue( + tx_queue->core_txq); } insert_ptr = tx_queue->insert_count & tx_queue->ptr_mask; @@ -338,8 +340,7 @@ netdev_tx_t efx_hard_start_xmit(struct sk_buff *skb, struct efx_tx_queue *tx_queue; unsigned index, type; - if (unlikely(efx->port_inhibited)) - return NETDEV_TX_BUSY; + EFX_WARN_ON_PARANOID(!netif_device_present(net_dev)); index = skb_get_queue_mapping(skb); type = skb->ip_summed == CHECKSUM_PARTIAL ? EFX_TXQ_TYPE_OFFLOAD : 0; @@ -436,7 +437,7 @@ void efx_xmit_done(struct efx_tx_queue *tx_queue, unsigned int index) smp_mb(); if (unlikely(netif_tx_queue_stopped(tx_queue->core_txq)) && likely(efx->port_enabled) && - likely(!efx->port_inhibited)) { + likely(netif_device_present(efx->net_dev))) { fill_level = tx_queue->insert_count - tx_queue->read_count; if (fill_level < EFX_TXQ_THRESHOLD(efx)) { EFX_BUG_ON_PARANOID(!efx_dev_registered(efx)); -- cgit v0.10.2 From 93d2175d3d31f11ba04fcfa0e9a496a1b4bc8b34 Mon Sep 17 00:00:00 2001 From: Yinghai Lu Date: Fri, 13 May 2011 18:06:17 -0700 Subject: PCI: Clear bridge resource flags if requested size is 0 During pci remove/rescan testing found: pci 0000:c0:03.0: PCI bridge to [bus c4-c9] pci 0000:c0:03.0: bridge window [io 0x1000-0x0fff] pci 0000:c0:03.0: bridge window [mem 0xf0000000-0xf00fffff] pci 0000:c0:03.0: bridge window [mem 0xfc180000000-0xfc197ffffff 64bit pref] pci 0000:c0:03.0: device not available (can't reserve [io 0x1000-0x0fff]) pci 0000:c0:03.0: Error enabling bridge (-22), continuing pci 0000:c0:03.0: enabling bus mastering pci 0000:c0:03.0: setting latency timer to 64 pcieport 0000:c0:03.0: device not available (can't reserve [io 0x1000-0x0fff]) pcieport: probe of 0000:c0:03.0 failed with error -22 This bug was caused by commit c8adf9a3e873 ("PCI: pre-allocate additional resources to devices only after successful allocation of essential resources.") After that commit, pci_hotplug_io_size is changed to additional_io_size from minium size. So it will not go through resource_size(res) != 0 path, and will not be reset. The root cause is: pci_bridge_check_ranges will set RESOURCE_IO flag for pci bridge, and later if children do not need IO resource. those bridge resources will not need to be allocated. but flags is still there. that will confuse the the pci_enable_bridges later. related code: static void assign_requested_resources_sorted(struct resource_list *head, struct resource_list_x *fail_head) { struct resource *res; struct resource_list *list; int idx; for (list = head->next; list; list = list->next) { res = list->res; idx = res - &list->dev->resource[0]; if (resource_size(res) && pci_assign_resource(list->dev, idx)) { ... reset_resource(res); } } } At last, We have to clear the flags in pbus_size_mem/io when requested size == 0 and !add_head. becasue this case it will not go through adjust_resources_sorted(). Just make size1 = size0 when !add_head. it will make flags get cleared. At the same time when requested size == 0, add_size != 0, will still have in head and add_list. because we do not clear the flags for it. After this, we will get right result: pci 0000:c0:03.0: PCI bridge to [bus c4-c9] pci 0000:c0:03.0: bridge window [io disabled] pci 0000:c0:03.0: bridge window [mem 0xf0000000-0xf00fffff] pci 0000:c0:03.0: bridge window [mem 0xfc180000000-0xfc197ffffff 64bit pref] pci 0000:c0:03.0: enabling bus mastering pci 0000:c0:03.0: setting latency timer to 64 pcieport 0000:c0:03.0: setting latency timer to 64 pcieport 0000:c0:03.0: irq 160 for MSI/MSI-X pcieport 0000:c0:03.0: Signaling PME through PCIe PME interrupt pci 0000:c4:00.0: Signaling PME through PCIe PME interrupt pcie_pme 0000:c0:03.0:pcie01: service driver pcie_pme loaded aer 0000:c0:03.0:pcie02: service driver aer loaded pciehp 0000:c0:03.0:pcie04: Hotplug Controller: v3: more simple fix. also fix one typo in pbus_size_mem Signed-off-by: Yinghai Lu Reviewed-by: Ram Pai Cc: Jesse Barnes Cc: Bjorn Helgaas Signed-off-by: Linus Torvalds diff --git a/drivers/pci/setup-bus.c b/drivers/pci/setup-bus.c index ebf51ad..a806cb3 100644 --- a/drivers/pci/setup-bus.c +++ b/drivers/pci/setup-bus.c @@ -579,7 +579,7 @@ static void pbus_size_io(struct pci_bus *bus, resource_size_t min_size, } size0 = calculate_iosize(size, min_size, size1, resource_size(b_res), 4096); - size1 = !add_size? size0: + size1 = (!add_head || (add_head && !add_size)) ? size0 : calculate_iosize(size, min_size+add_size, size1, resource_size(b_res), 4096); if (!size0 && !size1) { @@ -677,7 +677,7 @@ static int pbus_size_mem(struct pci_bus *bus, unsigned long mask, align += aligns[order]; } size0 = calculate_memsize(size, min_size, 0, resource_size(b_res), min_align); - size1 = !add_size ? size : + size1 = (!add_head || (add_head && !add_size)) ? size0 : calculate_memsize(size, min_size+add_size, 0, resource_size(b_res), min_align); if (!size0 && !size1) { -- cgit v0.10.2 From b5e6ab589d570ac79cc939517fab05c87a23c262 Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Mon, 16 May 2011 13:16:54 -0700 Subject: mm: fix kernel-doc warning in page_alloc.c Fix new kernel-doc warning in mm/page_alloc.c: Warning(mm/page_alloc.c:2370): No description found for parameter 'nid' Signed-off-by: Randy Dunlap Signed-off-by: Linus Torvalds diff --git a/mm/page_alloc.c b/mm/page_alloc.c index 570d944..3f8bce2 100644 --- a/mm/page_alloc.c +++ b/mm/page_alloc.c @@ -2358,6 +2358,7 @@ EXPORT_SYMBOL(alloc_pages_exact); /** * alloc_pages_exact_nid - allocate an exact number of physically-contiguous * pages on a node. + * @nid: the preferred node ID where memory should be allocated * @size: the number of bytes to allocate * @gfp_mask: GFP flags for the allocation * -- cgit v0.10.2 From 6dcae1eaee2b437536b2fe928a609f9589691ebf Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Mon, 16 May 2011 23:09:26 -0400 Subject: bluetooth: Fix warnings in l2cap_core.c MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit net/bluetooth/l2cap_core.c: In function ‘l2cap_recv_frame’: net/bluetooth/l2cap_core.c:3758:15: warning: ‘sk’ may be used uninitialized in this function net/bluetooth/l2cap_core.c:3758:15: note: ‘sk’ was declared here net/bluetooth/l2cap_core.c:3791:15: warning: ‘sk’ may be used uninitialized in this function net/bluetooth/l2cap_core.c:3791:15: note: ‘sk’ was declared here Signed-off-by: David S. Miller diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index 4f3bc74..a86f9ba 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -3755,7 +3755,7 @@ done: static inline int l2cap_conless_channel(struct l2cap_conn *conn, __le16 psm, struct sk_buff *skb) { - struct sock *sk; + struct sock *sk = NULL; struct l2cap_chan *chan; chan = l2cap_global_chan_by_psm(0, psm, conn->src); @@ -3788,7 +3788,7 @@ done: static inline int l2cap_att_channel(struct l2cap_conn *conn, __le16 cid, struct sk_buff *skb) { - struct sock *sk; + struct sock *sk = NULL; struct l2cap_chan *chan; chan = l2cap_global_chan_by_scid(0, cid, conn->src); -- cgit v0.10.2 From 3699d92a4d7b649bde67dff3cc681400992e0254 Mon Sep 17 00:00:00 2001 From: Kiran Patil Date: Mon, 18 Apr 2011 16:24:14 -0700 Subject: [SCSI] tcm_fc: Adding FC_FC4 provider (tcm_fc) for FCoE target (TCM - target core) support This is a comprehensive patch for FC-FC4 provider. tcm_fc is a FC-FC4 provider which glues target core (TCM) with Fiber channel library (libfc). tcm_fc uses existing FC4 provider hooks from Fiber channel library. This Fiber channel library is used by FCoE (transport - FC over Ethernet) protocol driver as well. Combination of modules such as Fiber channel library, tcm_fc, TCM target core, and FCoE protocol driver enables functional FCoE target. This patch includes initial commit for tcm_fc plus additional enhancement, bug fixes. This tcm_fc module essentially contains 3 entry points such as "prli", "prlo", "recv". When process login request (ELS_PRLI) request is received, Fiber channel library (libfc) module calls passive providers (FC-FC4, tcm_fc) (if any registered) "prli" function. Likewise when LOGO request is received, "prlo" function of passive provider is invoked by libfc. For all other request (e.g. any read/write, task management, LUN inquiry commands), "recv" function of passiver provider is invoked by libfc. Those passive providers "prli, prlo, recv" functions interact with TCM target core for requested operation. This module was primarily developed by "Joe Eykholt" and there were significant contributions from the people listed under signed-off. Signed-off-by: Joe Eykholt Signed-off-by: Nicholas A. Bellinger Signed-off-by: Christoph Hellwig Signed-off-by: Yi Zou Signed-off-by: Kiran Patil Acked-by: Robert Love Signed-off-by: James Bottomley Signed-off-by: James Bottomley diff --git a/drivers/target/Kconfig b/drivers/target/Kconfig index 9ef2dbb..5cb0f0e 100644 --- a/drivers/target/Kconfig +++ b/drivers/target/Kconfig @@ -30,5 +30,6 @@ config TCM_PSCSI passthrough access to Linux/SCSI device source "drivers/target/loopback/Kconfig" +source "drivers/target/tcm_fc/Kconfig" endif diff --git a/drivers/target/Makefile b/drivers/target/Makefile index 1178bbf..21df808 100644 --- a/drivers/target/Makefile +++ b/drivers/target/Makefile @@ -24,3 +24,5 @@ obj-$(CONFIG_TCM_PSCSI) += target_core_pscsi.o # Fabric modules obj-$(CONFIG_LOOPBACK_TARGET) += loopback/ + +obj-$(CONFIG_TCM_FC) += tcm_fc/ diff --git a/drivers/target/tcm_fc/Kconfig b/drivers/target/tcm_fc/Kconfig new file mode 100644 index 0000000..40caf45 --- /dev/null +++ b/drivers/target/tcm_fc/Kconfig @@ -0,0 +1,5 @@ +config TCM_FC + tristate "TCM_FC fabric Plugin" + depends on LIBFC + help + Say Y here to enable the TCM FC plugin for accessing FC fabrics in TCM diff --git a/drivers/target/tcm_fc/Makefile b/drivers/target/tcm_fc/Makefile new file mode 100644 index 0000000..7a5c2b6 --- /dev/null +++ b/drivers/target/tcm_fc/Makefile @@ -0,0 +1,15 @@ +EXTRA_CFLAGS += -I$(srctree)/drivers/target/ \ + -I$(srctree)/drivers/scsi/ \ + -I$(srctree)/include/scsi/ \ + -I$(srctree)/drivers/target/tcm_fc/ + +tcm_fc-y += tfc_cmd.o \ + tfc_conf.o \ + tfc_io.o \ + tfc_sess.o + +obj-$(CONFIG_TCM_FC) += tcm_fc.o + +ifdef CONFIGFS_TCM_FC_DEBUG +EXTRA_CFLAGS += -DTCM_FC_DEBUG +endif diff --git a/drivers/target/tcm_fc/tcm_fc.h b/drivers/target/tcm_fc/tcm_fc.h new file mode 100644 index 0000000..defff32 --- /dev/null +++ b/drivers/target/tcm_fc/tcm_fc.h @@ -0,0 +1,215 @@ +/* + * Copyright (c) 2010 Cisco Systems, Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions 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 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., + * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + */ +#ifndef __TCM_FC_H__ +#define __TCM_FC_H__ + +#define FT_VERSION "0.3" + +#define FT_NAMELEN 32 /* length of ASCII WWPNs including pad */ +#define FT_TPG_NAMELEN 32 /* max length of TPG name */ +#define FT_LUN_NAMELEN 32 /* max length of LUN name */ + +/* + * Debug options. + */ +#define FT_DEBUG_CONF 0x01 /* configuration messages */ +#define FT_DEBUG_SESS 0x02 /* session messages */ +#define FT_DEBUG_TM 0x04 /* TM operations */ +#define FT_DEBUG_IO 0x08 /* I/O commands */ +#define FT_DEBUG_DATA 0x10 /* Data transfer */ + +extern unsigned int ft_debug_logging; /* debug options */ + +#define FT_DEBUG(mask, fmt, args...) \ + do { \ + if (ft_debug_logging & (mask)) \ + printk(KERN_INFO "tcm_fc: %s: " fmt, \ + __func__, ##args); \ + } while (0) + +#define FT_CONF_DBG(fmt, args...) FT_DEBUG(FT_DEBUG_CONF, fmt, ##args) +#define FT_SESS_DBG(fmt, args...) FT_DEBUG(FT_DEBUG_SESS, fmt, ##args) +#define FT_TM_DBG(fmt, args...) FT_DEBUG(FT_DEBUG_TM, fmt, ##args) +#define FT_IO_DBG(fmt, args...) FT_DEBUG(FT_DEBUG_IO, fmt, ##args) +#define FT_DATA_DBG(fmt, args...) FT_DEBUG(FT_DEBUG_DATA, fmt, ##args) + +struct ft_transport_id { + __u8 format; + __u8 __resvd1[7]; + __u8 wwpn[8]; + __u8 __resvd2[8]; +} __attribute__((__packed__)); + +/* + * Session (remote port). + */ +struct ft_sess { + u32 port_id; /* for hash lookup use only */ + u32 params; + u16 max_frame; /* maximum frame size */ + u64 port_name; /* port name for transport ID */ + struct ft_tport *tport; + struct se_session *se_sess; + struct hlist_node hash; /* linkage in ft_sess_hash table */ + struct rcu_head rcu; + struct kref kref; /* ref for hash and outstanding I/Os */ +}; + +/* + * Hash table of sessions per local port. + * Hash lookup by remote port FC_ID. + */ +#define FT_SESS_HASH_BITS 6 +#define FT_SESS_HASH_SIZE (1 << FT_SESS_HASH_BITS) + +/* + * Per local port data. + * This is created only after a TPG exists that allows target function + * for the local port. If the TPG exists, this is allocated when + * we're notified that the local port has been created, or when + * the first PRLI provider callback is received. + */ +struct ft_tport { + struct fc_lport *lport; + struct ft_tpg *tpg; /* NULL if TPG deleted before tport */ + u32 sess_count; /* number of sessions in hash */ + struct rcu_head rcu; + struct hlist_head hash[FT_SESS_HASH_SIZE]; /* list of sessions */ +}; + +/* + * Node ID and authentication. + */ +struct ft_node_auth { + u64 port_name; + u64 node_name; +}; + +/* + * Node ACL for FC remote port session. + */ +struct ft_node_acl { + struct ft_node_auth node_auth; + struct se_node_acl se_node_acl; +}; + +struct ft_lun { + u32 index; + char name[FT_LUN_NAMELEN]; +}; + +/* + * Target portal group (local port). + */ +struct ft_tpg { + u32 index; + struct ft_lport_acl *lport_acl; + struct ft_tport *tport; /* active tport or NULL */ + struct list_head list; /* linkage in ft_lport_acl tpg_list */ + struct list_head lun_list; /* head of LUNs */ + struct se_portal_group se_tpg; + struct task_struct *thread; /* processing thread */ + struct se_queue_obj qobj; /* queue for processing thread */ +}; + +struct ft_lport_acl { + u64 wwpn; + char name[FT_NAMELEN]; + struct list_head list; + struct list_head tpg_list; + struct se_wwn fc_lport_wwn; +}; + +enum ft_cmd_state { + FC_CMD_ST_NEW = 0, + FC_CMD_ST_REJ +}; + +/* + * Commands + */ +struct ft_cmd { + enum ft_cmd_state state; + u16 lun; /* LUN from request */ + struct ft_sess *sess; /* session held for cmd */ + struct fc_seq *seq; /* sequence in exchange mgr */ + struct se_cmd se_cmd; /* Local TCM I/O descriptor */ + struct fc_frame *req_frame; + unsigned char *cdb; /* pointer to CDB inside frame */ + u32 write_data_len; /* data received on writes */ + struct se_queue_req se_req; + /* Local sense buffer */ + unsigned char ft_sense_buffer[TRANSPORT_SENSE_BUFFER]; + u32 was_ddp_setup:1; /* Set only if ddp is setup */ + struct scatterlist *sg; /* Set only if DDP is setup */ + u32 sg_cnt; /* No. of item in scatterlist */ +}; + +extern struct list_head ft_lport_list; +extern struct mutex ft_lport_lock; +extern struct fc4_prov ft_prov; +extern struct target_fabric_configfs *ft_configfs; + +/* + * Fabric methods. + */ + +/* + * Session ops. + */ +void ft_sess_put(struct ft_sess *); +int ft_sess_shutdown(struct se_session *); +void ft_sess_close(struct se_session *); +void ft_sess_stop(struct se_session *, int, int); +int ft_sess_logged_in(struct se_session *); +u32 ft_sess_get_index(struct se_session *); +u32 ft_sess_get_port_name(struct se_session *, unsigned char *, u32); +void ft_sess_set_erl0(struct se_session *); + +void ft_lport_add(struct fc_lport *, void *); +void ft_lport_del(struct fc_lport *, void *); +int ft_lport_notify(struct notifier_block *, unsigned long, void *); + +/* + * IO methods. + */ +void ft_check_stop_free(struct se_cmd *); +void ft_release_cmd(struct se_cmd *); +int ft_queue_status(struct se_cmd *); +int ft_queue_data_in(struct se_cmd *); +int ft_write_pending(struct se_cmd *); +int ft_write_pending_status(struct se_cmd *); +u32 ft_get_task_tag(struct se_cmd *); +int ft_get_cmd_state(struct se_cmd *); +void ft_new_cmd_failure(struct se_cmd *); +int ft_queue_tm_resp(struct se_cmd *); +int ft_is_state_remove(struct se_cmd *); + +/* + * other internal functions. + */ +int ft_thread(void *); +void ft_recv_req(struct ft_sess *, struct fc_frame *); +struct ft_tpg *ft_lport_find_tpg(struct fc_lport *); +struct ft_node_acl *ft_acl_get(struct ft_tpg *, struct fc_rport_priv *); + +void ft_recv_write_data(struct ft_cmd *, struct fc_frame *); +void ft_dump_cmd(struct ft_cmd *, const char *caller); + +ssize_t ft_format_wwn(char *, size_t, u64); + +#endif /* __TCM_FC_H__ */ diff --git a/drivers/target/tcm_fc/tfc_cmd.c b/drivers/target/tcm_fc/tfc_cmd.c new file mode 100644 index 0000000..49e5177 --- /dev/null +++ b/drivers/target/tcm_fc/tfc_cmd.c @@ -0,0 +1,696 @@ +/* + * Copyright (c) 2010 Cisco Systems, Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions 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 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., + * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + */ + +/* XXX TBD some includes may be extraneous */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "tcm_fc.h" + +/* + * Dump cmd state for debugging. + */ +void ft_dump_cmd(struct ft_cmd *cmd, const char *caller) +{ + struct fc_exch *ep; + struct fc_seq *sp; + struct se_cmd *se_cmd; + struct se_mem *mem; + struct se_transport_task *task; + + if (!(ft_debug_logging & FT_DEBUG_IO)) + return; + + se_cmd = &cmd->se_cmd; + printk(KERN_INFO "%s: cmd %p state %d sess %p seq %p se_cmd %p\n", + caller, cmd, cmd->state, cmd->sess, cmd->seq, se_cmd); + printk(KERN_INFO "%s: cmd %p cdb %p\n", + caller, cmd, cmd->cdb); + printk(KERN_INFO "%s: cmd %p lun %d\n", caller, cmd, cmd->lun); + + task = T_TASK(se_cmd); + printk(KERN_INFO "%s: cmd %p task %p se_num %u buf %p len %u se_cmd_flags <0x%x>\n", + caller, cmd, task, task->t_tasks_se_num, + task->t_task_buf, se_cmd->data_length, se_cmd->se_cmd_flags); + if (task->t_mem_list) + list_for_each_entry(mem, task->t_mem_list, se_list) + printk(KERN_INFO "%s: cmd %p mem %p page %p " + "len 0x%x off 0x%x\n", + caller, cmd, mem, + mem->se_page, mem->se_len, mem->se_off); + sp = cmd->seq; + if (sp) { + ep = fc_seq_exch(sp); + printk(KERN_INFO "%s: cmd %p sid %x did %x " + "ox_id %x rx_id %x seq_id %x e_stat %x\n", + caller, cmd, ep->sid, ep->did, ep->oxid, ep->rxid, + sp->id, ep->esb_stat); + } + print_hex_dump(KERN_INFO, "ft_dump_cmd ", DUMP_PREFIX_NONE, + 16, 4, cmd->cdb, MAX_COMMAND_SIZE, 0); +} + +/* + * Get LUN from CDB. + */ +static int ft_get_lun_for_cmd(struct ft_cmd *cmd, u8 *lunp) +{ + u64 lun; + + lun = lunp[1]; + switch (lunp[0] >> 6) { + case 0: + break; + case 1: + lun |= (lunp[0] & 0x3f) << 8; + break; + default: + return -1; + } + if (lun >= TRANSPORT_MAX_LUNS_PER_TPG) + return -1; + cmd->lun = lun; + return transport_get_lun_for_cmd(&cmd->se_cmd, NULL, lun); +} + +static void ft_queue_cmd(struct ft_sess *sess, struct ft_cmd *cmd) +{ + struct se_queue_obj *qobj; + unsigned long flags; + + qobj = &sess->tport->tpg->qobj; + spin_lock_irqsave(&qobj->cmd_queue_lock, flags); + list_add_tail(&cmd->se_req.qr_list, &qobj->qobj_list); + spin_unlock_irqrestore(&qobj->cmd_queue_lock, flags); + atomic_inc(&qobj->queue_cnt); + wake_up_interruptible(&qobj->thread_wq); +} + +static struct ft_cmd *ft_dequeue_cmd(struct se_queue_obj *qobj) +{ + unsigned long flags; + struct se_queue_req *qr; + + spin_lock_irqsave(&qobj->cmd_queue_lock, flags); + if (list_empty(&qobj->qobj_list)) { + spin_unlock_irqrestore(&qobj->cmd_queue_lock, flags); + return NULL; + } + qr = list_first_entry(&qobj->qobj_list, struct se_queue_req, qr_list); + list_del(&qr->qr_list); + atomic_dec(&qobj->queue_cnt); + spin_unlock_irqrestore(&qobj->cmd_queue_lock, flags); + return container_of(qr, struct ft_cmd, se_req); +} + +static void ft_free_cmd(struct ft_cmd *cmd) +{ + struct fc_frame *fp; + struct fc_lport *lport; + + if (!cmd) + return; + fp = cmd->req_frame; + lport = fr_dev(fp); + if (fr_seq(fp)) + lport->tt.seq_release(fr_seq(fp)); + fc_frame_free(fp); + ft_sess_put(cmd->sess); /* undo get from lookup at recv */ + kfree(cmd); +} + +void ft_release_cmd(struct se_cmd *se_cmd) +{ + struct ft_cmd *cmd = container_of(se_cmd, struct ft_cmd, se_cmd); + + ft_free_cmd(cmd); +} + +void ft_check_stop_free(struct se_cmd *se_cmd) +{ + transport_generic_free_cmd(se_cmd, 0, 1, 0); +} + +/* + * Send response. + */ +int ft_queue_status(struct se_cmd *se_cmd) +{ + struct ft_cmd *cmd = container_of(se_cmd, struct ft_cmd, se_cmd); + struct fc_frame *fp; + struct fcp_resp_with_ext *fcp; + struct fc_lport *lport; + struct fc_exch *ep; + size_t len; + + ft_dump_cmd(cmd, __func__); + ep = fc_seq_exch(cmd->seq); + lport = ep->lp; + len = sizeof(*fcp) + se_cmd->scsi_sense_length; + fp = fc_frame_alloc(lport, len); + if (!fp) { + /* XXX shouldn't just drop it - requeue and retry? */ + return 0; + } + fcp = fc_frame_payload_get(fp, len); + memset(fcp, 0, len); + fcp->resp.fr_status = se_cmd->scsi_status; + + len = se_cmd->scsi_sense_length; + if (len) { + fcp->resp.fr_flags |= FCP_SNS_LEN_VAL; + fcp->ext.fr_sns_len = htonl(len); + memcpy((fcp + 1), se_cmd->sense_buffer, len); + } + + /* + * Test underflow and overflow with one mask. Usually both are off. + * Bidirectional commands are not handled yet. + */ + if (se_cmd->se_cmd_flags & (SCF_OVERFLOW_BIT | SCF_UNDERFLOW_BIT)) { + if (se_cmd->se_cmd_flags & SCF_OVERFLOW_BIT) + fcp->resp.fr_flags |= FCP_RESID_OVER; + else + fcp->resp.fr_flags |= FCP_RESID_UNDER; + fcp->ext.fr_resid = cpu_to_be32(se_cmd->residual_count); + } + + /* + * Send response. + */ + cmd->seq = lport->tt.seq_start_next(cmd->seq); + fc_fill_fc_hdr(fp, FC_RCTL_DD_CMD_STATUS, ep->did, ep->sid, FC_TYPE_FCP, + FC_FC_EX_CTX | FC_FC_LAST_SEQ | FC_FC_END_SEQ, 0); + + lport->tt.seq_send(lport, cmd->seq, fp); + lport->tt.exch_done(cmd->seq); + return 0; +} + +int ft_write_pending_status(struct se_cmd *se_cmd) +{ + struct ft_cmd *cmd = container_of(se_cmd, struct ft_cmd, se_cmd); + + return cmd->write_data_len != se_cmd->data_length; +} + +/* + * Send TX_RDY (transfer ready). + */ +int ft_write_pending(struct se_cmd *se_cmd) +{ + struct ft_cmd *cmd = container_of(se_cmd, struct ft_cmd, se_cmd); + struct fc_frame *fp; + struct fcp_txrdy *txrdy; + struct fc_lport *lport; + struct fc_exch *ep; + struct fc_frame_header *fh; + u32 f_ctl; + + ft_dump_cmd(cmd, __func__); + + ep = fc_seq_exch(cmd->seq); + lport = ep->lp; + fp = fc_frame_alloc(lport, sizeof(*txrdy)); + if (!fp) + return PYX_TRANSPORT_OUT_OF_MEMORY_RESOURCES; + + txrdy = fc_frame_payload_get(fp, sizeof(*txrdy)); + memset(txrdy, 0, sizeof(*txrdy)); + txrdy->ft_burst_len = htonl(se_cmd->data_length); + + cmd->seq = lport->tt.seq_start_next(cmd->seq); + fc_fill_fc_hdr(fp, FC_RCTL_DD_DATA_DESC, ep->did, ep->sid, FC_TYPE_FCP, + FC_FC_EX_CTX | FC_FC_END_SEQ | FC_FC_SEQ_INIT, 0); + + fh = fc_frame_header_get(fp); + f_ctl = ntoh24(fh->fh_f_ctl); + + /* Only if it is 'Exchange Responder' */ + if (f_ctl & FC_FC_EX_CTX) { + /* Target is 'exchange responder' and sending XFER_READY + * to 'exchange initiator (initiator)' + */ + if ((ep->xid <= lport->lro_xid) && + (fh->fh_r_ctl == FC_RCTL_DD_DATA_DESC)) { + if (se_cmd->se_cmd_flags & SCF_SCSI_DATA_SG_IO_CDB) { + /* + * Map se_mem list to scatterlist, so that + * DDP can be setup. DDP setup function require + * scatterlist. se_mem_list is internal to + * TCM/LIO target + */ + transport_do_task_sg_chain(se_cmd); + cmd->sg = T_TASK(se_cmd)->t_tasks_sg_chained; + cmd->sg_cnt = + T_TASK(se_cmd)->t_tasks_sg_chained_no; + } + if (cmd->sg && lport->tt.ddp_setup(lport, ep->xid, + cmd->sg, cmd->sg_cnt)) + cmd->was_ddp_setup = 1; + } + } + lport->tt.seq_send(lport, cmd->seq, fp); + return 0; +} + +u32 ft_get_task_tag(struct se_cmd *se_cmd) +{ + struct ft_cmd *cmd = container_of(se_cmd, struct ft_cmd, se_cmd); + + return fc_seq_exch(cmd->seq)->rxid; +} + +int ft_get_cmd_state(struct se_cmd *se_cmd) +{ + struct ft_cmd *cmd = container_of(se_cmd, struct ft_cmd, se_cmd); + + return cmd->state; +} + +int ft_is_state_remove(struct se_cmd *se_cmd) +{ + return 0; /* XXX TBD */ +} + +void ft_new_cmd_failure(struct se_cmd *se_cmd) +{ + /* XXX TBD */ + printk(KERN_INFO "%s: se_cmd %p\n", __func__, se_cmd); +} + +/* + * FC sequence response handler for follow-on sequences (data) and aborts. + */ +static void ft_recv_seq(struct fc_seq *sp, struct fc_frame *fp, void *arg) +{ + struct ft_cmd *cmd = arg; + struct fc_frame_header *fh; + + if (IS_ERR(fp)) { + /* XXX need to find cmd if queued */ + cmd->se_cmd.t_state = TRANSPORT_REMOVE; + cmd->seq = NULL; + transport_generic_free_cmd(&cmd->se_cmd, 0, 1, 0); + return; + } + + fh = fc_frame_header_get(fp); + + switch (fh->fh_r_ctl) { + case FC_RCTL_DD_SOL_DATA: /* write data */ + ft_recv_write_data(cmd, fp); + break; + case FC_RCTL_DD_UNSOL_CTL: /* command */ + case FC_RCTL_DD_SOL_CTL: /* transfer ready */ + case FC_RCTL_DD_DATA_DESC: /* transfer ready */ + default: + printk(KERN_INFO "%s: unhandled frame r_ctl %x\n", + __func__, fh->fh_r_ctl); + fc_frame_free(fp); + transport_generic_free_cmd(&cmd->se_cmd, 0, 1, 0); + break; + } +} + +/* + * Send a FCP response including SCSI status and optional FCP rsp_code. + * status is SAM_STAT_GOOD (zero) iff code is valid. + * This is used in error cases, such as allocation failures. + */ +static void ft_send_resp_status(struct fc_lport *lport, + const struct fc_frame *rx_fp, + u32 status, enum fcp_resp_rsp_codes code) +{ + struct fc_frame *fp; + struct fc_seq *sp; + const struct fc_frame_header *fh; + size_t len; + struct fcp_resp_with_ext *fcp; + struct fcp_resp_rsp_info *info; + + fh = fc_frame_header_get(rx_fp); + FT_IO_DBG("FCP error response: did %x oxid %x status %x code %x\n", + ntoh24(fh->fh_s_id), ntohs(fh->fh_ox_id), status, code); + len = sizeof(*fcp); + if (status == SAM_STAT_GOOD) + len += sizeof(*info); + fp = fc_frame_alloc(lport, len); + if (!fp) + return; + fcp = fc_frame_payload_get(fp, len); + memset(fcp, 0, len); + fcp->resp.fr_status = status; + if (status == SAM_STAT_GOOD) { + fcp->ext.fr_rsp_len = htonl(sizeof(*info)); + fcp->resp.fr_flags |= FCP_RSP_LEN_VAL; + info = (struct fcp_resp_rsp_info *)(fcp + 1); + info->rsp_code = code; + } + + fc_fill_reply_hdr(fp, rx_fp, FC_RCTL_DD_CMD_STATUS, 0); + sp = fr_seq(fp); + if (sp) + lport->tt.seq_send(lport, sp, fp); + else + lport->tt.frame_send(lport, fp); +} + +/* + * Send error or task management response. + * Always frees the cmd and associated state. + */ +static void ft_send_resp_code(struct ft_cmd *cmd, enum fcp_resp_rsp_codes code) +{ + ft_send_resp_status(cmd->sess->tport->lport, + cmd->req_frame, SAM_STAT_GOOD, code); + ft_free_cmd(cmd); +} + +/* + * Handle Task Management Request. + */ +static void ft_send_tm(struct ft_cmd *cmd) +{ + struct se_tmr_req *tmr; + struct fcp_cmnd *fcp; + u8 tm_func; + + fcp = fc_frame_payload_get(cmd->req_frame, sizeof(*fcp)); + + switch (fcp->fc_tm_flags) { + case FCP_TMF_LUN_RESET: + tm_func = TMR_LUN_RESET; + if (ft_get_lun_for_cmd(cmd, fcp->fc_lun) < 0) { + ft_dump_cmd(cmd, __func__); + transport_send_check_condition_and_sense(&cmd->se_cmd, + cmd->se_cmd.scsi_sense_reason, 0); + ft_sess_put(cmd->sess); + return; + } + break; + case FCP_TMF_TGT_RESET: + tm_func = TMR_TARGET_WARM_RESET; + break; + case FCP_TMF_CLR_TASK_SET: + tm_func = TMR_CLEAR_TASK_SET; + break; + case FCP_TMF_ABT_TASK_SET: + tm_func = TMR_ABORT_TASK_SET; + break; + case FCP_TMF_CLR_ACA: + tm_func = TMR_CLEAR_ACA; + break; + default: + /* + * FCP4r01 indicates having a combination of + * tm_flags set is invalid. + */ + FT_TM_DBG("invalid FCP tm_flags %x\n", fcp->fc_tm_flags); + ft_send_resp_code(cmd, FCP_CMND_FIELDS_INVALID); + return; + } + + FT_TM_DBG("alloc tm cmd fn %d\n", tm_func); + tmr = core_tmr_alloc_req(&cmd->se_cmd, cmd, tm_func); + if (!tmr) { + FT_TM_DBG("alloc failed\n"); + ft_send_resp_code(cmd, FCP_TMF_FAILED); + return; + } + cmd->se_cmd.se_tmr_req = tmr; + transport_generic_handle_tmr(&cmd->se_cmd); +} + +/* + * Send status from completed task management request. + */ +int ft_queue_tm_resp(struct se_cmd *se_cmd) +{ + struct ft_cmd *cmd = container_of(se_cmd, struct ft_cmd, se_cmd); + struct se_tmr_req *tmr = se_cmd->se_tmr_req; + enum fcp_resp_rsp_codes code; + + switch (tmr->response) { + case TMR_FUNCTION_COMPLETE: + code = FCP_TMF_CMPL; + break; + case TMR_LUN_DOES_NOT_EXIST: + code = FCP_TMF_INVALID_LUN; + break; + case TMR_FUNCTION_REJECTED: + code = FCP_TMF_REJECTED; + break; + case TMR_TASK_DOES_NOT_EXIST: + case TMR_TASK_STILL_ALLEGIANT: + case TMR_TASK_FAILOVER_NOT_SUPPORTED: + case TMR_TASK_MGMT_FUNCTION_NOT_SUPPORTED: + case TMR_FUNCTION_AUTHORIZATION_FAILED: + default: + code = FCP_TMF_FAILED; + break; + } + FT_TM_DBG("tmr fn %d resp %d fcp code %d\n", + tmr->function, tmr->response, code); + ft_send_resp_code(cmd, code); + return 0; +} + +/* + * Handle incoming FCP command. + */ +static void ft_recv_cmd(struct ft_sess *sess, struct fc_frame *fp) +{ + struct ft_cmd *cmd; + struct fc_lport *lport = sess->tport->lport; + + cmd = kzalloc(sizeof(*cmd), GFP_ATOMIC); + if (!cmd) + goto busy; + cmd->sess = sess; + cmd->seq = lport->tt.seq_assign(lport, fp); + if (!cmd->seq) { + kfree(cmd); + goto busy; + } + cmd->req_frame = fp; /* hold frame during cmd */ + ft_queue_cmd(sess, cmd); + return; + +busy: + FT_IO_DBG("cmd or seq allocation failure - sending BUSY\n"); + ft_send_resp_status(lport, fp, SAM_STAT_BUSY, 0); + fc_frame_free(fp); + ft_sess_put(sess); /* undo get from lookup */ +} + + +/* + * Handle incoming FCP frame. + * Caller has verified that the frame is type FCP. + */ +void ft_recv_req(struct ft_sess *sess, struct fc_frame *fp) +{ + struct fc_frame_header *fh = fc_frame_header_get(fp); + + switch (fh->fh_r_ctl) { + case FC_RCTL_DD_UNSOL_CMD: /* command */ + ft_recv_cmd(sess, fp); + break; + case FC_RCTL_DD_SOL_DATA: /* write data */ + case FC_RCTL_DD_UNSOL_CTL: + case FC_RCTL_DD_SOL_CTL: + case FC_RCTL_DD_DATA_DESC: /* transfer ready */ + case FC_RCTL_ELS4_REQ: /* SRR, perhaps */ + default: + printk(KERN_INFO "%s: unhandled frame r_ctl %x\n", + __func__, fh->fh_r_ctl); + fc_frame_free(fp); + ft_sess_put(sess); /* undo get from lookup */ + break; + } +} + +/* + * Send new command to target. + */ +static void ft_send_cmd(struct ft_cmd *cmd) +{ + struct fc_frame_header *fh = fc_frame_header_get(cmd->req_frame); + struct se_cmd *se_cmd; + struct fcp_cmnd *fcp; + int data_dir; + u32 data_len; + int task_attr; + int ret; + + fcp = fc_frame_payload_get(cmd->req_frame, sizeof(*fcp)); + if (!fcp) + goto err; + + if (fcp->fc_flags & FCP_CFL_LEN_MASK) + goto err; /* not handling longer CDBs yet */ + + if (fcp->fc_tm_flags) { + task_attr = FCP_PTA_SIMPLE; + data_dir = DMA_NONE; + data_len = 0; + } else { + switch (fcp->fc_flags & (FCP_CFL_RDDATA | FCP_CFL_WRDATA)) { + case 0: + data_dir = DMA_NONE; + break; + case FCP_CFL_RDDATA: + data_dir = DMA_FROM_DEVICE; + break; + case FCP_CFL_WRDATA: + data_dir = DMA_TO_DEVICE; + break; + case FCP_CFL_WRDATA | FCP_CFL_RDDATA: + goto err; /* TBD not supported by tcm_fc yet */ + } + + /* FCP_PTA_ maps 1:1 to TASK_ATTR_ */ + task_attr = fcp->fc_pri_ta & FCP_PTA_MASK; + data_len = ntohl(fcp->fc_dl); + cmd->cdb = fcp->fc_cdb; + } + + se_cmd = &cmd->se_cmd; + /* + * Initialize struct se_cmd descriptor from target_core_mod + * infrastructure + */ + transport_init_se_cmd(se_cmd, &ft_configfs->tf_ops, cmd->sess->se_sess, + data_len, data_dir, task_attr, + &cmd->ft_sense_buffer[0]); + /* + * Check for FCP task management flags + */ + if (fcp->fc_tm_flags) { + ft_send_tm(cmd); + return; + } + + fc_seq_exch(cmd->seq)->lp->tt.seq_set_resp(cmd->seq, ft_recv_seq, cmd); + + ret = ft_get_lun_for_cmd(cmd, fcp->fc_lun); + if (ret < 0) { + ft_dump_cmd(cmd, __func__); + transport_send_check_condition_and_sense(&cmd->se_cmd, + cmd->se_cmd.scsi_sense_reason, 0); + return; + } + + ret = transport_generic_allocate_tasks(se_cmd, cmd->cdb); + + FT_IO_DBG("r_ctl %x alloc task ret %d\n", fh->fh_r_ctl, ret); + ft_dump_cmd(cmd, __func__); + + if (ret == -1) { + transport_send_check_condition_and_sense(se_cmd, + TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE, 0); + transport_generic_free_cmd(se_cmd, 0, 1, 0); + return; + } + if (ret == -2) { + if (se_cmd->se_cmd_flags & SCF_SCSI_RESERVATION_CONFLICT) + ft_queue_status(se_cmd); + else + transport_send_check_condition_and_sense(se_cmd, + se_cmd->scsi_sense_reason, 0); + transport_generic_free_cmd(se_cmd, 0, 1, 0); + return; + } + transport_generic_handle_cdb(se_cmd); + return; + +err: + ft_send_resp_code(cmd, FCP_CMND_FIELDS_INVALID); + return; +} + +/* + * Handle request in the command thread. + */ +static void ft_exec_req(struct ft_cmd *cmd) +{ + FT_IO_DBG("cmd state %x\n", cmd->state); + switch (cmd->state) { + case FC_CMD_ST_NEW: + ft_send_cmd(cmd); + break; + default: + break; + } +} + +/* + * Processing thread. + * Currently one thread per tpg. + */ +int ft_thread(void *arg) +{ + struct ft_tpg *tpg = arg; + struct se_queue_obj *qobj = &tpg->qobj; + struct ft_cmd *cmd; + int ret; + + set_user_nice(current, -20); + + while (!kthread_should_stop()) { + ret = wait_event_interruptible(qobj->thread_wq, + atomic_read(&qobj->queue_cnt) || kthread_should_stop()); + if (ret < 0 || kthread_should_stop()) + goto out; + cmd = ft_dequeue_cmd(qobj); + if (cmd) + ft_exec_req(cmd); + } + +out: + return 0; +} diff --git a/drivers/target/tcm_fc/tfc_conf.c b/drivers/target/tcm_fc/tfc_conf.c new file mode 100644 index 0000000..fcdbbff --- /dev/null +++ b/drivers/target/tcm_fc/tfc_conf.c @@ -0,0 +1,677 @@ +/******************************************************************************* + * Filename: tcm_fc.c + * + * This file contains the configfs implementation for TCM_fc fabric node. + * Based on tcm_loop_configfs.c + * + * Copyright (c) 2010 Cisco Systems, Inc. + * Copyright (c) 2009,2010 Rising Tide, Inc. + * Copyright (c) 2009,2010 Linux-iSCSI.org + * + * Copyright (c) 2009,2010 Nicholas A. Bellinger + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + ****************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "tcm_fc.h" + +struct target_fabric_configfs *ft_configfs; + +LIST_HEAD(ft_lport_list); +DEFINE_MUTEX(ft_lport_lock); + +unsigned int ft_debug_logging; +module_param_named(debug_logging, ft_debug_logging, int, S_IRUGO|S_IWUSR); +MODULE_PARM_DESC(debug_logging, "a bit mask of logging levels"); + +/* + * Parse WWN. + * If strict, we require lower-case hex and colon separators to be sure + * the name is the same as what would be generated by ft_format_wwn() + * so the name and wwn are mapped one-to-one. + */ +static ssize_t ft_parse_wwn(const char *name, u64 *wwn, int strict) +{ + const char *cp; + char c; + u32 nibble; + u32 byte = 0; + u32 pos = 0; + u32 err; + + *wwn = 0; + for (cp = name; cp < &name[FT_NAMELEN - 1]; cp++) { + c = *cp; + if (c == '\n' && cp[1] == '\0') + continue; + if (strict && pos++ == 2 && byte++ < 7) { + pos = 0; + if (c == ':') + continue; + err = 1; + goto fail; + } + if (c == '\0') { + err = 2; + if (strict && byte != 8) + goto fail; + return cp - name; + } + err = 3; + if (isdigit(c)) + nibble = c - '0'; + else if (isxdigit(c) && (islower(c) || !strict)) + nibble = tolower(c) - 'a' + 10; + else + goto fail; + *wwn = (*wwn << 4) | nibble; + } + err = 4; +fail: + FT_CONF_DBG("err %u len %zu pos %u byte %u\n", + err, cp - name, pos, byte); + return -1; +} + +ssize_t ft_format_wwn(char *buf, size_t len, u64 wwn) +{ + u8 b[8]; + + put_unaligned_be64(wwn, b); + return snprintf(buf, len, + "%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x", + b[0], b[1], b[2], b[3], b[4], b[5], b[6], b[7]); +} + +static ssize_t ft_wwn_show(void *arg, char *buf) +{ + u64 *wwn = arg; + ssize_t len; + + len = ft_format_wwn(buf, PAGE_SIZE - 2, *wwn); + buf[len++] = '\n'; + return len; +} + +static ssize_t ft_wwn_store(void *arg, const char *buf, size_t len) +{ + ssize_t ret; + u64 wwn; + + ret = ft_parse_wwn(buf, &wwn, 0); + if (ret > 0) + *(u64 *)arg = wwn; + return ret; +} + +/* + * ACL auth ops. + */ + +static ssize_t ft_nacl_show_port_name( + struct se_node_acl *se_nacl, + char *page) +{ + struct ft_node_acl *acl = container_of(se_nacl, + struct ft_node_acl, se_node_acl); + + return ft_wwn_show(&acl->node_auth.port_name, page); +} + +static ssize_t ft_nacl_store_port_name( + struct se_node_acl *se_nacl, + const char *page, + size_t count) +{ + struct ft_node_acl *acl = container_of(se_nacl, + struct ft_node_acl, se_node_acl); + + return ft_wwn_store(&acl->node_auth.port_name, page, count); +} + +TF_NACL_BASE_ATTR(ft, port_name, S_IRUGO | S_IWUSR); + +static ssize_t ft_nacl_show_node_name( + struct se_node_acl *se_nacl, + char *page) +{ + struct ft_node_acl *acl = container_of(se_nacl, + struct ft_node_acl, se_node_acl); + + return ft_wwn_show(&acl->node_auth.node_name, page); +} + +static ssize_t ft_nacl_store_node_name( + struct se_node_acl *se_nacl, + const char *page, + size_t count) +{ + struct ft_node_acl *acl = container_of(se_nacl, + struct ft_node_acl, se_node_acl); + + return ft_wwn_store(&acl->node_auth.node_name, page, count); +} + +TF_NACL_BASE_ATTR(ft, node_name, S_IRUGO | S_IWUSR); + +static struct configfs_attribute *ft_nacl_base_attrs[] = { + &ft_nacl_port_name.attr, + &ft_nacl_node_name.attr, + NULL, +}; + +/* + * ACL ops. + */ + +/* + * Add ACL for an initiator. The ACL is named arbitrarily. + * The port_name and/or node_name are attributes. + */ +static struct se_node_acl *ft_add_acl( + struct se_portal_group *se_tpg, + struct config_group *group, + const char *name) +{ + struct ft_node_acl *acl; + struct ft_tpg *tpg; + u64 wwpn; + u32 q_depth; + + FT_CONF_DBG("add acl %s\n", name); + tpg = container_of(se_tpg, struct ft_tpg, se_tpg); + + if (ft_parse_wwn(name, &wwpn, 1) < 0) + return ERR_PTR(-EINVAL); + + acl = kzalloc(sizeof(struct ft_node_acl), GFP_KERNEL); + if (!(acl)) + return ERR_PTR(-ENOMEM); + acl->node_auth.port_name = wwpn; + + q_depth = 32; /* XXX bogus default - get from tpg? */ + return core_tpg_add_initiator_node_acl(&tpg->se_tpg, + &acl->se_node_acl, name, q_depth); +} + +static void ft_del_acl(struct se_node_acl *se_acl) +{ + struct se_portal_group *se_tpg = se_acl->se_tpg; + struct ft_tpg *tpg; + struct ft_node_acl *acl = container_of(se_acl, + struct ft_node_acl, se_node_acl); + + FT_CONF_DBG("del acl %s\n", + config_item_name(&se_acl->acl_group.cg_item)); + + tpg = container_of(se_tpg, struct ft_tpg, se_tpg); + FT_CONF_DBG("del acl %p se_acl %p tpg %p se_tpg %p\n", + acl, se_acl, tpg, &tpg->se_tpg); + + core_tpg_del_initiator_node_acl(&tpg->se_tpg, se_acl, 1); + kfree(acl); +} + +struct ft_node_acl *ft_acl_get(struct ft_tpg *tpg, struct fc_rport_priv *rdata) +{ + struct ft_node_acl *found = NULL; + struct ft_node_acl *acl; + struct se_portal_group *se_tpg = &tpg->se_tpg; + struct se_node_acl *se_acl; + + spin_lock_bh(&se_tpg->acl_node_lock); + list_for_each_entry(se_acl, &se_tpg->acl_node_list, acl_list) { + acl = container_of(se_acl, struct ft_node_acl, se_node_acl); + FT_CONF_DBG("acl %p port_name %llx\n", + acl, (unsigned long long)acl->node_auth.port_name); + if (acl->node_auth.port_name == rdata->ids.port_name || + acl->node_auth.node_name == rdata->ids.node_name) { + FT_CONF_DBG("acl %p port_name %llx matched\n", acl, + (unsigned long long)rdata->ids.port_name); + found = acl; + /* XXX need to hold onto ACL */ + break; + } + } + spin_unlock_bh(&se_tpg->acl_node_lock); + return found; +} + +struct se_node_acl *ft_tpg_alloc_fabric_acl(struct se_portal_group *se_tpg) +{ + struct ft_node_acl *acl; + + acl = kzalloc(sizeof(*acl), GFP_KERNEL); + if (!(acl)) { + printk(KERN_ERR "Unable to allocate struct ft_node_acl\n"); + return NULL; + } + FT_CONF_DBG("acl %p\n", acl); + return &acl->se_node_acl; +} + +static void ft_tpg_release_fabric_acl(struct se_portal_group *se_tpg, + struct se_node_acl *se_acl) +{ + struct ft_node_acl *acl = container_of(se_acl, + struct ft_node_acl, se_node_acl); + + FT_CONF_DBG(KERN_INFO "acl %p\n", acl); + kfree(acl); +} + +/* + * local_port port_group (tpg) ops. + */ +static struct se_portal_group *ft_add_tpg( + struct se_wwn *wwn, + struct config_group *group, + const char *name) +{ + struct ft_lport_acl *lacl; + struct ft_tpg *tpg; + unsigned long index; + int ret; + + FT_CONF_DBG("tcm_fc: add tpg %s\n", name); + + /* + * Name must be "tpgt_" followed by the index. + */ + if (strstr(name, "tpgt_") != name) + return NULL; + if (strict_strtoul(name + 5, 10, &index) || index > UINT_MAX) + return NULL; + + lacl = container_of(wwn, struct ft_lport_acl, fc_lport_wwn); + tpg = kzalloc(sizeof(*tpg), GFP_KERNEL); + if (!tpg) + return NULL; + tpg->index = index; + tpg->lport_acl = lacl; + INIT_LIST_HEAD(&tpg->lun_list); + transport_init_queue_obj(&tpg->qobj); + + ret = core_tpg_register(&ft_configfs->tf_ops, wwn, &tpg->se_tpg, + (void *)tpg, TRANSPORT_TPG_TYPE_NORMAL); + if (ret < 0) { + kfree(tpg); + return NULL; + } + + tpg->thread = kthread_run(ft_thread, tpg, "ft_tpg%lu", index); + if (IS_ERR(tpg->thread)) { + kfree(tpg); + return NULL; + } + + mutex_lock(&ft_lport_lock); + list_add_tail(&tpg->list, &lacl->tpg_list); + mutex_unlock(&ft_lport_lock); + + return &tpg->se_tpg; +} + +static void ft_del_tpg(struct se_portal_group *se_tpg) +{ + struct ft_tpg *tpg = container_of(se_tpg, struct ft_tpg, se_tpg); + + FT_CONF_DBG("del tpg %s\n", + config_item_name(&tpg->se_tpg.tpg_group.cg_item)); + + kthread_stop(tpg->thread); + + /* Wait for sessions to be freed thru RCU, for BUG_ON below */ + synchronize_rcu(); + + mutex_lock(&ft_lport_lock); + list_del(&tpg->list); + if (tpg->tport) { + tpg->tport->tpg = NULL; + tpg->tport = NULL; + } + mutex_unlock(&ft_lport_lock); + + core_tpg_deregister(se_tpg); + kfree(tpg); +} + +/* + * Verify that an lport is configured to use the tcm_fc module, and return + * the target port group that should be used. + * + * The caller holds ft_lport_lock. + */ +struct ft_tpg *ft_lport_find_tpg(struct fc_lport *lport) +{ + struct ft_lport_acl *lacl; + struct ft_tpg *tpg; + + list_for_each_entry(lacl, &ft_lport_list, list) { + if (lacl->wwpn == lport->wwpn) { + list_for_each_entry(tpg, &lacl->tpg_list, list) + return tpg; /* XXX for now return first entry */ + return NULL; + } + } + return NULL; +} + +/* + * target config instance ops. + */ + +/* + * Add lport to allowed config. + * The name is the WWPN in lower-case ASCII, colon-separated bytes. + */ +static struct se_wwn *ft_add_lport( + struct target_fabric_configfs *tf, + struct config_group *group, + const char *name) +{ + struct ft_lport_acl *lacl; + struct ft_lport_acl *old_lacl; + u64 wwpn; + + FT_CONF_DBG("add lport %s\n", name); + if (ft_parse_wwn(name, &wwpn, 1) < 0) + return NULL; + lacl = kzalloc(sizeof(*lacl), GFP_KERNEL); + if (!lacl) + return NULL; + lacl->wwpn = wwpn; + INIT_LIST_HEAD(&lacl->tpg_list); + + mutex_lock(&ft_lport_lock); + list_for_each_entry(old_lacl, &ft_lport_list, list) { + if (old_lacl->wwpn == wwpn) { + mutex_unlock(&ft_lport_lock); + kfree(lacl); + return NULL; + } + } + list_add_tail(&lacl->list, &ft_lport_list); + ft_format_wwn(lacl->name, sizeof(lacl->name), wwpn); + mutex_unlock(&ft_lport_lock); + + return &lacl->fc_lport_wwn; +} + +static void ft_del_lport(struct se_wwn *wwn) +{ + struct ft_lport_acl *lacl = container_of(wwn, + struct ft_lport_acl, fc_lport_wwn); + + FT_CONF_DBG("del lport %s\n", + config_item_name(&wwn->wwn_group.cg_item)); + mutex_lock(&ft_lport_lock); + list_del(&lacl->list); + mutex_unlock(&ft_lport_lock); + + kfree(lacl); +} + +static ssize_t ft_wwn_show_attr_version( + struct target_fabric_configfs *tf, + char *page) +{ + return sprintf(page, "TCM FC " FT_VERSION " on %s/%s on " + ""UTS_RELEASE"\n", utsname()->sysname, utsname()->machine); +} + +TF_WWN_ATTR_RO(ft, version); + +static struct configfs_attribute *ft_wwn_attrs[] = { + &ft_wwn_version.attr, + NULL, +}; + +static char *ft_get_fabric_name(void) +{ + return "fc"; +} + +static char *ft_get_fabric_wwn(struct se_portal_group *se_tpg) +{ + struct ft_tpg *tpg = se_tpg->se_tpg_fabric_ptr; + + return tpg->lport_acl->name; +} + +static u16 ft_get_tag(struct se_portal_group *se_tpg) +{ + struct ft_tpg *tpg = se_tpg->se_tpg_fabric_ptr; + + /* + * This tag is used when forming SCSI Name identifier in EVPD=1 0x83 + * to represent the SCSI Target Port. + */ + return tpg->index; +} + +static u32 ft_get_default_depth(struct se_portal_group *se_tpg) +{ + return 1; +} + +static int ft_check_false(struct se_portal_group *se_tpg) +{ + return 0; +} + +static void ft_set_default_node_attr(struct se_node_acl *se_nacl) +{ +} + +static u16 ft_get_fabric_sense_len(void) +{ + return 0; +} + +static u16 ft_set_fabric_sense_len(struct se_cmd *se_cmd, u32 sense_len) +{ + return 0; +} + +static u32 ft_tpg_get_inst_index(struct se_portal_group *se_tpg) +{ + struct ft_tpg *tpg = se_tpg->se_tpg_fabric_ptr; + + return tpg->index; +} + +static u64 ft_pack_lun(unsigned int index) +{ + WARN_ON(index >= 256); + /* Caller wants this byte-swapped */ + return cpu_to_le64((index & 0xff) << 8); +} + +static struct target_core_fabric_ops ft_fabric_ops = { + .get_fabric_name = ft_get_fabric_name, + .get_fabric_proto_ident = fc_get_fabric_proto_ident, + .tpg_get_wwn = ft_get_fabric_wwn, + .tpg_get_tag = ft_get_tag, + .tpg_get_default_depth = ft_get_default_depth, + .tpg_get_pr_transport_id = fc_get_pr_transport_id, + .tpg_get_pr_transport_id_len = fc_get_pr_transport_id_len, + .tpg_parse_pr_out_transport_id = fc_parse_pr_out_transport_id, + .tpg_check_demo_mode = ft_check_false, + .tpg_check_demo_mode_cache = ft_check_false, + .tpg_check_demo_mode_write_protect = ft_check_false, + .tpg_check_prod_mode_write_protect = ft_check_false, + .tpg_alloc_fabric_acl = ft_tpg_alloc_fabric_acl, + .tpg_release_fabric_acl = ft_tpg_release_fabric_acl, + .tpg_get_inst_index = ft_tpg_get_inst_index, + .check_stop_free = ft_check_stop_free, + .release_cmd_to_pool = ft_release_cmd, + .release_cmd_direct = ft_release_cmd, + .shutdown_session = ft_sess_shutdown, + .close_session = ft_sess_close, + .stop_session = ft_sess_stop, + .fall_back_to_erl0 = ft_sess_set_erl0, + .sess_logged_in = ft_sess_logged_in, + .sess_get_index = ft_sess_get_index, + .sess_get_initiator_sid = NULL, + .write_pending = ft_write_pending, + .write_pending_status = ft_write_pending_status, + .set_default_node_attributes = ft_set_default_node_attr, + .get_task_tag = ft_get_task_tag, + .get_cmd_state = ft_get_cmd_state, + .new_cmd_failure = ft_new_cmd_failure, + .queue_data_in = ft_queue_data_in, + .queue_status = ft_queue_status, + .queue_tm_rsp = ft_queue_tm_resp, + .get_fabric_sense_len = ft_get_fabric_sense_len, + .set_fabric_sense_len = ft_set_fabric_sense_len, + .is_state_remove = ft_is_state_remove, + .pack_lun = ft_pack_lun, + /* + * Setup function pointers for generic logic in + * target_core_fabric_configfs.c + */ + .fabric_make_wwn = &ft_add_lport, + .fabric_drop_wwn = &ft_del_lport, + .fabric_make_tpg = &ft_add_tpg, + .fabric_drop_tpg = &ft_del_tpg, + .fabric_post_link = NULL, + .fabric_pre_unlink = NULL, + .fabric_make_np = NULL, + .fabric_drop_np = NULL, + .fabric_make_nodeacl = &ft_add_acl, + .fabric_drop_nodeacl = &ft_del_acl, +}; + +int ft_register_configfs(void) +{ + struct target_fabric_configfs *fabric; + int ret; + + /* + * Register the top level struct config_item_type with TCM core + */ + fabric = target_fabric_configfs_init(THIS_MODULE, "fc"); + if (!fabric) { + printk(KERN_INFO "%s: target_fabric_configfs_init() failed!\n", + __func__); + return -1; + } + fabric->tf_ops = ft_fabric_ops; + + /* Allowing support for task_sg_chaining */ + fabric->tf_ops.task_sg_chaining = 1; + + /* + * Setup default attribute lists for various fabric->tf_cit_tmpl + */ + TF_CIT_TMPL(fabric)->tfc_wwn_cit.ct_attrs = ft_wwn_attrs; + TF_CIT_TMPL(fabric)->tfc_tpg_base_cit.ct_attrs = NULL; + TF_CIT_TMPL(fabric)->tfc_tpg_attrib_cit.ct_attrs = NULL; + TF_CIT_TMPL(fabric)->tfc_tpg_param_cit.ct_attrs = NULL; + TF_CIT_TMPL(fabric)->tfc_tpg_np_base_cit.ct_attrs = NULL; + TF_CIT_TMPL(fabric)->tfc_tpg_nacl_base_cit.ct_attrs = + ft_nacl_base_attrs; + TF_CIT_TMPL(fabric)->tfc_tpg_nacl_attrib_cit.ct_attrs = NULL; + TF_CIT_TMPL(fabric)->tfc_tpg_nacl_auth_cit.ct_attrs = NULL; + TF_CIT_TMPL(fabric)->tfc_tpg_nacl_param_cit.ct_attrs = NULL; + /* + * register the fabric for use within TCM + */ + ret = target_fabric_configfs_register(fabric); + if (ret < 0) { + FT_CONF_DBG("target_fabric_configfs_register() for" + " FC Target failed!\n"); + printk(KERN_INFO + "%s: target_fabric_configfs_register() failed!\n", + __func__); + target_fabric_configfs_free(fabric); + return -1; + } + + /* + * Setup our local pointer to *fabric. + */ + ft_configfs = fabric; + return 0; +} + +void ft_deregister_configfs(void) +{ + if (!ft_configfs) + return; + target_fabric_configfs_deregister(ft_configfs); + ft_configfs = NULL; +} + +static struct notifier_block ft_notifier = { + .notifier_call = ft_lport_notify +}; + +static int __init ft_init(void) +{ + if (ft_register_configfs()) + return -1; + if (fc_fc4_register_provider(FC_TYPE_FCP, &ft_prov)) { + ft_deregister_configfs(); + return -1; + } + blocking_notifier_chain_register(&fc_lport_notifier_head, &ft_notifier); + fc_lport_iterate(ft_lport_add, NULL); + return 0; +} + +static void __exit ft_exit(void) +{ + blocking_notifier_chain_unregister(&fc_lport_notifier_head, + &ft_notifier); + fc_fc4_deregister_provider(FC_TYPE_FCP, &ft_prov); + fc_lport_iterate(ft_lport_del, NULL); + ft_deregister_configfs(); + synchronize_rcu(); +} + +#ifdef MODULE +MODULE_DESCRIPTION("FC TCM fabric driver " FT_VERSION); +MODULE_LICENSE("GPL"); +module_init(ft_init); +module_exit(ft_exit); +#endif /* MODULE */ diff --git a/drivers/target/tcm_fc/tfc_io.c b/drivers/target/tcm_fc/tfc_io.c new file mode 100644 index 0000000..4c3c0ef --- /dev/null +++ b/drivers/target/tcm_fc/tfc_io.c @@ -0,0 +1,374 @@ +/* + * Copyright (c) 2010 Cisco Systems, Inc. + * + * Portions based on tcm_loop_fabric_scsi.c and libfc/fc_fcp.c + * + * Copyright (c) 2007 Intel Corporation. All rights reserved. + * Copyright (c) 2008 Red Hat, Inc. All rights reserved. + * Copyright (c) 2008 Mike Christie + * Copyright (c) 2009 Rising Tide, Inc. + * Copyright (c) 2009 Linux-iSCSI.org + * Copyright (c) 2009 Nicholas A. Bellinger + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions 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 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., + * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + */ + +/* XXX TBD some includes may be extraneous */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "tcm_fc.h" + +/* + * Deliver read data back to initiator. + * XXX TBD handle resource problems later. + */ +int ft_queue_data_in(struct se_cmd *se_cmd) +{ + struct ft_cmd *cmd = container_of(se_cmd, struct ft_cmd, se_cmd); + struct se_transport_task *task; + struct fc_frame *fp = NULL; + struct fc_exch *ep; + struct fc_lport *lport; + struct se_mem *mem; + size_t remaining; + u32 f_ctl = FC_FC_EX_CTX | FC_FC_REL_OFF; + u32 mem_off; + u32 fh_off = 0; + u32 frame_off = 0; + size_t frame_len = 0; + size_t mem_len; + size_t tlen; + size_t off_in_page; + struct page *page; + int use_sg; + int error; + void *page_addr; + void *from; + void *to = NULL; + + ep = fc_seq_exch(cmd->seq); + lport = ep->lp; + cmd->seq = lport->tt.seq_start_next(cmd->seq); + + task = T_TASK(se_cmd); + BUG_ON(!task); + remaining = se_cmd->data_length; + + /* + * Setup to use first mem list entry if any. + */ + if (task->t_tasks_se_num) { + mem = list_first_entry(task->t_mem_list, + struct se_mem, se_list); + mem_len = mem->se_len; + mem_off = mem->se_off; + page = mem->se_page; + } else { + mem = NULL; + mem_len = remaining; + mem_off = 0; + page = NULL; + } + + /* no scatter/gather in skb for odd word length due to fc_seq_send() */ + use_sg = !(remaining % 4); + + while (remaining) { + if (!mem_len) { + BUG_ON(!mem); + mem = list_entry(mem->se_list.next, + struct se_mem, se_list); + mem_len = min((size_t)mem->se_len, remaining); + mem_off = mem->se_off; + page = mem->se_page; + } + if (!frame_len) { + /* + * If lport's has capability of Large Send Offload LSO) + * , then allow 'frame_len' to be as big as 'lso_max' + * if indicated transfer length is >= lport->lso_max + */ + frame_len = (lport->seq_offload) ? lport->lso_max : + cmd->sess->max_frame; + frame_len = min(frame_len, remaining); + fp = fc_frame_alloc(lport, use_sg ? 0 : frame_len); + if (!fp) + return -ENOMEM; + to = fc_frame_payload_get(fp, 0); + fh_off = frame_off; + frame_off += frame_len; + /* + * Setup the frame's max payload which is used by base + * driver to indicate HW about max frame size, so that + * HW can do fragmentation appropriately based on + * "gso_max_size" of underline netdev. + */ + fr_max_payload(fp) = cmd->sess->max_frame; + } + tlen = min(mem_len, frame_len); + + if (use_sg) { + if (!mem) { + BUG_ON(!task->t_task_buf); + page_addr = task->t_task_buf + mem_off; + /* + * In this case, offset is 'offset_in_page' of + * (t_task_buf + mem_off) instead of 'mem_off'. + */ + off_in_page = offset_in_page(page_addr); + page = virt_to_page(page_addr); + tlen = min(tlen, PAGE_SIZE - off_in_page); + } else + off_in_page = mem_off; + BUG_ON(!page); + get_page(page); + skb_fill_page_desc(fp_skb(fp), + skb_shinfo(fp_skb(fp))->nr_frags, + page, off_in_page, tlen); + fr_len(fp) += tlen; + fp_skb(fp)->data_len += tlen; + fp_skb(fp)->truesize += + PAGE_SIZE << compound_order(page); + } else if (mem) { + BUG_ON(!page); + from = kmap_atomic(page + (mem_off >> PAGE_SHIFT), + KM_SOFTIRQ0); + page_addr = from; + from += mem_off & ~PAGE_MASK; + tlen = min(tlen, (size_t)(PAGE_SIZE - + (mem_off & ~PAGE_MASK))); + memcpy(to, from, tlen); + kunmap_atomic(page_addr, KM_SOFTIRQ0); + to += tlen; + } else { + from = task->t_task_buf + mem_off; + memcpy(to, from, tlen); + to += tlen; + } + + mem_off += tlen; + mem_len -= tlen; + frame_len -= tlen; + remaining -= tlen; + + if (frame_len && + (skb_shinfo(fp_skb(fp))->nr_frags < FC_FRAME_SG_LEN)) + continue; + if (!remaining) + f_ctl |= FC_FC_END_SEQ; + fc_fill_fc_hdr(fp, FC_RCTL_DD_SOL_DATA, ep->did, ep->sid, + FC_TYPE_FCP, f_ctl, fh_off); + error = lport->tt.seq_send(lport, cmd->seq, fp); + if (error) { + /* XXX For now, initiator will retry */ + if (printk_ratelimit()) + printk(KERN_ERR "%s: Failed to send frame %p, " + "xid <0x%x>, remaining <0x%x>, " + "lso_max <0x%x>\n", + __func__, fp, ep->xid, + remaining, lport->lso_max); + } + } + return ft_queue_status(se_cmd); +} + +/* + * Receive write data frame. + */ +void ft_recv_write_data(struct ft_cmd *cmd, struct fc_frame *fp) +{ + struct se_cmd *se_cmd = &cmd->se_cmd; + struct fc_seq *seq = cmd->seq; + struct fc_exch *ep; + struct fc_lport *lport; + struct se_transport_task *task; + struct fc_frame_header *fh; + struct se_mem *mem; + u32 mem_off; + u32 rel_off; + size_t frame_len; + size_t mem_len; + size_t tlen; + struct page *page; + void *page_addr; + void *from; + void *to; + u32 f_ctl; + void *buf; + + task = T_TASK(se_cmd); + BUG_ON(!task); + + fh = fc_frame_header_get(fp); + if (!(ntoh24(fh->fh_f_ctl) & FC_FC_REL_OFF)) + goto drop; + + /* + * Doesn't expect even single byte of payload. Payload + * is expected to be copied directly to user buffers + * due to DDP (Large Rx offload) feature, hence + * BUG_ON if BUF is non-NULL + */ + buf = fc_frame_payload_get(fp, 1); + if (cmd->was_ddp_setup && buf) { + printk(KERN_INFO "%s: When DDP was setup, not expected to" + "receive frame with payload, Payload shall be" + "copied directly to buffer instead of coming " + "via. legacy receive queues\n", __func__); + BUG_ON(buf); + } + + /* + * If ft_cmd indicated 'ddp_setup', in that case only the last frame + * should come with 'TSI bit being set'. If 'TSI bit is not set and if + * data frame appears here, means error condition. In both the cases + * release the DDP context (ddp_put) and in error case, as well + * initiate error recovery mechanism. + */ + ep = fc_seq_exch(seq); + if (cmd->was_ddp_setup) { + BUG_ON(!ep); + lport = ep->lp; + BUG_ON(!lport); + } + if (cmd->was_ddp_setup && ep->xid != FC_XID_UNKNOWN) { + f_ctl = ntoh24(fh->fh_f_ctl); + /* + * If TSI bit set in f_ctl, means last write data frame is + * received successfully where payload is posted directly + * to user buffer and only the last frame's header is posted + * in legacy receive queue + */ + if (f_ctl & FC_FC_SEQ_INIT) { /* TSI bit set in FC frame */ + cmd->write_data_len = lport->tt.ddp_done(lport, + ep->xid); + goto last_frame; + } else { + /* + * Updating the write_data_len may be meaningless at + * this point, but just in case if required in future + * for debugging or any other purpose + */ + printk(KERN_ERR "%s: Received frame with TSI bit not" + " being SET, dropping the frame, " + "cmd->sg <%p>, cmd->sg_cnt <0x%x>\n", + __func__, cmd->sg, cmd->sg_cnt); + cmd->write_data_len = lport->tt.ddp_done(lport, + ep->xid); + lport->tt.seq_exch_abort(cmd->seq, 0); + goto drop; + } + } + + rel_off = ntohl(fh->fh_parm_offset); + frame_len = fr_len(fp); + if (frame_len <= sizeof(*fh)) + goto drop; + frame_len -= sizeof(*fh); + from = fc_frame_payload_get(fp, 0); + if (rel_off >= se_cmd->data_length) + goto drop; + if (frame_len + rel_off > se_cmd->data_length) + frame_len = se_cmd->data_length - rel_off; + + /* + * Setup to use first mem list entry if any. + */ + if (task->t_tasks_se_num) { + mem = list_first_entry(task->t_mem_list, + struct se_mem, se_list); + mem_len = mem->se_len; + mem_off = mem->se_off; + page = mem->se_page; + } else { + mem = NULL; + page = NULL; + mem_off = 0; + mem_len = frame_len; + } + + while (frame_len) { + if (!mem_len) { + BUG_ON(!mem); + mem = list_entry(mem->se_list.next, + struct se_mem, se_list); + mem_len = mem->se_len; + mem_off = mem->se_off; + page = mem->se_page; + } + if (rel_off >= mem_len) { + rel_off -= mem_len; + mem_len = 0; + continue; + } + mem_off += rel_off; + mem_len -= rel_off; + rel_off = 0; + + tlen = min(mem_len, frame_len); + + if (mem) { + to = kmap_atomic(page + (mem_off >> PAGE_SHIFT), + KM_SOFTIRQ0); + page_addr = to; + to += mem_off & ~PAGE_MASK; + tlen = min(tlen, (size_t)(PAGE_SIZE - + (mem_off & ~PAGE_MASK))); + memcpy(to, from, tlen); + kunmap_atomic(page_addr, KM_SOFTIRQ0); + } else { + to = task->t_task_buf + mem_off; + memcpy(to, from, tlen); + } + from += tlen; + frame_len -= tlen; + mem_off += tlen; + mem_len -= tlen; + cmd->write_data_len += tlen; + } +last_frame: + if (cmd->write_data_len == se_cmd->data_length) + transport_generic_handle_data(se_cmd); +drop: + fc_frame_free(fp); +} diff --git a/drivers/target/tcm_fc/tfc_sess.c b/drivers/target/tcm_fc/tfc_sess.c new file mode 100644 index 0000000..a3bd57f --- /dev/null +++ b/drivers/target/tcm_fc/tfc_sess.c @@ -0,0 +1,541 @@ +/* + * Copyright (c) 2010 Cisco Systems, Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions 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 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., + * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + */ + +/* XXX TBD some includes may be extraneous */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include "tcm_fc.h" + +static void ft_sess_delete_all(struct ft_tport *); + +/* + * Lookup or allocate target local port. + * Caller holds ft_lport_lock. + */ +static struct ft_tport *ft_tport_create(struct fc_lport *lport) +{ + struct ft_tpg *tpg; + struct ft_tport *tport; + int i; + + tport = rcu_dereference(lport->prov[FC_TYPE_FCP]); + if (tport && tport->tpg) + return tport; + + tpg = ft_lport_find_tpg(lport); + if (!tpg) + return NULL; + + if (tport) { + tport->tpg = tpg; + return tport; + } + + tport = kzalloc(sizeof(*tport), GFP_KERNEL); + if (!tport) + return NULL; + + tport->lport = lport; + tport->tpg = tpg; + tpg->tport = tport; + for (i = 0; i < FT_SESS_HASH_SIZE; i++) + INIT_HLIST_HEAD(&tport->hash[i]); + + rcu_assign_pointer(lport->prov[FC_TYPE_FCP], tport); + return tport; +} + +/* + * Free tport via RCU. + */ +static void ft_tport_rcu_free(struct rcu_head *rcu) +{ + struct ft_tport *tport = container_of(rcu, struct ft_tport, rcu); + + kfree(tport); +} + +/* + * Delete a target local port. + * Caller holds ft_lport_lock. + */ +static void ft_tport_delete(struct ft_tport *tport) +{ + struct fc_lport *lport; + struct ft_tpg *tpg; + + ft_sess_delete_all(tport); + lport = tport->lport; + BUG_ON(tport != lport->prov[FC_TYPE_FCP]); + rcu_assign_pointer(lport->prov[FC_TYPE_FCP], NULL); + + tpg = tport->tpg; + if (tpg) { + tpg->tport = NULL; + tport->tpg = NULL; + } + call_rcu(&tport->rcu, ft_tport_rcu_free); +} + +/* + * Add local port. + * Called thru fc_lport_iterate(). + */ +void ft_lport_add(struct fc_lport *lport, void *arg) +{ + mutex_lock(&ft_lport_lock); + ft_tport_create(lport); + mutex_unlock(&ft_lport_lock); +} + +/* + * Delete local port. + * Called thru fc_lport_iterate(). + */ +void ft_lport_del(struct fc_lport *lport, void *arg) +{ + struct ft_tport *tport; + + mutex_lock(&ft_lport_lock); + tport = lport->prov[FC_TYPE_FCP]; + if (tport) + ft_tport_delete(tport); + mutex_unlock(&ft_lport_lock); +} + +/* + * Notification of local port change from libfc. + * Create or delete local port and associated tport. + */ +int ft_lport_notify(struct notifier_block *nb, unsigned long event, void *arg) +{ + struct fc_lport *lport = arg; + + switch (event) { + case FC_LPORT_EV_ADD: + ft_lport_add(lport, NULL); + break; + case FC_LPORT_EV_DEL: + ft_lport_del(lport, NULL); + break; + } + return NOTIFY_DONE; +} + +/* + * Hash function for FC_IDs. + */ +static u32 ft_sess_hash(u32 port_id) +{ + return hash_32(port_id, FT_SESS_HASH_BITS); +} + +/* + * Find session in local port. + * Sessions and hash lists are RCU-protected. + * A reference is taken which must be eventually freed. + */ +static struct ft_sess *ft_sess_get(struct fc_lport *lport, u32 port_id) +{ + struct ft_tport *tport; + struct hlist_head *head; + struct hlist_node *pos; + struct ft_sess *sess; + + rcu_read_lock(); + tport = rcu_dereference(lport->prov[FC_TYPE_FCP]); + if (!tport) + goto out; + + head = &tport->hash[ft_sess_hash(port_id)]; + hlist_for_each_entry_rcu(sess, pos, head, hash) { + if (sess->port_id == port_id) { + kref_get(&sess->kref); + rcu_read_unlock(); + FT_SESS_DBG("port_id %x found %p\n", port_id, sess); + return sess; + } + } +out: + rcu_read_unlock(); + FT_SESS_DBG("port_id %x not found\n", port_id); + return NULL; +} + +/* + * Allocate session and enter it in the hash for the local port. + * Caller holds ft_lport_lock. + */ +static struct ft_sess *ft_sess_create(struct ft_tport *tport, u32 port_id, + struct ft_node_acl *acl) +{ + struct ft_sess *sess; + struct hlist_head *head; + struct hlist_node *pos; + + head = &tport->hash[ft_sess_hash(port_id)]; + hlist_for_each_entry_rcu(sess, pos, head, hash) + if (sess->port_id == port_id) + return sess; + + sess = kzalloc(sizeof(*sess), GFP_KERNEL); + if (!sess) + return NULL; + + sess->se_sess = transport_init_session(); + if (!sess->se_sess) { + kfree(sess); + return NULL; + } + sess->se_sess->se_node_acl = &acl->se_node_acl; + sess->tport = tport; + sess->port_id = port_id; + kref_init(&sess->kref); /* ref for table entry */ + hlist_add_head_rcu(&sess->hash, head); + tport->sess_count++; + + FT_SESS_DBG("port_id %x sess %p\n", port_id, sess); + + transport_register_session(&tport->tpg->se_tpg, &acl->se_node_acl, + sess->se_sess, sess); + return sess; +} + +/* + * Unhash the session. + * Caller holds ft_lport_lock. + */ +static void ft_sess_unhash(struct ft_sess *sess) +{ + struct ft_tport *tport = sess->tport; + + hlist_del_rcu(&sess->hash); + BUG_ON(!tport->sess_count); + tport->sess_count--; + sess->port_id = -1; + sess->params = 0; +} + +/* + * Delete session from hash. + * Caller holds ft_lport_lock. + */ +static struct ft_sess *ft_sess_delete(struct ft_tport *tport, u32 port_id) +{ + struct hlist_head *head; + struct hlist_node *pos; + struct ft_sess *sess; + + head = &tport->hash[ft_sess_hash(port_id)]; + hlist_for_each_entry_rcu(sess, pos, head, hash) { + if (sess->port_id == port_id) { + ft_sess_unhash(sess); + return sess; + } + } + return NULL; +} + +/* + * Delete all sessions from tport. + * Caller holds ft_lport_lock. + */ +static void ft_sess_delete_all(struct ft_tport *tport) +{ + struct hlist_head *head; + struct hlist_node *pos; + struct ft_sess *sess; + + for (head = tport->hash; + head < &tport->hash[FT_SESS_HASH_SIZE]; head++) { + hlist_for_each_entry_rcu(sess, pos, head, hash) { + ft_sess_unhash(sess); + transport_deregister_session_configfs(sess->se_sess); + ft_sess_put(sess); /* release from table */ + } + } +} + +/* + * TCM ops for sessions. + */ + +/* + * Determine whether session is allowed to be shutdown in the current context. + * Returns non-zero if the session should be shutdown. + */ +int ft_sess_shutdown(struct se_session *se_sess) +{ + struct ft_sess *sess = se_sess->fabric_sess_ptr; + + FT_SESS_DBG("port_id %x\n", sess->port_id); + return 1; +} + +/* + * Remove session and send PRLO. + * This is called when the ACL is being deleted or queue depth is changing. + */ +void ft_sess_close(struct se_session *se_sess) +{ + struct ft_sess *sess = se_sess->fabric_sess_ptr; + struct fc_lport *lport; + u32 port_id; + + mutex_lock(&ft_lport_lock); + lport = sess->tport->lport; + port_id = sess->port_id; + if (port_id == -1) { + mutex_lock(&ft_lport_lock); + return; + } + FT_SESS_DBG("port_id %x\n", port_id); + ft_sess_unhash(sess); + mutex_unlock(&ft_lport_lock); + transport_deregister_session_configfs(se_sess); + ft_sess_put(sess); + /* XXX Send LOGO or PRLO */ + synchronize_rcu(); /* let transport deregister happen */ +} + +void ft_sess_stop(struct se_session *se_sess, int sess_sleep, int conn_sleep) +{ + struct ft_sess *sess = se_sess->fabric_sess_ptr; + + FT_SESS_DBG("port_id %x\n", sess->port_id); +} + +int ft_sess_logged_in(struct se_session *se_sess) +{ + struct ft_sess *sess = se_sess->fabric_sess_ptr; + + return sess->port_id != -1; +} + +u32 ft_sess_get_index(struct se_session *se_sess) +{ + struct ft_sess *sess = se_sess->fabric_sess_ptr; + + return sess->port_id; /* XXX TBD probably not what is needed */ +} + +u32 ft_sess_get_port_name(struct se_session *se_sess, + unsigned char *buf, u32 len) +{ + struct ft_sess *sess = se_sess->fabric_sess_ptr; + + return ft_format_wwn(buf, len, sess->port_name); +} + +void ft_sess_set_erl0(struct se_session *se_sess) +{ + /* XXX TBD called when out of memory */ +} + +/* + * libfc ops involving sessions. + */ + +static int ft_prli_locked(struct fc_rport_priv *rdata, u32 spp_len, + const struct fc_els_spp *rspp, struct fc_els_spp *spp) +{ + struct ft_tport *tport; + struct ft_sess *sess; + struct ft_node_acl *acl; + u32 fcp_parm; + + tport = ft_tport_create(rdata->local_port); + if (!tport) + return 0; /* not a target for this local port */ + + acl = ft_acl_get(tport->tpg, rdata); + if (!acl) + return 0; + + if (!rspp) + goto fill; + + if (rspp->spp_flags & (FC_SPP_OPA_VAL | FC_SPP_RPA_VAL)) + return FC_SPP_RESP_NO_PA; + + /* + * If both target and initiator bits are off, the SPP is invalid. + */ + fcp_parm = ntohl(rspp->spp_params); + if (!(fcp_parm & (FCP_SPPF_INIT_FCN | FCP_SPPF_TARG_FCN))) + return FC_SPP_RESP_INVL; + + /* + * Create session (image pair) only if requested by + * EST_IMG_PAIR flag and if the requestor is an initiator. + */ + if (rspp->spp_flags & FC_SPP_EST_IMG_PAIR) { + spp->spp_flags |= FC_SPP_EST_IMG_PAIR; + if (!(fcp_parm & FCP_SPPF_INIT_FCN)) + return FC_SPP_RESP_CONF; + sess = ft_sess_create(tport, rdata->ids.port_id, acl); + if (!sess) + return FC_SPP_RESP_RES; + if (!sess->params) + rdata->prli_count++; + sess->params = fcp_parm; + sess->port_name = rdata->ids.port_name; + sess->max_frame = rdata->maxframe_size; + + /* XXX TBD - clearing actions. unit attn, see 4.10 */ + } + + /* + * OR in our service parameters with other provider (initiator), if any. + * TBD XXX - indicate RETRY capability? + */ +fill: + fcp_parm = ntohl(spp->spp_params); + spp->spp_params = htonl(fcp_parm | FCP_SPPF_TARG_FCN); + return FC_SPP_RESP_ACK; +} + +/** + * tcm_fcp_prli() - Handle incoming or outgoing PRLI for the FCP target + * @rdata: remote port private + * @spp_len: service parameter page length + * @rspp: received service parameter page (NULL for outgoing PRLI) + * @spp: response service parameter page + * + * Returns spp response code. + */ +static int ft_prli(struct fc_rport_priv *rdata, u32 spp_len, + const struct fc_els_spp *rspp, struct fc_els_spp *spp) +{ + int ret; + + mutex_lock(&ft_lport_lock); + ret = ft_prli_locked(rdata, spp_len, rspp, spp); + mutex_unlock(&ft_lport_lock); + FT_SESS_DBG("port_id %x flags %x ret %x\n", + rdata->ids.port_id, rspp ? rspp->spp_flags : 0, ret); + return ret; +} + +static void ft_sess_rcu_free(struct rcu_head *rcu) +{ + struct ft_sess *sess = container_of(rcu, struct ft_sess, rcu); + + transport_deregister_session(sess->se_sess); + kfree(sess); +} + +static void ft_sess_free(struct kref *kref) +{ + struct ft_sess *sess = container_of(kref, struct ft_sess, kref); + + call_rcu(&sess->rcu, ft_sess_rcu_free); +} + +void ft_sess_put(struct ft_sess *sess) +{ + int sess_held = atomic_read(&sess->kref.refcount); + + BUG_ON(!sess_held); + kref_put(&sess->kref, ft_sess_free); +} + +static void ft_prlo(struct fc_rport_priv *rdata) +{ + struct ft_sess *sess; + struct ft_tport *tport; + + mutex_lock(&ft_lport_lock); + tport = rcu_dereference(rdata->local_port->prov[FC_TYPE_FCP]); + if (!tport) { + mutex_unlock(&ft_lport_lock); + return; + } + sess = ft_sess_delete(tport, rdata->ids.port_id); + if (!sess) { + mutex_unlock(&ft_lport_lock); + return; + } + mutex_unlock(&ft_lport_lock); + transport_deregister_session_configfs(sess->se_sess); + ft_sess_put(sess); /* release from table */ + rdata->prli_count--; + /* XXX TBD - clearing actions. unit attn, see 4.10 */ +} + +/* + * Handle incoming FCP request. + * Caller has verified that the frame is type FCP. + */ +static void ft_recv(struct fc_lport *lport, struct fc_frame *fp) +{ + struct ft_sess *sess; + u32 sid = fc_frame_sid(fp); + + FT_SESS_DBG("sid %x\n", sid); + + sess = ft_sess_get(lport, sid); + if (!sess) { + FT_SESS_DBG("sid %x sess lookup failed\n", sid); + /* TBD XXX - if FCP_CMND, send PRLO */ + fc_frame_free(fp); + return; + } + ft_recv_req(sess, fp); /* must do ft_sess_put() */ +} + +/* + * Provider ops for libfc. + */ +struct fc4_prov ft_prov = { + .prli = ft_prli, + .prlo = ft_prlo, + .recv = ft_recv, + .module = THIS_MODULE, +}; -- cgit v0.10.2 From 72ef0e5757c160fc627d2c89b6379bc102ccab5c Mon Sep 17 00:00:00 2001 From: Borislav Petkov Date: Mon, 2 May 2011 16:49:38 +0200 Subject: [SCSI] mptsas: Fix annoying warning Shut up drivers/message/fusion/mptsas.c: In function 'mptsas_event_process': drivers/message/fusion/mptsas.c:5015: warning: unused variable 'log_info' for configs with CONFIG_SCSI_MPT2SAS_LOGGING unset. Signed-off-by: Borislav Petkov Acked-by: "Desai, Kashyap" Signed-off-by: James Bottomley Signed-off-by: James Bottomley diff --git a/drivers/message/fusion/mptsas.c b/drivers/message/fusion/mptsas.c index 66f94125..7596aec 100644 --- a/drivers/message/fusion/mptsas.c +++ b/drivers/message/fusion/mptsas.c @@ -5012,7 +5012,6 @@ mptsas_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *reply) (ioc_stat & MPI_IOCSTATUS_FLAG_LOG_INFO_AVAILABLE)) { VirtTarget *vtarget = NULL; u8 id, channel; - u32 log_info = le32_to_cpu(reply->IOCLogInfo); id = sas_event_data->TargetID; channel = sas_event_data->Bus; @@ -5023,7 +5022,8 @@ mptsas_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *reply) "LogInfo (0x%x) available for " "INTERNAL_DEVICE_RESET" "fw_id %d fw_channel %d\n", ioc->name, - log_info, id, channel)); + le32_to_cpu(reply->IOCLogInfo), + id, channel)); if (vtarget->raidVolume) { devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Skipping Raid Volume for inDMD\n", -- cgit v0.10.2 From d0be5ec8693944c2e2fc0de70fda9dbc1b93bd7d Mon Sep 17 00:00:00 2001 From: "Stephen M. Cameron" Date: Tue, 3 May 2011 14:58:49 -0500 Subject: [SCSI] hpsa: do readl after writel in main i/o path to ensure commands don't get lost. Apparently we've been doin it rong for a decade, but only lately do we run into problems. Signed-off-by: Stephen M. Cameron Signed-off-by: James Bottomley Signed-off-by: James Bottomley diff --git a/drivers/scsi/hpsa.h b/drivers/scsi/hpsa.h index 621a153..98c97ca 100644 --- a/drivers/scsi/hpsa.h +++ b/drivers/scsi/hpsa.h @@ -212,6 +212,7 @@ static void SA5_submit_command(struct ctlr_info *h, dev_dbg(&h->pdev->dev, "Sending %x, tag = %x\n", c->busaddr, c->Header.Tag.lower); writel(c->busaddr, h->vaddr + SA5_REQUEST_PORT_OFFSET); + (void) readl(h->vaddr + SA5_REQUEST_PORT_OFFSET); h->commands_outstanding++; if (h->commands_outstanding > h->max_outstanding) h->max_outstanding = h->commands_outstanding; -- cgit v0.10.2 From 8cd21da71c952843f9cc215436286cf7f991cc6e Mon Sep 17 00:00:00 2001 From: "Stephen M. Cameron" Date: Tue, 3 May 2011 14:58:55 -0500 Subject: [SCSI] hpsa: add readl after writel in interrupt mask setting code This is to ensure the board interrupts are really off when these functions return. Signed-off-by: Stephen M. Cameron Signed-off-by: James Bottomley Signed-off-by: James Bottomley diff --git a/drivers/scsi/hpsa.h b/drivers/scsi/hpsa.h index 98c97ca..7eec397 100644 --- a/drivers/scsi/hpsa.h +++ b/drivers/scsi/hpsa.h @@ -228,10 +228,12 @@ static void SA5_intr_mask(struct ctlr_info *h, unsigned long val) if (val) { /* Turn interrupts on */ h->interrupts_enabled = 1; writel(0, h->vaddr + SA5_REPLY_INTR_MASK_OFFSET); + (void) readl(h->vaddr + SA5_REPLY_INTR_MASK_OFFSET); } else { /* Turn them off */ h->interrupts_enabled = 0; writel(SA5_INTR_OFF, h->vaddr + SA5_REPLY_INTR_MASK_OFFSET); + (void) readl(h->vaddr + SA5_REPLY_INTR_MASK_OFFSET); } } @@ -240,10 +242,12 @@ static void SA5_performant_intr_mask(struct ctlr_info *h, unsigned long val) if (val) { /* turn on interrupts */ h->interrupts_enabled = 1; writel(0, h->vaddr + SA5_REPLY_INTR_MASK_OFFSET); + (void) readl(h->vaddr + SA5_REPLY_INTR_MASK_OFFSET); } else { h->interrupts_enabled = 0; writel(SA5_PERF_INTR_OFF, h->vaddr + SA5_REPLY_INTR_MASK_OFFSET); + (void) readl(h->vaddr + SA5_REPLY_INTR_MASK_OFFSET); } } -- cgit v0.10.2 From 1fb011fb05b6bac4fb8eabd324a6983116f7594d Mon Sep 17 00:00:00 2001 From: "Stephen M. Cameron" Date: Tue, 3 May 2011 14:59:00 -0500 Subject: [SCSI] hpsa: remove unused parameter from hpsa_complete_scsi_command() Signed-off-by: Stephen M. Cameron Signed-off-by: James Bottomley Signed-off-by: James Bottomley diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index 415ad4f..8266850 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -1006,8 +1006,7 @@ static void hpsa_unmap_sg_chain_block(struct ctlr_info *h, pci_unmap_single(h->pdev, temp64.val, chain_sg->Len, PCI_DMA_TODEVICE); } -static void complete_scsi_command(struct CommandList *cp, - int timeout, u32 tag) +static void complete_scsi_command(struct CommandList *cp) { struct scsi_cmnd *cmd; struct ctlr_info *h; @@ -2936,7 +2935,7 @@ static inline void finish_cmd(struct CommandList *c, u32 raw_tag) { removeQ(c); if (likely(c->cmd_type == CMD_SCSI)) - complete_scsi_command(c, 0, raw_tag); + complete_scsi_command(c); else if (c->cmd_type == CMD_IOCTL_PEND) complete(c->waiting); } -- cgit v0.10.2 From a2a431a4fd3b11c6808933ca1bdb2d28a8fa0634 Mon Sep 17 00:00:00 2001 From: "Stephen M. Cameron" Date: Tue, 3 May 2011 14:59:05 -0500 Subject: [SCSI] hpsa: delete old unused padding garbage Signed-off-by: Stephen M. Cameron Signed-off-by: James Bottomley Signed-off-by: James Bottomley diff --git a/drivers/scsi/hpsa_cmd.h b/drivers/scsi/hpsa_cmd.h index 1846490..0500740 100644 --- a/drivers/scsi/hpsa_cmd.h +++ b/drivers/scsi/hpsa_cmd.h @@ -256,14 +256,6 @@ struct ErrorInfo { #define CMD_IOCTL_PEND 0x01 #define CMD_SCSI 0x03 -/* This structure needs to be divisible by 32 for new - * indexing method and performant mode. - */ -#define PAD32 32 -#define PAD64DIFF 0 -#define USEEXTRA ((sizeof(void *) - 4)/4) -#define PADSIZE (PAD32 + PAD64DIFF * USEEXTRA) - #define DIRECT_LOOKUP_SHIFT 5 #define DIRECT_LOOKUP_BIT 0x10 #define DIRECT_LOOKUP_MASK (~((1 << DIRECT_LOOKUP_SHIFT) - 1)) -- cgit v0.10.2 From 580ada3c1e2f23b4b0f3c254cae3eb278f92d494 Mon Sep 17 00:00:00 2001 From: "Stephen M. Cameron" Date: Tue, 3 May 2011 14:59:10 -0500 Subject: [SCSI] hpsa: do a better job of detecting controller reset failure Detect failure of controller reset by noticing if the 32 bytes of "driver version" we store on the hardware in the config table fail to get zeroed out. Previously we noticed if the controller did not transition to "simple mode", but this did not detect reset failure if the controller was already in simple mode prior to the reset attempt (e.g. due to module parameter hpsa_simple_mode=1). Signed-off-by: Stephen M. Cameron Signed-off-by: James Bottomley Signed-off-by: James Bottomley diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index 8266850..2aeb210 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -3184,6 +3184,59 @@ static int hpsa_controller_hard_reset(struct pci_dev *pdev, return 0; } +static __devinit void init_driver_version(char *driver_version, int len) +{ + memset(driver_version, 0, len); + strncpy(driver_version, "hpsa " HPSA_DRIVER_VERSION, len - 1); +} + +static __devinit int write_driver_ver_to_cfgtable( + struct CfgTable __iomem *cfgtable) +{ + char *driver_version; + int i, size = sizeof(cfgtable->driver_version); + + driver_version = kmalloc(size, GFP_KERNEL); + if (!driver_version) + return -ENOMEM; + + init_driver_version(driver_version, size); + for (i = 0; i < size; i++) + writeb(driver_version[i], &cfgtable->driver_version[i]); + kfree(driver_version); + return 0; +} + +static __devinit void read_driver_ver_from_cfgtable( + struct CfgTable __iomem *cfgtable, unsigned char *driver_ver) +{ + int i; + + for (i = 0; i < sizeof(cfgtable->driver_version); i++) + driver_ver[i] = readb(&cfgtable->driver_version[i]); +} + +static __devinit int controller_reset_failed( + struct CfgTable __iomem *cfgtable) +{ + + char *driver_ver, *old_driver_ver; + int rc, size = sizeof(cfgtable->driver_version); + + old_driver_ver = kmalloc(2 * size, GFP_KERNEL); + if (!old_driver_ver) + return -ENOMEM; + driver_ver = old_driver_ver + size; + + /* After a reset, the 32 bytes of "driver version" in the cfgtable + * should have been changed, otherwise we know the reset failed. + */ + init_driver_version(old_driver_ver, size); + read_driver_ver_from_cfgtable(cfgtable, driver_ver); + rc = !memcmp(driver_ver, old_driver_ver, size); + kfree(old_driver_ver); + return rc; +} /* This does a hard reset of the controller using PCI power management * states or the using the doorbell register. */ @@ -3194,7 +3247,7 @@ static __devinit int hpsa_kdump_hard_reset_controller(struct pci_dev *pdev) u64 cfg_base_addr_index; void __iomem *vaddr; unsigned long paddr; - u32 misc_fw_support, active_transport; + u32 misc_fw_support; int rc; struct CfgTable __iomem *cfgtable; bool use_doorbell; @@ -3256,6 +3309,9 @@ static __devinit int hpsa_kdump_hard_reset_controller(struct pci_dev *pdev) rc = -ENOMEM; goto unmap_vaddr; } + rc = write_driver_ver_to_cfgtable(cfgtable); + if (rc) + goto unmap_vaddr; /* If reset via doorbell register is supported, use that. */ misc_fw_support = readl(&cfgtable->misc_fw_support); @@ -3289,19 +3345,16 @@ static __devinit int hpsa_kdump_hard_reset_controller(struct pci_dev *pdev) "failed waiting for board to become ready\n"); goto unmap_cfgtable; } - dev_info(&pdev->dev, "board ready.\n"); - /* Controller should be in simple mode at this point. If it's not, - * It means we're on one of those controllers which doesn't support - * the doorbell reset method and on which the PCI power management reset - * method doesn't work (P800, for example.) - * In those cases, don't try to proceed, as it generally doesn't work. - */ - active_transport = readl(&cfgtable->TransportActive); - if (active_transport & PERFORMANT_MODE) { + rc = controller_reset_failed(vaddr); + if (rc < 0) + goto unmap_cfgtable; + if (rc) { dev_warn(&pdev->dev, "Unable to successfully reset controller," " Ignoring controller.\n"); rc = -ENODEV; + } else { + dev_info(&pdev->dev, "board ready.\n"); } unmap_cfgtable: @@ -3542,6 +3595,9 @@ static int __devinit hpsa_find_cfgtables(struct ctlr_info *h) cfg_base_addr_index) + cfg_offset, sizeof(*h->cfgtable)); if (!h->cfgtable) return -ENOMEM; + rc = write_driver_ver_to_cfgtable(h->cfgtable); + if (rc) + return rc; /* Find performant mode table. */ trans_offset = readl(&h->cfgtable->TransMethodOffset); h->transtable = remap_pci_mem(pci_resource_start(h->pdev, diff --git a/drivers/scsi/hpsa_cmd.h b/drivers/scsi/hpsa_cmd.h index 0500740..8fd35a7 100644 --- a/drivers/scsi/hpsa_cmd.h +++ b/drivers/scsi/hpsa_cmd.h @@ -337,6 +337,7 @@ struct CfgTable { u8 reserved[0x78 - 0x58]; u32 misc_fw_support; /* offset 0x78 */ #define MISC_FW_DOORBELL_RESET (0x02) + u8 driver_version[32]; }; #define NUM_BLOCKFETCH_ENTRIES 8 -- cgit v0.10.2 From 516fda49e8596904a741693059c8746f11ce579c Mon Sep 17 00:00:00 2001 From: "Stephen M. Cameron" Date: Tue, 3 May 2011 14:59:15 -0500 Subject: [SCSI] hpsa: wait longer for no-op to complete after resetting controller This is to avoid the usual two or three messages about the command timing out. We're obviously not waiting long enough. Signed-off-by: Stephen M. Cameron Signed-off-by: James Bottomley Signed-off-by: James Bottomley diff --git a/drivers/scsi/hpsa.h b/drivers/scsi/hpsa.h index 7eec397..7a4ee73 100644 --- a/drivers/scsi/hpsa.h +++ b/drivers/scsi/hpsa.h @@ -130,7 +130,7 @@ struct ctlr_info { #define HPSA_BUS_RESET_MSG 2 #define HPSA_HOST_RESET_MSG 3 #define HPSA_MSG_SEND_RETRY_LIMIT 10 -#define HPSA_MSG_SEND_RETRY_INTERVAL_MSECS 1000 +#define HPSA_MSG_SEND_RETRY_INTERVAL_MSECS (10000) /* Maximum time in seconds driver will wait for command completions * when polling before giving up. -- cgit v0.10.2 From 2e9d1b3626c4383362df30bb853a1b57c2798300 Mon Sep 17 00:00:00 2001 From: "Stephen M. Cameron" Date: Tue, 3 May 2011 14:59:20 -0500 Subject: [SCSI] hpsa: factor out cmd pool allocation functions Signed-off-by: Stephen M. Cameron Signed-off-by: James Bottomley Signed-off-by: James Bottomley diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index 2aeb210..7336f3c 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -3847,6 +3847,40 @@ static __devinit int hpsa_init_reset_devices(struct pci_dev *pdev) return 0; } +static __devinit int hpsa_allocate_cmd_pool(struct ctlr_info *h) +{ + h->cmd_pool_bits = kzalloc( + DIV_ROUND_UP(h->nr_cmds, BITS_PER_LONG) * + sizeof(unsigned long), GFP_KERNEL); + h->cmd_pool = pci_alloc_consistent(h->pdev, + h->nr_cmds * sizeof(*h->cmd_pool), + &(h->cmd_pool_dhandle)); + h->errinfo_pool = pci_alloc_consistent(h->pdev, + h->nr_cmds * sizeof(*h->errinfo_pool), + &(h->errinfo_pool_dhandle)); + if ((h->cmd_pool_bits == NULL) + || (h->cmd_pool == NULL) + || (h->errinfo_pool == NULL)) { + dev_err(&h->pdev->dev, "out of memory in %s", __func__); + return -ENOMEM; + } + return 0; +} + +static void hpsa_free_cmd_pool(struct ctlr_info *h) +{ + kfree(h->cmd_pool_bits); + if (h->cmd_pool) + pci_free_consistent(h->pdev, + h->nr_cmds * sizeof(struct CommandList), + h->cmd_pool, h->cmd_pool_dhandle); + if (h->errinfo_pool) + pci_free_consistent(h->pdev, + h->nr_cmds * sizeof(struct ErrorInfo), + h->errinfo_pool, + h->errinfo_pool_dhandle); +} + static int __devinit hpsa_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) { @@ -3917,33 +3951,14 @@ static int __devinit hpsa_init_one(struct pci_dev *pdev, dev_info(&pdev->dev, "%s: <0x%x> at IRQ %d%s using DAC\n", h->devname, pdev->device, h->intr[h->intr_mode], dac ? "" : " not"); - - h->cmd_pool_bits = - kmalloc(((h->nr_cmds + BITS_PER_LONG - - 1) / BITS_PER_LONG) * sizeof(unsigned long), GFP_KERNEL); - h->cmd_pool = pci_alloc_consistent(h->pdev, - h->nr_cmds * sizeof(*h->cmd_pool), - &(h->cmd_pool_dhandle)); - h->errinfo_pool = pci_alloc_consistent(h->pdev, - h->nr_cmds * sizeof(*h->errinfo_pool), - &(h->errinfo_pool_dhandle)); - if ((h->cmd_pool_bits == NULL) - || (h->cmd_pool == NULL) - || (h->errinfo_pool == NULL)) { - dev_err(&pdev->dev, "out of memory"); - rc = -ENOMEM; + if (hpsa_allocate_cmd_pool(h)) goto clean4; - } if (hpsa_allocate_sg_chain_blocks(h)) goto clean4; init_waitqueue_head(&h->scan_wait_queue); h->scan_finished = 1; /* no scan currently in progress */ pci_set_drvdata(pdev, h); - memset(h->cmd_pool_bits, 0, - ((h->nr_cmds + BITS_PER_LONG - - 1) / BITS_PER_LONG) * sizeof(unsigned long)); - hpsa_scsi_setup(h); /* Turn the interrupts on so we can service requests */ @@ -3957,16 +3972,7 @@ static int __devinit hpsa_init_one(struct pci_dev *pdev, clean4: hpsa_free_sg_chain_blocks(h); - kfree(h->cmd_pool_bits); - if (h->cmd_pool) - pci_free_consistent(h->pdev, - h->nr_cmds * sizeof(struct CommandList), - h->cmd_pool, h->cmd_pool_dhandle); - if (h->errinfo_pool) - pci_free_consistent(h->pdev, - h->nr_cmds * sizeof(struct ErrorInfo), - h->errinfo_pool, - h->errinfo_pool_dhandle); + hpsa_free_cmd_pool(h); free_irq(h->intr[h->intr_mode], h); clean2: clean1: -- cgit v0.10.2 From 0ae01a32cb4a89ef0ed49bb6f49bd5830b13ab3e Mon Sep 17 00:00:00 2001 From: "Stephen M. Cameron" Date: Tue, 3 May 2011 14:59:25 -0500 Subject: [SCSI] hpsa: factor out irq request code Signed-off-by: Stephen M. Cameron Signed-off-by: James Bottomley Signed-off-by: James Bottomley diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index 7336f3c..97db2e5 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -3881,6 +3881,26 @@ static void hpsa_free_cmd_pool(struct ctlr_info *h) h->errinfo_pool_dhandle); } +static int hpsa_request_irq(struct ctlr_info *h, + irqreturn_t (*msixhandler)(int, void *), + irqreturn_t (*intxhandler)(int, void *)) +{ + int rc; + + if (h->msix_vector || h->msi_vector) + rc = request_irq(h->intr[h->intr_mode], msixhandler, + IRQF_DISABLED, h->devname, h); + else + rc = request_irq(h->intr[h->intr_mode], intxhandler, + IRQF_DISABLED, h->devname, h); + if (rc) { + dev_err(&h->pdev->dev, "unable to get irq %d for %s\n", + h->intr[h->intr_mode], h->devname); + return -ENODEV; + } + return 0; +} + static int __devinit hpsa_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) { @@ -3936,18 +3956,8 @@ static int __devinit hpsa_init_one(struct pci_dev *pdev, /* make sure the board interrupts are off */ h->access.set_intr_mask(h, HPSA_INTR_OFF); - if (h->msix_vector || h->msi_vector) - rc = request_irq(h->intr[h->intr_mode], do_hpsa_intr_msi, - IRQF_DISABLED, h->devname, h); - else - rc = request_irq(h->intr[h->intr_mode], do_hpsa_intr_intx, - IRQF_DISABLED, h->devname, h); - if (rc) { - dev_err(&pdev->dev, "unable to get irq %d for %s\n", - h->intr[h->intr_mode], h->devname); + if (hpsa_request_irq(h, do_hpsa_intr_msi, do_hpsa_intr_intx)) goto clean2; - } - dev_info(&pdev->dev, "%s: <0x%x> at IRQ %d%s using DAC\n", h->devname, pdev->device, h->intr[h->intr_mode], dac ? "" : " not"); -- cgit v0.10.2 From 2ed7127bceb10a6a7d5a38c30ab65176d4e4bc0f Mon Sep 17 00:00:00 2001 From: "Stephen M. Cameron" Date: Tue, 3 May 2011 14:59:31 -0500 Subject: [SCSI] hpsa: increase time to wait for board reset Signed-off-by: Stephen M. Cameron Signed-off-by: James Bottomley Signed-off-by: James Bottomley diff --git a/drivers/scsi/hpsa.h b/drivers/scsi/hpsa.h index 7a4ee73..b1412a7 100644 --- a/drivers/scsi/hpsa.h +++ b/drivers/scsi/hpsa.h @@ -155,7 +155,7 @@ struct ctlr_info { * HPSA_BOARD_READY_ITERATIONS are derived from those. */ #define HPSA_BOARD_READY_WAIT_SECS (120) -#define HPSA_BOARD_NOT_READY_WAIT_SECS (10) +#define HPSA_BOARD_NOT_READY_WAIT_SECS (100) #define HPSA_BOARD_READY_POLL_INTERVAL_MSECS (100) #define HPSA_BOARD_READY_POLL_INTERVAL \ ((HPSA_BOARD_READY_POLL_INTERVAL_MSECS * HZ) / 1000) -- cgit v0.10.2 From 2b870cb30000477e425666f9c6d83cca8fddc7c0 Mon Sep 17 00:00:00 2001 From: "Stephen M. Cameron" Date: Tue, 3 May 2011 14:59:36 -0500 Subject: [SCSI] hpsa: clarify messages around reset behavior When waiting for the board to become "not ready" don't print a message saying "waiting for board to become ready" (possibly followed by a message saying "failed waiting for board to become not ready". Instead, it should be "waiting for board to reset" and "failed waiting for board to reset." Signed-off-by: Stephen M. Cameron Signed-off-by: James Bottomley Signed-off-by: James Bottomley diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index 97db2e5..2a90e9a 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -3334,11 +3334,11 @@ static __devinit int hpsa_kdump_hard_reset_controller(struct pci_dev *pdev) msleep(HPSA_POST_RESET_PAUSE_MSECS); /* Wait for board to become not ready, then ready. */ - dev_info(&pdev->dev, "Waiting for board to become ready.\n"); + dev_info(&pdev->dev, "Waiting for board to reset.\n"); rc = hpsa_wait_for_board_state(pdev, vaddr, BOARD_NOT_READY); if (rc) dev_warn(&pdev->dev, - "failed waiting for board to become not ready\n"); + "failed waiting for board to reset\n"); rc = hpsa_wait_for_board_state(pdev, vaddr, BOARD_READY); if (rc) { dev_warn(&pdev->dev, @@ -3837,6 +3837,7 @@ static __devinit int hpsa_init_reset_devices(struct pci_dev *pdev) return -ENODEV; /* Now try to get the controller to respond to a no-op */ + dev_warn(&pdev->dev, "Waiting for controller to respond to no-op\n"); for (i = 0; i < HPSA_POST_RESET_NOOP_RETRIES; i++) { if (hpsa_noop(pdev) == 0) break; -- cgit v0.10.2 From 9a41338e5b474add499a7ca2a5a76148e5076805 Mon Sep 17 00:00:00 2001 From: "Stephen M. Cameron" Date: Tue, 3 May 2011 14:59:41 -0500 Subject: [SCSI] hpsa: remove atrophied hpsa_scsi_setup function hpsa_scsi_setup at one time contained enough code to justify its existence, but that time has passed. Signed-off-by: Stephen M. Cameron Signed-off-by: James Bottomley Signed-off-by: James Bottomley diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index 2a90e9a..ca92141 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -929,13 +929,6 @@ static void hpsa_slave_destroy(struct scsi_device *sdev) /* nothing to do. */ } -static void hpsa_scsi_setup(struct ctlr_info *h) -{ - h->ndevices = 0; - h->scsi_host = NULL; - spin_lock_init(&h->devlock); -} - static void hpsa_free_sg_chain_blocks(struct ctlr_info *h) { int i; @@ -3970,7 +3963,9 @@ static int __devinit hpsa_init_one(struct pci_dev *pdev, h->scan_finished = 1; /* no scan currently in progress */ pci_set_drvdata(pdev, h); - hpsa_scsi_setup(h); + h->ndevices = 0; + h->scsi_host = NULL; + spin_lock_init(&h->devlock); /* Turn the interrupts on so we can service requests */ h->access.set_intr_mask(h, HPSA_INTR_ON); -- cgit v0.10.2 From cf0b08d0cd87ada9d284925834d08fb8026da888 Mon Sep 17 00:00:00 2001 From: "Stephen M. Cameron" Date: Tue, 3 May 2011 14:59:46 -0500 Subject: [SCSI] hpsa: use new doorbell-bit-5 reset method The bit-2-doorbell reset method seemed to cause (survivable) NMIs on some systems and (unsurvivable) IOCK NMIs on some G7 servers. Firmware guys implemented a new doorbell method to alleviate these problems triggered by bit 5 of the doorbell register. We want to use it if it's available. Signed-off-by: Stephen M. Cameron Signed-off-by: James Bottomley Signed-off-by: James Bottomley diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index ca92141..c096cda 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -3128,7 +3128,7 @@ static __devinit int hpsa_message(struct pci_dev *pdev, unsigned char opcode, #define hpsa_noop(p) hpsa_message(p, 3, 0) static int hpsa_controller_hard_reset(struct pci_dev *pdev, - void * __iomem vaddr, bool use_doorbell) + void * __iomem vaddr, u32 use_doorbell) { u16 pmcsr; int pos; @@ -3139,7 +3139,7 @@ static int hpsa_controller_hard_reset(struct pci_dev *pdev, * other way using the doorbell register. */ dev_info(&pdev->dev, "using doorbell to reset controller\n"); - writel(DOORBELL_CTLR_RESET, vaddr + SA5_DOORBELL); + writel(use_doorbell, vaddr + SA5_DOORBELL); msleep(1000); } else { /* Try to do it the PCI power state way */ @@ -3243,7 +3243,7 @@ static __devinit int hpsa_kdump_hard_reset_controller(struct pci_dev *pdev) u32 misc_fw_support; int rc; struct CfgTable __iomem *cfgtable; - bool use_doorbell; + u32 use_doorbell; u32 board_id; u16 command_register; @@ -3306,9 +3306,24 @@ static __devinit int hpsa_kdump_hard_reset_controller(struct pci_dev *pdev) if (rc) goto unmap_vaddr; - /* If reset via doorbell register is supported, use that. */ + /* If reset via doorbell register is supported, use that. + * There are two such methods. Favor the newest method. + */ misc_fw_support = readl(&cfgtable->misc_fw_support); - use_doorbell = misc_fw_support & MISC_FW_DOORBELL_RESET; + use_doorbell = misc_fw_support & MISC_FW_DOORBELL_RESET2; + if (use_doorbell) { + use_doorbell = DOORBELL_CTLR_RESET2; + } else { + use_doorbell = misc_fw_support & MISC_FW_DOORBELL_RESET; + if (use_doorbell) { + dev_warn(&pdev->dev, "Controller claims that " + "'Bit 2 doorbell reset' is " + "supported, but not 'bit 5 doorbell reset'. " + "Firmware update is recommended.\n"); + rc = -ENODEV; + goto unmap_cfgtable; + } + } rc = hpsa_controller_hard_reset(pdev, vaddr, use_doorbell); if (rc) diff --git a/drivers/scsi/hpsa_cmd.h b/drivers/scsi/hpsa_cmd.h index 8fd35a7..55d741b 100644 --- a/drivers/scsi/hpsa_cmd.h +++ b/drivers/scsi/hpsa_cmd.h @@ -101,6 +101,7 @@ #define CFGTBL_ChangeReq 0x00000001l #define CFGTBL_AccCmds 0x00000001l #define DOORBELL_CTLR_RESET 0x00000004l +#define DOORBELL_CTLR_RESET2 0x00000020l #define CFGTBL_Trans_Simple 0x00000002l #define CFGTBL_Trans_Performant 0x00000004l @@ -337,6 +338,7 @@ struct CfgTable { u8 reserved[0x78 - 0x58]; u32 misc_fw_support; /* offset 0x78 */ #define MISC_FW_DOORBELL_RESET (0x02) +#define MISC_FW_DOORBELL_RESET2 (0x010) u8 driver_version[32]; }; -- cgit v0.10.2 From 64670ac8702ec37a00ad6e479f3cacbde0fd4efa Mon Sep 17 00:00:00 2001 From: "Stephen M. Cameron" Date: Tue, 3 May 2011 14:59:51 -0500 Subject: [SCSI] hpsa: do soft reset if hard reset is broken on driver load, if reset_devices is set, and the hard reset attempts fail, try to bring up the controller to the point that a command can be sent, and send it a soft reset command, then after the reset undo whatever driver initialization was done to get it to the point to take a command, and re-do it after the reset. This is to get kdump to work on all the "non-resettable" controllers (except 64xx controllers which can't be reset due to the potentially shared cache module.) Signed-off-by: Stephen M. Cameron Signed-off-by: James Bottomley Signed-off-by: James Bottomley diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index c096cda..6fe77d0 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -2743,6 +2743,26 @@ static int hpsa_ioctl(struct scsi_device *dev, int cmd, void *arg) } } +static int __devinit hpsa_send_host_reset(struct ctlr_info *h, + unsigned char *scsi3addr, u8 reset_type) +{ + struct CommandList *c; + + c = cmd_alloc(h); + if (!c) + return -ENOMEM; + fill_cmd(c, HPSA_DEVICE_RESET_MSG, h, NULL, 0, 0, + RAID_CTLR_LUNID, TYPE_MSG); + c->Request.CDB[1] = reset_type; /* fill_cmd defaults to target reset */ + c->waiting = NULL; + enqueue_cmd_and_start_io(h, c); + /* Don't wait for completion, the reset won't complete. Don't free + * the command either. This is the last command we will send before + * re-initializing everything, so it doesn't matter and won't leak. + */ + return 0; +} + static void fill_cmd(struct CommandList *c, u8 cmd, struct ctlr_info *h, void *buff, size_t size, u8 page_code, unsigned char *scsi3addr, int cmd_type) @@ -2820,7 +2840,8 @@ static void fill_cmd(struct CommandList *c, u8 cmd, struct ctlr_info *h, c->Request.Type.Attribute = ATTR_SIMPLE; c->Request.Type.Direction = XFER_NONE; c->Request.Timeout = 0; /* Don't time out */ - c->Request.CDB[0] = 0x01; /* RESET_MSG is 0x01 */ + memset(&c->Request.CDB[0], 0, sizeof(c->Request.CDB)); + c->Request.CDB[0] = cmd; c->Request.CDB[1] = 0x03; /* Reset target above */ /* If bytes 4-7 are zero, it means reset the */ /* LunID device */ @@ -2986,6 +3007,63 @@ static inline u32 process_nonindexed_cmd(struct ctlr_info *h, return next_command(h); } +/* Some controllers, like p400, will give us one interrupt + * after a soft reset, even if we turned interrupts off. + * Only need to check for this in the hpsa_xxx_discard_completions + * functions. + */ +static int ignore_bogus_interrupt(struct ctlr_info *h) +{ + if (likely(!reset_devices)) + return 0; + + if (likely(h->interrupts_enabled)) + return 0; + + dev_info(&h->pdev->dev, "Received interrupt while interrupts disabled " + "(known firmware bug.) Ignoring.\n"); + + return 1; +} + +static irqreturn_t hpsa_intx_discard_completions(int irq, void *dev_id) +{ + struct ctlr_info *h = dev_id; + unsigned long flags; + u32 raw_tag; + + if (ignore_bogus_interrupt(h)) + return IRQ_NONE; + + if (interrupt_not_for_us(h)) + return IRQ_NONE; + spin_lock_irqsave(&h->lock, flags); + while (interrupt_pending(h)) { + raw_tag = get_next_completion(h); + while (raw_tag != FIFO_EMPTY) + raw_tag = next_command(h); + } + spin_unlock_irqrestore(&h->lock, flags); + return IRQ_HANDLED; +} + +static irqreturn_t hpsa_msix_discard_completions(int irq, void *dev_id) +{ + struct ctlr_info *h = dev_id; + unsigned long flags; + u32 raw_tag; + + if (ignore_bogus_interrupt(h)) + return IRQ_NONE; + + spin_lock_irqsave(&h->lock, flags); + raw_tag = get_next_completion(h); + while (raw_tag != FIFO_EMPTY) + raw_tag = next_command(h); + spin_unlock_irqrestore(&h->lock, flags); + return IRQ_HANDLED; +} + static irqreturn_t do_hpsa_intr_intx(int irq, void *dev_id) { struct ctlr_info *h = dev_id; @@ -3124,7 +3202,6 @@ static __devinit int hpsa_message(struct pci_dev *pdev, unsigned char opcode, return 0; } -#define hpsa_soft_reset_controller(p) hpsa_message(p, 1, 0) #define hpsa_noop(p) hpsa_message(p, 3, 0) static int hpsa_controller_hard_reset(struct pci_dev *pdev, @@ -3320,7 +3397,7 @@ static __devinit int hpsa_kdump_hard_reset_controller(struct pci_dev *pdev) "'Bit 2 doorbell reset' is " "supported, but not 'bit 5 doorbell reset'. " "Firmware update is recommended.\n"); - rc = -ENODEV; + rc = -ENOTSUPP; /* try soft reset */ goto unmap_cfgtable; } } @@ -3344,13 +3421,18 @@ static __devinit int hpsa_kdump_hard_reset_controller(struct pci_dev *pdev) /* Wait for board to become not ready, then ready. */ dev_info(&pdev->dev, "Waiting for board to reset.\n"); rc = hpsa_wait_for_board_state(pdev, vaddr, BOARD_NOT_READY); - if (rc) + if (rc) { dev_warn(&pdev->dev, - "failed waiting for board to reset\n"); + "failed waiting for board to reset." + " Will try soft reset.\n"); + rc = -ENOTSUPP; /* Not expected, but try soft reset later */ + goto unmap_cfgtable; + } rc = hpsa_wait_for_board_state(pdev, vaddr, BOARD_READY); if (rc) { dev_warn(&pdev->dev, - "failed waiting for board to become ready\n"); + "failed waiting for board to become ready " + "after hard reset\n"); goto unmap_cfgtable; } @@ -3358,11 +3440,11 @@ static __devinit int hpsa_kdump_hard_reset_controller(struct pci_dev *pdev) if (rc < 0) goto unmap_cfgtable; if (rc) { - dev_warn(&pdev->dev, "Unable to successfully reset controller," - " Ignoring controller.\n"); - rc = -ENODEV; + dev_warn(&pdev->dev, "Unable to successfully reset " + "controller. Will try soft reset.\n"); + rc = -ENOTSUPP; } else { - dev_info(&pdev->dev, "board ready.\n"); + dev_info(&pdev->dev, "board ready after hard reset.\n"); } unmap_cfgtable: @@ -3840,7 +3922,7 @@ static __devinit int hpsa_init_reset_devices(struct pci_dev *pdev) * due to concerns about shared bbwc between 6402/6404 pair. */ if (rc == -ENOTSUPP) - return 0; /* just try to do the kdump anyhow. */ + return rc; /* just try to do the kdump anyhow. */ if (rc) return -ENODEV; @@ -3910,18 +3992,79 @@ static int hpsa_request_irq(struct ctlr_info *h, return 0; } +static int __devinit hpsa_kdump_soft_reset(struct ctlr_info *h) +{ + if (hpsa_send_host_reset(h, RAID_CTLR_LUNID, + HPSA_RESET_TYPE_CONTROLLER)) { + dev_warn(&h->pdev->dev, "Resetting array controller failed.\n"); + return -EIO; + } + + dev_info(&h->pdev->dev, "Waiting for board to soft reset.\n"); + if (hpsa_wait_for_board_state(h->pdev, h->vaddr, BOARD_NOT_READY)) { + dev_warn(&h->pdev->dev, "Soft reset had no effect.\n"); + return -1; + } + + dev_info(&h->pdev->dev, "Board reset, awaiting READY status.\n"); + if (hpsa_wait_for_board_state(h->pdev, h->vaddr, BOARD_READY)) { + dev_warn(&h->pdev->dev, "Board failed to become ready " + "after soft reset.\n"); + return -1; + } + + return 0; +} + +static void hpsa_undo_allocations_after_kdump_soft_reset(struct ctlr_info *h) +{ + free_irq(h->intr[h->intr_mode], h); +#ifdef CONFIG_PCI_MSI + if (h->msix_vector) + pci_disable_msix(h->pdev); + else if (h->msi_vector) + pci_disable_msi(h->pdev); +#endif /* CONFIG_PCI_MSI */ + hpsa_free_sg_chain_blocks(h); + hpsa_free_cmd_pool(h); + kfree(h->blockFetchTable); + pci_free_consistent(h->pdev, h->reply_pool_size, + h->reply_pool, h->reply_pool_dhandle); + if (h->vaddr) + iounmap(h->vaddr); + if (h->transtable) + iounmap(h->transtable); + if (h->cfgtable) + iounmap(h->cfgtable); + pci_release_regions(h->pdev); + kfree(h); +} + static int __devinit hpsa_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) { int dac, rc; struct ctlr_info *h; + int try_soft_reset = 0; + unsigned long flags; if (number_of_controllers == 0) printk(KERN_INFO DRIVER_NAME "\n"); rc = hpsa_init_reset_devices(pdev); - if (rc) - return rc; + if (rc) { + if (rc != -ENOTSUPP) + return rc; + /* If the reset fails in a particular way (it has no way to do + * a proper hard reset, so returns -ENOTSUPP) we can try to do + * a soft reset once we get the controller configured up to the + * point that it can accept a command. + */ + try_soft_reset = 1; + rc = 0; + } + +reinit_after_soft_reset: /* Command structures must be aligned on a 32-byte boundary because * the 5 lower bits of the address are used by the hardware. and by @@ -3981,11 +4124,66 @@ static int __devinit hpsa_init_one(struct pci_dev *pdev, h->ndevices = 0; h->scsi_host = NULL; spin_lock_init(&h->devlock); + hpsa_put_ctlr_into_performant_mode(h); + + /* At this point, the controller is ready to take commands. + * Now, if reset_devices and the hard reset didn't work, try + * the soft reset and see if that works. + */ + if (try_soft_reset) { + + /* This is kind of gross. We may or may not get a completion + * from the soft reset command, and if we do, then the value + * from the fifo may or may not be valid. So, we wait 10 secs + * after the reset throwing away any completions we get during + * that time. Unregister the interrupt handler and register + * fake ones to scoop up any residual completions. + */ + spin_lock_irqsave(&h->lock, flags); + h->access.set_intr_mask(h, HPSA_INTR_OFF); + spin_unlock_irqrestore(&h->lock, flags); + free_irq(h->intr[h->intr_mode], h); + rc = hpsa_request_irq(h, hpsa_msix_discard_completions, + hpsa_intx_discard_completions); + if (rc) { + dev_warn(&h->pdev->dev, "Failed to request_irq after " + "soft reset.\n"); + goto clean4; + } + + rc = hpsa_kdump_soft_reset(h); + if (rc) + /* Neither hard nor soft reset worked, we're hosed. */ + goto clean4; + + dev_info(&h->pdev->dev, "Board READY.\n"); + dev_info(&h->pdev->dev, + "Waiting for stale completions to drain.\n"); + h->access.set_intr_mask(h, HPSA_INTR_ON); + msleep(10000); + h->access.set_intr_mask(h, HPSA_INTR_OFF); + + rc = controller_reset_failed(h->cfgtable); + if (rc) + dev_info(&h->pdev->dev, + "Soft reset appears to have failed.\n"); + + /* since the controller's reset, we have to go back and re-init + * everything. Easiest to just forget what we've done and do it + * all over again. + */ + hpsa_undo_allocations_after_kdump_soft_reset(h); + try_soft_reset = 0; + if (rc) + /* don't go to clean4, we already unallocated */ + return -ENODEV; + + goto reinit_after_soft_reset; + } /* Turn the interrupts on so we can service requests */ h->access.set_intr_mask(h, HPSA_INTR_ON); - hpsa_put_ctlr_into_performant_mode(h); hpsa_hba_inquiry(h); hpsa_register_scsi(h); /* hook ourselves into SCSI subsystem */ h->busy_initializing = 0; diff --git a/drivers/scsi/hpsa.h b/drivers/scsi/hpsa.h index b1412a7..6d8dcd4 100644 --- a/drivers/scsi/hpsa.h +++ b/drivers/scsi/hpsa.h @@ -127,8 +127,10 @@ struct ctlr_info { }; #define HPSA_ABORT_MSG 0 #define HPSA_DEVICE_RESET_MSG 1 -#define HPSA_BUS_RESET_MSG 2 -#define HPSA_HOST_RESET_MSG 3 +#define HPSA_RESET_TYPE_CONTROLLER 0x00 +#define HPSA_RESET_TYPE_BUS 0x01 +#define HPSA_RESET_TYPE_TARGET 0x03 +#define HPSA_RESET_TYPE_LUN 0x04 #define HPSA_MSG_SEND_RETRY_LIMIT 10 #define HPSA_MSG_SEND_RETRY_INTERVAL_MSECS (10000) -- cgit v0.10.2 From dfc2224828c5fc4ec7e11587b9d6b97283aa2d01 Mon Sep 17 00:00:00 2001 From: "Stephen M. Cameron" Date: Tue, 3 May 2011 14:59:56 -0500 Subject: [SCSI] hpsa: remove superfluous sleeps around reset code Signed-off-by: Stephen M. Cameron Signed-off-by: James Bottomley Signed-off-by: James Bottomley diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index 6fe77d0..ca8ee92 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -3217,7 +3217,6 @@ static int hpsa_controller_hard_reset(struct pci_dev *pdev, */ dev_info(&pdev->dev, "using doorbell to reset controller\n"); writel(use_doorbell, vaddr + SA5_DOORBELL); - msleep(1000); } else { /* Try to do it the PCI power state way */ /* Quoting from the Open CISS Specification: "The Power @@ -3248,8 +3247,6 @@ static int hpsa_controller_hard_reset(struct pci_dev *pdev, pmcsr &= ~PCI_PM_CTRL_STATE_MASK; pmcsr |= PCI_D0; pci_write_config_word(pdev, pos + PCI_PM_CTRL, pmcsr); - - msleep(500); } return 0; } -- cgit v0.10.2 From 4638078697574be43816779845e26bf05ae70d9d Mon Sep 17 00:00:00 2001 From: "Stephen M. Cameron" Date: Tue, 3 May 2011 15:00:01 -0500 Subject: [SCSI] hpsa: do not attempt PCI power management reset method if we know it won't work. Just go straight to the soft-reset method instead. Signed-off-by: Stephen M. Cameron Signed-off-by: James Bottomley Signed-off-by: James Bottomley diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index ca8ee92..5c03cb5 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -273,7 +273,7 @@ static ssize_t host_show_transport_mode(struct device *dev, "performant" : "simple"); } -/* List of controllers which cannot be reset on kexec with reset_devices */ +/* List of controllers which cannot be hard reset on kexec with reset_devices */ static u32 unresettable_controller[] = { 0x324a103C, /* Smart Array P712m */ 0x324b103C, /* SmartArray P711m */ @@ -291,16 +291,45 @@ static u32 unresettable_controller[] = { 0x409D0E11, /* Smart Array 6400 EM */ }; -static int ctlr_is_resettable(struct ctlr_info *h) +/* List of controllers which cannot even be soft reset */ +static u32 soft_unresettable_controller[] = { + /* Exclude 640x boards. These are two pci devices in one slot + * which share a battery backed cache module. One controls the + * cache, the other accesses the cache through the one that controls + * it. If we reset the one controlling the cache, the other will + * likely not be happy. Just forbid resetting this conjoined mess. + * The 640x isn't really supported by hpsa anyway. + */ + 0x409C0E11, /* Smart Array 6400 */ + 0x409D0E11, /* Smart Array 6400 EM */ +}; + +static int ctlr_is_hard_resettable(u32 board_id) { int i; for (i = 0; i < ARRAY_SIZE(unresettable_controller); i++) - if (unresettable_controller[i] == h->board_id) + if (unresettable_controller[i] == board_id) + return 0; + return 1; +} + +static int ctlr_is_soft_resettable(u32 board_id) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(soft_unresettable_controller); i++) + if (soft_unresettable_controller[i] == board_id) return 0; return 1; } +static int ctlr_is_resettable(u32 board_id) +{ + return ctlr_is_hard_resettable(board_id) || + ctlr_is_soft_resettable(board_id); +} + static ssize_t host_show_resettable(struct device *dev, struct device_attribute *attr, char *buf) { @@ -308,7 +337,7 @@ static ssize_t host_show_resettable(struct device *dev, struct Scsi_Host *shost = class_to_shost(dev); h = shost_to_hba(shost); - return snprintf(buf, 20, "%d\n", ctlr_is_resettable(h)); + return snprintf(buf, 20, "%d\n", ctlr_is_resettable(h->board_id)); } static inline int is_logical_dev_addr_mode(unsigned char scsi3addr[]) @@ -3334,20 +3363,15 @@ static __devinit int hpsa_kdump_hard_reset_controller(struct pci_dev *pdev) * using the doorbell register. */ - /* Exclude 640x boards. These are two pci devices in one slot - * which share a battery backed cache module. One controls the - * cache, the other accesses the cache through the one that controls - * it. If we reset the one controlling the cache, the other will - * likely not be happy. Just forbid resetting this conjoined mess. - * The 640x isn't really supported by hpsa anyway. - */ rc = hpsa_lookup_board_id(pdev, &board_id); - if (rc < 0) { + if (rc < 0 || !ctlr_is_resettable(board_id)) { dev_warn(&pdev->dev, "Not resetting device.\n"); return -ENODEV; } - if (board_id == 0x409C0E11 || board_id == 0x409D0E11) - return -ENOTSUPP; + + /* if controller is soft- but not hard resettable... */ + if (!ctlr_is_hard_resettable(board_id)) + return -ENOTSUPP; /* try soft reset later. */ /* Save the PCI command register */ pci_read_config_word(pdev, 4, &command_register); -- cgit v0.10.2 From fda38518f236cbd965110938e324f6c6fcc91f38 Mon Sep 17 00:00:00 2001 From: "Stephen M. Cameron" Date: Tue, 3 May 2011 15:00:07 -0500 Subject: [SCSI] hpsa: add P2000 to list of shared SAS devices Signed-off-by: Scott Teel Signed-off-by: James Bottomley Signed-off-by: James Bottomley diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index 5c03cb5..cffc7bb 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -1591,6 +1591,7 @@ static unsigned char *msa2xxx_model[] = { "MSA2024", "MSA2312", "MSA2324", + "P2000 G3 SAS", NULL, }; -- cgit v0.10.2 From 51f52a47527a07e45746b1bac1ab6123892095a0 Mon Sep 17 00:00:00 2001 From: Anton Blanchard Date: Mon, 9 May 2011 10:07:40 +1000 Subject: [SCSI] ipr: Rate limit DMA mapping errors I noticed a stream of errors from the IPR driver while doing IOMMU fault injection. Rate limit the errors so we don't clog up the console and logfiles. Signed-off-by: Anton Blanchard Acked-by: Brian King Signed-off-by: James Bottomley Signed-off-by: James Bottomley diff --git a/drivers/scsi/ipr.c b/drivers/scsi/ipr.c index 3667f89..12868ca 100644 --- a/drivers/scsi/ipr.c +++ b/drivers/scsi/ipr.c @@ -5200,7 +5200,8 @@ static int ipr_build_ioadl64(struct ipr_ioa_cfg *ioa_cfg, nseg = scsi_dma_map(scsi_cmd); if (nseg < 0) { - dev_err(&ioa_cfg->pdev->dev, "pci_map_sg failed!\n"); + if (printk_ratelimit()) + dev_err(&ioa_cfg->pdev->dev, "pci_map_sg failed!\n"); return -1; } -- cgit v0.10.2 From 7630abd0c690e90cea9412846f596fe1565aaa0e Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Sun, 8 May 2011 23:32:40 -0700 Subject: [SCSI] hpsa: Change memset using sizeof(ptr) to sizeof(*ptr) Not at all sure this is correct or appropriate to change, but this seems odd. Found via coccinelle script @@ type T; T* ptr; expression E1; @@ * memset(E1, 0, sizeof(ptr)); Signed-off-by: Joe Perches Acked-by: Stephen M. Cameron Signed-off-by: James Bottomley Signed-off-by: James Bottomley diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index cffc7bb..c6c0434 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -1329,7 +1329,7 @@ static void hpsa_scsi_do_simple_cmd_with_retry(struct ctlr_info *h, int retry_count = 0; do { - memset(c->err_info, 0, sizeof(c->err_info)); + memset(c->err_info, 0, sizeof(*c->err_info)); hpsa_scsi_do_simple_cmd_core(h, c); retry_count++; } while (check_for_unit_attention(h, c) && retry_count <= 3); -- cgit v0.10.2 From 9f40682e2857a3c2ddb80a87b185af3c6a708346 Mon Sep 17 00:00:00 2001 From: Arun Easi Date: Tue, 10 May 2011 11:18:17 -0700 Subject: [SCSI] qla2xxx: Fix vport delete hang when logins are outstanding. Timer is required to flush out entries that may be present in work queues. Cc: stable@kernel.org Signed-off-by: Arun Easi Signed-off-by: Madhuranath Iyengar Signed-off-by: James Bottomley Signed-off-by: James Bottomley diff --git a/drivers/scsi/qla2xxx/qla_attr.c b/drivers/scsi/qla2xxx/qla_attr.c index 75faf48..260c030 100644 --- a/drivers/scsi/qla2xxx/qla_attr.c +++ b/drivers/scsi/qla2xxx/qla_attr.c @@ -1877,14 +1877,15 @@ qla24xx_vport_delete(struct fc_vport *fc_vport) scsi_remove_host(vha->host); + /* Allow timer to run to drain queued items, when removing vp */ + qla24xx_deallocate_vp_id(vha); + if (vha->timer_active) { qla2x00_vp_stop_timer(vha); DEBUG15(printk(KERN_INFO "scsi(%ld): timer for the vport[%d]" " = %p has stopped\n", vha->host_no, vha->vp_idx, vha)); } - qla24xx_deallocate_vp_id(vha); - /* No pending activities shall be there on the vha now */ DEBUG(msleep(random32()%10)); /* Just to see if something falls on * the net we have placed below */ -- cgit v0.10.2 From cefcaba67ab97fb756b3a6af5139c94d861b660d Mon Sep 17 00:00:00 2001 From: Saurav Kashyap Date: Tue, 10 May 2011 11:18:18 -0700 Subject: [SCSI] qla2xxx: Fix virtual port failing to login after chip reset. This patch ensures qla82xx_watchdog is not being run for the vport. It also makes sure that beacon ON is not done for the vport, as it will lead to the waking up of the dpc thread again and again. Signed-off-by: Saurav Kashyap Signed-off-by: Madhuranath Iyengar Cc: stable@kernel.org Signed-off-by: James Bottomley Signed-off-by: James Bottomley diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c index 0ca6664..7168e7f 100644 --- a/drivers/scsi/qla2xxx/qla_os.c +++ b/drivers/scsi/qla2xxx/qla_os.c @@ -3623,7 +3623,8 @@ qla2x00_timer(scsi_qla_host_t *vha) if (!pci_channel_offline(ha->pdev)) pci_read_config_word(ha->pdev, PCI_VENDOR_ID, &w); - if (IS_QLA82XX(ha)) { + /* Make sure qla82xx_watchdog is run only for physical port */ + if (!vha->vp_idx && IS_QLA82XX(ha)) { if (test_bit(ISP_QUIESCE_NEEDED, &vha->dpc_flags)) start_dpc++; qla82xx_watchdog(vha); @@ -3704,8 +3705,8 @@ qla2x00_timer(scsi_qla_host_t *vha) atomic_read(&vha->loop_down_timer))); } - /* Check if beacon LED needs to be blinked */ - if (ha->beacon_blink_led == 1) { + /* Check if beacon LED needs to be blinked for physical host only */ + if (!vha->vp_idx && (ha->beacon_blink_led == 1)) { set_bit(BEACON_BLINK_NEEDED, &vha->dpc_flags); start_dpc++; } -- cgit v0.10.2 From fa96d927362a422405d65491326f8ef763572e84 Mon Sep 17 00:00:00 2001 From: Andrew Vasquez Date: Tue, 10 May 2011 11:18:15 -0700 Subject: [SCSI] qla2xxx: Properly set the dsd_list_len for dsd_chaining in cmd type 6. The firmware spec has the fcp_data_dseg_len defined as a 32-bit value, while the corresponding field in the driver structure has it defined as a 16-bit value. Cc: stable@kernel.org Signed-off-by: Andrew Vasquez Signed-off-by: Madhuranath Iyengar Cc: stable@kernel.org Signed-off-by: James Bottomley Signed-off-by: James Bottomley diff --git a/drivers/scsi/qla2xxx/qla_fw.h b/drivers/scsi/qla2xxx/qla_fw.h index 73888ae..691783a 100644 --- a/drivers/scsi/qla2xxx/qla_fw.h +++ b/drivers/scsi/qla2xxx/qla_fw.h @@ -416,8 +416,7 @@ struct cmd_type_6 { uint8_t vp_index; uint32_t fcp_data_dseg_address[2]; /* Data segment address. */ - uint16_t fcp_data_dseg_len; /* Data segment length. */ - uint16_t reserved_1; /* MUST be set to 0. */ + uint32_t fcp_data_dseg_len; /* Data segment length. */ }; #define COMMAND_TYPE_7 0x18 /* Command Type 7 entry */ diff --git a/drivers/scsi/qla2xxx/qla_nx.c b/drivers/scsi/qla2xxx/qla_nx.c index acd1ad3..8b217f3 100644 --- a/drivers/scsi/qla2xxx/qla_nx.c +++ b/drivers/scsi/qla2xxx/qla_nx.c @@ -2563,11 +2563,11 @@ qla2xx_build_scsi_type_6_iocbs(srb_t *sp, struct cmd_type_6 *cmd_pkt, dsd_seg = (uint32_t *)&cmd_pkt->fcp_data_dseg_address; *dsd_seg++ = cpu_to_le32(LSD(dsd_ptr->dsd_list_dma)); *dsd_seg++ = cpu_to_le32(MSD(dsd_ptr->dsd_list_dma)); - cmd_pkt->fcp_data_dseg_len = dsd_list_len; + *dsd_seg++ = cpu_to_le32(dsd_list_len); } else { *cur_dsd++ = cpu_to_le32(LSD(dsd_ptr->dsd_list_dma)); *cur_dsd++ = cpu_to_le32(MSD(dsd_ptr->dsd_list_dma)); - *cur_dsd++ = dsd_list_len; + *cur_dsd++ = cpu_to_le32(dsd_list_len); } cur_dsd = (uint32_t *)next_dsd; while (avail_dsds) { -- cgit v0.10.2 From 43ebf16d762b082663976b679b813e1b546548d1 Mon Sep 17 00:00:00 2001 From: Arun Easi Date: Tue, 10 May 2011 11:18:16 -0700 Subject: [SCSI] qla2xxx: Fix hang during driver unload when vport is active. Bumping ref count during fc_vport_terminate() was the cause. vport delete would wait for ref count to drop to zero and that would never happen. Cc: stable@kernel.org Signed-off-by: Arun Easi Signed-off-by: Madhuranath Iyengar Signed-off-by: James Bottomley Signed-off-by: James Bottomley diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c index 7168e7f..010f560 100644 --- a/drivers/scsi/qla2xxx/qla_os.c +++ b/drivers/scsi/qla2xxx/qla_os.c @@ -2368,21 +2368,26 @@ qla2x00_remove_one(struct pci_dev *pdev) base_vha = pci_get_drvdata(pdev); ha = base_vha->hw; - spin_lock_irqsave(&ha->vport_slock, flags); - list_for_each_entry(vha, &ha->vp_list, list) { - atomic_inc(&vha->vref_count); + mutex_lock(&ha->vport_lock); + while (ha->cur_vport_count) { + struct Scsi_Host *scsi_host; - if (vha->fc_vport) { - spin_unlock_irqrestore(&ha->vport_slock, flags); + spin_lock_irqsave(&ha->vport_slock, flags); - fc_vport_terminate(vha->fc_vport); + BUG_ON(base_vha->list.next == &ha->vp_list); + /* This assumes first entry in ha->vp_list is always base vha */ + vha = list_first_entry(&base_vha->list, scsi_qla_host_t, list); + scsi_host = scsi_host_get(vha->host); - spin_lock_irqsave(&ha->vport_slock, flags); - } + spin_unlock_irqrestore(&ha->vport_slock, flags); + mutex_unlock(&ha->vport_lock); + + fc_vport_terminate(vha->fc_vport); + scsi_host_put(vha->host); - atomic_dec(&vha->vref_count); + mutex_lock(&ha->vport_lock); } - spin_unlock_irqrestore(&ha->vport_slock, flags); + mutex_unlock(&ha->vport_lock); set_bit(UNLOADING, &base_vha->dpc_flags); -- cgit v0.10.2 From 53296788f425def50d09c7e0d773bdeaae57c623 Mon Sep 17 00:00:00 2001 From: Saurav Kashyap Date: Tue, 10 May 2011 11:30:06 -0700 Subject: [SCSI] qla2xxx: Update firmware version after flash update for ISP82xx. The driver keeps a copy of the fw_version within the ha structure. For ISP82xx, this local copy doesn't get updated, and as a result, the old firmware version ends up getting displayed. This patch fixes this issue. Signed-off-by: Saurav Kashyap Signed-off-by: Madhuranath Iyengar Signed-off-by: James Bottomley Signed-off-by: James Bottomley diff --git a/drivers/scsi/qla2xxx/qla_init.c b/drivers/scsi/qla2xxx/qla_init.c index 24d2d19..cb69693 100644 --- a/drivers/scsi/qla2xxx/qla_init.c +++ b/drivers/scsi/qla2xxx/qla_init.c @@ -5435,6 +5435,13 @@ qla82xx_restart_isp(scsi_qla_host_t *vha) ha->isp_abort_cnt = 0; clear_bit(ISP_ABORT_RETRY, &vha->dpc_flags); + /* Update the firmware version */ + qla2x00_get_fw_version(vha, &ha->fw_major_version, + &ha->fw_minor_version, &ha->fw_subminor_version, + &ha->fw_attributes, &ha->fw_memory_size, + ha->mpi_version, &ha->mpi_capabilities, + ha->phy_version); + if (ha->fce) { ha->flags.fce_enabled = 1; memset(ha->fce, 0, -- cgit v0.10.2 From 93d29cc63f1832dbbbab721cce1b9f845becf4d7 Mon Sep 17 00:00:00 2001 From: Joe Carnuccio Date: Tue, 10 May 2011 11:30:07 -0700 Subject: [SCSI] qla2xxx: Correct buffer start in edc sysfs debug print. The debug print prints the first byte of the buffer which is buf[8]. Signed-off-by: Joe Carnuccio Signed-off-by: Madhuranath Iyengar Signed-off-by: James Bottomley Signed-off-by: James Bottomley diff --git a/drivers/scsi/qla2xxx/qla_attr.c b/drivers/scsi/qla2xxx/qla_attr.c index 260c030..4e51124 100644 --- a/drivers/scsi/qla2xxx/qla_attr.c +++ b/drivers/scsi/qla2xxx/qla_attr.c @@ -633,7 +633,7 @@ qla2x00_sysfs_write_edc(struct file *filp, struct kobject *kobj, if (rval != QLA_SUCCESS) { DEBUG2(qla_printk(KERN_INFO, ha, "Unable to write EDC (%x) %02x:%02x:%04x:%02x:%02x.\n", - rval, dev, adr, opt, len, *buf)); + rval, dev, adr, opt, len, buf[8])); return 0; } -- cgit v0.10.2 From 134ae078504293cadeecc8550c4def876a42b07b Mon Sep 17 00:00:00 2001 From: Madhuranath Iyengar Date: Tue, 10 May 2011 11:30:08 -0700 Subject: [SCSI] qla2xxx: Use passed in host to initialize local scsi_qla_host in queuecommand function Signed-off-by: Madhuranath Iyengar Signed-off-by: James Bottomley Signed-off-by: James Bottomley diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c index 010f560..8401a6f 100644 --- a/drivers/scsi/qla2xxx/qla_os.c +++ b/drivers/scsi/qla2xxx/qla_os.c @@ -536,7 +536,7 @@ qla2x00_get_new_sp(scsi_qla_host_t *vha, fc_port_t *fcport, static int qla2xxx_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *cmd) { - scsi_qla_host_t *vha = shost_priv(cmd->device->host); + scsi_qla_host_t *vha = shost_priv(host); fc_port_t *fcport = (struct fc_port *) cmd->device->hostdata; struct fc_rport *rport = starget_to_rport(scsi_target(cmd->device)); struct qla_hw_data *ha = vha->hw; -- cgit v0.10.2 From 875efad774f05433210c8d99af405260cfda4f09 Mon Sep 17 00:00:00 2001 From: Chad Dupuis Date: Tue, 10 May 2011 11:30:09 -0700 Subject: [SCSI] qla2xxx: Log if qla82xx firmware fails to load from flash. Signed-off-by: Chad Dupuis Signed-off-by: Madhuranath Iyengar Signed-off-by: James Bottomley Signed-off-by: James Bottomley diff --git a/drivers/scsi/qla2xxx/qla_nx.c b/drivers/scsi/qla2xxx/qla_nx.c index 8b217f3..752b03e 100644 --- a/drivers/scsi/qla2xxx/qla_nx.c +++ b/drivers/scsi/qla2xxx/qla_nx.c @@ -2410,9 +2410,13 @@ qla82xx_load_fw(scsi_qla_host_t *vha) if (qla82xx_fw_load_from_flash(ha) == QLA_SUCCESS) { qla_printk(KERN_ERR, ha, - "Firmware loaded successfully from flash\n"); + "Firmware loaded successfully from flash\n"); return QLA_SUCCESS; + } else { + qla_printk(KERN_ERR, ha, + "Firmware load from flash failed\n"); } + try_blob_fw: qla_printk(KERN_INFO, ha, "Attempting to load firmware from blob\n"); -- cgit v0.10.2 From d652e0937029e1f7cf9b17d639782db1b0c23ea9 Mon Sep 17 00:00:00 2001 From: Chad Dupuis Date: Tue, 10 May 2011 11:30:10 -0700 Subject: [SCSI] qla2xxx: Add qla82xx_rom_unlock() function. Encapsulate the unlocking of the ROM lock in a function for better code readability. Signed-off-by: Chad Dupuis Signed-off-by: Madhuranath Iyengar Signed-off-by: James Bottomley Signed-off-by: James Bottomley diff --git a/drivers/scsi/qla2xxx/qla_gbl.h b/drivers/scsi/qla2xxx/qla_gbl.h index fbb4b8f..53968cc 100644 --- a/drivers/scsi/qla2xxx/qla_gbl.h +++ b/drivers/scsi/qla2xxx/qla_gbl.h @@ -552,7 +552,6 @@ extern int qla82xx_wr_32(struct qla_hw_data *, ulong, u32); extern int qla82xx_rd_32(struct qla_hw_data *, ulong); extern int qla82xx_rdmem(struct qla_hw_data *, u64, void *, int); extern int qla82xx_wrmem(struct qla_hw_data *, u64, void *, int); -extern void qla82xx_rom_unlock(struct qla_hw_data *); /* ISP 8021 IDC */ extern void qla82xx_clear_drv_active(struct qla_hw_data *); diff --git a/drivers/scsi/qla2xxx/qla_nx.c b/drivers/scsi/qla2xxx/qla_nx.c index 752b03e..5d5b603 100644 --- a/drivers/scsi/qla2xxx/qla_nx.c +++ b/drivers/scsi/qla2xxx/qla_nx.c @@ -844,6 +844,12 @@ qla82xx_rom_lock(struct qla_hw_data *ha) return 0; } +static void +qla82xx_rom_unlock(struct qla_hw_data *ha) +{ + qla82xx_rd_32(ha, QLA82XX_PCIE_REG(PCIE_SEM2_UNLOCK)); +} + static int qla82xx_wait_rom_busy(struct qla_hw_data *ha) { @@ -924,7 +930,7 @@ qla82xx_rom_fast_read(struct qla_hw_data *ha, int addr, int *valp) return -1; } ret = qla82xx_do_rom_fast_read(ha, addr, valp); - qla82xx_rd_32(ha, QLA82XX_PCIE_REG(PCIE_SEM2_UNLOCK)); + qla82xx_rom_unlock(ha); return ret; } @@ -1056,7 +1062,7 @@ qla82xx_write_flash_dword(struct qla_hw_data *ha, uint32_t flashaddr, ret = qla82xx_flash_wait_write_finish(ha); done_write: - qla82xx_rd_32(ha, QLA82XX_PCIE_REG(PCIE_SEM2_UNLOCK)); + qla82xx_rom_unlock(ha); return ret; } @@ -1144,7 +1150,7 @@ qla82xx_pinit_from_rom(scsi_qla_host_t *vha) qla82xx_wr_32(ha, QLA82XX_CRB_QDR_NET + 0xe4, val); msleep(20); - qla82xx_rd_32(ha, QLA82XX_PCIE_REG(PCIE_SEM2_UNLOCK)); + qla82xx_rom_unlock(ha); /* Read the signature value from the flash. * Offset 0: Contain signature (0xcafecafe) @@ -3010,7 +3016,7 @@ qla82xx_unprotect_flash(struct qla_hw_data *ha) qla_printk(KERN_WARNING, ha, "Write disable failed\n"); done_unprotect: - qla82xx_rd_32(ha, QLA82XX_PCIE_REG(PCIE_SEM2_UNLOCK)); + qla82xx_rom_unlock(ha); return ret; } @@ -3039,7 +3045,7 @@ qla82xx_protect_flash(struct qla_hw_data *ha) if (qla82xx_write_disable_flash(ha) != 0) qla_printk(KERN_WARNING, ha, "Write disable failed\n"); done_protect: - qla82xx_rd_32(ha, QLA82XX_PCIE_REG(PCIE_SEM2_UNLOCK)); + qla82xx_rom_unlock(ha); return ret; } @@ -3067,7 +3073,7 @@ qla82xx_erase_sector(struct qla_hw_data *ha, int addr) } ret = qla82xx_flash_wait_write_finish(ha); done: - qla82xx_rd_32(ha, QLA82XX_PCIE_REG(PCIE_SEM2_UNLOCK)); + qla82xx_rom_unlock(ha); return ret; } @@ -3247,7 +3253,7 @@ void qla82xx_rom_lock_recovery(struct qla_hw_data *ha) * else died while holding it. * In either case, unlock. */ - qla82xx_rd_32(ha, QLA82XX_PCIE_REG(PCIE_SEM2_UNLOCK)); + qla82xx_rom_unlock(ha); } /* -- cgit v0.10.2 From 1bff6cc8fbb73d6bed809d3eff18e90c175a601c Mon Sep 17 00:00:00 2001 From: Joe Carnuccio Date: Tue, 10 May 2011 11:30:11 -0700 Subject: [SCSI] qla2xxx: Correctly read sfp single byte mailbox register. When reading a single byte using the READ SFP mailbox command, the single byte of data is returned in MB[1] and not MB[8]. The reason that MB[8] was being used is that the spec was unclear as it evolved over time; and we have not needed to read a single byte until recently. Signed-off-by: Joe Carnuccio Signed-off-by: Madhuranath Iyengar Signed-off-by: James Bottomley Signed-off-by: James Bottomley diff --git a/drivers/scsi/qla2xxx/qla_mbx.c b/drivers/scsi/qla2xxx/qla_mbx.c index 975aeaa..aab628b 100644 --- a/drivers/scsi/qla2xxx/qla_mbx.c +++ b/drivers/scsi/qla2xxx/qla_mbx.c @@ -3608,14 +3608,14 @@ qla2x00_read_edc(scsi_qla_host_t *vha, uint16_t dev, uint16_t adr, mcp->mb[9] = adr; mcp->mb[10] = opt; mcp->out_mb = MBX_10|MBX_9|MBX_8|MBX_7|MBX_6|MBX_3|MBX_2|MBX_1|MBX_0; - mcp->in_mb = MBX_0; + mcp->in_mb = MBX_1|MBX_0; mcp->tov = MBX_TOV_SECONDS; mcp->flags = 0; rval = qla2x00_mailbox_command(vha, mcp); if (opt & BIT_0) if (sfp) - *sfp = mcp->mb[8]; + *sfp = mcp->mb[1]; if (rval != QLA_SUCCESS) { DEBUG2_3_11(printk("%s(%ld): failed=%x (%x).\n", __func__, -- cgit v0.10.2 From 24014d046485e1947dfb5d79365472d9981cda1e Mon Sep 17 00:00:00 2001 From: Saurav Kashyap Date: Tue, 10 May 2011 11:30:12 -0700 Subject: [SCSI] qla2xxx: Add host number in reset and quiescent message logs. Signed-off-by: Saurav Kashyap Signed-off-by: Madhuranath Iyengar Signed-off-by: James Bottomley Signed-off-by: James Bottomley diff --git a/drivers/scsi/qla2xxx/qla_nx.c b/drivers/scsi/qla2xxx/qla_nx.c index 5d5b603..e1138bc 100644 --- a/drivers/scsi/qla2xxx/qla_nx.c +++ b/drivers/scsi/qla2xxx/qla_nx.c @@ -3657,7 +3657,8 @@ void qla82xx_watchdog(scsi_qla_host_t *vha) if (dev_state == QLA82XX_DEV_NEED_RESET && !test_bit(ISP_ABORT_NEEDED, &vha->dpc_flags)) { qla_printk(KERN_WARNING, ha, - "%s(): Adapter reset needed!\n", __func__); + "scsi(%ld) %s: Adapter reset needed!\n", + vha->host_no, __func__); set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags); qla2xxx_wake_dpc(vha); } else if (dev_state == QLA82XX_DEV_NEED_QUIESCENT && @@ -3704,8 +3705,9 @@ void qla82xx_watchdog(scsi_qla_host_t *vha) if (ha->flags.mbox_busy) { ha->flags.mbox_int = 1; DEBUG2(qla_printk(KERN_ERR, ha, - "Due to fw hung, doing premature " - "completion of mbx command\n")); + "scsi(%ld) Due to fw hung, doing " + "premature completion of mbx " + "command\n", vha->host_no)); if (test_bit(MBX_INTR_WAIT, &ha->mbx_cmd_flags)) complete(&ha->mbx_intr_comp); -- cgit v0.10.2 From 82515920b60760bca9f66decdaa7dd98191fa47c Mon Sep 17 00:00:00 2001 From: Andrew Vasquez Date: Tue, 10 May 2011 11:30:13 -0700 Subject: [SCSI] qla2xxx: Allow an override of the registered maximum LUN. The 'max_lun' value registered for each scsi_host is currently capped at 0xffff. The new module parameter can allow for 2nd-level flat-space addressing method-infrastructure to be supported. Signed-off-by: Andrew Vasquez Signed-off-by: Madhuranath Iyengar Signed-off-by: James Bottomley Signed-off-by: James Bottomley diff --git a/drivers/scsi/qla2xxx/qla_gbl.h b/drivers/scsi/qla2xxx/qla_gbl.h index 53968cc..79a12aa 100644 --- a/drivers/scsi/qla2xxx/qla_gbl.h +++ b/drivers/scsi/qla2xxx/qla_gbl.h @@ -103,6 +103,7 @@ extern int ql2xenabledif; extern int ql2xenablehba_err_chk; extern int ql2xtargetreset; extern int ql2xdontresethba; +extern unsigned int ql2xmaxlun; extern int qla2x00_loop_reset(scsi_qla_host_t *); extern void qla2x00_abort_all_cmds(scsi_qla_host_t *, int); diff --git a/drivers/scsi/qla2xxx/qla_mid.c b/drivers/scsi/qla2xxx/qla_mid.c index e34d7dd..5e34391 100644 --- a/drivers/scsi/qla2xxx/qla_mid.c +++ b/drivers/scsi/qla2xxx/qla_mid.c @@ -456,7 +456,7 @@ qla24xx_create_vhost(struct fc_vport *fc_vport) else host->max_cmd_len = MAX_CMDSZ; host->max_channel = MAX_BUSES - 1; - host->max_lun = MAX_LUNS; + host->max_lun = ql2xmaxlun; host->unique_id = host->host_no; host->max_id = MAX_TARGETS_2200; host->transportt = qla2xxx_transport_vport_template; diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c index 8401a6f..f461925 100644 --- a/drivers/scsi/qla2xxx/qla_os.c +++ b/drivers/scsi/qla2xxx/qla_os.c @@ -172,6 +172,12 @@ MODULE_PARM_DESC(ql2xdontresethba, " 0 (Default) -- Reset on failure.\n" " 1 -- Do not reset on failure.\n"); +uint ql2xmaxlun = MAX_LUNS; +module_param(ql2xmaxlun, uint, S_IRUGO); +MODULE_PARM_DESC(ql2xmaxlun, + "Defines the maximum LU number to register with the SCSI " + "midlayer. Default is 65535."); + /* * SCSI host template entry points */ @@ -2136,7 +2142,7 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id) else host->max_cmd_len = MAX_CMDSZ; host->max_channel = MAX_BUSES - 1; - host->max_lun = MAX_LUNS; + host->max_lun = ql2xmaxlun; host->transportt = qla2xxx_transport_template; sht->vendor_id = (SCSI_NL_VID_TYPE_PCI | PCI_VENDOR_ID_QLOGIC); -- cgit v0.10.2 From 773120e4df1d2bf543345ad850cc92dc1f1bad8a Mon Sep 17 00:00:00 2001 From: Andrew Vasquez Date: Tue, 10 May 2011 11:30:14 -0700 Subject: [SCSI] qla2xxx: Clear complete initialization control block. Use proper init_cb_size member which takes into account MID/non-MID init-cb structure sizes. Signed-off-by: Andrew Vasquez Signed-off-by: Madhuranath Iyengar Signed-off-by: James Bottomley Signed-off-by: James Bottomley diff --git a/drivers/scsi/qla2xxx/qla_init.c b/drivers/scsi/qla2xxx/qla_init.c index cb69693..920b76b 100644 --- a/drivers/scsi/qla2xxx/qla_init.c +++ b/drivers/scsi/qla2xxx/qla_init.c @@ -5210,7 +5210,7 @@ qla81xx_nvram_config(scsi_qla_host_t *vha) } /* Reset Initialization control block */ - memset(icb, 0, sizeof(struct init_cb_81xx)); + memset(icb, 0, ha->init_cb_size); /* Copy 1st segment. */ dptr1 = (uint8_t *)icb; -- cgit v0.10.2 From 6766df9e8ae2ab29459381ade1ca91b28688ab13 Mon Sep 17 00:00:00 2001 From: Joe Carnuccio Date: Tue, 10 May 2011 11:30:15 -0700 Subject: [SCSI] qla2xxx: Unify the read/write sfp mailbox command routines. Make the read/write sfp mailbox command routines uniform, and remove redundancy. Also protect against attempting to do a single byte dma in these routines. Signed-off-by: Joe Carnuccio Signed-off-by: Madhuranath Iyengar Signed-off-by: James Bottomley Signed-off-by: James Bottomley diff --git a/drivers/scsi/qla2xxx/qla_attr.c b/drivers/scsi/qla2xxx/qla_attr.c index 4e51124..532313e 100644 --- a/drivers/scsi/qla2xxx/qla_attr.c +++ b/drivers/scsi/qla2xxx/qla_attr.c @@ -496,8 +496,8 @@ do_read: offset = 0; } - rval = qla2x00_read_sfp(vha, ha->sfp_data_dma, addr, offset, - SFP_BLOCK_SIZE); + rval = qla2x00_read_sfp(vha, ha->sfp_data_dma, ha->sfp_data, + addr, offset, SFP_BLOCK_SIZE, 0); if (rval != QLA_SUCCESS) { qla_printk(KERN_WARNING, ha, "Unable to read SFP data (%x/%x/%x).\n", rval, @@ -628,8 +628,8 @@ qla2x00_sysfs_write_edc(struct file *filp, struct kobject *kobj, memcpy(ha->edc_data, &buf[8], len); - rval = qla2x00_write_edc(vha, dev, adr, ha->edc_data_dma, - ha->edc_data, len, opt); + rval = qla2x00_write_sfp(vha, ha->edc_data_dma, ha->edc_data, + dev, adr, len, opt); if (rval != QLA_SUCCESS) { DEBUG2(qla_printk(KERN_INFO, ha, "Unable to write EDC (%x) %02x:%02x:%04x:%02x:%02x.\n", @@ -685,8 +685,8 @@ qla2x00_sysfs_write_edc_status(struct file *filp, struct kobject *kobj, return -EINVAL; memset(ha->edc_data, 0, len); - rval = qla2x00_read_edc(vha, dev, adr, ha->edc_data_dma, - ha->edc_data, len, opt); + rval = qla2x00_read_sfp(vha, ha->edc_data_dma, ha->edc_data, + dev, adr, len, opt); if (rval != QLA_SUCCESS) { DEBUG2(qla_printk(KERN_INFO, ha, "Unable to write EDC status (%x) %02x:%02x:%04x:%02x.\n", diff --git a/drivers/scsi/qla2xxx/qla_gbl.h b/drivers/scsi/qla2xxx/qla_gbl.h index 79a12aa..0b38122 100644 --- a/drivers/scsi/qla2xxx/qla_gbl.h +++ b/drivers/scsi/qla2xxx/qla_gbl.h @@ -323,15 +323,12 @@ extern int qla2x00_disable_fce_trace(scsi_qla_host_t *, uint64_t *, uint64_t *); extern int -qla2x00_read_sfp(scsi_qla_host_t *, dma_addr_t, uint16_t, uint16_t, uint16_t); +qla2x00_read_sfp(scsi_qla_host_t *, dma_addr_t, uint8_t *, + uint16_t, uint16_t, uint16_t, uint16_t); extern int -qla2x00_read_edc(scsi_qla_host_t *, uint16_t, uint16_t, dma_addr_t, - uint8_t *, uint16_t, uint16_t); - -extern int -qla2x00_write_edc(scsi_qla_host_t *, uint16_t, uint16_t, dma_addr_t, - uint8_t *, uint16_t, uint16_t); +qla2x00_write_sfp(scsi_qla_host_t *, dma_addr_t, uint8_t *, + uint16_t, uint16_t, uint16_t, uint16_t); extern int qla2x00_set_idma_speed(scsi_qla_host_t *, uint16_t, uint16_t, uint16_t *); diff --git a/drivers/scsi/qla2xxx/qla_mbx.c b/drivers/scsi/qla2xxx/qla_mbx.c index aab628b..7184b87 100644 --- a/drivers/scsi/qla2xxx/qla_mbx.c +++ b/drivers/scsi/qla2xxx/qla_mbx.c @@ -2787,44 +2787,6 @@ qla2x00_disable_fce_trace(scsi_qla_host_t *vha, uint64_t *wr, uint64_t *rd) } int -qla2x00_read_sfp(scsi_qla_host_t *vha, dma_addr_t sfp_dma, uint16_t addr, - uint16_t off, uint16_t count) -{ - int rval; - mbx_cmd_t mc; - mbx_cmd_t *mcp = &mc; - - if (!IS_FWI2_CAPABLE(vha->hw)) - return QLA_FUNCTION_FAILED; - - DEBUG11(printk("%s(%ld): entered.\n", __func__, vha->host_no)); - - mcp->mb[0] = MBC_READ_SFP; - mcp->mb[1] = addr; - mcp->mb[2] = MSW(sfp_dma); - mcp->mb[3] = LSW(sfp_dma); - mcp->mb[6] = MSW(MSD(sfp_dma)); - mcp->mb[7] = LSW(MSD(sfp_dma)); - mcp->mb[8] = count; - mcp->mb[9] = off; - mcp->mb[10] = 0; - mcp->out_mb = MBX_10|MBX_9|MBX_8|MBX_7|MBX_6|MBX_3|MBX_2|MBX_1|MBX_0; - mcp->in_mb = MBX_0; - mcp->tov = MBX_TOV_SECONDS; - mcp->flags = 0; - rval = qla2x00_mailbox_command(vha, mcp); - - if (rval != QLA_SUCCESS) { - DEBUG2_3_11(printk("%s(%ld): failed=%x (%x).\n", __func__, - vha->host_no, rval, mcp->mb[0])); - } else { - DEBUG11(printk("%s(%ld): done.\n", __func__, vha->host_no)); - } - - return rval; -} - -int qla2x00_get_idma_speed(scsi_qla_host_t *vha, uint16_t loop_id, uint16_t *port_speed, uint16_t *mb) { @@ -3589,15 +3551,22 @@ qla81xx_restart_mpi_firmware(scsi_qla_host_t *vha) } int -qla2x00_read_edc(scsi_qla_host_t *vha, uint16_t dev, uint16_t adr, - dma_addr_t sfp_dma, uint8_t *sfp, uint16_t len, uint16_t opt) +qla2x00_read_sfp(scsi_qla_host_t *vha, dma_addr_t sfp_dma, uint8_t *sfp, + uint16_t dev, uint16_t off, uint16_t len, uint16_t opt) { int rval; mbx_cmd_t mc; mbx_cmd_t *mcp = &mc; + struct qla_hw_data *ha = vha->hw; + + if (!IS_FWI2_CAPABLE(ha)) + return QLA_FUNCTION_FAILED; DEBUG11(printk("%s(%ld): entered.\n", __func__, vha->host_no)); + if (len == 1) + opt |= BIT_0; + mcp->mb[0] = MBC_READ_SFP; mcp->mb[1] = dev; mcp->mb[2] = MSW(sfp_dma); @@ -3605,7 +3574,7 @@ qla2x00_read_edc(scsi_qla_host_t *vha, uint16_t dev, uint16_t adr, mcp->mb[6] = MSW(MSD(sfp_dma)); mcp->mb[7] = LSW(MSD(sfp_dma)); mcp->mb[8] = len; - mcp->mb[9] = adr; + mcp->mb[9] = off; mcp->mb[10] = opt; mcp->out_mb = MBX_10|MBX_9|MBX_8|MBX_7|MBX_6|MBX_3|MBX_2|MBX_1|MBX_0; mcp->in_mb = MBX_1|MBX_0; @@ -3614,8 +3583,7 @@ qla2x00_read_edc(scsi_qla_host_t *vha, uint16_t dev, uint16_t adr, rval = qla2x00_mailbox_command(vha, mcp); if (opt & BIT_0) - if (sfp) - *sfp = mcp->mb[1]; + *sfp = mcp->mb[1]; if (rval != QLA_SUCCESS) { DEBUG2_3_11(printk("%s(%ld): failed=%x (%x).\n", __func__, @@ -3628,18 +3596,24 @@ qla2x00_read_edc(scsi_qla_host_t *vha, uint16_t dev, uint16_t adr, } int -qla2x00_write_edc(scsi_qla_host_t *vha, uint16_t dev, uint16_t adr, - dma_addr_t sfp_dma, uint8_t *sfp, uint16_t len, uint16_t opt) +qla2x00_write_sfp(scsi_qla_host_t *vha, dma_addr_t sfp_dma, uint8_t *sfp, + uint16_t dev, uint16_t off, uint16_t len, uint16_t opt) { int rval; mbx_cmd_t mc; mbx_cmd_t *mcp = &mc; + struct qla_hw_data *ha = vha->hw; + + if (!IS_FWI2_CAPABLE(ha)) + return QLA_FUNCTION_FAILED; DEBUG11(printk("%s(%ld): entered.\n", __func__, vha->host_no)); + if (len == 1) + opt |= BIT_0; + if (opt & BIT_0) - if (sfp) - len = *sfp; + len = *sfp; mcp->mb[0] = MBC_WRITE_SFP; mcp->mb[1] = dev; @@ -3648,10 +3622,10 @@ qla2x00_write_edc(scsi_qla_host_t *vha, uint16_t dev, uint16_t adr, mcp->mb[6] = MSW(MSD(sfp_dma)); mcp->mb[7] = LSW(MSD(sfp_dma)); mcp->mb[8] = len; - mcp->mb[9] = adr; + mcp->mb[9] = off; mcp->mb[10] = opt; mcp->out_mb = MBX_10|MBX_9|MBX_8|MBX_7|MBX_6|MBX_3|MBX_2|MBX_1|MBX_0; - mcp->in_mb = MBX_0; + mcp->in_mb = MBX_1|MBX_0; mcp->tov = MBX_TOV_SECONDS; mcp->flags = 0; rval = qla2x00_mailbox_command(vha, mcp); -- cgit v0.10.2 From 6ad11eaa8a689a27e0c99905bcf800a37cd432a0 Mon Sep 17 00:00:00 2001 From: Joe Carnuccio Date: Tue, 10 May 2011 11:30:16 -0700 Subject: [SCSI] qla2xxx: Refactor call to qla2xxx_read_sfp for thermal temperature. Eliminate duplicate code by refactoring the calls to qla2xxx_read_sfp() in qla2x00_get_thermal_temp(). This keeps the parameter values separate from the mailbox register mechanics. This also allows qla2xxx_read_sfp() to be the sole "spec" for READ SFP semantics. Signed-off_by: Joe Carnuccio Signed-off-by: Madhuranath Iyengar Signed-off-by: James Bottomley Signed-off-by: James Bottomley diff --git a/drivers/scsi/qla2xxx/qla_mbx.c b/drivers/scsi/qla2xxx/qla_mbx.c index 7184b87..c26f0ac 100644 --- a/drivers/scsi/qla2xxx/qla_mbx.c +++ b/drivers/scsi/qla2xxx/qla_mbx.c @@ -4142,63 +4142,32 @@ int qla2x00_get_thermal_temp(scsi_qla_host_t *vha, uint16_t *temp, uint16_t *frac) { int rval; - mbx_cmd_t mc; - mbx_cmd_t *mcp = &mc; + uint8_t byte; struct qla_hw_data *ha = vha->hw; - DEBUG11(printk(KERN_INFO "%s(%ld): entered.\n", __func__, ha->host_no)); + DEBUG11(printk(KERN_INFO "%s(%ld): entered.\n", __func__, vha->host_no)); - /* High bits. */ - mcp->mb[0] = MBC_READ_SFP; - mcp->mb[1] = 0x98; - mcp->mb[2] = 0; - mcp->mb[3] = 0; - mcp->mb[6] = 0; - mcp->mb[7] = 0; - mcp->mb[8] = 1; - mcp->mb[9] = 0x01; - mcp->mb[10] = BIT_13|BIT_0; - mcp->out_mb = MBX_10|MBX_9|MBX_8|MBX_7|MBX_6|MBX_3|MBX_2|MBX_1|MBX_0; - mcp->in_mb = MBX_1|MBX_0; - mcp->tov = MBX_TOV_SECONDS; - mcp->flags = 0; - rval = qla2x00_mailbox_command(vha, mcp); + /* Integer part */ + rval = qla2x00_read_sfp(vha, 0, &byte, 0x98, 0x01, 1, BIT_13|BIT_0); if (rval != QLA_SUCCESS) { DEBUG2_3_11(printk(KERN_WARNING - "%s(%ld): failed=%x (%x).\n", __func__, - vha->host_no, rval, mcp->mb[0])); + "%s(%ld): failed=%x.\n", __func__, vha->host_no, rval)); ha->flags.thermal_supported = 0; goto fail; } - *temp = mcp->mb[1] & 0xFF; + *temp = byte; - /* Low bits. */ - mcp->mb[0] = MBC_READ_SFP; - mcp->mb[1] = 0x98; - mcp->mb[2] = 0; - mcp->mb[3] = 0; - mcp->mb[6] = 0; - mcp->mb[7] = 0; - mcp->mb[8] = 1; - mcp->mb[9] = 0x10; - mcp->mb[10] = BIT_13|BIT_0; - mcp->out_mb = MBX_10|MBX_9|MBX_8|MBX_7|MBX_6|MBX_3|MBX_2|MBX_1|MBX_0; - mcp->in_mb = MBX_1|MBX_0; - mcp->tov = MBX_TOV_SECONDS; - mcp->flags = 0; - rval = qla2x00_mailbox_command(vha, mcp); + /* Fraction part */ + rval = qla2x00_read_sfp(vha, 0, &byte, 0x98, 0x10, 1, BIT_13|BIT_0); if (rval != QLA_SUCCESS) { DEBUG2_3_11(printk(KERN_WARNING - "%s(%ld): failed=%x (%x).\n", __func__, - vha->host_no, rval, mcp->mb[0])); + "%s(%ld): failed=%x.\n", __func__, vha->host_no, rval)); ha->flags.thermal_supported = 0; goto fail; } - *frac = ((mcp->mb[1] & 0xFF) >> 6) * 25; + *frac = (byte >> 6) * 25; - if (rval == QLA_SUCCESS) - DEBUG11(printk(KERN_INFO - "%s(%ld): done.\n", __func__, ha->host_no)); + DEBUG11(printk(KERN_INFO "%s(%ld): done.\n", __func__, vha->host_no)); fail: return rval; } -- cgit v0.10.2 From 9937a5e2f32892db0dbeefc2b3bc74b3ae3ea9c7 Mon Sep 17 00:00:00 2001 From: Jens Axboe Date: Tue, 17 May 2011 11:04:44 +0200 Subject: scsi: remove performance regression due to async queue run Commit c21e6beb removed our queue request_fn re-enter protection, and defaulted to always running the queues from kblockd to be safe. This was a known potential slow down, but should be safe. Unfortunately this is causing big performance regressions for some, so we need to improve this logic. Looking into the details of the re-enter, the real issue is on requeue of requests. Requeue of requests upon seeing a BUSY condition from the device ends up re-running the queue, causing traces like this: scsi_request_fn() scsi_dispatch_cmd() scsi_queue_insert() __scsi_queue_insert() scsi_run_queue() scsi_request_fn() ... potentially causing the issue we want to avoid. So special case the requeue re-run of the queue, but improve it to offload the entire run of local queue and starved queue from a single workqueue callback. This is a lot better than potentially kicking off a workqueue run for each device seen. This also fixes the issue of the local device going into recursion, since the above mentioned commit never moved that queue run out of line. Signed-off-by: Jens Axboe diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c index e9901b8..01e4e51 100644 --- a/drivers/scsi/scsi_lib.c +++ b/drivers/scsi/scsi_lib.c @@ -74,8 +74,6 @@ struct kmem_cache *scsi_sdb_cache; */ #define SCSI_QUEUE_DELAY 3 -static void scsi_run_queue(struct request_queue *q); - /* * Function: scsi_unprep_request() * @@ -161,7 +159,7 @@ static int __scsi_queue_insert(struct scsi_cmnd *cmd, int reason, int unbusy) blk_requeue_request(q, cmd->request); spin_unlock_irqrestore(q->queue_lock, flags); - scsi_run_queue(q); + kblockd_schedule_work(q, &device->requeue_work); return 0; } @@ -433,7 +431,11 @@ static void scsi_run_queue(struct request_queue *q) continue; } - blk_run_queue_async(sdev->request_queue); + spin_unlock(shost->host_lock); + spin_lock(sdev->request_queue->queue_lock); + __blk_run_queue(sdev->request_queue); + spin_unlock(sdev->request_queue->queue_lock); + spin_lock(shost->host_lock); } /* put any unprocessed entries back */ list_splice(&starved_list, &shost->starved_list); @@ -442,6 +444,16 @@ static void scsi_run_queue(struct request_queue *q) blk_run_queue(q); } +void scsi_requeue_run_queue(struct work_struct *work) +{ + struct scsi_device *sdev; + struct request_queue *q; + + sdev = container_of(work, struct scsi_device, requeue_work); + q = sdev->request_queue; + scsi_run_queue(q); +} + /* * Function: scsi_requeue_command() * diff --git a/drivers/scsi/scsi_scan.c b/drivers/scsi/scsi_scan.c index 087821f..58584dc 100644 --- a/drivers/scsi/scsi_scan.c +++ b/drivers/scsi/scsi_scan.c @@ -242,6 +242,7 @@ static struct scsi_device *scsi_alloc_sdev(struct scsi_target *starget, int display_failure_msg = 1, ret; struct Scsi_Host *shost = dev_to_shost(starget->dev.parent); extern void scsi_evt_thread(struct work_struct *work); + extern void scsi_requeue_run_queue(struct work_struct *work); sdev = kzalloc(sizeof(*sdev) + shost->transportt->device_size, GFP_ATOMIC); @@ -264,6 +265,7 @@ static struct scsi_device *scsi_alloc_sdev(struct scsi_target *starget, INIT_LIST_HEAD(&sdev->event_list); spin_lock_init(&sdev->list_lock); INIT_WORK(&sdev->event_work, scsi_evt_thread); + INIT_WORK(&sdev->requeue_work, scsi_requeue_run_queue); sdev->sdev_gendev.parent = get_device(&starget->dev); sdev->sdev_target = starget; diff --git a/include/scsi/scsi_device.h b/include/scsi/scsi_device.h index 2d3ec50..dd82e02 100644 --- a/include/scsi/scsi_device.h +++ b/include/scsi/scsi_device.h @@ -169,6 +169,7 @@ struct scsi_device { sdev_dev; struct execute_work ew; /* used to get process context on put */ + struct work_struct requeue_work; struct scsi_dh_data *scsi_dh_data; enum scsi_device_state sdev_state; -- cgit v0.10.2 From 328935e6348c6a7cb34798a68c326f4b8372e68a Mon Sep 17 00:00:00 2001 From: Borislav Petkov Date: Tue, 17 May 2011 14:55:18 +0200 Subject: Revert "x86, AMD: Fix APIC timer erratum 400 affecting K8 Rev.A-E processors" This reverts commit e20a2d205c05cef6b5783df339a7d54adeb50962, as it crashes certain boxes with specific AMD CPU models. Moving the lower endpoint of the Erratum 400 check to accomodate earlier K8 revisions (A-E) opens a can of worms which is simply not worth to fix properly by tweaking the errata checking framework: * missing IntPenging MSR on revisions < CG cause #GP: http://marc.info/?l=linux-kernel&m=130541471818831 * makes earlier revisions use the LAPIC timer instead of the C1E idle routine which switches to HPET, thus not waking up in deeper C-states: http://lkml.org/lkml/2011/4/24/20 Therefore, leave the original boundary starting with K8-revF. Signed-off-by: Ingo Molnar diff --git a/arch/x86/kernel/cpu/amd.c b/arch/x86/kernel/cpu/amd.c index bb9eb29..3532d3b 100644 --- a/arch/x86/kernel/cpu/amd.c +++ b/arch/x86/kernel/cpu/amd.c @@ -698,7 +698,7 @@ cpu_dev_register(amd_cpu_dev); */ const int amd_erratum_400[] = - AMD_OSVW_ERRATUM(1, AMD_MODEL_RANGE(0x0f, 0x4, 0x2, 0xff, 0xf), + AMD_OSVW_ERRATUM(1, AMD_MODEL_RANGE(0xf, 0x41, 0x2, 0xff, 0xf), AMD_MODEL_RANGE(0x10, 0x2, 0x1, 0xff, 0xf)); EXPORT_SYMBOL_GPL(amd_erratum_400); -- cgit v0.10.2 From 14fb57dccb6e1defe9f89a66f548fcb24c374c1d Mon Sep 17 00:00:00 2001 From: Borislav Petkov Date: Tue, 17 May 2011 14:55:19 +0200 Subject: x86, AMD: Fix ARAT feature setting again Trying to enable the local APIC timer on early K8 revisions uncovers a number of other issues with it, in conjunction with the C1E enter path on AMD. Fixing those causes much more churn and troubles than the benefit of using that timer brings so don't enable it on K8 at all, falling back to the original functionality the kernel had wrt to that. Reported-and-bisected-by: Nick Bowler Cc: Boris Ostrovsky Cc: Andreas Herrmann Cc: Greg Kroah-Hartman Cc: Hans Rosenfeld Cc: Nick Bowler Cc: Joerg-Volker-Peetz Signed-off-by: Borislav Petkov Link: http://lkml.kernel.org/r/1305636919-31165-3-git-send-email-bp@amd64.org Signed-off-by: Ingo Molnar diff --git a/arch/x86/kernel/cpu/amd.c b/arch/x86/kernel/cpu/amd.c index 3532d3b..6f9d1f6 100644 --- a/arch/x86/kernel/cpu/amd.c +++ b/arch/x86/kernel/cpu/amd.c @@ -613,7 +613,7 @@ static void __cpuinit init_amd(struct cpuinfo_x86 *c) #endif /* As a rule processors have APIC timer running in deep C states */ - if (c->x86 >= 0xf && !cpu_has_amd_erratum(amd_erratum_400)) + if (c->x86 > 0xf && !cpu_has_amd_erratum(amd_erratum_400)) set_cpu_cap(c, X86_FEATURE_ARAT); /* -- cgit v0.10.2 From 372b2312010bece1e36f577d6c99a6193ec54cbd Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Tue, 17 May 2011 13:56:59 -0400 Subject: net: use hlist_del_rcu() in dev_change_name() Using plain hlist_del() in dev_change_name() is wrong since a concurrent reader can crash trying to dereference LIST_POISON1. Bug introduced in commit 72c9528bab94 (net: Introduce dev_get_by_name_rcu()) Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller diff --git a/net/core/dev.c b/net/core/dev.c index b624fe4..30a4078 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -1007,7 +1007,7 @@ rollback: } write_lock_bh(&dev_base_lock); - hlist_del(&dev->name_hlist); + hlist_del_rcu(&dev->name_hlist); write_unlock_bh(&dev_base_lock); synchronize_rcu(); -- cgit v0.10.2 From f56e03e8dc149bf0ac2888d6843584f48c8700fc Mon Sep 17 00:00:00 2001 From: Vasiliy Kulikov Date: Tue, 17 May 2011 00:16:56 +0000 Subject: net: ping: fix build failure If CONFIG_PROC_SYSCTL=n the building process fails: ping.c:(.text+0x52af3): undefined reference to `inet_get_ping_group_range_net' Moved inet_get_ping_group_range_net() to ping.c. Reported-by: Randy Dunlap Signed-off-by: Vasiliy Kulikov Acked-by: Eric Dumazet Acked-by: Randy Dunlap Signed-off-by: David S. Miller diff --git a/include/net/ping.h b/include/net/ping.h index 23062c3..682b5ae 100644 --- a/include/net/ping.h +++ b/include/net/ping.h @@ -44,8 +44,6 @@ extern struct proto ping_prot; extern void ping_rcv(struct sk_buff *); extern void ping_err(struct sk_buff *, u32 info); -extern void inet_get_ping_group_range_net(struct net *net, unsigned int *low, unsigned int *high); - #ifdef CONFIG_PROC_FS extern int __init ping_proc_init(void); extern void ping_proc_exit(void); diff --git a/net/ipv4/ping.c b/net/ipv4/ping.c index 41836ab..6a21da9 100644 --- a/net/ipv4/ping.c +++ b/net/ipv4/ping.c @@ -187,6 +187,19 @@ exit: return sk; } +static void inet_get_ping_group_range_net(struct net *net, gid_t *low, gid_t *high) +{ + gid_t *data = net->ipv4.sysctl_ping_group_range; + unsigned seq; + do { + seq = read_seqbegin(&sysctl_local_ports.lock); + + *low = data[0]; + *high = data[1]; + } while (read_seqretry(&sysctl_local_ports.lock, seq)); +} + + static int ping_init_sock(struct sock *sk) { struct net *net = sock_net(sk); diff --git a/net/ipv4/sysctl_net_ipv4.c b/net/ipv4/sysctl_net_ipv4.c index 28e8273..57d0752 100644 --- a/net/ipv4/sysctl_net_ipv4.c +++ b/net/ipv4/sysctl_net_ipv4.c @@ -73,18 +73,6 @@ static int ipv4_local_port_range(ctl_table *table, int write, } -void inet_get_ping_group_range_net(struct net *net, gid_t *low, gid_t *high) -{ - gid_t *data = net->ipv4.sysctl_ping_group_range; - unsigned seq; - do { - seq = read_seqbegin(&sysctl_local_ports.lock); - - *low = data[0]; - *high = data[1]; - } while (read_seqretry(&sysctl_local_ports.lock, seq)); -} - void inet_get_ping_group_range_table(struct ctl_table *table, gid_t *low, gid_t *high) { gid_t *data = table->data; -- cgit v0.10.2 From 94692349c4fc1bc74c19a28f9379509361a06a3b Mon Sep 17 00:00:00 2001 From: Stephane Eranian Date: Tue, 17 May 2011 15:36:19 +0200 Subject: perf: Fix multi-event parsing bug This patch fixes an issue with event parsing. The following commit appears to have broken the ability to specify a comma separated list of events: commit ceb53fbf6dbb1df26d38379a262c6981fe73dd36 Author: Ingo Molnar Date: Wed Apr 27 04:06:33 2011 +0200 perf stat: Fail more clearly when an invalid modifier is specified This patch fixes this while preserving the desired effect: $ perf stat -e instructions:u,instructions:k ls /dev/null /dev/null Performance counter stats for 'ls /dev/null': 365956 instructions:u # 0.00 insns per cycle 731806 instructions:k # 0.00 insns per cycle 0.001108862 seconds time elapsed $ perf stat -e task-clock-msecs true invalid event modifier: '-msecs' Run 'perf list' for a list of valid events and modifiers Signed-off-by: Stephane Eranian Cc: acme@redhat.com Cc: peterz@infradead.org Cc: fweisbec@gmail.com Link: http://lkml.kernel.org/r/20110517133619.GA6999@quad Signed-off-by: Ingo Molnar diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c index ffa493a..41982c3 100644 --- a/tools/perf/util/parse-events.c +++ b/tools/perf/util/parse-events.c @@ -734,6 +734,9 @@ parse_event_modifier(const char **strp, struct perf_event_attr *attr) if (!*str) return 0; + if (*str == ',') + return 0; + if (*str++ != ':') return -1; -- cgit v0.10.2 From 221d1d797202984cb874e3ed9f1388593d34ee22 Mon Sep 17 00:00:00 2001 From: Jeff Layton Date: Tue, 17 May 2011 06:40:30 -0400 Subject: cifs: add fallback in is_path_accessible for old servers The is_path_accessible check uses a QPathInfo call, which isn't supported by ancient win9x era servers. Fall back to an older SMBQueryInfo call if it fails with the magic error codes. Cc: stable@kernel.org Reported-and-Tested-by: Sandro Bonazzola Signed-off-by: Jeff Layton Signed-off-by: Steve French diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index 05f1dcf..277262a 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c @@ -2673,6 +2673,11 @@ is_path_accessible(int xid, struct cifsTconInfo *tcon, 0 /* not legacy */, cifs_sb->local_nls, cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); + + if (rc == -EOPNOTSUPP || rc == -EINVAL) + rc = SMBQueryInformation(xid, tcon, full_path, pfile_info, + cifs_sb->local_nls, cifs_sb->mnt_cifs_flags & + CIFS_MOUNT_MAP_SPECIAL_CHR); kfree(pfile_info); return rc; } -- cgit v0.10.2 From 11e73de7ccc1c9c61c65f914a214cb6467966a51 Mon Sep 17 00:00:00 2001 From: Ian Campbell Date: Mon, 16 May 2011 23:59:48 +0000 Subject: xen: netback: use __CONST_RING_SIZE not __RING_SIZE The later causes warnings with gcc 4.5+. __CONST_RING_SIZE was introduced in 667c78afaec0 to fix this but as netback wasn't upstream at the time it did not benefit, hence: CC drivers/net/xen-netback/netback.o drivers/net/xen-netback/netback.c:110:37: warning: variably modified 'grant_copy_op' at file scope [enabled by default] drivers/net/xen-netback/netback.c:111:30: warning: variably modified 'meta' at file scope [enabled by default] drivers/net/xen-netback/netback.c: In function 'xen_netbk_rx_action': drivers/net/xen-netback/netback.c:584:6: warning: variable 'irq' set but not used [-Wunused-but-set-variable] Thanks to Witold Baryluk for pointing this out. Signed-off-by: Ian Campbell Cc: Witold Baryluk Signed-off-by: David S. Miller diff --git a/drivers/net/xen-netback/common.h b/drivers/net/xen-netback/common.h index 8753e6d..161f207 100644 --- a/drivers/net/xen-netback/common.h +++ b/drivers/net/xen-netback/common.h @@ -106,8 +106,8 @@ struct xenvif { wait_queue_head_t waiting_to_free; }; -#define XEN_NETIF_TX_RING_SIZE __RING_SIZE((struct xen_netif_tx_sring *)0, PAGE_SIZE) -#define XEN_NETIF_RX_RING_SIZE __RING_SIZE((struct xen_netif_rx_sring *)0, PAGE_SIZE) +#define XEN_NETIF_TX_RING_SIZE __CONST_RING_SIZE(xen_netif_tx, PAGE_SIZE) +#define XEN_NETIF_RX_RING_SIZE __CONST_RING_SIZE(xen_netif_rx, PAGE_SIZE) struct xenvif *xenvif_alloc(struct device *parent, domid_t domid, -- cgit v0.10.2 From b9eb8b8752804cecbacdb4d24b52e823cf07f107 Mon Sep 17 00:00:00 2001 From: Anton Blanchard Date: Tue, 17 May 2011 15:38:57 -0400 Subject: net: recvmmsg: Strip MSG_WAITFORONE when calling recvmsg recvmmsg fails on a raw socket with EINVAL. The reason for this is packet_recvmsg checks the incoming flags: err = -EINVAL; if (flags & ~(MSG_PEEK|MSG_DONTWAIT|MSG_TRUNC|MSG_CMSG_COMPAT|MSG_ERRQUEUE)) goto out; This patch strips out MSG_WAITFORONE when calling recvmmsg which fixes the issue. Signed-off-by: Anton Blanchard Cc: stable@kernel.org [2.6.34+] Signed-off-by: David S. Miller diff --git a/net/socket.c b/net/socket.c index 310d16b..65b2310 100644 --- a/net/socket.c +++ b/net/socket.c @@ -2122,14 +2122,16 @@ int __sys_recvmmsg(int fd, struct mmsghdr __user *mmsg, unsigned int vlen, */ if (MSG_CMSG_COMPAT & flags) { err = __sys_recvmsg(sock, (struct msghdr __user *)compat_entry, - &msg_sys, flags, datagrams); + &msg_sys, flags & ~MSG_WAITFORONE, + datagrams); if (err < 0) break; err = __put_user(err, &compat_entry->msg_len); ++compat_entry; } else { err = __sys_recvmsg(sock, (struct msghdr __user *)entry, - &msg_sys, flags, datagrams); + &msg_sys, flags & ~MSG_WAITFORONE, + datagrams); if (err < 0) break; err = put_user(err, &entry->msg_len); -- cgit v0.10.2 From 604ae14ffb6d75d6eef4757859226b758d6bf9e3 Mon Sep 17 00:00:00 2001 From: "Michael S. Tsirkin" Date: Mon, 16 May 2011 10:37:39 +0000 Subject: net: Change netdev_fix_features messages loglevel Cool, how about we make 'Features changed' debug as well? This way userspace can't fill up the log just by tweaking tun features with an ioctl. Signed-off-by: Michael S. Tsirkin Signed-off-by: David S. Miller diff --git a/net/core/dev.c b/net/core/dev.c index 30a4078..acd7423 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -5258,7 +5258,7 @@ void netdev_update_features(struct net_device *dev) if (dev->features == features) return; - netdev_info(dev, "Features changed: 0x%08x -> 0x%08x\n", + netdev_dbg(dev, "Features changed: 0x%08x -> 0x%08x\n", dev->features, features); if (dev->netdev_ops->ndo_set_features) -- cgit v0.10.2 From 2494b030ba9334c7dd7df9b9f7abe4eacc950ec5 Mon Sep 17 00:00:00 2001 From: Fenghua Yu Date: Tue, 17 May 2011 12:33:26 -0700 Subject: x86, cpufeature: Fix cpuid leaf 7 feature detection CPUID leaf 7, subleaf 0 returns the maximum subleaf in EAX, not the number of subleaves. Since so far only subleaf 0 is defined (and only the EBX bitfield) we do not need to qualify the test. Signed-off-by: Fenghua Yu Link: http://lkml.kernel.org/r/1305660806-17519-1-git-send-email-fenghua.yu@intel.com Signed-off-by: H. Peter Anvin Cc: 2.6.36..39 diff --git a/arch/x86/kernel/cpu/common.c b/arch/x86/kernel/cpu/common.c index e2ced00..173f3a3 100644 --- a/arch/x86/kernel/cpu/common.c +++ b/arch/x86/kernel/cpu/common.c @@ -565,8 +565,7 @@ void __cpuinit get_cpu_cap(struct cpuinfo_x86 *c) cpuid_count(0x00000007, 0, &eax, &ebx, &ecx, &edx); - if (eax > 0) - c->x86_capability[9] = ebx; + c->x86_capability[9] = ebx; } /* AMD-defined flags: level 0x80000001 */ -- cgit v0.10.2 From 7cc31a9ae1477abc79d5992b3afe889f25c50c99 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Miros=C5=82aw?= Date: Tue, 17 May 2011 16:50:02 -0400 Subject: net: ethtool: fix IPV6 checksum feature name string MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: MichaÅ‚ MirosÅ‚aw Signed-off-by: David S. Miller diff --git a/net/core/ethtool.c b/net/core/ethtool.c index 74ead9e..f337525 100644 --- a/net/core/ethtool.c +++ b/net/core/ethtool.c @@ -330,7 +330,7 @@ static const char netdev_features_strings[ETHTOOL_DEV_FEATURE_WORDS * 32][ETH_GS /* NETIF_F_IP_CSUM */ "tx-checksum-ipv4", /* NETIF_F_NO_CSUM */ "tx-checksum-unneeded", /* NETIF_F_HW_CSUM */ "tx-checksum-ip-generic", - /* NETIF_F_IPV6_CSUM */ "tx_checksum-ipv6", + /* NETIF_F_IPV6_CSUM */ "tx-checksum-ipv6", /* NETIF_F_HIGHDMA */ "highdma", /* NETIF_F_FRAGLIST */ "tx-scatter-gather-fraglist", /* NETIF_F_HW_VLAN_TX */ "tx-vlan-hw-insert", -- cgit v0.10.2 From 11379b5e33950048ad66825da7f462b0d0da9d73 Mon Sep 17 00:00:00 2001 From: Jeff Layton Date: Tue, 17 May 2011 15:28:21 -0400 Subject: cifs: fix cifsConvertToUCS() for the mapchars case As Metze pointed out, commit 84cdf74e broke mapchars option: Commit "cifs: fix unaligned accesses in cifsConvertToUCS" (84cdf74e8096a10dd6acbb870dd404b92f07a756) does multiple steps in just one commit (moving the function and changing it without testing). put_unaligned_le16(temp, &target[j]); is never called for any codepoint the goes via the 'default' switch statement. As a result we put just zero (or maybe uninitialized) bytes into the target buffer. His proposed patch looks correct, but doesn't apply to the current head of the tree. This patch should also fix it. Cc: # .38.x: 581ade4: cifs: clean up various nits in unicode routines (try #2) Reported-by: Stefan Metzmacher Signed-off-by: Jeff Layton Signed-off-by: Steve French diff --git a/fs/cifs/cifs_unicode.c b/fs/cifs/cifs_unicode.c index 23d43cd..1b2e180 100644 --- a/fs/cifs/cifs_unicode.c +++ b/fs/cifs/cifs_unicode.c @@ -277,6 +277,7 @@ cifsConvertToUCS(__le16 *target, const char *source, int srclen, for (i = 0, j = 0; i < srclen; j++) { src_char = source[i]; + charlen = 1; switch (src_char) { case 0: put_unaligned(0, &target[j]); @@ -316,16 +317,13 @@ cifsConvertToUCS(__le16 *target, const char *source, int srclen, dst_char = cpu_to_le16(0x003f); charlen = 1; } - /* - * character may take more than one byte in the source - * string, but will take exactly two bytes in the - * target string - */ - i += charlen; - continue; } + /* + * character may take more than one byte in the source string, + * but will take exactly two bytes in the target string + */ + i += charlen; put_unaligned(dst_char, &target[j]); - i++; /* move to next char in source string */ } ctoUCS_out: -- cgit v0.10.2 From 3c431936087e93d2219a184a8e19eaa68077e379 Mon Sep 17 00:00:00 2001 From: MyungJoo Ham Date: Fri, 22 Apr 2011 22:00:54 +0200 Subject: PM / Suspend: Do not ignore error codes returned by suspend_enter() The current implementation of suspend-to-RAM returns 0 if there is an error from suspend_enter(), because suspend_devices_and_enter() ignores the return value from suspend_enter(). This patch addresses this issue and properly keep the error return from suspend_enter() and let suspend_devices_and_enter relay the error return. Signed-off-by: MyungJoo Ham Signed-off-by: Kyungmin Park Signed-off-by: Rafael J. Wysocki diff --git a/kernel/power/suspend.c b/kernel/power/suspend.c index 6275970..fa9fabd 100644 --- a/kernel/power/suspend.c +++ b/kernel/power/suspend.c @@ -226,7 +226,7 @@ int suspend_devices_and_enter(suspend_state_t state) if (suspend_test(TEST_DEVICES)) goto Recover_platform; - suspend_enter(state); + error = suspend_enter(state); Resume_devices: suspend_test_start(); -- cgit v0.10.2 From ee940d8dccd899aa1777ea84da3d9cd04b1d2e8e Mon Sep 17 00:00:00 2001 From: Mike Frysinger Date: Mon, 25 Apr 2011 12:33:15 +0200 Subject: Freezer: Use SMP barriers The freezer processes are dealing with multiple threads running simultaneously, and on a UP system, the memory reads/writes do not need barriers to keep things in sync. These are only needed on SMP systems, so use SMP barriers instead. Signed-off-by: Mike Frysinger Acked-by: Pavel Machek Signed-off-by: Rafael J. Wysocki diff --git a/kernel/freezer.c b/kernel/freezer.c index 66ecd2e..7b01de9 100644 --- a/kernel/freezer.c +++ b/kernel/freezer.c @@ -17,7 +17,7 @@ static inline void frozen_process(void) { if (!unlikely(current->flags & PF_NOFREEZE)) { current->flags |= PF_FROZEN; - wmb(); + smp_wmb(); } clear_freeze_flag(current); } @@ -93,7 +93,7 @@ bool freeze_task(struct task_struct *p, bool sig_only) * the task as frozen and next clears its TIF_FREEZE. */ if (!freezing(p)) { - rmb(); + smp_rmb(); if (frozen(p)) return false; -- cgit v0.10.2 From e1866b33b1e89f077b7132daae3dfd9a594e9a1a Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Fri, 29 Apr 2011 00:33:45 +0200 Subject: PM / Runtime: Rework runtime PM handling during driver removal The driver core tries to prevent race conditions between runtime PM and driver removal from happening by incrementing the runtime PM usage counter of the device and executing pm_runtime_barrier() before running the bus notifier and the ->remove() callbacks provided by the device's subsystem or driver. This guarantees that, if a future runtime suspend of the device has been scheduled or a runtime resume or idle request has been queued up right before the driver removal, it will be canceled or waited for to complete and no other asynchronous runtime suspend or idle requests for the device will be put into the PM workqueue until the ->remove() callback returns. However, it doesn't prevent resume requests from being queued up after pm_runtime_barrier() has been called and it doesn't prevent pm_runtime_resume() from executing the device subsystem's runtime resume callback. Morever, it prevents the device's subsystem or driver from putting the device into the suspended state by calling pm_runtime_suspend() from its ->remove() routine. This turns out to be a major inconvenience for some subsystems and drivers that want to leave the devices they handle in the suspended state. To really prevent runtime PM callbacks from racing with the bus notifier callback in __device_release_driver(), which is necessary, because the notifier is used by some subsystems to carry out operations affecting the runtime PM functionality, use pm_runtime_get_sync() instead of the combination of pm_runtime_get_noresume() and pm_runtime_barrier(). This will resume the device if it's in the suspended state and will prevent it from being suspended again until pm_runtime_put_*() is called. To allow subsystems and drivers to put devices into the suspended state by calling pm_runtime_suspend() from their ->remove() routines, execute pm_runtime_put_sync() after running the bus notifier in __device_release_driver(). This will require subsystems and drivers to make their ->remove() callbacks avoid races with runtime PM directly, but it will allow of more flexibility in the handling of devices during the removal of their drivers. Signed-off-by: Rafael J. Wysocki diff --git a/drivers/base/dd.c b/drivers/base/dd.c index da57ee9..29917c7 100644 --- a/drivers/base/dd.c +++ b/drivers/base/dd.c @@ -316,8 +316,7 @@ static void __device_release_driver(struct device *dev) drv = dev->driver; if (drv) { - pm_runtime_get_noresume(dev); - pm_runtime_barrier(dev); + pm_runtime_get_sync(dev); driver_sysfs_remove(dev); @@ -326,6 +325,8 @@ static void __device_release_driver(struct device *dev) BUS_NOTIFY_UNBIND_DRIVER, dev); + pm_runtime_put_sync(dev); + if (dev->bus && dev->bus->remove) dev->bus->remove(dev); else if (drv->remove) @@ -338,7 +339,6 @@ static void __device_release_driver(struct device *dev) BUS_NOTIFY_UNBOUND_DRIVER, dev); - pm_runtime_put_sync(dev); } } -- cgit v0.10.2 From a144c6a6c924aa1da04dd77fb84b89927354fdff Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Fri, 6 May 2011 20:09:42 +0200 Subject: PM: Print a warning if firmware is requested when tasks are frozen Some drivers erroneously use request_firmware() from their ->resume() (or ->thaw(), or ->restore()) callbacks, which is not going to work unless the firmware has been built in. This causes system resume to stall until the firmware-loading timeout expires, which makes users think that the resume has failed and reboot their machines unnecessarily. For this reason, make _request_firmware() print a warning and return immediately with error code if it has been called when tasks are frozen and it's impossible to start any new usermode helpers. Signed-off-by: Rafael J. Wysocki Acked-by: Greg Kroah-Hartman Reviewed-by: Valdis Kletnieks diff --git a/drivers/base/firmware_class.c b/drivers/base/firmware_class.c index 8c798ef..bbb03e6 100644 --- a/drivers/base/firmware_class.c +++ b/drivers/base/firmware_class.c @@ -521,6 +521,11 @@ static int _request_firmware(const struct firmware **firmware_p, if (!firmware_p) return -EINVAL; + if (WARN_ON(usermodehelper_is_disabled())) { + dev_err(device, "firmware: %s will not be loaded\n", name); + return -EBUSY; + } + *firmware_p = firmware = kzalloc(sizeof(*firmware), GFP_KERNEL); if (!firmware) { dev_err(device, "%s: kmalloc(struct firmware) failed\n", diff --git a/include/linux/kmod.h b/include/linux/kmod.h index 6efd7a7..7f3dbcb 100644 --- a/include/linux/kmod.h +++ b/include/linux/kmod.h @@ -111,7 +111,12 @@ call_usermodehelper(char *path, char **argv, char **envp, enum umh_wait wait) extern void usermodehelper_init(void); +#ifdef CONFIG_PM_SLEEP extern int usermodehelper_disable(void); extern void usermodehelper_enable(void); +extern bool usermodehelper_is_disabled(void); +#else +static inline bool usermodehelper_is_disabled(void) { return false; } +#endif #endif /* __LINUX_KMOD_H__ */ diff --git a/kernel/kmod.c b/kernel/kmod.c index 9cd0591..9ab513b 100644 --- a/kernel/kmod.c +++ b/kernel/kmod.c @@ -301,6 +301,15 @@ void usermodehelper_enable(void) usermodehelper_disabled = 0; } +/** + * usermodehelper_is_disabled - check if new helpers are allowed to be started + */ +bool usermodehelper_is_disabled(void) +{ + return usermodehelper_disabled; +} +EXPORT_SYMBOL_GPL(usermodehelper_is_disabled); + static void helper_lock(void) { atomic_inc(&running_helpers); -- cgit v0.10.2 From e762318baae3002944d68220910aef7caffcd065 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Sat, 7 May 2011 18:11:52 +0200 Subject: PM / Wakeup: Fix build warning related to the "wakeup" sysfs file The "wakeup" device sysfs file is only created if CONFIG_PM_SLEEP is set, so put it under CONFIG_PM_SLEEP and make a build warning related to it go away. Signed-off-by: Rafael J. Wysocki Acked-by: Greg Kroah-Hartman diff --git a/drivers/base/power/sysfs.c b/drivers/base/power/sysfs.c index fff49be..a9f5b89 100644 --- a/drivers/base/power/sysfs.c +++ b/drivers/base/power/sysfs.c @@ -212,8 +212,9 @@ static ssize_t autosuspend_delay_ms_store(struct device *dev, static DEVICE_ATTR(autosuspend_delay_ms, 0644, autosuspend_delay_ms_show, autosuspend_delay_ms_store); -#endif +#endif /* CONFIG_PM_RUNTIME */ +#ifdef CONFIG_PM_SLEEP static ssize_t wake_show(struct device * dev, struct device_attribute *attr, char * buf) { @@ -248,7 +249,6 @@ wake_store(struct device * dev, struct device_attribute *attr, static DEVICE_ATTR(wakeup, 0644, wake_show, wake_store); -#ifdef CONFIG_PM_SLEEP static ssize_t wakeup_count_show(struct device *dev, struct device_attribute *attr, char *buf) { -- cgit v0.10.2 From c3b0795c98c08351567464150db66d11e05d7611 Mon Sep 17 00:00:00 2001 From: Amerigo Wang Date: Tue, 10 May 2011 21:09:38 +0200 Subject: PM / ACPI: Remove acpi_sleep=s4_nonvs acpi_sleep=s4_nonvs is superseded by acpi_sleep=nonvs, so remove it. Signed-off-by: WANG Cong Acked-by: Pavel Machek Acked-by: Len Brown Signed-off-by: Rafael J. Wysocki diff --git a/Documentation/feature-removal-schedule.txt b/Documentation/feature-removal-schedule.txt index 492e81d..f6a24e8 100644 --- a/Documentation/feature-removal-schedule.txt +++ b/Documentation/feature-removal-schedule.txt @@ -460,14 +460,6 @@ Who: Thomas Gleixner ---------------------------- -What: The acpi_sleep=s4_nonvs command line option -When: 2.6.37 -Files: arch/x86/kernel/acpi/sleep.c -Why: superseded by acpi_sleep=nonvs -Who: Rafael J. Wysocki - ----------------------------- - What: PCI DMA unmap state API When: August 2012 Why: PCI DMA unmap state API (include/linux/pci-dma.h) was replaced diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt index cc85a92..259037b 100644 --- a/Documentation/kernel-parameters.txt +++ b/Documentation/kernel-parameters.txt @@ -245,7 +245,7 @@ bytes respectively. Such letter suffixes can also be entirely omitted. acpi_sleep= [HW,ACPI] Sleep options Format: { s3_bios, s3_mode, s3_beep, s4_nohwsig, - old_ordering, s4_nonvs, sci_force_enable } + old_ordering, nonvs, sci_force_enable } See Documentation/power/video.txt for information on s3_bios and s3_mode. s3_beep is for debugging; it makes the PC's speaker beep diff --git a/arch/x86/kernel/acpi/sleep.c b/arch/x86/kernel/acpi/sleep.c index ff93bc1..18a857b 100644 --- a/arch/x86/kernel/acpi/sleep.c +++ b/arch/x86/kernel/acpi/sleep.c @@ -112,11 +112,6 @@ static int __init acpi_sleep_setup(char *str) #ifdef CONFIG_HIBERNATION if (strncmp(str, "s4_nohwsig", 10) == 0) acpi_no_s4_hw_signature(); - if (strncmp(str, "s4_nonvs", 8) == 0) { - pr_warning("ACPI: acpi_sleep=s4_nonvs is deprecated, " - "please use acpi_sleep=nonvs instead"); - acpi_nvs_nosave(); - } #endif if (strncmp(str, "nonvs", 5) == 0) acpi_nvs_nosave(); -- cgit v0.10.2 From 13d53f8775c6a00b070a3eef6833795412eb7fcd Mon Sep 17 00:00:00 2001 From: Kay Sievers Date: Tue, 10 May 2011 21:27:34 +0200 Subject: kmod: always provide usermodehelper_disable() We need to prevent kernel-forked processes during system poweroff. Such processes try to access the filesystem whose disks we are trying to shutdown at the same time. This causes delays and exceptions in the storage drivers. A follow-up patch will add these calls and need usermodehelper_disable() also on systems without suspend support. Signed-off-by: Kay Sievers Signed-off-by: Rafael J. Wysocki diff --git a/include/linux/kmod.h b/include/linux/kmod.h index 7f3dbcb..3102318 100644 --- a/include/linux/kmod.h +++ b/include/linux/kmod.h @@ -111,12 +111,8 @@ call_usermodehelper(char *path, char **argv, char **envp, enum umh_wait wait) extern void usermodehelper_init(void); -#ifdef CONFIG_PM_SLEEP extern int usermodehelper_disable(void); extern void usermodehelper_enable(void); extern bool usermodehelper_is_disabled(void); -#else -static inline bool usermodehelper_is_disabled(void) { return false; } -#endif #endif /* __LINUX_KMOD_H__ */ diff --git a/kernel/kmod.c b/kernel/kmod.c index 9ab513b..5ae0ff3 100644 --- a/kernel/kmod.c +++ b/kernel/kmod.c @@ -245,7 +245,6 @@ static void __call_usermodehelper(struct work_struct *work) } } -#ifdef CONFIG_PM_SLEEP /* * If set, call_usermodehelper_exec() will exit immediately returning -EBUSY * (used for preventing user land processes from being created after the user @@ -321,12 +320,6 @@ static void helper_unlock(void) if (atomic_dec_and_test(&running_helpers)) wake_up(&running_helpers_waitq); } -#else /* CONFIG_PM_SLEEP */ -#define usermodehelper_disabled 0 - -static inline void helper_lock(void) {} -static inline void helper_unlock(void) {} -#endif /* CONFIG_PM_SLEEP */ /** * call_usermodehelper_setup - prepare to call a usermode helper -- cgit v0.10.2 From 13e381365614855bf14c8ad68f9b65e3afd3dd2c Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Wed, 11 May 2011 22:40:45 +0200 Subject: PM / Wakeup: Remove useless synchronize_rcu() call wakeup_source_add() adds an item into wakeup_sources list. There is no need to call synchronize_rcu() at this point. Its only needed in wakeup_source_remove() Signed-off-by: Eric Dumazet Signed-off-by: Rafael J. Wysocki diff --git a/drivers/base/power/wakeup.c b/drivers/base/power/wakeup.c index abbbd33..84f7c7d 100644 --- a/drivers/base/power/wakeup.c +++ b/drivers/base/power/wakeup.c @@ -110,7 +110,6 @@ void wakeup_source_add(struct wakeup_source *ws) spin_lock_irq(&events_lock); list_add_rcu(&ws->entry, &wakeup_sources); spin_unlock_irq(&events_lock); - synchronize_rcu(); } EXPORT_SYMBOL_GPL(wakeup_source_add); -- cgit v0.10.2 From ddeb648708108091a641adad0a438ec4fd8bf190 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Sun, 15 May 2011 11:38:48 +0200 Subject: PM / Hibernate: Add sysfs knob to control size of memory for drivers Martin reports that on his system hibernation occasionally fails due to the lack of memory, because the radeon driver apparently allocates too much of it during the device freeze stage. It turns out that the amount of memory allocated by radeon during hibernation (and presumably during system suspend too) depends on the utilization of the GPU (e.g. hibernating while there are two KDE 4 sessions with compositing enabled causes radeon to allocate more memory than for one KDE 4 session). In principle it should be possible to use image_size to make the memory preallocation mechanism free enough memory for the radeon driver, but in practice it is not easy to guess the right value because of the way the preallocation code uses image_size. For this reason, it seems reasonable to allow users to control the amount of memory reserved for driver allocations made after the hibernate preallocation, which currently is constant and amounts to 1 MB. Introduce a new sysfs file, /sys/power/reserved_size, whose value will be used as the amount of memory to reserve for the post-preallocation reservations made by device drivers, in bytes. For backwards compatibility, set its default (and initial) value to the currently used number (1 MB). References: https://bugzilla.kernel.org/show_bug.cgi?id=34102 Reported-and-tested-by: Martin Steigerwald Signed-off-by: Rafael J. Wysocki diff --git a/Documentation/ABI/testing/sysfs-power b/Documentation/ABI/testing/sysfs-power index 194ca44..b464d1276 100644 --- a/Documentation/ABI/testing/sysfs-power +++ b/Documentation/ABI/testing/sysfs-power @@ -158,3 +158,17 @@ Description: successful, will make the kernel abort a subsequent transition to a sleep state if any wakeup events are reported after the write has returned. + +What: /sys/power/reserved_size +Date: May 2011 +Contact: Rafael J. Wysocki +Description: + The /sys/power/reserved_size file allows user space to control + the amount of memory reserved for allocations made by device + drivers during the "device freeze" stage of hibernation. It can + be written a string representing a non-negative integer that + will be used as the amount of memory to reserve for allocations + made by device drivers' "freeze" callbacks, in bytes. + + Reading from this file will display the current value, which is + set to 1 MB by default. diff --git a/kernel/power/hibernate.c b/kernel/power/hibernate.c index 50aae66..4317213 100644 --- a/kernel/power/hibernate.c +++ b/kernel/power/hibernate.c @@ -982,10 +982,33 @@ static ssize_t image_size_store(struct kobject *kobj, struct kobj_attribute *att power_attr(image_size); +static ssize_t reserved_size_show(struct kobject *kobj, + struct kobj_attribute *attr, char *buf) +{ + return sprintf(buf, "%lu\n", reserved_size); +} + +static ssize_t reserved_size_store(struct kobject *kobj, + struct kobj_attribute *attr, + const char *buf, size_t n) +{ + unsigned long size; + + if (sscanf(buf, "%lu", &size) == 1) { + reserved_size = size; + return n; + } + + return -EINVAL; +} + +power_attr(reserved_size); + static struct attribute * g[] = { &disk_attr.attr, &resume_attr.attr, &image_size_attr.attr, + &reserved_size_attr.attr, NULL, }; diff --git a/kernel/power/main.c b/kernel/power/main.c index de9aef8..2981af4 100644 --- a/kernel/power/main.c +++ b/kernel/power/main.c @@ -337,6 +337,7 @@ static int __init pm_init(void) if (error) return error; hibernate_image_size_init(); + hibernate_reserved_size_init(); power_kobj = kobject_create_and_add("power", NULL); if (!power_kobj) return -ENOMEM; diff --git a/kernel/power/power.h b/kernel/power/power.h index 03634be..9a00a0a 100644 --- a/kernel/power/power.h +++ b/kernel/power/power.h @@ -15,6 +15,7 @@ struct swsusp_info { #ifdef CONFIG_HIBERNATION /* kernel/power/snapshot.c */ +extern void __init hibernate_reserved_size_init(void); extern void __init hibernate_image_size_init(void); #ifdef CONFIG_ARCH_HIBERNATION_HEADER @@ -55,6 +56,7 @@ extern int hibernation_platform_enter(void); #else /* !CONFIG_HIBERNATION */ +static inline void hibernate_reserved_size_init(void) {} static inline void hibernate_image_size_init(void) {} #endif /* !CONFIG_HIBERNATION */ @@ -72,6 +74,8 @@ static struct kobj_attribute _name##_attr = { \ /* Preferred image size in bytes (default 500 MB) */ extern unsigned long image_size; +/* Size of memory reserved for drivers (default SPARE_PAGES x PAGE_SIZE) */ +extern unsigned long reserved_size; extern int in_suspend; extern dev_t swsusp_resume_device; extern sector_t swsusp_resume_block; diff --git a/kernel/power/snapshot.c b/kernel/power/snapshot.c index ca0aacc..d69e332 100644 --- a/kernel/power/snapshot.c +++ b/kernel/power/snapshot.c @@ -41,6 +41,18 @@ static void swsusp_set_page_forbidden(struct page *); static void swsusp_unset_page_forbidden(struct page *); /* + * Number of bytes to reserve for memory allocations made by device drivers + * from their ->freeze() and ->freeze_noirq() callbacks so that they don't + * cause image creation to fail (tunable via /sys/power/reserved_size). + */ +unsigned long reserved_size; + +void __init hibernate_reserved_size_init(void) +{ + reserved_size = SPARE_PAGES * PAGE_SIZE; +} + +/* * Preferred image size in bytes (tunable via /sys/power/image_size). * When it is set to N, the image creating code will do its best to * ensure the image size will not exceed N bytes, but if that is @@ -1263,11 +1275,13 @@ static unsigned long minimum_image_size(unsigned long saveable) * frame in use. We also need a number of page frames to be free during * hibernation for allocations made while saving the image and for device * drivers, in case they need to allocate memory from their hibernation - * callbacks (these two numbers are given by PAGES_FOR_IO and SPARE_PAGES, - * respectively, both of which are rough estimates). To make this happen, we - * compute the total number of available page frames and allocate at least + * callbacks (these two numbers are given by PAGES_FOR_IO (which is a rough + * estimate) and reserverd_size divided by PAGE_SIZE (which is tunable through + * /sys/power/reserved_size, respectively). To make this happen, we compute the + * total number of available page frames and allocate at least * - * ([page frames total] + PAGES_FOR_IO + [metadata pages]) / 2 + 2 * SPARE_PAGES + * ([page frames total] + PAGES_FOR_IO + [metadata pages]) / 2 + * + 2 * DIV_ROUND_UP(reserved_size, PAGE_SIZE) * * of them, which corresponds to the maximum size of a hibernation image. * @@ -1322,7 +1336,8 @@ int hibernate_preallocate_memory(void) count -= totalreserve_pages; /* Compute the maximum number of saveable pages to leave in memory. */ - max_size = (count - (size + PAGES_FOR_IO)) / 2 - 2 * SPARE_PAGES; + max_size = (count - (size + PAGES_FOR_IO)) / 2 + - 2 * DIV_ROUND_UP(reserved_size, PAGE_SIZE); /* Compute the desired number of image pages specified by image_size. */ size = DIV_ROUND_UP(image_size, PAGE_SIZE); if (size > max_size) -- cgit v0.10.2 From 1c1be3a949a61427a962771c85a347c822aeb991 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Sun, 15 May 2011 11:39:48 +0200 Subject: Revert "PM / Hibernate: Reduce autotuned default image size" This reverts commit bea3864fb627d110933cfb8babe048b63c4fc76e (PM / Hibernate: Reduce autotuned default image size), because users are now able to resolve the issue this commit was supposed to address in a different way (i.e. by using the new /sys/power/reserved_size interface). Signed-off-by: Rafael J. Wysocki diff --git a/kernel/power/snapshot.c b/kernel/power/snapshot.c index d69e332..ace5588 100644 --- a/kernel/power/snapshot.c +++ b/kernel/power/snapshot.c @@ -54,15 +54,15 @@ void __init hibernate_reserved_size_init(void) /* * Preferred image size in bytes (tunable via /sys/power/image_size). - * When it is set to N, the image creating code will do its best to - * ensure the image size will not exceed N bytes, but if that is - * impossible, it will try to create the smallest image possible. + * When it is set to N, swsusp will do its best to ensure the image + * size will not exceed N bytes, but if that is impossible, it will + * try to create the smallest image possible. */ unsigned long image_size; void __init hibernate_image_size_init(void) { - image_size = (totalram_pages / 3) * PAGE_SIZE; + image_size = ((totalram_pages * 2) / 5) * PAGE_SIZE; } /* List of PBEs needed for restoring the pages that were allocated before -- cgit v0.10.2 From c650da23d59d2c82307380414606774c6d49b8bd Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Tue, 17 May 2011 23:25:10 +0200 Subject: PM: Remove CONFIG_PM_VERBOSE Now that we have CONFIG_DYNAMIC_DEBUG there is no need for yet another flag causing dev_dbg() and pr_debug() statements in the core PM code to produce output. Moreover, CONFIG_PM_VERBOSE causes so much output to be generated that it's not really useful and almost no one sets it. References: https://bugzilla.kernel.org/show_bug.cgi?id=23182 Signed-off-by: Rafael J. Wysocki diff --git a/arch/sh/configs/apsh4ad0a_defconfig b/arch/sh/configs/apsh4ad0a_defconfig index e71a531..77ec0e7 100644 --- a/arch/sh/configs/apsh4ad0a_defconfig +++ b/arch/sh/configs/apsh4ad0a_defconfig @@ -48,7 +48,6 @@ CONFIG_PREEMPT=y CONFIG_BINFMT_MISC=y CONFIG_PM=y CONFIG_PM_DEBUG=y -CONFIG_PM_VERBOSE=y CONFIG_PM_RUNTIME=y CONFIG_CPU_IDLE=y CONFIG_NET=y diff --git a/arch/sh/configs/sdk7786_defconfig b/arch/sh/configs/sdk7786_defconfig index dc4a2eb..c416505 100644 --- a/arch/sh/configs/sdk7786_defconfig +++ b/arch/sh/configs/sdk7786_defconfig @@ -83,7 +83,6 @@ CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS=y CONFIG_BINFMT_MISC=y CONFIG_PM=y CONFIG_PM_DEBUG=y -CONFIG_PM_VERBOSE=y CONFIG_PM_RUNTIME=y CONFIG_CPU_IDLE=y CONFIG_NET=y diff --git a/drivers/base/power/Makefile b/drivers/base/power/Makefile index 06a7073..3647e11 100644 --- a/drivers/base/power/Makefile +++ b/drivers/base/power/Makefile @@ -5,5 +5,4 @@ obj-$(CONFIG_PM_TRACE_RTC) += trace.o obj-$(CONFIG_PM_OPP) += opp.o obj-$(CONFIG_HAVE_CLK) += clock_ops.o -ccflags-$(CONFIG_DEBUG_DRIVER) := -DDEBUG -ccflags-$(CONFIG_PM_VERBOSE) += -DDEBUG +ccflags-$(CONFIG_DEBUG_DRIVER) := -DDEBUG \ No newline at end of file diff --git a/kernel/power/Kconfig b/kernel/power/Kconfig index d74ad4a..87f4d24 100644 --- a/kernel/power/Kconfig +++ b/kernel/power/Kconfig @@ -125,12 +125,6 @@ config PM_DEBUG code. This is helpful when debugging and reporting PM bugs, like suspend support. -config PM_VERBOSE - bool "Verbose Power Management debugging" - depends on PM_DEBUG - ---help--- - This option enables verbose messages from the Power Management code. - config PM_ADVANCED_DEBUG bool "Extra PM attributes in sysfs for low-level debugging/testing" depends on PM_DEBUG -- cgit v0.10.2 From 91e7c75ba93c48a82670d630b9daac92ff70095d Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Tue, 17 May 2011 23:26:00 +0200 Subject: PM: Allow drivers to allocate memory from .prepare() callbacks safely If device drivers allocate substantial amounts of memory (above 1 MB) in their hibernate .freeze() callbacks (or in their legacy suspend callbcks during hibernation), the subsequent creation of hibernate image may fail due to the lack of memory. This is the case, because the drivers' .freeze() callbacks are executed after the hibernate memory preallocation has been carried out and the preallocated amount of memory may be too small to cover the new driver allocations. Unfortunately, the drivers' .prepare() callbacks also are executed after the hibernate memory preallocation has completed, so they are not suitable for allocating additional memory either. Thus the only way a driver can safely allocate memory during hibernation is to use a hibernate/suspend notifier. However, the notifiers are called before the freezing of user space and the drivers wanting to use them for allocating additional memory may not know how much memory needs to be allocated at that point. To let device drivers overcome this difficulty rework the hibernation sequence so that the memory preallocation is carried out after the drivers' .prepare() callbacks have been executed, so that the .prepare() callbacks can be used for allocating additional memory to be used by the drivers' .freeze() callbacks. Update documentation to match the new behavior of the code. Signed-off-by: Rafael J. Wysocki diff --git a/Documentation/power/devices.txt b/Documentation/power/devices.txt index 1971bcf..8888083 100644 --- a/Documentation/power/devices.txt +++ b/Documentation/power/devices.txt @@ -279,11 +279,15 @@ When the system goes into the standby or memory sleep state, the phases are: time.) Unlike the other suspend-related phases, during the prepare phase the device tree is traversed top-down. - The prepare phase uses only a bus callback. After the callback method - returns, no new children may be registered below the device. The method - may also prepare the device or driver in some way for the upcoming - system power transition, but it should not put the device into a - low-power state. + In addition to that, if device drivers need to allocate additional + memory to be able to hadle device suspend correctly, that should be + done in the prepare phase. + + After the prepare callback method returns, no new children may be + registered below the device. The method may also prepare the device or + driver in some way for the upcoming system power transition (for + example, by allocating additional memory required for this purpose), but + it should not put the device into a low-power state. 2. The suspend methods should quiesce the device to stop it from performing I/O. They also may save the device registers and put it into the diff --git a/Documentation/power/notifiers.txt b/Documentation/power/notifiers.txt index cf98070..c2a4a34 100644 --- a/Documentation/power/notifiers.txt +++ b/Documentation/power/notifiers.txt @@ -1,46 +1,41 @@ Suspend notifiers - (C) 2007 Rafael J. Wysocki , GPL - -There are some operations that device drivers may want to carry out in their -.suspend() routines, but shouldn't, because they can cause the hibernation or -suspend to fail. For example, a driver may want to allocate a substantial amount -of memory (like 50 MB) in .suspend(), but that shouldn't be done after the -swsusp's memory shrinker has run. - -Also, there may be some operations, that subsystems want to carry out before a -hibernation/suspend or after a restore/resume, requiring the system to be fully -functional, so the drivers' .suspend() and .resume() routines are not suitable -for this purpose. For example, device drivers may want to upload firmware to -their devices after a restore from a hibernation image, but they cannot do it by -calling request_firmware() from their .resume() routines (user land processes -are frozen at this point). The solution may be to load the firmware into -memory before processes are frozen and upload it from there in the .resume() -routine. Of course, a hibernation notifier may be used for this purpose. - -The subsystems that have such needs can register suspend notifiers that will be -called upon the following events by the suspend core: + (C) 2007-2011 Rafael J. Wysocki , GPL + +There are some operations that subsystems or drivers may want to carry out +before hibernation/suspend or after restore/resume, but they require the system +to be fully functional, so the drivers' and subsystems' .suspend() and .resume() +or even .prepare() and .complete() callbacks are not suitable for this purpose. +For example, device drivers may want to upload firmware to their devices after +resume/restore, but they cannot do it by calling request_firmware() from their +.resume() or .complete() routines (user land processes are frozen at these +points). The solution may be to load the firmware into memory before processes +are frozen and upload it from there in the .resume() routine. +A suspend/hibernation notifier may be used for this purpose. + +The subsystems or drivers having such needs can register suspend notifiers that +will be called upon the following events by the PM core: PM_HIBERNATION_PREPARE The system is going to hibernate or suspend, tasks will be frozen immediately. PM_POST_HIBERNATION The system memory state has been restored from a - hibernation image or an error occurred during the - hibernation. Device drivers' .resume() callbacks have + hibernation image or an error occurred during + hibernation. Device drivers' restore callbacks have been executed and tasks have been thawed. PM_RESTORE_PREPARE The system is going to restore a hibernation image. - If all goes well the restored kernel will issue a + If all goes well, the restored kernel will issue a PM_POST_HIBERNATION notification. -PM_POST_RESTORE An error occurred during the hibernation restore. - Device drivers' .resume() callbacks have been executed +PM_POST_RESTORE An error occurred during restore from hibernation. + Device drivers' restore callbacks have been executed and tasks have been thawed. -PM_SUSPEND_PREPARE The system is preparing for a suspend. +PM_SUSPEND_PREPARE The system is preparing for suspend. PM_POST_SUSPEND The system has just resumed or an error occurred during - the suspend. Device drivers' .resume() callbacks have - been executed and tasks have been thawed. + suspend. Device drivers' resume callbacks have been + executed and tasks have been thawed. It is generally assumed that whatever the notifiers do for PM_HIBERNATION_PREPARE, should be undone for PM_POST_HIBERNATION. Analogously, diff --git a/drivers/base/power/main.c b/drivers/base/power/main.c index 3b35456..aa632020 100644 --- a/drivers/base/power/main.c +++ b/drivers/base/power/main.c @@ -579,11 +579,13 @@ static bool is_async(struct device *dev) * Execute the appropriate "resume" callback for all devices whose status * indicates that they are suspended. */ -static void dpm_resume(pm_message_t state) +void dpm_resume(pm_message_t state) { struct device *dev; ktime_t starttime = ktime_get(); + might_sleep(); + mutex_lock(&dpm_list_mtx); pm_transition = state; async_error = 0; @@ -656,10 +658,12 @@ static void device_complete(struct device *dev, pm_message_t state) * Execute the ->complete() callbacks for all devices whose PM status is not * DPM_ON (this allows new devices to be registered). */ -static void dpm_complete(pm_message_t state) +void dpm_complete(pm_message_t state) { struct list_head list; + might_sleep(); + INIT_LIST_HEAD(&list); mutex_lock(&dpm_list_mtx); while (!list_empty(&dpm_prepared_list)) { @@ -688,7 +692,6 @@ static void dpm_complete(pm_message_t state) */ void dpm_resume_end(pm_message_t state) { - might_sleep(); dpm_resume(state); dpm_complete(state); } @@ -912,11 +915,13 @@ static int device_suspend(struct device *dev) * dpm_suspend - Execute "suspend" callbacks for all non-sysdev devices. * @state: PM transition of the system being carried out. */ -static int dpm_suspend(pm_message_t state) +int dpm_suspend(pm_message_t state) { ktime_t starttime = ktime_get(); int error = 0; + might_sleep(); + mutex_lock(&dpm_list_mtx); pm_transition = state; async_error = 0; @@ -1003,10 +1008,12 @@ static int device_prepare(struct device *dev, pm_message_t state) * * Execute the ->prepare() callback(s) for all devices. */ -static int dpm_prepare(pm_message_t state) +int dpm_prepare(pm_message_t state) { int error = 0; + might_sleep(); + mutex_lock(&dpm_list_mtx); while (!list_empty(&dpm_list)) { struct device *dev = to_device(dpm_list.next); @@ -1055,7 +1062,6 @@ int dpm_suspend_start(pm_message_t state) { int error; - might_sleep(); error = dpm_prepare(state); if (!error) error = dpm_suspend(state); diff --git a/include/linux/pm.h b/include/linux/pm.h index 3cc3e7e..dce7c71 100644 --- a/include/linux/pm.h +++ b/include/linux/pm.h @@ -533,10 +533,14 @@ struct dev_power_domain { extern void device_pm_lock(void); extern void dpm_resume_noirq(pm_message_t state); extern void dpm_resume_end(pm_message_t state); +extern void dpm_resume(pm_message_t state); +extern void dpm_complete(pm_message_t state); extern void device_pm_unlock(void); extern int dpm_suspend_noirq(pm_message_t state); extern int dpm_suspend_start(pm_message_t state); +extern int dpm_suspend(pm_message_t state); +extern int dpm_prepare(pm_message_t state); extern void __suspend_report_result(const char *function, void *fn, int ret); diff --git a/kernel/power/hibernate.c b/kernel/power/hibernate.c index 95a2ac4..f9bec56 100644 --- a/kernel/power/hibernate.c +++ b/kernel/power/hibernate.c @@ -327,20 +327,25 @@ static int create_image(int platform_mode) int hibernation_snapshot(int platform_mode) { + pm_message_t msg = PMSG_RECOVER; int error; error = platform_begin(platform_mode); if (error) goto Close; + error = dpm_prepare(PMSG_FREEZE); + if (error) + goto Complete_devices; + /* Preallocate image memory before shutting down devices. */ error = hibernate_preallocate_memory(); if (error) - goto Close; + goto Complete_devices; suspend_console(); pm_restrict_gfp_mask(); - error = dpm_suspend_start(PMSG_FREEZE); + error = dpm_suspend(PMSG_FREEZE); if (error) goto Recover_platform; @@ -358,13 +363,17 @@ int hibernation_snapshot(int platform_mode) if (error || !in_suspend) swsusp_free(); - dpm_resume_end(in_suspend ? - (error ? PMSG_RECOVER : PMSG_THAW) : PMSG_RESTORE); + msg = in_suspend ? (error ? PMSG_RECOVER : PMSG_THAW) : PMSG_RESTORE; + dpm_resume(msg); if (error || !in_suspend) pm_restore_gfp_mask(); resume_console(); + + Complete_devices: + dpm_complete(msg); + Close: platform_end(platform_mode); return error; -- cgit v0.10.2 From 6538df80194e305f1b78cafb556f4bb442f808b3 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Tue, 17 May 2011 23:26:21 +0200 Subject: PM: Introduce generic prepare and complete callbacks for subsystems Introduce generic .prepare() and .complete() power management callbacks, currently missing, that can be used by subsystems and power domains and export them. Provide NULL definitions of all the generic system sleep callbacks for CONFIG_PM_SLEEP unset. Signed-off-by: Rafael J. Wysocki diff --git a/drivers/base/power/generic_ops.c b/drivers/base/power/generic_ops.c index 42f97f9..cb3bb36 100644 --- a/drivers/base/power/generic_ops.c +++ b/drivers/base/power/generic_ops.c @@ -74,6 +74,23 @@ EXPORT_SYMBOL_GPL(pm_generic_runtime_resume); #ifdef CONFIG_PM_SLEEP /** + * pm_generic_prepare - Generic routine preparing a device for power transition. + * @dev: Device to prepare. + * + * Prepare a device for a system-wide power transition. + */ +int pm_generic_prepare(struct device *dev) +{ + struct device_driver *drv = dev->driver; + int ret = 0; + + if (drv && drv->pm && drv->pm->prepare) + ret = drv->pm->prepare(dev); + + return ret; +} + +/** * __pm_generic_call - Generic suspend/freeze/poweroff/thaw subsystem callback. * @dev: Device to handle. * @event: PM transition of the system under way. @@ -213,16 +230,38 @@ int pm_generic_restore(struct device *dev) return __pm_generic_resume(dev, PM_EVENT_RESTORE); } EXPORT_SYMBOL_GPL(pm_generic_restore); + +/** + * pm_generic_complete - Generic routine competing a device power transition. + * @dev: Device to handle. + * + * Complete a device power transition during a system-wide power transition. + */ +void pm_generic_complete(struct device *dev) +{ + struct device_driver *drv = dev->driver; + + if (drv && drv->pm && drv->pm->complete) + drv->pm->complete(dev); + + /* + * Let runtime PM try to suspend devices that haven't been in use before + * going into the system-wide sleep state we're resuming from. + */ + pm_runtime_idle(dev); +} #endif /* CONFIG_PM_SLEEP */ struct dev_pm_ops generic_subsys_pm_ops = { #ifdef CONFIG_PM_SLEEP + .prepare = pm_generic_prepare, .suspend = pm_generic_suspend, .resume = pm_generic_resume, .freeze = pm_generic_freeze, .thaw = pm_generic_thaw, .poweroff = pm_generic_poweroff, .restore = pm_generic_restore, + .complete = pm_generic_complete, #endif #ifdef CONFIG_PM_RUNTIME .runtime_suspend = pm_generic_runtime_suspend, diff --git a/include/linux/pm.h b/include/linux/pm.h index dce7c71..3160648 100644 --- a/include/linux/pm.h +++ b/include/linux/pm.h @@ -550,6 +550,16 @@ extern void __suspend_report_result(const char *function, void *fn, int ret); } while (0) extern int device_pm_wait_for_dev(struct device *sub, struct device *dev); + +extern int pm_generic_prepare(struct device *dev); +extern int pm_generic_suspend(struct device *dev); +extern int pm_generic_resume(struct device *dev); +extern int pm_generic_freeze(struct device *dev); +extern int pm_generic_thaw(struct device *dev); +extern int pm_generic_restore(struct device *dev); +extern int pm_generic_poweroff(struct device *dev); +extern void pm_generic_complete(struct device *dev); + #else /* !CONFIG_PM_SLEEP */ #define device_pm_lock() do {} while (0) @@ -566,6 +576,15 @@ static inline int device_pm_wait_for_dev(struct device *a, struct device *b) { return 0; } + +#define pm_generic_prepare NULL +#define pm_generic_suspend NULL +#define pm_generic_resume NULL +#define pm_generic_freeze NULL +#define pm_generic_thaw NULL +#define pm_generic_restore NULL +#define pm_generic_poweroff NULL +#define pm_generic_complete NULL #endif /* !CONFIG_PM_SLEEP */ /* How to reorder dpm_list after device_move() */ @@ -576,11 +595,4 @@ enum dpm_order { DPM_ORDER_DEV_LAST, }; -extern int pm_generic_suspend(struct device *dev); -extern int pm_generic_resume(struct device *dev); -extern int pm_generic_freeze(struct device *dev); -extern int pm_generic_thaw(struct device *dev); -extern int pm_generic_restore(struct device *dev); -extern int pm_generic_poweroff(struct device *dev); - #endif /* _LINUX_PM_H */ -- cgit v0.10.2 From 1d1652cbdb9885e4d73972263e4cdbe1b0beebfe Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Tue, 17 May 2011 17:28:02 -0400 Subject: ipv4: Don't use enums as bitmasks in ip_fragment.c Noticed by Joe Perches. Signed-off-by: David S. Miller diff --git a/net/ipv4/ip_fragment.c b/net/ipv4/ip_fragment.c index 9e1458d..0ad6035 100644 --- a/net/ipv4/ip_fragment.c +++ b/net/ipv4/ip_fragment.c @@ -81,12 +81,10 @@ struct ipq { * We want to check ECN values of all fragments, do detect invalid combinations. * In ipq->ecn, we store the OR value of each ip4_frag_ecn() fragment value. */ -enum { - IPFRAG_ECN_NOT_ECT = 0x01, /* one frag had ECN_NOT_ECT */ - IPFRAG_ECN_ECT_1 = 0x02, /* one frag had ECN_ECT_1 */ - IPFRAG_ECN_ECT_0 = 0x04, /* one frag had ECN_ECT_0 */ - IPFRAG_ECN_CE = 0x08, /* one frag had ECN_CE */ -}; +#define IPFRAG_ECN_NOT_ECT 0x01 /* one frag had ECN_NOT_ECT */ +#define IPFRAG_ECN_ECT_1 0x02 /* one frag had ECN_ECT_1 */ +#define IPFRAG_ECN_ECT_0 0x04 /* one frag had ECN_ECT_0 */ +#define IPFRAG_ECN_CE 0x08 /* one frag had ECN_CE */ static inline u8 ip4_frag_ecn(u8 tos) { -- cgit v0.10.2 From b56269468483a0255a27126ebc2ae7e321638d7b Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Tue, 17 May 2011 17:53:22 -0400 Subject: sfc: Don't use enums as a bitmask. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This fixes: drivers/net/sfc/mcdi_mac.c: In function ‘efx_mcdi_set_mac’: drivers/net/sfc/mcdi_mac.c:36:2: warning: case value ‘3’ not in enumerated type ‘enum efx_fc_type’ Signed-off-by: David S. Miller diff --git a/drivers/net/sfc/efx.c b/drivers/net/sfc/efx.c index 05502b3..c914729 100644 --- a/drivers/net/sfc/efx.c +++ b/drivers/net/sfc/efx.c @@ -833,7 +833,7 @@ void efx_link_set_advertising(struct efx_nic *efx, u32 advertising) } } -void efx_link_set_wanted_fc(struct efx_nic *efx, enum efx_fc_type wanted_fc) +void efx_link_set_wanted_fc(struct efx_nic *efx, u8 wanted_fc) { efx->wanted_fc = wanted_fc; if (efx->link_advertising) { diff --git a/drivers/net/sfc/efx.h b/drivers/net/sfc/efx.h index 3d83a1f..b0d1209 100644 --- a/drivers/net/sfc/efx.h +++ b/drivers/net/sfc/efx.h @@ -142,6 +142,6 @@ static inline void efx_schedule_channel(struct efx_channel *channel) extern void efx_link_status_changed(struct efx_nic *efx); extern void efx_link_set_advertising(struct efx_nic *efx, u32); -extern void efx_link_set_wanted_fc(struct efx_nic *efx, enum efx_fc_type); +extern void efx_link_set_wanted_fc(struct efx_nic *efx, u8); #endif /* EFX_EFX_H */ diff --git a/drivers/net/sfc/ethtool.c b/drivers/net/sfc/ethtool.c index 348437a..d229027 100644 --- a/drivers/net/sfc/ethtool.c +++ b/drivers/net/sfc/ethtool.c @@ -698,7 +698,7 @@ static int efx_ethtool_set_pauseparam(struct net_device *net_dev, struct ethtool_pauseparam *pause) { struct efx_nic *efx = netdev_priv(net_dev); - enum efx_fc_type wanted_fc, old_fc; + u8 wanted_fc, old_fc; u32 old_adv; bool reset; int rc = 0; diff --git a/drivers/net/sfc/mdio_10g.c b/drivers/net/sfc/mdio_10g.c index 7115914..7ab385c 100644 --- a/drivers/net/sfc/mdio_10g.c +++ b/drivers/net/sfc/mdio_10g.c @@ -284,7 +284,7 @@ void efx_mdio_an_reconfigure(struct efx_nic *efx) efx_mdio_write(efx, MDIO_MMD_AN, MDIO_CTRL1, reg); } -enum efx_fc_type efx_mdio_get_pause(struct efx_nic *efx) +u8 efx_mdio_get_pause(struct efx_nic *efx) { BUILD_BUG_ON(EFX_FC_AUTO & (EFX_FC_RX | EFX_FC_TX)); diff --git a/drivers/net/sfc/mdio_10g.h b/drivers/net/sfc/mdio_10g.h index df07039..a97dbbd 100644 --- a/drivers/net/sfc/mdio_10g.h +++ b/drivers/net/sfc/mdio_10g.h @@ -92,7 +92,7 @@ extern void efx_mdio_an_reconfigure(struct efx_nic *efx); /* Get pause parameters from AN if available (otherwise return * requested pause parameters) */ -enum efx_fc_type efx_mdio_get_pause(struct efx_nic *efx); +u8 efx_mdio_get_pause(struct efx_nic *efx); /* Wait for specified MMDs to exit reset within a timeout */ extern int efx_mdio_wait_reset_mmds(struct efx_nic *efx, diff --git a/drivers/net/sfc/net_driver.h b/drivers/net/sfc/net_driver.h index ce9697b..e8d5f03 100644 --- a/drivers/net/sfc/net_driver.h +++ b/drivers/net/sfc/net_driver.h @@ -449,11 +449,9 @@ enum nic_state { struct efx_nic; /* Pseudo bit-mask flow control field */ -enum efx_fc_type { - EFX_FC_RX = FLOW_CTRL_RX, - EFX_FC_TX = FLOW_CTRL_TX, - EFX_FC_AUTO = 4, -}; +#define EFX_FC_RX FLOW_CTRL_RX +#define EFX_FC_TX FLOW_CTRL_TX +#define EFX_FC_AUTO 4 /** * struct efx_link_state - Current state of the link @@ -465,7 +463,7 @@ enum efx_fc_type { struct efx_link_state { bool up; bool fd; - enum efx_fc_type fc; + u8 fc; unsigned int speed; }; @@ -784,7 +782,7 @@ struct efx_nic { bool promiscuous; union efx_multicast_hash multicast_hash; - enum efx_fc_type wanted_fc; + u8 wanted_fc; atomic_t rx_reset; enum efx_loopback_mode loopback_mode; -- cgit v0.10.2 From 724a92ee45c04cb9d82884a856b03b1e594d9de1 Mon Sep 17 00:00:00 2001 From: Fenghua Yu Date: Tue, 17 May 2011 15:29:10 -0700 Subject: x86, cpufeature: Add CPU feature bit for enhanced REP MOVSB/STOSB Intel processors are adding enhancements to REP MOVSB/STOSB and the use of REP MOVSB/STOSB for optimal memcpy/memset or similar functions is recommended. Enhancement availability is indicated by CPUID.7.0.EBX[9] (Enhanced REP MOVSB/ STOSB). Signed-off-by: Fenghua Yu Link: http://lkml.kernel.org/r/1305671358-14478-2-git-send-email-fenghua.yu@intel.com Signed-off-by: H. Peter Anvin diff --git a/arch/x86/include/asm/cpufeature.h b/arch/x86/include/asm/cpufeature.h index 91f3e087..7f2f7b1 100644 --- a/arch/x86/include/asm/cpufeature.h +++ b/arch/x86/include/asm/cpufeature.h @@ -195,6 +195,7 @@ /* Intel-defined CPU features, CPUID level 0x00000007:0 (ebx), word 9 */ #define X86_FEATURE_FSGSBASE (9*32+ 0) /* {RD/WR}{FS/GS}BASE instructions*/ +#define X86_FEATURE_ERMS (9*32+ 9) /* Enhanced REP MOVSB/STOSB */ #if defined(__KERNEL__) && !defined(__ASSEMBLY__) -- cgit v0.10.2 From 161ec53c702ce9df2f439804dfb9331807066daa Mon Sep 17 00:00:00 2001 From: Fenghua Yu Date: Tue, 17 May 2011 15:29:11 -0700 Subject: x86, mem, intel: Initialize Enhanced REP MOVSB/STOSB If kernel intends to use enhanced REP MOVSB/STOSB, it must ensure IA32_MISC_ENABLE.Fast_String_Enable (bit 0) is set and CPUID.(EAX=07H, ECX=0H): EBX[bit 9] also reports 1. Signed-off-by: Fenghua Yu Link: http://lkml.kernel.org/r/1305671358-14478-3-git-send-email-fenghua.yu@intel.com Signed-off-by: H. Peter Anvin diff --git a/arch/x86/kernel/cpu/intel.c b/arch/x86/kernel/cpu/intel.c index df86bc8..fc73a34 100644 --- a/arch/x86/kernel/cpu/intel.c +++ b/arch/x86/kernel/cpu/intel.c @@ -29,10 +29,10 @@ static void __cpuinit early_init_intel(struct cpuinfo_x86 *c) { + u64 misc_enable; + /* Unmask CPUID levels if masked: */ if (c->x86 > 6 || (c->x86 == 6 && c->x86_model >= 0xd)) { - u64 misc_enable; - rdmsrl(MSR_IA32_MISC_ENABLE, misc_enable); if (misc_enable & MSR_IA32_MISC_ENABLE_LIMIT_CPUID) { @@ -118,8 +118,6 @@ static void __cpuinit early_init_intel(struct cpuinfo_x86 *c) * (model 2) with the same problem. */ if (c->x86 == 15) { - u64 misc_enable; - rdmsrl(MSR_IA32_MISC_ENABLE, misc_enable); if (misc_enable & MSR_IA32_MISC_ENABLE_FAST_STRING) { @@ -130,6 +128,19 @@ static void __cpuinit early_init_intel(struct cpuinfo_x86 *c) } } #endif + + /* + * If fast string is not enabled in IA32_MISC_ENABLE for any reason, + * clear the fast string and enhanced fast string CPU capabilities. + */ + if (c->x86 > 6 || (c->x86 == 6 && c->x86_model >= 0xd)) { + rdmsrl(MSR_IA32_MISC_ENABLE, misc_enable); + if (!(misc_enable & MSR_IA32_MISC_ENABLE_FAST_STRING)) { + printk(KERN_INFO "Disabled fast string operations\n"); + setup_clear_cpu_cap(X86_FEATURE_REP_GOOD); + setup_clear_cpu_cap(X86_FEATURE_ERMS); + } + } } #ifdef CONFIG_X86_32 -- cgit v0.10.2 From 509731336313b3799cf03071d72c64fa6383895e Mon Sep 17 00:00:00 2001 From: Fenghua Yu Date: Tue, 17 May 2011 15:29:12 -0700 Subject: x86, alternative, doc: Add comment for applying alternatives order Some string operation functions may be patched twice, e.g. on enhanced REP MOVSB /STOSB processors, memcpy is patched first by fast string alternative function, then it is patched by enhanced REP MOVSB/STOSB alternative function. Add comment for applying alternatives order to warn people who may change the applying alternatives order for any reason. [ Documentation-only patch ] Signed-off-by: Fenghua Yu Link: http://lkml.kernel.org/r/1305671358-14478-4-git-send-email-fenghua.yu@intel.com Signed-off-by: H. Peter Anvin diff --git a/arch/x86/kernel/alternative.c b/arch/x86/kernel/alternative.c index 4a23467..f4fe15d 100644 --- a/arch/x86/kernel/alternative.c +++ b/arch/x86/kernel/alternative.c @@ -210,6 +210,15 @@ void __init_or_module apply_alternatives(struct alt_instr *start, u8 insnbuf[MAX_PATCH_LEN]; DPRINTK("%s: alt table %p -> %p\n", __func__, start, end); + /* + * The scan order should be from start to end. A later scanned + * alternative code can overwrite a previous scanned alternative code. + * Some kernel functions (e.g. memcpy, memset, etc) use this order to + * patch code. + * + * So be careful if you want to change the scan order to any other + * order. + */ for (a = start; a < end; a++) { u8 *instr = a->instr; BUG_ON(a->replacementlen > a->instrlen); -- cgit v0.10.2 From 9072d11da15a71e086eab3b5085184f2c1d06913 Mon Sep 17 00:00:00 2001 From: Fenghua Yu Date: Tue, 17 May 2011 15:29:13 -0700 Subject: x86, alternative: Add altinstruction_entry macro Add altinstruction_entry macro to generate .altinstructions section entries from assembly code. This should be less failure-prone than open-coding. Signed-off-by: Fenghua Yu Link: http://lkml.kernel.org/r/1305671358-14478-5-git-send-email-fenghua.yu@intel.com Signed-off-by: H. Peter Anvin diff --git a/arch/x86/include/asm/alternative-asm.h b/arch/x86/include/asm/alternative-asm.h index a63a68b..94d420b 100644 --- a/arch/x86/include/asm/alternative-asm.h +++ b/arch/x86/include/asm/alternative-asm.h @@ -15,4 +15,13 @@ .endm #endif +.macro altinstruction_entry orig alt feature orig_len alt_len + .align 8 + .quad \orig + .quad \alt + .word \feature + .byte \orig_len + .byte \alt_len +.endm + #endif /* __ASSEMBLY__ */ -- cgit v0.10.2 From e365c9df2f2f001450decf9512412d2d5bd1cdef Mon Sep 17 00:00:00 2001 From: Fenghua Yu Date: Tue, 17 May 2011 15:29:14 -0700 Subject: x86, mem: clear_page_64.S: Support clear_page() with enhanced REP MOVSB/STOSB Intel processors are adding enhancements to REP MOVSB/STOSB and the use of REP MOVSB/STOSB for optimal memcpy/memset or similar functions is recommended. Enhancement availability is indicated by CPUID.7.0.EBX[9] (Enhanced REP MOVSB/ STOSB). Support clear_page() with rep stosb for processor supporting enhanced REP MOVSB /STOSB. On processors supporting enhanced REP MOVSB/STOSB, the alternative clear_page_c_e function using enhanced REP STOSB overrides the original function and the fast string function. Signed-off-by: Fenghua Yu Link: http://lkml.kernel.org/r/1305671358-14478-6-git-send-email-fenghua.yu@intel.com Signed-off-by: H. Peter Anvin diff --git a/arch/x86/lib/clear_page_64.S b/arch/x86/lib/clear_page_64.S index aa4326b..f2145cf 100644 --- a/arch/x86/lib/clear_page_64.S +++ b/arch/x86/lib/clear_page_64.S @@ -1,5 +1,6 @@ #include #include +#include /* * Zero a page. @@ -14,6 +15,15 @@ ENTRY(clear_page_c) CFI_ENDPROC ENDPROC(clear_page_c) +ENTRY(clear_page_c_e) + CFI_STARTPROC + movl $4096,%ecx + xorl %eax,%eax + rep stosb + ret + CFI_ENDPROC +ENDPROC(clear_page_c_e) + ENTRY(clear_page) CFI_STARTPROC xorl %eax,%eax @@ -38,21 +48,26 @@ ENTRY(clear_page) .Lclear_page_end: ENDPROC(clear_page) - /* Some CPUs run faster using the string instructions. - It is also a lot simpler. Use this when possible */ + /* + * Some CPUs support enhanced REP MOVSB/STOSB instructions. + * It is recommended to use this when possible. + * If enhanced REP MOVSB/STOSB is not available, try to use fast string. + * Otherwise, use original function. + * + */ #include .section .altinstr_replacement,"ax" 1: .byte 0xeb /* jmp */ .byte (clear_page_c - clear_page) - (2f - 1b) /* offset */ -2: +2: .byte 0xeb /* jmp */ + .byte (clear_page_c_e - clear_page) - (3f - 2b) /* offset */ +3: .previous .section .altinstructions,"a" - .align 8 - .quad clear_page - .quad 1b - .word X86_FEATURE_REP_GOOD - .byte .Lclear_page_end - clear_page - .byte 2b - 1b + altinstruction_entry clear_page,1b,X86_FEATURE_REP_GOOD,\ + .Lclear_page_end-clear_page, 2b-1b + altinstruction_entry clear_page,2b,X86_FEATURE_ERMS, \ + .Lclear_page_end-clear_page,3b-2b .previous -- cgit v0.10.2 From 4307bec9344aed83f8107c3eb4285bd9d218fc10 Mon Sep 17 00:00:00 2001 From: Fenghua Yu Date: Tue, 17 May 2011 15:29:15 -0700 Subject: x86, mem: copy_user_64.S: Support copy_to/from_user by enhanced REP MOVSB/STOSB Support copy_to_user/copy_from_user() by enhanced REP MOVSB/STOSB. On processors supporting enhanced REP MOVSB/STOSB, the alternative copy_user_enhanced_fast_string function using enhanced rep movsb overrides the original function and the fast string function. Signed-off-by: Fenghua Yu Link: http://lkml.kernel.org/r/1305671358-14478-7-git-send-email-fenghua.yu@intel.com Signed-off-by: H. Peter Anvin diff --git a/arch/x86/lib/copy_user_64.S b/arch/x86/lib/copy_user_64.S index 99e4826..d17a117 100644 --- a/arch/x86/lib/copy_user_64.S +++ b/arch/x86/lib/copy_user_64.S @@ -15,23 +15,30 @@ #include #include #include +#include - .macro ALTERNATIVE_JUMP feature,orig,alt +/* + * By placing feature2 after feature1 in altinstructions section, we logically + * implement: + * If CPU has feature2, jmp to alt2 is used + * else if CPU has feature1, jmp to alt1 is used + * else jmp to orig is used. + */ + .macro ALTERNATIVE_JUMP feature1,feature2,orig,alt1,alt2 0: .byte 0xe9 /* 32bit jump */ .long \orig-1f /* by default jump to orig */ 1: .section .altinstr_replacement,"ax" 2: .byte 0xe9 /* near jump with 32bit immediate */ - .long \alt-1b /* offset */ /* or alternatively to alt */ + .long \alt1-1b /* offset */ /* or alternatively to alt1 */ +3: .byte 0xe9 /* near jump with 32bit immediate */ + .long \alt2-1b /* offset */ /* or alternatively to alt2 */ .previous + .section .altinstructions,"a" - .align 8 - .quad 0b - .quad 2b - .word \feature /* when feature is set */ - .byte 5 - .byte 5 + altinstruction_entry 0b,2b,\feature1,5,5 + altinstruction_entry 0b,3b,\feature2,5,5 .previous .endm @@ -73,7 +80,9 @@ ENTRY(_copy_to_user) jc bad_to_user cmpq TI_addr_limit(%rax),%rcx jae bad_to_user - ALTERNATIVE_JUMP X86_FEATURE_REP_GOOD,copy_user_generic_unrolled,copy_user_generic_string + ALTERNATIVE_JUMP X86_FEATURE_REP_GOOD,X86_FEATURE_ERMS, \ + copy_user_generic_unrolled,copy_user_generic_string, \ + copy_user_enhanced_fast_string CFI_ENDPROC ENDPROC(_copy_to_user) @@ -86,7 +95,9 @@ ENTRY(_copy_from_user) jc bad_from_user cmpq TI_addr_limit(%rax),%rcx jae bad_from_user - ALTERNATIVE_JUMP X86_FEATURE_REP_GOOD,copy_user_generic_unrolled,copy_user_generic_string + ALTERNATIVE_JUMP X86_FEATURE_REP_GOOD,X86_FEATURE_ERMS, \ + copy_user_generic_unrolled,copy_user_generic_string, \ + copy_user_enhanced_fast_string CFI_ENDPROC ENDPROC(_copy_from_user) @@ -255,3 +266,37 @@ ENTRY(copy_user_generic_string) .previous CFI_ENDPROC ENDPROC(copy_user_generic_string) + +/* + * Some CPUs are adding enhanced REP MOVSB/STOSB instructions. + * It's recommended to use enhanced REP MOVSB/STOSB if it's enabled. + * + * Input: + * rdi destination + * rsi source + * rdx count + * + * Output: + * eax uncopied bytes or 0 if successful. + */ +ENTRY(copy_user_enhanced_fast_string) + CFI_STARTPROC + andl %edx,%edx + jz 2f + movl %edx,%ecx +1: rep + movsb +2: xorl %eax,%eax + ret + + .section .fixup,"ax" +12: movl %ecx,%edx /* ecx is zerorest also */ + jmp copy_user_handle_tail + .previous + + .section __ex_table,"a" + .align 8 + .quad 1b,12b + .previous + CFI_ENDPROC +ENDPROC(copy_user_enhanced_fast_string) -- cgit v0.10.2 From 101068c1f4a947ffa08f2782c78e40097300754d Mon Sep 17 00:00:00 2001 From: Fenghua Yu Date: Tue, 17 May 2011 15:29:16 -0700 Subject: x86, mem: memcpy_64.S: Optimize memcpy by enhanced REP MOVSB/STOSB Support memcpy() with enhanced rep movsb. On processors supporting enhanced rep movsb, the alternative memcpy() function using enhanced rep movsb overrides the original function and the fast string function. Signed-off-by: Fenghua Yu Link: http://lkml.kernel.org/r/1305671358-14478-8-git-send-email-fenghua.yu@intel.com Signed-off-by: H. Peter Anvin diff --git a/arch/x86/lib/memcpy_64.S b/arch/x86/lib/memcpy_64.S index 75ef61e..daab21d 100644 --- a/arch/x86/lib/memcpy_64.S +++ b/arch/x86/lib/memcpy_64.S @@ -4,6 +4,7 @@ #include #include +#include /* * memcpy - Copy a memory block. @@ -37,6 +38,23 @@ .Lmemcpy_e: .previous +/* + * memcpy_c_e() - enhanced fast string memcpy. This is faster and simpler than + * memcpy_c. Use memcpy_c_e when possible. + * + * This gets patched over the unrolled variant (below) via the + * alternative instructions framework: + */ + .section .altinstr_replacement, "ax", @progbits +.Lmemcpy_c_e: + movq %rdi, %rax + + movl %edx, %ecx + rep movsb + ret +.Lmemcpy_e_e: + .previous + ENTRY(__memcpy) ENTRY(memcpy) CFI_STARTPROC @@ -171,21 +189,22 @@ ENDPROC(memcpy) ENDPROC(__memcpy) /* - * Some CPUs run faster using the string copy instructions. - * It is also a lot simpler. Use this when possible: - */ - - .section .altinstructions, "a" - .align 8 - .quad memcpy - .quad .Lmemcpy_c - .word X86_FEATURE_REP_GOOD - - /* + * Some CPUs are adding enhanced REP MOVSB/STOSB feature + * If the feature is supported, memcpy_c_e() is the first choice. + * If enhanced rep movsb copy is not available, use fast string copy + * memcpy_c() when possible. This is faster and code is simpler than + * original memcpy(). + * Otherwise, original memcpy() is used. + * In .altinstructions section, ERMS feature is placed after REG_GOOD + * feature to implement the right patch order. + * * Replace only beginning, memcpy is used to apply alternatives, * so it is silly to overwrite itself with nops - reboot is the * only outcome... */ - .byte .Lmemcpy_e - .Lmemcpy_c - .byte .Lmemcpy_e - .Lmemcpy_c + .section .altinstructions, "a" + altinstruction_entry memcpy,.Lmemcpy_c,X86_FEATURE_REP_GOOD,\ + .Lmemcpy_e-.Lmemcpy_c,.Lmemcpy_e-.Lmemcpy_c + altinstruction_entry memcpy,.Lmemcpy_c_e,X86_FEATURE_ERMS, \ + .Lmemcpy_e_e-.Lmemcpy_c_e,.Lmemcpy_e_e-.Lmemcpy_c_e .previous -- cgit v0.10.2 From 057e05c1d6440117875f455e59da8691e08f65d5 Mon Sep 17 00:00:00 2001 From: Fenghua Yu Date: Tue, 17 May 2011 15:29:17 -0700 Subject: x86, mem: memmove_64.S: Optimize memmove by enhanced REP MOVSB/STOSB Support memmove() by enhanced rep movsb. On processors supporting enhanced REP MOVSB/STOSB, the alternative memmove() function using enhanced rep movsb overrides the original function. The patch doesn't change the backward memmove case to use enhanced rep movsb. Signed-off-by: Fenghua Yu Link: http://lkml.kernel.org/r/1305671358-14478-9-git-send-email-fenghua.yu@intel.com Signed-off-by: H. Peter Anvin diff --git a/arch/x86/lib/memmove_64.S b/arch/x86/lib/memmove_64.S index 0ecb843..d0ec9c2 100644 --- a/arch/x86/lib/memmove_64.S +++ b/arch/x86/lib/memmove_64.S @@ -8,6 +8,7 @@ #define _STRING_C #include #include +#include #undef memmove @@ -24,6 +25,7 @@ */ ENTRY(memmove) CFI_STARTPROC + /* Handle more 32bytes in loop */ mov %rdi, %rax cmp $0x20, %rdx @@ -31,8 +33,13 @@ ENTRY(memmove) /* Decide forward/backward copy mode */ cmp %rdi, %rsi - jb 2f + jge .Lmemmove_begin_forward + mov %rsi, %r8 + add %rdx, %r8 + cmp %rdi, %r8 + jg 2f +.Lmemmove_begin_forward: /* * movsq instruction have many startup latency * so we handle small size by general register. @@ -78,6 +85,8 @@ ENTRY(memmove) rep movsq movq %r11, (%r10) jmp 13f +.Lmemmove_end_forward: + /* * Handle data backward by movsq. */ @@ -194,4 +203,22 @@ ENTRY(memmove) 13: retq CFI_ENDPROC + + .section .altinstr_replacement,"ax" +.Lmemmove_begin_forward_efs: + /* Forward moving data. */ + movq %rdx, %rcx + rep movsb + retq +.Lmemmove_end_forward_efs: + .previous + + .section .altinstructions,"a" + .align 8 + .quad .Lmemmove_begin_forward + .quad .Lmemmove_begin_forward_efs + .word X86_FEATURE_ERMS + .byte .Lmemmove_end_forward-.Lmemmove_begin_forward + .byte .Lmemmove_end_forward_efs-.Lmemmove_begin_forward_efs + .previous ENDPROC(memmove) -- cgit v0.10.2 From 2f19e06ac30771c7cb96fd61d8aeacfa74dac21c Mon Sep 17 00:00:00 2001 From: Fenghua Yu Date: Tue, 17 May 2011 15:29:18 -0700 Subject: x86, mem: memset_64.S: Optimize memset by enhanced REP MOVSB/STOSB Support memset() with enhanced rep stosb. On processors supporting enhanced REP MOVSB/STOSB, the alternative memset_c_e function using enhanced rep stosb overrides the fast string alternative memset_c and the original function. Signed-off-by: Fenghua Yu Link: http://lkml.kernel.org/r/1305671358-14478-10-git-send-email-fenghua.yu@intel.com Signed-off-by: H. Peter Anvin diff --git a/arch/x86/lib/memset_64.S b/arch/x86/lib/memset_64.S index 09d3442..79bd454 100644 --- a/arch/x86/lib/memset_64.S +++ b/arch/x86/lib/memset_64.S @@ -2,9 +2,13 @@ #include #include +#include +#include /* - * ISO C memset - set a memory block to a byte value. + * ISO C memset - set a memory block to a byte value. This function uses fast + * string to get better performance than the original function. The code is + * simpler and shorter than the orignal function as well. * * rdi destination * rsi value (char) @@ -31,6 +35,28 @@ .Lmemset_e: .previous +/* + * ISO C memset - set a memory block to a byte value. This function uses + * enhanced rep stosb to override the fast string function. + * The code is simpler and shorter than the fast string function as well. + * + * rdi destination + * rsi value (char) + * rdx count (bytes) + * + * rax original destination + */ + .section .altinstr_replacement, "ax", @progbits +.Lmemset_c_e: + movq %rdi,%r9 + movb %sil,%al + movl %edx,%ecx + rep stosb + movq %r9,%rax + ret +.Lmemset_e_e: + .previous + ENTRY(memset) ENTRY(__memset) CFI_STARTPROC @@ -112,16 +138,20 @@ ENTRY(__memset) ENDPROC(memset) ENDPROC(__memset) - /* Some CPUs run faster using the string instructions. - It is also a lot simpler. Use this when possible */ - -#include - + /* Some CPUs support enhanced REP MOVSB/STOSB feature. + * It is recommended to use this when possible. + * + * If enhanced REP MOVSB/STOSB feature is not available, use fast string + * instructions. + * + * Otherwise, use original memset function. + * + * In .altinstructions section, ERMS feature is placed after REG_GOOD + * feature to implement the right patch order. + */ .section .altinstructions,"a" - .align 8 - .quad memset - .quad .Lmemset_c - .word X86_FEATURE_REP_GOOD - .byte .Lfinal - memset - .byte .Lmemset_e - .Lmemset_c + altinstruction_entry memset,.Lmemset_c,X86_FEATURE_REP_GOOD,\ + .Lfinal-memset,.Lmemset_e-.Lmemset_c + altinstruction_entry memset,.Lmemset_c_e,X86_FEATURE_ERMS, \ + .Lfinal-memset,.Lmemset_e_e-.Lmemset_c_e .previous -- cgit v0.10.2 From 9bed4aca296fdf9c1b85a8f093e92018dc9864f3 Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Wed, 18 May 2011 09:03:34 +1000 Subject: crypto: aesni-intel - fix aesni build on i386 Fix build error on i386 by moving function prototypes: arch/x86/crypto/aesni-intel_glue.c: In function 'aesni_init': arch/x86/crypto/aesni-intel_glue.c:1263: error: implicit declaration of function 'crypto_fpu_init' arch/x86/crypto/aesni-intel_glue.c: In function 'aesni_exit': arch/x86/crypto/aesni-intel_glue.c:1373: error: implicit declaration of function 'crypto_fpu_exit' Signed-off-by: Randy Dunlap Signed-off-by: Herbert Xu diff --git a/arch/x86/crypto/aesni-intel_glue.c b/arch/x86/crypto/aesni-intel_glue.c index cbc60ef..feee8ff 100644 --- a/arch/x86/crypto/aesni-intel_glue.c +++ b/arch/x86/crypto/aesni-intel_glue.c @@ -94,6 +94,10 @@ asmlinkage void aesni_cbc_enc(struct crypto_aes_ctx *ctx, u8 *out, const u8 *in, unsigned int len, u8 *iv); asmlinkage void aesni_cbc_dec(struct crypto_aes_ctx *ctx, u8 *out, const u8 *in, unsigned int len, u8 *iv); + +int crypto_fpu_init(void); +void crypto_fpu_exit(void); + #ifdef CONFIG_X86_64 asmlinkage void aesni_ctr_enc(struct crypto_aes_ctx *ctx, u8 *out, const u8 *in, unsigned int len, u8 *iv); @@ -140,9 +144,6 @@ asmlinkage void aesni_gcm_dec(void *ctx, u8 *out, u8 *hash_subkey, const u8 *aad, unsigned long aad_len, u8 *auth_tag, unsigned long auth_tag_len); -int crypto_fpu_init(void); -void crypto_fpu_exit(void); - static inline struct aesni_rfc4106_gcm_ctx *aesni_rfc4106_gcm_ctx_get(struct crypto_aead *tfm) { -- cgit v0.10.2 From d0281a257f370b09c410e466571858b4e12869c9 Mon Sep 17 00:00:00 2001 From: Fenghua Yu Date: Tue, 17 May 2011 18:44:26 -0700 Subject: x86, cpufeature: Add cpufeature flag for SMEP Add support for newly documented SMEP (Supervisor Mode Execution Protection) CPU feature flag. SMEP prevents the CPU in kernel-mode to jump to an executable page that has the user flag set in the PTE. This prevents the kernel from executing user-space code accidentally or maliciously, so it for example prevents kernel exploits from jumping to specially prepared user-mode shell code. [ hpa: added better description by Ingo Molnar ] Signed-off-by: Fenghua Yu LKML-Reference: <1305683069-25394-2-git-send-email-fenghua.yu@intel.com> Signed-off-by: H. Peter Anvin diff --git a/arch/x86/include/asm/cpufeature.h b/arch/x86/include/asm/cpufeature.h index 7f2f7b1..8808cdb 100644 --- a/arch/x86/include/asm/cpufeature.h +++ b/arch/x86/include/asm/cpufeature.h @@ -195,6 +195,7 @@ /* Intel-defined CPU features, CPUID level 0x00000007:0 (ebx), word 9 */ #define X86_FEATURE_FSGSBASE (9*32+ 0) /* {RD/WR}{FS/GS}BASE instructions*/ +#define X86_FEATURE_SMEP (9*32+ 7) /* Supervisor Mode Execution Protection */ #define X86_FEATURE_ERMS (9*32+ 9) /* Enhanced REP MOVSB/STOSB */ #if defined(__KERNEL__) && !defined(__ASSEMBLY__) -- cgit v0.10.2 From dc23c0bccf5eea171c87b3db285d032b9a5f06c4 Mon Sep 17 00:00:00 2001 From: Fenghua Yu Date: Tue, 17 May 2011 18:44:27 -0700 Subject: x86, cpu: Add SMEP CPU feature in CR4 Add support for newly documented SMEP (Supervisor Mode Execution Protection) CPU feature in CR4. Signed-off-by: Fenghua Yu LKML-Reference: <1305683069-25394-3-git-send-email-fenghua.yu@intel.com> Signed-off-by: H. Peter Anvin diff --git a/arch/x86/include/asm/processor-flags.h b/arch/x86/include/asm/processor-flags.h index a898a2b..59ab4df 100644 --- a/arch/x86/include/asm/processor-flags.h +++ b/arch/x86/include/asm/processor-flags.h @@ -60,6 +60,7 @@ #define X86_CR4_OSXMMEXCPT 0x00000400 /* enable unmasked SSE exceptions */ #define X86_CR4_VMXE 0x00002000 /* enable VMX virtualization */ #define X86_CR4_OSXSAVE 0x00040000 /* enable xsave and xrestore */ +#define X86_CR4_SMEP 0x00100000 /* enable SMEP support */ /* * x86-64 Task Priority Register, CR8 -- cgit v0.10.2 From de5397ad5b9ad22e2401c4dacdf1bb3b19c05679 Mon Sep 17 00:00:00 2001 From: Fenghua Yu Date: Wed, 11 May 2011 16:51:05 -0700 Subject: x86, cpu: Enable/disable Supervisor Mode Execution Protection Enable/disable newly documented SMEP (Supervisor Mode Execution Protection) CPU feature in kernel. CR4.SMEP (bit 20) is 0 at power-on. If the feature is supported by CPU (X86_FEATURE_SMEP), enable SMEP by setting CR4.SMEP. New kernel option nosmep disables the feature even if the feature is supported by CPU. [ hpa: moved the call to setup_smep() until after the vendor-specific initialization; that ensures that CPUID features are unmasked. We will still run it before we have userspace (never mind uncontrolled userspace). ] Signed-off-by: Fenghua Yu LKML-Reference: <1305157865-31727-1-git-send-email-fenghua.yu@intel.com> Signed-off-by: H. Peter Anvin diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt index cc85a92..56fb8c1 100644 --- a/Documentation/kernel-parameters.txt +++ b/Documentation/kernel-parameters.txt @@ -1664,6 +1664,10 @@ bytes respectively. Such letter suffixes can also be entirely omitted. noexec=on: enable non-executable mappings (default) noexec=off: disable non-executable mappings + nosmep [X86] + Disable SMEP (Supervisor Mode Execution Protection) + even if it is supported by processor. + noexec32 [X86-64] This affects only 32-bit executables. noexec32=on: enable non-executable mappings (default) diff --git a/arch/x86/kernel/cpu/common.c b/arch/x86/kernel/cpu/common.c index 173f3a3..cbc70a2 100644 --- a/arch/x86/kernel/cpu/common.c +++ b/arch/x86/kernel/cpu/common.c @@ -254,6 +254,25 @@ static inline void squash_the_stupid_serial_number(struct cpuinfo_x86 *c) } #endif +static int disable_smep __initdata; +static __init int setup_disable_smep(char *arg) +{ + disable_smep = 1; + return 1; +} +__setup("nosmep", setup_disable_smep); + +static __init void setup_smep(struct cpuinfo_x86 *c) +{ + if (cpu_has(c, X86_FEATURE_SMEP)) { + if (unlikely(disable_smep)) { + setup_clear_cpu_cap(X86_FEATURE_SMEP); + clear_in_cr4(X86_CR4_SMEP); + } else + set_in_cr4(X86_CR4_SMEP); + } +} + /* * Some CPU features depend on higher CPUID levels, which may not always * be available due to CPUID level capping or broken virtualization @@ -667,6 +686,8 @@ static void __init early_identify_cpu(struct cpuinfo_x86 *c) c->cpu_index = 0; #endif filter_cpuid_features(c, false); + + setup_smep(c); } void __init early_cpu_init(void) @@ -752,6 +773,8 @@ static void __cpuinit generic_identify(struct cpuinfo_x86 *c) #endif } + setup_smep(c); + get_model_name(c); /* Default name */ detect_nopl(c); -- cgit v0.10.2 From abb57ea48fd9431fa320a5c55f73e6b5a44c2efb Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Wed, 18 May 2011 02:21:31 -0400 Subject: net: add skb_dst_force() in sock_queue_err_skb() Commit 7fee226ad239 (add a noref bit on skb dst) forgot to use skb_dst_force() on packets queued in sk_error_queue This triggers following warning, for applications using IP_CMSG_PKTINFO receiving one error status ------------[ cut here ]------------ WARNING: at include/linux/skbuff.h:457 ip_cmsg_recv_pktinfo+0xa6/0xb0() Hardware name: 2669UYD Modules linked in: isofs vboxnetadp vboxnetflt nfsd ebtable_nat ebtables lib80211_crypt_ccmp uinput xcbc hdaps tp_smapi thinkpad_ec radeonfb fb_ddc radeon ttm drm_kms_helper drm ipw2200 intel_agp intel_gtt libipw i2c_algo_bit i2c_i801 agpgart rng_core cfbfillrect cfbcopyarea cfbimgblt video raid10 raid1 raid0 linear md_mod vboxdrv Pid: 4697, comm: miredo Not tainted 2.6.39-rc6-00569-g5895198-dirty #22 Call Trace: [] ? printk+0x1d/0x1f [] warn_slowpath_common+0x72/0xa0 [] ? ip_cmsg_recv_pktinfo+0xa6/0xb0 [] ? ip_cmsg_recv_pktinfo+0xa6/0xb0 [] warn_slowpath_null+0x20/0x30 [] ip_cmsg_recv_pktinfo+0xa6/0xb0 [] ip_cmsg_recv+0x127/0x260 [] ? skb_dequeue+0x4d/0x70 [] ? skb_copy_datagram_iovec+0x53/0x300 [] ? sub_preempt_count+0x24/0x50 [] ip_recv_error+0x23d/0x270 [] udp_recvmsg+0x264/0x2b0 [] inet_recvmsg+0xd9/0x130 [] sock_recvmsg+0xf2/0x120 [] ? might_fault+0x4b/0xa0 [] ? verify_iovec+0x4c/0xc0 [] ? sock_recvmsg_nosec+0x100/0x100 [] __sys_recvmsg+0x114/0x1e0 [] ? __lock_acquire+0x365/0x780 [] ? fget_light+0xa6/0x3e0 [] ? fget_light+0xbf/0x3e0 [] ? fget_light+0x2e/0x3e0 [] sys_recvmsg+0x39/0x60 Close bug https://bugzilla.kernel.org/show_bug.cgi?id=34622 Reported-by: Witold Baryluk Signed-off-by: Eric Dumazet CC: Stephen Hemminger Signed-off-by: David S. Miller diff --git a/net/core/skbuff.c b/net/core/skbuff.c index 7ebeed0..3e934fe 100644 --- a/net/core/skbuff.c +++ b/net/core/skbuff.c @@ -2993,6 +2993,9 @@ int sock_queue_err_skb(struct sock *sk, struct sk_buff *skb) skb->destructor = sock_rmem_free; atomic_add(skb->truesize, &sk->sk_rmem_alloc); + /* before exiting rcu section, make sure dst is refcounted */ + skb_dst_force(skb); + skb_queue_tail(&sk->sk_error_queue, skb); if (!sock_flag(sk, SOCK_DEAD)) sk->sk_data_ready(sk, skb->len); -- cgit v0.10.2 From 0bf2461fdd9008290cf429e50e4f362dafab4249 Mon Sep 17 00:00:00 2001 From: Alexandre Bounine Date: Tue, 17 May 2011 15:44:08 -0700 Subject: rapidio: fix default routing initialization Fix switch initialization to ensure that all switches have default routing disabled. This guarantees that no unexpected RapidIO packets arrive to the default port set by reset and there is no default routing destination until it is properly configured by software. This update also unifies handling of unmapped destinations by tsi57x, IDT Gen1 and IDT Gen2 switches. Signed-off-by: Alexandre Bounine Cc: Kumar Gala Cc: Matt Porter Cc: Li Yang Cc: Thomas Moll Cc: [2.6.37+] Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/drivers/rapidio/switches/idt_gen2.c b/drivers/rapidio/switches/idt_gen2.c index ac2701b..043ee31 100644 --- a/drivers/rapidio/switches/idt_gen2.c +++ b/drivers/rapidio/switches/idt_gen2.c @@ -95,6 +95,9 @@ idtg2_route_add_entry(struct rio_mport *mport, u16 destid, u8 hopcount, else table++; + if (route_port == RIO_INVALID_ROUTE) + route_port = IDT_DEFAULT_ROUTE; + rio_mport_write_config_32(mport, destid, hopcount, LOCAL_RTE_CONF_DESTID_SEL, table); @@ -411,6 +414,12 @@ static int idtg2_switch_init(struct rio_dev *rdev, int do_enum) rdev->rswitch->em_handle = idtg2_em_handler; rdev->rswitch->sw_sysfs = idtg2_sysfs; + if (do_enum) { + /* Ensure that default routing is disabled on startup */ + rio_write_config_32(rdev, + RIO_STD_RTE_DEFAULT_PORT, IDT_NO_ROUTE); + } + return 0; } diff --git a/drivers/rapidio/switches/idtcps.c b/drivers/rapidio/switches/idtcps.c index 3a97107..d06ee2d 100644 --- a/drivers/rapidio/switches/idtcps.c +++ b/drivers/rapidio/switches/idtcps.c @@ -26,6 +26,9 @@ idtcps_route_add_entry(struct rio_mport *mport, u16 destid, u8 hopcount, { u32 result; + if (route_port == RIO_INVALID_ROUTE) + route_port = CPS_DEFAULT_ROUTE; + if (table == RIO_GLOBAL_TABLE) { rio_mport_write_config_32(mport, destid, hopcount, RIO_STD_RTE_CONF_DESTID_SEL_CSR, route_destid); @@ -130,6 +133,9 @@ static int idtcps_switch_init(struct rio_dev *rdev, int do_enum) /* set TVAL = ~50us */ rio_write_config_32(rdev, rdev->phys_efptr + RIO_PORT_LINKTO_CTL_CSR, 0x8e << 8); + /* Ensure that default routing is disabled on startup */ + rio_write_config_32(rdev, + RIO_STD_RTE_DEFAULT_PORT, CPS_NO_ROUTE); } return 0; diff --git a/drivers/rapidio/switches/tsi57x.c b/drivers/rapidio/switches/tsi57x.c index 1a62934..db8b802 100644 --- a/drivers/rapidio/switches/tsi57x.c +++ b/drivers/rapidio/switches/tsi57x.c @@ -303,6 +303,12 @@ static int tsi57x_switch_init(struct rio_dev *rdev, int do_enum) rdev->rswitch->em_init = tsi57x_em_init; rdev->rswitch->em_handle = tsi57x_em_handler; + if (do_enum) { + /* Ensure that default routing is disabled on startup */ + rio_write_config_32(rdev, RIO_STD_RTE_DEFAULT_PORT, + RIO_INVALID_ROUTE); + } + return 0; } -- cgit v0.10.2 From d5f33d45e4c0e306e8d16b4573891a65d9ad544f Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Tue, 17 May 2011 15:44:09 -0700 Subject: drivers/leds/leds-lm3530.c: add MODULE_DEVICE_TABLE Adding the necessary MODULE_DEVICE_TABLE() information allows the driver to be automatically loaded by udev. Signed-off-by: Axel Lin Cc: Shreshtha Kumar SAHU Cc: Richard Purdie Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/drivers/leds/leds-lm3530.c b/drivers/leds/leds-lm3530.c index e7089a1..b37e618 100644 --- a/drivers/leds/leds-lm3530.c +++ b/drivers/leds/leds-lm3530.c @@ -349,6 +349,7 @@ static const struct i2c_device_id lm3530_id[] = { {LM3530_NAME, 0}, {} }; +MODULE_DEVICE_TABLE(i2c, lm3530_id); static struct i2c_driver lm3530_i2c_driver = { .probe = lm3530_probe, -- cgit v0.10.2 From d6c438b6cd733834a3cec55af8577a8fc3548016 Mon Sep 17 00:00:00 2001 From: KAMEZAWA Hiroyuki Date: Tue, 17 May 2011 15:44:10 -0700 Subject: memcg: fix zone congestion ZONE_CONGESTED should be a state of global memory reclaim. If not, a busy memcg sets this and give unnecessary throttoling in wait_iff_congested() against memory recalim in other contexts. This makes system performance bad. I'll think about "memcg is congested!" flag is required or not, later. But this fix is required first. Signed-off-by: KAMEZAWA Hiroyuki Reviewed-by: Minchan Kim Cc: Daisuke Nishimura Acked-by: Ying Han Cc: Balbir Singh Cc: Johannes Weiner Cc: Michal Hocko Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/mm/vmscan.c b/mm/vmscan.c index f6b435c..8bfd450 100644 --- a/mm/vmscan.c +++ b/mm/vmscan.c @@ -937,7 +937,7 @@ keep_lumpy: * back off and wait for congestion to clear because further reclaim * will encounter the same problem */ - if (nr_dirty == nr_congested && nr_dirty != 0) + if (nr_dirty && nr_dirty == nr_congested && scanning_global_lru(sc)) zone_set_flag(zone, ZONE_CONGESTED); free_page_list(&free_pages); -- cgit v0.10.2 From b2db21997f43907f54500edaf063253ca2a186f9 Mon Sep 17 00:00:00 2001 From: Richard Weinberger Date: Tue, 17 May 2011 15:44:11 -0700 Subject: um: fix abort os_dump_core() uses abort() to terminate UML in case of an fatal error. glibc's abort() calls raise(SIGABRT) which makes use of tgkill(). tgkill() has no effect within UML's kernel threads because they are not pthreads. As fallback abort() executes an invalid instruction to terminate the process. Therefore UML gets killed by SIGSEGV and leaves a ugly log entry in the host's kernel ring buffer. To get rid of this we use our own abort routine. Signed-off-by: Richard Weinberger Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/arch/um/os-Linux/util.c b/arch/um/os-Linux/util.c index 6ea7797..42827ca 100644 --- a/arch/um/os-Linux/util.c +++ b/arch/um/os-Linux/util.c @@ -5,6 +5,7 @@ #include #include +#include #include #include #include @@ -75,6 +76,26 @@ void setup_hostinfo(char *buf, int len) host.release, host.version, host.machine); } +/* + * We cannot use glibc's abort(). It makes use of tgkill() which + * has no effect within UML's kernel threads. + * After that glibc would execute an invalid instruction to kill + * the calling process and UML crashes with SIGSEGV. + */ +static inline void __attribute__ ((noreturn)) uml_abort(void) +{ + sigset_t sig; + + fflush(NULL); + + if (!sigemptyset(&sig) && !sigaddset(&sig, SIGABRT)) + sigprocmask(SIG_UNBLOCK, &sig, 0); + + for (;;) + if (kill(getpid(), SIGABRT) < 0) + exit(127); +} + void os_dump_core(void) { int pid; @@ -116,5 +137,5 @@ void os_dump_core(void) while ((pid = waitpid(-1, NULL, WNOHANG | __WALL)) > 0) os_kill_ptraced_process(pid, 0); - abort(); + uml_abort(); } -- cgit v0.10.2 From f12a20fc9bfba4218ecbc4e40c8e08dc2a85dc99 Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Tue, 17 May 2011 15:44:12 -0700 Subject: procfs: add stub for proc_mkdir_mode() Provide a stub for proc_mkdir_mode() when CONFIG_PROC_FS is not enabled, just like the stub for proc_mkdir(). Fixes this linux-next build error: drivers/net/wireless/airo.c:4504: error: implicit declaration of function 'proc_mkdir_mode' Signed-off-by: Randy Dunlap Cc: Stephen Rothwell Cc: Alexey Dobriyan Cc: "John W. Linville" Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/include/linux/proc_fs.h b/include/linux/proc_fs.h index 838c114..eaf4350 100644 --- a/include/linux/proc_fs.h +++ b/include/linux/proc_fs.h @@ -208,6 +208,8 @@ static inline struct proc_dir_entry *proc_symlink(const char *name, struct proc_dir_entry *parent,const char *dest) {return NULL;} static inline struct proc_dir_entry *proc_mkdir(const char *name, struct proc_dir_entry *parent) {return NULL;} +static inline struct proc_dir_entry *proc_mkdir_mode(const char *name, + mode_t mode, struct proc_dir_entry *parent) { return NULL; } static inline struct proc_dir_entry *create_proc_read_entry(const char *name, mode_t mode, struct proc_dir_entry *base, -- cgit v0.10.2 From 3ec717b7ca4ee1d75d77e4f6286430d8f01d1dbd Mon Sep 17 00:00:00 2001 From: Shaohua Li Date: Wed, 18 May 2011 11:22:43 +0200 Subject: block: don't delay blk_run_queue_async Let's check a scenario: 1. blk_delay_queue(q, SCSI_QUEUE_DELAY); 2. blk_run_queue_async(); the second one will became a noop, because q->delay_work already has WORK_STRUCT_PENDING_BIT set, so the delayed work will still run after SCSI_QUEUE_DELAY. But blk_run_queue_async actually hopes the delayed work runs immediately. Fix this by doing a cancel on potentially pending delayed work before queuing an immediate run of the workqueue. Signed-off-by: Shaohua Li Signed-off-by: Jens Axboe diff --git a/block/blk-core.c b/block/blk-core.c index a2e58ee..3fe00a1 100644 --- a/block/blk-core.c +++ b/block/blk-core.c @@ -316,8 +316,10 @@ EXPORT_SYMBOL(__blk_run_queue); */ void blk_run_queue_async(struct request_queue *q) { - if (likely(!blk_queue_stopped(q))) + if (likely(!blk_queue_stopped(q))) { + __cancel_delayed_work(&q->delay_work); queue_delayed_work(kblockd_workqueue, &q->delay_work, 0); + } } EXPORT_SYMBOL(blk_run_queue_async); -- cgit v0.10.2 From df7f99670a4c76f269ae57ce91876b309417a316 Mon Sep 17 00:00:00 2001 From: Joel Becker Date: Tue, 22 Feb 2011 01:09:49 -0800 Subject: configfs: Don't try to d_delete() negative dentries. When configfs is faking mkdir() on its subsystem or default group objects, it starts by adding a negative dentry. It then tries to instantiate the group. If that should fail, it must clean up after itself. I was using d_delete() here, but configfs_attach_group() promises to return an empty dentry on error. d_delete() explodes with the entry dentry. Let's try d_drop() instead. The unhashing is what we want for our dentry. Signed-off-by: Joel Becker diff --git a/fs/configfs/dir.c b/fs/configfs/dir.c index 3313dd1..b11d734 100644 --- a/fs/configfs/dir.c +++ b/fs/configfs/dir.c @@ -689,7 +689,8 @@ static int create_default_group(struct config_group *parent_group, sd = child->d_fsdata; sd->s_type |= CONFIGFS_USET_DEFAULT; } else { - d_delete(child); + BUG_ON(child->d_inode); + d_drop(child); dput(child); } } @@ -1683,7 +1684,8 @@ int configfs_register_subsystem(struct configfs_subsystem *subsys) err = configfs_attach_group(sd->s_element, &group->cg_item, dentry); if (err) { - d_delete(dentry); + BUG_ON(dentry->d_inode); + d_drop(dentry); dput(dentry); } else { spin_lock(&configfs_dirent_lock); -- cgit v0.10.2 From 26afb7c661080ae3f1f13ddf7f0c58c4f931c22b Mon Sep 17 00:00:00 2001 From: Jiri Olsa Date: Thu, 12 May 2011 16:30:30 +0200 Subject: x86, 64-bit: Fix copy_[to/from]_user() checks for the userspace address limit As reported in BZ #30352: https://bugzilla.kernel.org/show_bug.cgi?id=30352 there's a kernel bug related to reading the last allowed page on x86_64. The _copy_to_user() and _copy_from_user() functions use the following check for address limit: if (buf + size >= limit) fail(); while it should be more permissive: if (buf + size > limit) fail(); That's because the size represents the number of bytes being read/write from/to buf address AND including the buf address. So the copy function will actually never touch the limit address even if "buf + size == limit". Following program fails to use the last page as buffer due to the wrong limit check: #include #include #include #define PAGE_SIZE (4096) #define LAST_PAGE ((void*)(0x7fffffffe000)) int main() { int fds[2], err; void * ptr = mmap(LAST_PAGE, PAGE_SIZE, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE | MAP_FIXED, -1, 0); assert(ptr == LAST_PAGE); err = socketpair(AF_LOCAL, SOCK_STREAM, 0, fds); assert(err == 0); err = send(fds[0], ptr, PAGE_SIZE, 0); perror("send"); assert(err == PAGE_SIZE); err = recv(fds[1], ptr, PAGE_SIZE, MSG_WAITALL); perror("recv"); assert(err == PAGE_SIZE); return 0; } The other place checking the addr limit is the access_ok() function, which is working properly. There's just a misleading comment for the __range_not_ok() macro - which this patch fixes as well. The last page of the user-space address range is a guard page and Brian Gerst observed that the guard page itself due to an erratum on K8 cpus (#121 Sequential Execution Across Non-Canonical Boundary Causes Processor Hang). However, the test code is using the last valid page before the guard page. The bug is that the last byte before the guard page can't be read because of the off-by-one error. The guard page is left in place. This bug would normally not show up because the last page is part of the process stack and never accessed via syscalls. Signed-off-by: Jiri Olsa Acked-by: Brian Gerst Acked-by: Linus Torvalds Cc: Link: http://lkml.kernel.org/r/1305210630-7136-1-git-send-email-jolsa@redhat.com Signed-off-by: Ingo Molnar diff --git a/arch/x86/include/asm/uaccess.h b/arch/x86/include/asm/uaccess.h index abd3e0e..99f0ad7 100644 --- a/arch/x86/include/asm/uaccess.h +++ b/arch/x86/include/asm/uaccess.h @@ -42,7 +42,7 @@ * Returns 0 if the range is valid, nonzero otherwise. * * This is equivalent to the following test: - * (u33)addr + (u33)size >= (u33)current->addr_limit.seg (u65 for x86_64) + * (u33)addr + (u33)size > (u33)current->addr_limit.seg (u65 for x86_64) * * This needs 33-bit (65-bit for x86_64) arithmetic. We have a carry... */ diff --git a/arch/x86/lib/copy_user_64.S b/arch/x86/lib/copy_user_64.S index d17a117..0248402 100644 --- a/arch/x86/lib/copy_user_64.S +++ b/arch/x86/lib/copy_user_64.S @@ -79,7 +79,7 @@ ENTRY(_copy_to_user) addq %rdx,%rcx jc bad_to_user cmpq TI_addr_limit(%rax),%rcx - jae bad_to_user + ja bad_to_user ALTERNATIVE_JUMP X86_FEATURE_REP_GOOD,X86_FEATURE_ERMS, \ copy_user_generic_unrolled,copy_user_generic_string, \ copy_user_enhanced_fast_string @@ -94,7 +94,7 @@ ENTRY(_copy_from_user) addq %rdx,%rcx jc bad_from_user cmpq TI_addr_limit(%rax),%rcx - jae bad_from_user + ja bad_from_user ALTERNATIVE_JUMP X86_FEATURE_REP_GOOD,X86_FEATURE_ERMS, \ copy_user_generic_unrolled,copy_user_generic_string, \ copy_user_enhanced_fast_string -- cgit v0.10.2 From 24307aa1e707b31613be92deaba7990e16bc1aec Mon Sep 17 00:00:00 2001 From: Joel Becker Date: Wed, 18 May 2011 04:08:16 -0700 Subject: configfs: Fix race between configfs_readdir() and configfs_d_iput() configfs_readdir() will use the existing inode numbers of inodes in the dcache, but it makes them up for attribute files that aren't currently instantiated. There is a race where a closing attribute file can be tearing down at the same time as configfs_readdir() is trying to get its inode number. We want to get the inode number of open attribute files, because they should match while instantiated. We can't lock down the transition where dentry->d_inode is set to NULL, so we just check for NULL there. We can, however, ensure that an inode we find isn't iput() in configfs_d_iput() until after we've accessed it. Signed-off-by: Joel Becker diff --git a/fs/configfs/dir.c b/fs/configfs/dir.c index b11d734..9a37a9b 100644 --- a/fs/configfs/dir.c +++ b/fs/configfs/dir.c @@ -53,11 +53,14 @@ DEFINE_SPINLOCK(configfs_dirent_lock); static void configfs_d_iput(struct dentry * dentry, struct inode * inode) { - struct configfs_dirent * sd = dentry->d_fsdata; + struct configfs_dirent *sd = dentry->d_fsdata; if (sd) { BUG_ON(sd->s_dentry != dentry); + /* Coordinate with configfs_readdir */ + spin_lock(&configfs_dirent_lock); sd->s_dentry = NULL; + spin_unlock(&configfs_dirent_lock); configfs_put(sd); } iput(inode); @@ -1546,7 +1549,7 @@ static int configfs_readdir(struct file * filp, void * dirent, filldir_t filldir struct configfs_dirent * parent_sd = dentry->d_fsdata; struct configfs_dirent *cursor = filp->private_data; struct list_head *p, *q = &cursor->s_sibling; - ino_t ino; + ino_t ino = 0; int i = filp->f_pos; switch (i) { @@ -1574,6 +1577,7 @@ static int configfs_readdir(struct file * filp, void * dirent, filldir_t filldir struct configfs_dirent *next; const char * name; int len; + struct inode *inode = NULL; next = list_entry(p, struct configfs_dirent, s_sibling); @@ -1582,9 +1586,28 @@ static int configfs_readdir(struct file * filp, void * dirent, filldir_t filldir name = configfs_get_name(next); len = strlen(name); - if (next->s_dentry) - ino = next->s_dentry->d_inode->i_ino; - else + + /* + * We'll have a dentry and an inode for + * PINNED items and for open attribute + * files. We lock here to prevent a race + * with configfs_d_iput() clearing + * s_dentry before calling iput(). + * + * Why do we go to the trouble? If + * someone has an attribute file open, + * the inode number should match until + * they close it. Beyond that, we don't + * care. + */ + spin_lock(&configfs_dirent_lock); + dentry = next->s_dentry; + if (dentry) + inode = dentry->d_inode; + if (inode) + ino = inode->i_ino; + spin_unlock(&configfs_dirent_lock); + if (!inode) ino = iunique(configfs_sb, 2); if (filldir(dirent, name, len, filp->f_pos, ino, -- cgit v0.10.2 From fe0514348452f5b0ad7e842b0d71b8322b1297de Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Wed, 18 May 2011 12:53:03 +0200 Subject: genirq: Remove pointless ifdefs kernel/irq/ is only built when CONFIG_GENERIC_HARDIRQS=y. So making code inside of kernel/irq/ conditional on CONFIG_GENERIC_HARDIRQS is pointless. Signed-off-by: Thomas Gleixner diff --git a/kernel/irq/irqdesc.c b/kernel/irq/irqdesc.c index 2c039c9..e07b975 100644 --- a/kernel/irq/irqdesc.c +++ b/kernel/irq/irqdesc.c @@ -22,7 +22,7 @@ */ static struct lock_class_key irq_desc_lock_class; -#if defined(CONFIG_SMP) && defined(CONFIG_GENERIC_HARDIRQS) +#if defined(CONFIG_SMP) static void __init init_irq_default_affinity(void) { alloc_cpumask_var(&irq_default_affinity, GFP_NOWAIT); @@ -430,7 +430,6 @@ unsigned int kstat_irqs_cpu(unsigned int irq, int cpu) *per_cpu_ptr(desc->kstat_irqs, cpu) : 0; } -#ifdef CONFIG_GENERIC_HARDIRQS unsigned int kstat_irqs(unsigned int irq) { struct irq_desc *desc = irq_to_desc(irq); @@ -443,4 +442,3 @@ unsigned int kstat_irqs(unsigned int irq) sum += *per_cpu_ptr(desc->kstat_irqs, cpu); return sum; } -#endif /* CONFIG_GENERIC_HARDIRQS */ -- cgit v0.10.2 From fe12bc2c996d3e492b2920e32ac79f7bbae3e15d Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Wed, 18 May 2011 12:48:00 +0200 Subject: genirq: Uninline and sanity check generic_handle_irq() generic_handle_irq() is missing a NULL pointer check for the result of irq_to_desc. This was a not a big problem, but we want to expose it to drivers, so we better have sanity checks in place. Add a return value as well, which indicates that the irq number was valid and the handler was invoked. Based on the pure code move from Jonathan Cameron. Signed-off-by: Thomas Gleixner Cc: Jonathan Cameron diff --git a/include/linux/irqdesc.h b/include/linux/irqdesc.h index c70b1aa..2d921b3 100644 --- a/include/linux/irqdesc.h +++ b/include/linux/irqdesc.h @@ -111,10 +111,7 @@ static inline void generic_handle_irq_desc(unsigned int irq, struct irq_desc *de desc->handle_irq(irq, desc); } -static inline void generic_handle_irq(unsigned int irq) -{ - generic_handle_irq_desc(irq, irq_to_desc(irq)); -} +int generic_handle_irq(unsigned int irq); /* Test to see if a driver has successfully requested an irq */ static inline int irq_has_action(unsigned int irq) diff --git a/kernel/irq/irqdesc.c b/kernel/irq/irqdesc.c index e07b975..9f65b02 100644 --- a/kernel/irq/irqdesc.c +++ b/kernel/irq/irqdesc.c @@ -290,6 +290,21 @@ static int irq_expand_nr_irqs(unsigned int nr) #endif /* !CONFIG_SPARSE_IRQ */ +/** + * generic_handle_irq - Invoke the handler for a particular irq + * @irq: The irq number to handle + * + */ +int generic_handle_irq(unsigned int irq) +{ + struct irq_desc *desc = irq_to_desc(irq); + + if (!desc) + return -EINVAL; + generic_handle_irq_desc(irq, desc); + return 0; +} + /* Dynamic interrupt handling */ /** -- cgit v0.10.2 From edf76f8307c350bcb81f0c760118a991b3e62956 Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Wed, 18 May 2011 10:39:04 +0100 Subject: irq: Export functions to allow modular irq drivers Export handle_simple_irq, irq_modify_status, irq_alloc_descs, irq_free_descs and generic_handle_irq to allow their usage in modules. First user is IIO, which wants to be built modular, but needs to be able to create irq chips, allocate and configure interrupt descriptors and handle demultiplexing interrupts. [ tglx: Moved the uninlinig of generic_handle_irq to a separate patch ] Signed-off-by: Jonathan Cameron Link: http://lkml.kernel.org/r/%3C1305711544-505-1-git-send-email-jic23%40cam.ac.uk%3E Signed-off-by: Thomas Gleixner diff --git a/kernel/irq/chip.c b/kernel/irq/chip.c index 52d856d..d5a3009 100644 --- a/kernel/irq/chip.c +++ b/kernel/irq/chip.c @@ -310,6 +310,7 @@ handle_simple_irq(unsigned int irq, struct irq_desc *desc) out_unlock: raw_spin_unlock(&desc->lock); } +EXPORT_SYMBOL_GPL(handle_simple_irq); /** * handle_level_irq - Level type irq handler @@ -613,6 +614,7 @@ void irq_modify_status(unsigned int irq, unsigned long clr, unsigned long set) irq_put_desc_unlock(desc, flags); } +EXPORT_SYMBOL_GPL(irq_modify_status); /** * irq_cpu_online - Invoke all irq_cpu_online functions. diff --git a/kernel/irq/irqdesc.c b/kernel/irq/irqdesc.c index 9f65b02..886e803 100644 --- a/kernel/irq/irqdesc.c +++ b/kernel/irq/irqdesc.c @@ -304,6 +304,7 @@ int generic_handle_irq(unsigned int irq) generic_handle_irq_desc(irq, desc); return 0; } +EXPORT_SYMBOL_GPL(generic_handle_irq); /* Dynamic interrupt handling */ @@ -326,6 +327,7 @@ void irq_free_descs(unsigned int from, unsigned int cnt) bitmap_clear(allocated_irqs, from, cnt); mutex_unlock(&sparse_irq_lock); } +EXPORT_SYMBOL_GPL(irq_free_descs); /** * irq_alloc_descs - allocate and initialize a range of irq descriptors @@ -366,6 +368,7 @@ err: mutex_unlock(&sparse_irq_lock); return ret; } +EXPORT_SYMBOL_GPL(irq_alloc_descs); /** * irq_reserve_irqs - mark irqs allocated -- cgit v0.10.2 From b2b07e4fdbc51383cfc0ba5618c2ddf5c9d038f2 Mon Sep 17 00:00:00 2001 From: Oleg Nesterov Date: Wed, 18 May 2011 15:08:03 +0200 Subject: signal: trivial, fix the "timespec declared inside parameter list" warning Fix the compile warning, do_sigtimedwait(struct timespec *) in signal.h needs the forward declaration of timespec. Reported-and-acked-by: Mike Frysinger Signed-off-by: Oleg Nesterov diff --git a/include/linux/signal.h b/include/linux/signal.h index 7e25263..a44e7f0 100644 --- a/include/linux/signal.h +++ b/include/linux/signal.h @@ -234,6 +234,9 @@ static inline int valid_signal(unsigned long sig) return sig <= _NSIG ? 1 : 0; } +struct timespec; +struct pt_regs; + extern int next_signal(struct sigpending *pending, sigset_t *mask); extern int do_send_sig_info(int sig, struct siginfo *info, struct task_struct *p, bool group); @@ -248,7 +251,6 @@ extern int sigprocmask(int, sigset_t *, sigset_t *); extern void set_current_blocked(const sigset_t *); extern int show_unhandled_signals; -struct pt_regs; extern int get_signal_to_deliver(siginfo_t *info, struct k_sigaction *return_ka, struct pt_regs *regs, void *cookie); extern void exit_signals(struct task_struct *tsk); -- cgit v0.10.2 From 3436830af53c38b7674097c00b02b7a4064476f2 Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Thu, 12 May 2011 13:55:48 +0100 Subject: MIPS: RB532: Fix iomap resource size miscalculation. This is the MIPS portion of Joe Perches 's https://patchwork.linux-mips.org/patch/2172/ which seems to have been lost in time and space. Signed-off-by: Ralf Baechle diff --git a/arch/mips/rb532/gpio.c b/arch/mips/rb532/gpio.c index 37de05d..6c47dfe 100644 --- a/arch/mips/rb532/gpio.c +++ b/arch/mips/rb532/gpio.c @@ -185,7 +185,7 @@ int __init rb532_gpio_init(void) struct resource *r; r = rb532_gpio_reg0_res; - rb532_gpio_chip->regbase = ioremap_nocache(r->start, r->end - r->start); + rb532_gpio_chip->regbase = ioremap_nocache(r->start, resource_size(r)); if (!rb532_gpio_chip->regbase) { printk(KERN_ERR "rb532: cannot remap GPIO register 0\n"); -- cgit v0.10.2 From 10423c91ffc8e59d4f99d401f7beb3115cdc117a Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Fri, 13 May 2011 10:33:28 +0100 Subject: MIPS: Fix duplicate invocation of notify_die. Initial patch by Yury Polyanskiy . Signed-off-by: Ralf Baechle Patchwork: https://patchwork.linux-mips.org/patch/2373/ diff --git a/arch/mips/kernel/traps.c b/arch/mips/kernel/traps.c index 71350f7..e9b3af2 100644 --- a/arch/mips/kernel/traps.c +++ b/arch/mips/kernel/traps.c @@ -374,7 +374,8 @@ void __noreturn die(const char *str, struct pt_regs *regs) unsigned long dvpret = dvpe(); #endif /* CONFIG_MIPS_MT_SMTC */ - notify_die(DIE_OOPS, str, regs, 0, regs_to_trapnr(regs), SIGSEGV); + if (notify_die(DIE_OOPS, str, regs, 0, regs_to_trapnr(regs), SIGSEGV) == NOTIFY_STOP) + sig = 0; console_verbose(); spin_lock_irq(&die_lock); @@ -383,9 +384,6 @@ void __noreturn die(const char *str, struct pt_regs *regs) mips_mt_regdump(dvpret); #endif /* CONFIG_MIPS_MT_SMTC */ - if (notify_die(DIE_OOPS, str, regs, 0, regs_to_trapnr(regs), SIGSEGV) == NOTIFY_STOP) - sig = 0; - printk("%s[#%d]:\n", str, ++die_counter); show_registers(regs); add_taint(TAINT_DIE); -- cgit v0.10.2 From 3e9957b4866f3767f19bf0e543b322ad7906c564 Mon Sep 17 00:00:00 2001 From: Florian Fainelli Date: Fri, 13 May 2011 17:41:21 +0200 Subject: MIPS: AR7: Fix GPIO register size for Titan variant. The 'size' variable contains the correct register size for both AR7 and Titan, but we never used it to ioremap the correct register size. This problem only shows up on Titan. [ralf@linux-mips.org: Fixed the fix. The original patch as in patchwork recognizes the problem correctly then fails to fix it ...] Reported-by: Alexander Clouter Signed-off-by: Florian Fainelli Patchwork: https://patchwork.linux-mips.org/patch/2380/ Signed-off-by: Ralf Baechle diff --git a/arch/mips/ar7/gpio.c b/arch/mips/ar7/gpio.c index 425dfa5..bb571bc 100644 --- a/arch/mips/ar7/gpio.c +++ b/arch/mips/ar7/gpio.c @@ -325,9 +325,7 @@ int __init ar7_gpio_init(void) size = 0x1f; } - gpch->regs = ioremap_nocache(AR7_REGS_GPIO, - AR7_REGS_GPIO + 0x10); - + gpch->regs = ioremap_nocache(AR7_REGS_GPIO, size); if (!gpch->regs) { printk(KERN_ERR "%s: failed to ioremap regs\n", gpch->chip.label); -- cgit v0.10.2 From a5602a3273774c720aaf165ff670e5b85e5910a5 Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Wed, 18 May 2011 13:14:36 +0100 Subject: MIPS: Kludge IP27 build for 2.6.39. Signed-off-by: Ralf Baechle diff --git a/arch/mips/include/asm/dma-mapping.h b/arch/mips/include/asm/dma-mapping.h index 655f849..7aa37dd 100644 --- a/arch/mips/include/asm/dma-mapping.h +++ b/arch/mips/include/asm/dma-mapping.h @@ -5,7 +5,9 @@ #include #include +#ifndef CONFIG_SGI_IP27 /* Kludge to fix 2.6.39 build for IP27 */ #include +#endif extern struct dma_map_ops *mips_dma_map_ops; -- cgit v0.10.2 From 01294d82622d6d9d64bde8e4530c7e2c6dbb6ee6 Mon Sep 17 00:00:00 2001 From: Milton Miller Date: Wed, 18 May 2011 10:27:39 -0500 Subject: of: fix race when matching drivers If two drivers are probing devices at the same time, both will write their match table result to the dev->of_match cache at the same time. Only write the result if the device matches. In a thread titled "SBus devices sometimes detected, sometimes not", Meelis reported his SBus hme was not detected about 50% of the time. From the debug suggested by Grant it was obvious another driver matched some devices between the call to match the hme and the hme discovery failling. Reported-by: Meelis Roos Signed-off-by: Milton Miller [grant.likely: modified to only call of_match_device() once] Signed-off-by: Grant Likely diff --git a/include/linux/of_device.h b/include/linux/of_device.h index 8bfe6c1..b33d688 100644 --- a/include/linux/of_device.h +++ b/include/linux/of_device.h @@ -21,8 +21,12 @@ extern void of_device_make_bus_id(struct device *dev); static inline int of_driver_match_device(struct device *dev, const struct device_driver *drv) { - dev->of_match = of_match_device(drv->of_match_table, dev); - return dev->of_match != NULL; + const struct of_device_id *match; + + match = of_match_device(drv->of_match_table, dev); + if (match) + dev->of_match = match; + return match != NULL; } extern struct platform_device *of_dev_get(struct platform_device *dev); -- cgit v0.10.2 From b1608d69cb804e414d0887140ba08a9398e4e638 Mon Sep 17 00:00:00 2001 From: Grant Likely Date: Wed, 18 May 2011 11:19:24 -0600 Subject: drivercore: revert addition of of_match to struct device Commit b826291c, "drivercore/dt: add a match table pointer to struct device" added an of_match pointer to struct device to cache the of_match_table entry discovered at driver match time. This was unsafe because matching is not an atomic operation with probing a driver. If two or more drivers are attempted to be matched to a driver at the same time, then the cached matching entry pointer could get overwritten. This patch reverts the of_match cache pointer and reworks all users to call of_match_device() directly instead. Signed-off-by: Grant Likely diff --git a/arch/powerpc/platforms/83xx/suspend.c b/arch/powerpc/platforms/83xx/suspend.c index 1882729..104faa8 100644 --- a/arch/powerpc/platforms/83xx/suspend.c +++ b/arch/powerpc/platforms/83xx/suspend.c @@ -318,17 +318,20 @@ static const struct platform_suspend_ops mpc83xx_suspend_ops = { .end = mpc83xx_suspend_end, }; +static struct of_device_id pmc_match[]; static int pmc_probe(struct platform_device *ofdev) { + const struct of_device_id *match; struct device_node *np = ofdev->dev.of_node; struct resource res; struct pmc_type *type; int ret = 0; - if (!ofdev->dev.of_match) + match = of_match_device(pmc_match, &ofdev->dev); + if (!match) return -EINVAL; - type = ofdev->dev.of_match->data; + type = match->data; if (!of_device_is_available(np)) return -ENODEV; diff --git a/arch/powerpc/sysdev/fsl_msi.c b/arch/powerpc/sysdev/fsl_msi.c index d5679dc..01cd2f0 100644 --- a/arch/powerpc/sysdev/fsl_msi.c +++ b/arch/powerpc/sysdev/fsl_msi.c @@ -304,8 +304,10 @@ static int __devinit fsl_msi_setup_hwirq(struct fsl_msi *msi, return 0; } +static const struct of_device_id fsl_of_msi_ids[]; static int __devinit fsl_of_msi_probe(struct platform_device *dev) { + const struct of_device_id *match; struct fsl_msi *msi; struct resource res; int err, i, j, irq_index, count; @@ -316,9 +318,10 @@ static int __devinit fsl_of_msi_probe(struct platform_device *dev) u32 offset; static const u32 all_avail[] = { 0, NR_MSI_IRQS }; - if (!dev->dev.of_match) + match = of_match_device(fsl_of_msi_ids, &dev->dev); + if (!match) return -EINVAL; - features = dev->dev.of_match->data; + features = match->data; printk(KERN_DEBUG "Setting up Freescale MSI support\n"); diff --git a/arch/sparc/kernel/pci_sabre.c b/arch/sparc/kernel/pci_sabre.c index 948068a..d1840db 100644 --- a/arch/sparc/kernel/pci_sabre.c +++ b/arch/sparc/kernel/pci_sabre.c @@ -452,8 +452,10 @@ static void __devinit sabre_pbm_init(struct pci_pbm_info *pbm, sabre_scan_bus(pbm, &op->dev); } +static const struct of_device_id sabre_match[]; static int __devinit sabre_probe(struct platform_device *op) { + const struct of_device_id *match; const struct linux_prom64_registers *pr_regs; struct device_node *dp = op->dev.of_node; struct pci_pbm_info *pbm; @@ -463,7 +465,8 @@ static int __devinit sabre_probe(struct platform_device *op) const u32 *vdma; u64 clear_irq; - hummingbird_p = op->dev.of_match && (op->dev.of_match->data != NULL); + match = of_match_device(sabre_match, &op->dev); + hummingbird_p = match && (match->data != NULL); if (!hummingbird_p) { struct device_node *cpu_dp; diff --git a/arch/sparc/kernel/pci_schizo.c b/arch/sparc/kernel/pci_schizo.c index fecfcb2..283fbc3 100644 --- a/arch/sparc/kernel/pci_schizo.c +++ b/arch/sparc/kernel/pci_schizo.c @@ -1458,11 +1458,15 @@ out_err: return err; } +static const struct of_device_id schizo_match[]; static int __devinit schizo_probe(struct platform_device *op) { - if (!op->dev.of_match) + const struct of_device_id *match; + + match = of_match_device(schizo_match, &op->dev); + if (!match) return -EINVAL; - return __schizo_init(op, (unsigned long) op->dev.of_match->data); + return __schizo_init(op, (unsigned long)match->data); } /* The ordering of this table is very important. Some Tomatillo diff --git a/drivers/atm/fore200e.c b/drivers/atm/fore200e.c index bdd2719..bc9e702 100644 --- a/drivers/atm/fore200e.c +++ b/drivers/atm/fore200e.c @@ -2643,16 +2643,19 @@ fore200e_init(struct fore200e* fore200e, struct device *parent) } #ifdef CONFIG_SBUS +static const struct of_device_id fore200e_sba_match[]; static int __devinit fore200e_sba_probe(struct platform_device *op) { + const struct of_device_id *match; const struct fore200e_bus *bus; struct fore200e *fore200e; static int index = 0; int err; - if (!op->dev.of_match) + match = of_match_device(fore200e_sba_match, &op->dev); + if (!match) return -EINVAL; - bus = op->dev.of_match->data; + bus = match->data; fore200e = kzalloc(sizeof(struct fore200e), GFP_KERNEL); if (!fore200e) diff --git a/drivers/char/hw_random/n2-drv.c b/drivers/char/hw_random/n2-drv.c index 43ac619..ac6739e 100644 --- a/drivers/char/hw_random/n2-drv.c +++ b/drivers/char/hw_random/n2-drv.c @@ -619,15 +619,18 @@ static void __devinit n2rng_driver_version(void) pr_info("%s", version); } +static const struct of_device_id n2rng_match[]; static int __devinit n2rng_probe(struct platform_device *op) { + const struct of_device_id *match; int victoria_falls; int err = -ENOMEM; struct n2rng *np; - if (!op->dev.of_match) + match = of_match_device(n2rng_match, &op->dev); + if (!match) return -EINVAL; - victoria_falls = (op->dev.of_match->data != NULL); + victoria_falls = (match->data != NULL); n2rng_driver_version(); np = kzalloc(sizeof(*np), GFP_KERNEL); diff --git a/drivers/char/ipmi/ipmi_si_intf.c b/drivers/char/ipmi/ipmi_si_intf.c index cc6c9b2..64c6b85 100644 --- a/drivers/char/ipmi/ipmi_si_intf.c +++ b/drivers/char/ipmi/ipmi_si_intf.c @@ -2554,9 +2554,11 @@ static struct pci_driver ipmi_pci_driver = { }; #endif /* CONFIG_PCI */ +static struct of_device_id ipmi_match[]; static int __devinit ipmi_probe(struct platform_device *dev) { #ifdef CONFIG_OF + const struct of_device_id *match; struct smi_info *info; struct resource resource; const __be32 *regsize, *regspacing, *regshift; @@ -2566,7 +2568,8 @@ static int __devinit ipmi_probe(struct platform_device *dev) dev_info(&dev->dev, "probing via device tree\n"); - if (!dev->dev.of_match) + match = of_match_device(ipmi_match, &dev->dev); + if (!match) return -EINVAL; ret = of_address_to_resource(np, 0, &resource); @@ -2601,7 +2604,7 @@ static int __devinit ipmi_probe(struct platform_device *dev) return -ENOMEM; } - info->si_type = (enum si_type) dev->dev.of_match->data; + info->si_type = (enum si_type) match->data; info->addr_source = SI_DEVICETREE; info->irq_setup = std_irq_setup; diff --git a/drivers/char/xilinx_hwicap/xilinx_hwicap.c b/drivers/char/xilinx_hwicap/xilinx_hwicap.c index d6412c1..39ccdea 100644 --- a/drivers/char/xilinx_hwicap/xilinx_hwicap.c +++ b/drivers/char/xilinx_hwicap/xilinx_hwicap.c @@ -715,13 +715,13 @@ static int __devexit hwicap_remove(struct device *dev) } #ifdef CONFIG_OF -static int __devinit hwicap_of_probe(struct platform_device *op) +static int __devinit hwicap_of_probe(struct platform_device *op, + const struct hwicap_driver_config *config) { struct resource res; const unsigned int *id; const char *family; int rc; - const struct hwicap_driver_config *config = op->dev.of_match->data; const struct config_registers *regs; @@ -751,20 +751,24 @@ static int __devinit hwicap_of_probe(struct platform_device *op) regs); } #else -static inline int hwicap_of_probe(struct platform_device *op) +static inline int hwicap_of_probe(struct platform_device *op, + const struct hwicap_driver_config *config) { return -EINVAL; } #endif /* CONFIG_OF */ +static const struct of_device_id __devinitconst hwicap_of_match[]; static int __devinit hwicap_drv_probe(struct platform_device *pdev) { + const struct of_device_id *match; struct resource *res; const struct config_registers *regs; const char *family; - if (pdev->dev.of_match) - return hwicap_of_probe(pdev); + match = of_match_device(hwicap_of_match, &pdev->dev); + if (match) + return hwicap_of_probe(pdev, match->data); res = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!res) diff --git a/drivers/edac/ppc4xx_edac.c b/drivers/edac/ppc4xx_edac.c index c1f0045..af8e7b1 100644 --- a/drivers/edac/ppc4xx_edac.c +++ b/drivers/edac/ppc4xx_edac.c @@ -1019,7 +1019,7 @@ ppc4xx_edac_mc_init(struct mem_ctl_info *mci, struct ppc4xx_edac_pdata *pdata = NULL; const struct device_node *np = op->dev.of_node; - if (op->dev.of_match == NULL) + if (of_match_device(ppc4xx_edac_match, &op->dev) == NULL) return -EINVAL; /* Initial driver pointers and private data */ diff --git a/drivers/i2c/busses/i2c-mpc.c b/drivers/i2c/busses/i2c-mpc.c index 75b984c..107397a 100644 --- a/drivers/i2c/busses/i2c-mpc.c +++ b/drivers/i2c/busses/i2c-mpc.c @@ -560,15 +560,18 @@ static struct i2c_adapter mpc_ops = { .timeout = HZ, }; +static const struct of_device_id mpc_i2c_of_match[]; static int __devinit fsl_i2c_probe(struct platform_device *op) { + const struct of_device_id *match; struct mpc_i2c *i2c; const u32 *prop; u32 clock = MPC_I2C_CLOCK_LEGACY; int result = 0; int plen; - if (!op->dev.of_match) + match = of_match_device(mpc_i2c_of_match, &op->dev); + if (!match) return -EINVAL; i2c = kzalloc(sizeof(*i2c), GFP_KERNEL); @@ -605,8 +608,8 @@ static int __devinit fsl_i2c_probe(struct platform_device *op) clock = *prop; } - if (op->dev.of_match->data) { - struct mpc_i2c_data *data = op->dev.of_match->data; + if (match->data) { + struct mpc_i2c_data *data = match->data; data->setup(op->dev.of_node, i2c, clock, data->prescaler); } else { /* Backwards compatibility */ diff --git a/drivers/mmc/host/sdhci-of-core.c b/drivers/mmc/host/sdhci-of-core.c index f9b611f..60e4186 100644 --- a/drivers/mmc/host/sdhci-of-core.c +++ b/drivers/mmc/host/sdhci-of-core.c @@ -124,8 +124,10 @@ static bool __devinit sdhci_of_wp_inverted(struct device_node *np) #endif } +static const struct of_device_id sdhci_of_match[]; static int __devinit sdhci_of_probe(struct platform_device *ofdev) { + const struct of_device_id *match; struct device_node *np = ofdev->dev.of_node; struct sdhci_of_data *sdhci_of_data; struct sdhci_host *host; @@ -134,9 +136,10 @@ static int __devinit sdhci_of_probe(struct platform_device *ofdev) int size; int ret; - if (!ofdev->dev.of_match) + match = of_match_device(sdhci_of_match, &ofdev->dev); + if (!match) return -EINVAL; - sdhci_of_data = ofdev->dev.of_match->data; + sdhci_of_data = match->data; if (!of_device_is_available(np)) return -ENODEV; diff --git a/drivers/mtd/maps/physmap_of.c b/drivers/mtd/maps/physmap_of.c index bd483f0..c1d3346 100644 --- a/drivers/mtd/maps/physmap_of.c +++ b/drivers/mtd/maps/physmap_of.c @@ -214,11 +214,13 @@ static void __devinit of_free_probes(const char **probes) } #endif +static struct of_device_id of_flash_match[]; static int __devinit of_flash_probe(struct platform_device *dev) { #ifdef CONFIG_MTD_PARTITIONS const char **part_probe_types; #endif + const struct of_device_id *match; struct device_node *dp = dev->dev.of_node; struct resource res; struct of_flash *info; @@ -232,9 +234,10 @@ static int __devinit of_flash_probe(struct platform_device *dev) struct mtd_info **mtd_list = NULL; resource_size_t res_size; - if (!dev->dev.of_match) + match = of_match_device(of_flash_match, &dev->dev); + if (!match) return -EINVAL; - probe_type = dev->dev.of_match->data; + probe_type = match->data; reg_tuple_size = (of_n_addr_cells(dp) + of_n_size_cells(dp)) * sizeof(u32); diff --git a/drivers/net/can/mscan/mpc5xxx_can.c b/drivers/net/can/mscan/mpc5xxx_can.c index bd1d811..5fedc33 100644 --- a/drivers/net/can/mscan/mpc5xxx_can.c +++ b/drivers/net/can/mscan/mpc5xxx_can.c @@ -247,8 +247,10 @@ static u32 __devinit mpc512x_can_get_clock(struct platform_device *ofdev, } #endif /* CONFIG_PPC_MPC512x */ +static struct of_device_id mpc5xxx_can_table[]; static int __devinit mpc5xxx_can_probe(struct platform_device *ofdev) { + const struct of_device_id *match; struct mpc5xxx_can_data *data; struct device_node *np = ofdev->dev.of_node; struct net_device *dev; @@ -258,9 +260,10 @@ static int __devinit mpc5xxx_can_probe(struct platform_device *ofdev) int irq, mscan_clksrc = 0; int err = -ENOMEM; - if (!ofdev->dev.of_match) + match = of_match_device(mpc5xxx_can_table, &ofdev->dev); + if (!match) return -EINVAL; - data = (struct mpc5xxx_can_data *)ofdev->dev.of_match->data; + data = match->data; base = of_iomap(np, 0); if (!base) { diff --git a/drivers/net/fs_enet/fs_enet-main.c b/drivers/net/fs_enet/fs_enet-main.c index 24cb953..5131e61 100644 --- a/drivers/net/fs_enet/fs_enet-main.c +++ b/drivers/net/fs_enet/fs_enet-main.c @@ -998,8 +998,10 @@ static const struct net_device_ops fs_enet_netdev_ops = { #endif }; +static struct of_device_id fs_enet_match[]; static int __devinit fs_enet_probe(struct platform_device *ofdev) { + const struct of_device_id *match; struct net_device *ndev; struct fs_enet_private *fep; struct fs_platform_info *fpi; @@ -1007,14 +1009,15 @@ static int __devinit fs_enet_probe(struct platform_device *ofdev) const u8 *mac_addr; int privsize, len, ret = -ENODEV; - if (!ofdev->dev.of_match) + match = of_match_device(fs_enet_match, &ofdev->dev); + if (!match) return -EINVAL; fpi = kzalloc(sizeof(*fpi), GFP_KERNEL); if (!fpi) return -ENOMEM; - if (!IS_FEC(ofdev->dev.of_match)) { + if (!IS_FEC(match)) { data = of_get_property(ofdev->dev.of_node, "fsl,cpm-command", &len); if (!data || len != 4) goto out_free_fpi; @@ -1049,7 +1052,7 @@ static int __devinit fs_enet_probe(struct platform_device *ofdev) fep->dev = &ofdev->dev; fep->ndev = ndev; fep->fpi = fpi; - fep->ops = ofdev->dev.of_match->data; + fep->ops = match->data; ret = fep->ops->setup_data(ndev); if (ret) diff --git a/drivers/net/fs_enet/mii-fec.c b/drivers/net/fs_enet/mii-fec.c index 7e840d3..6a2e150 100644 --- a/drivers/net/fs_enet/mii-fec.c +++ b/drivers/net/fs_enet/mii-fec.c @@ -101,17 +101,20 @@ static int fs_enet_fec_mii_reset(struct mii_bus *bus) return 0; } +static struct of_device_id fs_enet_mdio_fec_match[]; static int __devinit fs_enet_mdio_probe(struct platform_device *ofdev) { + const struct of_device_id *match; struct resource res; struct mii_bus *new_bus; struct fec_info *fec; int (*get_bus_freq)(struct device_node *); int ret = -ENOMEM, clock, speed; - if (!ofdev->dev.of_match) + match = of_match_device(fs_enet_mdio_fec_match, &ofdev->dev); + if (!match) return -EINVAL; - get_bus_freq = ofdev->dev.of_match->data; + get_bus_freq = match->data; new_bus = mdiobus_alloc(); if (!new_bus) diff --git a/drivers/net/sunhme.c b/drivers/net/sunhme.c index eb4f59f..bff2f79 100644 --- a/drivers/net/sunhme.c +++ b/drivers/net/sunhme.c @@ -3237,15 +3237,18 @@ static void happy_meal_pci_exit(void) #endif #ifdef CONFIG_SBUS +static const struct of_device_id hme_sbus_match[]; static int __devinit hme_sbus_probe(struct platform_device *op) { + const struct of_device_id *match; struct device_node *dp = op->dev.of_node; const char *model = of_get_property(dp, "model", NULL); int is_qfe; - if (!op->dev.of_match) + match = of_match_device(hme_sbus_match, &op->dev); + if (!match) return -EINVAL; - is_qfe = (op->dev.of_match->data != NULL); + is_qfe = (match->data != NULL); if (!is_qfe && model && !strcmp(model, "SUNW,sbus-qfe")) is_qfe = 1; diff --git a/drivers/scsi/qlogicpti.c b/drivers/scsi/qlogicpti.c index e2d45c9..9689d41c 100644 --- a/drivers/scsi/qlogicpti.c +++ b/drivers/scsi/qlogicpti.c @@ -1292,8 +1292,10 @@ static struct scsi_host_template qpti_template = { .use_clustering = ENABLE_CLUSTERING, }; +static const struct of_device_id qpti_match[]; static int __devinit qpti_sbus_probe(struct platform_device *op) { + const struct of_device_id *match; struct scsi_host_template *tpnt; struct device_node *dp = op->dev.of_node; struct Scsi_Host *host; @@ -1301,9 +1303,10 @@ static int __devinit qpti_sbus_probe(struct platform_device *op) static int nqptis; const char *fcode; - if (!op->dev.of_match) + match = of_match_device(qpti_match, &op->dev); + if (!match) return -EINVAL; - tpnt = op->dev.of_match->data; + tpnt = match->data; /* Sometimes Antares cards come up not completely * setup, and we get a report of a zero IRQ. diff --git a/drivers/tty/serial/of_serial.c b/drivers/tty/serial/of_serial.c index 0e8eec5..c911b24 100644 --- a/drivers/tty/serial/of_serial.c +++ b/drivers/tty/serial/of_serial.c @@ -80,14 +80,17 @@ static int __devinit of_platform_serial_setup(struct platform_device *ofdev, /* * Try to register a serial port */ +static struct of_device_id of_platform_serial_table[]; static int __devinit of_platform_serial_probe(struct platform_device *ofdev) { + const struct of_device_id *match; struct of_serial_info *info; struct uart_port port; int port_type; int ret; - if (!ofdev->dev.of_match) + match = of_match_device(of_platform_serial_table, &ofdev->dev); + if (!match) return -EINVAL; if (of_find_property(ofdev->dev.of_node, "used-by-rtas", NULL)) @@ -97,7 +100,7 @@ static int __devinit of_platform_serial_probe(struct platform_device *ofdev) if (info == NULL) return -ENOMEM; - port_type = (unsigned long)ofdev->dev.of_match->data; + port_type = (unsigned long)match->data; ret = of_platform_serial_setup(ofdev, port_type, &port); if (ret) goto out; diff --git a/drivers/usb/gadget/fsl_qe_udc.c b/drivers/usb/gadget/fsl_qe_udc.c index 36613b3..3a68e09 100644 --- a/drivers/usb/gadget/fsl_qe_udc.c +++ b/drivers/usb/gadget/fsl_qe_udc.c @@ -2539,15 +2539,18 @@ static void qe_udc_release(struct device *dev) } /* Driver probe functions */ +static const struct of_device_id qe_udc_match[]; static int __devinit qe_udc_probe(struct platform_device *ofdev) { + const struct of_device_id *match; struct device_node *np = ofdev->dev.of_node; struct qe_ep *ep; unsigned int ret = 0; unsigned int i; const void *prop; - if (!ofdev->dev.of_match) + match = of_match_device(qe_udc_match, &ofdev->dev); + if (!match) return -EINVAL; prop = of_get_property(np, "mode", NULL); @@ -2561,7 +2564,7 @@ static int __devinit qe_udc_probe(struct platform_device *ofdev) return -ENOMEM; } - udc_controller->soc_type = (unsigned long)ofdev->dev.of_match->data; + udc_controller->soc_type = (unsigned long)match->data; udc_controller->usb_regs = of_iomap(np, 0); if (!udc_controller->usb_regs) { ret = -ENOMEM; diff --git a/drivers/watchdog/mpc8xxx_wdt.c b/drivers/watchdog/mpc8xxx_wdt.c index 528bceb..eed5436f 100644 --- a/drivers/watchdog/mpc8xxx_wdt.c +++ b/drivers/watchdog/mpc8xxx_wdt.c @@ -185,17 +185,20 @@ static struct miscdevice mpc8xxx_wdt_miscdev = { .fops = &mpc8xxx_wdt_fops, }; +static const struct of_device_id mpc8xxx_wdt_match[]; static int __devinit mpc8xxx_wdt_probe(struct platform_device *ofdev) { int ret; + const struct of_device_id *match; struct device_node *np = ofdev->dev.of_node; struct mpc8xxx_wdt_type *wdt_type; u32 freq = fsl_get_sys_freq(); bool enabled; - if (!ofdev->dev.of_match) + match = of_match_device(mpc8xxx_wdt_match, &ofdev->dev); + if (!match) return -EINVAL; - wdt_type = ofdev->dev.of_match->data; + wdt_type = match->data; if (!freq || freq == -1) return -EINVAL; diff --git a/include/linux/device.h b/include/linux/device.h index ab8dfc0..d08399d 100644 --- a/include/linux/device.h +++ b/include/linux/device.h @@ -442,7 +442,6 @@ struct device { struct dev_archdata archdata; struct device_node *of_node; /* associated device tree node */ - const struct of_device_id *of_match; /* matching of_device_id from driver */ dev_t devt; /* dev_t, creates the sysfs "dev" */ diff --git a/include/linux/of_device.h b/include/linux/of_device.h index b33d688..ae56384 100644 --- a/include/linux/of_device.h +++ b/include/linux/of_device.h @@ -21,12 +21,7 @@ extern void of_device_make_bus_id(struct device *dev); static inline int of_driver_match_device(struct device *dev, const struct device_driver *drv) { - const struct of_device_id *match; - - match = of_match_device(drv->of_match_table, dev); - if (match) - dev->of_match = match; - return match != NULL; + return of_match_device(drv->of_match_table, dev) != NULL; } extern struct platform_device *of_dev_get(struct platform_device *dev); @@ -62,6 +57,11 @@ static inline int of_device_uevent(struct device *dev, static inline void of_device_node_put(struct device *dev) { } +static inline const struct of_device_id *of_match_device( + const struct of_device_id *matches, const struct device *dev) +{ + return NULL; +} #endif /* CONFIG_OF_DEVICE */ #endif /* _LINUX_OF_DEVICE_H */ -- cgit v0.10.2 From b313207286a78abac19f1dd2721292eae598b0f5 Mon Sep 17 00:00:00 2001 From: Ingo Molnar Date: Wed, 18 May 2011 21:00:44 +0200 Subject: perf bench, x86: Add alternatives-asm.h wrapper perf bench needs this to build the kernel's memcpy routine: In file included from bench/mem-memcpy-x86-64-asm.S:2:0: bench/../../../arch/x86/lib/memcpy_64.S:7:33: fatal error: asm/alternative-asm.h: No such file or directory Cc: Peter Zijlstra Cc: Arnaldo Carvalho de Melo Cc: Frederic Weisbecker Cc: Mike Galbraith Cc: Steven Rostedt Link: http://lkml.kernel.org/n/tip-c5d41xibgullk8h2280q4gv0@git.kernel.org Signed-off-by: Ingo Molnar diff --git a/tools/perf/util/include/asm/alternative-asm.h b/tools/perf/util/include/asm/alternative-asm.h new file mode 100644 index 0000000..6789d788 --- /dev/null +++ b/tools/perf/util/include/asm/alternative-asm.h @@ -0,0 +1,8 @@ +#ifndef _PERF_ASM_ALTERNATIVE_ASM_H +#define _PERF_ASM_ALTERNATIVE_ASM_H + +/* Just disable it so we can build arch/x86/lib/memcpy_64.S for perf bench: */ + +#define altinstruction_entry # + +#endif -- cgit v0.10.2 From b448c4e3ae6d20108dba1d7833f2c0d3dbad87ce Mon Sep 17 00:00:00 2001 From: Steven Rostedt Date: Fri, 29 Apr 2011 15:12:32 -0400 Subject: ftrace: Replace FTRACE_FL_NOTRACE flag with a hash of ignored functions To prepare for the accounting system that will allow multiple users of the function tracer, having the FTRACE_FL_NOTRACE as a flag in the dyn_trace record does not make sense. All ftrace_ops will soon have a hash of functions they should trace and not trace. By making a global hash of functions not to trace makes this easier for the transition. Signed-off-by: Steven Rostedt diff --git a/include/linux/ftrace.h b/include/linux/ftrace.h index 3204744..fe0a90a 100644 --- a/include/linux/ftrace.h +++ b/include/linux/ftrace.h @@ -149,7 +149,6 @@ enum { FTRACE_FL_FREE = (1 << 0), FTRACE_FL_FILTER = (1 << 1), FTRACE_FL_ENABLED = (1 << 2), - FTRACE_FL_NOTRACE = (1 << 3), }; struct dyn_ftrace { diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c index d340634..04c002a 100644 --- a/kernel/trace/ftrace.c +++ b/kernel/trace/ftrace.c @@ -57,6 +57,7 @@ /* hash bits for specific function selection */ #define FTRACE_HASH_BITS 7 #define FTRACE_FUNC_HASHSIZE (1 << FTRACE_HASH_BITS) +#define FTRACE_HASH_MAX_BITS 10 /* ftrace_enabled is a method to turn ftrace on or off */ int ftrace_enabled __read_mostly; @@ -865,6 +866,22 @@ enum { FTRACE_START_FUNC_RET = (1 << 3), FTRACE_STOP_FUNC_RET = (1 << 4), }; +struct ftrace_func_entry { + struct hlist_node hlist; + unsigned long ip; +}; + +struct ftrace_hash { + unsigned long size_bits; + struct hlist_head *buckets; + unsigned long count; +}; + +static struct hlist_head notrace_buckets[1 << FTRACE_HASH_MAX_BITS]; +static struct ftrace_hash notrace_hash = { + .size_bits = FTRACE_HASH_MAX_BITS, + .buckets = notrace_buckets, +}; static int ftrace_filtered; @@ -889,6 +906,79 @@ static struct ftrace_page *ftrace_pages; static struct dyn_ftrace *ftrace_free_records; +static struct ftrace_func_entry * +ftrace_lookup_ip(struct ftrace_hash *hash, unsigned long ip) +{ + unsigned long key; + struct ftrace_func_entry *entry; + struct hlist_head *hhd; + struct hlist_node *n; + + if (!hash->count) + return NULL; + + if (hash->size_bits > 0) + key = hash_long(ip, hash->size_bits); + else + key = 0; + + hhd = &hash->buckets[key]; + + hlist_for_each_entry_rcu(entry, n, hhd, hlist) { + if (entry->ip == ip) + return entry; + } + return NULL; +} + +static int add_hash_entry(struct ftrace_hash *hash, unsigned long ip) +{ + struct ftrace_func_entry *entry; + struct hlist_head *hhd; + unsigned long key; + + entry = kmalloc(sizeof(*entry), GFP_KERNEL); + if (!entry) + return -ENOMEM; + + if (hash->size_bits) + key = hash_long(ip, hash->size_bits); + else + key = 0; + + entry->ip = ip; + hhd = &hash->buckets[key]; + hlist_add_head(&entry->hlist, hhd); + hash->count++; + + return 0; +} + +static void +remove_hash_entry(struct ftrace_hash *hash, + struct ftrace_func_entry *entry) +{ + hlist_del(&entry->hlist); + kfree(entry); + hash->count--; +} + +static void ftrace_hash_clear(struct ftrace_hash *hash) +{ + struct hlist_head *hhd; + struct hlist_node *tp, *tn; + struct ftrace_func_entry *entry; + int size = 1 << hash->size_bits; + int i; + + for (i = 0; i < size; i++) { + hhd = &hash->buckets[i]; + hlist_for_each_entry_safe(entry, tp, tn, hhd, hlist) + remove_hash_entry(hash, entry); + } + FTRACE_WARN_ON(hash->count); +} + /* * This is a double for. Do not use 'break' to break out of the loop, * you must use a goto. @@ -1032,7 +1122,7 @@ __ftrace_replace_code(struct dyn_ftrace *rec, int enable) * If we want to enable it and filtering is on, enable it only if * it's filtered */ - if (enable && !(rec->flags & FTRACE_FL_NOTRACE)) { + if (enable && !ftrace_lookup_ip(¬race_hash, rec->ip)) { if (!ftrace_filtered || (rec->flags & FTRACE_FL_FILTER)) flag = FTRACE_FL_ENABLED; } @@ -1465,7 +1555,7 @@ t_next(struct seq_file *m, void *v, loff_t *pos) !(rec->flags & FTRACE_FL_FILTER)) || ((iter->flags & FTRACE_ITER_NOTRACE) && - !(rec->flags & FTRACE_FL_NOTRACE))) { + !ftrace_lookup_ip(¬race_hash, rec->ip))) { rec = NULL; goto retry; } @@ -1609,14 +1699,15 @@ static void ftrace_filter_reset(int enable) { struct ftrace_page *pg; struct dyn_ftrace *rec; - unsigned long type = enable ? FTRACE_FL_FILTER : FTRACE_FL_NOTRACE; mutex_lock(&ftrace_lock); - if (enable) + if (enable) { ftrace_filtered = 0; - do_for_each_ftrace_rec(pg, rec) { - rec->flags &= ~type; - } while_for_each_ftrace_rec(); + do_for_each_ftrace_rec(pg, rec) { + rec->flags &= ~FTRACE_FL_FILTER; + } while_for_each_ftrace_rec(); + } else + ftrace_hash_clear(¬race_hash); mutex_unlock(&ftrace_lock); } @@ -1716,13 +1807,36 @@ static int ftrace_match(char *str, char *regex, int len, int type) return matched; } -static void -update_record(struct dyn_ftrace *rec, unsigned long flag, int not) +static int +update_record(struct dyn_ftrace *rec, int enable, int not) { - if (not) - rec->flags &= ~flag; - else - rec->flags |= flag; + struct ftrace_func_entry *entry; + struct ftrace_hash *hash = ¬race_hash; + int ret = 0; + + if (enable) { + if (not) + rec->flags &= ~FTRACE_FL_FILTER; + else + rec->flags |= FTRACE_FL_FILTER; + } else { + if (not) { + /* Do nothing if it doesn't exist */ + entry = ftrace_lookup_ip(hash, rec->ip); + if (!entry) + return 0; + + remove_hash_entry(hash, entry); + } else { + /* Do nothing if it exists */ + entry = ftrace_lookup_ip(hash, rec->ip); + if (entry) + return 0; + + ret = add_hash_entry(hash, rec->ip); + } + } + return ret; } static int @@ -1754,16 +1868,14 @@ static int match_records(char *buff, int len, char *mod, int enable, int not) struct dyn_ftrace *rec; int type = MATCH_FULL; char *search = buff; - unsigned long flag; int found = 0; + int ret; if (len) { type = filter_parse_regex(buff, len, &search, ¬); search_len = strlen(search); } - flag = enable ? FTRACE_FL_FILTER : FTRACE_FL_NOTRACE; - mutex_lock(&ftrace_lock); if (unlikely(ftrace_disabled)) @@ -1772,7 +1884,11 @@ static int match_records(char *buff, int len, char *mod, int enable, int not) do_for_each_ftrace_rec(pg, rec) { if (ftrace_match_record(rec, mod, search, search_len, type)) { - update_record(rec, flag, not); + ret = update_record(rec, enable, not); + if (ret < 0) { + found = ret; + goto out_unlock; + } found = 1; } /* @@ -1821,6 +1937,7 @@ static int ftrace_mod_callback(char *func, char *cmd, char *param, int enable) { char *mod; + int ret = -EINVAL; /* * cmd == 'mod' because we only registered this func @@ -1832,15 +1949,19 @@ ftrace_mod_callback(char *func, char *cmd, char *param, int enable) /* we must have a module name */ if (!param) - return -EINVAL; + return ret; mod = strsep(¶m, ":"); if (!strlen(mod)) - return -EINVAL; + return ret; - if (ftrace_match_module_records(func, mod, enable)) - return 0; - return -EINVAL; + ret = ftrace_match_module_records(func, mod, enable); + if (!ret) + ret = -EINVAL; + if (ret < 0) + return ret; + + return 0; } static struct ftrace_func_command ftrace_mod_cmd = { @@ -2132,14 +2253,17 @@ static int ftrace_process_regex(char *buff, int len, int enable) { char *func, *command, *next = buff; struct ftrace_func_command *p; - int ret = -EINVAL; + int ret; func = strsep(&next, ":"); if (!next) { - if (ftrace_match_records(func, len, enable)) - return 0; - return ret; + ret = ftrace_match_records(func, len, enable); + if (!ret) + ret = -EINVAL; + if (ret < 0) + return ret; + return 0; } /* command found */ -- cgit v0.10.2 From 1cf41dd79993389b012e4542ab502ce36ae7343f Mon Sep 17 00:00:00 2001 From: Steven Rostedt Date: Fri, 29 Apr 2011 20:59:51 -0400 Subject: ftrace: Use hash instead for FTRACE_FL_FILTER When multiple users are allowed to have their own set of functions to trace, having the FTRACE_FL_FILTER flag will not be enough to handle the accounting of those users. Each user will need their own set of functions. Replace the FTRACE_FL_FILTER with a filter_hash instead. This is temporary until the rest of the function filtering accounting gets in. Signed-off-by: Steven Rostedt diff --git a/include/linux/ftrace.h b/include/linux/ftrace.h index fe0a90a..52fc5d4 100644 --- a/include/linux/ftrace.h +++ b/include/linux/ftrace.h @@ -147,8 +147,7 @@ extern int ftrace_text_reserved(void *start, void *end); enum { FTRACE_FL_FREE = (1 << 0), - FTRACE_FL_FILTER = (1 << 1), - FTRACE_FL_ENABLED = (1 << 2), + FTRACE_FL_ENABLED = (1 << 1), }; struct dyn_ftrace { diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c index 04c002a..222eca4 100644 --- a/kernel/trace/ftrace.c +++ b/kernel/trace/ftrace.c @@ -883,7 +883,11 @@ static struct ftrace_hash notrace_hash = { .buckets = notrace_buckets, }; -static int ftrace_filtered; +static struct hlist_head filter_buckets[1 << FTRACE_HASH_MAX_BITS]; +static struct ftrace_hash filter_hash = { + .size_bits = FTRACE_HASH_MAX_BITS, + .buckets = filter_buckets, +}; static struct dyn_ftrace *ftrace_new_addrs; @@ -1123,7 +1127,7 @@ __ftrace_replace_code(struct dyn_ftrace *rec, int enable) * it's filtered */ if (enable && !ftrace_lookup_ip(¬race_hash, rec->ip)) { - if (!ftrace_filtered || (rec->flags & FTRACE_FL_FILTER)) + if (!filter_hash.count || ftrace_lookup_ip(&filter_hash, rec->ip)) flag = FTRACE_FL_ENABLED; } @@ -1430,6 +1434,7 @@ struct ftrace_iterator { struct dyn_ftrace *func; struct ftrace_func_probe *probe; struct trace_parser parser; + struct ftrace_hash *hash; int hidx; int idx; unsigned flags; @@ -1552,7 +1557,7 @@ t_next(struct seq_file *m, void *v, loff_t *pos) if ((rec->flags & FTRACE_FL_FREE) || ((iter->flags & FTRACE_ITER_FILTER) && - !(rec->flags & FTRACE_FL_FILTER)) || + !(ftrace_lookup_ip(&filter_hash, rec->ip))) || ((iter->flags & FTRACE_ITER_NOTRACE) && !ftrace_lookup_ip(¬race_hash, rec->ip))) { @@ -1598,7 +1603,7 @@ static void *t_start(struct seq_file *m, loff_t *pos) * off, we can short cut and just print out that all * functions are enabled. */ - if (iter->flags & FTRACE_ITER_FILTER && !ftrace_filtered) { + if (iter->flags & FTRACE_ITER_FILTER && !filter_hash.count) { if (*pos > 0) return t_hash_start(m, pos); iter->flags |= FTRACE_ITER_PRINTALL; @@ -1695,24 +1700,16 @@ ftrace_avail_open(struct inode *inode, struct file *file) return ret; } -static void ftrace_filter_reset(int enable) +static void ftrace_filter_reset(struct ftrace_hash *hash) { - struct ftrace_page *pg; - struct dyn_ftrace *rec; - mutex_lock(&ftrace_lock); - if (enable) { - ftrace_filtered = 0; - do_for_each_ftrace_rec(pg, rec) { - rec->flags &= ~FTRACE_FL_FILTER; - } while_for_each_ftrace_rec(); - } else - ftrace_hash_clear(¬race_hash); + ftrace_hash_clear(hash); mutex_unlock(&ftrace_lock); } static int -ftrace_regex_open(struct inode *inode, struct file *file, int enable) +ftrace_regex_open(struct ftrace_hash *hash, int flag, + struct inode *inode, struct file *file) { struct ftrace_iterator *iter; int ret = 0; @@ -1729,15 +1726,16 @@ ftrace_regex_open(struct inode *inode, struct file *file, int enable) return -ENOMEM; } + iter->hash = hash; + mutex_lock(&ftrace_regex_lock); if ((file->f_mode & FMODE_WRITE) && (file->f_flags & O_TRUNC)) - ftrace_filter_reset(enable); + ftrace_filter_reset(hash); if (file->f_mode & FMODE_READ) { iter->pg = ftrace_pages_start; - iter->flags = enable ? FTRACE_ITER_FILTER : - FTRACE_ITER_NOTRACE; + iter->flags = flag; ret = seq_open(file, &show_ftrace_seq_ops); if (!ret) { @@ -1757,13 +1755,15 @@ ftrace_regex_open(struct inode *inode, struct file *file, int enable) static int ftrace_filter_open(struct inode *inode, struct file *file) { - return ftrace_regex_open(inode, file, 1); + return ftrace_regex_open(&filter_hash, FTRACE_ITER_FILTER, + inode, file); } static int ftrace_notrace_open(struct inode *inode, struct file *file) { - return ftrace_regex_open(inode, file, 0); + return ftrace_regex_open(¬race_hash, FTRACE_ITER_NOTRACE, + inode, file); } static loff_t @@ -1808,33 +1808,24 @@ static int ftrace_match(char *str, char *regex, int len, int type) } static int -update_record(struct dyn_ftrace *rec, int enable, int not) +enter_record(struct ftrace_hash *hash, struct dyn_ftrace *rec, int not) { struct ftrace_func_entry *entry; - struct ftrace_hash *hash = ¬race_hash; int ret = 0; - if (enable) { - if (not) - rec->flags &= ~FTRACE_FL_FILTER; - else - rec->flags |= FTRACE_FL_FILTER; - } else { - if (not) { - /* Do nothing if it doesn't exist */ - entry = ftrace_lookup_ip(hash, rec->ip); - if (!entry) - return 0; + entry = ftrace_lookup_ip(hash, rec->ip); + if (not) { + /* Do nothing if it doesn't exist */ + if (!entry) + return 0; - remove_hash_entry(hash, entry); - } else { - /* Do nothing if it exists */ - entry = ftrace_lookup_ip(hash, rec->ip); - if (entry) - return 0; + remove_hash_entry(hash, entry); + } else { + /* Do nothing if it exists */ + if (entry) + return 0; - ret = add_hash_entry(hash, rec->ip); - } + ret = add_hash_entry(hash, rec->ip); } return ret; } @@ -1861,7 +1852,9 @@ ftrace_match_record(struct dyn_ftrace *rec, char *mod, return ftrace_match(str, regex, len, type); } -static int match_records(char *buff, int len, char *mod, int enable, int not) +static int +match_records(struct ftrace_hash *hash, char *buff, + int len, char *mod, int not) { unsigned search_len = 0; struct ftrace_page *pg; @@ -1884,20 +1877,13 @@ static int match_records(char *buff, int len, char *mod, int enable, int not) do_for_each_ftrace_rec(pg, rec) { if (ftrace_match_record(rec, mod, search, search_len, type)) { - ret = update_record(rec, enable, not); + ret = enter_record(hash, rec, not); if (ret < 0) { found = ret; goto out_unlock; } found = 1; } - /* - * Only enable filtering if we have a function that - * is filtered on. - */ - if (enable && (rec->flags & FTRACE_FL_FILTER)) - ftrace_filtered = 1; - } while_for_each_ftrace_rec(); out_unlock: mutex_unlock(&ftrace_lock); @@ -1906,12 +1892,13 @@ static int match_records(char *buff, int len, char *mod, int enable, int not) } static int -ftrace_match_records(char *buff, int len, int enable) +ftrace_match_records(struct ftrace_hash *hash, char *buff, int len) { - return match_records(buff, len, NULL, enable, 0); + return match_records(hash, buff, len, NULL, 0); } -static int ftrace_match_module_records(char *buff, char *mod, int enable) +static int +ftrace_match_module_records(struct ftrace_hash *hash, char *buff, char *mod) { int not = 0; @@ -1925,7 +1912,7 @@ static int ftrace_match_module_records(char *buff, char *mod, int enable) not = 1; } - return match_records(buff, strlen(buff), mod, enable, not); + return match_records(hash, buff, strlen(buff), mod, not); } /* @@ -1936,6 +1923,7 @@ static int ftrace_match_module_records(char *buff, char *mod, int enable) static int ftrace_mod_callback(char *func, char *cmd, char *param, int enable) { + struct ftrace_hash *hash; char *mod; int ret = -EINVAL; @@ -1955,7 +1943,12 @@ ftrace_mod_callback(char *func, char *cmd, char *param, int enable) if (!strlen(mod)) return ret; - ret = ftrace_match_module_records(func, mod, enable); + if (enable) + hash = &filter_hash; + else + hash = ¬race_hash; + + ret = ftrace_match_module_records(hash, func, mod); if (!ret) ret = -EINVAL; if (ret < 0) @@ -2253,12 +2246,18 @@ static int ftrace_process_regex(char *buff, int len, int enable) { char *func, *command, *next = buff; struct ftrace_func_command *p; + struct ftrace_hash *hash; int ret; + if (enable) + hash = &filter_hash; + else + hash = ¬race_hash; + func = strsep(&next, ":"); if (!next) { - ret = ftrace_match_records(func, len, enable); + ret = ftrace_match_records(hash, func, len); if (!ret) ret = -EINVAL; if (ret < 0) @@ -2340,16 +2339,16 @@ ftrace_notrace_write(struct file *file, const char __user *ubuf, } static void -ftrace_set_regex(unsigned char *buf, int len, int reset, int enable) +ftrace_set_regex(struct ftrace_hash *hash, unsigned char *buf, int len, int reset) { if (unlikely(ftrace_disabled)) return; mutex_lock(&ftrace_regex_lock); if (reset) - ftrace_filter_reset(enable); + ftrace_filter_reset(hash); if (buf) - ftrace_match_records(buf, len, enable); + ftrace_match_records(hash, buf, len); mutex_unlock(&ftrace_regex_lock); } @@ -2364,7 +2363,7 @@ ftrace_set_regex(unsigned char *buf, int len, int reset, int enable) */ void ftrace_set_filter(unsigned char *buf, int len, int reset) { - ftrace_set_regex(buf, len, reset, 1); + ftrace_set_regex(&filter_hash, buf, len, reset); } /** @@ -2379,7 +2378,7 @@ void ftrace_set_filter(unsigned char *buf, int len, int reset) */ void ftrace_set_notrace(unsigned char *buf, int len, int reset) { - ftrace_set_regex(buf, len, reset, 0); + ftrace_set_regex(¬race_hash, buf, len, reset); } /* @@ -2431,22 +2430,22 @@ static void __init set_ftrace_early_graph(char *buf) } #endif /* CONFIG_FUNCTION_GRAPH_TRACER */ -static void __init set_ftrace_early_filter(char *buf, int enable) +static void __init set_ftrace_early_filter(struct ftrace_hash *hash, char *buf) { char *func; while (buf) { func = strsep(&buf, ","); - ftrace_set_regex(func, strlen(func), 0, enable); + ftrace_set_regex(hash, func, strlen(func), 0); } } static void __init set_ftrace_early_filters(void) { if (ftrace_filter_buf[0]) - set_ftrace_early_filter(ftrace_filter_buf, 1); + set_ftrace_early_filter(&filter_hash, ftrace_filter_buf); if (ftrace_notrace_buf[0]) - set_ftrace_early_filter(ftrace_notrace_buf, 0); + set_ftrace_early_filter(¬race_hash, ftrace_notrace_buf); #ifdef CONFIG_FUNCTION_GRAPH_TRACER if (ftrace_graph_buf[0]) set_ftrace_early_graph(ftrace_graph_buf); @@ -2454,7 +2453,7 @@ static void __init set_ftrace_early_filters(void) } static int -ftrace_regex_release(struct inode *inode, struct file *file, int enable) +ftrace_regex_release(struct inode *inode, struct file *file) { struct seq_file *m = (struct seq_file *)file->private_data; struct ftrace_iterator *iter; @@ -2471,7 +2470,7 @@ ftrace_regex_release(struct inode *inode, struct file *file, int enable) parser = &iter->parser; if (trace_parser_loaded(parser)) { parser->buffer[parser->idx] = 0; - ftrace_match_records(parser->buffer, parser->idx, enable); + ftrace_match_records(iter->hash, parser->buffer, parser->idx); } trace_parser_put(parser); @@ -2488,18 +2487,6 @@ ftrace_regex_release(struct inode *inode, struct file *file, int enable) return 0; } -static int -ftrace_filter_release(struct inode *inode, struct file *file) -{ - return ftrace_regex_release(inode, file, 1); -} - -static int -ftrace_notrace_release(struct inode *inode, struct file *file) -{ - return ftrace_regex_release(inode, file, 0); -} - static const struct file_operations ftrace_avail_fops = { .open = ftrace_avail_open, .read = seq_read, @@ -2512,7 +2499,7 @@ static const struct file_operations ftrace_filter_fops = { .read = seq_read, .write = ftrace_filter_write, .llseek = ftrace_regex_lseek, - .release = ftrace_filter_release, + .release = ftrace_regex_release, }; static const struct file_operations ftrace_notrace_fops = { @@ -2520,7 +2507,7 @@ static const struct file_operations ftrace_notrace_fops = { .read = seq_read, .write = ftrace_notrace_write, .llseek = ftrace_regex_lseek, - .release = ftrace_notrace_release, + .release = ftrace_regex_release, }; #ifdef CONFIG_FUNCTION_GRAPH_TRACER -- cgit v0.10.2 From f45948e898e7bc76a73a468796d2ce80dd040058 Mon Sep 17 00:00:00 2001 From: Steven Rostedt Date: Mon, 2 May 2011 12:29:25 -0400 Subject: ftrace: Create a global_ops to hold the filter and notrace hashes Combine the filter and notrace hashes to be accessed by a single entity, the global_ops. The global_ops is a ftrace_ops structure that is passed to different functions that can read or modify the filtering of the function tracer. The ftrace_ops structure was modified to hold a filter and notrace hashes so that later patches may allow each ftrace_ops to have its own set of rules to what functions may be filtered. Signed-off-by: Steven Rostedt diff --git a/include/linux/ftrace.h b/include/linux/ftrace.h index 52fc5d4..6658a51 100644 --- a/include/linux/ftrace.h +++ b/include/linux/ftrace.h @@ -29,9 +29,15 @@ ftrace_enable_sysctl(struct ctl_table *table, int write, typedef void (*ftrace_func_t)(unsigned long ip, unsigned long parent_ip); +struct ftrace_hash; + struct ftrace_ops { - ftrace_func_t func; - struct ftrace_ops *next; + ftrace_func_t func; + struct ftrace_ops *next; +#ifdef CONFIG_DYNAMIC_FTRACE + struct ftrace_hash *notrace_hash; + struct ftrace_hash *filter_hash; +#endif }; extern int function_trace_stop; diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c index 222eca4..a517a6c 100644 --- a/kernel/trace/ftrace.c +++ b/kernel/trace/ftrace.c @@ -889,6 +889,12 @@ static struct ftrace_hash filter_hash = { .buckets = filter_buckets, }; +struct ftrace_ops global_ops = { + .func = ftrace_stub, + .notrace_hash = ¬race_hash, + .filter_hash = &filter_hash, +}; + static struct dyn_ftrace *ftrace_new_addrs; static DEFINE_MUTEX(ftrace_regex_lock); @@ -1112,6 +1118,7 @@ int ftrace_text_reserved(void *start, void *end) static int __ftrace_replace_code(struct dyn_ftrace *rec, int enable) { + struct ftrace_ops *ops = &global_ops; unsigned long ftrace_addr; unsigned long flag = 0UL; @@ -1126,8 +1133,9 @@ __ftrace_replace_code(struct dyn_ftrace *rec, int enable) * If we want to enable it and filtering is on, enable it only if * it's filtered */ - if (enable && !ftrace_lookup_ip(¬race_hash, rec->ip)) { - if (!filter_hash.count || ftrace_lookup_ip(&filter_hash, rec->ip)) + if (enable && !ftrace_lookup_ip(ops->notrace_hash, rec->ip)) { + if (!ops->filter_hash->count || + ftrace_lookup_ip(ops->filter_hash, rec->ip)) flag = FTRACE_FL_ENABLED; } @@ -1531,6 +1539,7 @@ static void * t_next(struct seq_file *m, void *v, loff_t *pos) { struct ftrace_iterator *iter = m->private; + struct ftrace_ops *ops = &global_ops; struct dyn_ftrace *rec = NULL; if (unlikely(ftrace_disabled)) @@ -1557,10 +1566,10 @@ t_next(struct seq_file *m, void *v, loff_t *pos) if ((rec->flags & FTRACE_FL_FREE) || ((iter->flags & FTRACE_ITER_FILTER) && - !(ftrace_lookup_ip(&filter_hash, rec->ip))) || + !(ftrace_lookup_ip(ops->filter_hash, rec->ip))) || ((iter->flags & FTRACE_ITER_NOTRACE) && - !ftrace_lookup_ip(¬race_hash, rec->ip))) { + !ftrace_lookup_ip(ops->notrace_hash, rec->ip))) { rec = NULL; goto retry; } @@ -1584,6 +1593,7 @@ static void reset_iter_read(struct ftrace_iterator *iter) static void *t_start(struct seq_file *m, loff_t *pos) { struct ftrace_iterator *iter = m->private; + struct ftrace_ops *ops = &global_ops; void *p = NULL; loff_t l; @@ -1603,7 +1613,7 @@ static void *t_start(struct seq_file *m, loff_t *pos) * off, we can short cut and just print out that all * functions are enabled. */ - if (iter->flags & FTRACE_ITER_FILTER && !filter_hash.count) { + if (iter->flags & FTRACE_ITER_FILTER && !ops->filter_hash->count) { if (*pos > 0) return t_hash_start(m, pos); iter->flags |= FTRACE_ITER_PRINTALL; @@ -1708,10 +1718,11 @@ static void ftrace_filter_reset(struct ftrace_hash *hash) } static int -ftrace_regex_open(struct ftrace_hash *hash, int flag, +ftrace_regex_open(struct ftrace_ops *ops, int flag, struct inode *inode, struct file *file) { struct ftrace_iterator *iter; + struct ftrace_hash *hash; int ret = 0; if (unlikely(ftrace_disabled)) @@ -1726,6 +1737,11 @@ ftrace_regex_open(struct ftrace_hash *hash, int flag, return -ENOMEM; } + if (flag & FTRACE_ITER_NOTRACE) + hash = ops->notrace_hash; + else + hash = ops->filter_hash; + iter->hash = hash; mutex_lock(&ftrace_regex_lock); @@ -1755,14 +1771,14 @@ ftrace_regex_open(struct ftrace_hash *hash, int flag, static int ftrace_filter_open(struct inode *inode, struct file *file) { - return ftrace_regex_open(&filter_hash, FTRACE_ITER_FILTER, + return ftrace_regex_open(&global_ops, FTRACE_ITER_FILTER, inode, file); } static int ftrace_notrace_open(struct inode *inode, struct file *file) { - return ftrace_regex_open(¬race_hash, FTRACE_ITER_NOTRACE, + return ftrace_regex_open(&global_ops, FTRACE_ITER_NOTRACE, inode, file); } @@ -1923,6 +1939,7 @@ ftrace_match_module_records(struct ftrace_hash *hash, char *buff, char *mod) static int ftrace_mod_callback(char *func, char *cmd, char *param, int enable) { + struct ftrace_ops *ops = &global_ops; struct ftrace_hash *hash; char *mod; int ret = -EINVAL; @@ -1944,9 +1961,9 @@ ftrace_mod_callback(char *func, char *cmd, char *param, int enable) return ret; if (enable) - hash = &filter_hash; + hash = ops->filter_hash; else - hash = ¬race_hash; + hash = ops->notrace_hash; ret = ftrace_match_module_records(hash, func, mod); if (!ret) @@ -2245,14 +2262,15 @@ int unregister_ftrace_command(struct ftrace_func_command *cmd) static int ftrace_process_regex(char *buff, int len, int enable) { char *func, *command, *next = buff; + struct ftrace_ops *ops = &global_ops; struct ftrace_func_command *p; struct ftrace_hash *hash; int ret; if (enable) - hash = &filter_hash; + hash = ops->filter_hash; else - hash = ¬race_hash; + hash = ops->notrace_hash; func = strsep(&next, ":"); @@ -2339,11 +2357,19 @@ ftrace_notrace_write(struct file *file, const char __user *ubuf, } static void -ftrace_set_regex(struct ftrace_hash *hash, unsigned char *buf, int len, int reset) +ftrace_set_regex(struct ftrace_ops *ops, unsigned char *buf, int len, + int reset, int enable) { + struct ftrace_hash *hash; + if (unlikely(ftrace_disabled)) return; + if (enable) + hash = ops->filter_hash; + else + hash = ops->notrace_hash; + mutex_lock(&ftrace_regex_lock); if (reset) ftrace_filter_reset(hash); @@ -2363,7 +2389,7 @@ ftrace_set_regex(struct ftrace_hash *hash, unsigned char *buf, int len, int rese */ void ftrace_set_filter(unsigned char *buf, int len, int reset) { - ftrace_set_regex(&filter_hash, buf, len, reset); + ftrace_set_regex(&global_ops, buf, len, reset, 1); } /** @@ -2378,7 +2404,7 @@ void ftrace_set_filter(unsigned char *buf, int len, int reset) */ void ftrace_set_notrace(unsigned char *buf, int len, int reset) { - ftrace_set_regex(¬race_hash, buf, len, reset); + ftrace_set_regex(&global_ops, buf, len, reset, 0); } /* @@ -2430,22 +2456,23 @@ static void __init set_ftrace_early_graph(char *buf) } #endif /* CONFIG_FUNCTION_GRAPH_TRACER */ -static void __init set_ftrace_early_filter(struct ftrace_hash *hash, char *buf) +static void __init +set_ftrace_early_filter(struct ftrace_ops *ops, char *buf, int enable) { char *func; while (buf) { func = strsep(&buf, ","); - ftrace_set_regex(hash, func, strlen(func), 0); + ftrace_set_regex(ops, func, strlen(func), 0, enable); } } static void __init set_ftrace_early_filters(void) { if (ftrace_filter_buf[0]) - set_ftrace_early_filter(&filter_hash, ftrace_filter_buf); + set_ftrace_early_filter(&global_ops, ftrace_filter_buf, 1); if (ftrace_notrace_buf[0]) - set_ftrace_early_filter(¬race_hash, ftrace_notrace_buf); + set_ftrace_early_filter(&global_ops, ftrace_notrace_buf, 0); #ifdef CONFIG_FUNCTION_GRAPH_TRACER if (ftrace_graph_buf[0]) set_ftrace_early_graph(ftrace_graph_buf); -- cgit v0.10.2 From 33dc9b1267d59cef46ff0bd6bc043190845dc919 Mon Sep 17 00:00:00 2001 From: Steven Rostedt Date: Mon, 2 May 2011 17:34:47 -0400 Subject: ftrace: Separate hash allocation and assignment When filtering, allocate a hash to insert the function records. After the filtering is complete, assign it to the ftrace_ops structure. This allows the ftrace_ops structure to have a much smaller array of hash buckets instead of wasting a lot of memory. A read only empty_hash is created to be the minimum size that any ftrace_ops can point to. When a new hash is created, it has the following steps: o Allocate a default hash. o Walk the function records assigning the filtered records to the hash o Allocate a new hash with the appropriate size buckets o Move the entries from the default hash to the new hash. Signed-off-by: Steven Rostedt diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c index a517a6c..46f0826 100644 --- a/kernel/trace/ftrace.c +++ b/kernel/trace/ftrace.c @@ -57,7 +57,8 @@ /* hash bits for specific function selection */ #define FTRACE_HASH_BITS 7 #define FTRACE_FUNC_HASHSIZE (1 << FTRACE_HASH_BITS) -#define FTRACE_HASH_MAX_BITS 10 +#define FTRACE_HASH_DEFAULT_BITS 10 +#define FTRACE_HASH_MAX_BITS 12 /* ftrace_enabled is a method to turn ftrace on or off */ int ftrace_enabled __read_mostly; @@ -877,22 +878,22 @@ struct ftrace_hash { unsigned long count; }; -static struct hlist_head notrace_buckets[1 << FTRACE_HASH_MAX_BITS]; -static struct ftrace_hash notrace_hash = { - .size_bits = FTRACE_HASH_MAX_BITS, - .buckets = notrace_buckets, -}; - -static struct hlist_head filter_buckets[1 << FTRACE_HASH_MAX_BITS]; -static struct ftrace_hash filter_hash = { - .size_bits = FTRACE_HASH_MAX_BITS, - .buckets = filter_buckets, +/* + * We make these constant because no one should touch them, + * but they are used as the default "empty hash", to avoid allocating + * it all the time. These are in a read only section such that if + * anyone does try to modify it, it will cause an exception. + */ +static const struct hlist_head empty_buckets[1]; +static const struct ftrace_hash empty_hash = { + .buckets = (struct hlist_head *)empty_buckets, }; +#define EMPTY_HASH ((struct ftrace_hash *)&empty_hash) struct ftrace_ops global_ops = { .func = ftrace_stub, - .notrace_hash = ¬race_hash, - .filter_hash = &filter_hash, + .notrace_hash = EMPTY_HASH, + .filter_hash = EMPTY_HASH, }; static struct dyn_ftrace *ftrace_new_addrs; @@ -941,31 +942,38 @@ ftrace_lookup_ip(struct ftrace_hash *hash, unsigned long ip) return NULL; } -static int add_hash_entry(struct ftrace_hash *hash, unsigned long ip) +static void __add_hash_entry(struct ftrace_hash *hash, + struct ftrace_func_entry *entry) { - struct ftrace_func_entry *entry; struct hlist_head *hhd; unsigned long key; - entry = kmalloc(sizeof(*entry), GFP_KERNEL); - if (!entry) - return -ENOMEM; - if (hash->size_bits) - key = hash_long(ip, hash->size_bits); + key = hash_long(entry->ip, hash->size_bits); else key = 0; - entry->ip = ip; hhd = &hash->buckets[key]; hlist_add_head(&entry->hlist, hhd); hash->count++; +} + +static int add_hash_entry(struct ftrace_hash *hash, unsigned long ip) +{ + struct ftrace_func_entry *entry; + + entry = kmalloc(sizeof(*entry), GFP_KERNEL); + if (!entry) + return -ENOMEM; + + entry->ip = ip; + __add_hash_entry(hash, entry); return 0; } static void -remove_hash_entry(struct ftrace_hash *hash, +free_hash_entry(struct ftrace_hash *hash, struct ftrace_func_entry *entry) { hlist_del(&entry->hlist); @@ -973,6 +981,14 @@ remove_hash_entry(struct ftrace_hash *hash, hash->count--; } +static void +remove_hash_entry(struct ftrace_hash *hash, + struct ftrace_func_entry *entry) +{ + hlist_del(&entry->hlist); + hash->count--; +} + static void ftrace_hash_clear(struct ftrace_hash *hash) { struct hlist_head *hhd; @@ -981,14 +997,156 @@ static void ftrace_hash_clear(struct ftrace_hash *hash) int size = 1 << hash->size_bits; int i; + if (!hash->count) + return; + for (i = 0; i < size; i++) { hhd = &hash->buckets[i]; hlist_for_each_entry_safe(entry, tp, tn, hhd, hlist) - remove_hash_entry(hash, entry); + free_hash_entry(hash, entry); } FTRACE_WARN_ON(hash->count); } +static void free_ftrace_hash(struct ftrace_hash *hash) +{ + if (!hash || hash == EMPTY_HASH) + return; + ftrace_hash_clear(hash); + kfree(hash->buckets); + kfree(hash); +} + +static struct ftrace_hash *alloc_ftrace_hash(int size_bits) +{ + struct ftrace_hash *hash; + int size; + + hash = kzalloc(sizeof(*hash), GFP_KERNEL); + if (!hash) + return NULL; + + size = 1 << size_bits; + hash->buckets = kzalloc(sizeof(*hash->buckets) * size, GFP_KERNEL); + + if (!hash->buckets) { + kfree(hash); + return NULL; + } + + hash->size_bits = size_bits; + + return hash; +} + +static struct ftrace_hash * +alloc_and_copy_ftrace_hash(int size_bits, struct ftrace_hash *hash) +{ + struct ftrace_func_entry *entry; + struct ftrace_hash *new_hash; + struct hlist_node *tp; + int size; + int ret; + int i; + + new_hash = alloc_ftrace_hash(size_bits); + if (!new_hash) + return NULL; + + /* Empty hash? */ + if (!hash || !hash->count) + return new_hash; + + size = 1 << hash->size_bits; + for (i = 0; i < size; i++) { + hlist_for_each_entry(entry, tp, &hash->buckets[i], hlist) { + ret = add_hash_entry(new_hash, entry->ip); + if (ret < 0) + goto free_hash; + } + } + + FTRACE_WARN_ON(new_hash->count != hash->count); + + return new_hash; + + free_hash: + free_ftrace_hash(new_hash); + return NULL; +} + +static int +ftrace_hash_move(struct ftrace_hash **dst, struct ftrace_hash *src) +{ + struct ftrace_func_entry *entry; + struct hlist_node *tp, *tn; + struct hlist_head *hhd; + struct ftrace_hash *hash = *dst; + unsigned long key; + int size = src->count; + int bits = 0; + int i; + + /* + * If the new source is empty, just free dst and assign it + * the empty_hash. + */ + if (!src->count) { + free_ftrace_hash(*dst); + *dst = EMPTY_HASH; + return 0; + } + + ftrace_hash_clear(hash); + + /* + * Make the hash size about 1/2 the # found + */ + for (size /= 2; size; size >>= 1) + bits++; + + /* Don't allocate too much */ + if (bits > FTRACE_HASH_MAX_BITS) + bits = FTRACE_HASH_MAX_BITS; + + /* We can't modify the empty_hash */ + if (hash == EMPTY_HASH) { + /* Create a new hash */ + *dst = alloc_ftrace_hash(bits); + if (!*dst) { + *dst = EMPTY_HASH; + return -ENOMEM; + } + hash = *dst; + } else { + size = 1 << bits; + + /* Use the old hash, but create new buckets */ + hhd = kzalloc(sizeof(*hhd) * size, GFP_KERNEL); + if (!hhd) + return -ENOMEM; + + kfree(hash->buckets); + hash->buckets = hhd; + hash->size_bits = bits; + } + + size = 1 << src->size_bits; + for (i = 0; i < size; i++) { + hhd = &src->buckets[i]; + hlist_for_each_entry_safe(entry, tp, tn, hhd, hlist) { + if (bits > 0) + key = hash_long(entry->ip, bits); + else + key = 0; + remove_hash_entry(src, entry); + __add_hash_entry(hash, entry); + } + } + + return 0; +} + /* * This is a double for. Do not use 'break' to break out of the loop, * you must use a goto. @@ -1443,6 +1601,7 @@ struct ftrace_iterator { struct ftrace_func_probe *probe; struct trace_parser parser; struct ftrace_hash *hash; + struct ftrace_ops *ops; int hidx; int idx; unsigned flags; @@ -1742,22 +1901,37 @@ ftrace_regex_open(struct ftrace_ops *ops, int flag, else hash = ops->filter_hash; - iter->hash = hash; + iter->ops = ops; + iter->flags = flag; + + if (file->f_mode & FMODE_WRITE) { + mutex_lock(&ftrace_lock); + iter->hash = alloc_and_copy_ftrace_hash(FTRACE_HASH_DEFAULT_BITS, hash); + mutex_unlock(&ftrace_lock); + + if (!iter->hash) { + trace_parser_put(&iter->parser); + kfree(iter); + return -ENOMEM; + } + } mutex_lock(&ftrace_regex_lock); + if ((file->f_mode & FMODE_WRITE) && (file->f_flags & O_TRUNC)) - ftrace_filter_reset(hash); + ftrace_filter_reset(iter->hash); if (file->f_mode & FMODE_READ) { iter->pg = ftrace_pages_start; - iter->flags = flag; ret = seq_open(file, &show_ftrace_seq_ops); if (!ret) { struct seq_file *m = file->private_data; m->private = iter; } else { + /* Failed */ + free_ftrace_hash(iter->hash); trace_parser_put(&iter->parser); kfree(iter); } @@ -1835,7 +2009,7 @@ enter_record(struct ftrace_hash *hash, struct dyn_ftrace *rec, int not) if (!entry) return 0; - remove_hash_entry(hash, entry); + free_hash_entry(hash, entry); } else { /* Do nothing if it exists */ if (entry) @@ -2259,19 +2433,13 @@ int unregister_ftrace_command(struct ftrace_func_command *cmd) return ret; } -static int ftrace_process_regex(char *buff, int len, int enable) +static int ftrace_process_regex(struct ftrace_hash *hash, + char *buff, int len, int enable) { char *func, *command, *next = buff; - struct ftrace_ops *ops = &global_ops; struct ftrace_func_command *p; - struct ftrace_hash *hash; int ret; - if (enable) - hash = ops->filter_hash; - else - hash = ops->notrace_hash; - func = strsep(&next, ":"); if (!next) { @@ -2328,7 +2496,7 @@ ftrace_regex_write(struct file *file, const char __user *ubuf, if (read >= 0 && trace_parser_loaded(parser) && !trace_parser_cont(parser)) { - ret = ftrace_process_regex(parser->buffer, + ret = ftrace_process_regex(iter->hash, parser->buffer, parser->idx, enable); trace_parser_clear(parser); if (ret) @@ -2356,26 +2524,40 @@ ftrace_notrace_write(struct file *file, const char __user *ubuf, return ftrace_regex_write(file, ubuf, cnt, ppos, 0); } -static void +static int ftrace_set_regex(struct ftrace_ops *ops, unsigned char *buf, int len, int reset, int enable) { + struct ftrace_hash **orig_hash; struct ftrace_hash *hash; + int ret; if (unlikely(ftrace_disabled)) - return; + return -ENODEV; if (enable) - hash = ops->filter_hash; + orig_hash = &ops->filter_hash; else - hash = ops->notrace_hash; + orig_hash = &ops->notrace_hash; + + hash = alloc_and_copy_ftrace_hash(FTRACE_HASH_DEFAULT_BITS, *orig_hash); + if (!hash) + return -ENOMEM; mutex_lock(&ftrace_regex_lock); if (reset) ftrace_filter_reset(hash); if (buf) ftrace_match_records(hash, buf, len); + + mutex_lock(&ftrace_lock); + ret = ftrace_hash_move(orig_hash, hash); + mutex_unlock(&ftrace_lock); + mutex_unlock(&ftrace_regex_lock); + + free_ftrace_hash(hash); + return ret; } /** @@ -2484,7 +2666,9 @@ ftrace_regex_release(struct inode *inode, struct file *file) { struct seq_file *m = (struct seq_file *)file->private_data; struct ftrace_iterator *iter; + struct ftrace_hash **orig_hash; struct trace_parser *parser; + int ret; mutex_lock(&ftrace_regex_lock); if (file->f_mode & FMODE_READ) { @@ -2501,14 +2685,21 @@ ftrace_regex_release(struct inode *inode, struct file *file) } trace_parser_put(parser); - kfree(iter); if (file->f_mode & FMODE_WRITE) { + if (iter->flags & FTRACE_ITER_NOTRACE) + orig_hash = &iter->ops->notrace_hash; + else + orig_hash = &iter->ops->filter_hash; + mutex_lock(&ftrace_lock); - if (ftrace_start_up && ftrace_enabled) + ret = ftrace_hash_move(orig_hash, iter->hash); + if (!ret && ftrace_start_up && ftrace_enabled) ftrace_run_update_code(FTRACE_ENABLE_CALLS); mutex_unlock(&ftrace_lock); } + free_ftrace_hash(iter->hash); + kfree(iter); mutex_unlock(&ftrace_regex_lock); return 0; -- cgit v0.10.2 From ed926f9b35cda0988234c356e16a7cb30f4e5338 Mon Sep 17 00:00:00 2001 From: Steven Rostedt Date: Tue, 3 May 2011 13:25:24 -0400 Subject: ftrace: Use counters to enable functions to trace Every function has its own record that stores the instruction pointer and flags for the function to be traced. There are only two flags: enabled and free. The enabled flag states that tracing for the function has been enabled (actively traced), and the free flag states that the record no longer points to a function and can be used by new functions (loaded modules). These flags are now moved to the MSB of the flags (actually just the top 32bits). The rest of the bits (30 bits) are now used as a ref counter. Everytime a tracer register functions to trace, those functions will have its counter incremented. When tracing is enabled, to determine if a function should be traced, the counter is examined, and if it is non-zero it is set to trace. When a ftrace_ops is registered to trace functions, its hashes are examined. If the ftrace_ops filter_hash count is zero, then all functions are set to be traced, otherwise only the functions in the hash are to be traced. The exception to this is if a function is also in the ftrace_ops notrace_hash. Then that function's counter is not incremented for this ftrace_ops. Signed-off-by: Steven Rostedt diff --git a/include/linux/ftrace.h b/include/linux/ftrace.h index 6658a51..ab1c46e 100644 --- a/include/linux/ftrace.h +++ b/include/linux/ftrace.h @@ -37,6 +37,7 @@ struct ftrace_ops { #ifdef CONFIG_DYNAMIC_FTRACE struct ftrace_hash *notrace_hash; struct ftrace_hash *filter_hash; + unsigned long flags; #endif }; @@ -152,10 +153,13 @@ extern void unregister_ftrace_function_probe_all(char *glob); extern int ftrace_text_reserved(void *start, void *end); enum { - FTRACE_FL_FREE = (1 << 0), - FTRACE_FL_ENABLED = (1 << 1), + FTRACE_FL_ENABLED = (1 << 30), + FTRACE_FL_FREE = (1 << 31), }; +#define FTRACE_FL_MASK (0x3UL << 30) +#define FTRACE_REF_MAX ((1 << 30) - 1) + struct dyn_ftrace { union { unsigned long ip; /* address of mcount call-site */ diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c index 46f0826..5dd332cc 100644 --- a/kernel/trace/ftrace.c +++ b/kernel/trace/ftrace.c @@ -890,6 +890,10 @@ static const struct ftrace_hash empty_hash = { }; #define EMPTY_HASH ((struct ftrace_hash *)&empty_hash) +enum { + FTRACE_OPS_FL_ENABLED = 1, +}; + struct ftrace_ops global_ops = { .func = ftrace_stub, .notrace_hash = EMPTY_HASH, @@ -1161,6 +1165,105 @@ ftrace_hash_move(struct ftrace_hash **dst, struct ftrace_hash *src) } \ } +static void __ftrace_hash_rec_update(struct ftrace_ops *ops, + int filter_hash, + bool inc) +{ + struct ftrace_hash *hash; + struct ftrace_hash *other_hash; + struct ftrace_page *pg; + struct dyn_ftrace *rec; + int count = 0; + int all = 0; + + /* Only update if the ops has been registered */ + if (!(ops->flags & FTRACE_OPS_FL_ENABLED)) + return; + + /* + * In the filter_hash case: + * If the count is zero, we update all records. + * Otherwise we just update the items in the hash. + * + * In the notrace_hash case: + * We enable the update in the hash. + * As disabling notrace means enabling the tracing, + * and enabling notrace means disabling, the inc variable + * gets inversed. + */ + if (filter_hash) { + hash = ops->filter_hash; + other_hash = ops->notrace_hash; + if (!hash->count) + all = 1; + } else { + inc = !inc; + hash = ops->notrace_hash; + other_hash = ops->filter_hash; + /* + * If the notrace hash has no items, + * then there's nothing to do. + */ + if (!hash->count) + return; + } + + do_for_each_ftrace_rec(pg, rec) { + int in_other_hash = 0; + int in_hash = 0; + int match = 0; + + if (all) { + /* + * Only the filter_hash affects all records. + * Update if the record is not in the notrace hash. + */ + if (!ftrace_lookup_ip(other_hash, rec->ip)) + match = 1; + } else { + in_hash = !!ftrace_lookup_ip(hash, rec->ip); + in_other_hash = !!ftrace_lookup_ip(other_hash, rec->ip); + + /* + * + */ + if (filter_hash && in_hash && !in_other_hash) + match = 1; + else if (!filter_hash && in_hash && + (in_other_hash || !other_hash->count)) + match = 1; + } + if (!match) + continue; + + if (inc) { + rec->flags++; + if (FTRACE_WARN_ON((rec->flags & ~FTRACE_FL_MASK) == FTRACE_REF_MAX)) + return; + } else { + if (FTRACE_WARN_ON((rec->flags & ~FTRACE_FL_MASK) == 0)) + return; + rec->flags--; + } + count++; + /* Shortcut, if we handled all records, we are done. */ + if (!all && count == hash->count) + return; + } while_for_each_ftrace_rec(); +} + +static void ftrace_hash_rec_disable(struct ftrace_ops *ops, + int filter_hash) +{ + __ftrace_hash_rec_update(ops, filter_hash, 0); +} + +static void ftrace_hash_rec_enable(struct ftrace_ops *ops, + int filter_hash) +{ + __ftrace_hash_rec_update(ops, filter_hash, 1); +} + static void ftrace_free_rec(struct dyn_ftrace *rec) { rec->freelist = ftrace_free_records; @@ -1276,26 +1379,24 @@ int ftrace_text_reserved(void *start, void *end) static int __ftrace_replace_code(struct dyn_ftrace *rec, int enable) { - struct ftrace_ops *ops = &global_ops; unsigned long ftrace_addr; unsigned long flag = 0UL; ftrace_addr = (unsigned long)FTRACE_ADDR; /* - * If this record is not to be traced or we want to disable it, - * then disable it. + * If we are enabling tracing: * - * If we want to enable it and filtering is off, then enable it. + * If the record has a ref count, then we need to enable it + * because someone is using it. * - * If we want to enable it and filtering is on, enable it only if - * it's filtered + * Otherwise we make sure its disabled. + * + * If we are disabling tracing, then disable all records that + * are enabled. */ - if (enable && !ftrace_lookup_ip(ops->notrace_hash, rec->ip)) { - if (!ops->filter_hash->count || - ftrace_lookup_ip(ops->filter_hash, rec->ip)) - flag = FTRACE_FL_ENABLED; - } + if (enable && (rec->flags & ~FTRACE_FL_MASK)) + flag = FTRACE_FL_ENABLED; /* If the state of this record hasn't changed, then do nothing */ if ((rec->flags & FTRACE_FL_ENABLED) == flag) @@ -1423,17 +1524,25 @@ static void ftrace_startup_enable(int command) static void ftrace_startup(int command) { + struct ftrace_ops *ops = &global_ops; + if (unlikely(ftrace_disabled)) return; ftrace_start_up++; command |= FTRACE_ENABLE_CALLS; + ops->flags |= FTRACE_OPS_FL_ENABLED; + if (ftrace_start_up == 1) + ftrace_hash_rec_enable(ops, 1); + ftrace_startup_enable(command); } static void ftrace_shutdown(int command) { + struct ftrace_ops *ops = &global_ops; + if (unlikely(ftrace_disabled)) return; @@ -1446,7 +1555,12 @@ static void ftrace_shutdown(int command) WARN_ON_ONCE(ftrace_start_up < 0); if (!ftrace_start_up) + ftrace_hash_rec_disable(ops, 1); + + if (!ftrace_start_up) { command |= FTRACE_DISABLE_CALLS; + ops->flags &= ~FTRACE_OPS_FL_ENABLED; + } if (saved_ftrace_func != ftrace_trace_function) { saved_ftrace_func = ftrace_trace_function; @@ -2668,6 +2782,7 @@ ftrace_regex_release(struct inode *inode, struct file *file) struct ftrace_iterator *iter; struct ftrace_hash **orig_hash; struct trace_parser *parser; + int filter_hash; int ret; mutex_lock(&ftrace_regex_lock); @@ -2687,15 +2802,26 @@ ftrace_regex_release(struct inode *inode, struct file *file) trace_parser_put(parser); if (file->f_mode & FMODE_WRITE) { - if (iter->flags & FTRACE_ITER_NOTRACE) - orig_hash = &iter->ops->notrace_hash; - else + filter_hash = !!(iter->flags & FTRACE_ITER_FILTER); + + if (filter_hash) orig_hash = &iter->ops->filter_hash; + else + orig_hash = &iter->ops->notrace_hash; mutex_lock(&ftrace_lock); + /* + * Remove the current set, update the hash and add + * them back. + */ + ftrace_hash_rec_disable(iter->ops, filter_hash); ret = ftrace_hash_move(orig_hash, iter->hash); - if (!ret && ftrace_start_up && ftrace_enabled) - ftrace_run_update_code(FTRACE_ENABLE_CALLS); + if (!ret) { + ftrace_hash_rec_enable(iter->ops, filter_hash); + if (iter->ops->flags & FTRACE_OPS_FL_ENABLED + && ftrace_enabled) + ftrace_run_update_code(FTRACE_ENABLE_CALLS); + } mutex_unlock(&ftrace_lock); } free_ftrace_hash(iter->hash); -- cgit v0.10.2 From 647bcd03d5b2fb44fd9c9ef1a4f50c2eee8f779a Mon Sep 17 00:00:00 2001 From: Steven Rostedt Date: Tue, 3 May 2011 14:39:21 -0400 Subject: ftrace: Add enabled_functions file Add the enabled_functions file that is used to show all the functions that have been enabled for tracing as well as their ref counts. This helps seeing if any function has been registered and what functions are being traced. Signed-off-by: Steven Rostedt diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c index 5dd332cc..065f1e6 100644 --- a/kernel/trace/ftrace.c +++ b/kernel/trace/ftrace.c @@ -1703,6 +1703,7 @@ enum { FTRACE_ITER_NOTRACE = (1 << 1), FTRACE_ITER_PRINTALL = (1 << 2), FTRACE_ITER_HASH = (1 << 3), + FTRACE_ITER_ENABLED = (1 << 4), }; #define FTRACE_BUFF_MAX (KSYM_SYMBOL_LEN+4) /* room for wildcards */ @@ -1842,7 +1843,11 @@ t_next(struct seq_file *m, void *v, loff_t *pos) !(ftrace_lookup_ip(ops->filter_hash, rec->ip))) || ((iter->flags & FTRACE_ITER_NOTRACE) && - !ftrace_lookup_ip(ops->notrace_hash, rec->ip))) { + !ftrace_lookup_ip(ops->notrace_hash, rec->ip)) || + + ((iter->flags & FTRACE_ITER_ENABLED) && + !(rec->flags & ~FTRACE_FL_MASK))) { + rec = NULL; goto retry; } @@ -1944,7 +1949,11 @@ static int t_show(struct seq_file *m, void *v) if (!rec) return 0; - seq_printf(m, "%ps\n", (void *)rec->ip); + seq_printf(m, "%ps", (void *)rec->ip); + if (iter->flags & FTRACE_ITER_ENABLED) + seq_printf(m, " (%ld)", + rec->flags & ~FTRACE_FL_MASK); + seq_printf(m, "\n"); return 0; } @@ -1983,6 +1992,34 @@ ftrace_avail_open(struct inode *inode, struct file *file) return ret; } +static int +ftrace_enabled_open(struct inode *inode, struct file *file) +{ + struct ftrace_iterator *iter; + int ret; + + if (unlikely(ftrace_disabled)) + return -ENODEV; + + iter = kzalloc(sizeof(*iter), GFP_KERNEL); + if (!iter) + return -ENOMEM; + + iter->pg = ftrace_pages_start; + iter->flags = FTRACE_ITER_ENABLED; + + ret = seq_open(file, &show_ftrace_seq_ops); + if (!ret) { + struct seq_file *m = file->private_data; + + m->private = iter; + } else { + kfree(iter); + } + + return ret; +} + static void ftrace_filter_reset(struct ftrace_hash *hash) { mutex_lock(&ftrace_lock); @@ -2838,6 +2875,13 @@ static const struct file_operations ftrace_avail_fops = { .release = seq_release_private, }; +static const struct file_operations ftrace_enabled_fops = { + .open = ftrace_enabled_open, + .read = seq_read, + .llseek = seq_lseek, + .release = seq_release_private, +}; + static const struct file_operations ftrace_filter_fops = { .open = ftrace_filter_open, .read = seq_read, @@ -3069,6 +3113,9 @@ static __init int ftrace_init_dyn_debugfs(struct dentry *d_tracer) trace_create_file("available_filter_functions", 0444, d_tracer, NULL, &ftrace_avail_fops); + trace_create_file("enabled_functions", 0444, + d_tracer, NULL, &ftrace_enabled_fops); + trace_create_file("set_ftrace_filter", 0644, d_tracer, NULL, &ftrace_filter_fops); -- cgit v0.10.2 From bd69c30b1d08032d97ab0dabd7a1eb7fb73ca2b2 Mon Sep 17 00:00:00 2001 From: Steven Rostedt Date: Tue, 3 May 2011 21:55:54 -0400 Subject: ftrace: Add ops parameter to ftrace_startup/shutdown functions In order to allow different ops to enable different functions, the ftrace_startup() and ftrace_shutdown() functions need the ops parameter passed to them. Signed-off-by: Steven Rostedt diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c index 065f1e6..8fef1d9 100644 --- a/kernel/trace/ftrace.c +++ b/kernel/trace/ftrace.c @@ -1522,10 +1522,8 @@ static void ftrace_startup_enable(int command) ftrace_run_update_code(command); } -static void ftrace_startup(int command) +static void ftrace_startup(struct ftrace_ops *ops, int command) { - struct ftrace_ops *ops = &global_ops; - if (unlikely(ftrace_disabled)) return; @@ -1539,10 +1537,8 @@ static void ftrace_startup(int command) ftrace_startup_enable(command); } -static void ftrace_shutdown(int command) +static void ftrace_shutdown(struct ftrace_ops *ops, int command) { - struct ftrace_ops *ops = &global_ops; - if (unlikely(ftrace_disabled)) return; @@ -2362,7 +2358,7 @@ static void __enable_ftrace_function_probe(void) return; __register_ftrace_function(&trace_probe_ops); - ftrace_startup(0); + ftrace_startup(&global_ops, 0); ftrace_probe_registered = 1; } @@ -2381,7 +2377,7 @@ static void __disable_ftrace_function_probe(void) /* no more funcs left */ __unregister_ftrace_function(&trace_probe_ops); - ftrace_shutdown(0); + ftrace_shutdown(&global_ops, 0); ftrace_probe_registered = 0; } @@ -3267,6 +3263,10 @@ void __init ftrace_init(void) #else +struct ftrace_ops global_ops = { + .func = ftrace_stub, +}; + static int __init ftrace_nodyn_init(void) { ftrace_enabled = 1; @@ -3277,8 +3277,8 @@ device_initcall(ftrace_nodyn_init); static inline int ftrace_init_dyn_debugfs(struct dentry *d_tracer) { return 0; } static inline void ftrace_startup_enable(int command) { } /* Keep as macros so we do not need to define the commands */ -# define ftrace_startup(command) do { } while (0) -# define ftrace_shutdown(command) do { } while (0) +# define ftrace_startup(ops, command) do { } while (0) +# define ftrace_shutdown(ops, command) do { } while (0) # define ftrace_startup_sysctl() do { } while (0) # define ftrace_shutdown_sysctl() do { } while (0) #endif /* CONFIG_DYNAMIC_FTRACE */ @@ -3583,7 +3583,7 @@ int register_ftrace_function(struct ftrace_ops *ops) goto out_unlock; ret = __register_ftrace_function(ops); - ftrace_startup(0); + ftrace_startup(&global_ops, 0); out_unlock: mutex_unlock(&ftrace_lock); @@ -3602,7 +3602,7 @@ int unregister_ftrace_function(struct ftrace_ops *ops) mutex_lock(&ftrace_lock); ret = __unregister_ftrace_function(ops); - ftrace_shutdown(0); + ftrace_shutdown(&global_ops, 0); mutex_unlock(&ftrace_lock); return ret; @@ -3825,7 +3825,7 @@ int register_ftrace_graph(trace_func_graph_ret_t retfunc, ftrace_graph_return = retfunc; ftrace_graph_entry = entryfunc; - ftrace_startup(FTRACE_START_FUNC_RET); + ftrace_startup(&global_ops, FTRACE_START_FUNC_RET); out: mutex_unlock(&ftrace_lock); @@ -3842,7 +3842,7 @@ void unregister_ftrace_graph(void) ftrace_graph_active--; ftrace_graph_return = (trace_func_graph_ret_t)ftrace_stub; ftrace_graph_entry = ftrace_graph_entry_stub; - ftrace_shutdown(FTRACE_STOP_FUNC_RET); + ftrace_shutdown(&global_ops, FTRACE_STOP_FUNC_RET); unregister_pm_notifier(&ftrace_suspend_notifier); unregister_trace_sched_switch(ftrace_graph_probe_sched_switch, NULL); -- cgit v0.10.2 From 2b499381bc50ede01b3d8eab164ca2fad00655f0 Mon Sep 17 00:00:00 2001 From: Steven Rostedt Date: Tue, 3 May 2011 22:49:52 -0400 Subject: ftrace: Have global_ops store the functions that are to be traced This is a step towards each ops structure defining its own set of functions to trace. As the current code with pid's and such are specific to the global_ops, it is restructured to be used with the global ops. Signed-off-by: Steven Rostedt diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c index 8fef1d9..dcce0bf 100644 --- a/kernel/trace/ftrace.c +++ b/kernel/trace/ftrace.c @@ -91,6 +91,7 @@ static struct ftrace_ops *ftrace_list __read_mostly = &ftrace_list_end; ftrace_func_t ftrace_trace_function __read_mostly = ftrace_stub; ftrace_func_t __ftrace_trace_function __read_mostly = ftrace_stub; ftrace_func_t ftrace_pid_function __read_mostly = ftrace_stub; +static struct ftrace_ops global_ops; /* * Traverse the ftrace_list, invoking all entries. The reason that we @@ -153,7 +154,7 @@ static void ftrace_test_stop_func(unsigned long ip, unsigned long parent_ip) } #endif -static void update_ftrace_function(void) +static void update_global_ops(void) { ftrace_func_t func; @@ -173,6 +174,18 @@ static void update_ftrace_function(void) set_ftrace_pid_function(func); func = ftrace_pid_func; } + + global_ops.func = func; +} + +static void update_ftrace_function(void) +{ + ftrace_func_t func; + + update_global_ops(); + + func = global_ops.func; + #ifdef CONFIG_HAVE_FUNCTION_TRACE_MCOUNT_TEST ftrace_trace_function = func; #else @@ -181,24 +194,19 @@ static void update_ftrace_function(void) #endif } -static int __register_ftrace_function(struct ftrace_ops *ops) +static void add_ftrace_ops(struct ftrace_ops **list, struct ftrace_ops *ops) { - ops->next = ftrace_list; + ops->next = *list; /* * We are entering ops into the ftrace_list but another * CPU might be walking that list. We need to make sure * the ops->next pointer is valid before another CPU sees * the ops pointer included into the ftrace_list. */ - rcu_assign_pointer(ftrace_list, ops); - - if (ftrace_enabled) - update_ftrace_function(); - - return 0; + rcu_assign_pointer(*list, ops); } -static int __unregister_ftrace_function(struct ftrace_ops *ops) +static int remove_ftrace_ops(struct ftrace_ops **list, struct ftrace_ops *ops) { struct ftrace_ops **p; @@ -206,13 +214,12 @@ static int __unregister_ftrace_function(struct ftrace_ops *ops) * If we are removing the last function, then simply point * to the ftrace_stub. */ - if (ftrace_list == ops && ops->next == &ftrace_list_end) { - ftrace_trace_function = ftrace_stub; - ftrace_list = &ftrace_list_end; + if (*list == ops && ops->next == &ftrace_list_end) { + *list = &ftrace_list_end; return 0; } - for (p = &ftrace_list; *p != &ftrace_list_end; p = &(*p)->next) + for (p = list; *p != &ftrace_list_end; p = &(*p)->next) if (*p == ops) break; @@ -220,7 +227,37 @@ static int __unregister_ftrace_function(struct ftrace_ops *ops) return -1; *p = (*p)->next; + return 0; +} + +static int __register_ftrace_function(struct ftrace_ops *ops) +{ + if (ftrace_disabled) + return -ENODEV; + + if (FTRACE_WARN_ON(ops == &global_ops)) + return -EINVAL; + + add_ftrace_ops(&ftrace_list, ops); + if (ftrace_enabled) + update_ftrace_function(); + + return 0; +} +static int __unregister_ftrace_function(struct ftrace_ops *ops) +{ + int ret; + + if (ftrace_disabled) + return -ENODEV; + + if (FTRACE_WARN_ON(ops == &global_ops)) + return -EINVAL; + + ret = remove_ftrace_ops(&ftrace_list, ops); + if (ret < 0) + return ret; if (ftrace_enabled) update_ftrace_function(); @@ -894,7 +931,7 @@ enum { FTRACE_OPS_FL_ENABLED = 1, }; -struct ftrace_ops global_ops = { +static struct ftrace_ops global_ops = { .func = ftrace_stub, .notrace_hash = EMPTY_HASH, .filter_hash = EMPTY_HASH, @@ -3263,7 +3300,7 @@ void __init ftrace_init(void) #else -struct ftrace_ops global_ops = { +static struct ftrace_ops global_ops = { .func = ftrace_stub, }; -- cgit v0.10.2 From 07fd5515f3b5c20704707f63e7f4485b534508a8 Mon Sep 17 00:00:00 2001 From: Steven Rostedt Date: Thu, 5 May 2011 18:03:47 -0400 Subject: ftrace: Free hash with call_rcu_sched() When a hash is modified and might be in use, we need to perform a schedule RCU operation on it, as the hashes will soon be used directly in the function tracer callback. Cc: Paul E. McKenney Signed-off-by: Steven Rostedt diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c index dcce0bf..92b6fdf 100644 --- a/kernel/trace/ftrace.c +++ b/kernel/trace/ftrace.c @@ -913,6 +913,7 @@ struct ftrace_hash { unsigned long size_bits; struct hlist_head *buckets; unsigned long count; + struct rcu_head rcu; }; /* @@ -1058,6 +1059,21 @@ static void free_ftrace_hash(struct ftrace_hash *hash) kfree(hash); } +static void __free_ftrace_hash_rcu(struct rcu_head *rcu) +{ + struct ftrace_hash *hash; + + hash = container_of(rcu, struct ftrace_hash, rcu); + free_ftrace_hash(hash); +} + +static void free_ftrace_hash_rcu(struct ftrace_hash *hash) +{ + if (!hash || hash == EMPTY_HASH) + return; + call_rcu_sched(&hash->rcu, __free_ftrace_hash_rcu); +} + static struct ftrace_hash *alloc_ftrace_hash(int size_bits) { struct ftrace_hash *hash; @@ -1122,7 +1138,8 @@ ftrace_hash_move(struct ftrace_hash **dst, struct ftrace_hash *src) struct ftrace_func_entry *entry; struct hlist_node *tp, *tn; struct hlist_head *hhd; - struct ftrace_hash *hash = *dst; + struct ftrace_hash *old_hash; + struct ftrace_hash *new_hash; unsigned long key; int size = src->count; int bits = 0; @@ -1133,13 +1150,11 @@ ftrace_hash_move(struct ftrace_hash **dst, struct ftrace_hash *src) * the empty_hash. */ if (!src->count) { - free_ftrace_hash(*dst); - *dst = EMPTY_HASH; + free_ftrace_hash_rcu(*dst); + rcu_assign_pointer(*dst, EMPTY_HASH); return 0; } - ftrace_hash_clear(hash); - /* * Make the hash size about 1/2 the # found */ @@ -1150,27 +1165,9 @@ ftrace_hash_move(struct ftrace_hash **dst, struct ftrace_hash *src) if (bits > FTRACE_HASH_MAX_BITS) bits = FTRACE_HASH_MAX_BITS; - /* We can't modify the empty_hash */ - if (hash == EMPTY_HASH) { - /* Create a new hash */ - *dst = alloc_ftrace_hash(bits); - if (!*dst) { - *dst = EMPTY_HASH; - return -ENOMEM; - } - hash = *dst; - } else { - size = 1 << bits; - - /* Use the old hash, but create new buckets */ - hhd = kzalloc(sizeof(*hhd) * size, GFP_KERNEL); - if (!hhd) - return -ENOMEM; - - kfree(hash->buckets); - hash->buckets = hhd; - hash->size_bits = bits; - } + new_hash = alloc_ftrace_hash(bits); + if (!new_hash) + return -ENOMEM; size = 1 << src->size_bits; for (i = 0; i < size; i++) { @@ -1181,10 +1178,14 @@ ftrace_hash_move(struct ftrace_hash **dst, struct ftrace_hash *src) else key = 0; remove_hash_entry(src, entry); - __add_hash_entry(hash, entry); + __add_hash_entry(new_hash, entry); } } + old_hash = *dst; + rcu_assign_pointer(*dst, new_hash); + free_ftrace_hash_rcu(old_hash); + return 0; } -- cgit v0.10.2 From b848914ce39589d89ee0078a6d1ef452b464729e Mon Sep 17 00:00:00 2001 From: Steven Rostedt Date: Wed, 4 May 2011 09:27:52 -0400 Subject: ftrace: Implement separate user function filtering ftrace_ops that are registered to trace functions can now be agnostic to each other in respect to what functions they trace. Each ops has their own hash of the functions they want to trace and a hash to what they do not want to trace. A empty hash for the functions they want to trace denotes all functions should be traced that are not in the notrace hash. Cc: Paul E. McKenney Signed-off-by: Steven Rostedt diff --git a/include/linux/ftrace.h b/include/linux/ftrace.h index ab1c46e..4609c0e 100644 --- a/include/linux/ftrace.h +++ b/include/linux/ftrace.h @@ -31,13 +31,18 @@ typedef void (*ftrace_func_t)(unsigned long ip, unsigned long parent_ip); struct ftrace_hash; +enum { + FTRACE_OPS_FL_ENABLED = 1 << 0, + FTRACE_OPS_FL_GLOBAL = 1 << 1, +}; + struct ftrace_ops { ftrace_func_t func; struct ftrace_ops *next; + unsigned long flags; #ifdef CONFIG_DYNAMIC_FTRACE struct ftrace_hash *notrace_hash; struct ftrace_hash *filter_hash; - unsigned long flags; #endif }; diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c index 92b6fdf..6c7e1df 100644 --- a/kernel/trace/ftrace.c +++ b/kernel/trace/ftrace.c @@ -87,24 +87,29 @@ static struct ftrace_ops ftrace_list_end __read_mostly = .func = ftrace_stub, }; -static struct ftrace_ops *ftrace_list __read_mostly = &ftrace_list_end; +static struct ftrace_ops *ftrace_global_list __read_mostly = &ftrace_list_end; +static struct ftrace_ops *ftrace_ops_list __read_mostly = &ftrace_list_end; ftrace_func_t ftrace_trace_function __read_mostly = ftrace_stub; ftrace_func_t __ftrace_trace_function __read_mostly = ftrace_stub; ftrace_func_t ftrace_pid_function __read_mostly = ftrace_stub; static struct ftrace_ops global_ops; +static void +ftrace_ops_list_func(unsigned long ip, unsigned long parent_ip); + /* - * Traverse the ftrace_list, invoking all entries. The reason that we + * Traverse the ftrace_global_list, invoking all entries. The reason that we * can use rcu_dereference_raw() is that elements removed from this list * are simply leaked, so there is no need to interact with a grace-period * mechanism. The rcu_dereference_raw() calls are needed to handle - * concurrent insertions into the ftrace_list. + * concurrent insertions into the ftrace_global_list. * * Silly Alpha and silly pointer-speculation compiler optimizations! */ -static void ftrace_list_func(unsigned long ip, unsigned long parent_ip) +static void ftrace_global_list_func(unsigned long ip, + unsigned long parent_ip) { - struct ftrace_ops *op = rcu_dereference_raw(ftrace_list); /*see above*/ + struct ftrace_ops *op = rcu_dereference_raw(ftrace_global_list); /*see above*/ while (op != &ftrace_list_end) { op->func(ip, parent_ip); @@ -163,11 +168,11 @@ static void update_global_ops(void) * function directly. Otherwise, we need to iterate over the * registered callers. */ - if (ftrace_list == &ftrace_list_end || - ftrace_list->next == &ftrace_list_end) - func = ftrace_list->func; + if (ftrace_global_list == &ftrace_list_end || + ftrace_global_list->next == &ftrace_list_end) + func = ftrace_global_list->func; else - func = ftrace_list_func; + func = ftrace_global_list_func; /* If we filter on pids, update to use the pid function */ if (!list_empty(&ftrace_pids)) { @@ -184,7 +189,11 @@ static void update_ftrace_function(void) update_global_ops(); - func = global_ops.func; + if (ftrace_ops_list == &ftrace_list_end || + ftrace_ops_list->next == &ftrace_list_end) + func = ftrace_ops_list->func; + else + func = ftrace_ops_list_func; #ifdef CONFIG_HAVE_FUNCTION_TRACE_MCOUNT_TEST ftrace_trace_function = func; @@ -198,10 +207,10 @@ static void add_ftrace_ops(struct ftrace_ops **list, struct ftrace_ops *ops) { ops->next = *list; /* - * We are entering ops into the ftrace_list but another + * We are entering ops into the list but another * CPU might be walking that list. We need to make sure * the ops->next pointer is valid before another CPU sees - * the ops pointer included into the ftrace_list. + * the ops pointer included into the list. */ rcu_assign_pointer(*list, ops); } @@ -238,7 +247,18 @@ static int __register_ftrace_function(struct ftrace_ops *ops) if (FTRACE_WARN_ON(ops == &global_ops)) return -EINVAL; - add_ftrace_ops(&ftrace_list, ops); + if (WARN_ON(ops->flags & FTRACE_OPS_FL_ENABLED)) + return -EBUSY; + + if (ops->flags & FTRACE_OPS_FL_GLOBAL) { + int first = ftrace_global_list == &ftrace_list_end; + add_ftrace_ops(&ftrace_global_list, ops); + ops->flags |= FTRACE_OPS_FL_ENABLED; + if (first) + add_ftrace_ops(&ftrace_ops_list, &global_ops); + } else + add_ftrace_ops(&ftrace_ops_list, ops); + if (ftrace_enabled) update_ftrace_function(); @@ -252,12 +272,24 @@ static int __unregister_ftrace_function(struct ftrace_ops *ops) if (ftrace_disabled) return -ENODEV; + if (WARN_ON(!(ops->flags & FTRACE_OPS_FL_ENABLED))) + return -EBUSY; + if (FTRACE_WARN_ON(ops == &global_ops)) return -EINVAL; - ret = remove_ftrace_ops(&ftrace_list, ops); + if (ops->flags & FTRACE_OPS_FL_GLOBAL) { + ret = remove_ftrace_ops(&ftrace_global_list, ops); + if (!ret && ftrace_global_list == &ftrace_list_end) + ret = remove_ftrace_ops(&ftrace_ops_list, &global_ops); + if (!ret) + ops->flags &= ~FTRACE_OPS_FL_ENABLED; + } else + ret = remove_ftrace_ops(&ftrace_ops_list, ops); + if (ret < 0) return ret; + if (ftrace_enabled) update_ftrace_function(); @@ -928,10 +960,6 @@ static const struct ftrace_hash empty_hash = { }; #define EMPTY_HASH ((struct ftrace_hash *)&empty_hash) -enum { - FTRACE_OPS_FL_ENABLED = 1, -}; - static struct ftrace_ops global_ops = { .func = ftrace_stub, .notrace_hash = EMPTY_HASH, @@ -1190,6 +1218,40 @@ ftrace_hash_move(struct ftrace_hash **dst, struct ftrace_hash *src) } /* + * Test the hashes for this ops to see if we want to call + * the ops->func or not. + * + * It's a match if the ip is in the ops->filter_hash or + * the filter_hash does not exist or is empty, + * AND + * the ip is not in the ops->notrace_hash. + */ +static int +ftrace_ops_test(struct ftrace_ops *ops, unsigned long ip) +{ + struct ftrace_hash *filter_hash; + struct ftrace_hash *notrace_hash; + int ret; + + /* The hashes are freed with call_rcu_sched() */ + preempt_disable_notrace(); + + filter_hash = rcu_dereference_raw(ops->filter_hash); + notrace_hash = rcu_dereference_raw(ops->notrace_hash); + + if ((!filter_hash || !filter_hash->count || + ftrace_lookup_ip(filter_hash, ip)) && + (!notrace_hash || !notrace_hash->count || + !ftrace_lookup_ip(notrace_hash, ip))) + ret = 1; + else + ret = 0; + preempt_enable_notrace(); + + return ret; +} + +/* * This is a double for. Do not use 'break' to break out of the loop, * you must use a goto. */ @@ -1232,7 +1294,7 @@ static void __ftrace_hash_rec_update(struct ftrace_ops *ops, if (filter_hash) { hash = ops->filter_hash; other_hash = ops->notrace_hash; - if (!hash->count) + if (!hash || !hash->count) all = 1; } else { inc = !inc; @@ -1242,7 +1304,7 @@ static void __ftrace_hash_rec_update(struct ftrace_ops *ops, * If the notrace hash has no items, * then there's nothing to do. */ - if (!hash->count) + if (hash && !hash->count) return; } @@ -1256,11 +1318,11 @@ static void __ftrace_hash_rec_update(struct ftrace_ops *ops, * Only the filter_hash affects all records. * Update if the record is not in the notrace hash. */ - if (!ftrace_lookup_ip(other_hash, rec->ip)) + if (!other_hash || !ftrace_lookup_ip(other_hash, rec->ip)) match = 1; } else { - in_hash = !!ftrace_lookup_ip(hash, rec->ip); - in_other_hash = !!ftrace_lookup_ip(other_hash, rec->ip); + in_hash = hash && !!ftrace_lookup_ip(hash, rec->ip); + in_other_hash = other_hash && !!ftrace_lookup_ip(other_hash, rec->ip); /* * @@ -1546,6 +1608,7 @@ static void ftrace_run_update_code(int command) static ftrace_func_t saved_ftrace_func; static int ftrace_start_up; +static int global_start_up; static void ftrace_startup_enable(int command) { @@ -1562,14 +1625,25 @@ static void ftrace_startup_enable(int command) static void ftrace_startup(struct ftrace_ops *ops, int command) { + bool hash_enable = true; + if (unlikely(ftrace_disabled)) return; ftrace_start_up++; command |= FTRACE_ENABLE_CALLS; + /* ops marked global share the filter hashes */ + if (ops->flags & FTRACE_OPS_FL_GLOBAL) { + ops = &global_ops; + /* Don't update hash if global is already set */ + if (global_start_up) + hash_enable = false; + global_start_up++; + } + ops->flags |= FTRACE_OPS_FL_ENABLED; - if (ftrace_start_up == 1) + if (hash_enable) ftrace_hash_rec_enable(ops, 1); ftrace_startup_enable(command); @@ -1577,6 +1651,8 @@ static void ftrace_startup(struct ftrace_ops *ops, int command) static void ftrace_shutdown(struct ftrace_ops *ops, int command) { + bool hash_disable = true; + if (unlikely(ftrace_disabled)) return; @@ -1588,13 +1664,25 @@ static void ftrace_shutdown(struct ftrace_ops *ops, int command) */ WARN_ON_ONCE(ftrace_start_up < 0); - if (!ftrace_start_up) + if (ops->flags & FTRACE_OPS_FL_GLOBAL) { + ops = &global_ops; + global_start_up--; + WARN_ON_ONCE(global_start_up < 0); + /* Don't update hash if global still has users */ + if (global_start_up) { + WARN_ON_ONCE(!ftrace_start_up); + hash_disable = false; + } + } + + if (hash_disable) ftrace_hash_rec_disable(ops, 1); - if (!ftrace_start_up) { - command |= FTRACE_DISABLE_CALLS; + if (ops != &global_ops || !global_start_up) ops->flags &= ~FTRACE_OPS_FL_ENABLED; - } + + if (!ftrace_start_up) + command |= FTRACE_DISABLE_CALLS; if (saved_ftrace_func != ftrace_trace_function) { saved_ftrace_func = ftrace_trace_function; @@ -2381,6 +2469,7 @@ static int ftrace_probe_registered; static void __enable_ftrace_function_probe(void) { + int ret; int i; if (ftrace_probe_registered) @@ -2395,13 +2484,16 @@ static void __enable_ftrace_function_probe(void) if (i == FTRACE_FUNC_HASHSIZE) return; - __register_ftrace_function(&trace_probe_ops); - ftrace_startup(&global_ops, 0); + ret = __register_ftrace_function(&trace_probe_ops); + if (!ret) + ftrace_startup(&trace_probe_ops, 0); + ftrace_probe_registered = 1; } static void __disable_ftrace_function_probe(void) { + int ret; int i; if (!ftrace_probe_registered) @@ -2414,8 +2506,10 @@ static void __disable_ftrace_function_probe(void) } /* no more funcs left */ - __unregister_ftrace_function(&trace_probe_ops); - ftrace_shutdown(&global_ops, 0); + ret = __unregister_ftrace_function(&trace_probe_ops); + if (!ret) + ftrace_shutdown(&trace_probe_ops, 0); + ftrace_probe_registered = 0; } @@ -3319,8 +3413,28 @@ static inline void ftrace_startup_enable(int command) { } # define ftrace_shutdown(ops, command) do { } while (0) # define ftrace_startup_sysctl() do { } while (0) # define ftrace_shutdown_sysctl() do { } while (0) + +static inline int +ftrace_ops_test(struct ftrace_ops *ops, unsigned long ip) +{ + return 1; +} + #endif /* CONFIG_DYNAMIC_FTRACE */ +static void +ftrace_ops_list_func(unsigned long ip, unsigned long parent_ip) +{ + /* see comment above ftrace_global_list_func */ + struct ftrace_ops *op = rcu_dereference_raw(ftrace_ops_list); + + while (op != &ftrace_list_end) { + if (ftrace_ops_test(op, ip)) + op->func(ip, parent_ip); + op = rcu_dereference_raw(op->next); + }; +} + static void clear_ftrace_swapper(void) { struct task_struct *p; @@ -3621,7 +3735,9 @@ int register_ftrace_function(struct ftrace_ops *ops) goto out_unlock; ret = __register_ftrace_function(ops); - ftrace_startup(&global_ops, 0); + if (!ret) + ftrace_startup(ops, 0); + out_unlock: mutex_unlock(&ftrace_lock); @@ -3640,7 +3756,8 @@ int unregister_ftrace_function(struct ftrace_ops *ops) mutex_lock(&ftrace_lock); ret = __unregister_ftrace_function(ops); - ftrace_shutdown(&global_ops, 0); + if (!ret) + ftrace_shutdown(ops, 0); mutex_unlock(&ftrace_lock); return ret; @@ -3670,11 +3787,11 @@ ftrace_enable_sysctl(struct ctl_table *table, int write, ftrace_startup_sysctl(); /* we are starting ftrace again */ - if (ftrace_list != &ftrace_list_end) { - if (ftrace_list->next == &ftrace_list_end) - ftrace_trace_function = ftrace_list->func; + if (ftrace_ops_list != &ftrace_list_end) { + if (ftrace_ops_list->next == &ftrace_list_end) + ftrace_trace_function = ftrace_ops_list->func; else - ftrace_trace_function = ftrace_list_func; + ftrace_trace_function = ftrace_ops_list_func; } } else { diff --git a/kernel/trace/trace_functions.c b/kernel/trace/trace_functions.c index 16aee4d..8d0e1cc 100644 --- a/kernel/trace/trace_functions.c +++ b/kernel/trace/trace_functions.c @@ -149,11 +149,13 @@ function_stack_trace_call(unsigned long ip, unsigned long parent_ip) static struct ftrace_ops trace_ops __read_mostly = { .func = function_trace_call, + .flags = FTRACE_OPS_FL_GLOBAL, }; static struct ftrace_ops trace_stack_ops __read_mostly = { .func = function_stack_trace_call, + .flags = FTRACE_OPS_FL_GLOBAL, }; /* Our two options */ diff --git a/kernel/trace/trace_irqsoff.c b/kernel/trace/trace_irqsoff.c index a4969b4..c77424b 100644 --- a/kernel/trace/trace_irqsoff.c +++ b/kernel/trace/trace_irqsoff.c @@ -153,6 +153,7 @@ irqsoff_tracer_call(unsigned long ip, unsigned long parent_ip) static struct ftrace_ops trace_ops __read_mostly = { .func = irqsoff_tracer_call, + .flags = FTRACE_OPS_FL_GLOBAL, }; #endif /* CONFIG_FUNCTION_TRACER */ diff --git a/kernel/trace/trace_sched_wakeup.c b/kernel/trace/trace_sched_wakeup.c index 7319559..f029dd4 100644 --- a/kernel/trace/trace_sched_wakeup.c +++ b/kernel/trace/trace_sched_wakeup.c @@ -129,6 +129,7 @@ wakeup_tracer_call(unsigned long ip, unsigned long parent_ip) static struct ftrace_ops trace_ops __read_mostly = { .func = wakeup_tracer_call, + .flags = FTRACE_OPS_FL_GLOBAL, }; #endif /* CONFIG_FUNCTION_TRACER */ diff --git a/kernel/trace/trace_stack.c b/kernel/trace/trace_stack.c index 4c5dead..b0b53b8 100644 --- a/kernel/trace/trace_stack.c +++ b/kernel/trace/trace_stack.c @@ -133,6 +133,7 @@ stack_trace_call(unsigned long ip, unsigned long parent_ip) static struct ftrace_ops trace_ops __read_mostly = { .func = stack_trace_call, + .flags = FTRACE_OPS_FL_GLOBAL, }; static ssize_t -- cgit v0.10.2 From cdbe61bfe70440939e457fb4a8d0995eaaed17de Mon Sep 17 00:00:00 2001 From: Steven Rostedt Date: Thu, 5 May 2011 21:14:55 -0400 Subject: ftrace: Allow dynamically allocated function tracers Now that functions may be selected individually, it only makes sense that we should allow dynamically allocated trace structures to be traced. This will allow perf to allocate a ftrace_ops structure at runtime and use it to pick and choose which functions that structure will trace. Note, a dynamically allocated ftrace_ops will always be called indirectly instead of being called directly from the mcount in entry.S. This is because there's no safe way to prevent mcount from being preempted before calling the function, unless we modify every entry.S to do so (not likely). Thus, dynamically allocated functions will now be called by the ftrace_ops_list_func() that loops through the ops that are allocated if there are more than one op allocated at a time. This loop is protected with a preempt_disable. To determine if an ftrace_ops structure is allocated or not, a new util function was added to the kernel/extable.c called core_kernel_data(), which returns 1 if the address is between _sdata and _edata. Cc: Paul E. McKenney Signed-off-by: Steven Rostedt diff --git a/include/linux/ftrace.h b/include/linux/ftrace.h index 4609c0e..caba694 100644 --- a/include/linux/ftrace.h +++ b/include/linux/ftrace.h @@ -34,6 +34,7 @@ struct ftrace_hash; enum { FTRACE_OPS_FL_ENABLED = 1 << 0, FTRACE_OPS_FL_GLOBAL = 1 << 1, + FTRACE_OPS_FL_DYNAMIC = 1 << 2, }; struct ftrace_ops { diff --git a/include/linux/kernel.h b/include/linux/kernel.h index 00cec4d..f37ba71 100644 --- a/include/linux/kernel.h +++ b/include/linux/kernel.h @@ -283,6 +283,7 @@ extern char *get_options(const char *str, int nints, int *ints); extern unsigned long long memparse(const char *ptr, char **retptr); extern int core_kernel_text(unsigned long addr); +extern int core_kernel_data(unsigned long addr); extern int __kernel_text_address(unsigned long addr); extern int kernel_text_address(unsigned long addr); extern int func_ptr_is_kernel_text(void *ptr); diff --git a/kernel/extable.c b/kernel/extable.c index 7f8f263..c2d625f 100644 --- a/kernel/extable.c +++ b/kernel/extable.c @@ -72,6 +72,14 @@ int core_kernel_text(unsigned long addr) return 0; } +int core_kernel_data(unsigned long addr) +{ + if (addr >= (unsigned long)_sdata && + addr < (unsigned long)_edata) + return 1; + return 0; +} + int __kernel_text_address(unsigned long addr) { if (core_kernel_text(addr)) diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c index 6c7e1df..5b3ee04 100644 --- a/kernel/trace/ftrace.c +++ b/kernel/trace/ftrace.c @@ -189,8 +189,14 @@ static void update_ftrace_function(void) update_global_ops(); + /* + * If we are at the end of the list and this ops is + * not dynamic, then have the mcount trampoline call + * the function directly + */ if (ftrace_ops_list == &ftrace_list_end || - ftrace_ops_list->next == &ftrace_list_end) + (ftrace_ops_list->next == &ftrace_list_end && + !(ftrace_ops_list->flags & FTRACE_OPS_FL_DYNAMIC))) func = ftrace_ops_list->func; else func = ftrace_ops_list_func; @@ -250,6 +256,9 @@ static int __register_ftrace_function(struct ftrace_ops *ops) if (WARN_ON(ops->flags & FTRACE_OPS_FL_ENABLED)) return -EBUSY; + if (!core_kernel_data((unsigned long)ops)) + ops->flags |= FTRACE_OPS_FL_DYNAMIC; + if (ops->flags & FTRACE_OPS_FL_GLOBAL) { int first = ftrace_global_list == &ftrace_list_end; add_ftrace_ops(&ftrace_global_list, ops); @@ -293,6 +302,13 @@ static int __unregister_ftrace_function(struct ftrace_ops *ops) if (ftrace_enabled) update_ftrace_function(); + /* + * Dynamic ops may be freed, we must make sure that all + * callers are done before leaving this function. + */ + if (ops->flags & FTRACE_OPS_FL_DYNAMIC) + synchronize_sched(); + return 0; } @@ -1225,6 +1241,9 @@ ftrace_hash_move(struct ftrace_hash **dst, struct ftrace_hash *src) * the filter_hash does not exist or is empty, * AND * the ip is not in the ops->notrace_hash. + * + * This needs to be called with preemption disabled as + * the hashes are freed with call_rcu_sched(). */ static int ftrace_ops_test(struct ftrace_ops *ops, unsigned long ip) @@ -1233,9 +1252,6 @@ ftrace_ops_test(struct ftrace_ops *ops, unsigned long ip) struct ftrace_hash *notrace_hash; int ret; - /* The hashes are freed with call_rcu_sched() */ - preempt_disable_notrace(); - filter_hash = rcu_dereference_raw(ops->filter_hash); notrace_hash = rcu_dereference_raw(ops->notrace_hash); @@ -1246,7 +1262,6 @@ ftrace_ops_test(struct ftrace_ops *ops, unsigned long ip) ret = 1; else ret = 0; - preempt_enable_notrace(); return ret; } @@ -3425,14 +3440,20 @@ ftrace_ops_test(struct ftrace_ops *ops, unsigned long ip) static void ftrace_ops_list_func(unsigned long ip, unsigned long parent_ip) { - /* see comment above ftrace_global_list_func */ - struct ftrace_ops *op = rcu_dereference_raw(ftrace_ops_list); + struct ftrace_ops *op; + /* + * Some of the ops may be dynamically allocated, + * they must be freed after a synchronize_sched(). + */ + preempt_disable_notrace(); + op = rcu_dereference_raw(ftrace_ops_list); while (op != &ftrace_list_end) { if (ftrace_ops_test(op, ip)) op->func(ip, parent_ip); op = rcu_dereference_raw(op->next); }; + preempt_enable_notrace(); } static void clear_ftrace_swapper(void) @@ -3743,6 +3764,7 @@ int register_ftrace_function(struct ftrace_ops *ops) mutex_unlock(&ftrace_lock); return ret; } +EXPORT_SYMBOL_GPL(register_ftrace_function); /** * unregister_ftrace_function - unregister a function for profiling. @@ -3762,6 +3784,7 @@ int unregister_ftrace_function(struct ftrace_ops *ops) return ret; } +EXPORT_SYMBOL_GPL(unregister_ftrace_function); int ftrace_enable_sysctl(struct ctl_table *table, int write, -- cgit v0.10.2 From f634a4e7074f66ac3dfaf2cc6786e0ec3080a2d1 Mon Sep 17 00:00:00 2001 From: Luciano Coelho Date: Wed, 18 May 2011 16:51:26 -0400 Subject: wl12xx: fix compilation error when CONFIG_PM is not set There was a compilation error when PM is not enabled: CC [M] drivers/net/wireless/wl12xx/main.o drivers/net/wireless/wl12xx/main.c:3653: error: unknown field 'suspend' specified in initializer drivers/net/wireless/wl12xx/main.c:3653: warning: initialization from incompatible pointer type drivers/net/wireless/wl12xx/main.c:3654: error: unknown field 'resume' specified in initializer drivers/net/wireless/wl12xx/main.c:3654: warning: initialization from incompatible pointer type Fix this by adding #ifdef's in the appropriate places. Cc: Eliad Peller Signed-off-by: Luciano Coelho Signed-off-by: David S. Miller diff --git a/drivers/net/wireless/wl12xx/main.c b/drivers/net/wireless/wl12xx/main.c index 610be03..bc00e52 100644 --- a/drivers/net/wireless/wl12xx/main.c +++ b/drivers/net/wireless/wl12xx/main.c @@ -1350,6 +1350,7 @@ static struct notifier_block wl1271_dev_notifier = { .notifier_call = wl1271_dev_notify, }; +#ifdef CONFIG_PM static int wl1271_configure_suspend(struct wl1271 *wl) { int ret; @@ -1493,6 +1494,7 @@ static int wl1271_op_resume(struct ieee80211_hw *hw) return 0; } +#endif static int wl1271_op_start(struct ieee80211_hw *hw) { @@ -3650,8 +3652,10 @@ static const struct ieee80211_ops wl1271_ops = { .stop = wl1271_op_stop, .add_interface = wl1271_op_add_interface, .remove_interface = wl1271_op_remove_interface, +#ifdef CONFIG_PM .suspend = wl1271_op_suspend, .resume = wl1271_op_resume, +#endif .config = wl1271_op_config, .prepare_multicast = wl1271_op_prepare_multicast, .configure_filter = wl1271_op_configure_filter, diff --git a/drivers/net/wireless/wl12xx/sdio.c b/drivers/net/wireless/wl12xx/sdio.c index 92d29a8..536e506 100644 --- a/drivers/net/wireless/wl12xx/sdio.c +++ b/drivers/net/wireless/wl12xx/sdio.c @@ -330,6 +330,7 @@ static void __devexit wl1271_remove(struct sdio_func *func) wl1271_free_hw(wl); } +#ifdef CONFIG_PM static int wl1271_suspend(struct device *dev) { /* Tell MMC/SDIO core it's OK to power down the card @@ -385,15 +386,18 @@ static const struct dev_pm_ops wl1271_sdio_pm_ops = { .suspend = wl1271_suspend, .resume = wl1271_resume, }; +#endif static struct sdio_driver wl1271_sdio_driver = { .name = "wl1271_sdio", .id_table = wl1271_devices, .probe = wl1271_probe, .remove = __devexit_p(wl1271_remove), +#ifdef CONFIG_PM .drv = { .pm = &wl1271_sdio_pm_ops, }, +#endif }; static int __init wl1271_init(void) -- cgit v0.10.2 From 60a34277d5da958e7f39a942e0ed1016a904f6c6 Mon Sep 17 00:00:00 2001 From: Frank Blaschka Date: Wed, 18 May 2011 03:28:35 +0000 Subject: qeth: use ndo_set_features callback for initial setup and recovery MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This patch uses the ndo_set_features callback during normal device startup or recovery to turn on hardware RX checksum. Patch was done with much help from Michal Miroslaw, thx!!! Signed-off-by: Frank Blaschka Reviewed-by: MichaÅ‚ MirosÅ‚aw Signed-off-by: David S. Miller diff --git a/drivers/s390/net/qeth_l3_main.c b/drivers/s390/net/qeth_l3_main.c index bbe7e1c..fd69da3 100644 --- a/drivers/s390/net/qeth_l3_main.c +++ b/drivers/s390/net/qeth_l3_main.c @@ -1417,63 +1417,33 @@ int qeth_l3_set_rx_csum(struct qeth_card *card, int on) int rc = 0; if (on) { - if (card->state != CARD_STATE_DOWN) { - if (!qeth_is_supported(card, - IPA_INBOUND_CHECKSUM)) - return -EPERM; - rc = qeth_l3_send_checksum_command(card); - if (rc) - return -EIO; - } - card->dev->features |= NETIF_F_RXCSUM; + rc = qeth_l3_send_checksum_command(card); + if (rc) + return -EIO; + dev_info(&card->gdev->dev, + "HW Checksumming (inbound) enabled\n"); } else { - if (card->state != CARD_STATE_DOWN) { - rc = qeth_l3_send_simple_setassparms(card, - IPA_INBOUND_CHECKSUM, IPA_CMD_ASS_STOP, 0); - if (rc) - return -EIO; - } - card->dev->features &= ~NETIF_F_RXCSUM; + rc = qeth_l3_send_simple_setassparms(card, + IPA_INBOUND_CHECKSUM, IPA_CMD_ASS_STOP, 0); + if (rc) + return -EIO; } - return rc; + return 0; } static int qeth_l3_start_ipa_checksum(struct qeth_card *card) { - int rc = 0; - QETH_CARD_TEXT(card, 3, "strtcsum"); if (card->dev->features & NETIF_F_RXCSUM) { - /* hw may have changed during offline or recovery */ - if (!qeth_is_supported(card, IPA_INBOUND_CHECKSUM)) { - dev_info(&card->gdev->dev, - "Inbound HW Checksumming not " - "supported on %s,\ncontinuing " - "using Inbound SW Checksumming\n", - QETH_CARD_IFNAME(card)); - goto update_feature; - } - - rc = qeth_l3_send_checksum_command(card); - if (!rc) - dev_info(&card->gdev->dev, - "HW Checksumming (inbound) enabled\n"); - else - goto update_feature; - } else - dev_info(&card->gdev->dev, - "Using SW checksumming on %s.\n", - QETH_CARD_IFNAME(card)); + rtnl_lock(); + /* force set_features call */ + card->dev->features &= ~NETIF_F_RXCSUM; + netdev_update_features(card->dev); + rtnl_unlock(); + } return 0; - -update_feature: - rtnl_lock(); - card->dev->features &= ~NETIF_F_RXCSUM; - netdev_update_features(card->dev); - rtnl_unlock(); - return rc; } static int qeth_l3_start_ipa_tx_checksum(struct qeth_card *card) @@ -3196,17 +3166,20 @@ static int qeth_l3_set_features(struct net_device *dev, u32 features) { struct qeth_card *card = dev->ml_priv; u32 changed = dev->features ^ features; - int on; + int err; if (!(changed & NETIF_F_RXCSUM)) return 0; - if (features & NETIF_F_RXCSUM) - on = 1; - else - on = 0; + if (card->state == CARD_STATE_DOWN || + card->state == CARD_STATE_RECOVER) + return 0; + + err = qeth_l3_set_rx_csum(card, features & NETIF_F_RXCSUM); + if (err) + dev->features = features ^ NETIF_F_RXCSUM; - return qeth_l3_set_rx_csum(card, on); + return err; } static const struct ethtool_ops qeth_l3_ethtool_ops = { -- cgit v0.10.2 From 0be6bc62cdd5e1bed75b2122ba7d26fc245b534b Mon Sep 17 00:00:00 2001 From: Shmulik Ravid Date: Wed, 18 May 2011 02:55:31 +0000 Subject: bnx2x: add support for retrieving dcb peer configuration This patch adds support to the bnx2x for retrieving dcb peer (remote) configuration from the embedded DCBX stack. Signed-off-by: Shmulik Ravid Signed-off-by: Eilon Greenstein Signed-off-by: David S. Miller diff --git a/drivers/net/bnx2x/bnx2x.h b/drivers/net/bnx2x/bnx2x.h index 16a76f0..668a578 100644 --- a/drivers/net/bnx2x/bnx2x.h +++ b/drivers/net/bnx2x/bnx2x.h @@ -1242,6 +1242,10 @@ struct bnx2x { /* DCBX Negotiation results */ struct dcbx_features dcbx_local_feat; u32 dcbx_error; +#ifdef BCM_DCBNL + struct dcbx_features dcbx_remote_feat; + u32 dcbx_remote_flags; +#endif u32 pending_max; }; diff --git a/drivers/net/bnx2x/bnx2x_dcb.c b/drivers/net/bnx2x/bnx2x_dcb.c index 0f83092..410a49e 100644 --- a/drivers/net/bnx2x/bnx2x_dcb.c +++ b/drivers/net/bnx2x/bnx2x_dcb.c @@ -485,6 +485,36 @@ static void bnx2x_dcbx_update_ets_params(struct bnx2x *bp) } } +#ifdef BCM_DCBNL +static int bnx2x_dcbx_read_shmem_remote_mib(struct bnx2x *bp) +{ + struct lldp_remote_mib remote_mib = {0}; + u32 dcbx_remote_mib_offset = SHMEM2_RD(bp, dcbx_remote_mib_offset); + int rc; + + DP(NETIF_MSG_LINK, "dcbx_remote_mib_offset 0x%x\n", + dcbx_remote_mib_offset); + + if (SHMEM_DCBX_REMOTE_MIB_NONE == dcbx_remote_mib_offset) { + BNX2X_ERR("FW doesn't support dcbx_remote_mib_offset\n"); + return -EINVAL; + } + + rc = bnx2x_dcbx_read_mib(bp, (u32 *)&remote_mib, dcbx_remote_mib_offset, + DCBX_READ_REMOTE_MIB); + + if (rc) { + BNX2X_ERR("Faild to read remote mib from FW\n"); + return rc; + } + + /* save features and flags */ + bp->dcbx_remote_feat = remote_mib.features; + bp->dcbx_remote_flags = remote_mib.flags; + return 0; +} +#endif + static int bnx2x_dcbx_read_shmem_neg_results(struct bnx2x *bp) { struct lldp_local_mib local_mib = {0}; @@ -601,6 +631,10 @@ void bnx2x_dcbx_set_params(struct bnx2x *bp, u32 state) * negotiation results */ bnx2x_dcbnl_update_applist(bp, true); + + /* Read rmeote mib if dcbx is in the FW */ + if (bnx2x_dcbx_read_shmem_remote_mib(bp)) + return; #endif /* Read neg results if dcbx is in the FW */ if (bnx2x_dcbx_read_shmem_neg_results(bp)) @@ -2031,7 +2065,6 @@ static u8 bnx2x_dcbnl_set_dcbx(struct net_device *netdev, u8 state) return 0; } - static u8 bnx2x_dcbnl_get_featcfg(struct net_device *netdev, int featid, u8 *flags) { @@ -2111,31 +2144,100 @@ static u8 bnx2x_dcbnl_set_featcfg(struct net_device *netdev, int featid, return rval; } +static int bnx2x_peer_appinfo(struct net_device *netdev, + struct dcb_peer_app_info *info, u16* app_count) +{ + int i; + struct bnx2x *bp = netdev_priv(netdev); + + DP(NETIF_MSG_LINK, "APP-INFO\n"); + + info->willing = (bp->dcbx_remote_flags & DCBX_APP_REM_WILLING) ?: 0; + info->error = (bp->dcbx_remote_flags & DCBX_APP_RX_ERROR) ?: 0; + *app_count = 0; + + for (i = 0; i < DCBX_MAX_APP_PROTOCOL; i++) + if (bp->dcbx_remote_feat.app.app_pri_tbl[i].appBitfield & + DCBX_APP_ENTRY_VALID) + (*app_count)++; + return 0; +} + +static int bnx2x_peer_apptable(struct net_device *netdev, + struct dcb_app *table) +{ + int i, j; + struct bnx2x *bp = netdev_priv(netdev); + + DP(NETIF_MSG_LINK, "APP-TABLE\n"); + + for (i = 0, j = 0; i < DCBX_MAX_APP_PROTOCOL; i++) { + struct dcbx_app_priority_entry *ent = + &bp->dcbx_remote_feat.app.app_pri_tbl[i]; + + if (ent->appBitfield & DCBX_APP_ENTRY_VALID) { + table[j].selector = bnx2x_dcbx_dcbnl_app_idtype(ent); + table[j].priority = bnx2x_dcbx_dcbnl_app_up(ent); + table[j++].protocol = ent->app_id; + } + } + return 0; +} + +static int bnx2x_cee_peer_getpg(struct net_device *netdev, struct cee_pg *pg) +{ + int i; + struct bnx2x *bp = netdev_priv(netdev); + + pg->willing = (bp->dcbx_remote_flags & DCBX_ETS_REM_WILLING) ?: 0; + + for (i = 0; i < CEE_DCBX_MAX_PGS; i++) { + pg->pg_bw[i] = + DCBX_PG_BW_GET(bp->dcbx_remote_feat.ets.pg_bw_tbl, i); + pg->prio_pg[i] = + DCBX_PRI_PG_GET(bp->dcbx_remote_feat.ets.pri_pg_tbl, i); + } + return 0; +} + +static int bnx2x_cee_peer_getpfc(struct net_device *netdev, + struct cee_pfc *pfc) +{ + struct bnx2x *bp = netdev_priv(netdev); + pfc->tcs_supported = bp->dcbx_remote_feat.pfc.pfc_caps; + pfc->pfc_en = bp->dcbx_remote_feat.pfc.pri_en_bitmap; + return 0; +} + const struct dcbnl_rtnl_ops bnx2x_dcbnl_ops = { - .getstate = bnx2x_dcbnl_get_state, - .setstate = bnx2x_dcbnl_set_state, - .getpermhwaddr = bnx2x_dcbnl_get_perm_hw_addr, - .setpgtccfgtx = bnx2x_dcbnl_set_pg_tccfg_tx, - .setpgbwgcfgtx = bnx2x_dcbnl_set_pg_bwgcfg_tx, - .setpgtccfgrx = bnx2x_dcbnl_set_pg_tccfg_rx, - .setpgbwgcfgrx = bnx2x_dcbnl_set_pg_bwgcfg_rx, - .getpgtccfgtx = bnx2x_dcbnl_get_pg_tccfg_tx, - .getpgbwgcfgtx = bnx2x_dcbnl_get_pg_bwgcfg_tx, - .getpgtccfgrx = bnx2x_dcbnl_get_pg_tccfg_rx, - .getpgbwgcfgrx = bnx2x_dcbnl_get_pg_bwgcfg_rx, - .setpfccfg = bnx2x_dcbnl_set_pfc_cfg, - .getpfccfg = bnx2x_dcbnl_get_pfc_cfg, - .setall = bnx2x_dcbnl_set_all, - .getcap = bnx2x_dcbnl_get_cap, - .getnumtcs = bnx2x_dcbnl_get_numtcs, - .setnumtcs = bnx2x_dcbnl_set_numtcs, - .getpfcstate = bnx2x_dcbnl_get_pfc_state, - .setpfcstate = bnx2x_dcbnl_set_pfc_state, - .setapp = bnx2x_dcbnl_set_app_up, - .getdcbx = bnx2x_dcbnl_get_dcbx, - .setdcbx = bnx2x_dcbnl_set_dcbx, - .getfeatcfg = bnx2x_dcbnl_get_featcfg, - .setfeatcfg = bnx2x_dcbnl_set_featcfg, + .getstate = bnx2x_dcbnl_get_state, + .setstate = bnx2x_dcbnl_set_state, + .getpermhwaddr = bnx2x_dcbnl_get_perm_hw_addr, + .setpgtccfgtx = bnx2x_dcbnl_set_pg_tccfg_tx, + .setpgbwgcfgtx = bnx2x_dcbnl_set_pg_bwgcfg_tx, + .setpgtccfgrx = bnx2x_dcbnl_set_pg_tccfg_rx, + .setpgbwgcfgrx = bnx2x_dcbnl_set_pg_bwgcfg_rx, + .getpgtccfgtx = bnx2x_dcbnl_get_pg_tccfg_tx, + .getpgbwgcfgtx = bnx2x_dcbnl_get_pg_bwgcfg_tx, + .getpgtccfgrx = bnx2x_dcbnl_get_pg_tccfg_rx, + .getpgbwgcfgrx = bnx2x_dcbnl_get_pg_bwgcfg_rx, + .setpfccfg = bnx2x_dcbnl_set_pfc_cfg, + .getpfccfg = bnx2x_dcbnl_get_pfc_cfg, + .setall = bnx2x_dcbnl_set_all, + .getcap = bnx2x_dcbnl_get_cap, + .getnumtcs = bnx2x_dcbnl_get_numtcs, + .setnumtcs = bnx2x_dcbnl_set_numtcs, + .getpfcstate = bnx2x_dcbnl_get_pfc_state, + .setpfcstate = bnx2x_dcbnl_set_pfc_state, + .setapp = bnx2x_dcbnl_set_app_up, + .getdcbx = bnx2x_dcbnl_get_dcbx, + .setdcbx = bnx2x_dcbnl_set_dcbx, + .getfeatcfg = bnx2x_dcbnl_get_featcfg, + .setfeatcfg = bnx2x_dcbnl_set_featcfg, + .peer_getappinfo = bnx2x_peer_appinfo, + .peer_getapptable = bnx2x_peer_apptable, + .cee_peer_getpg = bnx2x_cee_peer_getpg, + .cee_peer_getpfc = bnx2x_cee_peer_getpfc, }; #endif /* BCM_DCBNL */ -- cgit v0.10.2 From 12f4d0a8770ab26639091d0b2509b19681daad69 Mon Sep 17 00:00:00 2001 From: Mammatha Edhala Date: Wed, 18 May 2011 03:26:22 +0000 Subject: be2net: Enable SR-IOV for Lancer Enable SR-IOV for Lancer Signed-off-by: Mammatha Edhala Signed-off-by: Padmanabh Ratnakar Signed-off-by: David S. Miller diff --git a/drivers/net/benet/be.h b/drivers/net/benet/be.h index 0b73dcf..a7db870 100644 --- a/drivers/net/benet/be.h +++ b/drivers/net/benet/be.h @@ -49,6 +49,7 @@ #define OC_DEVICE_ID1 0x700 /* Device Id for BE2 cards */ #define OC_DEVICE_ID2 0x710 /* Device Id for BE3 cards */ #define OC_DEVICE_ID3 0xe220 /* Device id for Lancer cards */ +#define OC_DEVICE_ID4 0xe228 /* Device id for VF in Lancer */ static inline char *nic_name(struct pci_dev *pdev) { @@ -58,6 +59,7 @@ static inline char *nic_name(struct pci_dev *pdev) case OC_DEVICE_ID2: return OC_NAME_BE; case OC_DEVICE_ID3: + case OC_DEVICE_ID4: return OC_NAME_LANCER; case BE_DEVICE_ID2: return BE3_NAME; @@ -383,7 +385,8 @@ struct be_adapter { #define BE_GEN2 2 #define BE_GEN3 3 -#define lancer_chip(adapter) (adapter->pdev->device == OC_DEVICE_ID3) +#define lancer_chip(adapter) ((adapter->pdev->device == OC_DEVICE_ID3) || \ + (adapter->pdev->device == OC_DEVICE_ID4)) extern const struct ethtool_ops be_ethtool_ops; diff --git a/drivers/net/benet/be_main.c b/drivers/net/benet/be_main.c index 7322a51..ce6edac 100644 --- a/drivers/net/benet/be_main.c +++ b/drivers/net/benet/be_main.c @@ -42,6 +42,7 @@ static DEFINE_PCI_DEVICE_TABLE(be_dev_ids) = { { PCI_DEVICE(BE_VENDOR_ID, OC_DEVICE_ID1) }, { PCI_DEVICE(BE_VENDOR_ID, OC_DEVICE_ID2) }, { PCI_DEVICE(EMULEX_VENDOR_ID, OC_DEVICE_ID3)}, + { PCI_DEVICE(EMULEX_VENDOR_ID, OC_DEVICE_ID4)}, { 0 } }; MODULE_DEVICE_TABLE(pci, be_dev_ids); @@ -3161,7 +3162,8 @@ static int be_get_config(struct be_adapter *adapter) memset(mac, 0, ETH_ALEN); - if (be_physfn(adapter)) { + /* A default permanent address is given to each VF for Lancer*/ + if (be_physfn(adapter) || lancer_chip(adapter)) { status = be_cmd_mac_addr_query(adapter, mac, MAC_ADDRESS_TYPE_NETWORK, true /*permanent */, 0); @@ -3203,6 +3205,7 @@ static int be_dev_family_check(struct be_adapter *adapter) adapter->generation = BE_GEN3; break; case OC_DEVICE_ID3: + case OC_DEVICE_ID4: pci_read_config_dword(pdev, SLI_INTF_REG_OFFSET, &sli_intf); if_type = (sli_intf & SLI_INTF_IF_TYPE_MASK) >> SLI_INTF_IF_TYPE_SHIFT; @@ -3212,10 +3215,6 @@ static int be_dev_family_check(struct be_adapter *adapter) dev_err(&pdev->dev, "SLI_INTF reg val is not valid\n"); return -EINVAL; } - if (num_vfs > 0) { - dev_err(&pdev->dev, "VFs not supported\n"); - return -EINVAL; - } adapter->sli_family = ((sli_intf & SLI_INTF_FAMILY_MASK) >> SLI_INTF_FAMILY_SHIFT); adapter->generation = BE_GEN3; @@ -3381,9 +3380,11 @@ static int __devinit be_probe(struct pci_dev *pdev, bool link_up; u16 vf, lnk_speed; - status = be_vf_eth_addr_config(adapter); - if (status) - goto unreg_netdev; + if (!lancer_chip(adapter)) { + status = be_vf_eth_addr_config(adapter); + if (status) + goto unreg_netdev; + } for (vf = 0; vf < num_vfs; vf++) { status = be_cmd_link_status_query(adapter, &link_up, -- cgit v0.10.2 From 6882f933ccee5c3a86443ffc7621ce888b93ab6b Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Wed, 18 May 2011 18:23:21 -0400 Subject: ipv4: Kill RT_CACHE_DEBUG It's way past it's usefulness. And this gets rid of a bunch of stray ->rt_{dst,src} references. Even the comment documenting the macro was inaccurate (stated default was 1 when it's 0). If reintroduced, it should be done properly, with dynamic debug facilities. Signed-off-by: David S. Miller diff --git a/include/net/dst.h b/include/net/dst.h index 2588a9a..07a0402 100644 --- a/include/net/dst.h +++ b/include/net/dst.h @@ -16,13 +16,6 @@ #include #include -/* - * 0 - no debugging messages - * 1 - rare events and bugs (default) - * 2 - trace mode. - */ -#define RT_CACHE_DEBUG 0 - #define DST_GC_MIN (HZ/10) #define DST_GC_INC (HZ/2) #define DST_GC_MAX (120*HZ) diff --git a/net/core/dst.c b/net/core/dst.c index 30f0093..da47a29 100644 --- a/net/core/dst.c +++ b/net/core/dst.c @@ -33,9 +33,6 @@ * 3) This list is guarded by a mutex, * so that the gc_task and dst_dev_event() can be synchronized. */ -#if RT_CACHE_DEBUG >= 2 -static atomic_t dst_total = ATOMIC_INIT(0); -#endif /* * We want to keep lock & list close together @@ -69,10 +66,6 @@ static void dst_gc_task(struct work_struct *work) unsigned long expires = ~0L; struct dst_entry *dst, *next, head; struct dst_entry *last = &head; -#if RT_CACHE_DEBUG >= 2 - ktime_t time_start = ktime_get(); - struct timespec elapsed; -#endif mutex_lock(&dst_gc_mutex); next = dst_busy_list; @@ -146,15 +139,6 @@ loop: spin_unlock_bh(&dst_garbage.lock); mutex_unlock(&dst_gc_mutex); -#if RT_CACHE_DEBUG >= 2 - elapsed = ktime_to_timespec(ktime_sub(ktime_get(), time_start)); - printk(KERN_DEBUG "dst_total: %d delayed: %d work_perf: %d" - " expires: %lu elapsed: %lu us\n", - atomic_read(&dst_total), delayed, work_performed, - expires, - elapsed.tv_sec * USEC_PER_SEC + - elapsed.tv_nsec / NSEC_PER_USEC); -#endif } int dst_discard(struct sk_buff *skb) @@ -205,9 +189,6 @@ void *dst_alloc(struct dst_ops *ops, struct net_device *dev, dst->lastuse = jiffies; dst->flags = flags; dst->next = NULL; -#if RT_CACHE_DEBUG >= 2 - atomic_inc(&dst_total); -#endif dst_entries_add(ops, 1); return dst; } @@ -267,9 +248,6 @@ again: dst->ops->destroy(dst); if (dst->dev) dev_put(dst->dev); -#if RT_CACHE_DEBUG >= 2 - atomic_dec(&dst_total); -#endif kmem_cache_free(dst->ops->kmem_cachep, dst); dst = child; diff --git a/net/ipv4/route.c b/net/ipv4/route.c index cb93c32..9c5ad86 100644 --- a/net/ipv4/route.c +++ b/net/ipv4/route.c @@ -968,10 +968,6 @@ static int rt_garbage_collect(struct dst_ops *ops) break; expire >>= 1; -#if RT_CACHE_DEBUG >= 2 - printk(KERN_DEBUG "expire>> %u %d %d %d\n", expire, - dst_entries_get_fast(&ipv4_dst_ops), goal, i); -#endif if (dst_entries_get_fast(&ipv4_dst_ops) < ip_rt_max_size) goto out; @@ -992,10 +988,6 @@ work_done: dst_entries_get_fast(&ipv4_dst_ops) < ipv4_dst_ops.gc_thresh || dst_entries_get_slow(&ipv4_dst_ops) < ipv4_dst_ops.gc_thresh) expire = ip_rt_gc_timeout; -#if RT_CACHE_DEBUG >= 2 - printk(KERN_DEBUG "expire++ %u %d %d %d\n", expire, - dst_entries_get_fast(&ipv4_dst_ops), goal, rover); -#endif out: return 0; } @@ -1179,16 +1171,6 @@ restart: rt->dst.rt_next = rt_hash_table[hash].chain; -#if RT_CACHE_DEBUG >= 2 - if (rt->dst.rt_next) { - struct rtable *trt; - printk(KERN_DEBUG "rt_cache @%02x: %pI4", - hash, &rt->rt_dst); - for (trt = rt->dst.rt_next; trt; trt = trt->dst.rt_next) - printk(" . %pI4", &trt->rt_dst); - printk("\n"); - } -#endif /* * Since lookup is lockfree, we must make sure * previous writes to rt are committed to memory @@ -1347,10 +1329,6 @@ static struct dst_entry *ipv4_negative_advice(struct dst_entry *dst) unsigned hash = rt_hash(rt->rt_key_dst, rt->rt_key_src, rt->rt_oif, rt_genid(dev_net(dst->dev))); -#if RT_CACHE_DEBUG >= 1 - printk(KERN_DEBUG "ipv4_negative_advice: redirect to %pI4/%02x dropped\n", - &rt->rt_dst, rt->rt_key_tos); -#endif rt_del(hash, rt); ret = NULL; } else if (rt->peer && -- cgit v0.10.2 From 6bd023f3dddfc7c5f660089598c10e1f4167083b Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Wed, 18 May 2011 18:32:03 -0400 Subject: ipv4: Make caller provide flowi4 key to inet_csk_route_req(). This way the caller can get at the fully resolved fl4->{daddr,saddr} etc. Signed-off-by: David S. Miller diff --git a/include/net/inet_connection_sock.h b/include/net/inet_connection_sock.h index 96546ca..e6db62e 100644 --- a/include/net/inet_connection_sock.h +++ b/include/net/inet_connection_sock.h @@ -249,6 +249,7 @@ extern int inet_csk_bind_conflict(const struct sock *sk, extern int inet_csk_get_port(struct sock *sk, unsigned short snum); extern struct dst_entry* inet_csk_route_req(struct sock *sk, + struct flowi4 *fl4, const struct request_sock *req); extern struct dst_entry* inet_csk_route_child_sock(struct sock *sk, struct sock *newsk, diff --git a/net/dccp/ipv4.c b/net/dccp/ipv4.c index 46b15e9..8c36adf 100644 --- a/net/dccp/ipv4.c +++ b/net/dccp/ipv4.c @@ -497,8 +497,9 @@ static int dccp_v4_send_response(struct sock *sk, struct request_sock *req, int err = -1; struct sk_buff *skb; struct dst_entry *dst; + struct flowi4 fl4; - dst = inet_csk_route_req(sk, req); + dst = inet_csk_route_req(sk, &fl4, req); if (dst == NULL) goto out; diff --git a/net/ipv4/inet_connection_sock.c b/net/ipv4/inet_connection_sock.c index 3a2ba56..61fac4c 100644 --- a/net/ipv4/inet_connection_sock.c +++ b/net/ipv4/inet_connection_sock.c @@ -350,24 +350,24 @@ void inet_csk_reset_keepalive_timer(struct sock *sk, unsigned long len) EXPORT_SYMBOL(inet_csk_reset_keepalive_timer); struct dst_entry *inet_csk_route_req(struct sock *sk, + struct flowi4 *fl4, const struct request_sock *req) { struct rtable *rt; const struct inet_request_sock *ireq = inet_rsk(req); struct ip_options_rcu *opt = inet_rsk(req)->opt; struct net *net = sock_net(sk); - struct flowi4 fl4; - flowi4_init_output(&fl4, sk->sk_bound_dev_if, sk->sk_mark, + flowi4_init_output(fl4, sk->sk_bound_dev_if, sk->sk_mark, RT_CONN_FLAGS(sk), RT_SCOPE_UNIVERSE, sk->sk_protocol, inet_sk_flowi_flags(sk), (opt && opt->opt.srr) ? opt->opt.faddr : ireq->rmt_addr, ireq->loc_addr, ireq->rmt_port, inet_sk(sk)->inet_sport); - security_req_classify_flow(req, flowi4_to_flowi(&fl4)); - rt = ip_route_output_flow(net, &fl4, sk); + security_req_classify_flow(req, flowi4_to_flowi(fl4)); + rt = ip_route_output_flow(net, fl4, sk); if (IS_ERR(rt)) goto no_route; - if (opt && opt->opt.is_strictroute && fl4.daddr != rt->rt_gateway) + if (opt && opt->opt.is_strictroute && fl4->daddr != rt->rt_gateway) goto route_err; return &rt->dst; diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c index f67fb34..7e0bc60 100644 --- a/net/ipv4/tcp_ipv4.c +++ b/net/ipv4/tcp_ipv4.c @@ -769,11 +769,12 @@ static int tcp_v4_send_synack(struct sock *sk, struct dst_entry *dst, struct request_values *rvp) { const struct inet_request_sock *ireq = inet_rsk(req); + struct flowi4 fl4; int err = -1; struct sk_buff * skb; /* First, grab a route. */ - if (!dst && (dst = inet_csk_route_req(sk, req)) == NULL) + if (!dst && (dst = inet_csk_route_req(sk, &fl4, req)) == NULL) return -1; skb = tcp_make_synack(sk, dst, req, rvp); @@ -1338,6 +1339,7 @@ int tcp_v4_conn_request(struct sock *sk, struct sk_buff *skb) req->cookie_ts = tmp_opt.tstamp_ok; } else if (!isn) { struct inet_peer *peer = NULL; + struct flowi4 fl4; /* VJ's idea. We save last timestamp seen * from the destination in peer table, when entering @@ -1350,7 +1352,7 @@ int tcp_v4_conn_request(struct sock *sk, struct sk_buff *skb) */ if (tmp_opt.saw_tstamp && tcp_death_row.sysctl_tw_recycle && - (dst = inet_csk_route_req(sk, req)) != NULL && + (dst = inet_csk_route_req(sk, &fl4, req)) != NULL && (peer = rt_get_peer((struct rtable *)dst)) != NULL && peer->daddr.addr.a4 == saddr) { inet_peer_refcheck(peer); -- cgit v0.10.2 From ed2361e66eec60645f8e4715fe39a42235ef43ae Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Wed, 18 May 2011 18:38:54 -0400 Subject: ipv4: Pass explicit destination address to rt_get_peer(). This will next trickle down to rt_bind_peer(). Signed-off-by: David S. Miller diff --git a/include/net/route.h b/include/net/route.h index ba0e084..600d0f2 100644 --- a/include/net/route.h +++ b/include/net/route.h @@ -292,7 +292,7 @@ static inline struct rtable *ip_route_newports(struct flowi4 *fl4, struct rtable extern void rt_bind_peer(struct rtable *rt, int create); -static inline struct inet_peer *rt_get_peer(struct rtable *rt) +static inline struct inet_peer *rt_get_peer(struct rtable *rt, __be32 daddr) { if (rt->peer) return rt->peer; diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c index 7e0bc60..1d290ac 100644 --- a/net/ipv4/tcp_ipv4.c +++ b/net/ipv4/tcp_ipv4.c @@ -206,7 +206,7 @@ int tcp_v4_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len) if (tcp_death_row.sysctl_tw_recycle && !tp->rx_opt.ts_recent_stamp && fl4->daddr == daddr) { - struct inet_peer *peer = rt_get_peer(rt); + struct inet_peer *peer = rt_get_peer(rt, fl4->daddr); /* * VJ's idea. We save last timestamp seen from * the destination in peer table, when entering state @@ -1353,8 +1353,8 @@ int tcp_v4_conn_request(struct sock *sk, struct sk_buff *skb) if (tmp_opt.saw_tstamp && tcp_death_row.sysctl_tw_recycle && (dst = inet_csk_route_req(sk, &fl4, req)) != NULL && - (peer = rt_get_peer((struct rtable *)dst)) != NULL && - peer->daddr.addr.a4 == saddr) { + fl4.daddr == saddr && + (peer = rt_get_peer((struct rtable *)dst, fl4.daddr)) != NULL) { inet_peer_refcheck(peer); if ((u32)get_seconds() - peer->tcp_ts_stamp < TCP_PAWS_MSL && (s32)(peer->tcp_ts - req->ts_recent) > -- cgit v0.10.2 From a48eff128865aa20520fa6e0e0c5fbd2ac50d712 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Wed, 18 May 2011 18:42:43 -0400 Subject: ipv4: Pass explicit destination address to rt_bind_peer(). Signed-off-by: David S. Miller diff --git a/include/net/route.h b/include/net/route.h index 600d0f2..db7b343 100644 --- a/include/net/route.h +++ b/include/net/route.h @@ -290,14 +290,14 @@ static inline struct rtable *ip_route_newports(struct flowi4 *fl4, struct rtable return rt; } -extern void rt_bind_peer(struct rtable *rt, int create); +extern void rt_bind_peer(struct rtable *rt, __be32 daddr, int create); static inline struct inet_peer *rt_get_peer(struct rtable *rt, __be32 daddr) { if (rt->peer) return rt->peer; - rt_bind_peer(rt, 0); + rt_bind_peer(rt, daddr, 0); return rt->peer; } diff --git a/net/ipv4/icmp.c b/net/ipv4/icmp.c index 3f47585..5395e45 100644 --- a/net/ipv4/icmp.c +++ b/net/ipv4/icmp.c @@ -234,7 +234,7 @@ static inline void icmp_xmit_unlock(struct sock *sk) */ static inline bool icmpv4_xrlim_allow(struct net *net, struct rtable *rt, - int type, int code) + struct flowi4 *fl4, int type, int code) { struct dst_entry *dst = &rt->dst; bool rc = true; @@ -253,7 +253,7 @@ static inline bool icmpv4_xrlim_allow(struct net *net, struct rtable *rt, /* Limit if icmp type is enabled in ratemask. */ if ((1 << type) & net->ipv4.sysctl_icmp_ratemask) { if (!rt->peer) - rt_bind_peer(rt, 1); + rt_bind_peer(rt, fl4->daddr, 1); rc = inet_peer_xrlim_allow(rt->peer, net->ipv4.sysctl_icmp_ratelimit); } @@ -363,7 +363,7 @@ static void icmp_reply(struct icmp_bxm *icmp_param, struct sk_buff *skb) rt = ip_route_output_key(net, &fl4); if (IS_ERR(rt)) goto out_unlock; - if (icmpv4_xrlim_allow(net, rt, icmp_param->data.icmph.type, + if (icmpv4_xrlim_allow(net, rt, &fl4, icmp_param->data.icmph.type, icmp_param->data.icmph.code)) icmp_push_reply(icmp_param, &fl4, &ipc, &rt); ip_rt_put(rt); @@ -603,7 +603,7 @@ void icmp_send(struct sk_buff *skb_in, int type, int code, __be32 info) if (IS_ERR(rt)) goto out_unlock; - if (!icmpv4_xrlim_allow(net, rt, type, code)) + if (!icmpv4_xrlim_allow(net, rt, &fl4, type, code)) goto ende; /* RFC says return as much as we can without exceeding 576 bytes. */ diff --git a/net/ipv4/route.c b/net/ipv4/route.c index 9c5ad86..b24d58e 100644 --- a/net/ipv4/route.c +++ b/net/ipv4/route.c @@ -156,7 +156,7 @@ static u32 *ipv4_cow_metrics(struct dst_entry *dst, unsigned long old) u32 *p = NULL; if (!rt->peer) - rt_bind_peer(rt, 1); + rt_bind_peer(rt, rt->rt_dst, 1); peer = rt->peer; if (peer) { @@ -1193,11 +1193,11 @@ static u32 rt_peer_genid(void) return atomic_read(&__rt_peer_genid); } -void rt_bind_peer(struct rtable *rt, int create) +void rt_bind_peer(struct rtable *rt, __be32 daddr, int create) { struct inet_peer *peer; - peer = inet_getpeer_v4(rt->rt_dst, create); + peer = inet_getpeer_v4(daddr, create); if (peer && cmpxchg(&rt->peer, NULL, peer) != NULL) inet_putpeer(peer); @@ -1231,7 +1231,7 @@ void __ip_select_ident(struct iphdr *iph, struct dst_entry *dst, int more) if (rt) { if (rt->peer == NULL) - rt_bind_peer(rt, 1); + rt_bind_peer(rt, rt->rt_dst, 1); /* If peer is attached to destination, it is never detached, so that we need not to grab a lock to dereference it. @@ -1377,7 +1377,7 @@ void ip_rt_send_redirect(struct sk_buff *skb) rcu_read_unlock(); if (!rt->peer) - rt_bind_peer(rt, 1); + rt_bind_peer(rt, rt->rt_dst, 1); peer = rt->peer; if (!peer) { icmp_send(skb, ICMP_REDIRECT, ICMP_REDIR_HOST, rt->rt_gateway); @@ -1445,7 +1445,7 @@ static int ip_error(struct sk_buff *skb) } if (!rt->peer) - rt_bind_peer(rt, 1); + rt_bind_peer(rt, rt->rt_dst, 1); peer = rt->peer; send = true; @@ -1552,7 +1552,7 @@ static void ip_rt_update_pmtu(struct dst_entry *dst, u32 mtu) dst_confirm(dst); if (!rt->peer) - rt_bind_peer(rt, 1); + rt_bind_peer(rt, rt->rt_dst, 1); peer = rt->peer; if (peer) { if (mtu < ip_rt_min_pmtu) @@ -1609,7 +1609,7 @@ static struct dst_entry *ipv4_dst_check(struct dst_entry *dst, u32 cookie) struct inet_peer *peer; if (!rt->peer) - rt_bind_peer(rt, 0); + rt_bind_peer(rt, rt->rt_dst, 0); peer = rt->peer; if (peer && peer->pmtu_expires) diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c index 1d290ac..3c8d9b6 100644 --- a/net/ipv4/tcp_ipv4.c +++ b/net/ipv4/tcp_ipv4.c @@ -1781,7 +1781,7 @@ struct inet_peer *tcp_v4_get_peer(struct sock *sk, bool *release_it) *release_it = true; } else { if (!rt->peer) - rt_bind_peer(rt, 1); + rt_bind_peer(rt, inet->inet_daddr, 1); peer = rt->peer; *release_it = false; } -- cgit v0.10.2 From 936e074b286ae779f134312178dbab139ee7ea52 Mon Sep 17 00:00:00 2001 From: Steven Rostedt Date: Thu, 5 May 2011 22:54:01 -0400 Subject: ftrace: Modify ftrace_set_filter/notrace to take ops Since users of the function tracer can now pick and choose which functions they want to trace agnostically from other users of the function tracer, we need to pass the ops struct to the ftrace_set_filter() functions. The functions ftrace_set_global_filter() and ftrace_set_global_notrace() is added to keep the old filter functions which are used to modify the generic function tracers. Signed-off-by: Steven Rostedt diff --git a/include/linux/ftrace.h b/include/linux/ftrace.h index caba694..9d88e1c 100644 --- a/include/linux/ftrace.h +++ b/include/linux/ftrace.h @@ -179,7 +179,12 @@ struct dyn_ftrace { }; int ftrace_force_update(void); -void ftrace_set_filter(unsigned char *buf, int len, int reset); +void ftrace_set_filter(struct ftrace_ops *ops, unsigned char *buf, + int len, int reset); +void ftrace_set_notrace(struct ftrace_ops *ops, unsigned char *buf, + int len, int reset); +void ftrace_set_global_filter(unsigned char *buf, int len, int reset); +void ftrace_set_global_notrace(unsigned char *buf, int len, int reset); int register_ftrace_command(struct ftrace_func_command *cmd); int unregister_ftrace_command(struct ftrace_func_command *cmd); diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c index 5b3ee04..d017c2c 100644 --- a/kernel/trace/ftrace.c +++ b/kernel/trace/ftrace.c @@ -2826,6 +2826,10 @@ ftrace_set_regex(struct ftrace_ops *ops, unsigned char *buf, int len, struct ftrace_hash *hash; int ret; + /* All global ops uses the global ops filters */ + if (ops->flags & FTRACE_OPS_FL_GLOBAL) + ops = &global_ops; + if (unlikely(ftrace_disabled)) return -ENODEV; @@ -2856,6 +2860,41 @@ ftrace_set_regex(struct ftrace_ops *ops, unsigned char *buf, int len, /** * ftrace_set_filter - set a function to filter on in ftrace + * @ops - the ops to set the filter with + * @buf - the string that holds the function filter text. + * @len - the length of the string. + * @reset - non zero to reset all filters before applying this filter. + * + * Filters denote which functions should be enabled when tracing is enabled. + * If @buf is NULL and reset is set, all functions will be enabled for tracing. + */ +void ftrace_set_filter(struct ftrace_ops *ops, unsigned char *buf, + int len, int reset) +{ + ftrace_set_regex(ops, buf, len, reset, 1); +} +EXPORT_SYMBOL_GPL(ftrace_set_filter); + +/** + * ftrace_set_notrace - set a function to not trace in ftrace + * @ops - the ops to set the notrace filter with + * @buf - the string that holds the function notrace text. + * @len - the length of the string. + * @reset - non zero to reset all filters before applying this filter. + * + * Notrace Filters denote which functions should not be enabled when tracing + * is enabled. If @buf is NULL and reset is set, all functions will be enabled + * for tracing. + */ +void ftrace_set_notrace(struct ftrace_ops *ops, unsigned char *buf, + int len, int reset) +{ + ftrace_set_regex(ops, buf, len, reset, 0); +} +EXPORT_SYMBOL_GPL(ftrace_set_notrace); +/** + * ftrace_set_filter - set a function to filter on in ftrace + * @ops - the ops to set the filter with * @buf - the string that holds the function filter text. * @len - the length of the string. * @reset - non zero to reset all filters before applying this filter. @@ -2863,13 +2902,15 @@ ftrace_set_regex(struct ftrace_ops *ops, unsigned char *buf, int len, * Filters denote which functions should be enabled when tracing is enabled. * If @buf is NULL and reset is set, all functions will be enabled for tracing. */ -void ftrace_set_filter(unsigned char *buf, int len, int reset) +void ftrace_set_global_filter(unsigned char *buf, int len, int reset) { ftrace_set_regex(&global_ops, buf, len, reset, 1); } +EXPORT_SYMBOL_GPL(ftrace_set_global_filter); /** * ftrace_set_notrace - set a function to not trace in ftrace + * @ops - the ops to set the notrace filter with * @buf - the string that holds the function notrace text. * @len - the length of the string. * @reset - non zero to reset all filters before applying this filter. @@ -2878,10 +2919,11 @@ void ftrace_set_filter(unsigned char *buf, int len, int reset) * is enabled. If @buf is NULL and reset is set, all functions will be enabled * for tracing. */ -void ftrace_set_notrace(unsigned char *buf, int len, int reset) +void ftrace_set_global_notrace(unsigned char *buf, int len, int reset) { ftrace_set_regex(&global_ops, buf, len, reset, 0); } +EXPORT_SYMBOL_GPL(ftrace_set_global_notrace); /* * command line interface to allow users to set filters on boot up. diff --git a/kernel/trace/trace_selftest.c b/kernel/trace/trace_selftest.c index 659732e..0fa2db3 100644 --- a/kernel/trace/trace_selftest.c +++ b/kernel/trace/trace_selftest.c @@ -131,7 +131,7 @@ int trace_selftest_startup_dynamic_tracing(struct tracer *trace, func_name = "*" __stringify(DYN_FTRACE_TEST_NAME); /* filter only on our function */ - ftrace_set_filter(func_name, strlen(func_name), 1); + ftrace_set_global_filter(func_name, strlen(func_name), 1); /* enable tracing */ ret = tracer_init(trace, tr); @@ -181,7 +181,7 @@ int trace_selftest_startup_dynamic_tracing(struct tracer *trace, tracer_enabled = save_tracer_enabled; /* Enable tracing on all functions again */ - ftrace_set_filter(NULL, 0, 1); + ftrace_set_global_filter(NULL, 0, 1); return ret; } -- cgit v0.10.2 From 95950c2ecb31314ef827428e43ff771cf3b037e5 Mon Sep 17 00:00:00 2001 From: Steven Rostedt Date: Fri, 6 May 2011 00:08:51 -0400 Subject: ftrace: Add self-tests for multiple function trace users Add some basic sanity tests for multiple users of the function tracer at startup. Signed-off-by: Steven Rostedt diff --git a/kernel/trace/trace.h b/kernel/trace/trace.h index 5e9dfc6..6b69c4b 100644 --- a/kernel/trace/trace.h +++ b/kernel/trace/trace.h @@ -419,6 +419,8 @@ extern void trace_find_cmdline(int pid, char comm[]); extern unsigned long ftrace_update_tot_cnt; #define DYN_FTRACE_TEST_NAME trace_selftest_dynamic_test_func extern int DYN_FTRACE_TEST_NAME(void); +#define DYN_FTRACE_TEST_NAME2 trace_selftest_dynamic_test_func2 +extern int DYN_FTRACE_TEST_NAME2(void); #endif extern int ring_buffer_expanded; diff --git a/kernel/trace/trace_selftest.c b/kernel/trace/trace_selftest.c index 0fa2db3..288541f 100644 --- a/kernel/trace/trace_selftest.c +++ b/kernel/trace/trace_selftest.c @@ -101,6 +101,206 @@ static inline void warn_failed_init_tracer(struct tracer *trace, int init_ret) #ifdef CONFIG_DYNAMIC_FTRACE +static int trace_selftest_test_probe1_cnt; +static void trace_selftest_test_probe1_func(unsigned long ip, + unsigned long pip) +{ + trace_selftest_test_probe1_cnt++; +} + +static int trace_selftest_test_probe2_cnt; +static void trace_selftest_test_probe2_func(unsigned long ip, + unsigned long pip) +{ + trace_selftest_test_probe2_cnt++; +} + +static int trace_selftest_test_probe3_cnt; +static void trace_selftest_test_probe3_func(unsigned long ip, + unsigned long pip) +{ + trace_selftest_test_probe3_cnt++; +} + +static int trace_selftest_test_global_cnt; +static void trace_selftest_test_global_func(unsigned long ip, + unsigned long pip) +{ + trace_selftest_test_global_cnt++; +} + +static int trace_selftest_test_dyn_cnt; +static void trace_selftest_test_dyn_func(unsigned long ip, + unsigned long pip) +{ + trace_selftest_test_dyn_cnt++; +} + +static struct ftrace_ops test_probe1 = { + .func = trace_selftest_test_probe1_func, +}; + +static struct ftrace_ops test_probe2 = { + .func = trace_selftest_test_probe2_func, +}; + +static struct ftrace_ops test_probe3 = { + .func = trace_selftest_test_probe3_func, +}; + +static struct ftrace_ops test_global = { + .func = trace_selftest_test_global_func, + .flags = FTRACE_OPS_FL_GLOBAL, +}; + +static void print_counts(void) +{ + printk("(%d %d %d %d %d) ", + trace_selftest_test_probe1_cnt, + trace_selftest_test_probe2_cnt, + trace_selftest_test_probe3_cnt, + trace_selftest_test_global_cnt, + trace_selftest_test_dyn_cnt); +} + +static void reset_counts(void) +{ + trace_selftest_test_probe1_cnt = 0; + trace_selftest_test_probe2_cnt = 0; + trace_selftest_test_probe3_cnt = 0; + trace_selftest_test_global_cnt = 0; + trace_selftest_test_dyn_cnt = 0; +} + +static int trace_selftest_ops(int cnt) +{ + int save_ftrace_enabled = ftrace_enabled; + struct ftrace_ops *dyn_ops; + char *func1_name; + char *func2_name; + int len1; + int len2; + int ret = -1; + + printk(KERN_CONT "PASSED\n"); + pr_info("Testing dynamic ftrace ops #%d: ", cnt); + + ftrace_enabled = 1; + reset_counts(); + + /* Handle PPC64 '.' name */ + func1_name = "*" __stringify(DYN_FTRACE_TEST_NAME); + func2_name = "*" __stringify(DYN_FTRACE_TEST_NAME2); + len1 = strlen(func1_name); + len2 = strlen(func2_name); + + /* + * Probe 1 will trace function 1. + * Probe 2 will trace function 2. + * Probe 3 will trace functions 1 and 2. + */ + ftrace_set_filter(&test_probe1, func1_name, len1, 1); + ftrace_set_filter(&test_probe2, func2_name, len2, 1); + ftrace_set_filter(&test_probe3, func1_name, len1, 1); + ftrace_set_filter(&test_probe3, func2_name, len2, 0); + + register_ftrace_function(&test_probe1); + register_ftrace_function(&test_probe2); + register_ftrace_function(&test_probe3); + register_ftrace_function(&test_global); + + DYN_FTRACE_TEST_NAME(); + + print_counts(); + + if (trace_selftest_test_probe1_cnt != 1) + goto out; + if (trace_selftest_test_probe2_cnt != 0) + goto out; + if (trace_selftest_test_probe3_cnt != 1) + goto out; + if (trace_selftest_test_global_cnt == 0) + goto out; + + DYN_FTRACE_TEST_NAME2(); + + print_counts(); + + if (trace_selftest_test_probe1_cnt != 1) + goto out; + if (trace_selftest_test_probe2_cnt != 1) + goto out; + if (trace_selftest_test_probe3_cnt != 2) + goto out; + + /* Add a dynamic probe */ + dyn_ops = kzalloc(sizeof(*dyn_ops), GFP_KERNEL); + if (!dyn_ops) { + printk("MEMORY ERROR "); + goto out; + } + + dyn_ops->func = trace_selftest_test_dyn_func; + + register_ftrace_function(dyn_ops); + + trace_selftest_test_global_cnt = 0; + + DYN_FTRACE_TEST_NAME(); + + print_counts(); + + if (trace_selftest_test_probe1_cnt != 2) + goto out_free; + if (trace_selftest_test_probe2_cnt != 1) + goto out_free; + if (trace_selftest_test_probe3_cnt != 3) + goto out_free; + if (trace_selftest_test_global_cnt == 0) + goto out; + if (trace_selftest_test_dyn_cnt == 0) + goto out_free; + + DYN_FTRACE_TEST_NAME2(); + + print_counts(); + + if (trace_selftest_test_probe1_cnt != 2) + goto out_free; + if (trace_selftest_test_probe2_cnt != 2) + goto out_free; + if (trace_selftest_test_probe3_cnt != 4) + goto out_free; + + ret = 0; + out_free: + unregister_ftrace_function(dyn_ops); + kfree(dyn_ops); + + out: + /* Purposely unregister in the same order */ + unregister_ftrace_function(&test_probe1); + unregister_ftrace_function(&test_probe2); + unregister_ftrace_function(&test_probe3); + unregister_ftrace_function(&test_global); + + /* Make sure everything is off */ + reset_counts(); + DYN_FTRACE_TEST_NAME(); + DYN_FTRACE_TEST_NAME(); + + if (trace_selftest_test_probe1_cnt || + trace_selftest_test_probe2_cnt || + trace_selftest_test_probe3_cnt || + trace_selftest_test_global_cnt || + trace_selftest_test_dyn_cnt) + ret = -1; + + ftrace_enabled = save_ftrace_enabled; + + return ret; +} + /* Test dynamic code modification and ftrace filters */ int trace_selftest_startup_dynamic_tracing(struct tracer *trace, struct trace_array *tr, @@ -166,16 +366,20 @@ int trace_selftest_startup_dynamic_tracing(struct tracer *trace, /* check the trace buffer */ ret = trace_test_buffer(tr, &count); - trace->reset(tr); tracing_start(); /* we should only have one item */ if (!ret && count != 1) { + trace->reset(tr); printk(KERN_CONT ".. filter failed count=%ld ..", count); ret = -1; goto out; } + /* Test the ops with global tracing running */ + ret = trace_selftest_ops(1); + trace->reset(tr); + out: ftrace_enabled = save_ftrace_enabled; tracer_enabled = save_tracer_enabled; @@ -183,6 +387,10 @@ int trace_selftest_startup_dynamic_tracing(struct tracer *trace, /* Enable tracing on all functions again */ ftrace_set_global_filter(NULL, 0, 1); + /* Test the ops with global tracing off */ + if (!ret) + ret = trace_selftest_ops(2); + return ret; } #else diff --git a/kernel/trace/trace_selftest_dynamic.c b/kernel/trace/trace_selftest_dynamic.c index 54dd77c..b4c475a 100644 --- a/kernel/trace/trace_selftest_dynamic.c +++ b/kernel/trace/trace_selftest_dynamic.c @@ -5,3 +5,9 @@ int DYN_FTRACE_TEST_NAME(void) /* used to call mcount */ return 0; } + +int DYN_FTRACE_TEST_NAME2(void) +{ + /* used to call mcount */ + return 0; +} -- cgit v0.10.2 From 69e3cea8d5fd52677f2b6219542d0f8b53fe4c80 Mon Sep 17 00:00:00 2001 From: Benjamin Herrenschmidt Date: Thu, 19 May 2011 13:07:12 +1000 Subject: powerpc/smp: Make start_secondary_resume available to all CPU variants This should fix SMP & Hotplug builds on FSL BookE and 476 Signed-off-by: Benjamin Herrenschmidt diff --git a/arch/powerpc/kernel/head_32.S b/arch/powerpc/kernel/head_32.S index c5c24be..98c4b29 100644 --- a/arch/powerpc/kernel/head_32.S +++ b/arch/powerpc/kernel/head_32.S @@ -890,15 +890,6 @@ __secondary_start: mtspr SPRN_SRR1,r4 SYNC RFI - -_GLOBAL(start_secondary_resume) - /* Reset stack */ - rlwinm r1,r1,0,0,(31-THREAD_SHIFT) /* current_thread_info() */ - addi r1,r1,THREAD_SIZE-STACK_FRAME_OVERHEAD - li r3,0 - std r3,0(r1) /* Zero the stack frame pointer */ - bl start_secondary - b . #endif /* CONFIG_SMP */ #ifdef CONFIG_KVM_BOOK3S_HANDLER diff --git a/arch/powerpc/kernel/misc_32.S b/arch/powerpc/kernel/misc_32.S index 094bd98..402560e 100644 --- a/arch/powerpc/kernel/misc_32.S +++ b/arch/powerpc/kernel/misc_32.S @@ -694,6 +694,17 @@ _GLOBAL(kernel_thread) addi r1,r1,16 blr +#ifdef CONFIG_SMP +_GLOBAL(start_secondary_resume) + /* Reset stack */ + rlwinm r1,r1,0,0,(31-THREAD_SHIFT) /* current_thread_info() */ + addi r1,r1,THREAD_SIZE-STACK_FRAME_OVERHEAD + li r3,0 + std r3,0(r1) /* Zero the stack frame pointer */ + bl start_secondary + b . +#endif /* CONFIG_SMP */ + /* * This routine is just here to keep GCC happy - sigh... */ -- cgit v0.10.2 From 35d215fbe4f4d3569f2adabd8d53510a26ecb9c5 Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Sun, 24 Apr 2011 15:04:31 +0000 Subject: powerpc/kexec: Fix build failure on 32-bit SMP Commit b987812b3fcaf70fdf0037589e5d2f5f2453e6ce left crash_kexec_wait_realmode() undefined for UP. Commit 7c7a81b53e581d727d069cc45df5510516faac31 defined it for UP but left it undefined for 32-bit SMP. Seems like people are getting confused by nested #ifdef's, so move the definitions of crash_kexec_wait_realmode() after the #ifdef CONFIG_SMP section. Compile-tested with 32-bit UP, 32-bit SMP and 64-bit SMP configurations. Signed-off-by: Ben Hutchings Tested-by: Paul Gortmaker Signed-off-by: Benjamin Herrenschmidt diff --git a/arch/powerpc/kernel/crash.c b/arch/powerpc/kernel/crash.c index 5b5e1f0..5eb0ee3 100644 --- a/arch/powerpc/kernel/crash.c +++ b/arch/powerpc/kernel/crash.c @@ -162,34 +162,6 @@ static void crash_kexec_prepare_cpus(int cpu) /* Leave the IPI callback set */ } -/* wait for all the CPUs to hit real mode but timeout if they don't come in */ -#ifdef CONFIG_PPC_STD_MMU_64 -static void crash_kexec_wait_realmode(int cpu) -{ - unsigned int msecs; - int i; - - msecs = 10000; - for (i=0; i < NR_CPUS && msecs > 0; i++) { - if (i == cpu) - continue; - - while (paca[i].kexec_state < KEXEC_STATE_REAL_MODE) { - barrier(); - if (!cpu_possible(i)) { - break; - } - if (!cpu_online(i)) { - break; - } - msecs--; - mdelay(1); - } - } - mb(); -} -#endif /* CONFIG_PPC_STD_MMU_64 */ - /* * This function will be called by secondary cpus or by kexec cpu * if soft-reset is activated to stop some CPUs. @@ -234,7 +206,6 @@ void crash_kexec_secondary(struct pt_regs *regs) } #else /* ! CONFIG_SMP */ -static inline void crash_kexec_wait_realmode(int cpu) {} static void crash_kexec_prepare_cpus(int cpu) { @@ -257,6 +228,36 @@ void crash_kexec_secondary(struct pt_regs *regs) } #endif /* CONFIG_SMP */ +/* wait for all the CPUs to hit real mode but timeout if they don't come in */ +#if defined(CONFIG_SMP) && defined(CONFIG_PPC_STD_MMU_64) +static void crash_kexec_wait_realmode(int cpu) +{ + unsigned int msecs; + int i; + + msecs = 10000; + for (i=0; i < NR_CPUS && msecs > 0; i++) { + if (i == cpu) + continue; + + while (paca[i].kexec_state < KEXEC_STATE_REAL_MODE) { + barrier(); + if (!cpu_possible(i)) { + break; + } + if (!cpu_online(i)) { + break; + } + msecs--; + mdelay(1); + } + } + mb(); +} +#else +static inline void crash_kexec_wait_realmode(int cpu) {} +#endif /* CONFIG_SMP && CONFIG_PPC_STD_MMU_64 */ + /* * Register a function to be called on shutdown. Only use this if you * can't reset your device in the second kernel. -- cgit v0.10.2 From c560bbceaf6b06e52f1ef20131b76a3fdc0a2c19 Mon Sep 17 00:00:00 2001 From: kerstin jonsson Date: Tue, 17 May 2011 23:57:11 +0000 Subject: powerpc/4xx: Fix regression in SMP on 476 commit c56e58537d504706954a06570b4034c04e5b7500 breaks SMP support in PPC_47x chip. secondary_ti must be set to current thread info before callin kick_cpu or else start_secondary_47x will jump into void when trying to return to c-code. In the current setup secondary_ti is initialized before the CPU idle task is started and only the boot core will start. I am not sure this is the correct solution, but it makes SMP possible in my chip. Note! The HOTPLUG support probably need some fixing to, There is no trampoline code available in head_44x.S - start_secondary_resume? Signed-off-by: Kerstin Jonsson Signed-off-by: Benjamin Herrenschmidt diff --git a/arch/powerpc/kernel/smp.c b/arch/powerpc/kernel/smp.c index cbdbb14..f2dcab7 100644 --- a/arch/powerpc/kernel/smp.c +++ b/arch/powerpc/kernel/smp.c @@ -410,8 +410,6 @@ int __cpuinit __cpu_up(unsigned int cpu) { int rc, c; - secondary_ti = current_set[cpu]; - if (smp_ops == NULL || (smp_ops->cpu_bootable && !smp_ops->cpu_bootable(cpu))) return -EINVAL; @@ -421,6 +419,8 @@ int __cpuinit __cpu_up(unsigned int cpu) if (rc) return rc; + secondary_ti = current_set[cpu]; + /* Make sure callin-map entry is 0 (can be leftover a CPU * hotplug */ -- cgit v0.10.2 From 61c4f2c81c61f73549928dfd9f3e8f26aa36a8cf Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Wed, 18 May 2011 21:06:34 -0700 Subject: Linux 2.6.39 diff --git a/Makefile b/Makefile index 41ea6fb..123d858 100644 --- a/Makefile +++ b/Makefile @@ -1,7 +1,7 @@ VERSION = 2 PATCHLEVEL = 6 SUBLEVEL = 39 -EXTRAVERSION = -rc7 +EXTRAVERSION = NAME = Flesh-Eating Bats with Fangs # *DOCUMENTATION* -- cgit v0.10.2 From c4f56af0f64ea894363b428b6590f5073047b455 Mon Sep 17 00:00:00 2001 From: Michal Marek Date: Tue, 5 Apr 2011 04:58:50 +0000 Subject: powerpc: Call gzip with -n The timestamps recorded in the .gz files add no value. Cc: Benjamin Herrenschmidt Cc: Paul Mackerras Cc: linuxppc-dev@lists.ozlabs.org Signed-off-by: Michal Marek Signed-off-by: Benjamin Herrenschmidt diff --git a/arch/powerpc/boot/wrapper b/arch/powerpc/boot/wrapper index dfa29cb..c74531a 100755 --- a/arch/powerpc/boot/wrapper +++ b/arch/powerpc/boot/wrapper @@ -258,7 +258,7 @@ if [ -z "$cacheit" -o ! -f "$vmz$gzip" -o "$vmz$gzip" -ot "$kernel" ]; then ${CROSS}objcopy $objflags "$kernel" "$vmz.$$" if [ -n "$gzip" ]; then - gzip -f -9 "$vmz.$$" + gzip -n -f -9 "$vmz.$$" fi if [ -n "$cacheit" ]; then @@ -343,7 +343,7 @@ coff) $objbin/hack-coff "$ofile" ;; cuboot*) - gzip -f -9 "$ofile" + gzip -n -f -9 "$ofile" ${MKIMAGE} -A ppc -O linux -T kernel -C gzip -a "$base" -e "$entry" \ $uboot_version -d "$ofile".gz "$ofile" ;; @@ -390,6 +390,6 @@ ps3) odir="$(dirname "$ofile.bin")" rm -f "$odir/otheros.bld" - gzip --force -9 --stdout "$ofile.bin" > "$odir/otheros.bld" + gzip -n --force -9 --stdout "$ofile.bin" > "$odir/otheros.bld" ;; esac -- cgit v0.10.2 From 93395febdb51ed812ac1003852f537177a172aad Mon Sep 17 00:00:00 2001 From: Justin Mattock Date: Tue, 5 Apr 2011 06:58:22 +0000 Subject: powerpc: Remove unused config in the Makefile The patch below removes an unused config variable found by using a kernel cleanup script. Note: I did try to cross compile these but hit erros while doing so.. (gcc is not setup to cross compile) and am unsure if anymore needs to be done. Please have a look if/when anybody has free time. Signed-off-by: Justin P. Mattock Signed-off-by: Benjamin Herrenschmidt diff --git a/arch/powerpc/kernel/Makefile b/arch/powerpc/kernel/Makefile index 82e0bed..9aab363 100644 --- a/arch/powerpc/kernel/Makefile +++ b/arch/powerpc/kernel/Makefile @@ -78,7 +78,6 @@ obj-$(CONFIG_PPC_FSL_BOOK3E) += cpu_setup_fsl_booke.o dbell.o obj-$(CONFIG_PPC_BOOK3E_64) += dbell.o extra-y := head_$(CONFIG_WORD_SIZE).o -extra-$(CONFIG_PPC_BOOK3E_32) := head_new_booke.o extra-$(CONFIG_40x) := head_40x.o extra-$(CONFIG_44x) := head_44x.o extra-$(CONFIG_FSL_BOOKE) := head_fsl_booke.o -- cgit v0.10.2 From 31355403dba5aa7a700c69f91cd6266092932701 Mon Sep 17 00:00:00 2001 From: Michal Marek Date: Thu, 5 May 2011 05:22:55 +0000 Subject: powerpc: Use the deterministic mode of ar Signed-off-by: Michal Marek Signed-off-by: Benjamin Herrenschmidt diff --git a/arch/powerpc/boot/Makefile b/arch/powerpc/boot/Makefile index 0e2a152..c26200b 100644 --- a/arch/powerpc/boot/Makefile +++ b/arch/powerpc/boot/Makefile @@ -128,7 +128,7 @@ quiet_cmd_bootas = BOOTAS $@ cmd_bootas = $(CROSS32CC) -Wp,-MD,$(depfile) $(BOOTAFLAGS) -c -o $@ $< quiet_cmd_bootar = BOOTAR $@ - cmd_bootar = $(CROSS32AR) -cr $@.$$$$ $(filter-out FORCE,$^); mv $@.$$$$ $@ + cmd_bootar = $(CROSS32AR) -cr$(KBUILD_ARFLAGS) $@.$$$$ $(filter-out FORCE,$^); mv $@.$$$$ $@ $(obj-libfdt): $(obj)/%.o: $(srctree)/scripts/dtc/libfdt/%.c FORCE $(call if_changed_dep,bootcc) -- cgit v0.10.2 From 767303349e052ae0cb9e6495a70870da3459eeb6 Mon Sep 17 00:00:00 2001 From: Nishanth Aravamudan Date: Fri, 6 May 2011 13:27:30 +0000 Subject: powerpc: Fix kexec with dynamic dma windows When we kexec we look for a particular property added by the first kernel, "linux,direct64-ddr-window-info", per-device where we already have set up dynamic dma windows. The current code, though, wasn't initializing the size of this property and thus when we kexec'd, we would find the property but read uninitialized memory resulting in garbage ddw values for the kexec'd kernel and panics. Fix this by setting the size at enable_ddw() time and ensuring that the size of the found property is valid at dupe_ddw_if_kexec() time. Signed-off-by: Nishanth Aravamudan Signed-off-by: Benjamin Herrenschmidt diff --git a/arch/powerpc/platforms/pseries/iommu.c b/arch/powerpc/platforms/pseries/iommu.c index 6d5412a..019009b 100644 --- a/arch/powerpc/platforms/pseries/iommu.c +++ b/arch/powerpc/platforms/pseries/iommu.c @@ -730,16 +730,20 @@ static u64 dupe_ddw_if_kexec(struct pci_dev *dev, struct device_node *pdn) pcidn = PCI_DN(dn); direct64 = of_get_property(pdn, DIRECT64_PROPNAME, &len); if (direct64) { - window = kzalloc(sizeof(*window), GFP_KERNEL); - if (!window) { + if (len < sizeof(struct dynamic_dma_window_prop)) { remove_ddw(pdn); } else { - window->device = pdn; - window->prop = direct64; - spin_lock(&direct_window_list_lock); - list_add(&window->list, &direct_window_list); - spin_unlock(&direct_window_list_lock); - dma_addr = direct64->dma_base; + window = kzalloc(sizeof(*window), GFP_KERNEL); + if (!window) { + remove_ddw(pdn); + } else { + window->device = pdn; + window->prop = direct64; + spin_lock(&direct_window_list_lock); + list_add(&window->list, &direct_window_list); + spin_unlock(&direct_window_list_lock); + dma_addr = direct64->dma_base; + } } } @@ -833,7 +837,7 @@ static u64 enable_ddw(struct pci_dev *dev, struct device_node *pdn) struct device_node *dn; const u32 *uninitialized_var(ddr_avail); struct direct_window *window; - struct property *uninitialized_var(win64); + struct property *win64; struct dynamic_dma_window_prop *ddwprop; mutex_lock(&direct_window_init_mutex); @@ -907,6 +911,7 @@ static u64 enable_ddw(struct pci_dev *dev, struct device_node *pdn) } win64->name = kstrdup(DIRECT64_PROPNAME, GFP_KERNEL); win64->value = ddwprop = kmalloc(sizeof(*ddwprop), GFP_KERNEL); + win64->length = sizeof(*ddwprop); if (!win64->name || !win64->value) { dev_info(&dev->dev, "couldn't allocate property name and value\n"); -- cgit v0.10.2 From af442a1baa6d00117cc7e7377ce7e6a545268684 Mon Sep 17 00:00:00 2001 From: Nishanth Aravamudan Date: Wed, 4 May 2011 12:54:16 +0000 Subject: powerpc: Ensure dtl buffers do not cross 4k boundary Future releases of fimrware will enforce a requirement that DTL buffers do not cross a 4k boundary. Commit 127493d5dc73589cbe00ea5ec8357cc2a4c0d82a satisfies this requirement for CONFIG_VIRT_CPU_ACCOUNTING=y kernels, but if !CONFIG_VIRT_CPU_ACCOUNTING && CONFIG_DTL=y, the current code will fail at dtl registration time. Fix this by making the kmem cache from 127493d5dc73589cbe00ea5ec8357cc2a4c0d82a visible outside of setup.c and using the same cache in both dtl.c and setup.c. This requires a bit of reorganization to ensure ordering of the kmem cache and buffer allocations. Note: Since firmware now limits the size of the buffer, I made dtl_buf_entries read-only in debugfs. Tested with upcoming firmware with the 4 combinations of CONFIG_VIRT_CPU_ACCOUNTING and CONFIG_DTL. Signed-off-by: Nishanth Aravamudan Cc: Paul Mackerras Cc: Anton Blanchard Cc: linuxppc-dev@lists.ozlabs.org Signed-off-by: Benjamin Herrenschmidt diff --git a/arch/powerpc/include/asm/lppaca.h b/arch/powerpc/include/asm/lppaca.h index a077adc..e0298d2 100644 --- a/arch/powerpc/include/asm/lppaca.h +++ b/arch/powerpc/include/asm/lppaca.h @@ -210,6 +210,8 @@ struct dtl_entry { #define DISPATCH_LOG_BYTES 4096 /* bytes per cpu */ #define N_DISPATCH_LOG (DISPATCH_LOG_BYTES / sizeof(struct dtl_entry)) +extern struct kmem_cache *dtl_cache; + /* * When CONFIG_VIRT_CPU_ACCOUNTING = y, the cpu accounting code controls * reading from the dispatch trace log. If other code wants to consume diff --git a/arch/powerpc/platforms/pseries/dtl.c b/arch/powerpc/platforms/pseries/dtl.c index c371bc0..e919007 100644 --- a/arch/powerpc/platforms/pseries/dtl.c +++ b/arch/powerpc/platforms/pseries/dtl.c @@ -52,10 +52,10 @@ static u8 dtl_event_mask = 0x7; /* - * Size of per-cpu log buffers. Default is just under 16 pages worth. + * Size of per-cpu log buffers. Firmware requires that the buffer does + * not cross a 4k boundary. */ -static int dtl_buf_entries = (16 * 85); - +static int dtl_buf_entries = N_DISPATCH_LOG; #ifdef CONFIG_VIRT_CPU_ACCOUNTING struct dtl_ring { @@ -151,7 +151,7 @@ static int dtl_start(struct dtl *dtl) /* Register our dtl buffer with the hypervisor. The HV expects the * buffer size to be passed in the second word of the buffer */ - ((u32 *)dtl->buf)[1] = dtl->buf_entries * sizeof(struct dtl_entry); + ((u32 *)dtl->buf)[1] = DISPATCH_LOG_BYTES; hwcpu = get_hard_smp_processor_id(dtl->cpu); addr = __pa(dtl->buf); @@ -196,13 +196,15 @@ static int dtl_enable(struct dtl *dtl) long int rc; struct dtl_entry *buf = NULL; + if (!dtl_cache) + return -ENOMEM; + /* only allow one reader */ if (dtl->buf) return -EBUSY; n_entries = dtl_buf_entries; - buf = kmalloc_node(n_entries * sizeof(struct dtl_entry), - GFP_KERNEL, cpu_to_node(dtl->cpu)); + buf = kmem_cache_alloc_node(dtl_cache, GFP_KERNEL, cpu_to_node(dtl->cpu)); if (!buf) { printk(KERN_WARNING "%s: buffer alloc failed for cpu %d\n", __func__, dtl->cpu); @@ -223,7 +225,7 @@ static int dtl_enable(struct dtl *dtl) spin_unlock(&dtl->lock); if (rc) - kfree(buf); + kmem_cache_free(dtl_cache, buf); return rc; } @@ -231,7 +233,7 @@ static void dtl_disable(struct dtl *dtl) { spin_lock(&dtl->lock); dtl_stop(dtl); - kfree(dtl->buf); + kmem_cache_free(dtl_cache, dtl->buf); dtl->buf = NULL; dtl->buf_entries = 0; spin_unlock(&dtl->lock); @@ -365,7 +367,7 @@ static int dtl_init(void) event_mask_file = debugfs_create_x8("dtl_event_mask", 0600, dtl_dir, &dtl_event_mask); - buf_entries_file = debugfs_create_u32("dtl_buf_entries", 0600, + buf_entries_file = debugfs_create_u32("dtl_buf_entries", 0400, dtl_dir, &dtl_buf_entries); if (!event_mask_file || !buf_entries_file) { diff --git a/arch/powerpc/platforms/pseries/setup.c b/arch/powerpc/platforms/pseries/setup.c index 1689adc..593acce 100644 --- a/arch/powerpc/platforms/pseries/setup.c +++ b/arch/powerpc/platforms/pseries/setup.c @@ -278,6 +278,8 @@ static struct notifier_block pci_dn_reconfig_nb = { .notifier_call = pci_dn_reconfig_notifier, }; +struct kmem_cache *dtl_cache; + #ifdef CONFIG_VIRT_CPU_ACCOUNTING /* * Allocate space for the dispatch trace log for all possible cpus @@ -289,18 +291,12 @@ static int alloc_dispatch_logs(void) int cpu, ret; struct paca_struct *pp; struct dtl_entry *dtl; - struct kmem_cache *dtl_cache; if (!firmware_has_feature(FW_FEATURE_SPLPAR)) return 0; - dtl_cache = kmem_cache_create("dtl", DISPATCH_LOG_BYTES, - DISPATCH_LOG_BYTES, 0, NULL); - if (!dtl_cache) { - pr_warn("Failed to create dispatch trace log buffer cache\n"); - pr_warn("Stolen time statistics will be unreliable\n"); + if (!dtl_cache) return 0; - } for_each_possible_cpu(cpu) { pp = &paca[cpu]; @@ -334,10 +330,27 @@ static int alloc_dispatch_logs(void) return 0; } - -early_initcall(alloc_dispatch_logs); +#else /* !CONFIG_VIRT_CPU_ACCOUNTING */ +static inline int alloc_dispatch_logs(void) +{ + return 0; +} #endif /* CONFIG_VIRT_CPU_ACCOUNTING */ +static int alloc_dispatch_log_kmem_cache(void) +{ + dtl_cache = kmem_cache_create("dtl", DISPATCH_LOG_BYTES, + DISPATCH_LOG_BYTES, 0, NULL); + if (!dtl_cache) { + pr_warn("Failed to create dispatch trace log buffer cache\n"); + pr_warn("Stolen time statistics will be unreliable\n"); + return 0; + } + + return alloc_dispatch_logs(); +} +early_initcall(alloc_dispatch_log_kmem_cache); + static void __init pSeries_setup_arch(void) { /* Discover PIC type and setup ppc_md accordingly */ -- cgit v0.10.2 From 2a2c29c1a581319f4485af55e8d628d89e8f2583 Mon Sep 17 00:00:00 2001 From: Stratos Psomadakis Date: Sat, 7 May 2011 04:11:31 +0000 Subject: powerpc/mm: Fix compiler warning in pgtable-ppc64.h [-Wunused-but-set-variable] The variable 'old' is set but not used in the wrprotect functions in arch/powerpc/include/asm/pgtable-ppc64.h, which can trigger a compiler warning. Remove the variable, since it's not used anyway. Signed-off-by: Stratos Psomadakis Signed-off-by: Benjamin Herrenschmidt diff --git a/arch/powerpc/include/asm/pgtable-ppc64.h b/arch/powerpc/include/asm/pgtable-ppc64.h index 2b09cd5..81576ee 100644 --- a/arch/powerpc/include/asm/pgtable-ppc64.h +++ b/arch/powerpc/include/asm/pgtable-ppc64.h @@ -257,21 +257,20 @@ static inline int __ptep_test_and_clear_young(struct mm_struct *mm, static inline void ptep_set_wrprotect(struct mm_struct *mm, unsigned long addr, pte_t *ptep) { - unsigned long old; - if ((pte_val(*ptep) & _PAGE_RW) == 0) - return; - old = pte_update(mm, addr, ptep, _PAGE_RW, 0); + if ((pte_val(*ptep) & _PAGE_RW) == 0) + return; + + pte_update(mm, addr, ptep, _PAGE_RW, 0); } static inline void huge_ptep_set_wrprotect(struct mm_struct *mm, unsigned long addr, pte_t *ptep) { - unsigned long old; - if ((pte_val(*ptep) & _PAGE_RW) == 0) return; - old = pte_update(mm, addr, ptep, _PAGE_RW, 1); + + pte_update(mm, addr, ptep, _PAGE_RW, 1); } /* -- cgit v0.10.2 From 32218bdd31fc9367c0babd6f7d309c6856a5c7da Mon Sep 17 00:00:00 2001 From: Anton Blanchard Date: Sun, 8 May 2011 13:18:27 +0000 Subject: powerpc/pseries: Enable Emulex and Qlogic 10Gbit cards Enable the Qlogic and Emulex 10Gbit adapters. Signed-off-by: Anton Blanchard Signed-off-by: Benjamin Herrenschmidt diff --git a/arch/powerpc/configs/pseries_defconfig b/arch/powerpc/configs/pseries_defconfig index 249ddd0..e4abe27 100644 --- a/arch/powerpc/configs/pseries_defconfig +++ b/arch/powerpc/configs/pseries_defconfig @@ -197,6 +197,8 @@ CONFIG_S2IO=m CONFIG_MYRI10GE=m CONFIG_NETXEN_NIC=m CONFIG_MLX4_EN=m +CONFIG_QLGE=m +CONFIG_BE2NET=m CONFIG_PPP=m CONFIG_PPP_ASYNC=m CONFIG_PPP_SYNC_TTY=m -- cgit v0.10.2 From 37e0c21e9b5b6d6fd38a444762076c84c6170598 Mon Sep 17 00:00:00 2001 From: Anton Blanchard Date: Sun, 8 May 2011 13:19:30 +0000 Subject: powerpc/pseries: Enable iSCSI support for a number of cards Enable iSCSI support for a number of cards. We had the base networking devices enabled but forgot to enable iSCSI. Signed-off-by: Anton Blanchard Signed-off-by: Benjamin Herrenschmidt diff --git a/arch/powerpc/configs/pseries_defconfig b/arch/powerpc/configs/pseries_defconfig index e4abe27..7de1386 100644 --- a/arch/powerpc/configs/pseries_defconfig +++ b/arch/powerpc/configs/pseries_defconfig @@ -146,12 +146,18 @@ CONFIG_SCSI_MULTI_LUN=y CONFIG_SCSI_CONSTANTS=y CONFIG_SCSI_FC_ATTRS=y CONFIG_SCSI_SAS_ATTRS=m +CONFIG_SCSI_CXGB3_ISCSI=m +CONFIG_SCSI_CXGB4_ISCSI=m +CONFIG_SCSI_BNX2_ISCSI=m +CONFIG_SCSI_BNX2_ISCSI=m +CONFIG_BE2ISCSI=m CONFIG_SCSI_IBMVSCSI=y CONFIG_SCSI_IBMVFC=m CONFIG_SCSI_SYM53C8XX_2=y CONFIG_SCSI_SYM53C8XX_DMA_ADDRESSING_MODE=0 CONFIG_SCSI_IPR=y CONFIG_SCSI_QLA_FC=m +CONFIG_SCSI_QLA_ISCSI=m CONFIG_SCSI_LPFC=m CONFIG_ATA=y # CONFIG_ATA_SFF is not set -- cgit v0.10.2 From d988f0e3f84cb8a4f85ccdbca6f6fefcc37bedcb Mon Sep 17 00:00:00 2001 From: Anton Blanchard Date: Sun, 8 May 2011 21:18:38 +0000 Subject: powerpc: Simplify 4k/64k copy_page logic To make it easier to add optimised versions of copy_page, remove the 4kB loop for 64kB pages and just do all the work in copy_page. Signed-off-by: Anton Blanchard Signed-off-by: Benjamin Herrenschmidt diff --git a/arch/powerpc/include/asm/page_64.h b/arch/powerpc/include/asm/page_64.h index 488c52e..9356262 100644 --- a/arch/powerpc/include/asm/page_64.h +++ b/arch/powerpc/include/asm/page_64.h @@ -59,24 +59,7 @@ static __inline__ void clear_page(void *addr) : "ctr", "memory"); } -extern void copy_4K_page(void *to, void *from); - -#ifdef CONFIG_PPC_64K_PAGES -static inline void copy_page(void *to, void *from) -{ - unsigned int i; - for (i=0; i < (1 << (PAGE_SHIFT - 12)); i++) { - copy_4K_page(to, from); - to += 4096; - from += 4096; - } -} -#else /* CONFIG_PPC_64K_PAGES */ -static inline void copy_page(void *to, void *from) -{ - copy_4K_page(to, from); -} -#endif /* CONFIG_PPC_64K_PAGES */ +extern void copy_page(void *to, void *from); /* Log 2 of page table size */ extern u64 ppc64_pft_size; diff --git a/arch/powerpc/kernel/ppc_ksyms.c b/arch/powerpc/kernel/ppc_ksyms.c index ef3ef56..7d28f54 100644 --- a/arch/powerpc/kernel/ppc_ksyms.c +++ b/arch/powerpc/kernel/ppc_ksyms.c @@ -54,7 +54,6 @@ extern void single_step_exception(struct pt_regs *regs); extern int sys_sigreturn(struct pt_regs *regs); EXPORT_SYMBOL(clear_pages); -EXPORT_SYMBOL(copy_page); EXPORT_SYMBOL(ISA_DMA_THRESHOLD); EXPORT_SYMBOL(DMA_MODE_READ); EXPORT_SYMBOL(DMA_MODE_WRITE); @@ -88,9 +87,7 @@ EXPORT_SYMBOL(__copy_tofrom_user); EXPORT_SYMBOL(__clear_user); EXPORT_SYMBOL(__strncpy_from_user); EXPORT_SYMBOL(__strnlen_user); -#ifdef CONFIG_PPC64 -EXPORT_SYMBOL(copy_4K_page); -#endif +EXPORT_SYMBOL(copy_page); #if defined(CONFIG_PCI) && defined(CONFIG_PPC32) EXPORT_SYMBOL(isa_io_base); diff --git a/arch/powerpc/lib/copypage_64.S b/arch/powerpc/lib/copypage_64.S index 4d4eeb9..53dcb6b 100644 --- a/arch/powerpc/lib/copypage_64.S +++ b/arch/powerpc/lib/copypage_64.S @@ -6,6 +6,7 @@ * as published by the Free Software Foundation; either version * 2 of the License, or (at your option) any later version. */ +#include #include #include #include @@ -15,9 +16,9 @@ PPC64_CACHES: .tc ppc64_caches[TC],ppc64_caches .section ".text" - -_GLOBAL(copy_4K_page) - li r5,4096 /* 4K page size */ +_GLOBAL(copy_page) + lis r5,PAGE_SIZE@h + ori r5,r5,PAGE_SIZE@l BEGIN_FTR_SECTION ld r10,PPC64_CACHES@toc(r2) lwz r11,DCACHEL1LOGLINESIZE(r10) /* log2 of cache line size */ -- cgit v0.10.2 From ba00ce1d6e08ad06f19f2ac53fd5c60bbe3fbeeb Mon Sep 17 00:00:00 2001 From: Anton Blanchard Date: Sun, 8 May 2011 21:20:19 +0000 Subject: powerpc: Remove static branch hint in giveup_altivec A static branch hint will override dynamic branch prediction on recent POWER CPUs. Since we are about to use more altivec in the kernel remove the static hint in giveup_altivec that assumes a userspace task is using altivec. Signed-off-by: Anton Blanchard Signed-off-by: Benjamin Herrenschmidt diff --git a/arch/powerpc/kernel/vector.S b/arch/powerpc/kernel/vector.S index 9de6f39..4d5a3ed 100644 --- a/arch/powerpc/kernel/vector.S +++ b/arch/powerpc/kernel/vector.S @@ -102,7 +102,7 @@ _GLOBAL(giveup_altivec) MTMSRD(r5) /* enable use of VMX now */ isync PPC_LCMPI 0,r3,0 - beqlr- /* if no previous owner, done */ + beqlr /* if no previous owner, done */ addi r3,r3,THREAD /* want THREAD of task */ PPC_LL r5,PT_REGS(r3) PPC_LCMPI 0,r5,0 -- cgit v0.10.2 From f5f0307f42d39a51a925ca4841f76a2f2ea330ff Mon Sep 17 00:00:00 2001 From: Anton Blanchard Date: Sun, 8 May 2011 21:36:44 +0000 Subject: powerpc: Improve scheduling of system call entry instructions After looking at our system call path, Mary Brown suggested that we should put all mfspr SRR* instructions before any mtspr SRR*. To test this I used a very simple null syscall (actually getppid) testcase at http://ozlabs.org/~anton/junkcode/null_syscall.c I tested with the following changes against the pseries_defconfig: CONFIG_VIRT_CPU_ACCOUNTING=n CONFIG_AUDIT=n to remove the overhead of virtual CPU accounting and syscall auditing. POWER6: baseline: mean = 757.2 cycles sd = 2.108 modified: mean = 759.1 cycles sd = 2.020 POWER7: baseline: mean = 411.4 cycles sd = 0.138 modified: mean = 404.1 cycles sd = 0.109 So we have 1.77% improvement on POWER7 which looks significant. The POWER6 suggest a 0.25% slowdown, but the results are within 1 standard deviation and may be in the noise. Signed-off-by: Anton Blanchard Signed-off-by: Benjamin Herrenschmidt diff --git a/arch/powerpc/kernel/exceptions-64s.S b/arch/powerpc/kernel/exceptions-64s.S index 0ec3b42..a85f487 100644 --- a/arch/powerpc/kernel/exceptions-64s.S +++ b/arch/powerpc/kernel/exceptions-64s.S @@ -211,11 +211,11 @@ END_FTR_SECTION_IFSET(CPU_FTR_REAL_LE) mr r9,r13 GET_PACA(r13) mfspr r11,SPRN_SRR0 - ld r12,PACAKBASE(r13) - ld r10,PACAKMSR(r13) - LOAD_HANDLER(r12, system_call_entry) - mtspr SPRN_SRR0,r12 mfspr r12,SPRN_SRR1 + ld r10,PACAKBASE(r13) + LOAD_HANDLER(r10, system_call_entry) + mtspr SPRN_SRR0,r10 + ld r10,PACAKMSR(r13) mtspr SPRN_SRR1,r10 rfid b . /* prevent speculative execution */ -- cgit v0.10.2 From be135f40899cb3334faa7d2e27025055da311ec4 Mon Sep 17 00:00:00 2001 From: Anton Blanchard Date: Sun, 8 May 2011 21:41:59 +0000 Subject: powerpc: Add ioremap_wc Add ioremap_wc so drivers can request write combining on kernel mappings. Signed-off-by: Anton Blanchard Signed-off-by: Benjamin Herrenschmidt diff --git a/arch/powerpc/include/asm/io.h b/arch/powerpc/include/asm/io.h index 2f365f5..662d2ed 100644 --- a/arch/powerpc/include/asm/io.h +++ b/arch/powerpc/include/asm/io.h @@ -2,6 +2,8 @@ #define _ASM_POWERPC_IO_H #ifdef __KERNEL__ +#define ARCH_HAS_IOREMAP_WC + /* * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -628,6 +630,8 @@ static inline void iosync(void) * * * ioremap_nocache is identical to ioremap * + * * ioremap_wc enables write combining + * * * iounmap undoes such a mapping and can be hooked * * * __ioremap_at (and the pending __iounmap_at) are low level functions to @@ -648,6 +652,7 @@ static inline void iosync(void) extern void __iomem *ioremap(phys_addr_t address, unsigned long size); extern void __iomem *ioremap_flags(phys_addr_t address, unsigned long size, unsigned long flags); +extern void __iomem *ioremap_wc(phys_addr_t address, unsigned long size); #define ioremap_nocache(addr, size) ioremap((addr), (size)) #define ioremap_prot(addr, size, prot) ioremap_flags((addr), (size), (prot)) diff --git a/arch/powerpc/mm/pgtable_32.c b/arch/powerpc/mm/pgtable_32.c index 8dc41c0..fca98f8 100644 --- a/arch/powerpc/mm/pgtable_32.c +++ b/arch/powerpc/mm/pgtable_32.c @@ -133,6 +133,14 @@ ioremap(phys_addr_t addr, unsigned long size) EXPORT_SYMBOL(ioremap); void __iomem * +ioremap_wc(phys_addr_t addr, unsigned long size) +{ + return __ioremap_caller(addr, size, _PAGE_NO_CACHE, + __builtin_return_address(0)); +} +EXPORT_SYMBOL(ioremap_wc); + +void __iomem * ioremap_flags(phys_addr_t addr, unsigned long size, unsigned long flags) { /* writeable implies dirty for kernel addresses */ diff --git a/arch/powerpc/mm/pgtable_64.c b/arch/powerpc/mm/pgtable_64.c index 88927a0..1146fc6 100644 --- a/arch/powerpc/mm/pgtable_64.c +++ b/arch/powerpc/mm/pgtable_64.c @@ -255,6 +255,16 @@ void __iomem * ioremap(phys_addr_t addr, unsigned long size) return __ioremap_caller(addr, size, flags, caller); } +void __iomem * ioremap_wc(phys_addr_t addr, unsigned long size) +{ + unsigned long flags = _PAGE_NO_CACHE; + void *caller = __builtin_return_address(0); + + if (ppc_md.ioremap) + return ppc_md.ioremap(addr, size, flags, caller); + return __ioremap_caller(addr, size, flags, caller); +} + void __iomem * ioremap_flags(phys_addr_t addr, unsigned long size, unsigned long flags) { @@ -311,6 +321,7 @@ void iounmap(volatile void __iomem *token) } EXPORT_SYMBOL(ioremap); +EXPORT_SYMBOL(ioremap_wc); EXPORT_SYMBOL(ioremap_flags); EXPORT_SYMBOL(__ioremap); EXPORT_SYMBOL(__ioremap_at); -- cgit v0.10.2 From 40f1ce7fb7e8b5d4d0821c0f3dc866cb1d47d99c Mon Sep 17 00:00:00 2001 From: Anton Blanchard Date: Sun, 8 May 2011 21:43:47 +0000 Subject: powerpc: Remove ioremap_flags We have a confusing number of ioremap functions. Make things just a bit simpler by merging ioremap_flags and ioremap_prot. Signed-off-by: Anton Blanchard Signed-off-by: Benjamin Herrenschmidt diff --git a/arch/powerpc/include/asm/io.h b/arch/powerpc/include/asm/io.h index 662d2ed..45698d5 100644 --- a/arch/powerpc/include/asm/io.h +++ b/arch/powerpc/include/asm/io.h @@ -624,9 +624,8 @@ static inline void iosync(void) * * ioremap is the standard one and provides non-cacheable guarded mappings * and can be hooked by the platform via ppc_md * - * * ioremap_flags allows to specify the page flags as an argument and can - * also be hooked by the platform via ppc_md. ioremap_prot is the exact - * same thing as ioremap_flags. + * * ioremap_prot allows to specify the page flags as an argument and can + * also be hooked by the platform via ppc_md. * * * ioremap_nocache is identical to ioremap * @@ -639,7 +638,7 @@ static inline void iosync(void) * currently be hooked. Must be page aligned. * * * __ioremap is the low level implementation used by ioremap and - * ioremap_flags and cannot be hooked (but can be used by a hook on one + * ioremap_prot and cannot be hooked (but can be used by a hook on one * of the previous ones) * * * __ioremap_caller is the same as above but takes an explicit caller @@ -650,11 +649,10 @@ static inline void iosync(void) * */ extern void __iomem *ioremap(phys_addr_t address, unsigned long size); -extern void __iomem *ioremap_flags(phys_addr_t address, unsigned long size, - unsigned long flags); +extern void __iomem *ioremap_prot(phys_addr_t address, unsigned long size, + unsigned long flags); extern void __iomem *ioremap_wc(phys_addr_t address, unsigned long size); #define ioremap_nocache(addr, size) ioremap((addr), (size)) -#define ioremap_prot(addr, size, prot) ioremap_flags((addr), (size), (prot)) extern void iounmap(volatile void __iomem *addr); diff --git a/arch/powerpc/lib/devres.c b/arch/powerpc/lib/devres.c index deac4d3..e91615a 100644 --- a/arch/powerpc/lib/devres.c +++ b/arch/powerpc/lib/devres.c @@ -9,11 +9,11 @@ #include /* devres_*(), devm_ioremap_release() */ #include -#include /* ioremap_flags() */ +#include /* ioremap_prot() */ #include /* EXPORT_SYMBOL() */ /** - * devm_ioremap_prot - Managed ioremap_flags() + * devm_ioremap_prot - Managed ioremap_prot() * @dev: Generic device to remap IO address for * @offset: BUS offset to map * @size: Size of map @@ -31,7 +31,7 @@ void __iomem *devm_ioremap_prot(struct device *dev, resource_size_t offset, if (!ptr) return NULL; - addr = ioremap_flags(offset, size, flags); + addr = ioremap_prot(offset, size, flags); if (addr) { *ptr = addr; devres_add(dev, ptr); diff --git a/arch/powerpc/mm/pgtable_32.c b/arch/powerpc/mm/pgtable_32.c index fca98f8..51f8795 100644 --- a/arch/powerpc/mm/pgtable_32.c +++ b/arch/powerpc/mm/pgtable_32.c @@ -141,7 +141,7 @@ ioremap_wc(phys_addr_t addr, unsigned long size) EXPORT_SYMBOL(ioremap_wc); void __iomem * -ioremap_flags(phys_addr_t addr, unsigned long size, unsigned long flags) +ioremap_prot(phys_addr_t addr, unsigned long size, unsigned long flags) { /* writeable implies dirty for kernel addresses */ if (flags & _PAGE_RW) @@ -160,7 +160,7 @@ ioremap_flags(phys_addr_t addr, unsigned long size, unsigned long flags) return __ioremap_caller(addr, size, flags, __builtin_return_address(0)); } -EXPORT_SYMBOL(ioremap_flags); +EXPORT_SYMBOL(ioremap_prot); void __iomem * __ioremap(phys_addr_t addr, unsigned long size, unsigned long flags) diff --git a/arch/powerpc/mm/pgtable_64.c b/arch/powerpc/mm/pgtable_64.c index 1146fc6..6e595f6 100644 --- a/arch/powerpc/mm/pgtable_64.c +++ b/arch/powerpc/mm/pgtable_64.c @@ -265,7 +265,7 @@ void __iomem * ioremap_wc(phys_addr_t addr, unsigned long size) return __ioremap_caller(addr, size, flags, caller); } -void __iomem * ioremap_flags(phys_addr_t addr, unsigned long size, +void __iomem * ioremap_prot(phys_addr_t addr, unsigned long size, unsigned long flags) { void *caller = __builtin_return_address(0); @@ -322,7 +322,7 @@ void iounmap(volatile void __iomem *token) EXPORT_SYMBOL(ioremap); EXPORT_SYMBOL(ioremap_wc); -EXPORT_SYMBOL(ioremap_flags); +EXPORT_SYMBOL(ioremap_prot); EXPORT_SYMBOL(__ioremap); EXPORT_SYMBOL(__ioremap_at); EXPORT_SYMBOL(iounmap); diff --git a/arch/powerpc/platforms/ps3/spu.c b/arch/powerpc/platforms/ps3/spu.c index 39a472e..375a9f9 100644 --- a/arch/powerpc/platforms/ps3/spu.c +++ b/arch/powerpc/platforms/ps3/spu.c @@ -197,7 +197,7 @@ static void spu_unmap(struct spu *spu) * The current HV requires the spu shadow regs to be mapped with the * PTE page protection bits set as read-only (PP=3). This implementation * uses the low level __ioremap() to bypass the page protection settings - * inforced by ioremap_flags() to get the needed PTE bits set for the + * inforced by ioremap_prot() to get the needed PTE bits set for the * shadow regs. */ @@ -214,7 +214,7 @@ static int __init setup_areas(struct spu *spu) goto fail_ioremap; } - spu->local_store = (__force void *)ioremap_flags(spu->local_store_phys, + spu->local_store = (__force void *)ioremap_prot(spu->local_store_phys, LS_SIZE, _PAGE_NO_CACHE); if (!spu->local_store) { diff --git a/arch/powerpc/sysdev/axonram.c b/arch/powerpc/sysdev/axonram.c index 1636dd8..bd0d540 100644 --- a/arch/powerpc/sysdev/axonram.c +++ b/arch/powerpc/sysdev/axonram.c @@ -216,7 +216,7 @@ static int axon_ram_probe(struct platform_device *device) AXON_RAM_DEVICE_NAME, axon_ram_bank_id, bank->size >> 20); bank->ph_addr = resource.start; - bank->io_addr = (unsigned long) ioremap_flags( + bank->io_addr = (unsigned long) ioremap_prot( bank->ph_addr, bank->size, _PAGE_NO_CACHE); if (bank->io_addr == 0) { dev_err(&device->dev, "ioremap() failed\n"); diff --git a/arch/powerpc/sysdev/fsl_85xx_cache_sram.c b/arch/powerpc/sysdev/fsl_85xx_cache_sram.c index 54fb192..1164158 100644 --- a/arch/powerpc/sysdev/fsl_85xx_cache_sram.c +++ b/arch/powerpc/sysdev/fsl_85xx_cache_sram.c @@ -106,10 +106,10 @@ int __init instantiate_cache_sram(struct platform_device *dev, goto out_free; } - cache_sram->base_virt = ioremap_flags(cache_sram->base_phys, + cache_sram->base_virt = ioremap_prot(cache_sram->base_phys, cache_sram->size, _PAGE_COHERENT | PAGE_KERNEL); if (!cache_sram->base_virt) { - dev_err(&dev->dev, "%s: ioremap_flags failed\n", + dev_err(&dev->dev, "%s: ioremap_prot failed\n", dev->dev.of_node->full_name); ret = -ENOMEM; goto out_release; -- cgit v0.10.2 From eb0dd411bd90dd5ad3f1936930d3e83d9ef95561 Mon Sep 17 00:00:00 2001 From: Nishanth Aravamudan Date: Mon, 9 May 2011 12:58:03 +0000 Subject: pseries/iommu: Restore iommu table pointer when restoring iommu ops When we swtich to direct dma ops, we set the dma data union to have the dma offset. When we switch back to iommu table ops because of a later dma_set_mask, we need to restore the iommu table pointer. Without this change, crashes have been observed on kexec where (for reasons still being investigated) we fall back to a 32-bit dma mask on a particular device and then panic because the table pointer is not valid. The easiset way to find this value is to call pci_dma_dev_setup_pSeriesLP which will search up the pci tree until it finds the node with the table. Signed-off-by: Nishanth Aravamudan Cc: Milton Miller Cc: Paul Mackerras Cc: Anton Blanchard Cc: linuxppc-dev@lists.ozlabs.org Signed-off-by: Benjamin Herrenschmidt diff --git a/arch/powerpc/platforms/pseries/iommu.c b/arch/powerpc/platforms/pseries/iommu.c index 019009b..48eec3b 100644 --- a/arch/powerpc/platforms/pseries/iommu.c +++ b/arch/powerpc/platforms/pseries/iommu.c @@ -1029,10 +1029,10 @@ static int dma_set_mask_pSeriesLP(struct device *dev, u64 dma_mask) if (!dev->dma_mask || !dma_supported(dev, dma_mask)) return -EIO; + pdev = to_pci_dev(dev); + /* only attempt to use a new window if 64-bit DMA is requested */ if (!disable_ddw && dma_mask == DMA_BIT_MASK(64)) { - pdev = to_pci_dev(dev); - dn = pci_device_to_OF_node(pdev); dev_dbg(dev, "node is %s\n", dn->full_name); @@ -1063,6 +1063,7 @@ static int dma_set_mask_pSeriesLP(struct device *dev, u64 dma_mask) if (!ddw_enabled) { dev_info(dev, "Using 32-bit DMA via iommu\n"); set_dma_ops(dev, &dma_iommu_ops); + pci_dma_dev_setup_pSeriesLP(pdev); } *dev->dma_mask = dma_mask; -- cgit v0.10.2 From f0e939ae373836400b38e090d78fba6a183976f0 Mon Sep 17 00:00:00 2001 From: Anton Blanchard Date: Tue, 10 May 2011 13:34:03 +0000 Subject: powerpc/pseries: Print corrupt r3 in FWNMI code I have a report of an FWNMI with an r3 value that we think is corrupt, but since we don't print r3 we have no idea what was wrong with it. Signed-off-by: Anton Blanchard Signed-off-by: Benjamin Herrenschmidt diff --git a/arch/powerpc/platforms/pseries/ras.c b/arch/powerpc/platforms/pseries/ras.c index 164a8eb..086d2ae 100644 --- a/arch/powerpc/platforms/pseries/ras.c +++ b/arch/powerpc/platforms/pseries/ras.c @@ -227,7 +227,7 @@ static struct rtas_error_log *fwnmi_get_errinfo(struct pt_regs *regs) struct rtas_error_log *h, *errhdr = NULL; if (!VALID_FWNMI_BUFFER(regs->gpr[3])) { - printk(KERN_ERR "FWNMI: corrupt r3\n"); + printk(KERN_ERR "FWNMI: corrupt r3 0x%016lx\n", regs->gpr[3]); return NULL; } -- cgit v0.10.2 From 3d2cea732d68aa270c360f55d8669820ebce188a Mon Sep 17 00:00:00 2001 From: Milton Miller Date: Tue, 10 May 2011 19:28:33 +0000 Subject: powerpc/kexec: Fix memory corruption from unallocated slaves Commit 1fc711f7ffb01089efc58042cfdbac8573d1b59a (powerpc/kexec: Fix race in kexec shutdown) moved the write to signal the cpu had exited the kernel from before the transition to real mode in kexec_smp_wait to kexec_wait. Unfornately it missed that kexec_wait is used both by cpus leaving the kernel and by secondary slave cpus that were not allocated a paca for what ever reason -- they could be beyond nr_cpus or not described in the current device tree for whatever reason (for example, kexec-load was not refreshed after a cpu hotplug operation). Cpus coming through that path they will write to paca[NR_CPUS] which is beyond the space allocated for the paca data and overwrite memory not allocated to pacas but very likely still real mode accessable). Move the write back to kexec_smp_wait, which is used only by cpus that found their paca, but after the transition to real mode. Signed-off-by: Milton Miller Cc: # (1fc711f was backported to 2.6.32) Signed-off-by: Benjamin Herrenschmidt diff --git a/arch/powerpc/kernel/misc_64.S b/arch/powerpc/kernel/misc_64.S index 206a321..e89df59 100644 --- a/arch/powerpc/kernel/misc_64.S +++ b/arch/powerpc/kernel/misc_64.S @@ -462,7 +462,8 @@ _GLOBAL(disable_kernel_fp) * wait for the flag to change, indicating this kernel is going away but * the slave code for the next one is at addresses 0 to 100. * - * This is used by all slaves. + * This is used by all slaves, even those that did not find a matching + * paca in the secondary startup code. * * Physical (hardware) cpu id should be in r3. */ @@ -471,10 +472,6 @@ _GLOBAL(kexec_wait) 1: mflr r5 addi r5,r5,kexec_flag-1b - li r4,KEXEC_STATE_REAL_MODE - stb r4,PACAKEXECSTATE(r13) - SYNC - 99: HMT_LOW #ifdef CONFIG_KEXEC /* use no memory without kexec */ lwz r4,0(r5) @@ -499,11 +496,17 @@ kexec_flag: * * get phys id from paca * switch to real mode + * mark the paca as no longer used * join other cpus in kexec_wait(phys_id) */ _GLOBAL(kexec_smp_wait) lhz r3,PACAHWCPUID(r13) bl real_mode + + li r4,KEXEC_STATE_REAL_MODE + stb r4,PACAKEXECSTATE(r13) + SYNC + b .kexec_wait /* -- cgit v0.10.2 From 768d18ad6d5e600d911f9499ca287d6986d8d81b Mon Sep 17 00:00:00 2001 From: Milton Miller Date: Tue, 10 May 2011 19:28:37 +0000 Subject: powerpc: Don't search for paca in freed memory Starting with 1426d5a3bd07589534286375998c0c8c6fdc5260 (powerpc: Dynamically allocate pacas) we free the memory for pacas beyond cpu_possible, but we failed to update the loop the secondary cpus use to find their paca. If the system has running cpu threads for which the kernel did not allocate a paca for they will search the memory that was freed. For instance this could happen when the device tree for a kdump kernel was not updated after a cpu hotplug, or the kernel is running with more cpus than the kernel was configured. Since c1854e00727f50f7ac99e98d26ece04c087ef785 (powerpc: Set nr_cpu_ids early and use it to free PACAs) we set nr_cpu_ids before telling the cpus to advance, so use that to limit the search. We can't reference nr_cpu_ids without CONFIG_SMP because it is defined as 1 instead of a memory location, but any extra threads should be sent to kexec_wait in that case anyways, so make that explicit and remove the search loop for UP. Note to stable: The fix also requires c1854e00727f50f7ac99e98d26ece04c087ef785 (powerpc: Set nr_cpu_ids early and use it to free PACAs) to function. Also 9d07bc841c9779b4d7902e417f4e509996ce805d (Properly handshake CPUs going out of boot spin loop) affects the second chunk, specifically the branch target was 3b before and is 4b after that patch, and there was a blank line before the #ifdef CONFIG_SMP that was removed Cc: # .34.x: c1854e0072 powerpc: Set nr_cpu_ids early Cc: # .34.x Signed-off-by: Milton Miller Signed-off-by: Benjamin Herrenschmidt diff --git a/arch/powerpc/kernel/head_64.S b/arch/powerpc/kernel/head_64.S index 73d6e9a..ba50409 100644 --- a/arch/powerpc/kernel/head_64.S +++ b/arch/powerpc/kernel/head_64.S @@ -218,13 +218,19 @@ generic_secondary_common_init: */ LOAD_REG_ADDR(r13, paca) /* Load paca pointer */ ld r13,0(r13) /* Get base vaddr of paca array */ +#ifndef CONFIG_SMP + addi r13,r13,PACA_SIZE /* know r13 if used accidentally */ + b .kexec_wait /* wait for next kernel if !SMP */ +#else + LOAD_REG_ADDR(r7, nr_cpu_ids) /* Load nr_cpu_ids address */ + lwz r7,0(r7) /* also the max paca allocated */ li r5,0 /* logical cpu id */ 1: lhz r6,PACAHWCPUID(r13) /* Load HW procid from paca */ cmpw r6,r24 /* Compare to our id */ beq 2f addi r13,r13,PACA_SIZE /* Loop to next PACA on miss */ addi r5,r5,1 - cmpwi r5,NR_CPUS + cmpw r5,r7 /* Check if more pacas exist */ blt 1b mr r3,r24 /* not found, copy phys to r3 */ @@ -259,9 +265,6 @@ generic_secondary_common_init: 4: HMT_LOW lbz r23,PACAPROCSTART(r13) /* Test if this processor should */ /* start. */ -#ifndef CONFIG_SMP - b 4b /* Never go on non-SMP */ -#else cmpwi 0,r23,0 beq 4b /* Loop until told to go */ @@ -273,7 +276,7 @@ generic_secondary_common_init: subi r1,r1,STACK_FRAME_OVERHEAD b __secondary_start -#endif +#endif /* SMP */ /* * Turn the MMU off. -- cgit v0.10.2 From bd9e5eefecb3d69018bb95796298019d309cbec8 Mon Sep 17 00:00:00 2001 From: Milton Miller Date: Tue, 10 May 2011 19:28:41 +0000 Subject: powerpc/kdump64: Don't reference freed memory as pacas Starting with 1426d5a3bd07589534286375998c0c8c6fdc5260 (powerpc: Dynamically allocate pacas) the space for pacas beyond cpu_possible is freed, but we failed to update the loop in crash.c. Since c1854e00727f50f7ac99e98d26ece04c087ef785 (powerpc: Set nr_cpu_ids early and use it to free PACAs) the number of pacas allocated is always nr_cpu_ids. Signed-off-by: Milton Miller Cc: # .34.x Signed-off-by: Benjamin Herrenschmidt diff --git a/arch/powerpc/kernel/crash.c b/arch/powerpc/kernel/crash.c index 21f2c78..4e6ee94 100644 --- a/arch/powerpc/kernel/crash.c +++ b/arch/powerpc/kernel/crash.c @@ -236,7 +236,7 @@ static void crash_kexec_wait_realmode(int cpu) int i; msecs = 10000; - for (i=0; i < NR_CPUS && msecs > 0; i++) { + for (i=0; i < nr_cpu_ids && msecs > 0; i++) { if (i == cpu) continue; -- cgit v0.10.2 From 7c82733744a74f45e86125f369e876b896765038 Mon Sep 17 00:00:00 2001 From: Milton Miller Date: Tue, 10 May 2011 19:28:44 +0000 Subject: powerpc/iseries: Cleanup and fix secondary startup 9cb82f2f4692293a27c578c3038518ce4477de72 (Make iSeries spin on __secondary_hold_spinloop, like pSeries) added a load of current_set but this load was repeated later and we don't even have the paca yet. It also checked __secondary_hold_spinloop with a 32 bit compare instead of a 64 bit compare. b6f6b98a4e91fcf31db7de54c3aa86252fc6fb5f (Don't spin on sync instruction at boot time) missed the copy of the startup code in iseries. 1426d5a3bd07589534286375998c0c8c6fdc5260 (Dynamically allocate pacas) doesn't allow for pacas to be less than lppacas and recalculated the paca location from the cpu id in r0 every time through the secondary loop. Various revisions over time made the comments on conditional branches confusing with respect to being a hold loop or forward progress Mostly in-order description of the changes: Replicate the few lines of code saved by the ugly scoped ifdef CONFIG_SMP in the secondary loop between yielding on UP and marking time with the hypervisor on SMP. Always compile the iseries_secondary_yield loop and use it if the cpu id is above nr_cpu_ids. Change all forward progress paths to be forward branches to the next numerical label. Assign a label to all loops. Move all sync instructions from the loops to the forward progress path. Wait to load current_set until paca is set to go. Move the iseries_secondary_smp_loop label to cover the whole spin loop. Add HMT_MEDIUM when we make forward progress. Signed-off-by: Milton Miller Signed-off-by: Benjamin Herrenschmidt diff --git a/arch/powerpc/platforms/iseries/exception.S b/arch/powerpc/platforms/iseries/exception.S index a67984c..29c02f3 100644 --- a/arch/powerpc/platforms/iseries/exception.S +++ b/arch/powerpc/platforms/iseries/exception.S @@ -61,29 +61,31 @@ system_reset_iSeries: /* Spin on __secondary_hold_spinloop until it is updated by the boot cpu. */ /* In the UP case we'll yield() later, and we will not access the paca anyway */ #ifdef CONFIG_SMP -1: +iSeries_secondary_wait_paca: HMT_LOW LOAD_REG_ADDR(r23, __secondary_hold_spinloop) ld r23,0(r23) - sync - LOAD_REG_ADDR(r3,current_set) - sldi r28,r24,3 /* get current_set[cpu#] */ - ldx r3,r3,r28 - addi r1,r3,THREAD_SIZE - subi r1,r1,STACK_FRAME_OVERHEAD - cmpwi 0,r23,0 /* Keep poking the Hypervisor until */ - bne 2f /* we're released */ - /* Let the Hypervisor know we are alive */ + cmpdi 0,r23,0 + bne 2f /* go on when the master is ready */ + + /* Keep poking the Hypervisor until we're released */ /* 8002 is a call to HvCallCfg::getLps, a harmless Hypervisor function */ lis r3,0x8002 rldicr r3,r3,32,15 /* r0 = (r3 << 32) & 0xffff000000000000 */ li r0,-1 /* r0=-1 indicates a Hypervisor call */ sc /* Invoke the hypervisor via a system call */ - b 1b -#endif + b iSeries_secondary_wait_paca 2: + HMT_MEDIUM + sync + + LOAD_REG_ADDR(r3, nr_cpu_ids) /* get number of pacas allocated */ + lwz r3,0(r3) /* nr_cpus= or NR_CPUS can limit */ + cmpld 0,r24,r3 /* is our cpu number allocated? */ + bge iSeries_secondary_yield /* no, yield forever */ + /* Load our paca now that it's been allocated */ LOAD_REG_ADDR(r13, paca) ld r13,0(r13) @@ -94,10 +96,24 @@ system_reset_iSeries: ori r23,r23,MSR_RI mtmsrd r23 /* RI on */ - HMT_LOW -#ifdef CONFIG_SMP +iSeries_secondary_smp_loop: lbz r23,PACAPROCSTART(r13) /* Test if this processor * should start */ + cmpwi 0,r23,0 + bne 3f /* go on when we are told */ + + HMT_LOW + /* Let the Hypervisor know we are alive */ + /* 8002 is a call to HvCallCfg::getLps, a harmless Hypervisor function */ + lis r3,0x8002 + rldicr r3,r3,32,15 /* r0 = (r3 << 32) & 0xffff000000000000 */ + li r0,-1 /* r0=-1 indicates a Hypervisor call */ + sc /* Invoke the hypervisor via a system call */ + mfspr r13,SPRN_SPRG_PACA /* Put r13 back ???? */ + b iSeries_secondary_smp_loop /* wait for signal to start */ + +3: + HMT_MEDIUM sync LOAD_REG_ADDR(r3,current_set) sldi r28,r24,3 /* get current_set[cpu#] */ @@ -105,27 +121,22 @@ system_reset_iSeries: addi r1,r3,THREAD_SIZE subi r1,r1,STACK_FRAME_OVERHEAD - cmpwi 0,r23,0 - beq iSeries_secondary_smp_loop /* Loop until told to go */ b __secondary_start /* Loop until told to go */ -iSeries_secondary_smp_loop: - /* Let the Hypervisor know we are alive */ - /* 8002 is a call to HvCallCfg::getLps, a harmless Hypervisor function */ - lis r3,0x8002 - rldicr r3,r3,32,15 /* r0 = (r3 << 32) & 0xffff000000000000 */ -#else /* CONFIG_SMP */ +#endif /* CONFIG_SMP */ + +iSeries_secondary_yield: /* Yield the processor. This is required for non-SMP kernels which are running on multi-threaded machines. */ + HMT_LOW lis r3,0x8000 rldicr r3,r3,32,15 /* r3 = (r3 << 32) & 0xffff000000000000 */ addi r3,r3,18 /* r3 = 0x8000000000000012 which is "yield" */ li r4,0 /* "yield timed" */ li r5,-1 /* "yield forever" */ -#endif /* CONFIG_SMP */ li r0,-1 /* r0=-1 indicates a Hypervisor call */ sc /* Invoke the hypervisor via a system call */ mfspr r13,SPRN_SPRG_PACA /* Put r13 back ???? */ - b 2b /* If SMP not configured, secondaries + b iSeries_secondary_yield /* If SMP not configured, secondaries * loop forever */ /*** ISeries-LPAR interrupt handlers ***/ -- cgit v0.10.2 From 8657ae28ddd34db0f52b0730a6a25992c0173264 Mon Sep 17 00:00:00 2001 From: Milton Miller Date: Tue, 10 May 2011 19:28:48 +0000 Subject: powerpc: Respect nr_cpu_ids when calling set_cpu_possible and set_cpu_present We should not set cpus above nr_cpu_ids to possible. While we will trigger a warning with CONFIG_CPUMASK_DEBUG, even then the mask initializers will set the bits beyond what the iterators check and cause nr_cpu_ids to increase. Respecting nr_cpu_ids during setup will allow us to use it in our initial paca allocation. It can be reduced from NR_CPUS by the existing early param nr_cpus=, which was added in 2b633e3fac5efada088b57d31e65401f22bcc18f (smp: Use nr_cpus= to set nr_cpu_ids early). We already call parse_early_parms between finding the command line and allocating the pacas. Signed-off-by: Milton Miller Signed-off-by: Benjamin Herrenschmidt diff --git a/arch/powerpc/kernel/setup-common.c b/arch/powerpc/kernel/setup-common.c index 1475df6..fce759b 100644 --- a/arch/powerpc/kernel/setup-common.c +++ b/arch/powerpc/kernel/setup-common.c @@ -404,7 +404,7 @@ static void __init cpu_init_thread_core_maps(int tpc) * cpu_present_mask * * Having the possible map set up early allows us to restrict allocations - * of things like irqstacks to num_possible_cpus() rather than NR_CPUS. + * of things like irqstacks to nr_cpu_ids rather than NR_CPUS. * * We do not initialize the online map here; cpus set their own bits in * cpu_online_mask as they come up. @@ -424,7 +424,7 @@ void __init smp_setup_cpu_maps(void) DBG("smp_setup_cpu_maps()\n"); - while ((dn = of_find_node_by_type(dn, "cpu")) && cpu < NR_CPUS) { + while ((dn = of_find_node_by_type(dn, "cpu")) && cpu < nr_cpu_ids) { const int *intserv; int j, len; @@ -443,7 +443,7 @@ void __init smp_setup_cpu_maps(void) intserv = &cpu; /* assume logical == phys */ } - for (j = 0; j < nthreads && cpu < NR_CPUS; j++) { + for (j = 0; j < nthreads && cpu < nr_cpu_ids; j++) { DBG(" thread %d -> cpu %d (hard id %d)\n", j, cpu, intserv[j]); set_cpu_present(cpu, true); @@ -483,12 +483,12 @@ void __init smp_setup_cpu_maps(void) if (cpu_has_feature(CPU_FTR_SMT)) maxcpus *= nthreads; - if (maxcpus > NR_CPUS) { + if (maxcpus > nr_cpu_ids) { printk(KERN_WARNING "Partition configured for %d cpus, " "operating system maximum is %d.\n", - maxcpus, NR_CPUS); - maxcpus = NR_CPUS; + maxcpus, nr_cpu_ids); + maxcpus = nr_cpu_ids; } else printk(KERN_INFO "Partition configured for %d cpus.\n", maxcpus); -- cgit v0.10.2 From 2cd947f1757fb937806535be13caf2ddd813d60b Mon Sep 17 00:00:00 2001 From: Milton Miller Date: Tue, 10 May 2011 19:28:52 +0000 Subject: powerpc: Use nr_cpu_ids in initial paca allocation Now that we never set a cpu above nr_cpu_ids possible we can limit our initial paca allocation to nr_cpu_ids. We can then clamp the number of cpus in platforms/iseries/setup.c. Signed-off-by: Milton Miller Signed-off-by: Benjamin Herrenschmidt diff --git a/arch/powerpc/kernel/paca.c b/arch/powerpc/kernel/paca.c index 102244e..efeb881 100644 --- a/arch/powerpc/kernel/paca.c +++ b/arch/powerpc/kernel/paca.c @@ -7,7 +7,7 @@ * 2 of the License, or (at your option) any later version. */ -#include +#include #include #include @@ -178,7 +178,7 @@ static int __initdata paca_size; void __init allocate_pacas(void) { - int nr_cpus, cpu, limit; + int cpu, limit; /* * We can't take SLB misses on the paca, and we want to access them @@ -190,23 +190,18 @@ void __init allocate_pacas(void) if (firmware_has_feature(FW_FEATURE_ISERIES)) limit = min(limit, HvPagesToMap * HVPAGESIZE); - nr_cpus = NR_CPUS; - /* On iSeries we know we can never have more than 64 cpus */ - if (firmware_has_feature(FW_FEATURE_ISERIES)) - nr_cpus = min(64, nr_cpus); - - paca_size = PAGE_ALIGN(sizeof(struct paca_struct) * nr_cpus); + paca_size = PAGE_ALIGN(sizeof(struct paca_struct) * nr_cpu_ids); paca = __va(memblock_alloc_base(paca_size, PAGE_SIZE, limit)); memset(paca, 0, paca_size); printk(KERN_DEBUG "Allocated %u bytes for %d pacas at %p\n", - paca_size, nr_cpus, paca); + paca_size, nr_cpu_ids, paca); - allocate_lppacas(nr_cpus, limit); + allocate_lppacas(nr_cpu_ids, limit); /* Can't use for_each_*_cpu, as they aren't functional yet */ - for (cpu = 0; cpu < nr_cpus; cpu++) + for (cpu = 0; cpu < nr_cpu_ids; cpu++) initialise_paca(&paca[cpu], cpu); } diff --git a/arch/powerpc/platforms/iseries/setup.c b/arch/powerpc/platforms/iseries/setup.c index 81cb8d2..c25a081 100644 --- a/arch/powerpc/platforms/iseries/setup.c +++ b/arch/powerpc/platforms/iseries/setup.c @@ -685,6 +685,11 @@ void * __init iSeries_early_setup(void) powerpc_firmware_features |= FW_FEATURE_ISERIES; powerpc_firmware_features |= FW_FEATURE_LPAR; +#ifdef CONFIG_SMP + /* On iSeries we know we can never have more than 64 cpus */ + nr_cpu_ids = max(nr_cpu_ids, 64); +#endif + iSeries_fixup_klimit(); /* -- cgit v0.10.2 From aa79bc2167104581cc1d77762394f2c01d3bf3f3 Mon Sep 17 00:00:00 2001 From: Milton Miller Date: Tue, 10 May 2011 19:28:55 +0000 Subject: powerpc: Call no-longer static setup_nr_cpu_ids instead of replicating it c1854e00727f50f7ac99e98d26ece04c087ef785 (powerpc: Set nr_cpu_ids early and use it to free PACAs) copied the formerly static setup_nr_cpu_ids from init/main.c but 34db18a054c600b6f81787165669dc572fe4de25 (smp: move smp setup functions to kernel/smp.c) moved it to kernel/smp.c with a declaration in include/linux/smp.h, so we can call it instead of replicating it. Signed-off-by: Milton Miller Signed-off-by: Benjamin Herrenschmidt diff --git a/arch/powerpc/kernel/setup-common.c b/arch/powerpc/kernel/setup-common.c index fce759b..ef33a08 100644 --- a/arch/powerpc/kernel/setup-common.c +++ b/arch/powerpc/kernel/setup-common.c @@ -510,7 +510,7 @@ void __init smp_setup_cpu_maps(void) cpu_init_thread_core_maps(nthreads); /* Now that possible cpus are set, set nr_cpu_ids for later use */ - nr_cpu_ids = find_last_bit(cpumask_bits(cpu_possible_mask),NR_CPUS) + 1; + setup_nr_cpu_ids(); free_unused_pacas(); } -- cgit v0.10.2 From ebc04215108c124cb4f519d687a8e27a0d16a4aa Mon Sep 17 00:00:00 2001 From: Milton Miller Date: Tue, 10 May 2011 19:28:59 +0000 Subject: powerpc/mpic: Limit NR_CPUS loop to 32 bit mpic_physmask was looping NR_CPUS times over a mask that was passed as a u32. Since mpic is architecturaly limited to 32 physical cpus, clamp the logical cpus to 32 when compiling (we could also clamp at runtime to nr_cpu_ids). Signed-off-by: Milton Miller Signed-off-by: Benjamin Herrenschmidt diff --git a/arch/powerpc/sysdev/mpic.c b/arch/powerpc/sysdev/mpic.c index 824a94f..a93da80 100644 --- a/arch/powerpc/sysdev/mpic.c +++ b/arch/powerpc/sysdev/mpic.c @@ -631,7 +631,7 @@ static inline u32 mpic_physmask(u32 cpumask) int i; u32 mask = 0; - for (i = 0; i < NR_CPUS; ++i, cpumask >>= 1) + for (i = 0; i < min(32, NR_CPUS); ++i, cpumask >>= 1) mask |= (cpumask & 1) << get_hard_smp_processor_id(i); return mask; } -- cgit v0.10.2 From 2a116f3dd07cbb55b440d3841fc24a0b3fd99ccd Mon Sep 17 00:00:00 2001 From: Milton Miller Date: Tue, 10 May 2011 19:29:02 +0000 Subject: powerpc/mpic: Break cpumask abstraction earlier mpic_set_affinity is allocating and freeing a cpumask var even though it was breaking the cpumask abstraction when passing the mask to mpic_physmask. It also didn't have any check for allocatin failure. Break the cpumask abstraction earlier and use simple bitwise and of the bits from the mask with the bits of cpu_online_mask. Signed-off-by: Milton Miller Signed-off-by: Benjamin Herrenschmidt diff --git a/arch/powerpc/sysdev/mpic.c b/arch/powerpc/sysdev/mpic.c index a93da80..116695b 100644 --- a/arch/powerpc/sysdev/mpic.c +++ b/arch/powerpc/sysdev/mpic.c @@ -821,16 +821,12 @@ int mpic_set_affinity(struct irq_data *d, const struct cpumask *cpumask, mpic_irq_write(src, MPIC_INFO(IRQ_DESTINATION), 1 << cpuid); } else { - cpumask_var_t tmp; + u32 mask = cpumask_bits(cpumask)[0]; - alloc_cpumask_var(&tmp, GFP_KERNEL); - - cpumask_and(tmp, cpumask, cpu_online_mask); + mask &= cpumask_bits(cpu_online_mask)[0]; mpic_irq_write(src, MPIC_INFO(IRQ_DESTINATION), - mpic_physmask(cpumask_bits(tmp)[0])); - - free_cpumask_var(tmp); + mpic_physmask(mask)); } return 0; -- cgit v0.10.2 From e04763713286b1e00e1c2a33fe2741caf9470f2b Mon Sep 17 00:00:00 2001 From: Milton Miller Date: Tue, 10 May 2011 19:29:06 +0000 Subject: powerpc: Remove call sites of MSG_ALL_BUT_SELF The only user of MSG_ALL_BUT_SELF in the whole kernel tree is powerpc, and it only uses it to start the debugger. Both debuggers always call smp_send_debugger_break with MSG_ALL_BUT_SELF, and only mpic can do anything more optimal than a loop over all online cpus, but all message passing implementations have to code for this special delivery target. Convert smp_send_debugger_break to take void and loop calling the smp_ops message_pass function for each of the other cpus in the online cpumask. Use raw_smp_processor_id() because we are either entering the debugger or trying to start kdump and the additional warning it not useful were it to trigger. Signed-off-by: Milton Miller Signed-off-by: Benjamin Herrenschmidt diff --git a/arch/powerpc/include/asm/smp.h b/arch/powerpc/include/asm/smp.h index 5087349..91472c5 100644 --- a/arch/powerpc/include/asm/smp.h +++ b/arch/powerpc/include/asm/smp.h @@ -35,7 +35,7 @@ extern void cpu_die(void); #ifdef CONFIG_SMP -extern void smp_send_debugger_break(int cpu); +extern void smp_send_debugger_break(void); extern void smp_message_recv(int); extern void start_secondary_resume(void); diff --git a/arch/powerpc/kernel/kgdb.c b/arch/powerpc/kernel/kgdb.c index 42850ee..bd9d35f 100644 --- a/arch/powerpc/kernel/kgdb.c +++ b/arch/powerpc/kernel/kgdb.c @@ -109,7 +109,7 @@ static int kgdb_call_nmi_hook(struct pt_regs *regs) #ifdef CONFIG_SMP void kgdb_roundup_cpus(unsigned long flags) { - smp_send_debugger_break(MSG_ALL_BUT_SELF); + smp_send_debugger_break(); } #endif diff --git a/arch/powerpc/kernel/smp.c b/arch/powerpc/kernel/smp.c index 87517ab..b744114 100644 --- a/arch/powerpc/kernel/smp.c +++ b/arch/powerpc/kernel/smp.c @@ -218,11 +218,18 @@ void arch_send_call_function_ipi_mask(const struct cpumask *mask) smp_ops->message_pass(cpu, PPC_MSG_CALL_FUNCTION); } -#ifdef CONFIG_DEBUGGER -void smp_send_debugger_break(int cpu) +#if defined(CONFIG_DEBUGGER) || defined(CONFIG_KEXEC) +void smp_send_debugger_break(void) { - if (likely(smp_ops)) - smp_ops->message_pass(cpu, PPC_MSG_DEBUGGER_BREAK); + int cpu; + int me = raw_smp_processor_id(); + + if (unlikely(!smp_ops)) + return; + + for_each_online_cpu(cpu) + if (cpu != me) + smp_ops->message_pass(cpu, PPC_MSG_DEBUGGER_BREAK); } #endif @@ -230,9 +237,9 @@ void smp_send_debugger_break(int cpu) void crash_send_ipi(void (*crash_ipi_callback)(struct pt_regs *)) { crash_ipi_function_ptr = crash_ipi_callback; - if (crash_ipi_callback && smp_ops) { + if (crash_ipi_callback) { mb(); - smp_ops->message_pass(MSG_ALL_BUT_SELF, PPC_MSG_DEBUGGER_BREAK); + smp_send_debugger_break(); } } #endif diff --git a/arch/powerpc/xmon/xmon.c b/arch/powerpc/xmon/xmon.c index 91309c5..42541bb 100644 --- a/arch/powerpc/xmon/xmon.c +++ b/arch/powerpc/xmon/xmon.c @@ -437,7 +437,7 @@ static int xmon_core(struct pt_regs *regs, int fromipi) xmon_owner = cpu; mb(); if (ncpus > 1) { - smp_send_debugger_break(MSG_ALL_BUT_SELF); + smp_send_debugger_break(); /* wait for other cpus to come in */ for (timeout = 100000000; timeout != 0; --timeout) { if (cpumask_weight(&cpus_in_xmon) >= ncpus) -- cgit v0.10.2 From f1072939b6dd01d038d47db0bdc01b33e5f90f28 Mon Sep 17 00:00:00 2001 From: Milton Miller Date: Tue, 10 May 2011 19:29:10 +0000 Subject: powerpc: Remove checks for MSG_ALL and MSG_ALL_BUT_SELF Now that smp_ops->smp_message_pass is always called with an (online) cpu number for the target remove the checks for MSG_ALL and MSG_ALL_BUT_SELF. Signed-off-by: Milton Miller Signed-off-by: Benjamin Herrenschmidt diff --git a/arch/powerpc/include/asm/dbell.h b/arch/powerpc/include/asm/dbell.h index 0893ab9..3269eb4 100644 --- a/arch/powerpc/include/asm/dbell.h +++ b/arch/powerpc/include/asm/dbell.h @@ -27,7 +27,7 @@ enum ppc_dbell { PPC_G_DBELL_MC = 4, /* guest mcheck doorbell */ }; -extern void doorbell_message_pass(int target, int msg); +extern void doorbell_message_pass(int cpu, int msg); extern void doorbell_exception(struct pt_regs *regs); extern void doorbell_check_self(void); extern void doorbell_setup_this_cpu(void); diff --git a/arch/powerpc/include/asm/machdep.h b/arch/powerpc/include/asm/machdep.h index c6345ac..b0802a5 100644 --- a/arch/powerpc/include/asm/machdep.h +++ b/arch/powerpc/include/asm/machdep.h @@ -31,7 +31,7 @@ struct kimage; #ifdef CONFIG_SMP struct smp_ops_t { - void (*message_pass)(int target, int msg); + void (*message_pass)(int cpu, int msg); int (*probe)(void); int (*kick_cpu)(int nr); void (*setup_cpu)(int nr); diff --git a/arch/powerpc/include/asm/xics.h b/arch/powerpc/include/asm/xics.h index 6c06306..1750c8d 100644 --- a/arch/powerpc/include/asm/xics.h +++ b/arch/powerpc/include/asm/xics.h @@ -40,7 +40,7 @@ struct icp_ops { void (*teardown_cpu)(void); void (*flush_ipi)(void); #ifdef CONFIG_SMP - void (*message_pass)(int target, int msg); + void (*message_pass)(int cpu, int msg); irq_handler_t ipi_action; #endif }; diff --git a/arch/powerpc/kernel/dbell.c b/arch/powerpc/kernel/dbell.c index 3307a52..e49b24c 100644 --- a/arch/powerpc/kernel/dbell.c +++ b/arch/powerpc/kernel/dbell.c @@ -34,32 +34,13 @@ void doorbell_setup_this_cpu(void) info->tag = mfspr(SPRN_PIR) & 0x3fff; } -void doorbell_message_pass(int target, int msg) +void doorbell_message_pass(int cpu, int msg) { struct doorbell_cpu_info *info; - int i; - - if (target < NR_CPUS) { - info = &per_cpu(doorbell_cpu_info, target); - set_bit(msg, &info->messages); - ppc_msgsnd(PPC_DBELL, 0, info->tag); - } - else if (target == MSG_ALL_BUT_SELF) { - for_each_online_cpu(i) { - if (i == smp_processor_id()) - continue; - info = &per_cpu(doorbell_cpu_info, i); - set_bit(msg, &info->messages); - ppc_msgsnd(PPC_DBELL, 0, info->tag); - } - } - else { /* target == MSG_ALL */ - for_each_online_cpu(i) { - info = &per_cpu(doorbell_cpu_info, i); - set_bit(msg, &info->messages); - } - ppc_msgsnd(PPC_DBELL, PPC_DBELL_MSG_BRDCAST, 0); - } + + info = &per_cpu(doorbell_cpu_info, cpu); + set_bit(msg, &info->messages); + ppc_msgsnd(PPC_DBELL, 0, info->tag); } void doorbell_exception(struct pt_regs *regs) diff --git a/arch/powerpc/platforms/cell/beat_smp.c b/arch/powerpc/platforms/cell/beat_smp.c index 3e86acb..23bbe6e 100644 --- a/arch/powerpc/platforms/cell/beat_smp.c +++ b/arch/powerpc/platforms/cell/beat_smp.c @@ -67,22 +67,6 @@ static inline int __devinit smp_startup_cpu(unsigned int lcpu) return 0; } -static void smp_beatic_message_pass(int target, int msg) -{ - unsigned int i; - - if (target < NR_CPUS) { - beatic_cause_IPI(target, msg); - } else { - for_each_online_cpu(i) { - if (target == MSG_ALL_BUT_SELF - && i == smp_processor_id()) - continue; - beatic_cause_IPI(i, msg); - } - } -} - static int __init smp_beatic_probe(void) { return cpumask_weight(cpu_possible_mask); @@ -105,7 +89,7 @@ static int smp_celleb_cpu_bootable(unsigned int nr) return 1; } static struct smp_ops_t bpa_beatic_smp_ops = { - .message_pass = smp_beatic_message_pass, + .message_pass = beatic_cause_IPI, .probe = smp_beatic_probe, .kick_cpu = smp_celleb_kick_cpu, .setup_cpu = smp_beatic_setup_cpu, diff --git a/arch/powerpc/platforms/cell/smp.c b/arch/powerpc/platforms/cell/smp.c index a2161b9..d176e61 100644 --- a/arch/powerpc/platforms/cell/smp.c +++ b/arch/powerpc/platforms/cell/smp.c @@ -103,22 +103,6 @@ static inline int __devinit smp_startup_cpu(unsigned int lcpu) return 1; } -static void smp_iic_message_pass(int target, int msg) -{ - unsigned int i; - - if (target < NR_CPUS) { - iic_cause_IPI(target, msg); - } else { - for_each_online_cpu(i) { - if (target == MSG_ALL_BUT_SELF - && i == smp_processor_id()) - continue; - iic_cause_IPI(i, msg); - } - } -} - static int __init smp_iic_probe(void) { iic_request_IPIs(); @@ -168,7 +152,7 @@ static int smp_cell_cpu_bootable(unsigned int nr) return 1; } static struct smp_ops_t bpa_iic_smp_ops = { - .message_pass = smp_iic_message_pass, + .message_pass = iic_cause_IPI, .probe = smp_iic_probe, .kick_cpu = smp_cell_kick_cpu, .setup_cpu = smp_cell_setup_cpu, diff --git a/arch/powerpc/platforms/iseries/smp.c b/arch/powerpc/platforms/iseries/smp.c index 02a677a..dcdbc5d 100644 --- a/arch/powerpc/platforms/iseries/smp.c +++ b/arch/powerpc/platforms/iseries/smp.c @@ -59,28 +59,12 @@ void iSeries_smp_message_recv(void) smp_message_recv(msg); } -static inline void smp_iSeries_do_message(int cpu, int msg) +static void smp_iSeries_message_pass(int cpu, int msg) { set_bit(msg, &iSeries_smp_message[cpu]); HvCall_sendIPI(&(paca[cpu])); } -static void smp_iSeries_message_pass(int target, int msg) -{ - int i; - - if (target < NR_CPUS) - smp_iSeries_do_message(target, msg); - else { - for_each_online_cpu(i) { - if ((target == MSG_ALL_BUT_SELF) && - (i == smp_processor_id())) - continue; - smp_iSeries_do_message(i, msg); - } - } -} - static int smp_iSeries_probe(void) { return cpumask_weight(cpu_possible_mask); diff --git a/arch/powerpc/platforms/powermac/smp.c b/arch/powerpc/platforms/powermac/smp.c index 621d4b7..c49e719 100644 --- a/arch/powerpc/platforms/powermac/smp.c +++ b/arch/powerpc/platforms/powermac/smp.c @@ -186,21 +186,10 @@ irqreturn_t psurge_primary_intr(int irq, void *d) return IRQ_HANDLED; } -static void smp_psurge_message_pass(int target, int msg) +static void smp_psurge_message_pass(int cpu, int msg) { - int i; - - if (num_online_cpus() < 2) - return; - - for_each_online_cpu(i) { - if (target == MSG_ALL - || (target == MSG_ALL_BUT_SELF && i != smp_processor_id()) - || target == i) { - set_bit(msg, &psurge_smp_message[i]); - psurge_set_ipi(i); - } - } + set_bit(msg, &psurge_smp_message[cpu]); + psurge_set_ipi(cpu); } /* diff --git a/arch/powerpc/platforms/ps3/smp.c b/arch/powerpc/platforms/ps3/smp.c index 51ffde4..4c44794 100644 --- a/arch/powerpc/platforms/ps3/smp.c +++ b/arch/powerpc/platforms/ps3/smp.c @@ -39,7 +39,7 @@ #define MSG_COUNT 4 static DEFINE_PER_CPU(unsigned int [MSG_COUNT], ps3_ipi_virqs); -static void do_message_pass(int target, int msg) +static void ps3_smp_message_pass(int cpu, int msg) { int result; unsigned int virq; @@ -49,28 +49,12 @@ static void do_message_pass(int target, int msg) return; } - virq = per_cpu(ps3_ipi_virqs, target)[msg]; + virq = per_cpu(ps3_ipi_virqs, cpu)[msg]; result = ps3_send_event_locally(virq); if (result) DBG("%s:%d: ps3_send_event_locally(%d, %d) failed" - " (%d)\n", __func__, __LINE__, target, msg, result); -} - -static void ps3_smp_message_pass(int target, int msg) -{ - int cpu; - - if (target < NR_CPUS) - do_message_pass(target, msg); - else if (target == MSG_ALL_BUT_SELF) { - for_each_online_cpu(cpu) - if (cpu != smp_processor_id()) - do_message_pass(cpu, msg); - } else { - for_each_online_cpu(cpu) - do_message_pass(cpu, msg); - } + " (%d)\n", __func__, __LINE__, cpu, msg, result); } static int ps3_smp_probe(void) diff --git a/arch/powerpc/sysdev/mpic.c b/arch/powerpc/sysdev/mpic.c index 116695b..68ea50c 100644 --- a/arch/powerpc/sysdev/mpic.c +++ b/arch/powerpc/sysdev/mpic.c @@ -1628,31 +1628,15 @@ static void mpic_send_ipi(unsigned int ipi_no, const struct cpumask *cpu_mask) mpic_physmask(cpumask_bits(cpu_mask)[0])); } -void smp_mpic_message_pass(int target, int msg) +void smp_mpic_message_pass(int cpu, int msg) { - cpumask_var_t tmp; - /* make sure we're sending something that translates to an IPI */ if ((unsigned int)msg > 3) { printk("SMP %d: smp_message_pass: unknown msg %d\n", smp_processor_id(), msg); return; } - switch (target) { - case MSG_ALL: - mpic_send_ipi(msg, cpu_online_mask); - break; - case MSG_ALL_BUT_SELF: - alloc_cpumask_var(&tmp, GFP_NOWAIT); - cpumask_andnot(tmp, cpu_online_mask, - cpumask_of(smp_processor_id())); - mpic_send_ipi(msg, tmp); - free_cpumask_var(tmp); - break; - default: - mpic_send_ipi(msg, cpumask_of(target)); - break; - } + mpic_send_ipi(msg, cpumask_of(cpu)); } int __init smp_mpic_probe(void) diff --git a/arch/powerpc/sysdev/xics/icp-hv.c b/arch/powerpc/sysdev/xics/icp-hv.c index 76e8724..234764c 100644 --- a/arch/powerpc/sysdev/xics/icp-hv.c +++ b/arch/powerpc/sysdev/xics/icp-hv.c @@ -118,7 +118,7 @@ static void icp_hv_set_cpu_priority(unsigned char cppr) #ifdef CONFIG_SMP -static inline void icp_hv_do_message(int cpu, int msg) +static void icp_hv_message_pass(int cpu, int msg) { unsigned long *tgt = &per_cpu(xics_ipi_message, cpu); @@ -127,22 +127,6 @@ static inline void icp_hv_do_message(int cpu, int msg) icp_hv_set_qirr(cpu, IPI_PRIORITY); } -static void icp_hv_message_pass(int target, int msg) -{ - unsigned int i; - - if (target < NR_CPUS) { - icp_hv_do_message(target, msg); - } else { - for_each_online_cpu(i) { - if (target == MSG_ALL_BUT_SELF - && i == smp_processor_id()) - continue; - icp_hv_do_message(i, msg); - } - } -} - static irqreturn_t icp_hv_ipi_action(int irq, void *dev_id) { int cpu = smp_processor_id(); diff --git a/arch/powerpc/sysdev/xics/icp-native.c b/arch/powerpc/sysdev/xics/icp-native.c index 3508321..246500e 100644 --- a/arch/powerpc/sysdev/xics/icp-native.c +++ b/arch/powerpc/sysdev/xics/icp-native.c @@ -134,7 +134,7 @@ static unsigned int icp_native_get_irq(void) #ifdef CONFIG_SMP -static inline void icp_native_do_message(int cpu, int msg) +static void icp_native_message_pass(int cpu, int msg) { unsigned long *tgt = &per_cpu(xics_ipi_message, cpu); @@ -143,22 +143,6 @@ static inline void icp_native_do_message(int cpu, int msg) icp_native_set_qirr(cpu, IPI_PRIORITY); } -static void icp_native_message_pass(int target, int msg) -{ - unsigned int i; - - if (target < NR_CPUS) { - icp_native_do_message(target, msg); - } else { - for_each_online_cpu(i) { - if (target == MSG_ALL_BUT_SELF - && i == smp_processor_id()) - continue; - icp_native_do_message(i, msg); - } - } -} - static irqreturn_t icp_native_ipi_action(int irq, void *dev_id) { int cpu = smp_processor_id(); -- cgit v0.10.2 From 2930d49768e5276da4fbed9d9cc1bd40ed25818e Mon Sep 17 00:00:00 2001 From: Kim Phillips Date: Sat, 14 May 2011 22:07:55 -0500 Subject: crypto: caam - platform_bus_type migration this fixes a build error since cryptodev-2.6 got rebased to include commit d714d1979d7b4df7e2c127407f4014ce71f73cd0 "dt: eliminate of_platform_driver shim code". Signed-off-by: Kim Phillips Signed-off-by: Herbert Xu diff --git a/drivers/crypto/caam/ctrl.c b/drivers/crypto/caam/ctrl.c index 59aae4e..9009713 100644 --- a/drivers/crypto/caam/ctrl.c +++ b/drivers/crypto/caam/ctrl.c @@ -44,8 +44,7 @@ static int caam_remove(struct platform_device *pdev) } /* Probe routine for CAAM top (controller) level */ -static int caam_probe(struct platform_device *pdev, - const struct of_device_id *devmatch) +static int caam_probe(struct platform_device *pdev) { int d, ring, rspec; struct device *dev; @@ -242,7 +241,7 @@ static struct of_device_id caam_match[] = { }; MODULE_DEVICE_TABLE(of, caam_match); -static struct of_platform_driver caam_driver = { +static struct platform_driver caam_driver = { .driver = { .name = "caam", .owner = THIS_MODULE, @@ -254,12 +253,12 @@ static struct of_platform_driver caam_driver = { static int __init caam_base_init(void) { - return of_register_platform_driver(&caam_driver); + return platform_driver_register(&caam_driver); } static void __exit caam_base_exit(void) { - return of_unregister_platform_driver(&caam_driver); + return platform_driver_unregister(&caam_driver); } module_init(caam_base_init); -- cgit v0.10.2 From ddbb80884a37601026ac3e5eaf176c4296231862 Mon Sep 17 00:00:00 2001 From: Kim Phillips Date: Sat, 14 May 2011 22:08:02 -0500 Subject: crypto: caam - fix decryption shared vs. non-shared key setting Key sharing is enabled by default in the shared descriptor. Using CBC decrypt, AES has to alter the key in order to decrypt. During high traffic decryption rates, i.e, when sharing starts to take place, we need to use a different OPERATION option to tell AES that the key was already altered by the PRIOR descriptor - we need the following kind of logic: if ( shared ) operation where AES uses decryption key (DK=1) else operation where AES uses encryption key (DK=0) this patch implements this logic using a conditional and a non-conditional local jump within the decryption job descriptor. Signed-off-by: Kim Phillips Signed-off-by: Herbert Xu diff --git a/drivers/crypto/caam/caamalg.c b/drivers/crypto/caam/caamalg.c index b97575e..4c69ba7 100644 --- a/drivers/crypto/caam/caamalg.c +++ b/drivers/crypto/caam/caamalg.c @@ -571,9 +571,27 @@ static int ipsec_esp(struct ipsec_esp_edesc *edesc, struct aead_request *areq, /* copy iv from cipher/class1 input context to class2 infifo */ append_move(desc, MOVE_SRC_CLASS1CTX | MOVE_DEST_CLASS2INFIFO | ivsize); - /* start class 1 (cipher) operation */ - append_operation(desc, ctx->class1_alg_type | OP_ALG_AS_INITFINAL | - encrypt); + if (!encrypt) { + u32 *jump_cmd, *uncond_jump_cmd; + + /* JUMP if shared */ + jump_cmd = append_jump(desc, JUMP_TEST_ALL | JUMP_COND_SHRD); + + /* start class 1 (cipher) operation, non-shared version */ + append_operation(desc, ctx->class1_alg_type | + OP_ALG_AS_INITFINAL); + + uncond_jump_cmd = append_jump(desc, 0); + + set_jump_tgt_here(desc, jump_cmd); + + /* start class 1 (cipher) operation, shared version */ + append_operation(desc, ctx->class1_alg_type | + OP_ALG_AS_INITFINAL | OP_ALG_AAI_DK); + set_jump_tgt_here(desc, uncond_jump_cmd); + } else + append_operation(desc, ctx->class1_alg_type | + OP_ALG_AS_INITFINAL | encrypt); /* load payload & instruct to class2 to snoop class 1 if encrypting */ options = 0; @@ -762,7 +780,7 @@ static int aead_authenc_decrypt(struct aead_request *req) req->cryptlen -= ctx->authsize; /* allocate extended descriptor */ - edesc = ipsec_esp_edesc_alloc(req, 21 * sizeof(u32)); + edesc = ipsec_esp_edesc_alloc(req, 24 * sizeof(u32)); if (IS_ERR(edesc)) return PTR_ERR(edesc); -- cgit v0.10.2 From 66664487b137d71fd43667ac2a6a90970a040eb7 Mon Sep 17 00:00:00 2001 From: Kim Phillips Date: Sat, 14 May 2011 22:08:11 -0500 Subject: crypto: caam - remove unused authkeylen from caam_ctx Signed-off-by: Kim Phillips Signed-off-by: Herbert Xu diff --git a/drivers/crypto/caam/caamalg.c b/drivers/crypto/caam/caamalg.c index 4c69ba7..672abf3 100644 --- a/drivers/crypto/caam/caamalg.c +++ b/drivers/crypto/caam/caamalg.c @@ -83,7 +83,6 @@ struct caam_ctx { u8 *key; dma_addr_t key_phys; unsigned int enckeylen; - unsigned int authkeylen; unsigned int split_key_len; unsigned int split_key_pad_len; unsigned int authsize; @@ -330,7 +329,6 @@ static int aead_authenc_setkey(struct crypto_aead *aead, #endif ctx->enckeylen = enckeylen; - ctx->authkeylen = authkeylen; ret = build_sh_desc_ipsec(ctx); if (ret) { -- cgit v0.10.2 From 4427b1b4ec111622071ec872c94594e05635c6e9 Mon Sep 17 00:00:00 2001 From: Kim Phillips Date: Sat, 14 May 2011 22:08:17 -0500 Subject: crypto: caam - add support for sha512 variants of existing AEAD algorithms In doing so, sha512 sized keys would not fit with the current descriptor inlining mechanism, so we now calculate whether keys should be referenced instead by pointers in the shared descriptor. also, use symbols for descriptor text lengths, and, ahem, unmap and free key i/o memory in cra_exit. Signed-off-by: Kim Phillips Signed-off-by: Herbert Xu diff --git a/drivers/crypto/caam/caamalg.c b/drivers/crypto/caam/caamalg.c index 672abf3..d0e65d6 100644 --- a/drivers/crypto/caam/caamalg.c +++ b/drivers/crypto/caam/caamalg.c @@ -61,6 +61,12 @@ /* max IV is max of AES_BLOCK_SIZE, DES3_EDE_BLOCK_SIZE */ #define CAAM_MAX_IV_LENGTH 16 +/* length of descriptors text */ +#define DESC_AEAD_SHARED_TEXT_LEN 4 +#define DESC_AEAD_ENCRYPT_TEXT_LEN 21 +#define DESC_AEAD_DECRYPT_TEXT_LEN 24 +#define DESC_AEAD_GIVENCRYPT_TEXT_LEN 27 + #ifdef DEBUG /* for print_hex_dumps with line references */ #define xstr(s) str(s) @@ -219,10 +225,22 @@ static int build_sh_desc_ipsec(struct caam_ctx *ctx) struct device *jrdev = ctx->jrdev; u32 *sh_desc; u32 *jump_cmd; + bool keys_fit_inline = 0; + + /* + * largest Job Descriptor and its Shared Descriptor + * must both fit into the 64-word Descriptor h/w Buffer + */ + if ((DESC_AEAD_GIVENCRYPT_TEXT_LEN + + DESC_AEAD_SHARED_TEXT_LEN) * CAAM_CMD_SZ + + ctx->split_key_pad_len + ctx->enckeylen <= CAAM_DESC_BYTES_MAX) + keys_fit_inline = 1; /* build shared descriptor for this session */ - sh_desc = kmalloc(CAAM_CMD_SZ * 4 + ctx->split_key_pad_len + - ctx->enckeylen, GFP_DMA | GFP_KERNEL); + sh_desc = kmalloc(CAAM_CMD_SZ * DESC_AEAD_SHARED_TEXT_LEN + + keys_fit_inline ? + ctx->split_key_pad_len + ctx->enckeylen : + CAAM_PTR_SZ * 2, GFP_DMA | GFP_KERNEL); if (!sh_desc) { dev_err(jrdev, "could not allocate shared descriptor\n"); return -ENOMEM; @@ -233,14 +251,23 @@ static int build_sh_desc_ipsec(struct caam_ctx *ctx) jump_cmd = append_jump(sh_desc, CLASS_BOTH | JUMP_TEST_ALL | JUMP_COND_SHRD | JUMP_COND_SELF); - /* process keys, starting with class 2/authentication */ - append_key_as_imm(sh_desc, ctx->key, ctx->split_key_pad_len, - ctx->split_key_len, - CLASS_2 | KEY_DEST_MDHA_SPLIT | KEY_ENC); - - append_key_as_imm(sh_desc, (void *)ctx->key + ctx->split_key_pad_len, - ctx->enckeylen, ctx->enckeylen, - CLASS_1 | KEY_DEST_CLASS_REG); + /* + * process keys, starting with class 2/authentication. + */ + if (keys_fit_inline) { + append_key_as_imm(sh_desc, ctx->key, ctx->split_key_pad_len, + ctx->split_key_len, + CLASS_2 | KEY_DEST_MDHA_SPLIT | KEY_ENC); + + append_key_as_imm(sh_desc, (void *)ctx->key + + ctx->split_key_pad_len, ctx->enckeylen, + ctx->enckeylen, CLASS_1 | KEY_DEST_CLASS_REG); + } else { + append_key(sh_desc, ctx->key_phys, ctx->split_key_len, CLASS_2 | + KEY_DEST_MDHA_SPLIT | KEY_ENC); + append_key(sh_desc, ctx->key_phys + ctx->split_key_pad_len, + ctx->enckeylen, CLASS_1 | KEY_DEST_CLASS_REG); + } /* update jump cmd now that we are at the jump target */ set_jump_tgt_here(sh_desc, jump_cmd); @@ -746,7 +773,8 @@ static int aead_authenc_encrypt(struct aead_request *areq) dma_addr_t iv_dma; /* allocate extended descriptor */ - edesc = ipsec_esp_edesc_alloc(areq, 21 * sizeof(u32)); + edesc = ipsec_esp_edesc_alloc(areq, DESC_AEAD_ENCRYPT_TEXT_LEN * + CAAM_CMD_SZ); if (IS_ERR(edesc)) return PTR_ERR(edesc); @@ -778,7 +806,8 @@ static int aead_authenc_decrypt(struct aead_request *req) req->cryptlen -= ctx->authsize; /* allocate extended descriptor */ - edesc = ipsec_esp_edesc_alloc(req, 24 * sizeof(u32)); + edesc = ipsec_esp_edesc_alloc(req, DESC_AEAD_DECRYPT_TEXT_LEN * + CAAM_CMD_SZ); if (IS_ERR(edesc)) return PTR_ERR(edesc); @@ -813,7 +842,8 @@ static int aead_authenc_givencrypt(struct aead_givcrypt_request *req) debug("%s: giv %p\n", __func__, req->giv); /* allocate extended descriptor */ - edesc = ipsec_esp_edesc_alloc(areq, 27 * sizeof(u32)); + edesc = ipsec_esp_edesc_alloc(areq, DESC_AEAD_GIVENCRYPT_TEXT_LEN * + CAAM_CMD_SZ); if (IS_ERR(edesc)) return PTR_ERR(edesc); @@ -904,6 +934,25 @@ static struct caam_alg_template driver_algs[] = { .alg_op = OP_ALG_ALGSEL_SHA256 | OP_ALG_AAI_HMAC, }, { + .name = "authenc(hmac(sha512),cbc(aes))", + .driver_name = "authenc-hmac-sha512-cbc-aes-caam", + .blocksize = AES_BLOCK_SIZE, + .aead = { + .setkey = aead_authenc_setkey, + .setauthsize = aead_authenc_setauthsize, + .encrypt = aead_authenc_encrypt, + .decrypt = aead_authenc_decrypt, + .givencrypt = aead_authenc_givencrypt, + .geniv = "", + .ivsize = AES_BLOCK_SIZE, + .maxauthsize = SHA512_DIGEST_SIZE, + }, + .class1_alg_type = OP_ALG_ALGSEL_AES | OP_ALG_AAI_CBC, + .class2_alg_type = OP_ALG_ALGSEL_SHA512 | + OP_ALG_AAI_HMAC_PRECOMP, + .alg_op = OP_ALG_ALGSEL_SHA512 | OP_ALG_AAI_HMAC, + }, + { .name = "authenc(hmac(sha1),cbc(des3_ede))", .driver_name = "authenc-hmac-sha1-cbc-des3_ede-caam", .blocksize = DES3_EDE_BLOCK_SIZE, @@ -941,6 +990,25 @@ static struct caam_alg_template driver_algs[] = { .alg_op = OP_ALG_ALGSEL_SHA256 | OP_ALG_AAI_HMAC, }, { + .name = "authenc(hmac(sha512),cbc(des3_ede))", + .driver_name = "authenc-hmac-sha512-cbc-des3_ede-caam", + .blocksize = DES3_EDE_BLOCK_SIZE, + .aead = { + .setkey = aead_authenc_setkey, + .setauthsize = aead_authenc_setauthsize, + .encrypt = aead_authenc_encrypt, + .decrypt = aead_authenc_decrypt, + .givencrypt = aead_authenc_givencrypt, + .geniv = "", + .ivsize = DES3_EDE_BLOCK_SIZE, + .maxauthsize = SHA512_DIGEST_SIZE, + }, + .class1_alg_type = OP_ALG_ALGSEL_3DES | OP_ALG_AAI_CBC, + .class2_alg_type = OP_ALG_ALGSEL_SHA512 | + OP_ALG_AAI_HMAC_PRECOMP, + .alg_op = OP_ALG_ALGSEL_SHA512 | OP_ALG_AAI_HMAC, + }, + { .name = "authenc(hmac(sha1),cbc(des))", .driver_name = "authenc-hmac-sha1-cbc-des-caam", .blocksize = DES_BLOCK_SIZE, @@ -977,6 +1045,25 @@ static struct caam_alg_template driver_algs[] = { OP_ALG_AAI_HMAC_PRECOMP, .alg_op = OP_ALG_ALGSEL_SHA256 | OP_ALG_AAI_HMAC, }, + { + .name = "authenc(hmac(sha512),cbc(des))", + .driver_name = "authenc-hmac-sha512-cbc-des-caam", + .blocksize = DES_BLOCK_SIZE, + .aead = { + .setkey = aead_authenc_setkey, + .setauthsize = aead_authenc_setauthsize, + .encrypt = aead_authenc_encrypt, + .decrypt = aead_authenc_decrypt, + .givencrypt = aead_authenc_givencrypt, + .geniv = "", + .ivsize = DES_BLOCK_SIZE, + .maxauthsize = SHA512_DIGEST_SIZE, + }, + .class1_alg_type = OP_ALG_ALGSEL_DES | OP_ALG_AAI_CBC, + .class2_alg_type = OP_ALG_ALGSEL_SHA512 | + OP_ALG_AAI_HMAC_PRECOMP, + .alg_op = OP_ALG_ALGSEL_SHA512 | OP_ALG_AAI_HMAC, + }, }; struct caam_crypto_alg { @@ -1019,6 +1106,12 @@ static void caam_cra_exit(struct crypto_tfm *tfm) dma_unmap_single(ctx->jrdev, ctx->shared_desc_phys, desc_bytes(ctx->sh_desc), DMA_TO_DEVICE); kfree(ctx->sh_desc); + + if (!dma_mapping_error(ctx->jrdev, ctx->key_phys)) + dma_unmap_single(ctx->jrdev, ctx->key_phys, + ctx->split_key_pad_len + ctx->enckeylen, + DMA_TO_DEVICE); + kfree(ctx->key); } static void __exit caam_algapi_exit(void) diff --git a/drivers/crypto/caam/desc_constr.h b/drivers/crypto/caam/desc_constr.h index c224f39..4691580 100644 --- a/drivers/crypto/caam/desc_constr.h +++ b/drivers/crypto/caam/desc_constr.h @@ -9,6 +9,7 @@ #define IMMEDIATE (1 << 23) #define CAAM_CMD_SZ sizeof(u32) #define CAAM_PTR_SZ sizeof(dma_addr_t) +#define CAAM_DESC_BYTES_MAX (CAAM_CMD_SZ * 64) #ifdef DEBUG #define PRINT_POS do { printk(KERN_DEBUG "%02d: %s\n", desc_len(desc),\ -- cgit v0.10.2 From 3caba98fddd551ca7dcdb1eb701b36ed70b04fde Mon Sep 17 00:00:00 2001 From: Milton Miller Date: Tue, 10 May 2011 19:29:17 +0000 Subject: powerpc/mpic: Simplify ipi cpu mask handling Now that MSG_ALL and MSG_ALL_BUT_SELF have been eliminated, smp_mpic_mesage_pass no longer needs to lookup the cpumask just to have mpic_send_ipi extract part of it and recode it in a NR_CPUS loop by mpic_physmask. Signed-off-by: Milton Miller Signed-off-by: Benjamin Herrenschmidt diff --git a/arch/powerpc/sysdev/mpic.c b/arch/powerpc/sysdev/mpic.c index 68ea50c..53121f6 100644 --- a/arch/powerpc/sysdev/mpic.c +++ b/arch/powerpc/sysdev/mpic.c @@ -1613,30 +1613,28 @@ void mpic_request_ipis(void) } } -static void mpic_send_ipi(unsigned int ipi_no, const struct cpumask *cpu_mask) +void smp_mpic_message_pass(int cpu, int msg) { struct mpic *mpic = mpic_primary; + u32 physmask; BUG_ON(mpic == NULL); -#ifdef DEBUG_IPI - DBG("%s: send_ipi(ipi_no: %d)\n", mpic->name, ipi_no); -#endif - - mpic_cpu_write(MPIC_INFO(CPU_IPI_DISPATCH_0) + - ipi_no * MPIC_INFO(CPU_IPI_DISPATCH_STRIDE), - mpic_physmask(cpumask_bits(cpu_mask)[0])); -} - -void smp_mpic_message_pass(int cpu, int msg) -{ /* make sure we're sending something that translates to an IPI */ if ((unsigned int)msg > 3) { printk("SMP %d: smp_message_pass: unknown msg %d\n", smp_processor_id(), msg); return; } - mpic_send_ipi(msg, cpumask_of(cpu)); + +#ifdef DEBUG_IPI + DBG("%s: send_ipi(ipi_no: %d)\n", mpic->name, msg); +#endif + + physmask = 1 << get_hard_smp_processor_id(cpu); + + mpic_cpu_write(MPIC_INFO(CPU_IPI_DISPATCH_0) + + msg * MPIC_INFO(CPU_IPI_DISPATCH_STRIDE), physmask); } int __init smp_mpic_probe(void) -- cgit v0.10.2 From 7ca8aa0924712de81485c70e00bbea8c092a08c1 Mon Sep 17 00:00:00 2001 From: Milton Miller Date: Tue, 10 May 2011 19:29:20 +0000 Subject: powerpc: Remove powermac/pic.h Its unused, and of the three declarations, one is duplicated in pmac.h, the second is static and the third is renamed and static. Signed-off-by: Milton Miller Signed-off-by: Benjamin Herrenschmidt diff --git a/arch/powerpc/platforms/powermac/pic.h b/arch/powerpc/platforms/powermac/pic.h deleted file mode 100644 index d622a83..0000000 --- a/arch/powerpc/platforms/powermac/pic.h +++ /dev/null @@ -1,11 +0,0 @@ -#ifndef __PPC_PLATFORMS_PMAC_PIC_H -#define __PPC_PLATFORMS_PMAC_PIC_H - -#include - -extern struct irq_chip pmac_pic; - -extern void pmac_pic_init(void); -extern int pmac_get_irq(void); - -#endif /* __PPC_PLATFORMS_PMAC_PIC_H */ -- cgit v0.10.2 From a56555e573d3740d588d912aada506d57759cf5d Mon Sep 17 00:00:00 2001 From: Milton Miller Date: Tue, 10 May 2011 19:29:24 +0000 Subject: powerpc: Remove alloc_maybe_bootmem for zalloc version Replace all remaining callers of alloc_maybe_bootmem with zalloc_maybe_bootmem. The callsite in pci_dn is followed with a memset to clear the memory, and not zeroing at the other callsites in the celleb fake pci code could lead to following uninitialized memory as pointers or even freeing said pointers on error paths. Signed-off-by: Milton Miller Signed-off-by: Benjamin Herrenschmidt diff --git a/arch/powerpc/include/asm/system.h b/arch/powerpc/include/asm/system.h index 5e474dd..2dc595d 100644 --- a/arch/powerpc/include/asm/system.h +++ b/arch/powerpc/include/asm/system.h @@ -219,8 +219,6 @@ extern int mem_init_done; /* set on boot once kmalloc can be called */ extern int init_bootmem_done; /* set once bootmem is available */ extern phys_addr_t memory_limit; extern unsigned long klimit; - -extern void *alloc_maybe_bootmem(size_t size, gfp_t mask); extern void *zalloc_maybe_bootmem(size_t size, gfp_t mask); extern int powersave_nap; /* set if nap mode can be used in idle loop */ diff --git a/arch/powerpc/kernel/pci_dn.c b/arch/powerpc/kernel/pci_dn.c index d225d99..6baabc1 100644 --- a/arch/powerpc/kernel/pci_dn.c +++ b/arch/powerpc/kernel/pci_dn.c @@ -43,10 +43,9 @@ void * __devinit update_dn_pci_info(struct device_node *dn, void *data) const u32 *regs; struct pci_dn *pdn; - pdn = alloc_maybe_bootmem(sizeof(*pdn), GFP_KERNEL); + pdn = zalloc_maybe_bootmem(sizeof(*pdn), GFP_KERNEL); if (pdn == NULL) return NULL; - memset(pdn, 0, sizeof(*pdn)); dn->data = pdn; pdn->node = dn; pdn->phb = phb; diff --git a/arch/powerpc/lib/alloc.c b/arch/powerpc/lib/alloc.c index f53e09c..13b676c 100644 --- a/arch/powerpc/lib/alloc.c +++ b/arch/powerpc/lib/alloc.c @@ -6,14 +6,6 @@ #include -void * __init_refok alloc_maybe_bootmem(size_t size, gfp_t mask) -{ - if (mem_init_done) - return kmalloc(size, mask); - else - return alloc_bootmem(size); -} - void * __init_refok zalloc_maybe_bootmem(size_t size, gfp_t mask) { void *p; diff --git a/arch/powerpc/platforms/cell/celleb_pci.c b/arch/powerpc/platforms/cell/celleb_pci.c index 2904b0a..5822141 100644 --- a/arch/powerpc/platforms/cell/celleb_pci.c +++ b/arch/powerpc/platforms/cell/celleb_pci.c @@ -319,7 +319,7 @@ static int __init celleb_setup_fake_pci_device(struct device_node *node, size = 256; config = &private->fake_config[devno][fn]; - *config = alloc_maybe_bootmem(size, GFP_KERNEL); + *config = zalloc_maybe_bootmem(size, GFP_KERNEL); if (*config == NULL) { printk(KERN_ERR "PCI: " "not enough memory for fake configuration space\n"); @@ -330,7 +330,7 @@ static int __init celleb_setup_fake_pci_device(struct device_node *node, size = sizeof(struct celleb_pci_resource); res = &private->res[devno][fn]; - *res = alloc_maybe_bootmem(size, GFP_KERNEL); + *res = zalloc_maybe_bootmem(size, GFP_KERNEL); if (*res == NULL) { printk(KERN_ERR "PCI: not enough memory for resource data space\n"); @@ -431,7 +431,7 @@ static int __init phb_set_bus_ranges(struct device_node *dev, static void __init celleb_alloc_private_mem(struct pci_controller *hose) { hose->private_data = - alloc_maybe_bootmem(sizeof(struct celleb_pci_private), + zalloc_maybe_bootmem(sizeof(struct celleb_pci_private), GFP_KERNEL); } -- cgit v0.10.2 From d4fc8fe1f66f46493d3c56436685eef3b5b32b07 Mon Sep 17 00:00:00 2001 From: Milton Miller Date: Tue, 10 May 2011 19:29:28 +0000 Subject: powerpc: Remove stubbed beat smp support I have no idea if the beat hypervisor supports multiple cpus in a partition, but the code has not been touched since these stubs were added in February of 2007 except to move them in April of 2008. These are stubs: start_cpu always returns fail (which is dropped), the message passing and reciving are empty functions, and the top of file comment says "Incomplete". Signed-off-by: Milton Miller Signed-off-by: Benjamin Herrenschmidt diff --git a/arch/powerpc/platforms/cell/Makefile b/arch/powerpc/platforms/cell/Makefile index 8839ef6..a4a8935 100644 --- a/arch/powerpc/platforms/cell/Makefile +++ b/arch/powerpc/platforms/cell/Makefile @@ -43,7 +43,6 @@ obj-y += celleb_setup.o \ beat_hvCall.o beat_interrupt.o \ beat_iommu.o -obj-$(CONFIG_SMP) += beat_smp.o obj-$(CONFIG_PPC_UDBG_BEAT) += beat_udbg.o obj-$(CONFIG_SERIAL_TXX9) += celleb_scc_sio.o obj-$(CONFIG_SPU_BASE) += beat_spu_priv1.o diff --git a/arch/powerpc/platforms/cell/beat_interrupt.c b/arch/powerpc/platforms/cell/beat_interrupt.c index 4cb9e14..d46f7e4 100644 --- a/arch/powerpc/platforms/cell/beat_interrupt.c +++ b/arch/powerpc/platforms/cell/beat_interrupt.c @@ -257,22 +257,6 @@ void __init beatic_init_IRQ(void) irq_set_default_host(beatic_host); } -#ifdef CONFIG_SMP - -/* Nullified to compile with SMP mode */ -void beatic_setup_cpu(int cpu) -{ -} - -void beatic_cause_IPI(int cpu, int mesg) -{ -} - -void beatic_request_IPIs(void) -{ -} -#endif /* CONFIG_SMP */ - void beatic_deinit_IRQ(void) { int i; diff --git a/arch/powerpc/platforms/cell/beat_interrupt.h b/arch/powerpc/platforms/cell/beat_interrupt.h index b470fd0..a7e52f9 100644 --- a/arch/powerpc/platforms/cell/beat_interrupt.h +++ b/arch/powerpc/platforms/cell/beat_interrupt.h @@ -24,9 +24,6 @@ extern void beatic_init_IRQ(void); extern unsigned int beatic_get_irq(void); -extern void beatic_cause_IPI(int cpu, int mesg); -extern void beatic_request_IPIs(void); -extern void beatic_setup_cpu(int); extern void beatic_deinit_IRQ(void); #endif diff --git a/arch/powerpc/platforms/cell/beat_smp.c b/arch/powerpc/platforms/cell/beat_smp.c deleted file mode 100644 index 23bbe6e..0000000 --- a/arch/powerpc/platforms/cell/beat_smp.c +++ /dev/null @@ -1,107 +0,0 @@ -/* - * SMP support for Celleb platform. (Incomplete) - * - * (C) Copyright 2006 TOSHIBA CORPORATION - * - * This code is based on arch/powerpc/platforms/cell/smp.c: - * Dave Engebretsen, Peter Bergner, and - * Mike Corrigan {engebret|bergner|mikec}@us.ibm.com - * Plus various changes from other IBM teams... - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ - -#undef DEBUG - -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#include "beat_interrupt.h" - -#ifdef DEBUG -#define DBG(fmt...) udbg_printf(fmt) -#else -#define DBG(fmt...) -#endif - -/* - * The primary thread of each non-boot processor is recorded here before - * smp init. - */ -/* static cpumask_t of_spin_map; */ - -/** - * smp_startup_cpu() - start the given cpu - * - * At boot time, there is nothing to do for primary threads which were - * started from Open Firmware. For anything else, call RTAS with the - * appropriate start location. - * - * Returns: - * 0 - failure - * 1 - success - */ -static inline int __devinit smp_startup_cpu(unsigned int lcpu) -{ - return 0; -} - -static int __init smp_beatic_probe(void) -{ - return cpumask_weight(cpu_possible_mask); -} - -static void __devinit smp_beatic_setup_cpu(int cpu) -{ - beatic_setup_cpu(cpu); -} - -static int __devinit smp_celleb_kick_cpu(int nr) -{ - BUG_ON(nr < 0 || nr >= NR_CPUS); - - return smp_startup_cpu(nr); -} - -static int smp_celleb_cpu_bootable(unsigned int nr) -{ - return 1; -} -static struct smp_ops_t bpa_beatic_smp_ops = { - .message_pass = beatic_cause_IPI, - .probe = smp_beatic_probe, - .kick_cpu = smp_celleb_kick_cpu, - .setup_cpu = smp_beatic_setup_cpu, - .cpu_bootable = smp_celleb_cpu_bootable, -}; - -/* This is called very early */ -void __init smp_init_celleb(void) -{ - DBG(" -> smp_init_celleb()\n"); - - smp_ops = &bpa_beatic_smp_ops; - - DBG(" <- smp_init_celleb()\n"); -} diff --git a/arch/powerpc/platforms/cell/celleb_setup.c b/arch/powerpc/platforms/cell/celleb_setup.c index e538455..d58d9ba 100644 --- a/arch/powerpc/platforms/cell/celleb_setup.c +++ b/arch/powerpc/platforms/cell/celleb_setup.c @@ -128,10 +128,6 @@ static void __init celleb_setup_arch_beat(void) spu_management_ops = &spu_management_of_ops; #endif -#ifdef CONFIG_SMP - smp_init_celleb(); -#endif - celleb_setup_arch_common(); } -- cgit v0.10.2 From 17f9c8a73bac2c7dfe28a520516ea6b8bbbe977e Mon Sep 17 00:00:00 2001 From: Milton Miller Date: Tue, 10 May 2011 19:29:35 +0000 Subject: powerpc: Move smp_ops_t from machdep.h to smp.h I can't see any reason these functions are needed by machdep.h and they are all hidden by CONFIG_SMP with no UP alternative. Also move the declarations for the fallback timebase ops, which are used to fill in the smp ops. Signed-off-by: Milton Miller Signed-off-by: Benjamin Herrenschmidt diff --git a/arch/powerpc/include/asm/machdep.h b/arch/powerpc/include/asm/machdep.h index b0802a5..47cacddb 100644 --- a/arch/powerpc/include/asm/machdep.h +++ b/arch/powerpc/include/asm/machdep.h @@ -29,21 +29,6 @@ struct file; struct pci_controller; struct kimage; -#ifdef CONFIG_SMP -struct smp_ops_t { - void (*message_pass)(int cpu, int msg); - int (*probe)(void); - int (*kick_cpu)(int nr); - void (*setup_cpu)(int nr); - void (*bringup_done)(void); - void (*take_timebase)(void); - void (*give_timebase)(void); - int (*cpu_disable)(void); - void (*cpu_die)(unsigned int nr); - int (*cpu_bootable)(unsigned int nr); -}; -#endif - struct machdep_calls { char *name; #ifdef CONFIG_PPC64 @@ -312,12 +297,6 @@ extern sys_ctrler_t sys_ctrler; #endif /* CONFIG_PPC_PMAC */ -#ifdef CONFIG_SMP -/* Poor default implementations */ -extern void __devinit smp_generic_give_timebase(void); -extern void __devinit smp_generic_take_timebase(void); -#endif /* CONFIG_SMP */ - /* Functions to produce codes on the leds. * The SRC code should be unique for the message category and should diff --git a/arch/powerpc/include/asm/smp.h b/arch/powerpc/include/asm/smp.h index 91472c5..6f7c95c 100644 --- a/arch/powerpc/include/asm/smp.h +++ b/arch/powerpc/include/asm/smp.h @@ -35,9 +35,24 @@ extern void cpu_die(void); #ifdef CONFIG_SMP +struct smp_ops_t { + void (*message_pass)(int cpu, int msg); + int (*probe)(void); + int (*kick_cpu)(int nr); + void (*setup_cpu)(int nr); + void (*bringup_done)(void); + void (*take_timebase)(void); + void (*give_timebase)(void); + int (*cpu_disable)(void); + void (*cpu_die)(unsigned int nr); + int (*cpu_bootable)(unsigned int nr); +}; + extern void smp_send_debugger_break(void); extern void smp_message_recv(int); extern void start_secondary_resume(void); +extern void __devinit smp_generic_give_timebase(void); +extern void __devinit smp_generic_take_timebase(void); DECLARE_PER_CPU(unsigned int, cpu_pvr); -- cgit v0.10.2 From 23d72bfd8f9f24aa9efafed3586a99f5669c23d7 Mon Sep 17 00:00:00 2001 From: Milton Miller Date: Tue, 10 May 2011 19:29:39 +0000 Subject: powerpc: Consolidate ipi message mux and demux Consolidate the mux and demux of ipi messages into smp.c and call a new smp_ops callback to actually trigger the ipi. The powerpc architecture code is optimised for having 4 distinct ipi triggers, which are mapped to 4 distinct messages (ipi many, ipi single, scheduler ipi, and enter debugger). However, several interrupt controllers only provide a single software triggered interrupt that can be delivered to each cpu. To resolve this limitation, each smp_ops implementation created a per-cpu variable that is manipulated with atomic bitops. Since these lines will be contended they are optimialy marked as shared_aligned and take a full cache line for each cpu. Distro kernels may have 2 or 3 of these in their config, each taking per-cpu space even though at most one will be in use. This consolidation removes smp_message_recv and replaces the single call actions cases with direct calls from the common message recognition loop. The complicated debugger ipi case with its muxed crash handling code is moved to debug_ipi_action which is now called from the demux code (instead of the multi-message action calling smp_message_recv). I put a call to reschedule_action to increase the likelyhood of correctly merging the anticipated scheduler_ipi() hook coming from the scheduler tree; that single required call can be inlined later. The actual message decode is a copy of the old pseries xics code with its memory barriers and cache line spacing, augmented with a per-cpu unsigned long based on the book-e doorbell code. The optional data is set via a callback from the implementation and is passed to the new cause-ipi hook along with the logical cpu number. While currently only the doorbell implemntation uses this data it should be almost zero cost to retrieve and pass it -- it adds a single register load for the argument from the same cache line to which we just completed a store and the register is dead on return from the call. I extended the data element from unsigned int to unsigned long in case some other code wanted to associate a pointer. The doorbell check_self is replaced by a call to smp_muxed_ipi_resend, conditioned on the CPU_DBELL feature. The ifdef guard could be relaxed to CONFIG_SMP but I left it with BOOKE for now. Also, the doorbell interrupt vector for book-e was not calling irq_enter and irq_exit, which throws off cpu accounting and causes code to not realize it is running in interrupt context. Add the missing calls. Signed-off-by: Milton Miller Signed-off-by: Benjamin Herrenschmidt diff --git a/arch/powerpc/include/asm/dbell.h b/arch/powerpc/include/asm/dbell.h index 3269eb4..9c70d0c 100644 --- a/arch/powerpc/include/asm/dbell.h +++ b/arch/powerpc/include/asm/dbell.h @@ -27,9 +27,8 @@ enum ppc_dbell { PPC_G_DBELL_MC = 4, /* guest mcheck doorbell */ }; -extern void doorbell_message_pass(int cpu, int msg); +extern void doorbell_cause_ipi(int cpu, unsigned long data); extern void doorbell_exception(struct pt_regs *regs); -extern void doorbell_check_self(void); extern void doorbell_setup_this_cpu(void); static inline void ppc_msgsnd(enum ppc_dbell type, u32 flags, u32 tag) diff --git a/arch/powerpc/include/asm/smp.h b/arch/powerpc/include/asm/smp.h index 6f7c95c..26f8615 100644 --- a/arch/powerpc/include/asm/smp.h +++ b/arch/powerpc/include/asm/smp.h @@ -20,6 +20,7 @@ #include #include #include +#include #ifndef __ASSEMBLY__ @@ -37,6 +38,7 @@ extern void cpu_die(void); struct smp_ops_t { void (*message_pass)(int cpu, int msg); + void (*cause_ipi)(int cpu, unsigned long data); int (*probe)(void); int (*kick_cpu)(int nr); void (*setup_cpu)(int nr); @@ -49,7 +51,6 @@ struct smp_ops_t { }; extern void smp_send_debugger_break(void); -extern void smp_message_recv(int); extern void start_secondary_resume(void); extern void __devinit smp_generic_give_timebase(void); extern void __devinit smp_generic_take_timebase(void); @@ -109,13 +110,16 @@ extern int cpu_to_core_id(int cpu); #define PPC_MSG_CALL_FUNC_SINGLE 2 #define PPC_MSG_DEBUGGER_BREAK 3 -/* - * irq controllers that have dedicated ipis per message and don't - * need additional code in the action handler may use this - */ +/* for irq controllers that have dedicated ipis per message (4) */ extern int smp_request_message_ipi(int virq, int message); extern const char *smp_ipi_name[]; +/* for irq controllers with only a single ipi */ +extern void smp_muxed_ipi_set_data(int cpu, unsigned long data); +extern void smp_muxed_ipi_message_pass(int cpu, int msg); +extern void smp_muxed_ipi_resend(void); +extern irqreturn_t smp_ipi_demux(void); + void smp_init_iSeries(void); void smp_init_pSeries(void); void smp_init_cell(void); @@ -185,6 +189,8 @@ extern unsigned long __secondary_hold_spinloop; extern unsigned long __secondary_hold_acknowledge; extern char __secondary_hold; +extern irqreturn_t debug_ipi_action(int irq, void *data); + #endif /* __ASSEMBLY__ */ #endif /* __KERNEL__ */ diff --git a/arch/powerpc/include/asm/xics.h b/arch/powerpc/include/asm/xics.h index 1750c8d..b183a40 100644 --- a/arch/powerpc/include/asm/xics.h +++ b/arch/powerpc/include/asm/xics.h @@ -40,7 +40,7 @@ struct icp_ops { void (*teardown_cpu)(void); void (*flush_ipi)(void); #ifdef CONFIG_SMP - void (*message_pass)(int cpu, int msg); + void (*cause_ipi)(int cpu, unsigned long data); irq_handler_t ipi_action; #endif }; diff --git a/arch/powerpc/kernel/dbell.c b/arch/powerpc/kernel/dbell.c index e49b24c..2cc451a 100644 --- a/arch/powerpc/kernel/dbell.c +++ b/arch/powerpc/kernel/dbell.c @@ -13,65 +13,35 @@ #include #include #include -#include +#include #include #include #ifdef CONFIG_SMP -struct doorbell_cpu_info { - unsigned long messages; /* current messages bits */ - unsigned int tag; /* tag value */ -}; - -static DEFINE_PER_CPU(struct doorbell_cpu_info, doorbell_cpu_info); - void doorbell_setup_this_cpu(void) { - struct doorbell_cpu_info *info = &__get_cpu_var(doorbell_cpu_info); + unsigned long tag = mfspr(SPRN_PIR) & 0x3fff; - info->messages = 0; - info->tag = mfspr(SPRN_PIR) & 0x3fff; + smp_muxed_ipi_set_data(smp_processor_id(), tag); } -void doorbell_message_pass(int cpu, int msg) +void doorbell_cause_ipi(int cpu, unsigned long data) { - struct doorbell_cpu_info *info; - - info = &per_cpu(doorbell_cpu_info, cpu); - set_bit(msg, &info->messages); - ppc_msgsnd(PPC_DBELL, 0, info->tag); + ppc_msgsnd(PPC_DBELL, 0, data); } void doorbell_exception(struct pt_regs *regs) { struct pt_regs *old_regs = set_irq_regs(regs); - struct doorbell_cpu_info *info = &__get_cpu_var(doorbell_cpu_info); - int msg; - /* Warning: regs can be NULL when called from irq enable */ + irq_enter(); - if (!info->messages || (num_online_cpus() < 2)) - goto out; + smp_ipi_demux(); - for (msg = 0; msg < 4; msg++) - if (test_and_clear_bit(msg, &info->messages)) - smp_message_recv(msg); - -out: + irq_exit(); set_irq_regs(old_regs); } - -void doorbell_check_self(void) -{ - struct doorbell_cpu_info *info = &__get_cpu_var(doorbell_cpu_info); - - if (!info->messages) - return; - - ppc_msgsnd(PPC_DBELL, 0, info->tag); -} - #else /* CONFIG_SMP */ void doorbell_exception(struct pt_regs *regs) { diff --git a/arch/powerpc/kernel/irq.c b/arch/powerpc/kernel/irq.c index a81dd74..826552c 100644 --- a/arch/powerpc/kernel/irq.c +++ b/arch/powerpc/kernel/irq.c @@ -66,7 +66,6 @@ #include #include #include -#include #include #ifdef CONFIG_PPC64 @@ -160,7 +159,8 @@ notrace void arch_local_irq_restore(unsigned long en) #if defined(CONFIG_BOOKE) && defined(CONFIG_SMP) /* Check for pending doorbell interrupts and resend to ourself */ - doorbell_check_self(); + if (cpu_has_feature(CPU_FTR_DBELL)) + smp_muxed_ipi_resend(); #endif /* diff --git a/arch/powerpc/kernel/smp.c b/arch/powerpc/kernel/smp.c index b744114..fa8e870 100644 --- a/arch/powerpc/kernel/smp.c +++ b/arch/powerpc/kernel/smp.c @@ -111,35 +111,6 @@ int __devinit smp_generic_kick_cpu(int nr) } #endif -void smp_message_recv(int msg) -{ - switch(msg) { - case PPC_MSG_CALL_FUNCTION: - generic_smp_call_function_interrupt(); - break; - case PPC_MSG_RESCHEDULE: - /* we notice need_resched on exit */ - break; - case PPC_MSG_CALL_FUNC_SINGLE: - generic_smp_call_function_single_interrupt(); - break; - case PPC_MSG_DEBUGGER_BREAK: - if (crash_ipi_function_ptr) { - crash_ipi_function_ptr(get_irq_regs()); - break; - } -#ifdef CONFIG_DEBUGGER - debugger_ipi(get_irq_regs()); - break; -#endif /* CONFIG_DEBUGGER */ - /* FALLTHROUGH */ - default: - printk("SMP %d: smp_message_recv(): unknown msg %d\n", - smp_processor_id(), msg); - break; - } -} - static irqreturn_t call_function_action(int irq, void *data) { generic_smp_call_function_interrupt(); @@ -158,9 +129,17 @@ static irqreturn_t call_function_single_action(int irq, void *data) return IRQ_HANDLED; } -static irqreturn_t debug_ipi_action(int irq, void *data) +irqreturn_t debug_ipi_action(int irq, void *data) { - smp_message_recv(PPC_MSG_DEBUGGER_BREAK); + if (crash_ipi_function_ptr) { + crash_ipi_function_ptr(get_irq_regs()); + return IRQ_HANDLED; + } + +#ifdef CONFIG_DEBUGGER + debugger_ipi(get_irq_regs()); +#endif /* CONFIG_DEBUGGER */ + return IRQ_HANDLED; } @@ -199,6 +178,59 @@ int smp_request_message_ipi(int virq, int msg) return err; } +struct cpu_messages { + unsigned long messages; /* current messages bits */ + unsigned long data; /* data for cause ipi */ +}; +static DEFINE_PER_CPU_SHARED_ALIGNED(struct cpu_messages, ipi_message); + +void smp_muxed_ipi_set_data(int cpu, unsigned long data) +{ + struct cpu_messages *info = &per_cpu(ipi_message, cpu); + + info->data = data; +} + +void smp_muxed_ipi_message_pass(int cpu, int msg) +{ + struct cpu_messages *info = &per_cpu(ipi_message, cpu); + unsigned long *tgt = &info->messages; + + set_bit(msg, tgt); + mb(); + smp_ops->cause_ipi(cpu, info->data); +} + +void smp_muxed_ipi_resend(void) +{ + struct cpu_messages *info = &__get_cpu_var(ipi_message); + unsigned long *tgt = &info->messages; + + if (*tgt) + smp_ops->cause_ipi(smp_processor_id(), info->data); +} + +irqreturn_t smp_ipi_demux(void) +{ + struct cpu_messages *info = &__get_cpu_var(ipi_message); + unsigned long *tgt = &info->messages; + + mb(); /* order any irq clear */ + while (*tgt) { + if (test_and_clear_bit(PPC_MSG_CALL_FUNCTION, tgt)) + generic_smp_call_function_interrupt(); + if (test_and_clear_bit(PPC_MSG_RESCHEDULE, tgt)) + reschedule_action(0, NULL); /* upcoming sched hook */ + if (test_and_clear_bit(PPC_MSG_CALL_FUNC_SINGLE, tgt)) + generic_smp_call_function_single_interrupt(); +#if defined(CONFIG_DEBUGGER) || defined(CONFIG_KEXEC) + if (test_and_clear_bit(PPC_MSG_DEBUGGER_BREAK, tgt)) + debug_ipi_action(0, NULL); +#endif + } + return IRQ_HANDLED; +} + void smp_send_reschedule(int cpu) { if (likely(smp_ops)) diff --git a/arch/powerpc/platforms/85xx/smp.c b/arch/powerpc/platforms/85xx/smp.c index fe3f6a3..d6a93a10 100644 --- a/arch/powerpc/platforms/85xx/smp.c +++ b/arch/powerpc/platforms/85xx/smp.c @@ -235,8 +235,10 @@ void __init mpc85xx_smp_init(void) smp_85xx_ops.message_pass = smp_mpic_message_pass; } - if (cpu_has_feature(CPU_FTR_DBELL)) - smp_85xx_ops.message_pass = doorbell_message_pass; + if (cpu_has_feature(CPU_FTR_DBELL)) { + smp_85xx_ops.message_pass = smp_muxed_ipi_message_pass; + smp_85xx_ops.cause_ipi = doorbell_cause_ipi; + } BUG_ON(!smp_85xx_ops.message_pass); diff --git a/arch/powerpc/platforms/cell/interrupt.c b/arch/powerpc/platforms/cell/interrupt.c index 44cfd1b..6a58744 100644 --- a/arch/powerpc/platforms/cell/interrupt.c +++ b/arch/powerpc/platforms/cell/interrupt.c @@ -196,8 +196,20 @@ static irqreturn_t iic_ipi_action(int irq, void *dev_id) { int ipi = (int)(long)dev_id; - smp_message_recv(ipi); - + switch(ipi) { + case PPC_MSG_CALL_FUNCTION: + generic_smp_call_function_interrupt(); + break; + case PPC_MSG_RESCHEDULE: + /* Upcoming sched hook */ + break; + case PPC_MSG_CALL_FUNC_SINGLE: + generic_smp_call_function_single_interrupt(); + break; + case PPC_MSG_DEBUGGER_BREAK: + debug_ipi_action(0, NULL); + break; + } return IRQ_HANDLED; } static void iic_request_ipi(int ipi, const char *name) diff --git a/arch/powerpc/platforms/iseries/irq.c b/arch/powerpc/platforms/iseries/irq.c index 375c21c..b210345 100644 --- a/arch/powerpc/platforms/iseries/irq.c +++ b/arch/powerpc/platforms/iseries/irq.c @@ -42,7 +42,6 @@ #include "irq.h" #include "pci.h" #include "call_pci.h" -#include "smp.h" #ifdef CONFIG_PCI @@ -316,7 +315,7 @@ unsigned int iSeries_get_irq(void) #ifdef CONFIG_SMP if (get_lppaca()->int_dword.fields.ipi_cnt) { get_lppaca()->int_dword.fields.ipi_cnt = 0; - iSeries_smp_message_recv(); + smp_ipi_demux(); } #endif /* CONFIG_SMP */ if (hvlpevent_is_pending()) diff --git a/arch/powerpc/platforms/iseries/smp.c b/arch/powerpc/platforms/iseries/smp.c index dcdbc5d..e3265ad 100644 --- a/arch/powerpc/platforms/iseries/smp.c +++ b/arch/powerpc/platforms/iseries/smp.c @@ -42,26 +42,8 @@ #include #include -#include "smp.h" - -static unsigned long iSeries_smp_message[NR_CPUS]; - -void iSeries_smp_message_recv(void) -{ - int cpu = smp_processor_id(); - int msg; - - if (num_online_cpus() < 2) - return; - - for (msg = 0; msg < 4; msg++) - if (test_and_clear_bit(msg, &iSeries_smp_message[cpu])) - smp_message_recv(msg); -} - -static void smp_iSeries_message_pass(int cpu, int msg) +static void smp_iSeries_cause_ipi(int cpu, unsigned long data) { - set_bit(msg, &iSeries_smp_message[cpu]); HvCall_sendIPI(&(paca[cpu])); } @@ -93,7 +75,8 @@ static void __devinit smp_iSeries_setup_cpu(int nr) } static struct smp_ops_t iSeries_smp_ops = { - .message_pass = smp_iSeries_message_pass, + .message_pass = smp_muxed_ipi_message_pass, + .cause_ipi = smp_iSeries_cause_ipi, .probe = smp_iSeries_probe, .kick_cpu = smp_iSeries_kick_cpu, .setup_cpu = smp_iSeries_setup_cpu, diff --git a/arch/powerpc/platforms/iseries/smp.h b/arch/powerpc/platforms/iseries/smp.h deleted file mode 100644 index d501f7d..0000000 --- a/arch/powerpc/platforms/iseries/smp.h +++ /dev/null @@ -1,6 +0,0 @@ -#ifndef _PLATFORMS_ISERIES_SMP_H -#define _PLATFORMS_ISERIES_SMP_H - -extern void iSeries_smp_message_recv(void); - -#endif /* _PLATFORMS_ISERIES_SMP_H */ diff --git a/arch/powerpc/platforms/powermac/smp.c b/arch/powerpc/platforms/powermac/smp.c index c49e719..a340107 100644 --- a/arch/powerpc/platforms/powermac/smp.c +++ b/arch/powerpc/platforms/powermac/smp.c @@ -156,28 +156,13 @@ static inline void psurge_clr_ipi(int cpu) /* * On powersurge (old SMP powermac architecture) we don't have * separate IPIs for separate messages like openpic does. Instead - * we have a bitmap for each processor, where a 1 bit means that - * the corresponding message is pending for that processor. - * Ideally each cpu's entry would be in a different cache line. + * use the generic demux helpers * -- paulus. */ -static unsigned long psurge_smp_message[NR_CPUS]; - void psurge_smp_message_recv(void) { - int cpu = smp_processor_id(); - int msg; - - /* clear interrupt */ - psurge_clr_ipi(cpu); - - if (num_online_cpus() < 2) - return; - - /* make sure there is a message there */ - for (msg = 0; msg < 4; msg++) - if (test_and_clear_bit(msg, &psurge_smp_message[cpu])) - smp_message_recv(msg); + psurge_clr_ipi(smp_processor_id()); + smp_ipi_demux(); } irqreturn_t psurge_primary_intr(int irq, void *d) @@ -186,9 +171,8 @@ irqreturn_t psurge_primary_intr(int irq, void *d) return IRQ_HANDLED; } -static void smp_psurge_message_pass(int cpu, int msg) +static void smp_psurge_cause_ipi(int cpu, unsigned long data) { - set_bit(msg, &psurge_smp_message[cpu]); psurge_set_ipi(cpu); } @@ -428,7 +412,8 @@ void __init smp_psurge_give_timebase(void) /* PowerSurge-style Macs */ struct smp_ops_t psurge_smp_ops = { - .message_pass = smp_psurge_message_pass, + .message_pass = smp_muxed_ipi_message_pass, + .cause_ipi = smp_psurge_cause_ipi, .probe = smp_psurge_probe, .kick_cpu = smp_psurge_kick_cpu, .setup_cpu = smp_psurge_setup_cpu, diff --git a/arch/powerpc/platforms/pseries/smp.c b/arch/powerpc/platforms/pseries/smp.c index 95f5781..fbffd7e 100644 --- a/arch/powerpc/platforms/pseries/smp.c +++ b/arch/powerpc/platforms/pseries/smp.c @@ -207,7 +207,8 @@ static struct smp_ops_t pSeries_mpic_smp_ops = { }; static struct smp_ops_t pSeries_xics_smp_ops = { - .message_pass = NULL, /* Filled at runtime by xics_smp_probe() */ + .message_pass = smp_muxed_ipi_message_pass, + .cause_ipi = NULL, /* Filled at runtime by xics_smp_probe() */ .probe = xics_smp_probe, .kick_cpu = smp_pSeries_kick_cpu, .setup_cpu = smp_xics_setup_cpu, diff --git a/arch/powerpc/platforms/wsp/smp.c b/arch/powerpc/platforms/wsp/smp.c index c7b8db9..9d20fa9 100644 --- a/arch/powerpc/platforms/wsp/smp.c +++ b/arch/powerpc/platforms/wsp/smp.c @@ -75,7 +75,8 @@ static int __init smp_a2_probe(void) } static struct smp_ops_t a2_smp_ops = { - .message_pass = doorbell_message_pass, + .message_pass = smp_muxed_ipi_message_pass, + .cause_ipi = doorbell_cause_ipi, .probe = smp_a2_probe, .kick_cpu = smp_a2_kick_cpu, .setup_cpu = smp_a2_setup_cpu, diff --git a/arch/powerpc/sysdev/xics/icp-hv.c b/arch/powerpc/sysdev/xics/icp-hv.c index 234764c..9518d36 100644 --- a/arch/powerpc/sysdev/xics/icp-hv.c +++ b/arch/powerpc/sysdev/xics/icp-hv.c @@ -118,12 +118,8 @@ static void icp_hv_set_cpu_priority(unsigned char cppr) #ifdef CONFIG_SMP -static void icp_hv_message_pass(int cpu, int msg) +static void icp_hv_cause_ipi(int cpu, unsigned long data) { - unsigned long *tgt = &per_cpu(xics_ipi_message, cpu); - - set_bit(msg, tgt); - mb(); icp_hv_set_qirr(cpu, IPI_PRIORITY); } @@ -133,7 +129,7 @@ static irqreturn_t icp_hv_ipi_action(int irq, void *dev_id) icp_hv_set_qirr(cpu, 0xff); - return xics_ipi_dispatch(cpu); + return smp_ipi_demux(); } #endif /* CONFIG_SMP */ @@ -146,7 +142,7 @@ static const struct icp_ops icp_hv_ops = { .flush_ipi = icp_hv_flush_ipi, #ifdef CONFIG_SMP .ipi_action = icp_hv_ipi_action, - .message_pass = icp_hv_message_pass, + .cause_ipi = icp_hv_cause_ipi, #endif }; diff --git a/arch/powerpc/sysdev/xics/icp-native.c b/arch/powerpc/sysdev/xics/icp-native.c index 246500e..1f15ad4 100644 --- a/arch/powerpc/sysdev/xics/icp-native.c +++ b/arch/powerpc/sysdev/xics/icp-native.c @@ -134,12 +134,8 @@ static unsigned int icp_native_get_irq(void) #ifdef CONFIG_SMP -static void icp_native_message_pass(int cpu, int msg) +static void icp_native_cause_ipi(int cpu, unsigned long data) { - unsigned long *tgt = &per_cpu(xics_ipi_message, cpu); - - set_bit(msg, tgt); - mb(); icp_native_set_qirr(cpu, IPI_PRIORITY); } @@ -149,7 +145,7 @@ static irqreturn_t icp_native_ipi_action(int irq, void *dev_id) icp_native_set_qirr(cpu, 0xff); - return xics_ipi_dispatch(cpu); + return smp_ipi_demux(); } #endif /* CONFIG_SMP */ @@ -267,7 +263,7 @@ static const struct icp_ops icp_native_ops = { .flush_ipi = icp_native_flush_ipi, #ifdef CONFIG_SMP .ipi_action = icp_native_ipi_action, - .message_pass = icp_native_message_pass, + .cause_ipi = icp_native_cause_ipi, #endif }; diff --git a/arch/powerpc/sysdev/xics/xics-common.c b/arch/powerpc/sysdev/xics/xics-common.c index a0576b7..a31a710 100644 --- a/arch/powerpc/sysdev/xics/xics-common.c +++ b/arch/powerpc/sysdev/xics/xics-common.c @@ -126,32 +126,6 @@ void xics_mask_unknown_vec(unsigned int vec) #ifdef CONFIG_SMP -DEFINE_PER_CPU_SHARED_ALIGNED(unsigned long, xics_ipi_message); - -irqreturn_t xics_ipi_dispatch(int cpu) -{ - unsigned long *tgt = &per_cpu(xics_ipi_message, cpu); - - mb(); /* order mmio clearing qirr */ - while (*tgt) { - if (test_and_clear_bit(PPC_MSG_CALL_FUNCTION, tgt)) { - smp_message_recv(PPC_MSG_CALL_FUNCTION); - } - if (test_and_clear_bit(PPC_MSG_RESCHEDULE, tgt)) { - smp_message_recv(PPC_MSG_RESCHEDULE); - } - if (test_and_clear_bit(PPC_MSG_CALL_FUNC_SINGLE, tgt)) { - smp_message_recv(PPC_MSG_CALL_FUNC_SINGLE); - } -#if defined(CONFIG_DEBUGGER) || defined(CONFIG_KEXEC) - if (test_and_clear_bit(PPC_MSG_DEBUGGER_BREAK, tgt)) { - smp_message_recv(PPC_MSG_DEBUGGER_BREAK); - } -#endif - } - return IRQ_HANDLED; -} - static void xics_request_ipi(void) { unsigned int ipi; @@ -170,8 +144,8 @@ static void xics_request_ipi(void) int __init xics_smp_probe(void) { - /* Setup message_pass callback based on which ICP is used */ - smp_ops->message_pass = icp_ops->message_pass; + /* Setup cause_ipi callback based on which ICP is used */ + smp_ops->cause_ipi = icp_ops->cause_ipi; /* Register all the IPIs */ xics_request_ipi(); -- cgit v0.10.2 From 1ece355b6825b7c61d1dc39a5c6cf49dc746e193 Mon Sep 17 00:00:00 2001 From: Milton Miller Date: Tue, 10 May 2011 19:29:42 +0000 Subject: powerpc: Add kconfig for muxed smp ipi support Compile the new smp ipi mux and demux code only if a platform will make use of it. The new config is selected as required. The new cause_ipi smp op is only available conditionally to point out configs where the select is required; this makes setting the op an immediate fail instead of a deferred unresolved symbol at link. This also creates a new config for power surge powermac upgrade support that can be disabled in expert mode but is default on. I also removed the depends / default y on CONFIG_XICS since it is selected by PSERIES. Signed-off-by: Milton Miller Signed-off-by: Benjamin Herrenschmidt diff --git a/arch/powerpc/include/asm/smp.h b/arch/powerpc/include/asm/smp.h index 26f8615..880b8c1 100644 --- a/arch/powerpc/include/asm/smp.h +++ b/arch/powerpc/include/asm/smp.h @@ -38,7 +38,9 @@ extern void cpu_die(void); struct smp_ops_t { void (*message_pass)(int cpu, int msg); +#ifdef CONFIG_PPC_SMP_MUXED_IPI void (*cause_ipi)(int cpu, unsigned long data); +#endif int (*probe)(void); int (*kick_cpu)(int nr); void (*setup_cpu)(int nr); diff --git a/arch/powerpc/kernel/smp.c b/arch/powerpc/kernel/smp.c index fa8e870..d76f7d7 100644 --- a/arch/powerpc/kernel/smp.c +++ b/arch/powerpc/kernel/smp.c @@ -178,6 +178,7 @@ int smp_request_message_ipi(int virq, int msg) return err; } +#ifdef CONFIG_PPC_SMP_MUXED_IPI struct cpu_messages { unsigned long messages; /* current messages bits */ unsigned long data; /* data for cause ipi */ @@ -230,6 +231,7 @@ irqreturn_t smp_ipi_demux(void) } return IRQ_HANDLED; } +#endif /* CONFIG_PPC_SMP_MUXED_IPI */ void smp_send_reschedule(int cpu) { diff --git a/arch/powerpc/platforms/Kconfig b/arch/powerpc/platforms/Kconfig index 6059053..83c704a 100644 --- a/arch/powerpc/platforms/Kconfig +++ b/arch/powerpc/platforms/Kconfig @@ -57,6 +57,14 @@ config UDBG_RTAS_CONSOLE depends on PPC_RTAS default n +config PPC_SMP_MUXED_IPI + bool + help + Select this opton if your platform supports SMP and your + interrupt controller provides less than 4 interrupts to each + cpu. This will enable the generic code to multiplex the 4 + messages on to one ipi. + config PPC_UDBG_BEAT bool "BEAT based debug console" depends on PPC_CELLEB diff --git a/arch/powerpc/platforms/Kconfig.cputype b/arch/powerpc/platforms/Kconfig.cputype index a1e6238..2165b65 100644 --- a/arch/powerpc/platforms/Kconfig.cputype +++ b/arch/powerpc/platforms/Kconfig.cputype @@ -73,6 +73,7 @@ config PPC_BOOK3S_64 config PPC_BOOK3E_64 bool "Embedded processors" select PPC_FPU # Make it a choice ? + select PPC_SMP_MUXED_IPI endchoice @@ -178,6 +179,7 @@ config FSL_BOOKE config PPC_FSL_BOOK3E bool select FSL_EMB_PERFMON + select PPC_SMP_MUXED_IPI default y if FSL_BOOKE config PTE_64BIT diff --git a/arch/powerpc/platforms/iseries/Kconfig b/arch/powerpc/platforms/iseries/Kconfig index ea1d362..b57cda3 100644 --- a/arch/powerpc/platforms/iseries/Kconfig +++ b/arch/powerpc/platforms/iseries/Kconfig @@ -1,6 +1,7 @@ config PPC_ISERIES bool "IBM Legacy iSeries" depends on PPC64 && PPC_BOOK3S + select PPC_SMP_MUXED_IPI select PPC_INDIRECT_PIO select PPC_INDIRECT_MMIO select PPC_PCI_CHOICE if EXPERT diff --git a/arch/powerpc/platforms/powermac/Kconfig b/arch/powerpc/platforms/powermac/Kconfig index 1e1a087..1afd10f 100644 --- a/arch/powerpc/platforms/powermac/Kconfig +++ b/arch/powerpc/platforms/powermac/Kconfig @@ -18,4 +18,13 @@ config PPC_PMAC64 select PPC_970_NAP default y - +config PPC_PMAC32_PSURGE + bool "Support for powersurge upgrade cards" if EXPERT + depends on SMP && PPC32 && PPC_PMAC + select PPC_SMP_MUXED_IPI + default y + help + The powersurge cpu boards can be used in the generation + of powermacs that have a socket for an upgradeable cpu card, + including the 7500, 8500, 9500, 9600. Support exists for + both dual and quad socket upgrade cards. diff --git a/arch/powerpc/platforms/powermac/pic.c b/arch/powerpc/platforms/powermac/pic.c index 2f34ad0..b706cb3 100644 --- a/arch/powerpc/platforms/powermac/pic.c +++ b/arch/powerpc/platforms/powermac/pic.c @@ -239,7 +239,7 @@ static unsigned int pmac_pic_get_irq(void) unsigned long bits = 0; unsigned long flags; -#ifdef CONFIG_SMP +#ifdef CONFIG_PPC_PMAC32_PSURGE void psurge_smp_message_recv(void); /* IPI's are a hack on the powersurge -- Cort */ @@ -247,7 +247,7 @@ static unsigned int pmac_pic_get_irq(void) psurge_smp_message_recv(); return NO_IRQ_IGNORE; /* ignore, already handled */ } -#endif /* CONFIG_SMP */ +#endif /* CONFIG_PPC_PMAC32_PSURGE */ raw_spin_lock_irqsave(&pmac_pic_lock, flags); for (irq = max_real_irqs; (irq -= 32) >= 0; ) { int i = irq >> 5; diff --git a/arch/powerpc/platforms/powermac/smp.c b/arch/powerpc/platforms/powermac/smp.c index a340107..67b6e14 100644 --- a/arch/powerpc/platforms/powermac/smp.c +++ b/arch/powerpc/platforms/powermac/smp.c @@ -70,7 +70,7 @@ static void (*pmac_tb_freeze)(int freeze); static u64 timebase; static int tb_req; -#ifdef CONFIG_PPC32 +#ifdef CONFIG_PPC_PMAC32_PSURGE /* * Powersurge (old powermac SMP) support. @@ -420,7 +420,7 @@ struct smp_ops_t psurge_smp_ops = { .give_timebase = smp_psurge_give_timebase, .take_timebase = smp_psurge_take_timebase, }; -#endif /* CONFIG_PPC32 - actually powersurge support */ +#endif /* CONFIG_PPC_PMAC32_PSURGE */ /* * Core 99 and later support @@ -980,7 +980,7 @@ void __init pmac_setup_smp(void) of_node_put(np); smp_ops = &core99_smp_ops; } -#ifdef CONFIG_PPC32 +#ifdef CONFIG_PPC_PMAC32_PSURGE else { /* We have to set bits in cpu_possible_mask here since the * secondary CPU(s) aren't in the device tree. Various @@ -993,7 +993,7 @@ void __init pmac_setup_smp(void) set_cpu_possible(cpu, true); smp_ops = &psurge_smp_ops; } -#endif /* CONFIG_PPC32 */ +#endif /* CONFIG_PPC_PMAC32_PSURGE */ #ifdef CONFIG_HOTPLUG_CPU ppc_md.cpu_die = pmac_cpu_die; diff --git a/arch/powerpc/sysdev/xics/Kconfig b/arch/powerpc/sysdev/xics/Kconfig index 123b8dd..0031eda 100644 --- a/arch/powerpc/sysdev/xics/Kconfig +++ b/arch/powerpc/sysdev/xics/Kconfig @@ -1,5 +1,6 @@ config PPC_XICS def_bool n + select PPC_SMP_MUXED_IPI config PPC_ICP_NATIVE def_bool n -- cgit v0.10.2 From 714542721b4a53a3ebbdd5f0619ac0f66e7df610 Mon Sep 17 00:00:00 2001 From: Milton Miller Date: Tue, 10 May 2011 19:29:46 +0000 Subject: powerpc: Use bytes instead of bitops in smp ipi multiplexing Since there are only 4 messages, we can replace the atomic bit set (which uses atomic load reserve and store conditional sequence) with a byte stores to seperate bytes. We still have to perform a load reserve and store conditional sequence to avoid loosing messages on reception but we can do that with a single call to xchg. The do {} while and __BIG_ENDIAN specific mask testing was chosen by looking at the generated asm code. On gcc-4.4, the bit masking becomes a simple bit mask and test of the register returned from xchg without storing and loading the value to the stack like attempts with a union of bytes and an int (or worse, loading single bit constants from the constant pool into non-voliatle registers that had to be preseved on the stack). The do {} while avoids an unconditional branch to the end of the loop to test the entry / repeat condition of a while loop and instead optimises for the expected single iteration of the loop. We have a full mb() at the beginning to cover ordering between send, ipi, and receive so we can use xchg_local and forgo the further acquire and release barriers of xchg. Signed-off-by: Milton Miller Signed-off-by: Benjamin Herrenschmidt diff --git a/arch/powerpc/kernel/smp.c b/arch/powerpc/kernel/smp.c index d76f7d7..a8909aa 100644 --- a/arch/powerpc/kernel/smp.c +++ b/arch/powerpc/kernel/smp.c @@ -180,7 +180,7 @@ int smp_request_message_ipi(int virq, int msg) #ifdef CONFIG_PPC_SMP_MUXED_IPI struct cpu_messages { - unsigned long messages; /* current messages bits */ + int messages; /* current messages */ unsigned long data; /* data for cause ipi */ }; static DEFINE_PER_CPU_SHARED_ALIGNED(struct cpu_messages, ipi_message); @@ -195,9 +195,9 @@ void smp_muxed_ipi_set_data(int cpu, unsigned long data) void smp_muxed_ipi_message_pass(int cpu, int msg) { struct cpu_messages *info = &per_cpu(ipi_message, cpu); - unsigned long *tgt = &info->messages; + char *message = (char *)&info->messages; - set_bit(msg, tgt); + message[msg] = 1; mb(); smp_ops->cause_ipi(cpu, info->data); } @@ -205,30 +205,35 @@ void smp_muxed_ipi_message_pass(int cpu, int msg) void smp_muxed_ipi_resend(void) { struct cpu_messages *info = &__get_cpu_var(ipi_message); - unsigned long *tgt = &info->messages; - if (*tgt) + if (info->messages) smp_ops->cause_ipi(smp_processor_id(), info->data); } irqreturn_t smp_ipi_demux(void) { struct cpu_messages *info = &__get_cpu_var(ipi_message); - unsigned long *tgt = &info->messages; + unsigned int all; mb(); /* order any irq clear */ - while (*tgt) { - if (test_and_clear_bit(PPC_MSG_CALL_FUNCTION, tgt)) + + do { + all = xchg_local(&info->messages, 0); + +#ifdef __BIG_ENDIAN + if (all & (1 << (24 - 8 * PPC_MSG_CALL_FUNCTION))) generic_smp_call_function_interrupt(); - if (test_and_clear_bit(PPC_MSG_RESCHEDULE, tgt)) + if (all & (1 << (24 - 8 * PPC_MSG_RESCHEDULE))) reschedule_action(0, NULL); /* upcoming sched hook */ - if (test_and_clear_bit(PPC_MSG_CALL_FUNC_SINGLE, tgt)) + if (all & (1 << (24 - 8 * PPC_MSG_CALL_FUNC_SINGLE))) generic_smp_call_function_single_interrupt(); -#if defined(CONFIG_DEBUGGER) || defined(CONFIG_KEXEC) - if (test_and_clear_bit(PPC_MSG_DEBUGGER_BREAK, tgt)) + if (all & (1 << (24 - 8 * PPC_MSG_DEBUGGER_BREAK))) debug_ipi_action(0, NULL); +#else +#error Unsupported ENDIAN #endif - } + } while (info->messages); + return IRQ_HANDLED; } #endif /* CONFIG_PPC_SMP_MUXED_IPI */ -- cgit v0.10.2 From e085255ebce87c0b85d4752638d8a7d4f35f5b64 Mon Sep 17 00:00:00 2001 From: Milton Miller Date: Tue, 10 May 2011 19:29:49 +0000 Subject: powerpc/xics: Cleanup xics_host_map and ipi Since we already have a special case in map to set the ipi handler, use the desired flow. If we don't find an ics to handle the interrupt complain instead of returning 0 without having set a chip or handler. Signed-off-by: Milton Miller Signed-off-by: Benjamin Herrenschmidt diff --git a/arch/powerpc/sysdev/xics/xics-common.c b/arch/powerpc/sysdev/xics/xics-common.c index a31a710..43b2a79 100644 --- a/arch/powerpc/sysdev/xics/xics-common.c +++ b/arch/powerpc/sysdev/xics/xics-common.c @@ -135,9 +135,8 @@ static void xics_request_ipi(void) /* * IPIs are marked IRQF_DISABLED as they must run with irqs - * disabled + * disabled, and PERCPU. The handler was set in map. */ - irq_set_handler(ipi, handle_percpu_irq); BUG_ON(request_irq(ipi, icp_ops->ipi_action, IRQF_DISABLED|IRQF_PERCPU, "IPI", NULL)); } @@ -341,15 +340,16 @@ static int xics_host_map(struct irq_host *h, unsigned int virq, /* Don't call into ICS for IPIs */ if (hw == XICS_IPI) { irq_set_chip_and_handler(virq, &xics_ipi_chip, - handle_fasteoi_irq); + handle_percpu_irq); return 0; } /* Let the ICS setup the chip data */ list_for_each_entry(ics, &ics_list, link) if (ics->map(ics, virq) == 0) - break; - return 0; + return 0; + + return -EINVAL; } static int xics_host_xlate(struct irq_host *h, struct device_node *ct, -- cgit v0.10.2 From 3af259d1555a93b3b6f6545af13e0eb99b0d5d32 Mon Sep 17 00:00:00 2001 From: Milton Miller Date: Tue, 10 May 2011 19:29:53 +0000 Subject: powerpc: Radix trees are available before init_IRQ Since the generic irq code uses a radix tree for sparse interrupts, the initcall ordering has been changed to initialize radix trees before irqs. We no longer need to defer creating revmap radix trees to the arch_initcall irq_late_init. Also, the kmem caches are allocated so we don't need to use zalloc_maybe_bootmem. Signed-off-by: Milton Miller Reviewed-by: Grant Likely Signed-off-by: Benjamin Herrenschmidt diff --git a/arch/powerpc/kernel/irq.c b/arch/powerpc/kernel/irq.c index 826552c..f42e869 100644 --- a/arch/powerpc/kernel/irq.c +++ b/arch/powerpc/kernel/irq.c @@ -493,7 +493,6 @@ struct irq_map_entry { static LIST_HEAD(irq_hosts); static DEFINE_RAW_SPINLOCK(irq_big_lock); -static unsigned int revmap_trees_allocated; static DEFINE_MUTEX(revmap_trees_mutex); static struct irq_map_entry irq_map[NR_IRQS]; static unsigned int irq_virq_count = NR_IRQS; @@ -537,7 +536,7 @@ struct irq_host *irq_alloc_host(struct device_node *of_node, /* Allocate structure and revmap table if using linear mapping */ if (revmap_type == IRQ_HOST_MAP_LINEAR) size += revmap_arg * sizeof(unsigned int); - host = zalloc_maybe_bootmem(size, GFP_KERNEL); + host = kzalloc(size, GFP_KERNEL); if (host == NULL) return NULL; @@ -605,6 +604,9 @@ struct irq_host *irq_alloc_host(struct device_node *of_node, smp_wmb(); host->revmap_data.linear.revmap = rmap; break; + case IRQ_HOST_MAP_TREE: + INIT_RADIX_TREE(&host->revmap_data.tree, GFP_KERNEL); + break; default: break; } @@ -839,13 +841,6 @@ void irq_dispose_mapping(unsigned int virq) host->revmap_data.linear.revmap[hwirq] = NO_IRQ; break; case IRQ_HOST_MAP_TREE: - /* - * Check if radix tree allocated yet, if not then nothing to - * remove. - */ - smp_rmb(); - if (revmap_trees_allocated < 1) - break; mutex_lock(&revmap_trees_mutex); radix_tree_delete(&host->revmap_data.tree, hwirq); mutex_unlock(&revmap_trees_mutex); @@ -906,14 +901,6 @@ unsigned int irq_radix_revmap_lookup(struct irq_host *host, WARN_ON(host->revmap_type != IRQ_HOST_MAP_TREE); /* - * Check if the radix tree exists and has bee initialized. - * If not, we fallback to slow mode - */ - if (revmap_trees_allocated < 2) - return irq_find_mapping(host, hwirq); - - /* Now try to resolve */ - /* * No rcu_read_lock(ing) needed, the ptr returned can't go under us * as it's referencing an entry in the static irq_map table. */ @@ -935,18 +922,8 @@ unsigned int irq_radix_revmap_lookup(struct irq_host *host, void irq_radix_revmap_insert(struct irq_host *host, unsigned int virq, irq_hw_number_t hwirq) { - WARN_ON(host->revmap_type != IRQ_HOST_MAP_TREE); - /* - * Check if the radix tree exists yet. - * If not, then the irq will be inserted into the tree when it gets - * initialized. - */ - smp_rmb(); - if (revmap_trees_allocated < 1) - return; - if (virq != NO_IRQ) { mutex_lock(&revmap_trees_mutex); radix_tree_insert(&host->revmap_data.tree, hwirq, @@ -1054,53 +1031,6 @@ int arch_early_irq_init(void) return 0; } -/* We need to create the radix trees late */ -static int irq_late_init(void) -{ - struct irq_host *h; - unsigned int i; - - /* - * No mutual exclusion with respect to accessors of the tree is needed - * here as the synchronization is done via the state variable - * revmap_trees_allocated. - */ - list_for_each_entry(h, &irq_hosts, link) { - if (h->revmap_type == IRQ_HOST_MAP_TREE) - INIT_RADIX_TREE(&h->revmap_data.tree, GFP_KERNEL); - } - - /* - * Make sure the radix trees inits are visible before setting - * the flag - */ - smp_wmb(); - revmap_trees_allocated = 1; - - /* - * Insert the reverse mapping for those interrupts already present - * in irq_map[]. - */ - mutex_lock(&revmap_trees_mutex); - for (i = 0; i < irq_virq_count; i++) { - if (irq_map[i].host && - (irq_map[i].host->revmap_type == IRQ_HOST_MAP_TREE)) - radix_tree_insert(&irq_map[i].host->revmap_data.tree, - irq_map[i].hwirq, &irq_map[i]); - } - mutex_unlock(&revmap_trees_mutex); - - /* - * Make sure the radix trees insertions are visible before setting - * the flag - */ - smp_wmb(); - revmap_trees_allocated = 2; - - return 0; -} -arch_initcall(irq_late_init); - #ifdef CONFIG_VIRQ_DEBUG static int virq_debug_show(struct seq_file *m, void *private) { -- cgit v0.10.2 From 2d441681a4df7822e6ef6fcc0320bb14d2a06dbb Mon Sep 17 00:00:00 2001 From: Milton Miller Date: Tue, 10 May 2011 19:29:57 +0000 Subject: powerpc: Return early if irq_host lookup type is wrong If for some reason the code incrorectly calls the wrong function to manage the revmap, not only should we warn, we should take action. However, in the paths we expect to be taken every delivered interrupt change to WARN_ON_ONCE. Use the if (WARN_ON(x)) format to get the unlikely for free. Signed-off-by: Milton Miller Reviewed-by: Grant Likely Signed-off-by: Benjamin Herrenschmidt diff --git a/arch/powerpc/kernel/irq.c b/arch/powerpc/kernel/irq.c index f42e869..4a5aa8c 100644 --- a/arch/powerpc/kernel/irq.c +++ b/arch/powerpc/kernel/irq.c @@ -814,8 +814,7 @@ void irq_dispose_mapping(unsigned int virq) return; host = irq_map[virq].host; - WARN_ON (host == NULL); - if (host == NULL) + if (WARN_ON(host == NULL)) return; /* Never unmap legacy interrupts */ @@ -898,7 +897,8 @@ unsigned int irq_radix_revmap_lookup(struct irq_host *host, struct irq_map_entry *ptr; unsigned int virq; - WARN_ON(host->revmap_type != IRQ_HOST_MAP_TREE); + if (WARN_ON_ONCE(host->revmap_type != IRQ_HOST_MAP_TREE)) + return irq_find_mapping(host, hwirq); /* * No rcu_read_lock(ing) needed, the ptr returned can't go under us @@ -922,7 +922,8 @@ unsigned int irq_radix_revmap_lookup(struct irq_host *host, void irq_radix_revmap_insert(struct irq_host *host, unsigned int virq, irq_hw_number_t hwirq) { - WARN_ON(host->revmap_type != IRQ_HOST_MAP_TREE); + if (WARN_ON(host->revmap_type != IRQ_HOST_MAP_TREE)) + return; if (virq != NO_IRQ) { mutex_lock(&revmap_trees_mutex); @@ -937,7 +938,8 @@ unsigned int irq_linear_revmap(struct irq_host *host, { unsigned int *revmap; - WARN_ON(host->revmap_type != IRQ_HOST_MAP_LINEAR); + if (WARN_ON_ONCE(host->revmap_type != IRQ_HOST_MAP_LINEAR)) + return irq_find_mapping(host, hwirq); /* Check revmap bounds */ if (unlikely(hwirq >= host->revmap_data.linear.size)) -- cgit v0.10.2 From df74e70ac25fc4bf4036a2f9690b4e2e4520e65d Mon Sep 17 00:00:00 2001 From: Milton Miller Date: Tue, 10 May 2011 19:30:00 +0000 Subject: powerpc: Remove trival irq_host_ops.unmap These all just clear chip or chipdata fields, which will be done by the generic code when we call irq_free_descs. Signed-off-by: Milton Miller Signed-off-by: Benjamin Herrenschmidt diff --git a/arch/powerpc/platforms/82xx/pq2ads-pci-pic.c b/arch/powerpc/platforms/82xx/pq2ads-pci-pic.c index 5d6c34c..8ccf9ed 100644 --- a/arch/powerpc/platforms/82xx/pq2ads-pci-pic.c +++ b/arch/powerpc/platforms/82xx/pq2ads-pci-pic.c @@ -112,16 +112,8 @@ static int pci_pic_host_map(struct irq_host *h, unsigned int virq, return 0; } -static void pci_host_unmap(struct irq_host *h, unsigned int virq) -{ - /* remove chip and handler */ - irq_set_chip_data(virq, NULL); - irq_set_chip(virq, NULL); -} - static struct irq_host_ops pci_pic_host_ops = { .map = pci_pic_host_map, - .unmap = pci_host_unmap, }; int __init pq2ads_pci_init_irq(void) diff --git a/arch/powerpc/platforms/embedded6xx/flipper-pic.c b/arch/powerpc/platforms/embedded6xx/flipper-pic.c index 77cbe4c..f61a2dd 100644 --- a/arch/powerpc/platforms/embedded6xx/flipper-pic.c +++ b/arch/powerpc/platforms/embedded6xx/flipper-pic.c @@ -107,12 +107,6 @@ static int flipper_pic_map(struct irq_host *h, unsigned int virq, return 0; } -static void flipper_pic_unmap(struct irq_host *h, unsigned int irq) -{ - irq_set_chip_data(irq, NULL); - irq_set_chip(irq, NULL); -} - static int flipper_pic_match(struct irq_host *h, struct device_node *np) { return 1; @@ -121,7 +115,6 @@ static int flipper_pic_match(struct irq_host *h, struct device_node *np) static struct irq_host_ops flipper_irq_host_ops = { .map = flipper_pic_map, - .unmap = flipper_pic_unmap, .match = flipper_pic_match, }; diff --git a/arch/powerpc/platforms/embedded6xx/hlwd-pic.c b/arch/powerpc/platforms/embedded6xx/hlwd-pic.c index 44b398b..e491917 100644 --- a/arch/powerpc/platforms/embedded6xx/hlwd-pic.c +++ b/arch/powerpc/platforms/embedded6xx/hlwd-pic.c @@ -100,15 +100,8 @@ static int hlwd_pic_map(struct irq_host *h, unsigned int virq, return 0; } -static void hlwd_pic_unmap(struct irq_host *h, unsigned int irq) -{ - irq_set_chip_data(irq, NULL); - irq_set_chip(irq, NULL); -} - static struct irq_host_ops hlwd_irq_host_ops = { .map = hlwd_pic_map, - .unmap = hlwd_pic_unmap, }; static unsigned int __hlwd_pic_get_irq(struct irq_host *h) diff --git a/arch/powerpc/platforms/ps3/interrupt.c b/arch/powerpc/platforms/ps3/interrupt.c index 523bd0d..600ed2c 100644 --- a/arch/powerpc/platforms/ps3/interrupt.c +++ b/arch/powerpc/platforms/ps3/interrupt.c @@ -659,11 +659,6 @@ static void __maybe_unused _dump_mask(struct ps3_private *pd, static void dump_bmp(struct ps3_private* pd) {}; #endif /* defined(DEBUG) */ -static void ps3_host_unmap(struct irq_host *h, unsigned int virq) -{ - irq_set_chip_data(virq, NULL); -} - static int ps3_host_map(struct irq_host *h, unsigned int virq, irq_hw_number_t hwirq) { @@ -683,7 +678,6 @@ static int ps3_host_match(struct irq_host *h, struct device_node *np) static struct irq_host_ops ps3_host_ops = { .map = ps3_host_map, - .unmap = ps3_host_unmap, .match = ps3_host_match, }; -- cgit v0.10.2 From 7ee342bdc3d7e2cba4be6d1eece56efec9d3809f Mon Sep 17 00:00:00 2001 From: Milton Miller Date: Tue, 10 May 2011 19:30:04 +0000 Subject: powerpc: Remove i8259 irq_host_ops->unmap It was never called because the host is always IRQ_HOST_MAP_LEGACY. And what it purported to do was mask the interrupt (which will already have happend if we shutdown the interrupt), then synchronise_irq and clear the chip pointer, both of which will have been be done by the caller were we to call unmap on a legacy irq. Signed-off-by: Milton Miller Signed-off-by: Benjamin Herrenschmidt diff --git a/arch/powerpc/sysdev/i8259.c b/arch/powerpc/sysdev/i8259.c index 142770c..d18bb27 100644 --- a/arch/powerpc/sysdev/i8259.c +++ b/arch/powerpc/sysdev/i8259.c @@ -185,18 +185,6 @@ static int i8259_host_map(struct irq_host *h, unsigned int virq, return 0; } -static void i8259_host_unmap(struct irq_host *h, unsigned int virq) -{ - /* Make sure irq is masked in hardware */ - i8259_mask_irq(irq_get_irq_data(virq)); - - /* remove chip and handler */ - irq_set_chip_and_handler(virq, NULL, NULL); - - /* Make sure it's completed */ - synchronize_irq(virq); -} - static int i8259_host_xlate(struct irq_host *h, struct device_node *ct, const u32 *intspec, unsigned int intsize, irq_hw_number_t *out_hwirq, unsigned int *out_flags) @@ -220,7 +208,6 @@ static int i8259_host_xlate(struct irq_host *h, struct device_node *ct, static struct irq_host_ops i8259_host_ops = { .match = i8259_host_match, .map = i8259_host_map, - .unmap = i8259_host_unmap, .xlate = i8259_host_xlate, }; -- cgit v0.10.2 From 6c4c82e20a1b476589c1e2b0b7c2adc783c93006 Mon Sep 17 00:00:00 2001 From: Milton Miller Date: Tue, 10 May 2011 19:30:07 +0000 Subject: powerpc/fsl_msi: Don't abuse platform_data for driver_data The msi platform device driver was abusing dev.platform_data for its platform_driver_data. Use the correct pointer for storage. Platform_data is supposed to be for platforms to communicate to drivers parameters that are not otherwise discoverable. Its lifetime matches the platform_device not the platform device driver. It is generally not needed for drivers that only support systems with device trees. Signed-off-by: Milton Miller Acked-by: Grant Likely Signed-off-by: Benjamin Herrenschmidt diff --git a/arch/powerpc/sysdev/fsl_msi.c b/arch/powerpc/sysdev/fsl_msi.c index d5679dc..077776c 100644 --- a/arch/powerpc/sysdev/fsl_msi.c +++ b/arch/powerpc/sysdev/fsl_msi.c @@ -253,7 +253,7 @@ unlock: static int fsl_of_msi_remove(struct platform_device *ofdev) { - struct fsl_msi *msi = ofdev->dev.platform_data; + struct fsl_msi *msi = platform_get_drvdata(ofdev); int virq, i; struct fsl_msi_cascade_data *cascade_data; @@ -327,7 +327,7 @@ static int __devinit fsl_of_msi_probe(struct platform_device *dev) dev_err(&dev->dev, "No memory for MSI structure\n"); return -ENOMEM; } - dev->dev.platform_data = msi; + platform_set_drvdata(dev, msi); msi->irqhost = irq_alloc_host(dev->dev.of_node, IRQ_HOST_MAP_LINEAR, NR_MSI_IRQS, &fsl_msi_host_ops, 0); -- cgit v0.10.2 From d1921bcdeee66c3d1704ef753dc74464856e4b7f Mon Sep 17 00:00:00 2001 From: Milton Miller Date: Tue, 10 May 2011 19:30:11 +0000 Subject: powerpc/fsl_msi: Use chip_data not handler_data handler_data should be reserved for flow handlers on the dependent irq, not consumed by the parent irq code that is part of the irq_chip code. The msi_data pointer was already set in msidesc->irqhost->hostdata and being copied to irq_data->chipdata in the msidesc->irqhost->map() method called via create_irq_mapping, so we can obtain the pointer from there and free the instance it in teardown_msi_irqs. Also remove the unnecessary cast of irq_get_handler_data in the cascade handler, which is the demux flow handler of the parent msi interrupt. (This is the expected usage for handler_data). Signed-off-by: Milton Miller Signed-off-by: Benjamin Herrenschmidt diff --git a/arch/powerpc/sysdev/fsl_msi.c b/arch/powerpc/sysdev/fsl_msi.c index 077776c..067cc88 100644 --- a/arch/powerpc/sysdev/fsl_msi.c +++ b/arch/powerpc/sysdev/fsl_msi.c @@ -110,7 +110,7 @@ static void fsl_teardown_msi_irqs(struct pci_dev *pdev) list_for_each_entry(entry, &pdev->msi_list, list) { if (entry->irq == NO_IRQ) continue; - msi_data = irq_get_handler_data(entry->irq); + msi_data = irq_get_chip_data(entry->irq); irq_set_msi_desc(entry->irq, NULL); msi_bitmap_free_hwirqs(&msi_data->bitmap, virq_to_hw(entry->irq), 1); @@ -168,7 +168,7 @@ static int fsl_setup_msi_irqs(struct pci_dev *pdev, int nvec, int type) rc = -ENOSPC; goto out_free; } - irq_set_handler_data(virq, msi_data); + /* chip_data is msi_data via host->hostdata in host->map() */ irq_set_msi_desc(virq, entry); fsl_compose_msi_msg(pdev, hwirq, &msg, msi_data); @@ -193,7 +193,7 @@ static void fsl_msi_cascade(unsigned int irq, struct irq_desc *desc) u32 have_shift = 0; struct fsl_msi_cascade_data *cascade_data; - cascade_data = (struct fsl_msi_cascade_data *)irq_get_handler_data(irq); + cascade_data = irq_get_handler_data(irq); msi_data = cascade_data->msi_data; raw_spin_lock(&desc->lock); -- cgit v0.10.2 From c42385cd4533b5ba9b9dd0034285cfcfd7982708 Mon Sep 17 00:00:00 2001 From: Milton Miller Date: Tue, 10 May 2011 19:30:15 +0000 Subject: powerpc/mpc5121_ads_cpld: Remove use of NO_IRQ_IGNORE As NO_IRQ_IGNORE is only used between the static function cpld_pic_get_irq and its caller cpld_pic_cascade, and cpld_pic_cascade only uses it to suppress calling handle_generic_irq, we can change these uses to NO_IRQ and remove the extra tests and pathlength in cpld_pic_cascade. Signed-off-by: Milton Miller Acked-by: Grant Likely Signed-off-by: Benjamin Herrenschmidt diff --git a/arch/powerpc/platforms/512x/mpc5121_ads_cpld.c b/arch/powerpc/platforms/512x/mpc5121_ads_cpld.c index a8bc0d4..9f09319 100644 --- a/arch/powerpc/platforms/512x/mpc5121_ads_cpld.c +++ b/arch/powerpc/platforms/512x/mpc5121_ads_cpld.c @@ -97,7 +97,7 @@ cpld_pic_get_irq(int offset, u8 ignore, u8 __iomem *statusp, status |= (ignore | mask); if (status == 0xff) - return NO_IRQ_IGNORE; + return NO_IRQ; cpld_irq = ffz(status) + offset; @@ -109,14 +109,14 @@ cpld_pic_cascade(unsigned int irq, struct irq_desc *desc) { irq = cpld_pic_get_irq(0, PCI_IGNORE, &cpld_regs->pci_status, &cpld_regs->pci_mask); - if (irq != NO_IRQ && irq != NO_IRQ_IGNORE) { + if (irq != NO_IRQ) { generic_handle_irq(irq); return; } irq = cpld_pic_get_irq(8, MISC_IGNORE, &cpld_regs->misc_status, &cpld_regs->misc_mask); - if (irq != NO_IRQ && irq != NO_IRQ_IGNORE) { + if (irq != NO_IRQ) { generic_handle_irq(irq); return; } -- cgit v0.10.2 From 67347eba156d64150be73c9f5797342a66b123d9 Mon Sep 17 00:00:00 2001 From: Milton Miller Date: Tue, 10 May 2011 19:30:18 +0000 Subject: powerpc/mpc62xx_pic: Fix get_irq handling of NO_IRQ If none of irq category bits were set mpc52xx_get_irq() would pass NO_IRQ_IGNORE (-1) to irq_linear_revmap, which does an unsigned compare and declares the interrupt above the linear map range. It then punts to irq_find_mapping, which performs a linear search of all irqs, which will likely miss and only then return NO_IRQ. If no status bit is set, then we should return NO_IRQ directly. The interrupt should not be suppressed from spurious counting, in fact that is the definition of supurious. Signed-off-by: Milton Miller Acked-by: Grant Likely Signed-off-by: Benjamin Herrenschmidt diff --git a/arch/powerpc/platforms/52xx/mpc52xx_pic.c b/arch/powerpc/platforms/52xx/mpc52xx_pic.c index bb61181..1a9a495 100644 --- a/arch/powerpc/platforms/52xx/mpc52xx_pic.c +++ b/arch/powerpc/platforms/52xx/mpc52xx_pic.c @@ -486,7 +486,7 @@ void __init mpc52xx_init_irq(void) unsigned int mpc52xx_get_irq(void) { u32 status; - int irq = NO_IRQ_IGNORE; + int irq; status = in_be32(&intr->enc_status); if (status & 0x00000400) { /* critical */ @@ -509,6 +509,8 @@ unsigned int mpc52xx_get_irq(void) } else { irq |= (MPC52xx_IRQ_L1_PERP << MPC52xx_IRQ_L1_OFFSET); } + } else { + return NO_IRQ; } return irq_linear_revmap(mpc52xx_irqhost, irq); -- cgit v0.10.2 From 23f73a5fb0dee5ab681bfeb8897bcfc57153ba9a Mon Sep 17 00:00:00 2001 From: Milton Miller Date: Tue, 10 May 2011 19:30:22 +0000 Subject: powerpc/psurge: Create a irq_host for secondary cpus Create a dummy irq_host using the generic dummy irq chip for the secondary cpus to use. Create a direct irq mapping for the ipi and register the ipi action handler against it. If for some unlikely reason part of this fails then don't detect the secondary cpus. This removes another instance of NO_IRQ_IGNORE, records the ipi stats for the secondary cpus, and runs the ipi on the interrupt stack. Signed-off-by: Milton Miller Signed-off-by: Benjamin Herrenschmidt diff --git a/arch/powerpc/platforms/powermac/pic.c b/arch/powerpc/platforms/powermac/pic.c index b706cb3..360260d 100644 --- a/arch/powerpc/platforms/powermac/pic.c +++ b/arch/powerpc/platforms/powermac/pic.c @@ -240,12 +240,9 @@ static unsigned int pmac_pic_get_irq(void) unsigned long flags; #ifdef CONFIG_PPC_PMAC32_PSURGE - void psurge_smp_message_recv(void); - - /* IPI's are a hack on the powersurge -- Cort */ - if ( smp_processor_id() != 0 ) { - psurge_smp_message_recv(); - return NO_IRQ_IGNORE; /* ignore, already handled */ + /* IPI's are a hack on the powersurge -- Cort */ + if (smp_processor_id() != 0) { + return psurge_secondary_virq; } #endif /* CONFIG_PPC_PMAC32_PSURGE */ raw_spin_lock_irqsave(&pmac_pic_lock, flags); diff --git a/arch/powerpc/platforms/powermac/pmac.h b/arch/powerpc/platforms/powermac/pmac.h index 20468f4..8327cce 100644 --- a/arch/powerpc/platforms/powermac/pmac.h +++ b/arch/powerpc/platforms/powermac/pmac.h @@ -33,6 +33,7 @@ extern void pmac_setup_pci_dma(void); extern void pmac_check_ht_link(void); extern void pmac_setup_smp(void); +extern int psurge_secondary_virq; extern void low_cpu_die(void) __attribute__((noreturn)); extern int pmac_nvram_init(void); diff --git a/arch/powerpc/platforms/powermac/smp.c b/arch/powerpc/platforms/powermac/smp.c index 67b6e14..db092d7 100644 --- a/arch/powerpc/platforms/powermac/smp.c +++ b/arch/powerpc/platforms/powermac/smp.c @@ -124,6 +124,10 @@ static volatile u32 __iomem *psurge_start; /* what sort of powersurge board we have */ static int psurge_type = PSURGE_NONE; +/* irq for secondary cpus to report */ +static struct irq_host *psurge_host; +int psurge_secondary_virq; + /* * Set and clear IPIs for powersurge. */ @@ -159,15 +163,11 @@ static inline void psurge_clr_ipi(int cpu) * use the generic demux helpers * -- paulus. */ -void psurge_smp_message_recv(void) +static irqreturn_t psurge_ipi_intr(int irq, void *d) { psurge_clr_ipi(smp_processor_id()); smp_ipi_demux(); -} -irqreturn_t psurge_primary_intr(int irq, void *d) -{ - psurge_smp_message_recv(); return IRQ_HANDLED; } @@ -176,6 +176,38 @@ static void smp_psurge_cause_ipi(int cpu, unsigned long data) psurge_set_ipi(cpu); } +static int psurge_host_map(struct irq_host *h, unsigned int virq, + irq_hw_number_t hw) +{ + irq_set_chip_and_handler(virq, &dummy_irq_chip, handle_percpu_irq); + + return 0; +} + +struct irq_host_ops psurge_host_ops = { + .map = psurge_host_map, +}; + +static int psurge_secondary_ipi_init(void) +{ + int rc = -ENOMEM; + + psurge_host = irq_alloc_host(NULL, IRQ_HOST_MAP_NOMAP, 0, + &psurge_host_ops, 0); + + if (psurge_host) + psurge_secondary_virq = irq_create_direct_mapping(psurge_host); + + if (psurge_secondary_virq) + rc = request_irq(psurge_secondary_virq, psurge_ipi_intr, + IRQF_DISABLED|IRQF_PERCPU, "IPI", NULL); + + if (rc) + pr_err("Failed to setup secondary cpu IPI\n"); + + return rc; +} + /* * Determine a quad card presence. We read the board ID register, we * force the data bus to change to something else, and we read it again. @@ -284,6 +316,9 @@ static int __init smp_psurge_probe(void) ncpus = 2; } + if (psurge_secondary_ipi_init()) + return 1; + psurge_start = ioremap(PSURGE_START, 4); psurge_pri_intr = ioremap(PSURGE_PRI_INTR, 4); @@ -372,8 +407,8 @@ static int __init smp_psurge_kick_cpu(int nr) } static struct irqaction psurge_irqaction = { - .handler = psurge_primary_intr, - .flags = IRQF_DISABLED, + .handler = psurge_ipi_intr, + .flags = IRQF_DISABLED|IRQF_PERCPU, .name = "primary IPI", }; -- cgit v0.10.2 From da0519800260a3c791b4fe3317a0c7560027a372 Mon Sep 17 00:00:00 2001 From: Milton Miller Date: Tue, 10 May 2011 19:30:26 +0000 Subject: powerpc: Remove irq_host_ops->remap hook It was called from irq_create_mapping if that was called for a host and hwirq that was previously mapped, "to update the flags". But the only implementation was in beat_interrupt and all it did was repeat a hypervisor call without error checking that was performed with error checking at the beginning of the map hook. In addition, the comment on the beat remap hook says it will only called once for a given mapping, which would apply to map not remap. All flags should be known by the time the match hook is called, before we call the map hook. Removing this mostly unused hook will simpify the requirements of irq_domain concept. Signed-off-by: Milton Miller Signed-off-by: Benjamin Herrenschmidt diff --git a/arch/powerpc/include/asm/irq.h b/arch/powerpc/include/asm/irq.h index e1983d5..6f4a3ef 100644 --- a/arch/powerpc/include/asm/irq.h +++ b/arch/powerpc/include/asm/irq.h @@ -88,9 +88,6 @@ struct irq_host_ops { /* Dispose of such a mapping */ void (*unmap)(struct irq_host *h, unsigned int virq); - /* Update of such a mapping */ - void (*remap)(struct irq_host *h, unsigned int virq, irq_hw_number_t hw); - /* Translate device-tree interrupt specifier from raw format coming * from the firmware to a irq_hw_number_t (interrupt line number) and * type (sense) that can be passed to set_irq_type(). In the absence diff --git a/arch/powerpc/kernel/irq.c b/arch/powerpc/kernel/irq.c index 4a5aa8c..0715a09 100644 --- a/arch/powerpc/kernel/irq.c +++ b/arch/powerpc/kernel/irq.c @@ -732,8 +732,6 @@ unsigned int irq_create_mapping(struct irq_host *host, */ virq = irq_find_mapping(host, hwirq); if (virq != NO_IRQ) { - if (host->ops->remap) - host->ops->remap(host, virq, hwirq); pr_debug("irq: -> existing mapping on virq %d\n", virq); return virq; } diff --git a/arch/powerpc/platforms/cell/beat_interrupt.c b/arch/powerpc/platforms/cell/beat_interrupt.c index d46f7e4..55015e1 100644 --- a/arch/powerpc/platforms/cell/beat_interrupt.c +++ b/arch/powerpc/platforms/cell/beat_interrupt.c @@ -148,16 +148,6 @@ static int beatic_pic_host_map(struct irq_host *h, unsigned int virq, } /* - * Update binding hardware IRQ number (hw) and Virtuql - * IRQ number (virq). This is called only once for a given mapping. - */ -static void beatic_pic_host_remap(struct irq_host *h, unsigned int virq, - irq_hw_number_t hw) -{ - beat_construct_and_connect_irq_plug(virq, hw); -} - -/* * Translate device-tree interrupt spec to irq_hw_number_t style (ulong), * to pass away to irq_create_mapping(). * @@ -184,7 +174,6 @@ static int beatic_pic_host_match(struct irq_host *h, struct device_node *np) static struct irq_host_ops beatic_pic_host_ops = { .map = beatic_pic_host_map, - .remap = beatic_pic_host_remap, .unmap = beatic_pic_host_unmap, .xlate = beatic_pic_host_xlate, .match = beatic_pic_host_match, -- cgit v0.10.2 From 6b0aea44d6b36b52010d206be69ce37c2f4f1bd1 Mon Sep 17 00:00:00 2001 From: Milton Miller Date: Tue, 10 May 2011 19:30:29 +0000 Subject: powerpc/spider-pic: Get pic from chip_data instead of irq_map Building on Grant's efforts to remove the irq_map array, this patch moves spider-pics use of virq_to_host() to use irq_data_get_chip_data and sets the irq chip data in the map call, like most other interrupt controllers in powerpc. Signed-off-by: Milton Miller Signed-off-by: Benjamin Herrenschmidt diff --git a/arch/powerpc/platforms/cell/spider-pic.c b/arch/powerpc/platforms/cell/spider-pic.c index 34d2b99..442c28c 100644 --- a/arch/powerpc/platforms/cell/spider-pic.c +++ b/arch/powerpc/platforms/cell/spider-pic.c @@ -68,9 +68,9 @@ struct spider_pic { }; static struct spider_pic spider_pics[SPIDER_CHIP_COUNT]; -static struct spider_pic *spider_virq_to_pic(unsigned int virq) +static struct spider_pic *spider_irq_data_to_pic(struct irq_data *d) { - return virq_to_host(virq)->host_data; + return irq_data_get_irq_chip_data(d); } static void __iomem *spider_get_irq_config(struct spider_pic *pic, @@ -81,7 +81,7 @@ static void __iomem *spider_get_irq_config(struct spider_pic *pic, static void spider_unmask_irq(struct irq_data *d) { - struct spider_pic *pic = spider_virq_to_pic(d->irq); + struct spider_pic *pic = spider_irq_data_to_pic(d); void __iomem *cfg = spider_get_irq_config(pic, irqd_to_hwirq(d)); out_be32(cfg, in_be32(cfg) | 0x30000000u); @@ -89,7 +89,7 @@ static void spider_unmask_irq(struct irq_data *d) static void spider_mask_irq(struct irq_data *d) { - struct spider_pic *pic = spider_virq_to_pic(d->irq); + struct spider_pic *pic = spider_irq_data_to_pic(d); void __iomem *cfg = spider_get_irq_config(pic, irqd_to_hwirq(d)); out_be32(cfg, in_be32(cfg) & ~0x30000000u); @@ -97,7 +97,7 @@ static void spider_mask_irq(struct irq_data *d) static void spider_ack_irq(struct irq_data *d) { - struct spider_pic *pic = spider_virq_to_pic(d->irq); + struct spider_pic *pic = spider_irq_data_to_pic(d); unsigned int src = irqd_to_hwirq(d); /* Reset edge detection logic if necessary @@ -116,7 +116,7 @@ static void spider_ack_irq(struct irq_data *d) static int spider_set_irq_type(struct irq_data *d, unsigned int type) { unsigned int sense = type & IRQ_TYPE_SENSE_MASK; - struct spider_pic *pic = spider_virq_to_pic(d->irq); + struct spider_pic *pic = spider_irq_data_to_pic(d); unsigned int hw = irqd_to_hwirq(d); void __iomem *cfg = spider_get_irq_config(pic, hw); u32 old_mask; @@ -171,6 +171,7 @@ static struct irq_chip spider_pic = { static int spider_host_map(struct irq_host *h, unsigned int virq, irq_hw_number_t hw) { + irq_set_chip_data(virq, h->host_data); irq_set_chip_and_handler(virq, &spider_pic, handle_level_irq); /* Set default irq type */ -- cgit v0.10.2 From 9553361499f9f9e8ca8c9dae2e103f651fa48217 Mon Sep 17 00:00:00 2001 From: Milton Miller Date: Tue, 10 May 2011 19:30:33 +0000 Subject: powerpc/axon_msi: Validate msi irq via chip_data Instead of checking for rogue msi numbers via the irq_map host field set the chip_data to h.host_data (which is the msic struct pointer) at map and compare it in get_irq. Signed-off-by: Milton Miller Signed-off-by: Benjamin Herrenschmidt diff --git a/arch/powerpc/platforms/cell/axon_msi.c b/arch/powerpc/platforms/cell/axon_msi.c index 1e3329e..ac06903 100644 --- a/arch/powerpc/platforms/cell/axon_msi.c +++ b/arch/powerpc/platforms/cell/axon_msi.c @@ -113,7 +113,7 @@ static void axon_msi_cascade(unsigned int irq, struct irq_desc *desc) pr_devel("axon_msi: woff %x roff %x msi %x\n", write_offset, msic->read_offset, msi); - if (msi < NR_IRQS && virq_to_host(msi) == msic->irq_host) { + if (msi < NR_IRQS && irq_get_chip_data(msi) == msic) { generic_handle_irq(msi); msic->fifo_virt[idx] = cpu_to_le32(0xffffffff); } else { @@ -320,6 +320,7 @@ static struct irq_chip msic_irq_chip = { static int msic_host_map(struct irq_host *h, unsigned int virq, irq_hw_number_t hw) { + irq_set_chip_data(virq, h->host_data); irq_set_chip_and_handler(virq, &msic_irq_chip, handle_simple_irq); return 0; -- cgit v0.10.2 From 3ee62d365b519c0c18c774049efcde84fe51c60c Mon Sep 17 00:00:00 2001 From: Milton Miller Date: Tue, 10 May 2011 19:30:36 +0000 Subject: powerpc: Add virq_is_host to reduce virq_to_host usage Some irq_host implementations are using virq_to_host to check if they are the irq_host for a virtual irq. To allow us to make space versus time tradeoffs, replace this usage with an assertive virq_is_host that confirms or denies the irq is associated with the given irq_host. Signed-off-by: Milton Miller Acked-by: Grant Likely Signed-off-by: Benjamin Herrenschmidt diff --git a/arch/powerpc/include/asm/irq.h b/arch/powerpc/include/asm/irq.h index 6f4a3ef..a65d170 100644 --- a/arch/powerpc/include/asm/irq.h +++ b/arch/powerpc/include/asm/irq.h @@ -128,6 +128,7 @@ struct irq_host { struct irq_data; extern irq_hw_number_t irqd_to_hwirq(struct irq_data *d); extern irq_hw_number_t virq_to_hw(unsigned int virq); +extern bool virq_is_host(unsigned int virq, struct irq_host *host); extern struct irq_host *virq_to_host(unsigned int virq); /** diff --git a/arch/powerpc/kernel/irq.c b/arch/powerpc/kernel/irq.c index 0715a09..73cf290 100644 --- a/arch/powerpc/kernel/irq.c +++ b/arch/powerpc/kernel/irq.c @@ -510,6 +510,12 @@ irq_hw_number_t virq_to_hw(unsigned int virq) } EXPORT_SYMBOL_GPL(virq_to_hw); +bool virq_is_host(unsigned int virq, struct irq_host *host) +{ + return irq_map[virq].host == host; +} +EXPORT_SYMBOL_GPL(virq_is_host); + struct irq_host *virq_to_host(unsigned int virq) { return irq_map[virq].host; diff --git a/arch/powerpc/sysdev/xics/xics-common.c b/arch/powerpc/sysdev/xics/xics-common.c index 43b2a79..445c5a0 100644 --- a/arch/powerpc/sysdev/xics/xics-common.c +++ b/arch/powerpc/sysdev/xics/xics-common.c @@ -213,7 +213,7 @@ void xics_migrate_irqs_away(void) /* We can't set affinity on ISA interrupts */ if (virq < NUM_ISA_INTERRUPTS) continue; - if (virq_to_host(virq) != xics_host) + if (!virq_is_host(virq, xics_host)) continue; irq = (unsigned int)virq_to_hw(virq); /* We need to get IPIs still. */ -- cgit v0.10.2 From 1e8c23013ed0d535e531b3b9cc30200e884f3ff0 Mon Sep 17 00:00:00 2001 From: Milton Miller Date: Tue, 10 May 2011 19:30:40 +0000 Subject: powerpc: Remove virq_to_host The only references to the irq_map[].host field are internal to arch/powerpc/kernel/irq.c Signed-off-by: Milton Miller Acked-by: Grant Likely Signed-off-by: Benjamin Herrenschmidt diff --git a/arch/powerpc/include/asm/irq.h b/arch/powerpc/include/asm/irq.h index a65d170..1bff591 100644 --- a/arch/powerpc/include/asm/irq.h +++ b/arch/powerpc/include/asm/irq.h @@ -129,7 +129,6 @@ struct irq_data; extern irq_hw_number_t irqd_to_hwirq(struct irq_data *d); extern irq_hw_number_t virq_to_hw(unsigned int virq); extern bool virq_is_host(unsigned int virq, struct irq_host *host); -extern struct irq_host *virq_to_host(unsigned int virq); /** * irq_alloc_host - Allocate a new irq_host data structure diff --git a/arch/powerpc/kernel/irq.c b/arch/powerpc/kernel/irq.c index 73cf290..4368b5e 100644 --- a/arch/powerpc/kernel/irq.c +++ b/arch/powerpc/kernel/irq.c @@ -516,12 +516,6 @@ bool virq_is_host(unsigned int virq, struct irq_host *host) } EXPORT_SYMBOL_GPL(virq_is_host); -struct irq_host *virq_to_host(unsigned int virq) -{ - return irq_map[virq].host; -} -EXPORT_SYMBOL_GPL(virq_to_host); - static int default_irq_host_match(struct irq_host *h, struct device_node *np) { return h->of_node != NULL && h->of_node == np; -- cgit v0.10.2 From d36b4c4f3cc6caae6d4a12d9f995513e4c3acdd5 Mon Sep 17 00:00:00 2001 From: Kumar Gala Date: Wed, 6 Apr 2011 00:18:48 -0500 Subject: powerpc/fsl-booke64: Add support for Debug Level exception handler Signed-off-by: Kumar Gala diff --git a/arch/powerpc/include/asm/cputable.h b/arch/powerpc/include/asm/cputable.h index 4efbfb3..c0d842c 100644 --- a/arch/powerpc/include/asm/cputable.h +++ b/arch/powerpc/include/asm/cputable.h @@ -157,6 +157,7 @@ extern const char *powerpc_base_platform; #define CPU_FTR_476_DD2 ASM_CONST(0x0000000000010000) #define CPU_FTR_NEED_COHERENT ASM_CONST(0x0000000000020000) #define CPU_FTR_NO_BTIC ASM_CONST(0x0000000000040000) +#define CPU_FTR_DEBUG_LVL_EXC ASM_CONST(0x0000000000080000) #define CPU_FTR_NODSISRALIGN ASM_CONST(0x0000000000100000) #define CPU_FTR_PPC_LE ASM_CONST(0x0000000000200000) #define CPU_FTR_REAL_LE ASM_CONST(0x0000000000400000) @@ -385,7 +386,8 @@ extern const char *powerpc_base_platform; CPU_FTR_DBELL) #define CPU_FTRS_E5500 (CPU_FTR_USE_TB | CPU_FTR_NODSISRALIGN | \ CPU_FTR_L2CSR | CPU_FTR_LWSYNC | CPU_FTR_NOEXECUTE | \ - CPU_FTR_DBELL | CPU_FTR_POPCNTB | CPU_FTR_POPCNTD) + CPU_FTR_DBELL | CPU_FTR_POPCNTB | CPU_FTR_POPCNTD | \ + CPU_FTR_DEBUG_LVL_EXC) #define CPU_FTRS_GENERIC_32 (CPU_FTR_COMMON | CPU_FTR_NODSISRALIGN) /* 64-bit CPUs */ diff --git a/arch/powerpc/kernel/exceptions-64e.S b/arch/powerpc/kernel/exceptions-64e.S index 4d0abb4..cf27a8f 100644 --- a/arch/powerpc/kernel/exceptions-64e.S +++ b/arch/powerpc/kernel/exceptions-64e.S @@ -253,9 +253,6 @@ exception_marker: .balign 0x1000 .globl interrupt_base_book3e interrupt_base_book3e: /* fake trap */ - /* Note: If real debug exceptions are supported by the HW, the vector - * below will have to be patched up to point to an appropriate handler - */ EXCEPTION_STUB(0x000, machine_check) /* 0x0200 */ EXCEPTION_STUB(0x020, critical_input) /* 0x0580 */ EXCEPTION_STUB(0x040, debug_crit) /* 0x0d00 */ @@ -455,6 +452,68 @@ interrupt_end_book3e: kernel_dbg_exc: b . /* NYI */ +/* Debug exception as a debug interrupt*/ + START_EXCEPTION(debug_debug); + DBG_EXCEPTION_PROLOG(0xd00, PROLOG_ADDITION_2REGS) + + /* + * If there is a single step or branch-taken exception in an + * exception entry sequence, it was probably meant to apply to + * the code where the exception occurred (since exception entry + * doesn't turn off DE automatically). We simulate the effect + * of turning off DE on entry to an exception handler by turning + * off DE in the DSRR1 value and clearing the debug status. + */ + + mfspr r14,SPRN_DBSR /* check single-step/branch taken */ + andis. r15,r14,DBSR_IC@h + beq+ 1f + + LOAD_REG_IMMEDIATE(r14,interrupt_base_book3e) + LOAD_REG_IMMEDIATE(r15,interrupt_end_book3e) + cmpld cr0,r10,r14 + cmpld cr1,r10,r15 + blt+ cr0,1f + bge+ cr1,1f + + /* here it looks like we got an inappropriate debug exception. */ + lis r14,DBSR_IC@h /* clear the IC event */ + rlwinm r11,r11,0,~MSR_DE /* clear DE in the DSRR1 value */ + mtspr SPRN_DBSR,r14 + mtspr SPRN_DSRR1,r11 + lwz r10,PACA_EXDBG+EX_CR(r13) /* restore registers */ + ld r1,PACA_EXDBG+EX_R1(r13) + ld r14,PACA_EXDBG+EX_R14(r13) + ld r15,PACA_EXDBG+EX_R15(r13) + mtcr r10 + ld r10,PACA_EXDBG+EX_R10(r13) /* restore registers */ + ld r11,PACA_EXDBG+EX_R11(r13) + mfspr r13,SPRN_SPRG_DBG_SCRATCH + rfdi + + /* Normal debug exception */ + /* XXX We only handle coming from userspace for now since we can't + * quite save properly an interrupted kernel state yet + */ +1: andi. r14,r11,MSR_PR; /* check for userspace again */ + beq kernel_dbg_exc; /* if from kernel mode */ + + /* Now we mash up things to make it look like we are coming on a + * normal exception + */ + mfspr r15,SPRN_SPRG_DBG_SCRATCH + mtspr SPRN_SPRG_GEN_SCRATCH,r15 + mfspr r14,SPRN_DBSR + EXCEPTION_COMMON(0xd00, PACA_EXDBG, INTS_DISABLE_ALL) + std r14,_DSISR(r1) + addi r3,r1,STACK_FRAME_OVERHEAD + mr r4,r14 + ld r14,PACA_EXDBG+EX_R14(r13) + ld r15,PACA_EXDBG+EX_R15(r13) + bl .save_nvgprs + bl .DebugException + b .ret_from_except + /* Doorbell interrupt */ MASKABLE_EXCEPTION(0x2070, doorbell, .doorbell_exception, ACK_NONE) diff --git a/arch/powerpc/kernel/setup_64.c b/arch/powerpc/kernel/setup_64.c index c2ec0a1..a88bf27 100644 --- a/arch/powerpc/kernel/setup_64.c +++ b/arch/powerpc/kernel/setup_64.c @@ -62,6 +62,7 @@ #include #include #include +#include #include "setup.h" @@ -477,6 +478,9 @@ static void __init irqstack_early_init(void) #ifdef CONFIG_PPC_BOOK3E static void __init exc_lvl_early_init(void) { + extern unsigned int interrupt_base_book3e; + extern unsigned int exc_debug_debug_book3e; + unsigned int i; for_each_possible_cpu(i) { @@ -487,6 +491,10 @@ static void __init exc_lvl_early_init(void) mcheckirq_ctx[i] = (struct thread_info *) __va(memblock_alloc(THREAD_SIZE, THREAD_SIZE)); } + + if (cpu_has_feature(CPU_FTR_DEBUG_LVL_EXC)) + patch_branch(&interrupt_base_book3e + (0x040 / 4) + 1, + (unsigned long)&exc_debug_debug_book3e, 0); } #else #define exc_lvl_early_init() -- cgit v0.10.2 From 3a6e9bd7f60b29efc205485ceb11a768032c40d4 Mon Sep 17 00:00:00 2001 From: Scott Wood Date: Mon, 9 May 2011 16:26:00 -0500 Subject: powerpc/e5500: set non-base IVORs Without this, we attempt to use doorbells for IPIs, and end up branching to some bad address. Plus, even for the exceptions we don't implement, it's good to handle it and get a message out. Signed-off-by: Scott Wood Signed-off-by: Kumar Gala diff --git a/arch/powerpc/include/asm/reg_booke.h b/arch/powerpc/include/asm/reg_booke.h index 817bd1a..0f0ad9f 100644 --- a/arch/powerpc/include/asm/reg_booke.h +++ b/arch/powerpc/include/asm/reg_booke.h @@ -83,6 +83,10 @@ #define SPRN_IVOR13 0x19D /* Interrupt Vector Offset Register 13 */ #define SPRN_IVOR14 0x19E /* Interrupt Vector Offset Register 14 */ #define SPRN_IVOR15 0x19F /* Interrupt Vector Offset Register 15 */ +#define SPRN_IVOR38 0x1B0 /* Interrupt Vector Offset Register 38 */ +#define SPRN_IVOR39 0x1B1 /* Interrupt Vector Offset Register 39 */ +#define SPRN_IVOR40 0x1B2 /* Interrupt Vector Offset Register 40 */ +#define SPRN_IVOR41 0x1B3 /* Interrupt Vector Offset Register 41 */ #define SPRN_SPEFSCR 0x200 /* SPE & Embedded FP Status & Control */ #define SPRN_BBEAR 0x201 /* Branch Buffer Entry Address Register */ #define SPRN_BBTAR 0x202 /* Branch Buffer Target Address Register */ diff --git a/arch/powerpc/kernel/cpu_setup_fsl_booke.S b/arch/powerpc/kernel/cpu_setup_fsl_booke.S index 9136111..8053db0 100644 --- a/arch/powerpc/kernel/cpu_setup_fsl_booke.S +++ b/arch/powerpc/kernel/cpu_setup_fsl_booke.S @@ -88,6 +88,9 @@ _GLOBAL(__setup_cpu_e5500) bl __e500_dcache_setup #ifdef CONFIG_PPC_BOOK3E_64 bl .__setup_base_ivors + bl .setup_perfmon_ivor + bl .setup_doorbell_ivors + bl .setup_ehv_ivors #else bl __setup_e500mc_ivors #endif diff --git a/arch/powerpc/kernel/exceptions-64e.S b/arch/powerpc/kernel/exceptions-64e.S index cf27a8f..d24d440 100644 --- a/arch/powerpc/kernel/exceptions-64e.S +++ b/arch/powerpc/kernel/exceptions-64e.S @@ -269,8 +269,13 @@ interrupt_base_book3e: /* fake trap */ EXCEPTION_STUB(0x1a0, watchdog) /* 0x09f0 */ EXCEPTION_STUB(0x1c0, data_tlb_miss) EXCEPTION_STUB(0x1e0, instruction_tlb_miss) + EXCEPTION_STUB(0x260, perfmon) EXCEPTION_STUB(0x280, doorbell) EXCEPTION_STUB(0x2a0, doorbell_crit) + EXCEPTION_STUB(0x2c0, guest_doorbell) + EXCEPTION_STUB(0x2e0, guest_doorbell_crit) + EXCEPTION_STUB(0x300, hypercall) + EXCEPTION_STUB(0x320, ehpriv) .globl interrupt_end_book3e interrupt_end_book3e: @@ -514,6 +519,8 @@ kernel_dbg_exc: bl .DebugException b .ret_from_except + MASKABLE_EXCEPTION(0x260, perfmon, .performance_monitor_exception, ACK_NONE) + /* Doorbell interrupt */ MASKABLE_EXCEPTION(0x2070, doorbell, .doorbell_exception, ACK_NONE) @@ -528,6 +535,11 @@ kernel_dbg_exc: // b ret_from_crit_except b . + MASKABLE_EXCEPTION(0x2c0, guest_doorbell, .unknown_exception, ACK_NONE) + MASKABLE_EXCEPTION(0x2e0, guest_doorbell_crit, .unknown_exception, ACK_NONE) + MASKABLE_EXCEPTION(0x310, hypercall, .unknown_exception, ACK_NONE) + MASKABLE_EXCEPTION(0x320, ehpriv, .unknown_exception, ACK_NONE) + /* * An interrupt came in while soft-disabled; clear EE in SRR1, @@ -647,7 +659,12 @@ fast_exception_return: BAD_STACK_TRAMPOLINE(0x000) BAD_STACK_TRAMPOLINE(0x100) BAD_STACK_TRAMPOLINE(0x200) +BAD_STACK_TRAMPOLINE(0x260) +BAD_STACK_TRAMPOLINE(0x2c0) +BAD_STACK_TRAMPOLINE(0x2e0) BAD_STACK_TRAMPOLINE(0x300) +BAD_STACK_TRAMPOLINE(0x310) +BAD_STACK_TRAMPOLINE(0x320) BAD_STACK_TRAMPOLINE(0x400) BAD_STACK_TRAMPOLINE(0x500) BAD_STACK_TRAMPOLINE(0x600) @@ -1183,3 +1200,33 @@ _GLOBAL(__setup_base_ivors) sync blr + +_GLOBAL(setup_perfmon_ivor) + SET_IVOR(35, 0x260) /* Performance Monitor */ + blr + +_GLOBAL(setup_doorbell_ivors) + SET_IVOR(36, 0x280) /* Processor Doorbell */ + SET_IVOR(37, 0x2a0) /* Processor Doorbell Crit */ + + /* Check MMUCFG[LPIDSIZE] to determine if we have category E.HV */ + mfspr r10,SPRN_MMUCFG + rlwinm. r10,r10,0,MMUCFG_LPIDSIZE + beqlr + + SET_IVOR(38, 0x2c0) /* Guest Processor Doorbell */ + SET_IVOR(39, 0x2e0) /* Guest Processor Doorbell Crit/MC */ + blr + +_GLOBAL(setup_ehv_ivors) + /* + * We may be running as a guest and lack E.HV even on a chip + * that normally has it. + */ + mfspr r10,SPRN_MMUCFG + rlwinm. r10,r10,0,MMUCFG_LPIDSIZE + beqlr + + SET_IVOR(40, 0x300) /* Embedded Hypervisor System Call */ + SET_IVOR(41, 0x320) /* Embedded Hypervisor Privilege */ + blr -- cgit v0.10.2 From e0be2c21649107282930837f0805c71dfe29e2cc Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Wed, 4 May 2011 16:29:31 +0200 Subject: powerpc/mpc8610_hpcd: Do not use "/" in interrupt names It may trigger a warning in fs/proc/generic.c:__xlate_proc_name() when trying to add an entry for the interrupt handler to sysfs. Signed-off-by: Geert Uytterhoeven Acked-by: Timur Tabi Signed-off-by: Kumar Gala diff --git a/arch/powerpc/platforms/86xx/mpc8610_hpcd.c b/arch/powerpc/platforms/86xx/mpc8610_hpcd.c index 018cc67..efadd3b 100644 --- a/arch/powerpc/platforms/86xx/mpc8610_hpcd.c +++ b/arch/powerpc/platforms/86xx/mpc8610_hpcd.c @@ -66,7 +66,7 @@ static void __init mpc8610_suspend_init(void) return; } - ret = request_irq(irq, mpc8610_sw9_irq, 0, "sw9/wakeup", NULL); + ret = request_irq(irq, mpc8610_sw9_irq, 0, "sw9:wakeup", NULL); if (ret) { pr_err("%s: can't request pixis event IRQ: %d\n", __func__, ret); -- cgit v0.10.2 From f46dad270b7f425d7d4ec08676f2513732d11c2b Mon Sep 17 00:00:00 2001 From: Timur Tabi Date: Mon, 9 May 2011 14:29:40 -0500 Subject: powerpc/86xx: don't pretend that we support 8-bit pixels on the MPC8610 HPCD If the video mode is set to 16-, 24-, or 32-bit pixels, then the pixel data contains actual levels of red, blue, and green. However, if the video mode is set to 8-bit pixels, then the 8-bit value represents an index into color table. This is called "palette mode" on the Freescale DIU video controller. The DIU driver does not currently support palette mode, but the MPC8610 HPCD board file returned a non-zero (although incorrect) pixel format value for 8-bit mode. Signed-off-by: Timur Tabi Signed-off-by: Kumar Gala diff --git a/arch/powerpc/platforms/86xx/mpc8610_hpcd.c b/arch/powerpc/platforms/86xx/mpc8610_hpcd.c index efadd3b..a896511 100644 --- a/arch/powerpc/platforms/86xx/mpc8610_hpcd.c +++ b/arch/powerpc/platforms/86xx/mpc8610_hpcd.c @@ -105,45 +105,77 @@ machine_device_initcall(mpc86xx_hpcd, mpc8610_declare_of_platform_devices); #if defined(CONFIG_FB_FSL_DIU) || defined(CONFIG_FB_FSL_DIU_MODULE) -static u32 get_busfreq(void) -{ - struct device_node *node; - - u32 fs_busfreq = 0; - node = of_find_node_by_type(NULL, "cpu"); - if (node) { - unsigned int size; - const unsigned int *prop = - of_get_property(node, "bus-frequency", &size); - if (prop) - fs_busfreq = *prop; - of_node_put(node); - }; - return fs_busfreq; -} +/* + * DIU Area Descriptor + * + * The MPC8610 reference manual shows the bits of the AD register in + * little-endian order, which causes the BLUE_C field to be split into two + * parts. To simplify the definition of the MAKE_AD() macro, we define the + * fields in big-endian order and byte-swap the result. + * + * So even though the registers don't look like they're in the + * same bit positions as they are on the P1022, the same value is written to + * the AD register on the MPC8610 and on the P1022. + */ +#define AD_BYTE_F 0x10000000 +#define AD_ALPHA_C_MASK 0x0E000000 +#define AD_ALPHA_C_SHIFT 25 +#define AD_BLUE_C_MASK 0x01800000 +#define AD_BLUE_C_SHIFT 23 +#define AD_GREEN_C_MASK 0x00600000 +#define AD_GREEN_C_SHIFT 21 +#define AD_RED_C_MASK 0x00180000 +#define AD_RED_C_SHIFT 19 +#define AD_PALETTE 0x00040000 +#define AD_PIXEL_S_MASK 0x00030000 +#define AD_PIXEL_S_SHIFT 16 +#define AD_COMP_3_MASK 0x0000F000 +#define AD_COMP_3_SHIFT 12 +#define AD_COMP_2_MASK 0x00000F00 +#define AD_COMP_2_SHIFT 8 +#define AD_COMP_1_MASK 0x000000F0 +#define AD_COMP_1_SHIFT 4 +#define AD_COMP_0_MASK 0x0000000F +#define AD_COMP_0_SHIFT 0 + +#define MAKE_AD(alpha, red, blue, green, size, c0, c1, c2, c3) \ + cpu_to_le32(AD_BYTE_F | (alpha << AD_ALPHA_C_SHIFT) | \ + (blue << AD_BLUE_C_SHIFT) | (green << AD_GREEN_C_SHIFT) | \ + (red << AD_RED_C_SHIFT) | (c3 << AD_COMP_3_SHIFT) | \ + (c2 << AD_COMP_2_SHIFT) | (c1 << AD_COMP_1_SHIFT) | \ + (c0 << AD_COMP_0_SHIFT) | (size << AD_PIXEL_S_SHIFT)) unsigned int mpc8610hpcd_get_pixel_format(unsigned int bits_per_pixel, int monitor_port) { static const unsigned long pixelformat[][3] = { - {0x88882317, 0x88083218, 0x65052119}, - {0x88883316, 0x88082219, 0x65053118}, + { + MAKE_AD(3, 0, 2, 1, 3, 8, 8, 8, 8), + MAKE_AD(4, 2, 0, 1, 2, 8, 8, 8, 0), + MAKE_AD(4, 0, 2, 1, 1, 5, 6, 5, 0) + }, + { + MAKE_AD(3, 2, 0, 1, 3, 8, 8, 8, 8), + MAKE_AD(4, 0, 2, 1, 2, 8, 8, 8, 0), + MAKE_AD(4, 2, 0, 1, 1, 5, 6, 5, 0) + }, }; - unsigned int pix_fmt, arch_monitor; + unsigned int arch_monitor; + /* The DVI port is mis-wired on revision 1 of this board. */ arch_monitor = ((*pixis_arch == 0x01) && (monitor_port == 0))? 0 : 1; - /* DVI port for board version 0x01 */ - - if (bits_per_pixel == 32) - pix_fmt = pixelformat[arch_monitor][0]; - else if (bits_per_pixel == 24) - pix_fmt = pixelformat[arch_monitor][1]; - else if (bits_per_pixel == 16) - pix_fmt = pixelformat[arch_monitor][2]; - else - pix_fmt = pixelformat[1][0]; - - return pix_fmt; + + switch (bits_per_pixel) { + case 32: + return pixelformat[arch_monitor][0]; + case 24: + return pixelformat[arch_monitor][1]; + case 16: + return pixelformat[arch_monitor][2]; + default: + pr_err("fsl-diu: unsupported pixel depth %u\n", bits_per_pixel); + return 0; + } } void mpc8610hpcd_set_gamma_table(int monitor_port, char *gamma_table_base) @@ -190,8 +222,7 @@ void mpc8610hpcd_set_pixel_clock(unsigned int pixclock) } /* Pixel Clock configuration */ - pr_debug("DIU: Bus Frequency = %d\n", get_busfreq()); - speed_ccb = get_busfreq(); + speed_ccb = fsl_get_sys_freq(); /* Calculate the pixel clock with the smallest error */ /* calculate the following in steps to avoid overflow */ -- cgit v0.10.2 From 180076cb11a5f02de7d26f8cb82969b895a26f40 Mon Sep 17 00:00:00 2001 From: Scott Wood Date: Thu, 24 Mar 2011 16:43:15 -0500 Subject: powerpc: Add fsl mpic timer binding Update the existing example in the general mpic binding to have a separate TCRx region. Currently the example doesn't describe TCRx at all. The one upstream device tree with an mpic timer node (p1022ds) uses one large reg region to describe both, even though there are other unrelated registers in between. That device tree also contains a bogus interrupt specifier, and there's no upstream software that uses this yet, so changing this shouldn't be a problem. Add a full binding for the MPIC timer node, not just an example of 4-cell interrupts in the MPIC binding. Add fsl,available-ranges, similar to msi-available-ranges. Signed-off-by: Scott Wood Signed-off-by: Kumar Gala diff --git a/Documentation/devicetree/bindings/powerpc/fsl/mpic-timer.txt b/Documentation/devicetree/bindings/powerpc/fsl/mpic-timer.txt new file mode 100644 index 0000000..df41958 --- /dev/null +++ b/Documentation/devicetree/bindings/powerpc/fsl/mpic-timer.txt @@ -0,0 +1,38 @@ +* Freescale MPIC timers + +Required properties: +- compatible: "fsl,mpic-global-timer" + +- reg : Contains two regions. The first is the main timer register bank + (GTCCRxx, GTBCRxx, GTVPRxx, GTDRxx). The second is the timer control + register (TCRx) for the group. + +- fsl,available-ranges: use style section to define which + timer interrupts can be used. This property is optional; without this, + all timers within the group can be used. + +- interrupts: one interrupt per timer in the group, in order, starting + with timer zero. If timer-available-ranges is present, only the + interrupts that correspond to available timers shall be present. + +Example: + /* Note that this requires #interrupt-cells to be 4 */ + timer0: timer@41100 { + compatible = "fsl,mpic-global-timer"; + reg = <0x41100 0x100 0x41300 4>; + + /* Another AMP partition is using timers 0 and 1 */ + fsl,available-ranges = <2 2>; + + interrupts = <2 0 3 0 + 3 0 3 0>; + }; + + timer1: timer@42100 { + compatible = "fsl,mpic-global-timer"; + reg = <0x42100 0x100 0x42300 4>; + interrupts = <4 0 3 0 + 5 0 3 0 + 6 0 3 0 + 7 0 3 0>; + }; diff --git a/Documentation/devicetree/bindings/powerpc/fsl/mpic.txt b/Documentation/devicetree/bindings/powerpc/fsl/mpic.txt index 4f61458..2cf38bd 100644 --- a/Documentation/devicetree/bindings/powerpc/fsl/mpic.txt +++ b/Documentation/devicetree/bindings/powerpc/fsl/mpic.txt @@ -190,7 +190,7 @@ EXAMPLE 4 */ timer0: timer@41100 { compatible = "fsl,mpic-global-timer"; - reg = <0x41100 0x100>; + reg = <0x41100 0x100 0x41300 4>; interrupts = <0 0 3 0 1 0 3 0 2 0 3 0 -- cgit v0.10.2 From c281739f5988af1f86ef06e92485aec25b8c8c4f Mon Sep 17 00:00:00 2001 From: Scott Wood Date: Thu, 24 Mar 2011 16:43:52 -0500 Subject: powerpc/p1022ds: fix broken mpic timer node There is no hardware interrupt 0xf7. But now we can express the timer interrupt using 4-cell interrupts. This requires converting all of the other interrupt specifiers in the tree as well. Also add the second timer group, and fix the reg property to only describe the timer registers. Signed-off-by: Scott Wood Signed-off-by: Kumar Gala diff --git a/arch/powerpc/boot/dts/p1022ds.dts b/arch/powerpc/boot/dts/p1022ds.dts index 59ef405..4f685a7 100644 --- a/arch/powerpc/boot/dts/p1022ds.dts +++ b/arch/powerpc/boot/dts/p1022ds.dts @@ -52,7 +52,7 @@ #size-cells = <1>; compatible = "fsl,p1022-elbc", "fsl,elbc", "simple-bus"; reg = <0 0xffe05000 0 0x1000>; - interrupts = <19 2>; + interrupts = <19 2 0 0>; ranges = <0x0 0x0 0xf 0xe8000000 0x08000000 0x1 0x0 0xf 0xe0000000 0x08000000 @@ -157,7 +157,7 @@ * IRQ8 is generated if the "EVENT" switch is pressed * and PX_CTL[EVESEL] is set to 00. */ - interrupts = <8 8>; + interrupts = <8 8 0 0>; }; }; @@ -178,13 +178,13 @@ ecm@1000 { compatible = "fsl,p1022-ecm", "fsl,ecm"; reg = <0x1000 0x1000>; - interrupts = <16 2>; + interrupts = <16 2 0 0>; }; memory-controller@2000 { compatible = "fsl,p1022-memory-controller"; reg = <0x2000 0x1000>; - interrupts = <16 2>; + interrupts = <16 2 0 0>; }; i2c@3000 { @@ -193,7 +193,7 @@ cell-index = <0>; compatible = "fsl-i2c"; reg = <0x3000 0x100>; - interrupts = <43 2>; + interrupts = <43 2 0 0>; dfsrr; }; @@ -203,7 +203,7 @@ cell-index = <1>; compatible = "fsl-i2c"; reg = <0x3100 0x100>; - interrupts = <43 2>; + interrupts = <43 2 0 0>; dfsrr; wm8776:codec@1a { @@ -220,7 +220,7 @@ compatible = "ns16550"; reg = <0x4500 0x100>; clock-frequency = <0>; - interrupts = <42 2>; + interrupts = <42 2 0 0>; }; serial1: serial@4600 { @@ -229,7 +229,7 @@ compatible = "ns16550"; reg = <0x4600 0x100>; clock-frequency = <0>; - interrupts = <42 2>; + interrupts = <42 2 0 0>; }; spi@7000 { @@ -238,7 +238,7 @@ #size-cells = <0>; compatible = "fsl,espi"; reg = <0x7000 0x1000>; - interrupts = <59 0x2>; + interrupts = <59 0x2 0 0>; espi,num-ss-bits = <4>; mode = "cpu"; @@ -275,7 +275,7 @@ compatible = "fsl,mpc8610-ssi"; cell-index = <0>; reg = <0x15000 0x100>; - interrupts = <75 2>; + interrupts = <75 2 0 0>; fsl,mode = "i2s-slave"; codec-handle = <&wm8776>; fsl,playback-dma = <&dma00>; @@ -294,25 +294,25 @@ compatible = "fsl,ssi-dma-channel"; reg = <0x0 0x80>; cell-index = <0>; - interrupts = <76 2>; + interrupts = <76 2 0 0>; }; dma01: dma-channel@80 { compatible = "fsl,ssi-dma-channel"; reg = <0x80 0x80>; cell-index = <1>; - interrupts = <77 2>; + interrupts = <77 2 0 0>; }; dma-channel@100 { compatible = "fsl,eloplus-dma-channel"; reg = <0x100 0x80>; cell-index = <2>; - interrupts = <78 2>; + interrupts = <78 2 0 0>; }; dma-channel@180 { compatible = "fsl,eloplus-dma-channel"; reg = <0x180 0x80>; cell-index = <3>; - interrupts = <79 2>; + interrupts = <79 2 0 0>; }; }; @@ -320,7 +320,7 @@ #gpio-cells = <2>; compatible = "fsl,mpc8572-gpio"; reg = <0xf000 0x100>; - interrupts = <47 0x2>; + interrupts = <47 0x2 0 0>; gpio-controller; }; @@ -329,7 +329,7 @@ reg = <0x20000 0x1000>; cache-line-size = <32>; // 32 bytes cache-size = <0x40000>; // L2, 256K - interrupts = <16 2>; + interrupts = <16 2 0 0>; }; dma@21300 { @@ -343,25 +343,25 @@ compatible = "fsl,eloplus-dma-channel"; reg = <0x0 0x80>; cell-index = <0>; - interrupts = <20 2>; + interrupts = <20 2 0 0>; }; dma-channel@80 { compatible = "fsl,eloplus-dma-channel"; reg = <0x80 0x80>; cell-index = <1>; - interrupts = <21 2>; + interrupts = <21 2 0 0>; }; dma-channel@100 { compatible = "fsl,eloplus-dma-channel"; reg = <0x100 0x80>; cell-index = <2>; - interrupts = <22 2>; + interrupts = <22 2 0 0>; }; dma-channel@180 { compatible = "fsl,eloplus-dma-channel"; reg = <0x180 0x80>; cell-index = <3>; - interrupts = <23 2>; + interrupts = <23 2 0 0>; }; }; @@ -370,7 +370,7 @@ #size-cells = <0>; compatible = "fsl-usb2-dr"; reg = <0x22000 0x1000>; - interrupts = <28 0x2>; + interrupts = <28 0x2 0 0>; phy_type = "ulpi"; }; @@ -381,11 +381,11 @@ reg = <0x24000 0x1000 0xb0030 0x4>; phy0: ethernet-phy@0 { - interrupts = <3 1>; + interrupts = <3 1 0 0>; reg = <0x1>; }; phy1: ethernet-phy@1 { - interrupts = <9 1>; + interrupts = <9 1 0 0>; reg = <0x2>; }; }; @@ -416,13 +416,13 @@ #address-cells = <1>; #size-cells = <1>; reg = <0xB0000 0x1000>; - interrupts = <29 2 30 2 34 2>; + interrupts = <29 2 0 0 30 2 0 0 34 2 0 0>; }; queue-group@1{ #address-cells = <1>; #size-cells = <1>; reg = <0xB4000 0x1000>; - interrupts = <17 2 18 2 24 2>; + interrupts = <17 2 0 0 18 2 0 0 24 2 0 0>; }; }; @@ -443,20 +443,20 @@ #address-cells = <1>; #size-cells = <1>; reg = <0xB1000 0x1000>; - interrupts = <35 2 36 2 40 2>; + interrupts = <35 2 0 0 36 2 0 0 40 2 0 0>; }; queue-group@1{ #address-cells = <1>; #size-cells = <1>; reg = <0xB5000 0x1000>; - interrupts = <51 2 52 2 67 2>; + interrupts = <51 2 0 0 52 2 0 0 67 2 0 0>; }; }; sdhci@2e000 { compatible = "fsl,p1022-esdhc", "fsl,esdhc"; reg = <0x2e000 0x1000>; - interrupts = <72 0x2>; + interrupts = <72 0x2 0 0>; fsl,sdhci-auto-cmd12; /* Filled in by U-Boot */ clock-frequency = <0>; @@ -467,7 +467,7 @@ "fsl,sec2.4", "fsl,sec2.2", "fsl,sec2.1", "fsl,sec2.0"; reg = <0x30000 0x10000>; - interrupts = <45 2 58 2>; + interrupts = <45 2 0 0 58 2 0 0>; fsl,num-channels = <4>; fsl,channel-fifo-len = <24>; fsl,exec-units-mask = <0x97c>; @@ -478,14 +478,14 @@ compatible = "fsl,p1022-sata", "fsl,pq-sata-v2"; reg = <0x18000 0x1000>; cell-index = <1>; - interrupts = <74 0x2>; + interrupts = <74 0x2 0 0>; }; sata@19000 { compatible = "fsl,p1022-sata", "fsl,pq-sata-v2"; reg = <0x19000 0x1000>; cell-index = <2>; - interrupts = <41 0x2>; + interrupts = <41 0x2 0 0>; }; power@e0070{ @@ -496,21 +496,33 @@ display@10000 { compatible = "fsl,diu", "fsl,p1022-diu"; reg = <0x10000 1000>; - interrupts = <64 2>; + interrupts = <64 2 0 0>; }; timer@41100 { compatible = "fsl,mpic-global-timer"; - reg = <0x41100 0x204>; - interrupts = <0xf7 0x2>; + reg = <0x41100 0x100 0x41300 4>; + interrupts = <0 0 3 0 + 1 0 3 0 + 2 0 3 0 + 3 0 3 0>; + }; + + timer@42100 { + compatible = "fsl,mpic-global-timer"; + reg = <0x42100 0x100 0x42300 4>; + interrupts = <4 0 3 0 + 5 0 3 0 + 6 0 3 0 + 7 0 3 0>; }; mpic: pic@40000 { interrupt-controller; #address-cells = <0>; - #interrupt-cells = <2>; + #interrupt-cells = <4>; reg = <0x40000 0x40000>; - compatible = "chrp,open-pic"; + compatible = "fsl,mpic"; device_type = "open-pic"; }; @@ -519,14 +531,14 @@ reg = <0x41600 0x80>; msi-available-ranges = <0 0x100>; interrupts = < - 0xe0 0 - 0xe1 0 - 0xe2 0 - 0xe3 0 - 0xe4 0 - 0xe5 0 - 0xe6 0 - 0xe7 0>; + 0xe0 0 0 0 + 0xe1 0 0 0 + 0xe2 0 0 0 + 0xe3 0 0 0 + 0xe4 0 0 0 + 0xe5 0 0 0 + 0xe6 0 0 0 + 0xe7 0 0 0>; }; global-utilities@e0000 { //global utilities block @@ -547,7 +559,7 @@ ranges = <0x2000000 0x0 0xa0000000 0xc 0x20000000 0x0 0x20000000 0x1000000 0x0 0x00000000 0xf 0xffc10000 0x0 0x10000>; clock-frequency = <33333333>; - interrupts = <16 2>; + interrupts = <16 2 0 0>; interrupt-map-mask = <0xf800 0 0 7>; interrupt-map = < /* IDSEL 0x0 */ @@ -582,7 +594,7 @@ ranges = <0x2000000 0x0 0xc0000000 0xc 0x40000000 0x0 0x20000000 0x1000000 0x0 0x00000000 0xf 0xffc20000 0x0 0x10000>; clock-frequency = <33333333>; - interrupts = <16 2>; + interrupts = <16 2 0 0>; interrupt-map-mask = <0xf800 0 0 7>; interrupt-map = < /* IDSEL 0x0 */ @@ -618,7 +630,7 @@ ranges = <0x2000000 0x0 0x80000000 0xc 0x00000000 0x0 0x20000000 0x1000000 0x0 0x00000000 0xf 0xffc00000 0x0 0x10000>; clock-frequency = <33333333>; - interrupts = <16 2>; + interrupts = <16 2 0 0>; interrupt-map-mask = <0xf800 0 0 7>; interrupt-map = < /* IDSEL 0x0 */ -- cgit v0.10.2 From 22d168ce60272ca112e86e58c5ebde82f20f9c83 Mon Sep 17 00:00:00 2001 From: Scott Wood Date: Thu, 24 Mar 2011 16:43:54 -0500 Subject: powerpc/mpic: parse 4-cell intspec types other than zero Signed-off-by: Scott Wood Signed-off-by: Kumar Gala diff --git a/arch/powerpc/include/asm/mpic.h b/arch/powerpc/include/asm/mpic.h index 7005ee0..25a0cb3 100644 --- a/arch/powerpc/include/asm/mpic.h +++ b/arch/powerpc/include/asm/mpic.h @@ -371,6 +371,8 @@ struct mpic * NOTE: This flag trumps MPIC_WANTS_RESET. */ #define MPIC_NO_RESET 0x00004000 +/* Freescale MPIC (compatible includes "fsl,mpic") */ +#define MPIC_FSL 0x00008000 /* MPIC HW modification ID */ #define MPIC_REGSET_MASK 0xf0000000 diff --git a/arch/powerpc/sysdev/mpic.c b/arch/powerpc/sysdev/mpic.c index 824a94f..0a3c1c2 100644 --- a/arch/powerpc/sysdev/mpic.c +++ b/arch/powerpc/sysdev/mpic.c @@ -6,6 +6,7 @@ * with various broken implementations of this HW. * * Copyright (C) 2004 Benjamin Herrenschmidt, IBM Corp. + * Copyright 2010-2011 Freescale Semiconductor, Inc. * * 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 @@ -1023,6 +1024,7 @@ static int mpic_host_xlate(struct irq_host *h, struct device_node *ct, irq_hw_number_t *out_hwirq, unsigned int *out_flags) { + struct mpic *mpic = h->host_data; static unsigned char map_mpic_senses[4] = { IRQ_TYPE_EDGE_RISING, IRQ_TYPE_LEVEL_LOW, @@ -1031,7 +1033,38 @@ static int mpic_host_xlate(struct irq_host *h, struct device_node *ct, }; *out_hwirq = intspec[0]; - if (intsize > 1) { + if (intsize >= 4 && (mpic->flags & MPIC_FSL)) { + /* + * Freescale MPIC with extended intspec: + * First two cells are as usual. Third specifies + * an "interrupt type". Fourth is type-specific data. + * + * See Documentation/devicetree/bindings/powerpc/fsl/mpic.txt + */ + switch (intspec[2]) { + case 0: + case 1: /* no EISR/EIMR support for now, treat as shared IRQ */ + break; + case 2: + if (intspec[0] >= ARRAY_SIZE(mpic->ipi_vecs)) + return -EINVAL; + + *out_hwirq = mpic->ipi_vecs[intspec[0]]; + break; + case 3: + if (intspec[0] >= ARRAY_SIZE(mpic->timer_vecs)) + return -EINVAL; + + *out_hwirq = mpic->timer_vecs[intspec[0]]; + break; + default: + pr_debug("%s: unknown irq type %u\n", + __func__, intspec[2]); + return -EINVAL; + } + + *out_flags = map_mpic_senses[intspec[1] & 3]; + } else if (intsize > 1) { u32 mask = 0x3; /* Apple invented a new race of encoding on machines with @@ -1130,6 +1163,8 @@ struct mpic * __init mpic_alloc(struct device_node *node, /* Check for "big-endian" in device-tree */ if (node && of_get_property(node, "big-endian", NULL) != NULL) mpic->flags |= MPIC_BIG_ENDIAN; + if (node && of_device_is_compatible(node, "fsl,mpic")) + mpic->flags |= MPIC_FSL; /* Look for protected sources */ if (node) { -- cgit v0.10.2 From ea94187face757e723aa461a60698ca43c09fbb9 Mon Sep 17 00:00:00 2001 From: Scott Wood Date: Thu, 24 Mar 2011 16:43:55 -0500 Subject: powerpc/mpic: add the mpic global timer support Add support for MPIC timers as requestable interrupt sources. Based on http://patchwork.ozlabs.org/patch/20941/ by Dave Liu. Signed-off-by: Dave Liu Signed-off-by: Scott Wood Signed-off-by: Kumar Gala diff --git a/arch/powerpc/include/asm/mpic.h b/arch/powerpc/include/asm/mpic.h index 25a0cb3..664bee66 100644 --- a/arch/powerpc/include/asm/mpic.h +++ b/arch/powerpc/include/asm/mpic.h @@ -263,6 +263,7 @@ struct mpic #ifdef CONFIG_SMP struct irq_chip hc_ipi; #endif + struct irq_chip hc_tm; const char *name; /* Flags */ unsigned int flags; @@ -281,7 +282,7 @@ struct mpic /* vector numbers used for internal sources (ipi/timers) */ unsigned int ipi_vecs[4]; - unsigned int timer_vecs[4]; + unsigned int timer_vecs[8]; /* Spurious vector to program into unused sources */ unsigned int spurious_vec; diff --git a/arch/powerpc/sysdev/mpic.c b/arch/powerpc/sysdev/mpic.c index 0a3c1c2..0e47bce5 100644 --- a/arch/powerpc/sysdev/mpic.c +++ b/arch/powerpc/sysdev/mpic.c @@ -219,6 +219,28 @@ static inline void _mpic_ipi_write(struct mpic *mpic, unsigned int ipi, u32 valu _mpic_write(mpic->reg_type, &mpic->gregs, offset, value); } +static inline u32 _mpic_tm_read(struct mpic *mpic, unsigned int tm) +{ + unsigned int offset = MPIC_INFO(TIMER_VECTOR_PRI) + + ((tm & 3) * MPIC_INFO(TIMER_STRIDE)); + + if (tm >= 4) + offset += 0x1000 / 4; + + return _mpic_read(mpic->reg_type, &mpic->tmregs, offset); +} + +static inline void _mpic_tm_write(struct mpic *mpic, unsigned int tm, u32 value) +{ + unsigned int offset = MPIC_INFO(TIMER_VECTOR_PRI) + + ((tm & 3) * MPIC_INFO(TIMER_STRIDE)); + + if (tm >= 4) + offset += 0x1000 / 4; + + _mpic_write(mpic->reg_type, &mpic->tmregs, offset, value); +} + static inline u32 _mpic_cpu_read(struct mpic *mpic, unsigned int reg) { unsigned int cpu = mpic_processor_id(mpic); @@ -269,6 +291,8 @@ static inline void _mpic_irq_write(struct mpic *mpic, unsigned int src_no, #define mpic_write(b,r,v) _mpic_write(mpic->reg_type,&(b),(r),(v)) #define mpic_ipi_read(i) _mpic_ipi_read(mpic,(i)) #define mpic_ipi_write(i,v) _mpic_ipi_write(mpic,(i),(v)) +#define mpic_tm_read(i) _mpic_tm_read(mpic,(i)) +#define mpic_tm_write(i,v) _mpic_tm_write(mpic,(i),(v)) #define mpic_cpu_read(i) _mpic_cpu_read(mpic,(i)) #define mpic_cpu_write(i,v) _mpic_cpu_write(mpic,(i),(v)) #define mpic_irq_read(s,r) _mpic_irq_read(mpic,(s),(r)) @@ -625,6 +649,13 @@ static unsigned int mpic_is_ipi(struct mpic *mpic, unsigned int irq) return (src >= mpic->ipi_vecs[0] && src <= mpic->ipi_vecs[3]); } +/* Determine if the linux irq is a timer */ +static unsigned int mpic_is_tm(struct mpic *mpic, unsigned int irq) +{ + unsigned int src = virq_to_hw(irq); + + return (src >= mpic->timer_vecs[0] && src <= mpic->timer_vecs[7]); +} /* Convert a cpu mask from logical to physical cpu numbers. */ static inline u32 mpic_physmask(u32 cpumask) @@ -811,6 +842,25 @@ static void mpic_end_ipi(struct irq_data *d) #endif /* CONFIG_SMP */ +static void mpic_unmask_tm(struct irq_data *d) +{ + struct mpic *mpic = mpic_from_irq_data(d); + unsigned int src = virq_to_hw(d->irq) - mpic->timer_vecs[0]; + + DBG("%s: enable_tm: %d (tm %d)\n", mpic->name, irq, src); + mpic_tm_write(src, mpic_tm_read(src) & ~MPIC_VECPRI_MASK); + mpic_tm_read(src); +} + +static void mpic_mask_tm(struct irq_data *d) +{ + struct mpic *mpic = mpic_from_irq_data(d); + unsigned int src = virq_to_hw(d->irq) - mpic->timer_vecs[0]; + + mpic_tm_write(src, mpic_tm_read(src) | MPIC_VECPRI_MASK); + mpic_tm_read(src); +} + int mpic_set_affinity(struct irq_data *d, const struct cpumask *cpumask, bool force) { @@ -941,6 +991,12 @@ static struct irq_chip mpic_ipi_chip = { }; #endif /* CONFIG_SMP */ +static struct irq_chip mpic_tm_chip = { + .irq_mask = mpic_mask_tm, + .irq_unmask = mpic_unmask_tm, + .irq_eoi = mpic_end_irq, +}; + #ifdef CONFIG_MPIC_U3_HT_IRQS static struct irq_chip mpic_irq_ht_chip = { .irq_startup = mpic_startup_ht_irq, @@ -984,6 +1040,16 @@ static int mpic_host_map(struct irq_host *h, unsigned int virq, } #endif /* CONFIG_SMP */ + if (hw >= mpic->timer_vecs[0] && hw <= mpic->timer_vecs[7]) { + WARN_ON(!(mpic->flags & MPIC_PRIMARY)); + + DBG("mpic: mapping as timer\n"); + irq_set_chip_data(virq, mpic); + irq_set_chip_and_handler(virq, &mpic->hc_tm, + handle_fasteoi_irq); + return 0; + } + if (hw >= mpic->irq_count) return -EINVAL; @@ -1140,6 +1206,9 @@ struct mpic * __init mpic_alloc(struct device_node *node, mpic->hc_ipi.name = name; #endif /* CONFIG_SMP */ + mpic->hc_tm = mpic_tm_chip; + mpic->hc_tm.name = name; + mpic->flags = flags; mpic->isu_size = isu_size; mpic->irq_count = irq_count; @@ -1150,10 +1219,14 @@ struct mpic * __init mpic_alloc(struct device_node *node, else intvec_top = 255; - mpic->timer_vecs[0] = intvec_top - 8; - mpic->timer_vecs[1] = intvec_top - 7; - mpic->timer_vecs[2] = intvec_top - 6; - mpic->timer_vecs[3] = intvec_top - 5; + mpic->timer_vecs[0] = intvec_top - 12; + mpic->timer_vecs[1] = intvec_top - 11; + mpic->timer_vecs[2] = intvec_top - 10; + mpic->timer_vecs[3] = intvec_top - 9; + mpic->timer_vecs[4] = intvec_top - 8; + mpic->timer_vecs[5] = intvec_top - 7; + mpic->timer_vecs[6] = intvec_top - 6; + mpic->timer_vecs[7] = intvec_top - 5; mpic->ipi_vecs[0] = intvec_top - 4; mpic->ipi_vecs[1] = intvec_top - 3; mpic->ipi_vecs[2] = intvec_top - 2; @@ -1356,15 +1429,17 @@ void __init mpic_init(struct mpic *mpic) /* Set current processor priority to max */ mpic_cpu_write(MPIC_INFO(CPU_CURRENT_TASK_PRI), 0xf); - /* Initialize timers: just disable them all */ + /* Initialize timers to our reserved vectors and mask them for now */ for (i = 0; i < 4; i++) { mpic_write(mpic->tmregs, i * MPIC_INFO(TIMER_STRIDE) + - MPIC_INFO(TIMER_DESTINATION), 0); + MPIC_INFO(TIMER_DESTINATION), + 1 << hard_smp_processor_id()); mpic_write(mpic->tmregs, i * MPIC_INFO(TIMER_STRIDE) + MPIC_INFO(TIMER_VECTOR_PRI), MPIC_VECPRI_MASK | + (9 << MPIC_VECPRI_PRIORITY_SHIFT) | (mpic->timer_vecs[0] + i)); } @@ -1473,6 +1548,11 @@ void mpic_irq_set_priority(unsigned int irq, unsigned int pri) ~MPIC_VECPRI_PRIORITY_MASK; mpic_ipi_write(src - mpic->ipi_vecs[0], reg | (pri << MPIC_VECPRI_PRIORITY_SHIFT)); + } else if (mpic_is_tm(mpic, irq)) { + reg = mpic_tm_read(src - mpic->timer_vecs[0]) & + ~MPIC_VECPRI_PRIORITY_MASK; + mpic_tm_write(src - mpic->timer_vecs[0], + reg | (pri << MPIC_VECPRI_PRIORITY_SHIFT)); } else { reg = mpic_irq_read(src, MPIC_INFO(IRQ_VECTOR_PRI)) & ~MPIC_VECPRI_PRIORITY_MASK; -- cgit v0.10.2 From 5e8393ab311d2c34f2965be40ebec99c772284ab Mon Sep 17 00:00:00 2001 From: Scott Wood Date: Tue, 10 May 2011 13:01:47 -0500 Subject: powerpc/e5500: add networking to defconfig Even though support for the p5020's on-chip ethernet is not yet upstream, it is not appropriate to disable all networking support (including loopback, unix domain sockets, external ethernet devices, etc) in the defconfig. The networking settings are taken from mpc85xx_smp_defconfig, minus the drivers for ethernet devices not found on any current e5500 chip. The other changes are the result of running "make savedefconfig". Signed-off-by: Scott Wood Signed-off-by: Kumar Gala diff --git a/arch/powerpc/configs/e55xx_smp_defconfig b/arch/powerpc/configs/e55xx_smp_defconfig index 9fa1613..f4c5780 100644 --- a/arch/powerpc/configs/e55xx_smp_defconfig +++ b/arch/powerpc/configs/e55xx_smp_defconfig @@ -6,10 +6,10 @@ CONFIG_NR_CPUS=2 CONFIG_EXPERIMENTAL=y CONFIG_SYSVIPC=y CONFIG_BSD_PROCESS_ACCT=y +CONFIG_SPARSE_IRQ=y CONFIG_IKCONFIG=y CONFIG_IKCONFIG_PROC=y CONFIG_LOG_BUF_SHIFT=14 -CONFIG_SYSFS_DEPRECATED_V2=y CONFIG_BLK_DEV_INITRD=y # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set CONFIG_EXPERT=y @@ -25,8 +25,32 @@ CONFIG_P5020_DS=y CONFIG_NO_HZ=y CONFIG_HIGH_RES_TIMERS=y CONFIG_BINFMT_MISC=m -CONFIG_SPARSE_IRQ=y # CONFIG_PCI is not set +CONFIG_NET=y +CONFIG_PACKET=y +CONFIG_UNIX=y +CONFIG_XFRM_USER=y +CONFIG_NET_KEY=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_PNP=y +CONFIG_IP_PNP_DHCP=y +CONFIG_IP_PNP_BOOTP=y +CONFIG_IP_PNP_RARP=y +CONFIG_NET_IPIP=y +CONFIG_IP_MROUTE=y +CONFIG_IP_PIMSM_V1=y +CONFIG_IP_PIMSM_V2=y +CONFIG_ARPD=y +CONFIG_INET_ESP=y +# CONFIG_INET_XFRM_MODE_BEET is not set +# CONFIG_INET_LRO is not set +CONFIG_IPV6=y +CONFIG_IP_SCTP=m CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" CONFIG_PROC_DEVICETREE=y CONFIG_BLK_DEV_LOOP=y @@ -34,6 +58,9 @@ CONFIG_BLK_DEV_RAM=y CONFIG_BLK_DEV_RAM_SIZE=131072 CONFIG_MISC_DEVICES=y CONFIG_EEPROM_LEGACY=y +CONFIG_NETDEVICES=y +CONFIG_DUMMY=y +CONFIG_NET_ETHERNET=y CONFIG_INPUT_FF_MEMLESS=m # CONFIG_INPUT_MOUSEDEV is not set # CONFIG_INPUT_KEYBOARD is not set @@ -64,7 +91,6 @@ CONFIG_NLS=y CONFIG_NLS_UTF8=m CONFIG_CRC_T10DIF=y CONFIG_CRC_ITU_T=m -CONFIG_LIBCRC32C=m CONFIG_FRAME_WARN=1024 CONFIG_DEBUG_FS=y CONFIG_DEBUG_KERNEL=y @@ -74,12 +100,6 @@ CONFIG_DEBUG_INFO=y # CONFIG_RCU_CPU_STALL_DETECTOR is not set CONFIG_SYSCTL_SYSCALL_CHECK=y CONFIG_VIRQ_DEBUG=y -CONFIG_CRYPTO=y -CONFIG_CRYPTO_CBC=y CONFIG_CRYPTO_PCBC=m -CONFIG_CRYPTO_HMAC=y -CONFIG_CRYPTO_MD5=y -CONFIG_CRYPTO_SHA1=m -CONFIG_CRYPTO_DES=y # CONFIG_CRYPTO_ANSI_CPRNG is not set CONFIG_CRYPTO_DEV_TALITOS=y -- cgit v0.10.2 From b637cf7bf82d0692609821cd84e3a345e56cd96c Mon Sep 17 00:00:00 2001 From: Scott Wood Date: Tue, 10 May 2011 13:02:06 -0500 Subject: powerpc/fsl: enable verbose bug output This debug option has no overhead other than a slight increase in kernel size, and makes bug reports more useful. While some end users may prefer to save the space, as a default on a kernel config aimed primarily at development on reference boards, it should be enabled. Signed-off-by: Scott Wood Signed-off-by: Kumar Gala diff --git a/arch/powerpc/configs/83xx/mpc8313_rdb_defconfig b/arch/powerpc/configs/83xx/mpc8313_rdb_defconfig index c683bce..126ef1b 100644 --- a/arch/powerpc/configs/83xx/mpc8313_rdb_defconfig +++ b/arch/powerpc/configs/83xx/mpc8313_rdb_defconfig @@ -104,7 +104,6 @@ CONFIG_ROOT_NFS=y CONFIG_PARTITION_ADVANCED=y CONFIG_DEBUG_KERNEL=y CONFIG_DETECT_HUNG_TASK=y -# CONFIG_DEBUG_BUGVERBOSE is not set # CONFIG_RCU_CPU_STALL_DETECTOR is not set CONFIG_SYSCTL_SYSCALL_CHECK=y CONFIG_CRYPTO_PCBC=m diff --git a/arch/powerpc/configs/83xx/mpc8315_rdb_defconfig b/arch/powerpc/configs/83xx/mpc8315_rdb_defconfig index a721cd3..abcf00a 100644 --- a/arch/powerpc/configs/83xx/mpc8315_rdb_defconfig +++ b/arch/powerpc/configs/83xx/mpc8315_rdb_defconfig @@ -101,7 +101,6 @@ CONFIG_ROOT_NFS=y CONFIG_PARTITION_ADVANCED=y CONFIG_DEBUG_KERNEL=y CONFIG_DETECT_HUNG_TASK=y -# CONFIG_DEBUG_BUGVERBOSE is not set # CONFIG_RCU_CPU_STALL_DETECTOR is not set CONFIG_SYSCTL_SYSCALL_CHECK=y CONFIG_CRYPTO_PCBC=m diff --git a/arch/powerpc/configs/85xx/mpc8540_ads_defconfig b/arch/powerpc/configs/85xx/mpc8540_ads_defconfig index 55e0725..11662c2 100644 --- a/arch/powerpc/configs/85xx/mpc8540_ads_defconfig +++ b/arch/powerpc/configs/85xx/mpc8540_ads_defconfig @@ -58,7 +58,6 @@ CONFIG_PARTITION_ADVANCED=y CONFIG_DEBUG_KERNEL=y CONFIG_DETECT_HUNG_TASK=y CONFIG_DEBUG_MUTEXES=y -# CONFIG_DEBUG_BUGVERBOSE is not set # CONFIG_RCU_CPU_STALL_DETECTOR is not set CONFIG_SYSCTL_SYSCALL_CHECK=y # CONFIG_CRYPTO_ANSI_CPRNG is not set diff --git a/arch/powerpc/configs/85xx/mpc8560_ads_defconfig b/arch/powerpc/configs/85xx/mpc8560_ads_defconfig index d724095..ebe9b30 100644 --- a/arch/powerpc/configs/85xx/mpc8560_ads_defconfig +++ b/arch/powerpc/configs/85xx/mpc8560_ads_defconfig @@ -59,7 +59,6 @@ CONFIG_PARTITION_ADVANCED=y CONFIG_DEBUG_KERNEL=y CONFIG_DETECT_HUNG_TASK=y CONFIG_DEBUG_MUTEXES=y -# CONFIG_DEBUG_BUGVERBOSE is not set # CONFIG_RCU_CPU_STALL_DETECTOR is not set CONFIG_SYSCTL_SYSCALL_CHECK=y # CONFIG_CRYPTO_ANSI_CPRNG is not set diff --git a/arch/powerpc/configs/85xx/mpc85xx_cds_defconfig b/arch/powerpc/configs/85xx/mpc85xx_cds_defconfig index 4b44bea..eb25229 100644 --- a/arch/powerpc/configs/85xx/mpc85xx_cds_defconfig +++ b/arch/powerpc/configs/85xx/mpc85xx_cds_defconfig @@ -63,7 +63,6 @@ CONFIG_PARTITION_ADVANCED=y CONFIG_DEBUG_KERNEL=y CONFIG_DETECT_HUNG_TASK=y CONFIG_DEBUG_MUTEXES=y -# CONFIG_DEBUG_BUGVERBOSE is not set # CONFIG_RCU_CPU_STALL_DETECTOR is not set CONFIG_SYSCTL_SYSCALL_CHECK=y # CONFIG_CRYPTO_ANSI_CPRNG is not set diff --git a/arch/powerpc/configs/86xx/mpc8641_hpcn_defconfig b/arch/powerpc/configs/86xx/mpc8641_hpcn_defconfig index b614508d..f51c7eb 100644 --- a/arch/powerpc/configs/86xx/mpc8641_hpcn_defconfig +++ b/arch/powerpc/configs/86xx/mpc8641_hpcn_defconfig @@ -168,7 +168,6 @@ CONFIG_MAC_PARTITION=y CONFIG_CRC_T10DIF=y CONFIG_DEBUG_KERNEL=y CONFIG_DETECT_HUNG_TASK=y -# CONFIG_DEBUG_BUGVERBOSE is not set CONFIG_DEBUG_INFO=y # CONFIG_RCU_CPU_STALL_DETECTOR is not set CONFIG_SYSCTL_SYSCALL_CHECK=y diff --git a/arch/powerpc/configs/e55xx_smp_defconfig b/arch/powerpc/configs/e55xx_smp_defconfig index f4c5780..d322835 100644 --- a/arch/powerpc/configs/e55xx_smp_defconfig +++ b/arch/powerpc/configs/e55xx_smp_defconfig @@ -95,7 +95,6 @@ CONFIG_FRAME_WARN=1024 CONFIG_DEBUG_FS=y CONFIG_DEBUG_KERNEL=y CONFIG_DETECT_HUNG_TASK=y -# CONFIG_DEBUG_BUGVERBOSE is not set CONFIG_DEBUG_INFO=y # CONFIG_RCU_CPU_STALL_DETECTOR is not set CONFIG_SYSCTL_SYSCALL_CHECK=y diff --git a/arch/powerpc/configs/mpc85xx_defconfig b/arch/powerpc/configs/mpc85xx_defconfig index c06a86c..96b89df 100644 --- a/arch/powerpc/configs/mpc85xx_defconfig +++ b/arch/powerpc/configs/mpc85xx_defconfig @@ -204,7 +204,6 @@ CONFIG_CRC_T10DIF=y CONFIG_DEBUG_FS=y CONFIG_DEBUG_KERNEL=y CONFIG_DETECT_HUNG_TASK=y -# CONFIG_DEBUG_BUGVERBOSE is not set CONFIG_DEBUG_INFO=y # CONFIG_RCU_CPU_STALL_DETECTOR is not set CONFIG_SYSCTL_SYSCALL_CHECK=y diff --git a/arch/powerpc/configs/mpc85xx_smp_defconfig b/arch/powerpc/configs/mpc85xx_smp_defconfig index 942ced9..de65841 100644 --- a/arch/powerpc/configs/mpc85xx_smp_defconfig +++ b/arch/powerpc/configs/mpc85xx_smp_defconfig @@ -206,7 +206,6 @@ CONFIG_CRC_T10DIF=y CONFIG_DEBUG_FS=y CONFIG_DEBUG_KERNEL=y CONFIG_DETECT_HUNG_TASK=y -# CONFIG_DEBUG_BUGVERBOSE is not set CONFIG_DEBUG_INFO=y # CONFIG_RCU_CPU_STALL_DETECTOR is not set CONFIG_SYSCTL_SYSCALL_CHECK=y diff --git a/arch/powerpc/configs/mpc86xx_defconfig b/arch/powerpc/configs/mpc86xx_defconfig index 038a308..a1cc817 100644 --- a/arch/powerpc/configs/mpc86xx_defconfig +++ b/arch/powerpc/configs/mpc86xx_defconfig @@ -171,7 +171,6 @@ CONFIG_MAC_PARTITION=y CONFIG_CRC_T10DIF=y CONFIG_DEBUG_KERNEL=y CONFIG_DETECT_HUNG_TASK=y -# CONFIG_DEBUG_BUGVERBOSE is not set CONFIG_DEBUG_INFO=y # CONFIG_RCU_CPU_STALL_DETECTOR is not set CONFIG_SYSCTL_SYSCALL_CHECK=y -- cgit v0.10.2 From 9c817f183b8e02e418d3d5396a16879dc11f921d Mon Sep 17 00:00:00 2001 From: Bhaskar Upadhaya Date: Tue, 19 Apr 2011 19:28:31 +0530 Subject: powerpc: Adding bindings for flexcan controller Signed-off-by: Bhaskar Upadhaya Acked-By: Scott Wood Signed-off-by: Kumar Gala diff --git a/Documentation/devicetree/bindings/net/can/fsl-flexcan.txt b/Documentation/devicetree/bindings/net/can/fsl-flexcan.txt new file mode 100755 index 0000000..1a729f0 --- /dev/null +++ b/Documentation/devicetree/bindings/net/can/fsl-flexcan.txt @@ -0,0 +1,61 @@ +CAN Device Tree Bindings +------------------------ +2011 Freescale Semiconductor, Inc. + +fsl,flexcan-v1.0 nodes +----------------------- +In addition to the required compatible-, reg- and interrupt-properties, you can +also specify which clock source shall be used for the controller. + +CPI Clock- Can Protocol Interface Clock + This CLK_SRC bit of CTRL(control register) selects the clock source to + the CAN Protocol Interface(CPI) to be either the peripheral clock + (driven by the PLL) or the crystal oscillator clock. The selected clock + is the one fed to the prescaler to generate the Serial Clock (Sclock). + The PRESDIV field of CTRL(control register) controls a prescaler that + generates the Serial Clock (Sclock), whose period defines the + time quantum used to compose the CAN waveform. + +Can Engine Clock Source + There are two sources for CAN clock + - Platform Clock It represents the bus clock + - Oscillator Clock + + Peripheral Clock (PLL) + -------------- + | + --------- ------------- + | |CPI Clock | Prescaler | Sclock + | |---------------->| (1.. 256) |------------> + --------- ------------- + | | + -------------- ---------------------CLK_SRC + Oscillator Clock + +- fsl,flexcan-clock-source : CAN Engine Clock Source.This property selects + the peripheral clock. PLL clock is fed to the + prescaler to generate the Serial Clock (Sclock). + Valid values are "oscillator" and "platform" + "oscillator": CAN engine clock source is oscillator clock. + "platform" The CAN engine clock source is the bus clock + (platform clock). + +- fsl,flexcan-clock-divider : for the reference and system clock, an additional + clock divider can be specified. +- clock-frequency: frequency required to calculate the bitrate for FlexCAN. + +Note: + - v1.0 of flexcan-v1.0 represent the IP block version for P1010 SOC. + - P1010 does not have oscillator as the Clock Source.So the default + Clock Source is platform clock. +Examples: + + can0@1c000 { + compatible = "fsl,flexcan-v1.0"; + reg = <0x1c000 0x1000>; + interrupts = <48 0x2>; + interrupt-parent = <&mpic>; + fsl,flexcan-clock-source = "platform"; + fsl,flexcan-clock-divider = <2>; + clock-frequency = ; + }; -- cgit v0.10.2 From b6e4df4dab86e3cd2475748c49aac16dadb8330e Mon Sep 17 00:00:00 2001 From: Prabhakar Kushwaha Date: Thu, 7 Apr 2011 14:40:55 +0530 Subject: powerpc/85xx: P1020 DTS : re-organize dts files Creates P1020si.dtsi, containing information for the P1020 SoC. Modifies dts files for P1020 based systems to use dtsi file Signed-off-by: Prabhakar Kushwaha Acked-by: Grant Likely Signed-off-by: Kumar Gala diff --git a/arch/powerpc/boot/dts/p1020rdb.dts b/arch/powerpc/boot/dts/p1020rdb.dts index e0668f8..7ed4793 100644 --- a/arch/powerpc/boot/dts/p1020rdb.dts +++ b/arch/powerpc/boot/dts/p1020rdb.dts @@ -9,12 +9,11 @@ * option) any later version. */ -/dts-v1/; +/include/ "p1020si.dtsi" + / { - model = "fsl,P1020"; + model = "fsl,P1020RDB"; compatible = "fsl,P1020RDB"; - #address-cells = <2>; - #size-cells = <2>; aliases { serial0 = &serial0; @@ -26,34 +25,11 @@ pci1 = &pci1; }; - cpus { - #address-cells = <1>; - #size-cells = <0>; - - PowerPC,P1020@0 { - device_type = "cpu"; - reg = <0x0>; - next-level-cache = <&L2>; - }; - - PowerPC,P1020@1 { - device_type = "cpu"; - reg = <0x1>; - next-level-cache = <&L2>; - }; - }; - memory { device_type = "memory"; }; localbus@ffe05000 { - #address-cells = <2>; - #size-cells = <1>; - compatible = "fsl,p1020-elbc", "fsl,elbc", "simple-bus"; - reg = <0 0xffe05000 0 0x1000>; - interrupts = <19 2>; - interrupt-parent = <&mpic>; /* NOR, NAND Flashes and Vitesse 5 port L2 switch */ ranges = <0x0 0x0 0x0 0xef000000 0x01000000 @@ -165,88 +141,14 @@ }; soc@ffe00000 { - #address-cells = <1>; - #size-cells = <1>; - device_type = "soc"; - compatible = "fsl,p1020-immr", "simple-bus"; - ranges = <0x0 0x0 0xffe00000 0x100000>; - bus-frequency = <0>; // Filled out by uboot. - - ecm-law@0 { - compatible = "fsl,ecm-law"; - reg = <0x0 0x1000>; - fsl,num-laws = <12>; - }; - - ecm@1000 { - compatible = "fsl,p1020-ecm", "fsl,ecm"; - reg = <0x1000 0x1000>; - interrupts = <16 2>; - interrupt-parent = <&mpic>; - }; - - memory-controller@2000 { - compatible = "fsl,p1020-memory-controller"; - reg = <0x2000 0x1000>; - interrupt-parent = <&mpic>; - interrupts = <16 2>; - }; - i2c@3000 { - #address-cells = <1>; - #size-cells = <0>; - cell-index = <0>; - compatible = "fsl-i2c"; - reg = <0x3000 0x100>; - interrupts = <43 2>; - interrupt-parent = <&mpic>; - dfsrr; rtc@68 { compatible = "dallas,ds1339"; reg = <0x68>; }; }; - i2c@3100 { - #address-cells = <1>; - #size-cells = <0>; - cell-index = <1>; - compatible = "fsl-i2c"; - reg = <0x3100 0x100>; - interrupts = <43 2>; - interrupt-parent = <&mpic>; - dfsrr; - }; - - serial0: serial@4500 { - cell-index = <0>; - device_type = "serial"; - compatible = "ns16550"; - reg = <0x4500 0x100>; - clock-frequency = <0>; - interrupts = <42 2>; - interrupt-parent = <&mpic>; - }; - - serial1: serial@4600 { - cell-index = <1>; - device_type = "serial"; - compatible = "ns16550"; - reg = <0x4600 0x100>; - clock-frequency = <0>; - interrupts = <42 2>; - interrupt-parent = <&mpic>; - }; - spi@7000 { - cell-index = <0>; - #address-cells = <1>; - #size-cells = <0>; - compatible = "fsl,espi"; - reg = <0x7000 0x1000>; - interrupts = <59 0x2>; - interrupt-parent = <&mpic>; - mode = "cpu"; fsl_m25p80@0 { #address-cells = <1>; @@ -294,66 +196,7 @@ }; }; - gpio: gpio-controller@f000 { - #gpio-cells = <2>; - compatible = "fsl,mpc8572-gpio"; - reg = <0xf000 0x100>; - interrupts = <47 0x2>; - interrupt-parent = <&mpic>; - gpio-controller; - }; - - L2: l2-cache-controller@20000 { - compatible = "fsl,p1020-l2-cache-controller"; - reg = <0x20000 0x1000>; - cache-line-size = <32>; // 32 bytes - cache-size = <0x40000>; // L2,256K - interrupt-parent = <&mpic>; - interrupts = <16 2>; - }; - - dma@21300 { - #address-cells = <1>; - #size-cells = <1>; - compatible = "fsl,eloplus-dma"; - reg = <0x21300 0x4>; - ranges = <0x0 0x21100 0x200>; - cell-index = <0>; - dma-channel@0 { - compatible = "fsl,eloplus-dma-channel"; - reg = <0x0 0x80>; - cell-index = <0>; - interrupt-parent = <&mpic>; - interrupts = <20 2>; - }; - dma-channel@80 { - compatible = "fsl,eloplus-dma-channel"; - reg = <0x80 0x80>; - cell-index = <1>; - interrupt-parent = <&mpic>; - interrupts = <21 2>; - }; - dma-channel@100 { - compatible = "fsl,eloplus-dma-channel"; - reg = <0x100 0x80>; - cell-index = <2>; - interrupt-parent = <&mpic>; - interrupts = <22 2>; - }; - dma-channel@180 { - compatible = "fsl,eloplus-dma-channel"; - reg = <0x180 0x80>; - cell-index = <3>; - interrupt-parent = <&mpic>; - interrupts = <23 2>; - }; - }; - mdio@24000 { - #address-cells = <1>; - #size-cells = <0>; - compatible = "fsl,etsec2-mdio"; - reg = <0x24000 0x1000 0xb0030 0x4>; phy0: ethernet-phy@0 { interrupt-parent = <&mpic>; @@ -369,10 +212,6 @@ }; mdio@25000 { - #address-cells = <1>; - #size-cells = <0>; - compatible = "fsl,etsec2-tbi"; - reg = <0x25000 0x1000 0xb1030 0x4>; tbi0: tbi-phy@11 { reg = <0x11>; @@ -381,97 +220,25 @@ }; enet0: ethernet@b0000 { - #address-cells = <1>; - #size-cells = <1>; - device_type = "network"; - model = "eTSEC"; - compatible = "fsl,etsec2"; - fsl,num_rx_queues = <0x8>; - fsl,num_tx_queues = <0x8>; - local-mac-address = [ 00 00 00 00 00 00 ]; - interrupt-parent = <&mpic>; fixed-link = <1 1 1000 0 0>; phy-connection-type = "rgmii-id"; - queue-group@0 { - #address-cells = <1>; - #size-cells = <1>; - reg = <0xb0000 0x1000>; - interrupts = <29 2 30 2 34 2>; - }; - - queue-group@1 { - #address-cells = <1>; - #size-cells = <1>; - reg = <0xb4000 0x1000>; - interrupts = <17 2 18 2 24 2>; - }; }; enet1: ethernet@b1000 { - #address-cells = <1>; - #size-cells = <1>; - device_type = "network"; - model = "eTSEC"; - compatible = "fsl,etsec2"; - fsl,num_rx_queues = <0x8>; - fsl,num_tx_queues = <0x8>; - local-mac-address = [ 00 00 00 00 00 00 ]; - interrupt-parent = <&mpic>; phy-handle = <&phy0>; tbi-handle = <&tbi0>; phy-connection-type = "sgmii"; - queue-group@0 { - #address-cells = <1>; - #size-cells = <1>; - reg = <0xb1000 0x1000>; - interrupts = <35 2 36 2 40 2>; - }; - - queue-group@1 { - #address-cells = <1>; - #size-cells = <1>; - reg = <0xb5000 0x1000>; - interrupts = <51 2 52 2 67 2>; - }; }; enet2: ethernet@b2000 { - #address-cells = <1>; - #size-cells = <1>; - device_type = "network"; - model = "eTSEC"; - compatible = "fsl,etsec2"; - fsl,num_rx_queues = <0x8>; - fsl,num_tx_queues = <0x8>; - local-mac-address = [ 00 00 00 00 00 00 ]; - interrupt-parent = <&mpic>; phy-handle = <&phy1>; phy-connection-type = "rgmii-id"; - queue-group@0 { - #address-cells = <1>; - #size-cells = <1>; - reg = <0xb2000 0x1000>; - interrupts = <31 2 32 2 33 2>; - }; - - queue-group@1 { - #address-cells = <1>; - #size-cells = <1>; - reg = <0xb6000 0x1000>; - interrupts = <25 2 26 2 27 2>; - }; }; usb@22000 { - #address-cells = <1>; - #size-cells = <0>; - compatible = "fsl-usb2-dr"; - reg = <0x22000 0x1000>; - interrupt-parent = <&mpic>; - interrupts = <28 0x2>; phy_type = "ulpi"; }; @@ -481,82 +248,15 @@ it enables USB2. OTOH, U-Boot does create a new node when there isn't any. So, just comment it out. usb@23000 { - #address-cells = <1>; - #size-cells = <0>; - compatible = "fsl-usb2-dr"; - reg = <0x23000 0x1000>; - interrupt-parent = <&mpic>; - interrupts = <46 0x2>; phy_type = "ulpi"; }; */ - sdhci@2e000 { - compatible = "fsl,p1020-esdhc", "fsl,esdhc"; - reg = <0x2e000 0x1000>; - interrupts = <72 0x2>; - interrupt-parent = <&mpic>; - /* Filled in by U-Boot */ - clock-frequency = <0>; - }; - - crypto@30000 { - compatible = "fsl,sec3.1", "fsl,sec3.0", "fsl,sec2.4", - "fsl,sec2.2", "fsl,sec2.1", "fsl,sec2.0"; - reg = <0x30000 0x10000>; - interrupts = <45 2 58 2>; - interrupt-parent = <&mpic>; - fsl,num-channels = <4>; - fsl,channel-fifo-len = <24>; - fsl,exec-units-mask = <0xbfe>; - fsl,descriptor-types-mask = <0x3ab0ebf>; - }; - - mpic: pic@40000 { - interrupt-controller; - #address-cells = <0>; - #interrupt-cells = <2>; - reg = <0x40000 0x40000>; - compatible = "chrp,open-pic"; - device_type = "open-pic"; - }; - - msi@41600 { - compatible = "fsl,p1020-msi", "fsl,mpic-msi"; - reg = <0x41600 0x80>; - msi-available-ranges = <0 0x100>; - interrupts = < - 0xe0 0 - 0xe1 0 - 0xe2 0 - 0xe3 0 - 0xe4 0 - 0xe5 0 - 0xe6 0 - 0xe7 0>; - interrupt-parent = <&mpic>; - }; - - global-utilities@e0000 { //global utilities block - compatible = "fsl,p1020-guts"; - reg = <0xe0000 0x1000>; - fsl,has-rstcr; - }; }; pci0: pcie@ffe09000 { - compatible = "fsl,mpc8548-pcie"; - device_type = "pci"; - #interrupt-cells = <1>; - #size-cells = <2>; - #address-cells = <3>; - reg = <0 0xffe09000 0 0x1000>; - bus-range = <0 255>; ranges = <0x2000000 0x0 0xa0000000 0 0xa0000000 0x0 0x20000000 0x1000000 0x0 0x00000000 0 0xffc10000 0x0 0x10000>; - clock-frequency = <33333333>; - interrupt-parent = <&mpic>; - interrupts = <16 2>; pcie@0 { reg = <0x0 0x0 0x0 0x0 0x0>; #size-cells = <2>; @@ -573,18 +273,8 @@ }; pci1: pcie@ffe0a000 { - compatible = "fsl,mpc8548-pcie"; - device_type = "pci"; - #interrupt-cells = <1>; - #size-cells = <2>; - #address-cells = <3>; - reg = <0 0xffe0a000 0 0x1000>; - bus-range = <0 255>; ranges = <0x2000000 0x0 0x80000000 0 0x80000000 0x0 0x20000000 0x1000000 0x0 0x00000000 0 0xffc00000 0x0 0x10000>; - clock-frequency = <33333333>; - interrupt-parent = <&mpic>; - interrupts = <16 2>; pcie@0 { reg = <0x0 0x0 0x0 0x0 0x0>; #size-cells = <2>; diff --git a/arch/powerpc/boot/dts/p1020si.dtsi b/arch/powerpc/boot/dts/p1020si.dtsi new file mode 100644 index 0000000..f6f1100 --- /dev/null +++ b/arch/powerpc/boot/dts/p1020si.dtsi @@ -0,0 +1,377 @@ +/* + * P1020si Device Tree Source + * + * Copyright 2011 Freescale Semiconductor Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ + +/dts-v1/; +/ { + compatible = "fsl,P1020"; + #address-cells = <2>; + #size-cells = <2>; + + cpus { + #address-cells = <1>; + #size-cells = <0>; + + PowerPC,P1020@0 { + device_type = "cpu"; + reg = <0x0>; + next-level-cache = <&L2>; + }; + + PowerPC,P1020@1 { + device_type = "cpu"; + reg = <0x1>; + next-level-cache = <&L2>; + }; + }; + + localbus@ffe05000 { + #address-cells = <2>; + #size-cells = <1>; + compatible = "fsl,p1020-elbc", "fsl,elbc", "simple-bus"; + reg = <0 0xffe05000 0 0x1000>; + interrupts = <19 2>; + interrupt-parent = <&mpic>; + }; + + soc@ffe00000 { + #address-cells = <1>; + #size-cells = <1>; + device_type = "soc"; + compatible = "fsl,p1020-immr", "simple-bus"; + ranges = <0x0 0x0 0xffe00000 0x100000>; + bus-frequency = <0>; // Filled out by uboot. + + ecm-law@0 { + compatible = "fsl,ecm-law"; + reg = <0x0 0x1000>; + fsl,num-laws = <12>; + }; + + ecm@1000 { + compatible = "fsl,p1020-ecm", "fsl,ecm"; + reg = <0x1000 0x1000>; + interrupts = <16 2>; + interrupt-parent = <&mpic>; + }; + + memory-controller@2000 { + compatible = "fsl,p1020-memory-controller"; + reg = <0x2000 0x1000>; + interrupt-parent = <&mpic>; + interrupts = <16 2>; + }; + + i2c@3000 { + #address-cells = <1>; + #size-cells = <0>; + cell-index = <0>; + compatible = "fsl-i2c"; + reg = <0x3000 0x100>; + interrupts = <43 2>; + interrupt-parent = <&mpic>; + dfsrr; + }; + + i2c@3100 { + #address-cells = <1>; + #size-cells = <0>; + cell-index = <1>; + compatible = "fsl-i2c"; + reg = <0x3100 0x100>; + interrupts = <43 2>; + interrupt-parent = <&mpic>; + dfsrr; + }; + + serial0: serial@4500 { + cell-index = <0>; + device_type = "serial"; + compatible = "ns16550"; + reg = <0x4500 0x100>; + clock-frequency = <0>; + interrupts = <42 2>; + interrupt-parent = <&mpic>; + }; + + serial1: serial@4600 { + cell-index = <1>; + device_type = "serial"; + compatible = "ns16550"; + reg = <0x4600 0x100>; + clock-frequency = <0>; + interrupts = <42 2>; + interrupt-parent = <&mpic>; + }; + + spi@7000 { + cell-index = <0>; + #address-cells = <1>; + #size-cells = <0>; + compatible = "fsl,espi"; + reg = <0x7000 0x1000>; + interrupts = <59 0x2>; + interrupt-parent = <&mpic>; + mode = "cpu"; + }; + + gpio: gpio-controller@f000 { + #gpio-cells = <2>; + compatible = "fsl,mpc8572-gpio"; + reg = <0xf000 0x100>; + interrupts = <47 0x2>; + interrupt-parent = <&mpic>; + gpio-controller; + }; + + L2: l2-cache-controller@20000 { + compatible = "fsl,p1020-l2-cache-controller"; + reg = <0x20000 0x1000>; + cache-line-size = <32>; // 32 bytes + cache-size = <0x40000>; // L2,256K + interrupt-parent = <&mpic>; + interrupts = <16 2>; + }; + + dma@21300 { + #address-cells = <1>; + #size-cells = <1>; + compatible = "fsl,eloplus-dma"; + reg = <0x21300 0x4>; + ranges = <0x0 0x21100 0x200>; + cell-index = <0>; + dma-channel@0 { + compatible = "fsl,eloplus-dma-channel"; + reg = <0x0 0x80>; + cell-index = <0>; + interrupt-parent = <&mpic>; + interrupts = <20 2>; + }; + dma-channel@80 { + compatible = "fsl,eloplus-dma-channel"; + reg = <0x80 0x80>; + cell-index = <1>; + interrupt-parent = <&mpic>; + interrupts = <21 2>; + }; + dma-channel@100 { + compatible = "fsl,eloplus-dma-channel"; + reg = <0x100 0x80>; + cell-index = <2>; + interrupt-parent = <&mpic>; + interrupts = <22 2>; + }; + dma-channel@180 { + compatible = "fsl,eloplus-dma-channel"; + reg = <0x180 0x80>; + cell-index = <3>; + interrupt-parent = <&mpic>; + interrupts = <23 2>; + }; + }; + + mdio@24000 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "fsl,etsec2-mdio"; + reg = <0x24000 0x1000 0xb0030 0x4>; + + }; + + mdio@25000 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "fsl,etsec2-tbi"; + reg = <0x25000 0x1000 0xb1030 0x4>; + + }; + + enet0: ethernet@b0000 { + #address-cells = <1>; + #size-cells = <1>; + device_type = "network"; + model = "eTSEC"; + compatible = "fsl,etsec2"; + fsl,num_rx_queues = <0x8>; + fsl,num_tx_queues = <0x8>; + local-mac-address = [ 00 00 00 00 00 00 ]; + interrupt-parent = <&mpic>; + + queue-group@0 { + #address-cells = <1>; + #size-cells = <1>; + reg = <0xb0000 0x1000>; + interrupts = <29 2 30 2 34 2>; + }; + + queue-group@1 { + #address-cells = <1>; + #size-cells = <1>; + reg = <0xb4000 0x1000>; + interrupts = <17 2 18 2 24 2>; + }; + }; + + enet1: ethernet@b1000 { + #address-cells = <1>; + #size-cells = <1>; + device_type = "network"; + model = "eTSEC"; + compatible = "fsl,etsec2"; + fsl,num_rx_queues = <0x8>; + fsl,num_tx_queues = <0x8>; + local-mac-address = [ 00 00 00 00 00 00 ]; + interrupt-parent = <&mpic>; + + queue-group@0 { + #address-cells = <1>; + #size-cells = <1>; + reg = <0xb1000 0x1000>; + interrupts = <35 2 36 2 40 2>; + }; + + queue-group@1 { + #address-cells = <1>; + #size-cells = <1>; + reg = <0xb5000 0x1000>; + interrupts = <51 2 52 2 67 2>; + }; + }; + + enet2: ethernet@b2000 { + #address-cells = <1>; + #size-cells = <1>; + device_type = "network"; + model = "eTSEC"; + compatible = "fsl,etsec2"; + fsl,num_rx_queues = <0x8>; + fsl,num_tx_queues = <0x8>; + local-mac-address = [ 00 00 00 00 00 00 ]; + interrupt-parent = <&mpic>; + + queue-group@0 { + #address-cells = <1>; + #size-cells = <1>; + reg = <0xb2000 0x1000>; + interrupts = <31 2 32 2 33 2>; + }; + + queue-group@1 { + #address-cells = <1>; + #size-cells = <1>; + reg = <0xb6000 0x1000>; + interrupts = <25 2 26 2 27 2>; + }; + }; + + usb@22000 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "fsl-usb2-dr"; + reg = <0x22000 0x1000>; + interrupt-parent = <&mpic>; + interrupts = <28 0x2>; + }; + + /* USB2 is shared with localbus, so it must be disabled + by default. We can't put 'status = "disabled";' here + since U-Boot doesn't clear the status property when + it enables USB2. OTOH, U-Boot does create a new node + when there isn't any. So, just comment it out. + usb@23000 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "fsl-usb2-dr"; + reg = <0x23000 0x1000>; + interrupt-parent = <&mpic>; + interrupts = <46 0x2>; + phy_type = "ulpi"; + }; + */ + + sdhci@2e000 { + compatible = "fsl,p1020-esdhc", "fsl,esdhc"; + reg = <0x2e000 0x1000>; + interrupts = <72 0x2>; + interrupt-parent = <&mpic>; + /* Filled in by U-Boot */ + clock-frequency = <0>; + }; + + crypto@30000 { + compatible = "fsl,sec3.1", "fsl,sec3.0", "fsl,sec2.4", + "fsl,sec2.2", "fsl,sec2.1", "fsl,sec2.0"; + reg = <0x30000 0x10000>; + interrupts = <45 2 58 2>; + interrupt-parent = <&mpic>; + fsl,num-channels = <4>; + fsl,channel-fifo-len = <24>; + fsl,exec-units-mask = <0xbfe>; + fsl,descriptor-types-mask = <0x3ab0ebf>; + }; + + mpic: pic@40000 { + interrupt-controller; + #address-cells = <0>; + #interrupt-cells = <2>; + reg = <0x40000 0x40000>; + compatible = "chrp,open-pic"; + device_type = "open-pic"; + }; + + msi@41600 { + compatible = "fsl,p1020-msi", "fsl,mpic-msi"; + reg = <0x41600 0x80>; + msi-available-ranges = <0 0x100>; + interrupts = < + 0xe0 0 + 0xe1 0 + 0xe2 0 + 0xe3 0 + 0xe4 0 + 0xe5 0 + 0xe6 0 + 0xe7 0>; + interrupt-parent = <&mpic>; + }; + + global-utilities@e0000 { //global utilities block + compatible = "fsl,p1020-guts"; + reg = <0xe0000 0x1000>; + fsl,has-rstcr; + }; + }; + + pci0: pcie@ffe09000 { + compatible = "fsl,mpc8548-pcie"; + device_type = "pci"; + #interrupt-cells = <1>; + #size-cells = <2>; + #address-cells = <3>; + reg = <0 0xffe09000 0 0x1000>; + bus-range = <0 255>; + clock-frequency = <33333333>; + interrupt-parent = <&mpic>; + interrupts = <16 2>; + }; + + pci1: pcie@ffe0a000 { + compatible = "fsl,mpc8548-pcie"; + device_type = "pci"; + #interrupt-cells = <1>; + #size-cells = <2>; + #address-cells = <3>; + reg = <0 0xffe0a000 0 0x1000>; + bus-range = <0 255>; + clock-frequency = <33333333>; + interrupt-parent = <&mpic>; + interrupts = <16 2>; + }; +}; -- cgit v0.10.2 From eb2c5d9965adec2d7cd1946fa39f2dece073dab7 Mon Sep 17 00:00:00 2001 From: Prabhakar Kushwaha Date: Fri, 8 Apr 2011 17:57:05 +0530 Subject: powerpc/85xx: P2020 DTS: re-organize dts files Creates P2020si.dtsi, containing information for P2020 SoC. Modifies dts files for P2020 based systems to use dtsi file. Signed-off-by: Prabhakar Kushwaha Signed-off-by: Kumar Gala diff --git a/arch/powerpc/boot/dts/p2020ds.dts b/arch/powerpc/boot/dts/p2020ds.dts index 1101914..2bcf368 100644 --- a/arch/powerpc/boot/dts/p2020ds.dts +++ b/arch/powerpc/boot/dts/p2020ds.dts @@ -1,7 +1,7 @@ /* * P2020 DS Device Tree Source * - * Copyright 2009 Freescale Semiconductor Inc. + * Copyright 2009-2011 Freescale Semiconductor Inc. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the @@ -9,12 +9,11 @@ * option) any later version. */ -/dts-v1/; +/include/ "p2020si.dtsi" + / { - model = "fsl,P2020"; + model = "fsl,P2020DS"; compatible = "fsl,P2020DS"; - #address-cells = <2>; - #size-cells = <2>; aliases { ethernet0 = &enet0; @@ -27,35 +26,13 @@ pci2 = &pci2; }; - cpus { - #address-cells = <1>; - #size-cells = <0>; - - PowerPC,P2020@0 { - device_type = "cpu"; - reg = <0x0>; - next-level-cache = <&L2>; - }; - - PowerPC,P2020@1 { - device_type = "cpu"; - reg = <0x1>; - next-level-cache = <&L2>; - }; - }; memory { device_type = "memory"; }; localbus@ffe05000 { - #address-cells = <2>; - #size-cells = <1>; compatible = "fsl,elbc", "simple-bus"; - reg = <0 0xffe05000 0 0x1000>; - interrupts = <19 2>; - interrupt-parent = <&mpic>; - ranges = <0x0 0x0 0x0 0xe8000000 0x08000000 0x1 0x0 0x0 0xe0000000 0x08000000 0x2 0x0 0x0 0xffa00000 0x00040000 @@ -158,352 +135,77 @@ }; soc@ffe00000 { - #address-cells = <1>; - #size-cells = <1>; - device_type = "soc"; - compatible = "fsl,p2020-immr", "simple-bus"; - ranges = <0x0 0 0xffe00000 0x100000>; - bus-frequency = <0>; // Filled out by uboot. - - ecm-law@0 { - compatible = "fsl,ecm-law"; - reg = <0x0 0x1000>; - fsl,num-laws = <12>; - }; - - ecm@1000 { - compatible = "fsl,p2020-ecm", "fsl,ecm"; - reg = <0x1000 0x1000>; - interrupts = <17 2>; - interrupt-parent = <&mpic>; - }; - - memory-controller@2000 { - compatible = "fsl,p2020-memory-controller"; - reg = <0x2000 0x1000>; - interrupt-parent = <&mpic>; - interrupts = <18 2>; - }; - - i2c@3000 { - #address-cells = <1>; - #size-cells = <0>; - cell-index = <0>; - compatible = "fsl-i2c"; - reg = <0x3000 0x100>; - interrupts = <43 2>; - interrupt-parent = <&mpic>; - dfsrr; - }; - - i2c@3100 { - #address-cells = <1>; - #size-cells = <0>; - cell-index = <1>; - compatible = "fsl-i2c"; - reg = <0x3100 0x100>; - interrupts = <43 2>; - interrupt-parent = <&mpic>; - dfsrr; - }; - serial0: serial@4500 { - cell-index = <0>; - device_type = "serial"; - compatible = "ns16550"; - reg = <0x4500 0x100>; - clock-frequency = <0>; - interrupts = <42 2>; - interrupt-parent = <&mpic>; - }; - - serial1: serial@4600 { - cell-index = <1>; - device_type = "serial"; - compatible = "ns16550"; - reg = <0x4600 0x100>; - clock-frequency = <0>; - interrupts = <42 2>; - interrupt-parent = <&mpic>; - }; - - spi@7000 { - compatible = "fsl,espi"; - reg = <0x7000 0x1000>; - interrupts = <59 0x2>; - interrupt-parent = <&mpic>; + usb@22000 { + phy_type = "ulpi"; }; - dma@c300 { - #address-cells = <1>; - #size-cells = <1>; - compatible = "fsl,eloplus-dma"; - reg = <0xc300 0x4>; - ranges = <0x0 0xc100 0x200>; - cell-index = <1>; - dma-channel@0 { - compatible = "fsl,eloplus-dma-channel"; - reg = <0x0 0x80>; - cell-index = <0>; + mdio@24520 { + phy0: ethernet-phy@0 { interrupt-parent = <&mpic>; - interrupts = <76 2>; + interrupts = <3 1>; + reg = <0x0>; }; - dma-channel@80 { - compatible = "fsl,eloplus-dma-channel"; - reg = <0x80 0x80>; - cell-index = <1>; + phy1: ethernet-phy@1 { interrupt-parent = <&mpic>; - interrupts = <77 2>; + interrupts = <3 1>; + reg = <0x1>; }; - dma-channel@100 { - compatible = "fsl,eloplus-dma-channel"; - reg = <0x100 0x80>; - cell-index = <2>; + phy2: ethernet-phy@2 { interrupt-parent = <&mpic>; - interrupts = <78 2>; + interrupts = <3 1>; + reg = <0x2>; }; - dma-channel@180 { - compatible = "fsl,eloplus-dma-channel"; - reg = <0x180 0x80>; - cell-index = <3>; - interrupt-parent = <&mpic>; - interrupts = <79 2>; + tbi0: tbi-phy@11 { + reg = <0x11>; + device_type = "tbi-phy"; }; - }; - gpio: gpio-controller@f000 { - #gpio-cells = <2>; - compatible = "fsl,mpc8572-gpio"; - reg = <0xf000 0x100>; - interrupts = <47 0x2>; - interrupt-parent = <&mpic>; - gpio-controller; }; - L2: l2-cache-controller@20000 { - compatible = "fsl,p2020-l2-cache-controller"; - reg = <0x20000 0x1000>; - cache-line-size = <32>; // 32 bytes - cache-size = <0x80000>; // L2, 512k - interrupt-parent = <&mpic>; - interrupts = <16 2>; + mdio@25520 { + tbi1: tbi-phy@11 { + reg = <0x11>; + device_type = "tbi-phy"; + }; }; - dma@21300 { - #address-cells = <1>; - #size-cells = <1>; - compatible = "fsl,eloplus-dma"; - reg = <0x21300 0x4>; - ranges = <0x0 0x21100 0x200>; - cell-index = <0>; - dma-channel@0 { - compatible = "fsl,eloplus-dma-channel"; - reg = <0x0 0x80>; - cell-index = <0>; - interrupt-parent = <&mpic>; - interrupts = <20 2>; - }; - dma-channel@80 { - compatible = "fsl,eloplus-dma-channel"; - reg = <0x80 0x80>; - cell-index = <1>; - interrupt-parent = <&mpic>; - interrupts = <21 2>; + mdio@26520 { + tbi2: tbi-phy@11 { + reg = <0x11>; + device_type = "tbi-phy"; }; - dma-channel@100 { - compatible = "fsl,eloplus-dma-channel"; - reg = <0x100 0x80>; - cell-index = <2>; - interrupt-parent = <&mpic>; - interrupts = <22 2>; - }; - dma-channel@180 { - compatible = "fsl,eloplus-dma-channel"; - reg = <0x180 0x80>; - cell-index = <3>; - interrupt-parent = <&mpic>; - interrupts = <23 2>; - }; - }; - usb@22000 { - #address-cells = <1>; - #size-cells = <0>; - compatible = "fsl-usb2-dr"; - reg = <0x22000 0x1000>; - interrupt-parent = <&mpic>; - interrupts = <28 0x2>; - phy_type = "ulpi"; }; enet0: ethernet@24000 { - #address-cells = <1>; - #size-cells = <1>; - cell-index = <0>; - device_type = "network"; - model = "eTSEC"; - compatible = "gianfar"; - reg = <0x24000 0x1000>; - ranges = <0x0 0x24000 0x1000>; - local-mac-address = [ 00 00 00 00 00 00 ]; - interrupts = <29 2 30 2 34 2>; - interrupt-parent = <&mpic>; tbi-handle = <&tbi0>; phy-handle = <&phy0>; phy-connection-type = "rgmii-id"; - - mdio@520 { - #address-cells = <1>; - #size-cells = <0>; - compatible = "fsl,gianfar-mdio"; - reg = <0x520 0x20>; - - phy0: ethernet-phy@0 { - interrupt-parent = <&mpic>; - interrupts = <3 1>; - reg = <0x0>; - }; - phy1: ethernet-phy@1 { - interrupt-parent = <&mpic>; - interrupts = <3 1>; - reg = <0x1>; - }; - phy2: ethernet-phy@2 { - interrupt-parent = <&mpic>; - interrupts = <3 1>; - reg = <0x2>; - }; - tbi0: tbi-phy@11 { - reg = <0x11>; - device_type = "tbi-phy"; - }; - }; }; enet1: ethernet@25000 { - #address-cells = <1>; - #size-cells = <1>; - cell-index = <1>; - device_type = "network"; - model = "eTSEC"; - compatible = "gianfar"; - reg = <0x25000 0x1000>; - ranges = <0x0 0x25000 0x1000>; - local-mac-address = [ 00 00 00 00 00 00 ]; - interrupts = <35 2 36 2 40 2>; - interrupt-parent = <&mpic>; tbi-handle = <&tbi1>; phy-handle = <&phy1>; phy-connection-type = "rgmii-id"; - mdio@520 { - #address-cells = <1>; - #size-cells = <0>; - compatible = "fsl,gianfar-tbi"; - reg = <0x520 0x20>; - - tbi1: tbi-phy@11 { - reg = <0x11>; - device_type = "tbi-phy"; - }; - }; }; enet2: ethernet@26000 { - #address-cells = <1>; - #size-cells = <1>; - cell-index = <2>; - device_type = "network"; - model = "eTSEC"; - compatible = "gianfar"; - reg = <0x26000 0x1000>; - ranges = <0x0 0x26000 0x1000>; - local-mac-address = [ 00 00 00 00 00 00 ]; - interrupts = <31 2 32 2 33 2>; - interrupt-parent = <&mpic>; tbi-handle = <&tbi2>; phy-handle = <&phy2>; phy-connection-type = "rgmii-id"; - - mdio@520 { - #address-cells = <1>; - #size-cells = <0>; - compatible = "fsl,gianfar-tbi"; - reg = <0x520 0x20>; - - tbi2: tbi-phy@11 { - reg = <0x11>; - device_type = "tbi-phy"; - }; - }; - }; - - sdhci@2e000 { - compatible = "fsl,p2020-esdhc", "fsl,esdhc"; - reg = <0x2e000 0x1000>; - interrupts = <72 0x2>; - interrupt-parent = <&mpic>; - /* Filled in by U-Boot */ - clock-frequency = <0>; - }; - - crypto@30000 { - compatible = "fsl,sec3.1", "fsl,sec3.0", "fsl,sec2.4", - "fsl,sec2.2", "fsl,sec2.1", "fsl,sec2.0"; - reg = <0x30000 0x10000>; - interrupts = <45 2 58 2>; - interrupt-parent = <&mpic>; - fsl,num-channels = <4>; - fsl,channel-fifo-len = <24>; - fsl,exec-units-mask = <0xbfe>; - fsl,descriptor-types-mask = <0x3ab0ebf>; }; - mpic: pic@40000 { - interrupt-controller; - #address-cells = <0>; - #interrupt-cells = <2>; - reg = <0x40000 0x40000>; - compatible = "chrp,open-pic"; - device_type = "open-pic"; - }; msi@41600 { compatible = "fsl,mpic-msi"; - reg = <0x41600 0x80>; - msi-available-ranges = <0 0x100>; - interrupts = < - 0xe0 0 - 0xe1 0 - 0xe2 0 - 0xe3 0 - 0xe4 0 - 0xe5 0 - 0xe6 0 - 0xe7 0>; - interrupt-parent = <&mpic>; - }; - - global-utilities@e0000 { //global utilities block - compatible = "fsl,p2020-guts"; - reg = <0xe0000 0x1000>; - fsl,has-rstcr; }; }; pci0: pcie@ffe08000 { - compatible = "fsl,mpc8548-pcie"; - device_type = "pci"; - #interrupt-cells = <1>; - #size-cells = <2>; - #address-cells = <3>; - reg = <0 0xffe08000 0 0x1000>; - bus-range = <0 255>; ranges = <0x2000000 0x0 0x80000000 0 0x80000000 0x0 0x20000000 0x1000000 0x0 0x00000000 0 0xffc00000 0x0 0x10000>; - clock-frequency = <33333333>; - interrupt-parent = <&mpic>; - interrupts = <24 2>; interrupt-map-mask = <0xf800 0x0 0x0 0x7>; interrupt-map = < /* IDSEL 0x0 */ @@ -528,18 +230,8 @@ }; pci1: pcie@ffe09000 { - compatible = "fsl,mpc8548-pcie"; - device_type = "pci"; - #interrupt-cells = <1>; - #size-cells = <2>; - #address-cells = <3>; - reg = <0 0xffe09000 0 0x1000>; - bus-range = <0 255>; ranges = <0x2000000 0x0 0xa0000000 0 0xa0000000 0x0 0x20000000 0x1000000 0x0 0x00000000 0 0xffc10000 0x0 0x10000>; - clock-frequency = <33333333>; - interrupt-parent = <&mpic>; - interrupts = <25 2>; interrupt-map-mask = <0xff00 0x0 0x0 0x7>; interrupt-map = < @@ -667,18 +359,8 @@ }; pci2: pcie@ffe0a000 { - compatible = "fsl,mpc8548-pcie"; - device_type = "pci"; - #interrupt-cells = <1>; - #size-cells = <2>; - #address-cells = <3>; - reg = <0 0xffe0a000 0 0x1000>; - bus-range = <0 255>; ranges = <0x2000000 0x0 0xc0000000 0 0xc0000000 0x0 0x20000000 0x1000000 0x0 0x00000000 0 0xffc20000 0x0 0x10000>; - clock-frequency = <33333333>; - interrupt-parent = <&mpic>; - interrupts = <26 2>; interrupt-map-mask = <0xf800 0x0 0x0 0x7>; interrupt-map = < /* IDSEL 0x0 */ diff --git a/arch/powerpc/boot/dts/p2020rdb.dts b/arch/powerpc/boot/dts/p2020rdb.dts index e2d48fd..60a0a8c 100644 --- a/arch/powerpc/boot/dts/p2020rdb.dts +++ b/arch/powerpc/boot/dts/p2020rdb.dts @@ -9,12 +9,11 @@ * option) any later version. */ -/dts-v1/; +/include/ "p2020si.dtsi" + / { - model = "fsl,P2020"; + model = "fsl,P2020RDB"; compatible = "fsl,P2020RDB"; - #address-cells = <2>; - #size-cells = <2>; aliases { ethernet0 = &enet0; @@ -26,34 +25,11 @@ pci1 = &pci1; }; - cpus { - #address-cells = <1>; - #size-cells = <0>; - - PowerPC,P2020@0 { - device_type = "cpu"; - reg = <0x0>; - next-level-cache = <&L2>; - }; - - PowerPC,P2020@1 { - device_type = "cpu"; - reg = <0x1>; - next-level-cache = <&L2>; - }; - }; - memory { device_type = "memory"; }; localbus@ffe05000 { - #address-cells = <2>; - #size-cells = <1>; - compatible = "fsl,p2020-elbc", "fsl,elbc", "simple-bus"; - reg = <0 0xffe05000 0 0x1000>; - interrupts = <19 2>; - interrupt-parent = <&mpic>; /* NOR and NAND Flashes */ ranges = <0x0 0x0 0x0 0xef000000 0x01000000 @@ -165,90 +141,16 @@ }; soc@ffe00000 { - #address-cells = <1>; - #size-cells = <1>; - device_type = "soc"; - compatible = "fsl,p2020-immr", "simple-bus"; - ranges = <0x0 0x0 0xffe00000 0x100000>; - bus-frequency = <0>; // Filled out by uboot. - - ecm-law@0 { - compatible = "fsl,ecm-law"; - reg = <0x0 0x1000>; - fsl,num-laws = <12>; - }; - - ecm@1000 { - compatible = "fsl,p2020-ecm", "fsl,ecm"; - reg = <0x1000 0x1000>; - interrupts = <17 2>; - interrupt-parent = <&mpic>; - }; - - memory-controller@2000 { - compatible = "fsl,p2020-memory-controller"; - reg = <0x2000 0x1000>; - interrupt-parent = <&mpic>; - interrupts = <18 2>; - }; - i2c@3000 { - #address-cells = <1>; - #size-cells = <0>; - cell-index = <0>; - compatible = "fsl-i2c"; - reg = <0x3000 0x100>; - interrupts = <43 2>; - interrupt-parent = <&mpic>; - dfsrr; rtc@68 { compatible = "dallas,ds1339"; reg = <0x68>; }; }; - i2c@3100 { - #address-cells = <1>; - #size-cells = <0>; - cell-index = <1>; - compatible = "fsl-i2c"; - reg = <0x3100 0x100>; - interrupts = <43 2>; - interrupt-parent = <&mpic>; - dfsrr; - }; - - serial0: serial@4500 { - cell-index = <0>; - device_type = "serial"; - compatible = "ns16550"; - reg = <0x4500 0x100>; - clock-frequency = <0>; - interrupts = <42 2>; - interrupt-parent = <&mpic>; - }; - - serial1: serial@4600 { - cell-index = <1>; - device_type = "serial"; - compatible = "ns16550"; - reg = <0x4600 0x100>; - clock-frequency = <0>; - interrupts = <42 2>; - interrupt-parent = <&mpic>; - }; + spi@7000 { - spi@7000 { - cell-index = <0>; - #address-cells = <1>; - #size-cells = <0>; - compatible = "fsl,espi"; - reg = <0x7000 0x1000>; - interrupts = <59 0x2>; - interrupt-parent = <&mpic>; - mode = "cpu"; - - fsl_m25p80@0 { + fsl_m25p80@0 { #address-cells = <1>; #size-cells = <1>; compatible = "fsl,espi-flash"; @@ -294,254 +196,60 @@ }; }; - dma@c300 { - #address-cells = <1>; - #size-cells = <1>; - compatible = "fsl,eloplus-dma"; - reg = <0xc300 0x4>; - ranges = <0x0 0xc100 0x200>; - cell-index = <1>; - dma-channel@0 { - compatible = "fsl,eloplus-dma-channel"; - reg = <0x0 0x80>; - cell-index = <0>; - interrupt-parent = <&mpic>; - interrupts = <76 2>; - }; - dma-channel@80 { - compatible = "fsl,eloplus-dma-channel"; - reg = <0x80 0x80>; - cell-index = <1>; - interrupt-parent = <&mpic>; - interrupts = <77 2>; - }; - dma-channel@100 { - compatible = "fsl,eloplus-dma-channel"; - reg = <0x100 0x80>; - cell-index = <2>; - interrupt-parent = <&mpic>; - interrupts = <78 2>; - }; - dma-channel@180 { - compatible = "fsl,eloplus-dma-channel"; - reg = <0x180 0x80>; - cell-index = <3>; - interrupt-parent = <&mpic>; - interrupts = <79 2>; - }; - }; - - gpio: gpio-controller@f000 { - #gpio-cells = <2>; - compatible = "fsl,mpc8572-gpio"; - reg = <0xf000 0x100>; - interrupts = <47 0x2>; - interrupt-parent = <&mpic>; - gpio-controller; - }; - - L2: l2-cache-controller@20000 { - compatible = "fsl,p2020-l2-cache-controller"; - reg = <0x20000 0x1000>; - cache-line-size = <32>; // 32 bytes - cache-size = <0x80000>; // L2,512K - interrupt-parent = <&mpic>; - interrupts = <16 2>; + usb@22000 { + phy_type = "ulpi"; }; - dma@21300 { - #address-cells = <1>; - #size-cells = <1>; - compatible = "fsl,eloplus-dma"; - reg = <0x21300 0x4>; - ranges = <0x0 0x21100 0x200>; - cell-index = <0>; - dma-channel@0 { - compatible = "fsl,eloplus-dma-channel"; - reg = <0x0 0x80>; - cell-index = <0>; + mdio@24520 { + phy0: ethernet-phy@0 { interrupt-parent = <&mpic>; - interrupts = <20 2>; - }; - dma-channel@80 { - compatible = "fsl,eloplus-dma-channel"; - reg = <0x80 0x80>; - cell-index = <1>; - interrupt-parent = <&mpic>; - interrupts = <21 2>; - }; - dma-channel@100 { - compatible = "fsl,eloplus-dma-channel"; - reg = <0x100 0x80>; - cell-index = <2>; - interrupt-parent = <&mpic>; - interrupts = <22 2>; - }; - dma-channel@180 { - compatible = "fsl,eloplus-dma-channel"; - reg = <0x180 0x80>; - cell-index = <3>; + interrupts = <3 1>; + reg = <0x0>; + }; + phy1: ethernet-phy@1 { interrupt-parent = <&mpic>; - interrupts = <23 2>; + interrupts = <3 1>; + reg = <0x1>; + }; + }; + + mdio@25520 { + tbi0: tbi-phy@11 { + reg = <0x11>; + device_type = "tbi-phy"; }; }; - usb@22000 { - #address-cells = <1>; - #size-cells = <0>; - compatible = "fsl-usb2-dr"; - reg = <0x22000 0x1000>; - interrupt-parent = <&mpic>; - interrupts = <28 0x2>; - phy_type = "ulpi"; + mdio@26520 { + status = "disabled"; }; enet0: ethernet@24000 { - #address-cells = <1>; - #size-cells = <1>; - cell-index = <0>; - device_type = "network"; - model = "eTSEC"; - compatible = "gianfar"; - reg = <0x24000 0x1000>; - ranges = <0x0 0x24000 0x1000>; - local-mac-address = [ 00 00 00 00 00 00 ]; - interrupts = <29 2 30 2 34 2>; - interrupt-parent = <&mpic>; fixed-link = <1 1 1000 0 0>; phy-connection-type = "rgmii-id"; - - mdio@520 { - #address-cells = <1>; - #size-cells = <0>; - compatible = "fsl,gianfar-mdio"; - reg = <0x520 0x20>; - - phy0: ethernet-phy@0 { - interrupt-parent = <&mpic>; - interrupts = <3 1>; - reg = <0x0>; - }; - phy1: ethernet-phy@1 { - interrupt-parent = <&mpic>; - interrupts = <3 1>; - reg = <0x1>; - }; - }; }; enet1: ethernet@25000 { - #address-cells = <1>; - #size-cells = <1>; - cell-index = <1>; - device_type = "network"; - model = "eTSEC"; - compatible = "gianfar"; - reg = <0x25000 0x1000>; - ranges = <0x0 0x25000 0x1000>; - local-mac-address = [ 00 00 00 00 00 00 ]; - interrupts = <35 2 36 2 40 2>; - interrupt-parent = <&mpic>; tbi-handle = <&tbi0>; phy-handle = <&phy0>; phy-connection-type = "sgmii"; - - mdio@520 { - #address-cells = <1>; - #size-cells = <0>; - compatible = "fsl,gianfar-tbi"; - reg = <0x520 0x20>; - - tbi0: tbi-phy@11 { - reg = <0x11>; - device_type = "tbi-phy"; - }; - }; }; enet2: ethernet@26000 { - #address-cells = <1>; - #size-cells = <1>; - cell-index = <2>; - device_type = "network"; - model = "eTSEC"; - compatible = "gianfar"; - reg = <0x26000 0x1000>; - ranges = <0x0 0x26000 0x1000>; - local-mac-address = [ 00 00 00 00 00 00 ]; - interrupts = <31 2 32 2 33 2>; - interrupt-parent = <&mpic>; phy-handle = <&phy1>; phy-connection-type = "rgmii-id"; }; - sdhci@2e000 { - compatible = "fsl,p2020-esdhc", "fsl,esdhc"; - reg = <0x2e000 0x1000>; - interrupts = <72 0x2>; - interrupt-parent = <&mpic>; - /* Filled in by U-Boot */ - clock-frequency = <0>; - }; - - crypto@30000 { - compatible = "fsl,sec3.1", "fsl,sec3.0", "fsl,sec2.4", - "fsl,sec2.2", "fsl,sec2.1", "fsl,sec2.0"; - reg = <0x30000 0x10000>; - interrupts = <45 2 58 2>; - interrupt-parent = <&mpic>; - fsl,num-channels = <4>; - fsl,channel-fifo-len = <24>; - fsl,exec-units-mask = <0xbfe>; - fsl,descriptor-types-mask = <0x3ab0ebf>; - }; - - mpic: pic@40000 { - interrupt-controller; - #address-cells = <0>; - #interrupt-cells = <2>; - reg = <0x40000 0x40000>; - compatible = "chrp,open-pic"; - device_type = "open-pic"; - }; - - msi@41600 { - compatible = "fsl,p2020-msi", "fsl,mpic-msi"; - reg = <0x41600 0x80>; - msi-available-ranges = <0 0x100>; - interrupts = < - 0xe0 0 - 0xe1 0 - 0xe2 0 - 0xe3 0 - 0xe4 0 - 0xe5 0 - 0xe6 0 - 0xe7 0>; - interrupt-parent = <&mpic>; - }; + }; - global-utilities@e0000 { //global utilities block - compatible = "fsl,p2020-guts"; - reg = <0xe0000 0x1000>; - fsl,has-rstcr; - }; + pci0: pcie@ffe08000 { + status = "disabled"; }; - pci0: pcie@ffe09000 { - compatible = "fsl,mpc8548-pcie"; - device_type = "pci"; - #interrupt-cells = <1>; - #size-cells = <2>; - #address-cells = <3>; - reg = <0 0xffe09000 0 0x1000>; - bus-range = <0 255>; + pci1: pcie@ffe09000 { ranges = <0x2000000 0x0 0xa0000000 0 0xa0000000 0x0 0x20000000 0x1000000 0x0 0x00000000 0 0xffc10000 0x0 0x10000>; - clock-frequency = <33333333>; - interrupt-parent = <&mpic>; - interrupts = <25 2>; - pcie@0 { + pcie@0 { reg = <0x0 0x0 0x0 0x0 0x0>; #size-cells = <2>; #address-cells = <3>; @@ -556,19 +264,9 @@ }; }; - pci1: pcie@ffe0a000 { - compatible = "fsl,mpc8548-pcie"; - device_type = "pci"; - #interrupt-cells = <1>; - #size-cells = <2>; - #address-cells = <3>; - reg = <0 0xffe0a000 0 0x1000>; - bus-range = <0 255>; + pci2: pcie@ffe0a000 { ranges = <0x2000000 0x0 0x80000000 0 0x80000000 0x0 0x20000000 0x1000000 0x0 0x00000000 0 0xffc00000 0x0 0x10000>; - clock-frequency = <33333333>; - interrupt-parent = <&mpic>; - interrupts = <26 2>; pcie@0 { reg = <0x0 0x0 0x0 0x0 0x0>; #size-cells = <2>; diff --git a/arch/powerpc/boot/dts/p2020rdb_camp_core0.dts b/arch/powerpc/boot/dts/p2020rdb_camp_core0.dts index b69c3a5..72c912f 100644 --- a/arch/powerpc/boot/dts/p2020rdb_camp_core0.dts +++ b/arch/powerpc/boot/dts/p2020rdb_camp_core0.dts @@ -14,12 +14,11 @@ * option) any later version. */ -/dts-v1/; +/include/ "p2020si.dtsi" + / { - model = "fsl,P2020"; + model = "fsl,P2020RDB"; compatible = "fsl,P2020RDB", "fsl,MPC85XXRDB-CAMP"; - #address-cells = <2>; - #size-cells = <2>; aliases { ethernet1 = &enet1; @@ -29,91 +28,33 @@ }; cpus { - #address-cells = <1>; - #size-cells = <0>; - - PowerPC,P2020@0 { - device_type = "cpu"; - reg = <0x0>; - next-level-cache = <&L2>; + PowerPC,P2020@1 { + status = "disabled"; }; + }; memory { device_type = "memory"; }; - soc@ffe00000 { - #address-cells = <1>; - #size-cells = <1>; - device_type = "soc"; - compatible = "fsl,p2020-immr", "simple-bus"; - ranges = <0x0 0x0 0xffe00000 0x100000>; - bus-frequency = <0>; // Filled out by uboot. - - ecm-law@0 { - compatible = "fsl,ecm-law"; - reg = <0x0 0x1000>; - fsl,num-laws = <12>; - }; - - ecm@1000 { - compatible = "fsl,p2020-ecm", "fsl,ecm"; - reg = <0x1000 0x1000>; - interrupts = <17 2>; - interrupt-parent = <&mpic>; - }; - - memory-controller@2000 { - compatible = "fsl,p2020-memory-controller"; - reg = <0x2000 0x1000>; - interrupt-parent = <&mpic>; - interrupts = <18 2>; - }; + localbus@ffe05000 { + status = "disabled"; + }; + soc@ffe00000 { i2c@3000 { - #address-cells = <1>; - #size-cells = <0>; - cell-index = <0>; - compatible = "fsl-i2c"; - reg = <0x3000 0x100>; - interrupts = <43 2>; - interrupt-parent = <&mpic>; - dfsrr; rtc@68 { compatible = "dallas,ds1339"; reg = <0x68>; }; }; - i2c@3100 { - #address-cells = <1>; - #size-cells = <0>; - cell-index = <1>; - compatible = "fsl-i2c"; - reg = <0x3100 0x100>; - interrupts = <43 2>; - interrupt-parent = <&mpic>; - dfsrr; - }; - - serial0: serial@4500 { - cell-index = <0>; - device_type = "serial"; - compatible = "ns16550"; - reg = <0x4500 0x100>; - clock-frequency = <0>; + serial1: serial@4600 { + status = "disabled"; }; spi@7000 { - cell-index = <0>; - #address-cells = <1>; - #size-cells = <0>; - compatible = "fsl,espi"; - reg = <0x7000 0x1000>; - interrupts = <59 0x2>; - interrupt-parent = <&mpic>; - mode = "cpu"; fsl_m25p80@0 { #address-cells = <1>; @@ -161,76 +102,15 @@ }; }; - gpio: gpio-controller@f000 { - #gpio-cells = <2>; - compatible = "fsl,mpc8572-gpio"; - reg = <0xf000 0x100>; - interrupts = <47 0x2>; - interrupt-parent = <&mpic>; - gpio-controller; - }; - - L2: l2-cache-controller@20000 { - compatible = "fsl,p2020-l2-cache-controller"; - reg = <0x20000 0x1000>; - cache-line-size = <32>; // 32 bytes - cache-size = <0x80000>; // L2,512K - interrupt-parent = <&mpic>; - interrupts = <16 2>; - }; - - dma@21300 { - #address-cells = <1>; - #size-cells = <1>; - compatible = "fsl,eloplus-dma"; - reg = <0x21300 0x4>; - ranges = <0x0 0x21100 0x200>; - cell-index = <0>; - dma-channel@0 { - compatible = "fsl,eloplus-dma-channel"; - reg = <0x0 0x80>; - cell-index = <0>; - interrupt-parent = <&mpic>; - interrupts = <20 2>; - }; - dma-channel@80 { - compatible = "fsl,eloplus-dma-channel"; - reg = <0x80 0x80>; - cell-index = <1>; - interrupt-parent = <&mpic>; - interrupts = <21 2>; - }; - dma-channel@100 { - compatible = "fsl,eloplus-dma-channel"; - reg = <0x100 0x80>; - cell-index = <2>; - interrupt-parent = <&mpic>; - interrupts = <22 2>; - }; - dma-channel@180 { - compatible = "fsl,eloplus-dma-channel"; - reg = <0x180 0x80>; - cell-index = <3>; - interrupt-parent = <&mpic>; - interrupts = <23 2>; - }; + dma@c300 { + status = "disabled"; }; usb@22000 { - #address-cells = <1>; - #size-cells = <0>; - compatible = "fsl-usb2-dr"; - reg = <0x22000 0x1000>; - interrupt-parent = <&mpic>; - interrupts = <28 0x2>; phy_type = "ulpi"; }; mdio@24520 { - #address-cells = <1>; - #size-cells = <0>; - compatible = "fsl,gianfar-mdio"; - reg = <0x24520 0x20>; phy0: ethernet-phy@0 { interrupt-parent = <&mpic>; @@ -245,29 +125,21 @@ }; mdio@25520 { - #address-cells = <1>; - #size-cells = <0>; - compatible = "fsl,gianfar-tbi"; - reg = <0x26520 0x20>; - tbi0: tbi-phy@11 { reg = <0x11>; device_type = "tbi-phy"; }; }; + mdio@26520 { + status = "disabled"; + }; + + enet0: ethernet@24000 { + status = "disabled"; + }; + enet1: ethernet@25000 { - #address-cells = <1>; - #size-cells = <1>; - cell-index = <1>; - device_type = "network"; - model = "eTSEC"; - compatible = "gianfar"; - reg = <0x25000 0x1000>; - ranges = <0x0 0x25000 0x1000>; - local-mac-address = [ 00 00 00 00 00 00 ]; - interrupts = <35 2 36 2 40 2>; - interrupt-parent = <&mpic>; tbi-handle = <&tbi0>; phy-handle = <&phy0>; phy-connection-type = "sgmii"; @@ -275,49 +147,12 @@ }; enet2: ethernet@26000 { - #address-cells = <1>; - #size-cells = <1>; - cell-index = <2>; - device_type = "network"; - model = "eTSEC"; - compatible = "gianfar"; - reg = <0x26000 0x1000>; - ranges = <0x0 0x26000 0x1000>; - local-mac-address = [ 00 00 00 00 00 00 ]; - interrupts = <31 2 32 2 33 2>; - interrupt-parent = <&mpic>; phy-handle = <&phy1>; phy-connection-type = "rgmii-id"; }; - sdhci@2e000 { - compatible = "fsl,p2020-esdhc", "fsl,esdhc"; - reg = <0x2e000 0x1000>; - interrupts = <72 0x2>; - interrupt-parent = <&mpic>; - /* Filled in by U-Boot */ - clock-frequency = <0>; - }; - - crypto@30000 { - compatible = "fsl,sec3.1", "fsl,sec3.0", "fsl,sec2.4", - "fsl,sec2.2", "fsl,sec2.1", "fsl,sec2.0"; - reg = <0x30000 0x10000>; - interrupts = <45 2 58 2>; - interrupt-parent = <&mpic>; - fsl,num-channels = <4>; - fsl,channel-fifo-len = <24>; - fsl,exec-units-mask = <0xbfe>; - fsl,descriptor-types-mask = <0x3ab0ebf>; - }; mpic: pic@40000 { - interrupt-controller; - #address-cells = <0>; - #interrupt-cells = <2>; - reg = <0x40000 0x40000>; - compatible = "chrp,open-pic"; - device_type = "open-pic"; protected-sources = < 42 76 77 78 79 /* serial1 , dma2 */ 29 30 34 26 /* enet0, pci1 */ @@ -326,26 +161,20 @@ >; }; - global-utilities@e0000 { - compatible = "fsl,p2020-guts"; - reg = <0xe0000 0x1000>; - fsl,has-rstcr; + msi@41600 { + status = "disabled"; }; + + }; - pci0: pcie@ffe09000 { - compatible = "fsl,mpc8548-pcie"; - device_type = "pci"; - #interrupt-cells = <1>; - #size-cells = <2>; - #address-cells = <3>; - reg = <0 0xffe09000 0 0x1000>; - bus-range = <0 255>; + pci0: pcie@ffe08000 { + status = "disabled"; + }; + + pci1: pcie@ffe09000 { ranges = <0x2000000 0x0 0xa0000000 0 0xa0000000 0x0 0x20000000 0x1000000 0x0 0x00000000 0 0xffc10000 0x0 0x10000>; - clock-frequency = <33333333>; - interrupt-parent = <&mpic>; - interrupts = <25 2>; pcie@0 { reg = <0x0 0x0 0x0 0x0 0x0>; #size-cells = <2>; @@ -360,4 +189,8 @@ 0x0 0x100000>; }; }; + + pci2: pcie@ffe0a000 { + status = "disabled"; + }; }; diff --git a/arch/powerpc/boot/dts/p2020rdb_camp_core1.dts b/arch/powerpc/boot/dts/p2020rdb_camp_core1.dts index 7a31d46c..eb572cc 100644 --- a/arch/powerpc/boot/dts/p2020rdb_camp_core1.dts +++ b/arch/powerpc/boot/dts/p2020rdb_camp_core1.dts @@ -15,27 +15,21 @@ * option) any later version. */ -/dts-v1/; +/include/ "p2020si.dtsi" + / { - model = "fsl,P2020"; + model = "fsl,P2020RDB"; compatible = "fsl,P2020RDB", "fsl,MPC85XXRDB-CAMP"; - #address-cells = <2>; - #size-cells = <2>; aliases { ethernet0 = &enet0; - serial0 = &serial0; + serial0 = &serial1; pci1 = &pci1; }; cpus { - #address-cells = <1>; - #size-cells = <0>; - - PowerPC,P2020@1 { - device_type = "cpu"; - reg = <0x1>; - next-level-cache = <&L2>; + PowerPC,P2020@0 { + status = "disabled"; }; }; @@ -43,20 +37,37 @@ device_type = "memory"; }; + localbus@ffe05000 { + status = "disabled"; + }; + soc@ffe00000 { - #address-cells = <1>; - #size-cells = <1>; - device_type = "soc"; - compatible = "fsl,p2020-immr", "simple-bus"; - ranges = <0x0 0x0 0xffe00000 0x100000>; - bus-frequency = <0>; // Filled out by uboot. - - serial0: serial@4600 { - cell-index = <1>; - device_type = "serial"; - compatible = "ns16550"; - reg = <0x4600 0x100>; - clock-frequency = <0>; + ecm-law@0 { + status = "disabled"; + }; + + ecm@1000 { + status = "disabled"; + }; + + memory-controller@2000 { + status = "disabled"; + }; + + i2c@3000 { + status = "disabled"; + }; + + i2c@3100 { + status = "disabled"; + }; + + serial0: serial@4500 { + status = "disabled"; + }; + + spi@7000 { + status = "disabled"; }; dma@c300 { @@ -96,6 +107,10 @@ }; }; + gpio: gpio-controller@f000 { + status = "disabled"; + }; + L2: l2-cache-controller@20000 { compatible = "fsl,p2020-l2-cache-controller"; reg = <0x20000 0x1000>; @@ -104,31 +119,49 @@ interrupt-parent = <&mpic>; }; + dma@21300 { + status = "disabled"; + }; + + usb@22000 { + status = "disabled"; + }; + + mdio@24520 { + status = "disabled"; + }; + + mdio@25520 { + status = "disabled"; + }; + + mdio@26520 { + status = "disabled"; + }; enet0: ethernet@24000 { - #address-cells = <1>; - #size-cells = <1>; - cell-index = <0>; - device_type = "network"; - model = "eTSEC"; - compatible = "gianfar"; - reg = <0x24000 0x1000>; - ranges = <0x0 0x24000 0x1000>; - local-mac-address = [ 00 00 00 00 00 00 ]; - interrupts = <29 2 30 2 34 2>; - interrupt-parent = <&mpic>; fixed-link = <1 1 1000 0 0>; phy-connection-type = "rgmii-id"; }; + enet1: ethernet@25000 { + status = "disabled"; + }; + + enet2: ethernet@26000 { + status = "disabled"; + }; + + sdhci@2e000 { + status = "disabled"; + }; + + crypto@30000 { + status = "disabled"; + }; + mpic: pic@40000 { - interrupt-controller; - #address-cells = <0>; - #interrupt-cells = <2>; - reg = <0x40000 0x40000>; - compatible = "chrp,open-pic"; - device_type = "open-pic"; protected-sources = < 17 18 43 42 59 47 /*ecm, mem, i2c, serial0, spi,gpio */ 16 20 21 22 23 28 /* L2, dma1, USB */ @@ -152,21 +185,24 @@ 0xe7 0>; interrupt-parent = <&mpic>; }; + + global-utilities@e0000 { //global utilities block + status = "disabled"; + }; + + }; + + pci0: pcie@ffe08000 { + status = "disabled"; + }; + + pci1: pcie@ffe09000 { + status = "disabled"; }; - pci1: pcie@ffe0a000 { - compatible = "fsl,mpc8548-pcie"; - device_type = "pci"; - #interrupt-cells = <1>; - #size-cells = <2>; - #address-cells = <3>; - reg = <0 0xffe0a000 0 0x1000>; - bus-range = <0 255>; + pci2: pcie@ffe0a000 { ranges = <0x2000000 0x0 0x80000000 0 0x80000000 0x0 0x20000000 0x1000000 0x0 0x00000000 0 0xffc00000 0x0 0x10000>; - clock-frequency = <33333333>; - interrupt-parent = <&mpic>; - interrupts = <26 2>; pcie@0 { reg = <0x0 0x0 0x0 0x0 0x0>; #size-cells = <2>; diff --git a/arch/powerpc/boot/dts/p2020si.dtsi b/arch/powerpc/boot/dts/p2020si.dtsi new file mode 100644 index 0000000..6def17f --- /dev/null +++ b/arch/powerpc/boot/dts/p2020si.dtsi @@ -0,0 +1,382 @@ +/* + * P2020 Device Tree Source + * + * Copyright 2011 Freescale Semiconductor Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ + +/dts-v1/; +/ { + compatible = "fsl,P2020"; + #address-cells = <2>; + #size-cells = <2>; + + cpus { + #address-cells = <1>; + #size-cells = <0>; + + PowerPC,P2020@0 { + device_type = "cpu"; + reg = <0x0>; + next-level-cache = <&L2>; + }; + + PowerPC,P2020@1 { + device_type = "cpu"; + reg = <0x1>; + next-level-cache = <&L2>; + }; + }; + + localbus@ffe05000 { + #address-cells = <2>; + #size-cells = <1>; + compatible = "fsl,p2020-elbc", "fsl,elbc", "simple-bus"; + reg = <0 0xffe05000 0 0x1000>; + interrupts = <19 2>; + interrupt-parent = <&mpic>; + }; + + soc@ffe00000 { + #address-cells = <1>; + #size-cells = <1>; + device_type = "soc"; + compatible = "fsl,p2020-immr", "simple-bus"; + ranges = <0x0 0x0 0xffe00000 0x100000>; + bus-frequency = <0>; // Filled out by uboot. + + ecm-law@0 { + compatible = "fsl,ecm-law"; + reg = <0x0 0x1000>; + fsl,num-laws = <12>; + }; + + ecm@1000 { + compatible = "fsl,p2020-ecm", "fsl,ecm"; + reg = <0x1000 0x1000>; + interrupts = <17 2>; + interrupt-parent = <&mpic>; + }; + + memory-controller@2000 { + compatible = "fsl,p2020-memory-controller"; + reg = <0x2000 0x1000>; + interrupt-parent = <&mpic>; + interrupts = <18 2>; + }; + + i2c@3000 { + #address-cells = <1>; + #size-cells = <0>; + cell-index = <0>; + compatible = "fsl-i2c"; + reg = <0x3000 0x100>; + interrupts = <43 2>; + interrupt-parent = <&mpic>; + dfsrr; + }; + + i2c@3100 { + #address-cells = <1>; + #size-cells = <0>; + cell-index = <1>; + compatible = "fsl-i2c"; + reg = <0x3100 0x100>; + interrupts = <43 2>; + interrupt-parent = <&mpic>; + dfsrr; + }; + + serial0: serial@4500 { + cell-index = <0>; + device_type = "serial"; + compatible = "ns16550"; + reg = <0x4500 0x100>; + clock-frequency = <0>; + interrupts = <42 2>; + interrupt-parent = <&mpic>; + }; + + serial1: serial@4600 { + cell-index = <1>; + device_type = "serial"; + compatible = "ns16550"; + reg = <0x4600 0x100>; + clock-frequency = <0>; + interrupts = <42 2>; + interrupt-parent = <&mpic>; + }; + + spi@7000 { + cell-index = <0>; + #address-cells = <1>; + #size-cells = <0>; + compatible = "fsl,espi"; + reg = <0x7000 0x1000>; + interrupts = <59 0x2>; + interrupt-parent = <&mpic>; + mode = "cpu"; + }; + + dma@c300 { + #address-cells = <1>; + #size-cells = <1>; + compatible = "fsl,eloplus-dma"; + reg = <0xc300 0x4>; + ranges = <0x0 0xc100 0x200>; + cell-index = <1>; + dma-channel@0 { + compatible = "fsl,eloplus-dma-channel"; + reg = <0x0 0x80>; + cell-index = <0>; + interrupt-parent = <&mpic>; + interrupts = <76 2>; + }; + dma-channel@80 { + compatible = "fsl,eloplus-dma-channel"; + reg = <0x80 0x80>; + cell-index = <1>; + interrupt-parent = <&mpic>; + interrupts = <77 2>; + }; + dma-channel@100 { + compatible = "fsl,eloplus-dma-channel"; + reg = <0x100 0x80>; + cell-index = <2>; + interrupt-parent = <&mpic>; + interrupts = <78 2>; + }; + dma-channel@180 { + compatible = "fsl,eloplus-dma-channel"; + reg = <0x180 0x80>; + cell-index = <3>; + interrupt-parent = <&mpic>; + interrupts = <79 2>; + }; + }; + + gpio: gpio-controller@f000 { + #gpio-cells = <2>; + compatible = "fsl,mpc8572-gpio"; + reg = <0xf000 0x100>; + interrupts = <47 0x2>; + interrupt-parent = <&mpic>; + gpio-controller; + }; + + L2: l2-cache-controller@20000 { + compatible = "fsl,p2020-l2-cache-controller"; + reg = <0x20000 0x1000>; + cache-line-size = <32>; // 32 bytes + cache-size = <0x80000>; // L2,512K + interrupt-parent = <&mpic>; + interrupts = <16 2>; + }; + + dma@21300 { + #address-cells = <1>; + #size-cells = <1>; + compatible = "fsl,eloplus-dma"; + reg = <0x21300 0x4>; + ranges = <0x0 0x21100 0x200>; + cell-index = <0>; + dma-channel@0 { + compatible = "fsl,eloplus-dma-channel"; + reg = <0x0 0x80>; + cell-index = <0>; + interrupt-parent = <&mpic>; + interrupts = <20 2>; + }; + dma-channel@80 { + compatible = "fsl,eloplus-dma-channel"; + reg = <0x80 0x80>; + cell-index = <1>; + interrupt-parent = <&mpic>; + interrupts = <21 2>; + }; + dma-channel@100 { + compatible = "fsl,eloplus-dma-channel"; + reg = <0x100 0x80>; + cell-index = <2>; + interrupt-parent = <&mpic>; + interrupts = <22 2>; + }; + dma-channel@180 { + compatible = "fsl,eloplus-dma-channel"; + reg = <0x180 0x80>; + cell-index = <3>; + interrupt-parent = <&mpic>; + interrupts = <23 2>; + }; + }; + + usb@22000 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "fsl-usb2-dr"; + reg = <0x22000 0x1000>; + interrupt-parent = <&mpic>; + interrupts = <28 0x2>; + }; + + mdio@24520 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "fsl,gianfar-mdio"; + reg = <0x24520 0x20>; + }; + + mdio@25520 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "fsl,gianfar-tbi"; + reg = <0x26520 0x20>; + }; + + mdio@26520 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "fsl,gianfar-tbi"; + reg = <0x520 0x20>; + }; + + enet0: ethernet@24000 { + #address-cells = <1>; + #size-cells = <1>; + cell-index = <0>; + device_type = "network"; + model = "eTSEC"; + compatible = "gianfar"; + reg = <0x24000 0x1000>; + ranges = <0x0 0x24000 0x1000>; + local-mac-address = [ 00 00 00 00 00 00 ]; + interrupts = <29 2 30 2 34 2>; + interrupt-parent = <&mpic>; + }; + + enet1: ethernet@25000 { + #address-cells = <1>; + #size-cells = <1>; + cell-index = <1>; + device_type = "network"; + model = "eTSEC"; + compatible = "gianfar"; + reg = <0x25000 0x1000>; + ranges = <0x0 0x25000 0x1000>; + local-mac-address = [ 00 00 00 00 00 00 ]; + interrupts = <35 2 36 2 40 2>; + interrupt-parent = <&mpic>; + + }; + + enet2: ethernet@26000 { + #address-cells = <1>; + #size-cells = <1>; + cell-index = <2>; + device_type = "network"; + model = "eTSEC"; + compatible = "gianfar"; + reg = <0x26000 0x1000>; + ranges = <0x0 0x26000 0x1000>; + local-mac-address = [ 00 00 00 00 00 00 ]; + interrupts = <31 2 32 2 33 2>; + interrupt-parent = <&mpic>; + + }; + + sdhci@2e000 { + compatible = "fsl,p2020-esdhc", "fsl,esdhc"; + reg = <0x2e000 0x1000>; + interrupts = <72 0x2>; + interrupt-parent = <&mpic>; + /* Filled in by U-Boot */ + clock-frequency = <0>; + }; + + crypto@30000 { + compatible = "fsl,sec3.1", "fsl,sec3.0", "fsl,sec2.4", + "fsl,sec2.2", "fsl,sec2.1", "fsl,sec2.0"; + reg = <0x30000 0x10000>; + interrupts = <45 2 58 2>; + interrupt-parent = <&mpic>; + fsl,num-channels = <4>; + fsl,channel-fifo-len = <24>; + fsl,exec-units-mask = <0xbfe>; + fsl,descriptor-types-mask = <0x3ab0ebf>; + }; + + mpic: pic@40000 { + interrupt-controller; + #address-cells = <0>; + #interrupt-cells = <2>; + reg = <0x40000 0x40000>; + compatible = "chrp,open-pic"; + device_type = "open-pic"; + }; + + msi@41600 { + compatible = "fsl,p2020-msi", "fsl,mpic-msi"; + reg = <0x41600 0x80>; + msi-available-ranges = <0 0x100>; + interrupts = < + 0xe0 0 + 0xe1 0 + 0xe2 0 + 0xe3 0 + 0xe4 0 + 0xe5 0 + 0xe6 0 + 0xe7 0>; + interrupt-parent = <&mpic>; + }; + + global-utilities@e0000 { //global utilities block + compatible = "fsl,p2020-guts"; + reg = <0xe0000 0x1000>; + fsl,has-rstcr; + }; + }; + + pci0: pcie@ffe08000 { + compatible = "fsl,mpc8548-pcie"; + device_type = "pci"; + #interrupt-cells = <1>; + #size-cells = <2>; + #address-cells = <3>; + reg = <0 0xffe08000 0 0x1000>; + bus-range = <0 255>; + clock-frequency = <33333333>; + interrupt-parent = <&mpic>; + interrupts = <24 2>; + }; + + pci1: pcie@ffe09000 { + compatible = "fsl,mpc8548-pcie"; + device_type = "pci"; + #interrupt-cells = <1>; + #size-cells = <2>; + #address-cells = <3>; + reg = <0 0xffe09000 0 0x1000>; + bus-range = <0 255>; + clock-frequency = <33333333>; + interrupt-parent = <&mpic>; + interrupts = <25 2>; + }; + + pci2: pcie@ffe0a000 { + compatible = "fsl,mpc8548-pcie"; + device_type = "pci"; + #interrupt-cells = <1>; + #size-cells = <2>; + #address-cells = <3>; + reg = <0 0xffe0a000 0 0x1000>; + bus-range = <0 255>; + clock-frequency = <33333333>; + interrupt-parent = <&mpic>; + interrupts = <26 2>; + }; +}; -- cgit v0.10.2 From bc99d09abe14b4841454701c47e45f22444a890a Mon Sep 17 00:00:00 2001 From: Prabhakar Kushwaha Date: Wed, 20 Apr 2011 09:42:44 +0530 Subject: powerpc/85xx: Fix PCIe IDSEL for Px020RDB PCIe device in legacy mode can trigger interrupts using the wires #INTA, #INTB ,#INTC and #INTD. PCI devices are obligated to use #INTx for interrupts under legacy mode. Each PCI slot or device is typically wired to different inputs on the interrupt controller. So, Define interrupt-map and interrupt-map-mask properties for device tree to of map each PCI interrupt signal to the inputs of the interrupt controller. Signed-off-by: Prabhakar Kushwaha Signed-off-by: Kumar Gala diff --git a/arch/powerpc/boot/dts/p1020rdb.dts b/arch/powerpc/boot/dts/p1020rdb.dts index 7ed4793..d6a8ae4 100644 --- a/arch/powerpc/boot/dts/p1020rdb.dts +++ b/arch/powerpc/boot/dts/p1020rdb.dts @@ -257,6 +257,14 @@ pci0: pcie@ffe09000 { ranges = <0x2000000 0x0 0xa0000000 0 0xa0000000 0x0 0x20000000 0x1000000 0x0 0x00000000 0 0xffc10000 0x0 0x10000>; + interrupt-map-mask = <0xf800 0x0 0x0 0x7>; + interrupt-map = < + /* IDSEL 0x0 */ + 0000 0x0 0x0 0x1 &mpic 0x4 0x1 + 0000 0x0 0x0 0x2 &mpic 0x5 0x1 + 0000 0x0 0x0 0x3 &mpic 0x6 0x1 + 0000 0x0 0x0 0x4 &mpic 0x7 0x1 + >; pcie@0 { reg = <0x0 0x0 0x0 0x0 0x0>; #size-cells = <2>; @@ -275,6 +283,14 @@ pci1: pcie@ffe0a000 { ranges = <0x2000000 0x0 0x80000000 0 0x80000000 0x0 0x20000000 0x1000000 0x0 0x00000000 0 0xffc00000 0x0 0x10000>; + interrupt-map-mask = <0xf800 0x0 0x0 0x7>; + interrupt-map = < + /* IDSEL 0x0 */ + 0000 0x0 0x0 0x1 &mpic 0x0 0x1 + 0000 0x0 0x0 0x2 &mpic 0x1 0x1 + 0000 0x0 0x0 0x3 &mpic 0x2 0x1 + 0000 0x0 0x0 0x4 &mpic 0x3 0x1 + >; pcie@0 { reg = <0x0 0x0 0x0 0x0 0x0>; #size-cells = <2>; diff --git a/arch/powerpc/boot/dts/p2020rdb.dts b/arch/powerpc/boot/dts/p2020rdb.dts index 60a0a8c..3782a58 100644 --- a/arch/powerpc/boot/dts/p2020rdb.dts +++ b/arch/powerpc/boot/dts/p2020rdb.dts @@ -249,6 +249,14 @@ pci1: pcie@ffe09000 { ranges = <0x2000000 0x0 0xa0000000 0 0xa0000000 0x0 0x20000000 0x1000000 0x0 0x00000000 0 0xffc10000 0x0 0x10000>; + interrupt-map-mask = <0xf800 0x0 0x0 0x7>; + interrupt-map = < + /* IDSEL 0x0 */ + 0000 0x0 0x0 0x1 &mpic 0x4 0x1 + 0000 0x0 0x0 0x2 &mpic 0x5 0x1 + 0000 0x0 0x0 0x3 &mpic 0x6 0x1 + 0000 0x0 0x0 0x4 &mpic 0x7 0x1 + >; pcie@0 { reg = <0x0 0x0 0x0 0x0 0x0>; #size-cells = <2>; @@ -267,6 +275,14 @@ pci2: pcie@ffe0a000 { ranges = <0x2000000 0x0 0x80000000 0 0x80000000 0x0 0x20000000 0x1000000 0x0 0x00000000 0 0xffc00000 0x0 0x10000>; + interrupt-map-mask = <0xf800 0x0 0x0 0x7>; + interrupt-map = < + /* IDSEL 0x0 */ + 0000 0x0 0x0 0x1 &mpic 0x0 0x1 + 0000 0x0 0x0 0x2 &mpic 0x1 0x1 + 0000 0x0 0x0 0x3 &mpic 0x2 0x1 + 0000 0x0 0x0 0x4 &mpic 0x3 0x1 + >; pcie@0 { reg = <0x0 0x0 0x0 0x0 0x0>; #size-cells = <2>; diff --git a/arch/powerpc/boot/dts/p2020rdb_camp_core0.dts b/arch/powerpc/boot/dts/p2020rdb_camp_core0.dts index 72c912f..fc8ddddf 100644 --- a/arch/powerpc/boot/dts/p2020rdb_camp_core0.dts +++ b/arch/powerpc/boot/dts/p2020rdb_camp_core0.dts @@ -175,6 +175,14 @@ pci1: pcie@ffe09000 { ranges = <0x2000000 0x0 0xa0000000 0 0xa0000000 0x0 0x20000000 0x1000000 0x0 0x00000000 0 0xffc10000 0x0 0x10000>; + interrupt-map-mask = <0xf800 0x0 0x0 0x7>; + interrupt-map = < + /* IDSEL 0x0 */ + 0000 0x0 0x0 0x1 &mpic 0x4 0x1 + 0000 0x0 0x0 0x2 &mpic 0x5 0x1 + 0000 0x0 0x0 0x3 &mpic 0x6 0x1 + 0000 0x0 0x0 0x4 &mpic 0x7 0x1 + >; pcie@0 { reg = <0x0 0x0 0x0 0x0 0x0>; #size-cells = <2>; diff --git a/arch/powerpc/boot/dts/p2020rdb_camp_core1.dts b/arch/powerpc/boot/dts/p2020rdb_camp_core1.dts index eb572cc..261c34b 100644 --- a/arch/powerpc/boot/dts/p2020rdb_camp_core1.dts +++ b/arch/powerpc/boot/dts/p2020rdb_camp_core1.dts @@ -203,6 +203,14 @@ pci2: pcie@ffe0a000 { ranges = <0x2000000 0x0 0x80000000 0 0x80000000 0x0 0x20000000 0x1000000 0x0 0x00000000 0 0xffc00000 0x0 0x10000>; + interrupt-map-mask = <0xf800 0x0 0x0 0x7>; + interrupt-map = < + /* IDSEL 0x0 */ + 0000 0x0 0x0 0x1 &mpic 0x0 0x1 + 0000 0x0 0x0 0x2 &mpic 0x1 0x1 + 0000 0x0 0x0 0x3 &mpic 0x2 0x1 + 0000 0x0 0x0 0x4 &mpic 0x3 0x1 + >; pcie@0 { reg = <0x0 0x0 0x0 0x0 0x0>; #size-cells = <2>; -- cgit v0.10.2 From 41cd08560bbf8371bbd00e783e992b0dc7e7c83d Mon Sep 17 00:00:00 2001 From: Prabhakar Kushwaha Date: Thu, 28 Apr 2011 12:30:00 +0530 Subject: powerpc/85xx: Create dts of each core in CAMP mode for P1020RDB Create the dts files for each core and splits the devices between the two cores for P1020RDB. Core0 has core0 to have memory, l2, i2c, spi, gpio, tdm, dma, usb, eth1, eth2, sdhc, crypto, global-util, message, pci0, pci1, msi. Core1 has l2, eth0, crypto. MPIC is shared between two cores but each core will protect its interrupts from other core by using "protected-sources" of mpic. Fix compatible property for global-util node of P1020si.dtsi. Signed-off-by: Prabhakar Kushwaha Signed-off-by: Kumar Gala diff --git a/arch/powerpc/boot/dts/p1020rdb_camp_core0.dts b/arch/powerpc/boot/dts/p1020rdb_camp_core0.dts new file mode 100644 index 0000000..f0bf7f4 --- /dev/null +++ b/arch/powerpc/boot/dts/p1020rdb_camp_core0.dts @@ -0,0 +1,213 @@ +/* + * P1020 RDB Core0 Device Tree Source in CAMP mode. + * + * In CAMP mode, each core needs to have its own dts. Only mpic and L2 cache + * can be shared, all the other devices must be assigned to one core only. + * This dts file allows core0 to have memory, l2, i2c, spi, gpio, tdm, dma, usb, + * eth1, eth2, sdhc, crypto, global-util, message, pci0, pci1, msi. + * + * Please note to add "-b 0" for core0's dts compiling. + * + * Copyright 2011 Freescale Semiconductor Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ + +/include/ "p1020si.dtsi" + +/ { + model = "fsl,P1020RDB"; + compatible = "fsl,P1020RDB", "fsl,MPC85XXRDB-CAMP"; + + aliases { + ethernet1 = &enet1; + ethernet2 = &enet2; + serial0 = &serial0; + pci0 = &pci0; + pci1 = &pci1; + }; + + cpus { + PowerPC,P1020@1 { + status = "disabled"; + }; + }; + + memory { + device_type = "memory"; + }; + + localbus@ffe05000 { + status = "disabled"; + }; + + soc@ffe00000 { + i2c@3000 { + rtc@68 { + compatible = "dallas,ds1339"; + reg = <0x68>; + }; + }; + + serial1: serial@4600 { + status = "disabled"; + }; + + spi@7000 { + fsl_m25p80@0 { + #address-cells = <1>; + #size-cells = <1>; + compatible = "fsl,espi-flash"; + reg = <0>; + linux,modalias = "fsl_m25p80"; + spi-max-frequency = <40000000>; + + partition@0 { + /* 512KB for u-boot Bootloader Image */ + reg = <0x0 0x00080000>; + label = "SPI (RO) U-Boot Image"; + read-only; + }; + + partition@80000 { + /* 512KB for DTB Image */ + reg = <0x00080000 0x00080000>; + label = "SPI (RO) DTB Image"; + read-only; + }; + + partition@100000 { + /* 4MB for Linux Kernel Image */ + reg = <0x00100000 0x00400000>; + label = "SPI (RO) Linux Kernel Image"; + read-only; + }; + + partition@500000 { + /* 4MB for Compressed RFS Image */ + reg = <0x00500000 0x00400000>; + label = "SPI (RO) Compressed RFS Image"; + read-only; + }; + + partition@900000 { + /* 7MB for JFFS2 based RFS */ + reg = <0x00900000 0x00700000>; + label = "SPI (RW) JFFS2 RFS"; + }; + }; + }; + + mdio@24000 { + phy0: ethernet-phy@0 { + interrupt-parent = <&mpic>; + interrupts = <3 1>; + reg = <0x0>; + }; + phy1: ethernet-phy@1 { + interrupt-parent = <&mpic>; + interrupts = <2 1>; + reg = <0x1>; + }; + }; + + mdio@25000 { + tbi0: tbi-phy@11 { + reg = <0x11>; + device_type = "tbi-phy"; + }; + }; + + enet0: ethernet@b0000 { + status = "disabled"; + }; + + enet1: ethernet@b1000 { + phy-handle = <&phy0>; + tbi-handle = <&tbi0>; + phy-connection-type = "sgmii"; + }; + + enet2: ethernet@b2000 { + phy-handle = <&phy1>; + phy-connection-type = "rgmii-id"; + }; + + usb@22000 { + phy_type = "ulpi"; + }; + + /* USB2 is shared with localbus, so it must be disabled + by default. We can't put 'status = "disabled";' here + since U-Boot doesn't clear the status property when + it enables USB2. OTOH, U-Boot does create a new node + when there isn't any. So, just comment it out. + usb@23000 { + phy_type = "ulpi"; + }; + */ + + mpic: pic@40000 { + protected-sources = < + 42 29 30 34 /* serial1, enet0-queue-group0 */ + 17 18 24 45 /* enet0-queue-group1, crypto */ + >; + }; + + }; + + pci0: pcie@ffe09000 { + ranges = <0x2000000 0x0 0xa0000000 0 0xa0000000 0x0 0x20000000 + 0x1000000 0x0 0x00000000 0 0xffc10000 0x0 0x10000>; + interrupt-map-mask = <0xf800 0x0 0x0 0x7>; + interrupt-map = < + /* IDSEL 0x0 */ + 0000 0x0 0x0 0x1 &mpic 0x4 0x1 + 0000 0x0 0x0 0x2 &mpic 0x5 0x1 + 0000 0x0 0x0 0x3 &mpic 0x6 0x1 + 0000 0x0 0x0 0x4 &mpic 0x7 0x1 + >; + pcie@0 { + reg = <0x0 0x0 0x0 0x0 0x0>; + #size-cells = <2>; + #address-cells = <3>; + device_type = "pci"; + ranges = <0x2000000 0x0 0xa0000000 + 0x2000000 0x0 0xa0000000 + 0x0 0x20000000 + + 0x1000000 0x0 0x0 + 0x1000000 0x0 0x0 + 0x0 0x100000>; + }; + }; + + pci1: pcie@ffe0a000 { + ranges = <0x2000000 0x0 0x80000000 0 0x80000000 0x0 0x20000000 + 0x1000000 0x0 0x00000000 0 0xffc00000 0x0 0x10000>; + interrupt-map-mask = <0xf800 0x0 0x0 0x7>; + interrupt-map = < + /* IDSEL 0x0 */ + 0000 0x0 0x0 0x1 &mpic 0x0 0x1 + 0000 0x0 0x0 0x2 &mpic 0x1 0x1 + 0000 0x0 0x0 0x3 &mpic 0x2 0x1 + 0000 0x0 0x0 0x4 &mpic 0x3 0x1 + >; + pcie@0 { + reg = <0x0 0x0 0x0 0x0 0x0>; + #size-cells = <2>; + #address-cells = <3>; + device_type = "pci"; + ranges = <0x2000000 0x0 0x80000000 + 0x2000000 0x0 0x80000000 + 0x0 0x20000000 + + 0x1000000 0x0 0x0 + 0x1000000 0x0 0x0 + 0x0 0x100000>; + }; + }; +}; diff --git a/arch/powerpc/boot/dts/p1020rdb_camp_core1.dts b/arch/powerpc/boot/dts/p1020rdb_camp_core1.dts new file mode 100644 index 0000000..6ec0220 --- /dev/null +++ b/arch/powerpc/boot/dts/p1020rdb_camp_core1.dts @@ -0,0 +1,148 @@ +/* + * P1020 RDB Core1 Device Tree Source in CAMP mode. + * + * In CAMP mode, each core needs to have its own dts. Only mpic and L2 cache + * can be shared, all the other devices must be assigned to one core only. + * This dts allows core1 to have l2, eth0, crypto. + * + * Please note to add "-b 1" for core1's dts compiling. + * + * Copyright 2011 Freescale Semiconductor Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ + +/include/ "p1020si.dtsi" + +/ { + model = "fsl,P1020RDB"; + compatible = "fsl,P1020RDB", "fsl,MPC85XXRDB-CAMP"; + + aliases { + ethernet0 = &enet0; + serial0 = &serial1; + }; + + cpus { + PowerPC,P1020@0 { + status = "disabled"; + }; + }; + + memory { + device_type = "memory"; + }; + + localbus@ffe05000 { + status = "disabled"; + }; + + soc@ffe00000 { + ecm-law@0 { + status = "disabled"; + }; + + ecm@1000 { + status = "disabled"; + }; + + memory-controller@2000 { + status = "disabled"; + }; + + i2c@3000 { + status = "disabled"; + }; + + i2c@3100 { + status = "disabled"; + }; + + serial0: serial@4500 { + status = "disabled"; + }; + + spi@7000 { + status = "disabled"; + }; + + gpio: gpio-controller@f000 { + status = "disabled"; + }; + + dma@21300 { + status = "disabled"; + }; + + mdio@24000 { + status = "disabled"; + }; + + mdio@25000 { + status = "disabled"; + }; + + enet0: ethernet@b0000 { + fixed-link = <1 1 1000 0 0>; + phy-connection-type = "rgmii-id"; + + }; + + enet1: ethernet@b1000 { + status = "disabled"; + }; + + enet2: ethernet@b2000 { + status = "disabled"; + }; + + usb@22000 { + status = "disabled"; + }; + + sdhci@2e000 { + status = "disabled"; + }; + + mpic: pic@40000 { + protected-sources = < + 16 /* ecm, mem, L2, pci0, pci1 */ + 43 42 59 /* i2c, serial0, spi */ + 47 63 62 /* gpio, tdm */ + 20 21 22 23 /* dma */ + 03 02 /* mdio */ + 35 36 40 /* enet1-queue-group0 */ + 51 52 67 /* enet1-queue-group1 */ + 31 32 33 /* enet2-queue-group0 */ + 25 26 27 /* enet2-queue-group1 */ + 28 72 58 /* usb, sdhci, crypto */ + 0xb0 0xb1 0xb2 /* message */ + 0xb3 0xb4 0xb5 + 0xb6 0xb7 + 0xe0 0xe1 0xe2 /* msi */ + 0xe3 0xe4 0xe5 + 0xe6 0xe7 /* sdhci, crypto , pci */ + >; + }; + + msi@41600 { + status = "disabled"; + }; + + global-utilities@e0000 { //global utilities block + status = "disabled"; + }; + + }; + + pci0: pcie@ffe09000 { + status = "disabled"; + }; + + pci1: pcie@ffe0a000 { + status = "disabled"; + }; +}; diff --git a/arch/powerpc/boot/dts/p1020si.dtsi b/arch/powerpc/boot/dts/p1020si.dtsi index f6f1100..5c5acb6 100644 --- a/arch/powerpc/boot/dts/p1020si.dtsi +++ b/arch/powerpc/boot/dts/p1020si.dtsi @@ -343,7 +343,7 @@ }; global-utilities@e0000 { //global utilities block - compatible = "fsl,p1020-guts"; + compatible = "fsl,p1020-guts","fsl,p2020-guts"; reg = <0xe0000 0x1000>; fsl,has-rstcr; }; -- cgit v0.10.2 From bbfff72ee3e76bd4712b87386af00bfe97114bc9 Mon Sep 17 00:00:00 2001 From: Dipen Dudhat Date: Thu, 19 May 2011 12:08:23 +0530 Subject: powerpc: Integrated Flash controller device tree bindings Signed-off-by: Dipen Dudhat Acked-By: Scott Wood Signed-off-by: Kumar Gala diff --git a/Documentation/devicetree/bindings/powerpc/fsl/ifc.txt b/Documentation/devicetree/bindings/powerpc/fsl/ifc.txt new file mode 100644 index 0000000..939a26d --- /dev/null +++ b/Documentation/devicetree/bindings/powerpc/fsl/ifc.txt @@ -0,0 +1,76 @@ +Integrated Flash Controller + +Properties: +- name : Should be ifc +- compatible : should contain "fsl,ifc". The version of the integrated + flash controller can be found in the IFC_REV register at + offset zero. + +- #address-cells : Should be either two or three. The first cell is the + chipselect number, and the remaining cells are the + offset into the chipselect. +- #size-cells : Either one or two, depending on how large each chipselect + can be. +- reg : Offset and length of the register set for the device +- interrupts : IFC has two interrupts. The first one is the "common" + interrupt(CM_EVTER_STAT), and second is the NAND interrupt + (NAND_EVTER_STAT). + +- ranges : Each range corresponds to a single chipselect, and covers + the entire access window as configured. + +Child device nodes describe the devices connected to IFC such as NOR (e.g. +cfi-flash) and NAND (fsl,ifc-nand). There might be board specific devices +like FPGAs, CPLDs, etc. + +Example: + + ifc@ffe1e000 { + compatible = "fsl,ifc", "simple-bus"; + #address-cells = <2>; + #size-cells = <1>; + reg = <0x0 0xffe1e000 0 0x2000>; + interrupts = <16 2 19 2>; + + /* NOR, NAND Flashes and CPLD on board */ + ranges = <0x0 0x0 0x0 0xee000000 0x02000000 + 0x1 0x0 0x0 0xffa00000 0x00010000 + 0x3 0x0 0x0 0xffb00000 0x00020000>; + + flash@0,0 { + #address-cells = <1>; + #size-cells = <1>; + compatible = "cfi-flash"; + reg = <0x0 0x0 0x2000000>; + bank-width = <2>; + device-width = <1>; + + partition@0 { + /* 32MB for user data */ + reg = <0x0 0x02000000>; + label = "NOR Data"; + }; + }; + + flash@1,0 { + #address-cells = <1>; + #size-cells = <1>; + compatible = "fsl,ifc-nand"; + reg = <0x1 0x0 0x10000>; + + partition@0 { + /* This location must not be altered */ + /* 1MB for u-boot Bootloader Image */ + reg = <0x0 0x00100000>; + label = "NAND U-Boot Image"; + read-only; + }; + }; + + cpld@3,0 { + #address-cells = <1>; + #size-cells = <1>; + compatible = "fsl,p1010rdb-cpld"; + reg = <0x3 0x0 0x000001f>; + }; + }; -- cgit v0.10.2 From 41fb5e62604c5ddd00a784ffb7672dd8df5d76f2 Mon Sep 17 00:00:00 2001 From: Milton Miller Date: Tue, 10 May 2011 19:30:44 +0000 Subject: powerpc: Make IRQ_NOREQUEST last to clear, first to set When creating an irq, don't allow a concurent driver request until we have caled map, which will likley call set_chip_and_handler to change the irq_chip and its operations. Similarly, when tearing down an IRQ, make sure no new uses come along while we change the irq back to the nop chip and then reset the descriptor to freed status. Signed-off-by: Milton Miller Signed-off-by: Benjamin Herrenschmidt diff --git a/arch/powerpc/kernel/irq.c b/arch/powerpc/kernel/irq.c index 4368b5e..a24d37d 100644 --- a/arch/powerpc/kernel/irq.c +++ b/arch/powerpc/kernel/irq.c @@ -586,14 +586,14 @@ struct irq_host *irq_alloc_host(struct device_node *of_node, irq_map[i].host = host; smp_wmb(); - /* Clear norequest flags */ - irq_clear_status_flags(i, IRQ_NOREQUEST); - /* Legacy flags are left to default at this point, * one can then use irq_create_mapping() to * explicitly change them */ ops->map(host, i, i); + + /* Clear norequest flags */ + irq_clear_status_flags(i, IRQ_NOREQUEST); } break; case IRQ_HOST_MAP_LINEAR: @@ -664,8 +664,6 @@ static int irq_setup_virq(struct irq_host *host, unsigned int virq, goto error; } - irq_clear_status_flags(virq, IRQ_NOREQUEST); - /* map it */ smp_wmb(); irq_map[virq].hwirq = hwirq; @@ -676,6 +674,8 @@ static int irq_setup_virq(struct irq_host *host, unsigned int virq, goto errdesc; } + irq_clear_status_flags(virq, IRQ_NOREQUEST); + return 0; errdesc: @@ -819,6 +819,8 @@ void irq_dispose_mapping(unsigned int virq) if (host->revmap_type == IRQ_HOST_MAP_LEGACY) return; + irq_set_status_flags(virq, IRQ_NOREQUEST); + /* remove chip and handler */ irq_set_chip_and_handler(virq, NULL, NULL); @@ -848,8 +850,6 @@ void irq_dispose_mapping(unsigned int virq) smp_mb(); irq_map[virq].hwirq = host->inval_irq; - irq_set_status_flags(virq, IRQ_NOREQUEST); - irq_free_descs(virq, 1); /* Free it */ irq_free_virt(virq, 1); -- cgit v0.10.2 From c186f0e177275e83728d7acfdf4a1b68793a7038 Mon Sep 17 00:00:00 2001 From: Ira Snyder Date: Fri, 11 Feb 2011 13:34:29 +0000 Subject: misc: Add CARMA DATA-FPGA Access Driver This driver allows userspace to access the data processing FPGAs on the OVRO CARMA board. It has two modes of operation: 1) random access This allows users to poke any DATA-FPGA registers by using mmap to map the address region directly into their memory map. 2) correlation dumping When correlating, the DATA-FPGA's have special requirements for getting the data out of their memory before the next correlation. This nominally happens at 64Hz (every 15.625ms). If the data is not dumped before the next correlation, data is lost. The data dumping driver handles buffering up to 1 second worth of correlation data from the FPGAs. This lowers the realtime scheduling requirements for the userspace process reading the device. Signed-off-by: Ira W. Snyder Signed-off-by: Benjamin Herrenschmidt diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig index 4e007c6..d80dcde 100644 --- a/drivers/misc/Kconfig +++ b/drivers/misc/Kconfig @@ -481,5 +481,6 @@ source "drivers/misc/cb710/Kconfig" source "drivers/misc/iwmc3200top/Kconfig" source "drivers/misc/ti-st/Kconfig" source "drivers/misc/lis3lv02d/Kconfig" +source "drivers/misc/carma/Kconfig" endif # MISC_DEVICES diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile index f546860..848e846 100644 --- a/drivers/misc/Makefile +++ b/drivers/misc/Makefile @@ -44,3 +44,4 @@ obj-$(CONFIG_PCH_PHUB) += pch_phub.o obj-y += ti-st/ obj-$(CONFIG_AB8500_PWM) += ab8500-pwm.o obj-y += lis3lv02d/ +obj-y += carma/ diff --git a/drivers/misc/carma/Kconfig b/drivers/misc/carma/Kconfig new file mode 100644 index 0000000..4be183f --- /dev/null +++ b/drivers/misc/carma/Kconfig @@ -0,0 +1,9 @@ +config CARMA_FPGA + tristate "CARMA DATA-FPGA Access Driver" + depends on FSL_SOC && PPC_83xx && MEDIA_SUPPORT && HAS_DMA && FSL_DMA + select VIDEOBUF_DMA_SG + default n + help + Say Y here to include support for communicating with the data + processing FPGAs on the OVRO CARMA board. + diff --git a/drivers/misc/carma/Makefile b/drivers/misc/carma/Makefile new file mode 100644 index 0000000..0b69fa7 --- /dev/null +++ b/drivers/misc/carma/Makefile @@ -0,0 +1 @@ +obj-$(CONFIG_CARMA_FPGA) += carma-fpga.o diff --git a/drivers/misc/carma/carma-fpga.c b/drivers/misc/carma/carma-fpga.c new file mode 100644 index 0000000..3965821 --- /dev/null +++ b/drivers/misc/carma/carma-fpga.c @@ -0,0 +1,1433 @@ +/* + * CARMA DATA-FPGA Access Driver + * + * Copyright (c) 2009-2011 Ira W. Snyder + * + * 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. + */ + +/* + * FPGA Memory Dump Format + * + * FPGA #0 control registers (32 x 32-bit words) + * FPGA #1 control registers (32 x 32-bit words) + * FPGA #2 control registers (32 x 32-bit words) + * FPGA #3 control registers (32 x 32-bit words) + * SYSFPGA control registers (32 x 32-bit words) + * FPGA #0 correlation array (NUM_CORL0 correlation blocks) + * FPGA #1 correlation array (NUM_CORL1 correlation blocks) + * FPGA #2 correlation array (NUM_CORL2 correlation blocks) + * FPGA #3 correlation array (NUM_CORL3 correlation blocks) + * + * Each correlation array consists of: + * + * Correlation Data (2 x NUM_LAGSn x 32-bit words) + * Pipeline Metadata (2 x NUM_METAn x 32-bit words) + * Quantization Counters (2 x NUM_QCNTn x 32-bit words) + * + * The NUM_CORLn, NUM_LAGSn, NUM_METAn, and NUM_QCNTn values come from + * the FPGA configuration registers. They do not change once the FPGA's + * have been programmed, they only change on re-programming. + */ + +/* + * Basic Description: + * + * This driver is used to capture correlation spectra off of the four data + * processing FPGAs. The FPGAs are often reprogrammed at runtime, therefore + * this driver supports dynamic enable/disable of capture while the device + * remains open. + * + * The nominal capture rate is 64Hz (every 15.625ms). To facilitate this fast + * capture rate, all buffers are pre-allocated to avoid any potentially long + * running memory allocations while capturing. + * + * There are two lists and one pointer which are used to keep track of the + * different states of data buffers. + * + * 1) free list + * This list holds all empty data buffers which are ready to receive data. + * + * 2) inflight pointer + * This pointer holds the currently inflight data buffer. This buffer is having + * data copied into it by the DMA engine. + * + * 3) used list + * This list holds data buffers which have been filled, and are waiting to be + * read by userspace. + * + * All buffers start life on the free list, then move successively to the + * inflight pointer, and then to the used list. After they have been read by + * userspace, they are moved back to the free list. The cycle repeats as long + * as necessary. + * + * It should be noted that all buffers are mapped and ready for DMA when they + * are on any of the three lists. They are only unmapped when they are in the + * process of being read by userspace. + */ + +/* + * Notes on the IRQ masking scheme: + * + * The IRQ masking scheme here is different than most other hardware. The only + * way for the DATA-FPGAs to detect if the kernel has taken too long to copy + * the data is if the status registers are not cleared before the next + * correlation data dump is ready. + * + * The interrupt line is connected to the status registers, such that when they + * are cleared, the interrupt is de-asserted. Therein lies our problem. We need + * to schedule a long-running DMA operation and return from the interrupt + * handler quickly, but we cannot clear the status registers. + * + * To handle this, the system controller FPGA has the capability to connect the + * interrupt line to a user-controlled GPIO pin. This pin is driven high + * (unasserted) and left that way. To mask the interrupt, we change the + * interrupt source to the GPIO pin. Tada, we hid the interrupt. :) + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +/* system controller registers */ +#define SYS_IRQ_SOURCE_CTL 0x24 +#define SYS_IRQ_OUTPUT_EN 0x28 +#define SYS_IRQ_OUTPUT_DATA 0x2C +#define SYS_IRQ_INPUT_DATA 0x30 +#define SYS_FPGA_CONFIG_STATUS 0x44 + +/* GPIO IRQ line assignment */ +#define IRQ_CORL_DONE 0x10 + +/* FPGA registers */ +#define MMAP_REG_VERSION 0x00 +#define MMAP_REG_CORL_CONF1 0x08 +#define MMAP_REG_CORL_CONF2 0x0C +#define MMAP_REG_STATUS 0x48 + +#define SYS_FPGA_BLOCK 0xF0000000 + +#define DATA_FPGA_START 0x400000 +#define DATA_FPGA_SIZE 0x80000 + +static const char drv_name[] = "carma-fpga"; + +#define NUM_FPGA 4 + +#define MIN_DATA_BUFS 8 +#define MAX_DATA_BUFS 64 + +struct fpga_info { + unsigned int num_lag_ram; + unsigned int blk_size; +}; + +struct data_buf { + struct list_head entry; + struct videobuf_dmabuf vb; + size_t size; +}; + +struct fpga_device { + /* character device */ + struct miscdevice miscdev; + struct device *dev; + struct mutex mutex; + + /* reference count */ + struct kref ref; + + /* FPGA registers and information */ + struct fpga_info info[NUM_FPGA]; + void __iomem *regs; + int irq; + + /* FPGA Physical Address/Size Information */ + resource_size_t phys_addr; + size_t phys_size; + + /* DMA structures */ + struct sg_table corl_table; + unsigned int corl_nents; + struct dma_chan *chan; + + /* Protection for all members below */ + spinlock_t lock; + + /* Device enable/disable flag */ + bool enabled; + + /* Correlation data buffers */ + wait_queue_head_t wait; + struct list_head free; + struct list_head used; + struct data_buf *inflight; + + /* Information about data buffers */ + unsigned int num_dropped; + unsigned int num_buffers; + size_t bufsize; + struct dentry *dbg_entry; +}; + +struct fpga_reader { + struct fpga_device *priv; + struct data_buf *buf; + off_t buf_start; +}; + +static void fpga_device_release(struct kref *ref) +{ + struct fpga_device *priv = container_of(ref, struct fpga_device, ref); + + /* the last reader has exited, cleanup the last bits */ + mutex_destroy(&priv->mutex); + kfree(priv); +} + +/* + * Data Buffer Allocation Helpers + */ + +/** + * data_free_buffer() - free a single data buffer and all allocated memory + * @buf: the buffer to free + * + * This will free all of the pages allocated to the given data buffer, and + * then free the structure itself + */ +static void data_free_buffer(struct data_buf *buf) +{ + /* It is ok to free a NULL buffer */ + if (!buf) + return; + + /* free all memory */ + videobuf_dma_free(&buf->vb); + kfree(buf); +} + +/** + * data_alloc_buffer() - allocate and fill a data buffer with pages + * @bytes: the number of bytes required + * + * This allocates all space needed for a data buffer. It must be mapped before + * use in a DMA transaction using videobuf_dma_map(). + * + * Returns NULL on failure + */ +static struct data_buf *data_alloc_buffer(const size_t bytes) +{ + unsigned int nr_pages; + struct data_buf *buf; + int ret; + + /* calculate the number of pages necessary */ + nr_pages = DIV_ROUND_UP(bytes, PAGE_SIZE); + + /* allocate the buffer structure */ + buf = kzalloc(sizeof(*buf), GFP_KERNEL); + if (!buf) + goto out_return; + + /* initialize internal fields */ + INIT_LIST_HEAD(&buf->entry); + buf->size = bytes; + + /* allocate the videobuf */ + videobuf_dma_init(&buf->vb); + ret = videobuf_dma_init_kernel(&buf->vb, DMA_FROM_DEVICE, nr_pages); + if (ret) + goto out_free_buf; + + return buf; + +out_free_buf: + kfree(buf); +out_return: + return NULL; +} + +/** + * data_free_buffers() - free all allocated buffers + * @priv: the driver's private data structure + * + * Free all buffers allocated by the driver (except those currently in the + * process of being read by userspace). + * + * LOCKING: must hold dev->mutex + * CONTEXT: user + */ +static void data_free_buffers(struct fpga_device *priv) +{ + struct data_buf *buf, *tmp; + + /* the device should be stopped, no DMA in progress */ + BUG_ON(priv->inflight != NULL); + + list_for_each_entry_safe(buf, tmp, &priv->free, entry) { + list_del_init(&buf->entry); + videobuf_dma_unmap(priv->dev, &buf->vb); + data_free_buffer(buf); + } + + list_for_each_entry_safe(buf, tmp, &priv->used, entry) { + list_del_init(&buf->entry); + videobuf_dma_unmap(priv->dev, &buf->vb); + data_free_buffer(buf); + } + + priv->num_buffers = 0; + priv->bufsize = 0; +} + +/** + * data_alloc_buffers() - allocate 1 seconds worth of data buffers + * @priv: the driver's private data structure + * + * Allocate enough buffers for a whole second worth of data + * + * This routine will attempt to degrade nicely by succeeding even if a full + * second worth of data buffers could not be allocated, as long as a minimum + * number were allocated. In this case, it will print a message to the kernel + * log. + * + * The device must not be modifying any lists when this is called. + * + * CONTEXT: user + * LOCKING: must hold dev->mutex + * + * Returns 0 on success, -ERRNO otherwise + */ +static int data_alloc_buffers(struct fpga_device *priv) +{ + struct data_buf *buf; + int i, ret; + + for (i = 0; i < MAX_DATA_BUFS; i++) { + + /* allocate a buffer */ + buf = data_alloc_buffer(priv->bufsize); + if (!buf) + break; + + /* map it for DMA */ + ret = videobuf_dma_map(priv->dev, &buf->vb); + if (ret) { + data_free_buffer(buf); + break; + } + + /* add it to the list of free buffers */ + list_add_tail(&buf->entry, &priv->free); + priv->num_buffers++; + } + + /* Make sure we allocated the minimum required number of buffers */ + if (priv->num_buffers < MIN_DATA_BUFS) { + dev_err(priv->dev, "Unable to allocate enough data buffers\n"); + data_free_buffers(priv); + return -ENOMEM; + } + + /* Warn if we are running in a degraded state, but do not fail */ + if (priv->num_buffers < MAX_DATA_BUFS) { + dev_warn(priv->dev, + "Unable to allocate %d buffers, using %d buffers instead\n", + MAX_DATA_BUFS, i); + } + + return 0; +} + +/* + * DMA Operations Helpers + */ + +/** + * fpga_start_addr() - get the physical address a DATA-FPGA + * @priv: the driver's private data structure + * @fpga: the DATA-FPGA number (zero based) + */ +static dma_addr_t fpga_start_addr(struct fpga_device *priv, unsigned int fpga) +{ + return priv->phys_addr + 0x400000 + (0x80000 * fpga); +} + +/** + * fpga_block_addr() - get the physical address of a correlation data block + * @priv: the driver's private data structure + * @fpga: the DATA-FPGA number (zero based) + * @blknum: the correlation block number (zero based) + */ +static dma_addr_t fpga_block_addr(struct fpga_device *priv, unsigned int fpga, + unsigned int blknum) +{ + return fpga_start_addr(priv, fpga) + (0x10000 * (1 + blknum)); +} + +#define REG_BLOCK_SIZE (32 * 4) + +/** + * data_setup_corl_table() - create the scatterlist for correlation dumps + * @priv: the driver's private data structure + * + * Create the scatterlist for transferring a correlation dump from the + * DATA FPGAs. This structure will be reused for each buffer than needs + * to be filled with correlation data. + * + * Returns 0 on success, -ERRNO otherwise + */ +static int data_setup_corl_table(struct fpga_device *priv) +{ + struct sg_table *table = &priv->corl_table; + struct scatterlist *sg; + struct fpga_info *info; + int i, j, ret; + + /* Calculate the number of entries needed */ + priv->corl_nents = (1 + NUM_FPGA) * REG_BLOCK_SIZE; + for (i = 0; i < NUM_FPGA; i++) + priv->corl_nents += priv->info[i].num_lag_ram; + + /* Allocate the scatterlist table */ + ret = sg_alloc_table(table, priv->corl_nents, GFP_KERNEL); + if (ret) { + dev_err(priv->dev, "unable to allocate DMA table\n"); + return ret; + } + + /* Add the DATA FPGA registers to the scatterlist */ + sg = table->sgl; + for (i = 0; i < NUM_FPGA; i++) { + sg_dma_address(sg) = fpga_start_addr(priv, i); + sg_dma_len(sg) = REG_BLOCK_SIZE; + sg = sg_next(sg); + } + + /* Add the SYS-FPGA registers to the scatterlist */ + sg_dma_address(sg) = SYS_FPGA_BLOCK; + sg_dma_len(sg) = REG_BLOCK_SIZE; + sg = sg_next(sg); + + /* Add the FPGA correlation data blocks to the scatterlist */ + for (i = 0; i < NUM_FPGA; i++) { + info = &priv->info[i]; + for (j = 0; j < info->num_lag_ram; j++) { + sg_dma_address(sg) = fpga_block_addr(priv, i, j); + sg_dma_len(sg) = info->blk_size; + sg = sg_next(sg); + } + } + + /* + * All physical addresses and lengths are present in the structure + * now. It can be reused for every FPGA DATA interrupt + */ + return 0; +} + +/* + * FPGA Register Access Helpers + */ + +static void fpga_write_reg(struct fpga_device *priv, unsigned int fpga, + unsigned int reg, u32 val) +{ + const int fpga_start = DATA_FPGA_START + (fpga * DATA_FPGA_SIZE); + iowrite32be(val, priv->regs + fpga_start + reg); +} + +static u32 fpga_read_reg(struct fpga_device *priv, unsigned int fpga, + unsigned int reg) +{ + const int fpga_start = DATA_FPGA_START + (fpga * DATA_FPGA_SIZE); + return ioread32be(priv->regs + fpga_start + reg); +} + +/** + * data_calculate_bufsize() - calculate the data buffer size required + * @priv: the driver's private data structure + * + * Calculate the total buffer size needed to hold a single block + * of correlation data + * + * CONTEXT: user + * + * Returns 0 on success, -ERRNO otherwise + */ +static int data_calculate_bufsize(struct fpga_device *priv) +{ + u32 num_corl, num_lags, num_meta, num_qcnt, num_pack; + u32 conf1, conf2, version; + u32 num_lag_ram, blk_size; + int i; + + /* Each buffer starts with the 5 FPGA register areas */ + priv->bufsize = (1 + NUM_FPGA) * REG_BLOCK_SIZE; + + /* Read and store the configuration data for each FPGA */ + for (i = 0; i < NUM_FPGA; i++) { + version = fpga_read_reg(priv, i, MMAP_REG_VERSION); + conf1 = fpga_read_reg(priv, i, MMAP_REG_CORL_CONF1); + conf2 = fpga_read_reg(priv, i, MMAP_REG_CORL_CONF2); + + /* minor version 2 and later */ + if ((version & 0x000000FF) >= 2) { + num_corl = (conf1 & 0x000000F0) >> 4; + num_pack = (conf1 & 0x00000F00) >> 8; + num_lags = (conf1 & 0x00FFF000) >> 12; + num_meta = (conf1 & 0x7F000000) >> 24; + num_qcnt = (conf2 & 0x00000FFF) >> 0; + } else { + num_corl = (conf1 & 0x000000F0) >> 4; + num_pack = 1; /* implied */ + num_lags = (conf1 & 0x000FFF00) >> 8; + num_meta = (conf1 & 0x7FF00000) >> 20; + num_qcnt = (conf2 & 0x00000FFF) >> 0; + } + + num_lag_ram = (num_corl + num_pack - 1) / num_pack; + blk_size = ((num_pack * num_lags) + num_meta + num_qcnt) * 8; + + priv->info[i].num_lag_ram = num_lag_ram; + priv->info[i].blk_size = blk_size; + priv->bufsize += num_lag_ram * blk_size; + + dev_dbg(priv->dev, "FPGA %d NUM_CORL: %d\n", i, num_corl); + dev_dbg(priv->dev, "FPGA %d NUM_PACK: %d\n", i, num_pack); + dev_dbg(priv->dev, "FPGA %d NUM_LAGS: %d\n", i, num_lags); + dev_dbg(priv->dev, "FPGA %d NUM_META: %d\n", i, num_meta); + dev_dbg(priv->dev, "FPGA %d NUM_QCNT: %d\n", i, num_qcnt); + dev_dbg(priv->dev, "FPGA %d BLK_SIZE: %d\n", i, blk_size); + } + + dev_dbg(priv->dev, "TOTAL BUFFER SIZE: %zu bytes\n", priv->bufsize); + return 0; +} + +/* + * Interrupt Handling + */ + +/** + * data_disable_interrupts() - stop the device from generating interrupts + * @priv: the driver's private data structure + * + * Hide interrupts by switching to GPIO interrupt source + * + * LOCKING: must hold dev->lock + */ +static void data_disable_interrupts(struct fpga_device *priv) +{ + /* hide the interrupt by switching the IRQ driver to GPIO */ + iowrite32be(0x2F, priv->regs + SYS_IRQ_SOURCE_CTL); +} + +/** + * data_enable_interrupts() - allow the device to generate interrupts + * @priv: the driver's private data structure + * + * Unhide interrupts by switching to the FPGA interrupt source. At the + * same time, clear the DATA-FPGA status registers. + * + * LOCKING: must hold dev->lock + */ +static void data_enable_interrupts(struct fpga_device *priv) +{ + /* clear the actual FPGA corl_done interrupt */ + fpga_write_reg(priv, 0, MMAP_REG_STATUS, 0x0); + fpga_write_reg(priv, 1, MMAP_REG_STATUS, 0x0); + fpga_write_reg(priv, 2, MMAP_REG_STATUS, 0x0); + fpga_write_reg(priv, 3, MMAP_REG_STATUS, 0x0); + + /* flush the writes */ + fpga_read_reg(priv, 0, MMAP_REG_STATUS); + + /* switch back to the external interrupt source */ + iowrite32be(0x3F, priv->regs + SYS_IRQ_SOURCE_CTL); +} + +/** + * data_dma_cb() - DMAEngine callback for DMA completion + * @data: the driver's private data structure + * + * Complete a DMA transfer from the DATA-FPGA's + * + * This is called via the DMA callback mechanism, and will handle moving the + * completed DMA transaction to the used list, and then wake any processes + * waiting for new data + * + * CONTEXT: any, softirq expected + */ +static void data_dma_cb(void *data) +{ + struct fpga_device *priv = data; + unsigned long flags; + + spin_lock_irqsave(&priv->lock, flags); + + /* If there is no inflight buffer, we've got a bug */ + BUG_ON(priv->inflight == NULL); + + /* Move the inflight buffer onto the used list */ + list_move_tail(&priv->inflight->entry, &priv->used); + priv->inflight = NULL; + + /* clear the FPGA status and re-enable interrupts */ + data_enable_interrupts(priv); + + spin_unlock_irqrestore(&priv->lock, flags); + + /* + * We've changed both the inflight and used lists, so we need + * to wake up any processes that are blocking for those events + */ + wake_up(&priv->wait); +} + +/** + * data_submit_dma() - prepare and submit the required DMA to fill a buffer + * @priv: the driver's private data structure + * @buf: the data buffer + * + * Prepare and submit the necessary DMA transactions to fill a correlation + * data buffer. + * + * LOCKING: must hold dev->lock + * CONTEXT: hardirq only + * + * Returns 0 on success, -ERRNO otherwise + */ +static int data_submit_dma(struct fpga_device *priv, struct data_buf *buf) +{ + struct scatterlist *dst_sg, *src_sg; + unsigned int dst_nents, src_nents; + struct dma_chan *chan = priv->chan; + struct dma_async_tx_descriptor *tx; + dma_cookie_t cookie; + dma_addr_t dst, src; + + dst_sg = buf->vb.sglist; + dst_nents = buf->vb.sglen; + + src_sg = priv->corl_table.sgl; + src_nents = priv->corl_nents; + + /* + * All buffers passed to this function should be ready and mapped + * for DMA already. Therefore, we don't need to do anything except + * submit it to the Freescale DMA Engine for processing + */ + + /* setup the scatterlist to scatterlist transfer */ + tx = chan->device->device_prep_dma_sg(chan, + dst_sg, dst_nents, + src_sg, src_nents, + 0); + if (!tx) { + dev_err(priv->dev, "unable to prep scatterlist DMA\n"); + return -ENOMEM; + } + + /* submit the transaction to the DMA controller */ + cookie = tx->tx_submit(tx); + if (dma_submit_error(cookie)) { + dev_err(priv->dev, "unable to submit scatterlist DMA\n"); + return -ENOMEM; + } + + /* Prepare the re-read of the SYS-FPGA block */ + dst = sg_dma_address(dst_sg) + (NUM_FPGA * REG_BLOCK_SIZE); + src = SYS_FPGA_BLOCK; + tx = chan->device->device_prep_dma_memcpy(chan, dst, src, + REG_BLOCK_SIZE, + DMA_PREP_INTERRUPT); + if (!tx) { + dev_err(priv->dev, "unable to prep SYS-FPGA DMA\n"); + return -ENOMEM; + } + + /* Setup the callback */ + tx->callback = data_dma_cb; + tx->callback_param = priv; + + /* submit the transaction to the DMA controller */ + cookie = tx->tx_submit(tx); + if (dma_submit_error(cookie)) { + dev_err(priv->dev, "unable to submit SYS-FPGA DMA\n"); + return -ENOMEM; + } + + return 0; +} + +#define CORL_DONE 0x1 +#define CORL_ERR 0x2 + +static irqreturn_t data_irq(int irq, void *dev_id) +{ + struct fpga_device *priv = dev_id; + bool submitted = false; + struct data_buf *buf; + u32 status; + int i; + + /* detect spurious interrupts via FPGA status */ + for (i = 0; i < 4; i++) { + status = fpga_read_reg(priv, i, MMAP_REG_STATUS); + if (!(status & (CORL_DONE | CORL_ERR))) { + dev_err(priv->dev, "spurious irq detected (FPGA)\n"); + return IRQ_NONE; + } + } + + /* detect spurious interrupts via raw IRQ pin readback */ + status = ioread32be(priv->regs + SYS_IRQ_INPUT_DATA); + if (status & IRQ_CORL_DONE) { + dev_err(priv->dev, "spurious irq detected (IRQ)\n"); + return IRQ_NONE; + } + + spin_lock(&priv->lock); + + /* hide the interrupt by switching the IRQ driver to GPIO */ + data_disable_interrupts(priv); + + /* If there are no free buffers, drop this data */ + if (list_empty(&priv->free)) { + priv->num_dropped++; + goto out; + } + + buf = list_first_entry(&priv->free, struct data_buf, entry); + list_del_init(&buf->entry); + BUG_ON(buf->size != priv->bufsize); + + /* Submit a DMA transfer to get the correlation data */ + if (data_submit_dma(priv, buf)) { + dev_err(priv->dev, "Unable to setup DMA transfer\n"); + list_move_tail(&buf->entry, &priv->free); + goto out; + } + + /* Save the buffer for the DMA callback */ + priv->inflight = buf; + submitted = true; + + /* Start the DMA Engine */ + dma_async_memcpy_issue_pending(priv->chan); + +out: + /* If no DMA was submitted, re-enable interrupts */ + if (!submitted) + data_enable_interrupts(priv); + + spin_unlock(&priv->lock); + return IRQ_HANDLED; +} + +/* + * Realtime Device Enable Helpers + */ + +/** + * data_device_enable() - enable the device for buffered dumping + * @priv: the driver's private data structure + * + * Enable the device for buffered dumping. Allocates buffers and hooks up + * the interrupt handler. When this finishes, data will come pouring in. + * + * LOCKING: must hold dev->mutex + * CONTEXT: user context only + * + * Returns 0 on success, -ERRNO otherwise + */ +static int data_device_enable(struct fpga_device *priv) +{ + u32 val; + int ret; + + /* multiple enables are safe: they do nothing */ + if (priv->enabled) + return 0; + + /* check that the FPGAs are programmed */ + val = ioread32be(priv->regs + SYS_FPGA_CONFIG_STATUS); + if (!(val & (1 << 18))) { + dev_err(priv->dev, "DATA-FPGAs are not enabled\n"); + return -ENODATA; + } + + /* read the FPGAs to calculate the buffer size */ + ret = data_calculate_bufsize(priv); + if (ret) { + dev_err(priv->dev, "unable to calculate buffer size\n"); + goto out_error; + } + + /* allocate the correlation data buffers */ + ret = data_alloc_buffers(priv); + if (ret) { + dev_err(priv->dev, "unable to allocate buffers\n"); + goto out_error; + } + + /* setup the source scatterlist for dumping correlation data */ + ret = data_setup_corl_table(priv); + if (ret) { + dev_err(priv->dev, "unable to setup correlation DMA table\n"); + goto out_error; + } + + /* hookup the irq handler */ + ret = request_irq(priv->irq, data_irq, IRQF_SHARED, drv_name, priv); + if (ret) { + dev_err(priv->dev, "unable to request IRQ handler\n"); + goto out_error; + } + + /* switch to the external FPGA IRQ line */ + data_enable_interrupts(priv); + + /* success, we're enabled */ + priv->enabled = true; + return 0; + +out_error: + sg_free_table(&priv->corl_table); + priv->corl_nents = 0; + + data_free_buffers(priv); + return ret; +} + +/** + * data_device_disable() - disable the device for buffered dumping + * @priv: the driver's private data structure + * + * Disable the device for buffered dumping. Stops new DMA transactions from + * being generated, waits for all outstanding DMA to complete, and then frees + * all buffers. + * + * LOCKING: must hold dev->mutex + * CONTEXT: user only + * + * Returns 0 on success, -ERRNO otherwise + */ +static int data_device_disable(struct fpga_device *priv) +{ + int ret; + + /* allow multiple disable */ + if (!priv->enabled) + return 0; + + /* switch to the internal GPIO IRQ line */ + data_disable_interrupts(priv); + + /* unhook the irq handler */ + free_irq(priv->irq, priv); + + /* + * wait for all outstanding DMA to complete + * + * Device interrupts are disabled, therefore another buffer cannot + * be marked inflight. + */ + ret = wait_event_interruptible(priv->wait, priv->inflight == NULL); + if (ret) + return ret; + + /* free the correlation table */ + sg_free_table(&priv->corl_table); + priv->corl_nents = 0; + + /* + * We are taking the spinlock not to protect priv->enabled, but instead + * to make sure that there are no readers in the process of altering + * the free or used lists while we are setting this flag. + */ + spin_lock_irq(&priv->lock); + priv->enabled = false; + spin_unlock_irq(&priv->lock); + + /* free all buffers: the free and used lists are not being changed */ + data_free_buffers(priv); + return 0; +} + +/* + * DEBUGFS Interface + */ +#ifdef CONFIG_DEBUG_FS + +/* + * Count the number of entries in the given list + */ +static unsigned int list_num_entries(struct list_head *list) +{ + struct list_head *entry; + unsigned int ret = 0; + + list_for_each(entry, list) + ret++; + + return ret; +} + +static int data_debug_show(struct seq_file *f, void *offset) +{ + struct fpga_device *priv = f->private; + int ret; + + /* + * Lock the mutex first, so that we get an accurate value for enable + * Lock the spinlock next, to get accurate list counts + */ + ret = mutex_lock_interruptible(&priv->mutex); + if (ret) + return ret; + + spin_lock_irq(&priv->lock); + + seq_printf(f, "enabled: %d\n", priv->enabled); + seq_printf(f, "bufsize: %d\n", priv->bufsize); + seq_printf(f, "num_buffers: %d\n", priv->num_buffers); + seq_printf(f, "num_free: %d\n", list_num_entries(&priv->free)); + seq_printf(f, "inflight: %d\n", priv->inflight != NULL); + seq_printf(f, "num_used: %d\n", list_num_entries(&priv->used)); + seq_printf(f, "num_dropped: %d\n", priv->num_dropped); + + spin_unlock_irq(&priv->lock); + mutex_unlock(&priv->mutex); + return 0; +} + +static int data_debug_open(struct inode *inode, struct file *file) +{ + return single_open(file, data_debug_show, inode->i_private); +} + +static const struct file_operations data_debug_fops = { + .owner = THIS_MODULE, + .open = data_debug_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + +static int data_debugfs_init(struct fpga_device *priv) +{ + priv->dbg_entry = debugfs_create_file(drv_name, S_IRUGO, NULL, priv, + &data_debug_fops); + if (IS_ERR(priv->dbg_entry)) + return PTR_ERR(priv->dbg_entry); + + return 0; +} + +static void data_debugfs_exit(struct fpga_device *priv) +{ + debugfs_remove(priv->dbg_entry); +} + +#else + +static inline int data_debugfs_init(struct fpga_device *priv) +{ + return 0; +} + +static inline void data_debugfs_exit(struct fpga_device *priv) +{ +} + +#endif /* CONFIG_DEBUG_FS */ + +/* + * SYSFS Attributes + */ + +static ssize_t data_en_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct fpga_device *priv = dev_get_drvdata(dev); + return snprintf(buf, PAGE_SIZE, "%u\n", priv->enabled); +} + +static ssize_t data_en_set(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct fpga_device *priv = dev_get_drvdata(dev); + unsigned long enable; + int ret; + + ret = strict_strtoul(buf, 0, &enable); + if (ret) { + dev_err(priv->dev, "unable to parse enable input\n"); + return -EINVAL; + } + + ret = mutex_lock_interruptible(&priv->mutex); + if (ret) + return ret; + + if (enable) + ret = data_device_enable(priv); + else + ret = data_device_disable(priv); + + if (ret) { + dev_err(priv->dev, "device %s failed\n", + enable ? "enable" : "disable"); + count = ret; + goto out_unlock; + } + +out_unlock: + mutex_unlock(&priv->mutex); + return count; +} + +static DEVICE_ATTR(enable, S_IWUSR | S_IRUGO, data_en_show, data_en_set); + +static struct attribute *data_sysfs_attrs[] = { + &dev_attr_enable.attr, + NULL, +}; + +static const struct attribute_group rt_sysfs_attr_group = { + .attrs = data_sysfs_attrs, +}; + +/* + * FPGA Realtime Data Character Device + */ + +static int data_open(struct inode *inode, struct file *filp) +{ + /* + * The miscdevice layer puts our struct miscdevice into the + * filp->private_data field. We use this to find our private + * data and then overwrite it with our own private structure. + */ + struct fpga_device *priv = container_of(filp->private_data, + struct fpga_device, miscdev); + struct fpga_reader *reader; + int ret; + + /* allocate private data */ + reader = kzalloc(sizeof(*reader), GFP_KERNEL); + if (!reader) + return -ENOMEM; + + reader->priv = priv; + reader->buf = NULL; + + filp->private_data = reader; + ret = nonseekable_open(inode, filp); + if (ret) { + dev_err(priv->dev, "nonseekable-open failed\n"); + kfree(reader); + return ret; + } + + /* + * success, increase the reference count of the private data structure + * so that it doesn't disappear if the device is unbound + */ + kref_get(&priv->ref); + return 0; +} + +static int data_release(struct inode *inode, struct file *filp) +{ + struct fpga_reader *reader = filp->private_data; + struct fpga_device *priv = reader->priv; + + /* free the per-reader structure */ + data_free_buffer(reader->buf); + kfree(reader); + filp->private_data = NULL; + + /* decrement our reference count to the private data */ + kref_put(&priv->ref, fpga_device_release); + return 0; +} + +static ssize_t data_read(struct file *filp, char __user *ubuf, size_t count, + loff_t *f_pos) +{ + struct fpga_reader *reader = filp->private_data; + struct fpga_device *priv = reader->priv; + struct list_head *used = &priv->used; + struct data_buf *dbuf; + size_t avail; + void *data; + int ret; + + /* check if we already have a partial buffer */ + if (reader->buf) { + dbuf = reader->buf; + goto have_buffer; + } + + spin_lock_irq(&priv->lock); + + /* Block until there is at least one buffer on the used list */ + while (list_empty(used)) { + spin_unlock_irq(&priv->lock); + + if (filp->f_flags & O_NONBLOCK) + return -EAGAIN; + + ret = wait_event_interruptible(priv->wait, !list_empty(used)); + if (ret) + return ret; + + spin_lock_irq(&priv->lock); + } + + /* Grab the first buffer off of the used list */ + dbuf = list_first_entry(used, struct data_buf, entry); + list_del_init(&dbuf->entry); + + spin_unlock_irq(&priv->lock); + + /* Buffers are always mapped: unmap it */ + videobuf_dma_unmap(priv->dev, &dbuf->vb); + + /* save the buffer for later */ + reader->buf = dbuf; + reader->buf_start = 0; + +have_buffer: + /* Get the number of bytes available */ + avail = dbuf->size - reader->buf_start; + data = dbuf->vb.vaddr + reader->buf_start; + + /* Get the number of bytes we can transfer */ + count = min(count, avail); + + /* Copy the data to the userspace buffer */ + if (copy_to_user(ubuf, data, count)) + return -EFAULT; + + /* Update the amount of available space */ + avail -= count; + + /* + * If there is still some data available, save the buffer for the + * next userspace call to read() and return + */ + if (avail > 0) { + reader->buf_start += count; + reader->buf = dbuf; + return count; + } + + /* + * Get the buffer ready to be reused for DMA + * + * If it fails, we pretend that the read never happed and return + * -EFAULT to userspace. The read will be retried. + */ + ret = videobuf_dma_map(priv->dev, &dbuf->vb); + if (ret) { + dev_err(priv->dev, "unable to remap buffer for DMA\n"); + return -EFAULT; + } + + /* Lock against concurrent enable/disable */ + spin_lock_irq(&priv->lock); + + /* the reader is finished with this buffer */ + reader->buf = NULL; + + /* + * One of two things has happened, the device is disabled, or the + * device has been reconfigured underneath us. In either case, we + * should just throw away the buffer. + */ + if (!priv->enabled || dbuf->size != priv->bufsize) { + videobuf_dma_unmap(priv->dev, &dbuf->vb); + data_free_buffer(dbuf); + goto out_unlock; + } + + /* The buffer is safe to reuse, so add it back to the free list */ + list_add_tail(&dbuf->entry, &priv->free); + +out_unlock: + spin_unlock_irq(&priv->lock); + return count; +} + +static unsigned int data_poll(struct file *filp, struct poll_table_struct *tbl) +{ + struct fpga_reader *reader = filp->private_data; + struct fpga_device *priv = reader->priv; + unsigned int mask = 0; + + poll_wait(filp, &priv->wait, tbl); + + if (!list_empty(&priv->used)) + mask |= POLLIN | POLLRDNORM; + + return mask; +} + +static int data_mmap(struct file *filp, struct vm_area_struct *vma) +{ + struct fpga_reader *reader = filp->private_data; + struct fpga_device *priv = reader->priv; + unsigned long offset, vsize, psize, addr; + + /* VMA properties */ + offset = vma->vm_pgoff << PAGE_SHIFT; + vsize = vma->vm_end - vma->vm_start; + psize = priv->phys_size - offset; + addr = (priv->phys_addr + offset) >> PAGE_SHIFT; + + /* Check against the FPGA region's physical memory size */ + if (vsize > psize) { + dev_err(priv->dev, "requested mmap mapping too large\n"); + return -EINVAL; + } + + /* IO memory (stop cacheing) */ + vma->vm_flags |= VM_IO | VM_RESERVED; + vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); + + return io_remap_pfn_range(vma, vma->vm_start, addr, vsize, + vma->vm_page_prot); +} + +static const struct file_operations data_fops = { + .owner = THIS_MODULE, + .open = data_open, + .release = data_release, + .read = data_read, + .poll = data_poll, + .mmap = data_mmap, + .llseek = no_llseek, +}; + +/* + * OpenFirmware Device Subsystem + */ + +static bool dma_filter(struct dma_chan *chan, void *data) +{ + /* + * DMA Channel #0 is used for the FPGA Programmer, so ignore it + * + * This probably won't survive an unload/load cycle of the Freescale + * DMAEngine driver, but that won't be a problem + */ + if (chan->chan_id == 0 && chan->device->dev_id == 0) + return false; + + return true; +} + +static int data_of_probe(struct platform_device *op, + const struct of_device_id *match) +{ + struct device_node *of_node = op->dev.of_node; + struct device *this_device; + struct fpga_device *priv; + struct resource res; + dma_cap_mask_t mask; + int ret; + + /* Allocate private data */ + priv = kzalloc(sizeof(*priv), GFP_KERNEL); + if (!priv) { + dev_err(&op->dev, "Unable to allocate device private data\n"); + ret = -ENOMEM; + goto out_return; + } + + dev_set_drvdata(&op->dev, priv); + priv->dev = &op->dev; + kref_init(&priv->ref); + mutex_init(&priv->mutex); + + dev_set_drvdata(priv->dev, priv); + spin_lock_init(&priv->lock); + INIT_LIST_HEAD(&priv->free); + INIT_LIST_HEAD(&priv->used); + init_waitqueue_head(&priv->wait); + + /* Setup the misc device */ + priv->miscdev.minor = MISC_DYNAMIC_MINOR; + priv->miscdev.name = drv_name; + priv->miscdev.fops = &data_fops; + + /* Get the physical address of the FPGA registers */ + ret = of_address_to_resource(of_node, 0, &res); + if (ret) { + dev_err(&op->dev, "Unable to find FPGA physical address\n"); + ret = -ENODEV; + goto out_free_priv; + } + + priv->phys_addr = res.start; + priv->phys_size = resource_size(&res); + + /* ioremap the registers for use */ + priv->regs = of_iomap(of_node, 0); + if (!priv->regs) { + dev_err(&op->dev, "Unable to ioremap registers\n"); + ret = -ENOMEM; + goto out_free_priv; + } + + dma_cap_zero(mask); + dma_cap_set(DMA_MEMCPY, mask); + dma_cap_set(DMA_INTERRUPT, mask); + dma_cap_set(DMA_SLAVE, mask); + dma_cap_set(DMA_SG, mask); + + /* Request a DMA channel */ + priv->chan = dma_request_channel(mask, dma_filter, NULL); + if (!priv->chan) { + dev_err(&op->dev, "Unable to request DMA channel\n"); + ret = -ENODEV; + goto out_unmap_regs; + } + + /* Find the correct IRQ number */ + priv->irq = irq_of_parse_and_map(of_node, 0); + if (priv->irq == NO_IRQ) { + dev_err(&op->dev, "Unable to find IRQ line\n"); + ret = -ENODEV; + goto out_release_dma; + } + + /* Drive the GPIO for FPGA IRQ high (no interrupt) */ + iowrite32be(IRQ_CORL_DONE, priv->regs + SYS_IRQ_OUTPUT_DATA); + + /* Register the miscdevice */ + ret = misc_register(&priv->miscdev); + if (ret) { + dev_err(&op->dev, "Unable to register miscdevice\n"); + goto out_irq_dispose_mapping; + } + + /* Create the debugfs files */ + ret = data_debugfs_init(priv); + if (ret) { + dev_err(&op->dev, "Unable to create debugfs files\n"); + goto out_misc_deregister; + } + + /* Create the sysfs files */ + this_device = priv->miscdev.this_device; + dev_set_drvdata(this_device, priv); + ret = sysfs_create_group(&this_device->kobj, &rt_sysfs_attr_group); + if (ret) { + dev_err(&op->dev, "Unable to create sysfs files\n"); + goto out_data_debugfs_exit; + } + + dev_info(&op->dev, "CARMA FPGA Realtime Data Driver Loaded\n"); + return 0; + +out_data_debugfs_exit: + data_debugfs_exit(priv); +out_misc_deregister: + misc_deregister(&priv->miscdev); +out_irq_dispose_mapping: + irq_dispose_mapping(priv->irq); +out_release_dma: + dma_release_channel(priv->chan); +out_unmap_regs: + iounmap(priv->regs); +out_free_priv: + kref_put(&priv->ref, fpga_device_release); +out_return: + return ret; +} + +static int data_of_remove(struct platform_device *op) +{ + struct fpga_device *priv = dev_get_drvdata(&op->dev); + struct device *this_device = priv->miscdev.this_device; + + /* remove all sysfs files, now the device cannot be re-enabled */ + sysfs_remove_group(&this_device->kobj, &rt_sysfs_attr_group); + + /* remove all debugfs files */ + data_debugfs_exit(priv); + + /* disable the device from generating data */ + data_device_disable(priv); + + /* remove the character device to stop new readers from appearing */ + misc_deregister(&priv->miscdev); + + /* cleanup everything not needed by readers */ + irq_dispose_mapping(priv->irq); + dma_release_channel(priv->chan); + iounmap(priv->regs); + + /* release our reference */ + kref_put(&priv->ref, fpga_device_release); + return 0; +} + +static struct of_device_id data_of_match[] = { + { .compatible = "carma,carma-fpga", }, + {}, +}; + +static struct of_platform_driver data_of_driver = { + .probe = data_of_probe, + .remove = data_of_remove, + .driver = { + .name = drv_name, + .of_match_table = data_of_match, + .owner = THIS_MODULE, + }, +}; + +/* + * Module Init / Exit + */ + +static int __init data_init(void) +{ + return of_register_platform_driver(&data_of_driver); +} + +static void __exit data_exit(void) +{ + of_unregister_platform_driver(&data_of_driver); +} + +MODULE_AUTHOR("Ira W. Snyder "); +MODULE_DESCRIPTION("CARMA DATA-FPGA Access Driver"); +MODULE_LICENSE("GPL"); + +module_init(data_init); +module_exit(data_exit); -- cgit v0.10.2 From 0e1d715b5b982ee0099f3fbf6ad47dc8bda518a6 Mon Sep 17 00:00:00 2001 From: Ira Snyder Date: Fri, 11 Feb 2011 13:34:30 +0000 Subject: misc: Add CARMA DATA-FPGA Programmer support This adds support for programming the data processing FPGAs on the OVRO CARMA board. These FPGAs have a special programming sequence that requires that we program the Freescale DMA engine, which is only available inside the kernel. Signed-off-by: Ira W. Snyder Signed-off-by: Benjamin Herrenschmidt diff --git a/drivers/misc/carma/Kconfig b/drivers/misc/carma/Kconfig index 4be183f..c90370e 100644 --- a/drivers/misc/carma/Kconfig +++ b/drivers/misc/carma/Kconfig @@ -7,3 +7,11 @@ config CARMA_FPGA Say Y here to include support for communicating with the data processing FPGAs on the OVRO CARMA board. +config CARMA_FPGA_PROGRAM + tristate "CARMA DATA-FPGA Programmer" + depends on FSL_SOC && PPC_83xx && MEDIA_SUPPORT && HAS_DMA && FSL_DMA + select VIDEOBUF_DMA_SG + default n + help + Say Y here to include support for programming the data processing + FPGAs on the OVRO CARMA board. diff --git a/drivers/misc/carma/Makefile b/drivers/misc/carma/Makefile index 0b69fa7..ff36ac2 100644 --- a/drivers/misc/carma/Makefile +++ b/drivers/misc/carma/Makefile @@ -1 +1,2 @@ obj-$(CONFIG_CARMA_FPGA) += carma-fpga.o +obj-$(CONFIG_CARMA_FPGA_PROGRAM) += carma-fpga-program.o diff --git a/drivers/misc/carma/carma-fpga-program.c b/drivers/misc/carma/carma-fpga-program.c new file mode 100644 index 0000000..7ce6065 --- /dev/null +++ b/drivers/misc/carma/carma-fpga-program.c @@ -0,0 +1,1141 @@ +/* + * CARMA Board DATA-FPGA Programmer + * + * Copyright (c) 2009-2011 Ira W. Snyder + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +/* MPC8349EMDS specific get_immrbase() */ +#include + +static const char drv_name[] = "carma-fpga-program"; + +/* + * Firmware images are always this exact size + * + * 12849552 bytes for a CARMA Digitizer Board (EP2S90 FPGAs) + * 18662880 bytes for a CARMA Correlator Board (EP2S130 FPGAs) + */ +#define FW_SIZE_EP2S90 12849552 +#define FW_SIZE_EP2S130 18662880 + +struct fpga_dev { + struct miscdevice miscdev; + + /* Reference count */ + struct kref ref; + + /* Device Registers */ + struct device *dev; + void __iomem *regs; + void __iomem *immr; + + /* Freescale DMA Device */ + struct dma_chan *chan; + + /* Interrupts */ + int irq, status; + struct completion completion; + + /* FPGA Bitfile */ + struct mutex lock; + + struct videobuf_dmabuf vb; + bool vb_allocated; + + /* max size and written bytes */ + size_t fw_size; + size_t bytes; +}; + +/* + * FPGA Bitfile Helpers + */ + +/** + * fpga_drop_firmware_data() - drop the bitfile image from memory + * @priv: the driver's private data structure + * + * LOCKING: must hold priv->lock + */ +static void fpga_drop_firmware_data(struct fpga_dev *priv) +{ + videobuf_dma_free(&priv->vb); + priv->vb_allocated = false; + priv->bytes = 0; +} + +/* + * Private Data Reference Count + */ + +static void fpga_dev_remove(struct kref *ref) +{ + struct fpga_dev *priv = container_of(ref, struct fpga_dev, ref); + + /* free any firmware image that was not programmed */ + fpga_drop_firmware_data(priv); + + mutex_destroy(&priv->lock); + kfree(priv); +} + +/* + * LED Trigger (could be a seperate module) + */ + +/* + * NOTE: this whole thing does have the problem that whenever the led's are + * NOTE: first set to use the fpga trigger, they could be in the wrong state + */ + +DEFINE_LED_TRIGGER(ledtrig_fpga); + +static void ledtrig_fpga_programmed(bool enabled) +{ + if (enabled) + led_trigger_event(ledtrig_fpga, LED_FULL); + else + led_trigger_event(ledtrig_fpga, LED_OFF); +} + +/* + * FPGA Register Helpers + */ + +/* Register Definitions */ +#define FPGA_CONFIG_CONTROL 0x40 +#define FPGA_CONFIG_STATUS 0x44 +#define FPGA_CONFIG_FIFO_SIZE 0x48 +#define FPGA_CONFIG_FIFO_USED 0x4C +#define FPGA_CONFIG_TOTAL_BYTE_COUNT 0x50 +#define FPGA_CONFIG_CUR_BYTE_COUNT 0x54 + +#define FPGA_FIFO_ADDRESS 0x3000 + +static int fpga_fifo_size(void __iomem *regs) +{ + return ioread32be(regs + FPGA_CONFIG_FIFO_SIZE); +} + +#define CFG_STATUS_ERR_MASK 0xfffe + +static int fpga_config_error(void __iomem *regs) +{ + return ioread32be(regs + FPGA_CONFIG_STATUS) & CFG_STATUS_ERR_MASK; +} + +static int fpga_fifo_empty(void __iomem *regs) +{ + return ioread32be(regs + FPGA_CONFIG_FIFO_USED) == 0; +} + +static void fpga_fifo_write(void __iomem *regs, u32 val) +{ + iowrite32be(val, regs + FPGA_FIFO_ADDRESS); +} + +static void fpga_set_byte_count(void __iomem *regs, u32 count) +{ + iowrite32be(count, regs + FPGA_CONFIG_TOTAL_BYTE_COUNT); +} + +#define CFG_CTL_ENABLE (1 << 0) +#define CFG_CTL_RESET (1 << 1) +#define CFG_CTL_DMA (1 << 2) + +static void fpga_programmer_enable(struct fpga_dev *priv, bool dma) +{ + u32 val; + + val = (dma) ? (CFG_CTL_ENABLE | CFG_CTL_DMA) : CFG_CTL_ENABLE; + iowrite32be(val, priv->regs + FPGA_CONFIG_CONTROL); +} + +static void fpga_programmer_disable(struct fpga_dev *priv) +{ + iowrite32be(0x0, priv->regs + FPGA_CONFIG_CONTROL); +} + +static void fpga_dump_registers(struct fpga_dev *priv) +{ + u32 control, status, size, used, total, curr; + + /* good status: do nothing */ + if (priv->status == 0) + return; + + /* Dump all status registers */ + control = ioread32be(priv->regs + FPGA_CONFIG_CONTROL); + status = ioread32be(priv->regs + FPGA_CONFIG_STATUS); + size = ioread32be(priv->regs + FPGA_CONFIG_FIFO_SIZE); + used = ioread32be(priv->regs + FPGA_CONFIG_FIFO_USED); + total = ioread32be(priv->regs + FPGA_CONFIG_TOTAL_BYTE_COUNT); + curr = ioread32be(priv->regs + FPGA_CONFIG_CUR_BYTE_COUNT); + + dev_err(priv->dev, "Configuration failed, dumping status registers\n"); + dev_err(priv->dev, "Control: 0x%.8x\n", control); + dev_err(priv->dev, "Status: 0x%.8x\n", status); + dev_err(priv->dev, "FIFO Size: 0x%.8x\n", size); + dev_err(priv->dev, "FIFO Used: 0x%.8x\n", used); + dev_err(priv->dev, "FIFO Total: 0x%.8x\n", total); + dev_err(priv->dev, "FIFO Curr: 0x%.8x\n", curr); +} + +/* + * FPGA Power Supply Code + */ + +#define CTL_PWR_CONTROL 0x2006 +#define CTL_PWR_STATUS 0x200A +#define CTL_PWR_FAIL 0x200B + +#define PWR_CONTROL_ENABLE 0x01 + +#define PWR_STATUS_ERROR_MASK 0x10 +#define PWR_STATUS_GOOD 0x0f + +/* + * Determine if the FPGA power is good for all supplies + */ +static bool fpga_power_good(struct fpga_dev *priv) +{ + u8 val; + + val = ioread8(priv->regs + CTL_PWR_STATUS); + if (val & PWR_STATUS_ERROR_MASK) + return false; + + return val == PWR_STATUS_GOOD; +} + +/* + * Disable the FPGA power supplies + */ +static void fpga_disable_power_supplies(struct fpga_dev *priv) +{ + unsigned long start; + u8 val; + + iowrite8(0x0, priv->regs + CTL_PWR_CONTROL); + + /* + * Wait 500ms for the power rails to discharge + * + * Without this delay, the CTL-CPLD state machine can get into a + * state where it is waiting for the power-goods to assert, but they + * never do. This only happens when enabling and disabling the + * power sequencer very rapidly. + * + * The loop below will also wait for the power goods to de-assert, + * but testing has shown that they are always disabled by the time + * the sleep completes. However, omitting the sleep and only waiting + * for the power-goods to de-assert was not sufficient to ensure + * that the power sequencer would not wedge itself. + */ + msleep(500); + + start = jiffies; + while (time_before(jiffies, start + HZ)) { + val = ioread8(priv->regs + CTL_PWR_STATUS); + if (!(val & PWR_STATUS_GOOD)) + break; + + usleep_range(5000, 10000); + } + + val = ioread8(priv->regs + CTL_PWR_STATUS); + if (val & PWR_STATUS_GOOD) { + dev_err(priv->dev, "power disable failed: " + "power goods: status 0x%.2x\n", val); + } + + if (val & PWR_STATUS_ERROR_MASK) { + dev_err(priv->dev, "power disable failed: " + "alarm bit set: status 0x%.2x\n", val); + } +} + +/** + * fpga_enable_power_supplies() - enable the DATA-FPGA power supplies + * @priv: the driver's private data structure + * + * Enable the DATA-FPGA power supplies, waiting up to 1 second for + * them to enable successfully. + * + * Returns 0 on success, -ERRNO otherwise + */ +static int fpga_enable_power_supplies(struct fpga_dev *priv) +{ + unsigned long start = jiffies; + + if (fpga_power_good(priv)) { + dev_dbg(priv->dev, "power was already good\n"); + return 0; + } + + iowrite8(PWR_CONTROL_ENABLE, priv->regs + CTL_PWR_CONTROL); + while (time_before(jiffies, start + HZ)) { + if (fpga_power_good(priv)) + return 0; + + usleep_range(5000, 10000); + } + + return fpga_power_good(priv) ? 0 : -ETIMEDOUT; +} + +/* + * Determine if the FPGA power supplies are all enabled + */ +static bool fpga_power_enabled(struct fpga_dev *priv) +{ + u8 val; + + val = ioread8(priv->regs + CTL_PWR_CONTROL); + if (val & PWR_CONTROL_ENABLE) + return true; + + return false; +} + +/* + * Determine if the FPGA's are programmed and running correctly + */ +static bool fpga_running(struct fpga_dev *priv) +{ + if (!fpga_power_good(priv)) + return false; + + /* Check the config done bit */ + return ioread32be(priv->regs + FPGA_CONFIG_STATUS) & (1 << 18); +} + +/* + * FPGA Programming Code + */ + +/** + * fpga_program_block() - put a block of data into the programmer's FIFO + * @priv: the driver's private data structure + * @buf: the data to program + * @count: the length of data to program (must be a multiple of 4 bytes) + * + * Returns 0 on success, -ERRNO otherwise + */ +static int fpga_program_block(struct fpga_dev *priv, void *buf, size_t count) +{ + u32 *data = buf; + int size = fpga_fifo_size(priv->regs); + int i, len; + unsigned long timeout; + + /* enforce correct data length for the FIFO */ + BUG_ON(count % 4 != 0); + + while (count > 0) { + + /* Get the size of the block to write (maximum is FIFO_SIZE) */ + len = min_t(size_t, count, size); + timeout = jiffies + HZ / 4; + + /* Write the block */ + for (i = 0; i < len / 4; i++) + fpga_fifo_write(priv->regs, data[i]); + + /* Update the amounts left */ + count -= len; + data += len / 4; + + /* Wait for the fifo to empty */ + while (true) { + + if (fpga_fifo_empty(priv->regs)) { + break; + } else { + dev_dbg(priv->dev, "Fifo not empty\n"); + cpu_relax(); + } + + if (fpga_config_error(priv->regs)) { + dev_err(priv->dev, "Error detected\n"); + return -EIO; + } + + if (time_after(jiffies, timeout)) { + dev_err(priv->dev, "Fifo drain timeout\n"); + return -ETIMEDOUT; + } + + usleep_range(5000, 10000); + } + } + + return 0; +} + +/** + * fpga_program_cpu() - program the DATA-FPGA's using the CPU + * @priv: the driver's private data structure + * + * This is useful when the DMA programming method fails. It is possible to + * wedge the Freescale DMA controller such that the DMA programming method + * always fails. This method has always succeeded. + * + * Returns 0 on success, -ERRNO otherwise + */ +static noinline int fpga_program_cpu(struct fpga_dev *priv) +{ + int ret; + + /* Disable the programmer */ + fpga_programmer_disable(priv); + + /* Set the total byte count */ + fpga_set_byte_count(priv->regs, priv->bytes); + dev_dbg(priv->dev, "total byte count %u bytes\n", priv->bytes); + + /* Enable the controller for programming */ + fpga_programmer_enable(priv, false); + dev_dbg(priv->dev, "enabled the controller\n"); + + /* Write each chunk of the FPGA bitfile to FPGA programmer */ + ret = fpga_program_block(priv, priv->vb.vaddr, priv->bytes); + if (ret) + goto out_disable_controller; + + /* Wait for the interrupt handler to signal that programming finished */ + ret = wait_for_completion_timeout(&priv->completion, 2 * HZ); + if (!ret) { + dev_err(priv->dev, "Timed out waiting for completion\n"); + ret = -ETIMEDOUT; + goto out_disable_controller; + } + + /* Retrieve the status from the interrupt handler */ + ret = priv->status; + +out_disable_controller: + fpga_programmer_disable(priv); + return ret; +} + +#define FIFO_DMA_ADDRESS 0xf0003000 +#define FIFO_MAX_LEN 4096 + +/** + * fpga_program_dma() - program the DATA-FPGA's using the DMA engine + * @priv: the driver's private data structure + * + * Program the DATA-FPGA's using the Freescale DMA engine. This requires that + * the engine is programmed such that the hardware DMA request lines can + * control the entire DMA transaction. The system controller FPGA then + * completely offloads the programming from the CPU. + * + * Returns 0 on success, -ERRNO otherwise + */ +static noinline int fpga_program_dma(struct fpga_dev *priv) +{ + struct videobuf_dmabuf *vb = &priv->vb; + struct dma_chan *chan = priv->chan; + struct dma_async_tx_descriptor *tx; + size_t num_pages, len, avail = 0; + struct dma_slave_config config; + struct scatterlist *sg; + struct sg_table table; + dma_cookie_t cookie; + int ret, i; + + /* Disable the programmer */ + fpga_programmer_disable(priv); + + /* Allocate a scatterlist for the DMA destination */ + num_pages = DIV_ROUND_UP(priv->bytes, FIFO_MAX_LEN); + ret = sg_alloc_table(&table, num_pages, GFP_KERNEL); + if (ret) { + dev_err(priv->dev, "Unable to allocate dst scatterlist\n"); + ret = -ENOMEM; + goto out_return; + } + + /* + * This is an ugly hack + * + * We fill in a scatterlist as if it were mapped for DMA. This is + * necessary because there exists no better structure for this + * inside the kernel code. + * + * As an added bonus, we can use the DMAEngine API for all of this, + * rather than inventing another extremely similar API. + */ + avail = priv->bytes; + for_each_sg(table.sgl, sg, num_pages, i) { + len = min_t(size_t, avail, FIFO_MAX_LEN); + sg_dma_address(sg) = FIFO_DMA_ADDRESS; + sg_dma_len(sg) = len; + + avail -= len; + } + + /* Map the buffer for DMA */ + ret = videobuf_dma_map(priv->dev, &priv->vb); + if (ret) { + dev_err(priv->dev, "Unable to map buffer for DMA\n"); + goto out_free_table; + } + + /* + * Configure the DMA channel to transfer FIFO_SIZE / 2 bytes per + * transaction, and then put it under external control + */ + memset(&config, 0, sizeof(config)); + config.direction = DMA_TO_DEVICE; + config.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; + config.dst_maxburst = fpga_fifo_size(priv->regs) / 2 / 4; + ret = chan->device->device_control(chan, DMA_SLAVE_CONFIG, + (unsigned long)&config); + if (ret) { + dev_err(priv->dev, "DMA slave configuration failed\n"); + goto out_dma_unmap; + } + + ret = chan->device->device_control(chan, FSLDMA_EXTERNAL_START, 1); + if (ret) { + dev_err(priv->dev, "DMA external control setup failed\n"); + goto out_dma_unmap; + } + + /* setup and submit the DMA transaction */ + tx = chan->device->device_prep_dma_sg(chan, + table.sgl, num_pages, + vb->sglist, vb->sglen, 0); + if (!tx) { + dev_err(priv->dev, "Unable to prep DMA transaction\n"); + ret = -ENOMEM; + goto out_dma_unmap; + } + + cookie = tx->tx_submit(tx); + if (dma_submit_error(cookie)) { + dev_err(priv->dev, "Unable to submit DMA transaction\n"); + ret = -ENOMEM; + goto out_dma_unmap; + } + + dma_async_memcpy_issue_pending(chan); + + /* Set the total byte count */ + fpga_set_byte_count(priv->regs, priv->bytes); + dev_dbg(priv->dev, "total byte count %u bytes\n", priv->bytes); + + /* Enable the controller for DMA programming */ + fpga_programmer_enable(priv, true); + dev_dbg(priv->dev, "enabled the controller\n"); + + /* Wait for the interrupt handler to signal that programming finished */ + ret = wait_for_completion_timeout(&priv->completion, 2 * HZ); + if (!ret) { + dev_err(priv->dev, "Timed out waiting for completion\n"); + ret = -ETIMEDOUT; + goto out_disable_controller; + } + + /* Retrieve the status from the interrupt handler */ + ret = priv->status; + +out_disable_controller: + fpga_programmer_disable(priv); +out_dma_unmap: + videobuf_dma_unmap(priv->dev, vb); +out_free_table: + sg_free_table(&table); +out_return: + return ret; +} + +/* + * Interrupt Handling + */ + +static irqreturn_t fpga_irq(int irq, void *dev_id) +{ + struct fpga_dev *priv = dev_id; + + /* Save the status */ + priv->status = fpga_config_error(priv->regs) ? -EIO : 0; + dev_dbg(priv->dev, "INTERRUPT status %d\n", priv->status); + fpga_dump_registers(priv); + + /* Disabling the programmer clears the interrupt */ + fpga_programmer_disable(priv); + + /* Notify any waiters */ + complete(&priv->completion); + + return IRQ_HANDLED; +} + +/* + * SYSFS Helpers + */ + +/** + * fpga_do_stop() - deconfigure (reset) the DATA-FPGA's + * @priv: the driver's private data structure + * + * LOCKING: must hold priv->lock + */ +static int fpga_do_stop(struct fpga_dev *priv) +{ + u32 val; + + /* Set the led to unprogrammed */ + ledtrig_fpga_programmed(false); + + /* Pulse the config line to reset the FPGA's */ + val = CFG_CTL_ENABLE | CFG_CTL_RESET; + iowrite32be(val, priv->regs + FPGA_CONFIG_CONTROL); + iowrite32be(0x0, priv->regs + FPGA_CONFIG_CONTROL); + + return 0; +} + +static noinline int fpga_do_program(struct fpga_dev *priv) +{ + int ret; + + if (priv->bytes != priv->fw_size) { + dev_err(priv->dev, "Incorrect bitfile size: got %zu bytes, " + "should be %zu bytes\n", + priv->bytes, priv->fw_size); + return -EINVAL; + } + + if (!fpga_power_enabled(priv)) { + dev_err(priv->dev, "Power not enabled\n"); + return -EINVAL; + } + + if (!fpga_power_good(priv)) { + dev_err(priv->dev, "Power not good\n"); + return -EINVAL; + } + + /* Set the LED to unprogrammed */ + ledtrig_fpga_programmed(false); + + /* Try to program the FPGA's using DMA */ + ret = fpga_program_dma(priv); + + /* If DMA failed or doesn't exist, try with CPU */ + if (ret) { + dev_warn(priv->dev, "Falling back to CPU programming\n"); + ret = fpga_program_cpu(priv); + } + + if (ret) { + dev_err(priv->dev, "Unable to program FPGA's\n"); + return ret; + } + + /* Drop the firmware bitfile from memory */ + fpga_drop_firmware_data(priv); + + dev_dbg(priv->dev, "FPGA programming successful\n"); + ledtrig_fpga_programmed(true); + + return 0; +} + +/* + * File Operations + */ + +static int fpga_open(struct inode *inode, struct file *filp) +{ + /* + * The miscdevice layer puts our struct miscdevice into the + * filp->private_data field. We use this to find our private + * data and then overwrite it with our own private structure. + */ + struct fpga_dev *priv = container_of(filp->private_data, + struct fpga_dev, miscdev); + unsigned int nr_pages; + int ret; + + /* We only allow one process at a time */ + ret = mutex_lock_interruptible(&priv->lock); + if (ret) + return ret; + + filp->private_data = priv; + kref_get(&priv->ref); + + /* Truncation: drop any existing data */ + if (filp->f_flags & O_TRUNC) + priv->bytes = 0; + + /* Check if we have already allocated a buffer */ + if (priv->vb_allocated) + return 0; + + /* Allocate a buffer to hold enough data for the bitfile */ + nr_pages = DIV_ROUND_UP(priv->fw_size, PAGE_SIZE); + ret = videobuf_dma_init_kernel(&priv->vb, DMA_TO_DEVICE, nr_pages); + if (ret) { + dev_err(priv->dev, "unable to allocate data buffer\n"); + mutex_unlock(&priv->lock); + kref_put(&priv->ref, fpga_dev_remove); + return ret; + } + + priv->vb_allocated = true; + return 0; +} + +static int fpga_release(struct inode *inode, struct file *filp) +{ + struct fpga_dev *priv = filp->private_data; + + mutex_unlock(&priv->lock); + kref_put(&priv->ref, fpga_dev_remove); + return 0; +} + +static ssize_t fpga_write(struct file *filp, const char __user *buf, + size_t count, loff_t *f_pos) +{ + struct fpga_dev *priv = filp->private_data; + + /* FPGA bitfiles have an exact size: disallow anything else */ + if (priv->bytes >= priv->fw_size) + return -ENOSPC; + + count = min_t(size_t, priv->fw_size - priv->bytes, count); + if (copy_from_user(priv->vb.vaddr + priv->bytes, buf, count)) + return -EFAULT; + + priv->bytes += count; + return count; +} + +static ssize_t fpga_read(struct file *filp, char __user *buf, size_t count, + loff_t *f_pos) +{ + struct fpga_dev *priv = filp->private_data; + + count = min_t(size_t, priv->bytes - *f_pos, count); + if (copy_to_user(buf, priv->vb.vaddr + *f_pos, count)) + return -EFAULT; + + *f_pos += count; + return count; +} + +static loff_t fpga_llseek(struct file *filp, loff_t offset, int origin) +{ + struct fpga_dev *priv = filp->private_data; + loff_t newpos; + + /* only read-only opens are allowed to seek */ + if ((filp->f_flags & O_ACCMODE) != O_RDONLY) + return -EINVAL; + + switch (origin) { + case SEEK_SET: /* seek relative to the beginning of the file */ + newpos = offset; + break; + case SEEK_CUR: /* seek relative to current position in the file */ + newpos = filp->f_pos + offset; + break; + case SEEK_END: /* seek relative to the end of the file */ + newpos = priv->fw_size - offset; + break; + default: + return -EINVAL; + } + + /* check for sanity */ + if (newpos > priv->fw_size) + return -EINVAL; + + filp->f_pos = newpos; + return newpos; +} + +static const struct file_operations fpga_fops = { + .open = fpga_open, + .release = fpga_release, + .write = fpga_write, + .read = fpga_read, + .llseek = fpga_llseek, +}; + +/* + * Device Attributes + */ + +static ssize_t pfail_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct fpga_dev *priv = dev_get_drvdata(dev); + u8 val; + + val = ioread8(priv->regs + CTL_PWR_FAIL); + return snprintf(buf, PAGE_SIZE, "0x%.2x\n", val); +} + +static ssize_t pgood_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct fpga_dev *priv = dev_get_drvdata(dev); + return snprintf(buf, PAGE_SIZE, "%d\n", fpga_power_good(priv)); +} + +static ssize_t penable_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct fpga_dev *priv = dev_get_drvdata(dev); + return snprintf(buf, PAGE_SIZE, "%d\n", fpga_power_enabled(priv)); +} + +static ssize_t penable_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct fpga_dev *priv = dev_get_drvdata(dev); + unsigned long val; + int ret; + + if (strict_strtoul(buf, 0, &val)) + return -EINVAL; + + if (val) { + ret = fpga_enable_power_supplies(priv); + if (ret) + return ret; + } else { + fpga_do_stop(priv); + fpga_disable_power_supplies(priv); + } + + return count; +} + +static ssize_t program_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct fpga_dev *priv = dev_get_drvdata(dev); + return snprintf(buf, PAGE_SIZE, "%d\n", fpga_running(priv)); +} + +static ssize_t program_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct fpga_dev *priv = dev_get_drvdata(dev); + unsigned long val; + int ret; + + if (strict_strtoul(buf, 0, &val)) + return -EINVAL; + + /* We can't have an image writer and be programming simultaneously */ + if (mutex_lock_interruptible(&priv->lock)) + return -ERESTARTSYS; + + /* Program or Reset the FPGA's */ + ret = val ? fpga_do_program(priv) : fpga_do_stop(priv); + if (ret) + goto out_unlock; + + /* Success */ + ret = count; + +out_unlock: + mutex_unlock(&priv->lock); + return ret; +} + +static DEVICE_ATTR(power_fail, S_IRUGO, pfail_show, NULL); +static DEVICE_ATTR(power_good, S_IRUGO, pgood_show, NULL); +static DEVICE_ATTR(power_enable, S_IRUGO | S_IWUSR, + penable_show, penable_store); + +static DEVICE_ATTR(program, S_IRUGO | S_IWUSR, + program_show, program_store); + +static struct attribute *fpga_attributes[] = { + &dev_attr_power_fail.attr, + &dev_attr_power_good.attr, + &dev_attr_power_enable.attr, + &dev_attr_program.attr, + NULL, +}; + +static const struct attribute_group fpga_attr_group = { + .attrs = fpga_attributes, +}; + +/* + * OpenFirmware Device Subsystem + */ + +#define SYS_REG_VERSION 0x00 +#define SYS_REG_GEOGRAPHIC 0x10 + +static bool dma_filter(struct dma_chan *chan, void *data) +{ + /* + * DMA Channel #0 is the only acceptable device + * + * This probably won't survive an unload/load cycle of the Freescale + * DMAEngine driver, but that won't be a problem + */ + return chan->chan_id == 0 && chan->device->dev_id == 0; +} + +static int fpga_of_remove(struct platform_device *op) +{ + struct fpga_dev *priv = dev_get_drvdata(&op->dev); + struct device *this_device = priv->miscdev.this_device; + + sysfs_remove_group(&this_device->kobj, &fpga_attr_group); + misc_deregister(&priv->miscdev); + + free_irq(priv->irq, priv); + irq_dispose_mapping(priv->irq); + + /* make sure the power supplies are off */ + fpga_disable_power_supplies(priv); + + /* unmap registers */ + iounmap(priv->immr); + iounmap(priv->regs); + + dma_release_channel(priv->chan); + + /* drop our reference to the private data structure */ + kref_put(&priv->ref, fpga_dev_remove); + return 0; +} + +/* CTL-CPLD Version Register */ +#define CTL_CPLD_VERSION 0x2000 + +static int fpga_of_probe(struct platform_device *op, + const struct of_device_id *match) +{ + struct device_node *of_node = op->dev.of_node; + struct device *this_device; + struct fpga_dev *priv; + dma_cap_mask_t mask; + u32 ver; + int ret; + + /* Allocate private data */ + priv = kzalloc(sizeof(*priv), GFP_KERNEL); + if (!priv) { + dev_err(&op->dev, "Unable to allocate private data\n"); + ret = -ENOMEM; + goto out_return; + } + + /* Setup the miscdevice */ + priv->miscdev.minor = MISC_DYNAMIC_MINOR; + priv->miscdev.name = drv_name; + priv->miscdev.fops = &fpga_fops; + + kref_init(&priv->ref); + + dev_set_drvdata(&op->dev, priv); + priv->dev = &op->dev; + mutex_init(&priv->lock); + init_completion(&priv->completion); + videobuf_dma_init(&priv->vb); + + dev_set_drvdata(priv->dev, priv); + dma_cap_zero(mask); + dma_cap_set(DMA_MEMCPY, mask); + dma_cap_set(DMA_INTERRUPT, mask); + dma_cap_set(DMA_SLAVE, mask); + dma_cap_set(DMA_SG, mask); + + /* Get control of DMA channel #0 */ + priv->chan = dma_request_channel(mask, dma_filter, NULL); + if (!priv->chan) { + dev_err(&op->dev, "Unable to acquire DMA channel #0\n"); + ret = -ENODEV; + goto out_free_priv; + } + + /* Remap the registers for use */ + priv->regs = of_iomap(of_node, 0); + if (!priv->regs) { + dev_err(&op->dev, "Unable to ioremap registers\n"); + ret = -ENOMEM; + goto out_dma_release_channel; + } + + /* Remap the IMMR for use */ + priv->immr = ioremap(get_immrbase(), 0x100000); + if (!priv->immr) { + dev_err(&op->dev, "Unable to ioremap IMMR\n"); + ret = -ENOMEM; + goto out_unmap_regs; + } + + /* + * Check that external DMA is configured + * + * U-Boot does this for us, but we should check it and bail out if + * there is a problem. Failing to have this register setup correctly + * will cause the DMA controller to transfer a single cacheline + * worth of data, then wedge itself. + */ + if ((ioread32be(priv->immr + 0x114) & 0xE00) != 0xE00) { + dev_err(&op->dev, "External DMA control not configured\n"); + ret = -ENODEV; + goto out_unmap_immr; + } + + /* + * Check the CTL-CPLD version + * + * This driver uses the CTL-CPLD DATA-FPGA power sequencer, and we + * don't want to run on any version of the CTL-CPLD that does not use + * a compatible register layout. + * + * v2: changed register layout, added power sequencer + * v3: added glitch filter on the i2c overcurrent/overtemp outputs + */ + ver = ioread8(priv->regs + CTL_CPLD_VERSION); + if (ver != 0x02 && ver != 0x03) { + dev_err(&op->dev, "CTL-CPLD is not version 0x02 or 0x03!\n"); + ret = -ENODEV; + goto out_unmap_immr; + } + + /* Set the exact size that the firmware image should be */ + ver = ioread32be(priv->regs + SYS_REG_VERSION); + priv->fw_size = (ver & (1 << 18)) ? FW_SIZE_EP2S130 : FW_SIZE_EP2S90; + + /* Find the correct IRQ number */ + priv->irq = irq_of_parse_and_map(of_node, 0); + if (priv->irq == NO_IRQ) { + dev_err(&op->dev, "Unable to find IRQ line\n"); + ret = -ENODEV; + goto out_unmap_immr; + } + + /* Request the IRQ */ + ret = request_irq(priv->irq, fpga_irq, IRQF_SHARED, drv_name, priv); + if (ret) { + dev_err(&op->dev, "Unable to request IRQ %d\n", priv->irq); + ret = -ENODEV; + goto out_irq_dispose_mapping; + } + + /* Reset and stop the FPGA's, just in case */ + fpga_do_stop(priv); + + /* Register the miscdevice */ + ret = misc_register(&priv->miscdev); + if (ret) { + dev_err(&op->dev, "Unable to register miscdevice\n"); + goto out_free_irq; + } + + /* Create the sysfs files */ + this_device = priv->miscdev.this_device; + dev_set_drvdata(this_device, priv); + ret = sysfs_create_group(&this_device->kobj, &fpga_attr_group); + if (ret) { + dev_err(&op->dev, "Unable to create sysfs files\n"); + goto out_misc_deregister; + } + + dev_info(priv->dev, "CARMA FPGA Programmer: %s rev%s with %s FPGAs\n", + (ver & (1 << 17)) ? "Correlator" : "Digitizer", + (ver & (1 << 16)) ? "B" : "A", + (ver & (1 << 18)) ? "EP2S130" : "EP2S90"); + + return 0; + +out_misc_deregister: + misc_deregister(&priv->miscdev); +out_free_irq: + free_irq(priv->irq, priv); +out_irq_dispose_mapping: + irq_dispose_mapping(priv->irq); +out_unmap_immr: + iounmap(priv->immr); +out_unmap_regs: + iounmap(priv->regs); +out_dma_release_channel: + dma_release_channel(priv->chan); +out_free_priv: + kref_put(&priv->ref, fpga_dev_remove); +out_return: + return ret; +} + +static struct of_device_id fpga_of_match[] = { + { .compatible = "carma,fpga-programmer", }, + {}, +}; + +static struct of_platform_driver fpga_of_driver = { + .probe = fpga_of_probe, + .remove = fpga_of_remove, + .driver = { + .name = drv_name, + .of_match_table = fpga_of_match, + .owner = THIS_MODULE, + }, +}; + +/* + * Module Init / Exit + */ + +static int __init fpga_init(void) +{ + led_trigger_register_simple("fpga", &ledtrig_fpga); + return of_register_platform_driver(&fpga_of_driver); +} + +static void __exit fpga_exit(void) +{ + of_unregister_platform_driver(&fpga_of_driver); + led_trigger_unregister_simple(ledtrig_fpga); +} + +MODULE_AUTHOR("Ira W. Snyder "); +MODULE_DESCRIPTION("CARMA Board DATA-FPGA Programmer"); +MODULE_LICENSE("GPL"); + +module_init(fpga_init); +module_exit(fpga_exit); -- cgit v0.10.2 From 751e1f5099f1568444fe2485f2485ca541d4952e Mon Sep 17 00:00:00 2001 From: Benjamin Herrenschmidt Date: Thu, 19 May 2011 14:44:31 +1000 Subject: powerpc: Remove unused/obsolete CONFIG_XICS Signed-off-by: Benjamin Herrenschmidt diff --git a/arch/powerpc/platforms/Kconfig b/arch/powerpc/platforms/Kconfig index 83c704a..f970ca2 100644 --- a/arch/powerpc/platforms/Kconfig +++ b/arch/powerpc/platforms/Kconfig @@ -70,11 +70,6 @@ config PPC_UDBG_BEAT depends on PPC_CELLEB default n -config XICS - depends on PPC_PSERIES - bool - default y - config IPIC bool default n -- cgit v0.10.2 From b4bc842802db3314f9a657094da0450a903ea619 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Mon, 7 Feb 2011 16:02:25 -0800 Subject: module: deal with alignment issues in built-in module versions On m68k natural alignment is 2-byte boundary but we are trying to align structures in __modver section on sizeof(void *) boundary. This causes trouble when we try to access elements in this section in array-like fashion when create "version" attributes for built-in modules. Moreover, as DaveM said, we can't reliably put structures into independent objects, put them into a special section, and then expect array access over them (via the section boundaries) after linking the objects together to just "work" due to variable alignment choices in different situations. The only solution that seems to work reliably is to make an array of plain pointers to the objects in question and put those pointers in the special section. Reported-by: Geert Uytterhoeven Signed-off-by: Dmitry Torokhov Signed-off-by: Rusty Russell diff --git a/include/linux/module.h b/include/linux/module.h index 5de4204..4cfebc2 100644 --- a/include/linux/module.h +++ b/include/linux/module.h @@ -174,10 +174,7 @@ extern struct module __this_module; #define MODULE_VERSION(_version) \ extern ssize_t __modver_version_show(struct module_attribute *, \ struct module *, char *); \ - static struct module_version_attribute __modver_version_attr \ - __used \ - __attribute__ ((__section__ ("__modver"),aligned(sizeof(void *)))) \ - = { \ + static struct module_version_attribute ___modver_attr = { \ .mattr = { \ .attr = { \ .name = "version", \ @@ -187,7 +184,10 @@ extern struct module __this_module; }, \ .module_name = KBUILD_MODNAME, \ .version = _version, \ - } + }; \ + static const struct module_version_attribute \ + __used __attribute__ ((__section__ ("__modver"))) \ + * __moduleparam_const __modver_attr = &___modver_attr #endif /* Optional firmware file (or files) needed by the module diff --git a/kernel/params.c b/kernel/params.c index 7ab388a..28c5d5c 100644 --- a/kernel/params.c +++ b/kernel/params.c @@ -821,15 +821,18 @@ ssize_t __modver_version_show(struct module_attribute *mattr, return sprintf(buf, "%s\n", vattr->version); } -extern struct module_version_attribute __start___modver[], __stop___modver[]; +extern const struct module_version_attribute *__start___modver[]; +extern const struct module_version_attribute *__stop___modver[]; static void __init version_sysfs_builtin(void) { - const struct module_version_attribute *vattr; + const struct module_version_attribute **p; struct module_kobject *mk; int err; - for (vattr = __start___modver; vattr < __stop___modver; vattr++) { + for (p = __start___modver; p < __stop___modver; p++) { + const struct module_version_attribute *vattr = *p; + mk = locate_module_kobject(vattr->module_name); if (mk) { err = sysfs_create_file(&mk->kobj, &vattr->mattr.attr); -- cgit v0.10.2 From 9b73a5840c7d5f77e5766626716df13787cb258c Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Mon, 7 Feb 2011 16:02:27 -0800 Subject: module: do not hide __modver_version_show declaration behind ifdef Doing so prevents the following warning from sparse: CHECK kernel/params.c kernel/params.c:817:9: warning: symbol '__modver_version_show' was not declared. Should it be static? since kernel/params.c is never compiled with MODULE being set. Signed-off-by: Dmitry Torokhov Signed-off-by: Rusty Russell diff --git a/include/linux/module.h b/include/linux/module.h index 4cfebc2..23996ad 100644 --- a/include/linux/module.h +++ b/include/linux/module.h @@ -64,6 +64,9 @@ struct module_version_attribute { const char *version; } __attribute__ ((__aligned__(sizeof(void *)))); +extern ssize_t __modver_version_show(struct module_attribute *, + struct module *, char *); + struct module_kobject { struct kobject kobj; @@ -172,8 +175,6 @@ extern struct module __this_module; #define MODULE_VERSION(_version) MODULE_INFO(version, _version) #else #define MODULE_VERSION(_version) \ - extern ssize_t __modver_version_show(struct module_attribute *, \ - struct module *, char *); \ static struct module_version_attribute ___modver_attr = { \ .mattr = { \ .attr = { \ -- cgit v0.10.2 From a288bd651f4180c224cfddf837a0416157a36661 Mon Sep 17 00:00:00 2001 From: Richard Kennedy Date: Thu, 19 May 2011 16:55:25 -0600 Subject: module: remove 64 bit alignment padding from struct module with CONFIG_TRACE* Reorder struct module to remove 24 bytes of alignment padding on 64 bit builds when the CONFIG_TRACE options are selected. This allows the structure to fit into one fewer cache lines, and its size drops from 592 to 568 on x86_64. Signed-off-by: Richard Kennedy Signed-off-by: Rusty Russell diff --git a/include/linux/module.h b/include/linux/module.h index 23996ad..65cc6cc 100644 --- a/include/linux/module.h +++ b/include/linux/module.h @@ -368,34 +368,35 @@ struct module struct module_notes_attrs *notes_attrs; #endif + /* The command line arguments (may be mangled). People like + keeping pointers to this stuff */ + char *args; + #ifdef CONFIG_SMP /* Per-cpu data. */ void __percpu *percpu; unsigned int percpu_size; #endif - /* The command line arguments (may be mangled). People like - keeping pointers to this stuff */ - char *args; #ifdef CONFIG_TRACEPOINTS - struct tracepoint * const *tracepoints_ptrs; unsigned int num_tracepoints; + struct tracepoint * const *tracepoints_ptrs; #endif #ifdef HAVE_JUMP_LABEL struct jump_entry *jump_entries; unsigned int num_jump_entries; #endif #ifdef CONFIG_TRACING - const char **trace_bprintk_fmt_start; unsigned int num_trace_bprintk_fmt; + const char **trace_bprintk_fmt_start; #endif #ifdef CONFIG_EVENT_TRACING struct ftrace_event_call **trace_events; unsigned int num_trace_events; #endif #ifdef CONFIG_FTRACE_MCOUNT_RECORD - unsigned long *ftrace_callsites; unsigned int num_ftrace_callsites; + unsigned long *ftrace_callsites; #endif #ifdef CONFIG_MODULE_UNLOAD -- cgit v0.10.2 From c5be0b2eb1ca05e0cd747f9c0ba552c6ee8827a0 Mon Sep 17 00:00:00 2001 From: Richard Kennedy Date: Thu, 19 May 2011 16:55:25 -0600 Subject: module: reorder kparam_array to remove alignment padding on 64 bit builds Reorder structure kparam_array to remove 8 bytes of alignment padding on 64 bit builds, dropping its size from 40 to 32 bytes. Also update the macro module_param_array_named to initialise the structure using its member names to allow it to be changed without touching all its call sites. 'git grep' finds module_param_array in 1037 places so this patch will save a small amount of data space across many modules. Signed-off-by: Richard Kennedy Signed-off-by: Rusty Russell diff --git a/include/linux/moduleparam.h b/include/linux/moduleparam.h index 07b4195..ddaae98 100644 --- a/include/linux/moduleparam.h +++ b/include/linux/moduleparam.h @@ -67,9 +67,9 @@ struct kparam_string { struct kparam_array { unsigned int max; + unsigned int elemsize; unsigned int *num; const struct kernel_param_ops *ops; - unsigned int elemsize; void *elem; }; @@ -371,8 +371,9 @@ extern int param_get_invbool(char *buffer, const struct kernel_param *kp); */ #define module_param_array_named(name, array, type, nump, perm) \ static const struct kparam_array __param_arr_##name \ - = { ARRAY_SIZE(array), nump, ¶m_ops_##type, \ - sizeof(array[0]), array }; \ + = { .max = ARRAY_SIZE(array), .num = nump, \ + .ops = ¶m_ops_##type, \ + .elemsize = sizeof(array[0]), .elem = array }; \ __module_param_call(MODULE_PARAM_PREFIX, name, \ ¶m_array_ops, \ .arr = &__param_arr_##name, \ -- cgit v0.10.2 From 5d05c70849f760ac8f4ed3ebfeefb92689858834 Mon Sep 17 00:00:00 2001 From: Daniel J Blueman Date: Tue, 8 Mar 2011 22:01:47 +0800 Subject: minor ANSI prototype sparse fix Fix function prototype to be ANSI-C compliant, consistent with other function prototypes, addressing a sparse warning. Signed-off-by: Daniel J Blueman Signed-off-by: Rusty Russell diff --git a/kernel/module.c b/kernel/module.c index d5938a5..523c40b71 100644 --- a/kernel/module.c +++ b/kernel/module.c @@ -1627,7 +1627,7 @@ void unset_section_ro_nx(struct module *mod, void *module_region) } /* Iterate through all modules and set each module's text as RW */ -void set_all_modules_text_rw() +void set_all_modules_text_rw(void) { struct module *mod; @@ -1648,7 +1648,7 @@ void set_all_modules_text_rw() } /* Iterate through all modules and set each module's text as RO */ -void set_all_modules_text_ro() +void set_all_modules_text_ro(void) { struct module *mod; -- cgit v0.10.2 From 4d10380e720a3ce19dbe88d0133f66ded07b6a8f Mon Sep 17 00:00:00 2001 From: Jan Glauber Date: Thu, 19 May 2011 16:55:25 -0600 Subject: module: zero mod->init_ro_size after init is freed. Reset mod->init_ro_size to zero after the init part of a module is unloaded. Otherwise we need to check if module->init is NULL in the unprotect functions in the next patch. Signed-off-by: Jan Glauber Signed-off-by: Rusty Russell diff --git a/kernel/module.c b/kernel/module.c index 523c40b71..92112c9 100644 --- a/kernel/module.c +++ b/kernel/module.c @@ -2935,6 +2935,7 @@ SYSCALL_DEFINE3(init_module, void __user *, umod, module_free(mod, mod->module_init); mod->module_init = NULL; mod->init_size = 0; + mod->init_ro_size = 0; mod->init_text_size = 0; mutex_unlock(&module_mutex); -- cgit v0.10.2 From 448694a1d50432be63aafccb42d6f54d8cf3d02c Mon Sep 17 00:00:00 2001 From: Jan Glauber Date: Thu, 19 May 2011 16:55:26 -0600 Subject: module: undo module RONX protection correctly. While debugging I stumbled over two problems in the code that protects module pages. First issue is that disabling the protection before freeing init or unload of a module is not symmetric with the enablement. For instance, if pages are set to RO the page range from module_core to module_core + core_ro_size is protected. If a module is unloaded the page range from module_core to module_core + core_size is set back to RW. So pages that were not set to RO are also changed to RW. This is not critical but IMHO it should be symmetric. Second issue is that while set_memory_rw & set_memory_ro are used for RO/RW changes only set_memory_nx is involved for NX/X. One would await that the inverse function is called when the NX protection should be removed, which is not the case here, unless I'm missing something. Signed-off-by: Jan Glauber Signed-off-by: Rusty Russell diff --git a/arch/s390/include/asm/cacheflush.h b/arch/s390/include/asm/cacheflush.h index 43a5c78..3e20383 100644 --- a/arch/s390/include/asm/cacheflush.h +++ b/arch/s390/include/asm/cacheflush.h @@ -11,5 +11,6 @@ void kernel_map_pages(struct page *page, int numpages, int enable); int set_memory_ro(unsigned long addr, int numpages); int set_memory_rw(unsigned long addr, int numpages); int set_memory_nx(unsigned long addr, int numpages); +int set_memory_x(unsigned long addr, int numpages); #endif /* _S390_CACHEFLUSH_H */ diff --git a/arch/s390/mm/pageattr.c b/arch/s390/mm/pageattr.c index 0607e4b..f05edcc 100644 --- a/arch/s390/mm/pageattr.c +++ b/arch/s390/mm/pageattr.c @@ -54,3 +54,8 @@ int set_memory_nx(unsigned long addr, int numpages) return 0; } EXPORT_SYMBOL_GPL(set_memory_nx); + +int set_memory_x(unsigned long addr, int numpages) +{ + return 0; +} diff --git a/kernel/module.c b/kernel/module.c index 92112c9..b99dceb 100644 --- a/kernel/module.c +++ b/kernel/module.c @@ -1607,22 +1607,23 @@ static void set_section_ro_nx(void *base, } } -/* Setting memory back to RW+NX before releasing it */ +/* Setting memory back to W+X before releasing it */ void unset_section_ro_nx(struct module *mod, void *module_region) { - unsigned long total_pages; - if (mod->module_core == module_region) { - /* Set core as NX+RW */ - total_pages = MOD_NUMBER_OF_PAGES(mod->module_core, mod->core_size); - set_memory_nx((unsigned long)mod->module_core, total_pages); - set_memory_rw((unsigned long)mod->module_core, total_pages); - + set_page_attributes(mod->module_core + mod->core_text_size, + mod->module_core + mod->core_size, + set_memory_x); + set_page_attributes(mod->module_core, + mod->module_core + mod->core_ro_size, + set_memory_rw); } else if (mod->module_init == module_region) { - /* Set init as NX+RW */ - total_pages = MOD_NUMBER_OF_PAGES(mod->module_init, mod->init_size); - set_memory_nx((unsigned long)mod->module_init, total_pages); - set_memory_rw((unsigned long)mod->module_init, total_pages); + set_page_attributes(mod->module_init + mod->init_text_size, + mod->module_init + mod->init_size, + set_memory_x); + set_page_attributes(mod->module_init, + mod->module_init + mod->init_ro_size, + set_memory_rw); } } -- cgit v0.10.2 From 01526ed0830643bd53a8434c3068e4c077e1b09d Mon Sep 17 00:00:00 2001 From: Jan Glauber Date: Thu, 19 May 2011 16:55:26 -0600 Subject: module: split unset_section_ro_nx function. Split the unprotect function into a function per section to make the code more readable and add the missing static declaration. Signed-off-by: Jan Glauber Signed-off-by: Rusty Russell diff --git a/kernel/module.c b/kernel/module.c index b99dceb..0e6f97f 100644 --- a/kernel/module.c +++ b/kernel/module.c @@ -1607,24 +1607,24 @@ static void set_section_ro_nx(void *base, } } -/* Setting memory back to W+X before releasing it */ -void unset_section_ro_nx(struct module *mod, void *module_region) -{ - if (mod->module_core == module_region) { - set_page_attributes(mod->module_core + mod->core_text_size, - mod->module_core + mod->core_size, - set_memory_x); - set_page_attributes(mod->module_core, - mod->module_core + mod->core_ro_size, - set_memory_rw); - } else if (mod->module_init == module_region) { - set_page_attributes(mod->module_init + mod->init_text_size, - mod->module_init + mod->init_size, - set_memory_x); - set_page_attributes(mod->module_init, - mod->module_init + mod->init_ro_size, - set_memory_rw); - } +static void unset_module_core_ro_nx(struct module *mod) +{ + set_page_attributes(mod->module_core + mod->core_text_size, + mod->module_core + mod->core_size, + set_memory_x); + set_page_attributes(mod->module_core, + mod->module_core + mod->core_ro_size, + set_memory_rw); +} + +static void unset_module_init_ro_nx(struct module *mod) +{ + set_page_attributes(mod->module_init + mod->init_text_size, + mod->module_init + mod->init_size, + set_memory_x); + set_page_attributes(mod->module_init, + mod->module_init + mod->init_ro_size, + set_memory_rw); } /* Iterate through all modules and set each module's text as RW */ @@ -1670,7 +1670,8 @@ void set_all_modules_text_ro(void) } #else static inline void set_section_ro_nx(void *base, unsigned long text_size, unsigned long ro_size, unsigned long total_size) { } -static inline void unset_section_ro_nx(struct module *mod, void *module_region) { } +static void unset_module_core_ro_nx(struct module *mod) { } +static void unset_module_init_ro_nx(struct module *mod) { } #endif /* Free a module, remove from lists, etc. */ @@ -1697,7 +1698,7 @@ static void free_module(struct module *mod) destroy_params(mod->kp, mod->num_kp); /* This may be NULL, but that's OK */ - unset_section_ro_nx(mod, mod->module_init); + unset_module_init_ro_nx(mod); module_free(mod, mod->module_init); kfree(mod->args); percpu_modfree(mod); @@ -1706,7 +1707,7 @@ static void free_module(struct module *mod) lockdep_free_key_range(mod->module_core, mod->core_size); /* Finally, free the core (containing the module structure) */ - unset_section_ro_nx(mod, mod->module_core); + unset_module_core_ro_nx(mod); module_free(mod, mod->module_core); #ifdef CONFIG_MPU @@ -2932,7 +2933,7 @@ SYSCALL_DEFINE3(init_module, void __user *, umod, mod->symtab = mod->core_symtab; mod->strtab = mod->core_strtab; #endif - unset_section_ro_nx(mod, mod->module_init); + unset_module_init_ro_nx(mod); module_free(mod, mod->module_init); mod->module_init = NULL; mod->init_size = 0; -- cgit v0.10.2 From de4d8d53465483168d6a627d409ee2d09d8e3308 Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Tue, 19 Apr 2011 21:49:58 +0200 Subject: module: each_symbol_section instead of each_symbol Instead of having a callback function for each symbol in the kernel, have a callback for each array of symbols. This eases the logic when we move to sorted symbols and binary search. Signed-off-by: Rusty Russell Signed-off-by: Alessio Igor Bogani diff --git a/include/linux/module.h b/include/linux/module.h index 65cc6cc..49f4ad0 100644 --- a/include/linux/module.h +++ b/include/linux/module.h @@ -477,8 +477,9 @@ const struct kernel_symbol *find_symbol(const char *name, bool warn); /* Walk the exported symbol table */ -bool each_symbol(bool (*fn)(const struct symsearch *arr, struct module *owner, - unsigned int symnum, void *data), void *data); +bool each_symbol_section(bool (*fn)(const struct symsearch *arr, + struct module *owner, + void *data), void *data); /* Returns 0 and fills in value, defined and namebuf, or -ERANGE if symnum out of range. */ diff --git a/kernel/module.c b/kernel/module.c index 0e6f97f..e8aa462 100644 --- a/kernel/module.c +++ b/kernel/module.c @@ -240,23 +240,24 @@ static bool each_symbol_in_section(const struct symsearch *arr, struct module *owner, bool (*fn)(const struct symsearch *syms, struct module *owner, - unsigned int symnum, void *data), + void *data), void *data) { - unsigned int i, j; + unsigned int j; for (j = 0; j < arrsize; j++) { - for (i = 0; i < arr[j].stop - arr[j].start; i++) - if (fn(&arr[j], owner, i, data)) - return true; + if (fn(&arr[j], owner, data)) + return true; } return false; } /* Returns true as soon as fn returns true, otherwise false. */ -bool each_symbol(bool (*fn)(const struct symsearch *arr, struct module *owner, - unsigned int symnum, void *data), void *data) +bool each_symbol_section(bool (*fn)(const struct symsearch *arr, + struct module *owner, + void *data), + void *data) { struct module *mod; static const struct symsearch arr[] = { @@ -309,7 +310,7 @@ bool each_symbol(bool (*fn)(const struct symsearch *arr, struct module *owner, } return false; } -EXPORT_SYMBOL_GPL(each_symbol); +EXPORT_SYMBOL_GPL(each_symbol_section); struct find_symbol_arg { /* Input */ @@ -323,15 +324,12 @@ struct find_symbol_arg { const struct kernel_symbol *sym; }; -static bool find_symbol_in_section(const struct symsearch *syms, - struct module *owner, - unsigned int symnum, void *data) +static bool check_symbol(const struct symsearch *syms, + struct module *owner, + unsigned int symnum, void *data) { struct find_symbol_arg *fsa = data; - if (strcmp(syms->start[symnum].name, fsa->name) != 0) - return false; - if (!fsa->gplok) { if (syms->licence == GPL_ONLY) return false; @@ -365,6 +363,20 @@ static bool find_symbol_in_section(const struct symsearch *syms, return true; } +static bool find_symbol_in_section(const struct symsearch *syms, + struct module *owner, + void *data) +{ + struct find_symbol_arg *fsa = data; + unsigned int i; + + for (i = 0; i < syms->stop - syms->start; i++) { + if (strcmp(syms->start[i].name, fsa->name) == 0) + return check_symbol(syms, owner, i, data); + } + return false; +} + /* Find a symbol and return it, along with, (optional) crc and * (optional) module which owns it. Needs preempt disabled or module_mutex. */ const struct kernel_symbol *find_symbol(const char *name, @@ -379,7 +391,7 @@ const struct kernel_symbol *find_symbol(const char *name, fsa.gplok = gplok; fsa.warn = warn; - if (each_symbol(find_symbol_in_section, &fsa)) { + if (each_symbol_section(find_symbol_in_section, &fsa)) { if (owner) *owner = fsa.owner; if (crc) -- cgit v0.10.2 From f02e8a6596b7dc9b2171f7ff5654039ef0950cdc Mon Sep 17 00:00:00 2001 From: Alessio Igor Bogani Date: Thu, 14 Apr 2011 14:59:39 +0200 Subject: module: Sort exported symbols This patch places every exported symbol in its own section (i.e. "___ksymtab+printk"). Thus the linker will use its SORT() directive to sort and finally merge all symbol in the right and final section (i.e. "__ksymtab"). The symbol prefixed archs use an underscore as prefix for symbols. To avoid collision we use a different character to create the temporary section names. This work was supported by a hardware donation from the CE Linux Forum. Signed-off-by: Alessio Igor Bogani Signed-off-by: Rusty Russell (folded in '+' fixup) Tested-by: Dirk Behme diff --git a/include/asm-generic/vmlinux.lds.h b/include/asm-generic/vmlinux.lds.h index bd297a2..b27445e 100644 --- a/include/asm-generic/vmlinux.lds.h +++ b/include/asm-generic/vmlinux.lds.h @@ -274,70 +274,70 @@ /* Kernel symbol table: Normal symbols */ \ __ksymtab : AT(ADDR(__ksymtab) - LOAD_OFFSET) { \ VMLINUX_SYMBOL(__start___ksymtab) = .; \ - *(__ksymtab) \ + *(SORT(___ksymtab+*)) \ VMLINUX_SYMBOL(__stop___ksymtab) = .; \ } \ \ /* Kernel symbol table: GPL-only symbols */ \ __ksymtab_gpl : AT(ADDR(__ksymtab_gpl) - LOAD_OFFSET) { \ VMLINUX_SYMBOL(__start___ksymtab_gpl) = .; \ - *(__ksymtab_gpl) \ + *(SORT(___ksymtab_gpl+*)) \ VMLINUX_SYMBOL(__stop___ksymtab_gpl) = .; \ } \ \ /* Kernel symbol table: Normal unused symbols */ \ __ksymtab_unused : AT(ADDR(__ksymtab_unused) - LOAD_OFFSET) { \ VMLINUX_SYMBOL(__start___ksymtab_unused) = .; \ - *(__ksymtab_unused) \ + *(SORT(___ksymtab_unused+*)) \ VMLINUX_SYMBOL(__stop___ksymtab_unused) = .; \ } \ \ /* Kernel symbol table: GPL-only unused symbols */ \ __ksymtab_unused_gpl : AT(ADDR(__ksymtab_unused_gpl) - LOAD_OFFSET) { \ VMLINUX_SYMBOL(__start___ksymtab_unused_gpl) = .; \ - *(__ksymtab_unused_gpl) \ + *(SORT(___ksymtab_unused_gpl+*)) \ VMLINUX_SYMBOL(__stop___ksymtab_unused_gpl) = .; \ } \ \ /* Kernel symbol table: GPL-future-only symbols */ \ __ksymtab_gpl_future : AT(ADDR(__ksymtab_gpl_future) - LOAD_OFFSET) { \ VMLINUX_SYMBOL(__start___ksymtab_gpl_future) = .; \ - *(__ksymtab_gpl_future) \ + *(SORT(___ksymtab_gpl_future+*)) \ VMLINUX_SYMBOL(__stop___ksymtab_gpl_future) = .; \ } \ \ /* Kernel symbol table: Normal symbols */ \ __kcrctab : AT(ADDR(__kcrctab) - LOAD_OFFSET) { \ VMLINUX_SYMBOL(__start___kcrctab) = .; \ - *(__kcrctab) \ + *(SORT(___kcrctab+*)) \ VMLINUX_SYMBOL(__stop___kcrctab) = .; \ } \ \ /* Kernel symbol table: GPL-only symbols */ \ __kcrctab_gpl : AT(ADDR(__kcrctab_gpl) - LOAD_OFFSET) { \ VMLINUX_SYMBOL(__start___kcrctab_gpl) = .; \ - *(__kcrctab_gpl) \ + *(SORT(___kcrctab_gpl+*)) \ VMLINUX_SYMBOL(__stop___kcrctab_gpl) = .; \ } \ \ /* Kernel symbol table: Normal unused symbols */ \ __kcrctab_unused : AT(ADDR(__kcrctab_unused) - LOAD_OFFSET) { \ VMLINUX_SYMBOL(__start___kcrctab_unused) = .; \ - *(__kcrctab_unused) \ + *(SORT(___kcrctab_unused+*)) \ VMLINUX_SYMBOL(__stop___kcrctab_unused) = .; \ } \ \ /* Kernel symbol table: GPL-only unused symbols */ \ __kcrctab_unused_gpl : AT(ADDR(__kcrctab_unused_gpl) - LOAD_OFFSET) { \ VMLINUX_SYMBOL(__start___kcrctab_unused_gpl) = .; \ - *(__kcrctab_unused_gpl) \ + *(SORT(___kcrctab_unused_gpl+*)) \ VMLINUX_SYMBOL(__stop___kcrctab_unused_gpl) = .; \ } \ \ /* Kernel symbol table: GPL-future-only symbols */ \ __kcrctab_gpl_future : AT(ADDR(__kcrctab_gpl_future) - LOAD_OFFSET) { \ VMLINUX_SYMBOL(__start___kcrctab_gpl_future) = .; \ - *(__kcrctab_gpl_future) \ + *(SORT(___kcrctab_gpl_future+*)) \ VMLINUX_SYMBOL(__stop___kcrctab_gpl_future) = .; \ } \ \ diff --git a/include/linux/module.h b/include/linux/module.h index 49f4ad0..d9ca2d5 100644 --- a/include/linux/module.h +++ b/include/linux/module.h @@ -224,7 +224,7 @@ struct module_use { extern void *__crc_##sym __attribute__((weak)); \ static const unsigned long __kcrctab_##sym \ __used \ - __attribute__((section("__kcrctab" sec), unused)) \ + __attribute__((section("___kcrctab" sec "+" #sym), unused)) \ = (unsigned long) &__crc_##sym; #else #define __CRC_SYMBOL(sym, sec) @@ -239,7 +239,7 @@ struct module_use { = MODULE_SYMBOL_PREFIX #sym; \ static const struct kernel_symbol __ksymtab_##sym \ __used \ - __attribute__((section("__ksymtab" sec), unused)) \ + __attribute__((section("___ksymtab" sec "+" #sym), unused)) \ = { (unsigned long)&sym, __kstrtab_##sym } #define EXPORT_SYMBOL(sym) \ diff --git a/scripts/module-common.lds b/scripts/module-common.lds index 47a1f9a..0865b3e 100644 --- a/scripts/module-common.lds +++ b/scripts/module-common.lds @@ -5,4 +5,15 @@ */ SECTIONS { /DISCARD/ : { *(.discard) } + + __ksymtab : { *(SORT(___ksymtab+*)) } + __ksymtab_gpl : { *(SORT(___ksymtab_gpl+*)) } + __ksymtab_unused : { *(SORT(___ksymtab_unused+*)) } + __ksymtab_unused_gpl : { *(SORT(___ksymtab_unused_gpl+*)) } + __ksymtab_gpl_future : { *(SORT(___ksymtab_gpl_future+*)) } + __kcrctab : { *(SORT(___kcrctab+*)) } + __kcrctab_gpl : { *(SORT(___kcrctab_gpl+*)) } + __kcrctab_unused : { *(SORT(___kcrctab_unused+*)) } + __kcrctab_unused_gpl : { *(SORT(___kcrctab_unused_gpl+*)) } + __kcrctab_gpl_future : { *(SORT(___kcrctab_gpl_future+*)) } } -- cgit v0.10.2 From 1a94dc35bc5c166d89913dc01a49d27a3c21a455 Mon Sep 17 00:00:00 2001 From: Tim Abbott Date: Thu, 14 Apr 2011 20:00:19 +0200 Subject: lib: Add generic binary search function to the kernel. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit There a large number hand-coded binary searches in the kernel (run "git grep search | grep binary" to find many of them). Since in my experience, hand-coding binary searches can be error-prone, it seems worth cleaning this up by providing a generic binary search function. This generic binary search implementation comes from Ksplice. It has the same basic API as the C library bsearch() function. Ksplice uses it in half a dozen places with 4 different comparison functions, and I think our code is substantially cleaner because of this. Signed-off-by: Tim Abbott Extra-bikeshedding-by: Alan Jenkins Extra-bikeshedding-by: André Goddard Rosa Extra-bikeshedding-by: Rusty Russell Signed-off-by: Rusty Russell Signed-off-by: Alessio Igor Bogani Signed-off-by: Rusty Russell diff --git a/include/linux/bsearch.h b/include/linux/bsearch.h new file mode 100644 index 0000000..90b1aa8 --- /dev/null +++ b/include/linux/bsearch.h @@ -0,0 +1,9 @@ +#ifndef _LINUX_BSEARCH_H +#define _LINUX_BSEARCH_H + +#include + +void *bsearch(const void *key, const void *base, size_t num, size_t size, + int (*cmp)(const void *key, const void *elt)); + +#endif /* _LINUX_BSEARCH_H */ diff --git a/lib/Makefile b/lib/Makefile index ef0f285..4b49a24 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -21,7 +21,8 @@ lib-y += kobject.o kref.o klist.o obj-y += bcd.o div64.o sort.o parser.o halfmd4.o debug_locks.o random32.o \ bust_spinlocks.o hexdump.o kasprintf.o bitmap.o scatterlist.o \ - string_helpers.o gcd.o lcm.o list_sort.o uuid.o flex_array.o + string_helpers.o gcd.o lcm.o list_sort.o uuid.o flex_array.o \ + bsearch.o obj-y += kstrtox.o obj-$(CONFIG_TEST_KSTRTOX) += test-kstrtox.o diff --git a/lib/bsearch.c b/lib/bsearch.c new file mode 100644 index 0000000..5b54758 --- /dev/null +++ b/lib/bsearch.c @@ -0,0 +1,53 @@ +/* + * A generic implementation of binary search for the Linux kernel + * + * Copyright (C) 2008-2009 Ksplice, Inc. + * Author: Tim Abbott + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; version 2. + */ + +#include +#include + +/* + * bsearch - binary search an array of elements + * @key: pointer to item being searched for + * @base: pointer to first element to search + * @num: number of elements + * @size: size of each element + * @cmp: pointer to comparison function + * + * This function does a binary search on the given array. The + * contents of the array should already be in ascending sorted order + * under the provided comparison function. + * + * Note that the key need not have the same type as the elements in + * the array, e.g. key could be a string and the comparison function + * could compare the string with the struct's name field. However, if + * the key and elements in the array are of the same type, you can use + * the same comparison function for both sort() and bsearch(). + */ +void *bsearch(const void *key, const void *base, size_t num, size_t size, + int (*cmp)(const void *key, const void *elt)) +{ + size_t start = 0, end = num; + int result; + + while (start < end) { + size_t mid = start + (end - start) / 2; + + result = cmp(key, base + mid * size); + if (result < 0) + end = mid; + else if (result > 0) + start = mid + 1; + else + return (void *)base + mid * size; + } + + return NULL; +} +EXPORT_SYMBOL(bsearch); -- cgit v0.10.2 From 23a6c484047bb8ac50e6d5bb718f8d178a4bf32e Mon Sep 17 00:00:00 2001 From: Nishanth Aravamudan Date: Wed, 11 May 2011 11:07:51 +0000 Subject: powerpc/pseries/iommu: Use correct return type in dupe_ddw_if_already_created Otherwise we get silent truncations. Signed-off-by: Nishanth Aravamudan Cc: Anton Blanchard Cc: Milton Miller Cc: linuxppc-dev@ozlabs.org Signed-off-by: Benjamin Herrenschmidt diff --git a/arch/powerpc/platforms/pseries/iommu.c b/arch/powerpc/platforms/pseries/iommu.c index 48eec3b..44d47ac 100644 --- a/arch/powerpc/platforms/pseries/iommu.c +++ b/arch/powerpc/platforms/pseries/iommu.c @@ -693,7 +693,7 @@ static void remove_ddw(struct device_node *np) } -static int dupe_ddw_if_already_created(struct pci_dev *dev, struct device_node *pdn) +static u64 dupe_ddw_if_already_created(struct pci_dev *dev, struct device_node *pdn) { struct device_node *dn; struct pci_dn *pcidn; -- cgit v0.10.2 From 403ed27846aa126ecf0b842b5b179c506b9d989c Mon Sep 17 00:00:00 2001 From: Alessio Igor Bogani Date: Wed, 20 Apr 2011 11:10:52 +0200 Subject: module: Use the binary search for symbols resolution Takes advantage of the order and locates symbols using binary search. This work was supported by a hardware donation from the CE Linux Forum. Signed-off-by: Alessio Igor Bogani Signed-off-by: Rusty Russell Tested-by: Dirk Behme diff --git a/kernel/module.c b/kernel/module.c index e8aa462..d1db8eb 100644 --- a/kernel/module.c +++ b/kernel/module.c @@ -57,6 +57,7 @@ #include #include #include +#include #define CREATE_TRACE_POINTS #include @@ -363,17 +364,27 @@ static bool check_symbol(const struct symsearch *syms, return true; } +static int cmp_name(const void *va, const void *vb) +{ + const char *a; + const struct kernel_symbol *b; + a = va; b = vb; + return strcmp(a, b->name); +} + static bool find_symbol_in_section(const struct symsearch *syms, struct module *owner, void *data) { struct find_symbol_arg *fsa = data; - unsigned int i; + struct kernel_symbol *sym; + + sym = bsearch(fsa->name, syms->start, syms->stop - syms->start, + sizeof(struct kernel_symbol), cmp_name); + + if (sym != NULL && check_symbol(syms, owner, sym - syms->start, data)) + return true; - for (i = 0; i < syms->stop - syms->start; i++) { - if (strcmp(syms->start[i].name, fsa->name) == 0) - return check_symbol(syms, owner, i, data); - } return false; } -- cgit v0.10.2 From 64ac822fb4554fb516bce123a38b35e04e41fff5 Mon Sep 17 00:00:00 2001 From: Milton Miller Date: Wed, 11 May 2011 12:24:57 +0000 Subject: powerpc/pseries/iommu: Add additional checks when changing iommu mask Do not check dma supported until we have chosen the right dma ops. Check that the device is pci before treating it as such. Check the mask is supported by the selected dma ops before committing it. We only need to set iommu ops if it is not the current ops; this avoids searching the tree for the iommu table unnecessarily. Signed-off-by: Milton Miller Signed-off-by: Nishanth Aravamudan Signed-off-by: Benjamin Herrenschmidt diff --git a/arch/powerpc/platforms/pseries/iommu.c b/arch/powerpc/platforms/pseries/iommu.c index 44d47ac..05c101e 100644 --- a/arch/powerpc/platforms/pseries/iommu.c +++ b/arch/powerpc/platforms/pseries/iommu.c @@ -1026,9 +1026,12 @@ static int dma_set_mask_pSeriesLP(struct device *dev, u64 dma_mask) const void *dma_window = NULL; u64 dma_offset; - if (!dev->dma_mask || !dma_supported(dev, dma_mask)) + if (!dev->dma_mask) return -EIO; + if (!dev_is_pci(dev)) + goto check_mask; + pdev = to_pci_dev(dev); /* only attempt to use a new window if 64-bit DMA is requested */ @@ -1059,13 +1062,17 @@ static int dma_set_mask_pSeriesLP(struct device *dev, u64 dma_mask) } } - /* fall-through to iommu ops */ - if (!ddw_enabled) { - dev_info(dev, "Using 32-bit DMA via iommu\n"); + /* fall back on iommu ops, restore table pointer with ops */ + if (!ddw_enabled && get_dma_ops(dev) != &dma_iommu_ops) { + dev_info(dev, "Restoring 32-bit DMA via iommu\n"); set_dma_ops(dev, &dma_iommu_ops); pci_dma_dev_setup_pSeriesLP(pdev); } +check_mask: + if (!dma_supported(dev, dma_mask)) + return -EIO; + *dev->dma_mask = dma_mask; return 0; } -- cgit v0.10.2 From 9d63487f86115b1d3ef69670043bcf2b83c4d227 Mon Sep 17 00:00:00 2001 From: Alessio Igor Bogani Date: Wed, 18 May 2011 22:35:59 +0200 Subject: module: Use binary search in lookup_symbol() The function is_exported() with its helper function lookup_symbol() are used to verify if a provided symbol is effectively exported by the kernel or by the modules. Now that both have their symbols sorted we can replace a linear search with a binary search which provide a considerably speed-up. This work was supported by a hardware donation from the CE Linux Forum. Signed-off-by: Alessio Igor Bogani Acked-by: Greg Kroah-Hartman Signed-off-by: Rusty Russell diff --git a/kernel/module.c b/kernel/module.c index d1db8eb..2287972 100644 --- a/kernel/module.c +++ b/kernel/module.c @@ -2055,11 +2055,8 @@ static const struct kernel_symbol *lookup_symbol(const char *name, const struct kernel_symbol *start, const struct kernel_symbol *stop) { - const struct kernel_symbol *ks = start; - for (; ks < stop; ks++) - if (strcmp(ks->name, name) == 0) - return ks; - return NULL; + return bsearch(name, start, stop - start, + sizeof(struct kernel_symbol), cmp_name); } static int is_exported(const char *name, unsigned long value, -- cgit v0.10.2 From 2573f6842201a00f139237e4b42ab16711b582af Mon Sep 17 00:00:00 2001 From: Milton Miller Date: Wed, 11 May 2011 12:24:58 +0000 Subject: powerpc/pseries/iommu: Remove ddw property when destroying window If we destroy the window, we need to remove the property recording that we setup the window. Otherwise the next kernel we kexec will be confused. Also we should remove the property if even if we don't find the ibm,ddw-applicable window or if one of the property sizes is unexpected; presumably these came from a prior kernel via kexec, and we will not be maintaining the window with respect to memory hotplug. Signed-off-by: Milton Miller Signed-off-by: Nishanth Aravamudan Signed-off-by: Benjamin Herrenschmidt diff --git a/arch/powerpc/platforms/pseries/iommu.c b/arch/powerpc/platforms/pseries/iommu.c index 05c101e..a0421ac 100644 --- a/arch/powerpc/platforms/pseries/iommu.c +++ b/arch/powerpc/platforms/pseries/iommu.c @@ -665,9 +665,12 @@ static void remove_ddw(struct device_node *np) ddr_avail = of_get_property(np, "ibm,ddw-applicable", &len); win64 = of_find_property(np, DIRECT64_PROPNAME, NULL); - if (!win64 || !ddr_avail || len < 3 * sizeof(u32)) + if (!win64) return; + if (!ddr_avail || len < 3 * sizeof(u32) || win64->length < sizeof(*dwp)) + goto delprop; + dwp = win64->value; liobn = (u64)be32_to_cpu(dwp->liobn); @@ -690,8 +693,13 @@ static void remove_ddw(struct device_node *np) pr_debug("%s: successfully removed direct window: rtas returned " "%d to ibm,remove-pe-dma-window(%x) %llx\n", np->full_name, ret, ddr_avail[2], liobn); -} +delprop: + ret = of_remove_property(np, win64); + if (ret) + pr_warning("%s: failed to remove direct window property: %d\n" + np->full_name, ret); +} static u64 dupe_ddw_if_already_created(struct pci_dev *dev, struct device_node *pdn) { -- cgit v0.10.2 From 6845756b29e4c4e7db41e2d75cafa9d091bc1c07 Mon Sep 17 00:00:00 2001 From: Anders Kaseorg Date: Thu, 19 May 2011 16:55:27 -0600 Subject: modpost: Update 64k section support for binutils 2.18.50 Binutils 2.18.50 made a backwards-incompatible change in the way it writes ELF objects with over 65280 sections, to improve conformance with the ELF specification and interoperability with other ELF tools. Specifically, it no longer adds 256 to section indices SHN_LORESERVE and higher to skip over the reserved range SHN_LORESERVE through SHN_HIRESERVE; those values are only considered special in the st_shndx field, and not in other places where section indices are stored. See: http://sourceware.org/bugzilla/show_bug.cgi?id=5900 http://groups.google.com/group/generic-abi/browse_thread/thread/e8bb63714b072e67/6c63738f12cc8a17 Signed-off-by: Anders Kaseorg Signed-off-by: Rusty Russell diff --git a/scripts/mod/modpost.c b/scripts/mod/modpost.c index cd104af..413c536 100644 --- a/scripts/mod/modpost.c +++ b/scripts/mod/modpost.c @@ -420,11 +420,10 @@ static int parse_elf(struct elf_info *info, const char *filename) return 0; } - if (hdr->e_shnum == 0) { + if (hdr->e_shnum == SHN_UNDEF) { /* * There are more than 64k sections, * read count from .sh_size. - * note: it doesn't need shndx2secindex() */ info->num_sections = TO_NATIVE(sechdrs[0].sh_size); } @@ -432,8 +431,7 @@ static int parse_elf(struct elf_info *info, const char *filename) info->num_sections = hdr->e_shnum; } if (hdr->e_shstrndx == SHN_XINDEX) { - info->secindex_strings = - shndx2secindex(TO_NATIVE(sechdrs[0].sh_link)); + info->secindex_strings = TO_NATIVE(sechdrs[0].sh_link); } else { info->secindex_strings = hdr->e_shstrndx; @@ -489,7 +487,7 @@ static int parse_elf(struct elf_info *info, const char *filename) sechdrs[i].sh_offset; info->symtab_stop = (void *)hdr + sechdrs[i].sh_offset + sechdrs[i].sh_size; - sh_link_idx = shndx2secindex(sechdrs[i].sh_link); + sh_link_idx = sechdrs[i].sh_link; info->strtab = (void *)hdr + sechdrs[sh_link_idx].sh_offset; } @@ -516,11 +514,9 @@ static int parse_elf(struct elf_info *info, const char *filename) if (symtab_shndx_idx != ~0U) { Elf32_Word *p; - if (symtab_idx != - shndx2secindex(sechdrs[symtab_shndx_idx].sh_link)) + if (symtab_idx != sechdrs[symtab_shndx_idx].sh_link) fatal("%s: SYMTAB_SHNDX has bad sh_link: %u!=%u\n", - filename, - shndx2secindex(sechdrs[symtab_shndx_idx].sh_link), + filename, sechdrs[symtab_shndx_idx].sh_link, symtab_idx); /* Fix endianness */ for (p = info->symtab_shndx_start; p < info->symtab_shndx_stop; @@ -1446,7 +1442,7 @@ static unsigned int *reloc_location(struct elf_info *elf, Elf_Shdr *sechdr, Elf_Rela *r) { Elf_Shdr *sechdrs = elf->sechdrs; - int section = shndx2secindex(sechdr->sh_info); + int section = sechdr->sh_info; return (void *)elf->hdr + sechdrs[section].sh_offset + r->r_offset; diff --git a/scripts/mod/modpost.h b/scripts/mod/modpost.h index 0388cfcc..2031119 100644 --- a/scripts/mod/modpost.h +++ b/scripts/mod/modpost.h @@ -145,33 +145,22 @@ static inline int is_shndx_special(unsigned int i) return i != SHN_XINDEX && i >= SHN_LORESERVE && i <= SHN_HIRESERVE; } -/* shndx is in [0..SHN_LORESERVE) U (SHN_HIRESERVE, 0xfffffff], thus: - * shndx == 0 <=> sechdrs[0] - * ...... - * shndx == SHN_LORESERVE-1 <=> sechdrs[SHN_LORESERVE-1] - * shndx == SHN_HIRESERVE+1 <=> sechdrs[SHN_LORESERVE] - * shndx == SHN_HIRESERVE+2 <=> sechdrs[SHN_LORESERVE+1] - * ...... - * fyi: sym->st_shndx is uint16, SHN_LORESERVE = ff00, SHN_HIRESERVE = ffff, - * so basically we map 0000..feff -> 0000..feff - * ff00..ffff -> (you are a bad boy, dont do it) - * 10000..xxxx -> ff00..(xxxx-0x100) +/* + * Move reserved section indices SHN_LORESERVE..SHN_HIRESERVE out of + * the way to -256..-1, to avoid conflicting with real section + * indices. */ -static inline unsigned int shndx2secindex(unsigned int i) -{ - if (i <= SHN_HIRESERVE) - return i; - return i - (SHN_HIRESERVE + 1 - SHN_LORESERVE); -} +#define SPECIAL(i) ((i) - (SHN_HIRESERVE + 1)) /* Accessor for sym->st_shndx, hides ugliness of "64k sections" */ static inline unsigned int get_secindex(const struct elf_info *info, const Elf_Sym *sym) { + if (is_shndx_special(sym->st_shndx)) + return SPECIAL(sym->st_shndx); if (sym->st_shndx != SHN_XINDEX) return sym->st_shndx; - return shndx2secindex(info->symtab_shndx_start[sym - - info->symtab_start]); + return info->symtab_shndx_start[sym - info->symtab_start]; } /* file2alias.c */ -- cgit v0.10.2 From d0f1fed29e6e73d9d17f4c91a5896a4ce3938d45 Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Tue, 19 Apr 2011 12:43:45 +0100 Subject: Add a strtobool function matching semantics of existing in kernel equivalents This is a rename of the usr_strtobool proposal, which was a renamed, relocated and fixed version of previous kstrtobool RFC Signed-off-by: Jonathan Cameron Signed-off-by: Rusty Russell diff --git a/include/linux/string.h b/include/linux/string.h index a716ee2..a176db2 100644 --- a/include/linux/string.h +++ b/include/linux/string.h @@ -123,6 +123,7 @@ extern char **argv_split(gfp_t gfp, const char *str, int *argcp); extern void argv_free(char **argv); extern bool sysfs_streq(const char *s1, const char *s2); +extern int strtobool(const char *s, bool *res); #ifdef CONFIG_BINARY_PRINTF int vbin_printf(u32 *bin_buf, size_t size, const char *fmt, va_list args); diff --git a/lib/string.c b/lib/string.c index f71bead..01fad9b 100644 --- a/lib/string.c +++ b/lib/string.c @@ -535,6 +535,35 @@ bool sysfs_streq(const char *s1, const char *s2) } EXPORT_SYMBOL(sysfs_streq); +/** + * strtobool - convert common user inputs into boolean values + * @s: input string + * @res: result + * + * This routine returns 0 iff the first character is one of 'Yy1Nn0'. + * Otherwise it will return -EINVAL. Value pointed to by res is + * updated upon finding a match. + */ +int strtobool(const char *s, bool *res) +{ + switch (s[0]) { + case 'y': + case 'Y': + case '1': + *res = true; + break; + case 'n': + case 'N': + case '0': + *res = false; + break; + default: + return -EINVAL; + } + return 0; +} +EXPORT_SYMBOL(strtobool); + #ifndef __HAVE_ARCH_MEMSET /** * memset - Fill a region of memory with the given value -- cgit v0.10.2 From c85667802bb5093c4054f8a887a90dd0acf82d3e Mon Sep 17 00:00:00 2001 From: Milton Miller Date: Wed, 11 May 2011 12:24:59 +0000 Subject: powerpc/pseries/iommu: Find windows after kexec during boot Move the discovery of windows previously setup from when the pci driver calls set_dma_mask to an arch_initcall. When kexecing into a kernel with dynamic dma windows allocated, we need to find the windows early so that memory hot remove will be able to delete the tces mapping the to be removed memory and memory hotplug add will map the new memory into the window. We should not wait for the driver to be loaded and the device to be probed. The iommu init hooks are before kmalloc is setup, so defer to arch_initcall. Signed-off-by: Milton Miller Signed-off-by: Nishanth Aravamudan Signed-off-by: Benjamin Herrenschmidt diff --git a/arch/powerpc/platforms/pseries/iommu.c b/arch/powerpc/platforms/pseries/iommu.c index a0421ac..a48f126 100644 --- a/arch/powerpc/platforms/pseries/iommu.c +++ b/arch/powerpc/platforms/pseries/iommu.c @@ -695,9 +695,9 @@ static void remove_ddw(struct device_node *np) np->full_name, ret, ddr_avail[2], liobn); delprop: - ret = of_remove_property(np, win64); + ret = prom_remove_property(np, win64); if (ret) - pr_warning("%s: failed to remove direct window property: %d\n" + pr_warning("%s: failed to remove direct window property: %d\n", np->full_name, ret); } @@ -725,38 +725,38 @@ static u64 dupe_ddw_if_already_created(struct pci_dev *dev, struct device_node * return dma_addr; } -static u64 dupe_ddw_if_kexec(struct pci_dev *dev, struct device_node *pdn) +static int find_existing_ddw_windows(void) { - struct device_node *dn; - struct pci_dn *pcidn; int len; + struct device_node *pdn; struct direct_window *window; const struct dynamic_dma_window_prop *direct64; - u64 dma_addr = 0; - dn = pci_device_to_OF_node(dev); - pcidn = PCI_DN(dn); - direct64 = of_get_property(pdn, DIRECT64_PROPNAME, &len); - if (direct64) { - if (len < sizeof(struct dynamic_dma_window_prop)) { + if (!firmware_has_feature(FW_FEATURE_LPAR)) + return 0; + + for_each_node_with_property(pdn, DIRECT64_PROPNAME) { + direct64 = of_get_property(pdn, DIRECT64_PROPNAME, &len); + if (!direct64) + continue; + + window = kzalloc(sizeof(*window), GFP_KERNEL); + if (!window || len < sizeof(struct dynamic_dma_window_prop)) { + kfree(window); remove_ddw(pdn); - } else { - window = kzalloc(sizeof(*window), GFP_KERNEL); - if (!window) { - remove_ddw(pdn); - } else { - window->device = pdn; - window->prop = direct64; - spin_lock(&direct_window_list_lock); - list_add(&window->list, &direct_window_list); - spin_unlock(&direct_window_list_lock); - dma_addr = direct64->dma_base; - } + continue; } + + window->device = pdn; + window->prop = direct64; + spin_lock(&direct_window_list_lock); + list_add(&window->list, &direct_window_list); + spin_unlock(&direct_window_list_lock); } - return dma_addr; + return 0; } +machine_arch_initcall(pseries, find_existing_ddw_windows); static int query_ddw(struct pci_dev *dev, const u32 *ddr_avail, struct ddw_query_response *query) @@ -854,10 +854,6 @@ static u64 enable_ddw(struct pci_dev *dev, struct device_node *pdn) if (dma_addr != 0) goto out_unlock; - dma_addr = dupe_ddw_if_kexec(dev, pdn); - if (dma_addr != 0) - goto out_unlock; - /* * the ibm,ddw-applicable property holds the tokens for: * ibm,query-pe-dma-window -- cgit v0.10.2 From a0374396375d06398c419ebb6857fb5809cff81f Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Tue, 19 Apr 2011 12:43:46 +0100 Subject: debugfs: move to new strtobool No functional changes requires that we eat errors from strtobool. If people want to not do this, then it should be fixed at a later date. V2: Simplification suggested by Rusty Russell removes the need for additional variable ret. Signed-off-by: Jonathan Cameron Signed-off-by: Rusty Russell diff --git a/fs/debugfs/file.c b/fs/debugfs/file.c index 89d394d..568304d 100644 --- a/fs/debugfs/file.c +++ b/fs/debugfs/file.c @@ -429,25 +429,16 @@ static ssize_t write_file_bool(struct file *file, const char __user *user_buf, { char buf[32]; int buf_size; + bool bv; u32 *val = file->private_data; buf_size = min(count, (sizeof(buf)-1)); if (copy_from_user(buf, user_buf, buf_size)) return -EFAULT; - switch (buf[0]) { - case 'y': - case 'Y': - case '1': - *val = 1; - break; - case 'n': - case 'N': - case '0': - *val = 0; - break; - } - + if (strtobool(buf, &bv) == 0) + *val = bv; + return count; } -- cgit v0.10.2 From b73a635f348610304eee543d733a6277f67ba178 Mon Sep 17 00:00:00 2001 From: Milton Miller Date: Wed, 11 May 2011 12:25:00 +0000 Subject: powerpc/pseries/iommu: Cleanup ddw naming When using a property refering to the availibily of dynamic dma windows call it ddw_avail not ddr_avail. dupe_ddw_if_already_created does not dupilcate anything, it only finds and reuses the windows we already created, so rename it to find_existing_ddw. Also, it does not need the pci device node, so remove that argument. Signed-off-by: Milton Miller Signed-off-by: Nishanth Aravamudan Signed-off-by: Benjamin Herrenschmidt diff --git a/arch/powerpc/platforms/pseries/iommu.c b/arch/powerpc/platforms/pseries/iommu.c index a48f126..01faab9 100644 --- a/arch/powerpc/platforms/pseries/iommu.c +++ b/arch/powerpc/platforms/pseries/iommu.c @@ -659,16 +659,16 @@ static void remove_ddw(struct device_node *np) { struct dynamic_dma_window_prop *dwp; struct property *win64; - const u32 *ddr_avail; + const u32 *ddw_avail; u64 liobn; int len, ret; - ddr_avail = of_get_property(np, "ibm,ddw-applicable", &len); + ddw_avail = of_get_property(np, "ibm,ddw-applicable", &len); win64 = of_find_property(np, DIRECT64_PROPNAME, NULL); if (!win64) return; - if (!ddr_avail || len < 3 * sizeof(u32) || win64->length < sizeof(*dwp)) + if (!ddw_avail || len < 3 * sizeof(u32) || win64->length < sizeof(*dwp)) goto delprop; dwp = win64->value; @@ -684,15 +684,15 @@ static void remove_ddw(struct device_node *np) pr_debug("%s successfully cleared tces in window.\n", np->full_name); - ret = rtas_call(ddr_avail[2], 1, 1, NULL, liobn); + ret = rtas_call(ddw_avail[2], 1, 1, NULL, liobn); if (ret) pr_warning("%s: failed to remove direct window: rtas returned " "%d to ibm,remove-pe-dma-window(%x) %llx\n", - np->full_name, ret, ddr_avail[2], liobn); + np->full_name, ret, ddw_avail[2], liobn); else pr_debug("%s: successfully removed direct window: rtas returned " "%d to ibm,remove-pe-dma-window(%x) %llx\n", - np->full_name, ret, ddr_avail[2], liobn); + np->full_name, ret, ddw_avail[2], liobn); delprop: ret = prom_remove_property(np, win64); @@ -701,16 +701,12 @@ delprop: np->full_name, ret); } -static u64 dupe_ddw_if_already_created(struct pci_dev *dev, struct device_node *pdn) +static u64 find_existing_ddw(struct device_node *pdn) { - struct device_node *dn; - struct pci_dn *pcidn; struct direct_window *window; const struct dynamic_dma_window_prop *direct64; u64 dma_addr = 0; - dn = pci_device_to_OF_node(dev); - pcidn = PCI_DN(dn); spin_lock(&direct_window_list_lock); /* check if we already created a window and dupe that config if so */ list_for_each_entry(window, &direct_window_list, list) { @@ -758,7 +754,7 @@ static int find_existing_ddw_windows(void) } machine_arch_initcall(pseries, find_existing_ddw_windows); -static int query_ddw(struct pci_dev *dev, const u32 *ddr_avail, +static int query_ddw(struct pci_dev *dev, const u32 *ddw_avail, struct ddw_query_response *query) { struct device_node *dn; @@ -779,15 +775,15 @@ static int query_ddw(struct pci_dev *dev, const u32 *ddr_avail, if (pcidn->eeh_pe_config_addr) cfg_addr = pcidn->eeh_pe_config_addr; buid = pcidn->phb->buid; - ret = rtas_call(ddr_avail[0], 3, 5, (u32 *)query, + ret = rtas_call(ddw_avail[0], 3, 5, (u32 *)query, cfg_addr, BUID_HI(buid), BUID_LO(buid)); dev_info(&dev->dev, "ibm,query-pe-dma-windows(%x) %x %x %x" - " returned %d\n", ddr_avail[0], cfg_addr, BUID_HI(buid), + " returned %d\n", ddw_avail[0], cfg_addr, BUID_HI(buid), BUID_LO(buid), ret); return ret; } -static int create_ddw(struct pci_dev *dev, const u32 *ddr_avail, +static int create_ddw(struct pci_dev *dev, const u32 *ddw_avail, struct ddw_create_response *create, int page_shift, int window_shift) { @@ -812,12 +808,12 @@ static int create_ddw(struct pci_dev *dev, const u32 *ddr_avail, do { /* extra outputs are LIOBN and dma-addr (hi, lo) */ - ret = rtas_call(ddr_avail[1], 5, 4, (u32 *)create, cfg_addr, + ret = rtas_call(ddw_avail[1], 5, 4, (u32 *)create, cfg_addr, BUID_HI(buid), BUID_LO(buid), page_shift, window_shift); } while (rtas_busy_delay(ret)); dev_info(&dev->dev, "ibm,create-pe-dma-window(%x) %x %x %x %x %x returned %d " - "(liobn = 0x%x starting addr = %x %x)\n", ddr_avail[1], + "(liobn = 0x%x starting addr = %x %x)\n", ddw_avail[1], cfg_addr, BUID_HI(buid), BUID_LO(buid), page_shift, window_shift, ret, create->liobn, create->addr_hi, create->addr_lo); @@ -843,14 +839,14 @@ static u64 enable_ddw(struct pci_dev *dev, struct device_node *pdn) int page_shift; u64 dma_addr, max_addr; struct device_node *dn; - const u32 *uninitialized_var(ddr_avail); + const u32 *uninitialized_var(ddw_avail); struct direct_window *window; struct property *win64; struct dynamic_dma_window_prop *ddwprop; mutex_lock(&direct_window_init_mutex); - dma_addr = dupe_ddw_if_already_created(dev, pdn); + dma_addr = find_existing_ddw(pdn); if (dma_addr != 0) goto out_unlock; @@ -862,8 +858,8 @@ static u64 enable_ddw(struct pci_dev *dev, struct device_node *pdn) * for the given node in that order. * the property is actually in the parent, not the PE */ - ddr_avail = of_get_property(pdn, "ibm,ddw-applicable", &len); - if (!ddr_avail || len < 3 * sizeof(u32)) + ddw_avail = of_get_property(pdn, "ibm,ddw-applicable", &len); + if (!ddw_avail || len < 3 * sizeof(u32)) goto out_unlock; /* @@ -873,7 +869,7 @@ static u64 enable_ddw(struct pci_dev *dev, struct device_node *pdn) * of page sizes: supported and supported for migrate-dma. */ dn = pci_device_to_OF_node(dev); - ret = query_ddw(dev, ddr_avail, &query); + ret = query_ddw(dev, ddw_avail, &query); if (ret != 0) goto out_unlock; @@ -922,7 +918,7 @@ static u64 enable_ddw(struct pci_dev *dev, struct device_node *pdn) goto out_free_prop; } - ret = create_ddw(dev, ddr_avail, &create, page_shift, len); + ret = create_ddw(dev, ddw_avail, &create, page_shift, len); if (ret != 0) goto out_free_prop; -- cgit v0.10.2 From f721a465cddbe7f03e6cd2272008da558cf93818 Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Tue, 19 Apr 2011 12:43:47 +0100 Subject: params.c: Use new strtobool function to process boolean inputs Signed-off-by: Jonathan Cameron Signed-off-by: Rusty Russell diff --git a/kernel/params.c b/kernel/params.c index 28c5d5c..ed72e13 100644 --- a/kernel/params.c +++ b/kernel/params.c @@ -297,21 +297,15 @@ EXPORT_SYMBOL(param_ops_charp); int param_set_bool(const char *val, const struct kernel_param *kp) { bool v; + int ret; /* No equals means "set"... */ if (!val) val = "1"; /* One of =[yYnN01] */ - switch (val[0]) { - case 'y': case 'Y': case '1': - v = true; - break; - case 'n': case 'N': case '0': - v = false; - break; - default: - return -EINVAL; - } + ret = strtobool(val, &v); + if (ret) + return ret; if (kp->flags & KPARAM_ISBOOL) *(bool *)kp->arg = v; -- cgit v0.10.2 From 03bf469add176afd8a1a4c493d9f4e0e520db12b Mon Sep 17 00:00:00 2001 From: Benjamin Herrenschmidt Date: Wed, 11 May 2011 20:58:18 +0000 Subject: powerpc: Make early memory scan more resilient to out of order nodes We keep track of the size of the lowest block of memory and call setup_initial_memory_limit() only after we've parsed them all Signed-off-by: Benjamin Herrenschmidt Acked-by: Milton Miller diff --git a/arch/powerpc/kernel/prom.c b/arch/powerpc/kernel/prom.c index 5f5e6ae..5311a26 100644 --- a/arch/powerpc/kernel/prom.c +++ b/arch/powerpc/kernel/prom.c @@ -68,6 +68,7 @@ int __initdata iommu_force_on; unsigned long tce_alloc_start, tce_alloc_end; u64 ppc64_rma_size; #endif +static phys_addr_t first_memblock_size; static int __init early_parse_mem(char *p) { @@ -505,11 +506,14 @@ void __init early_init_dt_add_memory_arch(u64 base, u64 size) size = 0x80000000ul - base; } #endif - - /* First MEMBLOCK added, do some special initializations */ - if (memstart_addr == ~(phys_addr_t)0) - setup_initial_memory_limit(base, size); - memstart_addr = min((u64)memstart_addr, base); + /* Keep track of the beginning of memory -and- the size of + * the very first block in the device-tree as it represents + * the RMA on ppc64 server + */ + if (base < memstart_addr) { + memstart_addr = base; + first_memblock_size = size; + } /* Add the chunk to the MEMBLOCK list */ memblock_add(base, size); @@ -694,6 +698,7 @@ void __init early_init_devtree(void *params) of_scan_flat_dt(early_init_dt_scan_root, NULL); of_scan_flat_dt(early_init_dt_scan_memory_ppc, NULL); + setup_initial_memory_limit(memstart_addr, first_memblock_size); /* Save command line for /proc/cmdline and then parse parameters */ strlcpy(boot_command_line, cmd_line, COMMAND_LINE_SIZE); -- cgit v0.10.2 From 2c78027a62ea38585da1ff944afdc6146335cb7c Mon Sep 17 00:00:00 2001 From: Gabriel Paubert Date: Fri, 13 May 2011 01:03:13 +0000 Subject: powerpc: Fix for Pegasos keyboard and mouse [See http://lists.ozlabs.org/pipermail/linuxppc-dev/2010-October/086424.html and followups. Part of the commit message is directly copied from that.] Commit 540c6c392f01887dcc96bef0a41e63e6c1334f01 tries to find i8042 IRQs in the device-tree but doesn't fall back to the old hardcoded 1 and 12 in all failure cases. Specifically, the case where the device-tree contains nothing matching pnpPNP,303 or pnpPNP,f03 doesn't seem to be handled well. It sort of falls through to the old code, but leaves the IRQs set to 0. Signed-off-by: Gabriel Paubert Signed-off-by: Benjamin Herrenschmidt diff --git a/arch/powerpc/kernel/setup-common.c b/arch/powerpc/kernel/setup-common.c index ef33a08..79fca26 100644 --- a/arch/powerpc/kernel/setup-common.c +++ b/arch/powerpc/kernel/setup-common.c @@ -602,6 +602,10 @@ int check_legacy_ioport(unsigned long base_port) * name instead */ if (!np) np = of_find_node_by_name(NULL, "8042"); + if (np) { + of_i8042_kbd_irq = 1; + of_i8042_aux_irq = 12; + } break; case FDC_BASE: /* FDC1 */ np = of_find_node_by_type(NULL, "fdc"); -- cgit v0.10.2 From f38aa708776aefd9e3ba7ec1211c07efe9fa3227 Mon Sep 17 00:00:00 2001 From: Sebastian Siewior Date: Mon, 16 May 2011 08:58:13 +0000 Subject: powerpc: Remove last piece of GEMINI It seems that Adrian is getting old. He removed almost everything of GEMINI in commit c53653130 ("[POWERPC] Remove the broken Gemini support") except this piece. Signed-off-by: Sebastian Andrzej Siewior Signed-off-by: Benjamin Herrenschmidt diff --git a/arch/powerpc/kernel/head_32.S b/arch/powerpc/kernel/head_32.S index 98c4b29..ba250d5 100644 --- a/arch/powerpc/kernel/head_32.S +++ b/arch/powerpc/kernel/head_32.S @@ -805,19 +805,6 @@ _ENTRY(copy_and_flush) blr #ifdef CONFIG_SMP -#ifdef CONFIG_GEMINI - .globl __secondary_start_gemini -__secondary_start_gemini: - mfspr r4,SPRN_HID0 - ori r4,r4,HID0_ICFI - li r3,0 - ori r3,r3,HID0_ICE - andc r4,r4,r3 - mtspr SPRN_HID0,r4 - sync - b __secondary_start -#endif /* CONFIG_GEMINI */ - .globl __secondary_start_mpc86xx __secondary_start_mpc86xx: mfspr r3, SPRN_PIR -- cgit v0.10.2 From a7117c6bddcbfff2fa237a14a853b32cb94bf59a Mon Sep 17 00:00:00 2001 From: Jayachandran C Date: Wed, 11 May 2011 12:04:58 +0530 Subject: MIPS: Netlogic XLR/XLS processor IDs. Add Netlogic Microsystems company ID and processor IDs for XLR and XLS processors for CPU probe. Add CPU_XLR to cpu_type_enum. Signed-off-by: Jayachandran C Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/2367/ Signed-off-by: Ralf Baechle diff --git a/arch/mips/include/asm/cpu.h b/arch/mips/include/asm/cpu.h index 8687753..34c0d3c 100644 --- a/arch/mips/include/asm/cpu.h +++ b/arch/mips/include/asm/cpu.h @@ -33,6 +33,7 @@ #define PRID_COMP_TOSHIBA 0x070000 #define PRID_COMP_LSI 0x080000 #define PRID_COMP_LEXRA 0x0b0000 +#define PRID_COMP_NETLOGIC 0x0c0000 #define PRID_COMP_CAVIUM 0x0d0000 #define PRID_COMP_INGENIC 0xd00000 @@ -142,6 +143,31 @@ #define PRID_IMP_JZRISC 0x0200 /* + * These are the PRID's for when 23:16 == PRID_COMP_NETLOGIC + */ +#define PRID_IMP_NETLOGIC_XLR732 0x0000 +#define PRID_IMP_NETLOGIC_XLR716 0x0200 +#define PRID_IMP_NETLOGIC_XLR532 0x0900 +#define PRID_IMP_NETLOGIC_XLR308 0x0600 +#define PRID_IMP_NETLOGIC_XLR532C 0x0800 +#define PRID_IMP_NETLOGIC_XLR516C 0x0a00 +#define PRID_IMP_NETLOGIC_XLR508C 0x0b00 +#define PRID_IMP_NETLOGIC_XLR308C 0x0f00 +#define PRID_IMP_NETLOGIC_XLS608 0x8000 +#define PRID_IMP_NETLOGIC_XLS408 0x8800 +#define PRID_IMP_NETLOGIC_XLS404 0x8c00 +#define PRID_IMP_NETLOGIC_XLS208 0x8e00 +#define PRID_IMP_NETLOGIC_XLS204 0x8f00 +#define PRID_IMP_NETLOGIC_XLS108 0xce00 +#define PRID_IMP_NETLOGIC_XLS104 0xcf00 +#define PRID_IMP_NETLOGIC_XLS616B 0x4000 +#define PRID_IMP_NETLOGIC_XLS608B 0x4a00 +#define PRID_IMP_NETLOGIC_XLS416B 0x4400 +#define PRID_IMP_NETLOGIC_XLS412B 0x4c00 +#define PRID_IMP_NETLOGIC_XLS408B 0x4e00 +#define PRID_IMP_NETLOGIC_XLS404B 0x4f00 + +/* * Definitions for 7:0 on legacy processors */ @@ -234,6 +260,7 @@ enum cpu_type_enum { */ CPU_5KC, CPU_20KC, CPU_25KF, CPU_SB1, CPU_SB1A, CPU_LOONGSON2, CPU_CAVIUM_OCTEON, CPU_CAVIUM_OCTEON_PLUS, CPU_CAVIUM_OCTEON2, + CPU_XLR, CPU_LAST }; diff --git a/arch/mips/kernel/cpu-probe.c b/arch/mips/kernel/cpu-probe.c index f65d4c8..c7b7eb2 100644 --- a/arch/mips/kernel/cpu-probe.c +++ b/arch/mips/kernel/cpu-probe.c @@ -988,6 +988,59 @@ static inline void cpu_probe_ingenic(struct cpuinfo_mips *c, unsigned int cpu) } } +static inline void cpu_probe_netlogic(struct cpuinfo_mips *c, int cpu) +{ + decode_configs(c); + + c->options = (MIPS_CPU_TLB | + MIPS_CPU_4KEX | + MIPS_CPU_COUNTER | + MIPS_CPU_DIVEC | + MIPS_CPU_WATCH | + MIPS_CPU_EJTAG | + MIPS_CPU_LLSC); + + switch (c->processor_id & 0xff00) { + case PRID_IMP_NETLOGIC_XLR732: + case PRID_IMP_NETLOGIC_XLR716: + case PRID_IMP_NETLOGIC_XLR532: + case PRID_IMP_NETLOGIC_XLR308: + case PRID_IMP_NETLOGIC_XLR532C: + case PRID_IMP_NETLOGIC_XLR516C: + case PRID_IMP_NETLOGIC_XLR508C: + case PRID_IMP_NETLOGIC_XLR308C: + c->cputype = CPU_XLR; + __cpu_name[cpu] = "Netlogic XLR"; + break; + + case PRID_IMP_NETLOGIC_XLS608: + case PRID_IMP_NETLOGIC_XLS408: + case PRID_IMP_NETLOGIC_XLS404: + case PRID_IMP_NETLOGIC_XLS208: + case PRID_IMP_NETLOGIC_XLS204: + case PRID_IMP_NETLOGIC_XLS108: + case PRID_IMP_NETLOGIC_XLS104: + case PRID_IMP_NETLOGIC_XLS616B: + case PRID_IMP_NETLOGIC_XLS608B: + case PRID_IMP_NETLOGIC_XLS416B: + case PRID_IMP_NETLOGIC_XLS412B: + case PRID_IMP_NETLOGIC_XLS408B: + case PRID_IMP_NETLOGIC_XLS404B: + c->cputype = CPU_XLR; + __cpu_name[cpu] = "Netlogic XLS"; + break; + + default: + printk(KERN_INFO "Unknown Netlogic chip id [%02x]!\n", + c->processor_id); + c->cputype = CPU_XLR; + break; + } + + c->isa_level = MIPS_CPU_ISA_M64R1; + c->tlbsize = ((read_c0_config1() >> 25) & 0x3f) + 1; +} + #ifdef CONFIG_64BIT /* For use by uaccess.h */ u64 __ua_limit; @@ -1035,6 +1088,9 @@ __cpuinit void cpu_probe(void) case PRID_COMP_INGENIC: cpu_probe_ingenic(c, cpu); break; + case PRID_COMP_NETLOGIC: + cpu_probe_netlogic(c, cpu); + break; } BUG_ON(!__cpu_name[cpu]); -- cgit v0.10.2 From 3c595a515dbb61ae96e8f5607d895820aa06e870 Mon Sep 17 00:00:00 2001 From: Jayachandran C Date: Sat, 7 May 2011 01:36:05 +0530 Subject: MIPS: Netlogic: mach-netlogic include files Add war.h and irq.h with XLR/XLS definitions. Signed-off-by: Jayachandran C To: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/2331/ Signed-off-by: Ralf Baechle diff --git a/arch/mips/include/asm/mach-netlogic/cpu-feature-overrides.h b/arch/mips/include/asm/mach-netlogic/cpu-feature-overrides.h new file mode 100644 index 0000000..3b72827 --- /dev/null +++ b/arch/mips/include/asm/mach-netlogic/cpu-feature-overrides.h @@ -0,0 +1,47 @@ +/* + * 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) 2011 Netlogic Microsystems + * Copyright (C) 2003 Ralf Baechle + */ +#ifndef __ASM_MACH_NETLOGIC_CPU_FEATURE_OVERRIDES_H +#define __ASM_MACH_NETLOGIC_CPU_FEATURE_OVERRIDES_H + +#define cpu_has_4kex 1 +#define cpu_has_4k_cache 1 +#define cpu_has_watch 1 +#define cpu_has_mips16 0 +#define cpu_has_counter 1 +#define cpu_has_divec 1 +#define cpu_has_vce 0 +#define cpu_has_cache_cdex_p 0 +#define cpu_has_cache_cdex_s 0 +#define cpu_has_prefetch 1 +#define cpu_has_mcheck 1 +#define cpu_has_ejtag 1 + +#define cpu_has_llsc 1 +#define cpu_has_vtag_icache 0 +#define cpu_has_dc_aliases 0 +#define cpu_has_ic_fills_f_dc 0 +#define cpu_has_dsp 0 +#define cpu_has_mipsmt 0 +#define cpu_has_userlocal 0 +#define cpu_icache_snoops_remote_store 0 + +#define cpu_has_nofpuex 0 +#define cpu_has_64bits 1 + +#define cpu_has_mips32r1 1 +#define cpu_has_mips32r2 0 +#define cpu_has_mips64r1 1 +#define cpu_has_mips64r2 0 + +#define cpu_has_inclusive_pcaches 0 + +#define cpu_dcache_line_size() 32 +#define cpu_icache_line_size() 32 + +#endif /* __ASM_MACH_NETLOGIC_CPU_FEATURE_OVERRIDES_H */ diff --git a/arch/mips/include/asm/mach-netlogic/irq.h b/arch/mips/include/asm/mach-netlogic/irq.h new file mode 100644 index 0000000..b590245 --- /dev/null +++ b/arch/mips/include/asm/mach-netlogic/irq.h @@ -0,0 +1,14 @@ +/* + * 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) 2011 Netlogic Microsystems. + */ +#ifndef __ASM_NETLOGIC_IRQ_H +#define __ASM_NETLOGIC_IRQ_H + +#define NR_IRQS 64 +#define MIPS_CPU_IRQ_BASE 0 + +#endif /* __ASM_NETLOGIC_IRQ_H */ diff --git a/arch/mips/include/asm/mach-netlogic/war.h b/arch/mips/include/asm/mach-netlogic/war.h new file mode 100644 index 0000000..22da893 --- /dev/null +++ b/arch/mips/include/asm/mach-netlogic/war.h @@ -0,0 +1,26 @@ +/* + * 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) 2011 Netlogic Microsystems. + * Copyright (C) 2002, 2004, 2007 by Ralf Baechle + */ +#ifndef __ASM_MIPS_MACH_NLM_WAR_H +#define __ASM_MIPS_MACH_NLM_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_MIPS_MACH_NLM_WAR_H */ -- cgit v0.10.2 From efa0f81c11021c95b1e72c65868115b6fb4ecc6a Mon Sep 17 00:00:00 2001 From: Jayachandran C Date: Sat, 7 May 2011 01:36:21 +0530 Subject: MIPS: Netlogic: Cache, TLB support and feature overrides for XLR CPU_XLR case added to mm/tlbex.c CPU_XLR case added to mm/c-r4k.c for PINDEX attribute Feature overrides for XLR cpu. Signed-off-by: Jayachandran C To: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/2333/ Signed-off-by: Ralf Baechle diff --git a/arch/mips/include/asm/module.h b/arch/mips/include/asm/module.h index d94085a..bc01a02 100644 --- a/arch/mips/include/asm/module.h +++ b/arch/mips/include/asm/module.h @@ -118,6 +118,8 @@ search_module_dbetables(unsigned long addr) #define MODULE_PROC_FAMILY "LOONGSON2 " #elif defined CONFIG_CPU_CAVIUM_OCTEON #define MODULE_PROC_FAMILY "OCTEON " +#elif defined CONFIG_CPU_XLR +#define MODULE_PROC_FAMILY "XLR " #else #error MODULE_PROC_FAMILY undefined for your processor configuration #endif diff --git a/arch/mips/mm/c-r4k.c b/arch/mips/mm/c-r4k.c index 71bddf8..d9bc5d3 100644 --- a/arch/mips/mm/c-r4k.c +++ b/arch/mips/mm/c-r4k.c @@ -1006,6 +1006,7 @@ static void __cpuinit probe_pcache(void) case CPU_25KF: case CPU_SB1: case CPU_SB1A: + case CPU_XLR: c->dcache.flags |= MIPS_CACHE_PINDEX; break; diff --git a/arch/mips/mm/tlbex.c b/arch/mips/mm/tlbex.c index f5734c2..424ed4b 100644 --- a/arch/mips/mm/tlbex.c +++ b/arch/mips/mm/tlbex.c @@ -404,6 +404,7 @@ static void __cpuinit build_tlb_write_entry(u32 **p, struct uasm_label **l, case CPU_5KC: case CPU_TX49XX: case CPU_PR4450: + case CPU_XLR: uasm_i_nop(p); tlbw(p); break; -- cgit v0.10.2 From 5c642506740ecbf20fb7a9e482287e4e5c639e5c Mon Sep 17 00:00:00 2001 From: Jayachandran C Date: Sat, 7 May 2011 01:36:40 +0530 Subject: MIPS: Platform files for XLR/XLS processor support * include/asm/netlogic added with files common for all Netlogic processors (common with XLP which will be added later) * include/asm/netlogic/xlr for XLR/XLS chip specific files * netlogic/xlr for XLR/XLS platform files Signed-off-by: Jayachandran C To: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/2334/ Signed-off-by: Ralf Baechle diff --git a/arch/mips/include/asm/netlogic/interrupt.h b/arch/mips/include/asm/netlogic/interrupt.h new file mode 100644 index 0000000..a85aadb --- /dev/null +++ b/arch/mips/include/asm/netlogic/interrupt.h @@ -0,0 +1,45 @@ +/* + * Copyright 2003-2011 NetLogic Microsystems, Inc. (NetLogic). All rights + * reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the NetLogic + * license below: + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY NETLOGIC ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL NETLOGIC OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _ASM_NLM_INTERRUPT_H +#define _ASM_NLM_INTERRUPT_H + +/* Defines for the IRQ numbers */ + +#define IRQ_IPI_SMP_FUNCTION 3 +#define IRQ_IPI_SMP_RESCHEDULE 4 +#define IRQ_MSGRING 6 +#define IRQ_TIMER 7 + +#endif diff --git a/arch/mips/include/asm/netlogic/mips-extns.h b/arch/mips/include/asm/netlogic/mips-extns.h new file mode 100644 index 0000000..8c53d0b --- /dev/null +++ b/arch/mips/include/asm/netlogic/mips-extns.h @@ -0,0 +1,76 @@ +/* + * Copyright 2003-2011 NetLogic Microsystems, Inc. (NetLogic). All rights + * reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the NetLogic + * license below: + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY NETLOGIC ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL NETLOGIC OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _ASM_NLM_MIPS_EXTS_H +#define _ASM_NLM_MIPS_EXTS_H + +/* + * XLR and XLP interrupt request and interrupt mask registers + */ +#define read_c0_eirr() __read_64bit_c0_register($9, 6) +#define read_c0_eimr() __read_64bit_c0_register($9, 7) +#define write_c0_eirr(val) __write_64bit_c0_register($9, 6, val) + +/* + * Writing EIMR in 32 bit is a special case, the lower 8 bit of the + * EIMR is shadowed in the status register, so we cannot save and + * restore status register for split read. + */ +#define write_c0_eimr(val) \ +do { \ + if (sizeof(unsigned long) == 4) { \ + unsigned long __flags; \ + \ + local_irq_save(__flags); \ + __asm__ __volatile__( \ + ".set\tmips64\n\t" \ + "dsll\t%L0, %L0, 32\n\t" \ + "dsrl\t%L0, %L0, 32\n\t" \ + "dsll\t%M0, %M0, 32\n\t" \ + "or\t%L0, %L0, %M0\n\t" \ + "dmtc0\t%L0, $9, 7\n\t" \ + ".set\tmips0" \ + : : "r" (val)); \ + __flags = (__flags & 0xffff00ff) | (((val) & 0xff) << 8);\ + local_irq_restore(__flags); \ + } else \ + __write_64bit_c0_register($9, 7, (val)); \ +} while (0) + +static inline int hard_smp_processor_id(void) +{ + return __read_32bit_c0_register($15, 1) & 0x3ff; +} + +#endif /*_ASM_NLM_MIPS_EXTS_H */ diff --git a/arch/mips/include/asm/netlogic/psb-bootinfo.h b/arch/mips/include/asm/netlogic/psb-bootinfo.h new file mode 100644 index 0000000..6878307 --- /dev/null +++ b/arch/mips/include/asm/netlogic/psb-bootinfo.h @@ -0,0 +1,109 @@ +/* + * Copyright 2003-2011 NetLogic Microsystems, Inc. (NetLogic). All rights + * reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the NetLogic + * license below: + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY NETLOGIC ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL NETLOGIC OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _ASM_NETLOGIC_BOOTINFO_H +#define _ASM_NETLOGIC_BOOTINFO_H + +struct psb_info { + uint64_t boot_level; + uint64_t io_base; + uint64_t output_device; + uint64_t uart_print; + uint64_t led_output; + uint64_t init; + uint64_t exit; + uint64_t warm_reset; + uint64_t wakeup; + uint64_t online_cpu_map; + uint64_t master_reentry_sp; + uint64_t master_reentry_gp; + uint64_t master_reentry_fn; + uint64_t slave_reentry_fn; + uint64_t magic_dword; + uint64_t uart_putchar; + uint64_t size; + uint64_t uart_getchar; + uint64_t nmi_handler; + uint64_t psb_version; + uint64_t mac_addr; + uint64_t cpu_frequency; + uint64_t board_version; + uint64_t malloc; + uint64_t free; + uint64_t global_shmem_addr; + uint64_t global_shmem_size; + uint64_t psb_os_cpu_map; + uint64_t userapp_cpu_map; + uint64_t wakeup_os; + uint64_t psb_mem_map; + uint64_t board_major_version; + uint64_t board_minor_version; + uint64_t board_manf_revision; + uint64_t board_serial_number; + uint64_t psb_physaddr_map; + uint64_t xlr_loaderip_config; + uint64_t bldr_envp; + uint64_t avail_mem_map; +}; + +enum { + NETLOGIC_IO_SPACE = 0x10, + PCIX_IO_SPACE, + PCIX_CFG_SPACE, + PCIX_MEMORY_SPACE, + HT_IO_SPACE, + HT_CFG_SPACE, + HT_MEMORY_SPACE, + SRAM_SPACE, + FLASH_CONTROLLER_SPACE +}; + +#define NLM_MAX_ARGS 64 +#define NLM_MAX_ENVS 32 + +/* This is what netlboot passes and linux boot_mem_map is subtly different */ +#define NLM_BOOT_MEM_MAP_MAX 32 +struct nlm_boot_mem_map { + int nr_map; + struct nlm_boot_mem_map_entry { + uint64_t addr; /* start of memory segment */ + uint64_t size; /* size of memory segment */ + uint32_t type; /* type of memory segment */ + } map[NLM_BOOT_MEM_MAP_MAX]; +}; + +/* Pointer to saved boot loader info */ +extern struct psb_info nlm_prom_info; + +#endif diff --git a/arch/mips/include/asm/netlogic/xlr/gpio.h b/arch/mips/include/asm/netlogic/xlr/gpio.h new file mode 100644 index 0000000..51f6ad4 --- /dev/null +++ b/arch/mips/include/asm/netlogic/xlr/gpio.h @@ -0,0 +1,73 @@ +/* + * Copyright 2003-2011 NetLogic Microsystems, Inc. (NetLogic). All rights + * reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the NetLogic + * license below: + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY NETLOGIC ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL NETLOGIC OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _ASM_NLM_GPIO_H +#define _ASM_NLM_GPIO_H + +#define NETLOGIC_GPIO_INT_EN_REG 0 +#define NETLOGIC_GPIO_INPUT_INVERSION_REG 1 +#define NETLOGIC_GPIO_IO_DIR_REG 2 +#define NETLOGIC_GPIO_IO_DATA_WR_REG 3 +#define NETLOGIC_GPIO_IO_DATA_RD_REG 4 + +#define NETLOGIC_GPIO_SWRESET_REG 8 +#define NETLOGIC_GPIO_DRAM1_CNTRL_REG 9 +#define NETLOGIC_GPIO_DRAM1_RATIO_REG 10 +#define NETLOGIC_GPIO_DRAM1_RESET_REG 11 +#define NETLOGIC_GPIO_DRAM1_STATUS_REG 12 +#define NETLOGIC_GPIO_DRAM2_CNTRL_REG 13 +#define NETLOGIC_GPIO_DRAM2_RATIO_REG 14 +#define NETLOGIC_GPIO_DRAM2_RESET_REG 15 +#define NETLOGIC_GPIO_DRAM2_STATUS_REG 16 + +#define NETLOGIC_GPIO_PWRON_RESET_CFG_REG 21 +#define NETLOGIC_GPIO_BIST_ALL_GO_STATUS_REG 24 +#define NETLOGIC_GPIO_BIST_CPU_GO_STATUS_REG 25 +#define NETLOGIC_GPIO_BIST_DEV_GO_STATUS_REG 26 + +#define NETLOGIC_GPIO_FUSE_BANK_REG 35 +#define NETLOGIC_GPIO_CPU_RESET_REG 40 +#define NETLOGIC_GPIO_RNG_REG 43 + +#define NETLOGIC_PWRON_RESET_PCMCIA_BOOT 17 +#define NETLOGIC_GPIO_LED_BITMAP 0x1700000 +#define NETLOGIC_GPIO_LED_0_SHIFT 20 +#define NETLOGIC_GPIO_LED_1_SHIFT 24 + +#define NETLOGIC_GPIO_LED_OUTPUT_CODE_RESET 0x01 +#define NETLOGIC_GPIO_LED_OUTPUT_CODE_HARD_RESET 0x02 +#define NETLOGIC_GPIO_LED_OUTPUT_CODE_SOFT_RESET 0x03 +#define NETLOGIC_GPIO_LED_OUTPUT_CODE_MAIN 0x04 + +#endif diff --git a/arch/mips/include/asm/netlogic/xlr/iomap.h b/arch/mips/include/asm/netlogic/xlr/iomap.h new file mode 100644 index 0000000..2e3a4dd --- /dev/null +++ b/arch/mips/include/asm/netlogic/xlr/iomap.h @@ -0,0 +1,131 @@ +/* + * Copyright 2003-2011 NetLogic Microsystems, Inc. (NetLogic). All rights + * reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the NetLogic + * license below: + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY NETLOGIC ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL NETLOGIC OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _ASM_NLM_IOMAP_H +#define _ASM_NLM_IOMAP_H + +#define DEFAULT_NETLOGIC_IO_BASE CKSEG1ADDR(0x1ef00000) +#define NETLOGIC_IO_DDR2_CHN0_OFFSET 0x01000 +#define NETLOGIC_IO_DDR2_CHN1_OFFSET 0x02000 +#define NETLOGIC_IO_DDR2_CHN2_OFFSET 0x03000 +#define NETLOGIC_IO_DDR2_CHN3_OFFSET 0x04000 +#define NETLOGIC_IO_PIC_OFFSET 0x08000 +#define NETLOGIC_IO_UART_0_OFFSET 0x14000 +#define NETLOGIC_IO_UART_1_OFFSET 0x15100 + +#define NETLOGIC_IO_SIZE 0x1000 + +#define NETLOGIC_IO_BRIDGE_OFFSET 0x00000 + +#define NETLOGIC_IO_RLD2_CHN0_OFFSET 0x05000 +#define NETLOGIC_IO_RLD2_CHN1_OFFSET 0x06000 + +#define NETLOGIC_IO_SRAM_OFFSET 0x07000 + +#define NETLOGIC_IO_PCIX_OFFSET 0x09000 +#define NETLOGIC_IO_HT_OFFSET 0x0A000 + +#define NETLOGIC_IO_SECURITY_OFFSET 0x0B000 + +#define NETLOGIC_IO_GMAC_0_OFFSET 0x0C000 +#define NETLOGIC_IO_GMAC_1_OFFSET 0x0D000 +#define NETLOGIC_IO_GMAC_2_OFFSET 0x0E000 +#define NETLOGIC_IO_GMAC_3_OFFSET 0x0F000 + +/* XLS devices */ +#define NETLOGIC_IO_GMAC_4_OFFSET 0x20000 +#define NETLOGIC_IO_GMAC_5_OFFSET 0x21000 +#define NETLOGIC_IO_GMAC_6_OFFSET 0x22000 +#define NETLOGIC_IO_GMAC_7_OFFSET 0x23000 + +#define NETLOGIC_IO_PCIE_0_OFFSET 0x1E000 +#define NETLOGIC_IO_PCIE_1_OFFSET 0x1F000 +#define NETLOGIC_IO_SRIO_0_OFFSET 0x1E000 +#define NETLOGIC_IO_SRIO_1_OFFSET 0x1F000 + +#define NETLOGIC_IO_USB_0_OFFSET 0x24000 +#define NETLOGIC_IO_USB_1_OFFSET 0x25000 + +#define NETLOGIC_IO_COMP_OFFSET 0x1D000 +/* end XLS devices */ + +/* XLR devices */ +#define NETLOGIC_IO_SPI4_0_OFFSET 0x10000 +#define NETLOGIC_IO_XGMAC_0_OFFSET 0x11000 +#define NETLOGIC_IO_SPI4_1_OFFSET 0x12000 +#define NETLOGIC_IO_XGMAC_1_OFFSET 0x13000 +/* end XLR devices */ + +#define NETLOGIC_IO_I2C_0_OFFSET 0x16000 +#define NETLOGIC_IO_I2C_1_OFFSET 0x17000 + +#define NETLOGIC_IO_GPIO_OFFSET 0x18000 +#define NETLOGIC_IO_FLASH_OFFSET 0x19000 +#define NETLOGIC_IO_TB_OFFSET 0x1C000 + +#define NETLOGIC_CPLD_OFFSET KSEG1ADDR(0x1d840000) + +/* + * Base Address (Virtual) of the PCI Config address space + * For now, choose 256M phys in kseg1 = 0xA0000000 + (1<<28) + * Config space spans 256 (num of buses) * 256 (num functions) * 256 bytes + * ie 1<<24 = 16M + */ +#define DEFAULT_PCI_CONFIG_BASE 0x18000000 +#define DEFAULT_HT_TYPE0_CFG_BASE 0x16000000 +#define DEFAULT_HT_TYPE1_CFG_BASE 0x17000000 + +#ifndef __ASSEMBLY__ +#include +#include + +typedef volatile __u32 nlm_reg_t; +extern unsigned long netlogic_io_base; + +/* FIXME read once in write_reg */ +#ifdef CONFIG_CPU_LITTLE_ENDIAN +#define netlogic_read_reg(base, offset) ((base)[(offset)]) +#define netlogic_write_reg(base, offset, value) ((base)[(offset)] = (value)) +#else +#define netlogic_read_reg(base, offset) (be32_to_cpu((base)[(offset)])) +#define netlogic_write_reg(base, offset, value) \ + ((base)[(offset)] = cpu_to_be32((value))) +#endif + +#define netlogic_read_reg_le32(base, offset) (le32_to_cpu((base)[(offset)])) +#define netlogic_write_reg_le32(base, offset, value) \ + ((base)[(offset)] = cpu_to_le32((value))) +#define netlogic_io_mmio(offset) ((nlm_reg_t *)(netlogic_io_base+(offset))) +#endif /* __ASSEMBLY__ */ +#endif diff --git a/arch/mips/include/asm/netlogic/xlr/pic.h b/arch/mips/include/asm/netlogic/xlr/pic.h new file mode 100644 index 0000000..5cceb74 --- /dev/null +++ b/arch/mips/include/asm/netlogic/xlr/pic.h @@ -0,0 +1,231 @@ +/* + * Copyright 2003-2011 NetLogic Microsystems, Inc. (NetLogic). All rights + * reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the NetLogic + * license below: + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY NETLOGIC ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL NETLOGIC OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _ASM_NLM_XLR_PIC_H +#define _ASM_NLM_XLR_PIC_H + +#define PIC_CLKS_PER_SEC 66666666ULL +/* PIC hardware interrupt numbers */ +#define PIC_IRT_WD_INDEX 0 +#define PIC_IRT_TIMER_0_INDEX 1 +#define PIC_IRT_TIMER_1_INDEX 2 +#define PIC_IRT_TIMER_2_INDEX 3 +#define PIC_IRT_TIMER_3_INDEX 4 +#define PIC_IRT_TIMER_4_INDEX 5 +#define PIC_IRT_TIMER_5_INDEX 6 +#define PIC_IRT_TIMER_6_INDEX 7 +#define PIC_IRT_TIMER_7_INDEX 8 +#define PIC_IRT_CLOCK_INDEX PIC_IRT_TIMER_7_INDEX +#define PIC_IRT_UART_0_INDEX 9 +#define PIC_IRT_UART_1_INDEX 10 +#define PIC_IRT_I2C_0_INDEX 11 +#define PIC_IRT_I2C_1_INDEX 12 +#define PIC_IRT_PCMCIA_INDEX 13 +#define PIC_IRT_GPIO_INDEX 14 +#define PIC_IRT_HYPER_INDEX 15 +#define PIC_IRT_PCIX_INDEX 16 +/* XLS */ +#define PIC_IRT_CDE_INDEX 15 +#define PIC_IRT_BRIDGE_TB_XLS_INDEX 16 +/* XLS */ +#define PIC_IRT_GMAC0_INDEX 17 +#define PIC_IRT_GMAC1_INDEX 18 +#define PIC_IRT_GMAC2_INDEX 19 +#define PIC_IRT_GMAC3_INDEX 20 +#define PIC_IRT_XGS0_INDEX 21 +#define PIC_IRT_XGS1_INDEX 22 +#define PIC_IRT_HYPER_FATAL_INDEX 23 +#define PIC_IRT_PCIX_FATAL_INDEX 24 +#define PIC_IRT_BRIDGE_AERR_INDEX 25 +#define PIC_IRT_BRIDGE_BERR_INDEX 26 +#define PIC_IRT_BRIDGE_TB_XLR_INDEX 27 +#define PIC_IRT_BRIDGE_AERR_NMI_INDEX 28 +/* XLS */ +#define PIC_IRT_GMAC4_INDEX 21 +#define PIC_IRT_GMAC5_INDEX 22 +#define PIC_IRT_GMAC6_INDEX 23 +#define PIC_IRT_GMAC7_INDEX 24 +#define PIC_IRT_BRIDGE_ERR_INDEX 25 +#define PIC_IRT_PCIE_LINK0_INDEX 26 +#define PIC_IRT_PCIE_LINK1_INDEX 27 +#define PIC_IRT_PCIE_LINK2_INDEX 23 +#define PIC_IRT_PCIE_LINK3_INDEX 24 +#define PIC_IRT_PCIE_XLSB0_LINK2_INDEX 28 +#define PIC_IRT_PCIE_XLSB0_LINK3_INDEX 29 +#define PIC_IRT_SRIO_LINK0_INDEX 26 +#define PIC_IRT_SRIO_LINK1_INDEX 27 +#define PIC_IRT_SRIO_LINK2_INDEX 28 +#define PIC_IRT_SRIO_LINK3_INDEX 29 +#define PIC_IRT_PCIE_INT_INDEX 28 +#define PIC_IRT_PCIE_FATAL_INDEX 29 +#define PIC_IRT_GPIO_B_INDEX 30 +#define PIC_IRT_USB_INDEX 31 +/* XLS */ +#define PIC_NUM_IRTS 32 + + +#define PIC_CLOCK_TIMER 7 + +/* PIC Registers */ +#define PIC_CTRL 0x00 +#define PIC_IPI 0x04 +#define PIC_INT_ACK 0x06 + +#define WD_MAX_VAL_0 0x08 +#define WD_MAX_VAL_1 0x09 +#define WD_MASK_0 0x0a +#define WD_MASK_1 0x0b +#define WD_HEARBEAT_0 0x0c +#define WD_HEARBEAT_1 0x0d + +#define PIC_IRT_0_BASE 0x40 +#define PIC_IRT_1_BASE 0x80 +#define PIC_TIMER_MAXVAL_0_BASE 0x100 +#define PIC_TIMER_MAXVAL_1_BASE 0x110 +#define PIC_TIMER_COUNT_0_BASE 0x120 +#define PIC_TIMER_COUNT_1_BASE 0x130 + +#define PIC_IRT_0(picintr) (PIC_IRT_0_BASE + (picintr)) +#define PIC_IRT_1(picintr) (PIC_IRT_1_BASE + (picintr)) + +#define PIC_TIMER_MAXVAL_0(i) (PIC_TIMER_MAXVAL_0_BASE + (i)) +#define PIC_TIMER_MAXVAL_1(i) (PIC_TIMER_MAXVAL_1_BASE + (i)) +#define PIC_TIMER_COUNT_0(i) (PIC_TIMER_COUNT_0_BASE + (i)) +#define PIC_TIMER_COUNT_1(i) (PIC_TIMER_COUNT_0_BASE + (i)) + +/* + * Mapping between hardware interrupt numbers and IRQs on CPU + * we use a simple scheme to map PIC interrupts 0-31 to IRQs + * 8-39. This leaves the IRQ 0-7 for cpu interrupts like + * count/compare and FMN + */ +#define PIC_IRQ_BASE 8 +#define PIC_INTR_TO_IRQ(i) (PIC_IRQ_BASE + (i)) +#define PIC_IRQ_TO_INTR(i) ((i) - PIC_IRQ_BASE) + +#define PIC_IRT_FIRST_IRQ PIC_IRQ_BASE +#define PIC_WD_IRQ PIC_INTR_TO_IRQ(PIC_IRT_WD_INDEX) +#define PIC_TIMER_0_IRQ PIC_INTR_TO_IRQ(PIC_IRT_TIMER_0_INDEX) +#define PIC_TIMER_1_IRQ PIC_INTR_TO_IRQ(PIC_IRT_TIMER_1_INDEX) +#define PIC_TIMER_2_IRQ PIC_INTR_TO_IRQ(PIC_IRT_TIMER_2_INDEX) +#define PIC_TIMER_3_IRQ PIC_INTR_TO_IRQ(PIC_IRT_TIMER_3_INDEX) +#define PIC_TIMER_4_IRQ PIC_INTR_TO_IRQ(PIC_IRT_TIMER_4_INDEX) +#define PIC_TIMER_5_IRQ PIC_INTR_TO_IRQ(PIC_IRT_TIMER_5_INDEX) +#define PIC_TIMER_6_IRQ PIC_INTR_TO_IRQ(PIC_IRT_TIMER_6_INDEX) +#define PIC_TIMER_7_IRQ PIC_INTR_TO_IRQ(PIC_IRT_TIMER_7_INDEX) +#define PIC_CLOCK_IRQ (PIC_TIMER_7_IRQ) +#define PIC_UART_0_IRQ PIC_INTR_TO_IRQ(PIC_IRT_UART_0_INDEX) +#define PIC_UART_1_IRQ PIC_INTR_TO_IRQ(PIC_IRT_UART_1_INDEX) +#define PIC_I2C_0_IRQ PIC_INTR_TO_IRQ(PIC_IRT_I2C_0_INDEX) +#define PIC_I2C_1_IRQ PIC_INTR_TO_IRQ(PIC_IRT_I2C_1_INDEX) +#define PIC_PCMCIA_IRQ PIC_INTR_TO_IRQ(PIC_IRT_PCMCIA_INDEX) +#define PIC_GPIO_IRQ PIC_INTR_TO_IRQ(PIC_IRT_GPIO_INDEX) +#define PIC_HYPER_IRQ PIC_INTR_TO_IRQ(PIC_IRT_HYPER_INDEX) +#define PIC_PCIX_IRQ PIC_INTR_TO_IRQ(PIC_IRT_PCIX_INDEX) +/* XLS */ +#define PIC_CDE_IRQ PIC_INTR_TO_IRQ(PIC_IRT_CDE_INDEX) +#define PIC_BRIDGE_TB_XLS_IRQ PIC_INTR_TO_IRQ(PIC_IRT_BRIDGE_TB_XLS_INDEX) +/* end XLS */ +#define PIC_GMAC_0_IRQ PIC_INTR_TO_IRQ(PIC_IRT_GMAC0_INDEX) +#define PIC_GMAC_1_IRQ PIC_INTR_TO_IRQ(PIC_IRT_GMAC1_INDEX) +#define PIC_GMAC_2_IRQ PIC_INTR_TO_IRQ(PIC_IRT_GMAC2_INDEX) +#define PIC_GMAC_3_IRQ PIC_INTR_TO_IRQ(PIC_IRT_GMAC3_INDEX) +#define PIC_XGS_0_IRQ PIC_INTR_TO_IRQ(PIC_IRT_XGS0_INDEX) +#define PIC_XGS_1_IRQ PIC_INTR_TO_IRQ(PIC_IRT_XGS1_INDEX) +#define PIC_HYPER_FATAL_IRQ PIC_INTR_TO_IRQ(PIC_IRT_HYPER_FATAL_INDEX) +#define PIC_PCIX_FATAL_IRQ PIC_INTR_TO_IRQ(PIC_IRT_PCIX_FATAL_INDEX) +#define PIC_BRIDGE_AERR_IRQ PIC_INTR_TO_IRQ(PIC_IRT_BRIDGE_AERR_INDEX) +#define PIC_BRIDGE_BERR_IRQ PIC_INTR_TO_IRQ(PIC_IRT_BRIDGE_BERR_INDEX) +#define PIC_BRIDGE_TB_XLR_IRQ PIC_INTR_TO_IRQ(PIC_IRT_BRIDGE_TB_XLR_INDEX) +#define PIC_BRIDGE_AERR_NMI_IRQ PIC_INTR_TO_IRQ(PIC_IRT_BRIDGE_AERR_NMI_INDEX) +/* XLS defines */ +#define PIC_GMAC_4_IRQ PIC_INTR_TO_IRQ(PIC_IRT_GMAC4_INDEX) +#define PIC_GMAC_5_IRQ PIC_INTR_TO_IRQ(PIC_IRT_GMAC5_INDEX) +#define PIC_GMAC_6_IRQ PIC_INTR_TO_IRQ(PIC_IRT_GMAC6_INDEX) +#define PIC_GMAC_7_IRQ PIC_INTR_TO_IRQ(PIC_IRT_GMAC7_INDEX) +#define PIC_BRIDGE_ERR_IRQ PIC_INTR_TO_IRQ(PIC_IRT_BRIDGE_ERR_INDEX) +#define PIC_PCIE_LINK0_IRQ PIC_INTR_TO_IRQ(PIC_IRT_PCIE_LINK0_INDEX) +#define PIC_PCIE_LINK1_IRQ PIC_INTR_TO_IRQ(PIC_IRT_PCIE_LINK1_INDEX) +#define PIC_PCIE_LINK2_IRQ PIC_INTR_TO_IRQ(PIC_IRT_PCIE_LINK2_INDEX) +#define PIC_PCIE_LINK3_IRQ PIC_INTR_TO_IRQ(PIC_IRT_PCIE_LINK3_INDEX) +#define PIC_PCIE_XLSB0_LINK2_IRQ PIC_INTR_TO_IRQ(PIC_IRT_PCIE_XLSB0_LINK2_INDEX) +#define PIC_PCIE_XLSB0_LINK3_IRQ PIC_INTR_TO_IRQ(PIC_IRT_PCIE_XLSB0_LINK3_INDEX) +#define PIC_SRIO_LINK0_IRQ PIC_INTR_TO_IRQ(PIC_IRT_SRIO_LINK0_INDEX) +#define PIC_SRIO_LINK1_IRQ PIC_INTR_TO_IRQ(PIC_IRT_SRIO_LINK1_INDEX) +#define PIC_SRIO_LINK2_IRQ PIC_INTR_TO_IRQ(PIC_IRT_SRIO_LINK2_INDEX) +#define PIC_SRIO_LINK3_IRQ PIC_INTR_TO_IRQ(PIC_IRT_SRIO_LINK3_INDEX) +#define PIC_PCIE_INT_IRQ PIC_INTR_TO_IRQ(PIC_IRT_PCIE_INT__INDEX) +#define PIC_PCIE_FATAL_IRQ PIC_INTR_TO_IRQ(PIC_IRT_PCIE_FATAL_INDEX) +#define PIC_GPIO_B_IRQ PIC_INTR_TO_IRQ(PIC_IRT_GPIO_B_INDEX) +#define PIC_USB_IRQ PIC_INTR_TO_IRQ(PIC_IRT_USB_INDEX) +#define PIC_IRT_LAST_IRQ PIC_USB_IRQ +/* end XLS */ + +#ifndef __ASSEMBLY__ +static inline void pic_send_ipi(u32 ipi) +{ + nlm_reg_t *mmio = netlogic_io_mmio(NETLOGIC_IO_PIC_OFFSET); + + netlogic_write_reg(mmio, PIC_IPI, ipi); +} + +static inline u32 pic_read_control(void) +{ + nlm_reg_t *mmio = netlogic_io_mmio(NETLOGIC_IO_PIC_OFFSET); + + return netlogic_read_reg(mmio, PIC_CTRL); +} + +static inline void pic_write_control(u32 control) +{ + nlm_reg_t *mmio = netlogic_io_mmio(NETLOGIC_IO_PIC_OFFSET); + + netlogic_write_reg(mmio, PIC_CTRL, control); +} + +static inline void pic_update_control(u32 control) +{ + nlm_reg_t *mmio = netlogic_io_mmio(NETLOGIC_IO_PIC_OFFSET); + + netlogic_write_reg(mmio, PIC_CTRL, + (control | netlogic_read_reg(mmio, PIC_CTRL))); +} + +#define PIC_IRQ_IS_EDGE_TRIGGERED(irq) (((irq) >= PIC_TIMER_0_IRQ) && \ + ((irq) <= PIC_TIMER_7_IRQ)) +#define PIC_IRQ_IS_IRT(irq) (((irq) >= PIC_IRT_FIRST_IRQ) && \ + ((irq) <= PIC_IRT_LAST_IRQ)) +#endif + +#endif /* _ASM_NLM_XLR_PIC_H */ diff --git a/arch/mips/include/asm/netlogic/xlr/xlr.h b/arch/mips/include/asm/netlogic/xlr/xlr.h new file mode 100644 index 0000000..454c236 --- /dev/null +++ b/arch/mips/include/asm/netlogic/xlr/xlr.h @@ -0,0 +1,54 @@ +/* + * Copyright 2003-2011 NetLogic Microsystems, Inc. (NetLogic). All rights + * reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the NetLogic + * license below: + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY NETLOGIC ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL NETLOGIC OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _ASM_NLM_XLR_H +#define _ASM_NLM_XLR_H + +/* Platform UART functions */ +struct uart_port; +unsigned int nlm_xlr_uart_in(struct uart_port *, int); +void nlm_xlr_uart_out(struct uart_port *, int, int); + +/* SMP support functions */ +void nlm_smp_function_ipi_handler(unsigned int irq, struct irq_desc *desc); +void nlm_smp_resched_ipi_handler(unsigned int irq, struct irq_desc *desc); +int nlm_wakeup_secondary_cpus(u32 wakeup_mask); +void nlm_smp_irq_init(void); +void nlm_boot_smp_nmi(void); +void prom_pre_boot_secondary_cpus(void); + +extern struct plat_smp_ops nlm_smp_ops; +extern unsigned long nlm_common_ebase; + +#endif /* _ASM_NLM_XLR_H */ diff --git a/arch/mips/netlogic/xlr/irq.c b/arch/mips/netlogic/xlr/irq.c new file mode 100644 index 0000000..2033f56 --- /dev/null +++ b/arch/mips/netlogic/xlr/irq.c @@ -0,0 +1,216 @@ +/* + * Copyright 2003-2011 NetLogic Microsystems, Inc. (NetLogic). All rights + * reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the NetLogic + * license below: + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY NETLOGIC ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL NETLOGIC OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include + +#include +#include + +static u64 nlm_irq_mask; +static DEFINE_SPINLOCK(nlm_pic_lock); + +static void xlr_pic_enable(struct irq_data *d) +{ + nlm_reg_t *mmio = netlogic_io_mmio(NETLOGIC_IO_PIC_OFFSET); + unsigned long flags; + nlm_reg_t reg; + int irq = d->irq; + + WARN(!PIC_IRQ_IS_IRT(irq), "Bad irq %d", irq); + + spin_lock_irqsave(&nlm_pic_lock, flags); + reg = netlogic_read_reg(mmio, PIC_IRT_1_BASE + irq - PIC_IRQ_BASE); + netlogic_write_reg(mmio, PIC_IRT_1_BASE + irq - PIC_IRQ_BASE, + reg | (1 << 6) | (1 << 30) | (1 << 31)); + spin_unlock_irqrestore(&nlm_pic_lock, flags); +} + +static void xlr_pic_mask(struct irq_data *d) +{ + nlm_reg_t *mmio = netlogic_io_mmio(NETLOGIC_IO_PIC_OFFSET); + unsigned long flags; + nlm_reg_t reg; + int irq = d->irq; + + WARN(!PIC_IRQ_IS_IRT(irq), "Bad irq %d", irq); + + spin_lock_irqsave(&nlm_pic_lock, flags); + reg = netlogic_read_reg(mmio, PIC_IRT_1_BASE + irq - PIC_IRQ_BASE); + netlogic_write_reg(mmio, PIC_IRT_1_BASE + irq - PIC_IRQ_BASE, + reg | (1 << 6) | (1 << 30) | (0 << 31)); + spin_unlock_irqrestore(&nlm_pic_lock, flags); +} + +static void xlr_pic_ack(struct irq_data *d) +{ + unsigned long flags; + nlm_reg_t *mmio; + int irq = d->irq; + + WARN(!PIC_IRQ_IS_IRT(irq), "Bad irq %d", irq); + + mmio = netlogic_io_mmio(NETLOGIC_IO_PIC_OFFSET); + spin_lock_irqsave(&nlm_pic_lock, flags); + netlogic_write_reg(mmio, PIC_INT_ACK, (1 << (irq - PIC_IRQ_BASE))); + spin_unlock_irqrestore(&nlm_pic_lock, flags); +} + +/* + * This chip definition handles interrupts routed thru the XLR + * hardware PIC, currently IRQs 8-39 are mapped to hardware intr + * 0-31 wired the XLR PIC + */ +static struct irq_chip xlr_pic = { + .name = "XLR-PIC", + .irq_enable = xlr_pic_enable, + .irq_mask = xlr_pic_mask, + .irq_ack = xlr_pic_ack, +}; + +static void rsvd_irq_handler(struct irq_data *d) +{ + WARN(d->irq >= PIC_IRQ_BASE, "Bad irq %d", d->irq); +} + +/* + * Chip definition for CPU originated interrupts(timer, msg) and + * IPIs + */ +struct irq_chip nlm_cpu_intr = { + .name = "XLR-CPU-INTR", + .irq_enable = rsvd_irq_handler, + .irq_mask = rsvd_irq_handler, + .irq_ack = rsvd_irq_handler, +}; + +void __init init_xlr_irqs(void) +{ + nlm_reg_t *mmio = netlogic_io_mmio(NETLOGIC_IO_PIC_OFFSET); + uint32_t thread_mask = 1; + int level, i; + + pr_info("Interrupt thread mask [%x]\n", thread_mask); + for (i = 0; i < PIC_NUM_IRTS; i++) { + level = PIC_IRQ_IS_EDGE_TRIGGERED(i); + + /* Bind all PIC irqs to boot cpu */ + netlogic_write_reg(mmio, PIC_IRT_0_BASE + i, thread_mask); + + /* + * Use local scheduling and high polarity for all IRTs + * Invalidate all IRTs, by default + */ + netlogic_write_reg(mmio, PIC_IRT_1_BASE + i, + (level << 30) | (1 << 6) | (PIC_IRQ_BASE + i)); + } + + /* Make all IRQs as level triggered by default */ + for (i = 0; i < NR_IRQS; i++) { + if (PIC_IRQ_IS_IRT(i)) + irq_set_chip_and_handler(i, &xlr_pic, handle_level_irq); + else + irq_set_chip_and_handler(i, &nlm_cpu_intr, + handle_level_irq); + } +#ifdef CONFIG_SMP + irq_set_chip_and_handler(IRQ_IPI_SMP_FUNCTION, &nlm_cpu_intr, + nlm_smp_function_ipi_handler); + irq_set_chip_and_handler(IRQ_IPI_SMP_RESCHEDULE, &nlm_cpu_intr, + nlm_smp_resched_ipi_handler); + nlm_irq_mask |= + ((1ULL << IRQ_IPI_SMP_FUNCTION) | (1ULL << IRQ_IPI_SMP_RESCHEDULE)); +#endif + /* unmask all PIC related interrupts. If no handler is installed by the + * drivers, it'll just ack the interrupt and return + */ + for (i = PIC_IRT_FIRST_IRQ; i <= PIC_IRT_LAST_IRQ; i++) + nlm_irq_mask |= (1ULL << i); + + nlm_irq_mask |= (1ULL << IRQ_TIMER); +} + +void __init arch_init_irq(void) +{ + /* Initialize the irq descriptors */ + init_xlr_irqs(); + write_c0_eimr(nlm_irq_mask); +} + +void __cpuinit nlm_smp_irq_init(void) +{ + /* set interrupt mask for non-zero cpus */ + write_c0_eimr(nlm_irq_mask); +} + +asmlinkage void plat_irq_dispatch(void) +{ + uint64_t eirr; + int i; + + eirr = read_c0_eirr() & read_c0_eimr(); + if (!eirr) + return; + + /* no need of EIRR here, writing compare clears interrupt */ + if (eirr & (1 << IRQ_TIMER)) { + do_IRQ(IRQ_TIMER); + return; + } + + /* TODO use dcltz: optimize below code */ + for (i = 63; i != -1; i--) { + if (eirr & (1ULL << i)) + break; + } + if (i == -1) { + pr_err("no interrupt !!\n"); + return; + } + + /* Ack eirr */ + write_c0_eirr(1ULL << i); + + do_IRQ(i); +} diff --git a/arch/mips/netlogic/xlr/platform.c b/arch/mips/netlogic/xlr/platform.c new file mode 100644 index 0000000..609ec25 --- /dev/null +++ b/arch/mips/netlogic/xlr/platform.c @@ -0,0 +1,98 @@ +/* + * Copyright 2011, Netlogic Microsystems. + * Copyright 2004, Matt Porter + * + * This file is licensed under the terms of the GNU General Public + * License version 2. This program is licensed "as is" without any + * warranty of any kind, whether express or implied. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +unsigned int nlm_xlr_uart_in(struct uart_port *p, int offset) +{ + nlm_reg_t *mmio; + unsigned int value; + + /* XLR uart does not need any mapping of regs */ + mmio = (nlm_reg_t *)(p->membase + (offset << p->regshift)); + value = netlogic_read_reg(mmio, 0); + + /* See XLR/XLS errata */ + if (offset == UART_MSR) + value ^= 0xF0; + else if (offset == UART_MCR) + value ^= 0x3; + + return value; +} + +void nlm_xlr_uart_out(struct uart_port *p, int offset, int value) +{ + nlm_reg_t *mmio; + + /* XLR uart does not need any mapping of regs */ + mmio = (nlm_reg_t *)(p->membase + (offset << p->regshift)); + + /* See XLR/XLS errata */ + if (offset == UART_MSR) + value ^= 0xF0; + else if (offset == UART_MCR) + value ^= 0x3; + + netlogic_write_reg(mmio, 0, value); +} + +#define PORT(_irq) \ + { \ + .irq = _irq, \ + .regshift = 2, \ + .iotype = UPIO_MEM32, \ + .flags = (UPF_SKIP_TEST | \ + UPF_FIXED_TYPE | UPF_BOOT_AUTOCONF),\ + .uartclk = PIC_CLKS_PER_SEC, \ + .type = PORT_16550A, \ + .serial_in = nlm_xlr_uart_in, \ + .serial_out = nlm_xlr_uart_out, \ + } + +static struct plat_serial8250_port xlr_uart_data[] = { + PORT(PIC_UART_0_IRQ), + PORT(PIC_UART_1_IRQ), + {}, +}; + +static struct platform_device uart_device = { + .name = "serial8250", + .id = PLAT8250_DEV_PLATFORM, + .dev = { + .platform_data = xlr_uart_data, + }, +}; + +static int __init nlm_uart_init(void) +{ + nlm_reg_t *mmio; + + mmio = netlogic_io_mmio(NETLOGIC_IO_UART_0_OFFSET); + xlr_uart_data[0].membase = (void __iomem *)mmio; + xlr_uart_data[0].mapbase = CPHYSADDR((unsigned long)mmio); + + mmio = netlogic_io_mmio(NETLOGIC_IO_UART_1_OFFSET); + xlr_uart_data[1].membase = (void __iomem *)mmio; + xlr_uart_data[1].mapbase = CPHYSADDR((unsigned long)mmio); + + return platform_device_register(&uart_device); +} + +arch_initcall(nlm_uart_init); diff --git a/arch/mips/netlogic/xlr/setup.c b/arch/mips/netlogic/xlr/setup.c new file mode 100644 index 0000000..4828025 --- /dev/null +++ b/arch/mips/netlogic/xlr/setup.c @@ -0,0 +1,188 @@ +/* + * Copyright 2003-2011 NetLogic Microsystems, Inc. (NetLogic). All rights + * reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the NetLogic + * license below: + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY NETLOGIC ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL NETLOGIC OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include +#include + +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include + +unsigned long netlogic_io_base = (unsigned long)(DEFAULT_NETLOGIC_IO_BASE); +unsigned long nlm_common_ebase = 0x0; +struct psb_info nlm_prom_info; + +static void nlm_early_serial_setup(void) +{ + struct uart_port s; + nlm_reg_t *uart_base; + + uart_base = netlogic_io_mmio(NETLOGIC_IO_UART_0_OFFSET); + memset(&s, 0, sizeof(s)); + s.flags = ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST; + s.iotype = UPIO_MEM32; + s.regshift = 2; + s.irq = PIC_UART_0_IRQ; + s.uartclk = PIC_CLKS_PER_SEC; + s.serial_in = nlm_xlr_uart_in; + s.serial_out = nlm_xlr_uart_out; + s.mapbase = (unsigned long)uart_base; + s.membase = (unsigned char __iomem *)uart_base; + early_serial_setup(&s); +} + +static void nlm_linux_exit(void) +{ + nlm_reg_t *mmio; + + mmio = netlogic_io_mmio(NETLOGIC_IO_GPIO_OFFSET); + /* trigger a chip reset by writing 1 to GPIO_SWRESET_REG */ + netlogic_write_reg(mmio, NETLOGIC_GPIO_SWRESET_REG, 1); + for ( ; ; ) + cpu_wait(); +} + +void __init plat_mem_setup(void) +{ + panic_timeout = 5; + _machine_restart = (void (*)(char *))nlm_linux_exit; + _machine_halt = nlm_linux_exit; + pm_power_off = nlm_linux_exit; +} + +const char *get_system_type(void) +{ + return "Netlogic XLR/XLS Series"; +} + +void __init prom_free_prom_memory(void) +{ + /* Nothing yet */ +} + +static void build_arcs_cmdline(int *argv) +{ + int i, remain, len; + char *arg; + + remain = sizeof(arcs_cmdline) - 1; + arcs_cmdline[0] = '\0'; + for (i = 0; argv[i] != 0; i++) { + arg = (char *)(long)argv[i]; + len = strlen(arg); + if (len + 1 > remain) + break; + strcat(arcs_cmdline, arg); + strcat(arcs_cmdline, " "); + remain -= len + 1; + } + + /* Add the default options here */ + if ((strstr(arcs_cmdline, "console=")) == NULL) { + arg = "console=ttyS0,38400 "; + len = strlen(arg); + if (len > remain) + goto fail; + strcat(arcs_cmdline, arg); + remain -= len; + } +#ifdef CONFIG_BLK_DEV_INITRD + if ((strstr(arcs_cmdline, "rdinit=")) == NULL) { + arg = "rdinit=/sbin/init "; + len = strlen(arg); + if (len > remain) + goto fail; + strcat(arcs_cmdline, arg); + remain -= len; + } +#endif + return; +fail: + panic("Cannot add %s, command line too big!", arg); +} + +static void prom_add_memory(void) +{ + struct nlm_boot_mem_map *bootm; + u64 start, size; + u64 pref_backup = 512; /* avoid pref walking beyond end */ + int i; + + bootm = (void *)(long)nlm_prom_info.psb_mem_map; + for (i = 0; i < bootm->nr_map; i++) { + if (bootm->map[i].type != BOOT_MEM_RAM) + continue; + start = bootm->map[i].addr; + size = bootm->map[i].size; + + /* Work around for using bootloader mem */ + if (i == 0 && start == 0 && size == 0x0c000000) + size = 0x0ff00000; + + add_memory_region(start, size - pref_backup, BOOT_MEM_RAM); + } +} + +void __init prom_init(void) +{ + int *argv, *envp; /* passed as 32 bit ptrs */ + struct psb_info *prom_infop; + + /* truncate to 32 bit and sign extend all args */ + argv = (int *)(long)(int)fw_arg1; + envp = (int *)(long)(int)fw_arg2; + prom_infop = (struct psb_info *)(long)(int)fw_arg3; + + nlm_prom_info = *prom_infop; + + nlm_early_serial_setup(); + build_arcs_cmdline(argv); + nlm_common_ebase = read_c0_ebase() & (~((1 << 12) - 1)); + prom_add_memory(); + +#ifdef CONFIG_SMP + nlm_wakeup_secondary_cpus(nlm_prom_info.online_cpu_map); + register_smp_ops(&nlm_smp_ops); +#endif +} diff --git a/arch/mips/netlogic/xlr/smp.c b/arch/mips/netlogic/xlr/smp.c new file mode 100644 index 0000000..b495a7f --- /dev/null +++ b/arch/mips/netlogic/xlr/smp.c @@ -0,0 +1,225 @@ +/* + * Copyright 2003-2011 NetLogic Microsystems, Inc. (NetLogic). All rights + * reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the NetLogic + * license below: + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY NETLOGIC ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL NETLOGIC OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include +#include +#include +#include + +#include + +#include +#include + +#include +#include +#include + +void core_send_ipi(int logical_cpu, unsigned int action) +{ + int cpu = cpu_logical_map(logical_cpu); + u32 tid = cpu & 0x3; + u32 pid = (cpu >> 2) & 0x07; + u32 ipi = (tid << 16) | (pid << 20); + + if (action & SMP_CALL_FUNCTION) + ipi |= IRQ_IPI_SMP_FUNCTION; + else if (action & SMP_RESCHEDULE_YOURSELF) + ipi |= IRQ_IPI_SMP_RESCHEDULE; + else + return; + + pic_send_ipi(ipi); +} + +void nlm_send_ipi_single(int cpu, unsigned int action) +{ + core_send_ipi(cpu, action); +} + +void nlm_send_ipi_mask(const struct cpumask *mask, unsigned int action) +{ + int cpu; + + for_each_cpu(cpu, mask) { + core_send_ipi(cpu, action); + } +} + +/* IRQ_IPI_SMP_FUNCTION Handler */ +void nlm_smp_function_ipi_handler(unsigned int irq, struct irq_desc *desc) +{ + smp_call_function_interrupt(); +} + +/* IRQ_IPI_SMP_RESCHEDULE handler */ +void nlm_smp_resched_ipi_handler(unsigned int irq, struct irq_desc *desc) +{ + set_need_resched(); +} + +void nlm_common_ipi_handler(int irq, struct pt_regs *regs) +{ + if (irq == IRQ_IPI_SMP_FUNCTION) { + smp_call_function_interrupt(); + } else { + /* Announce that we are for reschduling */ + set_need_resched(); + } +} + +/* + * Called before going into mips code, early cpu init + */ +void nlm_early_init_secondary(void) +{ + write_c0_ebase((uint32_t)nlm_common_ebase); + /* TLB partition here later */ +} + +/* + * Code to run on secondary just after probing the CPU + */ +static void __cpuinit nlm_init_secondary(void) +{ + nlm_smp_irq_init(); +} + +void nlm_smp_finish(void) +{ +#ifdef notyet + nlm_common_msgring_cpu_init(); +#endif +} + +void nlm_cpus_done(void) +{ +} + +/* + * Boot all other cpus in the system, initialize them, and bring them into + * the boot function + */ +int nlm_cpu_unblock[NR_CPUS]; +int nlm_cpu_ready[NR_CPUS]; +unsigned long nlm_next_gp; +unsigned long nlm_next_sp; +cpumask_t phys_cpu_present_map; + +void nlm_boot_secondary(int logical_cpu, struct task_struct *idle) +{ + unsigned long gp = (unsigned long)task_thread_info(idle); + unsigned long sp = (unsigned long)__KSTK_TOS(idle); + int cpu = cpu_logical_map(logical_cpu); + + nlm_next_sp = sp; + nlm_next_gp = gp; + + /* barrier */ + __sync(); + nlm_cpu_unblock[cpu] = 1; +} + +void __init nlm_smp_setup(void) +{ + unsigned int boot_cpu; + int num_cpus, i; + + boot_cpu = hard_smp_processor_id(); + cpus_clear(phys_cpu_present_map); + + cpu_set(boot_cpu, phys_cpu_present_map); + __cpu_number_map[boot_cpu] = 0; + __cpu_logical_map[0] = boot_cpu; + cpu_set(0, cpu_possible_map); + + num_cpus = 1; + for (i = 0; i < NR_CPUS; i++) { + if (nlm_cpu_ready[i]) { + cpu_set(i, phys_cpu_present_map); + __cpu_number_map[i] = num_cpus; + __cpu_logical_map[num_cpus] = i; + cpu_set(num_cpus, cpu_possible_map); + ++num_cpus; + } + } + + pr_info("Phys CPU present map: %lx, possible map %lx\n", + (unsigned long)phys_cpu_present_map.bits[0], + (unsigned long)cpu_possible_map.bits[0]); + + pr_info("Detected %i Slave CPU(s)\n", num_cpus); +} + +void nlm_prepare_cpus(unsigned int max_cpus) +{ +} + +struct plat_smp_ops nlm_smp_ops = { + .send_ipi_single = nlm_send_ipi_single, + .send_ipi_mask = nlm_send_ipi_mask, + .init_secondary = nlm_init_secondary, + .smp_finish = nlm_smp_finish, + .cpus_done = nlm_cpus_done, + .boot_secondary = nlm_boot_secondary, + .smp_setup = nlm_smp_setup, + .prepare_cpus = nlm_prepare_cpus, +}; + +unsigned long secondary_entry_point; + +int nlm_wakeup_secondary_cpus(u32 wakeup_mask) +{ + unsigned int tid, pid, ipi, i, boot_cpu; + void *reset_vec; + + secondary_entry_point = (unsigned long)prom_pre_boot_secondary_cpus; + reset_vec = (void *)CKSEG1ADDR(0x1fc00000); + memcpy(reset_vec, nlm_boot_smp_nmi, 0x80); + boot_cpu = hard_smp_processor_id(); + + for (i = 0; i < NR_CPUS; i++) { + if (i == boot_cpu) + continue; + if (wakeup_mask & (1u << i)) { + tid = i & 0x3; + pid = (i >> 2) & 0x7; + ipi = (tid << 16) | (pid << 20) | (1 << 8); + pic_send_ipi(ipi); + } + } + + return 0; +} diff --git a/arch/mips/netlogic/xlr/smpboot.S b/arch/mips/netlogic/xlr/smpboot.S new file mode 100644 index 0000000..b8e0744 --- /dev/null +++ b/arch/mips/netlogic/xlr/smpboot.S @@ -0,0 +1,94 @@ +/* + * Copyright 2003-2011 NetLogic Microsystems, Inc. (NetLogic). All rights + * reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the NetLogic + * license below: + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY NETLOGIC ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL NETLOGIC OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include +#include +#include + + +/* Don't jump to linux function from Bootloader stack. Change it + * here. Kernel might allocate bootloader memory before all the CPUs are + * brought up (eg: Inode cache region) and we better don't overwrite this + * memory + */ +NESTED(prom_pre_boot_secondary_cpus, 16, sp) + .set mips64 + mfc0 t0, $15, 1 # read ebase + andi t0, 0x1f # t0 has the processor_id() + sll t0, 2 # offset in cpu array + + PTR_LA t1, nlm_cpu_ready # mark CPU ready + PTR_ADDU t1, t0 + li t2, 1 + sw t2, 0(t1) + + PTR_LA t1, nlm_cpu_unblock + PTR_ADDU t1, t0 +1: lw t2, 0(t1) # wait till unblocked + beqz t2, 1b + nop + + PTR_LA t1, nlm_next_sp + PTR_L sp, 0(t1) + PTR_LA t1, nlm_next_gp + PTR_L gp, 0(t1) + + PTR_LA t0, nlm_early_init_secondary + jalr t0 + nop + + PTR_LA t0, smp_bootstrap + jr t0 + nop +END(prom_pre_boot_secondary_cpus) + +NESTED(nlm_boot_smp_nmi, 0, sp) + .set push + .set noat + .set mips64 + .set noreorder + + /* Clear the NMI and BEV bits */ + MFC0 k0, CP0_STATUS + li k1, 0xffb7ffff + and k0, k0, k1 + MTC0 k0, CP0_STATUS + + PTR_LA k1, secondary_entry_point + PTR_L k0, 0(k1) + jr k0 + nop + .set pop +END(nlm_boot_smp_nmi) diff --git a/arch/mips/netlogic/xlr/time.c b/arch/mips/netlogic/xlr/time.c new file mode 100644 index 0000000..0d81b26 --- /dev/null +++ b/arch/mips/netlogic/xlr/time.c @@ -0,0 +1,51 @@ +/* + * Copyright 2003-2011 NetLogic Microsystems, Inc. (NetLogic). All rights + * reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the NetLogic + * license below: + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY NETLOGIC ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL NETLOGIC OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include + +#include +#include +#include + +unsigned int __cpuinit get_c0_compare_int(void) +{ + return IRQ_TIMER; +} + +void __init plat_time_init(void) +{ + mips_hpt_frequency = nlm_prom_info.cpu_frequency; + pr_info("MIPS counter frequency [%ld]\n", + (unsigned long)mips_hpt_frequency); +} diff --git a/arch/mips/netlogic/xlr/xlr_console.c b/arch/mips/netlogic/xlr/xlr_console.c new file mode 100644 index 0000000..759df06 --- /dev/null +++ b/arch/mips/netlogic/xlr/xlr_console.c @@ -0,0 +1,46 @@ +/* + * Copyright 2003-2011 NetLogic Microsystems, Inc. (NetLogic). All rights + * reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the NetLogic + * license below: + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY NETLOGIC ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL NETLOGIC OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include + +void prom_putchar(char c) +{ + nlm_reg_t *mmio; + + mmio = netlogic_io_mmio(NETLOGIC_IO_UART_0_OFFSET); + while (netlogic_read_reg(mmio, 0x5) == 0) + ; + netlogic_write_reg(mmio, 0x0, c); +} -- cgit v0.10.2 From 7f058e852b229ec77b37676b2b78baf2e78ffee8 Mon Sep 17 00:00:00 2001 From: Jayachandran C Date: Sat, 7 May 2011 01:36:57 +0530 Subject: MIPS: Kconfig and Makefile update for Netlogic XLR/XLS Add NLM_XLR_BOARD, CPU_XLR and other config options Makefile updates, mostly based on r4k Signed-off-by: Jayachandran C To: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/2334/ Signed-off-by: Ralf Baechle diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig index 351c80f..5016caa 100644 --- a/arch/mips/Kconfig +++ b/arch/mips/Kconfig @@ -736,6 +736,33 @@ config CAVIUM_OCTEON_REFERENCE_BOARD Hikari Say Y here for most Octeon reference boards. +config NLM_XLR_BOARD + bool "Netlogic XLR/XLS based systems" + depends on EXPERIMENTAL + select BOOT_ELF32 + select NLM_COMMON + select NLM_XLR + select SYS_HAS_CPU_XLR + select SYS_SUPPORTS_SMP + select HW_HAS_PCI + select SWAP_IO_SPACE + select SYS_SUPPORTS_32BIT_KERNEL + select SYS_SUPPORTS_64BIT_KERNEL + select 64BIT_PHYS_ADDR + select SYS_SUPPORTS_BIG_ENDIAN + select SYS_SUPPORTS_HIGHMEM + select DMA_COHERENT + select NR_CPUS_DEFAULT_32 + select CEVT_R4K + select CSRC_R4K + select IRQ_CPU + select ZONE_DMA if 64BIT + select SYNC_R4K + select SYS_HAS_EARLY_PRINTK + help + Support for systems based on Netlogic XLR and XLS processors. + Say Y here if you have a XLR or XLS based board. + endchoice source "arch/mips/alchemy/Kconfig" @@ -752,6 +779,7 @@ source "arch/mips/txx9/Kconfig" source "arch/mips/vr41xx/Kconfig" source "arch/mips/cavium-octeon/Kconfig" source "arch/mips/loongson/Kconfig" +source "arch/mips/netlogic/Kconfig" endmenu @@ -1420,6 +1448,17 @@ config CPU_BMIPS5000 help Broadcom BMIPS5000 processors. +config CPU_XLR + bool "Netlogic XLR SoC" + depends on SYS_HAS_CPU_XLR + select CPU_SUPPORTS_32BIT_KERNEL + select CPU_SUPPORTS_64BIT_KERNEL + select CPU_SUPPORTS_HIGHMEM + select WEAK_ORDERING + select WEAK_REORDERING_BEYOND_LLSC + select CPU_SUPPORTS_HUGEPAGES + help + Netlogic Microsystems XLR/XLS processors. endchoice if CPU_LOONGSON2F @@ -1550,6 +1589,9 @@ config SYS_HAS_CPU_BMIPS4380 config SYS_HAS_CPU_BMIPS5000 bool +config SYS_HAS_CPU_XLR + bool + # # CPU may reorder R->R, R->W, W->R, W->W # Reordering beyond LL and SC is handled in WEAK_REORDERING_BEYOND_LLSC diff --git a/arch/mips/Makefile b/arch/mips/Makefile index 53e3514..884819c 100644 --- a/arch/mips/Makefile +++ b/arch/mips/Makefile @@ -191,6 +191,18 @@ endif # include $(srctree)/arch/mips/Kbuild.platforms +# +# NETLOGIC SOC Common (common) +# +cflags-$(CONFIG_NLM_COMMON) += -I$(srctree)/arch/mips/include/asm/mach-netlogic +cflags-$(CONFIG_NLM_COMMON) += -I$(srctree)/arch/mips/include/asm/netlogic + +# +# NETLOGIC XLR/XLS SoC, Simulator and boards +# +core-$(CONFIG_NLM_XLR) += arch/mips/netlogic/xlr/ +load-$(CONFIG_NLM_XLR_BOARD) += 0xffffffff84000000 + cflags-y += -I$(srctree)/arch/mips/include/asm/mach-generic drivers-$(CONFIG_PCI) += arch/mips/pci/ diff --git a/arch/mips/kernel/Makefile b/arch/mips/kernel/Makefile index cedee2b..83bba33 100644 --- a/arch/mips/kernel/Makefile +++ b/arch/mips/kernel/Makefile @@ -52,6 +52,7 @@ obj-$(CONFIG_CPU_TX39XX) += r2300_fpu.o r2300_switch.o obj-$(CONFIG_CPU_TX49XX) += r4k_fpu.o r4k_switch.o obj-$(CONFIG_CPU_VR41XX) += r4k_fpu.o r4k_switch.o obj-$(CONFIG_CPU_CAVIUM_OCTEON) += octeon_switch.o +obj-$(CONFIG_CPU_XLR) += r4k_fpu.o r4k_switch.o obj-$(CONFIG_SMP) += smp.o obj-$(CONFIG_SMP_UP) += smp-up.o diff --git a/arch/mips/lib/Makefile b/arch/mips/lib/Makefile index 2adead5..b2cad4f 100644 --- a/arch/mips/lib/Makefile +++ b/arch/mips/lib/Makefile @@ -28,6 +28,7 @@ obj-$(CONFIG_CPU_TX39XX) += r3k_dump_tlb.o obj-$(CONFIG_CPU_TX49XX) += dump_tlb.o obj-$(CONFIG_CPU_VR41XX) += dump_tlb.o obj-$(CONFIG_CPU_CAVIUM_OCTEON) += dump_tlb.o +obj-$(CONFIG_CPU_XLR) += dump_tlb.o # libgcc-style stuff needed in the kernel obj-y += ashldi3.o ashrdi3.o cmpdi2.o lshrdi3.o ucmpdi2.o diff --git a/arch/mips/mm/Makefile b/arch/mips/mm/Makefile index d679c77..eb44636 100644 --- a/arch/mips/mm/Makefile +++ b/arch/mips/mm/Makefile @@ -29,6 +29,7 @@ obj-$(CONFIG_CPU_TX39XX) += c-tx39.o tlb-r3k.o obj-$(CONFIG_CPU_TX49XX) += c-r4k.o cex-gen.o tlb-r4k.o obj-$(CONFIG_CPU_VR41XX) += c-r4k.o cex-gen.o tlb-r4k.o obj-$(CONFIG_CPU_CAVIUM_OCTEON) += c-octeon.o cex-oct.o tlb-r4k.o +obj-$(CONFIG_CPU_XLR) += c-r4k.o tlb-r4k.o cex-gen.o obj-$(CONFIG_IP22_CPU_SCACHE) += sc-ip22.o obj-$(CONFIG_R5000_CPU_SCACHE) += sc-r5k.o diff --git a/arch/mips/netlogic/Kconfig b/arch/mips/netlogic/Kconfig new file mode 100644 index 0000000..a5ca743 --- /dev/null +++ b/arch/mips/netlogic/Kconfig @@ -0,0 +1,5 @@ +config NLM_COMMON + bool + +config NLM_XLR + bool diff --git a/arch/mips/netlogic/xlr/Makefile b/arch/mips/netlogic/xlr/Makefile new file mode 100644 index 0000000..9bd3f73 --- /dev/null +++ b/arch/mips/netlogic/xlr/Makefile @@ -0,0 +1,5 @@ +obj-y += setup.o platform.o irq.o setup.o time.o +obj-$(CONFIG_SMP) += smp.o smpboot.o +obj-$(CONFIG_EARLY_PRINTK) += xlr_console.o + +EXTRA_CFLAGS += -Werror -- cgit v0.10.2 From f9cab74fd9b0cf19f52a989694e7a1d8213af3a1 Mon Sep 17 00:00:00 2001 From: Jayachandran C Date: Sat, 7 May 2011 01:37:14 +0530 Subject: MIPS: Add default configuration for XLR/XLS processors Enable XLR CPU support, SMP, initramfs based root filesystem etc. [ralf@linux-mips.org: shrink the defconfig file through make savedefconfig.] Signed-off-by: Jayachandran C To: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/2338/ Signed-off-by: Ralf Baechle diff --git a/arch/mips/configs/nlm_xlr_defconfig b/arch/mips/configs/nlm_xlr_defconfig new file mode 100644 index 0000000..e4b399f --- /dev/null +++ b/arch/mips/configs/nlm_xlr_defconfig @@ -0,0 +1,574 @@ +CONFIG_NLM_XLR_BOARD=y +CONFIG_HIGHMEM=y +CONFIG_KSM=y +CONFIG_DEFAULT_MMAP_MIN_ADDR=65536 +CONFIG_SMP=y +CONFIG_NO_HZ=y +CONFIG_HIGH_RES_TIMERS=y +CONFIG_PREEMPT_VOLUNTARY=y +CONFIG_KEXEC=y +CONFIG_EXPERIMENTAL=y +CONFIG_CROSS_COMPILE="mips64-unknown-linux-gnu-" +# CONFIG_LOCALVERSION_AUTO is not set +CONFIG_SYSVIPC=y +CONFIG_POSIX_MQUEUE=y +CONFIG_BSD_PROCESS_ACCT=y +CONFIG_BSD_PROCESS_ACCT_V3=y +CONFIG_TASKSTATS=y +CONFIG_TASK_DELAY_ACCT=y +CONFIG_TASK_XACCT=y +CONFIG_TASK_IO_ACCOUNTING=y +CONFIG_AUDIT=y +CONFIG_NAMESPACES=y +CONFIG_SCHED_AUTOGROUP=y +CONFIG_BLK_DEV_INITRD=y +CONFIG_INITRAMFS_SOURCE="usr/dev_file_list usr/rootfs" +CONFIG_RD_BZIP2=y +CONFIG_RD_LZMA=y +CONFIG_INITRAMFS_COMPRESSION_GZIP=y +# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set +CONFIG_EXPERT=y +CONFIG_KALLSYMS_ALL=y +# CONFIG_ELF_CORE is not set +# CONFIG_PCSPKR_PLATFORM is not set +# CONFIG_PERF_EVENTS is not set +# CONFIG_COMPAT_BRK is not set +CONFIG_PROFILING=y +CONFIG_MODULES=y +CONFIG_MODULE_UNLOAD=y +CONFIG_MODVERSIONS=y +CONFIG_MODULE_SRCVERSION_ALL=y +CONFIG_BLK_DEV_INTEGRITY=y +CONFIG_BINFMT_MISC=m +CONFIG_PM_RUNTIME=y +CONFIG_PM_DEBUG=y +CONFIG_PACKET=y +CONFIG_UNIX=y +CONFIG_XFRM_USER=m +CONFIG_NET_KEY=m +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_NET_IPIP=m +CONFIG_IP_MROUTE=y +CONFIG_IP_PIMSM_V1=y +CONFIG_IP_PIMSM_V2=y +CONFIG_SYN_COOKIES=y +CONFIG_INET_AH=m +CONFIG_INET_ESP=m +CONFIG_INET_IPCOMP=m +CONFIG_INET_XFRM_MODE_TRANSPORT=m +CONFIG_INET_XFRM_MODE_TUNNEL=m +CONFIG_INET_XFRM_MODE_BEET=m +CONFIG_TCP_CONG_ADVANCED=y +CONFIG_TCP_CONG_HSTCP=m +CONFIG_TCP_CONG_HYBLA=m +CONFIG_TCP_CONG_SCALABLE=m +CONFIG_TCP_CONG_LP=m +CONFIG_TCP_CONG_VENO=m +CONFIG_TCP_CONG_YEAH=m +CONFIG_TCP_CONG_ILLINOIS=m +CONFIG_TCP_MD5SIG=y +CONFIG_IPV6=y +CONFIG_IPV6_PRIVACY=y +CONFIG_INET6_AH=m +CONFIG_INET6_ESP=m +CONFIG_INET6_IPCOMP=m +CONFIG_INET6_XFRM_MODE_TRANSPORT=m +CONFIG_INET6_XFRM_MODE_TUNNEL=m +CONFIG_INET6_XFRM_MODE_BEET=m +CONFIG_INET6_XFRM_MODE_ROUTEOPTIMIZATION=m +CONFIG_IPV6_SIT=m +CONFIG_IPV6_TUNNEL=m +CONFIG_IPV6_MULTIPLE_TABLES=y +CONFIG_NETLABEL=y +CONFIG_NETFILTER=y +CONFIG_NF_CONNTRACK=m +CONFIG_NF_CONNTRACK_SECMARK=y +CONFIG_NF_CONNTRACK_EVENTS=y +CONFIG_NF_CT_PROTO_UDPLITE=m +CONFIG_NF_CONNTRACK_AMANDA=m +CONFIG_NF_CONNTRACK_FTP=m +CONFIG_NF_CONNTRACK_H323=m +CONFIG_NF_CONNTRACK_IRC=m +CONFIG_NF_CONNTRACK_NETBIOS_NS=m +CONFIG_NF_CONNTRACK_PPTP=m +CONFIG_NF_CONNTRACK_SANE=m +CONFIG_NF_CONNTRACK_SIP=m +CONFIG_NF_CONNTRACK_TFTP=m +CONFIG_NF_CT_NETLINK=m +CONFIG_NETFILTER_TPROXY=m +CONFIG_NETFILTER_XT_TARGET_CLASSIFY=m +CONFIG_NETFILTER_XT_TARGET_CONNMARK=m +CONFIG_NETFILTER_XT_TARGET_CONNSECMARK=m +CONFIG_NETFILTER_XT_TARGET_DSCP=m +CONFIG_NETFILTER_XT_TARGET_MARK=m +CONFIG_NETFILTER_XT_TARGET_NFLOG=m +CONFIG_NETFILTER_XT_TARGET_NFQUEUE=m +CONFIG_NETFILTER_XT_TARGET_NOTRACK=m +CONFIG_NETFILTER_XT_TARGET_TPROXY=m +CONFIG_NETFILTER_XT_TARGET_TRACE=m +CONFIG_NETFILTER_XT_TARGET_SECMARK=m +CONFIG_NETFILTER_XT_TARGET_TCPMSS=m +CONFIG_NETFILTER_XT_MATCH_CLUSTER=m +CONFIG_NETFILTER_XT_MATCH_COMMENT=m +CONFIG_NETFILTER_XT_MATCH_CONNBYTES=m +CONFIG_NETFILTER_XT_MATCH_CONNLIMIT=m +CONFIG_NETFILTER_XT_MATCH_CONNMARK=m +CONFIG_NETFILTER_XT_MATCH_CONNTRACK=m +CONFIG_NETFILTER_XT_MATCH_DSCP=m +CONFIG_NETFILTER_XT_MATCH_ESP=m +CONFIG_NETFILTER_XT_MATCH_HASHLIMIT=m +CONFIG_NETFILTER_XT_MATCH_HELPER=m +CONFIG_NETFILTER_XT_MATCH_IPRANGE=m +CONFIG_NETFILTER_XT_MATCH_LENGTH=m +CONFIG_NETFILTER_XT_MATCH_LIMIT=m +CONFIG_NETFILTER_XT_MATCH_MAC=m +CONFIG_NETFILTER_XT_MATCH_MARK=m +CONFIG_NETFILTER_XT_MATCH_MULTIPORT=m +CONFIG_NETFILTER_XT_MATCH_OSF=m +CONFIG_NETFILTER_XT_MATCH_OWNER=m +CONFIG_NETFILTER_XT_MATCH_POLICY=m +CONFIG_NETFILTER_XT_MATCH_PHYSDEV=m +CONFIG_NETFILTER_XT_MATCH_PKTTYPE=m +CONFIG_NETFILTER_XT_MATCH_QUOTA=m +CONFIG_NETFILTER_XT_MATCH_RATEEST=m +CONFIG_NETFILTER_XT_MATCH_REALM=m +CONFIG_NETFILTER_XT_MATCH_RECENT=m +CONFIG_NETFILTER_XT_MATCH_SOCKET=m +CONFIG_NETFILTER_XT_MATCH_STATE=m +CONFIG_NETFILTER_XT_MATCH_STATISTIC=m +CONFIG_NETFILTER_XT_MATCH_STRING=m +CONFIG_NETFILTER_XT_MATCH_TCPMSS=m +CONFIG_NETFILTER_XT_MATCH_TIME=m +CONFIG_NETFILTER_XT_MATCH_U32=m +CONFIG_IP_VS=m +CONFIG_IP_VS_IPV6=y +CONFIG_IP_VS_PROTO_TCP=y +CONFIG_IP_VS_PROTO_UDP=y +CONFIG_IP_VS_PROTO_ESP=y +CONFIG_IP_VS_PROTO_AH=y +CONFIG_IP_VS_RR=m +CONFIG_IP_VS_WRR=m +CONFIG_IP_VS_LC=m +CONFIG_IP_VS_WLC=m +CONFIG_IP_VS_LBLC=m +CONFIG_IP_VS_LBLCR=m +CONFIG_IP_VS_DH=m +CONFIG_IP_VS_SH=m +CONFIG_IP_VS_SED=m +CONFIG_IP_VS_NQ=m +CONFIG_IP_VS_FTP=m +CONFIG_NF_CONNTRACK_IPV4=m +CONFIG_IP_NF_QUEUE=m +CONFIG_IP_NF_IPTABLES=m +CONFIG_IP_NF_MATCH_AH=m +CONFIG_IP_NF_MATCH_ECN=m +CONFIG_IP_NF_MATCH_TTL=m +CONFIG_IP_NF_FILTER=m +CONFIG_IP_NF_TARGET_REJECT=m +CONFIG_IP_NF_TARGET_LOG=m +CONFIG_IP_NF_TARGET_ULOG=m +CONFIG_NF_NAT=m +CONFIG_IP_NF_TARGET_MASQUERADE=m +CONFIG_IP_NF_TARGET_NETMAP=m +CONFIG_IP_NF_TARGET_REDIRECT=m +CONFIG_IP_NF_MANGLE=m +CONFIG_IP_NF_TARGET_CLUSTERIP=m +CONFIG_IP_NF_TARGET_ECN=m +CONFIG_IP_NF_TARGET_TTL=m +CONFIG_IP_NF_RAW=m +CONFIG_IP_NF_SECURITY=m +CONFIG_IP_NF_ARPTABLES=m +CONFIG_IP_NF_ARPFILTER=m +CONFIG_IP_NF_ARP_MANGLE=m +CONFIG_NF_CONNTRACK_IPV6=m +CONFIG_IP6_NF_QUEUE=m +CONFIG_IP6_NF_IPTABLES=m +CONFIG_IP6_NF_MATCH_AH=m +CONFIG_IP6_NF_MATCH_EUI64=m +CONFIG_IP6_NF_MATCH_FRAG=m +CONFIG_IP6_NF_MATCH_OPTS=m +CONFIG_IP6_NF_MATCH_HL=m +CONFIG_IP6_NF_MATCH_IPV6HEADER=m +CONFIG_IP6_NF_MATCH_MH=m +CONFIG_IP6_NF_MATCH_RT=m +CONFIG_IP6_NF_TARGET_HL=m +CONFIG_IP6_NF_TARGET_LOG=m +CONFIG_IP6_NF_FILTER=m +CONFIG_IP6_NF_TARGET_REJECT=m +CONFIG_IP6_NF_MANGLE=m +CONFIG_IP6_NF_RAW=m +CONFIG_IP6_NF_SECURITY=m +CONFIG_DECNET_NF_GRABULATOR=m +CONFIG_BRIDGE_NF_EBTABLES=m +CONFIG_BRIDGE_EBT_BROUTE=m +CONFIG_BRIDGE_EBT_T_FILTER=m +CONFIG_BRIDGE_EBT_T_NAT=m +CONFIG_BRIDGE_EBT_802_3=m +CONFIG_BRIDGE_EBT_AMONG=m +CONFIG_BRIDGE_EBT_ARP=m +CONFIG_BRIDGE_EBT_IP=m +CONFIG_BRIDGE_EBT_IP6=m +CONFIG_BRIDGE_EBT_LIMIT=m +CONFIG_BRIDGE_EBT_MARK=m +CONFIG_BRIDGE_EBT_PKTTYPE=m +CONFIG_BRIDGE_EBT_STP=m +CONFIG_BRIDGE_EBT_VLAN=m +CONFIG_BRIDGE_EBT_ARPREPLY=m +CONFIG_BRIDGE_EBT_DNAT=m +CONFIG_BRIDGE_EBT_MARK_T=m +CONFIG_BRIDGE_EBT_REDIRECT=m +CONFIG_BRIDGE_EBT_SNAT=m +CONFIG_BRIDGE_EBT_LOG=m +CONFIG_BRIDGE_EBT_ULOG=m +CONFIG_BRIDGE_EBT_NFLOG=m +CONFIG_IP_DCCP=m +CONFIG_RDS=m +CONFIG_RDS_TCP=m +CONFIG_TIPC=m +CONFIG_ATM=m +CONFIG_ATM_CLIP=m +CONFIG_ATM_LANE=m +CONFIG_ATM_MPOA=m +CONFIG_ATM_BR2684=m +CONFIG_BRIDGE=m +CONFIG_VLAN_8021Q=m +CONFIG_VLAN_8021Q_GVRP=y +CONFIG_DECNET=m +CONFIG_LLC2=m +CONFIG_IPX=m +CONFIG_ATALK=m +CONFIG_DEV_APPLETALK=m +CONFIG_IPDDP=m +CONFIG_IPDDP_ENCAP=y +CONFIG_IPDDP_DECAP=y +CONFIG_X25=m +CONFIG_LAPB=m +CONFIG_ECONET=m +CONFIG_ECONET_AUNUDP=y +CONFIG_ECONET_NATIVE=y +CONFIG_WAN_ROUTER=m +CONFIG_PHONET=m +CONFIG_IEEE802154=m +CONFIG_NET_SCHED=y +CONFIG_NET_SCH_CBQ=m +CONFIG_NET_SCH_HTB=m +CONFIG_NET_SCH_HFSC=m +CONFIG_NET_SCH_ATM=m +CONFIG_NET_SCH_PRIO=m +CONFIG_NET_SCH_MULTIQ=m +CONFIG_NET_SCH_RED=m +CONFIG_NET_SCH_SFQ=m +CONFIG_NET_SCH_TEQL=m +CONFIG_NET_SCH_TBF=m +CONFIG_NET_SCH_GRED=m +CONFIG_NET_SCH_DSMARK=m +CONFIG_NET_SCH_NETEM=m +CONFIG_NET_SCH_DRR=m +CONFIG_NET_SCH_INGRESS=m +CONFIG_NET_CLS_BASIC=m +CONFIG_NET_CLS_TCINDEX=m +CONFIG_NET_CLS_ROUTE4=m +CONFIG_NET_CLS_FW=m +CONFIG_NET_CLS_U32=m +CONFIG_CLS_U32_MARK=y +CONFIG_NET_CLS_RSVP=m +CONFIG_NET_CLS_RSVP6=m +CONFIG_NET_CLS_FLOW=m +CONFIG_NET_EMATCH=y +CONFIG_NET_EMATCH_CMP=m +CONFIG_NET_EMATCH_NBYTE=m +CONFIG_NET_EMATCH_U32=m +CONFIG_NET_EMATCH_META=m +CONFIG_NET_EMATCH_TEXT=m +CONFIG_NET_CLS_ACT=y +CONFIG_NET_ACT_POLICE=m +CONFIG_NET_ACT_GACT=m +CONFIG_GACT_PROB=y +CONFIG_NET_ACT_MIRRED=m +CONFIG_NET_ACT_IPT=m +CONFIG_NET_ACT_NAT=m +CONFIG_NET_ACT_PEDIT=m +CONFIG_NET_ACT_SIMP=m +CONFIG_NET_ACT_SKBEDIT=m +CONFIG_DCB=y +CONFIG_NET_PKTGEN=m +# CONFIG_WIRELESS is not set +CONFIG_DEVTMPFS=y +CONFIG_DEVTMPFS_MOUNT=y +# CONFIG_STANDALONE is not set +CONFIG_CONNECTOR=y +CONFIG_MTD=m +CONFIG_BLK_DEV_LOOP=y +CONFIG_BLK_DEV_CRYPTOLOOP=m +CONFIG_BLK_DEV_NBD=m +CONFIG_BLK_DEV_OSD=m +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_SIZE=65536 +CONFIG_CDROM_PKTCDVD=y +CONFIG_MISC_DEVICES=y +CONFIG_RAID_ATTRS=m +CONFIG_SCSI=y +CONFIG_SCSI_TGT=m +CONFIG_BLK_DEV_SD=y +CONFIG_CHR_DEV_ST=m +CONFIG_CHR_DEV_OSST=m +CONFIG_BLK_DEV_SR=y +CONFIG_CHR_DEV_SG=y +CONFIG_CHR_DEV_SCH=m +CONFIG_SCSI_MULTI_LUN=y +CONFIG_SCSI_CONSTANTS=y +CONFIG_SCSI_LOGGING=y +CONFIG_SCSI_SCAN_ASYNC=y +CONFIG_SCSI_SPI_ATTRS=m +CONFIG_SCSI_FC_TGT_ATTRS=y +CONFIG_SCSI_SAS_LIBSAS=m +CONFIG_SCSI_SRP_ATTRS=m +CONFIG_SCSI_SRP_TGT_ATTRS=y +CONFIG_ISCSI_TCP=m +CONFIG_LIBFCOE=m +CONFIG_SCSI_DEBUG=m +CONFIG_SCSI_DH=y +CONFIG_SCSI_DH_RDAC=m +CONFIG_SCSI_DH_HP_SW=m +CONFIG_SCSI_DH_EMC=m +CONFIG_SCSI_DH_ALUA=m +CONFIG_SCSI_OSD_INITIATOR=m +CONFIG_SCSI_OSD_ULD=m +# CONFIG_INPUT_MOUSEDEV is not set +CONFIG_INPUT_EVDEV=y +CONFIG_INPUT_EVBUG=m +# CONFIG_INPUT_KEYBOARD is not set +# CONFIG_INPUT_MOUSE is not set +# CONFIG_SERIO_I8042 is not set +CONFIG_SERIO_SERPORT=m +CONFIG_SERIO_LIBPS2=y +CONFIG_SERIO_RAW=m +CONFIG_VT_HW_CONSOLE_BINDING=y +CONFIG_DEVPTS_MULTIPLE_INSTANCES=y +CONFIG_LEGACY_PTY_COUNT=0 +CONFIG_SERIAL_NONSTANDARD=y +CONFIG_N_HDLC=m +# CONFIG_DEVKMEM is not set +CONFIG_STALDRV=y +CONFIG_SERIAL_8250=y +CONFIG_SERIAL_8250_CONSOLE=y +CONFIG_SERIAL_8250_NR_UARTS=48 +CONFIG_SERIAL_8250_EXTENDED=y +CONFIG_SERIAL_8250_MANY_PORTS=y +CONFIG_SERIAL_8250_SHARE_IRQ=y +CONFIG_SERIAL_8250_RSA=y +CONFIG_HW_RANDOM=y +CONFIG_HW_RANDOM_TIMERIOMEM=m +CONFIG_RAW_DRIVER=m +# CONFIG_HWMON is not set +# CONFIG_VGA_CONSOLE is not set +# CONFIG_HID_SUPPORT is not set +# CONFIG_USB_SUPPORT is not set +CONFIG_UIO=y +CONFIG_UIO_PDRV=m +CONFIG_UIO_PDRV_GENIRQ=m +CONFIG_EXT2_FS=y +CONFIG_EXT2_FS_XATTR=y +CONFIG_EXT2_FS_POSIX_ACL=y +CONFIG_EXT2_FS_SECURITY=y +CONFIG_EXT3_FS=y +CONFIG_EXT3_FS_POSIX_ACL=y +CONFIG_EXT3_FS_SECURITY=y +CONFIG_EXT4_FS=y +CONFIG_EXT4_FS_POSIX_ACL=y +CONFIG_EXT4_FS_SECURITY=y +CONFIG_GFS2_FS=m +CONFIG_GFS2_FS_LOCKING_DLM=y +CONFIG_OCFS2_FS=m +CONFIG_BTRFS_FS=m +CONFIG_BTRFS_FS_POSIX_ACL=y +CONFIG_NILFS2_FS=m +CONFIG_QUOTA_NETLINK_INTERFACE=y +# CONFIG_PRINT_QUOTA_WARNING is not set +CONFIG_QFMT_V1=m +CONFIG_QFMT_V2=m +CONFIG_AUTOFS4_FS=m +CONFIG_FUSE_FS=y +CONFIG_CUSE=m +CONFIG_FSCACHE=m +CONFIG_FSCACHE_STATS=y +CONFIG_FSCACHE_HISTOGRAM=y +CONFIG_CACHEFILES=m +CONFIG_ISO9660_FS=m +CONFIG_JOLIET=y +CONFIG_ZISOFS=y +CONFIG_UDF_FS=m +CONFIG_MSDOS_FS=m +CONFIG_VFAT_FS=m +CONFIG_NTFS_FS=m +CONFIG_PROC_KCORE=y +CONFIG_TMPFS=y +CONFIG_TMPFS_POSIX_ACL=y +CONFIG_CONFIGFS_FS=y +CONFIG_ADFS_FS=m +CONFIG_AFFS_FS=m +CONFIG_ECRYPT_FS=y +CONFIG_HFS_FS=m +CONFIG_HFSPLUS_FS=m +CONFIG_BEFS_FS=m +CONFIG_BFS_FS=m +CONFIG_EFS_FS=m +CONFIG_CRAMFS=m +CONFIG_SQUASHFS=m +CONFIG_VXFS_FS=m +CONFIG_MINIX_FS=m +CONFIG_OMFS_FS=m +CONFIG_HPFS_FS=m +CONFIG_QNX4FS_FS=m +CONFIG_ROMFS_FS=m +CONFIG_SYSV_FS=m +CONFIG_UFS_FS=m +CONFIG_EXOFS_FS=m +CONFIG_NFS_FS=m +CONFIG_NFS_V3=y +CONFIG_NFS_V3_ACL=y +CONFIG_NFS_V4=y +CONFIG_NFS_FSCACHE=y +CONFIG_NFSD=m +CONFIG_NFSD_V3_ACL=y +CONFIG_NFSD_V4=y +CONFIG_CIFS=m +CONFIG_CIFS_WEAK_PW_HASH=y +CONFIG_CIFS_UPCALL=y +CONFIG_CIFS_XATTR=y +CONFIG_CIFS_POSIX=y +CONFIG_CIFS_DFS_UPCALL=y +CONFIG_CIFS_EXPERIMENTAL=y +CONFIG_NCP_FS=m +CONFIG_NCPFS_PACKET_SIGNING=y +CONFIG_NCPFS_IOCTL_LOCKING=y +CONFIG_NCPFS_STRONG=y +CONFIG_NCPFS_NFS_NS=y +CONFIG_NCPFS_OS2_NS=y +CONFIG_NCPFS_NLS=y +CONFIG_NCPFS_EXTRAS=y +CONFIG_CODA_FS=m +CONFIG_AFS_FS=m +CONFIG_PARTITION_ADVANCED=y +CONFIG_ACORN_PARTITION=y +CONFIG_ACORN_PARTITION_ICS=y +CONFIG_ACORN_PARTITION_RISCIX=y +CONFIG_OSF_PARTITION=y +CONFIG_AMIGA_PARTITION=y +CONFIG_ATARI_PARTITION=y +CONFIG_MAC_PARTITION=y +CONFIG_BSD_DISKLABEL=y +CONFIG_MINIX_SUBPARTITION=y +CONFIG_SOLARIS_X86_PARTITION=y +CONFIG_UNIXWARE_DISKLABEL=y +CONFIG_LDM_PARTITION=y +CONFIG_SGI_PARTITION=y +CONFIG_ULTRIX_PARTITION=y +CONFIG_SUN_PARTITION=y +CONFIG_KARMA_PARTITION=y +CONFIG_EFI_PARTITION=y +CONFIG_SYSV68_PARTITION=y +CONFIG_NLS=y +CONFIG_NLS_DEFAULT="cp437" +CONFIG_NLS_CODEPAGE_437=m +CONFIG_NLS_CODEPAGE_737=m +CONFIG_NLS_CODEPAGE_775=m +CONFIG_NLS_CODEPAGE_850=m +CONFIG_NLS_CODEPAGE_852=m +CONFIG_NLS_CODEPAGE_855=m +CONFIG_NLS_CODEPAGE_857=m +CONFIG_NLS_CODEPAGE_860=m +CONFIG_NLS_CODEPAGE_861=m +CONFIG_NLS_CODEPAGE_862=m +CONFIG_NLS_CODEPAGE_863=m +CONFIG_NLS_CODEPAGE_864=m +CONFIG_NLS_CODEPAGE_865=m +CONFIG_NLS_CODEPAGE_866=m +CONFIG_NLS_CODEPAGE_869=m +CONFIG_NLS_CODEPAGE_936=m +CONFIG_NLS_CODEPAGE_950=m +CONFIG_NLS_CODEPAGE_932=m +CONFIG_NLS_CODEPAGE_949=m +CONFIG_NLS_CODEPAGE_874=m +CONFIG_NLS_ISO8859_8=m +CONFIG_NLS_CODEPAGE_1250=m +CONFIG_NLS_CODEPAGE_1251=m +CONFIG_NLS_ASCII=m +CONFIG_NLS_ISO8859_1=m +CONFIG_NLS_ISO8859_2=m +CONFIG_NLS_ISO8859_3=m +CONFIG_NLS_ISO8859_4=m +CONFIG_NLS_ISO8859_5=m +CONFIG_NLS_ISO8859_6=m +CONFIG_NLS_ISO8859_7=m +CONFIG_NLS_ISO8859_9=m +CONFIG_NLS_ISO8859_13=m +CONFIG_NLS_ISO8859_14=m +CONFIG_NLS_ISO8859_15=m +CONFIG_NLS_KOI8_R=m +CONFIG_NLS_KOI8_U=m +CONFIG_PRINTK_TIME=y +# CONFIG_ENABLE_WARN_DEPRECATED is not set +# CONFIG_ENABLE_MUST_CHECK is not set +CONFIG_UNUSED_SYMBOLS=y +CONFIG_DEBUG_KERNEL=y +CONFIG_DETECT_HUNG_TASK=y +CONFIG_SCHEDSTATS=y +CONFIG_TIMER_STATS=y +CONFIG_DEBUG_INFO=y +CONFIG_DEBUG_MEMORY_INIT=y +CONFIG_SYSCTL_SYSCALL_CHECK=y +CONFIG_SCHED_TRACER=y +CONFIG_BLK_DEV_IO_TRACE=y +CONFIG_KGDB=y +CONFIG_SECURITY=y +CONFIG_SECURITY_NETWORK=y +CONFIG_LSM_MMAP_MIN_ADDR=0 +CONFIG_SECURITY_SELINUX=y +CONFIG_SECURITY_SELINUX_BOOTPARAM=y +CONFIG_SECURITY_SELINUX_BOOTPARAM_VALUE=0 +CONFIG_SECURITY_SELINUX_DISABLE=y +CONFIG_SECURITY_SMACK=y +CONFIG_SECURITY_TOMOYO=y +CONFIG_CRYPTO_NULL=m +CONFIG_CRYPTO_CRYPTD=m +CONFIG_CRYPTO_TEST=m +CONFIG_CRYPTO_CCM=m +CONFIG_CRYPTO_GCM=m +CONFIG_CRYPTO_CTS=m +CONFIG_CRYPTO_LRW=m +CONFIG_CRYPTO_PCBC=m +CONFIG_CRYPTO_XTS=m +CONFIG_CRYPTO_HMAC=y +CONFIG_CRYPTO_XCBC=m +CONFIG_CRYPTO_VMAC=m +CONFIG_CRYPTO_MICHAEL_MIC=m +CONFIG_CRYPTO_RMD128=m +CONFIG_CRYPTO_RMD160=m +CONFIG_CRYPTO_RMD256=m +CONFIG_CRYPTO_RMD320=m +CONFIG_CRYPTO_SHA256=m +CONFIG_CRYPTO_SHA512=m +CONFIG_CRYPTO_TGR192=m +CONFIG_CRYPTO_WP512=m +CONFIG_CRYPTO_ANUBIS=m +CONFIG_CRYPTO_BLOWFISH=m +CONFIG_CRYPTO_CAMELLIA=m +CONFIG_CRYPTO_CAST5=m +CONFIG_CRYPTO_CAST6=m +CONFIG_CRYPTO_FCRYPT=m +CONFIG_CRYPTO_KHAZAD=m +CONFIG_CRYPTO_SALSA20=m +CONFIG_CRYPTO_SEED=m +CONFIG_CRYPTO_SERPENT=m +CONFIG_CRYPTO_TEA=m +CONFIG_CRYPTO_TWOFISH=m +CONFIG_CRYPTO_ZLIB=m +CONFIG_CRYPTO_LZO=m +CONFIG_CRC_CCITT=m +CONFIG_CRC7=m -- cgit v0.10.2 From 9b130f8004e51c65b20b0f0e17cdee073a719047 Mon Sep 17 00:00:00 2001 From: Jayachandran C Date: Sat, 7 May 2011 01:37:31 +0530 Subject: MIPS: XLR, XLS: Add PCI support. Adds pci/pci-xlr.c to support for XLR PCI/PCI-X interface and XLS PCIe interface. Update irq.c to ack PCI interrupts, use irq handler data to do the PCI/PCIe bus ack. Signed-off-by: Jayachandran C Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/2337/ Signed-off-by: Ralf Baechle diff --git a/arch/mips/include/asm/netlogic/xlr/xlr.h b/arch/mips/include/asm/netlogic/xlr/xlr.h index 454c236..3e63726 100644 --- a/arch/mips/include/asm/netlogic/xlr/xlr.h +++ b/arch/mips/include/asm/netlogic/xlr/xlr.h @@ -41,6 +41,7 @@ unsigned int nlm_xlr_uart_in(struct uart_port *, int); void nlm_xlr_uart_out(struct uart_port *, int, int); /* SMP support functions */ +struct irq_desc; void nlm_smp_function_ipi_handler(unsigned int irq, struct irq_desc *desc); void nlm_smp_resched_ipi_handler(unsigned int irq, struct irq_desc *desc); int nlm_wakeup_secondary_cpus(u32 wakeup_mask); @@ -51,4 +52,24 @@ void prom_pre_boot_secondary_cpus(void); extern struct plat_smp_ops nlm_smp_ops; extern unsigned long nlm_common_ebase; +/* XLS B silicon "Rook" */ +static inline unsigned int nlm_chip_is_xls_b(void) +{ + uint32_t prid = read_c0_prid(); + + return ((prid & 0xf000) == 0x4000); +} + +/* + * XLR chip types + */ + /* The XLS product line has chip versions 0x[48c]? */ +static inline unsigned int nlm_chip_is_xls(void) +{ + uint32_t prid = read_c0_prid(); + + return ((prid & 0xf000) == 0x8000 || (prid & 0xf000) == 0x4000 || + (prid & 0xf000) == 0xc000); +} + #endif /* _ASM_NLM_XLR_H */ diff --git a/arch/mips/netlogic/xlr/irq.c b/arch/mips/netlogic/xlr/irq.c index 2033f56..1446d58e 100644 --- a/arch/mips/netlogic/xlr/irq.c +++ b/arch/mips/netlogic/xlr/irq.c @@ -83,14 +83,71 @@ static void xlr_pic_mask(struct irq_data *d) spin_unlock_irqrestore(&nlm_pic_lock, flags); } +#ifdef CONFIG_PCI +/* Extra ACK needed for XLR on chip PCI controller */ +static void xlr_pci_ack(struct irq_data *d) +{ + nlm_reg_t *pci_mmio = netlogic_io_mmio(NETLOGIC_IO_PCIX_OFFSET); + + netlogic_read_reg(pci_mmio, (0x140 >> 2)); +} + +/* Extra ACK needed for XLS on chip PCIe controller */ +static void xls_pcie_ack(struct irq_data *d) +{ + nlm_reg_t *pcie_mmio_le = netlogic_io_mmio(NETLOGIC_IO_PCIE_1_OFFSET); + + switch (d->irq) { + case PIC_PCIE_LINK0_IRQ: + netlogic_write_reg(pcie_mmio_le, (0x90 >> 2), 0xffffffff); + break; + case PIC_PCIE_LINK1_IRQ: + netlogic_write_reg(pcie_mmio_le, (0x94 >> 2), 0xffffffff); + break; + case PIC_PCIE_LINK2_IRQ: + netlogic_write_reg(pcie_mmio_le, (0x190 >> 2), 0xffffffff); + break; + case PIC_PCIE_LINK3_IRQ: + netlogic_write_reg(pcie_mmio_le, (0x194 >> 2), 0xffffffff); + break; + } +} + +/* For XLS B silicon, the 3,4 PCI interrupts are different */ +static void xls_pcie_ack_b(struct irq_data *d) +{ + nlm_reg_t *pcie_mmio_le = netlogic_io_mmio(NETLOGIC_IO_PCIE_1_OFFSET); + + switch (d->irq) { + case PIC_PCIE_LINK0_IRQ: + netlogic_write_reg(pcie_mmio_le, (0x90 >> 2), 0xffffffff); + break; + case PIC_PCIE_LINK1_IRQ: + netlogic_write_reg(pcie_mmio_le, (0x94 >> 2), 0xffffffff); + break; + case PIC_PCIE_XLSB0_LINK2_IRQ: + netlogic_write_reg(pcie_mmio_le, (0x190 >> 2), 0xffffffff); + break; + case PIC_PCIE_XLSB0_LINK3_IRQ: + netlogic_write_reg(pcie_mmio_le, (0x194 >> 2), 0xffffffff); + break; + } +} +#endif + static void xlr_pic_ack(struct irq_data *d) { unsigned long flags; nlm_reg_t *mmio; int irq = d->irq; + void *hd = irq_data_get_irq_handler_data(d); WARN(!PIC_IRQ_IS_IRT(irq), "Bad irq %d", irq); + if (hd) { + void (*extra_ack)(void *) = hd; + extra_ack(d); + } mmio = netlogic_io_mmio(NETLOGIC_IO_PIC_OFFSET); spin_lock_irqsave(&nlm_pic_lock, flags); netlogic_write_reg(mmio, PIC_INT_ACK, (1 << (irq - PIC_IRQ_BASE))); @@ -162,6 +219,33 @@ void __init init_xlr_irqs(void) nlm_irq_mask |= ((1ULL << IRQ_IPI_SMP_FUNCTION) | (1ULL << IRQ_IPI_SMP_RESCHEDULE)); #endif + +#ifdef CONFIG_PCI + /* + * For PCI interrupts, we need to ack the PIC controller too, overload + * irq handler data to do this + */ + if (nlm_chip_is_xls()) { + if (nlm_chip_is_xls_b()) { + irq_set_handler_data(PIC_PCIE_LINK0_IRQ, + xls_pcie_ack_b); + irq_set_handler_data(PIC_PCIE_LINK1_IRQ, + xls_pcie_ack_b); + irq_set_handler_data(PIC_PCIE_XLSB0_LINK2_IRQ, + xls_pcie_ack_b); + irq_set_handler_data(PIC_PCIE_XLSB0_LINK3_IRQ, + xls_pcie_ack_b); + } else { + irq_set_handler_data(PIC_PCIE_LINK0_IRQ, xls_pcie_ack); + irq_set_handler_data(PIC_PCIE_LINK1_IRQ, xls_pcie_ack); + irq_set_handler_data(PIC_PCIE_LINK2_IRQ, xls_pcie_ack); + irq_set_handler_data(PIC_PCIE_LINK3_IRQ, xls_pcie_ack); + } + } else { + /* XLR PCI controller ACK */ + irq_set_handler_data(PIC_PCIE_XLSB0_LINK3_IRQ, xlr_pci_ack); + } +#endif /* unmask all PIC related interrupts. If no handler is installed by the * drivers, it'll just ack the interrupt and return */ @@ -199,7 +283,7 @@ asmlinkage void plat_irq_dispatch(void) return; } - /* TODO use dcltz: optimize below code */ + /* use dcltz: optimize below code */ for (i = 63; i != -1; i--) { if (eirr & (1ULL << i)) break; diff --git a/arch/mips/pci/Makefile b/arch/mips/pci/Makefile index c9209ca..f0d5329 100644 --- a/arch/mips/pci/Makefile +++ b/arch/mips/pci/Makefile @@ -55,6 +55,7 @@ obj-$(CONFIG_ZAO_CAPCELLA) += fixup-capcella.o obj-$(CONFIG_WR_PPMC) += fixup-wrppmc.o obj-$(CONFIG_MIKROTIK_RB532) += pci-rc32434.o ops-rc32434.o fixup-rc32434.o obj-$(CONFIG_CPU_CAVIUM_OCTEON) += pci-octeon.o pcie-octeon.o +obj-$(CONFIG_NLM_XLR) += pci-xlr.o ifdef CONFIG_PCI_MSI obj-$(CONFIG_CPU_CAVIUM_OCTEON) += msi-octeon.o diff --git a/arch/mips/pci/pci-xlr.c b/arch/mips/pci/pci-xlr.c new file mode 100644 index 0000000..38fece1 --- /dev/null +++ b/arch/mips/pci/pci-xlr.c @@ -0,0 +1,214 @@ +/* + * Copyright 2003-2011 NetLogic Microsystems, Inc. (NetLogic). All rights + * reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the NetLogic + * license below: + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY NETLOGIC ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL NETLOGIC OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include + +static void *pci_config_base; + +#define pci_cfg_addr(bus, devfn, off) (((bus) << 16) | ((devfn) << 8) | (off)) + +/* PCI ops */ +static inline u32 pci_cfg_read_32bit(struct pci_bus *bus, unsigned int devfn, + int where) +{ + u32 data; + u32 *cfgaddr; + + cfgaddr = (u32 *)(pci_config_base + + pci_cfg_addr(bus->number, devfn, where & ~3)); + data = *cfgaddr; + return cpu_to_le32(data); +} + +static inline void pci_cfg_write_32bit(struct pci_bus *bus, unsigned int devfn, + int where, u32 data) +{ + u32 *cfgaddr; + + cfgaddr = (u32 *)(pci_config_base + + pci_cfg_addr(bus->number, devfn, where & ~3)); + *cfgaddr = cpu_to_le32(data); +} + +static int nlm_pcibios_read(struct pci_bus *bus, unsigned int devfn, + int where, int size, u32 *val) +{ + u32 data; + + if ((size == 2) && (where & 1)) + return PCIBIOS_BAD_REGISTER_NUMBER; + else if ((size == 4) && (where & 3)) + return PCIBIOS_BAD_REGISTER_NUMBER; + + data = pci_cfg_read_32bit(bus, devfn, where); + + if (size == 1) + *val = (data >> ((where & 3) << 3)) & 0xff; + else if (size == 2) + *val = (data >> ((where & 3) << 3)) & 0xffff; + else + *val = data; + + return PCIBIOS_SUCCESSFUL; +} + + +static int nlm_pcibios_write(struct pci_bus *bus, unsigned int devfn, + int where, int size, u32 val) +{ + u32 data; + + if ((size == 2) && (where & 1)) + return PCIBIOS_BAD_REGISTER_NUMBER; + else if ((size == 4) && (where & 3)) + return PCIBIOS_BAD_REGISTER_NUMBER; + + data = pci_cfg_read_32bit(bus, devfn, where); + + if (size == 1) + data = (data & ~(0xff << ((where & 3) << 3))) | + (val << ((where & 3) << 3)); + else if (size == 2) + data = (data & ~(0xffff << ((where & 3) << 3))) | + (val << ((where & 3) << 3)); + else + data = val; + + pci_cfg_write_32bit(bus, devfn, where, data); + + return PCIBIOS_SUCCESSFUL; +} + +struct pci_ops nlm_pci_ops = { + .read = nlm_pcibios_read, + .write = nlm_pcibios_write +}; + +static struct resource nlm_pci_mem_resource = { + .name = "XLR PCI MEM", + .start = 0xd0000000UL, /* 256MB PCI mem @ 0xd000_0000 */ + .end = 0xdfffffffUL, + .flags = IORESOURCE_MEM, +}; + +static struct resource nlm_pci_io_resource = { + .name = "XLR IO MEM", + .start = 0x10000000UL, /* 16MB PCI IO @ 0x1000_0000 */ + .end = 0x100fffffUL, + .flags = IORESOURCE_IO, +}; + +struct pci_controller nlm_pci_controller = { + .index = 0, + .pci_ops = &nlm_pci_ops, + .mem_resource = &nlm_pci_mem_resource, + .mem_offset = 0x00000000UL, + .io_resource = &nlm_pci_io_resource, + .io_offset = 0x00000000UL, +}; + +int __init pcibios_map_irq(const struct pci_dev *dev, u8 slot, u8 pin) +{ + if (!nlm_chip_is_xls()) + return PIC_PCIX_IRQ; /* for XLR just one IRQ*/ + + /* + * For XLS 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; + + switch (dev->bus->self->devfn) { + case 0x0: + return PIC_PCIE_LINK0_IRQ; + case 0x8: + return PIC_PCIE_LINK1_IRQ; + case 0x10: + if (nlm_chip_is_xls_b()) + return PIC_PCIE_XLSB0_LINK2_IRQ; + else + return PIC_PCIE_LINK2_IRQ; + case 0x18: + if (nlm_chip_is_xls_b()) + return PIC_PCIE_XLSB0_LINK3_IRQ; + else + return PIC_PCIE_LINK3_IRQ; + } + WARN(1, "Unexpected devfn %d\n", dev->bus->self->devfn); + return 0; +} + +/* Do platform specific device initialization at pci_enable_device() time */ +int pcibios_plat_dev_init(struct pci_dev *dev) +{ + return 0; +} + +static int __init pcibios_init(void) +{ + /* PSB assigns PCI resources */ + pci_probe_only = 1; + pci_config_base = ioremap(DEFAULT_PCI_CONFIG_BASE, 16 << 20); + + /* Extend IO port for memory mapped io */ + ioport_resource.start = 0; + ioport_resource.end = ~0; + + set_io_port_base(CKSEG1); + nlm_pci_controller.io_map_base = CKSEG1; + + pr_info("Registering XLR/XLS PCIX/PCIE Controller.\n"); + register_pci_controller(&nlm_pci_controller); + + return 0; +} + +arch_initcall(pcibios_init); + +struct pci_fixup pcibios_fixups[] = { + {0} +}; -- cgit v0.10.2 From c0a5afb9bcf6b5aa5685e4fcf1282cad5fab3d91 Mon Sep 17 00:00:00 2001 From: Maxin John Date: Tue, 29 Mar 2011 00:15:55 +0300 Subject: MIPS: Enable kmemleak for MIPS Signed-off-by: Maxin B. John To: Catalin Marinas Cc: Daniel Baluta Cc: naveen yadav Cc: linux-mips@linux-mips.org Cc: linux-kernel@vger.kernel.org Cc: linux-mm@kvack.org Patchwork: https://patchwork.linux-mips.org/patch/2244/ Signed-off-by: Ralf Baechle diff --git a/arch/mips/kernel/vmlinux.lds.S b/arch/mips/kernel/vmlinux.lds.S index e4b0b0b..cd2ca54 100644 --- a/arch/mips/kernel/vmlinux.lds.S +++ b/arch/mips/kernel/vmlinux.lds.S @@ -68,6 +68,7 @@ SECTIONS RODATA /* writeable */ + _sdata = .; /* Start of data section */ .data : { /* Data */ . = . + DATAOFFSET; /* for CONFIG_MAPPED_KERNEL */ diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug index c768bcd..f0aa00b 100644 --- a/lib/Kconfig.debug +++ b/lib/Kconfig.debug @@ -398,7 +398,7 @@ config SLUB_STATS config DEBUG_KMEMLEAK bool "Kernel memory leak detector" depends on DEBUG_KERNEL && EXPERIMENTAL && !MEMORY_HOTPLUG && \ - (X86 || ARM || PPC || S390 || SPARC64 || SUPERH || MICROBLAZE || TILE) + (X86 || ARM || PPC || MIPS || S390 || SPARC64 || SUPERH || MICROBLAZE || TILE) select DEBUG_FS if SYSFS select STACKTRACE if STACKTRACE_SUPPORT -- cgit v0.10.2 From 171bb2f19ed6f3627f4f783f658f2f475b2fbd50 Mon Sep 17 00:00:00 2001 From: John Crispin Date: Wed, 30 Mar 2011 09:27:47 +0200 Subject: MIPS: Lantiq: Add initial support for Lantiq SoCs Add initial support for Mips based SoCs made by Lantiq. This series will add support for the XWAY family. The series allows booting a minimal system using a initramfs or NOR. Missing drivers and support for Amazon and GPON family will be provided in a later series. [Ralf: Remove some cargo cult programming and fixed formatting.] Signed-off-by: John Crispin Signed-off-by: Ralph Hempel Signed-off-by: David Daney Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/2252/ Patchwork: https://patchwork.linux-mips.org/patch/2371/ Signed-off-by: Ralf Baechle diff --git a/arch/mips/Kbuild.platforms b/arch/mips/Kbuild.platforms index 7ff9b54..aef6c91 100644 --- a/arch/mips/Kbuild.platforms +++ b/arch/mips/Kbuild.platforms @@ -11,6 +11,7 @@ platforms += dec platforms += emma platforms += jazz platforms += jz4740 +platforms += lantiq platforms += lasat platforms += loongson platforms += mipssim diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig index 5016caa..1787572 100644 --- a/arch/mips/Kconfig +++ b/arch/mips/Kconfig @@ -212,6 +212,23 @@ config MACH_JZ4740 select HAVE_PWM select HAVE_CLK +config LANTIQ + bool "Lantiq based platforms" + select DMA_NONCOHERENT + select IRQ_CPU + select CEVT_R4K + select CSRC_R4K + select SYS_HAS_CPU_MIPS32_R1 + select SYS_HAS_CPU_MIPS32_R2 + select SYS_SUPPORTS_BIG_ENDIAN + select SYS_SUPPORTS_32BIT_KERNEL + select SYS_SUPPORTS_MULTITHREADING + select SYS_HAS_EARLY_PRINTK + select ARCH_REQUIRE_GPIOLIB + select SWAP_IO_SPACE + select BOOT_RAW + select HAVE_CLK + config LASAT bool "LASAT Networks platforms" select CEVT_R4K diff --git a/arch/mips/include/asm/mach-lantiq/lantiq.h b/arch/mips/include/asm/mach-lantiq/lantiq.h new file mode 100644 index 0000000..ce2f029 --- /dev/null +++ b/arch/mips/include/asm/mach-lantiq/lantiq.h @@ -0,0 +1,63 @@ +/* + * 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) 2010 John Crispin + */ +#ifndef _LANTIQ_H__ +#define _LANTIQ_H__ + +#include + +/* generic reg access functions */ +#define ltq_r32(reg) __raw_readl(reg) +#define ltq_w32(val, reg) __raw_writel(val, reg) +#define ltq_w32_mask(clear, set, reg) \ + ltq_w32((ltq_r32(reg) & ~(clear)) | (set), reg) +#define ltq_r8(reg) __raw_readb(reg) +#define ltq_w8(val, reg) __raw_writeb(val, reg) + +/* register access macros for EBU and CGU */ +#define ltq_ebu_w32(x, y) ltq_w32((x), ltq_ebu_membase + (y)) +#define ltq_ebu_r32(x) ltq_r32(ltq_ebu_membase + (x)) +#define ltq_cgu_w32(x, y) ltq_w32((x), ltq_cgu_membase + (y)) +#define ltq_cgu_r32(x) ltq_r32(ltq_cgu_membase + (x)) + +extern __iomem void *ltq_ebu_membase; +extern __iomem void *ltq_cgu_membase; + +extern unsigned int ltq_get_cpu_ver(void); +extern unsigned int ltq_get_soc_type(void); + +/* clock speeds */ +#define CLOCK_60M 60000000 +#define CLOCK_83M 83333333 +#define CLOCK_111M 111111111 +#define CLOCK_133M 133333333 +#define CLOCK_167M 166666667 +#define CLOCK_200M 200000000 +#define CLOCK_266M 266666666 +#define CLOCK_333M 333333333 +#define CLOCK_400M 400000000 + +/* spinlock all ebu i/o */ +extern spinlock_t ebu_lock; + +/* some irq helpers */ +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); + +/* find out what caused the last cpu reset */ +extern int ltq_reset_cause(void); +#define LTQ_RST_CAUSE_WDTRST 0x20 + +#define IOPORT_RESOURCE_START 0x10000000 +#define IOPORT_RESOURCE_END 0xffffffff +#define IOMEM_RESOURCE_START 0x10000000 +#define IOMEM_RESOURCE_END 0xffffffff +#define LTQ_FLASH_START 0x10000000 +#define LTQ_FLASH_MAX 0x04000000 + +#endif diff --git a/arch/mips/include/asm/mach-lantiq/war.h b/arch/mips/include/asm/mach-lantiq/war.h new file mode 100644 index 0000000..01b08ef --- /dev/null +++ b/arch/mips/include/asm/mach-lantiq/war.h @@ -0,0 +1,24 @@ +/* + * 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. + * + */ +#ifndef __ASM_MIPS_MACH_LANTIQ_WAR_H +#define __ASM_MIPS_MACH_LANTIQ_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 diff --git a/arch/mips/lantiq/Makefile b/arch/mips/lantiq/Makefile new file mode 100644 index 0000000..6a30de6 --- /dev/null +++ b/arch/mips/lantiq/Makefile @@ -0,0 +1,9 @@ +# Copyright (C) 2010 John Crispin +# +# 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. + +obj-y := irq.o setup.o clk.o prom.o + +obj-$(CONFIG_EARLY_PRINTK) += early_printk.o diff --git a/arch/mips/lantiq/Platform b/arch/mips/lantiq/Platform new file mode 100644 index 0000000..eef587f --- /dev/null +++ b/arch/mips/lantiq/Platform @@ -0,0 +1,7 @@ +# +# Lantiq +# + +platform-$(CONFIG_LANTIQ) += lantiq/ +cflags-$(CONFIG_LANTIQ) += -I$(srctree)/arch/mips/include/asm/mach-lantiq +load-$(CONFIG_LANTIQ) = 0xffffffff80002000 diff --git a/arch/mips/lantiq/clk.c b/arch/mips/lantiq/clk.c new file mode 100644 index 0000000..9456089 --- /dev/null +++ b/arch/mips/lantiq/clk.c @@ -0,0 +1,140 @@ +/* + * 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) 2010 Thomas Langer + * Copyright (C) 2010 John Crispin + */ +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include + +#include "clk.h" + +struct clk { + const char *name; + unsigned long rate; + unsigned long (*get_rate) (void); +}; + +static struct clk *cpu_clk; +static int cpu_clk_cnt; + +/* lantiq socs have 3 static clocks */ +static struct clk cpu_clk_generic[] = { + { + .name = "cpu", + .get_rate = ltq_get_cpu_hz, + }, { + .name = "fpi", + .get_rate = ltq_get_fpi_hz, + }, { + .name = "io", + .get_rate = ltq_get_io_region_clock, + }, +}; + +static struct resource ltq_cgu_resource = { + .name = "cgu", + .start = LTQ_CGU_BASE_ADDR, + .end = LTQ_CGU_BASE_ADDR + LTQ_CGU_SIZE - 1, + .flags = IORESOURCE_MEM, +}; + +/* remapped clock register range */ +void __iomem *ltq_cgu_membase; + +void clk_init(void) +{ + cpu_clk = cpu_clk_generic; + cpu_clk_cnt = ARRAY_SIZE(cpu_clk_generic); +} + +static inline int clk_good(struct clk *clk) +{ + return clk && !IS_ERR(clk); +} + +unsigned long clk_get_rate(struct clk *clk) +{ + if (unlikely(!clk_good(clk))) + return 0; + + if (clk->rate != 0) + return clk->rate; + + if (clk->get_rate != NULL) + return clk->get_rate(); + + return 0; +} +EXPORT_SYMBOL(clk_get_rate); + +struct clk *clk_get(struct device *dev, const char *id) +{ + int i; + + for (i = 0; i < cpu_clk_cnt; i++) + if (!strcmp(id, cpu_clk[i].name)) + return &cpu_clk[i]; + BUG(); + return ERR_PTR(-ENOENT); +} +EXPORT_SYMBOL(clk_get); + +void clk_put(struct clk *clk) +{ + /* not used */ +} +EXPORT_SYMBOL(clk_put); + +static inline u32 ltq_get_counter_resolution(void) +{ + u32 res; + + __asm__ __volatile__( + ".set push\n" + ".set mips32r2\n" + "rdhwr %0, $3\n" + ".set pop\n" + : "=&r" (res) + : /* no input */ + : "memory"); + + return res; +} + +void __init plat_time_init(void) +{ + struct clk *clk; + + if (insert_resource(&iomem_resource, <q_cgu_resource) < 0) + panic("Failed to insert cgu memory\n"); + + if (request_mem_region(ltq_cgu_resource.start, + resource_size(<q_cgu_resource), "cgu") < 0) + panic("Failed to request cgu memory\n"); + + ltq_cgu_membase = ioremap_nocache(ltq_cgu_resource.start, + resource_size(<q_cgu_resource)); + if (!ltq_cgu_membase) { + pr_err("Failed to remap cgu memory\n"); + unreachable(); + } + clk = clk_get(0, "cpu"); + mips_hpt_frequency = clk_get_rate(clk) / ltq_get_counter_resolution(); + write_c0_compare(read_c0_count()); + clk_put(clk); +} diff --git a/arch/mips/lantiq/clk.h b/arch/mips/lantiq/clk.h new file mode 100644 index 0000000..3328925 --- /dev/null +++ b/arch/mips/lantiq/clk.h @@ -0,0 +1,18 @@ +/* + * 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) 2010 John Crispin + */ + +#ifndef _LTQ_CLK_H__ +#define _LTQ_CLK_H__ + +extern void clk_init(void); + +extern unsigned long ltq_get_cpu_hz(void); +extern unsigned long ltq_get_fpi_hz(void); +extern unsigned long ltq_get_io_region_clock(void); + +#endif diff --git a/arch/mips/lantiq/early_printk.c b/arch/mips/lantiq/early_printk.c new file mode 100644 index 0000000..972e05f --- /dev/null +++ b/arch/mips/lantiq/early_printk.c @@ -0,0 +1,33 @@ +/* + * 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) 2010 John Crispin + */ + +#include +#include + +#include +#include + +/* no ioremap possible at this early stage, lets use KSEG1 instead */ +#define LTQ_ASC_BASE KSEG1ADDR(LTQ_ASC1_BASE_ADDR) +#define ASC_BUF 1024 +#define LTQ_ASC_FSTAT ((u32 *)(LTQ_ASC_BASE + 0x0048)) +#define LTQ_ASC_TBUF ((u32 *)(LTQ_ASC_BASE + 0x0020)) +#define TXMASK 0x3F00 +#define TXOFFSET 8 + +void prom_putchar(char c) +{ + unsigned long flags; + + local_irq_save(flags); + do { } while ((ltq_r32(LTQ_ASC_FSTAT) & TXMASK) >> TXOFFSET); + if (c == '\n') + ltq_w32('\r', LTQ_ASC_TBUF); + ltq_w32(c, LTQ_ASC_TBUF); + local_irq_restore(flags); +} diff --git a/arch/mips/lantiq/irq.c b/arch/mips/lantiq/irq.c new file mode 100644 index 0000000..fc89795 --- /dev/null +++ b/arch/mips/lantiq/irq.c @@ -0,0 +1,326 @@ +/* + * 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) 2010 John Crispin + * Copyright (C) 2010 Thomas Langer + */ + +#include +#include + +#include +#include + +#include +#include + +/* register definitions */ +#define LTQ_ICU_IM0_ISR 0x0000 +#define LTQ_ICU_IM0_IER 0x0008 +#define LTQ_ICU_IM0_IOSR 0x0010 +#define LTQ_ICU_IM0_IRSR 0x0018 +#define LTQ_ICU_IM0_IMR 0x0020 +#define LTQ_ICU_IM1_ISR 0x0028 +#define LTQ_ICU_OFFSET (LTQ_ICU_IM1_ISR - LTQ_ICU_IM0_ISR) + +#define LTQ_EIU_EXIN_C 0x0000 +#define LTQ_EIU_EXIN_INIC 0x0004 +#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 MAX_EIU 6 + +/* irqs generated by device attached to the EBU need to be acked in + * a special manner + */ +#define LTQ_ICU_EBU_IRQ 22 + +#define ltq_icu_w32(x, y) ltq_w32((x), ltq_icu_membase + (y)) +#define ltq_icu_r32(x) ltq_r32(ltq_icu_membase + (x)) + +#define ltq_eiu_w32(x, y) ltq_w32((x), ltq_eiu_membase + (y)) +#define ltq_eiu_r32(x) ltq_r32(ltq_eiu_membase + (x)) + +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 struct resource ltq_icu_resource = { + .name = "icu", + .start = LTQ_ICU_BASE_ADDR, + .end = LTQ_ICU_BASE_ADDR + LTQ_ICU_SIZE - 1, + .flags = IORESOURCE_MEM, +}; + +static struct resource ltq_eiu_resource = { + .name = "eiu", + .start = LTQ_EIU_BASE_ADDR, + .end = LTQ_EIU_BASE_ADDR + LTQ_ICU_SIZE - 1, + .flags = IORESOURCE_MEM, +}; + +static void __iomem *ltq_icu_membase; +static void __iomem *ltq_eiu_membase; + +void ltq_disable_irq(struct irq_data *d) +{ + u32 ier = LTQ_ICU_IM0_IER; + int irq_nr = d->irq - INT_NUM_IRQ0; + + ier += LTQ_ICU_OFFSET * (irq_nr / INT_NUM_IM_OFFSET); + irq_nr %= INT_NUM_IM_OFFSET; + ltq_icu_w32(ltq_icu_r32(ier) & ~(1 << irq_nr), ier); +} + +void ltq_mask_and_ack_irq(struct irq_data *d) +{ + u32 ier = LTQ_ICU_IM0_IER; + u32 isr = LTQ_ICU_IM0_ISR; + int irq_nr = d->irq - INT_NUM_IRQ0; + + ier += LTQ_ICU_OFFSET * (irq_nr / INT_NUM_IM_OFFSET); + isr += LTQ_ICU_OFFSET * (irq_nr / INT_NUM_IM_OFFSET); + irq_nr %= INT_NUM_IM_OFFSET; + ltq_icu_w32(ltq_icu_r32(ier) & ~(1 << irq_nr), ier); + ltq_icu_w32((1 << irq_nr), isr); +} + +static void ltq_ack_irq(struct irq_data *d) +{ + u32 isr = LTQ_ICU_IM0_ISR; + int irq_nr = d->irq - INT_NUM_IRQ0; + + isr += LTQ_ICU_OFFSET * (irq_nr / INT_NUM_IM_OFFSET); + irq_nr %= INT_NUM_IM_OFFSET; + ltq_icu_w32((1 << irq_nr), isr); +} + +void ltq_enable_irq(struct irq_data *d) +{ + u32 ier = LTQ_ICU_IM0_IER; + int irq_nr = d->irq - INT_NUM_IRQ0; + + ier += LTQ_ICU_OFFSET * (irq_nr / INT_NUM_IM_OFFSET); + irq_nr %= INT_NUM_IM_OFFSET; + ltq_icu_w32(ltq_icu_r32(ier) | (1 << irq_nr), ier); +} + +static unsigned int ltq_startup_eiu_irq(struct irq_data *d) +{ + int i; + int irq_nr = d->irq - INT_NUM_IRQ0; + + ltq_enable_irq(d); + for (i = 0; i < MAX_EIU; i++) { + if (irq_nr == 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); + /* clear all pending */ + ltq_eiu_w32(ltq_eiu_r32(LTQ_EIU_EXIN_INIC) & ~(1 << i), + LTQ_EIU_EXIN_INIC); + /* enable */ + ltq_eiu_w32(ltq_eiu_r32(LTQ_EIU_EXIN_INEN) | (1 << i), + LTQ_EIU_EXIN_INEN); + break; + } + } + + return 0; +} + +static void ltq_shutdown_eiu_irq(struct irq_data *d) +{ + int i; + int irq_nr = d->irq - INT_NUM_IRQ0; + + ltq_disable_irq(d); + for (i = 0; i < MAX_EIU; i++) { + if (irq_nr == ltq_eiu_irq[i]) { + /* disable */ + ltq_eiu_w32(ltq_eiu_r32(LTQ_EIU_EXIN_INEN) & ~(1 << i), + LTQ_EIU_EXIN_INEN); + break; + } + } +} + +static struct irq_chip ltq_irq_type = { + "icu", + .irq_enable = ltq_enable_irq, + .irq_disable = ltq_disable_irq, + .irq_unmask = ltq_enable_irq, + .irq_ack = ltq_ack_irq, + .irq_mask = ltq_disable_irq, + .irq_mask_ack = ltq_mask_and_ack_irq, +}; + +static struct irq_chip ltq_eiu_type = { + "eiu", + .irq_startup = ltq_startup_eiu_irq, + .irq_shutdown = ltq_shutdown_eiu_irq, + .irq_enable = ltq_enable_irq, + .irq_disable = ltq_disable_irq, + .irq_unmask = ltq_enable_irq, + .irq_ack = ltq_ack_irq, + .irq_mask = ltq_disable_irq, + .irq_mask_ack = ltq_mask_and_ack_irq, +}; + +static void ltq_hw_irqdispatch(int module) +{ + u32 irq; + + irq = ltq_icu_r32(LTQ_ICU_IM0_IOSR + (module * LTQ_ICU_OFFSET)); + if (irq == 0) + return; + + /* silicon bug causes only the msb set to 1 to be valid. all + * other bits might be bogus + */ + irq = __fls(irq); + do_IRQ((int)irq + INT_NUM_IM0_IRL0 + (INT_NUM_IM_OFFSET * module)); + + /* if this is a EBU irq, we need to ack it or get a deadlock */ + if ((irq == LTQ_ICU_EBU_IRQ) && (module == 0)) + ltq_ebu_w32(ltq_ebu_r32(LTQ_EBU_PCC_ISTAT) | 0x10, + LTQ_EBU_PCC_ISTAT); +} + +#define DEFINE_HWx_IRQDISPATCH(x) \ + static void ltq_hw ## x ## _irqdispatch(void) \ + { \ + ltq_hw_irqdispatch(x); \ + } +DEFINE_HWx_IRQDISPATCH(0) +DEFINE_HWx_IRQDISPATCH(1) +DEFINE_HWx_IRQDISPATCH(2) +DEFINE_HWx_IRQDISPATCH(3) +DEFINE_HWx_IRQDISPATCH(4) + +static void ltq_hw5_irqdispatch(void) +{ + do_IRQ(MIPS_CPU_TIMER_IRQ); +} + +asmlinkage void plat_irq_dispatch(void) +{ + unsigned int pending = read_c0_status() & read_c0_cause() & ST0_IM; + unsigned int i; + + if (pending & CAUSEF_IP7) { + do_IRQ(MIPS_CPU_TIMER_IRQ); + goto out; + } else { + for (i = 0; i < 5; i++) { + if (pending & (CAUSEF_IP2 << i)) { + ltq_hw_irqdispatch(i); + goto out; + } + } + } + pr_alert("Spurious IRQ: CAUSE=0x%08x\n", read_c0_status()); + +out: + return; +} + +static struct irqaction cascade = { + .handler = no_action, + .flags = IRQF_DISABLED, + .name = "cascade", +}; + +void __init arch_init_irq(void) +{ + int i; + + if (insert_resource(&iomem_resource, <q_icu_resource) < 0) + panic("Failed to insert icu memory\n"); + + if (request_mem_region(ltq_icu_resource.start, + resource_size(<q_icu_resource), "icu") < 0) + panic("Failed to request icu memory\n"); + + ltq_icu_membase = ioremap_nocache(ltq_icu_resource.start, + resource_size(<q_icu_resource)); + if (!ltq_icu_membase) + panic("Failed to remap icu memory\n"); + + if (insert_resource(&iomem_resource, <q_eiu_resource) < 0) + panic("Failed to insert eiu memory\n"); + + if (request_mem_region(ltq_eiu_resource.start, + resource_size(<q_eiu_resource), "eiu") < 0) + panic("Failed to request eiu memory\n"); + + ltq_eiu_membase = ioremap_nocache(ltq_eiu_resource.start, + resource_size(<q_eiu_resource)); + if (!ltq_eiu_membase) + panic("Failed to remap eiu memory\n"); + + /* make sure all irqs are turned off by default */ + for (i = 0; i < 5; i++) + ltq_icu_w32(0, LTQ_ICU_IM0_IER + (i * LTQ_ICU_OFFSET)); + + /* clear all possibly pending interrupts */ + ltq_icu_w32(~0, LTQ_ICU_IM0_ISR + (i * LTQ_ICU_OFFSET)); + + mips_cpu_irq_init(); + + for (i = 2; i <= 6; i++) + setup_irq(i, &cascade); + + if (cpu_has_vint) { + pr_info("Setting up vectored interrupts\n"); + set_vi_handler(2, ltq_hw0_irqdispatch); + set_vi_handler(3, ltq_hw1_irqdispatch); + set_vi_handler(4, ltq_hw2_irqdispatch); + set_vi_handler(5, ltq_hw3_irqdispatch); + set_vi_handler(6, ltq_hw4_irqdispatch); + set_vi_handler(7, ltq_hw5_irqdispatch); + } + + for (i = INT_NUM_IRQ0; + i <= (INT_NUM_IRQ0 + (5 * INT_NUM_IM_OFFSET)); i++) + if ((i == LTQ_EIU_IR0) || (i == LTQ_EIU_IR1) || + (i == LTQ_EIU_IR2)) + irq_set_chip_and_handler(i, <q_eiu_type, + handle_level_irq); + /* EIU3-5 only exist on ar9 and vr9 */ + else if (((i == LTQ_EIU_IR3) || (i == LTQ_EIU_IR4) || + (i == LTQ_EIU_IR5)) && (ltq_is_ar9() || ltq_is_vr9())) + irq_set_chip_and_handler(i, <q_eiu_type, + handle_level_irq); + else + irq_set_chip_and_handler(i, <q_irq_type, + handle_level_irq); + +#if !defined(CONFIG_MIPS_MT_SMP) && !defined(CONFIG_MIPS_MT_SMTC) + set_c0_status(IE_IRQ0 | IE_IRQ1 | IE_IRQ2 | + IE_IRQ3 | IE_IRQ4 | IE_IRQ5); +#else + set_c0_status(IE_SW0 | IE_SW1 | IE_IRQ0 | IE_IRQ1 | + IE_IRQ2 | IE_IRQ3 | IE_IRQ4 | IE_IRQ5); +#endif +} + +unsigned int __cpuinit get_c0_compare_int(void) +{ + return CP0_LEGACY_COMPARE_IRQ; +} diff --git a/arch/mips/lantiq/prom.c b/arch/mips/lantiq/prom.c new file mode 100644 index 0000000..56ba007 --- /dev/null +++ b/arch/mips/lantiq/prom.c @@ -0,0 +1,71 @@ +/* + * 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) 2010 John Crispin + */ + +#include +#include +#include +#include + +#include + +#include "prom.h" +#include "clk.h" + +static struct ltq_soc_info soc_info; + +unsigned int ltq_get_cpu_ver(void) +{ + return soc_info.rev; +} +EXPORT_SYMBOL(ltq_get_cpu_ver); + +unsigned int ltq_get_soc_type(void) +{ + return soc_info.type; +} +EXPORT_SYMBOL(ltq_get_soc_type); + +const char *get_system_type(void) +{ + return soc_info.sys_type; +} + +void prom_free_prom_memory(void) +{ +} + +static void __init prom_init_cmdline(void) +{ + int argc = fw_arg0; + char **argv = (char **) KSEG1ADDR(fw_arg1); + int i; + + for (i = 0; i < argc; i++) { + char *p = (char *) KSEG1ADDR(argv[i]); + + if (p && *p) { + strlcat(arcs_cmdline, p, sizeof(arcs_cmdline)); + strlcat(arcs_cmdline, " ", sizeof(arcs_cmdline)); + } + } +} + +void __init prom_init(void) +{ + struct clk *clk; + + ltq_soc_detect(&soc_info); + clk_init(); + clk = clk_get(0, "cpu"); + snprintf(soc_info.sys_type, LTQ_SYS_TYPE_LEN - 1, "%s rev1.%d", + soc_info.name, soc_info.rev); + clk_put(clk); + soc_info.sys_type[LTQ_SYS_TYPE_LEN - 1] = '\0'; + pr_info("SoC: %s\n", soc_info.sys_type); + prom_init_cmdline(); +} diff --git a/arch/mips/lantiq/prom.h b/arch/mips/lantiq/prom.h new file mode 100644 index 0000000..4165ad1 --- /dev/null +++ b/arch/mips/lantiq/prom.h @@ -0,0 +1,24 @@ +/* + * 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) 2010 John Crispin + */ + +#ifndef _LTQ_PROM_H__ +#define _LTQ_PROM_H__ + +#define LTQ_SYS_TYPE_LEN 0x100 + +struct ltq_soc_info { + unsigned char *name; + unsigned int rev; + unsigned int partnum; + unsigned int type; + unsigned char sys_type[LTQ_SYS_TYPE_LEN]; +}; + +extern void ltq_soc_detect(struct ltq_soc_info *i); + +#endif diff --git a/arch/mips/lantiq/setup.c b/arch/mips/lantiq/setup.c new file mode 100644 index 0000000..79a2b0c --- /dev/null +++ b/arch/mips/lantiq/setup.c @@ -0,0 +1,41 @@ +/* + * 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) 2010 John Crispin + */ + +#include +#include +#include +#include +#include + +#include + +void __init plat_mem_setup(void) +{ + /* assume 16M as default incase uboot fails to pass proper ramsize */ + unsigned long memsize = 16; + char **envp = (char **) KSEG1ADDR(fw_arg2); + + ioport_resource.start = IOPORT_RESOURCE_START; + ioport_resource.end = IOPORT_RESOURCE_END; + iomem_resource.start = IOMEM_RESOURCE_START; + iomem_resource.end = IOMEM_RESOURCE_END; + + set_io_port_base((unsigned long) KSEG1); + + while (*envp) { + char *e = (char *)KSEG1ADDR(*envp); + if (!strncmp(e, "memsize=", 8)) { + e += 8; + if (strict_strtoul(e, 0, &memsize)) + pr_warn("bad memsize specified\n"); + } + envp++; + } + memsize *= 1024 * 1024; + add_memory_region(0x00000000, memsize, BOOT_MEM_RAM); +} -- cgit v0.10.2 From 8ec6d93508f705dacafd5fcd058c69ef405002f9 Mon Sep 17 00:00:00 2001 From: John Crispin Date: Wed, 30 Mar 2011 09:27:48 +0200 Subject: MIPS: Lantiq: add SoC specific code for XWAY family Add support for the Lantiq XWAY family of Mips24KEc SoCs. * Danube (PSB50702) * Twinpass (PSB4000) * AR9 (PSB50802) * Amazon SE (PSB5061) The Amazon SE is a lightweight SoC and has no PCI as well as a different clock. We split the code out into seperate files to handle this. The GPIO pins on the SoCs are multi function and there are several bits we can use to configure the pins. To be as compatible as possible to GPIOLIB we add a function int lq_gpio_request(unsigned int pin, unsigned int alt0, unsigned int alt1, unsigned int dir, const char *name); which lets you configure the 2 "alternate function" bits. This way drivers like PCI can make use of GPIOLIB without a cubersome wrapper. The PLL code inside arch/mips/lantiq/xway/clk-xway.c is voodoo to me. It was taken from a 2.4.20 source tree and was never really changed by me since then. Signed-off-by: John Crispin Signed-off-by: Ralph Hempel Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/2249/ Signed-off-by: Ralf Baechle diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig index 1787572..b3b4999 100644 --- a/arch/mips/Kconfig +++ b/arch/mips/Kconfig @@ -787,6 +787,7 @@ source "arch/mips/ath79/Kconfig" source "arch/mips/bcm63xx/Kconfig" source "arch/mips/jazz/Kconfig" source "arch/mips/jz4740/Kconfig" +source "arch/mips/lantiq/Kconfig" source "arch/mips/lasat/Kconfig" source "arch/mips/pmc-sierra/Kconfig" source "arch/mips/powertv/Kconfig" diff --git a/arch/mips/include/asm/mach-lantiq/xway/irq.h b/arch/mips/include/asm/mach-lantiq/xway/irq.h new file mode 100644 index 0000000..a1471d2 --- /dev/null +++ b/arch/mips/include/asm/mach-lantiq/xway/irq.h @@ -0,0 +1,18 @@ +/* + * 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) 2010 John Crispin + */ + +#ifndef __LANTIQ_IRQ_H +#define __LANTIQ_IRQ_H + +#include + +#define NR_IRQS 256 + +#include_next + +#endif diff --git a/arch/mips/include/asm/mach-lantiq/xway/lantiq_irq.h b/arch/mips/include/asm/mach-lantiq/xway/lantiq_irq.h new file mode 100644 index 0000000..b4465a8 --- /dev/null +++ b/arch/mips/include/asm/mach-lantiq/xway/lantiq_irq.h @@ -0,0 +1,66 @@ +/* + * 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) 2010 John Crispin + */ + +#ifndef _LANTIQ_XWAY_IRQ_H__ +#define _LANTIQ_XWAY_IRQ_H__ + +#define INT_NUM_IRQ0 8 +#define INT_NUM_IM0_IRL0 (INT_NUM_IRQ0 + 0) +#define INT_NUM_IM1_IRL0 (INT_NUM_IRQ0 + 32) +#define INT_NUM_IM2_IRL0 (INT_NUM_IRQ0 + 64) +#define INT_NUM_IM3_IRL0 (INT_NUM_IRQ0 + 96) +#define INT_NUM_IM4_IRL0 (INT_NUM_IRQ0 + 128) +#define INT_NUM_IM_OFFSET (INT_NUM_IM1_IRL0 - INT_NUM_IM0_IRL0) + +#define LTQ_ASC_TIR(x) (INT_NUM_IM3_IRL0 + (x * 8)) +#define LTQ_ASC_RIR(x) (INT_NUM_IM3_IRL0 + (x * 8) + 1) +#define LTQ_ASC_EIR(x) (INT_NUM_IM3_IRL0 + (x * 8) + 2) + +#define LTQ_ASC_ASE_TIR INT_NUM_IM2_IRL0 +#define LTQ_ASC_ASE_RIR (INT_NUM_IM2_IRL0 + 2) +#define LTQ_ASC_ASE_EIR (INT_NUM_IM2_IRL0 + 3) + +#define LTQ_SSC_TIR (INT_NUM_IM0_IRL0 + 15) +#define LTQ_SSC_RIR (INT_NUM_IM0_IRL0 + 14) +#define LTQ_SSC_EIR (INT_NUM_IM0_IRL0 + 16) + +#define LTQ_MEI_DYING_GASP_INT (INT_NUM_IM1_IRL0 + 21) +#define LTQ_MEI_INT (INT_NUM_IM1_IRL0 + 23) + +#define LTQ_TIMER6_INT (INT_NUM_IM1_IRL0 + 23) +#define LTQ_USB_INT (INT_NUM_IM1_IRL0 + 22) +#define LTQ_USB_OC_INT (INT_NUM_IM4_IRL0 + 23) + +#define MIPS_CPU_TIMER_IRQ 7 + +#define LTQ_DMA_CH0_INT (INT_NUM_IM2_IRL0) +#define LTQ_DMA_CH1_INT (INT_NUM_IM2_IRL0 + 1) +#define LTQ_DMA_CH2_INT (INT_NUM_IM2_IRL0 + 2) +#define LTQ_DMA_CH3_INT (INT_NUM_IM2_IRL0 + 3) +#define LTQ_DMA_CH4_INT (INT_NUM_IM2_IRL0 + 4) +#define LTQ_DMA_CH5_INT (INT_NUM_IM2_IRL0 + 5) +#define LTQ_DMA_CH6_INT (INT_NUM_IM2_IRL0 + 6) +#define LTQ_DMA_CH7_INT (INT_NUM_IM2_IRL0 + 7) +#define LTQ_DMA_CH8_INT (INT_NUM_IM2_IRL0 + 8) +#define LTQ_DMA_CH9_INT (INT_NUM_IM2_IRL0 + 9) +#define LTQ_DMA_CH10_INT (INT_NUM_IM2_IRL0 + 10) +#define LTQ_DMA_CH11_INT (INT_NUM_IM2_IRL0 + 11) +#define LTQ_DMA_CH12_INT (INT_NUM_IM2_IRL0 + 25) +#define LTQ_DMA_CH13_INT (INT_NUM_IM2_IRL0 + 26) +#define LTQ_DMA_CH14_INT (INT_NUM_IM2_IRL0 + 27) +#define LTQ_DMA_CH15_INT (INT_NUM_IM2_IRL0 + 28) +#define LTQ_DMA_CH16_INT (INT_NUM_IM2_IRL0 + 29) +#define LTQ_DMA_CH17_INT (INT_NUM_IM2_IRL0 + 30) +#define LTQ_DMA_CH18_INT (INT_NUM_IM2_IRL0 + 16) +#define LTQ_DMA_CH19_INT (INT_NUM_IM2_IRL0 + 21) + +#define LTQ_PPE_MBOX_INT (INT_NUM_IM2_IRL0 + 24) + +#define INT_NUM_IM4_IRL14 (INT_NUM_IM4_IRL0 + 14) + +#endif diff --git a/arch/mips/include/asm/mach-lantiq/xway/lantiq_soc.h b/arch/mips/include/asm/mach-lantiq/xway/lantiq_soc.h new file mode 100644 index 0000000..343e82cb --- /dev/null +++ b/arch/mips/include/asm/mach-lantiq/xway/lantiq_soc.h @@ -0,0 +1,140 @@ +/* + * 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) 2010 John Crispin + */ + +#ifndef _LTQ_XWAY_H__ +#define _LTQ_XWAY_H__ + +#ifdef CONFIG_SOC_TYPE_XWAY + +#include + +/* Chip IDs */ +#define SOC_ID_DANUBE1 0x129 +#define SOC_ID_DANUBE2 0x12B +#define SOC_ID_TWINPASS 0x12D +#define SOC_ID_AMAZON_SE 0x152 +#define SOC_ID_ARX188 0x16C +#define SOC_ID_ARX168 0x16D +#define SOC_ID_ARX182 0x16F + +/* SoC Types */ +#define SOC_TYPE_DANUBE 0x01 +#define SOC_TYPE_TWINPASS 0x02 +#define SOC_TYPE_AR9 0x03 +#define SOC_TYPE_VR9 0x04 +#define SOC_TYPE_AMAZON_SE 0x05 + +/* ASC0/1 - serial port */ +#define LTQ_ASC0_BASE_ADDR 0x1E100400 +#define LTQ_ASC1_BASE_ADDR 0x1E100C00 +#define LTQ_ASC_SIZE 0x400 + +/* RCU - reset control unit */ +#define LTQ_RCU_BASE_ADDR 0x1F203000 +#define LTQ_RCU_SIZE 0x1000 + +/* GPTU - general purpose timer unit */ +#define LTQ_GPTU_BASE_ADDR 0x18000300 +#define LTQ_GPTU_SIZE 0x100 + +/* EBU - external bus unit */ +#define LTQ_EBU_GPIO_START 0x14000000 +#define LTQ_EBU_GPIO_SIZE 0x1000 + +#define LTQ_EBU_BASE_ADDR 0x1E105300 +#define LTQ_EBU_SIZE 0x100 + +#define LTQ_EBU_BUSCON0 0x0060 +#define LTQ_EBU_PCC_CON 0x0090 +#define LTQ_EBU_PCC_IEN 0x00A4 +#define LTQ_EBU_PCC_ISTAT 0x00A0 +#define LTQ_EBU_BUSCON1 0x0064 +#define LTQ_EBU_ADDRSEL1 0x0024 +#define EBU_WRDIS 0x80000000 + +/* CGU - clock generation unit */ +#define LTQ_CGU_BASE_ADDR 0x1F103000 +#define LTQ_CGU_SIZE 0x1000 + +/* ICU - interrupt control unit */ +#define LTQ_ICU_BASE_ADDR 0x1F880200 +#define LTQ_ICU_SIZE 0x100 + +/* EIU - external interrupt unit */ +#define LTQ_EIU_BASE_ADDR 0x1F101000 +#define LTQ_EIU_SIZE 0x1000 + +/* PMU - power management unit */ +#define LTQ_PMU_BASE_ADDR 0x1F102000 +#define LTQ_PMU_SIZE 0x1000 + +#define PMU_DMA 0x0020 +#define PMU_USB 0x8041 +#define PMU_LED 0x0800 +#define PMU_GPT 0x1000 +#define PMU_PPE 0x2000 +#define PMU_FPI 0x4000 +#define PMU_SWITCH 0x10000000 + +/* ETOP - ethernet */ +#define LTQ_PPE32_BASE_ADDR 0xBE180000 +#define LTQ_PPE32_SIZE 0x40000 + +/* DMA */ +#define LTQ_DMA_BASE_ADDR 0xBE104100 + +/* PCI */ +#define PCI_CR_BASE_ADDR 0x1E105400 +#define PCI_CR_SIZE 0x400 + +/* WDT */ +#define LTQ_WDT_BASE_ADDR 0x1F8803F0 +#define LTQ_WDT_SIZE 0x10 + +/* STP - serial to parallel conversion unit */ +#define LTQ_STP_BASE_ADDR 0x1E100BB0 +#define LTQ_STP_SIZE 0x40 + +/* GPIO */ +#define LTQ_GPIO0_BASE_ADDR 0x1E100B10 +#define LTQ_GPIO1_BASE_ADDR 0x1E100B40 +#define LTQ_GPIO2_BASE_ADDR 0x1E100B70 +#define LTQ_GPIO_SIZE 0x30 + +/* SSC */ +#define LTQ_SSC_BASE_ADDR 0x1e100800 +#define LTQ_SSC_SIZE 0x100 + +/* MEI - dsl core */ +#define LTQ_MEI_BASE_ADDR 0x1E116000 + +/* DEU - data encryption unit */ +#define LTQ_DEU_BASE_ADDR 0x1E103100 + +/* MPS - multi processor unit (voice) */ +#define LTQ_MPS_BASE_ADDR (KSEG1 + 0x1F107000) +#define LTQ_MPS_CHIPID ((u32 *)(LTQ_MPS_BASE_ADDR + 0x0344)) + +/* request a non-gpio and set the PIO config */ +extern int ltq_gpio_request(unsigned int pin, unsigned int alt0, + unsigned int alt1, unsigned int dir, const char *name); +extern void ltq_pmu_enable(unsigned int module); +extern void ltq_pmu_disable(unsigned int module); + +static inline int ltq_is_ar9(void) +{ + return (ltq_get_soc_type() == SOC_TYPE_AR9); +} + +static inline int ltq_is_vr9(void) +{ + return (ltq_get_soc_type() == SOC_TYPE_VR9); +} + +#endif /* CONFIG_SOC_TYPE_XWAY */ +#endif /* _LTQ_XWAY_H__ */ diff --git a/arch/mips/lantiq/Kconfig b/arch/mips/lantiq/Kconfig new file mode 100644 index 0000000..2780461 --- /dev/null +++ b/arch/mips/lantiq/Kconfig @@ -0,0 +1,21 @@ +if LANTIQ + +config SOC_TYPE_XWAY + bool + default n + +choice + prompt "SoC Type" + default SOC_XWAY + +config SOC_AMAZON_SE + bool "Amazon SE" + select SOC_TYPE_XWAY + +config SOC_XWAY + bool "XWAY" + select SOC_TYPE_XWAY + select HW_HAS_PCI +endchoice + +endif diff --git a/arch/mips/lantiq/Makefile b/arch/mips/lantiq/Makefile index 6a30de6..a268391 100644 --- a/arch/mips/lantiq/Makefile +++ b/arch/mips/lantiq/Makefile @@ -7,3 +7,5 @@ obj-y := irq.o setup.o clk.o prom.o obj-$(CONFIG_EARLY_PRINTK) += early_printk.o + +obj-$(CONFIG_SOC_TYPE_XWAY) += xway/ diff --git a/arch/mips/lantiq/Platform b/arch/mips/lantiq/Platform index eef587f..f3dff05 100644 --- a/arch/mips/lantiq/Platform +++ b/arch/mips/lantiq/Platform @@ -5,3 +5,4 @@ platform-$(CONFIG_LANTIQ) += lantiq/ cflags-$(CONFIG_LANTIQ) += -I$(srctree)/arch/mips/include/asm/mach-lantiq load-$(CONFIG_LANTIQ) = 0xffffffff80002000 +cflags-$(CONFIG_SOC_TYPE_XWAY) += -I$(srctree)/arch/mips/include/asm/mach-lantiq/xway diff --git a/arch/mips/lantiq/xway/Makefile b/arch/mips/lantiq/xway/Makefile new file mode 100644 index 0000000..9c85ff9 --- /dev/null +++ b/arch/mips/lantiq/xway/Makefile @@ -0,0 +1,4 @@ +obj-y := pmu.o ebu.o reset.o gpio.o + +obj-$(CONFIG_SOC_XWAY) += clk-xway.o prom-xway.o +obj-$(CONFIG_SOC_AMAZON_SE) += clk-ase.o prom-ase.o diff --git a/arch/mips/lantiq/xway/clk-ase.c b/arch/mips/lantiq/xway/clk-ase.c new file mode 100644 index 0000000..22d823a --- /dev/null +++ b/arch/mips/lantiq/xway/clk-ase.c @@ -0,0 +1,48 @@ +/* + * 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 John Crispin + */ + +#include +#include +#include +#include + +#include +#include +#include + +#include + +/* cgu registers */ +#define LTQ_CGU_SYS 0x0010 + +unsigned int ltq_get_io_region_clock(void) +{ + return CLOCK_133M; +} +EXPORT_SYMBOL(ltq_get_io_region_clock); + +unsigned int ltq_get_fpi_bus_clock(int fpi) +{ + return CLOCK_133M; +} +EXPORT_SYMBOL(ltq_get_fpi_bus_clock); + +unsigned int ltq_get_cpu_hz(void) +{ + if (ltq_cgu_r32(LTQ_CGU_SYS) & (1 << 5)) + return CLOCK_266M; + else + return CLOCK_133M; +} +EXPORT_SYMBOL(ltq_get_cpu_hz); + +unsigned int ltq_get_fpi_hz(void) +{ + return CLOCK_133M; +} +EXPORT_SYMBOL(ltq_get_fpi_hz); diff --git a/arch/mips/lantiq/xway/clk-xway.c b/arch/mips/lantiq/xway/clk-xway.c new file mode 100644 index 0000000..ddd3959 --- /dev/null +++ b/arch/mips/lantiq/xway/clk-xway.c @@ -0,0 +1,223 @@ +/* + * 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) 2010 John Crispin + */ + +#include +#include +#include +#include + +#include +#include +#include + +#include + +static unsigned int ltq_ram_clocks[] = { + CLOCK_167M, CLOCK_133M, CLOCK_111M, CLOCK_83M }; +#define DDR_HZ ltq_ram_clocks[ltq_cgu_r32(LTQ_CGU_SYS) & 0x3] + +#define BASIC_FREQUENCY_1 35328000 +#define BASIC_FREQUENCY_2 36000000 +#define BASIS_REQUENCY_USB 12000000 + +#define GET_BITS(x, msb, lsb) \ + (((x) & ((1 << ((msb) + 1)) - 1)) >> (lsb)) + +#define LTQ_CGU_PLL0_CFG 0x0004 +#define LTQ_CGU_PLL1_CFG 0x0008 +#define LTQ_CGU_PLL2_CFG 0x000C +#define LTQ_CGU_SYS 0x0010 +#define LTQ_CGU_UPDATE 0x0014 +#define LTQ_CGU_IF_CLK 0x0018 +#define LTQ_CGU_OSC_CON 0x001C +#define LTQ_CGU_SMD 0x0020 +#define LTQ_CGU_CT1SR 0x0028 +#define LTQ_CGU_CT2SR 0x002C +#define LTQ_CGU_PCMCR 0x0030 +#define LTQ_CGU_PCI_CR 0x0034 +#define LTQ_CGU_PD_PC 0x0038 +#define LTQ_CGU_FMR 0x003C + +#define CGU_PLL0_PHASE_DIVIDER_ENABLE \ + (ltq_cgu_r32(LTQ_CGU_PLL0_CFG) & (1 << 31)) +#define CGU_PLL0_BYPASS \ + (ltq_cgu_r32(LTQ_CGU_PLL0_CFG) & (1 << 30)) +#define CGU_PLL0_CFG_DSMSEL \ + (ltq_cgu_r32(LTQ_CGU_PLL0_CFG) & (1 << 28)) +#define CGU_PLL0_CFG_FRAC_EN \ + (ltq_cgu_r32(LTQ_CGU_PLL0_CFG) & (1 << 27)) +#define CGU_PLL1_SRC \ + (ltq_cgu_r32(LTQ_CGU_PLL1_CFG) & (1 << 31)) +#define CGU_PLL2_PHASE_DIVIDER_ENABLE \ + (ltq_cgu_r32(LTQ_CGU_PLL2_CFG) & (1 << 20)) +#define CGU_SYS_FPI_SEL (1 << 6) +#define CGU_SYS_DDR_SEL 0x3 +#define CGU_PLL0_SRC (1 << 29) + +#define CGU_PLL0_CFG_PLLK GET_BITS(ltq_cgu_r32(LTQ_CGU_PLL0_CFG), 26, 17) +#define CGU_PLL0_CFG_PLLN GET_BITS(ltq_cgu_r32(LTQ_CGU_PLL0_CFG), 12, 6) +#define CGU_PLL0_CFG_PLLM GET_BITS(ltq_cgu_r32(LTQ_CGU_PLL0_CFG), 5, 2) +#define CGU_PLL2_SRC GET_BITS(ltq_cgu_r32(LTQ_CGU_PLL2_CFG), 18, 17) +#define CGU_PLL2_CFG_INPUT_DIV GET_BITS(ltq_cgu_r32(LTQ_CGU_PLL2_CFG), 16, 13) + +static unsigned int ltq_get_pll0_fdiv(void); + +static inline unsigned int get_input_clock(int pll) +{ + switch (pll) { + case 0: + if (ltq_cgu_r32(LTQ_CGU_PLL0_CFG) & CGU_PLL0_SRC) + return BASIS_REQUENCY_USB; + else if (CGU_PLL0_PHASE_DIVIDER_ENABLE) + return BASIC_FREQUENCY_1; + else + return BASIC_FREQUENCY_2; + case 1: + if (CGU_PLL1_SRC) + return BASIS_REQUENCY_USB; + else if (CGU_PLL0_PHASE_DIVIDER_ENABLE) + return BASIC_FREQUENCY_1; + else + return BASIC_FREQUENCY_2; + case 2: + switch (CGU_PLL2_SRC) { + case 0: + return ltq_get_pll0_fdiv(); + case 1: + return CGU_PLL2_PHASE_DIVIDER_ENABLE ? + BASIC_FREQUENCY_1 : + BASIC_FREQUENCY_2; + case 2: + return BASIS_REQUENCY_USB; + } + default: + return 0; + } +} + +static inline unsigned int cal_dsm(int pll, unsigned int num, unsigned int den) +{ + u64 res, clock = get_input_clock(pll); + + res = num * clock; + do_div(res, den); + return res; +} + +static inline unsigned int mash_dsm(int pll, unsigned int M, unsigned int N, + unsigned int K) +{ + unsigned int num = ((N + 1) << 10) + K; + unsigned int den = (M + 1) << 10; + + return cal_dsm(pll, num, den); +} + +static inline unsigned int ssff_dsm_1(int pll, unsigned int M, unsigned int N, + unsigned int K) +{ + unsigned int num = ((N + 1) << 11) + K + 512; + unsigned int den = (M + 1) << 11; + + return cal_dsm(pll, num, den); +} + +static inline unsigned int ssff_dsm_2(int pll, unsigned int M, unsigned int N, + unsigned int K) +{ + unsigned int num = K >= 512 ? + ((N + 1) << 12) + K - 512 : ((N + 1) << 12) + K + 3584; + unsigned int den = (M + 1) << 12; + + return cal_dsm(pll, num, den); +} + +static inline unsigned int dsm(int pll, unsigned int M, unsigned int N, + unsigned int K, unsigned int dsmsel, unsigned int phase_div_en) +{ + if (!dsmsel) + return mash_dsm(pll, M, N, K); + else if (!phase_div_en) + return mash_dsm(pll, M, N, K); + else + return ssff_dsm_2(pll, M, N, K); +} + +static inline unsigned int ltq_get_pll0_fosc(void) +{ + if (CGU_PLL0_BYPASS) + return get_input_clock(0); + else + return !CGU_PLL0_CFG_FRAC_EN + ? dsm(0, CGU_PLL0_CFG_PLLM, CGU_PLL0_CFG_PLLN, 0, + CGU_PLL0_CFG_DSMSEL, + CGU_PLL0_PHASE_DIVIDER_ENABLE) + : dsm(0, CGU_PLL0_CFG_PLLM, CGU_PLL0_CFG_PLLN, + CGU_PLL0_CFG_PLLK, CGU_PLL0_CFG_DSMSEL, + CGU_PLL0_PHASE_DIVIDER_ENABLE); +} + +static unsigned int ltq_get_pll0_fdiv(void) +{ + unsigned int div = CGU_PLL2_CFG_INPUT_DIV + 1; + + return (ltq_get_pll0_fosc() + (div >> 1)) / div; +} + +unsigned int ltq_get_io_region_clock(void) +{ + unsigned int ret = ltq_get_pll0_fosc(); + + switch (ltq_cgu_r32(LTQ_CGU_PLL2_CFG) & CGU_SYS_DDR_SEL) { + default: + case 0: + return (ret + 1) / 2; + case 1: + return (ret * 2 + 2) / 5; + case 2: + return (ret + 1) / 3; + case 3: + return (ret + 2) / 4; + } +} +EXPORT_SYMBOL(ltq_get_io_region_clock); + +unsigned int ltq_get_fpi_bus_clock(int fpi) +{ + unsigned int ret = ltq_get_io_region_clock(); + + if ((fpi == 2) && (ltq_cgu_r32(LTQ_CGU_SYS) & CGU_SYS_FPI_SEL)) + ret >>= 1; + return ret; +} +EXPORT_SYMBOL(ltq_get_fpi_bus_clock); + +unsigned int ltq_get_cpu_hz(void) +{ + switch (ltq_cgu_r32(LTQ_CGU_SYS) & 0xc) { + case 0: + return CLOCK_333M; + case 4: + return DDR_HZ; + case 8: + return DDR_HZ << 1; + default: + return DDR_HZ >> 1; + } +} +EXPORT_SYMBOL(ltq_get_cpu_hz); + +unsigned int ltq_get_fpi_hz(void) +{ + unsigned int ddr_clock = DDR_HZ; + + if (ltq_cgu_r32(LTQ_CGU_SYS) & 0x40) + return ddr_clock >> 1; + return ddr_clock; +} +EXPORT_SYMBOL(ltq_get_fpi_hz); diff --git a/arch/mips/lantiq/xway/ebu.c b/arch/mips/lantiq/xway/ebu.c new file mode 100644 index 0000000..66eb52f --- /dev/null +++ b/arch/mips/lantiq/xway/ebu.c @@ -0,0 +1,53 @@ +/* + * 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. + * + * EBU - the external bus unit attaches PCI, NOR and NAND + * + * Copyright (C) 2010 John Crispin + */ + +#include +#include +#include +#include + +#include + +/* all access to the ebu must be locked */ +DEFINE_SPINLOCK(ebu_lock); +EXPORT_SYMBOL_GPL(ebu_lock); + +static struct resource ltq_ebu_resource = { + .name = "ebu", + .start = LTQ_EBU_BASE_ADDR, + .end = LTQ_EBU_BASE_ADDR + LTQ_EBU_SIZE - 1, + .flags = IORESOURCE_MEM, +}; + +/* remapped base addr of the clock unit and external bus unit */ +void __iomem *ltq_ebu_membase; + +static int __init lantiq_ebu_init(void) +{ + /* insert and request the memory region */ + if (insert_resource(&iomem_resource, <q_ebu_resource) < 0) + panic("Failed to insert ebu memory\n"); + + if (request_mem_region(ltq_ebu_resource.start, + resource_size(<q_ebu_resource), "ebu") < 0) + panic("Failed to request ebu memory\n"); + + /* remap ebu register range */ + ltq_ebu_membase = ioremap_nocache(ltq_ebu_resource.start, + resource_size(<q_ebu_resource)); + if (!ltq_ebu_membase) + panic("Failed to remap ebu memory\n"); + + /* make sure to unprotect the memory region where flash is located */ + ltq_ebu_w32(ltq_ebu_r32(LTQ_EBU_BUSCON0) & ~EBU_WRDIS, LTQ_EBU_BUSCON0); + return 0; +} + +postcore_initcall(lantiq_ebu_init); diff --git a/arch/mips/lantiq/xway/gpio.c b/arch/mips/lantiq/xway/gpio.c new file mode 100644 index 0000000..a321451 --- /dev/null +++ b/arch/mips/lantiq/xway/gpio.c @@ -0,0 +1,195 @@ +/* + * 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) 2010 John Crispin + */ + +#include +#include +#include +#include +#include +#include + +#include + +#define LTQ_GPIO_OUT 0x00 +#define LTQ_GPIO_IN 0x04 +#define LTQ_GPIO_DIR 0x08 +#define LTQ_GPIO_ALTSEL0 0x0C +#define LTQ_GPIO_ALTSEL1 0x10 +#define LTQ_GPIO_OD 0x14 + +#define PINS_PER_PORT 16 +#define MAX_PORTS 3 + +#define ltq_gpio_getbit(m, r, p) (!!(ltq_r32(m + r) & (1 << p))) +#define ltq_gpio_setbit(m, r, p) ltq_w32_mask(0, (1 << p), m + r) +#define ltq_gpio_clearbit(m, r, p) ltq_w32_mask((1 << p), 0, m + r) + +struct ltq_gpio { + void __iomem *membase; + struct gpio_chip chip; +}; + +static struct ltq_gpio ltq_gpio_port[MAX_PORTS]; + +int gpio_to_irq(unsigned int gpio) +{ + return -EINVAL; +} +EXPORT_SYMBOL(gpio_to_irq); + +int irq_to_gpio(unsigned int gpio) +{ + return -EINVAL; +} +EXPORT_SYMBOL(irq_to_gpio); + +int ltq_gpio_request(unsigned int pin, unsigned int alt0, + unsigned int alt1, unsigned int dir, const char *name) +{ + int id = 0; + + if (pin >= (MAX_PORTS * PINS_PER_PORT)) + return -EINVAL; + if (gpio_request(pin, name)) { + pr_err("failed to setup lantiq gpio: %s\n", name); + return -EBUSY; + } + if (dir) + gpio_direction_output(pin, 1); + else + gpio_direction_input(pin); + while (pin >= PINS_PER_PORT) { + pin -= PINS_PER_PORT; + id++; + } + if (alt0) + ltq_gpio_setbit(ltq_gpio_port[id].membase, + LTQ_GPIO_ALTSEL0, pin); + else + ltq_gpio_clearbit(ltq_gpio_port[id].membase, + LTQ_GPIO_ALTSEL0, pin); + if (alt1) + ltq_gpio_setbit(ltq_gpio_port[id].membase, + LTQ_GPIO_ALTSEL1, pin); + else + ltq_gpio_clearbit(ltq_gpio_port[id].membase, + LTQ_GPIO_ALTSEL1, pin); + return 0; +} +EXPORT_SYMBOL(ltq_gpio_request); + +static void ltq_gpio_set(struct gpio_chip *chip, unsigned int offset, int value) +{ + struct ltq_gpio *ltq_gpio = container_of(chip, struct ltq_gpio, chip); + + if (value) + ltq_gpio_setbit(ltq_gpio->membase, LTQ_GPIO_OUT, offset); + else + ltq_gpio_clearbit(ltq_gpio->membase, LTQ_GPIO_OUT, offset); +} + +static int ltq_gpio_get(struct gpio_chip *chip, unsigned int offset) +{ + struct ltq_gpio *ltq_gpio = container_of(chip, struct ltq_gpio, chip); + + return ltq_gpio_getbit(ltq_gpio->membase, LTQ_GPIO_IN, offset); +} + +static int ltq_gpio_direction_input(struct gpio_chip *chip, unsigned int offset) +{ + struct ltq_gpio *ltq_gpio = container_of(chip, struct ltq_gpio, chip); + + ltq_gpio_clearbit(ltq_gpio->membase, LTQ_GPIO_OD, offset); + ltq_gpio_clearbit(ltq_gpio->membase, LTQ_GPIO_DIR, offset); + + return 0; +} + +static int ltq_gpio_direction_output(struct gpio_chip *chip, + unsigned int offset, int value) +{ + struct ltq_gpio *ltq_gpio = container_of(chip, struct ltq_gpio, chip); + + ltq_gpio_setbit(ltq_gpio->membase, LTQ_GPIO_OD, offset); + ltq_gpio_setbit(ltq_gpio->membase, LTQ_GPIO_DIR, offset); + ltq_gpio_set(chip, offset, value); + + return 0; +} + +static int ltq_gpio_req(struct gpio_chip *chip, unsigned offset) +{ + struct ltq_gpio *ltq_gpio = container_of(chip, struct ltq_gpio, chip); + + ltq_gpio_clearbit(ltq_gpio->membase, LTQ_GPIO_ALTSEL0, offset); + ltq_gpio_clearbit(ltq_gpio->membase, LTQ_GPIO_ALTSEL1, offset); + return 0; +} + +static int ltq_gpio_probe(struct platform_device *pdev) +{ + struct resource *res; + + if (pdev->id >= MAX_PORTS) { + dev_err(&pdev->dev, "invalid gpio port %d\n", + pdev->id); + return -EINVAL; + } + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) { + dev_err(&pdev->dev, "failed to get memory for gpio port %d\n", + pdev->id); + return -ENOENT; + } + res = devm_request_mem_region(&pdev->dev, res->start, + resource_size(res), dev_name(&pdev->dev)); + if (!res) { + dev_err(&pdev->dev, + "failed to request memory for gpio port %d\n", + pdev->id); + return -EBUSY; + } + ltq_gpio_port[pdev->id].membase = devm_ioremap_nocache(&pdev->dev, + res->start, resource_size(res)); + if (!ltq_gpio_port[pdev->id].membase) { + dev_err(&pdev->dev, "failed to remap memory for gpio port %d\n", + pdev->id); + return -ENOMEM; + } + ltq_gpio_port[pdev->id].chip.label = "ltq_gpio"; + ltq_gpio_port[pdev->id].chip.direction_input = ltq_gpio_direction_input; + ltq_gpio_port[pdev->id].chip.direction_output = + ltq_gpio_direction_output; + ltq_gpio_port[pdev->id].chip.get = ltq_gpio_get; + ltq_gpio_port[pdev->id].chip.set = ltq_gpio_set; + ltq_gpio_port[pdev->id].chip.request = ltq_gpio_req; + ltq_gpio_port[pdev->id].chip.base = PINS_PER_PORT * pdev->id; + ltq_gpio_port[pdev->id].chip.ngpio = PINS_PER_PORT; + platform_set_drvdata(pdev, <q_gpio_port[pdev->id]); + return gpiochip_add(<q_gpio_port[pdev->id].chip); +} + +static struct platform_driver +ltq_gpio_driver = { + .probe = ltq_gpio_probe, + .driver = { + .name = "ltq_gpio", + .owner = THIS_MODULE, + }, +}; + +int __init ltq_gpio_init(void) +{ + int ret = platform_driver_register(<q_gpio_driver); + + if (ret) + pr_info("ltq_gpio : Error registering platfom driver!"); + return ret; +} + +postcore_initcall(ltq_gpio_init); diff --git a/arch/mips/lantiq/xway/pmu.c b/arch/mips/lantiq/xway/pmu.c new file mode 100644 index 0000000..9d69f01e --- /dev/null +++ b/arch/mips/lantiq/xway/pmu.c @@ -0,0 +1,70 @@ +/* + * 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) 2010 John Crispin + */ + +#include +#include +#include +#include + +#include + +/* PMU - the power management unit allows us to turn part of the core + * on and off + */ + +/* the enable / disable registers */ +#define LTQ_PMU_PWDCR 0x1C +#define LTQ_PMU_PWDSR 0x20 + +#define ltq_pmu_w32(x, y) ltq_w32((x), ltq_pmu_membase + (y)) +#define ltq_pmu_r32(x) ltq_r32(ltq_pmu_membase + (x)) + +static struct resource ltq_pmu_resource = { + .name = "pmu", + .start = LTQ_PMU_BASE_ADDR, + .end = LTQ_PMU_BASE_ADDR + LTQ_PMU_SIZE - 1, + .flags = IORESOURCE_MEM, +}; + +static void __iomem *ltq_pmu_membase; + +void ltq_pmu_enable(unsigned int module) +{ + int err = 1000000; + + ltq_pmu_w32(ltq_pmu_r32(LTQ_PMU_PWDCR) & ~module, LTQ_PMU_PWDCR); + do {} while (--err && (ltq_pmu_r32(LTQ_PMU_PWDSR) & module)); + + if (!err) + panic("activating PMU module failed!\n"); +} +EXPORT_SYMBOL(ltq_pmu_enable); + +void ltq_pmu_disable(unsigned int module) +{ + ltq_pmu_w32(ltq_pmu_r32(LTQ_PMU_PWDCR) | module, LTQ_PMU_PWDCR); +} +EXPORT_SYMBOL(ltq_pmu_disable); + +int __init ltq_pmu_init(void) +{ + if (insert_resource(&iomem_resource, <q_pmu_resource) < 0) + panic("Failed to insert pmu memory\n"); + + if (request_mem_region(ltq_pmu_resource.start, + resource_size(<q_pmu_resource), "pmu") < 0) + panic("Failed to request pmu memory\n"); + + ltq_pmu_membase = ioremap_nocache(ltq_pmu_resource.start, + resource_size(<q_pmu_resource)); + if (!ltq_pmu_membase) + panic("Failed to remap pmu memory\n"); + return 0; +} + +core_initcall(ltq_pmu_init); diff --git a/arch/mips/lantiq/xway/prom-ase.c b/arch/mips/lantiq/xway/prom-ase.c new file mode 100644 index 0000000..abe49f4 --- /dev/null +++ b/arch/mips/lantiq/xway/prom-ase.c @@ -0,0 +1,39 @@ +/* + * 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) 2010 John Crispin + */ + +#include +#include +#include +#include + +#include + +#include "../prom.h" + +#define SOC_AMAZON_SE "Amazon_SE" + +#define PART_SHIFT 12 +#define PART_MASK 0x0FFFFFFF +#define REV_SHIFT 28 +#define REV_MASK 0xF0000000 + +void __init ltq_soc_detect(struct ltq_soc_info *i) +{ + i->partnum = (ltq_r32(LTQ_MPS_CHIPID) & PART_MASK) >> PART_SHIFT; + i->rev = (ltq_r32(LTQ_MPS_CHIPID) & REV_MASK) >> REV_SHIFT; + switch (i->partnum) { + case SOC_ID_AMAZON_SE: + i->name = SOC_AMAZON_SE; + i->type = SOC_TYPE_AMAZON_SE; + break; + + default: + unreachable(); + break; + } +} diff --git a/arch/mips/lantiq/xway/prom-xway.c b/arch/mips/lantiq/xway/prom-xway.c new file mode 100644 index 0000000..1686692a --- /dev/null +++ b/arch/mips/lantiq/xway/prom-xway.c @@ -0,0 +1,54 @@ +/* + * 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) 2010 John Crispin + */ + +#include +#include +#include +#include + +#include + +#include "../prom.h" + +#define SOC_DANUBE "Danube" +#define SOC_TWINPASS "Twinpass" +#define SOC_AR9 "AR9" + +#define PART_SHIFT 12 +#define PART_MASK 0x0FFFFFFF +#define REV_SHIFT 28 +#define REV_MASK 0xF0000000 + +void __init ltq_soc_detect(struct ltq_soc_info *i) +{ + i->partnum = (ltq_r32(LTQ_MPS_CHIPID) & PART_MASK) >> PART_SHIFT; + i->rev = (ltq_r32(LTQ_MPS_CHIPID) & REV_MASK) >> REV_SHIFT; + switch (i->partnum) { + case SOC_ID_DANUBE1: + case SOC_ID_DANUBE2: + i->name = SOC_DANUBE; + i->type = SOC_TYPE_DANUBE; + break; + + case SOC_ID_TWINPASS: + i->name = SOC_TWINPASS; + i->type = SOC_TYPE_DANUBE; + break; + + case SOC_ID_ARX188: + case SOC_ID_ARX168: + case SOC_ID_ARX182: + i->name = SOC_AR9; + i->type = SOC_TYPE_AR9; + break; + + default: + unreachable(); + break; + } +} diff --git a/arch/mips/lantiq/xway/reset.c b/arch/mips/lantiq/xway/reset.c new file mode 100644 index 0000000..a1be36d --- /dev/null +++ b/arch/mips/lantiq/xway/reset.c @@ -0,0 +1,91 @@ +/* + * 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) 2010 John Crispin + */ + +#include +#include +#include +#include +#include +#include + +#include + +#define ltq_rcu_w32(x, y) ltq_w32((x), ltq_rcu_membase + (y)) +#define ltq_rcu_r32(x) ltq_r32(ltq_rcu_membase + (x)) + +/* register definitions */ +#define LTQ_RCU_RST 0x0010 +#define LTQ_RCU_RST_ALL 0x40000000 + +#define LTQ_RCU_RST_STAT 0x0014 +#define LTQ_RCU_STAT_SHIFT 26 + +static struct resource ltq_rcu_resource = { + .name = "rcu", + .start = LTQ_RCU_BASE_ADDR, + .end = LTQ_RCU_BASE_ADDR + LTQ_RCU_SIZE - 1, + .flags = IORESOURCE_MEM, +}; + +/* remapped base addr of the reset control unit */ +static void __iomem *ltq_rcu_membase; + +/* This function is used by the watchdog driver */ +int ltq_reset_cause(void) +{ + u32 val = ltq_rcu_r32(LTQ_RCU_RST_STAT); + return val >> LTQ_RCU_STAT_SHIFT; +} +EXPORT_SYMBOL_GPL(ltq_reset_cause); + +static void ltq_machine_restart(char *command) +{ + pr_notice("System restart\n"); + local_irq_disable(); + ltq_rcu_w32(ltq_rcu_r32(LTQ_RCU_RST) | LTQ_RCU_RST_ALL, LTQ_RCU_RST); + unreachable(); +} + +static void ltq_machine_halt(void) +{ + pr_notice("System halted.\n"); + local_irq_disable(); + unreachable(); +} + +static void ltq_machine_power_off(void) +{ + pr_notice("Please turn off the power now.\n"); + local_irq_disable(); + unreachable(); +} + +static int __init mips_reboot_setup(void) +{ + /* insert and request the memory region */ + if (insert_resource(&iomem_resource, <q_rcu_resource) < 0) + panic("Failed to insert rcu memory\n"); + + if (request_mem_region(ltq_rcu_resource.start, + resource_size(<q_rcu_resource), "rcu") < 0) + panic("Failed to request rcu memory\n"); + + /* remap rcu register range */ + ltq_rcu_membase = ioremap_nocache(ltq_rcu_resource.start, + resource_size(<q_rcu_resource)); + if (!ltq_rcu_membase) + panic("Failed to remap rcu memory\n"); + + _machine_restart = ltq_machine_restart; + _machine_halt = ltq_machine_halt; + pm_power_off = ltq_machine_power_off; + + return 0; +} + +arch_initcall(mips_reboot_setup); -- cgit v0.10.2 From e47d488935ed0b2dd3d59d3ba4e13956ff6849c0 Mon Sep 17 00:00:00 2001 From: John Crispin Date: Wed, 30 Mar 2011 09:27:49 +0200 Subject: MIPS: Lantiq: Add PCI controller support. The Lantiq family of SoCs have a EBU (External Bus Unit). This patch adds the driver that allows us to use the EBU as a PCI controller. In order for PCI to work the EBU is set to endianess swap all the data. In addition we need to make use of SWAP_IO_SPACE for device->host DMA to work. The clock of the PCI works in several modes (internal/external). If this is not configured correctly the SoC will hang. Signed-off-by: John Crispin Signed-off-by: Ralph Hempel Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/2250/ Signed-off-by: Ralf Baechle diff --git a/arch/mips/include/asm/mach-lantiq/lantiq_platform.h b/arch/mips/include/asm/mach-lantiq/lantiq_platform.h new file mode 100644 index 0000000..1f1dba6 --- /dev/null +++ b/arch/mips/include/asm/mach-lantiq/lantiq_platform.h @@ -0,0 +1,46 @@ +/* + * 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) 2010 John Crispin + */ + +#ifndef _LANTIQ_PLATFORM_H__ +#define _LANTIQ_PLATFORM_H__ + +#include + +/* struct used to pass info to the pci core */ +enum { + PCI_CLOCK_INT = 0, + PCI_CLOCK_EXT +}; + +#define PCI_EXIN0 0x0001 +#define PCI_EXIN1 0x0002 +#define PCI_EXIN2 0x0004 +#define PCI_EXIN3 0x0008 +#define PCI_EXIN4 0x0010 +#define PCI_EXIN5 0x0020 +#define PCI_EXIN_MAX 6 + +#define PCI_GNT1 0x0040 +#define PCI_GNT2 0x0080 +#define PCI_GNT3 0x0100 +#define PCI_GNT4 0x0200 + +#define PCI_REQ1 0x0400 +#define PCI_REQ2 0x0800 +#define PCI_REQ3 0x1000 +#define PCI_REQ4 0x2000 +#define PCI_REQ_SHIFT 10 +#define PCI_REQ_MASK 0xf + +struct ltq_pci_data { + int clock; + int gpio; + int irq[16]; +}; + +#endif diff --git a/arch/mips/pci/Makefile b/arch/mips/pci/Makefile index f0d5329..4df8799 100644 --- a/arch/mips/pci/Makefile +++ b/arch/mips/pci/Makefile @@ -41,6 +41,7 @@ obj-$(CONFIG_SIBYTE_SB1250) += fixup-sb1250.o pci-sb1250.o obj-$(CONFIG_SIBYTE_BCM112X) += fixup-sb1250.o pci-sb1250.o obj-$(CONFIG_SIBYTE_BCM1x80) += pci-bcm1480.o pci-bcm1480ht.o obj-$(CONFIG_SNI_RM) += fixup-sni.o ops-sni.o +obj-$(CONFIG_SOC_XWAY) += pci-lantiq.o ops-lantiq.o obj-$(CONFIG_TANBAC_TB0219) += fixup-tb0219.o obj-$(CONFIG_TANBAC_TB0226) += fixup-tb0226.o obj-$(CONFIG_TANBAC_TB0287) += fixup-tb0287.o diff --git a/arch/mips/pci/ops-lantiq.c b/arch/mips/pci/ops-lantiq.c new file mode 100644 index 0000000..1f2afb5 --- /dev/null +++ b/arch/mips/pci/ops-lantiq.c @@ -0,0 +1,116 @@ +/* + * 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) 2010 John Crispin + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "pci-lantiq.h" + +#define LTQ_PCI_CFG_BUSNUM_SHF 16 +#define LTQ_PCI_CFG_DEVNUM_SHF 11 +#define LTQ_PCI_CFG_FUNNUM_SHF 8 + +#define PCI_ACCESS_READ 0 +#define PCI_ACCESS_WRITE 1 + +static int ltq_pci_config_access(unsigned char access_type, struct pci_bus *bus, + unsigned int devfn, unsigned int where, u32 *data) +{ + unsigned long cfg_base; + unsigned long flags; + u32 temp; + + /* we support slot from 0 to 15 dev_fn & 0x68 (AD29) is the + SoC itself */ + if ((bus->number != 0) || ((devfn & 0xf8) > 0x78) + || ((devfn & 0xf8) == 0) || ((devfn & 0xf8) == 0x68)) + return 1; + + spin_lock_irqsave(&ebu_lock, flags); + + cfg_base = (unsigned long) ltq_pci_mapped_cfg; + cfg_base |= (bus->number << LTQ_PCI_CFG_BUSNUM_SHF) | (devfn << + LTQ_PCI_CFG_FUNNUM_SHF) | (where & ~0x3); + + /* Perform access */ + if (access_type == PCI_ACCESS_WRITE) { + ltq_w32(swab32(*data), ((u32 *)cfg_base)); + } else { + *data = ltq_r32(((u32 *)(cfg_base))); + *data = swab32(*data); + } + wmb(); + + /* clean possible Master abort */ + cfg_base = (unsigned long) ltq_pci_mapped_cfg; + cfg_base |= (0x0 << LTQ_PCI_CFG_FUNNUM_SHF) + 4; + temp = ltq_r32(((u32 *)(cfg_base))); + temp = swab32(temp); + cfg_base = (unsigned long) ltq_pci_mapped_cfg; + cfg_base |= (0x68 << LTQ_PCI_CFG_FUNNUM_SHF) + 4; + ltq_w32(temp, ((u32 *)cfg_base)); + + spin_unlock_irqrestore(&ebu_lock, flags); + + if (((*data) == 0xffffffff) && (access_type == PCI_ACCESS_READ)) + return 1; + + return 0; +} + +int ltq_pci_read_config_dword(struct pci_bus *bus, unsigned int devfn, + int where, int size, u32 *val) +{ + u32 data = 0; + + if (ltq_pci_config_access(PCI_ACCESS_READ, bus, devfn, where, &data)) + return PCIBIOS_DEVICE_NOT_FOUND; + + if (size == 1) + *val = (data >> ((where & 3) << 3)) & 0xff; + else if (size == 2) + *val = (data >> ((where & 3) << 3)) & 0xffff; + else + *val = data; + + return PCIBIOS_SUCCESSFUL; +} + +int ltq_pci_write_config_dword(struct pci_bus *bus, unsigned int devfn, + int where, int size, u32 val) +{ + u32 data = 0; + + if (size == 4) { + data = val; + } else { + if (ltq_pci_config_access(PCI_ACCESS_READ, bus, + devfn, where, &data)) + return PCIBIOS_DEVICE_NOT_FOUND; + + if (size == 1) + data = (data & ~(0xff << ((where & 3) << 3))) | + (val << ((where & 3) << 3)); + else if (size == 2) + data = (data & ~(0xffff << ((where & 3) << 3))) | + (val << ((where & 3) << 3)); + } + + if (ltq_pci_config_access(PCI_ACCESS_WRITE, bus, devfn, where, &data)) + return PCIBIOS_DEVICE_NOT_FOUND; + + return PCIBIOS_SUCCESSFUL; +} diff --git a/arch/mips/pci/pci-lantiq.c b/arch/mips/pci/pci-lantiq.c new file mode 100644 index 0000000..603d749 --- /dev/null +++ b/arch/mips/pci/pci-lantiq.c @@ -0,0 +1,297 @@ +/* + * 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) 2010 John Crispin + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include + +#include "pci-lantiq.h" + +#define LTQ_PCI_CFG_BASE 0x17000000 +#define LTQ_PCI_CFG_SIZE 0x00008000 +#define LTQ_PCI_MEM_BASE 0x18000000 +#define LTQ_PCI_MEM_SIZE 0x02000000 +#define LTQ_PCI_IO_BASE 0x1AE00000 +#define LTQ_PCI_IO_SIZE 0x00200000 + +#define PCI_CR_FCI_ADDR_MAP0 0x00C0 +#define PCI_CR_FCI_ADDR_MAP1 0x00C4 +#define PCI_CR_FCI_ADDR_MAP2 0x00C8 +#define PCI_CR_FCI_ADDR_MAP3 0x00CC +#define PCI_CR_FCI_ADDR_MAP4 0x00D0 +#define PCI_CR_FCI_ADDR_MAP5 0x00D4 +#define PCI_CR_FCI_ADDR_MAP6 0x00D8 +#define PCI_CR_FCI_ADDR_MAP7 0x00DC +#define PCI_CR_CLK_CTRL 0x0000 +#define PCI_CR_PCI_MOD 0x0030 +#define PCI_CR_PC_ARB 0x0080 +#define PCI_CR_FCI_ADDR_MAP11hg 0x00E4 +#define PCI_CR_BAR11MASK 0x0044 +#define PCI_CR_BAR12MASK 0x0048 +#define PCI_CR_BAR13MASK 0x004C +#define PCI_CS_BASE_ADDR1 0x0010 +#define PCI_CR_PCI_ADDR_MAP11 0x0064 +#define PCI_CR_FCI_BURST_LENGTH 0x00E8 +#define PCI_CR_PCI_EOI 0x002C +#define PCI_CS_STS_CMD 0x0004 + +#define PCI_MASTER0_REQ_MASK_2BITS 8 +#define PCI_MASTER1_REQ_MASK_2BITS 10 +#define PCI_MASTER2_REQ_MASK_2BITS 12 +#define INTERNAL_ARB_ENABLE_BIT 0 + +#define LTQ_CGU_IFCCR 0x0018 +#define LTQ_CGU_PCICR 0x0034 + +#define ltq_pci_w32(x, y) ltq_w32((x), ltq_pci_membase + (y)) +#define ltq_pci_r32(x) ltq_r32(ltq_pci_membase + (x)) + +#define ltq_pci_cfg_w32(x, y) ltq_w32((x), ltq_pci_mapped_cfg + (y)) +#define ltq_pci_cfg_r32(x) ltq_r32(ltq_pci_mapped_cfg + (x)) + +struct ltq_pci_gpio_map { + int pin; + int alt0; + int alt1; + int dir; + char *name; +}; + +/* the pci core can make use of the following gpios */ +static struct ltq_pci_gpio_map ltq_pci_gpio_map[] = { + { 0, 1, 0, 0, "pci-exin0" }, + { 1, 1, 0, 0, "pci-exin1" }, + { 2, 1, 0, 0, "pci-exin2" }, + { 39, 1, 0, 0, "pci-exin3" }, + { 10, 1, 0, 0, "pci-exin4" }, + { 9, 1, 0, 0, "pci-exin5" }, + { 30, 1, 0, 1, "pci-gnt1" }, + { 23, 1, 0, 1, "pci-gnt2" }, + { 19, 1, 0, 1, "pci-gnt3" }, + { 38, 1, 0, 1, "pci-gnt4" }, + { 29, 1, 0, 0, "pci-req1" }, + { 31, 1, 0, 0, "pci-req2" }, + { 3, 1, 0, 0, "pci-req3" }, + { 37, 1, 0, 0, "pci-req4" }, +}; + +__iomem void *ltq_pci_mapped_cfg; +static __iomem void *ltq_pci_membase; + +int (*ltqpci_plat_dev_init)(struct pci_dev *dev) = NULL; + +/* Since the PCI REQ pins can be reused for other functionality, make it + possible to exclude those from interpretation by the PCI controller */ +static int ltq_pci_req_mask = 0xf; + +static int *ltq_pci_irq_map; + +struct pci_ops ltq_pci_ops = { + .read = ltq_pci_read_config_dword, + .write = ltq_pci_write_config_dword +}; + +static struct resource pci_io_resource = { + .name = "pci io space", + .start = LTQ_PCI_IO_BASE, + .end = LTQ_PCI_IO_BASE + LTQ_PCI_IO_SIZE - 1, + .flags = IORESOURCE_IO +}; + +static struct resource pci_mem_resource = { + .name = "pci memory space", + .start = LTQ_PCI_MEM_BASE, + .end = LTQ_PCI_MEM_BASE + LTQ_PCI_MEM_SIZE - 1, + .flags = IORESOURCE_MEM +}; + +static struct pci_controller ltq_pci_controller = { + .pci_ops = <q_pci_ops, + .mem_resource = &pci_mem_resource, + .mem_offset = 0x00000000UL, + .io_resource = &pci_io_resource, + .io_offset = 0x00000000UL, +}; + +int pcibios_plat_dev_init(struct pci_dev *dev) +{ + if (ltqpci_plat_dev_init) + return ltqpci_plat_dev_init(dev); + + return 0; +} + +static u32 ltq_calc_bar11mask(void) +{ + u32 mem, bar11mask; + + /* BAR11MASK value depends on available memory on system. */ + mem = num_physpages * PAGE_SIZE; + bar11mask = (0x0ffffff0 & ~((1 << (fls(mem) - 1)) - 1)) | 8; + + return bar11mask; +} + +static void ltq_pci_setup_gpio(int gpio) +{ + int i; + for (i = 0; i < ARRAY_SIZE(ltq_pci_gpio_map); i++) { + if (gpio & (1 << i)) { + ltq_gpio_request(ltq_pci_gpio_map[i].pin, + ltq_pci_gpio_map[i].alt0, + ltq_pci_gpio_map[i].alt1, + ltq_pci_gpio_map[i].dir, + ltq_pci_gpio_map[i].name); + } + } + ltq_gpio_request(21, 0, 0, 1, "pci-reset"); + ltq_pci_req_mask = (gpio >> PCI_REQ_SHIFT) & PCI_REQ_MASK; +} + +static int __devinit ltq_pci_startup(struct ltq_pci_data *conf) +{ + u32 temp_buffer; + + /* set clock to 33Mhz */ + ltq_cgu_w32(ltq_cgu_r32(LTQ_CGU_IFCCR) & ~0xf00000, LTQ_CGU_IFCCR); + ltq_cgu_w32(ltq_cgu_r32(LTQ_CGU_IFCCR) | 0x800000, LTQ_CGU_IFCCR); + + /* external or internal clock ? */ + if (conf->clock) { + ltq_cgu_w32(ltq_cgu_r32(LTQ_CGU_IFCCR) & ~(1 << 16), + LTQ_CGU_IFCCR); + ltq_cgu_w32((1 << 30), LTQ_CGU_PCICR); + } else { + ltq_cgu_w32(ltq_cgu_r32(LTQ_CGU_IFCCR) | (1 << 16), + LTQ_CGU_IFCCR); + ltq_cgu_w32((1 << 31) | (1 << 30), LTQ_CGU_PCICR); + } + + /* setup pci clock and gpis used by pci */ + ltq_pci_setup_gpio(conf->gpio); + + /* enable auto-switching between PCI and EBU */ + ltq_pci_w32(0xa, PCI_CR_CLK_CTRL); + + /* busy, i.e. configuration is not done, PCI access has to be retried */ + ltq_pci_w32(ltq_pci_r32(PCI_CR_PCI_MOD) & ~(1 << 24), PCI_CR_PCI_MOD); + wmb(); + /* BUS Master/IO/MEM access */ + ltq_pci_cfg_w32(ltq_pci_cfg_r32(PCI_CS_STS_CMD) | 7, PCI_CS_STS_CMD); + + /* enable external 2 PCI masters */ + temp_buffer = ltq_pci_r32(PCI_CR_PC_ARB); + temp_buffer &= (~(ltq_pci_req_mask << 16)); + /* enable internal arbiter */ + temp_buffer |= (1 << INTERNAL_ARB_ENABLE_BIT); + /* enable internal PCI master reqest */ + temp_buffer &= (~(3 << PCI_MASTER0_REQ_MASK_2BITS)); + + /* enable EBU request */ + temp_buffer &= (~(3 << PCI_MASTER1_REQ_MASK_2BITS)); + + /* enable all external masters request */ + temp_buffer &= (~(3 << PCI_MASTER2_REQ_MASK_2BITS)); + ltq_pci_w32(temp_buffer, PCI_CR_PC_ARB); + wmb(); + + /* setup BAR memory regions */ + ltq_pci_w32(0x18000000, PCI_CR_FCI_ADDR_MAP0); + ltq_pci_w32(0x18400000, PCI_CR_FCI_ADDR_MAP1); + ltq_pci_w32(0x18800000, PCI_CR_FCI_ADDR_MAP2); + ltq_pci_w32(0x18c00000, PCI_CR_FCI_ADDR_MAP3); + ltq_pci_w32(0x19000000, PCI_CR_FCI_ADDR_MAP4); + ltq_pci_w32(0x19400000, PCI_CR_FCI_ADDR_MAP5); + ltq_pci_w32(0x19800000, PCI_CR_FCI_ADDR_MAP6); + ltq_pci_w32(0x19c00000, PCI_CR_FCI_ADDR_MAP7); + ltq_pci_w32(0x1ae00000, PCI_CR_FCI_ADDR_MAP11hg); + ltq_pci_w32(ltq_calc_bar11mask(), PCI_CR_BAR11MASK); + ltq_pci_w32(0, PCI_CR_PCI_ADDR_MAP11); + ltq_pci_w32(0, PCI_CS_BASE_ADDR1); + /* both TX and RX endian swap are enabled */ + ltq_pci_w32(ltq_pci_r32(PCI_CR_PCI_EOI) | 3, PCI_CR_PCI_EOI); + wmb(); + ltq_pci_w32(ltq_pci_r32(PCI_CR_BAR12MASK) | 0x80000000, + PCI_CR_BAR12MASK); + ltq_pci_w32(ltq_pci_r32(PCI_CR_BAR13MASK) | 0x80000000, + PCI_CR_BAR13MASK); + /*use 8 dw burst length */ + ltq_pci_w32(0x303, PCI_CR_FCI_BURST_LENGTH); + ltq_pci_w32(ltq_pci_r32(PCI_CR_PCI_MOD) | (1 << 24), PCI_CR_PCI_MOD); + wmb(); + + /* setup irq line */ + ltq_ebu_w32(ltq_ebu_r32(LTQ_EBU_PCC_CON) | 0xc, LTQ_EBU_PCC_CON); + ltq_ebu_w32(ltq_ebu_r32(LTQ_EBU_PCC_IEN) | 0x10, LTQ_EBU_PCC_IEN); + + /* toggle reset pin */ + __gpio_set_value(21, 0); + wmb(); + mdelay(1); + __gpio_set_value(21, 1); + return 0; +} + +int __init pcibios_map_irq(const struct pci_dev *dev, u8 slot, u8 pin) +{ + if (ltq_pci_irq_map[slot]) + return ltq_pci_irq_map[slot]; + printk(KERN_ERR "lq_pci: trying to map irq for unknown slot %d\n", + slot); + + return 0; +} + +static int __devinit ltq_pci_probe(struct platform_device *pdev) +{ + struct ltq_pci_data *ltq_pci_data = + (struct ltq_pci_data *) pdev->dev.platform_data; + pci_probe_only = 0; + ltq_pci_irq_map = ltq_pci_data->irq; + ltq_pci_membase = ioremap_nocache(PCI_CR_BASE_ADDR, PCI_CR_SIZE); + ltq_pci_mapped_cfg = + ioremap_nocache(LTQ_PCI_CFG_BASE, LTQ_PCI_CFG_BASE); + ltq_pci_controller.io_map_base = + (unsigned long)ioremap(LTQ_PCI_IO_BASE, LTQ_PCI_IO_SIZE - 1); + ltq_pci_startup(ltq_pci_data); + register_pci_controller(<q_pci_controller); + + return 0; +} + +static struct platform_driver +ltq_pci_driver = { + .probe = ltq_pci_probe, + .driver = { + .name = "ltq_pci", + .owner = THIS_MODULE, + }, +}; + +int __init pcibios_init(void) +{ + int ret = platform_driver_register(<q_pci_driver); + if (ret) + printk(KERN_INFO "ltq_pci: Error registering platfom driver!"); + return ret; +} + +arch_initcall(pcibios_init); diff --git a/arch/mips/pci/pci-lantiq.h b/arch/mips/pci/pci-lantiq.h new file mode 100644 index 0000000..66bf6cd --- /dev/null +++ b/arch/mips/pci/pci-lantiq.h @@ -0,0 +1,18 @@ +/* + * 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) 2010 John Crispin + */ + +#ifndef _LTQ_PCI_H__ +#define _LTQ_PCI_H__ + +extern __iomem void *ltq_pci_mapped_cfg; +extern int ltq_pci_read_config_dword(struct pci_bus *bus, + unsigned int devfn, int where, int size, u32 *val); +extern int ltq_pci_write_config_dword(struct pci_bus *bus, + unsigned int devfn, int where, int size, u32 val); + +#endif -- cgit v0.10.2 From 3c5447390c3e1a462913e327a016a55cae501580 Mon Sep 17 00:00:00 2001 From: John Crispin Date: Tue, 12 Apr 2011 18:10:01 +0200 Subject: MIPS: Lantiq: Add NOR flash support This patch adds the driver/map for NOR devices attached to the SoC via the External Bus Unit (EBU). Signed-off-by: John Crispin Signed-off-by: Ralph Hempel Cc: David Woodhouse Cc: Daniel Schwierzeck Cc: linux-mips@linux-mips.org Cc: linux-mtd@lists.infradead.org Acked-by: Artem Bityutskiy Patchwork: https://patchwork.linux-mips.org/patch/2285/ Signed-off-by: Ralf Baechle diff --git a/drivers/mtd/maps/Kconfig b/drivers/mtd/maps/Kconfig index 44b1f46..5069111 100644 --- a/drivers/mtd/maps/Kconfig +++ b/drivers/mtd/maps/Kconfig @@ -260,6 +260,13 @@ config MTD_BCM963XX Support for parsing CFE image tag and creating MTD partitions on Broadcom BCM63xx boards. +config MTD_LANTIQ + tristate "Lantiq SoC NOR support" + depends on LANTIQ + select MTD_PARTITIONS + help + Support for NOR flash attached to the Lantiq SoC's External Bus Unit. + config MTD_DILNETPC tristate "CFI Flash device mapped on DIL/Net PC" depends on X86 && MTD_PARTITIONS && MTD_CFI_INTELEXT && BROKEN diff --git a/drivers/mtd/maps/Makefile b/drivers/mtd/maps/Makefile index 08533bd..6adf4c9 100644 --- a/drivers/mtd/maps/Makefile +++ b/drivers/mtd/maps/Makefile @@ -60,3 +60,4 @@ obj-$(CONFIG_MTD_VMU) += vmu-flash.o obj-$(CONFIG_MTD_GPIO_ADDR) += gpio-addr-flash.o obj-$(CONFIG_MTD_BCM963XX) += bcm963xx-flash.o obj-$(CONFIG_MTD_LATCH_ADDR) += latch-addr-flash.o +obj-$(CONFIG_MTD_LANTIQ) += lantiq-flash.o diff --git a/drivers/mtd/maps/lantiq-flash.c b/drivers/mtd/maps/lantiq-flash.c new file mode 100644 index 0000000..a90cabd --- /dev/null +++ b/drivers/mtd/maps/lantiq-flash.c @@ -0,0 +1,251 @@ +/* + * 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) 2004 Liu Peng Infineon IFAP DC COM CPE + * Copyright (C) 2010 John Crispin + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +/* + * The NOR flash is connected to the same external bus unit (EBU) as PCI. + * To make PCI work we need to enable the endianness swapping for the address + * written to the EBU. This endianness swapping works for PCI correctly but + * fails for attached NOR devices. To workaround this we need to use a complex + * map. The workaround involves swapping all addresses whilst probing the chip. + * Once probing is complete we stop swapping the addresses but swizzle the + * unlock addresses to ensure that access to the NOR device works correctly. + */ + +enum { + LTQ_NOR_PROBING, + LTQ_NOR_NORMAL +}; + +struct ltq_mtd { + struct resource *res; + struct mtd_info *mtd; + struct map_info *map; +}; + +static char ltq_map_name[] = "ltq_nor"; + +static map_word +ltq_read16(struct map_info *map, unsigned long adr) +{ + unsigned long flags; + map_word temp; + + if (map->map_priv_1 == LTQ_NOR_PROBING) + adr ^= 2; + spin_lock_irqsave(&ebu_lock, flags); + temp.x[0] = *(u16 *)(map->virt + adr); + spin_unlock_irqrestore(&ebu_lock, flags); + return temp; +} + +static void +ltq_write16(struct map_info *map, map_word d, unsigned long adr) +{ + unsigned long flags; + + if (map->map_priv_1 == LTQ_NOR_PROBING) + adr ^= 2; + spin_lock_irqsave(&ebu_lock, flags); + *(u16 *)(map->virt + adr) = d.x[0]; + spin_unlock_irqrestore(&ebu_lock, flags); +} + +/* + * The following 2 functions copy data between iomem and a cached memory + * section. As memcpy() makes use of pre-fetching we cannot use it here. + * The normal alternative of using memcpy_{to,from}io also makes use of + * memcpy() on MIPS so it is not applicable either. We are therefore stuck + * with having to use our own loop. + */ +static void +ltq_copy_from(struct map_info *map, void *to, + unsigned long from, ssize_t len) +{ + unsigned char *f = (unsigned char *)map->virt + from; + unsigned char *t = (unsigned char *)to; + unsigned long flags; + + spin_lock_irqsave(&ebu_lock, flags); + while (len--) + *t++ = *f++; + spin_unlock_irqrestore(&ebu_lock, flags); +} + +static void +ltq_copy_to(struct map_info *map, unsigned long to, + const void *from, ssize_t len) +{ + unsigned char *f = (unsigned char *)from; + unsigned char *t = (unsigned char *)map->virt + to; + unsigned long flags; + + spin_lock_irqsave(&ebu_lock, flags); + while (len--) + *t++ = *f++; + spin_unlock_irqrestore(&ebu_lock, flags); +} + +static const char const *part_probe_types[] = { "cmdlinepart", NULL }; + +static int __init +ltq_mtd_probe(struct platform_device *pdev) +{ + struct physmap_flash_data *ltq_mtd_data = dev_get_platdata(&pdev->dev); + struct ltq_mtd *ltq_mtd; + struct mtd_partition *parts; + struct resource *res; + int nr_parts = 0; + struct cfi_private *cfi; + int err; + + ltq_mtd = kzalloc(sizeof(struct ltq_mtd), GFP_KERNEL); + platform_set_drvdata(pdev, ltq_mtd); + + ltq_mtd->res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!ltq_mtd->res) { + dev_err(&pdev->dev, "failed to get memory resource"); + err = -ENOENT; + goto err_out; + } + + res = devm_request_mem_region(&pdev->dev, ltq_mtd->res->start, + resource_size(ltq_mtd->res), dev_name(&pdev->dev)); + if (!ltq_mtd->res) { + dev_err(&pdev->dev, "failed to request mem resource"); + err = -EBUSY; + goto err_out; + } + + ltq_mtd->map = kzalloc(sizeof(struct map_info), GFP_KERNEL); + ltq_mtd->map->phys = res->start; + ltq_mtd->map->size = resource_size(res); + ltq_mtd->map->virt = devm_ioremap_nocache(&pdev->dev, + ltq_mtd->map->phys, ltq_mtd->map->size); + if (!ltq_mtd->map->virt) { + dev_err(&pdev->dev, "failed to ioremap!\n"); + err = -ENOMEM; + goto err_free; + } + + ltq_mtd->map->name = ltq_map_name; + ltq_mtd->map->bankwidth = 2; + ltq_mtd->map->read = ltq_read16; + ltq_mtd->map->write = ltq_write16; + ltq_mtd->map->copy_from = ltq_copy_from; + ltq_mtd->map->copy_to = ltq_copy_to; + + ltq_mtd->map->map_priv_1 = LTQ_NOR_PROBING; + ltq_mtd->mtd = do_map_probe("cfi_probe", ltq_mtd->map); + ltq_mtd->map->map_priv_1 = LTQ_NOR_NORMAL; + + if (!ltq_mtd->mtd) { + dev_err(&pdev->dev, "probing failed\n"); + err = -ENXIO; + goto err_unmap; + } + + ltq_mtd->mtd->owner = THIS_MODULE; + + cfi = ltq_mtd->map->fldrv_priv; + cfi->addr_unlock1 ^= 1; + cfi->addr_unlock2 ^= 1; + + nr_parts = parse_mtd_partitions(ltq_mtd->mtd, + part_probe_types, &parts, 0); + if (nr_parts > 0) { + dev_info(&pdev->dev, + "using %d partitions from cmdline", nr_parts); + } else { + nr_parts = ltq_mtd_data->nr_parts; + parts = ltq_mtd_data->parts; + } + + err = add_mtd_partitions(ltq_mtd->mtd, parts, nr_parts); + if (err) { + dev_err(&pdev->dev, "failed to add partitions\n"); + goto err_destroy; + } + + return 0; + +err_destroy: + map_destroy(ltq_mtd->mtd); +err_unmap: + iounmap(ltq_mtd->map->virt); +err_free: + kfree(ltq_mtd->map); +err_out: + kfree(ltq_mtd); + return err; +} + +static int __devexit +ltq_mtd_remove(struct platform_device *pdev) +{ + struct ltq_mtd *ltq_mtd = platform_get_drvdata(pdev); + + if (ltq_mtd) { + if (ltq_mtd->mtd) { + del_mtd_partitions(ltq_mtd->mtd); + map_destroy(ltq_mtd->mtd); + } + if (ltq_mtd->map->virt) + iounmap(ltq_mtd->map->virt); + kfree(ltq_mtd->map); + kfree(ltq_mtd); + } + return 0; +} + +static struct platform_driver ltq_mtd_driver = { + .remove = __devexit_p(ltq_mtd_remove), + .driver = { + .name = "ltq_nor", + .owner = THIS_MODULE, + }, +}; + +static int __init +init_ltq_mtd(void) +{ + int ret = platform_driver_probe(<q_mtd_driver, ltq_mtd_probe); + + if (ret) + pr_err("ltq_nor: error registering platform driver"); + return ret; +} + +static void __exit +exit_ltq_mtd(void) +{ + platform_driver_unregister(<q_mtd_driver); +} + +module_init(init_ltq_mtd); +module_exit(exit_ltq_mtd); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("John Crispin "); +MODULE_DESCRIPTION("Lantiq SoC NOR"); -- cgit v0.10.2 From 24aff71fa8df0d6a73dab17f3f2285a24b8f658f Mon Sep 17 00:00:00 2001 From: John Crispin Date: Wed, 30 Mar 2011 09:27:53 +0200 Subject: MIPS: Lantiq: Add platform device support This patch adds the wrappers for registering our platform devices. Signed-off-by: John Crispin Signed-off-by: Ralph Hempel Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/2254/ Patchwork: https://patchwork.linux-mips.org/patch/2360/ Patchwork: https://patchwork.linux-mips.org/patch/2359/ Signed-off-by: Ralf Baechle diff --git a/arch/mips/lantiq/Makefile b/arch/mips/lantiq/Makefile index a268391..e5dae0e 100644 --- a/arch/mips/lantiq/Makefile +++ b/arch/mips/lantiq/Makefile @@ -4,7 +4,7 @@ # under the terms of the GNU General Public License version 2 as published # by the Free Software Foundation. -obj-y := irq.o setup.o clk.o prom.o +obj-y := irq.o setup.o clk.o prom.o devices.o obj-$(CONFIG_EARLY_PRINTK) += early_printk.o diff --git a/arch/mips/lantiq/devices.c b/arch/mips/lantiq/devices.c new file mode 100644 index 0000000..7b82c34 --- /dev/null +++ b/arch/mips/lantiq/devices.c @@ -0,0 +1,122 @@ +/* + * 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) 2010 John Crispin + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include + +#include "devices.h" + +/* nor flash */ +static struct resource ltq_nor_resource = { + .name = "nor", + .start = LTQ_FLASH_START, + .end = LTQ_FLASH_START + LTQ_FLASH_MAX - 1, + .flags = IORESOURCE_MEM, +}; + +static struct platform_device ltq_nor = { + .name = "ltq_nor", + .resource = <q_nor_resource, + .num_resources = 1, +}; + +void __init ltq_register_nor(struct physmap_flash_data *data) +{ + ltq_nor.dev.platform_data = data; + platform_device_register(<q_nor); +} + +/* watchdog */ +static struct resource ltq_wdt_resource = { + .name = "watchdog", + .start = LTQ_WDT_BASE_ADDR, + .end = LTQ_WDT_BASE_ADDR + LTQ_WDT_SIZE - 1, + .flags = IORESOURCE_MEM, +}; + +void __init ltq_register_wdt(void) +{ + platform_device_register_simple("ltq_wdt", 0, <q_wdt_resource, 1); +} + +/* asc ports */ +static struct resource ltq_asc0_resources[] = { + { + .name = "asc0", + .start = LTQ_ASC0_BASE_ADDR, + .end = LTQ_ASC0_BASE_ADDR + LTQ_ASC_SIZE - 1, + .flags = IORESOURCE_MEM, + }, + IRQ_RES(tx, LTQ_ASC_TIR(0)), + IRQ_RES(rx, LTQ_ASC_RIR(0)), + IRQ_RES(err, LTQ_ASC_EIR(0)), +}; + +static struct resource ltq_asc1_resources[] = { + { + .name = "asc1", + .start = LTQ_ASC1_BASE_ADDR, + .end = LTQ_ASC1_BASE_ADDR + LTQ_ASC_SIZE - 1, + .flags = IORESOURCE_MEM, + }, + IRQ_RES(tx, LTQ_ASC_TIR(1)), + IRQ_RES(rx, LTQ_ASC_RIR(1)), + IRQ_RES(err, LTQ_ASC_EIR(1)), +}; + +void __init ltq_register_asc(int port) +{ + switch (port) { + case 0: + platform_device_register_simple("ltq_asc", 0, + ltq_asc0_resources, ARRAY_SIZE(ltq_asc0_resources)); + break; + case 1: + platform_device_register_simple("ltq_asc", 1, + ltq_asc1_resources, ARRAY_SIZE(ltq_asc1_resources)); + break; + default: + break; + } +} + +#ifdef CONFIG_PCI +/* pci */ +static struct platform_device ltq_pci = { + .name = "ltq_pci", + .num_resources = 0, +}; + +void __init ltq_register_pci(struct ltq_pci_data *data) +{ + ltq_pci.dev.platform_data = data; + platform_device_register(<q_pci); +} +#else +void __init ltq_register_pci(struct ltq_pci_data *data) +{ + pr_err("kernel is compiled without PCI support\n"); +} +#endif diff --git a/arch/mips/lantiq/devices.h b/arch/mips/lantiq/devices.h new file mode 100644 index 0000000..2947bb1 --- /dev/null +++ b/arch/mips/lantiq/devices.h @@ -0,0 +1,23 @@ +/* + * 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) 2010 John Crispin + */ + +#ifndef _LTQ_DEVICES_H__ +#define _LTQ_DEVICES_H__ + +#include +#include + +#define IRQ_RES(resname, irq) \ + {.name = #resname, .start = (irq), .flags = IORESOURCE_IRQ} + +extern void ltq_register_nor(struct physmap_flash_data *data); +extern void ltq_register_wdt(void); +extern void ltq_register_asc(int port); +extern void ltq_register_pci(struct ltq_pci_data *data); + +#endif diff --git a/arch/mips/lantiq/xway/Makefile b/arch/mips/lantiq/xway/Makefile index 9c85ff9..74ce438 100644 --- a/arch/mips/lantiq/xway/Makefile +++ b/arch/mips/lantiq/xway/Makefile @@ -1,4 +1,4 @@ -obj-y := pmu.o ebu.o reset.o gpio.o +obj-y := pmu.o ebu.o reset.o gpio.o devices.o obj-$(CONFIG_SOC_XWAY) += clk-xway.o prom-xway.o obj-$(CONFIG_SOC_AMAZON_SE) += clk-ase.o prom-ase.o diff --git a/arch/mips/lantiq/xway/devices.c b/arch/mips/lantiq/xway/devices.c new file mode 100644 index 0000000..a71b3b5 --- /dev/null +++ b/arch/mips/lantiq/xway/devices.c @@ -0,0 +1,98 @@ +/* + * 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) 2010 John Crispin + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include + +#include "devices.h" + +/* gpio */ +static struct resource ltq_gpio_resource[] = { + { + .name = "gpio0", + .start = LTQ_GPIO0_BASE_ADDR, + .end = LTQ_GPIO0_BASE_ADDR + LTQ_GPIO_SIZE - 1, + .flags = IORESOURCE_MEM, + }, { + .name = "gpio1", + .start = LTQ_GPIO1_BASE_ADDR, + .end = LTQ_GPIO1_BASE_ADDR + LTQ_GPIO_SIZE - 1, + .flags = IORESOURCE_MEM, + }, { + .name = "gpio2", + .start = LTQ_GPIO2_BASE_ADDR, + .end = LTQ_GPIO2_BASE_ADDR + LTQ_GPIO_SIZE - 1, + .flags = IORESOURCE_MEM, + } +}; + +void __init ltq_register_gpio(void) +{ + platform_device_register_simple("ltq_gpio", 0, + <q_gpio_resource[0], 1); + platform_device_register_simple("ltq_gpio", 1, + <q_gpio_resource[1], 1); + + /* AR9 and VR9 have an extra gpio block */ + if (ltq_is_ar9() || ltq_is_vr9()) { + platform_device_register_simple("ltq_gpio", 2, + <q_gpio_resource[2], 1); + } +} + +/* serial to parallel conversion */ +static struct resource ltq_stp_resource = { + .name = "stp", + .start = LTQ_STP_BASE_ADDR, + .end = LTQ_STP_BASE_ADDR + LTQ_STP_SIZE - 1, + .flags = IORESOURCE_MEM, +}; + +void __init ltq_register_gpio_stp(void) +{ + platform_device_register_simple("ltq_stp", 0, <q_stp_resource, 1); +} + +/* asc ports - amazon se has its own serial mapping */ +static struct resource ltq_ase_asc_resources[] = { + { + .name = "asc0", + .start = LTQ_ASC1_BASE_ADDR, + .end = LTQ_ASC1_BASE_ADDR + LTQ_ASC_SIZE - 1, + .flags = IORESOURCE_MEM, + }, + IRQ_RES(tx, LTQ_ASC_ASE_TIR), + IRQ_RES(rx, LTQ_ASC_ASE_RIR), + IRQ_RES(err, LTQ_ASC_ASE_EIR), +}; + +void __init ltq_register_ase_asc(void) +{ + platform_device_register_simple("ltq_asc", 0, + ltq_ase_asc_resources, ARRAY_SIZE(ltq_ase_asc_resources)); +} diff --git a/arch/mips/lantiq/xway/devices.h b/arch/mips/lantiq/xway/devices.h new file mode 100644 index 0000000..51f56b5 --- /dev/null +++ b/arch/mips/lantiq/xway/devices.h @@ -0,0 +1,18 @@ +/* + * 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) 2010 John Crispin + */ + +#ifndef _LTQ_DEVICES_XWAY_H__ +#define _LTQ_DEVICES_XWAY_H__ + +#include "../devices.h" + +extern void ltq_register_gpio(void); +extern void ltq_register_gpio_stp(void); +extern void ltq_register_ase_asc(void); + +#endif -- cgit v0.10.2 From a053ac17024561f3a2fd02424b5f92823282b5ad Mon Sep 17 00:00:00 2001 From: John Crispin Date: Wed, 30 Mar 2011 09:27:54 +0200 Subject: MIPS: Lantiq: Add mips_machine support This patch adds support for Gabor's mips_machine patch. Signed-off-by: John Crispin Signed-off-by: Ralph Hempel Cc: Gabor Juhos Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/2251/ Patchwork: https://patchwork.linux-mips.org/patch/2358/ Signed-off-by: Ralf Baechle diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig index b3b4999..2d1cf97 100644 --- a/arch/mips/Kconfig +++ b/arch/mips/Kconfig @@ -228,6 +228,7 @@ config LANTIQ select SWAP_IO_SPACE select BOOT_RAW select HAVE_CLK + select MIPS_MACHINE config LASAT bool "LASAT Networks platforms" diff --git a/arch/mips/lantiq/machtypes.h b/arch/mips/lantiq/machtypes.h new file mode 100644 index 0000000..ffcacfc --- /dev/null +++ b/arch/mips/lantiq/machtypes.h @@ -0,0 +1,18 @@ +/* + * 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) 2010 John Crispin + */ + +#ifndef _LANTIQ_MACH_H__ +#define _LANTIQ_MACH_H__ + +#include + +enum lantiq_mach_type { + LTQ_MACH_GENERIC = 0, +}; + +#endif diff --git a/arch/mips/lantiq/prom.h b/arch/mips/lantiq/prom.h index 4165ad1..b4229d9 100644 --- a/arch/mips/lantiq/prom.h +++ b/arch/mips/lantiq/prom.h @@ -20,5 +20,6 @@ struct ltq_soc_info { }; extern void ltq_soc_detect(struct ltq_soc_info *i); +extern void ltq_soc_setup(void); #endif diff --git a/arch/mips/lantiq/setup.c b/arch/mips/lantiq/setup.c index 79a2b0c..9b8af77 100644 --- a/arch/mips/lantiq/setup.c +++ b/arch/mips/lantiq/setup.c @@ -14,6 +14,10 @@ #include +#include "machtypes.h" +#include "devices.h" +#include "prom.h" + void __init plat_mem_setup(void) { /* assume 16M as default incase uboot fails to pass proper ramsize */ @@ -39,3 +43,24 @@ void __init plat_mem_setup(void) memsize *= 1024 * 1024; add_memory_region(0x00000000, memsize, BOOT_MEM_RAM); } + +static int __init +lantiq_setup(void) +{ + ltq_soc_setup(); + mips_machine_setup(); + return 0; +} + +arch_initcall(lantiq_setup); + +static void __init +lantiq_generic_init(void) +{ + /* Nothing to do */ +} + +MIPS_MACHINE(LTQ_MACH_GENERIC, + "Generic", + "Generic Lantiq based board", + lantiq_generic_init); diff --git a/arch/mips/lantiq/xway/Makefile b/arch/mips/lantiq/xway/Makefile index 74ce438..8c06a97 100644 --- a/arch/mips/lantiq/xway/Makefile +++ b/arch/mips/lantiq/xway/Makefile @@ -1,4 +1,4 @@ obj-y := pmu.o ebu.o reset.o gpio.o devices.o -obj-$(CONFIG_SOC_XWAY) += clk-xway.o prom-xway.o -obj-$(CONFIG_SOC_AMAZON_SE) += clk-ase.o prom-ase.o +obj-$(CONFIG_SOC_XWAY) += clk-xway.o prom-xway.o setup-xway.o +obj-$(CONFIG_SOC_AMAZON_SE) += clk-ase.o prom-ase.o setup-ase.o diff --git a/arch/mips/lantiq/xway/setup-ase.c b/arch/mips/lantiq/xway/setup-ase.c new file mode 100644 index 0000000..f6f3267 --- /dev/null +++ b/arch/mips/lantiq/xway/setup-ase.c @@ -0,0 +1,19 @@ +/* + * 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 John Crispin + */ + +#include + +#include "../prom.h" +#include "devices.h" + +void __init ltq_soc_setup(void) +{ + ltq_register_ase_asc(); + ltq_register_gpio(); + ltq_register_wdt(); +} diff --git a/arch/mips/lantiq/xway/setup-xway.c b/arch/mips/lantiq/xway/setup-xway.c new file mode 100644 index 0000000..c292f64 --- /dev/null +++ b/arch/mips/lantiq/xway/setup-xway.c @@ -0,0 +1,20 @@ +/* + * 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 John Crispin + */ + +#include + +#include "../prom.h" +#include "devices.h" + +void __init ltq_soc_setup(void) +{ + ltq_register_asc(0); + ltq_register_asc(1); + ltq_register_gpio(); + ltq_register_wdt(); +} -- cgit v0.10.2 From 973c32eb7f2d5c45d0e68b0083ead9ee763d9a6f Mon Sep 17 00:00:00 2001 From: John Crispin Date: Wed, 30 Mar 2011 09:27:55 +0200 Subject: MIPS: Lantiq: Add machtypes for lantiq eval kits This patch adds mach specific code for the Lantiq EASY50712/50601 evaluation boards Signed-off-by: John Crispin Signed-off-by: Ralph Hempel Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/2255/ Patchwork: https://patchwork.linux-mips.org/patch/2361/ Signed-off-by: Ralf Baechle diff --git a/arch/mips/lantiq/Kconfig b/arch/mips/lantiq/Kconfig index 2780461..3fccf21 100644 --- a/arch/mips/lantiq/Kconfig +++ b/arch/mips/lantiq/Kconfig @@ -18,4 +18,6 @@ config SOC_XWAY select HW_HAS_PCI endchoice +source "arch/mips/lantiq/xway/Kconfig" + endif diff --git a/arch/mips/lantiq/machtypes.h b/arch/mips/lantiq/machtypes.h index ffcacfc..7e01b8c 100644 --- a/arch/mips/lantiq/machtypes.h +++ b/arch/mips/lantiq/machtypes.h @@ -13,6 +13,8 @@ enum lantiq_mach_type { LTQ_MACH_GENERIC = 0, + LTQ_MACH_EASY50712, /* Danube evaluation board */ + LTQ_MACH_EASY50601, /* Amazon SE evaluation board */ }; #endif diff --git a/arch/mips/lantiq/xway/Kconfig b/arch/mips/lantiq/xway/Kconfig new file mode 100644 index 0000000..2b857de --- /dev/null +++ b/arch/mips/lantiq/xway/Kconfig @@ -0,0 +1,23 @@ +if SOC_XWAY + +menu "MIPS Machine" + +config LANTIQ_MACH_EASY50712 + bool "Easy50712 - Danube" + default y + +endmenu + +endif + +if SOC_AMAZON_SE + +menu "MIPS Machine" + +config LANTIQ_MACH_EASY50601 + bool "Easy50601 - Amazon SE" + default y + +endmenu + +endif diff --git a/arch/mips/lantiq/xway/Makefile b/arch/mips/lantiq/xway/Makefile index 8c06a97..b1d3640 100644 --- a/arch/mips/lantiq/xway/Makefile +++ b/arch/mips/lantiq/xway/Makefile @@ -2,3 +2,6 @@ obj-y := pmu.o ebu.o reset.o gpio.o devices.o obj-$(CONFIG_SOC_XWAY) += clk-xway.o prom-xway.o setup-xway.o obj-$(CONFIG_SOC_AMAZON_SE) += clk-ase.o prom-ase.o setup-ase.o + +obj-$(CONFIG_LANTIQ_MACH_EASY50712) += mach-easy50712.o +obj-$(CONFIG_LANTIQ_MACH_EASY50601) += mach-easy50601.o diff --git a/arch/mips/lantiq/xway/mach-easy50601.c b/arch/mips/lantiq/xway/mach-easy50601.c new file mode 100644 index 0000000..d5aaf63 --- /dev/null +++ b/arch/mips/lantiq/xway/mach-easy50601.c @@ -0,0 +1,57 @@ +/* + * 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) 2010 John Crispin + */ + +#include +#include +#include +#include +#include +#include + +#include + +#include "../machtypes.h" +#include "devices.h" + +static struct mtd_partition easy50601_partitions[] = { + { + .name = "uboot", + .offset = 0x0, + .size = 0x10000, + }, + { + .name = "uboot_env", + .offset = 0x10000, + .size = 0x10000, + }, + { + .name = "linux", + .offset = 0x20000, + .size = 0xE0000, + }, + { + .name = "rootfs", + .offset = 0x100000, + .size = 0x300000, + }, +}; + +static struct physmap_flash_data easy50601_flash_data = { + .nr_parts = ARRAY_SIZE(easy50601_partitions), + .parts = easy50601_partitions, +}; + +static void __init easy50601_init(void) +{ + ltq_register_nor(&easy50601_flash_data); +} + +MIPS_MACHINE(LTQ_MACH_EASY50601, + "EASY50601", + "EASY50601 Eval Board", + easy50601_init); diff --git a/arch/mips/lantiq/xway/mach-easy50712.c b/arch/mips/lantiq/xway/mach-easy50712.c new file mode 100644 index 0000000..e5e7e09 --- /dev/null +++ b/arch/mips/lantiq/xway/mach-easy50712.c @@ -0,0 +1,68 @@ +/* + * 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) 2010 John Crispin + */ + +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "../machtypes.h" +#include "devices.h" + +static struct mtd_partition easy50712_partitions[] = { + { + .name = "uboot", + .offset = 0x0, + .size = 0x10000, + }, + { + .name = "uboot_env", + .offset = 0x10000, + .size = 0x10000, + }, + { + .name = "linux", + .offset = 0x20000, + .size = 0xe0000, + }, + { + .name = "rootfs", + .offset = 0x100000, + .size = 0x300000, + }, +}; + +static struct physmap_flash_data easy50712_flash_data = { + .nr_parts = ARRAY_SIZE(easy50712_partitions), + .parts = easy50712_partitions, +}; + +static struct ltq_pci_data ltq_pci_data = { + .clock = PCI_CLOCK_INT, + .gpio = PCI_GNT1 | PCI_REQ1, + .irq = { + [14] = INT_NUM_IM0_IRL0 + 22, + }, +}; + +static void __init easy50712_init(void) +{ + ltq_register_gpio_stp(); + ltq_register_nor(&easy50712_flash_data); + ltq_register_pci(<q_pci_data); +} + +MIPS_MACHINE(LTQ_MACH_EASY50712, + "EASY50712", + "EASY50712 Eval Board", + easy50712_init); -- cgit v0.10.2 From 935c500c377d8e414bbe08e0e169f6c85d2a4273 Mon Sep 17 00:00:00 2001 From: John Crispin Date: Wed, 30 Mar 2011 09:27:56 +0200 Subject: MIPS: Lantiq: Add more gpio drivers The XWAY family allows to extend the number of gpios by using shift registers or latches. This patch adds the 2 drivers needed for this. The extended gpios are output only. [ralf@linux-mips.org: Fixed ltq_stp_probe section() attributes.] Signed-off-by: John Crispin Signed-off-by: Ralph Hempel Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/2258/ Signed-off-by: Ralf Baechle diff --git a/arch/mips/lantiq/xway/Makefile b/arch/mips/lantiq/xway/Makefile index b1d3640..6b5e07e 100644 --- a/arch/mips/lantiq/xway/Makefile +++ b/arch/mips/lantiq/xway/Makefile @@ -1,4 +1,4 @@ -obj-y := pmu.o ebu.o reset.o gpio.o devices.o +obj-y := pmu.o ebu.o reset.o gpio.o gpio_stp.o gpio_ebu.o devices.o obj-$(CONFIG_SOC_XWAY) += clk-xway.o prom-xway.o setup-xway.o obj-$(CONFIG_SOC_AMAZON_SE) += clk-ase.o prom-ase.o setup-ase.o diff --git a/arch/mips/lantiq/xway/gpio_ebu.c b/arch/mips/lantiq/xway/gpio_ebu.c new file mode 100644 index 0000000..a479355 --- /dev/null +++ b/arch/mips/lantiq/xway/gpio_ebu.c @@ -0,0 +1,126 @@ +/* + * 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) 2010 John Crispin + */ + +#include +#include +#include +#include +#include +#include +#include + +#include + +/* + * By attaching hardware latches to the EBU it is possible to create output + * only gpios. This driver configures a special memory address, which when + * written to outputs 16 bit to the latches. + */ + +#define LTQ_EBU_BUSCON 0x1e7ff /* 16 bit access, slowest timing */ +#define LTQ_EBU_WP 0x80000000 /* write protect bit */ + +/* we keep a shadow value of the last value written to the ebu */ +static int ltq_ebu_gpio_shadow = 0x0; +static void __iomem *ltq_ebu_gpio_membase; + +static void ltq_ebu_apply(void) +{ + unsigned long flags; + + spin_lock_irqsave(&ebu_lock, flags); + ltq_ebu_w32(LTQ_EBU_BUSCON, LTQ_EBU_BUSCON1); + *((__u16 *)ltq_ebu_gpio_membase) = ltq_ebu_gpio_shadow; + ltq_ebu_w32(LTQ_EBU_BUSCON | LTQ_EBU_WP, LTQ_EBU_BUSCON1); + spin_unlock_irqrestore(&ebu_lock, flags); +} + +static void ltq_ebu_set(struct gpio_chip *chip, unsigned offset, int value) +{ + if (value) + ltq_ebu_gpio_shadow |= (1 << offset); + else + ltq_ebu_gpio_shadow &= ~(1 << offset); + ltq_ebu_apply(); +} + +static int ltq_ebu_direction_output(struct gpio_chip *chip, unsigned offset, + int value) +{ + ltq_ebu_set(chip, offset, value); + + return 0; +} + +static struct gpio_chip ltq_ebu_chip = { + .label = "ltq_ebu", + .direction_output = ltq_ebu_direction_output, + .set = ltq_ebu_set, + .base = 72, + .ngpio = 16, + .can_sleep = 1, + .owner = THIS_MODULE, +}; + +static int ltq_ebu_probe(struct platform_device *pdev) +{ + int ret = 0; + struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + + if (!res) { + dev_err(&pdev->dev, "failed to get memory resource\n"); + return -ENOENT; + } + + res = devm_request_mem_region(&pdev->dev, res->start, + resource_size(res), dev_name(&pdev->dev)); + if (!res) { + dev_err(&pdev->dev, "failed to request memory resource\n"); + return -EBUSY; + } + + ltq_ebu_gpio_membase = devm_ioremap_nocache(&pdev->dev, res->start, + resource_size(res)); + if (!ltq_ebu_gpio_membase) { + dev_err(&pdev->dev, "Failed to ioremap mem region\n"); + return -ENOMEM; + } + + /* grab the default shadow value passed form the platform code */ + ltq_ebu_gpio_shadow = (unsigned int) pdev->dev.platform_data; + + /* tell the ebu controller which memory address we will be using */ + ltq_ebu_w32(pdev->resource->start | 0x1, LTQ_EBU_ADDRSEL1); + + /* write protect the region */ + ltq_ebu_w32(LTQ_EBU_BUSCON | LTQ_EBU_WP, LTQ_EBU_BUSCON1); + + ret = gpiochip_add(<q_ebu_chip); + if (!ret) + ltq_ebu_apply(); + return ret; +} + +static struct platform_driver ltq_ebu_driver = { + .probe = ltq_ebu_probe, + .driver = { + .name = "ltq_ebu", + .owner = THIS_MODULE, + }, +}; + +static int __init ltq_ebu_init(void) +{ + int ret = platform_driver_register(<q_ebu_driver); + + if (ret) + pr_info("ltq_ebu : Error registering platfom driver!"); + return ret; +} + +postcore_initcall(ltq_ebu_init); diff --git a/arch/mips/lantiq/xway/gpio_stp.c b/arch/mips/lantiq/xway/gpio_stp.c new file mode 100644 index 0000000..67d59d6 --- /dev/null +++ b/arch/mips/lantiq/xway/gpio_stp.c @@ -0,0 +1,157 @@ +/* + * 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) 2007 John Crispin + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#define LTQ_STP_CON0 0x00 +#define LTQ_STP_CON1 0x04 +#define LTQ_STP_CPU0 0x08 +#define LTQ_STP_CPU1 0x0C +#define LTQ_STP_AR 0x10 + +#define LTQ_STP_CON_SWU (1 << 31) +#define LTQ_STP_2HZ 0 +#define LTQ_STP_4HZ (1 << 23) +#define LTQ_STP_8HZ (2 << 23) +#define LTQ_STP_10HZ (3 << 23) +#define LTQ_STP_SPEED_MASK (0xf << 23) +#define LTQ_STP_UPD_FPI (1 << 31) +#define LTQ_STP_UPD_MASK (3 << 30) +#define LTQ_STP_ADSL_SRC (3 << 24) + +#define LTQ_STP_GROUP0 (1 << 0) + +#define LTQ_STP_RISING 0 +#define LTQ_STP_FALLING (1 << 26) +#define LTQ_STP_EDGE_MASK (1 << 26) + +#define ltq_stp_r32(reg) __raw_readl(ltq_stp_membase + reg) +#define ltq_stp_w32(val, reg) __raw_writel(val, ltq_stp_membase + reg) +#define ltq_stp_w32_mask(clear, set, reg) \ + ltq_w32((ltq_r32(ltq_stp_membase + reg) & ~(clear)) | (set), \ + ltq_stp_membase + (reg)) + +static int ltq_stp_shadow = 0xffff; +static void __iomem *ltq_stp_membase; + +static void ltq_stp_set(struct gpio_chip *chip, unsigned offset, int value) +{ + if (value) + ltq_stp_shadow |= (1 << offset); + else + ltq_stp_shadow &= ~(1 << offset); + ltq_stp_w32(ltq_stp_shadow, LTQ_STP_CPU0); +} + +static int ltq_stp_direction_output(struct gpio_chip *chip, unsigned offset, + int value) +{ + ltq_stp_set(chip, offset, value); + + return 0; +} + +static struct gpio_chip ltq_stp_chip = { + .label = "ltq_stp", + .direction_output = ltq_stp_direction_output, + .set = ltq_stp_set, + .base = 48, + .ngpio = 24, + .can_sleep = 1, + .owner = THIS_MODULE, +}; + +static int ltq_stp_hw_init(void) +{ + /* the 3 pins used to control the external stp */ + ltq_gpio_request(4, 1, 0, 1, "stp-st"); + ltq_gpio_request(5, 1, 0, 1, "stp-d"); + ltq_gpio_request(6, 1, 0, 1, "stp-sh"); + + /* sane defaults */ + ltq_stp_w32(0, LTQ_STP_AR); + ltq_stp_w32(0, LTQ_STP_CPU0); + ltq_stp_w32(0, LTQ_STP_CPU1); + ltq_stp_w32(LTQ_STP_CON_SWU, LTQ_STP_CON0); + ltq_stp_w32(0, LTQ_STP_CON1); + + /* rising or falling edge */ + ltq_stp_w32_mask(LTQ_STP_EDGE_MASK, LTQ_STP_FALLING, LTQ_STP_CON0); + + /* per default stp 15-0 are set */ + ltq_stp_w32_mask(0, LTQ_STP_GROUP0, LTQ_STP_CON1); + + /* stp are update periodically by the FPI bus */ + ltq_stp_w32_mask(LTQ_STP_UPD_MASK, LTQ_STP_UPD_FPI, LTQ_STP_CON1); + + /* set stp update speed */ + ltq_stp_w32_mask(LTQ_STP_SPEED_MASK, LTQ_STP_8HZ, LTQ_STP_CON1); + + /* tell the hardware that pin (led) 0 and 1 are controlled + * by the dsl arc + */ + ltq_stp_w32_mask(0, LTQ_STP_ADSL_SRC, LTQ_STP_CON0); + + ltq_pmu_enable(PMU_LED); + return 0; +} + +static int __devinit ltq_stp_probe(struct platform_device *pdev) +{ + struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + int ret = 0; + + if (!res) + return -ENOENT; + res = devm_request_mem_region(&pdev->dev, res->start, + resource_size(res), dev_name(&pdev->dev)); + if (!res) { + dev_err(&pdev->dev, "failed to request STP memory\n"); + return -EBUSY; + } + ltq_stp_membase = devm_ioremap_nocache(&pdev->dev, res->start, + resource_size(res)); + if (!ltq_stp_membase) { + dev_err(&pdev->dev, "failed to remap STP memory\n"); + return -ENOMEM; + } + ret = gpiochip_add(<q_stp_chip); + if (!ret) + ret = ltq_stp_hw_init(); + + return ret; +} + +static struct platform_driver ltq_stp_driver = { + .probe = ltq_stp_probe, + .driver = { + .name = "ltq_stp", + .owner = THIS_MODULE, + }, +}; + +int __init ltq_stp_init(void) +{ + int ret = platform_driver_register(<q_stp_driver); + + if (ret) + pr_info("ltq_stp: error registering platfom driver"); + return ret; +} + +postcore_initcall(ltq_stp_init); -- cgit v0.10.2 From 2f0fc4159a6abc20b13569522c545150b99485cf Mon Sep 17 00:00:00 2001 From: John Crispin Date: Tue, 5 Apr 2011 14:10:57 +0200 Subject: SERIAL: Lantiq: Add driver for MIPS Lantiq SOCs. Signed-off-by: John Crispin Signed-off-by: Ralph Hempel Signed-off-by: Felix Fietkau Cc: alan@lxorguk.ukuu.org.uk Cc: linux-mips@linux-mips.org Cc: linux-serial@vger.kernel.org Patchwork: https://patchwork.linux-mips.org/patch/2269/ Acked-by: Alan Cox Signed-off-by: Ralf Baechle diff --git a/drivers/tty/serial/Kconfig b/drivers/tty/serial/Kconfig index 80484af..b1f0f83 100644 --- a/drivers/tty/serial/Kconfig +++ b/drivers/tty/serial/Kconfig @@ -1391,6 +1391,14 @@ config SERIAL_OF_PLATFORM_NWPSERIAL_CONSOLE help Support for Console on the NWP serial ports. +config SERIAL_LANTIQ + bool "Lantiq serial driver" + depends on LANTIQ + select SERIAL_CORE + select SERIAL_CORE_CONSOLE + help + Support for console and UART on Lantiq SoCs. + config SERIAL_QE tristate "Freescale QUICC Engine serial port support" depends on QUICC_ENGINE diff --git a/drivers/tty/serial/Makefile b/drivers/tty/serial/Makefile index fee0690..3527604 100644 --- a/drivers/tty/serial/Makefile +++ b/drivers/tty/serial/Makefile @@ -94,3 +94,4 @@ obj-$(CONFIG_SERIAL_IFX6X60) += ifx6x60.o obj-$(CONFIG_SERIAL_PCH_UART) += pch_uart.o obj-$(CONFIG_SERIAL_MSM_SMD) += msm_smd_tty.o obj-$(CONFIG_SERIAL_MXS_AUART) += mxs-auart.o +obj-$(CONFIG_SERIAL_LANTIQ) += lantiq.o diff --git a/drivers/tty/serial/lantiq.c b/drivers/tty/serial/lantiq.c new file mode 100644 index 0000000..58cf279e --- /dev/null +++ b/drivers/tty/serial/lantiq.c @@ -0,0 +1,756 @@ +/* + * Based on drivers/char/serial.c, by Linus Torvalds, Theodore Ts'o. + * + * 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. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Copyright (C) 2004 Infineon IFAP DC COM CPE + * Copyright (C) 2007 Felix Fietkau + * Copyright (C) 2007 John Crispin + * Copyright (C) 2010 Thomas Langer, + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#define PORT_LTQ_ASC 111 +#define MAXPORTS 2 +#define UART_DUMMY_UER_RX 1 +#define DRVNAME "ltq_asc" +#ifdef __BIG_ENDIAN +#define LTQ_ASC_TBUF (0x0020 + 3) +#define LTQ_ASC_RBUF (0x0024 + 3) +#else +#define LTQ_ASC_TBUF 0x0020 +#define LTQ_ASC_RBUF 0x0024 +#endif +#define LTQ_ASC_FSTAT 0x0048 +#define LTQ_ASC_WHBSTATE 0x0018 +#define LTQ_ASC_STATE 0x0014 +#define LTQ_ASC_IRNCR 0x00F8 +#define LTQ_ASC_CLC 0x0000 +#define LTQ_ASC_ID 0x0008 +#define LTQ_ASC_PISEL 0x0004 +#define LTQ_ASC_TXFCON 0x0044 +#define LTQ_ASC_RXFCON 0x0040 +#define LTQ_ASC_CON 0x0010 +#define LTQ_ASC_BG 0x0050 +#define LTQ_ASC_IRNREN 0x00F4 + +#define ASC_IRNREN_TX 0x1 +#define ASC_IRNREN_RX 0x2 +#define ASC_IRNREN_ERR 0x4 +#define ASC_IRNREN_TX_BUF 0x8 +#define ASC_IRNCR_TIR 0x1 +#define ASC_IRNCR_RIR 0x2 +#define ASC_IRNCR_EIR 0x4 + +#define ASCOPT_CSIZE 0x3 +#define TXFIFO_FL 1 +#define RXFIFO_FL 1 +#define ASCCLC_DISS 0x2 +#define ASCCLC_RMCMASK 0x0000FF00 +#define ASCCLC_RMCOFFSET 8 +#define ASCCON_M_8ASYNC 0x0 +#define ASCCON_M_7ASYNC 0x2 +#define ASCCON_ODD 0x00000020 +#define ASCCON_STP 0x00000080 +#define ASCCON_BRS 0x00000100 +#define ASCCON_FDE 0x00000200 +#define ASCCON_R 0x00008000 +#define ASCCON_FEN 0x00020000 +#define ASCCON_ROEN 0x00080000 +#define ASCCON_TOEN 0x00100000 +#define ASCSTATE_PE 0x00010000 +#define ASCSTATE_FE 0x00020000 +#define ASCSTATE_ROE 0x00080000 +#define ASCSTATE_ANY (ASCSTATE_ROE|ASCSTATE_PE|ASCSTATE_FE) +#define ASCWHBSTATE_CLRREN 0x00000001 +#define ASCWHBSTATE_SETREN 0x00000002 +#define ASCWHBSTATE_CLRPE 0x00000004 +#define ASCWHBSTATE_CLRFE 0x00000008 +#define ASCWHBSTATE_CLRROE 0x00000020 +#define ASCTXFCON_TXFEN 0x0001 +#define ASCTXFCON_TXFFLU 0x0002 +#define ASCTXFCON_TXFITLMASK 0x3F00 +#define ASCTXFCON_TXFITLOFF 8 +#define ASCRXFCON_RXFEN 0x0001 +#define ASCRXFCON_RXFFLU 0x0002 +#define ASCRXFCON_RXFITLMASK 0x3F00 +#define ASCRXFCON_RXFITLOFF 8 +#define ASCFSTAT_RXFFLMASK 0x003F +#define ASCFSTAT_TXFFLMASK 0x3F00 +#define ASCFSTAT_TXFREEMASK 0x3F000000 +#define ASCFSTAT_TXFREEOFF 24 + +static void lqasc_tx_chars(struct uart_port *port); +static struct ltq_uart_port *lqasc_port[MAXPORTS]; +static struct uart_driver lqasc_reg; +static DEFINE_SPINLOCK(ltq_asc_lock); + +struct ltq_uart_port { + struct uart_port port; + struct clk *clk; + unsigned int tx_irq; + unsigned int rx_irq; + unsigned int err_irq; +}; + +static inline struct +ltq_uart_port *to_ltq_uart_port(struct uart_port *port) +{ + return container_of(port, struct ltq_uart_port, port); +} + +static void +lqasc_stop_tx(struct uart_port *port) +{ + return; +} + +static void +lqasc_start_tx(struct uart_port *port) +{ + unsigned long flags; + spin_lock_irqsave(<q_asc_lock, flags); + lqasc_tx_chars(port); + spin_unlock_irqrestore(<q_asc_lock, flags); + return; +} + +static void +lqasc_stop_rx(struct uart_port *port) +{ + ltq_w32(ASCWHBSTATE_CLRREN, port->membase + LTQ_ASC_WHBSTATE); +} + +static void +lqasc_enable_ms(struct uart_port *port) +{ +} + +static int +lqasc_rx_chars(struct uart_port *port) +{ + struct tty_struct *tty = tty_port_tty_get(&port->state->port); + unsigned int ch = 0, rsr = 0, fifocnt; + + if (!tty) { + dev_dbg(port->dev, "%s:tty is busy now", __func__); + return -EBUSY; + } + fifocnt = + ltq_r32(port->membase + LTQ_ASC_FSTAT) & ASCFSTAT_RXFFLMASK; + while (fifocnt--) { + u8 flag = TTY_NORMAL; + ch = ltq_r8(port->membase + LTQ_ASC_RBUF); + rsr = (ltq_r32(port->membase + LTQ_ASC_STATE) + & ASCSTATE_ANY) | UART_DUMMY_UER_RX; + tty_flip_buffer_push(tty); + port->icount.rx++; + + /* + * Note that the error handling code is + * out of the main execution path + */ + if (rsr & ASCSTATE_ANY) { + if (rsr & ASCSTATE_PE) { + port->icount.parity++; + ltq_w32_mask(0, ASCWHBSTATE_CLRPE, + port->membase + LTQ_ASC_WHBSTATE); + } else if (rsr & ASCSTATE_FE) { + port->icount.frame++; + ltq_w32_mask(0, ASCWHBSTATE_CLRFE, + port->membase + LTQ_ASC_WHBSTATE); + } + if (rsr & ASCSTATE_ROE) { + port->icount.overrun++; + ltq_w32_mask(0, ASCWHBSTATE_CLRROE, + port->membase + LTQ_ASC_WHBSTATE); + } + + rsr &= port->read_status_mask; + + if (rsr & ASCSTATE_PE) + flag = TTY_PARITY; + else if (rsr & ASCSTATE_FE) + flag = TTY_FRAME; + } + + if ((rsr & port->ignore_status_mask) == 0) + tty_insert_flip_char(tty, ch, flag); + + if (rsr & ASCSTATE_ROE) + /* + * Overrun is special, since it's reported + * immediately, and doesn't affect the current + * character + */ + tty_insert_flip_char(tty, 0, TTY_OVERRUN); + } + if (ch != 0) + tty_flip_buffer_push(tty); + tty_kref_put(tty); + return 0; +} + +static void +lqasc_tx_chars(struct uart_port *port) +{ + struct circ_buf *xmit = &port->state->xmit; + if (uart_tx_stopped(port)) { + lqasc_stop_tx(port); + return; + } + + while (((ltq_r32(port->membase + LTQ_ASC_FSTAT) & + ASCFSTAT_TXFREEMASK) >> ASCFSTAT_TXFREEOFF) != 0) { + if (port->x_char) { + ltq_w8(port->x_char, port->membase + LTQ_ASC_TBUF); + port->icount.tx++; + port->x_char = 0; + continue; + } + + if (uart_circ_empty(xmit)) + break; + + ltq_w8(port->state->xmit.buf[port->state->xmit.tail], + port->membase + LTQ_ASC_TBUF); + xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); + port->icount.tx++; + } + + if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) + uart_write_wakeup(port); +} + +static irqreturn_t +lqasc_tx_int(int irq, void *_port) +{ + unsigned long flags; + struct uart_port *port = (struct uart_port *)_port; + spin_lock_irqsave(<q_asc_lock, flags); + ltq_w32(ASC_IRNCR_TIR, port->membase + LTQ_ASC_IRNCR); + spin_unlock_irqrestore(<q_asc_lock, flags); + lqasc_start_tx(port); + return IRQ_HANDLED; +} + +static irqreturn_t +lqasc_err_int(int irq, void *_port) +{ + unsigned long flags; + struct uart_port *port = (struct uart_port *)_port; + spin_lock_irqsave(<q_asc_lock, flags); + /* clear any pending interrupts */ + ltq_w32_mask(0, ASCWHBSTATE_CLRPE | ASCWHBSTATE_CLRFE | + ASCWHBSTATE_CLRROE, port->membase + LTQ_ASC_WHBSTATE); + spin_unlock_irqrestore(<q_asc_lock, flags); + return IRQ_HANDLED; +} + +static irqreturn_t +lqasc_rx_int(int irq, void *_port) +{ + unsigned long flags; + struct uart_port *port = (struct uart_port *)_port; + spin_lock_irqsave(<q_asc_lock, flags); + ltq_w32(ASC_IRNCR_RIR, port->membase + LTQ_ASC_IRNCR); + lqasc_rx_chars(port); + spin_unlock_irqrestore(<q_asc_lock, flags); + return IRQ_HANDLED; +} + +static unsigned int +lqasc_tx_empty(struct uart_port *port) +{ + int status; + status = ltq_r32(port->membase + LTQ_ASC_FSTAT) & ASCFSTAT_TXFFLMASK; + return status ? 0 : TIOCSER_TEMT; +} + +static unsigned int +lqasc_get_mctrl(struct uart_port *port) +{ + return TIOCM_CTS | TIOCM_CAR | TIOCM_DSR; +} + +static void +lqasc_set_mctrl(struct uart_port *port, u_int mctrl) +{ +} + +static void +lqasc_break_ctl(struct uart_port *port, int break_state) +{ +} + +static int +lqasc_startup(struct uart_port *port) +{ + struct ltq_uart_port *ltq_port = to_ltq_uart_port(port); + int retval; + + port->uartclk = clk_get_rate(ltq_port->clk); + + ltq_w32_mask(ASCCLC_DISS | ASCCLC_RMCMASK, (1 << ASCCLC_RMCOFFSET), + port->membase + LTQ_ASC_CLC); + + ltq_w32(0, port->membase + LTQ_ASC_PISEL); + ltq_w32( + ((TXFIFO_FL << ASCTXFCON_TXFITLOFF) & ASCTXFCON_TXFITLMASK) | + ASCTXFCON_TXFEN | ASCTXFCON_TXFFLU, + port->membase + LTQ_ASC_TXFCON); + ltq_w32( + ((RXFIFO_FL << ASCRXFCON_RXFITLOFF) & ASCRXFCON_RXFITLMASK) + | ASCRXFCON_RXFEN | ASCRXFCON_RXFFLU, + port->membase + LTQ_ASC_RXFCON); + /* make sure other settings are written to hardware before + * setting enable bits + */ + wmb(); + ltq_w32_mask(0, ASCCON_M_8ASYNC | ASCCON_FEN | ASCCON_TOEN | + ASCCON_ROEN, port->membase + LTQ_ASC_CON); + + retval = request_irq(ltq_port->tx_irq, lqasc_tx_int, + IRQF_DISABLED, "asc_tx", port); + if (retval) { + pr_err("failed to request lqasc_tx_int\n"); + return retval; + } + + retval = request_irq(ltq_port->rx_irq, lqasc_rx_int, + IRQF_DISABLED, "asc_rx", port); + if (retval) { + pr_err("failed to request lqasc_rx_int\n"); + goto err1; + } + + retval = request_irq(ltq_port->err_irq, lqasc_err_int, + IRQF_DISABLED, "asc_err", port); + if (retval) { + pr_err("failed to request lqasc_err_int\n"); + goto err2; + } + + ltq_w32(ASC_IRNREN_RX | ASC_IRNREN_ERR | ASC_IRNREN_TX, + port->membase + LTQ_ASC_IRNREN); + return 0; + +err2: + free_irq(ltq_port->rx_irq, port); +err1: + free_irq(ltq_port->tx_irq, port); + return retval; +} + +static void +lqasc_shutdown(struct uart_port *port) +{ + struct ltq_uart_port *ltq_port = to_ltq_uart_port(port); + free_irq(ltq_port->tx_irq, port); + free_irq(ltq_port->rx_irq, port); + free_irq(ltq_port->err_irq, port); + + ltq_w32(0, port->membase + LTQ_ASC_CON); + ltq_w32_mask(ASCRXFCON_RXFEN, ASCRXFCON_RXFFLU, + port->membase + LTQ_ASC_RXFCON); + ltq_w32_mask(ASCTXFCON_TXFEN, ASCTXFCON_TXFFLU, + port->membase + LTQ_ASC_TXFCON); +} + +static void +lqasc_set_termios(struct uart_port *port, + struct ktermios *new, struct ktermios *old) +{ + unsigned int cflag; + unsigned int iflag; + unsigned int divisor; + unsigned int baud; + unsigned int con = 0; + unsigned long flags; + + cflag = new->c_cflag; + iflag = new->c_iflag; + + switch (cflag & CSIZE) { + case CS7: + con = ASCCON_M_7ASYNC; + break; + + case CS5: + case CS6: + default: + new->c_cflag &= ~ CSIZE; + new->c_cflag |= CS8; + con = ASCCON_M_8ASYNC; + break; + } + + cflag &= ~CMSPAR; /* Mark/Space parity is not supported */ + + if (cflag & CSTOPB) + con |= ASCCON_STP; + + if (cflag & PARENB) { + if (!(cflag & PARODD)) + con &= ~ASCCON_ODD; + else + con |= ASCCON_ODD; + } + + port->read_status_mask = ASCSTATE_ROE; + if (iflag & INPCK) + port->read_status_mask |= ASCSTATE_FE | ASCSTATE_PE; + + port->ignore_status_mask = 0; + if (iflag & IGNPAR) + port->ignore_status_mask |= ASCSTATE_FE | ASCSTATE_PE; + + if (iflag & IGNBRK) { + /* + * If we're ignoring parity and break indicators, + * ignore overruns too (for real raw support). + */ + if (iflag & IGNPAR) + port->ignore_status_mask |= ASCSTATE_ROE; + } + + if ((cflag & CREAD) == 0) + port->ignore_status_mask |= UART_DUMMY_UER_RX; + + /* set error signals - framing, parity and overrun, enable receiver */ + con |= ASCCON_FEN | ASCCON_TOEN | ASCCON_ROEN; + + spin_lock_irqsave(<q_asc_lock, flags); + + /* set up CON */ + ltq_w32_mask(0, con, port->membase + LTQ_ASC_CON); + + /* Set baud rate - take a divider of 2 into account */ + baud = uart_get_baud_rate(port, new, old, 0, port->uartclk / 16); + divisor = uart_get_divisor(port, baud); + divisor = divisor / 2 - 1; + + /* disable the baudrate generator */ + ltq_w32_mask(ASCCON_R, 0, port->membase + LTQ_ASC_CON); + + /* make sure the fractional divider is off */ + ltq_w32_mask(ASCCON_FDE, 0, port->membase + LTQ_ASC_CON); + + /* set up to use divisor of 2 */ + ltq_w32_mask(ASCCON_BRS, 0, port->membase + LTQ_ASC_CON); + + /* now we can write the new baudrate into the register */ + ltq_w32(divisor, port->membase + LTQ_ASC_BG); + + /* turn the baudrate generator back on */ + ltq_w32_mask(0, ASCCON_R, port->membase + LTQ_ASC_CON); + + /* enable rx */ + ltq_w32(ASCWHBSTATE_SETREN, port->membase + LTQ_ASC_WHBSTATE); + + spin_unlock_irqrestore(<q_asc_lock, flags); + + /* Don't rewrite B0 */ + if (tty_termios_baud_rate(new)) + tty_termios_encode_baud_rate(new, baud, baud); +} + +static const char* +lqasc_type(struct uart_port *port) +{ + if (port->type == PORT_LTQ_ASC) + return DRVNAME; + else + return NULL; +} + +static void +lqasc_release_port(struct uart_port *port) +{ + if (port->flags & UPF_IOREMAP) { + iounmap(port->membase); + port->membase = NULL; + } +} + +static int +lqasc_request_port(struct uart_port *port) +{ + struct platform_device *pdev = to_platform_device(port->dev); + struct resource *res; + int size; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) { + dev_err(&pdev->dev, "cannot obtain I/O memory region"); + return -ENODEV; + } + size = resource_size(res); + + res = devm_request_mem_region(&pdev->dev, res->start, + size, dev_name(&pdev->dev)); + if (!res) { + dev_err(&pdev->dev, "cannot request I/O memory region"); + return -EBUSY; + } + + if (port->flags & UPF_IOREMAP) { + port->membase = devm_ioremap_nocache(&pdev->dev, + port->mapbase, size); + if (port->membase == NULL) + return -ENOMEM; + } + return 0; +} + +static void +lqasc_config_port(struct uart_port *port, int flags) +{ + if (flags & UART_CONFIG_TYPE) { + port->type = PORT_LTQ_ASC; + lqasc_request_port(port); + } +} + +static int +lqasc_verify_port(struct uart_port *port, + struct serial_struct *ser) +{ + int ret = 0; + if (ser->type != PORT_UNKNOWN && ser->type != PORT_LTQ_ASC) + ret = -EINVAL; + if (ser->irq < 0 || ser->irq >= NR_IRQS) + ret = -EINVAL; + if (ser->baud_base < 9600) + ret = -EINVAL; + return ret; +} + +static struct uart_ops lqasc_pops = { + .tx_empty = lqasc_tx_empty, + .set_mctrl = lqasc_set_mctrl, + .get_mctrl = lqasc_get_mctrl, + .stop_tx = lqasc_stop_tx, + .start_tx = lqasc_start_tx, + .stop_rx = lqasc_stop_rx, + .enable_ms = lqasc_enable_ms, + .break_ctl = lqasc_break_ctl, + .startup = lqasc_startup, + .shutdown = lqasc_shutdown, + .set_termios = lqasc_set_termios, + .type = lqasc_type, + .release_port = lqasc_release_port, + .request_port = lqasc_request_port, + .config_port = lqasc_config_port, + .verify_port = lqasc_verify_port, +}; + +static void +lqasc_console_putchar(struct uart_port *port, int ch) +{ + int fifofree; + + if (!port->membase) + return; + + do { + fifofree = (ltq_r32(port->membase + LTQ_ASC_FSTAT) + & ASCFSTAT_TXFREEMASK) >> ASCFSTAT_TXFREEOFF; + } while (fifofree == 0); + ltq_w8(ch, port->membase + LTQ_ASC_TBUF); +} + + +static void +lqasc_console_write(struct console *co, const char *s, u_int count) +{ + struct ltq_uart_port *ltq_port; + struct uart_port *port; + unsigned long flags; + + if (co->index >= MAXPORTS) + return; + + ltq_port = lqasc_port[co->index]; + if (!ltq_port) + return; + + port = <q_port->port; + + spin_lock_irqsave(<q_asc_lock, flags); + uart_console_write(port, s, count, lqasc_console_putchar); + spin_unlock_irqrestore(<q_asc_lock, flags); +} + +static int __init +lqasc_console_setup(struct console *co, char *options) +{ + struct ltq_uart_port *ltq_port; + struct uart_port *port; + int baud = 115200; + int bits = 8; + int parity = 'n'; + int flow = 'n'; + + if (co->index >= MAXPORTS) + return -ENODEV; + + ltq_port = lqasc_port[co->index]; + if (!ltq_port) + return -ENODEV; + + port = <q_port->port; + + port->uartclk = clk_get_rate(ltq_port->clk); + + if (options) + uart_parse_options(options, &baud, &parity, &bits, &flow); + return uart_set_options(port, co, baud, parity, bits, flow); +} + +static struct console lqasc_console = { + .name = "ttyLTQ", + .write = lqasc_console_write, + .device = uart_console_device, + .setup = lqasc_console_setup, + .flags = CON_PRINTBUFFER, + .index = -1, + .data = &lqasc_reg, +}; + +static int __init +lqasc_console_init(void) +{ + register_console(&lqasc_console); + return 0; +} +console_initcall(lqasc_console_init); + +static struct uart_driver lqasc_reg = { + .owner = THIS_MODULE, + .driver_name = DRVNAME, + .dev_name = "ttyLTQ", + .major = 0, + .minor = 0, + .nr = MAXPORTS, + .cons = &lqasc_console, +}; + +static int __init +lqasc_probe(struct platform_device *pdev) +{ + struct ltq_uart_port *ltq_port; + struct uart_port *port; + struct resource *mmres, *irqres; + int tx_irq, rx_irq, err_irq; + struct clk *clk; + int ret; + + mmres = platform_get_resource(pdev, IORESOURCE_MEM, 0); + irqres = platform_get_resource(pdev, IORESOURCE_IRQ, 0); + if (!mmres || !irqres) + return -ENODEV; + + if (pdev->id >= MAXPORTS) + return -EBUSY; + + if (lqasc_port[pdev->id] != NULL) + return -EBUSY; + + clk = clk_get(&pdev->dev, "fpi"); + if (IS_ERR(clk)) { + pr_err("failed to get fpi clk\n"); + return -ENOENT; + } + + tx_irq = platform_get_irq_byname(pdev, "tx"); + rx_irq = platform_get_irq_byname(pdev, "rx"); + err_irq = platform_get_irq_byname(pdev, "err"); + if ((tx_irq < 0) | (rx_irq < 0) | (err_irq < 0)) + return -ENODEV; + + ltq_port = kzalloc(sizeof(struct ltq_uart_port), GFP_KERNEL); + if (!ltq_port) + return -ENOMEM; + + port = <q_port->port; + + port->iotype = SERIAL_IO_MEM; + port->flags = ASYNC_BOOT_AUTOCONF | UPF_IOREMAP; + port->ops = &lqasc_pops; + port->fifosize = 16; + port->type = PORT_LTQ_ASC, + port->line = pdev->id; + port->dev = &pdev->dev; + + port->irq = tx_irq; /* unused, just to be backward-compatibe */ + port->mapbase = mmres->start; + + ltq_port->clk = clk; + + ltq_port->tx_irq = tx_irq; + ltq_port->rx_irq = rx_irq; + ltq_port->err_irq = err_irq; + + lqasc_port[pdev->id] = ltq_port; + platform_set_drvdata(pdev, ltq_port); + + ret = uart_add_one_port(&lqasc_reg, port); + + return ret; +} + +static struct platform_driver lqasc_driver = { + .driver = { + .name = DRVNAME, + .owner = THIS_MODULE, + }, +}; + +int __init +init_lqasc(void) +{ + int ret; + + ret = uart_register_driver(&lqasc_reg); + if (ret != 0) + return ret; + + ret = platform_driver_probe(&lqasc_driver, lqasc_probe); + if (ret != 0) + uart_unregister_driver(&lqasc_reg); + + return ret; +} + +module_init(init_lqasc); + +MODULE_DESCRIPTION("Lantiq serial port driver"); +MODULE_LICENSE("GPL"); -- cgit v0.10.2 From dfec1a827d2bdc35d0990afd100f79a685ec0985 Mon Sep 17 00:00:00 2001 From: John Crispin Date: Fri, 6 May 2011 00:10:00 +0200 Subject: MIPS: Lantiq: Add DMA support This patch adds support for the DMA engine found inside the XWAY family of SoCs. The engine has 5 ports and 20 channels. Signed-off-by: John Crispin Signed-off-by: Ralph Hempel Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/2355/ Signed-off-by: Ralf Baechle diff --git a/arch/mips/include/asm/mach-lantiq/xway/lantiq_soc.h b/arch/mips/include/asm/mach-lantiq/xway/lantiq_soc.h index 343e82cb..4827afb 100644 --- a/arch/mips/include/asm/mach-lantiq/xway/lantiq_soc.h +++ b/arch/mips/include/asm/mach-lantiq/xway/lantiq_soc.h @@ -86,7 +86,8 @@ #define LTQ_PPE32_SIZE 0x40000 /* DMA */ -#define LTQ_DMA_BASE_ADDR 0xBE104100 +#define LTQ_DMA_BASE_ADDR 0x1E104100 +#define LTQ_DMA_SIZE 0x800 /* PCI */ #define PCI_CR_BASE_ADDR 0x1E105400 diff --git a/arch/mips/include/asm/mach-lantiq/xway/xway_dma.h b/arch/mips/include/asm/mach-lantiq/xway/xway_dma.h new file mode 100644 index 0000000..872943a --- /dev/null +++ b/arch/mips/include/asm/mach-lantiq/xway/xway_dma.h @@ -0,0 +1,60 @@ +/* + * 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. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. + * + * Copyright (C) 2011 John Crispin + */ + +#ifndef LTQ_DMA_H__ +#define LTQ_DMA_H__ + +#define LTQ_DESC_SIZE 0x08 /* each descriptor is 64bit */ +#define LTQ_DESC_NUM 0x40 /* 64 descriptors / channel */ + +#define LTQ_DMA_OWN BIT(31) /* owner bit */ +#define LTQ_DMA_C BIT(30) /* complete bit */ +#define LTQ_DMA_SOP BIT(29) /* start of packet */ +#define LTQ_DMA_EOP BIT(28) /* end of packet */ +#define LTQ_DMA_TX_OFFSET(x) ((x & 0x1f) << 23) /* data bytes offset */ +#define LTQ_DMA_RX_OFFSET(x) ((x & 0x7) << 23) /* data bytes offset */ +#define LTQ_DMA_SIZE_MASK (0xffff) /* the size field is 16 bit */ + +struct ltq_dma_desc { + u32 ctl; + u32 addr; +}; + +struct ltq_dma_channel { + int nr; /* the channel number */ + int irq; /* the mapped irq */ + int desc; /* the current descriptor */ + struct ltq_dma_desc *desc_base; /* the descriptor base */ + int phys; /* physical addr */ +}; + +enum { + DMA_PORT_ETOP = 0, + DMA_PORT_DEU, +}; + +extern void ltq_dma_enable_irq(struct ltq_dma_channel *ch); +extern void ltq_dma_disable_irq(struct ltq_dma_channel *ch); +extern void ltq_dma_ack_irq(struct ltq_dma_channel *ch); +extern void ltq_dma_open(struct ltq_dma_channel *ch); +extern void ltq_dma_close(struct ltq_dma_channel *ch); +extern void ltq_dma_alloc_tx(struct ltq_dma_channel *ch); +extern void ltq_dma_alloc_rx(struct ltq_dma_channel *ch); +extern void ltq_dma_free(struct ltq_dma_channel *ch); +extern void ltq_dma_init_port(int p); + +#endif diff --git a/arch/mips/lantiq/xway/Makefile b/arch/mips/lantiq/xway/Makefile index 6b5e07e..c517f2e 100644 --- a/arch/mips/lantiq/xway/Makefile +++ b/arch/mips/lantiq/xway/Makefile @@ -1,4 +1,4 @@ -obj-y := pmu.o ebu.o reset.o gpio.o gpio_stp.o gpio_ebu.o devices.o +obj-y := pmu.o ebu.o reset.o gpio.o gpio_stp.o gpio_ebu.o devices.o dma.o obj-$(CONFIG_SOC_XWAY) += clk-xway.o prom-xway.o setup-xway.o obj-$(CONFIG_SOC_AMAZON_SE) += clk-ase.o prom-ase.o setup-ase.o diff --git a/arch/mips/lantiq/xway/devices.h b/arch/mips/lantiq/xway/devices.h index 51f56b5..d573084 100644 --- a/arch/mips/lantiq/xway/devices.h +++ b/arch/mips/lantiq/xway/devices.h @@ -10,6 +10,7 @@ #define _LTQ_DEVICES_XWAY_H__ #include "../devices.h" +#include extern void ltq_register_gpio(void); extern void ltq_register_gpio_stp(void); diff --git a/arch/mips/lantiq/xway/dma.c b/arch/mips/lantiq/xway/dma.c new file mode 100644 index 0000000..4278a45 --- /dev/null +++ b/arch/mips/lantiq/xway/dma.c @@ -0,0 +1,253 @@ +/* + * 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. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. + * + * Copyright (C) 2011 John Crispin + */ + +#include +#include +#include +#include + +#include +#include + +#define LTQ_DMA_CTRL 0x10 +#define LTQ_DMA_CPOLL 0x14 +#define LTQ_DMA_CS 0x18 +#define LTQ_DMA_CCTRL 0x1C +#define LTQ_DMA_CDBA 0x20 +#define LTQ_DMA_CDLEN 0x24 +#define LTQ_DMA_CIS 0x28 +#define LTQ_DMA_CIE 0x2C +#define LTQ_DMA_PS 0x40 +#define LTQ_DMA_PCTRL 0x44 +#define LTQ_DMA_IRNEN 0xf4 + +#define DMA_DESCPT BIT(3) /* descriptor complete irq */ +#define DMA_TX BIT(8) /* TX channel direction */ +#define DMA_CHAN_ON BIT(0) /* channel on / off bit */ +#define DMA_PDEN BIT(6) /* enable packet drop */ +#define DMA_CHAN_RST BIT(1) /* channel on / off bit */ +#define DMA_RESET BIT(0) /* channel on / off bit */ +#define DMA_IRQ_ACK 0x7e /* IRQ status register */ +#define DMA_POLL BIT(31) /* turn on channel polling */ +#define DMA_CLK_DIV4 BIT(6) /* polling clock divider */ +#define DMA_2W_BURST BIT(1) /* 2 word burst length */ +#define DMA_MAX_CHANNEL 20 /* the soc has 20 channels */ +#define DMA_ETOP_ENDIANESS (0xf << 8) /* endianess swap etop channels */ +#define DMA_WEIGHT (BIT(17) | BIT(16)) /* default channel wheight */ + +#define ltq_dma_r32(x) ltq_r32(ltq_dma_membase + (x)) +#define ltq_dma_w32(x, y) ltq_w32(x, ltq_dma_membase + (y)) +#define ltq_dma_w32_mask(x, y, z) ltq_w32_mask(x, y, \ + ltq_dma_membase + (z)) + +static struct resource ltq_dma_resource = { + .name = "dma", + .start = LTQ_DMA_BASE_ADDR, + .end = LTQ_DMA_BASE_ADDR + LTQ_DMA_SIZE - 1, + .flags = IORESOURCE_MEM, +}; + +static void __iomem *ltq_dma_membase; + +void +ltq_dma_enable_irq(struct ltq_dma_channel *ch) +{ + unsigned long flags; + + local_irq_save(flags); + ltq_dma_w32(ch->nr, LTQ_DMA_CS); + ltq_dma_w32_mask(0, 1 << ch->nr, LTQ_DMA_IRNEN); + local_irq_restore(flags); +} +EXPORT_SYMBOL_GPL(ltq_dma_enable_irq); + +void +ltq_dma_disable_irq(struct ltq_dma_channel *ch) +{ + unsigned long flags; + + local_irq_save(flags); + ltq_dma_w32(ch->nr, LTQ_DMA_CS); + ltq_dma_w32_mask(1 << ch->nr, 0, LTQ_DMA_IRNEN); + local_irq_restore(flags); +} +EXPORT_SYMBOL_GPL(ltq_dma_disable_irq); + +void +ltq_dma_ack_irq(struct ltq_dma_channel *ch) +{ + unsigned long flags; + + local_irq_save(flags); + ltq_dma_w32(ch->nr, LTQ_DMA_CS); + ltq_dma_w32(DMA_IRQ_ACK, LTQ_DMA_CIS); + local_irq_restore(flags); +} +EXPORT_SYMBOL_GPL(ltq_dma_ack_irq); + +void +ltq_dma_open(struct ltq_dma_channel *ch) +{ + unsigned long flag; + + local_irq_save(flag); + ltq_dma_w32(ch->nr, LTQ_DMA_CS); + ltq_dma_w32_mask(0, DMA_CHAN_ON, LTQ_DMA_CCTRL); + ltq_dma_enable_irq(ch); + local_irq_restore(flag); +} +EXPORT_SYMBOL_GPL(ltq_dma_open); + +void +ltq_dma_close(struct ltq_dma_channel *ch) +{ + unsigned long flag; + + local_irq_save(flag); + ltq_dma_w32(ch->nr, LTQ_DMA_CS); + ltq_dma_w32_mask(DMA_CHAN_ON, 0, LTQ_DMA_CCTRL); + ltq_dma_disable_irq(ch); + local_irq_restore(flag); +} +EXPORT_SYMBOL_GPL(ltq_dma_close); + +static void +ltq_dma_alloc(struct ltq_dma_channel *ch) +{ + unsigned long flags; + + ch->desc = 0; + ch->desc_base = dma_alloc_coherent(NULL, + LTQ_DESC_NUM * LTQ_DESC_SIZE, + &ch->phys, GFP_ATOMIC); + memset(ch->desc_base, 0, LTQ_DESC_NUM * LTQ_DESC_SIZE); + + local_irq_save(flags); + ltq_dma_w32(ch->nr, LTQ_DMA_CS); + ltq_dma_w32(ch->phys, LTQ_DMA_CDBA); + ltq_dma_w32(LTQ_DESC_NUM, LTQ_DMA_CDLEN); + ltq_dma_w32_mask(DMA_CHAN_ON, 0, LTQ_DMA_CCTRL); + wmb(); + ltq_dma_w32_mask(0, DMA_CHAN_RST, LTQ_DMA_CCTRL); + while (ltq_dma_r32(LTQ_DMA_CCTRL) & DMA_CHAN_RST) + ; + local_irq_restore(flags); +} + +void +ltq_dma_alloc_tx(struct ltq_dma_channel *ch) +{ + unsigned long flags; + + ltq_dma_alloc(ch); + + local_irq_save(flags); + ltq_dma_w32(DMA_DESCPT, LTQ_DMA_CIE); + ltq_dma_w32_mask(0, 1 << ch->nr, LTQ_DMA_IRNEN); + ltq_dma_w32(DMA_WEIGHT | DMA_TX, LTQ_DMA_CCTRL); + local_irq_restore(flags); +} +EXPORT_SYMBOL_GPL(ltq_dma_alloc_tx); + +void +ltq_dma_alloc_rx(struct ltq_dma_channel *ch) +{ + unsigned long flags; + + ltq_dma_alloc(ch); + + local_irq_save(flags); + ltq_dma_w32(DMA_DESCPT, LTQ_DMA_CIE); + ltq_dma_w32_mask(0, 1 << ch->nr, LTQ_DMA_IRNEN); + ltq_dma_w32(DMA_WEIGHT, LTQ_DMA_CCTRL); + local_irq_restore(flags); +} +EXPORT_SYMBOL_GPL(ltq_dma_alloc_rx); + +void +ltq_dma_free(struct ltq_dma_channel *ch) +{ + if (!ch->desc_base) + return; + ltq_dma_close(ch); + dma_free_coherent(NULL, LTQ_DESC_NUM * LTQ_DESC_SIZE, + ch->desc_base, ch->phys); +} +EXPORT_SYMBOL_GPL(ltq_dma_free); + +void +ltq_dma_init_port(int p) +{ + ltq_dma_w32(p, LTQ_DMA_PS); + switch (p) { + case DMA_PORT_ETOP: + /* + * Tell the DMA engine to swap the endianess of data frames and + * drop packets if the channel arbitration fails. + */ + ltq_dma_w32_mask(0, DMA_ETOP_ENDIANESS | DMA_PDEN, + LTQ_DMA_PCTRL); + break; + + case DMA_PORT_DEU: + ltq_dma_w32((DMA_2W_BURST << 4) | (DMA_2W_BURST << 2), + LTQ_DMA_PCTRL); + break; + + default: + break; + } +} +EXPORT_SYMBOL_GPL(ltq_dma_init_port); + +int __init +ltq_dma_init(void) +{ + int i; + + /* insert and request the memory region */ + if (insert_resource(&iomem_resource, <q_dma_resource) < 0) + panic("Failed to insert dma memory\n"); + + if (request_mem_region(ltq_dma_resource.start, + resource_size(<q_dma_resource), "dma") < 0) + panic("Failed to request dma memory\n"); + + /* remap dma register range */ + ltq_dma_membase = ioremap_nocache(ltq_dma_resource.start, + resource_size(<q_dma_resource)); + if (!ltq_dma_membase) + panic("Failed to remap dma memory\n"); + + /* power up and reset the dma engine */ + ltq_pmu_enable(PMU_DMA); + ltq_dma_w32_mask(0, DMA_RESET, LTQ_DMA_CTRL); + + /* disable all interrupts */ + ltq_dma_w32(0, LTQ_DMA_IRNEN); + + /* reset/configure each channel */ + for (i = 0; i < DMA_MAX_CHANNEL; i++) { + ltq_dma_w32(i, LTQ_DMA_CS); + ltq_dma_w32(DMA_CHAN_RST, LTQ_DMA_CCTRL); + ltq_dma_w32(DMA_POLL | DMA_CLK_DIV4, LTQ_DMA_CPOLL); + ltq_dma_w32_mask(DMA_CHAN_ON, 0, LTQ_DMA_CCTRL); + } + return 0; +} + +postcore_initcall(ltq_dma_init); -- cgit v0.10.2 From 504d4721ee8e432af4b5f196a08af38bc4dac5fe Mon Sep 17 00:00:00 2001 From: John Crispin Date: Fri, 6 May 2011 00:10:01 +0200 Subject: MIPS: Lantiq: Add ethernet driver This patch adds the driver for the ETOP Packet Processing Engine (PPE32) found inside the XWAY family of Lantiq MIPS SoCs. This driver makes 100MBit ethernet work. Support for all 8 dma channels, gbit and the embedded switch found on the ar9/vr9 still needs to be implemented. Signed-off-by: John Crispin Signed-off-by: Ralph Hempel Cc: linux-mips@linux-mips.org Cc: netdev@vger.kernel.org Patchwork: https://patchwork.linux-mips.org/patch/2357/ Acked-by: David S. Miller Signed-off-by: Ralf Baechle diff --git a/arch/mips/include/asm/mach-lantiq/lantiq_platform.h b/arch/mips/include/asm/mach-lantiq/lantiq_platform.h index 1f1dba6..a305f1d 100644 --- a/arch/mips/include/asm/mach-lantiq/lantiq_platform.h +++ b/arch/mips/include/asm/mach-lantiq/lantiq_platform.h @@ -10,6 +10,7 @@ #define _LANTIQ_PLATFORM_H__ #include +#include /* struct used to pass info to the pci core */ enum { @@ -43,4 +44,10 @@ struct ltq_pci_data { int irq[16]; }; +/* struct used to pass info to network drivers */ +struct ltq_eth_data { + struct sockaddr mac; + int mii_mode; +}; + #endif diff --git a/arch/mips/include/asm/mach-lantiq/xway/lantiq_soc.h b/arch/mips/include/asm/mach-lantiq/xway/lantiq_soc.h index 4827afb..8a3c6be 100644 --- a/arch/mips/include/asm/mach-lantiq/xway/lantiq_soc.h +++ b/arch/mips/include/asm/mach-lantiq/xway/lantiq_soc.h @@ -82,8 +82,8 @@ #define PMU_SWITCH 0x10000000 /* ETOP - ethernet */ -#define LTQ_PPE32_BASE_ADDR 0xBE180000 -#define LTQ_PPE32_SIZE 0x40000 +#define LTQ_ETOP_BASE_ADDR 0x1E180000 +#define LTQ_ETOP_SIZE 0x40000 /* DMA */ #define LTQ_DMA_BASE_ADDR 0x1E104100 diff --git a/arch/mips/lantiq/xway/devices.c b/arch/mips/lantiq/xway/devices.c index a71b3b5..e09e789 100644 --- a/arch/mips/lantiq/xway/devices.c +++ b/arch/mips/lantiq/xway/devices.c @@ -96,3 +96,26 @@ void __init ltq_register_ase_asc(void) platform_device_register_simple("ltq_asc", 0, ltq_ase_asc_resources, ARRAY_SIZE(ltq_ase_asc_resources)); } + +/* ethernet */ +static struct resource ltq_etop_resources = { + .name = "etop", + .start = LTQ_ETOP_BASE_ADDR, + .end = LTQ_ETOP_BASE_ADDR + LTQ_ETOP_SIZE - 1, + .flags = IORESOURCE_MEM, +}; + +static struct platform_device ltq_etop = { + .name = "ltq_etop", + .resource = <q_etop_resources, + .num_resources = 1, +}; + +void __init +ltq_register_etop(struct ltq_eth_data *eth) +{ + if (eth) { + ltq_etop.dev.platform_data = eth; + platform_device_register(<q_etop); + } +} diff --git a/arch/mips/lantiq/xway/devices.h b/arch/mips/lantiq/xway/devices.h index d573084..e904934 100644 --- a/arch/mips/lantiq/xway/devices.h +++ b/arch/mips/lantiq/xway/devices.h @@ -15,5 +15,6 @@ extern void ltq_register_gpio(void); extern void ltq_register_gpio_stp(void); extern void ltq_register_ase_asc(void); +extern void ltq_register_etop(struct ltq_eth_data *eth); #endif diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index 6c884ef..19f04a3 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -2017,6 +2017,13 @@ config FTMAC100 from Faraday. It is used on Faraday A320, Andes AG101 and some other ARM/NDS32 SoC's. +config LANTIQ_ETOP + tristate "Lantiq SoC ETOP driver" + depends on SOC_TYPE_XWAY + help + Support for the MII0 inside the Lantiq SoC + + source "drivers/net/fs_enet/Kconfig" source "drivers/net/octeon/Kconfig" diff --git a/drivers/net/Makefile b/drivers/net/Makefile index e5a7375..209fbb7 100644 --- a/drivers/net/Makefile +++ b/drivers/net/Makefile @@ -259,6 +259,7 @@ obj-$(CONFIG_MLX4_CORE) += mlx4/ obj-$(CONFIG_ENC28J60) += enc28j60.o obj-$(CONFIG_ETHOC) += ethoc.o obj-$(CONFIG_GRETH) += greth.o +obj-$(CONFIG_LANTIQ_ETOP) += lantiq_etop.o obj-$(CONFIG_XTENSA_XT2000_SONIC) += xtsonic.o diff --git a/drivers/net/lantiq_etop.c b/drivers/net/lantiq_etop.c new file mode 100644 index 0000000..45f252b --- /dev/null +++ b/drivers/net/lantiq_etop.c @@ -0,0 +1,805 @@ +/* + * 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. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. + * + * Copyright (C) 2011 John Crispin + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include + +#define LTQ_ETOP_MDIO 0x11804 +#define MDIO_REQUEST 0x80000000 +#define MDIO_READ 0x40000000 +#define MDIO_ADDR_MASK 0x1f +#define MDIO_ADDR_OFFSET 0x15 +#define MDIO_REG_MASK 0x1f +#define MDIO_REG_OFFSET 0x10 +#define MDIO_VAL_MASK 0xffff + +#define PPE32_CGEN 0x800 +#define LQ_PPE32_ENET_MAC_CFG 0x1840 + +#define LTQ_ETOP_ENETS0 0x11850 +#define LTQ_ETOP_MAC_DA0 0x1186C +#define LTQ_ETOP_MAC_DA1 0x11870 +#define LTQ_ETOP_CFG 0x16020 +#define LTQ_ETOP_IGPLEN 0x16080 + +#define MAX_DMA_CHAN 0x8 +#define MAX_DMA_CRC_LEN 0x4 +#define MAX_DMA_DATA_LEN 0x600 + +#define ETOP_FTCU BIT(28) +#define ETOP_MII_MASK 0xf +#define ETOP_MII_NORMAL 0xd +#define ETOP_MII_REVERSE 0xe +#define ETOP_PLEN_UNDER 0x40 +#define ETOP_CGEN 0x800 + +/* use 2 static channels for TX/RX */ +#define LTQ_ETOP_TX_CHANNEL 1 +#define LTQ_ETOP_RX_CHANNEL 6 +#define IS_TX(x) (x == LTQ_ETOP_TX_CHANNEL) +#define IS_RX(x) (x == LTQ_ETOP_RX_CHANNEL) + +#define ltq_etop_r32(x) ltq_r32(ltq_etop_membase + (x)) +#define ltq_etop_w32(x, y) ltq_w32(x, ltq_etop_membase + (y)) +#define ltq_etop_w32_mask(x, y, z) \ + ltq_w32_mask(x, y, ltq_etop_membase + (z)) + +#define DRV_VERSION "1.0" + +static void __iomem *ltq_etop_membase; + +struct ltq_etop_chan { + int idx; + int tx_free; + struct net_device *netdev; + struct napi_struct napi; + struct ltq_dma_channel dma; + struct sk_buff *skb[LTQ_DESC_NUM]; +}; + +struct ltq_etop_priv { + struct net_device *netdev; + struct ltq_eth_data *pldata; + struct resource *res; + + struct mii_bus *mii_bus; + struct phy_device *phydev; + + struct ltq_etop_chan ch[MAX_DMA_CHAN]; + int tx_free[MAX_DMA_CHAN >> 1]; + + spinlock_t lock; +}; + +static int +ltq_etop_alloc_skb(struct ltq_etop_chan *ch) +{ + ch->skb[ch->dma.desc] = dev_alloc_skb(MAX_DMA_DATA_LEN); + if (!ch->skb[ch->dma.desc]) + return -ENOMEM; + ch->dma.desc_base[ch->dma.desc].addr = dma_map_single(NULL, + ch->skb[ch->dma.desc]->data, MAX_DMA_DATA_LEN, + DMA_FROM_DEVICE); + ch->dma.desc_base[ch->dma.desc].addr = + CPHYSADDR(ch->skb[ch->dma.desc]->data); + ch->dma.desc_base[ch->dma.desc].ctl = + LTQ_DMA_OWN | LTQ_DMA_RX_OFFSET(NET_IP_ALIGN) | + MAX_DMA_DATA_LEN; + skb_reserve(ch->skb[ch->dma.desc], NET_IP_ALIGN); + return 0; +} + +static void +ltq_etop_hw_receive(struct ltq_etop_chan *ch) +{ + struct ltq_etop_priv *priv = netdev_priv(ch->netdev); + struct ltq_dma_desc *desc = &ch->dma.desc_base[ch->dma.desc]; + struct sk_buff *skb = ch->skb[ch->dma.desc]; + int len = (desc->ctl & LTQ_DMA_SIZE_MASK) - MAX_DMA_CRC_LEN; + unsigned long flags; + + spin_lock_irqsave(&priv->lock, flags); + if (ltq_etop_alloc_skb(ch)) { + netdev_err(ch->netdev, + "failed to allocate new rx buffer, stopping DMA\n"); + ltq_dma_close(&ch->dma); + } + ch->dma.desc++; + ch->dma.desc %= LTQ_DESC_NUM; + spin_unlock_irqrestore(&priv->lock, flags); + + skb_put(skb, len); + skb->dev = ch->netdev; + skb->protocol = eth_type_trans(skb, ch->netdev); + netif_receive_skb(skb); +} + +static int +ltq_etop_poll_rx(struct napi_struct *napi, int budget) +{ + struct ltq_etop_chan *ch = container_of(napi, + struct ltq_etop_chan, napi); + int rx = 0; + int complete = 0; + + while ((rx < budget) && !complete) { + struct ltq_dma_desc *desc = &ch->dma.desc_base[ch->dma.desc]; + + if ((desc->ctl & (LTQ_DMA_OWN | LTQ_DMA_C)) == LTQ_DMA_C) { + ltq_etop_hw_receive(ch); + rx++; + } else { + complete = 1; + } + } + if (complete || !rx) { + napi_complete(&ch->napi); + ltq_dma_ack_irq(&ch->dma); + } + return rx; +} + +static int +ltq_etop_poll_tx(struct napi_struct *napi, int budget) +{ + struct ltq_etop_chan *ch = + container_of(napi, struct ltq_etop_chan, napi); + struct ltq_etop_priv *priv = netdev_priv(ch->netdev); + struct netdev_queue *txq = + netdev_get_tx_queue(ch->netdev, ch->idx >> 1); + unsigned long flags; + + spin_lock_irqsave(&priv->lock, flags); + while ((ch->dma.desc_base[ch->tx_free].ctl & + (LTQ_DMA_OWN | LTQ_DMA_C)) == LTQ_DMA_C) { + dev_kfree_skb_any(ch->skb[ch->tx_free]); + ch->skb[ch->tx_free] = NULL; + memset(&ch->dma.desc_base[ch->tx_free], 0, + sizeof(struct ltq_dma_desc)); + ch->tx_free++; + ch->tx_free %= LTQ_DESC_NUM; + } + spin_unlock_irqrestore(&priv->lock, flags); + + if (netif_tx_queue_stopped(txq)) + netif_tx_start_queue(txq); + napi_complete(&ch->napi); + ltq_dma_ack_irq(&ch->dma); + return 1; +} + +static irqreturn_t +ltq_etop_dma_irq(int irq, void *_priv) +{ + struct ltq_etop_priv *priv = _priv; + int ch = irq - LTQ_DMA_CH0_INT; + + napi_schedule(&priv->ch[ch].napi); + return IRQ_HANDLED; +} + +static void +ltq_etop_free_channel(struct net_device *dev, struct ltq_etop_chan *ch) +{ + struct ltq_etop_priv *priv = netdev_priv(dev); + + ltq_dma_free(&ch->dma); + if (ch->dma.irq) + free_irq(ch->dma.irq, priv); + if (IS_RX(ch->idx)) { + int desc; + for (desc = 0; desc < LTQ_DESC_NUM; desc++) + dev_kfree_skb_any(ch->skb[ch->dma.desc]); + } +} + +static void +ltq_etop_hw_exit(struct net_device *dev) +{ + struct ltq_etop_priv *priv = netdev_priv(dev); + int i; + + ltq_pmu_disable(PMU_PPE); + for (i = 0; i < MAX_DMA_CHAN; i++) + if (IS_TX(i) || IS_RX(i)) + ltq_etop_free_channel(dev, &priv->ch[i]); +} + +static int +ltq_etop_hw_init(struct net_device *dev) +{ + struct ltq_etop_priv *priv = netdev_priv(dev); + int i; + + ltq_pmu_enable(PMU_PPE); + + switch (priv->pldata->mii_mode) { + case PHY_INTERFACE_MODE_RMII: + ltq_etop_w32_mask(ETOP_MII_MASK, + ETOP_MII_REVERSE, LTQ_ETOP_CFG); + break; + + case PHY_INTERFACE_MODE_MII: + ltq_etop_w32_mask(ETOP_MII_MASK, + ETOP_MII_NORMAL, LTQ_ETOP_CFG); + break; + + default: + netdev_err(dev, "unknown mii mode %d\n", + priv->pldata->mii_mode); + return -ENOTSUPP; + } + + /* enable crc generation */ + ltq_etop_w32(PPE32_CGEN, LQ_PPE32_ENET_MAC_CFG); + + ltq_dma_init_port(DMA_PORT_ETOP); + + for (i = 0; i < MAX_DMA_CHAN; i++) { + int irq = LTQ_DMA_CH0_INT + i; + struct ltq_etop_chan *ch = &priv->ch[i]; + + ch->idx = ch->dma.nr = i; + + if (IS_TX(i)) { + ltq_dma_alloc_tx(&ch->dma); + request_irq(irq, ltq_etop_dma_irq, IRQF_DISABLED, + "etop_tx", priv); + } else if (IS_RX(i)) { + ltq_dma_alloc_rx(&ch->dma); + for (ch->dma.desc = 0; ch->dma.desc < LTQ_DESC_NUM; + ch->dma.desc++) + if (ltq_etop_alloc_skb(ch)) + return -ENOMEM; + ch->dma.desc = 0; + request_irq(irq, ltq_etop_dma_irq, IRQF_DISABLED, + "etop_rx", priv); + } + ch->dma.irq = irq; + } + return 0; +} + +static void +ltq_etop_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info) +{ + strcpy(info->driver, "Lantiq ETOP"); + strcpy(info->bus_info, "internal"); + strcpy(info->version, DRV_VERSION); +} + +static int +ltq_etop_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) +{ + struct ltq_etop_priv *priv = netdev_priv(dev); + + return phy_ethtool_gset(priv->phydev, cmd); +} + +static int +ltq_etop_set_settings(struct net_device *dev, struct ethtool_cmd *cmd) +{ + struct ltq_etop_priv *priv = netdev_priv(dev); + + return phy_ethtool_sset(priv->phydev, cmd); +} + +static int +ltq_etop_nway_reset(struct net_device *dev) +{ + struct ltq_etop_priv *priv = netdev_priv(dev); + + return phy_start_aneg(priv->phydev); +} + +static const struct ethtool_ops ltq_etop_ethtool_ops = { + .get_drvinfo = ltq_etop_get_drvinfo, + .get_settings = ltq_etop_get_settings, + .set_settings = ltq_etop_set_settings, + .nway_reset = ltq_etop_nway_reset, +}; + +static int +ltq_etop_mdio_wr(struct mii_bus *bus, int phy_addr, int phy_reg, u16 phy_data) +{ + u32 val = MDIO_REQUEST | + ((phy_addr & MDIO_ADDR_MASK) << MDIO_ADDR_OFFSET) | + ((phy_reg & MDIO_REG_MASK) << MDIO_REG_OFFSET) | + phy_data; + + while (ltq_etop_r32(LTQ_ETOP_MDIO) & MDIO_REQUEST) + ; + ltq_etop_w32(val, LTQ_ETOP_MDIO); + return 0; +} + +static int +ltq_etop_mdio_rd(struct mii_bus *bus, int phy_addr, int phy_reg) +{ + u32 val = MDIO_REQUEST | MDIO_READ | + ((phy_addr & MDIO_ADDR_MASK) << MDIO_ADDR_OFFSET) | + ((phy_reg & MDIO_REG_MASK) << MDIO_REG_OFFSET); + + while (ltq_etop_r32(LTQ_ETOP_MDIO) & MDIO_REQUEST) + ; + ltq_etop_w32(val, LTQ_ETOP_MDIO); + while (ltq_etop_r32(LTQ_ETOP_MDIO) & MDIO_REQUEST) + ; + val = ltq_etop_r32(LTQ_ETOP_MDIO) & MDIO_VAL_MASK; + return val; +} + +static void +ltq_etop_mdio_link(struct net_device *dev) +{ + /* nothing to do */ +} + +static int +ltq_etop_mdio_probe(struct net_device *dev) +{ + struct ltq_etop_priv *priv = netdev_priv(dev); + struct phy_device *phydev = NULL; + int phy_addr; + + for (phy_addr = 0; phy_addr < PHY_MAX_ADDR; phy_addr++) { + if (priv->mii_bus->phy_map[phy_addr]) { + phydev = priv->mii_bus->phy_map[phy_addr]; + break; + } + } + + if (!phydev) { + netdev_err(dev, "no PHY found\n"); + return -ENODEV; + } + + phydev = phy_connect(dev, dev_name(&phydev->dev), <q_etop_mdio_link, + 0, priv->pldata->mii_mode); + + if (IS_ERR(phydev)) { + netdev_err(dev, "Could not attach to PHY\n"); + return PTR_ERR(phydev); + } + + phydev->supported &= (SUPPORTED_10baseT_Half + | SUPPORTED_10baseT_Full + | SUPPORTED_100baseT_Half + | SUPPORTED_100baseT_Full + | SUPPORTED_Autoneg + | SUPPORTED_MII + | SUPPORTED_TP); + + phydev->advertising = phydev->supported; + priv->phydev = phydev; + pr_info("%s: attached PHY [%s] (phy_addr=%s, irq=%d)\n", + dev->name, phydev->drv->name, + dev_name(&phydev->dev), phydev->irq); + + return 0; +} + +static int +ltq_etop_mdio_init(struct net_device *dev) +{ + struct ltq_etop_priv *priv = netdev_priv(dev); + int i; + int err; + + priv->mii_bus = mdiobus_alloc(); + if (!priv->mii_bus) { + netdev_err(dev, "failed to allocate mii bus\n"); + err = -ENOMEM; + goto err_out; + } + + priv->mii_bus->priv = dev; + priv->mii_bus->read = ltq_etop_mdio_rd; + priv->mii_bus->write = ltq_etop_mdio_wr; + priv->mii_bus->name = "ltq_mii"; + snprintf(priv->mii_bus->id, MII_BUS_ID_SIZE, "%x", 0); + priv->mii_bus->irq = kmalloc(sizeof(int) * PHY_MAX_ADDR, GFP_KERNEL); + if (!priv->mii_bus->irq) { + err = -ENOMEM; + goto err_out_free_mdiobus; + } + + for (i = 0; i < PHY_MAX_ADDR; ++i) + priv->mii_bus->irq[i] = PHY_POLL; + + if (mdiobus_register(priv->mii_bus)) { + err = -ENXIO; + goto err_out_free_mdio_irq; + } + + if (ltq_etop_mdio_probe(dev)) { + err = -ENXIO; + goto err_out_unregister_bus; + } + return 0; + +err_out_unregister_bus: + mdiobus_unregister(priv->mii_bus); +err_out_free_mdio_irq: + kfree(priv->mii_bus->irq); +err_out_free_mdiobus: + mdiobus_free(priv->mii_bus); +err_out: + return err; +} + +static void +ltq_etop_mdio_cleanup(struct net_device *dev) +{ + struct ltq_etop_priv *priv = netdev_priv(dev); + + phy_disconnect(priv->phydev); + mdiobus_unregister(priv->mii_bus); + kfree(priv->mii_bus->irq); + mdiobus_free(priv->mii_bus); +} + +static int +ltq_etop_open(struct net_device *dev) +{ + struct ltq_etop_priv *priv = netdev_priv(dev); + int i; + + for (i = 0; i < MAX_DMA_CHAN; i++) { + struct ltq_etop_chan *ch = &priv->ch[i]; + + if (!IS_TX(i) && (!IS_RX(i))) + continue; + ltq_dma_open(&ch->dma); + napi_enable(&ch->napi); + } + phy_start(priv->phydev); + netif_tx_start_all_queues(dev); + return 0; +} + +static int +ltq_etop_stop(struct net_device *dev) +{ + struct ltq_etop_priv *priv = netdev_priv(dev); + int i; + + netif_tx_stop_all_queues(dev); + phy_stop(priv->phydev); + for (i = 0; i < MAX_DMA_CHAN; i++) { + struct ltq_etop_chan *ch = &priv->ch[i]; + + if (!IS_RX(i) && !IS_TX(i)) + continue; + napi_disable(&ch->napi); + ltq_dma_close(&ch->dma); + } + return 0; +} + +static int +ltq_etop_tx(struct sk_buff *skb, struct net_device *dev) +{ + int queue = skb_get_queue_mapping(skb); + struct netdev_queue *txq = netdev_get_tx_queue(dev, queue); + struct ltq_etop_priv *priv = netdev_priv(dev); + struct ltq_etop_chan *ch = &priv->ch[(queue << 1) | 1]; + struct ltq_dma_desc *desc = &ch->dma.desc_base[ch->dma.desc]; + int len; + unsigned long flags; + u32 byte_offset; + + len = skb->len < ETH_ZLEN ? ETH_ZLEN : skb->len; + + if ((desc->ctl & (LTQ_DMA_OWN | LTQ_DMA_C)) || ch->skb[ch->dma.desc]) { + dev_kfree_skb_any(skb); + netdev_err(dev, "tx ring full\n"); + netif_tx_stop_queue(txq); + return NETDEV_TX_BUSY; + } + + /* dma needs to start on a 16 byte aligned address */ + byte_offset = CPHYSADDR(skb->data) % 16; + ch->skb[ch->dma.desc] = skb; + + dev->trans_start = jiffies; + + spin_lock_irqsave(&priv->lock, flags); + desc->addr = ((unsigned int) dma_map_single(NULL, skb->data, len, + DMA_TO_DEVICE)) - byte_offset; + wmb(); + desc->ctl = LTQ_DMA_OWN | LTQ_DMA_SOP | LTQ_DMA_EOP | + LTQ_DMA_TX_OFFSET(byte_offset) | (len & LTQ_DMA_SIZE_MASK); + ch->dma.desc++; + ch->dma.desc %= LTQ_DESC_NUM; + spin_unlock_irqrestore(&priv->lock, flags); + + if (ch->dma.desc_base[ch->dma.desc].ctl & LTQ_DMA_OWN) + netif_tx_stop_queue(txq); + + return NETDEV_TX_OK; +} + +static int +ltq_etop_change_mtu(struct net_device *dev, int new_mtu) +{ + int ret = eth_change_mtu(dev, new_mtu); + + if (!ret) { + struct ltq_etop_priv *priv = netdev_priv(dev); + unsigned long flags; + + spin_lock_irqsave(&priv->lock, flags); + ltq_etop_w32((ETOP_PLEN_UNDER << 16) | new_mtu, + LTQ_ETOP_IGPLEN); + spin_unlock_irqrestore(&priv->lock, flags); + } + return ret; +} + +static int +ltq_etop_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) +{ + struct ltq_etop_priv *priv = netdev_priv(dev); + + /* TODO: mii-toll reports "No MII transceiver present!." ?!*/ + return phy_mii_ioctl(priv->phydev, rq, cmd); +} + +static int +ltq_etop_set_mac_address(struct net_device *dev, void *p) +{ + int ret = eth_mac_addr(dev, p); + + if (!ret) { + struct ltq_etop_priv *priv = netdev_priv(dev); + unsigned long flags; + + /* store the mac for the unicast filter */ + spin_lock_irqsave(&priv->lock, flags); + ltq_etop_w32(*((u32 *)dev->dev_addr), LTQ_ETOP_MAC_DA0); + ltq_etop_w32(*((u16 *)&dev->dev_addr[4]) << 16, + LTQ_ETOP_MAC_DA1); + spin_unlock_irqrestore(&priv->lock, flags); + } + return ret; +} + +static void +ltq_etop_set_multicast_list(struct net_device *dev) +{ + struct ltq_etop_priv *priv = netdev_priv(dev); + unsigned long flags; + + /* ensure that the unicast filter is not enabled in promiscious mode */ + spin_lock_irqsave(&priv->lock, flags); + if ((dev->flags & IFF_PROMISC) || (dev->flags & IFF_ALLMULTI)) + ltq_etop_w32_mask(ETOP_FTCU, 0, LTQ_ETOP_ENETS0); + else + ltq_etop_w32_mask(0, ETOP_FTCU, LTQ_ETOP_ENETS0); + spin_unlock_irqrestore(&priv->lock, flags); +} + +static u16 +ltq_etop_select_queue(struct net_device *dev, struct sk_buff *skb) +{ + /* we are currently only using the first queue */ + return 0; +} + +static int +ltq_etop_init(struct net_device *dev) +{ + struct ltq_etop_priv *priv = netdev_priv(dev); + struct sockaddr mac; + int err; + + ether_setup(dev); + dev->watchdog_timeo = 10 * HZ; + err = ltq_etop_hw_init(dev); + if (err) + goto err_hw; + ltq_etop_change_mtu(dev, 1500); + + memcpy(&mac, &priv->pldata->mac, sizeof(struct sockaddr)); + if (!is_valid_ether_addr(mac.sa_data)) { + pr_warn("etop: invalid MAC, using random\n"); + random_ether_addr(mac.sa_data); + } + + err = ltq_etop_set_mac_address(dev, &mac); + if (err) + goto err_netdev; + ltq_etop_set_multicast_list(dev); + err = ltq_etop_mdio_init(dev); + if (err) + goto err_netdev; + return 0; + +err_netdev: + unregister_netdev(dev); + free_netdev(dev); +err_hw: + ltq_etop_hw_exit(dev); + return err; +} + +static void +ltq_etop_tx_timeout(struct net_device *dev) +{ + int err; + + ltq_etop_hw_exit(dev); + err = ltq_etop_hw_init(dev); + if (err) + goto err_hw; + dev->trans_start = jiffies; + netif_wake_queue(dev); + return; + +err_hw: + ltq_etop_hw_exit(dev); + netdev_err(dev, "failed to restart etop after TX timeout\n"); +} + +static const struct net_device_ops ltq_eth_netdev_ops = { + .ndo_open = ltq_etop_open, + .ndo_stop = ltq_etop_stop, + .ndo_start_xmit = ltq_etop_tx, + .ndo_change_mtu = ltq_etop_change_mtu, + .ndo_do_ioctl = ltq_etop_ioctl, + .ndo_set_mac_address = ltq_etop_set_mac_address, + .ndo_validate_addr = eth_validate_addr, + .ndo_set_multicast_list = ltq_etop_set_multicast_list, + .ndo_select_queue = ltq_etop_select_queue, + .ndo_init = ltq_etop_init, + .ndo_tx_timeout = ltq_etop_tx_timeout, +}; + +static int __init +ltq_etop_probe(struct platform_device *pdev) +{ + struct net_device *dev; + struct ltq_etop_priv *priv; + struct resource *res; + int err; + int i; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) { + dev_err(&pdev->dev, "failed to get etop resource\n"); + err = -ENOENT; + goto err_out; + } + + res = devm_request_mem_region(&pdev->dev, res->start, + resource_size(res), dev_name(&pdev->dev)); + if (!res) { + dev_err(&pdev->dev, "failed to request etop resource\n"); + err = -EBUSY; + goto err_out; + } + + ltq_etop_membase = devm_ioremap_nocache(&pdev->dev, + res->start, resource_size(res)); + if (!ltq_etop_membase) { + dev_err(&pdev->dev, "failed to remap etop engine %d\n", + pdev->id); + err = -ENOMEM; + goto err_out; + } + + dev = alloc_etherdev_mq(sizeof(struct ltq_etop_priv), 4); + strcpy(dev->name, "eth%d"); + dev->netdev_ops = <q_eth_netdev_ops; + dev->ethtool_ops = <q_etop_ethtool_ops; + priv = netdev_priv(dev); + priv->res = res; + priv->pldata = dev_get_platdata(&pdev->dev); + priv->netdev = dev; + spin_lock_init(&priv->lock); + + for (i = 0; i < MAX_DMA_CHAN; i++) { + if (IS_TX(i)) + netif_napi_add(dev, &priv->ch[i].napi, + ltq_etop_poll_tx, 8); + else if (IS_RX(i)) + netif_napi_add(dev, &priv->ch[i].napi, + ltq_etop_poll_rx, 32); + priv->ch[i].netdev = dev; + } + + err = register_netdev(dev); + if (err) + goto err_free; + + platform_set_drvdata(pdev, dev); + return 0; + +err_free: + kfree(dev); +err_out: + return err; +} + +static int __devexit +ltq_etop_remove(struct platform_device *pdev) +{ + struct net_device *dev = platform_get_drvdata(pdev); + + if (dev) { + netif_tx_stop_all_queues(dev); + ltq_etop_hw_exit(dev); + ltq_etop_mdio_cleanup(dev); + unregister_netdev(dev); + } + return 0; +} + +static struct platform_driver ltq_mii_driver = { + .remove = __devexit_p(ltq_etop_remove), + .driver = { + .name = "ltq_etop", + .owner = THIS_MODULE, + }, +}; + +int __init +init_ltq_etop(void) +{ + int ret = platform_driver_probe(<q_mii_driver, ltq_etop_probe); + + if (ret) + pr_err("ltq_etop: Error registering platfom driver!"); + return ret; +} + +static void __exit +exit_ltq_etop(void) +{ + platform_driver_unregister(<q_mii_driver); +} + +module_init(init_ltq_etop); +module_exit(exit_ltq_etop); + +MODULE_AUTHOR("John Crispin "); +MODULE_DESCRIPTION("Lantiq SoC ETOP"); +MODULE_LICENSE("GPL"); -- cgit v0.10.2 From f1f0ceaada9d040a41023017c87abb1d651b44af Mon Sep 17 00:00:00 2001 From: John Crispin Date: Fri, 6 May 2011 00:10:02 +0200 Subject: MIPS: Lantiq: Add etop board support Register the etop platform device inside the machtype specific init code. Signed-off-by: John Crispin Signed-off-by: Ralph Hempel Signed-off-by: David Daney Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/2356/ Patchwork: https://patchwork.linux-mips.org/patch/2370/ Signed-off-by: Ralf Baechle diff --git a/arch/mips/lantiq/xway/mach-easy50712.c b/arch/mips/lantiq/xway/mach-easy50712.c index e5e7e09..ea5027b 100644 --- a/arch/mips/lantiq/xway/mach-easy50712.c +++ b/arch/mips/lantiq/xway/mach-easy50712.c @@ -12,6 +12,7 @@ #include #include #include +#include #include #include @@ -55,11 +56,16 @@ static struct ltq_pci_data ltq_pci_data = { }, }; +static struct ltq_eth_data ltq_eth_data = { + .mii_mode = PHY_INTERFACE_MODE_MII, +}; + static void __init easy50712_init(void) { ltq_register_gpio_stp(); ltq_register_nor(&easy50712_flash_data); ltq_register_pci(<q_pci_data); + ltq_register_etop(<q_eth_data); } MIPS_MACHINE(LTQ_MACH_EASY50712, -- cgit v0.10.2 From 2f58b8d04e680ec13157ba6eee44455438c56d5f Mon Sep 17 00:00:00 2001 From: John Crispin Date: Thu, 5 May 2011 23:00:23 +0200 Subject: MIPS: Lantiq: Add watchdog support This patch adds the driver for the watchdog found inside the Lantiq SoC family. Signed-off-by: John Crispin Signed-off-by: Ralph Hempel Cc: Wim Van Sebroeck Cc: linux-mips@linux-mips.org Cc: linux-watchdog@vger.kernel.org Patchwork: https://patchwork.linux-mips.org/patch/2327/ Signed-off-by: Ralf Baechle diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig index 1b0f98b..022f9eb 100644 --- a/drivers/watchdog/Kconfig +++ b/drivers/watchdog/Kconfig @@ -990,6 +990,12 @@ config BCM63XX_WDT To compile this driver as a loadable module, choose M here. The module will be called bcm63xx_wdt. +config LANTIQ_WDT + tristate "Lantiq SoC watchdog" + depends on LANTIQ + help + Hardware driver for the Lantiq SoC Watchdog Timer. + # PARISC Architecture # POWERPC Architecture diff --git a/drivers/watchdog/Makefile b/drivers/watchdog/Makefile index 3f8608b..ed26f70 100644 --- a/drivers/watchdog/Makefile +++ b/drivers/watchdog/Makefile @@ -123,6 +123,7 @@ obj-$(CONFIG_AR7_WDT) += ar7_wdt.o obj-$(CONFIG_TXX9_WDT) += txx9wdt.o obj-$(CONFIG_OCTEON_WDT) += octeon-wdt.o octeon-wdt-y := octeon-wdt-main.o octeon-wdt-nmi.o +obj-$(CONFIG_LANTIQ_WDT) += lantiq_wdt.o # PARISC Architecture diff --git a/drivers/watchdog/lantiq_wdt.c b/drivers/watchdog/lantiq_wdt.c new file mode 100644 index 0000000..7d82ada --- /dev/null +++ b/drivers/watchdog/lantiq_wdt.c @@ -0,0 +1,261 @@ +/* + * 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) 2010 John Crispin + * Based on EP93xx wdt driver + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +/* Section 3.4 of the datasheet + * The password sequence protects the WDT control register from unintended + * write actions, which might cause malfunction of the WDT. + * + * essentially the following two magic passwords need to be written to allow + * IO access to the WDT core + */ +#define LTQ_WDT_PW1 0x00BE0000 +#define LTQ_WDT_PW2 0x00DC0000 + +#define LTQ_WDT_CR 0x0 /* watchdog control register */ +#define LTQ_WDT_SR 0x8 /* watchdog status register */ + +#define LTQ_WDT_SR_EN (0x1 << 31) /* enable bit */ +#define LTQ_WDT_SR_PWD (0x3 << 26) /* turn on power */ +#define LTQ_WDT_SR_CLKDIV (0x3 << 24) /* turn on clock and set */ + /* divider to 0x40000 */ +#define LTQ_WDT_DIVIDER 0x40000 +#define LTQ_MAX_TIMEOUT ((1 << 16) - 1) /* the reload field is 16 bit */ + +static int nowayout = WATCHDOG_NOWAYOUT; + +static void __iomem *ltq_wdt_membase; +static unsigned long ltq_io_region_clk_rate; + +static unsigned long ltq_wdt_bootstatus; +static unsigned long ltq_wdt_in_use; +static int ltq_wdt_timeout = 30; +static int ltq_wdt_ok_to_close; + +static void +ltq_wdt_enable(void) +{ + ltq_wdt_timeout = ltq_wdt_timeout * + (ltq_io_region_clk_rate / LTQ_WDT_DIVIDER) + 0x1000; + if (ltq_wdt_timeout > LTQ_MAX_TIMEOUT) + ltq_wdt_timeout = LTQ_MAX_TIMEOUT; + + /* write the first password magic */ + ltq_w32(LTQ_WDT_PW1, ltq_wdt_membase + LTQ_WDT_CR); + /* write the second magic plus the configuration and new timeout */ + ltq_w32(LTQ_WDT_SR_EN | LTQ_WDT_SR_PWD | LTQ_WDT_SR_CLKDIV | + LTQ_WDT_PW2 | ltq_wdt_timeout, ltq_wdt_membase + LTQ_WDT_CR); +} + +static void +ltq_wdt_disable(void) +{ + /* write the first password magic */ + ltq_w32(LTQ_WDT_PW1, ltq_wdt_membase + LTQ_WDT_CR); + /* write the second password magic with no config + * this turns the watchdog off + */ + ltq_w32(LTQ_WDT_PW2, ltq_wdt_membase + LTQ_WDT_CR); +} + +static ssize_t +ltq_wdt_write(struct file *file, const char __user *data, + size_t len, loff_t *ppos) +{ + if (len) { + if (!nowayout) { + size_t i; + + ltq_wdt_ok_to_close = 0; + for (i = 0; i != len; i++) { + char c; + + if (get_user(c, data + i)) + return -EFAULT; + if (c == 'V') + ltq_wdt_ok_to_close = 1; + else + ltq_wdt_ok_to_close = 0; + } + } + ltq_wdt_enable(); + } + + return len; +} + +static struct watchdog_info ident = { + .options = WDIOF_MAGICCLOSE | WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING | + WDIOF_CARDRESET, + .identity = "ltq_wdt", +}; + +static long +ltq_wdt_ioctl(struct file *file, + unsigned int cmd, unsigned long arg) +{ + int ret = -ENOTTY; + + switch (cmd) { + case WDIOC_GETSUPPORT: + ret = copy_to_user((struct watchdog_info __user *)arg, &ident, + sizeof(ident)) ? -EFAULT : 0; + break; + + case WDIOC_GETBOOTSTATUS: + ret = put_user(ltq_wdt_bootstatus, (int __user *)arg); + break; + + case WDIOC_GETSTATUS: + ret = put_user(0, (int __user *)arg); + break; + + case WDIOC_SETTIMEOUT: + ret = get_user(ltq_wdt_timeout, (int __user *)arg); + if (!ret) + ltq_wdt_enable(); + /* intentional drop through */ + case WDIOC_GETTIMEOUT: + ret = put_user(ltq_wdt_timeout, (int __user *)arg); + break; + + case WDIOC_KEEPALIVE: + ltq_wdt_enable(); + ret = 0; + break; + } + return ret; +} + +static int +ltq_wdt_open(struct inode *inode, struct file *file) +{ + if (test_and_set_bit(0, <q_wdt_in_use)) + return -EBUSY; + ltq_wdt_in_use = 1; + ltq_wdt_enable(); + + return nonseekable_open(inode, file); +} + +static int +ltq_wdt_release(struct inode *inode, struct file *file) +{ + if (ltq_wdt_ok_to_close) + ltq_wdt_disable(); + else + pr_err("ltq_wdt: watchdog closed without warning\n"); + ltq_wdt_ok_to_close = 0; + clear_bit(0, <q_wdt_in_use); + + return 0; +} + +static const struct file_operations ltq_wdt_fops = { + .owner = THIS_MODULE, + .write = ltq_wdt_write, + .unlocked_ioctl = ltq_wdt_ioctl, + .open = ltq_wdt_open, + .release = ltq_wdt_release, + .llseek = no_llseek, +}; + +static struct miscdevice ltq_wdt_miscdev = { + .minor = WATCHDOG_MINOR, + .name = "watchdog", + .fops = <q_wdt_fops, +}; + +static int __init +ltq_wdt_probe(struct platform_device *pdev) +{ + struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + struct clk *clk; + + if (!res) { + dev_err(&pdev->dev, "cannot obtain I/O memory region"); + return -ENOENT; + } + res = devm_request_mem_region(&pdev->dev, res->start, + resource_size(res), dev_name(&pdev->dev)); + if (!res) { + dev_err(&pdev->dev, "cannot request I/O memory region"); + return -EBUSY; + } + ltq_wdt_membase = devm_ioremap_nocache(&pdev->dev, res->start, + resource_size(res)); + if (!ltq_wdt_membase) { + dev_err(&pdev->dev, "cannot remap I/O memory region\n"); + return -ENOMEM; + } + + /* we do not need to enable the clock as it is always running */ + clk = clk_get(&pdev->dev, "io"); + WARN_ON(!clk); + ltq_io_region_clk_rate = clk_get_rate(clk); + clk_put(clk); + + if (ltq_reset_cause() == LTQ_RST_CAUSE_WDTRST) + ltq_wdt_bootstatus = WDIOF_CARDRESET; + + return misc_register(<q_wdt_miscdev); +} + +static int __devexit +ltq_wdt_remove(struct platform_device *pdev) +{ + misc_deregister(<q_wdt_miscdev); + + if (ltq_wdt_membase) + iounmap(ltq_wdt_membase); + + return 0; +} + + +static struct platform_driver ltq_wdt_driver = { + .remove = __devexit_p(ltq_wdt_remove), + .driver = { + .name = "ltq_wdt", + .owner = THIS_MODULE, + }, +}; + +static int __init +init_ltq_wdt(void) +{ + return platform_driver_probe(<q_wdt_driver, ltq_wdt_probe); +} + +static void __exit +exit_ltq_wdt(void) +{ + return platform_driver_unregister(<q_wdt_driver); +} + +module_init(init_ltq_wdt); +module_exit(exit_ltq_wdt); + +module_param(nowayout, int, 0); +MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started"); + +MODULE_AUTHOR("John Crispin "); +MODULE_DESCRIPTION("Lantiq SoC Watchdog"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR); -- cgit v0.10.2 From 4f0ad950880a33df792b1e63649e29f8784b0163 Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Thu, 19 May 2011 09:21:28 +0100 Subject: MIPS: IP27: Remove pointless switch statement. Signed-off-by: Ralf Baechle diff --git a/arch/mips/sgi-ip27/ip27-timer.c b/arch/mips/sgi-ip27/ip27-timer.c index a152538..3f810c9 100644 --- a/arch/mips/sgi-ip27/ip27-timer.c +++ b/arch/mips/sgi-ip27/ip27-timer.c @@ -66,18 +66,7 @@ static int rt_next_event(unsigned long delta, struct clock_event_device *evt) static void rt_set_mode(enum clock_event_mode mode, struct clock_event_device *evt) { - switch (mode) { - case CLOCK_EVT_MODE_ONESHOT: - /* The only mode supported */ - break; - - case CLOCK_EVT_MODE_PERIODIC: - case CLOCK_EVT_MODE_UNUSED: - case CLOCK_EVT_MODE_SHUTDOWN: - case CLOCK_EVT_MODE_RESUME: - /* Nothing to do */ - break; - } + /* Nothing to do ... */ } int rt_timer_irq; -- cgit v0.10.2 From c19c20ac6338435469a2c222ef5dc55e0469a6dc Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Thu, 19 May 2011 09:21:28 +0100 Subject: MIPS: Use single define for pending work on syscall exit Signed-off-by: Ralf Baechle diff --git a/arch/mips/include/asm/thread_info.h b/arch/mips/include/asm/thread_info.h index d71160d..97f8bf6 100644 --- a/arch/mips/include/asm/thread_info.h +++ b/arch/mips/include/asm/thread_info.h @@ -149,6 +149,9 @@ register struct thread_info *__current_thread_info __asm__("$28"); #define _TIF_FPUBOUND (1< Date: Thu, 19 May 2011 09:21:29 +0100 Subject: MIPS: Split do_syscall_trace into two functions. Signed-off-by: Ralf Baechle diff --git a/arch/mips/include/asm/ptrace.h b/arch/mips/include/asm/ptrace.h index 9f1b8db..de39b1f 100644 --- a/arch/mips/include/asm/ptrace.h +++ b/arch/mips/include/asm/ptrace.h @@ -141,7 +141,8 @@ extern int ptrace_set_watch_regs(struct task_struct *child, #define instruction_pointer(regs) ((regs)->cp0_epc) #define profile_pc(regs) instruction_pointer(regs) -extern asmlinkage void do_syscall_trace(struct pt_regs *regs, int entryexit); +extern asmlinkage void syscall_trace_enter(struct pt_regs *regs); +extern asmlinkage void syscall_trace_leave(struct pt_regs *regs); extern NORET_TYPE void die(const char *, struct pt_regs *) ATTRIB_NORET; diff --git a/arch/mips/kernel/entry.S b/arch/mips/kernel/entry.S index a917e34..37acfa0 100644 --- a/arch/mips/kernel/entry.S +++ b/arch/mips/kernel/entry.S @@ -170,11 +170,10 @@ syscall_exit_work: li t0, _TIF_WORK_SYSCALL_EXIT and t0, a2 # a2 is preloaded with TI_FLAGS beqz t0, work_pending # trace bit set? - local_irq_enable # could let do_syscall_trace() + local_irq_enable # could let syscall_trace_leave() # call schedule() instead move a0, sp - li a1, 1 - jal do_syscall_trace + jal syscall_trace_leave b resume_userspace #if defined(CONFIG_CPU_MIPSR2) || defined(CONFIG_MIPS_MT) diff --git a/arch/mips/kernel/ptrace.c b/arch/mips/kernel/ptrace.c index 584e6b5..4e6ea1f 100644 --- a/arch/mips/kernel/ptrace.c +++ b/arch/mips/kernel/ptrace.c @@ -533,15 +533,10 @@ static inline int audit_arch(void) * Notification of system call entry/exit * - triggered by current->work.syscall_trace */ -asmlinkage void do_syscall_trace(struct pt_regs *regs, int entryexit) +asmlinkage void syscall_trace_enter(struct pt_regs *regs) { /* do the secure computing check first */ - if (!entryexit) - secure_computing(regs->regs[2]); - - if (unlikely(current->audit_context) && entryexit) - audit_syscall_exit(AUDITSC_RESULT(regs->regs[7]), - -regs->regs[2]); + secure_computing(regs->regs[2]); if (!(current->ptrace & PT_PTRACED)) goto out; @@ -565,8 +560,40 @@ asmlinkage void do_syscall_trace(struct pt_regs *regs, int entryexit) } out: - if (unlikely(current->audit_context) && !entryexit) + if (unlikely(current->audit_context)) audit_syscall_entry(audit_arch(), regs->regs[2], regs->regs[4], regs->regs[5], regs->regs[6], regs->regs[7]); } + +/* + * Notification of system call entry/exit + * - triggered by current->work.syscall_trace + */ +asmlinkage void syscall_trace_leave(struct pt_regs *regs) +{ + if (unlikely(current->audit_context)) + audit_syscall_exit(AUDITSC_RESULT(regs->regs[7]), + -regs->regs[2]); + + if (!(current->ptrace & PT_PTRACED)) + return; + + if (!test_thread_flag(TIF_SYSCALL_TRACE)) + return; + + /* The 0x80 provides a way for the tracing parent to distinguish + between a syscall stop and SIGTRAP delivery */ + ptrace_notify(SIGTRAP | ((current->ptrace & PT_TRACESYSGOOD) ? + 0x80 : 0)); + + /* + * this isn't the same as continuing with a signal, but it will do + * for normal use. strace only continues with a signal if the + * stopping signal is not SIGTRAP. -brl + */ + if (current->exit_code) { + send_sig(current->exit_code, current, 1); + current->exit_code = 0; + } +} diff --git a/arch/mips/kernel/scall32-o32.S b/arch/mips/kernel/scall32-o32.S index 7f1377e..7a8e1dd 100644 --- a/arch/mips/kernel/scall32-o32.S +++ b/arch/mips/kernel/scall32-o32.S @@ -88,8 +88,7 @@ syscall_trace_entry: SAVE_STATIC move s0, t2 move a0, sp - li a1, 0 - jal do_syscall_trace + jal syscall_trace_enter move t0, s0 RESTORE_STATIC diff --git a/arch/mips/kernel/scall64-64.S b/arch/mips/kernel/scall64-64.S index 7c0ef7f..2d31c83 100644 --- a/arch/mips/kernel/scall64-64.S +++ b/arch/mips/kernel/scall64-64.S @@ -91,8 +91,7 @@ syscall_trace_entry: SAVE_STATIC move s0, t2 move a0, sp - li a1, 0 - jal do_syscall_trace + jal syscall_trace_enter move t0, s0 RESTORE_STATIC diff --git a/arch/mips/kernel/scall64-n32.S b/arch/mips/kernel/scall64-n32.S index de6c556..38a0503 100644 --- a/arch/mips/kernel/scall64-n32.S +++ b/arch/mips/kernel/scall64-n32.S @@ -89,8 +89,7 @@ n32_syscall_trace_entry: SAVE_STATIC move s0, t2 move a0, sp - li a1, 0 - jal do_syscall_trace + jal syscall_trace_enter move t0, s0 RESTORE_STATIC diff --git a/arch/mips/kernel/scall64-o32.S b/arch/mips/kernel/scall64-o32.S index b0541dd..91ea5e4 100644 --- a/arch/mips/kernel/scall64-o32.S +++ b/arch/mips/kernel/scall64-o32.S @@ -123,8 +123,7 @@ trace_a_syscall: move s0, t2 # Save syscall pointer move a0, sp - li a1, 0 - jal do_syscall_trace + jal syscall_trace_enter move t0, s0 RESTORE_STATIC -- cgit v0.10.2 From 0591128066bdfe07e0ef0ab7f877f794d8ba071d Mon Sep 17 00:00:00 2001 From: Manuel Lauss Date: Sun, 8 May 2011 10:42:12 +0200 Subject: MIPS: DB1200: Set Config[OD] for improved stability. Setting Config[OD] gets rid of a _LOT_ of spurious CPLD interrupts, but also decreases overall performance a bit. Signed-off-by: Manuel Lauss To: Linux-MIPS Cc: Florian Fainelli Cc: Wolfgang Grandegger Patchwork: https://patchwork.linux-mips.org/patch/2347/ Signed-off-by: Ralf Baechle diff --git a/arch/mips/alchemy/common/setup.c b/arch/mips/alchemy/common/setup.c index 561e5da..1b887c8 100644 --- a/arch/mips/alchemy/common/setup.c +++ b/arch/mips/alchemy/common/setup.c @@ -52,8 +52,6 @@ void __init plat_mem_setup(void) /* this is faster than wasting cycles trying to approximate it */ preset_lpj = (est_freq >> 1) / HZ; - board_setup(); /* board specific setup */ - if (au1xxx_cpu_needs_config_od()) /* Various early Au1xx0 errata corrected by this */ set_c0_config(1 << 19); /* Set Config[OD] */ @@ -61,6 +59,8 @@ void __init plat_mem_setup(void) /* Clear to obtain best system bus performance */ clear_c0_config(1 << 19); /* Clear Config[OD] */ + board_setup(); /* board specific setup */ + /* IO/MEM resources. */ set_io_port_base(0); ioport_resource.start = IOPORT_RESOURCE_START; diff --git a/arch/mips/alchemy/devboards/db1200/setup.c b/arch/mips/alchemy/devboards/db1200/setup.c index 4a89800..1dac4f2 100644 --- a/arch/mips/alchemy/devboards/db1200/setup.c +++ b/arch/mips/alchemy/devboards/db1200/setup.c @@ -23,6 +23,13 @@ void __init board_setup(void) unsigned long freq0, clksrc, div, pfc; unsigned short whoami; + /* Set Config[OD] (disable overlapping bus transaction): + * This gets rid of a _lot_ of spurious interrupts (especially + * wrt. IDE); but incurs ~10% performance hit in some + * cpu-bound applications. + */ + set_c0_config(1 << 19); + bcsr_init(DB1200_BCSR_PHYS_ADDR, DB1200_BCSR_PHYS_ADDR + DB1200_BCSR_HEXLED_OFS); -- cgit v0.10.2 From c1e58a3129bc327f7e0eb06fd4fe5ebf2af5d8ef Mon Sep 17 00:00:00 2001 From: Manuel Lauss Date: Sun, 8 May 2011 10:42:13 +0200 Subject: MIPS: Alchemy: update inlinable GPIO API This fixes a build failure with gpio_keys and CONFIG_GPIOLIB=n (mtx1): CC drivers/input/keyboard/gpio_keys.o gpio_keys.c: In function 'gpio_keys_report_event': gpio_keys.c:325:2: error: implicit declaration of function 'gpio_get_value_cansleep' gpio_keys.c: In function 'gpio_keys_setup_key': gpio_keys.c:390:3: error: implicit declaration of function 'gpio_set_debounce' Also add stubs for the other new functions. Signed-off-by: Manuel Lauss To: Linux-MIPS Cc: Florian Fainelli Cc: Wolfgang Grandegger Patchwork: https://patchwork.linux-mips.org/patch/2346/ Signed-off-by: Ralf Baechle diff --git a/arch/mips/include/asm/mach-au1x00/gpio-au1000.h b/arch/mips/include/asm/mach-au1x00/gpio-au1000.h index 62d2f13..8f8c1c5 100644 --- a/arch/mips/include/asm/mach-au1x00/gpio-au1000.h +++ b/arch/mips/include/asm/mach-au1x00/gpio-au1000.h @@ -24,6 +24,7 @@ #define MAKE_IRQ(intc, off) (AU1000_INTC##intc##_INT_BASE + (off)) +struct gpio; static inline int au1000_gpio1_to_irq(int gpio) { @@ -556,6 +557,16 @@ static inline void gpio_set_value(int gpio, int v) alchemy_gpio_set_value(gpio, v); } +static inline int gpio_get_value_cansleep(unsigned gpio) +{ + return gpio_get_value(gpio); +} + +static inline void gpio_set_value_cansleep(unsigned gpio, int value) +{ + gpio_set_value(gpio, value); +} + static inline int gpio_is_valid(int gpio) { return alchemy_gpio_is_valid(gpio); @@ -581,10 +592,50 @@ static inline int gpio_request(unsigned gpio, const char *label) return 0; } +static inline int gpio_request_one(unsigned gpio, + unsigned long flags, const char *label) +{ + return 0; +} + +static inline int gpio_request_array(struct gpio *array, size_t num) +{ + return 0; +} + static inline void gpio_free(unsigned gpio) { } +static inline void gpio_free_array(struct gpio *array, size_t num) +{ +} + +static inline int gpio_set_debounce(unsigned gpio, unsigned debounce) +{ + return -ENOSYS; +} + +static inline int gpio_export(unsigned gpio, bool direction_may_change) +{ + return -ENOSYS; +} + +static inline int gpio_export_link(struct device *dev, const char *name, + unsigned gpio) +{ + return -ENOSYS; +} + +static inline int gpio_sysfs_set_active_low(unsigned gpio, int value) +{ + return -ENOSYS; +} + +static inline void gpio_unexport(unsigned gpio) +{ +} + #endif /* !CONFIG_ALCHEMY_GPIO_INDIRECT */ -- cgit v0.10.2 From dca7587185b3a499a09a9e2755316eee31c49c7f Mon Sep 17 00:00:00 2001 From: Manuel Lauss Date: Sun, 8 May 2011 10:42:14 +0200 Subject: MIPS: Alchemy: irq code and constant cleanup replace au_readl/au_writel with __raw_readl/__raw_writel, and clean up IC-related stuff from the headers. Signed-off-by: Manuel Lauss To: Linux-MIPS Cc: Florian Fainelli Cc: Wolfgang Grandegger Patchwork: https://patchwork.linux-mips.org/patch/2354/ Signed-off-by: Ralf Baechle diff --git a/arch/mips/alchemy/common/irq.c b/arch/mips/alchemy/common/irq.c index 55dd7c8..b72e128 100644 --- a/arch/mips/alchemy/common/irq.c +++ b/arch/mips/alchemy/common/irq.c @@ -39,6 +39,36 @@ #include #endif +/* Interrupt Controller register offsets */ +#define IC_CFG0RD 0x40 +#define IC_CFG0SET 0x40 +#define IC_CFG0CLR 0x44 +#define IC_CFG1RD 0x48 +#define IC_CFG1SET 0x48 +#define IC_CFG1CLR 0x4C +#define IC_CFG2RD 0x50 +#define IC_CFG2SET 0x50 +#define IC_CFG2CLR 0x54 +#define IC_REQ0INT 0x54 +#define IC_SRCRD 0x58 +#define IC_SRCSET 0x58 +#define IC_SRCCLR 0x5C +#define IC_REQ1INT 0x5C +#define IC_ASSIGNRD 0x60 +#define IC_ASSIGNSET 0x60 +#define IC_ASSIGNCLR 0x64 +#define IC_WAKERD 0x68 +#define IC_WAKESET 0x68 +#define IC_WAKECLR 0x6C +#define IC_MASKRD 0x70 +#define IC_MASKSET 0x70 +#define IC_MASKCLR 0x74 +#define IC_RISINGRD 0x78 +#define IC_RISINGCLR 0x78 +#define IC_FALLINGRD 0x7C +#define IC_FALLINGCLR 0x7C +#define IC_TESTBIT 0x80 + static int au1x_ic_settype(struct irq_data *d, unsigned int flow_type); /* NOTE on interrupt priorities: The original writers of this code said: @@ -221,89 +251,101 @@ struct au1xxx_irqmap au1200_irqmap[] __initdata = { static void au1x_ic0_unmask(struct irq_data *d) { unsigned int bit = d->irq - AU1000_INTC0_INT_BASE; - au_writel(1 << bit, IC0_MASKSET); - au_writel(1 << bit, IC0_WAKESET); - au_sync(); + void __iomem *base = (void __iomem *)KSEG1ADDR(AU1000_IC0_PHYS_ADDR); + + __raw_writel(1 << bit, base + IC_MASKSET); + __raw_writel(1 << bit, base + IC_WAKESET); + wmb(); } static void au1x_ic1_unmask(struct irq_data *d) { unsigned int bit = d->irq - AU1000_INTC1_INT_BASE; - au_writel(1 << bit, IC1_MASKSET); - au_writel(1 << bit, IC1_WAKESET); + void __iomem *base = (void __iomem *)KSEG1ADDR(AU1000_IC1_PHYS_ADDR); + + __raw_writel(1 << bit, base + IC_MASKSET); + __raw_writel(1 << bit, base + IC_WAKESET); /* very hacky. does the pb1000 cpld auto-disable this int? * nowhere in the current kernel sources is it disabled. --mlau */ #if defined(CONFIG_MIPS_PB1000) if (d->irq == AU1000_GPIO15_INT) - au_writel(0x4000, PB1000_MDR); /* enable int */ + __raw_writel(0x4000, (void __iomem *)PB1000_MDR); /* enable int */ #endif - au_sync(); + wmb(); } static void au1x_ic0_mask(struct irq_data *d) { unsigned int bit = d->irq - AU1000_INTC0_INT_BASE; - au_writel(1 << bit, IC0_MASKCLR); - au_writel(1 << bit, IC0_WAKECLR); - au_sync(); + void __iomem *base = (void __iomem *)KSEG1ADDR(AU1000_IC0_PHYS_ADDR); + + __raw_writel(1 << bit, base + IC_MASKCLR); + __raw_writel(1 << bit, base + IC_WAKECLR); + wmb(); } static void au1x_ic1_mask(struct irq_data *d) { unsigned int bit = d->irq - AU1000_INTC1_INT_BASE; - au_writel(1 << bit, IC1_MASKCLR); - au_writel(1 << bit, IC1_WAKECLR); - au_sync(); + void __iomem *base = (void __iomem *)KSEG1ADDR(AU1000_IC1_PHYS_ADDR); + + __raw_writel(1 << bit, base + IC_MASKCLR); + __raw_writel(1 << bit, base + IC_WAKECLR); + wmb(); } static void au1x_ic0_ack(struct irq_data *d) { unsigned int bit = d->irq - AU1000_INTC0_INT_BASE; + void __iomem *base = (void __iomem *)KSEG1ADDR(AU1000_IC0_PHYS_ADDR); /* * This may assume that we don't get interrupts from * both edges at once, or if we do, that we don't care. */ - au_writel(1 << bit, IC0_FALLINGCLR); - au_writel(1 << bit, IC0_RISINGCLR); - au_sync(); + __raw_writel(1 << bit, base + IC_FALLINGCLR); + __raw_writel(1 << bit, base + IC_RISINGCLR); + wmb(); } static void au1x_ic1_ack(struct irq_data *d) { unsigned int bit = d->irq - AU1000_INTC1_INT_BASE; + void __iomem *base = (void __iomem *)KSEG1ADDR(AU1000_IC1_PHYS_ADDR); /* * This may assume that we don't get interrupts from * both edges at once, or if we do, that we don't care. */ - au_writel(1 << bit, IC1_FALLINGCLR); - au_writel(1 << bit, IC1_RISINGCLR); - au_sync(); + __raw_writel(1 << bit, base + IC_FALLINGCLR); + __raw_writel(1 << bit, base + IC_RISINGCLR); + wmb(); } static void au1x_ic0_maskack(struct irq_data *d) { unsigned int bit = d->irq - AU1000_INTC0_INT_BASE; + void __iomem *base = (void __iomem *)KSEG1ADDR(AU1000_IC0_PHYS_ADDR); - au_writel(1 << bit, IC0_WAKECLR); - au_writel(1 << bit, IC0_MASKCLR); - au_writel(1 << bit, IC0_RISINGCLR); - au_writel(1 << bit, IC0_FALLINGCLR); - au_sync(); + __raw_writel(1 << bit, base + IC_WAKECLR); + __raw_writel(1 << bit, base + IC_MASKCLR); + __raw_writel(1 << bit, base + IC_RISINGCLR); + __raw_writel(1 << bit, base + IC_FALLINGCLR); + wmb(); } static void au1x_ic1_maskack(struct irq_data *d) { unsigned int bit = d->irq - AU1000_INTC1_INT_BASE; + void __iomem *base = (void __iomem *)KSEG1ADDR(AU1000_IC1_PHYS_ADDR); - au_writel(1 << bit, IC1_WAKECLR); - au_writel(1 << bit, IC1_MASKCLR); - au_writel(1 << bit, IC1_RISINGCLR); - au_writel(1 << bit, IC1_FALLINGCLR); - au_sync(); + __raw_writel(1 << bit, base + IC_WAKECLR); + __raw_writel(1 << bit, base + IC_MASKCLR); + __raw_writel(1 << bit, base + IC_RISINGCLR); + __raw_writel(1 << bit, base + IC_FALLINGCLR); + wmb(); } static int au1x_ic1_setwake(struct irq_data *d, unsigned int on) @@ -318,13 +360,13 @@ static int au1x_ic1_setwake(struct irq_data *d, unsigned int on) return -EINVAL; local_irq_save(flags); - wakemsk = au_readl(SYS_WAKEMSK); + wakemsk = __raw_readl((void __iomem *)SYS_WAKEMSK); if (on) wakemsk |= 1 << bit; else wakemsk &= ~(1 << bit); - au_writel(wakemsk, SYS_WAKEMSK); - au_sync(); + __raw_writel(wakemsk, (void __iomem *)SYS_WAKEMSK); + wmb(); local_irq_restore(flags); return 0; @@ -356,81 +398,74 @@ static struct irq_chip au1x_ic1_chip = { static int au1x_ic_settype(struct irq_data *d, unsigned int flow_type) { struct irq_chip *chip; - unsigned long icr[6]; - unsigned int bit, ic, irq = d->irq; + unsigned int bit, irq = d->irq; irq_flow_handler_t handler = NULL; unsigned char *name = NULL; + void __iomem *base; int ret; if (irq >= AU1000_INTC1_INT_BASE) { bit = irq - AU1000_INTC1_INT_BASE; chip = &au1x_ic1_chip; - ic = 1; + base = (void __iomem *)KSEG1ADDR(AU1000_IC1_PHYS_ADDR); } else { bit = irq - AU1000_INTC0_INT_BASE; chip = &au1x_ic0_chip; - ic = 0; + base = (void __iomem *)KSEG1ADDR(AU1000_IC0_PHYS_ADDR); } if (bit > 31) return -EINVAL; - icr[0] = ic ? IC1_CFG0SET : IC0_CFG0SET; - icr[1] = ic ? IC1_CFG1SET : IC0_CFG1SET; - icr[2] = ic ? IC1_CFG2SET : IC0_CFG2SET; - icr[3] = ic ? IC1_CFG0CLR : IC0_CFG0CLR; - icr[4] = ic ? IC1_CFG1CLR : IC0_CFG1CLR; - icr[5] = ic ? IC1_CFG2CLR : IC0_CFG2CLR; - ret = 0; switch (flow_type) { /* cfgregs 2:1:0 */ case IRQ_TYPE_EDGE_RISING: /* 0:0:1 */ - au_writel(1 << bit, icr[5]); - au_writel(1 << bit, icr[4]); - au_writel(1 << bit, icr[0]); + __raw_writel(1 << bit, base + IC_CFG2CLR); + __raw_writel(1 << bit, base + IC_CFG1CLR); + __raw_writel(1 << bit, base + IC_CFG0SET); handler = handle_edge_irq; name = "riseedge"; break; case IRQ_TYPE_EDGE_FALLING: /* 0:1:0 */ - au_writel(1 << bit, icr[5]); - au_writel(1 << bit, icr[1]); - au_writel(1 << bit, icr[3]); + __raw_writel(1 << bit, base + IC_CFG2CLR); + __raw_writel(1 << bit, base + IC_CFG1SET); + __raw_writel(1 << bit, base + IC_CFG0CLR); handler = handle_edge_irq; name = "falledge"; break; case IRQ_TYPE_EDGE_BOTH: /* 0:1:1 */ - au_writel(1 << bit, icr[5]); - au_writel(1 << bit, icr[1]); - au_writel(1 << bit, icr[0]); + __raw_writel(1 << bit, base + IC_CFG2CLR); + __raw_writel(1 << bit, base + IC_CFG1SET); + __raw_writel(1 << bit, base + IC_CFG0SET); handler = handle_edge_irq; name = "bothedge"; break; case IRQ_TYPE_LEVEL_HIGH: /* 1:0:1 */ - au_writel(1 << bit, icr[2]); - au_writel(1 << bit, icr[4]); - au_writel(1 << bit, icr[0]); + __raw_writel(1 << bit, base + IC_CFG2SET); + __raw_writel(1 << bit, base + IC_CFG1CLR); + __raw_writel(1 << bit, base + IC_CFG0SET); handler = handle_level_irq; name = "hilevel"; break; case IRQ_TYPE_LEVEL_LOW: /* 1:1:0 */ - au_writel(1 << bit, icr[2]); - au_writel(1 << bit, icr[1]); - au_writel(1 << bit, icr[3]); + __raw_writel(1 << bit, base + IC_CFG2SET); + __raw_writel(1 << bit, base + IC_CFG1SET); + __raw_writel(1 << bit, base + IC_CFG0CLR); handler = handle_level_irq; name = "lowlevel"; break; case IRQ_TYPE_NONE: /* 0:0:0 */ - au_writel(1 << bit, icr[5]); - au_writel(1 << bit, icr[4]); - au_writel(1 << bit, icr[3]); + __raw_writel(1 << bit, base + IC_CFG2CLR); + __raw_writel(1 << bit, base + IC_CFG1CLR); + __raw_writel(1 << bit, base + IC_CFG0CLR); break; default: ret = -EINVAL; } __irq_set_chip_handler_name_locked(d->irq, chip, handler, name); - au_sync(); + wmb(); return ret; } @@ -444,21 +479,21 @@ asmlinkage void plat_irq_dispatch(void) off = MIPS_CPU_IRQ_BASE + 7; goto handle; } else if (pending & CAUSEF_IP2) { - s = IC0_REQ0INT; + s = KSEG1ADDR(AU1000_IC0_PHYS_ADDR) + IC_REQ0INT; off = AU1000_INTC0_INT_BASE; } else if (pending & CAUSEF_IP3) { - s = IC0_REQ1INT; + s = KSEG1ADDR(AU1000_IC0_PHYS_ADDR) + IC_REQ1INT; off = AU1000_INTC0_INT_BASE; } else if (pending & CAUSEF_IP4) { - s = IC1_REQ0INT; + s = KSEG1ADDR(AU1000_IC1_PHYS_ADDR) + IC_REQ0INT; off = AU1000_INTC1_INT_BASE; } else if (pending & CAUSEF_IP5) { - s = IC1_REQ1INT; + s = KSEG1ADDR(AU1000_IC1_PHYS_ADDR) + IC_REQ1INT; off = AU1000_INTC1_INT_BASE; } else goto spurious; - s = au_readl(s); + s = __raw_readl((void __iomem *)s); if (unlikely(!s)) { spurious: spurious_interrupt(); @@ -469,48 +504,42 @@ handle: do_IRQ(off); } + +static inline void ic_init(void __iomem *base) +{ + /* initialize interrupt controller to a safe state */ + __raw_writel(0xffffffff, base + IC_CFG0CLR); + __raw_writel(0xffffffff, base + IC_CFG1CLR); + __raw_writel(0xffffffff, base + IC_CFG2CLR); + __raw_writel(0xffffffff, base + IC_MASKCLR); + __raw_writel(0xffffffff, base + IC_ASSIGNCLR); + __raw_writel(0xffffffff, base + IC_WAKECLR); + __raw_writel(0xffffffff, base + IC_SRCSET); + __raw_writel(0xffffffff, base + IC_FALLINGCLR); + __raw_writel(0xffffffff, base + IC_RISINGCLR); + __raw_writel(0x00000000, base + IC_TESTBIT); + wmb(); +} + static void __init au1000_init_irq(struct au1xxx_irqmap *map) { unsigned int bit, irq_nr; - int i; - - /* - * Initialize interrupt controllers to a safe state. - */ - au_writel(0xffffffff, IC0_CFG0CLR); - au_writel(0xffffffff, IC0_CFG1CLR); - au_writel(0xffffffff, IC0_CFG2CLR); - au_writel(0xffffffff, IC0_MASKCLR); - au_writel(0xffffffff, IC0_ASSIGNCLR); - au_writel(0xffffffff, IC0_WAKECLR); - au_writel(0xffffffff, IC0_SRCSET); - au_writel(0xffffffff, IC0_FALLINGCLR); - au_writel(0xffffffff, IC0_RISINGCLR); - au_writel(0x00000000, IC0_TESTBIT); - - au_writel(0xffffffff, IC1_CFG0CLR); - au_writel(0xffffffff, IC1_CFG1CLR); - au_writel(0xffffffff, IC1_CFG2CLR); - au_writel(0xffffffff, IC1_MASKCLR); - au_writel(0xffffffff, IC1_ASSIGNCLR); - au_writel(0xffffffff, IC1_WAKECLR); - au_writel(0xffffffff, IC1_SRCSET); - au_writel(0xffffffff, IC1_FALLINGCLR); - au_writel(0xffffffff, IC1_RISINGCLR); - au_writel(0x00000000, IC1_TESTBIT); + void __iomem *base; + ic_init((void __iomem *)KSEG1ADDR(AU1000_IC0_PHYS_ADDR)); + ic_init((void __iomem *)KSEG1ADDR(AU1000_IC1_PHYS_ADDR)); mips_cpu_irq_init(); /* register all 64 possible IC0+IC1 irq sources as type "none". * Use set_irq_type() to set edge/level behaviour at runtime. */ - for (i = AU1000_INTC0_INT_BASE; - (i < AU1000_INTC0_INT_BASE + 32); i++) - au1x_ic_settype(irq_get_irq_data(i), IRQ_TYPE_NONE); + for (irq_nr = AU1000_INTC0_INT_BASE; + (irq_nr < AU1000_INTC0_INT_BASE + 32); irq_nr++) + au1x_ic_settype(irq_get_irq_data(irq_nr), IRQ_TYPE_NONE); - for (i = AU1000_INTC1_INT_BASE; - (i < AU1000_INTC1_INT_BASE + 32); i++) - au1x_ic_settype(irq_get_irq_data(i), IRQ_TYPE_NONE); + for (irq_nr = AU1000_INTC1_INT_BASE; + (irq_nr < AU1000_INTC1_INT_BASE + 32); irq_nr++) + au1x_ic_settype(irq_get_irq_data(irq_nr), IRQ_TYPE_NONE); /* * Initialize IC0, which is fixed per processor. @@ -520,13 +549,13 @@ static void __init au1000_init_irq(struct au1xxx_irqmap *map) if (irq_nr >= AU1000_INTC1_INT_BASE) { bit = irq_nr - AU1000_INTC1_INT_BASE; - if (map->im_request) - au_writel(1 << bit, IC1_ASSIGNSET); + base = (void __iomem *)KSEG1ADDR(AU1000_IC1_PHYS_ADDR); } else { bit = irq_nr - AU1000_INTC0_INT_BASE; - if (map->im_request) - au_writel(1 << bit, IC0_ASSIGNSET); + base = (void __iomem *)KSEG1ADDR(AU1000_IC0_PHYS_ADDR); } + if (map->im_request) + __raw_writel(1 << bit, base + IC_ASSIGNSET); au1x_ic_settype(irq_get_irq_data(irq_nr), map->im_type); ++map; @@ -583,17 +612,8 @@ static int alchemy_ic_resume(struct sys_device *dev) struct alchemy_ic_sysdev *icdev = container_of(dev, struct alchemy_ic_sysdev, sysdev); - __raw_writel(0xffffffff, icdev->base + IC_MASKCLR); - __raw_writel(0xffffffff, icdev->base + IC_CFG0CLR); - __raw_writel(0xffffffff, icdev->base + IC_CFG1CLR); - __raw_writel(0xffffffff, icdev->base + IC_CFG2CLR); - __raw_writel(0xffffffff, icdev->base + IC_SRCCLR); - __raw_writel(0xffffffff, icdev->base + IC_ASSIGNCLR); - __raw_writel(0xffffffff, icdev->base + IC_WAKECLR); - __raw_writel(0xffffffff, icdev->base + IC_RISINGCLR); - __raw_writel(0xffffffff, icdev->base + IC_FALLINGCLR); - __raw_writel(0x00000000, icdev->base + IC_TESTBIT); - wmb(); + ic_init(icdev->base); + __raw_writel(icdev->pmdata[0], icdev->base + IC_CFG0SET); __raw_writel(icdev->pmdata[1], icdev->base + IC_CFG1SET); __raw_writel(icdev->pmdata[2], icdev->base + IC_CFG2SET); @@ -617,7 +637,7 @@ static struct sysdev_class alchemy_ic_sysdev_class = { static int __init alchemy_ic_sysdev_init(void) { struct alchemy_ic_sysdev *icdev; - unsigned long icbase[2] = { IC0_PHYS_ADDR, IC1_PHYS_ADDR }; + unsigned long icbase[2] = { AU1000_IC0_PHYS_ADDR, AU1000_IC1_PHYS_ADDR }; int err, i; err = sysdev_class_register(&alchemy_ic_sysdev_class); diff --git a/arch/mips/include/asm/mach-au1x00/au1000.h b/arch/mips/include/asm/mach-au1x00/au1000.h index a697661..66cfcdc 100644 --- a/arch/mips/include/asm/mach-au1x00/au1000.h +++ b/arch/mips/include/asm/mach-au1x00/au1000.h @@ -630,8 +630,13 @@ enum soc_au1200_ints { /* * Physical base addresses for integrated peripherals + * 0..au1000 1..au1500 2..au1100 3..au1550 4..au1200 */ +#define AU1000_IC0_PHYS_ADDR 0x10400000 /* 01234 */ +#define AU1000_IC1_PHYS_ADDR 0x11800000 /* 01234 */ + + #ifdef CONFIG_SOC_AU1000 #define MEM_PHYS_ADDR 0x14000000 #define STATIC_MEM_PHYS_ADDR 0x14001000 @@ -643,8 +648,6 @@ enum soc_au1200_ints { #define DMA5_PHYS_ADDR 0x14002500 #define DMA6_PHYS_ADDR 0x14002600 #define DMA7_PHYS_ADDR 0x14002700 -#define IC0_PHYS_ADDR 0x10400000 -#define IC1_PHYS_ADDR 0x11800000 #define AC97_PHYS_ADDR 0x10000000 #define USBH_PHYS_ADDR 0x10100000 #define USBD_PHYS_ADDR 0x10200000 @@ -680,8 +683,6 @@ enum soc_au1200_ints { #define DMA5_PHYS_ADDR 0x14002500 #define DMA6_PHYS_ADDR 0x14002600 #define DMA7_PHYS_ADDR 0x14002700 -#define IC0_PHYS_ADDR 0x10400000 -#define IC1_PHYS_ADDR 0x11800000 #define AC97_PHYS_ADDR 0x10000000 #define USBH_PHYS_ADDR 0x10100000 #define USBD_PHYS_ADDR 0x10200000 @@ -718,10 +719,8 @@ enum soc_au1200_ints { #define DMA5_PHYS_ADDR 0x14002500 #define DMA6_PHYS_ADDR 0x14002600 #define DMA7_PHYS_ADDR 0x14002700 -#define IC0_PHYS_ADDR 0x10400000 #define SD0_PHYS_ADDR 0x10600000 #define SD1_PHYS_ADDR 0x10680000 -#define IC1_PHYS_ADDR 0x11800000 #define AC97_PHYS_ADDR 0x10000000 #define USBH_PHYS_ADDR 0x10100000 #define USBD_PHYS_ADDR 0x10200000 @@ -749,8 +748,6 @@ enum soc_au1200_ints { #ifdef CONFIG_SOC_AU1550 #define MEM_PHYS_ADDR 0x14000000 #define STATIC_MEM_PHYS_ADDR 0x14001000 -#define IC0_PHYS_ADDR 0x10400000 -#define IC1_PHYS_ADDR 0x11800000 #define USBH_PHYS_ADDR 0x14020000 #define USBD_PHYS_ADDR 0x10200000 #define PCI_PHYS_ADDR 0x14005000 @@ -786,8 +783,6 @@ enum soc_au1200_ints { #define STATIC_MEM_PHYS_ADDR 0x14001000 #define AES_PHYS_ADDR 0x10300000 #define CIM_PHYS_ADDR 0x14004000 -#define IC0_PHYS_ADDR 0x10400000 -#define IC1_PHYS_ADDR 0x11800000 #define USBM_PHYS_ADDR 0x14020000 #define USBH_PHYS_ADDR 0x14020100 #define UART0_PHYS_ADDR 0x11100000 @@ -835,112 +830,6 @@ enum soc_au1200_ints { #endif -/* Interrupt Controller register offsets */ -#define IC_CFG0RD 0x40 -#define IC_CFG0SET 0x40 -#define IC_CFG0CLR 0x44 -#define IC_CFG1RD 0x48 -#define IC_CFG1SET 0x48 -#define IC_CFG1CLR 0x4C -#define IC_CFG2RD 0x50 -#define IC_CFG2SET 0x50 -#define IC_CFG2CLR 0x54 -#define IC_REQ0INT 0x54 -#define IC_SRCRD 0x58 -#define IC_SRCSET 0x58 -#define IC_SRCCLR 0x5C -#define IC_REQ1INT 0x5C -#define IC_ASSIGNRD 0x60 -#define IC_ASSIGNSET 0x60 -#define IC_ASSIGNCLR 0x64 -#define IC_WAKERD 0x68 -#define IC_WAKESET 0x68 -#define IC_WAKECLR 0x6C -#define IC_MASKRD 0x70 -#define IC_MASKSET 0x70 -#define IC_MASKCLR 0x74 -#define IC_RISINGRD 0x78 -#define IC_RISINGCLR 0x78 -#define IC_FALLINGRD 0x7C -#define IC_FALLINGCLR 0x7C -#define IC_TESTBIT 0x80 - - -/* Interrupt Controller 0 */ -#define IC0_CFG0RD 0xB0400040 -#define IC0_CFG0SET 0xB0400040 -#define IC0_CFG0CLR 0xB0400044 - -#define IC0_CFG1RD 0xB0400048 -#define IC0_CFG1SET 0xB0400048 -#define IC0_CFG1CLR 0xB040004C - -#define IC0_CFG2RD 0xB0400050 -#define IC0_CFG2SET 0xB0400050 -#define IC0_CFG2CLR 0xB0400054 - -#define IC0_REQ0INT 0xB0400054 -#define IC0_SRCRD 0xB0400058 -#define IC0_SRCSET 0xB0400058 -#define IC0_SRCCLR 0xB040005C -#define IC0_REQ1INT 0xB040005C - -#define IC0_ASSIGNRD 0xB0400060 -#define IC0_ASSIGNSET 0xB0400060 -#define IC0_ASSIGNCLR 0xB0400064 - -#define IC0_WAKERD 0xB0400068 -#define IC0_WAKESET 0xB0400068 -#define IC0_WAKECLR 0xB040006C - -#define IC0_MASKRD 0xB0400070 -#define IC0_MASKSET 0xB0400070 -#define IC0_MASKCLR 0xB0400074 - -#define IC0_RISINGRD 0xB0400078 -#define IC0_RISINGCLR 0xB0400078 -#define IC0_FALLINGRD 0xB040007C -#define IC0_FALLINGCLR 0xB040007C - -#define IC0_TESTBIT 0xB0400080 - -/* Interrupt Controller 1 */ -#define IC1_CFG0RD 0xB1800040 -#define IC1_CFG0SET 0xB1800040 -#define IC1_CFG0CLR 0xB1800044 - -#define IC1_CFG1RD 0xB1800048 -#define IC1_CFG1SET 0xB1800048 -#define IC1_CFG1CLR 0xB180004C - -#define IC1_CFG2RD 0xB1800050 -#define IC1_CFG2SET 0xB1800050 -#define IC1_CFG2CLR 0xB1800054 - -#define IC1_REQ0INT 0xB1800054 -#define IC1_SRCRD 0xB1800058 -#define IC1_SRCSET 0xB1800058 -#define IC1_SRCCLR 0xB180005C -#define IC1_REQ1INT 0xB180005C - -#define IC1_ASSIGNRD 0xB1800060 -#define IC1_ASSIGNSET 0xB1800060 -#define IC1_ASSIGNCLR 0xB1800064 - -#define IC1_WAKERD 0xB1800068 -#define IC1_WAKESET 0xB1800068 -#define IC1_WAKECLR 0xB180006C - -#define IC1_MASKRD 0xB1800070 -#define IC1_MASKSET 0xB1800070 -#define IC1_MASKCLR 0xB1800074 - -#define IC1_RISINGRD 0xB1800078 -#define IC1_RISINGCLR 0xB1800078 -#define IC1_FALLINGRD 0xB180007C -#define IC1_FALLINGCLR 0xB180007C - -#define IC1_TESTBIT 0xB1800080 /* Au1000 */ -- cgit v0.10.2 From 4b5c82b5e57ac6cb919e7e74984e28b312bdf10c Mon Sep 17 00:00:00 2001 From: Manuel Lauss Date: Sun, 8 May 2011 10:42:15 +0200 Subject: MIPS: Alchemy: Convert irq.c to syscore_ops. Convert the PM sysdev to use syscore_ops instead. Signed-off-by: Manuel Lauss To: Linux-MIPS Cc: Florian Fainelli Cc: Wolfgang Grandegger Patchwork: https://patchwork.linux-mips.org/patch/2350/ Signed-off-by: Ralf Baechle diff --git a/arch/mips/alchemy/common/irq.c b/arch/mips/alchemy/common/irq.c index b72e128..8b60ba0 100644 --- a/arch/mips/alchemy/common/irq.c +++ b/arch/mips/alchemy/common/irq.c @@ -30,7 +30,7 @@ #include #include #include -#include +#include #include #include @@ -585,81 +585,62 @@ void __init arch_init_irq(void) } } -struct alchemy_ic_sysdev { - struct sys_device sysdev; - void __iomem *base; - unsigned long pmdata[7]; -}; - -static int alchemy_ic_suspend(struct sys_device *dev, pm_message_t state) -{ - struct alchemy_ic_sysdev *icdev = - container_of(dev, struct alchemy_ic_sysdev, sysdev); - icdev->pmdata[0] = __raw_readl(icdev->base + IC_CFG0RD); - icdev->pmdata[1] = __raw_readl(icdev->base + IC_CFG1RD); - icdev->pmdata[2] = __raw_readl(icdev->base + IC_CFG2RD); - icdev->pmdata[3] = __raw_readl(icdev->base + IC_SRCRD); - icdev->pmdata[4] = __raw_readl(icdev->base + IC_ASSIGNRD); - icdev->pmdata[5] = __raw_readl(icdev->base + IC_WAKERD); - icdev->pmdata[6] = __raw_readl(icdev->base + IC_MASKRD); +static unsigned long alchemy_ic_pmdata[7 * 2]; - return 0; +static inline void alchemy_ic_suspend_one(void __iomem *base, unsigned long *d) +{ + d[0] = __raw_readl(base + IC_CFG0RD); + d[1] = __raw_readl(base + IC_CFG1RD); + d[2] = __raw_readl(base + IC_CFG2RD); + d[3] = __raw_readl(base + IC_SRCRD); + d[4] = __raw_readl(base + IC_ASSIGNRD); + d[5] = __raw_readl(base + IC_WAKERD); + d[6] = __raw_readl(base + IC_MASKRD); + ic_init(base); /* shut it up too while at it */ } -static int alchemy_ic_resume(struct sys_device *dev) +static inline void alchemy_ic_resume_one(void __iomem *base, unsigned long *d) { - struct alchemy_ic_sysdev *icdev = - container_of(dev, struct alchemy_ic_sysdev, sysdev); - - ic_init(icdev->base); - - __raw_writel(icdev->pmdata[0], icdev->base + IC_CFG0SET); - __raw_writel(icdev->pmdata[1], icdev->base + IC_CFG1SET); - __raw_writel(icdev->pmdata[2], icdev->base + IC_CFG2SET); - __raw_writel(icdev->pmdata[3], icdev->base + IC_SRCSET); - __raw_writel(icdev->pmdata[4], icdev->base + IC_ASSIGNSET); - __raw_writel(icdev->pmdata[5], icdev->base + IC_WAKESET); + ic_init(base); + + __raw_writel(d[0], base + IC_CFG0SET); + __raw_writel(d[1], base + IC_CFG1SET); + __raw_writel(d[2], base + IC_CFG2SET); + __raw_writel(d[3], base + IC_SRCSET); + __raw_writel(d[4], base + IC_ASSIGNSET); + __raw_writel(d[5], base + IC_WAKESET); wmb(); - __raw_writel(icdev->pmdata[6], icdev->base + IC_MASKSET); + __raw_writel(d[6], base + IC_MASKSET); wmb(); +} +static int alchemy_ic_suspend(void) +{ + alchemy_ic_suspend_one((void __iomem *)KSEG1ADDR(AU1000_IC0_PHYS_ADDR), + alchemy_ic_pmdata); + alchemy_ic_suspend_one((void __iomem *)KSEG1ADDR(AU1000_IC1_PHYS_ADDR), + &alchemy_ic_pmdata[7]); return 0; } -static struct sysdev_class alchemy_ic_sysdev_class = { - .name = "ic", +static void alchemy_ic_resume(void) +{ + alchemy_ic_resume_one((void __iomem *)KSEG1ADDR(AU1000_IC1_PHYS_ADDR), + &alchemy_ic_pmdata[7]); + alchemy_ic_resume_one((void __iomem *)KSEG1ADDR(AU1000_IC0_PHYS_ADDR), + alchemy_ic_pmdata); +} + +static struct syscore_ops alchemy_ic_syscore_ops = { .suspend = alchemy_ic_suspend, .resume = alchemy_ic_resume, }; -static int __init alchemy_ic_sysdev_init(void) +static int __init alchemy_ic_pm_init(void) { - struct alchemy_ic_sysdev *icdev; - unsigned long icbase[2] = { AU1000_IC0_PHYS_ADDR, AU1000_IC1_PHYS_ADDR }; - int err, i; - - err = sysdev_class_register(&alchemy_ic_sysdev_class); - if (err) - return err; - - for (i = 0; i < 2; i++) { - icdev = kzalloc(sizeof(struct alchemy_ic_sysdev), GFP_KERNEL); - if (!icdev) - return -ENOMEM; - - icdev->base = ioremap(icbase[i], 0x1000); - - icdev->sysdev.id = i; - icdev->sysdev.cls = &alchemy_ic_sysdev_class; - err = sysdev_register(&icdev->sysdev); - if (err) { - kfree(icdev); - return err; - } - } - + register_syscore_ops(&alchemy_ic_syscore_ops); return 0; } -device_initcall(alchemy_ic_sysdev_init); +device_initcall(alchemy_ic_pm_init); -- cgit v0.10.2 From adcb86279f1e4d7a1a9f267b49441aecf4a5110a Mon Sep 17 00:00:00 2001 From: Manuel Lauss Date: Sun, 8 May 2011 10:42:16 +0200 Subject: MIPS: Alchemy: Convert dbdma.c to syscore_ops Convert the PM sysdev to syscore_ops and clean up the ddma addresses a bit. Signed-off-by: Manuel Lauss To: Linux-MIPS Cc: Florian Fainelli Cc: Wolfgang Grandegger Patchwork: https://patchwork.linux-mips.org/patch/2351/ Signed-off-by: Ralf Baechle diff --git a/arch/mips/alchemy/common/dbdma.c b/arch/mips/alchemy/common/dbdma.c index ca0506a..3a5abb5 100644 --- a/arch/mips/alchemy/common/dbdma.c +++ b/arch/mips/alchemy/common/dbdma.c @@ -36,7 +36,7 @@ #include #include #include -#include +#include #include #include @@ -58,7 +58,8 @@ static DEFINE_SPINLOCK(au1xxx_dbdma_spin_lock); /* I couldn't find a macro that did this... */ #define ALIGN_ADDR(x, a) ((((u32)(x)) + (a-1)) & ~(a-1)) -static dbdma_global_t *dbdma_gptr = (dbdma_global_t *)DDMA_GLOBAL_BASE; +static dbdma_global_t *dbdma_gptr = + (dbdma_global_t *)KSEG1ADDR(AU1550_DBDMA_CONF_PHYS_ADDR); static int dbdma_initialized; static dbdev_tab_t dbdev_tab[] = { @@ -299,7 +300,7 @@ u32 au1xxx_dbdma_chan_alloc(u32 srcid, u32 destid, if (ctp != NULL) { memset(ctp, 0, sizeof(chan_tab_t)); ctp->chan_index = chan = i; - dcp = DDMA_CHANNEL_BASE; + dcp = KSEG1ADDR(AU1550_DBDMA_PHYS_ADDR); dcp += (0x0100 * chan); ctp->chan_ptr = (au1x_dma_chan_t *)dcp; cp = (au1x_dma_chan_t *)dcp; @@ -958,105 +959,75 @@ u32 au1xxx_dbdma_put_dscr(u32 chanid, au1x_ddma_desc_t *dscr) } -struct alchemy_dbdma_sysdev { - struct sys_device sysdev; - u32 pm_regs[NUM_DBDMA_CHANS + 1][6]; -}; +static unsigned long alchemy_dbdma_pm_data[NUM_DBDMA_CHANS + 1][6]; -static int alchemy_dbdma_suspend(struct sys_device *dev, - pm_message_t state) +static int alchemy_dbdma_suspend(void) { - struct alchemy_dbdma_sysdev *sdev = - container_of(dev, struct alchemy_dbdma_sysdev, sysdev); int i; - u32 addr; + void __iomem *addr; - addr = DDMA_GLOBAL_BASE; - sdev->pm_regs[0][0] = au_readl(addr + 0x00); - sdev->pm_regs[0][1] = au_readl(addr + 0x04); - sdev->pm_regs[0][2] = au_readl(addr + 0x08); - sdev->pm_regs[0][3] = au_readl(addr + 0x0c); + addr = (void __iomem *)KSEG1ADDR(AU1550_DBDMA_CONF_PHYS_ADDR); + alchemy_dbdma_pm_data[0][0] = __raw_readl(addr + 0x00); + alchemy_dbdma_pm_data[0][1] = __raw_readl(addr + 0x04); + alchemy_dbdma_pm_data[0][2] = __raw_readl(addr + 0x08); + alchemy_dbdma_pm_data[0][3] = __raw_readl(addr + 0x0c); /* save channel configurations */ - for (i = 1, addr = DDMA_CHANNEL_BASE; i <= NUM_DBDMA_CHANS; i++) { - sdev->pm_regs[i][0] = au_readl(addr + 0x00); - sdev->pm_regs[i][1] = au_readl(addr + 0x04); - sdev->pm_regs[i][2] = au_readl(addr + 0x08); - sdev->pm_regs[i][3] = au_readl(addr + 0x0c); - sdev->pm_regs[i][4] = au_readl(addr + 0x10); - sdev->pm_regs[i][5] = au_readl(addr + 0x14); + addr = (void __iomem *)KSEG1ADDR(AU1550_DBDMA_PHYS_ADDR); + for (i = 1; i <= NUM_DBDMA_CHANS; i++) { + alchemy_dbdma_pm_data[i][0] = __raw_readl(addr + 0x00); + alchemy_dbdma_pm_data[i][1] = __raw_readl(addr + 0x04); + alchemy_dbdma_pm_data[i][2] = __raw_readl(addr + 0x08); + alchemy_dbdma_pm_data[i][3] = __raw_readl(addr + 0x0c); + alchemy_dbdma_pm_data[i][4] = __raw_readl(addr + 0x10); + alchemy_dbdma_pm_data[i][5] = __raw_readl(addr + 0x14); /* halt channel */ - au_writel(sdev->pm_regs[i][0] & ~1, addr + 0x00); - au_sync(); - while (!(au_readl(addr + 0x14) & 1)) - au_sync(); + __raw_writel(alchemy_dbdma_pm_data[i][0] & ~1, addr + 0x00); + wmb(); + while (!(__raw_readl(addr + 0x14) & 1)) + wmb(); addr += 0x100; /* next channel base */ } /* disable channel interrupts */ - au_writel(0, DDMA_GLOBAL_BASE + 0x0c); - au_sync(); + addr = (void __iomem *)KSEG1ADDR(AU1550_DBDMA_CONF_PHYS_ADDR); + __raw_writel(0, addr + 0x0c); + wmb(); return 0; } -static int alchemy_dbdma_resume(struct sys_device *dev) +static void alchemy_dbdma_resume(void) { - struct alchemy_dbdma_sysdev *sdev = - container_of(dev, struct alchemy_dbdma_sysdev, sysdev); int i; - u32 addr; + void __iomem *addr; - addr = DDMA_GLOBAL_BASE; - au_writel(sdev->pm_regs[0][0], addr + 0x00); - au_writel(sdev->pm_regs[0][1], addr + 0x04); - au_writel(sdev->pm_regs[0][2], addr + 0x08); - au_writel(sdev->pm_regs[0][3], addr + 0x0c); + addr = (void __iomem *)KSEG1ADDR(AU1550_DBDMA_CONF_PHYS_ADDR); + __raw_writel(alchemy_dbdma_pm_data[0][0], addr + 0x00); + __raw_writel(alchemy_dbdma_pm_data[0][1], addr + 0x04); + __raw_writel(alchemy_dbdma_pm_data[0][2], addr + 0x08); + __raw_writel(alchemy_dbdma_pm_data[0][3], addr + 0x0c); /* restore channel configurations */ - for (i = 1, addr = DDMA_CHANNEL_BASE; i <= NUM_DBDMA_CHANS; i++) { - au_writel(sdev->pm_regs[i][0], addr + 0x00); - au_writel(sdev->pm_regs[i][1], addr + 0x04); - au_writel(sdev->pm_regs[i][2], addr + 0x08); - au_writel(sdev->pm_regs[i][3], addr + 0x0c); - au_writel(sdev->pm_regs[i][4], addr + 0x10); - au_writel(sdev->pm_regs[i][5], addr + 0x14); - au_sync(); + addr = (void __iomem *)KSEG1ADDR(AU1550_DBDMA_PHYS_ADDR); + for (i = 1; i <= NUM_DBDMA_CHANS; i++) { + __raw_writel(alchemy_dbdma_pm_data[i][0], addr + 0x00); + __raw_writel(alchemy_dbdma_pm_data[i][1], addr + 0x04); + __raw_writel(alchemy_dbdma_pm_data[i][2], addr + 0x08); + __raw_writel(alchemy_dbdma_pm_data[i][3], addr + 0x0c); + __raw_writel(alchemy_dbdma_pm_data[i][4], addr + 0x10); + __raw_writel(alchemy_dbdma_pm_data[i][5], addr + 0x14); + wmb(); addr += 0x100; /* next channel base */ } - - return 0; } -static struct sysdev_class alchemy_dbdma_sysdev_class = { - .name = "dbdma", +static struct syscore_ops alchemy_dbdma_syscore_ops = { .suspend = alchemy_dbdma_suspend, .resume = alchemy_dbdma_resume, }; -static int __init alchemy_dbdma_sysdev_init(void) -{ - struct alchemy_dbdma_sysdev *sdev; - int ret; - - ret = sysdev_class_register(&alchemy_dbdma_sysdev_class); - if (ret) - return ret; - - sdev = kzalloc(sizeof(struct alchemy_dbdma_sysdev), GFP_KERNEL); - if (!sdev) - return -ENOMEM; - - sdev->sysdev.id = -1; - sdev->sysdev.cls = &alchemy_dbdma_sysdev_class; - ret = sysdev_register(&sdev->sysdev); - if (ret) - kfree(sdev); - - return ret; -} - static int __init au1xxx_dbdma_init(void) { int irq_nr, ret; @@ -1084,11 +1055,7 @@ static int __init au1xxx_dbdma_init(void) else { dbdma_initialized = 1; printk(KERN_INFO "Alchemy DBDMA initialized\n"); - ret = alchemy_dbdma_sysdev_init(); - if (ret) { - printk(KERN_ERR "DBDMA PM init failed\n"); - ret = 0; - } + register_syscore_ops(&alchemy_dbdma_syscore_ops); } return ret; diff --git a/arch/mips/include/asm/mach-au1x00/au1000.h b/arch/mips/include/asm/mach-au1x00/au1000.h index 66cfcdc..eb8f103 100644 --- a/arch/mips/include/asm/mach-au1x00/au1000.h +++ b/arch/mips/include/asm/mach-au1x00/au1000.h @@ -635,6 +635,8 @@ enum soc_au1200_ints { #define AU1000_IC0_PHYS_ADDR 0x10400000 /* 01234 */ #define AU1000_IC1_PHYS_ADDR 0x11800000 /* 01234 */ +#define AU1550_DBDMA_PHYS_ADDR 0x14002000 /* 34 */ +#define AU1550_DBDMA_CONF_PHYS_ADDR 0x14003000 /* 34 */ #ifdef CONFIG_SOC_AU1000 @@ -761,7 +763,6 @@ enum soc_au1200_ints { #define UART3_PHYS_ADDR 0x11400000 #define GPIO2_PHYS_ADDR 0x11700000 #define SYS_PHYS_ADDR 0x11900000 -#define DDMA_PHYS_ADDR 0x14002000 #define PE_PHYS_ADDR 0x14008000 #define PSC0_PHYS_ADDR 0x11A00000 #define PSC1_PHYS_ADDR 0x11B00000 @@ -789,7 +790,6 @@ enum soc_au1200_ints { #define UART1_PHYS_ADDR 0x11200000 #define GPIO2_PHYS_ADDR 0x11700000 #define SYS_PHYS_ADDR 0x11900000 -#define DDMA_PHYS_ADDR 0x14002000 #define PSC0_PHYS_ADDR 0x11A00000 #define PSC1_PHYS_ADDR 0x11B00000 #define SD0_PHYS_ADDR 0x10600000 diff --git a/arch/mips/include/asm/mach-au1x00/au1xxx_dbdma.h b/arch/mips/include/asm/mach-au1x00/au1xxx_dbdma.h index c8a553a3..2fdacfe 100644 --- a/arch/mips/include/asm/mach-au1x00/au1xxx_dbdma.h +++ b/arch/mips/include/asm/mach-au1x00/au1xxx_dbdma.h @@ -37,14 +37,6 @@ #ifndef _LANGUAGE_ASSEMBLY -/* - * The DMA base addresses. - * The channels are every 256 bytes (0x0100) from the channel 0 base. - * Interrupt status/enable is bits 15:0 for channels 15 to zero. - */ -#define DDMA_GLOBAL_BASE 0xb4003000 -#define DDMA_CHANNEL_BASE 0xb4002000 - typedef volatile struct dbdma_global { u32 ddma_config; u32 ddma_intstat; -- cgit v0.10.2 From 80130204b43ce9c3b50924e4c2d44e9f2881f8c3 Mon Sep 17 00:00:00 2001 From: Manuel Lauss Date: Sun, 8 May 2011 10:42:17 +0200 Subject: MIPS: Alchemy: Rewrite UART setup and constants. Detect CPU type at runtime and setup uarts accordingly; also clean up the uart base address mess in the process as far as possible. Signed-off-by: Manuel Lauss To: Linux-MIPS Cc: Florian Fainelli Cc: Wolfgang Grandegger Patchwork: https://patchwork.linux-mips.org/patch/2352/ Signed-off-by: Ralf Baechle membase + UART_MOD_CNTRL) & 3) != 3) { - /* power-on sequence as suggested in the databooks */ - __raw_writel(0, port->membase + UART_MOD_CNTRL); - wmb(); - __raw_writel(1, port->membase + UART_MOD_CNTRL); - wmb(); - } - __raw_writel(3, port->membase + UART_MOD_CNTRL); /* full on */ - wmb(); + alchemy_uart_enable(CPHYSADDR(port->membase)); serial8250_do_pm(port, state, old_state); break; case 3: /* power off */ serial8250_do_pm(port, state, old_state); - __raw_writel(0, port->membase + UART_MOD_CNTRL); - wmb(); + alchemy_uart_disable(CPHYSADDR(port->membase)); break; default: serial8250_do_pm(port, state, old_state); @@ -65,38 +56,60 @@ static void alchemy_8250_pm(struct uart_port *port, unsigned int state, .pm = alchemy_8250_pm, \ } -static struct plat_serial8250_port au1x00_uart_data[] = { -#if defined(CONFIG_SOC_AU1000) - PORT(UART0_PHYS_ADDR, AU1000_UART0_INT), - PORT(UART1_PHYS_ADDR, AU1000_UART1_INT), - PORT(UART2_PHYS_ADDR, AU1000_UART2_INT), - PORT(UART3_PHYS_ADDR, AU1000_UART3_INT), -#elif defined(CONFIG_SOC_AU1500) - PORT(UART0_PHYS_ADDR, AU1500_UART0_INT), - PORT(UART3_PHYS_ADDR, AU1500_UART3_INT), -#elif defined(CONFIG_SOC_AU1100) - PORT(UART0_PHYS_ADDR, AU1100_UART0_INT), - PORT(UART1_PHYS_ADDR, AU1100_UART1_INT), - PORT(UART3_PHYS_ADDR, AU1100_UART3_INT), -#elif defined(CONFIG_SOC_AU1550) - PORT(UART0_PHYS_ADDR, AU1550_UART0_INT), - PORT(UART1_PHYS_ADDR, AU1550_UART1_INT), - PORT(UART3_PHYS_ADDR, AU1550_UART3_INT), -#elif defined(CONFIG_SOC_AU1200) - PORT(UART0_PHYS_ADDR, AU1200_UART0_INT), - PORT(UART1_PHYS_ADDR, AU1200_UART1_INT), -#endif - { }, +static struct plat_serial8250_port au1x00_uart_data[][4] __initdata = { + [ALCHEMY_CPU_AU1000] = { + PORT(AU1000_UART0_PHYS_ADDR, AU1000_UART0_INT), + PORT(AU1000_UART1_PHYS_ADDR, AU1000_UART1_INT), + PORT(AU1000_UART2_PHYS_ADDR, AU1000_UART2_INT), + PORT(AU1000_UART3_PHYS_ADDR, AU1000_UART3_INT), + }, + [ALCHEMY_CPU_AU1500] = { + PORT(AU1000_UART0_PHYS_ADDR, AU1500_UART0_INT), + PORT(AU1000_UART3_PHYS_ADDR, AU1500_UART3_INT), + }, + [ALCHEMY_CPU_AU1100] = { + PORT(AU1000_UART0_PHYS_ADDR, AU1100_UART0_INT), + PORT(AU1000_UART1_PHYS_ADDR, AU1100_UART1_INT), + PORT(AU1000_UART3_PHYS_ADDR, AU1100_UART3_INT), + }, + [ALCHEMY_CPU_AU1550] = { + PORT(AU1000_UART0_PHYS_ADDR, AU1550_UART0_INT), + PORT(AU1000_UART1_PHYS_ADDR, AU1550_UART1_INT), + PORT(AU1000_UART3_PHYS_ADDR, AU1550_UART3_INT), + }, + [ALCHEMY_CPU_AU1200] = { + PORT(AU1000_UART0_PHYS_ADDR, AU1200_UART0_INT), + PORT(AU1000_UART1_PHYS_ADDR, AU1200_UART1_INT), + }, }; static struct platform_device au1xx0_uart_device = { .name = "serial8250", .id = PLAT8250_DEV_AU1X00, - .dev = { - .platform_data = au1x00_uart_data, - }, }; +static void __init alchemy_setup_uarts(int ctype) +{ + unsigned int uartclk = get_au1x00_uart_baud_base() * 16; + int s = sizeof(struct plat_serial8250_port); + int c = alchemy_get_uarts(ctype); + struct plat_serial8250_port *ports; + + ports = kzalloc(s * (c + 1), GFP_KERNEL); + if (!ports) { + printk(KERN_INFO "Alchemy: no memory for UART data\n"); + return; + } + memcpy(ports, au1x00_uart_data[ctype], s * c); + au1xx0_uart_device.dev.platform_data = ports; + + /* Fill up uartclk. */ + for (s = 0; s < c; s++) + ports[s].uartclk = uartclk; + if (platform_device_register(&au1xx0_uart_device)) + printk(KERN_INFO "Alchemy: failed to register UARTs\n"); +} + /* OHCI (USB full speed host controller) */ static struct resource au1xxx_usb_ohci_resources[] = { [0] = { @@ -442,7 +455,6 @@ void __init au1xxx_override_eth_cfg(unsigned int port, } static struct platform_device *au1xxx_platform_devices[] __initdata = { - &au1xx0_uart_device, &au1xxx_usb_ohci_device, #ifdef CONFIG_FB_AU1100 &au1100_lcd_device, @@ -465,13 +477,10 @@ static struct platform_device *au1xxx_platform_devices[] __initdata = { static int __init au1xxx_platform_init(void) { - unsigned int uartclk = get_au1x00_uart_baud_base() * 16; - int err, i; + int err, i, ctype = alchemy_get_cputype(); unsigned char ethaddr[6]; - /* Fill up uartclk. */ - for (i = 0; au1x00_uart_data[i].flags; i++) - au1x00_uart_data[i].uartclk = uartclk; + alchemy_setup_uarts(ctype); /* use firmware-provided mac addr if available and necessary */ i = prom_get_ethernet_addr(ethaddr); diff --git a/arch/mips/alchemy/devboards/prom.c b/arch/mips/alchemy/devboards/prom.c index baeb213..e5306b5 100644 --- a/arch/mips/alchemy/devboards/prom.c +++ b/arch/mips/alchemy/devboards/prom.c @@ -62,5 +62,5 @@ void __init prom_init(void) void prom_putchar(unsigned char c) { - alchemy_uart_putchar(UART0_PHYS_ADDR, c); + alchemy_uart_putchar(AU1000_UART0_PHYS_ADDR, c); } diff --git a/arch/mips/alchemy/gpr/board_setup.c b/arch/mips/alchemy/gpr/board_setup.c index ad2e3f1..5f8f069 100644 --- a/arch/mips/alchemy/gpr/board_setup.c +++ b/arch/mips/alchemy/gpr/board_setup.c @@ -36,9 +36,6 @@ #include -#define UART1_ADDR KSEG1ADDR(UART1_PHYS_ADDR) -#define UART3_ADDR KSEG1ADDR(UART3_PHYS_ADDR) - char irq_tab_alchemy[][5] __initdata = { [0] = { -1, AU1500_PCI_INTA, AU1500_PCI_INTB, 0xff, 0xff }, }; @@ -67,18 +64,15 @@ static void gpr_power_off(void) void __init board_setup(void) { - printk(KERN_INFO "Tarpeze ITS GPR board\n"); + printk(KERN_INFO "Trapeze ITS GPR board\n"); pm_power_off = gpr_power_off; _machine_halt = gpr_power_off; _machine_restart = gpr_reset; - /* Enable UART3 */ - au_writel(0x1, UART3_ADDR + UART_MOD_CNTRL);/* clock enable (CE) */ - au_writel(0x3, UART3_ADDR + UART_MOD_CNTRL); /* CE and "enable" */ - /* Enable UART1 */ - au_writel(0x1, UART1_ADDR + UART_MOD_CNTRL); /* clock enable (CE) */ - au_writel(0x3, UART1_ADDR + UART_MOD_CNTRL); /* CE and "enable" */ + /* Enable UART1/3 */ + alchemy_uart_enable(AU1000_UART3_PHYS_ADDR); + alchemy_uart_enable(AU1000_UART1_PHYS_ADDR); /* Take away Reset of UMTS-card */ alchemy_gpio_direction_output(215, 1); diff --git a/arch/mips/alchemy/gpr/init.c b/arch/mips/alchemy/gpr/init.c index f044f4c..229aafa 100644 --- a/arch/mips/alchemy/gpr/init.c +++ b/arch/mips/alchemy/gpr/init.c @@ -59,5 +59,5 @@ void __init prom_init(void) void prom_putchar(unsigned char c) { - alchemy_uart_putchar(UART0_PHYS_ADDR, c); + alchemy_uart_putchar(AU1000_UART0_PHYS_ADDR, c); } diff --git a/arch/mips/alchemy/mtx-1/init.c b/arch/mips/alchemy/mtx-1/init.c index f8d2557..2e81cc7 100644 --- a/arch/mips/alchemy/mtx-1/init.c +++ b/arch/mips/alchemy/mtx-1/init.c @@ -62,5 +62,5 @@ void __init prom_init(void) void prom_putchar(unsigned char c) { - alchemy_uart_putchar(UART0_PHYS_ADDR, c); + alchemy_uart_putchar(AU1000_UART0_PHYS_ADDR, c); } diff --git a/arch/mips/alchemy/xxs1500/board_setup.c b/arch/mips/alchemy/xxs1500/board_setup.c index febfb0fb..81e57fa 100644 --- a/arch/mips/alchemy/xxs1500/board_setup.c +++ b/arch/mips/alchemy/xxs1500/board_setup.c @@ -66,13 +66,10 @@ void __init board_setup(void) au_writel(pin_func, SYS_PINFUNC); /* Enable UART */ - au_writel(0x01, UART3_ADDR + UART_MOD_CNTRL); /* clock enable (CE) */ - mdelay(10); - au_writel(0x03, UART3_ADDR + UART_MOD_CNTRL); /* CE and "enable" */ - mdelay(10); - - /* Enable DTR = USB power up */ - au_writel(0x01, UART3_ADDR + UART_MCR); /* UART_MCR_DTR is 0x01??? */ + alchemy_uart_enable(AU1000_UART3_PHYS_ADDR); + /* Enable DTR (MCR bit 0) = USB power up */ + __raw_writel(1, (void __iomem *)KSEG1ADDR(AU1000_UART3_PHYS_ADDR + 0x18)); + wmb(); #ifdef CONFIG_PCI #if defined(__MIPSEB__) diff --git a/arch/mips/alchemy/xxs1500/init.c b/arch/mips/alchemy/xxs1500/init.c index 34a90a4..0ee02cf 100644 --- a/arch/mips/alchemy/xxs1500/init.c +++ b/arch/mips/alchemy/xxs1500/init.c @@ -59,5 +59,5 @@ void __init prom_init(void) void prom_putchar(unsigned char c) { - alchemy_uart_putchar(UART0_PHYS_ADDR, c); + alchemy_uart_putchar(AU1000_UART0_PHYS_ADDR, c); } diff --git a/arch/mips/boot/compressed/uart-alchemy.c b/arch/mips/boot/compressed/uart-alchemy.c index 1bff22f..eb063e6 100644 --- a/arch/mips/boot/compressed/uart-alchemy.c +++ b/arch/mips/boot/compressed/uart-alchemy.c @@ -3,5 +3,5 @@ void putc(char c) { /* all current (Jan. 2010) in-kernel boards */ - alchemy_uart_putchar(UART0_PHYS_ADDR, c); + alchemy_uart_putchar(AU1000_UART0_PHYS_ADDR, c); } diff --git a/arch/mips/include/asm/mach-au1x00/au1000.h b/arch/mips/include/asm/mach-au1x00/au1000.h index eb8f103..c4ffb20 100644 --- a/arch/mips/include/asm/mach-au1x00/au1000.h +++ b/arch/mips/include/asm/mach-au1x00/au1000.h @@ -161,6 +161,45 @@ static inline int alchemy_get_cputype(void) return ALCHEMY_CPU_UNKNOWN; } +/* return number of uarts on a given cputype */ +static inline int alchemy_get_uarts(int type) +{ + switch (type) { + case ALCHEMY_CPU_AU1000: + return 4; + case ALCHEMY_CPU_AU1500: + case ALCHEMY_CPU_AU1200: + return 2; + case ALCHEMY_CPU_AU1100: + case ALCHEMY_CPU_AU1550: + return 3; + } + return 0; +} + +/* enable an UART block if it isn't already */ +static inline void alchemy_uart_enable(u32 uart_phys) +{ + void __iomem *addr = (void __iomem *)KSEG1ADDR(uart_phys); + + /* reset, enable clock, deassert reset */ + if ((__raw_readl(addr + 0x100) & 3) != 3) { + __raw_writel(0, addr + 0x100); + wmb(); + __raw_writel(1, addr + 0x100); + wmb(); + } + __raw_writel(3, addr + 0x100); + wmb(); +} + +static inline void alchemy_uart_disable(u32 uart_phys) +{ + void __iomem *addr = (void __iomem *)KSEG1ADDR(uart_phys); + __raw_writel(0, addr + 0x100); /* UART_MOD_CNTRL */ + wmb(); +} + static inline void alchemy_uart_putchar(u32 uart_phys, u8 c) { void __iomem *base = (void __iomem *)KSEG1ADDR(uart_phys); @@ -634,6 +673,10 @@ enum soc_au1200_ints { */ #define AU1000_IC0_PHYS_ADDR 0x10400000 /* 01234 */ +#define AU1000_UART0_PHYS_ADDR 0x11100000 /* 01234 */ +#define AU1000_UART1_PHYS_ADDR 0x11200000 /* 0234 */ +#define AU1000_UART2_PHYS_ADDR 0x11300000 /* 0 */ +#define AU1000_UART3_PHYS_ADDR 0x11400000 /* 0123 */ #define AU1000_IC1_PHYS_ADDR 0x11800000 /* 01234 */ #define AU1550_DBDMA_PHYS_ADDR 0x14002000 /* 34 */ #define AU1550_DBDMA_CONF_PHYS_ADDR 0x14003000 /* 34 */ @@ -660,10 +703,6 @@ enum soc_au1200_ints { #define MACDMA0_PHYS_ADDR 0x14004000 #define MACDMA1_PHYS_ADDR 0x14004200 #define I2S_PHYS_ADDR 0x11000000 -#define UART0_PHYS_ADDR 0x11100000 -#define UART1_PHYS_ADDR 0x11200000 -#define UART2_PHYS_ADDR 0x11300000 -#define UART3_PHYS_ADDR 0x11400000 #define SSI0_PHYS_ADDR 0x11600000 #define SSI1_PHYS_ADDR 0x11680000 #define SYS_PHYS_ADDR 0x11900000 @@ -695,8 +734,6 @@ enum soc_au1200_ints { #define MACDMA0_PHYS_ADDR 0x14004000 #define MACDMA1_PHYS_ADDR 0x14004200 #define I2S_PHYS_ADDR 0x11000000 -#define UART0_PHYS_ADDR 0x11100000 -#define UART3_PHYS_ADDR 0x11400000 #define GPIO2_PHYS_ADDR 0x11700000 #define SYS_PHYS_ADDR 0x11900000 #define PCI_MEM_PHYS_ADDR 0x400000000ULL @@ -732,9 +769,6 @@ enum soc_au1200_ints { #define MACDMA0_PHYS_ADDR 0x14004000 #define MACDMA1_PHYS_ADDR 0x14004200 #define I2S_PHYS_ADDR 0x11000000 -#define UART0_PHYS_ADDR 0x11100000 -#define UART1_PHYS_ADDR 0x11200000 -#define UART3_PHYS_ADDR 0x11400000 #define SSI0_PHYS_ADDR 0x11600000 #define SSI1_PHYS_ADDR 0x11680000 #define GPIO2_PHYS_ADDR 0x11700000 @@ -758,9 +792,6 @@ enum soc_au1200_ints { #define MACEN_PHYS_ADDR 0x10520000 #define MACDMA0_PHYS_ADDR 0x14004000 #define MACDMA1_PHYS_ADDR 0x14004200 -#define UART0_PHYS_ADDR 0x11100000 -#define UART1_PHYS_ADDR 0x11200000 -#define UART3_PHYS_ADDR 0x11400000 #define GPIO2_PHYS_ADDR 0x11700000 #define SYS_PHYS_ADDR 0x11900000 #define PE_PHYS_ADDR 0x14008000 @@ -786,8 +817,6 @@ enum soc_au1200_ints { #define CIM_PHYS_ADDR 0x14004000 #define USBM_PHYS_ADDR 0x14020000 #define USBH_PHYS_ADDR 0x14020100 -#define UART0_PHYS_ADDR 0x11100000 -#define UART1_PHYS_ADDR 0x11200000 #define GPIO2_PHYS_ADDR 0x11700000 #define SYS_PHYS_ADDR 0x11900000 #define PSC0_PHYS_ADDR 0x11A00000 -- cgit v0.10.2 From 40d8bc281711d188f35f035f28d94b111b735484 Mon Sep 17 00:00:00 2001 From: Manuel Lauss Date: Sun, 8 May 2011 10:42:18 +0200 Subject: MIPS: Alchemy: Rewrite ethernet platform setup Rewrite ethernet setup to use runtime cpu detection, and also clean up the ethernet base address mess as far as possible. Signed-off-by: Manuel Lauss To: Linux-MIPS Cc: Florian Fainelli Cc: Wolfgang Grandegger Patchwork: https://patchwork.linux-mips.org/patch/2353/ Signed-off-by: Ralf Baechle #include +#include #include #include -#include +#include #include #include @@ -372,15 +373,16 @@ static struct platform_device pbdb_smbus_device = { #endif /* Macro to help defining the Ethernet MAC resources */ +#define MAC_RES_COUNT 3 /* MAC regs base, MAC enable reg, MAC INT */ #define MAC_RES(_base, _enable, _irq) \ { \ - .start = CPHYSADDR(_base), \ - .end = CPHYSADDR(_base + 0xffff), \ + .start = _base, \ + .end = _base + 0xffff, \ .flags = IORESOURCE_MEM, \ }, \ { \ - .start = CPHYSADDR(_enable), \ - .end = CPHYSADDR(_enable + 0x3), \ + .start = _enable, \ + .end = _enable + 0x3, \ .flags = IORESOURCE_MEM, \ }, \ { \ @@ -389,19 +391,29 @@ static struct platform_device pbdb_smbus_device = { .flags = IORESOURCE_IRQ \ } -static struct resource au1xxx_eth0_resources[] = { -#if defined(CONFIG_SOC_AU1000) - MAC_RES(AU1000_ETH0_BASE, AU1000_MAC0_ENABLE, AU1000_MAC0_DMA_INT), -#elif defined(CONFIG_SOC_AU1100) - MAC_RES(AU1100_ETH0_BASE, AU1100_MAC0_ENABLE, AU1100_MAC0_DMA_INT), -#elif defined(CONFIG_SOC_AU1550) - MAC_RES(AU1550_ETH0_BASE, AU1550_MAC0_ENABLE, AU1550_MAC0_DMA_INT), -#elif defined(CONFIG_SOC_AU1500) - MAC_RES(AU1500_ETH0_BASE, AU1500_MAC0_ENABLE, AU1500_MAC0_DMA_INT), -#endif +static struct resource au1xxx_eth0_resources[][MAC_RES_COUNT] __initdata = { + [ALCHEMY_CPU_AU1000] = { + MAC_RES(AU1000_MAC0_PHYS_ADDR, + AU1000_MACEN_PHYS_ADDR, + AU1000_MAC0_DMA_INT) + }, + [ALCHEMY_CPU_AU1500] = { + MAC_RES(AU1500_MAC0_PHYS_ADDR, + AU1500_MACEN_PHYS_ADDR, + AU1500_MAC0_DMA_INT) + }, + [ALCHEMY_CPU_AU1100] = { + MAC_RES(AU1000_MAC0_PHYS_ADDR, + AU1000_MACEN_PHYS_ADDR, + AU1100_MAC0_DMA_INT) + }, + [ALCHEMY_CPU_AU1550] = { + MAC_RES(AU1000_MAC0_PHYS_ADDR, + AU1000_MACEN_PHYS_ADDR, + AU1550_MAC0_DMA_INT) + }, }; - static struct au1000_eth_platform_data au1xxx_eth0_platform_data = { .phy1_search_mac0 = 1, }; @@ -409,20 +421,26 @@ static struct au1000_eth_platform_data au1xxx_eth0_platform_data = { static struct platform_device au1xxx_eth0_device = { .name = "au1000-eth", .id = 0, - .num_resources = ARRAY_SIZE(au1xxx_eth0_resources), - .resource = au1xxx_eth0_resources, + .num_resources = MAC_RES_COUNT, .dev.platform_data = &au1xxx_eth0_platform_data, }; -#ifndef CONFIG_SOC_AU1100 -static struct resource au1xxx_eth1_resources[] = { -#if defined(CONFIG_SOC_AU1000) - MAC_RES(AU1000_ETH1_BASE, AU1000_MAC1_ENABLE, AU1000_MAC1_DMA_INT), -#elif defined(CONFIG_SOC_AU1550) - MAC_RES(AU1550_ETH1_BASE, AU1550_MAC1_ENABLE, AU1550_MAC1_DMA_INT), -#elif defined(CONFIG_SOC_AU1500) - MAC_RES(AU1500_ETH1_BASE, AU1500_MAC1_ENABLE, AU1500_MAC1_DMA_INT), -#endif +static struct resource au1xxx_eth1_resources[][MAC_RES_COUNT] __initdata = { + [ALCHEMY_CPU_AU1000] = { + MAC_RES(AU1000_MAC1_PHYS_ADDR, + AU1000_MACEN_PHYS_ADDR + 4, + AU1000_MAC1_DMA_INT) + }, + [ALCHEMY_CPU_AU1500] = { + MAC_RES(AU1500_MAC1_PHYS_ADDR, + AU1500_MACEN_PHYS_ADDR + 4, + AU1500_MAC1_DMA_INT) + }, + [ALCHEMY_CPU_AU1550] = { + MAC_RES(AU1000_MAC1_PHYS_ADDR, + AU1000_MACEN_PHYS_ADDR + 4, + AU1550_MAC1_DMA_INT) + }, }; static struct au1000_eth_platform_data au1xxx_eth1_platform_data = { @@ -432,11 +450,9 @@ static struct au1000_eth_platform_data au1xxx_eth1_platform_data = { static struct platform_device au1xxx_eth1_device = { .name = "au1000-eth", .id = 1, - .num_resources = ARRAY_SIZE(au1xxx_eth1_resources), - .resource = au1xxx_eth1_resources, + .num_resources = MAC_RES_COUNT, .dev.platform_data = &au1xxx_eth1_platform_data, }; -#endif void __init au1xxx_override_eth_cfg(unsigned int port, struct au1000_eth_platform_data *eth_data) @@ -447,11 +463,62 @@ void __init au1xxx_override_eth_cfg(unsigned int port, if (port == 0) memcpy(&au1xxx_eth0_platform_data, eth_data, sizeof(struct au1000_eth_platform_data)); -#ifndef CONFIG_SOC_AU1100 else memcpy(&au1xxx_eth1_platform_data, eth_data, sizeof(struct au1000_eth_platform_data)); -#endif +} + +static void __init alchemy_setup_macs(int ctype) +{ + int ret, i; + unsigned char ethaddr[6]; + struct resource *macres; + + /* Handle 1st MAC */ + if (alchemy_get_macs(ctype) < 1) + return; + + macres = kmalloc(sizeof(struct resource) * MAC_RES_COUNT, GFP_KERNEL); + if (!macres) { + printk(KERN_INFO "Alchemy: no memory for MAC0 resources\n"); + return; + } + memcpy(macres, au1xxx_eth0_resources[ctype], + sizeof(struct resource) * MAC_RES_COUNT); + au1xxx_eth0_device.resource = macres; + + i = prom_get_ethernet_addr(ethaddr); + if (!i && !is_valid_ether_addr(au1xxx_eth0_platform_data.mac)) + memcpy(au1xxx_eth0_platform_data.mac, ethaddr, 6); + + ret = platform_device_register(&au1xxx_eth0_device); + if (!ret) + printk(KERN_INFO "Alchemy: failed to register MAC0\n"); + + + /* Handle 2nd MAC */ + if (alchemy_get_macs(ctype) < 2) + return; + + macres = kmalloc(sizeof(struct resource) * MAC_RES_COUNT, GFP_KERNEL); + if (!macres) { + printk(KERN_INFO "Alchemy: no memory for MAC1 resources\n"); + return; + } + memcpy(macres, au1xxx_eth1_resources[ctype], + sizeof(struct resource) * MAC_RES_COUNT); + au1xxx_eth1_device.resource = macres; + + ethaddr[5] += 1; /* next addr for 2nd MAC */ + if (!i && !is_valid_ether_addr(au1xxx_eth1_platform_data.mac)) + memcpy(au1xxx_eth1_platform_data.mac, ethaddr, 6); + + /* Register second MAC if enabled in pinfunc */ + if (!(au_readl(SYS_PINFUNC) & (u32)SYS_PF_NI2)) { + ret = platform_device_register(&au1xxx_eth1_device); + if (ret) + printk(KERN_INFO "Alchemy: failed to register MAC1\n"); + } } static struct platform_device *au1xxx_platform_devices[] __initdata = { @@ -472,33 +539,17 @@ static struct platform_device *au1xxx_platform_devices[] __initdata = { #ifdef SMBUS_PSC_BASE &pbdb_smbus_device, #endif - &au1xxx_eth0_device, }; static int __init au1xxx_platform_init(void) { - int err, i, ctype = alchemy_get_cputype(); - unsigned char ethaddr[6]; + int err, ctype = alchemy_get_cputype(); alchemy_setup_uarts(ctype); - - /* use firmware-provided mac addr if available and necessary */ - i = prom_get_ethernet_addr(ethaddr); - if (!i && !is_valid_ether_addr(au1xxx_eth0_platform_data.mac)) - memcpy(au1xxx_eth0_platform_data.mac, ethaddr, 6); + alchemy_setup_macs(ctype); err = platform_add_devices(au1xxx_platform_devices, ARRAY_SIZE(au1xxx_platform_devices)); -#ifndef CONFIG_SOC_AU1100 - ethaddr[5] += 1; /* next addr for 2nd MAC */ - if (!i && !is_valid_ether_addr(au1xxx_eth1_platform_data.mac)) - memcpy(au1xxx_eth1_platform_data.mac, ethaddr, 6); - - /* Register second MAC if enabled in pinfunc */ - if (!err && !(au_readl(SYS_PINFUNC) & (u32)SYS_PF_NI2)) - err = platform_device_register(&au1xxx_eth1_device); -#endif - return err; } diff --git a/arch/mips/include/asm/mach-au1x00/au1000.h b/arch/mips/include/asm/mach-au1x00/au1000.h index c4ffb20..415d287 100644 --- a/arch/mips/include/asm/mach-au1x00/au1000.h +++ b/arch/mips/include/asm/mach-au1x00/au1000.h @@ -219,6 +219,20 @@ static inline void alchemy_uart_putchar(u32 uart_phys, u8 c) wmb(); } +/* return number of ethernet MACs on a given cputype */ +static inline int alchemy_get_macs(int type) +{ + switch (type) { + case ALCHEMY_CPU_AU1000: + case ALCHEMY_CPU_AU1500: + case ALCHEMY_CPU_AU1550: + return 2; + case ALCHEMY_CPU_AU1100: + return 1; + } + return 0; +} + /* arch/mips/au1000/common/clocks.c */ extern void set_au1x00_speed(unsigned int new_freq); extern unsigned int get_au1x00_speed(void); @@ -673,6 +687,12 @@ enum soc_au1200_ints { */ #define AU1000_IC0_PHYS_ADDR 0x10400000 /* 01234 */ +#define AU1000_MAC0_PHYS_ADDR 0x10500000 /* 023 */ +#define AU1000_MAC1_PHYS_ADDR 0x10510000 /* 023 */ +#define AU1000_MACEN_PHYS_ADDR 0x10520000 /* 023 */ +#define AU1500_MAC0_PHYS_ADDR 0x11500000 /* 1 */ +#define AU1500_MAC1_PHYS_ADDR 0x11510000 /* 1 */ +#define AU1500_MACEN_PHYS_ADDR 0x11520000 /* 1 */ #define AU1000_UART0_PHYS_ADDR 0x11100000 /* 01234 */ #define AU1000_UART1_PHYS_ADDR 0x11200000 /* 0234 */ #define AU1000_UART2_PHYS_ADDR 0x11300000 /* 0 */ @@ -680,6 +700,8 @@ enum soc_au1200_ints { #define AU1000_IC1_PHYS_ADDR 0x11800000 /* 01234 */ #define AU1550_DBDMA_PHYS_ADDR 0x14002000 /* 34 */ #define AU1550_DBDMA_CONF_PHYS_ADDR 0x14003000 /* 34 */ +#define AU1000_MACDMA0_PHYS_ADDR 0x14004000 /* 0123 */ +#define AU1000_MACDMA1_PHYS_ADDR 0x14004200 /* 0123 */ #ifdef CONFIG_SOC_AU1000 @@ -697,11 +719,6 @@ enum soc_au1200_ints { #define USBH_PHYS_ADDR 0x10100000 #define USBD_PHYS_ADDR 0x10200000 #define IRDA_PHYS_ADDR 0x10300000 -#define MAC0_PHYS_ADDR 0x10500000 -#define MAC1_PHYS_ADDR 0x10510000 -#define MACEN_PHYS_ADDR 0x10520000 -#define MACDMA0_PHYS_ADDR 0x14004000 -#define MACDMA1_PHYS_ADDR 0x14004200 #define I2S_PHYS_ADDR 0x11000000 #define SSI0_PHYS_ADDR 0x11600000 #define SSI1_PHYS_ADDR 0x11680000 @@ -728,11 +745,6 @@ enum soc_au1200_ints { #define USBH_PHYS_ADDR 0x10100000 #define USBD_PHYS_ADDR 0x10200000 #define PCI_PHYS_ADDR 0x14005000 -#define MAC0_PHYS_ADDR 0x11500000 -#define MAC1_PHYS_ADDR 0x11510000 -#define MACEN_PHYS_ADDR 0x11520000 -#define MACDMA0_PHYS_ADDR 0x14004000 -#define MACDMA1_PHYS_ADDR 0x14004200 #define I2S_PHYS_ADDR 0x11000000 #define GPIO2_PHYS_ADDR 0x11700000 #define SYS_PHYS_ADDR 0x11900000 @@ -764,10 +776,6 @@ enum soc_au1200_ints { #define USBH_PHYS_ADDR 0x10100000 #define USBD_PHYS_ADDR 0x10200000 #define IRDA_PHYS_ADDR 0x10300000 -#define MAC0_PHYS_ADDR 0x10500000 -#define MACEN_PHYS_ADDR 0x10520000 -#define MACDMA0_PHYS_ADDR 0x14004000 -#define MACDMA1_PHYS_ADDR 0x14004200 #define I2S_PHYS_ADDR 0x11000000 #define SSI0_PHYS_ADDR 0x11600000 #define SSI1_PHYS_ADDR 0x11680000 @@ -787,11 +795,6 @@ enum soc_au1200_ints { #define USBH_PHYS_ADDR 0x14020000 #define USBD_PHYS_ADDR 0x10200000 #define PCI_PHYS_ADDR 0x14005000 -#define MAC0_PHYS_ADDR 0x10500000 -#define MAC1_PHYS_ADDR 0x10510000 -#define MACEN_PHYS_ADDR 0x10520000 -#define MACDMA0_PHYS_ADDR 0x14004000 -#define MACDMA1_PHYS_ADDR 0x14004200 #define GPIO2_PHYS_ADDR 0x11700000 #define SYS_PHYS_ADDR 0x11900000 #define PE_PHYS_ADDR 0x14008000 @@ -870,12 +873,6 @@ enum soc_au1200_ints { #define USB_OHCI_BASE 0x10100000 /* phys addr for ioremap */ #define USB_HOST_CONFIG 0xB017FFFC #define FOR_PLATFORM_C_USB_HOST_INT AU1000_USB_HOST_INT - -#define AU1000_ETH0_BASE 0xB0500000 -#define AU1000_ETH1_BASE 0xB0510000 -#define AU1000_MAC0_ENABLE 0xB0520000 -#define AU1000_MAC1_ENABLE 0xB0520004 -#define NUM_ETH_INTERFACES 2 #endif /* CONFIG_SOC_AU1000 */ /* Au1500 */ @@ -887,12 +884,6 @@ enum soc_au1200_ints { #define USB_OHCI_BASE 0x10100000 /* phys addr for ioremap */ #define USB_HOST_CONFIG 0xB017fffc #define FOR_PLATFORM_C_USB_HOST_INT AU1500_USB_HOST_INT - -#define AU1500_ETH0_BASE 0xB1500000 -#define AU1500_ETH1_BASE 0xB1510000 -#define AU1500_MAC0_ENABLE 0xB1520000 -#define AU1500_MAC1_ENABLE 0xB1520004 -#define NUM_ETH_INTERFACES 2 #endif /* CONFIG_SOC_AU1500 */ /* Au1100 */ @@ -904,10 +895,6 @@ enum soc_au1200_ints { #define USB_OHCI_BASE 0x10100000 /* phys addr for ioremap */ #define USB_HOST_CONFIG 0xB017FFFC #define FOR_PLATFORM_C_USB_HOST_INT AU1100_USB_HOST_INT - -#define AU1100_ETH0_BASE 0xB0500000 -#define AU1100_MAC0_ENABLE 0xB0520000 -#define NUM_ETH_INTERFACES 1 #endif /* CONFIG_SOC_AU1100 */ #ifdef CONFIG_SOC_AU1550 @@ -917,12 +904,6 @@ enum soc_au1200_ints { #define USB_OHCI_LEN 0x00060000 #define USB_HOST_CONFIG 0xB4027ffc #define FOR_PLATFORM_C_USB_HOST_INT AU1550_USB_HOST_INT - -#define AU1550_ETH0_BASE 0xB0500000 -#define AU1550_ETH1_BASE 0xB0510000 -#define AU1550_MAC0_ENABLE 0xB0520000 -#define AU1550_MAC1_ENABLE 0xB0520004 -#define NUM_ETH_INTERFACES 2 #endif /* CONFIG_SOC_AU1550 */ -- cgit v0.10.2 From 5d4ddcb4279672e69136e746d6de6f01b501b853 Mon Sep 17 00:00:00 2001 From: Manuel Lauss Date: Sun, 8 May 2011 10:42:19 +0200 Subject: MIPS: Alchemy: Cleanup DMA addresses According to the databooks, the Au1000 DMA engine must be programmed with the physical FIFO addresses. This patch does that; furthermore this opened the possibility to get rid of a lot of now unnecessary address defines. Signed-off-by: Manuel Lauss To: Linux-MIPS Cc: Florian Fainelli Cc: Wolfgang Grandegger Patchwork: https://patchwork.linux-mips.org/patch/2348/ Signed-off-by: Ralf Baechle io = DMA_CHANNEL_BASE + i * DMA_CHANNEL_LEN; + chan->io = KSEG1ADDR(AU1000_DMA_PHYS_ADDR) + i * DMA_CHANNEL_LEN; chan->dev_id = dev_id; chan->dev_str = dev_str; chan->fifo_addr = dev->fifo_addr; diff --git a/arch/mips/alchemy/common/platform.c b/arch/mips/alchemy/common/platform.c index 541fff2..3b2c18b 100644 --- a/arch/mips/alchemy/common/platform.c +++ b/arch/mips/alchemy/common/platform.c @@ -283,8 +283,8 @@ extern struct au1xmmc_platform_data au1xmmc_platdata[2]; static struct resource au1200_mmc0_resources[] = { [0] = { - .start = SD0_PHYS_ADDR, - .end = SD0_PHYS_ADDR + 0x7ffff, + .start = AU1100_SD0_PHYS_ADDR, + .end = AU1100_SD0_PHYS_ADDR + 0xfff, .flags = IORESOURCE_MEM, }, [1] = { @@ -319,8 +319,8 @@ static struct platform_device au1200_mmc0_device = { #ifndef CONFIG_MIPS_DB1200 static struct resource au1200_mmc1_resources[] = { [0] = { - .start = SD1_PHYS_ADDR, - .end = SD1_PHYS_ADDR + 0x7ffff, + .start = AU1100_SD1_PHYS_ADDR, + .end = AU1100_SD1_PHYS_ADDR + 0xfff, .flags = IORESOURCE_MEM, }, [1] = { diff --git a/arch/mips/include/asm/mach-au1x00/au1000.h b/arch/mips/include/asm/mach-au1x00/au1000.h index 415d287..2dfff4f 100644 --- a/arch/mips/include/asm/mach-au1x00/au1000.h +++ b/arch/mips/include/asm/mach-au1x00/au1000.h @@ -686,10 +686,15 @@ enum soc_au1200_ints { * 0..au1000 1..au1500 2..au1100 3..au1550 4..au1200 */ +#define AU1000_AC97_PHYS_ADDR 0x10000000 /* 012 */ +#define AU1000_USBD_PHYS_ADDR 0x10200000 /* 0123 */ #define AU1000_IC0_PHYS_ADDR 0x10400000 /* 01234 */ #define AU1000_MAC0_PHYS_ADDR 0x10500000 /* 023 */ #define AU1000_MAC1_PHYS_ADDR 0x10510000 /* 023 */ #define AU1000_MACEN_PHYS_ADDR 0x10520000 /* 023 */ +#define AU1100_SD0_PHYS_ADDR 0x10600000 /* 24 */ +#define AU1100_SD1_PHYS_ADDR 0x10680000 /* 24 */ +#define AU1000_I2S_PHYS_ADDR 0x11000000 /* 02 */ #define AU1500_MAC0_PHYS_ADDR 0x11500000 /* 1 */ #define AU1500_MAC1_PHYS_ADDR 0x11510000 /* 1 */ #define AU1500_MACEN_PHYS_ADDR 0x11520000 /* 1 */ @@ -698,6 +703,7 @@ enum soc_au1200_ints { #define AU1000_UART2_PHYS_ADDR 0x11300000 /* 0 */ #define AU1000_UART3_PHYS_ADDR 0x11400000 /* 0123 */ #define AU1000_IC1_PHYS_ADDR 0x11800000 /* 01234 */ +#define AU1000_DMA_PHYS_ADDR 0x14002000 /* 012 */ #define AU1550_DBDMA_PHYS_ADDR 0x14002000 /* 34 */ #define AU1550_DBDMA_CONF_PHYS_ADDR 0x14003000 /* 34 */ #define AU1000_MACDMA0_PHYS_ADDR 0x14004000 /* 0123 */ @@ -707,19 +713,8 @@ enum soc_au1200_ints { #ifdef CONFIG_SOC_AU1000 #define MEM_PHYS_ADDR 0x14000000 #define STATIC_MEM_PHYS_ADDR 0x14001000 -#define DMA0_PHYS_ADDR 0x14002000 -#define DMA1_PHYS_ADDR 0x14002100 -#define DMA2_PHYS_ADDR 0x14002200 -#define DMA3_PHYS_ADDR 0x14002300 -#define DMA4_PHYS_ADDR 0x14002400 -#define DMA5_PHYS_ADDR 0x14002500 -#define DMA6_PHYS_ADDR 0x14002600 -#define DMA7_PHYS_ADDR 0x14002700 -#define AC97_PHYS_ADDR 0x10000000 #define USBH_PHYS_ADDR 0x10100000 -#define USBD_PHYS_ADDR 0x10200000 #define IRDA_PHYS_ADDR 0x10300000 -#define I2S_PHYS_ADDR 0x11000000 #define SSI0_PHYS_ADDR 0x11600000 #define SSI1_PHYS_ADDR 0x11680000 #define SYS_PHYS_ADDR 0x11900000 @@ -733,19 +728,8 @@ enum soc_au1200_ints { #ifdef CONFIG_SOC_AU1500 #define MEM_PHYS_ADDR 0x14000000 #define STATIC_MEM_PHYS_ADDR 0x14001000 -#define DMA0_PHYS_ADDR 0x14002000 -#define DMA1_PHYS_ADDR 0x14002100 -#define DMA2_PHYS_ADDR 0x14002200 -#define DMA3_PHYS_ADDR 0x14002300 -#define DMA4_PHYS_ADDR 0x14002400 -#define DMA5_PHYS_ADDR 0x14002500 -#define DMA6_PHYS_ADDR 0x14002600 -#define DMA7_PHYS_ADDR 0x14002700 -#define AC97_PHYS_ADDR 0x10000000 #define USBH_PHYS_ADDR 0x10100000 -#define USBD_PHYS_ADDR 0x10200000 #define PCI_PHYS_ADDR 0x14005000 -#define I2S_PHYS_ADDR 0x11000000 #define GPIO2_PHYS_ADDR 0x11700000 #define SYS_PHYS_ADDR 0x11900000 #define PCI_MEM_PHYS_ADDR 0x400000000ULL @@ -762,21 +746,8 @@ enum soc_au1200_ints { #ifdef CONFIG_SOC_AU1100 #define MEM_PHYS_ADDR 0x14000000 #define STATIC_MEM_PHYS_ADDR 0x14001000 -#define DMA0_PHYS_ADDR 0x14002000 -#define DMA1_PHYS_ADDR 0x14002100 -#define DMA2_PHYS_ADDR 0x14002200 -#define DMA3_PHYS_ADDR 0x14002300 -#define DMA4_PHYS_ADDR 0x14002400 -#define DMA5_PHYS_ADDR 0x14002500 -#define DMA6_PHYS_ADDR 0x14002600 -#define DMA7_PHYS_ADDR 0x14002700 -#define SD0_PHYS_ADDR 0x10600000 -#define SD1_PHYS_ADDR 0x10680000 -#define AC97_PHYS_ADDR 0x10000000 #define USBH_PHYS_ADDR 0x10100000 -#define USBD_PHYS_ADDR 0x10200000 #define IRDA_PHYS_ADDR 0x10300000 -#define I2S_PHYS_ADDR 0x11000000 #define SSI0_PHYS_ADDR 0x11600000 #define SSI1_PHYS_ADDR 0x11680000 #define GPIO2_PHYS_ADDR 0x11700000 @@ -793,7 +764,6 @@ enum soc_au1200_ints { #define MEM_PHYS_ADDR 0x14000000 #define STATIC_MEM_PHYS_ADDR 0x14001000 #define USBH_PHYS_ADDR 0x14020000 -#define USBD_PHYS_ADDR 0x10200000 #define PCI_PHYS_ADDR 0x14005000 #define GPIO2_PHYS_ADDR 0x11700000 #define SYS_PHYS_ADDR 0x11900000 @@ -824,8 +794,6 @@ enum soc_au1200_ints { #define SYS_PHYS_ADDR 0x11900000 #define PSC0_PHYS_ADDR 0x11A00000 #define PSC1_PHYS_ADDR 0x11B00000 -#define SD0_PHYS_ADDR 0x10600000 -#define SD1_PHYS_ADDR 0x10680000 #define LCD_PHYS_ADDR 0x15000000 #define SWCNT_PHYS_ADDR 0x1110010C #define MAEFE_PHYS_ADDR 0x14012000 @@ -867,9 +835,6 @@ enum soc_au1200_ints { /* Au1000 */ #ifdef CONFIG_SOC_AU1000 -#define UART0_ADDR 0xB1100000 -#define UART3_ADDR 0xB1400000 - #define USB_OHCI_BASE 0x10100000 /* phys addr for ioremap */ #define USB_HOST_CONFIG 0xB017FFFC #define FOR_PLATFORM_C_USB_HOST_INT AU1000_USB_HOST_INT @@ -878,9 +843,6 @@ enum soc_au1200_ints { /* Au1500 */ #ifdef CONFIG_SOC_AU1500 -#define UART0_ADDR 0xB1100000 -#define UART3_ADDR 0xB1400000 - #define USB_OHCI_BASE 0x10100000 /* phys addr for ioremap */ #define USB_HOST_CONFIG 0xB017fffc #define FOR_PLATFORM_C_USB_HOST_INT AU1500_USB_HOST_INT @@ -889,16 +851,12 @@ enum soc_au1200_ints { /* Au1100 */ #ifdef CONFIG_SOC_AU1100 -#define UART0_ADDR 0xB1100000 -#define UART3_ADDR 0xB1400000 - #define USB_OHCI_BASE 0x10100000 /* phys addr for ioremap */ #define USB_HOST_CONFIG 0xB017FFFC #define FOR_PLATFORM_C_USB_HOST_INT AU1100_USB_HOST_INT #endif /* CONFIG_SOC_AU1100 */ #ifdef CONFIG_SOC_AU1550 -#define UART0_ADDR 0xB1100000 #define USB_OHCI_BASE 0x14020000 /* phys addr for ioremap */ #define USB_OHCI_LEN 0x00060000 @@ -909,8 +867,6 @@ enum soc_au1200_ints { #ifdef CONFIG_SOC_AU1200 -#define UART0_ADDR 0xB1100000 - #define USB_UOC_BASE 0x14020020 #define USB_UOC_LEN 0x20 #define USB_OHCI_BASE 0x14020100 @@ -1534,12 +1490,6 @@ enum soc_au1200_ints { # define AC97C_RS (1 << 1) # define AC97C_CE (1 << 0) -/* Secure Digital (SD) Controller */ -#define SD0_XMIT_FIFO 0xB0600000 -#define SD0_RECV_FIFO 0xB0600004 -#define SD1_XMIT_FIFO 0xB0680000 -#define SD1_RECV_FIFO 0xB0680004 - #if defined(CONFIG_SOC_AU1500) || defined(CONFIG_SOC_AU1550) /* Au1500 PCI Controller */ #define Au1500_CFG_BASE 0xB4005000 /* virtual, KSEG1 addr */ diff --git a/arch/mips/include/asm/mach-au1x00/au1000_dma.h b/arch/mips/include/asm/mach-au1x00/au1000_dma.h index c333b4e..59f5b55 100644 --- a/arch/mips/include/asm/mach-au1x00/au1000_dma.h +++ b/arch/mips/include/asm/mach-au1x00/au1000_dma.h @@ -37,10 +37,6 @@ #define NUM_AU1000_DMA_CHANNELS 8 -/* DMA Channel Base Addresses */ -#define DMA_CHANNEL_BASE 0xB4002000 -#define DMA_CHANNEL_LEN 0x00000100 - /* DMA Channel Register Offsets */ #define DMA_MODE_SET 0x00000000 #define DMA_MODE_READ DMA_MODE_SET -- cgit v0.10.2 From b7f720d68c0042cc8ce496e31a61df79a77f1b48 Mon Sep 17 00:00:00 2001 From: Manuel Lauss Date: Sun, 8 May 2011 10:42:20 +0200 Subject: MIPS: Alchemy: Clean up GPIO registers and accessors remove au_readl/au_writel, remove the predefined GPIO1/2 KSEG1 register addresses and fix the fallout in all boards and drivers. This also fixes a bug in the mtx-1_wdt driver which was introduced by commit 6ea8115bb6f359df4f45152f2b40e1d4d1891392 ("Convert mtx1 wdt to be a platform device and use generic GPIO API") before this patch mtx-1_wdt only modified GPIO215, the patch then used the gpio resource information as bit index into the GPIO2 register but the conversion to the GPIO API didn't realize that. With this patch the drivers original behaviour is restored and GPIO15 is left alone. Signed-off-by: Manuel Lauss Cc: Florian Fainelli To: Linux-MIPS Cc: linux-watchdog@vger.kernel.org Cc: Wim Van Sebroeck Patchwork: https://patchwork.linux-mips.org/patch/2381/ Signed-off-by: Ralf Baechle +#include #include #include #include @@ -470,7 +471,7 @@ static int __init au1xxx_nand_init(void) #ifdef CONFIG_MIPS_PB1550 /* set gpio206 high */ - au_writel(au_readl(GPIO2_DIR) & ~(1 << 6), GPIO2_DIR); + gpio_direction_input(206); boot_swapboot = (au_readl(MEM_STSTAT) & (0x7 << 1)) | ((bcsr_read(BCSR_STATUS) >> 6) & 0x1); diff --git a/drivers/watchdog/mtx-1_wdt.c b/drivers/watchdog/mtx-1_wdt.c index 5ec5ac1..1479dc4 100644 --- a/drivers/watchdog/mtx-1_wdt.c +++ b/drivers/watchdog/mtx-1_wdt.c @@ -66,6 +66,7 @@ static struct { int default_ticks; unsigned long inuse; unsigned gpio; + int gstate; } mtx1_wdt_device; static void mtx1_wdt_trigger(unsigned long unused) @@ -75,13 +76,13 @@ static void mtx1_wdt_trigger(unsigned long unused) spin_lock(&mtx1_wdt_device.lock); if (mtx1_wdt_device.running) ticks--; - /* - * toggle GPIO2_15 - */ - tmp = au_readl(GPIO2_DIR); - tmp = (tmp & ~(1 << mtx1_wdt_device.gpio)) | - ((~tmp) & (1 << mtx1_wdt_device.gpio)); - au_writel(tmp, GPIO2_DIR); + + /* toggle wdt gpio */ + mtx1_wdt_device.gstate = ~mtx1_wdt_device.gstate; + if (mtx1_wdt_device.gstate) + gpio_direction_output(mtx1_wdt_device.gpio, 1); + else + gpio_direction_input(mtx1_wdt_device.gpio); if (mtx1_wdt_device.queue && ticks) mod_timer(&mtx1_wdt_device.timer, jiffies + MTX1_WDT_INTERVAL); @@ -103,7 +104,8 @@ static void mtx1_wdt_start(void) spin_lock_irqsave(&mtx1_wdt_device.lock, flags); if (!mtx1_wdt_device.queue) { mtx1_wdt_device.queue = 1; - gpio_set_value(mtx1_wdt_device.gpio, 1); + mtx1_wdt_device.gstate = 1; + gpio_direction_output(mtx1_wdt_device.gpio, 1); mod_timer(&mtx1_wdt_device.timer, jiffies + MTX1_WDT_INTERVAL); } mtx1_wdt_device.running++; @@ -117,7 +119,8 @@ static int mtx1_wdt_stop(void) spin_lock_irqsave(&mtx1_wdt_device.lock, flags); if (mtx1_wdt_device.queue) { mtx1_wdt_device.queue = 0; - gpio_set_value(mtx1_wdt_device.gpio, 0); + mtx1_wdt_device.gstate = 0; + gpio_direction_output(mtx1_wdt_device.gpio, 0); } ticks = mtx1_wdt_device.default_ticks; spin_unlock_irqrestore(&mtx1_wdt_device.lock, flags); -- cgit v0.10.2 From b3ae52b6b0335eba547221aad2cb3c50902e3d2d Mon Sep 17 00:00:00 2001 From: Hauke Mehrtens Date: Tue, 10 May 2011 23:31:30 +0200 Subject: SSB: Change fallback sprom to callback mechanism. Some embedded devices like the Netgear WNDR3300 have two SSB based cards without an own sprom on the pci bus. We have to provide two different fallback sproms for these and this was not possible with the old solution. In the bcm47xx architecture the sprom data is stored in the nvram in the main flash storage. The architecture code will be able to fill the sprom with the stored data based on the bus where the device was found. The bcm63xx code should do the same thing as before, just using the new API. Acked-by: Michael Buesch Cc: netdev@vger.kernel.org Cc: linux-wireless@vger.kernel.org Cc: Florian Fainelli Signed-off-by: Hauke Mehrtens Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/2362/ Signed-off-by: Ralf Baechle diff --git a/arch/mips/bcm63xx/boards/board_bcm963xx.c b/arch/mips/bcm63xx/boards/board_bcm963xx.c index 8dba8cf..40b223b 100644 --- a/arch/mips/bcm63xx/boards/board_bcm963xx.c +++ b/arch/mips/bcm63xx/boards/board_bcm963xx.c @@ -643,6 +643,17 @@ static struct ssb_sprom bcm63xx_sprom = { .boardflags_lo = 0x2848, .boardflags_hi = 0x0000, }; + +int bcm63xx_get_fallback_sprom(struct ssb_bus *bus, struct ssb_sprom *out) +{ + if (bus->bustype == SSB_BUSTYPE_PCI) { + memcpy(out, &bcm63xx_sprom, sizeof(struct ssb_sprom)); + return 0; + } else { + printk(KERN_ERR PFX "unable to fill SPROM for given bustype.\n"); + return -EINVAL; + } +} #endif /* @@ -793,8 +804,9 @@ void __init board_prom_init(void) if (!board_get_mac_address(bcm63xx_sprom.il0mac)) { memcpy(bcm63xx_sprom.et0mac, bcm63xx_sprom.il0mac, ETH_ALEN); memcpy(bcm63xx_sprom.et1mac, bcm63xx_sprom.il0mac, ETH_ALEN); - if (ssb_arch_set_fallback_sprom(&bcm63xx_sprom) < 0) - printk(KERN_ERR "failed to register fallback SPROM\n"); + if (ssb_arch_register_fallback_sprom( + &bcm63xx_get_fallback_sprom) < 0) + printk(KERN_ERR PFX "failed to register fallback SPROM\n"); } #endif } diff --git a/drivers/ssb/pci.c b/drivers/ssb/pci.c index 6f34963..7ad4858 100644 --- a/drivers/ssb/pci.c +++ b/drivers/ssb/pci.c @@ -662,7 +662,6 @@ static int sprom_extract(struct ssb_bus *bus, struct ssb_sprom *out, static int ssb_pci_sprom_get(struct ssb_bus *bus, struct ssb_sprom *sprom) { - const struct ssb_sprom *fallback; int err; u16 *buf; @@ -707,10 +706,17 @@ static int ssb_pci_sprom_get(struct ssb_bus *bus, if (err) { /* All CRC attempts failed. * Maybe there is no SPROM on the device? - * If we have a fallback, use that. */ - fallback = ssb_get_fallback_sprom(); - if (fallback) { - memcpy(sprom, fallback, sizeof(*sprom)); + * Now we ask the arch code if there is some sprom + * available for this device in some other storage */ + err = ssb_fill_sprom_with_fallback(bus, sprom); + if (err) { + ssb_printk(KERN_WARNING PFX "WARNING: Using" + " fallback SPROM failed (err %d)\n", + err); + } else { + ssb_dprintk(KERN_DEBUG PFX "Using SPROM" + " revision %d provided by" + " platform.\n", sprom->revision); err = 0; goto out_free; } diff --git a/drivers/ssb/sprom.c b/drivers/ssb/sprom.c index 5f34d7a..45ff0e3 100644 --- a/drivers/ssb/sprom.c +++ b/drivers/ssb/sprom.c @@ -17,7 +17,7 @@ #include -static const struct ssb_sprom *fallback_sprom; +static int(*get_fallback_sprom)(struct ssb_bus *dev, struct ssb_sprom *out); static int sprom2hex(const u16 *sprom, char *buf, size_t buf_len, @@ -145,36 +145,43 @@ out: } /** - * ssb_arch_set_fallback_sprom - Set a fallback SPROM for use if no SPROM is found. + * ssb_arch_register_fallback_sprom - Registers a method providing a + * fallback SPROM if no SPROM is found. * - * @sprom: The SPROM data structure to register. + * @sprom_callback: The callback function. * - * With this function the architecture implementation may register a fallback - * SPROM data structure. The fallback is only used for PCI based SSB devices, - * where no valid SPROM can be found in the shadow registers. + * With this function the architecture implementation may register a + * callback handler which fills the SPROM data structure. The fallback is + * only used for PCI based SSB devices, where no valid SPROM can be found + * in the shadow registers. * - * This function is useful for weird architectures that have a half-assed SSB device - * hardwired to their PCI bus. + * This function is useful for weird architectures that have a half-assed + * SSB device hardwired to their PCI bus. * - * Note that it does only work with PCI attached SSB devices. PCMCIA devices currently - * don't use this fallback. - * Architectures must provide the SPROM for native SSB devices anyway, - * so the fallback also isn't used for native devices. + * Note that it does only work with PCI attached SSB devices. PCMCIA + * devices currently don't use this fallback. + * Architectures must provide the SPROM for native SSB devices anyway, so + * the fallback also isn't used for native devices. * - * This function is available for architecture code, only. So it is not exported. + * This function is available for architecture code, only. So it is not + * exported. */ -int ssb_arch_set_fallback_sprom(const struct ssb_sprom *sprom) +int ssb_arch_register_fallback_sprom(int (*sprom_callback)(struct ssb_bus *bus, + struct ssb_sprom *out)) { - if (fallback_sprom) + if (get_fallback_sprom) return -EEXIST; - fallback_sprom = sprom; + get_fallback_sprom = sprom_callback; return 0; } -const struct ssb_sprom *ssb_get_fallback_sprom(void) +int ssb_fill_sprom_with_fallback(struct ssb_bus *bus, struct ssb_sprom *out) { - return fallback_sprom; + if (!get_fallback_sprom) + return -ENOENT; + + return get_fallback_sprom(bus, out); } /* http://bcm-v4.sipsolutions.net/802.11/IsSpromAvailable */ diff --git a/drivers/ssb/ssb_private.h b/drivers/ssb/ssb_private.h index 0331139..7765301 100644 --- a/drivers/ssb/ssb_private.h +++ b/drivers/ssb/ssb_private.h @@ -171,7 +171,8 @@ ssize_t ssb_attr_sprom_store(struct ssb_bus *bus, const char *buf, size_t count, int (*sprom_check_crc)(const u16 *sprom, size_t size), int (*sprom_write)(struct ssb_bus *bus, const u16 *sprom)); -extern const struct ssb_sprom *ssb_get_fallback_sprom(void); +extern int ssb_fill_sprom_with_fallback(struct ssb_bus *bus, + struct ssb_sprom *out); /* core.c */ diff --git a/include/linux/ssb/ssb.h b/include/linux/ssb/ssb.h index 9659eff..045f72a 100644 --- a/include/linux/ssb/ssb.h +++ b/include/linux/ssb/ssb.h @@ -404,7 +404,9 @@ extern bool ssb_is_sprom_available(struct ssb_bus *bus); /* Set a fallback SPROM. * See kdoc at the function definition for complete documentation. */ -extern int ssb_arch_set_fallback_sprom(const struct ssb_sprom *sprom); +extern int ssb_arch_register_fallback_sprom( + int (*sprom_callback)(struct ssb_bus *bus, + struct ssb_sprom *out)); /* Suspend a SSB bus. * Call this from the parent bus suspend routine. */ -- cgit v0.10.2 From a7c62f8564357532872e106f0fa383728cf886cc Mon Sep 17 00:00:00 2001 From: Hauke Mehrtens Date: Tue, 10 May 2011 23:31:31 +0200 Subject: MIPS: BCM47xx: Extend bcm47xx_fill_sprom with prefix. When an other SSB based device without an own SPROM is attached, using the PCI bus to the main SSB based device, the data normally found in the SPROM will be stored in the NVRAM on modern devices. The keys, to load the data from the NVRAM, are all using some sort of prefix like pci/1/1/, pci/1/3/ or sb/1/ before the actual key. This patch extends bcm47xx_fill_sprom() to make it possible to read out these values when some prefix was used. The keys for the SPROM data used on the main chip does not have a prefix. Signed-off-by: Hauke Mehrtens Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/2363/ Signed-off-by: Ralf Baechle diff --git a/arch/mips/bcm47xx/setup.c b/arch/mips/bcm47xx/setup.c index c95f90b..bbfcf9b 100644 --- a/arch/mips/bcm47xx/setup.c +++ b/arch/mips/bcm47xx/setup.c @@ -57,10 +57,23 @@ static void bcm47xx_machine_halt(void) } #define READ_FROM_NVRAM(_outvar, name, buf) \ - if (nvram_getenv(name, buf, sizeof(buf)) >= 0)\ + if (nvram_getprefix(prefix, name, buf, sizeof(buf)) >= 0)\ sprom->_outvar = simple_strtoul(buf, NULL, 0); -static void bcm47xx_fill_sprom(struct ssb_sprom *sprom) +static inline int nvram_getprefix(const char *prefix, char *name, + char *buf, int len) +{ + if (prefix) { + char key[100]; + + snprintf(key, sizeof(key), "%s%s", prefix, name); + return nvram_getenv(key, buf, len); + } + + return nvram_getenv(name, buf, len); +} + +static void bcm47xx_fill_sprom(struct ssb_sprom *sprom, const char *prefix) { char buf[100]; u32 boardflags; @@ -69,11 +82,11 @@ static void bcm47xx_fill_sprom(struct ssb_sprom *sprom) sprom->revision = 1; /* Fallback: Old hardware does not define this. */ READ_FROM_NVRAM(revision, "sromrev", buf); - if (nvram_getenv("il0macaddr", buf, sizeof(buf)) >= 0) + if (nvram_getprefix(prefix, "il0macaddr", buf, sizeof(buf)) >= 0) nvram_parse_macaddr(buf, sprom->il0mac); - if (nvram_getenv("et0macaddr", buf, sizeof(buf)) >= 0) + if (nvram_getprefix(prefix, "et0macaddr", buf, sizeof(buf)) >= 0) nvram_parse_macaddr(buf, sprom->et0mac); - if (nvram_getenv("et1macaddr", buf, sizeof(buf)) >= 0) + if (nvram_getprefix(prefix, "et1macaddr", buf, sizeof(buf)) >= 0) nvram_parse_macaddr(buf, sprom->et1mac); READ_FROM_NVRAM(et0phyaddr, "et0phyaddr", buf); READ_FROM_NVRAM(et1phyaddr, "et1phyaddr", buf); @@ -125,14 +138,14 @@ static void bcm47xx_fill_sprom(struct ssb_sprom *sprom) READ_FROM_NVRAM(ofdm5gpo, "ofdm5gpo", buf); READ_FROM_NVRAM(ofdm5ghpo, "ofdm5ghpo", buf); - if (nvram_getenv("boardflags", buf, sizeof(buf)) >= 0) { + if (nvram_getprefix(prefix, "boardflags", buf, sizeof(buf)) >= 0) { boardflags = simple_strtoul(buf, NULL, 0); if (boardflags) { sprom->boardflags_lo = (boardflags & 0x0000FFFFU); sprom->boardflags_hi = (boardflags & 0xFFFF0000U) >> 16; } } - if (nvram_getenv("boardflags2", buf, sizeof(buf)) >= 0) { + if (nvram_getprefix(prefix, "boardflags2", buf, sizeof(buf)) >= 0) { boardflags = simple_strtoul(buf, NULL, 0); if (boardflags) { sprom->boardflags2_lo = (boardflags & 0x0000FFFFU); @@ -158,7 +171,7 @@ static int bcm47xx_get_invariants(struct ssb_bus *bus, if (nvram_getenv("boardrev", buf, sizeof(buf)) >= 0) iv->boardinfo.rev = (u16)simple_strtoul(buf, NULL, 0); - bcm47xx_fill_sprom(&iv->sprom); + bcm47xx_fill_sprom(&iv->sprom, NULL); if (nvram_getenv("cardbus", buf, sizeof(buf)) >= 0) iv->has_cardbus_slot = !!simple_strtoul(buf, NULL, 10); -- cgit v0.10.2 From fe6f3642ac70d21004ddbe7242bd4548c35f1c10 Mon Sep 17 00:00:00 2001 From: Hauke Mehrtens Date: Tue, 10 May 2011 23:31:32 +0200 Subject: MIPS: BCM47xx: Register SSB fallback sprom callback We are generating the prefix based on the PCI bus address the device is on. This is done like Broadcom does it in their code expect that the the bus number is increased by one. In the SB bus implementation used by Broadcom the SB bus emulates a PCI bus so the kernel sees one PCI bus more then in our implementation. We do not handle prefixes like sb/1/ yet as they are only used on the new bus which is not implemented yet. Signed-off-by: Hauke Mehrtens Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/2364/ Signed-off-by: Ralf Baechle diff --git a/arch/mips/bcm47xx/nvram.c b/arch/mips/bcm47xx/nvram.c index e5b6615..54db815 100644 --- a/arch/mips/bcm47xx/nvram.c +++ b/arch/mips/bcm47xx/nvram.c @@ -3,6 +3,7 @@ * * Copyright (C) 2005 Broadcom Corporation * Copyright (C) 2006 Felix Fietkau + * Copyright (C) 2010-2011 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,7 +24,7 @@ static char nvram_buf[NVRAM_SPACE]; /* Probe for NVRAM header */ -static void __init early_nvram_init(void) +static void early_nvram_init(void) { struct ssb_mipscore *mcore = &ssb_bcm47xx.mipscore; struct nvram_header *header; diff --git a/arch/mips/bcm47xx/setup.c b/arch/mips/bcm47xx/setup.c index bbfcf9b..258ffcf 100644 --- a/arch/mips/bcm47xx/setup.c +++ b/arch/mips/bcm47xx/setup.c @@ -3,6 +3,7 @@ * Copyright (C) 2006 Felix Fietkau * Copyright (C) 2006 Michael Buesch * Copyright (C) 2010 Waldemar Brodkorb + * Copyright (C) 2010-2011 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 @@ -154,6 +155,22 @@ static void bcm47xx_fill_sprom(struct ssb_sprom *sprom, const char *prefix) } } +int bcm47xx_get_sprom(struct ssb_bus *bus, struct ssb_sprom *out) +{ + char prefix[10]; + + if (bus->bustype == SSB_BUSTYPE_PCI) { + snprintf(prefix, sizeof(prefix), "pci/%u/%u/", + bus->host_pci->bus->number + 1, + PCI_SLOT(bus->host_pci->devfn)); + bcm47xx_fill_sprom(out, prefix); + return 0; + } else { + printk(KERN_WARNING "bcm47xx: unable to fill SPROM for given bustype.\n"); + return -EINVAL; + } +} + static int bcm47xx_get_invariants(struct ssb_bus *bus, struct ssb_init_invariants *iv) { @@ -185,6 +202,11 @@ void __init plat_mem_setup(void) char buf[100]; struct ssb_mipscore *mcore; + err = ssb_arch_register_fallback_sprom(&bcm47xx_get_sprom); + if (err) + printk(KERN_WARNING "bcm47xx: someone else already registered" + " a ssb SPROM callback handler (err %d)\n", err); + err = ssb_bus_ssbbus_register(&ssb_bcm47xx, SSB_ENUM_BASE, bcm47xx_get_invariants); if (err) -- cgit v0.10.2 From 41790fd51f71f3744a5d142cc5369eebab8817a0 Mon Sep 17 00:00:00 2001 From: Hauke Mehrtens Date: Tue, 10 May 2011 23:31:33 +0200 Subject: MIPS: BCM47xx: Extend the filling of SPROM from NVRAM Some members of the struct ssb_sprom where not filled with data available in the NVRAM. Some attribute names in the NVRAM changed from SPROM version 3 to version 4. This patch was done by analyzing the the pci sprom parser in the ssb code and some open source parts of the braodcom wireless driver used on embedded devices. Signed-off-by: Hauke Mehrtens Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/2365/ Signed-off-by: Ralf Baechle diff --git a/arch/mips/bcm47xx/setup.c b/arch/mips/bcm47xx/setup.c index 258ffcf..73b529b 100644 --- a/arch/mips/bcm47xx/setup.c +++ b/arch/mips/bcm47xx/setup.c @@ -61,6 +61,11 @@ static void bcm47xx_machine_halt(void) if (nvram_getprefix(prefix, name, buf, sizeof(buf)) >= 0)\ sprom->_outvar = simple_strtoul(buf, NULL, 0); +#define READ_FROM_NVRAM2(_outvar, name1, name2, buf) \ + if (nvram_getprefix(prefix, name1, buf, sizeof(buf)) >= 0 || \ + nvram_getprefix(prefix, name2, buf, sizeof(buf)) >= 0)\ + sprom->_outvar = simple_strtoul(buf, NULL, 0); + static inline int nvram_getprefix(const char *prefix, char *name, char *buf, int len) { @@ -74,6 +79,27 @@ static inline int nvram_getprefix(const char *prefix, char *name, return nvram_getenv(name, buf, len); } +static u32 nvram_getu32(const char *name, char *buf, int len) +{ + int rv; + char key[100]; + u16 var0, var1; + + snprintf(key, sizeof(key), "%s0", name); + rv = nvram_getenv(key, buf, len); + /* return 0 here so this looks like unset */ + if (rv < 0) + return 0; + var0 = simple_strtoul(buf, NULL, 0); + + snprintf(key, sizeof(key), "%s1", name); + rv = nvram_getenv(key, buf, len); + if (rv < 0) + return 0; + var1 = simple_strtoul(buf, NULL, 0); + return var1 << 16 | var0; +} + static void bcm47xx_fill_sprom(struct ssb_sprom *sprom, const char *prefix) { char buf[100]; @@ -83,7 +109,8 @@ static void bcm47xx_fill_sprom(struct ssb_sprom *sprom, const char *prefix) sprom->revision = 1; /* Fallback: Old hardware does not define this. */ READ_FROM_NVRAM(revision, "sromrev", buf); - if (nvram_getprefix(prefix, "il0macaddr", buf, sizeof(buf)) >= 0) + if (nvram_getprefix(prefix, "il0macaddr", buf, sizeof(buf)) >= 0 || + nvram_getprefix(prefix, "macaddr", buf, sizeof(buf)) >= 0) nvram_parse_macaddr(buf, sprom->il0mac); if (nvram_getprefix(prefix, "et0macaddr", buf, sizeof(buf)) >= 0) nvram_parse_macaddr(buf, sprom->et0mac); @@ -109,20 +136,36 @@ static void bcm47xx_fill_sprom(struct ssb_sprom *sprom, const char *prefix) READ_FROM_NVRAM(pa1hib0, "pa1hib0", buf); READ_FROM_NVRAM(pa1hib2, "pa1hib1", buf); READ_FROM_NVRAM(pa1hib1, "pa1hib2", buf); - READ_FROM_NVRAM(gpio0, "wl0gpio0", buf); - READ_FROM_NVRAM(gpio1, "wl0gpio1", buf); - READ_FROM_NVRAM(gpio2, "wl0gpio2", buf); - READ_FROM_NVRAM(gpio3, "wl0gpio3", buf); - READ_FROM_NVRAM(maxpwr_bg, "pa0maxpwr", buf); - READ_FROM_NVRAM(maxpwr_al, "pa1lomaxpwr", buf); - READ_FROM_NVRAM(maxpwr_a, "pa1maxpwr", buf); - READ_FROM_NVRAM(maxpwr_ah, "pa1himaxpwr", buf); - READ_FROM_NVRAM(itssi_a, "pa1itssit", buf); - READ_FROM_NVRAM(itssi_bg, "pa0itssit", buf); + READ_FROM_NVRAM2(gpio0, "ledbh0", "wl0gpio0", buf); + READ_FROM_NVRAM2(gpio1, "ledbh1", "wl0gpio1", buf); + READ_FROM_NVRAM2(gpio2, "ledbh2", "wl0gpio2", buf); + READ_FROM_NVRAM2(gpio3, "ledbh3", "wl0gpio3", buf); + READ_FROM_NVRAM2(maxpwr_bg, "maxp2ga0", "pa0maxpwr", buf); + READ_FROM_NVRAM2(maxpwr_al, "maxp5gla0", "pa1lomaxpwr", buf); + READ_FROM_NVRAM2(maxpwr_a, "maxp5ga0", "pa1maxpwr", buf); + READ_FROM_NVRAM2(maxpwr_ah, "maxp5gha0", "pa1himaxpwr", buf); + READ_FROM_NVRAM2(itssi_bg, "itt5ga0", "pa0itssit", buf); + READ_FROM_NVRAM2(itssi_a, "itt2ga0", "pa1itssit", buf); READ_FROM_NVRAM(tri2g, "tri2g", buf); READ_FROM_NVRAM(tri5gl, "tri5gl", buf); READ_FROM_NVRAM(tri5g, "tri5g", buf); READ_FROM_NVRAM(tri5gh, "tri5gh", buf); + READ_FROM_NVRAM(txpid2g[0], "txpid2ga0", buf); + READ_FROM_NVRAM(txpid2g[1], "txpid2ga1", buf); + READ_FROM_NVRAM(txpid2g[2], "txpid2ga2", buf); + READ_FROM_NVRAM(txpid2g[3], "txpid2ga3", buf); + READ_FROM_NVRAM(txpid5g[0], "txpid5ga0", buf); + READ_FROM_NVRAM(txpid5g[1], "txpid5ga1", buf); + READ_FROM_NVRAM(txpid5g[2], "txpid5ga2", buf); + READ_FROM_NVRAM(txpid5g[3], "txpid5ga3", buf); + READ_FROM_NVRAM(txpid5gl[0], "txpid5gla0", buf); + READ_FROM_NVRAM(txpid5gl[1], "txpid5gla1", buf); + READ_FROM_NVRAM(txpid5gl[2], "txpid5gla2", buf); + READ_FROM_NVRAM(txpid5gl[3], "txpid5gla3", buf); + READ_FROM_NVRAM(txpid5gh[0], "txpid5gha0", buf); + READ_FROM_NVRAM(txpid5gh[1], "txpid5gha1", buf); + READ_FROM_NVRAM(txpid5gh[2], "txpid5gha2", buf); + READ_FROM_NVRAM(txpid5gh[3], "txpid5gha3", buf); READ_FROM_NVRAM(rxpo2g, "rxpo2g", buf); READ_FROM_NVRAM(rxpo5g, "rxpo5g", buf); READ_FROM_NVRAM(rssisav2g, "rssisav2g", buf); @@ -134,10 +177,18 @@ static void bcm47xx_fill_sprom(struct ssb_sprom *sprom, const char *prefix) READ_FROM_NVRAM(rssismf5g, "rssismf5g", buf); READ_FROM_NVRAM(bxa5g, "bxa5g", buf); READ_FROM_NVRAM(cck2gpo, "cck2gpo", buf); - READ_FROM_NVRAM(ofdm2gpo, "ofdm2gpo", buf); - READ_FROM_NVRAM(ofdm5glpo, "ofdm5glpo", buf); - READ_FROM_NVRAM(ofdm5gpo, "ofdm5gpo", buf); - READ_FROM_NVRAM(ofdm5ghpo, "ofdm5ghpo", buf); + + sprom->ofdm2gpo = nvram_getu32("ofdm2gpo", buf, sizeof(buf)); + sprom->ofdm5glpo = nvram_getu32("ofdm5glpo", buf, sizeof(buf)); + sprom->ofdm5gpo = nvram_getu32("ofdm5gpo", buf, sizeof(buf)); + sprom->ofdm5ghpo = nvram_getu32("ofdm5ghpo", buf, sizeof(buf)); + + READ_FROM_NVRAM(antenna_gain.ghz24.a0, "ag0", buf); + READ_FROM_NVRAM(antenna_gain.ghz24.a1, "ag1", buf); + READ_FROM_NVRAM(antenna_gain.ghz24.a2, "ag2", buf); + READ_FROM_NVRAM(antenna_gain.ghz24.a3, "ag3", buf); + memcpy(&sprom->antenna_gain.ghz5, &sprom->antenna_gain.ghz24, + sizeof(sprom->antenna_gain.ghz5)); if (nvram_getprefix(prefix, "boardflags", buf, sizeof(buf)) >= 0) { boardflags = simple_strtoul(buf, NULL, 0); -- cgit v0.10.2 From 9cbda726bb283d60cd4f34a3a9da8b5b48a46b0f Mon Sep 17 00:00:00 2001 From: Hauke Mehrtens Date: Tue, 10 May 2011 23:31:34 +0200 Subject: MIPS: BCM47xx: Fix MAC address parsing. Some devices like the Netgear WGT634u are using minuses between the blocks of the MAC address and other devices are using colons to separate them. Signed-off-by: Hauke Mehrtens Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/2366/ Signed-off-by: Ralf Baechle diff --git a/arch/mips/include/asm/mach-bcm47xx/nvram.h b/arch/mips/include/asm/mach-bcm47xx/nvram.h index 9759588..184d5ec 100644 --- a/arch/mips/include/asm/mach-bcm47xx/nvram.h +++ b/arch/mips/include/asm/mach-bcm47xx/nvram.h @@ -39,8 +39,16 @@ extern int nvram_getenv(char *name, char *val, size_t val_len); static inline void nvram_parse_macaddr(char *buf, u8 *macaddr) { - sscanf(buf, "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx", &macaddr[0], &macaddr[1], - &macaddr[2], &macaddr[3], &macaddr[4], &macaddr[5]); + 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 -- cgit v0.10.2 From 6edde0247644db475f68f25dcb1bf72260600081 Mon Sep 17 00:00:00 2001 From: Maarten ter Huurne Date: Mon, 2 May 2011 11:47:00 +0200 Subject: MIPS: JZ4740: setup: Autodetect physical memory. Assume that the boot loader knows the physical memory of the system and deduce that information from the contents of the SDRAM control register. It is still possible to override with with the "mem=" parameter, but we have a sensible default now. Signed-off-by: Maarten ter Huurne Acked-by: Lars-Peter Clausen Cc: linux-kernel@vger.kernel.org Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/2319/ Signed-off-by: Ralf Baechle diff --git a/arch/mips/jz4740/setup.c b/arch/mips/jz4740/setup.c index 6a9e14d..d97cfbf 100644 --- a/arch/mips/jz4740/setup.c +++ b/arch/mips/jz4740/setup.c @@ -1,5 +1,6 @@ /* * Copyright (C) 2009-2010, Lars-Peter Clausen + * Copyright (C) 2011, Maarten ter Huurne * JZ4740 setup code * * This program is free software; you can redistribute it and/or modify it @@ -14,13 +15,44 @@ */ #include +#include #include +#include + +#include + #include "reset.h" + +#define JZ4740_EMC_SDRAM_CTRL 0x80 + + +static void __init jz4740_detect_mem(void) +{ + void __iomem *jz_emc_base; + u32 ctrl, bus, bank, rows, cols; + phys_t size; + + jz_emc_base = ioremap(JZ4740_EMC_BASE_ADDR, 0x100); + ctrl = readl(jz_emc_base + JZ4740_EMC_SDRAM_CTRL); + bus = 2 - ((ctrl >> 31) & 1); + bank = 1 + ((ctrl >> 19) & 1); + cols = 8 + ((ctrl >> 26) & 7); + rows = 11 + ((ctrl >> 20) & 3); + printk(KERN_DEBUG + "SDRAM preconfigured: bus:%u bank:%u rows:%u cols:%u\n", + bus, bank, rows, cols); + iounmap(jz_emc_base); + + size = 1 << (bus + bank + cols + rows); + add_memory_region(0, size, BOOT_MEM_RAM); +} + void __init plat_mem_setup(void) { jz4740_reset_init(); + jz4740_detect_mem(); } const char *get_system_type(void) -- cgit v0.10.2 From c094c99e659efedcbb05a0f75b8f77145d8ec539 Mon Sep 17 00:00:00 2001 From: Robert Millan Date: Mon, 18 Apr 2011 11:37:55 -0700 Subject: MIPS: Introduce set_elf_platform() helper function Replace these sequences: if (cpu == 0) __elf_platform = "foo"; with a trivial inline function. Signed-off-by: Robert Millan Signed-off-by: Kevin Cernekee Signed-off-by: David Daney Cc: wu zhangjin Cc: Aurelien Jarno Cc: linux-mips@linux-mips.org Cc: linux-kernel@vger.kernel.org Patchwork: https://patchwork.linux-mips.org/patch/2304/ Patchwork: https://patchwork.linux-mips.org/patch/2374/ Signed-off-by: Ralf Baechle diff --git a/arch/mips/kernel/cpu-probe.c b/arch/mips/kernel/cpu-probe.c index c7b7eb2..aa86250 100644 --- a/arch/mips/kernel/cpu-probe.c +++ b/arch/mips/kernel/cpu-probe.c @@ -291,6 +291,12 @@ static inline int cpu_has_confreg(void) #endif } +static inline void set_elf_platform(int cpu, const char *plat) +{ + if (cpu == 0) + __elf_platform = plat; +} + /* * Get the FPU Implementation/Revision. */ @@ -956,14 +962,12 @@ static inline void cpu_probe_cavium(struct cpuinfo_mips *c, unsigned int cpu) c->cputype = CPU_CAVIUM_OCTEON_PLUS; __cpu_name[cpu] = "Cavium Octeon+"; platform: - if (cpu == 0) - __elf_platform = "octeon"; + set_elf_platform(cpu, "octeon"); break; case PRID_IMP_CAVIUM_CN63XX: c->cputype = CPU_CAVIUM_OCTEON2; __cpu_name[cpu] = "Cavium Octeon II"; - if (cpu == 0) - __elf_platform = "octeon2"; + set_elf_platform(cpu, "octeon2"); break; default: printk(KERN_INFO "Unknown Octeon chip!\n"); -- cgit v0.10.2 From 06785df09b18e9127d16893039b64ae118c53cb4 Mon Sep 17 00:00:00 2001 From: Kevin Cernekee Date: Sat, 16 Apr 2011 11:29:28 -0700 Subject: MIPS: Set ELF AT_PLATFORM string for BMIPS processors Signed-off-by: Kevin Cernekee Cc: Robert Millan Cc: David Daney Cc: wu zhangjin Cc: Aurelien Jarno Cc: linux-mips@linux-mips.org Cc: linux-kernel@vger.kernel.org Patchwork: https://patchwork.linux-mips.org/patch/2300/ Signed-off-by: Ralf Baechle diff --git a/arch/mips/kernel/cpu-probe.c b/arch/mips/kernel/cpu-probe.c index aa86250..7da8617 100644 --- a/arch/mips/kernel/cpu-probe.c +++ b/arch/mips/kernel/cpu-probe.c @@ -917,12 +917,14 @@ static inline void cpu_probe_broadcom(struct cpuinfo_mips *c, unsigned int cpu) case PRID_IMP_BMIPS32_REV8: c->cputype = CPU_BMIPS32; __cpu_name[cpu] = "Broadcom BMIPS32"; + set_elf_platform(cpu, "bmips32"); break; case PRID_IMP_BMIPS3300: case PRID_IMP_BMIPS3300_ALT: case PRID_IMP_BMIPS3300_BUG: c->cputype = CPU_BMIPS3300; __cpu_name[cpu] = "Broadcom BMIPS3300"; + set_elf_platform(cpu, "bmips3300"); break; case PRID_IMP_BMIPS43XX: { int rev = c->processor_id & 0xff; @@ -931,15 +933,18 @@ static inline void cpu_probe_broadcom(struct cpuinfo_mips *c, unsigned int cpu) rev <= PRID_REV_BMIPS4380_HI) { c->cputype = CPU_BMIPS4380; __cpu_name[cpu] = "Broadcom BMIPS4380"; + set_elf_platform(cpu, "bmips4380"); } else { c->cputype = CPU_BMIPS4350; __cpu_name[cpu] = "Broadcom BMIPS4350"; + set_elf_platform(cpu, "bmips4350"); } break; } case PRID_IMP_BMIPS5000: c->cputype = CPU_BMIPS5000; __cpu_name[cpu] = "Broadcom BMIPS5000"; + set_elf_platform(cpu, "bmips5000"); c->options |= MIPS_CPU_ULRI; break; } -- cgit v0.10.2 From 5aac1e8a381d52a977b5050369a82a547c446ee2 Mon Sep 17 00:00:00 2001 From: Robert Millan Date: Sat, 16 Apr 2011 11:29:29 -0700 Subject: MIPS: Set ELF AT_PLATFORM string for Loongson2 processors Signed-off-by: Robert Millan Acked-by: David Daney Signed-off-by: Kevin Cernekee Cc: David Daney Cc: wu zhangjin Cc: Aurelien Jarno Cc: linux-mips@linux-mips.org Cc: linux-kernel@vger.kernel.org Patchwork: https://patchwork.linux-mips.org/patch/2302/ Signed-off-by: Ralf Baechle diff --git a/arch/mips/kernel/cpu-probe.c b/arch/mips/kernel/cpu-probe.c index 7da8617..bb133d1 100644 --- a/arch/mips/kernel/cpu-probe.c +++ b/arch/mips/kernel/cpu-probe.c @@ -620,6 +620,16 @@ static inline void cpu_probe_legacy(struct cpuinfo_mips *c, unsigned int cpu) case PRID_IMP_LOONGSON2: c->cputype = CPU_LOONGSON2; __cpu_name[cpu] = "ICT Loongson-2"; + + switch (c->processor_id & PRID_REV_MASK) { + case PRID_REV_LOONGSON2E: + set_elf_platform(cpu, "loongson2e"); + break; + case PRID_REV_LOONGSON2F: + set_elf_platform(cpu, "loongson2f"); + break; + } + c->isa_level = MIPS_CPU_ISA_III; c->options = R4K_OPTS | MIPS_CPU_FPU | MIPS_CPU_LLSC | -- cgit v0.10.2 From 1c8da7a1107a46c94b21cc176aaf95c819aab3db Mon Sep 17 00:00:00 2001 From: Wanlong Gao Date: Sun, 10 Apr 2011 01:42:17 +0800 Subject: MIPS: Lemote 2F, Malta: Fix build warning Since 5ada28bf76752e33dce3d807bf0dfbe6d1b943ad ["led-class: always implement blinking"] LEDS_CLASS=m is no longer valid so change the setting from m to y. Signed-off-by: Wanlong Gao To: david.woodhouse@intel.com To: akpm@linux-foundation.org To: mingo@elte.hu Cc: linux-mips@linux-mips.org Cc: linux-kernel@vger.kernel.org Patchwork: https://patchwork.linux-mips.org/patch/2276/ Signed-off-by: Ralf Baechle diff --git a/arch/mips/configs/lemote2f_defconfig b/arch/mips/configs/lemote2f_defconfig index 167c1d0..cb2c5ea 100644 --- a/arch/mips/configs/lemote2f_defconfig +++ b/arch/mips/configs/lemote2f_defconfig @@ -329,7 +329,7 @@ CONFIG_USB_LED=m CONFIG_USB_GADGET=m CONFIG_USB_GADGET_M66592=y CONFIG_MMC=m -CONFIG_LEDS_CLASS=m +CONFIG_LEDS_CLASS=y CONFIG_STAGING=y # CONFIG_STAGING_EXCLUDE_BUILD is not set CONFIG_FB_SM7XX=y diff --git a/arch/mips/configs/malta_defconfig b/arch/mips/configs/malta_defconfig index 7270f31..5527abb 100644 --- a/arch/mips/configs/malta_defconfig +++ b/arch/mips/configs/malta_defconfig @@ -374,7 +374,7 @@ CONFIG_FB_CIRRUS=y # CONFIG_VGA_CONSOLE is not set CONFIG_FRAMEBUFFER_CONSOLE=y CONFIG_HID=m -CONFIG_LEDS_CLASS=m +CONFIG_LEDS_CLASS=y CONFIG_LEDS_TRIGGER_TIMER=m CONFIG_LEDS_TRIGGER_IDE_DISK=y CONFIG_LEDS_TRIGGER_HEARTBEAT=m -- cgit v0.10.2 From b32ee693eb106172f89639acff88dc8fee8ba3e2 Mon Sep 17 00:00:00 2001 From: Wanlong Gao Date: Sun, 10 Apr 2011 03:04:18 +0800 Subject: MIPS: Fix build warnings on defconfigs Since d45dcef77019012fc6769e657fc2f1a5d681bbbb ["Bluetooth: Fix BT_L2CAP and BT_SCO in Kconfig"] BT_L2CAP=m and BT_SCO=m are no longer valid so change the settings from m to y. [ralf@linux-mips.org: Merging only the MIPS parts of this patch.] Signed-off-by: Wanlong Gao To: akpm@linux-foundation.org To: manuel.lauss@googlemail.com Cc: linux-arm-kernel@lists.infradead.org Cc: linux-kernel@vger.kernel.org Cc: linux-mips@linux-mips.org Cc: linuxppc-dev@lists.ozlabs.org Patchwork: https://patchwork.linux-mips.org/patch/2277/ Signed-off-by: Ralf Baechle diff --git a/arch/mips/configs/lemote2f_defconfig b/arch/mips/configs/lemote2f_defconfig index cb2c5ea..b6acd2f 100644 --- a/arch/mips/configs/lemote2f_defconfig +++ b/arch/mips/configs/lemote2f_defconfig @@ -86,8 +86,8 @@ CONFIG_NET_SCHED=y CONFIG_NET_EMATCH=y CONFIG_NET_CLS_ACT=y CONFIG_BT=m -CONFIG_BT_L2CAP=m -CONFIG_BT_SCO=m +CONFIG_BT_L2CAP=y +CONFIG_BT_SCO=y CONFIG_BT_RFCOMM=m CONFIG_BT_RFCOMM_TTY=y CONFIG_BT_BNEP=m diff --git a/arch/mips/configs/mtx1_defconfig b/arch/mips/configs/mtx1_defconfig index a97a42c6..37862b2 100644 --- a/arch/mips/configs/mtx1_defconfig +++ b/arch/mips/configs/mtx1_defconfig @@ -225,8 +225,8 @@ CONFIG_TOSHIBA_FIR=m CONFIG_VLSI_FIR=m CONFIG_MCS_FIR=m CONFIG_BT=m -CONFIG_BT_L2CAP=m -CONFIG_BT_SCO=m +CONFIG_BT_L2CAP=y +CONFIG_BT_SCO=y CONFIG_BT_RFCOMM=m CONFIG_BT_RFCOMM_TTY=y CONFIG_BT_BNEP=m -- cgit v0.10.2 From 7716e6548abed1582a7759666e79d5c612a906c7 Mon Sep 17 00:00:00 2001 From: Chandrakala Chavva Date: Thu, 17 Feb 2011 13:57:52 -0800 Subject: Octeon: Fix interrupt irq settings for performance counters. Octeon uses different interrupt irq for timer and performance counters. Set CvmCtl[IPPCI] to correct irq value very early. Signed-off-by: Chandrakala Chavva Signed-off-by: David Daney To: linux-mips@linux-mips.org Cc: Chandrakala Chavva Patchwork: https://patchwork.linux-mips.org/patch/2085/ Signed-off-by: Ralf Baechle diff --git a/arch/mips/cavium-octeon/setup.c b/arch/mips/cavium-octeon/setup.c index 0707fae..2d9028f 100644 --- a/arch/mips/cavium-octeon/setup.c +++ b/arch/mips/cavium-octeon/setup.c @@ -288,7 +288,6 @@ void octeon_user_io_init(void) union octeon_cvmemctl cvmmemctl; union cvmx_iob_fau_timeout fau_timeout; union cvmx_pow_nw_tim nm_tim; - uint64_t cvmctl; /* Get the current settings for CP0_CVMMEMCTL_REG */ cvmmemctl.u64 = read_c0_cvmmemctl(); @@ -392,12 +391,6 @@ void octeon_user_io_init(void) CONFIG_CAVIUM_OCTEON_CVMSEG_SIZE, CONFIG_CAVIUM_OCTEON_CVMSEG_SIZE * 128); - /* Move the performance counter interrupts to IRQ 6 */ - cvmctl = read_c0_cvmctl(); - cvmctl &= ~(7 << 7); - cvmctl |= 6 << 7; - write_c0_cvmctl(cvmctl); - /* Set a default for the hardware timeouts */ fau_timeout.u64 = 0; fau_timeout.s.tout_val = 0xfff; diff --git a/arch/mips/include/asm/mach-cavium-octeon/kernel-entry-init.h b/arch/mips/include/asm/mach-cavium-octeon/kernel-entry-init.h index 0b2b5eb..dedef7d 100644 --- a/arch/mips/include/asm/mach-cavium-octeon/kernel-entry-init.h +++ b/arch/mips/include/asm/mach-cavium-octeon/kernel-entry-init.h @@ -63,6 +63,11 @@ # CN30XX Disable instruction prefetching or v0, v0, 0x2000 skip: + # First clear off CvmCtl[IPPCI] bit and move the performance + # counters interrupt to IRQ 6 + li v1, ~(7 << 7) + and v0, v0, v1 + ori v0, v0, (6 << 7) # Write the cavium control register dmtc0 v0, CP0_CVMCTL_REG sync -- cgit v0.10.2 From e650ce0f083ff9354a10ad66e6bf8c193e8a2755 Mon Sep 17 00:00:00 2001 From: David Daney Date: Thu, 17 Feb 2011 14:47:52 -0800 Subject: MIPS: Octeon: Don't request interrupts for unused IPI mailbox bits. We only use the three low-order mailbox bits. Leave the upper bits alone for possible use by drivers and other software. Signed-off-by: David Daney To: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/2090/ Signed-off-by: Ralf Baechle diff --git a/arch/mips/cavium-octeon/smp.c b/arch/mips/cavium-octeon/smp.c index ba78b21..716fae6 100644 --- a/arch/mips/cavium-octeon/smp.c +++ b/arch/mips/cavium-octeon/smp.c @@ -37,7 +37,7 @@ static irqreturn_t mailbox_interrupt(int irq, void *dev_id) uint64_t action; /* Load the mailbox register to figure out what we're supposed to do */ - action = cvmx_read_csr(CVMX_CIU_MBOX_CLRX(coreid)); + action = cvmx_read_csr(CVMX_CIU_MBOX_CLRX(coreid)) & 0xffff; /* Clear the mailbox to clear the interrupt */ cvmx_write_csr(CVMX_CIU_MBOX_CLRX(coreid), action); @@ -200,16 +200,15 @@ void octeon_prepare_cpus(unsigned int max_cpus) if (labi->labi_signature != LABI_SIGNATURE) panic("The bootloader version on this board is incorrect."); #endif - - cvmx_write_csr(CVMX_CIU_MBOX_CLRX(cvmx_get_core_num()), 0xffffffff); + /* + * Only the low order mailbox bits are used for IPIs, leave + * the other bits alone. + */ + cvmx_write_csr(CVMX_CIU_MBOX_CLRX(cvmx_get_core_num()), 0xffff); if (request_irq(OCTEON_IRQ_MBOX0, mailbox_interrupt, IRQF_DISABLED, - "mailbox0", mailbox_interrupt)) { + "SMP-IPI", mailbox_interrupt)) { panic("Cannot request_irq(OCTEON_IRQ_MBOX0)\n"); } - if (request_irq(OCTEON_IRQ_MBOX1, mailbox_interrupt, IRQF_DISABLED, - "mailbox1", mailbox_interrupt)) { - panic("Cannot request_irq(OCTEON_IRQ_MBOX1)\n"); - } } /** -- cgit v0.10.2 From 9c1e8a9138ff92a4ff816ea8a1884ad2461a993a Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Tue, 17 May 2011 16:18:09 +0100 Subject: MIPS: Cleanup arch_get_unmapped_area As noticed by Kevin Cernekee in http://www.linux-mips.org/cgi-bin/extract-mesg.cgi?a=linux-mips&m=2011-05&i=BANLkTikq04wuK%3Dbz%2BLieavmm3oDtoYWKxg%40mail.gmail.com Patchwork: https://patchwork.linux-mips.org/patch/2387/ Signed-off-by: Ralf Baechle diff --git a/arch/mips/kernel/syscall.c b/arch/mips/kernel/syscall.c index 58beabf..0c207e8 100644 --- a/arch/mips/kernel/syscall.c +++ b/arch/mips/kernel/syscall.c @@ -79,20 +79,13 @@ unsigned long arch_get_unmapped_area(struct file *filp, unsigned long addr, { struct vm_area_struct * vmm; int do_color_align; - unsigned long task_size; -#ifdef CONFIG_32BIT - task_size = TASK_SIZE; -#else /* Must be CONFIG_64BIT*/ - task_size = test_thread_flag(TIF_32BIT_ADDR) ? TASK_SIZE32 : TASK_SIZE; -#endif - - if (len > task_size) + if (len > TASK_SIZE) return -ENOMEM; if (flags & MAP_FIXED) { - /* Even MAP_FIXED mappings must reside within task_size. */ - if (task_size - len < addr) + /* Even MAP_FIXED mappings must reside within TASK_SIZE. */ + if (TASK_SIZE - len < addr) return -EINVAL; /* @@ -114,7 +107,7 @@ unsigned long arch_get_unmapped_area(struct file *filp, unsigned long addr, else addr = PAGE_ALIGN(addr); vmm = find_vma(current->mm, addr); - if (task_size - len >= addr && + if (TASK_SIZE - len >= addr && (!vmm || addr + len <= vmm->vm_start)) return addr; } @@ -126,7 +119,7 @@ unsigned long arch_get_unmapped_area(struct file *filp, unsigned long addr, for (vmm = find_vma(current->mm, addr); ; vmm = vmm->vm_next) { /* At this point: (!vmm || addr < vmm->vm_end). */ - if (task_size - len < addr) + if (TASK_SIZE - len < addr) return -ENOMEM; if (!vmm || addr + len <= vmm->vm_start) return addr; -- cgit v0.10.2 From 6f6c3c33c027f2c83d53e8562cd9daa73fe8108b Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Thu, 19 May 2011 09:21:33 +0100 Subject: MIPS: Move arch_get_unmapped_area and gang to new file. It never really belonged into syscall.c and it's about to become well more complex. Signed-off-by: Ralf Baechle diff --git a/arch/mips/kernel/syscall.c b/arch/mips/kernel/syscall.c index 0c207e8..d027657 100644 --- a/arch/mips/kernel/syscall.c +++ b/arch/mips/kernel/syscall.c @@ -10,12 +10,9 @@ #include #include #include -#include #include #include -#include #include -#include #include #include #include @@ -25,11 +22,9 @@ #include #include #include -#include #include #include #include -#include #include #include @@ -66,114 +61,6 @@ out: return res; } -unsigned long shm_align_mask = PAGE_SIZE - 1; /* Sane caches */ - -EXPORT_SYMBOL(shm_align_mask); - -#define COLOUR_ALIGN(addr,pgoff) \ - ((((addr) + shm_align_mask) & ~shm_align_mask) + \ - (((pgoff) << PAGE_SHIFT) & shm_align_mask)) - -unsigned long arch_get_unmapped_area(struct file *filp, unsigned long addr, - unsigned long len, unsigned long pgoff, unsigned long flags) -{ - struct vm_area_struct * vmm; - int do_color_align; - - if (len > TASK_SIZE) - return -ENOMEM; - - if (flags & MAP_FIXED) { - /* Even MAP_FIXED mappings must reside within TASK_SIZE. */ - if (TASK_SIZE - len < addr) - return -EINVAL; - - /* - * We do not accept a shared mapping if it would violate - * cache aliasing constraints. - */ - if ((flags & MAP_SHARED) && - ((addr - (pgoff << PAGE_SHIFT)) & shm_align_mask)) - return -EINVAL; - return addr; - } - - do_color_align = 0; - if (filp || (flags & MAP_SHARED)) - do_color_align = 1; - if (addr) { - if (do_color_align) - addr = COLOUR_ALIGN(addr, pgoff); - else - addr = PAGE_ALIGN(addr); - vmm = find_vma(current->mm, addr); - if (TASK_SIZE - len >= addr && - (!vmm || addr + len <= vmm->vm_start)) - return addr; - } - addr = current->mm->mmap_base; - if (do_color_align) - addr = COLOUR_ALIGN(addr, pgoff); - else - addr = PAGE_ALIGN(addr); - - for (vmm = find_vma(current->mm, addr); ; vmm = vmm->vm_next) { - /* At this point: (!vmm || addr < vmm->vm_end). */ - if (TASK_SIZE - len < addr) - return -ENOMEM; - if (!vmm || addr + len <= vmm->vm_start) - return addr; - addr = vmm->vm_end; - if (do_color_align) - addr = COLOUR_ALIGN(addr, pgoff); - } -} - -void arch_pick_mmap_layout(struct mm_struct *mm) -{ - unsigned long random_factor = 0UL; - - if (current->flags & PF_RANDOMIZE) { - random_factor = get_random_int(); - random_factor = random_factor << PAGE_SHIFT; - if (TASK_IS_32BIT_ADDR) - random_factor &= 0xfffffful; - else - random_factor &= 0xffffffful; - } - - mm->mmap_base = TASK_UNMAPPED_BASE + random_factor; - mm->get_unmapped_area = arch_get_unmapped_area; - mm->unmap_area = arch_unmap_area; -} - -static inline unsigned long brk_rnd(void) -{ - unsigned long rnd = get_random_int(); - - rnd = rnd << PAGE_SHIFT; - /* 8MB for 32bit, 256MB for 64bit */ - if (TASK_IS_32BIT_ADDR) - rnd = rnd & 0x7ffffful; - else - rnd = rnd & 0xffffffful; - - return rnd; -} - -unsigned long arch_randomize_brk(struct mm_struct *mm) -{ - unsigned long base = mm->brk; - unsigned long ret; - - ret = PAGE_ALIGN(base + brk_rnd()); - - if (ret < mm->brk) - return mm->brk; - - return ret; -} - SYSCALL_DEFINE6(mips_mmap, unsigned long, addr, unsigned long, len, unsigned long, prot, unsigned long, flags, unsigned long, fd, off_t, offset) diff --git a/arch/mips/mm/Makefile b/arch/mips/mm/Makefile index eb44636..4d8c162 100644 --- a/arch/mips/mm/Makefile +++ b/arch/mips/mm/Makefile @@ -3,7 +3,8 @@ # obj-y += cache.o dma-default.o extable.o fault.o \ - init.o tlbex.o tlbex-fault.o uasm.o page.o + init.o mmap.o tlbex.o tlbex-fault.o uasm.o \ + page.o obj-$(CONFIG_32BIT) += ioremap.o pgtable-32.o obj-$(CONFIG_64BIT) += pgtable-64.o diff --git a/arch/mips/mm/mmap.c b/arch/mips/mm/mmap.c new file mode 100644 index 0000000..ae3c20a --- /dev/null +++ b/arch/mips/mm/mmap.c @@ -0,0 +1,122 @@ +/* + * 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) 2011 Wind River Systems, + * written by Ralf Baechle + */ +#include +#include +#include +#include +#include +#include + +unsigned long shm_align_mask = PAGE_SIZE - 1; /* Sane caches */ + +EXPORT_SYMBOL(shm_align_mask); + +#define COLOUR_ALIGN(addr,pgoff) \ + ((((addr) + shm_align_mask) & ~shm_align_mask) + \ + (((pgoff) << PAGE_SHIFT) & shm_align_mask)) + +unsigned long arch_get_unmapped_area(struct file *filp, unsigned long addr, + unsigned long len, unsigned long pgoff, unsigned long flags) +{ + struct vm_area_struct * vmm; + int do_color_align; + + if (len > TASK_SIZE) + return -ENOMEM; + + if (flags & MAP_FIXED) { + /* Even MAP_FIXED mappings must reside within TASK_SIZE. */ + if (TASK_SIZE - len < addr) + return -EINVAL; + + /* + * We do not accept a shared mapping if it would violate + * cache aliasing constraints. + */ + if ((flags & MAP_SHARED) && + ((addr - (pgoff << PAGE_SHIFT)) & shm_align_mask)) + return -EINVAL; + return addr; + } + + do_color_align = 0; + if (filp || (flags & MAP_SHARED)) + do_color_align = 1; + if (addr) { + if (do_color_align) + addr = COLOUR_ALIGN(addr, pgoff); + else + addr = PAGE_ALIGN(addr); + vmm = find_vma(current->mm, addr); + if (TASK_SIZE - len >= addr && + (!vmm || addr + len <= vmm->vm_start)) + return addr; + } + addr = current->mm->mmap_base; + if (do_color_align) + addr = COLOUR_ALIGN(addr, pgoff); + else + addr = PAGE_ALIGN(addr); + + for (vmm = find_vma(current->mm, addr); ; vmm = vmm->vm_next) { + /* At this point: (!vmm || addr < vmm->vm_end). */ + if (TASK_SIZE - len < addr) + return -ENOMEM; + if (!vmm || addr + len <= vmm->vm_start) + return addr; + addr = vmm->vm_end; + if (do_color_align) + addr = COLOUR_ALIGN(addr, pgoff); + } +} + +void arch_pick_mmap_layout(struct mm_struct *mm) +{ + unsigned long random_factor = 0UL; + + if (current->flags & PF_RANDOMIZE) { + random_factor = get_random_int(); + random_factor = random_factor << PAGE_SHIFT; + if (TASK_IS_32BIT_ADDR) + random_factor &= 0xfffffful; + else + random_factor &= 0xffffffful; + } + + mm->mmap_base = TASK_UNMAPPED_BASE + random_factor; + mm->get_unmapped_area = arch_get_unmapped_area; + mm->unmap_area = arch_unmap_area; +} + +static inline unsigned long brk_rnd(void) +{ + unsigned long rnd = get_random_int(); + + rnd = rnd << PAGE_SHIFT; + /* 8MB for 32bit, 256MB for 64bit */ + if (TASK_IS_32BIT_ADDR) + rnd = rnd & 0x7ffffful; + else + rnd = rnd & 0xffffffful; + + return rnd; +} + +unsigned long arch_randomize_brk(struct mm_struct *mm) +{ + unsigned long base = mm->brk; + unsigned long ret; + + ret = PAGE_ALIGN(base + brk_rnd()); + + if (ret < mm->brk) + return mm->brk; + + return ret; +} -- cgit v0.10.2 From d6971822c288ce5547190c6f812cc978d6520777 Mon Sep 17 00:00:00 2001 From: Michal Marek Date: Tue, 17 May 2011 15:36:46 +0200 Subject: ftrace/kbuild: Add recordmcount files to force full build Modifications to recordmcount must be performed on all object files to stay consistent with what the kernel code may expect. Add the recordmcount files to the main dependencies to make sure any change to them causes a full recompile. Signed-off-by: Michal Marek Link: http://lkml.kernel.org/r/20110517133646.GP13293@sepie.suse.cz Signed-off-by: Steven Rostedt diff --git a/scripts/Makefile.build b/scripts/Makefile.build index fdca952..6165622 100644 --- a/scripts/Makefile.build +++ b/scripts/Makefile.build @@ -255,6 +255,8 @@ sub_cmd_record_mcount = \ if [ $(@) != "scripts/mod/empty.o" ]; then \ $(objtree)/scripts/recordmcount $(RECORDMCOUNT_FLAGS) "$(@)"; \ fi; +recordmcount_source := $(srctree)/scripts/recordmcount.c \ + $(srctree)/scripts/recordmcount.h else sub_cmd_record_mcount = set -e ; perl $(srctree)/scripts/recordmcount.pl "$(ARCH)" \ "$(if $(CONFIG_CPU_BIG_ENDIAN),big,little)" \ @@ -262,6 +264,7 @@ sub_cmd_record_mcount = set -e ; perl $(srctree)/scripts/recordmcount.pl "$(ARCH "$(OBJDUMP)" "$(OBJCOPY)" "$(CC) $(KBUILD_CFLAGS)" \ "$(LD)" "$(NM)" "$(RM)" "$(MV)" \ "$(if $(part-of-module),1,0)" "$(@)"; +recordmcount_source := $(srctree)/scripts/recordmcount.pl endif cmd_record_mcount = \ if [ "$(findstring -pg,$(_c_flags))" = "-pg" ]; then \ @@ -282,13 +285,13 @@ define rule_cc_o_c endef # Built-in and composite module parts -$(obj)/%.o: $(src)/%.c FORCE +$(obj)/%.o: $(src)/%.c $(recordmcount_source) FORCE $(call cmd,force_checksrc) $(call if_changed_rule,cc_o_c) # Single-part modules are special since we need to mark them in $(MODVERDIR) -$(single-used-m): $(obj)/%.o: $(src)/%.c FORCE +$(single-used-m): $(obj)/%.o: $(src)/%.c $(recordmcount_source) FORCE $(call cmd,force_checksrc) $(call if_changed_rule,cc_o_c) @{ echo $(@:.o=.ko); echo $@; } > $(MODVERDIR)/$(@F:.o=.mod) -- cgit v0.10.2 From 369db4c9524b7487faf1ff89646eee396c1363e1 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Wed, 18 May 2011 21:33:40 +0000 Subject: clocksource: Restructure clocksource struct members Group the hot path members of struct clocksource together so we have a better cache line footprint. Make it cacheline aligned. Signed-off-by: Thomas Gleixner Cc: John Stultz Cc: Eric Dumazet Reviewed-by: Ingo Molnar Link: http://lkml.kernel.org/r/%3C20110518210136.003081882%40linutronix.de%3E diff --git a/include/linux/clocksource.h b/include/linux/clocksource.h index 0fb0b7e..c918fbd 100644 --- a/include/linux/clocksource.h +++ b/include/linux/clocksource.h @@ -159,42 +159,38 @@ extern u64 timecounter_cyc2time(struct timecounter *tc, */ struct clocksource { /* - * First part of structure is read mostly + * Hotpath data, fits in a single cache line when the + * clocksource itself is cacheline aligned. */ - const char *name; - struct list_head list; - int rating; cycle_t (*read)(struct clocksource *cs); - int (*enable)(struct clocksource *cs); - void (*disable)(struct clocksource *cs); + cycle_t cycle_last; cycle_t mask; u32 mult; u32 shift; u64 max_idle_ns; - unsigned long flags; - cycle_t (*vread)(void); - void (*suspend)(struct clocksource *cs); - void (*resume)(struct clocksource *cs); + #ifdef CONFIG_IA64 void *fsys_mmio; /* used by fsyscall asm code */ #define CLKSRC_FSYS_MMIO_SET(mmio, addr) ((mmio) = (addr)) #else #define CLKSRC_FSYS_MMIO_SET(mmio, addr) do { } while (0) #endif - - /* - * Second part is written at each timer interrupt - * Keep it in a different cache line to dirty no - * more than one cache line. - */ - cycle_t cycle_last ____cacheline_aligned_in_smp; + const char *name; + struct list_head list; + int rating; + cycle_t (*vread)(void); + int (*enable)(struct clocksource *cs); + void (*disable)(struct clocksource *cs); + unsigned long flags; + void (*suspend)(struct clocksource *cs); + void (*resume)(struct clocksource *cs); #ifdef CONFIG_CLOCKSOURCE_WATCHDOG /* Watchdog related data, used by the framework */ struct list_head wd_list; cycle_t wd_last; #endif -}; +} ____cacheline_aligned; /* * Clock source flags bits:: -- cgit v0.10.2 From 724ed53e8ac2c5278af8955673049714c1073464 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Wed, 18 May 2011 21:33:40 +0000 Subject: clocksource: Get rid of the hardcoded 5 seconds sleep time limit Slow clocksources can have a way longer sleep time than 5 seconds and even fast ones can easily cope with 600 seconds and still maintain proper accuracy. Signed-off-by: Thomas Gleixner Cc: John Stultz Reviewed-by: Ingo Molnar Link: http://lkml.kernel.org/r/%3C20110518210136.109811585%40linutronix.de%3E diff --git a/kernel/time/clocksource.c b/kernel/time/clocksource.c index 6519cf6..6dbbbb1 100644 --- a/kernel/time/clocksource.c +++ b/kernel/time/clocksource.c @@ -626,19 +626,6 @@ static void clocksource_enqueue(struct clocksource *cs) list_add(&cs->list, entry); } - -/* - * Maximum time we expect to go between ticks. This includes idle - * tickless time. It provides the trade off between selecting a - * mult/shift pair that is very precise but can only handle a short - * period of time, vs. a mult/shift pair that can handle long periods - * of time but isn't as precise. - * - * This is a subsystem constant, and actual hardware limitations - * may override it (ie: clocksources that wrap every 3 seconds). - */ -#define MAX_UPDATE_LENGTH 5 /* Seconds */ - /** * __clocksource_updatefreq_scale - Used update clocksource with new freq * @t: clocksource to be registered @@ -652,15 +639,28 @@ static void clocksource_enqueue(struct clocksource *cs) */ void __clocksource_updatefreq_scale(struct clocksource *cs, u32 scale, u32 freq) { + unsigned long sec; + /* - * Ideally we want to use some of the limits used in - * clocksource_max_deferment, to provide a more informed - * MAX_UPDATE_LENGTH. But for now this just gets the - * register interface working properly. + * Calc the maximum number of seconds which we can run before + * wrapping around. For clocksources which have a mask > 32bit + * we need to limit the max sleep time to have a good + * conversion precision. 10 minutes is still a reasonable + * amount. That results in a shift value of 24 for a + * clocksource with mask >= 40bit and f >= 4GHz. That maps to + * ~ 0.06ppm granularity for NTP. We apply the same 12.5% + * margin as we do in clocksource_max_deferment() */ + sec = (cs->mask - (cs->mask >> 5)); + do_div(sec, freq); + do_div(sec, scale); + if (!sec) + sec = 1; + else if (sec > 600 && cs->mask > UINT_MAX) + sec = 600; + clocks_calc_mult_shift(&cs->mult, &cs->shift, freq, - NSEC_PER_SEC/scale, - MAX_UPDATE_LENGTH*scale); + NSEC_PER_SEC / scale, sec * scale); cs->max_idle_ns = clocksource_max_deferment(cs); } EXPORT_SYMBOL_GPL(__clocksource_updatefreq_scale); -- cgit v0.10.2 From 847b2f42be203f3cff7f243fdd3ee50c1e06c882 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Wed, 18 May 2011 21:33:41 +0000 Subject: clockevents: Restructure clock_event_device members Group the hot path members of struct clock_event_device together so we have a better cache line footprint. Make it cacheline aligned. Signed-off-by: Thomas Gleixner Cc: John Stultz Reviewed-by: Ingo Molnar Link: http://lkml.kernel.org/r/%3C20110518210136.223607682%40linutronix.de%3E diff --git a/include/linux/clockchips.h b/include/linux/clockchips.h index fc53492..9466eeb 100644 --- a/include/linux/clockchips.h +++ b/include/linux/clockchips.h @@ -56,46 +56,47 @@ enum clock_event_nofitiers { /** * struct clock_event_device - clock event device descriptor - * @name: ptr to clock event name - * @features: features + * @event_handler: Assigned by the framework to be called by the low + * level handler of the event source + * @set_next_event: set next event function + * @next_event: local storage for the next event in oneshot mode * @max_delta_ns: maximum delta value in ns * @min_delta_ns: minimum delta value in ns * @mult: nanosecond to cycles multiplier * @shift: nanoseconds to cycles divisor (power of two) + * @mode: operating mode assigned by the management code + * @features: features + * @retries: number of forced programming retries + * @set_mode: set mode function + * @broadcast: function to broadcast events + * @name: ptr to clock event name * @rating: variable to rate clock event devices * @irq: IRQ number (only for non CPU local devices) * @cpumask: cpumask to indicate for which CPUs this device works - * @set_next_event: set next event function - * @set_mode: set mode function - * @event_handler: Assigned by the framework to be called by the low - * level handler of the event source - * @broadcast: function to broadcast events * @list: list head for the management code - * @mode: operating mode assigned by the management code - * @next_event: local storage for the next event in oneshot mode - * @retries: number of forced programming retries */ struct clock_event_device { - const char *name; - unsigned int features; + void (*event_handler)(struct clock_event_device *); + int (*set_next_event)(unsigned long evt, + struct clock_event_device *); + ktime_t next_event; u64 max_delta_ns; u64 min_delta_ns; u32 mult; u32 shift; + enum clock_event_mode mode; + unsigned int features; + unsigned long retries; + + void (*broadcast)(const struct cpumask *mask); + void (*set_mode)(enum clock_event_mode mode, + struct clock_event_device *); + const char *name; int rating; int irq; const struct cpumask *cpumask; - int (*set_next_event)(unsigned long evt, - struct clock_event_device *); - void (*set_mode)(enum clock_event_mode mode, - struct clock_event_device *); - void (*event_handler)(struct clock_event_device *); - void (*broadcast)(const struct cpumask *mask); struct list_head list; - enum clock_event_mode mode; - ktime_t next_event; - unsigned long retries; -}; +} ____cacheline_aligned; /* * Calculate a multiplication factor for scaled math, which is used to convert -- cgit v0.10.2 From 57f0fcbe1dea8a36c9d1673086326059991c5f81 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Wed, 18 May 2011 21:33:41 +0000 Subject: clockevents: Provide combined configure and register function All clockevent devices have the same open coded initialization functions. Provide an interface which does all necessary initialization in the core code. Signed-off-by: Thomas Gleixner Cc: John Stultz Reviewed-by: Ingo Molnar Link: http://lkml.kernel.org/r/%3C20110518210136.331975870%40linutronix.de%3E diff --git a/include/linux/clockchips.h b/include/linux/clockchips.h index 9466eeb..80acc79e 100644 --- a/include/linux/clockchips.h +++ b/include/linux/clockchips.h @@ -69,6 +69,8 @@ enum clock_event_nofitiers { * @retries: number of forced programming retries * @set_mode: set mode function * @broadcast: function to broadcast events + * @min_delta_ticks: minimum delta value in ticks stored for reconfiguration + * @max_delta_ticks: maximum delta value in ticks stored for reconfiguration * @name: ptr to clock event name * @rating: variable to rate clock event devices * @irq: IRQ number (only for non CPU local devices) @@ -91,6 +93,9 @@ struct clock_event_device { void (*broadcast)(const struct cpumask *mask); void (*set_mode)(enum clock_event_mode mode, struct clock_event_device *); + unsigned long min_delta_ticks; + unsigned long max_delta_ticks; + const char *name; int rating; int irq; @@ -123,6 +128,10 @@ extern u64 clockevent_delta2ns(unsigned long latch, struct clock_event_device *evt); extern void clockevents_register_device(struct clock_event_device *dev); +extern void clockevents_config_and_register(struct clock_event_device *dev, + u32 freq, unsigned long min_delta, + unsigned long max_delta); + extern void clockevents_exchange_device(struct clock_event_device *old, struct clock_event_device *new); extern void clockevents_set_mode(struct clock_event_device *dev, diff --git a/kernel/time/clockevents.c b/kernel/time/clockevents.c index 0d74b9b..c69e88c 100644 --- a/kernel/time/clockevents.c +++ b/kernel/time/clockevents.c @@ -194,6 +194,50 @@ void clockevents_register_device(struct clock_event_device *dev) } EXPORT_SYMBOL_GPL(clockevents_register_device); +static void clockevents_config(struct clock_event_device *dev, + u32 freq) +{ + unsigned long sec; + + if (!(dev->features & CLOCK_EVT_FEAT_ONESHOT)) + return; + + /* + * Calculate the maximum number of seconds we can sleep. Limit + * to 10 minutes for hardware which can program more than + * 32bit ticks so we still get reasonable conversion values. + */ + sec = dev->max_delta_ticks; + do_div(sec, freq); + if (!sec) + sec = 1; + else if (sec > 600 && dev->max_delta_ticks > UINT_MAX) + sec = 600; + + clockevents_calc_mult_shift(dev, freq, sec); + dev->min_delta_ns = clockevent_delta2ns(dev->min_delta_ticks, dev); + dev->max_delta_ns = clockevent_delta2ns(dev->max_delta_ticks, dev); +} + +/** + * clockevents_config_and_register - Configure and register a clock event device + * @dev: device to register + * @freq: The clock frequency + * @min_delta: The minimum clock ticks to program in oneshot mode + * @max_delta: The maximum clock ticks to program in oneshot mode + * + * min/max_delta can be 0 for devices which do not support oneshot mode. + */ +void clockevents_config_and_register(struct clock_event_device *dev, + u32 freq, unsigned long min_delta, + unsigned long max_delta) +{ + dev->min_delta_ticks = min_delta; + dev->max_delta_ticks = max_delta; + clockevents_config(dev, freq); + clockevents_register_device(dev); +} + /* * Noop handler when we shut down an event device */ -- cgit v0.10.2 From 80b816b736cfa5b9582279127099b20a479ab7d9 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Wed, 18 May 2011 21:33:42 +0000 Subject: clockevents: Provide interface to reconfigure an active clock event device Some ARM SoCs have clock event devices which have their frequency modified due to frequency scaling. Provide an interface which allows to reconfigure an active device. After reconfiguration reprogram the current pending event. Signed-off-by: Thomas Gleixner Cc: LAK Cc: John Stultz Acked-by: Linus Walleij Reviewed-by: Ingo Molnar Link: http://lkml.kernel.org/r/%3C20110518210136.437459958%40linutronix.de%3E diff --git a/include/linux/clockchips.h b/include/linux/clockchips.h index 80acc79e..d6733e2 100644 --- a/include/linux/clockchips.h +++ b/include/linux/clockchips.h @@ -132,6 +132,8 @@ extern void clockevents_config_and_register(struct clock_event_device *dev, u32 freq, unsigned long min_delta, unsigned long max_delta); +extern int clockevents_update_freq(struct clock_event_device *ce, u32 freq); + extern void clockevents_exchange_device(struct clock_event_device *old, struct clock_event_device *new); extern void clockevents_set_mode(struct clock_event_device *dev, diff --git a/kernel/time/clockevents.c b/kernel/time/clockevents.c index c69e88c..22a9da9 100644 --- a/kernel/time/clockevents.c +++ b/kernel/time/clockevents.c @@ -238,6 +238,26 @@ void clockevents_config_and_register(struct clock_event_device *dev, clockevents_register_device(dev); } +/** + * clockevents_update_freq - Update frequency and reprogram a clock event device. + * @dev: device to modify + * @freq: new device frequency + * + * Reconfigure and reprogram a clock event device in oneshot + * mode. Must be called on the cpu for which the device delivers per + * cpu timer events with interrupts disabled! Returns 0 on success, + * -ETIME when the event is in the past. + */ +int clockevents_update_freq(struct clock_event_device *dev, u32 freq) +{ + clockevents_config(dev, freq); + + if (dev->mode != CLOCK_EVT_MODE_ONESHOT) + return 0; + + return clockevents_program_event(dev, dev->next_event, ktime_get()); +} + /* * Noop handler when we shut down an event device */ -- cgit v0.10.2 From 61ee9a4ba05f0a4163d43a33dee7a0651e080b98 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Wed, 18 May 2011 21:33:42 +0000 Subject: x86: Convert PIT to clockevents_config_and_register() Let the core do the work. Signed-off-by: Thomas Gleixner Cc: John Stultz Reviewed-by: Ingo Molnar Link: http://lkml.kernel.org/r/%3C20110518210136.545615675%40linutronix.de%3E diff --git a/arch/x86/kernel/i8253.c b/arch/x86/kernel/i8253.c index 577e90c..fb66dc9 100644 --- a/arch/x86/kernel/i8253.c +++ b/arch/x86/kernel/i8253.c @@ -93,7 +93,6 @@ static struct clock_event_device pit_ce = { .features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT, .set_mode = init_pit_timer, .set_next_event = pit_next_event, - .shift = 32, .irq = 0, }; @@ -108,11 +107,8 @@ void __init setup_pit_timer(void) * IO_APIC has been initialized. */ pit_ce.cpumask = cpumask_of(smp_processor_id()); - pit_ce.mult = div_sc(CLOCK_TICK_RATE, NSEC_PER_SEC, pit_ce.shift); - pit_ce.max_delta_ns = clockevent_delta2ns(0x7FFF, &pit_ce); - pit_ce.min_delta_ns = clockevent_delta2ns(0xF, &pit_ce); - clockevents_register_device(&pit_ce); + clockevents_config_and_register(&pit_ce, CLOCK_TICK_RATE, 0xF, 0x7FFF); global_clock_event = &pit_ce; } -- cgit v0.10.2 From ab0e08f15d23628dd8d50bf6ce1a935a8840c7dc Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Wed, 18 May 2011 21:33:43 +0000 Subject: x86: hpet: Cleanup the clockevents init and register code No need to recalculate the frequency and the conversion factors over and over. Calculate the frequency once and use the new config/register interface and let the core code do the math. Signed-off-by: Thomas Gleixner Cc: John Stultz Reviewed-by: Ingo Molnar Link: http://lkml.kernel.org/r/%3C20110518210136.646482357%40linutronix.de%3E diff --git a/arch/x86/kernel/hpet.c b/arch/x86/kernel/hpet.c index bfe8f72..6781765 100644 --- a/arch/x86/kernel/hpet.c +++ b/arch/x86/kernel/hpet.c @@ -217,7 +217,7 @@ static void hpet_reserve_platform_timers(unsigned int id) { } /* * Common hpet info */ -static unsigned long hpet_period; +static unsigned long hpet_freq; static void hpet_legacy_set_mode(enum clock_event_mode mode, struct clock_event_device *evt); @@ -232,7 +232,6 @@ static struct clock_event_device hpet_clockevent = { .features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT, .set_mode = hpet_legacy_set_mode, .set_next_event = hpet_legacy_next_event, - .shift = 32, .irq = 0, .rating = 50, }; @@ -290,28 +289,12 @@ static void hpet_legacy_clockevent_register(void) hpet_enable_legacy_int(); /* - * The mult factor is defined as (include/linux/clockchips.h) - * mult/2^shift = cyc/ns (in contrast to ns/cyc in clocksource.h) - * hpet_period is in units of femtoseconds (per cycle), so - * mult/2^shift = cyc/ns = 10^6/hpet_period - * mult = (10^6 * 2^shift)/hpet_period - * mult = (FSEC_PER_NSEC << hpet_clockevent.shift)/hpet_period - */ - hpet_clockevent.mult = div_sc((unsigned long) FSEC_PER_NSEC, - hpet_period, hpet_clockevent.shift); - /* Calculate the min / max delta */ - hpet_clockevent.max_delta_ns = clockevent_delta2ns(0x7FFFFFFF, - &hpet_clockevent); - /* Setup minimum reprogramming delta. */ - hpet_clockevent.min_delta_ns = clockevent_delta2ns(HPET_MIN_PROG_DELTA, - &hpet_clockevent); - - /* * Start hpet with the boot cpu mask and make it * global after the IO_APIC has been initialized. */ hpet_clockevent.cpumask = cpumask_of(smp_processor_id()); - clockevents_register_device(&hpet_clockevent); + clockevents_config_and_register(&hpet_clockevent, hpet_freq, + HPET_MIN_PROG_DELTA, 0x7FFFFFFF); global_clock_event = &hpet_clockevent; printk(KERN_DEBUG "hpet clockevent registered\n"); } @@ -549,7 +532,6 @@ static int hpet_setup_irq(struct hpet_dev *dev) static void init_one_hpet_msi_clockevent(struct hpet_dev *hdev, int cpu) { struct clock_event_device *evt = &hdev->evt; - uint64_t hpet_freq; WARN_ON(cpu != smp_processor_id()); if (!(hdev->flags & HPET_DEV_VALID)) @@ -571,24 +553,10 @@ static void init_one_hpet_msi_clockevent(struct hpet_dev *hdev, int cpu) evt->set_mode = hpet_msi_set_mode; evt->set_next_event = hpet_msi_next_event; - evt->shift = 32; - - /* - * The period is a femto seconds value. We need to calculate the - * scaled math multiplication factor for nanosecond to hpet tick - * conversion. - */ - hpet_freq = FSEC_PER_SEC; - do_div(hpet_freq, hpet_period); - evt->mult = div_sc((unsigned long) hpet_freq, - NSEC_PER_SEC, evt->shift); - /* Calculate the max delta */ - evt->max_delta_ns = clockevent_delta2ns(0x7FFFFFFF, evt); - /* 5 usec minimum reprogramming delta. */ - evt->min_delta_ns = 5000; - evt->cpumask = cpumask_of(hdev->cpu); - clockevents_register_device(evt); + + clockevents_config_and_register(evt, hpet_freq, HPET_MIN_PROG_DELTA, + 0x7FFFFFFF); } #ifdef CONFIG_HPET @@ -792,7 +760,6 @@ static struct clocksource clocksource_hpet = { static int hpet_clocksource_register(void) { u64 start, now; - u64 hpet_freq; cycle_t t1; /* Start the counter */ @@ -819,24 +786,7 @@ static int hpet_clocksource_register(void) return -ENODEV; } - /* - * The definition of mult is (include/linux/clocksource.h) - * mult/2^shift = ns/cyc and hpet_period is in units of fsec/cyc - * so we first need to convert hpet_period to ns/cyc units: - * mult/2^shift = ns/cyc = hpet_period/10^6 - * mult = (hpet_period * 2^shift)/10^6 - * mult = (hpet_period << shift)/FSEC_PER_NSEC - */ - - /* Need to convert hpet_period (fsec/cyc) to cyc/sec: - * - * cyc/sec = FSEC_PER_SEC/hpet_period(fsec/cyc) - * cyc/sec = (FSEC_PER_NSEC * NSEC_PER_SEC)/hpet_period - */ - hpet_freq = FSEC_PER_SEC; - do_div(hpet_freq, hpet_period); clocksource_register_hz(&clocksource_hpet, (u32)hpet_freq); - return 0; } @@ -845,7 +795,9 @@ static int hpet_clocksource_register(void) */ int __init hpet_enable(void) { + unsigned long hpet_period; unsigned int id; + u64 freq; int i; if (!is_hpet_capable()) @@ -884,6 +836,14 @@ int __init hpet_enable(void) goto out_nohpet; /* + * The period is a femto seconds value. Convert it to a + * frequency. + */ + freq = FSEC_PER_SEC; + do_div(freq, hpet_period); + hpet_freq = freq; + + /* * Read the HPET ID register to retrieve the IRQ routing * information and the number of channels */ -- cgit v0.10.2 From 2cba3ffb9a9db3874304a1739002d053d53c738b Mon Sep 17 00:00:00 2001 From: Ingo Molnar Date: Thu, 19 May 2011 13:30:56 +0200 Subject: perf stat: Add -d -d and -d -d -d options to show more CPU events Print even more detailed statistics if requested via perf stat -d: -d: detailed events, L1 and LLC data cache -d -d: more detailed events, dTLB and iTLB events -d -d -d: very detailed events, adding prefetch events Full output looks like this now: Performance counter stats for '/home/mingo/hackbench 10' (5 runs): 1703.674707 task-clock # 8.709 CPUs utilized ( +- 4.19% ) 49,068 context-switches # 0.029 M/sec ( +- 16.66% ) 8,303 CPU-migrations # 0.005 M/sec ( +- 24.90% ) 17,397 page-faults # 0.010 M/sec ( +- 0.46% ) 2,345,389,239 cycles # 1.377 GHz ( +- 4.61% ) [55.90%] 1,884,503,527 stalled-cycles-frontend # 80.35% frontend cycles idle ( +- 5.67% ) [50.39%] 743,919,737 stalled-cycles-backend # 31.72% backend cycles idle ( +- 8.75% ) [49.91%] 1,314,416,379 instructions # 0.56 insns per cycle # 1.43 stalled cycles per insn ( +- 2.53% ) [60.87%] 272,592,567 branches # 160.003 M/sec ( +- 1.74% ) [56.56%] 3,794,846 branch-misses # 1.39% of all branches ( +- 6.59% ) [58.50%] 449,982,778 L1-dcache-loads # 264.125 M/sec ( +- 2.47% ) [49.88%] 22,404,961 L1-dcache-load-misses # 4.98% of all L1-dcache hits ( +- 6.08% ) [55.05%] 6,204,750 LLC-loads # 3.642 M/sec ( +- 8.91% ) [43.75%] 1,837,411 LLC-load-misses # 1.078 M/sec ( +- 7.27% ) [12.07%] 411,440,421 L1-icache-loads # 241.502 M/sec ( +- 5.60% ) [36.52%] 27,556,832 L1-icache-load-misses # 16.175 M/sec ( +- 7.46% ) [46.72%] 464,067,627 dTLB-loads # 272.392 M/sec ( +- 4.46% ) [54.17%] 10,765,648 dTLB-load-misses # 6.319 M/sec ( +- 3.18% ) [48.68%] 1,273,080,386 iTLB-loads # 747.256 M/sec ( +- 3.38% ) [47.53%] 117,481 iTLB-load-misses # 0.069 M/sec ( +- 14.99% ) [47.01%] 4,590,653 L1-dcache-prefetches # 2.695 M/sec ( +- 4.49% ) [46.19%] 1,712,660 L1-dcache-prefetch-misses # 1.005 M/sec ( +- 3.75% ) [44.82%] 0.195622057 seconds time elapsed ( +- 6.84% ) Also clean up the attribute construction code to be appending, and factor it out into add_default_attributes(). Tweak the coverage percentage printout a bit, so that it's easier to view it alongside the +- sttddev colum. Cc: Peter Zijlstra Cc: Arnaldo Carvalho de Melo Cc: Frederic Weisbecker Cc: Mike Galbraith Cc: Steven Rostedt Link: http://lkml.kernel.org/n/tip-to3kgu04449s64062val8b62@git.kernel.org Signed-off-by: Ingo Molnar diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c index 602c3c9..a89fc08 100644 --- a/tools/perf/builtin-stat.c +++ b/tools/perf/builtin-stat.c @@ -6,24 +6,28 @@ * * Sample output: - $ perf stat ~/hackbench 10 - Time: 0.104 + $ perf stat ./hackbench 10 - Performance counter stats for '/home/mingo/hackbench': + Time: 0.118 - 1255.538611 task clock ticks # 10.143 CPU utilization factor - 54011 context switches # 0.043 M/sec - 385 CPU migrations # 0.000 M/sec - 17755 pagefaults # 0.014 M/sec - 3808323185 CPU cycles # 3033.219 M/sec - 1575111190 instructions # 1254.530 M/sec - 17367895 cache references # 13.833 M/sec - 7674421 cache misses # 6.112 M/sec + Performance counter stats for './hackbench 10': - Wall-clock time elapsed: 123.786620 msecs + 1708.761321 task-clock # 11.037 CPUs utilized + 41,190 context-switches # 0.024 M/sec + 6,735 CPU-migrations # 0.004 M/sec + 17,318 page-faults # 0.010 M/sec + 5,205,202,243 cycles # 3.046 GHz + 3,856,436,920 stalled-cycles-frontend # 74.09% frontend cycles idle + 1,600,790,871 stalled-cycles-backend # 30.75% backend cycles idle + 2,603,501,247 instructions # 0.50 insns per cycle + # 1.48 stalled cycles per insn + 484,357,498 branches # 283.455 M/sec + 6,388,934 branch-misses # 1.32% of all branches + + 0.154822978 seconds time elapsed * - * Copyright (C) 2008, Red Hat Inc, Ingo Molnar + * Copyright (C) 2008-2011, Red Hat Inc, Ingo Molnar * * Improvements and fixes by: * @@ -75,22 +79,10 @@ static struct perf_event_attr default_attrs[] = { }; /* - * Detailed stats: + * Detailed stats (-d), covering the L1 and last level data caches: */ static struct perf_event_attr detailed_attrs[] = { - { .type = PERF_TYPE_SOFTWARE, .config = PERF_COUNT_SW_TASK_CLOCK }, - { .type = PERF_TYPE_SOFTWARE, .config = PERF_COUNT_SW_CONTEXT_SWITCHES }, - { .type = PERF_TYPE_SOFTWARE, .config = PERF_COUNT_SW_CPU_MIGRATIONS }, - { .type = PERF_TYPE_SOFTWARE, .config = PERF_COUNT_SW_PAGE_FAULTS }, - - { .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_CPU_CYCLES }, - { .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_STALLED_CYCLES_FRONTEND }, - { .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_STALLED_CYCLES_BACKEND }, - { .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_INSTRUCTIONS }, - { .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_BRANCH_INSTRUCTIONS }, - { .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_BRANCH_MISSES }, - { .type = PERF_TYPE_HW_CACHE, .config = PERF_COUNT_HW_CACHE_L1D << 0 | @@ -116,6 +108,69 @@ static struct perf_event_attr detailed_attrs[] = { (PERF_COUNT_HW_CACHE_RESULT_MISS << 16) }, }; +/* + * Very detailed stats (-d -d), covering the instruction cache and the TLB caches: + */ +static struct perf_event_attr very_detailed_attrs[] = { + + { .type = PERF_TYPE_HW_CACHE, + .config = + PERF_COUNT_HW_CACHE_L1I << 0 | + (PERF_COUNT_HW_CACHE_OP_READ << 8) | + (PERF_COUNT_HW_CACHE_RESULT_ACCESS << 16) }, + + { .type = PERF_TYPE_HW_CACHE, + .config = + PERF_COUNT_HW_CACHE_L1I << 0 | + (PERF_COUNT_HW_CACHE_OP_READ << 8) | + (PERF_COUNT_HW_CACHE_RESULT_MISS << 16) }, + + { .type = PERF_TYPE_HW_CACHE, + .config = + PERF_COUNT_HW_CACHE_DTLB << 0 | + (PERF_COUNT_HW_CACHE_OP_READ << 8) | + (PERF_COUNT_HW_CACHE_RESULT_ACCESS << 16) }, + + { .type = PERF_TYPE_HW_CACHE, + .config = + PERF_COUNT_HW_CACHE_DTLB << 0 | + (PERF_COUNT_HW_CACHE_OP_READ << 8) | + (PERF_COUNT_HW_CACHE_RESULT_MISS << 16) }, + + { .type = PERF_TYPE_HW_CACHE, + .config = + PERF_COUNT_HW_CACHE_ITLB << 0 | + (PERF_COUNT_HW_CACHE_OP_READ << 8) | + (PERF_COUNT_HW_CACHE_RESULT_ACCESS << 16) }, + + { .type = PERF_TYPE_HW_CACHE, + .config = + PERF_COUNT_HW_CACHE_ITLB << 0 | + (PERF_COUNT_HW_CACHE_OP_READ << 8) | + (PERF_COUNT_HW_CACHE_RESULT_MISS << 16) }, + +}; + +/* + * Very, very detailed stats (-d -d -d), adding prefetch events: + */ +static struct perf_event_attr very_very_detailed_attrs[] = { + + { .type = PERF_TYPE_HW_CACHE, + .config = + PERF_COUNT_HW_CACHE_L1D << 0 | + (PERF_COUNT_HW_CACHE_OP_PREFETCH << 8) | + (PERF_COUNT_HW_CACHE_RESULT_ACCESS << 16) }, + + { .type = PERF_TYPE_HW_CACHE, + .config = + PERF_COUNT_HW_CACHE_L1D << 0 | + (PERF_COUNT_HW_CACHE_OP_PREFETCH << 8) | + (PERF_COUNT_HW_CACHE_RESULT_MISS << 16) }, +}; + + + struct perf_evlist *evsel_list; static bool system_wide = false; @@ -129,7 +184,7 @@ static pid_t target_pid = -1; static pid_t target_tid = -1; static pid_t child_pid = -1; static bool null_run = false; -static bool detailed_run = false; +static int detailed_run = 0; static bool sync_run = false; static bool big_num = true; static int big_num_opt = -1; @@ -464,7 +519,7 @@ static void nsec_printout(int cpu, struct perf_evsel *evsel, double avg) { double msecs = avg / 1e6; char cpustr[16] = { '\0', }; - const char *fmt = csv_output ? "%s%.6f%s%s" : "%s%18.6f%s%-24s"; + const char *fmt = csv_output ? "%s%.6f%s%s" : "%s%18.6f%s%-25s"; if (no_aggr) sprintf(cpustr, "CPU%*d%s", @@ -584,9 +639,9 @@ static void abs_printout(int cpu, struct perf_evsel *evsel, double avg) if (csv_output) fmt = "%s%.0f%s%s"; else if (big_num) - fmt = "%s%'18.0f%s%-24s"; + fmt = "%s%'18.0f%s%-25s"; else - fmt = "%s%18.0f%s%-24s"; + fmt = "%s%18.0f%s%-25s"; if (no_aggr) sprintf(cpustr, "CPU%*d%s", @@ -616,7 +671,7 @@ static void abs_printout(int cpu, struct perf_evsel *evsel, double avg) if (total && avg) { ratio = total / avg; - fprintf(stderr, "\n # %5.2f stalled cycles per insn", ratio); + fprintf(stderr, "\n # %5.2f stalled cycles per insn", ratio); } } else if (perf_evsel__match(evsel, HARDWARE, HW_BRANCH_MISSES) && @@ -704,7 +759,7 @@ static void print_counter_aggr(struct perf_evsel *counter) avg_enabled = avg_stats(&ps->res_stats[1]); avg_running = avg_stats(&ps->res_stats[2]); - fprintf(stderr, " (%.2f%%)", 100 * avg_running / avg_enabled); + fprintf(stderr, " [%5.2f%%]", 100 * avg_running / avg_enabled); } fprintf(stderr, "\n"); } @@ -854,7 +909,7 @@ static const struct option options[] = { "repeat command and print average + stddev (max: 100)"), OPT_BOOLEAN('n', "null", &null_run, "null run - dont start any counters"), - OPT_BOOLEAN('d', "detailed", &detailed_run, + OPT_INCR('d', "detailed", &detailed_run, "detailed run - start a lot of events"), OPT_BOOLEAN('S', "sync", &sync_run, "call sync() before starting a run"), @@ -873,6 +928,70 @@ static const struct option options[] = { OPT_END() }; +/* + * Add default attributes, if there were no attributes specified or + * if -d/--detailed, -d -d or -d -d -d is used: + */ +static int add_default_attributes(void) +{ + struct perf_evsel *pos; + size_t attr_nr = 0; + size_t c; + + /* Set attrs if no event is selected and !null_run: */ + if (null_run) + return 0; + + if (!evsel_list->nr_entries) { + for (c = 0; c < ARRAY_SIZE(default_attrs); c++) { + pos = perf_evsel__new(default_attrs + c, c + attr_nr); + if (pos == NULL) + return -1; + perf_evlist__add(evsel_list, pos); + } + attr_nr += c; + } + + /* Detailed events get appended to the event list: */ + + if (detailed_run < 1) + return 0; + + /* Append detailed run extra attributes: */ + for (c = 0; c < ARRAY_SIZE(detailed_attrs); c++) { + pos = perf_evsel__new(detailed_attrs + c, c + attr_nr); + if (pos == NULL) + return -1; + perf_evlist__add(evsel_list, pos); + } + attr_nr += c; + + if (detailed_run < 2) + return 0; + + /* Append very detailed run extra attributes: */ + for (c = 0; c < ARRAY_SIZE(very_detailed_attrs); c++) { + pos = perf_evsel__new(very_detailed_attrs + c, c + attr_nr); + if (pos == NULL) + return -1; + perf_evlist__add(evsel_list, pos); + } + + if (detailed_run < 3) + return 0; + + /* Append very, very detailed run extra attributes: */ + for (c = 0; c < ARRAY_SIZE(very_very_detailed_attrs); c++) { + pos = perf_evsel__new(very_very_detailed_attrs + c, c + attr_nr); + if (pos == NULL) + return -1; + perf_evlist__add(evsel_list, pos); + } + + + return 0; +} + int cmd_stat(int argc, const char **argv, const char *prefix __used) { struct perf_evsel *pos; @@ -918,28 +1037,8 @@ int cmd_stat(int argc, const char **argv, const char *prefix __used) usage_with_options(stat_usage, options); } - /* Set attrs and nr_counters if no event is selected and !null_run */ - if (detailed_run) { - size_t c; - - for (c = 0; c < ARRAY_SIZE(detailed_attrs); ++c) { - pos = perf_evsel__new(&detailed_attrs[c], c); - if (pos == NULL) - goto out; - perf_evlist__add(evsel_list, pos); - } - } - /* Set attrs and nr_counters if no event is selected and !null_run */ - if (!detailed_run && !null_run && !evsel_list->nr_entries) { - size_t c; - - for (c = 0; c < ARRAY_SIZE(default_attrs); ++c) { - pos = perf_evsel__new(&default_attrs[c], c); - if (pos == NULL) - goto out; - perf_evlist__add(evsel_list, pos); - } - } + if (add_default_attributes()) + goto out; if (target_pid != -1) target_tid = target_pid; -- cgit v0.10.2 From c3305257cd4df63e03e21e331a0140ae9c0faccc Mon Sep 17 00:00:00 2001 From: Ingo Molnar Date: Thu, 19 May 2011 14:01:42 +0200 Subject: perf stat: Add more cache-miss percentage printouts Print out the cache-miss percentage as well if the cache refs were collected, for all the generic cache event types. Before: 11,103,723,230 dTLB-loads # 622.471 M/sec ( +- 0.30% ) 87,065,337 dTLB-load-misses # 4.881 M/sec ( +- 0.90% ) After: 11,353,713,242 dTLB-loads # 626.020 M/sec ( +- 0.35% ) 113,393,472 dTLB-load-misses # 1.00% of all dTLB cache hits ( +- 0.49% ) Also ASCII color highlight too high percentages, them when it's executed on the console. Cc: Peter Zijlstra Cc: Arnaldo Carvalho de Melo Cc: Frederic Weisbecker Cc: Mike Galbraith Cc: Steven Rostedt Link: http://lkml.kernel.org/n/tip-lkhwxsevdbd9a8nymx0vxc3y@git.kernel.org Signed-off-by: Ingo Molnar diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c index a89fc08..a9f0671 100644 --- a/tools/perf/builtin-stat.c +++ b/tools/perf/builtin-stat.c @@ -261,6 +261,10 @@ struct stats runtime_stalled_cycles_back_stats[MAX_NR_CPUS]; struct stats runtime_branches_stats[MAX_NR_CPUS]; struct stats runtime_cacherefs_stats[MAX_NR_CPUS]; struct stats runtime_l1_dcache_stats[MAX_NR_CPUS]; +struct stats runtime_l1_icache_stats[MAX_NR_CPUS]; +struct stats runtime_ll_cache_stats[MAX_NR_CPUS]; +struct stats runtime_itlb_cache_stats[MAX_NR_CPUS]; +struct stats runtime_dtlb_cache_stats[MAX_NR_CPUS]; struct stats walltime_nsecs_stats; static int create_perf_stat_counter(struct perf_evsel *evsel) @@ -317,6 +321,14 @@ static void update_shadow_stats(struct perf_evsel *counter, u64 *count) update_stats(&runtime_cacherefs_stats[0], count[0]); else if (perf_evsel__match(counter, HW_CACHE, HW_CACHE_L1D)) update_stats(&runtime_l1_dcache_stats[0], count[0]); + else if (perf_evsel__match(counter, HW_CACHE, HW_CACHE_L1I)) + update_stats(&runtime_l1_icache_stats[0], count[0]); + else if (perf_evsel__match(counter, HW_CACHE, HW_CACHE_LL)) + update_stats(&runtime_ll_cache_stats[0], count[0]); + else if (perf_evsel__match(counter, HW_CACHE, HW_CACHE_DTLB)) + update_stats(&runtime_dtlb_cache_stats[0], count[0]); + else if (perf_evsel__match(counter, HW_CACHE, HW_CACHE_ITLB)) + update_stats(&runtime_itlb_cache_stats[0], count[0]); } /* @@ -630,6 +642,98 @@ static void print_l1_dcache_misses(int cpu, struct perf_evsel *evsel __used, dou fprintf(stderr, " of all L1-dcache hits "); } +static void print_l1_icache_misses(int cpu, struct perf_evsel *evsel __used, double avg) +{ + double total, ratio = 0.0; + const char *color; + + total = avg_stats(&runtime_l1_icache_stats[cpu]); + + if (total) + ratio = avg / total * 100.0; + + color = PERF_COLOR_NORMAL; + if (ratio > 20.0) + color = PERF_COLOR_RED; + else if (ratio > 10.0) + color = PERF_COLOR_MAGENTA; + else if (ratio > 5.0) + color = PERF_COLOR_YELLOW; + + fprintf(stderr, " # "); + color_fprintf(stderr, color, "%6.2f%%", ratio); + fprintf(stderr, " of all L1-icache hits "); +} + +static void print_dtlb_cache_misses(int cpu, struct perf_evsel *evsel __used, double avg) +{ + double total, ratio = 0.0; + const char *color; + + total = avg_stats(&runtime_dtlb_cache_stats[cpu]); + + if (total) + ratio = avg / total * 100.0; + + color = PERF_COLOR_NORMAL; + if (ratio > 20.0) + color = PERF_COLOR_RED; + else if (ratio > 10.0) + color = PERF_COLOR_MAGENTA; + else if (ratio > 5.0) + color = PERF_COLOR_YELLOW; + + fprintf(stderr, " # "); + color_fprintf(stderr, color, "%6.2f%%", ratio); + fprintf(stderr, " of all dTLB cache hits "); +} + +static void print_itlb_cache_misses(int cpu, struct perf_evsel *evsel __used, double avg) +{ + double total, ratio = 0.0; + const char *color; + + total = avg_stats(&runtime_itlb_cache_stats[cpu]); + + if (total) + ratio = avg / total * 100.0; + + color = PERF_COLOR_NORMAL; + if (ratio > 20.0) + color = PERF_COLOR_RED; + else if (ratio > 10.0) + color = PERF_COLOR_MAGENTA; + else if (ratio > 5.0) + color = PERF_COLOR_YELLOW; + + fprintf(stderr, " # "); + color_fprintf(stderr, color, "%6.2f%%", ratio); + fprintf(stderr, " of all iTLB cache hits "); +} + +static void print_ll_cache_misses(int cpu, struct perf_evsel *evsel __used, double avg) +{ + double total, ratio = 0.0; + const char *color; + + total = avg_stats(&runtime_ll_cache_stats[cpu]); + + if (total) + ratio = avg / total * 100.0; + + color = PERF_COLOR_NORMAL; + if (ratio > 20.0) + color = PERF_COLOR_RED; + else if (ratio > 10.0) + color = PERF_COLOR_MAGENTA; + else if (ratio > 5.0) + color = PERF_COLOR_YELLOW; + + fprintf(stderr, " # "); + color_fprintf(stderr, color, "%6.2f%%", ratio); + fprintf(stderr, " of all LL-cache hits "); +} + static void abs_printout(int cpu, struct perf_evsel *evsel, double avg) { double total, ratio = 0.0; @@ -684,6 +788,34 @@ static void abs_printout(int cpu, struct perf_evsel *evsel, double avg) ((PERF_COUNT_HW_CACHE_RESULT_MISS) << 16)) && runtime_l1_dcache_stats[cpu].n != 0) { print_l1_dcache_misses(cpu, evsel, avg); + } else if ( + evsel->attr.type == PERF_TYPE_HW_CACHE && + evsel->attr.config == ( PERF_COUNT_HW_CACHE_L1I | + ((PERF_COUNT_HW_CACHE_OP_READ) << 8) | + ((PERF_COUNT_HW_CACHE_RESULT_MISS) << 16)) && + runtime_l1_icache_stats[cpu].n != 0) { + print_l1_icache_misses(cpu, evsel, avg); + } else if ( + evsel->attr.type == PERF_TYPE_HW_CACHE && + evsel->attr.config == ( PERF_COUNT_HW_CACHE_DTLB | + ((PERF_COUNT_HW_CACHE_OP_READ) << 8) | + ((PERF_COUNT_HW_CACHE_RESULT_MISS) << 16)) && + runtime_dtlb_cache_stats[cpu].n != 0) { + print_dtlb_cache_misses(cpu, evsel, avg); + } else if ( + evsel->attr.type == PERF_TYPE_HW_CACHE && + evsel->attr.config == ( PERF_COUNT_HW_CACHE_ITLB | + ((PERF_COUNT_HW_CACHE_OP_READ) << 8) | + ((PERF_COUNT_HW_CACHE_RESULT_MISS) << 16)) && + runtime_itlb_cache_stats[cpu].n != 0) { + print_itlb_cache_misses(cpu, evsel, avg); + } else if ( + evsel->attr.type == PERF_TYPE_HW_CACHE && + evsel->attr.config == ( PERF_COUNT_HW_CACHE_LL | + ((PERF_COUNT_HW_CACHE_OP_READ) << 8) | + ((PERF_COUNT_HW_CACHE_RESULT_MISS) << 16)) && + runtime_ll_cache_stats[cpu].n != 0) { + print_ll_cache_misses(cpu, evsel, avg); } else if (perf_evsel__match(evsel, HARDWARE, HW_CACHE_MISSES) && runtime_cacherefs_stats[cpu].n != 0) { total = avg_stats(&runtime_cacherefs_stats[cpu]); @@ -842,10 +974,12 @@ static void print_stat(int argc, const char **argv) } if (!csv_output) { - fprintf(stderr, "\n"); - fprintf(stderr, " %18.9f seconds time elapsed", + if (!null_run) + fprintf(stderr, "\n"); + fprintf(stderr, " %17.9f seconds time elapsed", avg_stats(&walltime_nsecs_stats)/1e9); if (run_count > 1) { + fprintf(stderr, " "); print_noise_pct(stddev_stats(&walltime_nsecs_stats), avg_stats(&walltime_nsecs_stats)); } -- cgit v0.10.2 From b87ba87ca26e226b2277a2d5613ed596f408e96d Mon Sep 17 00:00:00 2001 From: "Tian, Kevin" Date: Fri, 6 May 2011 14:43:36 +0800 Subject: x86: Skip migrating IRQF_PER_CPU irqs in fixup_irqs() IRQF_PER_CPU means that the irq cannot be moved away from a given cpu. So it must not be migrated when the cpu goes offline. [ tglx: massaged changelog ] Signed-off-by: Fengzhe Zhang Signed-off-by: Kevin Tian Cc: Ian Campbell Cc: Jan Beulich Cc: "xen-devel@lists.xensource.com" Link: http://lkml.kernel.org/r/%3C625BA99ED14B2D499DC4E29D8138F1505C8ED7F7E2%40shsmsx502.ccr.corp.intel.com%3E Signed-off-by: Thomas Gleixner diff --git a/arch/x86/kernel/irq.c b/arch/x86/kernel/irq.c index 1cb0b9f..544efe2 100644 --- a/arch/x86/kernel/irq.c +++ b/arch/x86/kernel/irq.c @@ -249,7 +249,7 @@ void fixup_irqs(void) data = irq_desc_get_irq_data(desc); affinity = data->affinity; - if (!irq_has_action(irq) || + if (!irq_has_action(irq) || irqd_is_per_cpu(data) || cpumask_subset(affinity, cpu_online_mask)) { raw_spin_unlock(&desc->lock); continue; -- cgit v0.10.2 From 983bbf1af0664b78689612b247acb514300f62c7 Mon Sep 17 00:00:00 2001 From: "Tian, Kevin" Date: Fri, 6 May 2011 14:43:56 +0800 Subject: x86: Don't unmask disabled irqs when migrating them It doesn't make sense to unconditionally unmask a disabled irq when migrating it from offlined cpu to another. If the irq triggers then it will be disabled in the interrupt handler anyway. So we can just avoid unmasking it. [ tglx: Made masking unconditional again and fixed the changelog ] Signed-off-by: Fengzhe Zhang Signed-off-by: Kevin Tian Cc: Ian Campbell Cc: Jan Beulich Cc: "xen-devel@lists.xensource.com" Link: http://lkml.kernel.org/r/%3C625BA99ED14B2D499DC4E29D8138F1505C8ED7F7E3%40shsmsx502.ccr.corp.intel.com%3E Signed-off-by: Thomas Gleixner diff --git a/arch/x86/kernel/irq.c b/arch/x86/kernel/irq.c index 544efe2..6c0802e 100644 --- a/arch/x86/kernel/irq.c +++ b/arch/x86/kernel/irq.c @@ -276,7 +276,8 @@ void fixup_irqs(void) else if (!(warned++)) set_affinity = 0; - if (!irqd_can_move_in_process_context(data) && chip->irq_unmask) + if (!irqd_can_move_in_process_context(data) && + !irqd_irq_disabled(data) && chip->irq_unmask) chip->irq_unmask(data); raw_spin_unlock(&desc->lock); -- cgit v0.10.2 From 9b6763e0aacf245b58687a372816a0a4aabf2b1e Mon Sep 17 00:00:00 2001 From: Shirish Pargaonkar Date: Mon, 21 Feb 2011 23:56:59 -0600 Subject: cifs: Remove unused inode number while fetching root inode ino is unused in function cifs_root_iget(). Signed-off-by: Shirish Pargaonkar Signed-off-by: Steve French diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c index 5c412b3..0742c26 100644 --- a/fs/cifs/cifsfs.c +++ b/fs/cifs/cifsfs.c @@ -163,7 +163,7 @@ cifs_read_super(struct super_block *sb, void *data, sb->s_bdi = &cifs_sb->bdi; sb->s_blocksize = CIFS_MAX_MSGSIZE; sb->s_blocksize_bits = 14; /* default 2**14 = CIFS_MAX_MSGSIZE */ - inode = cifs_root_iget(sb, ROOT_I); + inode = cifs_root_iget(sb); if (IS_ERR(inode)) { rc = PTR_ERR(inode); diff --git a/fs/cifs/cifsfs.h b/fs/cifs/cifsfs.h index a9371b6..f191244 100644 --- a/fs/cifs/cifsfs.h +++ b/fs/cifs/cifsfs.h @@ -47,7 +47,7 @@ extern void cifs_sb_deactive(struct super_block *sb); /* Functions related to inodes */ extern const struct inode_operations cifs_dir_inode_ops; -extern struct inode *cifs_root_iget(struct super_block *, unsigned long); +extern struct inode *cifs_root_iget(struct super_block *); extern int cifs_create(struct inode *, struct dentry *, int, struct nameidata *); extern struct dentry *cifs_lookup(struct inode *, struct dentry *, diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c index 8852470..196ef60 100644 --- a/fs/cifs/inode.c +++ b/fs/cifs/inode.c @@ -878,7 +878,7 @@ retry_iget5_locked: } /* gets root inode */ -struct inode *cifs_root_iget(struct super_block *sb, unsigned long ino) +struct inode *cifs_root_iget(struct super_block *sb) { int xid; struct cifs_sb_info *cifs_sb = CIFS_SB(sb); -- cgit v0.10.2 From 0eff0e26777430bcfee1ef47bd90250858ada431 Mon Sep 17 00:00:00 2001 From: Steve French Date: Thu, 24 Feb 2011 05:39:23 +0000 Subject: Remove unused CIFSSMBNotify worker function The CIFSSMBNotify worker is unused, pending changes to allow it to be called via inotify, so move it into its own experimental config option so it does not get built in, until the necessary VFS support is fixed. It used to be used in dnotify, but according to Jeff, inotify needs minor changes before we can reenable this. CC: Jeff Layton Signed-off-by: Steve French diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c index 0742c26..b45d38b 100644 --- a/fs/cifs/cifsfs.c +++ b/fs/cifs/cifsfs.c @@ -981,10 +981,10 @@ init_cifs(void) int rc = 0; cifs_proc_init(); INIT_LIST_HEAD(&cifs_tcp_ses_list); -#ifdef CONFIG_CIFS_EXPERIMENTAL +#ifdef CONFIG_CIFS_DNOTIFY_EXPERIMENTAL /* unused temporarily */ INIT_LIST_HEAD(&GlobalDnotifyReqList); INIT_LIST_HEAD(&GlobalDnotifyRsp_Q); -#endif +#endif /* was needed for dnotify, and will be needed for inotify when VFS fix */ /* * Initialize Global counters */ diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h index a5d1106..6e211b6 100644 --- a/fs/cifs/cifsglob.h +++ b/fs/cifs/cifsglob.h @@ -780,10 +780,12 @@ GLOBAL_EXTERN spinlock_t cifs_tcp_ses_lock; */ GLOBAL_EXTERN spinlock_t cifs_file_list_lock; +#ifdef CONFIG_CIFS_DNOTIFY_EXPERIMENTAL /* unused temporarily */ /* Outstanding dir notify requests */ GLOBAL_EXTERN struct list_head GlobalDnotifyReqList; /* DirNotify response queue */ GLOBAL_EXTERN struct list_head GlobalDnotifyRsp_Q; +#endif /* was needed for dnotify, and will be needed for inotify when VFS fix */ /* * Global transaction id (XID) information diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h index 8096f27..34bbd5c 100644 --- a/fs/cifs/cifsproto.h +++ b/fs/cifs/cifsproto.h @@ -386,6 +386,12 @@ extern int calc_seckey(struct cifsSesInfo *); extern void calc_lanman_hash(const char *password, const char *cryptkey, bool encrypt, char *lnm_session_key); #endif /* CIFS_WEAK_PW_HASH */ +#ifdef CONFIG_CIFS_DNOTIFY_EXPERIMENTAL /* unused temporarily */ +extern int CIFSSMBNotify(const int xid, struct cifsTconInfo *tcon, + const int notify_subdirs, const __u16 netfid, + __u32 filter, struct file *file, int multishot, + const struct nls_table *nls_codepage); +#endif /* was needed for dnotify, and will be needed for inotify when VFS fix */ extern int CIFSSMBCopy(int xid, struct cifsTconInfo *source_tcon, const char *fromName, @@ -393,10 +399,6 @@ extern int CIFSSMBCopy(int xid, const char *toName, const int flags, const struct nls_table *nls_codepage, int remap_special_chars); -extern int CIFSSMBNotify(const int xid, struct cifsTconInfo *tcon, - const int notify_subdirs, const __u16 netfid, - __u32 filter, struct file *file, int multishot, - const struct nls_table *nls_codepage); extern ssize_t CIFSSMBQAllEAs(const int xid, struct cifsTconInfo *tcon, const unsigned char *searchName, const unsigned char *ea_name, char *EAData, diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c index df959ba..5630282 100644 --- a/fs/cifs/cifssmb.c +++ b/fs/cifs/cifssmb.c @@ -5418,79 +5418,6 @@ setPermsRetry: return rc; } -int CIFSSMBNotify(const int xid, struct cifsTconInfo *tcon, - const int notify_subdirs, const __u16 netfid, - __u32 filter, struct file *pfile, int multishot, - const struct nls_table *nls_codepage) -{ - int rc = 0; - struct smb_com_transaction_change_notify_req *pSMB = NULL; - struct smb_com_ntransaction_change_notify_rsp *pSMBr = NULL; - struct dir_notify_req *dnotify_req; - int bytes_returned; - - cFYI(1, "In CIFSSMBNotify for file handle %d", (int)netfid); - rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB, - (void **) &pSMBr); - if (rc) - return rc; - - pSMB->TotalParameterCount = 0 ; - pSMB->TotalDataCount = 0; - pSMB->MaxParameterCount = cpu_to_le32(2); - /* BB find exact data count max from sess structure BB */ - pSMB->MaxDataCount = 0; /* same in little endian or be */ -/* BB VERIFY verify which is correct for above BB */ - pSMB->MaxDataCount = cpu_to_le32((tcon->ses->server->maxBuf - - MAX_CIFS_HDR_SIZE) & 0xFFFFFF00); - - pSMB->MaxSetupCount = 4; - pSMB->Reserved = 0; - pSMB->ParameterOffset = 0; - pSMB->DataCount = 0; - pSMB->DataOffset = 0; - pSMB->SetupCount = 4; /* single byte does not need le conversion */ - pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_NOTIFY_CHANGE); - pSMB->ParameterCount = pSMB->TotalParameterCount; - if (notify_subdirs) - pSMB->WatchTree = 1; /* one byte - no le conversion needed */ - pSMB->Reserved2 = 0; - pSMB->CompletionFilter = cpu_to_le32(filter); - pSMB->Fid = netfid; /* file handle always le */ - pSMB->ByteCount = 0; - - rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, - (struct smb_hdr *)pSMBr, &bytes_returned, - CIFS_ASYNC_OP); - if (rc) { - cFYI(1, "Error in Notify = %d", rc); - } else { - /* Add file to outstanding requests */ - /* BB change to kmem cache alloc */ - dnotify_req = kmalloc( - sizeof(struct dir_notify_req), - GFP_KERNEL); - if (dnotify_req) { - dnotify_req->Pid = pSMB->hdr.Pid; - dnotify_req->PidHigh = pSMB->hdr.PidHigh; - dnotify_req->Mid = pSMB->hdr.Mid; - dnotify_req->Tid = pSMB->hdr.Tid; - dnotify_req->Uid = pSMB->hdr.Uid; - dnotify_req->netfid = netfid; - dnotify_req->pfile = pfile; - dnotify_req->filter = filter; - dnotify_req->multishot = multishot; - spin_lock(&GlobalMid_Lock); - list_add_tail(&dnotify_req->lhead, - &GlobalDnotifyReqList); - spin_unlock(&GlobalMid_Lock); - } else - rc = -ENOMEM; - } - cifs_buf_release(pSMB); - return rc; -} - #ifdef CONFIG_CIFS_XATTR /* * Do a path-based QUERY_ALL_EAS call and parse the result. This is a common @@ -5787,5 +5714,99 @@ SetEARetry: return rc; } - #endif + +#ifdef CONFIG_CIFS_DNOTIFY_EXPERIMENTAL /* BB unused temporarily */ +/* + * Years ago the kernel added a "dnotify" function for Samba server, + * to allow network clients (such as Windows) to display updated + * lists of files in directory listings automatically when + * files are added by one user when another user has the + * same directory open on their desktop. The Linux cifs kernel + * client hooked into the kernel side of this interface for + * the same reason, but ironically when the VFS moved from + * "dnotify" to "inotify" it became harder to plug in Linux + * network file system clients (the most obvious use case + * for notify interfaces is when multiple users can update + * the contents of the same directory - exactly what network + * file systems can do) although the server (Samba) could + * still use it. For the short term we leave the worker + * function ifdeffed out (below) until inotify is fixed + * in the VFS to make it easier to plug in network file + * system clients. If inotify turns out to be permanently + * incompatible for network fs clients, we could instead simply + * expose this config flag by adding a future cifs (and smb2) notify ioctl. + */ +int CIFSSMBNotify(const int xid, struct cifsTconInfo *tcon, + const int notify_subdirs, const __u16 netfid, + __u32 filter, struct file *pfile, int multishot, + const struct nls_table *nls_codepage) +{ + int rc = 0; + struct smb_com_transaction_change_notify_req *pSMB = NULL; + struct smb_com_ntransaction_change_notify_rsp *pSMBr = NULL; + struct dir_notify_req *dnotify_req; + int bytes_returned; + + cFYI(1, "In CIFSSMBNotify for file handle %d", (int)netfid); + rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB, + (void **) &pSMBr); + if (rc) + return rc; + + pSMB->TotalParameterCount = 0 ; + pSMB->TotalDataCount = 0; + pSMB->MaxParameterCount = cpu_to_le32(2); + /* BB find exact data count max from sess structure BB */ + pSMB->MaxDataCount = 0; /* same in little endian or be */ +/* BB VERIFY verify which is correct for above BB */ + pSMB->MaxDataCount = cpu_to_le32((tcon->ses->server->maxBuf - + MAX_CIFS_HDR_SIZE) & 0xFFFFFF00); + + pSMB->MaxSetupCount = 4; + pSMB->Reserved = 0; + pSMB->ParameterOffset = 0; + pSMB->DataCount = 0; + pSMB->DataOffset = 0; + pSMB->SetupCount = 4; /* single byte does not need le conversion */ + pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_NOTIFY_CHANGE); + pSMB->ParameterCount = pSMB->TotalParameterCount; + if (notify_subdirs) + pSMB->WatchTree = 1; /* one byte - no le conversion needed */ + pSMB->Reserved2 = 0; + pSMB->CompletionFilter = cpu_to_le32(filter); + pSMB->Fid = netfid; /* file handle always le */ + pSMB->ByteCount = 0; + + rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, + (struct smb_hdr *)pSMBr, &bytes_returned, + CIFS_ASYNC_OP); + if (rc) { + cFYI(1, "Error in Notify = %d", rc); + } else { + /* Add file to outstanding requests */ + /* BB change to kmem cache alloc */ + dnotify_req = kmalloc( + sizeof(struct dir_notify_req), + GFP_KERNEL); + if (dnotify_req) { + dnotify_req->Pid = pSMB->hdr.Pid; + dnotify_req->PidHigh = pSMB->hdr.PidHigh; + dnotify_req->Mid = pSMB->hdr.Mid; + dnotify_req->Tid = pSMB->hdr.Tid; + dnotify_req->Uid = pSMB->hdr.Uid; + dnotify_req->netfid = netfid; + dnotify_req->pfile = pfile; + dnotify_req->filter = filter; + dnotify_req->multishot = multishot; + spin_lock(&GlobalMid_Lock); + list_add_tail(&dnotify_req->lhead, + &GlobalDnotifyReqList); + spin_unlock(&GlobalMid_Lock); + } else + rc = -ENOMEM; + } + cifs_buf_release(pSMB); + return rc; +} +#endif /* was needed for dnotify, and will be needed for inotify when VFS fix */ -- cgit v0.10.2 From c52a95545c7f8060aa4e83deca16e3414ce73000 Mon Sep 17 00:00:00 2001 From: Steve French Date: Thu, 24 Feb 2011 06:16:22 +0000 Subject: Don't compile in unused reparse point symlink code Recent Windows versions now create symlinks more frequently and they do use this "reparse point" symlink mechanism. We can of course do symlinks nicely to Samba and other servers which support the CIFS Unix Extensions and we can also do SFU symlinks and "client only" "MF" symlinks optionally, but for recent Windows we currently can not handle the common "reparse point" symlinks fully, removing the caller for this. We will need to extend and reenable this "reparse point" worker code in cifs and fix cifs_symlink to call this. In the interim this code has been moved to its own config option so it is not compiled in by default until cifs_symlink fixed up (and tested) to use this. CC: Jeff Layton Signed-off-by: Steve French diff --git a/fs/cifs/README b/fs/cifs/README index 74ab165f..4a3ca0e 100644 --- a/fs/cifs/README +++ b/fs/cifs/README @@ -704,18 +704,6 @@ the start of smb requests and responses can be enabled via: echo 1 > /proc/fs/cifs/traceSMB -Two other experimental features are under development. To test these -requires enabling CONFIG_CIFS_EXPERIMENTAL - - cifsacl support needed to retrieve approximated mode bits based on - the contents on the CIFS ACL. - - lease support: cifs will check the oplock state before calling into - the vfs to see if we can grant a lease on a file. - - DNOTIFY fcntl: needed for support of directory change - notification and perhaps later for file leases) - Per share (per client mount) statistics are available in /proc/fs/cifs/Stats if the kernel was configured with cifs statistics enabled. The statistics represent the number of successful (ie non-zero return code from the server) diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h index 34bbd5c..da7a492 100644 --- a/fs/cifs/cifsproto.h +++ b/fs/cifs/cifsproto.h @@ -304,12 +304,13 @@ extern int CIFSSMBUnixQuerySymLink(const int xid, struct cifsTconInfo *tcon, const unsigned char *searchName, char **syminfo, const struct nls_table *nls_codepage); +#ifdef CONFIG_CIFS_SYMLINK_EXPERIMENTAL extern int CIFSSMBQueryReparseLinkInfo(const int xid, struct cifsTconInfo *tcon, const unsigned char *searchName, char *symlinkinfo, const int buflen, __u16 fid, const struct nls_table *nls_codepage); - +#endif /* temporarily unused until cifs_symlink fixed */ extern int CIFSSMBOpen(const int xid, struct cifsTconInfo *tcon, const char *fileName, const int disposition, const int access_flags, const int omode, diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c index 5630282..ae5e451 100644 --- a/fs/cifs/cifssmb.c +++ b/fs/cifs/cifssmb.c @@ -2516,7 +2516,17 @@ querySymLinkRetry: return rc; } -#ifdef CONFIG_CIFS_EXPERIMENTAL +#ifdef CONFIG_CIFS_SYMLINK_EXPERIMENTAL +/* + * Recent Windows versions now create symlinks more frequently + * and they use the "reparse point" mechanism below. We can of course + * do symlinks nicely to Samba and other servers which support the + * CIFS Unix Extensions and we can also do SFU symlinks and "client only" + * "MF" symlinks optionally, but for recent Windows we really need to + * reenable the code below and fix the cifs_symlink callers to handle this. + * In the interim this code has been moved to its own config option so + * it is not compiled in by default until callers fixed up and more tested. + */ int CIFSSMBQueryReparseLinkInfo(const int xid, struct cifsTconInfo *tcon, const unsigned char *searchName, @@ -2618,7 +2628,7 @@ qreparse_out: return rc; } -#endif /* CIFS_EXPERIMENTAL */ +#endif /* CIFS_SYMLINK_EXPERIMENTAL */ /* BB temporarily unused */ #ifdef CONFIG_CIFS_POSIX -- cgit v0.10.2 From fd62cb7e7411f1f5ca774145665316d3612fed9a Mon Sep 17 00:00:00 2001 From: "Justin P. Mattock" Date: Thu, 24 Feb 2011 22:15:02 -0800 Subject: fs:cifs:connect.c remove one to many l's in the word. The patch below removes an extra "l" in the word. Signed-off-by: Justin P. Mattock Signed-off-by: Steve French diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index 277262a..68b7dbf 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c @@ -735,7 +735,7 @@ multi_t2_fnd: sock_release(csocket); server->ssocket = NULL; } - /* buffer usuallly freed in free_mid - need to free it here on exit */ + /* buffer usually freed in free_mid - need to free it here on exit */ cifs_buf_release(bigbuf); if (smallbuf) /* no sense logging a debug message if NULL */ cifs_small_buf_release(smallbuf); -- cgit v0.10.2 From 34c87901e113799a45423fdac29c7478c889a95d Mon Sep 17 00:00:00 2001 From: Steve French Date: Tue, 1 Mar 2011 05:02:57 +0000 Subject: Shrink stack space usage in cifs_construct_tcon We were reserving MAX_USERNAME (now 256) on stack for something which only needs to fit about 24 bytes ie string krb50x + printf version of uid Signed-off-by: Steve French diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h index 6e211b6..108a1e99 100644 --- a/fs/cifs/cifsglob.h +++ b/fs/cifs/cifsglob.h @@ -274,7 +274,8 @@ struct cifsSesInfo { int capabilities; char serverName[SERVER_NAME_LEN_WITH_NULL * 2]; /* BB make bigger for TCP names - will ipv6 and sctp addresses fit? */ - char *user_name; + char *user_name; /* must not be null except during init of sess + and after mount option parsing we fill it */ char *domainName; char *password; struct session_key auth_key; diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index 68b7dbf..8d72acb 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c @@ -3258,7 +3258,9 @@ cifs_construct_tcon(struct cifs_sb_info *cifs_sb, uid_t fsuid) struct cifsSesInfo *ses; struct cifsTconInfo *tcon = NULL; struct smb_vol *vol_info; - char username[MAX_USERNAME_SIZE + 1]; + char username[28]; /* big enough for "krb50x" + hex of ULONG_MAX 6+16 */ + /* We used to have this as MAX_USERNAME which is */ + /* way too big now (256 instead of 32) */ vol_info = kzalloc(sizeof(*vol_info), GFP_KERNEL); if (vol_info == NULL) { -- cgit v0.10.2 From b34cb85cc2d84c487afe2baa2d3c04d8b677bbd0 Mon Sep 17 00:00:00 2001 From: Steve French Date: Thu, 24 Feb 2011 17:58:00 +0000 Subject: Introduce SMB2 Kconfig option SMB2 is the followon to the CIFS (and SMB) protocols and the default for Windows since Windows Vista, and also now implemented by various non-Windows servers. SMB2 is more secure, has various performance advantages, including larger i/o sizes, flow control, better caching model and more. SMB2 also resolves some scalability limits in the cifs protocol and adds many new features while being much simpler (only a few dozen commands instead of hundreds) and since the protocol is clearer it is also more consistently implemented across servers and thus easier to optimize. After much discussion with Jeff Layton, Jeremy Allison and others at Connectathon, we decided to move the smb2 code from a distinct .ko and fstype into distinct C files that optionally build in cifs.ko. As a result the Kconfig gets simpler. To avoid destabilizing cifs, the smb2 code is going to be moved into its own experimental CONFIG_CIFS_SMB2 ifdef as it is merged and rereviewed. The changes to stable cifs (builds with the smb2 ifdef off) are expected to be fairly small. Reviewed-by: Jeff Layton Signed-off-by: Steve French diff --git a/fs/cifs/Kconfig b/fs/cifs/Kconfig index 7cb0f7f..2a492aa 100644 --- a/fs/cifs/Kconfig +++ b/fs/cifs/Kconfig @@ -152,6 +152,26 @@ config CIFS_ACL Allows to fetch CIFS/NTFS ACL from the server. The DACL blob is handed over to the application/caller. +config CIFS_SMB2 + bool "SMB2 network file system support (EXPERIMENTAL)" + depends on EXPERIMENTAL && INET && BROKEN + select NLS + select KEYS + select FSCACHE + select DNS_RESOLVER + + help + This enables experimental support for the SMB2 (Server Message Block + version 2) protocol. The SMB2 protocol is the successor to the + popular CIFS and SMB network file sharing protocols. SMB2 is the + native file sharing mechanism for recent versions of Windows + operating systems (since Vista). SMB2 enablement will eventually + allow users better performance, security and features, than would be + possible with cifs. Note that smb2 mount options also are simpler + (compared to cifs) due to protocol improvements. + + Unless you are a developer or tester, say N. + config CIFS_EXPERIMENTAL bool "CIFS Experimental Features (EXPERIMENTAL)" depends on CIFS && EXPERIMENTAL -- cgit v0.10.2 From 257208736acc694def83627fa0de2892490a5d42 Mon Sep 17 00:00:00 2001 From: Shirish Pargaonkar Date: Fri, 25 Feb 2011 10:48:55 -0600 Subject: cifs: cleanup: Rename and remove config flags Remove config flag CIFS_EXPERIMENTAL. Do export operations under new config flag CIFS_NFSD_EXPORT Signed-off-by: Shirish Pargaonkar Reviewed-by: Jeff Layton Signed-off-by: Steve French diff --git a/fs/cifs/Kconfig b/fs/cifs/Kconfig index 2a492aa..7c584be 100644 --- a/fs/cifs/Kconfig +++ b/fs/cifs/Kconfig @@ -172,16 +172,8 @@ config CIFS_SMB2 Unless you are a developer or tester, say N. -config CIFS_EXPERIMENTAL - bool "CIFS Experimental Features (EXPERIMENTAL)" +config CIFS_NFSD_EXPORT + bool "Allow nfsd to export CIFS file system (EXPERIMENTAL)" depends on CIFS && EXPERIMENTAL help - Enables cifs features under testing. These features are - experimental and currently include DFS support and directory - change notification ie fcntl(F_DNOTIFY), as well as the upcall - mechanism which will be used for Kerberos session negotiation - and uid remapping. Some of these features also may depend on - setting a value of 1 to the pseudo-file /proc/fs/cifs/Experimental - (which is disabled by default). See the file fs/cifs/README - for more details. If unsure, say N. - + Allows NFS server to export a CIFS mounted share (nfsd over cifs) diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c index b45d38b..30fc505 100644 --- a/fs/cifs/cifsfs.c +++ b/fs/cifs/cifsfs.c @@ -184,12 +184,12 @@ cifs_read_super(struct super_block *sb, void *data, else sb->s_d_op = &cifs_dentry_ops; -#ifdef CONFIG_CIFS_EXPERIMENTAL +#ifdef CIFS_NFSD_EXPORT if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM) { cFYI(1, "export ops supported"); sb->s_export_op = &cifs_export_ops; } -#endif /* EXPERIMENTAL */ +#endif /* CIFS_NFSD_EXPORT */ return 0; diff --git a/fs/cifs/cifsfs.h b/fs/cifs/cifsfs.h index f191244..371d021 100644 --- a/fs/cifs/cifsfs.h +++ b/fs/cifs/cifsfs.h @@ -123,9 +123,9 @@ extern ssize_t cifs_getxattr(struct dentry *, const char *, void *, size_t); extern ssize_t cifs_listxattr(struct dentry *, char *, size_t); extern long cifs_ioctl(struct file *filep, unsigned int cmd, unsigned long arg); -#ifdef CONFIG_CIFS_EXPERIMENTAL +#ifdef CIFS_NFSD_EXPORT extern const struct export_operations cifs_export_ops; -#endif /* EXPERIMENTAL */ +#endif /* CIFS_NFSD_EXPORT */ #define CIFS_VERSION "1.71" #endif /* _CIFSFS_H */ diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c index ae5e451..e6374dd 100644 --- a/fs/cifs/cifssmb.c +++ b/fs/cifs/cifssmb.c @@ -541,10 +541,6 @@ CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses) server->secType = RawNTLMSSP; else if (secFlags & CIFSSEC_MAY_LANMAN) server->secType = LANMAN; -/* #ifdef CONFIG_CIFS_EXPERIMENTAL - else if (secFlags & CIFSSEC_MAY_PLNTXT) - server->secType = ?? -#endif */ else { rc = -EOPNOTSUPP; cERROR(1, "Invalid security type"); diff --git a/fs/cifs/export.c b/fs/cifs/export.c index 993f820..55d87ac 100644 --- a/fs/cifs/export.c +++ b/fs/cifs/export.c @@ -45,7 +45,7 @@ #include "cifs_debug.h" #include "cifsfs.h" -#ifdef CONFIG_CIFS_EXPERIMENTAL +#ifdef CIFS_NFSD_EXPORT static struct dentry *cifs_get_parent(struct dentry *dentry) { /* BB need to add code here eventually to enable export via NFSD */ @@ -63,5 +63,5 @@ const struct export_operations cifs_export_ops = { .encode_fs = */ }; -#endif /* EXPERIMENTAL */ +#endif /* CIFS_NFSD_EXPORT */ -- cgit v0.10.2 From 43988d76851077d2945080665e3c4e2e636d700a Mon Sep 17 00:00:00 2001 From: Steve French Date: Tue, 19 Apr 2011 18:23:31 +0000 Subject: [CIFS] Use ecb des kernel crypto APIs instead of local cifs functions (repost) Using kernel crypto APIs for DES encryption during LM and NT hash generation instead of local functions within cifs. Source file smbdes.c is deleted sans four functions, one of which uses ecb des functionality provided by kernel crypto APIs. Remove function SMBOWFencrypt. Add return codes to various functions such as calc_lanman_hash, SMBencrypt, and SMBNTencrypt. Includes fix noticed by Dan Carpenter. Signed-off-by: Shirish Pargaonkar CC: Dan Carpenter Acked-by: Jeff Layton Signed-off-by: Steve French diff --git a/fs/cifs/Kconfig b/fs/cifs/Kconfig index 7c584be..75c47cd 100644 --- a/fs/cifs/Kconfig +++ b/fs/cifs/Kconfig @@ -7,6 +7,7 @@ config CIFS select CRYPTO_MD5 select CRYPTO_HMAC select CRYPTO_ARC4 + select CRYPTO_DES help This is the client VFS module for the Common Internet File System (CIFS) protocol which is the successor to the Server Message Block diff --git a/fs/cifs/Makefile b/fs/cifs/Makefile index d875584..005d524 100644 --- a/fs/cifs/Makefile +++ b/fs/cifs/Makefile @@ -4,7 +4,7 @@ obj-$(CONFIG_CIFS) += cifs.o cifs-y := cifsfs.o cifssmb.o cifs_debug.o connect.o dir.o file.o inode.o \ - link.o misc.o netmisc.o smbdes.o smbencrypt.o transport.o asn1.o \ + link.o misc.o netmisc.o smbencrypt.o transport.o asn1.o \ cifs_unicode.o nterr.o xattr.o cifsencrypt.o \ readdir.o ioctl.o sess.o export.o diff --git a/fs/cifs/cifsencrypt.c b/fs/cifs/cifsencrypt.c index d1a016b..e7c5931 100644 --- a/fs/cifs/cifsencrypt.c +++ b/fs/cifs/cifsencrypt.c @@ -268,10 +268,11 @@ int setup_ntlm_response(struct cifsSesInfo *ses) } #ifdef CONFIG_CIFS_WEAK_PW_HASH -void calc_lanman_hash(const char *password, const char *cryptkey, bool encrypt, +int calc_lanman_hash(const char *password, const char *cryptkey, bool encrypt, char *lnm_session_key) { int i; + int rc; char password_with_pad[CIFS_ENCPWD_SIZE]; memset(password_with_pad, 0, CIFS_ENCPWD_SIZE); @@ -282,7 +283,7 @@ void calc_lanman_hash(const char *password, const char *cryptkey, bool encrypt, memset(lnm_session_key, 0, CIFS_SESS_KEY_SIZE); memcpy(lnm_session_key, password_with_pad, CIFS_ENCPWD_SIZE); - return; + return 0; } /* calculate old style session key */ @@ -299,10 +300,9 @@ void calc_lanman_hash(const char *password, const char *cryptkey, bool encrypt, for (i = 0; i < CIFS_ENCPWD_SIZE; i++) password_with_pad[i] = toupper(password_with_pad[i]); - SMBencrypt(password_with_pad, cryptkey, lnm_session_key); + rc = SMBencrypt(password_with_pad, cryptkey, lnm_session_key); - /* clear password before we return/free memory */ - memset(password_with_pad, 0, CIFS_ENCPWD_SIZE); + return rc; } #endif /* CIFS_WEAK_PW_HASH */ diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h index da7a492..e945269 100644 --- a/fs/cifs/cifsproto.h +++ b/fs/cifs/cifsproto.h @@ -384,7 +384,7 @@ extern void cifs_crypto_shash_release(struct TCP_Server_Info *); extern int calc_seckey(struct cifsSesInfo *); #ifdef CONFIG_CIFS_WEAK_PW_HASH -extern void calc_lanman_hash(const char *password, const char *cryptkey, +extern int calc_lanman_hash(const char *password, const char *cryptkey, bool encrypt, char *lnm_session_key); #endif /* CIFS_WEAK_PW_HASH */ #ifdef CONFIG_CIFS_DNOTIFY_EXPERIMENTAL /* unused temporarily */ @@ -430,9 +430,6 @@ extern int CIFSCheckMFSymlink(struct cifs_fattr *fattr, struct cifs_sb_info *cifs_sb, int xid); extern int mdfour(unsigned char *, unsigned char *, int); extern int E_md4hash(const unsigned char *passwd, unsigned char *p16); -extern void SMBencrypt(unsigned char *passwd, const unsigned char *c8, - unsigned char *p24); -extern void E_P16(unsigned char *p14, unsigned char *p16); -extern void E_P24(unsigned char *p21, const unsigned char *c8, +extern int SMBencrypt(unsigned char *passwd, const unsigned char *c8, unsigned char *p24); #endif /* _CIFSPROTO_H */ diff --git a/fs/cifs/sess.c b/fs/cifs/sess.c index 645114a..b6ff84a 100644 --- a/fs/cifs/sess.c +++ b/fs/cifs/sess.c @@ -656,7 +656,7 @@ ssetup_ntlmssp_authenticate: * to use challenge/response method (i.e. Password bit is 1). */ - calc_lanman_hash(ses->password, ses->server->cryptkey, + rc = calc_lanman_hash(ses->password, ses->server->cryptkey, ses->server->secMode & SECMODE_PW_ENCRYPT ? true : false, lnm_session_key); diff --git a/fs/cifs/smbdes.c b/fs/cifs/smbdes.c deleted file mode 100644 index 0472148..0000000 --- a/fs/cifs/smbdes.c +++ /dev/null @@ -1,418 +0,0 @@ -/* - Unix SMB/Netbios implementation. - Version 1.9. - - a partial implementation of DES designed for use in the - SMB authentication protocol - - Copyright (C) Andrew Tridgell 1998 - Modified by Steve French (sfrench@us.ibm.com) 2002,2004 - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -/* NOTES: - - This code makes no attempt to be fast! In fact, it is a very - slow implementation - - This code is NOT a complete DES implementation. It implements only - the minimum necessary for SMB authentication, as used by all SMB - products (including every copy of Microsoft Windows95 ever sold) - - In particular, it can only do a unchained forward DES pass. This - means it is not possible to use this code for encryption/decryption - of data, instead it is only useful as a "hash" algorithm. - - There is no entry point into this code that allows normal DES operation. - - I believe this means that this code does not come under ITAR - regulations but this is NOT a legal opinion. If you are concerned - about the applicability of ITAR regulations to this code then you - should confirm it for yourself (and maybe let me know if you come - up with a different answer to the one above) -*/ -#include -#define uchar unsigned char - -static uchar perm1[56] = { 57, 49, 41, 33, 25, 17, 9, - 1, 58, 50, 42, 34, 26, 18, - 10, 2, 59, 51, 43, 35, 27, - 19, 11, 3, 60, 52, 44, 36, - 63, 55, 47, 39, 31, 23, 15, - 7, 62, 54, 46, 38, 30, 22, - 14, 6, 61, 53, 45, 37, 29, - 21, 13, 5, 28, 20, 12, 4 -}; - -static uchar perm2[48] = { 14, 17, 11, 24, 1, 5, - 3, 28, 15, 6, 21, 10, - 23, 19, 12, 4, 26, 8, - 16, 7, 27, 20, 13, 2, - 41, 52, 31, 37, 47, 55, - 30, 40, 51, 45, 33, 48, - 44, 49, 39, 56, 34, 53, - 46, 42, 50, 36, 29, 32 -}; - -static uchar perm3[64] = { 58, 50, 42, 34, 26, 18, 10, 2, - 60, 52, 44, 36, 28, 20, 12, 4, - 62, 54, 46, 38, 30, 22, 14, 6, - 64, 56, 48, 40, 32, 24, 16, 8, - 57, 49, 41, 33, 25, 17, 9, 1, - 59, 51, 43, 35, 27, 19, 11, 3, - 61, 53, 45, 37, 29, 21, 13, 5, - 63, 55, 47, 39, 31, 23, 15, 7 -}; - -static uchar perm4[48] = { 32, 1, 2, 3, 4, 5, - 4, 5, 6, 7, 8, 9, - 8, 9, 10, 11, 12, 13, - 12, 13, 14, 15, 16, 17, - 16, 17, 18, 19, 20, 21, - 20, 21, 22, 23, 24, 25, - 24, 25, 26, 27, 28, 29, - 28, 29, 30, 31, 32, 1 -}; - -static uchar perm5[32] = { 16, 7, 20, 21, - 29, 12, 28, 17, - 1, 15, 23, 26, - 5, 18, 31, 10, - 2, 8, 24, 14, - 32, 27, 3, 9, - 19, 13, 30, 6, - 22, 11, 4, 25 -}; - -static uchar perm6[64] = { 40, 8, 48, 16, 56, 24, 64, 32, - 39, 7, 47, 15, 55, 23, 63, 31, - 38, 6, 46, 14, 54, 22, 62, 30, - 37, 5, 45, 13, 53, 21, 61, 29, - 36, 4, 44, 12, 52, 20, 60, 28, - 35, 3, 43, 11, 51, 19, 59, 27, - 34, 2, 42, 10, 50, 18, 58, 26, - 33, 1, 41, 9, 49, 17, 57, 25 -}; - -static uchar sc[16] = { 1, 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 1 }; - -static uchar sbox[8][4][16] = { - {{14, 4, 13, 1, 2, 15, 11, 8, 3, 10, 6, 12, 5, 9, 0, 7}, - {0, 15, 7, 4, 14, 2, 13, 1, 10, 6, 12, 11, 9, 5, 3, 8}, - {4, 1, 14, 8, 13, 6, 2, 11, 15, 12, 9, 7, 3, 10, 5, 0}, - {15, 12, 8, 2, 4, 9, 1, 7, 5, 11, 3, 14, 10, 0, 6, 13} }, - - {{15, 1, 8, 14, 6, 11, 3, 4, 9, 7, 2, 13, 12, 0, 5, 10}, - {3, 13, 4, 7, 15, 2, 8, 14, 12, 0, 1, 10, 6, 9, 11, 5}, - {0, 14, 7, 11, 10, 4, 13, 1, 5, 8, 12, 6, 9, 3, 2, 15}, - {13, 8, 10, 1, 3, 15, 4, 2, 11, 6, 7, 12, 0, 5, 14, 9} }, - - {{10, 0, 9, 14, 6, 3, 15, 5, 1, 13, 12, 7, 11, 4, 2, 8}, - {13, 7, 0, 9, 3, 4, 6, 10, 2, 8, 5, 14, 12, 11, 15, 1}, - {13, 6, 4, 9, 8, 15, 3, 0, 11, 1, 2, 12, 5, 10, 14, 7}, - {1, 10, 13, 0, 6, 9, 8, 7, 4, 15, 14, 3, 11, 5, 2, 12} }, - - {{7, 13, 14, 3, 0, 6, 9, 10, 1, 2, 8, 5, 11, 12, 4, 15}, - {13, 8, 11, 5, 6, 15, 0, 3, 4, 7, 2, 12, 1, 10, 14, 9}, - {10, 6, 9, 0, 12, 11, 7, 13, 15, 1, 3, 14, 5, 2, 8, 4}, - {3, 15, 0, 6, 10, 1, 13, 8, 9, 4, 5, 11, 12, 7, 2, 14} }, - - {{2, 12, 4, 1, 7, 10, 11, 6, 8, 5, 3, 15, 13, 0, 14, 9}, - {14, 11, 2, 12, 4, 7, 13, 1, 5, 0, 15, 10, 3, 9, 8, 6}, - {4, 2, 1, 11, 10, 13, 7, 8, 15, 9, 12, 5, 6, 3, 0, 14}, - {11, 8, 12, 7, 1, 14, 2, 13, 6, 15, 0, 9, 10, 4, 5, 3} }, - - {{12, 1, 10, 15, 9, 2, 6, 8, 0, 13, 3, 4, 14, 7, 5, 11}, - {10, 15, 4, 2, 7, 12, 9, 5, 6, 1, 13, 14, 0, 11, 3, 8}, - {9, 14, 15, 5, 2, 8, 12, 3, 7, 0, 4, 10, 1, 13, 11, 6}, - {4, 3, 2, 12, 9, 5, 15, 10, 11, 14, 1, 7, 6, 0, 8, 13} }, - - {{4, 11, 2, 14, 15, 0, 8, 13, 3, 12, 9, 7, 5, 10, 6, 1}, - {13, 0, 11, 7, 4, 9, 1, 10, 14, 3, 5, 12, 2, 15, 8, 6}, - {1, 4, 11, 13, 12, 3, 7, 14, 10, 15, 6, 8, 0, 5, 9, 2}, - {6, 11, 13, 8, 1, 4, 10, 7, 9, 5, 0, 15, 14, 2, 3, 12} }, - - {{13, 2, 8, 4, 6, 15, 11, 1, 10, 9, 3, 14, 5, 0, 12, 7}, - {1, 15, 13, 8, 10, 3, 7, 4, 12, 5, 6, 11, 0, 14, 9, 2}, - {7, 11, 4, 1, 9, 12, 14, 2, 0, 6, 10, 13, 15, 3, 5, 8}, - {2, 1, 14, 7, 4, 10, 8, 13, 15, 12, 9, 0, 3, 5, 6, 11} } -}; - -static void -permute(char *out, char *in, uchar *p, int n) -{ - int i; - for (i = 0; i < n; i++) - out[i] = in[p[i] - 1]; -} - -static void -lshift(char *d, int count, int n) -{ - char out[64]; - int i; - for (i = 0; i < n; i++) - out[i] = d[(i + count) % n]; - for (i = 0; i < n; i++) - d[i] = out[i]; -} - -static void -concat(char *out, char *in1, char *in2, int l1, int l2) -{ - while (l1--) - *out++ = *in1++; - while (l2--) - *out++ = *in2++; -} - -static void -xor(char *out, char *in1, char *in2, int n) -{ - int i; - for (i = 0; i < n; i++) - out[i] = in1[i] ^ in2[i]; -} - -static void -dohash(char *out, char *in, char *key, int forw) -{ - int i, j, k; - char *pk1; - char c[28]; - char d[28]; - char *cd; - char (*ki)[48]; - char *pd1; - char l[32], r[32]; - char *rl; - - /* Have to reduce stack usage */ - pk1 = kmalloc(56+56+64+64, GFP_KERNEL); - if (pk1 == NULL) - return; - - ki = kmalloc(16*48, GFP_KERNEL); - if (ki == NULL) { - kfree(pk1); - return; - } - - cd = pk1 + 56; - pd1 = cd + 56; - rl = pd1 + 64; - - permute(pk1, key, perm1, 56); - - for (i = 0; i < 28; i++) - c[i] = pk1[i]; - for (i = 0; i < 28; i++) - d[i] = pk1[i + 28]; - - for (i = 0; i < 16; i++) { - lshift(c, sc[i], 28); - lshift(d, sc[i], 28); - - concat(cd, c, d, 28, 28); - permute(ki[i], cd, perm2, 48); - } - - permute(pd1, in, perm3, 64); - - for (j = 0; j < 32; j++) { - l[j] = pd1[j]; - r[j] = pd1[j + 32]; - } - - for (i = 0; i < 16; i++) { - char *er; /* er[48] */ - char *erk; /* erk[48] */ - char b[8][6]; - char *cb; /* cb[32] */ - char *pcb; /* pcb[32] */ - char *r2; /* r2[32] */ - - er = kmalloc(48+48+32+32+32, GFP_KERNEL); - if (er == NULL) { - kfree(pk1); - kfree(ki); - return; - } - erk = er+48; - cb = erk+48; - pcb = cb+32; - r2 = pcb+32; - - permute(er, r, perm4, 48); - - xor(erk, er, ki[forw ? i : 15 - i], 48); - - for (j = 0; j < 8; j++) - for (k = 0; k < 6; k++) - b[j][k] = erk[j * 6 + k]; - - for (j = 0; j < 8; j++) { - int m, n; - m = (b[j][0] << 1) | b[j][5]; - - n = (b[j][1] << 3) | (b[j][2] << 2) | (b[j][3] << - 1) | b[j][4]; - - for (k = 0; k < 4; k++) - b[j][k] = - (sbox[j][m][n] & (1 << (3 - k))) ? 1 : 0; - } - - for (j = 0; j < 8; j++) - for (k = 0; k < 4; k++) - cb[j * 4 + k] = b[j][k]; - permute(pcb, cb, perm5, 32); - - xor(r2, l, pcb, 32); - - for (j = 0; j < 32; j++) - l[j] = r[j]; - - for (j = 0; j < 32; j++) - r[j] = r2[j]; - - kfree(er); - } - - concat(rl, r, l, 32, 32); - - permute(out, rl, perm6, 64); - kfree(pk1); - kfree(ki); -} - -static void -str_to_key(unsigned char *str, unsigned char *key) -{ - int i; - - key[0] = str[0] >> 1; - key[1] = ((str[0] & 0x01) << 6) | (str[1] >> 2); - key[2] = ((str[1] & 0x03) << 5) | (str[2] >> 3); - key[3] = ((str[2] & 0x07) << 4) | (str[3] >> 4); - key[4] = ((str[3] & 0x0F) << 3) | (str[4] >> 5); - key[5] = ((str[4] & 0x1F) << 2) | (str[5] >> 6); - key[6] = ((str[5] & 0x3F) << 1) | (str[6] >> 7); - key[7] = str[6] & 0x7F; - for (i = 0; i < 8; i++) - key[i] = (key[i] << 1); -} - -static void -smbhash(unsigned char *out, const unsigned char *in, unsigned char *key, - int forw) -{ - int i; - char *outb; /* outb[64] */ - char *inb; /* inb[64] */ - char *keyb; /* keyb[64] */ - unsigned char key2[8]; - - outb = kmalloc(64 * 3, GFP_KERNEL); - if (outb == NULL) - return; - - inb = outb + 64; - keyb = inb + 64; - - str_to_key(key, key2); - - for (i = 0; i < 64; i++) { - inb[i] = (in[i / 8] & (1 << (7 - (i % 8)))) ? 1 : 0; - keyb[i] = (key2[i / 8] & (1 << (7 - (i % 8)))) ? 1 : 0; - outb[i] = 0; - } - - dohash(outb, inb, keyb, forw); - - for (i = 0; i < 8; i++) - out[i] = 0; - - for (i = 0; i < 64; i++) { - if (outb[i]) - out[i / 8] |= (1 << (7 - (i % 8))); - } - kfree(outb); -} - -void -E_P16(unsigned char *p14, unsigned char *p16) -{ - unsigned char sp8[8] = - { 0x4b, 0x47, 0x53, 0x21, 0x40, 0x23, 0x24, 0x25 }; - smbhash(p16, sp8, p14, 1); - smbhash(p16 + 8, sp8, p14 + 7, 1); -} - -void -E_P24(unsigned char *p21, const unsigned char *c8, unsigned char *p24) -{ - smbhash(p24, c8, p21, 1); - smbhash(p24 + 8, c8, p21 + 7, 1); - smbhash(p24 + 16, c8, p21 + 14, 1); -} - -#if 0 /* currently unused */ -static void -D_P16(unsigned char *p14, unsigned char *in, unsigned char *out) -{ - smbhash(out, in, p14, 0); - smbhash(out + 8, in + 8, p14 + 7, 0); -} - -static void -E_old_pw_hash(unsigned char *p14, unsigned char *in, unsigned char *out) -{ - smbhash(out, in, p14, 1); - smbhash(out + 8, in + 8, p14 + 7, 1); -} -/* these routines are currently unneeded, but may be - needed later */ -void -cred_hash1(unsigned char *out, unsigned char *in, unsigned char *key) -{ - unsigned char buf[8]; - - smbhash(buf, in, key, 1); - smbhash(out, buf, key + 9, 1); -} - -void -cred_hash2(unsigned char *out, unsigned char *in, unsigned char *key) -{ - unsigned char buf[8]; - static unsigned char key2[8]; - - smbhash(buf, in, key, 1); - key2[0] = key[7]; - smbhash(out, buf, key2, 1); -} - -void -cred_hash3(unsigned char *out, unsigned char *in, unsigned char *key, int forw) -{ - static unsigned char key2[8]; - - smbhash(out, in, key, forw); - key2[0] = key[7]; - smbhash(out + 8, in + 8, key2, forw); -} -#endif /* unneeded routines */ diff --git a/fs/cifs/smbencrypt.c b/fs/cifs/smbencrypt.c index b5041c8..1525d5e 100644 --- a/fs/cifs/smbencrypt.c +++ b/fs/cifs/smbencrypt.c @@ -47,6 +47,88 @@ #define SSVALX(buf,pos,val) (CVAL(buf,pos)=(val)&0xFF,CVAL(buf,pos+1)=(val)>>8) #define SSVAL(buf,pos,val) SSVALX((buf),(pos),((__u16)(val))) +static void +str_to_key(unsigned char *str, unsigned char *key) +{ + int i; + + key[0] = str[0] >> 1; + key[1] = ((str[0] & 0x01) << 6) | (str[1] >> 2); + key[2] = ((str[1] & 0x03) << 5) | (str[2] >> 3); + key[3] = ((str[2] & 0x07) << 4) | (str[3] >> 4); + key[4] = ((str[3] & 0x0F) << 3) | (str[4] >> 5); + key[5] = ((str[4] & 0x1F) << 2) | (str[5] >> 6); + key[6] = ((str[5] & 0x3F) << 1) | (str[6] >> 7); + key[7] = str[6] & 0x7F; + for (i = 0; i < 8; i++) + key[i] = (key[i] << 1); +} + +static int +smbhash(unsigned char *out, const unsigned char *in, unsigned char *key) +{ + int rc; + unsigned char key2[8]; + struct crypto_blkcipher *tfm_des; + struct scatterlist sgin, sgout; + struct blkcipher_desc desc; + + str_to_key(key, key2); + + tfm_des = crypto_alloc_blkcipher("ecb(des)", 0, CRYPTO_ALG_ASYNC); + if (IS_ERR(tfm_des)) { + rc = PTR_ERR(tfm_des); + cERROR(1, "could not allocate des crypto API\n"); + goto smbhash_err; + } + + desc.tfm = tfm_des; + + crypto_blkcipher_setkey(tfm_des, key2, 8); + + sg_init_one(&sgin, in, 8); + sg_init_one(&sgout, out, 8); + + rc = crypto_blkcipher_encrypt(&desc, &sgout, &sgin, 8); + if (rc) { + cERROR(1, "could not encrypt crypt key rc: %d\n", rc); + crypto_free_blkcipher(tfm_des); + goto smbhash_err; + } + +smbhash_err: + return rc; +} + +static int +E_P16(unsigned char *p14, unsigned char *p16) +{ + int rc; + unsigned char sp8[8] = + { 0x4b, 0x47, 0x53, 0x21, 0x40, 0x23, 0x24, 0x25 }; + + rc = smbhash(p16, sp8, p14); + if (rc) + return rc; + rc = smbhash(p16 + 8, sp8, p14 + 7); + return rc; +} + +static int +E_P24(unsigned char *p21, const unsigned char *c8, unsigned char *p24) +{ + int rc; + + rc = smbhash(p24, c8, p21); + if (rc) + return rc; + rc = smbhash(p24 + 8, c8, p21 + 7); + if (rc) + return rc; + rc = smbhash(p24 + 16, c8, p21 + 14); + return rc; +} + /* produce a md4 message digest from data of length n bytes */ int mdfour(unsigned char *md4_hash, unsigned char *link_str, int link_len) @@ -87,40 +169,30 @@ mdfour_err: return rc; } -/* Does the des encryption from the NT or LM MD4 hash. */ -static void -SMBOWFencrypt(unsigned char passwd[16], const unsigned char *c8, - unsigned char p24[24]) -{ - unsigned char p21[21]; - - memset(p21, '\0', 21); - - memcpy(p21, passwd, 16); - E_P24(p21, c8, p24); -} - /* This implements the X/Open SMB password encryption It takes a password, a 8 byte "crypt key" and puts 24 bytes of encrypted password into p24 */ /* Note that password must be uppercased and null terminated */ -void +int SMBencrypt(unsigned char *passwd, const unsigned char *c8, unsigned char *p24) { - unsigned char p14[15], p21[21]; + int rc; + unsigned char p14[14], p16[16], p21[21]; - memset(p21, '\0', 21); memset(p14, '\0', 14); - strncpy((char *) p14, (char *) passwd, 14); + memset(p16, '\0', 16); + memset(p21, '\0', 21); -/* strupper((char *)p14); *//* BB at least uppercase the easy range */ - E_P16(p14, p21); + memcpy(p14, passwd, 14); + rc = E_P16(p14, p16); + if (rc) + return rc; - SMBOWFencrypt(p21, c8, p24); + memcpy(p21, p16, 16); + rc = E_P24(p21, c8, p24); - memset(p14, 0, 15); - memset(p21, 0, 21); + return rc; } /* Routines for Windows NT MD4 Hash functions. */ @@ -279,16 +351,18 @@ int SMBNTencrypt(unsigned char *passwd, unsigned char *c8, unsigned char *p24) { int rc; - unsigned char p21[21]; + unsigned char p16[16], p21[21]; + memset(p16, '\0', 16); memset(p21, '\0', 21); - rc = E_md4hash(passwd, p21); + rc = E_md4hash(passwd, p16); if (rc) { cFYI(1, "%s Can't generate NT hash, error: %d", __func__, rc); return rc; } - SMBOWFencrypt(p21, c8, p24); + memcpy(p21, p16, 16); + rc = E_P24(p21, c8, p24); return rc; } -- cgit v0.10.2 From b73b9a4ba753dfd7d304ee6ee4685b827524c533 Mon Sep 17 00:00:00 2001 From: Steve French Date: Tue, 19 Apr 2011 18:27:10 +0000 Subject: [CIFS] Allow to set extended attribute cifs_acl (try #2) Allow setting cifs_acl on the server. Pass on to the server the ACL blob generated by an application. cifs is just a pass-through, it does not monitor or inspect the contents of the blob, server decides whether to enforce/apply the ACL blob composed by an application. If setting of ACL is succeessful, mark the inode for revalidation. Signed-off-by: Shirish Pargaonkar Acked-by: Jeff Layton Signed-off-by: Steve French diff --git a/fs/cifs/cifsacl.c b/fs/cifs/cifsacl.c index beeebf1..a0d11ea 100644 --- a/fs/cifs/cifsacl.c +++ b/fs/cifs/cifsacl.c @@ -688,7 +688,7 @@ out: } /* Set an ACL on the server */ -static int set_cifs_acl(struct cifs_ntsd *pnntsd, __u32 acllen, +int set_cifs_acl(struct cifs_ntsd *pnntsd, __u32 acllen, struct inode *inode, const char *path) { struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb); diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h index e945269..0e4e057e 100644 --- a/fs/cifs/cifsproto.h +++ b/fs/cifs/cifsproto.h @@ -143,6 +143,8 @@ extern int cifs_acl_to_fattr(struct cifs_sb_info *cifs_sb, extern int mode_to_cifs_acl(struct inode *inode, const char *path, __u64); extern struct cifs_ntsd *get_cifs_acl(struct cifs_sb_info *, struct inode *, const char *, u32 *); +extern int set_cifs_acl(struct cifs_ntsd *, __u32, struct inode *, + const char *); extern int cifs_mount(struct super_block *, struct cifs_sb_info *, char *, const char *); diff --git a/fs/cifs/xattr.c b/fs/cifs/xattr.c index eae2a14..912995e 100644 --- a/fs/cifs/xattr.c +++ b/fs/cifs/xattr.c @@ -112,6 +112,7 @@ int cifs_setxattr(struct dentry *direntry, const char *ea_name, struct cifsTconInfo *pTcon; struct super_block *sb; char *full_path; + struct cifs_ntsd *pacl; if (direntry == NULL) return -EIO; @@ -166,6 +167,25 @@ int cifs_setxattr(struct dentry *direntry, const char *ea_name, rc = CIFSSMBSetEA(xid, pTcon, full_path, ea_name, ea_value, (__u16)value_size, cifs_sb->local_nls, cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); + } else if (strncmp(ea_name, CIFS_XATTR_CIFS_ACL, + strlen(CIFS_XATTR_CIFS_ACL)) == 0) { + pacl = kmalloc(value_size, GFP_KERNEL); + if (!pacl) { + cFYI(1, "%s: Can't allocate memory for ACL", + __func__); + rc = -ENOMEM; + } else { +#ifdef CONFIG_CIFS_ACL + memcpy(pacl, ea_value, value_size); + rc = set_cifs_acl(pacl, value_size, + direntry->d_inode, full_path); + if (rc == 0) /* force revalidate of the inode */ + CIFS_I(direntry->d_inode)->time = 0; + kfree(pacl); +#else + cFYI(1, "Set CIFS ACL not supported yet"); +#endif /* CONFIG_CIFS_ACL */ + } } else { int temp; temp = strncmp(ea_name, POSIX_ACL_XATTR_ACCESS, -- cgit v0.10.2 From 4358b5678b27ffe81391d84ce150df8e81010f6a Mon Sep 17 00:00:00 2001 From: Jeff Layton Date: Tue, 29 Mar 2011 09:33:31 -0400 Subject: VFS: trivial: fix comment on s_maxbytes value warning check I originally intended to remove this warning in 2.6.34, but it's not in a high performance codepath and might help us to catch bugs later. Let's keep it, but fix the comment to allay confusion about its removal. Signed-off-by: Jeff Layton Signed-off-by: Steve French diff --git a/fs/super.c b/fs/super.c index 8a06881..c04f7e0 100644 --- a/fs/super.c +++ b/fs/super.c @@ -948,8 +948,7 @@ mount_fs(struct file_system_type *type, int flags, const char *name, void *data) * filesystems should never set s_maxbytes larger than MAX_LFS_FILESIZE * but s_maxbytes was an unsigned long long for many releases. Throw * this warning for a little while to try and catch filesystems that - * violate this rule. This warning should be either removed or - * converted to a BUG() in 2.6.34. + * violate this rule. */ WARN((sb->s_maxbytes < 0), "%s set sb->s_maxbytes to " "negative value (%lld)\n", type->name, sb->s_maxbytes); -- cgit v0.10.2 From fd5707e1b44560d18b47d552c1871ea0bfc46688 Mon Sep 17 00:00:00 2001 From: Jeff Layton Date: Thu, 31 Mar 2011 17:22:07 -0400 Subject: cifs: fix comment in validate_t2 The comment about checking the bcc is in the wrong place. Also make it match kernel coding style. Reported-and-acked-by: David Howells Signed-off-by: Jeff Layton Signed-off-by: Steve French diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c index e6374dd..64dad47 100644 --- a/fs/cifs/cifssmb.c +++ b/fs/cifs/cifssmb.c @@ -339,12 +339,13 @@ static int validate_t2(struct smb_t2_rsp *pSMB) get_unaligned_le16(&pSMB->t2_rsp.DataOffset) > 1024) goto vt2_err; - /* check that bcc is at least as big as parms + data */ - /* check that bcc is less than negotiated smb buffer */ total_size = get_unaligned_le16(&pSMB->t2_rsp.ParameterCount); if (total_size >= 512) goto vt2_err; + /* check that bcc is at least as big as parms + data, and that it is + * less than negotiated smb buffer + */ total_size += get_unaligned_le16(&pSMB->t2_rsp.DataCount); if (total_size > get_bcc(&pSMB->hdr) || total_size >= CIFSMaxBufSize + MAX_CIFS_HDR_SIZE) -- cgit v0.10.2 From 257fb1f15d72f89dad2d72fa467c189f2d7fdd71 Mon Sep 17 00:00:00 2001 From: Pavel Shilovsky Date: Wed, 16 Mar 2011 01:55:32 +0300 Subject: CIFS: Use invalidate_inode_pages2 instead of invalidate_remote_inode (try #4) Use invalidate_inode_pages2 that don't leave pages even if shrink_page_list() has a temp ref on them. It prevents a data coherency problem when cifs_invalidate_mapping didn't invalidate pages but the client thinks that a data from the cache is uptodate according to an oplock level (exclusive or II). Signed-off-by: Pavel Shilovsky Signed-off-by: Steve French diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c index 196ef60..fbe7d58 100644 --- a/fs/cifs/inode.c +++ b/fs/cifs/inode.c @@ -1691,12 +1691,18 @@ cifs_invalidate_mapping(struct inode *inode) cifs_i->invalid_mapping = false; - /* write back any cached data */ if (inode->i_mapping && inode->i_mapping->nrpages != 0) { + /* write back any cached data */ rc = filemap_write_and_wait(inode->i_mapping); mapping_set_error(inode->i_mapping, rc); + rc = invalidate_inode_pages2(inode->i_mapping); + if (rc) { + cERROR(1, "%s: could not invalidate inode %p", __func__, + inode); + cifs_i->invalid_mapping = true; + } } - invalidate_remote_inode(inode); + cifs_fscache_reset_inode_cookie(inode); } -- cgit v0.10.2 From 1cb06d0b50536af177b2f2f7cab25546f3731d3e Mon Sep 17 00:00:00 2001 From: Steve French Date: Thu, 24 Feb 2011 18:07:19 +0000 Subject: Introduce smb2 mounts as vers=2 As with Linux nfs client, which uses "nfsvers=" or "vers=" to indicate which protocol to use for mount, specifying "vers=smb2" or "vers=2" will force an smb2 mount. When vers is not specified cifs is used ie "vers=cifs" or "vers=1" We can eventually autonegotiate down from smb2 to cifs when smb2 is stable enough to make it the default, but this is for the future. At that time we could also implement a "maxprotocol" mount option as smbclient and Samba have today, but that would be premature until smb2 is stable. Intially the smb2 Kconfig option will depend on "BROKEN" until the merge is complete, and then be "EXPERIMENTAL" When it is no longer experimental we can consider changing the default protocol to attempt first. Reviewed-by: Jeff Layton Reviewed-by: Pavel Shilovsky Signed-off-by: Steve French diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index 8d72acb..acd1e3c 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c @@ -102,6 +102,7 @@ struct smb_vol { bool fsc:1; /* enable fscache */ bool mfsymlinks:1; /* use Minshall+French Symlinks */ bool multiuser:1; + bool use_smb2:1; /* force smb2 use on mount instead of cifs */ unsigned int rsize; unsigned int wsize; bool sockopt_tcp_nodelay:1; @@ -1038,6 +1039,22 @@ cifs_parse_mount_options(char *options, const char *devname, cERROR(1, "bad security option: %s", value); return 1; } + } else if (strnicmp(data, "vers", 3) == 0) { + if (!value || !*value) { + cERROR(1, "no protocol version specified" + " after vers= mount option"); + } else if ((strnicmp(value, "cifs", 4) == 0) || + (strnicmp(value, "1", 1) == 0)) { + /* this is the default */ + continue; + } else if ((strnicmp(value, "smb2", 4) == 0) || + (strnicmp(value, "2", 1) == 0)) { +#ifdef CONFIG_CIFS_SMB2 + vol->use_smb2 = true; +#else + cERROR(1, "smb2 support not enabled"); +#endif /* CONFIG_CIFS_SMB2 */ + } } else if ((strnicmp(data, "unc", 3) == 0) || (strnicmp(data, "target", 6) == 0) || (strnicmp(data, "path", 4) == 0)) { -- cgit v0.10.2 From 9ad1506b42c828dff0b9d8f3914e1f837734e91c Mon Sep 17 00:00:00 2001 From: Pavel Shilovsky Date: Fri, 8 Apr 2011 05:29:10 +0400 Subject: CIFS: Add launder_page operation (try #3) Add this let us drop filemap_write_and_wait from cifs_invalidate_mapping and simplify the code to properly process invalidate logic. Reviewed-by: Jeff Layton Signed-off-by: Pavel Shilovsky Signed-off-by: Steve French diff --git a/fs/cifs/file.c b/fs/cifs/file.c index faf5952..00b466e 100644 --- a/fs/cifs/file.c +++ b/fs/cifs/file.c @@ -1420,9 +1420,10 @@ retry_write: return rc; } -static int cifs_writepage(struct page *page, struct writeback_control *wbc) +static int +cifs_writepage_locked(struct page *page, struct writeback_control *wbc) { - int rc = -EFAULT; + int rc; int xid; xid = GetXid(); @@ -1442,15 +1443,29 @@ static int cifs_writepage(struct page *page, struct writeback_control *wbc) * to fail to update with the state of the page correctly. */ set_page_writeback(page); +retry_write: rc = cifs_partialpagewrite(page, 0, PAGE_CACHE_SIZE); - SetPageUptodate(page); /* BB add check for error and Clearuptodate? */ - unlock_page(page); + if (rc == -EAGAIN && wbc->sync_mode == WB_SYNC_ALL) + goto retry_write; + else if (rc == -EAGAIN) + redirty_page_for_writepage(wbc, page); + else if (rc != 0) + SetPageError(page); + else + SetPageUptodate(page); end_page_writeback(page); page_cache_release(page); FreeXid(xid); return rc; } +static int cifs_writepage(struct page *page, struct writeback_control *wbc) +{ + int rc = cifs_writepage_locked(page, wbc); + unlock_page(page); + return rc; +} + static int cifs_write_end(struct file *file, struct address_space *mapping, loff_t pos, unsigned len, unsigned copied, struct page *page, void *fsdata) @@ -2415,6 +2430,27 @@ static void cifs_invalidate_page(struct page *page, unsigned long offset) cifs_fscache_invalidate_page(page, &cifsi->vfs_inode); } +static int cifs_launder_page(struct page *page) +{ + int rc = 0; + loff_t range_start = page_offset(page); + loff_t range_end = range_start + (loff_t)(PAGE_CACHE_SIZE - 1); + struct writeback_control wbc = { + .sync_mode = WB_SYNC_ALL, + .nr_to_write = 0, + .range_start = range_start, + .range_end = range_end, + }; + + cFYI(1, "Launder page: %p", page); + + if (clear_page_dirty_for_io(page)) + rc = cifs_writepage_locked(page, &wbc); + + cifs_fscache_invalidate_page(page, page->mapping->host); + return rc; +} + void cifs_oplock_break(struct work_struct *work) { struct cifsFileInfo *cfile = container_of(work, struct cifsFileInfo, @@ -2486,7 +2522,7 @@ const struct address_space_operations cifs_addr_ops = { .set_page_dirty = __set_page_dirty_nobuffers, .releasepage = cifs_release_page, .invalidatepage = cifs_invalidate_page, - /* .direct_IO = */ + .launder_page = cifs_launder_page, }; /* @@ -2503,5 +2539,5 @@ const struct address_space_operations cifs_addr_ops_smallbuf = { .set_page_dirty = __set_page_dirty_nobuffers, .releasepage = cifs_release_page, .invalidatepage = cifs_invalidate_page, - /* .direct_IO = */ + .launder_page = cifs_launder_page, }; -- cgit v0.10.2 From 4d79dba0e00749fa40de8ef13a9b85ce57a1603b Mon Sep 17 00:00:00 2001 From: Shirish Pargaonkar Date: Wed, 27 Apr 2011 23:34:35 -0500 Subject: cifs: Add idmap key and related data structures and functions (try #17 repost) Define (global) data structures to store ids, uids and gids, to which a SID maps. There are two separate trees, one for SID/uid and another one for SID/gid. A new type of key, cifs_idmap_key_type, is used. Keys are instantiated and searched using credential of the root by overriding and restoring the credentials of the caller requesting the key. Id mapping functions are invoked under config option of cifs acl. Signed-off-by: Shirish Pargaonkar Signed-off-by: Steve French diff --git a/fs/cifs/cifsacl.c b/fs/cifs/cifsacl.c index a0d11ea..061fc3a 100644 --- a/fs/cifs/cifsacl.c +++ b/fs/cifs/cifsacl.c @@ -23,6 +23,10 @@ #include #include +#include +#include +#include +#include #include "cifspdu.h" #include "cifsglob.h" #include "cifsacl.h" @@ -50,6 +54,140 @@ static const struct cifs_sid sid_authusers = { /* group users */ static const struct cifs_sid sid_user = {1, 2 , {0, 0, 0, 0, 0, 5}, {} }; +static const struct cred *root_cred; + +/* + * Run idmap cache shrinker. + */ +static int +cifs_idmap_shrinker(struct shrinker *shrink, int nr_to_scan, gfp_t gfp_mask) +{ + /* Use a pruning scheme in a subsequent patch instead */ + cifs_destroy_idmaptrees(); + return 0; +} + +static struct shrinker cifs_shrinker = { + .shrink = cifs_idmap_shrinker, + .seeks = DEFAULT_SEEKS, +}; + +static int +cifs_idmap_key_instantiate(struct key *key, const void *data, size_t datalen) +{ + char *payload; + + payload = kmalloc(datalen, GFP_KERNEL); + if (!payload) + return -ENOMEM; + + memcpy(payload, data, datalen); + key->payload.data = payload; + return 0; +} + +static inline void +cifs_idmap_key_destroy(struct key *key) +{ + kfree(key->payload.data); +} + +static +struct key_type cifs_idmap_key_type = { + .name = "cifs.cifs_idmap", + .instantiate = cifs_idmap_key_instantiate, + .destroy = cifs_idmap_key_destroy, + .describe = user_describe, + .match = user_match, +}; + +int +init_cifs_idmap(void) +{ + struct cred *cred; + struct key *keyring; + int ret; + + cFYI(1, "Registering the %s key type\n", cifs_idmap_key_type.name); + + /* create an override credential set with a special thread keyring in + * which requests are cached + * + * this is used to prevent malicious redirections from being installed + * with add_key(). + */ + cred = prepare_kernel_cred(NULL); + if (!cred) + return -ENOMEM; + + keyring = key_alloc(&key_type_keyring, ".cifs_idmap", 0, 0, cred, + (KEY_POS_ALL & ~KEY_POS_SETATTR) | + KEY_USR_VIEW | KEY_USR_READ, + KEY_ALLOC_NOT_IN_QUOTA); + if (IS_ERR(keyring)) { + ret = PTR_ERR(keyring); + goto failed_put_cred; + } + + ret = key_instantiate_and_link(keyring, NULL, 0, NULL, NULL); + if (ret < 0) + goto failed_put_key; + + ret = register_key_type(&cifs_idmap_key_type); + if (ret < 0) + goto failed_put_key; + + /* instruct request_key() to use this special keyring as a cache for + * the results it looks up */ + cred->thread_keyring = keyring; + cred->jit_keyring = KEY_REQKEY_DEFL_THREAD_KEYRING; + root_cred = cred; + + spin_lock_init(&siduidlock); + uidtree = RB_ROOT; + spin_lock_init(&sidgidlock); + gidtree = RB_ROOT; + + register_shrinker(&cifs_shrinker); + + cFYI(1, "cifs idmap keyring: %d\n", key_serial(keyring)); + return 0; + +failed_put_key: + key_put(keyring); +failed_put_cred: + put_cred(cred); + return ret; +} + +void +exit_cifs_idmap(void) +{ + key_revoke(root_cred->thread_keyring); + unregister_key_type(&cifs_idmap_key_type); + put_cred(root_cred); + unregister_shrinker(&cifs_shrinker); + cFYI(1, "Unregistered %s key type\n", cifs_idmap_key_type.name); +} + +void +cifs_destroy_idmaptrees(void) +{ + struct rb_root *root; + struct rb_node *node; + + root = &uidtree; + spin_lock(&siduidlock); + while ((node = rb_first(root))) + rb_erase(node, root); + spin_unlock(&siduidlock); + + root = &gidtree; + spin_lock(&sidgidlock); + while ((node = rb_first(root))) + rb_erase(node, root); + spin_unlock(&sidgidlock); +} int match_sid(struct cifs_sid *ctsid) { diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c index 30fc505..6c1d738 100644 --- a/fs/cifs/cifsfs.c +++ b/fs/cifs/cifsfs.c @@ -1033,22 +1033,31 @@ init_cifs(void) if (rc) goto out_destroy_mids; - rc = register_filesystem(&cifs_fs_type); - if (rc) - goto out_destroy_request_bufs; #ifdef CONFIG_CIFS_UPCALL rc = register_key_type(&cifs_spnego_key_type); if (rc) - goto out_unregister_filesystem; -#endif + goto out_destroy_request_bufs; +#endif /* CONFIG_CIFS_UPCALL */ + +#ifdef CONFIG_CIFS_ACL + rc = init_cifs_idmap(); + if (rc) + goto out_destroy_request_bufs; +#endif /* CONFIG_CIFS_ACL */ + + rc = register_filesystem(&cifs_fs_type); + if (rc) + goto out_destroy_request_bufs; return 0; +out_destroy_request_bufs: +#ifdef CONFIG_CIFS_ACL + exit_cifs_idmap(); +#endif #ifdef CONFIG_CIFS_UPCALL -out_unregister_filesystem: - unregister_filesystem(&cifs_fs_type); + unregister_key_type(&cifs_spnego_key_type); #endif -out_destroy_request_bufs: cifs_destroy_request_bufs(); out_destroy_mids: cifs_destroy_mids(); @@ -1070,6 +1079,10 @@ exit_cifs(void) #ifdef CONFIG_CIFS_DFS_UPCALL cifs_dfs_release_automount_timer(); #endif +#ifdef CONFIG_CIFS_ACL + cifs_destroy_idmaptrees(); + exit_cifs_idmap(); +#endif #ifdef CONFIG_CIFS_UPCALL unregister_key_type(&cifs_spnego_key_type); #endif diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h index 108a1e99..76b4517 100644 --- a/fs/cifs/cifsglob.h +++ b/fs/cifs/cifsglob.h @@ -833,6 +833,11 @@ GLOBAL_EXTERN unsigned int cifs_max_pending; /* MAX requests at once to server*/ /* reconnect after this many failed echo attempts */ GLOBAL_EXTERN unsigned short echo_retries; +GLOBAL_EXTERN struct rb_root uidtree; +GLOBAL_EXTERN struct rb_root gidtree; +GLOBAL_EXTERN spinlock_t siduidlock; +GLOBAL_EXTERN spinlock_t sidgidlock; + void cifs_oplock_break(struct work_struct *work); void cifs_oplock_break_get(struct cifsFileInfo *cfile); void cifs_oplock_break_put(struct cifsFileInfo *cfile); diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h index 0e4e057e..7c1ed01 100644 --- a/fs/cifs/cifsproto.h +++ b/fs/cifs/cifsproto.h @@ -53,6 +53,9 @@ do { \ cFYI(1, "CIFS VFS: leaving %s (xid = %d) rc = %d", \ __func__, curr_xid, (int)rc); \ } while (0) +extern int init_cifs_idmap(void); +extern void exit_cifs_idmap(void); +extern void cifs_destroy_idmaptrees(void); extern char *build_path_from_dentry(struct dentry *); extern char *cifs_build_path_to_root(struct cifs_sb_info *cifs_sb, struct cifsTconInfo *tcon); -- cgit v0.10.2 From 9409ae58e0759d010b347e7b19ebc90ab5d4b98f Mon Sep 17 00:00:00 2001 From: Shirish Pargaonkar Date: Fri, 22 Apr 2011 12:09:36 -0500 Subject: cifs: Invoke id mapping functions (try #17 repost) rb tree search and insertion routines. A SID which needs to be mapped, is looked up in one of the rb trees depending on whether SID is either owner or group SID. If found in the tree, a (mapped) id from that node is assigned to uid or gid as appropriate. If unmapped, an upcall is attempted to map the SID to an id. If upcall is successful, node is marked as mapped. If upcall fails, node stays marked as unmapped and a mapping is attempted again only after an arbitrary time period has passed. To map a SID, which can be either a Owner SID or a Group SID, key description starts with the string "os" or "gs" followed by SID converted to a string. Without "os" or "gs", cifs.upcall does not know whether SID needs to be mapped to either an uid or a gid. Nodes in rb tree have fields to prevent multiple upcalls for a SID. Searching, adding, and removing nodes is done within global locks. Whenever a node is either found or inserted in a tree, a reference is taken on that node. Shrinker routine prunes a node if it has expired but does not prune an expired node if its refcount is not zero (i.e. sid/id of that node is_being/will_be accessed). Thus a node, if its SID needs to be mapped by making an upcall, can safely stay and its fields accessed without shrinker pruning it. A reference (refcount) is put on the node without holding the spinlock but a reference is get on the node by holding the spinlock. Every time an existing mapped node is accessed or mapping is attempted, its timestamp is updated to prevent it from getting erased or a to prevent multiple unnecessary repeat mapping retries respectively. For now, cifs.upcall is only used to map a SID to an id (uid or gid) but it would be used to obtain an SID for an id. Signed-off-by: Shirish Pargaonkar Reviewed-by: Jeff Layton Signed-off-by: Steve French diff --git a/fs/cifs/cifsacl.c b/fs/cifs/cifsacl.c index 061fc3a..a4aa0f0 100644 --- a/fs/cifs/cifsacl.c +++ b/fs/cifs/cifsacl.c @@ -54,7 +54,33 @@ static const struct cifs_sid sid_authusers = { /* group users */ static const struct cifs_sid sid_user = {1, 2 , {0, 0, 0, 0, 0, 5}, {} }; -static const struct cred *root_cred; +const struct cred *root_cred; + +static void +shrink_idmap_tree(struct rb_root *root, int nr_to_scan, int *nr_rem, + int *nr_del) +{ + struct rb_node *node; + struct rb_node *tmp; + struct cifs_sid_id *psidid; + + node = rb_first(root); + while (node) { + tmp = node; + node = rb_next(tmp); + psidid = rb_entry(tmp, struct cifs_sid_id, rbnode); + if (nr_to_scan == 0 || *nr_del == nr_to_scan) + ++(*nr_rem); + else { + if (time_after(jiffies, psidid->time + SID_MAP_EXPIRE) + && psidid->refcount == 0) { + rb_erase(tmp, root); + ++(*nr_del); + } else + ++(*nr_rem); + } + } +} /* * Run idmap cache shrinker. @@ -62,9 +88,21 @@ static const struct cred *root_cred; static int cifs_idmap_shrinker(struct shrinker *shrink, int nr_to_scan, gfp_t gfp_mask) { - /* Use a pruning scheme in a subsequent patch instead */ - cifs_destroy_idmaptrees(); - return 0; + int nr_del = 0; + int nr_rem = 0; + struct rb_root *root; + + root = &uidtree; + spin_lock(&siduidlock); + shrink_idmap_tree(root, nr_to_scan, &nr_rem, &nr_del); + spin_unlock(&siduidlock); + + root = &gidtree; + spin_lock(&sidgidlock); + shrink_idmap_tree(root, nr_to_scan, &nr_rem, &nr_del); + spin_unlock(&sidgidlock); + + return nr_rem; } static struct shrinker cifs_shrinker = { @@ -92,7 +130,6 @@ cifs_idmap_key_destroy(struct key *key) kfree(key->payload.data); } -static struct key_type cifs_idmap_key_type = { .name = "cifs.cifs_idmap", .instantiate = cifs_idmap_key_instantiate, @@ -101,6 +138,220 @@ struct key_type cifs_idmap_key_type = { .match = user_match, }; +static void +sid_to_str(struct cifs_sid *sidptr, char *sidstr) +{ + int i; + unsigned long saval; + char *strptr; + + strptr = sidstr; + + sprintf(strptr, "%s", "S"); + strptr = sidstr + strlen(sidstr); + + sprintf(strptr, "-%d", sidptr->revision); + strptr = sidstr + strlen(sidstr); + + for (i = 0; i < 6; ++i) { + if (sidptr->authority[i]) { + sprintf(strptr, "-%d", sidptr->authority[i]); + strptr = sidstr + strlen(sidstr); + } + } + + for (i = 0; i < sidptr->num_subauth; ++i) { + saval = le32_to_cpu(sidptr->sub_auth[i]); + sprintf(strptr, "-%ld", saval); + strptr = sidstr + strlen(sidstr); + } +} + +static void +id_rb_insert(struct rb_root *root, struct cifs_sid *sidptr, + struct cifs_sid_id **psidid, char *typestr) +{ + int rc; + char *strptr; + struct rb_node *node = root->rb_node; + struct rb_node *parent = NULL; + struct rb_node **linkto = &(root->rb_node); + struct cifs_sid_id *lsidid; + + while (node) { + lsidid = rb_entry(node, struct cifs_sid_id, rbnode); + parent = node; + rc = compare_sids(sidptr, &((lsidid)->sid)); + if (rc > 0) { + linkto = &(node->rb_left); + node = node->rb_left; + } else if (rc < 0) { + linkto = &(node->rb_right); + node = node->rb_right; + } + } + + memcpy(&(*psidid)->sid, sidptr, sizeof(struct cifs_sid)); + (*psidid)->time = jiffies - (SID_MAP_RETRY + 1); + (*psidid)->refcount = 0; + + sprintf((*psidid)->sidstr, "%s", typestr); + strptr = (*psidid)->sidstr + strlen((*psidid)->sidstr); + sid_to_str(&(*psidid)->sid, strptr); + + clear_bit(SID_ID_PENDING, &(*psidid)->state); + clear_bit(SID_ID_MAPPED, &(*psidid)->state); + + rb_link_node(&(*psidid)->rbnode, parent, linkto); + rb_insert_color(&(*psidid)->rbnode, root); +} + +static struct cifs_sid_id * +id_rb_search(struct rb_root *root, struct cifs_sid *sidptr) +{ + int rc; + struct rb_node *node = root->rb_node; + struct rb_node *parent = NULL; + struct rb_node **linkto = &(root->rb_node); + struct cifs_sid_id *lsidid; + + while (node) { + lsidid = rb_entry(node, struct cifs_sid_id, rbnode); + parent = node; + rc = compare_sids(sidptr, &((lsidid)->sid)); + if (rc > 0) { + linkto = &(node->rb_left); + node = node->rb_left; + } else if (rc < 0) { + linkto = &(node->rb_right); + node = node->rb_right; + } else /* node found */ + return lsidid; + } + + return NULL; +} + +static int +sidid_pending_wait(void *unused) +{ + schedule(); + return signal_pending(current) ? -ERESTARTSYS : 0; +} + +static int +sid_to_id(struct cifs_sb_info *cifs_sb, struct cifs_sid *psid, + struct cifs_fattr *fattr, uint sidtype) +{ + int rc; + unsigned long cid; + struct key *idkey; + const struct cred *saved_cred; + struct cifs_sid_id *psidid, *npsidid; + struct rb_root *cidtree; + spinlock_t *cidlock; + + if (sidtype == SIDOWNER) { + cid = cifs_sb->mnt_uid; /* default uid, in case upcall fails */ + cidlock = &siduidlock; + cidtree = &uidtree; + } else if (sidtype == SIDGROUP) { + cid = cifs_sb->mnt_gid; /* default gid, in case upcall fails */ + cidlock = &sidgidlock; + cidtree = &gidtree; + } else + return -ENOENT; + + spin_lock(cidlock); + psidid = id_rb_search(cidtree, psid); + + if (!psidid) { /* node does not exist, allocate one & attempt adding */ + spin_unlock(cidlock); + npsidid = kzalloc(sizeof(struct cifs_sid_id), GFP_KERNEL); + if (!npsidid) + return -ENOMEM; + + npsidid->sidstr = kmalloc(SIDLEN, GFP_KERNEL); + if (!npsidid->sidstr) { + kfree(npsidid); + return -ENOMEM; + } + + spin_lock(cidlock); + psidid = id_rb_search(cidtree, psid); + if (psidid) { /* node happened to get inserted meanwhile */ + ++psidid->refcount; + spin_unlock(cidlock); + kfree(npsidid->sidstr); + kfree(npsidid); + } else { + psidid = npsidid; + id_rb_insert(cidtree, psid, &psidid, + sidtype == SIDOWNER ? "os:" : "gs:"); + ++psidid->refcount; + spin_unlock(cidlock); + } + } else { + ++psidid->refcount; + spin_unlock(cidlock); + } + + /* + * If we are here, it is safe to access psidid and its fields + * since a reference was taken earlier while holding the spinlock. + * A reference on the node is put without holding the spinlock + * and it is OK to do so in this case, shrinker will not erase + * this node until all references are put and we do not access + * any fields of the node after a reference is put . + */ + if (test_bit(SID_ID_MAPPED, &psidid->state)) { + cid = psidid->id; + psidid->time = jiffies; /* update ts for accessing */ + goto sid_to_id_out; + } + + if (time_after(psidid->time + SID_MAP_RETRY, jiffies)) + goto sid_to_id_out; + + if (!test_and_set_bit(SID_ID_PENDING, &psidid->state)) { + saved_cred = override_creds(root_cred); + idkey = request_key(&cifs_idmap_key_type, psidid->sidstr, ""); + if (IS_ERR(idkey)) + cFYI(1, "%s: Can't map SID to an id", __func__); + else { + cid = *(unsigned long *)idkey->payload.value; + psidid->id = cid; + set_bit(SID_ID_MAPPED, &psidid->state); + key_put(idkey); + kfree(psidid->sidstr); + } + revert_creds(saved_cred); + psidid->time = jiffies; /* update ts for accessing */ + clear_bit(SID_ID_PENDING, &psidid->state); + wake_up_bit(&psidid->state, SID_ID_PENDING); + } else { + rc = wait_on_bit(&psidid->state, SID_ID_PENDING, + sidid_pending_wait, TASK_INTERRUPTIBLE); + if (rc) { + cFYI(1, "%s: sidid_pending_wait interrupted %d", + __func__, rc); + --psidid->refcount; /* decremented without spinlock */ + return rc; + } + if (test_bit(SID_ID_MAPPED, &psidid->state)) + cid = psidid->id; + } + +sid_to_id_out: + --psidid->refcount; /* decremented without spinlock */ + if (sidtype == SIDOWNER) + fattr->cf_uid = cid; + else + fattr->cf_gid = cid; + + return 0; +} + int init_cifs_idmap(void) { @@ -242,16 +493,24 @@ int compare_sids(const struct cifs_sid *ctsid, const struct cifs_sid *cwsid) int num_subauth, num_sat, num_saw; if ((!ctsid) || (!cwsid)) - return 0; + return 1; /* compare the revision */ - if (ctsid->revision != cwsid->revision) - return 0; + if (ctsid->revision != cwsid->revision) { + if (ctsid->revision > cwsid->revision) + return 1; + else + return -1; + } /* compare all of the six auth values */ for (i = 0; i < 6; ++i) { - if (ctsid->authority[i] != cwsid->authority[i]) - return 0; + if (ctsid->authority[i] != cwsid->authority[i]) { + if (ctsid->authority[i] > cwsid->authority[i]) + return 1; + else + return -1; + } } /* compare all of the subauth values if any */ @@ -260,12 +519,16 @@ int compare_sids(const struct cifs_sid *ctsid, const struct cifs_sid *cwsid) num_subauth = num_sat < num_saw ? num_sat : num_saw; if (num_subauth) { for (i = 0; i < num_subauth; ++i) { - if (ctsid->sub_auth[i] != cwsid->sub_auth[i]) - return 0; + if (ctsid->sub_auth[i] != cwsid->sub_auth[i]) { + if (ctsid->sub_auth[i] > cwsid->sub_auth[i]) + return 1; + else + return -1; + } } } - return 1; /* sids compare/match */ + return 0; /* sids compare/match */ } @@ -520,22 +783,22 @@ static void parse_dacl(struct cifs_acl *pdacl, char *end_of_acl, #ifdef CONFIG_CIFS_DEBUG2 dump_ace(ppace[i], end_of_acl); #endif - if (compare_sids(&(ppace[i]->sid), pownersid)) + if (compare_sids(&(ppace[i]->sid), pownersid) == 0) access_flags_to_mode(ppace[i]->access_req, ppace[i]->type, &fattr->cf_mode, &user_mask); - if (compare_sids(&(ppace[i]->sid), pgrpsid)) + if (compare_sids(&(ppace[i]->sid), pgrpsid) == 0) access_flags_to_mode(ppace[i]->access_req, ppace[i]->type, &fattr->cf_mode, &group_mask); - if (compare_sids(&(ppace[i]->sid), &sid_everyone)) + if (compare_sids(&(ppace[i]->sid), &sid_everyone) == 0) access_flags_to_mode(ppace[i]->access_req, ppace[i]->type, &fattr->cf_mode, &other_mask); - if (compare_sids(&(ppace[i]->sid), &sid_authusers)) + if (compare_sids(&(ppace[i]->sid), &sid_authusers) == 0) access_flags_to_mode(ppace[i]->access_req, ppace[i]->type, &fattr->cf_mode, @@ -613,10 +876,10 @@ static int parse_sid(struct cifs_sid *psid, char *end_of_acl) /* Convert CIFS ACL to POSIX form */ -static int parse_sec_desc(struct cifs_ntsd *pntsd, int acl_len, - struct cifs_fattr *fattr) +static int parse_sec_desc(struct cifs_sb_info *cifs_sb, + struct cifs_ntsd *pntsd, int acl_len, struct cifs_fattr *fattr) { - int rc; + int rc = 0; struct cifs_sid *owner_sid_ptr, *group_sid_ptr; struct cifs_acl *dacl_ptr; /* no need for SACL ptr */ char *end_of_acl = ((char *)pntsd) + acl_len; @@ -638,12 +901,26 @@ static int parse_sec_desc(struct cifs_ntsd *pntsd, int acl_len, le32_to_cpu(pntsd->sacloffset), dacloffset); /* cifs_dump_mem("owner_sid: ", owner_sid_ptr, 64); */ rc = parse_sid(owner_sid_ptr, end_of_acl); - if (rc) + if (rc) { + cFYI(1, "%s: Error %d parsing Owner SID", __func__, rc); return rc; + } + rc = sid_to_id(cifs_sb, owner_sid_ptr, fattr, SIDOWNER); + if (rc) { + cFYI(1, "%s: Error %d mapping Owner SID to uid", __func__, rc); + return rc; + } rc = parse_sid(group_sid_ptr, end_of_acl); - if (rc) + if (rc) { + cFYI(1, "%s: Error %d mapping Owner SID to gid", __func__, rc); return rc; + } + rc = sid_to_id(cifs_sb, group_sid_ptr, fattr, SIDGROUP); + if (rc) { + cFYI(1, "%s: Error %d mapping Group SID to gid", __func__, rc); + return rc; + } if (dacloffset) parse_dacl(dacl_ptr, end_of_acl, owner_sid_ptr, @@ -658,7 +935,7 @@ static int parse_sec_desc(struct cifs_ntsd *pntsd, int acl_len, memcpy((void *)(&(cifscred->gsid)), (void *)group_sid_ptr, sizeof(struct cifs_sid)); */ - return 0; + return rc; } @@ -865,7 +1142,7 @@ cifs_acl_to_fattr(struct cifs_sb_info *cifs_sb, struct cifs_fattr *fattr, rc = PTR_ERR(pntsd); cERROR(1, "%s: error %d getting sec desc", __func__, rc); } else { - rc = parse_sec_desc(pntsd, acllen, fattr); + rc = parse_sec_desc(cifs_sb, pntsd, acllen, fattr); kfree(pntsd); if (rc) cERROR(1, "parse sec desc failed rc = %d", rc); diff --git a/fs/cifs/cifsacl.h b/fs/cifs/cifsacl.h index c4ae7d0..757cf5a 100644 --- a/fs/cifs/cifsacl.h +++ b/fs/cifs/cifsacl.h @@ -39,6 +39,15 @@ #define ACCESS_ALLOWED 0 #define ACCESS_DENIED 1 +#define SIDOWNER 1 +#define SIDGROUP 2 +#define SIDLEN 150 /* S- 1 revision- 6 authorities- max 5 sub authorities */ + +#define SID_ID_MAPPED 0 +#define SID_ID_PENDING 1 +#define SID_MAP_EXPIRE (3600 * HZ) /* map entry expires after one hour */ +#define SID_MAP_RETRY (300 * HZ) /* wait 5 minutes for next attempt to map */ + struct cifs_ntsd { __le16 revision; /* revision level */ __le16 type; @@ -74,6 +83,21 @@ struct cifs_wksid { char sidname[SIDNAMELENGTH]; } __attribute__((packed)); +struct cifs_sid_id { + unsigned int refcount; /* increment with spinlock, decrement without */ + unsigned long id; + unsigned long time; + unsigned long state; + char *sidstr; + struct rb_node rbnode; + struct cifs_sid sid; +}; + +#ifdef __KERNEL__ +extern struct key_type cifs_idmap_key_type; +extern const struct cred *root_cred; +#endif /* KERNEL */ + extern int match_sid(struct cifs_sid *); extern int compare_sids(const struct cifs_sid *, const struct cifs_sid *); -- cgit v0.10.2 From be8e3b0044a68e1f1002c432f6b40d290cf0701d Mon Sep 17 00:00:00 2001 From: Steve French Date: Fri, 29 Apr 2011 05:40:20 +0000 Subject: consistently use smb_buf_length as be32 for cifs (try 3) There is one big endian field in the cifs protocol, the RFC1001 length, which cifs code (unlike in the smb2 code) had been handling as u32 until the last possible moment, when it was converted to be32 (its native form) before sending on the wire. To remove the last sparse endian warning, and to make this consistent with the smb2 implementation (which always treats the fields in their native size and endianness), convert all uses of smb_buf_length to be32. This version incorporates Christoph's comment about using be32_add_cpu, and fixes a typo in the second version of the patch. Signed-off-by: Steve French Signed-off-by: Pavel Shilovsky Signed-off-by: Steve French diff --git a/fs/cifs/cifsencrypt.c b/fs/cifs/cifsencrypt.c index e7c5931..45c3f78 100644 --- a/fs/cifs/cifsencrypt.c +++ b/fs/cifs/cifsencrypt.c @@ -60,7 +60,7 @@ static int cifs_calculate_signature(const struct smb_hdr *cifs_pdu, server->session_key.response, server->session_key.len); crypto_shash_update(&server->secmech.sdescmd5->shash, - cifs_pdu->Protocol, cifs_pdu->smb_buf_length); + cifs_pdu->Protocol, be32_to_cpu(cifs_pdu->smb_buf_length)); rc = crypto_shash_final(&server->secmech.sdescmd5->shash, signature); diff --git a/fs/cifs/cifspdu.h b/fs/cifs/cifspdu.h index b5c8cc5..eac95e2 100644 --- a/fs/cifs/cifspdu.h +++ b/fs/cifs/cifspdu.h @@ -397,9 +397,9 @@ #define GETU32(var) (*((__u32 *)var)) /* BB check for endian issues */ struct smb_hdr { - __u32 smb_buf_length; /* big endian on wire *//* BB length is only two - or three bytes - with one or two byte type preceding it that are - zero - we could mask the type byte off just in case BB */ + __be32 smb_buf_length; /* BB length is only two (rarely three) bytes, + with one or two byte "type" preceding it that will be + zero - we could mask the type byte off */ __u8 Protocol[4]; __u8 Command; union { diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c index 64dad47..8800409 100644 --- a/fs/cifs/cifssmb.c +++ b/fs/cifs/cifssmb.c @@ -358,6 +358,13 @@ vt2_err: return -EINVAL; } +static inline void inc_rfc1001_len(void *pSMB, int count) +{ + struct smb_hdr *hdr = (struct smb_hdr *)pSMB; + + be32_add_cpu(&hdr->smb_buf_length, count); +} + int CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses) { @@ -410,7 +417,7 @@ CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses) count += strlen(protocols[i].name) + 1; /* null at end of source and target buffers anyway */ } - pSMB->hdr.smb_buf_length += count; + inc_rfc1001_len(pSMB, count); pSMB->ByteCount = cpu_to_le16(count); rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB, @@ -731,7 +738,7 @@ CIFSSMBEcho(struct TCP_Server_Info *server) put_unaligned_le16(1, &smb->EchoCount); put_bcc_le(1, &smb->hdr); smb->Data[0] = 'a'; - smb->hdr.smb_buf_length += 3; + inc_rfc1001_len(smb, 3); rc = cifs_call_async(server, (struct smb_hdr *)smb, cifs_echo_callback, server); @@ -849,7 +856,7 @@ PsxDelete: pSMB->TotalParameterCount = pSMB->ParameterCount; pSMB->InformationLevel = cpu_to_le16(SMB_POSIX_UNLINK); pSMB->Reserved4 = 0; - pSMB->hdr.smb_buf_length += byte_count; + inc_rfc1001_len(pSMB, byte_count); pSMB->ByteCount = cpu_to_le16(byte_count); rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, (struct smb_hdr *) pSMBr, &bytes_returned, 0); @@ -895,7 +902,7 @@ DelFileRetry: pSMB->SearchAttributes = cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM); pSMB->BufferFormat = 0x04; - pSMB->hdr.smb_buf_length += name_len + 1; + inc_rfc1001_len(pSMB, name_len + 1); pSMB->ByteCount = cpu_to_le16(name_len + 1); rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, (struct smb_hdr *) pSMBr, &bytes_returned, 0); @@ -939,7 +946,7 @@ RmDirRetry: } pSMB->BufferFormat = 0x04; - pSMB->hdr.smb_buf_length += name_len + 1; + inc_rfc1001_len(pSMB, name_len + 1); pSMB->ByteCount = cpu_to_le16(name_len + 1); rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, (struct smb_hdr *) pSMBr, &bytes_returned, 0); @@ -982,7 +989,7 @@ MkDirRetry: } pSMB->BufferFormat = 0x04; - pSMB->hdr.smb_buf_length += name_len + 1; + inc_rfc1001_len(pSMB, name_len + 1); pSMB->ByteCount = cpu_to_le16(name_len + 1); rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, (struct smb_hdr *) pSMBr, &bytes_returned, 0); @@ -1060,7 +1067,7 @@ PsxCreat: pSMB->TotalParameterCount = pSMB->ParameterCount; pSMB->InformationLevel = cpu_to_le16(SMB_POSIX_OPEN); pSMB->Reserved4 = 0; - pSMB->hdr.smb_buf_length += byte_count; + inc_rfc1001_len(pSMB, byte_count); pSMB->ByteCount = cpu_to_le16(byte_count); rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, (struct smb_hdr *) pSMBr, &bytes_returned, 0); @@ -1225,7 +1232,7 @@ OldOpenRetry: pSMB->Sattr = cpu_to_le16(ATTR_HIDDEN | ATTR_SYSTEM | ATTR_DIRECTORY); pSMB->OpenFunction = cpu_to_le16(convert_disposition(openDisposition)); count += name_len; - pSMB->hdr.smb_buf_length += count; + inc_rfc1001_len(pSMB, count); pSMB->ByteCount = cpu_to_le16(count); /* long_op set to 1 to allow for oplock break timeouts */ @@ -1338,7 +1345,7 @@ openRetry: SECURITY_CONTEXT_TRACKING | SECURITY_EFFECTIVE_ONLY; count += name_len; - pSMB->hdr.smb_buf_length += count; + inc_rfc1001_len(pSMB, count); pSMB->ByteCount = cpu_to_le16(count); /* long_op set to 1 to allow for oplock break timeouts */ @@ -1423,7 +1430,7 @@ CIFSSMBRead(const int xid, struct cifsTconInfo *tcon, const int netfid, } iov[0].iov_base = (char *)pSMB; - iov[0].iov_len = pSMB->hdr.smb_buf_length + 4; + iov[0].iov_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 4; rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovecs */, &resp_buf_type, CIFS_LOG_ERROR); cifs_stats_inc(&tcon->num_reads); @@ -1557,7 +1564,7 @@ CIFSSMBWrite(const int xid, struct cifsTconInfo *tcon, pSMB->DataLengthLow = cpu_to_le16(bytes_sent & 0xFFFF); pSMB->DataLengthHigh = cpu_to_le16(bytes_sent >> 16); - pSMB->hdr.smb_buf_length += byte_count; + inc_rfc1001_len(pSMB, byte_count); if (wct == 14) pSMB->ByteCount = cpu_to_le16(byte_count); @@ -1641,11 +1648,12 @@ CIFSSMBWrite2(const int xid, struct cifsTconInfo *tcon, pSMB->DataLengthLow = cpu_to_le16(count & 0xFFFF); pSMB->DataLengthHigh = cpu_to_le16(count >> 16); - smb_hdr_len = pSMB->hdr.smb_buf_length + 1; /* hdr + 1 byte pad */ + /* header + 1 byte pad */ + smb_hdr_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 1; if (wct == 14) - pSMB->hdr.smb_buf_length += count+1; + inc_rfc1001_len(pSMB, count + 1); else /* wct == 12 */ - pSMB->hdr.smb_buf_length += count+5; /* smb data starts later */ + inc_rfc1001_len(pSMB, count + 5); /* smb data starts later */ if (wct == 14) pSMB->ByteCount = cpu_to_le16(count + 1); else /* wct == 12 */ /* bigger pad, smaller smb hdr, keep offset ok */ { @@ -1745,7 +1753,7 @@ CIFSSMBLock(const int xid, struct cifsTconInfo *tcon, /* oplock break */ count = 0; } - pSMB->hdr.smb_buf_length += count; + inc_rfc1001_len(pSMB, count); pSMB->ByteCount = cpu_to_le16(count); if (waitFlag) { @@ -1836,14 +1844,14 @@ CIFSSMBPosixLock(const int xid, struct cifsTconInfo *tcon, pSMB->Fid = smb_file_id; pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_LOCK); pSMB->Reserved4 = 0; - pSMB->hdr.smb_buf_length += byte_count; + inc_rfc1001_len(pSMB, byte_count); pSMB->ByteCount = cpu_to_le16(byte_count); if (waitFlag) { rc = SendReceiveBlockingLock(xid, tcon, (struct smb_hdr *) pSMB, (struct smb_hdr *) pSMBr, &bytes_returned); } else { iov[0].iov_base = (char *)pSMB; - iov[0].iov_len = pSMB->hdr.smb_buf_length + 4; + iov[0].iov_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 4; rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovecs */, &resp_buf_type, timeout); pSMB = NULL; /* request buf already freed by SendReceive2. Do @@ -2009,7 +2017,7 @@ renameRetry: } count = 1 /* 1st signature byte */ + name_len + name_len2; - pSMB->hdr.smb_buf_length += count; + inc_rfc1001_len(pSMB, count); pSMB->ByteCount = cpu_to_le16(count); rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, @@ -2089,7 +2097,7 @@ int CIFSSMBRenameOpenFile(const int xid, struct cifsTconInfo *pTcon, pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_RENAME_INFORMATION); pSMB->Reserved4 = 0; - pSMB->hdr.smb_buf_length += byte_count; + inc_rfc1001_len(pSMB, byte_count); pSMB->ByteCount = cpu_to_le16(byte_count); rc = SendReceive(xid, pTcon->ses, (struct smb_hdr *) pSMB, (struct smb_hdr *) pSMBr, &bytes_returned, 0); @@ -2156,7 +2164,7 @@ copyRetry: } count = 1 /* 1st signature byte */ + name_len + name_len2; - pSMB->hdr.smb_buf_length += count; + inc_rfc1001_len(pSMB, count); pSMB->ByteCount = cpu_to_le16(count); rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, @@ -2246,7 +2254,7 @@ createSymLinkRetry: pSMB->DataOffset = cpu_to_le16(offset); pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_LINK); pSMB->Reserved4 = 0; - pSMB->hdr.smb_buf_length += byte_count; + inc_rfc1001_len(pSMB, byte_count); pSMB->ByteCount = cpu_to_le16(byte_count); rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, (struct smb_hdr *) pSMBr, &bytes_returned, 0); @@ -2332,7 +2340,7 @@ createHardLinkRetry: pSMB->DataOffset = cpu_to_le16(offset); pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_HLINK); pSMB->Reserved4 = 0; - pSMB->hdr.smb_buf_length += byte_count; + inc_rfc1001_len(pSMB, byte_count); pSMB->ByteCount = cpu_to_le16(byte_count); rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, (struct smb_hdr *) pSMBr, &bytes_returned, 0); @@ -2403,7 +2411,7 @@ winCreateHardLinkRetry: } count = 1 /* string type byte */ + name_len + name_len2; - pSMB->hdr.smb_buf_length += count; + inc_rfc1001_len(pSMB, count); pSMB->ByteCount = cpu_to_le16(count); rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, @@ -2474,7 +2482,7 @@ querySymLinkRetry: pSMB->ParameterCount = pSMB->TotalParameterCount; pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_LINK); pSMB->Reserved4 = 0; - pSMB->hdr.smb_buf_length += byte_count; + inc_rfc1001_len(pSMB, byte_count); pSMB->ByteCount = cpu_to_le16(byte_count); rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, @@ -2821,7 +2829,7 @@ queryAclRetry: pSMB->ParameterCount = pSMB->TotalParameterCount; pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_ACL); pSMB->Reserved4 = 0; - pSMB->hdr.smb_buf_length += byte_count; + inc_rfc1001_len(pSMB, byte_count); pSMB->ByteCount = cpu_to_le16(byte_count); rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, @@ -2915,7 +2923,7 @@ setAclRetry: pSMB->ParameterCount = cpu_to_le16(params); pSMB->TotalParameterCount = pSMB->ParameterCount; pSMB->Reserved4 = 0; - pSMB->hdr.smb_buf_length += byte_count; + inc_rfc1001_len(pSMB, byte_count); pSMB->ByteCount = cpu_to_le16(byte_count); rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, (struct smb_hdr *) pSMBr, &bytes_returned, 0); @@ -2973,7 +2981,7 @@ GetExtAttrRetry: pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_ATTR_FLAGS); pSMB->Pad = 0; pSMB->Fid = netfid; - pSMB->hdr.smb_buf_length += byte_count; + inc_rfc1001_len(pSMB, byte_count); pSMB->t2.ByteCount = cpu_to_le16(byte_count); rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, @@ -3131,9 +3139,9 @@ CIFSSMBGetCIFSACL(const int xid, struct cifsTconInfo *tcon, __u16 fid, pSMB->AclFlags = cpu_to_le32(CIFS_ACL_OWNER | CIFS_ACL_GROUP | CIFS_ACL_DACL); pSMB->ByteCount = cpu_to_le16(11); /* 3 bytes pad + 8 bytes parm */ - pSMB->hdr.smb_buf_length += 11; + inc_rfc1001_len(pSMB, 11); iov[0].iov_base = (char *)pSMB; - iov[0].iov_len = pSMB->hdr.smb_buf_length + 4; + iov[0].iov_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 4; rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovec */, &buf_type, 0); @@ -3242,10 +3250,9 @@ setCifsAclRetry: memcpy((char *) &pSMBr->hdr.Protocol + data_offset, (char *) pntsd, acllen); - pSMB->hdr.smb_buf_length += (byte_count + data_count); - + inc_rfc1001_len(pSMB, byte_count + data_count); } else - pSMB->hdr.smb_buf_length += byte_count; + inc_rfc1001_len(pSMB, byte_count); rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, (struct smb_hdr *) pSMBr, &bytes_returned, 0); @@ -3296,7 +3303,7 @@ QInfRetry: } pSMB->BufferFormat = 0x04; name_len++; /* account for buffer type byte */ - pSMB->hdr.smb_buf_length += (__u16) name_len; + inc_rfc1001_len(pSMB, (__u16)name_len); pSMB->ByteCount = cpu_to_le16(name_len); rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, @@ -3371,7 +3378,7 @@ QFileInfoRetry: pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_ALL_INFO); pSMB->Pad = 0; pSMB->Fid = netfid; - pSMB->hdr.smb_buf_length += byte_count; + inc_rfc1001_len(pSMB, byte_count); rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, (struct smb_hdr *) pSMBr, &bytes_returned, 0); @@ -3458,7 +3465,7 @@ QPathInfoRetry: else pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_ALL_INFO); pSMB->Reserved4 = 0; - pSMB->hdr.smb_buf_length += byte_count; + inc_rfc1001_len(pSMB, byte_count); pSMB->ByteCount = cpu_to_le16(byte_count); rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, @@ -3539,7 +3546,7 @@ UnixQFileInfoRetry: pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC); pSMB->Pad = 0; pSMB->Fid = netfid; - pSMB->hdr.smb_buf_length += byte_count; + inc_rfc1001_len(pSMB, byte_count); rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, (struct smb_hdr *) pSMBr, &bytes_returned, 0); @@ -3624,7 +3631,7 @@ UnixQPathInfoRetry: pSMB->ParameterCount = pSMB->TotalParameterCount; pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC); pSMB->Reserved4 = 0; - pSMB->hdr.smb_buf_length += byte_count; + inc_rfc1001_len(pSMB, byte_count); pSMB->ByteCount = cpu_to_le16(byte_count); rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, @@ -3738,7 +3745,7 @@ findFirstRetry: /* BB what should we set StorageType to? Does it matter? BB */ pSMB->SearchStorageType = 0; - pSMB->hdr.smb_buf_length += byte_count; + inc_rfc1001_len(pSMB, byte_count); pSMB->ByteCount = cpu_to_le16(byte_count); rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, @@ -3867,7 +3874,7 @@ int CIFSFindNext(const int xid, struct cifsTconInfo *tcon, byte_count = params + 1 /* pad */ ; pSMB->TotalParameterCount = cpu_to_le16(params); pSMB->ParameterCount = pSMB->TotalParameterCount; - pSMB->hdr.smb_buf_length += byte_count; + inc_rfc1001_len(pSMB, byte_count); pSMB->ByteCount = cpu_to_le16(byte_count); rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, @@ -4029,7 +4036,7 @@ GetInodeNumberRetry: pSMB->ParameterCount = pSMB->TotalParameterCount; pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_INTERNAL_INFO); pSMB->Reserved4 = 0; - pSMB->hdr.smb_buf_length += byte_count; + inc_rfc1001_len(pSMB, byte_count); pSMB->ByteCount = cpu_to_le16(byte_count); rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, @@ -4253,7 +4260,7 @@ getDFSRetry: pSMB->ParameterCount = cpu_to_le16(params); pSMB->TotalParameterCount = pSMB->ParameterCount; pSMB->MaxReferralLevel = cpu_to_le16(3); - pSMB->hdr.smb_buf_length += byte_count; + inc_rfc1001_len(pSMB, byte_count); pSMB->ByteCount = cpu_to_le16(byte_count); rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB, @@ -4327,7 +4334,7 @@ oldQFSInfoRetry: pSMB->Reserved3 = 0; pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION); pSMB->InformationLevel = cpu_to_le16(SMB_INFO_ALLOCATION); - pSMB->hdr.smb_buf_length += byte_count; + inc_rfc1001_len(pSMB, byte_count); pSMB->ByteCount = cpu_to_le16(byte_count); rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, @@ -4406,7 +4413,7 @@ QFSInfoRetry: pSMB->Reserved3 = 0; pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION); pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_SIZE_INFO); - pSMB->hdr.smb_buf_length += byte_count; + inc_rfc1001_len(pSMB, byte_count); pSMB->ByteCount = cpu_to_le16(byte_count); rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, @@ -4486,7 +4493,7 @@ QFSAttributeRetry: pSMB->Reserved3 = 0; pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION); pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_ATTRIBUTE_INFO); - pSMB->hdr.smb_buf_length += byte_count; + inc_rfc1001_len(pSMB, byte_count); pSMB->ByteCount = cpu_to_le16(byte_count); rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, @@ -4557,7 +4564,7 @@ QFSDeviceRetry: pSMB->Reserved3 = 0; pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION); pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_DEVICE_INFO); - pSMB->hdr.smb_buf_length += byte_count; + inc_rfc1001_len(pSMB, byte_count); pSMB->ByteCount = cpu_to_le16(byte_count); rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, @@ -4626,7 +4633,7 @@ QFSUnixRetry: pSMB->Reserved3 = 0; pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION); pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_CIFS_UNIX_INFO); - pSMB->hdr.smb_buf_length += byte_count; + inc_rfc1001_len(pSMB, byte_count); pSMB->ByteCount = cpu_to_le16(byte_count); rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, @@ -4709,7 +4716,7 @@ SETFSUnixRetry: pSMB->ClientUnixMinor = cpu_to_le16(CIFS_UNIX_MINOR_VERSION); pSMB->ClientUnixCap = cpu_to_le64(cap); - pSMB->hdr.smb_buf_length += byte_count; + inc_rfc1001_len(pSMB, byte_count); pSMB->ByteCount = cpu_to_le16(byte_count); rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, @@ -4771,7 +4778,7 @@ QFSPosixRetry: pSMB->Reserved3 = 0; pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION); pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_FS_INFO); - pSMB->hdr.smb_buf_length += byte_count; + inc_rfc1001_len(pSMB, byte_count); pSMB->ByteCount = cpu_to_le16(byte_count); rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, @@ -4897,7 +4904,7 @@ SetEOFRetry: pSMB->ParameterCount = cpu_to_le16(params); pSMB->TotalParameterCount = pSMB->ParameterCount; pSMB->Reserved4 = 0; - pSMB->hdr.smb_buf_length += byte_count; + inc_rfc1001_len(pSMB, byte_count); parm_data->FileSize = cpu_to_le64(size); pSMB->ByteCount = cpu_to_le16(byte_count); rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, @@ -4976,7 +4983,7 @@ CIFSSMBSetFileSize(const int xid, struct cifsTconInfo *tcon, __u64 size, cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO); } pSMB->Reserved4 = 0; - pSMB->hdr.smb_buf_length += byte_count; + inc_rfc1001_len(pSMB, byte_count); pSMB->ByteCount = cpu_to_le16(byte_count); rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0); if (rc) { @@ -5044,7 +5051,7 @@ CIFSSMBSetFileInfo(const int xid, struct cifsTconInfo *tcon, else pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO); pSMB->Reserved4 = 0; - pSMB->hdr.smb_buf_length += byte_count; + inc_rfc1001_len(pSMB, byte_count); pSMB->ByteCount = cpu_to_le16(byte_count); memcpy(data_offset, data, sizeof(FILE_BASIC_INFO)); rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0); @@ -5103,7 +5110,7 @@ CIFSSMBSetFileDisposition(const int xid, struct cifsTconInfo *tcon, pSMB->Fid = fid; pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_DISPOSITION_INFO); pSMB->Reserved4 = 0; - pSMB->hdr.smb_buf_length += byte_count; + inc_rfc1001_len(pSMB, byte_count); pSMB->ByteCount = cpu_to_le16(byte_count); *data_offset = delete_file ? 1 : 0; rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0); @@ -5176,7 +5183,7 @@ SetTimesRetry: else pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO); pSMB->Reserved4 = 0; - pSMB->hdr.smb_buf_length += byte_count; + inc_rfc1001_len(pSMB, byte_count); memcpy(data_offset, data, sizeof(FILE_BASIC_INFO)); pSMB->ByteCount = cpu_to_le16(byte_count); rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, @@ -5228,7 +5235,7 @@ SetAttrLgcyRetry: } pSMB->attr = cpu_to_le16(dos_attrs); pSMB->BufferFormat = 0x04; - pSMB->hdr.smb_buf_length += name_len + 1; + inc_rfc1001_len(pSMB, name_len + 1); pSMB->ByteCount = cpu_to_le16(name_len + 1); rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, (struct smb_hdr *) pSMBr, &bytes_returned, 0); @@ -5333,7 +5340,7 @@ CIFSSMBUnixSetFileInfo(const int xid, struct cifsTconInfo *tcon, pSMB->Fid = fid; pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_BASIC); pSMB->Reserved4 = 0; - pSMB->hdr.smb_buf_length += byte_count; + inc_rfc1001_len(pSMB, byte_count); pSMB->ByteCount = cpu_to_le16(byte_count); cifs_fill_unix_set_info(data_offset, args); @@ -5409,7 +5416,7 @@ setPermsRetry: pSMB->TotalDataCount = pSMB->DataCount; pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_BASIC); pSMB->Reserved4 = 0; - pSMB->hdr.smb_buf_length += byte_count; + inc_rfc1001_len(pSMB, byte_count); cifs_fill_unix_set_info(data_offset, args); @@ -5494,7 +5501,7 @@ QAllEAsRetry: pSMB->ParameterCount = pSMB->TotalParameterCount; pSMB->InformationLevel = cpu_to_le16(SMB_INFO_QUERY_ALL_EAS); pSMB->Reserved4 = 0; - pSMB->hdr.smb_buf_length += byte_count; + inc_rfc1001_len(pSMB, byte_count); pSMB->ByteCount = cpu_to_le16(byte_count); rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, @@ -5707,7 +5714,7 @@ SetEARetry: pSMB->ParameterCount = cpu_to_le16(params); pSMB->TotalParameterCount = pSMB->ParameterCount; pSMB->Reserved4 = 0; - pSMB->hdr.smb_buf_length += byte_count; + inc_rfc1001_len(pSMB, byte_count); pSMB->ByteCount = cpu_to_le16(byte_count); rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, (struct smb_hdr *) pSMBr, &bytes_returned, 0); diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index acd1e3c..5d331cd 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c @@ -324,12 +324,12 @@ static int coalesce_t2(struct smb_hdr *psecond, struct smb_hdr *pTargetSMB) return -EPROTO; put_bcc_le(byte_count, pTargetSMB); - byte_count = pTargetSMB->smb_buf_length; + byte_count = be32_to_cpu(pTargetSMB->smb_buf_length); byte_count += total_in_buf2; /* don't allow buffer to overflow */ if (byte_count > CIFSMaxBufSize) return -ENOBUFS; - pTargetSMB->smb_buf_length = byte_count; + pTargetSMB->smb_buf_length = cpu_to_be32(byte_count); memcpy(data_area_of_target, data_area_of_buf2, total_in_buf2); @@ -496,8 +496,7 @@ incomplete_rcv: /* Note that FC 1001 length is big endian on the wire, but we convert it here so it is always manipulated as host byte order */ - pdu_length = be32_to_cpu((__force __be32)smb_buffer->smb_buf_length); - smb_buffer->smb_buf_length = pdu_length; + pdu_length = be32_to_cpu(smb_buffer->smb_buf_length); cFYI(1, "rfc1002 length 0x%x", pdu_length+4); @@ -2297,7 +2296,7 @@ ip_rfc1001_connect(struct TCP_Server_Info *server) smb_buf = (struct smb_hdr *)ses_init_buf; /* sizeof RFC1002_SESSION_REQUEST with no scope */ - smb_buf->smb_buf_length = 0x81000044; + smb_buf->smb_buf_length = cpu_to_be32(0x81000044); rc = smb_send(server, smb_buf, 0x44); kfree(ses_init_buf); /* @@ -3100,7 +3099,8 @@ CIFSTCon(unsigned int xid, struct cifsSesInfo *ses, bcc_ptr += strlen("?????"); bcc_ptr += 1; count = bcc_ptr - &pSMB->Password[0]; - pSMB->hdr.smb_buf_length += count; + pSMB->hdr.smb_buf_length = cpu_to_be32(be32_to_cpu( + pSMB->hdr.smb_buf_length) + count); pSMB->ByteCount = cpu_to_le16(count); rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response, &length, diff --git a/fs/cifs/misc.c b/fs/cifs/misc.c index 0c684ae..533f863 100644 --- a/fs/cifs/misc.c +++ b/fs/cifs/misc.c @@ -304,12 +304,10 @@ header_assemble(struct smb_hdr *buffer, char smb_command /* command */ , memset(temp, 0, 256); /* bigger than MAX_CIFS_HDR_SIZE */ - buffer->smb_buf_length = + buffer->smb_buf_length = cpu_to_be32( (2 * word_count) + sizeof(struct smb_hdr) - 4 /* RFC 1001 length field does not count */ + - 2 /* for bcc field itself */ ; - /* Note that this is the only network field that has to be converted - to big endian and it is done just before we send it */ + 2 /* for bcc field itself */) ; buffer->Protocol[0] = 0xFF; buffer->Protocol[1] = 'S'; @@ -424,7 +422,7 @@ check_smb_hdr(struct smb_hdr *smb, __u16 mid) int checkSMB(struct smb_hdr *smb, __u16 mid, unsigned int length) { - __u32 len = smb->smb_buf_length; + __u32 len = be32_to_cpu(smb->smb_buf_length); __u32 clc_len; /* calculated length */ cFYI(0, "checkSMB Length: 0x%x, smb_buf_length: 0x%x", length, len); diff --git a/fs/cifs/sess.c b/fs/cifs/sess.c index b6ff84a..1daadad 100644 --- a/fs/cifs/sess.c +++ b/fs/cifs/sess.c @@ -621,7 +621,7 @@ ssetup_ntlmssp_authenticate: and rest of bcc area. This allows us to avoid a large buffer 17K allocation */ iov[0].iov_base = (char *)pSMB; - iov[0].iov_len = smb_buf->smb_buf_length + 4; + iov[0].iov_len = be32_to_cpu(smb_buf->smb_buf_length) + 4; /* setting this here allows the code at the end of the function to free the request buffer if there's an error */ @@ -859,7 +859,8 @@ ssetup_ntlmssp_authenticate: iov[2].iov_len = (long) bcc_ptr - (long) str_area; count = iov[1].iov_len + iov[2].iov_len; - smb_buf->smb_buf_length += count; + smb_buf->smb_buf_length = + cpu_to_be32(be32_to_cpu(smb_buf->smb_buf_length) + count); put_bcc_le(count, smb_buf); diff --git a/fs/cifs/transport.c b/fs/cifs/transport.c index 46d8756f..19df0e5 100644 --- a/fs/cifs/transport.c +++ b/fs/cifs/transport.c @@ -129,7 +129,7 @@ smb_sendv(struct TCP_Server_Info *server, struct kvec *iov, int n_vec) unsigned int len = iov[0].iov_len; unsigned int total_len; int first_vec = 0; - unsigned int smb_buf_length = smb_buffer->smb_buf_length; + unsigned int smb_buf_length = be32_to_cpu(smb_buffer->smb_buf_length); struct socket *ssocket = server->ssocket; if (ssocket == NULL) @@ -144,17 +144,10 @@ smb_sendv(struct TCP_Server_Info *server, struct kvec *iov, int n_vec) else smb_msg.msg_flags = MSG_NOSIGNAL; - /* smb header is converted in header_assemble. bcc and rest of SMB word - area, and byte area if necessary, is converted to littleendian in - cifssmb.c and RFC1001 len is converted to bigendian in smb_send - Flags2 is converted in SendReceive */ - - total_len = 0; for (i = 0; i < n_vec; i++) total_len += iov[i].iov_len; - smb_buffer->smb_buf_length = cpu_to_be32(smb_buffer->smb_buf_length); cFYI(1, "Sending smb: total_len %d", total_len); dump_smb(smb_buffer, len); @@ -243,7 +236,7 @@ smb_sendv(struct TCP_Server_Info *server, struct kvec *iov, int n_vec) /* Don't want to modify the buffer as a side effect of this call. */ - smb_buffer->smb_buf_length = smb_buf_length; + smb_buffer->smb_buf_length = cpu_to_be32(smb_buf_length); return rc; } @@ -387,7 +380,7 @@ cifs_call_async(struct TCP_Server_Info *server, struct smb_hdr *in_buf, #ifdef CONFIG_CIFS_STATS2 atomic_inc(&server->inSend); #endif - rc = smb_send(server, in_buf, in_buf->smb_buf_length); + rc = smb_send(server, in_buf, be32_to_cpu(in_buf->smb_buf_length)); #ifdef CONFIG_CIFS_STATS2 atomic_dec(&server->inSend); mid->when_sent = jiffies; @@ -422,7 +415,7 @@ SendReceiveNoRsp(const unsigned int xid, struct cifsSesInfo *ses, int resp_buf_type; iov[0].iov_base = (char *)in_buf; - iov[0].iov_len = in_buf->smb_buf_length + 4; + iov[0].iov_len = be32_to_cpu(in_buf->smb_buf_length) + 4; flags |= CIFS_NO_RESP; rc = SendReceive2(xid, ses, iov, 1, &resp_buf_type, flags); cFYI(DBG2, "SendRcvNoRsp flags %d rc %d", flags, rc); @@ -488,7 +481,7 @@ send_nt_cancel(struct TCP_Server_Info *server, struct smb_hdr *in_buf, int rc = 0; /* -4 for RFC1001 length and +2 for BCC field */ - in_buf->smb_buf_length = sizeof(struct smb_hdr) - 4 + 2; + in_buf->smb_buf_length = cpu_to_be32(sizeof(struct smb_hdr) - 4 + 2); in_buf->Command = SMB_COM_NT_CANCEL; in_buf->WordCount = 0; put_bcc_le(0, in_buf); @@ -499,7 +492,7 @@ send_nt_cancel(struct TCP_Server_Info *server, struct smb_hdr *in_buf, mutex_unlock(&server->srv_mutex); return rc; } - rc = smb_send(server, in_buf, in_buf->smb_buf_length); + rc = smb_send(server, in_buf, be32_to_cpu(in_buf->smb_buf_length)); mutex_unlock(&server->srv_mutex); cFYI(1, "issued NT_CANCEL for mid %u, rc = %d", @@ -612,7 +605,7 @@ SendReceive2(const unsigned int xid, struct cifsSesInfo *ses, return rc; } - receive_len = midQ->resp_buf->smb_buf_length; + receive_len = be32_to_cpu(midQ->resp_buf->smb_buf_length); if (receive_len > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE) { cERROR(1, "Frame too large received. Length: %d Xid: %d", @@ -698,9 +691,10 @@ SendReceive(const unsigned int xid, struct cifsSesInfo *ses, to the same server. We may make this configurable later or use ses->maxReq */ - if (in_buf->smb_buf_length > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE - 4) { + if (be32_to_cpu(in_buf->smb_buf_length) > CIFSMaxBufSize + + MAX_CIFS_HDR_SIZE - 4) { cERROR(1, "Illegal length, greater than maximum frame, %d", - in_buf->smb_buf_length); + be32_to_cpu(in_buf->smb_buf_length)); return -EIO; } @@ -733,7 +727,7 @@ SendReceive(const unsigned int xid, struct cifsSesInfo *ses, #ifdef CONFIG_CIFS_STATS2 atomic_inc(&ses->server->inSend); #endif - rc = smb_send(ses->server, in_buf, in_buf->smb_buf_length); + rc = smb_send(ses->server, in_buf, be32_to_cpu(in_buf->smb_buf_length)); #ifdef CONFIG_CIFS_STATS2 atomic_dec(&ses->server->inSend); midQ->when_sent = jiffies; @@ -768,7 +762,7 @@ SendReceive(const unsigned int xid, struct cifsSesInfo *ses, return rc; } - receive_len = midQ->resp_buf->smb_buf_length; + receive_len = be32_to_cpu(midQ->resp_buf->smb_buf_length); if (receive_len > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE) { cERROR(1, "Frame too large received. Length: %d Xid: %d", @@ -781,7 +775,7 @@ SendReceive(const unsigned int xid, struct cifsSesInfo *ses, if (midQ->resp_buf && out_buf && (midQ->midState == MID_RESPONSE_RECEIVED)) { - out_buf->smb_buf_length = receive_len; + out_buf->smb_buf_length = cpu_to_be32(receive_len); memcpy((char *)out_buf + 4, (char *)midQ->resp_buf + 4, receive_len); @@ -800,7 +794,7 @@ SendReceive(const unsigned int xid, struct cifsSesInfo *ses, } } - *pbytes_returned = out_buf->smb_buf_length; + *pbytes_returned = be32_to_cpu(out_buf->smb_buf_length); /* BB special case reconnect tid and uid here? */ rc = map_smb_to_linux_error(out_buf, 0 /* no log */ ); @@ -877,9 +871,10 @@ SendReceiveBlockingLock(const unsigned int xid, struct cifsTconInfo *tcon, to the same server. We may make this configurable later or use ses->maxReq */ - if (in_buf->smb_buf_length > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE - 4) { + if (be32_to_cpu(in_buf->smb_buf_length) > CIFSMaxBufSize + + MAX_CIFS_HDR_SIZE - 4) { cERROR(1, "Illegal length, greater than maximum frame, %d", - in_buf->smb_buf_length); + be32_to_cpu(in_buf->smb_buf_length)); return -EIO; } @@ -910,7 +905,7 @@ SendReceiveBlockingLock(const unsigned int xid, struct cifsTconInfo *tcon, #ifdef CONFIG_CIFS_STATS2 atomic_inc(&ses->server->inSend); #endif - rc = smb_send(ses->server, in_buf, in_buf->smb_buf_length); + rc = smb_send(ses->server, in_buf, be32_to_cpu(in_buf->smb_buf_length)); #ifdef CONFIG_CIFS_STATS2 atomic_dec(&ses->server->inSend); midQ->when_sent = jiffies; @@ -977,7 +972,7 @@ SendReceiveBlockingLock(const unsigned int xid, struct cifsTconInfo *tcon, if (rc != 0) return rc; - receive_len = midQ->resp_buf->smb_buf_length; + receive_len = be32_to_cpu(midQ->resp_buf->smb_buf_length); if (receive_len > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE) { cERROR(1, "Frame too large received. Length: %d Xid: %d", receive_len, xid); @@ -993,7 +988,7 @@ SendReceiveBlockingLock(const unsigned int xid, struct cifsTconInfo *tcon, goto out; } - out_buf->smb_buf_length = receive_len; + out_buf->smb_buf_length = cpu_to_be32(receive_len); memcpy((char *)out_buf + 4, (char *)midQ->resp_buf + 4, receive_len); @@ -1012,7 +1007,7 @@ SendReceiveBlockingLock(const unsigned int xid, struct cifsTconInfo *tcon, } } - *pbytes_returned = out_buf->smb_buf_length; + *pbytes_returned = be32_to_cpu(out_buf->smb_buf_length); /* BB special case reconnect tid and uid here? */ rc = map_smb_to_linux_error(out_buf, 0 /* no log */ ); -- cgit v0.10.2 From 0b81c1c405c063f3ecea66c2f5e9c3aefc5359c8 Mon Sep 17 00:00:00 2001 From: Pavel Shilovsky Date: Thu, 10 Mar 2011 10:11:05 +0300 Subject: CIFS: directio read/write cleanups Recently introduced strictcache mode brought a new code that can be efficiently used by directio part. That's let us add vectored operations and break unnecessary cifs_user_read and cifs_user_write. Signed-off-by: Pavel Shilovsky Reviewed-by: Jeff Layton Signed-off-by: Steve French diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c index 6c1d738..f736d8a 100644 --- a/fs/cifs/cifsfs.c +++ b/fs/cifs/cifsfs.c @@ -760,10 +760,11 @@ const struct file_operations cifs_file_strict_ops = { }; const struct file_operations cifs_file_direct_ops = { - /* no aio, no readv - - BB reevaluate whether they can be done with directio, no cache */ - .read = cifs_user_read, - .write = cifs_user_write, + /* BB reevaluate whether they can be done with directio, no cache */ + .read = do_sync_read, + .write = do_sync_write, + .aio_read = cifs_user_readv, + .aio_write = cifs_user_writev, .open = cifs_open, .release = cifs_close, .lock = cifs_lock, @@ -815,10 +816,11 @@ const struct file_operations cifs_file_strict_nobrl_ops = { }; const struct file_operations cifs_file_direct_nobrl_ops = { - /* no mmap, no aio, no readv - - BB reevaluate whether they can be done with directio, no cache */ - .read = cifs_user_read, - .write = cifs_user_write, + /* BB reevaluate whether they can be done with directio, no cache */ + .read = do_sync_read, + .write = do_sync_write, + .aio_read = cifs_user_readv, + .aio_write = cifs_user_writev, .open = cifs_open, .release = cifs_close, .fsync = cifs_fsync, diff --git a/fs/cifs/cifsfs.h b/fs/cifs/cifsfs.h index 371d021..bb64313 100644 --- a/fs/cifs/cifsfs.h +++ b/fs/cifs/cifsfs.h @@ -80,12 +80,12 @@ extern const struct file_operations cifs_file_strict_nobrl_ops; extern int cifs_open(struct inode *inode, struct file *file); extern int cifs_close(struct inode *inode, struct file *file); extern int cifs_closedir(struct inode *inode, struct file *file); -extern ssize_t cifs_user_read(struct file *file, char __user *read_data, - size_t read_size, loff_t *poffset); +extern ssize_t cifs_user_readv(struct kiocb *iocb, const struct iovec *iov, + unsigned long nr_segs, loff_t pos); extern ssize_t cifs_strict_readv(struct kiocb *iocb, const struct iovec *iov, unsigned long nr_segs, loff_t pos); -extern ssize_t cifs_user_write(struct file *file, const char __user *write_data, - size_t write_size, loff_t *poffset); +extern ssize_t cifs_user_writev(struct kiocb *iocb, const struct iovec *iov, + unsigned long nr_segs, loff_t pos); extern ssize_t cifs_strict_writev(struct kiocb *iocb, const struct iovec *iov, unsigned long nr_segs, loff_t pos); extern int cifs_lock(struct file *, int, struct file_lock *); diff --git a/fs/cifs/file.c b/fs/cifs/file.c index 00b466e..0aeaaf7 100644 --- a/fs/cifs/file.c +++ b/fs/cifs/file.c @@ -857,95 +857,6 @@ cifs_update_eof(struct cifsInodeInfo *cifsi, loff_t offset, cifsi->server_eof = end_of_write; } -ssize_t cifs_user_write(struct file *file, const char __user *write_data, - size_t write_size, loff_t *poffset) -{ - struct inode *inode = file->f_path.dentry->d_inode; - int rc = 0; - unsigned int bytes_written = 0; - unsigned int total_written; - struct cifs_sb_info *cifs_sb; - struct cifsTconInfo *pTcon; - int xid; - struct cifsFileInfo *open_file; - struct cifsInodeInfo *cifsi = CIFS_I(inode); - - cifs_sb = CIFS_SB(file->f_path.dentry->d_sb); - - /* cFYI(1, " write %d bytes to offset %lld of %s", write_size, - *poffset, file->f_path.dentry->d_name.name); */ - - if (file->private_data == NULL) - return -EBADF; - - open_file = file->private_data; - pTcon = tlink_tcon(open_file->tlink); - - rc = generic_write_checks(file, poffset, &write_size, 0); - if (rc) - return rc; - - xid = GetXid(); - - for (total_written = 0; write_size > total_written; - total_written += bytes_written) { - rc = -EAGAIN; - while (rc == -EAGAIN) { - if (file->private_data == NULL) { - /* file has been closed on us */ - FreeXid(xid); - /* if we have gotten here we have written some data - and blocked, and the file has been freed on us while - we blocked so return what we managed to write */ - return total_written; - } - if (open_file->invalidHandle) { - /* we could deadlock if we called - filemap_fdatawait from here so tell - reopen_file not to flush data to server - now */ - rc = cifs_reopen_file(open_file, false); - if (rc != 0) - break; - } - - rc = CIFSSMBWrite(xid, pTcon, - open_file->netfid, - min_t(const int, cifs_sb->wsize, - write_size - total_written), - *poffset, &bytes_written, - NULL, write_data + total_written, 0); - } - if (rc || (bytes_written == 0)) { - if (total_written) - break; - else { - FreeXid(xid); - return rc; - } - } else { - cifs_update_eof(cifsi, *poffset, bytes_written); - *poffset += bytes_written; - } - } - - cifs_stats_bytes_written(pTcon, total_written); - -/* Do not update local mtime - server will set its actual value on write - * inode->i_ctime = inode->i_mtime = - * current_fs_time(inode->i_sb);*/ - if (total_written > 0) { - spin_lock(&inode->i_lock); - if (*poffset > inode->i_size) - i_size_write(inode, *poffset); - spin_unlock(&inode->i_lock); - } - mark_inode_dirty_sync(inode); - - FreeXid(xid); - return total_written; -} - static ssize_t cifs_write(struct cifsFileInfo *open_file, const char *write_data, size_t write_size, loff_t *poffset) @@ -1741,7 +1652,7 @@ cifs_iovec_write(struct file *file, const struct iovec *iov, return total_written; } -static ssize_t cifs_user_writev(struct kiocb *iocb, const struct iovec *iov, +ssize_t cifs_user_writev(struct kiocb *iocb, const struct iovec *iov, unsigned long nr_segs, loff_t pos) { ssize_t written; @@ -1864,17 +1775,7 @@ cifs_iovec_read(struct file *file, const struct iovec *iov, return total_read; } -ssize_t cifs_user_read(struct file *file, char __user *read_data, - size_t read_size, loff_t *poffset) -{ - struct iovec iov; - iov.iov_base = read_data; - iov.iov_len = read_size; - - return cifs_iovec_read(file, &iov, 1, poffset); -} - -static ssize_t cifs_user_readv(struct kiocb *iocb, const struct iovec *iov, +ssize_t cifs_user_readv(struct kiocb *iocb, const struct iovec *iov, unsigned long nr_segs, loff_t pos) { ssize_t read; -- cgit v0.10.2 From 6feb9891da4f8b04ffca69c00eb56bb7c1b64dc4 Mon Sep 17 00:00:00 2001 From: Pavel Shilovsky Date: Thu, 7 Apr 2011 18:18:11 +0400 Subject: CIFS: Simplify invalidate part (try #5) Simplify many places when we call cifs_revalidate/invalidate to make it do what it exactly needs. Reviewed-by: Jeff Layton Signed-off-by: Pavel Shilovsky Signed-off-by: Steve French diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c index f736d8a..0f6a54f 100644 --- a/fs/cifs/cifsfs.c +++ b/fs/cifs/cifsfs.c @@ -618,16 +618,29 @@ static loff_t cifs_llseek(struct file *file, loff_t offset, int origin) { /* origin == SEEK_END => we must revalidate the cached file length */ if (origin == SEEK_END) { - int retval; - - /* some applications poll for the file length in this strange - way so we must seek to end on non-oplocked files by - setting the revalidate time to zero */ - CIFS_I(file->f_path.dentry->d_inode)->time = 0; - - retval = cifs_revalidate_file(file); - if (retval < 0) - return (loff_t)retval; + int rc; + struct inode *inode = file->f_path.dentry->d_inode; + + /* + * We need to be sure that all dirty pages are written and the + * server has the newest file length. + */ + if (!CIFS_I(inode)->clientCanCacheRead && inode->i_mapping && + inode->i_mapping->nrpages != 0) { + rc = filemap_fdatawait(inode->i_mapping); + mapping_set_error(inode->i_mapping, rc); + return rc; + } + /* + * Some applications poll for the file length in this strange + * way so we must seek to end on non-oplocked files by + * setting the revalidate time to zero. + */ + CIFS_I(inode)->time = 0; + + rc = cifs_revalidate_file_attr(file); + if (rc < 0) + return (loff_t)rc; } return generic_file_llseek_unlocked(file, offset, origin); } diff --git a/fs/cifs/cifsfs.h b/fs/cifs/cifsfs.h index bb64313..d304584 100644 --- a/fs/cifs/cifsfs.h +++ b/fs/cifs/cifsfs.h @@ -59,9 +59,11 @@ extern int cifs_mkdir(struct inode *, struct dentry *, int); extern int cifs_rmdir(struct inode *, struct dentry *); extern int cifs_rename(struct inode *, struct dentry *, struct inode *, struct dentry *); +extern int cifs_revalidate_file_attr(struct file *filp); +extern int cifs_revalidate_dentry_attr(struct dentry *); extern int cifs_revalidate_file(struct file *filp); extern int cifs_revalidate_dentry(struct dentry *); -extern void cifs_invalidate_mapping(struct inode *inode); +extern int cifs_invalidate_mapping(struct inode *inode); extern int cifs_getattr(struct vfsmount *, struct dentry *, struct kstat *); extern int cifs_setattr(struct dentry *, struct iattr *); diff --git a/fs/cifs/file.c b/fs/cifs/file.c index 0aeaaf7..c672afe 100644 --- a/fs/cifs/file.c +++ b/fs/cifs/file.c @@ -1445,8 +1445,13 @@ int cifs_strict_fsync(struct file *file, int datasync) cFYI(1, "Sync file - name: %s datasync: 0x%x", file->f_path.dentry->d_name.name, datasync); - if (!CIFS_I(inode)->clientCanCacheRead) - cifs_invalidate_mapping(inode); + if (!CIFS_I(inode)->clientCanCacheRead) { + rc = cifs_invalidate_mapping(inode); + if (rc) { + cFYI(1, "rc: %d during invalidate phase", rc); + rc = 0; /* don't care about it in fsync */ + } + } tcon = tlink_tcon(smbfile->tlink); if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NOSSYNC)) @@ -1903,8 +1908,11 @@ int cifs_file_strict_mmap(struct file *file, struct vm_area_struct *vma) xid = GetXid(); - if (!CIFS_I(inode)->clientCanCacheRead) - cifs_invalidate_mapping(inode); + if (!CIFS_I(inode)->clientCanCacheRead) { + rc = cifs_invalidate_mapping(inode); + if (rc) + return rc; + } rc = generic_file_mmap(file, vma); if (rc == 0) diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c index fbe7d58..0cc7edd 100644 --- a/fs/cifs/inode.c +++ b/fs/cifs/inode.c @@ -1683,18 +1683,15 @@ cifs_inode_needs_reval(struct inode *inode) /* * Zap the cache. Called when invalid_mapping flag is set. */ -void +int cifs_invalidate_mapping(struct inode *inode) { - int rc; + int rc = 0; struct cifsInodeInfo *cifs_i = CIFS_I(inode); cifs_i->invalid_mapping = false; if (inode->i_mapping && inode->i_mapping->nrpages != 0) { - /* write back any cached data */ - rc = filemap_write_and_wait(inode->i_mapping); - mapping_set_error(inode->i_mapping, rc); rc = invalidate_inode_pages2(inode->i_mapping); if (rc) { cERROR(1, "%s: could not invalidate inode %p", __func__, @@ -1704,56 +1701,52 @@ cifs_invalidate_mapping(struct inode *inode) } cifs_fscache_reset_inode_cookie(inode); + return rc; } -int cifs_revalidate_file(struct file *filp) +int cifs_revalidate_file_attr(struct file *filp) { int rc = 0; struct inode *inode = filp->f_path.dentry->d_inode; struct cifsFileInfo *cfile = (struct cifsFileInfo *) filp->private_data; if (!cifs_inode_needs_reval(inode)) - goto check_inval; + return rc; if (tlink_tcon(cfile->tlink)->unix_ext) rc = cifs_get_file_info_unix(filp); else rc = cifs_get_file_info(filp); -check_inval: - if (CIFS_I(inode)->invalid_mapping) - cifs_invalidate_mapping(inode); - return rc; } -/* revalidate a dentry's inode attributes */ -int cifs_revalidate_dentry(struct dentry *dentry) +int cifs_revalidate_dentry_attr(struct dentry *dentry) { int xid; int rc = 0; - char *full_path = NULL; struct inode *inode = dentry->d_inode; struct super_block *sb = dentry->d_sb; + char *full_path = NULL; if (inode == NULL) return -ENOENT; - xid = GetXid(); - if (!cifs_inode_needs_reval(inode)) - goto check_inval; + return rc; + + xid = GetXid(); /* can not safely grab the rename sem here if rename calls revalidate since that would deadlock */ full_path = build_path_from_dentry(dentry); if (full_path == NULL) { rc = -ENOMEM; - goto check_inval; + goto out; } - cFYI(1, "Revalidate: %s inode 0x%p count %d dentry: 0x%p d_time %ld " - "jiffies %ld", full_path, inode, inode->i_count.counter, + cFYI(1, "Update attributes: %s inode 0x%p count %d dentry: 0x%p d_time " + "%ld jiffies %ld", full_path, inode, inode->i_count.counter, dentry, dentry->d_time, jiffies); if (cifs_sb_master_tcon(CIFS_SB(sb))->unix_ext) @@ -1762,41 +1755,81 @@ int cifs_revalidate_dentry(struct dentry *dentry) rc = cifs_get_inode_info(&inode, full_path, NULL, sb, xid, NULL); -check_inval: - if (CIFS_I(inode)->invalid_mapping) - cifs_invalidate_mapping(inode); - +out: kfree(full_path); FreeXid(xid); return rc; } +int cifs_revalidate_file(struct file *filp) +{ + int rc; + struct inode *inode = filp->f_path.dentry->d_inode; + + rc = cifs_revalidate_file_attr(filp); + if (rc) + return rc; + + if (CIFS_I(inode)->invalid_mapping) + rc = cifs_invalidate_mapping(inode); + return rc; +} + +/* revalidate a dentry's inode attributes */ +int cifs_revalidate_dentry(struct dentry *dentry) +{ + int rc; + struct inode *inode = dentry->d_inode; + + rc = cifs_revalidate_dentry_attr(dentry); + if (rc) + return rc; + + if (CIFS_I(inode)->invalid_mapping) + rc = cifs_invalidate_mapping(inode); + return rc; +} + int cifs_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat) { struct cifs_sb_info *cifs_sb = CIFS_SB(dentry->d_sb); struct cifsTconInfo *tcon = cifs_sb_master_tcon(cifs_sb); - int err = cifs_revalidate_dentry(dentry); + struct inode *inode = dentry->d_inode; + int rc; - if (!err) { - generic_fillattr(dentry->d_inode, stat); - stat->blksize = CIFS_MAX_MSGSIZE; - stat->ino = CIFS_I(dentry->d_inode)->uniqueid; + /* + * We need to be sure that all dirty pages are written and the server + * has actual ctime, mtime and file length. + */ + if (!CIFS_I(inode)->clientCanCacheRead && inode->i_mapping && + inode->i_mapping->nrpages != 0) { + rc = filemap_fdatawait(inode->i_mapping); + mapping_set_error(inode->i_mapping, rc); + return rc; + } - /* - * If on a multiuser mount without unix extensions, and the - * admin hasn't overridden them, set the ownership to the - * fsuid/fsgid of the current process. - */ - if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MULTIUSER) && - !tcon->unix_ext) { - if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_OVERR_UID)) - stat->uid = current_fsuid(); - if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_OVERR_GID)) - stat->gid = current_fsgid(); - } + rc = cifs_revalidate_dentry_attr(dentry); + if (rc) + return rc; + + generic_fillattr(inode, stat); + stat->blksize = CIFS_MAX_MSGSIZE; + stat->ino = CIFS_I(inode)->uniqueid; + + /* + * If on a multiuser mount without unix extensions, and the admin hasn't + * overridden them, set the ownership to the fsuid/fsgid of the current + * process. + */ + if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MULTIUSER) && + !tcon->unix_ext) { + if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_OVERR_UID)) + stat->uid = current_fsuid(); + if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_OVERR_GID)) + stat->gid = current_fsgid(); } - return err; + return rc; } static int cifs_truncate_page(struct address_space *mapping, loff_t from) -- cgit v0.10.2 From 0e6e37a7a81f370d9aafafdf88aca13977f6fb5f Mon Sep 17 00:00:00 2001 From: Jeff Layton Date: Wed, 4 May 2011 08:08:19 -0400 Subject: cifs: fix some unused variable warnings in id_rb_search MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit fs/cifs/cifsacl.c: In function ‘id_rb_search’: fs/cifs/cifsacl.c:215:19: warning: variable ‘linkto’ set but not used [-Wunused-but-set-variable] fs/cifs/cifsacl.c:214:18: warning: variable ‘parent’ set but not used [-Wunused-but-set-variable] Reviewed-by: Shirish Pargaonkar Signed-off-by: Jeff Layton Signed-off-by: Steve French diff --git a/fs/cifs/cifsacl.c b/fs/cifs/cifsacl.c index a4aa0f0..bfb5ba5 100644 --- a/fs/cifs/cifsacl.c +++ b/fs/cifs/cifsacl.c @@ -211,19 +211,14 @@ id_rb_search(struct rb_root *root, struct cifs_sid *sidptr) { int rc; struct rb_node *node = root->rb_node; - struct rb_node *parent = NULL; - struct rb_node **linkto = &(root->rb_node); struct cifs_sid_id *lsidid; while (node) { lsidid = rb_entry(node, struct cifs_sid_id, rbnode); - parent = node; rc = compare_sids(sidptr, &((lsidid)->sid)); if (rc > 0) { - linkto = &(node->rb_left); node = node->rb_left; } else if (rc < 0) { - linkto = &(node->rb_right); node = node->rb_right; } else /* node found */ return lsidid; -- cgit v0.10.2 From 820a803ffac3ef591e597bc107f8e289a823a29c Mon Sep 17 00:00:00 2001 From: Jeff Layton Date: Wed, 4 May 2011 08:05:26 -0400 Subject: cifs: keep BCC in little-endian format This is the same patch as originally posted, just with some merge conflicts fixed up... Currently, the ByteCount is usually converted to host-endian on receive. This is confusing however, as we need to keep two sets of routines for accessing it, and keep track of when to use each routine. Munging received packets like this also limits when the signature can be calulated. Simplify the code by keeping the received ByteCount in little-endian format. This allows us to eliminate a set of routines for accessing it and we can now drop the *_le suffixes from the accessor functions since that's now implied. While we're at it, switch all of the places that read the ByteCount directly to use the get_bcc inline which should also clean up some unaligned accesses. Signed-off-by: Jeff Layton Signed-off-by: Steve French diff --git a/fs/cifs/cifs_debug.c b/fs/cifs/cifs_debug.c index 30d01bc..18f4272 100644 --- a/fs/cifs/cifs_debug.c +++ b/fs/cifs/cifs_debug.c @@ -63,7 +63,7 @@ void cifs_dump_detail(struct smb_hdr *smb) cERROR(1, "Cmd: %d Err: 0x%x Flags: 0x%x Flgs2: 0x%x Mid: %d Pid: %d", smb->Command, smb->Status.CifsError, smb->Flags, smb->Flags2, smb->Mid, smb->Pid); - cERROR(1, "smb buf %p len %d", smb, smbCalcSize_LE(smb)); + cERROR(1, "smb buf %p len %d", smb, smbCalcSize(smb)); } diff --git a/fs/cifs/cifspdu.h b/fs/cifs/cifspdu.h index eac95e2..291d735 100644 --- a/fs/cifs/cifspdu.h +++ b/fs/cifs/cifspdu.h @@ -435,36 +435,18 @@ struct smb_hdr { /* given a pointer to an smb_hdr retrieve the pointer to the byte area */ #define pByteArea(smb_var) (BCC(smb_var) + 2) -/* get the converted ByteCount for a SMB packet and return it */ -static inline __u16 -get_bcc(struct smb_hdr *hdr) -{ - __u16 *bc_ptr = (__u16 *)BCC(hdr); - - return get_unaligned(bc_ptr); -} - /* get the unconverted ByteCount for a SMB packet and return it */ static inline __u16 -get_bcc_le(struct smb_hdr *hdr) +get_bcc(struct smb_hdr *hdr) { __le16 *bc_ptr = (__le16 *)BCC(hdr); return get_unaligned_le16(bc_ptr); } -/* set the ByteCount for a SMB packet in host-byte order */ -static inline void -put_bcc(__u16 count, struct smb_hdr *hdr) -{ - __u16 *bc_ptr = (__u16 *)BCC(hdr); - - put_unaligned(count, bc_ptr); -} - /* set the ByteCount for a SMB packet in little-endian */ static inline void -put_bcc_le(__u16 count, struct smb_hdr *hdr) +put_bcc(__u16 count, struct smb_hdr *hdr) { __le16 *bc_ptr = (__le16 *)BCC(hdr); diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h index 7c1ed01..136d2f2 100644 --- a/fs/cifs/cifsproto.h +++ b/fs/cifs/cifsproto.h @@ -93,7 +93,6 @@ extern void cifs_update_eof(struct cifsInodeInfo *cifsi, loff_t offset, extern struct cifsFileInfo *find_writable_file(struct cifsInodeInfo *, bool); extern struct cifsFileInfo *find_readable_file(struct cifsInodeInfo *, bool); extern unsigned int smbCalcSize(struct smb_hdr *ptr); -extern unsigned int smbCalcSize_LE(struct smb_hdr *ptr); extern int decode_negTokenInit(unsigned char *security_blob, int length, struct TCP_Server_Info *server); extern int cifs_convert_address(struct sockaddr *dst, const char *src, int len); diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c index 8800409..83df937 100644 --- a/fs/cifs/cifssmb.c +++ b/fs/cifs/cifssmb.c @@ -582,7 +582,7 @@ CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses) if ((pSMBr->hdr.Flags2 & SMBFLG2_EXT_SEC) && (server->capabilities & CAP_EXTENDED_SECURITY)) { - count = pSMBr->ByteCount; + count = get_bcc(&pSMBr->hdr); if (count < 16) { rc = -EIO; goto neg_err_exit; @@ -736,7 +736,7 @@ CIFSSMBEcho(struct TCP_Server_Info *server) smb->hdr.Tid = 0xffff; smb->hdr.WordCount = 1; put_unaligned_le16(1, &smb->EchoCount); - put_bcc_le(1, &smb->hdr); + put_bcc(1, &smb->hdr); smb->Data[0] = 'a'; inc_rfc1001_len(smb, 3); @@ -1079,7 +1079,7 @@ PsxCreat: cFYI(1, "copying inode info"); rc = validate_t2((struct smb_t2_rsp *)pSMBr); - if (rc || (pSMBr->ByteCount < sizeof(OPEN_PSX_RSP))) { + if (rc || get_bcc(&pSMBr->hdr) < sizeof(OPEN_PSX_RSP)) { rc = -EIO; /* bad smb */ goto psx_create_err; } @@ -1100,7 +1100,7 @@ PsxCreat: pRetData->Type = cpu_to_le32(-1); /* unknown */ cFYI(DBG2, "unknown type"); } else { - if (pSMBr->ByteCount < sizeof(OPEN_PSX_RSP) + if (get_bcc(&pSMBr->hdr) < sizeof(OPEN_PSX_RSP) + sizeof(FILE_UNIX_BASIC_INFO)) { cERROR(1, "Open response data too small"); pRetData->Type = cpu_to_le32(-1); @@ -1867,7 +1867,7 @@ CIFSSMBPosixLock(const int xid, struct cifsTconInfo *tcon, __u16 data_count; rc = validate_t2((struct smb_t2_rsp *)pSMBr); - if (rc || (pSMBr->ByteCount < sizeof(struct cifs_posix_lock))) { + if (rc || get_bcc(&pSMBr->hdr) < sizeof(*parm_data)) { rc = -EIO; /* bad smb */ goto plk_err_exit; } @@ -2494,7 +2494,7 @@ querySymLinkRetry: rc = validate_t2((struct smb_t2_rsp *)pSMBr); /* BB also check enough total bytes returned */ - if (rc || (pSMBr->ByteCount < 2)) + if (rc || get_bcc(&pSMBr->hdr) < 2) rc = -EIO; else { bool is_unicode; @@ -2576,14 +2576,14 @@ CIFSSMBQueryReparseLinkInfo(const int xid, struct cifsTconInfo *tcon, } else { /* decode response */ __u32 data_offset = le32_to_cpu(pSMBr->DataOffset); __u32 data_count = le32_to_cpu(pSMBr->DataCount); - if ((pSMBr->ByteCount < 2) || (data_offset > 512)) { - /* BB also check enough total bytes returned */ + if (get_bcc(&pSMBr->hdr) < 2 || data_offset > 512) { + /* BB also check enough total bytes returned */ rc = -EIO; /* bad smb */ goto qreparse_out; } if (data_count && (data_count < 2048)) { char *end_of_smb = 2 /* sizeof byte count */ + - pSMBr->ByteCount + (char *)&pSMBr->ByteCount; + get_bcc(&pSMBr->hdr) + (char *)&pSMBr->ByteCount; struct reparse_data *reparse_buf = (struct reparse_data *) @@ -2841,8 +2841,8 @@ queryAclRetry: /* decode response */ rc = validate_t2((struct smb_t2_rsp *)pSMBr); - if (rc || (pSMBr->ByteCount < 2)) /* BB also check enough total bytes returned */ + if (rc || get_bcc(&pSMBr->hdr) < 2) rc = -EIO; /* bad smb */ else { __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset); @@ -2991,8 +2991,8 @@ GetExtAttrRetry: } else { /* decode response */ rc = validate_t2((struct smb_t2_rsp *)pSMBr); - if (rc || (pSMBr->ByteCount < 2)) /* BB also check enough total bytes returned */ + if (rc || get_bcc(&pSMBr->hdr) < 2) /* If rc should we check for EOPNOSUPP and disable the srvino flag? or in caller? */ rc = -EIO; /* bad smb */ @@ -3067,6 +3067,7 @@ validate_ntransact(char *buf, char **ppparm, char **ppdata, char *end_of_smb; __u32 data_count, data_offset, parm_count, parm_offset; struct smb_com_ntransact_rsp *pSMBr; + u16 bcc; *pdatalen = 0; *pparmlen = 0; @@ -3076,8 +3077,8 @@ validate_ntransact(char *buf, char **ppparm, char **ppdata, pSMBr = (struct smb_com_ntransact_rsp *)buf; - /* ByteCount was converted from little endian in SendReceive */ - end_of_smb = 2 /* sizeof byte count */ + pSMBr->ByteCount + + bcc = get_bcc(&pSMBr->hdr); + end_of_smb = 2 /* sizeof byte count */ + bcc + (char *)&pSMBr->ByteCount; data_offset = le32_to_cpu(pSMBr->DataOffset); @@ -3103,7 +3104,7 @@ validate_ntransact(char *buf, char **ppparm, char **ppdata, *ppdata, data_count, (data_count + *ppdata), end_of_smb, pSMBr); return -EINVAL; - } else if (parm_count + data_count > pSMBr->ByteCount) { + } else if (parm_count + data_count > bcc) { cFYI(1, "parm count and data count larger than SMB"); return -EINVAL; } @@ -3389,7 +3390,7 @@ QFileInfoRetry: if (rc) /* BB add auto retry on EOPNOTSUPP? */ rc = -EIO; - else if (pSMBr->ByteCount < 40) + else if (get_bcc(&pSMBr->hdr) < 40) rc = -EIO; /* bad smb */ else if (pFindData) { __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset); @@ -3477,9 +3478,9 @@ QPathInfoRetry: if (rc) /* BB add auto retry on EOPNOTSUPP? */ rc = -EIO; - else if (!legacy && (pSMBr->ByteCount < 40)) + else if (!legacy && get_bcc(&pSMBr->hdr) < 40) rc = -EIO; /* bad smb */ - else if (legacy && (pSMBr->ByteCount < 24)) + else if (legacy && get_bcc(&pSMBr->hdr) < 24) rc = -EIO; /* 24 or 26 expected but we do not read last field */ else if (pFindData) { @@ -3555,7 +3556,7 @@ UnixQFileInfoRetry: } else { /* decode response */ rc = validate_t2((struct smb_t2_rsp *)pSMBr); - if (rc || (pSMBr->ByteCount < sizeof(FILE_UNIX_BASIC_INFO))) { + if (rc || get_bcc(&pSMBr->hdr) < sizeof(FILE_UNIX_BASIC_INFO)) { cERROR(1, "Malformed FILE_UNIX_BASIC_INFO response.\n" "Unix Extensions can be disabled on mount " "by specifying the nosfu mount option."); @@ -3641,7 +3642,7 @@ UnixQPathInfoRetry: } else { /* decode response */ rc = validate_t2((struct smb_t2_rsp *)pSMBr); - if (rc || (pSMBr->ByteCount < sizeof(FILE_UNIX_BASIC_INFO))) { + if (rc || get_bcc(&pSMBr->hdr) < sizeof(FILE_UNIX_BASIC_INFO)) { cERROR(1, "Malformed FILE_UNIX_BASIC_INFO response.\n" "Unix Extensions can be disabled on mount " "by specifying the nosfu mount option."); @@ -4046,8 +4047,8 @@ GetInodeNumberRetry: } else { /* decode response */ rc = validate_t2((struct smb_t2_rsp *)pSMBr); - if (rc || (pSMBr->ByteCount < 2)) /* BB also check enough total bytes returned */ + if (rc || get_bcc(&pSMBr->hdr) < 2) /* If rc should we check for EOPNOSUPP and disable the srvino flag? or in caller? */ rc = -EIO; /* bad smb */ @@ -4272,13 +4273,13 @@ getDFSRetry: rc = validate_t2((struct smb_t2_rsp *)pSMBr); /* BB Also check if enough total bytes returned? */ - if (rc || (pSMBr->ByteCount < 17)) { + if (rc || get_bcc(&pSMBr->hdr) < 17) { rc = -EIO; /* bad smb */ goto GetDFSRefExit; } cFYI(1, "Decoding GetDFSRefer response BCC: %d Offset %d", - pSMBr->ByteCount, + get_bcc(&pSMBr->hdr), le16_to_cpu(pSMBr->t2.DataOffset)); /* parse returned result into more usable form */ @@ -4344,12 +4345,12 @@ oldQFSInfoRetry: } else { /* decode response */ rc = validate_t2((struct smb_t2_rsp *)pSMBr); - if (rc || (pSMBr->ByteCount < 18)) + if (rc || get_bcc(&pSMBr->hdr) < 18) rc = -EIO; /* bad smb */ else { __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset); cFYI(1, "qfsinf resp BCC: %d Offset %d", - pSMBr->ByteCount, data_offset); + get_bcc(&pSMBr->hdr), data_offset); response_data = (FILE_SYSTEM_ALLOC_INFO *) (((char *) &pSMBr->hdr.Protocol) + data_offset); @@ -4423,7 +4424,7 @@ QFSInfoRetry: } else { /* decode response */ rc = validate_t2((struct smb_t2_rsp *)pSMBr); - if (rc || (pSMBr->ByteCount < 24)) + if (rc || get_bcc(&pSMBr->hdr) < 24) rc = -EIO; /* bad smb */ else { __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset); @@ -4503,7 +4504,7 @@ QFSAttributeRetry: } else { /* decode response */ rc = validate_t2((struct smb_t2_rsp *)pSMBr); - if (rc || (pSMBr->ByteCount < 13)) { + if (rc || get_bcc(&pSMBr->hdr) < 13) { /* BB also check if enough bytes returned */ rc = -EIO; /* bad smb */ } else { @@ -4574,7 +4575,8 @@ QFSDeviceRetry: } else { /* decode response */ rc = validate_t2((struct smb_t2_rsp *)pSMBr); - if (rc || (pSMBr->ByteCount < sizeof(FILE_SYSTEM_DEVICE_INFO))) + if (rc || get_bcc(&pSMBr->hdr) < + sizeof(FILE_SYSTEM_DEVICE_INFO)) rc = -EIO; /* bad smb */ else { __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset); @@ -4643,7 +4645,7 @@ QFSUnixRetry: } else { /* decode response */ rc = validate_t2((struct smb_t2_rsp *)pSMBr); - if (rc || (pSMBr->ByteCount < 13)) { + if (rc || get_bcc(&pSMBr->hdr) < 13) { rc = -EIO; /* bad smb */ } else { __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset); @@ -4788,7 +4790,7 @@ QFSPosixRetry: } else { /* decode response */ rc = validate_t2((struct smb_t2_rsp *)pSMBr); - if (rc || (pSMBr->ByteCount < 13)) { + if (rc || get_bcc(&pSMBr->hdr) < 13) { rc = -EIO; /* bad smb */ } else { __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset); @@ -5517,7 +5519,7 @@ QAllEAsRetry: of these trans2 responses */ rc = validate_t2((struct smb_t2_rsp *)pSMBr); - if (rc || (pSMBr->ByteCount < 4)) { + if (rc || get_bcc(&pSMBr->hdr) < 4) { rc = -EIO; /* bad smb */ goto QAllEAsOut; } diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index 5d331cd..2b51199 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c @@ -317,12 +317,12 @@ static int coalesce_t2(struct smb_hdr *psecond, struct smb_hdr *pTargetSMB) put_unaligned_le16(total_in_buf, &pSMBt->t2_rsp.DataCount); /* fix up the BCC */ - byte_count = get_bcc_le(pTargetSMB); + byte_count = get_bcc(pTargetSMB); byte_count += total_in_buf2; /* is the result too big for the field? */ if (byte_count > USHRT_MAX) return -EPROTO; - put_bcc_le(byte_count, pTargetSMB); + put_bcc(byte_count, pTargetSMB); byte_count = be32_to_cpu(pTargetSMB->smb_buf_length); byte_count += total_in_buf2; diff --git a/fs/cifs/misc.c b/fs/cifs/misc.c index 533f863..907531a 100644 --- a/fs/cifs/misc.c +++ b/fs/cifs/misc.c @@ -462,7 +462,7 @@ checkSMB(struct smb_hdr *smb, __u16 mid, unsigned int length) if (check_smb_hdr(smb, mid)) return 1; - clc_len = smbCalcSize_LE(smb); + clc_len = smbCalcSize(smb); if (4 + len != length) { cERROR(1, "Length read does not match RFC1001 length %d", @@ -519,7 +519,7 @@ is_valid_oplock_break(struct smb_hdr *buf, struct TCP_Server_Info *srv) (struct smb_com_transaction_change_notify_rsp *)buf; struct file_notify_information *pnotify; __u32 data_offset = 0; - if (get_bcc_le(buf) > sizeof(struct file_notify_information)) { + if (get_bcc(buf) > sizeof(struct file_notify_information)) { data_offset = le32_to_cpu(pSMBr->DataOffset); pnotify = (struct file_notify_information *) diff --git a/fs/cifs/netmisc.c b/fs/cifs/netmisc.c index 79f641e..79b71c2 100644 --- a/fs/cifs/netmisc.c +++ b/fs/cifs/netmisc.c @@ -919,13 +919,6 @@ smbCalcSize(struct smb_hdr *ptr) 2 /* size of the bcc field */ + get_bcc(ptr)); } -unsigned int -smbCalcSize_LE(struct smb_hdr *ptr) -{ - return (sizeof(struct smb_hdr) + (2 * ptr->WordCount) + - 2 /* size of the bcc field */ + get_bcc_le(ptr)); -} - /* The following are taken from fs/ntfs/util.c */ #define NTFS_TIME_OFFSET ((u64)(369*365 + 89) * 24 * 3600 * 10000000) diff --git a/fs/cifs/sess.c b/fs/cifs/sess.c index 1daadad..7dd4621 100644 --- a/fs/cifs/sess.c +++ b/fs/cifs/sess.c @@ -862,7 +862,7 @@ ssetup_ntlmssp_authenticate: smb_buf->smb_buf_length = cpu_to_be32(be32_to_cpu(smb_buf->smb_buf_length) + count); - put_bcc_le(count, smb_buf); + put_bcc(count, smb_buf); rc = SendReceive2(xid, ses, iov, 3 /* num_iovecs */, &resp_buf_type, CIFS_LOG_ERROR); diff --git a/fs/cifs/transport.c b/fs/cifs/transport.c index 19df0e5..f2513fb 100644 --- a/fs/cifs/transport.c +++ b/fs/cifs/transport.c @@ -484,7 +484,7 @@ send_nt_cancel(struct TCP_Server_Info *server, struct smb_hdr *in_buf, in_buf->smb_buf_length = cpu_to_be32(sizeof(struct smb_hdr) - 4 + 2); in_buf->Command = SMB_COM_NT_CANCEL; in_buf->WordCount = 0; - put_bcc_le(0, in_buf); + put_bcc(0, in_buf); mutex_lock(&server->srv_mutex); rc = cifs_sign_smb(in_buf, server, &mid->sequence_number); @@ -644,11 +644,6 @@ SendReceive2(const unsigned int xid, struct cifsSesInfo *ses, rc = map_smb_to_linux_error(midQ->resp_buf, flags & CIFS_LOG_ERROR); - /* convert ByteCount if necessary */ - if (receive_len >= sizeof(struct smb_hdr) - 4 - /* do not count RFC1001 header */ + - (2 * midQ->resp_buf->WordCount) + 2 /* bcc */ ) - put_bcc(get_bcc_le(midQ->resp_buf), midQ->resp_buf); if ((flags & CIFS_NO_RESP) == 0) midQ->resp_buf = NULL; /* mark it so buf will not be freed by @@ -798,12 +793,6 @@ SendReceive(const unsigned int xid, struct cifsSesInfo *ses, /* BB special case reconnect tid and uid here? */ rc = map_smb_to_linux_error(out_buf, 0 /* no log */ ); - - /* convert ByteCount if necessary */ - if (receive_len >= sizeof(struct smb_hdr) - 4 - /* do not count RFC1001 header */ + - (2 * out_buf->WordCount) + 2 /* bcc */ ) - put_bcc(get_bcc_le(midQ->resp_buf), midQ->resp_buf); } else { rc = -EIO; cERROR(1, "Bad MID state?"); @@ -1012,12 +1001,6 @@ SendReceiveBlockingLock(const unsigned int xid, struct cifsTconInfo *tcon, /* BB special case reconnect tid and uid here? */ rc = map_smb_to_linux_error(out_buf, 0 /* no log */ ); - /* convert ByteCount if necessary */ - if (receive_len >= sizeof(struct smb_hdr) - 4 - /* do not count RFC1001 header */ + - (2 * out_buf->WordCount) + 2 /* bcc */ ) - put_bcc(get_bcc_le(out_buf), out_buf); - out: delete_mid(midQ); if (rstart && rc == -EACCES) -- cgit v0.10.2 From 460458ce8ec195a1902f0c742b76880fbd01dd96 Mon Sep 17 00:00:00 2001 From: Jeff Layton Date: Thu, 31 Mar 2011 21:18:15 -0400 Subject: cifs: turn BCC into a static inlined function It's a bad idea to have macro functions that reference variables more than once, as the arguments could have side effects. Turn BCC() into a static inlined function instead. While we're at it, make it return a void * to discourage anyone from dereferencing it as-is. Reported-and-acked-by: David Howells Signed-off-by: Jeff Layton Signed-off-by: Steve French Signed-off-by: Pavel Shilovsky Signed-off-by: Steve French diff --git a/fs/cifs/cifspdu.h b/fs/cifs/cifspdu.h index 291d735..de3aa28 100644 --- a/fs/cifs/cifspdu.h +++ b/fs/cifs/cifspdu.h @@ -428,9 +428,12 @@ struct smb_hdr { __u8 WordCount; } __attribute__((packed)); -/* given a pointer to an smb_hdr retrieve a char pointer to the byte count */ -#define BCC(smb_var) ((unsigned char *)(smb_var) + sizeof(struct smb_hdr) + \ - (2 * (smb_var)->WordCount)) +/* given a pointer to an smb_hdr, retrieve a void pointer to the ByteCount */ +static inline void * +BCC(struct smb_hdr *smb) +{ + return (void *)smb + sizeof(*smb) + 2 * smb->WordCount; +} /* given a pointer to an smb_hdr retrieve the pointer to the byte area */ #define pByteArea(smb_var) (BCC(smb_var) + 2) -- cgit v0.10.2 From dd61394586dbd9387fe53b325c6807f61734cf89 Mon Sep 17 00:00:00 2001 From: Sean Finney Date: Mon, 11 Apr 2011 13:19:30 +0000 Subject: cifs: Extract DFS referral expansion logic to separate function The logic behind the expansion of DFS referrals is now extracted from cifs_mount into a new static function, expand_dfs_referral. This will reduce duplicate code in upcoming commits. Reviewed-by: Jeff Layton Signed-off-by: Sean Finney Signed-off-by: Pavel Shilovsky Signed-off-by: Steve French diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index 2b51199..b6c6a36 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c @@ -2745,6 +2745,57 @@ build_unc_path_to_root(const struct smb_vol *volume_info, full_path[unc_len + cifs_sb->prepathlen] = 0; /* add trailing null */ return full_path; } + +/* + * Perform a dfs referral query for a share and (optionally) prefix + * + * If a referral is found, mount_data will be set to point at a newly + * allocated string containing updated options for the submount. + * Otherwise it will be left untouched. + * + * Returns the rc from get_dfs_path to the caller, which can be used to + * determine whether there were referrals. + */ +static int +expand_dfs_referral(int xid, struct cifsSesInfo *pSesInfo, + struct smb_vol *volume_info, struct cifs_sb_info *cifs_sb, + char **mount_data, int check_prefix) +{ + int rc; + unsigned int num_referrals = 0; + struct dfs_info3_param *referrals = NULL; + char *full_path = NULL, *ref_path = NULL, *mdata = NULL; + + full_path = build_unc_path_to_root(volume_info, cifs_sb); + if (IS_ERR(full_path)) + return PTR_ERR(full_path); + + /* For DFS paths, skip the first '\' of the UNC */ + ref_path = check_prefix ? full_path + 1 : volume_info->UNC + 1; + + rc = get_dfs_path(xid, pSesInfo , ref_path, cifs_sb->local_nls, + &num_referrals, &referrals, + cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); + + if (!rc && num_referrals > 0) { + char *fake_devname = NULL; + + mdata = cifs_compose_mount_options(cifs_sb->mountdata, + full_path + 1, referrals, + &fake_devname); + + free_dfs_info_array(referrals, num_referrals); + kfree(fake_devname); + + if (IS_ERR(mdata)) { + rc = PTR_ERR(mdata); + mdata = NULL; + } + *mount_data = mdata; + } + kfree(full_path); + return rc; +} #endif int @@ -2761,10 +2812,19 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb, char *mount_data = mount_data_global; struct tcon_link *tlink; #ifdef CONFIG_CIFS_DFS_UPCALL - struct dfs_info3_param *referrals = NULL; - unsigned int num_referrals = 0; int referral_walks_count = 0; try_mount_again: + + /* cleanup activities if we're chasing a referral */ + if (referral_walks_count) { + if (tcon) + cifs_put_tcon(tcon); + else if (pSesInfo) + cifs_put_smb_ses(pSesInfo); + + cleanup_volume_info(&volume_info); + FreeXid(xid); + } #endif rc = 0; tcon = NULL; @@ -2910,46 +2970,19 @@ remote_path_check: if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_POSIX_PATHS) == 0) convert_delimiter(cifs_sb->prepath, CIFS_DIR_SEP(cifs_sb)); - full_path = build_unc_path_to_root(volume_info, cifs_sb); - if (IS_ERR(full_path)) { - rc = PTR_ERR(full_path); - goto mount_fail_check; - } - cFYI(1, "Getting referral for: %s", full_path); - rc = get_dfs_path(xid, pSesInfo , full_path + 1, - cifs_sb->local_nls, &num_referrals, &referrals, - cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); - if (!rc && num_referrals > 0) { - char *fake_devname = NULL; - - if (mount_data != mount_data_global) - kfree(mount_data); - - mount_data = cifs_compose_mount_options( - cifs_sb->mountdata, full_path + 1, - referrals, &fake_devname); - - free_dfs_info_array(referrals, num_referrals); - kfree(fake_devname); - kfree(full_path); - - if (IS_ERR(mount_data)) { - rc = PTR_ERR(mount_data); - mount_data = NULL; - goto mount_fail_check; - } + if (mount_data != mount_data_global) + kfree(mount_data); - if (tcon) - cifs_put_tcon(tcon); - else if (pSesInfo) - cifs_put_smb_ses(pSesInfo); + rc = expand_dfs_referral(xid, pSesInfo, volume_info, cifs_sb, + &mount_data, true); - cleanup_volume_info(&volume_info); + if (!rc) { referral_walks_count++; - FreeXid(xid); goto try_mount_again; } + mount_data = NULL; + goto mount_fail_check; #else /* No DFS support, return error on mount */ rc = -EOPNOTSUPP; #endif -- cgit v0.10.2 From c1508ca23653245266e2e3ab69a8dad464f7a569 Mon Sep 17 00:00:00 2001 From: Sean Finney Date: Mon, 11 Apr 2011 13:19:31 +0000 Subject: cifs: Add support for mounting Windows 2008 DFS shares Windows 2008 CIFS servers do not always return PATH_NOT_COVERED when attempting to access a DFS share. Therefore, when checking for remote shares, unconditionally ask for a DFS referral for the UNC (w/out prepath) before continuing with previous behavior of attempting to access the UNC + prepath and checking for PATH_NOT_COVERED. Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=31092 Reviewed-by: Jeff Layton Signed-off-by: Sean Finney Signed-off-by: Pavel Shilovsky Signed-off-by: Steve French diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index b6c6a36..c7ebeee 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c @@ -2937,6 +2937,24 @@ try_mount_again: (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE)); remote_path_check: +#ifdef CONFIG_CIFS_DFS_UPCALL + /* + * Perform an unconditional check for whether there are DFS + * referrals for this path without prefix, to provide support + * for DFS referrals from w2k8 servers which don't seem to respond + * with PATH_NOT_COVERED to requests that include the prefix. + * Chase the referral if found, otherwise continue normally. + */ + if (referral_walks_count == 0) { + int refrc = expand_dfs_referral(xid, pSesInfo, volume_info, + cifs_sb, &mount_data, false); + if (!refrc) { + referral_walks_count++; + goto try_mount_again; + } + } +#endif + /* check if a whole path (including prepath) is not remote */ if (!rc && tcon) { /* build_path_to_root works only when we have a valid tcon */ -- cgit v0.10.2 From b946845a9dc523c759cae2b6a0f6827486c3221a Mon Sep 17 00:00:00 2001 From: Sean Finney Date: Mon, 11 Apr 2011 13:19:32 +0000 Subject: cifs: cifs_parse_mount_options: do not tokenize mount options in-place To keep strings passed to cifs_parse_mount_options re-usable (which is needed to clean up the DFS referral handling), tokenize a copy of the mount options instead. If values are needed from this tokenized string, they too must be duplicated (previously, some options were copied and others duplicated). Since we are not on the critical path and any cleanup is relatively easy, the extra memory usage shouldn't be a problem (and it is a bit simpler than trying to implement something smarter). Reviewed-by: Jeff Layton Signed-off-by: Sean Finney Signed-off-by: Pavel Shilovsky Signed-off-by: Steve French diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index c7ebeee..20c60dd 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c @@ -818,10 +818,11 @@ extract_hostname(const char *unc) } static int -cifs_parse_mount_options(char *options, const char *devname, +cifs_parse_mount_options(const char *mountdata, const char *devname, struct smb_vol *vol) { char *value, *data, *end; + char *mountdata_copy, *options; unsigned int temp_len, i, j; char separator[2]; short int override_uid = -1; @@ -861,9 +862,14 @@ cifs_parse_mount_options(char *options, const char *devname, vol->actimeo = CIFS_DEF_ACTIMEO; - if (!options) - return 1; + if (!mountdata) + goto cifs_parse_mount_err; + + mountdata_copy = kstrndup(mountdata, PAGE_SIZE, GFP_KERNEL); + if (!mountdata_copy) + goto cifs_parse_mount_err; + options = mountdata_copy; end = options + strlen(options); if (strncmp(options, "sep=", 4) == 0) { if (options[4] != 0) { @@ -889,17 +895,22 @@ cifs_parse_mount_options(char *options, const char *devname, if (!value) { printk(KERN_WARNING "CIFS: invalid or missing username\n"); - return 1; /* needs_arg; */ + goto cifs_parse_mount_err; } else if (!*value) { /* null user, ie anonymous, authentication */ vol->nullauth = 1; } if (strnlen(value, MAX_USERNAME_SIZE) < MAX_USERNAME_SIZE) { - vol->username = value; + vol->username = kstrdup(value, GFP_KERNEL); + if (!vol->username) { + printk(KERN_WARNING "CIFS: no memory " + "for username\n"); + goto cifs_parse_mount_err; + } } else { printk(KERN_WARNING "CIFS: username too long\n"); - return 1; + goto cifs_parse_mount_err; } } else if (strnicmp(data, "pass", 4) == 0) { if (!value) { @@ -963,7 +974,7 @@ cifs_parse_mount_options(char *options, const char *devname, if (vol->password == NULL) { printk(KERN_WARNING "CIFS: no memory " "for password\n"); - return 1; + goto cifs_parse_mount_err; } for (i = 0, j = 0; i < temp_len; i++, j++) { vol->password[j] = value[i]; @@ -979,7 +990,7 @@ cifs_parse_mount_options(char *options, const char *devname, if (vol->password == NULL) { printk(KERN_WARNING "CIFS: no memory " "for password\n"); - return 1; + goto cifs_parse_mount_err; } strcpy(vol->password, value); } @@ -989,11 +1000,16 @@ cifs_parse_mount_options(char *options, const char *devname, vol->UNCip = NULL; } else if (strnlen(value, INET6_ADDRSTRLEN) < INET6_ADDRSTRLEN) { - vol->UNCip = value; + vol->UNCip = kstrdup(value, GFP_KERNEL); + if (!vol->UNCip) { + printk(KERN_WARNING "CIFS: no memory " + "for UNC IP\n"); + goto cifs_parse_mount_err; + } } else { printk(KERN_WARNING "CIFS: ip address " "too long\n"); - return 1; + goto cifs_parse_mount_err; } } else if (strnicmp(data, "sec", 3) == 0) { if (!value || !*value) { @@ -1006,7 +1022,7 @@ cifs_parse_mount_options(char *options, const char *devname, /* vol->secFlg |= CIFSSEC_MUST_SEAL | CIFSSEC_MAY_KRB5; */ cERROR(1, "Krb5 cifs privacy not supported"); - return 1; + goto cifs_parse_mount_err; } else if (strnicmp(value, "krb5", 4) == 0) { vol->secFlg |= CIFSSEC_MAY_KRB5; } else if (strnicmp(value, "ntlmsspi", 8) == 0) { @@ -1036,7 +1052,7 @@ cifs_parse_mount_options(char *options, const char *devname, vol->nullauth = 1; } else { cERROR(1, "bad security option: %s", value); - return 1; + goto cifs_parse_mount_err; } } else if (strnicmp(data, "vers", 3) == 0) { if (!value || !*value) { @@ -1060,12 +1076,12 @@ cifs_parse_mount_options(char *options, const char *devname, if (!value || !*value) { printk(KERN_WARNING "CIFS: invalid path to " "network resource\n"); - return 1; /* needs_arg; */ + goto cifs_parse_mount_err; } if ((temp_len = strnlen(value, 300)) < 300) { vol->UNC = kmalloc(temp_len+1, GFP_KERNEL); if (vol->UNC == NULL) - return 1; + goto cifs_parse_mount_err; strcpy(vol->UNC, value); if (strncmp(vol->UNC, "//", 2) == 0) { vol->UNC[0] = '\\'; @@ -1074,27 +1090,32 @@ cifs_parse_mount_options(char *options, const char *devname, printk(KERN_WARNING "CIFS: UNC Path does not begin " "with // or \\\\ \n"); - return 1; + goto cifs_parse_mount_err; } } else { printk(KERN_WARNING "CIFS: UNC name too long\n"); - return 1; + goto cifs_parse_mount_err; } } else if ((strnicmp(data, "domain", 3) == 0) || (strnicmp(data, "workgroup", 5) == 0)) { if (!value || !*value) { printk(KERN_WARNING "CIFS: invalid domain name\n"); - return 1; /* needs_arg; */ + goto cifs_parse_mount_err; } /* BB are there cases in which a comma can be valid in a domain name and need special handling? */ if (strnlen(value, 256) < 256) { - vol->domainname = value; + vol->domainname = kstrdup(value, GFP_KERNEL); + if (!vol->domainname) { + printk(KERN_WARNING "CIFS: no memory " + "for domainname\n"); + goto cifs_parse_mount_err; + } cFYI(1, "Domain name set"); } else { printk(KERN_WARNING "CIFS: domain name too " "long\n"); - return 1; + goto cifs_parse_mount_err; } } else if (strnicmp(data, "srcaddr", 7) == 0) { vol->srcaddr.ss_family = AF_UNSPEC; @@ -1102,7 +1123,7 @@ cifs_parse_mount_options(char *options, const char *devname, if (!value || !*value) { printk(KERN_WARNING "CIFS: srcaddr value" " not specified.\n"); - return 1; /* needs_arg; */ + goto cifs_parse_mount_err; } i = cifs_convert_address((struct sockaddr *)&vol->srcaddr, value, strlen(value)); @@ -1110,20 +1131,20 @@ cifs_parse_mount_options(char *options, const char *devname, printk(KERN_WARNING "CIFS: Could not parse" " srcaddr: %s\n", value); - return 1; + goto cifs_parse_mount_err; } } else if (strnicmp(data, "prefixpath", 10) == 0) { if (!value || !*value) { printk(KERN_WARNING "CIFS: invalid path prefix\n"); - return 1; /* needs_argument */ + goto cifs_parse_mount_err; } if ((temp_len = strnlen(value, 1024)) < 1024) { if (value[0] != '/') temp_len++; /* missing leading slash */ vol->prepath = kmalloc(temp_len+1, GFP_KERNEL); if (vol->prepath == NULL) - return 1; + goto cifs_parse_mount_err; if (value[0] != '/') { vol->prepath[0] = '/'; strcpy(vol->prepath+1, value); @@ -1132,24 +1153,33 @@ cifs_parse_mount_options(char *options, const char *devname, cFYI(1, "prefix path %s", vol->prepath); } else { printk(KERN_WARNING "CIFS: prefix too long\n"); - return 1; + goto cifs_parse_mount_err; } } else if (strnicmp(data, "iocharset", 9) == 0) { if (!value || !*value) { printk(KERN_WARNING "CIFS: invalid iocharset " "specified\n"); - return 1; /* needs_arg; */ + goto cifs_parse_mount_err; } if (strnlen(value, 65) < 65) { - if (strnicmp(value, "default", 7)) - vol->iocharset = value; + if (strnicmp(value, "default", 7)) { + vol->iocharset = kstrdup(value, + GFP_KERNEL); + + if (!vol->iocharset) { + printk(KERN_WARNING "CIFS: no " + "memory for" + "charset\n"); + goto cifs_parse_mount_err; + } + } /* if iocharset not set then load_nls_default is used by caller */ cFYI(1, "iocharset set to %s", value); } else { printk(KERN_WARNING "CIFS: iocharset name " "too long.\n"); - return 1; + goto cifs_parse_mount_err; } } else if (!strnicmp(data, "uid", 3) && value && *value) { vol->linux_uid = simple_strtoul(value, &value, 0); @@ -1262,7 +1292,7 @@ cifs_parse_mount_options(char *options, const char *devname, if (vol->actimeo > CIFS_MAX_ACTIMEO) { cERROR(1, "CIFS: attribute cache" "timeout too large"); - return 1; + goto cifs_parse_mount_err; } } } else if (strnicmp(data, "credentials", 4) == 0) { @@ -1406,7 +1436,7 @@ cifs_parse_mount_options(char *options, const char *devname, #ifndef CONFIG_CIFS_FSCACHE cERROR(1, "FS-Cache support needs CONFIG_CIFS_FSCACHE" "kernel config option set"); - return 1; + goto cifs_parse_mount_err; #endif vol->fsc = true; } else if (strnicmp(data, "mfsymlinks", 10) == 0) { @@ -1421,12 +1451,12 @@ cifs_parse_mount_options(char *options, const char *devname, if (devname == NULL) { printk(KERN_WARNING "CIFS: Missing UNC name for mount " "target\n"); - return 1; + goto cifs_parse_mount_err; } if ((temp_len = strnlen(devname, 300)) < 300) { vol->UNC = kmalloc(temp_len+1, GFP_KERNEL); if (vol->UNC == NULL) - return 1; + goto cifs_parse_mount_err; strcpy(vol->UNC, devname); if (strncmp(vol->UNC, "//", 2) == 0) { vol->UNC[0] = '\\'; @@ -1434,21 +1464,21 @@ cifs_parse_mount_options(char *options, const char *devname, } else if (strncmp(vol->UNC, "\\\\", 2) != 0) { printk(KERN_WARNING "CIFS: UNC Path does not " "begin with // or \\\\ \n"); - return 1; + goto cifs_parse_mount_err; } value = strpbrk(vol->UNC+2, "/\\"); if (value) *value = '\\'; } else { printk(KERN_WARNING "CIFS: UNC name too long\n"); - return 1; + goto cifs_parse_mount_err; } } if (vol->multiuser && !(vol->secFlg & CIFSSEC_MAY_KRB5)) { cERROR(1, "Multiuser mounts currently require krb5 " "authentication!"); - return 1; + goto cifs_parse_mount_err; } if (vol->UNCip == NULL) @@ -1466,7 +1496,12 @@ cifs_parse_mount_options(char *options, const char *devname, printk(KERN_NOTICE "CIFS: ignoring forcegid mount option " "specified with no gid= option.\n"); + kfree(mountdata_copy); return 0; + +cifs_parse_mount_err: + kfree(mountdata_copy); + return 1; } /** Returns true if srcaddr isn't specified and rhs isn't @@ -2707,8 +2742,12 @@ cleanup_volume_info(struct smb_vol **pvolume_info) return; volume_info = *pvolume_info; + kfree(volume_info->username); kzfree(volume_info->password); kfree(volume_info->UNC); + kfree(volume_info->UNCip); + kfree(volume_info->domainname); + kfree(volume_info->iocharset); kfree(volume_info->prepath); kfree(volume_info); *pvolume_info = NULL; -- cgit v0.10.2 From 046462abca2576cc1c71f501c148798fac4ea314 Mon Sep 17 00:00:00 2001 From: Sean Finney Date: Mon, 11 Apr 2011 13:19:33 +0000 Subject: cifs: Simplify handling of submount options in cifs_mount. With CONFIG_DFS_UPCALL enabled, maintain the submount options in cifs_sb->mountdata, simplifying the code just a bit as well as making corner-case allocation problems less likely. Reviewed-by: Jeff Layton Signed-off-by: Sean Finney Signed-off-by: Pavel Shilovsky Signed-off-by: Steve French diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index 20c60dd..3e20831 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c @@ -2788,9 +2788,9 @@ build_unc_path_to_root(const struct smb_vol *volume_info, /* * Perform a dfs referral query for a share and (optionally) prefix * - * If a referral is found, mount_data will be set to point at a newly - * allocated string containing updated options for the submount. - * Otherwise it will be left untouched. + * If a referral is found, cifs_sb->mountdata will be (re-)allocated + * to a string containing updated options for the submount. Otherwise it + * will be left untouched. * * Returns the rc from get_dfs_path to the caller, which can be used to * determine whether there were referrals. @@ -2798,7 +2798,7 @@ build_unc_path_to_root(const struct smb_vol *volume_info, static int expand_dfs_referral(int xid, struct cifsSesInfo *pSesInfo, struct smb_vol *volume_info, struct cifs_sb_info *cifs_sb, - char **mount_data, int check_prefix) + int check_prefix) { int rc; unsigned int num_referrals = 0; @@ -2826,11 +2826,14 @@ expand_dfs_referral(int xid, struct cifsSesInfo *pSesInfo, free_dfs_info_array(referrals, num_referrals); kfree(fake_devname); + if (cifs_sb->mountdata != NULL) + kfree(cifs_sb->mountdata); + if (IS_ERR(mdata)) { rc = PTR_ERR(mdata); mdata = NULL; } - *mount_data = mdata; + cifs_sb->mountdata = mdata; } kfree(full_path); return rc; @@ -2853,6 +2856,7 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb, #ifdef CONFIG_CIFS_DFS_UPCALL int referral_walks_count = 0; try_mount_again: + mount_data = cifs_sb->mountdata; /* cleanup activities if we're chasing a referral */ if (referral_walks_count) { @@ -2986,7 +2990,7 @@ remote_path_check: */ if (referral_walks_count == 0) { int refrc = expand_dfs_referral(xid, pSesInfo, volume_info, - cifs_sb, &mount_data, false); + cifs_sb, false); if (!refrc) { referral_walks_count++; goto try_mount_again; @@ -3028,17 +3032,13 @@ remote_path_check: convert_delimiter(cifs_sb->prepath, CIFS_DIR_SEP(cifs_sb)); - if (mount_data != mount_data_global) - kfree(mount_data); - rc = expand_dfs_referral(xid, pSesInfo, volume_info, cifs_sb, - &mount_data, true); + true); if (!rc) { referral_walks_count++; goto try_mount_again; } - mount_data = NULL; goto mount_fail_check; #else /* No DFS support, return error on mount */ rc = -EOPNOTSUPP; @@ -3072,8 +3072,6 @@ remote_path_check: mount_fail_check: /* on error free sesinfo and tcon struct if needed */ if (rc) { - if (mount_data != mount_data_global) - kfree(mount_data); /* If find_unc succeeded then rc == 0 so we can not end */ /* up accidentally freeing someone elses tcon struct */ if (tcon) -- cgit v0.10.2 From 5167f11ec962690ecf926fab00f1d0524cd78664 Mon Sep 17 00:00:00 2001 From: Sean Finney Date: Mon, 11 Apr 2011 13:19:34 +0000 Subject: cifs: Use kstrndup for cifs_sb->mountdata A relatively minor nit, but also clarified the "consensus" from the preceding comments that it is in fact better to try for the kstrdup early and cleanup while cleaning up is still a simple thing to do. Reviewed-By: Steve French Signed-off-by: Sean Finney Signed-off-by: Pavel Shilovsky Signed-off-by: Steve French diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c index 0f6a54f..bb39afc 100644 --- a/fs/cifs/cifsfs.c +++ b/fs/cifs/cifsfs.c @@ -129,24 +129,19 @@ cifs_read_super(struct super_block *sb, void *data, cifs_sb->bdi.ra_pages = default_backing_dev_info.ra_pages; #ifdef CONFIG_CIFS_DFS_UPCALL - /* copy mount params to sb for use in submounts */ - /* BB: should we move this after the mount so we - * do not have to do the copy on failed mounts? - * BB: May be it is better to do simple copy before - * complex operation (mount), and in case of fail - * just exit instead of doing mount and attempting - * undo it if this copy fails?*/ + /* + * Copy mount params to sb for use in submounts. Better to do + * the copy here and deal with the error before cleanup gets + * complicated post-mount. + */ if (data) { - int len = strlen(data); - cifs_sb->mountdata = kzalloc(len + 1, GFP_KERNEL); + cifs_sb->mountdata = kstrndup(data, PAGE_SIZE, GFP_KERNEL); if (cifs_sb->mountdata == NULL) { bdi_destroy(&cifs_sb->bdi); kfree(sb->s_fs_info); sb->s_fs_info = NULL; return -ENOMEM; } - strncpy(cifs_sb->mountdata, data, len + 1); - cifs_sb->mountdata[len] = '\0'; } #endif -- cgit v0.10.2 From f14bcf71d1b802f6042b6c70a0c37120e47a0876 Mon Sep 17 00:00:00 2001 From: Sean Finney Date: Mon, 11 Apr 2011 13:19:35 +0000 Subject: cifs: Unconditionally copy mount options to superblock info Previously mount options were copied and updated in the cifs_sb_info struct only when CONFIG_CIFS_DFS_UPCALL was enabled. Making this information generally available allows us to remove a number of ifdefs, extra function params, and temporary variables. Reviewed-by: Jeff Layton Signed-off-by: Sean Finney Signed-off-by: Steve French diff --git a/fs/cifs/cifs_fs_sb.h b/fs/cifs/cifs_fs_sb.h index ac51cd2..a9d5692 100644 --- a/fs/cifs/cifs_fs_sb.h +++ b/fs/cifs/cifs_fs_sb.h @@ -58,9 +58,7 @@ struct cifs_sb_info { unsigned int mnt_cifs_flags; int prepathlen; char *prepath; /* relative path under the share to mount to */ -#ifdef CONFIG_CIFS_DFS_UPCALL - char *mountdata; /* mount options received at mount time */ -#endif + char *mountdata; /* options received at mount time or via DFS refs */ struct backing_dev_info bdi; struct delayed_work prune_tlinks; }; diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c index bb39afc..2b8e47e 100644 --- a/fs/cifs/cifsfs.c +++ b/fs/cifs/cifsfs.c @@ -128,7 +128,6 @@ cifs_read_super(struct super_block *sb, void *data, } cifs_sb->bdi.ra_pages = default_backing_dev_info.ra_pages; -#ifdef CONFIG_CIFS_DFS_UPCALL /* * Copy mount params to sb for use in submounts. Better to do * the copy here and deal with the error before cleanup gets @@ -143,9 +142,8 @@ cifs_read_super(struct super_block *sb, void *data, return -ENOMEM; } } -#endif - rc = cifs_mount(sb, cifs_sb, data, devname); + rc = cifs_mount(sb, cifs_sb, devname); if (rc) { if (!silent) @@ -197,12 +195,10 @@ out_no_root: out_mount_failed: if (cifs_sb) { -#ifdef CONFIG_CIFS_DFS_UPCALL if (cifs_sb->mountdata) { kfree(cifs_sb->mountdata); cifs_sb->mountdata = NULL; } -#endif unload_nls(cifs_sb->local_nls); bdi_destroy(&cifs_sb->bdi); kfree(cifs_sb); @@ -226,12 +222,10 @@ cifs_put_super(struct super_block *sb) rc = cifs_umount(sb, cifs_sb); if (rc) cERROR(1, "cifs_umount failed with return code %d", rc); -#ifdef CONFIG_CIFS_DFS_UPCALL if (cifs_sb->mountdata) { kfree(cifs_sb->mountdata); cifs_sb->mountdata = NULL; } -#endif unload_nls(cifs_sb->local_nls); bdi_destroy(&cifs_sb->bdi); diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h index 136d2f2..a1c94d3 100644 --- a/fs/cifs/cifsproto.h +++ b/fs/cifs/cifsproto.h @@ -148,7 +148,7 @@ extern struct cifs_ntsd *get_cifs_acl(struct cifs_sb_info *, struct inode *, extern int set_cifs_acl(struct cifs_ntsd *, __u32, struct inode *, const char *); -extern int cifs_mount(struct super_block *, struct cifs_sb_info *, char *, +extern int cifs_mount(struct super_block *, struct cifs_sb_info *, const char *); extern int cifs_umount(struct super_block *, struct cifs_sb_info *); extern void cifs_dfs_release_automount_timer(void); diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index 3e20831..da284e3 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c @@ -2842,7 +2842,7 @@ expand_dfs_referral(int xid, struct cifsSesInfo *pSesInfo, int cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb, - char *mount_data_global, const char *devname) + const char *devname) { int rc; int xid; @@ -2851,13 +2851,10 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb, struct cifsTconInfo *tcon; struct TCP_Server_Info *srvTcp; char *full_path; - char *mount_data = mount_data_global; struct tcon_link *tlink; #ifdef CONFIG_CIFS_DFS_UPCALL int referral_walks_count = 0; try_mount_again: - mount_data = cifs_sb->mountdata; - /* cleanup activities if we're chasing a referral */ if (referral_walks_count) { if (tcon) @@ -2884,7 +2881,8 @@ try_mount_again: goto out; } - if (cifs_parse_mount_options(mount_data, devname, volume_info)) { + if (cifs_parse_mount_options(cifs_sb->mountdata, devname, + volume_info)) { rc = -EINVAL; goto out; } -- cgit v0.10.2 From c4aca0c09f80ca40dbcecb2370af9594fbe9051d Mon Sep 17 00:00:00 2001 From: Shirish Pargaonkar Date: Fri, 6 May 2011 02:35:00 -0500 Subject: cifs: Change key name to cifs.idmap, misc. clean-up Change idmap key name from cifs.cifs_idmap to cifs.idmap. Removed unused structure wksidarr and function match_sid(). Handle errors correctly in function init_cifs(). Signed-off-by: Shirish Pargaonkar Reviewed-by: Jeff Layton Signed-off-by: Steve French diff --git a/fs/cifs/cifsacl.c b/fs/cifs/cifsacl.c index bfb5ba5..f3c6fb9 100644 --- a/fs/cifs/cifsacl.c +++ b/fs/cifs/cifsacl.c @@ -33,18 +33,6 @@ #include "cifsproto.h" #include "cifs_debug.h" - -static struct cifs_wksid wksidarr[NUM_WK_SIDS] = { - {{1, 0, {0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0} }, "null user"}, - {{1, 1, {0, 0, 0, 0, 0, 1}, {0, 0, 0, 0, 0} }, "nobody"}, - {{1, 1, {0, 0, 0, 0, 0, 5}, {__constant_cpu_to_le32(11), 0, 0, 0, 0} }, "net-users"}, - {{1, 1, {0, 0, 0, 0, 0, 5}, {__constant_cpu_to_le32(18), 0, 0, 0, 0} }, "sys"}, - {{1, 2, {0, 0, 0, 0, 0, 5}, {__constant_cpu_to_le32(32), __constant_cpu_to_le32(544), 0, 0, 0} }, "root"}, - {{1, 2, {0, 0, 0, 0, 0, 5}, {__constant_cpu_to_le32(32), __constant_cpu_to_le32(545), 0, 0, 0} }, "users"}, - {{1, 2, {0, 0, 0, 0, 0, 5}, {__constant_cpu_to_le32(32), __constant_cpu_to_le32(546), 0, 0, 0} }, "guest"} } -; - - /* security id for everyone/world system group */ static const struct cifs_sid sid_everyone = { 1, 1, {0, 0, 0, 0, 0, 1}, {0} }; @@ -131,7 +119,7 @@ cifs_idmap_key_destroy(struct key *key) } struct key_type cifs_idmap_key_type = { - .name = "cifs.cifs_idmap", + .name = "cifs.idmap", .instantiate = cifs_idmap_key_instantiate, .destroy = cifs_idmap_key_destroy, .describe = user_describe, @@ -435,51 +423,6 @@ cifs_destroy_idmaptrees(void) spin_unlock(&sidgidlock); } -int match_sid(struct cifs_sid *ctsid) -{ - int i, j; - int num_subauth, num_sat, num_saw; - struct cifs_sid *cwsid; - - if (!ctsid) - return -1; - - for (i = 0; i < NUM_WK_SIDS; ++i) { - cwsid = &(wksidarr[i].cifssid); - - /* compare the revision */ - if (ctsid->revision != cwsid->revision) - continue; - - /* compare all of the six auth values */ - for (j = 0; j < 6; ++j) { - if (ctsid->authority[j] != cwsid->authority[j]) - break; - } - if (j < 6) - continue; /* all of the auth values did not match */ - - /* compare all of the subauth values if any */ - num_sat = ctsid->num_subauth; - num_saw = cwsid->num_subauth; - num_subauth = num_sat < num_saw ? num_sat : num_saw; - if (num_subauth) { - for (j = 0; j < num_subauth; ++j) { - if (ctsid->sub_auth[j] != cwsid->sub_auth[j]) - break; - } - if (j < num_subauth) - continue; /* all sub_auth values do not match */ - } - - cFYI(1, "matching sid: %s\n", wksidarr[i].sidname); - return 0; /* sids compare/match */ - } - - cFYI(1, "No matching sid"); - return -1; -} - /* if the two SIDs (roughly equivalent to a UUID for a user or group) are the same returns 1, if they do not match returns 0 */ int compare_sids(const struct cifs_sid *ctsid, const struct cifs_sid *cwsid) diff --git a/fs/cifs/cifsacl.h b/fs/cifs/cifsacl.h index 757cf5a..5c902c7 100644 --- a/fs/cifs/cifsacl.h +++ b/fs/cifs/cifsacl.h @@ -98,7 +98,6 @@ extern struct key_type cifs_idmap_key_type; extern const struct cred *root_cred; #endif /* KERNEL */ -extern int match_sid(struct cifs_sid *); extern int compare_sids(const struct cifs_sid *, const struct cifs_sid *); #endif /* _CIFSACL_H */ diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c index 2b8e47e..ed92c7d 100644 --- a/fs/cifs/cifsfs.c +++ b/fs/cifs/cifsfs.c @@ -1046,21 +1046,23 @@ init_cifs(void) #ifdef CONFIG_CIFS_ACL rc = init_cifs_idmap(); if (rc) - goto out_destroy_request_bufs; + goto out_register_key_type; #endif /* CONFIG_CIFS_ACL */ rc = register_filesystem(&cifs_fs_type); if (rc) - goto out_destroy_request_bufs; + goto out_init_cifs_idmap; return 0; -out_destroy_request_bufs: +out_init_cifs_idmap: #ifdef CONFIG_CIFS_ACL exit_cifs_idmap(); +out_register_key_type: #endif #ifdef CONFIG_CIFS_UPCALL unregister_key_type(&cifs_spnego_key_type); +out_destroy_request_bufs: #endif cifs_destroy_request_bufs(); out_destroy_mids: -- cgit v0.10.2 From 4e64fb33dea9c4cad0106760c49c7629d4c699a5 Mon Sep 17 00:00:00 2001 From: Steve French Date: Wed, 18 May 2011 18:08:28 +0000 Subject: [CIFS] Update cifs to version 1.72 Signed-off-by: Steve French diff --git a/fs/cifs/cifsfs.h b/fs/cifs/cifsfs.h index d304584..64313f7 100644 --- a/fs/cifs/cifsfs.h +++ b/fs/cifs/cifsfs.h @@ -129,5 +129,5 @@ extern long cifs_ioctl(struct file *filep, unsigned int cmd, unsigned long arg); extern const struct export_operations cifs_export_ops; #endif /* CIFS_NFSD_EXPORT */ -#define CIFS_VERSION "1.71" +#define CIFS_VERSION "1.72" #endif /* _CIFSFS_H */ -- cgit v0.10.2 From ceec1e0fae6eecac876ec28cfb97786f87dfb1c6 Mon Sep 17 00:00:00 2001 From: Steve French Date: Mon, 14 Mar 2011 19:01:59 +0000 Subject: [CIFS] Remove sparse warning Move extern for cifsConvertToUCS to different header to prevent following warning: CHECK fs/cifs/cifs_unicode.c fs/cifs/cifs_unicode.c:267:1: warning: symbol 'cifsConvertToUCS' was not declared. Should it be static? Signed-off-by: Steve French Signed-off-by: Pavel Shilovsky Signed-off-by: Steve French diff --git a/fs/cifs/cifs_unicode.h b/fs/cifs/cifs_unicode.h index 644dd882..6d02fd5 100644 --- a/fs/cifs/cifs_unicode.h +++ b/fs/cifs/cifs_unicode.h @@ -82,6 +82,9 @@ int cifs_strtoUCS(__le16 *, const char *, int, const struct nls_table *); char *cifs_strndup_from_ucs(const char *src, const int maxlen, const bool is_unicode, const struct nls_table *codepage); +extern int cifsConvertToUCS(__le16 *target, const char *source, int maxlen, + const struct nls_table *cp, int mapChars); + #endif /* diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h index a1c94d3..6e69e06 100644 --- a/fs/cifs/cifsproto.h +++ b/fs/cifs/cifsproto.h @@ -353,8 +353,6 @@ extern int CIFSGetSrvInodeNumber(const int xid, struct cifsTconInfo *tcon, const unsigned char *searchName, __u64 *inode_number, const struct nls_table *nls_codepage, int remap_special_chars); -extern int cifsConvertToUCS(__le16 *target, const char *source, int maxlen, - const struct nls_table *cp, int mapChars); extern int CIFSSMBLock(const int xid, struct cifsTconInfo *tcon, const __u16 netfid, const __u64 len, -- cgit v0.10.2 From 3f508953dd2ebcbcd32d28d0b6aad4d76980e722 Mon Sep 17 00:00:00 2001 From: Daniel Kiper Date: Thu, 12 May 2011 17:19:53 -0400 Subject: arch/x86/xen/mmu: Cleanup code/data sections definitions Cleanup code/data sections definitions accordingly to include/linux/init.h. Signed-off-by: Daniel Kiper [v1: Rebased on top of latest linus's to include fixes in mmu.c] Signed-off-by: Konrad Rzeszutek Wilk diff --git a/arch/x86/xen/mmu.c b/arch/x86/xen/mmu.c index 0684f3c..b5f776f 100644 --- a/arch/x86/xen/mmu.c +++ b/arch/x86/xen/mmu.c @@ -1054,7 +1054,7 @@ void xen_mm_pin_all(void) * that's before we have page structures to store the bits. So do all * the book-keeping now. */ -static __init int xen_mark_pinned(struct mm_struct *mm, struct page *page, +static int __init xen_mark_pinned(struct mm_struct *mm, struct page *page, enum pt_level level) { SetPagePinned(page); @@ -1271,7 +1271,7 @@ void xen_exit_mmap(struct mm_struct *mm) spin_unlock(&mm->page_table_lock); } -static __init void xen_pagetable_setup_start(pgd_t *base) +static void __init xen_pagetable_setup_start(pgd_t *base) { } @@ -1291,7 +1291,7 @@ static __init void xen_mapping_pagetable_reserve(u64 start, u64 end) static void xen_post_allocator_init(void); -static __init void xen_pagetable_setup_done(pgd_t *base) +static void __init xen_pagetable_setup_done(pgd_t *base) { xen_setup_shared_info(); xen_post_allocator_init(); @@ -1488,7 +1488,7 @@ static void xen_pgd_free(struct mm_struct *mm, pgd_t *pgd) } #ifdef CONFIG_X86_32 -static __init pte_t mask_rw_pte(pte_t *ptep, pte_t pte) +static pte_t __init mask_rw_pte(pte_t *ptep, pte_t pte) { /* If there's an existing pte, then don't allow _PAGE_RW to be set */ if (pte_val_ma(*ptep) & _PAGE_PRESENT) @@ -1498,7 +1498,7 @@ static __init pte_t mask_rw_pte(pte_t *ptep, pte_t pte) return pte; } #else /* CONFIG_X86_64 */ -static __init pte_t mask_rw_pte(pte_t *ptep, pte_t pte) +static pte_t __init mask_rw_pte(pte_t *ptep, pte_t pte) { unsigned long pfn = pte_pfn(pte); @@ -1519,7 +1519,7 @@ static __init pte_t mask_rw_pte(pte_t *ptep, pte_t pte) /* Init-time set_pte while constructing initial pagetables, which doesn't allow RO pagetable pages to be remapped RW */ -static __init void xen_set_pte_init(pte_t *ptep, pte_t pte) +static void __init xen_set_pte_init(pte_t *ptep, pte_t pte) { pte = mask_rw_pte(ptep, pte); @@ -1537,7 +1537,7 @@ static void pin_pagetable_pfn(unsigned cmd, unsigned long pfn) /* Early in boot, while setting up the initial pagetable, assume everything is pinned. */ -static __init void xen_alloc_pte_init(struct mm_struct *mm, unsigned long pfn) +static void __init xen_alloc_pte_init(struct mm_struct *mm, unsigned long pfn) { #ifdef CONFIG_FLATMEM BUG_ON(mem_map); /* should only be used early */ @@ -1547,7 +1547,7 @@ static __init void xen_alloc_pte_init(struct mm_struct *mm, unsigned long pfn) } /* Used for pmd and pud */ -static __init void xen_alloc_pmd_init(struct mm_struct *mm, unsigned long pfn) +static void __init xen_alloc_pmd_init(struct mm_struct *mm, unsigned long pfn) { #ifdef CONFIG_FLATMEM BUG_ON(mem_map); /* should only be used early */ @@ -1557,13 +1557,13 @@ static __init void xen_alloc_pmd_init(struct mm_struct *mm, unsigned long pfn) /* Early release_pte assumes that all pts are pinned, since there's only init_mm and anything attached to that is pinned. */ -static __init void xen_release_pte_init(unsigned long pfn) +static void __init xen_release_pte_init(unsigned long pfn) { pin_pagetable_pfn(MMUEXT_UNPIN_TABLE, pfn); make_lowmem_page_readwrite(__va(PFN_PHYS(pfn))); } -static __init void xen_release_pmd_init(unsigned long pfn) +static void __init xen_release_pmd_init(unsigned long pfn) { make_lowmem_page_readwrite(__va(PFN_PHYS(pfn))); } @@ -1689,7 +1689,7 @@ static void set_page_prot(void *addr, pgprot_t prot) BUG(); } -static __init void xen_map_identity_early(pmd_t *pmd, unsigned long max_pfn) +static void __init xen_map_identity_early(pmd_t *pmd, unsigned long max_pfn) { unsigned pmdidx, pteidx; unsigned ident_pte; @@ -1772,7 +1772,7 @@ static void convert_pfn_mfn(void *v) * of the physical mapping once some sort of allocator has been set * up. */ -__init pgd_t *xen_setup_kernel_pagetable(pgd_t *pgd, +pgd_t * __init xen_setup_kernel_pagetable(pgd_t *pgd, unsigned long max_pfn) { pud_t *l3; @@ -1843,7 +1843,7 @@ __init pgd_t *xen_setup_kernel_pagetable(pgd_t *pgd, static RESERVE_BRK_ARRAY(pmd_t, initial_kernel_pmd, PTRS_PER_PMD); static RESERVE_BRK_ARRAY(pmd_t, swapper_kernel_pmd, PTRS_PER_PMD); -static __init void xen_write_cr3_init(unsigned long cr3) +static void __init xen_write_cr3_init(unsigned long cr3) { unsigned long pfn = PFN_DOWN(__pa(swapper_pg_dir)); @@ -1880,7 +1880,7 @@ static __init void xen_write_cr3_init(unsigned long cr3) pv_mmu_ops.write_cr3 = &xen_write_cr3; } -__init pgd_t *xen_setup_kernel_pagetable(pgd_t *pgd, +pgd_t * __init xen_setup_kernel_pagetable(pgd_t *pgd, unsigned long max_pfn) { pmd_t *kernel_pmd; @@ -1986,7 +1986,7 @@ static void xen_set_fixmap(unsigned idx, phys_addr_t phys, pgprot_t prot) #endif } -__init void xen_ident_map_ISA(void) +void __init xen_ident_map_ISA(void) { unsigned long pa; @@ -2009,7 +2009,7 @@ __init void xen_ident_map_ISA(void) xen_flush_tlb(); } -static __init void xen_post_allocator_init(void) +static void __init xen_post_allocator_init(void) { #ifdef CONFIG_XEN_DEBUG pv_mmu_ops.make_pte = PV_CALLEE_SAVE(xen_make_pte_debug); @@ -2046,7 +2046,7 @@ static void xen_leave_lazy_mmu(void) preempt_enable(); } -static const struct pv_mmu_ops xen_mmu_ops __initdata = { +static const struct pv_mmu_ops xen_mmu_ops __initconst = { .read_cr2 = xen_read_cr2, .write_cr2 = xen_write_cr2, -- cgit v0.10.2 From ad7ba09e658f8e890797ed168dfb3f84be934b09 Mon Sep 17 00:00:00 2001 From: Daniel Kiper Date: Wed, 4 May 2011 20:19:15 +0200 Subject: arch/x86/xen/xen-ops: Cleanup code/data sections definitions Cleanup code/data sections definitions accordingly to include/linux/init.h. Signed-off-by: Daniel Kiper Signed-off-by: Konrad Rzeszutek Wilk diff --git a/arch/x86/xen/xen-ops.h b/arch/x86/xen/xen-ops.h index 3112f55..97dfdc8 100644 --- a/arch/x86/xen/xen-ops.h +++ b/arch/x86/xen/xen-ops.h @@ -74,7 +74,7 @@ static inline void xen_hvm_smp_init(void) {} #ifdef CONFIG_PARAVIRT_SPINLOCKS void __init xen_init_spinlocks(void); -__cpuinit void xen_init_lock_cpu(int cpu); +void __cpuinit xen_init_lock_cpu(int cpu); void xen_uninit_lock_cpu(int cpu); #else static inline void xen_init_spinlocks(void) -- cgit v0.10.2 From fb6ce5dea4bb704bfcd9fda7e6b1354da66f4d2f Mon Sep 17 00:00:00 2001 From: Daniel Kiper Date: Wed, 4 May 2011 20:18:45 +0200 Subject: arch/x86/xen/time: Cleanup code/data sections definitions Cleanup code/data sections definitions accordingly to include/linux/init.h. Signed-off-by: Daniel Kiper Signed-off-by: Konrad Rzeszutek Wilk diff --git a/arch/x86/xen/time.c b/arch/x86/xen/time.c index 2e2d370..bd4ffd7 100644 --- a/arch/x86/xen/time.c +++ b/arch/x86/xen/time.c @@ -439,11 +439,11 @@ void xen_timer_resume(void) } } -static const struct pv_time_ops xen_time_ops __initdata = { +static const struct pv_time_ops xen_time_ops __initconst = { .sched_clock = xen_clocksource_read, }; -static __init void xen_time_init(void) +static void __init xen_time_init(void) { int cpu = smp_processor_id(); struct timespec tp; @@ -468,7 +468,7 @@ static __init void xen_time_init(void) xen_setup_cpu_clockevents(); } -__init void xen_init_time_ops(void) +void __init xen_init_time_ops(void) { pv_time_ops = xen_time_ops; @@ -490,7 +490,7 @@ static void xen_hvm_setup_cpu_clockevents(void) xen_setup_cpu_clockevents(); } -__init void xen_hvm_init_time_ops(void) +void __init xen_hvm_init_time_ops(void) { /* vector callback is needed otherwise we cannot receive interrupts * on cpu > 0 and at this point we don't know how many cpus are -- cgit v0.10.2 From b53cedebd74918237176520f9157deb7ae066b71 Mon Sep 17 00:00:00 2001 From: Daniel Kiper Date: Wed, 4 May 2011 20:18:05 +0200 Subject: arch/x86/xen/smp: Cleanup code/data sections definitions Cleanup code/data sections definitions accordingly to include/linux/init.h. Signed-off-by: Daniel Kiper Signed-off-by: Konrad Rzeszutek Wilk diff --git a/arch/x86/xen/smp.c b/arch/x86/xen/smp.c index 3061244..194a3ed 100644 --- a/arch/x86/xen/smp.c +++ b/arch/x86/xen/smp.c @@ -57,7 +57,7 @@ static irqreturn_t xen_reschedule_interrupt(int irq, void *dev_id) return IRQ_HANDLED; } -static __cpuinit void cpu_bringup(void) +static void __cpuinit cpu_bringup(void) { int cpu = smp_processor_id(); @@ -85,7 +85,7 @@ static __cpuinit void cpu_bringup(void) wmb(); /* make sure everything is out */ } -static __cpuinit void cpu_bringup_and_idle(void) +static void __cpuinit cpu_bringup_and_idle(void) { cpu_bringup(); cpu_idle(); @@ -242,7 +242,7 @@ static void __init xen_smp_prepare_cpus(unsigned int max_cpus) } } -static __cpuinit int +static int __cpuinit cpu_initialize_context(unsigned int cpu, struct task_struct *idle) { struct vcpu_guest_context *ctxt; @@ -486,7 +486,7 @@ static irqreturn_t xen_call_function_single_interrupt(int irq, void *dev_id) return IRQ_HANDLED; } -static const struct smp_ops xen_smp_ops __initdata = { +static const struct smp_ops xen_smp_ops __initconst = { .smp_prepare_boot_cpu = xen_smp_prepare_boot_cpu, .smp_prepare_cpus = xen_smp_prepare_cpus, .smp_cpus_done = xen_smp_cpus_done, -- cgit v0.10.2 From 887cb45694f77d59de19674cb73146fec72fadbb Mon Sep 17 00:00:00 2001 From: Daniel Kiper Date: Wed, 4 May 2011 20:19:49 +0200 Subject: drivers/xen/sys-hypervisor: Cleanup code/data sections definitions Cleanup code/data sections definitions accordingly to include/linux/init.h. Signed-off-by: Daniel Kiper Signed-off-by: Konrad Rzeszutek Wilk diff --git a/drivers/xen/sys-hypervisor.c b/drivers/xen/sys-hypervisor.c index 60f1827..1e0fe01 100644 --- a/drivers/xen/sys-hypervisor.c +++ b/drivers/xen/sys-hypervisor.c @@ -215,7 +215,7 @@ static struct attribute_group xen_compilation_group = { .attrs = xen_compile_attrs, }; -int __init static xen_compilation_init(void) +static int __init xen_compilation_init(void) { return sysfs_create_group(hypervisor_kobj, &xen_compilation_group); } -- cgit v0.10.2 From 359c47ea71be21c1105ae474e8c90ec3e988bbdf Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Sun, 3 Apr 2011 13:32:00 +0200 Subject: m68k: bitops - offset == ((long)p - (long)vaddr) * 8 Hence use "offset" in find_next_{,zero_}bit(), like is already done for find_next_{,zero_}bit_le() Signed-off-by: Geert Uytterhoeven Cc: Akinobu Mita Cc: Andreas Schwab Signed-off-by: Geert Uytterhoeven diff --git a/arch/m68k/include/asm/bitops_mm.h b/arch/m68k/include/asm/bitops_mm.h index 9d69f6e..5bd3afa 100644 --- a/arch/m68k/include/asm/bitops_mm.h +++ b/arch/m68k/include/asm/bitops_mm.h @@ -220,8 +220,7 @@ static inline int find_next_zero_bit(const unsigned long *vaddr, int size, offset += 32; } /* No zero yet, search remaining full bytes for a zero */ - res = find_first_zero_bit(p, size - ((long)p - (long)vaddr) * 8); - return offset + res; + return offset + find_first_zero_bit(p, size - offset); } static inline int find_first_bit(const unsigned long *vaddr, unsigned size) @@ -267,8 +266,7 @@ static inline int find_next_bit(const unsigned long *vaddr, int size, offset += 32; } /* No one yet, search remaining full bytes for a one */ - res = find_first_bit(p, size - ((long)p - (long)vaddr) * 8); - return offset + res; + return offset + find_first_bit(p, size - offset); } /* -- cgit v0.10.2 From f82a519f1262963d6ab30fa238721463fad2e0c8 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Sun, 3 Apr 2011 14:00:10 +0200 Subject: m68k: bitops - Never step beyond the end of the bitmap find_next bitops on m68k (find_next_zero_bit, find_next_bit, and find_next_bit_le) may cause out of bounds memory access when the bitmap size in bits % 32 != 0 and offset (the bitnumber to start searching at) is very close to the bitmap size. For example, unsigned long bitmap[2] = { 0, 0 }; find_next_bit(bitmap, 63, 62); 1. find_next_bit() tries to find any set bits in bitmap[1], but no bits set. 2. Then find_first_bit(bimap + 2, -1) 3. Unfortunately find_first_bit() takes unsigned int as the size argument. 4. find_first_bit will access bitmap[2~] until it find any set bits. Add missing tests for stepping beyond the end of the bitmap to all find_{first,next}_*() functions, and make sure they never return a value larger than the bitmap size. Reported-by: Akinobu Mita Cc: Andreas Schwab Signed-off-by: Geert Uytterhoeven diff --git a/arch/m68k/include/asm/bitops_mm.h b/arch/m68k/include/asm/bitops_mm.h index 5bd3afa..e9020f8 100644 --- a/arch/m68k/include/asm/bitops_mm.h +++ b/arch/m68k/include/asm/bitops_mm.h @@ -181,14 +181,15 @@ static inline int find_first_zero_bit(const unsigned long *vaddr, { const unsigned long *p = vaddr; int res = 32; + unsigned int words; unsigned long num; if (!size) return 0; - size = (size + 31) >> 5; + words = (size + 31) >> 5; while (!(num = ~*p++)) { - if (!--size) + if (!--words) goto out; } @@ -196,7 +197,8 @@ static inline int find_first_zero_bit(const unsigned long *vaddr, : "=d" (res) : "d" (num & -num)); res ^= 31; out: - return ((long)p - (long)vaddr - 4) * 8 + res; + res += ((long)p - (long)vaddr - 4) * 8; + return res < size ? res : size; } static inline int find_next_zero_bit(const unsigned long *vaddr, int size, @@ -215,9 +217,14 @@ static inline int find_next_zero_bit(const unsigned long *vaddr, int size, /* Look for zero in first longword */ __asm__ __volatile__ ("bfffo %1{#0,#0},%0" : "=d" (res) : "d" (num & -num)); - if (res < 32) - return offset + (res ^ 31); + if (res < 32) { + offset += res ^ 31; + return offset < size ? offset : size; + } offset += 32; + + if (offset >= size) + return size; } /* No zero yet, search remaining full bytes for a zero */ return offset + find_first_zero_bit(p, size - offset); @@ -227,14 +234,15 @@ static inline int find_first_bit(const unsigned long *vaddr, unsigned size) { const unsigned long *p = vaddr; int res = 32; + unsigned int words; unsigned long num; if (!size) return 0; - size = (size + 31) >> 5; + words = (size + 31) >> 5; while (!(num = *p++)) { - if (!--size) + if (!--words) goto out; } @@ -242,7 +250,8 @@ static inline int find_first_bit(const unsigned long *vaddr, unsigned size) : "=d" (res) : "d" (num & -num)); res ^= 31; out: - return ((long)p - (long)vaddr - 4) * 8 + res; + res += ((long)p - (long)vaddr - 4) * 8; + return res < size ? res : size; } static inline int find_next_bit(const unsigned long *vaddr, int size, @@ -261,9 +270,14 @@ static inline int find_next_bit(const unsigned long *vaddr, int size, /* Look for one in first longword */ __asm__ __volatile__ ("bfffo %1{#0,#0},%0" : "=d" (res) : "d" (num & -num)); - if (res < 32) - return offset + (res ^ 31); + if (res < 32) { + offset += res ^ 31; + return offset < size ? offset : size; + } offset += 32; + + if (offset >= size) + return size; } /* No one yet, search remaining full bytes for a one */ return offset + find_first_bit(p, size - offset); @@ -364,23 +378,25 @@ static inline int test_bit_le(int nr, const void *vaddr) static inline int find_first_zero_bit_le(const void *vaddr, unsigned size) { const unsigned long *p = vaddr, *addr = vaddr; - int res; + int res = 0; + unsigned int words; if (!size) return 0; - size = (size >> 5) + ((size & 31) > 0); - while (*p++ == ~0UL) - { - if (--size == 0) - return (p - addr) << 5; + words = (size >> 5) + ((size & 31) > 0); + while (*p++ == ~0UL) { + if (--words == 0) + goto out; } --p; for (res = 0; res < 32; res++) if (!test_bit_le(res, p)) break; - return (p - addr) * 32 + res; +out: + res += (p - addr) * 32; + return res < size ? res : size; } static inline unsigned long find_next_zero_bit_le(const void *addr, @@ -398,10 +414,15 @@ static inline unsigned long find_next_zero_bit_le(const void *addr, offset -= bit; /* Look for zero in first longword */ for (res = bit; res < 32; res++) - if (!test_bit_le(res, p)) - return offset + res; + if (!test_bit_le(res, p)) { + offset += res; + return offset < size ? offset : size; + } p++; offset += 32; + + if (offset >= size) + return size; } /* No zero yet, search remaining full bytes for a zero */ return offset + find_first_zero_bit_le(p, size - offset); @@ -410,22 +431,25 @@ static inline unsigned long find_next_zero_bit_le(const void *addr, static inline int find_first_bit_le(const void *vaddr, unsigned size) { const unsigned long *p = vaddr, *addr = vaddr; - int res; + int res = 0; + unsigned int words; if (!size) return 0; - size = (size >> 5) + ((size & 31) > 0); + words = (size >> 5) + ((size & 31) > 0); while (*p++ == 0UL) { - if (--size == 0) - return (p - addr) << 5; + if (--words == 0) + goto out; } --p; for (res = 0; res < 32; res++) if (test_bit_le(res, p)) break; - return (p - addr) * 32 + res; +out: + res += (p - addr) * 32; + return res < size ? res : size; } static inline unsigned long find_next_bit_le(const void *addr, @@ -443,10 +467,15 @@ static inline unsigned long find_next_bit_le(const void *addr, offset -= bit; /* Look for one in first longword */ for (res = bit; res < 32; res++) - if (test_bit_le(res, p)) - return offset + res; + if (test_bit_le(res, p)) { + offset += res; + return offset < size ? offset : size; + } p++; offset += 32; + + if (offset >= size) + return size; } /* No set bit yet, search remaining full bytes for a set bit */ return offset + find_first_bit_le(p, size - offset); -- cgit v0.10.2 From 6cf515e113fc1938b3cc9812bd8519a4c6155ef9 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Sun, 24 Apr 2011 10:32:49 +0200 Subject: MAINTAINERS: Roman Zippel has been MIA for several years. Hence make AFFS and HFS orphans, and remove him as an m68k maintainer. Signed-off-by: Geert Uytterhoeven diff --git a/MAINTAINERS b/MAINTAINERS index 69f19f1..a01796e 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -405,8 +405,8 @@ S: Maintained F: sound/oss/aedsp16.c AFFS FILE SYSTEM -M: Roman Zippel -S: Maintained +L: linux-fsdevel@vger.kernel.org +S: Orphan F: Documentation/filesystems/affs.txt F: fs/affs/ @@ -2946,8 +2946,8 @@ F: drivers/block/cciss* F: include/linux/cciss_ioctl.h HFS FILESYSTEM -M: Roman Zippel -S: Maintained +L: linux-fsdevel@vger.kernel.org +S: Orphan F: Documentation/filesystems/hfs.txt F: fs/hfs/ @@ -4001,7 +4001,6 @@ F: arch/m32r/ M68K ARCHITECTURE M: Geert Uytterhoeven -M: Roman Zippel L: linux-m68k@lists.linux-m68k.org W: http://www.linux-m68k.org/ T: git git://git.kernel.org/pub/scm/linux/kernel/git/geert/linux-m68k.git -- cgit v0.10.2 From c4245c9d6535f3d02fda7f6eb9adcec9f09e8fe3 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Wed, 6 Apr 2011 22:12:53 +0200 Subject: m68k: Merge mmu and non-mmu versions of sys_call_table Impact for nommu: - Store table in .rodata instead of .text, - Let kernel/sys_ni.c handle the stubbing of MMU-only syscalls, - Implement sys_mremap and sys_nfsservct, - Remove unused padding at the end of the table. Impact for mmu: - Store table in .rodata instead of .data. Signed-off-by: Geert Uytterhoeven Acked-by: Greg Ungerer diff --git a/arch/m68k/kernel/Makefile_mm b/arch/m68k/kernel/Makefile_mm index 55d5d6b..aced678 100644 --- a/arch/m68k/kernel/Makefile_mm +++ b/arch/m68k/kernel/Makefile_mm @@ -10,7 +10,7 @@ endif extra-y += vmlinux.lds obj-y := entry.o process.o traps.o ints.o signal.o ptrace.o module.o \ - sys_m68k.o time.o setup.o m68k_ksyms.o devres.o + sys_m68k.o time.o setup.o m68k_ksyms.o devres.o syscalltable.o devres-y = ../../../kernel/irq/devres.o diff --git a/arch/m68k/kernel/entry_mm.S b/arch/m68k/kernel/entry_mm.S index 1359ee6..bd0ec05 100644 --- a/arch/m68k/kernel/entry_mm.S +++ b/arch/m68k/kernel/entry_mm.S @@ -407,351 +407,3 @@ resume: rts -.data -ALIGN -sys_call_table: - .long sys_restart_syscall /* 0 - old "setup()" system call, used for restarting */ - .long sys_exit - .long sys_fork - .long sys_read - .long sys_write - .long sys_open /* 5 */ - .long sys_close - .long sys_waitpid - .long sys_creat - .long sys_link - .long sys_unlink /* 10 */ - .long sys_execve - .long sys_chdir - .long sys_time - .long sys_mknod - .long sys_chmod /* 15 */ - .long sys_chown16 - .long sys_ni_syscall /* old break syscall holder */ - .long sys_stat - .long sys_lseek - .long sys_getpid /* 20 */ - .long sys_mount - .long sys_oldumount - .long sys_setuid16 - .long sys_getuid16 - .long sys_stime /* 25 */ - .long sys_ptrace - .long sys_alarm - .long sys_fstat - .long sys_pause - .long sys_utime /* 30 */ - .long sys_ni_syscall /* old stty syscall holder */ - .long sys_ni_syscall /* old gtty syscall holder */ - .long sys_access - .long sys_nice - .long sys_ni_syscall /* 35 */ /* old ftime syscall holder */ - .long sys_sync - .long sys_kill - .long sys_rename - .long sys_mkdir - .long sys_rmdir /* 40 */ - .long sys_dup - .long sys_pipe - .long sys_times - .long sys_ni_syscall /* old prof syscall holder */ - .long sys_brk /* 45 */ - .long sys_setgid16 - .long sys_getgid16 - .long sys_signal - .long sys_geteuid16 - .long sys_getegid16 /* 50 */ - .long sys_acct - .long sys_umount /* recycled never used phys() */ - .long sys_ni_syscall /* old lock syscall holder */ - .long sys_ioctl - .long sys_fcntl /* 55 */ - .long sys_ni_syscall /* old mpx syscall holder */ - .long sys_setpgid - .long sys_ni_syscall /* old ulimit syscall holder */ - .long sys_ni_syscall - .long sys_umask /* 60 */ - .long sys_chroot - .long sys_ustat - .long sys_dup2 - .long sys_getppid - .long sys_getpgrp /* 65 */ - .long sys_setsid - .long sys_sigaction - .long sys_sgetmask - .long sys_ssetmask - .long sys_setreuid16 /* 70 */ - .long sys_setregid16 - .long sys_sigsuspend - .long sys_sigpending - .long sys_sethostname - .long sys_setrlimit /* 75 */ - .long sys_old_getrlimit - .long sys_getrusage - .long sys_gettimeofday - .long sys_settimeofday - .long sys_getgroups16 /* 80 */ - .long sys_setgroups16 - .long sys_old_select - .long sys_symlink - .long sys_lstat - .long sys_readlink /* 85 */ - .long sys_uselib - .long sys_swapon - .long sys_reboot - .long sys_old_readdir - .long sys_old_mmap /* 90 */ - .long sys_munmap - .long sys_truncate - .long sys_ftruncate - .long sys_fchmod - .long sys_fchown16 /* 95 */ - .long sys_getpriority - .long sys_setpriority - .long sys_ni_syscall /* old profil syscall holder */ - .long sys_statfs - .long sys_fstatfs /* 100 */ - .long sys_ni_syscall /* ioperm for i386 */ - .long sys_socketcall - .long sys_syslog - .long sys_setitimer - .long sys_getitimer /* 105 */ - .long sys_newstat - .long sys_newlstat - .long sys_newfstat - .long sys_ni_syscall - .long sys_ni_syscall /* 110 */ /* iopl for i386 */ - .long sys_vhangup - .long sys_ni_syscall /* obsolete idle() syscall */ - .long sys_ni_syscall /* vm86old for i386 */ - .long sys_wait4 - .long sys_swapoff /* 115 */ - .long sys_sysinfo - .long sys_ipc - .long sys_fsync - .long sys_sigreturn - .long sys_clone /* 120 */ - .long sys_setdomainname - .long sys_newuname - .long sys_cacheflush /* modify_ldt for i386 */ - .long sys_adjtimex - .long sys_mprotect /* 125 */ - .long sys_sigprocmask - .long sys_ni_syscall /* old "create_module" */ - .long sys_init_module - .long sys_delete_module - .long sys_ni_syscall /* 130 - old "get_kernel_syms" */ - .long sys_quotactl - .long sys_getpgid - .long sys_fchdir - .long sys_bdflush - .long sys_sysfs /* 135 */ - .long sys_personality - .long sys_ni_syscall /* for afs_syscall */ - .long sys_setfsuid16 - .long sys_setfsgid16 - .long sys_llseek /* 140 */ - .long sys_getdents - .long sys_select - .long sys_flock - .long sys_msync - .long sys_readv /* 145 */ - .long sys_writev - .long sys_getsid - .long sys_fdatasync - .long sys_sysctl - .long sys_mlock /* 150 */ - .long sys_munlock - .long sys_mlockall - .long sys_munlockall - .long sys_sched_setparam - .long sys_sched_getparam /* 155 */ - .long sys_sched_setscheduler - .long sys_sched_getscheduler - .long sys_sched_yield - .long sys_sched_get_priority_max - .long sys_sched_get_priority_min /* 160 */ - .long sys_sched_rr_get_interval - .long sys_nanosleep - .long sys_mremap - .long sys_setresuid16 - .long sys_getresuid16 /* 165 */ - .long sys_getpagesize - .long sys_ni_syscall /* old sys_query_module */ - .long sys_poll - .long sys_nfsservctl - .long sys_setresgid16 /* 170 */ - .long sys_getresgid16 - .long sys_prctl - .long sys_rt_sigreturn - .long sys_rt_sigaction - .long sys_rt_sigprocmask /* 175 */ - .long sys_rt_sigpending - .long sys_rt_sigtimedwait - .long sys_rt_sigqueueinfo - .long sys_rt_sigsuspend - .long sys_pread64 /* 180 */ - .long sys_pwrite64 - .long sys_lchown16; - .long sys_getcwd - .long sys_capget - .long sys_capset /* 185 */ - .long sys_sigaltstack - .long sys_sendfile - .long sys_ni_syscall /* streams1 */ - .long sys_ni_syscall /* streams2 */ - .long sys_vfork /* 190 */ - .long sys_getrlimit - .long sys_mmap2 - .long sys_truncate64 - .long sys_ftruncate64 - .long sys_stat64 /* 195 */ - .long sys_lstat64 - .long sys_fstat64 - .long sys_chown - .long sys_getuid - .long sys_getgid /* 200 */ - .long sys_geteuid - .long sys_getegid - .long sys_setreuid - .long sys_setregid - .long sys_getgroups /* 205 */ - .long sys_setgroups - .long sys_fchown - .long sys_setresuid - .long sys_getresuid - .long sys_setresgid /* 210 */ - .long sys_getresgid - .long sys_lchown - .long sys_setuid - .long sys_setgid - .long sys_setfsuid /* 215 */ - .long sys_setfsgid - .long sys_pivot_root - .long sys_ni_syscall - .long sys_ni_syscall - .long sys_getdents64 /* 220 */ - .long sys_gettid - .long sys_tkill - .long sys_setxattr - .long sys_lsetxattr - .long sys_fsetxattr /* 225 */ - .long sys_getxattr - .long sys_lgetxattr - .long sys_fgetxattr - .long sys_listxattr - .long sys_llistxattr /* 230 */ - .long sys_flistxattr - .long sys_removexattr - .long sys_lremovexattr - .long sys_fremovexattr - .long sys_futex /* 235 */ - .long sys_sendfile64 - .long sys_mincore - .long sys_madvise - .long sys_fcntl64 - .long sys_readahead /* 240 */ - .long sys_io_setup - .long sys_io_destroy - .long sys_io_getevents - .long sys_io_submit - .long sys_io_cancel /* 245 */ - .long sys_fadvise64 - .long sys_exit_group - .long sys_lookup_dcookie - .long sys_epoll_create - .long sys_epoll_ctl /* 250 */ - .long sys_epoll_wait - .long sys_remap_file_pages - .long sys_set_tid_address - .long sys_timer_create - .long sys_timer_settime /* 255 */ - .long sys_timer_gettime - .long sys_timer_getoverrun - .long sys_timer_delete - .long sys_clock_settime - .long sys_clock_gettime /* 260 */ - .long sys_clock_getres - .long sys_clock_nanosleep - .long sys_statfs64 - .long sys_fstatfs64 - .long sys_tgkill /* 265 */ - .long sys_utimes - .long sys_fadvise64_64 - .long sys_mbind - .long sys_get_mempolicy - .long sys_set_mempolicy /* 270 */ - .long sys_mq_open - .long sys_mq_unlink - .long sys_mq_timedsend - .long sys_mq_timedreceive - .long sys_mq_notify /* 275 */ - .long sys_mq_getsetattr - .long sys_waitid - .long sys_ni_syscall /* for sys_vserver */ - .long sys_add_key - .long sys_request_key /* 280 */ - .long sys_keyctl - .long sys_ioprio_set - .long sys_ioprio_get - .long sys_inotify_init - .long sys_inotify_add_watch /* 285 */ - .long sys_inotify_rm_watch - .long sys_migrate_pages - .long sys_openat - .long sys_mkdirat - .long sys_mknodat /* 290 */ - .long sys_fchownat - .long sys_futimesat - .long sys_fstatat64 - .long sys_unlinkat - .long sys_renameat /* 295 */ - .long sys_linkat - .long sys_symlinkat - .long sys_readlinkat - .long sys_fchmodat - .long sys_faccessat /* 300 */ - .long sys_ni_syscall /* Reserved for pselect6 */ - .long sys_ni_syscall /* Reserved for ppoll */ - .long sys_unshare - .long sys_set_robust_list - .long sys_get_robust_list /* 305 */ - .long sys_splice - .long sys_sync_file_range - .long sys_tee - .long sys_vmsplice - .long sys_move_pages /* 310 */ - .long sys_sched_setaffinity - .long sys_sched_getaffinity - .long sys_kexec_load - .long sys_getcpu - .long sys_epoll_pwait /* 315 */ - .long sys_utimensat - .long sys_signalfd - .long sys_timerfd_create - .long sys_eventfd - .long sys_fallocate /* 320 */ - .long sys_timerfd_settime - .long sys_timerfd_gettime - .long sys_signalfd4 - .long sys_eventfd2 - .long sys_epoll_create1 /* 325 */ - .long sys_dup3 - .long sys_pipe2 - .long sys_inotify_init1 - .long sys_preadv - .long sys_pwritev /* 330 */ - .long sys_rt_tgsigqueueinfo - .long sys_perf_event_open - .long sys_get_thread_area - .long sys_set_thread_area - .long sys_atomic_cmpxchg_32 /* 335 */ - .long sys_atomic_barrier - .long sys_fanotify_init - .long sys_fanotify_mark - .long sys_prlimit64 - .long sys_name_to_handle_at /* 340 */ - .long sys_open_by_handle_at - .long sys_clock_adjtime - .long sys_syncfs - diff --git a/arch/m68k/kernel/syscalltable.S b/arch/m68k/kernel/syscalltable.S index 9b8393d..0284192 100644 --- a/arch/m68k/kernel/syscalltable.S +++ b/arch/m68k/kernel/syscalltable.S @@ -1,6 +1,4 @@ /* - * linux/arch/m68knommu/kernel/syscalltable.S - * * Copyright (C) 2002, Greg Ungerer (gerg@snapgear.com) * * Based on older entry.S files, the following copyrights apply: @@ -9,171 +7,176 @@ * Kenneth Albanowski , * Copyright (C) 2000 Lineo Inc. (www.lineo.com) * Copyright (C) 1991, 1992 Linus Torvalds + * + * Linux/m68k support by Hamish Macdonald */ #include #include -#include -.text +#ifndef CONFIG_MMU +#define sys_mmap2 sys_mmap_pgoff +#endif + +.section .rodata ALIGN ENTRY(sys_call_table) - .long sys_restart_syscall /* 0 - old "setup()" system call */ + .long sys_restart_syscall /* 0 - old "setup()" system call, used for restarting */ .long sys_exit .long sys_fork .long sys_read .long sys_write - .long sys_open /* 5 */ + .long sys_open /* 5 */ .long sys_close .long sys_waitpid .long sys_creat .long sys_link - .long sys_unlink /* 10 */ + .long sys_unlink /* 10 */ .long sys_execve .long sys_chdir .long sys_time .long sys_mknod - .long sys_chmod /* 15 */ + .long sys_chmod /* 15 */ .long sys_chown16 - .long sys_ni_syscall /* old break syscall holder */ + .long sys_ni_syscall /* old break syscall holder */ .long sys_stat .long sys_lseek - .long sys_getpid /* 20 */ + .long sys_getpid /* 20 */ .long sys_mount .long sys_oldumount .long sys_setuid16 .long sys_getuid16 - .long sys_stime /* 25 */ + .long sys_stime /* 25 */ .long sys_ptrace .long sys_alarm .long sys_fstat .long sys_pause - .long sys_utime /* 30 */ - .long sys_ni_syscall /* old stty syscall holder */ - .long sys_ni_syscall /* old gtty syscall holder */ + .long sys_utime /* 30 */ + .long sys_ni_syscall /* old stty syscall holder */ + .long sys_ni_syscall /* old gtty syscall holder */ .long sys_access .long sys_nice - .long sys_ni_syscall /* 35 */ /* old ftime syscall holder */ + .long sys_ni_syscall /* 35 - old ftime syscall holder */ .long sys_sync .long sys_kill .long sys_rename .long sys_mkdir - .long sys_rmdir /* 40 */ + .long sys_rmdir /* 40 */ .long sys_dup .long sys_pipe .long sys_times - .long sys_ni_syscall /* old prof syscall holder */ - .long sys_brk /* 45 */ + .long sys_ni_syscall /* old prof syscall holder */ + .long sys_brk /* 45 */ .long sys_setgid16 .long sys_getgid16 .long sys_signal .long sys_geteuid16 - .long sys_getegid16 /* 50 */ + .long sys_getegid16 /* 50 */ .long sys_acct - .long sys_umount /* recycled never used phys() */ - .long sys_ni_syscall /* old lock syscall holder */ + .long sys_umount /* recycled never used phys() */ + .long sys_ni_syscall /* old lock syscall holder */ .long sys_ioctl - .long sys_fcntl /* 55 */ - .long sys_ni_syscall /* old mpx syscall holder */ + .long sys_fcntl /* 55 */ + .long sys_ni_syscall /* old mpx syscall holder */ .long sys_setpgid - .long sys_ni_syscall /* old ulimit syscall holder */ + .long sys_ni_syscall /* old ulimit syscall holder */ .long sys_ni_syscall - .long sys_umask /* 60 */ + .long sys_umask /* 60 */ .long sys_chroot .long sys_ustat .long sys_dup2 .long sys_getppid - .long sys_getpgrp /* 65 */ + .long sys_getpgrp /* 65 */ .long sys_setsid .long sys_sigaction .long sys_sgetmask .long sys_ssetmask - .long sys_setreuid16 /* 70 */ + .long sys_setreuid16 /* 70 */ .long sys_setregid16 .long sys_sigsuspend .long sys_sigpending .long sys_sethostname - .long sys_setrlimit /* 75 */ + .long sys_setrlimit /* 75 */ .long sys_old_getrlimit .long sys_getrusage .long sys_gettimeofday .long sys_settimeofday - .long sys_getgroups16 /* 80 */ + .long sys_getgroups16 /* 80 */ .long sys_setgroups16 .long sys_old_select .long sys_symlink .long sys_lstat - .long sys_readlink /* 85 */ + .long sys_readlink /* 85 */ .long sys_uselib - .long sys_ni_syscall /* sys_swapon */ + .long sys_swapon .long sys_reboot .long sys_old_readdir - .long sys_old_mmap /* 90 */ + .long sys_old_mmap /* 90 */ .long sys_munmap .long sys_truncate .long sys_ftruncate .long sys_fchmod - .long sys_fchown16 /* 95 */ + .long sys_fchown16 /* 95 */ .long sys_getpriority .long sys_setpriority - .long sys_ni_syscall /* old profil syscall holder */ + .long sys_ni_syscall /* old profil syscall holder */ .long sys_statfs - .long sys_fstatfs /* 100 */ - .long sys_ni_syscall /* ioperm for i386 */ + .long sys_fstatfs /* 100 */ + .long sys_ni_syscall /* ioperm for i386 */ .long sys_socketcall .long sys_syslog .long sys_setitimer - .long sys_getitimer /* 105 */ + .long sys_getitimer /* 105 */ .long sys_newstat .long sys_newlstat .long sys_newfstat .long sys_ni_syscall - .long sys_ni_syscall /* iopl for i386 */ /* 110 */ + .long sys_ni_syscall /* 110 - iopl for i386 */ .long sys_vhangup - .long sys_ni_syscall /* obsolete idle() syscall */ - .long sys_ni_syscall /* vm86old for i386 */ + .long sys_ni_syscall /* obsolete idle() syscall */ + .long sys_ni_syscall /* vm86old for i386 */ .long sys_wait4 - .long sys_ni_syscall /* 115 */ /* sys_swapoff */ + .long sys_swapoff /* 115 */ .long sys_sysinfo .long sys_ipc .long sys_fsync .long sys_sigreturn - .long sys_clone /* 120 */ + .long sys_clone /* 120 */ .long sys_setdomainname .long sys_newuname - .long sys_cacheflush /* modify_ldt for i386 */ + .long sys_cacheflush /* modify_ldt for i386 */ .long sys_adjtimex - .long sys_ni_syscall /* 125 */ /* sys_mprotect */ + .long sys_mprotect /* 125 */ .long sys_sigprocmask - .long sys_ni_syscall /* old "creat_module" */ + .long sys_ni_syscall /* old "create_module" */ .long sys_init_module .long sys_delete_module - .long sys_ni_syscall /* 130: old "get_kernel_syms" */ + .long sys_ni_syscall /* 130 - old "get_kernel_syms" */ .long sys_quotactl .long sys_getpgid .long sys_fchdir .long sys_bdflush - .long sys_sysfs /* 135 */ + .long sys_sysfs /* 135 */ .long sys_personality - .long sys_ni_syscall /* for afs_syscall */ + .long sys_ni_syscall /* for afs_syscall */ .long sys_setfsuid16 .long sys_setfsgid16 - .long sys_llseek /* 140 */ + .long sys_llseek /* 140 */ .long sys_getdents .long sys_select .long sys_flock - .long sys_ni_syscall /* sys_msync */ - .long sys_readv /* 145 */ + .long sys_msync + .long sys_readv /* 145 */ .long sys_writev .long sys_getsid .long sys_fdatasync .long sys_sysctl - .long sys_ni_syscall /* 150 */ /* sys_mlock */ - .long sys_ni_syscall /* sys_munlock */ - .long sys_ni_syscall /* sys_mlockall */ - .long sys_ni_syscall /* sys_munlockall */ + .long sys_mlock /* 150 */ + .long sys_munlock + .long sys_mlockall + .long sys_munlockall .long sys_sched_setparam - .long sys_sched_getparam /* 155 */ + .long sys_sched_getparam /* 155 */ .long sys_sched_setscheduler .long sys_sched_getscheduler .long sys_sched_yield @@ -181,124 +184,124 @@ ENTRY(sys_call_table) .long sys_sched_get_priority_min /* 160 */ .long sys_sched_rr_get_interval .long sys_nanosleep - .long sys_ni_syscall /* sys_mremap */ + .long sys_mremap .long sys_setresuid16 - .long sys_getresuid16 /* 165 */ - .long sys_getpagesize /* sys_getpagesize */ - .long sys_ni_syscall /* old "query_module" */ + .long sys_getresuid16 /* 165 */ + .long sys_getpagesize + .long sys_ni_syscall /* old "query_module" */ .long sys_poll - .long sys_ni_syscall /* sys_nfsservctl */ - .long sys_setresgid16 /* 170 */ + .long sys_nfsservctl + .long sys_setresgid16 /* 170 */ .long sys_getresgid16 .long sys_prctl .long sys_rt_sigreturn .long sys_rt_sigaction - .long sys_rt_sigprocmask /* 175 */ + .long sys_rt_sigprocmask /* 175 */ .long sys_rt_sigpending .long sys_rt_sigtimedwait .long sys_rt_sigqueueinfo .long sys_rt_sigsuspend - .long sys_pread64 /* 180 */ + .long sys_pread64 /* 180 */ .long sys_pwrite64 .long sys_lchown16 .long sys_getcwd .long sys_capget - .long sys_capset /* 185 */ + .long sys_capset /* 185 */ .long sys_sigaltstack .long sys_sendfile - .long sys_ni_syscall /* streams1 */ - .long sys_ni_syscall /* streams2 */ - .long sys_vfork /* 190 */ + .long sys_ni_syscall /* streams1 */ + .long sys_ni_syscall /* streams2 */ + .long sys_vfork /* 190 */ .long sys_getrlimit - .long sys_mmap_pgoff + .long sys_mmap2 .long sys_truncate64 .long sys_ftruncate64 - .long sys_stat64 /* 195 */ + .long sys_stat64 /* 195 */ .long sys_lstat64 .long sys_fstat64 .long sys_chown .long sys_getuid - .long sys_getgid /* 200 */ + .long sys_getgid /* 200 */ .long sys_geteuid .long sys_getegid .long sys_setreuid .long sys_setregid - .long sys_getgroups /* 205 */ + .long sys_getgroups /* 205 */ .long sys_setgroups .long sys_fchown .long sys_setresuid .long sys_getresuid - .long sys_setresgid /* 210 */ + .long sys_setresgid /* 210 */ .long sys_getresgid .long sys_lchown .long sys_setuid .long sys_setgid - .long sys_setfsuid /* 215 */ + .long sys_setfsuid /* 215 */ .long sys_setfsgid .long sys_pivot_root .long sys_ni_syscall .long sys_ni_syscall - .long sys_getdents64 /* 220 */ + .long sys_getdents64 /* 220 */ .long sys_gettid .long sys_tkill .long sys_setxattr .long sys_lsetxattr - .long sys_fsetxattr /* 225 */ + .long sys_fsetxattr /* 225 */ .long sys_getxattr .long sys_lgetxattr .long sys_fgetxattr .long sys_listxattr - .long sys_llistxattr /* 230 */ + .long sys_llistxattr /* 230 */ .long sys_flistxattr .long sys_removexattr .long sys_lremovexattr .long sys_fremovexattr - .long sys_futex /* 235 */ + .long sys_futex /* 235 */ .long sys_sendfile64 - .long sys_ni_syscall /* sys_mincore */ - .long sys_ni_syscall /* sys_madvise */ + .long sys_mincore + .long sys_madvise .long sys_fcntl64 - .long sys_readahead /* 240 */ + .long sys_readahead /* 240 */ .long sys_io_setup .long sys_io_destroy .long sys_io_getevents .long sys_io_submit - .long sys_io_cancel /* 245 */ + .long sys_io_cancel /* 245 */ .long sys_fadvise64 .long sys_exit_group .long sys_lookup_dcookie .long sys_epoll_create - .long sys_epoll_ctl /* 250 */ + .long sys_epoll_ctl /* 250 */ .long sys_epoll_wait - .long sys_ni_syscall /* sys_remap_file_pages */ + .long sys_remap_file_pages .long sys_set_tid_address .long sys_timer_create - .long sys_timer_settime /* 255 */ + .long sys_timer_settime /* 255 */ .long sys_timer_gettime .long sys_timer_getoverrun .long sys_timer_delete .long sys_clock_settime - .long sys_clock_gettime /* 260 */ + .long sys_clock_gettime /* 260 */ .long sys_clock_getres .long sys_clock_nanosleep .long sys_statfs64 .long sys_fstatfs64 - .long sys_tgkill /* 265 */ + .long sys_tgkill /* 265 */ .long sys_utimes .long sys_fadvise64_64 - .long sys_mbind + .long sys_mbind .long sys_get_mempolicy - .long sys_set_mempolicy /* 270 */ + .long sys_set_mempolicy /* 270 */ .long sys_mq_open .long sys_mq_unlink .long sys_mq_timedsend .long sys_mq_timedreceive - .long sys_mq_notify /* 275 */ + .long sys_mq_notify /* 275 */ .long sys_mq_getsetattr .long sys_waitid - .long sys_ni_syscall /* for sys_vserver */ + .long sys_ni_syscall /* for sys_vserver */ .long sys_add_key - .long sys_request_key /* 280 */ + .long sys_request_key /* 280 */ .long sys_keyctl .long sys_ioprio_set .long sys_ioprio_get @@ -363,7 +366,3 @@ ENTRY(sys_call_table) .long sys_clock_adjtime .long sys_syncfs - .rept NR_syscalls-(.-sys_call_table)/4 - .long sys_ni_syscall - .endr - -- cgit v0.10.2 From d6d42bb2f85d875dc0c421699de5a1401b2af6a6 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Fri, 6 May 2011 20:57:11 +0200 Subject: m68k: Really wire up sys_pselect6 and sys_ppoll We reserved the numbers a long time ago, but never wired them up in the syscall table as they need TIF_RESTORE_SIGMASK, which we only got last year in commit cb6831d5d3099e772a510eb3e1ed0760ccffb45e ("m68k: Switch to saner sigsuspend()") Signed-off-by: Geert Uytterhoeven Acked-by: Greg Ungerer Cc: stable@kernel.org diff --git a/arch/m68k/kernel/syscalltable.S b/arch/m68k/kernel/syscalltable.S index 0284192..5909e39 100644 --- a/arch/m68k/kernel/syscalltable.S +++ b/arch/m68k/kernel/syscalltable.S @@ -322,8 +322,8 @@ ENTRY(sys_call_table) .long sys_readlinkat .long sys_fchmodat .long sys_faccessat /* 300 */ - .long sys_ni_syscall /* Reserved for pselect6 */ - .long sys_ni_syscall /* Reserved for ppoll */ + .long sys_pselect6 + .long sys_ppoll .long sys_unshare .long sys_set_robust_list .long sys_get_robust_list /* 305 */ -- cgit v0.10.2 From 1fc74ac61229edfe053fb87e8939ae9ca3794389 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Thu, 5 May 2011 20:33:02 +0200 Subject: m68k: unistd - Comment out definitions for unimplemented syscalls Suggested-by: Arnd Bergmann Signed-off-by: Geert Uytterhoeven diff --git a/arch/m68k/include/asm/unistd.h b/arch/m68k/include/asm/unistd.h index 29e1790..f3b649d 100644 --- a/arch/m68k/include/asm/unistd.h +++ b/arch/m68k/include/asm/unistd.h @@ -22,7 +22,7 @@ #define __NR_mknod 14 #define __NR_chmod 15 #define __NR_chown 16 -#define __NR_break 17 +/*#define __NR_break 17*/ #define __NR_oldstat 18 #define __NR_lseek 19 #define __NR_getpid 20 @@ -36,11 +36,11 @@ #define __NR_oldfstat 28 #define __NR_pause 29 #define __NR_utime 30 -#define __NR_stty 31 -#define __NR_gtty 32 +/*#define __NR_stty 31*/ +/*#define __NR_gtty 32*/ #define __NR_access 33 #define __NR_nice 34 -#define __NR_ftime 35 +/*#define __NR_ftime 35*/ #define __NR_sync 36 #define __NR_kill 37 #define __NR_rename 38 @@ -49,7 +49,7 @@ #define __NR_dup 41 #define __NR_pipe 42 #define __NR_times 43 -#define __NR_prof 44 +/*#define __NR_prof 44*/ #define __NR_brk 45 #define __NR_setgid 46 #define __NR_getgid 47 @@ -58,13 +58,13 @@ #define __NR_getegid 50 #define __NR_acct 51 #define __NR_umount2 52 -#define __NR_lock 53 +/*#define __NR_lock 53*/ #define __NR_ioctl 54 #define __NR_fcntl 55 -#define __NR_mpx 56 +/*#define __NR_mpx 56*/ #define __NR_setpgid 57 -#define __NR_ulimit 58 -#define __NR_oldolduname 59 +/*#define __NR_ulimit 58*/ +/*#define __NR_oldolduname 59*/ #define __NR_umask 60 #define __NR_chroot 61 #define __NR_ustat 62 @@ -103,10 +103,10 @@ #define __NR_fchown 95 #define __NR_getpriority 96 #define __NR_setpriority 97 -#define __NR_profil 98 +/*#define __NR_profil 98*/ #define __NR_statfs 99 #define __NR_fstatfs 100 -#define __NR_ioperm 101 +/*#define __NR_ioperm 101*/ #define __NR_socketcall 102 #define __NR_syslog 103 #define __NR_setitimer 104 @@ -114,11 +114,11 @@ #define __NR_stat 106 #define __NR_lstat 107 #define __NR_fstat 108 -#define __NR_olduname 109 -#define __NR_iopl /* 110 */ not supported +/*#define __NR_olduname 109*/ +/*#define __NR_iopl 110*/ /* not supported */ #define __NR_vhangup 111 -#define __NR_idle /* 112 */ Obsolete -#define __NR_vm86 /* 113 */ not supported +/*#define __NR_idle 112*/ /* Obsolete */ +/*#define __NR_vm86 113*/ /* not supported */ #define __NR_wait4 114 #define __NR_swapoff 115 #define __NR_sysinfo 116 @@ -132,17 +132,17 @@ #define __NR_adjtimex 124 #define __NR_mprotect 125 #define __NR_sigprocmask 126 -#define __NR_create_module 127 +/*#define __NR_create_module 127*/ #define __NR_init_module 128 #define __NR_delete_module 129 -#define __NR_get_kernel_syms 130 +/*#define __NR_get_kernel_syms 130*/ #define __NR_quotactl 131 #define __NR_getpgid 132 #define __NR_fchdir 133 #define __NR_bdflush 134 #define __NR_sysfs 135 #define __NR_personality 136 -#define __NR_afs_syscall 137 /* Syscall for Andrew File System */ +/*#define __NR_afs_syscall 137*/ /* Syscall for Andrew File System */ #define __NR_setfsuid 138 #define __NR_setfsgid 139 #define __NR__llseek 140 @@ -172,7 +172,7 @@ #define __NR_setresuid 164 #define __NR_getresuid 165 #define __NR_getpagesize 166 -#define __NR_query_module 167 +/*#define __NR_query_module 167*/ #define __NR_poll 168 #define __NR_nfsservctl 169 #define __NR_setresgid 170 @@ -193,8 +193,8 @@ #define __NR_capset 185 #define __NR_sigaltstack 186 #define __NR_sendfile 187 -#define __NR_getpmsg 188 /* some people actually want streams */ -#define __NR_putpmsg 189 /* some people actually want streams */ +/*#define __NR_getpmsg 188*/ /* some people actually want streams */ +/*#define __NR_putpmsg 189*/ /* some people actually want streams */ #define __NR_vfork 190 #define __NR_ugetrlimit 191 #define __NR_mmap2 192 @@ -223,6 +223,8 @@ #define __NR_setfsuid32 215 #define __NR_setfsgid32 216 #define __NR_pivot_root 217 +/* 218*/ +/* 219*/ #define __NR_getdents64 220 #define __NR_gettid 221 #define __NR_tkill 222 @@ -281,7 +283,7 @@ #define __NR_mq_notify 275 #define __NR_mq_getsetattr 276 #define __NR_waitid 277 -#define __NR_vserver 278 +/*#define __NR_vserver 278*/ #define __NR_add_key 279 #define __NR_request_key 280 #define __NR_keyctl 281 -- cgit v0.10.2 From 79abeed6ee93231d494c191a9251c0845bd71fdd Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Wed, 4 May 2011 14:55:41 +0200 Subject: m68k/atari: Do not use "/" in interrupt names It may trigger a warning in fs/proc/generic.c:__xlate_proc_name() when trying to add an entry for the interrupt handler to sysfs. Signed-off-by: Geert Uytterhoeven diff --git a/arch/m68k/atari/atakeyb.c b/arch/m68k/atari/atakeyb.c index b995513..db26f0e 100644 --- a/arch/m68k/atari/atakeyb.c +++ b/arch/m68k/atari/atakeyb.c @@ -575,7 +575,7 @@ int atari_keyb_init(void) kb_state.len = 0; error = request_irq(IRQ_MFP_ACIA, atari_keyboard_interrupt, - IRQ_TYPE_SLOW, "keyboard/mouse/MIDI", + IRQ_TYPE_SLOW, "keyboard,mouse,MIDI", atari_keyboard_interrupt); if (error) return error; diff --git a/arch/m68k/atari/stdma.c b/arch/m68k/atari/stdma.c index 604329f..ddbf43c 100644 --- a/arch/m68k/atari/stdma.c +++ b/arch/m68k/atari/stdma.c @@ -180,7 +180,7 @@ void __init stdma_init(void) { stdma_isr = NULL; if (request_irq(IRQ_MFP_FDC, stdma_int, IRQ_TYPE_SLOW | IRQF_SHARED, - "ST-DMA: floppy/ACSI/IDE/Falcon-SCSI", stdma_int)) + "ST-DMA floppy,ACSI,IDE,Falcon-SCSI", stdma_int)) pr_err("Couldn't register ST-DMA interrupt\n"); } diff --git a/drivers/net/atarilance.c b/drivers/net/atarilance.c index ce0091e..1264d78 100644 --- a/drivers/net/atarilance.c +++ b/drivers/net/atarilance.c @@ -554,7 +554,7 @@ static unsigned long __init lance_probe1( struct net_device *dev, memaddr == (unsigned short *)0xffe00000) { /* PAMs card and Riebl on ST use level 5 autovector */ if (request_irq(IRQ_AUTO_5, lance_interrupt, IRQ_TYPE_PRIO, - "PAM/Riebl-ST Ethernet", dev)) { + "PAM,Riebl-ST Ethernet", dev)) { printk( "Lance: request for irq %d failed\n", IRQ_AUTO_5 ); return 0; } diff --git a/drivers/video/atafb.c b/drivers/video/atafb.c index 5b2b5ef..64e41f5 100644 --- a/drivers/video/atafb.c +++ b/drivers/video/atafb.c @@ -3117,7 +3117,7 @@ int __init atafb_init(void) atafb_ops.fb_setcolreg = &falcon_setcolreg; error = request_irq(IRQ_AUTO_4, falcon_vbl_switcher, IRQ_TYPE_PRIO, - "framebuffer/modeswitch", + "framebuffer:modeswitch", falcon_vbl_switcher); if (error) return error; -- cgit v0.10.2 From 7786908c3c1bb38dcc5cd2c037251c05507eef16 Mon Sep 17 00:00:00 2001 From: Michael Schmitz Date: Tue, 16 Dec 2008 21:26:03 +0100 Subject: input/atari: Use the correct mouse interrupt hook The Atari keyboard driver calls atari_mouse_interrupt_hook if it's set, not atari_input_mouse_interrupt_hook. Fix below. [geert] Killed off atari_mouse_interrupt_hook completely, after fixing another incorrect assignment in atarimouse.c. Signed-off-by: Michael Schmitz Signed-off-by: Geert Uytterhoeven diff --git a/arch/m68k/atari/atakeyb.c b/arch/m68k/atari/atakeyb.c index db26f0e..95022b0 100644 --- a/arch/m68k/atari/atakeyb.c +++ b/arch/m68k/atari/atakeyb.c @@ -36,13 +36,10 @@ /* Hook for MIDI serial driver */ void (*atari_MIDI_interrupt_hook) (void); -/* Hook for mouse driver */ -void (*atari_mouse_interrupt_hook) (char *); /* Hook for keyboard inputdev driver */ void (*atari_input_keyboard_interrupt_hook) (unsigned char, char); /* Hook for mouse inputdev driver */ void (*atari_input_mouse_interrupt_hook) (char *); -EXPORT_SYMBOL(atari_mouse_interrupt_hook); EXPORT_SYMBOL(atari_input_keyboard_interrupt_hook); EXPORT_SYMBOL(atari_input_mouse_interrupt_hook); @@ -263,8 +260,8 @@ repeat: kb_state.buf[kb_state.len++] = scancode; if (kb_state.len == 3) { kb_state.state = KEYBOARD; - if (atari_mouse_interrupt_hook) - atari_mouse_interrupt_hook(kb_state.buf); + if (atari_input_mouse_interrupt_hook) + atari_input_mouse_interrupt_hook(kb_state.buf); } break; diff --git a/arch/m68k/include/asm/atarikb.h b/arch/m68k/include/asm/atarikb.h index 546e7da..68f3622 100644 --- a/arch/m68k/include/asm/atarikb.h +++ b/arch/m68k/include/asm/atarikb.h @@ -34,8 +34,6 @@ void ikbd_joystick_disable(void); /* Hook for MIDI serial driver */ extern void (*atari_MIDI_interrupt_hook) (void); -/* Hook for mouse driver */ -extern void (*atari_mouse_interrupt_hook) (char *); /* Hook for keyboard inputdev driver */ extern void (*atari_input_keyboard_interrupt_hook) (unsigned char, char); /* Hook for mouse inputdev driver */ diff --git a/drivers/input/mouse/atarimouse.c b/drivers/input/mouse/atarimouse.c index adf45b3..a57143c 100644 --- a/drivers/input/mouse/atarimouse.c +++ b/drivers/input/mouse/atarimouse.c @@ -108,7 +108,7 @@ static int atamouse_open(struct input_dev *dev) static void atamouse_close(struct input_dev *dev) { ikbd_mouse_disable(); - atari_mouse_interrupt_hook = NULL; + atari_input_mouse_interrupt_hook = NULL; } static int __init atamouse_init(void) -- cgit v0.10.2 From 186f200a95cbd13c291cdd3ddeb07aad0a3782cc Mon Sep 17 00:00:00 2001 From: Michael Schmitz Date: Sun, 28 Dec 2008 23:00:45 +0100 Subject: input/atari: Fix atarimouse init Atarimouse fails to load as a module (with ENODEV), due to a brown paper bag bug, misinterpreting the semantics of atari_keyb_init(). [geert] Propagate the return value of atari_keyb_init() everywhere Signed-off-by: Michael Schmitz Signed-off-by: Geert Uytterhoeven diff --git a/drivers/input/keyboard/atakbd.c b/drivers/input/keyboard/atakbd.c index 1839194..10bcd4a 100644 --- a/drivers/input/keyboard/atakbd.c +++ b/drivers/input/keyboard/atakbd.c @@ -223,8 +223,9 @@ static int __init atakbd_init(void) return -ENODEV; // need to init core driver if not already done so - if (atari_keyb_init()) - return -ENODEV; + error = atari_keyb_init(); + if (error) + return error; atakbd_dev = input_allocate_device(); if (!atakbd_dev) diff --git a/drivers/input/mouse/atarimouse.c b/drivers/input/mouse/atarimouse.c index a57143c..16a9d0f 100644 --- a/drivers/input/mouse/atarimouse.c +++ b/drivers/input/mouse/atarimouse.c @@ -118,8 +118,9 @@ static int __init atamouse_init(void) if (!MACH_IS_ATARI || !ATARIHW_PRESENT(ST_MFP)) return -ENODEV; - if (!atari_keyb_init()) - return -ENODEV; + error = atari_keyb_init(); + if (error) + return error; atamouse_dev = input_allocate_device(); if (!atamouse_dev) -- cgit v0.10.2 From 659e6ed55ff8d617c895c10288644e3e6107834e Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Mon, 31 Jan 2011 20:15:04 +0100 Subject: input/atari: Fix mouse movement and button mapping Up and down movements were reversed, left and right buttons were swapped. Signed-off-by: Geert Uytterhoeven diff --git a/drivers/input/mouse/atarimouse.c b/drivers/input/mouse/atarimouse.c index 16a9d0f..5c4a692 100644 --- a/drivers/input/mouse/atarimouse.c +++ b/drivers/input/mouse/atarimouse.c @@ -77,15 +77,15 @@ static void atamouse_interrupt(char *buf) #endif /* only relative events get here */ - dx = buf[1]; - dy = -buf[2]; + dx = buf[1]; + dy = buf[2]; input_report_rel(atamouse_dev, REL_X, dx); input_report_rel(atamouse_dev, REL_Y, dy); - input_report_key(atamouse_dev, BTN_LEFT, buttons & 0x1); + input_report_key(atamouse_dev, BTN_LEFT, buttons & 0x4); input_report_key(atamouse_dev, BTN_MIDDLE, buttons & 0x2); - input_report_key(atamouse_dev, BTN_RIGHT, buttons & 0x4); + input_report_key(atamouse_dev, BTN_RIGHT, buttons & 0x1); input_sync(atamouse_dev); -- cgit v0.10.2 From 52c3ce4ec5601ee383a14f1485f6bac7b278896e Mon Sep 17 00:00:00 2001 From: Catalin Marinas Date: Wed, 27 Apr 2011 16:44:26 +0100 Subject: kmemleak: Do not return a pointer to an object that kmemleak did not get The kmemleak_seq_next() function tries to get an object (and increment its use count) before returning it. If it could not get the last object during list traversal (because it may have been freed), the function should return NULL rather than a pointer to such object that it did not get. Signed-off-by: Catalin Marinas Reported-by: Phil Carmody Acked-by: Phil Carmody Cc: diff --git a/mm/kmemleak.c b/mm/kmemleak.c index c1d5867..aacee45 100644 --- a/mm/kmemleak.c +++ b/mm/kmemleak.c @@ -1414,9 +1414,12 @@ static void *kmemleak_seq_next(struct seq_file *seq, void *v, loff_t *pos) ++(*pos); list_for_each_continue_rcu(n, &object_list) { - next_obj = list_entry(n, struct kmemleak_object, object_list); - if (get_object(next_obj)) + struct kmemleak_object *obj = + list_entry(n, struct kmemleak_object, object_list); + if (get_object(obj)) { + next_obj = obj; break; + } } put_object(prev_obj); -- cgit v0.10.2 From 79e0d9bd262bdd36009e8092e57e34dc5e22a1c7 Mon Sep 17 00:00:00 2001 From: Catalin Marinas Date: Wed, 27 Apr 2011 17:06:19 +0100 Subject: kmemleak: Select DEBUG_FS unconditionally in DEBUG_KMEMLEAK In the past DEBUG_FS used to depend on SYSFS and DEBUG_KMEMLEAK selected it conditionally. This is no longer the case, so always select DEBUG_FS via DEBUG_KMEMLEAK. Signed-off-by: Catalin Marinas diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug index c768bcd..4eebb90 100644 --- a/lib/Kconfig.debug +++ b/lib/Kconfig.debug @@ -400,7 +400,7 @@ config DEBUG_KMEMLEAK depends on DEBUG_KERNEL && EXPERIMENTAL && !MEMORY_HOTPLUG && \ (X86 || ARM || PPC || S390 || SPARC64 || SUPERH || MICROBLAZE || TILE) - select DEBUG_FS if SYSFS + select DEBUG_FS select STACKTRACE if STACKTRACE_SUPPORT select KALLSYMS select CRC32 -- cgit v0.10.2 From 9b090f2da85bd0df5e1a1ecfe4120b7b50358f48 Mon Sep 17 00:00:00 2001 From: Catalin Marinas Date: Thu, 19 May 2011 16:25:30 +0100 Subject: kmemleak: Initialise kmemleak after debug_objects_mem_init() Kmemleak frees objects via RCU and when CONFIG_DEBUG_OBJECTS_RCU_HEAD is enabled, the RCU callback triggers a call to free_object() in lib/debugobjects.c. Since kmemleak is initialised before debug objects initialisation, it may result in a kernel panic during booting. This patch moves the kmemleak_init() call after debug_objects_mem_init(). Reported-by: Marcin Slusarz Tested-by: Tejun Heo Signed-off-by: Catalin Marinas Cc: diff --git a/init/main.c b/init/main.c index 4a9479e..48df882 100644 --- a/init/main.c +++ b/init/main.c @@ -580,8 +580,8 @@ asmlinkage void __init start_kernel(void) #endif page_cgroup_init(); enable_debug_pagealloc(); - kmemleak_init(); debug_objects_mem_init(); + kmemleak_init(); setup_per_cpu_pageset(); numa_policy_init(); if (late_time_init) -- cgit v0.10.2 From bb0cd2fb539c4e454ed32e32194acc03b75753f3 Mon Sep 17 00:00:00 2001 From: Changli Gao Date: Wed, 18 May 2011 21:16:00 +0000 Subject: net: ping: make local functions static As these functions are only used in this file. Signed-off-by: Changli Gao Signed-off-by: David S. Miller diff --git a/net/ipv4/ping.c b/net/ipv4/ping.c index 6a21da9..5f9e2d1 100644 --- a/net/ipv4/ping.c +++ b/net/ipv4/ping.c @@ -449,8 +449,8 @@ static int ping_push_pending_frames(struct sock *sk, struct pingfakehdr *pfh, st return ip_push_pending_frames(sk, fl4); } -int ping_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, - size_t len) +static int ping_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, + size_t len) { struct net *net = sock_net(sk); struct flowi4 fl4; @@ -621,8 +621,8 @@ do_confirm: goto out; } -int ping_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, - size_t len, int noblock, int flags, int *addr_len) +static int ping_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, + size_t len, int noblock, int flags, int *addr_len) { struct inet_sock *isk = inet_sk(sk); struct sockaddr_in *sin = (struct sockaddr_in *)msg->msg_name; -- cgit v0.10.2 From 75e308c894c4a5e47c005b8e821ae5f539ad2ef3 Mon Sep 17 00:00:00 2001 From: Changli Gao Date: Wed, 18 May 2011 21:16:01 +0000 Subject: net: ping: fix the coding style The characters in a line should be no more than 80. Signed-off-by: Changli Gao Signed-off-by: David S. Miller diff --git a/net/ipv4/ping.c b/net/ipv4/ping.c index 5f9e2d1..1f3bb11 100644 --- a/net/ipv4/ping.c +++ b/net/ipv4/ping.c @@ -187,7 +187,8 @@ exit: return sk; } -static void inet_get_ping_group_range_net(struct net *net, gid_t *low, gid_t *high) +static void inet_get_ping_group_range_net(struct net *net, gid_t *low, + gid_t *high) { gid_t *data = net->ipv4.sysctl_ping_group_range; unsigned seq; @@ -437,7 +438,8 @@ static int ping_getfrag(void *from, char * to, return 0; } -static int ping_push_pending_frames(struct sock *sk, struct pingfakehdr *pfh, struct flowi4 *fl4) +static int ping_push_pending_frames(struct sock *sk, struct pingfakehdr *pfh, + struct flowi4 *fl4) { struct sk_buff *skb = skb_peek(&sk->sk_write_queue); @@ -754,7 +756,9 @@ static struct sock *ping_get_first(struct seq_file *seq, int start) for (state->bucket = start; state->bucket < PING_HTABLE_SIZE; ++state->bucket) { struct hlist_nulls_node *node; - struct hlist_nulls_head *hslot = &ping_table.hash[state->bucket]; + struct hlist_nulls_head *hslot; + + hslot = &ping_table.hash[state->bucket]; if (hlist_nulls_empty(hslot)) continue; -- cgit v0.10.2 From be281e554e2a4cf2478df7a8b8926c89454bccfa Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Thu, 19 May 2011 01:14:23 +0000 Subject: ipv6: reduce per device ICMP mib sizes ipv6 has per device ICMP SNMP counters, taking too much space because they use percpu storage. needed size per device is : (512+4)*sizeof(long)*number_of_possible_cpus*2 On a 32bit kernel, 16 possible cpus, this wastes more than 64kbytes of memory per ipv6 enabled network device, taken in vmalloc pool. Since ICMP messages are rare, just use shared counters (atomic_long_t) Per network space ICMP counters are still using percpu memory, we might also convert them to shared counters in a future patch. Signed-off-by: Eric Dumazet CC: Denys Fedoryshchenko Signed-off-by: David S. Miller diff --git a/include/net/if_inet6.h b/include/net/if_inet6.h index 0c603fe..11cf373 100644 --- a/include/net/if_inet6.h +++ b/include/net/if_inet6.h @@ -154,8 +154,8 @@ struct ifacaddr6 { struct ipv6_devstat { struct proc_dir_entry *proc_dir_entry; DEFINE_SNMP_STAT(struct ipstats_mib, ipv6); - DEFINE_SNMP_STAT(struct icmpv6_mib, icmpv6); - DEFINE_SNMP_STAT(struct icmpv6msg_mib, icmpv6msg); + DEFINE_SNMP_STAT_ATOMIC(struct icmpv6_mib_device, icmpv6dev); + DEFINE_SNMP_STAT_ATOMIC(struct icmpv6msg_mib_device, icmpv6msgdev); }; struct inet6_dev { diff --git a/include/net/ipv6.h b/include/net/ipv6.h index e1c60b4..c033ed0 100644 --- a/include/net/ipv6.h +++ b/include/net/ipv6.h @@ -123,6 +123,15 @@ extern struct ctl_path net_ipv6_ctl_path[]; SNMP_INC_STATS##modifier((net)->mib.statname##_statistics, (field));\ }) +/* per device counters are atomic_long_t */ +#define _DEVINCATOMIC(net, statname, modifier, idev, field) \ +({ \ + struct inet6_dev *_idev = (idev); \ + if (likely(_idev != NULL)) \ + SNMP_INC_STATS_ATOMIC_LONG((_idev)->stats.statname##dev, (field)); \ + SNMP_INC_STATS##modifier((net)->mib.statname##_statistics, (field));\ +}) + #define _DEVADD(net, statname, modifier, idev, field, val) \ ({ \ struct inet6_dev *_idev = (idev); \ @@ -154,16 +163,16 @@ extern struct ctl_path net_ipv6_ctl_path[]; #define IP6_UPD_PO_STATS_BH(net, idev,field,val) \ _DEVUPD(net, ipv6, 64_BH, idev, field, val) #define ICMP6_INC_STATS(net, idev, field) \ - _DEVINC(net, icmpv6, , idev, field) + _DEVINCATOMIC(net, icmpv6, , idev, field) #define ICMP6_INC_STATS_BH(net, idev, field) \ - _DEVINC(net, icmpv6, _BH, idev, field) + _DEVINCATOMIC(net, icmpv6, _BH, idev, field) #define ICMP6MSGOUT_INC_STATS(net, idev, field) \ - _DEVINC(net, icmpv6msg, , idev, field +256) + _DEVINCATOMIC(net, icmpv6msg, , idev, field +256) #define ICMP6MSGOUT_INC_STATS_BH(net, idev, field) \ - _DEVINC(net, icmpv6msg, _BH, idev, field +256) + _DEVINCATOMIC(net, icmpv6msg, _BH, idev, field +256) #define ICMP6MSGIN_INC_STATS_BH(net, idev, field) \ - _DEVINC(net, icmpv6msg, _BH, idev, field) + _DEVINCATOMIC(net, icmpv6msg, _BH, idev, field) struct ip6_ra_chain { struct ip6_ra_chain *next; diff --git a/include/net/snmp.h b/include/net/snmp.h index 27461d6..479083a 100644 --- a/include/net/snmp.h +++ b/include/net/snmp.h @@ -72,14 +72,24 @@ struct icmpmsg_mib { /* ICMP6 (IPv6-ICMP) */ #define ICMP6_MIB_MAX __ICMP6_MIB_MAX +/* per network ns counters */ struct icmpv6_mib { unsigned long mibs[ICMP6_MIB_MAX]; }; +/* per device counters, (shared on all cpus) */ +struct icmpv6_mib_device { + atomic_long_t mibs[ICMP6_MIB_MAX]; +}; #define ICMP6MSG_MIB_MAX __ICMP6MSG_MIB_MAX +/* per network ns counters */ struct icmpv6msg_mib { unsigned long mibs[ICMP6MSG_MIB_MAX]; }; +/* per device counters, (shared on all cpus) */ +struct icmpv6msg_mib_device { + atomic_long_t mibs[ICMP6MSG_MIB_MAX]; +}; /* TCP */ @@ -114,6 +124,8 @@ struct linux_xfrm_mib { */ #define DEFINE_SNMP_STAT(type, name) \ __typeof__(type) __percpu *name[2] +#define DEFINE_SNMP_STAT_ATOMIC(type, name) \ + __typeof__(type) *name #define DECLARE_SNMP_STAT(type, name) \ extern __typeof__(type) __percpu *name[2] @@ -124,6 +136,8 @@ struct linux_xfrm_mib { __this_cpu_inc(mib[0]->mibs[field]) #define SNMP_INC_STATS_USER(mib, field) \ this_cpu_inc(mib[1]->mibs[field]) +#define SNMP_INC_STATS_ATOMIC_LONG(mib, field) \ + atomic_long_inc(&mib->mibs[field]) #define SNMP_INC_STATS(mib, field) \ this_cpu_inc(mib[!in_softirq()]->mibs[field]) #define SNMP_DEC_STATS(mib, field) \ diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c index f2f9b2e..3cfbbf3 100644 --- a/net/ipv6/addrconf.c +++ b/net/ipv6/addrconf.c @@ -289,19 +289,19 @@ static int snmp6_alloc_dev(struct inet6_dev *idev) sizeof(struct ipstats_mib), __alignof__(struct ipstats_mib)) < 0) goto err_ip; - if (snmp_mib_init((void __percpu **)idev->stats.icmpv6, - sizeof(struct icmpv6_mib), - __alignof__(struct icmpv6_mib)) < 0) + idev->stats.icmpv6dev = kzalloc(sizeof(struct icmpv6_mib_device), + GFP_KERNEL); + if (!idev->stats.icmpv6dev) goto err_icmp; - if (snmp_mib_init((void __percpu **)idev->stats.icmpv6msg, - sizeof(struct icmpv6msg_mib), - __alignof__(struct icmpv6msg_mib)) < 0) + idev->stats.icmpv6msgdev = kzalloc(sizeof(struct icmpv6msg_mib_device), + GFP_KERNEL); + if (!idev->stats.icmpv6msgdev) goto err_icmpmsg; return 0; err_icmpmsg: - snmp_mib_free((void __percpu **)idev->stats.icmpv6); + kfree(idev->stats.icmpv6dev); err_icmp: snmp_mib_free((void __percpu **)idev->stats.ipv6); err_ip: @@ -310,8 +310,8 @@ err_ip: static void snmp6_free_dev(struct inet6_dev *idev) { - snmp_mib_free((void __percpu **)idev->stats.icmpv6msg); - snmp_mib_free((void __percpu **)idev->stats.icmpv6); + kfree(idev->stats.icmpv6msgdev); + kfree(idev->stats.icmpv6dev); snmp_mib_free((void __percpu **)idev->stats.ipv6); } @@ -3838,7 +3838,7 @@ static inline size_t inet6_if_nlmsg_size(void) + nla_total_size(inet6_ifla6_size()); /* IFLA_PROTINFO */ } -static inline void __snmp6_fill_stats(u64 *stats, void __percpu **mib, +static inline void __snmp6_fill_statsdev(u64 *stats, atomic_long_t *mib, int items, int bytes) { int i; @@ -3848,7 +3848,7 @@ static inline void __snmp6_fill_stats(u64 *stats, void __percpu **mib, /* Use put_unaligned() because stats may not be aligned for u64. */ put_unaligned(items, &stats[0]); for (i = 1; i < items; i++) - put_unaligned(snmp_fold_field(mib, i), &stats[i]); + put_unaligned(atomic_long_read(&mib[i]), &stats[i]); memset(&stats[items], 0, pad); } @@ -3877,7 +3877,7 @@ static void snmp6_fill_stats(u64 *stats, struct inet6_dev *idev, int attrtype, IPSTATS_MIB_MAX, bytes, offsetof(struct ipstats_mib, syncp)); break; case IFLA_INET6_ICMP6STATS: - __snmp6_fill_stats(stats, (void __percpu **)idev->stats.icmpv6, ICMP6_MIB_MAX, bytes); + __snmp6_fill_statsdev(stats, idev->stats.icmpv6dev->mibs, ICMP6_MIB_MAX, bytes); break; } } diff --git a/net/ipv6/proc.c b/net/ipv6/proc.c index 24b3558..18ff5df 100644 --- a/net/ipv6/proc.c +++ b/net/ipv6/proc.c @@ -141,7 +141,11 @@ static const struct snmp_mib snmp6_udplite6_list[] = { SNMP_MIB_SENTINEL }; -static void snmp6_seq_show_icmpv6msg(struct seq_file *seq, void __percpu **mib) +/* can be called either with percpu mib (pcpumib != NULL), + * or shared one (smib != NULL) + */ +static void snmp6_seq_show_icmpv6msg(struct seq_file *seq, void __percpu **pcpumib, + atomic_long_t *smib) { char name[32]; int i; @@ -158,14 +162,14 @@ static void snmp6_seq_show_icmpv6msg(struct seq_file *seq, void __percpu **mib) snprintf(name, sizeof(name), "Icmp6%s%s", i & 0x100 ? "Out" : "In", p); seq_printf(seq, "%-32s\t%lu\n", name, - snmp_fold_field(mib, i)); + pcpumib ? snmp_fold_field(pcpumib, i) : atomic_long_read(smib + i)); } /* print by number (nonzero only) - ICMPMsgStat format */ for (i = 0; i < ICMP6MSG_MIB_MAX; i++) { unsigned long val; - val = snmp_fold_field(mib, i); + val = pcpumib ? snmp_fold_field(pcpumib, i) : atomic_long_read(smib + i); if (!val) continue; snprintf(name, sizeof(name), "Icmp6%sType%u", @@ -174,14 +178,22 @@ static void snmp6_seq_show_icmpv6msg(struct seq_file *seq, void __percpu **mib) } } -static void snmp6_seq_show_item(struct seq_file *seq, void __percpu **mib, +/* can be called either with percpu mib (pcpumib != NULL), + * or shared one (smib != NULL) + */ +static void snmp6_seq_show_item(struct seq_file *seq, void __percpu **pcpumib, + atomic_long_t *smib, const struct snmp_mib *itemlist) { int i; + unsigned long val; - for (i = 0; itemlist[i].name; i++) - seq_printf(seq, "%-32s\t%lu\n", itemlist[i].name, - snmp_fold_field(mib, itemlist[i].entry)); + for (i = 0; itemlist[i].name; i++) { + val = pcpumib ? + snmp_fold_field(pcpumib, itemlist[i].entry) : + atomic_long_read(smib + itemlist[i].entry); + seq_printf(seq, "%-32s\t%lu\n", itemlist[i].name, val); + } } static void snmp6_seq_show_item64(struct seq_file *seq, void __percpu **mib, @@ -201,13 +213,13 @@ static int snmp6_seq_show(struct seq_file *seq, void *v) snmp6_seq_show_item64(seq, (void __percpu **)net->mib.ipv6_statistics, snmp6_ipstats_list, offsetof(struct ipstats_mib, syncp)); snmp6_seq_show_item(seq, (void __percpu **)net->mib.icmpv6_statistics, - snmp6_icmp6_list); + NULL, snmp6_icmp6_list); snmp6_seq_show_icmpv6msg(seq, - (void __percpu **)net->mib.icmpv6msg_statistics); + (void __percpu **)net->mib.icmpv6msg_statistics, NULL); snmp6_seq_show_item(seq, (void __percpu **)net->mib.udp_stats_in6, - snmp6_udp6_list); + NULL, snmp6_udp6_list); snmp6_seq_show_item(seq, (void __percpu **)net->mib.udplite_stats_in6, - snmp6_udplite6_list); + NULL, snmp6_udplite6_list); return 0; } @@ -229,11 +241,11 @@ static int snmp6_dev_seq_show(struct seq_file *seq, void *v) struct inet6_dev *idev = (struct inet6_dev *)seq->private; seq_printf(seq, "%-32s\t%u\n", "ifIndex", idev->dev->ifindex); - snmp6_seq_show_item(seq, (void __percpu **)idev->stats.ipv6, + snmp6_seq_show_item(seq, (void __percpu **)idev->stats.ipv6, NULL, snmp6_ipstats_list); - snmp6_seq_show_item(seq, (void __percpu **)idev->stats.icmpv6, + snmp6_seq_show_item(seq, NULL, idev->stats.icmpv6dev->mibs, snmp6_icmp6_list); - snmp6_seq_show_icmpv6msg(seq, (void __percpu **)idev->stats.icmpv6msg); + snmp6_seq_show_icmpv6msg(seq, NULL, idev->stats.icmpv6msgdev->mibs); return 0; } -- cgit v0.10.2 From 75d65a425c0163d3ec476ddc12b51087217a070c Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Thu, 19 May 2011 13:50:07 -0700 Subject: hlist: remove software prefetching in hlist iterators They not only increase the code footprint, they actually make things slower rather than faster. On internationally acclaimed benchmarks ("make -j16" on an already fully built kernel source tree) the hlist prefetching slows down the build by up to 1%. (Almost all of it comes from hlist_for_each_entry_rcu() as used by avc_has_perm_noaudit(), which is very hot due to all the pathname lookups to see if there is anything to do). The cause seems to be two-fold: - on at least some Intel cores, prefetch(NULL) ends up with some microarchitectural stall due to the TLB miss that it incurs. The hlist case triggers this very commonly, since the NULL pointer is the last entry in the list. - the prefetch appears to cause more D$ activity, probably because it prefetches hash list entries that are never actually used (because we ended the search early due to a hit). Regardless, the numbers clearly say that the implicit prefetching is simply a bad idea. If some _particular_ user of the hlist iterators wants to prefetch the next list entry, they can do so themselves explicitly, rather than depend on all list iterators doing so implicitly. Acked-by: Ingo Molnar Acked-by: David S. Miller Cc: linux-arch@vger.kernel.org Signed-off-by: Linus Torvalds diff --git a/include/linux/list.h b/include/linux/list.h index 3a54266..9ac1114 100644 --- a/include/linux/list.h +++ b/include/linux/list.h @@ -664,8 +664,7 @@ static inline void hlist_move_list(struct hlist_head *old, #define hlist_entry(ptr, type, member) container_of(ptr,type,member) #define hlist_for_each(pos, head) \ - for (pos = (head)->first; pos && ({ prefetch(pos->next); 1; }); \ - pos = pos->next) + for (pos = (head)->first; pos ; pos = pos->next) #define hlist_for_each_safe(pos, n, head) \ for (pos = (head)->first; pos && ({ n = pos->next; 1; }); \ @@ -680,7 +679,7 @@ static inline void hlist_move_list(struct hlist_head *old, */ #define hlist_for_each_entry(tpos, pos, head, member) \ for (pos = (head)->first; \ - pos && ({ prefetch(pos->next); 1;}) && \ + pos && \ ({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \ pos = pos->next) @@ -692,7 +691,7 @@ static inline void hlist_move_list(struct hlist_head *old, */ #define hlist_for_each_entry_continue(tpos, pos, member) \ for (pos = (pos)->next; \ - pos && ({ prefetch(pos->next); 1;}) && \ + pos && \ ({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \ pos = pos->next) @@ -703,7 +702,7 @@ static inline void hlist_move_list(struct hlist_head *old, * @member: the name of the hlist_node within the struct. */ #define hlist_for_each_entry_from(tpos, pos, member) \ - for (; pos && ({ prefetch(pos->next); 1;}) && \ + for (; pos && \ ({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \ pos = pos->next) diff --git a/include/linux/rculist.h b/include/linux/rculist.h index 2dea94f..900a97a 100644 --- a/include/linux/rculist.h +++ b/include/linux/rculist.h @@ -427,7 +427,7 @@ static inline void hlist_add_after_rcu(struct hlist_node *prev, #define __hlist_for_each_rcu(pos, head) \ for (pos = rcu_dereference(hlist_first_rcu(head)); \ - pos && ({ prefetch(pos->next); 1; }); \ + pos; \ pos = rcu_dereference(hlist_next_rcu(pos))) /** @@ -443,7 +443,7 @@ static inline void hlist_add_after_rcu(struct hlist_node *prev, */ #define hlist_for_each_entry_rcu(tpos, pos, head, member) \ for (pos = rcu_dereference_raw(hlist_first_rcu(head)); \ - pos && ({ prefetch(pos->next); 1; }) && \ + pos && \ ({ tpos = hlist_entry(pos, typeof(*tpos), member); 1; }); \ pos = rcu_dereference_raw(hlist_next_rcu(pos))) @@ -460,7 +460,7 @@ static inline void hlist_add_after_rcu(struct hlist_node *prev, */ #define hlist_for_each_entry_rcu_bh(tpos, pos, head, member) \ for (pos = rcu_dereference_bh((head)->first); \ - pos && ({ prefetch(pos->next); 1; }) && \ + pos && \ ({ tpos = hlist_entry(pos, typeof(*tpos), member); 1; }); \ pos = rcu_dereference_bh(pos->next)) @@ -472,7 +472,7 @@ static inline void hlist_add_after_rcu(struct hlist_node *prev, */ #define hlist_for_each_entry_continue_rcu(tpos, pos, member) \ for (pos = rcu_dereference((pos)->next); \ - pos && ({ prefetch(pos->next); 1; }) && \ + pos && \ ({ tpos = hlist_entry(pos, typeof(*tpos), member); 1; }); \ pos = rcu_dereference(pos->next)) @@ -484,7 +484,7 @@ static inline void hlist_add_after_rcu(struct hlist_node *prev, */ #define hlist_for_each_entry_continue_rcu_bh(tpos, pos, member) \ for (pos = rcu_dereference_bh((pos)->next); \ - pos && ({ prefetch(pos->next); 1; }) && \ + pos && \ ({ tpos = hlist_entry(pos, typeof(*tpos), member); 1; }); \ pos = rcu_dereference_bh(pos->next)) -- cgit v0.10.2 From c182f90bc1f22ce5039b8722e45621d5f96862c2 Mon Sep 17 00:00:00 2001 From: Jacek Luczak Date: Thu, 19 May 2011 09:55:13 +0000 Subject: SCTP: fix race between sctp_bind_addr_free() and sctp_bind_addr_conflict() During the sctp_close() call, we do not use rcu primitives to destroy the address list attached to the endpoint. At the same time, we do the removal of addresses from this list before attempting to remove the socket from the port hash As a result, it is possible for another process to find the socket in the port hash that is in the process of being closed. It then proceeds to traverse the address list to find the conflict, only to have that address list suddenly disappear without rcu() critical section. Fix issue by closing address list removal inside RCU critical section. Race can result in a kernel crash with general protection fault or kernel NULL pointer dereference: kernel: general protection fault: 0000 [#1] SMP kernel: RIP: 0010:[] [] sctp_bind_addr_conflict+0x64/0x82 [sctp] kernel: Call Trace: kernel: [] ? sctp_get_port_local+0x17b/0x2a3 [sctp] kernel: [] ? sctp_bind_addr_match+0x33/0x68 [sctp] kernel: [] ? sctp_do_bind+0xd3/0x141 [sctp] kernel: [] ? sctp_bindx_add+0x4d/0x8e [sctp] kernel: [] ? sctp_setsockopt_bindx+0x112/0x4a4 [sctp] kernel: [] ? generic_file_aio_write+0x7f/0x9b kernel: [] ? sctp_setsockopt+0x14f/0xfee [sctp] kernel: [] ? do_sync_write+0xab/0xeb kernel: [] ? fsnotify+0x239/0x282 kernel: [] ? alloc_file+0x18/0xb1 kernel: [] ? compat_sys_setsockopt+0x1a5/0x1d9 kernel: [] ? compat_sys_socketcall+0x143/0x1a4 kernel: [] ? sysenter_dispatch+0x7/0x32 Signed-off-by: Jacek Luczak Acked-by: Vlad Yasevich CC: Eric Dumazet Reviewed-by: Eric Dumazet Signed-off-by: David S. Miller diff --git a/net/sctp/bind_addr.c b/net/sctp/bind_addr.c index faf71d1..6150ac5 100644 --- a/net/sctp/bind_addr.c +++ b/net/sctp/bind_addr.c @@ -140,14 +140,12 @@ void sctp_bind_addr_init(struct sctp_bind_addr *bp, __u16 port) /* Dispose of the address list. */ static void sctp_bind_addr_clean(struct sctp_bind_addr *bp) { - struct sctp_sockaddr_entry *addr; - struct list_head *pos, *temp; + struct sctp_sockaddr_entry *addr, *temp; /* Empty the bind address list. */ - list_for_each_safe(pos, temp, &bp->address_list) { - addr = list_entry(pos, struct sctp_sockaddr_entry, list); - list_del(pos); - kfree(addr); + list_for_each_entry_safe(addr, temp, &bp->address_list, list) { + list_del_rcu(&addr->list); + call_rcu(&addr->rcu, sctp_local_addr_free); SCTP_DBG_OBJCNT_DEC(addr); } } -- cgit v0.10.2 From 3fb72f1e6e6165c5f495e8dc11c5bbd14c73385c Mon Sep 17 00:00:00 2001 From: Micha Nelissen Date: Thu, 19 May 2011 10:14:06 +0000 Subject: ipconfig wait for carrier v3 -> v4: fix return boolean false instead of 0 for ic_is_init_dev Currently the ip auto configuration has a hardcoded delay of 1 second. When (ethernet) link takes longer to come up (e.g. more than 3 seconds), nfs root may not be found. Remove the hardcoded delay, and wait for carrier on at least one network device. Signed-off-by: Micha Nelissen Cc: David Miller Signed-off-by: David S. Miller diff --git a/net/ipv4/ipconfig.c b/net/ipv4/ipconfig.c index cbff2ec..ab7e554 100644 --- a/net/ipv4/ipconfig.c +++ b/net/ipv4/ipconfig.c @@ -87,8 +87,8 @@ #endif /* Define the friendly delay before and after opening net devices */ -#define CONF_PRE_OPEN 500 /* Before opening: 1/2 second */ -#define CONF_POST_OPEN 1 /* After opening: 1 second */ +#define CONF_POST_OPEN 10 /* After opening: 10 msecs */ +#define CONF_CARRIER_TIMEOUT 120000 /* Wait for carrier timeout */ /* Define the timeout for waiting for a DHCP/BOOTP/RARP reply */ #define CONF_OPEN_RETRIES 2 /* (Re)open devices twice */ @@ -188,14 +188,14 @@ struct ic_device { static struct ic_device *ic_first_dev __initdata = NULL;/* List of open device */ static struct net_device *ic_dev __initdata = NULL; /* Selected device */ -static bool __init ic_device_match(struct net_device *dev) +static bool __init ic_is_init_dev(struct net_device *dev) { - if (user_dev_name[0] ? !strcmp(dev->name, user_dev_name) : + if (dev->flags & IFF_LOOPBACK) + return false; + return user_dev_name[0] ? !strcmp(dev->name, user_dev_name) : (!(dev->flags & IFF_LOOPBACK) && (dev->flags & (IFF_POINTOPOINT|IFF_BROADCAST)) && - strncmp(dev->name, "dummy", 5))) - return true; - return false; + strncmp(dev->name, "dummy", 5)); } static int __init ic_open_devs(void) @@ -203,6 +203,7 @@ static int __init ic_open_devs(void) struct ic_device *d, **last; struct net_device *dev; unsigned short oflags; + unsigned long start; last = &ic_first_dev; rtnl_lock(); @@ -216,9 +217,7 @@ static int __init ic_open_devs(void) } for_each_netdev(&init_net, dev) { - if (dev->flags & IFF_LOOPBACK) - continue; - if (ic_device_match(dev)) { + if (ic_is_init_dev(dev)) { int able = 0; if (dev->mtu >= 364) able |= IC_BOOTP; @@ -252,6 +251,17 @@ static int __init ic_open_devs(void) dev->name, able, d->xid)); } } + + /* wait for a carrier on at least one device */ + start = jiffies; + while (jiffies - start < msecs_to_jiffies(CONF_CARRIER_TIMEOUT)) { + for_each_netdev(&init_net, dev) + if (ic_is_init_dev(dev) && netif_carrier_ok(dev)) + goto have_carrier; + + msleep(1); + } +have_carrier: rtnl_unlock(); *last = NULL; @@ -1324,14 +1334,13 @@ static int __init wait_for_devices(void) { int i; - msleep(CONF_PRE_OPEN); for (i = 0; i < DEVICE_WAIT_MAX; i++) { struct net_device *dev; int found = 0; rtnl_lock(); for_each_netdev(&init_net, dev) { - if (ic_device_match(dev)) { + if (ic_is_init_dev(dev)) { found = 1; break; } @@ -1378,7 +1387,7 @@ static int __init ip_auto_config(void) return err; /* Give drivers a chance to settle */ - ssleep(CONF_POST_OPEN); + msleep(CONF_POST_OPEN); /* * If the config information is insufficient (e.g., our IP address or -- cgit v0.10.2 From e66eed651fd18a961f11cda62f3b5286c8cc4f9f Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Thu, 19 May 2011 14:15:29 -0700 Subject: list: remove prefetching from regular list iterators This is removes the use of software prefetching from the regular list iterators. We don't want it. If you do want to prefetch in some iterator of yours, go right ahead. Just don't expect the iterator to do it, since normally the downsides are bigger than the upsides. It also replaces with , because the use of LIST_POISON ends up needing it. is sadly not self-contained, and including prefetch.h just happened to hide that. Suggested by David Miller (networking has a lot of regular lists that are often empty or a single entry, and prefetching is not going to do anything but add useless instructions). Acked-by: Ingo Molnar Acked-by: David S. Miller Cc: linux-arch@vger.kernel.org Signed-off-by: Linus Torvalds diff --git a/include/linux/list.h b/include/linux/list.h index 9ac1114..cc6d2aa 100644 --- a/include/linux/list.h +++ b/include/linux/list.h @@ -4,7 +4,7 @@ #include #include #include -#include +#include /* * Simple doubly linked list implementation. @@ -367,18 +367,15 @@ static inline void list_splice_tail_init(struct list_head *list, * @head: the head for your list. */ #define list_for_each(pos, head) \ - for (pos = (head)->next; prefetch(pos->next), pos != (head); \ - pos = pos->next) + for (pos = (head)->next; pos != (head); pos = pos->next) /** * __list_for_each - iterate over a list * @pos: the &struct list_head to use as a loop cursor. * @head: the head for your list. * - * This variant differs from list_for_each() in that it's the - * simplest possible list iteration code, no prefetching is done. - * Use this for code that knows the list to be very short (empty - * or 1 entry) most of the time. + * This variant doesn't differ from list_for_each() any more. + * We don't do prefetching in either case. */ #define __list_for_each(pos, head) \ for (pos = (head)->next; pos != (head); pos = pos->next) @@ -389,8 +386,7 @@ static inline void list_splice_tail_init(struct list_head *list, * @head: the head for your list. */ #define list_for_each_prev(pos, head) \ - for (pos = (head)->prev; prefetch(pos->prev), pos != (head); \ - pos = pos->prev) + for (pos = (head)->prev; pos != (head); pos = pos->prev) /** * list_for_each_safe - iterate over a list safe against removal of list entry @@ -410,7 +406,7 @@ static inline void list_splice_tail_init(struct list_head *list, */ #define list_for_each_prev_safe(pos, n, head) \ for (pos = (head)->prev, n = pos->prev; \ - prefetch(pos->prev), pos != (head); \ + pos != (head); \ pos = n, n = pos->prev) /** @@ -421,7 +417,7 @@ static inline void list_splice_tail_init(struct list_head *list, */ #define list_for_each_entry(pos, head, member) \ for (pos = list_entry((head)->next, typeof(*pos), member); \ - prefetch(pos->member.next), &pos->member != (head); \ + &pos->member != (head); \ pos = list_entry(pos->member.next, typeof(*pos), member)) /** @@ -432,7 +428,7 @@ static inline void list_splice_tail_init(struct list_head *list, */ #define list_for_each_entry_reverse(pos, head, member) \ for (pos = list_entry((head)->prev, typeof(*pos), member); \ - prefetch(pos->member.prev), &pos->member != (head); \ + &pos->member != (head); \ pos = list_entry(pos->member.prev, typeof(*pos), member)) /** @@ -457,7 +453,7 @@ static inline void list_splice_tail_init(struct list_head *list, */ #define list_for_each_entry_continue(pos, head, member) \ for (pos = list_entry(pos->member.next, typeof(*pos), member); \ - prefetch(pos->member.next), &pos->member != (head); \ + &pos->member != (head); \ pos = list_entry(pos->member.next, typeof(*pos), member)) /** @@ -471,7 +467,7 @@ static inline void list_splice_tail_init(struct list_head *list, */ #define list_for_each_entry_continue_reverse(pos, head, member) \ for (pos = list_entry(pos->member.prev, typeof(*pos), member); \ - prefetch(pos->member.prev), &pos->member != (head); \ + &pos->member != (head); \ pos = list_entry(pos->member.prev, typeof(*pos), member)) /** @@ -483,7 +479,7 @@ static inline void list_splice_tail_init(struct list_head *list, * Iterate over list of given type, continuing from current position. */ #define list_for_each_entry_from(pos, head, member) \ - for (; prefetch(pos->member.next), &pos->member != (head); \ + for (; &pos->member != (head); \ pos = list_entry(pos->member.next, typeof(*pos), member)) /** diff --git a/include/linux/rculist.h b/include/linux/rculist.h index 900a97a..e3beb31 100644 --- a/include/linux/rculist.h +++ b/include/linux/rculist.h @@ -253,7 +253,7 @@ static inline void list_splice_init_rcu(struct list_head *list, */ #define list_for_each_entry_rcu(pos, head, member) \ for (pos = list_entry_rcu((head)->next, typeof(*pos), member); \ - prefetch(pos->member.next), &pos->member != (head); \ + &pos->member != (head); \ pos = list_entry_rcu(pos->member.next, typeof(*pos), member)) @@ -270,7 +270,7 @@ static inline void list_splice_init_rcu(struct list_head *list, */ #define list_for_each_continue_rcu(pos, head) \ for ((pos) = rcu_dereference_raw(list_next_rcu(pos)); \ - prefetch((pos)->next), (pos) != (head); \ + (pos) != (head); \ (pos) = rcu_dereference_raw(list_next_rcu(pos))) /** @@ -284,7 +284,7 @@ static inline void list_splice_init_rcu(struct list_head *list, */ #define list_for_each_entry_continue_rcu(pos, head, member) \ for (pos = list_entry_rcu(pos->member.next, typeof(*pos), member); \ - prefetch(pos->member.next), &pos->member != (head); \ + &pos->member != (head); \ pos = list_entry_rcu(pos->member.next, typeof(*pos), member)) /** -- cgit v0.10.2 From 80d02085d99039b3b7f3a73c8896226b0cb1ba07 Mon Sep 17 00:00:00 2001 From: "Paul E. McKenney" Date: Thu, 12 May 2011 01:08:07 -0700 Subject: Revert "rcu: Decrease memory-barrier usage based on semi-formal proof" This reverts commit e59fb3120becfb36b22ddb8bd27d065d3cdca499. This reversion was due to (extreme) boot-time slowdowns on SPARC seen by Yinghai Lu and on x86 by Ingo . This is a non-trivial reversion due to intervening commits. Conflicts: Documentation/RCU/trace.txt kernel/rcutree.c Signed-off-by: Ingo Molnar diff --git a/Documentation/RCU/trace.txt b/Documentation/RCU/trace.txt index 8173cec..c078ad4 100644 --- a/Documentation/RCU/trace.txt +++ b/Documentation/RCU/trace.txt @@ -99,11 +99,18 @@ o "qp" indicates that RCU still expects a quiescent state from o "dt" is the current value of the dyntick counter that is incremented when entering or leaving dynticks idle state, either by the - scheduler or by irq. This number is even if the CPU is in - dyntick idle mode and odd otherwise. The number after the first - "/" is the interrupt nesting depth when in dyntick-idle state, - or one greater than the interrupt-nesting depth otherwise. - The number after the second "/" is the NMI nesting depth. + scheduler or by irq. The number after the "/" is the interrupt + nesting depth when in dyntick-idle state, or one greater than + the interrupt-nesting depth otherwise. + + This field is displayed only for CONFIG_NO_HZ kernels. + +o "dn" is the current value of the dyntick counter that is incremented + when entering or leaving dynticks idle state via NMI. If both + the "dt" and "dn" values are even, then this CPU is in dynticks + idle mode and may be ignored by RCU. If either of these two + counters is odd, then RCU must be alert to the possibility of + an RCU read-side critical section running on this CPU. This field is displayed only for CONFIG_NO_HZ kernels. diff --git a/kernel/rcutree.c b/kernel/rcutree.c index 5616b17..e486f7c 100644 --- a/kernel/rcutree.c +++ b/kernel/rcutree.c @@ -162,7 +162,7 @@ EXPORT_SYMBOL_GPL(rcu_note_context_switch); #ifdef CONFIG_NO_HZ DEFINE_PER_CPU(struct rcu_dynticks, rcu_dynticks) = { .dynticks_nesting = 1, - .dynticks = ATOMIC_INIT(1), + .dynticks = 1, }; #endif /* #ifdef CONFIG_NO_HZ */ @@ -321,25 +321,13 @@ void rcu_enter_nohz(void) unsigned long flags; struct rcu_dynticks *rdtp; + smp_mb(); /* CPUs seeing ++ must see prior RCU read-side crit sects */ local_irq_save(flags); rdtp = &__get_cpu_var(rcu_dynticks); - if (--rdtp->dynticks_nesting) { - local_irq_restore(flags); - return; - } - /* CPUs seeing atomic_inc() must see prior RCU read-side crit sects */ - smp_mb__before_atomic_inc(); /* See above. */ - atomic_inc(&rdtp->dynticks); - smp_mb__after_atomic_inc(); /* Force ordering with next sojourn. */ - WARN_ON_ONCE(atomic_read(&rdtp->dynticks) & 0x1); + rdtp->dynticks++; + rdtp->dynticks_nesting--; + WARN_ON_ONCE(rdtp->dynticks & 0x1); local_irq_restore(flags); - - /* If the interrupt queued a callback, get out of dyntick mode. */ - if (in_irq() && - (__get_cpu_var(rcu_sched_data).nxtlist || - __get_cpu_var(rcu_bh_data).nxtlist || - rcu_preempt_needs_cpu(smp_processor_id()))) - set_need_resched(); } /* @@ -355,16 +343,11 @@ void rcu_exit_nohz(void) local_irq_save(flags); rdtp = &__get_cpu_var(rcu_dynticks); - if (rdtp->dynticks_nesting++) { - local_irq_restore(flags); - return; - } - smp_mb__before_atomic_inc(); /* Force ordering w/previous sojourn. */ - atomic_inc(&rdtp->dynticks); - /* CPUs seeing atomic_inc() must see later RCU read-side crit sects */ - smp_mb__after_atomic_inc(); /* See above. */ - WARN_ON_ONCE(!(atomic_read(&rdtp->dynticks) & 0x1)); + rdtp->dynticks++; + rdtp->dynticks_nesting++; + WARN_ON_ONCE(!(rdtp->dynticks & 0x1)); local_irq_restore(flags); + smp_mb(); /* CPUs seeing ++ must see later RCU read-side crit sects */ } /** @@ -378,15 +361,11 @@ void rcu_nmi_enter(void) { struct rcu_dynticks *rdtp = &__get_cpu_var(rcu_dynticks); - if (rdtp->dynticks_nmi_nesting == 0 && - (atomic_read(&rdtp->dynticks) & 0x1)) + if (rdtp->dynticks & 0x1) return; - rdtp->dynticks_nmi_nesting++; - smp_mb__before_atomic_inc(); /* Force delay from prior write. */ - atomic_inc(&rdtp->dynticks); - /* CPUs seeing atomic_inc() must see later RCU read-side crit sects */ - smp_mb__after_atomic_inc(); /* See above. */ - WARN_ON_ONCE(!(atomic_read(&rdtp->dynticks) & 0x1)); + rdtp->dynticks_nmi++; + WARN_ON_ONCE(!(rdtp->dynticks_nmi & 0x1)); + smp_mb(); /* CPUs seeing ++ must see later RCU read-side crit sects */ } /** @@ -400,14 +379,11 @@ void rcu_nmi_exit(void) { struct rcu_dynticks *rdtp = &__get_cpu_var(rcu_dynticks); - if (rdtp->dynticks_nmi_nesting == 0 || - --rdtp->dynticks_nmi_nesting != 0) + if (rdtp->dynticks & 0x1) return; - /* CPUs seeing atomic_inc() must see prior RCU read-side crit sects */ - smp_mb__before_atomic_inc(); /* See above. */ - atomic_inc(&rdtp->dynticks); - smp_mb__after_atomic_inc(); /* Force delay to next write. */ - WARN_ON_ONCE(atomic_read(&rdtp->dynticks) & 0x1); + smp_mb(); /* CPUs seeing ++ must see prior RCU read-side crit sects */ + rdtp->dynticks_nmi++; + WARN_ON_ONCE(rdtp->dynticks_nmi & 0x1); } /** @@ -418,7 +394,13 @@ void rcu_nmi_exit(void) */ void rcu_irq_enter(void) { - rcu_exit_nohz(); + struct rcu_dynticks *rdtp = &__get_cpu_var(rcu_dynticks); + + if (rdtp->dynticks_nesting++) + return; + rdtp->dynticks++; + WARN_ON_ONCE(!(rdtp->dynticks & 0x1)); + smp_mb(); /* CPUs seeing ++ must see later RCU read-side crit sects */ } /** @@ -430,7 +412,18 @@ void rcu_irq_enter(void) */ void rcu_irq_exit(void) { - rcu_enter_nohz(); + struct rcu_dynticks *rdtp = &__get_cpu_var(rcu_dynticks); + + if (--rdtp->dynticks_nesting) + return; + smp_mb(); /* CPUs seeing ++ must see prior RCU read-side crit sects */ + rdtp->dynticks++; + WARN_ON_ONCE(rdtp->dynticks & 0x1); + + /* If the interrupt queued a callback, get out of dyntick mode. */ + if (__this_cpu_read(rcu_sched_data.nxtlist) || + __this_cpu_read(rcu_bh_data.nxtlist)) + set_need_resched(); } #ifdef CONFIG_SMP @@ -442,8 +435,19 @@ void rcu_irq_exit(void) */ static int dyntick_save_progress_counter(struct rcu_data *rdp) { - rdp->dynticks_snap = atomic_add_return(0, &rdp->dynticks->dynticks); - return 0; + int ret; + int snap; + int snap_nmi; + + snap = rdp->dynticks->dynticks; + snap_nmi = rdp->dynticks->dynticks_nmi; + smp_mb(); /* Order sampling of snap with end of grace period. */ + rdp->dynticks_snap = snap; + rdp->dynticks_nmi_snap = snap_nmi; + ret = ((snap & 0x1) == 0) && ((snap_nmi & 0x1) == 0); + if (ret) + rdp->dynticks_fqs++; + return ret; } /* @@ -454,11 +458,16 @@ static int dyntick_save_progress_counter(struct rcu_data *rdp) */ static int rcu_implicit_dynticks_qs(struct rcu_data *rdp) { - unsigned long curr; - unsigned long snap; + long curr; + long curr_nmi; + long snap; + long snap_nmi; - curr = (unsigned long)atomic_add_return(0, &rdp->dynticks->dynticks); - snap = (unsigned long)rdp->dynticks_snap; + curr = rdp->dynticks->dynticks; + snap = rdp->dynticks_snap; + curr_nmi = rdp->dynticks->dynticks_nmi; + snap_nmi = rdp->dynticks_nmi_snap; + smp_mb(); /* force ordering with cpu entering/leaving dynticks. */ /* * If the CPU passed through or entered a dynticks idle phase with @@ -468,7 +477,8 @@ static int rcu_implicit_dynticks_qs(struct rcu_data *rdp) * read-side critical section that started before the beginning * of the current RCU grace period. */ - if ((curr & 0x1) == 0 || ULONG_CMP_GE(curr, snap + 2)) { + if ((curr != snap || (curr & 0x1) == 0) && + (curr_nmi != snap_nmi || (curr_nmi & 0x1) == 0)) { rdp->dynticks_fqs++; return 1; } @@ -897,12 +907,6 @@ static void rcu_report_qs_rsp(struct rcu_state *rsp, unsigned long flags) unsigned long gp_duration; WARN_ON_ONCE(!rcu_gp_in_progress(rsp)); - - /* - * Ensure that all grace-period and pre-grace-period activity - * is seen before the assignment to rsp->completed. - */ - smp_mb(); /* See above block comment. */ gp_duration = jiffies - rsp->gp_start; if (gp_duration > rsp->gp_max) rsp->gp_max = gp_duration; @@ -1450,11 +1454,25 @@ __rcu_process_callbacks(struct rcu_state *rsp, struct rcu_data *rdp) */ static void rcu_process_callbacks(void) { + /* + * Memory references from any prior RCU read-side critical sections + * executed by the interrupted code must be seen before any RCU + * grace-period manipulations below. + */ + smp_mb(); /* See above block comment. */ + __rcu_process_callbacks(&rcu_sched_state, &__get_cpu_var(rcu_sched_data)); __rcu_process_callbacks(&rcu_bh_state, &__get_cpu_var(rcu_bh_data)); rcu_preempt_process_callbacks(); + /* + * Memory references from any later RCU read-side critical sections + * executed by the interrupted code must be seen after any RCU + * grace-period manipulations above. + */ + smp_mb(); /* See above block comment. */ + /* If we are last CPU on way to dyntick-idle mode, accelerate it. */ rcu_needs_cpu_flush(); } diff --git a/kernel/rcutree.h b/kernel/rcutree.h index 93d4a1c..2576648 100644 --- a/kernel/rcutree.h +++ b/kernel/rcutree.h @@ -84,9 +84,11 @@ * Dynticks per-CPU state. */ struct rcu_dynticks { - int dynticks_nesting; /* Track irq/process nesting level. */ - int dynticks_nmi_nesting; /* Track NMI nesting level. */ - atomic_t dynticks; /* Even value for dynticks-idle, else odd. */ + int dynticks_nesting; /* Track nesting level, sort of. */ + int dynticks; /* Even value for dynticks-idle, else odd. */ + int dynticks_nmi; /* Even value for either dynticks-idle or */ + /* not in nmi handler, else odd. So this */ + /* remains even for nmi from irq handler. */ }; /* RCU's kthread states for tracing. */ @@ -282,6 +284,7 @@ struct rcu_data { /* 3) dynticks interface. */ struct rcu_dynticks *dynticks; /* Shared per-CPU dynticks state. */ int dynticks_snap; /* Per-GP tracking for dynticks. */ + int dynticks_nmi_snap; /* Per-GP tracking for dynticks_nmi. */ #endif /* #ifdef CONFIG_NO_HZ */ /* 4) reasons this CPU needed to be kicked by force_quiescent_state */ diff --git a/kernel/rcutree_plugin.h b/kernel/rcutree_plugin.h index ed339702..3f6559a 100644 --- a/kernel/rcutree_plugin.h +++ b/kernel/rcutree_plugin.h @@ -1520,6 +1520,7 @@ int rcu_needs_cpu(int cpu) { int c = 0; int snap; + int snap_nmi; int thatcpu; /* Check for being in the holdoff period. */ @@ -1530,10 +1531,10 @@ int rcu_needs_cpu(int cpu) for_each_online_cpu(thatcpu) { if (thatcpu == cpu) continue; - snap = atomic_add_return(0, &per_cpu(rcu_dynticks, - thatcpu).dynticks); + snap = per_cpu(rcu_dynticks, thatcpu).dynticks; + snap_nmi = per_cpu(rcu_dynticks, thatcpu).dynticks_nmi; smp_mb(); /* Order sampling of snap with end of grace period. */ - if ((snap & 0x1) != 0) { + if (((snap & 0x1) != 0) || ((snap_nmi & 0x1) != 0)) { per_cpu(rcu_dyntick_drain, cpu) = 0; per_cpu(rcu_dyntick_holdoff, cpu) = jiffies - 1; return rcu_needs_cpu_quick_check(cpu); diff --git a/kernel/rcutree_trace.c b/kernel/rcutree_trace.c index 9678cc3..aa0fd72 100644 --- a/kernel/rcutree_trace.c +++ b/kernel/rcutree_trace.c @@ -69,10 +69,10 @@ static void print_one_rcu_data(struct seq_file *m, struct rcu_data *rdp) rdp->passed_quiesc, rdp->passed_quiesc_completed, rdp->qs_pending); #ifdef CONFIG_NO_HZ - seq_printf(m, " dt=%d/%d/%d df=%lu", - atomic_read(&rdp->dynticks->dynticks), + seq_printf(m, " dt=%d/%d dn=%d df=%lu", + rdp->dynticks->dynticks, rdp->dynticks->dynticks_nesting, - rdp->dynticks->dynticks_nmi_nesting, + rdp->dynticks->dynticks_nmi, rdp->dynticks_fqs); #endif /* #ifdef CONFIG_NO_HZ */ seq_printf(m, " of=%lu ri=%lu", rdp->offline_fqs, rdp->resched_ipi); @@ -141,9 +141,9 @@ static void print_one_rcu_data_csv(struct seq_file *m, struct rcu_data *rdp) rdp->qs_pending); #ifdef CONFIG_NO_HZ seq_printf(m, ",%d,%d,%d,%lu", - atomic_read(&rdp->dynticks->dynticks), + rdp->dynticks->dynticks, rdp->dynticks->dynticks_nesting, - rdp->dynticks->dynticks_nmi_nesting, + rdp->dynticks->dynticks_nmi, rdp->dynticks_fqs); #endif /* #ifdef CONFIG_NO_HZ */ seq_printf(m, ",%lu,%lu", rdp->offline_fqs, rdp->resched_ipi); @@ -167,7 +167,7 @@ static int show_rcudata_csv(struct seq_file *m, void *unused) { seq_puts(m, "\"CPU\",\"Online?\",\"c\",\"g\",\"pq\",\"pqc\",\"pq\","); #ifdef CONFIG_NO_HZ - seq_puts(m, "\"dt\",\"dt nesting\",\"dt NMI nesting\",\"df\","); + seq_puts(m, "\"dt\",\"dt nesting\",\"dn\",\"df\","); #endif /* #ifdef CONFIG_NO_HZ */ seq_puts(m, "\"of\",\"ri\",\"ql\",\"b\",\"ci\",\"co\",\"ca\"\n"); #ifdef CONFIG_TREE_PREEMPT_RCU -- cgit v0.10.2 From 99517e3d7930f8cc064f7e9443b1b441e00e83d7 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Thu, 19 May 2011 17:38:57 -0400 Subject: 9p: Kill set but not used variable 'ret' in parse_opts() Signed-off-by: David S. Miller diff --git a/net/9p/trans_fd.c b/net/9p/trans_fd.c index aa5672b..4a90843 100644 --- a/net/9p/trans_fd.c +++ b/net/9p/trans_fd.c @@ -716,7 +716,6 @@ static int parse_opts(char *params, struct p9_fd_opts *opts) substring_t args[MAX_OPT_ARGS]; int option; char *options, *tmp_options; - int ret; opts->port = P9_PORT; opts->rfd = ~0; @@ -744,7 +743,6 @@ static int parse_opts(char *params, struct p9_fd_opts *opts) if (r < 0) { P9_DPRINTK(P9_DEBUG_ERROR, "integer field, but no integer?\n"); - ret = r; continue; } } -- cgit v0.10.2 From 5b5ed8afe48ca6916daabf9822e7a19fc19fdab4 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Thu, 19 May 2011 17:45:29 -0400 Subject: 9p: Kill unused variable 'ret' in trans_rdma.c:parse_opts() Probably just cut and pasted from the other parse_opts() implementations in the 9p sources. Signed-off-by: David S. Miller diff --git a/net/9p/trans_rdma.c b/net/9p/trans_rdma.c index 150e0c4..844a7a5 100644 --- a/net/9p/trans_rdma.c +++ b/net/9p/trans_rdma.c @@ -167,7 +167,6 @@ static int parse_opts(char *params, struct p9_rdma_opts *opts) substring_t args[MAX_OPT_ARGS]; int option; char *options, *tmp_options; - int ret; opts->port = P9_PORT; opts->sq_depth = P9_RDMA_SQ_DEPTH; @@ -195,7 +194,6 @@ static int parse_opts(char *params, struct p9_rdma_opts *opts) if (r < 0) { P9_DPRINTK(P9_DEBUG_ERROR, "integer field, but no integer?\n"); - ret = r; continue; } switch (token) { -- cgit v0.10.2 From 2ffcc981d823a0518c627ca22d51ef72d0b7ca9a Mon Sep 17 00:00:00 2001 From: Matt Carlson Date: Thu, 19 May 2011 12:12:44 +0000 Subject: tg3: Set tx bug flags for more devices It has been recently discovered that all tg3 devices have a 4Gb boundary DMA problem, and that all 5755 and newer devices can't handle fragments less than or equal to 8 bytes in size. This patch adjusts the flags and removes tg3_start_xmit(). tg3_start_xmit_dma_bug() has been renamed to tg3_start_xmit(). Signed-off-by: Matt Carlson Reviewed-by: Michael Chan Signed-off-by: David S. Miller diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index d5a1f9e..4c44168 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -5735,7 +5735,28 @@ static inline int tg3_40bit_overflow_test(struct tg3 *tp, dma_addr_t mapping, #endif } -static void tg3_set_txd(struct tg3_napi *, int, dma_addr_t, int, u32, u32); +static void tg3_set_txd(struct tg3_napi *tnapi, int entry, + dma_addr_t mapping, int len, u32 flags, + u32 mss_and_is_end) +{ + struct tg3_tx_buffer_desc *txd = &tnapi->tx_ring[entry]; + int is_end = (mss_and_is_end & 0x1); + u32 mss = (mss_and_is_end >> 1); + u32 vlan_tag = 0; + + if (is_end) + flags |= TXD_FLAG_END; + if (flags & TXD_FLAG_VLAN) { + vlan_tag = flags >> 16; + flags &= 0xffff; + } + vlan_tag |= (mss << TXD_MSS_SHIFT); + + txd->addr_hi = ((u64) mapping >> 32); + txd->addr_lo = ((u64) mapping & 0xffffffff); + txd->len_flags = (len << TXD_LEN_SHIFT) | flags; + txd->vlan_tag = vlan_tag << TXD_VLAN_TAG_SHIFT; +} /* Workaround 4GB and 40-bit hardware DMA bugs. */ static int tigon3_dma_hwbug_workaround(struct tg3_napi *tnapi, @@ -5818,202 +5839,7 @@ static int tigon3_dma_hwbug_workaround(struct tg3_napi *tnapi, return ret; } -static void tg3_set_txd(struct tg3_napi *tnapi, int entry, - dma_addr_t mapping, int len, u32 flags, - u32 mss_and_is_end) -{ - struct tg3_tx_buffer_desc *txd = &tnapi->tx_ring[entry]; - int is_end = (mss_and_is_end & 0x1); - u32 mss = (mss_and_is_end >> 1); - u32 vlan_tag = 0; - - if (is_end) - flags |= TXD_FLAG_END; - if (flags & TXD_FLAG_VLAN) { - vlan_tag = flags >> 16; - flags &= 0xffff; - } - vlan_tag |= (mss << TXD_MSS_SHIFT); - - txd->addr_hi = ((u64) mapping >> 32); - txd->addr_lo = ((u64) mapping & 0xffffffff); - txd->len_flags = (len << TXD_LEN_SHIFT) | flags; - txd->vlan_tag = vlan_tag << TXD_VLAN_TAG_SHIFT; -} - -/* hard_start_xmit for devices that don't have any bugs and - * support TG3_FLAG_HW_TSO_2 and TG3_FLAG_HW_TSO_3 only. - */ -static netdev_tx_t tg3_start_xmit(struct sk_buff *skb, - struct net_device *dev) -{ - struct tg3 *tp = netdev_priv(dev); - u32 len, entry, base_flags, mss; - dma_addr_t mapping; - struct tg3_napi *tnapi; - struct netdev_queue *txq; - unsigned int i, last; - - txq = netdev_get_tx_queue(dev, skb_get_queue_mapping(skb)); - tnapi = &tp->napi[skb_get_queue_mapping(skb)]; - if (tg3_flag(tp, ENABLE_TSS)) - tnapi++; - - /* We are running in BH disabled context with netif_tx_lock - * and TX reclaim runs via tp->napi.poll inside of a software - * interrupt. Furthermore, IRQ processing runs lockless so we have - * no IRQ context deadlocks to worry about either. Rejoice! - */ - if (unlikely(tg3_tx_avail(tnapi) <= (skb_shinfo(skb)->nr_frags + 1))) { - if (!netif_tx_queue_stopped(txq)) { - netif_tx_stop_queue(txq); - - /* This is a hard error, log it. */ - netdev_err(dev, - "BUG! Tx Ring full when queue awake!\n"); - } - return NETDEV_TX_BUSY; - } - - entry = tnapi->tx_prod; - base_flags = 0; - mss = skb_shinfo(skb)->gso_size; - if (mss) { - int tcp_opt_len, ip_tcp_len; - u32 hdrlen; - - if (skb_header_cloned(skb) && - pskb_expand_head(skb, 0, 0, GFP_ATOMIC)) { - dev_kfree_skb(skb); - goto out_unlock; - } - - if (skb_is_gso_v6(skb)) { - hdrlen = skb_headlen(skb) - ETH_HLEN; - } else { - struct iphdr *iph = ip_hdr(skb); - - tcp_opt_len = tcp_optlen(skb); - ip_tcp_len = ip_hdrlen(skb) + sizeof(struct tcphdr); - - iph->check = 0; - iph->tot_len = htons(mss + ip_tcp_len + tcp_opt_len); - hdrlen = ip_tcp_len + tcp_opt_len; - } - - if (tg3_flag(tp, HW_TSO_3)) { - mss |= (hdrlen & 0xc) << 12; - if (hdrlen & 0x10) - base_flags |= 0x00000010; - base_flags |= (hdrlen & 0x3e0) << 5; - } else - mss |= hdrlen << 9; - - base_flags |= (TXD_FLAG_CPU_PRE_DMA | - TXD_FLAG_CPU_POST_DMA); - - tcp_hdr(skb)->check = 0; - - } else if (skb->ip_summed == CHECKSUM_PARTIAL) { - base_flags |= TXD_FLAG_TCPUDP_CSUM; - } - - if (vlan_tx_tag_present(skb)) - base_flags |= (TXD_FLAG_VLAN | - (vlan_tx_tag_get(skb) << 16)); - - len = skb_headlen(skb); - - /* Queue skb data, a.k.a. the main skb fragment. */ - mapping = pci_map_single(tp->pdev, skb->data, len, PCI_DMA_TODEVICE); - if (pci_dma_mapping_error(tp->pdev, mapping)) { - dev_kfree_skb(skb); - goto out_unlock; - } - - tnapi->tx_buffers[entry].skb = skb; - dma_unmap_addr_set(&tnapi->tx_buffers[entry], mapping, mapping); - - if (tg3_flag(tp, USE_JUMBO_BDFLAG) && - !mss && skb->len > VLAN_ETH_FRAME_LEN) - base_flags |= TXD_FLAG_JMB_PKT; - - tg3_set_txd(tnapi, entry, mapping, len, base_flags, - (skb_shinfo(skb)->nr_frags == 0) | (mss << 1)); - - entry = NEXT_TX(entry); - - /* Now loop through additional data fragments, and queue them. */ - if (skb_shinfo(skb)->nr_frags > 0) { - last = skb_shinfo(skb)->nr_frags - 1; - for (i = 0; i <= last; i++) { - skb_frag_t *frag = &skb_shinfo(skb)->frags[i]; - - len = frag->size; - mapping = pci_map_page(tp->pdev, - frag->page, - frag->page_offset, - len, PCI_DMA_TODEVICE); - if (pci_dma_mapping_error(tp->pdev, mapping)) - goto dma_error; - - tnapi->tx_buffers[entry].skb = NULL; - dma_unmap_addr_set(&tnapi->tx_buffers[entry], mapping, - mapping); - - tg3_set_txd(tnapi, entry, mapping, len, - base_flags, (i == last) | (mss << 1)); - - entry = NEXT_TX(entry); - } - } - - /* Packets are ready, update Tx producer idx local and on card. */ - tw32_tx_mbox(tnapi->prodmbox, entry); - - tnapi->tx_prod = entry; - if (unlikely(tg3_tx_avail(tnapi) <= (MAX_SKB_FRAGS + 1))) { - netif_tx_stop_queue(txq); - - /* netif_tx_stop_queue() must be done before checking - * checking tx index in tg3_tx_avail() below, because in - * tg3_tx(), we update tx index before checking for - * netif_tx_queue_stopped(). - */ - smp_mb(); - if (tg3_tx_avail(tnapi) > TG3_TX_WAKEUP_THRESH(tnapi)) - netif_tx_wake_queue(txq); - } - -out_unlock: - mmiowb(); - - return NETDEV_TX_OK; - -dma_error: - last = i; - entry = tnapi->tx_prod; - tnapi->tx_buffers[entry].skb = NULL; - pci_unmap_single(tp->pdev, - dma_unmap_addr(&tnapi->tx_buffers[entry], mapping), - skb_headlen(skb), - PCI_DMA_TODEVICE); - for (i = 0; i <= last; i++) { - skb_frag_t *frag = &skb_shinfo(skb)->frags[i]; - entry = NEXT_TX(entry); - - pci_unmap_page(tp->pdev, - dma_unmap_addr(&tnapi->tx_buffers[entry], - mapping), - frag->size, PCI_DMA_TODEVICE); - } - - dev_kfree_skb(skb); - return NETDEV_TX_OK; -} - -static netdev_tx_t tg3_start_xmit_dma_bug(struct sk_buff *, - struct net_device *); +static netdev_tx_t tg3_start_xmit(struct sk_buff *, struct net_device *); /* Use GSO to workaround a rare TSO bug that may be triggered when the * TSO header is greater than 80 bytes. @@ -6047,7 +5873,7 @@ static int tg3_tso_bug(struct tg3 *tp, struct sk_buff *skb) nskb = segs; segs = segs->next; nskb->next = NULL; - tg3_start_xmit_dma_bug(nskb, tp->dev); + tg3_start_xmit(nskb, tp->dev); } while (segs); tg3_tso_bug_end: @@ -6059,8 +5885,7 @@ tg3_tso_bug_end: /* hard_start_xmit for devices that have the 4G bug and/or 40-bit bug and * support TG3_FLAG_HW_TSO_1 or firmware TSO only. */ -static netdev_tx_t tg3_start_xmit_dma_bug(struct sk_buff *skb, - struct net_device *dev) +static netdev_tx_t tg3_start_xmit(struct sk_buff *skb, struct net_device *dev) { struct tg3 *tp = netdev_priv(dev); u32 len, entry, base_flags, mss; @@ -13857,14 +13682,15 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) } } - if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5717 || - GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5719 || - GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906) + /* All chips can get confused if TX buffers + * straddle the 4GB address boundary. + */ + tg3_flag_set(tp, 4G_DMA_BNDRY_BUG); + + if (tg3_flag(tp, 5755_PLUS)) tg3_flag_set(tp, SHORT_DMA_BUG); - else if (!tg3_flag(tp, 5755_PLUS)) { - tg3_flag_set(tp, 4G_DMA_BNDRY_BUG); + else tg3_flag_set(tp, 40BIT_DMA_LIMIT_BUG); - } if (tg3_flag(tp, 5717_PLUS)) tg3_flag_set(tp, LRG_PROD_RING_CAP); @@ -15092,23 +14918,6 @@ static const struct net_device_ops tg3_netdev_ops = { #endif }; -static const struct net_device_ops tg3_netdev_ops_dma_bug = { - .ndo_open = tg3_open, - .ndo_stop = tg3_close, - .ndo_start_xmit = tg3_start_xmit_dma_bug, - .ndo_get_stats64 = tg3_get_stats64, - .ndo_validate_addr = eth_validate_addr, - .ndo_set_multicast_list = tg3_set_rx_mode, - .ndo_set_mac_address = tg3_set_mac_addr, - .ndo_do_ioctl = tg3_ioctl, - .ndo_tx_timeout = tg3_tx_timeout, - .ndo_change_mtu = tg3_change_mtu, - .ndo_set_features = tg3_set_features, -#ifdef CONFIG_NET_POLL_CONTROLLER - .ndo_poll_controller = tg3_poll_controller, -#endif -}; - static int __devinit tg3_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) { @@ -15205,6 +15014,7 @@ static int __devinit tg3_init_one(struct pci_dev *pdev, dev->ethtool_ops = &tg3_ethtool_ops; dev->watchdog_timeo = TG3_TX_TIMEOUT; + dev->netdev_ops = &tg3_netdev_ops; dev->irq = pdev->irq; err = tg3_get_invariants(tp); @@ -15214,12 +15024,6 @@ static int __devinit tg3_init_one(struct pci_dev *pdev, goto err_out_iounmap; } - if (tg3_flag(tp, 5755_PLUS) && !tg3_flag(tp, 5717_PLUS)) - dev->netdev_ops = &tg3_netdev_ops; - else - dev->netdev_ops = &tg3_netdev_ops_dma_bug; - - /* The EPB bridge inside 5714, 5715, and 5780 and any * device behind the EPB cannot support DMA addresses > 40-bit. * On 64-bit systems with IOMMU, use 40-bit dma_mask. -- cgit v0.10.2 From 432aa7ed75b3adaef6040d2cbe745fdd1c899415 Mon Sep 17 00:00:00 2001 From: Matt Carlson Date: Thu, 19 May 2011 12:12:45 +0000 Subject: tg3: Cleanup transmit error path This patch consolidates the skb cleanup code into a function named tg3_skb_error_unmap(). The modification addresses a long-standing bug where pci_unmap_single() was incorrectly being called instead of pci_unmap_page() in tigon3_dma_hwbug_workaround(). Signed-off-by: Matt Carlson Reviewed-by: Michael Chan Signed-off-by: David S. Miller diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index 4c44168..b2b1ba1 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -5758,16 +5758,39 @@ static void tg3_set_txd(struct tg3_napi *tnapi, int entry, txd->vlan_tag = vlan_tag << TXD_VLAN_TAG_SHIFT; } +static void tg3_skb_error_unmap(struct tg3_napi *tnapi, + struct sk_buff *skb, int last) +{ + int i; + u32 entry = tnapi->tx_prod; + struct ring_info *txb = &tnapi->tx_buffers[entry]; + + pci_unmap_single(tnapi->tp->pdev, + dma_unmap_addr(txb, mapping), + skb_headlen(skb), + PCI_DMA_TODEVICE); + for (i = 0; i <= last; i++) { + skb_frag_t *frag = &skb_shinfo(skb)->frags[i]; + + entry = NEXT_TX(entry); + txb = &tnapi->tx_buffers[entry]; + + pci_unmap_page(tnapi->tp->pdev, + dma_unmap_addr(txb, mapping), + frag->size, PCI_DMA_TODEVICE); + } +} + /* Workaround 4GB and 40-bit hardware DMA bugs. */ static int tigon3_dma_hwbug_workaround(struct tg3_napi *tnapi, - struct sk_buff *skb, u32 last_plus_one, - u32 *start, u32 base_flags, u32 mss) + struct sk_buff *skb, + u32 base_flags, u32 mss) { struct tg3 *tp = tnapi->tp; struct sk_buff *new_skb; dma_addr_t new_addr = 0; - u32 entry = *start; - int i, ret = 0; + u32 entry = tnapi->tx_prod; + int ret = 0; if (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5701) new_skb = skb_copy(skb, GFP_ATOMIC); @@ -5783,14 +5806,12 @@ static int tigon3_dma_hwbug_workaround(struct tg3_napi *tnapi, ret = -1; } else { /* New SKB is guaranteed to be linear. */ - entry = *start; new_addr = pci_map_single(tp->pdev, new_skb->data, new_skb->len, PCI_DMA_TODEVICE); /* Make sure the mapping succeeded */ if (pci_dma_mapping_error(tp->pdev, new_addr)) { ret = -1; dev_kfree_skb(new_skb); - new_skb = NULL; /* Make sure new skb does not cross any 4G boundaries. * Drop the packet if it does. @@ -5801,39 +5822,16 @@ static int tigon3_dma_hwbug_workaround(struct tg3_napi *tnapi, PCI_DMA_TODEVICE); ret = -1; dev_kfree_skb(new_skb); - new_skb = NULL; } else { + tnapi->tx_buffers[entry].skb = new_skb; + dma_unmap_addr_set(&tnapi->tx_buffers[entry], + mapping, new_addr); + tg3_set_txd(tnapi, entry, new_addr, new_skb->len, base_flags, 1 | (mss << 1)); - *start = NEXT_TX(entry); } } - /* Now clean up the sw ring entries. */ - i = 0; - while (entry != last_plus_one) { - int len; - - if (i == 0) - len = skb_headlen(skb); - else - len = skb_shinfo(skb)->frags[i-1].size; - - pci_unmap_single(tp->pdev, - dma_unmap_addr(&tnapi->tx_buffers[entry], - mapping), - len, PCI_DMA_TODEVICE); - if (i == 0) { - tnapi->tx_buffers[entry].skb = new_skb; - dma_unmap_addr_set(&tnapi->tx_buffers[entry], mapping, - new_addr); - } else { - tnapi->tx_buffers[entry].skb = NULL; - } - entry = NEXT_TX(entry); - i++; - } - dev_kfree_skb(skb); return ret; @@ -5889,11 +5887,11 @@ static netdev_tx_t tg3_start_xmit(struct sk_buff *skb, struct net_device *dev) { struct tg3 *tp = netdev_priv(dev); u32 len, entry, base_flags, mss; - int would_hit_hwbug; + int i = -1, would_hit_hwbug; dma_addr_t mapping; struct tg3_napi *tnapi; struct netdev_queue *txq; - unsigned int i, last; + unsigned int last; txq = netdev_get_tx_queue(dev, skb_get_queue_mapping(skb)); tnapi = &tp->napi[skb_get_queue_mapping(skb)]; @@ -6074,20 +6072,15 @@ static netdev_tx_t tg3_start_xmit(struct sk_buff *skb, struct net_device *dev) } if (would_hit_hwbug) { - u32 last_plus_one = entry; - u32 start; - - start = entry - 1 - skb_shinfo(skb)->nr_frags; - start &= (TG3_TX_RING_SIZE - 1); + tg3_skb_error_unmap(tnapi, skb, i); /* If the workaround fails due to memory/mapping * failure, silently drop this packet. */ - if (tigon3_dma_hwbug_workaround(tnapi, skb, last_plus_one, - &start, base_flags, mss)) + if (tigon3_dma_hwbug_workaround(tnapi, skb, base_flags, mss)) goto out_unlock; - entry = start; + entry = NEXT_TX(tnapi->tx_prod); } /* Packets are ready, update Tx producer idx local and on card. */ @@ -6113,24 +6106,9 @@ out_unlock: return NETDEV_TX_OK; dma_error: - last = i; - entry = tnapi->tx_prod; - tnapi->tx_buffers[entry].skb = NULL; - pci_unmap_single(tp->pdev, - dma_unmap_addr(&tnapi->tx_buffers[entry], mapping), - skb_headlen(skb), - PCI_DMA_TODEVICE); - for (i = 0; i <= last; i++) { - skb_frag_t *frag = &skb_shinfo(skb)->frags[i]; - entry = NEXT_TX(entry); - - pci_unmap_page(tp->pdev, - dma_unmap_addr(&tnapi->tx_buffers[entry], - mapping), - frag->size, PCI_DMA_TODEVICE); - } - + tg3_skb_error_unmap(tnapi, skb, i); dev_kfree_skb(skb); + tnapi->tx_buffers[tnapi->tx_prod].skb = NULL; return NETDEV_TX_OK; } -- cgit v0.10.2 From 1ff30a59f6d0c754e99442501a5145bdbbcfa6ea Mon Sep 17 00:00:00 2001 From: Matt Carlson Date: Thu, 19 May 2011 12:12:46 +0000 Subject: tg3: Fix 57765 B0 data corruption The PCIe max FTS limit is too aggressive on these chips. This patch loosens the limit a little to eliminate data corruption issues. Signed-off-by: Matt Carlson Reviewed-by: Michael Chan Signed-off-by: David S. Miller diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index b2b1ba1..09f2c11 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -7990,6 +7990,22 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy) tw32(GRC_MODE, grc_mode); } + if (GET_CHIP_REV(tp->pci_chip_rev_id) != CHIPREV_57765_AX) { + u32 grc_mode = tr32(GRC_MODE); + + /* Access the lower 1K of DL PCIE block registers. */ + val = grc_mode & ~GRC_MODE_PCIE_PORT_MASK; + tw32(GRC_MODE, val | GRC_MODE_PCIE_DL_SEL); + + val = tr32(TG3_PCIE_TLDLPL_PORT + + TG3_PCIE_DL_LO_FTSMAX); + val &= ~TG3_PCIE_DL_LO_FTSMAX_MSK; + tw32(TG3_PCIE_TLDLPL_PORT + TG3_PCIE_DL_LO_FTSMAX, + val | TG3_PCIE_DL_LO_FTSMAX_VAL); + + tw32(GRC_MODE, grc_mode); + } + val = tr32(TG3_CPMU_LSPD_10MB_CLK); val &= ~CPMU_LSPD_10MB_MACCLK_MASK; val |= CPMU_LSPD_10MB_MACCLK_6_25; diff --git a/drivers/net/tg3.h b/drivers/net/tg3.h index ce010cd3..330959b 100644 --- a/drivers/net/tg3.h +++ b/drivers/net/tg3.h @@ -180,6 +180,7 @@ #define CHIPREV_5750_BX 0x41 #define CHIPREV_5784_AX 0x57840 #define CHIPREV_5761_AX 0x57610 +#define CHIPREV_57765_AX 0x577650 #define GET_METAL_REV(CHIP_REV_ID) ((CHIP_REV_ID) & 0xff) #define METAL_REV_A0 0x00 #define METAL_REV_A1 0x01 @@ -1951,6 +1952,9 @@ /* Alternate PCIE definitions */ #define TG3_PCIE_TLDLPL_PORT 0x00007c00 +#define TG3_PCIE_DL_LO_FTSMAX 0x0000000c +#define TG3_PCIE_DL_LO_FTSMAX_MSK 0x000000ff +#define TG3_PCIE_DL_LO_FTSMAX_VAL 0x0000002c #define TG3_PCIE_PL_LO_PHYCTL1 0x00000004 #define TG3_PCIE_PL_LO_PHYCTL1_L1PLLPD_EN 0x00001000 #define TG3_PCIE_PL_LO_PHYCTL5 0x00000014 -- cgit v0.10.2 From 108a6c1655f184c9abb7b5917838a8fb204361f5 Mon Sep 17 00:00:00 2001 From: Matt Carlson Date: Thu, 19 May 2011 12:12:47 +0000 Subject: tg3: Fix IPv6 TCP problems for 5719 Commit 4d163b75e979833979cc401ae433cb1d7743d57e, entitled "tg3: Fix 5719 A0 tx completion bug" turned off TSO to fix a hardware bug. In doing so, it accidentally turned off all IPv6 TCP checksum offloading too. This patch fixes the problem by reenabling the hardware bit that control both features. The TSO capability is still not exposed to the kernel. Signed-off-by: Matt Carlson Reviewed-by: Michael Chan Signed-off-by: David S. Miller diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index 09f2c11..6c53e2c 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -8303,7 +8303,7 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy) tg3_flag(tp, HW_TSO_3)) rdmac_mode |= RDMAC_MODE_IPV4_LSO_EN; - if (tg3_flag(tp, HW_TSO_3) || + if (tg3_flag(tp, 57765_PLUS) || GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5785 || GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57780) rdmac_mode |= RDMAC_MODE_IPV6_LSO_EN; -- cgit v0.10.2 From b0c5943f1ca4df6c1c451ef6be5287a161d29a9d Mon Sep 17 00:00:00 2001 From: Matt Carlson Date: Thu, 19 May 2011 12:12:48 +0000 Subject: tg3: Fix EEE interoperability workaround Commit 21a00ab270f95d32e502d92f166dd75c518d3c5f, entitled "tg3: Fix EEE interoperability issue", added an EEE interoperability fix. We found that the fix doesn't work if applied too early though. This patch delays the fix until right before allowing LPI assertion. Signed-off-by: Matt Carlson Reviewed-by: Michael Chan Signed-off-by: David S. Miller diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index 6c53e2c..695dab2 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -1822,22 +1822,9 @@ static void tg3_phy_eee_adjust(struct tg3 *tp, u32 current_link_up) tg3_phy_cl45_read(tp, MDIO_MMD_AN, TG3_CL45_D7_EEERES_STAT, &val); - switch (val) { - case TG3_CL45_D7_EEERES_STAT_LP_1000T: - switch (GET_ASIC_REV(tp->pci_chip_rev_id)) { - case ASIC_REV_5717: - case ASIC_REV_5719: - case ASIC_REV_57765: - if (!TG3_PHY_AUXCTL_SMDSP_ENABLE(tp)) { - tg3_phydsp_write(tp, MII_TG3_DSP_TAP26, - 0x0000); - TG3_PHY_AUXCTL_SMDSP_DISABLE(tp); - } - } - /* Fallthrough */ - case TG3_CL45_D7_EEERES_STAT_LP_100TX: + if (val == TG3_CL45_D7_EEERES_STAT_LP_1000T || + val == TG3_CL45_D7_EEERES_STAT_LP_100TX) tp->setlpicnt = 2; - } } if (!tp->setlpicnt) { @@ -1846,6 +1833,23 @@ static void tg3_phy_eee_adjust(struct tg3 *tp, u32 current_link_up) } } +static void tg3_phy_eee_enable(struct tg3 *tp) +{ + u32 val; + + if (tp->link_config.active_speed == SPEED_1000 && + (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5717 || + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5719 || + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57765) && + !TG3_PHY_AUXCTL_SMDSP_ENABLE(tp)) { + tg3_phydsp_write(tp, MII_TG3_DSP_TAP26, 0x0003); + TG3_PHY_AUXCTL_SMDSP_DISABLE(tp); + } + + val = tr32(TG3_CPMU_EEE_MODE); + tw32(TG3_CPMU_EEE_MODE, val | TG3_CPMU_EEEMD_LPI_ENABLE); +} + static int tg3_wait_macro_done(struct tg3 *tp) { int limit = 100; @@ -8844,11 +8848,8 @@ static void tg3_timer(unsigned long __opaque) if (tg3_flag(tp, 5705_PLUS)) tg3_periodic_fetch_stats(tp); - if (tp->setlpicnt && !--tp->setlpicnt) { - u32 val = tr32(TG3_CPMU_EEE_MODE); - tw32(TG3_CPMU_EEE_MODE, - val | TG3_CPMU_EEEMD_LPI_ENABLE); - } + if (tp->setlpicnt && !--tp->setlpicnt) + tg3_phy_eee_enable(tp); if (tg3_flag(tp, USE_LINKCHG_REG)) { u32 mac_stat; diff --git a/drivers/net/tg3.h b/drivers/net/tg3.h index 330959b..83f45bf 100644 --- a/drivers/net/tg3.h +++ b/drivers/net/tg3.h @@ -2186,7 +2186,7 @@ #define MII_TG3_DSP_TAP26_OPCSINPT 0x0004 #define MII_TG3_DSP_AADJ1CH0 0x001f #define MII_TG3_DSP_CH34TP2 0x4022 -#define MII_TG3_DSP_CH34TP2_HIBW01 0x0010 +#define MII_TG3_DSP_CH34TP2_HIBW01 0x017b #define MII_TG3_DSP_AADJ1CH3 0x601f #define MII_TG3_DSP_AADJ1CH3_ADCCKADJ 0x0002 #define MII_TG3_DSP_EXP1_INT_STAT 0x0f01 -- cgit v0.10.2 From 42b64a450b81ec9e8cdd5b3fb13613ab9bb25048 Mon Sep 17 00:00:00 2001 From: Matt Carlson Date: Thu, 19 May 2011 12:12:49 +0000 Subject: tg3: Consolidate autoneg advertisement setup code Autonegotiation setup has gotten a little more complicated since the tg3 driver was created. This patch consolidates autoneg setup into one routine and modifies the call sites accordingly. Signed-off-by: Matt Carlson Reviewed-by: Michael Chan Signed-off-by: David S. Miller diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index 695dab2..7675231 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -2929,102 +2929,54 @@ static void tg3_aux_stat_to_speed_duplex(struct tg3 *tp, u32 val, u16 *speed, u8 } } -static void tg3_phy_copper_begin(struct tg3 *tp) +static int tg3_phy_autoneg_cfg(struct tg3 *tp, u32 advertise, u32 flowctrl) { - u32 new_adv; - int i; - - if (tp->phy_flags & TG3_PHYFLG_IS_LOW_POWER) { - /* Entering low power mode. Disable gigabit and - * 100baseT advertisements. - */ - tg3_writephy(tp, MII_TG3_CTRL, 0); + int err = 0; + u32 val, new_adv; - new_adv = (ADVERTISE_10HALF | ADVERTISE_10FULL | - ADVERTISE_CSMA | ADVERTISE_PAUSE_CAP); - if (tg3_flag(tp, WOL_SPEED_100MB)) - new_adv |= (ADVERTISE_100HALF | ADVERTISE_100FULL); + new_adv = ADVERTISE_CSMA; + if (advertise & ADVERTISED_10baseT_Half) + new_adv |= ADVERTISE_10HALF; + if (advertise & ADVERTISED_10baseT_Full) + new_adv |= ADVERTISE_10FULL; + if (advertise & ADVERTISED_100baseT_Half) + new_adv |= ADVERTISE_100HALF; + if (advertise & ADVERTISED_100baseT_Full) + new_adv |= ADVERTISE_100FULL; - tg3_writephy(tp, MII_ADVERTISE, new_adv); - } else if (tp->link_config.speed == SPEED_INVALID) { - if (tp->phy_flags & TG3_PHYFLG_10_100_ONLY) - tp->link_config.advertising &= - ~(ADVERTISED_1000baseT_Half | - ADVERTISED_1000baseT_Full); + new_adv |= tg3_advert_flowctrl_1000T(flowctrl); - new_adv = ADVERTISE_CSMA; - if (tp->link_config.advertising & ADVERTISED_10baseT_Half) - new_adv |= ADVERTISE_10HALF; - if (tp->link_config.advertising & ADVERTISED_10baseT_Full) - new_adv |= ADVERTISE_10FULL; - if (tp->link_config.advertising & ADVERTISED_100baseT_Half) - new_adv |= ADVERTISE_100HALF; - if (tp->link_config.advertising & ADVERTISED_100baseT_Full) - new_adv |= ADVERTISE_100FULL; - - new_adv |= tg3_advert_flowctrl_1000T(tp->link_config.flowctrl); - - tg3_writephy(tp, MII_ADVERTISE, new_adv); - - if (tp->link_config.advertising & - (ADVERTISED_1000baseT_Half | ADVERTISED_1000baseT_Full)) { - new_adv = 0; - if (tp->link_config.advertising & ADVERTISED_1000baseT_Half) - new_adv |= MII_TG3_CTRL_ADV_1000_HALF; - if (tp->link_config.advertising & ADVERTISED_1000baseT_Full) - new_adv |= MII_TG3_CTRL_ADV_1000_FULL; - if (!(tp->phy_flags & TG3_PHYFLG_10_100_ONLY) && - (tp->pci_chip_rev_id == CHIPREV_ID_5701_A0 || - tp->pci_chip_rev_id == CHIPREV_ID_5701_B0)) - new_adv |= (MII_TG3_CTRL_AS_MASTER | - MII_TG3_CTRL_ENABLE_AS_MASTER); - tg3_writephy(tp, MII_TG3_CTRL, new_adv); - } else { - tg3_writephy(tp, MII_TG3_CTRL, 0); - } - } else { - new_adv = tg3_advert_flowctrl_1000T(tp->link_config.flowctrl); - new_adv |= ADVERTISE_CSMA; + err = tg3_writephy(tp, MII_ADVERTISE, new_adv); + if (err) + goto done; - /* Asking for a specific link mode. */ - if (tp->link_config.speed == SPEED_1000) { - tg3_writephy(tp, MII_ADVERTISE, new_adv); + if (tp->phy_flags & TG3_PHYFLG_10_100_ONLY) + goto done; - if (tp->link_config.duplex == DUPLEX_FULL) - new_adv = MII_TG3_CTRL_ADV_1000_FULL; - else - new_adv = MII_TG3_CTRL_ADV_1000_HALF; - if (tp->pci_chip_rev_id == CHIPREV_ID_5701_A0 || - tp->pci_chip_rev_id == CHIPREV_ID_5701_B0) - new_adv |= (MII_TG3_CTRL_AS_MASTER | - MII_TG3_CTRL_ENABLE_AS_MASTER); - } else { - if (tp->link_config.speed == SPEED_100) { - if (tp->link_config.duplex == DUPLEX_FULL) - new_adv |= ADVERTISE_100FULL; - else - new_adv |= ADVERTISE_100HALF; - } else { - if (tp->link_config.duplex == DUPLEX_FULL) - new_adv |= ADVERTISE_10FULL; - else - new_adv |= ADVERTISE_10HALF; - } - tg3_writephy(tp, MII_ADVERTISE, new_adv); + new_adv = 0; + if (advertise & ADVERTISED_1000baseT_Half) + new_adv |= MII_TG3_CTRL_ADV_1000_HALF; + if (advertise & ADVERTISED_1000baseT_Full) + new_adv |= MII_TG3_CTRL_ADV_1000_FULL; - new_adv = 0; - } + if (tp->pci_chip_rev_id == CHIPREV_ID_5701_A0 || + tp->pci_chip_rev_id == CHIPREV_ID_5701_B0) + new_adv |= (MII_TG3_CTRL_AS_MASTER | + MII_TG3_CTRL_ENABLE_AS_MASTER); - tg3_writephy(tp, MII_TG3_CTRL, new_adv); - } + err = tg3_writephy(tp, MII_TG3_CTRL, new_adv); + if (err) + goto done; - if (tp->phy_flags & TG3_PHYFLG_EEE_CAP) { - u32 val; + if (!(tp->phy_flags & TG3_PHYFLG_EEE_CAP)) + goto done; - tw32(TG3_CPMU_EEE_MODE, - tr32(TG3_CPMU_EEE_MODE) & ~TG3_CPMU_EEEMD_LPI_ENABLE); + tw32(TG3_CPMU_EEE_MODE, + tr32(TG3_CPMU_EEE_MODE) & ~TG3_CPMU_EEEMD_LPI_ENABLE); - TG3_PHY_AUXCTL_SMDSP_ENABLE(tp); + err = TG3_PHY_AUXCTL_SMDSP_ENABLE(tp); + if (!err) { + u32 err2; switch (GET_ASIC_REV(tp->pci_chip_rev_id)) { case ASIC_REV_5717: @@ -3041,19 +2993,66 @@ static void tg3_phy_copper_begin(struct tg3 *tp) } val = 0; - if (tp->link_config.autoneg == AUTONEG_ENABLE) { - /* Advertise 100-BaseTX EEE ability */ - if (tp->link_config.advertising & - ADVERTISED_100baseT_Full) - val |= MDIO_AN_EEE_ADV_100TX; - /* Advertise 1000-BaseT EEE ability */ - if (tp->link_config.advertising & - ADVERTISED_1000baseT_Full) - val |= MDIO_AN_EEE_ADV_1000T; + /* Advertise 100-BaseTX EEE ability */ + if (advertise & ADVERTISED_100baseT_Full) + val |= MDIO_AN_EEE_ADV_100TX; + /* Advertise 1000-BaseT EEE ability */ + if (advertise & ADVERTISED_1000baseT_Full) + val |= MDIO_AN_EEE_ADV_1000T; + err = tg3_phy_cl45_write(tp, MDIO_MMD_AN, MDIO_AN_EEE_ADV, val); + + err2 = TG3_PHY_AUXCTL_SMDSP_DISABLE(tp); + if (!err) + err = err2; + } + +done: + return err; +} + +static void tg3_phy_copper_begin(struct tg3 *tp) +{ + u32 new_adv; + int i; + + if (tp->phy_flags & TG3_PHYFLG_IS_LOW_POWER) { + new_adv = ADVERTISED_10baseT_Half | + ADVERTISED_10baseT_Full; + if (tg3_flag(tp, WOL_SPEED_100MB)) + new_adv |= ADVERTISED_100baseT_Half | + ADVERTISED_100baseT_Full; + + tg3_phy_autoneg_cfg(tp, new_adv, + FLOW_CTRL_TX | FLOW_CTRL_RX); + } else if (tp->link_config.speed == SPEED_INVALID) { + if (tp->phy_flags & TG3_PHYFLG_10_100_ONLY) + tp->link_config.advertising &= + ~(ADVERTISED_1000baseT_Half | + ADVERTISED_1000baseT_Full); + + tg3_phy_autoneg_cfg(tp, tp->link_config.advertising, + tp->link_config.flowctrl); + } else { + /* Asking for a specific link mode. */ + if (tp->link_config.speed == SPEED_1000) { + if (tp->link_config.duplex == DUPLEX_FULL) + new_adv = ADVERTISED_1000baseT_Full; + else + new_adv = ADVERTISED_1000baseT_Half; + } else if (tp->link_config.speed == SPEED_100) { + if (tp->link_config.duplex == DUPLEX_FULL) + new_adv = ADVERTISED_100baseT_Full; + else + new_adv = ADVERTISED_100baseT_Half; + } else { + if (tp->link_config.duplex == DUPLEX_FULL) + new_adv = ADVERTISED_10baseT_Full; + else + new_adv = ADVERTISED_10baseT_Half; } - tg3_phy_cl45_write(tp, MDIO_MMD_AN, MDIO_AN_EEE_ADV, val); - TG3_PHY_AUXCTL_SMDSP_DISABLE(tp); + tg3_phy_autoneg_cfg(tp, new_adv, + tp->link_config.flowctrl); } if (tp->link_config.autoneg == AUTONEG_DISABLE && @@ -12953,7 +12952,7 @@ static int __devinit tg3_phy_probe(struct tg3 *tp) if (!(tp->phy_flags & TG3_PHYFLG_ANY_SERDES) && !tg3_flag(tp, ENABLE_APE) && !tg3_flag(tp, ENABLE_ASF)) { - u32 bmsr, adv_reg, tg3_ctrl, mask; + u32 bmsr, mask; tg3_readphy(tp, MII_BMSR, &bmsr); if (!tg3_readphy(tp, MII_BMSR, &bmsr) && @@ -12964,36 +12963,18 @@ static int __devinit tg3_phy_probe(struct tg3 *tp) if (err) return err; - adv_reg = (ADVERTISE_10HALF | ADVERTISE_10FULL | - ADVERTISE_100HALF | ADVERTISE_100FULL | - ADVERTISE_CSMA | ADVERTISE_PAUSE_CAP); - tg3_ctrl = 0; - if (!(tp->phy_flags & TG3_PHYFLG_10_100_ONLY)) { - tg3_ctrl = (MII_TG3_CTRL_ADV_1000_HALF | - MII_TG3_CTRL_ADV_1000_FULL); - if (tp->pci_chip_rev_id == CHIPREV_ID_5701_A0 || - tp->pci_chip_rev_id == CHIPREV_ID_5701_B0) - tg3_ctrl |= (MII_TG3_CTRL_AS_MASTER | - MII_TG3_CTRL_ENABLE_AS_MASTER); - } + tg3_phy_set_wirespeed(tp); mask = (ADVERTISED_10baseT_Half | ADVERTISED_10baseT_Full | ADVERTISED_100baseT_Half | ADVERTISED_100baseT_Full | ADVERTISED_1000baseT_Half | ADVERTISED_1000baseT_Full); if (!tg3_copper_is_advertising_all(tp, mask)) { - tg3_writephy(tp, MII_ADVERTISE, adv_reg); - - if (!(tp->phy_flags & TG3_PHYFLG_10_100_ONLY)) - tg3_writephy(tp, MII_TG3_CTRL, tg3_ctrl); + tg3_phy_autoneg_cfg(tp, tp->link_config.advertising, + tp->link_config.flowctrl); tg3_writephy(tp, MII_BMCR, BMCR_ANENABLE | BMCR_ANRESTART); } - tg3_phy_set_wirespeed(tp); - - tg3_writephy(tp, MII_ADVERTISE, adv_reg); - if (!(tp->phy_flags & TG3_PHYFLG_10_100_ONLY)) - tg3_writephy(tp, MII_TG3_CTRL, tg3_ctrl); } skip_phy_reset: -- cgit v0.10.2 From 54e0a67f446fae290f99781691eba46c5cda66e7 Mon Sep 17 00:00:00 2001 From: Matt Carlson Date: Thu, 19 May 2011 12:12:50 +0000 Subject: tg3: Fix TSO loopback test Commit bb158d696489244f79fd4c3abd47968a06b48c79, entitled "tg3: Add TSO loopback test", mistakenly inverted the checksum field test from the receive BD. This patch corrects the problem. Signed-off-by: Matt Carlson Reviewed-by: Michael Chan Signed-off-by: David S. Miller diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index 7675231..d05c6a0 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -11195,7 +11195,7 @@ static int tg3_run_loopback(struct tg3 *tp, u32 pktsz, int loopback_mode) } } else if ((desc->type_flags & RXD_FLAG_TCPUDP_CSUM) && (desc->ip_tcp_csum & RXD_TCPCSUM_MASK) - >> RXD_TCPCSUM_SHIFT == 0xffff) { + >> RXD_TCPCSUM_SHIFT != 0xffff) { goto out; } -- cgit v0.10.2 From 4452d0999906e3e26b718566362e943fcaa3d694 Mon Sep 17 00:00:00 2001 From: Matt Carlson Date: Thu, 19 May 2011 12:12:51 +0000 Subject: tg3: Fix stats for 5704 and later devices Commit 4d95847381228639844c7197deb8b2211274ef22, entitled "tg3: Workaround rx_discards stat bug" modified the hardware statistics data structure. The modification shifted the statistics so that the labels no longer corresponded to the counter values. This patch fixes the problem by utilizing reserved space for the new counters. Signed-off-by: Matt Carlson Reviewed-by: Michael Chan Signed-off-by: David S. Miller diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index d05c6a0..574fe97 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -364,7 +364,6 @@ static const struct { { "dma_write_prioq_full" }, { "rxbds_empty" }, { "rx_discards" }, - { "mbuf_lwm_thresh_hit" }, { "rx_errors" }, { "rx_threshold_hit" }, @@ -376,7 +375,9 @@ static const struct { { "ring_status_update" }, { "nic_irqs" }, { "nic_avoided_irqs" }, - { "nic_tx_threshold_hit" } + { "nic_tx_threshold_hit" }, + + { "mbuf_lwm_thresh_hit" }, }; #define TG3_NUM_STATS ARRAY_SIZE(ethtool_stats_keys) @@ -9546,6 +9547,8 @@ static struct tg3_ethtool_stats *tg3_get_estats(struct tg3 *tp) ESTAT_ADD(nic_avoided_irqs); ESTAT_ADD(nic_tx_threshold_hit); + ESTAT_ADD(mbuf_lwm_thresh_hit); + return estats; } diff --git a/drivers/net/tg3.h b/drivers/net/tg3.h index 83f45bf..5b3d2f3 100644 --- a/drivers/net/tg3.h +++ b/drivers/net/tg3.h @@ -2620,7 +2620,6 @@ struct tg3_hw_stats { tg3_stat64_t dma_write_prioq_full; tg3_stat64_t rxbds_empty; tg3_stat64_t rx_discards; - tg3_stat64_t mbuf_lwm_thresh_hit; tg3_stat64_t rx_errors; tg3_stat64_t rx_threshold_hit; @@ -2639,7 +2638,12 @@ struct tg3_hw_stats { tg3_stat64_t nic_avoided_irqs; tg3_stat64_t nic_tx_threshold_hit; - u8 __reserved4[0xb00-0x9c0]; + /* NOT a part of the hardware statistics block format. + * These stats are here as storage for tg3_periodic_fetch_stats(). + */ + tg3_stat64_t mbuf_lwm_thresh_hit; + + u8 __reserved4[0xb00-0x9c8]; }; /* 'mapping' is superfluous as the chip does not write into @@ -2771,6 +2775,8 @@ struct tg3_ethtool_stats { u64 nic_irqs; u64 nic_avoided_irqs; u64 nic_tx_threshold_hit; + + u64 mbuf_lwm_thresh_hit; }; struct tg3_rx_prodring_set { -- cgit v0.10.2 From dabc5c670d3f86d15ee4f42ab38ec5bd2682487d Mon Sep 17 00:00:00 2001 From: Matt Carlson Date: Thu, 19 May 2011 12:12:52 +0000 Subject: tg3: Move TSO_CAPABLE assignment This patch moves the code that asserts the TSO_CAPABLE flag closer to where the TSO capabilities flags are set. There isn't a good enough reason for the code to be separated. Signed-off-by: Matt Carlson Reviewed-by: Michael Chan Signed-off-by: David S. Miller diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index 574fe97..09fe067 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -13639,6 +13639,21 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) tp->fw_needed = FIRMWARE_TG3TSO; } + /* Selectively allow TSO based on operating conditions */ + if ((tg3_flag(tp, HW_TSO_1) || + tg3_flag(tp, HW_TSO_2) || + tg3_flag(tp, HW_TSO_3)) || + (tp->fw_needed && !tg3_flag(tp, ENABLE_ASF))) + tg3_flag_set(tp, TSO_CAPABLE); + else { + tg3_flag_clear(tp, TSO_CAPABLE); + tg3_flag_clear(tp, TSO_BUG); + tp->fw_needed = NULL; + } + + if (tp->pci_chip_rev_id == CHIPREV_ID_5701_A0) + tp->fw_needed = FIRMWARE_TG3; + tp->irq_max = 1; if (tg3_flag(tp, 5750_PLUS)) { @@ -13705,6 +13720,7 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) if (lnkctl & PCI_EXP_LNKCTL_CLKREQ_EN) { if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906) tg3_flag_clear(tp, HW_TSO_2); + tg3_flag_clear(tp, TSO_CAPABLE); if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784 || GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761 || tp->pci_chip_rev_id == CHIPREV_ID_57780_A0 || @@ -15044,21 +15060,6 @@ static int __devinit tg3_init_one(struct pci_dev *pdev, tg3_init_bufmgr_config(tp); - /* Selectively allow TSO based on operating conditions */ - if ((tg3_flag(tp, HW_TSO_1) || - tg3_flag(tp, HW_TSO_2) || - tg3_flag(tp, HW_TSO_3)) || - (tp->fw_needed && !tg3_flag(tp, ENABLE_ASF))) - tg3_flag_set(tp, TSO_CAPABLE); - else { - tg3_flag_clear(tp, TSO_CAPABLE); - tg3_flag_clear(tp, TSO_BUG); - tp->fw_needed = NULL; - } - - if (tp->pci_chip_rev_id == CHIPREV_ID_5701_A0) - tp->fw_needed = FIRMWARE_TG3; - /* TSO is on by default on chips that support hardware TSO. * Firmware TSO on older chips gives lower performance, so it * is off by default, but can be enabled using ethtool. -- cgit v0.10.2 From 0da0606f493c5cdab74bdcc96b12f4305ad94085 Mon Sep 17 00:00:00 2001 From: Matt Carlson Date: Thu, 19 May 2011 12:12:53 +0000 Subject: tg3: Consolidate all netdev feature assignments This patch consolidates all the netdev feature bit assignments to one location. Signed-off-by: Matt Carlson Reviewed-by: Michael Chan Signed-off-by: David S. Miller diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index 09fe067..5bf2ce1 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -13602,19 +13602,6 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) tg3_flag(tp, 5750_PLUS)) tg3_flag_set(tp, 5705_PLUS); - /* 5700 B0 chips do not support checksumming correctly due - * to hardware bugs. - */ - if (tp->pci_chip_rev_id != CHIPREV_ID_5700_B0) { - u32 features = NETIF_F_SG | NETIF_F_IP_CSUM | NETIF_F_RXCSUM; - - if (tg3_flag(tp, 5755_PLUS)) - features |= NETIF_F_IPV6_CSUM; - tp->dev->features |= features; - tp->dev->hw_features |= features; - tp->dev->vlan_features |= features; - } - /* Determine TSO capabilities */ if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5719) ; /* Do nothing. HW bug. */ @@ -14922,7 +14909,7 @@ static int __devinit tg3_init_one(struct pci_dev *pdev, u32 sndmbx, rcvmbx, intmbx; char str[40]; u64 dma_mask, persist_dma_mask; - u32 hw_features = 0; + u32 features = 0; printk_once(KERN_INFO "%s\n", version); @@ -14958,8 +14945,6 @@ static int __devinit tg3_init_one(struct pci_dev *pdev, SET_NETDEV_DEV(dev, &pdev->dev); - dev->features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX; - tp = netdev_priv(dev); tp->pdev = pdev; tp->dev = dev; @@ -15039,7 +15024,7 @@ static int __devinit tg3_init_one(struct pci_dev *pdev, if (dma_mask > DMA_BIT_MASK(32)) { err = pci_set_dma_mask(pdev, dma_mask); if (!err) { - dev->features |= NETIF_F_HIGHDMA; + features |= NETIF_F_HIGHDMA; err = pci_set_consistent_dma_mask(pdev, persist_dma_mask); if (err < 0) { @@ -15060,6 +15045,18 @@ static int __devinit tg3_init_one(struct pci_dev *pdev, tg3_init_bufmgr_config(tp); + features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX; + + /* 5700 B0 chips do not support checksumming correctly due + * to hardware bugs. + */ + if (tp->pci_chip_rev_id != CHIPREV_ID_5700_B0) { + features |= NETIF_F_SG | NETIF_F_IP_CSUM | NETIF_F_RXCSUM; + + if (tg3_flag(tp, 5755_PLUS)) + features |= NETIF_F_IPV6_CSUM; + } + /* TSO is on by default on chips that support hardware TSO. * Firmware TSO on older chips gives lower performance, so it * is off by default, but can be enabled using ethtool. @@ -15067,24 +15064,20 @@ static int __devinit tg3_init_one(struct pci_dev *pdev, if ((tg3_flag(tp, HW_TSO_1) || tg3_flag(tp, HW_TSO_2) || tg3_flag(tp, HW_TSO_3)) && - (dev->features & NETIF_F_IP_CSUM)) - hw_features |= NETIF_F_TSO; + (features & NETIF_F_IP_CSUM)) + features |= NETIF_F_TSO; if (tg3_flag(tp, HW_TSO_2) || tg3_flag(tp, HW_TSO_3)) { - if (dev->features & NETIF_F_IPV6_CSUM) - hw_features |= NETIF_F_TSO6; + if (features & NETIF_F_IPV6_CSUM) + features |= NETIF_F_TSO6; if (tg3_flag(tp, HW_TSO_3) || GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761 || (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784 && GET_CHIP_REV(tp->pci_chip_rev_id) != CHIPREV_5784_AX) || GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5785 || GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57780) - hw_features |= NETIF_F_TSO_ECN; + features |= NETIF_F_TSO_ECN; } - dev->hw_features |= hw_features; - dev->features |= hw_features; - dev->vlan_features |= hw_features; - /* * Add loopback capability only for a subset of devices that support * MAC-LOOPBACK. Eventually this need to be enhanced to allow INT-PHY @@ -15093,7 +15086,11 @@ static int __devinit tg3_init_one(struct pci_dev *pdev, if (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5780 && !tg3_flag(tp, CPMU_PRESENT)) /* Add the loopback capability */ - dev->hw_features |= NETIF_F_LOOPBACK; + features |= NETIF_F_LOOPBACK; + + dev->features |= features; + dev->hw_features |= features; + dev->vlan_features |= features; if (tp->pci_chip_rev_id == CHIPREV_ID_5705_A1 && !tg3_flag(tp, TSO_CAPABLE) && -- cgit v0.10.2 From 6ff6f81dd4ec08945e10147dbfe611569ef4cc09 Mon Sep 17 00:00:00 2001 From: Matt Carlson Date: Thu, 19 May 2011 12:12:54 +0000 Subject: tg3: Remove excessive parenthesis This patch removes some excessive parenthesizing. Signed-off-by: Matt Carlson Reviewed-by: Michael Chan Signed-off-by: David S. Miller diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index 5bf2ce1..eb8dc7b 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -553,7 +553,7 @@ static void tg3_write_mem(struct tg3 *tp, u32 off, u32 val) { unsigned long flags; - if ((GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906) && + if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906 && (off >= NIC_SRAM_STATS_BLK) && (off < NIC_SRAM_TX_BUFFER_DESC)) return; @@ -578,7 +578,7 @@ static void tg3_read_mem(struct tg3 *tp, u32 off, u32 *val) { unsigned long flags; - if ((GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906) && + if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906 && (off >= NIC_SRAM_STATS_BLK) && (off < NIC_SRAM_TX_BUFFER_DESC)) { *val = 0; return; @@ -2806,7 +2806,7 @@ static int tg3_power_down_prepare(struct tg3 *tp) CLOCK_CTRL_PWRDOWN_PLL133, 40); } else if (tg3_flag(tp, 5780_CLASS) || tg3_flag(tp, CPMU_PRESENT) || - (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906)) { + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906) { /* do nothing */ } else if (!(tg3_flag(tp, 5750_PLUS) && tg3_flag(tp, ENABLE_ASF))) { u32 newbits1, newbits2; @@ -8646,7 +8646,7 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy) } if ((tp->phy_flags & TG3_PHYFLG_MII_SERDES) && - (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5714)) { + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5714) { u32 tmp; tmp = tr32(SERDES_RX_CTRL); @@ -11636,7 +11636,7 @@ static void __devinit tg3_get_nvram_info(struct tg3 *tp) tw32(NVRAM_CFG1, nvcfg1); } - if ((GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5750) || + if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5750 || tg3_flag(tp, 5780_CLASS)) { switch (nvcfg1 & NVRAM_CFG1_VENDOR_MASK) { case FLASH_VENDOR_ATMEL_FLASH_BUFFERED: @@ -12640,9 +12640,9 @@ static void __devinit tg3_get_eeprom_hw_cfg(struct tg3 *tp) tg3_read_mem(tp, NIC_SRAM_DATA_VER, &ver); ver >>= NIC_SRAM_DATA_VER_SHIFT; - if ((GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5700) && - (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5701) && - (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5703) && + if (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5700 && + GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5701 && + GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5703 && (ver > 0) && (ver < 0x100)) tg3_read_mem(tp, NIC_SRAM_DATA_CFG_2, &cfg2); @@ -13498,7 +13498,7 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) } } - if ((GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5701)) { + if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5701) { static struct tg3_dev_id { u32 vendor; u32 device; @@ -13598,7 +13598,7 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) tg3_flag(tp, 5780_CLASS)) tg3_flag_set(tp, 5750_PLUS); - if ((GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5705) || + if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5705 || tg3_flag(tp, 5750_PLUS)) tg3_flag_set(tp, 5705_PLUS); @@ -13627,9 +13627,9 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) } /* Selectively allow TSO based on operating conditions */ - if ((tg3_flag(tp, HW_TSO_1) || - tg3_flag(tp, HW_TSO_2) || - tg3_flag(tp, HW_TSO_3)) || + if (tg3_flag(tp, HW_TSO_1) || + tg3_flag(tp, HW_TSO_2) || + tg3_flag(tp, HW_TSO_3) || (tp->fw_needed && !tg3_flag(tp, ENABLE_ASF))) tg3_flag_set(tp, TSO_CAPABLE); else { @@ -13891,7 +13891,7 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) * It is also used as eeprom write protect on LOMs. */ tp->grc_local_ctrl = GRC_LCLCTRL_INT_ON_ATTN | GRC_LCLCTRL_AUTO_SEEPROM; - if ((GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5700) || + if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5700 || tg3_flag(tp, EEPROM_WRITE_PROT)) tp->grc_local_ctrl |= (GRC_LCLCTRL_GPIO_OE1 | GRC_LCLCTRL_GPIO_OUTPUT1); @@ -13943,8 +13943,8 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) tp->phy_flags |= TG3_PHYFLG_IS_FET; /* A few boards don't want Ethernet@WireSpeed phy feature */ - if ((GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5700) || - ((GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5705) && + if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5700 || + (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5705 && (tp->pci_chip_rev_id != CHIPREV_ID_5705_A0) && (tp->pci_chip_rev_id != CHIPREV_ID_5705_A1)) || (tp->phy_flags & TG3_PHYFLG_IS_FET) || @@ -14064,7 +14064,7 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) tg3_flag_set(tp, IS_5788); if (!tg3_flag(tp, IS_5788) && - (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5700)) + GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5700) tg3_flag_set(tp, TAGGED_STATUS); if (tg3_flag(tp, TAGGED_STATUS)) { tp->coalesce_mode |= (HOSTCC_MODE_CLRTICK_RXBD | @@ -14215,7 +14215,7 @@ static int __devinit tg3_get_device_address(struct tg3 *tp) #endif mac_offset = 0x7c; - if ((GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5704) || + if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5704 || tg3_flag(tp, 5780_CLASS)) { if (tr32(TG3PCI_DUAL_MAC_CTRL) & DUAL_MAC_CTRL_ID) mac_offset = 0xcc; -- cgit v0.10.2 From 310050fad8962a2ebc70011353a549614e118152 Mon Sep 17 00:00:00 2001 From: Matt Carlson Date: Thu, 19 May 2011 12:12:55 +0000 Subject: tg3: Apply rx_discards fix to 5719/5720 Commit 4d95847381228639844c7197deb8b2211274ef22, entitled "tg3: Workaround rx_discards stat bug", was intended to be applied to the 5717, 5718, 5719_A0, and 5720 A0 chip revisions. The implementation missed the latter two when applying the fix in a critical area. This patch fixes the problem. Signed-off-by: Matt Carlson Signed-off-by: David S. Miller diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index eb8dc7b..8311f8e 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -8797,7 +8797,9 @@ static void tg3_periodic_fetch_stats(struct tg3 *tp) TG3_STAT_ADD32(&sp->rx_undersize_packets, MAC_RX_STATS_UNDERSIZE); TG3_STAT_ADD32(&sp->rxbds_empty, RCVLPC_NO_RCV_BD_CNT); - if (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5717) { + if (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5717 && + tp->pci_chip_rev_id != CHIPREV_ID_5719_A0 && + tp->pci_chip_rev_id != CHIPREV_ID_5720_A0) { TG3_STAT_ADD32(&sp->rx_discards, RCVLPC_IN_DISCARDS_CNT); } else { u32 val = tr32(HOSTCC_FLOW_ATTN); -- cgit v0.10.2 From 43a5f002afc6f24891e57d31275f34e19a1a07d0 Mon Sep 17 00:00:00 2001 From: Matt Carlson Date: Thu, 19 May 2011 12:12:56 +0000 Subject: tg3: Update version to 3.119 This patch updates the tg3 version to 3.119. Signed-off-by: Matt Carlson Reviewed-by: Michael Chan Signed-off-by: David S. Miller diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index 8311f8e..012ce70 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -88,10 +88,10 @@ static inline void _tg3_flag_clear(enum TG3_FLAGS flag, unsigned long *bits) #define DRV_MODULE_NAME "tg3" #define TG3_MAJ_NUM 3 -#define TG3_MIN_NUM 118 +#define TG3_MIN_NUM 119 #define DRV_MODULE_VERSION \ __stringify(TG3_MAJ_NUM) "." __stringify(TG3_MIN_NUM) -#define DRV_MODULE_RELDATE "April 22, 2011" +#define DRV_MODULE_RELDATE "May 18, 2011" #define TG3_DEF_MAC_MODE 0 #define TG3_DEF_RX_MODE 0 -- cgit v0.10.2 From 8fb53b959bd9e503b646a3d68c7b1759667b6a19 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Thu, 19 May 2011 18:20:29 -0400 Subject: isdn: capi: Use pr_debug() instead of ifdefs. I was investigating some warnings that spew because of the _DEBUG_FOO ifdef'ery in here. Instead of adding more ifdefs to fix that warning, let's use pr_debug() and get rid of these CPP checks altogether. Signed-off-by: David S. Miller diff --git a/drivers/isdn/capi/capi.c b/drivers/isdn/capi/capi.c index bea1009..e44933d 100644 --- a/drivers/isdn/capi/capi.c +++ b/drivers/isdn/capi/capi.c @@ -42,9 +42,6 @@ MODULE_DESCRIPTION("CAPI4Linux: Userspace /dev/capi20 interface"); MODULE_AUTHOR("Carsten Paeth"); MODULE_LICENSE("GPL"); -#undef _DEBUG_TTYFUNCS /* call to tty_driver */ -#undef _DEBUG_DATAFLOW /* data flow */ - /* -------- driver information -------------------------------------- */ static DEFINE_MUTEX(capi_mutex); @@ -418,9 +415,7 @@ static int handle_recv_skb(struct capiminor *mp, struct sk_buff *skb) tty = tty_port_tty_get(&mp->port); if (!tty) { -#ifdef _DEBUG_DATAFLOW - printk(KERN_DEBUG "capi: currently no receiver\n"); -#endif + pr_debug("capi: currently no receiver\n"); return -1; } @@ -433,23 +428,17 @@ static int handle_recv_skb(struct capiminor *mp, struct sk_buff *skb) } if (ld->ops->receive_buf == NULL) { -#if defined(_DEBUG_DATAFLOW) || defined(_DEBUG_TTYFUNCS) - printk(KERN_DEBUG "capi: ldisc has no receive_buf function\n"); -#endif + pr_debug("capi: ldisc has no receive_buf function\n"); /* fatal error, do not requeue */ goto free_skb; } if (mp->ttyinstop) { -#if defined(_DEBUG_DATAFLOW) || defined(_DEBUG_TTYFUNCS) - printk(KERN_DEBUG "capi: recv tty throttled\n"); -#endif + pr_debug("capi: recv tty throttled\n"); goto deref_ldisc; } if (tty->receive_room < datalen) { -#if defined(_DEBUG_DATAFLOW) || defined(_DEBUG_TTYFUNCS) - printk(KERN_DEBUG "capi: no room in tty\n"); -#endif + pr_debug("capi: no room in tty\n"); goto deref_ldisc; } @@ -465,10 +454,8 @@ static int handle_recv_skb(struct capiminor *mp, struct sk_buff *skb) if (errcode == CAPI_NOERROR) { skb_pull(skb, CAPIMSG_LEN(skb->data)); -#ifdef _DEBUG_DATAFLOW - printk(KERN_DEBUG "capi: DATA_B3_RESP %u len=%d => ldisc\n", - datahandle, skb->len); -#endif + pr_debug("capi: DATA_B3_RESP %u len=%d => ldisc\n", + datahandle, skb->len); ld->ops->receive_buf(tty, skb->data, NULL, skb->len); } else { printk(KERN_ERR "capi: send DATA_B3_RESP failed=%x\n", @@ -515,9 +502,7 @@ static void handle_minor_send(struct capiminor *mp) return; if (mp->ttyoutstop) { -#if defined(_DEBUG_DATAFLOW) || defined(_DEBUG_TTYFUNCS) - printk(KERN_DEBUG "capi: send: tty stopped\n"); -#endif + pr_debug("capi: send: tty stopped\n"); tty_kref_put(tty); return; } @@ -559,10 +544,8 @@ static void handle_minor_send(struct capiminor *mp) } errcode = capi20_put_message(mp->ap, skb); if (errcode == CAPI_NOERROR) { -#ifdef _DEBUG_DATAFLOW - printk(KERN_DEBUG "capi: DATA_B3_REQ %u len=%u\n", - datahandle, len); -#endif + pr_debug("capi: DATA_B3_REQ %u len=%u\n", + datahandle, len); continue; } capiminor_del_ack(mp, datahandle); @@ -636,10 +619,8 @@ static void capi_recv_message(struct capi20_appl *ap, struct sk_buff *skb) } if (CAPIMSG_SUBCOMMAND(skb->data) == CAPI_IND) { datahandle = CAPIMSG_U16(skb->data, CAPIMSG_BASELEN+4+4+2); -#ifdef _DEBUG_DATAFLOW - printk(KERN_DEBUG "capi_signal: DATA_B3_IND %u len=%d\n", - datahandle, skb->len-CAPIMSG_LEN(skb->data)); -#endif + pr_debug("capi_signal: DATA_B3_IND %u len=%d\n", + datahandle, skb->len-CAPIMSG_LEN(skb->data)); skb_queue_tail(&mp->inqueue, skb); handle_minor_recv(mp); @@ -647,11 +628,9 @@ static void capi_recv_message(struct capi20_appl *ap, struct sk_buff *skb) } else if (CAPIMSG_SUBCOMMAND(skb->data) == CAPI_CONF) { datahandle = CAPIMSG_U16(skb->data, CAPIMSG_BASELEN+4); -#ifdef _DEBUG_DATAFLOW - printk(KERN_DEBUG "capi_signal: DATA_B3_CONF %u 0x%x\n", - datahandle, - CAPIMSG_U16(skb->data, CAPIMSG_BASELEN+4+2)); -#endif + pr_debug("capi_signal: DATA_B3_CONF %u 0x%x\n", + datahandle, + CAPIMSG_U16(skb->data, CAPIMSG_BASELEN+4+2)); kfree_skb(skb); capiminor_del_ack(mp, datahandle); tty = tty_port_tty_get(&mp->port); @@ -1081,9 +1060,7 @@ static int capinc_tty_write(struct tty_struct *tty, struct capiminor *mp = tty->driver_data; struct sk_buff *skb; -#ifdef _DEBUG_TTYFUNCS - printk(KERN_DEBUG "capinc_tty_write(count=%d)\n", count); -#endif + pr_debug("capinc_tty_write(count=%d)\n", count); spin_lock_bh(&mp->outlock); skb = mp->outskb; @@ -1119,9 +1096,7 @@ static int capinc_tty_put_char(struct tty_struct *tty, unsigned char ch) struct sk_buff *skb; int ret = 1; -#ifdef _DEBUG_TTYFUNCS - printk(KERN_DEBUG "capinc_put_char(%u)\n", ch); -#endif + pr_debug("capinc_put_char(%u)\n", ch); spin_lock_bh(&mp->outlock); skb = mp->outskb; @@ -1160,9 +1135,7 @@ static void capinc_tty_flush_chars(struct tty_struct *tty) struct capiminor *mp = tty->driver_data; struct sk_buff *skb; -#ifdef _DEBUG_TTYFUNCS - printk(KERN_DEBUG "capinc_tty_flush_chars\n"); -#endif + pr_debug("capinc_tty_flush_chars\n"); spin_lock_bh(&mp->outlock); skb = mp->outskb; @@ -1186,9 +1159,7 @@ static int capinc_tty_write_room(struct tty_struct *tty) room = CAPINC_MAX_SENDQUEUE-skb_queue_len(&mp->outqueue); room *= CAPI_MAX_BLKSIZE; -#ifdef _DEBUG_TTYFUNCS - printk(KERN_DEBUG "capinc_tty_write_room = %d\n", room); -#endif + pr_debug("capinc_tty_write_room = %d\n", room); return room; } @@ -1196,12 +1167,10 @@ static int capinc_tty_chars_in_buffer(struct tty_struct *tty) { struct capiminor *mp = tty->driver_data; -#ifdef _DEBUG_TTYFUNCS - printk(KERN_DEBUG "capinc_tty_chars_in_buffer = %d nack=%d sq=%d rq=%d\n", - mp->outbytes, mp->nack, - skb_queue_len(&mp->outqueue), - skb_queue_len(&mp->inqueue)); -#endif + pr_debug("capinc_tty_chars_in_buffer = %d nack=%d sq=%d rq=%d\n", + mp->outbytes, mp->nack, + skb_queue_len(&mp->outqueue), + skb_queue_len(&mp->inqueue)); return mp->outbytes; } @@ -1213,17 +1182,13 @@ static int capinc_tty_ioctl(struct tty_struct *tty, static void capinc_tty_set_termios(struct tty_struct *tty, struct ktermios * old) { -#ifdef _DEBUG_TTYFUNCS - printk(KERN_DEBUG "capinc_tty_set_termios\n"); -#endif + pr_debug("capinc_tty_set_termios\n"); } static void capinc_tty_throttle(struct tty_struct *tty) { struct capiminor *mp = tty->driver_data; -#ifdef _DEBUG_TTYFUNCS - printk(KERN_DEBUG "capinc_tty_throttle\n"); -#endif + pr_debug("capinc_tty_throttle\n"); mp->ttyinstop = 1; } @@ -1231,9 +1196,7 @@ static void capinc_tty_unthrottle(struct tty_struct *tty) { struct capiminor *mp = tty->driver_data; -#ifdef _DEBUG_TTYFUNCS - printk(KERN_DEBUG "capinc_tty_unthrottle\n"); -#endif + pr_debug("capinc_tty_unthrottle\n"); mp->ttyinstop = 0; handle_minor_recv(mp); } @@ -1242,9 +1205,7 @@ static void capinc_tty_stop(struct tty_struct *tty) { struct capiminor *mp = tty->driver_data; -#ifdef _DEBUG_TTYFUNCS - printk(KERN_DEBUG "capinc_tty_stop\n"); -#endif + pr_debug("capinc_tty_stop\n"); mp->ttyoutstop = 1; } @@ -1252,9 +1213,7 @@ static void capinc_tty_start(struct tty_struct *tty) { struct capiminor *mp = tty->driver_data; -#ifdef _DEBUG_TTYFUNCS - printk(KERN_DEBUG "capinc_tty_start\n"); -#endif + pr_debug("capinc_tty_start\n"); mp->ttyoutstop = 0; handle_minor_send(mp); } @@ -1263,39 +1222,29 @@ static void capinc_tty_hangup(struct tty_struct *tty) { struct capiminor *mp = tty->driver_data; -#ifdef _DEBUG_TTYFUNCS - printk(KERN_DEBUG "capinc_tty_hangup\n"); -#endif + pr_debug("capinc_tty_hangup\n"); tty_port_hangup(&mp->port); } static int capinc_tty_break_ctl(struct tty_struct *tty, int state) { -#ifdef _DEBUG_TTYFUNCS - printk(KERN_DEBUG "capinc_tty_break_ctl(%d)\n", state); -#endif + pr_debug("capinc_tty_break_ctl(%d)\n", state); return 0; } static void capinc_tty_flush_buffer(struct tty_struct *tty) { -#ifdef _DEBUG_TTYFUNCS - printk(KERN_DEBUG "capinc_tty_flush_buffer\n"); -#endif + pr_debug("capinc_tty_flush_buffer\n"); } static void capinc_tty_set_ldisc(struct tty_struct *tty) { -#ifdef _DEBUG_TTYFUNCS - printk(KERN_DEBUG "capinc_tty_set_ldisc\n"); -#endif + pr_debug("capinc_tty_set_ldisc\n"); } static void capinc_tty_send_xchar(struct tty_struct *tty, char ch) { -#ifdef _DEBUG_TTYFUNCS - printk(KERN_DEBUG "capinc_tty_send_xchar(%d)\n", ch); -#endif + pr_debug("capinc_tty_send_xchar(%d)\n", ch); } static const struct tty_operations capinc_ops = { -- cgit v0.10.2 From f06cd54f555a4ceca4de39160c68c7e3da657e89 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Thu, 19 May 2011 18:32:55 -0400 Subject: pkt_sched: Kill set but unused variable 'protocol' in tc_classify() I checked the history and this has been like this since the beginning of time. Signed-off-by: David S. Miller diff --git a/net/sched/sch_api.c b/net/sched/sch_api.c index 7490f3f..6b86276 100644 --- a/net/sched/sch_api.c +++ b/net/sched/sch_api.c @@ -1673,10 +1673,8 @@ int tc_classify(struct sk_buff *skb, struct tcf_proto *tp, { int err = 0; #ifdef CONFIG_NET_CLS_ACT - __be16 protocol; struct tcf_proto *otp = tp; reclassify: - protocol = skb->protocol; #endif err = tc_classify_compat(skb, tp, res); -- cgit v0.10.2 From 504f284a713c46c6ecf975fbd20af00f4e205f5b Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Thu, 19 May 2011 18:34:37 -0400 Subject: rxrpc: Kill set but unused variable 'sp' in rxrpc_rotate_tx_window() Signed-off-by: David S. Miller diff --git a/net/rxrpc/ar-ack.c b/net/rxrpc/ar-ack.c index b6ffe4e..f99cfce 100644 --- a/net/rxrpc/ar-ack.c +++ b/net/rxrpc/ar-ack.c @@ -375,7 +375,6 @@ protocol_error: */ static void rxrpc_rotate_tx_window(struct rxrpc_call *call, u32 hard) { - struct rxrpc_skb_priv *sp; unsigned long _skb; int tail = call->acks_tail, old_tail; int win = CIRC_CNT(call->acks_head, tail, call->acks_winsz); @@ -387,7 +386,6 @@ static void rxrpc_rotate_tx_window(struct rxrpc_call *call, u32 hard) while (call->acks_hard < hard) { smp_read_barrier_depends(); _skb = call->acks_window[tail] & ~1; - sp = rxrpc_skb((struct sk_buff *) _skb); rxrpc_free_skb((struct sk_buff *) _skb); old_tail = tail; tail = (tail + 1) & (call->acks_winsz - 1); -- cgit v0.10.2 From 9e5e10a22507b8d372bcf0e88875d4a3f6ede297 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Thu, 19 May 2011 18:35:58 -0400 Subject: rxrpc: Kill set but unused variable 'sp' in rxrpc_process_connection() Signed-off-by: David S. Miller diff --git a/net/rxrpc/ar-connevent.c b/net/rxrpc/ar-connevent.c index 0505cdc..e7ed43a 100644 --- a/net/rxrpc/ar-connevent.c +++ b/net/rxrpc/ar-connevent.c @@ -259,7 +259,6 @@ void rxrpc_process_connection(struct work_struct *work) { struct rxrpc_connection *conn = container_of(work, struct rxrpc_connection, processor); - struct rxrpc_skb_priv *sp; struct sk_buff *skb; u32 abort_code = RX_PROTOCOL_ERROR; int ret; @@ -276,8 +275,6 @@ void rxrpc_process_connection(struct work_struct *work) /* go through the conn-level event packets, releasing the ref on this * connection that each one has when we've finished with it */ while ((skb = skb_dequeue(&conn->rx_queue))) { - sp = rxrpc_skb(skb); - ret = rxrpc_process_event(conn, skb, &abort_code); switch (ret) { case -EPROTO: -- cgit v0.10.2 From c9d10c497c3728a5c798c11486dccdc01b2092a8 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Thu, 19 May 2011 18:37:11 -0400 Subject: rxrpc: Kill set but unused variable 'local' in rxrpc_UDP_error_handler() Signed-off-by: David S. Miller diff --git a/net/rxrpc/ar-error.c b/net/rxrpc/ar-error.c index d4d1ae2..5d6b572 100644 --- a/net/rxrpc/ar-error.c +++ b/net/rxrpc/ar-error.c @@ -139,7 +139,7 @@ void rxrpc_UDP_error_handler(struct work_struct *work) struct rxrpc_transport *trans = container_of(work, struct rxrpc_transport, error_handler); struct sk_buff *skb; - int local, err; + int err; _enter(""); @@ -157,7 +157,6 @@ void rxrpc_UDP_error_handler(struct work_struct *work) switch (ee->ee_origin) { case SO_EE_ORIGIN_ICMP: - local = 0; switch (ee->ee_type) { case ICMP_DEST_UNREACH: switch (ee->ee_code) { @@ -207,7 +206,6 @@ void rxrpc_UDP_error_handler(struct work_struct *work) case SO_EE_ORIGIN_LOCAL: _proto("Rx Received local error { error=%d }", ee->ee_errno); - local = 1; break; case SO_EE_ORIGIN_NONE: @@ -215,7 +213,6 @@ void rxrpc_UDP_error_handler(struct work_struct *work) default: _proto("Rx Received error report { orig=%u }", ee->ee_origin); - local = 0; break; } -- cgit v0.10.2 From 2a64255019e13dd975f1487cec32b873bcb76da6 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Thu, 19 May 2011 18:41:03 -0400 Subject: rxrpc: Fix set but unused variable 'usage' in rxrpc_get_peer(). I backed off from trying to just eliminate this variable, since transforming atomic_inc_return() into atomic_inc() takes away the memory barriers. Signed-off-by: David S. Miller diff --git a/net/rxrpc/ar-peer.c b/net/rxrpc/ar-peer.c index b6ff063..2754f09 100644 --- a/net/rxrpc/ar-peer.c +++ b/net/rxrpc/ar-peer.c @@ -157,6 +157,7 @@ struct rxrpc_peer *rxrpc_get_peer(struct sockaddr_rxrpc *srx, gfp_t gfp) /* we can now add the new candidate to the list */ peer = candidate; candidate = NULL; + usage = atomic_read(&peer->usage); list_add_tail(&peer->link, &rxrpc_peers); write_unlock_bh(&rxrpc_peer_lock); @@ -171,7 +172,7 @@ success: &peer->srx.transport.sin.sin_addr, ntohs(peer->srx.transport.sin.sin_port)); - _leave(" = %p {u=%d}", peer, atomic_read(&peer->usage)); + _leave(" = %p {u=%d}", peer, usage); return peer; /* we found the peer in the list immediately */ -- cgit v0.10.2 From d187c1aab8d30771bb781c745b150f6159467d6f Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Thu, 19 May 2011 18:44:41 -0400 Subject: atl1c: atl1c_resume() is only used when CONFIG_PM_SLEEP is defined. Signed-off-by: David S. Miller diff --git a/drivers/net/atl1c/atl1c_main.c b/drivers/net/atl1c/atl1c_main.c index 48868de..1269ba5 100644 --- a/drivers/net/atl1c/atl1c_main.c +++ b/drivers/net/atl1c/atl1c_main.c @@ -2537,6 +2537,7 @@ static int atl1c_suspend(struct device *dev) return 0; } +#ifdef CONFIG_PM_SLEEP static int atl1c_resume(struct device *dev) { struct pci_dev *pdev = to_pci_dev(dev); @@ -2563,6 +2564,7 @@ static int atl1c_resume(struct device *dev) return 0; } +#endif static void atl1c_shutdown(struct pci_dev *pdev) { -- cgit v0.10.2 From fa7479cf48103ee9261398034528495966bd7d2d Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Thu, 19 May 2011 18:46:41 -0400 Subject: irda: Kill set but unused vars 'saddr' and 'daddr' in irlan_provider_connect_indication() Signed-off-by: David S. Miller diff --git a/net/irda/irlan/irlan_provider.c b/net/irda/irlan/irlan_provider.c index 5cf5e6c..b8af74a 100644 --- a/net/irda/irlan/irlan_provider.c +++ b/net/irda/irlan/irlan_provider.c @@ -128,7 +128,6 @@ static void irlan_provider_connect_indication(void *instance, void *sap, { struct irlan_cb *self; struct tsap_cb *tsap; - __u32 saddr, daddr; IRDA_DEBUG(0, "%s()\n", __func__ ); @@ -141,8 +140,6 @@ static void irlan_provider_connect_indication(void *instance, void *sap, IRDA_ASSERT(tsap == self->provider.tsap_ctrl,return;); IRDA_ASSERT(self->provider.state == IRLAN_IDLE, return;); - daddr = irttp_get_daddr(tsap); - saddr = irttp_get_saddr(tsap); self->provider.max_sdu_size = max_sdu_size; self->provider.max_header_size = max_header_size; -- cgit v0.10.2 From 63722966d703aeb8071d52172de87e377006cd28 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Thu, 19 May 2011 18:49:54 -0400 Subject: be2net: Kill set but unused variable 'req' in lancer_fw_download() Signed-off-by: David S. Miller diff --git a/drivers/net/benet/be_main.c b/drivers/net/benet/be_main.c index ce6edac..4b5e0ed 100644 --- a/drivers/net/benet/be_main.c +++ b/drivers/net/benet/be_main.c @@ -2736,7 +2736,6 @@ static int lancer_fw_download(struct be_adapter *adapter, #define LANCER_FW_DOWNLOAD_CHUNK (32 * 1024) #define LANCER_FW_DOWNLOAD_LOCATION "/prg" struct be_dma_mem flash_cmd; - struct lancer_cmd_req_write_object *req; const u8 *data_ptr = NULL; u8 *dest_image_ptr = NULL; size_t image_size = 0; @@ -2765,7 +2764,6 @@ static int lancer_fw_download(struct be_adapter *adapter, goto lancer_fw_exit; } - req = flash_cmd.va; dest_image_ptr = flash_cmd.va + sizeof(struct lancer_cmd_req_write_object); image_size = fw->size; -- cgit v0.10.2 From bb0a56ecc4ba2a3db1b6ea6949c309886e3447d3 Mon Sep 17 00:00:00 2001 From: Dave Jones Date: Thu, 19 May 2011 18:51:07 -0400 Subject: [CPUFREQ] Move x86 drivers to drivers/cpufreq/ Signed-off-by: Dave Jones diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig index cc6c53a..e7f94a5 100644 --- a/arch/x86/Kconfig +++ b/arch/x86/Kconfig @@ -1848,7 +1848,7 @@ config APM_ALLOW_INTS endif # APM -source "arch/x86/kernel/cpu/cpufreq/Kconfig" +source "drivers/cpufreq/Kconfig" source "drivers/cpuidle/Kconfig" diff --git a/arch/x86/kernel/cpu/Makefile b/arch/x86/kernel/cpu/Makefile index 3f0ebe4..6042981 100644 --- a/arch/x86/kernel/cpu/Makefile +++ b/arch/x86/kernel/cpu/Makefile @@ -30,7 +30,6 @@ obj-$(CONFIG_PERF_EVENTS) += perf_event.o obj-$(CONFIG_X86_MCE) += mcheck/ obj-$(CONFIG_MTRR) += mtrr/ -obj-$(CONFIG_CPU_FREQ) += cpufreq/ obj-$(CONFIG_X86_LOCAL_APIC) += perfctr-watchdog.o diff --git a/arch/x86/kernel/cpu/cpufreq/Kconfig b/arch/x86/kernel/cpu/cpufreq/Kconfig deleted file mode 100644 index 870e6cc..0000000 --- a/arch/x86/kernel/cpu/cpufreq/Kconfig +++ /dev/null @@ -1,266 +0,0 @@ -# -# CPU Frequency scaling -# - -menu "CPU Frequency scaling" - -source "drivers/cpufreq/Kconfig" - -if CPU_FREQ - -comment "CPUFreq processor drivers" - -config X86_PCC_CPUFREQ - tristate "Processor Clocking Control interface driver" - depends on ACPI && ACPI_PROCESSOR - help - This driver adds support for the PCC interface. - - For details, take a look at: - . - - To compile this driver as a module, choose M here: the - module will be called pcc-cpufreq. - - If in doubt, say N. - -config X86_ACPI_CPUFREQ - tristate "ACPI Processor P-States driver" - select CPU_FREQ_TABLE - depends on ACPI_PROCESSOR - help - This driver adds a CPUFreq driver which utilizes the ACPI - Processor Performance States. - This driver also supports Intel Enhanced Speedstep. - - To compile this driver as a module, choose M here: the - module will be called acpi-cpufreq. - - For details, take a look at . - - If in doubt, say N. - -config ELAN_CPUFREQ - tristate "AMD Elan SC400 and SC410" - select CPU_FREQ_TABLE - depends on X86_ELAN - ---help--- - This adds the CPUFreq driver for AMD Elan SC400 and SC410 - processors. - - You need to specify the processor maximum speed as boot - parameter: elanfreq=maxspeed (in kHz) or as module - parameter "max_freq". - - For details, take a look at . - - If in doubt, say N. - -config SC520_CPUFREQ - tristate "AMD Elan SC520" - select CPU_FREQ_TABLE - depends on X86_ELAN - ---help--- - This adds the CPUFreq driver for AMD Elan SC520 processor. - - For details, take a look at . - - If in doubt, say N. - - -config X86_POWERNOW_K6 - tristate "AMD Mobile K6-2/K6-3 PowerNow!" - select CPU_FREQ_TABLE - depends on X86_32 - help - This adds the CPUFreq driver for mobile AMD K6-2+ and mobile - AMD K6-3+ processors. - - For details, take a look at . - - If in doubt, say N. - -config X86_POWERNOW_K7 - tristate "AMD Mobile Athlon/Duron PowerNow!" - select CPU_FREQ_TABLE - depends on X86_32 - help - This adds the CPUFreq driver for mobile AMD K7 mobile processors. - - For details, take a look at . - - If in doubt, say N. - -config X86_POWERNOW_K7_ACPI - bool - depends on X86_POWERNOW_K7 && ACPI_PROCESSOR - depends on !(X86_POWERNOW_K7 = y && ACPI_PROCESSOR = m) - depends on X86_32 - default y - -config X86_POWERNOW_K8 - tristate "AMD Opteron/Athlon64 PowerNow!" - select CPU_FREQ_TABLE - depends on ACPI && ACPI_PROCESSOR - help - This adds the CPUFreq driver for K8/K10 Opteron/Athlon64 processors. - - To compile this driver as a module, choose M here: the - module will be called powernow-k8. - - For details, take a look at . - -config X86_GX_SUSPMOD - tristate "Cyrix MediaGX/NatSemi Geode Suspend Modulation" - depends on X86_32 && PCI - help - This add the CPUFreq driver for NatSemi Geode processors which - support suspend modulation. - - For details, take a look at . - - If in doubt, say N. - -config X86_SPEEDSTEP_CENTRINO - tristate "Intel Enhanced SpeedStep (deprecated)" - select CPU_FREQ_TABLE - select X86_SPEEDSTEP_CENTRINO_TABLE if X86_32 - depends on X86_32 || (X86_64 && ACPI_PROCESSOR) - help - This is deprecated and this functionality is now merged into - acpi_cpufreq (X86_ACPI_CPUFREQ). Use that driver instead of - speedstep_centrino. - This adds the CPUFreq driver for Enhanced SpeedStep enabled - mobile CPUs. This means Intel Pentium M (Centrino) CPUs - or 64bit enabled Intel Xeons. - - To compile this driver as a module, choose M here: the - module will be called speedstep-centrino. - - For details, take a look at . - - If in doubt, say N. - -config X86_SPEEDSTEP_CENTRINO_TABLE - bool "Built-in tables for Banias CPUs" - depends on X86_32 && X86_SPEEDSTEP_CENTRINO - default y - help - Use built-in tables for Banias CPUs if ACPI encoding - is not available. - - If in doubt, say N. - -config X86_SPEEDSTEP_ICH - tristate "Intel Speedstep on ICH-M chipsets (ioport interface)" - select CPU_FREQ_TABLE - depends on X86_32 - help - This adds the CPUFreq driver for certain mobile Intel Pentium III - (Coppermine), all mobile Intel Pentium III-M (Tualatin) and all - mobile Intel Pentium 4 P4-M on systems which have an Intel ICH2, - ICH3 or ICH4 southbridge. - - For details, take a look at . - - If in doubt, say N. - -config X86_SPEEDSTEP_SMI - tristate "Intel SpeedStep on 440BX/ZX/MX chipsets (SMI interface)" - select CPU_FREQ_TABLE - depends on X86_32 && EXPERIMENTAL - help - This adds the CPUFreq driver for certain mobile Intel Pentium III - (Coppermine), all mobile Intel Pentium III-M (Tualatin) - on systems which have an Intel 440BX/ZX/MX southbridge. - - For details, take a look at . - - If in doubt, say N. - -config X86_P4_CLOCKMOD - tristate "Intel Pentium 4 clock modulation" - select CPU_FREQ_TABLE - help - This adds the CPUFreq driver for Intel Pentium 4 / XEON - processors. When enabled it will lower CPU temperature by skipping - clocks. - - This driver should be only used in exceptional - circumstances when very low power is needed because it causes severe - slowdowns and noticeable latencies. Normally Speedstep should be used - instead. - - To compile this driver as a module, choose M here: the - module will be called p4-clockmod. - - For details, take a look at . - - Unless you are absolutely sure say N. - -config X86_CPUFREQ_NFORCE2 - tristate "nVidia nForce2 FSB changing" - depends on X86_32 && EXPERIMENTAL - help - This adds the CPUFreq driver for FSB changing on nVidia nForce2 - platforms. - - For details, take a look at . - - If in doubt, say N. - -config X86_LONGRUN - tristate "Transmeta LongRun" - depends on X86_32 - help - This adds the CPUFreq driver for Transmeta Crusoe and Efficeon processors - which support LongRun. - - For details, take a look at . - - If in doubt, say N. - -config X86_LONGHAUL - tristate "VIA Cyrix III Longhaul" - select CPU_FREQ_TABLE - depends on X86_32 && ACPI_PROCESSOR - help - This adds the CPUFreq driver for VIA Samuel/CyrixIII, - VIA Cyrix Samuel/C3, VIA Cyrix Ezra and VIA Cyrix Ezra-T - processors. - - For details, take a look at . - - If in doubt, say N. - -config X86_E_POWERSAVER - tristate "VIA C7 Enhanced PowerSaver (DANGEROUS)" - select CPU_FREQ_TABLE - depends on X86_32 && EXPERIMENTAL - help - This adds the CPUFreq driver for VIA C7 processors. However, this driver - does not have any safeguards to prevent operating the CPU out of spec - and is thus considered dangerous. Please use the regular ACPI cpufreq - driver, enabled by CONFIG_X86_ACPI_CPUFREQ. - - If in doubt, say N. - -comment "shared options" - -config X86_SPEEDSTEP_LIB - tristate - default (X86_SPEEDSTEP_ICH || X86_SPEEDSTEP_SMI || X86_P4_CLOCKMOD) - -config X86_SPEEDSTEP_RELAXED_CAP_CHECK - bool "Relaxed speedstep capability checks" - depends on X86_32 && (X86_SPEEDSTEP_SMI || X86_SPEEDSTEP_ICH) - help - Don't perform all checks for a speedstep capable system which would - normally be done. Some ancient or strange systems, though speedstep - capable, don't always indicate that they are speedstep capable. This - option lets the probing code bypass some of those checks if the - parameter "relaxed_check=1" is passed to the module. - -endif # CPU_FREQ - -endmenu diff --git a/arch/x86/kernel/cpu/cpufreq/Makefile b/arch/x86/kernel/cpu/cpufreq/Makefile deleted file mode 100644 index bd54bf6..0000000 --- a/arch/x86/kernel/cpu/cpufreq/Makefile +++ /dev/null @@ -1,21 +0,0 @@ -# Link order matters. K8 is preferred to ACPI because of firmware bugs in early -# K8 systems. ACPI is preferred to all other hardware-specific drivers. -# speedstep-* is preferred over p4-clockmod. - -obj-$(CONFIG_X86_POWERNOW_K8) += powernow-k8.o mperf.o -obj-$(CONFIG_X86_ACPI_CPUFREQ) += acpi-cpufreq.o mperf.o -obj-$(CONFIG_X86_PCC_CPUFREQ) += pcc-cpufreq.o -obj-$(CONFIG_X86_POWERNOW_K6) += powernow-k6.o -obj-$(CONFIG_X86_POWERNOW_K7) += powernow-k7.o -obj-$(CONFIG_X86_LONGHAUL) += longhaul.o -obj-$(CONFIG_X86_E_POWERSAVER) += e_powersaver.o -obj-$(CONFIG_ELAN_CPUFREQ) += elanfreq.o -obj-$(CONFIG_SC520_CPUFREQ) += sc520_freq.o -obj-$(CONFIG_X86_LONGRUN) += longrun.o -obj-$(CONFIG_X86_GX_SUSPMOD) += gx-suspmod.o -obj-$(CONFIG_X86_SPEEDSTEP_ICH) += speedstep-ich.o -obj-$(CONFIG_X86_SPEEDSTEP_LIB) += speedstep-lib.o -obj-$(CONFIG_X86_SPEEDSTEP_SMI) += speedstep-smi.o -obj-$(CONFIG_X86_SPEEDSTEP_CENTRINO) += speedstep-centrino.o -obj-$(CONFIG_X86_P4_CLOCKMOD) += p4-clockmod.o -obj-$(CONFIG_X86_CPUFREQ_NFORCE2) += cpufreq-nforce2.o diff --git a/arch/x86/kernel/cpu/cpufreq/acpi-cpufreq.c b/arch/x86/kernel/cpu/cpufreq/acpi-cpufreq.c deleted file mode 100644 index 4e04e12..0000000 --- a/arch/x86/kernel/cpu/cpufreq/acpi-cpufreq.c +++ /dev/null @@ -1,773 +0,0 @@ -/* - * acpi-cpufreq.c - ACPI Processor P-States Driver - * - * Copyright (C) 2001, 2002 Andy Grover - * Copyright (C) 2001, 2002 Paul Diefenbaugh - * Copyright (C) 2002 - 2004 Dominik Brodowski - * Copyright (C) 2006 Denis Sadykov - * - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or (at - * your option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. - * - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#include - -#include -#include -#include -#include "mperf.h" - -MODULE_AUTHOR("Paul Diefenbaugh, Dominik Brodowski"); -MODULE_DESCRIPTION("ACPI Processor P-States Driver"); -MODULE_LICENSE("GPL"); - -enum { - UNDEFINED_CAPABLE = 0, - SYSTEM_INTEL_MSR_CAPABLE, - SYSTEM_IO_CAPABLE, -}; - -#define INTEL_MSR_RANGE (0xffff) - -struct acpi_cpufreq_data { - struct acpi_processor_performance *acpi_data; - struct cpufreq_frequency_table *freq_table; - unsigned int resume; - unsigned int cpu_feature; -}; - -static DEFINE_PER_CPU(struct acpi_cpufreq_data *, acfreq_data); - -/* acpi_perf_data is a pointer to percpu data. */ -static struct acpi_processor_performance __percpu *acpi_perf_data; - -static struct cpufreq_driver acpi_cpufreq_driver; - -static unsigned int acpi_pstate_strict; - -static int check_est_cpu(unsigned int cpuid) -{ - struct cpuinfo_x86 *cpu = &cpu_data(cpuid); - - return cpu_has(cpu, X86_FEATURE_EST); -} - -static unsigned extract_io(u32 value, struct acpi_cpufreq_data *data) -{ - struct acpi_processor_performance *perf; - int i; - - perf = data->acpi_data; - - for (i = 0; i < perf->state_count; i++) { - if (value == perf->states[i].status) - return data->freq_table[i].frequency; - } - return 0; -} - -static unsigned extract_msr(u32 msr, struct acpi_cpufreq_data *data) -{ - int i; - struct acpi_processor_performance *perf; - - msr &= INTEL_MSR_RANGE; - perf = data->acpi_data; - - for (i = 0; data->freq_table[i].frequency != CPUFREQ_TABLE_END; i++) { - if (msr == perf->states[data->freq_table[i].index].status) - return data->freq_table[i].frequency; - } - return data->freq_table[0].frequency; -} - -static unsigned extract_freq(u32 val, struct acpi_cpufreq_data *data) -{ - switch (data->cpu_feature) { - case SYSTEM_INTEL_MSR_CAPABLE: - return extract_msr(val, data); - case SYSTEM_IO_CAPABLE: - return extract_io(val, data); - default: - return 0; - } -} - -struct msr_addr { - u32 reg; -}; - -struct io_addr { - u16 port; - u8 bit_width; -}; - -struct drv_cmd { - unsigned int type; - const struct cpumask *mask; - union { - struct msr_addr msr; - struct io_addr io; - } addr; - u32 val; -}; - -/* Called via smp_call_function_single(), on the target CPU */ -static void do_drv_read(void *_cmd) -{ - struct drv_cmd *cmd = _cmd; - u32 h; - - switch (cmd->type) { - case SYSTEM_INTEL_MSR_CAPABLE: - rdmsr(cmd->addr.msr.reg, cmd->val, h); - break; - case SYSTEM_IO_CAPABLE: - acpi_os_read_port((acpi_io_address)cmd->addr.io.port, - &cmd->val, - (u32)cmd->addr.io.bit_width); - break; - default: - break; - } -} - -/* Called via smp_call_function_many(), on the target CPUs */ -static void do_drv_write(void *_cmd) -{ - struct drv_cmd *cmd = _cmd; - u32 lo, hi; - - switch (cmd->type) { - case SYSTEM_INTEL_MSR_CAPABLE: - rdmsr(cmd->addr.msr.reg, lo, hi); - lo = (lo & ~INTEL_MSR_RANGE) | (cmd->val & INTEL_MSR_RANGE); - wrmsr(cmd->addr.msr.reg, lo, hi); - break; - case SYSTEM_IO_CAPABLE: - acpi_os_write_port((acpi_io_address)cmd->addr.io.port, - cmd->val, - (u32)cmd->addr.io.bit_width); - break; - default: - break; - } -} - -static void drv_read(struct drv_cmd *cmd) -{ - int err; - cmd->val = 0; - - err = smp_call_function_any(cmd->mask, do_drv_read, cmd, 1); - WARN_ON_ONCE(err); /* smp_call_function_any() was buggy? */ -} - -static void drv_write(struct drv_cmd *cmd) -{ - int this_cpu; - - this_cpu = get_cpu(); - if (cpumask_test_cpu(this_cpu, cmd->mask)) - do_drv_write(cmd); - smp_call_function_many(cmd->mask, do_drv_write, cmd, 1); - put_cpu(); -} - -static u32 get_cur_val(const struct cpumask *mask) -{ - struct acpi_processor_performance *perf; - struct drv_cmd cmd; - - if (unlikely(cpumask_empty(mask))) - return 0; - - switch (per_cpu(acfreq_data, cpumask_first(mask))->cpu_feature) { - case SYSTEM_INTEL_MSR_CAPABLE: - cmd.type = SYSTEM_INTEL_MSR_CAPABLE; - cmd.addr.msr.reg = MSR_IA32_PERF_STATUS; - break; - case SYSTEM_IO_CAPABLE: - cmd.type = SYSTEM_IO_CAPABLE; - perf = per_cpu(acfreq_data, cpumask_first(mask))->acpi_data; - cmd.addr.io.port = perf->control_register.address; - cmd.addr.io.bit_width = perf->control_register.bit_width; - break; - default: - return 0; - } - - cmd.mask = mask; - drv_read(&cmd); - - pr_debug("get_cur_val = %u\n", cmd.val); - - return cmd.val; -} - -static unsigned int get_cur_freq_on_cpu(unsigned int cpu) -{ - struct acpi_cpufreq_data *data = per_cpu(acfreq_data, cpu); - unsigned int freq; - unsigned int cached_freq; - - pr_debug("get_cur_freq_on_cpu (%d)\n", cpu); - - if (unlikely(data == NULL || - data->acpi_data == NULL || data->freq_table == NULL)) { - return 0; - } - - cached_freq = data->freq_table[data->acpi_data->state].frequency; - freq = extract_freq(get_cur_val(cpumask_of(cpu)), data); - if (freq != cached_freq) { - /* - * The dreaded BIOS frequency change behind our back. - * Force set the frequency on next target call. - */ - data->resume = 1; - } - - pr_debug("cur freq = %u\n", freq); - - return freq; -} - -static unsigned int check_freqs(const struct cpumask *mask, unsigned int freq, - struct acpi_cpufreq_data *data) -{ - unsigned int cur_freq; - unsigned int i; - - for (i = 0; i < 100; i++) { - cur_freq = extract_freq(get_cur_val(mask), data); - if (cur_freq == freq) - return 1; - udelay(10); - } - return 0; -} - -static int acpi_cpufreq_target(struct cpufreq_policy *policy, - unsigned int target_freq, unsigned int relation) -{ - struct acpi_cpufreq_data *data = per_cpu(acfreq_data, policy->cpu); - struct acpi_processor_performance *perf; - struct cpufreq_freqs freqs; - struct drv_cmd cmd; - unsigned int next_state = 0; /* Index into freq_table */ - unsigned int next_perf_state = 0; /* Index into perf table */ - unsigned int i; - int result = 0; - - pr_debug("acpi_cpufreq_target %d (%d)\n", target_freq, policy->cpu); - - if (unlikely(data == NULL || - data->acpi_data == NULL || data->freq_table == NULL)) { - return -ENODEV; - } - - perf = data->acpi_data; - result = cpufreq_frequency_table_target(policy, - data->freq_table, - target_freq, - relation, &next_state); - if (unlikely(result)) { - result = -ENODEV; - goto out; - } - - next_perf_state = data->freq_table[next_state].index; - if (perf->state == next_perf_state) { - if (unlikely(data->resume)) { - pr_debug("Called after resume, resetting to P%d\n", - next_perf_state); - data->resume = 0; - } else { - pr_debug("Already at target state (P%d)\n", - next_perf_state); - goto out; - } - } - - switch (data->cpu_feature) { - case SYSTEM_INTEL_MSR_CAPABLE: - cmd.type = SYSTEM_INTEL_MSR_CAPABLE; - cmd.addr.msr.reg = MSR_IA32_PERF_CTL; - cmd.val = (u32) perf->states[next_perf_state].control; - break; - case SYSTEM_IO_CAPABLE: - cmd.type = SYSTEM_IO_CAPABLE; - cmd.addr.io.port = perf->control_register.address; - cmd.addr.io.bit_width = perf->control_register.bit_width; - cmd.val = (u32) perf->states[next_perf_state].control; - break; - default: - result = -ENODEV; - goto out; - } - - /* cpufreq holds the hotplug lock, so we are safe from here on */ - if (policy->shared_type != CPUFREQ_SHARED_TYPE_ANY) - cmd.mask = policy->cpus; - else - cmd.mask = cpumask_of(policy->cpu); - - freqs.old = perf->states[perf->state].core_frequency * 1000; - freqs.new = data->freq_table[next_state].frequency; - for_each_cpu(i, policy->cpus) { - freqs.cpu = i; - cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE); - } - - drv_write(&cmd); - - if (acpi_pstate_strict) { - if (!check_freqs(cmd.mask, freqs.new, data)) { - pr_debug("acpi_cpufreq_target failed (%d)\n", - policy->cpu); - result = -EAGAIN; - goto out; - } - } - - for_each_cpu(i, policy->cpus) { - freqs.cpu = i; - cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE); - } - perf->state = next_perf_state; - -out: - return result; -} - -static int acpi_cpufreq_verify(struct cpufreq_policy *policy) -{ - struct acpi_cpufreq_data *data = per_cpu(acfreq_data, policy->cpu); - - pr_debug("acpi_cpufreq_verify\n"); - - return cpufreq_frequency_table_verify(policy, data->freq_table); -} - -static unsigned long -acpi_cpufreq_guess_freq(struct acpi_cpufreq_data *data, unsigned int cpu) -{ - struct acpi_processor_performance *perf = data->acpi_data; - - if (cpu_khz) { - /* search the closest match to cpu_khz */ - unsigned int i; - unsigned long freq; - unsigned long freqn = perf->states[0].core_frequency * 1000; - - for (i = 0; i < (perf->state_count-1); i++) { - freq = freqn; - freqn = perf->states[i+1].core_frequency * 1000; - if ((2 * cpu_khz) > (freqn + freq)) { - perf->state = i; - return freq; - } - } - perf->state = perf->state_count-1; - return freqn; - } else { - /* assume CPU is at P0... */ - perf->state = 0; - return perf->states[0].core_frequency * 1000; - } -} - -static void free_acpi_perf_data(void) -{ - unsigned int i; - - /* Freeing a NULL pointer is OK, and alloc_percpu zeroes. */ - for_each_possible_cpu(i) - free_cpumask_var(per_cpu_ptr(acpi_perf_data, i) - ->shared_cpu_map); - free_percpu(acpi_perf_data); -} - -/* - * acpi_cpufreq_early_init - initialize ACPI P-States library - * - * Initialize the ACPI P-States library (drivers/acpi/processor_perflib.c) - * in order to determine correct frequency and voltage pairings. We can - * do _PDC and _PSD and find out the processor dependency for the - * actual init that will happen later... - */ -static int __init acpi_cpufreq_early_init(void) -{ - unsigned int i; - pr_debug("acpi_cpufreq_early_init\n"); - - acpi_perf_data = alloc_percpu(struct acpi_processor_performance); - if (!acpi_perf_data) { - pr_debug("Memory allocation error for acpi_perf_data.\n"); - return -ENOMEM; - } - for_each_possible_cpu(i) { - if (!zalloc_cpumask_var_node( - &per_cpu_ptr(acpi_perf_data, i)->shared_cpu_map, - GFP_KERNEL, cpu_to_node(i))) { - - /* Freeing a NULL pointer is OK: alloc_percpu zeroes. */ - free_acpi_perf_data(); - return -ENOMEM; - } - } - - /* Do initialization in ACPI core */ - acpi_processor_preregister_performance(acpi_perf_data); - return 0; -} - -#ifdef CONFIG_SMP -/* - * Some BIOSes do SW_ANY coordination internally, either set it up in hw - * or do it in BIOS firmware and won't inform about it to OS. If not - * detected, this has a side effect of making CPU run at a different speed - * than OS intended it to run at. Detect it and handle it cleanly. - */ -static int bios_with_sw_any_bug; - -static int sw_any_bug_found(const struct dmi_system_id *d) -{ - bios_with_sw_any_bug = 1; - return 0; -} - -static const struct dmi_system_id sw_any_bug_dmi_table[] = { - { - .callback = sw_any_bug_found, - .ident = "Supermicro Server X6DLP", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "Supermicro"), - DMI_MATCH(DMI_BIOS_VERSION, "080010"), - DMI_MATCH(DMI_PRODUCT_NAME, "X6DLP"), - }, - }, - { } -}; - -static int acpi_cpufreq_blacklist(struct cpuinfo_x86 *c) -{ - /* Intel Xeon Processor 7100 Series Specification Update - * http://www.intel.com/Assets/PDF/specupdate/314554.pdf - * AL30: A Machine Check Exception (MCE) Occurring during an - * Enhanced Intel SpeedStep Technology Ratio Change May Cause - * Both Processor Cores to Lock Up. */ - if (c->x86_vendor == X86_VENDOR_INTEL) { - if ((c->x86 == 15) && - (c->x86_model == 6) && - (c->x86_mask == 8)) { - printk(KERN_INFO "acpi-cpufreq: Intel(R) " - "Xeon(R) 7100 Errata AL30, processors may " - "lock up on frequency changes: disabling " - "acpi-cpufreq.\n"); - return -ENODEV; - } - } - return 0; -} -#endif - -static int acpi_cpufreq_cpu_init(struct cpufreq_policy *policy) -{ - unsigned int i; - unsigned int valid_states = 0; - unsigned int cpu = policy->cpu; - struct acpi_cpufreq_data *data; - unsigned int result = 0; - struct cpuinfo_x86 *c = &cpu_data(policy->cpu); - struct acpi_processor_performance *perf; -#ifdef CONFIG_SMP - static int blacklisted; -#endif - - pr_debug("acpi_cpufreq_cpu_init\n"); - -#ifdef CONFIG_SMP - if (blacklisted) - return blacklisted; - blacklisted = acpi_cpufreq_blacklist(c); - if (blacklisted) - return blacklisted; -#endif - - data = kzalloc(sizeof(struct acpi_cpufreq_data), GFP_KERNEL); - if (!data) - return -ENOMEM; - - data->acpi_data = per_cpu_ptr(acpi_perf_data, cpu); - per_cpu(acfreq_data, cpu) = data; - - if (cpu_has(c, X86_FEATURE_CONSTANT_TSC)) - acpi_cpufreq_driver.flags |= CPUFREQ_CONST_LOOPS; - - result = acpi_processor_register_performance(data->acpi_data, cpu); - if (result) - goto err_free; - - perf = data->acpi_data; - policy->shared_type = perf->shared_type; - - /* - * Will let policy->cpus know about dependency only when software - * coordination is required. - */ - if (policy->shared_type == CPUFREQ_SHARED_TYPE_ALL || - policy->shared_type == CPUFREQ_SHARED_TYPE_ANY) { - cpumask_copy(policy->cpus, perf->shared_cpu_map); - } - cpumask_copy(policy->related_cpus, perf->shared_cpu_map); - -#ifdef CONFIG_SMP - dmi_check_system(sw_any_bug_dmi_table); - if (bios_with_sw_any_bug && cpumask_weight(policy->cpus) == 1) { - policy->shared_type = CPUFREQ_SHARED_TYPE_ALL; - cpumask_copy(policy->cpus, cpu_core_mask(cpu)); - } -#endif - - /* capability check */ - if (perf->state_count <= 1) { - pr_debug("No P-States\n"); - result = -ENODEV; - goto err_unreg; - } - - if (perf->control_register.space_id != perf->status_register.space_id) { - result = -ENODEV; - goto err_unreg; - } - - switch (perf->control_register.space_id) { - case ACPI_ADR_SPACE_SYSTEM_IO: - pr_debug("SYSTEM IO addr space\n"); - data->cpu_feature = SYSTEM_IO_CAPABLE; - break; - case ACPI_ADR_SPACE_FIXED_HARDWARE: - pr_debug("HARDWARE addr space\n"); - if (!check_est_cpu(cpu)) { - result = -ENODEV; - goto err_unreg; - } - data->cpu_feature = SYSTEM_INTEL_MSR_CAPABLE; - break; - default: - pr_debug("Unknown addr space %d\n", - (u32) (perf->control_register.space_id)); - result = -ENODEV; - goto err_unreg; - } - - data->freq_table = kmalloc(sizeof(struct cpufreq_frequency_table) * - (perf->state_count+1), GFP_KERNEL); - if (!data->freq_table) { - result = -ENOMEM; - goto err_unreg; - } - - /* detect transition latency */ - policy->cpuinfo.transition_latency = 0; - for (i = 0; i < perf->state_count; i++) { - if ((perf->states[i].transition_latency * 1000) > - policy->cpuinfo.transition_latency) - policy->cpuinfo.transition_latency = - perf->states[i].transition_latency * 1000; - } - - /* Check for high latency (>20uS) from buggy BIOSes, like on T42 */ - if (perf->control_register.space_id == ACPI_ADR_SPACE_FIXED_HARDWARE && - policy->cpuinfo.transition_latency > 20 * 1000) { - policy->cpuinfo.transition_latency = 20 * 1000; - printk_once(KERN_INFO - "P-state transition latency capped at 20 uS\n"); - } - - /* table init */ - for (i = 0; i < perf->state_count; i++) { - if (i > 0 && perf->states[i].core_frequency >= - data->freq_table[valid_states-1].frequency / 1000) - continue; - - data->freq_table[valid_states].index = i; - data->freq_table[valid_states].frequency = - perf->states[i].core_frequency * 1000; - valid_states++; - } - data->freq_table[valid_states].frequency = CPUFREQ_TABLE_END; - perf->state = 0; - - result = cpufreq_frequency_table_cpuinfo(policy, data->freq_table); - if (result) - goto err_freqfree; - - if (perf->states[0].core_frequency * 1000 != policy->cpuinfo.max_freq) - printk(KERN_WARNING FW_WARN "P-state 0 is not max freq\n"); - - switch (perf->control_register.space_id) { - case ACPI_ADR_SPACE_SYSTEM_IO: - /* Current speed is unknown and not detectable by IO port */ - policy->cur = acpi_cpufreq_guess_freq(data, policy->cpu); - break; - case ACPI_ADR_SPACE_FIXED_HARDWARE: - acpi_cpufreq_driver.get = get_cur_freq_on_cpu; - policy->cur = get_cur_freq_on_cpu(cpu); - break; - default: - break; - } - - /* notify BIOS that we exist */ - acpi_processor_notify_smm(THIS_MODULE); - - /* Check for APERF/MPERF support in hardware */ - if (cpu_has(c, X86_FEATURE_APERFMPERF)) - acpi_cpufreq_driver.getavg = cpufreq_get_measured_perf; - - pr_debug("CPU%u - ACPI performance management activated.\n", cpu); - for (i = 0; i < perf->state_count; i++) - pr_debug(" %cP%d: %d MHz, %d mW, %d uS\n", - (i == perf->state ? '*' : ' '), i, - (u32) perf->states[i].core_frequency, - (u32) perf->states[i].power, - (u32) perf->states[i].transition_latency); - - cpufreq_frequency_table_get_attr(data->freq_table, policy->cpu); - - /* - * the first call to ->target() should result in us actually - * writing something to the appropriate registers. - */ - data->resume = 1; - - return result; - -err_freqfree: - kfree(data->freq_table); -err_unreg: - acpi_processor_unregister_performance(perf, cpu); -err_free: - kfree(data); - per_cpu(acfreq_data, cpu) = NULL; - - return result; -} - -static int acpi_cpufreq_cpu_exit(struct cpufreq_policy *policy) -{ - struct acpi_cpufreq_data *data = per_cpu(acfreq_data, policy->cpu); - - pr_debug("acpi_cpufreq_cpu_exit\n"); - - if (data) { - cpufreq_frequency_table_put_attr(policy->cpu); - per_cpu(acfreq_data, policy->cpu) = NULL; - acpi_processor_unregister_performance(data->acpi_data, - policy->cpu); - kfree(data->freq_table); - kfree(data); - } - - return 0; -} - -static int acpi_cpufreq_resume(struct cpufreq_policy *policy) -{ - struct acpi_cpufreq_data *data = per_cpu(acfreq_data, policy->cpu); - - pr_debug("acpi_cpufreq_resume\n"); - - data->resume = 1; - - return 0; -} - -static struct freq_attr *acpi_cpufreq_attr[] = { - &cpufreq_freq_attr_scaling_available_freqs, - NULL, -}; - -static struct cpufreq_driver acpi_cpufreq_driver = { - .verify = acpi_cpufreq_verify, - .target = acpi_cpufreq_target, - .bios_limit = acpi_processor_get_bios_limit, - .init = acpi_cpufreq_cpu_init, - .exit = acpi_cpufreq_cpu_exit, - .resume = acpi_cpufreq_resume, - .name = "acpi-cpufreq", - .owner = THIS_MODULE, - .attr = acpi_cpufreq_attr, -}; - -static int __init acpi_cpufreq_init(void) -{ - int ret; - - if (acpi_disabled) - return 0; - - pr_debug("acpi_cpufreq_init\n"); - - ret = acpi_cpufreq_early_init(); - if (ret) - return ret; - - ret = cpufreq_register_driver(&acpi_cpufreq_driver); - if (ret) - free_acpi_perf_data(); - - return ret; -} - -static void __exit acpi_cpufreq_exit(void) -{ - pr_debug("acpi_cpufreq_exit\n"); - - cpufreq_unregister_driver(&acpi_cpufreq_driver); - - free_percpu(acpi_perf_data); -} - -module_param(acpi_pstate_strict, uint, 0644); -MODULE_PARM_DESC(acpi_pstate_strict, - "value 0 or non-zero. non-zero -> strict ACPI checks are " - "performed during frequency changes."); - -late_initcall(acpi_cpufreq_init); -module_exit(acpi_cpufreq_exit); - -MODULE_ALIAS("acpi"); diff --git a/arch/x86/kernel/cpu/cpufreq/cpufreq-nforce2.c b/arch/x86/kernel/cpu/cpufreq/cpufreq-nforce2.c deleted file mode 100644 index 7bac808..0000000 --- a/arch/x86/kernel/cpu/cpufreq/cpufreq-nforce2.c +++ /dev/null @@ -1,444 +0,0 @@ -/* - * (C) 2004-2006 Sebastian Witt - * - * Licensed under the terms of the GNU GPL License version 2. - * Based upon reverse engineered information - * - * BIG FAT DISCLAIMER: Work in progress code. Possibly *dangerous* - */ - -#include -#include -#include -#include -#include -#include -#include - -#define NFORCE2_XTAL 25 -#define NFORCE2_BOOTFSB 0x48 -#define NFORCE2_PLLENABLE 0xa8 -#define NFORCE2_PLLREG 0xa4 -#define NFORCE2_PLLADR 0xa0 -#define NFORCE2_PLL(mul, div) (0x100000 | (mul << 8) | div) - -#define NFORCE2_MIN_FSB 50 -#define NFORCE2_SAFE_DISTANCE 50 - -/* Delay in ms between FSB changes */ -/* #define NFORCE2_DELAY 10 */ - -/* - * nforce2_chipset: - * FSB is changed using the chipset - */ -static struct pci_dev *nforce2_dev; - -/* fid: - * multiplier * 10 - */ -static int fid; - -/* min_fsb, max_fsb: - * minimum and maximum FSB (= FSB at boot time) - */ -static int min_fsb; -static int max_fsb; - -MODULE_AUTHOR("Sebastian Witt "); -MODULE_DESCRIPTION("nForce2 FSB changing cpufreq driver"); -MODULE_LICENSE("GPL"); - -module_param(fid, int, 0444); -module_param(min_fsb, int, 0444); - -MODULE_PARM_DESC(fid, "CPU multiplier to use (11.5 = 115)"); -MODULE_PARM_DESC(min_fsb, - "Minimum FSB to use, if not defined: current FSB - 50"); - -#define PFX "cpufreq-nforce2: " - -/** - * nforce2_calc_fsb - calculate FSB - * @pll: PLL value - * - * Calculates FSB from PLL value - */ -static int nforce2_calc_fsb(int pll) -{ - unsigned char mul, div; - - mul = (pll >> 8) & 0xff; - div = pll & 0xff; - - if (div > 0) - return NFORCE2_XTAL * mul / div; - - return 0; -} - -/** - * nforce2_calc_pll - calculate PLL value - * @fsb: FSB - * - * Calculate PLL value for given FSB - */ -static int nforce2_calc_pll(unsigned int fsb) -{ - unsigned char xmul, xdiv; - unsigned char mul = 0, div = 0; - int tried = 0; - - /* Try to calculate multiplier and divider up to 4 times */ - while (((mul == 0) || (div == 0)) && (tried <= 3)) { - for (xdiv = 2; xdiv <= 0x80; xdiv++) - for (xmul = 1; xmul <= 0xfe; xmul++) - if (nforce2_calc_fsb(NFORCE2_PLL(xmul, xdiv)) == - fsb + tried) { - mul = xmul; - div = xdiv; - } - tried++; - } - - if ((mul == 0) || (div == 0)) - return -1; - - return NFORCE2_PLL(mul, div); -} - -/** - * nforce2_write_pll - write PLL value to chipset - * @pll: PLL value - * - * Writes new FSB PLL value to chipset - */ -static void nforce2_write_pll(int pll) -{ - int temp; - - /* Set the pll addr. to 0x00 */ - pci_write_config_dword(nforce2_dev, NFORCE2_PLLADR, 0); - - /* Now write the value in all 64 registers */ - for (temp = 0; temp <= 0x3f; temp++) - pci_write_config_dword(nforce2_dev, NFORCE2_PLLREG, pll); - - return; -} - -/** - * nforce2_fsb_read - Read FSB - * - * Read FSB from chipset - * If bootfsb != 0, return FSB at boot-time - */ -static unsigned int nforce2_fsb_read(int bootfsb) -{ - struct pci_dev *nforce2_sub5; - u32 fsb, temp = 0; - - /* Get chipset boot FSB from subdevice 5 (FSB at boot-time) */ - nforce2_sub5 = pci_get_subsys(PCI_VENDOR_ID_NVIDIA, 0x01EF, - PCI_ANY_ID, PCI_ANY_ID, NULL); - if (!nforce2_sub5) - return 0; - - pci_read_config_dword(nforce2_sub5, NFORCE2_BOOTFSB, &fsb); - fsb /= 1000000; - - /* Check if PLL register is already set */ - pci_read_config_byte(nforce2_dev, NFORCE2_PLLENABLE, (u8 *)&temp); - - if (bootfsb || !temp) - return fsb; - - /* Use PLL register FSB value */ - pci_read_config_dword(nforce2_dev, NFORCE2_PLLREG, &temp); - fsb = nforce2_calc_fsb(temp); - - return fsb; -} - -/** - * nforce2_set_fsb - set new FSB - * @fsb: New FSB - * - * Sets new FSB - */ -static int nforce2_set_fsb(unsigned int fsb) -{ - u32 temp = 0; - unsigned int tfsb; - int diff; - int pll = 0; - - if ((fsb > max_fsb) || (fsb < NFORCE2_MIN_FSB)) { - printk(KERN_ERR PFX "FSB %d is out of range!\n", fsb); - return -EINVAL; - } - - tfsb = nforce2_fsb_read(0); - if (!tfsb) { - printk(KERN_ERR PFX "Error while reading the FSB\n"); - return -EINVAL; - } - - /* First write? Then set actual value */ - pci_read_config_byte(nforce2_dev, NFORCE2_PLLENABLE, (u8 *)&temp); - if (!temp) { - pll = nforce2_calc_pll(tfsb); - - if (pll < 0) - return -EINVAL; - - nforce2_write_pll(pll); - } - - /* Enable write access */ - temp = 0x01; - pci_write_config_byte(nforce2_dev, NFORCE2_PLLENABLE, (u8)temp); - - diff = tfsb - fsb; - - if (!diff) - return 0; - - while ((tfsb != fsb) && (tfsb <= max_fsb) && (tfsb >= min_fsb)) { - if (diff < 0) - tfsb++; - else - tfsb--; - - /* Calculate the PLL reg. value */ - pll = nforce2_calc_pll(tfsb); - if (pll == -1) - return -EINVAL; - - nforce2_write_pll(pll); -#ifdef NFORCE2_DELAY - mdelay(NFORCE2_DELAY); -#endif - } - - temp = 0x40; - pci_write_config_byte(nforce2_dev, NFORCE2_PLLADR, (u8)temp); - - return 0; -} - -/** - * nforce2_get - get the CPU frequency - * @cpu: CPU number - * - * Returns the CPU frequency - */ -static unsigned int nforce2_get(unsigned int cpu) -{ - if (cpu) - return 0; - return nforce2_fsb_read(0) * fid * 100; -} - -/** - * nforce2_target - set a new CPUFreq policy - * @policy: new policy - * @target_freq: the target frequency - * @relation: how that frequency relates to achieved frequency - * (CPUFREQ_RELATION_L or CPUFREQ_RELATION_H) - * - * Sets a new CPUFreq policy. - */ -static int nforce2_target(struct cpufreq_policy *policy, - unsigned int target_freq, unsigned int relation) -{ -/* unsigned long flags; */ - struct cpufreq_freqs freqs; - unsigned int target_fsb; - - if ((target_freq > policy->max) || (target_freq < policy->min)) - return -EINVAL; - - target_fsb = target_freq / (fid * 100); - - freqs.old = nforce2_get(policy->cpu); - freqs.new = target_fsb * fid * 100; - freqs.cpu = 0; /* Only one CPU on nForce2 platforms */ - - if (freqs.old == freqs.new) - return 0; - - pr_debug("Old CPU frequency %d kHz, new %d kHz\n", - freqs.old, freqs.new); - - cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE); - - /* Disable IRQs */ - /* local_irq_save(flags); */ - - if (nforce2_set_fsb(target_fsb) < 0) - printk(KERN_ERR PFX "Changing FSB to %d failed\n", - target_fsb); - else - pr_debug("Changed FSB successfully to %d\n", - target_fsb); - - /* Enable IRQs */ - /* local_irq_restore(flags); */ - - cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE); - - return 0; -} - -/** - * nforce2_verify - verifies a new CPUFreq policy - * @policy: new policy - */ -static int nforce2_verify(struct cpufreq_policy *policy) -{ - unsigned int fsb_pol_max; - - fsb_pol_max = policy->max / (fid * 100); - - if (policy->min < (fsb_pol_max * fid * 100)) - policy->max = (fsb_pol_max + 1) * fid * 100; - - cpufreq_verify_within_limits(policy, - policy->cpuinfo.min_freq, - policy->cpuinfo.max_freq); - return 0; -} - -static int nforce2_cpu_init(struct cpufreq_policy *policy) -{ - unsigned int fsb; - unsigned int rfid; - - /* capability check */ - if (policy->cpu != 0) - return -ENODEV; - - /* Get current FSB */ - fsb = nforce2_fsb_read(0); - - if (!fsb) - return -EIO; - - /* FIX: Get FID from CPU */ - if (!fid) { - if (!cpu_khz) { - printk(KERN_WARNING PFX - "cpu_khz not set, can't calculate multiplier!\n"); - return -ENODEV; - } - - fid = cpu_khz / (fsb * 100); - rfid = fid % 5; - - if (rfid) { - if (rfid > 2) - fid += 5 - rfid; - else - fid -= rfid; - } - } - - printk(KERN_INFO PFX "FSB currently at %i MHz, FID %d.%d\n", fsb, - fid / 10, fid % 10); - - /* Set maximum FSB to FSB at boot time */ - max_fsb = nforce2_fsb_read(1); - - if (!max_fsb) - return -EIO; - - if (!min_fsb) - min_fsb = max_fsb - NFORCE2_SAFE_DISTANCE; - - if (min_fsb < NFORCE2_MIN_FSB) - min_fsb = NFORCE2_MIN_FSB; - - /* cpuinfo and default policy values */ - policy->cpuinfo.min_freq = min_fsb * fid * 100; - policy->cpuinfo.max_freq = max_fsb * fid * 100; - policy->cpuinfo.transition_latency = CPUFREQ_ETERNAL; - policy->cur = nforce2_get(policy->cpu); - policy->min = policy->cpuinfo.min_freq; - policy->max = policy->cpuinfo.max_freq; - - return 0; -} - -static int nforce2_cpu_exit(struct cpufreq_policy *policy) -{ - return 0; -} - -static struct cpufreq_driver nforce2_driver = { - .name = "nforce2", - .verify = nforce2_verify, - .target = nforce2_target, - .get = nforce2_get, - .init = nforce2_cpu_init, - .exit = nforce2_cpu_exit, - .owner = THIS_MODULE, -}; - -/** - * nforce2_detect_chipset - detect the Southbridge which contains FSB PLL logic - * - * Detects nForce2 A2 and C1 stepping - * - */ -static int nforce2_detect_chipset(void) -{ - nforce2_dev = pci_get_subsys(PCI_VENDOR_ID_NVIDIA, - PCI_DEVICE_ID_NVIDIA_NFORCE2, - PCI_ANY_ID, PCI_ANY_ID, NULL); - - if (nforce2_dev == NULL) - return -ENODEV; - - printk(KERN_INFO PFX "Detected nForce2 chipset revision %X\n", - nforce2_dev->revision); - printk(KERN_INFO PFX - "FSB changing is maybe unstable and can lead to " - "crashes and data loss.\n"); - - return 0; -} - -/** - * nforce2_init - initializes the nForce2 CPUFreq driver - * - * Initializes the nForce2 FSB support. Returns -ENODEV on unsupported - * devices, -EINVAL on problems during initiatization, and zero on - * success. - */ -static int __init nforce2_init(void) -{ - /* TODO: do we need to detect the processor? */ - - /* detect chipset */ - if (nforce2_detect_chipset()) { - printk(KERN_INFO PFX "No nForce2 chipset.\n"); - return -ENODEV; - } - - return cpufreq_register_driver(&nforce2_driver); -} - -/** - * nforce2_exit - unregisters cpufreq module - * - * Unregisters nForce2 FSB change support. - */ -static void __exit nforce2_exit(void) -{ - cpufreq_unregister_driver(&nforce2_driver); -} - -module_init(nforce2_init); -module_exit(nforce2_exit); - diff --git a/arch/x86/kernel/cpu/cpufreq/e_powersaver.c b/arch/x86/kernel/cpu/cpufreq/e_powersaver.c deleted file mode 100644 index 35a257d..0000000 --- a/arch/x86/kernel/cpu/cpufreq/e_powersaver.c +++ /dev/null @@ -1,367 +0,0 @@ -/* - * Based on documentation provided by Dave Jones. Thanks! - * - * Licensed under the terms of the GNU GPL License version 2. - * - * BIG FAT DISCLAIMER: Work in progress code. Possibly *dangerous* - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#define EPS_BRAND_C7M 0 -#define EPS_BRAND_C7 1 -#define EPS_BRAND_EDEN 2 -#define EPS_BRAND_C3 3 -#define EPS_BRAND_C7D 4 - -struct eps_cpu_data { - u32 fsb; - struct cpufreq_frequency_table freq_table[]; -}; - -static struct eps_cpu_data *eps_cpu[NR_CPUS]; - - -static unsigned int eps_get(unsigned int cpu) -{ - struct eps_cpu_data *centaur; - u32 lo, hi; - - if (cpu) - return 0; - centaur = eps_cpu[cpu]; - if (centaur == NULL) - return 0; - - /* Return current frequency */ - rdmsr(MSR_IA32_PERF_STATUS, lo, hi); - return centaur->fsb * ((lo >> 8) & 0xff); -} - -static int eps_set_state(struct eps_cpu_data *centaur, - unsigned int cpu, - u32 dest_state) -{ - struct cpufreq_freqs freqs; - u32 lo, hi; - int err = 0; - int i; - - freqs.old = eps_get(cpu); - freqs.new = centaur->fsb * ((dest_state >> 8) & 0xff); - freqs.cpu = cpu; - cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE); - - /* Wait while CPU is busy */ - rdmsr(MSR_IA32_PERF_STATUS, lo, hi); - i = 0; - while (lo & ((1 << 16) | (1 << 17))) { - udelay(16); - rdmsr(MSR_IA32_PERF_STATUS, lo, hi); - i++; - if (unlikely(i > 64)) { - err = -ENODEV; - goto postchange; - } - } - /* Set new multiplier and voltage */ - wrmsr(MSR_IA32_PERF_CTL, dest_state & 0xffff, 0); - /* Wait until transition end */ - i = 0; - do { - udelay(16); - rdmsr(MSR_IA32_PERF_STATUS, lo, hi); - i++; - if (unlikely(i > 64)) { - err = -ENODEV; - goto postchange; - } - } while (lo & ((1 << 16) | (1 << 17))); - - /* Return current frequency */ -postchange: - rdmsr(MSR_IA32_PERF_STATUS, lo, hi); - freqs.new = centaur->fsb * ((lo >> 8) & 0xff); - -#ifdef DEBUG - { - u8 current_multiplier, current_voltage; - - /* Print voltage and multiplier */ - rdmsr(MSR_IA32_PERF_STATUS, lo, hi); - current_voltage = lo & 0xff; - printk(KERN_INFO "eps: Current voltage = %dmV\n", - current_voltage * 16 + 700); - current_multiplier = (lo >> 8) & 0xff; - printk(KERN_INFO "eps: Current multiplier = %d\n", - current_multiplier); - } -#endif - cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE); - return err; -} - -static int eps_target(struct cpufreq_policy *policy, - unsigned int target_freq, - unsigned int relation) -{ - struct eps_cpu_data *centaur; - unsigned int newstate = 0; - unsigned int cpu = policy->cpu; - unsigned int dest_state; - int ret; - - if (unlikely(eps_cpu[cpu] == NULL)) - return -ENODEV; - centaur = eps_cpu[cpu]; - - if (unlikely(cpufreq_frequency_table_target(policy, - &eps_cpu[cpu]->freq_table[0], - target_freq, - relation, - &newstate))) { - return -EINVAL; - } - - /* Make frequency transition */ - dest_state = centaur->freq_table[newstate].index & 0xffff; - ret = eps_set_state(centaur, cpu, dest_state); - if (ret) - printk(KERN_ERR "eps: Timeout!\n"); - return ret; -} - -static int eps_verify(struct cpufreq_policy *policy) -{ - return cpufreq_frequency_table_verify(policy, - &eps_cpu[policy->cpu]->freq_table[0]); -} - -static int eps_cpu_init(struct cpufreq_policy *policy) -{ - unsigned int i; - u32 lo, hi; - u64 val; - u8 current_multiplier, current_voltage; - u8 max_multiplier, max_voltage; - u8 min_multiplier, min_voltage; - u8 brand = 0; - u32 fsb; - struct eps_cpu_data *centaur; - struct cpuinfo_x86 *c = &cpu_data(0); - struct cpufreq_frequency_table *f_table; - int k, step, voltage; - int ret; - int states; - - if (policy->cpu != 0) - return -ENODEV; - - /* Check brand */ - printk(KERN_INFO "eps: Detected VIA "); - - switch (c->x86_model) { - case 10: - rdmsr(0x1153, lo, hi); - brand = (((lo >> 2) ^ lo) >> 18) & 3; - printk(KERN_CONT "Model A "); - break; - case 13: - rdmsr(0x1154, lo, hi); - brand = (((lo >> 4) ^ (lo >> 2))) & 0x000000ff; - printk(KERN_CONT "Model D "); - break; - } - - switch (brand) { - case EPS_BRAND_C7M: - printk(KERN_CONT "C7-M\n"); - break; - case EPS_BRAND_C7: - printk(KERN_CONT "C7\n"); - break; - case EPS_BRAND_EDEN: - printk(KERN_CONT "Eden\n"); - break; - case EPS_BRAND_C7D: - printk(KERN_CONT "C7-D\n"); - break; - case EPS_BRAND_C3: - printk(KERN_CONT "C3\n"); - return -ENODEV; - break; - } - /* Enable Enhanced PowerSaver */ - rdmsrl(MSR_IA32_MISC_ENABLE, val); - if (!(val & MSR_IA32_MISC_ENABLE_ENHANCED_SPEEDSTEP)) { - val |= MSR_IA32_MISC_ENABLE_ENHANCED_SPEEDSTEP; - wrmsrl(MSR_IA32_MISC_ENABLE, val); - /* Can be locked at 0 */ - rdmsrl(MSR_IA32_MISC_ENABLE, val); - if (!(val & MSR_IA32_MISC_ENABLE_ENHANCED_SPEEDSTEP)) { - printk(KERN_INFO "eps: Can't enable Enhanced PowerSaver\n"); - return -ENODEV; - } - } - - /* Print voltage and multiplier */ - rdmsr(MSR_IA32_PERF_STATUS, lo, hi); - current_voltage = lo & 0xff; - printk(KERN_INFO "eps: Current voltage = %dmV\n", - current_voltage * 16 + 700); - current_multiplier = (lo >> 8) & 0xff; - printk(KERN_INFO "eps: Current multiplier = %d\n", current_multiplier); - - /* Print limits */ - max_voltage = hi & 0xff; - printk(KERN_INFO "eps: Highest voltage = %dmV\n", - max_voltage * 16 + 700); - max_multiplier = (hi >> 8) & 0xff; - printk(KERN_INFO "eps: Highest multiplier = %d\n", max_multiplier); - min_voltage = (hi >> 16) & 0xff; - printk(KERN_INFO "eps: Lowest voltage = %dmV\n", - min_voltage * 16 + 700); - min_multiplier = (hi >> 24) & 0xff; - printk(KERN_INFO "eps: Lowest multiplier = %d\n", min_multiplier); - - /* Sanity checks */ - if (current_multiplier == 0 || max_multiplier == 0 - || min_multiplier == 0) - return -EINVAL; - if (current_multiplier > max_multiplier - || max_multiplier <= min_multiplier) - return -EINVAL; - if (current_voltage > 0x1f || max_voltage > 0x1f) - return -EINVAL; - if (max_voltage < min_voltage) - return -EINVAL; - - /* Calc FSB speed */ - fsb = cpu_khz / current_multiplier; - /* Calc number of p-states supported */ - if (brand == EPS_BRAND_C7M) - states = max_multiplier - min_multiplier + 1; - else - states = 2; - - /* Allocate private data and frequency table for current cpu */ - centaur = kzalloc(sizeof(struct eps_cpu_data) - + (states + 1) * sizeof(struct cpufreq_frequency_table), - GFP_KERNEL); - if (!centaur) - return -ENOMEM; - eps_cpu[0] = centaur; - - /* Copy basic values */ - centaur->fsb = fsb; - - /* Fill frequency and MSR value table */ - f_table = ¢aur->freq_table[0]; - if (brand != EPS_BRAND_C7M) { - f_table[0].frequency = fsb * min_multiplier; - f_table[0].index = (min_multiplier << 8) | min_voltage; - f_table[1].frequency = fsb * max_multiplier; - f_table[1].index = (max_multiplier << 8) | max_voltage; - f_table[2].frequency = CPUFREQ_TABLE_END; - } else { - k = 0; - step = ((max_voltage - min_voltage) * 256) - / (max_multiplier - min_multiplier); - for (i = min_multiplier; i <= max_multiplier; i++) { - voltage = (k * step) / 256 + min_voltage; - f_table[k].frequency = fsb * i; - f_table[k].index = (i << 8) | voltage; - k++; - } - f_table[k].frequency = CPUFREQ_TABLE_END; - } - - policy->cpuinfo.transition_latency = 140000; /* 844mV -> 700mV in ns */ - policy->cur = fsb * current_multiplier; - - ret = cpufreq_frequency_table_cpuinfo(policy, ¢aur->freq_table[0]); - if (ret) { - kfree(centaur); - return ret; - } - - cpufreq_frequency_table_get_attr(¢aur->freq_table[0], policy->cpu); - return 0; -} - -static int eps_cpu_exit(struct cpufreq_policy *policy) -{ - unsigned int cpu = policy->cpu; - struct eps_cpu_data *centaur; - u32 lo, hi; - - if (eps_cpu[cpu] == NULL) - return -ENODEV; - centaur = eps_cpu[cpu]; - - /* Get max frequency */ - rdmsr(MSR_IA32_PERF_STATUS, lo, hi); - /* Set max frequency */ - eps_set_state(centaur, cpu, hi & 0xffff); - /* Bye */ - cpufreq_frequency_table_put_attr(policy->cpu); - kfree(eps_cpu[cpu]); - eps_cpu[cpu] = NULL; - return 0; -} - -static struct freq_attr *eps_attr[] = { - &cpufreq_freq_attr_scaling_available_freqs, - NULL, -}; - -static struct cpufreq_driver eps_driver = { - .verify = eps_verify, - .target = eps_target, - .init = eps_cpu_init, - .exit = eps_cpu_exit, - .get = eps_get, - .name = "e_powersaver", - .owner = THIS_MODULE, - .attr = eps_attr, -}; - -static int __init eps_init(void) -{ - struct cpuinfo_x86 *c = &cpu_data(0); - - /* This driver will work only on Centaur C7 processors with - * Enhanced SpeedStep/PowerSaver registers */ - if (c->x86_vendor != X86_VENDOR_CENTAUR - || c->x86 != 6 || c->x86_model < 10) - return -ENODEV; - if (!cpu_has(c, X86_FEATURE_EST)) - return -ENODEV; - - if (cpufreq_register_driver(&eps_driver)) - return -EINVAL; - return 0; -} - -static void __exit eps_exit(void) -{ - cpufreq_unregister_driver(&eps_driver); -} - -MODULE_AUTHOR("Rafal Bilski "); -MODULE_DESCRIPTION("Enhanced PowerSaver driver for VIA C7 CPU's."); -MODULE_LICENSE("GPL"); - -module_init(eps_init); -module_exit(eps_exit); diff --git a/arch/x86/kernel/cpu/cpufreq/elanfreq.c b/arch/x86/kernel/cpu/cpufreq/elanfreq.c deleted file mode 100644 index c587db4..0000000 --- a/arch/x86/kernel/cpu/cpufreq/elanfreq.c +++ /dev/null @@ -1,309 +0,0 @@ -/* - * elanfreq: cpufreq driver for the AMD ELAN family - * - * (c) Copyright 2002 Robert Schwebel - * - * Parts of this code are (c) Sven Geggus - * - * All Rights Reserved. - * - * 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. - * - * 2002-02-13: - initial revision for 2.4.18-pre9 by Robert Schwebel - * - */ - -#include -#include -#include - -#include -#include - -#include -#include -#include - -#define REG_CSCIR 0x22 /* Chip Setup and Control Index Register */ -#define REG_CSCDR 0x23 /* Chip Setup and Control Data Register */ - -/* Module parameter */ -static int max_freq; - -struct s_elan_multiplier { - int clock; /* frequency in kHz */ - int val40h; /* PMU Force Mode register */ - int val80h; /* CPU Clock Speed Register */ -}; - -/* - * It is important that the frequencies - * are listed in ascending order here! - */ -static struct s_elan_multiplier elan_multiplier[] = { - {1000, 0x02, 0x18}, - {2000, 0x02, 0x10}, - {4000, 0x02, 0x08}, - {8000, 0x00, 0x00}, - {16000, 0x00, 0x02}, - {33000, 0x00, 0x04}, - {66000, 0x01, 0x04}, - {99000, 0x01, 0x05} -}; - -static struct cpufreq_frequency_table elanfreq_table[] = { - {0, 1000}, - {1, 2000}, - {2, 4000}, - {3, 8000}, - {4, 16000}, - {5, 33000}, - {6, 66000}, - {7, 99000}, - {0, CPUFREQ_TABLE_END}, -}; - - -/** - * elanfreq_get_cpu_frequency: determine current cpu speed - * - * Finds out at which frequency the CPU of the Elan SOC runs - * at the moment. Frequencies from 1 to 33 MHz are generated - * the normal way, 66 and 99 MHz are called "Hyperspeed Mode" - * and have the rest of the chip running with 33 MHz. - */ - -static unsigned int elanfreq_get_cpu_frequency(unsigned int cpu) -{ - u8 clockspeed_reg; /* Clock Speed Register */ - - local_irq_disable(); - outb_p(0x80, REG_CSCIR); - clockspeed_reg = inb_p(REG_CSCDR); - local_irq_enable(); - - if ((clockspeed_reg & 0xE0) == 0xE0) - return 0; - - /* Are we in CPU clock multiplied mode (66/99 MHz)? */ - if ((clockspeed_reg & 0xE0) == 0xC0) { - if ((clockspeed_reg & 0x01) == 0) - return 66000; - else - return 99000; - } - - /* 33 MHz is not 32 MHz... */ - if ((clockspeed_reg & 0xE0) == 0xA0) - return 33000; - - return (1<<((clockspeed_reg & 0xE0) >> 5)) * 1000; -} - - -/** - * elanfreq_set_cpu_frequency: Change the CPU core frequency - * @cpu: cpu number - * @freq: frequency in kHz - * - * This function takes a frequency value and changes the CPU frequency - * according to this. Note that the frequency has to be checked by - * elanfreq_validatespeed() for correctness! - * - * There is no return value. - */ - -static void elanfreq_set_cpu_state(unsigned int state) -{ - struct cpufreq_freqs freqs; - - freqs.old = elanfreq_get_cpu_frequency(0); - freqs.new = elan_multiplier[state].clock; - freqs.cpu = 0; /* elanfreq.c is UP only driver */ - - cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE); - - printk(KERN_INFO "elanfreq: attempting to set frequency to %i kHz\n", - elan_multiplier[state].clock); - - - /* - * Access to the Elan's internal registers is indexed via - * 0x22: Chip Setup & Control Register Index Register (CSCI) - * 0x23: Chip Setup & Control Register Data Register (CSCD) - * - */ - - /* - * 0x40 is the Power Management Unit's Force Mode Register. - * Bit 6 enables Hyperspeed Mode (66/100 MHz core frequency) - */ - - local_irq_disable(); - outb_p(0x40, REG_CSCIR); /* Disable hyperspeed mode */ - outb_p(0x00, REG_CSCDR); - local_irq_enable(); /* wait till internal pipelines and */ - udelay(1000); /* buffers have cleaned up */ - - local_irq_disable(); - - /* now, set the CPU clock speed register (0x80) */ - outb_p(0x80, REG_CSCIR); - outb_p(elan_multiplier[state].val80h, REG_CSCDR); - - /* now, the hyperspeed bit in PMU Force Mode Register (0x40) */ - outb_p(0x40, REG_CSCIR); - outb_p(elan_multiplier[state].val40h, REG_CSCDR); - udelay(10000); - local_irq_enable(); - - cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE); -}; - - -/** - * elanfreq_validatespeed: test if frequency range is valid - * @policy: the policy to validate - * - * This function checks if a given frequency range in kHz is valid - * for the hardware supported by the driver. - */ - -static int elanfreq_verify(struct cpufreq_policy *policy) -{ - return cpufreq_frequency_table_verify(policy, &elanfreq_table[0]); -} - -static int elanfreq_target(struct cpufreq_policy *policy, - unsigned int target_freq, - unsigned int relation) -{ - unsigned int newstate = 0; - - if (cpufreq_frequency_table_target(policy, &elanfreq_table[0], - target_freq, relation, &newstate)) - return -EINVAL; - - elanfreq_set_cpu_state(newstate); - - return 0; -} - - -/* - * Module init and exit code - */ - -static int elanfreq_cpu_init(struct cpufreq_policy *policy) -{ - struct cpuinfo_x86 *c = &cpu_data(0); - unsigned int i; - int result; - - /* capability check */ - if ((c->x86_vendor != X86_VENDOR_AMD) || - (c->x86 != 4) || (c->x86_model != 10)) - return -ENODEV; - - /* max freq */ - if (!max_freq) - max_freq = elanfreq_get_cpu_frequency(0); - - /* table init */ - for (i = 0; (elanfreq_table[i].frequency != CPUFREQ_TABLE_END); i++) { - if (elanfreq_table[i].frequency > max_freq) - elanfreq_table[i].frequency = CPUFREQ_ENTRY_INVALID; - } - - /* cpuinfo and default policy values */ - policy->cpuinfo.transition_latency = CPUFREQ_ETERNAL; - policy->cur = elanfreq_get_cpu_frequency(0); - - result = cpufreq_frequency_table_cpuinfo(policy, elanfreq_table); - if (result) - return result; - - cpufreq_frequency_table_get_attr(elanfreq_table, policy->cpu); - return 0; -} - - -static int elanfreq_cpu_exit(struct cpufreq_policy *policy) -{ - cpufreq_frequency_table_put_attr(policy->cpu); - return 0; -} - - -#ifndef MODULE -/** - * elanfreq_setup - elanfreq command line parameter parsing - * - * elanfreq command line parameter. Use: - * elanfreq=66000 - * to set the maximum CPU frequency to 66 MHz. Note that in - * case you do not give this boot parameter, the maximum - * frequency will fall back to _current_ CPU frequency which - * might be lower. If you build this as a module, use the - * max_freq module parameter instead. - */ -static int __init elanfreq_setup(char *str) -{ - max_freq = simple_strtoul(str, &str, 0); - printk(KERN_WARNING "You're using the deprecated elanfreq command line option. Use elanfreq.max_freq instead, please!\n"); - return 1; -} -__setup("elanfreq=", elanfreq_setup); -#endif - - -static struct freq_attr *elanfreq_attr[] = { - &cpufreq_freq_attr_scaling_available_freqs, - NULL, -}; - - -static struct cpufreq_driver elanfreq_driver = { - .get = elanfreq_get_cpu_frequency, - .verify = elanfreq_verify, - .target = elanfreq_target, - .init = elanfreq_cpu_init, - .exit = elanfreq_cpu_exit, - .name = "elanfreq", - .owner = THIS_MODULE, - .attr = elanfreq_attr, -}; - - -static int __init elanfreq_init(void) -{ - struct cpuinfo_x86 *c = &cpu_data(0); - - /* Test if we have the right hardware */ - if ((c->x86_vendor != X86_VENDOR_AMD) || - (c->x86 != 4) || (c->x86_model != 10)) { - printk(KERN_INFO "elanfreq: error: no Elan processor found!\n"); - return -ENODEV; - } - return cpufreq_register_driver(&elanfreq_driver); -} - - -static void __exit elanfreq_exit(void) -{ - cpufreq_unregister_driver(&elanfreq_driver); -} - - -module_param(max_freq, int, 0444); - -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Robert Schwebel , " - "Sven Geggus "); -MODULE_DESCRIPTION("cpufreq driver for AMD's Elan CPUs"); - -module_init(elanfreq_init); -module_exit(elanfreq_exit); diff --git a/arch/x86/kernel/cpu/cpufreq/gx-suspmod.c b/arch/x86/kernel/cpu/cpufreq/gx-suspmod.c deleted file mode 100644 index ffe1f2c..0000000 --- a/arch/x86/kernel/cpu/cpufreq/gx-suspmod.c +++ /dev/null @@ -1,514 +0,0 @@ -/* - * Cyrix MediaGX and NatSemi Geode Suspend Modulation - * (C) 2002 Zwane Mwaikambo - * (C) 2002 Hiroshi Miura - * All Rights Reserved - * - * 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 - * - * The author(s) of this software shall not be held liable for damages - * of any nature resulting due to the use of this software. This - * software is provided AS-IS with no warranties. - * - * Theoretical note: - * - * (see Geode(tm) CS5530 manual (rev.4.1) page.56) - * - * CPU frequency control on NatSemi Geode GX1/GXLV processor and CS55x0 - * are based on Suspend Modulation. - * - * Suspend Modulation works by asserting and de-asserting the SUSP# pin - * to CPU(GX1/GXLV) for configurable durations. When asserting SUSP# - * the CPU enters an idle state. GX1 stops its core clock when SUSP# is - * asserted then power consumption is reduced. - * - * Suspend Modulation's OFF/ON duration are configurable - * with 'Suspend Modulation OFF Count Register' - * and 'Suspend Modulation ON Count Register'. - * These registers are 8bit counters that represent the number of - * 32us intervals which the SUSP# pin is asserted(ON)/de-asserted(OFF) - * to the processor. - * - * These counters define a ratio which is the effective frequency - * of operation of the system. - * - * OFF Count - * F_eff = Fgx * ---------------------- - * OFF Count + ON Count - * - * 0 <= On Count, Off Count <= 255 - * - * From these limits, we can get register values - * - * off_duration + on_duration <= MAX_DURATION - * on_duration = off_duration * (stock_freq - freq) / freq - * - * off_duration = (freq * DURATION) / stock_freq - * on_duration = DURATION - off_duration - * - * - *--------------------------------------------------------------------------- - * - * ChangeLog: - * Dec. 12, 2003 Hiroshi Miura - * - fix on/off register mistake - * - fix cpu_khz calc when it stops cpu modulation. - * - * Dec. 11, 2002 Hiroshi Miura - * - rewrite for Cyrix MediaGX Cx5510/5520 and - * NatSemi Geode Cs5530(A). - * - * Jul. ??, 2002 Zwane Mwaikambo - * - cs5530_mod patch for 2.4.19-rc1. - * - *--------------------------------------------------------------------------- - * - * Todo - * Test on machines with 5510, 5530, 5530A - */ - -/************************************************************************ - * Suspend Modulation - Definitions * - ************************************************************************/ - -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -/* PCI config registers, all at F0 */ -#define PCI_PMER1 0x80 /* power management enable register 1 */ -#define PCI_PMER2 0x81 /* power management enable register 2 */ -#define PCI_PMER3 0x82 /* power management enable register 3 */ -#define PCI_IRQTC 0x8c /* irq speedup timer counter register:typical 2 to 4ms */ -#define PCI_VIDTC 0x8d /* video speedup timer counter register: typical 50 to 100ms */ -#define PCI_MODOFF 0x94 /* suspend modulation OFF counter register, 1 = 32us */ -#define PCI_MODON 0x95 /* suspend modulation ON counter register */ -#define PCI_SUSCFG 0x96 /* suspend configuration register */ - -/* PMER1 bits */ -#define GPM (1<<0) /* global power management */ -#define GIT (1<<1) /* globally enable PM device idle timers */ -#define GTR (1<<2) /* globally enable IO traps */ -#define IRQ_SPDUP (1<<3) /* disable clock throttle during interrupt handling */ -#define VID_SPDUP (1<<4) /* disable clock throttle during vga video handling */ - -/* SUSCFG bits */ -#define SUSMOD (1<<0) /* enable/disable suspend modulation */ -/* the below is supported only with cs5530 (after rev.1.2)/cs5530A */ -#define SMISPDUP (1<<1) /* select how SMI re-enable suspend modulation: */ - /* IRQTC timer or read SMI speedup disable reg.(F1BAR[08-09h]) */ -#define SUSCFG (1<<2) /* enable powering down a GXLV processor. "Special 3Volt Suspend" mode */ -/* the below is supported only with cs5530A */ -#define PWRSVE_ISA (1<<3) /* stop ISA clock */ -#define PWRSVE (1<<4) /* active idle */ - -struct gxfreq_params { - u8 on_duration; - u8 off_duration; - u8 pci_suscfg; - u8 pci_pmer1; - u8 pci_pmer2; - struct pci_dev *cs55x0; -}; - -static struct gxfreq_params *gx_params; -static int stock_freq; - -/* PCI bus clock - defaults to 30.000 if cpu_khz is not available */ -static int pci_busclk; -module_param(pci_busclk, int, 0444); - -/* maximum duration for which the cpu may be suspended - * (32us * MAX_DURATION). If no parameter is given, this defaults - * to 255. - * Note that this leads to a maximum of 8 ms(!) where the CPU clock - * is suspended -- processing power is just 0.39% of what it used to be, - * though. 781.25 kHz(!) for a 200 MHz processor -- wow. */ -static int max_duration = 255; -module_param(max_duration, int, 0444); - -/* For the default policy, we want at least some processing power - * - let's say 5%. (min = maxfreq / POLICY_MIN_DIV) - */ -#define POLICY_MIN_DIV 20 - - -/** - * we can detect a core multipiler from dir0_lsb - * from GX1 datasheet p.56, - * MULT[3:0]: - * 0000 = SYSCLK multiplied by 4 (test only) - * 0001 = SYSCLK multiplied by 10 - * 0010 = SYSCLK multiplied by 4 - * 0011 = SYSCLK multiplied by 6 - * 0100 = SYSCLK multiplied by 9 - * 0101 = SYSCLK multiplied by 5 - * 0110 = SYSCLK multiplied by 7 - * 0111 = SYSCLK multiplied by 8 - * of 33.3MHz - **/ -static int gx_freq_mult[16] = { - 4, 10, 4, 6, 9, 5, 7, 8, - 0, 0, 0, 0, 0, 0, 0, 0 -}; - - -/**************************************************************** - * Low Level chipset interface * - ****************************************************************/ -static struct pci_device_id gx_chipset_tbl[] __initdata = { - { PCI_VDEVICE(CYRIX, PCI_DEVICE_ID_CYRIX_5530_LEGACY), }, - { PCI_VDEVICE(CYRIX, PCI_DEVICE_ID_CYRIX_5520), }, - { PCI_VDEVICE(CYRIX, PCI_DEVICE_ID_CYRIX_5510), }, - { 0, }, -}; - -static void gx_write_byte(int reg, int value) -{ - pci_write_config_byte(gx_params->cs55x0, reg, value); -} - -/** - * gx_detect_chipset: - * - **/ -static __init struct pci_dev *gx_detect_chipset(void) -{ - struct pci_dev *gx_pci = NULL; - - /* check if CPU is a MediaGX or a Geode. */ - if ((boot_cpu_data.x86_vendor != X86_VENDOR_NSC) && - (boot_cpu_data.x86_vendor != X86_VENDOR_CYRIX)) { - pr_debug("error: no MediaGX/Geode processor found!\n"); - return NULL; - } - - /* detect which companion chip is used */ - for_each_pci_dev(gx_pci) { - if ((pci_match_id(gx_chipset_tbl, gx_pci)) != NULL) - return gx_pci; - } - - pr_debug("error: no supported chipset found!\n"); - return NULL; -} - -/** - * gx_get_cpuspeed: - * - * Finds out at which efficient frequency the Cyrix MediaGX/NatSemi - * Geode CPU runs. - */ -static unsigned int gx_get_cpuspeed(unsigned int cpu) -{ - if ((gx_params->pci_suscfg & SUSMOD) == 0) - return stock_freq; - - return (stock_freq * gx_params->off_duration) - / (gx_params->on_duration + gx_params->off_duration); -} - -/** - * gx_validate_speed: - * determine current cpu speed - * - **/ - -static unsigned int gx_validate_speed(unsigned int khz, u8 *on_duration, - u8 *off_duration) -{ - unsigned int i; - u8 tmp_on, tmp_off; - int old_tmp_freq = stock_freq; - int tmp_freq; - - *off_duration = 1; - *on_duration = 0; - - for (i = max_duration; i > 0; i--) { - tmp_off = ((khz * i) / stock_freq) & 0xff; - tmp_on = i - tmp_off; - tmp_freq = (stock_freq * tmp_off) / i; - /* if this relation is closer to khz, use this. If it's equal, - * prefer it, too - lower latency */ - if (abs(tmp_freq - khz) <= abs(old_tmp_freq - khz)) { - *on_duration = tmp_on; - *off_duration = tmp_off; - old_tmp_freq = tmp_freq; - } - } - - return old_tmp_freq; -} - - -/** - * gx_set_cpuspeed: - * set cpu speed in khz. - **/ - -static void gx_set_cpuspeed(unsigned int khz) -{ - u8 suscfg, pmer1; - unsigned int new_khz; - unsigned long flags; - struct cpufreq_freqs freqs; - - freqs.cpu = 0; - freqs.old = gx_get_cpuspeed(0); - - new_khz = gx_validate_speed(khz, &gx_params->on_duration, - &gx_params->off_duration); - - freqs.new = new_khz; - - cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE); - local_irq_save(flags); - - - - if (new_khz != stock_freq) { - /* if new khz == 100% of CPU speed, it is special case */ - switch (gx_params->cs55x0->device) { - case PCI_DEVICE_ID_CYRIX_5530_LEGACY: - pmer1 = gx_params->pci_pmer1 | IRQ_SPDUP | VID_SPDUP; - /* FIXME: need to test other values -- Zwane,Miura */ - /* typical 2 to 4ms */ - gx_write_byte(PCI_IRQTC, 4); - /* typical 50 to 100ms */ - gx_write_byte(PCI_VIDTC, 100); - gx_write_byte(PCI_PMER1, pmer1); - - if (gx_params->cs55x0->revision < 0x10) { - /* CS5530(rev 1.2, 1.3) */ - suscfg = gx_params->pci_suscfg|SUSMOD; - } else { - /* CS5530A,B.. */ - suscfg = gx_params->pci_suscfg|SUSMOD|PWRSVE; - } - break; - case PCI_DEVICE_ID_CYRIX_5520: - case PCI_DEVICE_ID_CYRIX_5510: - suscfg = gx_params->pci_suscfg | SUSMOD; - break; - default: - local_irq_restore(flags); - pr_debug("fatal: try to set unknown chipset.\n"); - return; - } - } else { - suscfg = gx_params->pci_suscfg & ~(SUSMOD); - gx_params->off_duration = 0; - gx_params->on_duration = 0; - pr_debug("suspend modulation disabled: cpu runs 100%% speed.\n"); - } - - gx_write_byte(PCI_MODOFF, gx_params->off_duration); - gx_write_byte(PCI_MODON, gx_params->on_duration); - - gx_write_byte(PCI_SUSCFG, suscfg); - pci_read_config_byte(gx_params->cs55x0, PCI_SUSCFG, &suscfg); - - local_irq_restore(flags); - - gx_params->pci_suscfg = suscfg; - - cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE); - - pr_debug("suspend modulation w/ duration of ON:%d us, OFF:%d us\n", - gx_params->on_duration * 32, gx_params->off_duration * 32); - pr_debug("suspend modulation w/ clock speed: %d kHz.\n", freqs.new); -} - -/**************************************************************** - * High level functions * - ****************************************************************/ - -/* - * cpufreq_gx_verify: test if frequency range is valid - * - * This function checks if a given frequency range in kHz is valid - * for the hardware supported by the driver. - */ - -static int cpufreq_gx_verify(struct cpufreq_policy *policy) -{ - unsigned int tmp_freq = 0; - u8 tmp1, tmp2; - - if (!stock_freq || !policy) - return -EINVAL; - - policy->cpu = 0; - cpufreq_verify_within_limits(policy, (stock_freq / max_duration), - stock_freq); - - /* it needs to be assured that at least one supported frequency is - * within policy->min and policy->max. If it is not, policy->max - * needs to be increased until one freuqency is supported. - * policy->min may not be decreased, though. This way we guarantee a - * specific processing capacity. - */ - tmp_freq = gx_validate_speed(policy->min, &tmp1, &tmp2); - if (tmp_freq < policy->min) - tmp_freq += stock_freq / max_duration; - policy->min = tmp_freq; - if (policy->min > policy->max) - policy->max = tmp_freq; - tmp_freq = gx_validate_speed(policy->max, &tmp1, &tmp2); - if (tmp_freq > policy->max) - tmp_freq -= stock_freq / max_duration; - policy->max = tmp_freq; - if (policy->max < policy->min) - policy->max = policy->min; - cpufreq_verify_within_limits(policy, (stock_freq / max_duration), - stock_freq); - - return 0; -} - -/* - * cpufreq_gx_target: - * - */ -static int cpufreq_gx_target(struct cpufreq_policy *policy, - unsigned int target_freq, - unsigned int relation) -{ - u8 tmp1, tmp2; - unsigned int tmp_freq; - - if (!stock_freq || !policy) - return -EINVAL; - - policy->cpu = 0; - - tmp_freq = gx_validate_speed(target_freq, &tmp1, &tmp2); - while (tmp_freq < policy->min) { - tmp_freq += stock_freq / max_duration; - tmp_freq = gx_validate_speed(tmp_freq, &tmp1, &tmp2); - } - while (tmp_freq > policy->max) { - tmp_freq -= stock_freq / max_duration; - tmp_freq = gx_validate_speed(tmp_freq, &tmp1, &tmp2); - } - - gx_set_cpuspeed(tmp_freq); - - return 0; -} - -static int cpufreq_gx_cpu_init(struct cpufreq_policy *policy) -{ - unsigned int maxfreq, curfreq; - - if (!policy || policy->cpu != 0) - return -ENODEV; - - /* determine maximum frequency */ - if (pci_busclk) - maxfreq = pci_busclk * gx_freq_mult[getCx86(CX86_DIR1) & 0x0f]; - else if (cpu_khz) - maxfreq = cpu_khz; - else - maxfreq = 30000 * gx_freq_mult[getCx86(CX86_DIR1) & 0x0f]; - - stock_freq = maxfreq; - curfreq = gx_get_cpuspeed(0); - - pr_debug("cpu max frequency is %d.\n", maxfreq); - pr_debug("cpu current frequency is %dkHz.\n", curfreq); - - /* setup basic struct for cpufreq API */ - policy->cpu = 0; - - if (max_duration < POLICY_MIN_DIV) - policy->min = maxfreq / max_duration; - else - policy->min = maxfreq / POLICY_MIN_DIV; - policy->max = maxfreq; - policy->cur = curfreq; - policy->cpuinfo.min_freq = maxfreq / max_duration; - policy->cpuinfo.max_freq = maxfreq; - policy->cpuinfo.transition_latency = CPUFREQ_ETERNAL; - - return 0; -} - -/* - * cpufreq_gx_init: - * MediaGX/Geode GX initialize cpufreq driver - */ -static struct cpufreq_driver gx_suspmod_driver = { - .get = gx_get_cpuspeed, - .verify = cpufreq_gx_verify, - .target = cpufreq_gx_target, - .init = cpufreq_gx_cpu_init, - .name = "gx-suspmod", - .owner = THIS_MODULE, -}; - -static int __init cpufreq_gx_init(void) -{ - int ret; - struct gxfreq_params *params; - struct pci_dev *gx_pci; - - /* Test if we have the right hardware */ - gx_pci = gx_detect_chipset(); - if (gx_pci == NULL) - return -ENODEV; - - /* check whether module parameters are sane */ - if (max_duration > 0xff) - max_duration = 0xff; - - pr_debug("geode suspend modulation available.\n"); - - params = kzalloc(sizeof(struct gxfreq_params), GFP_KERNEL); - if (params == NULL) - return -ENOMEM; - - params->cs55x0 = gx_pci; - gx_params = params; - - /* keep cs55x0 configurations */ - pci_read_config_byte(params->cs55x0, PCI_SUSCFG, &(params->pci_suscfg)); - pci_read_config_byte(params->cs55x0, PCI_PMER1, &(params->pci_pmer1)); - pci_read_config_byte(params->cs55x0, PCI_PMER2, &(params->pci_pmer2)); - pci_read_config_byte(params->cs55x0, PCI_MODON, &(params->on_duration)); - pci_read_config_byte(params->cs55x0, PCI_MODOFF, - &(params->off_duration)); - - ret = cpufreq_register_driver(&gx_suspmod_driver); - if (ret) { - kfree(params); - return ret; /* register error! */ - } - - return 0; -} - -static void __exit cpufreq_gx_exit(void) -{ - cpufreq_unregister_driver(&gx_suspmod_driver); - pci_dev_put(gx_params->cs55x0); - kfree(gx_params); -} - -MODULE_AUTHOR("Hiroshi Miura "); -MODULE_DESCRIPTION("Cpufreq driver for Cyrix MediaGX and NatSemi Geode"); -MODULE_LICENSE("GPL"); - -module_init(cpufreq_gx_init); -module_exit(cpufreq_gx_exit); - diff --git a/arch/x86/kernel/cpu/cpufreq/longhaul.c b/arch/x86/kernel/cpu/cpufreq/longhaul.c deleted file mode 100644 index f47d26e..0000000 --- a/arch/x86/kernel/cpu/cpufreq/longhaul.c +++ /dev/null @@ -1,1024 +0,0 @@ -/* - * (C) 2001-2004 Dave Jones. - * (C) 2002 Padraig Brady. - * - * Licensed under the terms of the GNU GPL License version 2. - * Based upon datasheets & sample CPUs kindly provided by VIA. - * - * VIA have currently 3 different versions of Longhaul. - * Version 1 (Longhaul) uses the BCR2 MSR at 0x1147. - * It is present only in Samuel 1 (C5A), Samuel 2 (C5B) stepping 0. - * Version 2 of longhaul is backward compatible with v1, but adds - * LONGHAUL MSR for purpose of both frequency and voltage scaling. - * Present in Samuel 2 (steppings 1-7 only) (C5B), and Ezra (C5C). - * Version 3 of longhaul got renamed to Powersaver and redesigned - * to use only the POWERSAVER MSR at 0x110a. - * It is present in Ezra-T (C5M), Nehemiah (C5X) and above. - * It's pretty much the same feature wise to longhaul v2, though - * there is provision for scaling FSB too, but this doesn't work - * too well in practice so we don't even try to use this. - * - * BIG FAT DISCLAIMER: Work in progress code. Possibly *dangerous* - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include "longhaul.h" - -#define PFX "longhaul: " - -#define TYPE_LONGHAUL_V1 1 -#define TYPE_LONGHAUL_V2 2 -#define TYPE_POWERSAVER 3 - -#define CPU_SAMUEL 1 -#define CPU_SAMUEL2 2 -#define CPU_EZRA 3 -#define CPU_EZRA_T 4 -#define CPU_NEHEMIAH 5 -#define CPU_NEHEMIAH_C 6 - -/* Flags */ -#define USE_ACPI_C3 (1 << 1) -#define USE_NORTHBRIDGE (1 << 2) - -static int cpu_model; -static unsigned int numscales = 16; -static unsigned int fsb; - -static const struct mV_pos *vrm_mV_table; -static const unsigned char *mV_vrm_table; - -static unsigned int highest_speed, lowest_speed; /* kHz */ -static unsigned int minmult, maxmult; -static int can_scale_voltage; -static struct acpi_processor *pr; -static struct acpi_processor_cx *cx; -static u32 acpi_regs_addr; -static u8 longhaul_flags; -static unsigned int longhaul_index; - -/* Module parameters */ -static int scale_voltage; -static int disable_acpi_c3; -static int revid_errata; - - -/* Clock ratios multiplied by 10 */ -static int mults[32]; -static int eblcr[32]; -static int longhaul_version; -static struct cpufreq_frequency_table *longhaul_table; - -static char speedbuffer[8]; - -static char *print_speed(int speed) -{ - if (speed < 1000) { - snprintf(speedbuffer, sizeof(speedbuffer), "%dMHz", speed); - return speedbuffer; - } - - if (speed%1000 == 0) - snprintf(speedbuffer, sizeof(speedbuffer), - "%dGHz", speed/1000); - else - snprintf(speedbuffer, sizeof(speedbuffer), - "%d.%dGHz", speed/1000, (speed%1000)/100); - - return speedbuffer; -} - - -static unsigned int calc_speed(int mult) -{ - int khz; - khz = (mult/10)*fsb; - if (mult%10) - khz += fsb/2; - khz *= 1000; - return khz; -} - - -static int longhaul_get_cpu_mult(void) -{ - unsigned long invalue = 0, lo, hi; - - rdmsr(MSR_IA32_EBL_CR_POWERON, lo, hi); - invalue = (lo & (1<<22|1<<23|1<<24|1<<25))>>22; - if (longhaul_version == TYPE_LONGHAUL_V2 || - longhaul_version == TYPE_POWERSAVER) { - if (lo & (1<<27)) - invalue += 16; - } - return eblcr[invalue]; -} - -/* For processor with BCR2 MSR */ - -static void do_longhaul1(unsigned int mults_index) -{ - union msr_bcr2 bcr2; - - rdmsrl(MSR_VIA_BCR2, bcr2.val); - /* Enable software clock multiplier */ - bcr2.bits.ESOFTBF = 1; - bcr2.bits.CLOCKMUL = mults_index & 0xff; - - /* Sync to timer tick */ - safe_halt(); - /* Change frequency on next halt or sleep */ - wrmsrl(MSR_VIA_BCR2, bcr2.val); - /* Invoke transition */ - ACPI_FLUSH_CPU_CACHE(); - halt(); - - /* Disable software clock multiplier */ - local_irq_disable(); - rdmsrl(MSR_VIA_BCR2, bcr2.val); - bcr2.bits.ESOFTBF = 0; - wrmsrl(MSR_VIA_BCR2, bcr2.val); -} - -/* For processor with Longhaul MSR */ - -static void do_powersaver(int cx_address, unsigned int mults_index, - unsigned int dir) -{ - union msr_longhaul longhaul; - u32 t; - - rdmsrl(MSR_VIA_LONGHAUL, longhaul.val); - /* Setup new frequency */ - if (!revid_errata) - longhaul.bits.RevisionKey = longhaul.bits.RevisionID; - else - longhaul.bits.RevisionKey = 0; - longhaul.bits.SoftBusRatio = mults_index & 0xf; - longhaul.bits.SoftBusRatio4 = (mults_index & 0x10) >> 4; - /* Setup new voltage */ - if (can_scale_voltage) - longhaul.bits.SoftVID = (mults_index >> 8) & 0x1f; - /* Sync to timer tick */ - safe_halt(); - /* Raise voltage if necessary */ - if (can_scale_voltage && dir) { - longhaul.bits.EnableSoftVID = 1; - wrmsrl(MSR_VIA_LONGHAUL, longhaul.val); - /* Change voltage */ - if (!cx_address) { - ACPI_FLUSH_CPU_CACHE(); - halt(); - } else { - ACPI_FLUSH_CPU_CACHE(); - /* Invoke C3 */ - inb(cx_address); - /* Dummy op - must do something useless after P_LVL3 - * read */ - t = inl(acpi_gbl_FADT.xpm_timer_block.address); - } - longhaul.bits.EnableSoftVID = 0; - wrmsrl(MSR_VIA_LONGHAUL, longhaul.val); - } - - /* Change frequency on next halt or sleep */ - longhaul.bits.EnableSoftBusRatio = 1; - wrmsrl(MSR_VIA_LONGHAUL, longhaul.val); - if (!cx_address) { - ACPI_FLUSH_CPU_CACHE(); - halt(); - } else { - ACPI_FLUSH_CPU_CACHE(); - /* Invoke C3 */ - inb(cx_address); - /* Dummy op - must do something useless after P_LVL3 read */ - t = inl(acpi_gbl_FADT.xpm_timer_block.address); - } - /* Disable bus ratio bit */ - longhaul.bits.EnableSoftBusRatio = 0; - wrmsrl(MSR_VIA_LONGHAUL, longhaul.val); - - /* Reduce voltage if necessary */ - if (can_scale_voltage && !dir) { - longhaul.bits.EnableSoftVID = 1; - wrmsrl(MSR_VIA_LONGHAUL, longhaul.val); - /* Change voltage */ - if (!cx_address) { - ACPI_FLUSH_CPU_CACHE(); - halt(); - } else { - ACPI_FLUSH_CPU_CACHE(); - /* Invoke C3 */ - inb(cx_address); - /* Dummy op - must do something useless after P_LVL3 - * read */ - t = inl(acpi_gbl_FADT.xpm_timer_block.address); - } - longhaul.bits.EnableSoftVID = 0; - wrmsrl(MSR_VIA_LONGHAUL, longhaul.val); - } -} - -/** - * longhaul_set_cpu_frequency() - * @mults_index : bitpattern of the new multiplier. - * - * Sets a new clock ratio. - */ - -static void longhaul_setstate(unsigned int table_index) -{ - unsigned int mults_index; - int speed, mult; - struct cpufreq_freqs freqs; - unsigned long flags; - unsigned int pic1_mask, pic2_mask; - u16 bm_status = 0; - u32 bm_timeout = 1000; - unsigned int dir = 0; - - mults_index = longhaul_table[table_index].index; - /* Safety precautions */ - mult = mults[mults_index & 0x1f]; - if (mult == -1) - return; - speed = calc_speed(mult); - if ((speed > highest_speed) || (speed < lowest_speed)) - return; - /* Voltage transition before frequency transition? */ - if (can_scale_voltage && longhaul_index < table_index) - dir = 1; - - freqs.old = calc_speed(longhaul_get_cpu_mult()); - freqs.new = speed; - freqs.cpu = 0; /* longhaul.c is UP only driver */ - - cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE); - - pr_debug("Setting to FSB:%dMHz Mult:%d.%dx (%s)\n", - fsb, mult/10, mult%10, print_speed(speed/1000)); -retry_loop: - preempt_disable(); - local_irq_save(flags); - - pic2_mask = inb(0xA1); - pic1_mask = inb(0x21); /* works on C3. save mask. */ - outb(0xFF, 0xA1); /* Overkill */ - outb(0xFE, 0x21); /* TMR0 only */ - - /* Wait while PCI bus is busy. */ - if (acpi_regs_addr && (longhaul_flags & USE_NORTHBRIDGE - || ((pr != NULL) && pr->flags.bm_control))) { - bm_status = inw(acpi_regs_addr); - bm_status &= 1 << 4; - while (bm_status && bm_timeout) { - outw(1 << 4, acpi_regs_addr); - bm_timeout--; - bm_status = inw(acpi_regs_addr); - bm_status &= 1 << 4; - } - } - - if (longhaul_flags & USE_NORTHBRIDGE) { - /* Disable AGP and PCI arbiters */ - outb(3, 0x22); - } else if ((pr != NULL) && pr->flags.bm_control) { - /* Disable bus master arbitration */ - acpi_write_bit_register(ACPI_BITREG_ARB_DISABLE, 1); - } - switch (longhaul_version) { - - /* - * Longhaul v1. (Samuel[C5A] and Samuel2 stepping 0[C5B]) - * Software controlled multipliers only. - */ - case TYPE_LONGHAUL_V1: - do_longhaul1(mults_index); - break; - - /* - * Longhaul v2 appears in Samuel2 Steppings 1->7 [C5B] and Ezra [C5C] - * - * Longhaul v3 (aka Powersaver). (Ezra-T [C5M] & Nehemiah [C5N]) - * Nehemiah can do FSB scaling too, but this has never been proven - * to work in practice. - */ - case TYPE_LONGHAUL_V2: - case TYPE_POWERSAVER: - if (longhaul_flags & USE_ACPI_C3) { - /* Don't allow wakeup */ - acpi_write_bit_register(ACPI_BITREG_BUS_MASTER_RLD, 0); - do_powersaver(cx->address, mults_index, dir); - } else { - do_powersaver(0, mults_index, dir); - } - break; - } - - if (longhaul_flags & USE_NORTHBRIDGE) { - /* Enable arbiters */ - outb(0, 0x22); - } else if ((pr != NULL) && pr->flags.bm_control) { - /* Enable bus master arbitration */ - acpi_write_bit_register(ACPI_BITREG_ARB_DISABLE, 0); - } - outb(pic2_mask, 0xA1); /* restore mask */ - outb(pic1_mask, 0x21); - - local_irq_restore(flags); - preempt_enable(); - - freqs.new = calc_speed(longhaul_get_cpu_mult()); - /* Check if requested frequency is set. */ - if (unlikely(freqs.new != speed)) { - printk(KERN_INFO PFX "Failed to set requested frequency!\n"); - /* Revision ID = 1 but processor is expecting revision key - * equal to 0. Jumpers at the bottom of processor will change - * multiplier and FSB, but will not change bits in Longhaul - * MSR nor enable voltage scaling. */ - if (!revid_errata) { - printk(KERN_INFO PFX "Enabling \"Ignore Revision ID\" " - "option.\n"); - revid_errata = 1; - msleep(200); - goto retry_loop; - } - /* Why ACPI C3 sometimes doesn't work is a mystery for me. - * But it does happen. Processor is entering ACPI C3 state, - * but it doesn't change frequency. I tried poking various - * bits in northbridge registers, but without success. */ - if (longhaul_flags & USE_ACPI_C3) { - printk(KERN_INFO PFX "Disabling ACPI C3 support.\n"); - longhaul_flags &= ~USE_ACPI_C3; - if (revid_errata) { - printk(KERN_INFO PFX "Disabling \"Ignore " - "Revision ID\" option.\n"); - revid_errata = 0; - } - msleep(200); - goto retry_loop; - } - /* This shouldn't happen. Longhaul ver. 2 was reported not - * working on processors without voltage scaling, but with - * RevID = 1. RevID errata will make things right. Just - * to be 100% sure. */ - if (longhaul_version == TYPE_LONGHAUL_V2) { - printk(KERN_INFO PFX "Switching to Longhaul ver. 1\n"); - longhaul_version = TYPE_LONGHAUL_V1; - msleep(200); - goto retry_loop; - } - } - /* Report true CPU frequency */ - cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE); - - if (!bm_timeout) - printk(KERN_INFO PFX "Warning: Timeout while waiting for " - "idle PCI bus.\n"); -} - -/* - * Centaur decided to make life a little more tricky. - * Only longhaul v1 is allowed to read EBLCR BSEL[0:1]. - * Samuel2 and above have to try and guess what the FSB is. - * We do this by assuming we booted at maximum multiplier, and interpolate - * between that value multiplied by possible FSBs and cpu_mhz which - * was calculated at boot time. Really ugly, but no other way to do this. - */ - -#define ROUNDING 0xf - -static int guess_fsb(int mult) -{ - int speed = cpu_khz / 1000; - int i; - int speeds[] = { 666, 1000, 1333, 2000 }; - int f_max, f_min; - - for (i = 0; i < 4; i++) { - f_max = ((speeds[i] * mult) + 50) / 100; - f_max += (ROUNDING / 2); - f_min = f_max - ROUNDING; - if ((speed <= f_max) && (speed >= f_min)) - return speeds[i] / 10; - } - return 0; -} - - -static int __cpuinit longhaul_get_ranges(void) -{ - unsigned int i, j, k = 0; - unsigned int ratio; - int mult; - - /* Get current frequency */ - mult = longhaul_get_cpu_mult(); - if (mult == -1) { - printk(KERN_INFO PFX "Invalid (reserved) multiplier!\n"); - return -EINVAL; - } - fsb = guess_fsb(mult); - if (fsb == 0) { - printk(KERN_INFO PFX "Invalid (reserved) FSB!\n"); - return -EINVAL; - } - /* Get max multiplier - as we always did. - * Longhaul MSR is useful only when voltage scaling is enabled. - * C3 is booting at max anyway. */ - maxmult = mult; - /* Get min multiplier */ - switch (cpu_model) { - case CPU_NEHEMIAH: - minmult = 50; - break; - case CPU_NEHEMIAH_C: - minmult = 40; - break; - default: - minmult = 30; - break; - } - - pr_debug("MinMult:%d.%dx MaxMult:%d.%dx\n", - minmult/10, minmult%10, maxmult/10, maxmult%10); - - highest_speed = calc_speed(maxmult); - lowest_speed = calc_speed(minmult); - pr_debug("FSB:%dMHz Lowest speed: %s Highest speed:%s\n", fsb, - print_speed(lowest_speed/1000), - print_speed(highest_speed/1000)); - - if (lowest_speed == highest_speed) { - printk(KERN_INFO PFX "highestspeed == lowest, aborting.\n"); - return -EINVAL; - } - if (lowest_speed > highest_speed) { - printk(KERN_INFO PFX "nonsense! lowest (%d > %d) !\n", - lowest_speed, highest_speed); - return -EINVAL; - } - - longhaul_table = kmalloc((numscales + 1) * sizeof(*longhaul_table), - GFP_KERNEL); - if (!longhaul_table) - return -ENOMEM; - - for (j = 0; j < numscales; j++) { - ratio = mults[j]; - if (ratio == -1) - continue; - if (ratio > maxmult || ratio < minmult) - continue; - longhaul_table[k].frequency = calc_speed(ratio); - longhaul_table[k].index = j; - k++; - } - if (k <= 1) { - kfree(longhaul_table); - return -ENODEV; - } - /* Sort */ - for (j = 0; j < k - 1; j++) { - unsigned int min_f, min_i; - min_f = longhaul_table[j].frequency; - min_i = j; - for (i = j + 1; i < k; i++) { - if (longhaul_table[i].frequency < min_f) { - min_f = longhaul_table[i].frequency; - min_i = i; - } - } - if (min_i != j) { - swap(longhaul_table[j].frequency, - longhaul_table[min_i].frequency); - swap(longhaul_table[j].index, - longhaul_table[min_i].index); - } - } - - longhaul_table[k].frequency = CPUFREQ_TABLE_END; - - /* Find index we are running on */ - for (j = 0; j < k; j++) { - if (mults[longhaul_table[j].index & 0x1f] == mult) { - longhaul_index = j; - break; - } - } - return 0; -} - - -static void __cpuinit longhaul_setup_voltagescaling(void) -{ - union msr_longhaul longhaul; - struct mV_pos minvid, maxvid, vid; - unsigned int j, speed, pos, kHz_step, numvscales; - int min_vid_speed; - - rdmsrl(MSR_VIA_LONGHAUL, longhaul.val); - if (!(longhaul.bits.RevisionID & 1)) { - printk(KERN_INFO PFX "Voltage scaling not supported by CPU.\n"); - return; - } - - if (!longhaul.bits.VRMRev) { - printk(KERN_INFO PFX "VRM 8.5\n"); - vrm_mV_table = &vrm85_mV[0]; - mV_vrm_table = &mV_vrm85[0]; - } else { - printk(KERN_INFO PFX "Mobile VRM\n"); - if (cpu_model < CPU_NEHEMIAH) - return; - vrm_mV_table = &mobilevrm_mV[0]; - mV_vrm_table = &mV_mobilevrm[0]; - } - - minvid = vrm_mV_table[longhaul.bits.MinimumVID]; - maxvid = vrm_mV_table[longhaul.bits.MaximumVID]; - - if (minvid.mV == 0 || maxvid.mV == 0 || minvid.mV > maxvid.mV) { - printk(KERN_INFO PFX "Bogus values Min:%d.%03d Max:%d.%03d. " - "Voltage scaling disabled.\n", - minvid.mV/1000, minvid.mV%1000, - maxvid.mV/1000, maxvid.mV%1000); - return; - } - - if (minvid.mV == maxvid.mV) { - printk(KERN_INFO PFX "Claims to support voltage scaling but " - "min & max are both %d.%03d. " - "Voltage scaling disabled\n", - maxvid.mV/1000, maxvid.mV%1000); - return; - } - - /* How many voltage steps*/ - numvscales = maxvid.pos - minvid.pos + 1; - printk(KERN_INFO PFX - "Max VID=%d.%03d " - "Min VID=%d.%03d, " - "%d possible voltage scales\n", - maxvid.mV/1000, maxvid.mV%1000, - minvid.mV/1000, minvid.mV%1000, - numvscales); - - /* Calculate max frequency at min voltage */ - j = longhaul.bits.MinMHzBR; - if (longhaul.bits.MinMHzBR4) - j += 16; - min_vid_speed = eblcr[j]; - if (min_vid_speed == -1) - return; - switch (longhaul.bits.MinMHzFSB) { - case 0: - min_vid_speed *= 13333; - break; - case 1: - min_vid_speed *= 10000; - break; - case 3: - min_vid_speed *= 6666; - break; - default: - return; - break; - } - if (min_vid_speed >= highest_speed) - return; - /* Calculate kHz for one voltage step */ - kHz_step = (highest_speed - min_vid_speed) / numvscales; - - j = 0; - while (longhaul_table[j].frequency != CPUFREQ_TABLE_END) { - speed = longhaul_table[j].frequency; - if (speed > min_vid_speed) - pos = (speed - min_vid_speed) / kHz_step + minvid.pos; - else - pos = minvid.pos; - longhaul_table[j].index |= mV_vrm_table[pos] << 8; - vid = vrm_mV_table[mV_vrm_table[pos]]; - printk(KERN_INFO PFX "f: %d kHz, index: %d, vid: %d mV\n", - speed, j, vid.mV); - j++; - } - - can_scale_voltage = 1; - printk(KERN_INFO PFX "Voltage scaling enabled.\n"); -} - - -static int longhaul_verify(struct cpufreq_policy *policy) -{ - return cpufreq_frequency_table_verify(policy, longhaul_table); -} - - -static int longhaul_target(struct cpufreq_policy *policy, - unsigned int target_freq, unsigned int relation) -{ - unsigned int table_index = 0; - unsigned int i; - unsigned int dir = 0; - u8 vid, current_vid; - - if (cpufreq_frequency_table_target(policy, longhaul_table, target_freq, - relation, &table_index)) - return -EINVAL; - - /* Don't set same frequency again */ - if (longhaul_index == table_index) - return 0; - - if (!can_scale_voltage) - longhaul_setstate(table_index); - else { - /* On test system voltage transitions exceeding single - * step up or down were turning motherboard off. Both - * "ondemand" and "userspace" are unsafe. C7 is doing - * this in hardware, C3 is old and we need to do this - * in software. */ - i = longhaul_index; - current_vid = (longhaul_table[longhaul_index].index >> 8); - current_vid &= 0x1f; - if (table_index > longhaul_index) - dir = 1; - while (i != table_index) { - vid = (longhaul_table[i].index >> 8) & 0x1f; - if (vid != current_vid) { - longhaul_setstate(i); - current_vid = vid; - msleep(200); - } - if (dir) - i++; - else - i--; - } - longhaul_setstate(table_index); - } - longhaul_index = table_index; - return 0; -} - - -static unsigned int longhaul_get(unsigned int cpu) -{ - if (cpu) - return 0; - return calc_speed(longhaul_get_cpu_mult()); -} - -static acpi_status longhaul_walk_callback(acpi_handle obj_handle, - u32 nesting_level, - void *context, void **return_value) -{ - struct acpi_device *d; - - if (acpi_bus_get_device(obj_handle, &d)) - return 0; - - *return_value = acpi_driver_data(d); - return 1; -} - -/* VIA don't support PM2 reg, but have something similar */ -static int enable_arbiter_disable(void) -{ - struct pci_dev *dev; - int status = 1; - int reg; - u8 pci_cmd; - - /* Find PLE133 host bridge */ - reg = 0x78; - dev = pci_get_device(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8601_0, - NULL); - /* Find PM133/VT8605 host bridge */ - if (dev == NULL) - dev = pci_get_device(PCI_VENDOR_ID_VIA, - PCI_DEVICE_ID_VIA_8605_0, NULL); - /* Find CLE266 host bridge */ - if (dev == NULL) { - reg = 0x76; - dev = pci_get_device(PCI_VENDOR_ID_VIA, - PCI_DEVICE_ID_VIA_862X_0, NULL); - /* Find CN400 V-Link host bridge */ - if (dev == NULL) - dev = pci_get_device(PCI_VENDOR_ID_VIA, 0x7259, NULL); - } - if (dev != NULL) { - /* Enable access to port 0x22 */ - pci_read_config_byte(dev, reg, &pci_cmd); - if (!(pci_cmd & 1<<7)) { - pci_cmd |= 1<<7; - pci_write_config_byte(dev, reg, pci_cmd); - pci_read_config_byte(dev, reg, &pci_cmd); - if (!(pci_cmd & 1<<7)) { - printk(KERN_ERR PFX - "Can't enable access to port 0x22.\n"); - status = 0; - } - } - pci_dev_put(dev); - return status; - } - return 0; -} - -static int longhaul_setup_southbridge(void) -{ - struct pci_dev *dev; - u8 pci_cmd; - - /* Find VT8235 southbridge */ - dev = pci_get_device(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8235, NULL); - if (dev == NULL) - /* Find VT8237 southbridge */ - dev = pci_get_device(PCI_VENDOR_ID_VIA, - PCI_DEVICE_ID_VIA_8237, NULL); - if (dev != NULL) { - /* Set transition time to max */ - pci_read_config_byte(dev, 0xec, &pci_cmd); - pci_cmd &= ~(1 << 2); - pci_write_config_byte(dev, 0xec, pci_cmd); - pci_read_config_byte(dev, 0xe4, &pci_cmd); - pci_cmd &= ~(1 << 7); - pci_write_config_byte(dev, 0xe4, pci_cmd); - pci_read_config_byte(dev, 0xe5, &pci_cmd); - pci_cmd |= 1 << 7; - pci_write_config_byte(dev, 0xe5, pci_cmd); - /* Get address of ACPI registers block*/ - pci_read_config_byte(dev, 0x81, &pci_cmd); - if (pci_cmd & 1 << 7) { - pci_read_config_dword(dev, 0x88, &acpi_regs_addr); - acpi_regs_addr &= 0xff00; - printk(KERN_INFO PFX "ACPI I/O at 0x%x\n", - acpi_regs_addr); - } - - pci_dev_put(dev); - return 1; - } - return 0; -} - -static int __cpuinit longhaul_cpu_init(struct cpufreq_policy *policy) -{ - struct cpuinfo_x86 *c = &cpu_data(0); - char *cpuname = NULL; - int ret; - u32 lo, hi; - - /* Check what we have on this motherboard */ - switch (c->x86_model) { - case 6: - cpu_model = CPU_SAMUEL; - cpuname = "C3 'Samuel' [C5A]"; - longhaul_version = TYPE_LONGHAUL_V1; - memcpy(mults, samuel1_mults, sizeof(samuel1_mults)); - memcpy(eblcr, samuel1_eblcr, sizeof(samuel1_eblcr)); - break; - - case 7: - switch (c->x86_mask) { - case 0: - longhaul_version = TYPE_LONGHAUL_V1; - cpu_model = CPU_SAMUEL2; - cpuname = "C3 'Samuel 2' [C5B]"; - /* Note, this is not a typo, early Samuel2's had - * Samuel1 ratios. */ - memcpy(mults, samuel1_mults, sizeof(samuel1_mults)); - memcpy(eblcr, samuel2_eblcr, sizeof(samuel2_eblcr)); - break; - case 1 ... 15: - longhaul_version = TYPE_LONGHAUL_V2; - if (c->x86_mask < 8) { - cpu_model = CPU_SAMUEL2; - cpuname = "C3 'Samuel 2' [C5B]"; - } else { - cpu_model = CPU_EZRA; - cpuname = "C3 'Ezra' [C5C]"; - } - memcpy(mults, ezra_mults, sizeof(ezra_mults)); - memcpy(eblcr, ezra_eblcr, sizeof(ezra_eblcr)); - break; - } - break; - - case 8: - cpu_model = CPU_EZRA_T; - cpuname = "C3 'Ezra-T' [C5M]"; - longhaul_version = TYPE_POWERSAVER; - numscales = 32; - memcpy(mults, ezrat_mults, sizeof(ezrat_mults)); - memcpy(eblcr, ezrat_eblcr, sizeof(ezrat_eblcr)); - break; - - case 9: - longhaul_version = TYPE_POWERSAVER; - numscales = 32; - memcpy(mults, nehemiah_mults, sizeof(nehemiah_mults)); - memcpy(eblcr, nehemiah_eblcr, sizeof(nehemiah_eblcr)); - switch (c->x86_mask) { - case 0 ... 1: - cpu_model = CPU_NEHEMIAH; - cpuname = "C3 'Nehemiah A' [C5XLOE]"; - break; - case 2 ... 4: - cpu_model = CPU_NEHEMIAH; - cpuname = "C3 'Nehemiah B' [C5XLOH]"; - break; - case 5 ... 15: - cpu_model = CPU_NEHEMIAH_C; - cpuname = "C3 'Nehemiah C' [C5P]"; - break; - } - break; - - default: - cpuname = "Unknown"; - break; - } - /* Check Longhaul ver. 2 */ - if (longhaul_version == TYPE_LONGHAUL_V2) { - rdmsr(MSR_VIA_LONGHAUL, lo, hi); - if (lo == 0 && hi == 0) - /* Looks like MSR isn't present */ - longhaul_version = TYPE_LONGHAUL_V1; - } - - printk(KERN_INFO PFX "VIA %s CPU detected. ", cpuname); - switch (longhaul_version) { - case TYPE_LONGHAUL_V1: - case TYPE_LONGHAUL_V2: - printk(KERN_CONT "Longhaul v%d supported.\n", longhaul_version); - break; - case TYPE_POWERSAVER: - printk(KERN_CONT "Powersaver supported.\n"); - break; - }; - - /* Doesn't hurt */ - longhaul_setup_southbridge(); - - /* Find ACPI data for processor */ - acpi_walk_namespace(ACPI_TYPE_PROCESSOR, ACPI_ROOT_OBJECT, - ACPI_UINT32_MAX, &longhaul_walk_callback, NULL, - NULL, (void *)&pr); - - /* Check ACPI support for C3 state */ - if (pr != NULL && longhaul_version == TYPE_POWERSAVER) { - cx = &pr->power.states[ACPI_STATE_C3]; - if (cx->address > 0 && cx->latency <= 1000) - longhaul_flags |= USE_ACPI_C3; - } - /* Disable if it isn't working */ - if (disable_acpi_c3) - longhaul_flags &= ~USE_ACPI_C3; - /* Check if northbridge is friendly */ - if (enable_arbiter_disable()) - longhaul_flags |= USE_NORTHBRIDGE; - - /* Check ACPI support for bus master arbiter disable */ - if (!(longhaul_flags & USE_ACPI_C3 - || longhaul_flags & USE_NORTHBRIDGE) - && ((pr == NULL) || !(pr->flags.bm_control))) { - printk(KERN_ERR PFX - "No ACPI support. Unsupported northbridge.\n"); - return -ENODEV; - } - - if (longhaul_flags & USE_NORTHBRIDGE) - printk(KERN_INFO PFX "Using northbridge support.\n"); - if (longhaul_flags & USE_ACPI_C3) - printk(KERN_INFO PFX "Using ACPI support.\n"); - - ret = longhaul_get_ranges(); - if (ret != 0) - return ret; - - if ((longhaul_version != TYPE_LONGHAUL_V1) && (scale_voltage != 0)) - longhaul_setup_voltagescaling(); - - policy->cpuinfo.transition_latency = 200000; /* nsec */ - policy->cur = calc_speed(longhaul_get_cpu_mult()); - - ret = cpufreq_frequency_table_cpuinfo(policy, longhaul_table); - if (ret) - return ret; - - cpufreq_frequency_table_get_attr(longhaul_table, policy->cpu); - - return 0; -} - -static int __devexit longhaul_cpu_exit(struct cpufreq_policy *policy) -{ - cpufreq_frequency_table_put_attr(policy->cpu); - return 0; -} - -static struct freq_attr *longhaul_attr[] = { - &cpufreq_freq_attr_scaling_available_freqs, - NULL, -}; - -static struct cpufreq_driver longhaul_driver = { - .verify = longhaul_verify, - .target = longhaul_target, - .get = longhaul_get, - .init = longhaul_cpu_init, - .exit = __devexit_p(longhaul_cpu_exit), - .name = "longhaul", - .owner = THIS_MODULE, - .attr = longhaul_attr, -}; - - -static int __init longhaul_init(void) -{ - struct cpuinfo_x86 *c = &cpu_data(0); - - if (c->x86_vendor != X86_VENDOR_CENTAUR || c->x86 != 6) - return -ENODEV; - -#ifdef CONFIG_SMP - if (num_online_cpus() > 1) { - printk(KERN_ERR PFX "More than 1 CPU detected, " - "longhaul disabled.\n"); - return -ENODEV; - } -#endif -#ifdef CONFIG_X86_IO_APIC - if (cpu_has_apic) { - printk(KERN_ERR PFX "APIC detected. Longhaul is currently " - "broken in this configuration.\n"); - return -ENODEV; - } -#endif - switch (c->x86_model) { - case 6 ... 9: - return cpufreq_register_driver(&longhaul_driver); - case 10: - printk(KERN_ERR PFX "Use acpi-cpufreq driver for VIA C7\n"); - default: - ; - } - - return -ENODEV; -} - - -static void __exit longhaul_exit(void) -{ - int i; - - for (i = 0; i < numscales; i++) { - if (mults[i] == maxmult) { - longhaul_setstate(i); - break; - } - } - - cpufreq_unregister_driver(&longhaul_driver); - kfree(longhaul_table); -} - -/* Even if BIOS is exporting ACPI C3 state, and it is used - * with success when CPU is idle, this state doesn't - * trigger frequency transition in some cases. */ -module_param(disable_acpi_c3, int, 0644); -MODULE_PARM_DESC(disable_acpi_c3, "Don't use ACPI C3 support"); -/* Change CPU voltage with frequency. Very useful to save - * power, but most VIA C3 processors aren't supporting it. */ -module_param(scale_voltage, int, 0644); -MODULE_PARM_DESC(scale_voltage, "Scale voltage of processor"); -/* Force revision key to 0 for processors which doesn't - * support voltage scaling, but are introducing itself as - * such. */ -module_param(revid_errata, int, 0644); -MODULE_PARM_DESC(revid_errata, "Ignore CPU Revision ID"); - -MODULE_AUTHOR("Dave Jones "); -MODULE_DESCRIPTION("Longhaul driver for VIA Cyrix processors."); -MODULE_LICENSE("GPL"); - -late_initcall(longhaul_init); -module_exit(longhaul_exit); diff --git a/arch/x86/kernel/cpu/cpufreq/longhaul.h b/arch/x86/kernel/cpu/cpufreq/longhaul.h deleted file mode 100644 index cbf48fb..0000000 --- a/arch/x86/kernel/cpu/cpufreq/longhaul.h +++ /dev/null @@ -1,353 +0,0 @@ -/* - * longhaul.h - * (C) 2003 Dave Jones. - * - * Licensed under the terms of the GNU GPL License version 2. - * - * VIA-specific information - */ - -union msr_bcr2 { - struct { - unsigned Reseved:19, // 18:0 - ESOFTBF:1, // 19 - Reserved2:3, // 22:20 - CLOCKMUL:4, // 26:23 - Reserved3:5; // 31:27 - } bits; - unsigned long val; -}; - -union msr_longhaul { - struct { - unsigned RevisionID:4, // 3:0 - RevisionKey:4, // 7:4 - EnableSoftBusRatio:1, // 8 - EnableSoftVID:1, // 9 - EnableSoftBSEL:1, // 10 - Reserved:3, // 11:13 - SoftBusRatio4:1, // 14 - VRMRev:1, // 15 - SoftBusRatio:4, // 19:16 - SoftVID:5, // 24:20 - Reserved2:3, // 27:25 - SoftBSEL:2, // 29:28 - Reserved3:2, // 31:30 - MaxMHzBR:4, // 35:32 - MaximumVID:5, // 40:36 - MaxMHzFSB:2, // 42:41 - MaxMHzBR4:1, // 43 - Reserved4:4, // 47:44 - MinMHzBR:4, // 51:48 - MinimumVID:5, // 56:52 - MinMHzFSB:2, // 58:57 - MinMHzBR4:1, // 59 - Reserved5:4; // 63:60 - } bits; - unsigned long long val; -}; - -/* - * Clock ratio tables. Div/Mod by 10 to get ratio. - * The eblcr values specify the ratio read from the CPU. - * The mults values specify what to write to the CPU. - */ - -/* - * VIA C3 Samuel 1 & Samuel 2 (stepping 0) - */ -static const int __cpuinitdata samuel1_mults[16] = { - -1, /* 0000 -> RESERVED */ - 30, /* 0001 -> 3.0x */ - 40, /* 0010 -> 4.0x */ - -1, /* 0011 -> RESERVED */ - -1, /* 0100 -> RESERVED */ - 35, /* 0101 -> 3.5x */ - 45, /* 0110 -> 4.5x */ - 55, /* 0111 -> 5.5x */ - 60, /* 1000 -> 6.0x */ - 70, /* 1001 -> 7.0x */ - 80, /* 1010 -> 8.0x */ - 50, /* 1011 -> 5.0x */ - 65, /* 1100 -> 6.5x */ - 75, /* 1101 -> 7.5x */ - -1, /* 1110 -> RESERVED */ - -1, /* 1111 -> RESERVED */ -}; - -static const int __cpuinitdata samuel1_eblcr[16] = { - 50, /* 0000 -> RESERVED */ - 30, /* 0001 -> 3.0x */ - 40, /* 0010 -> 4.0x */ - -1, /* 0011 -> RESERVED */ - 55, /* 0100 -> 5.5x */ - 35, /* 0101 -> 3.5x */ - 45, /* 0110 -> 4.5x */ - -1, /* 0111 -> RESERVED */ - -1, /* 1000 -> RESERVED */ - 70, /* 1001 -> 7.0x */ - 80, /* 1010 -> 8.0x */ - 60, /* 1011 -> 6.0x */ - -1, /* 1100 -> RESERVED */ - 75, /* 1101 -> 7.5x */ - -1, /* 1110 -> RESERVED */ - 65, /* 1111 -> 6.5x */ -}; - -/* - * VIA C3 Samuel2 Stepping 1->15 - */ -static const int __cpuinitdata samuel2_eblcr[16] = { - 50, /* 0000 -> 5.0x */ - 30, /* 0001 -> 3.0x */ - 40, /* 0010 -> 4.0x */ - 100, /* 0011 -> 10.0x */ - 55, /* 0100 -> 5.5x */ - 35, /* 0101 -> 3.5x */ - 45, /* 0110 -> 4.5x */ - 110, /* 0111 -> 11.0x */ - 90, /* 1000 -> 9.0x */ - 70, /* 1001 -> 7.0x */ - 80, /* 1010 -> 8.0x */ - 60, /* 1011 -> 6.0x */ - 120, /* 1100 -> 12.0x */ - 75, /* 1101 -> 7.5x */ - 130, /* 1110 -> 13.0x */ - 65, /* 1111 -> 6.5x */ -}; - -/* - * VIA C3 Ezra - */ -static const int __cpuinitdata ezra_mults[16] = { - 100, /* 0000 -> 10.0x */ - 30, /* 0001 -> 3.0x */ - 40, /* 0010 -> 4.0x */ - 90, /* 0011 -> 9.0x */ - 95, /* 0100 -> 9.5x */ - 35, /* 0101 -> 3.5x */ - 45, /* 0110 -> 4.5x */ - 55, /* 0111 -> 5.5x */ - 60, /* 1000 -> 6.0x */ - 70, /* 1001 -> 7.0x */ - 80, /* 1010 -> 8.0x */ - 50, /* 1011 -> 5.0x */ - 65, /* 1100 -> 6.5x */ - 75, /* 1101 -> 7.5x */ - 85, /* 1110 -> 8.5x */ - 120, /* 1111 -> 12.0x */ -}; - -static const int __cpuinitdata ezra_eblcr[16] = { - 50, /* 0000 -> 5.0x */ - 30, /* 0001 -> 3.0x */ - 40, /* 0010 -> 4.0x */ - 100, /* 0011 -> 10.0x */ - 55, /* 0100 -> 5.5x */ - 35, /* 0101 -> 3.5x */ - 45, /* 0110 -> 4.5x */ - 95, /* 0111 -> 9.5x */ - 90, /* 1000 -> 9.0x */ - 70, /* 1001 -> 7.0x */ - 80, /* 1010 -> 8.0x */ - 60, /* 1011 -> 6.0x */ - 120, /* 1100 -> 12.0x */ - 75, /* 1101 -> 7.5x */ - 85, /* 1110 -> 8.5x */ - 65, /* 1111 -> 6.5x */ -}; - -/* - * VIA C3 (Ezra-T) [C5M]. - */ -static const int __cpuinitdata ezrat_mults[32] = { - 100, /* 0000 -> 10.0x */ - 30, /* 0001 -> 3.0x */ - 40, /* 0010 -> 4.0x */ - 90, /* 0011 -> 9.0x */ - 95, /* 0100 -> 9.5x */ - 35, /* 0101 -> 3.5x */ - 45, /* 0110 -> 4.5x */ - 55, /* 0111 -> 5.5x */ - 60, /* 1000 -> 6.0x */ - 70, /* 1001 -> 7.0x */ - 80, /* 1010 -> 8.0x */ - 50, /* 1011 -> 5.0x */ - 65, /* 1100 -> 6.5x */ - 75, /* 1101 -> 7.5x */ - 85, /* 1110 -> 8.5x */ - 120, /* 1111 -> 12.0x */ - - -1, /* 0000 -> RESERVED (10.0x) */ - 110, /* 0001 -> 11.0x */ - -1, /* 0010 -> 12.0x */ - -1, /* 0011 -> RESERVED (9.0x)*/ - 105, /* 0100 -> 10.5x */ - 115, /* 0101 -> 11.5x */ - 125, /* 0110 -> 12.5x */ - 135, /* 0111 -> 13.5x */ - 140, /* 1000 -> 14.0x */ - 150, /* 1001 -> 15.0x */ - 160, /* 1010 -> 16.0x */ - 130, /* 1011 -> 13.0x */ - 145, /* 1100 -> 14.5x */ - 155, /* 1101 -> 15.5x */ - -1, /* 1110 -> RESERVED (13.0x) */ - -1, /* 1111 -> RESERVED (12.0x) */ -}; - -static const int __cpuinitdata ezrat_eblcr[32] = { - 50, /* 0000 -> 5.0x */ - 30, /* 0001 -> 3.0x */ - 40, /* 0010 -> 4.0x */ - 100, /* 0011 -> 10.0x */ - 55, /* 0100 -> 5.5x */ - 35, /* 0101 -> 3.5x */ - 45, /* 0110 -> 4.5x */ - 95, /* 0111 -> 9.5x */ - 90, /* 1000 -> 9.0x */ - 70, /* 1001 -> 7.0x */ - 80, /* 1010 -> 8.0x */ - 60, /* 1011 -> 6.0x */ - 120, /* 1100 -> 12.0x */ - 75, /* 1101 -> 7.5x */ - 85, /* 1110 -> 8.5x */ - 65, /* 1111 -> 6.5x */ - - -1, /* 0000 -> RESERVED (9.0x) */ - 110, /* 0001 -> 11.0x */ - 120, /* 0010 -> 12.0x */ - -1, /* 0011 -> RESERVED (10.0x)*/ - 135, /* 0100 -> 13.5x */ - 115, /* 0101 -> 11.5x */ - 125, /* 0110 -> 12.5x */ - 105, /* 0111 -> 10.5x */ - 130, /* 1000 -> 13.0x */ - 150, /* 1001 -> 15.0x */ - 160, /* 1010 -> 16.0x */ - 140, /* 1011 -> 14.0x */ - -1, /* 1100 -> RESERVED (12.0x) */ - 155, /* 1101 -> 15.5x */ - -1, /* 1110 -> RESERVED (13.0x) */ - 145, /* 1111 -> 14.5x */ -}; - -/* - * VIA C3 Nehemiah */ - -static const int __cpuinitdata nehemiah_mults[32] = { - 100, /* 0000 -> 10.0x */ - -1, /* 0001 -> 16.0x */ - 40, /* 0010 -> 4.0x */ - 90, /* 0011 -> 9.0x */ - 95, /* 0100 -> 9.5x */ - -1, /* 0101 -> RESERVED */ - 45, /* 0110 -> 4.5x */ - 55, /* 0111 -> 5.5x */ - 60, /* 1000 -> 6.0x */ - 70, /* 1001 -> 7.0x */ - 80, /* 1010 -> 8.0x */ - 50, /* 1011 -> 5.0x */ - 65, /* 1100 -> 6.5x */ - 75, /* 1101 -> 7.5x */ - 85, /* 1110 -> 8.5x */ - 120, /* 1111 -> 12.0x */ - -1, /* 0000 -> 10.0x */ - 110, /* 0001 -> 11.0x */ - -1, /* 0010 -> 12.0x */ - -1, /* 0011 -> 9.0x */ - 105, /* 0100 -> 10.5x */ - 115, /* 0101 -> 11.5x */ - 125, /* 0110 -> 12.5x */ - 135, /* 0111 -> 13.5x */ - 140, /* 1000 -> 14.0x */ - 150, /* 1001 -> 15.0x */ - 160, /* 1010 -> 16.0x */ - 130, /* 1011 -> 13.0x */ - 145, /* 1100 -> 14.5x */ - 155, /* 1101 -> 15.5x */ - -1, /* 1110 -> RESERVED (13.0x) */ - -1, /* 1111 -> 12.0x */ -}; - -static const int __cpuinitdata nehemiah_eblcr[32] = { - 50, /* 0000 -> 5.0x */ - 160, /* 0001 -> 16.0x */ - 40, /* 0010 -> 4.0x */ - 100, /* 0011 -> 10.0x */ - 55, /* 0100 -> 5.5x */ - -1, /* 0101 -> RESERVED */ - 45, /* 0110 -> 4.5x */ - 95, /* 0111 -> 9.5x */ - 90, /* 1000 -> 9.0x */ - 70, /* 1001 -> 7.0x */ - 80, /* 1010 -> 8.0x */ - 60, /* 1011 -> 6.0x */ - 120, /* 1100 -> 12.0x */ - 75, /* 1101 -> 7.5x */ - 85, /* 1110 -> 8.5x */ - 65, /* 1111 -> 6.5x */ - 90, /* 0000 -> 9.0x */ - 110, /* 0001 -> 11.0x */ - 120, /* 0010 -> 12.0x */ - 100, /* 0011 -> 10.0x */ - 135, /* 0100 -> 13.5x */ - 115, /* 0101 -> 11.5x */ - 125, /* 0110 -> 12.5x */ - 105, /* 0111 -> 10.5x */ - 130, /* 1000 -> 13.0x */ - 150, /* 1001 -> 15.0x */ - 160, /* 1010 -> 16.0x */ - 140, /* 1011 -> 14.0x */ - 120, /* 1100 -> 12.0x */ - 155, /* 1101 -> 15.5x */ - -1, /* 1110 -> RESERVED (13.0x) */ - 145 /* 1111 -> 14.5x */ -}; - -/* - * Voltage scales. Div/Mod by 1000 to get actual voltage. - * Which scale to use depends on the VRM type in use. - */ - -struct mV_pos { - unsigned short mV; - unsigned short pos; -}; - -static const struct mV_pos __cpuinitdata vrm85_mV[32] = { - {1250, 8}, {1200, 6}, {1150, 4}, {1100, 2}, - {1050, 0}, {1800, 30}, {1750, 28}, {1700, 26}, - {1650, 24}, {1600, 22}, {1550, 20}, {1500, 18}, - {1450, 16}, {1400, 14}, {1350, 12}, {1300, 10}, - {1275, 9}, {1225, 7}, {1175, 5}, {1125, 3}, - {1075, 1}, {1825, 31}, {1775, 29}, {1725, 27}, - {1675, 25}, {1625, 23}, {1575, 21}, {1525, 19}, - {1475, 17}, {1425, 15}, {1375, 13}, {1325, 11} -}; - -static const unsigned char __cpuinitdata mV_vrm85[32] = { - 0x04, 0x14, 0x03, 0x13, 0x02, 0x12, 0x01, 0x11, - 0x00, 0x10, 0x0f, 0x1f, 0x0e, 0x1e, 0x0d, 0x1d, - 0x0c, 0x1c, 0x0b, 0x1b, 0x0a, 0x1a, 0x09, 0x19, - 0x08, 0x18, 0x07, 0x17, 0x06, 0x16, 0x05, 0x15 -}; - -static const struct mV_pos __cpuinitdata mobilevrm_mV[32] = { - {1750, 31}, {1700, 30}, {1650, 29}, {1600, 28}, - {1550, 27}, {1500, 26}, {1450, 25}, {1400, 24}, - {1350, 23}, {1300, 22}, {1250, 21}, {1200, 20}, - {1150, 19}, {1100, 18}, {1050, 17}, {1000, 16}, - {975, 15}, {950, 14}, {925, 13}, {900, 12}, - {875, 11}, {850, 10}, {825, 9}, {800, 8}, - {775, 7}, {750, 6}, {725, 5}, {700, 4}, - {675, 3}, {650, 2}, {625, 1}, {600, 0} -}; - -static const unsigned char __cpuinitdata mV_mobilevrm[32] = { - 0x1f, 0x1e, 0x1d, 0x1c, 0x1b, 0x1a, 0x19, 0x18, - 0x17, 0x16, 0x15, 0x14, 0x13, 0x12, 0x11, 0x10, - 0x0f, 0x0e, 0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x08, - 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00 -}; - diff --git a/arch/x86/kernel/cpu/cpufreq/longrun.c b/arch/x86/kernel/cpu/cpufreq/longrun.c deleted file mode 100644 index 34ea359..0000000 --- a/arch/x86/kernel/cpu/cpufreq/longrun.c +++ /dev/null @@ -1,324 +0,0 @@ -/* - * (C) 2002 - 2003 Dominik Brodowski - * - * Licensed under the terms of the GNU GPL License version 2. - * - * BIG FAT DISCLAIMER: Work in progress code. Possibly *dangerous* - */ - -#include -#include -#include -#include -#include - -#include -#include - -static struct cpufreq_driver longrun_driver; - -/** - * longrun_{low,high}_freq is needed for the conversion of cpufreq kHz - * values into per cent values. In TMTA microcode, the following is valid: - * performance_pctg = (current_freq - low_freq)/(high_freq - low_freq) - */ -static unsigned int longrun_low_freq, longrun_high_freq; - - -/** - * longrun_get_policy - get the current LongRun policy - * @policy: struct cpufreq_policy where current policy is written into - * - * Reads the current LongRun policy by access to MSR_TMTA_LONGRUN_FLAGS - * and MSR_TMTA_LONGRUN_CTRL - */ -static void __cpuinit longrun_get_policy(struct cpufreq_policy *policy) -{ - u32 msr_lo, msr_hi; - - rdmsr(MSR_TMTA_LONGRUN_FLAGS, msr_lo, msr_hi); - pr_debug("longrun flags are %x - %x\n", msr_lo, msr_hi); - if (msr_lo & 0x01) - policy->policy = CPUFREQ_POLICY_PERFORMANCE; - else - policy->policy = CPUFREQ_POLICY_POWERSAVE; - - rdmsr(MSR_TMTA_LONGRUN_CTRL, msr_lo, msr_hi); - pr_debug("longrun ctrl is %x - %x\n", msr_lo, msr_hi); - msr_lo &= 0x0000007F; - msr_hi &= 0x0000007F; - - if (longrun_high_freq <= longrun_low_freq) { - /* Assume degenerate Longrun table */ - policy->min = policy->max = longrun_high_freq; - } else { - policy->min = longrun_low_freq + msr_lo * - ((longrun_high_freq - longrun_low_freq) / 100); - policy->max = longrun_low_freq + msr_hi * - ((longrun_high_freq - longrun_low_freq) / 100); - } - policy->cpu = 0; -} - - -/** - * longrun_set_policy - sets a new CPUFreq policy - * @policy: new policy - * - * Sets a new CPUFreq policy on LongRun-capable processors. This function - * has to be called with cpufreq_driver locked. - */ -static int longrun_set_policy(struct cpufreq_policy *policy) -{ - u32 msr_lo, msr_hi; - u32 pctg_lo, pctg_hi; - - if (!policy) - return -EINVAL; - - if (longrun_high_freq <= longrun_low_freq) { - /* Assume degenerate Longrun table */ - pctg_lo = pctg_hi = 100; - } else { - pctg_lo = (policy->min - longrun_low_freq) / - ((longrun_high_freq - longrun_low_freq) / 100); - pctg_hi = (policy->max - longrun_low_freq) / - ((longrun_high_freq - longrun_low_freq) / 100); - } - - if (pctg_hi > 100) - pctg_hi = 100; - if (pctg_lo > pctg_hi) - pctg_lo = pctg_hi; - - /* performance or economy mode */ - rdmsr(MSR_TMTA_LONGRUN_FLAGS, msr_lo, msr_hi); - msr_lo &= 0xFFFFFFFE; - switch (policy->policy) { - case CPUFREQ_POLICY_PERFORMANCE: - msr_lo |= 0x00000001; - break; - case CPUFREQ_POLICY_POWERSAVE: - break; - } - wrmsr(MSR_TMTA_LONGRUN_FLAGS, msr_lo, msr_hi); - - /* lower and upper boundary */ - rdmsr(MSR_TMTA_LONGRUN_CTRL, msr_lo, msr_hi); - msr_lo &= 0xFFFFFF80; - msr_hi &= 0xFFFFFF80; - msr_lo |= pctg_lo; - msr_hi |= pctg_hi; - wrmsr(MSR_TMTA_LONGRUN_CTRL, msr_lo, msr_hi); - - return 0; -} - - -/** - * longrun_verify_poliy - verifies a new CPUFreq policy - * @policy: the policy to verify - * - * Validates a new CPUFreq policy. This function has to be called with - * cpufreq_driver locked. - */ -static int longrun_verify_policy(struct cpufreq_policy *policy) -{ - if (!policy) - return -EINVAL; - - policy->cpu = 0; - cpufreq_verify_within_limits(policy, - policy->cpuinfo.min_freq, - policy->cpuinfo.max_freq); - - if ((policy->policy != CPUFREQ_POLICY_POWERSAVE) && - (policy->policy != CPUFREQ_POLICY_PERFORMANCE)) - return -EINVAL; - - return 0; -} - -static unsigned int longrun_get(unsigned int cpu) -{ - u32 eax, ebx, ecx, edx; - - if (cpu) - return 0; - - cpuid(0x80860007, &eax, &ebx, &ecx, &edx); - pr_debug("cpuid eax is %u\n", eax); - - return eax * 1000; -} - -/** - * longrun_determine_freqs - determines the lowest and highest possible core frequency - * @low_freq: an int to put the lowest frequency into - * @high_freq: an int to put the highest frequency into - * - * Determines the lowest and highest possible core frequencies on this CPU. - * This is necessary to calculate the performance percentage according to - * TMTA rules: - * performance_pctg = (target_freq - low_freq)/(high_freq - low_freq) - */ -static int __cpuinit longrun_determine_freqs(unsigned int *low_freq, - unsigned int *high_freq) -{ - u32 msr_lo, msr_hi; - u32 save_lo, save_hi; - u32 eax, ebx, ecx, edx; - u32 try_hi; - struct cpuinfo_x86 *c = &cpu_data(0); - - if (!low_freq || !high_freq) - return -EINVAL; - - if (cpu_has(c, X86_FEATURE_LRTI)) { - /* if the LongRun Table Interface is present, the - * detection is a bit easier: - * For minimum frequency, read out the maximum - * level (msr_hi), write that into "currently - * selected level", and read out the frequency. - * For maximum frequency, read out level zero. - */ - /* minimum */ - rdmsr(MSR_TMTA_LRTI_READOUT, msr_lo, msr_hi); - wrmsr(MSR_TMTA_LRTI_READOUT, msr_hi, msr_hi); - rdmsr(MSR_TMTA_LRTI_VOLT_MHZ, msr_lo, msr_hi); - *low_freq = msr_lo * 1000; /* to kHz */ - - /* maximum */ - wrmsr(MSR_TMTA_LRTI_READOUT, 0, msr_hi); - rdmsr(MSR_TMTA_LRTI_VOLT_MHZ, msr_lo, msr_hi); - *high_freq = msr_lo * 1000; /* to kHz */ - - pr_debug("longrun table interface told %u - %u kHz\n", - *low_freq, *high_freq); - - if (*low_freq > *high_freq) - *low_freq = *high_freq; - return 0; - } - - /* set the upper border to the value determined during TSC init */ - *high_freq = (cpu_khz / 1000); - *high_freq = *high_freq * 1000; - pr_debug("high frequency is %u kHz\n", *high_freq); - - /* get current borders */ - rdmsr(MSR_TMTA_LONGRUN_CTRL, msr_lo, msr_hi); - save_lo = msr_lo & 0x0000007F; - save_hi = msr_hi & 0x0000007F; - - /* if current perf_pctg is larger than 90%, we need to decrease the - * upper limit to make the calculation more accurate. - */ - cpuid(0x80860007, &eax, &ebx, &ecx, &edx); - /* try decreasing in 10% steps, some processors react only - * on some barrier values */ - for (try_hi = 80; try_hi > 0 && ecx > 90; try_hi -= 10) { - /* set to 0 to try_hi perf_pctg */ - msr_lo &= 0xFFFFFF80; - msr_hi &= 0xFFFFFF80; - msr_hi |= try_hi; - wrmsr(MSR_TMTA_LONGRUN_CTRL, msr_lo, msr_hi); - - /* read out current core MHz and current perf_pctg */ - cpuid(0x80860007, &eax, &ebx, &ecx, &edx); - - /* restore values */ - wrmsr(MSR_TMTA_LONGRUN_CTRL, save_lo, save_hi); - } - pr_debug("percentage is %u %%, freq is %u MHz\n", ecx, eax); - - /* performance_pctg = (current_freq - low_freq)/(high_freq - low_freq) - * eqals - * low_freq * (1 - perf_pctg) = (cur_freq - high_freq * perf_pctg) - * - * high_freq * perf_pctg is stored tempoarily into "ebx". - */ - ebx = (((cpu_khz / 1000) * ecx) / 100); /* to MHz */ - - if ((ecx > 95) || (ecx == 0) || (eax < ebx)) - return -EIO; - - edx = ((eax - ebx) * 100) / (100 - ecx); - *low_freq = edx * 1000; /* back to kHz */ - - pr_debug("low frequency is %u kHz\n", *low_freq); - - if (*low_freq > *high_freq) - *low_freq = *high_freq; - - return 0; -} - - -static int __cpuinit longrun_cpu_init(struct cpufreq_policy *policy) -{ - int result = 0; - - /* capability check */ - if (policy->cpu != 0) - return -ENODEV; - - /* detect low and high frequency */ - result = longrun_determine_freqs(&longrun_low_freq, &longrun_high_freq); - if (result) - return result; - - /* cpuinfo and default policy values */ - policy->cpuinfo.min_freq = longrun_low_freq; - policy->cpuinfo.max_freq = longrun_high_freq; - policy->cpuinfo.transition_latency = CPUFREQ_ETERNAL; - longrun_get_policy(policy); - - return 0; -} - - -static struct cpufreq_driver longrun_driver = { - .flags = CPUFREQ_CONST_LOOPS, - .verify = longrun_verify_policy, - .setpolicy = longrun_set_policy, - .get = longrun_get, - .init = longrun_cpu_init, - .name = "longrun", - .owner = THIS_MODULE, -}; - - -/** - * longrun_init - initializes the Transmeta Crusoe LongRun CPUFreq driver - * - * Initializes the LongRun support. - */ -static int __init longrun_init(void) -{ - struct cpuinfo_x86 *c = &cpu_data(0); - - if (c->x86_vendor != X86_VENDOR_TRANSMETA || - !cpu_has(c, X86_FEATURE_LONGRUN)) - return -ENODEV; - - return cpufreq_register_driver(&longrun_driver); -} - - -/** - * longrun_exit - unregisters LongRun support - */ -static void __exit longrun_exit(void) -{ - cpufreq_unregister_driver(&longrun_driver); -} - - -MODULE_AUTHOR("Dominik Brodowski "); -MODULE_DESCRIPTION("LongRun driver for Transmeta Crusoe and " - "Efficeon processors."); -MODULE_LICENSE("GPL"); - -module_init(longrun_init); -module_exit(longrun_exit); diff --git a/arch/x86/kernel/cpu/cpufreq/mperf.c b/arch/x86/kernel/cpu/cpufreq/mperf.c deleted file mode 100644 index 911e193..0000000 --- a/arch/x86/kernel/cpu/cpufreq/mperf.c +++ /dev/null @@ -1,51 +0,0 @@ -#include -#include -#include -#include -#include -#include - -#include "mperf.h" - -static DEFINE_PER_CPU(struct aperfmperf, acfreq_old_perf); - -/* Called via smp_call_function_single(), on the target CPU */ -static void read_measured_perf_ctrs(void *_cur) -{ - struct aperfmperf *am = _cur; - - get_aperfmperf(am); -} - -/* - * Return the measured active (C0) frequency on this CPU since last call - * to this function. - * Input: cpu number - * Return: Average CPU frequency in terms of max frequency (zero on error) - * - * We use IA32_MPERF and IA32_APERF MSRs to get the measured performance - * over a period of time, while CPU is in C0 state. - * IA32_MPERF counts at the rate of max advertised frequency - * IA32_APERF counts at the rate of actual CPU frequency - * Only IA32_APERF/IA32_MPERF ratio is architecturally defined and - * no meaning should be associated with absolute values of these MSRs. - */ -unsigned int cpufreq_get_measured_perf(struct cpufreq_policy *policy, - unsigned int cpu) -{ - struct aperfmperf perf; - unsigned long ratio; - unsigned int retval; - - if (smp_call_function_single(cpu, read_measured_perf_ctrs, &perf, 1)) - return 0; - - ratio = calc_aperfmperf_ratio(&per_cpu(acfreq_old_perf, cpu), &perf); - per_cpu(acfreq_old_perf, cpu) = perf; - - retval = (policy->cpuinfo.max_freq * ratio) >> APERFMPERF_SHIFT; - - return retval; -} -EXPORT_SYMBOL_GPL(cpufreq_get_measured_perf); -MODULE_LICENSE("GPL"); diff --git a/arch/x86/kernel/cpu/cpufreq/mperf.h b/arch/x86/kernel/cpu/cpufreq/mperf.h deleted file mode 100644 index 5dbf295..0000000 --- a/arch/x86/kernel/cpu/cpufreq/mperf.h +++ /dev/null @@ -1,9 +0,0 @@ -/* - * (c) 2010 Advanced Micro Devices, Inc. - * Your use of this code is subject to the terms and conditions of the - * GNU general public license version 2. See "COPYING" or - * http://www.gnu.org/licenses/gpl.html - */ - -unsigned int cpufreq_get_measured_perf(struct cpufreq_policy *policy, - unsigned int cpu); diff --git a/arch/x86/kernel/cpu/cpufreq/p4-clockmod.c b/arch/x86/kernel/cpu/cpufreq/p4-clockmod.c deleted file mode 100644 index 6be3e07..0000000 --- a/arch/x86/kernel/cpu/cpufreq/p4-clockmod.c +++ /dev/null @@ -1,329 +0,0 @@ -/* - * Pentium 4/Xeon CPU on demand clock modulation/speed scaling - * (C) 2002 - 2003 Dominik Brodowski - * (C) 2002 Zwane Mwaikambo - * (C) 2002 Arjan van de Ven - * (C) 2002 Tora T. Engstad - * All Rights Reserved - * - * 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. - * - * The author(s) of this software shall not be held liable for damages - * of any nature resulting due to the use of this software. This - * software is provided AS-IS with no warranties. - * - * Date Errata Description - * 20020525 N44, O17 12.5% or 25% DC causes lockup - * - */ - -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#include "speedstep-lib.h" - -#define PFX "p4-clockmod: " - -/* - * Duty Cycle (3bits), note DC_DISABLE is not specified in - * intel docs i just use it to mean disable - */ -enum { - DC_RESV, DC_DFLT, DC_25PT, DC_38PT, DC_50PT, - DC_64PT, DC_75PT, DC_88PT, DC_DISABLE -}; - -#define DC_ENTRIES 8 - - -static int has_N44_O17_errata[NR_CPUS]; -static unsigned int stock_freq; -static struct cpufreq_driver p4clockmod_driver; -static unsigned int cpufreq_p4_get(unsigned int cpu); - -static int cpufreq_p4_setdc(unsigned int cpu, unsigned int newstate) -{ - u32 l, h; - - if (!cpu_online(cpu) || - (newstate > DC_DISABLE) || (newstate == DC_RESV)) - return -EINVAL; - - rdmsr_on_cpu(cpu, MSR_IA32_THERM_STATUS, &l, &h); - - if (l & 0x01) - pr_debug("CPU#%d currently thermal throttled\n", cpu); - - if (has_N44_O17_errata[cpu] && - (newstate == DC_25PT || newstate == DC_DFLT)) - newstate = DC_38PT; - - rdmsr_on_cpu(cpu, MSR_IA32_THERM_CONTROL, &l, &h); - if (newstate == DC_DISABLE) { - pr_debug("CPU#%d disabling modulation\n", cpu); - wrmsr_on_cpu(cpu, MSR_IA32_THERM_CONTROL, l & ~(1<<4), h); - } else { - pr_debug("CPU#%d setting duty cycle to %d%%\n", - cpu, ((125 * newstate) / 10)); - /* bits 63 - 5 : reserved - * bit 4 : enable/disable - * bits 3-1 : duty cycle - * bit 0 : reserved - */ - l = (l & ~14); - l = l | (1<<4) | ((newstate & 0x7)<<1); - wrmsr_on_cpu(cpu, MSR_IA32_THERM_CONTROL, l, h); - } - - return 0; -} - - -static struct cpufreq_frequency_table p4clockmod_table[] = { - {DC_RESV, CPUFREQ_ENTRY_INVALID}, - {DC_DFLT, 0}, - {DC_25PT, 0}, - {DC_38PT, 0}, - {DC_50PT, 0}, - {DC_64PT, 0}, - {DC_75PT, 0}, - {DC_88PT, 0}, - {DC_DISABLE, 0}, - {DC_RESV, CPUFREQ_TABLE_END}, -}; - - -static int cpufreq_p4_target(struct cpufreq_policy *policy, - unsigned int target_freq, - unsigned int relation) -{ - unsigned int newstate = DC_RESV; - struct cpufreq_freqs freqs; - int i; - - if (cpufreq_frequency_table_target(policy, &p4clockmod_table[0], - target_freq, relation, &newstate)) - return -EINVAL; - - freqs.old = cpufreq_p4_get(policy->cpu); - freqs.new = stock_freq * p4clockmod_table[newstate].index / 8; - - if (freqs.new == freqs.old) - return 0; - - /* notifiers */ - for_each_cpu(i, policy->cpus) { - freqs.cpu = i; - cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE); - } - - /* run on each logical CPU, - * see section 13.15.3 of IA32 Intel Architecture Software - * Developer's Manual, Volume 3 - */ - for_each_cpu(i, policy->cpus) - cpufreq_p4_setdc(i, p4clockmod_table[newstate].index); - - /* notifiers */ - for_each_cpu(i, policy->cpus) { - freqs.cpu = i; - cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE); - } - - return 0; -} - - -static int cpufreq_p4_verify(struct cpufreq_policy *policy) -{ - return cpufreq_frequency_table_verify(policy, &p4clockmod_table[0]); -} - - -static unsigned int cpufreq_p4_get_frequency(struct cpuinfo_x86 *c) -{ - if (c->x86 == 0x06) { - if (cpu_has(c, X86_FEATURE_EST)) - printk_once(KERN_WARNING PFX "Warning: EST-capable " - "CPU detected. The acpi-cpufreq module offers " - "voltage scaling in addition to frequency " - "scaling. You should use that instead of " - "p4-clockmod, if possible.\n"); - switch (c->x86_model) { - case 0x0E: /* Core */ - case 0x0F: /* Core Duo */ - case 0x16: /* Celeron Core */ - case 0x1C: /* Atom */ - p4clockmod_driver.flags |= CPUFREQ_CONST_LOOPS; - return speedstep_get_frequency(SPEEDSTEP_CPU_PCORE); - case 0x0D: /* Pentium M (Dothan) */ - p4clockmod_driver.flags |= CPUFREQ_CONST_LOOPS; - /* fall through */ - case 0x09: /* Pentium M (Banias) */ - return speedstep_get_frequency(SPEEDSTEP_CPU_PM); - } - } - - if (c->x86 != 0xF) - return 0; - - /* on P-4s, the TSC runs with constant frequency independent whether - * throttling is active or not. */ - p4clockmod_driver.flags |= CPUFREQ_CONST_LOOPS; - - if (speedstep_detect_processor() == SPEEDSTEP_CPU_P4M) { - printk(KERN_WARNING PFX "Warning: Pentium 4-M detected. " - "The speedstep-ich or acpi cpufreq modules offer " - "voltage scaling in addition of frequency scaling. " - "You should use either one instead of p4-clockmod, " - "if possible.\n"); - return speedstep_get_frequency(SPEEDSTEP_CPU_P4M); - } - - return speedstep_get_frequency(SPEEDSTEP_CPU_P4D); -} - - - -static int cpufreq_p4_cpu_init(struct cpufreq_policy *policy) -{ - struct cpuinfo_x86 *c = &cpu_data(policy->cpu); - int cpuid = 0; - unsigned int i; - -#ifdef CONFIG_SMP - cpumask_copy(policy->cpus, cpu_sibling_mask(policy->cpu)); -#endif - - /* Errata workaround */ - cpuid = (c->x86 << 8) | (c->x86_model << 4) | c->x86_mask; - switch (cpuid) { - case 0x0f07: - case 0x0f0a: - case 0x0f11: - case 0x0f12: - has_N44_O17_errata[policy->cpu] = 1; - pr_debug("has errata -- disabling low frequencies\n"); - } - - if (speedstep_detect_processor() == SPEEDSTEP_CPU_P4D && - c->x86_model < 2) { - /* switch to maximum frequency and measure result */ - cpufreq_p4_setdc(policy->cpu, DC_DISABLE); - recalibrate_cpu_khz(); - } - /* get max frequency */ - stock_freq = cpufreq_p4_get_frequency(c); - if (!stock_freq) - return -EINVAL; - - /* table init */ - for (i = 1; (p4clockmod_table[i].frequency != CPUFREQ_TABLE_END); i++) { - if ((i < 2) && (has_N44_O17_errata[policy->cpu])) - p4clockmod_table[i].frequency = CPUFREQ_ENTRY_INVALID; - else - p4clockmod_table[i].frequency = (stock_freq * i)/8; - } - cpufreq_frequency_table_get_attr(p4clockmod_table, policy->cpu); - - /* cpuinfo and default policy values */ - - /* the transition latency is set to be 1 higher than the maximum - * transition latency of the ondemand governor */ - policy->cpuinfo.transition_latency = 10000001; - policy->cur = stock_freq; - - return cpufreq_frequency_table_cpuinfo(policy, &p4clockmod_table[0]); -} - - -static int cpufreq_p4_cpu_exit(struct cpufreq_policy *policy) -{ - cpufreq_frequency_table_put_attr(policy->cpu); - return 0; -} - -static unsigned int cpufreq_p4_get(unsigned int cpu) -{ - u32 l, h; - - rdmsr_on_cpu(cpu, MSR_IA32_THERM_CONTROL, &l, &h); - - if (l & 0x10) { - l = l >> 1; - l &= 0x7; - } else - l = DC_DISABLE; - - if (l != DC_DISABLE) - return stock_freq * l / 8; - - return stock_freq; -} - -static struct freq_attr *p4clockmod_attr[] = { - &cpufreq_freq_attr_scaling_available_freqs, - NULL, -}; - -static struct cpufreq_driver p4clockmod_driver = { - .verify = cpufreq_p4_verify, - .target = cpufreq_p4_target, - .init = cpufreq_p4_cpu_init, - .exit = cpufreq_p4_cpu_exit, - .get = cpufreq_p4_get, - .name = "p4-clockmod", - .owner = THIS_MODULE, - .attr = p4clockmod_attr, -}; - - -static int __init cpufreq_p4_init(void) -{ - struct cpuinfo_x86 *c = &cpu_data(0); - int ret; - - /* - * THERM_CONTROL is architectural for IA32 now, so - * we can rely on the capability checks - */ - if (c->x86_vendor != X86_VENDOR_INTEL) - return -ENODEV; - - if (!test_cpu_cap(c, X86_FEATURE_ACPI) || - !test_cpu_cap(c, X86_FEATURE_ACC)) - return -ENODEV; - - ret = cpufreq_register_driver(&p4clockmod_driver); - if (!ret) - printk(KERN_INFO PFX "P4/Xeon(TM) CPU On-Demand Clock " - "Modulation available\n"); - - return ret; -} - - -static void __exit cpufreq_p4_exit(void) -{ - cpufreq_unregister_driver(&p4clockmod_driver); -} - - -MODULE_AUTHOR("Zwane Mwaikambo "); -MODULE_DESCRIPTION("cpufreq driver for Pentium(TM) 4/Xeon(TM)"); -MODULE_LICENSE("GPL"); - -late_initcall(cpufreq_p4_init); -module_exit(cpufreq_p4_exit); diff --git a/arch/x86/kernel/cpu/cpufreq/pcc-cpufreq.c b/arch/x86/kernel/cpu/cpufreq/pcc-cpufreq.c deleted file mode 100644 index 7b0603e..0000000 --- a/arch/x86/kernel/cpu/cpufreq/pcc-cpufreq.c +++ /dev/null @@ -1,621 +0,0 @@ -/* - * pcc-cpufreq.c - Processor Clocking Control firmware cpufreq interface - * - * Copyright (C) 2009 Red Hat, Matthew Garrett - * Copyright (C) 2009 Hewlett-Packard Development Company, L.P. - * Nagananda Chumbalkar - * - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or NON - * INFRINGEMENT. See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 675 Mass Ave, Cambridge, MA 02139, USA. - * - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - */ - -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#include - -#define PCC_VERSION "1.10.00" -#define POLL_LOOPS 300 - -#define CMD_COMPLETE 0x1 -#define CMD_GET_FREQ 0x0 -#define CMD_SET_FREQ 0x1 - -#define BUF_SZ 4 - -struct pcc_register_resource { - u8 descriptor; - u16 length; - u8 space_id; - u8 bit_width; - u8 bit_offset; - u8 access_size; - u64 address; -} __attribute__ ((packed)); - -struct pcc_memory_resource { - u8 descriptor; - u16 length; - u8 space_id; - u8 resource_usage; - u8 type_specific; - u64 granularity; - u64 minimum; - u64 maximum; - u64 translation_offset; - u64 address_length; -} __attribute__ ((packed)); - -static struct cpufreq_driver pcc_cpufreq_driver; - -struct pcc_header { - u32 signature; - u16 length; - u8 major; - u8 minor; - u32 features; - u16 command; - u16 status; - u32 latency; - u32 minimum_time; - u32 maximum_time; - u32 nominal; - u32 throttled_frequency; - u32 minimum_frequency; -}; - -static void __iomem *pcch_virt_addr; -static struct pcc_header __iomem *pcch_hdr; - -static DEFINE_SPINLOCK(pcc_lock); - -static struct acpi_generic_address doorbell; - -static u64 doorbell_preserve; -static u64 doorbell_write; - -static u8 OSC_UUID[16] = {0x9F, 0x2C, 0x9B, 0x63, 0x91, 0x70, 0x1f, 0x49, - 0xBB, 0x4F, 0xA5, 0x98, 0x2F, 0xA1, 0xB5, 0x46}; - -struct pcc_cpu { - u32 input_offset; - u32 output_offset; -}; - -static struct pcc_cpu __percpu *pcc_cpu_info; - -static int pcc_cpufreq_verify(struct cpufreq_policy *policy) -{ - cpufreq_verify_within_limits(policy, policy->cpuinfo.min_freq, - policy->cpuinfo.max_freq); - return 0; -} - -static inline void pcc_cmd(void) -{ - u64 doorbell_value; - int i; - - acpi_read(&doorbell_value, &doorbell); - acpi_write((doorbell_value & doorbell_preserve) | doorbell_write, - &doorbell); - - for (i = 0; i < POLL_LOOPS; i++) { - if (ioread16(&pcch_hdr->status) & CMD_COMPLETE) - break; - } -} - -static inline void pcc_clear_mapping(void) -{ - if (pcch_virt_addr) - iounmap(pcch_virt_addr); - pcch_virt_addr = NULL; -} - -static unsigned int pcc_get_freq(unsigned int cpu) -{ - struct pcc_cpu *pcc_cpu_data; - unsigned int curr_freq; - unsigned int freq_limit; - u16 status; - u32 input_buffer; - u32 output_buffer; - - spin_lock(&pcc_lock); - - pr_debug("get: get_freq for CPU %d\n", cpu); - pcc_cpu_data = per_cpu_ptr(pcc_cpu_info, cpu); - - input_buffer = 0x1; - iowrite32(input_buffer, - (pcch_virt_addr + pcc_cpu_data->input_offset)); - iowrite16(CMD_GET_FREQ, &pcch_hdr->command); - - pcc_cmd(); - - output_buffer = - ioread32(pcch_virt_addr + pcc_cpu_data->output_offset); - - /* Clear the input buffer - we are done with the current command */ - memset_io((pcch_virt_addr + pcc_cpu_data->input_offset), 0, BUF_SZ); - - status = ioread16(&pcch_hdr->status); - if (status != CMD_COMPLETE) { - pr_debug("get: FAILED: for CPU %d, status is %d\n", - cpu, status); - goto cmd_incomplete; - } - iowrite16(0, &pcch_hdr->status); - curr_freq = (((ioread32(&pcch_hdr->nominal) * (output_buffer & 0xff)) - / 100) * 1000); - - pr_debug("get: SUCCESS: (virtual) output_offset for cpu %d is " - "0x%p, contains a value of: 0x%x. Speed is: %d MHz\n", - cpu, (pcch_virt_addr + pcc_cpu_data->output_offset), - output_buffer, curr_freq); - - freq_limit = (output_buffer >> 8) & 0xff; - if (freq_limit != 0xff) { - pr_debug("get: frequency for cpu %d is being temporarily" - " capped at %d\n", cpu, curr_freq); - } - - spin_unlock(&pcc_lock); - return curr_freq; - -cmd_incomplete: - iowrite16(0, &pcch_hdr->status); - spin_unlock(&pcc_lock); - return 0; -} - -static int pcc_cpufreq_target(struct cpufreq_policy *policy, - unsigned int target_freq, - unsigned int relation) -{ - struct pcc_cpu *pcc_cpu_data; - struct cpufreq_freqs freqs; - u16 status; - u32 input_buffer; - int cpu; - - spin_lock(&pcc_lock); - cpu = policy->cpu; - pcc_cpu_data = per_cpu_ptr(pcc_cpu_info, cpu); - - pr_debug("target: CPU %d should go to target freq: %d " - "(virtual) input_offset is 0x%p\n", - cpu, target_freq, - (pcch_virt_addr + pcc_cpu_data->input_offset)); - - freqs.new = target_freq; - freqs.cpu = cpu; - cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE); - - input_buffer = 0x1 | (((target_freq * 100) - / (ioread32(&pcch_hdr->nominal) * 1000)) << 8); - iowrite32(input_buffer, - (pcch_virt_addr + pcc_cpu_data->input_offset)); - iowrite16(CMD_SET_FREQ, &pcch_hdr->command); - - pcc_cmd(); - - /* Clear the input buffer - we are done with the current command */ - memset_io((pcch_virt_addr + pcc_cpu_data->input_offset), 0, BUF_SZ); - - status = ioread16(&pcch_hdr->status); - if (status != CMD_COMPLETE) { - pr_debug("target: FAILED for cpu %d, with status: 0x%x\n", - cpu, status); - goto cmd_incomplete; - } - iowrite16(0, &pcch_hdr->status); - - cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE); - pr_debug("target: was SUCCESSFUL for cpu %d\n", cpu); - spin_unlock(&pcc_lock); - - return 0; - -cmd_incomplete: - iowrite16(0, &pcch_hdr->status); - spin_unlock(&pcc_lock); - return -EINVAL; -} - -static int pcc_get_offset(int cpu) -{ - acpi_status status; - struct acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER, NULL}; - union acpi_object *pccp, *offset; - struct pcc_cpu *pcc_cpu_data; - struct acpi_processor *pr; - int ret = 0; - - pr = per_cpu(processors, cpu); - pcc_cpu_data = per_cpu_ptr(pcc_cpu_info, cpu); - - status = acpi_evaluate_object(pr->handle, "PCCP", NULL, &buffer); - if (ACPI_FAILURE(status)) - return -ENODEV; - - pccp = buffer.pointer; - if (!pccp || pccp->type != ACPI_TYPE_PACKAGE) { - ret = -ENODEV; - goto out_free; - }; - - offset = &(pccp->package.elements[0]); - if (!offset || offset->type != ACPI_TYPE_INTEGER) { - ret = -ENODEV; - goto out_free; - } - - pcc_cpu_data->input_offset = offset->integer.value; - - offset = &(pccp->package.elements[1]); - if (!offset || offset->type != ACPI_TYPE_INTEGER) { - ret = -ENODEV; - goto out_free; - } - - pcc_cpu_data->output_offset = offset->integer.value; - - memset_io((pcch_virt_addr + pcc_cpu_data->input_offset), 0, BUF_SZ); - memset_io((pcch_virt_addr + pcc_cpu_data->output_offset), 0, BUF_SZ); - - pr_debug("pcc_get_offset: for CPU %d: pcc_cpu_data " - "input_offset: 0x%x, pcc_cpu_data output_offset: 0x%x\n", - cpu, pcc_cpu_data->input_offset, pcc_cpu_data->output_offset); -out_free: - kfree(buffer.pointer); - return ret; -} - -static int __init pcc_cpufreq_do_osc(acpi_handle *handle) -{ - acpi_status status; - struct acpi_object_list input; - struct acpi_buffer output = {ACPI_ALLOCATE_BUFFER, NULL}; - union acpi_object in_params[4]; - union acpi_object *out_obj; - u32 capabilities[2]; - u32 errors; - u32 supported; - int ret = 0; - - input.count = 4; - input.pointer = in_params; - in_params[0].type = ACPI_TYPE_BUFFER; - in_params[0].buffer.length = 16; - in_params[0].buffer.pointer = OSC_UUID; - in_params[1].type = ACPI_TYPE_INTEGER; - in_params[1].integer.value = 1; - in_params[2].type = ACPI_TYPE_INTEGER; - in_params[2].integer.value = 2; - in_params[3].type = ACPI_TYPE_BUFFER; - in_params[3].buffer.length = 8; - in_params[3].buffer.pointer = (u8 *)&capabilities; - - capabilities[0] = OSC_QUERY_ENABLE; - capabilities[1] = 0x1; - - status = acpi_evaluate_object(*handle, "_OSC", &input, &output); - if (ACPI_FAILURE(status)) - return -ENODEV; - - if (!output.length) - return -ENODEV; - - out_obj = output.pointer; - if (out_obj->type != ACPI_TYPE_BUFFER) { - ret = -ENODEV; - goto out_free; - } - - errors = *((u32 *)out_obj->buffer.pointer) & ~(1 << 0); - if (errors) { - ret = -ENODEV; - goto out_free; - } - - supported = *((u32 *)(out_obj->buffer.pointer + 4)); - if (!(supported & 0x1)) { - ret = -ENODEV; - goto out_free; - } - - kfree(output.pointer); - capabilities[0] = 0x0; - capabilities[1] = 0x1; - - status = acpi_evaluate_object(*handle, "_OSC", &input, &output); - if (ACPI_FAILURE(status)) - return -ENODEV; - - if (!output.length) - return -ENODEV; - - out_obj = output.pointer; - if (out_obj->type != ACPI_TYPE_BUFFER) { - ret = -ENODEV; - goto out_free; - } - - errors = *((u32 *)out_obj->buffer.pointer) & ~(1 << 0); - if (errors) { - ret = -ENODEV; - goto out_free; - } - - supported = *((u32 *)(out_obj->buffer.pointer + 4)); - if (!(supported & 0x1)) { - ret = -ENODEV; - goto out_free; - } - -out_free: - kfree(output.pointer); - return ret; -} - -static int __init pcc_cpufreq_probe(void) -{ - acpi_status status; - struct acpi_buffer output = {ACPI_ALLOCATE_BUFFER, NULL}; - struct pcc_memory_resource *mem_resource; - struct pcc_register_resource *reg_resource; - union acpi_object *out_obj, *member; - acpi_handle handle, osc_handle, pcch_handle; - int ret = 0; - - status = acpi_get_handle(NULL, "\\_SB", &handle); - if (ACPI_FAILURE(status)) - return -ENODEV; - - status = acpi_get_handle(handle, "PCCH", &pcch_handle); - if (ACPI_FAILURE(status)) - return -ENODEV; - - status = acpi_get_handle(handle, "_OSC", &osc_handle); - if (ACPI_SUCCESS(status)) { - ret = pcc_cpufreq_do_osc(&osc_handle); - if (ret) - pr_debug("probe: _OSC evaluation did not succeed\n"); - /* Firmware's use of _OSC is optional */ - ret = 0; - } - - status = acpi_evaluate_object(handle, "PCCH", NULL, &output); - if (ACPI_FAILURE(status)) - return -ENODEV; - - out_obj = output.pointer; - if (out_obj->type != ACPI_TYPE_PACKAGE) { - ret = -ENODEV; - goto out_free; - } - - member = &out_obj->package.elements[0]; - if (member->type != ACPI_TYPE_BUFFER) { - ret = -ENODEV; - goto out_free; - } - - mem_resource = (struct pcc_memory_resource *)member->buffer.pointer; - - pr_debug("probe: mem_resource descriptor: 0x%x," - " length: %d, space_id: %d, resource_usage: %d," - " type_specific: %d, granularity: 0x%llx," - " minimum: 0x%llx, maximum: 0x%llx," - " translation_offset: 0x%llx, address_length: 0x%llx\n", - mem_resource->descriptor, mem_resource->length, - mem_resource->space_id, mem_resource->resource_usage, - mem_resource->type_specific, mem_resource->granularity, - mem_resource->minimum, mem_resource->maximum, - mem_resource->translation_offset, - mem_resource->address_length); - - if (mem_resource->space_id != ACPI_ADR_SPACE_SYSTEM_MEMORY) { - ret = -ENODEV; - goto out_free; - } - - pcch_virt_addr = ioremap_nocache(mem_resource->minimum, - mem_resource->address_length); - if (pcch_virt_addr == NULL) { - pr_debug("probe: could not map shared mem region\n"); - goto out_free; - } - pcch_hdr = pcch_virt_addr; - - pr_debug("probe: PCCH header (virtual) addr: 0x%p\n", pcch_hdr); - pr_debug("probe: PCCH header is at physical address: 0x%llx," - " signature: 0x%x, length: %d bytes, major: %d, minor: %d," - " supported features: 0x%x, command field: 0x%x," - " status field: 0x%x, nominal latency: %d us\n", - mem_resource->minimum, ioread32(&pcch_hdr->signature), - ioread16(&pcch_hdr->length), ioread8(&pcch_hdr->major), - ioread8(&pcch_hdr->minor), ioread32(&pcch_hdr->features), - ioread16(&pcch_hdr->command), ioread16(&pcch_hdr->status), - ioread32(&pcch_hdr->latency)); - - pr_debug("probe: min time between commands: %d us," - " max time between commands: %d us," - " nominal CPU frequency: %d MHz," - " minimum CPU frequency: %d MHz," - " minimum CPU frequency without throttling: %d MHz\n", - ioread32(&pcch_hdr->minimum_time), - ioread32(&pcch_hdr->maximum_time), - ioread32(&pcch_hdr->nominal), - ioread32(&pcch_hdr->throttled_frequency), - ioread32(&pcch_hdr->minimum_frequency)); - - member = &out_obj->package.elements[1]; - if (member->type != ACPI_TYPE_BUFFER) { - ret = -ENODEV; - goto pcch_free; - } - - reg_resource = (struct pcc_register_resource *)member->buffer.pointer; - - doorbell.space_id = reg_resource->space_id; - doorbell.bit_width = reg_resource->bit_width; - doorbell.bit_offset = reg_resource->bit_offset; - doorbell.access_width = 64; - doorbell.address = reg_resource->address; - - pr_debug("probe: doorbell: space_id is %d, bit_width is %d, " - "bit_offset is %d, access_width is %d, address is 0x%llx\n", - doorbell.space_id, doorbell.bit_width, doorbell.bit_offset, - doorbell.access_width, reg_resource->address); - - member = &out_obj->package.elements[2]; - if (member->type != ACPI_TYPE_INTEGER) { - ret = -ENODEV; - goto pcch_free; - } - - doorbell_preserve = member->integer.value; - - member = &out_obj->package.elements[3]; - if (member->type != ACPI_TYPE_INTEGER) { - ret = -ENODEV; - goto pcch_free; - } - - doorbell_write = member->integer.value; - - pr_debug("probe: doorbell_preserve: 0x%llx," - " doorbell_write: 0x%llx\n", - doorbell_preserve, doorbell_write); - - pcc_cpu_info = alloc_percpu(struct pcc_cpu); - if (!pcc_cpu_info) { - ret = -ENOMEM; - goto pcch_free; - } - - printk(KERN_DEBUG "pcc-cpufreq: (v%s) driver loaded with frequency" - " limits: %d MHz, %d MHz\n", PCC_VERSION, - ioread32(&pcch_hdr->minimum_frequency), - ioread32(&pcch_hdr->nominal)); - kfree(output.pointer); - return ret; -pcch_free: - pcc_clear_mapping(); -out_free: - kfree(output.pointer); - return ret; -} - -static int pcc_cpufreq_cpu_init(struct cpufreq_policy *policy) -{ - unsigned int cpu = policy->cpu; - unsigned int result = 0; - - if (!pcch_virt_addr) { - result = -1; - goto out; - } - - result = pcc_get_offset(cpu); - if (result) { - pr_debug("init: PCCP evaluation failed\n"); - goto out; - } - - policy->max = policy->cpuinfo.max_freq = - ioread32(&pcch_hdr->nominal) * 1000; - policy->min = policy->cpuinfo.min_freq = - ioread32(&pcch_hdr->minimum_frequency) * 1000; - policy->cur = pcc_get_freq(cpu); - - if (!policy->cur) { - pr_debug("init: Unable to get current CPU frequency\n"); - result = -EINVAL; - goto out; - } - - pr_debug("init: policy->max is %d, policy->min is %d\n", - policy->max, policy->min); -out: - return result; -} - -static int pcc_cpufreq_cpu_exit(struct cpufreq_policy *policy) -{ - return 0; -} - -static struct cpufreq_driver pcc_cpufreq_driver = { - .flags = CPUFREQ_CONST_LOOPS, - .get = pcc_get_freq, - .verify = pcc_cpufreq_verify, - .target = pcc_cpufreq_target, - .init = pcc_cpufreq_cpu_init, - .exit = pcc_cpufreq_cpu_exit, - .name = "pcc-cpufreq", - .owner = THIS_MODULE, -}; - -static int __init pcc_cpufreq_init(void) -{ - int ret; - - if (acpi_disabled) - return 0; - - ret = pcc_cpufreq_probe(); - if (ret) { - pr_debug("pcc_cpufreq_init: PCCH evaluation failed\n"); - return ret; - } - - ret = cpufreq_register_driver(&pcc_cpufreq_driver); - - return ret; -} - -static void __exit pcc_cpufreq_exit(void) -{ - cpufreq_unregister_driver(&pcc_cpufreq_driver); - - pcc_clear_mapping(); - - free_percpu(pcc_cpu_info); -} - -MODULE_AUTHOR("Matthew Garrett, Naga Chumbalkar"); -MODULE_VERSION(PCC_VERSION); -MODULE_DESCRIPTION("Processor Clocking Control interface driver"); -MODULE_LICENSE("GPL"); - -late_initcall(pcc_cpufreq_init); -module_exit(pcc_cpufreq_exit); diff --git a/arch/x86/kernel/cpu/cpufreq/powernow-k6.c b/arch/x86/kernel/cpu/cpufreq/powernow-k6.c deleted file mode 100644 index b3379d6..0000000 --- a/arch/x86/kernel/cpu/cpufreq/powernow-k6.c +++ /dev/null @@ -1,261 +0,0 @@ -/* - * This file was based upon code in Powertweak Linux (http://powertweak.sf.net) - * (C) 2000-2003 Dave Jones, Arjan van de Ven, Janne Pänkälä, - * Dominik Brodowski. - * - * Licensed under the terms of the GNU GPL License version 2. - * - * BIG FAT DISCLAIMER: Work in progress code. Possibly *dangerous* - */ - -#include -#include -#include -#include -#include -#include -#include - -#include - -#define POWERNOW_IOPORT 0xfff0 /* it doesn't matter where, as long - as it is unused */ - -#define PFX "powernow-k6: " -static unsigned int busfreq; /* FSB, in 10 kHz */ -static unsigned int max_multiplier; - - -/* Clock ratio multiplied by 10 - see table 27 in AMD#23446 */ -static struct cpufreq_frequency_table clock_ratio[] = { - {45, /* 000 -> 4.5x */ 0}, - {50, /* 001 -> 5.0x */ 0}, - {40, /* 010 -> 4.0x */ 0}, - {55, /* 011 -> 5.5x */ 0}, - {20, /* 100 -> 2.0x */ 0}, - {30, /* 101 -> 3.0x */ 0}, - {60, /* 110 -> 6.0x */ 0}, - {35, /* 111 -> 3.5x */ 0}, - {0, CPUFREQ_TABLE_END} -}; - - -/** - * powernow_k6_get_cpu_multiplier - returns the current FSB multiplier - * - * Returns the current setting of the frequency multiplier. Core clock - * speed is frequency of the Front-Side Bus multiplied with this value. - */ -static int powernow_k6_get_cpu_multiplier(void) -{ - u64 invalue = 0; - u32 msrval; - - msrval = POWERNOW_IOPORT + 0x1; - wrmsr(MSR_K6_EPMR, msrval, 0); /* enable the PowerNow port */ - invalue = inl(POWERNOW_IOPORT + 0x8); - msrval = POWERNOW_IOPORT + 0x0; - wrmsr(MSR_K6_EPMR, msrval, 0); /* disable it again */ - - return clock_ratio[(invalue >> 5)&7].index; -} - - -/** - * powernow_k6_set_state - set the PowerNow! multiplier - * @best_i: clock_ratio[best_i] is the target multiplier - * - * Tries to change the PowerNow! multiplier - */ -static void powernow_k6_set_state(unsigned int best_i) -{ - unsigned long outvalue = 0, invalue = 0; - unsigned long msrval; - struct cpufreq_freqs freqs; - - if (clock_ratio[best_i].index > max_multiplier) { - printk(KERN_ERR PFX "invalid target frequency\n"); - return; - } - - freqs.old = busfreq * powernow_k6_get_cpu_multiplier(); - freqs.new = busfreq * clock_ratio[best_i].index; - freqs.cpu = 0; /* powernow-k6.c is UP only driver */ - - cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE); - - /* we now need to transform best_i to the BVC format, see AMD#23446 */ - - outvalue = (1<<12) | (1<<10) | (1<<9) | (best_i<<5); - - msrval = POWERNOW_IOPORT + 0x1; - wrmsr(MSR_K6_EPMR, msrval, 0); /* enable the PowerNow port */ - invalue = inl(POWERNOW_IOPORT + 0x8); - invalue = invalue & 0xf; - outvalue = outvalue | invalue; - outl(outvalue , (POWERNOW_IOPORT + 0x8)); - msrval = POWERNOW_IOPORT + 0x0; - wrmsr(MSR_K6_EPMR, msrval, 0); /* disable it again */ - - cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE); - - return; -} - - -/** - * powernow_k6_verify - verifies a new CPUfreq policy - * @policy: new policy - * - * Policy must be within lowest and highest possible CPU Frequency, - * and at least one possible state must be within min and max. - */ -static int powernow_k6_verify(struct cpufreq_policy *policy) -{ - return cpufreq_frequency_table_verify(policy, &clock_ratio[0]); -} - - -/** - * powernow_k6_setpolicy - sets a new CPUFreq policy - * @policy: new policy - * @target_freq: the target frequency - * @relation: how that frequency relates to achieved frequency - * (CPUFREQ_RELATION_L or CPUFREQ_RELATION_H) - * - * sets a new CPUFreq policy - */ -static int powernow_k6_target(struct cpufreq_policy *policy, - unsigned int target_freq, - unsigned int relation) -{ - unsigned int newstate = 0; - - if (cpufreq_frequency_table_target(policy, &clock_ratio[0], - target_freq, relation, &newstate)) - return -EINVAL; - - powernow_k6_set_state(newstate); - - return 0; -} - - -static int powernow_k6_cpu_init(struct cpufreq_policy *policy) -{ - unsigned int i, f; - int result; - - if (policy->cpu != 0) - return -ENODEV; - - /* get frequencies */ - max_multiplier = powernow_k6_get_cpu_multiplier(); - busfreq = cpu_khz / max_multiplier; - - /* table init */ - for (i = 0; (clock_ratio[i].frequency != CPUFREQ_TABLE_END); i++) { - f = clock_ratio[i].index; - if (f > max_multiplier) - clock_ratio[i].frequency = CPUFREQ_ENTRY_INVALID; - else - clock_ratio[i].frequency = busfreq * f; - } - - /* cpuinfo and default policy values */ - policy->cpuinfo.transition_latency = 200000; - policy->cur = busfreq * max_multiplier; - - result = cpufreq_frequency_table_cpuinfo(policy, clock_ratio); - if (result) - return result; - - cpufreq_frequency_table_get_attr(clock_ratio, policy->cpu); - - return 0; -} - - -static int powernow_k6_cpu_exit(struct cpufreq_policy *policy) -{ - unsigned int i; - for (i = 0; i < 8; i++) { - if (i == max_multiplier) - powernow_k6_set_state(i); - } - cpufreq_frequency_table_put_attr(policy->cpu); - return 0; -} - -static unsigned int powernow_k6_get(unsigned int cpu) -{ - unsigned int ret; - ret = (busfreq * powernow_k6_get_cpu_multiplier()); - return ret; -} - -static struct freq_attr *powernow_k6_attr[] = { - &cpufreq_freq_attr_scaling_available_freqs, - NULL, -}; - -static struct cpufreq_driver powernow_k6_driver = { - .verify = powernow_k6_verify, - .target = powernow_k6_target, - .init = powernow_k6_cpu_init, - .exit = powernow_k6_cpu_exit, - .get = powernow_k6_get, - .name = "powernow-k6", - .owner = THIS_MODULE, - .attr = powernow_k6_attr, -}; - - -/** - * powernow_k6_init - initializes the k6 PowerNow! CPUFreq driver - * - * Initializes the K6 PowerNow! support. Returns -ENODEV on unsupported - * devices, -EINVAL or -ENOMEM on problems during initiatization, and zero - * on success. - */ -static int __init powernow_k6_init(void) -{ - struct cpuinfo_x86 *c = &cpu_data(0); - - if ((c->x86_vendor != X86_VENDOR_AMD) || (c->x86 != 5) || - ((c->x86_model != 12) && (c->x86_model != 13))) - return -ENODEV; - - if (!request_region(POWERNOW_IOPORT, 16, "PowerNow!")) { - printk(KERN_INFO PFX "PowerNow IOPORT region already used.\n"); - return -EIO; - } - - if (cpufreq_register_driver(&powernow_k6_driver)) { - release_region(POWERNOW_IOPORT, 16); - return -EINVAL; - } - - return 0; -} - - -/** - * powernow_k6_exit - unregisters AMD K6-2+/3+ PowerNow! support - * - * Unregisters AMD K6-2+ / K6-3+ PowerNow! support. - */ -static void __exit powernow_k6_exit(void) -{ - cpufreq_unregister_driver(&powernow_k6_driver); - release_region(POWERNOW_IOPORT, 16); -} - - -MODULE_AUTHOR("Arjan van de Ven, Dave Jones , " - "Dominik Brodowski "); -MODULE_DESCRIPTION("PowerNow! driver for AMD K6-2+ / K6-3+ processors."); -MODULE_LICENSE("GPL"); - -module_init(powernow_k6_init); -module_exit(powernow_k6_exit); diff --git a/arch/x86/kernel/cpu/cpufreq/powernow-k7.c b/arch/x86/kernel/cpu/cpufreq/powernow-k7.c deleted file mode 100644 index d71d9f3..0000000 --- a/arch/x86/kernel/cpu/cpufreq/powernow-k7.c +++ /dev/null @@ -1,747 +0,0 @@ -/* - * AMD K7 Powernow driver. - * (C) 2003 Dave Jones on behalf of SuSE Labs. - * (C) 2003-2004 Dave Jones - * - * Licensed under the terms of the GNU GPL License version 2. - * Based upon datasheets & sample CPUs kindly provided by AMD. - * - * Errata 5: - * CPU may fail to execute a FID/VID change in presence of interrupt. - * - We cli/sti on stepping A0 CPUs around the FID/VID transition. - * Errata 15: - * CPU with half frequency multipliers may hang upon wakeup from disconnect. - * - We disable half multipliers if ACPI is used on A0 stepping CPUs. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include /* Needed for recalibrate_cpu_khz() */ -#include -#include - -#ifdef CONFIG_X86_POWERNOW_K7_ACPI -#include -#include -#endif - -#include "powernow-k7.h" - -#define PFX "powernow: " - - -struct psb_s { - u8 signature[10]; - u8 tableversion; - u8 flags; - u16 settlingtime; - u8 reserved1; - u8 numpst; -}; - -struct pst_s { - u32 cpuid; - u8 fsbspeed; - u8 maxfid; - u8 startvid; - u8 numpstates; -}; - -#ifdef CONFIG_X86_POWERNOW_K7_ACPI -union powernow_acpi_control_t { - struct { - unsigned long fid:5, - vid:5, - sgtc:20, - res1:2; - } bits; - unsigned long val; -}; -#endif - -/* divide by 1000 to get VCore voltage in V. */ -static const int mobile_vid_table[32] = { - 2000, 1950, 1900, 1850, 1800, 1750, 1700, 1650, - 1600, 1550, 1500, 1450, 1400, 1350, 1300, 0, - 1275, 1250, 1225, 1200, 1175, 1150, 1125, 1100, - 1075, 1050, 1025, 1000, 975, 950, 925, 0, -}; - -/* divide by 10 to get FID. */ -static const int fid_codes[32] = { - 110, 115, 120, 125, 50, 55, 60, 65, - 70, 75, 80, 85, 90, 95, 100, 105, - 30, 190, 40, 200, 130, 135, 140, 210, - 150, 225, 160, 165, 170, 180, -1, -1, -}; - -/* This parameter is used in order to force ACPI instead of legacy method for - * configuration purpose. - */ - -static int acpi_force; - -static struct cpufreq_frequency_table *powernow_table; - -static unsigned int can_scale_bus; -static unsigned int can_scale_vid; -static unsigned int minimum_speed = -1; -static unsigned int maximum_speed; -static unsigned int number_scales; -static unsigned int fsb; -static unsigned int latency; -static char have_a0; - -static int check_fsb(unsigned int fsbspeed) -{ - int delta; - unsigned int f = fsb / 1000; - - delta = (fsbspeed > f) ? fsbspeed - f : f - fsbspeed; - return delta < 5; -} - -static int check_powernow(void) -{ - struct cpuinfo_x86 *c = &cpu_data(0); - unsigned int maxei, eax, ebx, ecx, edx; - - if ((c->x86_vendor != X86_VENDOR_AMD) || (c->x86 != 6)) { -#ifdef MODULE - printk(KERN_INFO PFX "This module only works with " - "AMD K7 CPUs\n"); -#endif - return 0; - } - - /* Get maximum capabilities */ - maxei = cpuid_eax(0x80000000); - if (maxei < 0x80000007) { /* Any powernow info ? */ -#ifdef MODULE - printk(KERN_INFO PFX "No powernow capabilities detected\n"); -#endif - return 0; - } - - if ((c->x86_model == 6) && (c->x86_mask == 0)) { - printk(KERN_INFO PFX "K7 660[A0] core detected, " - "enabling errata workarounds\n"); - have_a0 = 1; - } - - cpuid(0x80000007, &eax, &ebx, &ecx, &edx); - - /* Check we can actually do something before we say anything.*/ - if (!(edx & (1 << 1 | 1 << 2))) - return 0; - - printk(KERN_INFO PFX "PowerNOW! Technology present. Can scale: "); - - if (edx & 1 << 1) { - printk("frequency"); - can_scale_bus = 1; - } - - if ((edx & (1 << 1 | 1 << 2)) == 0x6) - printk(" and "); - - if (edx & 1 << 2) { - printk("voltage"); - can_scale_vid = 1; - } - - printk(".\n"); - return 1; -} - -#ifdef CONFIG_X86_POWERNOW_K7_ACPI -static void invalidate_entry(unsigned int entry) -{ - powernow_table[entry].frequency = CPUFREQ_ENTRY_INVALID; -} -#endif - -static int get_ranges(unsigned char *pst) -{ - unsigned int j; - unsigned int speed; - u8 fid, vid; - - powernow_table = kzalloc((sizeof(struct cpufreq_frequency_table) * - (number_scales + 1)), GFP_KERNEL); - if (!powernow_table) - return -ENOMEM; - - for (j = 0 ; j < number_scales; j++) { - fid = *pst++; - - powernow_table[j].frequency = (fsb * fid_codes[fid]) / 10; - powernow_table[j].index = fid; /* lower 8 bits */ - - speed = powernow_table[j].frequency; - - if ((fid_codes[fid] % 10) == 5) { -#ifdef CONFIG_X86_POWERNOW_K7_ACPI - if (have_a0 == 1) - invalidate_entry(j); -#endif - } - - if (speed < minimum_speed) - minimum_speed = speed; - if (speed > maximum_speed) - maximum_speed = speed; - - vid = *pst++; - powernow_table[j].index |= (vid << 8); /* upper 8 bits */ - - pr_debug(" FID: 0x%x (%d.%dx [%dMHz]) " - "VID: 0x%x (%d.%03dV)\n", fid, fid_codes[fid] / 10, - fid_codes[fid] % 10, speed/1000, vid, - mobile_vid_table[vid]/1000, - mobile_vid_table[vid]%1000); - } - powernow_table[number_scales].frequency = CPUFREQ_TABLE_END; - powernow_table[number_scales].index = 0; - - return 0; -} - - -static void change_FID(int fid) -{ - union msr_fidvidctl fidvidctl; - - rdmsrl(MSR_K7_FID_VID_CTL, fidvidctl.val); - if (fidvidctl.bits.FID != fid) { - fidvidctl.bits.SGTC = latency; - fidvidctl.bits.FID = fid; - fidvidctl.bits.VIDC = 0; - fidvidctl.bits.FIDC = 1; - wrmsrl(MSR_K7_FID_VID_CTL, fidvidctl.val); - } -} - - -static void change_VID(int vid) -{ - union msr_fidvidctl fidvidctl; - - rdmsrl(MSR_K7_FID_VID_CTL, fidvidctl.val); - if (fidvidctl.bits.VID != vid) { - fidvidctl.bits.SGTC = latency; - fidvidctl.bits.VID = vid; - fidvidctl.bits.FIDC = 0; - fidvidctl.bits.VIDC = 1; - wrmsrl(MSR_K7_FID_VID_CTL, fidvidctl.val); - } -} - - -static void change_speed(unsigned int index) -{ - u8 fid, vid; - struct cpufreq_freqs freqs; - union msr_fidvidstatus fidvidstatus; - int cfid; - - /* fid are the lower 8 bits of the index we stored into - * the cpufreq frequency table in powernow_decode_bios, - * vid are the upper 8 bits. - */ - - fid = powernow_table[index].index & 0xFF; - vid = (powernow_table[index].index & 0xFF00) >> 8; - - freqs.cpu = 0; - - rdmsrl(MSR_K7_FID_VID_STATUS, fidvidstatus.val); - cfid = fidvidstatus.bits.CFID; - freqs.old = fsb * fid_codes[cfid] / 10; - - freqs.new = powernow_table[index].frequency; - - cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE); - - /* Now do the magic poking into the MSRs. */ - - if (have_a0 == 1) /* A0 errata 5 */ - local_irq_disable(); - - if (freqs.old > freqs.new) { - /* Going down, so change FID first */ - change_FID(fid); - change_VID(vid); - } else { - /* Going up, so change VID first */ - change_VID(vid); - change_FID(fid); - } - - - if (have_a0 == 1) - local_irq_enable(); - - cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE); -} - - -#ifdef CONFIG_X86_POWERNOW_K7_ACPI - -static struct acpi_processor_performance *acpi_processor_perf; - -static int powernow_acpi_init(void) -{ - int i; - int retval = 0; - union powernow_acpi_control_t pc; - - if (acpi_processor_perf != NULL && powernow_table != NULL) { - retval = -EINVAL; - goto err0; - } - - acpi_processor_perf = kzalloc(sizeof(struct acpi_processor_performance), - GFP_KERNEL); - if (!acpi_processor_perf) { - retval = -ENOMEM; - goto err0; - } - - if (!zalloc_cpumask_var(&acpi_processor_perf->shared_cpu_map, - GFP_KERNEL)) { - retval = -ENOMEM; - goto err05; - } - - if (acpi_processor_register_performance(acpi_processor_perf, 0)) { - retval = -EIO; - goto err1; - } - - if (acpi_processor_perf->control_register.space_id != - ACPI_ADR_SPACE_FIXED_HARDWARE) { - retval = -ENODEV; - goto err2; - } - - if (acpi_processor_perf->status_register.space_id != - ACPI_ADR_SPACE_FIXED_HARDWARE) { - retval = -ENODEV; - goto err2; - } - - number_scales = acpi_processor_perf->state_count; - - if (number_scales < 2) { - retval = -ENODEV; - goto err2; - } - - powernow_table = kzalloc((sizeof(struct cpufreq_frequency_table) * - (number_scales + 1)), GFP_KERNEL); - if (!powernow_table) { - retval = -ENOMEM; - goto err2; - } - - pc.val = (unsigned long) acpi_processor_perf->states[0].control; - for (i = 0; i < number_scales; i++) { - u8 fid, vid; - struct acpi_processor_px *state = - &acpi_processor_perf->states[i]; - unsigned int speed, speed_mhz; - - pc.val = (unsigned long) state->control; - pr_debug("acpi: P%d: %d MHz %d mW %d uS control %08x SGTC %d\n", - i, - (u32) state->core_frequency, - (u32) state->power, - (u32) state->transition_latency, - (u32) state->control, - pc.bits.sgtc); - - vid = pc.bits.vid; - fid = pc.bits.fid; - - powernow_table[i].frequency = fsb * fid_codes[fid] / 10; - powernow_table[i].index = fid; /* lower 8 bits */ - powernow_table[i].index |= (vid << 8); /* upper 8 bits */ - - speed = powernow_table[i].frequency; - speed_mhz = speed / 1000; - - /* processor_perflib will multiply the MHz value by 1000 to - * get a KHz value (e.g. 1266000). However, powernow-k7 works - * with true KHz values (e.g. 1266768). To ensure that all - * powernow frequencies are available, we must ensure that - * ACPI doesn't restrict them, so we round up the MHz value - * to ensure that perflib's computed KHz value is greater than - * or equal to powernow's KHz value. - */ - if (speed % 1000 > 0) - speed_mhz++; - - if ((fid_codes[fid] % 10) == 5) { - if (have_a0 == 1) - invalidate_entry(i); - } - - pr_debug(" FID: 0x%x (%d.%dx [%dMHz]) " - "VID: 0x%x (%d.%03dV)\n", fid, fid_codes[fid] / 10, - fid_codes[fid] % 10, speed_mhz, vid, - mobile_vid_table[vid]/1000, - mobile_vid_table[vid]%1000); - - if (state->core_frequency != speed_mhz) { - state->core_frequency = speed_mhz; - pr_debug(" Corrected ACPI frequency to %d\n", - speed_mhz); - } - - if (latency < pc.bits.sgtc) - latency = pc.bits.sgtc; - - if (speed < minimum_speed) - minimum_speed = speed; - if (speed > maximum_speed) - maximum_speed = speed; - } - - powernow_table[i].frequency = CPUFREQ_TABLE_END; - powernow_table[i].index = 0; - - /* notify BIOS that we exist */ - acpi_processor_notify_smm(THIS_MODULE); - - return 0; - -err2: - acpi_processor_unregister_performance(acpi_processor_perf, 0); -err1: - free_cpumask_var(acpi_processor_perf->shared_cpu_map); -err05: - kfree(acpi_processor_perf); -err0: - printk(KERN_WARNING PFX "ACPI perflib can not be used on " - "this platform\n"); - acpi_processor_perf = NULL; - return retval; -} -#else -static int powernow_acpi_init(void) -{ - printk(KERN_INFO PFX "no support for ACPI processor found." - " Please recompile your kernel with ACPI processor\n"); - return -EINVAL; -} -#endif - -static void print_pst_entry(struct pst_s *pst, unsigned int j) -{ - pr_debug("PST:%d (@%p)\n", j, pst); - pr_debug(" cpuid: 0x%x fsb: %d maxFID: 0x%x startvid: 0x%x\n", - pst->cpuid, pst->fsbspeed, pst->maxfid, pst->startvid); -} - -static int powernow_decode_bios(int maxfid, int startvid) -{ - struct psb_s *psb; - struct pst_s *pst; - unsigned int i, j; - unsigned char *p; - unsigned int etuple; - unsigned int ret; - - etuple = cpuid_eax(0x80000001); - - for (i = 0xC0000; i < 0xffff0 ; i += 16) { - - p = phys_to_virt(i); - - if (memcmp(p, "AMDK7PNOW!", 10) == 0) { - pr_debug("Found PSB header at %p\n", p); - psb = (struct psb_s *) p; - pr_debug("Table version: 0x%x\n", psb->tableversion); - if (psb->tableversion != 0x12) { - printk(KERN_INFO PFX "Sorry, only v1.2 tables" - " supported right now\n"); - return -ENODEV; - } - - pr_debug("Flags: 0x%x\n", psb->flags); - if ((psb->flags & 1) == 0) - pr_debug("Mobile voltage regulator\n"); - else - pr_debug("Desktop voltage regulator\n"); - - latency = psb->settlingtime; - if (latency < 100) { - printk(KERN_INFO PFX "BIOS set settling time " - "to %d microseconds. " - "Should be at least 100. " - "Correcting.\n", latency); - latency = 100; - } - pr_debug("Settling Time: %d microseconds.\n", - psb->settlingtime); - pr_debug("Has %d PST tables. (Only dumping ones " - "relevant to this CPU).\n", - psb->numpst); - - p += sizeof(struct psb_s); - - pst = (struct pst_s *) p; - - for (j = 0; j < psb->numpst; j++) { - pst = (struct pst_s *) p; - number_scales = pst->numpstates; - - if ((etuple == pst->cpuid) && - check_fsb(pst->fsbspeed) && - (maxfid == pst->maxfid) && - (startvid == pst->startvid)) { - print_pst_entry(pst, j); - p = (char *)pst + sizeof(struct pst_s); - ret = get_ranges(p); - return ret; - } else { - unsigned int k; - p = (char *)pst + sizeof(struct pst_s); - for (k = 0; k < number_scales; k++) - p += 2; - } - } - printk(KERN_INFO PFX "No PST tables match this cpuid " - "(0x%x)\n", etuple); - printk(KERN_INFO PFX "This is indicative of a broken " - "BIOS.\n"); - - return -EINVAL; - } - p++; - } - - return -ENODEV; -} - - -static int powernow_target(struct cpufreq_policy *policy, - unsigned int target_freq, - unsigned int relation) -{ - unsigned int newstate; - - if (cpufreq_frequency_table_target(policy, powernow_table, target_freq, - relation, &newstate)) - return -EINVAL; - - change_speed(newstate); - - return 0; -} - - -static int powernow_verify(struct cpufreq_policy *policy) -{ - return cpufreq_frequency_table_verify(policy, powernow_table); -} - -/* - * We use the fact that the bus frequency is somehow - * a multiple of 100000/3 khz, then we compute sgtc according - * to this multiple. - * That way, we match more how AMD thinks all of that work. - * We will then get the same kind of behaviour already tested under - * the "well-known" other OS. - */ -static int __cpuinit fixup_sgtc(void) -{ - unsigned int sgtc; - unsigned int m; - - m = fsb / 3333; - if ((m % 10) >= 5) - m += 5; - - m /= 10; - - sgtc = 100 * m * latency; - sgtc = sgtc / 3; - if (sgtc > 0xfffff) { - printk(KERN_WARNING PFX "SGTC too large %d\n", sgtc); - sgtc = 0xfffff; - } - return sgtc; -} - -static unsigned int powernow_get(unsigned int cpu) -{ - union msr_fidvidstatus fidvidstatus; - unsigned int cfid; - - if (cpu) - return 0; - rdmsrl(MSR_K7_FID_VID_STATUS, fidvidstatus.val); - cfid = fidvidstatus.bits.CFID; - - return fsb * fid_codes[cfid] / 10; -} - - -static int __cpuinit acer_cpufreq_pst(const struct dmi_system_id *d) -{ - printk(KERN_WARNING PFX - "%s laptop with broken PST tables in BIOS detected.\n", - d->ident); - printk(KERN_WARNING PFX - "You need to downgrade to 3A21 (09/09/2002), or try a newer " - "BIOS than 3A71 (01/20/2003)\n"); - printk(KERN_WARNING PFX - "cpufreq scaling has been disabled as a result of this.\n"); - return 0; -} - -/* - * Some Athlon laptops have really fucked PST tables. - * A BIOS update is all that can save them. - * Mention this, and disable cpufreq. - */ -static struct dmi_system_id __cpuinitdata powernow_dmi_table[] = { - { - .callback = acer_cpufreq_pst, - .ident = "Acer Aspire", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "Insyde Software"), - DMI_MATCH(DMI_BIOS_VERSION, "3A71"), - }, - }, - { } -}; - -static int __cpuinit powernow_cpu_init(struct cpufreq_policy *policy) -{ - union msr_fidvidstatus fidvidstatus; - int result; - - if (policy->cpu != 0) - return -ENODEV; - - rdmsrl(MSR_K7_FID_VID_STATUS, fidvidstatus.val); - - recalibrate_cpu_khz(); - - fsb = (10 * cpu_khz) / fid_codes[fidvidstatus.bits.CFID]; - if (!fsb) { - printk(KERN_WARNING PFX "can not determine bus frequency\n"); - return -EINVAL; - } - pr_debug("FSB: %3dMHz\n", fsb/1000); - - if (dmi_check_system(powernow_dmi_table) || acpi_force) { - printk(KERN_INFO PFX "PSB/PST known to be broken. " - "Trying ACPI instead\n"); - result = powernow_acpi_init(); - } else { - result = powernow_decode_bios(fidvidstatus.bits.MFID, - fidvidstatus.bits.SVID); - if (result) { - printk(KERN_INFO PFX "Trying ACPI perflib\n"); - maximum_speed = 0; - minimum_speed = -1; - latency = 0; - result = powernow_acpi_init(); - if (result) { - printk(KERN_INFO PFX - "ACPI and legacy methods failed\n"); - } - } else { - /* SGTC use the bus clock as timer */ - latency = fixup_sgtc(); - printk(KERN_INFO PFX "SGTC: %d\n", latency); - } - } - - if (result) - return result; - - printk(KERN_INFO PFX "Minimum speed %d MHz. Maximum speed %d MHz.\n", - minimum_speed/1000, maximum_speed/1000); - - policy->cpuinfo.transition_latency = - cpufreq_scale(2000000UL, fsb, latency); - - policy->cur = powernow_get(0); - - cpufreq_frequency_table_get_attr(powernow_table, policy->cpu); - - return cpufreq_frequency_table_cpuinfo(policy, powernow_table); -} - -static int powernow_cpu_exit(struct cpufreq_policy *policy) -{ - cpufreq_frequency_table_put_attr(policy->cpu); - -#ifdef CONFIG_X86_POWERNOW_K7_ACPI - if (acpi_processor_perf) { - acpi_processor_unregister_performance(acpi_processor_perf, 0); - free_cpumask_var(acpi_processor_perf->shared_cpu_map); - kfree(acpi_processor_perf); - } -#endif - - kfree(powernow_table); - return 0; -} - -static struct freq_attr *powernow_table_attr[] = { - &cpufreq_freq_attr_scaling_available_freqs, - NULL, -}; - -static struct cpufreq_driver powernow_driver = { - .verify = powernow_verify, - .target = powernow_target, - .get = powernow_get, -#ifdef CONFIG_X86_POWERNOW_K7_ACPI - .bios_limit = acpi_processor_get_bios_limit, -#endif - .init = powernow_cpu_init, - .exit = powernow_cpu_exit, - .name = "powernow-k7", - .owner = THIS_MODULE, - .attr = powernow_table_attr, -}; - -static int __init powernow_init(void) -{ - if (check_powernow() == 0) - return -ENODEV; - return cpufreq_register_driver(&powernow_driver); -} - - -static void __exit powernow_exit(void) -{ - cpufreq_unregister_driver(&powernow_driver); -} - -module_param(acpi_force, int, 0444); -MODULE_PARM_DESC(acpi_force, "Force ACPI to be used."); - -MODULE_AUTHOR("Dave Jones "); -MODULE_DESCRIPTION("Powernow driver for AMD K7 processors."); -MODULE_LICENSE("GPL"); - -late_initcall(powernow_init); -module_exit(powernow_exit); - diff --git a/arch/x86/kernel/cpu/cpufreq/powernow-k7.h b/arch/x86/kernel/cpu/cpufreq/powernow-k7.h deleted file mode 100644 index 35fb4ea..0000000 --- a/arch/x86/kernel/cpu/cpufreq/powernow-k7.h +++ /dev/null @@ -1,43 +0,0 @@ -/* - * (C) 2003 Dave Jones. - * - * Licensed under the terms of the GNU GPL License version 2. - * - * AMD-specific information - * - */ - -union msr_fidvidctl { - struct { - unsigned FID:5, // 4:0 - reserved1:3, // 7:5 - VID:5, // 12:8 - reserved2:3, // 15:13 - FIDC:1, // 16 - VIDC:1, // 17 - reserved3:2, // 19:18 - FIDCHGRATIO:1, // 20 - reserved4:11, // 31-21 - SGTC:20, // 32:51 - reserved5:12; // 63:52 - } bits; - unsigned long long val; -}; - -union msr_fidvidstatus { - struct { - unsigned CFID:5, // 4:0 - reserved1:3, // 7:5 - SFID:5, // 12:8 - reserved2:3, // 15:13 - MFID:5, // 20:16 - reserved3:11, // 31:21 - CVID:5, // 36:32 - reserved4:3, // 39:37 - SVID:5, // 44:40 - reserved5:3, // 47:45 - MVID:5, // 52:48 - reserved6:11; // 63:53 - } bits; - unsigned long long val; -}; diff --git a/arch/x86/kernel/cpu/cpufreq/powernow-k8.c b/arch/x86/kernel/cpu/cpufreq/powernow-k8.c deleted file mode 100644 index 83479b6..0000000 --- a/arch/x86/kernel/cpu/cpufreq/powernow-k8.c +++ /dev/null @@ -1,1607 +0,0 @@ -/* - * (c) 2003-2010 Advanced Micro Devices, Inc. - * Your use of this code is subject to the terms and conditions of the - * GNU general public license version 2. See "COPYING" or - * http://www.gnu.org/licenses/gpl.html - * - * Support : mark.langsdorf@amd.com - * - * Based on the powernow-k7.c module written by Dave Jones. - * (C) 2003 Dave Jones on behalf of SuSE Labs - * (C) 2004 Dominik Brodowski - * (C) 2004 Pavel Machek - * Licensed under the terms of the GNU GPL License version 2. - * Based upon datasheets & sample CPUs kindly provided by AMD. - * - * Valuable input gratefully received from Dave Jones, Pavel Machek, - * Dominik Brodowski, Jacob Shin, and others. - * Originally developed by Paul Devriendt. - * Processor information obtained from Chapter 9 (Power and Thermal Management) - * of the "BIOS and Kernel Developer's Guide for the AMD Athlon 64 and AMD - * Opteron Processors" available for download from www.amd.com - * - * Tables for specific CPUs can be inferred from - * http://www.amd.com/us-en/assets/content_type/white_papers_and_tech_docs/30430.pdf - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include /* for current / set_cpus_allowed() */ -#include -#include - -#include - -#include -#include -#include - -#define PFX "powernow-k8: " -#define VERSION "version 2.20.00" -#include "powernow-k8.h" -#include "mperf.h" - -/* serialize freq changes */ -static DEFINE_MUTEX(fidvid_mutex); - -static DEFINE_PER_CPU(struct powernow_k8_data *, powernow_data); - -static int cpu_family = CPU_OPTERON; - -/* core performance boost */ -static bool cpb_capable, cpb_enabled; -static struct msr __percpu *msrs; - -static struct cpufreq_driver cpufreq_amd64_driver; - -#ifndef CONFIG_SMP -static inline const struct cpumask *cpu_core_mask(int cpu) -{ - return cpumask_of(0); -} -#endif - -/* Return a frequency in MHz, given an input fid */ -static u32 find_freq_from_fid(u32 fid) -{ - return 800 + (fid * 100); -} - -/* Return a frequency in KHz, given an input fid */ -static u32 find_khz_freq_from_fid(u32 fid) -{ - return 1000 * find_freq_from_fid(fid); -} - -static u32 find_khz_freq_from_pstate(struct cpufreq_frequency_table *data, - u32 pstate) -{ - return data[pstate].frequency; -} - -/* Return the vco fid for an input fid - * - * Each "low" fid has corresponding "high" fid, and you can get to "low" fids - * only from corresponding high fids. This returns "high" fid corresponding to - * "low" one. - */ -static u32 convert_fid_to_vco_fid(u32 fid) -{ - if (fid < HI_FID_TABLE_BOTTOM) - return 8 + (2 * fid); - else - return fid; -} - -/* - * Return 1 if the pending bit is set. Unless we just instructed the processor - * to transition to a new state, seeing this bit set is really bad news. - */ -static int pending_bit_stuck(void) -{ - u32 lo, hi; - - if (cpu_family == CPU_HW_PSTATE) - return 0; - - rdmsr(MSR_FIDVID_STATUS, lo, hi); - return lo & MSR_S_LO_CHANGE_PENDING ? 1 : 0; -} - -/* - * Update the global current fid / vid values from the status msr. - * Returns 1 on error. - */ -static int query_current_values_with_pending_wait(struct powernow_k8_data *data) -{ - u32 lo, hi; - u32 i = 0; - - if (cpu_family == CPU_HW_PSTATE) { - rdmsr(MSR_PSTATE_STATUS, lo, hi); - i = lo & HW_PSTATE_MASK; - data->currpstate = i; - - /* - * a workaround for family 11h erratum 311 might cause - * an "out-of-range Pstate if the core is in Pstate-0 - */ - if ((boot_cpu_data.x86 == 0x11) && (i >= data->numps)) - data->currpstate = HW_PSTATE_0; - - return 0; - } - do { - if (i++ > 10000) { - pr_debug("detected change pending stuck\n"); - return 1; - } - rdmsr(MSR_FIDVID_STATUS, lo, hi); - } while (lo & MSR_S_LO_CHANGE_PENDING); - - data->currvid = hi & MSR_S_HI_CURRENT_VID; - data->currfid = lo & MSR_S_LO_CURRENT_FID; - - return 0; -} - -/* the isochronous relief time */ -static void count_off_irt(struct powernow_k8_data *data) -{ - udelay((1 << data->irt) * 10); - return; -} - -/* the voltage stabilization time */ -static void count_off_vst(struct powernow_k8_data *data) -{ - udelay(data->vstable * VST_UNITS_20US); - return; -} - -/* need to init the control msr to a safe value (for each cpu) */ -static void fidvid_msr_init(void) -{ - u32 lo, hi; - u8 fid, vid; - - rdmsr(MSR_FIDVID_STATUS, lo, hi); - vid = hi & MSR_S_HI_CURRENT_VID; - fid = lo & MSR_S_LO_CURRENT_FID; - lo = fid | (vid << MSR_C_LO_VID_SHIFT); - hi = MSR_C_HI_STP_GNT_BENIGN; - pr_debug("cpu%d, init lo 0x%x, hi 0x%x\n", smp_processor_id(), lo, hi); - wrmsr(MSR_FIDVID_CTL, lo, hi); -} - -/* write the new fid value along with the other control fields to the msr */ -static int write_new_fid(struct powernow_k8_data *data, u32 fid) -{ - u32 lo; - u32 savevid = data->currvid; - u32 i = 0; - - if ((fid & INVALID_FID_MASK) || (data->currvid & INVALID_VID_MASK)) { - printk(KERN_ERR PFX "internal error - overflow on fid write\n"); - return 1; - } - - lo = fid; - lo |= (data->currvid << MSR_C_LO_VID_SHIFT); - lo |= MSR_C_LO_INIT_FID_VID; - - pr_debug("writing fid 0x%x, lo 0x%x, hi 0x%x\n", - fid, lo, data->plllock * PLL_LOCK_CONVERSION); - - do { - wrmsr(MSR_FIDVID_CTL, lo, data->plllock * PLL_LOCK_CONVERSION); - if (i++ > 100) { - printk(KERN_ERR PFX - "Hardware error - pending bit very stuck - " - "no further pstate changes possible\n"); - return 1; - } - } while (query_current_values_with_pending_wait(data)); - - count_off_irt(data); - - if (savevid != data->currvid) { - printk(KERN_ERR PFX - "vid change on fid trans, old 0x%x, new 0x%x\n", - savevid, data->currvid); - return 1; - } - - if (fid != data->currfid) { - printk(KERN_ERR PFX - "fid trans failed, fid 0x%x, curr 0x%x\n", fid, - data->currfid); - return 1; - } - - return 0; -} - -/* Write a new vid to the hardware */ -static int write_new_vid(struct powernow_k8_data *data, u32 vid) -{ - u32 lo; - u32 savefid = data->currfid; - int i = 0; - - if ((data->currfid & INVALID_FID_MASK) || (vid & INVALID_VID_MASK)) { - printk(KERN_ERR PFX "internal error - overflow on vid write\n"); - return 1; - } - - lo = data->currfid; - lo |= (vid << MSR_C_LO_VID_SHIFT); - lo |= MSR_C_LO_INIT_FID_VID; - - pr_debug("writing vid 0x%x, lo 0x%x, hi 0x%x\n", - vid, lo, STOP_GRANT_5NS); - - do { - wrmsr(MSR_FIDVID_CTL, lo, STOP_GRANT_5NS); - if (i++ > 100) { - printk(KERN_ERR PFX "internal error - pending bit " - "very stuck - no further pstate " - "changes possible\n"); - return 1; - } - } while (query_current_values_with_pending_wait(data)); - - if (savefid != data->currfid) { - printk(KERN_ERR PFX "fid changed on vid trans, old " - "0x%x new 0x%x\n", - savefid, data->currfid); - return 1; - } - - if (vid != data->currvid) { - printk(KERN_ERR PFX "vid trans failed, vid 0x%x, " - "curr 0x%x\n", - vid, data->currvid); - return 1; - } - - return 0; -} - -/* - * Reduce the vid by the max of step or reqvid. - * Decreasing vid codes represent increasing voltages: - * vid of 0 is 1.550V, vid of 0x1e is 0.800V, vid of VID_OFF is off. - */ -static int decrease_vid_code_by_step(struct powernow_k8_data *data, - u32 reqvid, u32 step) -{ - if ((data->currvid - reqvid) > step) - reqvid = data->currvid - step; - - if (write_new_vid(data, reqvid)) - return 1; - - count_off_vst(data); - - return 0; -} - -/* Change hardware pstate by single MSR write */ -static int transition_pstate(struct powernow_k8_data *data, u32 pstate) -{ - wrmsr(MSR_PSTATE_CTRL, pstate, 0); - data->currpstate = pstate; - return 0; -} - -/* Change Opteron/Athlon64 fid and vid, by the 3 phases. */ -static int transition_fid_vid(struct powernow_k8_data *data, - u32 reqfid, u32 reqvid) -{ - if (core_voltage_pre_transition(data, reqvid, reqfid)) - return 1; - - if (core_frequency_transition(data, reqfid)) - return 1; - - if (core_voltage_post_transition(data, reqvid)) - return 1; - - if (query_current_values_with_pending_wait(data)) - return 1; - - if ((reqfid != data->currfid) || (reqvid != data->currvid)) { - printk(KERN_ERR PFX "failed (cpu%d): req 0x%x 0x%x, " - "curr 0x%x 0x%x\n", - smp_processor_id(), - reqfid, reqvid, data->currfid, data->currvid); - return 1; - } - - pr_debug("transitioned (cpu%d): new fid 0x%x, vid 0x%x\n", - smp_processor_id(), data->currfid, data->currvid); - - return 0; -} - -/* Phase 1 - core voltage transition ... setup voltage */ -static int core_voltage_pre_transition(struct powernow_k8_data *data, - u32 reqvid, u32 reqfid) -{ - u32 rvosteps = data->rvo; - u32 savefid = data->currfid; - u32 maxvid, lo, rvomult = 1; - - pr_debug("ph1 (cpu%d): start, currfid 0x%x, currvid 0x%x, " - "reqvid 0x%x, rvo 0x%x\n", - smp_processor_id(), - data->currfid, data->currvid, reqvid, data->rvo); - - if ((savefid < LO_FID_TABLE_TOP) && (reqfid < LO_FID_TABLE_TOP)) - rvomult = 2; - rvosteps *= rvomult; - rdmsr(MSR_FIDVID_STATUS, lo, maxvid); - maxvid = 0x1f & (maxvid >> 16); - pr_debug("ph1 maxvid=0x%x\n", maxvid); - if (reqvid < maxvid) /* lower numbers are higher voltages */ - reqvid = maxvid; - - while (data->currvid > reqvid) { - pr_debug("ph1: curr 0x%x, req vid 0x%x\n", - data->currvid, reqvid); - if (decrease_vid_code_by_step(data, reqvid, data->vidmvs)) - return 1; - } - - while ((rvosteps > 0) && - ((rvomult * data->rvo + data->currvid) > reqvid)) { - if (data->currvid == maxvid) { - rvosteps = 0; - } else { - pr_debug("ph1: changing vid for rvo, req 0x%x\n", - data->currvid - 1); - if (decrease_vid_code_by_step(data, data->currvid-1, 1)) - return 1; - rvosteps--; - } - } - - if (query_current_values_with_pending_wait(data)) - return 1; - - if (savefid != data->currfid) { - printk(KERN_ERR PFX "ph1 err, currfid changed 0x%x\n", - data->currfid); - return 1; - } - - pr_debug("ph1 complete, currfid 0x%x, currvid 0x%x\n", - data->currfid, data->currvid); - - return 0; -} - -/* Phase 2 - core frequency transition */ -static int core_frequency_transition(struct powernow_k8_data *data, u32 reqfid) -{ - u32 vcoreqfid, vcocurrfid, vcofiddiff; - u32 fid_interval, savevid = data->currvid; - - if (data->currfid == reqfid) { - printk(KERN_ERR PFX "ph2 null fid transition 0x%x\n", - data->currfid); - return 0; - } - - pr_debug("ph2 (cpu%d): starting, currfid 0x%x, currvid 0x%x, " - "reqfid 0x%x\n", - smp_processor_id(), - data->currfid, data->currvid, reqfid); - - vcoreqfid = convert_fid_to_vco_fid(reqfid); - vcocurrfid = convert_fid_to_vco_fid(data->currfid); - vcofiddiff = vcocurrfid > vcoreqfid ? vcocurrfid - vcoreqfid - : vcoreqfid - vcocurrfid; - - if ((reqfid <= LO_FID_TABLE_TOP) && (data->currfid <= LO_FID_TABLE_TOP)) - vcofiddiff = 0; - - while (vcofiddiff > 2) { - (data->currfid & 1) ? (fid_interval = 1) : (fid_interval = 2); - - if (reqfid > data->currfid) { - if (data->currfid > LO_FID_TABLE_TOP) { - if (write_new_fid(data, - data->currfid + fid_interval)) - return 1; - } else { - if (write_new_fid - (data, - 2 + convert_fid_to_vco_fid(data->currfid))) - return 1; - } - } else { - if (write_new_fid(data, data->currfid - fid_interval)) - return 1; - } - - vcocurrfid = convert_fid_to_vco_fid(data->currfid); - vcofiddiff = vcocurrfid > vcoreqfid ? vcocurrfid - vcoreqfid - : vcoreqfid - vcocurrfid; - } - - if (write_new_fid(data, reqfid)) - return 1; - - if (query_current_values_with_pending_wait(data)) - return 1; - - if (data->currfid != reqfid) { - printk(KERN_ERR PFX - "ph2: mismatch, failed fid transition, " - "curr 0x%x, req 0x%x\n", - data->currfid, reqfid); - return 1; - } - - if (savevid != data->currvid) { - printk(KERN_ERR PFX "ph2: vid changed, save 0x%x, curr 0x%x\n", - savevid, data->currvid); - return 1; - } - - pr_debug("ph2 complete, currfid 0x%x, currvid 0x%x\n", - data->currfid, data->currvid); - - return 0; -} - -/* Phase 3 - core voltage transition flow ... jump to the final vid. */ -static int core_voltage_post_transition(struct powernow_k8_data *data, - u32 reqvid) -{ - u32 savefid = data->currfid; - u32 savereqvid = reqvid; - - pr_debug("ph3 (cpu%d): starting, currfid 0x%x, currvid 0x%x\n", - smp_processor_id(), - data->currfid, data->currvid); - - if (reqvid != data->currvid) { - if (write_new_vid(data, reqvid)) - return 1; - - if (savefid != data->currfid) { - printk(KERN_ERR PFX - "ph3: bad fid change, save 0x%x, curr 0x%x\n", - savefid, data->currfid); - return 1; - } - - if (data->currvid != reqvid) { - printk(KERN_ERR PFX - "ph3: failed vid transition\n, " - "req 0x%x, curr 0x%x", - reqvid, data->currvid); - return 1; - } - } - - if (query_current_values_with_pending_wait(data)) - return 1; - - if (savereqvid != data->currvid) { - pr_debug("ph3 failed, currvid 0x%x\n", data->currvid); - return 1; - } - - if (savefid != data->currfid) { - pr_debug("ph3 failed, currfid changed 0x%x\n", - data->currfid); - return 1; - } - - pr_debug("ph3 complete, currfid 0x%x, currvid 0x%x\n", - data->currfid, data->currvid); - - return 0; -} - -static void check_supported_cpu(void *_rc) -{ - u32 eax, ebx, ecx, edx; - int *rc = _rc; - - *rc = -ENODEV; - - if (__this_cpu_read(cpu_info.x86_vendor) != X86_VENDOR_AMD) - return; - - eax = cpuid_eax(CPUID_PROCESSOR_SIGNATURE); - if (((eax & CPUID_XFAM) != CPUID_XFAM_K8) && - ((eax & CPUID_XFAM) < CPUID_XFAM_10H)) - return; - - if ((eax & CPUID_XFAM) == CPUID_XFAM_K8) { - if (((eax & CPUID_USE_XFAM_XMOD) != CPUID_USE_XFAM_XMOD) || - ((eax & CPUID_XMOD) > CPUID_XMOD_REV_MASK)) { - printk(KERN_INFO PFX - "Processor cpuid %x not supported\n", eax); - return; - } - - eax = cpuid_eax(CPUID_GET_MAX_CAPABILITIES); - if (eax < CPUID_FREQ_VOLT_CAPABILITIES) { - printk(KERN_INFO PFX - "No frequency change capabilities detected\n"); - return; - } - - cpuid(CPUID_FREQ_VOLT_CAPABILITIES, &eax, &ebx, &ecx, &edx); - if ((edx & P_STATE_TRANSITION_CAPABLE) - != P_STATE_TRANSITION_CAPABLE) { - printk(KERN_INFO PFX - "Power state transitions not supported\n"); - return; - } - } else { /* must be a HW Pstate capable processor */ - cpuid(CPUID_FREQ_VOLT_CAPABILITIES, &eax, &ebx, &ecx, &edx); - if ((edx & USE_HW_PSTATE) == USE_HW_PSTATE) - cpu_family = CPU_HW_PSTATE; - else - return; - } - - *rc = 0; -} - -static int check_pst_table(struct powernow_k8_data *data, struct pst_s *pst, - u8 maxvid) -{ - unsigned int j; - u8 lastfid = 0xff; - - for (j = 0; j < data->numps; j++) { - if (pst[j].vid > LEAST_VID) { - printk(KERN_ERR FW_BUG PFX "vid %d invalid : 0x%x\n", - j, pst[j].vid); - return -EINVAL; - } - if (pst[j].vid < data->rvo) { - /* vid + rvo >= 0 */ - printk(KERN_ERR FW_BUG PFX "0 vid exceeded with pstate" - " %d\n", j); - return -ENODEV; - } - if (pst[j].vid < maxvid + data->rvo) { - /* vid + rvo >= maxvid */ - printk(KERN_ERR FW_BUG PFX "maxvid exceeded with pstate" - " %d\n", j); - return -ENODEV; - } - if (pst[j].fid > MAX_FID) { - printk(KERN_ERR FW_BUG PFX "maxfid exceeded with pstate" - " %d\n", j); - return -ENODEV; - } - if (j && (pst[j].fid < HI_FID_TABLE_BOTTOM)) { - /* Only first fid is allowed to be in "low" range */ - printk(KERN_ERR FW_BUG PFX "two low fids - %d : " - "0x%x\n", j, pst[j].fid); - return -EINVAL; - } - if (pst[j].fid < lastfid) - lastfid = pst[j].fid; - } - if (lastfid & 1) { - printk(KERN_ERR FW_BUG PFX "lastfid invalid\n"); - return -EINVAL; - } - if (lastfid > LO_FID_TABLE_TOP) - printk(KERN_INFO FW_BUG PFX - "first fid not from lo freq table\n"); - - return 0; -} - -static void invalidate_entry(struct cpufreq_frequency_table *powernow_table, - unsigned int entry) -{ - powernow_table[entry].frequency = CPUFREQ_ENTRY_INVALID; -} - -static void print_basics(struct powernow_k8_data *data) -{ - int j; - for (j = 0; j < data->numps; j++) { - if (data->powernow_table[j].frequency != - CPUFREQ_ENTRY_INVALID) { - if (cpu_family == CPU_HW_PSTATE) { - printk(KERN_INFO PFX - " %d : pstate %d (%d MHz)\n", j, - data->powernow_table[j].index, - data->powernow_table[j].frequency/1000); - } else { - printk(KERN_INFO PFX - "fid 0x%x (%d MHz), vid 0x%x\n", - data->powernow_table[j].index & 0xff, - data->powernow_table[j].frequency/1000, - data->powernow_table[j].index >> 8); - } - } - } - if (data->batps) - printk(KERN_INFO PFX "Only %d pstates on battery\n", - data->batps); -} - -static u32 freq_from_fid_did(u32 fid, u32 did) -{ - u32 mhz = 0; - - if (boot_cpu_data.x86 == 0x10) - mhz = (100 * (fid + 0x10)) >> did; - else if (boot_cpu_data.x86 == 0x11) - mhz = (100 * (fid + 8)) >> did; - else - BUG(); - - return mhz * 1000; -} - -static int fill_powernow_table(struct powernow_k8_data *data, - struct pst_s *pst, u8 maxvid) -{ - struct cpufreq_frequency_table *powernow_table; - unsigned int j; - - if (data->batps) { - /* use ACPI support to get full speed on mains power */ - printk(KERN_WARNING PFX - "Only %d pstates usable (use ACPI driver for full " - "range\n", data->batps); - data->numps = data->batps; - } - - for (j = 1; j < data->numps; j++) { - if (pst[j-1].fid >= pst[j].fid) { - printk(KERN_ERR PFX "PST out of sequence\n"); - return -EINVAL; - } - } - - if (data->numps < 2) { - printk(KERN_ERR PFX "no p states to transition\n"); - return -ENODEV; - } - - if (check_pst_table(data, pst, maxvid)) - return -EINVAL; - - powernow_table = kmalloc((sizeof(struct cpufreq_frequency_table) - * (data->numps + 1)), GFP_KERNEL); - if (!powernow_table) { - printk(KERN_ERR PFX "powernow_table memory alloc failure\n"); - return -ENOMEM; - } - - for (j = 0; j < data->numps; j++) { - int freq; - powernow_table[j].index = pst[j].fid; /* lower 8 bits */ - powernow_table[j].index |= (pst[j].vid << 8); /* upper 8 bits */ - freq = find_khz_freq_from_fid(pst[j].fid); - powernow_table[j].frequency = freq; - } - powernow_table[data->numps].frequency = CPUFREQ_TABLE_END; - powernow_table[data->numps].index = 0; - - if (query_current_values_with_pending_wait(data)) { - kfree(powernow_table); - return -EIO; - } - - pr_debug("cfid 0x%x, cvid 0x%x\n", data->currfid, data->currvid); - data->powernow_table = powernow_table; - if (cpumask_first(cpu_core_mask(data->cpu)) == data->cpu) - print_basics(data); - - for (j = 0; j < data->numps; j++) - if ((pst[j].fid == data->currfid) && - (pst[j].vid == data->currvid)) - return 0; - - pr_debug("currfid/vid do not match PST, ignoring\n"); - return 0; -} - -/* Find and validate the PSB/PST table in BIOS. */ -static int find_psb_table(struct powernow_k8_data *data) -{ - struct psb_s *psb; - unsigned int i; - u32 mvs; - u8 maxvid; - u32 cpst = 0; - u32 thiscpuid; - - for (i = 0xc0000; i < 0xffff0; i += 0x10) { - /* Scan BIOS looking for the signature. */ - /* It can not be at ffff0 - it is too big. */ - - psb = phys_to_virt(i); - if (memcmp(psb, PSB_ID_STRING, PSB_ID_STRING_LEN) != 0) - continue; - - pr_debug("found PSB header at 0x%p\n", psb); - - pr_debug("table vers: 0x%x\n", psb->tableversion); - if (psb->tableversion != PSB_VERSION_1_4) { - printk(KERN_ERR FW_BUG PFX "PSB table is not v1.4\n"); - return -ENODEV; - } - - pr_debug("flags: 0x%x\n", psb->flags1); - if (psb->flags1) { - printk(KERN_ERR FW_BUG PFX "unknown flags\n"); - return -ENODEV; - } - - data->vstable = psb->vstable; - pr_debug("voltage stabilization time: %d(*20us)\n", - data->vstable); - - pr_debug("flags2: 0x%x\n", psb->flags2); - data->rvo = psb->flags2 & 3; - data->irt = ((psb->flags2) >> 2) & 3; - mvs = ((psb->flags2) >> 4) & 3; - data->vidmvs = 1 << mvs; - data->batps = ((psb->flags2) >> 6) & 3; - - pr_debug("ramp voltage offset: %d\n", data->rvo); - pr_debug("isochronous relief time: %d\n", data->irt); - pr_debug("maximum voltage step: %d - 0x%x\n", mvs, data->vidmvs); - - pr_debug("numpst: 0x%x\n", psb->num_tables); - cpst = psb->num_tables; - if ((psb->cpuid == 0x00000fc0) || - (psb->cpuid == 0x00000fe0)) { - thiscpuid = cpuid_eax(CPUID_PROCESSOR_SIGNATURE); - if ((thiscpuid == 0x00000fc0) || - (thiscpuid == 0x00000fe0)) - cpst = 1; - } - if (cpst != 1) { - printk(KERN_ERR FW_BUG PFX "numpst must be 1\n"); - return -ENODEV; - } - - data->plllock = psb->plllocktime; - pr_debug("plllocktime: 0x%x (units 1us)\n", psb->plllocktime); - pr_debug("maxfid: 0x%x\n", psb->maxfid); - pr_debug("maxvid: 0x%x\n", psb->maxvid); - maxvid = psb->maxvid; - - data->numps = psb->numps; - pr_debug("numpstates: 0x%x\n", data->numps); - return fill_powernow_table(data, - (struct pst_s *)(psb+1), maxvid); - } - /* - * If you see this message, complain to BIOS manufacturer. If - * he tells you "we do not support Linux" or some similar - * nonsense, remember that Windows 2000 uses the same legacy - * mechanism that the old Linux PSB driver uses. Tell them it - * is broken with Windows 2000. - * - * The reference to the AMD documentation is chapter 9 in the - * BIOS and Kernel Developer's Guide, which is available on - * www.amd.com - */ - printk(KERN_ERR FW_BUG PFX "No PSB or ACPI _PSS objects\n"); - printk(KERN_ERR PFX "Make sure that your BIOS is up to date" - " and Cool'N'Quiet support is enabled in BIOS setup\n"); - return -ENODEV; -} - -static void powernow_k8_acpi_pst_values(struct powernow_k8_data *data, - unsigned int index) -{ - u64 control; - - if (!data->acpi_data.state_count || (cpu_family == CPU_HW_PSTATE)) - return; - - control = data->acpi_data.states[index].control; - data->irt = (control >> IRT_SHIFT) & IRT_MASK; - data->rvo = (control >> RVO_SHIFT) & RVO_MASK; - data->exttype = (control >> EXT_TYPE_SHIFT) & EXT_TYPE_MASK; - data->plllock = (control >> PLL_L_SHIFT) & PLL_L_MASK; - data->vidmvs = 1 << ((control >> MVS_SHIFT) & MVS_MASK); - data->vstable = (control >> VST_SHIFT) & VST_MASK; -} - -static int powernow_k8_cpu_init_acpi(struct powernow_k8_data *data) -{ - struct cpufreq_frequency_table *powernow_table; - int ret_val = -ENODEV; - u64 control, status; - - if (acpi_processor_register_performance(&data->acpi_data, data->cpu)) { - pr_debug("register performance failed: bad ACPI data\n"); - return -EIO; - } - - /* verify the data contained in the ACPI structures */ - if (data->acpi_data.state_count <= 1) { - pr_debug("No ACPI P-States\n"); - goto err_out; - } - - control = data->acpi_data.control_register.space_id; - status = data->acpi_data.status_register.space_id; - - if ((control != ACPI_ADR_SPACE_FIXED_HARDWARE) || - (status != ACPI_ADR_SPACE_FIXED_HARDWARE)) { - pr_debug("Invalid control/status registers (%llx - %llx)\n", - control, status); - goto err_out; - } - - /* fill in data->powernow_table */ - powernow_table = kmalloc((sizeof(struct cpufreq_frequency_table) - * (data->acpi_data.state_count + 1)), GFP_KERNEL); - if (!powernow_table) { - pr_debug("powernow_table memory alloc failure\n"); - goto err_out; - } - - /* fill in data */ - data->numps = data->acpi_data.state_count; - powernow_k8_acpi_pst_values(data, 0); - - if (cpu_family == CPU_HW_PSTATE) - ret_val = fill_powernow_table_pstate(data, powernow_table); - else - ret_val = fill_powernow_table_fidvid(data, powernow_table); - if (ret_val) - goto err_out_mem; - - powernow_table[data->acpi_data.state_count].frequency = - CPUFREQ_TABLE_END; - powernow_table[data->acpi_data.state_count].index = 0; - data->powernow_table = powernow_table; - - if (cpumask_first(cpu_core_mask(data->cpu)) == data->cpu) - print_basics(data); - - /* notify BIOS that we exist */ - acpi_processor_notify_smm(THIS_MODULE); - - if (!zalloc_cpumask_var(&data->acpi_data.shared_cpu_map, GFP_KERNEL)) { - printk(KERN_ERR PFX - "unable to alloc powernow_k8_data cpumask\n"); - ret_val = -ENOMEM; - goto err_out_mem; - } - - return 0; - -err_out_mem: - kfree(powernow_table); - -err_out: - acpi_processor_unregister_performance(&data->acpi_data, data->cpu); - - /* data->acpi_data.state_count informs us at ->exit() - * whether ACPI was used */ - data->acpi_data.state_count = 0; - - return ret_val; -} - -static int fill_powernow_table_pstate(struct powernow_k8_data *data, - struct cpufreq_frequency_table *powernow_table) -{ - int i; - u32 hi = 0, lo = 0; - rdmsr(MSR_PSTATE_CUR_LIMIT, lo, hi); - data->max_hw_pstate = (lo & HW_PSTATE_MAX_MASK) >> HW_PSTATE_MAX_SHIFT; - - for (i = 0; i < data->acpi_data.state_count; i++) { - u32 index; - - index = data->acpi_data.states[i].control & HW_PSTATE_MASK; - if (index > data->max_hw_pstate) { - printk(KERN_ERR PFX "invalid pstate %d - " - "bad value %d.\n", i, index); - printk(KERN_ERR PFX "Please report to BIOS " - "manufacturer\n"); - invalidate_entry(powernow_table, i); - continue; - } - rdmsr(MSR_PSTATE_DEF_BASE + index, lo, hi); - if (!(hi & HW_PSTATE_VALID_MASK)) { - pr_debug("invalid pstate %d, ignoring\n", index); - invalidate_entry(powernow_table, i); - continue; - } - - powernow_table[i].index = index; - - /* Frequency may be rounded for these */ - if ((boot_cpu_data.x86 == 0x10 && boot_cpu_data.x86_model < 10) - || boot_cpu_data.x86 == 0x11) { - powernow_table[i].frequency = - freq_from_fid_did(lo & 0x3f, (lo >> 6) & 7); - } else - powernow_table[i].frequency = - data->acpi_data.states[i].core_frequency * 1000; - } - return 0; -} - -static int fill_powernow_table_fidvid(struct powernow_k8_data *data, - struct cpufreq_frequency_table *powernow_table) -{ - int i; - - for (i = 0; i < data->acpi_data.state_count; i++) { - u32 fid; - u32 vid; - u32 freq, index; - u64 status, control; - - if (data->exttype) { - status = data->acpi_data.states[i].status; - fid = status & EXT_FID_MASK; - vid = (status >> VID_SHIFT) & EXT_VID_MASK; - } else { - control = data->acpi_data.states[i].control; - fid = control & FID_MASK; - vid = (control >> VID_SHIFT) & VID_MASK; - } - - pr_debug(" %d : fid 0x%x, vid 0x%x\n", i, fid, vid); - - index = fid | (vid<<8); - powernow_table[i].index = index; - - freq = find_khz_freq_from_fid(fid); - powernow_table[i].frequency = freq; - - /* verify frequency is OK */ - if ((freq > (MAX_FREQ * 1000)) || (freq < (MIN_FREQ * 1000))) { - pr_debug("invalid freq %u kHz, ignoring\n", freq); - invalidate_entry(powernow_table, i); - continue; - } - - /* verify voltage is OK - - * BIOSs are using "off" to indicate invalid */ - if (vid == VID_OFF) { - pr_debug("invalid vid %u, ignoring\n", vid); - invalidate_entry(powernow_table, i); - continue; - } - - if (freq != (data->acpi_data.states[i].core_frequency * 1000)) { - printk(KERN_INFO PFX "invalid freq entries " - "%u kHz vs. %u kHz\n", freq, - (unsigned int) - (data->acpi_data.states[i].core_frequency - * 1000)); - invalidate_entry(powernow_table, i); - continue; - } - } - return 0; -} - -static void powernow_k8_cpu_exit_acpi(struct powernow_k8_data *data) -{ - if (data->acpi_data.state_count) - acpi_processor_unregister_performance(&data->acpi_data, - data->cpu); - free_cpumask_var(data->acpi_data.shared_cpu_map); -} - -static int get_transition_latency(struct powernow_k8_data *data) -{ - int max_latency = 0; - int i; - for (i = 0; i < data->acpi_data.state_count; i++) { - int cur_latency = data->acpi_data.states[i].transition_latency - + data->acpi_data.states[i].bus_master_latency; - if (cur_latency > max_latency) - max_latency = cur_latency; - } - if (max_latency == 0) { - /* - * Fam 11h and later may return 0 as transition latency. This - * is intended and means "very fast". While cpufreq core and - * governors currently can handle that gracefully, better set it - * to 1 to avoid problems in the future. - */ - if (boot_cpu_data.x86 < 0x11) - printk(KERN_ERR FW_WARN PFX "Invalid zero transition " - "latency\n"); - max_latency = 1; - } - /* value in usecs, needs to be in nanoseconds */ - return 1000 * max_latency; -} - -/* Take a frequency, and issue the fid/vid transition command */ -static int transition_frequency_fidvid(struct powernow_k8_data *data, - unsigned int index) -{ - u32 fid = 0; - u32 vid = 0; - int res, i; - struct cpufreq_freqs freqs; - - pr_debug("cpu %d transition to index %u\n", smp_processor_id(), index); - - /* fid/vid correctness check for k8 */ - /* fid are the lower 8 bits of the index we stored into - * the cpufreq frequency table in find_psb_table, vid - * are the upper 8 bits. - */ - fid = data->powernow_table[index].index & 0xFF; - vid = (data->powernow_table[index].index & 0xFF00) >> 8; - - pr_debug("table matched fid 0x%x, giving vid 0x%x\n", fid, vid); - - if (query_current_values_with_pending_wait(data)) - return 1; - - if ((data->currvid == vid) && (data->currfid == fid)) { - pr_debug("target matches current values (fid 0x%x, vid 0x%x)\n", - fid, vid); - return 0; - } - - pr_debug("cpu %d, changing to fid 0x%x, vid 0x%x\n", - smp_processor_id(), fid, vid); - freqs.old = find_khz_freq_from_fid(data->currfid); - freqs.new = find_khz_freq_from_fid(fid); - - for_each_cpu(i, data->available_cores) { - freqs.cpu = i; - cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE); - } - - res = transition_fid_vid(data, fid, vid); - freqs.new = find_khz_freq_from_fid(data->currfid); - - for_each_cpu(i, data->available_cores) { - freqs.cpu = i; - cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE); - } - return res; -} - -/* Take a frequency, and issue the hardware pstate transition command */ -static int transition_frequency_pstate(struct powernow_k8_data *data, - unsigned int index) -{ - u32 pstate = 0; - int res, i; - struct cpufreq_freqs freqs; - - pr_debug("cpu %d transition to index %u\n", smp_processor_id(), index); - - /* get MSR index for hardware pstate transition */ - pstate = index & HW_PSTATE_MASK; - if (pstate > data->max_hw_pstate) - return 0; - freqs.old = find_khz_freq_from_pstate(data->powernow_table, - data->currpstate); - freqs.new = find_khz_freq_from_pstate(data->powernow_table, pstate); - - for_each_cpu(i, data->available_cores) { - freqs.cpu = i; - cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE); - } - - res = transition_pstate(data, pstate); - freqs.new = find_khz_freq_from_pstate(data->powernow_table, pstate); - - for_each_cpu(i, data->available_cores) { - freqs.cpu = i; - cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE); - } - return res; -} - -/* Driver entry point to switch to the target frequency */ -static int powernowk8_target(struct cpufreq_policy *pol, - unsigned targfreq, unsigned relation) -{ - cpumask_var_t oldmask; - struct powernow_k8_data *data = per_cpu(powernow_data, pol->cpu); - u32 checkfid; - u32 checkvid; - unsigned int newstate; - int ret = -EIO; - - if (!data) - return -EINVAL; - - checkfid = data->currfid; - checkvid = data->currvid; - - /* only run on specific CPU from here on. */ - /* This is poor form: use a workqueue or smp_call_function_single */ - if (!alloc_cpumask_var(&oldmask, GFP_KERNEL)) - return -ENOMEM; - - cpumask_copy(oldmask, tsk_cpus_allowed(current)); - set_cpus_allowed_ptr(current, cpumask_of(pol->cpu)); - - if (smp_processor_id() != pol->cpu) { - printk(KERN_ERR PFX "limiting to cpu %u failed\n", pol->cpu); - goto err_out; - } - - if (pending_bit_stuck()) { - printk(KERN_ERR PFX "failing targ, change pending bit set\n"); - goto err_out; - } - - pr_debug("targ: cpu %d, %d kHz, min %d, max %d, relation %d\n", - pol->cpu, targfreq, pol->min, pol->max, relation); - - if (query_current_values_with_pending_wait(data)) - goto err_out; - - if (cpu_family != CPU_HW_PSTATE) { - pr_debug("targ: curr fid 0x%x, vid 0x%x\n", - data->currfid, data->currvid); - - if ((checkvid != data->currvid) || - (checkfid != data->currfid)) { - printk(KERN_INFO PFX - "error - out of sync, fix 0x%x 0x%x, " - "vid 0x%x 0x%x\n", - checkfid, data->currfid, - checkvid, data->currvid); - } - } - - if (cpufreq_frequency_table_target(pol, data->powernow_table, - targfreq, relation, &newstate)) - goto err_out; - - mutex_lock(&fidvid_mutex); - - powernow_k8_acpi_pst_values(data, newstate); - - if (cpu_family == CPU_HW_PSTATE) - ret = transition_frequency_pstate(data, newstate); - else - ret = transition_frequency_fidvid(data, newstate); - if (ret) { - printk(KERN_ERR PFX "transition frequency failed\n"); - ret = 1; - mutex_unlock(&fidvid_mutex); - goto err_out; - } - mutex_unlock(&fidvid_mutex); - - if (cpu_family == CPU_HW_PSTATE) - pol->cur = find_khz_freq_from_pstate(data->powernow_table, - newstate); - else - pol->cur = find_khz_freq_from_fid(data->currfid); - ret = 0; - -err_out: - set_cpus_allowed_ptr(current, oldmask); - free_cpumask_var(oldmask); - return ret; -} - -/* Driver entry point to verify the policy and range of frequencies */ -static int powernowk8_verify(struct cpufreq_policy *pol) -{ - struct powernow_k8_data *data = per_cpu(powernow_data, pol->cpu); - - if (!data) - return -EINVAL; - - return cpufreq_frequency_table_verify(pol, data->powernow_table); -} - -struct init_on_cpu { - struct powernow_k8_data *data; - int rc; -}; - -static void __cpuinit powernowk8_cpu_init_on_cpu(void *_init_on_cpu) -{ - struct init_on_cpu *init_on_cpu = _init_on_cpu; - - if (pending_bit_stuck()) { - printk(KERN_ERR PFX "failing init, change pending bit set\n"); - init_on_cpu->rc = -ENODEV; - return; - } - - if (query_current_values_with_pending_wait(init_on_cpu->data)) { - init_on_cpu->rc = -ENODEV; - return; - } - - if (cpu_family == CPU_OPTERON) - fidvid_msr_init(); - - init_on_cpu->rc = 0; -} - -/* per CPU init entry point to the driver */ -static int __cpuinit powernowk8_cpu_init(struct cpufreq_policy *pol) -{ - static const char ACPI_PSS_BIOS_BUG_MSG[] = - KERN_ERR FW_BUG PFX "No compatible ACPI _PSS objects found.\n" - FW_BUG PFX "Try again with latest BIOS.\n"; - struct powernow_k8_data *data; - struct init_on_cpu init_on_cpu; - int rc; - struct cpuinfo_x86 *c = &cpu_data(pol->cpu); - - if (!cpu_online(pol->cpu)) - return -ENODEV; - - smp_call_function_single(pol->cpu, check_supported_cpu, &rc, 1); - if (rc) - return -ENODEV; - - data = kzalloc(sizeof(struct powernow_k8_data), GFP_KERNEL); - if (!data) { - printk(KERN_ERR PFX "unable to alloc powernow_k8_data"); - return -ENOMEM; - } - - data->cpu = pol->cpu; - data->currpstate = HW_PSTATE_INVALID; - - if (powernow_k8_cpu_init_acpi(data)) { - /* - * Use the PSB BIOS structure. This is only available on - * an UP version, and is deprecated by AMD. - */ - if (num_online_cpus() != 1) { - printk_once(ACPI_PSS_BIOS_BUG_MSG); - goto err_out; - } - if (pol->cpu != 0) { - printk(KERN_ERR FW_BUG PFX "No ACPI _PSS objects for " - "CPU other than CPU0. Complain to your BIOS " - "vendor.\n"); - goto err_out; - } - rc = find_psb_table(data); - if (rc) - goto err_out; - - /* Take a crude guess here. - * That guess was in microseconds, so multiply with 1000 */ - pol->cpuinfo.transition_latency = ( - ((data->rvo + 8) * data->vstable * VST_UNITS_20US) + - ((1 << data->irt) * 30)) * 1000; - } else /* ACPI _PSS objects available */ - pol->cpuinfo.transition_latency = get_transition_latency(data); - - /* only run on specific CPU from here on */ - init_on_cpu.data = data; - smp_call_function_single(data->cpu, powernowk8_cpu_init_on_cpu, - &init_on_cpu, 1); - rc = init_on_cpu.rc; - if (rc != 0) - goto err_out_exit_acpi; - - if (cpu_family == CPU_HW_PSTATE) - cpumask_copy(pol->cpus, cpumask_of(pol->cpu)); - else - cpumask_copy(pol->cpus, cpu_core_mask(pol->cpu)); - data->available_cores = pol->cpus; - - if (cpu_family == CPU_HW_PSTATE) - pol->cur = find_khz_freq_from_pstate(data->powernow_table, - data->currpstate); - else - pol->cur = find_khz_freq_from_fid(data->currfid); - pr_debug("policy current frequency %d kHz\n", pol->cur); - - /* min/max the cpu is capable of */ - if (cpufreq_frequency_table_cpuinfo(pol, data->powernow_table)) { - printk(KERN_ERR FW_BUG PFX "invalid powernow_table\n"); - powernow_k8_cpu_exit_acpi(data); - kfree(data->powernow_table); - kfree(data); - return -EINVAL; - } - - /* Check for APERF/MPERF support in hardware */ - if (cpu_has(c, X86_FEATURE_APERFMPERF)) - cpufreq_amd64_driver.getavg = cpufreq_get_measured_perf; - - cpufreq_frequency_table_get_attr(data->powernow_table, pol->cpu); - - if (cpu_family == CPU_HW_PSTATE) - pr_debug("cpu_init done, current pstate 0x%x\n", - data->currpstate); - else - pr_debug("cpu_init done, current fid 0x%x, vid 0x%x\n", - data->currfid, data->currvid); - - per_cpu(powernow_data, pol->cpu) = data; - - return 0; - -err_out_exit_acpi: - powernow_k8_cpu_exit_acpi(data); - -err_out: - kfree(data); - return -ENODEV; -} - -static int __devexit powernowk8_cpu_exit(struct cpufreq_policy *pol) -{ - struct powernow_k8_data *data = per_cpu(powernow_data, pol->cpu); - - if (!data) - return -EINVAL; - - powernow_k8_cpu_exit_acpi(data); - - cpufreq_frequency_table_put_attr(pol->cpu); - - kfree(data->powernow_table); - kfree(data); - per_cpu(powernow_data, pol->cpu) = NULL; - - return 0; -} - -static void query_values_on_cpu(void *_err) -{ - int *err = _err; - struct powernow_k8_data *data = __this_cpu_read(powernow_data); - - *err = query_current_values_with_pending_wait(data); -} - -static unsigned int powernowk8_get(unsigned int cpu) -{ - struct powernow_k8_data *data = per_cpu(powernow_data, cpu); - unsigned int khz = 0; - int err; - - if (!data) - return 0; - - smp_call_function_single(cpu, query_values_on_cpu, &err, true); - if (err) - goto out; - - if (cpu_family == CPU_HW_PSTATE) - khz = find_khz_freq_from_pstate(data->powernow_table, - data->currpstate); - else - khz = find_khz_freq_from_fid(data->currfid); - - -out: - return khz; -} - -static void _cpb_toggle_msrs(bool t) -{ - int cpu; - - get_online_cpus(); - - rdmsr_on_cpus(cpu_online_mask, MSR_K7_HWCR, msrs); - - for_each_cpu(cpu, cpu_online_mask) { - struct msr *reg = per_cpu_ptr(msrs, cpu); - if (t) - reg->l &= ~BIT(25); - else - reg->l |= BIT(25); - } - wrmsr_on_cpus(cpu_online_mask, MSR_K7_HWCR, msrs); - - put_online_cpus(); -} - -/* - * Switch on/off core performance boosting. - * - * 0=disable - * 1=enable. - */ -static void cpb_toggle(bool t) -{ - if (!cpb_capable) - return; - - if (t && !cpb_enabled) { - cpb_enabled = true; - _cpb_toggle_msrs(t); - printk(KERN_INFO PFX "Core Boosting enabled.\n"); - } else if (!t && cpb_enabled) { - cpb_enabled = false; - _cpb_toggle_msrs(t); - printk(KERN_INFO PFX "Core Boosting disabled.\n"); - } -} - -static ssize_t store_cpb(struct cpufreq_policy *policy, const char *buf, - size_t count) -{ - int ret = -EINVAL; - unsigned long val = 0; - - ret = strict_strtoul(buf, 10, &val); - if (!ret && (val == 0 || val == 1) && cpb_capable) - cpb_toggle(val); - else - return -EINVAL; - - return count; -} - -static ssize_t show_cpb(struct cpufreq_policy *policy, char *buf) -{ - return sprintf(buf, "%u\n", cpb_enabled); -} - -#define define_one_rw(_name) \ -static struct freq_attr _name = \ -__ATTR(_name, 0644, show_##_name, store_##_name) - -define_one_rw(cpb); - -static struct freq_attr *powernow_k8_attr[] = { - &cpufreq_freq_attr_scaling_available_freqs, - &cpb, - NULL, -}; - -static struct cpufreq_driver cpufreq_amd64_driver = { - .verify = powernowk8_verify, - .target = powernowk8_target, - .bios_limit = acpi_processor_get_bios_limit, - .init = powernowk8_cpu_init, - .exit = __devexit_p(powernowk8_cpu_exit), - .get = powernowk8_get, - .name = "powernow-k8", - .owner = THIS_MODULE, - .attr = powernow_k8_attr, -}; - -/* - * Clear the boost-disable flag on the CPU_DOWN path so that this cpu - * cannot block the remaining ones from boosting. On the CPU_UP path we - * simply keep the boost-disable flag in sync with the current global - * state. - */ -static int cpb_notify(struct notifier_block *nb, unsigned long action, - void *hcpu) -{ - unsigned cpu = (long)hcpu; - u32 lo, hi; - - switch (action) { - case CPU_UP_PREPARE: - case CPU_UP_PREPARE_FROZEN: - - if (!cpb_enabled) { - rdmsr_on_cpu(cpu, MSR_K7_HWCR, &lo, &hi); - lo |= BIT(25); - wrmsr_on_cpu(cpu, MSR_K7_HWCR, lo, hi); - } - break; - - case CPU_DOWN_PREPARE: - case CPU_DOWN_PREPARE_FROZEN: - rdmsr_on_cpu(cpu, MSR_K7_HWCR, &lo, &hi); - lo &= ~BIT(25); - wrmsr_on_cpu(cpu, MSR_K7_HWCR, lo, hi); - break; - - default: - break; - } - - return NOTIFY_OK; -} - -static struct notifier_block cpb_nb = { - .notifier_call = cpb_notify, -}; - -/* driver entry point for init */ -static int __cpuinit powernowk8_init(void) -{ - unsigned int i, supported_cpus = 0, cpu; - int rv; - - for_each_online_cpu(i) { - int rc; - smp_call_function_single(i, check_supported_cpu, &rc, 1); - if (rc == 0) - supported_cpus++; - } - - if (supported_cpus != num_online_cpus()) - return -ENODEV; - - printk(KERN_INFO PFX "Found %d %s (%d cpu cores) (" VERSION ")\n", - num_online_nodes(), boot_cpu_data.x86_model_id, supported_cpus); - - if (boot_cpu_has(X86_FEATURE_CPB)) { - - cpb_capable = true; - - msrs = msrs_alloc(); - if (!msrs) { - printk(KERN_ERR "%s: Error allocating msrs!\n", __func__); - return -ENOMEM; - } - - register_cpu_notifier(&cpb_nb); - - rdmsr_on_cpus(cpu_online_mask, MSR_K7_HWCR, msrs); - - for_each_cpu(cpu, cpu_online_mask) { - struct msr *reg = per_cpu_ptr(msrs, cpu); - cpb_enabled |= !(!!(reg->l & BIT(25))); - } - - printk(KERN_INFO PFX "Core Performance Boosting: %s.\n", - (cpb_enabled ? "on" : "off")); - } - - rv = cpufreq_register_driver(&cpufreq_amd64_driver); - if (rv < 0 && boot_cpu_has(X86_FEATURE_CPB)) { - unregister_cpu_notifier(&cpb_nb); - msrs_free(msrs); - msrs = NULL; - } - return rv; -} - -/* driver entry point for term */ -static void __exit powernowk8_exit(void) -{ - pr_debug("exit\n"); - - if (boot_cpu_has(X86_FEATURE_CPB)) { - msrs_free(msrs); - msrs = NULL; - - unregister_cpu_notifier(&cpb_nb); - } - - cpufreq_unregister_driver(&cpufreq_amd64_driver); -} - -MODULE_AUTHOR("Paul Devriendt and " - "Mark Langsdorf "); -MODULE_DESCRIPTION("AMD Athlon 64 and Opteron processor frequency driver."); -MODULE_LICENSE("GPL"); - -late_initcall(powernowk8_init); -module_exit(powernowk8_exit); diff --git a/arch/x86/kernel/cpu/cpufreq/powernow-k8.h b/arch/x86/kernel/cpu/cpufreq/powernow-k8.h deleted file mode 100644 index 3744d26..0000000 --- a/arch/x86/kernel/cpu/cpufreq/powernow-k8.h +++ /dev/null @@ -1,222 +0,0 @@ -/* - * (c) 2003-2006 Advanced Micro Devices, Inc. - * Your use of this code is subject to the terms and conditions of the - * GNU general public license version 2. See "COPYING" or - * http://www.gnu.org/licenses/gpl.html - */ - -enum pstate { - HW_PSTATE_INVALID = 0xff, - HW_PSTATE_0 = 0, - HW_PSTATE_1 = 1, - HW_PSTATE_2 = 2, - HW_PSTATE_3 = 3, - HW_PSTATE_4 = 4, - HW_PSTATE_5 = 5, - HW_PSTATE_6 = 6, - HW_PSTATE_7 = 7, -}; - -struct powernow_k8_data { - unsigned int cpu; - - u32 numps; /* number of p-states */ - u32 batps; /* number of p-states supported on battery */ - u32 max_hw_pstate; /* maximum legal hardware pstate */ - - /* these values are constant when the PSB is used to determine - * vid/fid pairings, but are modified during the ->target() call - * when ACPI is used */ - u32 rvo; /* ramp voltage offset */ - u32 irt; /* isochronous relief time */ - u32 vidmvs; /* usable value calculated from mvs */ - u32 vstable; /* voltage stabilization time, units 20 us */ - u32 plllock; /* pll lock time, units 1 us */ - u32 exttype; /* extended interface = 1 */ - - /* keep track of the current fid / vid or pstate */ - u32 currvid; - u32 currfid; - enum pstate currpstate; - - /* the powernow_table includes all frequency and vid/fid pairings: - * fid are the lower 8 bits of the index, vid are the upper 8 bits. - * frequency is in kHz */ - struct cpufreq_frequency_table *powernow_table; - - /* the acpi table needs to be kept. it's only available if ACPI was - * used to determine valid frequency/vid/fid states */ - struct acpi_processor_performance acpi_data; - - /* we need to keep track of associated cores, but let cpufreq - * handle hotplug events - so just point at cpufreq pol->cpus - * structure */ - struct cpumask *available_cores; -}; - -/* processor's cpuid instruction support */ -#define CPUID_PROCESSOR_SIGNATURE 1 /* function 1 */ -#define CPUID_XFAM 0x0ff00000 /* extended family */ -#define CPUID_XFAM_K8 0 -#define CPUID_XMOD 0x000f0000 /* extended model */ -#define CPUID_XMOD_REV_MASK 0x000c0000 -#define CPUID_XFAM_10H 0x00100000 /* family 0x10 */ -#define CPUID_USE_XFAM_XMOD 0x00000f00 -#define CPUID_GET_MAX_CAPABILITIES 0x80000000 -#define CPUID_FREQ_VOLT_CAPABILITIES 0x80000007 -#define P_STATE_TRANSITION_CAPABLE 6 - -/* Model Specific Registers for p-state transitions. MSRs are 64-bit. For */ -/* writes (wrmsr - opcode 0f 30), the register number is placed in ecx, and */ -/* the value to write is placed in edx:eax. For reads (rdmsr - opcode 0f 32), */ -/* the register number is placed in ecx, and the data is returned in edx:eax. */ - -#define MSR_FIDVID_CTL 0xc0010041 -#define MSR_FIDVID_STATUS 0xc0010042 - -/* Field definitions within the FID VID Low Control MSR : */ -#define MSR_C_LO_INIT_FID_VID 0x00010000 -#define MSR_C_LO_NEW_VID 0x00003f00 -#define MSR_C_LO_NEW_FID 0x0000003f -#define MSR_C_LO_VID_SHIFT 8 - -/* Field definitions within the FID VID High Control MSR : */ -#define MSR_C_HI_STP_GNT_TO 0x000fffff - -/* Field definitions within the FID VID Low Status MSR : */ -#define MSR_S_LO_CHANGE_PENDING 0x80000000 /* cleared when completed */ -#define MSR_S_LO_MAX_RAMP_VID 0x3f000000 -#define MSR_S_LO_MAX_FID 0x003f0000 -#define MSR_S_LO_START_FID 0x00003f00 -#define MSR_S_LO_CURRENT_FID 0x0000003f - -/* Field definitions within the FID VID High Status MSR : */ -#define MSR_S_HI_MIN_WORKING_VID 0x3f000000 -#define MSR_S_HI_MAX_WORKING_VID 0x003f0000 -#define MSR_S_HI_START_VID 0x00003f00 -#define MSR_S_HI_CURRENT_VID 0x0000003f -#define MSR_C_HI_STP_GNT_BENIGN 0x00000001 - - -/* Hardware Pstate _PSS and MSR definitions */ -#define USE_HW_PSTATE 0x00000080 -#define HW_PSTATE_MASK 0x00000007 -#define HW_PSTATE_VALID_MASK 0x80000000 -#define HW_PSTATE_MAX_MASK 0x000000f0 -#define HW_PSTATE_MAX_SHIFT 4 -#define MSR_PSTATE_DEF_BASE 0xc0010064 /* base of Pstate MSRs */ -#define MSR_PSTATE_STATUS 0xc0010063 /* Pstate Status MSR */ -#define MSR_PSTATE_CTRL 0xc0010062 /* Pstate control MSR */ -#define MSR_PSTATE_CUR_LIMIT 0xc0010061 /* pstate current limit MSR */ - -/* define the two driver architectures */ -#define CPU_OPTERON 0 -#define CPU_HW_PSTATE 1 - - -/* - * There are restrictions frequencies have to follow: - * - only 1 entry in the low fid table ( <=1.4GHz ) - * - lowest entry in the high fid table must be >= 2 * the entry in the - * low fid table - * - lowest entry in the high fid table must be a <= 200MHz + 2 * the entry - * in the low fid table - * - the parts can only step at <= 200 MHz intervals, odd fid values are - * supported in revision G and later revisions. - * - lowest frequency must be >= interprocessor hypertransport link speed - * (only applies to MP systems obviously) - */ - -/* fids (frequency identifiers) are arranged in 2 tables - lo and hi */ -#define LO_FID_TABLE_TOP 7 /* fid values marking the boundary */ -#define HI_FID_TABLE_BOTTOM 8 /* between the low and high tables */ - -#define LO_VCOFREQ_TABLE_TOP 1400 /* corresponding vco frequency values */ -#define HI_VCOFREQ_TABLE_BOTTOM 1600 - -#define MIN_FREQ_RESOLUTION 200 /* fids jump by 2 matching freq jumps by 200 */ - -#define MAX_FID 0x2a /* Spec only gives FID values as far as 5 GHz */ -#define LEAST_VID 0x3e /* Lowest (numerically highest) useful vid value */ - -#define MIN_FREQ 800 /* Min and max freqs, per spec */ -#define MAX_FREQ 5000 - -#define INVALID_FID_MASK 0xffffffc0 /* not a valid fid if these bits are set */ -#define INVALID_VID_MASK 0xffffffc0 /* not a valid vid if these bits are set */ - -#define VID_OFF 0x3f - -#define STOP_GRANT_5NS 1 /* min poss memory access latency for voltage change */ - -#define PLL_LOCK_CONVERSION (1000/5) /* ms to ns, then divide by clock period */ - -#define MAXIMUM_VID_STEPS 1 /* Current cpus only allow a single step of 25mV */ -#define VST_UNITS_20US 20 /* Voltage Stabilization Time is in units of 20us */ - -/* - * Most values of interest are encoded in a single field of the _PSS - * entries: the "control" value. - */ - -#define IRT_SHIFT 30 -#define RVO_SHIFT 28 -#define EXT_TYPE_SHIFT 27 -#define PLL_L_SHIFT 20 -#define MVS_SHIFT 18 -#define VST_SHIFT 11 -#define VID_SHIFT 6 -#define IRT_MASK 3 -#define RVO_MASK 3 -#define EXT_TYPE_MASK 1 -#define PLL_L_MASK 0x7f -#define MVS_MASK 3 -#define VST_MASK 0x7f -#define VID_MASK 0x1f -#define FID_MASK 0x1f -#define EXT_VID_MASK 0x3f -#define EXT_FID_MASK 0x3f - - -/* - * Version 1.4 of the PSB table. This table is constructed by BIOS and is - * to tell the OS's power management driver which VIDs and FIDs are - * supported by this particular processor. - * If the data in the PSB / PST is wrong, then this driver will program the - * wrong values into hardware, which is very likely to lead to a crash. - */ - -#define PSB_ID_STRING "AMDK7PNOW!" -#define PSB_ID_STRING_LEN 10 - -#define PSB_VERSION_1_4 0x14 - -struct psb_s { - u8 signature[10]; - u8 tableversion; - u8 flags1; - u16 vstable; - u8 flags2; - u8 num_tables; - u32 cpuid; - u8 plllocktime; - u8 maxfid; - u8 maxvid; - u8 numps; -}; - -/* Pairs of fid/vid values are appended to the version 1.4 PSB table. */ -struct pst_s { - u8 fid; - u8 vid; -}; - -static int core_voltage_pre_transition(struct powernow_k8_data *data, - u32 reqvid, u32 regfid); -static int core_voltage_post_transition(struct powernow_k8_data *data, u32 reqvid); -static int core_frequency_transition(struct powernow_k8_data *data, u32 reqfid); - -static void powernow_k8_acpi_pst_values(struct powernow_k8_data *data, unsigned int index); - -static int fill_powernow_table_pstate(struct powernow_k8_data *data, struct cpufreq_frequency_table *powernow_table); -static int fill_powernow_table_fidvid(struct powernow_k8_data *data, struct cpufreq_frequency_table *powernow_table); diff --git a/arch/x86/kernel/cpu/cpufreq/sc520_freq.c b/arch/x86/kernel/cpu/cpufreq/sc520_freq.c deleted file mode 100644 index 1e205e6..0000000 --- a/arch/x86/kernel/cpu/cpufreq/sc520_freq.c +++ /dev/null @@ -1,192 +0,0 @@ -/* - * sc520_freq.c: cpufreq driver for the AMD Elan sc520 - * - * Copyright (C) 2005 Sean Young - * - * 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. - * - * Based on elanfreq.c - * - * 2005-03-30: - initial revision - */ - -#include -#include -#include - -#include -#include -#include -#include - -#include - -#define MMCR_BASE 0xfffef000 /* The default base address */ -#define OFFS_CPUCTL 0x2 /* CPU Control Register */ - -static __u8 __iomem *cpuctl; - -#define PFX "sc520_freq: " - -static struct cpufreq_frequency_table sc520_freq_table[] = { - {0x01, 100000}, - {0x02, 133000}, - {0, CPUFREQ_TABLE_END}, -}; - -static unsigned int sc520_freq_get_cpu_frequency(unsigned int cpu) -{ - u8 clockspeed_reg = *cpuctl; - - switch (clockspeed_reg & 0x03) { - default: - printk(KERN_ERR PFX "error: cpuctl register has unexpected " - "value %02x\n", clockspeed_reg); - case 0x01: - return 100000; - case 0x02: - return 133000; - } -} - -static void sc520_freq_set_cpu_state(unsigned int state) -{ - - struct cpufreq_freqs freqs; - u8 clockspeed_reg; - - freqs.old = sc520_freq_get_cpu_frequency(0); - freqs.new = sc520_freq_table[state].frequency; - freqs.cpu = 0; /* AMD Elan is UP */ - - cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE); - - pr_debug("attempting to set frequency to %i kHz\n", - sc520_freq_table[state].frequency); - - local_irq_disable(); - - clockspeed_reg = *cpuctl & ~0x03; - *cpuctl = clockspeed_reg | sc520_freq_table[state].index; - - local_irq_enable(); - - cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE); -}; - -static int sc520_freq_verify(struct cpufreq_policy *policy) -{ - return cpufreq_frequency_table_verify(policy, &sc520_freq_table[0]); -} - -static int sc520_freq_target(struct cpufreq_policy *policy, - unsigned int target_freq, - unsigned int relation) -{ - unsigned int newstate = 0; - - if (cpufreq_frequency_table_target(policy, sc520_freq_table, - target_freq, relation, &newstate)) - return -EINVAL; - - sc520_freq_set_cpu_state(newstate); - - return 0; -} - - -/* - * Module init and exit code - */ - -static int sc520_freq_cpu_init(struct cpufreq_policy *policy) -{ - struct cpuinfo_x86 *c = &cpu_data(0); - int result; - - /* capability check */ - if (c->x86_vendor != X86_VENDOR_AMD || - c->x86 != 4 || c->x86_model != 9) - return -ENODEV; - - /* cpuinfo and default policy values */ - policy->cpuinfo.transition_latency = 1000000; /* 1ms */ - policy->cur = sc520_freq_get_cpu_frequency(0); - - result = cpufreq_frequency_table_cpuinfo(policy, sc520_freq_table); - if (result) - return result; - - cpufreq_frequency_table_get_attr(sc520_freq_table, policy->cpu); - - return 0; -} - - -static int sc520_freq_cpu_exit(struct cpufreq_policy *policy) -{ - cpufreq_frequency_table_put_attr(policy->cpu); - return 0; -} - - -static struct freq_attr *sc520_freq_attr[] = { - &cpufreq_freq_attr_scaling_available_freqs, - NULL, -}; - - -static struct cpufreq_driver sc520_freq_driver = { - .get = sc520_freq_get_cpu_frequency, - .verify = sc520_freq_verify, - .target = sc520_freq_target, - .init = sc520_freq_cpu_init, - .exit = sc520_freq_cpu_exit, - .name = "sc520_freq", - .owner = THIS_MODULE, - .attr = sc520_freq_attr, -}; - - -static int __init sc520_freq_init(void) -{ - struct cpuinfo_x86 *c = &cpu_data(0); - int err; - - /* Test if we have the right hardware */ - if (c->x86_vendor != X86_VENDOR_AMD || - c->x86 != 4 || c->x86_model != 9) { - pr_debug("no Elan SC520 processor found!\n"); - return -ENODEV; - } - cpuctl = ioremap((unsigned long)(MMCR_BASE + OFFS_CPUCTL), 1); - if (!cpuctl) { - printk(KERN_ERR "sc520_freq: error: failed to remap memory\n"); - return -ENOMEM; - } - - err = cpufreq_register_driver(&sc520_freq_driver); - if (err) - iounmap(cpuctl); - - return err; -} - - -static void __exit sc520_freq_exit(void) -{ - cpufreq_unregister_driver(&sc520_freq_driver); - iounmap(cpuctl); -} - - -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Sean Young "); -MODULE_DESCRIPTION("cpufreq driver for AMD's Elan sc520 CPU"); - -module_init(sc520_freq_init); -module_exit(sc520_freq_exit); - diff --git a/arch/x86/kernel/cpu/cpufreq/speedstep-centrino.c b/arch/x86/kernel/cpu/cpufreq/speedstep-centrino.c deleted file mode 100644 index 6ea3455..0000000 --- a/arch/x86/kernel/cpu/cpufreq/speedstep-centrino.c +++ /dev/null @@ -1,633 +0,0 @@ -/* - * cpufreq driver for Enhanced SpeedStep, as found in Intel's Pentium - * M (part of the Centrino chipset). - * - * Since the original Pentium M, most new Intel CPUs support Enhanced - * SpeedStep. - * - * Despite the "SpeedStep" in the name, this is almost entirely unlike - * traditional SpeedStep. - * - * Modelled on speedstep.c - * - * Copyright (C) 2003 Jeremy Fitzhardinge - */ - -#include -#include -#include -#include -#include /* current */ -#include -#include -#include - -#include -#include -#include - -#define PFX "speedstep-centrino: " -#define MAINTAINER "cpufreq@vger.kernel.org" - -#define INTEL_MSR_RANGE (0xffff) - -struct cpu_id -{ - __u8 x86; /* CPU family */ - __u8 x86_model; /* model */ - __u8 x86_mask; /* stepping */ -}; - -enum { - CPU_BANIAS, - CPU_DOTHAN_A1, - CPU_DOTHAN_A2, - CPU_DOTHAN_B0, - CPU_MP4HT_D0, - CPU_MP4HT_E0, -}; - -static const struct cpu_id cpu_ids[] = { - [CPU_BANIAS] = { 6, 9, 5 }, - [CPU_DOTHAN_A1] = { 6, 13, 1 }, - [CPU_DOTHAN_A2] = { 6, 13, 2 }, - [CPU_DOTHAN_B0] = { 6, 13, 6 }, - [CPU_MP4HT_D0] = {15, 3, 4 }, - [CPU_MP4HT_E0] = {15, 4, 1 }, -}; -#define N_IDS ARRAY_SIZE(cpu_ids) - -struct cpu_model -{ - const struct cpu_id *cpu_id; - const char *model_name; - unsigned max_freq; /* max clock in kHz */ - - struct cpufreq_frequency_table *op_points; /* clock/voltage pairs */ -}; -static int centrino_verify_cpu_id(const struct cpuinfo_x86 *c, - const struct cpu_id *x); - -/* Operating points for current CPU */ -static DEFINE_PER_CPU(struct cpu_model *, centrino_model); -static DEFINE_PER_CPU(const struct cpu_id *, centrino_cpu); - -static struct cpufreq_driver centrino_driver; - -#ifdef CONFIG_X86_SPEEDSTEP_CENTRINO_TABLE - -/* Computes the correct form for IA32_PERF_CTL MSR for a particular - frequency/voltage operating point; frequency in MHz, volts in mV. - This is stored as "index" in the structure. */ -#define OP(mhz, mv) \ - { \ - .frequency = (mhz) * 1000, \ - .index = (((mhz)/100) << 8) | ((mv - 700) / 16) \ - } - -/* - * These voltage tables were derived from the Intel Pentium M - * datasheet, document 25261202.pdf, Table 5. I have verified they - * are consistent with my IBM ThinkPad X31, which has a 1.3GHz Pentium - * M. - */ - -/* Ultra Low Voltage Intel Pentium M processor 900MHz (Banias) */ -static struct cpufreq_frequency_table banias_900[] = -{ - OP(600, 844), - OP(800, 988), - OP(900, 1004), - { .frequency = CPUFREQ_TABLE_END } -}; - -/* Ultra Low Voltage Intel Pentium M processor 1000MHz (Banias) */ -static struct cpufreq_frequency_table banias_1000[] = -{ - OP(600, 844), - OP(800, 972), - OP(900, 988), - OP(1000, 1004), - { .frequency = CPUFREQ_TABLE_END } -}; - -/* Low Voltage Intel Pentium M processor 1.10GHz (Banias) */ -static struct cpufreq_frequency_table banias_1100[] = -{ - OP( 600, 956), - OP( 800, 1020), - OP( 900, 1100), - OP(1000, 1164), - OP(1100, 1180), - { .frequency = CPUFREQ_TABLE_END } -}; - - -/* Low Voltage Intel Pentium M processor 1.20GHz (Banias) */ -static struct cpufreq_frequency_table banias_1200[] = -{ - OP( 600, 956), - OP( 800, 1004), - OP( 900, 1020), - OP(1000, 1100), - OP(1100, 1164), - OP(1200, 1180), - { .frequency = CPUFREQ_TABLE_END } -}; - -/* Intel Pentium M processor 1.30GHz (Banias) */ -static struct cpufreq_frequency_table banias_1300[] = -{ - OP( 600, 956), - OP( 800, 1260), - OP(1000, 1292), - OP(1200, 1356), - OP(1300, 1388), - { .frequency = CPUFREQ_TABLE_END } -}; - -/* Intel Pentium M processor 1.40GHz (Banias) */ -static struct cpufreq_frequency_table banias_1400[] = -{ - OP( 600, 956), - OP( 800, 1180), - OP(1000, 1308), - OP(1200, 1436), - OP(1400, 1484), - { .frequency = CPUFREQ_TABLE_END } -}; - -/* Intel Pentium M processor 1.50GHz (Banias) */ -static struct cpufreq_frequency_table banias_1500[] = -{ - OP( 600, 956), - OP( 800, 1116), - OP(1000, 1228), - OP(1200, 1356), - OP(1400, 1452), - OP(1500, 1484), - { .frequency = CPUFREQ_TABLE_END } -}; - -/* Intel Pentium M processor 1.60GHz (Banias) */ -static struct cpufreq_frequency_table banias_1600[] = -{ - OP( 600, 956), - OP( 800, 1036), - OP(1000, 1164), - OP(1200, 1276), - OP(1400, 1420), - OP(1600, 1484), - { .frequency = CPUFREQ_TABLE_END } -}; - -/* Intel Pentium M processor 1.70GHz (Banias) */ -static struct cpufreq_frequency_table banias_1700[] = -{ - OP( 600, 956), - OP( 800, 1004), - OP(1000, 1116), - OP(1200, 1228), - OP(1400, 1308), - OP(1700, 1484), - { .frequency = CPUFREQ_TABLE_END } -}; -#undef OP - -#define _BANIAS(cpuid, max, name) \ -{ .cpu_id = cpuid, \ - .model_name = "Intel(R) Pentium(R) M processor " name "MHz", \ - .max_freq = (max)*1000, \ - .op_points = banias_##max, \ -} -#define BANIAS(max) _BANIAS(&cpu_ids[CPU_BANIAS], max, #max) - -/* CPU models, their operating frequency range, and freq/voltage - operating points */ -static struct cpu_model models[] = -{ - _BANIAS(&cpu_ids[CPU_BANIAS], 900, " 900"), - BANIAS(1000), - BANIAS(1100), - BANIAS(1200), - BANIAS(1300), - BANIAS(1400), - BANIAS(1500), - BANIAS(1600), - BANIAS(1700), - - /* NULL model_name is a wildcard */ - { &cpu_ids[CPU_DOTHAN_A1], NULL, 0, NULL }, - { &cpu_ids[CPU_DOTHAN_A2], NULL, 0, NULL }, - { &cpu_ids[CPU_DOTHAN_B0], NULL, 0, NULL }, - { &cpu_ids[CPU_MP4HT_D0], NULL, 0, NULL }, - { &cpu_ids[CPU_MP4HT_E0], NULL, 0, NULL }, - - { NULL, } -}; -#undef _BANIAS -#undef BANIAS - -static int centrino_cpu_init_table(struct cpufreq_policy *policy) -{ - struct cpuinfo_x86 *cpu = &cpu_data(policy->cpu); - struct cpu_model *model; - - for(model = models; model->cpu_id != NULL; model++) - if (centrino_verify_cpu_id(cpu, model->cpu_id) && - (model->model_name == NULL || - strcmp(cpu->x86_model_id, model->model_name) == 0)) - break; - - if (model->cpu_id == NULL) { - /* No match at all */ - pr_debug("no support for CPU model \"%s\": " - "send /proc/cpuinfo to " MAINTAINER "\n", - cpu->x86_model_id); - return -ENOENT; - } - - if (model->op_points == NULL) { - /* Matched a non-match */ - pr_debug("no table support for CPU model \"%s\"\n", - cpu->x86_model_id); - pr_debug("try using the acpi-cpufreq driver\n"); - return -ENOENT; - } - - per_cpu(centrino_model, policy->cpu) = model; - - pr_debug("found \"%s\": max frequency: %dkHz\n", - model->model_name, model->max_freq); - - return 0; -} - -#else -static inline int centrino_cpu_init_table(struct cpufreq_policy *policy) -{ - return -ENODEV; -} -#endif /* CONFIG_X86_SPEEDSTEP_CENTRINO_TABLE */ - -static int centrino_verify_cpu_id(const struct cpuinfo_x86 *c, - const struct cpu_id *x) -{ - if ((c->x86 == x->x86) && - (c->x86_model == x->x86_model) && - (c->x86_mask == x->x86_mask)) - return 1; - return 0; -} - -/* To be called only after centrino_model is initialized */ -static unsigned extract_clock(unsigned msr, unsigned int cpu, int failsafe) -{ - int i; - - /* - * Extract clock in kHz from PERF_CTL value - * for centrino, as some DSDTs are buggy. - * Ideally, this can be done using the acpi_data structure. - */ - if ((per_cpu(centrino_cpu, cpu) == &cpu_ids[CPU_BANIAS]) || - (per_cpu(centrino_cpu, cpu) == &cpu_ids[CPU_DOTHAN_A1]) || - (per_cpu(centrino_cpu, cpu) == &cpu_ids[CPU_DOTHAN_B0])) { - msr = (msr >> 8) & 0xff; - return msr * 100000; - } - - if ((!per_cpu(centrino_model, cpu)) || - (!per_cpu(centrino_model, cpu)->op_points)) - return 0; - - msr &= 0xffff; - for (i = 0; - per_cpu(centrino_model, cpu)->op_points[i].frequency - != CPUFREQ_TABLE_END; - i++) { - if (msr == per_cpu(centrino_model, cpu)->op_points[i].index) - return per_cpu(centrino_model, cpu)-> - op_points[i].frequency; - } - if (failsafe) - return per_cpu(centrino_model, cpu)->op_points[i-1].frequency; - else - return 0; -} - -/* Return the current CPU frequency in kHz */ -static unsigned int get_cur_freq(unsigned int cpu) -{ - unsigned l, h; - unsigned clock_freq; - - rdmsr_on_cpu(cpu, MSR_IA32_PERF_STATUS, &l, &h); - clock_freq = extract_clock(l, cpu, 0); - - if (unlikely(clock_freq == 0)) { - /* - * On some CPUs, we can see transient MSR values (which are - * not present in _PSS), while CPU is doing some automatic - * P-state transition (like TM2). Get the last freq set - * in PERF_CTL. - */ - rdmsr_on_cpu(cpu, MSR_IA32_PERF_CTL, &l, &h); - clock_freq = extract_clock(l, cpu, 1); - } - return clock_freq; -} - - -static int centrino_cpu_init(struct cpufreq_policy *policy) -{ - struct cpuinfo_x86 *cpu = &cpu_data(policy->cpu); - unsigned freq; - unsigned l, h; - int ret; - int i; - - /* Only Intel makes Enhanced Speedstep-capable CPUs */ - if (cpu->x86_vendor != X86_VENDOR_INTEL || - !cpu_has(cpu, X86_FEATURE_EST)) - return -ENODEV; - - if (cpu_has(cpu, X86_FEATURE_CONSTANT_TSC)) - centrino_driver.flags |= CPUFREQ_CONST_LOOPS; - - if (policy->cpu != 0) - return -ENODEV; - - for (i = 0; i < N_IDS; i++) - if (centrino_verify_cpu_id(cpu, &cpu_ids[i])) - break; - - if (i != N_IDS) - per_cpu(centrino_cpu, policy->cpu) = &cpu_ids[i]; - - if (!per_cpu(centrino_cpu, policy->cpu)) { - pr_debug("found unsupported CPU with " - "Enhanced SpeedStep: send /proc/cpuinfo to " - MAINTAINER "\n"); - return -ENODEV; - } - - if (centrino_cpu_init_table(policy)) { - return -ENODEV; - } - - /* Check to see if Enhanced SpeedStep is enabled, and try to - enable it if not. */ - rdmsr(MSR_IA32_MISC_ENABLE, l, h); - - if (!(l & MSR_IA32_MISC_ENABLE_ENHANCED_SPEEDSTEP)) { - l |= MSR_IA32_MISC_ENABLE_ENHANCED_SPEEDSTEP; - pr_debug("trying to enable Enhanced SpeedStep (%x)\n", l); - wrmsr(MSR_IA32_MISC_ENABLE, l, h); - - /* check to see if it stuck */ - rdmsr(MSR_IA32_MISC_ENABLE, l, h); - if (!(l & MSR_IA32_MISC_ENABLE_ENHANCED_SPEEDSTEP)) { - printk(KERN_INFO PFX - "couldn't enable Enhanced SpeedStep\n"); - return -ENODEV; - } - } - - freq = get_cur_freq(policy->cpu); - policy->cpuinfo.transition_latency = 10000; - /* 10uS transition latency */ - policy->cur = freq; - - pr_debug("centrino_cpu_init: cur=%dkHz\n", policy->cur); - - ret = cpufreq_frequency_table_cpuinfo(policy, - per_cpu(centrino_model, policy->cpu)->op_points); - if (ret) - return (ret); - - cpufreq_frequency_table_get_attr( - per_cpu(centrino_model, policy->cpu)->op_points, policy->cpu); - - return 0; -} - -static int centrino_cpu_exit(struct cpufreq_policy *policy) -{ - unsigned int cpu = policy->cpu; - - if (!per_cpu(centrino_model, cpu)) - return -ENODEV; - - cpufreq_frequency_table_put_attr(cpu); - - per_cpu(centrino_model, cpu) = NULL; - - return 0; -} - -/** - * centrino_verify - verifies a new CPUFreq policy - * @policy: new policy - * - * Limit must be within this model's frequency range at least one - * border included. - */ -static int centrino_verify (struct cpufreq_policy *policy) -{ - return cpufreq_frequency_table_verify(policy, - per_cpu(centrino_model, policy->cpu)->op_points); -} - -/** - * centrino_setpolicy - set a new CPUFreq policy - * @policy: new policy - * @target_freq: the target frequency - * @relation: how that frequency relates to achieved frequency - * (CPUFREQ_RELATION_L or CPUFREQ_RELATION_H) - * - * Sets a new CPUFreq policy. - */ -static int centrino_target (struct cpufreq_policy *policy, - unsigned int target_freq, - unsigned int relation) -{ - unsigned int newstate = 0; - unsigned int msr, oldmsr = 0, h = 0, cpu = policy->cpu; - struct cpufreq_freqs freqs; - int retval = 0; - unsigned int j, k, first_cpu, tmp; - cpumask_var_t covered_cpus; - - if (unlikely(!zalloc_cpumask_var(&covered_cpus, GFP_KERNEL))) - return -ENOMEM; - - if (unlikely(per_cpu(centrino_model, cpu) == NULL)) { - retval = -ENODEV; - goto out; - } - - if (unlikely(cpufreq_frequency_table_target(policy, - per_cpu(centrino_model, cpu)->op_points, - target_freq, - relation, - &newstate))) { - retval = -EINVAL; - goto out; - } - - first_cpu = 1; - for_each_cpu(j, policy->cpus) { - int good_cpu; - - /* cpufreq holds the hotplug lock, so we are safe here */ - if (!cpu_online(j)) - continue; - - /* - * Support for SMP systems. - * Make sure we are running on CPU that wants to change freq - */ - if (policy->shared_type == CPUFREQ_SHARED_TYPE_ANY) - good_cpu = cpumask_any_and(policy->cpus, - cpu_online_mask); - else - good_cpu = j; - - if (good_cpu >= nr_cpu_ids) { - pr_debug("couldn't limit to CPUs in this domain\n"); - retval = -EAGAIN; - if (first_cpu) { - /* We haven't started the transition yet. */ - goto out; - } - break; - } - - msr = per_cpu(centrino_model, cpu)->op_points[newstate].index; - - if (first_cpu) { - rdmsr_on_cpu(good_cpu, MSR_IA32_PERF_CTL, &oldmsr, &h); - if (msr == (oldmsr & 0xffff)) { - pr_debug("no change needed - msr was and needs " - "to be %x\n", oldmsr); - retval = 0; - goto out; - } - - freqs.old = extract_clock(oldmsr, cpu, 0); - freqs.new = extract_clock(msr, cpu, 0); - - pr_debug("target=%dkHz old=%d new=%d msr=%04x\n", - target_freq, freqs.old, freqs.new, msr); - - for_each_cpu(k, policy->cpus) { - if (!cpu_online(k)) - continue; - freqs.cpu = k; - cpufreq_notify_transition(&freqs, - CPUFREQ_PRECHANGE); - } - - first_cpu = 0; - /* all but 16 LSB are reserved, treat them with care */ - oldmsr &= ~0xffff; - msr &= 0xffff; - oldmsr |= msr; - } - - wrmsr_on_cpu(good_cpu, MSR_IA32_PERF_CTL, oldmsr, h); - if (policy->shared_type == CPUFREQ_SHARED_TYPE_ANY) - break; - - cpumask_set_cpu(j, covered_cpus); - } - - for_each_cpu(k, policy->cpus) { - if (!cpu_online(k)) - continue; - freqs.cpu = k; - cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE); - } - - if (unlikely(retval)) { - /* - * We have failed halfway through the frequency change. - * We have sent callbacks to policy->cpus and - * MSRs have already been written on coverd_cpus. - * Best effort undo.. - */ - - for_each_cpu(j, covered_cpus) - wrmsr_on_cpu(j, MSR_IA32_PERF_CTL, oldmsr, h); - - tmp = freqs.new; - freqs.new = freqs.old; - freqs.old = tmp; - for_each_cpu(j, policy->cpus) { - if (!cpu_online(j)) - continue; - cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE); - cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE); - } - } - retval = 0; - -out: - free_cpumask_var(covered_cpus); - return retval; -} - -static struct freq_attr* centrino_attr[] = { - &cpufreq_freq_attr_scaling_available_freqs, - NULL, -}; - -static struct cpufreq_driver centrino_driver = { - .name = "centrino", /* should be speedstep-centrino, - but there's a 16 char limit */ - .init = centrino_cpu_init, - .exit = centrino_cpu_exit, - .verify = centrino_verify, - .target = centrino_target, - .get = get_cur_freq, - .attr = centrino_attr, - .owner = THIS_MODULE, -}; - - -/** - * centrino_init - initializes the Enhanced SpeedStep CPUFreq driver - * - * Initializes the Enhanced SpeedStep support. Returns -ENODEV on - * unsupported devices, -ENOENT if there's no voltage table for this - * particular CPU model, -EINVAL on problems during initiatization, - * and zero on success. - * - * This is quite picky. Not only does the CPU have to advertise the - * "est" flag in the cpuid capability flags, we look for a specific - * CPU model and stepping, and we need to have the exact model name in - * our voltage tables. That is, be paranoid about not releasing - * someone's valuable magic smoke. - */ -static int __init centrino_init(void) -{ - struct cpuinfo_x86 *cpu = &cpu_data(0); - - if (!cpu_has(cpu, X86_FEATURE_EST)) - return -ENODEV; - - return cpufreq_register_driver(¢rino_driver); -} - -static void __exit centrino_exit(void) -{ - cpufreq_unregister_driver(¢rino_driver); -} - -MODULE_AUTHOR ("Jeremy Fitzhardinge "); -MODULE_DESCRIPTION ("Enhanced SpeedStep driver for Intel Pentium M processors."); -MODULE_LICENSE ("GPL"); - -late_initcall(centrino_init); -module_exit(centrino_exit); diff --git a/arch/x86/kernel/cpu/cpufreq/speedstep-ich.c b/arch/x86/kernel/cpu/cpufreq/speedstep-ich.c deleted file mode 100644 index a748ce7..0000000 --- a/arch/x86/kernel/cpu/cpufreq/speedstep-ich.c +++ /dev/null @@ -1,448 +0,0 @@ -/* - * (C) 2001 Dave Jones, Arjan van de ven. - * (C) 2002 - 2003 Dominik Brodowski - * - * Licensed under the terms of the GNU GPL License version 2. - * Based upon reverse engineered information, and on Intel documentation - * for chipsets ICH2-M and ICH3-M. - * - * Many thanks to Ducrot Bruno for finding and fixing the last - * "missing link" for ICH2-M/ICH3-M support, and to Thomas Winkler - * for extensive testing. - * - * BIG FAT DISCLAIMER: Work in progress code. Possibly *dangerous* - */ - - -/********************************************************************* - * SPEEDSTEP - DEFINITIONS * - *********************************************************************/ - -#include -#include -#include -#include -#include -#include - -#include "speedstep-lib.h" - - -/* speedstep_chipset: - * It is necessary to know which chipset is used. As accesses to - * this device occur at various places in this module, we need a - * static struct pci_dev * pointing to that device. - */ -static struct pci_dev *speedstep_chipset_dev; - - -/* speedstep_processor - */ -static enum speedstep_processor speedstep_processor; - -static u32 pmbase; - -/* - * There are only two frequency states for each processor. Values - * are in kHz for the time being. - */ -static struct cpufreq_frequency_table speedstep_freqs[] = { - {SPEEDSTEP_HIGH, 0}, - {SPEEDSTEP_LOW, 0}, - {0, CPUFREQ_TABLE_END}, -}; - - -/** - * speedstep_find_register - read the PMBASE address - * - * Returns: -ENODEV if no register could be found - */ -static int speedstep_find_register(void) -{ - if (!speedstep_chipset_dev) - return -ENODEV; - - /* get PMBASE */ - pci_read_config_dword(speedstep_chipset_dev, 0x40, &pmbase); - if (!(pmbase & 0x01)) { - printk(KERN_ERR "speedstep-ich: could not find speedstep register\n"); - return -ENODEV; - } - - pmbase &= 0xFFFFFFFE; - if (!pmbase) { - printk(KERN_ERR "speedstep-ich: could not find speedstep register\n"); - return -ENODEV; - } - - pr_debug("pmbase is 0x%x\n", pmbase); - return 0; -} - -/** - * speedstep_set_state - set the SpeedStep state - * @state: new processor frequency state (SPEEDSTEP_LOW or SPEEDSTEP_HIGH) - * - * Tries to change the SpeedStep state. Can be called from - * smp_call_function_single. - */ -static void speedstep_set_state(unsigned int state) -{ - u8 pm2_blk; - u8 value; - unsigned long flags; - - if (state > 0x1) - return; - - /* Disable IRQs */ - local_irq_save(flags); - - /* read state */ - value = inb(pmbase + 0x50); - - pr_debug("read at pmbase 0x%x + 0x50 returned 0x%x\n", pmbase, value); - - /* write new state */ - value &= 0xFE; - value |= state; - - pr_debug("writing 0x%x to pmbase 0x%x + 0x50\n", value, pmbase); - - /* Disable bus master arbitration */ - pm2_blk = inb(pmbase + 0x20); - pm2_blk |= 0x01; - outb(pm2_blk, (pmbase + 0x20)); - - /* Actual transition */ - outb(value, (pmbase + 0x50)); - - /* Restore bus master arbitration */ - pm2_blk &= 0xfe; - outb(pm2_blk, (pmbase + 0x20)); - - /* check if transition was successful */ - value = inb(pmbase + 0x50); - - /* Enable IRQs */ - local_irq_restore(flags); - - pr_debug("read at pmbase 0x%x + 0x50 returned 0x%x\n", pmbase, value); - - if (state == (value & 0x1)) - pr_debug("change to %u MHz succeeded\n", - speedstep_get_frequency(speedstep_processor) / 1000); - else - printk(KERN_ERR "cpufreq: change failed - I/O error\n"); - - return; -} - -/* Wrapper for smp_call_function_single. */ -static void _speedstep_set_state(void *_state) -{ - speedstep_set_state(*(unsigned int *)_state); -} - -/** - * speedstep_activate - activate SpeedStep control in the chipset - * - * Tries to activate the SpeedStep status and control registers. - * Returns -EINVAL on an unsupported chipset, and zero on success. - */ -static int speedstep_activate(void) -{ - u16 value = 0; - - if (!speedstep_chipset_dev) - return -EINVAL; - - pci_read_config_word(speedstep_chipset_dev, 0x00A0, &value); - if (!(value & 0x08)) { - value |= 0x08; - pr_debug("activating SpeedStep (TM) registers\n"); - pci_write_config_word(speedstep_chipset_dev, 0x00A0, value); - } - - return 0; -} - - -/** - * speedstep_detect_chipset - detect the Southbridge which contains SpeedStep logic - * - * Detects ICH2-M, ICH3-M and ICH4-M so far. The pci_dev points to - * the LPC bridge / PM module which contains all power-management - * functions. Returns the SPEEDSTEP_CHIPSET_-number for the detected - * chipset, or zero on failure. - */ -static unsigned int speedstep_detect_chipset(void) -{ - speedstep_chipset_dev = pci_get_subsys(PCI_VENDOR_ID_INTEL, - PCI_DEVICE_ID_INTEL_82801DB_12, - PCI_ANY_ID, PCI_ANY_ID, - NULL); - if (speedstep_chipset_dev) - return 4; /* 4-M */ - - speedstep_chipset_dev = pci_get_subsys(PCI_VENDOR_ID_INTEL, - PCI_DEVICE_ID_INTEL_82801CA_12, - PCI_ANY_ID, PCI_ANY_ID, - NULL); - if (speedstep_chipset_dev) - return 3; /* 3-M */ - - - speedstep_chipset_dev = pci_get_subsys(PCI_VENDOR_ID_INTEL, - PCI_DEVICE_ID_INTEL_82801BA_10, - PCI_ANY_ID, PCI_ANY_ID, - NULL); - if (speedstep_chipset_dev) { - /* speedstep.c causes lockups on Dell Inspirons 8000 and - * 8100 which use a pretty old revision of the 82815 - * host brige. Abort on these systems. - */ - static struct pci_dev *hostbridge; - - hostbridge = pci_get_subsys(PCI_VENDOR_ID_INTEL, - PCI_DEVICE_ID_INTEL_82815_MC, - PCI_ANY_ID, PCI_ANY_ID, - NULL); - - if (!hostbridge) - return 2; /* 2-M */ - - if (hostbridge->revision < 5) { - pr_debug("hostbridge does not support speedstep\n"); - speedstep_chipset_dev = NULL; - pci_dev_put(hostbridge); - return 0; - } - - pci_dev_put(hostbridge); - return 2; /* 2-M */ - } - - return 0; -} - -static void get_freq_data(void *_speed) -{ - unsigned int *speed = _speed; - - *speed = speedstep_get_frequency(speedstep_processor); -} - -static unsigned int speedstep_get(unsigned int cpu) -{ - unsigned int speed; - - /* You're supposed to ensure CPU is online. */ - if (smp_call_function_single(cpu, get_freq_data, &speed, 1) != 0) - BUG(); - - pr_debug("detected %u kHz as current frequency\n", speed); - return speed; -} - -/** - * speedstep_target - set a new CPUFreq policy - * @policy: new policy - * @target_freq: the target frequency - * @relation: how that frequency relates to achieved frequency - * (CPUFREQ_RELATION_L or CPUFREQ_RELATION_H) - * - * Sets a new CPUFreq policy. - */ -static int speedstep_target(struct cpufreq_policy *policy, - unsigned int target_freq, - unsigned int relation) -{ - unsigned int newstate = 0, policy_cpu; - struct cpufreq_freqs freqs; - int i; - - if (cpufreq_frequency_table_target(policy, &speedstep_freqs[0], - target_freq, relation, &newstate)) - return -EINVAL; - - policy_cpu = cpumask_any_and(policy->cpus, cpu_online_mask); - freqs.old = speedstep_get(policy_cpu); - freqs.new = speedstep_freqs[newstate].frequency; - freqs.cpu = policy->cpu; - - pr_debug("transiting from %u to %u kHz\n", freqs.old, freqs.new); - - /* no transition necessary */ - if (freqs.old == freqs.new) - return 0; - - for_each_cpu(i, policy->cpus) { - freqs.cpu = i; - cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE); - } - - smp_call_function_single(policy_cpu, _speedstep_set_state, &newstate, - true); - - for_each_cpu(i, policy->cpus) { - freqs.cpu = i; - cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE); - } - - return 0; -} - - -/** - * speedstep_verify - verifies a new CPUFreq policy - * @policy: new policy - * - * Limit must be within speedstep_low_freq and speedstep_high_freq, with - * at least one border included. - */ -static int speedstep_verify(struct cpufreq_policy *policy) -{ - return cpufreq_frequency_table_verify(policy, &speedstep_freqs[0]); -} - -struct get_freqs { - struct cpufreq_policy *policy; - int ret; -}; - -static void get_freqs_on_cpu(void *_get_freqs) -{ - struct get_freqs *get_freqs = _get_freqs; - - get_freqs->ret = - speedstep_get_freqs(speedstep_processor, - &speedstep_freqs[SPEEDSTEP_LOW].frequency, - &speedstep_freqs[SPEEDSTEP_HIGH].frequency, - &get_freqs->policy->cpuinfo.transition_latency, - &speedstep_set_state); -} - -static int speedstep_cpu_init(struct cpufreq_policy *policy) -{ - int result; - unsigned int policy_cpu, speed; - struct get_freqs gf; - - /* only run on CPU to be set, or on its sibling */ -#ifdef CONFIG_SMP - cpumask_copy(policy->cpus, cpu_sibling_mask(policy->cpu)); -#endif - policy_cpu = cpumask_any_and(policy->cpus, cpu_online_mask); - - /* detect low and high frequency and transition latency */ - gf.policy = policy; - smp_call_function_single(policy_cpu, get_freqs_on_cpu, &gf, 1); - if (gf.ret) - return gf.ret; - - /* get current speed setting */ - speed = speedstep_get(policy_cpu); - if (!speed) - return -EIO; - - pr_debug("currently at %s speed setting - %i MHz\n", - (speed == speedstep_freqs[SPEEDSTEP_LOW].frequency) - ? "low" : "high", - (speed / 1000)); - - /* cpuinfo and default policy values */ - policy->cur = speed; - - result = cpufreq_frequency_table_cpuinfo(policy, speedstep_freqs); - if (result) - return result; - - cpufreq_frequency_table_get_attr(speedstep_freqs, policy->cpu); - - return 0; -} - - -static int speedstep_cpu_exit(struct cpufreq_policy *policy) -{ - cpufreq_frequency_table_put_attr(policy->cpu); - return 0; -} - -static struct freq_attr *speedstep_attr[] = { - &cpufreq_freq_attr_scaling_available_freqs, - NULL, -}; - - -static struct cpufreq_driver speedstep_driver = { - .name = "speedstep-ich", - .verify = speedstep_verify, - .target = speedstep_target, - .init = speedstep_cpu_init, - .exit = speedstep_cpu_exit, - .get = speedstep_get, - .owner = THIS_MODULE, - .attr = speedstep_attr, -}; - - -/** - * speedstep_init - initializes the SpeedStep CPUFreq driver - * - * Initializes the SpeedStep support. Returns -ENODEV on unsupported - * devices, -EINVAL on problems during initiatization, and zero on - * success. - */ -static int __init speedstep_init(void) -{ - /* detect processor */ - speedstep_processor = speedstep_detect_processor(); - if (!speedstep_processor) { - pr_debug("Intel(R) SpeedStep(TM) capable processor " - "not found\n"); - return -ENODEV; - } - - /* detect chipset */ - if (!speedstep_detect_chipset()) { - pr_debug("Intel(R) SpeedStep(TM) for this chipset not " - "(yet) available.\n"); - return -ENODEV; - } - - /* activate speedstep support */ - if (speedstep_activate()) { - pci_dev_put(speedstep_chipset_dev); - return -EINVAL; - } - - if (speedstep_find_register()) - return -ENODEV; - - return cpufreq_register_driver(&speedstep_driver); -} - - -/** - * speedstep_exit - unregisters SpeedStep support - * - * Unregisters SpeedStep support. - */ -static void __exit speedstep_exit(void) -{ - pci_dev_put(speedstep_chipset_dev); - cpufreq_unregister_driver(&speedstep_driver); -} - - -MODULE_AUTHOR("Dave Jones , " - "Dominik Brodowski "); -MODULE_DESCRIPTION("Speedstep driver for Intel mobile processors on chipsets " - "with ICH-M southbridges."); -MODULE_LICENSE("GPL"); - -module_init(speedstep_init); -module_exit(speedstep_exit); diff --git a/arch/x86/kernel/cpu/cpufreq/speedstep-lib.c b/arch/x86/kernel/cpu/cpufreq/speedstep-lib.c deleted file mode 100644 index 8af2d2f..0000000 --- a/arch/x86/kernel/cpu/cpufreq/speedstep-lib.c +++ /dev/null @@ -1,478 +0,0 @@ -/* - * (C) 2002 - 2003 Dominik Brodowski - * - * Licensed under the terms of the GNU GPL License version 2. - * - * Library for common functions for Intel SpeedStep v.1 and v.2 support - * - * BIG FAT DISCLAIMER: Work in progress code. Possibly *dangerous* - */ - -#include -#include -#include -#include -#include - -#include -#include -#include "speedstep-lib.h" - -#define PFX "speedstep-lib: " - -#ifdef CONFIG_X86_SPEEDSTEP_RELAXED_CAP_CHECK -static int relaxed_check; -#else -#define relaxed_check 0 -#endif - -/********************************************************************* - * GET PROCESSOR CORE SPEED IN KHZ * - *********************************************************************/ - -static unsigned int pentium3_get_frequency(enum speedstep_processor processor) -{ - /* See table 14 of p3_ds.pdf and table 22 of 29834003.pdf */ - struct { - unsigned int ratio; /* Frequency Multiplier (x10) */ - u8 bitmap; /* power on configuration bits - [27, 25:22] (in MSR 0x2a) */ - } msr_decode_mult[] = { - { 30, 0x01 }, - { 35, 0x05 }, - { 40, 0x02 }, - { 45, 0x06 }, - { 50, 0x00 }, - { 55, 0x04 }, - { 60, 0x0b }, - { 65, 0x0f }, - { 70, 0x09 }, - { 75, 0x0d }, - { 80, 0x0a }, - { 85, 0x26 }, - { 90, 0x20 }, - { 100, 0x2b }, - { 0, 0xff } /* error or unknown value */ - }; - - /* PIII(-M) FSB settings: see table b1-b of 24547206.pdf */ - struct { - unsigned int value; /* Front Side Bus speed in MHz */ - u8 bitmap; /* power on configuration bits [18: 19] - (in MSR 0x2a) */ - } msr_decode_fsb[] = { - { 66, 0x0 }, - { 100, 0x2 }, - { 133, 0x1 }, - { 0, 0xff} - }; - - u32 msr_lo, msr_tmp; - int i = 0, j = 0; - - /* read MSR 0x2a - we only need the low 32 bits */ - rdmsr(MSR_IA32_EBL_CR_POWERON, msr_lo, msr_tmp); - pr_debug("P3 - MSR_IA32_EBL_CR_POWERON: 0x%x 0x%x\n", msr_lo, msr_tmp); - msr_tmp = msr_lo; - - /* decode the FSB */ - msr_tmp &= 0x00c0000; - msr_tmp >>= 18; - while (msr_tmp != msr_decode_fsb[i].bitmap) { - if (msr_decode_fsb[i].bitmap == 0xff) - return 0; - i++; - } - - /* decode the multiplier */ - if (processor == SPEEDSTEP_CPU_PIII_C_EARLY) { - pr_debug("workaround for early PIIIs\n"); - msr_lo &= 0x03c00000; - } else - msr_lo &= 0x0bc00000; - msr_lo >>= 22; - while (msr_lo != msr_decode_mult[j].bitmap) { - if (msr_decode_mult[j].bitmap == 0xff) - return 0; - j++; - } - - pr_debug("speed is %u\n", - (msr_decode_mult[j].ratio * msr_decode_fsb[i].value * 100)); - - return msr_decode_mult[j].ratio * msr_decode_fsb[i].value * 100; -} - - -static unsigned int pentiumM_get_frequency(void) -{ - u32 msr_lo, msr_tmp; - - rdmsr(MSR_IA32_EBL_CR_POWERON, msr_lo, msr_tmp); - pr_debug("PM - MSR_IA32_EBL_CR_POWERON: 0x%x 0x%x\n", msr_lo, msr_tmp); - - /* see table B-2 of 24547212.pdf */ - if (msr_lo & 0x00040000) { - printk(KERN_DEBUG PFX "PM - invalid FSB: 0x%x 0x%x\n", - msr_lo, msr_tmp); - return 0; - } - - msr_tmp = (msr_lo >> 22) & 0x1f; - pr_debug("bits 22-26 are 0x%x, speed is %u\n", - msr_tmp, (msr_tmp * 100 * 1000)); - - return msr_tmp * 100 * 1000; -} - -static unsigned int pentium_core_get_frequency(void) -{ - u32 fsb = 0; - u32 msr_lo, msr_tmp; - int ret; - - rdmsr(MSR_FSB_FREQ, msr_lo, msr_tmp); - /* see table B-2 of 25366920.pdf */ - switch (msr_lo & 0x07) { - case 5: - fsb = 100000; - break; - case 1: - fsb = 133333; - break; - case 3: - fsb = 166667; - break; - case 2: - fsb = 200000; - break; - case 0: - fsb = 266667; - break; - case 4: - fsb = 333333; - break; - default: - printk(KERN_ERR "PCORE - MSR_FSB_FREQ undefined value"); - } - - rdmsr(MSR_IA32_EBL_CR_POWERON, msr_lo, msr_tmp); - pr_debug("PCORE - MSR_IA32_EBL_CR_POWERON: 0x%x 0x%x\n", - msr_lo, msr_tmp); - - msr_tmp = (msr_lo >> 22) & 0x1f; - pr_debug("bits 22-26 are 0x%x, speed is %u\n", - msr_tmp, (msr_tmp * fsb)); - - ret = (msr_tmp * fsb); - return ret; -} - - -static unsigned int pentium4_get_frequency(void) -{ - struct cpuinfo_x86 *c = &boot_cpu_data; - u32 msr_lo, msr_hi, mult; - unsigned int fsb = 0; - unsigned int ret; - u8 fsb_code; - - /* Pentium 4 Model 0 and 1 do not have the Core Clock Frequency - * to System Bus Frequency Ratio Field in the Processor Frequency - * Configuration Register of the MSR. Therefore the current - * frequency cannot be calculated and has to be measured. - */ - if (c->x86_model < 2) - return cpu_khz; - - rdmsr(0x2c, msr_lo, msr_hi); - - pr_debug("P4 - MSR_EBC_FREQUENCY_ID: 0x%x 0x%x\n", msr_lo, msr_hi); - - /* decode the FSB: see IA-32 Intel (C) Architecture Software - * Developer's Manual, Volume 3: System Prgramming Guide, - * revision #12 in Table B-1: MSRs in the Pentium 4 and - * Intel Xeon Processors, on page B-4 and B-5. - */ - fsb_code = (msr_lo >> 16) & 0x7; - switch (fsb_code) { - case 0: - fsb = 100 * 1000; - break; - case 1: - fsb = 13333 * 10; - break; - case 2: - fsb = 200 * 1000; - break; - } - - if (!fsb) - printk(KERN_DEBUG PFX "couldn't detect FSB speed. " - "Please send an e-mail to \n"); - - /* Multiplier. */ - mult = msr_lo >> 24; - - pr_debug("P4 - FSB %u kHz; Multiplier %u; Speed %u kHz\n", - fsb, mult, (fsb * mult)); - - ret = (fsb * mult); - return ret; -} - - -/* Warning: may get called from smp_call_function_single. */ -unsigned int speedstep_get_frequency(enum speedstep_processor processor) -{ - switch (processor) { - case SPEEDSTEP_CPU_PCORE: - return pentium_core_get_frequency(); - case SPEEDSTEP_CPU_PM: - return pentiumM_get_frequency(); - case SPEEDSTEP_CPU_P4D: - case SPEEDSTEP_CPU_P4M: - return pentium4_get_frequency(); - case SPEEDSTEP_CPU_PIII_T: - case SPEEDSTEP_CPU_PIII_C: - case SPEEDSTEP_CPU_PIII_C_EARLY: - return pentium3_get_frequency(processor); - default: - return 0; - }; - return 0; -} -EXPORT_SYMBOL_GPL(speedstep_get_frequency); - - -/********************************************************************* - * DETECT SPEEDSTEP-CAPABLE PROCESSOR * - *********************************************************************/ - -unsigned int speedstep_detect_processor(void) -{ - struct cpuinfo_x86 *c = &cpu_data(0); - u32 ebx, msr_lo, msr_hi; - - pr_debug("x86: %x, model: %x\n", c->x86, c->x86_model); - - if ((c->x86_vendor != X86_VENDOR_INTEL) || - ((c->x86 != 6) && (c->x86 != 0xF))) - return 0; - - if (c->x86 == 0xF) { - /* Intel Mobile Pentium 4-M - * or Intel Mobile Pentium 4 with 533 MHz FSB */ - if (c->x86_model != 2) - return 0; - - ebx = cpuid_ebx(0x00000001); - ebx &= 0x000000FF; - - pr_debug("ebx value is %x, x86_mask is %x\n", ebx, c->x86_mask); - - switch (c->x86_mask) { - case 4: - /* - * B-stepping [M-P4-M] - * sample has ebx = 0x0f, production has 0x0e. - */ - if ((ebx == 0x0e) || (ebx == 0x0f)) - return SPEEDSTEP_CPU_P4M; - break; - case 7: - /* - * C-stepping [M-P4-M] - * needs to have ebx=0x0e, else it's a celeron: - * cf. 25130917.pdf / page 7, footnote 5 even - * though 25072120.pdf / page 7 doesn't say - * samples are only of B-stepping... - */ - if (ebx == 0x0e) - return SPEEDSTEP_CPU_P4M; - break; - case 9: - /* - * D-stepping [M-P4-M or M-P4/533] - * - * this is totally strange: CPUID 0x0F29 is - * used by M-P4-M, M-P4/533 and(!) Celeron CPUs. - * The latter need to be sorted out as they don't - * support speedstep. - * Celerons with CPUID 0x0F29 may have either - * ebx=0x8 or 0xf -- 25130917.pdf doesn't say anything - * specific. - * M-P4-Ms may have either ebx=0xe or 0xf [see above] - * M-P4/533 have either ebx=0xe or 0xf. [25317607.pdf] - * also, M-P4M HTs have ebx=0x8, too - * For now, they are distinguished by the model_id - * string - */ - if ((ebx == 0x0e) || - (strstr(c->x86_model_id, - "Mobile Intel(R) Pentium(R) 4") != NULL)) - return SPEEDSTEP_CPU_P4M; - break; - default: - break; - } - return 0; - } - - switch (c->x86_model) { - case 0x0B: /* Intel PIII [Tualatin] */ - /* cpuid_ebx(1) is 0x04 for desktop PIII, - * 0x06 for mobile PIII-M */ - ebx = cpuid_ebx(0x00000001); - pr_debug("ebx is %x\n", ebx); - - ebx &= 0x000000FF; - - if (ebx != 0x06) - return 0; - - /* So far all PIII-M processors support SpeedStep. See - * Intel's 24540640.pdf of June 2003 - */ - return SPEEDSTEP_CPU_PIII_T; - - case 0x08: /* Intel PIII [Coppermine] */ - - /* all mobile PIII Coppermines have FSB 100 MHz - * ==> sort out a few desktop PIIIs. */ - rdmsr(MSR_IA32_EBL_CR_POWERON, msr_lo, msr_hi); - pr_debug("Coppermine: MSR_IA32_EBL_CR_POWERON is 0x%x, 0x%x\n", - msr_lo, msr_hi); - msr_lo &= 0x00c0000; - if (msr_lo != 0x0080000) - return 0; - - /* - * If the processor is a mobile version, - * platform ID has bit 50 set - * it has SpeedStep technology if either - * bit 56 or 57 is set - */ - rdmsr(MSR_IA32_PLATFORM_ID, msr_lo, msr_hi); - pr_debug("Coppermine: MSR_IA32_PLATFORM ID is 0x%x, 0x%x\n", - msr_lo, msr_hi); - if ((msr_hi & (1<<18)) && - (relaxed_check ? 1 : (msr_hi & (3<<24)))) { - if (c->x86_mask == 0x01) { - pr_debug("early PIII version\n"); - return SPEEDSTEP_CPU_PIII_C_EARLY; - } else - return SPEEDSTEP_CPU_PIII_C; - } - - default: - return 0; - } -} -EXPORT_SYMBOL_GPL(speedstep_detect_processor); - - -/********************************************************************* - * DETECT SPEEDSTEP SPEEDS * - *********************************************************************/ - -unsigned int speedstep_get_freqs(enum speedstep_processor processor, - unsigned int *low_speed, - unsigned int *high_speed, - unsigned int *transition_latency, - void (*set_state) (unsigned int state)) -{ - unsigned int prev_speed; - unsigned int ret = 0; - unsigned long flags; - struct timeval tv1, tv2; - - if ((!processor) || (!low_speed) || (!high_speed) || (!set_state)) - return -EINVAL; - - pr_debug("trying to determine both speeds\n"); - - /* get current speed */ - prev_speed = speedstep_get_frequency(processor); - if (!prev_speed) - return -EIO; - - pr_debug("previous speed is %u\n", prev_speed); - - local_irq_save(flags); - - /* switch to low state */ - set_state(SPEEDSTEP_LOW); - *low_speed = speedstep_get_frequency(processor); - if (!*low_speed) { - ret = -EIO; - goto out; - } - - pr_debug("low speed is %u\n", *low_speed); - - /* start latency measurement */ - if (transition_latency) - do_gettimeofday(&tv1); - - /* switch to high state */ - set_state(SPEEDSTEP_HIGH); - - /* end latency measurement */ - if (transition_latency) - do_gettimeofday(&tv2); - - *high_speed = speedstep_get_frequency(processor); - if (!*high_speed) { - ret = -EIO; - goto out; - } - - pr_debug("high speed is %u\n", *high_speed); - - if (*low_speed == *high_speed) { - ret = -ENODEV; - goto out; - } - - /* switch to previous state, if necessary */ - if (*high_speed != prev_speed) - set_state(SPEEDSTEP_LOW); - - if (transition_latency) { - *transition_latency = (tv2.tv_sec - tv1.tv_sec) * USEC_PER_SEC + - tv2.tv_usec - tv1.tv_usec; - pr_debug("transition latency is %u uSec\n", *transition_latency); - - /* convert uSec to nSec and add 20% for safety reasons */ - *transition_latency *= 1200; - - /* check if the latency measurement is too high or too low - * and set it to a safe value (500uSec) in that case - */ - if (*transition_latency > 10000000 || - *transition_latency < 50000) { - printk(KERN_WARNING PFX "frequency transition " - "measured seems out of range (%u " - "nSec), falling back to a safe one of" - "%u nSec.\n", - *transition_latency, 500000); - *transition_latency = 500000; - } - } - -out: - local_irq_restore(flags); - return ret; -} -EXPORT_SYMBOL_GPL(speedstep_get_freqs); - -#ifdef CONFIG_X86_SPEEDSTEP_RELAXED_CAP_CHECK -module_param(relaxed_check, int, 0444); -MODULE_PARM_DESC(relaxed_check, - "Don't do all checks for speedstep capability."); -#endif - -MODULE_AUTHOR("Dominik Brodowski "); -MODULE_DESCRIPTION("Library for Intel SpeedStep 1 or 2 cpufreq drivers."); -MODULE_LICENSE("GPL"); diff --git a/arch/x86/kernel/cpu/cpufreq/speedstep-lib.h b/arch/x86/kernel/cpu/cpufreq/speedstep-lib.h deleted file mode 100644 index 70d9cea..0000000 --- a/arch/x86/kernel/cpu/cpufreq/speedstep-lib.h +++ /dev/null @@ -1,49 +0,0 @@ -/* - * (C) 2002 - 2003 Dominik Brodowski - * - * Licensed under the terms of the GNU GPL License version 2. - * - * Library for common functions for Intel SpeedStep v.1 and v.2 support - * - * BIG FAT DISCLAIMER: Work in progress code. Possibly *dangerous* - */ - - - -/* processors */ -enum speedstep_processor { - SPEEDSTEP_CPU_PIII_C_EARLY = 0x00000001, /* Coppermine core */ - SPEEDSTEP_CPU_PIII_C = 0x00000002, /* Coppermine core */ - SPEEDSTEP_CPU_PIII_T = 0x00000003, /* Tualatin core */ - SPEEDSTEP_CPU_P4M = 0x00000004, /* P4-M */ -/* the following processors are not speedstep-capable and are not auto-detected - * in speedstep_detect_processor(). However, their speed can be detected using - * the speedstep_get_frequency() call. */ - SPEEDSTEP_CPU_PM = 0xFFFFFF03, /* Pentium M */ - SPEEDSTEP_CPU_P4D = 0xFFFFFF04, /* desktop P4 */ - SPEEDSTEP_CPU_PCORE = 0xFFFFFF05, /* Core */ -}; - -/* speedstep states -- only two of them */ - -#define SPEEDSTEP_HIGH 0x00000000 -#define SPEEDSTEP_LOW 0x00000001 - - -/* detect a speedstep-capable processor */ -extern enum speedstep_processor speedstep_detect_processor(void); - -/* detect the current speed (in khz) of the processor */ -extern unsigned int speedstep_get_frequency(enum speedstep_processor processor); - - -/* detect the low and high speeds of the processor. The callback - * set_state"'s first argument is either SPEEDSTEP_HIGH or - * SPEEDSTEP_LOW; the second argument is zero so that no - * cpufreq_notify_transition calls are initiated. - */ -extern unsigned int speedstep_get_freqs(enum speedstep_processor processor, - unsigned int *low_speed, - unsigned int *high_speed, - unsigned int *transition_latency, - void (*set_state) (unsigned int state)); diff --git a/arch/x86/kernel/cpu/cpufreq/speedstep-smi.c b/arch/x86/kernel/cpu/cpufreq/speedstep-smi.c deleted file mode 100644 index c76ead3..0000000 --- a/arch/x86/kernel/cpu/cpufreq/speedstep-smi.c +++ /dev/null @@ -1,464 +0,0 @@ -/* - * Intel SpeedStep SMI driver. - * - * (C) 2003 Hiroshi Miura - * - * Licensed under the terms of the GNU GPL License version 2. - * - */ - - -/********************************************************************* - * SPEEDSTEP - DEFINITIONS * - *********************************************************************/ - -#include -#include -#include -#include -#include -#include -#include -#include - -#include "speedstep-lib.h" - -/* speedstep system management interface port/command. - * - * These parameters are got from IST-SMI BIOS call. - * If user gives it, these are used. - * - */ -static int smi_port; -static int smi_cmd; -static unsigned int smi_sig; - -/* info about the processor */ -static enum speedstep_processor speedstep_processor; - -/* - * There are only two frequency states for each processor. Values - * are in kHz for the time being. - */ -static struct cpufreq_frequency_table speedstep_freqs[] = { - {SPEEDSTEP_HIGH, 0}, - {SPEEDSTEP_LOW, 0}, - {0, CPUFREQ_TABLE_END}, -}; - -#define GET_SPEEDSTEP_OWNER 0 -#define GET_SPEEDSTEP_STATE 1 -#define SET_SPEEDSTEP_STATE 2 -#define GET_SPEEDSTEP_FREQS 4 - -/* how often shall the SMI call be tried if it failed, e.g. because - * of DMA activity going on? */ -#define SMI_TRIES 5 - -/** - * speedstep_smi_ownership - */ -static int speedstep_smi_ownership(void) -{ - u32 command, result, magic, dummy; - u32 function = GET_SPEEDSTEP_OWNER; - unsigned char magic_data[] = "Copyright (c) 1999 Intel Corporation"; - - command = (smi_sig & 0xffffff00) | (smi_cmd & 0xff); - magic = virt_to_phys(magic_data); - - pr_debug("trying to obtain ownership with command %x at port %x\n", - command, smi_port); - - __asm__ __volatile__( - "push %%ebp\n" - "out %%al, (%%dx)\n" - "pop %%ebp\n" - : "=D" (result), - "=a" (dummy), "=b" (dummy), "=c" (dummy), "=d" (dummy), - "=S" (dummy) - : "a" (command), "b" (function), "c" (0), "d" (smi_port), - "D" (0), "S" (magic) - : "memory" - ); - - pr_debug("result is %x\n", result); - - return result; -} - -/** - * speedstep_smi_get_freqs - get SpeedStep preferred & current freq. - * @low: the low frequency value is placed here - * @high: the high frequency value is placed here - * - * Only available on later SpeedStep-enabled systems, returns false results or - * even hangs [cf. bugme.osdl.org # 1422] on earlier systems. Empirical testing - * shows that the latter occurs if !(ist_info.event & 0xFFFF). - */ -static int speedstep_smi_get_freqs(unsigned int *low, unsigned int *high) -{ - u32 command, result = 0, edi, high_mhz, low_mhz, dummy; - u32 state = 0; - u32 function = GET_SPEEDSTEP_FREQS; - - if (!(ist_info.event & 0xFFFF)) { - pr_debug("bug #1422 -- can't read freqs from BIOS\n"); - return -ENODEV; - } - - command = (smi_sig & 0xffffff00) | (smi_cmd & 0xff); - - pr_debug("trying to determine frequencies with command %x at port %x\n", - command, smi_port); - - __asm__ __volatile__( - "push %%ebp\n" - "out %%al, (%%dx)\n" - "pop %%ebp" - : "=a" (result), - "=b" (high_mhz), - "=c" (low_mhz), - "=d" (state), "=D" (edi), "=S" (dummy) - : "a" (command), - "b" (function), - "c" (state), - "d" (smi_port), "S" (0), "D" (0) - ); - - pr_debug("result %x, low_freq %u, high_freq %u\n", - result, low_mhz, high_mhz); - - /* abort if results are obviously incorrect... */ - if ((high_mhz + low_mhz) < 600) - return -EINVAL; - - *high = high_mhz * 1000; - *low = low_mhz * 1000; - - return result; -} - -/** - * speedstep_get_state - set the SpeedStep state - * @state: processor frequency state (SPEEDSTEP_LOW or SPEEDSTEP_HIGH) - * - */ -static int speedstep_get_state(void) -{ - u32 function = GET_SPEEDSTEP_STATE; - u32 result, state, edi, command, dummy; - - command = (smi_sig & 0xffffff00) | (smi_cmd & 0xff); - - pr_debug("trying to determine current setting with command %x " - "at port %x\n", command, smi_port); - - __asm__ __volatile__( - "push %%ebp\n" - "out %%al, (%%dx)\n" - "pop %%ebp\n" - : "=a" (result), - "=b" (state), "=D" (edi), - "=c" (dummy), "=d" (dummy), "=S" (dummy) - : "a" (command), "b" (function), "c" (0), - "d" (smi_port), "S" (0), "D" (0) - ); - - pr_debug("state is %x, result is %x\n", state, result); - - return state & 1; -} - - -/** - * speedstep_set_state - set the SpeedStep state - * @state: new processor frequency state (SPEEDSTEP_LOW or SPEEDSTEP_HIGH) - * - */ -static void speedstep_set_state(unsigned int state) -{ - unsigned int result = 0, command, new_state, dummy; - unsigned long flags; - unsigned int function = SET_SPEEDSTEP_STATE; - unsigned int retry = 0; - - if (state > 0x1) - return; - - /* Disable IRQs */ - local_irq_save(flags); - - command = (smi_sig & 0xffffff00) | (smi_cmd & 0xff); - - pr_debug("trying to set frequency to state %u " - "with command %x at port %x\n", - state, command, smi_port); - - do { - if (retry) { - pr_debug("retry %u, previous result %u, waiting...\n", - retry, result); - mdelay(retry * 50); - } - retry++; - __asm__ __volatile__( - "push %%ebp\n" - "out %%al, (%%dx)\n" - "pop %%ebp" - : "=b" (new_state), "=D" (result), - "=c" (dummy), "=a" (dummy), - "=d" (dummy), "=S" (dummy) - : "a" (command), "b" (function), "c" (state), - "d" (smi_port), "S" (0), "D" (0) - ); - } while ((new_state != state) && (retry <= SMI_TRIES)); - - /* enable IRQs */ - local_irq_restore(flags); - - if (new_state == state) - pr_debug("change to %u MHz succeeded after %u tries " - "with result %u\n", - (speedstep_freqs[new_state].frequency / 1000), - retry, result); - else - printk(KERN_ERR "cpufreq: change to state %u " - "failed with new_state %u and result %u\n", - state, new_state, result); - - return; -} - - -/** - * speedstep_target - set a new CPUFreq policy - * @policy: new policy - * @target_freq: new freq - * @relation: - * - * Sets a new CPUFreq policy/freq. - */ -static int speedstep_target(struct cpufreq_policy *policy, - unsigned int target_freq, unsigned int relation) -{ - unsigned int newstate = 0; - struct cpufreq_freqs freqs; - - if (cpufreq_frequency_table_target(policy, &speedstep_freqs[0], - target_freq, relation, &newstate)) - return -EINVAL; - - freqs.old = speedstep_freqs[speedstep_get_state()].frequency; - freqs.new = speedstep_freqs[newstate].frequency; - freqs.cpu = 0; /* speedstep.c is UP only driver */ - - if (freqs.old == freqs.new) - return 0; - - cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE); - speedstep_set_state(newstate); - cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE); - - return 0; -} - - -/** - * speedstep_verify - verifies a new CPUFreq policy - * @policy: new policy - * - * Limit must be within speedstep_low_freq and speedstep_high_freq, with - * at least one border included. - */ -static int speedstep_verify(struct cpufreq_policy *policy) -{ - return cpufreq_frequency_table_verify(policy, &speedstep_freqs[0]); -} - - -static int speedstep_cpu_init(struct cpufreq_policy *policy) -{ - int result; - unsigned int speed, state; - unsigned int *low, *high; - - /* capability check */ - if (policy->cpu != 0) - return -ENODEV; - - result = speedstep_smi_ownership(); - if (result) { - pr_debug("fails in acquiring ownership of a SMI interface.\n"); - return -EINVAL; - } - - /* detect low and high frequency */ - low = &speedstep_freqs[SPEEDSTEP_LOW].frequency; - high = &speedstep_freqs[SPEEDSTEP_HIGH].frequency; - - result = speedstep_smi_get_freqs(low, high); - if (result) { - /* fall back to speedstep_lib.c dection mechanism: - * try both states out */ - pr_debug("could not detect low and high frequencies " - "by SMI call.\n"); - result = speedstep_get_freqs(speedstep_processor, - low, high, - NULL, - &speedstep_set_state); - - if (result) { - pr_debug("could not detect two different speeds" - " -- aborting.\n"); - return result; - } else - pr_debug("workaround worked.\n"); - } - - /* get current speed setting */ - state = speedstep_get_state(); - speed = speedstep_freqs[state].frequency; - - pr_debug("currently at %s speed setting - %i MHz\n", - (speed == speedstep_freqs[SPEEDSTEP_LOW].frequency) - ? "low" : "high", - (speed / 1000)); - - /* cpuinfo and default policy values */ - policy->cpuinfo.transition_latency = CPUFREQ_ETERNAL; - policy->cur = speed; - - result = cpufreq_frequency_table_cpuinfo(policy, speedstep_freqs); - if (result) - return result; - - cpufreq_frequency_table_get_attr(speedstep_freqs, policy->cpu); - - return 0; -} - -static int speedstep_cpu_exit(struct cpufreq_policy *policy) -{ - cpufreq_frequency_table_put_attr(policy->cpu); - return 0; -} - -static unsigned int speedstep_get(unsigned int cpu) -{ - if (cpu) - return -ENODEV; - return speedstep_get_frequency(speedstep_processor); -} - - -static int speedstep_resume(struct cpufreq_policy *policy) -{ - int result = speedstep_smi_ownership(); - - if (result) - pr_debug("fails in re-acquiring ownership of a SMI interface.\n"); - - return result; -} - -static struct freq_attr *speedstep_attr[] = { - &cpufreq_freq_attr_scaling_available_freqs, - NULL, -}; - -static struct cpufreq_driver speedstep_driver = { - .name = "speedstep-smi", - .verify = speedstep_verify, - .target = speedstep_target, - .init = speedstep_cpu_init, - .exit = speedstep_cpu_exit, - .get = speedstep_get, - .resume = speedstep_resume, - .owner = THIS_MODULE, - .attr = speedstep_attr, -}; - -/** - * speedstep_init - initializes the SpeedStep CPUFreq driver - * - * Initializes the SpeedStep support. Returns -ENODEV on unsupported - * BIOS, -EINVAL on problems during initiatization, and zero on - * success. - */ -static int __init speedstep_init(void) -{ - speedstep_processor = speedstep_detect_processor(); - - switch (speedstep_processor) { - case SPEEDSTEP_CPU_PIII_T: - case SPEEDSTEP_CPU_PIII_C: - case SPEEDSTEP_CPU_PIII_C_EARLY: - break; - default: - speedstep_processor = 0; - } - - if (!speedstep_processor) { - pr_debug("No supported Intel CPU detected.\n"); - return -ENODEV; - } - - pr_debug("signature:0x%.8ulx, command:0x%.8ulx, " - "event:0x%.8ulx, perf_level:0x%.8ulx.\n", - ist_info.signature, ist_info.command, - ist_info.event, ist_info.perf_level); - - /* Error if no IST-SMI BIOS or no PARM - sig= 'ISGE' aka 'Intel Speedstep Gate E' */ - if ((ist_info.signature != 0x47534943) && ( - (smi_port == 0) || (smi_cmd == 0))) - return -ENODEV; - - if (smi_sig == 1) - smi_sig = 0x47534943; - else - smi_sig = ist_info.signature; - - /* setup smi_port from MODLULE_PARM or BIOS */ - if ((smi_port > 0xff) || (smi_port < 0)) - return -EINVAL; - else if (smi_port == 0) - smi_port = ist_info.command & 0xff; - - if ((smi_cmd > 0xff) || (smi_cmd < 0)) - return -EINVAL; - else if (smi_cmd == 0) - smi_cmd = (ist_info.command >> 16) & 0xff; - - return cpufreq_register_driver(&speedstep_driver); -} - - -/** - * speedstep_exit - unregisters SpeedStep support - * - * Unregisters SpeedStep support. - */ -static void __exit speedstep_exit(void) -{ - cpufreq_unregister_driver(&speedstep_driver); -} - -module_param(smi_port, int, 0444); -module_param(smi_cmd, int, 0444); -module_param(smi_sig, uint, 0444); - -MODULE_PARM_DESC(smi_port, "Override the BIOS-given IST port with this value " - "-- Intel's default setting is 0xb2"); -MODULE_PARM_DESC(smi_cmd, "Override the BIOS-given IST command with this value " - "-- Intel's default setting is 0x82"); -MODULE_PARM_DESC(smi_sig, "Set to 1 to fake the IST signature when using the " - "SMI interface."); - -MODULE_AUTHOR("Hiroshi Miura"); -MODULE_DESCRIPTION("Speedstep driver for IST applet SMI interface."); -MODULE_LICENSE("GPL"); - -module_init(speedstep_init); -module_exit(speedstep_exit); diff --git a/drivers/cpufreq/Kconfig b/drivers/cpufreq/Kconfig index b78baa54..9fb8485 100644 --- a/drivers/cpufreq/Kconfig +++ b/drivers/cpufreq/Kconfig @@ -1,3 +1,5 @@ +menu "CPU Frequency scaling" + config CPU_FREQ bool "CPU Frequency scaling" help @@ -177,4 +179,10 @@ config CPU_FREQ_GOV_CONSERVATIVE If in doubt, say N. -endif # CPU_FREQ +menu "x86 CPU frequency scaling drivers" +depends on X86 +source "drivers/cpufreq/Kconfig.x86" +endmenu + +endif +endmenu diff --git a/drivers/cpufreq/Kconfig.x86 b/drivers/cpufreq/Kconfig.x86 new file mode 100644 index 0000000..343f847 --- /dev/null +++ b/drivers/cpufreq/Kconfig.x86 @@ -0,0 +1,255 @@ +# +# x86 CPU Frequency scaling drivers +# + +config X86_PCC_CPUFREQ + tristate "Processor Clocking Control interface driver" + depends on ACPI && ACPI_PROCESSOR + help + This driver adds support for the PCC interface. + + For details, take a look at: + . + + To compile this driver as a module, choose M here: the + module will be called pcc-cpufreq. + + If in doubt, say N. + +config X86_ACPI_CPUFREQ + tristate "ACPI Processor P-States driver" + select CPU_FREQ_TABLE + depends on ACPI_PROCESSOR + help + This driver adds a CPUFreq driver which utilizes the ACPI + Processor Performance States. + This driver also supports Intel Enhanced Speedstep. + + To compile this driver as a module, choose M here: the + module will be called acpi-cpufreq. + + For details, take a look at . + + If in doubt, say N. + +config ELAN_CPUFREQ + tristate "AMD Elan SC400 and SC410" + select CPU_FREQ_TABLE + depends on X86_ELAN + ---help--- + This adds the CPUFreq driver for AMD Elan SC400 and SC410 + processors. + + You need to specify the processor maximum speed as boot + parameter: elanfreq=maxspeed (in kHz) or as module + parameter "max_freq". + + For details, take a look at . + + If in doubt, say N. + +config SC520_CPUFREQ + tristate "AMD Elan SC520" + select CPU_FREQ_TABLE + depends on X86_ELAN + ---help--- + This adds the CPUFreq driver for AMD Elan SC520 processor. + + For details, take a look at . + + If in doubt, say N. + + +config X86_POWERNOW_K6 + tristate "AMD Mobile K6-2/K6-3 PowerNow!" + select CPU_FREQ_TABLE + depends on X86_32 + help + This adds the CPUFreq driver for mobile AMD K6-2+ and mobile + AMD K6-3+ processors. + + For details, take a look at . + + If in doubt, say N. + +config X86_POWERNOW_K7 + tristate "AMD Mobile Athlon/Duron PowerNow!" + select CPU_FREQ_TABLE + depends on X86_32 + help + This adds the CPUFreq driver for mobile AMD K7 mobile processors. + + For details, take a look at . + + If in doubt, say N. + +config X86_POWERNOW_K7_ACPI + bool + depends on X86_POWERNOW_K7 && ACPI_PROCESSOR + depends on !(X86_POWERNOW_K7 = y && ACPI_PROCESSOR = m) + depends on X86_32 + default y + +config X86_POWERNOW_K8 + tristate "AMD Opteron/Athlon64 PowerNow!" + select CPU_FREQ_TABLE + depends on ACPI && ACPI_PROCESSOR + help + This adds the CPUFreq driver for K8/K10 Opteron/Athlon64 processors. + + To compile this driver as a module, choose M here: the + module will be called powernow-k8. + + For details, take a look at . + +config X86_GX_SUSPMOD + tristate "Cyrix MediaGX/NatSemi Geode Suspend Modulation" + depends on X86_32 && PCI + help + This add the CPUFreq driver for NatSemi Geode processors which + support suspend modulation. + + For details, take a look at . + + If in doubt, say N. + +config X86_SPEEDSTEP_CENTRINO + tristate "Intel Enhanced SpeedStep (deprecated)" + select CPU_FREQ_TABLE + select X86_SPEEDSTEP_CENTRINO_TABLE if X86_32 + depends on X86_32 || (X86_64 && ACPI_PROCESSOR) + help + This is deprecated and this functionality is now merged into + acpi_cpufreq (X86_ACPI_CPUFREQ). Use that driver instead of + speedstep_centrino. + This adds the CPUFreq driver for Enhanced SpeedStep enabled + mobile CPUs. This means Intel Pentium M (Centrino) CPUs + or 64bit enabled Intel Xeons. + + To compile this driver as a module, choose M here: the + module will be called speedstep-centrino. + + For details, take a look at . + + If in doubt, say N. + +config X86_SPEEDSTEP_CENTRINO_TABLE + bool "Built-in tables for Banias CPUs" + depends on X86_32 && X86_SPEEDSTEP_CENTRINO + default y + help + Use built-in tables for Banias CPUs if ACPI encoding + is not available. + + If in doubt, say N. + +config X86_SPEEDSTEP_ICH + tristate "Intel Speedstep on ICH-M chipsets (ioport interface)" + select CPU_FREQ_TABLE + depends on X86_32 + help + This adds the CPUFreq driver for certain mobile Intel Pentium III + (Coppermine), all mobile Intel Pentium III-M (Tualatin) and all + mobile Intel Pentium 4 P4-M on systems which have an Intel ICH2, + ICH3 or ICH4 southbridge. + + For details, take a look at . + + If in doubt, say N. + +config X86_SPEEDSTEP_SMI + tristate "Intel SpeedStep on 440BX/ZX/MX chipsets (SMI interface)" + select CPU_FREQ_TABLE + depends on X86_32 && EXPERIMENTAL + help + This adds the CPUFreq driver for certain mobile Intel Pentium III + (Coppermine), all mobile Intel Pentium III-M (Tualatin) + on systems which have an Intel 440BX/ZX/MX southbridge. + + For details, take a look at . + + If in doubt, say N. + +config X86_P4_CLOCKMOD + tristate "Intel Pentium 4 clock modulation" + select CPU_FREQ_TABLE + help + This adds the CPUFreq driver for Intel Pentium 4 / XEON + processors. When enabled it will lower CPU temperature by skipping + clocks. + + This driver should be only used in exceptional + circumstances when very low power is needed because it causes severe + slowdowns and noticeable latencies. Normally Speedstep should be used + instead. + + To compile this driver as a module, choose M here: the + module will be called p4-clockmod. + + For details, take a look at . + + Unless you are absolutely sure say N. + +config X86_CPUFREQ_NFORCE2 + tristate "nVidia nForce2 FSB changing" + depends on X86_32 && EXPERIMENTAL + help + This adds the CPUFreq driver for FSB changing on nVidia nForce2 + platforms. + + For details, take a look at . + + If in doubt, say N. + +config X86_LONGRUN + tristate "Transmeta LongRun" + depends on X86_32 + help + This adds the CPUFreq driver for Transmeta Crusoe and Efficeon processors + which support LongRun. + + For details, take a look at . + + If in doubt, say N. + +config X86_LONGHAUL + tristate "VIA Cyrix III Longhaul" + select CPU_FREQ_TABLE + depends on X86_32 && ACPI_PROCESSOR + help + This adds the CPUFreq driver for VIA Samuel/CyrixIII, + VIA Cyrix Samuel/C3, VIA Cyrix Ezra and VIA Cyrix Ezra-T + processors. + + For details, take a look at . + + If in doubt, say N. + +config X86_E_POWERSAVER + tristate "VIA C7 Enhanced PowerSaver (DANGEROUS)" + select CPU_FREQ_TABLE + depends on X86_32 && EXPERIMENTAL + help + This adds the CPUFreq driver for VIA C7 processors. However, this driver + does not have any safeguards to prevent operating the CPU out of spec + and is thus considered dangerous. Please use the regular ACPI cpufreq + driver, enabled by CONFIG_X86_ACPI_CPUFREQ. + + If in doubt, say N. + +comment "shared options" + +config X86_SPEEDSTEP_LIB + tristate + default (X86_SPEEDSTEP_ICH || X86_SPEEDSTEP_SMI || X86_P4_CLOCKMOD) + +config X86_SPEEDSTEP_RELAXED_CAP_CHECK + bool "Relaxed speedstep capability checks" + depends on X86_32 && (X86_SPEEDSTEP_SMI || X86_SPEEDSTEP_ICH) + help + Don't perform all checks for a speedstep capable system which would + normally be done. Some ancient or strange systems, though speedstep + capable, don't always indicate that they are speedstep capable. This + option lets the probing code bypass some of those checks if the + parameter "relaxed_check=1" is passed to the module. + diff --git a/drivers/cpufreq/Makefile b/drivers/cpufreq/Makefile index 71fc3b4..c7f1a6f 100644 --- a/drivers/cpufreq/Makefile +++ b/drivers/cpufreq/Makefile @@ -13,3 +13,29 @@ obj-$(CONFIG_CPU_FREQ_GOV_CONSERVATIVE) += cpufreq_conservative.o # CPUfreq cross-arch helpers obj-$(CONFIG_CPU_FREQ_TABLE) += freq_table.o +##################################################################################d +# x86 drivers. +# Link order matters. K8 is preferred to ACPI because of firmware bugs in early +# K8 systems. ACPI is preferred to all other hardware-specific drivers. +# speedstep-* is preferred over p4-clockmod. + +obj-$(CONFIG_X86_POWERNOW_K8) += powernow-k8.o mperf.o +obj-$(CONFIG_X86_ACPI_CPUFREQ) += acpi-cpufreq.o mperf.o +obj-$(CONFIG_X86_PCC_CPUFREQ) += pcc-cpufreq.o +obj-$(CONFIG_X86_POWERNOW_K6) += powernow-k6.o +obj-$(CONFIG_X86_POWERNOW_K7) += powernow-k7.o +obj-$(CONFIG_X86_LONGHAUL) += longhaul.o +obj-$(CONFIG_X86_E_POWERSAVER) += e_powersaver.o +obj-$(CONFIG_ELAN_CPUFREQ) += elanfreq.o +obj-$(CONFIG_SC520_CPUFREQ) += sc520_freq.o +obj-$(CONFIG_X86_LONGRUN) += longrun.o +obj-$(CONFIG_X86_GX_SUSPMOD) += gx-suspmod.o +obj-$(CONFIG_X86_SPEEDSTEP_ICH) += speedstep-ich.o +obj-$(CONFIG_X86_SPEEDSTEP_LIB) += speedstep-lib.o +obj-$(CONFIG_X86_SPEEDSTEP_SMI) += speedstep-smi.o +obj-$(CONFIG_X86_SPEEDSTEP_CENTRINO) += speedstep-centrino.o +obj-$(CONFIG_X86_P4_CLOCKMOD) += p4-clockmod.o +obj-$(CONFIG_X86_CPUFREQ_NFORCE2) += cpufreq-nforce2.o + +##################################################################################d + diff --git a/drivers/cpufreq/acpi-cpufreq.c b/drivers/cpufreq/acpi-cpufreq.c new file mode 100644 index 0000000..4e04e12 --- /dev/null +++ b/drivers/cpufreq/acpi-cpufreq.c @@ -0,0 +1,773 @@ +/* + * acpi-cpufreq.c - ACPI Processor P-States Driver + * + * Copyright (C) 2001, 2002 Andy Grover + * Copyright (C) 2001, 2002 Paul Diefenbaugh + * Copyright (C) 2002 - 2004 Dominik Brodowski + * Copyright (C) 2006 Denis Sadykov + * + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or (at + * your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + * + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include + +#include +#include +#include +#include "mperf.h" + +MODULE_AUTHOR("Paul Diefenbaugh, Dominik Brodowski"); +MODULE_DESCRIPTION("ACPI Processor P-States Driver"); +MODULE_LICENSE("GPL"); + +enum { + UNDEFINED_CAPABLE = 0, + SYSTEM_INTEL_MSR_CAPABLE, + SYSTEM_IO_CAPABLE, +}; + +#define INTEL_MSR_RANGE (0xffff) + +struct acpi_cpufreq_data { + struct acpi_processor_performance *acpi_data; + struct cpufreq_frequency_table *freq_table; + unsigned int resume; + unsigned int cpu_feature; +}; + +static DEFINE_PER_CPU(struct acpi_cpufreq_data *, acfreq_data); + +/* acpi_perf_data is a pointer to percpu data. */ +static struct acpi_processor_performance __percpu *acpi_perf_data; + +static struct cpufreq_driver acpi_cpufreq_driver; + +static unsigned int acpi_pstate_strict; + +static int check_est_cpu(unsigned int cpuid) +{ + struct cpuinfo_x86 *cpu = &cpu_data(cpuid); + + return cpu_has(cpu, X86_FEATURE_EST); +} + +static unsigned extract_io(u32 value, struct acpi_cpufreq_data *data) +{ + struct acpi_processor_performance *perf; + int i; + + perf = data->acpi_data; + + for (i = 0; i < perf->state_count; i++) { + if (value == perf->states[i].status) + return data->freq_table[i].frequency; + } + return 0; +} + +static unsigned extract_msr(u32 msr, struct acpi_cpufreq_data *data) +{ + int i; + struct acpi_processor_performance *perf; + + msr &= INTEL_MSR_RANGE; + perf = data->acpi_data; + + for (i = 0; data->freq_table[i].frequency != CPUFREQ_TABLE_END; i++) { + if (msr == perf->states[data->freq_table[i].index].status) + return data->freq_table[i].frequency; + } + return data->freq_table[0].frequency; +} + +static unsigned extract_freq(u32 val, struct acpi_cpufreq_data *data) +{ + switch (data->cpu_feature) { + case SYSTEM_INTEL_MSR_CAPABLE: + return extract_msr(val, data); + case SYSTEM_IO_CAPABLE: + return extract_io(val, data); + default: + return 0; + } +} + +struct msr_addr { + u32 reg; +}; + +struct io_addr { + u16 port; + u8 bit_width; +}; + +struct drv_cmd { + unsigned int type; + const struct cpumask *mask; + union { + struct msr_addr msr; + struct io_addr io; + } addr; + u32 val; +}; + +/* Called via smp_call_function_single(), on the target CPU */ +static void do_drv_read(void *_cmd) +{ + struct drv_cmd *cmd = _cmd; + u32 h; + + switch (cmd->type) { + case SYSTEM_INTEL_MSR_CAPABLE: + rdmsr(cmd->addr.msr.reg, cmd->val, h); + break; + case SYSTEM_IO_CAPABLE: + acpi_os_read_port((acpi_io_address)cmd->addr.io.port, + &cmd->val, + (u32)cmd->addr.io.bit_width); + break; + default: + break; + } +} + +/* Called via smp_call_function_many(), on the target CPUs */ +static void do_drv_write(void *_cmd) +{ + struct drv_cmd *cmd = _cmd; + u32 lo, hi; + + switch (cmd->type) { + case SYSTEM_INTEL_MSR_CAPABLE: + rdmsr(cmd->addr.msr.reg, lo, hi); + lo = (lo & ~INTEL_MSR_RANGE) | (cmd->val & INTEL_MSR_RANGE); + wrmsr(cmd->addr.msr.reg, lo, hi); + break; + case SYSTEM_IO_CAPABLE: + acpi_os_write_port((acpi_io_address)cmd->addr.io.port, + cmd->val, + (u32)cmd->addr.io.bit_width); + break; + default: + break; + } +} + +static void drv_read(struct drv_cmd *cmd) +{ + int err; + cmd->val = 0; + + err = smp_call_function_any(cmd->mask, do_drv_read, cmd, 1); + WARN_ON_ONCE(err); /* smp_call_function_any() was buggy? */ +} + +static void drv_write(struct drv_cmd *cmd) +{ + int this_cpu; + + this_cpu = get_cpu(); + if (cpumask_test_cpu(this_cpu, cmd->mask)) + do_drv_write(cmd); + smp_call_function_many(cmd->mask, do_drv_write, cmd, 1); + put_cpu(); +} + +static u32 get_cur_val(const struct cpumask *mask) +{ + struct acpi_processor_performance *perf; + struct drv_cmd cmd; + + if (unlikely(cpumask_empty(mask))) + return 0; + + switch (per_cpu(acfreq_data, cpumask_first(mask))->cpu_feature) { + case SYSTEM_INTEL_MSR_CAPABLE: + cmd.type = SYSTEM_INTEL_MSR_CAPABLE; + cmd.addr.msr.reg = MSR_IA32_PERF_STATUS; + break; + case SYSTEM_IO_CAPABLE: + cmd.type = SYSTEM_IO_CAPABLE; + perf = per_cpu(acfreq_data, cpumask_first(mask))->acpi_data; + cmd.addr.io.port = perf->control_register.address; + cmd.addr.io.bit_width = perf->control_register.bit_width; + break; + default: + return 0; + } + + cmd.mask = mask; + drv_read(&cmd); + + pr_debug("get_cur_val = %u\n", cmd.val); + + return cmd.val; +} + +static unsigned int get_cur_freq_on_cpu(unsigned int cpu) +{ + struct acpi_cpufreq_data *data = per_cpu(acfreq_data, cpu); + unsigned int freq; + unsigned int cached_freq; + + pr_debug("get_cur_freq_on_cpu (%d)\n", cpu); + + if (unlikely(data == NULL || + data->acpi_data == NULL || data->freq_table == NULL)) { + return 0; + } + + cached_freq = data->freq_table[data->acpi_data->state].frequency; + freq = extract_freq(get_cur_val(cpumask_of(cpu)), data); + if (freq != cached_freq) { + /* + * The dreaded BIOS frequency change behind our back. + * Force set the frequency on next target call. + */ + data->resume = 1; + } + + pr_debug("cur freq = %u\n", freq); + + return freq; +} + +static unsigned int check_freqs(const struct cpumask *mask, unsigned int freq, + struct acpi_cpufreq_data *data) +{ + unsigned int cur_freq; + unsigned int i; + + for (i = 0; i < 100; i++) { + cur_freq = extract_freq(get_cur_val(mask), data); + if (cur_freq == freq) + return 1; + udelay(10); + } + return 0; +} + +static int acpi_cpufreq_target(struct cpufreq_policy *policy, + unsigned int target_freq, unsigned int relation) +{ + struct acpi_cpufreq_data *data = per_cpu(acfreq_data, policy->cpu); + struct acpi_processor_performance *perf; + struct cpufreq_freqs freqs; + struct drv_cmd cmd; + unsigned int next_state = 0; /* Index into freq_table */ + unsigned int next_perf_state = 0; /* Index into perf table */ + unsigned int i; + int result = 0; + + pr_debug("acpi_cpufreq_target %d (%d)\n", target_freq, policy->cpu); + + if (unlikely(data == NULL || + data->acpi_data == NULL || data->freq_table == NULL)) { + return -ENODEV; + } + + perf = data->acpi_data; + result = cpufreq_frequency_table_target(policy, + data->freq_table, + target_freq, + relation, &next_state); + if (unlikely(result)) { + result = -ENODEV; + goto out; + } + + next_perf_state = data->freq_table[next_state].index; + if (perf->state == next_perf_state) { + if (unlikely(data->resume)) { + pr_debug("Called after resume, resetting to P%d\n", + next_perf_state); + data->resume = 0; + } else { + pr_debug("Already at target state (P%d)\n", + next_perf_state); + goto out; + } + } + + switch (data->cpu_feature) { + case SYSTEM_INTEL_MSR_CAPABLE: + cmd.type = SYSTEM_INTEL_MSR_CAPABLE; + cmd.addr.msr.reg = MSR_IA32_PERF_CTL; + cmd.val = (u32) perf->states[next_perf_state].control; + break; + case SYSTEM_IO_CAPABLE: + cmd.type = SYSTEM_IO_CAPABLE; + cmd.addr.io.port = perf->control_register.address; + cmd.addr.io.bit_width = perf->control_register.bit_width; + cmd.val = (u32) perf->states[next_perf_state].control; + break; + default: + result = -ENODEV; + goto out; + } + + /* cpufreq holds the hotplug lock, so we are safe from here on */ + if (policy->shared_type != CPUFREQ_SHARED_TYPE_ANY) + cmd.mask = policy->cpus; + else + cmd.mask = cpumask_of(policy->cpu); + + freqs.old = perf->states[perf->state].core_frequency * 1000; + freqs.new = data->freq_table[next_state].frequency; + for_each_cpu(i, policy->cpus) { + freqs.cpu = i; + cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE); + } + + drv_write(&cmd); + + if (acpi_pstate_strict) { + if (!check_freqs(cmd.mask, freqs.new, data)) { + pr_debug("acpi_cpufreq_target failed (%d)\n", + policy->cpu); + result = -EAGAIN; + goto out; + } + } + + for_each_cpu(i, policy->cpus) { + freqs.cpu = i; + cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE); + } + perf->state = next_perf_state; + +out: + return result; +} + +static int acpi_cpufreq_verify(struct cpufreq_policy *policy) +{ + struct acpi_cpufreq_data *data = per_cpu(acfreq_data, policy->cpu); + + pr_debug("acpi_cpufreq_verify\n"); + + return cpufreq_frequency_table_verify(policy, data->freq_table); +} + +static unsigned long +acpi_cpufreq_guess_freq(struct acpi_cpufreq_data *data, unsigned int cpu) +{ + struct acpi_processor_performance *perf = data->acpi_data; + + if (cpu_khz) { + /* search the closest match to cpu_khz */ + unsigned int i; + unsigned long freq; + unsigned long freqn = perf->states[0].core_frequency * 1000; + + for (i = 0; i < (perf->state_count-1); i++) { + freq = freqn; + freqn = perf->states[i+1].core_frequency * 1000; + if ((2 * cpu_khz) > (freqn + freq)) { + perf->state = i; + return freq; + } + } + perf->state = perf->state_count-1; + return freqn; + } else { + /* assume CPU is at P0... */ + perf->state = 0; + return perf->states[0].core_frequency * 1000; + } +} + +static void free_acpi_perf_data(void) +{ + unsigned int i; + + /* Freeing a NULL pointer is OK, and alloc_percpu zeroes. */ + for_each_possible_cpu(i) + free_cpumask_var(per_cpu_ptr(acpi_perf_data, i) + ->shared_cpu_map); + free_percpu(acpi_perf_data); +} + +/* + * acpi_cpufreq_early_init - initialize ACPI P-States library + * + * Initialize the ACPI P-States library (drivers/acpi/processor_perflib.c) + * in order to determine correct frequency and voltage pairings. We can + * do _PDC and _PSD and find out the processor dependency for the + * actual init that will happen later... + */ +static int __init acpi_cpufreq_early_init(void) +{ + unsigned int i; + pr_debug("acpi_cpufreq_early_init\n"); + + acpi_perf_data = alloc_percpu(struct acpi_processor_performance); + if (!acpi_perf_data) { + pr_debug("Memory allocation error for acpi_perf_data.\n"); + return -ENOMEM; + } + for_each_possible_cpu(i) { + if (!zalloc_cpumask_var_node( + &per_cpu_ptr(acpi_perf_data, i)->shared_cpu_map, + GFP_KERNEL, cpu_to_node(i))) { + + /* Freeing a NULL pointer is OK: alloc_percpu zeroes. */ + free_acpi_perf_data(); + return -ENOMEM; + } + } + + /* Do initialization in ACPI core */ + acpi_processor_preregister_performance(acpi_perf_data); + return 0; +} + +#ifdef CONFIG_SMP +/* + * Some BIOSes do SW_ANY coordination internally, either set it up in hw + * or do it in BIOS firmware and won't inform about it to OS. If not + * detected, this has a side effect of making CPU run at a different speed + * than OS intended it to run at. Detect it and handle it cleanly. + */ +static int bios_with_sw_any_bug; + +static int sw_any_bug_found(const struct dmi_system_id *d) +{ + bios_with_sw_any_bug = 1; + return 0; +} + +static const struct dmi_system_id sw_any_bug_dmi_table[] = { + { + .callback = sw_any_bug_found, + .ident = "Supermicro Server X6DLP", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Supermicro"), + DMI_MATCH(DMI_BIOS_VERSION, "080010"), + DMI_MATCH(DMI_PRODUCT_NAME, "X6DLP"), + }, + }, + { } +}; + +static int acpi_cpufreq_blacklist(struct cpuinfo_x86 *c) +{ + /* Intel Xeon Processor 7100 Series Specification Update + * http://www.intel.com/Assets/PDF/specupdate/314554.pdf + * AL30: A Machine Check Exception (MCE) Occurring during an + * Enhanced Intel SpeedStep Technology Ratio Change May Cause + * Both Processor Cores to Lock Up. */ + if (c->x86_vendor == X86_VENDOR_INTEL) { + if ((c->x86 == 15) && + (c->x86_model == 6) && + (c->x86_mask == 8)) { + printk(KERN_INFO "acpi-cpufreq: Intel(R) " + "Xeon(R) 7100 Errata AL30, processors may " + "lock up on frequency changes: disabling " + "acpi-cpufreq.\n"); + return -ENODEV; + } + } + return 0; +} +#endif + +static int acpi_cpufreq_cpu_init(struct cpufreq_policy *policy) +{ + unsigned int i; + unsigned int valid_states = 0; + unsigned int cpu = policy->cpu; + struct acpi_cpufreq_data *data; + unsigned int result = 0; + struct cpuinfo_x86 *c = &cpu_data(policy->cpu); + struct acpi_processor_performance *perf; +#ifdef CONFIG_SMP + static int blacklisted; +#endif + + pr_debug("acpi_cpufreq_cpu_init\n"); + +#ifdef CONFIG_SMP + if (blacklisted) + return blacklisted; + blacklisted = acpi_cpufreq_blacklist(c); + if (blacklisted) + return blacklisted; +#endif + + data = kzalloc(sizeof(struct acpi_cpufreq_data), GFP_KERNEL); + if (!data) + return -ENOMEM; + + data->acpi_data = per_cpu_ptr(acpi_perf_data, cpu); + per_cpu(acfreq_data, cpu) = data; + + if (cpu_has(c, X86_FEATURE_CONSTANT_TSC)) + acpi_cpufreq_driver.flags |= CPUFREQ_CONST_LOOPS; + + result = acpi_processor_register_performance(data->acpi_data, cpu); + if (result) + goto err_free; + + perf = data->acpi_data; + policy->shared_type = perf->shared_type; + + /* + * Will let policy->cpus know about dependency only when software + * coordination is required. + */ + if (policy->shared_type == CPUFREQ_SHARED_TYPE_ALL || + policy->shared_type == CPUFREQ_SHARED_TYPE_ANY) { + cpumask_copy(policy->cpus, perf->shared_cpu_map); + } + cpumask_copy(policy->related_cpus, perf->shared_cpu_map); + +#ifdef CONFIG_SMP + dmi_check_system(sw_any_bug_dmi_table); + if (bios_with_sw_any_bug && cpumask_weight(policy->cpus) == 1) { + policy->shared_type = CPUFREQ_SHARED_TYPE_ALL; + cpumask_copy(policy->cpus, cpu_core_mask(cpu)); + } +#endif + + /* capability check */ + if (perf->state_count <= 1) { + pr_debug("No P-States\n"); + result = -ENODEV; + goto err_unreg; + } + + if (perf->control_register.space_id != perf->status_register.space_id) { + result = -ENODEV; + goto err_unreg; + } + + switch (perf->control_register.space_id) { + case ACPI_ADR_SPACE_SYSTEM_IO: + pr_debug("SYSTEM IO addr space\n"); + data->cpu_feature = SYSTEM_IO_CAPABLE; + break; + case ACPI_ADR_SPACE_FIXED_HARDWARE: + pr_debug("HARDWARE addr space\n"); + if (!check_est_cpu(cpu)) { + result = -ENODEV; + goto err_unreg; + } + data->cpu_feature = SYSTEM_INTEL_MSR_CAPABLE; + break; + default: + pr_debug("Unknown addr space %d\n", + (u32) (perf->control_register.space_id)); + result = -ENODEV; + goto err_unreg; + } + + data->freq_table = kmalloc(sizeof(struct cpufreq_frequency_table) * + (perf->state_count+1), GFP_KERNEL); + if (!data->freq_table) { + result = -ENOMEM; + goto err_unreg; + } + + /* detect transition latency */ + policy->cpuinfo.transition_latency = 0; + for (i = 0; i < perf->state_count; i++) { + if ((perf->states[i].transition_latency * 1000) > + policy->cpuinfo.transition_latency) + policy->cpuinfo.transition_latency = + perf->states[i].transition_latency * 1000; + } + + /* Check for high latency (>20uS) from buggy BIOSes, like on T42 */ + if (perf->control_register.space_id == ACPI_ADR_SPACE_FIXED_HARDWARE && + policy->cpuinfo.transition_latency > 20 * 1000) { + policy->cpuinfo.transition_latency = 20 * 1000; + printk_once(KERN_INFO + "P-state transition latency capped at 20 uS\n"); + } + + /* table init */ + for (i = 0; i < perf->state_count; i++) { + if (i > 0 && perf->states[i].core_frequency >= + data->freq_table[valid_states-1].frequency / 1000) + continue; + + data->freq_table[valid_states].index = i; + data->freq_table[valid_states].frequency = + perf->states[i].core_frequency * 1000; + valid_states++; + } + data->freq_table[valid_states].frequency = CPUFREQ_TABLE_END; + perf->state = 0; + + result = cpufreq_frequency_table_cpuinfo(policy, data->freq_table); + if (result) + goto err_freqfree; + + if (perf->states[0].core_frequency * 1000 != policy->cpuinfo.max_freq) + printk(KERN_WARNING FW_WARN "P-state 0 is not max freq\n"); + + switch (perf->control_register.space_id) { + case ACPI_ADR_SPACE_SYSTEM_IO: + /* Current speed is unknown and not detectable by IO port */ + policy->cur = acpi_cpufreq_guess_freq(data, policy->cpu); + break; + case ACPI_ADR_SPACE_FIXED_HARDWARE: + acpi_cpufreq_driver.get = get_cur_freq_on_cpu; + policy->cur = get_cur_freq_on_cpu(cpu); + break; + default: + break; + } + + /* notify BIOS that we exist */ + acpi_processor_notify_smm(THIS_MODULE); + + /* Check for APERF/MPERF support in hardware */ + if (cpu_has(c, X86_FEATURE_APERFMPERF)) + acpi_cpufreq_driver.getavg = cpufreq_get_measured_perf; + + pr_debug("CPU%u - ACPI performance management activated.\n", cpu); + for (i = 0; i < perf->state_count; i++) + pr_debug(" %cP%d: %d MHz, %d mW, %d uS\n", + (i == perf->state ? '*' : ' '), i, + (u32) perf->states[i].core_frequency, + (u32) perf->states[i].power, + (u32) perf->states[i].transition_latency); + + cpufreq_frequency_table_get_attr(data->freq_table, policy->cpu); + + /* + * the first call to ->target() should result in us actually + * writing something to the appropriate registers. + */ + data->resume = 1; + + return result; + +err_freqfree: + kfree(data->freq_table); +err_unreg: + acpi_processor_unregister_performance(perf, cpu); +err_free: + kfree(data); + per_cpu(acfreq_data, cpu) = NULL; + + return result; +} + +static int acpi_cpufreq_cpu_exit(struct cpufreq_policy *policy) +{ + struct acpi_cpufreq_data *data = per_cpu(acfreq_data, policy->cpu); + + pr_debug("acpi_cpufreq_cpu_exit\n"); + + if (data) { + cpufreq_frequency_table_put_attr(policy->cpu); + per_cpu(acfreq_data, policy->cpu) = NULL; + acpi_processor_unregister_performance(data->acpi_data, + policy->cpu); + kfree(data->freq_table); + kfree(data); + } + + return 0; +} + +static int acpi_cpufreq_resume(struct cpufreq_policy *policy) +{ + struct acpi_cpufreq_data *data = per_cpu(acfreq_data, policy->cpu); + + pr_debug("acpi_cpufreq_resume\n"); + + data->resume = 1; + + return 0; +} + +static struct freq_attr *acpi_cpufreq_attr[] = { + &cpufreq_freq_attr_scaling_available_freqs, + NULL, +}; + +static struct cpufreq_driver acpi_cpufreq_driver = { + .verify = acpi_cpufreq_verify, + .target = acpi_cpufreq_target, + .bios_limit = acpi_processor_get_bios_limit, + .init = acpi_cpufreq_cpu_init, + .exit = acpi_cpufreq_cpu_exit, + .resume = acpi_cpufreq_resume, + .name = "acpi-cpufreq", + .owner = THIS_MODULE, + .attr = acpi_cpufreq_attr, +}; + +static int __init acpi_cpufreq_init(void) +{ + int ret; + + if (acpi_disabled) + return 0; + + pr_debug("acpi_cpufreq_init\n"); + + ret = acpi_cpufreq_early_init(); + if (ret) + return ret; + + ret = cpufreq_register_driver(&acpi_cpufreq_driver); + if (ret) + free_acpi_perf_data(); + + return ret; +} + +static void __exit acpi_cpufreq_exit(void) +{ + pr_debug("acpi_cpufreq_exit\n"); + + cpufreq_unregister_driver(&acpi_cpufreq_driver); + + free_percpu(acpi_perf_data); +} + +module_param(acpi_pstate_strict, uint, 0644); +MODULE_PARM_DESC(acpi_pstate_strict, + "value 0 or non-zero. non-zero -> strict ACPI checks are " + "performed during frequency changes."); + +late_initcall(acpi_cpufreq_init); +module_exit(acpi_cpufreq_exit); + +MODULE_ALIAS("acpi"); diff --git a/drivers/cpufreq/cpufreq-nforce2.c b/drivers/cpufreq/cpufreq-nforce2.c new file mode 100644 index 0000000..7bac808 --- /dev/null +++ b/drivers/cpufreq/cpufreq-nforce2.c @@ -0,0 +1,444 @@ +/* + * (C) 2004-2006 Sebastian Witt + * + * Licensed under the terms of the GNU GPL License version 2. + * Based upon reverse engineered information + * + * BIG FAT DISCLAIMER: Work in progress code. Possibly *dangerous* + */ + +#include +#include +#include +#include +#include +#include +#include + +#define NFORCE2_XTAL 25 +#define NFORCE2_BOOTFSB 0x48 +#define NFORCE2_PLLENABLE 0xa8 +#define NFORCE2_PLLREG 0xa4 +#define NFORCE2_PLLADR 0xa0 +#define NFORCE2_PLL(mul, div) (0x100000 | (mul << 8) | div) + +#define NFORCE2_MIN_FSB 50 +#define NFORCE2_SAFE_DISTANCE 50 + +/* Delay in ms between FSB changes */ +/* #define NFORCE2_DELAY 10 */ + +/* + * nforce2_chipset: + * FSB is changed using the chipset + */ +static struct pci_dev *nforce2_dev; + +/* fid: + * multiplier * 10 + */ +static int fid; + +/* min_fsb, max_fsb: + * minimum and maximum FSB (= FSB at boot time) + */ +static int min_fsb; +static int max_fsb; + +MODULE_AUTHOR("Sebastian Witt "); +MODULE_DESCRIPTION("nForce2 FSB changing cpufreq driver"); +MODULE_LICENSE("GPL"); + +module_param(fid, int, 0444); +module_param(min_fsb, int, 0444); + +MODULE_PARM_DESC(fid, "CPU multiplier to use (11.5 = 115)"); +MODULE_PARM_DESC(min_fsb, + "Minimum FSB to use, if not defined: current FSB - 50"); + +#define PFX "cpufreq-nforce2: " + +/** + * nforce2_calc_fsb - calculate FSB + * @pll: PLL value + * + * Calculates FSB from PLL value + */ +static int nforce2_calc_fsb(int pll) +{ + unsigned char mul, div; + + mul = (pll >> 8) & 0xff; + div = pll & 0xff; + + if (div > 0) + return NFORCE2_XTAL * mul / div; + + return 0; +} + +/** + * nforce2_calc_pll - calculate PLL value + * @fsb: FSB + * + * Calculate PLL value for given FSB + */ +static int nforce2_calc_pll(unsigned int fsb) +{ + unsigned char xmul, xdiv; + unsigned char mul = 0, div = 0; + int tried = 0; + + /* Try to calculate multiplier and divider up to 4 times */ + while (((mul == 0) || (div == 0)) && (tried <= 3)) { + for (xdiv = 2; xdiv <= 0x80; xdiv++) + for (xmul = 1; xmul <= 0xfe; xmul++) + if (nforce2_calc_fsb(NFORCE2_PLL(xmul, xdiv)) == + fsb + tried) { + mul = xmul; + div = xdiv; + } + tried++; + } + + if ((mul == 0) || (div == 0)) + return -1; + + return NFORCE2_PLL(mul, div); +} + +/** + * nforce2_write_pll - write PLL value to chipset + * @pll: PLL value + * + * Writes new FSB PLL value to chipset + */ +static void nforce2_write_pll(int pll) +{ + int temp; + + /* Set the pll addr. to 0x00 */ + pci_write_config_dword(nforce2_dev, NFORCE2_PLLADR, 0); + + /* Now write the value in all 64 registers */ + for (temp = 0; temp <= 0x3f; temp++) + pci_write_config_dword(nforce2_dev, NFORCE2_PLLREG, pll); + + return; +} + +/** + * nforce2_fsb_read - Read FSB + * + * Read FSB from chipset + * If bootfsb != 0, return FSB at boot-time + */ +static unsigned int nforce2_fsb_read(int bootfsb) +{ + struct pci_dev *nforce2_sub5; + u32 fsb, temp = 0; + + /* Get chipset boot FSB from subdevice 5 (FSB at boot-time) */ + nforce2_sub5 = pci_get_subsys(PCI_VENDOR_ID_NVIDIA, 0x01EF, + PCI_ANY_ID, PCI_ANY_ID, NULL); + if (!nforce2_sub5) + return 0; + + pci_read_config_dword(nforce2_sub5, NFORCE2_BOOTFSB, &fsb); + fsb /= 1000000; + + /* Check if PLL register is already set */ + pci_read_config_byte(nforce2_dev, NFORCE2_PLLENABLE, (u8 *)&temp); + + if (bootfsb || !temp) + return fsb; + + /* Use PLL register FSB value */ + pci_read_config_dword(nforce2_dev, NFORCE2_PLLREG, &temp); + fsb = nforce2_calc_fsb(temp); + + return fsb; +} + +/** + * nforce2_set_fsb - set new FSB + * @fsb: New FSB + * + * Sets new FSB + */ +static int nforce2_set_fsb(unsigned int fsb) +{ + u32 temp = 0; + unsigned int tfsb; + int diff; + int pll = 0; + + if ((fsb > max_fsb) || (fsb < NFORCE2_MIN_FSB)) { + printk(KERN_ERR PFX "FSB %d is out of range!\n", fsb); + return -EINVAL; + } + + tfsb = nforce2_fsb_read(0); + if (!tfsb) { + printk(KERN_ERR PFX "Error while reading the FSB\n"); + return -EINVAL; + } + + /* First write? Then set actual value */ + pci_read_config_byte(nforce2_dev, NFORCE2_PLLENABLE, (u8 *)&temp); + if (!temp) { + pll = nforce2_calc_pll(tfsb); + + if (pll < 0) + return -EINVAL; + + nforce2_write_pll(pll); + } + + /* Enable write access */ + temp = 0x01; + pci_write_config_byte(nforce2_dev, NFORCE2_PLLENABLE, (u8)temp); + + diff = tfsb - fsb; + + if (!diff) + return 0; + + while ((tfsb != fsb) && (tfsb <= max_fsb) && (tfsb >= min_fsb)) { + if (diff < 0) + tfsb++; + else + tfsb--; + + /* Calculate the PLL reg. value */ + pll = nforce2_calc_pll(tfsb); + if (pll == -1) + return -EINVAL; + + nforce2_write_pll(pll); +#ifdef NFORCE2_DELAY + mdelay(NFORCE2_DELAY); +#endif + } + + temp = 0x40; + pci_write_config_byte(nforce2_dev, NFORCE2_PLLADR, (u8)temp); + + return 0; +} + +/** + * nforce2_get - get the CPU frequency + * @cpu: CPU number + * + * Returns the CPU frequency + */ +static unsigned int nforce2_get(unsigned int cpu) +{ + if (cpu) + return 0; + return nforce2_fsb_read(0) * fid * 100; +} + +/** + * nforce2_target - set a new CPUFreq policy + * @policy: new policy + * @target_freq: the target frequency + * @relation: how that frequency relates to achieved frequency + * (CPUFREQ_RELATION_L or CPUFREQ_RELATION_H) + * + * Sets a new CPUFreq policy. + */ +static int nforce2_target(struct cpufreq_policy *policy, + unsigned int target_freq, unsigned int relation) +{ +/* unsigned long flags; */ + struct cpufreq_freqs freqs; + unsigned int target_fsb; + + if ((target_freq > policy->max) || (target_freq < policy->min)) + return -EINVAL; + + target_fsb = target_freq / (fid * 100); + + freqs.old = nforce2_get(policy->cpu); + freqs.new = target_fsb * fid * 100; + freqs.cpu = 0; /* Only one CPU on nForce2 platforms */ + + if (freqs.old == freqs.new) + return 0; + + pr_debug("Old CPU frequency %d kHz, new %d kHz\n", + freqs.old, freqs.new); + + cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE); + + /* Disable IRQs */ + /* local_irq_save(flags); */ + + if (nforce2_set_fsb(target_fsb) < 0) + printk(KERN_ERR PFX "Changing FSB to %d failed\n", + target_fsb); + else + pr_debug("Changed FSB successfully to %d\n", + target_fsb); + + /* Enable IRQs */ + /* local_irq_restore(flags); */ + + cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE); + + return 0; +} + +/** + * nforce2_verify - verifies a new CPUFreq policy + * @policy: new policy + */ +static int nforce2_verify(struct cpufreq_policy *policy) +{ + unsigned int fsb_pol_max; + + fsb_pol_max = policy->max / (fid * 100); + + if (policy->min < (fsb_pol_max * fid * 100)) + policy->max = (fsb_pol_max + 1) * fid * 100; + + cpufreq_verify_within_limits(policy, + policy->cpuinfo.min_freq, + policy->cpuinfo.max_freq); + return 0; +} + +static int nforce2_cpu_init(struct cpufreq_policy *policy) +{ + unsigned int fsb; + unsigned int rfid; + + /* capability check */ + if (policy->cpu != 0) + return -ENODEV; + + /* Get current FSB */ + fsb = nforce2_fsb_read(0); + + if (!fsb) + return -EIO; + + /* FIX: Get FID from CPU */ + if (!fid) { + if (!cpu_khz) { + printk(KERN_WARNING PFX + "cpu_khz not set, can't calculate multiplier!\n"); + return -ENODEV; + } + + fid = cpu_khz / (fsb * 100); + rfid = fid % 5; + + if (rfid) { + if (rfid > 2) + fid += 5 - rfid; + else + fid -= rfid; + } + } + + printk(KERN_INFO PFX "FSB currently at %i MHz, FID %d.%d\n", fsb, + fid / 10, fid % 10); + + /* Set maximum FSB to FSB at boot time */ + max_fsb = nforce2_fsb_read(1); + + if (!max_fsb) + return -EIO; + + if (!min_fsb) + min_fsb = max_fsb - NFORCE2_SAFE_DISTANCE; + + if (min_fsb < NFORCE2_MIN_FSB) + min_fsb = NFORCE2_MIN_FSB; + + /* cpuinfo and default policy values */ + policy->cpuinfo.min_freq = min_fsb * fid * 100; + policy->cpuinfo.max_freq = max_fsb * fid * 100; + policy->cpuinfo.transition_latency = CPUFREQ_ETERNAL; + policy->cur = nforce2_get(policy->cpu); + policy->min = policy->cpuinfo.min_freq; + policy->max = policy->cpuinfo.max_freq; + + return 0; +} + +static int nforce2_cpu_exit(struct cpufreq_policy *policy) +{ + return 0; +} + +static struct cpufreq_driver nforce2_driver = { + .name = "nforce2", + .verify = nforce2_verify, + .target = nforce2_target, + .get = nforce2_get, + .init = nforce2_cpu_init, + .exit = nforce2_cpu_exit, + .owner = THIS_MODULE, +}; + +/** + * nforce2_detect_chipset - detect the Southbridge which contains FSB PLL logic + * + * Detects nForce2 A2 and C1 stepping + * + */ +static int nforce2_detect_chipset(void) +{ + nforce2_dev = pci_get_subsys(PCI_VENDOR_ID_NVIDIA, + PCI_DEVICE_ID_NVIDIA_NFORCE2, + PCI_ANY_ID, PCI_ANY_ID, NULL); + + if (nforce2_dev == NULL) + return -ENODEV; + + printk(KERN_INFO PFX "Detected nForce2 chipset revision %X\n", + nforce2_dev->revision); + printk(KERN_INFO PFX + "FSB changing is maybe unstable and can lead to " + "crashes and data loss.\n"); + + return 0; +} + +/** + * nforce2_init - initializes the nForce2 CPUFreq driver + * + * Initializes the nForce2 FSB support. Returns -ENODEV on unsupported + * devices, -EINVAL on problems during initiatization, and zero on + * success. + */ +static int __init nforce2_init(void) +{ + /* TODO: do we need to detect the processor? */ + + /* detect chipset */ + if (nforce2_detect_chipset()) { + printk(KERN_INFO PFX "No nForce2 chipset.\n"); + return -ENODEV; + } + + return cpufreq_register_driver(&nforce2_driver); +} + +/** + * nforce2_exit - unregisters cpufreq module + * + * Unregisters nForce2 FSB change support. + */ +static void __exit nforce2_exit(void) +{ + cpufreq_unregister_driver(&nforce2_driver); +} + +module_init(nforce2_init); +module_exit(nforce2_exit); + diff --git a/drivers/cpufreq/e_powersaver.c b/drivers/cpufreq/e_powersaver.c new file mode 100644 index 0000000..35a257d --- /dev/null +++ b/drivers/cpufreq/e_powersaver.c @@ -0,0 +1,367 @@ +/* + * Based on documentation provided by Dave Jones. Thanks! + * + * Licensed under the terms of the GNU GPL License version 2. + * + * BIG FAT DISCLAIMER: Work in progress code. Possibly *dangerous* + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#define EPS_BRAND_C7M 0 +#define EPS_BRAND_C7 1 +#define EPS_BRAND_EDEN 2 +#define EPS_BRAND_C3 3 +#define EPS_BRAND_C7D 4 + +struct eps_cpu_data { + u32 fsb; + struct cpufreq_frequency_table freq_table[]; +}; + +static struct eps_cpu_data *eps_cpu[NR_CPUS]; + + +static unsigned int eps_get(unsigned int cpu) +{ + struct eps_cpu_data *centaur; + u32 lo, hi; + + if (cpu) + return 0; + centaur = eps_cpu[cpu]; + if (centaur == NULL) + return 0; + + /* Return current frequency */ + rdmsr(MSR_IA32_PERF_STATUS, lo, hi); + return centaur->fsb * ((lo >> 8) & 0xff); +} + +static int eps_set_state(struct eps_cpu_data *centaur, + unsigned int cpu, + u32 dest_state) +{ + struct cpufreq_freqs freqs; + u32 lo, hi; + int err = 0; + int i; + + freqs.old = eps_get(cpu); + freqs.new = centaur->fsb * ((dest_state >> 8) & 0xff); + freqs.cpu = cpu; + cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE); + + /* Wait while CPU is busy */ + rdmsr(MSR_IA32_PERF_STATUS, lo, hi); + i = 0; + while (lo & ((1 << 16) | (1 << 17))) { + udelay(16); + rdmsr(MSR_IA32_PERF_STATUS, lo, hi); + i++; + if (unlikely(i > 64)) { + err = -ENODEV; + goto postchange; + } + } + /* Set new multiplier and voltage */ + wrmsr(MSR_IA32_PERF_CTL, dest_state & 0xffff, 0); + /* Wait until transition end */ + i = 0; + do { + udelay(16); + rdmsr(MSR_IA32_PERF_STATUS, lo, hi); + i++; + if (unlikely(i > 64)) { + err = -ENODEV; + goto postchange; + } + } while (lo & ((1 << 16) | (1 << 17))); + + /* Return current frequency */ +postchange: + rdmsr(MSR_IA32_PERF_STATUS, lo, hi); + freqs.new = centaur->fsb * ((lo >> 8) & 0xff); + +#ifdef DEBUG + { + u8 current_multiplier, current_voltage; + + /* Print voltage and multiplier */ + rdmsr(MSR_IA32_PERF_STATUS, lo, hi); + current_voltage = lo & 0xff; + printk(KERN_INFO "eps: Current voltage = %dmV\n", + current_voltage * 16 + 700); + current_multiplier = (lo >> 8) & 0xff; + printk(KERN_INFO "eps: Current multiplier = %d\n", + current_multiplier); + } +#endif + cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE); + return err; +} + +static int eps_target(struct cpufreq_policy *policy, + unsigned int target_freq, + unsigned int relation) +{ + struct eps_cpu_data *centaur; + unsigned int newstate = 0; + unsigned int cpu = policy->cpu; + unsigned int dest_state; + int ret; + + if (unlikely(eps_cpu[cpu] == NULL)) + return -ENODEV; + centaur = eps_cpu[cpu]; + + if (unlikely(cpufreq_frequency_table_target(policy, + &eps_cpu[cpu]->freq_table[0], + target_freq, + relation, + &newstate))) { + return -EINVAL; + } + + /* Make frequency transition */ + dest_state = centaur->freq_table[newstate].index & 0xffff; + ret = eps_set_state(centaur, cpu, dest_state); + if (ret) + printk(KERN_ERR "eps: Timeout!\n"); + return ret; +} + +static int eps_verify(struct cpufreq_policy *policy) +{ + return cpufreq_frequency_table_verify(policy, + &eps_cpu[policy->cpu]->freq_table[0]); +} + +static int eps_cpu_init(struct cpufreq_policy *policy) +{ + unsigned int i; + u32 lo, hi; + u64 val; + u8 current_multiplier, current_voltage; + u8 max_multiplier, max_voltage; + u8 min_multiplier, min_voltage; + u8 brand = 0; + u32 fsb; + struct eps_cpu_data *centaur; + struct cpuinfo_x86 *c = &cpu_data(0); + struct cpufreq_frequency_table *f_table; + int k, step, voltage; + int ret; + int states; + + if (policy->cpu != 0) + return -ENODEV; + + /* Check brand */ + printk(KERN_INFO "eps: Detected VIA "); + + switch (c->x86_model) { + case 10: + rdmsr(0x1153, lo, hi); + brand = (((lo >> 2) ^ lo) >> 18) & 3; + printk(KERN_CONT "Model A "); + break; + case 13: + rdmsr(0x1154, lo, hi); + brand = (((lo >> 4) ^ (lo >> 2))) & 0x000000ff; + printk(KERN_CONT "Model D "); + break; + } + + switch (brand) { + case EPS_BRAND_C7M: + printk(KERN_CONT "C7-M\n"); + break; + case EPS_BRAND_C7: + printk(KERN_CONT "C7\n"); + break; + case EPS_BRAND_EDEN: + printk(KERN_CONT "Eden\n"); + break; + case EPS_BRAND_C7D: + printk(KERN_CONT "C7-D\n"); + break; + case EPS_BRAND_C3: + printk(KERN_CONT "C3\n"); + return -ENODEV; + break; + } + /* Enable Enhanced PowerSaver */ + rdmsrl(MSR_IA32_MISC_ENABLE, val); + if (!(val & MSR_IA32_MISC_ENABLE_ENHANCED_SPEEDSTEP)) { + val |= MSR_IA32_MISC_ENABLE_ENHANCED_SPEEDSTEP; + wrmsrl(MSR_IA32_MISC_ENABLE, val); + /* Can be locked at 0 */ + rdmsrl(MSR_IA32_MISC_ENABLE, val); + if (!(val & MSR_IA32_MISC_ENABLE_ENHANCED_SPEEDSTEP)) { + printk(KERN_INFO "eps: Can't enable Enhanced PowerSaver\n"); + return -ENODEV; + } + } + + /* Print voltage and multiplier */ + rdmsr(MSR_IA32_PERF_STATUS, lo, hi); + current_voltage = lo & 0xff; + printk(KERN_INFO "eps: Current voltage = %dmV\n", + current_voltage * 16 + 700); + current_multiplier = (lo >> 8) & 0xff; + printk(KERN_INFO "eps: Current multiplier = %d\n", current_multiplier); + + /* Print limits */ + max_voltage = hi & 0xff; + printk(KERN_INFO "eps: Highest voltage = %dmV\n", + max_voltage * 16 + 700); + max_multiplier = (hi >> 8) & 0xff; + printk(KERN_INFO "eps: Highest multiplier = %d\n", max_multiplier); + min_voltage = (hi >> 16) & 0xff; + printk(KERN_INFO "eps: Lowest voltage = %dmV\n", + min_voltage * 16 + 700); + min_multiplier = (hi >> 24) & 0xff; + printk(KERN_INFO "eps: Lowest multiplier = %d\n", min_multiplier); + + /* Sanity checks */ + if (current_multiplier == 0 || max_multiplier == 0 + || min_multiplier == 0) + return -EINVAL; + if (current_multiplier > max_multiplier + || max_multiplier <= min_multiplier) + return -EINVAL; + if (current_voltage > 0x1f || max_voltage > 0x1f) + return -EINVAL; + if (max_voltage < min_voltage) + return -EINVAL; + + /* Calc FSB speed */ + fsb = cpu_khz / current_multiplier; + /* Calc number of p-states supported */ + if (brand == EPS_BRAND_C7M) + states = max_multiplier - min_multiplier + 1; + else + states = 2; + + /* Allocate private data and frequency table for current cpu */ + centaur = kzalloc(sizeof(struct eps_cpu_data) + + (states + 1) * sizeof(struct cpufreq_frequency_table), + GFP_KERNEL); + if (!centaur) + return -ENOMEM; + eps_cpu[0] = centaur; + + /* Copy basic values */ + centaur->fsb = fsb; + + /* Fill frequency and MSR value table */ + f_table = ¢aur->freq_table[0]; + if (brand != EPS_BRAND_C7M) { + f_table[0].frequency = fsb * min_multiplier; + f_table[0].index = (min_multiplier << 8) | min_voltage; + f_table[1].frequency = fsb * max_multiplier; + f_table[1].index = (max_multiplier << 8) | max_voltage; + f_table[2].frequency = CPUFREQ_TABLE_END; + } else { + k = 0; + step = ((max_voltage - min_voltage) * 256) + / (max_multiplier - min_multiplier); + for (i = min_multiplier; i <= max_multiplier; i++) { + voltage = (k * step) / 256 + min_voltage; + f_table[k].frequency = fsb * i; + f_table[k].index = (i << 8) | voltage; + k++; + } + f_table[k].frequency = CPUFREQ_TABLE_END; + } + + policy->cpuinfo.transition_latency = 140000; /* 844mV -> 700mV in ns */ + policy->cur = fsb * current_multiplier; + + ret = cpufreq_frequency_table_cpuinfo(policy, ¢aur->freq_table[0]); + if (ret) { + kfree(centaur); + return ret; + } + + cpufreq_frequency_table_get_attr(¢aur->freq_table[0], policy->cpu); + return 0; +} + +static int eps_cpu_exit(struct cpufreq_policy *policy) +{ + unsigned int cpu = policy->cpu; + struct eps_cpu_data *centaur; + u32 lo, hi; + + if (eps_cpu[cpu] == NULL) + return -ENODEV; + centaur = eps_cpu[cpu]; + + /* Get max frequency */ + rdmsr(MSR_IA32_PERF_STATUS, lo, hi); + /* Set max frequency */ + eps_set_state(centaur, cpu, hi & 0xffff); + /* Bye */ + cpufreq_frequency_table_put_attr(policy->cpu); + kfree(eps_cpu[cpu]); + eps_cpu[cpu] = NULL; + return 0; +} + +static struct freq_attr *eps_attr[] = { + &cpufreq_freq_attr_scaling_available_freqs, + NULL, +}; + +static struct cpufreq_driver eps_driver = { + .verify = eps_verify, + .target = eps_target, + .init = eps_cpu_init, + .exit = eps_cpu_exit, + .get = eps_get, + .name = "e_powersaver", + .owner = THIS_MODULE, + .attr = eps_attr, +}; + +static int __init eps_init(void) +{ + struct cpuinfo_x86 *c = &cpu_data(0); + + /* This driver will work only on Centaur C7 processors with + * Enhanced SpeedStep/PowerSaver registers */ + if (c->x86_vendor != X86_VENDOR_CENTAUR + || c->x86 != 6 || c->x86_model < 10) + return -ENODEV; + if (!cpu_has(c, X86_FEATURE_EST)) + return -ENODEV; + + if (cpufreq_register_driver(&eps_driver)) + return -EINVAL; + return 0; +} + +static void __exit eps_exit(void) +{ + cpufreq_unregister_driver(&eps_driver); +} + +MODULE_AUTHOR("Rafal Bilski "); +MODULE_DESCRIPTION("Enhanced PowerSaver driver for VIA C7 CPU's."); +MODULE_LICENSE("GPL"); + +module_init(eps_init); +module_exit(eps_exit); diff --git a/drivers/cpufreq/elanfreq.c b/drivers/cpufreq/elanfreq.c new file mode 100644 index 0000000..c587db4 --- /dev/null +++ b/drivers/cpufreq/elanfreq.c @@ -0,0 +1,309 @@ +/* + * elanfreq: cpufreq driver for the AMD ELAN family + * + * (c) Copyright 2002 Robert Schwebel + * + * Parts of this code are (c) Sven Geggus + * + * All Rights Reserved. + * + * 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. + * + * 2002-02-13: - initial revision for 2.4.18-pre9 by Robert Schwebel + * + */ + +#include +#include +#include + +#include +#include + +#include +#include +#include + +#define REG_CSCIR 0x22 /* Chip Setup and Control Index Register */ +#define REG_CSCDR 0x23 /* Chip Setup and Control Data Register */ + +/* Module parameter */ +static int max_freq; + +struct s_elan_multiplier { + int clock; /* frequency in kHz */ + int val40h; /* PMU Force Mode register */ + int val80h; /* CPU Clock Speed Register */ +}; + +/* + * It is important that the frequencies + * are listed in ascending order here! + */ +static struct s_elan_multiplier elan_multiplier[] = { + {1000, 0x02, 0x18}, + {2000, 0x02, 0x10}, + {4000, 0x02, 0x08}, + {8000, 0x00, 0x00}, + {16000, 0x00, 0x02}, + {33000, 0x00, 0x04}, + {66000, 0x01, 0x04}, + {99000, 0x01, 0x05} +}; + +static struct cpufreq_frequency_table elanfreq_table[] = { + {0, 1000}, + {1, 2000}, + {2, 4000}, + {3, 8000}, + {4, 16000}, + {5, 33000}, + {6, 66000}, + {7, 99000}, + {0, CPUFREQ_TABLE_END}, +}; + + +/** + * elanfreq_get_cpu_frequency: determine current cpu speed + * + * Finds out at which frequency the CPU of the Elan SOC runs + * at the moment. Frequencies from 1 to 33 MHz are generated + * the normal way, 66 and 99 MHz are called "Hyperspeed Mode" + * and have the rest of the chip running with 33 MHz. + */ + +static unsigned int elanfreq_get_cpu_frequency(unsigned int cpu) +{ + u8 clockspeed_reg; /* Clock Speed Register */ + + local_irq_disable(); + outb_p(0x80, REG_CSCIR); + clockspeed_reg = inb_p(REG_CSCDR); + local_irq_enable(); + + if ((clockspeed_reg & 0xE0) == 0xE0) + return 0; + + /* Are we in CPU clock multiplied mode (66/99 MHz)? */ + if ((clockspeed_reg & 0xE0) == 0xC0) { + if ((clockspeed_reg & 0x01) == 0) + return 66000; + else + return 99000; + } + + /* 33 MHz is not 32 MHz... */ + if ((clockspeed_reg & 0xE0) == 0xA0) + return 33000; + + return (1<<((clockspeed_reg & 0xE0) >> 5)) * 1000; +} + + +/** + * elanfreq_set_cpu_frequency: Change the CPU core frequency + * @cpu: cpu number + * @freq: frequency in kHz + * + * This function takes a frequency value and changes the CPU frequency + * according to this. Note that the frequency has to be checked by + * elanfreq_validatespeed() for correctness! + * + * There is no return value. + */ + +static void elanfreq_set_cpu_state(unsigned int state) +{ + struct cpufreq_freqs freqs; + + freqs.old = elanfreq_get_cpu_frequency(0); + freqs.new = elan_multiplier[state].clock; + freqs.cpu = 0; /* elanfreq.c is UP only driver */ + + cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE); + + printk(KERN_INFO "elanfreq: attempting to set frequency to %i kHz\n", + elan_multiplier[state].clock); + + + /* + * Access to the Elan's internal registers is indexed via + * 0x22: Chip Setup & Control Register Index Register (CSCI) + * 0x23: Chip Setup & Control Register Data Register (CSCD) + * + */ + + /* + * 0x40 is the Power Management Unit's Force Mode Register. + * Bit 6 enables Hyperspeed Mode (66/100 MHz core frequency) + */ + + local_irq_disable(); + outb_p(0x40, REG_CSCIR); /* Disable hyperspeed mode */ + outb_p(0x00, REG_CSCDR); + local_irq_enable(); /* wait till internal pipelines and */ + udelay(1000); /* buffers have cleaned up */ + + local_irq_disable(); + + /* now, set the CPU clock speed register (0x80) */ + outb_p(0x80, REG_CSCIR); + outb_p(elan_multiplier[state].val80h, REG_CSCDR); + + /* now, the hyperspeed bit in PMU Force Mode Register (0x40) */ + outb_p(0x40, REG_CSCIR); + outb_p(elan_multiplier[state].val40h, REG_CSCDR); + udelay(10000); + local_irq_enable(); + + cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE); +}; + + +/** + * elanfreq_validatespeed: test if frequency range is valid + * @policy: the policy to validate + * + * This function checks if a given frequency range in kHz is valid + * for the hardware supported by the driver. + */ + +static int elanfreq_verify(struct cpufreq_policy *policy) +{ + return cpufreq_frequency_table_verify(policy, &elanfreq_table[0]); +} + +static int elanfreq_target(struct cpufreq_policy *policy, + unsigned int target_freq, + unsigned int relation) +{ + unsigned int newstate = 0; + + if (cpufreq_frequency_table_target(policy, &elanfreq_table[0], + target_freq, relation, &newstate)) + return -EINVAL; + + elanfreq_set_cpu_state(newstate); + + return 0; +} + + +/* + * Module init and exit code + */ + +static int elanfreq_cpu_init(struct cpufreq_policy *policy) +{ + struct cpuinfo_x86 *c = &cpu_data(0); + unsigned int i; + int result; + + /* capability check */ + if ((c->x86_vendor != X86_VENDOR_AMD) || + (c->x86 != 4) || (c->x86_model != 10)) + return -ENODEV; + + /* max freq */ + if (!max_freq) + max_freq = elanfreq_get_cpu_frequency(0); + + /* table init */ + for (i = 0; (elanfreq_table[i].frequency != CPUFREQ_TABLE_END); i++) { + if (elanfreq_table[i].frequency > max_freq) + elanfreq_table[i].frequency = CPUFREQ_ENTRY_INVALID; + } + + /* cpuinfo and default policy values */ + policy->cpuinfo.transition_latency = CPUFREQ_ETERNAL; + policy->cur = elanfreq_get_cpu_frequency(0); + + result = cpufreq_frequency_table_cpuinfo(policy, elanfreq_table); + if (result) + return result; + + cpufreq_frequency_table_get_attr(elanfreq_table, policy->cpu); + return 0; +} + + +static int elanfreq_cpu_exit(struct cpufreq_policy *policy) +{ + cpufreq_frequency_table_put_attr(policy->cpu); + return 0; +} + + +#ifndef MODULE +/** + * elanfreq_setup - elanfreq command line parameter parsing + * + * elanfreq command line parameter. Use: + * elanfreq=66000 + * to set the maximum CPU frequency to 66 MHz. Note that in + * case you do not give this boot parameter, the maximum + * frequency will fall back to _current_ CPU frequency which + * might be lower. If you build this as a module, use the + * max_freq module parameter instead. + */ +static int __init elanfreq_setup(char *str) +{ + max_freq = simple_strtoul(str, &str, 0); + printk(KERN_WARNING "You're using the deprecated elanfreq command line option. Use elanfreq.max_freq instead, please!\n"); + return 1; +} +__setup("elanfreq=", elanfreq_setup); +#endif + + +static struct freq_attr *elanfreq_attr[] = { + &cpufreq_freq_attr_scaling_available_freqs, + NULL, +}; + + +static struct cpufreq_driver elanfreq_driver = { + .get = elanfreq_get_cpu_frequency, + .verify = elanfreq_verify, + .target = elanfreq_target, + .init = elanfreq_cpu_init, + .exit = elanfreq_cpu_exit, + .name = "elanfreq", + .owner = THIS_MODULE, + .attr = elanfreq_attr, +}; + + +static int __init elanfreq_init(void) +{ + struct cpuinfo_x86 *c = &cpu_data(0); + + /* Test if we have the right hardware */ + if ((c->x86_vendor != X86_VENDOR_AMD) || + (c->x86 != 4) || (c->x86_model != 10)) { + printk(KERN_INFO "elanfreq: error: no Elan processor found!\n"); + return -ENODEV; + } + return cpufreq_register_driver(&elanfreq_driver); +} + + +static void __exit elanfreq_exit(void) +{ + cpufreq_unregister_driver(&elanfreq_driver); +} + + +module_param(max_freq, int, 0444); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Robert Schwebel , " + "Sven Geggus "); +MODULE_DESCRIPTION("cpufreq driver for AMD's Elan CPUs"); + +module_init(elanfreq_init); +module_exit(elanfreq_exit); diff --git a/drivers/cpufreq/gx-suspmod.c b/drivers/cpufreq/gx-suspmod.c new file mode 100644 index 0000000..ffe1f2c --- /dev/null +++ b/drivers/cpufreq/gx-suspmod.c @@ -0,0 +1,514 @@ +/* + * Cyrix MediaGX and NatSemi Geode Suspend Modulation + * (C) 2002 Zwane Mwaikambo + * (C) 2002 Hiroshi Miura + * All Rights Reserved + * + * 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 + * + * The author(s) of this software shall not be held liable for damages + * of any nature resulting due to the use of this software. This + * software is provided AS-IS with no warranties. + * + * Theoretical note: + * + * (see Geode(tm) CS5530 manual (rev.4.1) page.56) + * + * CPU frequency control on NatSemi Geode GX1/GXLV processor and CS55x0 + * are based on Suspend Modulation. + * + * Suspend Modulation works by asserting and de-asserting the SUSP# pin + * to CPU(GX1/GXLV) for configurable durations. When asserting SUSP# + * the CPU enters an idle state. GX1 stops its core clock when SUSP# is + * asserted then power consumption is reduced. + * + * Suspend Modulation's OFF/ON duration are configurable + * with 'Suspend Modulation OFF Count Register' + * and 'Suspend Modulation ON Count Register'. + * These registers are 8bit counters that represent the number of + * 32us intervals which the SUSP# pin is asserted(ON)/de-asserted(OFF) + * to the processor. + * + * These counters define a ratio which is the effective frequency + * of operation of the system. + * + * OFF Count + * F_eff = Fgx * ---------------------- + * OFF Count + ON Count + * + * 0 <= On Count, Off Count <= 255 + * + * From these limits, we can get register values + * + * off_duration + on_duration <= MAX_DURATION + * on_duration = off_duration * (stock_freq - freq) / freq + * + * off_duration = (freq * DURATION) / stock_freq + * on_duration = DURATION - off_duration + * + * + *--------------------------------------------------------------------------- + * + * ChangeLog: + * Dec. 12, 2003 Hiroshi Miura + * - fix on/off register mistake + * - fix cpu_khz calc when it stops cpu modulation. + * + * Dec. 11, 2002 Hiroshi Miura + * - rewrite for Cyrix MediaGX Cx5510/5520 and + * NatSemi Geode Cs5530(A). + * + * Jul. ??, 2002 Zwane Mwaikambo + * - cs5530_mod patch for 2.4.19-rc1. + * + *--------------------------------------------------------------------------- + * + * Todo + * Test on machines with 5510, 5530, 5530A + */ + +/************************************************************************ + * Suspend Modulation - Definitions * + ************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +/* PCI config registers, all at F0 */ +#define PCI_PMER1 0x80 /* power management enable register 1 */ +#define PCI_PMER2 0x81 /* power management enable register 2 */ +#define PCI_PMER3 0x82 /* power management enable register 3 */ +#define PCI_IRQTC 0x8c /* irq speedup timer counter register:typical 2 to 4ms */ +#define PCI_VIDTC 0x8d /* video speedup timer counter register: typical 50 to 100ms */ +#define PCI_MODOFF 0x94 /* suspend modulation OFF counter register, 1 = 32us */ +#define PCI_MODON 0x95 /* suspend modulation ON counter register */ +#define PCI_SUSCFG 0x96 /* suspend configuration register */ + +/* PMER1 bits */ +#define GPM (1<<0) /* global power management */ +#define GIT (1<<1) /* globally enable PM device idle timers */ +#define GTR (1<<2) /* globally enable IO traps */ +#define IRQ_SPDUP (1<<3) /* disable clock throttle during interrupt handling */ +#define VID_SPDUP (1<<4) /* disable clock throttle during vga video handling */ + +/* SUSCFG bits */ +#define SUSMOD (1<<0) /* enable/disable suspend modulation */ +/* the below is supported only with cs5530 (after rev.1.2)/cs5530A */ +#define SMISPDUP (1<<1) /* select how SMI re-enable suspend modulation: */ + /* IRQTC timer or read SMI speedup disable reg.(F1BAR[08-09h]) */ +#define SUSCFG (1<<2) /* enable powering down a GXLV processor. "Special 3Volt Suspend" mode */ +/* the below is supported only with cs5530A */ +#define PWRSVE_ISA (1<<3) /* stop ISA clock */ +#define PWRSVE (1<<4) /* active idle */ + +struct gxfreq_params { + u8 on_duration; + u8 off_duration; + u8 pci_suscfg; + u8 pci_pmer1; + u8 pci_pmer2; + struct pci_dev *cs55x0; +}; + +static struct gxfreq_params *gx_params; +static int stock_freq; + +/* PCI bus clock - defaults to 30.000 if cpu_khz is not available */ +static int pci_busclk; +module_param(pci_busclk, int, 0444); + +/* maximum duration for which the cpu may be suspended + * (32us * MAX_DURATION). If no parameter is given, this defaults + * to 255. + * Note that this leads to a maximum of 8 ms(!) where the CPU clock + * is suspended -- processing power is just 0.39% of what it used to be, + * though. 781.25 kHz(!) for a 200 MHz processor -- wow. */ +static int max_duration = 255; +module_param(max_duration, int, 0444); + +/* For the default policy, we want at least some processing power + * - let's say 5%. (min = maxfreq / POLICY_MIN_DIV) + */ +#define POLICY_MIN_DIV 20 + + +/** + * we can detect a core multipiler from dir0_lsb + * from GX1 datasheet p.56, + * MULT[3:0]: + * 0000 = SYSCLK multiplied by 4 (test only) + * 0001 = SYSCLK multiplied by 10 + * 0010 = SYSCLK multiplied by 4 + * 0011 = SYSCLK multiplied by 6 + * 0100 = SYSCLK multiplied by 9 + * 0101 = SYSCLK multiplied by 5 + * 0110 = SYSCLK multiplied by 7 + * 0111 = SYSCLK multiplied by 8 + * of 33.3MHz + **/ +static int gx_freq_mult[16] = { + 4, 10, 4, 6, 9, 5, 7, 8, + 0, 0, 0, 0, 0, 0, 0, 0 +}; + + +/**************************************************************** + * Low Level chipset interface * + ****************************************************************/ +static struct pci_device_id gx_chipset_tbl[] __initdata = { + { PCI_VDEVICE(CYRIX, PCI_DEVICE_ID_CYRIX_5530_LEGACY), }, + { PCI_VDEVICE(CYRIX, PCI_DEVICE_ID_CYRIX_5520), }, + { PCI_VDEVICE(CYRIX, PCI_DEVICE_ID_CYRIX_5510), }, + { 0, }, +}; + +static void gx_write_byte(int reg, int value) +{ + pci_write_config_byte(gx_params->cs55x0, reg, value); +} + +/** + * gx_detect_chipset: + * + **/ +static __init struct pci_dev *gx_detect_chipset(void) +{ + struct pci_dev *gx_pci = NULL; + + /* check if CPU is a MediaGX or a Geode. */ + if ((boot_cpu_data.x86_vendor != X86_VENDOR_NSC) && + (boot_cpu_data.x86_vendor != X86_VENDOR_CYRIX)) { + pr_debug("error: no MediaGX/Geode processor found!\n"); + return NULL; + } + + /* detect which companion chip is used */ + for_each_pci_dev(gx_pci) { + if ((pci_match_id(gx_chipset_tbl, gx_pci)) != NULL) + return gx_pci; + } + + pr_debug("error: no supported chipset found!\n"); + return NULL; +} + +/** + * gx_get_cpuspeed: + * + * Finds out at which efficient frequency the Cyrix MediaGX/NatSemi + * Geode CPU runs. + */ +static unsigned int gx_get_cpuspeed(unsigned int cpu) +{ + if ((gx_params->pci_suscfg & SUSMOD) == 0) + return stock_freq; + + return (stock_freq * gx_params->off_duration) + / (gx_params->on_duration + gx_params->off_duration); +} + +/** + * gx_validate_speed: + * determine current cpu speed + * + **/ + +static unsigned int gx_validate_speed(unsigned int khz, u8 *on_duration, + u8 *off_duration) +{ + unsigned int i; + u8 tmp_on, tmp_off; + int old_tmp_freq = stock_freq; + int tmp_freq; + + *off_duration = 1; + *on_duration = 0; + + for (i = max_duration; i > 0; i--) { + tmp_off = ((khz * i) / stock_freq) & 0xff; + tmp_on = i - tmp_off; + tmp_freq = (stock_freq * tmp_off) / i; + /* if this relation is closer to khz, use this. If it's equal, + * prefer it, too - lower latency */ + if (abs(tmp_freq - khz) <= abs(old_tmp_freq - khz)) { + *on_duration = tmp_on; + *off_duration = tmp_off; + old_tmp_freq = tmp_freq; + } + } + + return old_tmp_freq; +} + + +/** + * gx_set_cpuspeed: + * set cpu speed in khz. + **/ + +static void gx_set_cpuspeed(unsigned int khz) +{ + u8 suscfg, pmer1; + unsigned int new_khz; + unsigned long flags; + struct cpufreq_freqs freqs; + + freqs.cpu = 0; + freqs.old = gx_get_cpuspeed(0); + + new_khz = gx_validate_speed(khz, &gx_params->on_duration, + &gx_params->off_duration); + + freqs.new = new_khz; + + cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE); + local_irq_save(flags); + + + + if (new_khz != stock_freq) { + /* if new khz == 100% of CPU speed, it is special case */ + switch (gx_params->cs55x0->device) { + case PCI_DEVICE_ID_CYRIX_5530_LEGACY: + pmer1 = gx_params->pci_pmer1 | IRQ_SPDUP | VID_SPDUP; + /* FIXME: need to test other values -- Zwane,Miura */ + /* typical 2 to 4ms */ + gx_write_byte(PCI_IRQTC, 4); + /* typical 50 to 100ms */ + gx_write_byte(PCI_VIDTC, 100); + gx_write_byte(PCI_PMER1, pmer1); + + if (gx_params->cs55x0->revision < 0x10) { + /* CS5530(rev 1.2, 1.3) */ + suscfg = gx_params->pci_suscfg|SUSMOD; + } else { + /* CS5530A,B.. */ + suscfg = gx_params->pci_suscfg|SUSMOD|PWRSVE; + } + break; + case PCI_DEVICE_ID_CYRIX_5520: + case PCI_DEVICE_ID_CYRIX_5510: + suscfg = gx_params->pci_suscfg | SUSMOD; + break; + default: + local_irq_restore(flags); + pr_debug("fatal: try to set unknown chipset.\n"); + return; + } + } else { + suscfg = gx_params->pci_suscfg & ~(SUSMOD); + gx_params->off_duration = 0; + gx_params->on_duration = 0; + pr_debug("suspend modulation disabled: cpu runs 100%% speed.\n"); + } + + gx_write_byte(PCI_MODOFF, gx_params->off_duration); + gx_write_byte(PCI_MODON, gx_params->on_duration); + + gx_write_byte(PCI_SUSCFG, suscfg); + pci_read_config_byte(gx_params->cs55x0, PCI_SUSCFG, &suscfg); + + local_irq_restore(flags); + + gx_params->pci_suscfg = suscfg; + + cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE); + + pr_debug("suspend modulation w/ duration of ON:%d us, OFF:%d us\n", + gx_params->on_duration * 32, gx_params->off_duration * 32); + pr_debug("suspend modulation w/ clock speed: %d kHz.\n", freqs.new); +} + +/**************************************************************** + * High level functions * + ****************************************************************/ + +/* + * cpufreq_gx_verify: test if frequency range is valid + * + * This function checks if a given frequency range in kHz is valid + * for the hardware supported by the driver. + */ + +static int cpufreq_gx_verify(struct cpufreq_policy *policy) +{ + unsigned int tmp_freq = 0; + u8 tmp1, tmp2; + + if (!stock_freq || !policy) + return -EINVAL; + + policy->cpu = 0; + cpufreq_verify_within_limits(policy, (stock_freq / max_duration), + stock_freq); + + /* it needs to be assured that at least one supported frequency is + * within policy->min and policy->max. If it is not, policy->max + * needs to be increased until one freuqency is supported. + * policy->min may not be decreased, though. This way we guarantee a + * specific processing capacity. + */ + tmp_freq = gx_validate_speed(policy->min, &tmp1, &tmp2); + if (tmp_freq < policy->min) + tmp_freq += stock_freq / max_duration; + policy->min = tmp_freq; + if (policy->min > policy->max) + policy->max = tmp_freq; + tmp_freq = gx_validate_speed(policy->max, &tmp1, &tmp2); + if (tmp_freq > policy->max) + tmp_freq -= stock_freq / max_duration; + policy->max = tmp_freq; + if (policy->max < policy->min) + policy->max = policy->min; + cpufreq_verify_within_limits(policy, (stock_freq / max_duration), + stock_freq); + + return 0; +} + +/* + * cpufreq_gx_target: + * + */ +static int cpufreq_gx_target(struct cpufreq_policy *policy, + unsigned int target_freq, + unsigned int relation) +{ + u8 tmp1, tmp2; + unsigned int tmp_freq; + + if (!stock_freq || !policy) + return -EINVAL; + + policy->cpu = 0; + + tmp_freq = gx_validate_speed(target_freq, &tmp1, &tmp2); + while (tmp_freq < policy->min) { + tmp_freq += stock_freq / max_duration; + tmp_freq = gx_validate_speed(tmp_freq, &tmp1, &tmp2); + } + while (tmp_freq > policy->max) { + tmp_freq -= stock_freq / max_duration; + tmp_freq = gx_validate_speed(tmp_freq, &tmp1, &tmp2); + } + + gx_set_cpuspeed(tmp_freq); + + return 0; +} + +static int cpufreq_gx_cpu_init(struct cpufreq_policy *policy) +{ + unsigned int maxfreq, curfreq; + + if (!policy || policy->cpu != 0) + return -ENODEV; + + /* determine maximum frequency */ + if (pci_busclk) + maxfreq = pci_busclk * gx_freq_mult[getCx86(CX86_DIR1) & 0x0f]; + else if (cpu_khz) + maxfreq = cpu_khz; + else + maxfreq = 30000 * gx_freq_mult[getCx86(CX86_DIR1) & 0x0f]; + + stock_freq = maxfreq; + curfreq = gx_get_cpuspeed(0); + + pr_debug("cpu max frequency is %d.\n", maxfreq); + pr_debug("cpu current frequency is %dkHz.\n", curfreq); + + /* setup basic struct for cpufreq API */ + policy->cpu = 0; + + if (max_duration < POLICY_MIN_DIV) + policy->min = maxfreq / max_duration; + else + policy->min = maxfreq / POLICY_MIN_DIV; + policy->max = maxfreq; + policy->cur = curfreq; + policy->cpuinfo.min_freq = maxfreq / max_duration; + policy->cpuinfo.max_freq = maxfreq; + policy->cpuinfo.transition_latency = CPUFREQ_ETERNAL; + + return 0; +} + +/* + * cpufreq_gx_init: + * MediaGX/Geode GX initialize cpufreq driver + */ +static struct cpufreq_driver gx_suspmod_driver = { + .get = gx_get_cpuspeed, + .verify = cpufreq_gx_verify, + .target = cpufreq_gx_target, + .init = cpufreq_gx_cpu_init, + .name = "gx-suspmod", + .owner = THIS_MODULE, +}; + +static int __init cpufreq_gx_init(void) +{ + int ret; + struct gxfreq_params *params; + struct pci_dev *gx_pci; + + /* Test if we have the right hardware */ + gx_pci = gx_detect_chipset(); + if (gx_pci == NULL) + return -ENODEV; + + /* check whether module parameters are sane */ + if (max_duration > 0xff) + max_duration = 0xff; + + pr_debug("geode suspend modulation available.\n"); + + params = kzalloc(sizeof(struct gxfreq_params), GFP_KERNEL); + if (params == NULL) + return -ENOMEM; + + params->cs55x0 = gx_pci; + gx_params = params; + + /* keep cs55x0 configurations */ + pci_read_config_byte(params->cs55x0, PCI_SUSCFG, &(params->pci_suscfg)); + pci_read_config_byte(params->cs55x0, PCI_PMER1, &(params->pci_pmer1)); + pci_read_config_byte(params->cs55x0, PCI_PMER2, &(params->pci_pmer2)); + pci_read_config_byte(params->cs55x0, PCI_MODON, &(params->on_duration)); + pci_read_config_byte(params->cs55x0, PCI_MODOFF, + &(params->off_duration)); + + ret = cpufreq_register_driver(&gx_suspmod_driver); + if (ret) { + kfree(params); + return ret; /* register error! */ + } + + return 0; +} + +static void __exit cpufreq_gx_exit(void) +{ + cpufreq_unregister_driver(&gx_suspmod_driver); + pci_dev_put(gx_params->cs55x0); + kfree(gx_params); +} + +MODULE_AUTHOR("Hiroshi Miura "); +MODULE_DESCRIPTION("Cpufreq driver for Cyrix MediaGX and NatSemi Geode"); +MODULE_LICENSE("GPL"); + +module_init(cpufreq_gx_init); +module_exit(cpufreq_gx_exit); + diff --git a/drivers/cpufreq/longhaul.c b/drivers/cpufreq/longhaul.c new file mode 100644 index 0000000..f47d26e --- /dev/null +++ b/drivers/cpufreq/longhaul.c @@ -0,0 +1,1024 @@ +/* + * (C) 2001-2004 Dave Jones. + * (C) 2002 Padraig Brady. + * + * Licensed under the terms of the GNU GPL License version 2. + * Based upon datasheets & sample CPUs kindly provided by VIA. + * + * VIA have currently 3 different versions of Longhaul. + * Version 1 (Longhaul) uses the BCR2 MSR at 0x1147. + * It is present only in Samuel 1 (C5A), Samuel 2 (C5B) stepping 0. + * Version 2 of longhaul is backward compatible with v1, but adds + * LONGHAUL MSR for purpose of both frequency and voltage scaling. + * Present in Samuel 2 (steppings 1-7 only) (C5B), and Ezra (C5C). + * Version 3 of longhaul got renamed to Powersaver and redesigned + * to use only the POWERSAVER MSR at 0x110a. + * It is present in Ezra-T (C5M), Nehemiah (C5X) and above. + * It's pretty much the same feature wise to longhaul v2, though + * there is provision for scaling FSB too, but this doesn't work + * too well in practice so we don't even try to use this. + * + * BIG FAT DISCLAIMER: Work in progress code. Possibly *dangerous* + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "longhaul.h" + +#define PFX "longhaul: " + +#define TYPE_LONGHAUL_V1 1 +#define TYPE_LONGHAUL_V2 2 +#define TYPE_POWERSAVER 3 + +#define CPU_SAMUEL 1 +#define CPU_SAMUEL2 2 +#define CPU_EZRA 3 +#define CPU_EZRA_T 4 +#define CPU_NEHEMIAH 5 +#define CPU_NEHEMIAH_C 6 + +/* Flags */ +#define USE_ACPI_C3 (1 << 1) +#define USE_NORTHBRIDGE (1 << 2) + +static int cpu_model; +static unsigned int numscales = 16; +static unsigned int fsb; + +static const struct mV_pos *vrm_mV_table; +static const unsigned char *mV_vrm_table; + +static unsigned int highest_speed, lowest_speed; /* kHz */ +static unsigned int minmult, maxmult; +static int can_scale_voltage; +static struct acpi_processor *pr; +static struct acpi_processor_cx *cx; +static u32 acpi_regs_addr; +static u8 longhaul_flags; +static unsigned int longhaul_index; + +/* Module parameters */ +static int scale_voltage; +static int disable_acpi_c3; +static int revid_errata; + + +/* Clock ratios multiplied by 10 */ +static int mults[32]; +static int eblcr[32]; +static int longhaul_version; +static struct cpufreq_frequency_table *longhaul_table; + +static char speedbuffer[8]; + +static char *print_speed(int speed) +{ + if (speed < 1000) { + snprintf(speedbuffer, sizeof(speedbuffer), "%dMHz", speed); + return speedbuffer; + } + + if (speed%1000 == 0) + snprintf(speedbuffer, sizeof(speedbuffer), + "%dGHz", speed/1000); + else + snprintf(speedbuffer, sizeof(speedbuffer), + "%d.%dGHz", speed/1000, (speed%1000)/100); + + return speedbuffer; +} + + +static unsigned int calc_speed(int mult) +{ + int khz; + khz = (mult/10)*fsb; + if (mult%10) + khz += fsb/2; + khz *= 1000; + return khz; +} + + +static int longhaul_get_cpu_mult(void) +{ + unsigned long invalue = 0, lo, hi; + + rdmsr(MSR_IA32_EBL_CR_POWERON, lo, hi); + invalue = (lo & (1<<22|1<<23|1<<24|1<<25))>>22; + if (longhaul_version == TYPE_LONGHAUL_V2 || + longhaul_version == TYPE_POWERSAVER) { + if (lo & (1<<27)) + invalue += 16; + } + return eblcr[invalue]; +} + +/* For processor with BCR2 MSR */ + +static void do_longhaul1(unsigned int mults_index) +{ + union msr_bcr2 bcr2; + + rdmsrl(MSR_VIA_BCR2, bcr2.val); + /* Enable software clock multiplier */ + bcr2.bits.ESOFTBF = 1; + bcr2.bits.CLOCKMUL = mults_index & 0xff; + + /* Sync to timer tick */ + safe_halt(); + /* Change frequency on next halt or sleep */ + wrmsrl(MSR_VIA_BCR2, bcr2.val); + /* Invoke transition */ + ACPI_FLUSH_CPU_CACHE(); + halt(); + + /* Disable software clock multiplier */ + local_irq_disable(); + rdmsrl(MSR_VIA_BCR2, bcr2.val); + bcr2.bits.ESOFTBF = 0; + wrmsrl(MSR_VIA_BCR2, bcr2.val); +} + +/* For processor with Longhaul MSR */ + +static void do_powersaver(int cx_address, unsigned int mults_index, + unsigned int dir) +{ + union msr_longhaul longhaul; + u32 t; + + rdmsrl(MSR_VIA_LONGHAUL, longhaul.val); + /* Setup new frequency */ + if (!revid_errata) + longhaul.bits.RevisionKey = longhaul.bits.RevisionID; + else + longhaul.bits.RevisionKey = 0; + longhaul.bits.SoftBusRatio = mults_index & 0xf; + longhaul.bits.SoftBusRatio4 = (mults_index & 0x10) >> 4; + /* Setup new voltage */ + if (can_scale_voltage) + longhaul.bits.SoftVID = (mults_index >> 8) & 0x1f; + /* Sync to timer tick */ + safe_halt(); + /* Raise voltage if necessary */ + if (can_scale_voltage && dir) { + longhaul.bits.EnableSoftVID = 1; + wrmsrl(MSR_VIA_LONGHAUL, longhaul.val); + /* Change voltage */ + if (!cx_address) { + ACPI_FLUSH_CPU_CACHE(); + halt(); + } else { + ACPI_FLUSH_CPU_CACHE(); + /* Invoke C3 */ + inb(cx_address); + /* Dummy op - must do something useless after P_LVL3 + * read */ + t = inl(acpi_gbl_FADT.xpm_timer_block.address); + } + longhaul.bits.EnableSoftVID = 0; + wrmsrl(MSR_VIA_LONGHAUL, longhaul.val); + } + + /* Change frequency on next halt or sleep */ + longhaul.bits.EnableSoftBusRatio = 1; + wrmsrl(MSR_VIA_LONGHAUL, longhaul.val); + if (!cx_address) { + ACPI_FLUSH_CPU_CACHE(); + halt(); + } else { + ACPI_FLUSH_CPU_CACHE(); + /* Invoke C3 */ + inb(cx_address); + /* Dummy op - must do something useless after P_LVL3 read */ + t = inl(acpi_gbl_FADT.xpm_timer_block.address); + } + /* Disable bus ratio bit */ + longhaul.bits.EnableSoftBusRatio = 0; + wrmsrl(MSR_VIA_LONGHAUL, longhaul.val); + + /* Reduce voltage if necessary */ + if (can_scale_voltage && !dir) { + longhaul.bits.EnableSoftVID = 1; + wrmsrl(MSR_VIA_LONGHAUL, longhaul.val); + /* Change voltage */ + if (!cx_address) { + ACPI_FLUSH_CPU_CACHE(); + halt(); + } else { + ACPI_FLUSH_CPU_CACHE(); + /* Invoke C3 */ + inb(cx_address); + /* Dummy op - must do something useless after P_LVL3 + * read */ + t = inl(acpi_gbl_FADT.xpm_timer_block.address); + } + longhaul.bits.EnableSoftVID = 0; + wrmsrl(MSR_VIA_LONGHAUL, longhaul.val); + } +} + +/** + * longhaul_set_cpu_frequency() + * @mults_index : bitpattern of the new multiplier. + * + * Sets a new clock ratio. + */ + +static void longhaul_setstate(unsigned int table_index) +{ + unsigned int mults_index; + int speed, mult; + struct cpufreq_freqs freqs; + unsigned long flags; + unsigned int pic1_mask, pic2_mask; + u16 bm_status = 0; + u32 bm_timeout = 1000; + unsigned int dir = 0; + + mults_index = longhaul_table[table_index].index; + /* Safety precautions */ + mult = mults[mults_index & 0x1f]; + if (mult == -1) + return; + speed = calc_speed(mult); + if ((speed > highest_speed) || (speed < lowest_speed)) + return; + /* Voltage transition before frequency transition? */ + if (can_scale_voltage && longhaul_index < table_index) + dir = 1; + + freqs.old = calc_speed(longhaul_get_cpu_mult()); + freqs.new = speed; + freqs.cpu = 0; /* longhaul.c is UP only driver */ + + cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE); + + pr_debug("Setting to FSB:%dMHz Mult:%d.%dx (%s)\n", + fsb, mult/10, mult%10, print_speed(speed/1000)); +retry_loop: + preempt_disable(); + local_irq_save(flags); + + pic2_mask = inb(0xA1); + pic1_mask = inb(0x21); /* works on C3. save mask. */ + outb(0xFF, 0xA1); /* Overkill */ + outb(0xFE, 0x21); /* TMR0 only */ + + /* Wait while PCI bus is busy. */ + if (acpi_regs_addr && (longhaul_flags & USE_NORTHBRIDGE + || ((pr != NULL) && pr->flags.bm_control))) { + bm_status = inw(acpi_regs_addr); + bm_status &= 1 << 4; + while (bm_status && bm_timeout) { + outw(1 << 4, acpi_regs_addr); + bm_timeout--; + bm_status = inw(acpi_regs_addr); + bm_status &= 1 << 4; + } + } + + if (longhaul_flags & USE_NORTHBRIDGE) { + /* Disable AGP and PCI arbiters */ + outb(3, 0x22); + } else if ((pr != NULL) && pr->flags.bm_control) { + /* Disable bus master arbitration */ + acpi_write_bit_register(ACPI_BITREG_ARB_DISABLE, 1); + } + switch (longhaul_version) { + + /* + * Longhaul v1. (Samuel[C5A] and Samuel2 stepping 0[C5B]) + * Software controlled multipliers only. + */ + case TYPE_LONGHAUL_V1: + do_longhaul1(mults_index); + break; + + /* + * Longhaul v2 appears in Samuel2 Steppings 1->7 [C5B] and Ezra [C5C] + * + * Longhaul v3 (aka Powersaver). (Ezra-T [C5M] & Nehemiah [C5N]) + * Nehemiah can do FSB scaling too, but this has never been proven + * to work in practice. + */ + case TYPE_LONGHAUL_V2: + case TYPE_POWERSAVER: + if (longhaul_flags & USE_ACPI_C3) { + /* Don't allow wakeup */ + acpi_write_bit_register(ACPI_BITREG_BUS_MASTER_RLD, 0); + do_powersaver(cx->address, mults_index, dir); + } else { + do_powersaver(0, mults_index, dir); + } + break; + } + + if (longhaul_flags & USE_NORTHBRIDGE) { + /* Enable arbiters */ + outb(0, 0x22); + } else if ((pr != NULL) && pr->flags.bm_control) { + /* Enable bus master arbitration */ + acpi_write_bit_register(ACPI_BITREG_ARB_DISABLE, 0); + } + outb(pic2_mask, 0xA1); /* restore mask */ + outb(pic1_mask, 0x21); + + local_irq_restore(flags); + preempt_enable(); + + freqs.new = calc_speed(longhaul_get_cpu_mult()); + /* Check if requested frequency is set. */ + if (unlikely(freqs.new != speed)) { + printk(KERN_INFO PFX "Failed to set requested frequency!\n"); + /* Revision ID = 1 but processor is expecting revision key + * equal to 0. Jumpers at the bottom of processor will change + * multiplier and FSB, but will not change bits in Longhaul + * MSR nor enable voltage scaling. */ + if (!revid_errata) { + printk(KERN_INFO PFX "Enabling \"Ignore Revision ID\" " + "option.\n"); + revid_errata = 1; + msleep(200); + goto retry_loop; + } + /* Why ACPI C3 sometimes doesn't work is a mystery for me. + * But it does happen. Processor is entering ACPI C3 state, + * but it doesn't change frequency. I tried poking various + * bits in northbridge registers, but without success. */ + if (longhaul_flags & USE_ACPI_C3) { + printk(KERN_INFO PFX "Disabling ACPI C3 support.\n"); + longhaul_flags &= ~USE_ACPI_C3; + if (revid_errata) { + printk(KERN_INFO PFX "Disabling \"Ignore " + "Revision ID\" option.\n"); + revid_errata = 0; + } + msleep(200); + goto retry_loop; + } + /* This shouldn't happen. Longhaul ver. 2 was reported not + * working on processors without voltage scaling, but with + * RevID = 1. RevID errata will make things right. Just + * to be 100% sure. */ + if (longhaul_version == TYPE_LONGHAUL_V2) { + printk(KERN_INFO PFX "Switching to Longhaul ver. 1\n"); + longhaul_version = TYPE_LONGHAUL_V1; + msleep(200); + goto retry_loop; + } + } + /* Report true CPU frequency */ + cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE); + + if (!bm_timeout) + printk(KERN_INFO PFX "Warning: Timeout while waiting for " + "idle PCI bus.\n"); +} + +/* + * Centaur decided to make life a little more tricky. + * Only longhaul v1 is allowed to read EBLCR BSEL[0:1]. + * Samuel2 and above have to try and guess what the FSB is. + * We do this by assuming we booted at maximum multiplier, and interpolate + * between that value multiplied by possible FSBs and cpu_mhz which + * was calculated at boot time. Really ugly, but no other way to do this. + */ + +#define ROUNDING 0xf + +static int guess_fsb(int mult) +{ + int speed = cpu_khz / 1000; + int i; + int speeds[] = { 666, 1000, 1333, 2000 }; + int f_max, f_min; + + for (i = 0; i < 4; i++) { + f_max = ((speeds[i] * mult) + 50) / 100; + f_max += (ROUNDING / 2); + f_min = f_max - ROUNDING; + if ((speed <= f_max) && (speed >= f_min)) + return speeds[i] / 10; + } + return 0; +} + + +static int __cpuinit longhaul_get_ranges(void) +{ + unsigned int i, j, k = 0; + unsigned int ratio; + int mult; + + /* Get current frequency */ + mult = longhaul_get_cpu_mult(); + if (mult == -1) { + printk(KERN_INFO PFX "Invalid (reserved) multiplier!\n"); + return -EINVAL; + } + fsb = guess_fsb(mult); + if (fsb == 0) { + printk(KERN_INFO PFX "Invalid (reserved) FSB!\n"); + return -EINVAL; + } + /* Get max multiplier - as we always did. + * Longhaul MSR is useful only when voltage scaling is enabled. + * C3 is booting at max anyway. */ + maxmult = mult; + /* Get min multiplier */ + switch (cpu_model) { + case CPU_NEHEMIAH: + minmult = 50; + break; + case CPU_NEHEMIAH_C: + minmult = 40; + break; + default: + minmult = 30; + break; + } + + pr_debug("MinMult:%d.%dx MaxMult:%d.%dx\n", + minmult/10, minmult%10, maxmult/10, maxmult%10); + + highest_speed = calc_speed(maxmult); + lowest_speed = calc_speed(minmult); + pr_debug("FSB:%dMHz Lowest speed: %s Highest speed:%s\n", fsb, + print_speed(lowest_speed/1000), + print_speed(highest_speed/1000)); + + if (lowest_speed == highest_speed) { + printk(KERN_INFO PFX "highestspeed == lowest, aborting.\n"); + return -EINVAL; + } + if (lowest_speed > highest_speed) { + printk(KERN_INFO PFX "nonsense! lowest (%d > %d) !\n", + lowest_speed, highest_speed); + return -EINVAL; + } + + longhaul_table = kmalloc((numscales + 1) * sizeof(*longhaul_table), + GFP_KERNEL); + if (!longhaul_table) + return -ENOMEM; + + for (j = 0; j < numscales; j++) { + ratio = mults[j]; + if (ratio == -1) + continue; + if (ratio > maxmult || ratio < minmult) + continue; + longhaul_table[k].frequency = calc_speed(ratio); + longhaul_table[k].index = j; + k++; + } + if (k <= 1) { + kfree(longhaul_table); + return -ENODEV; + } + /* Sort */ + for (j = 0; j < k - 1; j++) { + unsigned int min_f, min_i; + min_f = longhaul_table[j].frequency; + min_i = j; + for (i = j + 1; i < k; i++) { + if (longhaul_table[i].frequency < min_f) { + min_f = longhaul_table[i].frequency; + min_i = i; + } + } + if (min_i != j) { + swap(longhaul_table[j].frequency, + longhaul_table[min_i].frequency); + swap(longhaul_table[j].index, + longhaul_table[min_i].index); + } + } + + longhaul_table[k].frequency = CPUFREQ_TABLE_END; + + /* Find index we are running on */ + for (j = 0; j < k; j++) { + if (mults[longhaul_table[j].index & 0x1f] == mult) { + longhaul_index = j; + break; + } + } + return 0; +} + + +static void __cpuinit longhaul_setup_voltagescaling(void) +{ + union msr_longhaul longhaul; + struct mV_pos minvid, maxvid, vid; + unsigned int j, speed, pos, kHz_step, numvscales; + int min_vid_speed; + + rdmsrl(MSR_VIA_LONGHAUL, longhaul.val); + if (!(longhaul.bits.RevisionID & 1)) { + printk(KERN_INFO PFX "Voltage scaling not supported by CPU.\n"); + return; + } + + if (!longhaul.bits.VRMRev) { + printk(KERN_INFO PFX "VRM 8.5\n"); + vrm_mV_table = &vrm85_mV[0]; + mV_vrm_table = &mV_vrm85[0]; + } else { + printk(KERN_INFO PFX "Mobile VRM\n"); + if (cpu_model < CPU_NEHEMIAH) + return; + vrm_mV_table = &mobilevrm_mV[0]; + mV_vrm_table = &mV_mobilevrm[0]; + } + + minvid = vrm_mV_table[longhaul.bits.MinimumVID]; + maxvid = vrm_mV_table[longhaul.bits.MaximumVID]; + + if (minvid.mV == 0 || maxvid.mV == 0 || minvid.mV > maxvid.mV) { + printk(KERN_INFO PFX "Bogus values Min:%d.%03d Max:%d.%03d. " + "Voltage scaling disabled.\n", + minvid.mV/1000, minvid.mV%1000, + maxvid.mV/1000, maxvid.mV%1000); + return; + } + + if (minvid.mV == maxvid.mV) { + printk(KERN_INFO PFX "Claims to support voltage scaling but " + "min & max are both %d.%03d. " + "Voltage scaling disabled\n", + maxvid.mV/1000, maxvid.mV%1000); + return; + } + + /* How many voltage steps*/ + numvscales = maxvid.pos - minvid.pos + 1; + printk(KERN_INFO PFX + "Max VID=%d.%03d " + "Min VID=%d.%03d, " + "%d possible voltage scales\n", + maxvid.mV/1000, maxvid.mV%1000, + minvid.mV/1000, minvid.mV%1000, + numvscales); + + /* Calculate max frequency at min voltage */ + j = longhaul.bits.MinMHzBR; + if (longhaul.bits.MinMHzBR4) + j += 16; + min_vid_speed = eblcr[j]; + if (min_vid_speed == -1) + return; + switch (longhaul.bits.MinMHzFSB) { + case 0: + min_vid_speed *= 13333; + break; + case 1: + min_vid_speed *= 10000; + break; + case 3: + min_vid_speed *= 6666; + break; + default: + return; + break; + } + if (min_vid_speed >= highest_speed) + return; + /* Calculate kHz for one voltage step */ + kHz_step = (highest_speed - min_vid_speed) / numvscales; + + j = 0; + while (longhaul_table[j].frequency != CPUFREQ_TABLE_END) { + speed = longhaul_table[j].frequency; + if (speed > min_vid_speed) + pos = (speed - min_vid_speed) / kHz_step + minvid.pos; + else + pos = minvid.pos; + longhaul_table[j].index |= mV_vrm_table[pos] << 8; + vid = vrm_mV_table[mV_vrm_table[pos]]; + printk(KERN_INFO PFX "f: %d kHz, index: %d, vid: %d mV\n", + speed, j, vid.mV); + j++; + } + + can_scale_voltage = 1; + printk(KERN_INFO PFX "Voltage scaling enabled.\n"); +} + + +static int longhaul_verify(struct cpufreq_policy *policy) +{ + return cpufreq_frequency_table_verify(policy, longhaul_table); +} + + +static int longhaul_target(struct cpufreq_policy *policy, + unsigned int target_freq, unsigned int relation) +{ + unsigned int table_index = 0; + unsigned int i; + unsigned int dir = 0; + u8 vid, current_vid; + + if (cpufreq_frequency_table_target(policy, longhaul_table, target_freq, + relation, &table_index)) + return -EINVAL; + + /* Don't set same frequency again */ + if (longhaul_index == table_index) + return 0; + + if (!can_scale_voltage) + longhaul_setstate(table_index); + else { + /* On test system voltage transitions exceeding single + * step up or down were turning motherboard off. Both + * "ondemand" and "userspace" are unsafe. C7 is doing + * this in hardware, C3 is old and we need to do this + * in software. */ + i = longhaul_index; + current_vid = (longhaul_table[longhaul_index].index >> 8); + current_vid &= 0x1f; + if (table_index > longhaul_index) + dir = 1; + while (i != table_index) { + vid = (longhaul_table[i].index >> 8) & 0x1f; + if (vid != current_vid) { + longhaul_setstate(i); + current_vid = vid; + msleep(200); + } + if (dir) + i++; + else + i--; + } + longhaul_setstate(table_index); + } + longhaul_index = table_index; + return 0; +} + + +static unsigned int longhaul_get(unsigned int cpu) +{ + if (cpu) + return 0; + return calc_speed(longhaul_get_cpu_mult()); +} + +static acpi_status longhaul_walk_callback(acpi_handle obj_handle, + u32 nesting_level, + void *context, void **return_value) +{ + struct acpi_device *d; + + if (acpi_bus_get_device(obj_handle, &d)) + return 0; + + *return_value = acpi_driver_data(d); + return 1; +} + +/* VIA don't support PM2 reg, but have something similar */ +static int enable_arbiter_disable(void) +{ + struct pci_dev *dev; + int status = 1; + int reg; + u8 pci_cmd; + + /* Find PLE133 host bridge */ + reg = 0x78; + dev = pci_get_device(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8601_0, + NULL); + /* Find PM133/VT8605 host bridge */ + if (dev == NULL) + dev = pci_get_device(PCI_VENDOR_ID_VIA, + PCI_DEVICE_ID_VIA_8605_0, NULL); + /* Find CLE266 host bridge */ + if (dev == NULL) { + reg = 0x76; + dev = pci_get_device(PCI_VENDOR_ID_VIA, + PCI_DEVICE_ID_VIA_862X_0, NULL); + /* Find CN400 V-Link host bridge */ + if (dev == NULL) + dev = pci_get_device(PCI_VENDOR_ID_VIA, 0x7259, NULL); + } + if (dev != NULL) { + /* Enable access to port 0x22 */ + pci_read_config_byte(dev, reg, &pci_cmd); + if (!(pci_cmd & 1<<7)) { + pci_cmd |= 1<<7; + pci_write_config_byte(dev, reg, pci_cmd); + pci_read_config_byte(dev, reg, &pci_cmd); + if (!(pci_cmd & 1<<7)) { + printk(KERN_ERR PFX + "Can't enable access to port 0x22.\n"); + status = 0; + } + } + pci_dev_put(dev); + return status; + } + return 0; +} + +static int longhaul_setup_southbridge(void) +{ + struct pci_dev *dev; + u8 pci_cmd; + + /* Find VT8235 southbridge */ + dev = pci_get_device(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8235, NULL); + if (dev == NULL) + /* Find VT8237 southbridge */ + dev = pci_get_device(PCI_VENDOR_ID_VIA, + PCI_DEVICE_ID_VIA_8237, NULL); + if (dev != NULL) { + /* Set transition time to max */ + pci_read_config_byte(dev, 0xec, &pci_cmd); + pci_cmd &= ~(1 << 2); + pci_write_config_byte(dev, 0xec, pci_cmd); + pci_read_config_byte(dev, 0xe4, &pci_cmd); + pci_cmd &= ~(1 << 7); + pci_write_config_byte(dev, 0xe4, pci_cmd); + pci_read_config_byte(dev, 0xe5, &pci_cmd); + pci_cmd |= 1 << 7; + pci_write_config_byte(dev, 0xe5, pci_cmd); + /* Get address of ACPI registers block*/ + pci_read_config_byte(dev, 0x81, &pci_cmd); + if (pci_cmd & 1 << 7) { + pci_read_config_dword(dev, 0x88, &acpi_regs_addr); + acpi_regs_addr &= 0xff00; + printk(KERN_INFO PFX "ACPI I/O at 0x%x\n", + acpi_regs_addr); + } + + pci_dev_put(dev); + return 1; + } + return 0; +} + +static int __cpuinit longhaul_cpu_init(struct cpufreq_policy *policy) +{ + struct cpuinfo_x86 *c = &cpu_data(0); + char *cpuname = NULL; + int ret; + u32 lo, hi; + + /* Check what we have on this motherboard */ + switch (c->x86_model) { + case 6: + cpu_model = CPU_SAMUEL; + cpuname = "C3 'Samuel' [C5A]"; + longhaul_version = TYPE_LONGHAUL_V1; + memcpy(mults, samuel1_mults, sizeof(samuel1_mults)); + memcpy(eblcr, samuel1_eblcr, sizeof(samuel1_eblcr)); + break; + + case 7: + switch (c->x86_mask) { + case 0: + longhaul_version = TYPE_LONGHAUL_V1; + cpu_model = CPU_SAMUEL2; + cpuname = "C3 'Samuel 2' [C5B]"; + /* Note, this is not a typo, early Samuel2's had + * Samuel1 ratios. */ + memcpy(mults, samuel1_mults, sizeof(samuel1_mults)); + memcpy(eblcr, samuel2_eblcr, sizeof(samuel2_eblcr)); + break; + case 1 ... 15: + longhaul_version = TYPE_LONGHAUL_V2; + if (c->x86_mask < 8) { + cpu_model = CPU_SAMUEL2; + cpuname = "C3 'Samuel 2' [C5B]"; + } else { + cpu_model = CPU_EZRA; + cpuname = "C3 'Ezra' [C5C]"; + } + memcpy(mults, ezra_mults, sizeof(ezra_mults)); + memcpy(eblcr, ezra_eblcr, sizeof(ezra_eblcr)); + break; + } + break; + + case 8: + cpu_model = CPU_EZRA_T; + cpuname = "C3 'Ezra-T' [C5M]"; + longhaul_version = TYPE_POWERSAVER; + numscales = 32; + memcpy(mults, ezrat_mults, sizeof(ezrat_mults)); + memcpy(eblcr, ezrat_eblcr, sizeof(ezrat_eblcr)); + break; + + case 9: + longhaul_version = TYPE_POWERSAVER; + numscales = 32; + memcpy(mults, nehemiah_mults, sizeof(nehemiah_mults)); + memcpy(eblcr, nehemiah_eblcr, sizeof(nehemiah_eblcr)); + switch (c->x86_mask) { + case 0 ... 1: + cpu_model = CPU_NEHEMIAH; + cpuname = "C3 'Nehemiah A' [C5XLOE]"; + break; + case 2 ... 4: + cpu_model = CPU_NEHEMIAH; + cpuname = "C3 'Nehemiah B' [C5XLOH]"; + break; + case 5 ... 15: + cpu_model = CPU_NEHEMIAH_C; + cpuname = "C3 'Nehemiah C' [C5P]"; + break; + } + break; + + default: + cpuname = "Unknown"; + break; + } + /* Check Longhaul ver. 2 */ + if (longhaul_version == TYPE_LONGHAUL_V2) { + rdmsr(MSR_VIA_LONGHAUL, lo, hi); + if (lo == 0 && hi == 0) + /* Looks like MSR isn't present */ + longhaul_version = TYPE_LONGHAUL_V1; + } + + printk(KERN_INFO PFX "VIA %s CPU detected. ", cpuname); + switch (longhaul_version) { + case TYPE_LONGHAUL_V1: + case TYPE_LONGHAUL_V2: + printk(KERN_CONT "Longhaul v%d supported.\n", longhaul_version); + break; + case TYPE_POWERSAVER: + printk(KERN_CONT "Powersaver supported.\n"); + break; + }; + + /* Doesn't hurt */ + longhaul_setup_southbridge(); + + /* Find ACPI data for processor */ + acpi_walk_namespace(ACPI_TYPE_PROCESSOR, ACPI_ROOT_OBJECT, + ACPI_UINT32_MAX, &longhaul_walk_callback, NULL, + NULL, (void *)&pr); + + /* Check ACPI support for C3 state */ + if (pr != NULL && longhaul_version == TYPE_POWERSAVER) { + cx = &pr->power.states[ACPI_STATE_C3]; + if (cx->address > 0 && cx->latency <= 1000) + longhaul_flags |= USE_ACPI_C3; + } + /* Disable if it isn't working */ + if (disable_acpi_c3) + longhaul_flags &= ~USE_ACPI_C3; + /* Check if northbridge is friendly */ + if (enable_arbiter_disable()) + longhaul_flags |= USE_NORTHBRIDGE; + + /* Check ACPI support for bus master arbiter disable */ + if (!(longhaul_flags & USE_ACPI_C3 + || longhaul_flags & USE_NORTHBRIDGE) + && ((pr == NULL) || !(pr->flags.bm_control))) { + printk(KERN_ERR PFX + "No ACPI support. Unsupported northbridge.\n"); + return -ENODEV; + } + + if (longhaul_flags & USE_NORTHBRIDGE) + printk(KERN_INFO PFX "Using northbridge support.\n"); + if (longhaul_flags & USE_ACPI_C3) + printk(KERN_INFO PFX "Using ACPI support.\n"); + + ret = longhaul_get_ranges(); + if (ret != 0) + return ret; + + if ((longhaul_version != TYPE_LONGHAUL_V1) && (scale_voltage != 0)) + longhaul_setup_voltagescaling(); + + policy->cpuinfo.transition_latency = 200000; /* nsec */ + policy->cur = calc_speed(longhaul_get_cpu_mult()); + + ret = cpufreq_frequency_table_cpuinfo(policy, longhaul_table); + if (ret) + return ret; + + cpufreq_frequency_table_get_attr(longhaul_table, policy->cpu); + + return 0; +} + +static int __devexit longhaul_cpu_exit(struct cpufreq_policy *policy) +{ + cpufreq_frequency_table_put_attr(policy->cpu); + return 0; +} + +static struct freq_attr *longhaul_attr[] = { + &cpufreq_freq_attr_scaling_available_freqs, + NULL, +}; + +static struct cpufreq_driver longhaul_driver = { + .verify = longhaul_verify, + .target = longhaul_target, + .get = longhaul_get, + .init = longhaul_cpu_init, + .exit = __devexit_p(longhaul_cpu_exit), + .name = "longhaul", + .owner = THIS_MODULE, + .attr = longhaul_attr, +}; + + +static int __init longhaul_init(void) +{ + struct cpuinfo_x86 *c = &cpu_data(0); + + if (c->x86_vendor != X86_VENDOR_CENTAUR || c->x86 != 6) + return -ENODEV; + +#ifdef CONFIG_SMP + if (num_online_cpus() > 1) { + printk(KERN_ERR PFX "More than 1 CPU detected, " + "longhaul disabled.\n"); + return -ENODEV; + } +#endif +#ifdef CONFIG_X86_IO_APIC + if (cpu_has_apic) { + printk(KERN_ERR PFX "APIC detected. Longhaul is currently " + "broken in this configuration.\n"); + return -ENODEV; + } +#endif + switch (c->x86_model) { + case 6 ... 9: + return cpufreq_register_driver(&longhaul_driver); + case 10: + printk(KERN_ERR PFX "Use acpi-cpufreq driver for VIA C7\n"); + default: + ; + } + + return -ENODEV; +} + + +static void __exit longhaul_exit(void) +{ + int i; + + for (i = 0; i < numscales; i++) { + if (mults[i] == maxmult) { + longhaul_setstate(i); + break; + } + } + + cpufreq_unregister_driver(&longhaul_driver); + kfree(longhaul_table); +} + +/* Even if BIOS is exporting ACPI C3 state, and it is used + * with success when CPU is idle, this state doesn't + * trigger frequency transition in some cases. */ +module_param(disable_acpi_c3, int, 0644); +MODULE_PARM_DESC(disable_acpi_c3, "Don't use ACPI C3 support"); +/* Change CPU voltage with frequency. Very useful to save + * power, but most VIA C3 processors aren't supporting it. */ +module_param(scale_voltage, int, 0644); +MODULE_PARM_DESC(scale_voltage, "Scale voltage of processor"); +/* Force revision key to 0 for processors which doesn't + * support voltage scaling, but are introducing itself as + * such. */ +module_param(revid_errata, int, 0644); +MODULE_PARM_DESC(revid_errata, "Ignore CPU Revision ID"); + +MODULE_AUTHOR("Dave Jones "); +MODULE_DESCRIPTION("Longhaul driver for VIA Cyrix processors."); +MODULE_LICENSE("GPL"); + +late_initcall(longhaul_init); +module_exit(longhaul_exit); diff --git a/drivers/cpufreq/longhaul.h b/drivers/cpufreq/longhaul.h new file mode 100644 index 0000000..cbf48fb --- /dev/null +++ b/drivers/cpufreq/longhaul.h @@ -0,0 +1,353 @@ +/* + * longhaul.h + * (C) 2003 Dave Jones. + * + * Licensed under the terms of the GNU GPL License version 2. + * + * VIA-specific information + */ + +union msr_bcr2 { + struct { + unsigned Reseved:19, // 18:0 + ESOFTBF:1, // 19 + Reserved2:3, // 22:20 + CLOCKMUL:4, // 26:23 + Reserved3:5; // 31:27 + } bits; + unsigned long val; +}; + +union msr_longhaul { + struct { + unsigned RevisionID:4, // 3:0 + RevisionKey:4, // 7:4 + EnableSoftBusRatio:1, // 8 + EnableSoftVID:1, // 9 + EnableSoftBSEL:1, // 10 + Reserved:3, // 11:13 + SoftBusRatio4:1, // 14 + VRMRev:1, // 15 + SoftBusRatio:4, // 19:16 + SoftVID:5, // 24:20 + Reserved2:3, // 27:25 + SoftBSEL:2, // 29:28 + Reserved3:2, // 31:30 + MaxMHzBR:4, // 35:32 + MaximumVID:5, // 40:36 + MaxMHzFSB:2, // 42:41 + MaxMHzBR4:1, // 43 + Reserved4:4, // 47:44 + MinMHzBR:4, // 51:48 + MinimumVID:5, // 56:52 + MinMHzFSB:2, // 58:57 + MinMHzBR4:1, // 59 + Reserved5:4; // 63:60 + } bits; + unsigned long long val; +}; + +/* + * Clock ratio tables. Div/Mod by 10 to get ratio. + * The eblcr values specify the ratio read from the CPU. + * The mults values specify what to write to the CPU. + */ + +/* + * VIA C3 Samuel 1 & Samuel 2 (stepping 0) + */ +static const int __cpuinitdata samuel1_mults[16] = { + -1, /* 0000 -> RESERVED */ + 30, /* 0001 -> 3.0x */ + 40, /* 0010 -> 4.0x */ + -1, /* 0011 -> RESERVED */ + -1, /* 0100 -> RESERVED */ + 35, /* 0101 -> 3.5x */ + 45, /* 0110 -> 4.5x */ + 55, /* 0111 -> 5.5x */ + 60, /* 1000 -> 6.0x */ + 70, /* 1001 -> 7.0x */ + 80, /* 1010 -> 8.0x */ + 50, /* 1011 -> 5.0x */ + 65, /* 1100 -> 6.5x */ + 75, /* 1101 -> 7.5x */ + -1, /* 1110 -> RESERVED */ + -1, /* 1111 -> RESERVED */ +}; + +static const int __cpuinitdata samuel1_eblcr[16] = { + 50, /* 0000 -> RESERVED */ + 30, /* 0001 -> 3.0x */ + 40, /* 0010 -> 4.0x */ + -1, /* 0011 -> RESERVED */ + 55, /* 0100 -> 5.5x */ + 35, /* 0101 -> 3.5x */ + 45, /* 0110 -> 4.5x */ + -1, /* 0111 -> RESERVED */ + -1, /* 1000 -> RESERVED */ + 70, /* 1001 -> 7.0x */ + 80, /* 1010 -> 8.0x */ + 60, /* 1011 -> 6.0x */ + -1, /* 1100 -> RESERVED */ + 75, /* 1101 -> 7.5x */ + -1, /* 1110 -> RESERVED */ + 65, /* 1111 -> 6.5x */ +}; + +/* + * VIA C3 Samuel2 Stepping 1->15 + */ +static const int __cpuinitdata samuel2_eblcr[16] = { + 50, /* 0000 -> 5.0x */ + 30, /* 0001 -> 3.0x */ + 40, /* 0010 -> 4.0x */ + 100, /* 0011 -> 10.0x */ + 55, /* 0100 -> 5.5x */ + 35, /* 0101 -> 3.5x */ + 45, /* 0110 -> 4.5x */ + 110, /* 0111 -> 11.0x */ + 90, /* 1000 -> 9.0x */ + 70, /* 1001 -> 7.0x */ + 80, /* 1010 -> 8.0x */ + 60, /* 1011 -> 6.0x */ + 120, /* 1100 -> 12.0x */ + 75, /* 1101 -> 7.5x */ + 130, /* 1110 -> 13.0x */ + 65, /* 1111 -> 6.5x */ +}; + +/* + * VIA C3 Ezra + */ +static const int __cpuinitdata ezra_mults[16] = { + 100, /* 0000 -> 10.0x */ + 30, /* 0001 -> 3.0x */ + 40, /* 0010 -> 4.0x */ + 90, /* 0011 -> 9.0x */ + 95, /* 0100 -> 9.5x */ + 35, /* 0101 -> 3.5x */ + 45, /* 0110 -> 4.5x */ + 55, /* 0111 -> 5.5x */ + 60, /* 1000 -> 6.0x */ + 70, /* 1001 -> 7.0x */ + 80, /* 1010 -> 8.0x */ + 50, /* 1011 -> 5.0x */ + 65, /* 1100 -> 6.5x */ + 75, /* 1101 -> 7.5x */ + 85, /* 1110 -> 8.5x */ + 120, /* 1111 -> 12.0x */ +}; + +static const int __cpuinitdata ezra_eblcr[16] = { + 50, /* 0000 -> 5.0x */ + 30, /* 0001 -> 3.0x */ + 40, /* 0010 -> 4.0x */ + 100, /* 0011 -> 10.0x */ + 55, /* 0100 -> 5.5x */ + 35, /* 0101 -> 3.5x */ + 45, /* 0110 -> 4.5x */ + 95, /* 0111 -> 9.5x */ + 90, /* 1000 -> 9.0x */ + 70, /* 1001 -> 7.0x */ + 80, /* 1010 -> 8.0x */ + 60, /* 1011 -> 6.0x */ + 120, /* 1100 -> 12.0x */ + 75, /* 1101 -> 7.5x */ + 85, /* 1110 -> 8.5x */ + 65, /* 1111 -> 6.5x */ +}; + +/* + * VIA C3 (Ezra-T) [C5M]. + */ +static const int __cpuinitdata ezrat_mults[32] = { + 100, /* 0000 -> 10.0x */ + 30, /* 0001 -> 3.0x */ + 40, /* 0010 -> 4.0x */ + 90, /* 0011 -> 9.0x */ + 95, /* 0100 -> 9.5x */ + 35, /* 0101 -> 3.5x */ + 45, /* 0110 -> 4.5x */ + 55, /* 0111 -> 5.5x */ + 60, /* 1000 -> 6.0x */ + 70, /* 1001 -> 7.0x */ + 80, /* 1010 -> 8.0x */ + 50, /* 1011 -> 5.0x */ + 65, /* 1100 -> 6.5x */ + 75, /* 1101 -> 7.5x */ + 85, /* 1110 -> 8.5x */ + 120, /* 1111 -> 12.0x */ + + -1, /* 0000 -> RESERVED (10.0x) */ + 110, /* 0001 -> 11.0x */ + -1, /* 0010 -> 12.0x */ + -1, /* 0011 -> RESERVED (9.0x)*/ + 105, /* 0100 -> 10.5x */ + 115, /* 0101 -> 11.5x */ + 125, /* 0110 -> 12.5x */ + 135, /* 0111 -> 13.5x */ + 140, /* 1000 -> 14.0x */ + 150, /* 1001 -> 15.0x */ + 160, /* 1010 -> 16.0x */ + 130, /* 1011 -> 13.0x */ + 145, /* 1100 -> 14.5x */ + 155, /* 1101 -> 15.5x */ + -1, /* 1110 -> RESERVED (13.0x) */ + -1, /* 1111 -> RESERVED (12.0x) */ +}; + +static const int __cpuinitdata ezrat_eblcr[32] = { + 50, /* 0000 -> 5.0x */ + 30, /* 0001 -> 3.0x */ + 40, /* 0010 -> 4.0x */ + 100, /* 0011 -> 10.0x */ + 55, /* 0100 -> 5.5x */ + 35, /* 0101 -> 3.5x */ + 45, /* 0110 -> 4.5x */ + 95, /* 0111 -> 9.5x */ + 90, /* 1000 -> 9.0x */ + 70, /* 1001 -> 7.0x */ + 80, /* 1010 -> 8.0x */ + 60, /* 1011 -> 6.0x */ + 120, /* 1100 -> 12.0x */ + 75, /* 1101 -> 7.5x */ + 85, /* 1110 -> 8.5x */ + 65, /* 1111 -> 6.5x */ + + -1, /* 0000 -> RESERVED (9.0x) */ + 110, /* 0001 -> 11.0x */ + 120, /* 0010 -> 12.0x */ + -1, /* 0011 -> RESERVED (10.0x)*/ + 135, /* 0100 -> 13.5x */ + 115, /* 0101 -> 11.5x */ + 125, /* 0110 -> 12.5x */ + 105, /* 0111 -> 10.5x */ + 130, /* 1000 -> 13.0x */ + 150, /* 1001 -> 15.0x */ + 160, /* 1010 -> 16.0x */ + 140, /* 1011 -> 14.0x */ + -1, /* 1100 -> RESERVED (12.0x) */ + 155, /* 1101 -> 15.5x */ + -1, /* 1110 -> RESERVED (13.0x) */ + 145, /* 1111 -> 14.5x */ +}; + +/* + * VIA C3 Nehemiah */ + +static const int __cpuinitdata nehemiah_mults[32] = { + 100, /* 0000 -> 10.0x */ + -1, /* 0001 -> 16.0x */ + 40, /* 0010 -> 4.0x */ + 90, /* 0011 -> 9.0x */ + 95, /* 0100 -> 9.5x */ + -1, /* 0101 -> RESERVED */ + 45, /* 0110 -> 4.5x */ + 55, /* 0111 -> 5.5x */ + 60, /* 1000 -> 6.0x */ + 70, /* 1001 -> 7.0x */ + 80, /* 1010 -> 8.0x */ + 50, /* 1011 -> 5.0x */ + 65, /* 1100 -> 6.5x */ + 75, /* 1101 -> 7.5x */ + 85, /* 1110 -> 8.5x */ + 120, /* 1111 -> 12.0x */ + -1, /* 0000 -> 10.0x */ + 110, /* 0001 -> 11.0x */ + -1, /* 0010 -> 12.0x */ + -1, /* 0011 -> 9.0x */ + 105, /* 0100 -> 10.5x */ + 115, /* 0101 -> 11.5x */ + 125, /* 0110 -> 12.5x */ + 135, /* 0111 -> 13.5x */ + 140, /* 1000 -> 14.0x */ + 150, /* 1001 -> 15.0x */ + 160, /* 1010 -> 16.0x */ + 130, /* 1011 -> 13.0x */ + 145, /* 1100 -> 14.5x */ + 155, /* 1101 -> 15.5x */ + -1, /* 1110 -> RESERVED (13.0x) */ + -1, /* 1111 -> 12.0x */ +}; + +static const int __cpuinitdata nehemiah_eblcr[32] = { + 50, /* 0000 -> 5.0x */ + 160, /* 0001 -> 16.0x */ + 40, /* 0010 -> 4.0x */ + 100, /* 0011 -> 10.0x */ + 55, /* 0100 -> 5.5x */ + -1, /* 0101 -> RESERVED */ + 45, /* 0110 -> 4.5x */ + 95, /* 0111 -> 9.5x */ + 90, /* 1000 -> 9.0x */ + 70, /* 1001 -> 7.0x */ + 80, /* 1010 -> 8.0x */ + 60, /* 1011 -> 6.0x */ + 120, /* 1100 -> 12.0x */ + 75, /* 1101 -> 7.5x */ + 85, /* 1110 -> 8.5x */ + 65, /* 1111 -> 6.5x */ + 90, /* 0000 -> 9.0x */ + 110, /* 0001 -> 11.0x */ + 120, /* 0010 -> 12.0x */ + 100, /* 0011 -> 10.0x */ + 135, /* 0100 -> 13.5x */ + 115, /* 0101 -> 11.5x */ + 125, /* 0110 -> 12.5x */ + 105, /* 0111 -> 10.5x */ + 130, /* 1000 -> 13.0x */ + 150, /* 1001 -> 15.0x */ + 160, /* 1010 -> 16.0x */ + 140, /* 1011 -> 14.0x */ + 120, /* 1100 -> 12.0x */ + 155, /* 1101 -> 15.5x */ + -1, /* 1110 -> RESERVED (13.0x) */ + 145 /* 1111 -> 14.5x */ +}; + +/* + * Voltage scales. Div/Mod by 1000 to get actual voltage. + * Which scale to use depends on the VRM type in use. + */ + +struct mV_pos { + unsigned short mV; + unsigned short pos; +}; + +static const struct mV_pos __cpuinitdata vrm85_mV[32] = { + {1250, 8}, {1200, 6}, {1150, 4}, {1100, 2}, + {1050, 0}, {1800, 30}, {1750, 28}, {1700, 26}, + {1650, 24}, {1600, 22}, {1550, 20}, {1500, 18}, + {1450, 16}, {1400, 14}, {1350, 12}, {1300, 10}, + {1275, 9}, {1225, 7}, {1175, 5}, {1125, 3}, + {1075, 1}, {1825, 31}, {1775, 29}, {1725, 27}, + {1675, 25}, {1625, 23}, {1575, 21}, {1525, 19}, + {1475, 17}, {1425, 15}, {1375, 13}, {1325, 11} +}; + +static const unsigned char __cpuinitdata mV_vrm85[32] = { + 0x04, 0x14, 0x03, 0x13, 0x02, 0x12, 0x01, 0x11, + 0x00, 0x10, 0x0f, 0x1f, 0x0e, 0x1e, 0x0d, 0x1d, + 0x0c, 0x1c, 0x0b, 0x1b, 0x0a, 0x1a, 0x09, 0x19, + 0x08, 0x18, 0x07, 0x17, 0x06, 0x16, 0x05, 0x15 +}; + +static const struct mV_pos __cpuinitdata mobilevrm_mV[32] = { + {1750, 31}, {1700, 30}, {1650, 29}, {1600, 28}, + {1550, 27}, {1500, 26}, {1450, 25}, {1400, 24}, + {1350, 23}, {1300, 22}, {1250, 21}, {1200, 20}, + {1150, 19}, {1100, 18}, {1050, 17}, {1000, 16}, + {975, 15}, {950, 14}, {925, 13}, {900, 12}, + {875, 11}, {850, 10}, {825, 9}, {800, 8}, + {775, 7}, {750, 6}, {725, 5}, {700, 4}, + {675, 3}, {650, 2}, {625, 1}, {600, 0} +}; + +static const unsigned char __cpuinitdata mV_mobilevrm[32] = { + 0x1f, 0x1e, 0x1d, 0x1c, 0x1b, 0x1a, 0x19, 0x18, + 0x17, 0x16, 0x15, 0x14, 0x13, 0x12, 0x11, 0x10, + 0x0f, 0x0e, 0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x08, + 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00 +}; + diff --git a/drivers/cpufreq/longrun.c b/drivers/cpufreq/longrun.c new file mode 100644 index 0000000..34ea359 --- /dev/null +++ b/drivers/cpufreq/longrun.c @@ -0,0 +1,324 @@ +/* + * (C) 2002 - 2003 Dominik Brodowski + * + * Licensed under the terms of the GNU GPL License version 2. + * + * BIG FAT DISCLAIMER: Work in progress code. Possibly *dangerous* + */ + +#include +#include +#include +#include +#include + +#include +#include + +static struct cpufreq_driver longrun_driver; + +/** + * longrun_{low,high}_freq is needed for the conversion of cpufreq kHz + * values into per cent values. In TMTA microcode, the following is valid: + * performance_pctg = (current_freq - low_freq)/(high_freq - low_freq) + */ +static unsigned int longrun_low_freq, longrun_high_freq; + + +/** + * longrun_get_policy - get the current LongRun policy + * @policy: struct cpufreq_policy where current policy is written into + * + * Reads the current LongRun policy by access to MSR_TMTA_LONGRUN_FLAGS + * and MSR_TMTA_LONGRUN_CTRL + */ +static void __cpuinit longrun_get_policy(struct cpufreq_policy *policy) +{ + u32 msr_lo, msr_hi; + + rdmsr(MSR_TMTA_LONGRUN_FLAGS, msr_lo, msr_hi); + pr_debug("longrun flags are %x - %x\n", msr_lo, msr_hi); + if (msr_lo & 0x01) + policy->policy = CPUFREQ_POLICY_PERFORMANCE; + else + policy->policy = CPUFREQ_POLICY_POWERSAVE; + + rdmsr(MSR_TMTA_LONGRUN_CTRL, msr_lo, msr_hi); + pr_debug("longrun ctrl is %x - %x\n", msr_lo, msr_hi); + msr_lo &= 0x0000007F; + msr_hi &= 0x0000007F; + + if (longrun_high_freq <= longrun_low_freq) { + /* Assume degenerate Longrun table */ + policy->min = policy->max = longrun_high_freq; + } else { + policy->min = longrun_low_freq + msr_lo * + ((longrun_high_freq - longrun_low_freq) / 100); + policy->max = longrun_low_freq + msr_hi * + ((longrun_high_freq - longrun_low_freq) / 100); + } + policy->cpu = 0; +} + + +/** + * longrun_set_policy - sets a new CPUFreq policy + * @policy: new policy + * + * Sets a new CPUFreq policy on LongRun-capable processors. This function + * has to be called with cpufreq_driver locked. + */ +static int longrun_set_policy(struct cpufreq_policy *policy) +{ + u32 msr_lo, msr_hi; + u32 pctg_lo, pctg_hi; + + if (!policy) + return -EINVAL; + + if (longrun_high_freq <= longrun_low_freq) { + /* Assume degenerate Longrun table */ + pctg_lo = pctg_hi = 100; + } else { + pctg_lo = (policy->min - longrun_low_freq) / + ((longrun_high_freq - longrun_low_freq) / 100); + pctg_hi = (policy->max - longrun_low_freq) / + ((longrun_high_freq - longrun_low_freq) / 100); + } + + if (pctg_hi > 100) + pctg_hi = 100; + if (pctg_lo > pctg_hi) + pctg_lo = pctg_hi; + + /* performance or economy mode */ + rdmsr(MSR_TMTA_LONGRUN_FLAGS, msr_lo, msr_hi); + msr_lo &= 0xFFFFFFFE; + switch (policy->policy) { + case CPUFREQ_POLICY_PERFORMANCE: + msr_lo |= 0x00000001; + break; + case CPUFREQ_POLICY_POWERSAVE: + break; + } + wrmsr(MSR_TMTA_LONGRUN_FLAGS, msr_lo, msr_hi); + + /* lower and upper boundary */ + rdmsr(MSR_TMTA_LONGRUN_CTRL, msr_lo, msr_hi); + msr_lo &= 0xFFFFFF80; + msr_hi &= 0xFFFFFF80; + msr_lo |= pctg_lo; + msr_hi |= pctg_hi; + wrmsr(MSR_TMTA_LONGRUN_CTRL, msr_lo, msr_hi); + + return 0; +} + + +/** + * longrun_verify_poliy - verifies a new CPUFreq policy + * @policy: the policy to verify + * + * Validates a new CPUFreq policy. This function has to be called with + * cpufreq_driver locked. + */ +static int longrun_verify_policy(struct cpufreq_policy *policy) +{ + if (!policy) + return -EINVAL; + + policy->cpu = 0; + cpufreq_verify_within_limits(policy, + policy->cpuinfo.min_freq, + policy->cpuinfo.max_freq); + + if ((policy->policy != CPUFREQ_POLICY_POWERSAVE) && + (policy->policy != CPUFREQ_POLICY_PERFORMANCE)) + return -EINVAL; + + return 0; +} + +static unsigned int longrun_get(unsigned int cpu) +{ + u32 eax, ebx, ecx, edx; + + if (cpu) + return 0; + + cpuid(0x80860007, &eax, &ebx, &ecx, &edx); + pr_debug("cpuid eax is %u\n", eax); + + return eax * 1000; +} + +/** + * longrun_determine_freqs - determines the lowest and highest possible core frequency + * @low_freq: an int to put the lowest frequency into + * @high_freq: an int to put the highest frequency into + * + * Determines the lowest and highest possible core frequencies on this CPU. + * This is necessary to calculate the performance percentage according to + * TMTA rules: + * performance_pctg = (target_freq - low_freq)/(high_freq - low_freq) + */ +static int __cpuinit longrun_determine_freqs(unsigned int *low_freq, + unsigned int *high_freq) +{ + u32 msr_lo, msr_hi; + u32 save_lo, save_hi; + u32 eax, ebx, ecx, edx; + u32 try_hi; + struct cpuinfo_x86 *c = &cpu_data(0); + + if (!low_freq || !high_freq) + return -EINVAL; + + if (cpu_has(c, X86_FEATURE_LRTI)) { + /* if the LongRun Table Interface is present, the + * detection is a bit easier: + * For minimum frequency, read out the maximum + * level (msr_hi), write that into "currently + * selected level", and read out the frequency. + * For maximum frequency, read out level zero. + */ + /* minimum */ + rdmsr(MSR_TMTA_LRTI_READOUT, msr_lo, msr_hi); + wrmsr(MSR_TMTA_LRTI_READOUT, msr_hi, msr_hi); + rdmsr(MSR_TMTA_LRTI_VOLT_MHZ, msr_lo, msr_hi); + *low_freq = msr_lo * 1000; /* to kHz */ + + /* maximum */ + wrmsr(MSR_TMTA_LRTI_READOUT, 0, msr_hi); + rdmsr(MSR_TMTA_LRTI_VOLT_MHZ, msr_lo, msr_hi); + *high_freq = msr_lo * 1000; /* to kHz */ + + pr_debug("longrun table interface told %u - %u kHz\n", + *low_freq, *high_freq); + + if (*low_freq > *high_freq) + *low_freq = *high_freq; + return 0; + } + + /* set the upper border to the value determined during TSC init */ + *high_freq = (cpu_khz / 1000); + *high_freq = *high_freq * 1000; + pr_debug("high frequency is %u kHz\n", *high_freq); + + /* get current borders */ + rdmsr(MSR_TMTA_LONGRUN_CTRL, msr_lo, msr_hi); + save_lo = msr_lo & 0x0000007F; + save_hi = msr_hi & 0x0000007F; + + /* if current perf_pctg is larger than 90%, we need to decrease the + * upper limit to make the calculation more accurate. + */ + cpuid(0x80860007, &eax, &ebx, &ecx, &edx); + /* try decreasing in 10% steps, some processors react only + * on some barrier values */ + for (try_hi = 80; try_hi > 0 && ecx > 90; try_hi -= 10) { + /* set to 0 to try_hi perf_pctg */ + msr_lo &= 0xFFFFFF80; + msr_hi &= 0xFFFFFF80; + msr_hi |= try_hi; + wrmsr(MSR_TMTA_LONGRUN_CTRL, msr_lo, msr_hi); + + /* read out current core MHz and current perf_pctg */ + cpuid(0x80860007, &eax, &ebx, &ecx, &edx); + + /* restore values */ + wrmsr(MSR_TMTA_LONGRUN_CTRL, save_lo, save_hi); + } + pr_debug("percentage is %u %%, freq is %u MHz\n", ecx, eax); + + /* performance_pctg = (current_freq - low_freq)/(high_freq - low_freq) + * eqals + * low_freq * (1 - perf_pctg) = (cur_freq - high_freq * perf_pctg) + * + * high_freq * perf_pctg is stored tempoarily into "ebx". + */ + ebx = (((cpu_khz / 1000) * ecx) / 100); /* to MHz */ + + if ((ecx > 95) || (ecx == 0) || (eax < ebx)) + return -EIO; + + edx = ((eax - ebx) * 100) / (100 - ecx); + *low_freq = edx * 1000; /* back to kHz */ + + pr_debug("low frequency is %u kHz\n", *low_freq); + + if (*low_freq > *high_freq) + *low_freq = *high_freq; + + return 0; +} + + +static int __cpuinit longrun_cpu_init(struct cpufreq_policy *policy) +{ + int result = 0; + + /* capability check */ + if (policy->cpu != 0) + return -ENODEV; + + /* detect low and high frequency */ + result = longrun_determine_freqs(&longrun_low_freq, &longrun_high_freq); + if (result) + return result; + + /* cpuinfo and default policy values */ + policy->cpuinfo.min_freq = longrun_low_freq; + policy->cpuinfo.max_freq = longrun_high_freq; + policy->cpuinfo.transition_latency = CPUFREQ_ETERNAL; + longrun_get_policy(policy); + + return 0; +} + + +static struct cpufreq_driver longrun_driver = { + .flags = CPUFREQ_CONST_LOOPS, + .verify = longrun_verify_policy, + .setpolicy = longrun_set_policy, + .get = longrun_get, + .init = longrun_cpu_init, + .name = "longrun", + .owner = THIS_MODULE, +}; + + +/** + * longrun_init - initializes the Transmeta Crusoe LongRun CPUFreq driver + * + * Initializes the LongRun support. + */ +static int __init longrun_init(void) +{ + struct cpuinfo_x86 *c = &cpu_data(0); + + if (c->x86_vendor != X86_VENDOR_TRANSMETA || + !cpu_has(c, X86_FEATURE_LONGRUN)) + return -ENODEV; + + return cpufreq_register_driver(&longrun_driver); +} + + +/** + * longrun_exit - unregisters LongRun support + */ +static void __exit longrun_exit(void) +{ + cpufreq_unregister_driver(&longrun_driver); +} + + +MODULE_AUTHOR("Dominik Brodowski "); +MODULE_DESCRIPTION("LongRun driver for Transmeta Crusoe and " + "Efficeon processors."); +MODULE_LICENSE("GPL"); + +module_init(longrun_init); +module_exit(longrun_exit); diff --git a/drivers/cpufreq/mperf.c b/drivers/cpufreq/mperf.c new file mode 100644 index 0000000..911e193 --- /dev/null +++ b/drivers/cpufreq/mperf.c @@ -0,0 +1,51 @@ +#include +#include +#include +#include +#include +#include + +#include "mperf.h" + +static DEFINE_PER_CPU(struct aperfmperf, acfreq_old_perf); + +/* Called via smp_call_function_single(), on the target CPU */ +static void read_measured_perf_ctrs(void *_cur) +{ + struct aperfmperf *am = _cur; + + get_aperfmperf(am); +} + +/* + * Return the measured active (C0) frequency on this CPU since last call + * to this function. + * Input: cpu number + * Return: Average CPU frequency in terms of max frequency (zero on error) + * + * We use IA32_MPERF and IA32_APERF MSRs to get the measured performance + * over a period of time, while CPU is in C0 state. + * IA32_MPERF counts at the rate of max advertised frequency + * IA32_APERF counts at the rate of actual CPU frequency + * Only IA32_APERF/IA32_MPERF ratio is architecturally defined and + * no meaning should be associated with absolute values of these MSRs. + */ +unsigned int cpufreq_get_measured_perf(struct cpufreq_policy *policy, + unsigned int cpu) +{ + struct aperfmperf perf; + unsigned long ratio; + unsigned int retval; + + if (smp_call_function_single(cpu, read_measured_perf_ctrs, &perf, 1)) + return 0; + + ratio = calc_aperfmperf_ratio(&per_cpu(acfreq_old_perf, cpu), &perf); + per_cpu(acfreq_old_perf, cpu) = perf; + + retval = (policy->cpuinfo.max_freq * ratio) >> APERFMPERF_SHIFT; + + return retval; +} +EXPORT_SYMBOL_GPL(cpufreq_get_measured_perf); +MODULE_LICENSE("GPL"); diff --git a/drivers/cpufreq/mperf.h b/drivers/cpufreq/mperf.h new file mode 100644 index 0000000..5dbf295 --- /dev/null +++ b/drivers/cpufreq/mperf.h @@ -0,0 +1,9 @@ +/* + * (c) 2010 Advanced Micro Devices, Inc. + * Your use of this code is subject to the terms and conditions of the + * GNU general public license version 2. See "COPYING" or + * http://www.gnu.org/licenses/gpl.html + */ + +unsigned int cpufreq_get_measured_perf(struct cpufreq_policy *policy, + unsigned int cpu); diff --git a/drivers/cpufreq/p4-clockmod.c b/drivers/cpufreq/p4-clockmod.c new file mode 100644 index 0000000..6be3e07 --- /dev/null +++ b/drivers/cpufreq/p4-clockmod.c @@ -0,0 +1,329 @@ +/* + * Pentium 4/Xeon CPU on demand clock modulation/speed scaling + * (C) 2002 - 2003 Dominik Brodowski + * (C) 2002 Zwane Mwaikambo + * (C) 2002 Arjan van de Ven + * (C) 2002 Tora T. Engstad + * All Rights Reserved + * + * 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. + * + * The author(s) of this software shall not be held liable for damages + * of any nature resulting due to the use of this software. This + * software is provided AS-IS with no warranties. + * + * Date Errata Description + * 20020525 N44, O17 12.5% or 25% DC causes lockup + * + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "speedstep-lib.h" + +#define PFX "p4-clockmod: " + +/* + * Duty Cycle (3bits), note DC_DISABLE is not specified in + * intel docs i just use it to mean disable + */ +enum { + DC_RESV, DC_DFLT, DC_25PT, DC_38PT, DC_50PT, + DC_64PT, DC_75PT, DC_88PT, DC_DISABLE +}; + +#define DC_ENTRIES 8 + + +static int has_N44_O17_errata[NR_CPUS]; +static unsigned int stock_freq; +static struct cpufreq_driver p4clockmod_driver; +static unsigned int cpufreq_p4_get(unsigned int cpu); + +static int cpufreq_p4_setdc(unsigned int cpu, unsigned int newstate) +{ + u32 l, h; + + if (!cpu_online(cpu) || + (newstate > DC_DISABLE) || (newstate == DC_RESV)) + return -EINVAL; + + rdmsr_on_cpu(cpu, MSR_IA32_THERM_STATUS, &l, &h); + + if (l & 0x01) + pr_debug("CPU#%d currently thermal throttled\n", cpu); + + if (has_N44_O17_errata[cpu] && + (newstate == DC_25PT || newstate == DC_DFLT)) + newstate = DC_38PT; + + rdmsr_on_cpu(cpu, MSR_IA32_THERM_CONTROL, &l, &h); + if (newstate == DC_DISABLE) { + pr_debug("CPU#%d disabling modulation\n", cpu); + wrmsr_on_cpu(cpu, MSR_IA32_THERM_CONTROL, l & ~(1<<4), h); + } else { + pr_debug("CPU#%d setting duty cycle to %d%%\n", + cpu, ((125 * newstate) / 10)); + /* bits 63 - 5 : reserved + * bit 4 : enable/disable + * bits 3-1 : duty cycle + * bit 0 : reserved + */ + l = (l & ~14); + l = l | (1<<4) | ((newstate & 0x7)<<1); + wrmsr_on_cpu(cpu, MSR_IA32_THERM_CONTROL, l, h); + } + + return 0; +} + + +static struct cpufreq_frequency_table p4clockmod_table[] = { + {DC_RESV, CPUFREQ_ENTRY_INVALID}, + {DC_DFLT, 0}, + {DC_25PT, 0}, + {DC_38PT, 0}, + {DC_50PT, 0}, + {DC_64PT, 0}, + {DC_75PT, 0}, + {DC_88PT, 0}, + {DC_DISABLE, 0}, + {DC_RESV, CPUFREQ_TABLE_END}, +}; + + +static int cpufreq_p4_target(struct cpufreq_policy *policy, + unsigned int target_freq, + unsigned int relation) +{ + unsigned int newstate = DC_RESV; + struct cpufreq_freqs freqs; + int i; + + if (cpufreq_frequency_table_target(policy, &p4clockmod_table[0], + target_freq, relation, &newstate)) + return -EINVAL; + + freqs.old = cpufreq_p4_get(policy->cpu); + freqs.new = stock_freq * p4clockmod_table[newstate].index / 8; + + if (freqs.new == freqs.old) + return 0; + + /* notifiers */ + for_each_cpu(i, policy->cpus) { + freqs.cpu = i; + cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE); + } + + /* run on each logical CPU, + * see section 13.15.3 of IA32 Intel Architecture Software + * Developer's Manual, Volume 3 + */ + for_each_cpu(i, policy->cpus) + cpufreq_p4_setdc(i, p4clockmod_table[newstate].index); + + /* notifiers */ + for_each_cpu(i, policy->cpus) { + freqs.cpu = i; + cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE); + } + + return 0; +} + + +static int cpufreq_p4_verify(struct cpufreq_policy *policy) +{ + return cpufreq_frequency_table_verify(policy, &p4clockmod_table[0]); +} + + +static unsigned int cpufreq_p4_get_frequency(struct cpuinfo_x86 *c) +{ + if (c->x86 == 0x06) { + if (cpu_has(c, X86_FEATURE_EST)) + printk_once(KERN_WARNING PFX "Warning: EST-capable " + "CPU detected. The acpi-cpufreq module offers " + "voltage scaling in addition to frequency " + "scaling. You should use that instead of " + "p4-clockmod, if possible.\n"); + switch (c->x86_model) { + case 0x0E: /* Core */ + case 0x0F: /* Core Duo */ + case 0x16: /* Celeron Core */ + case 0x1C: /* Atom */ + p4clockmod_driver.flags |= CPUFREQ_CONST_LOOPS; + return speedstep_get_frequency(SPEEDSTEP_CPU_PCORE); + case 0x0D: /* Pentium M (Dothan) */ + p4clockmod_driver.flags |= CPUFREQ_CONST_LOOPS; + /* fall through */ + case 0x09: /* Pentium M (Banias) */ + return speedstep_get_frequency(SPEEDSTEP_CPU_PM); + } + } + + if (c->x86 != 0xF) + return 0; + + /* on P-4s, the TSC runs with constant frequency independent whether + * throttling is active or not. */ + p4clockmod_driver.flags |= CPUFREQ_CONST_LOOPS; + + if (speedstep_detect_processor() == SPEEDSTEP_CPU_P4M) { + printk(KERN_WARNING PFX "Warning: Pentium 4-M detected. " + "The speedstep-ich or acpi cpufreq modules offer " + "voltage scaling in addition of frequency scaling. " + "You should use either one instead of p4-clockmod, " + "if possible.\n"); + return speedstep_get_frequency(SPEEDSTEP_CPU_P4M); + } + + return speedstep_get_frequency(SPEEDSTEP_CPU_P4D); +} + + + +static int cpufreq_p4_cpu_init(struct cpufreq_policy *policy) +{ + struct cpuinfo_x86 *c = &cpu_data(policy->cpu); + int cpuid = 0; + unsigned int i; + +#ifdef CONFIG_SMP + cpumask_copy(policy->cpus, cpu_sibling_mask(policy->cpu)); +#endif + + /* Errata workaround */ + cpuid = (c->x86 << 8) | (c->x86_model << 4) | c->x86_mask; + switch (cpuid) { + case 0x0f07: + case 0x0f0a: + case 0x0f11: + case 0x0f12: + has_N44_O17_errata[policy->cpu] = 1; + pr_debug("has errata -- disabling low frequencies\n"); + } + + if (speedstep_detect_processor() == SPEEDSTEP_CPU_P4D && + c->x86_model < 2) { + /* switch to maximum frequency and measure result */ + cpufreq_p4_setdc(policy->cpu, DC_DISABLE); + recalibrate_cpu_khz(); + } + /* get max frequency */ + stock_freq = cpufreq_p4_get_frequency(c); + if (!stock_freq) + return -EINVAL; + + /* table init */ + for (i = 1; (p4clockmod_table[i].frequency != CPUFREQ_TABLE_END); i++) { + if ((i < 2) && (has_N44_O17_errata[policy->cpu])) + p4clockmod_table[i].frequency = CPUFREQ_ENTRY_INVALID; + else + p4clockmod_table[i].frequency = (stock_freq * i)/8; + } + cpufreq_frequency_table_get_attr(p4clockmod_table, policy->cpu); + + /* cpuinfo and default policy values */ + + /* the transition latency is set to be 1 higher than the maximum + * transition latency of the ondemand governor */ + policy->cpuinfo.transition_latency = 10000001; + policy->cur = stock_freq; + + return cpufreq_frequency_table_cpuinfo(policy, &p4clockmod_table[0]); +} + + +static int cpufreq_p4_cpu_exit(struct cpufreq_policy *policy) +{ + cpufreq_frequency_table_put_attr(policy->cpu); + return 0; +} + +static unsigned int cpufreq_p4_get(unsigned int cpu) +{ + u32 l, h; + + rdmsr_on_cpu(cpu, MSR_IA32_THERM_CONTROL, &l, &h); + + if (l & 0x10) { + l = l >> 1; + l &= 0x7; + } else + l = DC_DISABLE; + + if (l != DC_DISABLE) + return stock_freq * l / 8; + + return stock_freq; +} + +static struct freq_attr *p4clockmod_attr[] = { + &cpufreq_freq_attr_scaling_available_freqs, + NULL, +}; + +static struct cpufreq_driver p4clockmod_driver = { + .verify = cpufreq_p4_verify, + .target = cpufreq_p4_target, + .init = cpufreq_p4_cpu_init, + .exit = cpufreq_p4_cpu_exit, + .get = cpufreq_p4_get, + .name = "p4-clockmod", + .owner = THIS_MODULE, + .attr = p4clockmod_attr, +}; + + +static int __init cpufreq_p4_init(void) +{ + struct cpuinfo_x86 *c = &cpu_data(0); + int ret; + + /* + * THERM_CONTROL is architectural for IA32 now, so + * we can rely on the capability checks + */ + if (c->x86_vendor != X86_VENDOR_INTEL) + return -ENODEV; + + if (!test_cpu_cap(c, X86_FEATURE_ACPI) || + !test_cpu_cap(c, X86_FEATURE_ACC)) + return -ENODEV; + + ret = cpufreq_register_driver(&p4clockmod_driver); + if (!ret) + printk(KERN_INFO PFX "P4/Xeon(TM) CPU On-Demand Clock " + "Modulation available\n"); + + return ret; +} + + +static void __exit cpufreq_p4_exit(void) +{ + cpufreq_unregister_driver(&p4clockmod_driver); +} + + +MODULE_AUTHOR("Zwane Mwaikambo "); +MODULE_DESCRIPTION("cpufreq driver for Pentium(TM) 4/Xeon(TM)"); +MODULE_LICENSE("GPL"); + +late_initcall(cpufreq_p4_init); +module_exit(cpufreq_p4_exit); diff --git a/drivers/cpufreq/pcc-cpufreq.c b/drivers/cpufreq/pcc-cpufreq.c new file mode 100644 index 0000000..7b0603e --- /dev/null +++ b/drivers/cpufreq/pcc-cpufreq.c @@ -0,0 +1,621 @@ +/* + * pcc-cpufreq.c - Processor Clocking Control firmware cpufreq interface + * + * Copyright (C) 2009 Red Hat, Matthew Garrett + * Copyright (C) 2009 Hewlett-Packard Development Company, L.P. + * Nagananda Chumbalkar + * + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or NON + * INFRINGEMENT. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 675 Mass Ave, Cambridge, MA 02139, USA. + * + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include + +#define PCC_VERSION "1.10.00" +#define POLL_LOOPS 300 + +#define CMD_COMPLETE 0x1 +#define CMD_GET_FREQ 0x0 +#define CMD_SET_FREQ 0x1 + +#define BUF_SZ 4 + +struct pcc_register_resource { + u8 descriptor; + u16 length; + u8 space_id; + u8 bit_width; + u8 bit_offset; + u8 access_size; + u64 address; +} __attribute__ ((packed)); + +struct pcc_memory_resource { + u8 descriptor; + u16 length; + u8 space_id; + u8 resource_usage; + u8 type_specific; + u64 granularity; + u64 minimum; + u64 maximum; + u64 translation_offset; + u64 address_length; +} __attribute__ ((packed)); + +static struct cpufreq_driver pcc_cpufreq_driver; + +struct pcc_header { + u32 signature; + u16 length; + u8 major; + u8 minor; + u32 features; + u16 command; + u16 status; + u32 latency; + u32 minimum_time; + u32 maximum_time; + u32 nominal; + u32 throttled_frequency; + u32 minimum_frequency; +}; + +static void __iomem *pcch_virt_addr; +static struct pcc_header __iomem *pcch_hdr; + +static DEFINE_SPINLOCK(pcc_lock); + +static struct acpi_generic_address doorbell; + +static u64 doorbell_preserve; +static u64 doorbell_write; + +static u8 OSC_UUID[16] = {0x9F, 0x2C, 0x9B, 0x63, 0x91, 0x70, 0x1f, 0x49, + 0xBB, 0x4F, 0xA5, 0x98, 0x2F, 0xA1, 0xB5, 0x46}; + +struct pcc_cpu { + u32 input_offset; + u32 output_offset; +}; + +static struct pcc_cpu __percpu *pcc_cpu_info; + +static int pcc_cpufreq_verify(struct cpufreq_policy *policy) +{ + cpufreq_verify_within_limits(policy, policy->cpuinfo.min_freq, + policy->cpuinfo.max_freq); + return 0; +} + +static inline void pcc_cmd(void) +{ + u64 doorbell_value; + int i; + + acpi_read(&doorbell_value, &doorbell); + acpi_write((doorbell_value & doorbell_preserve) | doorbell_write, + &doorbell); + + for (i = 0; i < POLL_LOOPS; i++) { + if (ioread16(&pcch_hdr->status) & CMD_COMPLETE) + break; + } +} + +static inline void pcc_clear_mapping(void) +{ + if (pcch_virt_addr) + iounmap(pcch_virt_addr); + pcch_virt_addr = NULL; +} + +static unsigned int pcc_get_freq(unsigned int cpu) +{ + struct pcc_cpu *pcc_cpu_data; + unsigned int curr_freq; + unsigned int freq_limit; + u16 status; + u32 input_buffer; + u32 output_buffer; + + spin_lock(&pcc_lock); + + pr_debug("get: get_freq for CPU %d\n", cpu); + pcc_cpu_data = per_cpu_ptr(pcc_cpu_info, cpu); + + input_buffer = 0x1; + iowrite32(input_buffer, + (pcch_virt_addr + pcc_cpu_data->input_offset)); + iowrite16(CMD_GET_FREQ, &pcch_hdr->command); + + pcc_cmd(); + + output_buffer = + ioread32(pcch_virt_addr + pcc_cpu_data->output_offset); + + /* Clear the input buffer - we are done with the current command */ + memset_io((pcch_virt_addr + pcc_cpu_data->input_offset), 0, BUF_SZ); + + status = ioread16(&pcch_hdr->status); + if (status != CMD_COMPLETE) { + pr_debug("get: FAILED: for CPU %d, status is %d\n", + cpu, status); + goto cmd_incomplete; + } + iowrite16(0, &pcch_hdr->status); + curr_freq = (((ioread32(&pcch_hdr->nominal) * (output_buffer & 0xff)) + / 100) * 1000); + + pr_debug("get: SUCCESS: (virtual) output_offset for cpu %d is " + "0x%p, contains a value of: 0x%x. Speed is: %d MHz\n", + cpu, (pcch_virt_addr + pcc_cpu_data->output_offset), + output_buffer, curr_freq); + + freq_limit = (output_buffer >> 8) & 0xff; + if (freq_limit != 0xff) { + pr_debug("get: frequency for cpu %d is being temporarily" + " capped at %d\n", cpu, curr_freq); + } + + spin_unlock(&pcc_lock); + return curr_freq; + +cmd_incomplete: + iowrite16(0, &pcch_hdr->status); + spin_unlock(&pcc_lock); + return 0; +} + +static int pcc_cpufreq_target(struct cpufreq_policy *policy, + unsigned int target_freq, + unsigned int relation) +{ + struct pcc_cpu *pcc_cpu_data; + struct cpufreq_freqs freqs; + u16 status; + u32 input_buffer; + int cpu; + + spin_lock(&pcc_lock); + cpu = policy->cpu; + pcc_cpu_data = per_cpu_ptr(pcc_cpu_info, cpu); + + pr_debug("target: CPU %d should go to target freq: %d " + "(virtual) input_offset is 0x%p\n", + cpu, target_freq, + (pcch_virt_addr + pcc_cpu_data->input_offset)); + + freqs.new = target_freq; + freqs.cpu = cpu; + cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE); + + input_buffer = 0x1 | (((target_freq * 100) + / (ioread32(&pcch_hdr->nominal) * 1000)) << 8); + iowrite32(input_buffer, + (pcch_virt_addr + pcc_cpu_data->input_offset)); + iowrite16(CMD_SET_FREQ, &pcch_hdr->command); + + pcc_cmd(); + + /* Clear the input buffer - we are done with the current command */ + memset_io((pcch_virt_addr + pcc_cpu_data->input_offset), 0, BUF_SZ); + + status = ioread16(&pcch_hdr->status); + if (status != CMD_COMPLETE) { + pr_debug("target: FAILED for cpu %d, with status: 0x%x\n", + cpu, status); + goto cmd_incomplete; + } + iowrite16(0, &pcch_hdr->status); + + cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE); + pr_debug("target: was SUCCESSFUL for cpu %d\n", cpu); + spin_unlock(&pcc_lock); + + return 0; + +cmd_incomplete: + iowrite16(0, &pcch_hdr->status); + spin_unlock(&pcc_lock); + return -EINVAL; +} + +static int pcc_get_offset(int cpu) +{ + acpi_status status; + struct acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER, NULL}; + union acpi_object *pccp, *offset; + struct pcc_cpu *pcc_cpu_data; + struct acpi_processor *pr; + int ret = 0; + + pr = per_cpu(processors, cpu); + pcc_cpu_data = per_cpu_ptr(pcc_cpu_info, cpu); + + status = acpi_evaluate_object(pr->handle, "PCCP", NULL, &buffer); + if (ACPI_FAILURE(status)) + return -ENODEV; + + pccp = buffer.pointer; + if (!pccp || pccp->type != ACPI_TYPE_PACKAGE) { + ret = -ENODEV; + goto out_free; + }; + + offset = &(pccp->package.elements[0]); + if (!offset || offset->type != ACPI_TYPE_INTEGER) { + ret = -ENODEV; + goto out_free; + } + + pcc_cpu_data->input_offset = offset->integer.value; + + offset = &(pccp->package.elements[1]); + if (!offset || offset->type != ACPI_TYPE_INTEGER) { + ret = -ENODEV; + goto out_free; + } + + pcc_cpu_data->output_offset = offset->integer.value; + + memset_io((pcch_virt_addr + pcc_cpu_data->input_offset), 0, BUF_SZ); + memset_io((pcch_virt_addr + pcc_cpu_data->output_offset), 0, BUF_SZ); + + pr_debug("pcc_get_offset: for CPU %d: pcc_cpu_data " + "input_offset: 0x%x, pcc_cpu_data output_offset: 0x%x\n", + cpu, pcc_cpu_data->input_offset, pcc_cpu_data->output_offset); +out_free: + kfree(buffer.pointer); + return ret; +} + +static int __init pcc_cpufreq_do_osc(acpi_handle *handle) +{ + acpi_status status; + struct acpi_object_list input; + struct acpi_buffer output = {ACPI_ALLOCATE_BUFFER, NULL}; + union acpi_object in_params[4]; + union acpi_object *out_obj; + u32 capabilities[2]; + u32 errors; + u32 supported; + int ret = 0; + + input.count = 4; + input.pointer = in_params; + in_params[0].type = ACPI_TYPE_BUFFER; + in_params[0].buffer.length = 16; + in_params[0].buffer.pointer = OSC_UUID; + in_params[1].type = ACPI_TYPE_INTEGER; + in_params[1].integer.value = 1; + in_params[2].type = ACPI_TYPE_INTEGER; + in_params[2].integer.value = 2; + in_params[3].type = ACPI_TYPE_BUFFER; + in_params[3].buffer.length = 8; + in_params[3].buffer.pointer = (u8 *)&capabilities; + + capabilities[0] = OSC_QUERY_ENABLE; + capabilities[1] = 0x1; + + status = acpi_evaluate_object(*handle, "_OSC", &input, &output); + if (ACPI_FAILURE(status)) + return -ENODEV; + + if (!output.length) + return -ENODEV; + + out_obj = output.pointer; + if (out_obj->type != ACPI_TYPE_BUFFER) { + ret = -ENODEV; + goto out_free; + } + + errors = *((u32 *)out_obj->buffer.pointer) & ~(1 << 0); + if (errors) { + ret = -ENODEV; + goto out_free; + } + + supported = *((u32 *)(out_obj->buffer.pointer + 4)); + if (!(supported & 0x1)) { + ret = -ENODEV; + goto out_free; + } + + kfree(output.pointer); + capabilities[0] = 0x0; + capabilities[1] = 0x1; + + status = acpi_evaluate_object(*handle, "_OSC", &input, &output); + if (ACPI_FAILURE(status)) + return -ENODEV; + + if (!output.length) + return -ENODEV; + + out_obj = output.pointer; + if (out_obj->type != ACPI_TYPE_BUFFER) { + ret = -ENODEV; + goto out_free; + } + + errors = *((u32 *)out_obj->buffer.pointer) & ~(1 << 0); + if (errors) { + ret = -ENODEV; + goto out_free; + } + + supported = *((u32 *)(out_obj->buffer.pointer + 4)); + if (!(supported & 0x1)) { + ret = -ENODEV; + goto out_free; + } + +out_free: + kfree(output.pointer); + return ret; +} + +static int __init pcc_cpufreq_probe(void) +{ + acpi_status status; + struct acpi_buffer output = {ACPI_ALLOCATE_BUFFER, NULL}; + struct pcc_memory_resource *mem_resource; + struct pcc_register_resource *reg_resource; + union acpi_object *out_obj, *member; + acpi_handle handle, osc_handle, pcch_handle; + int ret = 0; + + status = acpi_get_handle(NULL, "\\_SB", &handle); + if (ACPI_FAILURE(status)) + return -ENODEV; + + status = acpi_get_handle(handle, "PCCH", &pcch_handle); + if (ACPI_FAILURE(status)) + return -ENODEV; + + status = acpi_get_handle(handle, "_OSC", &osc_handle); + if (ACPI_SUCCESS(status)) { + ret = pcc_cpufreq_do_osc(&osc_handle); + if (ret) + pr_debug("probe: _OSC evaluation did not succeed\n"); + /* Firmware's use of _OSC is optional */ + ret = 0; + } + + status = acpi_evaluate_object(handle, "PCCH", NULL, &output); + if (ACPI_FAILURE(status)) + return -ENODEV; + + out_obj = output.pointer; + if (out_obj->type != ACPI_TYPE_PACKAGE) { + ret = -ENODEV; + goto out_free; + } + + member = &out_obj->package.elements[0]; + if (member->type != ACPI_TYPE_BUFFER) { + ret = -ENODEV; + goto out_free; + } + + mem_resource = (struct pcc_memory_resource *)member->buffer.pointer; + + pr_debug("probe: mem_resource descriptor: 0x%x," + " length: %d, space_id: %d, resource_usage: %d," + " type_specific: %d, granularity: 0x%llx," + " minimum: 0x%llx, maximum: 0x%llx," + " translation_offset: 0x%llx, address_length: 0x%llx\n", + mem_resource->descriptor, mem_resource->length, + mem_resource->space_id, mem_resource->resource_usage, + mem_resource->type_specific, mem_resource->granularity, + mem_resource->minimum, mem_resource->maximum, + mem_resource->translation_offset, + mem_resource->address_length); + + if (mem_resource->space_id != ACPI_ADR_SPACE_SYSTEM_MEMORY) { + ret = -ENODEV; + goto out_free; + } + + pcch_virt_addr = ioremap_nocache(mem_resource->minimum, + mem_resource->address_length); + if (pcch_virt_addr == NULL) { + pr_debug("probe: could not map shared mem region\n"); + goto out_free; + } + pcch_hdr = pcch_virt_addr; + + pr_debug("probe: PCCH header (virtual) addr: 0x%p\n", pcch_hdr); + pr_debug("probe: PCCH header is at physical address: 0x%llx," + " signature: 0x%x, length: %d bytes, major: %d, minor: %d," + " supported features: 0x%x, command field: 0x%x," + " status field: 0x%x, nominal latency: %d us\n", + mem_resource->minimum, ioread32(&pcch_hdr->signature), + ioread16(&pcch_hdr->length), ioread8(&pcch_hdr->major), + ioread8(&pcch_hdr->minor), ioread32(&pcch_hdr->features), + ioread16(&pcch_hdr->command), ioread16(&pcch_hdr->status), + ioread32(&pcch_hdr->latency)); + + pr_debug("probe: min time between commands: %d us," + " max time between commands: %d us," + " nominal CPU frequency: %d MHz," + " minimum CPU frequency: %d MHz," + " minimum CPU frequency without throttling: %d MHz\n", + ioread32(&pcch_hdr->minimum_time), + ioread32(&pcch_hdr->maximum_time), + ioread32(&pcch_hdr->nominal), + ioread32(&pcch_hdr->throttled_frequency), + ioread32(&pcch_hdr->minimum_frequency)); + + member = &out_obj->package.elements[1]; + if (member->type != ACPI_TYPE_BUFFER) { + ret = -ENODEV; + goto pcch_free; + } + + reg_resource = (struct pcc_register_resource *)member->buffer.pointer; + + doorbell.space_id = reg_resource->space_id; + doorbell.bit_width = reg_resource->bit_width; + doorbell.bit_offset = reg_resource->bit_offset; + doorbell.access_width = 64; + doorbell.address = reg_resource->address; + + pr_debug("probe: doorbell: space_id is %d, bit_width is %d, " + "bit_offset is %d, access_width is %d, address is 0x%llx\n", + doorbell.space_id, doorbell.bit_width, doorbell.bit_offset, + doorbell.access_width, reg_resource->address); + + member = &out_obj->package.elements[2]; + if (member->type != ACPI_TYPE_INTEGER) { + ret = -ENODEV; + goto pcch_free; + } + + doorbell_preserve = member->integer.value; + + member = &out_obj->package.elements[3]; + if (member->type != ACPI_TYPE_INTEGER) { + ret = -ENODEV; + goto pcch_free; + } + + doorbell_write = member->integer.value; + + pr_debug("probe: doorbell_preserve: 0x%llx," + " doorbell_write: 0x%llx\n", + doorbell_preserve, doorbell_write); + + pcc_cpu_info = alloc_percpu(struct pcc_cpu); + if (!pcc_cpu_info) { + ret = -ENOMEM; + goto pcch_free; + } + + printk(KERN_DEBUG "pcc-cpufreq: (v%s) driver loaded with frequency" + " limits: %d MHz, %d MHz\n", PCC_VERSION, + ioread32(&pcch_hdr->minimum_frequency), + ioread32(&pcch_hdr->nominal)); + kfree(output.pointer); + return ret; +pcch_free: + pcc_clear_mapping(); +out_free: + kfree(output.pointer); + return ret; +} + +static int pcc_cpufreq_cpu_init(struct cpufreq_policy *policy) +{ + unsigned int cpu = policy->cpu; + unsigned int result = 0; + + if (!pcch_virt_addr) { + result = -1; + goto out; + } + + result = pcc_get_offset(cpu); + if (result) { + pr_debug("init: PCCP evaluation failed\n"); + goto out; + } + + policy->max = policy->cpuinfo.max_freq = + ioread32(&pcch_hdr->nominal) * 1000; + policy->min = policy->cpuinfo.min_freq = + ioread32(&pcch_hdr->minimum_frequency) * 1000; + policy->cur = pcc_get_freq(cpu); + + if (!policy->cur) { + pr_debug("init: Unable to get current CPU frequency\n"); + result = -EINVAL; + goto out; + } + + pr_debug("init: policy->max is %d, policy->min is %d\n", + policy->max, policy->min); +out: + return result; +} + +static int pcc_cpufreq_cpu_exit(struct cpufreq_policy *policy) +{ + return 0; +} + +static struct cpufreq_driver pcc_cpufreq_driver = { + .flags = CPUFREQ_CONST_LOOPS, + .get = pcc_get_freq, + .verify = pcc_cpufreq_verify, + .target = pcc_cpufreq_target, + .init = pcc_cpufreq_cpu_init, + .exit = pcc_cpufreq_cpu_exit, + .name = "pcc-cpufreq", + .owner = THIS_MODULE, +}; + +static int __init pcc_cpufreq_init(void) +{ + int ret; + + if (acpi_disabled) + return 0; + + ret = pcc_cpufreq_probe(); + if (ret) { + pr_debug("pcc_cpufreq_init: PCCH evaluation failed\n"); + return ret; + } + + ret = cpufreq_register_driver(&pcc_cpufreq_driver); + + return ret; +} + +static void __exit pcc_cpufreq_exit(void) +{ + cpufreq_unregister_driver(&pcc_cpufreq_driver); + + pcc_clear_mapping(); + + free_percpu(pcc_cpu_info); +} + +MODULE_AUTHOR("Matthew Garrett, Naga Chumbalkar"); +MODULE_VERSION(PCC_VERSION); +MODULE_DESCRIPTION("Processor Clocking Control interface driver"); +MODULE_LICENSE("GPL"); + +late_initcall(pcc_cpufreq_init); +module_exit(pcc_cpufreq_exit); diff --git a/drivers/cpufreq/powernow-k6.c b/drivers/cpufreq/powernow-k6.c new file mode 100644 index 0000000..b3379d6 --- /dev/null +++ b/drivers/cpufreq/powernow-k6.c @@ -0,0 +1,261 @@ +/* + * This file was based upon code in Powertweak Linux (http://powertweak.sf.net) + * (C) 2000-2003 Dave Jones, Arjan van de Ven, Janne Pänkälä, + * Dominik Brodowski. + * + * Licensed under the terms of the GNU GPL License version 2. + * + * BIG FAT DISCLAIMER: Work in progress code. Possibly *dangerous* + */ + +#include +#include +#include +#include +#include +#include +#include + +#include + +#define POWERNOW_IOPORT 0xfff0 /* it doesn't matter where, as long + as it is unused */ + +#define PFX "powernow-k6: " +static unsigned int busfreq; /* FSB, in 10 kHz */ +static unsigned int max_multiplier; + + +/* Clock ratio multiplied by 10 - see table 27 in AMD#23446 */ +static struct cpufreq_frequency_table clock_ratio[] = { + {45, /* 000 -> 4.5x */ 0}, + {50, /* 001 -> 5.0x */ 0}, + {40, /* 010 -> 4.0x */ 0}, + {55, /* 011 -> 5.5x */ 0}, + {20, /* 100 -> 2.0x */ 0}, + {30, /* 101 -> 3.0x */ 0}, + {60, /* 110 -> 6.0x */ 0}, + {35, /* 111 -> 3.5x */ 0}, + {0, CPUFREQ_TABLE_END} +}; + + +/** + * powernow_k6_get_cpu_multiplier - returns the current FSB multiplier + * + * Returns the current setting of the frequency multiplier. Core clock + * speed is frequency of the Front-Side Bus multiplied with this value. + */ +static int powernow_k6_get_cpu_multiplier(void) +{ + u64 invalue = 0; + u32 msrval; + + msrval = POWERNOW_IOPORT + 0x1; + wrmsr(MSR_K6_EPMR, msrval, 0); /* enable the PowerNow port */ + invalue = inl(POWERNOW_IOPORT + 0x8); + msrval = POWERNOW_IOPORT + 0x0; + wrmsr(MSR_K6_EPMR, msrval, 0); /* disable it again */ + + return clock_ratio[(invalue >> 5)&7].index; +} + + +/** + * powernow_k6_set_state - set the PowerNow! multiplier + * @best_i: clock_ratio[best_i] is the target multiplier + * + * Tries to change the PowerNow! multiplier + */ +static void powernow_k6_set_state(unsigned int best_i) +{ + unsigned long outvalue = 0, invalue = 0; + unsigned long msrval; + struct cpufreq_freqs freqs; + + if (clock_ratio[best_i].index > max_multiplier) { + printk(KERN_ERR PFX "invalid target frequency\n"); + return; + } + + freqs.old = busfreq * powernow_k6_get_cpu_multiplier(); + freqs.new = busfreq * clock_ratio[best_i].index; + freqs.cpu = 0; /* powernow-k6.c is UP only driver */ + + cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE); + + /* we now need to transform best_i to the BVC format, see AMD#23446 */ + + outvalue = (1<<12) | (1<<10) | (1<<9) | (best_i<<5); + + msrval = POWERNOW_IOPORT + 0x1; + wrmsr(MSR_K6_EPMR, msrval, 0); /* enable the PowerNow port */ + invalue = inl(POWERNOW_IOPORT + 0x8); + invalue = invalue & 0xf; + outvalue = outvalue | invalue; + outl(outvalue , (POWERNOW_IOPORT + 0x8)); + msrval = POWERNOW_IOPORT + 0x0; + wrmsr(MSR_K6_EPMR, msrval, 0); /* disable it again */ + + cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE); + + return; +} + + +/** + * powernow_k6_verify - verifies a new CPUfreq policy + * @policy: new policy + * + * Policy must be within lowest and highest possible CPU Frequency, + * and at least one possible state must be within min and max. + */ +static int powernow_k6_verify(struct cpufreq_policy *policy) +{ + return cpufreq_frequency_table_verify(policy, &clock_ratio[0]); +} + + +/** + * powernow_k6_setpolicy - sets a new CPUFreq policy + * @policy: new policy + * @target_freq: the target frequency + * @relation: how that frequency relates to achieved frequency + * (CPUFREQ_RELATION_L or CPUFREQ_RELATION_H) + * + * sets a new CPUFreq policy + */ +static int powernow_k6_target(struct cpufreq_policy *policy, + unsigned int target_freq, + unsigned int relation) +{ + unsigned int newstate = 0; + + if (cpufreq_frequency_table_target(policy, &clock_ratio[0], + target_freq, relation, &newstate)) + return -EINVAL; + + powernow_k6_set_state(newstate); + + return 0; +} + + +static int powernow_k6_cpu_init(struct cpufreq_policy *policy) +{ + unsigned int i, f; + int result; + + if (policy->cpu != 0) + return -ENODEV; + + /* get frequencies */ + max_multiplier = powernow_k6_get_cpu_multiplier(); + busfreq = cpu_khz / max_multiplier; + + /* table init */ + for (i = 0; (clock_ratio[i].frequency != CPUFREQ_TABLE_END); i++) { + f = clock_ratio[i].index; + if (f > max_multiplier) + clock_ratio[i].frequency = CPUFREQ_ENTRY_INVALID; + else + clock_ratio[i].frequency = busfreq * f; + } + + /* cpuinfo and default policy values */ + policy->cpuinfo.transition_latency = 200000; + policy->cur = busfreq * max_multiplier; + + result = cpufreq_frequency_table_cpuinfo(policy, clock_ratio); + if (result) + return result; + + cpufreq_frequency_table_get_attr(clock_ratio, policy->cpu); + + return 0; +} + + +static int powernow_k6_cpu_exit(struct cpufreq_policy *policy) +{ + unsigned int i; + for (i = 0; i < 8; i++) { + if (i == max_multiplier) + powernow_k6_set_state(i); + } + cpufreq_frequency_table_put_attr(policy->cpu); + return 0; +} + +static unsigned int powernow_k6_get(unsigned int cpu) +{ + unsigned int ret; + ret = (busfreq * powernow_k6_get_cpu_multiplier()); + return ret; +} + +static struct freq_attr *powernow_k6_attr[] = { + &cpufreq_freq_attr_scaling_available_freqs, + NULL, +}; + +static struct cpufreq_driver powernow_k6_driver = { + .verify = powernow_k6_verify, + .target = powernow_k6_target, + .init = powernow_k6_cpu_init, + .exit = powernow_k6_cpu_exit, + .get = powernow_k6_get, + .name = "powernow-k6", + .owner = THIS_MODULE, + .attr = powernow_k6_attr, +}; + + +/** + * powernow_k6_init - initializes the k6 PowerNow! CPUFreq driver + * + * Initializes the K6 PowerNow! support. Returns -ENODEV on unsupported + * devices, -EINVAL or -ENOMEM on problems during initiatization, and zero + * on success. + */ +static int __init powernow_k6_init(void) +{ + struct cpuinfo_x86 *c = &cpu_data(0); + + if ((c->x86_vendor != X86_VENDOR_AMD) || (c->x86 != 5) || + ((c->x86_model != 12) && (c->x86_model != 13))) + return -ENODEV; + + if (!request_region(POWERNOW_IOPORT, 16, "PowerNow!")) { + printk(KERN_INFO PFX "PowerNow IOPORT region already used.\n"); + return -EIO; + } + + if (cpufreq_register_driver(&powernow_k6_driver)) { + release_region(POWERNOW_IOPORT, 16); + return -EINVAL; + } + + return 0; +} + + +/** + * powernow_k6_exit - unregisters AMD K6-2+/3+ PowerNow! support + * + * Unregisters AMD K6-2+ / K6-3+ PowerNow! support. + */ +static void __exit powernow_k6_exit(void) +{ + cpufreq_unregister_driver(&powernow_k6_driver); + release_region(POWERNOW_IOPORT, 16); +} + + +MODULE_AUTHOR("Arjan van de Ven, Dave Jones , " + "Dominik Brodowski "); +MODULE_DESCRIPTION("PowerNow! driver for AMD K6-2+ / K6-3+ processors."); +MODULE_LICENSE("GPL"); + +module_init(powernow_k6_init); +module_exit(powernow_k6_exit); diff --git a/drivers/cpufreq/powernow-k7.c b/drivers/cpufreq/powernow-k7.c new file mode 100644 index 0000000..d71d9f3 --- /dev/null +++ b/drivers/cpufreq/powernow-k7.c @@ -0,0 +1,747 @@ +/* + * AMD K7 Powernow driver. + * (C) 2003 Dave Jones on behalf of SuSE Labs. + * (C) 2003-2004 Dave Jones + * + * Licensed under the terms of the GNU GPL License version 2. + * Based upon datasheets & sample CPUs kindly provided by AMD. + * + * Errata 5: + * CPU may fail to execute a FID/VID change in presence of interrupt. + * - We cli/sti on stepping A0 CPUs around the FID/VID transition. + * Errata 15: + * CPU with half frequency multipliers may hang upon wakeup from disconnect. + * - We disable half multipliers if ACPI is used on A0 stepping CPUs. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include /* Needed for recalibrate_cpu_khz() */ +#include +#include + +#ifdef CONFIG_X86_POWERNOW_K7_ACPI +#include +#include +#endif + +#include "powernow-k7.h" + +#define PFX "powernow: " + + +struct psb_s { + u8 signature[10]; + u8 tableversion; + u8 flags; + u16 settlingtime; + u8 reserved1; + u8 numpst; +}; + +struct pst_s { + u32 cpuid; + u8 fsbspeed; + u8 maxfid; + u8 startvid; + u8 numpstates; +}; + +#ifdef CONFIG_X86_POWERNOW_K7_ACPI +union powernow_acpi_control_t { + struct { + unsigned long fid:5, + vid:5, + sgtc:20, + res1:2; + } bits; + unsigned long val; +}; +#endif + +/* divide by 1000 to get VCore voltage in V. */ +static const int mobile_vid_table[32] = { + 2000, 1950, 1900, 1850, 1800, 1750, 1700, 1650, + 1600, 1550, 1500, 1450, 1400, 1350, 1300, 0, + 1275, 1250, 1225, 1200, 1175, 1150, 1125, 1100, + 1075, 1050, 1025, 1000, 975, 950, 925, 0, +}; + +/* divide by 10 to get FID. */ +static const int fid_codes[32] = { + 110, 115, 120, 125, 50, 55, 60, 65, + 70, 75, 80, 85, 90, 95, 100, 105, + 30, 190, 40, 200, 130, 135, 140, 210, + 150, 225, 160, 165, 170, 180, -1, -1, +}; + +/* This parameter is used in order to force ACPI instead of legacy method for + * configuration purpose. + */ + +static int acpi_force; + +static struct cpufreq_frequency_table *powernow_table; + +static unsigned int can_scale_bus; +static unsigned int can_scale_vid; +static unsigned int minimum_speed = -1; +static unsigned int maximum_speed; +static unsigned int number_scales; +static unsigned int fsb; +static unsigned int latency; +static char have_a0; + +static int check_fsb(unsigned int fsbspeed) +{ + int delta; + unsigned int f = fsb / 1000; + + delta = (fsbspeed > f) ? fsbspeed - f : f - fsbspeed; + return delta < 5; +} + +static int check_powernow(void) +{ + struct cpuinfo_x86 *c = &cpu_data(0); + unsigned int maxei, eax, ebx, ecx, edx; + + if ((c->x86_vendor != X86_VENDOR_AMD) || (c->x86 != 6)) { +#ifdef MODULE + printk(KERN_INFO PFX "This module only works with " + "AMD K7 CPUs\n"); +#endif + return 0; + } + + /* Get maximum capabilities */ + maxei = cpuid_eax(0x80000000); + if (maxei < 0x80000007) { /* Any powernow info ? */ +#ifdef MODULE + printk(KERN_INFO PFX "No powernow capabilities detected\n"); +#endif + return 0; + } + + if ((c->x86_model == 6) && (c->x86_mask == 0)) { + printk(KERN_INFO PFX "K7 660[A0] core detected, " + "enabling errata workarounds\n"); + have_a0 = 1; + } + + cpuid(0x80000007, &eax, &ebx, &ecx, &edx); + + /* Check we can actually do something before we say anything.*/ + if (!(edx & (1 << 1 | 1 << 2))) + return 0; + + printk(KERN_INFO PFX "PowerNOW! Technology present. Can scale: "); + + if (edx & 1 << 1) { + printk("frequency"); + can_scale_bus = 1; + } + + if ((edx & (1 << 1 | 1 << 2)) == 0x6) + printk(" and "); + + if (edx & 1 << 2) { + printk("voltage"); + can_scale_vid = 1; + } + + printk(".\n"); + return 1; +} + +#ifdef CONFIG_X86_POWERNOW_K7_ACPI +static void invalidate_entry(unsigned int entry) +{ + powernow_table[entry].frequency = CPUFREQ_ENTRY_INVALID; +} +#endif + +static int get_ranges(unsigned char *pst) +{ + unsigned int j; + unsigned int speed; + u8 fid, vid; + + powernow_table = kzalloc((sizeof(struct cpufreq_frequency_table) * + (number_scales + 1)), GFP_KERNEL); + if (!powernow_table) + return -ENOMEM; + + for (j = 0 ; j < number_scales; j++) { + fid = *pst++; + + powernow_table[j].frequency = (fsb * fid_codes[fid]) / 10; + powernow_table[j].index = fid; /* lower 8 bits */ + + speed = powernow_table[j].frequency; + + if ((fid_codes[fid] % 10) == 5) { +#ifdef CONFIG_X86_POWERNOW_K7_ACPI + if (have_a0 == 1) + invalidate_entry(j); +#endif + } + + if (speed < minimum_speed) + minimum_speed = speed; + if (speed > maximum_speed) + maximum_speed = speed; + + vid = *pst++; + powernow_table[j].index |= (vid << 8); /* upper 8 bits */ + + pr_debug(" FID: 0x%x (%d.%dx [%dMHz]) " + "VID: 0x%x (%d.%03dV)\n", fid, fid_codes[fid] / 10, + fid_codes[fid] % 10, speed/1000, vid, + mobile_vid_table[vid]/1000, + mobile_vid_table[vid]%1000); + } + powernow_table[number_scales].frequency = CPUFREQ_TABLE_END; + powernow_table[number_scales].index = 0; + + return 0; +} + + +static void change_FID(int fid) +{ + union msr_fidvidctl fidvidctl; + + rdmsrl(MSR_K7_FID_VID_CTL, fidvidctl.val); + if (fidvidctl.bits.FID != fid) { + fidvidctl.bits.SGTC = latency; + fidvidctl.bits.FID = fid; + fidvidctl.bits.VIDC = 0; + fidvidctl.bits.FIDC = 1; + wrmsrl(MSR_K7_FID_VID_CTL, fidvidctl.val); + } +} + + +static void change_VID(int vid) +{ + union msr_fidvidctl fidvidctl; + + rdmsrl(MSR_K7_FID_VID_CTL, fidvidctl.val); + if (fidvidctl.bits.VID != vid) { + fidvidctl.bits.SGTC = latency; + fidvidctl.bits.VID = vid; + fidvidctl.bits.FIDC = 0; + fidvidctl.bits.VIDC = 1; + wrmsrl(MSR_K7_FID_VID_CTL, fidvidctl.val); + } +} + + +static void change_speed(unsigned int index) +{ + u8 fid, vid; + struct cpufreq_freqs freqs; + union msr_fidvidstatus fidvidstatus; + int cfid; + + /* fid are the lower 8 bits of the index we stored into + * the cpufreq frequency table in powernow_decode_bios, + * vid are the upper 8 bits. + */ + + fid = powernow_table[index].index & 0xFF; + vid = (powernow_table[index].index & 0xFF00) >> 8; + + freqs.cpu = 0; + + rdmsrl(MSR_K7_FID_VID_STATUS, fidvidstatus.val); + cfid = fidvidstatus.bits.CFID; + freqs.old = fsb * fid_codes[cfid] / 10; + + freqs.new = powernow_table[index].frequency; + + cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE); + + /* Now do the magic poking into the MSRs. */ + + if (have_a0 == 1) /* A0 errata 5 */ + local_irq_disable(); + + if (freqs.old > freqs.new) { + /* Going down, so change FID first */ + change_FID(fid); + change_VID(vid); + } else { + /* Going up, so change VID first */ + change_VID(vid); + change_FID(fid); + } + + + if (have_a0 == 1) + local_irq_enable(); + + cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE); +} + + +#ifdef CONFIG_X86_POWERNOW_K7_ACPI + +static struct acpi_processor_performance *acpi_processor_perf; + +static int powernow_acpi_init(void) +{ + int i; + int retval = 0; + union powernow_acpi_control_t pc; + + if (acpi_processor_perf != NULL && powernow_table != NULL) { + retval = -EINVAL; + goto err0; + } + + acpi_processor_perf = kzalloc(sizeof(struct acpi_processor_performance), + GFP_KERNEL); + if (!acpi_processor_perf) { + retval = -ENOMEM; + goto err0; + } + + if (!zalloc_cpumask_var(&acpi_processor_perf->shared_cpu_map, + GFP_KERNEL)) { + retval = -ENOMEM; + goto err05; + } + + if (acpi_processor_register_performance(acpi_processor_perf, 0)) { + retval = -EIO; + goto err1; + } + + if (acpi_processor_perf->control_register.space_id != + ACPI_ADR_SPACE_FIXED_HARDWARE) { + retval = -ENODEV; + goto err2; + } + + if (acpi_processor_perf->status_register.space_id != + ACPI_ADR_SPACE_FIXED_HARDWARE) { + retval = -ENODEV; + goto err2; + } + + number_scales = acpi_processor_perf->state_count; + + if (number_scales < 2) { + retval = -ENODEV; + goto err2; + } + + powernow_table = kzalloc((sizeof(struct cpufreq_frequency_table) * + (number_scales + 1)), GFP_KERNEL); + if (!powernow_table) { + retval = -ENOMEM; + goto err2; + } + + pc.val = (unsigned long) acpi_processor_perf->states[0].control; + for (i = 0; i < number_scales; i++) { + u8 fid, vid; + struct acpi_processor_px *state = + &acpi_processor_perf->states[i]; + unsigned int speed, speed_mhz; + + pc.val = (unsigned long) state->control; + pr_debug("acpi: P%d: %d MHz %d mW %d uS control %08x SGTC %d\n", + i, + (u32) state->core_frequency, + (u32) state->power, + (u32) state->transition_latency, + (u32) state->control, + pc.bits.sgtc); + + vid = pc.bits.vid; + fid = pc.bits.fid; + + powernow_table[i].frequency = fsb * fid_codes[fid] / 10; + powernow_table[i].index = fid; /* lower 8 bits */ + powernow_table[i].index |= (vid << 8); /* upper 8 bits */ + + speed = powernow_table[i].frequency; + speed_mhz = speed / 1000; + + /* processor_perflib will multiply the MHz value by 1000 to + * get a KHz value (e.g. 1266000). However, powernow-k7 works + * with true KHz values (e.g. 1266768). To ensure that all + * powernow frequencies are available, we must ensure that + * ACPI doesn't restrict them, so we round up the MHz value + * to ensure that perflib's computed KHz value is greater than + * or equal to powernow's KHz value. + */ + if (speed % 1000 > 0) + speed_mhz++; + + if ((fid_codes[fid] % 10) == 5) { + if (have_a0 == 1) + invalidate_entry(i); + } + + pr_debug(" FID: 0x%x (%d.%dx [%dMHz]) " + "VID: 0x%x (%d.%03dV)\n", fid, fid_codes[fid] / 10, + fid_codes[fid] % 10, speed_mhz, vid, + mobile_vid_table[vid]/1000, + mobile_vid_table[vid]%1000); + + if (state->core_frequency != speed_mhz) { + state->core_frequency = speed_mhz; + pr_debug(" Corrected ACPI frequency to %d\n", + speed_mhz); + } + + if (latency < pc.bits.sgtc) + latency = pc.bits.sgtc; + + if (speed < minimum_speed) + minimum_speed = speed; + if (speed > maximum_speed) + maximum_speed = speed; + } + + powernow_table[i].frequency = CPUFREQ_TABLE_END; + powernow_table[i].index = 0; + + /* notify BIOS that we exist */ + acpi_processor_notify_smm(THIS_MODULE); + + return 0; + +err2: + acpi_processor_unregister_performance(acpi_processor_perf, 0); +err1: + free_cpumask_var(acpi_processor_perf->shared_cpu_map); +err05: + kfree(acpi_processor_perf); +err0: + printk(KERN_WARNING PFX "ACPI perflib can not be used on " + "this platform\n"); + acpi_processor_perf = NULL; + return retval; +} +#else +static int powernow_acpi_init(void) +{ + printk(KERN_INFO PFX "no support for ACPI processor found." + " Please recompile your kernel with ACPI processor\n"); + return -EINVAL; +} +#endif + +static void print_pst_entry(struct pst_s *pst, unsigned int j) +{ + pr_debug("PST:%d (@%p)\n", j, pst); + pr_debug(" cpuid: 0x%x fsb: %d maxFID: 0x%x startvid: 0x%x\n", + pst->cpuid, pst->fsbspeed, pst->maxfid, pst->startvid); +} + +static int powernow_decode_bios(int maxfid, int startvid) +{ + struct psb_s *psb; + struct pst_s *pst; + unsigned int i, j; + unsigned char *p; + unsigned int etuple; + unsigned int ret; + + etuple = cpuid_eax(0x80000001); + + for (i = 0xC0000; i < 0xffff0 ; i += 16) { + + p = phys_to_virt(i); + + if (memcmp(p, "AMDK7PNOW!", 10) == 0) { + pr_debug("Found PSB header at %p\n", p); + psb = (struct psb_s *) p; + pr_debug("Table version: 0x%x\n", psb->tableversion); + if (psb->tableversion != 0x12) { + printk(KERN_INFO PFX "Sorry, only v1.2 tables" + " supported right now\n"); + return -ENODEV; + } + + pr_debug("Flags: 0x%x\n", psb->flags); + if ((psb->flags & 1) == 0) + pr_debug("Mobile voltage regulator\n"); + else + pr_debug("Desktop voltage regulator\n"); + + latency = psb->settlingtime; + if (latency < 100) { + printk(KERN_INFO PFX "BIOS set settling time " + "to %d microseconds. " + "Should be at least 100. " + "Correcting.\n", latency); + latency = 100; + } + pr_debug("Settling Time: %d microseconds.\n", + psb->settlingtime); + pr_debug("Has %d PST tables. (Only dumping ones " + "relevant to this CPU).\n", + psb->numpst); + + p += sizeof(struct psb_s); + + pst = (struct pst_s *) p; + + for (j = 0; j < psb->numpst; j++) { + pst = (struct pst_s *) p; + number_scales = pst->numpstates; + + if ((etuple == pst->cpuid) && + check_fsb(pst->fsbspeed) && + (maxfid == pst->maxfid) && + (startvid == pst->startvid)) { + print_pst_entry(pst, j); + p = (char *)pst + sizeof(struct pst_s); + ret = get_ranges(p); + return ret; + } else { + unsigned int k; + p = (char *)pst + sizeof(struct pst_s); + for (k = 0; k < number_scales; k++) + p += 2; + } + } + printk(KERN_INFO PFX "No PST tables match this cpuid " + "(0x%x)\n", etuple); + printk(KERN_INFO PFX "This is indicative of a broken " + "BIOS.\n"); + + return -EINVAL; + } + p++; + } + + return -ENODEV; +} + + +static int powernow_target(struct cpufreq_policy *policy, + unsigned int target_freq, + unsigned int relation) +{ + unsigned int newstate; + + if (cpufreq_frequency_table_target(policy, powernow_table, target_freq, + relation, &newstate)) + return -EINVAL; + + change_speed(newstate); + + return 0; +} + + +static int powernow_verify(struct cpufreq_policy *policy) +{ + return cpufreq_frequency_table_verify(policy, powernow_table); +} + +/* + * We use the fact that the bus frequency is somehow + * a multiple of 100000/3 khz, then we compute sgtc according + * to this multiple. + * That way, we match more how AMD thinks all of that work. + * We will then get the same kind of behaviour already tested under + * the "well-known" other OS. + */ +static int __cpuinit fixup_sgtc(void) +{ + unsigned int sgtc; + unsigned int m; + + m = fsb / 3333; + if ((m % 10) >= 5) + m += 5; + + m /= 10; + + sgtc = 100 * m * latency; + sgtc = sgtc / 3; + if (sgtc > 0xfffff) { + printk(KERN_WARNING PFX "SGTC too large %d\n", sgtc); + sgtc = 0xfffff; + } + return sgtc; +} + +static unsigned int powernow_get(unsigned int cpu) +{ + union msr_fidvidstatus fidvidstatus; + unsigned int cfid; + + if (cpu) + return 0; + rdmsrl(MSR_K7_FID_VID_STATUS, fidvidstatus.val); + cfid = fidvidstatus.bits.CFID; + + return fsb * fid_codes[cfid] / 10; +} + + +static int __cpuinit acer_cpufreq_pst(const struct dmi_system_id *d) +{ + printk(KERN_WARNING PFX + "%s laptop with broken PST tables in BIOS detected.\n", + d->ident); + printk(KERN_WARNING PFX + "You need to downgrade to 3A21 (09/09/2002), or try a newer " + "BIOS than 3A71 (01/20/2003)\n"); + printk(KERN_WARNING PFX + "cpufreq scaling has been disabled as a result of this.\n"); + return 0; +} + +/* + * Some Athlon laptops have really fucked PST tables. + * A BIOS update is all that can save them. + * Mention this, and disable cpufreq. + */ +static struct dmi_system_id __cpuinitdata powernow_dmi_table[] = { + { + .callback = acer_cpufreq_pst, + .ident = "Acer Aspire", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Insyde Software"), + DMI_MATCH(DMI_BIOS_VERSION, "3A71"), + }, + }, + { } +}; + +static int __cpuinit powernow_cpu_init(struct cpufreq_policy *policy) +{ + union msr_fidvidstatus fidvidstatus; + int result; + + if (policy->cpu != 0) + return -ENODEV; + + rdmsrl(MSR_K7_FID_VID_STATUS, fidvidstatus.val); + + recalibrate_cpu_khz(); + + fsb = (10 * cpu_khz) / fid_codes[fidvidstatus.bits.CFID]; + if (!fsb) { + printk(KERN_WARNING PFX "can not determine bus frequency\n"); + return -EINVAL; + } + pr_debug("FSB: %3dMHz\n", fsb/1000); + + if (dmi_check_system(powernow_dmi_table) || acpi_force) { + printk(KERN_INFO PFX "PSB/PST known to be broken. " + "Trying ACPI instead\n"); + result = powernow_acpi_init(); + } else { + result = powernow_decode_bios(fidvidstatus.bits.MFID, + fidvidstatus.bits.SVID); + if (result) { + printk(KERN_INFO PFX "Trying ACPI perflib\n"); + maximum_speed = 0; + minimum_speed = -1; + latency = 0; + result = powernow_acpi_init(); + if (result) { + printk(KERN_INFO PFX + "ACPI and legacy methods failed\n"); + } + } else { + /* SGTC use the bus clock as timer */ + latency = fixup_sgtc(); + printk(KERN_INFO PFX "SGTC: %d\n", latency); + } + } + + if (result) + return result; + + printk(KERN_INFO PFX "Minimum speed %d MHz. Maximum speed %d MHz.\n", + minimum_speed/1000, maximum_speed/1000); + + policy->cpuinfo.transition_latency = + cpufreq_scale(2000000UL, fsb, latency); + + policy->cur = powernow_get(0); + + cpufreq_frequency_table_get_attr(powernow_table, policy->cpu); + + return cpufreq_frequency_table_cpuinfo(policy, powernow_table); +} + +static int powernow_cpu_exit(struct cpufreq_policy *policy) +{ + cpufreq_frequency_table_put_attr(policy->cpu); + +#ifdef CONFIG_X86_POWERNOW_K7_ACPI + if (acpi_processor_perf) { + acpi_processor_unregister_performance(acpi_processor_perf, 0); + free_cpumask_var(acpi_processor_perf->shared_cpu_map); + kfree(acpi_processor_perf); + } +#endif + + kfree(powernow_table); + return 0; +} + +static struct freq_attr *powernow_table_attr[] = { + &cpufreq_freq_attr_scaling_available_freqs, + NULL, +}; + +static struct cpufreq_driver powernow_driver = { + .verify = powernow_verify, + .target = powernow_target, + .get = powernow_get, +#ifdef CONFIG_X86_POWERNOW_K7_ACPI + .bios_limit = acpi_processor_get_bios_limit, +#endif + .init = powernow_cpu_init, + .exit = powernow_cpu_exit, + .name = "powernow-k7", + .owner = THIS_MODULE, + .attr = powernow_table_attr, +}; + +static int __init powernow_init(void) +{ + if (check_powernow() == 0) + return -ENODEV; + return cpufreq_register_driver(&powernow_driver); +} + + +static void __exit powernow_exit(void) +{ + cpufreq_unregister_driver(&powernow_driver); +} + +module_param(acpi_force, int, 0444); +MODULE_PARM_DESC(acpi_force, "Force ACPI to be used."); + +MODULE_AUTHOR("Dave Jones "); +MODULE_DESCRIPTION("Powernow driver for AMD K7 processors."); +MODULE_LICENSE("GPL"); + +late_initcall(powernow_init); +module_exit(powernow_exit); + diff --git a/drivers/cpufreq/powernow-k7.h b/drivers/cpufreq/powernow-k7.h new file mode 100644 index 0000000..35fb4ea --- /dev/null +++ b/drivers/cpufreq/powernow-k7.h @@ -0,0 +1,43 @@ +/* + * (C) 2003 Dave Jones. + * + * Licensed under the terms of the GNU GPL License version 2. + * + * AMD-specific information + * + */ + +union msr_fidvidctl { + struct { + unsigned FID:5, // 4:0 + reserved1:3, // 7:5 + VID:5, // 12:8 + reserved2:3, // 15:13 + FIDC:1, // 16 + VIDC:1, // 17 + reserved3:2, // 19:18 + FIDCHGRATIO:1, // 20 + reserved4:11, // 31-21 + SGTC:20, // 32:51 + reserved5:12; // 63:52 + } bits; + unsigned long long val; +}; + +union msr_fidvidstatus { + struct { + unsigned CFID:5, // 4:0 + reserved1:3, // 7:5 + SFID:5, // 12:8 + reserved2:3, // 15:13 + MFID:5, // 20:16 + reserved3:11, // 31:21 + CVID:5, // 36:32 + reserved4:3, // 39:37 + SVID:5, // 44:40 + reserved5:3, // 47:45 + MVID:5, // 52:48 + reserved6:11; // 63:53 + } bits; + unsigned long long val; +}; diff --git a/drivers/cpufreq/powernow-k8.c b/drivers/cpufreq/powernow-k8.c new file mode 100644 index 0000000..83479b6 --- /dev/null +++ b/drivers/cpufreq/powernow-k8.c @@ -0,0 +1,1607 @@ +/* + * (c) 2003-2010 Advanced Micro Devices, Inc. + * Your use of this code is subject to the terms and conditions of the + * GNU general public license version 2. See "COPYING" or + * http://www.gnu.org/licenses/gpl.html + * + * Support : mark.langsdorf@amd.com + * + * Based on the powernow-k7.c module written by Dave Jones. + * (C) 2003 Dave Jones on behalf of SuSE Labs + * (C) 2004 Dominik Brodowski + * (C) 2004 Pavel Machek + * Licensed under the terms of the GNU GPL License version 2. + * Based upon datasheets & sample CPUs kindly provided by AMD. + * + * Valuable input gratefully received from Dave Jones, Pavel Machek, + * Dominik Brodowski, Jacob Shin, and others. + * Originally developed by Paul Devriendt. + * Processor information obtained from Chapter 9 (Power and Thermal Management) + * of the "BIOS and Kernel Developer's Guide for the AMD Athlon 64 and AMD + * Opteron Processors" available for download from www.amd.com + * + * Tables for specific CPUs can be inferred from + * http://www.amd.com/us-en/assets/content_type/white_papers_and_tech_docs/30430.pdf + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include /* for current / set_cpus_allowed() */ +#include +#include + +#include + +#include +#include +#include + +#define PFX "powernow-k8: " +#define VERSION "version 2.20.00" +#include "powernow-k8.h" +#include "mperf.h" + +/* serialize freq changes */ +static DEFINE_MUTEX(fidvid_mutex); + +static DEFINE_PER_CPU(struct powernow_k8_data *, powernow_data); + +static int cpu_family = CPU_OPTERON; + +/* core performance boost */ +static bool cpb_capable, cpb_enabled; +static struct msr __percpu *msrs; + +static struct cpufreq_driver cpufreq_amd64_driver; + +#ifndef CONFIG_SMP +static inline const struct cpumask *cpu_core_mask(int cpu) +{ + return cpumask_of(0); +} +#endif + +/* Return a frequency in MHz, given an input fid */ +static u32 find_freq_from_fid(u32 fid) +{ + return 800 + (fid * 100); +} + +/* Return a frequency in KHz, given an input fid */ +static u32 find_khz_freq_from_fid(u32 fid) +{ + return 1000 * find_freq_from_fid(fid); +} + +static u32 find_khz_freq_from_pstate(struct cpufreq_frequency_table *data, + u32 pstate) +{ + return data[pstate].frequency; +} + +/* Return the vco fid for an input fid + * + * Each "low" fid has corresponding "high" fid, and you can get to "low" fids + * only from corresponding high fids. This returns "high" fid corresponding to + * "low" one. + */ +static u32 convert_fid_to_vco_fid(u32 fid) +{ + if (fid < HI_FID_TABLE_BOTTOM) + return 8 + (2 * fid); + else + return fid; +} + +/* + * Return 1 if the pending bit is set. Unless we just instructed the processor + * to transition to a new state, seeing this bit set is really bad news. + */ +static int pending_bit_stuck(void) +{ + u32 lo, hi; + + if (cpu_family == CPU_HW_PSTATE) + return 0; + + rdmsr(MSR_FIDVID_STATUS, lo, hi); + return lo & MSR_S_LO_CHANGE_PENDING ? 1 : 0; +} + +/* + * Update the global current fid / vid values from the status msr. + * Returns 1 on error. + */ +static int query_current_values_with_pending_wait(struct powernow_k8_data *data) +{ + u32 lo, hi; + u32 i = 0; + + if (cpu_family == CPU_HW_PSTATE) { + rdmsr(MSR_PSTATE_STATUS, lo, hi); + i = lo & HW_PSTATE_MASK; + data->currpstate = i; + + /* + * a workaround for family 11h erratum 311 might cause + * an "out-of-range Pstate if the core is in Pstate-0 + */ + if ((boot_cpu_data.x86 == 0x11) && (i >= data->numps)) + data->currpstate = HW_PSTATE_0; + + return 0; + } + do { + if (i++ > 10000) { + pr_debug("detected change pending stuck\n"); + return 1; + } + rdmsr(MSR_FIDVID_STATUS, lo, hi); + } while (lo & MSR_S_LO_CHANGE_PENDING); + + data->currvid = hi & MSR_S_HI_CURRENT_VID; + data->currfid = lo & MSR_S_LO_CURRENT_FID; + + return 0; +} + +/* the isochronous relief time */ +static void count_off_irt(struct powernow_k8_data *data) +{ + udelay((1 << data->irt) * 10); + return; +} + +/* the voltage stabilization time */ +static void count_off_vst(struct powernow_k8_data *data) +{ + udelay(data->vstable * VST_UNITS_20US); + return; +} + +/* need to init the control msr to a safe value (for each cpu) */ +static void fidvid_msr_init(void) +{ + u32 lo, hi; + u8 fid, vid; + + rdmsr(MSR_FIDVID_STATUS, lo, hi); + vid = hi & MSR_S_HI_CURRENT_VID; + fid = lo & MSR_S_LO_CURRENT_FID; + lo = fid | (vid << MSR_C_LO_VID_SHIFT); + hi = MSR_C_HI_STP_GNT_BENIGN; + pr_debug("cpu%d, init lo 0x%x, hi 0x%x\n", smp_processor_id(), lo, hi); + wrmsr(MSR_FIDVID_CTL, lo, hi); +} + +/* write the new fid value along with the other control fields to the msr */ +static int write_new_fid(struct powernow_k8_data *data, u32 fid) +{ + u32 lo; + u32 savevid = data->currvid; + u32 i = 0; + + if ((fid & INVALID_FID_MASK) || (data->currvid & INVALID_VID_MASK)) { + printk(KERN_ERR PFX "internal error - overflow on fid write\n"); + return 1; + } + + lo = fid; + lo |= (data->currvid << MSR_C_LO_VID_SHIFT); + lo |= MSR_C_LO_INIT_FID_VID; + + pr_debug("writing fid 0x%x, lo 0x%x, hi 0x%x\n", + fid, lo, data->plllock * PLL_LOCK_CONVERSION); + + do { + wrmsr(MSR_FIDVID_CTL, lo, data->plllock * PLL_LOCK_CONVERSION); + if (i++ > 100) { + printk(KERN_ERR PFX + "Hardware error - pending bit very stuck - " + "no further pstate changes possible\n"); + return 1; + } + } while (query_current_values_with_pending_wait(data)); + + count_off_irt(data); + + if (savevid != data->currvid) { + printk(KERN_ERR PFX + "vid change on fid trans, old 0x%x, new 0x%x\n", + savevid, data->currvid); + return 1; + } + + if (fid != data->currfid) { + printk(KERN_ERR PFX + "fid trans failed, fid 0x%x, curr 0x%x\n", fid, + data->currfid); + return 1; + } + + return 0; +} + +/* Write a new vid to the hardware */ +static int write_new_vid(struct powernow_k8_data *data, u32 vid) +{ + u32 lo; + u32 savefid = data->currfid; + int i = 0; + + if ((data->currfid & INVALID_FID_MASK) || (vid & INVALID_VID_MASK)) { + printk(KERN_ERR PFX "internal error - overflow on vid write\n"); + return 1; + } + + lo = data->currfid; + lo |= (vid << MSR_C_LO_VID_SHIFT); + lo |= MSR_C_LO_INIT_FID_VID; + + pr_debug("writing vid 0x%x, lo 0x%x, hi 0x%x\n", + vid, lo, STOP_GRANT_5NS); + + do { + wrmsr(MSR_FIDVID_CTL, lo, STOP_GRANT_5NS); + if (i++ > 100) { + printk(KERN_ERR PFX "internal error - pending bit " + "very stuck - no further pstate " + "changes possible\n"); + return 1; + } + } while (query_current_values_with_pending_wait(data)); + + if (savefid != data->currfid) { + printk(KERN_ERR PFX "fid changed on vid trans, old " + "0x%x new 0x%x\n", + savefid, data->currfid); + return 1; + } + + if (vid != data->currvid) { + printk(KERN_ERR PFX "vid trans failed, vid 0x%x, " + "curr 0x%x\n", + vid, data->currvid); + return 1; + } + + return 0; +} + +/* + * Reduce the vid by the max of step or reqvid. + * Decreasing vid codes represent increasing voltages: + * vid of 0 is 1.550V, vid of 0x1e is 0.800V, vid of VID_OFF is off. + */ +static int decrease_vid_code_by_step(struct powernow_k8_data *data, + u32 reqvid, u32 step) +{ + if ((data->currvid - reqvid) > step) + reqvid = data->currvid - step; + + if (write_new_vid(data, reqvid)) + return 1; + + count_off_vst(data); + + return 0; +} + +/* Change hardware pstate by single MSR write */ +static int transition_pstate(struct powernow_k8_data *data, u32 pstate) +{ + wrmsr(MSR_PSTATE_CTRL, pstate, 0); + data->currpstate = pstate; + return 0; +} + +/* Change Opteron/Athlon64 fid and vid, by the 3 phases. */ +static int transition_fid_vid(struct powernow_k8_data *data, + u32 reqfid, u32 reqvid) +{ + if (core_voltage_pre_transition(data, reqvid, reqfid)) + return 1; + + if (core_frequency_transition(data, reqfid)) + return 1; + + if (core_voltage_post_transition(data, reqvid)) + return 1; + + if (query_current_values_with_pending_wait(data)) + return 1; + + if ((reqfid != data->currfid) || (reqvid != data->currvid)) { + printk(KERN_ERR PFX "failed (cpu%d): req 0x%x 0x%x, " + "curr 0x%x 0x%x\n", + smp_processor_id(), + reqfid, reqvid, data->currfid, data->currvid); + return 1; + } + + pr_debug("transitioned (cpu%d): new fid 0x%x, vid 0x%x\n", + smp_processor_id(), data->currfid, data->currvid); + + return 0; +} + +/* Phase 1 - core voltage transition ... setup voltage */ +static int core_voltage_pre_transition(struct powernow_k8_data *data, + u32 reqvid, u32 reqfid) +{ + u32 rvosteps = data->rvo; + u32 savefid = data->currfid; + u32 maxvid, lo, rvomult = 1; + + pr_debug("ph1 (cpu%d): start, currfid 0x%x, currvid 0x%x, " + "reqvid 0x%x, rvo 0x%x\n", + smp_processor_id(), + data->currfid, data->currvid, reqvid, data->rvo); + + if ((savefid < LO_FID_TABLE_TOP) && (reqfid < LO_FID_TABLE_TOP)) + rvomult = 2; + rvosteps *= rvomult; + rdmsr(MSR_FIDVID_STATUS, lo, maxvid); + maxvid = 0x1f & (maxvid >> 16); + pr_debug("ph1 maxvid=0x%x\n", maxvid); + if (reqvid < maxvid) /* lower numbers are higher voltages */ + reqvid = maxvid; + + while (data->currvid > reqvid) { + pr_debug("ph1: curr 0x%x, req vid 0x%x\n", + data->currvid, reqvid); + if (decrease_vid_code_by_step(data, reqvid, data->vidmvs)) + return 1; + } + + while ((rvosteps > 0) && + ((rvomult * data->rvo + data->currvid) > reqvid)) { + if (data->currvid == maxvid) { + rvosteps = 0; + } else { + pr_debug("ph1: changing vid for rvo, req 0x%x\n", + data->currvid - 1); + if (decrease_vid_code_by_step(data, data->currvid-1, 1)) + return 1; + rvosteps--; + } + } + + if (query_current_values_with_pending_wait(data)) + return 1; + + if (savefid != data->currfid) { + printk(KERN_ERR PFX "ph1 err, currfid changed 0x%x\n", + data->currfid); + return 1; + } + + pr_debug("ph1 complete, currfid 0x%x, currvid 0x%x\n", + data->currfid, data->currvid); + + return 0; +} + +/* Phase 2 - core frequency transition */ +static int core_frequency_transition(struct powernow_k8_data *data, u32 reqfid) +{ + u32 vcoreqfid, vcocurrfid, vcofiddiff; + u32 fid_interval, savevid = data->currvid; + + if (data->currfid == reqfid) { + printk(KERN_ERR PFX "ph2 null fid transition 0x%x\n", + data->currfid); + return 0; + } + + pr_debug("ph2 (cpu%d): starting, currfid 0x%x, currvid 0x%x, " + "reqfid 0x%x\n", + smp_processor_id(), + data->currfid, data->currvid, reqfid); + + vcoreqfid = convert_fid_to_vco_fid(reqfid); + vcocurrfid = convert_fid_to_vco_fid(data->currfid); + vcofiddiff = vcocurrfid > vcoreqfid ? vcocurrfid - vcoreqfid + : vcoreqfid - vcocurrfid; + + if ((reqfid <= LO_FID_TABLE_TOP) && (data->currfid <= LO_FID_TABLE_TOP)) + vcofiddiff = 0; + + while (vcofiddiff > 2) { + (data->currfid & 1) ? (fid_interval = 1) : (fid_interval = 2); + + if (reqfid > data->currfid) { + if (data->currfid > LO_FID_TABLE_TOP) { + if (write_new_fid(data, + data->currfid + fid_interval)) + return 1; + } else { + if (write_new_fid + (data, + 2 + convert_fid_to_vco_fid(data->currfid))) + return 1; + } + } else { + if (write_new_fid(data, data->currfid - fid_interval)) + return 1; + } + + vcocurrfid = convert_fid_to_vco_fid(data->currfid); + vcofiddiff = vcocurrfid > vcoreqfid ? vcocurrfid - vcoreqfid + : vcoreqfid - vcocurrfid; + } + + if (write_new_fid(data, reqfid)) + return 1; + + if (query_current_values_with_pending_wait(data)) + return 1; + + if (data->currfid != reqfid) { + printk(KERN_ERR PFX + "ph2: mismatch, failed fid transition, " + "curr 0x%x, req 0x%x\n", + data->currfid, reqfid); + return 1; + } + + if (savevid != data->currvid) { + printk(KERN_ERR PFX "ph2: vid changed, save 0x%x, curr 0x%x\n", + savevid, data->currvid); + return 1; + } + + pr_debug("ph2 complete, currfid 0x%x, currvid 0x%x\n", + data->currfid, data->currvid); + + return 0; +} + +/* Phase 3 - core voltage transition flow ... jump to the final vid. */ +static int core_voltage_post_transition(struct powernow_k8_data *data, + u32 reqvid) +{ + u32 savefid = data->currfid; + u32 savereqvid = reqvid; + + pr_debug("ph3 (cpu%d): starting, currfid 0x%x, currvid 0x%x\n", + smp_processor_id(), + data->currfid, data->currvid); + + if (reqvid != data->currvid) { + if (write_new_vid(data, reqvid)) + return 1; + + if (savefid != data->currfid) { + printk(KERN_ERR PFX + "ph3: bad fid change, save 0x%x, curr 0x%x\n", + savefid, data->currfid); + return 1; + } + + if (data->currvid != reqvid) { + printk(KERN_ERR PFX + "ph3: failed vid transition\n, " + "req 0x%x, curr 0x%x", + reqvid, data->currvid); + return 1; + } + } + + if (query_current_values_with_pending_wait(data)) + return 1; + + if (savereqvid != data->currvid) { + pr_debug("ph3 failed, currvid 0x%x\n", data->currvid); + return 1; + } + + if (savefid != data->currfid) { + pr_debug("ph3 failed, currfid changed 0x%x\n", + data->currfid); + return 1; + } + + pr_debug("ph3 complete, currfid 0x%x, currvid 0x%x\n", + data->currfid, data->currvid); + + return 0; +} + +static void check_supported_cpu(void *_rc) +{ + u32 eax, ebx, ecx, edx; + int *rc = _rc; + + *rc = -ENODEV; + + if (__this_cpu_read(cpu_info.x86_vendor) != X86_VENDOR_AMD) + return; + + eax = cpuid_eax(CPUID_PROCESSOR_SIGNATURE); + if (((eax & CPUID_XFAM) != CPUID_XFAM_K8) && + ((eax & CPUID_XFAM) < CPUID_XFAM_10H)) + return; + + if ((eax & CPUID_XFAM) == CPUID_XFAM_K8) { + if (((eax & CPUID_USE_XFAM_XMOD) != CPUID_USE_XFAM_XMOD) || + ((eax & CPUID_XMOD) > CPUID_XMOD_REV_MASK)) { + printk(KERN_INFO PFX + "Processor cpuid %x not supported\n", eax); + return; + } + + eax = cpuid_eax(CPUID_GET_MAX_CAPABILITIES); + if (eax < CPUID_FREQ_VOLT_CAPABILITIES) { + printk(KERN_INFO PFX + "No frequency change capabilities detected\n"); + return; + } + + cpuid(CPUID_FREQ_VOLT_CAPABILITIES, &eax, &ebx, &ecx, &edx); + if ((edx & P_STATE_TRANSITION_CAPABLE) + != P_STATE_TRANSITION_CAPABLE) { + printk(KERN_INFO PFX + "Power state transitions not supported\n"); + return; + } + } else { /* must be a HW Pstate capable processor */ + cpuid(CPUID_FREQ_VOLT_CAPABILITIES, &eax, &ebx, &ecx, &edx); + if ((edx & USE_HW_PSTATE) == USE_HW_PSTATE) + cpu_family = CPU_HW_PSTATE; + else + return; + } + + *rc = 0; +} + +static int check_pst_table(struct powernow_k8_data *data, struct pst_s *pst, + u8 maxvid) +{ + unsigned int j; + u8 lastfid = 0xff; + + for (j = 0; j < data->numps; j++) { + if (pst[j].vid > LEAST_VID) { + printk(KERN_ERR FW_BUG PFX "vid %d invalid : 0x%x\n", + j, pst[j].vid); + return -EINVAL; + } + if (pst[j].vid < data->rvo) { + /* vid + rvo >= 0 */ + printk(KERN_ERR FW_BUG PFX "0 vid exceeded with pstate" + " %d\n", j); + return -ENODEV; + } + if (pst[j].vid < maxvid + data->rvo) { + /* vid + rvo >= maxvid */ + printk(KERN_ERR FW_BUG PFX "maxvid exceeded with pstate" + " %d\n", j); + return -ENODEV; + } + if (pst[j].fid > MAX_FID) { + printk(KERN_ERR FW_BUG PFX "maxfid exceeded with pstate" + " %d\n", j); + return -ENODEV; + } + if (j && (pst[j].fid < HI_FID_TABLE_BOTTOM)) { + /* Only first fid is allowed to be in "low" range */ + printk(KERN_ERR FW_BUG PFX "two low fids - %d : " + "0x%x\n", j, pst[j].fid); + return -EINVAL; + } + if (pst[j].fid < lastfid) + lastfid = pst[j].fid; + } + if (lastfid & 1) { + printk(KERN_ERR FW_BUG PFX "lastfid invalid\n"); + return -EINVAL; + } + if (lastfid > LO_FID_TABLE_TOP) + printk(KERN_INFO FW_BUG PFX + "first fid not from lo freq table\n"); + + return 0; +} + +static void invalidate_entry(struct cpufreq_frequency_table *powernow_table, + unsigned int entry) +{ + powernow_table[entry].frequency = CPUFREQ_ENTRY_INVALID; +} + +static void print_basics(struct powernow_k8_data *data) +{ + int j; + for (j = 0; j < data->numps; j++) { + if (data->powernow_table[j].frequency != + CPUFREQ_ENTRY_INVALID) { + if (cpu_family == CPU_HW_PSTATE) { + printk(KERN_INFO PFX + " %d : pstate %d (%d MHz)\n", j, + data->powernow_table[j].index, + data->powernow_table[j].frequency/1000); + } else { + printk(KERN_INFO PFX + "fid 0x%x (%d MHz), vid 0x%x\n", + data->powernow_table[j].index & 0xff, + data->powernow_table[j].frequency/1000, + data->powernow_table[j].index >> 8); + } + } + } + if (data->batps) + printk(KERN_INFO PFX "Only %d pstates on battery\n", + data->batps); +} + +static u32 freq_from_fid_did(u32 fid, u32 did) +{ + u32 mhz = 0; + + if (boot_cpu_data.x86 == 0x10) + mhz = (100 * (fid + 0x10)) >> did; + else if (boot_cpu_data.x86 == 0x11) + mhz = (100 * (fid + 8)) >> did; + else + BUG(); + + return mhz * 1000; +} + +static int fill_powernow_table(struct powernow_k8_data *data, + struct pst_s *pst, u8 maxvid) +{ + struct cpufreq_frequency_table *powernow_table; + unsigned int j; + + if (data->batps) { + /* use ACPI support to get full speed on mains power */ + printk(KERN_WARNING PFX + "Only %d pstates usable (use ACPI driver for full " + "range\n", data->batps); + data->numps = data->batps; + } + + for (j = 1; j < data->numps; j++) { + if (pst[j-1].fid >= pst[j].fid) { + printk(KERN_ERR PFX "PST out of sequence\n"); + return -EINVAL; + } + } + + if (data->numps < 2) { + printk(KERN_ERR PFX "no p states to transition\n"); + return -ENODEV; + } + + if (check_pst_table(data, pst, maxvid)) + return -EINVAL; + + powernow_table = kmalloc((sizeof(struct cpufreq_frequency_table) + * (data->numps + 1)), GFP_KERNEL); + if (!powernow_table) { + printk(KERN_ERR PFX "powernow_table memory alloc failure\n"); + return -ENOMEM; + } + + for (j = 0; j < data->numps; j++) { + int freq; + powernow_table[j].index = pst[j].fid; /* lower 8 bits */ + powernow_table[j].index |= (pst[j].vid << 8); /* upper 8 bits */ + freq = find_khz_freq_from_fid(pst[j].fid); + powernow_table[j].frequency = freq; + } + powernow_table[data->numps].frequency = CPUFREQ_TABLE_END; + powernow_table[data->numps].index = 0; + + if (query_current_values_with_pending_wait(data)) { + kfree(powernow_table); + return -EIO; + } + + pr_debug("cfid 0x%x, cvid 0x%x\n", data->currfid, data->currvid); + data->powernow_table = powernow_table; + if (cpumask_first(cpu_core_mask(data->cpu)) == data->cpu) + print_basics(data); + + for (j = 0; j < data->numps; j++) + if ((pst[j].fid == data->currfid) && + (pst[j].vid == data->currvid)) + return 0; + + pr_debug("currfid/vid do not match PST, ignoring\n"); + return 0; +} + +/* Find and validate the PSB/PST table in BIOS. */ +static int find_psb_table(struct powernow_k8_data *data) +{ + struct psb_s *psb; + unsigned int i; + u32 mvs; + u8 maxvid; + u32 cpst = 0; + u32 thiscpuid; + + for (i = 0xc0000; i < 0xffff0; i += 0x10) { + /* Scan BIOS looking for the signature. */ + /* It can not be at ffff0 - it is too big. */ + + psb = phys_to_virt(i); + if (memcmp(psb, PSB_ID_STRING, PSB_ID_STRING_LEN) != 0) + continue; + + pr_debug("found PSB header at 0x%p\n", psb); + + pr_debug("table vers: 0x%x\n", psb->tableversion); + if (psb->tableversion != PSB_VERSION_1_4) { + printk(KERN_ERR FW_BUG PFX "PSB table is not v1.4\n"); + return -ENODEV; + } + + pr_debug("flags: 0x%x\n", psb->flags1); + if (psb->flags1) { + printk(KERN_ERR FW_BUG PFX "unknown flags\n"); + return -ENODEV; + } + + data->vstable = psb->vstable; + pr_debug("voltage stabilization time: %d(*20us)\n", + data->vstable); + + pr_debug("flags2: 0x%x\n", psb->flags2); + data->rvo = psb->flags2 & 3; + data->irt = ((psb->flags2) >> 2) & 3; + mvs = ((psb->flags2) >> 4) & 3; + data->vidmvs = 1 << mvs; + data->batps = ((psb->flags2) >> 6) & 3; + + pr_debug("ramp voltage offset: %d\n", data->rvo); + pr_debug("isochronous relief time: %d\n", data->irt); + pr_debug("maximum voltage step: %d - 0x%x\n", mvs, data->vidmvs); + + pr_debug("numpst: 0x%x\n", psb->num_tables); + cpst = psb->num_tables; + if ((psb->cpuid == 0x00000fc0) || + (psb->cpuid == 0x00000fe0)) { + thiscpuid = cpuid_eax(CPUID_PROCESSOR_SIGNATURE); + if ((thiscpuid == 0x00000fc0) || + (thiscpuid == 0x00000fe0)) + cpst = 1; + } + if (cpst != 1) { + printk(KERN_ERR FW_BUG PFX "numpst must be 1\n"); + return -ENODEV; + } + + data->plllock = psb->plllocktime; + pr_debug("plllocktime: 0x%x (units 1us)\n", psb->plllocktime); + pr_debug("maxfid: 0x%x\n", psb->maxfid); + pr_debug("maxvid: 0x%x\n", psb->maxvid); + maxvid = psb->maxvid; + + data->numps = psb->numps; + pr_debug("numpstates: 0x%x\n", data->numps); + return fill_powernow_table(data, + (struct pst_s *)(psb+1), maxvid); + } + /* + * If you see this message, complain to BIOS manufacturer. If + * he tells you "we do not support Linux" or some similar + * nonsense, remember that Windows 2000 uses the same legacy + * mechanism that the old Linux PSB driver uses. Tell them it + * is broken with Windows 2000. + * + * The reference to the AMD documentation is chapter 9 in the + * BIOS and Kernel Developer's Guide, which is available on + * www.amd.com + */ + printk(KERN_ERR FW_BUG PFX "No PSB or ACPI _PSS objects\n"); + printk(KERN_ERR PFX "Make sure that your BIOS is up to date" + " and Cool'N'Quiet support is enabled in BIOS setup\n"); + return -ENODEV; +} + +static void powernow_k8_acpi_pst_values(struct powernow_k8_data *data, + unsigned int index) +{ + u64 control; + + if (!data->acpi_data.state_count || (cpu_family == CPU_HW_PSTATE)) + return; + + control = data->acpi_data.states[index].control; + data->irt = (control >> IRT_SHIFT) & IRT_MASK; + data->rvo = (control >> RVO_SHIFT) & RVO_MASK; + data->exttype = (control >> EXT_TYPE_SHIFT) & EXT_TYPE_MASK; + data->plllock = (control >> PLL_L_SHIFT) & PLL_L_MASK; + data->vidmvs = 1 << ((control >> MVS_SHIFT) & MVS_MASK); + data->vstable = (control >> VST_SHIFT) & VST_MASK; +} + +static int powernow_k8_cpu_init_acpi(struct powernow_k8_data *data) +{ + struct cpufreq_frequency_table *powernow_table; + int ret_val = -ENODEV; + u64 control, status; + + if (acpi_processor_register_performance(&data->acpi_data, data->cpu)) { + pr_debug("register performance failed: bad ACPI data\n"); + return -EIO; + } + + /* verify the data contained in the ACPI structures */ + if (data->acpi_data.state_count <= 1) { + pr_debug("No ACPI P-States\n"); + goto err_out; + } + + control = data->acpi_data.control_register.space_id; + status = data->acpi_data.status_register.space_id; + + if ((control != ACPI_ADR_SPACE_FIXED_HARDWARE) || + (status != ACPI_ADR_SPACE_FIXED_HARDWARE)) { + pr_debug("Invalid control/status registers (%llx - %llx)\n", + control, status); + goto err_out; + } + + /* fill in data->powernow_table */ + powernow_table = kmalloc((sizeof(struct cpufreq_frequency_table) + * (data->acpi_data.state_count + 1)), GFP_KERNEL); + if (!powernow_table) { + pr_debug("powernow_table memory alloc failure\n"); + goto err_out; + } + + /* fill in data */ + data->numps = data->acpi_data.state_count; + powernow_k8_acpi_pst_values(data, 0); + + if (cpu_family == CPU_HW_PSTATE) + ret_val = fill_powernow_table_pstate(data, powernow_table); + else + ret_val = fill_powernow_table_fidvid(data, powernow_table); + if (ret_val) + goto err_out_mem; + + powernow_table[data->acpi_data.state_count].frequency = + CPUFREQ_TABLE_END; + powernow_table[data->acpi_data.state_count].index = 0; + data->powernow_table = powernow_table; + + if (cpumask_first(cpu_core_mask(data->cpu)) == data->cpu) + print_basics(data); + + /* notify BIOS that we exist */ + acpi_processor_notify_smm(THIS_MODULE); + + if (!zalloc_cpumask_var(&data->acpi_data.shared_cpu_map, GFP_KERNEL)) { + printk(KERN_ERR PFX + "unable to alloc powernow_k8_data cpumask\n"); + ret_val = -ENOMEM; + goto err_out_mem; + } + + return 0; + +err_out_mem: + kfree(powernow_table); + +err_out: + acpi_processor_unregister_performance(&data->acpi_data, data->cpu); + + /* data->acpi_data.state_count informs us at ->exit() + * whether ACPI was used */ + data->acpi_data.state_count = 0; + + return ret_val; +} + +static int fill_powernow_table_pstate(struct powernow_k8_data *data, + struct cpufreq_frequency_table *powernow_table) +{ + int i; + u32 hi = 0, lo = 0; + rdmsr(MSR_PSTATE_CUR_LIMIT, lo, hi); + data->max_hw_pstate = (lo & HW_PSTATE_MAX_MASK) >> HW_PSTATE_MAX_SHIFT; + + for (i = 0; i < data->acpi_data.state_count; i++) { + u32 index; + + index = data->acpi_data.states[i].control & HW_PSTATE_MASK; + if (index > data->max_hw_pstate) { + printk(KERN_ERR PFX "invalid pstate %d - " + "bad value %d.\n", i, index); + printk(KERN_ERR PFX "Please report to BIOS " + "manufacturer\n"); + invalidate_entry(powernow_table, i); + continue; + } + rdmsr(MSR_PSTATE_DEF_BASE + index, lo, hi); + if (!(hi & HW_PSTATE_VALID_MASK)) { + pr_debug("invalid pstate %d, ignoring\n", index); + invalidate_entry(powernow_table, i); + continue; + } + + powernow_table[i].index = index; + + /* Frequency may be rounded for these */ + if ((boot_cpu_data.x86 == 0x10 && boot_cpu_data.x86_model < 10) + || boot_cpu_data.x86 == 0x11) { + powernow_table[i].frequency = + freq_from_fid_did(lo & 0x3f, (lo >> 6) & 7); + } else + powernow_table[i].frequency = + data->acpi_data.states[i].core_frequency * 1000; + } + return 0; +} + +static int fill_powernow_table_fidvid(struct powernow_k8_data *data, + struct cpufreq_frequency_table *powernow_table) +{ + int i; + + for (i = 0; i < data->acpi_data.state_count; i++) { + u32 fid; + u32 vid; + u32 freq, index; + u64 status, control; + + if (data->exttype) { + status = data->acpi_data.states[i].status; + fid = status & EXT_FID_MASK; + vid = (status >> VID_SHIFT) & EXT_VID_MASK; + } else { + control = data->acpi_data.states[i].control; + fid = control & FID_MASK; + vid = (control >> VID_SHIFT) & VID_MASK; + } + + pr_debug(" %d : fid 0x%x, vid 0x%x\n", i, fid, vid); + + index = fid | (vid<<8); + powernow_table[i].index = index; + + freq = find_khz_freq_from_fid(fid); + powernow_table[i].frequency = freq; + + /* verify frequency is OK */ + if ((freq > (MAX_FREQ * 1000)) || (freq < (MIN_FREQ * 1000))) { + pr_debug("invalid freq %u kHz, ignoring\n", freq); + invalidate_entry(powernow_table, i); + continue; + } + + /* verify voltage is OK - + * BIOSs are using "off" to indicate invalid */ + if (vid == VID_OFF) { + pr_debug("invalid vid %u, ignoring\n", vid); + invalidate_entry(powernow_table, i); + continue; + } + + if (freq != (data->acpi_data.states[i].core_frequency * 1000)) { + printk(KERN_INFO PFX "invalid freq entries " + "%u kHz vs. %u kHz\n", freq, + (unsigned int) + (data->acpi_data.states[i].core_frequency + * 1000)); + invalidate_entry(powernow_table, i); + continue; + } + } + return 0; +} + +static void powernow_k8_cpu_exit_acpi(struct powernow_k8_data *data) +{ + if (data->acpi_data.state_count) + acpi_processor_unregister_performance(&data->acpi_data, + data->cpu); + free_cpumask_var(data->acpi_data.shared_cpu_map); +} + +static int get_transition_latency(struct powernow_k8_data *data) +{ + int max_latency = 0; + int i; + for (i = 0; i < data->acpi_data.state_count; i++) { + int cur_latency = data->acpi_data.states[i].transition_latency + + data->acpi_data.states[i].bus_master_latency; + if (cur_latency > max_latency) + max_latency = cur_latency; + } + if (max_latency == 0) { + /* + * Fam 11h and later may return 0 as transition latency. This + * is intended and means "very fast". While cpufreq core and + * governors currently can handle that gracefully, better set it + * to 1 to avoid problems in the future. + */ + if (boot_cpu_data.x86 < 0x11) + printk(KERN_ERR FW_WARN PFX "Invalid zero transition " + "latency\n"); + max_latency = 1; + } + /* value in usecs, needs to be in nanoseconds */ + return 1000 * max_latency; +} + +/* Take a frequency, and issue the fid/vid transition command */ +static int transition_frequency_fidvid(struct powernow_k8_data *data, + unsigned int index) +{ + u32 fid = 0; + u32 vid = 0; + int res, i; + struct cpufreq_freqs freqs; + + pr_debug("cpu %d transition to index %u\n", smp_processor_id(), index); + + /* fid/vid correctness check for k8 */ + /* fid are the lower 8 bits of the index we stored into + * the cpufreq frequency table in find_psb_table, vid + * are the upper 8 bits. + */ + fid = data->powernow_table[index].index & 0xFF; + vid = (data->powernow_table[index].index & 0xFF00) >> 8; + + pr_debug("table matched fid 0x%x, giving vid 0x%x\n", fid, vid); + + if (query_current_values_with_pending_wait(data)) + return 1; + + if ((data->currvid == vid) && (data->currfid == fid)) { + pr_debug("target matches current values (fid 0x%x, vid 0x%x)\n", + fid, vid); + return 0; + } + + pr_debug("cpu %d, changing to fid 0x%x, vid 0x%x\n", + smp_processor_id(), fid, vid); + freqs.old = find_khz_freq_from_fid(data->currfid); + freqs.new = find_khz_freq_from_fid(fid); + + for_each_cpu(i, data->available_cores) { + freqs.cpu = i; + cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE); + } + + res = transition_fid_vid(data, fid, vid); + freqs.new = find_khz_freq_from_fid(data->currfid); + + for_each_cpu(i, data->available_cores) { + freqs.cpu = i; + cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE); + } + return res; +} + +/* Take a frequency, and issue the hardware pstate transition command */ +static int transition_frequency_pstate(struct powernow_k8_data *data, + unsigned int index) +{ + u32 pstate = 0; + int res, i; + struct cpufreq_freqs freqs; + + pr_debug("cpu %d transition to index %u\n", smp_processor_id(), index); + + /* get MSR index for hardware pstate transition */ + pstate = index & HW_PSTATE_MASK; + if (pstate > data->max_hw_pstate) + return 0; + freqs.old = find_khz_freq_from_pstate(data->powernow_table, + data->currpstate); + freqs.new = find_khz_freq_from_pstate(data->powernow_table, pstate); + + for_each_cpu(i, data->available_cores) { + freqs.cpu = i; + cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE); + } + + res = transition_pstate(data, pstate); + freqs.new = find_khz_freq_from_pstate(data->powernow_table, pstate); + + for_each_cpu(i, data->available_cores) { + freqs.cpu = i; + cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE); + } + return res; +} + +/* Driver entry point to switch to the target frequency */ +static int powernowk8_target(struct cpufreq_policy *pol, + unsigned targfreq, unsigned relation) +{ + cpumask_var_t oldmask; + struct powernow_k8_data *data = per_cpu(powernow_data, pol->cpu); + u32 checkfid; + u32 checkvid; + unsigned int newstate; + int ret = -EIO; + + if (!data) + return -EINVAL; + + checkfid = data->currfid; + checkvid = data->currvid; + + /* only run on specific CPU from here on. */ + /* This is poor form: use a workqueue or smp_call_function_single */ + if (!alloc_cpumask_var(&oldmask, GFP_KERNEL)) + return -ENOMEM; + + cpumask_copy(oldmask, tsk_cpus_allowed(current)); + set_cpus_allowed_ptr(current, cpumask_of(pol->cpu)); + + if (smp_processor_id() != pol->cpu) { + printk(KERN_ERR PFX "limiting to cpu %u failed\n", pol->cpu); + goto err_out; + } + + if (pending_bit_stuck()) { + printk(KERN_ERR PFX "failing targ, change pending bit set\n"); + goto err_out; + } + + pr_debug("targ: cpu %d, %d kHz, min %d, max %d, relation %d\n", + pol->cpu, targfreq, pol->min, pol->max, relation); + + if (query_current_values_with_pending_wait(data)) + goto err_out; + + if (cpu_family != CPU_HW_PSTATE) { + pr_debug("targ: curr fid 0x%x, vid 0x%x\n", + data->currfid, data->currvid); + + if ((checkvid != data->currvid) || + (checkfid != data->currfid)) { + printk(KERN_INFO PFX + "error - out of sync, fix 0x%x 0x%x, " + "vid 0x%x 0x%x\n", + checkfid, data->currfid, + checkvid, data->currvid); + } + } + + if (cpufreq_frequency_table_target(pol, data->powernow_table, + targfreq, relation, &newstate)) + goto err_out; + + mutex_lock(&fidvid_mutex); + + powernow_k8_acpi_pst_values(data, newstate); + + if (cpu_family == CPU_HW_PSTATE) + ret = transition_frequency_pstate(data, newstate); + else + ret = transition_frequency_fidvid(data, newstate); + if (ret) { + printk(KERN_ERR PFX "transition frequency failed\n"); + ret = 1; + mutex_unlock(&fidvid_mutex); + goto err_out; + } + mutex_unlock(&fidvid_mutex); + + if (cpu_family == CPU_HW_PSTATE) + pol->cur = find_khz_freq_from_pstate(data->powernow_table, + newstate); + else + pol->cur = find_khz_freq_from_fid(data->currfid); + ret = 0; + +err_out: + set_cpus_allowed_ptr(current, oldmask); + free_cpumask_var(oldmask); + return ret; +} + +/* Driver entry point to verify the policy and range of frequencies */ +static int powernowk8_verify(struct cpufreq_policy *pol) +{ + struct powernow_k8_data *data = per_cpu(powernow_data, pol->cpu); + + if (!data) + return -EINVAL; + + return cpufreq_frequency_table_verify(pol, data->powernow_table); +} + +struct init_on_cpu { + struct powernow_k8_data *data; + int rc; +}; + +static void __cpuinit powernowk8_cpu_init_on_cpu(void *_init_on_cpu) +{ + struct init_on_cpu *init_on_cpu = _init_on_cpu; + + if (pending_bit_stuck()) { + printk(KERN_ERR PFX "failing init, change pending bit set\n"); + init_on_cpu->rc = -ENODEV; + return; + } + + if (query_current_values_with_pending_wait(init_on_cpu->data)) { + init_on_cpu->rc = -ENODEV; + return; + } + + if (cpu_family == CPU_OPTERON) + fidvid_msr_init(); + + init_on_cpu->rc = 0; +} + +/* per CPU init entry point to the driver */ +static int __cpuinit powernowk8_cpu_init(struct cpufreq_policy *pol) +{ + static const char ACPI_PSS_BIOS_BUG_MSG[] = + KERN_ERR FW_BUG PFX "No compatible ACPI _PSS objects found.\n" + FW_BUG PFX "Try again with latest BIOS.\n"; + struct powernow_k8_data *data; + struct init_on_cpu init_on_cpu; + int rc; + struct cpuinfo_x86 *c = &cpu_data(pol->cpu); + + if (!cpu_online(pol->cpu)) + return -ENODEV; + + smp_call_function_single(pol->cpu, check_supported_cpu, &rc, 1); + if (rc) + return -ENODEV; + + data = kzalloc(sizeof(struct powernow_k8_data), GFP_KERNEL); + if (!data) { + printk(KERN_ERR PFX "unable to alloc powernow_k8_data"); + return -ENOMEM; + } + + data->cpu = pol->cpu; + data->currpstate = HW_PSTATE_INVALID; + + if (powernow_k8_cpu_init_acpi(data)) { + /* + * Use the PSB BIOS structure. This is only available on + * an UP version, and is deprecated by AMD. + */ + if (num_online_cpus() != 1) { + printk_once(ACPI_PSS_BIOS_BUG_MSG); + goto err_out; + } + if (pol->cpu != 0) { + printk(KERN_ERR FW_BUG PFX "No ACPI _PSS objects for " + "CPU other than CPU0. Complain to your BIOS " + "vendor.\n"); + goto err_out; + } + rc = find_psb_table(data); + if (rc) + goto err_out; + + /* Take a crude guess here. + * That guess was in microseconds, so multiply with 1000 */ + pol->cpuinfo.transition_latency = ( + ((data->rvo + 8) * data->vstable * VST_UNITS_20US) + + ((1 << data->irt) * 30)) * 1000; + } else /* ACPI _PSS objects available */ + pol->cpuinfo.transition_latency = get_transition_latency(data); + + /* only run on specific CPU from here on */ + init_on_cpu.data = data; + smp_call_function_single(data->cpu, powernowk8_cpu_init_on_cpu, + &init_on_cpu, 1); + rc = init_on_cpu.rc; + if (rc != 0) + goto err_out_exit_acpi; + + if (cpu_family == CPU_HW_PSTATE) + cpumask_copy(pol->cpus, cpumask_of(pol->cpu)); + else + cpumask_copy(pol->cpus, cpu_core_mask(pol->cpu)); + data->available_cores = pol->cpus; + + if (cpu_family == CPU_HW_PSTATE) + pol->cur = find_khz_freq_from_pstate(data->powernow_table, + data->currpstate); + else + pol->cur = find_khz_freq_from_fid(data->currfid); + pr_debug("policy current frequency %d kHz\n", pol->cur); + + /* min/max the cpu is capable of */ + if (cpufreq_frequency_table_cpuinfo(pol, data->powernow_table)) { + printk(KERN_ERR FW_BUG PFX "invalid powernow_table\n"); + powernow_k8_cpu_exit_acpi(data); + kfree(data->powernow_table); + kfree(data); + return -EINVAL; + } + + /* Check for APERF/MPERF support in hardware */ + if (cpu_has(c, X86_FEATURE_APERFMPERF)) + cpufreq_amd64_driver.getavg = cpufreq_get_measured_perf; + + cpufreq_frequency_table_get_attr(data->powernow_table, pol->cpu); + + if (cpu_family == CPU_HW_PSTATE) + pr_debug("cpu_init done, current pstate 0x%x\n", + data->currpstate); + else + pr_debug("cpu_init done, current fid 0x%x, vid 0x%x\n", + data->currfid, data->currvid); + + per_cpu(powernow_data, pol->cpu) = data; + + return 0; + +err_out_exit_acpi: + powernow_k8_cpu_exit_acpi(data); + +err_out: + kfree(data); + return -ENODEV; +} + +static int __devexit powernowk8_cpu_exit(struct cpufreq_policy *pol) +{ + struct powernow_k8_data *data = per_cpu(powernow_data, pol->cpu); + + if (!data) + return -EINVAL; + + powernow_k8_cpu_exit_acpi(data); + + cpufreq_frequency_table_put_attr(pol->cpu); + + kfree(data->powernow_table); + kfree(data); + per_cpu(powernow_data, pol->cpu) = NULL; + + return 0; +} + +static void query_values_on_cpu(void *_err) +{ + int *err = _err; + struct powernow_k8_data *data = __this_cpu_read(powernow_data); + + *err = query_current_values_with_pending_wait(data); +} + +static unsigned int powernowk8_get(unsigned int cpu) +{ + struct powernow_k8_data *data = per_cpu(powernow_data, cpu); + unsigned int khz = 0; + int err; + + if (!data) + return 0; + + smp_call_function_single(cpu, query_values_on_cpu, &err, true); + if (err) + goto out; + + if (cpu_family == CPU_HW_PSTATE) + khz = find_khz_freq_from_pstate(data->powernow_table, + data->currpstate); + else + khz = find_khz_freq_from_fid(data->currfid); + + +out: + return khz; +} + +static void _cpb_toggle_msrs(bool t) +{ + int cpu; + + get_online_cpus(); + + rdmsr_on_cpus(cpu_online_mask, MSR_K7_HWCR, msrs); + + for_each_cpu(cpu, cpu_online_mask) { + struct msr *reg = per_cpu_ptr(msrs, cpu); + if (t) + reg->l &= ~BIT(25); + else + reg->l |= BIT(25); + } + wrmsr_on_cpus(cpu_online_mask, MSR_K7_HWCR, msrs); + + put_online_cpus(); +} + +/* + * Switch on/off core performance boosting. + * + * 0=disable + * 1=enable. + */ +static void cpb_toggle(bool t) +{ + if (!cpb_capable) + return; + + if (t && !cpb_enabled) { + cpb_enabled = true; + _cpb_toggle_msrs(t); + printk(KERN_INFO PFX "Core Boosting enabled.\n"); + } else if (!t && cpb_enabled) { + cpb_enabled = false; + _cpb_toggle_msrs(t); + printk(KERN_INFO PFX "Core Boosting disabled.\n"); + } +} + +static ssize_t store_cpb(struct cpufreq_policy *policy, const char *buf, + size_t count) +{ + int ret = -EINVAL; + unsigned long val = 0; + + ret = strict_strtoul(buf, 10, &val); + if (!ret && (val == 0 || val == 1) && cpb_capable) + cpb_toggle(val); + else + return -EINVAL; + + return count; +} + +static ssize_t show_cpb(struct cpufreq_policy *policy, char *buf) +{ + return sprintf(buf, "%u\n", cpb_enabled); +} + +#define define_one_rw(_name) \ +static struct freq_attr _name = \ +__ATTR(_name, 0644, show_##_name, store_##_name) + +define_one_rw(cpb); + +static struct freq_attr *powernow_k8_attr[] = { + &cpufreq_freq_attr_scaling_available_freqs, + &cpb, + NULL, +}; + +static struct cpufreq_driver cpufreq_amd64_driver = { + .verify = powernowk8_verify, + .target = powernowk8_target, + .bios_limit = acpi_processor_get_bios_limit, + .init = powernowk8_cpu_init, + .exit = __devexit_p(powernowk8_cpu_exit), + .get = powernowk8_get, + .name = "powernow-k8", + .owner = THIS_MODULE, + .attr = powernow_k8_attr, +}; + +/* + * Clear the boost-disable flag on the CPU_DOWN path so that this cpu + * cannot block the remaining ones from boosting. On the CPU_UP path we + * simply keep the boost-disable flag in sync with the current global + * state. + */ +static int cpb_notify(struct notifier_block *nb, unsigned long action, + void *hcpu) +{ + unsigned cpu = (long)hcpu; + u32 lo, hi; + + switch (action) { + case CPU_UP_PREPARE: + case CPU_UP_PREPARE_FROZEN: + + if (!cpb_enabled) { + rdmsr_on_cpu(cpu, MSR_K7_HWCR, &lo, &hi); + lo |= BIT(25); + wrmsr_on_cpu(cpu, MSR_K7_HWCR, lo, hi); + } + break; + + case CPU_DOWN_PREPARE: + case CPU_DOWN_PREPARE_FROZEN: + rdmsr_on_cpu(cpu, MSR_K7_HWCR, &lo, &hi); + lo &= ~BIT(25); + wrmsr_on_cpu(cpu, MSR_K7_HWCR, lo, hi); + break; + + default: + break; + } + + return NOTIFY_OK; +} + +static struct notifier_block cpb_nb = { + .notifier_call = cpb_notify, +}; + +/* driver entry point for init */ +static int __cpuinit powernowk8_init(void) +{ + unsigned int i, supported_cpus = 0, cpu; + int rv; + + for_each_online_cpu(i) { + int rc; + smp_call_function_single(i, check_supported_cpu, &rc, 1); + if (rc == 0) + supported_cpus++; + } + + if (supported_cpus != num_online_cpus()) + return -ENODEV; + + printk(KERN_INFO PFX "Found %d %s (%d cpu cores) (" VERSION ")\n", + num_online_nodes(), boot_cpu_data.x86_model_id, supported_cpus); + + if (boot_cpu_has(X86_FEATURE_CPB)) { + + cpb_capable = true; + + msrs = msrs_alloc(); + if (!msrs) { + printk(KERN_ERR "%s: Error allocating msrs!\n", __func__); + return -ENOMEM; + } + + register_cpu_notifier(&cpb_nb); + + rdmsr_on_cpus(cpu_online_mask, MSR_K7_HWCR, msrs); + + for_each_cpu(cpu, cpu_online_mask) { + struct msr *reg = per_cpu_ptr(msrs, cpu); + cpb_enabled |= !(!!(reg->l & BIT(25))); + } + + printk(KERN_INFO PFX "Core Performance Boosting: %s.\n", + (cpb_enabled ? "on" : "off")); + } + + rv = cpufreq_register_driver(&cpufreq_amd64_driver); + if (rv < 0 && boot_cpu_has(X86_FEATURE_CPB)) { + unregister_cpu_notifier(&cpb_nb); + msrs_free(msrs); + msrs = NULL; + } + return rv; +} + +/* driver entry point for term */ +static void __exit powernowk8_exit(void) +{ + pr_debug("exit\n"); + + if (boot_cpu_has(X86_FEATURE_CPB)) { + msrs_free(msrs); + msrs = NULL; + + unregister_cpu_notifier(&cpb_nb); + } + + cpufreq_unregister_driver(&cpufreq_amd64_driver); +} + +MODULE_AUTHOR("Paul Devriendt and " + "Mark Langsdorf "); +MODULE_DESCRIPTION("AMD Athlon 64 and Opteron processor frequency driver."); +MODULE_LICENSE("GPL"); + +late_initcall(powernowk8_init); +module_exit(powernowk8_exit); diff --git a/drivers/cpufreq/powernow-k8.h b/drivers/cpufreq/powernow-k8.h new file mode 100644 index 0000000..3744d26 --- /dev/null +++ b/drivers/cpufreq/powernow-k8.h @@ -0,0 +1,222 @@ +/* + * (c) 2003-2006 Advanced Micro Devices, Inc. + * Your use of this code is subject to the terms and conditions of the + * GNU general public license version 2. See "COPYING" or + * http://www.gnu.org/licenses/gpl.html + */ + +enum pstate { + HW_PSTATE_INVALID = 0xff, + HW_PSTATE_0 = 0, + HW_PSTATE_1 = 1, + HW_PSTATE_2 = 2, + HW_PSTATE_3 = 3, + HW_PSTATE_4 = 4, + HW_PSTATE_5 = 5, + HW_PSTATE_6 = 6, + HW_PSTATE_7 = 7, +}; + +struct powernow_k8_data { + unsigned int cpu; + + u32 numps; /* number of p-states */ + u32 batps; /* number of p-states supported on battery */ + u32 max_hw_pstate; /* maximum legal hardware pstate */ + + /* these values are constant when the PSB is used to determine + * vid/fid pairings, but are modified during the ->target() call + * when ACPI is used */ + u32 rvo; /* ramp voltage offset */ + u32 irt; /* isochronous relief time */ + u32 vidmvs; /* usable value calculated from mvs */ + u32 vstable; /* voltage stabilization time, units 20 us */ + u32 plllock; /* pll lock time, units 1 us */ + u32 exttype; /* extended interface = 1 */ + + /* keep track of the current fid / vid or pstate */ + u32 currvid; + u32 currfid; + enum pstate currpstate; + + /* the powernow_table includes all frequency and vid/fid pairings: + * fid are the lower 8 bits of the index, vid are the upper 8 bits. + * frequency is in kHz */ + struct cpufreq_frequency_table *powernow_table; + + /* the acpi table needs to be kept. it's only available if ACPI was + * used to determine valid frequency/vid/fid states */ + struct acpi_processor_performance acpi_data; + + /* we need to keep track of associated cores, but let cpufreq + * handle hotplug events - so just point at cpufreq pol->cpus + * structure */ + struct cpumask *available_cores; +}; + +/* processor's cpuid instruction support */ +#define CPUID_PROCESSOR_SIGNATURE 1 /* function 1 */ +#define CPUID_XFAM 0x0ff00000 /* extended family */ +#define CPUID_XFAM_K8 0 +#define CPUID_XMOD 0x000f0000 /* extended model */ +#define CPUID_XMOD_REV_MASK 0x000c0000 +#define CPUID_XFAM_10H 0x00100000 /* family 0x10 */ +#define CPUID_USE_XFAM_XMOD 0x00000f00 +#define CPUID_GET_MAX_CAPABILITIES 0x80000000 +#define CPUID_FREQ_VOLT_CAPABILITIES 0x80000007 +#define P_STATE_TRANSITION_CAPABLE 6 + +/* Model Specific Registers for p-state transitions. MSRs are 64-bit. For */ +/* writes (wrmsr - opcode 0f 30), the register number is placed in ecx, and */ +/* the value to write is placed in edx:eax. For reads (rdmsr - opcode 0f 32), */ +/* the register number is placed in ecx, and the data is returned in edx:eax. */ + +#define MSR_FIDVID_CTL 0xc0010041 +#define MSR_FIDVID_STATUS 0xc0010042 + +/* Field definitions within the FID VID Low Control MSR : */ +#define MSR_C_LO_INIT_FID_VID 0x00010000 +#define MSR_C_LO_NEW_VID 0x00003f00 +#define MSR_C_LO_NEW_FID 0x0000003f +#define MSR_C_LO_VID_SHIFT 8 + +/* Field definitions within the FID VID High Control MSR : */ +#define MSR_C_HI_STP_GNT_TO 0x000fffff + +/* Field definitions within the FID VID Low Status MSR : */ +#define MSR_S_LO_CHANGE_PENDING 0x80000000 /* cleared when completed */ +#define MSR_S_LO_MAX_RAMP_VID 0x3f000000 +#define MSR_S_LO_MAX_FID 0x003f0000 +#define MSR_S_LO_START_FID 0x00003f00 +#define MSR_S_LO_CURRENT_FID 0x0000003f + +/* Field definitions within the FID VID High Status MSR : */ +#define MSR_S_HI_MIN_WORKING_VID 0x3f000000 +#define MSR_S_HI_MAX_WORKING_VID 0x003f0000 +#define MSR_S_HI_START_VID 0x00003f00 +#define MSR_S_HI_CURRENT_VID 0x0000003f +#define MSR_C_HI_STP_GNT_BENIGN 0x00000001 + + +/* Hardware Pstate _PSS and MSR definitions */ +#define USE_HW_PSTATE 0x00000080 +#define HW_PSTATE_MASK 0x00000007 +#define HW_PSTATE_VALID_MASK 0x80000000 +#define HW_PSTATE_MAX_MASK 0x000000f0 +#define HW_PSTATE_MAX_SHIFT 4 +#define MSR_PSTATE_DEF_BASE 0xc0010064 /* base of Pstate MSRs */ +#define MSR_PSTATE_STATUS 0xc0010063 /* Pstate Status MSR */ +#define MSR_PSTATE_CTRL 0xc0010062 /* Pstate control MSR */ +#define MSR_PSTATE_CUR_LIMIT 0xc0010061 /* pstate current limit MSR */ + +/* define the two driver architectures */ +#define CPU_OPTERON 0 +#define CPU_HW_PSTATE 1 + + +/* + * There are restrictions frequencies have to follow: + * - only 1 entry in the low fid table ( <=1.4GHz ) + * - lowest entry in the high fid table must be >= 2 * the entry in the + * low fid table + * - lowest entry in the high fid table must be a <= 200MHz + 2 * the entry + * in the low fid table + * - the parts can only step at <= 200 MHz intervals, odd fid values are + * supported in revision G and later revisions. + * - lowest frequency must be >= interprocessor hypertransport link speed + * (only applies to MP systems obviously) + */ + +/* fids (frequency identifiers) are arranged in 2 tables - lo and hi */ +#define LO_FID_TABLE_TOP 7 /* fid values marking the boundary */ +#define HI_FID_TABLE_BOTTOM 8 /* between the low and high tables */ + +#define LO_VCOFREQ_TABLE_TOP 1400 /* corresponding vco frequency values */ +#define HI_VCOFREQ_TABLE_BOTTOM 1600 + +#define MIN_FREQ_RESOLUTION 200 /* fids jump by 2 matching freq jumps by 200 */ + +#define MAX_FID 0x2a /* Spec only gives FID values as far as 5 GHz */ +#define LEAST_VID 0x3e /* Lowest (numerically highest) useful vid value */ + +#define MIN_FREQ 800 /* Min and max freqs, per spec */ +#define MAX_FREQ 5000 + +#define INVALID_FID_MASK 0xffffffc0 /* not a valid fid if these bits are set */ +#define INVALID_VID_MASK 0xffffffc0 /* not a valid vid if these bits are set */ + +#define VID_OFF 0x3f + +#define STOP_GRANT_5NS 1 /* min poss memory access latency for voltage change */ + +#define PLL_LOCK_CONVERSION (1000/5) /* ms to ns, then divide by clock period */ + +#define MAXIMUM_VID_STEPS 1 /* Current cpus only allow a single step of 25mV */ +#define VST_UNITS_20US 20 /* Voltage Stabilization Time is in units of 20us */ + +/* + * Most values of interest are encoded in a single field of the _PSS + * entries: the "control" value. + */ + +#define IRT_SHIFT 30 +#define RVO_SHIFT 28 +#define EXT_TYPE_SHIFT 27 +#define PLL_L_SHIFT 20 +#define MVS_SHIFT 18 +#define VST_SHIFT 11 +#define VID_SHIFT 6 +#define IRT_MASK 3 +#define RVO_MASK 3 +#define EXT_TYPE_MASK 1 +#define PLL_L_MASK 0x7f +#define MVS_MASK 3 +#define VST_MASK 0x7f +#define VID_MASK 0x1f +#define FID_MASK 0x1f +#define EXT_VID_MASK 0x3f +#define EXT_FID_MASK 0x3f + + +/* + * Version 1.4 of the PSB table. This table is constructed by BIOS and is + * to tell the OS's power management driver which VIDs and FIDs are + * supported by this particular processor. + * If the data in the PSB / PST is wrong, then this driver will program the + * wrong values into hardware, which is very likely to lead to a crash. + */ + +#define PSB_ID_STRING "AMDK7PNOW!" +#define PSB_ID_STRING_LEN 10 + +#define PSB_VERSION_1_4 0x14 + +struct psb_s { + u8 signature[10]; + u8 tableversion; + u8 flags1; + u16 vstable; + u8 flags2; + u8 num_tables; + u32 cpuid; + u8 plllocktime; + u8 maxfid; + u8 maxvid; + u8 numps; +}; + +/* Pairs of fid/vid values are appended to the version 1.4 PSB table. */ +struct pst_s { + u8 fid; + u8 vid; +}; + +static int core_voltage_pre_transition(struct powernow_k8_data *data, + u32 reqvid, u32 regfid); +static int core_voltage_post_transition(struct powernow_k8_data *data, u32 reqvid); +static int core_frequency_transition(struct powernow_k8_data *data, u32 reqfid); + +static void powernow_k8_acpi_pst_values(struct powernow_k8_data *data, unsigned int index); + +static int fill_powernow_table_pstate(struct powernow_k8_data *data, struct cpufreq_frequency_table *powernow_table); +static int fill_powernow_table_fidvid(struct powernow_k8_data *data, struct cpufreq_frequency_table *powernow_table); diff --git a/drivers/cpufreq/sc520_freq.c b/drivers/cpufreq/sc520_freq.c new file mode 100644 index 0000000..1e205e6 --- /dev/null +++ b/drivers/cpufreq/sc520_freq.c @@ -0,0 +1,192 @@ +/* + * sc520_freq.c: cpufreq driver for the AMD Elan sc520 + * + * Copyright (C) 2005 Sean Young + * + * 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. + * + * Based on elanfreq.c + * + * 2005-03-30: - initial revision + */ + +#include +#include +#include + +#include +#include +#include +#include + +#include + +#define MMCR_BASE 0xfffef000 /* The default base address */ +#define OFFS_CPUCTL 0x2 /* CPU Control Register */ + +static __u8 __iomem *cpuctl; + +#define PFX "sc520_freq: " + +static struct cpufreq_frequency_table sc520_freq_table[] = { + {0x01, 100000}, + {0x02, 133000}, + {0, CPUFREQ_TABLE_END}, +}; + +static unsigned int sc520_freq_get_cpu_frequency(unsigned int cpu) +{ + u8 clockspeed_reg = *cpuctl; + + switch (clockspeed_reg & 0x03) { + default: + printk(KERN_ERR PFX "error: cpuctl register has unexpected " + "value %02x\n", clockspeed_reg); + case 0x01: + return 100000; + case 0x02: + return 133000; + } +} + +static void sc520_freq_set_cpu_state(unsigned int state) +{ + + struct cpufreq_freqs freqs; + u8 clockspeed_reg; + + freqs.old = sc520_freq_get_cpu_frequency(0); + freqs.new = sc520_freq_table[state].frequency; + freqs.cpu = 0; /* AMD Elan is UP */ + + cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE); + + pr_debug("attempting to set frequency to %i kHz\n", + sc520_freq_table[state].frequency); + + local_irq_disable(); + + clockspeed_reg = *cpuctl & ~0x03; + *cpuctl = clockspeed_reg | sc520_freq_table[state].index; + + local_irq_enable(); + + cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE); +}; + +static int sc520_freq_verify(struct cpufreq_policy *policy) +{ + return cpufreq_frequency_table_verify(policy, &sc520_freq_table[0]); +} + +static int sc520_freq_target(struct cpufreq_policy *policy, + unsigned int target_freq, + unsigned int relation) +{ + unsigned int newstate = 0; + + if (cpufreq_frequency_table_target(policy, sc520_freq_table, + target_freq, relation, &newstate)) + return -EINVAL; + + sc520_freq_set_cpu_state(newstate); + + return 0; +} + + +/* + * Module init and exit code + */ + +static int sc520_freq_cpu_init(struct cpufreq_policy *policy) +{ + struct cpuinfo_x86 *c = &cpu_data(0); + int result; + + /* capability check */ + if (c->x86_vendor != X86_VENDOR_AMD || + c->x86 != 4 || c->x86_model != 9) + return -ENODEV; + + /* cpuinfo and default policy values */ + policy->cpuinfo.transition_latency = 1000000; /* 1ms */ + policy->cur = sc520_freq_get_cpu_frequency(0); + + result = cpufreq_frequency_table_cpuinfo(policy, sc520_freq_table); + if (result) + return result; + + cpufreq_frequency_table_get_attr(sc520_freq_table, policy->cpu); + + return 0; +} + + +static int sc520_freq_cpu_exit(struct cpufreq_policy *policy) +{ + cpufreq_frequency_table_put_attr(policy->cpu); + return 0; +} + + +static struct freq_attr *sc520_freq_attr[] = { + &cpufreq_freq_attr_scaling_available_freqs, + NULL, +}; + + +static struct cpufreq_driver sc520_freq_driver = { + .get = sc520_freq_get_cpu_frequency, + .verify = sc520_freq_verify, + .target = sc520_freq_target, + .init = sc520_freq_cpu_init, + .exit = sc520_freq_cpu_exit, + .name = "sc520_freq", + .owner = THIS_MODULE, + .attr = sc520_freq_attr, +}; + + +static int __init sc520_freq_init(void) +{ + struct cpuinfo_x86 *c = &cpu_data(0); + int err; + + /* Test if we have the right hardware */ + if (c->x86_vendor != X86_VENDOR_AMD || + c->x86 != 4 || c->x86_model != 9) { + pr_debug("no Elan SC520 processor found!\n"); + return -ENODEV; + } + cpuctl = ioremap((unsigned long)(MMCR_BASE + OFFS_CPUCTL), 1); + if (!cpuctl) { + printk(KERN_ERR "sc520_freq: error: failed to remap memory\n"); + return -ENOMEM; + } + + err = cpufreq_register_driver(&sc520_freq_driver); + if (err) + iounmap(cpuctl); + + return err; +} + + +static void __exit sc520_freq_exit(void) +{ + cpufreq_unregister_driver(&sc520_freq_driver); + iounmap(cpuctl); +} + + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Sean Young "); +MODULE_DESCRIPTION("cpufreq driver for AMD's Elan sc520 CPU"); + +module_init(sc520_freq_init); +module_exit(sc520_freq_exit); + diff --git a/drivers/cpufreq/speedstep-centrino.c b/drivers/cpufreq/speedstep-centrino.c new file mode 100644 index 0000000..6ea3455 --- /dev/null +++ b/drivers/cpufreq/speedstep-centrino.c @@ -0,0 +1,633 @@ +/* + * cpufreq driver for Enhanced SpeedStep, as found in Intel's Pentium + * M (part of the Centrino chipset). + * + * Since the original Pentium M, most new Intel CPUs support Enhanced + * SpeedStep. + * + * Despite the "SpeedStep" in the name, this is almost entirely unlike + * traditional SpeedStep. + * + * Modelled on speedstep.c + * + * Copyright (C) 2003 Jeremy Fitzhardinge + */ + +#include +#include +#include +#include +#include /* current */ +#include +#include +#include + +#include +#include +#include + +#define PFX "speedstep-centrino: " +#define MAINTAINER "cpufreq@vger.kernel.org" + +#define INTEL_MSR_RANGE (0xffff) + +struct cpu_id +{ + __u8 x86; /* CPU family */ + __u8 x86_model; /* model */ + __u8 x86_mask; /* stepping */ +}; + +enum { + CPU_BANIAS, + CPU_DOTHAN_A1, + CPU_DOTHAN_A2, + CPU_DOTHAN_B0, + CPU_MP4HT_D0, + CPU_MP4HT_E0, +}; + +static const struct cpu_id cpu_ids[] = { + [CPU_BANIAS] = { 6, 9, 5 }, + [CPU_DOTHAN_A1] = { 6, 13, 1 }, + [CPU_DOTHAN_A2] = { 6, 13, 2 }, + [CPU_DOTHAN_B0] = { 6, 13, 6 }, + [CPU_MP4HT_D0] = {15, 3, 4 }, + [CPU_MP4HT_E0] = {15, 4, 1 }, +}; +#define N_IDS ARRAY_SIZE(cpu_ids) + +struct cpu_model +{ + const struct cpu_id *cpu_id; + const char *model_name; + unsigned max_freq; /* max clock in kHz */ + + struct cpufreq_frequency_table *op_points; /* clock/voltage pairs */ +}; +static int centrino_verify_cpu_id(const struct cpuinfo_x86 *c, + const struct cpu_id *x); + +/* Operating points for current CPU */ +static DEFINE_PER_CPU(struct cpu_model *, centrino_model); +static DEFINE_PER_CPU(const struct cpu_id *, centrino_cpu); + +static struct cpufreq_driver centrino_driver; + +#ifdef CONFIG_X86_SPEEDSTEP_CENTRINO_TABLE + +/* Computes the correct form for IA32_PERF_CTL MSR for a particular + frequency/voltage operating point; frequency in MHz, volts in mV. + This is stored as "index" in the structure. */ +#define OP(mhz, mv) \ + { \ + .frequency = (mhz) * 1000, \ + .index = (((mhz)/100) << 8) | ((mv - 700) / 16) \ + } + +/* + * These voltage tables were derived from the Intel Pentium M + * datasheet, document 25261202.pdf, Table 5. I have verified they + * are consistent with my IBM ThinkPad X31, which has a 1.3GHz Pentium + * M. + */ + +/* Ultra Low Voltage Intel Pentium M processor 900MHz (Banias) */ +static struct cpufreq_frequency_table banias_900[] = +{ + OP(600, 844), + OP(800, 988), + OP(900, 1004), + { .frequency = CPUFREQ_TABLE_END } +}; + +/* Ultra Low Voltage Intel Pentium M processor 1000MHz (Banias) */ +static struct cpufreq_frequency_table banias_1000[] = +{ + OP(600, 844), + OP(800, 972), + OP(900, 988), + OP(1000, 1004), + { .frequency = CPUFREQ_TABLE_END } +}; + +/* Low Voltage Intel Pentium M processor 1.10GHz (Banias) */ +static struct cpufreq_frequency_table banias_1100[] = +{ + OP( 600, 956), + OP( 800, 1020), + OP( 900, 1100), + OP(1000, 1164), + OP(1100, 1180), + { .frequency = CPUFREQ_TABLE_END } +}; + + +/* Low Voltage Intel Pentium M processor 1.20GHz (Banias) */ +static struct cpufreq_frequency_table banias_1200[] = +{ + OP( 600, 956), + OP( 800, 1004), + OP( 900, 1020), + OP(1000, 1100), + OP(1100, 1164), + OP(1200, 1180), + { .frequency = CPUFREQ_TABLE_END } +}; + +/* Intel Pentium M processor 1.30GHz (Banias) */ +static struct cpufreq_frequency_table banias_1300[] = +{ + OP( 600, 956), + OP( 800, 1260), + OP(1000, 1292), + OP(1200, 1356), + OP(1300, 1388), + { .frequency = CPUFREQ_TABLE_END } +}; + +/* Intel Pentium M processor 1.40GHz (Banias) */ +static struct cpufreq_frequency_table banias_1400[] = +{ + OP( 600, 956), + OP( 800, 1180), + OP(1000, 1308), + OP(1200, 1436), + OP(1400, 1484), + { .frequency = CPUFREQ_TABLE_END } +}; + +/* Intel Pentium M processor 1.50GHz (Banias) */ +static struct cpufreq_frequency_table banias_1500[] = +{ + OP( 600, 956), + OP( 800, 1116), + OP(1000, 1228), + OP(1200, 1356), + OP(1400, 1452), + OP(1500, 1484), + { .frequency = CPUFREQ_TABLE_END } +}; + +/* Intel Pentium M processor 1.60GHz (Banias) */ +static struct cpufreq_frequency_table banias_1600[] = +{ + OP( 600, 956), + OP( 800, 1036), + OP(1000, 1164), + OP(1200, 1276), + OP(1400, 1420), + OP(1600, 1484), + { .frequency = CPUFREQ_TABLE_END } +}; + +/* Intel Pentium M processor 1.70GHz (Banias) */ +static struct cpufreq_frequency_table banias_1700[] = +{ + OP( 600, 956), + OP( 800, 1004), + OP(1000, 1116), + OP(1200, 1228), + OP(1400, 1308), + OP(1700, 1484), + { .frequency = CPUFREQ_TABLE_END } +}; +#undef OP + +#define _BANIAS(cpuid, max, name) \ +{ .cpu_id = cpuid, \ + .model_name = "Intel(R) Pentium(R) M processor " name "MHz", \ + .max_freq = (max)*1000, \ + .op_points = banias_##max, \ +} +#define BANIAS(max) _BANIAS(&cpu_ids[CPU_BANIAS], max, #max) + +/* CPU models, their operating frequency range, and freq/voltage + operating points */ +static struct cpu_model models[] = +{ + _BANIAS(&cpu_ids[CPU_BANIAS], 900, " 900"), + BANIAS(1000), + BANIAS(1100), + BANIAS(1200), + BANIAS(1300), + BANIAS(1400), + BANIAS(1500), + BANIAS(1600), + BANIAS(1700), + + /* NULL model_name is a wildcard */ + { &cpu_ids[CPU_DOTHAN_A1], NULL, 0, NULL }, + { &cpu_ids[CPU_DOTHAN_A2], NULL, 0, NULL }, + { &cpu_ids[CPU_DOTHAN_B0], NULL, 0, NULL }, + { &cpu_ids[CPU_MP4HT_D0], NULL, 0, NULL }, + { &cpu_ids[CPU_MP4HT_E0], NULL, 0, NULL }, + + { NULL, } +}; +#undef _BANIAS +#undef BANIAS + +static int centrino_cpu_init_table(struct cpufreq_policy *policy) +{ + struct cpuinfo_x86 *cpu = &cpu_data(policy->cpu); + struct cpu_model *model; + + for(model = models; model->cpu_id != NULL; model++) + if (centrino_verify_cpu_id(cpu, model->cpu_id) && + (model->model_name == NULL || + strcmp(cpu->x86_model_id, model->model_name) == 0)) + break; + + if (model->cpu_id == NULL) { + /* No match at all */ + pr_debug("no support for CPU model \"%s\": " + "send /proc/cpuinfo to " MAINTAINER "\n", + cpu->x86_model_id); + return -ENOENT; + } + + if (model->op_points == NULL) { + /* Matched a non-match */ + pr_debug("no table support for CPU model \"%s\"\n", + cpu->x86_model_id); + pr_debug("try using the acpi-cpufreq driver\n"); + return -ENOENT; + } + + per_cpu(centrino_model, policy->cpu) = model; + + pr_debug("found \"%s\": max frequency: %dkHz\n", + model->model_name, model->max_freq); + + return 0; +} + +#else +static inline int centrino_cpu_init_table(struct cpufreq_policy *policy) +{ + return -ENODEV; +} +#endif /* CONFIG_X86_SPEEDSTEP_CENTRINO_TABLE */ + +static int centrino_verify_cpu_id(const struct cpuinfo_x86 *c, + const struct cpu_id *x) +{ + if ((c->x86 == x->x86) && + (c->x86_model == x->x86_model) && + (c->x86_mask == x->x86_mask)) + return 1; + return 0; +} + +/* To be called only after centrino_model is initialized */ +static unsigned extract_clock(unsigned msr, unsigned int cpu, int failsafe) +{ + int i; + + /* + * Extract clock in kHz from PERF_CTL value + * for centrino, as some DSDTs are buggy. + * Ideally, this can be done using the acpi_data structure. + */ + if ((per_cpu(centrino_cpu, cpu) == &cpu_ids[CPU_BANIAS]) || + (per_cpu(centrino_cpu, cpu) == &cpu_ids[CPU_DOTHAN_A1]) || + (per_cpu(centrino_cpu, cpu) == &cpu_ids[CPU_DOTHAN_B0])) { + msr = (msr >> 8) & 0xff; + return msr * 100000; + } + + if ((!per_cpu(centrino_model, cpu)) || + (!per_cpu(centrino_model, cpu)->op_points)) + return 0; + + msr &= 0xffff; + for (i = 0; + per_cpu(centrino_model, cpu)->op_points[i].frequency + != CPUFREQ_TABLE_END; + i++) { + if (msr == per_cpu(centrino_model, cpu)->op_points[i].index) + return per_cpu(centrino_model, cpu)-> + op_points[i].frequency; + } + if (failsafe) + return per_cpu(centrino_model, cpu)->op_points[i-1].frequency; + else + return 0; +} + +/* Return the current CPU frequency in kHz */ +static unsigned int get_cur_freq(unsigned int cpu) +{ + unsigned l, h; + unsigned clock_freq; + + rdmsr_on_cpu(cpu, MSR_IA32_PERF_STATUS, &l, &h); + clock_freq = extract_clock(l, cpu, 0); + + if (unlikely(clock_freq == 0)) { + /* + * On some CPUs, we can see transient MSR values (which are + * not present in _PSS), while CPU is doing some automatic + * P-state transition (like TM2). Get the last freq set + * in PERF_CTL. + */ + rdmsr_on_cpu(cpu, MSR_IA32_PERF_CTL, &l, &h); + clock_freq = extract_clock(l, cpu, 1); + } + return clock_freq; +} + + +static int centrino_cpu_init(struct cpufreq_policy *policy) +{ + struct cpuinfo_x86 *cpu = &cpu_data(policy->cpu); + unsigned freq; + unsigned l, h; + int ret; + int i; + + /* Only Intel makes Enhanced Speedstep-capable CPUs */ + if (cpu->x86_vendor != X86_VENDOR_INTEL || + !cpu_has(cpu, X86_FEATURE_EST)) + return -ENODEV; + + if (cpu_has(cpu, X86_FEATURE_CONSTANT_TSC)) + centrino_driver.flags |= CPUFREQ_CONST_LOOPS; + + if (policy->cpu != 0) + return -ENODEV; + + for (i = 0; i < N_IDS; i++) + if (centrino_verify_cpu_id(cpu, &cpu_ids[i])) + break; + + if (i != N_IDS) + per_cpu(centrino_cpu, policy->cpu) = &cpu_ids[i]; + + if (!per_cpu(centrino_cpu, policy->cpu)) { + pr_debug("found unsupported CPU with " + "Enhanced SpeedStep: send /proc/cpuinfo to " + MAINTAINER "\n"); + return -ENODEV; + } + + if (centrino_cpu_init_table(policy)) { + return -ENODEV; + } + + /* Check to see if Enhanced SpeedStep is enabled, and try to + enable it if not. */ + rdmsr(MSR_IA32_MISC_ENABLE, l, h); + + if (!(l & MSR_IA32_MISC_ENABLE_ENHANCED_SPEEDSTEP)) { + l |= MSR_IA32_MISC_ENABLE_ENHANCED_SPEEDSTEP; + pr_debug("trying to enable Enhanced SpeedStep (%x)\n", l); + wrmsr(MSR_IA32_MISC_ENABLE, l, h); + + /* check to see if it stuck */ + rdmsr(MSR_IA32_MISC_ENABLE, l, h); + if (!(l & MSR_IA32_MISC_ENABLE_ENHANCED_SPEEDSTEP)) { + printk(KERN_INFO PFX + "couldn't enable Enhanced SpeedStep\n"); + return -ENODEV; + } + } + + freq = get_cur_freq(policy->cpu); + policy->cpuinfo.transition_latency = 10000; + /* 10uS transition latency */ + policy->cur = freq; + + pr_debug("centrino_cpu_init: cur=%dkHz\n", policy->cur); + + ret = cpufreq_frequency_table_cpuinfo(policy, + per_cpu(centrino_model, policy->cpu)->op_points); + if (ret) + return (ret); + + cpufreq_frequency_table_get_attr( + per_cpu(centrino_model, policy->cpu)->op_points, policy->cpu); + + return 0; +} + +static int centrino_cpu_exit(struct cpufreq_policy *policy) +{ + unsigned int cpu = policy->cpu; + + if (!per_cpu(centrino_model, cpu)) + return -ENODEV; + + cpufreq_frequency_table_put_attr(cpu); + + per_cpu(centrino_model, cpu) = NULL; + + return 0; +} + +/** + * centrino_verify - verifies a new CPUFreq policy + * @policy: new policy + * + * Limit must be within this model's frequency range at least one + * border included. + */ +static int centrino_verify (struct cpufreq_policy *policy) +{ + return cpufreq_frequency_table_verify(policy, + per_cpu(centrino_model, policy->cpu)->op_points); +} + +/** + * centrino_setpolicy - set a new CPUFreq policy + * @policy: new policy + * @target_freq: the target frequency + * @relation: how that frequency relates to achieved frequency + * (CPUFREQ_RELATION_L or CPUFREQ_RELATION_H) + * + * Sets a new CPUFreq policy. + */ +static int centrino_target (struct cpufreq_policy *policy, + unsigned int target_freq, + unsigned int relation) +{ + unsigned int newstate = 0; + unsigned int msr, oldmsr = 0, h = 0, cpu = policy->cpu; + struct cpufreq_freqs freqs; + int retval = 0; + unsigned int j, k, first_cpu, tmp; + cpumask_var_t covered_cpus; + + if (unlikely(!zalloc_cpumask_var(&covered_cpus, GFP_KERNEL))) + return -ENOMEM; + + if (unlikely(per_cpu(centrino_model, cpu) == NULL)) { + retval = -ENODEV; + goto out; + } + + if (unlikely(cpufreq_frequency_table_target(policy, + per_cpu(centrino_model, cpu)->op_points, + target_freq, + relation, + &newstate))) { + retval = -EINVAL; + goto out; + } + + first_cpu = 1; + for_each_cpu(j, policy->cpus) { + int good_cpu; + + /* cpufreq holds the hotplug lock, so we are safe here */ + if (!cpu_online(j)) + continue; + + /* + * Support for SMP systems. + * Make sure we are running on CPU that wants to change freq + */ + if (policy->shared_type == CPUFREQ_SHARED_TYPE_ANY) + good_cpu = cpumask_any_and(policy->cpus, + cpu_online_mask); + else + good_cpu = j; + + if (good_cpu >= nr_cpu_ids) { + pr_debug("couldn't limit to CPUs in this domain\n"); + retval = -EAGAIN; + if (first_cpu) { + /* We haven't started the transition yet. */ + goto out; + } + break; + } + + msr = per_cpu(centrino_model, cpu)->op_points[newstate].index; + + if (first_cpu) { + rdmsr_on_cpu(good_cpu, MSR_IA32_PERF_CTL, &oldmsr, &h); + if (msr == (oldmsr & 0xffff)) { + pr_debug("no change needed - msr was and needs " + "to be %x\n", oldmsr); + retval = 0; + goto out; + } + + freqs.old = extract_clock(oldmsr, cpu, 0); + freqs.new = extract_clock(msr, cpu, 0); + + pr_debug("target=%dkHz old=%d new=%d msr=%04x\n", + target_freq, freqs.old, freqs.new, msr); + + for_each_cpu(k, policy->cpus) { + if (!cpu_online(k)) + continue; + freqs.cpu = k; + cpufreq_notify_transition(&freqs, + CPUFREQ_PRECHANGE); + } + + first_cpu = 0; + /* all but 16 LSB are reserved, treat them with care */ + oldmsr &= ~0xffff; + msr &= 0xffff; + oldmsr |= msr; + } + + wrmsr_on_cpu(good_cpu, MSR_IA32_PERF_CTL, oldmsr, h); + if (policy->shared_type == CPUFREQ_SHARED_TYPE_ANY) + break; + + cpumask_set_cpu(j, covered_cpus); + } + + for_each_cpu(k, policy->cpus) { + if (!cpu_online(k)) + continue; + freqs.cpu = k; + cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE); + } + + if (unlikely(retval)) { + /* + * We have failed halfway through the frequency change. + * We have sent callbacks to policy->cpus and + * MSRs have already been written on coverd_cpus. + * Best effort undo.. + */ + + for_each_cpu(j, covered_cpus) + wrmsr_on_cpu(j, MSR_IA32_PERF_CTL, oldmsr, h); + + tmp = freqs.new; + freqs.new = freqs.old; + freqs.old = tmp; + for_each_cpu(j, policy->cpus) { + if (!cpu_online(j)) + continue; + cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE); + cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE); + } + } + retval = 0; + +out: + free_cpumask_var(covered_cpus); + return retval; +} + +static struct freq_attr* centrino_attr[] = { + &cpufreq_freq_attr_scaling_available_freqs, + NULL, +}; + +static struct cpufreq_driver centrino_driver = { + .name = "centrino", /* should be speedstep-centrino, + but there's a 16 char limit */ + .init = centrino_cpu_init, + .exit = centrino_cpu_exit, + .verify = centrino_verify, + .target = centrino_target, + .get = get_cur_freq, + .attr = centrino_attr, + .owner = THIS_MODULE, +}; + + +/** + * centrino_init - initializes the Enhanced SpeedStep CPUFreq driver + * + * Initializes the Enhanced SpeedStep support. Returns -ENODEV on + * unsupported devices, -ENOENT if there's no voltage table for this + * particular CPU model, -EINVAL on problems during initiatization, + * and zero on success. + * + * This is quite picky. Not only does the CPU have to advertise the + * "est" flag in the cpuid capability flags, we look for a specific + * CPU model and stepping, and we need to have the exact model name in + * our voltage tables. That is, be paranoid about not releasing + * someone's valuable magic smoke. + */ +static int __init centrino_init(void) +{ + struct cpuinfo_x86 *cpu = &cpu_data(0); + + if (!cpu_has(cpu, X86_FEATURE_EST)) + return -ENODEV; + + return cpufreq_register_driver(¢rino_driver); +} + +static void __exit centrino_exit(void) +{ + cpufreq_unregister_driver(¢rino_driver); +} + +MODULE_AUTHOR ("Jeremy Fitzhardinge "); +MODULE_DESCRIPTION ("Enhanced SpeedStep driver for Intel Pentium M processors."); +MODULE_LICENSE ("GPL"); + +late_initcall(centrino_init); +module_exit(centrino_exit); diff --git a/drivers/cpufreq/speedstep-ich.c b/drivers/cpufreq/speedstep-ich.c new file mode 100644 index 0000000..a748ce7 --- /dev/null +++ b/drivers/cpufreq/speedstep-ich.c @@ -0,0 +1,448 @@ +/* + * (C) 2001 Dave Jones, Arjan van de ven. + * (C) 2002 - 2003 Dominik Brodowski + * + * Licensed under the terms of the GNU GPL License version 2. + * Based upon reverse engineered information, and on Intel documentation + * for chipsets ICH2-M and ICH3-M. + * + * Many thanks to Ducrot Bruno for finding and fixing the last + * "missing link" for ICH2-M/ICH3-M support, and to Thomas Winkler + * for extensive testing. + * + * BIG FAT DISCLAIMER: Work in progress code. Possibly *dangerous* + */ + + +/********************************************************************* + * SPEEDSTEP - DEFINITIONS * + *********************************************************************/ + +#include +#include +#include +#include +#include +#include + +#include "speedstep-lib.h" + + +/* speedstep_chipset: + * It is necessary to know which chipset is used. As accesses to + * this device occur at various places in this module, we need a + * static struct pci_dev * pointing to that device. + */ +static struct pci_dev *speedstep_chipset_dev; + + +/* speedstep_processor + */ +static enum speedstep_processor speedstep_processor; + +static u32 pmbase; + +/* + * There are only two frequency states for each processor. Values + * are in kHz for the time being. + */ +static struct cpufreq_frequency_table speedstep_freqs[] = { + {SPEEDSTEP_HIGH, 0}, + {SPEEDSTEP_LOW, 0}, + {0, CPUFREQ_TABLE_END}, +}; + + +/** + * speedstep_find_register - read the PMBASE address + * + * Returns: -ENODEV if no register could be found + */ +static int speedstep_find_register(void) +{ + if (!speedstep_chipset_dev) + return -ENODEV; + + /* get PMBASE */ + pci_read_config_dword(speedstep_chipset_dev, 0x40, &pmbase); + if (!(pmbase & 0x01)) { + printk(KERN_ERR "speedstep-ich: could not find speedstep register\n"); + return -ENODEV; + } + + pmbase &= 0xFFFFFFFE; + if (!pmbase) { + printk(KERN_ERR "speedstep-ich: could not find speedstep register\n"); + return -ENODEV; + } + + pr_debug("pmbase is 0x%x\n", pmbase); + return 0; +} + +/** + * speedstep_set_state - set the SpeedStep state + * @state: new processor frequency state (SPEEDSTEP_LOW or SPEEDSTEP_HIGH) + * + * Tries to change the SpeedStep state. Can be called from + * smp_call_function_single. + */ +static void speedstep_set_state(unsigned int state) +{ + u8 pm2_blk; + u8 value; + unsigned long flags; + + if (state > 0x1) + return; + + /* Disable IRQs */ + local_irq_save(flags); + + /* read state */ + value = inb(pmbase + 0x50); + + pr_debug("read at pmbase 0x%x + 0x50 returned 0x%x\n", pmbase, value); + + /* write new state */ + value &= 0xFE; + value |= state; + + pr_debug("writing 0x%x to pmbase 0x%x + 0x50\n", value, pmbase); + + /* Disable bus master arbitration */ + pm2_blk = inb(pmbase + 0x20); + pm2_blk |= 0x01; + outb(pm2_blk, (pmbase + 0x20)); + + /* Actual transition */ + outb(value, (pmbase + 0x50)); + + /* Restore bus master arbitration */ + pm2_blk &= 0xfe; + outb(pm2_blk, (pmbase + 0x20)); + + /* check if transition was successful */ + value = inb(pmbase + 0x50); + + /* Enable IRQs */ + local_irq_restore(flags); + + pr_debug("read at pmbase 0x%x + 0x50 returned 0x%x\n", pmbase, value); + + if (state == (value & 0x1)) + pr_debug("change to %u MHz succeeded\n", + speedstep_get_frequency(speedstep_processor) / 1000); + else + printk(KERN_ERR "cpufreq: change failed - I/O error\n"); + + return; +} + +/* Wrapper for smp_call_function_single. */ +static void _speedstep_set_state(void *_state) +{ + speedstep_set_state(*(unsigned int *)_state); +} + +/** + * speedstep_activate - activate SpeedStep control in the chipset + * + * Tries to activate the SpeedStep status and control registers. + * Returns -EINVAL on an unsupported chipset, and zero on success. + */ +static int speedstep_activate(void) +{ + u16 value = 0; + + if (!speedstep_chipset_dev) + return -EINVAL; + + pci_read_config_word(speedstep_chipset_dev, 0x00A0, &value); + if (!(value & 0x08)) { + value |= 0x08; + pr_debug("activating SpeedStep (TM) registers\n"); + pci_write_config_word(speedstep_chipset_dev, 0x00A0, value); + } + + return 0; +} + + +/** + * speedstep_detect_chipset - detect the Southbridge which contains SpeedStep logic + * + * Detects ICH2-M, ICH3-M and ICH4-M so far. The pci_dev points to + * the LPC bridge / PM module which contains all power-management + * functions. Returns the SPEEDSTEP_CHIPSET_-number for the detected + * chipset, or zero on failure. + */ +static unsigned int speedstep_detect_chipset(void) +{ + speedstep_chipset_dev = pci_get_subsys(PCI_VENDOR_ID_INTEL, + PCI_DEVICE_ID_INTEL_82801DB_12, + PCI_ANY_ID, PCI_ANY_ID, + NULL); + if (speedstep_chipset_dev) + return 4; /* 4-M */ + + speedstep_chipset_dev = pci_get_subsys(PCI_VENDOR_ID_INTEL, + PCI_DEVICE_ID_INTEL_82801CA_12, + PCI_ANY_ID, PCI_ANY_ID, + NULL); + if (speedstep_chipset_dev) + return 3; /* 3-M */ + + + speedstep_chipset_dev = pci_get_subsys(PCI_VENDOR_ID_INTEL, + PCI_DEVICE_ID_INTEL_82801BA_10, + PCI_ANY_ID, PCI_ANY_ID, + NULL); + if (speedstep_chipset_dev) { + /* speedstep.c causes lockups on Dell Inspirons 8000 and + * 8100 which use a pretty old revision of the 82815 + * host brige. Abort on these systems. + */ + static struct pci_dev *hostbridge; + + hostbridge = pci_get_subsys(PCI_VENDOR_ID_INTEL, + PCI_DEVICE_ID_INTEL_82815_MC, + PCI_ANY_ID, PCI_ANY_ID, + NULL); + + if (!hostbridge) + return 2; /* 2-M */ + + if (hostbridge->revision < 5) { + pr_debug("hostbridge does not support speedstep\n"); + speedstep_chipset_dev = NULL; + pci_dev_put(hostbridge); + return 0; + } + + pci_dev_put(hostbridge); + return 2; /* 2-M */ + } + + return 0; +} + +static void get_freq_data(void *_speed) +{ + unsigned int *speed = _speed; + + *speed = speedstep_get_frequency(speedstep_processor); +} + +static unsigned int speedstep_get(unsigned int cpu) +{ + unsigned int speed; + + /* You're supposed to ensure CPU is online. */ + if (smp_call_function_single(cpu, get_freq_data, &speed, 1) != 0) + BUG(); + + pr_debug("detected %u kHz as current frequency\n", speed); + return speed; +} + +/** + * speedstep_target - set a new CPUFreq policy + * @policy: new policy + * @target_freq: the target frequency + * @relation: how that frequency relates to achieved frequency + * (CPUFREQ_RELATION_L or CPUFREQ_RELATION_H) + * + * Sets a new CPUFreq policy. + */ +static int speedstep_target(struct cpufreq_policy *policy, + unsigned int target_freq, + unsigned int relation) +{ + unsigned int newstate = 0, policy_cpu; + struct cpufreq_freqs freqs; + int i; + + if (cpufreq_frequency_table_target(policy, &speedstep_freqs[0], + target_freq, relation, &newstate)) + return -EINVAL; + + policy_cpu = cpumask_any_and(policy->cpus, cpu_online_mask); + freqs.old = speedstep_get(policy_cpu); + freqs.new = speedstep_freqs[newstate].frequency; + freqs.cpu = policy->cpu; + + pr_debug("transiting from %u to %u kHz\n", freqs.old, freqs.new); + + /* no transition necessary */ + if (freqs.old == freqs.new) + return 0; + + for_each_cpu(i, policy->cpus) { + freqs.cpu = i; + cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE); + } + + smp_call_function_single(policy_cpu, _speedstep_set_state, &newstate, + true); + + for_each_cpu(i, policy->cpus) { + freqs.cpu = i; + cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE); + } + + return 0; +} + + +/** + * speedstep_verify - verifies a new CPUFreq policy + * @policy: new policy + * + * Limit must be within speedstep_low_freq and speedstep_high_freq, with + * at least one border included. + */ +static int speedstep_verify(struct cpufreq_policy *policy) +{ + return cpufreq_frequency_table_verify(policy, &speedstep_freqs[0]); +} + +struct get_freqs { + struct cpufreq_policy *policy; + int ret; +}; + +static void get_freqs_on_cpu(void *_get_freqs) +{ + struct get_freqs *get_freqs = _get_freqs; + + get_freqs->ret = + speedstep_get_freqs(speedstep_processor, + &speedstep_freqs[SPEEDSTEP_LOW].frequency, + &speedstep_freqs[SPEEDSTEP_HIGH].frequency, + &get_freqs->policy->cpuinfo.transition_latency, + &speedstep_set_state); +} + +static int speedstep_cpu_init(struct cpufreq_policy *policy) +{ + int result; + unsigned int policy_cpu, speed; + struct get_freqs gf; + + /* only run on CPU to be set, or on its sibling */ +#ifdef CONFIG_SMP + cpumask_copy(policy->cpus, cpu_sibling_mask(policy->cpu)); +#endif + policy_cpu = cpumask_any_and(policy->cpus, cpu_online_mask); + + /* detect low and high frequency and transition latency */ + gf.policy = policy; + smp_call_function_single(policy_cpu, get_freqs_on_cpu, &gf, 1); + if (gf.ret) + return gf.ret; + + /* get current speed setting */ + speed = speedstep_get(policy_cpu); + if (!speed) + return -EIO; + + pr_debug("currently at %s speed setting - %i MHz\n", + (speed == speedstep_freqs[SPEEDSTEP_LOW].frequency) + ? "low" : "high", + (speed / 1000)); + + /* cpuinfo and default policy values */ + policy->cur = speed; + + result = cpufreq_frequency_table_cpuinfo(policy, speedstep_freqs); + if (result) + return result; + + cpufreq_frequency_table_get_attr(speedstep_freqs, policy->cpu); + + return 0; +} + + +static int speedstep_cpu_exit(struct cpufreq_policy *policy) +{ + cpufreq_frequency_table_put_attr(policy->cpu); + return 0; +} + +static struct freq_attr *speedstep_attr[] = { + &cpufreq_freq_attr_scaling_available_freqs, + NULL, +}; + + +static struct cpufreq_driver speedstep_driver = { + .name = "speedstep-ich", + .verify = speedstep_verify, + .target = speedstep_target, + .init = speedstep_cpu_init, + .exit = speedstep_cpu_exit, + .get = speedstep_get, + .owner = THIS_MODULE, + .attr = speedstep_attr, +}; + + +/** + * speedstep_init - initializes the SpeedStep CPUFreq driver + * + * Initializes the SpeedStep support. Returns -ENODEV on unsupported + * devices, -EINVAL on problems during initiatization, and zero on + * success. + */ +static int __init speedstep_init(void) +{ + /* detect processor */ + speedstep_processor = speedstep_detect_processor(); + if (!speedstep_processor) { + pr_debug("Intel(R) SpeedStep(TM) capable processor " + "not found\n"); + return -ENODEV; + } + + /* detect chipset */ + if (!speedstep_detect_chipset()) { + pr_debug("Intel(R) SpeedStep(TM) for this chipset not " + "(yet) available.\n"); + return -ENODEV; + } + + /* activate speedstep support */ + if (speedstep_activate()) { + pci_dev_put(speedstep_chipset_dev); + return -EINVAL; + } + + if (speedstep_find_register()) + return -ENODEV; + + return cpufreq_register_driver(&speedstep_driver); +} + + +/** + * speedstep_exit - unregisters SpeedStep support + * + * Unregisters SpeedStep support. + */ +static void __exit speedstep_exit(void) +{ + pci_dev_put(speedstep_chipset_dev); + cpufreq_unregister_driver(&speedstep_driver); +} + + +MODULE_AUTHOR("Dave Jones , " + "Dominik Brodowski "); +MODULE_DESCRIPTION("Speedstep driver for Intel mobile processors on chipsets " + "with ICH-M southbridges."); +MODULE_LICENSE("GPL"); + +module_init(speedstep_init); +module_exit(speedstep_exit); diff --git a/drivers/cpufreq/speedstep-lib.c b/drivers/cpufreq/speedstep-lib.c new file mode 100644 index 0000000..8af2d2f --- /dev/null +++ b/drivers/cpufreq/speedstep-lib.c @@ -0,0 +1,478 @@ +/* + * (C) 2002 - 2003 Dominik Brodowski + * + * Licensed under the terms of the GNU GPL License version 2. + * + * Library for common functions for Intel SpeedStep v.1 and v.2 support + * + * BIG FAT DISCLAIMER: Work in progress code. Possibly *dangerous* + */ + +#include +#include +#include +#include +#include + +#include +#include +#include "speedstep-lib.h" + +#define PFX "speedstep-lib: " + +#ifdef CONFIG_X86_SPEEDSTEP_RELAXED_CAP_CHECK +static int relaxed_check; +#else +#define relaxed_check 0 +#endif + +/********************************************************************* + * GET PROCESSOR CORE SPEED IN KHZ * + *********************************************************************/ + +static unsigned int pentium3_get_frequency(enum speedstep_processor processor) +{ + /* See table 14 of p3_ds.pdf and table 22 of 29834003.pdf */ + struct { + unsigned int ratio; /* Frequency Multiplier (x10) */ + u8 bitmap; /* power on configuration bits + [27, 25:22] (in MSR 0x2a) */ + } msr_decode_mult[] = { + { 30, 0x01 }, + { 35, 0x05 }, + { 40, 0x02 }, + { 45, 0x06 }, + { 50, 0x00 }, + { 55, 0x04 }, + { 60, 0x0b }, + { 65, 0x0f }, + { 70, 0x09 }, + { 75, 0x0d }, + { 80, 0x0a }, + { 85, 0x26 }, + { 90, 0x20 }, + { 100, 0x2b }, + { 0, 0xff } /* error or unknown value */ + }; + + /* PIII(-M) FSB settings: see table b1-b of 24547206.pdf */ + struct { + unsigned int value; /* Front Side Bus speed in MHz */ + u8 bitmap; /* power on configuration bits [18: 19] + (in MSR 0x2a) */ + } msr_decode_fsb[] = { + { 66, 0x0 }, + { 100, 0x2 }, + { 133, 0x1 }, + { 0, 0xff} + }; + + u32 msr_lo, msr_tmp; + int i = 0, j = 0; + + /* read MSR 0x2a - we only need the low 32 bits */ + rdmsr(MSR_IA32_EBL_CR_POWERON, msr_lo, msr_tmp); + pr_debug("P3 - MSR_IA32_EBL_CR_POWERON: 0x%x 0x%x\n", msr_lo, msr_tmp); + msr_tmp = msr_lo; + + /* decode the FSB */ + msr_tmp &= 0x00c0000; + msr_tmp >>= 18; + while (msr_tmp != msr_decode_fsb[i].bitmap) { + if (msr_decode_fsb[i].bitmap == 0xff) + return 0; + i++; + } + + /* decode the multiplier */ + if (processor == SPEEDSTEP_CPU_PIII_C_EARLY) { + pr_debug("workaround for early PIIIs\n"); + msr_lo &= 0x03c00000; + } else + msr_lo &= 0x0bc00000; + msr_lo >>= 22; + while (msr_lo != msr_decode_mult[j].bitmap) { + if (msr_decode_mult[j].bitmap == 0xff) + return 0; + j++; + } + + pr_debug("speed is %u\n", + (msr_decode_mult[j].ratio * msr_decode_fsb[i].value * 100)); + + return msr_decode_mult[j].ratio * msr_decode_fsb[i].value * 100; +} + + +static unsigned int pentiumM_get_frequency(void) +{ + u32 msr_lo, msr_tmp; + + rdmsr(MSR_IA32_EBL_CR_POWERON, msr_lo, msr_tmp); + pr_debug("PM - MSR_IA32_EBL_CR_POWERON: 0x%x 0x%x\n", msr_lo, msr_tmp); + + /* see table B-2 of 24547212.pdf */ + if (msr_lo & 0x00040000) { + printk(KERN_DEBUG PFX "PM - invalid FSB: 0x%x 0x%x\n", + msr_lo, msr_tmp); + return 0; + } + + msr_tmp = (msr_lo >> 22) & 0x1f; + pr_debug("bits 22-26 are 0x%x, speed is %u\n", + msr_tmp, (msr_tmp * 100 * 1000)); + + return msr_tmp * 100 * 1000; +} + +static unsigned int pentium_core_get_frequency(void) +{ + u32 fsb = 0; + u32 msr_lo, msr_tmp; + int ret; + + rdmsr(MSR_FSB_FREQ, msr_lo, msr_tmp); + /* see table B-2 of 25366920.pdf */ + switch (msr_lo & 0x07) { + case 5: + fsb = 100000; + break; + case 1: + fsb = 133333; + break; + case 3: + fsb = 166667; + break; + case 2: + fsb = 200000; + break; + case 0: + fsb = 266667; + break; + case 4: + fsb = 333333; + break; + default: + printk(KERN_ERR "PCORE - MSR_FSB_FREQ undefined value"); + } + + rdmsr(MSR_IA32_EBL_CR_POWERON, msr_lo, msr_tmp); + pr_debug("PCORE - MSR_IA32_EBL_CR_POWERON: 0x%x 0x%x\n", + msr_lo, msr_tmp); + + msr_tmp = (msr_lo >> 22) & 0x1f; + pr_debug("bits 22-26 are 0x%x, speed is %u\n", + msr_tmp, (msr_tmp * fsb)); + + ret = (msr_tmp * fsb); + return ret; +} + + +static unsigned int pentium4_get_frequency(void) +{ + struct cpuinfo_x86 *c = &boot_cpu_data; + u32 msr_lo, msr_hi, mult; + unsigned int fsb = 0; + unsigned int ret; + u8 fsb_code; + + /* Pentium 4 Model 0 and 1 do not have the Core Clock Frequency + * to System Bus Frequency Ratio Field in the Processor Frequency + * Configuration Register of the MSR. Therefore the current + * frequency cannot be calculated and has to be measured. + */ + if (c->x86_model < 2) + return cpu_khz; + + rdmsr(0x2c, msr_lo, msr_hi); + + pr_debug("P4 - MSR_EBC_FREQUENCY_ID: 0x%x 0x%x\n", msr_lo, msr_hi); + + /* decode the FSB: see IA-32 Intel (C) Architecture Software + * Developer's Manual, Volume 3: System Prgramming Guide, + * revision #12 in Table B-1: MSRs in the Pentium 4 and + * Intel Xeon Processors, on page B-4 and B-5. + */ + fsb_code = (msr_lo >> 16) & 0x7; + switch (fsb_code) { + case 0: + fsb = 100 * 1000; + break; + case 1: + fsb = 13333 * 10; + break; + case 2: + fsb = 200 * 1000; + break; + } + + if (!fsb) + printk(KERN_DEBUG PFX "couldn't detect FSB speed. " + "Please send an e-mail to \n"); + + /* Multiplier. */ + mult = msr_lo >> 24; + + pr_debug("P4 - FSB %u kHz; Multiplier %u; Speed %u kHz\n", + fsb, mult, (fsb * mult)); + + ret = (fsb * mult); + return ret; +} + + +/* Warning: may get called from smp_call_function_single. */ +unsigned int speedstep_get_frequency(enum speedstep_processor processor) +{ + switch (processor) { + case SPEEDSTEP_CPU_PCORE: + return pentium_core_get_frequency(); + case SPEEDSTEP_CPU_PM: + return pentiumM_get_frequency(); + case SPEEDSTEP_CPU_P4D: + case SPEEDSTEP_CPU_P4M: + return pentium4_get_frequency(); + case SPEEDSTEP_CPU_PIII_T: + case SPEEDSTEP_CPU_PIII_C: + case SPEEDSTEP_CPU_PIII_C_EARLY: + return pentium3_get_frequency(processor); + default: + return 0; + }; + return 0; +} +EXPORT_SYMBOL_GPL(speedstep_get_frequency); + + +/********************************************************************* + * DETECT SPEEDSTEP-CAPABLE PROCESSOR * + *********************************************************************/ + +unsigned int speedstep_detect_processor(void) +{ + struct cpuinfo_x86 *c = &cpu_data(0); + u32 ebx, msr_lo, msr_hi; + + pr_debug("x86: %x, model: %x\n", c->x86, c->x86_model); + + if ((c->x86_vendor != X86_VENDOR_INTEL) || + ((c->x86 != 6) && (c->x86 != 0xF))) + return 0; + + if (c->x86 == 0xF) { + /* Intel Mobile Pentium 4-M + * or Intel Mobile Pentium 4 with 533 MHz FSB */ + if (c->x86_model != 2) + return 0; + + ebx = cpuid_ebx(0x00000001); + ebx &= 0x000000FF; + + pr_debug("ebx value is %x, x86_mask is %x\n", ebx, c->x86_mask); + + switch (c->x86_mask) { + case 4: + /* + * B-stepping [M-P4-M] + * sample has ebx = 0x0f, production has 0x0e. + */ + if ((ebx == 0x0e) || (ebx == 0x0f)) + return SPEEDSTEP_CPU_P4M; + break; + case 7: + /* + * C-stepping [M-P4-M] + * needs to have ebx=0x0e, else it's a celeron: + * cf. 25130917.pdf / page 7, footnote 5 even + * though 25072120.pdf / page 7 doesn't say + * samples are only of B-stepping... + */ + if (ebx == 0x0e) + return SPEEDSTEP_CPU_P4M; + break; + case 9: + /* + * D-stepping [M-P4-M or M-P4/533] + * + * this is totally strange: CPUID 0x0F29 is + * used by M-P4-M, M-P4/533 and(!) Celeron CPUs. + * The latter need to be sorted out as they don't + * support speedstep. + * Celerons with CPUID 0x0F29 may have either + * ebx=0x8 or 0xf -- 25130917.pdf doesn't say anything + * specific. + * M-P4-Ms may have either ebx=0xe or 0xf [see above] + * M-P4/533 have either ebx=0xe or 0xf. [25317607.pdf] + * also, M-P4M HTs have ebx=0x8, too + * For now, they are distinguished by the model_id + * string + */ + if ((ebx == 0x0e) || + (strstr(c->x86_model_id, + "Mobile Intel(R) Pentium(R) 4") != NULL)) + return SPEEDSTEP_CPU_P4M; + break; + default: + break; + } + return 0; + } + + switch (c->x86_model) { + case 0x0B: /* Intel PIII [Tualatin] */ + /* cpuid_ebx(1) is 0x04 for desktop PIII, + * 0x06 for mobile PIII-M */ + ebx = cpuid_ebx(0x00000001); + pr_debug("ebx is %x\n", ebx); + + ebx &= 0x000000FF; + + if (ebx != 0x06) + return 0; + + /* So far all PIII-M processors support SpeedStep. See + * Intel's 24540640.pdf of June 2003 + */ + return SPEEDSTEP_CPU_PIII_T; + + case 0x08: /* Intel PIII [Coppermine] */ + + /* all mobile PIII Coppermines have FSB 100 MHz + * ==> sort out a few desktop PIIIs. */ + rdmsr(MSR_IA32_EBL_CR_POWERON, msr_lo, msr_hi); + pr_debug("Coppermine: MSR_IA32_EBL_CR_POWERON is 0x%x, 0x%x\n", + msr_lo, msr_hi); + msr_lo &= 0x00c0000; + if (msr_lo != 0x0080000) + return 0; + + /* + * If the processor is a mobile version, + * platform ID has bit 50 set + * it has SpeedStep technology if either + * bit 56 or 57 is set + */ + rdmsr(MSR_IA32_PLATFORM_ID, msr_lo, msr_hi); + pr_debug("Coppermine: MSR_IA32_PLATFORM ID is 0x%x, 0x%x\n", + msr_lo, msr_hi); + if ((msr_hi & (1<<18)) && + (relaxed_check ? 1 : (msr_hi & (3<<24)))) { + if (c->x86_mask == 0x01) { + pr_debug("early PIII version\n"); + return SPEEDSTEP_CPU_PIII_C_EARLY; + } else + return SPEEDSTEP_CPU_PIII_C; + } + + default: + return 0; + } +} +EXPORT_SYMBOL_GPL(speedstep_detect_processor); + + +/********************************************************************* + * DETECT SPEEDSTEP SPEEDS * + *********************************************************************/ + +unsigned int speedstep_get_freqs(enum speedstep_processor processor, + unsigned int *low_speed, + unsigned int *high_speed, + unsigned int *transition_latency, + void (*set_state) (unsigned int state)) +{ + unsigned int prev_speed; + unsigned int ret = 0; + unsigned long flags; + struct timeval tv1, tv2; + + if ((!processor) || (!low_speed) || (!high_speed) || (!set_state)) + return -EINVAL; + + pr_debug("trying to determine both speeds\n"); + + /* get current speed */ + prev_speed = speedstep_get_frequency(processor); + if (!prev_speed) + return -EIO; + + pr_debug("previous speed is %u\n", prev_speed); + + local_irq_save(flags); + + /* switch to low state */ + set_state(SPEEDSTEP_LOW); + *low_speed = speedstep_get_frequency(processor); + if (!*low_speed) { + ret = -EIO; + goto out; + } + + pr_debug("low speed is %u\n", *low_speed); + + /* start latency measurement */ + if (transition_latency) + do_gettimeofday(&tv1); + + /* switch to high state */ + set_state(SPEEDSTEP_HIGH); + + /* end latency measurement */ + if (transition_latency) + do_gettimeofday(&tv2); + + *high_speed = speedstep_get_frequency(processor); + if (!*high_speed) { + ret = -EIO; + goto out; + } + + pr_debug("high speed is %u\n", *high_speed); + + if (*low_speed == *high_speed) { + ret = -ENODEV; + goto out; + } + + /* switch to previous state, if necessary */ + if (*high_speed != prev_speed) + set_state(SPEEDSTEP_LOW); + + if (transition_latency) { + *transition_latency = (tv2.tv_sec - tv1.tv_sec) * USEC_PER_SEC + + tv2.tv_usec - tv1.tv_usec; + pr_debug("transition latency is %u uSec\n", *transition_latency); + + /* convert uSec to nSec and add 20% for safety reasons */ + *transition_latency *= 1200; + + /* check if the latency measurement is too high or too low + * and set it to a safe value (500uSec) in that case + */ + if (*transition_latency > 10000000 || + *transition_latency < 50000) { + printk(KERN_WARNING PFX "frequency transition " + "measured seems out of range (%u " + "nSec), falling back to a safe one of" + "%u nSec.\n", + *transition_latency, 500000); + *transition_latency = 500000; + } + } + +out: + local_irq_restore(flags); + return ret; +} +EXPORT_SYMBOL_GPL(speedstep_get_freqs); + +#ifdef CONFIG_X86_SPEEDSTEP_RELAXED_CAP_CHECK +module_param(relaxed_check, int, 0444); +MODULE_PARM_DESC(relaxed_check, + "Don't do all checks for speedstep capability."); +#endif + +MODULE_AUTHOR("Dominik Brodowski "); +MODULE_DESCRIPTION("Library for Intel SpeedStep 1 or 2 cpufreq drivers."); +MODULE_LICENSE("GPL"); diff --git a/drivers/cpufreq/speedstep-lib.h b/drivers/cpufreq/speedstep-lib.h new file mode 100644 index 0000000..70d9cea --- /dev/null +++ b/drivers/cpufreq/speedstep-lib.h @@ -0,0 +1,49 @@ +/* + * (C) 2002 - 2003 Dominik Brodowski + * + * Licensed under the terms of the GNU GPL License version 2. + * + * Library for common functions for Intel SpeedStep v.1 and v.2 support + * + * BIG FAT DISCLAIMER: Work in progress code. Possibly *dangerous* + */ + + + +/* processors */ +enum speedstep_processor { + SPEEDSTEP_CPU_PIII_C_EARLY = 0x00000001, /* Coppermine core */ + SPEEDSTEP_CPU_PIII_C = 0x00000002, /* Coppermine core */ + SPEEDSTEP_CPU_PIII_T = 0x00000003, /* Tualatin core */ + SPEEDSTEP_CPU_P4M = 0x00000004, /* P4-M */ +/* the following processors are not speedstep-capable and are not auto-detected + * in speedstep_detect_processor(). However, their speed can be detected using + * the speedstep_get_frequency() call. */ + SPEEDSTEP_CPU_PM = 0xFFFFFF03, /* Pentium M */ + SPEEDSTEP_CPU_P4D = 0xFFFFFF04, /* desktop P4 */ + SPEEDSTEP_CPU_PCORE = 0xFFFFFF05, /* Core */ +}; + +/* speedstep states -- only two of them */ + +#define SPEEDSTEP_HIGH 0x00000000 +#define SPEEDSTEP_LOW 0x00000001 + + +/* detect a speedstep-capable processor */ +extern enum speedstep_processor speedstep_detect_processor(void); + +/* detect the current speed (in khz) of the processor */ +extern unsigned int speedstep_get_frequency(enum speedstep_processor processor); + + +/* detect the low and high speeds of the processor. The callback + * set_state"'s first argument is either SPEEDSTEP_HIGH or + * SPEEDSTEP_LOW; the second argument is zero so that no + * cpufreq_notify_transition calls are initiated. + */ +extern unsigned int speedstep_get_freqs(enum speedstep_processor processor, + unsigned int *low_speed, + unsigned int *high_speed, + unsigned int *transition_latency, + void (*set_state) (unsigned int state)); diff --git a/drivers/cpufreq/speedstep-smi.c b/drivers/cpufreq/speedstep-smi.c new file mode 100644 index 0000000..c76ead3 --- /dev/null +++ b/drivers/cpufreq/speedstep-smi.c @@ -0,0 +1,464 @@ +/* + * Intel SpeedStep SMI driver. + * + * (C) 2003 Hiroshi Miura + * + * Licensed under the terms of the GNU GPL License version 2. + * + */ + + +/********************************************************************* + * SPEEDSTEP - DEFINITIONS * + *********************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "speedstep-lib.h" + +/* speedstep system management interface port/command. + * + * These parameters are got from IST-SMI BIOS call. + * If user gives it, these are used. + * + */ +static int smi_port; +static int smi_cmd; +static unsigned int smi_sig; + +/* info about the processor */ +static enum speedstep_processor speedstep_processor; + +/* + * There are only two frequency states for each processor. Values + * are in kHz for the time being. + */ +static struct cpufreq_frequency_table speedstep_freqs[] = { + {SPEEDSTEP_HIGH, 0}, + {SPEEDSTEP_LOW, 0}, + {0, CPUFREQ_TABLE_END}, +}; + +#define GET_SPEEDSTEP_OWNER 0 +#define GET_SPEEDSTEP_STATE 1 +#define SET_SPEEDSTEP_STATE 2 +#define GET_SPEEDSTEP_FREQS 4 + +/* how often shall the SMI call be tried if it failed, e.g. because + * of DMA activity going on? */ +#define SMI_TRIES 5 + +/** + * speedstep_smi_ownership + */ +static int speedstep_smi_ownership(void) +{ + u32 command, result, magic, dummy; + u32 function = GET_SPEEDSTEP_OWNER; + unsigned char magic_data[] = "Copyright (c) 1999 Intel Corporation"; + + command = (smi_sig & 0xffffff00) | (smi_cmd & 0xff); + magic = virt_to_phys(magic_data); + + pr_debug("trying to obtain ownership with command %x at port %x\n", + command, smi_port); + + __asm__ __volatile__( + "push %%ebp\n" + "out %%al, (%%dx)\n" + "pop %%ebp\n" + : "=D" (result), + "=a" (dummy), "=b" (dummy), "=c" (dummy), "=d" (dummy), + "=S" (dummy) + : "a" (command), "b" (function), "c" (0), "d" (smi_port), + "D" (0), "S" (magic) + : "memory" + ); + + pr_debug("result is %x\n", result); + + return result; +} + +/** + * speedstep_smi_get_freqs - get SpeedStep preferred & current freq. + * @low: the low frequency value is placed here + * @high: the high frequency value is placed here + * + * Only available on later SpeedStep-enabled systems, returns false results or + * even hangs [cf. bugme.osdl.org # 1422] on earlier systems. Empirical testing + * shows that the latter occurs if !(ist_info.event & 0xFFFF). + */ +static int speedstep_smi_get_freqs(unsigned int *low, unsigned int *high) +{ + u32 command, result = 0, edi, high_mhz, low_mhz, dummy; + u32 state = 0; + u32 function = GET_SPEEDSTEP_FREQS; + + if (!(ist_info.event & 0xFFFF)) { + pr_debug("bug #1422 -- can't read freqs from BIOS\n"); + return -ENODEV; + } + + command = (smi_sig & 0xffffff00) | (smi_cmd & 0xff); + + pr_debug("trying to determine frequencies with command %x at port %x\n", + command, smi_port); + + __asm__ __volatile__( + "push %%ebp\n" + "out %%al, (%%dx)\n" + "pop %%ebp" + : "=a" (result), + "=b" (high_mhz), + "=c" (low_mhz), + "=d" (state), "=D" (edi), "=S" (dummy) + : "a" (command), + "b" (function), + "c" (state), + "d" (smi_port), "S" (0), "D" (0) + ); + + pr_debug("result %x, low_freq %u, high_freq %u\n", + result, low_mhz, high_mhz); + + /* abort if results are obviously incorrect... */ + if ((high_mhz + low_mhz) < 600) + return -EINVAL; + + *high = high_mhz * 1000; + *low = low_mhz * 1000; + + return result; +} + +/** + * speedstep_get_state - set the SpeedStep state + * @state: processor frequency state (SPEEDSTEP_LOW or SPEEDSTEP_HIGH) + * + */ +static int speedstep_get_state(void) +{ + u32 function = GET_SPEEDSTEP_STATE; + u32 result, state, edi, command, dummy; + + command = (smi_sig & 0xffffff00) | (smi_cmd & 0xff); + + pr_debug("trying to determine current setting with command %x " + "at port %x\n", command, smi_port); + + __asm__ __volatile__( + "push %%ebp\n" + "out %%al, (%%dx)\n" + "pop %%ebp\n" + : "=a" (result), + "=b" (state), "=D" (edi), + "=c" (dummy), "=d" (dummy), "=S" (dummy) + : "a" (command), "b" (function), "c" (0), + "d" (smi_port), "S" (0), "D" (0) + ); + + pr_debug("state is %x, result is %x\n", state, result); + + return state & 1; +} + + +/** + * speedstep_set_state - set the SpeedStep state + * @state: new processor frequency state (SPEEDSTEP_LOW or SPEEDSTEP_HIGH) + * + */ +static void speedstep_set_state(unsigned int state) +{ + unsigned int result = 0, command, new_state, dummy; + unsigned long flags; + unsigned int function = SET_SPEEDSTEP_STATE; + unsigned int retry = 0; + + if (state > 0x1) + return; + + /* Disable IRQs */ + local_irq_save(flags); + + command = (smi_sig & 0xffffff00) | (smi_cmd & 0xff); + + pr_debug("trying to set frequency to state %u " + "with command %x at port %x\n", + state, command, smi_port); + + do { + if (retry) { + pr_debug("retry %u, previous result %u, waiting...\n", + retry, result); + mdelay(retry * 50); + } + retry++; + __asm__ __volatile__( + "push %%ebp\n" + "out %%al, (%%dx)\n" + "pop %%ebp" + : "=b" (new_state), "=D" (result), + "=c" (dummy), "=a" (dummy), + "=d" (dummy), "=S" (dummy) + : "a" (command), "b" (function), "c" (state), + "d" (smi_port), "S" (0), "D" (0) + ); + } while ((new_state != state) && (retry <= SMI_TRIES)); + + /* enable IRQs */ + local_irq_restore(flags); + + if (new_state == state) + pr_debug("change to %u MHz succeeded after %u tries " + "with result %u\n", + (speedstep_freqs[new_state].frequency / 1000), + retry, result); + else + printk(KERN_ERR "cpufreq: change to state %u " + "failed with new_state %u and result %u\n", + state, new_state, result); + + return; +} + + +/** + * speedstep_target - set a new CPUFreq policy + * @policy: new policy + * @target_freq: new freq + * @relation: + * + * Sets a new CPUFreq policy/freq. + */ +static int speedstep_target(struct cpufreq_policy *policy, + unsigned int target_freq, unsigned int relation) +{ + unsigned int newstate = 0; + struct cpufreq_freqs freqs; + + if (cpufreq_frequency_table_target(policy, &speedstep_freqs[0], + target_freq, relation, &newstate)) + return -EINVAL; + + freqs.old = speedstep_freqs[speedstep_get_state()].frequency; + freqs.new = speedstep_freqs[newstate].frequency; + freqs.cpu = 0; /* speedstep.c is UP only driver */ + + if (freqs.old == freqs.new) + return 0; + + cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE); + speedstep_set_state(newstate); + cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE); + + return 0; +} + + +/** + * speedstep_verify - verifies a new CPUFreq policy + * @policy: new policy + * + * Limit must be within speedstep_low_freq and speedstep_high_freq, with + * at least one border included. + */ +static int speedstep_verify(struct cpufreq_policy *policy) +{ + return cpufreq_frequency_table_verify(policy, &speedstep_freqs[0]); +} + + +static int speedstep_cpu_init(struct cpufreq_policy *policy) +{ + int result; + unsigned int speed, state; + unsigned int *low, *high; + + /* capability check */ + if (policy->cpu != 0) + return -ENODEV; + + result = speedstep_smi_ownership(); + if (result) { + pr_debug("fails in acquiring ownership of a SMI interface.\n"); + return -EINVAL; + } + + /* detect low and high frequency */ + low = &speedstep_freqs[SPEEDSTEP_LOW].frequency; + high = &speedstep_freqs[SPEEDSTEP_HIGH].frequency; + + result = speedstep_smi_get_freqs(low, high); + if (result) { + /* fall back to speedstep_lib.c dection mechanism: + * try both states out */ + pr_debug("could not detect low and high frequencies " + "by SMI call.\n"); + result = speedstep_get_freqs(speedstep_processor, + low, high, + NULL, + &speedstep_set_state); + + if (result) { + pr_debug("could not detect two different speeds" + " -- aborting.\n"); + return result; + } else + pr_debug("workaround worked.\n"); + } + + /* get current speed setting */ + state = speedstep_get_state(); + speed = speedstep_freqs[state].frequency; + + pr_debug("currently at %s speed setting - %i MHz\n", + (speed == speedstep_freqs[SPEEDSTEP_LOW].frequency) + ? "low" : "high", + (speed / 1000)); + + /* cpuinfo and default policy values */ + policy->cpuinfo.transition_latency = CPUFREQ_ETERNAL; + policy->cur = speed; + + result = cpufreq_frequency_table_cpuinfo(policy, speedstep_freqs); + if (result) + return result; + + cpufreq_frequency_table_get_attr(speedstep_freqs, policy->cpu); + + return 0; +} + +static int speedstep_cpu_exit(struct cpufreq_policy *policy) +{ + cpufreq_frequency_table_put_attr(policy->cpu); + return 0; +} + +static unsigned int speedstep_get(unsigned int cpu) +{ + if (cpu) + return -ENODEV; + return speedstep_get_frequency(speedstep_processor); +} + + +static int speedstep_resume(struct cpufreq_policy *policy) +{ + int result = speedstep_smi_ownership(); + + if (result) + pr_debug("fails in re-acquiring ownership of a SMI interface.\n"); + + return result; +} + +static struct freq_attr *speedstep_attr[] = { + &cpufreq_freq_attr_scaling_available_freqs, + NULL, +}; + +static struct cpufreq_driver speedstep_driver = { + .name = "speedstep-smi", + .verify = speedstep_verify, + .target = speedstep_target, + .init = speedstep_cpu_init, + .exit = speedstep_cpu_exit, + .get = speedstep_get, + .resume = speedstep_resume, + .owner = THIS_MODULE, + .attr = speedstep_attr, +}; + +/** + * speedstep_init - initializes the SpeedStep CPUFreq driver + * + * Initializes the SpeedStep support. Returns -ENODEV on unsupported + * BIOS, -EINVAL on problems during initiatization, and zero on + * success. + */ +static int __init speedstep_init(void) +{ + speedstep_processor = speedstep_detect_processor(); + + switch (speedstep_processor) { + case SPEEDSTEP_CPU_PIII_T: + case SPEEDSTEP_CPU_PIII_C: + case SPEEDSTEP_CPU_PIII_C_EARLY: + break; + default: + speedstep_processor = 0; + } + + if (!speedstep_processor) { + pr_debug("No supported Intel CPU detected.\n"); + return -ENODEV; + } + + pr_debug("signature:0x%.8ulx, command:0x%.8ulx, " + "event:0x%.8ulx, perf_level:0x%.8ulx.\n", + ist_info.signature, ist_info.command, + ist_info.event, ist_info.perf_level); + + /* Error if no IST-SMI BIOS or no PARM + sig= 'ISGE' aka 'Intel Speedstep Gate E' */ + if ((ist_info.signature != 0x47534943) && ( + (smi_port == 0) || (smi_cmd == 0))) + return -ENODEV; + + if (smi_sig == 1) + smi_sig = 0x47534943; + else + smi_sig = ist_info.signature; + + /* setup smi_port from MODLULE_PARM or BIOS */ + if ((smi_port > 0xff) || (smi_port < 0)) + return -EINVAL; + else if (smi_port == 0) + smi_port = ist_info.command & 0xff; + + if ((smi_cmd > 0xff) || (smi_cmd < 0)) + return -EINVAL; + else if (smi_cmd == 0) + smi_cmd = (ist_info.command >> 16) & 0xff; + + return cpufreq_register_driver(&speedstep_driver); +} + + +/** + * speedstep_exit - unregisters SpeedStep support + * + * Unregisters SpeedStep support. + */ +static void __exit speedstep_exit(void) +{ + cpufreq_unregister_driver(&speedstep_driver); +} + +module_param(smi_port, int, 0444); +module_param(smi_cmd, int, 0444); +module_param(smi_sig, uint, 0444); + +MODULE_PARM_DESC(smi_port, "Override the BIOS-given IST port with this value " + "-- Intel's default setting is 0xb2"); +MODULE_PARM_DESC(smi_cmd, "Override the BIOS-given IST command with this value " + "-- Intel's default setting is 0x82"); +MODULE_PARM_DESC(smi_sig, "Set to 1 to fake the IST signature when using the " + "SMI interface."); + +MODULE_AUTHOR("Hiroshi Miura"); +MODULE_DESCRIPTION("Speedstep driver for IST applet SMI interface."); +MODULE_LICENSE("GPL"); + +module_init(speedstep_init); +module_exit(speedstep_exit); -- cgit v0.10.2 From ed84cadb21e15a3e59a2154158c58579774f0851 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Thu, 19 May 2011 18:51:50 -0400 Subject: rxrpc: Fix set but unused variable 'usage' in rxrpc_get_transport() This is identical to the case I fixed in rxrpc_get_peer() Signed-off-by: David S. Miller diff --git a/net/rxrpc/ar-transport.c b/net/rxrpc/ar-transport.c index 5e0226f..92df566 100644 --- a/net/rxrpc/ar-transport.c +++ b/net/rxrpc/ar-transport.c @@ -111,6 +111,7 @@ struct rxrpc_transport *rxrpc_get_transport(struct rxrpc_local *local, /* we can now add the new candidate to the list */ trans = candidate; candidate = NULL; + usage = atomic_read(&trans->usage); rxrpc_get_local(trans->local); atomic_inc(&trans->peer->usage); @@ -125,7 +126,7 @@ success: trans->local->debug_id, trans->peer->debug_id); - _leave(" = %p {u=%d}", trans, atomic_read(&trans->usage)); + _leave(" = %p {u=%d}", trans, usage); return trans; /* we found the transport in the list immediately */ -- cgit v0.10.2 From bfad6ef6d29e776472b3ead1f5bc920c5410ed2c Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Thu, 19 May 2011 18:52:59 -0400 Subject: irda: Kill set but unused variable 'clen' in ircomm_connect_indication() Signed-off-by: David S. Miller diff --git a/net/irda/ircomm/ircomm_core.c b/net/irda/ircomm/ircomm_core.c index e970820..52079f1 100644 --- a/net/irda/ircomm/ircomm_core.c +++ b/net/irda/ircomm/ircomm_core.c @@ -244,14 +244,8 @@ EXPORT_SYMBOL(ircomm_connect_request); void ircomm_connect_indication(struct ircomm_cb *self, struct sk_buff *skb, struct ircomm_info *info) { - int clen = 0; - IRDA_DEBUG(2, "%s()\n", __func__ ); - /* Check if the packet contains data on the control channel */ - if (skb->len > 0) - clen = skb->data[0]; - /* * If there are any data hiding in the control channel, we must * deliver it first. The side effect is that the control channel -- cgit v0.10.2 From ad6376434c945495ea8c4082ad8a392cc58c3406 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Thu, 19 May 2011 18:53:58 -0400 Subject: irda: Kill set but unused variable 'bytes' in irlan_check_command_param() Signed-off-by: David S. Miller diff --git a/net/irda/irlan/irlan_filter.c b/net/irda/irlan/irlan_filter.c index 9ff7823..7977be7 100644 --- a/net/irda/irlan/irlan_filter.c +++ b/net/irda/irlan/irlan_filter.c @@ -143,12 +143,8 @@ void irlan_filter_request(struct irlan_cb *self, struct sk_buff *skb) */ void irlan_check_command_param(struct irlan_cb *self, char *param, char *value) { - __u8 *bytes; - IRDA_DEBUG(4, "%s()\n", __func__ ); - bytes = value; - IRDA_ASSERT(self != NULL, return;); IRDA_ASSERT(self->magic == IRLAN_MAGIC, return;); -- cgit v0.10.2 From 8ce6eb1a4a4bc46820f23e927377d386d3ec5404 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Thu, 19 May 2011 18:58:39 -0400 Subject: irda: Fix error propagation in ircomm_lmp_connect_response() The variable 'ret' is set but unused, and this pointed out that errors from irlmp_connect_response() are not propagated to the caller. Note that this is currently academic since irlmp_connect_response() always returns 0. :-) Signed-off-by: David S. Miller diff --git a/net/irda/ircomm/ircomm_lmp.c b/net/irda/ircomm/ircomm_lmp.c index 08fb54d..3b8095c 100644 --- a/net/irda/ircomm/ircomm_lmp.c +++ b/net/irda/ircomm/ircomm_lmp.c @@ -75,7 +75,6 @@ static int ircomm_lmp_connect_response(struct ircomm_cb *self, struct sk_buff *userdata) { struct sk_buff *tx_skb; - int ret; IRDA_DEBUG(0, "%s()\n", __func__ ); @@ -100,9 +99,7 @@ static int ircomm_lmp_connect_response(struct ircomm_cb *self, tx_skb = userdata; } - ret = irlmp_connect_response(self->lsap, tx_skb); - - return 0; + return irlmp_connect_response(self->lsap, tx_skb); } static int ircomm_lmp_disconnect_request(struct ircomm_cb *self, -- cgit v0.10.2 From 034cfe48d0efc248ba4b725e3a94b95e76fbc5d3 Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Thu, 19 May 2011 19:23:28 -0400 Subject: networking: NET_CLS_ROUTE4 depends on INET IP_ROUTE_CLASSID depends on INET and NET_CLS_ROUTE4 selects IP_ROUTE_CLASSID, but when INET is not enabled, this kconfig warning is produced, so fix it by making NET_CLS_ROUTE4 depend on INET. warning: (NET_CLS_ROUTE4) selects IP_ROUTE_CLASSID which has unmet direct dependencies (NET && INET) Signed-off-by: Randy Dunlap Signed-off-by: David S. Miller diff --git a/net/sched/Kconfig b/net/sched/Kconfig index aeaa211..2590e91 100644 --- a/net/sched/Kconfig +++ b/net/sched/Kconfig @@ -288,6 +288,7 @@ config NET_CLS_TCINDEX config NET_CLS_ROUTE4 tristate "Routing decision (ROUTE)" + depends on INET select IP_ROUTE_CLASSID select NET_CLS ---help--- -- cgit v0.10.2 From c5fc472171ec4f96d06d1ac039d88f9b89bb95db Mon Sep 17 00:00:00 2001 From: Ingo Molnar Date: Fri, 20 May 2011 01:22:14 +0200 Subject: core_kernel_data(): Fix architectures that do not define _sdata Some architectures such as Alpha do not define _sdata but _data: kernel/built-in.o: In function `core_kernel_data': kernel/extable.c:77: undefined reference to `_sdata' So expand the scope of the data range to the text addresses too, this might be more correct anyway because this way we can cover readonly variables as well. Cc: Paul E. McKenney Cc: Steven Rostedt Link: http://lkml.kernel.org/n/tip-i878c8a0e0g0ep4v7i6vxnhz@git.kernel.org Signed-off-by: Ingo Molnar diff --git a/kernel/extable.c b/kernel/extable.c index c2d625f..d44aac0 100644 --- a/kernel/extable.c +++ b/kernel/extable.c @@ -74,7 +74,7 @@ int core_kernel_text(unsigned long addr) int core_kernel_data(unsigned long addr) { - if (addr >= (unsigned long)_sdata && + if (addr >= (unsigned long)_stext && addr < (unsigned long)_edata) return 1; return 0; -- cgit v0.10.2 From f68b3afe45051d43e9f9277c6f1404670e1b99d2 Mon Sep 17 00:00:00 2001 From: Jeff Garzik Date: Thu, 19 May 2011 20:45:15 -0400 Subject: drivers/ata/acard-ahci.c: fix enum warning Signed-off-by: Jeff Garzik diff --git a/drivers/ata/acard-ahci.c b/drivers/ata/acard-ahci.c index 339c210..ae22be4 100644 --- a/drivers/ata/acard-ahci.c +++ b/drivers/ata/acard-ahci.c @@ -417,7 +417,7 @@ static int acard_ahci_init_one(struct pci_dev *pdev, const struct pci_device_id VPRINTK("ENTER\n"); - WARN_ON(ATA_MAX_QUEUE > AHCI_MAX_CMDS); + WARN_ON((int)ATA_MAX_QUEUE > AHCI_MAX_CMDS); if (!printed_version++) dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n"); -- cgit v0.10.2 From 5f4e206666f834340b69ddb43f86de3851c8675a Mon Sep 17 00:00:00 2001 From: "Martin K. Petersen" Date: Tue, 17 May 2011 22:13:23 -0400 Subject: libata: Use Maximum Write Same Length to report discard size limit Previously we used Maximum Unmap LBA Count in the Block Limits VPD to signal the maximum number of sectors we could handle in a single Write Same command. Starting with SBC3r26 the Block Limits VPD has an explicit limit on the number of blocks in a Write Same. This means we can stop abusing a field related to the Unmap command and let our SAT use the proper value in the VPD (Maximum Write Same Length). Signed-off-by: Martin K. Petersen Signed-off-by: Jeff Garzik Cc: stable@kernel.org diff --git a/drivers/ata/libata-scsi.c b/drivers/ata/libata-scsi.c index e2f57e9e..30ea95f 100644 --- a/drivers/ata/libata-scsi.c +++ b/drivers/ata/libata-scsi.c @@ -2138,7 +2138,7 @@ static unsigned int ata_scsiop_inq_b0(struct ata_scsi_args *args, u8 *rbuf) * with the unmap bit set. */ if (ata_id_has_trim(args->id)) { - put_unaligned_be32(65535 * 512 / 8, &rbuf[20]); + put_unaligned_be64(65535 * 512 / 8, &rbuf[36]); put_unaligned_be32(1, &rbuf[28]); } -- cgit v0.10.2 From bfeec8ca15c9c06c1978a25248e2bd11c4a26d72 Mon Sep 17 00:00:00 2001 From: Mikulas Patocka Date: Sun, 15 May 2011 22:33:19 +0200 Subject: ATA: Don't powerdown Compaq Triflex IDE device on suspend Don't powerdown Compaq Triflex IDE device on suspend This fixes APM suspend on Compaq Armada 7400. APM BIOS doesn't suspend if IDE is powered down when suspending. The Triflex controller is found only on old Compaq boards, so this patch will hopefully have no side effects. Signed-off-by: Mikulas Patocka Signed-off-by: Jeff Garzik diff --git a/drivers/ata/pata_triflex.c b/drivers/ata/pata_triflex.c index 03b6d69..b3e0c94 100644 --- a/drivers/ata/pata_triflex.c +++ b/drivers/ata/pata_triflex.c @@ -210,13 +210,34 @@ static const struct pci_device_id triflex[] = { { }, }; +#ifdef CONFIG_PM +static int triflex_ata_pci_device_suspend(struct pci_dev *pdev, pm_message_t mesg) +{ + struct ata_host *host = dev_get_drvdata(&pdev->dev); + int rc = 0; + + rc = ata_host_suspend(host, mesg); + if (rc) + return rc; + + /* + * We must not disable or powerdown the device. + * APM bios refuses to suspend if IDE is not accessible. + */ + pci_save_state(pdev); + + return 0; +} + +#endif + static struct pci_driver triflex_pci_driver = { .name = DRV_NAME, .id_table = triflex, .probe = triflex_init_one, .remove = ata_pci_remove_one, #ifdef CONFIG_PM - .suspend = ata_pci_device_suspend, + .suspend = triflex_ata_pci_device_suspend, .resume = ata_pci_device_resume, #endif }; -- cgit v0.10.2 From 0afc6f5ba95419fd505e60637f7645425f16e407 Mon Sep 17 00:00:00 2001 From: Pavel Herrmann Date: Thu, 28 Apr 2011 22:32:54 +0200 Subject: libata-pmp: add support for Thermaltake BlackX Duet esata drive dock Some errors still show up, but the dock works, both drives can be accessed at the same time The chip maker and designation is unknown - possibly jmicron JMB350? Signed-off-by: Pavel Herrmann Acked-by: Tejun Heo Signed-off-by: Jeff Garzik diff --git a/drivers/ata/libata-pmp.c b/drivers/ata/libata-pmp.c index 3120596..f06b7ea 100644 --- a/drivers/ata/libata-pmp.c +++ b/drivers/ata/libata-pmp.c @@ -449,6 +449,16 @@ static void sata_pmp_quirks(struct ata_port *ap) * otherwise. Don't try hard to recover it. */ ap->pmp_link[ap->nr_pmp_links - 1].flags |= ATA_LFLAG_NO_RETRY; + } else if (vendor == 0x197b && devid == 0x2352) { + /* chip found in Thermaltake BlackX Duet, jmicron JMB350? */ + ata_for_each_link(link, ap, EDGE) { + /* SRST breaks detection and disks get misclassified + * LPM disabled to avoid potential problems + */ + link->flags |= ATA_LFLAG_NO_LPM | + ATA_LFLAG_NO_SRST | + ATA_LFLAG_ASSUME_ATA; + } } } -- cgit v0.10.2 From 8a745f1f39b7a20047a362b67ce9151c07d14440 Mon Sep 17 00:00:00 2001 From: Kristen Carlson Accardi Date: Fri, 4 Mar 2011 10:24:11 -0800 Subject: libata: Power off empty ports Give users the option of completely powering off unoccupied SATA ports using the existing min_power link_power_management_policy option. When the use selects this option on an empty port, we will power the port off by setting DET to off. For occupied ports, behavior is unchanged. Signed-off-by: Kristen Carlson Accardi Signed-off-by: Jeff Garzik diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index 76c3c15..736bee5 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -3619,8 +3619,14 @@ int sata_link_scr_lpm(struct ata_link *link, enum ata_lpm_policy policy, scontrol |= (0x2 << 8); break; case ATA_LPM_MIN_POWER: - /* no restrictions on LPM transitions */ - scontrol &= ~(0x3 << 8); + if (ata_link_nr_enabled(link) > 0) + /* no restrictions on LPM transitions */ + scontrol &= ~(0x3 << 8); + else { + /* empty port, power off */ + scontrol &= ~0xf; + scontrol |= (0x1 << 2); + } break; default: WARN_ON(1); diff --git a/drivers/ata/libata-eh.c b/drivers/ata/libata-eh.c index dad9fd6..dfb6e9d 100644 --- a/drivers/ata/libata-eh.c +++ b/drivers/ata/libata-eh.c @@ -3423,7 +3423,7 @@ fail: return rc; } -static int ata_link_nr_enabled(struct ata_link *link) +int ata_link_nr_enabled(struct ata_link *link) { struct ata_device *dev; int cnt = 0; diff --git a/include/linux/libata.h b/include/linux/libata.h index 04f32a3..5a9926b 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -1151,6 +1151,7 @@ extern void ata_do_eh(struct ata_port *ap, ata_prereset_fn_t prereset, ata_reset_fn_t softreset, ata_reset_fn_t hardreset, ata_postreset_fn_t postreset); extern void ata_std_error_handler(struct ata_port *ap); +extern int ata_link_nr_enabled(struct ata_link *link); /* * Base operations to inherit from and initializers for sht -- cgit v0.10.2 From 1477fcc290b3d5c2614bde98bf3b1154c538860d Mon Sep 17 00:00:00 2001 From: Stephen Rothwell Date: Fri, 20 May 2011 11:11:53 +1000 Subject: signal.h need a definition of struct task_struct This fixes these build errors on powerpc: In file included from arch/powerpc/mm/fault.c:18: include/linux/signal.h:239: error: 'struct task_struct' declared inside parameter list include/linux/signal.h:239: error: its scope is only this definition or declaration, which is probably not what you want include/linux/signal.h:240: error: 'struct task_struct' declared inside parameter list .. Exposed by commit e66eed651fd1 ("list: remove prefetching from regular list iterators"), which removed the include of from . Without that, linux/signal.h no longer accidentally got the declaration of 'struct task_struct'. Fix by properly declaring the struct, rather than introducing any new header file dependency. Signed-off-by: Stephen Rothwell Signed-off-by: Linus Torvalds diff --git a/include/linux/signal.h b/include/linux/signal.h index fcd2b14..29a68ac 100644 --- a/include/linux/signal.h +++ b/include/linux/signal.h @@ -7,6 +7,8 @@ #ifdef __KERNEL__ #include +struct task_struct; + /* for sysctl */ extern int print_fatal_signals; /* -- cgit v0.10.2 From 044aea9b83614948c98564000db07d1d32b2d29b Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Thu, 19 May 2011 18:59:47 -0700 Subject: selinux: de-crapify avc cache stat code generation You can turn off the avc cache stats, but distributions seem to not do that (perhaps because several performance tuning how-to's talk about the avc cache statistics). Which is sad, because the code it generates is truly horrendous, with the statistics update being sandwitched between get_cpu/put_cpu which in turn causes preemption disables etc. We're talking ten+ instructions just to increment a per-cpu variable in some pretty hot code. Fix the craziness by just using 'this_cpu_inc()' instead. Suddenly we only need a single 'inc' instruction to increment the statistics. This is quite noticeable in the incredibly hot avc_has_perm_noaudit() function (which triggers all the statistics by virtue of doing an avc_lookup() call). Signed-off-by: Linus Torvalds diff --git a/security/selinux/avc.c b/security/selinux/avc.c index 1d027e2..5971e30e 100644 --- a/security/selinux/avc.c +++ b/security/selinux/avc.c @@ -38,11 +38,7 @@ #define AVC_CACHE_RECLAIM 16 #ifdef CONFIG_SECURITY_SELINUX_AVC_STATS -#define avc_cache_stats_incr(field) \ -do { \ - per_cpu(avc_cache_stats, get_cpu()).field++; \ - put_cpu(); \ -} while (0) +#define avc_cache_stats_incr(field) this_cpu_inc(avc_cache_stats.field) #else #define avc_cache_stats_incr(field) do {} while (0) #endif -- cgit v0.10.2 From 44075d95e2567ce7b454bc1a4cf264ff6afebe65 Mon Sep 17 00:00:00 2001 From: Paul Mackerras Date: Wed, 11 May 2011 00:38:50 +0000 Subject: powerpc/kvm: Fix kvmppc_core_pending_dec The vcpu->arch.pending_exceptions field is a bitfield indexed by interrupt priority number as returned by kvmppc_book3s_vec2irqprio. However, kvmppc_core_pending_dec was using an interrupt vector shifted by 7 as the bit index. Fix it to use the irqprio value for the decrementer interrupt instead. This problem was found by code inspection. Signed-off-by: Paul Mackerras Signed-off-by: Benjamin Herrenschmidt diff --git a/arch/powerpc/kvm/book3s.c b/arch/powerpc/kvm/book3s.c index c961de4..0f95b5c 100644 --- a/arch/powerpc/kvm/book3s.c +++ b/arch/powerpc/kvm/book3s.c @@ -236,7 +236,7 @@ void kvmppc_core_queue_dec(struct kvm_vcpu *vcpu) int kvmppc_core_pending_dec(struct kvm_vcpu *vcpu) { - return test_bit(BOOK3S_INTERRUPT_DECREMENTER >> 7, &vcpu->arch.pending_exceptions); + return test_bit(BOOK3S_IRQPRIO_DECREMENTER, &vcpu->arch.pending_exceptions); } void kvmppc_core_dequeue_dec(struct kvm_vcpu *vcpu) -- cgit v0.10.2 From 593adf317cf165f7c66facf2285db9d4befbd1c0 Mon Sep 17 00:00:00 2001 From: Paul Mackerras Date: Wed, 11 May 2011 00:39:50 +0000 Subject: powerpc/kvm: Fix the build for 32-bit Book 3S (classic) processors Commits a5d4f3ad3a ("powerpc: Base support for exceptions using HSRR0/1") and 673b189a2e ("powerpc: Always use SPRN_SPRG_HSCRATCH0 when running in HV mode") cause compile and link errors for 32-bit classic Book 3S processors when KVM is enabled. This fixes these errors. Signed-off-by: Paul Mackerras Signed-off-by: Benjamin Herrenschmidt diff --git a/arch/powerpc/include/asm/reg.h b/arch/powerpc/include/asm/reg.h index fdec593..c5cae0d 100644 --- a/arch/powerpc/include/asm/reg.h +++ b/arch/powerpc/include/asm/reg.h @@ -824,6 +824,11 @@ FTR_SECTION_ELSE_NESTED(66); \ mtspr SPRN_SPRG_HSCRATCH0,rX; \ ALT_FTR_SECTION_END_NESTED_IFCLR(CPU_FTR_HVMODE_206, 66) + +#else /* CONFIG_PPC_BOOK3S_64 */ +#define GET_SCRATCH0(rX) mfspr rX,SPRN_SPRG_SCRATCH0 +#define SET_SCRATCH0(rX) mtspr SPRN_SPRG_SCRATCH0,rX + #endif #ifdef CONFIG_PPC_BOOK3E_64 diff --git a/arch/powerpc/kvm/book3s_rmhandlers.S b/arch/powerpc/kvm/book3s_rmhandlers.S index ae99af6..1a1b344 100644 --- a/arch/powerpc/kvm/book3s_rmhandlers.S +++ b/arch/powerpc/kvm/book3s_rmhandlers.S @@ -112,7 +112,9 @@ INTERRUPT_TRAMPOLINE BOOK3S_INTERRUPT_MACHINE_CHECK INTERRUPT_TRAMPOLINE BOOK3S_INTERRUPT_DATA_STORAGE INTERRUPT_TRAMPOLINE BOOK3S_INTERRUPT_INST_STORAGE INTERRUPT_TRAMPOLINE BOOK3S_INTERRUPT_EXTERNAL +#ifdef CONFIG_PPC_BOOK3S_64 INTERRUPT_TRAMPOLINE BOOK3S_INTERRUPT_EXTERNAL_HV +#endif INTERRUPT_TRAMPOLINE BOOK3S_INTERRUPT_ALIGNMENT INTERRUPT_TRAMPOLINE BOOK3S_INTERRUPT_PROGRAM INTERRUPT_TRAMPOLINE BOOK3S_INTERRUPT_FP_UNAVAIL -- cgit v0.10.2 From 257313b2a87795e07a0bdf58d0fffbdba8b31051 Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Thu, 19 May 2011 21:22:53 -0700 Subject: selinux: avoid unnecessary avc cache stat hit count There is no point in counting hits - we can calculate it from the number of lookups and misses. This makes the avc statistics a bit smaller, and makes the code generation better too. Signed-off-by: Linus Torvalds diff --git a/security/selinux/avc.c b/security/selinux/avc.c index 5971e30e..3d2715f 100644 --- a/security/selinux/avc.c +++ b/security/selinux/avc.c @@ -343,11 +343,10 @@ static struct avc_node *avc_lookup(u32 ssid, u32 tsid, u16 tclass) node = avc_search_node(ssid, tsid, tclass); if (node) - avc_cache_stats_incr(hits); - else - avc_cache_stats_incr(misses); + return node; - return node; + avc_cache_stats_incr(misses); + return NULL; } static int avc_latest_notif_update(int seqno, int is_insert) @@ -765,7 +764,7 @@ int avc_has_perm_noaudit(u32 ssid, u32 tsid, rcu_read_lock(); node = avc_lookup(ssid, tsid, tclass); - if (!node) { + if (unlikely(!node)) { rcu_read_unlock(); if (in_avd) diff --git a/security/selinux/include/avc.h b/security/selinux/include/avc.h index e77b2ac..47fda96 100644 --- a/security/selinux/include/avc.h +++ b/security/selinux/include/avc.h @@ -41,7 +41,6 @@ struct sk_buff; */ struct avc_cache_stats { unsigned int lookups; - unsigned int hits; unsigned int misses; unsigned int allocations; unsigned int reclaims; diff --git a/security/selinux/selinuxfs.c b/security/selinux/selinuxfs.c index ea39cb7..c0e1a0f 100644 --- a/security/selinux/selinuxfs.c +++ b/security/selinux/selinuxfs.c @@ -1380,10 +1380,14 @@ static int sel_avc_stats_seq_show(struct seq_file *seq, void *v) if (v == SEQ_START_TOKEN) seq_printf(seq, "lookups hits misses allocations reclaims " "frees\n"); - else - seq_printf(seq, "%u %u %u %u %u %u\n", st->lookups, - st->hits, st->misses, st->allocations, + else { + unsigned int lookups = st->lookups; + unsigned int misses = st->misses; + unsigned int hits = lookups - misses; + seq_printf(seq, "%u %u %u %u %u %u\n", lookups, + hits, misses, st->allocations, st->reclaims, st->frees); + } return 0; } -- cgit v0.10.2 From 449f4544267e73d5db372971da63634707c32299 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Thu, 19 May 2011 12:24:16 +0000 Subject: macvlan: remove one synchronize_rcu() call When one macvlan device is dismantled, we can avoid one synchronize_rcu() call done after deletion from hash list, since caller will perform a synchronize_net() call after its ndo_stop() call. Add a new netdev->dismantle field to signal this dismantle intent. Reduces RTNL hold time. Signed-off-by: Eric Dumazet CC: Patrick McHardy CC: Ben Greear Signed-off-by: David S. Miller diff --git a/drivers/net/macvlan.c b/drivers/net/macvlan.c index d7c0bc62..07bcb80 100644 --- a/drivers/net/macvlan.c +++ b/drivers/net/macvlan.c @@ -70,16 +70,17 @@ static void macvlan_hash_add(struct macvlan_dev *vlan) hlist_add_head_rcu(&vlan->hlist, &port->vlan_hash[addr[5]]); } -static void macvlan_hash_del(struct macvlan_dev *vlan) +static void macvlan_hash_del(struct macvlan_dev *vlan, bool sync) { hlist_del_rcu(&vlan->hlist); - synchronize_rcu(); + if (sync) + synchronize_rcu(); } static void macvlan_hash_change_addr(struct macvlan_dev *vlan, const unsigned char *addr) { - macvlan_hash_del(vlan); + macvlan_hash_del(vlan, true); /* Now that we are unhashed it is safe to change the device * address without confusing packet delivery. */ @@ -345,7 +346,7 @@ static int macvlan_stop(struct net_device *dev) dev_uc_del(lowerdev, dev->dev_addr); hash_del: - macvlan_hash_del(vlan); + macvlan_hash_del(vlan, !dev->dismantle); return 0; } diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index a134d80..ca333e7 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -1293,7 +1293,9 @@ struct net_device { NETREG_UNREGISTERED, /* completed unregister todo */ NETREG_RELEASED, /* called free_netdev */ NETREG_DUMMY, /* dummy device for NAPI poll */ - } reg_state:16; + } reg_state:8; + + bool dismantle; /* device is going do be freed */ enum { RTNL_LINK_INITIALIZED, diff --git a/net/core/dev.c b/net/core/dev.c index 155de20..d945379 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -5126,7 +5126,7 @@ static void rollback_registered_many(struct list_head *head) list_del(&dev->unreg_list); continue; } - + dev->dismantle = true; BUG_ON(dev->reg_state != NETREG_REGISTERED); } -- cgit v0.10.2 From d542fe27c86ecf932f40c898881208ccdaef9dc5 Mon Sep 17 00:00:00 2001 From: Matt Carlson Date: Thu, 19 May 2011 16:02:43 +0000 Subject: tg3: Fix NETIF_F_LOOPBACK error Mahesh Bandewar noticed that the features cleanup in commit 0da0606f493c5cdab74bdcc96b12f4305ad94085, entitled "tg3: Consolidate all netdev feature assignments", mistakenly sets NETIF_F_LOOPBACK by default. This patch corrects the error. Signed-off-by: Matt Carlson Signed-off-by: Mahesh Bandewar Signed-off-by: David S. Miller diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index 012ce70..284e998 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -15080,6 +15080,9 @@ static int __devinit tg3_init_one(struct pci_dev *pdev, features |= NETIF_F_TSO_ECN; } + dev->features |= features; + dev->vlan_features |= features; + /* * Add loopback capability only for a subset of devices that support * MAC-LOOPBACK. Eventually this need to be enhanced to allow INT-PHY @@ -15090,9 +15093,7 @@ static int __devinit tg3_init_one(struct pci_dev *pdev, /* Add the loopback capability */ features |= NETIF_F_LOOPBACK; - dev->features |= features; dev->hw_features |= features; - dev->vlan_features |= features; if (tp->pci_chip_rev_id == CHIPREV_ID_5705_A1 && !tg3_flag(tp, TSO_CAPABLE) && -- cgit v0.10.2 From 7196cd6c3d4863000ef88b09f34d6dd75610ec3e Mon Sep 17 00:00:00 2001 From: Matt Carlson Date: Thu, 19 May 2011 16:02:44 +0000 Subject: tg3: Add braces around 5906 workaround. Commit dabc5c670d3f86d15ee4f42ab38ec5bd2682487d, entitled "tg3: Move TSO_CAPABLE assignment", moved some TSO flagging code around. In the process it failed to add braces around an exceptional 5906 condition. This patch fixes the problem. Signed-off-by: Matt Carlson Signed-off-by: David S. Miller diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index 284e998..db19332 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -13707,9 +13707,11 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) tp->pcie_cap + PCI_EXP_LNKCTL, &lnkctl); if (lnkctl & PCI_EXP_LNKCTL_CLKREQ_EN) { - if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906) + if (GET_ASIC_REV(tp->pci_chip_rev_id) == + ASIC_REV_5906) { tg3_flag_clear(tp, HW_TSO_2); tg3_flag_clear(tp, TSO_CAPABLE); + } if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784 || GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761 || tp->pci_chip_rev_id == CHIPREV_ID_57780_A0 || -- cgit v0.10.2 From e83b906c99eb87a11cd731f6726e60cd8ac9ec4b Mon Sep 17 00:00:00 2001 From: Benjamin Herrenschmidt Date: Fri, 20 May 2011 15:37:22 +1000 Subject: powerpc/pmac: Update via-pmu to new syscore_ops This was left as a sysdev, breaking the build Signed-off-by: Benjamin Herrenschmidt diff --git a/drivers/macintosh/via-pmu.c b/drivers/macintosh/via-pmu.c index 8b021eb..6cccd60 100644 --- a/drivers/macintosh/via-pmu.c +++ b/drivers/macintosh/via-pmu.c @@ -40,7 +40,7 @@ #include #include #include -#include +#include #include #include #include @@ -2527,12 +2527,9 @@ void pmu_blink(int n) #if defined(CONFIG_SUSPEND) && defined(CONFIG_PPC32) int pmu_sys_suspended; -static int pmu_sys_suspend(struct sys_device *sysdev, pm_message_t state) +static int pmu_syscore_suspend(void) { - if (state.event != PM_EVENT_SUSPEND || pmu_sys_suspended) - return 0; - - /* Suspend PMU event interrupts */\ + /* Suspend PMU event interrupts */ pmu_suspend(); pmu_sys_suspended = 1; @@ -2544,12 +2541,12 @@ static int pmu_sys_suspend(struct sys_device *sysdev, pm_message_t state) return 0; } -static int pmu_sys_resume(struct sys_device *sysdev) +static void pmu_syscore_resume(void) { struct adb_request req; if (!pmu_sys_suspended) - return 0; + return; /* Tell PMU we are ready */ pmu_request(&req, NULL, 2, PMU_SYSTEM_READY, 2); @@ -2562,50 +2559,21 @@ static int pmu_sys_resume(struct sys_device *sysdev) /* Resume PMU event interrupts */ pmu_resume(); pmu_sys_suspended = 0; - - return 0; } -#endif /* CONFIG_SUSPEND && CONFIG_PPC32 */ - -static struct sysdev_class pmu_sysclass = { - .name = "pmu", -}; - -static struct sys_device device_pmu = { - .cls = &pmu_sysclass, -}; - -static struct sysdev_driver driver_pmu = { -#if defined(CONFIG_SUSPEND) && defined(CONFIG_PPC32) - .suspend = &pmu_sys_suspend, - .resume = &pmu_sys_resume, -#endif /* CONFIG_SUSPEND && CONFIG_PPC32 */ +static struct syscore_ops pmu_syscore_ops = { + .suspend = pmu_syscore_suspend, + .resume = pmu_syscore_resume, }; -static int __init init_pmu_sysfs(void) +static int pmu_syscore_register(void) { - int rc; + register_syscore_ops(&pmu_syscore_ops); - rc = sysdev_class_register(&pmu_sysclass); - if (rc) { - printk(KERN_ERR "Failed registering PMU sys class\n"); - return -ENODEV; - } - rc = sysdev_register(&device_pmu); - if (rc) { - printk(KERN_ERR "Failed registering PMU sys device\n"); - return -ENODEV; - } - rc = sysdev_driver_register(&pmu_sysclass, &driver_pmu); - if (rc) { - printk(KERN_ERR "Failed registering PMU sys driver\n"); - return -ENODEV; - } return 0; } - -subsys_initcall(init_pmu_sysfs); +subsys_initcall(pmu_syscore_register); +#endif /* CONFIG_SUSPEND && CONFIG_PPC32 */ EXPORT_SYMBOL(pmu_request); EXPORT_SYMBOL(pmu_queue_request); -- cgit v0.10.2 From a2d063ac216c1618bfc2b4d40b7176adffa63511 Mon Sep 17 00:00:00 2001 From: Steven Rostedt Date: Thu, 19 May 2011 21:34:58 -0400 Subject: extable, core_kernel_data(): Make sure all archs define _sdata A new utility function (core_kernel_data()) is used to determine if a passed in address is part of core kernel data or not. It may or may not return true for RO data, but this utility must work for RW data. Thus both _sdata and _edata must be defined and continuous, without .init sections that may later be freed and replaced by volatile memory (memory that can be freed). This utility function is used to determine if data is safe from ever being freed. Thus it should return true for all RW global data that is not in a module or has been allocated, or false otherwise. Also change core_kernel_data() back to the more precise _sdata condition and document the function. Signed-off-by: Steven Rostedt Acked-by: Ralf Baechle Acked-by: Hirokazu Takata Cc: Richard Henderson Cc: Ivan Kokshaysky Cc: Matt Turner Cc: Geert Uytterhoeven Cc: Roman Zippel Cc: linux-m68k@lists.linux-m68k.org Cc: Kyle McMartin Cc: Helge Deller Cc: JamesE.J.Bottomley Link: http://lkml.kernel.org/r/1305855298.1465.19.camel@gandalf.stny.rr.com Signed-off-by: Ingo Molnar ---- arch/alpha/kernel/vmlinux.lds.S | 1 + arch/m32r/kernel/vmlinux.lds.S | 1 + arch/m68k/kernel/vmlinux-std.lds | 2 ++ arch/m68k/kernel/vmlinux-sun3.lds | 1 + arch/mips/kernel/vmlinux.lds.S | 1 + arch/parisc/kernel/vmlinux.lds.S | 3 +++ kernel/extable.c | 12 +++++++++++- 7 files changed, 20 insertions(+), 1 deletion(-) diff --git a/arch/alpha/kernel/vmlinux.lds.S b/arch/alpha/kernel/vmlinux.lds.S index 433be2a..3d890a9 100644 --- a/arch/alpha/kernel/vmlinux.lds.S +++ b/arch/alpha/kernel/vmlinux.lds.S @@ -46,6 +46,7 @@ SECTIONS __init_end = .; /* Freed after init ends here */ + _sdata = .; /* Start of rw data section */ _data = .; RW_DATA_SECTION(L1_CACHE_BYTES, PAGE_SIZE, THREAD_SIZE) diff --git a/arch/m32r/kernel/vmlinux.lds.S b/arch/m32r/kernel/vmlinux.lds.S index c194d64..cf95aec 100644 --- a/arch/m32r/kernel/vmlinux.lds.S +++ b/arch/m32r/kernel/vmlinux.lds.S @@ -44,6 +44,7 @@ SECTIONS EXCEPTION_TABLE(16) NOTES + _sdata = .; /* Start of data section */ RODATA RW_DATA_SECTION(32, PAGE_SIZE, THREAD_SIZE) _edata = .; /* End of data section */ diff --git a/arch/m68k/kernel/vmlinux-std.lds b/arch/m68k/kernel/vmlinux-std.lds index 878be5f..d099359 100644 --- a/arch/m68k/kernel/vmlinux-std.lds +++ b/arch/m68k/kernel/vmlinux-std.lds @@ -25,6 +25,8 @@ SECTIONS EXCEPTION_TABLE(16) + _sdata = .; /* Start of data section */ + RODATA RW_DATA_SECTION(16, PAGE_SIZE, THREAD_SIZE) diff --git a/arch/m68k/kernel/vmlinux-sun3.lds b/arch/m68k/kernel/vmlinux-sun3.lds index 1ad6b7a..8080469 100644 --- a/arch/m68k/kernel/vmlinux-sun3.lds +++ b/arch/m68k/kernel/vmlinux-sun3.lds @@ -25,6 +25,7 @@ SECTIONS _etext = .; /* End of text section */ EXCEPTION_TABLE(16) :data + _sdata = .; /* Start of rw data section */ RW_DATA_SECTION(16, PAGE_SIZE, THREAD_SIZE) :data /* End of data goes *here* so that freeing init code works properly. */ _edata = .; diff --git a/arch/mips/kernel/vmlinux.lds.S b/arch/mips/kernel/vmlinux.lds.S index cd2ca54..01af387 100644 --- a/arch/mips/kernel/vmlinux.lds.S +++ b/arch/mips/kernel/vmlinux.lds.S @@ -65,6 +65,7 @@ SECTIONS NOTES :text :note .dummy : { *(.dummy) } :text + _sdata = .; /* Start of data section */ RODATA /* writeable */ diff --git a/arch/parisc/kernel/vmlinux.lds.S b/arch/parisc/kernel/vmlinux.lds.S index 8f1e4ef..2d9a5c7 100644 --- a/arch/parisc/kernel/vmlinux.lds.S +++ b/arch/parisc/kernel/vmlinux.lds.S @@ -69,6 +69,9 @@ SECTIONS /* End of text section */ _etext = .; + /* Start of data section */ + _sdata = .; + RODATA /* writeable */ diff --git a/kernel/extable.c b/kernel/extable.c index d44aac0..5339705 100644 --- a/kernel/extable.c +++ b/kernel/extable.c @@ -72,9 +72,19 @@ int core_kernel_text(unsigned long addr) return 0; } +/** + * core_kernel_data - tell if addr points to kernel data + * @addr: address to test + * + * Returns true if @addr passed in is from the core kernel data + * section. + * + * Note: On some archs it may return true for core RODATA, and false + * for others. But will always be true for core RW data. + */ int core_kernel_data(unsigned long addr) { - if (addr >= (unsigned long)_stext && + if (addr >= (unsigned long)_sdata && addr < (unsigned long)_edata) return 1; return 0; -- cgit v0.10.2 From 208b3a4c196e733b9cec006dc132cfc149b2810a Mon Sep 17 00:00:00 2001 From: Benjamin Herrenschmidt Date: Fri, 20 May 2011 17:50:18 +1000 Subject: powerpc: Fix hard CPU IDs detection commit 9d07bc841c9779b4d7902e417f4e509996ce805d "powerpc: Properly handshake CPUs going out of boot spin loop" Would cause a miscalculation of the hard CPU ID. It removes breaking out of the loop when finding a match with a processor, thus the "i" used as an index in the intserv array is always incorrect This broke interrupt on my PowerMac laptop. Signed-off-by: Benjamin Herrenschmidt diff --git a/arch/powerpc/kernel/prom.c b/arch/powerpc/kernel/prom.c index 5311a26..48aeb55 100644 --- a/arch/powerpc/kernel/prom.c +++ b/arch/powerpc/kernel/prom.c @@ -278,6 +278,7 @@ static int __init early_init_dt_scan_cpus(unsigned long node, int i, nthreads; unsigned long len; int found = -1; + int found_thread = 0; /* We are scanning "cpu" nodes only */ if (type == NULL || strcmp(type, "cpu") != 0) @@ -301,9 +302,11 @@ static int __init early_init_dt_scan_cpus(unsigned long node, * version 2 of the kexec param format adds the phys cpuid of * booted proc. */ - if (initial_boot_params && initial_boot_params->version >= 2) { - if (intserv[i] == initial_boot_params->boot_cpuid_phys) + if (initial_boot_params->version >= 2) { + if (intserv[i] == initial_boot_params->boot_cpuid_phys) { found = boot_cpu_count; + found_thread = i; + } } else { /* * Check if it's the boot-cpu, set it's hw index now, @@ -322,9 +325,9 @@ static int __init early_init_dt_scan_cpus(unsigned long node, if (found >= 0) { DBG("boot cpu: logical %d physical %d\n", found, - intserv[i]); + intserv[found_thread]); boot_cpuid = found; - set_hard_smp_processor_id(found, intserv[i]); + set_hard_smp_processor_id(found, intserv[found_thread]); /* * PAPR defines "logical" PVR values for cpus that -- cgit v0.10.2 From c0e299b1a91cbdb21ae08e382a4176200398bc36 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Fri, 20 May 2011 10:50:52 +0200 Subject: clockevents/source: Use u64 to make 32bit happy unsigned long is not 64bit on 32bit machine. Signed-off-by: Thomas Gleixner diff --git a/kernel/time/clockevents.c b/kernel/time/clockevents.c index 22a9da9..c027d4f 100644 --- a/kernel/time/clockevents.c +++ b/kernel/time/clockevents.c @@ -197,7 +197,7 @@ EXPORT_SYMBOL_GPL(clockevents_register_device); static void clockevents_config(struct clock_event_device *dev, u32 freq) { - unsigned long sec; + u64 sec; if (!(dev->features & CLOCK_EVT_FEAT_ONESHOT)) return; diff --git a/kernel/time/clocksource.c b/kernel/time/clocksource.c index d9d5f8c..1c95fd6 100644 --- a/kernel/time/clocksource.c +++ b/kernel/time/clocksource.c @@ -639,7 +639,7 @@ static void clocksource_enqueue(struct clocksource *cs) */ void __clocksource_updatefreq_scale(struct clocksource *cs, u32 scale, u32 freq) { - unsigned long sec; + u64 sec; /* * Calc the maximum number of seconds which we can run before -- cgit v0.10.2 From bbe7b8bef48c567f5ff3f6041c1fb011292e8f12 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Fri, 20 May 2011 11:38:24 +0200 Subject: MAINTAINERS: Add drivers/clocksource to TIMEKEEPING It's not a random dump ground and we care about it. Signed-off-by: Thomas Gleixner Cc: Ralf Baechle diff --git a/MAINTAINERS b/MAINTAINERS index 8df8d2d..e20c974 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -5431,6 +5431,7 @@ F: include/linux/timex.h F: kernel/time/clocksource.c F: kernel/time/time*.c F: kernel/time/ntp.c +F: drivers/clocksource TLG2300 VIDEO4LINUX-2 DRIVER M: Huang Shijie -- cgit v0.10.2 From 156ecb2d8b06589098f6ce3012e6a10fef07c416 Mon Sep 17 00:00:00 2001 From: Steve French Date: Fri, 20 May 2011 17:00:01 +0000 Subject: [CIFS] Fix to problem with getattr caused by invalidate simplification patch Fix to earlier "Simplify invalidate part (try #6)" patch That patch caused problems with connectathon test 5. Reviewed-by: Jeff Layton Signed-off-by: Pavel Shilovsky Signed-off-by: Steve French diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c index ed92c7d..493b74c 100644 --- a/fs/cifs/cifsfs.c +++ b/fs/cifs/cifsfs.c @@ -617,8 +617,10 @@ static loff_t cifs_llseek(struct file *file, loff_t offset, int origin) if (!CIFS_I(inode)->clientCanCacheRead && inode->i_mapping && inode->i_mapping->nrpages != 0) { rc = filemap_fdatawait(inode->i_mapping); - mapping_set_error(inode->i_mapping, rc); - return rc; + if (rc) { + mapping_set_error(inode->i_mapping, rc); + return rc; + } } /* * Some applications poll for the file length in this strange diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c index 0cc7edd..de02ed5 100644 --- a/fs/cifs/inode.c +++ b/fs/cifs/inode.c @@ -1805,8 +1805,10 @@ int cifs_getattr(struct vfsmount *mnt, struct dentry *dentry, if (!CIFS_I(inode)->clientCanCacheRead && inode->i_mapping && inode->i_mapping->nrpages != 0) { rc = filemap_fdatawait(inode->i_mapping); - mapping_set_error(inode->i_mapping, rc); - return rc; + if (rc) { + mapping_set_error(inode->i_mapping, rc); + return rc; + } } rc = cifs_revalidate_dentry_attr(dentry); -- cgit v0.10.2 From 5d2a8342f64e93c217fcbf3206ec9ae770b1413d Mon Sep 17 00:00:00 2001 From: "Luck, Tony" Date: Wed, 13 Apr 2011 10:48:12 -0700 Subject: pstore: Fix Kconfig dependencies for apei->pstore Geert Uytterhoeven ran a dependency checker which kicked out this warning: + warning: (ACPI_APEI) selects PSTORE which has unmet direct dependencies (MISC_FILESYSTEMS): => N/A Randy confirmed that the fix was to "select MISC_FILESYSTEMS" too. Tested-by: Randy Dunlap Signed-off-by: Tony Luck diff --git a/drivers/acpi/apei/Kconfig b/drivers/acpi/apei/Kconfig index 66a03ca..f739a70 100644 --- a/drivers/acpi/apei/Kconfig +++ b/drivers/acpi/apei/Kconfig @@ -1,5 +1,6 @@ config ACPI_APEI bool "ACPI Platform Error Interface (APEI)" + select MISC_FILESYSTEMS select PSTORE depends on X86 help -- cgit v0.10.2 From 30f7276cb35a22743d709a460ae3639aad50366a Mon Sep 17 00:00:00 2001 From: Tony Luck Date: Fri, 20 May 2011 10:38:53 -0700 Subject: [IA64] define "_sdata" symbol core_kernel_data() wants to know if an address looks like kernel data. IA64 has had _edata forever, but never needed _sdata until now. Signed-off-by: Tony Luck diff --git a/arch/ia64/kernel/vmlinux.lds.S b/arch/ia64/kernel/vmlinux.lds.S index 787de4a..53c0ba0 100644 --- a/arch/ia64/kernel/vmlinux.lds.S +++ b/arch/ia64/kernel/vmlinux.lds.S @@ -209,6 +209,7 @@ SECTIONS { data : { } :data .data : AT(ADDR(.data) - LOAD_OFFSET) { + _sdata = .; INIT_TASK_DATA(PAGE_SIZE) CACHELINE_ALIGNED_DATA(SMP_CACHE_BYTES) READ_MOSTLY_DATA(SMP_CACHE_BYTES) -- cgit v0.10.2 From d93515611bbc70c2fe4db232e5feb448ed8e4cc9 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Fri, 20 May 2011 14:59:23 -0400 Subject: macvlan: fix panic if lowerdev in a bond commit a35e2c1b6d905 (macvlan: use rx_handler_data pointer to store macvlan_port pointer V2) added a bug in macvlan_port_create() Steps to reproduce the bug: # ifenslave bond0 eth0 eth1 # ip link add link eth0 up name eth0#1 type macvlan ->error EBUSY # ip link add link eth0 up name eth0#1 type macvlan ->panic Fix: Dont set IFF_MACVLAN_PORT in error case. Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller diff --git a/drivers/net/macvlan.c b/drivers/net/macvlan.c index 07bcb80..bbcf80a 100644 --- a/drivers/net/macvlan.c +++ b/drivers/net/macvlan.c @@ -585,8 +585,8 @@ static int macvlan_port_create(struct net_device *dev) err = netdev_rx_handler_register(dev, macvlan_handle_frame, port); if (err) kfree(port); - - dev->priv_flags |= IFF_MACVLAN_PORT; + else + dev->priv_flags |= IFF_MACVLAN_PORT; return err; } -- cgit v0.10.2 From 268bb0ce3e87872cb9290c322b0d35bce230d88f Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Fri, 20 May 2011 12:50:29 -0700 Subject: sanitize usage Commit e66eed651fd1 ("list: remove prefetching from regular list iterators") removed the include of prefetch.h from list.h, which uncovered several cases that had apparently relied on that rather obscure header file dependency. So this fixes things up a bit, using grep -L linux/prefetch.h $(git grep -l '[^a-z_]prefetchw*(' -- '*.[ch]') grep -L 'prefetchw*(' $(git grep -l 'linux/prefetch.h' -- '*.[ch]') to guide us in finding files that either need inclusion, or have it despite not needing it. There are more of them around (mostly network drivers), but this gets many core ones. Reported-by: Stephen Rothwell Signed-off-by: Linus Torvalds diff --git a/arch/ia64/hp/common/sba_iommu.c b/arch/ia64/hp/common/sba_iommu.c index 4ce8d13..c04dd57 100644 --- a/arch/ia64/hp/common/sba_iommu.c +++ b/arch/ia64/hp/common/sba_iommu.c @@ -37,6 +37,7 @@ #include #include #include +#include #include /* ia64_get_itc() */ #include diff --git a/arch/ia64/mm/fault.c b/arch/ia64/mm/fault.c index 0799fea..20b3593 100644 --- a/arch/ia64/mm/fault.c +++ b/arch/ia64/mm/fault.c @@ -10,6 +10,7 @@ #include #include #include +#include #include #include diff --git a/arch/powerpc/lib/sstep.c b/arch/powerpc/lib/sstep.c index ae5189a..f73daa6 100644 --- a/arch/powerpc/lib/sstep.c +++ b/arch/powerpc/lib/sstep.c @@ -11,6 +11,7 @@ #include #include #include +#include #include #include #include diff --git a/arch/sh/kernel/cpu/sh4/sq.c b/arch/sh/kernel/cpu/sh4/sq.c index 14726ee..f090799 100644 --- a/arch/sh/kernel/cpu/sh4/sq.c +++ b/arch/sh/kernel/cpu/sh4/sq.c @@ -20,6 +20,7 @@ #include #include #include +#include #include #include #include diff --git a/arch/x86/include/asm/uaccess.h b/arch/x86/include/asm/uaccess.h index 99f0ad7..99ddd14 100644 --- a/arch/x86/include/asm/uaccess.h +++ b/arch/x86/include/asm/uaccess.h @@ -6,7 +6,6 @@ #include #include #include -#include #include #include #include diff --git a/arch/x86/include/asm/uaccess_32.h b/arch/x86/include/asm/uaccess_32.h index 088d09f..566e803 100644 --- a/arch/x86/include/asm/uaccess_32.h +++ b/arch/x86/include/asm/uaccess_32.h @@ -6,7 +6,6 @@ */ #include #include -#include #include #include #include diff --git a/arch/x86/include/asm/uaccess_64.h b/arch/x86/include/asm/uaccess_64.h index 316708d..1c66d30 100644 --- a/arch/x86/include/asm/uaccess_64.h +++ b/arch/x86/include/asm/uaccess_64.h @@ -6,7 +6,6 @@ */ #include #include -#include #include #include #include diff --git a/arch/x86/mm/fault.c b/arch/x86/mm/fault.c index 20e3f87..bcb394d 100644 --- a/arch/x86/mm/fault.c +++ b/arch/x86/mm/fault.c @@ -12,6 +12,7 @@ #include /* kmmio_handler, ... */ #include /* perf_sw_event */ #include /* hstate_index_to_shift */ +#include /* prefetchw */ #include /* dotraplinkage, ... */ #include /* pgd_*(), ... */ diff --git a/drivers/misc/sgi-gru/grufault.c b/drivers/misc/sgi-gru/grufault.c index 38657cd..c4acac7 100644 --- a/drivers/misc/sgi-gru/grufault.c +++ b/drivers/misc/sgi-gru/grufault.c @@ -33,6 +33,7 @@ #include #include #include +#include #include #include "gru.h" #include "grutables.h" diff --git a/drivers/misc/sgi-gru/grumain.c b/drivers/misc/sgi-gru/grumain.c index f8538bb..ae16c8c 100644 --- a/drivers/misc/sgi-gru/grumain.c +++ b/drivers/misc/sgi-gru/grumain.c @@ -28,6 +28,7 @@ #include #include #include +#include #include #include "gru.h" #include "grutables.h" diff --git a/drivers/net/acenic.c b/drivers/net/acenic.c index ee648fe..01560bb 100644 --- a/drivers/net/acenic.c +++ b/drivers/net/acenic.c @@ -68,6 +68,7 @@ #include #include #include +#include #if defined(CONFIG_VLAN_8021Q) || defined(CONFIG_VLAN_8021Q_MODULE) #include diff --git a/drivers/net/ehea/ehea_main.c b/drivers/net/ehea/ehea_main.c index cf79cf7..2c60435 100644 --- a/drivers/net/ehea/ehea_main.c +++ b/drivers/net/ehea/ehea_main.c @@ -41,6 +41,7 @@ #include #include #include +#include #include diff --git a/drivers/staging/pohmelfs/inode.c b/drivers/staging/pohmelfs/inode.c index c93ef207..c0f0ac7 100644 --- a/drivers/staging/pohmelfs/inode.c +++ b/drivers/staging/pohmelfs/inode.c @@ -29,6 +29,7 @@ #include #include #include +#include #include "netfs.h" diff --git a/drivers/usb/gadget/goku_udc.c b/drivers/usb/gadget/goku_udc.c index 48a7602..bf6e11c 100644 --- a/drivers/usb/gadget/goku_udc.c +++ b/drivers/usb/gadget/goku_udc.c @@ -38,6 +38,7 @@ #include #include #include +#include #include #include diff --git a/drivers/usb/gadget/imx_udc.c b/drivers/usb/gadget/imx_udc.c index 5408186..ade4006 100644 --- a/drivers/usb/gadget/imx_udc.c +++ b/drivers/usb/gadget/imx_udc.c @@ -30,6 +30,7 @@ #include #include #include +#include #include #include diff --git a/drivers/usb/gadget/omap_udc.c b/drivers/usb/gadget/omap_udc.c index cb5cd42..82fd249 100644 --- a/drivers/usb/gadget/omap_udc.c +++ b/drivers/usb/gadget/omap_udc.c @@ -44,6 +44,7 @@ #include #include #include +#include #include #include diff --git a/drivers/usb/gadget/pxa25x_udc.c b/drivers/usb/gadget/pxa25x_udc.c index 444b60a..365c02f 100644 --- a/drivers/usb/gadget/pxa25x_udc.c +++ b/drivers/usb/gadget/pxa25x_udc.c @@ -46,6 +46,7 @@ #include #include #include +#include #include #include diff --git a/drivers/usb/gadget/pxa27x_udc.c b/drivers/usb/gadget/pxa27x_udc.c index 78a39a4..5760769 100644 --- a/drivers/usb/gadget/pxa27x_udc.c +++ b/drivers/usb/gadget/pxa27x_udc.c @@ -32,6 +32,7 @@ #include #include #include +#include #include #include diff --git a/drivers/usb/host/isp1362-hcd.c b/drivers/usb/host/isp1362-hcd.c index f97570a..9c37dad 100644 --- a/drivers/usb/host/isp1362-hcd.c +++ b/drivers/usb/host/isp1362-hcd.c @@ -81,6 +81,7 @@ #include #include #include +#include #include #include diff --git a/drivers/usb/host/sl811-hcd.c b/drivers/usb/host/sl811-hcd.c index 18b7099..fafccc2 100644 --- a/drivers/usb/host/sl811-hcd.c +++ b/drivers/usb/host/sl811-hcd.c @@ -47,6 +47,7 @@ #include #include #include +#include #include #include diff --git a/drivers/video/udlfb.c b/drivers/video/udlfb.c index 68041d9..695066b 100644 --- a/drivers/video/udlfb.c +++ b/drivers/video/udlfb.c @@ -27,6 +27,7 @@ #include #include #include +#include #include #include